aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.clang-format2
-rw-r--r--.git-blame-ignore-revs31
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.md34
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.yml75
-rw-r--r--.github/ISSUE_TEMPLATE/config.yml5
-rw-r--r--.github/ISSUE_TEMPLATE/feature_request.md27
-rw-r--r--.github/ISSUE_TEMPLATE/feature_request.yml21
-rw-r--r--.github/ISSUE_TEMPLATE/lsp_bug_report.md58
-rw-r--r--.github/ISSUE_TEMPLATE/lsp_bug_report.yml61
-rw-r--r--.github/labeler.yml34
-rw-r--r--.github/workflows/ci.yml9
-rw-r--r--.github/workflows/commitlint.yml16
-rw-r--r--.github/workflows/labeler.yml19
-rw-r--r--.github/workflows/release.yml12
-rw-r--r--.github/workflows/squash-typos.yml33
-rw-r--r--.gitignore1
-rw-r--r--.luacheckrc4
-rw-r--r--BSDmakefile4
-rw-r--r--CMakeLists.txt10
-rw-r--r--CONTRIBUTING.md122
-rw-r--r--LICENSE11
-rw-r--r--MAINTAIN.md35
-rw-r--r--Makefile85
-rw-r--r--README.md10
-rw-r--r--cmake/FindLibLUV.cmake2
-rw-r--r--cmake/FindLibUV.cmake8
-rw-r--r--cmake/RunTests.cmake8
-rw-r--r--contrib/flake.lock12
-rw-r--r--contrib/flake.nix95
-rw-r--r--contrib/uncrustify.cfg1578
-rw-r--r--man/nvim.12
-rw-r--r--runtime/autoload/ada.vim6
-rw-r--r--runtime/autoload/adacomplete.vim2
-rw-r--r--runtime/autoload/csscomplete.vim8
-rw-r--r--runtime/autoload/decada.vim2
-rw-r--r--runtime/autoload/dist/ft.vim19
-rw-r--r--runtime/autoload/haskellcomplete.vim6
-rw-r--r--runtime/autoload/health/lsp.vim5
-rw-r--r--runtime/autoload/htmlcomplete.vim2
-rw-r--r--runtime/autoload/man.vim19
-rw-r--r--runtime/autoload/netrw.vim274
-rw-r--r--runtime/autoload/netrwSettings.vim8
-rw-r--r--runtime/autoload/phpcomplete.vim40
-rw-r--r--runtime/autoload/provider/clipboard.vim4
-rw-r--r--runtime/autoload/python3complete.vim2
-rw-r--r--runtime/autoload/pythoncomplete.vim2
-rw-r--r--runtime/autoload/remote/host.vim2
-rw-r--r--runtime/autoload/rubycomplete.vim11
-rw-r--r--runtime/autoload/sqlcomplete.vim10
-rw-r--r--runtime/autoload/tar.vim2
-rw-r--r--runtime/autoload/tohtml.vim2
-rw-r--r--runtime/autoload/vimexpect.vim2
-rw-r--r--runtime/autoload/xmlcomplete.vim2
-rw-r--r--runtime/autoload/zip.vim2
-rw-r--r--runtime/compiler/fpc.vim2
-rw-r--r--runtime/compiler/scdoc.vim16
-rw-r--r--runtime/compiler/spectral.vim17
-rw-r--r--runtime/compiler/tex.vim2
-rw-r--r--runtime/compiler/yamllint.vim16
-rw-r--r--runtime/doc/api.txt167
-rw-r--r--runtime/doc/arabic.txt7
-rw-r--r--runtime/doc/autocmd.txt17
-rw-r--r--runtime/doc/change.txt27
-rw-r--r--runtime/doc/cmdline.txt14
-rw-r--r--runtime/doc/deprecated.txt50
-rw-r--r--runtime/doc/dev_style.txt1159
-rw-r--r--runtime/doc/develop.txt55
-rw-r--r--runtime/doc/diagnostic.txt562
-rw-r--r--runtime/doc/diff.txt8
-rw-r--r--runtime/doc/digraph.txt8
-rw-r--r--runtime/doc/eval.txt1508
-rw-r--r--runtime/doc/filetype.txt11
-rw-r--r--runtime/doc/fold.txt2
-rw-r--r--runtime/doc/ft_ps1.txt2
-rw-r--r--runtime/doc/ft_raku.txt4
-rw-r--r--runtime/doc/ft_sql.txt2
-rw-r--r--runtime/doc/gui.txt6
-rw-r--r--runtime/doc/help.txt22
-rw-r--r--runtime/doc/helphelp.txt1
-rw-r--r--runtime/doc/if_perl.txt3
-rw-r--r--runtime/doc/if_ruby.txt4
-rw-r--r--runtime/doc/index.txt11
-rw-r--r--runtime/doc/insert.txt19
-rw-r--r--runtime/doc/intro.txt7
-rw-r--r--runtime/doc/job_control.txt4
-rw-r--r--runtime/doc/lsp.txt887
-rw-r--r--runtime/doc/lua.txt399
-rw-r--r--runtime/doc/map.txt1
-rw-r--r--runtime/doc/motion.txt11
-rw-r--r--runtime/doc/nvim_terminal_emulator.txt45
-rw-r--r--runtime/doc/options.txt158
-rw-r--r--runtime/doc/pattern.txt2
-rw-r--r--runtime/doc/pi_netrw.txt80
-rw-r--r--runtime/doc/print.txt11
-rw-r--r--runtime/doc/provider.txt1
-rw-r--r--runtime/doc/quickfix.txt3
-rw-r--r--runtime/doc/quickref.txt2
-rw-r--r--runtime/doc/remote.txt189
-rw-r--r--runtime/doc/repeat.txt95
-rw-r--r--runtime/doc/rileft.txt2
-rw-r--r--runtime/doc/russian.txt4
-rw-r--r--runtime/doc/sign.txt24
-rw-r--r--runtime/doc/spell.txt6
-rw-r--r--runtime/doc/starting.txt87
-rw-r--r--runtime/doc/syntax.txt120
-rw-r--r--runtime/doc/tagsrch.txt13
-rw-r--r--runtime/doc/testing.txt41
-rw-r--r--runtime/doc/treesitter.txt90
-rw-r--r--runtime/doc/usr_05.txt6
-rw-r--r--runtime/doc/usr_08.txt2
-rw-r--r--runtime/doc/usr_09.txt2
-rw-r--r--runtime/doc/usr_41.txt12
-rw-r--r--runtime/doc/usr_45.txt7
-rw-r--r--runtime/doc/various.txt32
-rw-r--r--runtime/doc/vim_diff.txt66
-rw-r--r--runtime/doc/visual.txt2
-rw-r--r--runtime/doc/windows.txt5
-rw-r--r--runtime/filetype.vim35
-rw-r--r--runtime/ftplugin/8th.vim10
-rw-r--r--runtime/ftplugin/c.vim10
-rw-r--r--runtime/ftplugin/chicken.vim1
-rw-r--r--runtime/ftplugin/dosini.vim2
-rw-r--r--runtime/ftplugin/eruby.vim4
-rw-r--r--runtime/ftplugin/gprof.vim22
-rw-r--r--runtime/ftplugin/jsonc.vim27
-rw-r--r--runtime/ftplugin/julia.vim92
-rw-r--r--runtime/ftplugin/man.vim14
-rw-r--r--runtime/ftplugin/matlab.vim7
-rw-r--r--runtime/ftplugin/ocaml.vim8
-rw-r--r--runtime/ftplugin/octave.vim63
-rw-r--r--runtime/ftplugin/ruby.vim4
-rw-r--r--runtime/ftplugin/scala.vim6
-rw-r--r--runtime/ftplugin/scdoc.vim26
-rw-r--r--runtime/ftplugin/scheme.vim5
-rw-r--r--runtime/ftplugin/systemverilog.vim2
-rw-r--r--runtime/ftplugin/tex.vim2
-rw-r--r--runtime/indent/ada.vim2
-rw-r--r--runtime/indent/bzl.vim41
-rw-r--r--runtime/indent/cdl.vim12
-rw-r--r--runtime/indent/config.vim4
-rw-r--r--runtime/indent/dtd.vim6
-rw-r--r--runtime/indent/erlang.vim8
-rw-r--r--runtime/indent/html.vim63
-rw-r--r--runtime/indent/json.vim2
-rw-r--r--runtime/indent/jsonc.vim189
-rw-r--r--runtime/indent/julia.vim491
-rw-r--r--runtime/indent/lifelines.vim2
-rw-r--r--runtime/indent/objc.vim2
-rw-r--r--runtime/indent/pascal.vim4
-rw-r--r--runtime/indent/pov.vim2
-rw-r--r--runtime/indent/python.vim4
-rw-r--r--runtime/indent/ruby.vim3
-rw-r--r--runtime/indent/scala.vim9
-rw-r--r--runtime/indent/sqlanywhere.vim2
-rw-r--r--runtime/indent/systemverilog.vim4
-rw-r--r--runtime/indent/testdir/xml.in2
-rw-r--r--runtime/indent/testdir/xml.ok2
-rw-r--r--runtime/indent/tex.vim2
-rw-r--r--runtime/indent/treetop.vim2
-rw-r--r--runtime/indent/typescript.vim2
-rw-r--r--runtime/indent/verilog.vim4
-rw-r--r--runtime/indent/yaml.vim2
-rw-r--r--runtime/keymap/kana.vim4
-rw-r--r--runtime/keymap/korean.vim2
-rw-r--r--runtime/keymap/russian-jcukenwintype.vim2
-rw-r--r--runtime/keymap/russian-typograph.vim4
-rw-r--r--runtime/lua/vim/F.lua13
-rw-r--r--runtime/lua/vim/_meta.lua1
-rw-r--r--runtime/lua/vim/diagnostic.lua1381
-rw-r--r--runtime/lua/vim/highlight.lua20
-rw-r--r--runtime/lua/vim/lsp.lua392
-rw-r--r--runtime/lua/vim/lsp/_snippet.lua399
-rw-r--r--runtime/lua/vim/lsp/buf.lua281
-rw-r--r--runtime/lua/vim/lsp/codelens.lua57
-rw-r--r--runtime/lua/vim/lsp/diagnostic.lua1448
-rw-r--r--runtime/lua/vim/lsp/handlers.lua287
-rw-r--r--runtime/lua/vim/lsp/health.lua27
-rw-r--r--runtime/lua/vim/lsp/log.lua46
-rw-r--r--runtime/lua/vim/lsp/protocol.lua24
-rw-r--r--runtime/lua/vim/lsp/rpc.lua168
-rw-r--r--runtime/lua/vim/lsp/util.lua674
-rw-r--r--runtime/lua/vim/shared.lua157
-rw-r--r--runtime/lua/vim/treesitter.lua23
-rw-r--r--runtime/lua/vim/treesitter/highlighter.lua20
-rw-r--r--runtime/lua/vim/treesitter/language.lua8
-rw-r--r--runtime/lua/vim/treesitter/languagetree.lua34
-rw-r--r--runtime/lua/vim/treesitter/query.lua71
-rw-r--r--runtime/lua/vim/ui.lua36
-rw-r--r--runtime/lua/vim/uri.lua32
-rw-r--r--runtime/nvim.appdata.xml1
-rw-r--r--runtime/optwin.vim3
-rw-r--r--runtime/pack/dist/opt/matchit/doc/matchit.txt4
-rw-r--r--runtime/pack/dist/opt/termdebug/plugin/termdebug.vim84
-rw-r--r--runtime/plugin/diagnostic.vim26
-rw-r--r--runtime/plugin/man.vim4
-rw-r--r--runtime/plugin/netrwPlugin.vim28
-rw-r--r--runtime/plugin/tohtml.vim2
-rw-r--r--runtime/syntax/2html.vim4
-rw-r--r--runtime/syntax/8th.vim2
-rw-r--r--runtime/syntax/abel.vim2
-rw-r--r--runtime/syntax/ada.vim2
-rw-r--r--runtime/syntax/ahdl.vim2
-rw-r--r--runtime/syntax/aptconf.vim13
-rw-r--r--runtime/syntax/aspvbs.vim6
-rw-r--r--runtime/syntax/c.vim5
-rw-r--r--runtime/syntax/cfg.vim2
-rw-r--r--runtime/syntax/chicken.vim21
-rw-r--r--runtime/syntax/cpp.vim57
-rw-r--r--runtime/syntax/csc.vim2
-rw-r--r--runtime/syntax/cupl.vim2
-rw-r--r--runtime/syntax/debchangelog.vim6
-rw-r--r--runtime/syntax/debsources.vim6
-rw-r--r--runtime/syntax/dosbatch.vim2
-rw-r--r--runtime/syntax/doxygen.vim8
-rw-r--r--runtime/syntax/focexec.vim2
-rw-r--r--runtime/syntax/forth.vim2
-rw-r--r--runtime/syntax/gemtext.vim24
-rw-r--r--runtime/syntax/go.vim444
-rw-r--r--runtime/syntax/gprof.vim5
-rw-r--r--runtime/syntax/gvpr.vim85
-rw-r--r--runtime/syntax/hamster.vim2
-rw-r--r--runtime/syntax/help.vim2
-rw-r--r--runtime/syntax/idl.vim2
-rw-r--r--runtime/syntax/iss.vim4
-rw-r--r--runtime/syntax/jsonc.vim44
-rw-r--r--runtime/syntax/julia.vim550
-rw-r--r--runtime/syntax/man.vim8
-rw-r--r--runtime/syntax/mma.vim4
-rw-r--r--runtime/syntax/objc.vim2
-rw-r--r--runtime/syntax/pascal.vim2
-rw-r--r--runtime/syntax/php.vim267
-rw-r--r--runtime/syntax/postscr.vim8
-rw-r--r--runtime/syntax/redif.vim2
-rw-r--r--runtime/syntax/ruby.vim20
-rw-r--r--runtime/syntax/scala.vim25
-rw-r--r--runtime/syntax/scdoc.vim52
-rw-r--r--runtime/syntax/scheme.vim13
-rw-r--r--runtime/syntax/sgml.vim6
-rw-r--r--runtime/syntax/sh.vim46
-rw-r--r--runtime/syntax/spup.vim4
-rw-r--r--runtime/syntax/st.vim4
-rw-r--r--runtime/syntax/structurizr.vim76
-rw-r--r--runtime/syntax/syncolor.vim87
-rw-r--r--runtime/syntax/synload.vim7
-rw-r--r--runtime/syntax/tmux.vim2
-rw-r--r--runtime/syntax/vim.vim17
-rw-r--r--runtime/tutor/en/vim-01-beginner.tutor222
-rw-r--r--runtime/tutor/en/vim-01-beginner.tutor.json70
-rwxr-xr-xscripts/finddeclarations.pl50
-rwxr-xr-xscripts/gen_vimdoc.py29
-rw-r--r--scripts/genvimvim.lua9
-rw-r--r--scripts/lintcommit.lua205
-rw-r--r--scripts/lua2dox.lua95
-rwxr-xr-xscripts/pvscheck.sh4
-rwxr-xr-xscripts/release.sh15
-rw-r--r--scripts/squash_typos.py223
-rwxr-xr-xscripts/vim-patch.sh24
-rwxr-xr-xscripts/vimpatch.lua4
-rw-r--r--src/cjson/fpconv.c211
-rw-r--r--src/cjson/fpconv.h22
-rw-r--r--src/cjson/lua_cjson.c1609
-rw-r--r--src/cjson/lua_cjson.h10
-rw-r--r--src/cjson/strbuf.c251
-rw-r--r--src/cjson/strbuf.h159
-rwxr-xr-xsrc/clint.py4
-rw-r--r--src/mpack/LICENSE-MIT22
-rw-r--r--src/mpack/conv.c378
-rw-r--r--src/mpack/conv.h55
-rw-r--r--src/mpack/lmpack.c1218
-rw-r--r--src/mpack/lmpack.h3
-rw-r--r--src/mpack/mpack_core.c578
-rw-r--r--src/mpack/mpack_core.h87
-rw-r--r--src/mpack/object.c198
-rw-r--r--src/mpack/object.h86
-rw-r--r--src/mpack/rpc.c334
-rw-r--r--src/mpack/rpc.h83
-rw-r--r--src/nvim/CMakeLists.txt28
-rw-r--r--src/nvim/README.md104
-rw-r--r--src/nvim/api/buffer.c357
-rw-r--r--src/nvim/api/deprecated.c107
-rw-r--r--src/nvim/api/private/dispatch.c33
-rw-r--r--src/nvim/api/private/handle.c40
-rw-r--r--src/nvim/api/private/handle.h24
-rw-r--r--src/nvim/api/private/helpers.c637
-rw-r--r--src/nvim/api/private/helpers.h8
-rw-r--r--src/nvim/api/tabpage.c11
-rw-r--r--src/nvim/api/ui.c108
-rw-r--r--src/nvim/api/ui_events.in.h3
-rw-r--r--src/nvim/api/vim.c727
-rw-r--r--src/nvim/api/vim.h2
-rw-r--r--src/nvim/api/window.c23
-rw-r--r--src/nvim/arabic.c879
-rw-r--r--src/nvim/ascii.h8
-rw-r--r--src/nvim/aucmd.c36
-rw-r--r--src/nvim/autocmd.c120
-rw-r--r--src/nvim/buffer.c851
-rw-r--r--src/nvim/buffer.h7
-rw-r--r--src/nvim/buffer_defs.h23
-rw-r--r--src/nvim/buffer_updates.c76
-rw-r--r--src/nvim/change.c237
-rw-r--r--src/nvim/channel.c241
-rw-r--r--src/nvim/channel.h8
-rw-r--r--src/nvim/charset.c519
-rw-r--r--src/nvim/charset.h11
-rw-r--r--src/nvim/context.c4
-rw-r--r--src/nvim/cursor.c92
-rw-r--r--src/nvim/cursor_shape.c92
-rw-r--r--src/nvim/debugger.c837
-rw-r--r--src/nvim/debugger.h11
-rw-r--r--src/nvim/decoration.c107
-rw-r--r--src/nvim/decoration.h21
-rw-r--r--src/nvim/diff.c188
-rw-r--r--src/nvim/digraph.c32
-rw-r--r--src/nvim/edit.c1586
-rw-r--r--src/nvim/eval.c2947
-rw-r--r--src/nvim/eval.h3
-rw-r--r--src/nvim/eval.lua234
-rw-r--r--src/nvim/eval/decode.c984
-rw-r--r--src/nvim/eval/encode.c807
-rw-r--r--src/nvim/eval/executor.c181
-rw-r--r--src/nvim/eval/funcs.c2108
-rw-r--r--src/nvim/eval/funcs.h5
-rw-r--r--src/nvim/eval/gc.c2
-rw-r--r--src/nvim/eval/typval.c1112
-rw-r--r--src/nvim/eval/typval.h73
-rw-r--r--src/nvim/eval/typval_encode.c.h12
-rw-r--r--src/nvim/eval/userfunc.c623
-rw-r--r--src/nvim/eval/userfunc.h26
-rw-r--r--src/nvim/event/libuv_process.c7
-rw-r--r--src/nvim/event/loop.c1
-rw-r--r--src/nvim/event/multiqueue.c7
-rw-r--r--src/nvim/event/process.c98
-rw-r--r--src/nvim/event/process.h1
-rw-r--r--src/nvim/event/rstream.c28
-rw-r--r--src/nvim/event/socket.c38
-rw-r--r--src/nvim/event/stream.c13
-rw-r--r--src/nvim/event/time.c4
-rw-r--r--src/nvim/event/wstream.c12
-rw-r--r--src/nvim/ex_cmds.c1680
-rw-r--r--src/nvim/ex_cmds.lua2
-rw-r--r--src/nvim/ex_cmds2.c1267
-rw-r--r--src/nvim/ex_cmds_defs.h2
-rw-r--r--src/nvim/ex_docmd.c3303
-rw-r--r--src/nvim/ex_docmd.h7
-rw-r--r--src/nvim/ex_eval.c473
-rw-r--r--src/nvim/ex_getln.c1581
-rw-r--r--src/nvim/ex_session.c107
-rw-r--r--src/nvim/extmark.c162
-rw-r--r--src/nvim/extmark_defs.h14
-rw-r--r--src/nvim/file_search.c735
-rw-r--r--src/nvim/fileio.c1735
-rw-r--r--src/nvim/fold.c1174
-rw-r--r--src/nvim/fold.h2
-rw-r--r--src/nvim/garray.c23
-rw-r--r--src/nvim/generators/gen_api_dispatch.lua8
-rw-r--r--src/nvim/generators/gen_eval.lua7
-rw-r--r--src/nvim/generators/gen_options.lua13
-rw-r--r--src/nvim/getchar.c790
-rw-r--r--src/nvim/globals.h104
-rw-r--r--src/nvim/grid_defs.h2
-rw-r--r--src/nvim/hardcopy.c756
-rw-r--r--src/nvim/hashtab.c16
-rw-r--r--src/nvim/highlight.c192
-rw-r--r--src/nvim/highlight_defs.h6
-rw-r--r--src/nvim/indent.c67
-rw-r--r--src/nvim/keymap.c211
-rw-r--r--src/nvim/keymap.h10
-rw-r--r--src/nvim/log.c25
-rw-r--r--src/nvim/log.h2
-rw-r--r--src/nvim/lua/converter.c769
-rw-r--r--src/nvim/lua/executor.c355
-rw-r--r--src/nvim/lua/treesitter.c200
-rw-r--r--src/nvim/lua/vim.lua108
-rw-r--r--src/nvim/lua/xdiff.c332
-rw-r--r--src/nvim/lua/xdiff.h12
-rw-r--r--src/nvim/macros.h6
-rw-r--r--src/nvim/main.c935
-rw-r--r--src/nvim/main.h1
-rw-r--r--src/nvim/map.c73
-rw-r--r--src/nvim/map.h22
-rw-r--r--src/nvim/mark.c536
-rw-r--r--src/nvim/marktree.c49
-rw-r--r--src/nvim/marktree.h4
-rw-r--r--src/nvim/math.c42
-rw-r--r--src/nvim/mbyte.c853
-rw-r--r--src/nvim/memfile.c116
-rw-r--r--src/nvim/memfile_defs.h2
-rw-r--r--src/nvim/memline.c1595
-rw-r--r--src/nvim/memory.c142
-rw-r--r--src/nvim/menu.c478
-rw-r--r--src/nvim/message.c702
-rw-r--r--src/nvim/misc1.c441
-rw-r--r--src/nvim/mouse.c215
-rw-r--r--src/nvim/move.c585
-rw-r--r--src/nvim/msgpack_rpc/channel.c168
-rw-r--r--src/nvim/msgpack_rpc/channel_defs.h2
-rw-r--r--src/nvim/msgpack_rpc/helpers.c414
-rw-r--r--src/nvim/msgpack_rpc/server.c18
-rw-r--r--src/nvim/normal.c2523
-rw-r--r--src/nvim/ops.c1471
-rw-r--r--src/nvim/ops.h7
-rw-r--r--src/nvim/option.c1805
-rw-r--r--src/nvim/option_defs.h26
-rw-r--r--src/nvim/options.lua1134
-rw-r--r--src/nvim/os/dl.c36
-rw-r--r--src/nvim/os/env.c103
-rw-r--r--src/nvim/os/fileio.c38
-rw-r--r--src/nvim/os/fs.c135
-rw-r--r--src/nvim/os/input.c53
-rw-r--r--src/nvim/os/os_win_console.c2
-rw-r--r--src/nvim/os/process.c6
-rw-r--r--src/nvim/os/pty_conpty_win.c110
-rw-r--r--src/nvim/os/pty_process_unix.c14
-rw-r--r--src/nvim/os/pty_process_win.c89
-rw-r--r--src/nvim/os/shell.c97
-rw-r--r--src/nvim/os/signal.c89
-rw-r--r--src/nvim/os/stdpaths.c9
-rw-r--r--src/nvim/os/time.c12
-rw-r--r--src/nvim/os/tty.c9
-rw-r--r--src/nvim/os/users.c13
-rw-r--r--src/nvim/os_unix.c27
-rw-r--r--src/nvim/path.c404
-rw-r--r--src/nvim/plines.c510
-rw-r--r--src/nvim/plines.h9
-rw-r--r--src/nvim/po/sr.po52
-rw-r--r--src/nvim/po/tr.po759
-rw-r--r--src/nvim/popupmnu.c44
-rw-r--r--src/nvim/profile.c15
-rw-r--r--src/nvim/quickfix.c1066
-rw-r--r--src/nvim/rbuffer.c4
-rw-r--r--src/nvim/regexp.c15
-rw-r--r--src/nvim/regexp_nfa.c8
-rw-r--r--src/nvim/runtime.c376
-rw-r--r--src/nvim/runtime.h20
-rw-r--r--src/nvim/screen.c1975
-rw-r--r--src/nvim/search.c2417
-rw-r--r--src/nvim/search.h2
-rw-r--r--src/nvim/sha256.c11
-rw-r--r--src/nvim/shada.c2790
-rw-r--r--src/nvim/sign.c949
-rw-r--r--src/nvim/spell.c1921
-rw-r--r--src/nvim/spellfile.c1768
-rw-r--r--src/nvim/state.c24
-rw-r--r--src/nvim/strings.c15
-rw-r--r--src/nvim/syntax.c2545
-rw-r--r--src/nvim/tag.c126
-rw-r--r--src/nvim/terminal.c39
-rw-r--r--src/nvim/testdir/check.vim11
-rw-r--r--src/nvim/testdir/samples/memfile_test.c4
-rw-r--r--src/nvim/testdir/sautest/autoload/foo.vim4
-rw-r--r--src/nvim/testdir/setup.vim11
-rw-r--r--src/nvim/testdir/test42.inbin2373 -> 2387 bytes
-rw-r--r--src/nvim/testdir/test_alot.vim1
-rw-r--r--src/nvim/testdir/test_arglist.vim4
-rw-r--r--src/nvim/testdir/test_assert.vim2
-rw-r--r--src/nvim/testdir/test_autocmd.vim3
-rw-r--r--src/nvim/testdir/test_autoload.vim2
-rw-r--r--src/nvim/testdir/test_blob.vim349
-rw-r--r--src/nvim/testdir/test_breakindent.vim148
-rw-r--r--src/nvim/testdir/test_bufline.vim8
-rw-r--r--src/nvim/testdir/test_bufwintabinfo.vim2
-rw-r--r--src/nvim/testdir/test_cd.vim20
-rw-r--r--src/nvim/testdir/test_cindent.vim10
-rw-r--r--src/nvim/testdir/test_cmdline.vim19
-rw-r--r--src/nvim/testdir/test_command_count.vim2
-rw-r--r--src/nvim/testdir/test_const.vim33
-rw-r--r--src/nvim/testdir/test_cursorline.vim271
-rw-r--r--src/nvim/testdir/test_debugger.vim11
-rw-r--r--src/nvim/testdir/test_diffmode.vim73
-rw-r--r--src/nvim/testdir/test_display.vim18
-rw-r--r--src/nvim/testdir/test_eval_stuff.vim251
-rw-r--r--src/nvim/testdir/test_ex_z.vim36
-rw-r--r--src/nvim/testdir/test_excmd.vim36
-rw-r--r--src/nvim/testdir/test_expr.vim11
-rw-r--r--src/nvim/testdir/test_filetype.vim117
-rw-r--r--src/nvim/testdir/test_filter_map.vim6
-rw-r--r--src/nvim/testdir/test_float_func.vim27
-rw-r--r--src/nvim/testdir/test_fnamemodify.vim4
-rw-r--r--src/nvim/testdir/test_functions.vim114
-rw-r--r--src/nvim/testdir/test_gf.vim2
-rw-r--r--src/nvim/testdir/test_hide.vim2
-rw-r--r--src/nvim/testdir/test_highlight.vim2
-rw-r--r--src/nvim/testdir/test_ins_complete.vim129
-rw-r--r--src/nvim/testdir/test_ins_complete_no_halt.vim51
-rw-r--r--src/nvim/testdir/test_join.vim2
-rw-r--r--src/nvim/testdir/test_lambda.vim2
-rw-r--r--src/nvim/testdir/test_listchars.vim186
-rw-r--r--src/nvim/testdir/test_listdict.vim4
-rw-r--r--src/nvim/testdir/test_match.vim7
-rw-r--r--src/nvim/testdir/test_method.vim154
-rw-r--r--src/nvim/testdir/test_mksession.vim29
-rw-r--r--src/nvim/testdir/test_modeline.vim10
-rw-r--r--src/nvim/testdir/test_normal.vim2
-rw-r--r--src/nvim/testdir/test_number.vim44
-rw-r--r--src/nvim/testdir/test_options.vim2
-rw-r--r--src/nvim/testdir/test_popup.vim6
-rw-r--r--src/nvim/testdir/test_quickfix.vim130
-rw-r--r--src/nvim/testdir/test_registers.vim80
-rw-r--r--src/nvim/testdir/test_rename.vim1
-rw-r--r--src/nvim/testdir/test_spellfile.vim46
-rw-r--r--src/nvim/testdir/test_startup.vim12
-rw-r--r--src/nvim/testdir/test_swap.vim17
-rw-r--r--src/nvim/testdir/test_syntax.vim6
-rw-r--r--src/nvim/testdir/test_system.vim4
-rw-r--r--src/nvim/testdir/test_tagjump.vim25
-rw-r--r--src/nvim/testdir/test_textformat.vim7
-rw-r--r--src/nvim/testdir/test_textobjects.vim277
-rw-r--r--src/nvim/testdir/test_undo.vim1
-rw-r--r--src/nvim/testdir/test_user_func.vim18
-rw-r--r--src/nvim/testdir/test_usercommands.vim42
-rw-r--r--src/nvim/testdir/test_utf8.vim35
-rw-r--r--src/nvim/testdir/test_vimscript.vim8
-rw-r--r--src/nvim/testdir/test_visual.vim30
-rw-r--r--src/nvim/testdir/test_window_cmd.vim2
-rw-r--r--src/nvim/testdir/test_writefile.vim10
-rw-r--r--src/nvim/testdir/view_util.vim3
-rw-r--r--src/nvim/tui/input.c61
-rw-r--r--src/nvim/tui/terminfo.c15
-rw-r--r--src/nvim/tui/tui.c347
-rw-r--r--src/nvim/ui.c13
-rw-r--r--src/nvim/ui_bridge.c2
-rw-r--r--src/nvim/ui_compositor.c4
-rw-r--r--src/nvim/undo.c394
-rw-r--r--src/nvim/version.c8
-rw-r--r--src/nvim/vim.h14
-rw-r--r--src/nvim/viml/parser/expressions.c3279
-rw-r--r--src/nvim/window.c2155
-rw-r--r--src/uncrustify.cfg3295
-rw-r--r--src/xdiff/COPYING (renamed from src/nvim/xdiff/COPYING)0
-rw-r--r--src/xdiff/README.txt (renamed from src/nvim/xdiff/README.txt)2
-rw-r--r--src/xdiff/xdiff.h (renamed from src/nvim/xdiff/xdiff.h)39
-rw-r--r--src/xdiff/xdiffi.c (renamed from src/nvim/xdiff/xdiffi.c)176
-rw-r--r--src/xdiff/xdiffi.h (renamed from src/nvim/xdiff/xdiffi.h)2
-rw-r--r--src/xdiff/xemit.c (renamed from src/nvim/xdiff/xemit.c)34
-rw-r--r--src/xdiff/xemit.h (renamed from src/nvim/xdiff/xemit.h)2
-rw-r--r--src/xdiff/xhistogram.c (renamed from src/nvim/xdiff/xhistogram.c)16
-rw-r--r--src/xdiff/xinclude.h (renamed from src/nvim/xdiff/xinclude.h)8
-rw-r--r--src/xdiff/xmacros.h (renamed from src/nvim/xdiff/xmacros.h)2
-rw-r--r--src/xdiff/xpatience.c (renamed from src/nvim/xdiff/xpatience.c)53
-rw-r--r--src/xdiff/xprepare.c (renamed from src/nvim/xdiff/xprepare.c)0
-rw-r--r--src/xdiff/xprepare.h (renamed from src/nvim/xdiff/xprepare.h)2
-rw-r--r--src/xdiff/xtypes.h (renamed from src/nvim/xdiff/xtypes.h)2
-rw-r--r--src/xdiff/xutils.c (renamed from src/nvim/xdiff/xutils.c)35
-rw-r--r--src/xdiff/xutils.h (renamed from src/nvim/xdiff/xutils.h)2
-rw-r--r--test/README.md7
-rw-r--r--test/busted/outputHandlers/nvim.lua10
-rw-r--r--test/deprecated.lua9
-rw-r--r--test/functional/api/buffer_updates_spec.lua10
-rw-r--r--test/functional/api/command_spec.lua4
-rw-r--r--test/functional/api/extmark_spec.lua5
-rw-r--r--test/functional/api/server_notifications_spec.lua13
-rw-r--r--test/functional/api/server_requests_spec.lua5
-rw-r--r--test/functional/api/vim_spec.lua85
-rw-r--r--test/functional/api/window_spec.lua38
-rw-r--r--test/functional/autocmd/focus_spec.lua (renamed from test/functional/autoread/focus_spec.lua)0
-rw-r--r--test/functional/autocmd/tabnewentered_spec.lua32
-rw-r--r--test/functional/autocmd/termxx_spec.lua13
-rw-r--r--test/functional/cmdline/ctrl_r_spec.lua34
-rw-r--r--test/functional/core/channels_spec.lua5
-rw-r--r--test/functional/core/exit_spec.lua14
-rw-r--r--test/functional/core/job_spec.lua9
-rw-r--r--test/functional/core/startup_spec.lua69
-rw-r--r--test/functional/editor/K_spec.lua (renamed from test/functional/normal/K_spec.lua)6
-rw-r--r--test/functional/editor/completion_spec.lua (renamed from test/functional/viml/completion_spec.lua)3
-rw-r--r--test/functional/editor/count_spec.lua (renamed from test/functional/normal/count_spec.lua)0
-rw-r--r--test/functional/editor/fold_spec.lua (renamed from test/functional/normal/fold_spec.lua)0
-rw-r--r--test/functional/editor/jump_spec.lua (renamed from test/functional/normal/jump_spec.lua)18
-rw-r--r--test/functional/editor/lang_spec.lua (renamed from test/functional/normal/lang_spec.lua)0
-rw-r--r--test/functional/editor/langmap_spec.lua (renamed from test/functional/normal/langmap_spec.lua)0
-rw-r--r--test/functional/editor/macro_spec.lua (renamed from test/functional/normal/macro_spec.lua)0
-rw-r--r--test/functional/editor/meta_key_spec.lua (renamed from test/functional/insert/insert_spec.lua)38
-rw-r--r--test/functional/editor/mode_cmdline_spec.lua (renamed from test/functional/cmdline/history_spec.lua)39
-rw-r--r--test/functional/editor/mode_insert_spec.lua89
-rw-r--r--test/functional/editor/mode_visual_spec.lua27
-rw-r--r--test/functional/editor/put_spec.lua (renamed from test/functional/normal/put_spec.lua)0
-rw-r--r--test/functional/editor/search_spec.lua (renamed from test/functional/normal/search_spec.lua)0
-rw-r--r--test/functional/editor/tabpage_spec.lua (renamed from test/functional/normal/tabpage_spec.lua)0
-rw-r--r--test/functional/editor/undo_spec.lua (renamed from test/functional/normal/undo_spec.lua)0
-rw-r--r--test/functional/eval/backtick_expansion_spec.lua50
-rw-r--r--test/functional/eval/function_spec.lua37
-rw-r--r--test/functional/eval/interrupt_spec.lua61
-rw-r--r--test/functional/ex_cmds/dict_notifications_spec.lua5
-rw-r--r--test/functional/ex_cmds/drop_spec.lua1
-rw-r--r--test/functional/ex_cmds/echo_spec.lua30
-rw-r--r--test/functional/ex_cmds/mksession_spec.lua9
-rw-r--r--test/functional/ex_cmds/quickfix_commands_spec.lua11
-rw-r--r--test/functional/ex_cmds/source_spec.lua61
-rw-r--r--test/functional/ex_cmds/swapfile_preserve_recover_spec.lua3
-rw-r--r--test/functional/ex_cmds/write_spec.lua18
-rw-r--r--test/functional/fixtures/fake-lsp-server.lua116
-rw-r--r--test/functional/fixtures/middle/filen.lua1
-rw-r--r--test/functional/fixtures/nvim/after/filen.lua1
-rw-r--r--test/functional/fixtures/nvim/filen.lua1
-rw-r--r--test/functional/fixtures/pack/foo/opt/funky/filen.lua12
-rw-r--r--test/functional/fixtures/pack/foo/opt/superspecial/after/filen.lua1
-rw-r--r--test/functional/fixtures/pack/foo/opt/superspecial/filen.lua1
-rw-r--r--test/functional/fixtures/pack/foo/start/fancyplugin/after/filen.lua1
-rw-r--r--test/functional/fixtures/pack/foo/start/fancyplugin/filen.lua1
-rw-r--r--test/functional/fixtures/shell-test.c17
-rw-r--r--test/functional/helpers.lua27
-rw-r--r--test/functional/insert/ctrl_o_spec.lua54
-rw-r--r--test/functional/insert/ctrl_r_spec.lua19
-rw-r--r--test/functional/legacy/007_ball_buffer_list_spec.lua5
-rw-r--r--test/functional/legacy/008_autocommands_spec.lua3
-rw-r--r--test/functional/legacy/011_autocommands_spec.lua4
-rw-r--r--test/functional/legacy/012_directory_spec.lua1
-rw-r--r--test/functional/legacy/063_match_and_matchadd_spec.lua24
-rw-r--r--test/functional/legacy/arglist_spec.lua2
-rw-r--r--test/functional/legacy/assert_spec.lua65
-rw-r--r--test/functional/legacy/autocmd_option_spec.lua6
-rw-r--r--test/functional/legacy/cdo_spec.lua4
-rw-r--r--test/functional/legacy/eval_spec.lua6
-rw-r--r--test/functional/legacy/fixeol_spec.lua4
-rw-r--r--test/functional/legacy/listchars_spec.lua2
-rw-r--r--test/functional/legacy/memory_usage_spec.lua3
-rw-r--r--test/functional/legacy/mksession_spec.lua2
-rw-r--r--test/functional/lua/api_spec.lua7
-rw-r--r--test/functional/lua/buffer_updates_spec.lua16
-rw-r--r--test/functional/lua/commands_spec.lua44
-rw-r--r--test/functional/lua/diagnostic_spec.lua1147
-rw-r--r--test/functional/lua/highlight_spec.lua25
-rw-r--r--test/functional/lua/json_spec.lua133
-rw-r--r--test/functional/lua/luaeval_spec.lua56
-rw-r--r--test/functional/lua/mpack_spec.lua23
-rw-r--r--test/functional/lua/overrides_spec.lua47
-rw-r--r--test/functional/lua/ui_spec.lua46
-rw-r--r--test/functional/lua/uri_spec.lua32
-rw-r--r--test/functional/lua/vim_spec.lua122
-rw-r--r--test/functional/lua/xdiff_spec.lua112
-rw-r--r--test/functional/normal/meta_key_spec.lua22
-rw-r--r--test/functional/options/defaults_spec.lua28
-rw-r--r--test/functional/options/tabstop_spec.lua5
-rw-r--r--test/functional/plugin/lsp/codelens_spec.lua32
-rw-r--r--test/functional/plugin/lsp/diagnostic_spec.lua214
-rw-r--r--test/functional/plugin/lsp/snippet_spec.lua152
-rw-r--r--test/functional/plugin/lsp_spec.lua613
-rw-r--r--test/functional/plugin/shada_spec.lua6
-rw-r--r--test/functional/provider/clipboard_spec.lua2
-rw-r--r--test/functional/provider/python3_spec.lua3
-rw-r--r--test/functional/provider/ruby_spec.lua4
-rw-r--r--test/functional/shada/errors_spec.lua5
-rw-r--r--test/functional/shada/history_spec.lua4
-rw-r--r--test/functional/shada/marks_spec.lua6
-rw-r--r--test/functional/shada/merging_spec.lua12
-rw-r--r--test/functional/shada/variables_spec.lua8
-rw-r--r--test/functional/terminal/buffer_spec.lua23
-rw-r--r--test/functional/terminal/ex_terminal_spec.lua3
-rw-r--r--test/functional/terminal/tui_spec.lua4
-rw-r--r--test/functional/terminal/window_split_tab_spec.lua3
-rw-r--r--test/functional/treesitter/highlight_spec.lua43
-rw-r--r--test/functional/treesitter/node_spec.lua62
-rw-r--r--test/functional/treesitter/parser_spec.lua37
-rw-r--r--test/functional/ui/bufhl_spec.lua22
-rw-r--r--test/functional/ui/cmdline_spec.lua4
-rw-r--r--test/functional/ui/cursor_spec.lua4
-rw-r--r--test/functional/ui/decorations_spec.lua602
-rw-r--r--test/functional/ui/diff_spec.lua73
-rw-r--r--test/functional/ui/float_spec.lua338
-rw-r--r--test/functional/ui/fold_spec.lua2
-rw-r--r--test/functional/ui/highlight_spec.lua162
-rw-r--r--test/functional/ui/inccommand_spec.lua23
-rw-r--r--test/functional/ui/mouse_spec.lua124
-rw-r--r--test/functional/ui/multigrid_spec.lua171
-rw-r--r--test/functional/ui/output_spec.lua6
-rw-r--r--test/functional/ui/popupmenu_spec.lua4
-rw-r--r--test/functional/ui/screen.lua7
-rw-r--r--test/functional/ui/sign_spec.lua28
-rw-r--r--test/functional/ui/syntax_conceal_spec.lua42
-rw-r--r--test/functional/ui/tabline_spec.lua1
-rw-r--r--test/functional/viml/function_spec.lua216
-rw-r--r--test/functional/vimscript/api_functions_spec.lua (renamed from test/functional/eval/api_functions_spec.lua)9
-rw-r--r--test/functional/vimscript/buf_functions_spec.lua (renamed from test/functional/eval/buf_functions_spec.lua)10
-rw-r--r--test/functional/vimscript/changedtick_spec.lua (renamed from test/functional/eval/changedtick_spec.lua)85
-rw-r--r--test/functional/vimscript/container_functions_spec.lua (renamed from test/functional/eval/container_functions_spec.lua)0
-rw-r--r--test/functional/vimscript/ctx_functions_spec.lua (renamed from test/functional/eval/ctx_functions_spec.lua)38
-rw-r--r--test/functional/vimscript/environ_spec.lua (renamed from test/functional/eval/environ_spec.lua)0
-rw-r--r--test/functional/vimscript/errorlist_spec.lua (renamed from test/functional/viml/errorlist_spec.lua)0
-rw-r--r--test/functional/vimscript/eval_spec.lua146
-rw-r--r--test/functional/vimscript/executable_spec.lua (renamed from test/functional/eval/executable_spec.lua)0
-rw-r--r--test/functional/vimscript/execute_spec.lua (renamed from test/functional/eval/execute_spec.lua)18
-rw-r--r--test/functional/vimscript/exepath_spec.lua (renamed from test/functional/eval/exepath_spec.lua)0
-rw-r--r--test/functional/vimscript/fnamemodify_spec.lua (renamed from test/functional/eval/fnamemodify_spec.lua)0
-rw-r--r--test/functional/vimscript/functions_spec.lua20
-rw-r--r--test/functional/vimscript/getline_spec.lua (renamed from test/functional/eval/getline_spec.lua)0
-rw-r--r--test/functional/vimscript/glob_spec.lua (renamed from test/functional/eval/glob_spec.lua)0
-rw-r--r--test/functional/vimscript/has_spec.lua (renamed from test/functional/eval/has_spec.lua)0
-rw-r--r--test/functional/vimscript/hostname_spec.lua (renamed from test/functional/eval/hostname_spec.lua)0
-rw-r--r--test/functional/vimscript/input_spec.lua (renamed from test/functional/eval/input_spec.lua)0
-rw-r--r--test/functional/vimscript/json_functions_spec.lua (renamed from test/functional/eval/json_functions_spec.lua)16
-rw-r--r--test/functional/vimscript/lang_spec.lua (renamed from test/functional/viml/lang_spec.lua)2
-rw-r--r--test/functional/vimscript/let_spec.lua (renamed from test/functional/eval/let_spec.lua)10
-rw-r--r--test/functional/vimscript/map_functions_spec.lua (renamed from test/functional/eval/map_functions_spec.lua)0
-rw-r--r--test/functional/vimscript/match_functions_spec.lua (renamed from test/functional/eval/match_functions_spec.lua)15
-rw-r--r--test/functional/vimscript/minmax_functions_spec.lua (renamed from test/functional/eval/minmax_functions_spec.lua)30
-rw-r--r--test/functional/vimscript/modeline_spec.lua (renamed from test/functional/eval/modeline_spec.lua)4
-rw-r--r--test/functional/vimscript/msgpack_functions_spec.lua (renamed from test/functional/eval/msgpack_functions_spec.lua)135
-rw-r--r--test/functional/vimscript/null_spec.lua (renamed from test/functional/eval/null_spec.lua)22
-rw-r--r--test/functional/vimscript/operators_spec.lua (renamed from test/functional/eval/operators_spec.lua)0
-rw-r--r--test/functional/vimscript/printf_spec.lua (renamed from test/functional/eval/printf_spec.lua)0
-rw-r--r--test/functional/vimscript/reltime_spec.lua (renamed from test/functional/eval/reltime_spec.lua)0
-rw-r--r--test/functional/vimscript/server_spec.lua (renamed from test/functional/eval/server_spec.lua)0
-rw-r--r--test/functional/vimscript/setpos_spec.lua (renamed from test/functional/eval/setpos_spec.lua)0
-rw-r--r--test/functional/vimscript/sort_spec.lua (renamed from test/functional/eval/sort_spec.lua)7
-rw-r--r--test/functional/vimscript/special_vars_spec.lua (renamed from test/functional/eval/special_vars_spec.lua)0
-rw-r--r--test/functional/vimscript/string_spec.lua (renamed from test/functional/eval/string_spec.lua)44
-rw-r--r--test/functional/vimscript/system_spec.lua (renamed from test/functional/eval/system_spec.lua)7
-rw-r--r--test/functional/vimscript/timer_spec.lua (renamed from test/functional/eval/timer_spec.lua)0
-rw-r--r--test/functional/vimscript/uniq_spec.lua (renamed from test/functional/eval/uniq_spec.lua)8
-rw-r--r--test/functional/vimscript/vvar_event_spec.lua (renamed from test/functional/eval/vvar_event_spec.lua)0
-rw-r--r--test/functional/vimscript/wait_spec.lua (renamed from test/functional/eval/wait_spec.lua)0
-rw-r--r--test/functional/vimscript/writefile_spec.lua (renamed from test/functional/eval/writefile_spec.lua)59
-rw-r--r--test/functional/visual/meta_key_spec.lua22
-rw-r--r--test/helpers.lua14
-rw-r--r--test/unit/charset/vim_str2nr_spec.lua240
-rw-r--r--test/unit/eval/typval_spec.lua16
-rw-r--r--test/unit/undo_spec.lua2
-rw-r--r--test/unit/viml/expressions/parser_spec.lua58
-rw-r--r--third-party/CMakeLists.txt20
-rw-r--r--third-party/cmake/BuildLuarocks.cmake7
-rw-r--r--third-party/cmake/BuildLuv.cmake1
-rw-r--r--third-party/cmake/DownloadAndExtractFile.cmake75
721 files changed, 68466 insertions, 42841 deletions
diff --git a/.clang-format b/.clang-format
index ff61915aac..c86f5a3ddf 100644
--- a/.clang-format
+++ b/.clang-format
@@ -1,6 +1,6 @@
BasedOnStyle: Google
Language: Cpp
-ColumnLimit: 80
+ColumnLimit: 100
IndentWidth: 2
TabWidth: 2
UseTab: Never
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
new file mode 100644
index 0000000000..e5ee140301
--- /dev/null
+++ b/.git-blame-ignore-revs
@@ -0,0 +1,31 @@
+# To use this file (requires git 2.23):
+# git config blame.ignoreRevsFile .git-blame-ignore-revs
+
+# eval.c: factor out eval/funcs.c #11828
+# - This is a move/rename. git 2.33 doesn't know how to ignore it.
+# It is here anyway, (1) in case git improves later, and (2) to
+# save you the trouble of attempting this.
+6c5bbf07d988ef55e5e8ba8d70b62c1f0885261b
+
+# symbol renames
+6186df3562e33e92f04ed8c850204ceabc4746e1
+
+# style (uncrustify, etc.)
+2d240024acbd68c2d3f82bc72cb12b1a4928c6bf
+61178778230e609d68b271ffd53ffd993cd23c42
+15af08ad176339d1f269ce264bb0efea283c9536
+47f99d66440ae8be26b34531989ac61edc1ad9fe
+1e49a1c888a3d9a581f4aa409a26ada3ac2417cb
+3b3dbcf7b7ba5466e6ab643e256f2374b520a6b2
+e8067d1490a31ff76143d576dc9948b4f09c6c55
+d5b66e88601b4d2fde5d905f9d12847126ba4449
+07715044887d82f74254e64c4c32fa49b0501bea
+6ed43f8f1caad702f9590d174c5ec142f3d85b18
+0a83017fe95df0290adb98ec6bf457b96a3fab17
+867e8885991ae450019c18aa5e42546bd4b62c2c
+1f49268c46fcbe65f7e2e2cb620e6f51c059cf9e
+51a98aa0c2fe3231a0ffc8a78189bc6fafd6abf6
+853346a94d6aa78c97314a3b217fb5a5408a47f1
+30fefee684e641a0c6867446c6de30efa2f0a126
+f4ca3a29ddcb0c98e8e09c45a6342af709f8cc45
+48e67b229415b4e2b3315bd00b817e5f9ab970c8
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
deleted file mode 100644
index ae30f00f31..0000000000
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-name: Bug report
-about: Report a problem in Nvim
-title: ''
-labels: bug
-
----
-
-<!-- Before reporting: search existing issues and check the FAQ. -->
-
-- `nvim --version`:
-- Operating system/version:
-- Terminal name/version:
-- `$TERM`:
-
-<!--
-If this report is about different behaviour between Nvim and Vim, make sure to
-read `:h vim-differences` first. Otherwise remove the next line.
--->
-[ ] `vim -u DEFAULTS` (version: ) behaves differently
-
-### Steps to reproduce using `nvim -u NORC`
-
-```
-nvim -u NORC
-# Alternative for shell-related problems:
-# env -i TERM=ansi-256color "$(which nvim)"
-
-```
-
-### Actual behaviour
-
-### Expected behaviour
-
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 0000000000..fa8d05f6b5
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,75 @@
+name: Bug Report
+description: Report a problem in Neovim
+labels: [bug]
+body:
+
+ - type: markdown
+ attributes:
+ value: |
+ _Before reporting:_ search [existing issues](https://github.com/neovim/neovim/issues?q=is%3Aissue+is%3Aopen+label%3Abug) and check the [FAQ](https://github.com/neovim/neovim/wiki/FAQ). Usage questions such as "How do I...?" belong on the [Neovim Discourse](https://neovim.discourse.group/c/7-category/7) and will be closed.
+
+ - type: input
+ attributes:
+ label: "Neovim version (nvim -v)"
+ placeholder: "0.6.0 commit db1b0ee3b30f"
+ validations:
+ required: true
+ - type: input
+ attributes:
+ label: "Vim (not Nvim) behaves the same?"
+ description: "Does `vim -u DEFAULTS` have the same issue? Note the exact Vim version (`8.x.yyyy`)."
+ placeholder: "no, vim 7.3.432"
+ validations:
+ required: true
+ - type: input
+ attributes:
+ label: "Operating system/version"
+ placeholder: "macOS 11.5"
+ validations:
+ required: true
+ - type: input
+ attributes:
+ label: "Terminal name/version"
+ placeholder: "xterm 3.1"
+ validations:
+ required: true
+ - type: input
+ attributes:
+ label: "$TERM environment variable"
+ placeholder: "echo $TERM"
+ validations:
+ required: true
+
+ - type: input
+ attributes:
+ label: "Installation"
+ description: "How did you install neovim: build from repo / system package manager / appimage / homebrew / snap / chocolatey / other (describe)?"
+ placeholder: "Arch User Repository (AUR)"
+ validations:
+ required: true
+
+ - type: textarea
+ attributes:
+ label: "How to reproduce the issue"
+ description: |
+ - Steps to reproduce using `nvim -u NORC` or `nvim -u NONE` (try both).
+ - For build failures: list the exact steps including CMake flags (if any).
+ - For shell-related problems: try `env -i TERM=ansi-256color "$(which nvim)"`.
+ placeholder: |
+ nvim -u NONE
+ :edit foo
+ yiwp
+ validations:
+ required: true
+
+ - type: textarea
+ attributes:
+ label: "Expected behavior"
+ description: "Describe the behavior you expect. May include logs, images, or videos."
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: "Actual behavior"
+ validations:
+ required: true
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000000..796707be03
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,5 @@
+blank_issues_enabled: true
+contact_links:
+ - name: Question
+ url: https://neovim.discourse.group/
+ about: Ask questions about configuration and usage of Neovim
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
deleted file mode 100644
index 928cde894c..0000000000
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-name: Feature request
-about: Request an enhancement for Nvim
-title: ''
-labels: enhancement
-
----
-
-<!-- Before reporting: search existing issues and check the FAQ. -->
-
-- `nvim --version`:
-- `vim -u DEFAULTS` (version: ) behaves differently?
-- Operating system/version:
-- Terminal name/version:
-- `$TERM`:
-
-### Steps to reproduce using `nvim -u NORC`
-
-```
-nvim -u NORC
-
-```
-
-### Actual behaviour
-
-### Expected behaviour
-
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
new file mode 100644
index 0000000000..2b6fa3daf4
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -0,0 +1,21 @@
+name: Feature request
+description: Request an enhancement for Neovim
+labels: [enhancement]
+body:
+
+ - type: markdown
+ attributes:
+ value: |
+ Before requesting: search [existing issues](https://github.com/neovim/neovim/labels/enhancement) and check the [FAQ](https://github.com/neovim/neovim/wiki/FAQ).
+
+ - type: input
+ attributes:
+ label: "Feature already in Vim?"
+ description: "Does the feature already exist in Vim? If possible, specify which version (or commit) that introduced it."
+ placeholder: "Yes, Vim 7.3.432"
+
+ - type: textarea
+ attributes:
+ label: "Feature description"
+ validations:
+ required: true
diff --git a/.github/ISSUE_TEMPLATE/lsp_bug_report.md b/.github/ISSUE_TEMPLATE/lsp_bug_report.md
deleted file mode 100644
index d2488a14e8..0000000000
--- a/.github/ISSUE_TEMPLATE/lsp_bug_report.md
+++ /dev/null
@@ -1,58 +0,0 @@
----
-name: Language server client bug report
-about: Report a built-in lsp problem in Nvim
-title: ''
-labels: bug, lsp
-
----
-
-<!--
-Before reporting: search existing issues and check the FAQ. Usage questions
-such as "How do I...?" or "Why isn't X language server/feature working?" belong
-on the [Neovim Discourse](https://neovim.discourse.group/c/7-category/7) and will
-be closed.
--->
-
-- `nvim --version`:
-- language server name/version:
-- Operating system/version:
-
-<details>
-<summary>nvim -c ":checkhealth nvim lspconfig"</summary>
-
-<!-- Paste the results from `nvim -c ":checkhealth nvim lspconfig"` here. -->
-
-</details>
-
-<details>
-<summary>lsp.log</summary>
-
-<!--
-Please paste the lsp log before and after the problem.
-
-You can set log level like this.
-`:lua vim.lsp.set_log_level("debug")`
-
-You can find the location of the log with the following command.
-`:lua print(vim.lsp.get_log_path())`
--->
-
-</details>
-
-### Steps to reproduce using nvim -u minimal_init.lua
-<!--
- Note, if the issue is with an autocompletion or other LSP plugin, please
- report to the upstream tracker. Download the minmal config with
- wget https://raw.githubusercontent.com/neovim/nvim-lspconfig/master/test/minimal_init.lua
- and modify it to include any specific commands or servers pertaining to your issues.
--->
-
-
-```
-nvim -u minimal_init.lua
-```
-
-### Actual behaviour
-
-### Expected behaviour
-
diff --git a/.github/ISSUE_TEMPLATE/lsp_bug_report.yml b/.github/ISSUE_TEMPLATE/lsp_bug_report.yml
new file mode 100644
index 0000000000..b5b7687bf8
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/lsp_bug_report.yml
@@ -0,0 +1,61 @@
+name: Language server (LSP) client bug
+description: Report an issue with Neovim LSP
+labels: [bug, lsp]
+body:
+
+ - type: markdown
+ attributes:
+ value: |
+ _Before reporting:_ search [existing issues](https://github.com/neovim/neovim/issues?q=is%3Aissue+is%3Aopen+label%3Abug) and check the [FAQ](https://github.com/neovim/neovim/wiki/FAQ). Usage questions such as "How do I...?" or "Why isn't X language server/feature working?" belong on the [Neovim Discourse](https://neovim.discourse.group/c/7-category/7) and will be closed.
+
+ - type: input
+ attributes:
+ label: "Neovim version (nvim -v)"
+ placeholder: "0.6.0 commit db1b0ee3b30f"
+ validations:
+ required: true
+ - type: input
+ attributes:
+ label: "Language server name/version"
+ placeholder: "rls 0.5.2"
+ validations:
+ required: true
+ - type: input
+ attributes:
+ label: "Operating system/version"
+ placeholder: "emacs 23"
+ validations:
+ required: true
+
+ - type: textarea
+ attributes:
+ label: ':checkhealth'
+ description: |
+ Paste the results from `nvim -c ":checkhealth nvim lspconfig"`
+ render: markdown
+
+ - type: textarea
+ attributes:
+ label: 'Steps to reproduce using "nvim -u minimal_init.lua"'
+ description: |
+ - Download the minimal config with `curl -LO https://raw.githubusercontent.com/neovim/nvim-lspconfig/master/test/minimal_init.lua` and modify it to include any specific commands or servers pertaining to your issues.
+ - _Note_: if the issue is with an autocompletion or other LSP plugin, report to that plugin's issue tracker.
+ validations:
+ required: true
+
+ - type: textarea
+ attributes:
+ label: "Expected behavior"
+ description: "Describe the behavior you expect. May include logs, images, or videos."
+ - type: textarea
+ attributes:
+ label: "Actual behavior"
+
+ - type: input
+ attributes:
+ label: "Log file"
+ placeholder: "https://gist.github.com/prakhar1989/1b0a2c9849b2e1e912fb"
+ description: |
+ - Upload `lsp.log` before and after the problem in a [secret gist](https://gist.github.com/). Paste the URL to the gist.
+ - You can set the log level by adding `vim.lsp.set_log_level("debug")` after setting up LSP in your config.
+ - You can find the location of the log with `:lua print(vim.lsp.get_log_path())`
diff --git a/.github/labeler.yml b/.github/labeler.yml
index 282c6b1e7c..52998c65cf 100644
--- a/.github/labeler.yml
+++ b/.github/labeler.yml
@@ -4,7 +4,7 @@
"lua":
- runtime/lua/**/*
- - src/nvim/lua
+ - src/nvim/lua/*
"tui":
- src/nvim/tui/tui.*
@@ -14,36 +14,48 @@
- runtime/lua/vim/treesitter.lua
- runtime/lua/vim/treesitter/*
+"diagnostic":
+ - runtime/lua/vim/diagnostic.lua
+
"dependencies":
- third-party/**/*
-"topic: spell":
+"spell":
- src/nvim/spell*
-"topic: :terminal":
+"terminal":
- src/nvim/terminal.*
-"topic: column":
+"column":
- src/nvim/mark.h
- src/nvim/mark.c
- src/nvim/sign*
-"topic: folds":
+"folds":
- src/nvim/fold*
-"topic: mouse":
+"mouse":
- src/nvim/mouse*
-"topic: documentation":
- - runtime/doc/*
+"documentation":
+ - all: ["runtime/doc/*"]
-"topic: clipboard":
+"clipboard":
- runtime/autoload/provider/clipboard.vim
-"topic: diff":
+"diff":
- src/nvim/diff.*
-"topic: build":
+"build":
- CMakeLists.txt
- "**/CMakeLists.txt"
- "**/*.cmake"
+
+"tests":
+ - all: ["test/**/*"]
+
+"ci":
+ - .github/labeler.yml
+ - .github/workflows/**/*
+ - .builds/*
+ - ci/**/*
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index aa16a94802..0dbe484108 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -3,13 +3,14 @@ on:
push:
branches: '**'
pull_request:
+ types: [opened, synchronize, reopened, ready_for_review]
branches:
- 'master'
- 'release-[0-9]+.[0-9]+'
jobs:
unixish:
- name: ${{ matrix.os }} ${{ matrix.flavor }} (cc=${{ matrix.cc }})
+ name: ${{ matrix.runner }} ${{ matrix.flavor }} (cc=${{ matrix.cc }})
strategy:
fail-fast: false
matrix:
@@ -29,11 +30,15 @@ jobs:
- cc: clang
runner: macos-10.15
os: osx
+ - cc: clang
+ runner: macos-11.0
+ os: osx
- flavor: functionaltest-lua
cc: gcc
runner: ubuntu-20.04
os: linux
runs-on: ${{ matrix.runner }}
+ timeout-minutes: 45
if: github.event.pull_request.draft == false
env:
CC: ${{ matrix.cc }}
@@ -78,7 +83,7 @@ jobs:
path: |
${{ env.CACHE_NVIM_DEPS_DIR }}
~/.ccache
- key: ${{ runner.os }}-${{ matrix.flavor }}-${{ matrix.cc }}-${{ hashFiles('cmake/*', 'third-party/**', '**/CMakeLists.txt') }}-${{ github.base_ref }}
+ key: ${{ matrix.runner }}-${{ matrix.flavor }}-${{ matrix.cc }}-${{ hashFiles('cmake/*', 'third-party/**', '**/CMakeLists.txt') }}-${{ github.base_ref }}
- name: Build third-party
run: ./ci/before_script.sh
diff --git a/.github/workflows/commitlint.yml b/.github/workflows/commitlint.yml
new file mode 100644
index 0000000000..4c9c526946
--- /dev/null
+++ b/.github/workflows/commitlint.yml
@@ -0,0 +1,16 @@
+name: "Commit Linter"
+on: pull_request
+jobs:
+ lint-commits:
+ runs-on: ubuntu-latest
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ steps:
+ - uses: actions/checkout@v2.3.1
+ with:
+ fetch-depth: 0
+ - uses: rhysd/action-setup-vim@v1
+ with:
+ neovim: true
+ - run: gh pr checkout ${{ github.event.pull_request.number }}
+ - run: nvim --clean -es +"lua require('scripts.lintcommit').main({trace=true})"
diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml
index 909e197b57..c7a331c657 100644
--- a/.github/workflows/labeler.yml
+++ b/.github/workflows/labeler.yml
@@ -1,6 +1,7 @@
name: "Pull Request Labeler"
on:
-- pull_request_target
+ pull_request_target:
+ types: opened
jobs:
triage:
runs-on: ubuntu-latest
@@ -11,3 +12,19 @@ jobs:
- uses: actions/labeler@main
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
+ type-scope:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write
+ pull-requests: write
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ steps:
+ - uses: actions/checkout@v2.3.1
+ - run: gh pr checkout ${{ github.event.pull_request.number }}
+
+ # Extract type and try to add it as a label
+ - run: gh pr edit --add-label "$(echo "${{ github.event.pull_request.title }}" | sed -E 's|([[:alpha:]]+)(\(.*\))?:.*|\1|')" || true
+
+ # Extract scope and try to add it as a label
+ - run: gh pr edit --add-label "$(echo "${{ github.event.pull_request.title }}" | sed -E 's|[[:alpha:]]+\((.+)\):.*|\1|')" || true
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index ff7562bf20..c6d3eaf42b 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -28,10 +28,14 @@ jobs:
run: |
sudo apt-get update
sudo apt-get install -y autoconf automake build-essential cmake gcc-11 gettext gperf libtool-bin locales ninja-build pkg-config unzip
+ - if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.event.inputs.tag_name != 'nightly')
+ run: printf 'NVIM_BUILD_TYPE=Release\n' >> $GITHUB_ENV
+ - if: github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.tag_name == 'nightly')
+ run: printf 'NVIM_BUILD_TYPE=RelWithDebInfo\n' >> $GITHUB_ENV
- name: Build release
id: build
run: |
- CC=gcc-11 make CMAKE_BUILD_TYPE=RelWithDebInfo CMAKE_EXTRA_FLAGS="-DCMAKE_INSTALL_PREFIX:PATH="
+ CC=gcc-11 make CMAKE_BUILD_TYPE=${NVIM_BUILD_TYPE} CMAKE_EXTRA_FLAGS="-DCMAKE_INSTALL_PREFIX:PATH="
printf '::set-output name=version::%s\n' "$(./build/bin/nvim --version | head -n 3 | sed -z 's/\n/%0A/g')"
printf '::set-output name=release::%s\n' "$(./build/bin/nvim --version | head -n 1)"
make DESTDIR="$GITHUB_WORKSPACE/build/release/nvim-linux64" install
@@ -80,9 +84,13 @@ jobs:
brew update >/dev/null
brew upgrade
brew install automake ninja
+ - if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.event.inputs.tag_name != 'nightly')
+ run: printf 'NVIM_BUILD_TYPE=Release\n' >> $GITHUB_ENV
+ - if: github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.tag_name == 'nightly')
+ run: printf 'NVIM_BUILD_TYPE=RelWithDebInfo\n' >> $GITHUB_ENV
- name: Build release
run: |
- make CMAKE_BUILD_TYPE=Release CMAKE_EXTRA_FLAGS="-DCMAKE_INSTALL_PREFIX:PATH= -DCMAKE_OSX_DEPLOYMENT_TARGET=10.11"
+ make CMAKE_BUILD_TYPE=${NVIM_BUILD_TYPE} CMAKE_EXTRA_FLAGS="-DCMAKE_INSTALL_PREFIX:PATH= -DCMAKE_OSX_DEPLOYMENT_TARGET=10.11"
make DESTDIR="$GITHUB_WORKSPACE/build/release/nvim-osx64" install
- name: Create package
run: |
diff --git a/.github/workflows/squash-typos.yml b/.github/workflows/squash-typos.yml
new file mode 100644
index 0000000000..6779589dc6
--- /dev/null
+++ b/.github/workflows/squash-typos.yml
@@ -0,0 +1,33 @@
+name: Squash Typo Pull Requests
+
+on:
+ pull_request_target:
+ types: labeled
+concurrency:
+ group: ${{ github.workflow }}
+jobs:
+ build:
+ if: github.event.label.name == 'typo'
+ runs-on: ubuntu-latest
+
+ permissions:
+ contents: write
+ pull-requests: write
+
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+ - uses: actions/setup-python@v2
+
+ - name: Setup git config
+ run: |
+ git config --global user.name 'marvim'
+ git config --global user.email 'marvim@users.noreply.github.com'
+
+ - run: python scripts/squash_typos.py
+ env:
+ PR_NUMBER: ${{ github.event.number }}
diff --git a/.gitignore b/.gitignore
index 163140c6e1..e07ce4906e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,6 +13,7 @@ compile_commands.json
/tmp/
/.clangd/
/.cache/clangd/
+/.ccls-cache/
.DS_Store
*.mo
diff --git a/.luacheckrc b/.luacheckrc
index a628daed80..487f5ab552 100644
--- a/.luacheckrc
+++ b/.luacheckrc
@@ -25,3 +25,7 @@ ignore = {
read_globals = {
"vim",
}
+
+exclude_files = {
+ 'test/functional/fixtures/lua/syntax_error.lua',
+}
diff --git a/BSDmakefile b/BSDmakefile
index 93b7dc7f3d..f81223bafa 100644
--- a/BSDmakefile
+++ b/BSDmakefile
@@ -1,4 +1,4 @@
.DONE:
- @echo "Please use GNU Make (gmake) to build neovim"
+ @echo "Use GNU Make (gmake) to build neovim"
.DEFAULT:
- @echo "Please use GNU Make (gmake) to build neovim"
+ @echo "Use GNU Make (gmake) to build neovim"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 707079fc77..26c60ffbf1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -136,14 +136,14 @@ set_property(CACHE CMAKE_BUILD_TYPE PROPERTY
# If not in a git repo (e.g., a tarball) these tokens define the complete
# version string, else they are combined with the result of `git describe`.
set(NVIM_VERSION_MAJOR 0)
-set(NVIM_VERSION_MINOR 5)
+set(NVIM_VERSION_MINOR 6)
set(NVIM_VERSION_PATCH 0)
-set(NVIM_VERSION_PRERELEASE "") # for package maintainers
+set(NVIM_VERSION_PRERELEASE "-dev") # for package maintainers
# API level
-set(NVIM_API_LEVEL 7) # Bump this after any API change.
+set(NVIM_API_LEVEL 8) # Bump this after any API change.
set(NVIM_API_LEVEL_COMPAT 0) # Adjust this after a _breaking_ API change.
-set(NVIM_API_PRERELEASE false)
+set(NVIM_API_PRERELEASE true)
set(NVIM_VERSION_BUILD_TYPE "${CMAKE_BUILD_TYPE}")
# NVIM_VERSION_CFLAGS set further below.
@@ -691,7 +691,7 @@ endif()
if(LUACHECK_PRG)
add_custom_target(lualint
- COMMAND ${LUACHECK_PRG} -q runtime/ src/ test/ --exclude-files test/functional/fixtures/lua/syntax_error.lua
+ COMMAND ${LUACHECK_PRG} -q runtime/ scripts/ src/ test/
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
else()
add_custom_target(lualint false
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 27fd2b97bb..cd17b93462 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -8,9 +8,10 @@ If you want to help but don't know where to start, here are some
low-risk/isolated tasks:
- [Merge a Vim patch].
-- Try a [good first issue](../../labels/good%20first%20issue) or [complexity:low] issue.
+- Try a [good first issue](../../labels/good-first-issue) or [complexity:low] issue.
- Fix bugs found by [Clang](#clang-scan-build), [PVS](#pvs-studio) or
[Coverity](#coverity).
+- [Improve documentation][wiki-contribute-help]
Reporting problems
------------------
@@ -18,32 +19,31 @@ Reporting problems
- [Check the FAQ][wiki-faq].
- [Search existing issues][github-issues] (including closed!)
- Update Neovim to the latest version to see if your problem persists.
-- Disable plugins incrementally, to narrow down the cause of the issue.
+- [Bisect](https://neovim.io/doc/user/starting.html#bisect) your config: disable plugins incrementally, to narrow down the cause of the issue.
+- [Bisect][git-bisect] Neovim's source code to find the cause of a regression, if you can. This is _extremely_ helpful.
- When reporting a crash, [include a stacktrace](https://github.com/neovim/neovim/wiki/FAQ#backtrace-linux).
- Use [ASAN/UBSAN](#clang-sanitizers-asan-and-ubsan) to get detailed errors for segfaults and undefined behavior.
-- [Bisect][git-bisect] to the cause of a regression, if you are able. This is _extremely_ helpful.
-- Check `$NVIM_LOG_FILE`, if it exists.
+- Check the logs. `:edit $NVIM_LOG_FILE`
- Include `cmake --system-information` for build-related issues.
Developer guidelines
--------------------
-- Nvim contributors should read `:help dev`.
-- External UI developers should read `:help dev-ui`.
-- API client developers should read `:help dev-api-client`.
-- Nvim developers are _strongly encouraged_ to install `ninja` for faster builds.
+- Read `:help dev` if you are working on Nvim core.
+- Read `:help dev-ui` if you are developing a UI.
+- Read `:help dev-api-client` if you are developing an API client.
+- Install `ninja` for faster builds of Nvim.
```
sudo apt-get install ninja-build
make distclean
make # Nvim build system uses ninja automatically, if available.
```
-- [Improve documentation][wiki-contribute-help]
Pull requests (PRs)
---------------------
-- To avoid duplicate work, create a `[WIP]` pull request as soon as possible.
-- Your PR must include **test coverage.** See [test/README.md][run-tests].
+- To avoid duplicate work, create a draft pull request.
+- Your PR must include [test coverage][run-tests].
- Avoid cosmetic changes to unrelated files in the same commit.
- Use a [feature branch][git-feature-branch] instead of the master branch.
- Use a **rebase workflow** for small PRs.
@@ -62,21 +62,25 @@ Pull requests (PRs)
- During a squash/fixup, use `exec make -C build unittest` between each
pick/edit/reword.
-### Stages: WIP, RFC, RDY
+### Stages: Draft and Ready for review
-Pull requests have three stages: `[WIP]` (Work In Progress), `[RFC]` (Request
-For Comment) and `[RDY]` (Ready).
+Pull requests have two stages: Draft and Ready for review.
-1. `[RFC]` is assumed by default, **do not** put "RFC" in the PR title (it adds
- noise to merge commit messages).
-2. Add `[WIP]` to the PR title if you are _not_ requesting feedback and the work
- is still in flux.
-3. Add `[RDY]` to the PR title if you are _done_ and only waiting on merge.
+1. [Create a Draft PR][pr-draft] while you are _not_ requesting feedback as
+ you are still working on the PR.
+ - You can skip this if your PR is ready for review.
+2. [Change your PR to ready][pr-ready] when the PR is ready for review.
+ - You can convert back to Draft at any time.
+
+Do __not__ add labels like `[RFC]` or `[WIP]` in the title to indicate the
+state of your PR: this just adds noise. Non-Draft PRs are assumed to be open
+for comments; if you want feedback from specific people, `@`-mention them in
+a comment.
### Commit messages
-Follow the [convential commits guidelines][conventional_commits] to *make reviews easier* and to make
-the VCS/git logs more valuable. The general structure of a commit message is as follows:
+Follow the [conventional commits guidelines][conventional_commits] to *make reviews easier* and to make
+the VCS/git logs more valuable. The general structure of a commit message is:
```
<type>([optional scope]): <description>
@@ -86,21 +90,27 @@ the VCS/git logs more valuable. The general structure of a commit message is as
[optional footer(s)]
```
-- **Prefix the commit subject with a _type_:** `doc:`, `test:`
- `runtime:`, ...
- - Subject line for commits with only style/lint changes can be a single
- word: `style` or `lint`.
-- **Add the optional scope following <type> if possible:** `(lsp)`, `(treesitter)`, `(multigrid)`, ...
-- Try to keep the first line under 72 characters.
-- A blank line must separate the subject from the description.
-- Breaking changes must be indicated at the very beginning of the footer or body section of a commit. A breaking change must consist of the uppercase text BREAKING CHANGE, followed by a colon, a space, and a description of what has changed about the API.
-- Check your commit message for spelling and grammatical mistakes.
+- 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`
+ - 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.
- Use the _imperative voice_: "Fix bug" rather than "Fixed bug" or "Fixes bug."
+- Try to keep the first line under 72 characters.
+- A blank line must follow the subject.
+- Breaking API changes must be indicated by
+ 1. "!" after the type/scope, and
+ 2. a "BREAKING CHANGE" footer describing the change.
+ Example:
+ ```
+ refactor(provider)!: drop support for Python 2
+
+ BREAKING CHANGE: refactor to use Python 3 features since Python 2 is no longer supported.
+ ```
### Automated builds (CI)
-Each pull request must pass the automated builds on [Travis CI], [sourcehut]
-and [AppVeyor].
+Each pull request must pass the automated builds on [sourcehut] and [GitHub Actions].
- CI builds are compiled with [`-Werror`][gcc-warnings], so compiler warnings
will fail the build.
@@ -151,7 +161,7 @@ see potential bugs found by [PVS Studio](https://www.viva64.com/en/pvs-studio/).
- Use this format for commit messages (where `{id}` is the PVS warning-id)):
```
- PVS/V{id}: {description}
+ fix(PVS/V{id}): {description}
```
- Search the Neovim commit history to find examples:
```
@@ -167,26 +177,27 @@ master build. To view the defects, just request access; you will be approved.
- Use this format for commit messages (where `{id}` is the CID (Coverity ID);
([example](https://github.com/neovim/neovim/pull/804))):
```
- coverity/{id}: {description}
+ fix(coverity/{id}): {description}
```
- Search the Neovim commit history to find examples:
```
git log --oneline --no-merges --grep coverity
```
-
+
### Clang sanitizers (ASAN and UBSAN)
ASAN/UBSAN can be used to detect memory errors and other common forms of undefined behavior at runtime in debug builds.
- To build neovim with sanitizers enabled, use
+
+- To build Neovim with sanitizers enabled, use
```
rm -rf build && CMAKE_EXTRA_FLAGS="-DCMAKE_C_COMPILER=clang -DCLANG_ASAN_UBSAN=1" make
```
- When running neovim, use
+- When running Neovim, use
```
UBSAN_OPTIONS=print_stacktrace=1 ASAN_OPTIONS=log_path=/tmp/nvim_asan nvim args...
```
- If neovim exits unexpectedly, check `/tmp/nvim_asan.{PID}` (or your preferred `log_path`) for log files with error messages.
-
+- If Neovim exits unexpectedly, check `/tmp/nvim_asan.{PID}` (or your preferred `log_path`) for log files with error messages.
+
Coding
------
@@ -206,16 +217,27 @@ You can lint a single file (but this will _not_ exclude legacy errors):
### Style
-The repo includes a `.clang-format` config file which (mostly) matches the
-[style-guide]. You can use `clang-format` to format code with the `gq`
-operator in Nvim:
-
- if !empty(findfile('.clang-format', ';'))
- setlocal formatprg=clang-format\ -style=file
- endif
+- Style rules are (mostly) defined by `src/uncrustify.cfg` which tries to match
+ the [style-guide]. To use the Nvim `gq` command with `uncrustify`:
+ ```
+ if !empty(findfile('src/.uncrustify', ';'))
+ setlocal formatprg=uncrustify\ -q\ -c\ src/uncrustify.cfg\ --replace\ --no-backup
+ endif
+ ```
+- There is also `.clang-format` which has drifted from the [style-guide], but
+ is available for reference. To use the Nvim `gq` command with `clang-format`:
+ ```
+ if !empty(findfile('.clang-format', ';'))
+ setlocal formatprg=clang-format\ -style=file
+ endif
+ ```
### Navigate
+- Set `blame.ignoreRevsFile` to ignore [noise commits](https://github.com/neovim/neovim/commit/2d240024acbd68c2d3f82bc72cb12b1a4928c6bf) in git blame:
+ ```
+ git config blame.ignoreRevsFile .git-blame-ignore-revs
+ ```
- Use **[universal-ctags](https://github.com/universal-ctags/ctags).**
("Exuberant ctags", the typical `ctags` binary provided by your distro, is
unmaintained and won't recognize many function signatures in Neovim source.)
@@ -248,17 +270,19 @@ as context, use the `-W` argument as well.
[1820]: https://github.com/neovim/neovim/pull/1820
[hub]: https://hub.github.com/
[conventional_commits]: https://www.conventionalcommits.org
-[style-guide]: http://neovim.io/develop/style-guide.xml
+[style-guide]: https://neovim.io/doc/user/dev_style.html#dev-style
[ASan]: http://clang.llvm.org/docs/AddressSanitizer.html
[run-tests]: https://github.com/neovim/neovim/blob/master/test/README.md#running-tests
[wiki-faq]: https://github.com/neovim/neovim/wiki/FAQ
[review-checklist]: https://github.com/neovim/neovim/wiki/Code-review-checklist
[3174]: https://github.com/neovim/neovim/issues/3174
-[Travis CI]: https://travis-ci.org/neovim/neovim
[sourcehut]: https://builds.sr.ht/~jmk
-[AppVeyor]: https://ci.appveyor.com/project/neovim/neovim
+[GitHub Actions]: https://github.com/neovim/neovim/actions
[Merge a Vim patch]: https://github.com/neovim/neovim/wiki/Merging-patches-from-upstream-Vim
[Clang report]: https://neovim.io/doc/reports/clang/
[complexity:low]: https://github.com/neovim/neovim/issues?q=is%3Aopen+is%3Aissue+label%3Acomplexity%3Alow
[master error list]: https://raw.githubusercontent.com/neovim/doc/gh-pages/reports/clint/errors.json
[wiki-contribute-help]: https://github.com/neovim/neovim/wiki/contribute-%3Ahelp
+[pr-draft]: https://docs.github.com/en/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request
+[pr-ready]: https://docs.github.com/en/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/changing-the-stage-of-a-pull-request
+[uncrustify]: https://formulae.brew.sh/formula/uncrustify
diff --git a/LICENSE b/LICENSE
index 9e241ef0c3..c1b8286c4b 100644
--- a/LICENSE
+++ b/LICENSE
@@ -189,8 +189,17 @@ contributed under the Vim license and (2) externally maintained libraries.
The externally maintained libraries used by Neovim are:
- Klib: a Generic Library in C. MIT/X11 license.
- - libuv. Copyright Joyent, Inc. and other Node contributors. Node.js license.
+ - Lua: MIT license
- LuaJIT: a Just-In-Time Compiler for Lua. Copyright Mike Pall. MIT license.
+ - Luv: Apache 2.0 license
+ - libmpack: MIT license
+ - libtermkey: MIT license
+ - libuv. Copyright Joyent, Inc. and other Node contributors. Node.js license.
+ - libvterm: MIT license
+ - lua-compat: MIT license
+ - tree-sitter: MIT license
+ - xdiff: LGPL license
+ - lua-cjson: MIT license
====
diff --git a/MAINTAIN.md b/MAINTAIN.md
index 58d977f247..681ba91e3f 100644
--- a/MAINTAIN.md
+++ b/MAINTAIN.md
@@ -10,14 +10,13 @@ General guidelines
* Write down what was decided
* Constraints are good
* Use automation to solve problems
-* Never break the API
+* Never break the API... but sometimes break the UI
Ticket triage
-------------
-In practice we haven't found a meaningful way to forecast more precisely than
-"next" and "after next". That means there are usually one or two (at most)
-planned milestones:
+In practice we haven't found a way to forecast more precisely than "next" and
+"after next". So there are usually one or two (at most) planned milestones:
- Next bugfix-release (1.0.x)
- Next feature-release (1.x.0)
@@ -25,16 +24,16 @@ planned milestones:
The forecasting problem might be solved with an explicit priority system (like
Bram's todo.txt). Meanwhile the Neovim priority system is defined by:
-- PRs nearing completion (RDY).
+- PRs nearing completion.
- Issue labels. E.g. the `+plan` label increases the ticket's priority merely
for having a plan written down: it is _closer to completion_ than tickets
without a plan.
- Comment activity or new information.
-Anything that isn't in the next milestone, and doesn't have a RDY PR ... is
+Anything that isn't in the next milestone, and doesn't have a finished PR—is
just not something you care very much about, by construction. Post-release you
can review open issues, but chances are your next milestone is already getting
-full :)
+full... :)
Release policy
--------------
@@ -56,6 +55,28 @@ has a major bug:
- The [nightly job](https://github.com/neovim/bot-ci/blob/master/ci/nightly.sh)
will update the release assets based on the `stable` tag.
+Third-party dependencies
+--------------
+
+These "bundled" dependencies can be updated by bumping their versions in `third-party/CMakeLists.txt`:
+ - [Lua](https://www.lua.org/download.html)
+ - [LuaJIT](https://github.com/LuaJIT/LuaJIT)
+ - [Luv](https://github.com/luvit/luv)
+ - [libtermkey](https://github.com/neovim/libtermkey)
+ - [libuv](https://github.com/libuv/libuv)
+ - [libvterm](http://www.leonerd.org.uk/code/libvterm/)
+ - [lua-compat](https://github.com/keplerproject/lua-compat-5.3)
+ - [tree-sitter](https://github.com/tree-sitter/tree-sitter)
+
+These dependencies are "vendored" (inlined), we need to update the sources manually:
+ - [libmpack](https://github.com/libmpack/libmpack)
+ - [xdiff](https://github.com/git/git/tree/master/xdiff)
+ - [lua-cjson](https://github.com/openresty/lua-cjson)
+ - [Klib](https://github.com/attractivechaos/klib)
+
+We also maintain some forks, particularly for Windows, if we are waiting on upstream changes:
+https://github.com/neovim/neovim/wiki/Deps
+
See also
--------
diff --git a/Makefile b/Makefile
index 39f42739ff..86e723df67 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,6 @@
-THIS_DIR = $(shell pwd)
+MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
+MAKEFILE_DIR := $(dir $(MAKEFILE_PATH))
+
filter-false = $(strip $(filter-out 0 off OFF false FALSE,$1))
filter-true = $(strip $(filter-out 1 on ON true TRUE,$1))
@@ -12,6 +14,7 @@ CMAKE_BUILD_TYPE ?= Debug
CMAKE_FLAGS := -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE)
# Extra CMake flags which extend the default set
CMAKE_EXTRA_FLAGS ?=
+NVIM_PRG := $(MAKEFILE_DIR)/build/bin/nvim
# CMAKE_INSTALL_PREFIX
# - May be passed directly or as part of CMAKE_EXTRA_FLAGS.
@@ -35,7 +38,7 @@ else
checkprefix: ;
endif
-BUILD_TYPE ?= $(shell (type ninja > /dev/null 2>&1 && echo "Ninja") || \
+CMAKE_GENERATOR ?= $(shell (command -v ninja > /dev/null 2>&1 && echo "Ninja") || \
echo "Unix Makefiles")
DEPS_BUILD_DIR ?= .deps
ifneq (1,$(words [$(DEPS_BUILD_DIR)]))
@@ -43,29 +46,28 @@ ifneq (1,$(words [$(DEPS_BUILD_DIR)]))
endif
ifeq (,$(BUILD_TOOL))
- ifeq (Ninja,$(BUILD_TYPE))
+ ifeq (Ninja,$(CMAKE_GENERATOR))
ifneq ($(shell $(CMAKE_PRG) --help 2>/dev/null | grep Ninja),)
- BUILD_TOOL := ninja
+ BUILD_TOOL = ninja
else
# User's version of CMake doesn't support Ninja
BUILD_TOOL = $(MAKE)
- BUILD_TYPE := Unix Makefiles
+ CMAKE_GENERATOR := Unix Makefiles
endif
else
BUILD_TOOL = $(MAKE)
endif
endif
-BUILD_CMD = $(BUILD_TOOL)
-# Only need to handle Ninja here. Make will inherit the VERBOSE variable, and the -j and -n flags.
-ifeq ($(BUILD_TYPE),Ninja)
+# Only need to handle Ninja here. Make will inherit the VERBOSE variable, and the -j, -l, and -n flags.
+ifeq ($(CMAKE_GENERATOR),Ninja)
ifneq ($(VERBOSE),)
- BUILD_CMD += -v
+ BUILD_TOOL += -v
endif
- BUILD_CMD += $(shell printf '%s' '$(MAKEFLAGS)' | grep -o -- '-j[0-9]\+')
+ BUILD_TOOL += $(shell printf '%s' '$(MAKEFLAGS)' | grep -o -- ' *-[jl][0-9]\+ *')
ifeq (n,$(findstring n,$(firstword -$(MAKEFLAGS))))
- BUILD_CMD += -n
+ BUILD_TOOL += -n
endif
endif
@@ -87,22 +89,22 @@ endif
SINGLE_MAKE = export MAKEFLAGS= ; $(MAKE)
nvim: build/.ran-cmake deps
- +$(BUILD_CMD) -C build
+ +$(BUILD_TOOL) -C build
libnvim: build/.ran-cmake deps
- +$(BUILD_CMD) -C build libnvim
+ +$(BUILD_TOOL) -C build libnvim
cmake:
touch CMakeLists.txt
$(MAKE) build/.ran-cmake
build/.ran-cmake: | deps
- cd build && $(CMAKE_PRG) -G '$(BUILD_TYPE)' $(CMAKE_FLAGS) $(CMAKE_EXTRA_FLAGS) $(THIS_DIR)
+ cd build && $(CMAKE_PRG) -G '$(CMAKE_GENERATOR)' $(CMAKE_FLAGS) $(CMAKE_EXTRA_FLAGS) $(MAKEFILE_DIR)
touch $@
deps: | build/.ran-third-party-cmake
ifeq ($(call filter-true,$(USE_BUNDLED)),)
- +$(BUILD_CMD) -C $(DEPS_BUILD_DIR)
+ +$(BUILD_TOOL) -C $(DEPS_BUILD_DIR)
endif
ifeq ($(call filter-true,$(USE_BUNDLED)),)
@@ -110,8 +112,8 @@ $(DEPS_BUILD_DIR):
mkdir -p "$@"
build/.ran-third-party-cmake:: $(DEPS_BUILD_DIR)
cd $(DEPS_BUILD_DIR) && \
- $(CMAKE_PRG) -G '$(BUILD_TYPE)' $(BUNDLED_CMAKE_FLAG) $(BUNDLED_LUA_CMAKE_FLAG) \
- $(DEPS_CMAKE_FLAGS) $(THIS_DIR)/third-party
+ $(CMAKE_PRG) -G '$(CMAKE_GENERATOR)' $(BUNDLED_CMAKE_FLAG) $(BUNDLED_LUA_CMAKE_FLAG) \
+ $(DEPS_CMAKE_FLAGS) $(MAKEFILE_DIR)/third-party
endif
build/.ran-third-party-cmake::
mkdir -p build
@@ -121,31 +123,31 @@ build/.ran-third-party-cmake::
oldtest: | nvim build/runtime/doc/tags
+$(SINGLE_MAKE) -C src/nvim/testdir clean
ifeq ($(strip $(TEST_FILE)),)
- +$(SINGLE_MAKE) -C src/nvim/testdir NVIM_PRG="$(realpath build/bin/nvim)" $(MAKEOVERRIDES)
+ +$(SINGLE_MAKE) -C src/nvim/testdir NVIM_PRG=$(NVIM_PRG) $(MAKEOVERRIDES)
else
@# Handle TEST_FILE=test_foo{,.res,.vim}.
- +$(SINGLE_MAKE) -C src/nvim/testdir NVIM_PRG="$(realpath build/bin/nvim)" SCRIPTS= $(MAKEOVERRIDES) $(patsubst %.vim,%,$(patsubst %.res,%,$(TEST_FILE)))
+ +$(SINGLE_MAKE) -C src/nvim/testdir NVIM_PRG=$(NVIM_PRG) SCRIPTS= $(MAKEOVERRIDES) $(patsubst %.vim,%,$(patsubst %.res,%,$(TEST_FILE)))
endif
# Build oldtest by specifying the relative .vim filename.
.PHONY: phony_force
src/nvim/testdir/%.vim: phony_force
- +$(SINGLE_MAKE) -C src/nvim/testdir NVIM_PRG="$(realpath build/bin/nvim)" SCRIPTS= $(MAKEOVERRIDES) $(patsubst src/nvim/testdir/%.vim,%,$@)
+ +$(SINGLE_MAKE) -C src/nvim/testdir NVIM_PRG=$(NVIM_PRG) SCRIPTS= $(MAKEOVERRIDES) $(patsubst src/nvim/testdir/%.vim,%,$@)
build/runtime/doc/tags helptags: | nvim
- +$(BUILD_CMD) -C build runtime/doc/tags
+ +$(BUILD_TOOL) -C build runtime/doc/tags
# Builds help HTML _and_ checks for invalid help tags.
helphtml: | nvim build/runtime/doc/tags
- +$(BUILD_CMD) -C build doc_html
+ +$(BUILD_TOOL) -C build doc_html
functionaltest: | nvim
- +$(BUILD_CMD) -C build functionaltest
+ +$(BUILD_TOOL) -C build functionaltest
functionaltest-lua: | nvim
- +$(BUILD_CMD) -C build functionaltest-lua
+ +$(BUILD_TOOL) -C build functionaltest-lua
lualint: | build/.ran-cmake deps
- $(BUILD_CMD) -C build lualint
+ $(BUILD_TOOL) -C build lualint
shlint:
@shellcheck --version | head -n 2
@@ -163,16 +165,23 @@ _opt_pylint:
@command -v flake8 && { $(MAKE) pylint; exit $$?; } \
|| echo "SKIP: pylint (flake8 not found)"
+commitlint:
+ $(NVIM_PRG) --clean -es +"lua require('scripts.lintcommit').main({trace=false})"
+
+_opt_commitlint:
+ @test -x build/bin/nvim && { $(MAKE) commitlint; exit $$?; } \
+ || echo "SKIP: commitlint (build/bin/nvim not found)"
+
unittest: | nvim
- +$(BUILD_CMD) -C build unittest
+ +$(BUILD_TOOL) -C build unittest
benchmark: | nvim
- +$(BUILD_CMD) -C build benchmark
+ +$(BUILD_TOOL) -C build benchmark
test: functionaltest unittest
clean:
- +test -d build && $(BUILD_CMD) -C build clean || true
+ +test -d build && $(BUILD_TOOL) -C build clean || true
$(MAKE) -C src/nvim/testdir clean
$(MAKE) -C runtime/doc clean
$(MAKE) -C runtime/indent clean
@@ -182,19 +191,19 @@ distclean:
$(MAKE) clean
install: checkprefix nvim
- +$(BUILD_CMD) -C build install
+ +$(BUILD_TOOL) -C build install
clint: build/.ran-cmake
- +$(BUILD_CMD) -C build clint
+ +$(BUILD_TOOL) -C build clint
clint-full: build/.ran-cmake
- +$(BUILD_CMD) -C build clint-full
+ +$(BUILD_TOOL) -C build clint-full
check-single-includes: build/.ran-cmake
- +$(BUILD_CMD) -C build check-single-includes
+ +$(BUILD_TOOL) -C build check-single-includes
generated-sources: build/.ran-cmake
- +$(BUILD_CMD) -C build generated-sources
+ +$(BUILD_TOOL) -C build generated-sources
appimage:
bash scripts/genappimage.sh
@@ -205,16 +214,16 @@ appimage:
appimage-%:
bash scripts/genappimage.sh $*
-lint: check-single-includes clint lualint _opt_pylint _opt_shlint
+lint: check-single-includes clint lualint _opt_pylint _opt_shlint _opt_commitlint
# Generic pattern rules, allowing for `make build/bin/nvim` etc.
# Does not work with "Unix Makefiles".
-ifeq ($(BUILD_TYPE),Ninja)
+ifeq ($(CMAKE_GENERATOR),Ninja)
build/%: phony_force
- $(BUILD_CMD) -C build $(patsubst build/%,%,$@)
+ $(BUILD_TOOL) -C build $(patsubst build/%,%,$@)
$(DEPS_BUILD_DIR)/%: phony_force
- $(BUILD_CMD) -C $(DEPS_BUILD_DIR) $(patsubst $(DEPS_BUILD_DIR)/%,%,$@)
+ $(BUILD_TOOL) -C $(DEPS_BUILD_DIR) $(patsubst $(DEPS_BUILD_DIR)/%,%,$@)
endif
-.PHONY: test lualint pylint shlint functionaltest unittest lint clint clean distclean nvim libnvim cmake deps install appimage checkprefix
+.PHONY: test lualint pylint shlint functionaltest unittest lint clint clean distclean nvim libnvim cmake deps install appimage checkprefix commitlint
diff --git a/README.md b/README.md
index 42c9056892..8342c27fd7 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,10 @@
[![Neovim](https://raw.githubusercontent.com/neovim/neovim.github.io/master/logos/neovim-logo-300x87.png)](https://neovim.io)
[Documentation](https://neovim.io/doc/general/) |
-[Chat](https://gitter.im/neovim/neovim) |
+[Chat](https://app.element.io/#/room/#neovim:matrix.org) |
[Twitter](https://twitter.com/Neovim)
-[![GitHub CI](https://github.com/neovim/neovim/workflows/CI/badge.svg)](https://github.com/neovim/neovim/actions?query=workflow%3A%22CI%22)
+[![GitHub CI](https://github.com/neovim/neovim/workflows/CI/badge.svg)](https://github.com/neovim/neovim/actions?query=workflow%3ACI+branch%3Amaster+event%3Apush)
[![Codecov coverage](https://img.shields.io/codecov/c/github/neovim/neovim.svg)](https://codecov.io/gh/neovim/neovim)
[![Coverity Scan analysis](https://scan.coverity.com/projects/2227/badge.svg)](https://scan.coverity.com/projects/2227)
[![Clang analysis](https://neovim.io/doc/reports/clang/badge.svg)](https://neovim.io/doc/reports/clang)
@@ -46,8 +46,7 @@ Install from package
Pre-built packages for Windows, macOS, and Linux are found on the
[Releases](https://github.com/neovim/neovim/releases/) page.
-[Managed packages] are in [Homebrew], [Debian], [Ubuntu], [Fedora], [Arch Linux],
-[Gentoo], and more!
+[Managed packages] are in [Homebrew], [Debian], [Ubuntu], [Fedora], [Arch Linux], [Void Linux], [Gentoo], and more!
Install from source
-------------------
@@ -65,7 +64,7 @@ To install to a non-default location:
make CMAKE_INSTALL_PREFIX=/full/path/
make install
-To inspect the build, these CMake features are useful:
+CMake hints for inspecting the build:
- `cmake --build build --target help` lists all build targets.
- `build/CMakeCache.txt` (or `cmake -LAH build/`) contains the resolved values of all CMake variables.
@@ -122,6 +121,7 @@ Apache 2.0 license, except for contributions copied from Vim (identified by the
[Ubuntu]: http://packages.ubuntu.com/search?keywords=neovim
[Fedora]: https://apps.fedoraproject.org/packages/neovim
[Arch Linux]: https://www.archlinux.org/packages/?q=neovim
+[Void Linux]: https://voidlinux.org/packages/?arch=x86_64&q=neovim
[Gentoo]: https://packages.gentoo.org/packages/app-editors/neovim
[Homebrew]: https://formulae.brew.sh/formula/neovim
diff --git a/cmake/FindLibLUV.cmake b/cmake/FindLibLUV.cmake
index bc53d00f24..23b62b66d3 100644
--- a/cmake/FindLibLUV.cmake
+++ b/cmake/FindLibLUV.cmake
@@ -15,7 +15,7 @@ find_path(LIBLUV_INCLUDE_DIR luv/luv.h
PATHS ${PC_LIBLUV_INCLUDEDIR} ${PC_LIBLUV_INCLUDE_DIRS})
# Explicitly look for luv.so. #10407
-list(APPEND LIBLUV_NAMES luv luv${CMAKE_SHARED_LIBRARY_SUFFIX})
+list(APPEND LIBLUV_NAMES luv_a luv libluv_a luv${CMAKE_SHARED_LIBRARY_SUFFIX})
find_library(LIBLUV_LIBRARY NAMES ${LIBLUV_NAMES}
HINTS ${PC_LIBLUV_LIBDIR} ${PC_LIBLUV_LIBRARY_DIRS})
diff --git a/cmake/FindLibUV.cmake b/cmake/FindLibUV.cmake
index 951fb0435e..63babfea67 100644
--- a/cmake/FindLibUV.cmake
+++ b/cmake/FindLibUV.cmake
@@ -75,6 +75,14 @@ if(WIN32)
list(APPEND LIBUV_LIBRARIES ws2_32)
endif()
+find_package(Threads)
+if(Threads_FOUND)
+ # TODO: Fix the cmake file to properly handle static deps for bundled builds.
+ # Meanwhile just include the threads library if CMake tells us there's one to
+ # use.
+ list(APPEND LIBUV_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
+endif()
+
include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set LIBUV_FOUND to TRUE
diff --git a/cmake/RunTests.cmake b/cmake/RunTests.cmake
index f000004aec..0c48a77b9a 100644
--- a/cmake/RunTests.cmake
+++ b/cmake/RunTests.cmake
@@ -49,6 +49,13 @@ endif()
set(ENV{TMPDIR} "${BUILD_DIR}/Xtest_tmpdir/${TEST_PATH}")
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory $ENV{TMPDIR})
+# HISTFILE: do not write into user's ~/.bash_history
+set(ENV{HISTFILE} "/dev/null")
+
+if(NOT DEFINED ENV{TEST_TIMEOUT} OR "$ENV{TEST_TIMEOUT}" STREQUAL "")
+ set(ENV{TEST_TIMEOUT} 1200)
+endif()
+
set(ENV{SYSTEM_NAME} ${CMAKE_HOST_SYSTEM_NAME}) # used by test/helpers.lua.
execute_process(
COMMAND ${BUSTED_PRG} -v -o test.busted.outputHandlers.${BUSTED_OUTPUT_TYPE}
@@ -58,6 +65,7 @@ execute_process(
--lpath=?.lua
${BUSTED_ARGS}
${TEST_PATH}
+ TIMEOUT $ENV{TEST_TIMEOUT}
WORKING_DIRECTORY ${WORKING_DIR}
ERROR_VARIABLE err
RESULT_VARIABLE res
diff --git a/contrib/flake.lock b/contrib/flake.lock
index 521b7629d9..c4d7f120ba 100644
--- a/contrib/flake.lock
+++ b/contrib/flake.lock
@@ -2,11 +2,11 @@
"nodes": {
"flake-utils": {
"locked": {
- "lastModified": 1610051610,
- "narHash": "sha256-U9rPz/usA1/Aohhk7Cmc2gBrEEKRzcW4nwPWMPwja4Y=",
+ "lastModified": 1629481132,
+ "narHash": "sha256-JHgasjPR0/J1J3DRm4KxM4zTyAj4IOJY8vIl75v/kPI=",
"owner": "numtide",
"repo": "flake-utils",
- "rev": "3982c9903e93927c2164caa727cd3f6a0e6d14cc",
+ "rev": "997f7efcb746a9c140ce1f13c72263189225f482",
"type": "github"
},
"original": {
@@ -17,11 +17,11 @@
},
"nixpkgs": {
"locked": {
- "lastModified": 1613226215,
- "narHash": "sha256-3rA5cGIrBHD6yeKhNhsF7/t461ww25oJY8KyBb0IhjU=",
+ "lastModified": 1630074300,
+ "narHash": "sha256-BFM7OiXRs0RvSUZd6NCGAKWVPn3VodgYQ4TUQXxbMBU=",
"owner": "nixos",
"repo": "nixpkgs",
- "rev": "ff96a0fa5635770390b184ae74debea75c3fd534",
+ "rev": "21c937f8cb1e6adcfeb36dfd6c90d9d9bfab1d28",
"type": "github"
},
"original": {
diff --git a/contrib/flake.nix b/contrib/flake.nix
index e75ff0356b..848c52d208 100644
--- a/contrib/flake.nix
+++ b/contrib/flake.nix
@@ -16,24 +16,20 @@
neovim = pkgs.neovim-unwrapped.overrideAttrs (oa: {
version = "master";
src = ../.;
-
- buildInputs = oa.buildInputs ++ ([
- pkgs.tree-sitter
- ]);
-
- cmakeFlags = oa.cmakeFlags ++ [
- "-DUSE_BUNDLED=OFF"
- ];
});
# a development binary to help debug issues
neovim-debug = let
- stdenv = pkgs.stdenvAdapters.keepDebugInfo (if pkgs.stdenv.isLinux then pkgs.llvmPackages_latest.stdenv else pkgs.stdenv);
+ stdenv = if pkgs.stdenv.isLinux then pkgs.llvmPackages_latest.stdenv else pkgs.stdenv;
in
- pkgs.enableDebugging ((neovim.override {
- lua = pkgs.enableDebugging pkgs.luajit;
+ ((neovim.override {
+ lua = pkgs.luajit;
inherit stdenv;
}).overrideAttrs (oa: {
+
+ dontStrip = true;
+ NIX_CFLAGS_COMPILE = " -ggdb -Og";
+
cmakeBuildType = "Debug";
cmakeFlags = oa.cmakeFlags ++ [
"-DMIN_LOG_LEVEL=0"
@@ -42,16 +38,10 @@
disallowedReferences = [];
}));
- # for neovim developers, builds a slow binary
- # huge closure size but aims at covering all scripts
- # brings development tools as well
+ # for neovim developers, beware of the slow binary
neovim-developer =
let
lib = nixpkgs.lib;
- pythonEnv = pkgs.python3.withPackages(ps: [
- ps.msgpack
- ps.flake8 # for 'make pylint'
- ]);
luacheck = pkgs.luaPackages.luacheck;
in
(neovim-debug.override ({ doCheck = pkgs.stdenv.isLinux; })).overrideAttrs (oa: {
@@ -59,29 +49,11 @@
"-DLUACHECK_PRG=${luacheck}/bin/luacheck"
"-DMIN_LOG_LEVEL=0"
"-DENABLE_LTO=OFF"
- "-DUSE_BUNDLED=OFF"
] ++ pkgs.lib.optionals pkgs.stdenv.isLinux [
# https://github.com/google/sanitizers/wiki/AddressSanitizerFlags
# https://clang.llvm.org/docs/AddressSanitizer.html#symbolizing-the-reports
"-DCLANG_ASAN_UBSAN=ON"
];
-
- nativeBuildInputs = oa.nativeBuildInputs ++ (with pkgs; [
- pythonEnv
- include-what-you-use # for scripts/check-includes.py
- jq # jq for scripts/vim-patch.sh -r
- shellcheck # for `make shlint`
- doxygen # for script/gen_vimdoc.py
- clang-tools # for clangd to find the correct headers
- ]);
-
- shellHook = oa.shellHook + ''
- export NVIM_PYTHON_LOG_LEVEL=DEBUG
- export NVIM_LOG_FILE=/tmp/nvim.log
-
- export ASAN_OPTIONS="log_path=./test.log:abort_on_error=1"
- export UBSAN_OPTIONS=print_stacktrace=1
- '';
});
};
} //
@@ -91,6 +63,11 @@
overlays = [ self.overlay ];
inherit system;
};
+
+ pythonEnv = pkgs.python3.withPackages(ps: [
+ ps.msgpack
+ ps.flake8 # for 'make pylint'
+ ]);
in
rec {
@@ -98,6 +75,18 @@
inherit neovim neovim-debug neovim-developer;
};
+ checks = {
+ pylint = pkgs.runCommandNoCC "pylint" {
+ nativeBuildInputs = [ pythonEnv ];
+ preferLocalBuild = true;
+ } "make -C ${./..} pylint > $out";
+
+ shlint = pkgs.runCommandNoCC "shlint" {
+ nativeBuildInputs = [ pkgs.shellcheck ];
+ preferLocalBuild = true;
+ } "make -C ${./..} shlint > $out";
+ };
+
defaultPackage = pkgs.neovim;
apps = {
@@ -107,6 +96,38 @@
defaultApp = apps.nvim;
- devShell = pkgs.neovim-developer;
+ devShell = let
+ in
+ pkgs.neovim-developer.overrideAttrs(oa: {
+
+ buildInputs = with pkgs; oa.buildInputs ++ [
+ cmake
+ pythonEnv
+ include-what-you-use # for scripts/check-includes.py
+ jq # jq for scripts/vim-patch.sh -r
+ shellcheck # for `make shlint`
+ doxygen # for script/gen_vimdoc.py
+ clang-tools # for clangd to find the correct headers
+ ];
+
+ shellHook = oa.shellHook + ''
+ export NVIM_PYTHON_LOG_LEVEL=DEBUG
+ export NVIM_LOG_FILE=/tmp/nvim.log
+ export ASAN_SYMBOLIZER_PATH=${pkgs.llvm_11}/bin/llvm-symbolizer
+
+ # ASAN_OPTIONS=detect_leaks=1
+ export ASAN_OPTIONS="log_path=./test.log:abort_on_error=1"
+ export UBSAN_OPTIONS=print_stacktrace=1
+ mkdir -p build/runtime/parser
+ # nvim looks into CMAKE_INSTALL_DIR. Hack to avoid errors
+ # when running the functionaltests
+ mkdir -p outputs/out/share/nvim/syntax
+ touch outputs/out/share/nvim/syntax/syntax.vim
+
+ # for treesitter functionaltests
+ mkdir -p runtime/parser
+ cp -f ${pkgs.tree-sitter.builtGrammars.tree-sitter-c}/parser runtime/parser/c.so
+ '';
+ });
});
}
diff --git a/contrib/uncrustify.cfg b/contrib/uncrustify.cfg
deleted file mode 100644
index 11da34d59a..0000000000
--- a/contrib/uncrustify.cfg
+++ /dev/null
@@ -1,1578 +0,0 @@
-# Uncrustify 0.60
-
-#
-# General options
-#
-
-# The type of line endings
-newlines = auto # auto/lf/crlf/cr
-
-# The original size of tabs in the input
-input_tab_size = 8 # number
-
-# The size of tabs in the output (only used if align_with_tabs=true)
-output_tab_size = 8 # number
-
-# The ASCII value of the string escape char, usually 92 (\) or 94 (^). (Pawn)
-string_escape_char = 92 # number
-
-# Alternate string escape char for Pawn. Only works right before the quote char.
-string_escape_char2 = 0 # number
-
-# Allow interpreting '>=' and '>>=' as part of a template in 'void f(list<list<B>>=val);'.
-# If true (default), 'assert(x<0 && y>=3)' will be broken.
-# Improvements to template detection may make this option obsolete.
-tok_split_gte = false # false/true
-
-# Control what to do with the UTF-8 BOM (recommend 'remove')
-utf8_bom = ignore # ignore/add/remove/force
-
-# If the file contains bytes with values between 128 and 255, but is not UTF-8, then output as UTF-8
-utf8_byte = false # false/true
-
-# Force the output encoding to UTF-8
-utf8_force = false # false/true
-
-#
-# Indenting
-#
-
-# The number of columns to indent per level.
-# Usually 2, 3, 4, or 8.
-indent_columns = 2 # number
-
-# The continuation indent. If non-zero, this overrides the indent of '(' and '=' continuation indents.
-# For FreeBSD, this is set to 4. Negative value is absolute and not increased for each ( level
-indent_continue = 0 # number
-
-# How to use tabs when indenting code
-# 0=spaces only
-# 1=indent with tabs to brace level, align with spaces
-# 2=indent and align with tabs, using spaces when not on a tabstop
-indent_with_tabs = 0 # number
-
-# Comments that are not a brace level are indented with tabs on a tabstop.
-# Requires indent_with_tabs=2. If false, will use spaces.
-indent_cmt_with_tabs = false # false/true
-
-# Whether to indent strings broken by '\' so that they line up
-indent_align_string = true # false/true
-
-# The number of spaces to indent multi-line XML strings.
-# Requires indent_align_string=True
-indent_xml_string = 0 # number
-
-# Spaces to indent '{' from level
-indent_brace = 0 # number
-
-# Whether braces are indented to the body level
-indent_braces = false # false/true
-
-# Disabled indenting function braces if indent_braces is true
-indent_braces_no_func = false # false/true
-
-# Disabled indenting class braces if indent_braces is true
-indent_braces_no_class = false # false/true
-
-# Disabled indenting struct braces if indent_braces is true
-indent_braces_no_struct = false # false/true
-
-# Indent based on the size of the brace parent, i.e. 'if' => 3 spaces, 'for' => 4 spaces, etc.
-indent_brace_parent = false # false/true
-
-# Whether the 'namespace' body is indented
-indent_namespace = false # false/true
-
-# The number of spaces to indent a namespace block
-indent_namespace_level = 0 # number
-
-# If the body of the namespace is longer than this number, it won't be indented.
-# Requires indent_namespace=true. Default=0 (no limit)
-indent_namespace_limit = 0 # number
-
-# Whether the 'extern "C"' body is indented
-indent_extern = false # false/true
-
-# Whether the 'class' body is indented
-indent_class = true # false/true
-
-# Whether to indent the stuff after a leading class colon
-indent_class_colon = true # false/true
-
-# Virtual indent from the ':' for member initializers. Default is 2
-indent_ctor_init_leading = 2 # number
-
-# Additional indenting for constructor initializer list
-indent_ctor_init = 0 # number
-
-# False=treat 'else\nif' as 'else if' for indenting purposes
-# True=indent the 'if' one level
-indent_else_if = false # false/true
-
-# Amount to indent variable declarations after an open brace. neg=relative, pos=absolute
-indent_var_def_blk = 0 # number
-
-# Indent continued variable declarations instead of aligning.
-indent_var_def_cont = false # false/true
-
-# True: force indentation of function definition to start in column 1
-# False: use the default behavior
-indent_func_def_force_col1 = false # false/true
-
-# True: indent continued function call parameters one indent level
-# False: align parameters under the open paren
-indent_func_call_param = false # false/true
-
-# Same as indent_func_call_param, but for function defs
-indent_func_def_param = false # false/true
-
-# Same as indent_func_call_param, but for function protos
-indent_func_proto_param = false # false/true
-
-# Same as indent_func_call_param, but for class declarations
-indent_func_class_param = false # false/true
-
-# Same as indent_func_call_param, but for class variable constructors
-indent_func_ctor_var_param = false # false/true
-
-# Same as indent_func_call_param, but for templates
-indent_template_param = false # false/true
-
-# Double the indent for indent_func_xxx_param options
-indent_func_param_double = false # false/true
-
-# Indentation column for standalone 'const' function decl/proto qualifier
-indent_func_const = 0 # number
-
-# Indentation column for standalone 'throw' function decl/proto qualifier
-indent_func_throw = 0 # number
-
-# The number of spaces to indent a continued '->' or '.'
-# Usually set to 0, 1, or indent_columns.
-indent_member = 0 # number
-
-# Spaces to indent single line ('//') comments on lines before code
-indent_sing_line_comments = 0 # number
-
-# If set, will indent trailing single line ('//') comments relative
-# to the code instead of trying to keep the same absolute column
-indent_relative_single_line_comments = false # false/true
-
-# Spaces to indent 'case' from 'switch'
-# Usually 0 or indent_columns.
-indent_switch_case = 0 # number
-
-# Spaces to shift the 'case' line, without affecting any other lines
-# Usually 0.
-indent_case_shift = 0 # number
-
-# Spaces to indent '{' from 'case'.
-# By default, the brace will appear under the 'c' in case.
-# Usually set to 0 or indent_columns.
-indent_case_brace = 0 # number
-
-# Whether to indent comments found in first column
-indent_col1_comment = true # false/true
-
-# How to indent goto labels
-# >0 : absolute column where 1 is the leftmost column
-# <=0 : subtract from brace indent
-indent_label = 0 # number
-
-# Same as indent_label, but for access specifiers that are followed by a colon
-indent_access_spec = 1 # number
-
-# Indent the code after an access specifier by one level.
-# If set, this option forces 'indent_access_spec=0'
-indent_access_spec_body = false # false/true
-
-# If an open paren is followed by a newline, indent the next line so that it lines up after the open paren (not recommended)
-indent_paren_nl = false # false/true
-
-# Controls the indent of a close paren after a newline.
-# 0: Indent to body level
-# 1: Align under the open paren
-# 2: Indent to the brace level
-indent_paren_close = 0 # number
-
-# Controls the indent of a comma when inside a paren.If TRUE, aligns under the open paren
-indent_comma_paren = false # false/true
-
-# Controls the indent of a BOOL operator when inside a paren.If TRUE, aligns under the open paren
-indent_bool_paren = false # false/true
-
-# If 'indent_bool_paren' is true, controls the indent of the first expression. If TRUE, aligns the first expression to the following ones
-indent_first_bool_expr = false # false/true
-
-# If an open square is followed by a newline, indent the next line so that it lines up after the open square (not recommended)
-indent_square_nl = false # false/true
-
-# Don't change the relative indent of ESQL/C 'EXEC SQL' bodies
-indent_preserve_sql = false # false/true
-
-# Align continued statements at the '='. Default=True
-# If FALSE or the '=' is followed by a newline, the next line is indent one tab.
-indent_align_assign = true # false/true
-
-# Indent OC blocks at brace level instead of usual rules.
-indent_oc_block = false # false/true
-
-# Indent OC blocks in a message relative to the parameter name.
-# 0=use indent_oc_block rules, 1+=spaces to indent
-indent_oc_block_msg = 0 # number
-
-# Minimum indent for subsequent parameters
-indent_oc_msg_colon = 0 # number
-
-#
-# Spacing options
-#
-
-# Add or remove space around arithmetic operator '+', '-', '/', '*', etc
-sp_arith = add # ignore/add/remove/force
-
-# Add or remove space around assignment operator '=', '+=', etc
-sp_assign = add # ignore/add/remove/force
-
-# Add or remove space around '=' in C++11 lambda capture specifications. Overrides sp_assign
-sp_cpp_lambda_assign = ignore # ignore/add/remove/force
-
-# Add or remove space after the capture specification in C++11 lambda.
-sp_cpp_lambda_paren = ignore # ignore/add/remove/force
-
-# Add or remove space around assignment operator '=' in a prototype
-sp_assign_default = ignore # ignore/add/remove/force
-
-# Add or remove space before assignment operator '=', '+=', etc. Overrides sp_assign.
-sp_before_assign = ignore # ignore/add/remove/force
-
-# Add or remove space after assignment operator '=', '+=', etc. Overrides sp_assign.
-sp_after_assign = ignore # ignore/add/remove/force
-
-# Add or remove space around assignment '=' in enum
-sp_enum_assign = add # ignore/add/remove/force
-
-# Add or remove space before assignment '=' in enum. Overrides sp_enum_assign.
-sp_enum_before_assign = ignore # ignore/add/remove/force
-
-# Add or remove space after assignment '=' in enum. Overrides sp_enum_assign.
-sp_enum_after_assign = ignore # ignore/add/remove/force
-
-# Add or remove space around preprocessor '##' concatenation operator. Default=Add
-sp_pp_concat = add # ignore/add/remove/force
-
-# Add or remove space after preprocessor '#' stringify operator. Also affects the '#@' charizing operator.
-sp_pp_stringify = add # ignore/add/remove/force
-
-# Add or remove space before preprocessor '#' stringify operator as in '#define x(y) L#y'.
-sp_before_pp_stringify = ignore # ignore/add/remove/force
-
-# Add or remove space around boolean operators '&&' and '||'
-sp_bool = add # ignore/add/remove/force
-
-# Add or remove space around compare operator '<', '>', '==', etc
-sp_compare = add # ignore/add/remove/force
-
-# Add or remove space inside '(' and ')'
-sp_inside_paren = remove # ignore/add/remove/force
-
-# Add or remove space between nested parens
-sp_paren_paren = remove # ignore/add/remove/force
-
-# Whether to balance spaces inside nested parens
-sp_balance_nested_parens = false # false/true
-
-# Add or remove space between ')' and '{'
-sp_paren_brace = add # ignore/add/remove/force
-
-# Add or remove space before pointer star '*'
-sp_before_ptr_star = add # ignore/add/remove/force
-
-# Add or remove space before pointer star '*' that isn't followed by a variable name
-# If set to 'ignore', sp_before_ptr_star is used instead.
-sp_before_unnamed_ptr_star = add # ignore/add/remove/force
-
-# Add or remove space between pointer stars '*'
-sp_between_ptr_star = remove # ignore/add/remove/force
-
-# Add or remove space after pointer star '*', if followed by a word.
-sp_after_ptr_star = remove # ignore/add/remove/force
-
-# Add or remove space after a pointer star '*', if followed by a func proto/def.
-sp_after_ptr_star_func = add # ignore/add/remove/force
-
-# Add or remove space after a pointer star '*', if followed by an open paren (function types).
-sp_ptr_star_paren = ignore # ignore/add/remove/force
-
-# Add or remove space before a pointer star '*', if followed by a func proto/def.
-sp_before_ptr_star_func = remove # ignore/add/remove/force
-
-# Add or remove space before a reference sign '&'
-sp_before_byref = remove # ignore/add/remove/force
-
-# Add or remove space before a reference sign '&' that isn't followed by a variable name
-# If set to 'ignore', sp_before_byref is used instead.
-sp_before_unnamed_byref = remove # ignore/add/remove/force
-
-# Add or remove space after reference sign '&', if followed by a word.
-sp_after_byref = add # ignore/add/remove/force
-
-# Add or remove space after a reference sign '&', if followed by a func proto/def.
-sp_after_byref_func = add # ignore/add/remove/force
-
-# Add or remove space before a reference sign '&', if followed by a func proto/def.
-sp_before_byref_func = remove # ignore/add/remove/force
-
-# Add or remove space between type and word. Default=Force
-sp_after_type = add # ignore/add/remove/force
-
-# Add or remove space before the paren in the D constructs 'template Foo(' and 'class Foo('.
-sp_before_template_paren = ignore # ignore/add/remove/force
-
-# Add or remove space in 'template <' vs 'template<'.
-# If set to ignore, sp_before_angle is used.
-sp_template_angle = ignore # ignore/add/remove/force
-
-# Add or remove space before '<>'
-sp_before_angle = remove # ignore/add/remove/force
-
-# Add or remove space inside '<' and '>'
-sp_inside_angle = remove # ignore/add/remove/force
-
-# Add or remove space after '<>'
-sp_after_angle = remove # ignore/add/remove/force
-
-# Add or remove space between '<>' and '(' as found in 'new List<byte>();'
-sp_angle_paren = remove # ignore/add/remove/force
-
-# Add or remove space between '<>' and a word as in 'List<byte> m;'
-sp_angle_word = remove # ignore/add/remove/force
-
-# Add or remove space between '>' and '>' in '>>' (template stuff C++/C# only). Default=Add
-sp_angle_shift = add # ignore/add/remove/force
-
-# Permit removal of the space between '>>' in 'foo<bar<int> >' (C++11 only). Default=False
-# sp_angle_shift cannot remove the space without this option.
-sp_permit_cpp11_shift = false # false/true
-
-# Add or remove space before '(' of 'if', 'for', 'switch', and 'while'
-sp_before_sparen = add # ignore/add/remove/force
-
-# Add or remove space inside if-condition '(' and ')'
-sp_inside_sparen = remove # ignore/add/remove/force
-
-# Add or remove space before if-condition ')'. Overrides sp_inside_sparen.
-sp_inside_sparen_close = ignore # ignore/add/remove/force
-
-# Add or remove space before if-condition '('. Overrides sp_inside_sparen.
-sp_inside_sparen_open = ignore # ignore/add/remove/force
-
-# Add or remove space after ')' of 'if', 'for', 'switch', and 'while'
-sp_after_sparen = ignore # ignore/add/remove/force
-
-# Add or remove space between ')' and '{' of 'if', 'for', 'switch', and 'while'
-sp_sparen_brace = add # ignore/add/remove/force
-
-# Add or remove space between 'invariant' and '(' in the D language.
-sp_invariant_paren = ignore # ignore/add/remove/force
-
-# Add or remove space after the ')' in 'invariant (C) c' in the D language.
-sp_after_invariant_paren = ignore # ignore/add/remove/force
-
-# Add or remove space before empty statement ';' on 'if', 'for' and 'while'
-sp_special_semi = remove # ignore/add/remove/force
-
-# Add or remove space before ';'. Default=Remove
-sp_before_semi = remove # ignore/add/remove/force
-
-# Add or remove space before ';' in non-empty 'for' statements
-sp_before_semi_for = remove # ignore/add/remove/force
-
-# Add or remove space before a semicolon of an empty part of a for statement.
-sp_before_semi_for_empty = remove # ignore/add/remove/force
-
-# Add or remove space after ';', except when followed by a comment. Default=Add
-sp_after_semi = add # ignore/add/remove/force
-
-# Add or remove space after ';' in non-empty 'for' statements. Default=Force
-sp_after_semi_for = force # ignore/add/remove/force
-
-# Add or remove space after the final semicolon of an empty part of a for statement: for ( ; ; <here> ).
-sp_after_semi_for_empty = remove # ignore/add/remove/force
-
-# Add or remove space before '[' (except '[]')
-sp_before_square = remove # ignore/add/remove/force
-
-# Add or remove space before '[]'
-sp_before_squares = remove # ignore/add/remove/force
-
-# Add or remove space inside a non-empty '[' and ']'
-sp_inside_square = remove # ignore/add/remove/force
-
-# Add or remove space after ','
-sp_after_comma = add # ignore/add/remove/force
-
-# Add or remove space before ','
-sp_before_comma = remove # ignore/add/remove/force
-
-# Add or remove space between an open paren and comma: '(,' vs '( ,'
-sp_paren_comma = force # ignore/add/remove/force
-
-# Add or remove space before the variadic '...' when preceded by a non-punctuator
-sp_before_ellipsis = ignore # ignore/add/remove/force
-
-# Add or remove space after class ':'
-sp_after_class_colon = add # ignore/add/remove/force
-
-# Add or remove space before class ':'
-sp_before_class_colon = add # ignore/add/remove/force
-
-# Add or remove space before case ':'. Default=Remove
-sp_before_case_colon = remove # ignore/add/remove/force
-
-# Add or remove space between 'operator' and operator sign
-sp_after_operator = remove # ignore/add/remove/force
-
-# Add or remove space between the operator symbol and the open paren, as in 'operator ++('
-sp_after_operator_sym = remove # ignore/add/remove/force
-
-# Add or remove space after C/D cast, i.e. 'cast(int)a' vs 'cast(int) a' or '(int)a' vs '(int) a'
-sp_after_cast = remove # ignore/add/remove/force
-
-# Add or remove spaces inside cast parens
-sp_inside_paren_cast = remove # ignore/add/remove/force
-
-# Add or remove space between the type and open paren in a C++ cast, i.e. 'int(exp)' vs 'int (exp)'
-sp_cpp_cast_paren = remove # ignore/add/remove/force
-
-# Add or remove space between 'sizeof' and '('
-sp_sizeof_paren = remove # ignore/add/remove/force
-
-# Add or remove space after the tag keyword (Pawn)
-sp_after_tag = ignore # ignore/add/remove/force
-
-# Add or remove space inside enum '{' and '}'
-sp_inside_braces_enum = add # ignore/add/remove/force
-
-# Add or remove space inside struct/union '{' and '}'
-sp_inside_braces_struct = add # ignore/add/remove/force
-
-# Add or remove space inside '{' and '}'
-sp_inside_braces = add # ignore/add/remove/force
-
-# Add or remove space inside '{}'
-sp_inside_braces_empty = remove # ignore/add/remove/force
-
-# Add or remove space between return type and function name
-# A minimum of 1 is forced except for pointer return types.
-sp_type_func = add # ignore/add/remove/force
-
-# Add or remove space between function name and '(' on function declaration
-sp_func_proto_paren = remove # ignore/add/remove/force
-
-# Add or remove space between function name and '(' on function definition
-sp_func_def_paren = remove # ignore/add/remove/force
-
-# Add or remove space inside empty function '()'
-sp_inside_fparens = remove # ignore/add/remove/force
-
-# Add or remove space inside function '(' and ')'
-sp_inside_fparen = remove # ignore/add/remove/force
-
-# Add or remove space inside the first parens in the function type: 'void (*x)(...)'
-sp_inside_tparen = ignore # ignore/add/remove/force
-
-# Add or remove between the parens in the function type: 'void (*x)(...)'
-sp_after_tparen_close = ignore # ignore/add/remove/force
-
-# Add or remove space between ']' and '(' when part of a function call.
-sp_square_fparen = remove # ignore/add/remove/force
-
-# Add or remove space between ')' and '{' of function
-sp_fparen_brace = add # ignore/add/remove/force
-
-# Add or remove space between function name and '(' on function calls
-sp_func_call_paren = remove # ignore/add/remove/force
-
-# Add or remove space between function name and '()' on function calls without parameters.
-# If set to 'ignore' (the default), sp_func_call_paren is used.
-sp_func_call_paren_empty = ignore # ignore/add/remove/force
-
-# Add or remove space between the user function name and '(' on function calls
-# You need to set a keyword to be a user function, like this: 'set func_call_user _' in the config file.
-sp_func_call_user_paren = remove # ignore/add/remove/force
-
-# Add or remove space between a constructor/destructor and the open paren
-sp_func_class_paren = remove # ignore/add/remove/force
-
-# Add or remove space between 'return' and '('
-sp_return_paren = add # ignore/add/remove/force
-
-# Add or remove space between '__attribute__' and '('
-sp_attribute_paren = remove # ignore/add/remove/force
-
-# Add or remove space between 'defined' and '(' in '#if defined (FOO)'
-sp_defined_paren = remove # ignore/add/remove/force
-
-# Add or remove space between 'throw' and '(' in 'throw (something)'
-sp_throw_paren = remove # ignore/add/remove/force
-
-# Add or remove space between 'throw' and anything other than '(' as in '@throw [...];'
-sp_after_throw = ignore # ignore/add/remove/force
-
-# Add or remove space between 'catch' and '(' in 'catch (something) { }'
-# If set to ignore, sp_before_sparen is used.
-sp_catch_paren = ignore # ignore/add/remove/force
-
-# Add or remove space between 'version' and '(' in 'version (something) { }' (D language)
-# If set to ignore, sp_before_sparen is used.
-sp_version_paren = ignore # ignore/add/remove/force
-
-# Add or remove space between 'scope' and '(' in 'scope (something) { }' (D language)
-# If set to ignore, sp_before_sparen is used.
-sp_scope_paren = ignore # ignore/add/remove/force
-
-# Add or remove space between macro and value
-sp_macro = add # ignore/add/remove/force
-
-# Add or remove space between macro function ')' and value
-sp_macro_func = remove # ignore/add/remove/force
-
-# Add or remove space between 'else' and '{' if on the same line
-sp_else_brace = add # ignore/add/remove/force
-
-# Add or remove space between '}' and 'else' if on the same line
-sp_brace_else = add # ignore/add/remove/force
-
-# Add or remove space between '}' and the name of a typedef on the same line
-sp_brace_typedef = add # ignore/add/remove/force
-
-# Add or remove space between 'catch' and '{' if on the same line
-sp_catch_brace = add # ignore/add/remove/force
-
-# Add or remove space between '}' and 'catch' if on the same line
-sp_brace_catch = add # ignore/add/remove/force
-
-# Add or remove space between 'finally' and '{' if on the same line
-sp_finally_brace = add # ignore/add/remove/force
-
-# Add or remove space between '}' and 'finally' if on the same line
-sp_brace_finally = add # ignore/add/remove/force
-
-# Add or remove space between 'try' and '{' if on the same line
-sp_try_brace = add # ignore/add/remove/force
-
-# Add or remove space between get/set and '{' if on the same line
-sp_getset_brace = add # ignore/add/remove/force
-
-# Add or remove space before the '::' operator
-sp_before_dc = remove # ignore/add/remove/force
-
-# Add or remove space after the '::' operator
-sp_after_dc = remove # ignore/add/remove/force
-
-# Add or remove around the D named array initializer ':' operator
-sp_d_array_colon = ignore # ignore/add/remove/force
-
-# Add or remove space after the '!' (not) operator. Default=Remove
-sp_not = remove # ignore/add/remove/force
-
-# Add or remove space after the '~' (invert) operator. Default=Remove
-sp_inv = remove # ignore/add/remove/force
-
-# Add or remove space after the '&' (address-of) operator. Default=Remove
-# This does not affect the spacing after a '&' that is part of a type.
-sp_addr = remove # ignore/add/remove/force
-
-# Add or remove space around the '.' or '->' operators. Default=Remove
-sp_member = remove # ignore/add/remove/force
-
-# Add or remove space after the '*' (dereference) operator. Default=Remove
-# This does not affect the spacing after a '*' that is part of a type.
-sp_deref = remove # ignore/add/remove/force
-
-# Add or remove space after '+' or '-', as in 'x = -5' or 'y = +7'. Default=Remove
-sp_sign = remove # ignore/add/remove/force
-
-# Add or remove space before or after '++' and '--', as in '(--x)' or 'y++;'. Default=Remove
-sp_incdec = remove # ignore/add/remove/force
-
-# Add or remove space before a backslash-newline at the end of a line. Default=Add
-sp_before_nl_cont = remove # ignore/add/remove/force
-
-# Add or remove space after the scope '+' or '-', as in '-(void) foo;' or '+(int) bar;'
-sp_after_oc_scope = remove # ignore/add/remove/force
-
-# Add or remove space after the colon in message specs
-# '-(int) f:(int) x;' vs '-(int) f: (int) x;'
-sp_after_oc_colon = remove # ignore/add/remove/force
-
-# Add or remove space before the colon in message specs
-# '-(int) f: (int) x;' vs '-(int) f : (int) x;'
-sp_before_oc_colon = remove # ignore/add/remove/force
-
-# Add or remove space after the colon in immutable dictionary expression
-# 'NSDictionary *test = @{@"foo" :@"bar"};'
-sp_after_oc_dict_colon = ignore # ignore/add/remove/force
-
-# Add or remove space before the colon in immutable dictionary expression
-# 'NSDictionary *test = @{@"foo" :@"bar"};'
-sp_before_oc_dict_colon = ignore # ignore/add/remove/force
-
-# Add or remove space after the colon in message specs
-# '[object setValue:1];' vs '[object setValue: 1];'
-sp_after_send_oc_colon = add # ignore/add/remove/force
-
-# Add or remove space before the colon in message specs
-# '[object setValue:1];' vs '[object setValue :1];'
-sp_before_send_oc_colon = remove # ignore/add/remove/force
-
-# Add or remove space after the (type) in message specs
-# '-(int)f: (int) x;' vs '-(int)f: (int)x;'
-sp_after_oc_type = remove # ignore/add/remove/force
-
-# Add or remove space after the first (type) in message specs
-# '-(int) f:(int)x;' vs '-(int)f:(int)x;'
-sp_after_oc_return_type = ignore # ignore/add/remove/force
-
-# Add or remove space between '@selector' and '('
-# '@selector(msgName)' vs '@selector (msgName)'
-# Also applies to @protocol() constructs
-sp_after_oc_at_sel = ignore # ignore/add/remove/force
-
-# Add or remove space between '@selector(x)' and the following word
-# '@selector(foo) a:' vs '@selector(foo)a:'
-sp_after_oc_at_sel_parens = ignore # ignore/add/remove/force
-
-# Add or remove space inside '@selector' parens
-# '@selector(foo)' vs '@selector( foo )'
-# Also applies to @protocol() constructs
-sp_inside_oc_at_sel_parens = ignore # ignore/add/remove/force
-
-# Add or remove space before a block pointer caret
-# '^int (int arg){...}' vs. ' ^int (int arg){...}'
-sp_before_oc_block_caret = ignore # ignore/add/remove/force
-
-# Add or remove space after a block pointer caret
-# '^int (int arg){...}' vs. '^ int (int arg){...}'
-sp_after_oc_block_caret = ignore # ignore/add/remove/force
-
-# Add or remove space between the receiver and selector in a message.
-# '[receiver selector ...]'
-sp_after_oc_msg_receiver = ignore # ignore/add/remove/force
-
-# Add or remove space after @property.
-sp_after_oc_property = ignore # ignore/add/remove/force
-
-# Add or remove space around the ':' in 'b ? t : f'
-sp_cond_colon = add # ignore/add/remove/force
-
-# Add or remove space around the '?' in 'b ? t : f'
-sp_cond_question = add # ignore/add/remove/force
-
-# Fix the spacing between 'case' and the label. Only 'ignore' and 'force' make sense here.
-sp_case_label = ignore # ignore/add/remove/force
-
-# Control the space around the D '..' operator.
-sp_range = ignore # ignore/add/remove/force
-
-# Control the spacing after ':' in 'for (TYPE VAR : EXPR)' (Java)
-sp_after_for_colon = ignore # ignore/add/remove/force
-
-# Control the spacing before ':' in 'for (TYPE VAR : EXPR)' (Java)
-sp_before_for_colon = ignore # ignore/add/remove/force
-
-# Control the spacing in 'extern (C)' (D)
-sp_extern_paren = ignore # ignore/add/remove/force
-
-# Control the space after the opening of a C++ comment '// A' vs '//A'
-sp_cmt_cpp_start = add # ignore/add/remove/force
-
-# Controls the spaces between #else or #endif and a trailing comment
-sp_endif_cmt = ignore # ignore/add/remove/force
-
-# Controls the spaces after 'new', 'delete', and 'delete[]'
-sp_after_new = ignore # ignore/add/remove/force
-
-# Controls the spaces before a trailing or embedded comment
-sp_before_tr_emb_cmt = ignore # ignore/add/remove/force
-
-# Number of spaces before a trailing or embedded comment
-sp_num_before_tr_emb_cmt = 0 # number
-
-# Control space between a Java annotation and the open paren.
-sp_annotation_paren = ignore # ignore/add/remove/force
-
-#
-# Code alignment (not left column spaces/tabs)
-#
-
-# Whether to keep non-indenting tabs
-align_keep_tabs = false # false/true
-
-# Whether to use tabs for aligning
-align_with_tabs = false # false/true
-
-# Whether to bump out to the next tab when aligning
-align_on_tabstop = false # false/true
-
-# Whether to left-align numbers
-align_number_left = false # false/true
-
-# Align variable definitions in prototypes and functions
-align_func_params = true # false/true
-
-# Align parameters in single-line functions that have the same name.
-# The function names must already be aligned with each other.
-align_same_func_call_params = true # false/true
-
-# The span for aligning variable definitions (0=don't align)
-align_var_def_span = 0 # number
-
-# How to align the star in variable definitions.
-# 0=Part of the type 'void * foo;'
-# 1=Part of the variable 'void *foo;'
-# 2=Dangling 'void *foo;'
-align_var_def_star_style = 1 # number
-
-# How to align the '&' in variable definitions.
-# 0=Part of the type
-# 1=Part of the variable
-# 2=Dangling
-align_var_def_amp_style = 2 # number
-
-# The threshold for aligning variable definitions (0=no limit)
-align_var_def_thresh = 3 # number
-
-# The gap for aligning variable definitions
-align_var_def_gap = 1 # number
-
-# Whether to align the colon in struct bit fields
-align_var_def_colon = true # false/true
-
-# Whether to align any attribute after the variable name
-align_var_def_attribute = true # false/true
-
-# Whether to align inline struct/enum/union variable definitions
-align_var_def_inline = true # false/true
-
-# The span for aligning on '=' in assignments (0=don't align)
-align_assign_span = 0 # number
-
-# The threshold for aligning on '=' in assignments (0=no limit)
-align_assign_thresh = 0 # number
-
-# The span for aligning on '=' in enums (0=don't align)
-align_enum_equ_span = 0 # number
-
-# The threshold for aligning on '=' in enums (0=no limit)
-align_enum_equ_thresh = 0 # number
-
-# The span for aligning struct/union (0=don't align)
-align_var_struct_span = 0 # number
-
-# The threshold for aligning struct/union member definitions (0=no limit)
-align_var_struct_thresh = 0 # number
-
-# The gap for aligning struct/union member definitions
-align_var_struct_gap = 0 # number
-
-# The span for aligning struct initializer values (0=don't align)
-align_struct_init_span = 0 # number
-
-# The minimum space between the type and the synonym of a typedef
-align_typedef_gap = 0 # number
-
-# The span for aligning single-line typedefs (0=don't align)
-align_typedef_span = 0 # number
-
-# How to align typedef'd functions with other typedefs
-# 0: Don't mix them at all
-# 1: align the open paren with the types
-# 2: align the function type name with the other type names
-align_typedef_func = 0 # number
-
-# Controls the positioning of the '*' in typedefs. Just try it.
-# 0: Align on typedef type, ignore '*'
-# 1: The '*' is part of type name: typedef int *pint;
-# 2: The '*' is part of the type, but dangling: typedef int *pint;
-align_typedef_star_style = 2 # number
-
-# Controls the positioning of the '&' in typedefs. Just try it.
-# 0: Align on typedef type, ignore '&'
-# 1: The '&' is part of type name: typedef int &pint;
-# 2: The '&' is part of the type, but dangling: typedef int &pint;
-align_typedef_amp_style = 2 # number
-
-# The span for aligning comments that end lines (0=don't align)
-align_right_cmt_span = 4 # number
-
-# If aligning comments, mix with comments after '}' and #endif with less than 3 spaces before the comment
-align_right_cmt_mix = false # false/true
-
-# If a trailing comment is more than this number of columns away from the text it follows,
-# it will qualify for being aligned. This has to be > 0 to do anything.
-align_right_cmt_gap = 0 # number
-
-# Align trailing comment at or beyond column N; 'pulls in' comments as a bonus side effect (0=ignore)
-align_right_cmt_at_col = 1 # number
-
-# The span for aligning function prototypes (0=don't align)
-align_func_proto_span = 0 # number
-
-# Minimum gap between the return type and the function name.
-align_func_proto_gap = 0 # number
-
-# Align function protos on the 'operator' keyword instead of what follows
-align_on_operator = true # false/true
-
-# Whether to mix aligning prototype and variable declarations.
-# If true, align_var_def_XXX options are used instead of align_func_proto_XXX options.
-align_mix_var_proto = false # false/true
-
-# Align single-line functions with function prototypes, uses align_func_proto_span
-align_single_line_func = true # false/true
-
-# Aligning the open brace of single-line functions.
-# Requires align_single_line_func=true, uses align_func_proto_span
-align_single_line_brace = true # false/true
-
-# Gap for align_single_line_brace.
-align_single_line_brace_gap = 0 # number
-
-# The span for aligning ObjC msg spec (0=don't align)
-align_oc_msg_spec_span = 0 # number
-
-# Whether to align macros wrapped with a backslash and a newline.
-# This will not work right if the macro contains a multi-line comment.
-align_nl_cont = true # false/true
-
-# # Align macro functions and variables together
-align_pp_define_together = false # false/true
-
-# The minimum space between label and value of a preprocessor define
-align_pp_define_gap = 0 # number
-
-# The span for aligning on '#define' bodies (0=don't align)
-align_pp_define_span = 0 # number
-
-# Align lines that start with '<<' with previous '<<'. Default=true
-align_left_shift = true # false/true
-
-# Span for aligning parameters in an Obj-C message call on the ':' (0=don't align)
-align_oc_msg_colon_span = 0 # number
-
-# If true, always align with the first parameter, even if it is too short.
-align_oc_msg_colon_first = false # false/true
-
-# Aligning parameters in an Obj-C '+' or '-' declaration on the ':'
-align_oc_decl_colon = false # false/true
-
-#
-# Newline adding and removing options
-#
-
-# Whether to collapse empty blocks between '{' and '}'
-nl_collapse_empty_body = true # false/true
-
-# Don't split one-line braced assignments - 'foo_t f = { 1, 2 };'
-nl_assign_leave_one_liners = false # false/true
-
-# Don't split one-line braced statements inside a class xx { } body
-nl_class_leave_one_liners = false # false/true
-
-# Don't split one-line enums: 'enum foo { BAR = 15 };'
-nl_enum_leave_one_liners = false # false/true
-
-# Don't split one-line get or set functions
-nl_getset_leave_one_liners = false # false/true
-
-# Don't split one-line function definitions - 'int foo() { return 0; }'
-nl_func_leave_one_liners = false # false/true
-
-# Don't split one-line if/else statements - 'if(a) b++;'
-nl_if_leave_one_liners = true # false/true
-
-# Don't split one-line OC messages
-nl_oc_msg_leave_one_liner = false # false/true
-
-# Add or remove newlines at the start of the file
-nl_start_of_file = ignore # ignore/add/remove/force
-
-# The number of newlines at the start of the file (only used if nl_start_of_file is 'add' or 'force'
-nl_start_of_file_min = 0 # number
-
-# Add or remove newline at the end of the file
-nl_end_of_file = add # ignore/add/remove/force
-
-# The number of newlines at the end of the file (only used if nl_end_of_file is 'add' or 'force')
-nl_end_of_file_min = 1 # number
-
-# Add or remove newline between '=' and '{'
-nl_assign_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between '=' and '[' (D only)
-nl_assign_square = ignore # ignore/add/remove/force
-
-# Add or remove newline after '= [' (D only). Will also affect the newline before the ']'
-nl_after_square_assign = ignore # ignore/add/remove/force
-
-# The number of blank lines after a block of variable definitions at the top of a function body
-# 0 = No change (default)
-nl_func_var_def_blk = 1 # number
-
-# The number of newlines before a block of typedefs
-# 0 = No change (default)
-nl_typedef_blk_start = 0 # number
-
-# The number of newlines after a block of typedefs
-# 0 = No change (default)
-nl_typedef_blk_end = 0 # number
-
-# The maximum consecutive newlines within a block of typedefs
-# 0 = No change (default)
-nl_typedef_blk_in = 0 # number
-
-# The number of newlines before a block of variable definitions not at the top of a function body
-# 0 = No change (default)
-nl_var_def_blk_start = 0 # number
-
-# The number of newlines after a block of variable definitions not at the top of a function body
-# 0 = No change (default)
-nl_var_def_blk_end = 0 # number
-
-# The maximum consecutive newlines within a block of variable definitions
-# 0 = No change (default)
-nl_var_def_blk_in = 0 # number
-
-# Add or remove newline between a function call's ')' and '{', as in:
-# list_for_each(item, &list) { }
-nl_fcall_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'enum' and '{'
-nl_enum_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'struct and '{'
-nl_struct_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'union' and '{'
-nl_union_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'if' and '{'
-nl_if_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between '}' and 'else'
-nl_brace_else = remove # ignore/add/remove/force
-
-# Add or remove newline between 'else if' and '{'
-# If set to ignore, nl_if_brace is used instead
-nl_elseif_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'else' and '{'
-nl_else_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'else' and 'if'
-nl_else_if = ignore # ignore/add/remove/force
-
-# Add or remove newline between '}' and 'finally'
-nl_brace_finally = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'finally' and '{'
-nl_finally_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'try' and '{'
-nl_try_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between get/set and '{'
-nl_getset_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'for' and '{'
-nl_for_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'catch' and '{'
-nl_catch_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between '}' and 'catch'
-nl_brace_catch = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'while' and '{'
-nl_while_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'scope (x)' and '{' (D)
-nl_scope_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'unittest' and '{' (D)
-nl_unittest_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'version (x)' and '{' (D)
-nl_version_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'using' and '{'
-nl_using_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between two open or close braces.
-# Due to general newline/brace handling, REMOVE may not work.
-nl_brace_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'do' and '{'
-nl_do_brace = ignore # ignore/add/remove/force
-
-# Add or remove newline between '}' and 'while' of 'do' statement
-nl_brace_while = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'switch' and '{'
-nl_switch_brace = ignore # ignore/add/remove/force
-
-# Add a newline between ')' and '{' if the ')' is on a different line than the if/for/etc.
-# Overrides nl_for_brace, nl_if_brace, nl_switch_brace, nl_while_switch, and nl_catch_brace.
-nl_multi_line_cond = false # false/true
-
-# Force a newline in a define after the macro name for multi-line defines.
-nl_multi_line_define = false # false/true
-
-# Whether to put a newline before 'case' statement
-nl_before_case = true # false/true
-
-# Add or remove newline between ')' and 'throw'
-nl_before_throw = ignore # ignore/add/remove/force
-
-# Whether to put a newline after 'case' statement
-nl_after_case = true # false/true
-
-# Add or remove a newline between a case ':' and '{'. Overrides nl_after_case.
-nl_case_colon_brace = ignore # ignore/add/remove/force
-
-# Newline between namespace and {
-nl_namespace_brace = remove # ignore/add/remove/force
-
-# Add or remove newline between 'template<>' and whatever follows.
-nl_template_class = ignore # ignore/add/remove/force
-
-# Add or remove newline between 'class' and '{'
-nl_class_brace = remove # ignore/add/remove/force
-
-# Add or remove newline after each ',' in the constructor member initialization
-nl_class_init_args = add # ignore/add/remove/force
-
-# Add or remove newline between return type and function name in a function definition
-nl_func_type_name = ignore # ignore/add/remove/force
-
-# Add or remove newline between return type and function name inside a class {}
-# Uses nl_func_type_name or nl_func_proto_type_name if set to ignore.
-nl_func_type_name_class = ignore # ignore/add/remove/force
-
-# Add or remove newline between function scope and name in a definition
-# Controls the newline after '::' in 'void A::f() { }'
-nl_func_scope_name = ignore # ignore/add/remove/force
-
-# Add or remove newline between return type and function name in a prototype
-nl_func_proto_type_name = ignore # ignore/add/remove/force
-
-# Add or remove newline between a function name and the opening '('
-nl_func_paren = ignore # ignore/add/remove/force
-
-# Add or remove newline between a function name and the opening '(' in the definition
-nl_func_def_paren = ignore # ignore/add/remove/force
-
-# Add or remove newline after '(' in a function declaration
-nl_func_decl_start = ignore # ignore/add/remove/force
-
-# Add or remove newline after '(' in a function definition
-nl_func_def_start = ignore # ignore/add/remove/force
-
-# Overrides nl_func_decl_start when there is only one parameter.
-nl_func_decl_start_single = ignore # ignore/add/remove/force
-
-# Overrides nl_func_def_start when there is only one parameter.
-nl_func_def_start_single = ignore # ignore/add/remove/force
-
-# Add or remove newline after each ',' in a function declaration
-nl_func_decl_args = add # ignore/add/remove/force
-
-# Add or remove newline after each ',' in a function definition
-nl_func_def_args = ignore # ignore/add/remove/force
-
-# Add or remove newline before the ')' in a function declaration
-nl_func_decl_end = ignore # ignore/add/remove/force
-
-# Add or remove newline before the ')' in a function definition
-nl_func_def_end = ignore # ignore/add/remove/force
-
-# Overrides nl_func_decl_end when there is only one parameter.
-nl_func_decl_end_single = ignore # ignore/add/remove/force
-
-# Overrides nl_func_def_end when there is only one parameter.
-nl_func_def_end_single = ignore # ignore/add/remove/force
-
-# Add or remove newline between '()' in a function declaration.
-nl_func_decl_empty = ignore # ignore/add/remove/force
-
-# Add or remove newline between '()' in a function definition.
-nl_func_def_empty = ignore # ignore/add/remove/force
-
-# Whether to put each OC message parameter on a separate line
-# See nl_oc_msg_leave_one_liner
-nl_oc_msg_args = false # false/true
-
-# Add or remove newline between function signature and '{'
-nl_fdef_brace = ignore # ignore/add/remove/force
-
-# Add or remove a newline between the return keyword and return expression.
-nl_return_expr = ignore # ignore/add/remove/force
-
-# Whether to put a newline after semicolons, except in 'for' statements
-nl_after_semicolon = false # false/true
-
-# Whether to put a newline after brace open.
-# This also adds a newline before the matching brace close.
-nl_after_brace_open = false # false/true
-
-# If nl_after_brace_open and nl_after_brace_open_cmt are true, a newline is
-# placed between the open brace and a trailing single-line comment.
-nl_after_brace_open_cmt = false # false/true
-
-# Whether to put a newline after a virtual brace open with a non-empty body.
-# These occur in un-braced if/while/do/for statement bodies.
-nl_after_vbrace_open = false # false/true
-
-# Whether to put a newline after a virtual brace open with an empty body.
-# These occur in un-braced if/while/do/for statement bodies.
-nl_after_vbrace_open_empty = false # false/true
-
-# Whether to put a newline after a brace close.
-# Does not apply if followed by a necessary ';'.
-nl_after_brace_close = false # false/true
-
-# Whether to put a newline after a virtual brace close.
-# Would add a newline before return in: 'if (foo) a++; return;'
-nl_after_vbrace_close = false # false/true
-
-# Control the newline between the close brace and 'b' in: 'struct { int a; } b;'
-# Affects enums, unions, and structures. If set to ignore, uses nl_after_brace_close
-nl_brace_struct_var = ignore # ignore/add/remove/force
-
-# Whether to alter newlines in '#define' macros
-nl_define_macro = true # false/true
-
-# Whether to not put blanks after '#ifxx', '#elxx', or before '#endif'
-nl_squeeze_ifdef = false # false/true
-
-# Add or remove blank line before 'if'
-nl_before_if = add # ignore/add/remove/force
-
-# Add or remove blank line after 'if' statement
-nl_after_if = ignore # ignore/add/remove/force
-
-# Add or remove blank line before 'for'
-nl_before_for = add # ignore/add/remove/force
-
-# Add or remove blank line after 'for' statement
-nl_after_for = ignore # ignore/add/remove/force
-
-# Add or remove blank line before 'while'
-nl_before_while = add # ignore/add/remove/force
-
-# Add or remove blank line after 'while' statement
-nl_after_while = ignore # ignore/add/remove/force
-
-# Add or remove blank line before 'switch'
-nl_before_switch = add # ignore/add/remove/force
-
-# Add or remove blank line after 'switch' statement
-nl_after_switch = ignore # ignore/add/remove/force
-
-# Add or remove blank line before 'do'
-nl_before_do = add # ignore/add/remove/force
-
-# Add or remove blank line after 'do/while' statement
-nl_after_do = ignore # ignore/add/remove/force
-
-# Whether to double-space commented-entries in struct/enum
-nl_ds_struct_enum_cmt = true # false/true
-
-# Whether to double-space before the close brace of a struct/union/enum
-# (lower priority than 'eat_blanks_before_close_brace')
-nl_ds_struct_enum_close_brace = true # false/true
-
-# Add or remove a newline around a class colon.
-# Related to pos_class_colon, nl_class_init_args, and pos_comma.
-nl_class_colon = ignore # ignore/add/remove/force
-
-# Change simple unbraced if statements into a one-liner
-# 'if(b)\n i++;' => 'if(b) i++;'
-nl_create_if_one_liner = true # false/true
-
-# Change simple unbraced for statements into a one-liner
-# 'for (i=0;i<5;i++)\n foo(i);' => 'for (i=0;i<5;i++) foo(i);'
-nl_create_for_one_liner = true # false/true
-
-# Change simple unbraced while statements into a one-liner
-# 'while (i<5)\n foo(i++);' => 'while (i<5) foo(i++);'
-nl_create_while_one_liner = true # false/true
-
-#
-# Positioning options
-#
-
-# The position of arithmetic operators in wrapped expressions
-pos_arith = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force
-
-# The position of assignment in wrapped expressions.
-# Do not affect '=' followed by '{'
-pos_assign = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force
-
-# The position of boolean operators in wrapped expressions
-pos_bool = lead_break # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force
-
-# The position of comparison operators in wrapped expressions
-pos_compare = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force
-
-# The position of conditional (b ? t : f) operators in wrapped expressions
-pos_conditional = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force
-
-# The position of the comma in wrapped expressions
-pos_comma = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force
-
-# The position of the comma in the constructor initialization list
-pos_class_comma = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force
-
-# The position of colons between constructor and member initialization
-pos_class_colon = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force
-
-#
-# Line Splitting options
-#
-
-# Try to limit code width to N number of columns
-code_width = 80 # number
-
-# Whether to fully split long 'for' statements at semi-colons
-ls_for_split_full = false # false/true
-
-# Whether to fully split long function protos/calls at commas
-ls_func_split_full = true # false/true
-
-# Whether to split lines as close to code_width as possible and ignore some groupings
-ls_code_width = false # false/true
-
-#
-# Blank line options
-#
-
-# The maximum consecutive newlines
-nl_max = 3 # number
-
-# The number of newlines after a function prototype, if followed by another function prototype
-nl_after_func_proto = 0 # number
-
-# The number of newlines after a function prototype, if not followed by another function prototype
-nl_after_func_proto_group = 0 # number
-
-# The number of newlines after '}' of a multi-line function body
-nl_after_func_body = 2 # number
-
-# The number of newlines after '}' of a multi-line function body in a class declaration
-nl_after_func_body_class = 0 # number
-
-# The number of newlines after '}' of a single line function body
-nl_after_func_body_one_liner = 2 # number
-
-# The minimum number of newlines before a multi-line comment.
-# Doesn't apply if after a brace open or another multi-line comment.
-nl_before_block_comment = 2 # number
-
-# The minimum number of newlines before a single-line C comment.
-# Doesn't apply if after a brace open or other single-line C comments.
-nl_before_c_comment = 2 # number
-
-# The minimum number of newlines before a CPP comment.
-# Doesn't apply if after a brace open or other CPP comments.
-nl_before_cpp_comment = 2 # number
-
-# Whether to force a newline after a multi-line comment.
-nl_after_multiline_comment = true # false/true
-
-# The number of newlines after '}' or ';' of a struct/enum/union definition
-nl_after_struct = 0 # number
-
-# The number of newlines after '}' or ';' of a class definition
-nl_after_class = 0 # number
-
-# The number of newlines before a 'private:', 'public:', 'protected:', 'signals:', or 'slots:' label.
-# Will not change the newline count if after a brace open.
-# 0 = No change.
-nl_before_access_spec = 2 # number
-
-# The number of newlines after a 'private:', 'public:', 'protected:', 'signals:', or 'slots:' label.
-# 0 = No change.
-nl_after_access_spec = 2 # number
-
-# The number of newlines between a function def and the function comment.
-# 0 = No change.
-nl_comment_func_def = 1 # number
-
-# The number of newlines after a try-catch-finally block that isn't followed by a brace close.
-# 0 = No change.
-nl_after_try_catch_finally = 1 # number
-
-# The number of newlines before and after a property, indexer or event decl.
-# 0 = No change.
-nl_around_cs_property = 0 # number
-
-# The number of newlines between the get/set/add/remove handlers in C#.
-# 0 = No change.
-nl_between_get_set = 0 # number
-
-# Add or remove newline between C# property and the '{'
-nl_property_brace = ignore # ignore/add/remove/force
-
-# Whether to remove blank lines after '{'
-eat_blanks_after_open_brace = true # false/true
-
-# Whether to remove blank lines before '}'
-eat_blanks_before_close_brace = true # false/true
-
-# How aggressively to remove extra newlines not in preproc.
-# 0: No change
-# 1: Remove most newlines not handled by other config
-# 2: Remove all newlines and reformat completely by config
-nl_remove_extra_newlines = 0 # number
-
-# Whether to put a blank line before 'return' statements, unless after an open brace.
-nl_before_return = false # false/true
-
-# Whether to put a blank line after 'return' statements, unless followed by a close brace.
-nl_after_return = true # false/true
-
-# Whether to put a newline after a Java annotation statement.
-# Only affects annotations that are after a newline.
-nl_after_annotation = ignore # ignore/add/remove/force
-
-# Controls the newline between two annotations.
-nl_between_annotation = ignore # ignore/add/remove/force
-
-#
-# Code modifying options (non-whitespace)
-#
-
-# Add or remove braces on single-line 'do' statement
-mod_full_brace_do = add # ignore/add/remove/force
-
-# Add or remove braces on single-line 'for' statement
-mod_full_brace_for = add # ignore/add/remove/force
-
-# Add or remove braces on single-line function definitions. (Pawn)
-mod_full_brace_function = ignore # ignore/add/remove/force
-
-# Add or remove braces on single-line 'if' statement. Will not remove the braces if they contain an 'else'.
-mod_full_brace_if = add # ignore/add/remove/force
-
-# Make all if/elseif/else statements in a chain be braced or not. Overrides mod_full_brace_if.
-# If any must be braced, they are all braced. If all can be unbraced, then the braces are removed.
-mod_full_brace_if_chain = false # false/true
-
-# Don't remove braces around statements that span N newlines
-mod_full_brace_nl = 1 # number
-
-# Add or remove braces on single-line 'while' statement
-mod_full_brace_while = add # ignore/add/remove/force
-
-# Add or remove braces on single-line 'using ()' statement
-mod_full_brace_using = ignore # ignore/add/remove/force
-
-# Add or remove unnecessary paren on 'return' statement
-mod_paren_on_return = remove # ignore/add/remove/force
-
-# Whether to change optional semicolons to real semicolons
-mod_pawn_semicolon = false # false/true
-
-# Add parens on 'while' and 'if' statement around bools
-mod_full_paren_if_bool = true # false/true
-
-# Whether to remove superfluous semicolons
-mod_remove_extra_semicolon = true # false/true
-
-# If a function body exceeds the specified number of newlines and doesn't have a comment after
-# the close brace, a comment will be added.
-mod_add_long_function_closebrace_comment = 0 # number
-
-# If a switch body exceeds the specified number of newlines and doesn't have a comment after
-# the close brace, a comment will be added.
-mod_add_long_switch_closebrace_comment = 0 # number
-
-# If an #ifdef body exceeds the specified number of newlines and doesn't have a comment after
-# the #endif, a comment will be added.
-mod_add_long_ifdef_endif_comment = 1 # number
-
-# If an #ifdef or #else body exceeds the specified number of newlines and doesn't have a comment after
-# the #else, a comment will be added.
-mod_add_long_ifdef_else_comment = 1 # number
-
-# If TRUE, will sort consecutive single-line 'import' statements [Java, D]
-mod_sort_import = false # false/true
-
-# If TRUE, will sort consecutive single-line 'using' statements [C#]
-mod_sort_using = false # false/true
-
-# If TRUE, will sort consecutive single-line '#include' statements [C/C++] and '#import' statements [Obj-C]
-# This is generally a bad idea, as it may break your code.
-mod_sort_include = false # false/true
-
-# If TRUE, it will move a 'break' that appears after a fully braced 'case' before the close brace.
-mod_move_case_break = true # false/true
-
-# Will add or remove the braces around a fully braced case statement.
-# Will only remove the braces if there are no variable declarations in the block.
-mod_case_brace = ignore # ignore/add/remove/force
-
-# If TRUE, it will remove a void 'return;' that appears as the last statement in a function.
-mod_remove_empty_return = true # false/true
-
-#
-# Comment modifications
-#
-
-# Try to wrap comments at cmt_width columns
-cmt_width = 80 # number
-
-# Set the comment reflow mode (default: 0)
-# 0: no reflowing (apart from the line wrapping due to cmt_width)
-# 1: no touching at all
-# 2: full reflow
-cmt_reflow_mode = 0 # number
-
-# If false, disable all multi-line comment changes, including cmt_width. keyword substitution, and leading chars.
-# Default is true.
-cmt_indent_multi = true # false/true
-
-# Whether to group c-comments that look like they are in a block
-cmt_c_group = false # false/true
-
-# Whether to put an empty '/*' on the first line of the combined c-comment
-cmt_c_nl_start = false # false/true
-
-# Whether to put a newline before the closing '*/' of the combined c-comment
-cmt_c_nl_end = false # false/true
-
-# Whether to group cpp-comments that look like they are in a block
-cmt_cpp_group = false # false/true
-
-# Whether to put an empty '/*' on the first line of the combined cpp-comment
-cmt_cpp_nl_start = false # false/true
-
-# Whether to put a newline before the closing '*/' of the combined cpp-comment
-cmt_cpp_nl_end = false # false/true
-
-# Whether to change cpp-comments into c-comments
-cmt_cpp_to_c = false # false/true
-
-# Whether to put a star on subsequent comment lines
-cmt_star_cont = false # false/true
-
-# The number of spaces to insert at the start of subsequent comment lines
-cmt_sp_before_star_cont = 0 # number
-
-# The number of spaces to insert after the star on subsequent comment lines
-cmt_sp_after_star_cont = 0 # number
-
-# For multi-line comments with a '*' lead, remove leading spaces if the first and last lines of
-# the comment are the same length. Default=True
-cmt_multi_check_last = true # false/true
-
-# The filename that contains text to insert at the head of a file if the file doesn't start with a C/C++ comment.
-# Will substitute $(filename) with the current file's name.
-cmt_insert_file_header = "" # string
-
-# The filename that contains text to insert at the end of a file if the file doesn't end with a C/C++ comment.
-# Will substitute $(filename) with the current file's name.
-cmt_insert_file_footer = "" # string
-
-# The filename that contains text to insert before a function implementation if the function isn't preceded with a C/C++ comment.
-# Will substitute $(function) with the function name and $(javaparam) with the javadoc @param and @return stuff.
-# Will also substitute $(fclass) with the class name: void CFoo::Bar() { ... }
-cmt_insert_func_header = "" # string
-
-# The filename that contains text to insert before a class if the class isn't preceded with a C/C++ comment.
-# Will substitute $(class) with the class name.
-cmt_insert_class_header = "" # string
-
-# The filename that contains text to insert before an Obj-C message specification if the method isn't preceded with a C/C++ comment.
-# Will substitute $(message) with the function name and $(javaparam) with the javadoc @param and @return stuff.
-cmt_insert_oc_msg_header = "" # string
-
-# If a preprocessor is encountered when stepping backwards from a function name, then
-# this option decides whether the comment should be inserted.
-# Affects cmt_insert_oc_msg_header, cmt_insert_func_header and cmt_insert_class_header.
-cmt_insert_before_preproc = false # false/true
-
-#
-# Preprocessor options
-#
-
-# Control indent of preprocessors inside #if blocks at brace level 0
-pp_indent = ignore # ignore/add/remove/force
-
-# Whether to indent #if/#else/#endif at the brace level (true) or from column 1 (false)
-pp_indent_at_level = false # false/true
-
-# If pp_indent_at_level=false, specifies the number of columns to indent per level. Default=1.
-pp_indent_count = 1 # number
-
-# Add or remove space after # based on pp_level of #if blocks
-pp_space = add # ignore/add/remove/force
-
-# Sets the number of spaces added with pp_space
-pp_space_count = 0 # number
-
-# The indent for #region and #endregion in C# and '#pragma region' in C/C++
-pp_indent_region = 0 # number
-
-# Whether to indent the code between #region and #endregion
-pp_region_indent_code = false # false/true
-
-# If pp_indent_at_level=true, sets the indent for #if, #else, and #endif when not at file-level
-pp_indent_if = 0 # number
-
-# Control whether to indent the code between #if, #else and #endif when not at file-level
-pp_if_indent_code = false # false/true
-
-# Whether to indent '#define' at the brace level (true) or from column 1 (false)
-pp_define_at_level = false # false/true
-
-# You can force a token to be a type with the 'type' option.
-# Example:
-# type myfoo1 myfoo2
-#
-# You can create custom macro-based indentation using macro-open,
-# macro-else and macro-close.
-# Example:
-# macro-open BEGIN_TEMPLATE_MESSAGE_MAP
-# macro-open BEGIN_MESSAGE_MAP
-# macro-close END_MESSAGE_MAP
-#
-# You can assign any keyword to any type with the set option.
-# set func_call_user _ N_
-#
-# The full syntax description of all custom definition config entries
-# is shown below:
-#
-# define custom tokens as:
-# - embed whitespace in token using '' escape character, or
-# put token in quotes
-# - these: ' " and ` are recognized as quote delimiters
-#
-# type token1 token2 token3 ...
-# ^ optionally specify multiple tokens on a single line
-# define def_token output_token
-# ^ output_token is optional, then NULL is assumed
-# macro-open token
-# macro-close token
-# macro-else token
-# set id token1 token2 ...
-# ^ optionally specify multiple tokens on a single line
-# ^ id is one of the names in token_enum.h sans the CT_ prefix,
-# e.g. PP_PRAGMA
-#
-# all tokens are separated by any mix of ',' commas, '=' equal signs
-# and whitespace (space, tab)
-#
diff --git a/man/nvim.1 b/man/nvim.1
index ca0f41d489..3f57f397d2 100644
--- a/man/nvim.1
+++ b/man/nvim.1
@@ -100,7 +100,7 @@ Useful for scripting because it does NOT start a UI, unlike
.Ic :help silent-mode
.It Fl d
Diff mode.
-Show the difference between two to four files, similar to
+Show the difference between two to eight files, similar to
.Xr sdiff 1 .
.Ic ":help diff"
.It Fl R
diff --git a/runtime/autoload/ada.vim b/runtime/autoload/ada.vim
index d04feb9250..3f1b40398f 100644
--- a/runtime/autoload/ada.vim
+++ b/runtime/autoload/ada.vim
@@ -67,13 +67,13 @@ if exists ('g:ada_with_gnat_project_files')
endfor
endif
-" Section: add standart exception {{{2
+" Section: add standard exception {{{2
"
for Item in ['Constraint_Error', 'Program_Error', 'Storage_Error', 'Tasking_Error', 'Status_Error', 'Mode_Error', 'Name_Error', 'Use_Error', 'Device_Error', 'End_Error', 'Data_Error', 'Layout_Error', 'Length_Error', 'Pattern_Error', 'Index_Error', 'Translation_Error', 'Time_Error', 'Argument_Error', 'Tag_Error', 'Picture_Error', 'Terminator_Error', 'Conversion_Error', 'Pointer_Error', 'Dereference_Error', 'Update_Error']
let g:ada#Keywords += [{
\ 'word': Item,
\ 'menu': 'exception',
- \ 'info': 'Ada standart exception.',
+ \ 'info': 'Ada standard exception.',
\ 'kind': 'x',
\ 'icase': 1}]
endfor
@@ -210,7 +210,7 @@ function ada#Word (...)
let l:Line = substitute (getline (l:Line_Nr), g:ada#Comment, '', '' )
" Cope with tag searching for items in comments; if we are, don't loop
- " backards looking for previous lines
+ " backwards looking for previous lines
if l:Column_Nr > strlen(l:Line)
" We were in a comment
let l:Line = getline(l:Line_Nr)
diff --git a/runtime/autoload/adacomplete.vim b/runtime/autoload/adacomplete.vim
index 2659f51d5c..d7bba93d12 100644
--- a/runtime/autoload/adacomplete.vim
+++ b/runtime/autoload/adacomplete.vim
@@ -14,7 +14,7 @@
" 15.10.2006 MK Bram's suggestion for runtime integration
" 05.11.2006 MK Bram suggested not to use include protection for
" autoload
-" 05.11.2006 MK Bram suggested agaist using setlocal omnifunc
+" 05.11.2006 MK Bram suggested against using setlocal omnifunc
" 05.11.2006 MK Bram suggested to save on spaces
" Help Page: ft-ada-omni
"------------------------------------------------------------------------------
diff --git a/runtime/autoload/csscomplete.vim b/runtime/autoload/csscomplete.vim
index f6c5a6c391..4b673ac9b8 100644
--- a/runtime/autoload/csscomplete.vim
+++ b/runtime/autoload/csscomplete.vim
@@ -4,7 +4,7 @@
" plus CSS Speech Module <http://www.w3.org/TR/css3-speech/>
" Maintainer: Kao, Wei-Ko(othree) ( othree AT gmail DOT com )
" Original Author: Mikolaj Machowski ( mikmach AT wp DOT pl )
-" Last Change: 2018 Jul 02
+" Last Change: 2021 Sep 21
let s:values = split("all additive-symbols align-content align-items align-self animation animation-delay animation-direction animation-duration animation-fill-mode animation-iteration-count animation-name animation-play-state animation-timing-function backface-visibility background background-attachment background-blend-mode background-clip background-color background-image background-origin background-position background-repeat background-size block-size border border-block-end border-block-end-color border-block-end-style border-block-end-width border-block-start border-block-start-color border-block-start-style border-block-start-width border-bottom border-bottom-color border-bottom-left-radius border-bottom-right-radius border-bottom-style border-bottom-width border-collapse border-color border-image border-image-outset border-image-repeat border-image-slice border-image-source border-image-width border-inline-end border-inline-end-color border-inline-end-style border-inline-end-width border-inline-start border-inline-start-color border-inline-start-style border-inline-start-width border-left border-left-color border-left-style border-left-width border-radius border-right border-right-color border-right-style border-right-width border-spacing border-style border-top border-top-color border-top-left-radius border-top-right-radius border-top-style border-top-width border-width bottom box-decoration-break box-shadow box-sizing break-after break-before break-inside caption-side clear clip clip-path color columns column-count column-fill column-gap column-rule column-rule-color column-rule-style column-rule-width column-span column-width content counter-increment counter-reset cue cue-before cue-after cursor direction display empty-cells fallback filter flex flex-basis flex-direction flex-flow flex-grow flex-shrink flex-wrap float font font-family font-feature-settings font-kerning font-language-override font-size font-size-adjust font-stretch font-style font-synthesis font-variant font-variant-alternates font-variant-caps font-variant-east-asian font-variant-ligatures font-variant-numeric font-variant-position font-weight grid grid-area grid-auto-columns grid-auto-flow grid-auto-position grid-auto-rows grid-column grid-column-start grid-column-end grid-row grid-row-start grid-row-end grid-template grid-template-areas grid-template-rows grid-template-columns height hyphens image-rendering image-resolution image-orientation ime-mode inline-size isolation justify-content left letter-spacing line-break line-height list-style list-style-image list-style-position list-style-type margin margin-block-end margin-block-start margin-bottom margin-inline-end margin-inline-start margin-left margin-right margin-top marks mask mask-type max-block-size max-height max-inline-size max-width max-zoom min-block-size min-height min-inline-size min-width min-zoom mix-blend-mode negative object-fit object-position offset-block-end offset-block-start offset-inline-end offset-inline-start opacity order orientation orphans outline outline-color outline-offset outline-style outline-width overflow overflow-wrap overflow-x overflow-y pad padding padding-block-end padding-block-start padding-bottom padding-inline-end padding-inline-start padding-left padding-right padding-top page-break-after page-break-before page-break-inside pause-before pause-after pause perspective perspective-origin pointer-events position prefix quotes range resize rest rest-before rest-after right ruby-align ruby-merge ruby-position scroll-behavior scroll-snap-coordinate scroll-snap-destination scroll-snap-points-x scroll-snap-points-y scroll-snap-type scroll-snap-type-x scroll-snap-type-y shape-image-threshold shape-margin shape-outside speak speak-as suffix symbols system table-layout tab-size text-align text-align-last text-combine-upright text-decoration text-decoration-color text-decoration-line text-emphasis text-emphasis-color text-emphasis-position text-emphasis-style text-indent text-orientation text-overflow text-rendering text-shadow text-transform text-underline-position top touch-action transform transform-box transform-origin transform-style transition transition-delay transition-duration transition-property transition-timing-function unicode-bidi unicode-range user-zoom vertical-align visibility voice-balance voice-duration voice-family voice-pitch voice-rate voice-range voice-stress voice-volume white-space widows width will-change word-break word-spacing word-wrap writing-mode z-index zoom")
@@ -38,12 +38,12 @@ function! csscomplete#CompleteCSS(findstart, base)
if exists("b:compl_context")
let line = getline('.')
let compl_begin = col('.') - 2
- let after = line[compl_begin:]
+ let b:after = line[compl_begin:]
let line = b:compl_context
unlet! b:compl_context
else
let line = a:base
- let after = ''
+ let b:after = ''
endif
let res = []
@@ -311,7 +311,7 @@ function! csscomplete#CompleteCSS(findstart, base)
let values = ["normal", "italic", "oblique", "small-caps", "bold", "bolder", "lighter", "100", "200", "300", "400", "500", "600", "700", "800", "900", "xx-small", "x-small", "small", "medium", "large", "x-large", "xx-large", "larger", "smaller", "sans-serif", "serif", "monospace", "cursive", "fantasy", "caption", "icon", "menu", "message-box", "small-caption", "status-bar"]
elseif prop =~ '^\%(height\|width\)$'
let values = ["auto", "border-box", "content-box", "max-content", "min-content", "available", "fit-content"]
- elseif prop =~ '^\%(left\|rigth\)$'
+ elseif prop =~ '^\%(left\|right\)$'
let values = ["auto"]
elseif prop == 'image-rendering'
let values = ["auto", "crisp-edges", "pixelated"]
diff --git a/runtime/autoload/decada.vim b/runtime/autoload/decada.vim
index 5124429a75..fda2b76dac 100644
--- a/runtime/autoload/decada.vim
+++ b/runtime/autoload/decada.vim
@@ -23,7 +23,7 @@ endif
function decada#Unit_Name () dict " {{{1
" Convert filename into acs unit:
- " 1: remove the file extenstion.
+ " 1: remove the file extension.
" 2: replace all double '_' or '-' with an dot (which denotes a separate)
" 3: remove a trailing '_' (which denotes a specification)
return substitute (substitute (expand ("%:t:r"), '__\|-', ".", "g"), '_$', "", '')
diff --git a/runtime/autoload/dist/ft.vim b/runtime/autoload/dist/ft.vim
index ac80659113..7484149a26 100644
--- a/runtime/autoload/dist/ft.vim
+++ b/runtime/autoload/dist/ft.vim
@@ -264,6 +264,14 @@ func dist#ft#ProtoCheck(default)
endfunc
func dist#ft#FTm()
+ if exists("g:filetype_m")
+ exe "setf " . g:filetype_m
+ return
+ endif
+
+ " excluding end(for|function|if|switch|while) common to Murphi
+ let octave_block_terminators = '\<end\%(_try_catch\|classdef\|enumeration\|events\|methods\|parfor\|properties\)\>'
+
let n = 1
let saw_comment = 0 " Whether we've seen a multiline comment leader.
while n < 100
@@ -278,6 +286,12 @@ func dist#ft#FTm()
setf objc
return
endif
+ if line =~ '^\s*\%(#\|%!\)' || line =~ '^\s*unwind_protect\>' ||
+ \ line =~ '\%(^\|;\)\s*' .. octave_block_terminators
+ setf octave
+ return
+ endif
+ " TODO: could be Matlab or Octave
if line =~ '^\s*%'
setf matlab
return
@@ -298,11 +312,8 @@ func dist#ft#FTm()
" or Murphi based on the comment leader. Assume the former as it is more
" common.
setf objc
- elseif exists("g:filetype_m")
- " Use user specified default filetype for .m
- exe "setf " . g:filetype_m
else
- " Default is matlab
+ " Default is Matlab
setf matlab
endif
endfunc
diff --git a/runtime/autoload/haskellcomplete.vim b/runtime/autoload/haskellcomplete.vim
index 48fbac7f9f..759ff8741a 100644
--- a/runtime/autoload/haskellcomplete.vim
+++ b/runtime/autoload/haskellcomplete.vim
@@ -54,7 +54,7 @@ function! haskellcomplete#Complete(findstart, base)
if b:completingLangExtension
if a:base ==? ""
- " Return all posible Lang extensions
+ " Return all possible Lang extensions
return s:langExtensions
else
let l:matches = []
@@ -70,7 +70,7 @@ function! haskellcomplete#Complete(findstart, base)
elseif b:completingOptionsGHC
if a:base ==? ""
- " Return all posible GHC options
+ " Return all possible GHC options
return s:optionsGHC
else
let l:matches = []
@@ -86,7 +86,7 @@ function! haskellcomplete#Complete(findstart, base)
elseif b:completingModule
if a:base ==? ""
- " Return all posible modules
+ " Return all possible modules
return s:commonModules
else
let l:matches = []
diff --git a/runtime/autoload/health/lsp.vim b/runtime/autoload/health/lsp.vim
new file mode 100644
index 0000000000..2d2ba91cdf
--- /dev/null
+++ b/runtime/autoload/health/lsp.vim
@@ -0,0 +1,5 @@
+function! health#lsp#check() abort
+ call health#report_start('Checking language server client configuration')
+ lua require 'vim.lsp.health'.check_health()
+endfunction
+
diff --git a/runtime/autoload/htmlcomplete.vim b/runtime/autoload/htmlcomplete.vim
index 6b9d49a469..267889d97f 100644
--- a/runtime/autoload/htmlcomplete.vim
+++ b/runtime/autoload/htmlcomplete.vim
@@ -486,7 +486,7 @@ function! htmlcomplete#CompleteTags(findstart, base)
endif
endif
" Value of attribute completion {{{
- " If attr contains =\s*[\"'] we catched value of attribute
+ " If attr contains =\s*[\"'] we match value of attribute
if attr =~ "=\s*[\"']" || attr =~ "=\s*$"
" Let do attribute specific completion
let attrname = matchstr(attr, '.*\ze\s*=')
diff --git a/runtime/autoload/man.vim b/runtime/autoload/man.vim
index 4f556e6e87..4f132b6121 100644
--- a/runtime/autoload/man.vim
+++ b/runtime/autoload/man.vim
@@ -58,6 +58,7 @@ function! man#open_page(count, mods, ...) abort
else
execute 'silent keepalt' a:mods 'stag' l:target
endif
+ call s:set_options(v:false)
finally
call setbufvar(l:buf, '&tagfunc', l:save_tfu)
endtry
@@ -65,6 +66,7 @@ function! man#open_page(count, mods, ...) abort
let b:man_sect = sect
endfunction
+" Called when a man:// buffer is opened.
function! man#read_page(ref) abort
try
let [sect, name] = s:extract_sect_and_name_ref(a:ref)
@@ -121,6 +123,15 @@ function! s:system(cmd, ...) abort
return opts.stdout
endfunction
+function! s:set_options(pager) abort
+ setlocal filetype=man
+ setlocal noswapfile buftype=nofile bufhidden=hide
+ setlocal nomodified readonly nomodifiable
+ if a:pager
+ nnoremap <silent> <buffer> <nowait> q :lclose<CR>:q<CR>
+ endif
+endfunction
+
function! s:get_page(path) abort
" Disable hard-wrap by using a big $MANWIDTH (max 1000 on some systems #9065).
" Soft-wrap: ftplugin/man.vim sets wrap/breakindent/….
@@ -134,9 +145,7 @@ function! s:get_page(path) abort
endfunction
function! s:put_page(page) abort
- setlocal modifiable
- setlocal noreadonly
- setlocal noswapfile
+ setlocal modifiable noreadonly noswapfile
silent keepjumps %delete _
silent put =a:page
while getline(1) =~# '^\s*$'
@@ -148,7 +157,7 @@ function! s:put_page(page) abort
silent! keeppatterns keepjumps %s/\s\{199,}/\=repeat(' ', 10)/g
1
lua require("man").highlight_man_page()
- setlocal filetype=man
+ call s:set_options(v:false)
endfunction
function! man#show_toc() abort
@@ -397,6 +406,7 @@ function! s:format_candidate(path, psect) abort
endif
endfunction
+" Called when Nvim is invoked as $MANPAGER.
function! man#init_pager() abort
" https://github.com/neovim/neovim/issues/6828
let og_modifiable = &modifiable
@@ -420,6 +430,7 @@ function! man#init_pager() abort
execute 'silent file man://'.tolower(fnameescape(ref))
endif
+ call s:set_options(v:true)
let &l:modifiable = og_modifiable
endfunction
diff --git a/runtime/autoload/netrw.vim b/runtime/autoload/netrw.vim
index 74ceab35d4..b6edc4c4d8 100644
--- a/runtime/autoload/netrw.vim
+++ b/runtime/autoload/netrw.vim
@@ -1,7 +1,7 @@
" netrw.vim: Handles file transfer and remote directory listing across
" AUTOLOAD SECTION
-" Date: Sep 18, 2020
-" Version: 170
+" Date: Aug 16, 2021
+" Version: 171
" Maintainer: Charles E Campbell <NcampObell@SdrPchip.AorgM-NOSPAM>
" GetLatestVimScripts: 1075 1 :AutoInstall: netrw.vim
" Copyright: Copyright (C) 2016 Charles E. Campbell {{{1
@@ -43,7 +43,7 @@ if exists("s:needspatches")
endfor
endif
-let g:loaded_netrw = "v170"
+let g:loaded_netrw = "v171"
if !exists("s:NOTE")
let s:NOTE = 0
let s:WARNING = 1
@@ -93,7 +93,7 @@ fun! netrw#ErrorMsg(level,msg,errnum)
else
let msg= level.a:msg
endif
- let s:popuperr_id = popup_beval(msg,{})
+ let s:popuperr_id = popup_atcursor(msg,{})
let s:popuperr_text= ""
elseif g:netrw_use_errorwindow
" (default) netrw creates a one-line window to show error/warning
@@ -322,6 +322,7 @@ call s:NetrwInit("g:netrw_banner" , 1)
call s:NetrwInit("g:netrw_browse_split", 0)
call s:NetrwInit("g:netrw_bufsettings" , "noma nomod nonu nobl nowrap ro nornu")
call s:NetrwInit("g:netrw_chgwin" , -1)
+call s:NetrwInit("g:netrw_clipboard" , 1)
call s:NetrwInit("g:netrw_compress" , "gzip")
call s:NetrwInit("g:netrw_ctags" , "ctags")
if exists("g:netrw_cursorline") && !exists("g:netrw_cursor")
@@ -331,6 +332,7 @@ endif
call s:NetrwInit("g:netrw_cursor" , 2)
let s:netrw_usercul = &cursorline
let s:netrw_usercuc = &cursorcolumn
+"call Decho("(netrw) COMBAK: cuc=".&l:cuc." cul=".&l:cul." initialization of s:netrw_cu[cl]")
call s:NetrwInit("g:netrw_cygdrive","/cygdrive")
" Default values - d-g ---------- {{{3
call s:NetrwInit("s:didstarstar",0)
@@ -1606,7 +1608,8 @@ endfun
fun! s:NetrwOptionsSave(vt)
" call Dfunc("s:NetrwOptionsSave(vt<".a:vt.">) win#".winnr()." buf#".bufnr("%")."<".bufname(bufnr("%")).">"." winnr($)=".winnr("$")." mod=".&mod." ma=".&ma)
" call Decho(a:vt."netrw_optionsave".(exists("{a:vt}netrw_optionsave")? ("=".{a:vt}netrw_optionsave) : " doesn't exist"),'~'.expand("<slnum>"))
-" call Decho("settings buf#".bufnr("%")."<".bufname("%").">: ".((&l:ma == 0)? "no" : "")."ma ".((&l:mod == 0)? "no" : "")."mod ".((&l:bl == 0)? "no" : "")."bl ".((&l:ro == 0)? "no" : "")."ro fo=".&l:fo." a:vt=".a:vt,'~'.expand("<slnum>"))
+" call Decho("settings buf#".bufnr("%")."<".bufname("%").">: ".((&l:ma == 0)? "no" : "")."ma ".((&l:mod == 0)? "no" : "")."mod ".((&l:bl == 0)? "no" : "")."bl ".((&l:ro == 0)? "no" : "")."ro fo=".&l:fo." a:vt=".a:vt." hid=".&hid,'~'.expand("<slnum>"))
+" call Decho("(s:NetrwOptionsSave) lines=".&lines)
if !exists("{a:vt}netrw_optionsave")
let {a:vt}netrw_optionsave= 1
@@ -1632,6 +1635,9 @@ fun! s:NetrwOptionsSave(vt)
let {a:vt}netrw_cinokeep = &l:cino
let {a:vt}netrw_comkeep = &l:com
let {a:vt}netrw_cpokeep = &l:cpo
+ let {a:vt}netrw_cuckeep = &l:cuc
+ let {a:vt}netrw_culkeep = &l:cul
+" call Decho("(s:NetrwOptionsSave) COMBAK: cuc=".&l:cuc." cul=".&l:cul)
let {a:vt}netrw_diffkeep = &l:diff
let {a:vt}netrw_fenkeep = &l:fen
if !exists("g:netrw_ffkeep") || g:netrw_ffkeep
@@ -1639,9 +1645,11 @@ fun! s:NetrwOptionsSave(vt)
endif
let {a:vt}netrw_fokeep = &l:fo " formatoptions
let {a:vt}netrw_gdkeep = &l:gd " gdefault
+ let {a:vt}netrw_gokeep = &l:go " guioptions
let {a:vt}netrw_hidkeep = &l:hidden
let {a:vt}netrw_imkeep = &l:im
let {a:vt}netrw_iskkeep = &l:isk
+ let {a:vt}netrw_lines = &lines
let {a:vt}netrw_lskeep = &l:ls
let {a:vt}netrw_makeep = &l:ma
let {a:vt}netrw_magickeep = &l:magic
@@ -1693,12 +1701,17 @@ fun! s:NetrwOptionsSafe(islocal)
endif
call s:NetrwSetSafeSetting("&l:ci",0)
call s:NetrwSetSafeSetting("&l:cin",0)
- call s:NetrwSetSafeSetting("&l:bh","hide")
+ if g:netrw_fastbrowse > a:islocal
+ call s:NetrwSetSafeSetting("&l:bh","hide")
+ else
+ call s:NetrwSetSafeSetting("&l:bh","delete")
+ endif
call s:NetrwSetSafeSetting("&l:cino","")
call s:NetrwSetSafeSetting("&l:com","")
if &cpo =~ 'a' | call s:NetrwSetSafeSetting("&cpo",substitute(&cpo,'a','','g')) | endif
if &cpo =~ 'A' | call s:NetrwSetSafeSetting("&cpo",substitute(&cpo,'A','','g')) | endif
setl fo=nroql2
+ call s:NetrwSetSafeSetting("&go","begmr")
call s:NetrwSetSafeSetting("&l:hid",0)
call s:NetrwSetSafeSetting("&l:im",0)
setl isk+=@ isk+=* isk+=/
@@ -1712,7 +1725,10 @@ fun! s:NetrwOptionsSafe(islocal)
call s:NetrwSetSafeSetting("&l:tw",0)
call s:NetrwSetSafeSetting("&l:wig","")
setl cedit&
- call s:NetrwCursor()
+
+ " set up cuc and cul based on g:netrw_cursor and listing style
+ " COMBAK -- cuc cul related
+ call s:NetrwCursor(0)
" allow the user to override safe options
" call Decho("ft<".&ft."> ei=".&ei,'~'.expand("<slnum>"))
@@ -1730,11 +1746,14 @@ endfun
" s:NetrwOptionsRestore: restore options (based on prior s:NetrwOptionsSave) {{{2
fun! s:NetrwOptionsRestore(vt)
" call Dfunc("s:NetrwOptionsRestore(vt<".a:vt.">) win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> winnr($)=".winnr("$"))
+" call Decho("(s:NetrwOptionsRestore) lines=".&lines)
" call Decho("settings buf#".bufnr("%")."<".bufname("%").">: ".((&l:ma == 0)? "no" : "")."ma ".((&l:mod == 0)? "no" : "")."mod ".((&l:bl == 0)? "no" : "")."bl ".((&l:ro == 0)? "no" : "")."ro fo=".&l:fo." a:vt=".a:vt,'~'.expand("<slnum>"))
if !exists("{a:vt}netrw_optionsave")
" call Decho("case ".a:vt."netrw_optionsave : doesn't exist",'~'.expand("<slnum>"))
-" call Decho("settings buf#".bufnr("%")."<".bufname("%").">: ".((&l:ma == 0)? "no" : "")."ma ".((&l:mod == 0)? "no" : "")."mod ".((&l:bl == 0)? "no" : "")."bl ".((&l:ro == 0)? "no" : "")."ro fo=".&l:fo." a:vt=".a:vt,'~'.expand("<slnum>"))
-" call Decho("ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("<slnum>"))
+" call Decho("..doing filetype detect anyway")
+ filetype detect
+" call Decho("..settings buf#".bufnr("%")."<".bufname("%").">: ".((&l:ma == 0)? "no" : "")."ma ".((&l:mod == 0)? "no" : "")."mod ".((&l:bl == 0)? "no" : "")."bl ".((&l:ro == 0)? "no" : "")."ro fo=".&l:fo." a:vt=".a:vt,'~'.expand("<slnum>"))
+" call Decho("..ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("<slnum>"))
" call Dret("s:NetrwOptionsRestore : ".a:vt."netrw_optionsave doesn't exist")
return
endif
@@ -1751,41 +1770,53 @@ fun! s:NetrwOptionsRestore(vt)
endif
endif
endif
+" call Decho("(s:NetrwOptionsRestore) #1 lines=".&lines)
call s:NetrwRestoreSetting(a:vt."netrw_aikeep","&l:ai")
call s:NetrwRestoreSetting(a:vt."netrw_awkeep","&l:aw")
call s:NetrwRestoreSetting(a:vt."netrw_blkeep","&l:bl")
call s:NetrwRestoreSetting(a:vt."netrw_btkeep","&l:bt")
call s:NetrwRestoreSetting(a:vt."netrw_bombkeep","&l:bomb")
+" call Decho("(s:NetrwOptionsRestore) #2 lines=".&lines)
call s:NetrwRestoreSetting(a:vt."netrw_cedit","&cedit")
call s:NetrwRestoreSetting(a:vt."netrw_cikeep","&l:ci")
call s:NetrwRestoreSetting(a:vt."netrw_cinkeep","&l:cin")
call s:NetrwRestoreSetting(a:vt."netrw_cinokeep","&l:cino")
call s:NetrwRestoreSetting(a:vt."netrw_comkeep","&l:com")
+" call Decho("(s:NetrwOptionsRestore) #3 lines=".&lines)
call s:NetrwRestoreSetting(a:vt."netrw_cpokeep","&l:cpo")
call s:NetrwRestoreSetting(a:vt."netrw_diffkeep","&l:diff")
call s:NetrwRestoreSetting(a:vt."netrw_fenkeep","&l:fen")
if exists("g:netrw_ffkeep") && g:netrw_ffkeep
call s:NetrwRestoreSetting(a:vt."netrw_ffkeep")","&l:ff")
endif
- call s:NetrwRestoreSetting(a:vt."netrw_fokeep","&l:fo")
- call s:NetrwRestoreSetting(a:vt."netrw_gdkeep","&l:gd")
- call s:NetrwRestoreSetting(a:vt."netrw_hidkeep","&l:hidden")
- call s:NetrwRestoreSetting(a:vt."netrw_imkeep","&l:im")
- call s:NetrwRestoreSetting(a:vt."netrw_iskkeep","&l:isk")
- call s:NetrwRestoreSetting(a:vt."netrw_lskeep","&l:ls")
- call s:NetrwRestoreSetting(a:vt."netrw_makeep","&l:ma")
+" call Decho("(s:NetrwOptionsRestore) #4 lines=".&lines)
+ call s:NetrwRestoreSetting(a:vt."netrw_fokeep" ,"&l:fo")
+ call s:NetrwRestoreSetting(a:vt."netrw_gdkeep" ,"&l:gd")
+ call s:NetrwRestoreSetting(a:vt."netrw_gokeep" ,"&l:go")
+ call s:NetrwRestoreSetting(a:vt."netrw_hidkeep" ,"&l:hidden")
+" call Decho("(s:NetrwOptionsRestore) #5 lines=".&lines)
+ call s:NetrwRestoreSetting(a:vt."netrw_imkeep" ,"&l:im")
+ call s:NetrwRestoreSetting(a:vt."netrw_iskkeep" ,"&l:isk")
+" call Decho("(s:NetrwOptionsRestore) #6 lines=".&lines)
+ call s:NetrwRestoreSetting(a:vt."netrw_lines" ,"&lines")
+" call Decho("(s:NetrwOptionsRestore) #7 lines=".&lines)
+ call s:NetrwRestoreSetting(a:vt."netrw_lskeep" ,"&l:ls")
+ call s:NetrwRestoreSetting(a:vt."netrw_makeep" ,"&l:ma")
call s:NetrwRestoreSetting(a:vt."netrw_magickeep","&l:magic")
- call s:NetrwRestoreSetting(a:vt."netrw_modkeep","&l:mod")
- call s:NetrwRestoreSetting(a:vt."netrw_nukeep","&l:nu")
- call s:NetrwRestoreSetting(a:vt."netrw_rnukeep","&l:rnu")
- call s:NetrwRestoreSetting(a:vt."netrw_repkeep","&l:report")
- call s:NetrwRestoreSetting(a:vt."netrw_rokeep","&l:ro")
- call s:NetrwRestoreSetting(a:vt."netrw_selkeep","&l:sel")
+ call s:NetrwRestoreSetting(a:vt."netrw_modkeep" ,"&l:mod")
+ call s:NetrwRestoreSetting(a:vt."netrw_nukeep" ,"&l:nu")
+" call Decho("(s:NetrwOptionsRestore) #8 lines=".&lines)
+ call s:NetrwRestoreSetting(a:vt."netrw_rnukeep" ,"&l:rnu")
+ call s:NetrwRestoreSetting(a:vt."netrw_repkeep" ,"&l:report")
+ call s:NetrwRestoreSetting(a:vt."netrw_rokeep" ,"&l:ro")
+ call s:NetrwRestoreSetting(a:vt."netrw_selkeep" ,"&l:sel")
+" call Decho("(s:NetrwOptionsRestore) #9 lines=".&lines)
call s:NetrwRestoreSetting(a:vt."netrw_spellkeep","&l:spell")
- call s:NetrwRestoreSetting(a:vt."netrw_twkeep","&l:tw")
- call s:NetrwRestoreSetting(a:vt."netrw_wigkeep","&l:wig")
- call s:NetrwRestoreSetting(a:vt."netrw_wrapkeep","&l:wrap")
+ call s:NetrwRestoreSetting(a:vt."netrw_twkeep" ,"&l:tw")
+ call s:NetrwRestoreSetting(a:vt."netrw_wigkeep" ,"&l:wig")
+ call s:NetrwRestoreSetting(a:vt."netrw_wrapkeep" ,"&l:wrap")
call s:NetrwRestoreSetting(a:vt."netrw_writekeep","&l:write")
+" call Decho("(s:NetrwOptionsRestore) #10 lines=".&lines)
call s:NetrwRestoreSetting("s:yykeep","@@")
" former problem: start with liststyle=0; press <i> : result, following line resets l:ts.
" Fixed; in s:PerformListing, when w:netrw_liststyle is s:LONGLIST, will use a printf to pad filename with spaces
@@ -1827,9 +1858,11 @@ fun! s:NetrwOptionsRestore(vt)
" were having their filetype detect-generated settings overwritten by
" NetrwOptionRestore.
if &ft != "netrw"
-" call Decho("filetype detect (ft=".&ft.")",'~'.expand("<slnum>"))
+" call Decho("before: filetype detect (ft=".&ft.")",'~'.expand("<slnum>"))
filetype detect
+" call Decho("after : filetype detect (ft=".&ft.")",'~'.expand("<slnum>"))
endif
+" call Decho("(s:NetrwOptionsRestore) lines=".&lines)
" call Decho("settings buf#".bufnr("%")."<".bufname("%").">: ".((&l:ma == 0)? "no" : "")."ma ".((&l:mod == 0)? "no" : "")."mod ".((&l:bl == 0)? "no" : "")."bl ".((&l:ro == 0)? "no" : "")."ro fo=".&l:fo." a:vt=".a:vt,'~'.expand("<slnum>"))
" call Dret("s:NetrwOptionsRestore : tab#".tabpagenr()." win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> modified=".&modified." modifiable=".&modifiable." readonly=".&readonly)
endfun
@@ -1879,7 +1912,7 @@ fun! s:NetrwRestoreSetting(keepvar,setting)
" typically called from s:NetrwOptionsRestore
" call s:NetrwRestoreSettings(keep-option-variable-name,'associated-option')
" ex. call s:NetrwRestoreSetting(a:vt."netrw_selkeep","&l:sel")
- " Restores option (if different) from a keepvar
+ " Restores option (but only if different) from a:keepvar
if exists(a:keepvar)
exe "let keepvarval= ".a:keepvar
exe "let setting= ".a:setting
@@ -2801,14 +2834,16 @@ fun! netrw#SetTreetop(iscmd,...)
" call Decho("inittreetop<".(exists("inittreetop")? inittreetop : "n/a").">")
if (a:iscmd == 0 || a:1 == "") && exists("inittreetop")
- let treedir= s:NetrwTreePath(inittreetop)
+ let treedir = s:NetrwTreePath(inittreetop)
" call Decho("treedir<".treedir.">",'~'.expand("<slnum>"))
else
if isdirectory(s:NetrwFile(a:1))
" call Decho("a:1<".a:1."> is a directory",'~'.expand("<slnum>"))
- let treedir= a:1
+ let treedir = a:1
+ let s:netrw_treetop = treedir
elseif exists("b:netrw_curdir") && (isdirectory(s:NetrwFile(b:netrw_curdir."/".a:1)) || a:1 =~ '^\a\{3,}://')
- let treedir= b:netrw_curdir."/".a:1
+ let treedir = b:netrw_curdir."/".a:1
+ let s:netrw_treetop = treedir
" call Decho("a:1<".a:1."> is NOT a directory, using treedir<".treedir.">",'~'.expand("<slnum>"))
else
" normally the cursor is left in the message window.
@@ -2816,7 +2851,8 @@ fun! netrw#SetTreetop(iscmd,...)
let netrwbuf= bufnr("%")
call netrw#ErrorMsg(s:ERROR,"sorry, ".a:1." doesn't seem to be a directory!",95)
exe bufwinnr(netrwbuf)."wincmd w"
- let treedir= "."
+ let treedir = "."
+ let s:netrw_treetop = getcwd()
endif
endif
" call Decho("treedir<".treedir.">",'~'.expand("<slnum>"))
@@ -4071,6 +4107,7 @@ fun! s:NetrwFileInfo(islocal,fname)
elseif g:netrw_sizestyle =~# 'h'
let lsopt= "-lsadh --si"
endif
+" call Decho("(s:NetrwFileInfo) lsopt<".lsopt.">")
if (has("unix") || has("macunix")) && executable("/bin/ls")
if getline(".") == "../"
@@ -4132,9 +4169,10 @@ endfun
" s:NetrwGetBuffer: [get a new|find an old netrw] buffer for a netrw listing {{{2
" returns 0=cleared buffer
" 1=re-used buffer (buffer not cleared)
+" Nov 09, 2020: tst952 shows that when user does :set hidden that NetrwGetBuffer will come up with a [No Name] buffer (hid fix)
fun! s:NetrwGetBuffer(islocal,dirname)
" call Dfunc("s:NetrwGetBuffer(islocal=".a:islocal." dirname<".a:dirname.">) liststyle=".g:netrw_liststyle)
-" call Decho("settings buf#".bufnr("%")."<".bufname("%").">: ".((&l:ma == 0)? "no" : "")."ma ".((&l:mod == 0)? "no" : "")."mod ".((&l:bl == 0)? "no" : "")."bl ".((&l:ro == 0)? "no" : "")."ro fo=".&l:fo,'~'.expand("<slnum>"))
+" call Decho("settings buf#".bufnr("%")."<".bufname("%").">: ".((&l:ma == 0)? "no" : "")."ma ".((&l:mod == 0)? "no" : "")."mod ".((&l:bl == 0)? "no" : "")."bl ".((&l:ro == 0)? "no" : "")."ro fo=".&l:fo." hid=".&hid,'~'.expand("<slnum>"))
" call Decho("netrwbuf dictionary=".(exists("s:netrwbuf")? string(s:netrwbuf) : 'n/a'),'~'.expand("<slnum>"))
" call Dredir("ls!","s:NetrwGetBuffer")
let dirname= a:dirname
@@ -4184,17 +4222,26 @@ fun! s:NetrwGetBuffer(islocal,dirname)
endif
" call Decho(" bufnum#".bufnum,'~'.expand("<slnum>"))
- " highjack the current buffer if
- " it has the desired name
- " it is empty
-" call Decho("deciding if I can highjack the current buffer#".bufnr("%"),'~'.expand("<slnum>"))
-" call Decho("..dirname<".dirname.">",'~'.expand("<slnum>"))
-" call Decho("..bufname<".bufname("%").">",'~'.expand("<slnum>"))
-" call Decho("..getline($)<".getline("$").">",'~'.expand("<slnum>"))
- if dirname == bufname("%") && line("$") == 1 && getline("%") == ""
+ " hijack the current buffer
+ " IF the buffer already has the desired name
+ " AND it is empty
+ let curbuf = bufname("%")
+ if curbuf == '.'
+ let curbuf = getcwd()
+ endif
+" call Dredir("ls!","NetrwGetFile (renamed buffer back to remote filename<".rfile."> : expand(%)<".expand("%").">)")
+" call Decho("deciding if netrw may hijack the current buffer#".bufnr("%")."<".curbuf.">",'~'.expand("<slnum>"))
+" call Decho("..dirname<".dirname."> IF dirname == bufname",'~'.expand("<slnum>"))
+" call Decho("..curbuf<".curbuf.">",'~'.expand("<slnum>"))
+" call Decho("..line($)=".line("$")." AND this is 1",'~'.expand("<slnum>"))
+" call Decho("..getline(%)<".getline("%")."> AND this line is empty",'~'.expand("<slnum>"))
+ if dirname == curbuf && line("$") == 1 && getline("%") == ""
" call Dret("s:NetrwGetBuffer 0<cleared buffer> : highjacking buffer#".bufnr("%"))
return 0
+ else " DEBUG
+" call Decho("..did NOT hijack buffer",'~'.expand("<slnum>"))
endif
+ " Aug 14, 2021: was thinking about looking for a [No Name] buffer here and using it, but that might cause problems
" get enew buffer and name it -or- re-use buffer {{{3
if bufnum < 0 " get enew buffer and name it
@@ -4519,7 +4566,7 @@ fun! s:NetrwListStyle(islocal)
" refresh the listing
" call Decho("refresh the listing",'~'.expand("<slnum>"))
NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./'))
- NetrwKeepj call s:NetrwCursor()
+ NetrwKeepj call s:NetrwCursor(0)
" repoint t:netrw_lexbufnr if appropriate
if exists("repointlexbufnr")
@@ -4725,7 +4772,7 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
endif
" call Decho("b:netrw_curdir<".b:netrw_curdir.">")
- " NetrwBrowseChgDir: save options and initialize {{{3
+ " NetrwBrowseChgDir; save options and initialize {{{3
" call Decho("saving options",'~'.expand("<slnum>"))
call s:SavePosn(s:netrw_posn)
NetrwKeepj call s:NetrwOptionsSave("s:")
@@ -4793,6 +4840,8 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
if exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST && exists("w:netrw_treedict") && newdir !~ '^\(/\|\a:\)'
" call Decho("edit-a-file: handle tree listing: w:netrw_treedict<".(exists("w:netrw_treedict")? string(w:netrw_treedict) : 'n/a').">",'~'.expand("<slnum>"))
" call Decho("edit-a-file: newdir<".newdir.">",'~'.expand("<slnum>"))
+" let newdir = s:NetrwTreePath(s:netrw_treetop)
+" call Decho("edit-a-file: COMBAK why doesn't this recognize file1's directory???")
let dirname= s:NetrwTreeDir(a:islocal)
"COMBAK : not working for a symlink -- but what about a regular file? a directory?
" call Decho("COMBAK : not working for a symlink -- but what about a regular file? a directory?")
@@ -4906,7 +4955,8 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
exe "NetrwKeepj e ".fnameescape(dirname)
endif
" call Decho("edit-a-file: after e! ".dirname.": hidden=".&hidden." bufhidden<".&bufhidden."> mod=".&mod,'~'.expand("<slnum>"))
- call s:NetrwCursor()
+ " COMBAK -- cuc cul related
+ call s:NetrwCursor(1)
if &hidden || &bufhidden == "hide"
" file came from vim's hidden storage. Don't "restore" options with it.
let dorestore= 0
@@ -4927,8 +4977,8 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
elseif type(g:Netrw_funcref) == 3
" call Decho("edit-a-file: handling a list of g:Netrw_funcrefs",'~'.expand("<slnum>"))
for Fncref in g:Netrw_funcref
- if type(FncRef) == 2
- NetrwKeepj call FncRef()
+ if type(Fncref) == 2
+ NetrwKeepj call Fncref()
endif
endfor
endif
@@ -5220,6 +5270,12 @@ fun! netrw#BrowseX(fname,remote)
endif
" call Decho("not a local file nor a webpage request",'~'.expand("<slnum>"))
+ if exists("g:netrw_browsex_viewer") && exists("g:netrw_browsex_support_remote") && !g:netrw_browsex_support_remote
+ let remote = a:remote
+ else
+ let remote = 0
+ endif
+
let ykeep = @@
let screenposn = winsaveview()
" call Decho("saving posn to screenposn<".string(screenposn).">",'~'.expand("<slnum>"))
@@ -5264,9 +5320,9 @@ fun! netrw#BrowseX(fname,remote)
endif
" call Decho("exten<".exten.">",'~'.expand("<slnum>"))
- if a:remote == 1
+ if remote == 1
" create a local copy
-" call Decho("remote: a:remote=".a:remote.": create a local copy of <".a:fname.">",'~'.expand("<slnum>"))
+" call Decho("remote: remote=".remote.": create a local copy of <".a:fname.">",'~'.expand("<slnum>"))
setl bh=delete
call netrw#NetRead(3,a:fname)
" attempt to rename tempfile
@@ -5288,7 +5344,7 @@ fun! netrw#BrowseX(fname,remote)
let fname= s:netrw_tmpfile
endif
else
-" call Decho("local: a:remote=".a:remote.": handling local copy of <".a:fname.">",'~'.expand("<slnum>"))
+" call Decho("local: remote=".remote.": handling local copy of <".a:fname.">",'~'.expand("<slnum>"))
let fname= a:fname
" special ~ handler for local
if fname =~ '^\~' && expand("$HOME") != ""
@@ -5382,8 +5438,8 @@ fun! netrw#BrowseX(fname,remote)
if a:fname =~ '^https\=://'
" atril does not appear to understand how to handle html -- so use gvim to edit the document
let use_ctrlo= 0
-" call Decho("(COMBAK) fname<".fname.">")
-" call Decho("(COMBAK) a:fname<".a:fname.">")
+" call Decho("fname<".fname.">")
+" call Decho("a:fname<".a:fname.">")
call s:NetrwExe("sil! !gvim ".fname.' -c "keepj keepalt file '.fnameescape(a:fname).'"')
else
@@ -5431,12 +5487,12 @@ fun! netrw#BrowseX(fname,remote)
" return to prior buffer (directory listing)
" Feb 12, 2008: had to de-activiate removal of
" temporary file because it wasn't getting seen.
-" if a:remote == 1 && fname != a:fname
+" if remote == 1 && fname != a:fname
"" call Decho("deleting temporary file<".fname.">",'~'.expand("<slnum>"))
" call s:NetrwDelete(fname)
" endif
- if a:remote == 1
+ if remote == 1
setl bh=delete bt=nofile
if g:netrw_use_noswf
setl noswf
@@ -5495,7 +5551,7 @@ fun! s:NetrwBufRename(newname)
let b:junk= 1
" call Decho("rename buffer: sil! keepj keepalt file ".fnameescape(a:newname),'~'.expand("<slnum>"))
exe 'sil! keepj keepalt file '.fnameescape(a:newname)
-" call Dredir("ls!","s:NetrwBufRename (before bwipe)")
+" call Dredir("ls!","s:NetrwBufRename (before bwipe)~".expand("<slnum>"))
let oldbufnr= bufnr(oldbufname)
" call Decho("oldbufname<".oldbufname."> oldbufnr#".oldbufnr,'~'.expand("<slnum>"))
" call Decho("bufnr(%)=".bufnr("%"),'~'.expand("<slnum>"))
@@ -5504,6 +5560,9 @@ fun! s:NetrwBufRename(newname)
exe "bwipe! ".oldbufnr
" else " Decho
" call Decho("did *not* bwipe buf#".oldbufnr,'~'.expand("<slnum>"))
+" call Decho("..reason: if oldbufname<".oldbufname."> is empty",'~'.expand("<slnum>"))"
+" call Decho("..reason: if oldbufnr#".oldbufnr." is -1",'~'.expand("<slnum>"))"
+" call Decho("..reason: if oldbufnr#".oldbufnr." != bufnr(%)#".bufnr("%"),'~'.expand("<slnum>"))"
endif
" call Dredir("ls!","s:NetrwBufRename (after rename)")
" else " Decho
@@ -6482,7 +6541,7 @@ fun! s:NetrwMaps(islocal)
if !hasmapto('<Plug>NetrwRefresh')
nmap <buffer> <unique> <c-l> <Plug>NetrwRefresh
endif
- nnoremap <buffer> <silent> <Plug>NetrwRefresh <c-l>:call <SID>NetrwRefresh(1,<SID>NetrwBrowseChgDir(1,(w:netrw_liststyle == 3)? w:netrw_treetop : './'))<cr>
+ nnoremap <buffer> <silent> <Plug>NetrwRefresh <c-l>:call <SID>NetrwRefresh(1,<SID>NetrwBrowseChgDir(1,(exists("w:netrw_liststyle") && exists("w:netrw_treetop") && w:netrw_liststyle == 3)? w:netrw_treetop : './'))<cr>
if s:didstarstar || !mapcheck("<s-down>","n")
nnoremap <buffer> <silent> <s-down> :Nexplore<cr>
endif
@@ -6731,7 +6790,7 @@ fun! s:NetrwMarkFile(islocal,fname)
" sanity check
if empty(a:fname)
-" call Dret("s:NetrwMarkFile : emtpy fname")
+" call Dret("s:NetrwMarkFile : empty fname")
return
endif
let curdir = s:NetrwGetCurdir(a:islocal)
@@ -8110,6 +8169,23 @@ fun! s:NetrwOpenFile(islocal)
call inputsave()
let fname= input("Enter filename: ")
call inputrestore()
+" call Decho("(s:NetrwOpenFile) fname<".fname.">",'~'.expand("<slnum>"))
+
+ " determine if Lexplore is in use
+ if exists("t:netrw_lexbufnr")
+ " check if t:netrw_lexbufnr refers to a netrw window
+" call Decho("(s:netrwOpenFile) ..t:netrw_lexbufnr=".t:netrw_lexbufnr,'~'.expand("<slnum>"))
+ let lexwinnr = bufwinnr(t:netrw_lexbufnr)
+ if lexwinnr != -1 && exists("g:netrw_chgwin") && g:netrw_chgwin != -1
+" call Decho("(s:netrwOpenFile) ..Lexplore in use",'~'.expand("<slnum>"))
+ exe "NetrwKeepj keepalt ".g:netrw_chgwin."wincmd w"
+ exe "NetrwKeepj e ".fnameescape(fname)
+ let @@= ykeep
+" call Dret("s:NetrwOpenFile : creating a file with Lexplore mode")
+ endif
+ endif
+
+ " Does the filename contain a path?
if fname !~ '[/\\]'
if exists("b:netrw_curdir")
if exists("g:netrw_quiet")
@@ -8448,6 +8524,7 @@ fun! s:NetrwPrevWinOpen(islocal)
let lastwinnr = winnr("$")
let curword = s:NetrwGetWord()
let choice = 0
+ let s:prevwinopen= 1 " lets s:NetrwTreeDir() know that NetrwPrevWinOpen called it
let s:treedir = s:NetrwTreeDir(a:islocal)
let curdir = s:treedir
" call Decho("winnr($)#".lastwinnr." curword<".curword.">",'~'.expand("<slnum>"))
@@ -8775,7 +8852,7 @@ fun! s:NetrwPreview(path) range
" 0 : 1: top -- preview window is horizontally split off and on the top
" 0 : 0: bot -- preview window is horizontally split off and on the bottom
"
- " Note that the file being previewed is already known to not be a directory, hence we can avoid doing a LocalBrowse() check via
+ " Note that the file being previewed is already known to not be a directory, hence we can avoid doing a LocalBrowseCheck() check via
" the BufEnter event set up in netrwPlugin.vim
" call Decho("exe ".(g:netrw_alto? "top " : "bot ").(g:netrw_preview? "vert " : "")."pedit ".fnameescape(a:path),'~'.expand("<slnum>"))
let eikeep = &ei
@@ -9210,14 +9287,20 @@ fun! s:NetrwTreeDir(islocal)
" call Decho("g:netrw_keepdir =".(exists("g:netrw_keepdir")? g:netrw_keepdir : 'n/a'),'~'.expand("<slnum>"))
" call Decho("w:netrw_liststyle=".(exists("w:netrw_liststyle")? w:netrw_liststyle : 'n/a'),'~'.expand("<slnum>"))
" call Decho("w:netrw_treetop =".(exists("w:netrw_treetop")? w:netrw_treetop : 'n/a'),'~'.expand("<slnum>"))
+" call Decho("current line<".getline(".").">")
- if exists("s:treedir")
+ if exists("s:treedir") && exists("s:prevwinopen")
" s:NetrwPrevWinOpen opens a "previous" window -- and thus needs to and does call s:NetrwTreeDir early
+" call Decho('s:NetrwPrevWinOpen opens a "previous" window -- and thus needs to and does call s:NetrwTreeDir early')
let treedir= s:treedir
unlet s:treedir
-" call Dret("s:NetrwTreeDir ".treedir)
+ unlet s:prevwinopen
+" call Dret("s:NetrwTreeDir ".treedir.": early return since s:treedir existed previously")
return treedir
endif
+ if exists("s:prevwinopen")
+ unlet s:prevwinopen
+ endif
if !exists("b:netrw_curdir") || b:netrw_curdir == ""
let b:netrw_curdir= getcwd()
@@ -9424,20 +9507,29 @@ endfun
" Called by s:PerformListing()
fun! s:NetrwTreeListing(dirname)
if exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST
-" call Dfunc("NetrwTreeListing() bufname<".expand("%").">")
+" call Dfunc("s:NetrwTreeListing() bufname<".expand("%").">")
" call Decho("curdir<".a:dirname.">",'~'.expand("<slnum>"))
" call Decho("win#".winnr().": w:netrw_treetop ".(exists("w:netrw_treetop")? "exists" : "doesn't exist")." w:netrw_treedict ".(exists("w:netrw_treedict")? "exists" : "doesn't exit"),'~'.expand("<slnum>"))
" call Decho("g:netrw_banner=".g:netrw_banner.": banner ".(g:netrw_banner? "enabled" : "suppressed").": (line($)=".line("$")." byte2line(1)=".byte2line(1)." bannercnt=".w:netrw_bannercnt.")",'~'.expand("<slnum>"))
" update the treetop
-" call Decho("update the treetop",'~'.expand("<slnum>"))
if !exists("w:netrw_treetop")
+" call Decho("update the treetop (w:netrw_treetop doesn't exist yet)",'~'.expand("<slnum>"))
let w:netrw_treetop= a:dirname
+ let s:netrw_treetop= w:netrw_treetop
" call Decho("w:netrw_treetop<".w:netrw_treetop."> (reusing)",'~'.expand("<slnum>"))
elseif (w:netrw_treetop =~ ('^'.a:dirname) && s:Strlen(a:dirname) < s:Strlen(w:netrw_treetop)) || a:dirname !~ ('^'.w:netrw_treetop)
+" call Decho("update the treetop (override w:netrw_treetop with a:dirname<".a:dirname.">)",'~'.expand("<slnum>"))
let w:netrw_treetop= a:dirname
+ let s:netrw_treetop= w:netrw_treetop
" call Decho("w:netrw_treetop<".w:netrw_treetop."> (went up)",'~'.expand("<slnum>"))
endif
+ if exists("w:netrw_treetop")
+ let s:netrw_treetop= w:netrw_treetop
+ else
+ let w:netrw_treetop= getcwd()
+ let s:netrw_treetop= w:netrw_treetop
+ endif
if !exists("w:netrw_treedict")
" insure that we have a treedict, albeit empty
@@ -9475,7 +9567,7 @@ fun! s:NetrwTreeListing(dirname)
exe "setl ".g:netrw_bufsettings
-" call Dret("NetrwTreeListing : bufname<".expand("%").">")
+" call Dret("s:NetrwTreeListing : bufname<".expand("%").">")
return
endif
endfun
@@ -10619,7 +10711,7 @@ endfun
" ---------------------------------------------------------------------
" netrw#LocalBrowseCheck: {{{2
fun! netrw#LocalBrowseCheck(dirname)
- " This function is called by netrwPlugin.vim's s:LocalBrowse(), s:NetrwRexplore(),
+ " This function is called by netrwPlugin.vim's s:LocalBrowseCheck(), s:NetrwRexplore(),
" and by <cr> when atop a listed file/directory (via a buffer-local map)
"
" unfortunate interaction -- split window debugging can't be used here, must use
@@ -10770,7 +10862,7 @@ endfun
" Hiding a buffer means that it will be re-used when examined, hence "fast".
" (re-using a buffer may not be as accurate)
"
-" s:netrw_events : doesn't exist, s:LocalFastBrowser() will install autocmds whena med or fast browsing
+" s:netrw_events : doesn't exist, s:LocalFastBrowser() will install autocmds with medium-speed or fast browsing
" =1: autocmds installed, but ignore next FocusGained event to avoid initial double-refresh of listing.
" BufEnter may be first event, then a FocusGained event. Ignore the first FocusGained event.
" If :Explore used: it sets s:netrw_events to 2, so no FocusGained events are ignored.
@@ -10932,13 +11024,14 @@ fun! s:LocalListing()
let sz= s:NetrwHumanReadable(sz)
endif
let longfile= printf("%-".(g:netrw_maxfilenamelen+1)."s",pfile)
- let pfile = longfile.fsz." ".strftime(g:netrw_timefmt,getftime(filename))
+ let pfile = longfile.sz." ".strftime(g:netrw_timefmt,getftime(filename))
" call Decho("longlist support: sz=".sz." fsz=".fsz,'~'.expand("<slnum>"))
endif
if g:netrw_sort_by =~# "^t"
" sort by time (handles time up to 1 quintillion seconds, US)
" Decorate listing by prepending a timestamp/ . Sorting will then be done based on time.
+" call Decho("implementing g:netrw_sort_by=".g:netrw_sort_by." (time)")
" call Decho("getftime(".filename.")=".getftime(filename),'~'.expand("<slnum>"))
let t = getftime(filename)
let ft = strpart("000000000000000000",1,18-strlen(t)).t
@@ -10948,6 +11041,7 @@ fun! s:LocalListing()
elseif g:netrw_sort_by =~ "^s"
" sort by size (handles file sizes up to 1 quintillion bytes, US)
+" call Decho("implementing g:netrw_sort_by=".g:netrw_sort_by." (size)")
" call Decho("getfsize(".filename.")=".getfsize(filename),'~'.expand("<slnum>"))
let sz = getfsize(filename)
if g:netrw_sizestyle =~# "[hH]"
@@ -10960,6 +11054,7 @@ fun! s:LocalListing()
else
" sort by name
+" call Decho("implementing g:netrw_sort_by=".g:netrw_sort_by." (name)")
" call Decho("exe NetrwKeepj put ='".pfile."'",'~'.expand("<slnum>"))
sil! NetrwKeepj put=pfile
endif
@@ -11682,19 +11777,32 @@ endfun
" ---------------------------------------------------------------------
" s:NetrwCursor: responsible for setting cursorline/cursorcolumn based upon g:netrw_cursor {{{2
-fun! s:NetrwCursor()
+fun! s:NetrwCursor(editfile)
if !exists("w:netrw_liststyle")
let w:netrw_liststyle= g:netrw_liststyle
endif
" call Dfunc("s:NetrwCursor() ft<".&ft."> liststyle=".w:netrw_liststyle." g:netrw_cursor=".g:netrw_cursor." s:netrw_usercuc=".s:netrw_usercuc." s:netrw_usercul=".s:netrw_usercul)
+" call Decho("(s:NetrwCursor) COMBAK: cuc=".&l:cuc." cul=".&l:cul)
+
if &ft != "netrw"
" if the current window isn't a netrw directory listing window, then use user cursorline/column
" settings. Affects when netrw is used to read/write a file using scp/ftp/etc.
" call Decho("case ft!=netrw: use user cul,cuc",'~'.expand("<slnum>"))
- let &l:cursorline = s:netrw_usercul
- let &l:cursorcolumn = s:netrw_usercuc
+ elseif g:netrw_cursor == 8
+ if w:netrw_liststyle == s:WIDELIST
+ setl cursorline
+ setl cursorcolumn
+ else
+ setl cursorline
+ endif
+ elseif g:netrw_cursor == 7
+ setl cursorline
+ elseif g:netrw_cursor == 6
+ if w:netrw_liststyle == s:WIDELIST
+ setl cursorline
+ endif
elseif g:netrw_cursor == 4
" all styles: cursorline, cursorcolumn
" call Decho("case g:netrw_cursor==4: setl cul cuc",'~'.expand("<slnum>"))
@@ -11711,26 +11819,22 @@ fun! s:NetrwCursor()
else
" call Decho("case g:netrw_cursor==3 and not wide: setl cul (use user's cuc)",'~'.expand("<slnum>"))
setl cursorline
- let &l:cursorcolumn = s:netrw_usercuc
endif
elseif g:netrw_cursor == 2
" thin-long-tree: cursorline, user's cursorcolumn
" wide : cursorline, user's cursorcolumn
" call Decho("case g:netrw_cursor==2: setl cuc (use user's cul)",'~'.expand("<slnum>"))
- let &l:cursorcolumn = s:netrw_usercuc
setl cursorline
elseif g:netrw_cursor == 1
" thin-long-tree: user's cursorline, user's cursorcolumn
" wide : cursorline, user's cursorcolumn
- let &l:cursorcolumn = s:netrw_usercuc
if w:netrw_liststyle == s:WIDELIST
" call Decho("case g:netrw_cursor==2 and wide: setl cul (use user's cuc)",'~'.expand("<slnum>"))
setl cursorline
else
" call Decho("case g:netrw_cursor==2 and not wide: (use user's cul,cuc)",'~'.expand("<slnum>"))
- let &l:cursorline = s:netrw_usercul
endif
else
@@ -11740,6 +11844,7 @@ fun! s:NetrwCursor()
let &l:cursorcolumn = s:netrw_usercuc
endif
+" call Decho("(s:NetrwCursor) COMBAK: cuc=".&l:cuc." cul=".&l:cul)
" call Dret("s:NetrwCursor : l:cursorline=".&l:cursorline." l:cursorcolumn=".&l:cursorcolumn)
endfun
@@ -11753,6 +11858,7 @@ fun! s:RestoreCursorline()
if exists("s:netrw_usercuc")
let &l:cursorcolumn = s:netrw_usercuc
endif
+" call Decho("(s:RestoreCursorline) COMBAK: cuc=".&l:cuc." cul=".&l:cul)
" call Dret("s:RestoreCursorline : restored cul=".&l:cursorline." cuc=".&l:cursorcolumn)
endfun
@@ -11788,11 +11894,37 @@ fun! s:NetrwDelete(path)
endfun
" ---------------------------------------------------------------------
+" s:NetrwBufRemover: removes a buffer that: {{{2s
+" has buffer-id > 1
+" is unlisted
+" is unnamed
+" does not appear in any window
+fun! s:NetrwBufRemover(bufid)
+" call Dfunc("s:NetrwBufRemover(".a:bufid.")")
+" call Decho("buf#".a:bufid." ".((a:bufid > 1)? ">" : "≯")." must be >1 for removal","~".expand("<slnum>"))
+" call Decho("buf#".a:bufid." is ".(buflisted(a:bufid)? "listed" : "unlisted"),"~".expand("<slnum>"))
+" call Decho("buf#".a:bufid." has name <".bufname(a:bufid).">","~".expand("<slnum>"))
+" call Decho("buf#".a:bufid." has winid#".bufwinid(a:bufid),"~".expand("<slnum>"))
+
+ if a:bufid > 1 && !buflisted(a:bufid) && bufname(a:bufid) == "" && bufwinid(a:bufid) == -1
+" call Decho("(s:NetrwBufRemover) removing buffer#".a:bufid,"~".expand("<slnum>"))
+ exe "bd! ".a:bufid
+ endif
+
+" call Dret("s:NetrwBufRemover")
+endfun
+
+" ---------------------------------------------------------------------
" s:NetrwEnew: opens a new buffer, passes netrw buffer variables through {{{2
fun! s:NetrwEnew(...)
" call Dfunc("s:NetrwEnew() a:0=".a:0." win#".winnr()." winnr($)=".winnr("$")." bufnr($)=".bufnr("$")." expand(%)<".expand("%").">")
" call Decho("curdir<".((a:0>0)? a:1 : "")."> buf#".bufnr("%")."<".bufname("%").">",'~'.expand("<slnum>"))
+ " Clean out the last buffer:
+ " Check if the last buffer has # > 1, is unlisted, is unnamed, and does not appear in a window
+ " If so, delete it.
+ call s:NetrwBufRemover(bufnr("$"))
+
" grab a function-local-variable copy of buffer variables
" call Decho("make function-local copy of netrw variables",'~'.expand("<slnum>"))
if exists("b:netrw_bannercnt") |let netrw_bannercnt = b:netrw_bannercnt |endif
diff --git a/runtime/autoload/netrwSettings.vim b/runtime/autoload/netrwSettings.vim
index bed5cfc455..61c0ef739e 100644
--- a/runtime/autoload/netrwSettings.vim
+++ b/runtime/autoload/netrwSettings.vim
@@ -1,7 +1,7 @@
" netrwSettings.vim: makes netrw settings simpler
-" Date: Nov 09, 2016
+" Date: Aug 12, 2021
" Maintainer: Charles E Campbell <NcampObell@SdrPchip.AorgM-NOSPAM>
-" Version: 16
+" Version: 17 ASTRO-ONLY
" Copyright: Copyright (C) 1999-2007 Charles E. Campbell {{{1
" Permission is hereby granted to use and distribute this code,
" with or without modifications, provided that this copyright
@@ -19,7 +19,7 @@
if exists("g:loaded_netrwSettings") || &cp
finish
endif
-let g:loaded_netrwSettings = "v16"
+let g:loaded_netrwSettings = "v17"
if v:version < 700
echohl WarningMsg
echo "***warning*** this version of netrwSettings needs vim 7.0"
@@ -31,7 +31,7 @@ endif
" NetrwSettings: {{{1
fun! netrwSettings#NetrwSettings()
" this call is here largely just to insure that netrw has been loaded
- call netrw#SavePosn()
+ call netrw#WinPath("")
if !exists("g:loaded_netrw")
echohl WarningMsg | echomsg "***sorry*** netrw needs to be loaded prior to using NetrwSettings" | echohl None
return
diff --git a/runtime/autoload/phpcomplete.vim b/runtime/autoload/phpcomplete.vim
index 377baa8432..f9aa15c827 100644
--- a/runtime/autoload/phpcomplete.vim
+++ b/runtime/autoload/phpcomplete.vim
@@ -9,7 +9,7 @@
"
" let g:phpcomplete_relax_static_constraint = 1/0 [default 0]
" Enables completion for non-static methods when completing for static context (::).
-" This generates E_STRICT level warning, but php calls these methods nontheless.
+" This generates E_STRICT level warning, but php calls these methods nonetheless.
"
" let g:phpcomplete_complete_for_unknown_classes = 1/0 [default 0]
" Enables completion of variables and functions in "everything under the sun" fashion
@@ -28,7 +28,7 @@
" This option controls the number of characters the user needs to type before
" the tags will be searched for namespaces and classes in typed out namespaces in
" "use ..." context. Setting this to 0 is not recommended because that means the code
-" have to scan every tag, and vim's taglist() function runs extremly slow with a
+" have to scan every tag, and vim's taglist() function runs extremely slow with a
" "match everything" pattern.
"
" let g:phpcomplete_parse_docblock_comments = 1/0 [default 0]
@@ -268,7 +268,7 @@ function! phpcomplete#CompleteUse(base) " {{{
call add(no_namespace_matches, {'word': namespace_for_class.'\'.tag.name, 'kind': tag.kind, 'menu': tag.filename, 'info': tag.filename })
endif
endfor
- " if it seems that the tags file have namespace informations we can safely throw
+ " if it seems that the tags file have namespace information we can safely throw
" away namespaceless tag matches since we can be sure they are invalid
if patched_ctags_detected
no_namespace_matches = []
@@ -810,7 +810,7 @@ function! phpcomplete#CompleteClassName(base, kinds, current_namespace, imports)
endif
endfor
- " resolve the typed in part with namespaces (if theres a \ in it)
+ " resolve the typed in part with namespaces (if there's a \ in it)
let [tag_match_pattern, namespace_for_class] = phpcomplete#ExpandClassName(a:base, a:current_namespace, a:imports)
let tags = []
@@ -926,11 +926,11 @@ function! s:getNextCharWithPos(filelines, current_pos) " {{{
endfunction " }}}
function! phpcomplete#EvaluateModifiers(modifiers, required_modifiers, prohibited_modifiers) " {{{
- " if theres no modifier, and no modifier is allowed and no modifier is required
+ " if there's no modifier, and no modifier is allowed and no modifier is required
if len(a:modifiers) == 0 && len(a:required_modifiers) == 0
return 1
else
- " check if every requred modifier is present
+ " check if every required modifier is present
for required_modifier in a:required_modifiers
if index(a:modifiers, required_modifier) == -1
return 0
@@ -1258,7 +1258,7 @@ function! phpcomplete#GetCurrentInstruction(line_number, col_number, phpbegin) "
endif
endif
- " save the coma position for later use if theres a "naked" , possibly separating a parameter and it is not in a parented part
+ " save the coma position for later use if there's a "naked" , possibly separating a parameter and it is not in a parented part
if first_coma_break_pos == -1 && current_char == ','
let first_coma_break_pos = len(instruction)
endif
@@ -1304,7 +1304,7 @@ function! phpcomplete#GetCurrentInstruction(line_number, col_number, phpbegin) "
" there were a "naked" coma in the instruction
if first_coma_break_pos != -1
- if instruction !~? '^use' && instruction !~? '^class' " use ... statements and class delcarations should not be broken up by comas
+ if instruction !~? '^use' && instruction !~? '^class' " use ... statements and class declarations should not be broken up by comas
let pos = (-1 * first_coma_break_pos) + 1
let instruction = instruction[pos :]
endif
@@ -1316,7 +1316,7 @@ function! phpcomplete#GetCurrentInstruction(line_number, col_number, phpbegin) "
" clear everything up until the first (
let instruction = substitute(instruction, '^\(if\|while\|foreach\|for\)\s*(\s*', '', '')
- " lets iterate trough the instruction until we can find the pair for the opening (
+ " lets iterate through the instruction until we can find the pair for the opening (
let i = 0
let depth = 1
while i < len(instruction)
@@ -1424,7 +1424,7 @@ function! phpcomplete#GetCallChainReturnType(classname_candidate, class_candidat
let parts = split(substitute(type, '^\\', '', ''), '\')
let class_candidate_namespace = join(parts[0:-2], '\')
let classname_candidate = parts[-1]
- " check for renamed namepsace in imports
+ " check for renamed namespace in imports
if has_key(classstructure.imports, class_candidate_namespace)
let class_candidate_namespace = classstructure.imports[class_candidate_namespace].name
endif
@@ -2023,7 +2023,7 @@ function! phpcomplete#GetCachedClassContents(classlocation, class_name) " {{{
if getftime(classstructure.file) != classstructure.mtime
let valid = 0
" we could break here, but the time required for checking probably worth
- " the the memory we can free by checking every file in the cached hirearchy
+ " the memory we can free by checking every file in the cached hierarchy
call phpcomplete#ClearCachedClassContents(classstructure.file)
endif
endfor
@@ -2037,7 +2037,7 @@ function! phpcomplete#GetCachedClassContents(classlocation, class_name) " {{{
call remove(s:cache_classstructures, cache_key)
call phpcomplete#ClearCachedClassContents(full_file_path)
- " fall trough for the read from files path
+ " fall through for the read from files path
endif
else
call phpcomplete#ClearCachedClassContents(full_file_path)
@@ -2590,7 +2590,7 @@ function! phpcomplete#GetCurrentNameSpace(file_lines) " {{{
let search_line = line
let use_line = line
- " add lines from the file until theres no ';' in them
+ " add lines from the file until there's no ';' in them
while search_line !~? ';' && l > 0
" file lines are reversed so we need to go backwards
let l -= 1
@@ -2622,7 +2622,7 @@ function! phpcomplete#GetCurrentNameSpace(file_lines) " {{{
" find kind flags from tags or built in methods for the objects we extracted
" they can be either classes, interfaces or namespaces, no other thing is importable in php
for [key, import] in items(imports)
- " if theres a \ in the name we have it's definitely not a built in thing, look for tags
+ " if there's a \ in the name we have it's definitely not a built in thing, look for tags
if import.name =~ '\\'
let patched_ctags_detected = 0
let [classname, namespace_for_classes] = phpcomplete#ExpandClassName(import.name, '\', {})
@@ -2679,10 +2679,10 @@ function! phpcomplete#GetCurrentNameSpace(file_lines) " {{{
let import['kind'] = 'i'
let import['builtin'] = 1
else
- " or can be a tag with exactly matchign name
+ " or can be a tag with exactly matching name
let tags = phpcomplete#GetTaglist('^'.import['name'].'$')
for tag in tags
- " search for the first matchin namespace, class, interface with no namespace
+ " search for the first matching namespace, class, interface with no namespace
if !has_key(tag, 'namespace') && (tag.kind == 'n' || tag.kind == 'c' || tag.kind == 'i' || tag.kind == 't')
call extend(import, tag)
let import['builtin'] = 0
@@ -2900,7 +2900,7 @@ for [ext, data] in items(php_builtin['functions'])
call extend(g:php_builtin_functions, data)
endfor
-" Built in classs
+" Built in class
let g:php_builtin_classes = {}
for [ext, data] in items(php_builtin['classes'])
call extend(g:php_builtin_classes, data)
@@ -2918,10 +2918,10 @@ for [ext, data] in items(php_builtin['constants'])
call extend(g:php_constants, data)
endfor
-" When the classname not found or found but the tags dosen't contain that
-" class we will try to complate any method of any builtin class. To speed up
+" When the classname not found or found but the tags doesn't contain that
+" class we will try to complete any method of any builtin class. To speed up
" that lookup we compile a 'ClassName::MethodName':'info' dictionary from the
-" builtin class informations
+" builtin class information
let g:php_builtin_object_functions = {}
" When completing for 'everyting imaginable' (no class context, not a
diff --git a/runtime/autoload/provider/clipboard.vim b/runtime/autoload/provider/clipboard.vim
index dea79f21f0..991bed6bbd 100644
--- a/runtime/autoload/provider/clipboard.vim
+++ b/runtime/autoload/provider/clipboard.vim
@@ -158,7 +158,9 @@ function! s:clipboard.get(reg) abort
end
let clipboard_data = s:try_cmd(s:paste[a:reg])
- if match(&clipboard, '\v(unnamed|unnamedplus)') >= 0 && get(s:selections[a:reg].data, 0, []) == clipboard_data
+ if match(&clipboard, '\v(unnamed|unnamedplus)') >= 0
+ \ && type(clipboard_data) == v:t_list
+ \ && get(s:selections[a:reg].data, 0, []) ==# clipboard_data
" When system clipboard return is same as our cache return the cache
" as it contains regtype information
return s:selections[a:reg].data
diff --git a/runtime/autoload/python3complete.vim b/runtime/autoload/python3complete.vim
index 1d7f5d18f5..192e9e6df8 100644
--- a/runtime/autoload/python3complete.vim
+++ b/runtime/autoload/python3complete.vim
@@ -173,7 +173,7 @@ class Completer(object):
pass
if len(arg_text) == 0:
# The doc string sometimes contains the function signature
- # this works for alot of C modules that are part of the
+ # this works for a lot of C modules that are part of the
# standard library
doc = func_obj.__doc__
if doc:
diff --git a/runtime/autoload/pythoncomplete.vim b/runtime/autoload/pythoncomplete.vim
index 575c23e6d3..e9233e1d49 100644
--- a/runtime/autoload/pythoncomplete.vim
+++ b/runtime/autoload/pythoncomplete.vim
@@ -191,7 +191,7 @@ class Completer(object):
pass
if len(arg_text) == 0:
# The doc string sometimes contains the function signature
- # this works for alot of C modules that are part of the
+ # this works for a lot of C modules that are part of the
# standard library
doc = func_obj.__doc__
if doc:
diff --git a/runtime/autoload/remote/host.vim b/runtime/autoload/remote/host.vim
index c34ff4bee7..884b478f19 100644
--- a/runtime/autoload/remote/host.vim
+++ b/runtime/autoload/remote/host.vim
@@ -114,7 +114,7 @@ function! s:RegistrationCommands(host) abort
let host_id = a:host.'-registration-clone'
call remote#host#RegisterClone(host_id, a:host)
let pattern = s:plugin_patterns[a:host]
- let paths = globpath(&rtp, 'rplugin/'.a:host.'/'.pattern, 1, 1)
+ let paths = nvim_get_runtime_file('rplugin/'.a:host.'/'.pattern, 1)
let paths = map(paths, 'tr(resolve(v:val),"\\","/")') " Normalize slashes #4795
let paths = uniq(sort(paths))
if empty(paths)
diff --git a/runtime/autoload/rubycomplete.vim b/runtime/autoload/rubycomplete.vim
index e8a1879668..3677b25aeb 100644
--- a/runtime/autoload/rubycomplete.vim
+++ b/runtime/autoload/rubycomplete.vim
@@ -3,7 +3,7 @@
" Maintainer: Mark Guzman <segfault@hasno.info>
" URL: https://github.com/vim-ruby/vim-ruby
" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
-" Last Change: 2019 Feb 25
+" Last Change: 2020 Apr 12
" ----------------------------------------------------------------------------
"
" Ruby IRB/Complete author: Keiju ISHITSUKA(keiju@ishitsuka.com)
@@ -501,13 +501,8 @@ class VimRubyCompletion
return if rails_base == nil
$:.push rails_base unless $:.index( rails_base )
- rails_config = rails_base + "config/"
- rails_lib = rails_base + "lib/"
- $:.push rails_config unless $:.index( rails_config )
- $:.push rails_lib unless $:.index( rails_lib )
-
- bootfile = rails_config + "boot.rb"
- envfile = rails_config + "environment.rb"
+ bootfile = rails_base + "config/boot.rb"
+ envfile = rails_base + "config/environment.rb"
if File.exists?( bootfile ) && File.exists?( envfile )
begin
require bootfile
diff --git a/runtime/autoload/sqlcomplete.vim b/runtime/autoload/sqlcomplete.vim
index ea0d8c2de9..adbdbab894 100644
--- a/runtime/autoload/sqlcomplete.vim
+++ b/runtime/autoload/sqlcomplete.vim
@@ -17,7 +17,7 @@
" and complete it.
"
" Version 16.0 (Dec 2015)
-" - NF: If reseting the cache and table, procedure or view completion
+" - NF: If resetting the cache and table, procedure or view completion
" had been used via dbext, have dbext delete or recreate the
" dictionary so that new objects are picked up for the
" next completion.
@@ -554,7 +554,7 @@ function! sqlcomplete#PreCacheSyntax(...)
let syn_group_arr = g:omni_sql_precache_syntax_groups
endif
" For each group specified in the list, precache all
- " the sytnax items.
+ " the syntax items.
if !empty(syn_group_arr)
for group_name in syn_group_arr
let syn_items = extend( syn_items, s:SQLCGetSyntaxList(group_name) )
@@ -577,7 +577,7 @@ function! sqlcomplete#ResetCacheSyntax(...)
let syn_group_arr = g:omni_sql_precache_syntax_groups
endif
" For each group specified in the list, precache all
- " the sytnax items.
+ " the syntax items.
if !empty(syn_group_arr)
for group_name in syn_group_arr
let list_idx = index(s:syn_list, group_name, 0, &ignorecase)
@@ -843,7 +843,7 @@ function! s:SQLCGetColumns(table_name, list_type)
let curline = line(".")
let curcol = col(".")
- " Do not let searchs wrap
+ " Do not let searches wrap
setlocal nowrapscan
" If . was entered, look at the word just before the .
" We are looking for something like this:
@@ -863,7 +863,7 @@ function! s:SQLCGetColumns(table_name, list_type)
" Search forward until one of the following:
" 1. Another select/update/delete statement
" 2. A ; at the end of a line (the delimiter)
- " 3. The end of the file (incase no delimiter)
+ " 3. The end of the file (in case no delimiter)
" Yank the visually selected text into the "y register.
exec 'silent! normal! vl/\c\(\<select\>\|\<update\>\|\<delete\>\|;\s*$\|\%$\)'."\n".'"yy'
diff --git a/runtime/autoload/tar.vim b/runtime/autoload/tar.vim
index b6c4c660b8..e495e8262a 100644
--- a/runtime/autoload/tar.vim
+++ b/runtime/autoload/tar.vim
@@ -778,7 +778,7 @@ fun! tar#Vimuntar(...)
elseif executable("gzip")
silent exe "!gzip -d ".shellescape(tartail)
else
- echoerr "unable to decompress<".tartail."> on this sytem"
+ echoerr "unable to decompress<".tartail."> on this system"
if simplify(curdir) != simplify(tarhome)
" remove decompressed tarball, restore directory
" call Decho("delete(".tartail.".tar)")
diff --git a/runtime/autoload/tohtml.vim b/runtime/autoload/tohtml.vim
index 76092f0f93..66f1cb46cb 100644
--- a/runtime/autoload/tohtml.vim
+++ b/runtime/autoload/tohtml.vim
@@ -693,7 +693,7 @@ func! tohtml#GetUserSettings() "{{{
let user_settings = {}
" Define the correct option if the old option name exists and we haven't
- " already defined the correct one. Maybe I'll put out a warnig message about
+ " already defined the correct one. Maybe I'll put out a warning message about
" this sometime and remove the old option entirely at some even later time,
" but for now just silently accept the old option.
if exists('g:use_xhtml') && !exists("g:html_use_xhtml")
diff --git a/runtime/autoload/vimexpect.vim b/runtime/autoload/vimexpect.vim
index 0ed888d2a4..04c742b894 100644
--- a/runtime/autoload/vimexpect.vim
+++ b/runtime/autoload/vimexpect.vim
@@ -39,7 +39,7 @@ let s:Parser.LINE_BUFFER_MAX_LEN = 100
" Create a new Parser instance with the initial state and a target. The target
" is a dictionary that will be the `self` of every State method call associated
" with the parser, and may contain options normally passed to
-" `jobstart`(on_stdout/on_stderr will be overriden). Returns the target so it
+" `jobstart`(on_stdout/on_stderr will be overridden). Returns the target so it
" can be called directly as the second argument of `jobstart`:
"
" call jobstart(prog_argv, vimexpect#Parser(initial_state, {'pty': 1}))
diff --git a/runtime/autoload/xmlcomplete.vim b/runtime/autoload/xmlcomplete.vim
index 4c1ac4f6b5..55fb031e68 100644
--- a/runtime/autoload/xmlcomplete.vim
+++ b/runtime/autoload/xmlcomplete.vim
@@ -199,7 +199,7 @@ function! xmlcomplete#CompleteTags(findstart, base)
" 1. Events attributes
if context =~ '\s'
- " If attr contains =\s*[\"'] we catched value of attribute
+ " If attr contains =\s*[\"'] we catch value of attribute
if attr =~ "=\s*[\"']" || attr =~ "=\s*$"
" Let do attribute specific completion
let attrname = matchstr(attr, '.*\ze\s*=')
diff --git a/runtime/autoload/zip.vim b/runtime/autoload/zip.vim
index f6b876df05..9588bbf4a2 100644
--- a/runtime/autoload/zip.vim
+++ b/runtime/autoload/zip.vim
@@ -81,7 +81,7 @@ fun! zip#Browse(zipfile)
" sanity checks
if !exists("*fnameescape")
if &verbose > 1
- echoerr "the zip plugin is not available (your vim doens't support fnameescape())"
+ echoerr "the zip plugin is not available (your vim doesn't support fnameescape())"
endif
return
endif
diff --git a/runtime/compiler/fpc.vim b/runtime/compiler/fpc.vim
index fb4f424986..de8e2fe3dc 100644
--- a/runtime/compiler/fpc.vim
+++ b/runtime/compiler/fpc.vim
@@ -12,6 +12,6 @@ if exists(":CompilerSet") != 2 " older Vim always used :setlocal
command -nargs=* CompilerSet setlocal <args>
endif
-" NOTE: compiler must be runned with -vb to write whole source path, not only file
+" NOTE: compiler must be run with -vb to write whole source path, not only file
" name.
CompilerSet errorformat=%f(%l\\,%c)\ %m
diff --git a/runtime/compiler/scdoc.vim b/runtime/compiler/scdoc.vim
new file mode 100644
index 0000000000..2f6edc6322
--- /dev/null
+++ b/runtime/compiler/scdoc.vim
@@ -0,0 +1,16 @@
+" scdoc compiler for Vim
+" Compiler: scdoc
+" Maintainer: Greg Anders <greg@gpanders.com>
+" Last Updated: 2019-10-24
+
+if exists('current_compiler')
+ finish
+endif
+let current_compiler = 'scdoc'
+
+if exists(':CompilerSet') != 2
+ command -nargs=* CompilerSet setlocal <args>
+endif
+
+CompilerSet makeprg=scdoc\ <\ %\ 2>&1
+CompilerSet errorformat=Error\ at\ %l:%c:\ %m,%-G%.%#
diff --git a/runtime/compiler/spectral.vim b/runtime/compiler/spectral.vim
new file mode 100644
index 0000000000..bd13c51f43
--- /dev/null
+++ b/runtime/compiler/spectral.vim
@@ -0,0 +1,17 @@
+" Vim compiler file
+" Compiler: Spectral for YAML
+" Maintainer: Romain Lafourcade <romainlafourcade@gmail.com>
+" Last Change: 2021 July 21
+
+if exists("current_compiler")
+ finish
+endif
+let current_compiler = "spectral"
+
+if exists(":CompilerSet") != 2
+ command -nargs=* CompilerSet setlocal <args>
+endif
+
+CompilerSet makeprg=spectral\ lint\ %\ -f\ text
+CompilerSet errorformat=%f:%l:%c\ %t%.%\\{-}\ %m
+
diff --git a/runtime/compiler/tex.vim b/runtime/compiler/tex.vim
index e43be8dbd6..65e15cf6e2 100644
--- a/runtime/compiler/tex.vim
+++ b/runtime/compiler/tex.vim
@@ -18,7 +18,7 @@ endif
if exists('b:tex_ignore_makefile') || exists('g:tex_ignore_makefile') ||
\(!filereadable('Makefile') && !filereadable('makefile'))
" If buffer-local variable 'tex_flavor' exists, it defines TeX flavor,
- " otherwize the same for global variable with same name, else it will be
+ " otherwise the same for global variable with same name, else it will be
" LaTeX
if exists("b:tex_flavor")
let current_compiler = b:tex_flavor
diff --git a/runtime/compiler/yamllint.vim b/runtime/compiler/yamllint.vim
new file mode 100644
index 0000000000..889b04b63c
--- /dev/null
+++ b/runtime/compiler/yamllint.vim
@@ -0,0 +1,16 @@
+" Vim compiler file
+" Compiler: Yamllint for YAML
+" Maintainer: Romain Lafourcade <romainlafourcade@gmail.com>
+" Last Change: 2021 July 21
+
+if exists("current_compiler")
+ finish
+endif
+let current_compiler = "yamllint"
+
+if exists(":CompilerSet") != 2
+ command -nargs=* CompilerSet setlocal <args>
+endif
+
+CompilerSet makeprg=yamllint\ -f\ parsable
+
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index 07c45c9298..df345e4981 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -134,6 +134,14 @@ lines, 0-based columns):
|nvim_win_get_cursor()|
|nvim_win_set_cursor()|
+Exception: the following API functions use |extmarks| indexing (0-based
+indices, end-inclusive):
+
+ |nvim_buf_del_extmark()|
+ |nvim_buf_get_extmark_by_id()|
+ |nvim_buf_get_extmarks()|
+ |nvim_buf_set_extmark()|
+
*api-fast*
Most API functions are "deferred": they are queued on the main loop and
processed sequentially with normal input. So if the editor is waiting for
@@ -436,36 +444,76 @@ Example: create a float with scratch buffer: >
>
==============================================================================
-Extended marks *api-extended-marks*
+Extended marks *api-extended-marks* *extmarks*
Extended marks (extmarks) represent buffer annotations that track text changes
-in the buffer. They could be used to represent cursors, folds, misspelled
-words, and anything else that needs to track a logical location in the buffer
-over time.
+in the buffer. They can represent cursors, folds, misspelled words, anything
+that needs to track a logical location in the buffer over time. |api-indexing|
+
+Extmark position works like "bar" cursor: it exists between characters. Thus
+the maximum extmark index on a line is 1 more than the character index: >
+
+ f o o b a r line contents
+ 0 1 2 3 4 5 character positions (0-based)
+ 0 1 2 3 4 5 6 extmark positions (0-based)
+
+Extmarks have "forward gravity": if you place the cursor directly on an
+extmark position and enter some text, the extmark migrates forward. >
+
+ f o o|b a r line (| = cursor)
+ 3 extmark
+
+ f o o z|b a r line (| = cursor)
+ 4 extmark (after typing "z")
+
+If an extmark is on the last index of a line and you inputsa newline at that
+point, the extmark will accordingly migrate to the next line: >
+
+ f o o z b a r| line (| = cursor)
+ 7 extmark
+
+ f o o z b a r first line
+ extmarks (none present)
+ | second line (| = cursor)
+ 0 extmark (after typing <CR>)
+
Example:
-We will set an extmark at the first row and third column. |api-indexing| is
-zero-indexed, so we use row=0 and column=2. Passing id=0 creates a new mark
-and returns the id: >
+Let's set an extmark at the first row (row=0) and third column (column=2).
+|api-indexing| Passing id=0 creates a new mark and returns the id: >
+ 01 2345678
+ 0 ex|ample..
+< ^ extmark position
+>
let g:mark_ns = nvim_create_namespace('myplugin')
- let g:mark_id = nvim_buf_set_extmark(0, g:mark_ns, 0, 0, 2, {})
-
-We can get a mark by its id: >
+ let g:mark_id = nvim_buf_set_extmark(0, g:mark_ns, 0, 2, {})
+<
+We can get the mark by its id: >
- echo nvim_buf_get_extmark_by_id(0, g:mark_ns, g:mark_id)
+ echo nvim_buf_get_extmark_by_id(0, g:mark_ns, g:mark_id, {})
=> [0, 2]
-We can get all marks in a buffer for our namespace (or by a range): >
+We can get all marks in a buffer by |namespace| (or by a range): >
echo nvim_buf_get_extmarks(0, g:mark_ns, 0, -1, {})
=> [[1, 0, 2]]
-Deleting all text surrounding an extmark does not remove the extmark. To
-remove an extmark use |nvim_buf_del_extmark()|.
+Deleting all surrounding text does NOT remove an extmark! To remove extmarks
+use |nvim_buf_del_extmark()|. Deleting "x" in our example: >
-Namespaces allow your plugin to manage only its own extmarks, ignoring those
+ 0 12345678
+ 0 e|ample..
+< ^ extmark position
+>
+ echo nvim_buf_get_extmark_by_id(0, g:mark_ns, g:mark_id, {})
+ => [0, 1]
+<
+ Note: Extmark "gravity" decides how it will shift after a text edit.
+ See |nvim_buf_set_extmark()|
+
+Namespaces allow any plugin to manage only its own extmarks, ignoring those
created by another plugin.
Extmark positions changed by an edit will be restored on undo/redo. Creating
@@ -661,8 +709,7 @@ nvim_create_namespace({name}) *nvim_create_namespace()*
Creates a new namespace, or gets an existing one.
Namespaces are used for buffer highlights and virtual text,
- see |nvim_buf_add_highlight()| and
- |nvim_buf_set_virtual_text()|.
+ see |nvim_buf_add_highlight()| and |nvim_buf_set_extmark()|.
Namespaces can be named or anonymous. If `name` matches an
existing namespace, the associated id is returned. If `name`
@@ -780,10 +827,9 @@ nvim_feedkeys({keys}, {mode}, {escape_csi}) *nvim_feedkeys()*
On execution error: does not fail, but updates v:errmsg.
- If you need to input sequences like <C-o> use
- |nvim_replace_termcodes| to replace the termcodes and then
- pass the resulting string to nvim_feedkeys. You'll also want
- to enable escape_csi.
+ To input sequences like <C-o> use |nvim_replace_termcodes()|
+ (typically with escape_csi=true) to replace the keycodes. Then
+ pass the result to nvim_feedkeys().
Example: >
:let key = nvim_replace_termcodes("<C-o>", v:true, v:false, v:true)
@@ -1104,7 +1150,7 @@ nvim_input_mouse({button}, {action}, {modifier}, {grid}, {row}, {col})
intermediate mouse positions will be ignored. It should be
used to implement real-time mouse input in a GUI. The
deprecated pseudokey form ("<LeftMouse><col,row>") of
- |nvim_input()| has the same limitiation.
+ |nvim_input()| has the same limitation.
Attributes: ~
{fast}
@@ -1183,7 +1229,7 @@ nvim_notify({msg}, {log_level}, {opts}) *nvim_notify()*
Notify the user with a message
Relays the call to vim.notify . By default forwards your
- message in the echo area but can be overriden to trigger
+ message in the echo area but can be overridden to trigger
desktop notifications.
Parameters: ~
@@ -1197,7 +1243,7 @@ nvim_open_term({buffer}, {opts}) *nvim_open_term()*
By default (and currently the only option) the terminal will
not be connected to an external process. Instead, input send
on the channel will be echoed directly by the terminal. This
- is useful to disply ANSI terminal sequences returned as part
+ is useful to display ANSI terminal sequences returned as part
of a rpc message, or similar.
Note: to directly initiate the terminal using the right size,
@@ -1419,8 +1465,9 @@ nvim_parse_expression({expr}, {flags}, {highlight})
• "len": Amount of bytes successfully parsed. With flags
equal to "" that should be equal to the length of expr
- string. (“Sucessfully parsed” here means “participated
- in AST creation”, not “till the first error”.)
+ string. (“Successfully parsed” here means
+ “participated in AST creation”, not “till the first
+ error”.)
• "ast": AST, either nil or a dictionary with these
keys:
• "type": node type, one of the value names from
@@ -1681,7 +1728,7 @@ nvim_set_decoration_provider({ns_id}, {opts})
Note: this function should not be called often. Rather, the
callbacks themselves can be used to throttle unneeded
callbacks. the `on_start` callback can return `false` to
- disable the provider until the next redraw. Similarily, return
+ disable the provider until the next redraw. Similarly, return
`false` in `on_win` will skip the `on_lines` calls for that
window (but any extmarks set in `on_win` will still be used).
A plugin managing multiple sources of decoration should
@@ -1721,7 +1768,7 @@ nvim_set_hl({ns_id}, {name}, {val}) *nvim_set_hl()*
Parameters: ~
{ns_id} number of namespace for this highlight
{name} highlight group name, like ErrorMsg
- {val} highlight definiton map, like
+ {val} highlight definition map, like
|nvim_get_hl_by_name|. in addition the following
keys are also recognized: `default` : don't
override existing definition, like `hi default`
@@ -2072,7 +2119,7 @@ nvim_buf_get_commands({buffer}, {opts}) *nvim_buf_get_commands()*
*nvim_buf_get_extmark_by_id()*
nvim_buf_get_extmark_by_id({buffer}, {ns_id}, {id}, {opts})
- Returns position for a given extmark id
+ Gets the position (0-indexed) of an extmark {id}.
Parameters: ~
{buffer} Buffer handle, or 0 for current buffer
@@ -2082,7 +2129,8 @@ nvim_buf_get_extmark_by_id({buffer}, {ns_id}, {id}, {opts})
• details: Whether to include the details dict
Return: ~
- (row, col) tuple or empty list () if extmark id was absent
+ 0-indexed (row, col) tuple or empty list () if extmark id
+ was absent
*nvim_buf_get_extmarks()*
nvim_buf_get_extmarks({buffer}, {ns_id}, {start}, {end}, {opts})
@@ -2122,10 +2170,12 @@ nvim_buf_get_extmarks({buffer}, {ns_id}, {start}, {end}, {opts})
Parameters: ~
{buffer} Buffer handle, or 0 for current buffer
{ns_id} Namespace id from |nvim_create_namespace()|
- {start} Start of range, given as (row, col) or valid
- extmark id (whose position defines the bound)
- {end} End of range, given as (row, col) or valid
- extmark id (whose position defines the bound)
+ {start} Start of range, given as 0-indexed (row, col) or
+ valid extmark id (whose position defines the
+ bound)
+ {end} End of range (inclusive), given as 0-indexed
+ (row, col) or valid extmark id (whose position
+ defines the bound)
{opts} Optional parameters. Keys:
• limit: Maximum number of marks to return
• details Whether to include the details dict
@@ -2289,7 +2339,16 @@ nvim_buf_set_extmark({buffer}, {ns_id}, {line}, {col}, {opts})
• hl_group : name of the highlight group used to
highlight this mark.
• virt_text : virtual text to link to this mark.
- • virt_text_pos : positioning of virtual text.
+ A list of [text, highlight] tuples, each
+ representing a text chunk with specified
+ highlight. `highlight` element can either be a
+ a single highlight group, or an array of
+ multiple highlight groups that will be stacked
+ (highest priority last). A highlight group can
+ be supplied either as a string or as an
+ integer, the latter which can be obtained
+ using |nvim_get_hl_id_by_name|.
+ • virt_text_pos : position of virtual text.
Possible values:
• "eol": right after eol character (default)
• "overlay": display over the specified
@@ -2426,44 +2485,6 @@ nvim_buf_set_var({buffer}, {name}, {value}) *nvim_buf_set_var()*
{name} Variable name
{value} Variable value
- *nvim_buf_set_virtual_text()*
-nvim_buf_set_virtual_text({buffer}, {src_id}, {line}, {chunks}, {opts})
- Set the virtual text (annotation) for a buffer line.
-
- By default (and currently the only option) the text will be
- placed after the buffer text. Virtual text will never cause
- reflow, rather virtual text will be truncated at the end of
- the screen line. The virtual text will begin one cell
- (|lcs-eol| or space) after the ordinary text.
-
- Namespaces are used to support batch deletion/updating of
- virtual text. To create a namespace, use
- |nvim_create_namespace()|. Virtual text is cleared using
- |nvim_buf_clear_namespace()|. The same `ns_id` can be used for
- both virtual text and highlights added by
- |nvim_buf_add_highlight()|, both can then be cleared with a
- single call to |nvim_buf_clear_namespace()|. If the virtual
- text never will be cleared by an API call, pass `ns_id = -1` .
-
- As a shorthand, `ns_id = 0` can be used to create a new
- namespace for the virtual text, the allocated id is then
- returned.
-
- Parameters: ~
- {buffer} Buffer handle, or 0 for current buffer
- {ns_id} Namespace to use or 0 to create a namespace, or
- -1 for a ungrouped annotation
- {line} Line to annotate with virtual text
- (zero-indexed)
- {chunks} A list of [text, hl_group] arrays, each
- representing a text chunk with specified
- highlight. `hl_group` element can be omitted for
- no highlight.
- {opts} Optional parameters. Currently not used.
-
- Return: ~
- The ns_id that was used
-
==============================================================================
Window Functions *api-window*
diff --git a/runtime/doc/arabic.txt b/runtime/doc/arabic.txt
index df91b8d065..5d3bf7a761 100644
--- a/runtime/doc/arabic.txt
+++ b/runtime/doc/arabic.txt
@@ -171,6 +171,13 @@ o Enable Arabic settings [short-cut]
and its support is preferred due to its level of offerings.
'arabic' when 'termbidi' is enabled only sets the keymap.
+ For vertical window isolation while setting 'termbidi' an LTR
+ vertical separator like "l" or "𝖨" may be used. It may also be
+ hidden by changing its color to the foreground color: >
+ :set fillchars=vert:l
+ :hi VertSplit ctermbg=White
+< Note that this is a workaround, not a proper solution.
+
If, on the other hand, you'd like to be verbose and explicit and
are opting not to use the 'arabic' short-cut command, here's what
is needed (i.e. if you use ':set arabic' you can skip this section) -
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index 9ee1954514..7a53f17a78 100644
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -232,7 +232,7 @@ BufDelete Before deleting a buffer from the buffer list.
*BufEnter*
BufEnter After entering a buffer. Useful for setting
options for a file type. Also executed when
- starting to edit a buffer, after the
+ starting to edit a buffer.
After |BufAdd|.
After |BufReadPost|.
*BufFilePost*
@@ -499,8 +499,10 @@ CursorMoved After the cursor was moved in Normal or Visual
mode or to another window. Also when the text
of the cursor line has been changed, e.g. with
"x", "rx" or "p".
- Not triggered when there is typeahead or when
- an operator is pending.
+ Not triggered when there is typeahead, while
+ executing a script file, when an operator is
+ pending, or when moving to another window while
+ remaining at the same cursor position.
For an example see |match-parens|.
Note: Cannot be skipped with |:noautocmd|.
Careful: This is triggered very often, don't
@@ -798,9 +800,10 @@ QuickFixCmdPost Like QuickFixCmdPre, but after a quickfix
*QuitPre*
QuitPre When using `:quit`, `:wq` or `:qall`, before
deciding whether it closes the current window
- or quits Vim. Can be used to close any
- non-essential window if the current window is
- the last ordinary window.
+ or quits Vim. For `:wq` the buffer is written
+ before QuitPre is triggered. Can be used to
+ close any non-essential window if the current
+ window is the last ordinary window.
See also |ExitPre|, ||WinClosed|.
*RemoteReply*
RemoteReply When a reply from a Vim that functions as
@@ -914,6 +917,8 @@ TermLeave After leaving |Terminal-mode|.
After TermClose.
*TermClose*
TermClose When a |terminal| job ends.
+ Sets these |v:event| keys:
+ status
*TermResponse*
TermResponse After the response to t_RV is received from
the terminal. The value of |v:termresponse|
diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt
index 7a63a89986..2b799e3e27 100644
--- a/runtime/doc/change.txt
+++ b/runtime/doc/change.txt
@@ -568,9 +568,7 @@ with ".". Vim does not recognize a comment (starting with '"') after the
option is empty (this is the default), use the
internal formatting function |C-indenting| and
|'lisp'|. But when 'indentexpr' is not empty, it will
- be used instead |indent-expression|. When Vim was
- compiled without internal formatting then the "indent"
- program is used as a last resort.
+ be used instead |indent-expression|.
*==*
== Filter [count] lines like with ={motion}.
@@ -749,12 +747,14 @@ For compatibility with Vi these two exceptions are allowed:
"\/{string}/" and "\?{string}?" do the same as "//{string}/r".
"\&{string}&" does the same as "//{string}/".
*pattern-delimiter* *E146*
-Instead of the '/' which surrounds the pattern and replacement string, you
-can use any other single-byte character, but not an alphanumeric character,
-'\', '"' or '|'. This is useful if you want to include a '/' in the search
-pattern or replacement string. Example: >
+Instead of the '/' which surrounds the pattern and replacement string, you can
+use another single-byte character. This is useful if you want to include a
+'/' in the search pattern or replacement string. Example: >
:s+/+//+
+You can use most characters, but not an alphanumeric character, '\', '"' or
+'|'.
+
For the definition of a pattern, see |pattern|. In Visual block mode, use
|/\%V| in the pattern to have the substitute work in the block only.
Otherwise it works on whole lines anyway.
@@ -988,9 +988,9 @@ inside of strings can change! Also see 'softtabstop' option. >
*Y*
["x]Y yank [count] lines [into register x] (synonym for
- yy, |linewise|). If you like "Y" to work from the
- cursor to the end of line (which is more logical,
- but not Vi-compatible) use ":map Y y$".
+ yy, |linewise|).
+ *Y-default*
+ Mapped to "y$" by default. |default-mappings|
*zy*
["x]zy{motion} Yank {motion} text [into register x]. Only differs
@@ -1011,9 +1011,7 @@ inside of strings can change! Also see 'softtabstop' option. >
with `zp`. (for {Visual} see |Visual-mode|)
*:y* *:yank* *E850*
-:[range]y[ank] [x] Yank [range] lines [into register x]. Yanking to the
- "* or "+ registers is possible only when the
- |+clipboard| feature is included.
+:[range]y[ank] [x] Yank [range] lines [into register x].
:[range]y[ank] [x] {count}
Yank {count} lines, starting with last line number
@@ -1802,8 +1800,7 @@ found here: |sort()|, |uniq()|.
With [f] sorting is done on the Float in the line.
The value of Float is determined similar to passing
the text (after or inside a {pattern} match) to
- str2float() function. This option is available only
- if Vim was compiled with Floating point support.
+ str2float() function.
With [x] sorting is done on the first hexadecimal
number in the line (after or inside a {pattern}
diff --git a/runtime/doc/cmdline.txt b/runtime/doc/cmdline.txt
index 2db694cf07..6b46ac9cf2 100644
--- a/runtime/doc/cmdline.txt
+++ b/runtime/doc/cmdline.txt
@@ -153,7 +153,12 @@ CTRL-R {register} *c_CTRL-R* *c_<C-R>*
too.
When the result is a Float it's automatically
converted to a String.
- See |registers| about registers.
+ Note that when you only want to move the
+ cursor and not insert anything, you must make
+ sure the expression evaluates to an empty
+ string. E.g.: >
+ <C-R><C-R>=setcmdpos(2)[-1]<CR>
+< See |registers| about registers.
Implementation detail: When using the |expression| register
and invoking setcmdpos(), this sets the position before
inserting the resulting string. Use CTRL-R CTRL-R to set the
@@ -1067,7 +1072,7 @@ in Normal mode and Insert mode.
It is possible to use ":", "/" and other commands that use the command-line,
but it's not possible to open another command-line window then. There is no
nesting.
- *E11*
+ *E11* *E1188*
The command-line window is not a normal window. It is not possible to move to
another window or edit another buffer. All commands that would do this are
disabled in the command-line window. Of course it _is_ possible to execute
@@ -1140,6 +1145,11 @@ Thus you can resize the command-line window, but not others.
The |getcmdwintype()| function returns the type of the command-line being
edited as described in |cmdwin-char|.
+Nvim defines this default CmdWinEnter autocmd in the "nvim_cmdwin" group: >
+ autocmd CmdWinEnter [:>] syntax sync minlines=1 maxlines=1
+<
+You can disable this in your config with "autocmd! nvim_cmdwin". |default-autocmds|
+
AUTOCOMMANDS
diff --git a/runtime/doc/deprecated.txt b/runtime/doc/deprecated.txt
index 3b5287ee44..a7ce4135af 100644
--- a/runtime/doc/deprecated.txt
+++ b/runtime/doc/deprecated.txt
@@ -14,6 +14,7 @@ updated.
API ~
*nvim_buf_clear_highlight()* Use |nvim_buf_clear_namespace()| instead.
+*nvim_buf_set_virtual_text()* Use |nvim_buf_set_extmark()| instead.
*nvim_command_output()* Use |nvim_exec()| instead.
*nvim_execute_lua()* Use |nvim_exec_lua()| instead.
@@ -54,6 +55,55 @@ Functions ~
without stopping the job. Use chanclose(id) to close
any socket.
+LSP Diagnostics ~
+
+For each of the functions below, use the corresponding function in
+|vim.diagnostic| instead (unless otherwise noted). For example, use
+|vim.diagnostic.get()| instead of |vim.lsp.diagnostic.get()|.
+
+*vim.lsp.diagnostic.clear()* Use |vim.diagnostic.hide()| instead.
+*vim.lsp.diagnostic.disable()*
+*vim.lsp.diagnostic.display()* Use |vim.diagnostic.show()| instead.
+*vim.lsp.diagnostic.enable()*
+*vim.lsp.diagnostic.get()*
+*vim.lsp.diagnostic.get_all()* Use |vim.diagnostic.get()| instead.
+*vim.lsp.diagnostic.get_count()* Use |vim.diagnostic.get()| instead.
+*vim.lsp.diagnostic.get_line_diagnostics()*
+ Use |vim.diagnostic.get()| instead.
+*vim.lsp.diagnostic.get_next()*
+*vim.lsp.diagnostic.get_next_pos()*
+*vim.lsp.diagnostic.get_prev()*
+*vim.lsp.diagnostic.get_prev_pos()*
+*vim.lsp.diagnostic.get_virtual_text_chunks_for_line()*
+ No replacement. Use options provided by
+ |vim.diagnostic.config()| to customize
+ virtual text.
+*vim.lsp.diagnostic.goto_next()*
+*vim.lsp.diagnostic.goto_prev()*
+*vim.lsp.diagnostic.redraw()* Use |vim.diagnostic.show()| instead.
+*vim.lsp.diagnostic.reset()*
+*vim.lsp.diagnostic.save()* Use |vim.diagnostic.set()| instead.
+*vim.lsp.diagnostic.set_loclist()* Use |vim.diagnostic.setloclist()| instead.
+*vim.lsp.diagnostic.set_qflist()* Use |vim.diagnostic.setqflist()| instead.
+*vim.lsp.diagnostic.show_line_diagnostics()*
+*vim.lsp.diagnostic.show_position_diagnostics()*
+
+The following are deprecated without replacement. These functions are moved
+internally and are no longer exposed as part of the API. Instead, use
+|vim.diagnostic.config()| and |vim.diagnostic.show()|.
+
+*vim.lsp.diagnostic.set_signs()*
+*vim.lsp.diagnostic.set_underline()*
+*vim.lsp.diagnostic.set_virtual_text()*
+
+LSP Utility 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.
+
+Lua ~
+*vim.register_keystroke_callback()* Use |vim.on_key()| instead.
Modifiers ~
*cpo-<*
diff --git a/runtime/doc/dev_style.txt b/runtime/doc/dev_style.txt
new file mode 100644
index 0000000000..82f279e781
--- /dev/null
+++ b/runtime/doc/dev_style.txt
@@ -0,0 +1,1159 @@
+*dev_style.txt* Nvim
+
+
+ NVIM REFERENCE MANUAL
+
+
+Nvim style guide *dev-style*
+
+This is style guide for developers working on Nvim's source code.
+
+License: CC-By 3.0 http://creativecommons.org/licenses/by/3.0/
+
+ Type |gO| to see the table of contents.
+
+==============================================================================
+Background
+
+One way in which we keep the code base manageable is by enforcing consistency.
+It is very important that any programmer be able to look at another's code and
+quickly understand it.
+
+Maintaining a uniform style and following conventions means that we can more
+easily use "pattern-matching" to infer what various symbols are and what
+invariants are true about them. Creating common, required idioms and patterns
+makes code much easier to understand.
+
+In some cases there might be good arguments for changing certain style rules,
+but we nonetheless keep things as they are in order to preserve consistency.
+
+
+==============================================================================
+Header Files *dev-style-header*
+
+
+The #define Guard ~
+
+All header files should have `#define` guards to prevent multiple inclusion.
+The format of the symbol name should be `NVIM_<DIRECTORY>_<FILE>_H`.
+
+ In foo/bar.h:
+>
+ #ifndef NVIM_FOO_BAR_H
+ #define NVIM_FOO_BAR_H
+
+ ...
+
+ #endif // NVIM_FOO_BAR_H
+<
+
+
+Names and Order of Includes ~
+
+Use standard order for readability and to avoid hidden dependencies: C
+library, other libraries' `.h`, your project's `.h`.
+
+ In foo.c order your includes as follows:
+
+ 1. C system files.
+ 2. Other libraries' `.h` files.
+ 3. Your project's `.h` files.
+
+ Exception: sometimes, system-specific code needs conditional includes.
+ Such code can put conditional includes after other includes. Of course,
+ keep your system-specific code small and localized.
+
+
+Constants ~
+
+Do not use macros to define constants in headers.
+
+Macro constants in header files cannot be used by unit tests.
+
+However, you are allowed to define a macro that holds the same value as a
+non-enum constant (defined in the same header) if the value of the constant
+represents the size of an array.
+
+
+==============================================================================
+Scoping *dev-style-scope*
+
+Local Variables ~
+
+Place a function's variables in the narrowest scope possible, and initialize
+variables in the declaration.
+
+C99 allows you to declare variables anywhere in a function. Declare them in as
+local a scope as possible, and as close to the first use as possible. This
+makes it easier for the reader to find the declaration and see what type the
+variable is and what it was initialized to. In particular, initialization
+should be used instead of declaration and assignment, e.g. >
+
+ int i;
+ i = f(); // BAD: initialization separate from declaration.
+
+ int j = g(); // GOOD: declaration has initialization.
+
+
+==============================================================================
+Nvim-Specific Magic
+
+clint ~
+
+Use `clint.py` to detect style errors.
+
+`src/clint.py` is a Python script that reads a source file and identifies
+style errors. It is not perfect, and has both false positives and false
+negatives, but it is still a valuable tool. False positives can be ignored by
+putting `// NOLINT` at the end of the line.
+
+uncrustify ~
+
+src/uncrustify.cfg is the authority for expected code formatting, for cases
+not covered by clint.py. We remove checks in clint.py if they are covered by
+uncrustify rules.
+
+==============================================================================
+Other C Features *dev-style-features*
+
+
+Variable-Length Arrays and alloca() ~
+
+We do not allow variable-length arrays or `alloca()`.
+
+Variable-length arrays can cause hard to detect stack overflows.
+
+
+Postincrement and Postdecrement ~
+
+Use postfix form (`i++`) in statements. >
+
+ for (int i = 0; i < 3; i++) { }
+ int j = ++i; // OK: ++i is used as an expression.
+
+ for (int i = 0; i < 3; ++i) { }
+ ++i; // BAD: ++i is used as a statement.
+
+
+Use of const ~
+
+Use `const` pointers whenever possible. Avoid `const` on non-pointer parameter definitions.
+
+ Where to put the const ~
+
+ Some people favor the form `int const *foo` to `const int *foo` . They
+ argue that this is more readable because it's more consistent: it keeps
+ the rule that `const` always follows the object it's describing. However,
+ this consistency argument doesn't apply in codebases with few
+ deeply-nested pointer expressions since most `const` expressions have only
+ one `const`, and it applies to the underlying value. In such cases, there's
+ no consistency to maintain. Putting the `const` first is arguably more
+ readable, since it follows English in putting the "adjective" (`const`)
+ before the "noun" (`int`).
+
+ That said, while we encourage putting `const` first, we do not require it.
+ But be consistent with the code around you! >
+
+ void foo(const char *p, int i);
+ }
+
+ int foo(const int a, const bool b) {
+ }
+
+ int foo(int *const p) {
+ }
+
+
+Integer Types ~
+
+Of the built-in integer types only use `char`, `int`, `uint8_t`, `int8_t`,
+`uint16_t`, `int16_t`, `uint32_t`, `int32_t`, `uint64_t`, `int64_t`,
+`uintmax_t`, `intmax_t`, `size_t`, `ssize_t`, `uintptr_t`, `intptr_t`, and
+`ptrdiff_t`.
+
+Use `int` for error codes and local, trivial variables only.
+
+Use care when converting integer types. Integer conversions and promotions can
+cause non-intuitive behavior. Note that the signedness of `char` is
+implementation defined.
+
+Public facing types must have fixed width (`uint8_t`, etc.)
+
+There are no convenient `printf` format placeholders for fixed width types.
+Cast to `uintmax_t` or `intmax_t` if you have to format fixed width integers.
+
+Type unsigned signed
+`char` `%hhu` `%hhd`
+`int` n/a `%d`
+`(u)intmax_t` `%ju` `%jd`
+`(s)size_t` `%zu` `%zd`
+`ptrdiff_t` `%tu` `%td`
+
+
+Booleans ~
+
+Use `bool` to represent boolean values. >
+
+ int loaded = 1; // BAD: loaded should have type bool.
+
+
+Variable declarations ~
+
+Declare only one variable per line. >
+
+ int i, j = 1
+
+
+Conditions ~
+
+Don't use "yoda-conditions". Use at most one assignment per condition. >
+
+ if (1 == x) {
+
+ if (x == 1) { //use this order
+
+ if ((x = f()) && (y = g())) {
+
+
+Function declarations ~
+
+Every function must not have a separate declaration.
+
+Function declarations are created by the gendeclarations.lua script. >
+
+ static void f(void);
+
+ static void f(void)
+ {
+ ...
+ }
+
+
+General translation unit layout ~
+
+The definitions of public functions precede the definitions of static
+functions. >
+
+ <HEADER>
+
+ <PUBLIC FUNCTION DEFINITIONS>
+
+ <STATIC FUNCTION DEFINITIONS>
+
+
+Integration with declarations generator ~
+
+Every C file must contain #include of the generated header file, guarded by
+#ifdef INCLUDE_GENERATED_DECLARATIONS.
+
+Include must go after other #includes and typedefs in .c files and after
+everything else in header files. It is allowed to omit #include in a .c file
+if .c file does not contain any static functions.
+
+Included file name consists of the .c file name without extension, preceded by
+the directory name relative to src/nvim. Name of the file containing static
+functions declarations ends with `.c.generated.h`, `*.h.generated.h` files
+contain only non-static function declarations. >
+
+ // src/nvim/foo.c file
+ #include <stddef.h>
+
+ typedef int FooType;
+
+ #ifdef INCLUDE_GENERATED_DECLARATIONS
+ # include "foo.c.generated.h"
+ #endif
+
+ …
+
+
+ // src/nvim/foo.h file
+ #ifndef NVIM_FOO_H
+ #define NVIM_FOO_H
+
+ …
+
+ #ifdef INCLUDE_GENERATED_DECLARATIONS
+ # include "foo.h.generated.h"
+ #endif
+ #endif // NVIM_FOO_H
+
+
+64-bit Portability ~
+
+Code should be 64-bit and 32-bit friendly. Bear in mind problems of printing,
+comparisons, and structure alignment.
+
+- Remember that `sizeof(void *)` != `sizeof(int)`. Use `intptr_t` if you want
+ a pointer-sized integer.
+
+- You may need to be careful with structure alignments, particularly for
+ structures being stored on disk. Any class/structure with a
+ `int64_t`/`uint64_t` member will by default end up being 8-byte aligned on a
+ 64-bit system. If you have such structures being shared on disk between
+ 32-bit and 64-bit code, you will need to ensure that they are packed the
+ same on both architectures. Most compilers offer a way to alter structure
+ alignment. For gcc, you can use `__attribute__((packed))`. MSVC offers
+ `#pragma pack()` and `__declspec(align())`.
+
+- Use the `LL` or `ULL` suffixes as needed to create 64-bit constants. For
+ example: >
+
+ int64_t my_value = 0x123456789LL;
+ uint64_t my_mask = 3ULL << 48;
+
+
+sizeof ~
+
+Prefer `sizeof(varname)` to `sizeof(type)`.
+
+Use `sizeof(varname)` when you take the size of a particular variable.
+`sizeof(varname)` will update appropriately if someone changes the variable
+type either now or later. You may use `sizeof(type)` for code unrelated to any
+particular variable, such as code that manages an external or internal data
+format where a variable of an appropriate C type is not convenient. >
+
+ Struct data;
+ memset(&data, 0, sizeof(data));
+
+ memset(&data, 0, sizeof(Struct));
+
+ if (raw_size < sizeof(int)) {
+ fprintf(stderr, "compressed record not big enough for count: %ju", raw_size);
+ return false;
+ }
+
+
+==============================================================================
+Naming *dev-style-naming*
+
+The most important consistency rules are those that govern naming. The style
+of a name immediately informs us what sort of thing the named entity is: a
+type, a variable, a function, a constant, a macro, etc., without requiring us
+to search for the declaration of that entity. The pattern-matching engine in
+our brains relies a great deal on these naming rules.
+
+Naming rules are pretty arbitrary, but we feel that consistency is more
+important than individual preferences in this area, so regardless of whether
+you find them sensible or not, the rules are the rules.
+
+
+General Naming Rules ~
+
+Function names, variable names, and filenames should be descriptive; eschew
+abbreviation.
+
+Give as descriptive a name as possible, within reason. Do not worry about
+saving horizontal space as it is far more important to make your code
+immediately understandable by a new reader. Do not use abbreviations that are
+ambiguous or unfamiliar to readers outside your project, and do not abbreviate
+by deleting letters within a word. >
+
+ int price_count_reader; // No abbreviation.
+ int num_errors; // "num" is a widespread convention.
+ int num_dns_connections; // Most people know what "DNS" stands for.
+
+ int n; // Meaningless.
+ int nerr; // Ambiguous abbreviation.
+ int n_comp_conns; // Ambiguous abbreviation.
+ int wgc_connections; // Only your group knows what this stands for.
+ int pc_reader; // Lots of things can be abbreviated "pc".
+ int cstmr_id; // Deletes internal letters.
+
+
+File Names ~
+
+Filenames should be all lowercase and can include underscores (`_`).
+
+Use underscores to separate words. Examples of acceptable file names: >
+
+ my_useful_file.c
+ getline_fix.c // OK: getline refers to the glibc function.
+
+C files should end in `.c` and header files should end in `.h`.
+
+Do not use filenames that already exist in `/usr/include`, such as `db.h`.
+
+In general, make your filenames very specific. For example, use
+`http_server_logs.h` rather than `logs.h`.
+
+
+Type Names ~
+
+Typedef-ed structs and enums start with a capital letter and have a capital
+letter for each new word, with no underscores: `MyExcitingStruct`.
+
+Non-Typedef-ed structs and enums are all lowercase with underscores between
+words: `struct my_exciting_struct` . >
+
+ struct my_struct {
+ ...
+ };
+ typedef struct my_struct MyAwesomeStruct;
+
+
+Variable Names ~
+
+Variable names are all lowercase, with underscores between words. For
+instance: `my_exciting_local_variable`.
+
+ Common Variable names ~
+
+ For example: >
+
+ string table_name; // OK: uses underscore.
+ string tablename; // OK: all lowercase.
+
+ string tableName; // BAD: mixed case.
+<
+
+ Struct Variables ~
+
+ Data members in structs should be named like regular variables. >
+
+ struct url_table_properties {
+ string name;
+ int num_entries;
+ }
+<
+
+ Global Variables ~
+
+ Don't use global variables unless absolutely necessary. Prefix global
+ variables with `g_`.
+
+
+Constant Names ~
+
+Use a `k` followed by mixed case: `kDaysInAWeek`.
+
+All compile-time constants, whether they are declared locally or globally,
+follow a slightly different naming convention from other variables. Use a `k`
+followed by words with uppercase first letters: >
+
+ const int kDaysInAWeek = 7;
+
+Function Names ~
+
+Function names are all lowercase, with underscores between words. For
+instance: `my_exceptional_function()`. All functions in the same header file
+should have a common prefix.
+
+In `os_unix.h`: >
+
+ void unix_open(const char *path);
+ void unix_user_id(void);
+
+If your function crashes upon an error, you should append `or_die` to the
+function name. This only applies to functions which could be used by
+production code and to errors that are reasonably likely to occur during
+normal operation.
+
+
+Enumerator Names ~
+
+Enumerators should be named like constants: `kEnumName`. >
+
+ enum url_table_errors {
+ kOK = 0,
+ kErrorOutOfMemory,
+ kErrorMalformedInput,
+ };
+
+
+Macro Names ~
+
+They're like this: `MY_MACRO_THAT_SCARES_CPP_DEVELOPERS`. >
+
+ #define ROUND(x) ...
+ #define PI_ROUNDED 5.0
+
+
+==============================================================================
+Comments *dev-style-comments*
+
+Comments are vital to keeping our code readable. The following rules describe
+what you should comment and where. But remember: while comments are very
+important, the best code is self-documenting.
+
+When writing your comments, write for your audience: the next contributor who
+will need to understand your code. Be generous — the next one may be you!
+
+Nvim uses Doxygen comments.
+
+
+Comment Style ~
+
+Use the `//`-style syntax only. >
+
+ // This is a comment spanning
+ // multiple lines
+ f();
+
+
+File Comments ~
+
+Start each file with a description of its contents.
+
+ Legal Notice ~
+
+ We have no such thing. These things are in LICENSE and only there.
+
+ File Contents ~
+
+ Every file should have a comment at the top describing its contents.
+
+ Generally a `.h` file will describe the variables and functions that are
+ declared in the file with an overview of what they are for and how they
+ are used. A `.c` file should contain more information about implementation
+ details or discussions of tricky algorithms. If you feel the
+ implementation details or a discussion of the algorithms would be useful
+ for someone reading the `.h`, feel free to put it there instead, but
+ mention in the `.c` that the documentation is in the `.h` file.
+
+ Do not duplicate comments in both the `.h` and the `.c`. Duplicated
+ comments diverge. >
+
+ /// A brief description of this file.
+ ///
+ /// A longer description of this file.
+ /// Be very generous here.
+
+
+Struct Comments ~
+
+Every struct definition should have accompanying comments that describes what
+it is for and how it should be used. >
+
+ /// Window info stored with a buffer.
+ ///
+ /// Two types of info are kept for a buffer which are associated with a
+ /// specific window:
+ /// 1. Each window can have a different line number associated with a
+ /// buffer.
+ /// 2. The window-local options for a buffer work in a similar way.
+ /// The window-info is kept in a list at g_wininfo. It is kept in
+ /// most-recently-used order.
+ struct win_info {
+ /// Next entry or NULL for last entry.
+ WinInfo *wi_next;
+ /// Previous entry or NULL for first entry.
+ WinInfo *wi_prev;
+ /// Pointer to window that did the wi_fpos.
+ Win *wi_win;
+ ...
+ };
+
+If the field comments are short, you can also put them next to the field. But
+be consistent within one struct. >
+
+ struct wininfo_S {
+ WinInfo *wi_next; /// Next entry or NULL for last entry.
+ WinInfo *wi_prev; /// Previous entry or NULL for first entry.
+ Win *wi_win; /// Pointer to window that did the wi_fpos.
+ ...
+ };
+
+If you have already described a struct in detail in the comments at the top of
+your file feel free to simply state "See comment at top of file for a complete
+description", but be sure to have some sort of comment.
+
+Document the synchronization assumptions the struct makes, if any. If an
+instance of the struct can be accessed by multiple threads, take extra care to
+document the rules and invariants surrounding multithreaded use.
+
+
+Function Comments ~
+
+Declaration comments describe use of the function; comments at the definition
+of a function describe operation.
+
+ Function Declarations ~
+
+ Every function declaration should have comments immediately preceding it
+ that describe what the function does and how to use it. These comments
+ should be descriptive ("Opens the file") rather than imperative ("Open the
+ file"); the comment describes the function, it does not tell the function
+ what to do. In general, these comments do not describe how the function
+ performs its task. Instead, that should be left to comments in the
+ function definition.
+
+ Types of things to mention in comments at the function declaration:
+
+ - If the function allocates memory that the caller must free.
+ - Whether any of the arguments can be a null pointer.
+ - If there are any performance implications of how a function is used.
+ - If the function is re-entrant. What are its synchronization assumptions?
+ >
+ /// Brief description of the function.
+ ///
+ /// Detailed description.
+ /// May span multiple paragraphs.
+ ///
+ /// @param arg1 Description of arg1
+ /// @param arg2 Description of arg2. May span
+ /// multiple lines.
+ ///
+ /// @return Description of the return value.
+ Iterator *get_iterator(void *arg1, void *arg2);
+<
+
+ Function Definitions ~
+
+ If there is anything tricky about how a function does its job, the
+ function definition should have an explanatory comment. For example, in
+ the definition comment you might describe any coding tricks you use, give
+ an overview of the steps you go through, or explain why you chose to
+ implement the function in the way you did rather than using a viable
+ alternative. For instance, you might mention why it must acquire a lock
+ for the first half of the function but why it is not needed for the second
+ half.
+
+ Note you should not just repeat the comments given with the function
+ declaration, in the `.h` file or wherever. It's okay to recapitulate
+ briefly what the function does, but the focus of the comments should be on
+ how it does it. >
+
+ // Note that we don't use Doxygen comments here.
+ Iterator *get_iterator(void *arg1, void *arg2)
+ {
+ ...
+ }
+
+
+Variable Comments ~
+
+In general the actual name of the variable should be descriptive enough to
+give a good idea of what the variable is used for. In certain cases, more
+comments are required.
+
+ Global Variables ~
+
+ All global variables should have a comment describing what they are and
+ what they are used for. For example: >
+
+ /// The total number of tests cases that we run
+ /// through in this regression test.
+ const int kNumTestCases = 6;
+
+
+Implementation Comments ~
+
+In your implementation you should have comments in tricky, non-obvious,
+interesting, or important parts of your code.
+
+ Line Comments ~
+
+ Also, lines that are non-obvious should get a comment at the end of the
+ line. These end-of-line comments should be separated from the code by 2
+ spaces. Example: >
+
+ // If we have enough memory, mmap the data portion too.
+ mmap_budget = max<int64>(0, mmap_budget - index_->length());
+ if (mmap_budget >= data_size_ && !MmapData(mmap_chunk_bytes, mlock)) {
+ return; // Error already logged.
+ }
+<
+ Note that there are both comments that describe what the code is doing,
+ and comments that mention that an error has already been logged when the
+ function returns.
+
+ If you have several comments on subsequent lines, it can often be more
+ readable to line them up: >
+
+ do_something(); // Comment here so the comments line up.
+ do_something_else_that_is_longer(); // Comment here so there are two spaces between
+ // the code and the comment.
+ { // One space before comment when opening a new scope is allowed,
+ // thus the comment lines up with the following comments and code.
+ do_something_else(); // Two spaces before line comments normally.
+ }
+<
+
+ NULL, true/false, 1, 2, 3... ~
+
+ When you pass in a null pointer, boolean, or literal integer values to
+ functions, you should consider adding a comment about what they are, or
+ make your code self-documenting by using constants. For example, compare:
+ >
+
+ bool success = calculate_something(interesting_value,
+ 10,
+ false,
+ NULL); // What are these arguments??
+<
+
+ versus: >
+
+ bool success = calculate_something(interesting_value,
+ 10, // Default base value.
+ false, // Not the first time we're calling this.
+ NULL); // No callback.
+<
+
+ Or alternatively, constants or self-describing variables: >
+
+ const int kDefaultBaseValue = 10;
+ const bool kFirstTimeCalling = false;
+ Callback *null_callback = NULL;
+ bool success = calculate_something(interesting_value,
+ kDefaultBaseValue,
+ kFirstTimeCalling,
+ null_callback);
+<
+
+ Don'ts ~
+
+ Note that you should never describe the code itself. Assume that the
+ person reading the code knows C better than you do, even though he or she
+ does not know what you are trying to do: >
+
+ // Now go through the b array and make sure that if i occurs,
+ // the next element is i+1.
+ ... // Geez. What a useless comment.
+
+
+Punctuation, Spelling and Grammar ~
+
+Pay attention to punctuation, spelling, and grammar; it is easier to read
+well-written comments than badly written ones.
+
+Comments should be as readable as narrative text, with proper capitalization
+and punctuation. In many cases, complete sentences are more readable than
+sentence fragments. Shorter comments, such as comments at the end of a line of
+code, can sometimes be less formal, but you should be consistent with your
+style.
+
+Although it can be frustrating to have a code reviewer point out that you are
+using a comma when you should be using a semicolon, it is very important that
+source code maintain a high level of clarity and readability. Proper
+punctuation, spelling, and grammar help with that goal.
+
+
+TODO Comments ~
+
+Use `TODO` comments for code that is temporary, a short-term solution, or
+good-enough but not perfect.
+
+`TODO`s should include the string `TODO` in all caps, followed by the name,
+email address, or other identifier of the person who can best provide context
+about the problem referenced by the `TODO`. The main purpose is to have a
+consistent `TODO` format that can be searched to find the person who can
+provide more details upon request. A `TODO` is not a commitment that the
+person referenced will fix the problem. Thus when you create a `TODO`, it is
+almost always your name that is given. >
+
+ // TODO(kl@gmail.com): Use a "*" here for concatenation operator.
+ // TODO(Zeke): change this to use relations.
+
+If your `TODO` is of the form "At a future date do something" make sure that
+you either include a very specific date ("Fix by November 2005") or a very
+specific event ("Remove this code when all clients can handle XML
+responses.").
+
+
+Deprecation Comments ~
+
+Mark deprecated interface points with `@deprecated` docstring token.
+
+You can mark an interface as deprecated by writing a comment containing the
+word `@deprecated` in all caps. The comment goes either before the declaration
+of the interface or on the same line as the declaration.
+
+After `@deprecated`, write your name, email, or other identifier in
+parentheses.
+
+A deprecation comment must include simple, clear directions for people to fix
+their callsites. In C, you can implement a deprecated function as an inline
+function that calls the new interface point.
+
+Marking an interface point `DEPRECATED` will not magically cause any callsites
+to change. If you want people to actually stop using the deprecated facility,
+you will have to fix the callsites yourself or recruit a crew to help you.
+
+New code should not contain calls to deprecated interface points. Use the new
+interface point instead. If you cannot understand the directions, find the
+person who created the deprecation and ask them for help using the new
+interface point.
+
+
+==============================================================================
+Formatting *dev-style-format*
+
+Coding style and formatting are pretty arbitrary, but a project is much easier
+to follow if everyone uses the same style. Individuals may not agree with
+every aspect of the formatting rules, and some of the rules may take some
+getting used to, but it is important that all project contributors follow the
+style rules so that they can all read and understand everyone's code easily.
+
+
+Line Length ~
+
+Each line of text in your code should be at most 100 characters long.
+
+Exception: if a comment line contains an example command or a literal URL
+longer than 100 characters, that line may be longer than 100 characters for ease
+of cut and paste.
+
+
+Non-ASCII Characters ~
+
+Non-ASCII characters should be rare, and must use UTF-8 formatting.
+
+You shouldn't hard-code user-facing text in source (OR SHOULD YOU?), even
+English, so use of non-ASCII characters should be rare. However, in certain
+cases it is appropriate to include such words in your code. For example, if
+your code parses data files from foreign sources, it may be appropriate to
+hard-code the non-ASCII string(s) used in those data files as delimiters. More
+commonly, unittest code (which does not need to be localized) might contain
+non-ASCII strings. In such cases, you should use UTF-8, since that is an
+encoding understood by most tools able to handle more than just ASCII.
+
+Hex encoding is also OK, and encouraged where it enhances readability — for
+example, `"\uFEFF"`, is the Unicode zero-width no-break space character, which
+would be invisible if included in the source as straight UTF-8.
+
+
+Spaces vs. Tabs ~
+
+Use only spaces, and indent 2 spaces at a time. Do not use tabs in your code.
+
+
+Function Declarations and Definitions ~
+
+Return type on the same line as function name, parameters on the same line if
+they fit.
+
+Functions look like this: >
+
+ ReturnType function_name(Type par_name1, Type par_name2)
+ {
+ do_something();
+ ...
+ }
+
+If you have too much text to fit on one line: >
+
+ ReturnType really_long_function_name(Type par_name1, Type par_name2,
+ Type par_name3)
+ {
+ do_something();
+ ...
+ }
+
+or if you cannot fit even the first parameter (but only then): >
+
+ ReturnType really_really_really_long_function_name(
+ Type par_name1, // 4 space indent
+ Type par_name2,
+ Type par_name3)
+ {
+ do_something(); // 2 space indent
+ ...
+ }
+
+Some points to note:
+
+- The open parenthesis is always on the same line as the function name.
+- There is never a space between the function name and the open parenthesis.
+- There is never a space between the parentheses and the parameters.
+- The open curly brace is always on the next line.
+- The close curly brace is always on the last line by itself.
+- There should be a space between the close parenthesis and the open curly
+ brace.
+- All parameters should be named, with identical names in the declaration and
+ implementation.
+- All parameters should be aligned if possible.
+- Default indentation is 2 spaces.
+- Wrapped parameters have a 4 space indent.
+
+
+Function Calls ~
+
+On one line if it fits; otherwise, wrap arguments at the parenthesis.
+
+Function calls have the following format: >
+
+ bool retval = do_something(argument1, argument2, argument3);
+
+If the arguments do not all fit on one line, they should be broken up onto
+multiple lines, with each subsequent line aligned with the first argument. Do
+not add spaces after the open paren or before the close paren: >
+
+ bool retval = do_something(averyveryveryverylongargument1,
+ argument2, argument3);
+
+If the function has many arguments, consider having one per line if this makes
+the code more readable: >
+
+ bool retval = do_something(argument1,
+ argument2,
+ argument3,
+ argument4);
+
+Arguments may optionally all be placed on subsequent lines, with one line per
+argument: >
+
+ if (...) {
+ ...
+ ...
+ if (...) {
+ do_something(
+ argument1, // 4 space indent
+ argument2,
+ argument3,
+ argument4);
+ }
+
+In particular, this should be done if the function signature is so long that
+it cannot fit within the maximum line length.
+
+
+Braced Initializer Lists ~
+
+Format a braced list exactly like you would format a function call in its
+place but with one space after the `{` and one space before the `}`
+
+If the braced list follows a name (e.g. a type or variable name), format as if
+the `{}` were the parentheses of a function call with that name. If there is
+no name, assume a zero-length name. >
+
+ struct my_struct m = { // Here, you could also break before {.
+ superlongvariablename1,
+ superlongvariablename2,
+ { short, interior, list },
+ { interiorwrappinglist,
+ interiorwrappinglist2 } };
+
+
+Conditionals ~
+
+Don't use spaces inside parentheses. Always use curly braces. >
+
+ if (condition) { // no spaces inside parentheses
+ ... // 2 space indent.
+ } else if (...) { // The else goes on the same line as the closing brace.
+ ...
+ } else {
+ ...
+ }
+
+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`.
+
+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
+warn you if any values are not handled). If the default case should never
+execute, simply `assert`: >
+
+ switch (var) {
+ case 0: // 2 space indent
+ ... // 4 space indent
+ break;
+ case 1:
+ ...
+ break;
+ default:
+ 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
+spaces.
+
+The following are examples of correctly-formatted pointer and reference
+expressions: >
+
+ x = *p;
+ p = &x;
+ x = r.y;
+ x = r->y;
+
+Note that:
+
+ - There are no spaces around the period or arrow when accessing a member.
+ - Pointer operators have no space after the * or &.
+
+When declaring a pointer variable or argument, place the asterisk adjacent to
+the variable name: >
+
+ char *c;
+
+ char * c; // BAD: spaces on both sides of *
+ char* c; // BAD
+
+
+Boolean Expressions ~
+
+When you have a boolean expression that is longer than the standard line
+length, keep operators at the start of the line. >
+
+ if (this_one_thing > this_other_thing
+ && a_third_thing == a_fourth_thing
+ && yet_another && last_one) {
+ ...
+ }
+
+Also note that you should always use the punctuation operators, such as `&&`
+and `~`, rather than the word operators, such as `and` and `compl`.
+
+
+Return Values ~
+
+Do not needlessly surround the `return` expression with parentheses.
+
+Use parentheses in `return expr`; only where you would use them in `x =
+expr;`. >
+
+ return result;
+ return (some_long_condition && another_condition);
+
+ return (value); // You wouldn't write var = (value);
+ 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
+whitespace at the end of a line.
+
+ General ~
+>
+ if (x) { // Open braces should always have a space before them.
+ ...
+ }
+ int i = 0; // Semicolons usually have no space before them.
+ int x[] = { 0 }; // Spaces inside braces for braced-init-list.
+<
+
+ Variables ~
+>
+ int long_variable = 0; // Don't align assignments.
+ int i = 1;
+
+ struct my_struct { // Exception: struct arrays.
+ const char *boy;
+ const char *girl;
+ int pos;
+ } my_variable[] = {
+ { "Mia", "Michael", 8 },
+ { "Elizabeth", "Aiden", 10 },
+ { "Emma", "Mason", 2 },
+ };
+<
+
+ Macros ~
+>
+ #define FI(x) \ // Don't align \'s in macro definitions.
+ foo(); \
+ bar(); \
+ ...
+<
+
+ Loops and Conditionals ~
+>
+ if (b) { // Space after the keyword in condition.
+ } else { // Spaces around else.
+ }
+ while (test) {} // There is usually no space inside parentheses.
+ for (; i < 5; i++) { // For loops always have a space after the
+ ... // semicolon and no a space before the
+ ... // semicolon.
+ }
+ switch (i) {
+ case 1: // No space before colon in a switch case.
+ ...
+ case 2: break; // Space after a colon if there's code after it.
+<
+
+ Operators ~
+>
+ x = 0; // Assignment operators always have spaces around
+ // them.
+ x = -5; // No spaces separating unary operators and their
+ x++; // arguments.
+ if (x && !y)
+ ...
+ v = w*x + y/z; // Use spaces to indicate operator precedence.
+ v = w * (x + z); // Parentheses should have no spaces inside them.
+ i = (int)d; // No spaces after a cast operator.
+<
+
+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
+use your judgment. But in general, minimize use of vertical whitespace.
+
+
+==============================================================================
+Parting Words
+
+The style guide is intended to make the code more readable. If you think you
+must violate its rules for the sake of clarity, do it! But please add a note
+to your pull request explaining your reasoning.
+
+
+ vim:tw=78:ts=8:et:ft=help:norl:
diff --git a/runtime/doc/develop.txt b/runtime/doc/develop.txt
index aec0178da2..14f35acce3 100644
--- a/runtime/doc/develop.txt
+++ b/runtime/doc/develop.txt
@@ -46,7 +46,7 @@ NVIM IS... WELL DOCUMENTED *design-documented*
item is easier to find.
-NVIM IS... HIGH SPEED AND SMALL IN SIZE *design-speed-size*
+NVIM IS... FAST AND SMALL *design-speed-size*
Keep Nvim small and fast.
- Computers are becoming faster and bigger each year. Vim can grow too, but
@@ -127,14 +127,20 @@ Sometimes a GUI or other application may want to force a provider to
DOCUMENTATION *dev-doc*
-- Do not prefix help tags with "nvim-". Use |vim_diff.txt| to document
- differences from Vim; no other distinction is necessary.
-- If a Vim feature is removed, delete its help section and move its tag to
- |vim_diff.txt|.
-- Move deprecated features to |deprecated.txt|.
+- "Just say it". Avoid mushy, colloquial phrasing in all documentation
+ (docstrings, user manual, website materials, newsletters, …). Don't mince
+ words. Personality and flavor, used sparingly, are welcome--but in general,
+ optimize for the reader's time and energy: be "precise yet concise".
+ - Prefer the active voice: "Foo does X", not "X is done by Foo".
+- Vim differences:
+ - Do not prefix help tags with "nvim-". Use |vim_diff.txt| to catalog
+ differences from Vim; no other distinction is necessary.
+ - If a Vim feature is removed, delete its help section and move its tag to
+ |vim_diff.txt|.
+- Mention deprecated features in |deprecated.txt| and delete their old doc.
- Use consistent language.
- - "terminal" in a help tag always means "the embedded terminal emulator", not
- "the user host terminal".
+ - "terminal" in a help tag always means "the embedded terminal emulator",
+ not "the user host terminal".
- Use "tui-" to prefix help tags related to the host terminal, and "TUI"
in prose if possible.
- Docstrings: do not start parameter descriptions with "The" or "A" unless it
@@ -191,8 +197,8 @@ definitions. The |lua-vim| :help is generated from the docstrings.
Docstring format:
- Lines in the main description start with `---`
-- Special tokens start with `--@` followed by the token name:
- `--@see`, `--@param`, `--@returns`
+- Special tokens start with `---@` followed by the token name:
+ `---@see`, `---@param`, `---@returns`
- Limited markdown is supported.
- List-items start with `-` (useful to nest or "indent")
- Use `<pre>` for code samples.
@@ -211,24 +217,24 @@ vim.paste in src/nvim/lua/vim.lua like this: >
--- end)()
--- </pre>
---
- --@see |paste|
+ ---@see |paste|
---
- --@param lines ...
- --@param phase ...
- --@returns false if client should cancel the paste.
+ ---@param lines ...
+ ---@param phase ...
+ ---@returns false if client should cancel the paste.
LUA *dev-lua*
- Keep the core Lua modules |lua-stdlib| simple. Avoid elaborate OOP or
pseudo-OOP designs. Plugin authors just want functions to call, they don't
- want to learn a big, fancy inheritance hierarchy. So we should avoid complex
- objects: tables are usually better.
+ want to learn a big, fancy inheritance hierarchy. Thus avoid specialized
+ objects; tables or values are usually better.
API *dev-api*
-Use this template to name new API functions:
+Use this template to name new RPC |API| functions:
nvim_{thing}_{action}_{arbitrary-qualifiers}
If the function acts on an object then {thing} is the name of that object
@@ -356,4 +362,19 @@ External UIs are expected to implement these common features:
published in this event. See also "mouse_on", "mouse_off".
+NAMING *dev-naming*
+
+Naming is important. Consistent naming in the API and UI helps both users and
+developers discover and intuitively understand related concepts ("families"),
+and reduces cognitive burden. Discoverability encourages code re-use and
+likewise avoids redundant, overlapping mechanisms, which reduces code
+surface-area, and thereby minimizes bugs...
+
+Naming conventions ~
+
+Use the "on_" prefix to name event handlers and also the interface for
+"registering" such handlers (on_key). The dual nature is acceptable to avoid
+a confused collection of naming conventions for these related concepts.
+
+
vim:tw=78:ts=8:noet:ft=help:norl:
diff --git a/runtime/doc/diagnostic.txt b/runtime/doc/diagnostic.txt
new file mode 100644
index 0000000000..679bb2f7ff
--- /dev/null
+++ b/runtime/doc/diagnostic.txt
@@ -0,0 +1,562 @@
+*diagnostic.txt* Diagnostics
+
+
+ NVIM REFERENCE MANUAL
+
+
+Diagnostic framework *vim.diagnostic*
+
+Nvim provides a framework for displaying errors or warnings from external
+tools, otherwise known as "diagnostics". These diagnostics can come from a
+variety of sources, such as linters or LSP servers. The diagnostic framework
+is an extension to existing error handling functionality such as the
+|quickfix| list.
+
+ Type |gO| to see the table of contents.
+
+==============================================================================
+QUICKSTART *diagnostic-quickstart*
+
+Anything that reports diagnostics is referred to below as a "diagnostic
+producer". Diagnostic producers need only follow a few simple steps to
+report diagnostics:
+
+1. Create a namespace |nvim_create_namespace()|. Note that the namespace must
+ have a name. Anonymous namespaces WILL NOT WORK.
+2. (Optional) Configure options for the diagnostic namespace
+ |vim.diagnostic.config()|.
+3. Generate diagnostics.
+4. Set the diagnostics for the buffer |vim.diagnostic.set()|.
+5. Repeat from step 3.
+
+Generally speaking, the API is split between functions meant to be used by
+diagnostic producers and those meant for diagnostic consumers (i.e. end users
+who want to read and view the diagnostics for a buffer). The APIs for
+producers require a {namespace} as their first argument, while those for
+consumers generally do not require a namespace (though often one may be
+optionally supplied). A good rule of thumb is that if a method is meant to
+modify the diagnostics for a buffer (e.g. |vim.diagnostic.set()|) then it
+requires a namespace.
+
+ *diagnostic-structure*
+A diagnostic is a Lua table with the following keys:
+
+ lnum: The starting line of the diagnostic
+ end_lnum: The final line of the diagnostic
+ col: The starting column of the diagnostic
+ end_col: The final column of the diagnostic
+ severity: The severity of the diagnostic |vim.diagnostic.severity|
+ message: The diagnostic text
+ source: The source of the diagnostic
+
+Diagnostics use the same indexing as the rest of the Nvim API (i.e. 0-based
+rows and columns). |api-indexing|
+
+ *vim.diagnostic.severity* *diagnostic-severity*
+The "severity" key in a diagnostic is one of the values defined in
+`vim.diagnostic.severity`:
+
+ vim.diagnostic.severity.ERROR
+ vim.diagnostic.severity.WARN
+ vim.diagnostic.severity.INFO
+ vim.diagnostic.severity.HINT
+
+Functions that take a severity as an optional parameter (e.g.
+|vim.diagnostic.get()|) accept one of two forms:
+
+1. A single |vim.diagnostic.severity| value: >
+
+ vim.diagnostic.get(0, { severity = vim.diagnostic.severity.WARN })
+
+2. A table with a "min" or "max" key (or both): >
+
+ vim.diagnostic.get(0, { severity = {min=vim.diagnostic.severity.WARN})
+
+The latter form allows users to specify a range of severities.
+
+==============================================================================
+HIGHLIGHTS *diagnostic-highlights*
+
+All highlights defined for diagnostics begin with `Diagnostic` followed by
+the type of highlight (e.g., `Sign`, `Underline`, etc.) and the severity (e.g.
+`Error`, `Warn`, etc.)
+
+Sign, underline and virtual text highlights (by default) are linked to their
+corresponding default highlight.
+
+For example, the default highlighting for |hl-DiagnosticSignError| is linked
+to |hl-DiagnosticError|. To change the default (and therefore the linked
+highlights), use the |:highlight| command: >
+
+ highlight DiagnosticError guifg="BrightRed"
+<
+ *hl-DiagnosticError*
+DiagnosticError
+ Used as the base highlight group.
+ Other Diagnostic highlights link to this by default (except Underline)
+
+ *hl-DiagnosticWarn*
+DiagnosticWarn
+ Used as the base highlight group.
+ Other Diagnostic highlights link to this by default (except Underline)
+
+ *hl-DiagnosticInfo*
+DiagnosticInfo
+ Used as the base highlight group.
+ Other Diagnostic highlights link to this by default (except Underline)
+
+ *hl-DiagnosticHint*
+DiagnosticHint
+ Used as the base highlight group.
+ Other Diagnostic highlights link to this by default (except Underline)
+
+ *hl-DiagnosticVirtualTextError*
+DiagnosticVirtualTextError
+ Used for "Error" diagnostic virtual text.
+
+ *hl-DiagnosticVirtualTextWarn*
+DiagnosticVirtualTextWarn
+ Used for "Warn" diagnostic virtual text.
+
+ *hl-DiagnosticVirtualTextInfo*
+DiagnosticVirtualTextInfo
+ Used for "Info" diagnostic virtual text.
+
+ *hl-DiagnosticVirtualTextHint*
+DiagnosticVirtualTextHint
+ Used for "Hint" diagnostic virtual text.
+
+ *hl-DiagnosticUnderlineError*
+DiagnosticUnderlineError
+ Used to underline "Error" diagnostics.
+
+ *hl-DiagnosticUnderlineWarn*
+DiagnosticUnderlineWarn
+ Used to underline "Warn" diagnostics.
+
+ *hl-DiagnosticUnderlineInfo*
+DiagnosticUnderlineInfo
+ Used to underline "Info" diagnostics.
+
+ *hl-DiagnosticUnderlineHint*
+DiagnosticUnderlineHint
+ Used to underline "Hint" diagnostics.
+
+ *hl-DiagnosticFloatingError*
+DiagnosticFloatingError
+ Used to color "Error" diagnostic messages in diagnostics float.
+ See |vim.diagnostic.show_line_diagnostics()|
+
+ *hl-DiagnosticFloatingWarn*
+DiagnosticFloatingWarn
+ Used to color "Warn" diagnostic messages in diagnostics float.
+
+ *hl-DiagnosticFloatingInfo*
+DiagnosticFloatingInfo
+ Used to color "Info" diagnostic messages in diagnostics float.
+
+ *hl-DiagnosticFloatingHint*
+DiagnosticFloatingHint
+ Used to color "Hint" diagnostic messages in diagnostics float.
+
+ *hl-DiagnosticSignError*
+DiagnosticSignError
+ Used for "Error" signs in sign column.
+
+ *hl-DiagnosticSignWarn*
+DiagnosticSignWarn
+ Used for "Warn" signs in sign column.
+
+ *hl-DiagnosticSignInfo*
+DiagnosticSignInfo
+ Used for "Info" signs in sign column.
+
+ *hl-DiagnosticSignHint*
+DiagnosticSignHint
+ Used for "Hint" signs in sign column.
+
+==============================================================================
+SIGNS *diagnostic-signs*
+
+Signs are defined for each diagnostic severity. The default text for each sign
+is the first letter of the severity name (for example, "E" for ERROR). Signs
+can be customized using the following: >
+
+ sign define DiagnosticSignError text=E texthl=DiagnosticSignError linehl= numhl=
+ sign define DiagnosticSignWarn text=W texthl=DiagnosticSignWarn linehl= numhl=
+ sign define DiagnosticSignInfo text=I texthl=DiagnosticSignInfo linehl= numhl=
+ sign define DiagnosticSignHint text=H texthl=DiagnosticSignHint linehl= numhl=
+
+When the "severity_sort" option is set (see |vim.diagnostic.config()|) the
+priority of each sign depends on the severity of the associated diagnostic.
+Otherwise, all signs have the same priority (the value of the "priority"
+option in the "signs" table of |vim.diagnostic.config()| or 10 if unset).
+
+==============================================================================
+EVENTS *diagnostic-events*
+
+ *DiagnosticsChanged*
+DiagnosticsChanged After diagnostics have changed.
+
+Example: >
+ autocmd User DiagnosticsChanged lua vim.diagnostic.setqflist({open = false })
+<
+
+==============================================================================
+Lua module: vim.diagnostic *diagnostic-api*
+
+config({opts}, {namespace}) *vim.diagnostic.config()*
+ Configure diagnostic options globally or for a specific
+ diagnostic namespace.
+
+ Note:
+ Each of the configuration options below accepts one of the
+ following:
+ • `false` : Disable this feature
+ • `true` : Enable this feature, use default settings.
+ • `table` : Enable this feature with overrides.
+ • `function` : Function with signature (namespace, bufnr)
+ that returns any of the above.
+
+ Parameters: ~
+ {opts} table Configuration table with the following
+ keys:
+ • underline: (default true) Use underline for
+ diagnostics. Options:
+ • severity: Only underline diagnostics
+ matching the given severity
+ |diagnostic-severity|
+
+ • virtual_text: (default true) Use virtual
+ text for diagnostics. Options:
+ • severity: Only show virtual text for
+ diagnostics matching the given severity
+ |diagnostic-severity|
+ • source: (string) Include the diagnostic
+ source in virtual text. One of "always"
+ or "if_many".
+ • format: (function) A function that takes
+ a diagnostic as input and returns a
+ string. The return value is the text used
+ to display the diagnostic. Example:>
+
+ function(diagnostic)
+ if diagnostic.severity == vim.diagnostic.severity.ERROR then
+ return string.format("E: %s", diagnostic.message)
+ end
+ return diagnostic.message
+ end
+<
+
+ • signs: (default true) Use signs for
+ diagnostics. Options:
+ • severity: Only show signs for diagnostics
+ matching the given severity
+ |diagnostic-severity|
+
+ • update_in_insert: (default false) Update
+ diagnostics in Insert mode (if false,
+ diagnostics are updated on InsertLeave)
+ • severity_sort: (default false) Sort
+ diagnostics by severity. This affects the
+ order in which signs and virtual text are
+ displayed. When true, higher severities are
+ displayed before lower severities (e.g.
+ ERROR is displayed before WARN). Options:
+ • reverse: (boolean) Reverse sort order
+ {namespace} number|nil Update the options for the given
+ namespace. When omitted, update the global
+ diagnostic options.
+
+disable({bufnr}, {namespace}) *vim.diagnostic.disable()*
+ Disable diagnostics in the given buffer.
+
+ Parameters: ~
+ {bufnr} number|nil Buffer number. Defaults to the
+ current buffer.
+ {namespace} number|nil Only disable diagnostics for the
+ given namespace.
+
+enable({bufnr}, {namespace}) *vim.diagnostic.enable()*
+ Enable diagnostics in the given buffer.
+
+ Parameters: ~
+ {bufnr} number|nil Buffer number. Defaults to the
+ current buffer.
+ {namespace} number|nil Only enable diagnostics for the
+ given namespace.
+
+fromqflist({list}) *vim.diagnostic.fromqflist()*
+ Convert a list of quickfix items to a list of diagnostics.
+
+ Parameters: ~
+ {list} table A list of quickfix items from |getqflist()|
+ or |getloclist()|.
+
+ Return: ~
+ array of diagnostics |diagnostic-structure|
+
+get({bufnr}, {opts}) *vim.diagnostic.get()*
+ Get current diagnostics.
+
+ Parameters: ~
+ {bufnr} number|nil Buffer number to get diagnostics from.
+ Use 0 for current buffer or nil for all buffers.
+ {opts} table|nil A table with the following keys:
+ • namespace: (number) Limit diagnostics to the
+ given namespace.
+ • lnum: (number) Limit diagnostics to the given
+ line number.
+ • severity: See |diagnostic-severity|.
+
+ Return: ~
+ table A list of diagnostic items |diagnostic-structure|.
+
+get_next({opts}) *vim.diagnostic.get_next()*
+ Get the next diagnostic closest to the cursor position.
+
+ Parameters: ~
+ {opts} table See |vim.diagnostic.goto_next()|
+
+ Return: ~
+ table Next diagnostic
+
+get_next_pos({opts}) *vim.diagnostic.get_next_pos()*
+ Return the position of the next diagnostic in the current
+ buffer.
+
+ Parameters: ~
+ {opts} table See |vim.diagnostic.goto_next()|
+
+ Return: ~
+ table Next diagnostic position as a (row, col) tuple.
+
+get_prev({opts}) *vim.diagnostic.get_prev()*
+ Get the previous diagnostic closest to the cursor position.
+
+ Parameters: ~
+ {opts} table See |vim.diagnostic.goto_next()|
+
+ Return: ~
+ table Previous diagnostic
+
+get_prev_pos({opts}) *vim.diagnostic.get_prev_pos()*
+ Return the position of the previous diagnostic in the current
+ buffer.
+
+ Parameters: ~
+ {opts} table See |vim.diagnostic.goto_next()|
+
+ Return: ~
+ table Previous diagnostic position as a (row, col) tuple.
+
+goto_next({opts}) *vim.diagnostic.goto_next()*
+ Move to the next diagnostic.
+
+ Parameters: ~
+ {opts} table|nil Configuration table with the following
+ keys:
+ • namespace: (number) Only consider diagnostics
+ from the given namespace.
+ • cursor_position: (cursor position) Cursor
+ position as a (row, col) tuple. See
+ |nvim_win_get_cursor()|. Defaults to the current
+ cursor position.
+ • wrap: (boolean, default true) Whether to loop
+ around file or not. Similar to 'wrapscan'.
+ • severity: See |diagnostic-severity|.
+ • enable_popup: (boolean, default true) Call
+ |vim.diagnostic.show_line_diagnostics()| on
+ jump.
+ • popup_opts: (table) Table to pass as {opts}
+ parameter to
+ |vim.diagnostic.show_line_diagnostics()|
+ • win_id: (number, default 0) Window ID
+
+goto_prev({opts}) *vim.diagnostic.goto_prev()*
+ Move to the previous diagnostic in the current buffer.
+
+ Parameters: ~
+ {opts} table See |vim.diagnostic.goto_next()|
+
+hide({namespace}, {bufnr}) *vim.diagnostic.hide()*
+ Hide currently displayed diagnostics.
+
+ This only clears the decorations displayed in the buffer.
+ Diagnostics can be redisplayed with |vim.diagnostic.show()|.
+ To completely remove diagnostics, use
+ |vim.diagnostic.reset()|.
+
+ To hide diagnostics and prevent them from re-displaying, use
+ |vim.diagnostic.disable()|.
+
+ Parameters: ~
+ {namespace} number The diagnostic namespace
+ {bufnr} number|nil Buffer number. Defaults to the
+ current buffer.
+
+ *vim.diagnostic.match()*
+match({str}, {pat}, {groups}, {severity_map}, {defaults})
+ Parse a diagnostic from a string.
+
+ For example, consider a line of output from a linter: >
+
+ WARNING filename:27:3: Variable 'foo' does not exist
+
+ < This can be parsed into a diagnostic |diagnostic-structure|
+ with: >
+
+ local s = "WARNING filename:27:3: Variable 'foo' does not exist"
+ local pattern = "^(%w+) %w+:(%d+):(%d+): (.+)$"
+ local groups = {"severity", "lnum", "col", "message"}
+ vim.diagnostic.match(s, pattern, groups, {WARNING = vim.diagnostic.WARN})
+<
+
+ Parameters: ~
+ {str} string String to parse diagnostics from.
+ {pat} string Lua pattern with capture groups.
+ {groups} table List of fields in a
+ |diagnostic-structure| to associate with
+ captures from {pat}.
+ {severity_map} table A table mapping the severity field
+ from {groups} with an item from
+ |vim.diagnostic.severity|.
+ {defaults} table|nil Table of default values for any
+ fields not listed in {groups}. When
+ omitted, numeric values default to 0 and
+ "severity" defaults to ERROR.
+
+ Return: ~
+ diagnostic |diagnostic-structure| or `nil` if {pat} fails
+ to match {str}.
+
+reset({namespace}, {bufnr}) *vim.diagnostic.reset()*
+ Remove all diagnostics from the given namespace.
+
+ Unlike |vim.diagnostic.hide()|, this function removes all
+ saved diagnostics. They cannot be redisplayed using
+ |vim.diagnostic.show()|. To simply remove diagnostic
+ decorations in a way that they can be re-displayed, use
+ |vim.diagnostic.hide()|.
+
+ Parameters: ~
+ {namespace} number
+ {bufnr} number|nil Remove diagnostics for the given
+ buffer. When omitted, diagnostics are removed
+ for all buffers.
+
+set({namespace}, {bufnr}, {diagnostics}, {opts}) *vim.diagnostic.set()*
+ Set diagnostics for the given namespace and buffer.
+
+ Parameters: ~
+ {namespace} number The diagnostic namespace
+ {bufnr} number Buffer number
+ {diagnostics} table A list of diagnostic items
+ |diagnostic-structure|
+ {opts} table|nil Display options to pass to
+ |vim.diagnostic.show()|
+
+setloclist({opts}) *vim.diagnostic.setloclist()*
+ Add buffer diagnostics to the location list.
+
+ Parameters: ~
+ {opts} table|nil Configuration table with the following
+ keys:
+ • namespace: (number) Only add diagnostics from
+ the given namespace.
+ • winnr: (number, default 0) Window number to set
+ location list for.
+ • open: (boolean, default true) Open the location
+ list after setting.
+ • title: (string) Title of the location list.
+ Defaults to "Diagnostics".
+ • severity: See |diagnostic-severity|.
+
+setqflist({opts}) *vim.diagnostic.setqflist()*
+ Add all diagnostics to the quickfix list.
+
+ Parameters: ~
+ {opts} table|nil Configuration table with the following
+ keys:
+ • namespace: (number) Only add diagnostics from
+ the given namespace.
+ • open: (boolean, default true) Open quickfix list
+ after setting.
+ • title: (string) Title of quickfix list. Defaults
+ to "Diagnostics".
+ • severity: See |diagnostic-severity|.
+
+ *vim.diagnostic.show()*
+show({namespace}, {bufnr}, {diagnostics}, {opts})
+ Display diagnostics for the given namespace and buffer.
+
+ Parameters: ~
+ {namespace} number Diagnostic namespace
+ {bufnr} number|nil Buffer number. Defaults to the
+ current buffer.
+ {diagnostics} table|nil The diagnostics to display. When
+ omitted, use the saved diagnostics for the
+ given namespace and buffer. This can be
+ used to display a list of diagnostics
+ without saving them or to display only a
+ subset of diagnostics.
+ {opts} table|nil Display options. See
+ |vim.diagnostic.config()|.
+
+ *vim.diagnostic.show_line_diagnostics()*
+show_line_diagnostics({opts}, {bufnr}, {lnum})
+ Open a floating window with the diagnostics from the given
+ line.
+
+ Parameters: ~
+ {opts} table Configuration table. See
+ |vim.diagnostic.show_position_diagnostics()|.
+ {bufnr} number|nil Buffer number. Defaults to the current
+ buffer.
+ {lnum} number|nil Line number. Defaults to line number
+ of cursor.
+
+ Return: ~
+ tuple ({popup_bufnr}, {win_id})
+
+ *vim.diagnostic.show_position_diagnostics()*
+show_position_diagnostics({opts}, {bufnr}, {position})
+ Open a floating window with the diagnostics at the given
+ position.
+
+ Parameters: ~
+ {opts} table|nil Configuration table with the same
+ keys as |vim.lsp.util.open_floating_preview()|
+ in addition to the following:
+ • namespace: (number) Limit diagnostics to the
+ given namespace
+ • severity: See |diagnostic-severity|.
+ • show_header: (boolean, default true) Show
+ "Diagnostics:" header
+ • source: (string) Include the diagnostic
+ source in the message. One of "always" or
+ "if_many".
+ • format: (function) A function that takes a
+ diagnostic as input and returns a string.
+ The return value is the text used to display
+ the diagnostic.
+ {bufnr} number|nil Buffer number. Defaults to the
+ current buffer.
+ {position} table|nil The (0,0)-indexed position. Defaults
+ to the current cursor position.
+
+ Return: ~
+ tuple ({popup_bufnr}, {win_id})
+
+toqflist({diagnostics}) *vim.diagnostic.toqflist()*
+ Convert a list of diagnostics to a list of quickfix items that
+ can be passed to |setqflist()| or |setloclist()|.
+
+ Parameters: ~
+ {diagnostics} table List of diagnostics
+ |diagnostic-structure|.
+
+ Return: ~
+ array of quickfix list items |setqflist-what|
+
+ vim:tw=78:ts=8:ft=help:norl:
diff --git a/runtime/doc/diff.txt b/runtime/doc/diff.txt
index a9e2a0d522..6115a5d235 100644
--- a/runtime/doc/diff.txt
+++ b/runtime/doc/diff.txt
@@ -334,9 +334,11 @@ between file1 and file2: >
The ">" is replaced with the value of 'shellredir'.
-The output of "diff" must be a normal "ed" style diff or a unified diff. Do
-NOT use a context diff. This example explains the format that Vim expects for
-the "ed" style diff: >
+The output of "diff" must be a normal "ed" style diff or a unified diff. A
+context diff will NOT work. For a unified diff no context lines can be used.
+Using "diff -u" will NOT work, use "diff -U0".
+
+This example explains the format that Vim expects for the "ed" style diff: >
1a2
> bbb
diff --git a/runtime/doc/digraph.txt b/runtime/doc/digraph.txt
index b7dc16341d..dd7e9a331a 100644
--- a/runtime/doc/digraph.txt
+++ b/runtime/doc/digraph.txt
@@ -165,7 +165,7 @@ ROUBLE
The rouble sign was added in 2014 as 0x20bd. Vim supports the digraphs =R and
=P for this. Note that R= and P= are other characters.
- *digraph-table*
+ *digraph-table* *digraph-table-mbyte*
char digraph hex dec official name ~
^@ NU 0x00 0 NULL (NUL)
^A SH 0x01 1 START OF HEADING (SOH)
@@ -341,12 +341,6 @@ $ DO 0x24 36 DOLLAR SIGN
ý y' 0xfd 253 LATIN SMALL LETTER Y WITH ACUTE
þ th 0xfe 254 LATIN SMALL LETTER THORN (Icelandic)
ÿ y: 0xff 255 LATIN SMALL LETTER Y WITH DIAERESIS
-
-If your Vim is compiled with |multibyte| support and you are using a multibyte
-'encoding', Vim provides this enhanced set of additional digraphs:
-
- *digraph-table-mbyte*
-char digraph hex dec official name ~
Ā A- 0100 0256 LATIN CAPITAL LETTER A WITH MACRON
ā a- 0101 0257 LATIN SMALL LETTER A WITH MACRON
Ă A( 0102 0258 LATIN CAPITAL LETTER A WITH BREVE
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index bf7f2b21de..d6f72b68f7 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -14,18 +14,17 @@ Using expressions is introduced in chapter 41 of the user manual |usr_41.txt|.
1. Variables *variables*
1.1 Variable types ~
- *E712*
-There are six types of variables:
+ *E712* *E896* *E897* *E899*
+There are seven types of variables:
*Number* *Integer*
Number A 32 or 64 bit signed number. |expr-number|
The number of bits is available in |v:numbersize|.
- Examples: -123 0x10 0177 0b1011
+ Examples: -123 0x10 0177 0o177 0b1011
Float A floating point number. |floating-point-format| *Float*
Examples: 123.456 1.15e-6 -1.1e3
- *E928*
String A NUL terminated string of 8-bit unsigned characters (bytes).
|expr-string| Examples: "ab\txx\"--" 'x-z''a,c'
@@ -35,7 +34,7 @@ Funcref A reference to a function |Funcref|.
like a Partial.
Example: function("Callback", [arg], myDict)
-List An ordered sequence of items |List|.
+List An ordered sequence of items, see |List| for details.
Example: [1, 2, ['a', 'b']]
Dictionary An associative, unordered array: Each entry has a key and a
@@ -44,6 +43,11 @@ Dictionary An associative, unordered array: Each entry has a key and a
{'blue': "#0000ff", 'red': "#ff0000"}
#{blue: "#0000ff", red: "#ff0000"}
+Blob Binary Large Object. Stores any sequence of bytes. See |Blob|
+ for details.
+ Example: 0zFF00ED015DAF
+ 0z is an empty Blob.
+
The Number and String types are converted automatically, depending on how they
are used.
@@ -54,14 +58,15 @@ the Number. Examples:
Number -1 --> String "-1" ~
*octal*
Conversion from a String to a Number is done by converting the first digits to
-a number. Hexadecimal "0xf9", Octal "017", and Binary "0b10" numbers are
-recognized. If the String doesn't start with digits, the result is zero.
-Examples:
+a number. Hexadecimal "0xf9", Octal "017" or "0o17", and Binary "0b10"
+numbers are recognized. If the String doesn't start with digits, the result
+is zero. Examples:
String "456" --> Number 456 ~
String "6bar" --> Number 6 ~
String "foo" --> Number 0 ~
String "0xf1" --> Number 241 ~
String "0100" --> Number 64 ~
+ String "0o100" --> Number 64 ~
String "0b101" --> Number 5 ~
String "-8" --> Number -8 ~
String "+8" --> Number 0 ~
@@ -97,6 +102,7 @@ Note that " " and "0" are also non-empty strings, thus considered to be TRUE.
A List, Dictionary or Float is not a Number or String, thus evaluate to FALSE.
*E745* *E728* *E703* *E729* *E730* *E731*
+ *E974* *E975* *E976*
|List|, |Dictionary|, |Funcref|, and |Blob| types are not automatically
converted.
@@ -366,8 +372,8 @@ Changing the order of items in a list: >
For loop ~
-The |:for| loop executes commands for each item in a list. A variable is set
-to each item in the list in sequence. Example: >
+The |:for| loop executes commands for each item in a |List| or |Blob|.
+A variable is set to each item in the sequence. Example with a List: >
:for item in mylist
: call Doit(item)
:endfor
@@ -400,6 +406,8 @@ It is also possible to put remaining items in a List variable: >
: endif
:endfor
+For a Blob one byte at a time is used.
+
List functions ~
*E714*
@@ -578,7 +586,7 @@ It is not necessary to use the "dict" attribute for a numbered function.
If you get an error for a numbered function, you can find out what it is with
a trick. Assuming the function is 42, the command is: >
- :function {42}
+ :function g:42
Functions for Dictionaries ~
@@ -594,7 +602,137 @@ Functions that can be used with a Dictionary: >
:call map(dict, '">> " . v:val') " prepend ">> " to each item
-1.5 More about variables ~
+1.5 Blobs ~
+ *blob* *Blob* *Blobs* *E978*
+A Blob is a binary object. It can be used to read an image from a file and
+send it over a channel, for example.
+
+A Blob mostly behaves like a |List| of numbers, where each number has the
+value of an 8-bit byte, from 0 to 255.
+
+
+Blob creation ~
+
+A Blob can be created with a |blob-literal|: >
+ :let b = 0zFF00ED015DAF
+Dots can be inserted between bytes (pair of hex characters) for readability,
+they don't change the value: >
+ :let b = 0zFF00.ED01.5DAF
+
+A blob can be read from a file with |readfile()| passing the {type} argument
+set to "B", for example: >
+ :let b = readfile('image.png', 'B')
+
+
+Blob index ~
+ *blob-index* *E979*
+A byte in the Blob can be accessed by putting the index in square brackets
+after the Blob. Indexes are zero-based, thus the first byte has index zero. >
+ :let myblob = 0z00112233
+ :let byte = myblob[0] " get the first byte: 0x00
+ :let byte = myblob[2] " get the third byte: 0x22
+
+A negative index is counted from the end. Index -1 refers to the last byte in
+the Blob, -2 to the last but one byte, etc. >
+ :let last = myblob[-1] " get the last byte: 0x33
+
+To avoid an error for an invalid index use the |get()| function. When an item
+is not available it returns -1 or the default value you specify: >
+ :echo get(myblob, idx)
+ :echo get(myblob, idx, 999)
+
+
+Blob iteration ~
+
+The |:for| loop executes commands for each byte of a Blob. The loop variable is
+set to each byte in the Blob. Example: >
+ :for byte in 0z112233
+ : call Doit(byte)
+ :endfor
+This calls Doit() with 0x11, 0x22 and 0x33.
+
+
+Blob concatenation ~
+
+Two blobs can be concatenated with the "+" operator: >
+ :let longblob = myblob + 0z4455
+ :let myblob += 0z6677
+
+To change a blob in-place see |blob-modification| below.
+
+
+Part of a blob ~
+
+A part of the Blob can be obtained by specifying the first and last index,
+separated by a colon in square brackets: >
+ :let myblob = 0z00112233
+ :let shortblob = myblob[1:2] " get 0z1122
+ :let shortblob = myblob[2:-1] " get 0z2233
+
+Omitting the first index is similar to zero. Omitting the last index is
+similar to -1. >
+ :let endblob = myblob[2:] " from item 2 to the end: 0z2233
+ :let shortblob = myblob[2:2] " Blob with one byte: 0z22
+ :let otherblob = myblob[:] " make a copy of the Blob
+
+If the first index is beyond the last byte of the Blob or the second byte is
+before the first byte, the result is an empty Blob. There is no error
+message.
+
+If the second index is equal to or greater than the length of the Blob the
+length minus one is used: >
+ :echo myblob[2:8] " result: 0z2233
+
+
+Blob modification ~
+ *blob-modification*
+To change a specific byte of a blob use |:let| this way: >
+ :let blob[4] = 0x44
+
+When the index is just one beyond the end of the Blob, it is appended. Any
+higher index is an error.
+
+To change a sequence of bytes the [:] notation can be used: >
+ let blob[1:3] = 0z445566
+The length of the replaced bytes must be exactly the same as the value
+provided. *E972*
+
+To change part of a blob you can specify the first and last byte to be
+modified. The value must at least have the number of bytes in the range: >
+ :let blob[3:5] = [3, 4, 5]
+
+You can also use the functions |add()|, |remove()| and |insert()|.
+
+
+Blob identity ~
+
+Blobs can be compared for equality: >
+ if blob == 0z001122
+And for equal identity: >
+ if blob is otherblob
+< *blob-identity* *E977*
+When variable "aa" is a Blob and you assign it to another variable "bb", both
+variables refer to the same Blob. Then the "is" operator returns true.
+
+When making a copy using [:] or |copy()| the values are the same, but the
+identity is different: >
+ :let blob = 0z112233
+ :let blob2 = blob
+ :echo blob == blob2
+< 1 >
+ :echo blob is blob2
+< 1 >
+ :let blob3 = blob[:]
+ :echo blob == blob3
+< 1 >
+ :echo blob is blob3
+< 0
+
+Making a copy of a Blob is done with the |copy()| function. Using [:] also
+works, as explained above.
+
+
+1.6 More about variables ~
*more-variables*
If you need to know the type of a variable or expression, use the |type()|
function.
@@ -645,8 +783,9 @@ Expression syntax summary, from least to most significant:
etc. As above, append ? for ignoring case, # for
matching case
- expr5 is expr5 same |List| instance
- expr5 isnot expr5 different |List| instance
+ expr5 is expr5 same |List|, |Dictionary| or |Blob| instance
+ expr5 isnot expr5 different |List|, |Dictionary| or |Blob|
+ instance
|expr5| expr6
expr6 + expr6 ... number addition, list or blob concatenation
@@ -669,12 +808,14 @@ Expression syntax summary, from least to most significant:
expr8[expr1 : expr1] substring of a String or sublist of a |List|
expr8.name entry in a |Dictionary|
expr8(expr1, ...) function call with |Funcref| variable
+ expr8->name(expr1, ...) |method| call
|expr9| number number constant
"string" string constant, backslash is special
'string' string constant, ' is doubled
[expr1, ...] |List|
{expr1: expr1, ...} |Dictionary|
+ #{key: expr1, ...} |Dictionary|
&option option value
(expr1) nested expression
variable internal variable
@@ -815,12 +956,12 @@ Dictionary and arguments, use |get()| to get the function name: >
if get(Part1, 'name') == get(Part2, 'name')
" Part1 and Part2 refer to the same function
-When using "is" or "isnot" with a |List| or a |Dictionary| this checks if the
-expressions are referring to the same |List| or |Dictionary| instance. A copy
-of a |List| is different from the original |List|. When using "is" without
-a |List| or a |Dictionary| it is equivalent to using "equal", using "isnot"
-equivalent to using "not equal". Except that a different type means the
-values are different: >
+Using "is" or "isnot" with a |List|, |Dictionary| or |Blob| checks whether
+the expressions are referring to the same |List|, |Dictionary| or |Blob|
+instance. A copy of a |List| is different from the original |List|. When
+using "is" without a |List|, |Dictionary| or |Blob|, it is equivalent to
+using "equal", using "isnot" is equivalent to using "not equal". Except that
+a different type means the values are different: >
echo 4 == '4'
1
echo 4 is '4'
@@ -939,9 +1080,11 @@ expr8 *expr8*
-----
This expression is either |expr9| or a sequence of the alternatives below,
in any order. E.g., these are all possible:
- expr9[expr1].name
- expr9.name[expr1]
- expr9(expr1, ...)[expr1].name
+ expr8[expr1].name
+ expr8.name[expr1]
+ expr8(expr1, ...)[expr1].name
+ expr8->(expr1, ...)[expr1]
+Evaluation is always from left to right.
expr8[expr1] item of String or |List| *expr-[]* *E111*
@@ -1008,6 +1151,12 @@ just above. Also see |sublist| below. Examples: >
:let l = mylist[4:4] " List with one item
:let l = mylist[:] " shallow copy of a List
+If expr8 is a |Blob| this results in a new |Blob| with the bytes in the
+indexes expr1a and expr1b, inclusive. Examples: >
+ :let b = 0zDEADBEEF
+ :let bs = b[1:2] " 0zADBE
+ :let bs = b[] " copy of 0zDEADBEEF
+
Using expr8[expr1] or expr8[expr1a : expr1b] on a |Funcref| results in an
error.
@@ -1043,6 +1192,36 @@ expr8(expr1, ...) |Funcref| function call
When expr8 is a |Funcref| type variable, invoke the function it refers to.
+expr8->name([args]) method call *method* *->*
+expr8->{lambda}([args])
+
+For methods that are also available as global functions this is the same as: >
+ name(expr8 [, args])
+There can also be methods specifically for the type of "expr8".
+
+This allows for chaining, passing the value that one method returns to the
+next method: >
+ mylist->filter(filterexpr)->map(mapexpr)->sort()->join()
+<
+Example of using a lambda: >
+ GetPercentage->{x -> x * 100}()->printf('%d%%')
+<
+When using -> the |expr7| operators will be applied first, thus: >
+ -1.234->string()
+Is equivalent to: >
+ (-1.234)->string()
+And NOT: >
+ -(1.234->string())
+<
+ *E274*
+"->name(" must not contain white space. There can be white space before the
+"->" and after the "(", thus you can split the lines like this: >
+ mylist
+ \ ->filter(filterexpr)
+ \ ->map(mapexpr)
+ \ ->sort()
+ \ ->join()
+<
*expr9*
number
@@ -1051,7 +1230,7 @@ number number constant *expr-number*
*hex-number* *octal-number* *binary-number*
Decimal, Hexadecimal (starting with 0x or 0X), Binary (starting with 0b or 0B)
-and Octal (starting with 0).
+and Octal (starting with 0, 0o or 0O).
*floating-point-format*
Floating point numbers can be written in two forms:
@@ -1146,6 +1325,14 @@ encodings. Use "\u00ff" to store character 255 correctly as UTF-8.
Note that "\000" and "\x00" force the end of the string.
+blob-literal *blob-literal* *E973*
+------------
+
+Hexadecimal starting with 0z or 0Z, with an arbitrary number of bytes.
+The sequence must be an even number of hex characters. Example: >
+ :let b = 0zFF00ED015DAF
+
+
literal-string *literal-string* *E115*
---------------
'string' string constant *expr-'*
@@ -1283,7 +1470,17 @@ The lambda expression is also useful for jobs and timers: >
Handler called
Handler called
-Note how execute() is used to execute an Ex command. That's ugly though.
+Note that it is possible to cause memory to be used and not freed if the
+closure is referenced by the context it depends on: >
+ function Function()
+ let x = 0
+ let F = {-> x}
+ endfunction
+The closure uses "x" from the function scope, and "F" in that same scope
+refers to the closure. This cycle results in the memory not being freed.
+Recommendation: don't do this.
+
+Notice how execute() is used to execute an Ex command. That's ugly though.
Lambda expressions have internal names like '<lambda>42'. If you get an error
@@ -1641,6 +1838,7 @@ v:event Dictionary of event data for the current |autocommand|. Valid
|v:false| if not.
changed_window Is |v:true| if the the event fired
while changing window (or tab) on |DirChanged|.
+ status Job status or exit code, -1 means "unknown". |TermClose|
*v:exception* *exception-variable*
v:exception The value of the exception most recently caught and not
@@ -1687,7 +1885,8 @@ v:fcs_choice What should happen after a |FileChangedShell| event was
Vim behaves like it is empty, there is no warning message.
*v:fname* *fname-variable*
-v:fname The file name set by 'includeexpr'. Empty otherwise.
+v:fname When evaluating 'includeexpr': the file name that was
+ detected. Empty otherwise.
*v:fname_in* *fname_in-variable*
v:fname_in The name of the input file. Valid while evaluating:
@@ -1821,7 +2020,7 @@ v:null Special value used to put "null" in JSON and NIL in msgpack.
v:numbermax Maximum value of a number.
*v:numbermin* *numbermin-variable*
-v:numbermin Minimum value of a number (negative)
+v:numbermin Minimum value of a number (negative).
*v:numbersize* *numbersize-variable*
v:numbersize Number of bits in a Number. This is normally 64, but on some
@@ -1961,19 +2160,21 @@ v:swapcommand Normal mode command to be executed after a file has been
For ":edit +cmd file" the value is ":cmd\r".
*v:t_TYPE* *v:t_bool* *t_bool-variable*
-v:t_bool Value of Boolean type. Read-only. See: |type()|
+v:t_bool Value of |Boolean| type. Read-only. See: |type()|
*v:t_dict* *t_dict-variable*
-v:t_dict Value of Dictionary type. Read-only. See: |type()|
+v:t_dict Value of |Dictionary| type. Read-only. See: |type()|
*v:t_float* *t_float-variable*
-v:t_float Value of Float type. Read-only. See: |type()|
+v:t_float Value of |Float| type. Read-only. See: |type()|
*v:t_func* *t_func-variable*
-v:t_func Value of Funcref type. Read-only. See: |type()|
+v:t_func Value of |Funcref| type. Read-only. See: |type()|
*v:t_list* *t_list-variable*
-v:t_list Value of List type. Read-only. See: |type()|
+v:t_list Value of |List| type. Read-only. See: |type()|
*v:t_number* *t_number-variable*
-v:t_number Value of Number type. Read-only. See: |type()|
+v:t_number Value of |Number| type. Read-only. See: |type()|
*v:t_string* *t_string-variable*
-v:t_string Value of String type. Read-only. See: |type()|
+v:t_string Value of |String| type. Read-only. See: |type()|
+ *v:t_blob* *t_blob-variable*
+v:t_blob Value of |Blob| type. Read-only. See: |type()|
*v:termresponse* *termresponse-variable*
v:termresponse The escape sequence returned by the terminal for the DA
@@ -2057,7 +2258,7 @@ USAGE RESULT DESCRIPTION ~
abs({expr}) Float or Number absolute value of {expr}
acos({expr}) Float arc cosine of {expr}
-add({list}, {item}) List append {item} to |List| {list}
+add({object}, {item}) List/Blob append {item} to {object}
and({expr}, {expr}) Number bitwise AND
api_info() Dict api metadata
append({lnum}, {string}) Number append {string} below line {lnum}
@@ -2114,7 +2315,7 @@ chanclose({id}[, {stream}]) Number Closes a channel or one of its streams
chansend({id}, {data}) Number Writes {data} to channel
char2nr({expr}[, {utf8}]) Number ASCII/UTF8 value of first char in {expr}
charidx({string}, {idx} [, {countcc}])
- Number char index of byte {idx} in {string}
+ Number char index of byte {idx} in {string}
cindent({lnum}) Number C indent for line {lnum}
clearmatches([{win}]) none clear all matches
col({expr}) Number column nr of cursor or mark
@@ -2144,8 +2345,8 @@ cursor({list}) Number move cursor to position in {list}
debugbreak({pid}) Number interrupt process being debugged
deepcopy({expr} [, {noref}]) any make a full copy of {expr}
delete({fname} [, {flags}]) Number delete the file or directory {fname}
-deletebufline({expr}, {first}[, {last}])
- Number delete lines from buffer {expr}
+deletebufline({buf}, {first}[, {last}])
+ Number delete lines from buffer {buf}
dictwatcheradd({dict}, {pattern}, {callback})
Start watching a dictionary
dictwatcherdel({dict}, {pattern}, {callback})
@@ -2197,15 +2398,17 @@ garbagecollect([{atexit}]) none free memory, breaking cyclic references
get({list}, {idx} [, {def}]) any get item {idx} from {list} or {def}
get({dict}, {key} [, {def}]) any get item {key} from {dict} or {def}
get({func}, {what}) any get property of funcref/partial {func}
-getbufinfo([{expr}]) List information about buffers
-getbufline({expr}, {lnum} [, {end}])
- List lines {lnum} to {end} of buffer {expr}
-getbufvar({expr}, {varname} [, {def}])
- any variable {varname} in buffer {expr}
-getchangelist({expr}) List list of change list items
-getchar([expr]) Number get one character from the user
+getbufinfo([{buf}]) List information about buffers
+getbufline({buf}, {lnum} [, {end}])
+ List lines {lnum} to {end} of buffer {buf}
+getbufvar({buf}, {varname} [, {def}])
+ any variable {varname} in buffer {buf}
+getchangelist([{buf}]) List list of change list items
+getchar([expr]) Number or String
+ get one character from the user
getcharmod() Number modifiers for the last typed character
getcharsearch() Dict last character search
+getcharstr([expr]) String get one character from the user
getcmdline() String return the current command-line
getcmdpos() Number return cursor position in command-line
getcmdtype() String return current command-line type
@@ -2226,15 +2429,17 @@ getline({lnum}) String line {lnum} of current buffer
getline({lnum}, {end}) List lines {lnum} to {end} of current buffer
getloclist({nr}) List list of location list items
getloclist({nr}, {what}) Dict get specific location list properties
-getmarklist([{expr}]) List list of global/local marks
+getmarklist([{buf}]) List list of global/local marks
getmatches([{win}]) List list of current matches
+getmousepos() Dict last known mouse position
getpid() Number process ID of Vim
getpos({expr}) List position of cursor, mark, etc.
getqflist() List list of quickfix items
getqflist({what}) Dict get specific quickfix list properties
getreg([{regname} [, 1 [, {list}]]])
- String or List contents of register
-getregtype([{regname}]) String type of register
+ String or List contents of a register
+getreginfo([{regname}]) Dict information about a register
+getregtype([{regname}]) String type of a register
gettabinfo([{expr}]) List list of tab pages
gettabvar({nr}, {varname} [, {def}])
any variable {varname} in tab {nr} or {def}
@@ -2267,8 +2472,8 @@ hlID({name}) Number syntax ID of highlight group {name}
hostname() String name of the machine Vim is running on
iconv({expr}, {from}, {to}) String convert encoding of {expr}
indent({lnum}) Number indent of line {lnum}
-index({list}, {expr} [, {start} [, {ic}]])
- Number index in {list} where {expr} appears
+index({object}, {expr} [, {start} [, {ic}]])
+ Number index in {object} where {expr} appears
input({prompt} [, {text} [, {completion}]])
String get input from the user
inputlist({textlist}) Number let the user pick from a choice list
@@ -2276,8 +2481,8 @@ inputrestore() Number restore typeahead
inputsave() Number save and clear typeahead
inputsecret({prompt} [, {text}])
String like input() but hiding the text
-insert({list}, {item} [, {idx}])
- List insert {item} in {list} [before {idx}]
+insert({object}, {item} [, {idx}])
+ List insert {item} in {object} [before {idx}]
interrupt() none interrupt script execution
invert({expr}) Number bitwise invert
isdirectory({directory}) Number |TRUE| if {directory} is a directory
@@ -2331,12 +2536,13 @@ matchstr({expr}, {pat}[, {start}[, {count}]])
matchstrpos({expr}, {pat}[, {start}[, {count}]])
List {count}'th match of {pat} in {expr}
max({expr}) Number maximum value of items in {expr}
+menu_get({path} [, {modes}]) List description of |menus| matched by {path}
min({expr}) Number minimum value of items in {expr}
mkdir({name} [, {path} [, {prot}]])
Number create directory {name}
mode([expr]) String current editing mode
-msgpackdump({list}) List dump a list of objects to msgpack
-msgpackparse({list}) List parse msgpack to a list of objects
+msgpackdump({list} [, {type}]) List/Blob dump objects to msgpack
+msgpackparse({data}) List parse msgpack to a list of objects
nextnonblank({lnum}) Number line nr of non-blank line >= {lnum}
nr2char({expr}[, {utf8}]) String single char with ASCII/UTF8 value {expr}
nvim_...({args}...) any call nvim |api| functions
@@ -2358,7 +2564,7 @@ pyxeval({expr}) any evaluate |python_x| expression
range({expr} [, {max} [, {stride}]])
List items from {expr} to {max}
readdir({dir} [, {expr}]) List file names in {dir} selected by {expr}
-readfile({fname} [, {binary} [, {max}]])
+readfile({fname} [, {type} [, {max}]])
List get list of lines from file {fname}
reg_executing() String get the executing register name
reg_recording() String get the recording register name
@@ -2375,7 +2581,10 @@ remote_read({serverid} [, {timeout}])
remote_send({server}, {string} [, {idvar}])
String send key sequence
remote_startserver({name}) none become server {name}
-remove({list}, {idx} [, {end}]) any remove items {idx}-{end} from {list}
+remove({list}, {idx} [, {end}]) any/List
+ remove items {idx}-{end} from {list}
+remove({blob}, {idx} [, {end}]) Number/Blob
+ remove bytes {idx}-{end} from {blob}
remove({dict}, {key}) any remove entry {key} from {dict}
rename({from}, {to}) Number rename (move) file from {from} to {to}
repeat({expr}, {count}) String repeat {expr} {count} times
@@ -2389,9 +2598,11 @@ rpcrequest({channel}, {method}[, {args}...])
Sends an |RPC| request to {channel}
screenattr({row}, {col}) Number attribute at screen position
screenchar({row}, {col}) Number character at screen position
+screenchars({row}, {col}) List List of characters at screen position
screencol() Number current cursor column
screenpos({winid}, {lnum}, {col}) Dict screen row and col of a text character
screenrow() Number current cursor row
+screenstring({row}, {col}) String characters at screen position
search({pattern} [, {flags} [, {stopline} [, {timeout}]]])
Number search for {pattern}
searchcount([{options}]) Dict Get or update the last search count
@@ -2409,7 +2620,7 @@ serverlist() String get a list of available servers
setbufline( {expr}, {lnum}, {line})
Number set line {lnum} to {line} in buffer
{expr}
-setbufvar({expr}, {varname}, {val}) set {varname} in buffer {expr} to {val}
+setbufvar({buf}, {varname}, {val}) set {varname} in buffer {buf} to {val}
setcharsearch({dict}) Dict set character search from {dict}
setcmdpos({pos}) Number set cursor position in command-line
setenv({name}, {val}) none set environment variable
@@ -2439,11 +2650,11 @@ shiftwidth([{col}]) Number effective value of 'shiftwidth'
sign_define({name} [, {dict}]) Number define or update a sign
sign_define({list}) List define or update a list of signs
sign_getdefined([{name}]) List get a list of defined signs
-sign_getplaced([{expr} [, {dict}]])
+sign_getplaced([{buf} [, {dict}]])
List get a list of placed signs
-sign_jump({id}, {group}, {expr})
+sign_jump({id}, {group}, {buf})
Number jump to a sign
-sign_place({id}, {group}, {name}, {expr} [, {dict}])
+sign_place({id}, {group}, {name}, {buf} [, {dict}])
Number place a sign
sign_placelist({list}) List place a list of signs
sign_undefine([{name}]) Number undefine a sign
@@ -2467,10 +2678,11 @@ split({expr} [, {pat} [, {keepempty}]])
sqrt({expr}) Float square root of {expr}
stdioopen({dict}) Number open stdio in a headless instance.
stdpath({what}) String/List returns the standard path(s) for {what}
-str2float({expr}) Float convert String to Float
+str2float({expr} [, {quoted}]) Float convert String to Float
str2list({expr} [, {utf8}]) List convert each character of {expr} to
ASCII/UTF8 value
-str2nr({expr} [, {base}]) Number convert String to Number
+str2nr({expr} [, {base} [, {quoted}]])
+ Number convert String to Number
strchars({expr} [, {skipcc}]) Number character length of the String {expr}
strcharpart({str}, {start} [, {len}])
String {len} characters of {str} at
@@ -2496,7 +2708,7 @@ submatch({nr} [, {list}]) String or List
substitute({expr}, {pat}, {sub}, {flags})
String all {pat} in {expr} replaced with {sub}
swapinfo({fname}) Dict information about swap file {fname}
-swapname({expr}) String swap file of buffer {expr}
+swapname({buf}) String swap file of buffer {buf}
synID({lnum}, {col}, {trans}) Number syntax ID at {lnum} and {col}
synIDattr({synID}, {what} [, {mode}])
String attribute {what} of syntax ID {synID}
@@ -2562,8 +2774,8 @@ winrestview({dict}) none restore view of current window
winsaveview() Dict save view of current window
winwidth({nr}) Number width of window {nr}
wordcount() Dict get byte/char/word statistics
-writefile({list}, {fname} [, {flags}])
- Number write list of lines to file {fname}
+writefile({object}, {fname} [, {flags}])
+ Number write |Blob| or |List| of lines to file
xor({expr}, {expr}) Number bitwise XOR
@@ -2580,6 +2792,8 @@ abs({expr}) *abs()*
echo abs(-4)
< 4
+ Can also be used as a |method|: >
+ Compute()->abs()
acos({expr}) *acos()*
Return the arc cosine of {expr} measured in radians, as a
@@ -2592,22 +2806,29 @@ acos({expr}) *acos()*
:echo acos(-0.5)
< 2.094395
+ Can also be used as a |method|: >
+ Compute()->acos()
-add({list}, {expr}) *add()*
- Append the item {expr} to |List| {list}. Returns the
- resulting |List|. Examples: >
+add({object}, {expr}) *add()*
+ Append the item {expr} to |List| or |Blob| {object}. Returns
+ the resulting |List| or |Blob|. Examples: >
:let alist = add([1, 2, 3], item)
:call add(mylist, "woodstock")
< Note that when {expr} is a |List| it is appended as a single
item. Use |extend()| to concatenate |Lists|.
+ When {object} is a |Blob| then {expr} must be a number.
Use |insert()| to add an item at another position.
+ Can also be used as a |method|: >
+ mylist->add(val1)->add(val2)
and({expr}, {expr}) *and()*
Bitwise AND on the two arguments. The arguments are converted
to a number. A List, Dict or Float argument causes an error.
Example: >
:let flag = and(bits, 0x80)
+< Can also be used as a |method|: >
+ :let flag = bits->and(0x80)
api_info() *api_info()*
Returns Dictionary of |api-metadata|.
@@ -2621,18 +2842,22 @@ append({lnum}, {text}) *append()*
Otherwise append {text} as one text line below line {lnum} in
the current buffer.
{lnum} can be zero to insert a line before the first one.
+ {lnum} is used like with |getline()|.
Returns 1 for failure ({lnum} out of range or out of memory),
0 for success. Example: >
:let failed = append(line('$'), "# THE END")
:let failed = append(0, ["Chapter 1", "the beginning"])
-appendbufline({expr}, {lnum}, {text}) *appendbufline()*
+< Can also be used as a |method| after a List: >
+ mylist->append(lnum)
+
+appendbufline({buf}, {lnum}, {text}) *appendbufline()*
Like |append()| but append the text in buffer {expr}.
This function works only for loaded buffers. First call
|bufload()| if needed.
- For the use of {expr}, see |bufname()|.
+ For the use of {buf}, see |bufname()|.
{lnum} is used like with |append()|. Note that using |line()|
would use the current buffer, not the one appending to.
@@ -2640,12 +2865,14 @@ appendbufline({expr}, {lnum}, {text}) *appendbufline()*
On success 0 is returned, on failure 1 is returned.
- If {expr} is not a valid buffer or {lnum} is not valid, an
+ If {buf} is not a valid buffer or {lnum} is not valid, an
error message is given. Example: >
:let failed = appendbufline(13, 0, "# THE START")
<
- *argc()*
-argc([{winid}])
+ Can also be used as a |method| after a List: >
+ mylist->appendbufline(buf, lnum)
+
+argc([{winid}]) *argc()*
The result is the number of files in the argument list. See
|arglist|.
If {winid} is not supplied, the argument list of the current
@@ -2699,6 +2926,9 @@ asin({expr}) *asin()*
:echo asin(-0.5)
< -0.523599
+ Can also be used as a |method|: >
+ Compute()->asin()
+
assert_ functions are documented here: |assert-functions-details|
@@ -2713,6 +2943,8 @@ atan({expr}) *atan()*
:echo atan(-4.01)
< -1.326405
+ Can also be used as a |method|: >
+ Compute()->atan()
atan2({expr1}, {expr2}) *atan2()*
Return the arc tangent of {expr1} / {expr2}, measured in
@@ -2724,6 +2956,8 @@ atan2({expr1}, {expr2}) *atan2()*
:echo atan2(1, -1)
< 2.356194
+ Can also be used as a |method|: >
+ Compute()->atan2(1)
*browse()*
browse({save}, {title}, {initdir}, {default})
@@ -2734,8 +2968,8 @@ browse({save}, {title}, {initdir}, {default})
{title} title for the requester
{initdir} directory to start browsing in
{default} default file name
- When the "Cancel" button is hit, something went wrong, or
- browsing is not possible, an empty string is returned.
+ An empty string is returned when the "Cancel" button is hit,
+ something went wrong, or browsing is not possible.
*browsedir()*
browsedir({title}, {initdir})
@@ -2751,20 +2985,22 @@ browsedir({title}, {initdir})
browsing is not possible, an empty string is returned.
bufadd({name}) *bufadd()*
- Add a buffer to the buffer list with {name}.
+ Add a buffer to the buffer list with String {name}.
If a buffer for file {name} already exists, return that buffer
number. Otherwise return the buffer number of the newly
created buffer. When {name} is an empty string then a new
buffer is always created.
The buffer will not have' 'buflisted' set.
+< Can also be used as a |method|: >
+ let bufnr = 'somename'->bufadd()
-bufexists({expr}) *bufexists()*
+bufexists({buf}) *bufexists()*
The result is a Number, which is |TRUE| if a buffer called
- {expr} exists.
- If the {expr} argument is a number, buffer numbers are used.
+ {buf} exists.
+ If the {buf} argument is a number, buffer numbers are used.
Number zero is the alternate buffer for the current window.
- If the {expr} argument is a string it must match a buffer name
+ If the {buf} argument is a string it must match a buffer name
exactly. The name can be:
- Relative to the current directory.
- A full path.
@@ -2780,32 +3016,45 @@ bufexists({expr}) *bufexists()*
Use "bufexists(0)" to test for the existence of an alternate
file name.
-buflisted({expr}) *buflisted()*
+ Can also be used as a |method|: >
+ let exists = 'somename'->bufexists()
+
+buflisted({buf}) *buflisted()*
The result is a Number, which is |TRUE| if a buffer called
- {expr} exists and is listed (has the 'buflisted' option set).
- The {expr} argument is used like with |bufexists()|.
+ {buf} exists and is listed (has the 'buflisted' option set).
+ The {buf} argument is used like with |bufexists()|.
+
+ Can also be used as a |method|: >
+ let listed = 'somename'->buflisted()
-bufload({expr}) *bufload()*
- Ensure the buffer {expr} is loaded. When the buffer name
+bufload({buf}) *bufload()*
+ Ensure the buffer {buf} is loaded. When the buffer name
refers to an existing file then the file is read. Otherwise
the buffer will be empty. If the buffer was already loaded
then there is no change.
If there is an existing swap file for the file of the buffer,
there will be no dialog, the buffer will be loaded anyway.
- The {expr} argument is used like with |bufexists()|.
+ The {buf} argument is used like with |bufexists()|.
+
+ Can also be used as a |method|: >
+ eval 'somename'->bufload()
-bufloaded({expr}) *bufloaded()*
+bufloaded({buf}) *bufloaded()*
The result is a Number, which is |TRUE| if a buffer called
- {expr} exists and is loaded (shown in a window or hidden).
- The {expr} argument is used like with |bufexists()|.
-
-bufname([{expr}]) *bufname()*
- The result is the name of a buffer, as it is displayed by the
- ":ls" command.
-+ If {expr} is omitted the current buffer is used.
- If {expr} is a Number, that buffer number's name is given.
+ {buf} exists and is loaded (shown in a window or hidden).
+ The {buf} argument is used like with |bufexists()|.
+
+ Can also be used as a |method|: >
+ let loaded = 'somename'->bufloaded()
+
+bufname([{buf}]) *bufname()*
+ The result is the name of a buffer. Mostly as it is displayed
+ by the `:ls` command, but not using special names such as
+ "[No Name]".
+ If {buf} is omitted the current buffer is used.
+ If {buf} is a Number, that buffer number's name is given.
Number zero is the alternate buffer for the current window.
- If {expr} is a String, it is used as a |file-pattern| to match
+ If {buf} is a String, it is used as a |file-pattern| to match
with the buffer names. This is always done like 'magic' is
set and 'cpoptions' is empty. When there is more than one
match an empty string is returned.
@@ -2818,9 +3067,12 @@ bufname([{expr}]) *bufname()*
Listed buffers are found first. If there is a single match
with a listed buffer, that one is returned. Next unlisted
buffers are searched for.
- If the {expr} is a String, but you want to use it as a buffer
+ If the {buf} is a String, but you want to use it as a buffer
number, force it to be a Number by adding zero to it: >
:echo bufname("3" + 0)
+< Can also be used as a |method|: >
+ echo bufnr->bufname()
+
< If the buffer doesn't exist, or doesn't have a name, an empty
string is returned. >
bufname("#") alternate buffer name
@@ -2829,9 +3081,9 @@ bufname([{expr}]) *bufname()*
bufname("file2") name of buffer where "file2" matches.
*bufnr()*
-bufnr([{expr} [, {create}]])
+bufnr([{buf} [, {create}]])
The result is the number of a buffer, as it is displayed by
- the ":ls" command. For the use of {expr}, see |bufname()|
+ the `:ls` command. For the use of {buf}, see |bufname()|
above.
If the buffer doesn't exist, -1 is returned. Or, if the
{create} argument is present and TRUE, a new, unlisted,
@@ -2843,28 +3095,35 @@ bufnr([{expr} [, {create}]])
number necessarily exist, because ":bwipeout" may have removed
them. Use bufexists() to test for the existence of a buffer.
-bufwinid({expr}) *bufwinid()*
+ Can also be used as a |method|: >
+ echo bufref->bufnr()
+
+bufwinid({buf}) *bufwinid()*
The result is a Number, which is the |window-ID| of the first
- window associated with buffer {expr}. For the use of {expr},
- see |bufname()| above. If buffer {expr} doesn't exist or
+ window associated with buffer {buf}. For the use of {buf},
+ see |bufname()| above. If buffer {buf} doesn't exist or
there is no such window, -1 is returned. Example: >
echo "A window containing buffer 1 is " . (bufwinid(1))
<
Only deals with the current tab page.
-bufwinnr({expr}) *bufwinnr()*
- The result is a Number, which is the number of the first
- window associated with buffer {expr}. For the use of {expr},
- see |bufname()| above. If buffer {expr} doesn't exist or
- there is no such window, -1 is returned. Example: >
+ Can also be used as a |method|: >
+ FindBuffer()->bufwinid()
+
+bufwinnr({buf}) *bufwinnr()*
+ Like |bufwinid()| but return the window number instead of the
+ |window-ID|.
+ If buffer {buf} doesn't exist or there is no such window, -1
+ is returned. Example: >
echo "A window containing buffer 1 is " . (bufwinnr(1))
< The number can be used with |CTRL-W_w| and ":wincmd w"
|:wincmd|.
- Only deals with the current tab page.
+ Can also be used as a |method|: >
+ FindBuffer()->bufwinnr()
byte2line({byte}) *byte2line()*
Return the line number that contains the character at byte
@@ -2874,8 +3133,11 @@ byte2line({byte}) *byte2line()*
one.
Also see |line2byte()|, |go| and |:goto|.
+ Can also be used as a |method|: >
+ GetOffset()->byte2line()
+
byteidx({expr}, {nr}) *byteidx()*
- Return byte index of the {nr}'th character in the string
+ Return byte index of the {nr}'th character in the String
{expr}. Use zero for the first character, it then returns
zero.
If there are no multibyte characters the returned value is
@@ -2896,6 +3158,9 @@ byteidx({expr}, {nr}) *byteidx()*
If there are exactly {nr} characters the length of the string
in bytes is returned.
+ Can also be used as a |method|: >
+ GetName()->byteidx(idx)
+
byteidxcomp({expr}, {nr}) *byteidxcomp()*
Like byteidx(), except that a composing character is counted
as a separate character. Example: >
@@ -2909,6 +3174,9 @@ byteidxcomp({expr}, {nr}) *byteidxcomp()*
Only works differently from byteidx() when 'encoding' is set to
a Unicode encoding.
+ Can also be used as a |method|: >
+ GetName()->byteidxcomp(idx)
+
call({func}, {arglist} [, {dict}]) *call()* *E699*
Call function {func} with the items in |List| {arglist} as
arguments.
@@ -2918,6 +3186,9 @@ call({func}, {arglist} [, {dict}]) *call()* *E699*
{dict} is for functions with the "dict" attribute. It will be
used to set the local variable "self". |Dictionary-function|
+ Can also be used as a |method|: >
+ GetFunc()->call([arg, arg], dict)
+
ceil({expr}) *ceil()*
Return the smallest integral value greater than or equal to
{expr} as a |Float| (round up).
@@ -2930,6 +3201,9 @@ ceil({expr}) *ceil()*
echo ceil(4.0)
< 4.0
+ Can also be used as a |method|: >
+ Compute()->ceil()
+
changenr() *changenr()*
Return the number of the most recent change. This is the same
number as what is displayed with |:undolist| and can be used
@@ -2955,8 +3229,8 @@ chansend({id}, {data}) *chansend()*
written if the write succeeded, 0 otherwise.
See |channel-bytes| for more information.
- {data} may be a string, string convertible, or a list. If
- {data} is a list, the items will be joined by newlines; any
+ {data} may be a string, string convertible, |Blob|, or a list.
+ If {data} is a list, the items will be joined by newlines; any
newlines in an item will be sent as NUL. To send a final
newline, include a final empty string. Example: >
:call chansend(id, ["abc", "123\n456", ""])
@@ -2967,8 +3241,9 @@ chansend({id}, {data}) *chansend()*
messages, use |rpcnotify()| and |rpcrequest()| instead.
-char2nr({expr} [, {utf8}]) *char2nr()*
- Return number value of the first char in {expr}. Examples: >
+char2nr({string} [, {utf8}]) *char2nr()*
+ Return number value of the first char in {string}.
+ Examples: >
char2nr(" ") returns 32
char2nr("ABC") returns 65
char2nr("á") returns 225
@@ -2979,16 +3254,19 @@ char2nr({expr} [, {utf8}]) *char2nr()*
A combining character is a separate character.
|nr2char()| does the opposite.
+ Can also be used as a |method|: >
+ GetChar()->char2nr()
+
*charidx()*
charidx({string}, {idx} [, {countcc}])
Return the character index of the byte at {idx} in {string}.
The index of the first character is zero.
If there are no multibyte characters the returned value is
equal to {idx}.
- When {countcc} is omitted or zero, then composing characters
- are not counted separately, their byte length is added to the
- preceding base character.
- When {countcc} is set to 1, then composing characters are
+ When {countcc} is omitted or |FALSE|, then composing characters
+ are not counted separately, their byte length is
+ added to the preceding base character.
+ When {countcc} is |TRUE|, then composing characters are
counted as separate characters.
Returns -1 if the arguments are invalid or if {idx} is greater
than the index of the last byte in {string}. An error is
@@ -3010,12 +3288,18 @@ cindent({lnum}) *cindent()*
When {lnum} is invalid -1 is returned.
See |C-indenting|.
+ Can also be used as a |method|: >
+ GetLnum()->cindent()
+
clearmatches([{win}]) *clearmatches()*
Clears all matches previously defined for the current window
by |matchadd()| and the |:match| commands.
If {win} is specified, use the window with this number or
window ID instead of the current window.
+ Can also be used as a |method|: >
+ GetWin()->clearmatches()
+<
*col()*
col({expr}) The result is a Number, which is the byte index of the column
position given with {expr}. The accepted positions are:
@@ -3051,6 +3335,9 @@ col({expr}) The result is a Number, which is the byte index of the column
\<C-O>:set ve=all<CR>
\<C-O>:echo col(".") . "\n" <Bar>
\let &ve = save_ve<CR>
+
+< Can also be used as a |method|: >
+ GetPos()->col()
<
complete({startcol}, {matches}) *complete()* *E785*
@@ -3065,6 +3352,7 @@ complete({startcol}, {matches}) *complete()* *E785*
match.
{matches} must be a |List|. Each |List| item is one match.
See |complete-items| for the kind of items that are possible.
+ "longest" in 'completeopt' is ignored.
Note that the after calling this function you need to avoid
inserting anything that would cause completion to stop.
The match can be selected with CTRL-N and CTRL-P as usual with
@@ -3082,6 +3370,10 @@ complete({startcol}, {matches}) *complete()* *E785*
< This isn't very useful, but it shows how it works. Note that
an empty string is returned to avoid a zero being inserted.
+ Can also be used as a |method|, the second argument is passed
+ in: >
+ GetMatches()->complete(col('.'))
+
complete_add({expr}) *complete_add()*
Add {expr} to the list of matches. Only to be used by the
function specified with the 'completefunc' option.
@@ -3091,6 +3383,9 @@ complete_add({expr}) *complete_add()*
See |complete-functions| for an explanation of {expr}. It is
the same as one item in the list that 'omnifunc' would return.
+ Can also be used as a |method|: >
+ GetMoreMatches()->complete_add()
+
complete_check() *complete_check()*
Check for a key typed while looking for completion matches.
This is to be used when looking for matches takes some time.
@@ -3099,8 +3394,8 @@ complete_check() *complete_check()*
Only to be used by the function specified with the
'completefunc' option.
- *complete_info()*
-complete_info([{what}])
+
+complete_info([{what}]) *complete_info()*
Returns a |Dictionary| with information about Insert mode
completion. See |ins-completion|.
The items are:
@@ -3114,7 +3409,9 @@ complete_info([{what}])
See |complete-items|.
selected Selected item index. First index is zero.
Index is -1 if no item is selected (showing
- typed text only)
+ typed text only, or the last completion after
+ no item is selected when using the <Up> or
+ <Down> keys)
inserted Inserted string. [NOT IMPLEMENT YET]
*complete_info_mode*
@@ -3151,6 +3448,9 @@ complete_info([{what}])
call complete_info(['mode'])
" Get only 'mode' and 'pum_visible'
call complete_info(['mode', 'pum_visible'])
+
+< Can also be used as a |method|: >
+ GetItems()->complete_info()
<
*confirm()*
confirm({msg} [, {choices} [, {default} [, {type}]]])
@@ -3174,10 +3474,10 @@ confirm({msg} [, {choices} [, {default} [, {type}]]])
< For the console, the first letter of each choice is used as
the default shortcut key. Case is ignored.
- The optional {default} argument is the number of the choice
- that is made if the user hits <CR>. Use 1 to make the first
- choice the default one. Use 0 to not set a default. If
- {default} is omitted, 1 is used.
+ The optional {type} String argument gives the type of dialog.
+ It can be one of these values: "Error", "Question", "Info",
+ "Warning" or "Generic". Only the first character is relevant.
+ When {type} is omitted, "Generic" is used.
The optional {type} argument gives the type of dialog. This
is only used for the icon of the Win32 GUI. It can be one of
@@ -3204,6 +3504,9 @@ confirm({msg} [, {choices} [, {default} [, {type}]]])
don't fit, a vertical layout is used anyway. For some systems
the horizontal layout is always used.
+ Can also be used as a |method|in: >
+ BuildMessage()->confirm("&Yes\n&No")
+
*copy()*
copy({expr}) Make a copy of {expr}. For Numbers and Strings this isn't
different from using {expr} directly.
@@ -3213,6 +3516,8 @@ copy({expr}) Make a copy of {expr}. For Numbers and Strings this isn't
changing an item changes the contents of both |Lists|.
A |Dictionary| is copied in a similar way as a |List|.
Also see |deepcopy()|.
+ Can also be used as a |method|: >
+ mylist->copy()
cos({expr}) *cos()*
Return the cosine of {expr}, measured in radians, as a |Float|.
@@ -3223,6 +3528,8 @@ cos({expr}) *cos()*
:echo cos(-4.01)
< -0.646043
+ Can also be used as a |method|: >
+ Compute()->cos()
cosh({expr}) *cosh()*
Return the hyperbolic cosine of {expr} as a |Float| in the range
@@ -3234,6 +3541,8 @@ cosh({expr}) *cosh()*
:echo cosh(-0.5)
< -1.127626
+ Can also be used as a |method|: >
+ Compute()->cosh()
count({comp}, {expr} [, {ic} [, {start}]]) *count()*
Return the number of times an item with value {expr} appears
@@ -3248,12 +3557,14 @@ count({comp}, {expr} [, {ic} [, {start}]]) *count()*
occurrences of {expr} is returned. Zero is returned when
{expr} is an empty string.
+ Can also be used as a |method|: >
+ mylist->count(val)
+
*cscope_connection()*
cscope_connection([{num} , {dbpath} [, {prepend}]])
Checks for the existence of a |cscope| connection. If no
parameters are specified, then the function returns:
- 0, if cscope was not available (not compiled in), or
- if there are no cscope connections;
+ 0, if there are no cscope connections;
1, if there is at least one cscope connection.
If parameters are specified, then the value of {num}
@@ -3344,6 +3655,8 @@ cursor({list})
position within a <Tab> or after the last character.
Returns 0 when the position could be set, -1 otherwise.
+ Can also be used as a |method|: >
+ GetCursorPos()->cursor()
deepcopy({expr}[, {noref}]) *deepcopy()* *E698*
Make a copy of {expr}. For Numbers and Strings this isn't
@@ -3365,7 +3678,10 @@ deepcopy({expr}[, {noref}]) *deepcopy()* *E698*
{noref} set to 1 will fail.
Also see |copy()|.
-delete({fname} [, {flags}]) *delete()*
+ Can also be used as a |method|: >
+ GetObject()->deepcopy()
+
+delete({fname} [, {flags}]) *delete()*
Without {flags} or with {flags} empty: Deletes the file by the
name {fname}. This also works when {fname} is a symbolic link.
A symbolic link itself is deleted, not what it points to.
@@ -3382,19 +3698,25 @@ delete({fname} [, {flags}]) *delete()*
operation was successful and -1/true when the deletion failed
or partly failed.
-deletebufline({expr}, {first}[, {last}]) *deletebufline()*
- Delete lines {first} to {last} (inclusive) from buffer {expr}.
+ Can also be used as a |method|: >
+ GetName()->delete()
+
+deletebufline({buf}, {first}[, {last}]) *deletebufline()*
+ Delete lines {first} to {last} (inclusive) from buffer {buf}.
If {last} is omitted then delete line {first} only.
On success 0 is returned, on failure 1 is returned.
This function works only for loaded buffers. First call
|bufload()| if needed.
- For the use of {expr}, see |bufname()| above.
+ For the use of {buf}, see |bufname()| above.
{first} and {last} are used like with |setline()|. Note that
when using |line()| this refers to the current buffer. Use "$"
- to refer to the last line in buffer {expr}.
+ to refer to the last line in buffer {buf}.
+
+ Can also be used as a |method|: >
+ GetBuffer()->deletebufline(1)
dictwatcheradd({dict}, {pattern}, {callback}) *dictwatcheradd()*
Adds a watcher to a dictionary. A dictionary watcher is
@@ -3462,6 +3784,9 @@ diff_filler({lnum}) *diff_filler()*
line, "'m" mark m, etc.
Returns 0 if the current window is not in diff mode.
+ Can also be used as a |method|: >
+ GetLnum()->diff_filler()
+
diff_hlID({lnum}, {col}) *diff_hlID()*
Returns the highlight ID for diff mode at line {lnum} column
{col} (byte index). When the current line does not have a
@@ -3473,11 +3798,20 @@ diff_hlID({lnum}, {col}) *diff_hlID()*
The highlight ID can be used with |synIDattr()| to obtain
syntax information about the highlighting.
+ Can also be used as a |method|: >
+ GetLnum()->diff_hlID(col)
+
empty({expr}) *empty()*
Return the Number 1 if {expr} is empty, zero otherwise.
- A |List| or |Dictionary| is empty when it does not have any
- items. A Number is empty when its value is zero. Special
- variable is empty when it is |v:false| or |v:null|.
+ - A |List| or |Dictionary| is empty when it does not have any
+ items.
+ - A |String| is empty when its length is zero.
+ - A |Number| and |Float| are empty when their value is zero.
+ - |v:false| and |v:null| are empty, |v:true| is not.
+ - A |Blob| is empty when its length is zero.
+
+ Can also be used as a |method|: >
+ mylist->empty()
environ() *environ()*
Return all of environment variables as dictionary. You can
@@ -3498,10 +3832,13 @@ escape({string}, {chars}) *escape()*
*eval()*
eval({string}) Evaluate {string} and return the result. Especially useful to
turn the result of |string()| back into the original value.
- This works for Numbers, Floats, Strings and composites of
- them. Also works for |Funcref|s that refer to existing
+ This works for Numbers, Floats, Strings, Blobs and composites
+ of them. Also works for |Funcref|s that refer to existing
functions.
+ Can also be used as a |method|: >
+ argv->join()->eval()
+
eventhandler() *eventhandler()*
Returns 1 when inside an event handler. That is that Vim got
interrupted while waiting for the user to type a character,
@@ -3659,27 +3996,33 @@ exp({expr}) *exp()*
:echo exp(-1)
< 0.367879
+ Can also be used as a |method|: >
+ Compute()->exp()
+
debugbreak({pid}) *debugbreak()*
Specifically used to interrupt a program being debugged. It
will cause process {pid} to get a SIGTRAP. Behavior for other
processes is undefined. See |terminal-debugger|.
{Sends a SIGINT to a process {pid} other than MS-Windows}
-expand({expr} [, {nosuf} [, {list}]]) *expand()*
- Expand wildcards and the following special keywords in {expr}.
- 'wildignorecase' applies.
+ Can also be used as a |method|: >
+ GetPid()->debugbreak()
+
+expand({string} [, {nosuf} [, {list}]]) *expand()*
+ Expand wildcards and the following special keywords in
+ {string}. 'wildignorecase' applies.
If {list} is given and it is |TRUE|, a List will be returned.
Otherwise the result is a String and when there are several
matches, they are separated by <NL> characters.
If the expansion fails, the result is an empty string. A name
- for a non-existing file is not included, unless {expr} does
+ for a non-existing file is not included, unless {string} does
not start with '%', '#' or '<', see below.
- When {expr} starts with '%', '#' or '<', the expansion is done
- like for the |cmdline-special| variables with their associated
- modifiers. Here is a short overview:
+ When {string} starts with '%', '#' or '<', the expansion is
+ done like for the |cmdline-special| variables with their
+ associated modifiers. Here is a short overview:
% current file name
# alternate file name
@@ -3728,7 +4071,7 @@ expand({expr} [, {nosuf} [, {list}]]) *expand()*
buffer with no name, results in the current directory, with a
'/' added.
- When {expr} does not start with '%', '#' or '<', it is
+ When {string} does not start with '%', '#' or '<', it is
expanded like a file name is expanded on the command line.
'suffixes' and 'wildignore' are used, unless the optional
{nosuf} argument is given and it is |TRUE|.
@@ -3793,6 +4136,8 @@ extend({expr1}, {expr2} [, {expr3}]) *extend()*
fails.
Returns {expr1}.
+ Can also be used as a |method|: >
+ mylist->extend(otherlist)
feedkeys({string} [, {mode}]) *feedkeys()*
Characters in {string} are queued for processing as if they
@@ -3846,7 +4191,11 @@ filereadable({file}) *filereadable()*
expression, which is used as a String.
If you don't care about the file being readable you can use
|glob()|.
-
+ {file} is used as-is, you may want to expand wildcards first: >
+ echo filereadable('~/.vimrc')
+ 0
+ echo filereadable(expand('~/.vimrc'))
+ 1
filewritable({file}) *filewritable()*
The result is a Number, which is 1 when a file with the
@@ -3856,16 +4205,19 @@ filewritable({file}) *filewritable()*
filter({expr1}, {expr2}) *filter()*
- {expr1} must be a |List| or a |Dictionary|.
+ {expr1} must be a |List|, |Blob|, or a |Dictionary|.
For each item in {expr1} evaluate {expr2} and when the result
- is zero remove the item from the |List| or |Dictionary|.
+ is zero remove the item from the |List| or |Dictionary|. For a
+ |Blob| each byte is removed.
+
{expr2} must be a |string| or |Funcref|.
If {expr2} is a |string|, inside {expr2} |v:val| has the value
of the current item. For a |Dictionary| |v:key| has the key
of the current item and for a |List| |v:key| has the index of
- the current item.
- For a |Dictionary| |v:key| has the key of the current item.
+ the current item. For a |Blob| |v:key| has the index of the
+ current byte.
+
Examples: >
call filter(mylist, 'v:val !~ "OLD"')
< Removes the items where "OLD" appears. >
@@ -3896,25 +4248,30 @@ filter({expr1}, {expr2}) *filter()*
|Dictionary| to remain unmodified make a copy first: >
:let l = filter(copy(mylist), 'v:val =~ "KEEP"')
-< Returns {expr1}, the |List| or |Dictionary| that was filtered.
- When an error is encountered while evaluating {expr2} no
- further items in {expr1} are processed. When {expr2} is a
- Funcref errors inside a function are ignored, unless it was
- defined with the "abort" flag.
+< Returns {expr1}, the |List|, |Blob| or |Dictionary| that was
+ filtered. When an error is encountered while evaluating
+ {expr2} no further items in {expr1} are processed. When
+ {expr2} is a Funcref errors inside a function are ignored,
+ unless it was defined with the "abort" flag.
+ Can also be used as a |method|: >
+ mylist->filter(expr2)
finddir({name} [, {path} [, {count}]]) *finddir()*
Find directory {name} in {path}. Supports both downwards and
upwards recursive directory searches. See |file-searching|
for the syntax of {path}.
+
Returns the path of the first found match. When the found
directory is below the current directory a relative path is
returned. Otherwise a full path is returned.
If {path} is omitted or empty then 'path' is used.
+
If the optional {count} is given, find {count}'s occurrence of
{name} in {path} instead of the first one.
When {count} is negative return all the matches in a |List|.
- This is quite similar to the ex-command |:find|.
+
+ This is quite similar to the ex-command `:find`.
findfile({name} [, {path} [, {count}]]) *findfile()*
Just like |finddir()|, but find a file instead of a directory.
@@ -3964,6 +4321,8 @@ float2nr({expr}) *float2nr()*
echo float2nr(1.0e-100)
< 0
+ Can also be used as a |method|: >
+ Compute()->float2nr()
floor({expr}) *floor()*
Return the largest integral value less than or equal to
@@ -3977,6 +4336,8 @@ floor({expr}) *floor()*
echo floor(4.0)
< 4.0
+ Can also be used as a |method|: >
+ Compute()->floor()
fmod({expr1}, {expr2}) *fmod()*
Return the remainder of {expr1} / {expr2}, even if the
@@ -3992,6 +4353,8 @@ fmod({expr1}, {expr2}) *fmod()*
:echo fmod(-12.33, 1.22)
< -0.13
+ Can also be used as a |method|: >
+ Compute()->fmod(1.22)
fnameescape({string}) *fnameescape()*
Escape {string} for use as file name command argument. All
@@ -4024,11 +4387,15 @@ foldclosed({lnum}) *foldclosed()*
The result is a Number. If the line {lnum} is in a closed
fold, the result is the number of the first line in that fold.
If the line {lnum} is not in a closed fold, -1 is returned.
+ {lnum} is used like with |getline()|. Thus "." is the current
+ line, "'m" mark m, etc.
foldclosedend({lnum}) *foldclosedend()*
The result is a Number. If the line {lnum} is in a closed
fold, the result is the number of the last line in that fold.
If the line {lnum} is not in a closed fold, -1 is returned.
+ {lnum} is used like with |getline()|. Thus "." is the current
+ line, "'m" mark m, etc.
foldlevel({lnum}) *foldlevel()*
The result is a Number, which is the foldlevel of line {lnum}
@@ -4039,6 +4406,8 @@ foldlevel({lnum}) *foldlevel()*
returned for lines where folds are still to be updated and the
foldlevel is unknown. As a special case the level of the
previous line is usually available.
+ {lnum} is used like with |getline()|. Thus "." is the current
+ line, "'m" mark m, etc.
*foldtext()*
foldtext() Returns a String, to be displayed for a closed fold. This is
@@ -4158,6 +4527,12 @@ get({list}, {idx} [, {default}]) *get()*
Get item {idx} from |List| {list}. When this item is not
available return {default}. Return zero when {default} is
omitted.
+ Can also be used as a |method|: >
+ mylist->get(idx)
+get({blob}, {idx} [, {default}])
+ Get byte {idx} from |Blob| {blob}. When this byte is not
+ available return {default}. Return -1 when {default} is
+ omitted.
get({dict}, {key} [, {default}])
Get item with key {key} from |Dictionary| {dict}. When this
item is not available return {default}. Return zero when
@@ -4174,7 +4549,7 @@ get({func}, {what})
"args" The list with arguments
*getbufinfo()*
-getbufinfo([{expr}])
+getbufinfo([{buf}])
getbufinfo([{dict}])
Get information about buffers as a List of Dictionaries.
@@ -4188,8 +4563,8 @@ getbufinfo([{dict}])
bufloaded include only loaded buffers.
bufmodified include only modified buffers.
- Otherwise, {expr} specifies a particular buffer to return
- information for. For the use of {expr}, see |bufname()|
+ Otherwise, {buf} specifies a particular buffer to return
+ information for. For the use of {buf}, see |bufname()|
above. If the buffer is found the returned List has one item.
Otherwise the result is an empty list.
@@ -4242,12 +4617,12 @@ getbufinfo([{dict}])
<
*getbufline()*
-getbufline({expr}, {lnum} [, {end}])
+getbufline({buf}, {lnum} [, {end}])
Return a |List| with the lines starting from {lnum} to {end}
- (inclusive) in the buffer {expr}. If {end} is omitted, a
+ (inclusive) in the buffer {buf}. If {end} is omitted, a
|List| with only the line {lnum} is returned.
- For the use of {expr}, see |bufname()| above.
+ For the use of {buf}, see |bufname()| above.
For {lnum} and {end} "$" can be used for the last line of the
buffer. Otherwise a number must be used.
@@ -4266,10 +4641,11 @@ getbufline({expr}, {lnum} [, {end}])
Example: >
:let lines = getbufline(bufnr("myfile"), 1, "$")
-getbufvar({expr}, {varname} [, {def}]) *getbufvar()*
+getbufvar({buf}, {varname} [, {def}]) *getbufvar()*
The result is the value of option or local buffer variable
- {varname} in buffer {expr}. Note that the name without "b:"
+ {varname} in buffer {buf}. Note that the name without "b:"
must be used.
+ The {varname} argument is a string.
When {varname} is empty returns a |Dictionary| with all the
buffer-local variables.
When {varname} is equal to "&" returns a |Dictionary| with all
@@ -4279,16 +4655,16 @@ getbufvar({expr}, {varname} [, {def}]) *getbufvar()*
This also works for a global or buffer-local option, but it
doesn't work for a global variable, window-local variable or
window-local option.
- For the use of {expr}, see |bufname()| above.
+ For the use of {buf}, see |bufname()| above.
When the buffer or variable doesn't exist {def} or an empty
string is returned, there is no error message.
Examples: >
:let bufmodified = getbufvar(1, "&mod")
:echo "todo myvar = " . getbufvar("todo", "myvar")
<
-getchangelist({expr}) *getchangelist()*
- Returns the |changelist| for the buffer {expr}. For the use
- of {expr}, see |bufname()| above. If buffer {expr} doesn't
+getchangelist({buf}) *getchangelist()*
+ Returns the |changelist| for the buffer {buf}. For the use
+ of {buf}, see |bufname()| above. If buffer {buf} doesn't
exist, an empty list is returned.
The returned list contains two entries: a list with the change
@@ -4298,7 +4674,7 @@ getchangelist({expr}) *getchangelist()*
col column number
coladd column offset for 'virtualedit'
lnum line number
- If buffer {expr} is the current buffer, then the current
+ If buffer {buf} is the current buffer, then the current
position refers to the position in the list. For other
buffers, it is set to the length of the list.
@@ -4309,6 +4685,7 @@ getchar([expr]) *getchar()*
Return zero otherwise.
If [expr] is 1, only check if a character is available, it is
not consumed. Return zero if no character available.
+ If you prefer always getting a string use |getcharstr()|.
Without [expr] and when [expr] is 0 a whole character or
special key is returned. If it is a single character, the
@@ -4333,7 +4710,8 @@ getchar([expr]) *getchar()*
When the user clicks a mouse button, the mouse event will be
returned. The position can then be found in |v:mouse_col|,
|v:mouse_lnum|, |v:mouse_winid| and |v:mouse_win|.
- Mouse move events will be ignored.
+ |getmousepos()| can also be used. Mouse move events will be
+ ignored.
This example positions the mouse as it would normally happen: >
let c = getchar()
if c == "\<LeftMouse>" && v:mouse_win > 0
@@ -4400,6 +4778,20 @@ getcharsearch() *getcharsearch()*
:nnoremap <expr> , getcharsearch().forward ? ',' : ';'
< Also see |setcharsearch()|.
+
+getcharstr([expr]) *getcharstr()*
+ Get a single character from the user or input stream as a
+ string.
+ If [expr] is omitted, wait until a character is available.
+ If [expr] is 0 or false, only get a character when one is
+ available. Return an empty string otherwise.
+ If [expr] is 1 or true, only check if a character is
+ available, it is not consumed. Return an empty string
+ if no character is available.
+ Otherwise this works like |getchar()|, except that a number
+ result is converted to a string.
+
+
getcmdline() *getcmdline()*
Return the current command-line. Only works when the command
line is being edited, thus requires use of |c_CTRL-\_e| or
@@ -4439,9 +4831,9 @@ getcmdwintype() *getcmdwintype()*
when not in the command-line window.
getcompletion({pat}, {type} [, {filtered}]) *getcompletion()*
- Return a list of command-line completion matches. {type}
- specifies what for. The following completion types are
- supported:
+ Return a list of command-line completion matches. The String
+ {type} argument specifies what for. The following completion
+ types are supported:
arglist file names in argument list
augroup autocmd groups
@@ -4512,9 +4904,9 @@ getcurpos() Get the position of the cursor. This is like getpos('.'), but
|winrestview()| for restoring more state.
getcwd([{winnr}[, {tabnr}]]) *getcwd()*
- With no arguments the result is a String, which is the name of
- the current effective working directory. With {winnr} or
- {tabnr} the working directory of that scope is returned.
+ With no arguments, returns the name of the effective
+ |current-directory|. With {winnr} or {tabnr} the working
+ directory of that scope is returned.
Tabs and windows are identified by their respective numbers,
0 means current tab or window. Missing argument implies 0.
Thus the following are equivalent: >
@@ -4525,8 +4917,11 @@ getcwd([{winnr}[, {tabnr}]]) *getcwd()*
{winnr} can be the window number or the |window-ID|.
getenv({name}) *getenv()*
- Return the value of environment variable {name}.
- When the variable does not exist |v:null| is returned. That
+ Return the value of environment variable {name}. The {name}
+ argument is a string, without a leading '$'. Example: >
+ myHome = getenv('HOME')
+
+< When the variable does not exist |v:null| is returned. That
is different from a variable set to an empty string.
See also |expr-env|.
@@ -4534,8 +4929,8 @@ getfontname([{name}]) *getfontname()*
Without an argument returns the name of the normal font being
used. Like what is used for the Normal highlight group
|hl-Normal|.
- With an argument a check is done whether {name} is a valid
- font name. If not then an empty string is returned.
+ With an argument a check is done whether String {name} is a
+ valid font name. If not then an empty string is returned.
Otherwise the actual font name is returned, or {name} if the
GUI does not support obtaining the real name.
Only works when the GUI is running, thus not in your vimrc or
@@ -4664,20 +5059,20 @@ getloclist({nr},[, {what}]) *getloclist()*
:echo getloclist(5, {'filewinid': 0})
-getmarklist([{expr}]) *getmarklist()*
- Without the {expr} argument returns a |List| with information
+getmarklist([{buf}]) *getmarklist()*
+ Without the {buf} argument returns a |List| with information
about all the global marks. |mark|
- If the optional {expr} argument is specified, returns the
- local marks defined in buffer {expr}. For the use of {expr},
+ If the optional {buf} argument is specified, returns the
+ local marks defined in buffer {buf}. For the use of {buf},
see |bufname()|.
Each item in the returned List is a |Dict| with the following:
- name - name of the mark prefixed by "'"
- pos - a |List| with the position of the mark:
+ mark name of the mark prefixed by "'"
+ pos a |List| with the position of the mark:
[bufnum, lnum, col, off]
- Refer to |getpos()| for more information.
- file - file name
+ Refer to |getpos()| for more information.
+ file file name
Refer to |getpos()| for getting information about a specific
mark.
@@ -4688,6 +5083,8 @@ getmatches([{win}]) *getmatches()*
|getmatches()| is useful in combination with |setmatches()|,
as |setmatches()| can restore a list of matches saved by
|getmatches()|.
+ If {win} is specified, use the window with this number or
+ window ID instead of the current window.
Example: >
:echo getmatches()
< [{'group': 'MyGroup1', 'pattern': 'TODO',
@@ -4704,13 +5101,42 @@ getmatches([{win}]) *getmatches()*
'pattern': 'FIXME', 'priority': 10, 'id': 2}] >
:unlet m
<
+getmousepos() *getmousepos()*
+ Returns a Dictionary with the last known position of the
+ mouse. This can be used in a mapping for a mouse click. The
+ items are:
+ screenrow screen row
+ screencol screen column
+ winid Window ID of the click
+ winrow row inside "winid"
+ wincol column inside "winid"
+ line text line inside "winid"
+ column text column inside "winid"
+ All numbers are 1-based.
+
+ If not over a window, e.g. when in the command line, then only
+ "screenrow" and "screencol" are valid, the others are zero.
+
+ When on the status line below a window or the vertical
+ separater right of a window, the "line" and "column" values
+ are zero.
+
+ When the position is after the text then "column" is the
+ length of the text in bytes plus one.
+
+ If the mouse is over a focusable floating window then that
+ window is used.
+
+ When using |getchar()| the Vim variables |v:mouse_lnum|,
+ |v:mouse_col| and |v:mouse_winid| also provide these values.
+
*getpid()*
getpid() Return a Number which is the process ID of the Vim process.
This is a unique number, until Vim exits.
*getpos()*
-getpos({expr}) Get the position for {expr}. For possible values of {expr}
- see |line()|. For getting the cursor position see
+getpos({expr}) Get the position for String {expr}. For possible values of
+ {expr} see |line()|. For getting the cursor position see
|getcurpos()|.
The result is a |List| with four numbers:
[bufnum, lnum, col, off]
@@ -4743,7 +5169,10 @@ getqflist([{what}]) *getqflist()*
bufname() to get the name
module module name
lnum line number in the buffer (first line is 1)
+ end_lnum
+ end of line number if the item is multiline
col column number (first column is 1)
+ end_col end of column number if the item has range
vcol |TRUE|: "col" is visual column
|FALSE|: "col" is byte index
nr error number
@@ -4753,8 +5182,10 @@ getqflist([{what}]) *getqflist()*
valid |TRUE|: recognized error message
When there is no error list or it's empty, an empty list is
- returned. Quickfix list entries with non-existing buffer
- number are returned with "bufnr" set to zero.
+ returned. Quickfix list entries with a non-existing buffer
+ number are returned with "bufnr" set to zero (Note: some
+ functions accept buffer number zero for the alternate buffer,
+ you may need to explicitly check for zero).
Useful application: Find pattern matches in multiple files and
do something with them: >
@@ -4831,6 +5262,7 @@ getreg([{regname} [, 1 [, {list}]]]) *getreg()*
{regname}. Example: >
:let cliptext = getreg('*')
< When {regname} was not set the result is an empty string.
+ The {regname} argument is a string.
getreg('=') returns the last evaluated value of the expression
register. (For use in maps.)
@@ -4847,6 +5279,32 @@ getreg([{regname} [, 1 [, {list}]]]) *getreg()*
If {regname} is not specified, |v:register| is used.
+getreginfo([{regname}]) *getreginfo()*
+ Returns detailed information about register {regname} as a
+ Dictionary with the following entries:
+ regcontents List of lines contained in register
+ {regname}, like
+ |getreg|({regname}, 1, 1).
+ regtype the type of register {regname}, as in
+ |getregtype()|.
+ isunnamed Boolean flag, v:true if this register
+ is currently pointed to by the unnamed
+ register.
+ points_to for the unnamed register, gives the
+ single letter name of the register
+ currently pointed to (see |quotequote|).
+ For example, after deleting a line
+ with `dd`, this field will be "1",
+ which is the register that got the
+ deleted text.
+
+ The {regname} argument is a string. If {regname} is invalid
+ or not set, an empty Dictionary will be returned.
+ If {regname} is not specified, |v:register| is used.
+ The returned Dictionary can be passed to |setreg()|.
+
+ Can also be used as a |method|: >
+ GetRegname()->getreginfo()
getregtype([{regname}]) *getregtype()*
The result is a String, which is type of register {regname}.
@@ -4856,14 +5314,15 @@ getregtype([{regname}]) *getregtype()*
"<CTRL-V>{width}" for |blockwise-visual| text
"" for an empty or unknown register
<CTRL-V> is one character with value 0x16.
- If {regname} is not specified, |v:register| is used.
+ The {regname} argument is a string. If {regname} is not
+ specified, |v:register| is used.
-gettabinfo([{arg}]) *gettabinfo()*
- If {arg} is not specified, then information about all the tab
- pages is returned as a |List|. Each List item is a |Dictionary|.
- Otherwise, {arg} specifies the tab page number and information
- about that one is returned. If the tab page does not exist an
- empty List is returned.
+gettabinfo([{tabnr}]) *gettabinfo()*
+ If {tabnr} is not specified, then information about all the
+ tab pages is returned as a |List|. Each List item is a
+ |Dictionary|. Otherwise, {tabnr} specifies the tab page
+ number and information about that one is returned. If the tab
+ page does not exist an empty List is returned.
Each List item is a |Dictionary| with the following entries:
tabnr tab page number.
@@ -4875,8 +5334,8 @@ gettabvar({tabnr}, {varname} [, {def}]) *gettabvar()*
Get the value of a tab-local variable {varname} in tab page
{tabnr}. |t:var|
Tabs are numbered starting with one.
- When {varname} is empty a dictionary with all tab-local
- variables is returned.
+ The {varname} argument is a string. When {varname} is empty a
+ dictionary with all tab-local variables is returned.
Note that the name without "t:" must be used.
When the tab or variable doesn't exist {def} or an empty
string is returned, there is no error message.
@@ -4884,8 +5343,8 @@ gettabvar({tabnr}, {varname} [, {def}]) *gettabvar()*
gettabwinvar({tabnr}, {winnr}, {varname} [, {def}]) *gettabwinvar()*
Get the value of window-local variable {varname} in window
{winnr} in tab page {tabnr}.
- When {varname} is empty a dictionary with all window-local
- variables is returned.
+ The {varname} argument is a string. When {varname} is empty a
+ dictionary with all window-local variables is returned.
When {varname} is equal to "&" get the values of all
window-local options in a |Dictionary|.
Otherwise, when {varname} starts with "&" get the value of a
@@ -4907,11 +5366,11 @@ gettabwinvar({tabnr}, {winnr}, {varname} [, {def}]) *gettabwinvar()*
To obtain all window-local variables use: >
gettabwinvar({tabnr}, {winnr}, '&')
-gettagstack([{nr}]) *gettagstack()*
- The result is a Dict, which is the tag stack of window {nr}.
- {nr} can be the window number or the |window-ID|.
- When {nr} is not specified, the current window is used.
- When window {nr} doesn't exist, an empty Dict is returned.
+gettagstack([{winnr}]) *gettagstack()*
+ The result is a Dict, which is the tag stack of window {winnr}.
+ {winnr} can be the window number or the |window-ID|.
+ When {winnr} is not specified, the current window is used.
+ When window {winnr} doesn't exist, an empty Dict is returned.
The returned dictionary contains the following entries:
curidx Current index in the stack. When at
@@ -5040,22 +5499,22 @@ glob({expr} [, {nosuf} [, {list} [, {alllinks}]]]) *glob()*
See |expand()| for expanding special Vim variables. See
|system()| for getting the raw output of an external command.
-glob2regpat({expr}) *glob2regpat()*
+glob2regpat({string}) *glob2regpat()*
Convert a file pattern, as used by glob(), into a search
pattern. The result can be used to match with a string that
is a file name. E.g. >
if filename =~ glob2regpat('Make*.mak')
< This is equivalent to: >
if filename =~ '^Make.*\.mak$'
-< When {expr} is an empty string the result is "^$", match an
+< When {string} is an empty string the result is "^$", match an
empty string.
Note that the result depends on the system. On MS-Windows
a backslash usually means a path separator.
*globpath()*
globpath({path}, {expr} [, {nosuf} [, {list} [, {allinks}]]])
- Perform glob() on all directories in {path} and concatenate
- the results. Example: >
+ Perform glob() for String {expr} on all directories in {path}
+ and concatenate the results. Example: >
:echo globpath(&rtp, "syntax/c.vim")
<
{path} is a comma-separated list of directory names. Each
@@ -5149,7 +5608,11 @@ has({feature}) Returns 1 if {feature} is supported, 0 otherwise. The
has_key({dict}, {key}) *has_key()*
The result is a Number, which is TRUE if |Dictionary| {dict}
- has an entry with key {key}. FALSE otherwise.
+ has an entry with key {key}. FALSE otherwise. The {key}
+ argument is a string.
+
+ Can also be used as a |method|: >
+ mydict->has_key(key)
haslocaldir([{winnr}[, {tabnr}]]) *haslocaldir()*
The result is a Number, which is 1 when the tabpage or window
@@ -5171,6 +5634,7 @@ hasmapto({what} [, {mode} [, {abbr}]]) *hasmapto()*
that contains {what} in somewhere in the rhs (what it is
mapped to) and this mapping exists in one of the modes
indicated by {mode}.
+ The arguments {what} and {mode} are strings.
When {abbr} is there and it is |TRUE| use abbreviations
instead of mappings. Don't forget to specify Insert and/or
Command-line mode.
@@ -5291,17 +5755,14 @@ hostname() *hostname()*
which Vim is currently running. Machine names greater than
256 characters long are truncated.
-iconv({expr}, {from}, {to}) *iconv()*
- The result is a String, which is the text {expr} converted
+iconv({string}, {from}, {to}) *iconv()*
+ The result is a String, which is the text {string} converted
from encoding {from} to encoding {to}.
When the conversion completely fails an empty string is
returned. When some characters could not be converted they
are replaced with "?".
The encoding names are whatever the iconv() library function
can accept, see ":!man 3 iconv".
- Most conversions require Vim to be compiled with the |+iconv|
- feature. Otherwise only UTF-8 to latin1 conversion and back
- can be done.
Note that Vim uses UTF-8 for all Unicode encodings, conversion
from/to UCS-2 is automatically changed to use UTF-8. You
cannot use UCS-2 in a string anyway, because of the NUL bytes.
@@ -5314,17 +5775,21 @@ indent({lnum}) The result is a Number, which is indent of line {lnum} in the
When {lnum} is invalid -1 is returned.
-index({list}, {expr} [, {start} [, {ic}]]) *index()*
- Return the lowest index in |List| {list} where the item has a
- value equal to {expr}. There is no automatic conversion, so
- the String "4" is different from the Number 4. And the number
- 4 is different from the Float 4.0. The value of 'ignorecase'
- is not used here, case always matters.
+index({object}, {expr} [, {start} [, {ic}]]) *index()*
+ If {object} is a |List| return the lowest index where the item
+ has a value equal to {expr}. There is no automatic
+ conversion, so the String "4" is different from the Number 4.
+ And the Number 4 is different from the Float 4.0. The value
+ of 'ignorecase' is not used here, case always matters.
+
+ If {object} is a |Blob| return the lowest index where the byte
+ value is equal to {expr}.
+
If {start} is given then start looking at the item with index
{start} (may be negative for an item relative to the end).
When {ic} is given and it is |TRUE|, ignore case. Otherwise
case must match.
- -1 is returned when {expr} is not found in {list}.
+ -1 is returned when {expr} is not found in {object}.
Example: >
:let idx = index(words, "the")
:if index(numbers, 123) >= 0
@@ -5483,13 +5948,16 @@ inputsecret({prompt} [, {text}]) *inputsecret()*
typed on the command-line in response to the issued prompt.
NOTE: Command-line completion is not supported.
-insert({list}, {item} [, {idx}]) *insert()*
- Insert {item} at the start of |List| {list}.
+insert({object}, {item} [, {idx}]) *insert()*
+ When {object} is a |List| or a |Blob| insert {item} at the start
+ of it.
+
If {idx} is specified insert {item} before the item with index
{idx}. If {idx} is zero it goes before the first item, just
like omitting {idx}. A negative {idx} is also possible, see
|list-index|. -1 inserts just before the last item.
- Returns the resulting |List|. Examples: >
+
+ Returns the resulting |List| or |Blob|. Examples: >
:let mylist = insert([2, 3, 5], 1)
:call insert(mylist, 4, -1)
:call insert(mylist, 6, len(mylist))
@@ -5497,6 +5965,9 @@ insert({list}, {item} [, {idx}]) *insert()*
Note that when {item} is a |List| it is inserted as a single
item. Use |extend()| to concatenate |Lists|.
+ Can also be used as a |method|: >
+ mylist->insert(item)
+
interrupt() *interrupt()*
Interrupt script execution. It works more or less like the
user typing CTRL-C, most commands won't execute and control
@@ -5514,6 +5985,8 @@ invert({expr}) *invert()*
Bitwise invert. The argument is converted to a number. A
List, Dict or Float argument causes an error. Example: >
:let bits = invert(bits)
+< Can also be used as a |method|: >
+ :let bits = bits->invert()
isdirectory({directory}) *isdirectory()*
The result is a Number, which is |TRUE| when a directory
@@ -5529,11 +6002,15 @@ isinf({expr}) *isinf()*
:echo isinf(-1.0 / 0.0)
< -1
+ Can also be used as a |method|: >
+ Compute()->isinf()
+
islocked({expr}) *islocked()* *E786*
The result is a Number, which is |TRUE| when {expr} is the
name of a locked variable.
- {expr} must be the name of a variable, |List| item or
- |Dictionary| entry, not the variable itself! Example: >
+ The string argument {expr} must be the name of a variable,
+ |List| item or |Dictionary| entry, not the variable itself!
+ Example: >
:let alist = [0, ['a', 'b'], 2, 3]
:lockvar 1 alist
:echo islocked('alist') " 1
@@ -5544,16 +6021,16 @@ islocked({expr}) *islocked()* *E786*
id({expr}) *id()*
Returns a |String| which is a unique identifier of the
- container type (|List|, |Dict| and |Partial|). It is
+ container type (|List|, |Dict|, |Blob| and |Partial|). It is
guaranteed that for the mentioned types `id(v1) ==# id(v2)`
returns true iff `type(v1) == type(v2) && v1 is v2`.
- Note that |v:_null_string|, |v:_null_list|, and |v:_null_dict|
- have the same `id()` with different types because they are
- internally represented as a NULL pointers. `id()` returns a
- hexadecimal representanion of the pointers to the containers
- (i.e. like `0x994a40`), same as `printf("%p", {expr})`,
- but it is advised against counting on the exact format of
- return value.
+ Note that |v:_null_string|, |v:_null_list|, |v:_null_dict| and
+ |v:_null_blob| have the same `id()` with different types
+ because they are internally represented as NULL pointers.
+ `id()` returns a hexadecimal representanion of the pointers to
+ the containers (i.e. like `0x994a40`), same as `printf("%p",
+ {expr})`, but it is advised against counting on the exact
+ format of the return value.
It is not guaranteed that `id(no_longer_existing_container)`
will not be equal to some other `id()`: new containers may
@@ -5563,13 +6040,23 @@ items({dict}) *items()*
Return a |List| with all the key-value pairs of {dict}. Each
|List| item is a list with two items: the key of a {dict}
entry and the value of this entry. The |List| is in arbitrary
- order.
+ order. Also see |keys()| and |values()|.
+ Example: >
+ for [key, value] in items(mydict)
+ echo key . ': ' . value
+ endfor
+
+< Can also be used as a |method|: >
+ mydict->items()
isnan({expr}) *isnan()*
Return |TRUE| if {expr} is a float with value NaN. >
echo isnan(0.0 / 0.0)
< 1
+ Can also be used as a |method|: >
+ Compute()->isnan()
+
jobpid({job}) *jobpid()*
Return the PID (process id) of |job-id| {job}.
@@ -5641,6 +6128,9 @@ jobstart({cmd}[, {opts}]) *jobstart()*
before invoking `on_stderr`. |channel-buffered|
stdout_buffered: (boolean) Collect data until EOF (stream
closed) before invoking `on_stdout`. |channel-buffered|
+ stdin: (string) Either "pipe" (default) to connect the
+ job's stdin to a channel or "null" to disconnect
+ stdin.
width: (number) Width of the `pty` terminal.
{opts} is passed as |self| dictionary to the callback; the
@@ -5666,8 +6156,8 @@ jobwait({jobs}[, {timeout}]) *jobwait()*
Waits for jobs and their |on_exit| handlers to complete.
{jobs} is a List of |job-id|s to wait for.
- {timeout} is the maximum waiting time in milliseconds, -1
- means forever.
+ {timeout} is the maximum waiting time in milliseconds. If
+ omitted or -1, wait forever.
Timeout of 0 can be used to check the status of a job: >
let running = jobwait([{job-id}], 0)[0] == -1
@@ -5694,6 +6184,9 @@ join({list} [, {sep}]) *join()*
converted into a string like with |string()|.
The opposite function is |split()|.
+ Can also be used as a |method|: >
+ mylist->join()
+
json_decode({expr}) *json_decode()*
Convert {expr} from JSON object. Accepts |readfile()|-style
list as the input, as well as regular string. May output any
@@ -5720,12 +6213,16 @@ json_encode({expr}) *json_encode()*
surrogate pairs (such strings are not valid UTF-8 strings).
Non-printable characters are converted into "\u1234" escapes
or special escapes like "\t", other are dumped as-is.
+ |Blob|s are converted to arrays of the individual bytes.
keys({dict}) *keys()*
Return a |List| with all the keys of {dict}. The |List| is in
- arbitrary order.
+ arbitrary order. Also see |items()| and |values()|.
+
+ Can also be used as a |method|: >
+ mydict->keys()
- *len()* *E701*
+< *len()* *E701*
len({expr}) The result is a Number, which is the length of the argument.
When {expr} is a String or a Number the length in bytes is
used, as with |strlen()|.
@@ -5736,7 +6233,10 @@ len({expr}) The result is a Number, which is the length of the argument.
|Dictionary| is returned.
Otherwise an error is given.
- *libcall()* *E364* *E368*
+ Can also be used as a |method|: >
+ mylist->len()
+
+< *libcall()* *E364* *E368*
libcall({libname}, {funcname}, {argument})
Call function {funcname} in the run-time library {libname}
with single argument {argument}.
@@ -5790,7 +6290,8 @@ libcallnr({libname}, {funcname}, {argument})
<
*line()*
line({expr}) The result is a Number, which is the line number of the file
- position given with {expr}. The accepted positions are:
+ position given with {expr}. The {expr} argument is a string.
+ The accepted positions are:
. the cursor position
$ the last line in the current buffer
'x position of mark x (if the mark is not set, 0 is
@@ -5821,8 +6322,8 @@ line2byte({lnum}) *line2byte()*
line just below the last line: >
line2byte(line("$") + 1)
< This is the buffer size plus one. If 'fileencoding' is empty
- it is the file size plus one.
- When {lnum} is invalid -1 is returned.
+ it is the file size plus one. {lnum} is used like with
+ |getline()|. When {lnum} is invalid -1 is returned.
Also see |byte2line()|, |go| and |:goto|.
lispindent({lnum}) *lispindent()*
@@ -5830,8 +6331,7 @@ lispindent({lnum}) *lispindent()*
indenting rules, as with 'lisp'.
The indent is counted in spaces, the value of 'tabstop' is
relevant. {lnum} is used just like in |getline()|.
- When {lnum} is invalid or Vim was not compiled the
- |+lispindent| feature, -1 is returned.
+ When {lnum} is invalid, -1 is returned.
list2str({list} [, {utf8}]) *list2str()*
Convert each number in {list} to a character string can
@@ -5862,6 +6362,8 @@ log({expr}) *log()*
:echo log(exp(5))
< 5.0
+ Can also be used as a |method|: >
+ Compute()->log()
log10({expr}) *log10()*
Return the logarithm of Float {expr} to base 10 as a |Float|.
@@ -5872,19 +6374,25 @@ log10({expr}) *log10()*
:echo log10(0.01)
< -2.0
+ Can also be used as a |method|: >
+ Compute()->log10()
+
luaeval({expr}[, {expr}])
Evaluate Lua expression {expr} and return its result converted
to Vim data structures. See |lua-eval| for more details.
map({expr1}, {expr2}) *map()*
- {expr1} must be a |List| or a |Dictionary|.
+ {expr1} must be a |List|, |Blob| or |Dictionary|.
Replace each item in {expr1} with the result of evaluating
- {expr2}. {expr2} must be a |string| or |Funcref|.
+ {expr2}. For a |Blob| each byte is replaced.
+
+ {expr2} must be a |string| or |Funcref|.
If {expr2} is a |string|, inside {expr2} |v:val| has the value
- of the current item. For a |Dictionary| |v:key| has the key
+ of the current item. For a |Dictionary| |v:key| has the key
of the current item and for a |List| |v:key| has the index of
- the current item.
+ the current item. For a |Blob| |v:key| has the index of the
+ current byte.
Example: >
:call map(mylist, '"> " . v:val . " <"')
< This puts "> " before and " <" after each item in "mylist".
@@ -5914,12 +6422,14 @@ map({expr1}, {expr2}) *map()*
|Dictionary| to remain unmodified make a copy first: >
:let tlist = map(copy(mylist), ' v:val . "\t"')
-< Returns {expr1}, the |List| or |Dictionary| that was filtered.
- When an error is encountered while evaluating {expr2} no
- further items in {expr1} are processed. When {expr2} is a
- Funcref errors inside a function are ignored, unless it was
- defined with the "abort" flag.
+< Returns {expr1}, the |List|, |Blob| or |Dictionary| that was
+ filtered. When an error is encountered while evaluating
+ {expr2} no further items in {expr1} are processed. When
+ {expr2} is a Funcref errors inside a function are ignored,
+ unless it was defined with the "abort" flag.
+ Can also be used as a |method|: >
+ mylist->map(expr2)
maparg({name} [, {mode} [, {abbr} [, {dict}]]]) *maparg()*
When {dict} is omitted or zero: Return the rhs of mapping
@@ -6179,7 +6689,7 @@ matcharg({nr}) *matcharg()*
Highlighting matches using the |:match| commands are limited
to three matches. |matchadd()| does not have this limitation.
-matchdelete({id} [, {win}) *matchdelete()* *E802* *E803*
+matchdelete({id} [, {win}]) *matchdelete()* *E802* *E803*
Deletes a match with ID {id} previously defined by |matchadd()|
or one of the |:match| commands. Returns 0 if successful,
otherwise -1. See example for |matchadd()|. All matches can
@@ -6255,7 +6765,10 @@ max({expr}) Return the maximum value of all items in {expr}.
items in {expr} cannot be used as a Number this results in
an error. An empty |List| or |Dictionary| results in zero.
-menu_get({path}, {modes}) *menu_get()*
+ Can also be used as a |method|: >
+ mylist->max()
+
+menu_get({path} [, {modes}]) *menu_get()*
Returns a |List| of |Dictionaries| describing |menus| (defined
by |:menu|, |:amenu|, …), including |hidden-menus|.
@@ -6309,15 +6822,18 @@ min({expr}) Return the minimum value of all items in {expr}.
items in {expr} cannot be used as a Number this results in
an error. An empty |List| or |Dictionary| results in zero.
- *mkdir()* *E739*
+ Can also be used as a |method|: >
+ mylist->min()
+
+< *mkdir()* *E739*
mkdir({name} [, {path} [, {prot}]])
Create directory {name}.
If {path} is "p" then intermediate directories are created as
necessary. Otherwise it must be "".
If {prot} is given it is used to set the protection bits of
- the new directory. The default is 0755 (rwxr-xr-x: r/w for
- the user readable for others). Use 0700 to make it unreadable
- for others.
+ the new directory. The default is 0o755 (rwxr-xr-x: r/w for
+ the user, readable for others). Use 0o700 to make it
+ unreadable for others.
{prot} is applied for all parts of {name}. Thus if you create
/tmp/foo/bar then /tmp/foo will be created with 0700. Example: >
@@ -6352,6 +6868,10 @@ mode([expr]) Return a string that indicates the current mode.
s Select by character
S Select by line
CTRL-S Select blockwise
+ vs Visual by character using |v_CTRL-O| from
+ Select mode
+ Vs Visual by line using |v_CTRL-O| from Select mode
+ CTRL-Vs Visual blockwise using |v_CTRL-O| from Select mode
i Insert
ic Insert mode completion |compl-generic|
ix Insert mode |i_CTRL-X| completion
@@ -6360,8 +6880,7 @@ mode([expr]) Return a string that indicates the current mode.
Rv Virtual Replace |gR|
Rx Replace mode |i_CTRL-X| completion
c Command-line editing
- cv Vim Ex mode |gQ|
- ce Normal Ex mode |Q|
+ cv Vim Ex mode |Q| or |gQ|
r Hit-enter prompt
rm The -- more -- prompt
r? |:confirm| query of some sort
@@ -6375,11 +6894,15 @@ mode([expr]) Return a string that indicates the current mode.
the leading character(s).
Also see |visualmode()|.
-msgpackdump({list}) *msgpackdump()*
- Convert a list of VimL objects to msgpack. Returned value is
- |readfile()|-style list. Example: >
+msgpackdump({list} [, {type}]) *msgpackdump()*
+ Convert a list of VimL objects to msgpack. Returned value is a
+ |readfile()|-style list. When {type} contains "B", a |Blob| is
+ returned instead. Example: >
call writefile(msgpackdump([{}]), 'fname.mpack', 'b')
-< This will write the single 0x80 byte to `fname.mpack` file
+< or, using a |Blob|: >
+ call writefile(msgpackdump([{}], 'B'), 'fname.mpack')
+<
+ This will write the single 0x80 byte to a `fname.mpack` file
(dictionary with zero items is represented by 0x80 byte in
messagepack).
@@ -6387,11 +6910,12 @@ msgpackdump({list}) *msgpackdump()*
1. |Funcref|s cannot be dumped.
2. Containers that reference themselves cannot be dumped.
3. Dictionary keys are always dumped as STR strings.
- 4. Other strings are always dumped as BIN strings.
+ 4. Other strings and |Blob|s are always dumped as BIN strings.
5. Points 3. and 4. do not apply to |msgpack-special-dict|s.
-msgpackparse({list}) *msgpackparse()*
- Convert a |readfile()|-style list to a list of VimL objects.
+msgpackparse({data}) *msgpackparse()*
+ Convert a |readfile()|-style list or a |Blob| to a list of
+ VimL objects.
Example: >
let fname = expand('~/.config/nvim/shada/main.shada')
let mpack = readfile(fname, 'b')
@@ -6401,7 +6925,7 @@ msgpackparse({list}) *msgpackparse()*
Limitations:
1. Mapping ordering is not preserved unless messagepack
- mapping is dumped using generic mapping
+ mapping is dumped using generic mapping
(|msgpack-special-map|).
2. Since the parser aims to preserve all data untouched
(except for 1.) some strings are parsed to
@@ -6445,9 +6969,9 @@ msgpackparse({list}) *msgpackparse()*
zero byte or if string is a mapping key and mapping is
being represented as special dictionary for other
reasons.
- binary |readfile()|-style list of strings. This value will
- appear in |msgpackparse()| output if binary string
- contains zero byte.
+ binary |String|, or |Blob| if binary string contains zero
+ byte. This value cannot appear in |msgpackparse()|
+ output since blobs were introduced.
array |List|. This value cannot appear in |msgpackparse()|
output.
*msgpack-special-map*
@@ -6469,6 +6993,7 @@ nextnonblank({lnum}) *nextnonblank()*
if getline(nextnonblank(1)) =~ "Java"
< When {lnum} is invalid or there is no non-blank line at or
below it, zero is returned.
+ {lnum} is used like with |getline()|.
See also |prevnonblank()|.
nr2char({expr} [, {utf8}]) *nr2char()*
@@ -6501,10 +7026,11 @@ or({expr}, {expr}) *or()*
to a number. A List, Dict or Float argument causes an error.
Example: >
:let bits = or(bits, 0x80)
+< Can also be used as a |method|: >
+ :let bits = bits->or(0x80)
-
-pathshorten({expr}) *pathshorten()*
- Shorten directory names in the path {expr} and return the
+pathshorten({path}) *pathshorten()*
+ Shorten directory names in the path {path} and return the
result. The tail, the file name, is kept as-is. The other
components in the path are reduced to single letters. Leading
'~' and '.' characters are kept. Example: >
@@ -6538,12 +7064,16 @@ pow({x}, {y}) *pow()*
:echo pow(32, 0.20)
< 2.0
+ Can also be used as a |method|: >
+ Compute()->pow(3)
+
prevnonblank({lnum}) *prevnonblank()*
Return the line number of the first line at or above {lnum}
that is not blank. Example: >
let ind = indent(prevnonblank(v:lnum - 1))
< When {lnum} is invalid or there is no non-blank line at or
above it, zero is returned.
+ {lnum} is used like with |getline()|.
Also see |nextnonblank()|.
@@ -6554,7 +7084,11 @@ printf({fmt}, {expr1} ...) *printf()*
< May result in:
" 99: E42 asdfasdfasdfasdfasdfasdfasdfas" ~
- Often used items are:
+ When used as a |method| the base is passed as the second
+ argument: >
+ Compute()->printf("result: %d")
+
+< Often used items are:
%s string
%6S string right-aligned in 6 display cells
%6s string right-aligned in 6 bytes
@@ -6882,16 +7416,18 @@ readdir({directory} [, {expr}])
echo s:tree(".")
<
*readfile()*
-readfile({fname} [, {binary} [, {max}]])
+readfile({fname} [, {type} [, {max}]])
Read file {fname} and return a |List|, each line of the file
as an item. Lines are broken at NL characters. Macintosh
files separated with CR will result in a single long line
(unless a NL appears somewhere).
All NUL characters are replaced with a NL character.
- When {binary} contains "b" binary mode is used:
+ When {type} contains "b" binary mode is used:
- When the last line ends in a NL an extra empty list item is
added.
- No CR characters are removed.
+ When {type} contains "B" a |Blob| is returned with the binary
+ data of the file unmodified.
Otherwise:
- CR characters that appear before a NL are removed.
- Whether the last line ends in a NL or not does not matter.
@@ -6949,7 +7485,8 @@ reltimefloat({time}) *reltimefloat()*
call MyFunction()
let seconds = reltimefloat(reltime(start))
See the note of reltimestr() about overhead.
- Also see |profiling|.
+ Also see |profiling|.
+ If there is an error an empty string is returned
reltimestr({time}) *reltimestr()*
Return a String that represents the time value of {time}.
@@ -6963,6 +7500,7 @@ reltimestr({time}) *reltimestr()*
can use split() to remove it. >
echo split(reltimestr(reltime(start)))[0]
< Also see |profiling|.
+ If there is an error an empty string is returned
*remote_expr()* *E449*
remote_expr({server}, {string} [, {idvar} [, {timeout}]])
@@ -6993,6 +7531,7 @@ remote_expr({server}, {string} [, {idvar} [, {timeout}]])
remote_foreground({server}) *remote_foreground()*
Move the Vim server with the name {server} to the foreground.
+ The {server} argument is a string.
This works like: >
remote_expr({server}, "foreground()")
< Except that on Win32 systems the client does the work, to work
@@ -7064,6 +7603,21 @@ remove({list}, {idx} [, {end}]) *remove()*
Example: >
:echo "last item: " . remove(mylist, -1)
:call remove(mylist, 0, 9)
+
+< Can also be used as a |method|: >
+ mylist->remove(idx)
+
+remove({blob}, {idx} [, {end}])
+ Without {end}: Remove the byte at {idx} from |Blob| {blob} and
+ return the byte.
+ With {end}: Remove bytes from {idx} to {end} (inclusive) and
+ return a |Blob| with these bytes. When {idx} points to the same
+ byte as {end} a |Blob| with one byte is returned. When {end}
+ points to a byte before {idx} this is an error.
+ Example: >
+ :echo "last byte: " . remove(myblob, -1)
+ :call remove(mylist, 0, 9)
+
remove({dict}, {key})
Remove the entry from {dict} with key {key} and return it.
Example: >
@@ -7090,6 +7644,8 @@ repeat({expr}, {count}) *repeat()*
:let longlist = repeat(['a', 'b'], 3)
< Results in ['a', 'b', 'a', 'b', 'a', 'b'].
+ Can also be used as a |method|: >
+ mylist->repeat(count)
resolve({filename}) *resolve()* *E655*
On MS-Windows, when {filename} is a shortcut (a .lnk file),
@@ -7105,10 +7661,14 @@ resolve({filename}) *resolve()* *E655*
path name) and also keeps a trailing path separator.
*reverse()*
-reverse({list}) Reverse the order of items in {list} in-place. Returns
- {list}.
- If you want a list to remain unmodified make a copy first: >
+reverse({object})
+ Reverse the order of items in {object} in-place.
+ {object} can be a |List| or a |Blob|.
+ Returns {object}.
+ If you want an object to remain unmodified make a copy first: >
:let revlist = reverse(copy(mylist))
+< Can also be used as a |method|: >
+ mylist->reverse()
round({expr}) *round()*
Round off {expr} to the nearest integral value and return it
@@ -7123,6 +7683,9 @@ round({expr}) *round()*
echo round(-4.5)
< -5.0
+ Can also be used as a |method|: >
+ Compute()->round()
+
rpcnotify({channel}, {event}[, {args}...]) *rpcnotify()*
Sends {event} to {channel} via |RPC| and returns immediately.
If {channel} is 0, the event is broadcast to all channels.
@@ -7150,7 +7713,6 @@ rubyeval({expr}) *rubyeval()*
Hashes are represented as Vim |Dictionary| type.
Other objects are represented as strings resulted from their
"Object#to_s" method.
- {only available when compiled with the |+ruby| feature}
screenattr({row}, {col}) *screenattr()*
Like |screenchar()|, but return the attribute. This is a rather
@@ -7167,6 +7729,13 @@ screenchar({row}, {col}) *screenchar()*
This is mainly to be used for testing.
Returns -1 when row or col is out of range.
+screenchars({row}, {col}) *screenchars()*
+ The result is a List of Numbers. The first number is the same
+ as what |screenchar()| returns. Further numbers are
+ composing characters on top of the base character.
+ This is mainly to be used for testing.
+ Returns an empty List when row or col is out of range.
+
screencol() *screencol()*
The result is a Number, which is the current screen column of
the cursor. The leftmost column has number 1.
@@ -7197,6 +7766,10 @@ screenpos({winid}, {lnum}, {col}) *screenpos()*
The "curscol" value is where the cursor would be placed. For
a Tab it would be the same as "endcol", while for a double
width character it would be the same as "col".
+ The |conceal| feature is ignored here, the column numbers are
+ as if 'conceallevel' is zero. You can set the cursor to the
+ right position and use |screencol()| to get the value with
+ |conceal| taken into account.
screenrow() *screenrow()*
The result is a Number, which is the current screen row of the
@@ -7206,6 +7779,14 @@ screenrow() *screenrow()*
Note: Same restrictions as with |screencol()|.
+screenstring({row}, {col}) *screenstring()*
+ The result is a String that contains the base character and
+ any composing characters at position [row, col] on the screen.
+ This is like |screenchars()| but returning a String with the
+ characters.
+ This is mainly to be used for testing.
+ Returns an empty String when row or col is out of range.
+
search({pattern} [, {flags} [, {stopline} [, {timeout}]]]) *search()*
Search for regexp pattern {pattern}. The search starts at the
cursor position (you can use |cursor()| to set it).
@@ -7601,8 +8182,8 @@ serverstop({address}) *serverstop()*
If |v:servername| is stopped it is set to the next available
address returned by |serverlist()|.
-setbufline({expr}, {lnum}, {text}) *setbufline()*
- Set line {lnum} to {text} in buffer {expr}. This works like
+setbufline({buf}, {lnum}, {text}) *setbufline()*
+ Set line {lnum} to {text} in buffer {buf}. This works like
|setline()| for the specified buffer.
This function works only for loaded buffers. First call
@@ -7615,23 +8196,24 @@ setbufline({expr}, {lnum}, {text}) *setbufline()*
to set multiple lines. If the list extends below the last
line then those lines are added.
- For the use of {expr}, see |bufname()| above.
+ For the use of {buf}, see |bufname()| above.
{lnum} is used like with |setline()|.
When {lnum} is just below the last line the {text} will be
added below the last line.
On success 0 is returned, on failure 1 is returned.
- If {expr} is not a valid buffer or {lnum} is not valid, an
+ If {buf} is not a valid buffer or {lnum} is not valid, an
error message is given.
-setbufvar({expr}, {varname}, {val}) *setbufvar()*
- Set option or local variable {varname} in buffer {expr} to
+setbufvar({buf}, {varname}, {val}) *setbufvar()*
+ Set option or local variable {varname} in buffer {buf} to
{val}.
This also works for a global or local window option, but it
doesn't work for a global or local window variable.
For a local window option the global value is unchanged.
- For the use of {expr}, see |bufname()| above.
+ For the use of {buf}, see |bufname()| above.
+ The {varname} argument is a string.
Note that the variable name without "b:" must be used.
Examples: >
:call setbufvar(1, "&mod", 1)
@@ -7674,8 +8256,10 @@ setcmdpos({pos}) *setcmdpos()*
command line.
setenv({name}, {val}) *setenv()*
- Set environment variable {name} to {val}.
- When {val} is |v:null| the environment variable is deleted.
+ Set environment variable {name} to {val}. Example: >
+ call setenv('HOME', '/home/myhome')
+
+< When {val} is |v:null| the environment variable is deleted.
See also |expr-env|.
setfperm({fname}, {mode}) *setfperm()* *chmod*
@@ -7746,7 +8330,7 @@ setmatches({list} [, {win}]) *setmatches()*
*setpos()*
setpos({expr}, {list})
- Set the position for {expr}. Possible values:
+ Set the position for String {expr}. Possible values:
. the cursor
'x mark x
@@ -7907,9 +8491,10 @@ setqflist({list} [, {action}[, {what}]]) *setqflist()*
*setreg()*
setreg({regname}, {value} [, {options}])
Set the register {regname} to {value}.
+ The {regname} argument is a string.
- {value} may be any value returned by |getreg()|, including
- a |List|.
+ {value} may be any value returned by |getreg()| or
+ |getreginfo()|, including a |List| or |Dict|.
If {options} contains "a" or {regname} is upper case,
then the value is appended.
@@ -7939,9 +8524,13 @@ setreg({regname}, {value} [, {options}])
:call setreg(v:register, @*)
:call setreg('*', @%, 'ac')
:call setreg('a', "1\n2\n3", 'b5')
+ :call setreg('"', { 'points_to': 'a'})
< This example shows using the functions to save and restore a
register: >
+ :let var_a = getreginfo()
+ :call setreg('a', var_a)
+< or: >
:let var_a = getreg('a', 1, 1)
:let var_amode = getregtype('a')
....
@@ -7958,6 +8547,7 @@ setreg({regname}, {value} [, {options}])
settabvar({tabnr}, {varname}, {val}) *settabvar()*
Set tab-local variable {varname} to {val} in tab page {tabnr}.
|t:var|
+ The {varname} argument is a string.
Note that the variable name without "t:" must be used.
Tabs are numbered starting with one.
This function is not available in the |sandbox|.
@@ -8042,6 +8632,10 @@ shellescape({string} [, {special}]) *shellescape()*
- The <NL> character is escaped (twice if {special} is
a ||non-zero-arg|).
+ If 'shell' contains "fish" in the tail, the "\" character will
+ be escaped because in fish it is used as an escape character
+ inside single quotes.
+
Example of use with a |:!| command: >
:exe '!dir ' . shellescape(expand('<cfile>'), 1)
< This results in a directory listing for the file under the
@@ -8100,6 +8694,8 @@ sin({expr}) *sin()*
:echo sin(-4.01)
< 0.763301
+ Can also be used as a |method|: >
+ Compute()->sin()
sinh({expr}) *sinh()*
Return the hyperbolic sine of {expr} as a |Float| in the range
@@ -8111,7 +8707,10 @@ sinh({expr}) *sinh()*
:echo sinh(-0.9)
< -1.026517
-sockconnect({mode}, {address}, {opts}) *sockconnect()*
+ Can also be used as a |method|: >
+ Compute()->sinh()
+
+sockconnect({mode}, {address} [, {opts}]) *sockconnect()*
Connect a socket to an address. If {mode} is "pipe" then
{address} should be the path of a named pipe. If {mode} is
"tcp" then {address} should be of the form "host:port" where
@@ -8123,7 +8722,7 @@ sockconnect({mode}, {address}, {opts}) *sockconnect()*
|rpcrequest()| and |rpcnotify()| to communicate with a RPC
socket.
- {opts} is a dictionary with these keys:
+ {opts} is an optional dictionary with these keys:
|on_data| : callback invoked when data was read from socket
data_buffered : read socket data in |channel-buffered| mode.
rpc : If set, |msgpack-rpc| will be used to communicate
@@ -8189,18 +8788,23 @@ sort({list} [, {func} [, {dict}]]) *sort()* *E702*
on numbers, text strings will sort next to each other, in the
same order as they were originally.
- Also see |uniq()|.
+ Can also be used as a |method|: >
+ mylist->sort()
+
+< Also see |uniq()|.
Example: >
func MyCompare(i1, i2)
return a:i1 == a:i2 ? 0 : a:i1 > a:i2 ? 1 : -1
endfunc
- let sortedlist = sort(mylist, "MyCompare")
+ eval mylist->sort("MyCompare")
< A shorter compare version for this specific simple case, which
ignores overflow: >
func MyCompare(i1, i2)
return a:i1 - a:i2
endfunc
+< For a simple expression you can use a lambda: >
+ eval mylist->sort({i1, i2 -> i1 - i2})
<
*soundfold()*
soundfold({word})
@@ -8259,8 +8863,8 @@ spellsuggest({word} [, {max} [, {capital}]])
values of 'spelllang' and 'spellsuggest' are used.
-split({expr} [, {pattern} [, {keepempty}]]) *split()*
- Make a |List| out of {expr}. When {pattern} is omitted or
+split({string} [, {pattern} [, {keepempty}]]) *split()*
+ Make a |List| out of {string}. When {pattern} is omitted or
empty each white-separated sequence of characters becomes an
item.
Otherwise the string is split where {pattern} matches,
@@ -8282,6 +8886,8 @@ split({expr} [, {pattern} [, {keepempty}]]) *split()*
:let items = split(line, ':', 1)
< The opposite function is |join()|.
+ Can also be used as a |method|: >
+ GetString()->split()
sqrt({expr}) *sqrt()*
Return the non-negative square root of Float {expr} as a
@@ -8295,6 +8901,8 @@ sqrt({expr}) *sqrt()*
< nan
"nan" may be different, it depends on system libraries.
+ Can also be used as a |method|: >
+ Compute()->sqrt()
stdioopen({opts}) *stdioopen()*
With |--headless| this opens stdin and stdout as a |channel|.
@@ -8333,23 +8941,29 @@ stdpath({what}) *stdpath()* *E6100*
:echo stdpath("config")
-str2float({expr}) *str2float()*
- Convert String {expr} to a Float. This mostly works the same
- as when using a floating point number in an expression, see
- |floating-point-format|. But it's a bit more permissive.
- E.g., "1e40" is accepted, while in an expression you need to
- write "1.0e40". The hexadecimal form "0x123" is also
- accepted, but not others, like binary or octal.
+str2float({string} [, {quoted}]) *str2float()*
+ Convert String {string} to a Float. This mostly works the
+ same as when using a floating point number in an expression,
+ see |floating-point-format|. But it's a bit more permissive.
+ E.g., "1e40" is accepted, while in an expression you need to
+ write "1.0e40". The hexadecimal form "0x123" is also
+ accepted, but not others, like binary or octal.
+ When {quoted} is present and non-zero then embedded single
+ quotes before the dot are ignored, thus "1'000.0" is a
+ thousand.
Text after the number is silently ignored.
The decimal point is always '.', no matter what the locale is
set to. A comma ends the number: "12,345.67" is converted to
12.0. You can strip out thousands separators with
|substitute()|: >
let f = str2float(substitute(text, ',', '', 'g'))
+<
+ Can also be used as a |method|: >
+ let f = text->substitute(',', '', 'g')->str2float()
-str2list({expr} [, {utf8}]) *str2list()*
+str2list({string} [, {utf8}]) *str2list()*
Return a list containing the number values which represent
- each character in String {expr}. Examples: >
+ each character in String {string}. Examples: >
str2list(" ") returns [32]
str2list("ABC") returns [65, 66, 67]
< |list2str()| does the opposite.
@@ -8360,22 +8974,30 @@ str2list({expr} [, {utf8}]) *str2list()*
properly: >
str2list("á") returns [97, 769]
-str2nr({expr} [, {base}]) *str2nr()*
- Convert string {expr} to a number.
+< Can also be used as a |method|: >
+ GetString()->str2list()
+
+str2nr({string} [, {base}]) *str2nr()*
+ Convert string {string} to a number.
{base} is the conversion base, it can be 2, 8, 10 or 16.
+ When {quoted} is present and non-zero then embedded single
+ quotes are ignored, thus "1'000'000" is a million.
+
When {base} is omitted base 10 is used. This also means that
a leading zero doesn't cause octal conversion to be used, as
- with the default String to Number conversion.
+ with the default String to Number conversion. Example: >
+ let nr = str2nr('123')
+<
When {base} is 16 a leading "0x" or "0X" is ignored. With a
- different base the result will be zero. Similarly, when {base}
- is 8 a leading "0" is ignored, and when {base} is 2 a leading
- "0b" or "0B" is ignored.
+ different base the result will be zero. Similarly, when
+ {base} is 8 a leading "0", "0o" or "0O" is ignored, and when
+ {base} is 2 a leading "0b" or "0B" is ignored.
Text after the number is silently ignored.
-strchars({expr} [, {skipcc}]) *strchars()*
+strchars({string} [, {skipcc}]) *strchars()*
The result is a Number, which is the number of characters
- in String {expr}.
+ in String {string}.
When {skipcc} is omitted or zero, composing characters are
counted separately.
When {skipcc} set to 1, Composing characters are ignored.
@@ -8406,16 +9028,16 @@ strcharpart({src}, {start} [, {len}]) *strcharpart()*
strcharpart('abc', -1, 2)
< results in 'a'.
-strdisplaywidth({expr} [, {col}]) *strdisplaywidth()*
+strdisplaywidth({string} [, {col}]) *strdisplaywidth()*
The result is a Number, which is the number of display cells
- String {expr} occupies on the screen when it starts at {col}
+ String {string} occupies on the screen when it starts at {col}
(first column is zero). When {col} is omitted zero is used.
Otherwise it is the screen column where to start. This
matters for Tab characters.
The option settings of the current window are used. This
matters for anything that's displayed differently, such as
'tabstop' and 'display'.
- When {expr} contains characters with East Asian Width Class
+ When {string} contains characters with East Asian Width Class
Ambiguous, this function's return value depends on 'ambiwidth'.
Also see |strlen()|, |strwidth()| and |strchars()|.
@@ -8463,14 +9085,15 @@ stridx({haystack}, {needle} [, {start}]) *stridx()*
*string()*
string({expr}) Return {expr} converted to a String. If {expr} is a Number,
- Float, String or a composition of them, then the result can be
- parsed back with |eval()|.
+ Float, String, Blob or a composition of them, then the result
+ can be parsed back with |eval()|.
{expr} type result ~
String 'string'
Number 123
Float 123.123456 or 1.123456e8 or
`str2float('inf')`
Funcref `function('name')`
+ Blob 0z00112233.44556677.8899
List [item, item]
Dictionary {key: value, key: value}
Note that in String values the ' character is doubled.
@@ -8484,15 +9107,21 @@ string({expr}) Return {expr} converted to a String. If {expr} is a Number,
method, use |msgpackdump()| or |json_encode()| if you need to
share data with other application.
- *strlen()*
-strlen({expr}) The result is a Number, which is the length of the String
- {expr} in bytes.
+ Can also be used as a |method|: >
+ mylist->string()
+
+strlen({string}) *strlen()*
+ The result is a Number, which is the length of the String
+ {string} in bytes.
If the argument is a Number it is first converted to a String.
For other types an error is given.
If you want to count the number of multibyte characters use
|strchars()|.
Also see |len()|, |strdisplaywidth()| and |strwidth()|.
+ Can also be used as a |method|: >
+ GetString()->strlen()
+
strpart({src}, {start} [, {len} [, {chars}]]) *strpart()*
The result is a String, which is part of {src}, starting from
byte {start}, with the byte length {len}.
@@ -8559,22 +9188,28 @@ strridx({haystack}, {needle} [, {start}]) *strridx()*
When used with a single character it works similar to the C
function strrchr().
-strtrans({expr}) *strtrans()*
- The result is a String, which is {expr} with all unprintable
+strtrans({string}) *strtrans()*
+ The result is a String, which is {string} with all unprintable
characters translated into printable characters |'isprint'|.
Like they are shown in a window. Example: >
echo strtrans(@a)
< This displays a newline in register a as "^@" instead of
starting a new line.
-strwidth({expr}) *strwidth()*
+ Can also be used as a |method|: >
+ GetString()->strtrans()
+
+strwidth({string}) *strwidth()*
The result is a Number, which is the number of display cells
- String {expr} occupies. A Tab character is counted as one
+ String {string} occupies. A Tab character is counted as one
cell, alternatively use |strdisplaywidth()|.
- When {expr} contains characters with East Asian Width Class
+ When {string} contains characters with East Asian Width Class
Ambiguous, this function's return value depends on 'ambiwidth'.
Also see |strlen()|, |strdisplaywidth()| and |strchars()|.
+ Can also be used as a |method|: >
+ GetString()->strwidth()
+
submatch({nr} [, {list}]) *submatch()* *E935*
Only for an expression in a |:substitute| command or
substitute() function.
@@ -8601,10 +9236,10 @@ submatch({nr} [, {list}]) *submatch()* *E935*
< This finds the first number in the line and adds one to it.
A line break is included as a newline character.
-substitute({expr}, {pat}, {sub}, {flags}) *substitute()*
- The result is a String, which is a copy of {expr}, in which
+substitute({string}, {pat}, {sub}, {flags}) *substitute()*
+ The result is a String, which is a copy of {string}, in which
the first match of {pat} is replaced with {sub}.
- When {flags} is "g", all matches of {pat} in {expr} are
+ When {flags} is "g", all matches of {pat} in {string} are
replaced. Otherwise {flags} should be "".
This works like the ":substitute" command (without any flags).
@@ -8620,7 +9255,7 @@ substitute({expr}, {pat}, {sub}, {flags}) *substitute()*
|sub-replace-special|. For example, to replace something with
"\n" (two characters), use "\\\\n" or '\\n'.
- When {pat} does not match in {expr}, {expr} is returned
+ When {pat} does not match in {string}, {string} is returned
unmodified.
Example: >
@@ -8642,6 +9277,9 @@ substitute({expr}, {pat}, {sub}, {flags}) *substitute()*
|submatch()| returns. Example: >
:echo substitute(s, '%\(\x\x\)', {m -> '0x' . m[1]}, 'g')
+< Can also be used as a |method|: >
+ GetString()->substitute(pat, sub, flags)
+
swapinfo({fname}) *swapinfo()*
The result is a dictionary, which holds information about the
swapfile {fname}. The available fields are:
@@ -8660,12 +9298,12 @@ swapinfo({fname}) *swapinfo()*
Not a swap file: does not contain correct block ID
Magic number mismatch: Info in first block is invalid
-swapname({expr}) *swapname()*
- The result is the swap file path of the buffer {expr}.
- For the use of {expr}, see |bufname()| above.
- If buffer {expr} is the current buffer, the result is equal to
+swapname({buf}) *swapname()*
+ The result is the swap file path of the buffer {buf}.
+ For the use of {buf}, see |bufname()| above.
+ If buffer {buf} is the current buffer, the result is equal to
|:swapname| (unless there is no swap file).
- If buffer {expr} has no swap file, returns an empty string.
+ If buffer {buf} has no swap file, returns an empty string.
synID({lnum}, {col}, {trans}) *synID()*
The result is a Number, which is the syntax ID at the position
@@ -8677,7 +9315,7 @@ synID({lnum}, {col}, {trans}) *synID()*
line. 'synmaxcol' applies, in a longer line zero is returned.
Note that when the position is after the last character,
that's where the cursor can be in Insert mode, synID() returns
- zero.
+ zero. {lnum} is used like with |getline()|.
When {trans} is |TRUE|, transparent items are reduced to the
item that they reveal. This is useful when wanting to know
@@ -8726,17 +9364,23 @@ synIDattr({synID}, {what} [, {mode}]) *synIDattr()*
cursor): >
:echo synIDattr(synIDtrans(synID(line("."), col("."), 1)), "fg")
<
+ Can also be used as a |method|: >
+ :echo synID(line("."), col("."), 1)->synIDtrans()->synIDattr("fg")
+
synIDtrans({synID}) *synIDtrans()*
The result is a Number, which is the translated syntax ID of
{synID}. This is the syntax group ID of what is being used to
highlight the character. Highlight links given with
":highlight link" are followed.
+ Can also be used as a |method|: >
+ :echo synID(line("."), col("."), 1)->synIDtrans()->synIDattr("fg")
+
synconcealed({lnum}, {col}) *synconcealed()*
The result is a |List| with currently three items:
1. The first item in the list is 0 if the character at the
position {lnum} and {col} is not part of a concealable
- region, 1 if it is.
+ region, 1 if it is. {lnum} is used like with |getline()|.
2. The second item in the list is a string. If the first item
is 1, the second item contains the text which will be
displayed in place of the concealed text, depending on the
@@ -8760,8 +9404,9 @@ synconcealed({lnum}, {col}) *synconcealed()*
synstack({lnum}, {col}) *synstack()*
Return a |List|, which is the stack of syntax items at the
- position {lnum} and {col} in the current window. Each item in
- the List is an ID like what |synID()| returns.
+ position {lnum} and {col} in the current window. {lnum} is
+ used like with |getline()|. Each item in the List is an ID
+ like what |synID()| returns.
The first item in the List is the outer region, following are
items contained in that one. The last one is what |synID()|
returns, unless not the whole item is highlighted or it is a
@@ -8777,11 +9422,23 @@ synstack({lnum}, {col}) *synstack()*
valid positions.
system({cmd} [, {input}]) *system()* *E677*
- Get the output of {cmd} as a |string| (use |systemlist()| to
- get a |List|). {cmd} is treated exactly as in |jobstart()|.
- Not to be used for interactive commands.
+ Gets the output of {cmd} as a |string| (|systemlist()| returns
+ a |List|) and sets |v:shell_error| to the error code.
+ {cmd} is treated as in |jobstart()|:
+ If {cmd} is a List it runs directly (no 'shell').
+ If {cmd} is a String it runs in the 'shell', like this: >
+ :call jobstart(split(&shell) + split(&shellcmdflag) + ['{cmd}'])
+
+< Not to be used for interactive commands.
+
+ Result is a String, filtered to avoid platform-specific quirks:
+ - <CR><NL> is replaced with <NL>
+ - NUL characters are replaced with SOH (0x01)
+
+ Example: >
+ :echo system(['ls', expand('%:h')])
- If {input} is a string it is written to a pipe and passed as
+< If {input} is a string it is written to a pipe and passed as
stdin to the command. The string is written as-is, line
separators are not changed.
If {input} is a |List| it is written to the pipe as
@@ -8794,7 +9451,7 @@ system({cmd} [, {input}]) *system()* *E677*
*E5677*
Note: system() cannot write to or read from backgrounded ("&")
shell commands, e.g.: >
- :echo system("cat - &", "foo"))
+ :echo system("cat - &", "foo")
< which is equivalent to: >
$ echo foo | bash -c 'cat - &'
< The pipes are disconnected (unless overridden by shell
@@ -8803,31 +9460,16 @@ system({cmd} [, {input}]) *system()* *E677*
Note: Use |shellescape()| or |::S| with |expand()| or
|fnamemodify()| to escape special characters in a command
- argument. Newlines in {cmd} may cause the command to fail.
- The characters in 'shellquote' and 'shellxquote' may also
- cause trouble.
+ argument. 'shellquote' and 'shellxquote' must be properly
+ configured. Example: >
+ :echo system('ls '..shellescape(expand('%:h')))
+ :echo system('ls '..expand('%:h:S'))
- Result is a String. Example: >
- :let files = system("ls " . shellescape(expand('%:h')))
- :let files = system('ls ' . expand('%:h:S'))
-
-< To make the result more system-independent, the shell output
- is filtered to replace <CR> with <NL> for Macintosh, and
- <CR><NL> with <NL> for DOS-like systems.
- To avoid the string being truncated at a NUL, all NUL
- characters are replaced with SOH (0x01).
-
- The command executed is constructed using several options when
- {cmd} is a string: 'shell' 'shellcmdflag' {cmd}
-
- The resulting error code can be found in |v:shell_error|.
-
- Note that any wrong value in the options mentioned above may
- make the function fail. It has also been reported to fail
- when using a security agent application.
- Unlike ":!cmd" there is no automatic check for changed files.
+< Unlike ":!cmd" there is no automatic check for changed files.
Use |:checktime| to force a check.
+ Can also be used as a |method|: >
+ :echo GetCmd()->system()
systemlist({cmd} [, {input} [, {keepempty}]]) *systemlist()*
Same as |system()|, but returns a |List| with lines (parts of
@@ -8843,6 +9485,8 @@ systemlist({cmd} [, {input} [, {keepempty}]]) *systemlist()*
<
Returns an empty string on error.
+ Can also be used as a |method|: >
+ :echo GetCmd()->systemlist()
tabpagebuflist([{arg}]) *tabpagebuflist()*
The result is a |List|, where each item is the number of the
@@ -8966,6 +9610,8 @@ tan({expr}) *tan()*
:echo tan(-4.01)
< -1.181502
+ Can also be used as a |method|: >
+ Compute()->tan()
tanh({expr}) *tanh()*
Return the hyperbolic tangent of {expr} as a |Float| in the
@@ -8977,7 +9623,9 @@ tanh({expr}) *tanh()*
:echo tanh(-1)
< -0.761594
-
+ Can also be used as a |method|: >
+ Compute()->tanh()
+<
*timer_info()*
timer_info([{id}])
Return a list with information about timers.
@@ -9103,6 +9751,9 @@ trunc({expr}) *trunc()*
echo trunc(4.0)
< 4.0
+ Can also be used as a |method|: >
+ Compute()->trunc()
+
type({expr}) *type()*
The result is a Number representing the type of {expr}.
Instead of using the number directly, it is better to use the
@@ -9115,6 +9766,7 @@ type({expr}) *type()*
Float: 5 (|v:t_float|)
Boolean: 6 (|v:true| and |v:false|)
Null: 7 (|v:null|)
+ Blob: 10 (|v:t_blob|)
For backward compatibility, this method can be used: >
:if type(myvar) == type(0)
:if type(myvar) == type("")
@@ -9129,6 +9781,9 @@ type({expr}) *type()*
< To check if the v:t_ variables exist use this: >
:if exists('v:t_number')
+< Can also be used as a |method|: >
+ mylist->type()
+
undofile({name}) *undofile()*
Return the name of the undo file that would be used for a file
with name {name} when writing. This uses the 'undodir'
@@ -9139,8 +9794,6 @@ undofile({name}) *undofile()*
If {name} is empty undofile() returns an empty string, since a
buffer without a file name will not write an undo file.
Useful in combination with |:wundo| and |:rundo|.
- When compiled without the |+persistent_undo| option this always
- returns an empty string.
undotree() *undotree()*
Return the current state of the undo tree in a dictionary with
@@ -9193,10 +9846,15 @@ uniq({list} [, {func} [, {dict}]]) *uniq()* *E882*
< The default compare function uses the string representation of
each item. For the use of {func} and {dict} see |sort()|.
+ Can also be used as a |method|: >
+ mylist->uniq()
+
values({dict}) *values()*
Return a |List| with all the values of {dict}. The |List| is
- in arbitrary order.
+ in arbitrary order. Also see |items()| and |keys()|.
+ Can also be used as a |method|: >
+ mydict->values()
virtcol({expr}) *virtcol()*
The result is a Number, which is the screen column of the file
@@ -9305,10 +9963,12 @@ win_gettype([{nr}]) *win_gettype()*
Return the type of the window:
"autocmd" autocommand window. Temporary window
used to execute autocommands.
- "popup" popup window |popup|
- "preview" preview window |preview-window|
"command" command-line window |cmdwin|
(empty) normal window
+ "loclist" |location-list-window|
+ "popup" popup window |popup|
+ "preview" preview window |preview-window|
+ "quickfix" |quickfix-window|
"unknown" window {nr} not found
When {nr} is omitted return the type of the current window.
@@ -9339,7 +9999,7 @@ win_screenpos({nr}) *win_screenpos()*
[1, 1], unless there is a tabline, then it is [2, 1].
{nr} can be the window number or the |window-ID|. Use zero
for the current window.
- Return [0, 0] if the window cannot be found in the current
+ Returns [0, 0] if the window cannot be found in the current
tabpage.
win_splitmove({nr}, {target} [, {options}]) *win_splitmove()*
@@ -9372,6 +10032,9 @@ winbufnr({nr}) The result is a Number, which is the number of the buffer
Example: >
:echo "The file in the current window is " . bufname(winbufnr(0))
<
+ Can also be used as a |method|: >
+ FindWindow()->winbufnr()->bufname()
+<
*wincol()*
wincol() The result is a Number, which is the virtual column of the
cursor in the window. This is counting screen cells from the
@@ -9548,14 +10211,17 @@ wordcount() *wordcount()*
*writefile()*
-writefile({list}, {fname} [, {flags}])
- Write |List| {list} to file {fname}. Each list item is
- separated with a NL. Each list item must be a String or
- Number.
+writefile({object}, {fname} [, {flags}])
+ When {object} is a |List| write it to file {fname}. Each list
+ item is separated with a NL. Each list item must be a String
+ or Number.
When {flags} contains "b" then binary mode is used: There will
not be a NL after the last list item. An empty item at the
end does cause the last line in the file to end in a NL.
+ When {object} is a |Blob| write the bytes to file {fname}
+ unmodified.
+
When {flags} contains "a" then append mode is used, lines are
appended to the file: >
:call writefile(["foo"], "event.log", "a")
@@ -9585,6 +10251,8 @@ xor({expr}, {expr}) *xor()*
to a number. A List, Dict or Float argument causes an error.
Example: >
:let bits = xor(bits, 0x80)
+< Can also be used as a |method|: >
+ :let bits = bits->xor(0x80)
<
@@ -9922,7 +10590,9 @@ This function can then be called with: >
The recursiveness of user functions is restricted with the |'maxfuncdepth'|
option.
-It is also possible to use `:eval`. It does not support a range.
+It is also possible to use `:eval`. It does not support a range, but does
+allow for method chaining, e.g.: >
+ eval GetList()->Filter()->append('$')
AUTOMATICALLY LOADING FUNCTIONS ~
@@ -10067,7 +10737,10 @@ This does NOT work: >
This cannot be used to set a byte in a String. You
can do that like this: >
:let var = var[0:2] . 'X' . var[4:]
-<
+< When {var-name} is a |Blob| then {idx} can be the
+ length of the blob, in which case one byte is
+ appended.
+
*E711* *E719*
:let {var-name}[{idx1}:{idx2}] = {expr1} *E708* *E709* *E710*
Set a sequence of items in a |List| to the result of
@@ -10078,14 +10751,15 @@ This does NOT work: >
When the selected range of items is partly past the
end of the list, items will be added.
- *:let+=* *:let-=* *:letstar=*
- *:let/=* *:let%=* *:let.=* *E734*
+ *:let+=* *:let-=* *:letstar=*
+ *:let/=* *:let%=* *:let.=* *:let..=* *E734*
:let {var} += {expr1} Like ":let {var} = {var} + {expr1}".
:let {var} -= {expr1} Like ":let {var} = {var} - {expr1}".
:let {var} *= {expr1} Like ":let {var} = {var} * {expr1}".
:let {var} /= {expr1} Like ":let {var} = {var} / {expr1}".
:let {var} %= {expr1} Like ":let {var} = {var} % {expr1}".
:let {var} .= {expr1} Like ":let {var} = {var} . {expr1}".
+:let {var} ..= {expr1} Like ":let {var} = {var} .. {expr1}".
These fail if {var} was not set yet and when the type
of {var} and {expr1} don't fit the operator.
@@ -10303,10 +10977,18 @@ text...
:const x = 1
< is equivalent to: >
:let x = 1
- :lockvar 1 x
+ :lockvar! x
< This is useful if you want to make sure the variable
- is not modified.
- *E995*
+ is not modified. If the value is a List or Dictionary
+ literal then the items also cannot be changed: >
+ const ll = [1, 2, 3]
+ let ll[1] = 5 " Error!
+< Nested references are not locked: >
+ let lvar = ['a']
+ const lconst = [0, lvar]
+ let lconst[0] = 2 " Error!
+ let lconst[1][0] = 'b' " OK
+< *E995*
|:const| does not allow to for changing a variable. >
:let x = 1
:const x = 2 " Error!
@@ -10423,28 +11105,34 @@ text...
NOTE: The ":append" and ":insert" commands don't work
properly inside a ":while" and ":for" loop.
-:for {var} in {list} *:for* *E690* *E732*
+:for {var} in {object} *:for* *E690* *E732*
:endfo[r] *:endfo* *:endfor*
Repeat the commands between ":for" and ":endfor" for
- each item in {list}. Variable {var} is set to the
- value of each item.
- When an error is detected for a command inside the
- loop, execution continues after the "endfor".
- Changing {list} inside the loop affects what items are
- used. Make a copy if this is unwanted: >
+ each item in {object}. {object} can be a |List| or
+ a |Blob|. Variable {var} is set to the value of each
+ item. When an error is detected for a command inside
+ the loop, execution continues after the "endfor".
+ Changing {object} inside the loop affects what items
+ are used. Make a copy if this is unwanted: >
:for item in copy(mylist)
-< When not making a copy, Vim stores a reference to the
- next item in the list, before executing the commands
- with the current item. Thus the current item can be
- removed without effect. Removing any later item means
- it will not be found. Thus the following example
- works (an inefficient way to make a list empty): >
+<
+ When {object} is a |List| and not making a copy, Vim
+ stores a reference to the next item in the |List|
+ before executing the commands with the current item.
+ Thus the current item can be removed without effect.
+ Removing any later item means it will not be found.
+ Thus the following example works (an inefficient way
+ to make a |List| empty): >
for item in mylist
call remove(mylist, 0)
endfor
-< Note that reordering the list (e.g., with sort() or
+< Note that reordering the |List| (e.g., with sort() or
reverse()) may have unexpected effects.
+ When {object} is a |Blob|, Vim always makes a copy to
+ iterate over. Unlike with |List|, modifying the
+ |Blob| does not affect the iteration.
+
:for [{var1}, {var2}, ...] in {listlist}
:endfo[r]
Like ":for" above, but each item in {listlist} must be
@@ -10665,7 +11353,7 @@ text...
<
*:eval*
:eval {expr} Evaluate {expr} and discard the result. Example: >
- :eval append(Filter(Getlist()), '$')
+ :eval Getlist()->Filter()->append('$')
< The expression is supposed to have a side effect,
since the resulting value is not used. In the example
@@ -11704,7 +12392,7 @@ displayed.
*except-several-errors*
When several errors appear in a single command, the first error message is
-usually the most specific one and therefor converted to the error exception.
+usually the most specific one and therefore converted to the error exception.
Example: >
echo novar
causes >
@@ -11886,7 +12574,7 @@ Command-line expressions highlighting *expr-highlight*
Expressions entered by the user in |i_CTRL-R_=|, |c_CTRL-\_e|, |quote=| are
highlighted by the built-in expressions parser. It uses highlight groups
-described in the table below, which may be overriden by colorschemes.
+described in the table below, which may be overridden by colorschemes.
*hl-NvimInvalid*
Besides the "Nvim"-prefixed highlight groups described below, there are
"NvimInvalid"-prefixed highlight groups which have the same meaning but
diff --git a/runtime/doc/filetype.txt b/runtime/doc/filetype.txt
index 36ed6bbac1..a23ae3fb76 100644
--- a/runtime/doc/filetype.txt
+++ b/runtime/doc/filetype.txt
@@ -135,6 +135,7 @@ can be used to overrule the filetype used for certain extensions:
*.inc g:filetype_inc
*.w g:filetype_w |ft-cweb-syntax|
*.i g:filetype_i |ft-progress-syntax|
+ *.m g:filetype_m |ft-mathematica-syntax|
*.p g:filetype_p |ft-pascal-syntax|
*.pp g:filetype_pp |ft-pascal-syntax|
*.sh g:bash_is_sh |ft-sh-syntax|
@@ -500,6 +501,14 @@ One command, :DiffGitCached, is provided to show a diff of the current commit
in the preview window. It is equivalent to calling "git diff --cached" plus
any arguments given to the command.
+GPROF
+
+The gprof filetype plugin defines a mapping <C-]> to jump from a function
+entry in the gprof flat profile or from a function entry in the call graph
+to the details of that function in the call graph.
+
+The mapping can be disabled with: >
+ let g:no_gprof_maps = 1
MAIL *ft-mail-plugin*
@@ -580,7 +589,7 @@ To disable bold highlighting: >
MARKDOWN *ft-markdown-plugin*
To enable folding use this: >
- let g:markdown_folding = 1
+ let g:markdown_folding = 1
<
PDF *ft-pdf-plugin*
diff --git a/runtime/doc/fold.txt b/runtime/doc/fold.txt
index 8e2cb2f728..80c934d13b 100644
--- a/runtime/doc/fold.txt
+++ b/runtime/doc/fold.txt
@@ -535,6 +535,8 @@ nest, the nested fold is one character right of the fold it's contained in.
A closed fold is indicated with a '+'.
+These characters can be changed with the 'fillchars' option.
+
Where the fold column is too narrow to display all nested folds, digits are
shown to indicate the nesting level.
diff --git a/runtime/doc/ft_ps1.txt b/runtime/doc/ft_ps1.txt
index df1480b929..3eb89a4c24 100644
--- a/runtime/doc/ft_ps1.txt
+++ b/runtime/doc/ft_ps1.txt
@@ -1,4 +1,4 @@
-*ps1.txt* A Windows PowerShell syntax plugin for Vim
+*ft_ps1.txt* A Windows PowerShell syntax plugin for Vim
Author: Peter Provost <https://www.github.com/PProvost>
License: Apache 2.0
diff --git a/runtime/doc/ft_raku.txt b/runtime/doc/ft_raku.txt
index 26ada8a140..00b140ee9c 100644
--- a/runtime/doc/ft_raku.txt
+++ b/runtime/doc/ft_raku.txt
@@ -1,4 +1,4 @@
-*vim-raku.txt* The Raku programming language filetype
+*ft_raku.txt* The Raku programming language filetype
*vim-raku*
@@ -45,7 +45,7 @@ Numbers, subscripts and superscripts are available with 's' and 'S':
1s ₁ 1S ¹ ~
2s ₂ 9S ⁹ ~
-But some don´t come defined by default. Those are digraph definitions you can
+But some don't come defined by default. Those are digraph definitions you can
add in your ~/.vimrc file. >
exec 'digraph \\ '.char2nr('∖')
exec 'digraph \< '.char2nr('≼')
diff --git a/runtime/doc/ft_sql.txt b/runtime/doc/ft_sql.txt
index f38c8edbf3..53a99a9e1d 100644
--- a/runtime/doc/ft_sql.txt
+++ b/runtime/doc/ft_sql.txt
@@ -436,7 +436,7 @@ the space bar):
replace the column list with the list of tables.
- This allows you to quickly drill down into a
table to view its columns and back again.
- - <Right> and <Left> can be also be chosen via
+ - <Right> and <Left> can also be chosen via
your |init.vim| >
let g:ftplugin_sql_omni_key_right = '<Right>'
let g:ftplugin_sql_omni_key_left = '<Left>'
diff --git a/runtime/doc/gui.txt b/runtime/doc/gui.txt
index 0f1fa2b7a7..812259741f 100644
--- a/runtime/doc/gui.txt
+++ b/runtime/doc/gui.txt
@@ -175,7 +175,6 @@ system. To do this, put these commands in your vimrc file: >
:map <F4> :emenu <C-Z>
Pressing <F4> will start the menu. You can now use the cursor keys to select
a menu entry. Hit <Enter> to execute it. Hit <Esc> if you want to cancel.
-This does require the |+menu| feature enabled at compile time.
Creating New Menus *creating-menus*
@@ -473,9 +472,8 @@ Executing Menus *execute-menus*
insert-mode menu Eg: >
:emenu File.Exit
-If the console-mode vim has been compiled with WANT_MENU defined, you can
-use :emenu to access useful menu items you may have got used to from GUI
-mode. See 'wildmenu' for an option that works well with this. See
+You can use :emenu to access useful menu items you may have got used to from
+GUI mode. See 'wildmenu' for an option that works well with this. See
|console-menus| for an example.
When using a range, if the lines match with '<,'>, then the menu is executed
diff --git a/runtime/doc/help.txt b/runtime/doc/help.txt
index 8b096ff28b..6416f49061 100644
--- a/runtime/doc/help.txt
+++ b/runtime/doc/help.txt
@@ -125,11 +125,12 @@ Advanced editing ~
|windows.txt| commands for using multiple windows and buffers
|tabpage.txt| commands for using multiple tab pages
|spell.txt| spell checking
-|diff.txt| working with two to four versions of the same file
+|diff.txt| working with two to eight versions of the same file
|autocmd.txt| automatically executing commands on an event
|eval.txt| expression evaluation, conditional commands
|fold.txt| hide (fold) ranges of lines
|lua.txt| Lua API
+|api.txt| Nvim API via RPC, Lua and VimL
Special issues ~
|testing.txt| testing Vim and Vim scripts
@@ -137,14 +138,17 @@ Special issues ~
|remote.txt| using Vim as a server or client
Programming language support ~
-|indent.txt| automatic indenting for C and other languages
-|lsp.txt| Language Server Protocol (LSP)
-|syntax.txt| syntax highlighting
-|filetype.txt| settings done specifically for a type of file
-|quickfix.txt| commands for a quick edit-compile-fix cycle
-|ft_ada.txt| Ada (the programming language) support
-|ft_rust.txt| Filetype plugin for Rust
-|ft_sql.txt| about the SQL filetype plugin
+|indent.txt| automatic indenting for C and other languages
+|lsp.txt| Language Server Protocol (LSP)
+|treesitter.txt| tree-sitter library for incremental parsing of buffers
+|syntax.txt| syntax highlighting
+|filetype.txt| settings done specifically for a type of file
+|quickfix.txt| commands for a quick edit-compile-fix cycle
+|ft_ada.txt| Ada (the programming language) support
+|ft_ps1.txt| Filetype plugin for Windows PowerShell
+|ft_raku.txt| Filetype plugin for Raku
+|ft_rust.txt| Filetype plugin for Rust
+|ft_sql.txt| about the SQL filetype plugin
Language support ~
|digraph.txt| list of available digraphs
diff --git a/runtime/doc/helphelp.txt b/runtime/doc/helphelp.txt
index 7643d84017..4a94701b2e 100644
--- a/runtime/doc/helphelp.txt
+++ b/runtime/doc/helphelp.txt
@@ -249,7 +249,6 @@ command: >
It is possible to add translated help files, next to the original English help
files. Vim will search for all help in "doc" directories in 'runtimepath'.
-This is only available when compiled with the |+multi_lang| feature.
At this moment translations are available for:
Chinese - multiple authors
diff --git a/runtime/doc/if_perl.txt b/runtime/doc/if_perl.txt
index ddcf220844..3787ca69ba 100644
--- a/runtime/doc/if_perl.txt
+++ b/runtime/doc/if_perl.txt
@@ -189,6 +189,9 @@ VIM::Eval({expr}) Evaluates {expr} and returns (success, value) in list
A |List| is turned into a string by joining the items
and inserting line breaks.
+ *perl-Blob*
+VIM::Blob({expr}) Return Blob literal string 0zXXXX from scalar value.
+
==============================================================================
3. VIM::Buffer objects *perl-buffer*
diff --git a/runtime/doc/if_ruby.txt b/runtime/doc/if_ruby.txt
index 02edd50ae8..47305c65fb 100644
--- a/runtime/doc/if_ruby.txt
+++ b/runtime/doc/if_ruby.txt
@@ -32,10 +32,6 @@ downloading Ruby there.
This form of the |:ruby| command is mainly useful for
including ruby code in vim scripts.
- Note: This command doesn't work when the Ruby feature
- wasn't compiled in. To avoid errors, see
- |script-here|.
-
Example Vim script: >
function! RedGem()
diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt
index 2aafc075a6..baa7bc1992 100644
--- a/runtime/doc/index.txt
+++ b/runtime/doc/index.txt
@@ -155,6 +155,7 @@ commands in CTRL-X submode *i_CTRL-X_index*
|i_CTRL-X_CTRL-Y| CTRL-X CTRL-Y scroll down
|i_CTRL-X_CTRL-U| CTRL-X CTRL-U complete with 'completefunc'
|i_CTRL-X_CTRL-V| CTRL-X CTRL-V complete like in : command line
+|i_CTRL-X_CTRL-Z| CTRL-X CTRL-Z stop completion, keeping the text as-is
|i_CTRL-X_CTRL-]| CTRL-X CTRL-] complete tags
|i_CTRL-X_s| CTRL-X s spelling suggestions
@@ -699,8 +700,7 @@ tag char note action in Normal mode ~
tag char note action in Normal mode ~
------------------------------------------------------------------------------
-|g_CTRL-A| g CTRL-A only when compiled with MEM_PROFILE
- defined: dump a memory profile
+|g_CTRL-A| g CTRL-A dump a memory profile
|g_CTRL-G| g CTRL-G show information about current cursor
position
|g_CTRL-H| g CTRL-H start Select block mode
@@ -1097,8 +1097,9 @@ tag command action in Command-line editing mode ~
==============================================================================
5. Terminal mode *terminal-mode-index*
-In a |terminal| buffer all keys except |CTRL-\_CTRL-N| are forwarded to the
-terminal job. Use CTRL-\_CTRL-N to go to Normal mode.
+In a |terminal| buffer all keys except CTRL-\ are forwarded to the terminal
+job. If CTRL-\ is pressed, the next key is forwarded unless it is CTRL-N.
+Use |CTRL-\_CTRL-N| to go to Normal mode.
You found it, Arthur! *holy-grail*
@@ -1609,7 +1610,7 @@ tag command action ~
|:tab| :tab create new tab when opening new window
|:tag| :ta[g] jump to tag
|:tags| :tags show the contents of the tag stack
-|:tcd| :tcd change directory for tab page
+|:tcd| :tc[d] change directory for tab page
|:tchdir| :tch[dir] change directory for tab page
|:terminal| :te[rminal] open a terminal buffer
|:tfirst| :tf[irst] jump to first matching tag
diff --git a/runtime/doc/insert.txt b/runtime/doc/insert.txt
index c8a4168ab2..bfc1c235ea 100644
--- a/runtime/doc/insert.txt
+++ b/runtime/doc/insert.txt
@@ -68,12 +68,18 @@ CTRL-A Insert previously inserted text.
CTRL-W Delete the word before the cursor (see |i_backspacing| about
joining lines). See the section "word motions",
|word-motions|, for the definition of a word.
+ *i_CTRL-W-default*
+ By default, sets a new undo point before deleting.
+ |default-mappings|
*i_CTRL-U*
CTRL-U Delete all entered characters before the cursor in the current
line. If there are no newly entered characters and
'backspace' is not empty, delete all characters before the
cursor in the current line.
See |i_backspacing| about joining lines.
+ *i_CTRL-U-default*
+ By default, sets a new undo point before deleting.
+ |default-mappings|
*i_CTRL-I* *i_<Tab>* *i_Tab*
<Tab> or CTRL-I Insert a tab. If the 'expandtab' option is on, the
equivalent number of spaces is inserted (use CTRL-V <Tab> to
@@ -616,6 +622,8 @@ Completion can be done for:
12. Spelling suggestions |i_CTRL-X_s|
13. keywords in 'complete' |i_CTRL-N| |i_CTRL-P|
+Additionally, |i_CTRL-X_CTRL-Z| stops completion without changing the text.
+
All these, except CTRL-N and CTRL-P, are done in CTRL-X mode. This is a
sub-mode of Insert and Replace modes. You enter CTRL-X mode by typing CTRL-X
and one of the CTRL-X commands. You exit CTRL-X mode by typing a key that is
@@ -1016,6 +1024,12 @@ CTRL-P Find previous match for words that start with the
other contexts unless a double CTRL-X is used.
+Stop completion *compl-stop*
+
+ *i_CTRL-X_CTRL-Z*
+CTRL-X CTRL-Z Stop completion without changing the text.
+
+
FUNCTIONS FOR FINDING COMPLETIONS *complete-functions*
This applies to 'completefunc' and 'omnifunc'.
@@ -1047,7 +1061,8 @@ On the second invocation the arguments are:
The function must return a List with the matching words. These matches
usually include the "a:base" text. When there are no matches return an empty
-List.
+List. Note that the cursor may have moved since the first invocation, the
+text may have been changed.
In order to return more information than the matching words, return a Dict
that contains the List. The Dict can have these items:
@@ -1118,7 +1133,7 @@ match to the total list. These matches should then not appear in the returned
list! Call |complete_check()| now and then to allow the user to press a key
while still searching for matches. Stop searching when it returns non-zero.
- *E839* *E840*
+ *E840*
The function is allowed to move the cursor, it is restored afterwards.
The function is not allowed to move to another window or delete text.
diff --git a/runtime/doc/intro.txt b/runtime/doc/intro.txt
index f739e2e88b..2baf3a247f 100644
--- a/runtime/doc/intro.txt
+++ b/runtime/doc/intro.txt
@@ -454,9 +454,10 @@ Ex mode Like Command-line mode, but after entering a command
command line. |Ex-mode|
*Terminal-mode*
-Terminal mode In Terminal mode all input (except |c_CTRL-\_CTRL-N|)
- is sent to the process running in the current
- |terminal| buffer.
+Terminal mode In Terminal mode all input (except CTRL-\) is sent to
+ the process running in the current |terminal| buffer.
+ If CTRL-\ is pressed, the next key is sent unless it
+ is CTRL-N (|CTRL-\_CTRL-N|).
If the 'showmode' option is on "-- TERMINAL --" is shown
at the bottom of the window.
diff --git a/runtime/doc/job_control.txt b/runtime/doc/job_control.txt
index bf01e8e266..6a9d865c40 100644
--- a/runtime/doc/job_control.txt
+++ b/runtime/doc/job_control.txt
@@ -19,7 +19,7 @@ Job Id *job-id*
Each job is identified by an integer id, unique for the life of the current
Nvim session. Each job-id is a valid |channel-id|: they share the same "key
space". Functions like |jobstart()| return job ids; functions like
-|jobsend()|, |jobstop()|, |rpcnotify()|, and |rpcrequest()| take job ids.
+|jobstop()|, |chansend()|, |rpcnotify()|, and |rpcrequest()| take job ids.
Job stdio streams form a |channel| which can send and receive raw bytes or
|msgpack-rpc| messages.
@@ -28,7 +28,7 @@ Job stdio streams form a |channel| which can send and receive raw bytes or
Usage *job-control-usage*
To control jobs, use the "job…" family of functions: |jobstart()|,
-|jobsend()|, |jobstop()|.
+|jobstop()|, etc.
Example: >
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index d6ef761bcb..5b2a8d68b4 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -202,23 +202,33 @@ responses and notifications from LSP servers.
For |lsp-request|, each |lsp-handler| has this signature: >
- function(err, method, result, client_id, bufnr, config)
+ function(err, result, ctx, config)
<
Parameters: ~
{err} (table|nil)
When the language server is unable to complete a
request, a table with information about the error
is sent. Otherwise, it is `nil`. See |lsp-response|.
- {method} (string)
- The |lsp-method| name.
{result} (Result | Params | nil)
When the language server is able to succesfully
complete a request, this contains the `result` key
of the response. See |lsp-response|.
- {client_id} (number)
- The ID of the |vim.lsp.client|.
- {bufnr} (Buffer)
- Buffer handle, or 0 for current.
+ {ctx} (table)
+ Context describes additional calling state
+ associated with the handler. It consists of the
+ following key, value pairs:
+
+ {method} (string)
+ The |lsp-method| name.
+ {client_id} (number)
+ The ID of the |vim.lsp.client|.
+ {bufnr} (Buffer)
+ Buffer handle, or 0 for current.
+
+ {params} (table|nil)
+ The parameters used in the original request
+ which resulted in this handler
+ call.
{config} (table)
Configuration for the handler.
@@ -229,6 +239,7 @@ For |lsp-request|, each |lsp-handler| has this signature: >
To configure a particular |lsp-handler|, see:
|lsp-handler-configuration|
+
Returns: ~
The |lsp-handler| can respond by returning two values: `result, err`
Where `err` must be shaped like an RPC error:
@@ -238,21 +249,24 @@ For |lsp-request|, each |lsp-handler| has this signature: >
For |lsp-notification|, each |lsp-handler| has this signature: >
- function(err, method, params, client_id, bufnr, config)
+ function(err, result, ctx, config)
<
Parameters: ~
{err} (nil)
This is always `nil`.
See |lsp-notification|
- {method} (string)
- The |lsp-method| name.
- {params} (Params)
+ {result} (Result)
This contains the `params` key of the notification.
See |lsp-notification|
- {client_id} (number)
- The ID of the |vim.lsp.client|
- {bufnr} (nil)
- `nil`, as the server doesn't have an associated buffer.
+ {ctx} (table)
+ Context describes additional calling state
+ associated with the handler. It consists of the
+ following key, value pairs:
+
+ {method} (string)
+ The |lsp-method| name.
+ {client_id} (number)
+ The ID of the |vim.lsp.client|.
{config} (table)
Configuration for the handler.
@@ -322,6 +336,18 @@ To configure the behavior of a builtin |lsp-handler|, the convenient method
}
}
<
+ Some handlers do not have an explicitly named handler function (such as
+ |on_publish_diagnostics()|). To override these, first create a reference
+ to the existing handler: >
+
+ local on_references = vim.lsp.handlers["textDocument/references"]
+ vim.lsp.handlers["textDocument/references"] = vim.lsp.with(
+ on_references, {
+ -- Use location list instead of quickfix list
+ loclist = true,
+ }
+ )
+<
*lsp-handler-resolution*
Handlers can be set by:
@@ -404,121 +430,6 @@ LspReferenceRead used for highlighting "read" references
LspReferenceWrite used for highlighting "write" references
- *lsp-highlight-diagnostics*
-All highlights defined for diagnostics begin with `LspDiagnostics` followed by
-the type of highlight (e.g., `Sign`, `Underline`, etc.) and then the Severity
-of the highlight (e.g. `Error`, `Warning`, etc.)
-
-Sign, underline and virtual text highlights (by default) are linked to their
-corresponding LspDiagnosticsDefault highlight.
-
-For example, the default highlighting for |hl-LspDiagnosticsSignError| is
-linked to |hl-LspDiagnosticsDefaultError|. To change the default (and
-therefore the linked highlights), use the |:highlight| command: >
-
- highlight LspDiagnosticsDefaultError guifg="BrightRed"
-<
-
- *hl-LspDiagnosticsDefaultError*
-LspDiagnosticsDefaultError
- Used as the base highlight group.
- Other LspDiagnostic highlights link to this by default (except Underline)
-
- *hl-LspDiagnosticsDefaultWarning*
-LspDiagnosticsDefaultWarning
- Used as the base highlight group.
- Other LspDiagnostic highlights link to this by default (except Underline)
-
- *hl-LspDiagnosticsDefaultInformation*
-LspDiagnosticsDefaultInformation
- Used as the base highlight group.
- Other LspDiagnostic highlights link to this by default (except Underline)
-
- *hl-LspDiagnosticsDefaultHint*
-LspDiagnosticsDefaultHint
- Used as the base highlight group.
- Other LspDiagnostic highlights link to this by default (except Underline)
-
- *hl-LspDiagnosticsVirtualTextError*
-LspDiagnosticsVirtualTextError
- Used for "Error" diagnostic virtual text.
- See |vim.lsp.diagnostic.set_virtual_text()|
-
- *hl-LspDiagnosticsVirtualTextWarning*
-LspDiagnosticsVirtualTextWarning
- Used for "Warning" diagnostic virtual text.
- See |vim.lsp.diagnostic.set_virtual_text()|
-
- *hl-LspDiagnosticsVirtualTextInformation*
-LspDiagnosticsVirtualTextInformation
- Used for "Information" diagnostic virtual text.
- See |vim.lsp.diagnostic.set_virtual_text()|
-
- *hl-LspDiagnosticsVirtualTextHint*
-LspDiagnosticsVirtualTextHint
- Used for "Hint" diagnostic virtual text.
- See |vim.lsp.diagnostic.set_virtual_text()|
-
- *hl-LspDiagnosticsUnderlineError*
-LspDiagnosticsUnderlineError
- Used to underline "Error" diagnostics.
- See |vim.lsp.diagnostic.set_underline()|
-
- *hl-LspDiagnosticsUnderlineWarning*
-LspDiagnosticsUnderlineWarning
- Used to underline "Warning" diagnostics.
- See |vim.lsp.diagnostic.set_underline()|
-
- *hl-LspDiagnosticsUnderlineInformation*
-LspDiagnosticsUnderlineInformation
- Used to underline "Information" diagnostics.
- See |vim.lsp.diagnostic.set_underline()|
-
- *hl-LspDiagnosticsUnderlineHint*
-LspDiagnosticsUnderlineHint
- Used to underline "Hint" diagnostics.
- See |vim.lsp.diagnostic.set_underline()|
-
- *hl-LspDiagnosticsFloatingError*
-LspDiagnosticsFloatingError
- Used to color "Error" diagnostic messages in diagnostics float.
- See |vim.lsp.diagnostic.show_line_diagnostics()|
-
- *hl-LspDiagnosticsFloatingWarning*
-LspDiagnosticsFloatingWarning
- Used to color "Warning" diagnostic messages in diagnostics float.
- See |vim.lsp.diagnostic.show_line_diagnostics()|
-
- *hl-LspDiagnosticsFloatingInformation*
-LspDiagnosticsFloatingInformation
- Used to color "Information" diagnostic messages in diagnostics float.
- See |vim.lsp.diagnostic.show_line_diagnostics()|
-
- *hl-LspDiagnosticsFloatingHint*
-LspDiagnosticsFloatingHint
- Used to color "Hint" diagnostic messages in diagnostics float.
- See |vim.lsp.diagnostic.show_line_diagnostics()|
-
- *hl-LspDiagnosticsSignError*
-LspDiagnosticsSignError
- Used for "Error" signs in sign column.
- See |vim.lsp.diagnostic.set_signs()|
-
- *hl-LspDiagnosticsSignWarning*
-LspDiagnosticsSignWarning
- Used for "Warning" signs in sign column.
- See |vim.lsp.diagnostic.set_signs()|
-
- *hl-LspDiagnosticsSignInformation*
-LspDiagnosticsSignInformation
- Used for "Information" signs in sign column.
- See |vim.lsp.diagnostic.set_signs()|
-
- *hl-LspDiagnosticsSignHint*
-LspDiagnosticsSignHint
- Used for "Hint" signs in sign column.
- See |vim.lsp.diagnostic.set_signs()|
-
*lsp-highlight-codelens*
Highlight groups related to |lsp-codelens| functionality.
@@ -526,14 +437,19 @@ Highlight groups related to |lsp-codelens| functionality.
*hl-LspCodeLens*
LspCodeLens
Used to color the virtual text of the codelens. See
- |nvim_buf_set_virtual_text()|.
+ |nvim_buf_set_extmark()|.
-==============================================================================
-AUTOCOMMANDS *lsp-autocommands*
+LspCodeLensSeparator *hl-LspCodeLensSeparator*
+ Used to color the seperator between two or more code lens.
- *LspDiagnosticsChanged*
-LspDiagnosticsChanged After receiving publishDiagnostics server response
+ *lsp-highlight-signature*
+Highlight groups related to |vim.lsp.handlers.signature_help()|.
+
+ *hl-LspSignatureActiveParameter*
+LspSignatureActiveParameter
+ Used to highlight the active parameter in the signature help. See
+ |vim.lsp.handlers.signature_help()|.
==============================================================================
Lua module: vim.lsp *lsp-core*
@@ -742,15 +658,6 @@ get_log_path() *vim.lsp.get_log_path()*
Return: ~
(String) Path to logfile.
-init({client}, {bufnr}) *vim.lsp.init()*
- client_id → state
-
- state pending_change?: function that the timer starts to
- trigger didChange pending_changes: list of tables with the
- pending changesets; for incremental_sync only
- use_incremental_sync: bool buffers?: table (bufnr → lines);
- for incremental sync only timer?: uv_timer
-
omnifunc({findstart}, {base}) *vim.lsp.omnifunc()*
Implements 'omnifunc' compatible LSP completion.
@@ -804,109 +711,117 @@ start_client({config}) *vim.lsp.start_client()*
table.
Parameters: ~
- {root_dir} (required, string) Directory where the
- LSP server will base its rootUri on
- initialization.
- {cmd} (required, string or list treated like
- |jobstart()|) Base command that
- initiates the LSP client.
- {cmd_cwd} (string, default=|getcwd()|) Directory
- to launch the `cmd` process. Not
- related to `root_dir` .
- {cmd_env} (table) Environment flags to pass to
- the LSP on spawn. Can be specified
- using keys like a map or as a list with `k=v` pairs or both. Non-string values are
- coerced to string. Example: >
+ {root_dir} (string) Directory where the LSP
+ server will base its rootUri on
+ initialization.
+ {cmd} (required, string or list treated
+ like |jobstart()|) Base command that
+ initiates the LSP client.
+ {cmd_cwd} (string, default=|getcwd()|)
+ Directory to launch the `cmd`
+ process. Not related to `root_dir` .
+ {cmd_env} (table) Environment flags to pass to
+ the LSP on spawn. Can be specified
+ using keys like a map or as a list
+ with `k=v` pairs or both. Non-string values are
+ coerced to string. Example: >
{ "PRODUCTION=true"; "TEST=123"; PORT = 8080; HOST = "0.0.0.0"; }
<
- {capabilities} Map overriding the default capabilities
- defined by
- |vim.lsp.protocol.make_client_capabilities()|,
- passed to the language server on
- initialization. Hint: use
- make_client_capabilities() and modify
- its result.
- • Note: To send an empty dictionary use
- `{[vim.type_idx]=vim.types.dictionary}`
- , else it will be encoded as an
- array.
- {handlers} Map of language server method names to
- |lsp-handler|
- {settings} Map with language server specific
- settings. These are returned to the
- language server if requested via
- `workspace/configuration` . Keys are
- case-sensitive.
- {init_options} Values to pass in the initialization
- request as `initializationOptions` .
- See `initialize` in the LSP spec.
- {name} (string, default=client-id) Name in log
- messages.
- {get_language_id} function(bufnr, filetype) -> language
- ID as string. Defaults to the filetype.
- {offset_encoding} (default="utf-16") One of "utf-8",
- "utf-16", or "utf-32" which is the
- encoding that the LSP server expects.
- Client does not verify this is correct.
- {on_error} Callback with parameters (code, ...),
- invoked when the client operation
- throws an error. `code` is a number
- describing the error. Other arguments
- may be passed depending on the error
- kind. See |vim.lsp.client_errors| for
- possible errors. Use
- `vim.lsp.client_errors[code]` to get
- human-friendly name.
- {before_init} Callback with parameters
- (initialize_params, config) invoked
- before the LSP "initialize" phase,
- where `params` contains the parameters
- being sent to the server and `config`
- is the config that was passed to
- |vim.lsp.start_client()|. You can use
- this to modify parameters before they
- are sent.
- {on_init} Callback (client, initialize_result)
- invoked after LSP "initialize", where
- `result` is a table of `capabilities`
- and anything else the server may send.
- For example, clangd sends
- `initialize_result.offsetEncoding` if
- `capabilities.offsetEncoding` was sent
- to it. You can only modify the
- `client.offset_encoding` here before
- any notifications are sent. Most
- language servers expect to be sent
- client specified settings after
- initialization. Neovim does not make
- this assumption. A
- `workspace/didChangeConfiguration`
- notification should be sent to the
- server during on_init.
- {on_exit} Callback (code, signal, client_id)
- invoked on client exit.
- • code: exit code of the process
- • signal: number describing the signal
- used to terminate (if any)
- • client_id: client handle
- {on_attach} Callback (client, bufnr) invoked when
- client attaches to a buffer.
- {trace} "off" | "messages" | "verbose" | nil
- passed directly to the language server
- in the initialize request.
- Invalid/empty values will default to
- "off"
- {flags} A table with flags for the client. The
- current (experimental) flags are:
- • allow_incremental_sync (bool, default
- true): Allow using incremental sync
- for buffer edits
- • debounce_text_changes (number,
- default nil): Debounce didChange
- notifications to the server by the
- given number in milliseconds. No
- debounce occurs if nil
+ {capabilities} Map overriding the default
+ capabilities defined by
+ |vim.lsp.protocol.make_client_capabilities()|,
+ passed to the language server on
+ initialization. Hint: use
+ make_client_capabilities() and modify
+ its result.
+ • Note: To send an empty dictionary
+ use
+ `{[vim.type_idx]=vim.types.dictionary}`
+ , else it will be encoded as an
+ array.
+ {handlers} Map of language server method names
+ to |lsp-handler|
+ {settings} Map with language server specific
+ settings. These are returned to the
+ language server if requested via
+ `workspace/configuration` . Keys are
+ case-sensitive.
+ {init_options} Values to pass in the initialization
+ request as `initializationOptions` .
+ See `initialize` in the LSP spec.
+ {name} (string, default=client-id) Name in
+ log messages.
+ {workspace_folders} (table) List of workspace folders
+ passed to the language server.
+ Defaults to root_dir if not set. See
+ `workspaceFolders` in the LSP spec
+ {get_language_id} function(bufnr, filetype) -> language
+ ID as string. Defaults to the
+ filetype.
+ {offset_encoding} (default="utf-16") One of "utf-8",
+ "utf-16", or "utf-32" which is the
+ encoding that the LSP server expects.
+ Client does not verify this is
+ correct.
+ {on_error} Callback with parameters (code, ...),
+ invoked when the client operation
+ throws an error. `code` is a number
+ describing the error. Other arguments
+ may be passed depending on the error
+ kind. See |vim.lsp.client_errors| for
+ possible errors. Use
+ `vim.lsp.client_errors[code]` to get
+ human-friendly name.
+ {before_init} Callback with parameters
+ (initialize_params, config) invoked
+ before the LSP "initialize" phase,
+ where `params` contains the
+ parameters being sent to the server
+ and `config` is the config that was
+ passed to |vim.lsp.start_client()|.
+ You can use this to modify parameters
+ before they are sent.
+ {on_init} Callback (client, initialize_result)
+ invoked after LSP "initialize", where
+ `result` is a table of `capabilities`
+ and anything else the server may
+ send. For example, clangd sends
+ `initialize_result.offsetEncoding` if
+ `capabilities.offsetEncoding` was
+ sent to it. You can only modify the
+ `client.offset_encoding` here before
+ any notifications are sent. Most
+ language servers expect to be sent
+ client specified settings after
+ initialization. Neovim does not make
+ this assumption. A
+ `workspace/didChangeConfiguration`
+ notification should be sent to the
+ server during on_init.
+ {on_exit} Callback (code, signal, client_id)
+ invoked on client exit.
+ • code: exit code of the process
+ • signal: number describing the
+ signal used to terminate (if any)
+ • client_id: client handle
+ {on_attach} Callback (client, bufnr) invoked when
+ client attaches to a buffer.
+ {trace} "off" | "messages" | "verbose" | nil
+ passed directly to the language
+ server in the initialize request.
+ Invalid/empty values will default to
+ "off"
+ {flags} A table with flags for the client.
+ The current (experimental) flags are:
+ • allow_incremental_sync (bool,
+ default true): Allow using
+ incremental sync for buffer edits
+ • debounce_text_changes (number,
+ default nil): Debounce didChange
+ notifications to the server by the
+ given number in milliseconds. No
+ debounce occurs if nil
Return: ~
Client id. |vim.lsp.get_client_by_id()| Note: client may
@@ -954,12 +869,17 @@ clear_references() *vim.lsp.buf.clear_references()*
Removes document highlights from current buffer.
code_action({context}) *vim.lsp.buf.code_action()*
- Selects a code action from the input list that is available at
- the current cursor position.
+ Selects a code action available at the current cursor
+ position.
Parameters: ~
- {context} (table, optional) Valid `CodeActionContext`
- object
+ {context} table|nil `CodeActionContext` of the LSP specification:
+ • diagnostics: (table|nil) LSP`Diagnostic[]` . Inferred from the current position if not
+ provided.
+ • only: (string|nil) LSP `CodeActionKind` used
+ to filter the code actions. Most language
+ servers support values like `refactor` or
+ `quickfix` .
See also: ~
https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction
@@ -1100,8 +1020,13 @@ range_code_action({context}, {start_pos}, {end_pos})
Performs |vim.lsp.buf.code_action()| for a given range.
Parameters: ~
- {context} (table, optional) Valid `CodeActionContext`
- object
+ {context} table|nil `CodeActionContext` of the LSP specification:
+ • diagnostics: (table|nil) LSP`Diagnostic[]` . Inferred from the current position if not
+ provided.
+ • only: (string|nil) LSP `CodeActionKind`
+ used to filter the code actions. Most
+ language servers support values like
+ `refactor` or `quickfix` .
{start_pos} ({number, number}, optional) mark-indexed
position. Defaults to the start of the last
visual selection.
@@ -1176,195 +1101,20 @@ workspace_symbol({query}) *vim.lsp.buf.workspace_symbol()*
==============================================================================
Lua module: vim.lsp.diagnostic *lsp-diagnostic*
- *vim.lsp.diagnostic.clear()*
-clear({bufnr}, {client_id}, {diagnostic_ns}, {sign_ns})
- Clears the currently displayed diagnostics
-
- Parameters: ~
- {bufnr} number The buffer number
- {client_id} number the client id
- {diagnostic_ns} number|nil Associated diagnostic
- namespace
- {sign_ns} number|nil Associated sign namespace
-
-get({bufnr}, {client_id}) *vim.lsp.diagnostic.get()*
- Return associated diagnostics for bufnr
-
- Parameters: ~
- {bufnr} number
- {client_id} number|nil If nil, then return all of the
- diagnostics. Else, return just the
- diagnostics associated with the client_id.
-
-get_all({client_id}) *vim.lsp.diagnostic.get_all()*
- Get all diagnostics for clients
-
- Parameters: ~
- {client_id} number Restrict included diagnostics to the
- client If nil, diagnostics of all clients are
- included.
-
- Return: ~
- table with diagnostics grouped by bufnr (bufnr:Diagnostic[])
-
- *vim.lsp.diagnostic.get_count()*
-get_count({bufnr}, {severity}, {client_id})
- Get the counts for a particular severity
-
- Useful for showing diagnostic counts in statusline. eg:
->
-
- function! LspStatus() abort
- let sl = ''
- if luaeval('not vim.tbl_isempty(vim.lsp.buf_get_clients(0))')
- let sl.='%#MyStatuslineLSP#E:'
- let sl.='%#MyStatuslineLSPErrors#%{luaeval("vim.lsp.diagnostic.get_count(0, [[Error]])")}'
- let sl.='%#MyStatuslineLSP# W:'
- let sl.='%#MyStatuslineLSPWarnings#%{luaeval("vim.lsp.diagnostic.get_count(0, [[Warning]])")}'
- else
- let sl.='%#MyStatuslineLSPErrors#off'
- endif
- return sl
- endfunction
- let &l:statusline = '%#MyStatuslineLSP#LSP '.LspStatus()
-<
-
- Parameters: ~
- {bufnr} number The buffer number
- {severity} DiagnosticSeverity
- {client_id} number the client id
-
- *vim.lsp.diagnostic.get_line_diagnostics()*
-get_line_diagnostics({bufnr}, {line_nr}, {opts}, {client_id})
- Get the diagnostics by line
-
- Parameters: ~
- {bufnr} number The buffer number
- {line_nr} number The line number
- {opts} table|nil Configuration keys
- • severity: (DiagnosticSeverity, default nil)
- • Only return diagnostics with this
- severity. Overrides severity_limit
-
- • severity_limit: (DiagnosticSeverity, default nil)
- • Limit severity of diagnostics found. E.g.
- "Warning" means { "Error", "Warning" }
- will be valid.
- {client_id} number the client id
-
- Return: ~
- table Table with map of line number to list of
- diagnostics.
-
-get_next({opts}) *vim.lsp.diagnostic.get_next()*
- Get the next diagnostic closest to the cursor_position
-
- Parameters: ~
- {opts} table See |vim.lsp.diagnostic.goto_next()|
-
- Return: ~
- table Next diagnostic
-
-get_next_pos({opts}) *vim.lsp.diagnostic.get_next_pos()*
- Return the pos, {row, col}, for the next diagnostic in the
- current buffer.
-
- Parameters: ~
- {opts} table See |vim.lsp.diagnostic.goto_next()|
-
- Return: ~
- table Next diagnostic position
-
-get_prev({opts}) *vim.lsp.diagnostic.get_prev()*
- Get the previous diagnostic closest to the cursor_position
-
- Parameters: ~
- {opts} table See |vim.lsp.diagnostic.goto_next()|
-
- Return: ~
- table Previous diagnostic
-
-get_prev_pos({opts}) *vim.lsp.diagnostic.get_prev_pos()*
- Return the pos, {row, col}, for the prev diagnostic in the
- current buffer.
-
- Parameters: ~
- {opts} table See |vim.lsp.diagnostic.goto_next()|
-
- Return: ~
- table Previous diagnostic position
-
- *vim.lsp.diagnostic.get_virtual_text_chunks_for_line()*
-get_virtual_text_chunks_for_line({bufnr}, {line}, {line_diags}, {opts})
- Default function to get text chunks to display using `nvim_buf_set_virtual_text` .
-
- Parameters: ~
- {bufnr} number The buffer to display the virtual
- text in
- {line} number The line number to display the
- virtual text on
- {line_diags} Diagnostic [] The diagnostics associated with the line
- {opts} table See {opts} from
- |vim.lsp.diagnostic.set_virtual_text()|
-
- Return: ~
- table chunks, as defined by |nvim_buf_set_virtual_text()|
-
-goto_next({opts}) *vim.lsp.diagnostic.goto_next()*
- Move to the next diagnostic
+get_namespace({client_id}) *vim.lsp.diagnostic.get_namespace()*
+ Get the diagnostic namespace associated with an LSP client
+ |vim.diagnostic|.
Parameters: ~
- {opts} table|nil Configuration table. Keys:
- • {client_id}: (number)
- • If nil, will consider all clients attached to
- buffer.
-
- • {cursor_position}: (Position, default current
- position)
- • See |nvim_win_get_cursor()|
-
- • {wrap}: (boolean, default true)
- • Whether to loop around file or not. Similar to
- 'wrapscan'
-
- • {severity}: (DiagnosticSeverity)
- • Exclusive severity to consider. Overrides
- {severity_limit}
-
- • {severity_limit}: (DiagnosticSeverity)
- • Limit severity of diagnostics found. E.g.
- "Warning" means { "Error", "Warning" } will be
- valid.
-
- • {enable_popup}: (boolean, default true)
- • Call
- |vim.lsp.diagnostic.show_line_diagnostics()|
- on jump
-
- • {popup_opts}: (table)
- • Table to pass as {opts} parameter to
- |vim.lsp.diagnostic.show_line_diagnostics()|
-
- • {win_id}: (number, default 0)
- • Window ID
-
-goto_prev({opts}) *vim.lsp.diagnostic.goto_prev()*
- Move to the previous diagnostic
-
- Parameters: ~
- {opts} table See |vim.lsp.diagnostic.goto_next()|
+ {client_id} number The id of the LSP client
*vim.lsp.diagnostic.on_publish_diagnostics()*
-on_publish_diagnostics({_}, {_}, {params}, {client_id}, {_}, {config})
+on_publish_diagnostics({_}, {result}, {ctx}, {config})
|lsp-handler| for the method "textDocument/publishDiagnostics"
- Note:
- Each of the configuration options accepts:
- • `false` : Disable this feature
- • `true` : Enable this feature, use default settings.
- • `table` : Enable this feature, use overrides.
- • `function`: Function with signature (bufnr, client_id) that
- returns any of the above.>
+ See |vim.diagnostic.config()| for configuration options.
+ Handler-specific configuration can be set using
+ |vim.lsp.with()|: >
vim.lsp.handlers["textDocument/publishDiagnostics"] = vim.lsp.with(
vim.lsp.diagnostic.on_publish_diagnostics, {
@@ -1386,180 +1136,8 @@ on_publish_diagnostics({_}, {_}, {params}, {client_id}, {_}, {config})
<
Parameters: ~
- {config} table Configuration table.
- • underline: (default=true)
- • Apply underlines to diagnostics.
- • See |vim.lsp.diagnostic.set_underline()|
-
- • virtual_text: (default=true)
- • Apply virtual text to line endings.
- • See |vim.lsp.diagnostic.set_virtual_text()|
-
- • signs: (default=true)
- • Apply signs for diagnostics.
- • See |vim.lsp.diagnostic.set_signs()|
-
- • update_in_insert: (default=false)
- • Update diagnostics in InsertMode or wait
- until InsertLeave
-
- • severity_sort: (default=false)
- • Sort diagnostics (and thus signs and virtual
- text)
-
-reset({client_id}, {buffer_client_map}) *vim.lsp.diagnostic.reset()*
- Clear diagnotics and diagnostic cache
-
- Handles saving diagnostics from multiple clients in the same
- buffer.
-
- Parameters: ~
- {client_id} number
- {buffer_client_map} table map of buffers to active
- clients
-
-save({diagnostics}, {bufnr}, {client_id}) *vim.lsp.diagnostic.save()*
- Save diagnostics to the current buffer.
-
- Handles saving diagnostics from multiple clients in the same
- buffer.
-
- Parameters: ~
- {diagnostics} Diagnostic []
- {bufnr} number
- {client_id} number
-
-set_loclist({opts}) *vim.lsp.diagnostic.set_loclist()*
- Sets the location list
-
- Parameters: ~
- {opts} table|nil Configuration table. Keys:
- • {open_loclist}: (boolean, default true)
- • Open loclist after set
-
- • {client_id}: (number)
- • If nil, will consider all clients attached to
- buffer.
-
- • {severity}: (DiagnosticSeverity)
- • Exclusive severity to consider. Overrides
- {severity_limit}
-
- • {severity_limit}: (DiagnosticSeverity)
- • Limit severity of diagnostics found. E.g.
- "Warning" means { "Error", "Warning" } will be
- valid.
-
- • {workspace}: (boolean, default false)
- • Set the list with workspace diagnostics
-
- *vim.lsp.diagnostic.set_signs()*
-set_signs({diagnostics}, {bufnr}, {client_id}, {sign_ns}, {opts})
- Set signs for given diagnostics
-
- Sign characters can be customized with the following commands:
->
-
- sign define LspDiagnosticsSignError text=E texthl=LspDiagnosticsSignError linehl= numhl=
- sign define LspDiagnosticsSignWarning text=W texthl=LspDiagnosticsSignWarning linehl= numhl=
- sign define LspDiagnosticsSignInformation text=I texthl=LspDiagnosticsSignInformation linehl= numhl=
- sign define LspDiagnosticsSignHint text=H texthl=LspDiagnosticsSignHint linehl= numhl=
-<
-
- Parameters: ~
- {diagnostics} Diagnostic []
- {bufnr} number The buffer number
- {client_id} number the client id
- {sign_ns} number|nil
- {opts} table Configuration for signs. Keys:
- • priority: Set the priority of the signs.
- • severity_limit (DiagnosticSeverity):
- • Limit severity of diagnostics found.
- E.g. "Warning" means { "Error",
- "Warning" } will be valid.
-
- *vim.lsp.diagnostic.set_underline()*
-set_underline({diagnostics}, {bufnr}, {client_id}, {diagnostic_ns}, {opts})
- Set underline for given diagnostics
-
- Underline highlights can be customized by changing the
- following |:highlight| groups.
->
-
- LspDiagnosticsUnderlineError
- LspDiagnosticsUnderlineWarning
- LspDiagnosticsUnderlineInformation
- LspDiagnosticsUnderlineHint
-<
-
- Parameters: ~
- {diagnostics} Diagnostic []
- {bufnr} number: The buffer number
- {client_id} number: The client id
- {diagnostic_ns} number|nil: The namespace
- {opts} table: Configuration table:
- • severity_limit (DiagnosticSeverity):
- • Limit severity of diagnostics found.
- E.g. "Warning" means { "Error",
- "Warning" } will be valid.
-
- *vim.lsp.diagnostic.set_virtual_text()*
-set_virtual_text({diagnostics}, {bufnr}, {client_id}, {diagnostic_ns}, {opts})
- Set virtual text given diagnostics
-
- Virtual text highlights can be customized by changing the
- following |:highlight| groups.
->
-
- LspDiagnosticsVirtualTextError
- LspDiagnosticsVirtualTextWarning
- LspDiagnosticsVirtualTextInformation
- LspDiagnosticsVirtualTextHint
-<
-
- Parameters: ~
- {diagnostics} Diagnostic []
- {bufnr} number
- {client_id} number
- {diagnostic_ns} number
- {opts} table Options on how to display virtual
- text. Keys:
- • prefix (string): Prefix to display
- before virtual text on line
- • spacing (number): Number of spaces to
- insert before virtual text
- • severity_limit (DiagnosticSeverity):
- • Limit severity of diagnostics found.
- E.g. "Warning" means { "Error",
- "Warning" } will be valid.
-
- *vim.lsp.diagnostic.show_line_diagnostics()*
-show_line_diagnostics({opts}, {bufnr}, {line_nr}, {client_id})
- Open a floating window with the diagnostics from {line_nr}
-
- The floating window can be customized with the following
- highlight groups: >
-
- LspDiagnosticsFloatingError
- LspDiagnosticsFloatingWarning
- LspDiagnosticsFloatingInformation
- LspDiagnosticsFloatingHint
-<
-
- Parameters: ~
- {opts} table Configuration table
- • show_header (boolean, default true): Show
- "Diagnostics:" header.
- • Plus all the opts for
- |vim.lsp.diagnostic.get_line_diagnostics()|
- and |vim.lsp.util.open_floating_preview()|
- can be used here.
- {bufnr} number The buffer number
- {line_nr} number The line number
- {client_id} number|nil the client id
-
- Return: ~
- table {popup_bufnr, win_id}
+ {config} table Configuration table (see
+ |vim.diagnostic.config()|).
==============================================================================
@@ -1577,11 +1155,15 @@ display({lenses}, {bufnr}, {client_id}) *vim.lsp.codelens.display()*
get({bufnr}) *vim.lsp.codelens.get()*
Return all lenses for the given buffer
+ Parameters: ~
+ {bufnr} number Buffer number. 0 can be used for the
+ current buffer.
+
Return: ~
table ( `CodeLens[]` )
*vim.lsp.codelens.on_codelens()*
-on_codelens({err}, {_}, {result}, {client_id}, {bufnr})
+on_codelens({err}, {result}, {ctx}, {_})
|lsp-handler| for the method `textDocument/codeLens`
refresh() *vim.lsp.codelens.refresh()*
@@ -1609,21 +1191,28 @@ save({lenses}, {bufnr}, {client_id}) *vim.lsp.codelens.save()*
==============================================================================
Lua module: vim.lsp.handlers *lsp-handlers*
- *vim.lsp.handlers.progress_handler()*
-progress_handler({_}, {_}, {params}, {client_id})
- See also: ~
- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand
+hover({_}, {result}, {ctx}, {config}) *vim.lsp.handlers.hover()*
+ |lsp-handler| for the method "textDocument/hover" >
+
+ vim.lsp.handlers["textDocument/hover"] = vim.lsp.with(
+ vim.lsp.handlers.hover, {
+ -- Use a sharp border with `FloatBorder` highlights
+ border = "single"
+ }
+ )
+<
- *vim.lsp.handlers.signature_help()*
-signature_help({_}, {method}, {result}, {_}, {bufnr}, {config})
Parameters: ~
{config} table Configuration table.
• border: (default=nil)
• Add borders to the floating window
• See |vim.api.nvim_open_win()|
- See also: ~
- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_declaration@seehttps://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition@seehttps://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_typeDefinition@seehttps://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_implementation|lsp-handler| for the method "textDocument/signatureHelp">
+ *vim.lsp.handlers.signature_help()*
+signature_help({_}, {result}, {ctx}, {config})
+ |lsp-handler| for the method "textDocument/signatureHelp". The
+ active parameter is highlighted with
+ |hl-LspSignatureActiveParameter|. >
vim.lsp.handlers["textDocument/signatureHelp"] = vim.lsp.with(
vim.lsp.handlers.signature_help, {
@@ -1633,6 +1222,12 @@ signature_help({_}, {method}, {result}, {_}, {bufnr}, {config})
)
<
+ Parameters: ~
+ {config} table Configuration table.
+ • border: (default=nil)
+ • Add borders to the floating window
+ • See |vim.api.nvim_open_win()|
+
==============================================================================
Lua module: vim.lsp.util *lsp-util*
@@ -1659,6 +1254,9 @@ apply_text_edits({text_edits}, {bufnr})
{text_edits} (table) list of `TextEdit` objects
{buf_nr} (number) Buffer id
+ See also: ~
+ https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textEdit
+
*vim.lsp.util.apply_workspace_edit()*
apply_workspace_edit({workspace_edit})
Applies a `WorkspaceEdit` .
@@ -1666,12 +1264,6 @@ apply_workspace_edit({workspace_edit})
Parameters: ~
{workspace_edit} (table) `WorkspaceEdit`
-border_height({id}) *vim.lsp.util.border_height()*
- TODO: Documentation
-
-border_width({id}) *vim.lsp.util.border_width()*
- TODO: Documentation
-
buf_clear_references({bufnr}) *vim.lsp.util.buf_clear_references()*
Removes document highlights from a buffer.
@@ -1687,6 +1279,9 @@ buf_highlight_references({bufnr}, {references})
{references} List of `DocumentHighlight` objects to
highlight
+ See also: ~
+ https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#documentHighlight
+
buf_lines({bufnr}) *vim.lsp.util.buf_lines()*
TODO: Documentation
@@ -1756,7 +1351,7 @@ convert_input_to_markdown_lines({input}, {contents})
https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover
*vim.lsp.util.convert_signature_help_to_markdown_lines()*
-convert_signature_help_to_markdown_lines({signature_help}, {ft})
+convert_signature_help_to_markdown_lines({signature_help}, {ft}, {triggers})
Converts `textDocument/SignatureHelp` response to markdown
lines.
@@ -1765,6 +1360,9 @@ convert_signature_help_to_markdown_lines({signature_help}, {ft})
{ft} optional filetype that will be use as
the `lang` for the label markdown code
block
+ {triggers} optional list of trigger characters from
+ the lsp server. used to better determine
+ parameter offsets
Return: ~
list of lines of converted markdown.
@@ -1778,19 +1376,6 @@ create_file({change}) *vim.lsp.util.create_file()*
delete_file({change}) *vim.lsp.util.delete_file()*
TODO: Documentation
- *vim.lsp.util.diagnostics_to_items()*
-diagnostics_to_items({diagnostics_by_bufnr}, {predicate})
- Convert diagnostics grouped by bufnr to a list of items for
- use in the quickfix or location list.
-
- Parameters: ~
- {diagnostics_by_bufnr} table bufnr -> Diagnostic []
- {predicate} an optional function to filter the
- diagnostics.
-
- Return: ~
- table (A list of items)
-
*vim.lsp.util.extract_completion_items()*
extract_completion_items({result})
Can be used to extract the completion items from a `textDocument/completion` request, which may return one of `CompletionItem[]` , `CompletionList` or null.
@@ -1819,6 +1404,8 @@ get_effective_tabstop({bufnr}) *vim.lsp.util.get_effective_tabstop()*
|softtabstop|
get_line({uri}, {row}) *vim.lsp.util.get_line()*
+ Gets the zero-indexed line from the given uri.
+
Parameters: ~
{uri} string uri of the resource to get the line from
{row} number zero-indexed line number
@@ -1827,6 +1414,8 @@ get_line({uri}, {row}) *vim.lsp.util.get_line()*
string the line at row in filename
get_lines({uri}, {rows}) *vim.lsp.util.get_lines()*
+ Gets the zero-indexed lines from the given uri.
+
Parameters: ~
{uri} string uri of the resource to get the lines from
{rows} number[] zero-indexed line numbers
@@ -1851,6 +1440,9 @@ locations_to_items({locations}) *vim.lsp.util.locations_to_items()*
and in sorted order, for display in quickfix and location
lists.
+ The result can be passed to the {list} argument of
+ |setqflist()| or |setloclist()|.
+
Parameters: ~
{locations} (table) list of `Location` s or
`LocationLink` s
@@ -1886,14 +1478,14 @@ make_floating_popup_options({width}, {height}, {opts})
*vim.lsp.util.make_formatting_params()*
make_formatting_params({options})
- Creates a `FormattingOptions` object for the current buffer
- and cursor position.
+ Creates a `DocumentFormattingParams` object for the current
+ buffer and cursor position.
Parameters: ~
{options} Table with valid `FormattingOptions` entries
Return: ~
- `FormattingOptions object
+ `DocumentFormattingParams` object
See also: ~
https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting
@@ -2014,6 +1606,8 @@ preview_location({location}, {opts}) *vim.lsp.util.preview_location()*
or nil
rename({old_fname}, {new_fname}, {opts}) *vim.lsp.util.rename()*
+ Rename old_fname to new_fname
+
Parameters: ~
{opts} (table)
@@ -2033,21 +1627,6 @@ set_lines({lines}, {A}, {B}, {new_lines}) *vim.lsp.util.set_lines()*
Return: ~
(table) The modified {lines} object
-set_loclist({items}, {win_id}) *vim.lsp.util.set_loclist()*
- Fills target window's location list with given list of items.
- Can be obtained with e.g. |vim.lsp.util.locations_to_items()|.
- Defaults to current window.
-
- Parameters: ~
- {items} (table) list of items
-
-set_qflist({items}) *vim.lsp.util.set_qflist()*
- Fills quickfix list with given list of items. Can be obtained
- with e.g. |vim.lsp.util.locations_to_items()|.
-
- Parameters: ~
- {items} (table) list of items
-
*vim.lsp.util.stylize_markdown()*
stylize_markdown({bufnr}, {contents}, {opts})
Converts markdown into syntax highlighted regions by stripping
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
index fd1bedd8ef..22e323baa7 100644
--- a/runtime/doc/lua.txt
+++ b/runtime/doc/lua.txt
@@ -1,15 +1,15 @@
*lua.txt* Nvim
- NVIM REFERENCE MANUAL
+ NVIM REFERENCE MANUAL
-Lua engine *lua* *Lua*
+Lua engine *lua* *Lua*
Type |gO| to see the table of contents.
==============================================================================
-INTRODUCTION *lua-intro*
+INTRODUCTION *lua-intro*
The Lua 5.1 language is builtin and always available. Try this command to get
an idea of what lurks beneath: >
@@ -27,11 +27,12 @@ are on 'runtimepath':
~/.config/nvim/lua/foo.lua
then `require('foo')` loads "~/.config/nvim/lua/foo.lua", and
"runtime/lua/foo.lua" is not used. See |lua-require| to understand how Nvim
-finds and loads Lua modules. The conventions are similar to VimL plugins,
-with some extra features. See |lua-require-example| for a walkthrough.
+finds and loads Lua modules. The conventions are similar to those of
+Vimscript |plugin|s, with some extra features. See |lua-require-example| for
+a walkthrough.
==============================================================================
-IMPORTING LUA MODULES *lua-require*
+IMPORTING LUA MODULES *lua-require*
*lua-package-path*
Nvim automatically adjusts `package.path` and `package.cpath` according to
@@ -157,7 +158,7 @@ function without any parentheses. This is most often used to approximate
------------------------------------------------------------------------------
-LUA PLUGIN EXAMPLE *lua-require-example*
+LUA PLUGIN EXAMPLE *lua-require-example*
The following example plugin adds a command `:MakeCharBlob` which transforms
current buffer into a long `unsigned char` array. Lua contains transformation
@@ -234,7 +235,7 @@ lua/charblob.lua: >
}
==============================================================================
-COMMANDS *lua-commands*
+COMMANDS *lua-commands*
These commands execute a Lua chunk from either the command line (:lua, :luado)
or a file (:luafile) on the given line [range]. As always in Lua, each chunk
@@ -298,19 +299,20 @@ arguments separated by " " (space) instead of "\t" (tab).
:luado if bp:match(line) then return "-->\t" .. line end
<
- *:luafile*
+ *:luafile*
:[range]luafile {file}
- Execute Lua script in {file}.
- The whole argument is used as a single file name.
+ Execute Lua script in {file}.
+ The whole argument is used as the filename (like
+ |:edit|), spaces do not need to be escaped.
+ Alternatively you can |:source| Lua files.
- Examples:
- >
+ Examples: >
:luafile script.lua
:luafile %
<
==============================================================================
-luaeval() *lua-eval* *luaeval()*
+luaeval() *lua-eval* *luaeval()*
The (dual) equivalent of "vim.eval" for passing Lua values to Nvim is
"luaeval". "luaeval" takes an expression string and an optional argument used
@@ -324,8 +326,8 @@ semantically equivalent in Lua to:
end
Lua nils, numbers, strings, tables and booleans are converted to their
-respective VimL types. An error is thrown if conversion of any other Lua types
-is attempted.
+respective Vimscript types. If a Lua string contains a NUL byte, it will be
+converted to a |Blob|. Conversion of other Lua types is an error.
The magic global "_A" contains the second argument to luaeval().
@@ -348,21 +350,21 @@ cases there is the following agreement:
3. Table with string keys, at least one of which contains NUL byte, is also
considered to be a dictionary, but this time it is converted to
a |msgpack-special-map|.
- *lua-special-tbl*
+ *lua-special-tbl*
4. Table with `vim.type_idx` key may be a dictionary, a list or floating-point
value:
- - `{[vim.type_idx]=vim.types.float, [vim.val_idx]=1}` is converted to
- a floating-point 1.0. Note that by default integral Lua numbers are
- converted to |Number|s, non-integral are converted to |Float|s. This
+ - `{[vim.type_idx]=vim.types.float, [vim.val_idx]=1}` is converted to
+ a floating-point 1.0. Note that by default integral Lua numbers are
+ converted to |Number|s, non-integral are converted to |Float|s. This
variant allows integral |Float|s.
- - `{[vim.type_idx]=vim.types.dictionary}` is converted to an empty
- dictionary, `{[vim.type_idx]=vim.types.dictionary, [42]=1, a=2}` is
- converted to a dictionary `{'a': 42}`: non-string keys are ignored.
- Without `vim.type_idx` key tables with keys not fitting in 1., 2. or 3.
+ - `{[vim.type_idx]=vim.types.dictionary}` is converted to an empty
+ dictionary, `{[vim.type_idx]=vim.types.dictionary, [42]=1, a=2}` is
+ converted to a dictionary `{'a': 42}`: non-string keys are ignored.
+ Without `vim.type_idx` key tables with keys not fitting in 1., 2. or 3.
are errors.
- - `{[vim.type_idx]=vim.types.list}` is converted to an empty list. As well
- as `{[vim.type_idx]=vim.types.list, [42]=1}`: integral keys that do not
- form a 1-step sequence from 1 to N are ignored, as well as all
+ - `{[vim.type_idx]=vim.types.list}` is converted to an empty list. As well
+ as `{[vim.type_idx]=vim.types.list, [42]=1}`: integral keys that do not
+ form a 1-step sequence from 1 to N are ignored, as well as all
non-integral keys.
Examples: >
@@ -373,13 +375,13 @@ Examples: >
: endfunction
:echo Rand(1,10)
-Note: second argument to `luaeval` undergoes VimL to Lua conversion
-("marshalled"), so changes to Lua containers do not affect values in VimL.
-Return value is also always converted. When converting,
-|msgpack-special-dict|s are treated specially.
+Note: second argument to `luaeval` is converted ("marshalled") from Vimscript
+to Lua, so changes to Lua containers do not affect values in Vimscript. Return
+value is also always converted. When converting, |msgpack-special-dict|s are
+treated specially.
==============================================================================
-Vimscript v:lua interface *v:lua-call*
+Vimscript v:lua interface *v:lua-call*
From Vimscript the special `v:lua` prefix can be used to call Lua functions
which are global or accessible from global tables. The expression >
@@ -391,6 +393,10 @@ where the args are converted to Lua values. The expression >
is equivalent to the Lua chunk >
return somemod.func(...)
+The `v:lua` prefix may be used to call Lua functions as |method|s. For
+example: >
+ arg1->v:lua.somemod.func(arg2)
+
You can use `v:lua` in "func" options like 'tagfunc', 'omnifunc', etc.
For example consider the following Lua omnifunc handler: >
@@ -415,7 +421,7 @@ Note: `v:lua` without a call is not allowed in a Vimscript expression:
==============================================================================
-Lua standard modules *lua-stdlib*
+Lua standard modules *lua-stdlib*
The Nvim Lua "standard library" (stdlib) is the `vim` module, which exposes
various functions and sub-modules. It is always loaded, thus require("vim")
@@ -449,7 +455,7 @@ Note that underscore-prefixed functions (e.g. "_os_proc_children") are
internal/private and must not be used by plugins.
------------------------------------------------------------------------------
-VIM.LOOP *lua-loop* *vim.loop*
+VIM.LOOP *lua-loop* *vim.loop*
`vim.loop` exposes all features of the Nvim event-loop. This is a low-level
API that provides functionality for networking, filesystem, and process
@@ -460,7 +466,7 @@ management. Try this command to see available functions: >
Reference: https://github.com/luvit/luv/blob/master/docs.md
Examples: https://github.com/luvit/luv/tree/master/examples
- *E5560* *lua-loop-callbacks*
+ *E5560* *lua-loop-callbacks*
It is an error to directly invoke `vim.api` functions (except |api-fast|) in
`vim.loop` callbacks. For example, this is an error: >
@@ -496,7 +502,7 @@ Example: repeating timer
print('sleeping');
-Example: File-change detection *watch-file*
+Example: File-change detection *watch-file*
1. Save this code to a file.
2. Execute it with ":luafile %".
3. Use ":Watch %" to watch any file.
@@ -522,7 +528,7 @@ Example: File-change detection *watch-file*
"command! -nargs=1 Watch call luaeval('watch_file(_A)', expand('<args>'))")
-Example: TCP echo-server *tcp-server*
+Example: TCP echo-server *tcp-server*
1. Save this code to a file.
2. Execute it with ":luafile %".
3. Note the port number.
@@ -552,7 +558,7 @@ Example: TCP echo-server *tcp-server*
print('TCP echo-server listening on port: '..server:getsockname().port)
------------------------------------------------------------------------------
-VIM.HIGHLIGHT *lua-highlight*
+VIM.HIGHLIGHT *lua-highlight*
Nvim includes a function for highlighting a selection on yank (see for example
https://github.com/machakann/vim-highlightedyank). To enable it, add
@@ -572,11 +578,11 @@ If you want to exclude visual selections from highlighting on yank, use
vim.highlight.on_yank({opts}) *vim.highlight.on_yank()*
Highlights the yanked text. The fields of the optional dict {opts}
control the highlight:
- - {higroup} highlight group for yanked region (default `"IncSearch"`)
+ - {higroup} highlight group for yanked region (default |hl-IncSearch|)
- {timeout} time in ms before highlight is cleared (default `150`)
- {on_macro} highlight when executing macro (default `false`)
- {on_visual} highlight when yanking visual selection (default `true`)
- - {event} event structure (default `vim.v.event`)
+ - {event} event structure (default |v:event|)
vim.highlight.range({bufnr}, {ns}, {higroup}, {start}, {finish}, {rtype}, {inclusive})
*vim.highlight.range()*
@@ -587,21 +593,19 @@ vim.highlight.range({bufnr}, {ns}, {higroup}, {start}, {finish}, {rtype}, {inclu
range is inclusive (default false).
------------------------------------------------------------------------------
-VIM.REGEX *lua-regex*
+VIM.REGEX *lua-regex*
Vim regexes can be used directly from lua. Currently they only allow
matching within a single line.
-vim.regex({re}) *vim.regex()*
+vim.regex({re}) *vim.regex()*
+ Parse the Vim regex {re} and return a regex object. Regexes are
+ "magic" and case-insensitive by default, regardless of 'magic' and
+ 'ignorecase'. The can be controlled with flags, see |/magic|.
- Parse the regex {re} and return a regex object. 'magic' and
- 'ignorecase' options are ignored, lua regexes always defaults to magic
- and ignoring case. The behavior can be changed with flags in
- the beginning of the string |/magic|.
+Methods on the regex object:
-Regex objects support the following methods:
-
-regex:match_str({str}) *regex:match_str()*
+regex:match_str({str}) *regex:match_str()*
Match the string against the regex. If the string should match the
regex precisely, surround the regex with `^` and `$`.
If the was a match, the byte indices for the beginning and end of
@@ -609,66 +613,144 @@ regex:match_str({str}) *regex:match_str()*
As any integer is truth-y, `regex:match()` can be directly used
as a condition in an if-statement.
-regex:match_line({bufnr}, {line_idx}[, {start}, {end}]) *regex:match_line()*
+regex:match_line({bufnr}, {line_idx}[, {start}, {end}]) *regex:match_line()*
Match line {line_idx} (zero-based) in buffer {bufnr}. If {start} and
{end} are supplied, match only this byte index range. Otherwise see
|regex:match_str()|. If {start} is used, then the returned byte
indices will be relative {start}.
------------------------------------------------------------------------------
-VIM *lua-builtin*
+VIM.DIFF *lua-diff*
+
+vim.diff({a}, {b}, {opts}) *vim.diff()*
+ Run diff on strings {a} and {b}. Any indices returned by this
+ function, either directly or via callback arguments, are
+ 1-based.
+
+ Examples: >
+ vim.diff('a\n', 'b\nc\n')
+ -->
+ @@ -1 +1,2 @@
+ -a
+ +b
+ +c
+
+ vim.diff('a\n', 'b\nc\n', {result_type = 'indices'})
+ -->
+ {
+ {1, 1, 1, 2}
+ }
+<
+ Parameters: ~
+ {a} First string to compare
+ {b} Second string to compare
+ {opts} Optional parameters:
+ • `on_hunk` (callback):
+ Invoked for each hunk in the diff. Return a
+ negative number to cancel the callback for any
+ remaining hunks.
+ Args:
+ • `start_a` (integer): Start line of hunk in {a}.
+ • `count_a` (integer): Hunk size in {a}.
+ • `start_b` (integer): Start line of hunk in {b}.
+ • `count_b` (integer): Hunk size in {b}.
+ • `result_type` (string): Form of the returned diff:
+ • "unified": (default) String in unified format.
+ • "indices": Array of hunk locations.
+ Note this option is ignored if `on_hunk` is
+ used.
+ • `algorithm` (string):
+ Diff algorithm to use. Values:
+ • "myers" the default algorithm
+ • "minimal" spend extra time to generate the
+ smallest possible diff
+ • "patience" patience diff algorithm
+ • "histogram" histogram diff algorithm
+ • `ctxlen` (integer): Context length
+ • `interhunkctxlen` (integer):
+ Inter hunk context length
+ • `ignore_whitespace` (boolean):
+ Ignore whitespace
+ • `ignore_whitespace_change` (boolean):
+ Ignore whitespace change
+ • `ignore_whitespace_change_at_eol` (boolean)
+ Ignore whitespace change at end-of-line.
+ • `ignore_cr_at_eol` (boolean)
+ Ignore carriage return at end-of-line
+ • `ignore_blank_lines` (boolean)
+ Ignore blank lines
+ • `indent_heuristic` (boolean):
+ Use the indent heuristic for the internal
+ diff library.
+
+ Return: ~
+ See {opts.result_type}. nil if {opts.on_hunk} is given.
+
+------------------------------------------------------------------------------
+VIM.MPACK *lua-mpack*
+
+The *vim.mpack* module provides packing and unpacking of lua objects to
+msgpack encoded strings. |vim.NIL| and |vim.empty_dict()| are supported.
+
+vim.mpack.pack({obj}) *vim.mpack.pack*
+ Packs a lua object {obj} and returns the msgpack representation as
+ a string
+
+vim.mpack.unpack({str}) *vim.mpack.unpack*
+ Unpacks the msgpack encoded {str} and returns a lua object
-vim.api.{func}({...}) *vim.api*
+------------------------------------------------------------------------------
+VIM *lua-builtin*
+
+vim.api.{func}({...}) *vim.api*
Invokes Nvim |API| function {func} with arguments {...}.
Example: call the "nvim_get_current_line()" API function: >
print(tostring(vim.api.nvim_get_current_line()))
-vim.version() *vim.version*
- Returns the version of the current neovim build.
+vim.version() *vim.version*
+ Gets the version of the current Nvim build.
-vim.in_fast_event() *vim.in_fast_event()*
+vim.in_fast_event() *vim.in_fast_event()*
Returns true if the code is executing as part of a "fast" event
handler, where most of the API is disabled. These are low-level events
(e.g. |lua-loop-callbacks|) which can be invoked whenever Nvim polls
for input. When this is `false` most API functions are callable (but
may be subject to other restrictions such as |textlock|).
-vim.NIL *vim.NIL*
- Special value used to represent NIL in msgpack-rpc and |v:null| in
- vimL interaction, and similar cases. Lua `nil` cannot be used as
- part of a lua table representing a Dictionary or Array, as it
- is equivalent to a missing value: `{"foo", nil}` is the same as
- `{"foo"}`
+vim.NIL *vim.NIL*
+ Special value representing NIL in |RPC| and |v:null| in Vimscript
+ conversion, and similar cases. Lua `nil` cannot be used as part of
+ a Lua table representing a Dictionary or Array, because it is
+ treated as missing: `{"foo", nil}` is the same as `{"foo"}`.
-vim.empty_dict() *vim.empty_dict()*
- Creates a special table which will be converted to an empty
- dictionary when converting lua values to vimL or API types. The
- table is empty, and this property is marked using a metatable. An
- empty table `{}` without this metatable will default to convert to
- an array/list.
+vim.empty_dict() *vim.empty_dict()*
+ Creates a special empty table (marked with a metatable), which Nvim
+ converts to an empty dictionary when translating Lua values to
+ Vimscript or API types. Nvim by default converts an empty table `{}`
+ without this metatable to an list/array.
- Note: if numeric keys are added to the table, the metatable will be
- ignored and the dict converted to a list/array anyway.
+ Note: if numeric keys are present in the table, Nvim ignores the
+ metatable marker and converts the dict to a list/array anyway.
-vim.rpcnotify({channel}, {method}[, {args}...]) *vim.rpcnotify()*
- Sends {event} to {channel} via |RPC| and returns immediately.
- If {channel} is 0, the event is broadcast to all channels.
+vim.rpcnotify({channel}, {method}[, {args}...]) *vim.rpcnotify()*
+ Sends {event} to {channel} via |RPC| and returns immediately. If
+ {channel} is 0, the event is broadcast to all channels.
- This function also works in a fast callback |lua-loop-callbacks|.
+ This function also works in a fast callback |lua-loop-callbacks|.
-vim.rpcrequest({channel}, {method}[, {args}...]) *vim.rpcrequest()*
- Sends a request to {channel} to invoke {method} via
- |RPC| and blocks until a response is received.
+vim.rpcrequest({channel}, {method}[, {args}...]) *vim.rpcrequest()*
+ Sends a request to {channel} to invoke {method} via |RPC| and blocks
+ until a response is received.
- Note: NIL values as part of the return value is represented as
- |vim.NIL| special value
+ Note: NIL values as part of the return value is represented as
+ |vim.NIL| special value
-vim.stricmp({a}, {b}) *vim.stricmp()*
+vim.stricmp({a}, {b}) *vim.stricmp()*
Compares strings case-insensitively. Returns 0, 1 or -1 if strings
are equal, {a} is greater than {b} or {a} is lesser than {b},
respectively.
-vim.str_utfindex({str}[, {index}]) *vim.str_utfindex()*
+vim.str_utfindex({str}[, {index}]) *vim.str_utfindex()*
Convert byte index to UTF-32 and UTF-16 indicies. If {index} is not
supplied, the length of the string is used. All indicies are zero-based.
Returns two values: the UTF-32 and UTF-16 indicies respectively.
@@ -756,40 +838,40 @@ vim.wait({time} [, {callback}, {interval}, {fast_only}]) *vim.wait()*
end
<
-vim.type_idx *vim.type_idx*
- Type index for use in |lua-special-tbl|. Specifying one of the
- values from |vim.types| allows typing the empty table (it is
- unclear whether empty Lua table represents empty list or empty array)
- and forcing integral numbers to be |Float|. See |lua-special-tbl| for
- more details.
+vim.type_idx *vim.type_idx*
+ Type index for use in |lua-special-tbl|. Specifying one of the values
+ from |vim.types| allows typing the empty table (it is unclear whether
+ empty Lua table represents empty list or empty array) and forcing
+ integral numbers to be |Float|. See |lua-special-tbl| for more
+ details.
-vim.val_idx *vim.val_idx*
- Value index for tables representing |Float|s. A table representing
- floating-point value 1.0 looks like this: >
+vim.val_idx *vim.val_idx*
+ Value index for tables representing |Float|s. A table representing
+ floating-point value 1.0 looks like this: >
{
[vim.type_idx] = vim.types.float,
[vim.val_idx] = 1.0,
}
-< See also |vim.type_idx| and |lua-special-tbl|.
-
-vim.types *vim.types*
- Table with possible values for |vim.type_idx|. Contains two sets
- of key-value pairs: first maps possible values for |vim.type_idx|
- to human-readable strings, second maps human-readable type names to
- values for |vim.type_idx|. Currently contains pairs for `float`,
- `array` and `dictionary` types.
-
- Note: one must expect that values corresponding to `vim.types.float`,
- `vim.types.array` and `vim.types.dictionary` fall under only two
- following assumptions:
- 1. Value may serve both as a key and as a value in a table. Given the
- properties of Lua tables this basically means “value is not `nil`”.
- 2. For each value in `vim.types` table `vim.types[vim.types[value]]`
- is the same as `value`.
- No other restrictions are put on types, and it is not guaranteed that
- values corresponding to `vim.types.float`, `vim.types.array` and
- `vim.types.dictionary` will not change or that `vim.types` table will
- only contain values for these three types.
+< See also |vim.type_idx| and |lua-special-tbl|.
+
+vim.types *vim.types*
+ Table with possible values for |vim.type_idx|. Contains two sets of
+ key-value pairs: first maps possible values for |vim.type_idx| to
+ human-readable strings, second maps human-readable type names to
+ values for |vim.type_idx|. Currently contains pairs for `float`,
+ `array` and `dictionary` types.
+
+ Note: one must expect that values corresponding to `vim.types.float`,
+ `vim.types.array` and `vim.types.dictionary` fall under only two
+ following assumptions:
+ 1. Value may serve both as a key and as a value in a table. Given the
+ properties of Lua tables this basically means “value is not `nil`”.
+ 2. For each value in `vim.types` table `vim.types[vim.types[value]]`
+ is the same as `value`.
+ No other restrictions are put on types, and it is not guaranteed that
+ values corresponding to `vim.types.float`, `vim.types.array` and
+ `vim.types.dictionary` will not change or that `vim.types` table will
+ only contain values for these three types.
------------------------------------------------------------------------------
LUA-VIMSCRIPT BRIDGE *lua-vimscript*
@@ -823,7 +905,7 @@ vim.fn.{func}({...}) *vim.fn*
To call autoload functions, use the syntax: >
vim.fn['some#function']({...})
<
- Unlike vim.api.|nvim_call_function| this converts directly between Vim
+ Unlike vim.api.|nvim_call_function()| this converts directly between Vim
objects and Lua objects. If the Vim function returns a float, it will
be represented directly as a Lua number. Empty lists and dictionaries
both are represented by an empty table.
@@ -882,8 +964,8 @@ vim.env *vim.env*
*lua-vim-optlocal*
*lua-vim-setlocal*
-In vimL, there is a succint and simple way to set options. For more
-information, see |set-option|. In Lua, the corresponding method is `vim.opt`.
+In Vimscript, there is an way to set options |set-option|. In Lua, the
+corresponding method is `vim.opt`.
`vim.opt` provides several conveniences for setting and controlling options
from within Lua.
@@ -891,18 +973,18 @@ from within Lua.
Examples: ~
To set a boolean toggle:
- In vimL:
+ In Vimscript:
`set number`
In Lua:
`vim.opt.number = true`
To set an array of values:
- In vimL:
+ In Vimscript:
`set wildignore=*.o,*.a,__pycache__`
In Lua, there are two ways you can do this now. One is very similar to
- the vimL way:
+ the Vimscript form:
`vim.opt.wildignore = '*.o,*.a,__pycache__'`
However, vim.opt also supports a more elegent way of setting
@@ -935,7 +1017,7 @@ from within Lua.
vim.opt.wildignore:remove { "node_modules" }
<
To set a map of values:
- In vimL:
+ In Vimscript:
`set listchars=space:_,tab:>~`
In Lua:
@@ -1110,7 +1192,9 @@ make_dict_accessor({scope}) *vim.make_dict_accessor()*
TODO: Documentation
notify({msg}, {log_level}, {_opts}) *vim.notify()*
- Notification provider without a runtime, writes to :Messages
+ Notification provider
+
+ Without a runtime, writes to :Messages
Parameters: ~
{msg} Content of the notification to show to the
@@ -1119,6 +1203,9 @@ notify({msg}, {log_level}, {_opts}) *vim.notify()*
{opts} Dictionary with optional options (timeout,
etc)
+ See also: ~
+ :help nvim_notify
+
paste({lines}, {phase}) *vim.paste()*
Paste handler, invoked by |nvim_paste()| when a conforming UI
(such as the |TUI|) pastes text into the editor.
@@ -1167,37 +1254,6 @@ region({bufnr}, {pos1}, {pos2}, {regtype}, {inclusive}) *vim.region()*
Return: ~
region lua table of the form {linenr = {startcol,endcol}}
- *vim.register_keystroke_callback()*
-register_keystroke_callback({fn}, {ns_id})
- Register a lua {fn} with an {id} to be run after every
- keystroke.
-
- If {fn} is nil, it removes the callback for the associated
- {ns_id}
- Note:
- {fn} will not be cleared from |nvim_buf_clear_namespace()|
-
- Note:
- {fn} will receive the keystrokes after mappings have been
- evaluated
-
- Parameters: ~
- {fn} function: Function to call. It should take one
- argument, which is a string. The string will contain
- the literal keys typed. See |i_CTRL-V|
- {ns_id} number? Namespace ID. If not passed or 0, will
- generate and return a new namespace ID from
- |nvim_create_namesapce()|
-
- Return: ~
- number Namespace ID associated with {fn}
-
- Note:
- {fn} will be automatically removed if an error occurs
- while calling. This is to prevent the annoying situation
- of every keystroke erroring while trying to remove a
- broken callback.
-
schedule_wrap({cb}) *vim.schedule_wrap()*
Defers callback `cb` until the Nvim API is safe to call.
@@ -1210,7 +1266,17 @@ schedule_wrap({cb}) *vim.schedule_wrap()*
deep_equal({a}, {b}) *vim.deep_equal()*
- TODO: Documentation
+ Deep compare values for equality
+
+ Tables are compared recursively unless they both provide the `eq` methamethod.
+ All other types are compared using the equality `==` operator.
+
+ Parameters: ~
+ {a} first value
+ {b} second value
+
+ Return: ~
+ `true` if values are equals, else `false` .
deepcopy({orig}) *vim.deepcopy()*
Returns a deep copy of the given object. Non-table objects are
@@ -1505,14 +1571,12 @@ validate({opt}) *vim.validate()*
vim.validate{arg1={{'foo'}, 'table'}, arg2={'foo', 'string'}}
=> NOP (success)
-<
->
- vim.validate{arg1={1, 'table'}}
- => error('arg1: expected table, got number')
-<
->
- vim.validate{arg1={3, function(a) return (a % 2) == 0 end, 'even number'}}
- => error('arg1: expected even number, got 3')
+
+ vim.validate{arg1={1, 'table'}}
+ => error('arg1: expected table, got number')
+
+ vim.validate{arg1={3, function(a) return (a % 2) == 0 end, 'even number'}}
+ => error('arg1: expected even number, got 3')
<
Parameters: ~
@@ -1581,4 +1645,25 @@ uri_to_fname({uri}) *vim.uri_to_fname()*
Return: ~
Filename
+
+==============================================================================
+Lua module: ui *lua-ui*
+
+select({items}, {opts}, {on_choice}) *vim.ui.select()*
+ Prompts the user to pick a single item from a collection of
+ entries
+
+ Parameters: ~
+ {items} table Arbitrary items
+ {opts} table Additional options
+ • prompt (string|nil) Text of the prompt.
+ Defaults to `Select one of:`
+ • format_item (function item -> text)
+ Function to format an individual item from
+ `items` . Defaults to `tostring` .
+ {on_choice} function ((item|nil, idx|nil) -> ()) Called
+ once the user made a choice. `idx` is the
+ 1-based index of `item` within `item` . `nil`
+ if the user aborted the dialog.
+
vim:tw=78:ts=8:ft=help:norl:
diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt
index 10d503e180..64c0d96aed 100644
--- a/runtime/doc/map.txt
+++ b/runtime/doc/map.txt
@@ -1306,6 +1306,7 @@ completion can be enabled:
-complete=highlight highlight groups
-complete=history :history suboptions
-complete=locale locale names (as output of locale -a)
+ -complete=lua Lua expression
-complete=mapclear buffer argument
-complete=mapping mapping name
-complete=menu menus
diff --git a/runtime/doc/motion.txt b/runtime/doc/motion.txt
index 9f8acff88a..c473244827 100644
--- a/runtime/doc/motion.txt
+++ b/runtime/doc/motion.txt
@@ -52,9 +52,14 @@ or change text. The following operators are available:
|<| < shift left
|zf| zf define a fold
|g@| g@ call function set with the 'operatorfunc' option
-
+ *motion-count-multiplied*
If the motion includes a count and the operator also had a count before it,
the two counts are multiplied. For example: "2d3w" deletes six words.
+ *operator-doubled*
+When doubling the operator it operates on a line. When using a count, before
+or after the first character, that many lines are operated upon. Thus `3dd`
+deletes three lines. A count before and after the first character is
+multiplied, thus `2y3y` yanks six lines.
After applying the operator the cursor is mostly left at the start of the text
that was operated upon. For example, "yfe" doesn't move the cursor, but "yFe"
@@ -187,9 +192,9 @@ l or *l*
*$* *<End>* *<kEnd>*
$ or <End> To the end of the line. When a count is given also go
[count - 1] lines downward, or as far is possible.
- |inclusive| motion. If a count of 2 of larger is
+ |inclusive| motion. If a count of 2 or larger is
given and the cursor is on the last line, that is an
- error an the cursor doesn't move.
+ error and the cursor doesn't move.
In Visual mode the cursor goes to just after the last
character in the line.
When 'virtualedit' is active, "$" may move the cursor
diff --git a/runtime/doc/nvim_terminal_emulator.txt b/runtime/doc/nvim_terminal_emulator.txt
index 5885b20ab7..5ad69d1122 100644
--- a/runtime/doc/nvim_terminal_emulator.txt
+++ b/runtime/doc/nvim_terminal_emulator.txt
@@ -13,7 +13,7 @@ from the connected program.
Terminal buffers behave like normal buffers, except:
- With 'modifiable', lines can be edited but not deleted.
- 'scrollback' controls how many lines are kept.
-- Output is followed if the cursor is on the last line.
+- Output is followed ("tailed") if cursor is on the last line.
- 'modified' is the default. You can set 'nomodified' to avoid a warning when
closing the terminal buffer.
- 'bufhidden' defaults to "hide".
@@ -47,8 +47,9 @@ Input *terminal-input*
To send input, enter |Terminal-mode| using any command that would enter "insert
mode" in a normal buffer, such as |i| or |:startinsert|. In this mode all keys
-except <C-\><C-N> are sent to the underlying program. Use <C-\><C-N> to return
-to normal-mode. |CTRL-\_CTRL-N|
+except <C-\> are sent to the underlying program. If <C-\> is pressed, the
+next key is sent unless it is <C-N>. Use <C-\><C-N> to return to normal-mode.
+|CTRL-\_CTRL-N|
Terminal-mode forces these local options:
@@ -134,6 +135,10 @@ Example: >
programs can set this by emitting an escape sequence.
- |'channel'| Terminal PTY |job-id|. Can be used with |chansend()| to send
input to the terminal.
+- The |TermClose| event gives the terminal job exit code in the |v:event|
+ "status" field. For example, this autocmd closes terminal buffers if the job
+ exited without error: >
+ autocmd TermClose * if !v:event.status | exe 'bdelete! '..expand('<abuf>') | endif
Use |jobwait()| to check if the terminal job has finished: >
let running = jobwait([&channel], 0)[0] == -1
@@ -316,6 +321,34 @@ Other commands ~
isn't one
+Events ~
+ *termdebug-events*
+Four autocommands can be used: >
+ au User TermdebugStartPre echomsg 'debugging starting'
+ au User TermdebugStartPost echomsg 'debugging started'
+ au User TermdebugStopPre echomsg 'debugging stopping'
+ au User TermdebugStopPost echomsg 'debugging stopped'
+<
+ *TermdebugStartPre*
+TermdebugStartPre Before starting debugging.
+ Not triggered if the debugger is already
+ running or |g:termdebugger| cannot be
+ executed.
+ *TermdebugStartPost*
+TermdebugStartPost After debugging has initialized.
+ If a "!" bang is passed to `:Termdebug` or
+ `:TermdebugCommand` the event is triggered
+ before running the provided command in gdb.
+ *TermdebugStopPre*
+TermdebugStopPre Before debugging ends, when gdb is terminated,
+ most likely after issuing a "quit" command in
+ the gdb window.
+ *TermdebugStopPost*
+TermdebugStopPost After debugging has ended, gdb-related windows
+ are closed, debug buffers wiped out and
+ the state before the debugging was restored.
+
+
Prompt mode ~
*termdebug-prompt*
When on MS-Windows, gdb will run in a buffer with 'buftype' set to "prompt".
@@ -324,12 +357,10 @@ This works slightly differently:
mode with <Esc>, then you can move around in the buffer, copy/paste, etc.
Go back to editing the gdb command with any command that starts Insert mode,
such as `a` or `i`.
-- The program being debugged will run in a separate window. On MS-Windows
- this is a new console window. On Unix, if the |+terminal| feature is
- available a Terminal window will be opened to run the debugged program in.
+- A separate :terminal window will be opened to run the debugged program in.
*termdebug_use_prompt*
-Prompt mode can be used even when the |+terminal| feature is present with: >
+Prompt mode can be used with: >
let g:termdebug_use_prompt = 1
<
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 791fb8664e..85be6eddaa 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -435,6 +435,15 @@ chance that a normal word like "lex:" is caught. There is one exception:
version 3.0). Using "ex:" at the start of the line will be ignored (this
could be short for "example:").
+If the modeline is disabled within a modeline, subsequent modelines will be
+ignored. This is to allow turning off modeline on a per-file basis. This is
+useful when a line looks like a modeline but isn't. For example, it would be
+good to start a YAML file containing strings like "vim:" with
+ # vim: nomodeline ~
+so as to avoid modeline misdetection. Following options on the same line
+after modeline deactivation, if any, are still evaluated (but you would
+normally not have any).
+
*modeline-local*
The options are set like with ":setlocal": The new value only applies to the
buffer and window that contain the file. Although it's possible to set global
@@ -824,12 +833,12 @@ A jump table for the options with a short description can be found at |Q_op|.
again not rename the file.
*'backupdir'* *'bdir'*
-'backupdir' 'bdir' string (default ".,$XDG_DATA_HOME/nvim/backup")
+'backupdir' 'bdir' string (default ".,$XDG_DATA_HOME/nvim/backup//")
global
List of directories for the backup file, separated with commas.
- The backup file will be created in the first directory in the list
- where this is possible. The directory must exist, Vim will not
- create it for you.
+ where this is possible. If none of the directories exist Nvim will
+ attempt to create the last directory in the list.
- Empty means that no backup file will be created ('patchmode' is
impossible!). Writing may fail because of this.
- A directory "." means to put the backup file in the same directory
@@ -1038,7 +1047,12 @@ A jump table for the options with a short description can be found at |Q_op|.
continuation (positive).
sbr Display the 'showbreak' value before applying the
additional indent.
- The default value for min is 20 and shift is 0.
+ list:{n} Adds an additional indent for lines that match a
+ numbered or bulleted list (using the
+ 'formatlistpat' setting).
+ list:-1 Uses the length of a match with 'formatlistpat'
+ for indentation.
+ The default value for min is 20, shift and list is 0.
*'browsedir'* *'bsdir'*
'browsedir' 'bsdir' string (default: "last")
@@ -1802,13 +1816,30 @@ A jump table for the options with a short description can be found at |Q_op|.
*'cursorline'* *'cul'* *'nocursorline'* *'nocul'*
'cursorline' 'cul' boolean (default off)
local to window
- Highlight the screen line of the cursor with CursorLine
- |hl-CursorLine|. Useful to easily spot the cursor. Will make screen
- redrawing slower.
+ Highlight the text line of the cursor with CursorLine |hl-CursorLine|.
+ Useful to easily spot the cursor. Will make screen redrawing slower.
When Visual mode is active the highlighting isn't used to make it
easier to see the selected text.
+ *'cursorlineopt'* *'culopt'*
+'cursorlineopt' 'culopt' string (default: "number,line")
+ local to window
+ Comma separated list of settings for how 'cursorline' is displayed.
+ Valid values:
+ "line" Highlight the text line of the cursor with
+ CursorLine |hl-CursorLine|.
+ "screenline" Highlight only the screen line of the cursor with
+ CursorLine |hl-CursorLine|.
+ "number" Highlight the line number of the cursor with
+ CursorLineNr |hl-CursorLineNr|.
+
+ Special value:
+ "both" Alias for the values "line,number".
+
+ "line" and "screenline" cannot be used together.
+
+
*'debug'*
'debug' string (default "")
global
@@ -2138,8 +2169,7 @@ A jump table for the options with a short description can be found at |Q_op|.
global or local to buffer |global-local|
External program to use for "=" command. When this option is empty
the internal formatting functions are used; either 'lisp', 'cindent'
- or 'indentexpr'. When Vim was compiled without internal formatting,
- the "indent" program is used.
+ or 'indentexpr'.
Environment variables are expanded |:set_env|. See |option-backslash|
about including spaces and backslashes.
This option cannot be set from a |modeline| or in the |sandbox|, for
@@ -3057,19 +3087,18 @@ A jump table for the options with a short description can be found at |Q_op|.
See |help-translated|.
*'hidden'* *'hid'* *'nohidden'* *'nohid'*
-'hidden' 'hid' boolean (default off)
- global
- When off a buffer is unloaded when it is |abandon|ed. When on a
- buffer becomes hidden when it is |abandon|ed. If the buffer is still
- displayed in another window, it does not become hidden, of course.
- The commands that move through the buffer list sometimes make a buffer
- hidden although the 'hidden' option is off: When the buffer is
- modified, 'autowrite' is off or writing is not possible, and the '!'
- flag was used. See also |windows.txt|.
- To only make one buffer hidden use the 'bufhidden' option.
- This option is set for one command with ":hide {command}" |:hide|.
- WARNING: It's easy to forget that you have changes in hidden buffers.
- Think twice when using ":q!" or ":qa!".
+'hidden' 'hid' boolean (default on)
+ global
+ When off a buffer is unloaded (including loss of undo information)
+ when it is |abandon|ed. When on a buffer becomes hidden when it is
+ |abandon|ed. A buffer displayed in another window does not become
+ hidden, of course.
+ Commands that move through the buffer list sometimes hide a buffer
+ although the 'hidden' option is off: when the buffer is modified,
+ 'autowrite' is off or writing is not possible, and the '!' flag was
+ used. See also |windows|.
+ To hide a specific buffer use the 'bufhidden' option.
+ 'hidden' is set for one command with ":hide {command}" |:hide|.
*'history'* *'hi'*
'history' 'hi' number (Vim default: 10000, Vi default: 0)
@@ -3192,7 +3221,7 @@ A jump table for the options with a short description can be found at |Q_op|.
option to a valid keymap name.
*'inccommand'* *'icm'*
-'inccommand' 'icm' string (default "")
+'inccommand' 'icm' string (default "nosplit")
global
"nosplit": Shows the effects of a command incrementally, as you type.
@@ -3477,7 +3506,7 @@ A jump table for the options with a short description can be found at |Q_op|.
|jumplist-stack|
*'joinspaces'* *'js'* *'nojoinspaces'* *'nojs'*
-'joinspaces' 'js' boolean (default on)
+'joinspaces' 'js' boolean (default off)
global
Insert two spaces after a '.', '?' and '!' with a join command.
Otherwise only one space is inserted.
@@ -3722,16 +3751,25 @@ A jump table for the options with a short description can be found at |Q_op|.
*lcs-space*
space:c Character to show for a space. When omitted, spaces
are left blank.
+ *lcs-multispace*
+ multispace:c...
+ One or more characters to use cyclically to show for
+ multiple consecutive spaces. Overrides the "space"
+ setting, except for single spaces. When omitted, the
+ "space" setting is used. For example,
+ `:set listchars=multispace:---+` shows ten consecutive
+ spaces as:
+ ---+---+--
*lcs-lead*
lead:c Character to show for leading spaces. When omitted,
- leading spaces are blank. Overrides the "space"
- setting for leading spaces. You can combine it with
- "tab:", for example: >
+ leading spaces are blank. Overrides the "space" and
+ "multispace" settings for leading spaces. You can
+ combine it with "tab:", for example: >
:set listchars+=tab:>-,lead:.
< *lcs-trail*
trail:c Character to show for trailing spaces. When omitted,
- trailing spaces are blank. Overrides the "space"
- setting for trailing spaces.
+ trailing spaces are blank. Overrides the "space" and
+ "multispace" settings for trailing spaces.
*lcs-extends*
extends:c Character to show in the last column, when 'wrap' is
off and the line continues beyond the right of the
@@ -3756,7 +3794,8 @@ A jump table for the options with a short description can be found at |Q_op|.
:set lcs=tab:>-,eol:<,nbsp:%
:set lcs=extends:>,precedes:<
< |hl-NonText| highlighting will be used for "eol", "extends" and
- "precedes". |hl-Whitespace| for "nbsp", "space", "tab" and "trail".
+ "precedes". |hl-Whitespace| for "nbsp", "space", "tab", "multispace",
+ "lead" and "trail".
*'lpl'* *'nolpl'* *'loadplugins'* *'noloadplugins'*
'loadplugins' 'lpl' boolean (default on)
@@ -3777,8 +3816,6 @@ A jump table for the options with a short description can be found at |Q_op|.
Only switch it off when working with old Vi scripts. In any other
situation write patterns that work when 'magic' is on. Include "\M"
when you want to |/\M|.
- In |Vim9| script the value of 'magic' is ignored, patterns behave like
- it is always set.
*'makeef'* *'mef'*
'makeef' 'mef' string (default: "")
@@ -4301,7 +4338,7 @@ A jump table for the options with a short description can be found at |Q_op|.
*'packpath'* *'pp'*
'packpath' 'pp' string (default: see 'runtimepath')
- Directories used to find packages. See |packages|.
+ Directories used to find packages. See |packages| and |rtp-packages|.
*'paragraphs'* *'para'*
@@ -4332,19 +4369,21 @@ A jump table for the options with a short description can be found at |Q_op|.
- abbreviations are disabled
- 'autoindent' is reset
- 'expandtab' is reset
- - 'formatoptions' is used like it is empty
+ - 'hkmap' is reset
- 'revins' is reset
- 'ruler' is reset
- 'showmatch' is reset
- - 'smartindent' is reset
- 'smarttab' is reset
- 'softtabstop' is set to 0
- 'textwidth' is set to 0
- 'wrapmargin' is set to 0
+ - 'varsofttabstop' is made empty
These options keep their value, but their effect is disabled:
- 'cindent'
+ - 'formatoptions' is used like it is empty
- 'indentexpr'
- 'lisp'
+ - 'smartindent'
NOTE: When you start editing another file while the 'paste' option is
on, settings from the modelines or autocommands may change the
settings again, causing trouble when pasting text. You might want to
@@ -4540,11 +4579,6 @@ A jump table for the options with a short description can be found at |Q_op|.
List of items that control the format of the output of |:hardcopy|.
See |popt-option|.
- *'prompt'* *'noprompt'*
-'prompt' boolean (default on)
- global
- When on a ":" prompt is used in Ex mode.
-
*'pumblend'* *'pb'*
'pumblend' 'pb' number (default 0)
global
@@ -4863,9 +4897,11 @@ A jump table for the options with a short description can be found at |Q_op|.
ordering. This is for preferences to overrule or add to the
distributed defaults or system-wide settings (rarely needed).
- More entries are added when using |packages|. If it gets very long
- then `:set rtp` will be truncated, use `:echo &rtp` to see the full
- string.
+ *rtp-packages*
+ "start" packages will additionally be used to search for runtime files
+ after these, but package entries are not visible in `:set rtp`.
+ See |runtime-search-path| for more information. "opt" packages
+ will be explicitly added to &rtp when |:packadd| is used.
Note that, unlike 'path', no wildcards like "**" are allowed. Normal
wildcards are allowed, but can significantly slow down searching for
@@ -5459,7 +5495,7 @@ A jump table for the options with a short description can be found at |Q_op|.
*'showbreak'* *'sbr'* *E595*
'showbreak' 'sbr' string (default "")
- global
+ global or local to window |global-local|
String to put at the start of lines that have been wrapped. Useful
values are "> " or "+++ ": >
:set showbreak=>\
@@ -5473,7 +5509,10 @@ A jump table for the options with a short description can be found at |Q_op|.
Note that tabs after the showbreak will be displayed differently.
If you want the 'showbreak' to appear in between line numbers, add the
"n" flag to 'cpoptions'.
-
+ A window-local value overrules a global value. If the global value is
+ set and you want no value in the current window use NONE: >
+ :setlocal showbreak=NONE
+<
*'showcmd'* *'sc'* *'noshowcmd'* *'nosc'*
'showcmd' 'sc' boolean (Vim default: on, Vi default: off)
global
@@ -5733,6 +5772,8 @@ A jump table for the options with a short description can be found at |Q_op|.
If the name "cjk" is included East Asian characters are excluded from
spell checking. This is useful when editing text that also has Asian
words.
+ Note that the "medical" dictionary does not exist, it is just an
+ example of a longer name.
*E757*
As a special case the name of a .spl file can be given as-is. The
first "_xx" in the name is removed and used as the region name
@@ -6100,9 +6141,11 @@ A jump table for the options with a short description can be found at |Q_op|.
specify special kinds of buffers. See |special-buffers|.
*'switchbuf'* *'swb'*
-'switchbuf' 'swb' string (default "")
+'switchbuf' 'swb' string (default "uselast")
global
This option controls the behavior when switching between buffers.
+ Mostly for |quickfix| commands some values are also used for other
+ commands, as mentioned below.
Possible values (comma separated list):
useopen If included, jump to the first open window that
contains the specified buffer (if there is one).
@@ -6518,17 +6561,17 @@ A jump table for the options with a short description can be found at |Q_op|.
'ttyfast' 'tf' Removed. |vim-differences|
*'undodir'* *'udir'* *E5003*
-'undodir' 'udir' string (default "$XDG_DATA_HOME/nvim/undo")
+'undodir' 'udir' string (default "$XDG_DATA_HOME/nvim/undo//")
global
List of directory names for undo files, separated with commas.
- See |'backupdir'| for details of the format.
+ See 'backupdir' for details of the format.
"." means using the directory of the file. The undo file name for
"file.txt" is ".file.txt.un~".
For other directories the file name is the full path of the edited
file, with path separators replaced with "%".
When writing: The first directory that exists is used. "." always
- works, no directories after "." will be used for writing. If none of
- the directories exist Neovim will attempt to create last directory in
+ works, no directories after "." will be used for writing. If none of
+ the directories exist Nvim will attempt to create the last directory in
the list.
When reading all entries are tried to find an undo file. The first
undo file that exists is used. When it cannot be read an error is
@@ -6537,6 +6580,10 @@ 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|, for
security reasons.
+ Note that unlike 'directory' and 'backupdir', 'undodir' always acts as
+ though the trailing slashes are present (see 'backupdir' for what this
+ means).
+
*'undofile'* *'noundofile'* *'udf'* *'noudf'*
'undofile' 'udf' boolean (default off)
local to buffer
@@ -6677,14 +6724,14 @@ A jump table for the options with a short description can be found at |Q_op|.
displayed when 'verbosefile' is set.
*'viewdir'* *'vdir'*
-'viewdir' 'vdir' string (default: "$XDG_DATA_HOME/nvim/view")
+'viewdir' 'vdir' string (default: "$XDG_DATA_HOME/nvim/view//")
global
Name of the directory where to store files for |:mkview|.
This option cannot be set from a |modeline| or in the |sandbox|, for
security reasons.
*'viewoptions'* *'vop'*
-'viewoptions' 'vop' string (default: "folds,options,cursor,curdir")
+'viewoptions' 'vop' string (default: "folds,cursor,curdir")
global
Changes the effect of the |:mkview| command. It is a comma separated
list of words. Each word enables saving and restoring something:
@@ -6723,6 +6770,7 @@ A jump table for the options with a short description can be found at |Q_op|.
The `g$` command will move to the end of the screen line.
It doesn't make sense to combine "all" with "onemore", but you will
not get a warning for it.
+ When combined with other words, "none" is ignored.
*'visualbell'* *'vb'* *'novisualbell'* *'novb'* *beep*
'visualbell' 'vb' boolean (default off)
@@ -6773,8 +6821,9 @@ A jump table for the options with a short description can be found at |Q_op|.
More info here: |cmdline-completion|.
The character is not recognized when used inside a macro. See
'wildcharm' for that.
+ Some keys will not work, such as CTRL-C, <CR> and Enter.
Although 'wc' is a number option, you can set it to a special key: >
- :set wc=<Esc>
+ :set wc=<Tab>
<
*'wildcharm'* *'wcm'*
@@ -7093,8 +7142,7 @@ A jump table for the options with a short description can be found at |Q_op|.
Allows writing to any file with no need for "!" override.
*'writebackup'* *'wb'* *'nowritebackup'* *'nowb'*
-'writebackup' 'wb' boolean (default on with |+writebackup| feature, off
- otherwise)
+'writebackup' 'wb' boolean (default on)
global
Make a backup before overwriting a file. The backup is removed after
the file was successfully written, unless the 'backup' option is
diff --git a/runtime/doc/pattern.txt b/runtime/doc/pattern.txt
index e74f3b72bf..c49cc6d540 100644
--- a/runtime/doc/pattern.txt
+++ b/runtime/doc/pattern.txt
@@ -1204,7 +1204,7 @@ x A single character, with no special meaning, matches itself
\%d123 Matches the character specified with a decimal number. Must be
followed by a non-digit.
-\%o40 Matches the character specified with an octal number up to 0377.
+\%o40 Matches the character specified with an octal number up to 0o377.
Numbers below 0o40 must be followed by a non-octal digit or a
non-digit.
\%x2a Matches the character specified with up to two hexadecimal characters.
diff --git a/runtime/doc/pi_netrw.txt b/runtime/doc/pi_netrw.txt
index 4b61cd4c25..3ac61be6f2 100644
--- a/runtime/doc/pi_netrw.txt
+++ b/runtime/doc/pi_netrw.txt
@@ -54,6 +54,7 @@ Copyright: Copyright (C) 2017 Charles E Campbell *netrw-copyright*
Browsing With A Horizontally Split Window...........|netrw-o|
Browsing With A New Tab.............................|netrw-t|
Browsing With A Vertically Split Window.............|netrw-v|
+ Change File Permission..............................|netrw-gp|
Change Listing Style.(thin wide long tree)..........|netrw-i|
Changing To A Bookmarked Directory..................|netrw-gb|
Changing To A Predecessor Directory.................|netrw-u|
@@ -1095,6 +1096,7 @@ QUICK REFERENCE: MAPS *netrw-browse-maps* {{{2
gf Force treatment as file |netrw-gf|
gh Quick hide/unhide of dot-files |netrw-gh|
gn Make top of tree the directory below the cursor |netrw-gn|
+ gp Change local-only file permissions |netrw-gp|
i Cycle between thin, long, wide, and tree listings |netrw-i|
I Toggle the displaying of the banner |netrw-I|
mb Bookmark current directory |netrw-mb|
@@ -1510,6 +1512,8 @@ Netrw determines which special handler by the following method:
If g:netrw_browsex_viewer == '-', then netrwFileHandlers#Invoke() will be
used instead (see |netrw_filehandler|).
+ If the viewer you wish to use does not support handling of a remote URL
+ directory, set |g:netrw_browsex_support_remote| to 0.
* for Windows 32 or 64, the URL and FileProtocolHandler dlls are used.
* for Gnome (with gnome-open): gnome-open is used.
* for KDE (with kfmclient) : kfmclient is used
@@ -2104,8 +2108,8 @@ the two directories the same, use the "cd" map (type cd). That map will
set Vim's notion of the current directory to netrw's current browsing
directory.
-|netrw-cd|: This map's name was changed from "c" to cd (see |netrw-cd|).
- This change was done to allow for |netrw-cb| and |netrw-cB| maps.
+|netrw-cd| : This map's name was changed from "c" to cd (see |netrw-cd|).
+ This change was done to allow for |netrw-cb| and |netrw-cB| maps.
Associated setting variable: |g:netrw_keepdir|
@@ -2607,13 +2611,29 @@ your browsing preferences. (see also: |netrw-settings|)
a script/function to handle the given
extension. (see |netrw_filehandler|).
+ *g:netrw_browsex_support_remote*
+ specify if the specified viewer supports a
+ remote URL. (see |netrw-handler|).
+
*g:netrw_chgperm* Unix/Linux: "chmod PERM FILENAME"
Windows: "cacls FILENAME /e /p PERM"
Used to change access permission for a file.
+ *g:netrw_clipboard* =1
+ By default, netrw will attempt to insure that
+ the clipboard's values will remain unchanged.
+ However, some users report that they have
+ speed problems with this; consequently, this
+ option, when set to zero, lets such users
+ prevent netrw from saving and restoring the
+ clipboard (the latter is done only as needed).
+ That means that if the clipboard is changed
+ (inadvertently) by normal netrw operation that
+ it will not be restored to its prior state.
+
*g:netrw_compress* ="gzip"
- Will compress marked files with this
- command
+ Will compress marked files with this
+ command
*g:Netrw_corehandler* Allows one to specify something additional
to do when handling <core> files via netrw's
@@ -2639,12 +2659,23 @@ your browsing preferences. (see also: |netrw-settings|)
=2 cul u-cuc cul u-cuc
=3 cul u-cuc cul cuc
=4 cul cuc cul cuc
+ =5 U-cul U-cuc U-cul U-cuc
+ =6 U-cul U-cuc cul U-cuc
+ =7 cul U-cuc cul U-cuc
+ =8 cul U-cuc cul cuc
Where
- u-cul : user's |'cursorline'| setting used
- u-cuc : user's |'cursorcolumn'| setting used
- cul : |'cursorline'| locally set
- cuc : |'cursorcolumn'| locally set
+ u-cul : user's |'cursorline'| initial setting used
+ u-cuc : user's |'cursorcolumn'| initial setting used
+ U-cul : user's |'cursorline'| current setting used
+ U-cuc : user's |'cursorcolumn'| current setting used
+ cul : |'cursorline'| will be locally set
+ cuc : |'cursorcolumn'| will be locally set
+
+ The "initial setting" means the values of
+ the |'cuc'| and |'cul'| settings in effect when
+ netrw last saw |g:netrw_cursor| >= 5 or when
+ netrw was initially run.
*g:netrw_decompress* = { ".gz" : "gunzip" ,
".bz2" : "bunzip2" ,
@@ -2654,7 +2685,7 @@ your browsing preferences. (see also: |netrw-settings|)
decompression programs.
*g:netrw_dirhistmax* =10: controls maximum quantity of past
- history. May be zero to supppress
+ history. May be zero to suppress
history.
(related: |netrw-qb| |netrw-u| |netrw-U|)
@@ -3141,6 +3172,9 @@ To open a new file in netrw's current directory, press "%". This map
will query the user for a new filename; an empty file by that name will
be placed in the netrw's current directory (ie. b:netrw_curdir).
+If Lexplore (|netrw-:Lexplore|) is in use, the new file will be generated
+in the |g:netrw_chgwin| window.
+
Related topics: |netrw-d|
@@ -3876,6 +3910,32 @@ netrw:
==============================================================================
12. History *netrw-history* {{{1
+ v171: Oct 09, 2020 * included code in s:NetrwOptionsSafe()
+ to allow |'bh'| to be set to delete when
+ rather than hide when g:netrw_fastbrowse
+ was zero.
+ * Installed |g:netrw_clipboard| setting
+ * Installed option bypass for |'guioptions'|
+ a/A settings
+ * Changed popup_beval() to |popup_atcursor|()
+ in netrw#ErrorMsg (lacygoill). Apparently
+ popup_beval doesn't reliably close the
+ popup when the mouse is moved.
+ * VimEnter() now using win_execute to examine
+ buffers for an attempt to open a directory.
+ Avoids issues with popups/terminal from
+ command line. (lacygoill)
+ Jun 28, 2021 * (zeertzjq) provided a patch for use of
+ xmap,xno instead of vmap,vno in
+ netrwPlugin.vim. Avoids entanglement with
+ select mode.
+ Jul 14, 2021 * Fixed problem addressed by tst976; opening
+ a file using tree mode, going up a
+ directory, and opening a file there was
+ opening the file in the wrong directory.
+ Jul 28, 2021 * (Ingo Karkat) provided a patch fixing an
+ E488 error with netrwPlugin.vim
+ (occurred for vim versions < 8.02)
v170: Mar 11, 2020 * (reported by Reiner Herrmann) netrw+tree
would not hide with the ^\..* pattern
correctly.
@@ -3892,7 +3952,7 @@ netrw:
Jun 07, 2020 * (reported by Jo Totland) repeatedly invoking
:Lexplore and quitting it left unused
hidden buffers. Netrw will now set netrw
- buffers created by :Lexplore to |bh|=wipe.
+ buffers created by :Lexplore to |'bh'|=wipe.
v169: Dec 20, 2019 * (reported by amkarthik) that netrw's x
(|netrw-x|) would throw an error when
attempting to open a local directory.
diff --git a/runtime/doc/print.txt b/runtime/doc/print.txt
index e7de5b9ee3..d9320ad315 100644
--- a/runtime/doc/print.txt
+++ b/runtime/doc/print.txt
@@ -103,10 +103,9 @@ will use the "latin1" print character encoding file.
When 'encoding' is set to a multibyte encoding, Vim will try to convert
characters to the printing encoding for printing (if 'printencoding' is empty
-then the conversion will be to latin1). Conversion to a printing encoding
-other than latin1 will require Vim to be compiled with the |+iconv| feature.
-If no conversion is possible then printing will fail. Any characters that
-cannot be converted will be replaced with upside down question marks.
+then the conversion will be to latin1). If no conversion is possible then
+printing will fail. Any characters that cannot be converted will be replaced
+with upside down question marks.
Two print character encoding files are provided to support default Mac and
HPUX character encodings and are used by default on these platforms. Code page
@@ -176,9 +175,7 @@ the font. When omitted, the point size is 10.
'printheader' 'pheader' string (default "%<%f%h%m%=Page %N")
global
This defines the format of the header produced in |:hardcopy| output. The
-option is defined in the same way as the 'statusline' option. If Vim has not
-been compiled with the |+statusline| feature, this option has no effect and a
-simple default header is used, which shows the page number. The same simple
+option is defined in the same way as the 'statusline' option. The same simple
header is used when this option is empty.
*pmbcs-option*
diff --git a/runtime/doc/provider.txt b/runtime/doc/provider.txt
index be895f9e4e..b785010699 100644
--- a/runtime/doc/provider.txt
+++ b/runtime/doc/provider.txt
@@ -207,6 +207,7 @@ registers. Nvim looks for these clipboard tools, in order of priority:
- lemonade (for SSH) https://github.com/pocke/lemonade
- doitclient (for SSH) http://www.chiark.greenend.org.uk/~sgtatham/doit/
- win32yank (Windows)
+ - termux (via termux-clipboard-set, termux-clipboard-set)
- tmux (if $TMUX is set)
*g:clipboard*
diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt
index 563fb0c962..9c1f584415 100644
--- a/runtime/doc/quickfix.txt
+++ b/runtime/doc/quickfix.txt
@@ -1333,7 +1333,8 @@ Basic items
%o module name (finds a string)
%l line number (finds a number)
%c column number (finds a number representing character
- column of the error, (1 <tab> == 1 character column))
+ column of the error, byte index, a <tab> is 1
+ character column)
%v virtual column number (finds a number representing
screen column of the error (1 <tab> == 8 screen
columns))
diff --git a/runtime/doc/quickref.txt b/runtime/doc/quickref.txt
index fb20a583c9..77e69a3eea 100644
--- a/runtime/doc/quickref.txt
+++ b/runtime/doc/quickref.txt
@@ -659,6 +659,7 @@ Short explanation of each option: *option-list*
'cursorbind' 'crb' move cursor in window as it moves in other windows
'cursorcolumn' 'cuc' highlight the screen column of the cursor
'cursorline' 'cul' highlight the screen line of the cursor
+'cursorlineopt' 'culopt' settings for 'cursorline'
'debug' set to "msg" to see all error messages
'define' 'def' pattern to be used to find a macro definition
'delcombine' 'deco' delete combining characters on their own
@@ -809,7 +810,6 @@ Short explanation of each option: *option-list*
'printmbcharset' 'pmbcs' CJK character set to be used for :hardcopy
'printmbfont' 'pmbfn' font names to be used for CJK output of :hardcopy
'printoptions' 'popt' controls the format of :hardcopy output
-'prompt' 'prompt' enable prompt in Ex mode
'pumheight' 'ph' maximum height of the popup menu
'pumwidth' 'pw' minimum width of the popup menu
'pythondll' name of the Python 2 dynamic library
diff --git a/runtime/doc/remote.txt b/runtime/doc/remote.txt
deleted file mode 100644
index 6c2ceb45be..0000000000
--- a/runtime/doc/remote.txt
+++ /dev/null
@@ -1,189 +0,0 @@
-*remote.txt* Nvim
-
-
- VIM REFERENCE MANUAL by Bram Moolenaar
-
-
-Vim client-server communication *client-server*
-
- Type |gO| to see the table of contents.
-
-==============================================================================
-1. Common functionality *clientserver*
-
-When compiled with the |+clientserver| option, Vim can act as a command
-server. It accepts messages from a client and executes them. At the same
-time, Vim can function as a client and send commands to a Vim server.
-
-The following command line arguments are available:
-
- argument meaning ~
-
- --remote [+{cmd}] {file} ... *--remote*
- Open the file list in a remote Vim. When
- there is no Vim server, execute locally.
- There is one optional init command: +{cmd}.
- This must be an Ex command that can be
- followed by "|".
- The rest of the command line is taken as the
- file list. Thus any non-file arguments must
- come before this.
- You cannot edit stdin this way |--|.
- The remote Vim is raised. If you don't want
- this use >
- vim --remote-send "<C-\><C-N>:n filename<CR>"
-<
- --remote-silent [+{cmd}] {file} ... *--remote-silent*
- As above, but don't complain if there is no
- server and the file is edited locally.
- --remote-wait [+{cmd}] {file} ... *--remote-wait*
- As --remote, but wait for files to complete
- (unload) in remote Vim.
- --remote-wait-silent [+{cmd}] {file} ... *--remote-wait-silent*
- As --remote-wait, but don't complain if there
- is no server.
- *--remote-tab*
- --remote-tab Like --remote but open each file in a new
- tabpage.
- *--remote-tab-silent*
- --remote-tab-silent Like --remote-silent but open each file in a
- new tabpage.
- *--remote-tab-wait*
- --remote-tab-wait Like --remote-wait but open each file in a new
- tabpage.
-
- *--remote-tab-wait-silent*
- --remote-tab-wait-silent Like --remote-wait-silent but open each file
- in a new tabpage.
- *--remote-send*
- --remote-send {keys} Send {keys} to server and exit. The {keys}
- are not mapped. Special key names are
- recognized, e.g., "<CR>" results in a CR
- character.
- *--remote-expr*
- --remote-expr {expr} Evaluate {expr} in server and print the result
- on stdout.
-
-Examples ~
-
-Edit "file.txt" in an already running GVIM server: >
- gvim --remote file.txt
-
-Edit "file.txt" in an already running server called FOOBAR: >
- gvim --servername FOOBAR --remote file.txt
-
-Edit "file.txt" in server "FILES" if it exists, become server "FILES"
-otherwise: >
- gvim --servername FILES --remote-silent file.txt
-
-This doesn't work, all arguments after --remote will be used as file names: >
- gvim --remote --servername FOOBAR file.txt
-
-Edit file "+foo" in a remote server (note the use of "./" to avoid the special
-meaning of the leading plus): >
- vim --remote ./+foo
-
-Tell the remote server "BLA" to write all files and exit: >
- vim --servername BLA --remote-send '<C-\><C-N>:wqa<CR>'
-
-
-SERVER NAME *client-server-name*
-
-By default Vim will try to register the name under which it was invoked (gvim,
-egvim ...). This can be overridden with the --servername argument. If the
-specified name is not available, a postfix is applied until a free name is
-encountered, i.e. "gvim1" for the second invocation of gvim on a particular
-X-server. The resulting name is available in the servername builtin variable
-|v:servername|. The case of the server name is ignored, thus "gvim" and
-"GVIM" are considered equal.
-
-When Vim is invoked with --remote, --remote-wait or --remote-send it will try
-to locate the server name determined by the invocation name and --servername
-argument as described above. If an exact match is not available, the first
-server with the number postfix will be used. If a name with the number
-postfix is specified with the --servername argument, it must match exactly.
-
-If no server can be located and --remote or --remote-wait was used, Vim will
-start up according to the rest of the command line and do the editing by
-itself. This way it is not necessary to know whether gvim is already started
-when sending command to it.
-
-The --serverlist argument will cause Vim to print a list of registered command
-servers on the standard output (stdout) and exit.
-
-Win32 Note: Making the Vim server go to the foreground doesn't always work,
-because MS-Windows doesn't allow it. The client will move the server to the
-foreground when using the --remote or --remote-wait argument and the server
-name starts with "g".
-
-
-REMOTE EDITING
-
-The --remote argument will cause a |:drop| command to be constructed from the
-rest of the command line and sent as described above.
-The --remote-wait argument does the same thing and additionally sets up to
-wait for each of the files to have been edited. This uses the BufUnload
-event, thus as soon as a file has been unloaded, Vim assumes you are done
-editing it.
-Note that the --remote and --remote-wait arguments will consume the rest of
-the command line. I.e. all remaining arguments will be regarded as filenames.
-You can not put options there!
-
-
-FUNCTIONS
- *E240* *E573*
-There are a number of Vim functions for scripting the command server. See
-the description in |eval.txt| or use CTRL-] on the function name to jump to
-the full explanation.
-
- synopsis explanation ~
- remote_startserver( name) run a server
- remote_expr( server, string, idvar) send expression
- remote_send( server, string, idvar) send key sequence
- serverlist() get a list of available servers
- remote_peek( serverid, retvar) check for reply string
- remote_read( serverid) read reply string
- server2client( serverid, string) send reply string
- remote_foreground( server) bring server to the front
-
-See also the explanation of |CTRL-\_CTRL-N|. Very useful as a leading key
-sequence.
-The {serverid} for server2client() can be obtained with expand("<client>")
-
-==============================================================================
-2. X11 specific items *x11-clientserver*
- *E247* *E248* *E251* *E258* *E277*
-
-The communication between client and server goes through the X server. The
-display of the Vim server must be specified. The usual protection of the X
-server is used, you must be able to open a window on the X server for the
-communication to work. It is possible to communicate between different
-systems.
-
-By default, a GUI Vim will register a name on the X-server by which it can be
-addressed for subsequent execution of injected strings. Vim can also act as
-a client and send strings to other instances of Vim on the same X11 display.
-
-When an X11 GUI Vim (gvim) is started, it will try to register a send-server
-name on the 'VimRegistry' property on the root window.
-
-An empty --servername argument will cause the command server to be disabled.
-
-To send commands to a Vim server from another application, read the source
-file src/if_xcmdsrv.c, it contains some hints about the protocol used.
-
-==============================================================================
-3. Win32 specific items *w32-clientserver*
-
-Every Win32 Vim can work as a server, also in the console. You do not need a
-version compiled with OLE. Windows messages are used, this works on any
-version of MS-Windows. But only communication within one system is possible.
-
-Since MS-Windows messages are used, any other application should be able to
-communicate with a Vim server.
-
-When using gvim, the --remote-wait only works properly this way: >
-
- start /w gvim --remote-wait file.txt
-<
- vim:tw=78:sw=4:ts=8:noet:ft=help:norl:
diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt
index 6755747dcf..7e8d93aa71 100644
--- a/runtime/doc/repeat.txt
+++ b/runtime/doc/repeat.txt
@@ -172,47 +172,42 @@ Using Vim scripts *using-scripts*
For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|.
*:so* *:source* *load-vim-script*
-:so[urce] {file} Runs vim or lua {file}
+:[range]so[urce] [file] Runs |Ex| commands or Lua code (".lua" files) from
+ [file], or from the current buffer if no [file] is
+ given.
Triggers the |SourcePre| autocommand.
-
- Note: Only files ending with `.lua` is sourced as
- lua file. Anything else is assumed to be vimscript.
*:source!*
-:so[urce]! {file} Read Vim commands from {file}. These are commands
- that are executed from Normal mode, like you type
- them.
- When used after |:global|, |:argdo|, |:windo|,
- |:bufdo|, in a loop or when another command follows
- the display won't be updated while executing the
- commands.
- Cannot be used in the |sandbox|.
+:[range]so[urce]! {file}
+ Runs |Normal-mode| commands from {file}. When used
+ after |:global|, |:argdo|, |:windo|, |:bufdo|, in
+ a loop or when another command follows the display
+ won't be updated while executing the commands.
*:ru* *:runtime*
:ru[ntime][!] [where] {file} ..
- Source vim/lua {file} in each directory given by
- 'runtimepath' and/or 'packpath'. The vim files are
- executed in same mannar as |:source| and lua files
- similarly as |:luafile|. There is no error
- for non-existing files.
+ Sources |Ex| commands or Lua code (".lua" files) read
+ from {file} (a relative path) in each directory given
+ by 'runtimepath' and/or 'packpath'.
+ Ignores non-existing files.
Example: >
:runtime syntax/c.vim
+ :runtime syntax/c.lua
-< There can be multiple {file} arguments, separated by
- spaces. Each {file} is searched for in the first
+< There can be multiple space-separated {file}
+ arguments. Each {file} is searched for in the first
directory from 'runtimepath', then in the second
- directory, etc. Use a backslash to include a space
- inside {file} (although it's better not to use spaces
- in file names, it causes trouble).
+ directory, etc.
When [!] is included, all found files are sourced.
- When it is not included only the first found file is
- sourced.
+ Else only the first found file is sourced.
- When [where] is omitted only 'runtimepath' is used.
+ When [where] is omitted, first 'runtimepath' is
+ searched, then directories under "start" in 'packpath'
+ are searched.
Other values:
- START search under "start" in 'packpath'
- OPT search under "opt" in 'packpath'
+ START search only under "start" in 'packpath'
+ OPT search only under "opt" in 'packpath'
PACK search under "start" and "opt" in
'packpath'
ALL first use 'runtimepath', then search
@@ -263,7 +258,9 @@ For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|.
ftdetect scripts are loaded, only the matching
directories are added to 'runtimepath'. This is
useful in your .vimrc. The plugins will then be
- loaded during initialization, see |load-plugins|.
+ loaded during initialization, see |load-plugins| (note
+ that the loading order will be reversed, because each
+ directory is inserted before others).
Note that for ftdetect scripts to be loaded
you will need to write `filetype plugin indent on`
AFTER all `packadd!` commands.
@@ -519,16 +516,26 @@ You would now have these files under ~/.local/share/nvim/site:
pack/foo/start/foobar/syntax/some.vim
pack/foo/opt/foodebug/plugin/debugger.vim
-When Vim starts up, after processing your .vimrc, it scans all directories in
-'packpath' for plugins under the "pack/*/start" directory. First all those
-directories are added to 'runtimepath'. Then all the plugins are loaded.
-See |packload-two-steps| for how these two steps can be useful.
+ *runtime-search-path*
+When runtime files are searched for, first all paths in 'runtimepath' are
+searched, then all "pack/*/start/*" dirs are searched. However, package entries
+are not visible in `:set rtp` or `echo &rtp`, as the final concatenated path
+would be too long and get truncated. To list all used directories, use
+|nvim_list_runtime_paths()|. In addition |nvim_get_runtime_file()| can be used
+to query for specific files or sub-folders within the runtime path. For
+instance to list all runtime dirs and packages with lua paths, use >
+
+ :echo nvim_get_runtime_file("lua/", v:true)
+
+<When Vim starts up, after processing your .vimrc, it scans all directories in
+'packpath' for plugins under the "pack/*/start" directory, and all the plugins
+are loaded.
-In the example Vim will find "pack/foo/start/foobar/plugin/foo.vim" and adds
-"~/.local/share/nvim/site/pack/foo/start/foobar" to 'runtimepath'.
+In the example Vim will find "pack/foo/start/foobar/plugin/foo.vim" and load it.
If the "foobar" plugin kicks in and sets the 'filetype' to "some", Vim will
-find the syntax/some.vim file, because its directory is in 'runtimepath'.
+find the syntax/some.vim file, because its directory is in the runtime search
+path.
Vim will also load ftdetect files, if there are any.
@@ -539,7 +546,7 @@ is used.
Loading packages automatically will not happen if loading plugins is disabled,
see |load-plugins|.
-To load packages earlier, so that 'runtimepath' gets updated: >
+To load packages earlier, so that plugin/ files are sourced:
:packloadall
This also works when loading plugins is disabled. The automatic loading will
only happen once.
@@ -667,8 +674,8 @@ found automatically. Your package would have these files:
< pack/foo/start/lib/autoload/foolib.vim >
func foolib#getit()
-This works, because loading packages will first add all found directories to
-'runtimepath' before sourcing the plugins.
+This works, because start packages will be used to look for autoload files,
+when sourcing the plugins.
==============================================================================
Debugging scripts *debug-scripts*
@@ -827,8 +834,12 @@ DEFINING BREAKPOINTS
Sets a breakpoint, that will break whenever the {expression}
evaluates to a different value. Example: >
:breakadd expr g:lnum
-
< Will break, whenever the global variable lnum changes.
+
+ Errors in evaluation are suppressed, you can use the name of a
+ variable that does not exist yet. This also means you will
+ not notice anything if the expression has a mistake.
+
Note if you watch a |script-variable| this will break
when switching scripts, since the script variable is only
valid in the script where it has been defined and if that
@@ -911,11 +922,9 @@ OBSCURE
Profiling *profile* *profiling*
Profiling means that Vim measures the time that is spent on executing
-functions and/or scripts. The |+profile| feature is required for this.
-It is only included when Vim was compiled with "huge" features.
+functions and/or scripts.
-You can also use the |reltime()| function to measure time. This only requires
-the |+reltime| feature, which is present more often.
+You can also use the |reltime()| function to measure time.
For profiling syntax highlighting see |:syntime|.
diff --git a/runtime/doc/rileft.txt b/runtime/doc/rileft.txt
index d45a2dce7e..aa11462595 100644
--- a/runtime/doc/rileft.txt
+++ b/runtime/doc/rileft.txt
@@ -70,7 +70,7 @@ o Invocations
o Typing backwards *ins-reverse*
----------------
- In lieu of using full-fledged the 'rightleft' option, one can opt for
+ In lieu of using the full-fledged 'rightleft' option, one can opt for
reverse insertion. When the 'revins' (reverse insert) option is set,
inserting happens backwards. This can be used to type right-to-left
text. When inserting characters the cursor is not moved and the text
diff --git a/runtime/doc/russian.txt b/runtime/doc/russian.txt
index 776630a52b..a2bc9f3b5e 100644
--- a/runtime/doc/russian.txt
+++ b/runtime/doc/russian.txt
@@ -47,10 +47,6 @@ different codepages from
http://www.sourceforge.net/projects/ruvim/
-Make sure that your Vim is at least 6.2.506 and use ruvim 0.5 or later for
-automatic installs. Vim also needs to be compiled with |+gettext| feature for
-user interface items translations to work.
-
After downloading an archive from RuVim project, unpack it into your
$VIMRUNTIME directory. We recommend using UTF-8 archive.
diff --git a/runtime/doc/sign.txt b/runtime/doc/sign.txt
index e8ed29c1a4..5079d900c9 100644
--- a/runtime/doc/sign.txt
+++ b/runtime/doc/sign.txt
@@ -435,13 +435,13 @@ sign_getdefined([{name}]) *sign_getdefined()*
" Get the attribute of the sign named mySign
echo sign_getdefined("mySign")
<
-sign_getplaced([{expr} [, {dict}]]) *sign_getplaced()*
+sign_getplaced([{buf} [, {dict}]]) *sign_getplaced()*
Return a list of signs placed in a buffer or all the buffers.
This is similar to the |:sign-place-list| command.
- If the optional buffer name {expr} is specified, then only the
+ If the optional buffer name {buf} is specified, then only the
list of signs placed in that buffer is returned. For the use
- of {expr}, see |bufname()|. The optional {dict} can contain
+ of {buf}, see |bufname()|. The optional {dict} can contain
the following entries:
group select only signs in this group
id select sign with this identifier
@@ -496,12 +496,12 @@ sign_getplaced([{expr} [, {dict}]]) *sign_getplaced()*
echo sign_getplaced()
<
*sign_jump()*
-sign_jump({id}, {group}, {expr})
- Open the buffer {expr} or jump to the window that contains
- {expr} and position the cursor at sign {id} in group {group}.
+sign_jump({id}, {group}, {buf})
+ Open the buffer {buf} or jump to the window that contains
+ {buf} and position the cursor at sign {id} in group {group}.
This is similar to the |:sign-jump| command.
- For the use of {expr}, see |bufname()|.
+ For the use of {buf}, see |bufname()|.
Returns the line number of the sign. Returns -1 if the
arguments are invalid.
@@ -512,9 +512,9 @@ sign_jump({id}, {group}, {expr})
<
*sign_place()*
-sign_place({id}, {group}, {name}, {expr} [, {dict}])
+sign_place({id}, {group}, {name}, {buf} [, {dict}])
Place the sign defined as {name} at line {lnum} in file or
- buffer {expr} and assign {id} and {group} to sign. This is
+ buffer {buf} and assign {id} and {group} to sign. This is
similar to the |:sign-place| command.
If the sign identifier {id} is zero, then a new identifier is
@@ -525,12 +525,12 @@ sign_place({id}, {group}, {name}, {expr} [, {dict}])
and |sign-group| for more information.
{name} refers to a defined sign.
- {expr} refers to a buffer name or number. For the accepted
+ {buf} refers to a buffer name or number. For the accepted
values, see |bufname()|.
The optional {dict} argument supports the following entries:
lnum line number in the file or buffer
- {expr} where the sign is to be placed.
+ {buf} where the sign is to be placed.
For the accepted values, see |line()|.
priority priority of the sign. See
|sign-priority| for more information.
@@ -578,7 +578,7 @@ sign_placelist({list})
then a new unique identifier is allocated.
Otherwise the specified number is used. See
|sign-identifier| for more information.
- lnum line number in the buffer {expr} where the
+ lnum line number in the buffer {buf} where the
sign is to be placed. For the accepted values,
see |line()|.
name name of the sign to place. See |sign_define()|
diff --git a/runtime/doc/spell.txt b/runtime/doc/spell.txt
index 22d7cdf491..03c00c8495 100644
--- a/runtime/doc/spell.txt
+++ b/runtime/doc/spell.txt
@@ -1127,10 +1127,10 @@ flag to avoid lots of errors.
CIRCUMFIX *spell-CIRCUMFIX*
The CIRCUMFIX flag means a prefix and suffix must be added at the same time.
-If a prefix has the CIRCUMFIX flag than only suffixes with the CIRCUMFIX flag
+If a prefix has the CIRCUMFIX flag then only suffixes with the CIRCUMFIX flag
can be added, and the other way around.
-An alternative is to only specify the suffix, and give the that suffix two
-flags: The required prefix and the NEEDAFFIX flag. |spell-NEEDAFFIX|
+An alternative is to only specify the suffix, and give that suffix two flags:
+the required prefix and the NEEDAFFIX flag. |spell-NEEDAFFIX|
PFXPOSTPONE *spell-PFXPOSTPONE*
diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt
index 5431ce3bd8..87a48e6d2a 100644
--- a/runtime/doc/starting.txt
+++ b/runtime/doc/starting.txt
@@ -329,12 +329,12 @@ argument.
-w{number} Set the 'window' option to {number}.
*-w*
--w {scriptout} All the characters that you type are recorded in the file
- "scriptout", until you exit Vim. This is useful if you want
- to create a script file to be used with "vim -s" or
- ":source!". When the "scriptout" file already exists, new
- characters are appended. See also |complex-repeat|.
- {scriptout} cannot start with a digit.
+-w {scriptout} All keys that you type are recorded in the file "scriptout",
+ until you exit Vim. Useful to create a script file to be used
+ with "vim -s" or ":source!". Appends to the "scriptout" file
+ if it already exists. {scriptout} cannot start with a digit.
+ See also |vim.on_key()|.
+ See also |complex-repeat|.
*-W*
-W {scriptout} Like -w, but do not append, overwrite an existing file.
@@ -388,8 +388,8 @@ argument.
==============================================================================
Initialization *initialization* *startup*
-At startup, Vim checks environment variables and files and sets values
-accordingly. Vim proceeds in this order:
+At startup, Nvim checks environment variables and files and sets values
+accordingly, proceeding as follows:
1. Set the 'shell' option *SHELL* *COMSPEC*
The environment variable SHELL, if it exists, is used to set the
@@ -406,21 +406,21 @@ accordingly. Vim proceeds in this order:
Nvim started with |--embed| waits for the UI to connect before
proceeding to load user configuration.
-4. Load user config (execute Ex commands from files, environment, …).
- An environment variable (e.g. $VIMINIT) is read as one Ex command
- line, where multiple commands must be separated with '|' or <NL>.
+4. Setup |default-mappings| and |default-autocmds|.
+
+5. Load user config (execute Ex commands from files, environment, …).
+ $VIMINIT environment variable is read as one Ex command line (separate
+ multiple commands with '|' or <NL>).
*config* *init.vim* *init.lua* *vimrc* *exrc*
- A file that contains initialization commands is generically called
- a "vimrc" or config file. It can be a Vimscript or Lua file named
- "init.vim" or "init.lua" respectively. It is an error to use both at
- the same time. Each line in a "init.vim" is executed as an Ex command
- line. See also |vimrc-intro| and |base-directories|.
+ A file containing initialization commands is generically called
+ a "vimrc" or config file. It can be either Vimscript ("init.vim") or
+ Lua ("init.lua"), but not both. *E5422*
+ See also |vimrc-intro| and |base-directories|.
The config file is located at:
- Unix ~/.config/nvim/init.vim (or init.lua)
- Windows ~/AppData/Local/nvim/init.vim (or init.lua)
- or if |$XDG_CONFIG_HOME| is defined:
- $XDG_CONFIG_HOME/nvim/init.vim (or init.lua)
+ Unix ~/.config/nvim/init.vim (or init.lua)
+ Windows ~/AppData/Local/nvim/init.vim (or init.lua)
+ |$XDG_CONFIG_HOME| $XDG_CONFIG_HOME/nvim/init.vim (or init.lua)
If Nvim was started with "-u {file}" then {file} is used as the config
and all initializations until 5. are skipped. $MYVIMRC is not set.
@@ -452,7 +452,7 @@ accordingly. Vim proceeds in this order:
- The file ".nvimrc"
- The file ".exrc"
-5. Enable filetype and indent plugins.
+6. Enable filetype and indent plugins.
This does the same as the commands: >
:runtime! filetype.vim
:runtime! ftplugin.vim
@@ -460,24 +460,21 @@ accordingly. Vim proceeds in this order:
< Skipped if ":filetype … off" was called or if the "-u NONE" command
line argument was given.
-6. Enable syntax highlighting.
+7. Enable syntax highlighting.
This does the same as the command: >
:runtime! syntax/syntax.vim
< Skipped if ":syntax off" was called or if the "-u NONE" command
line argument was given.
-7. Load the plugin scripts. *load-plugins*
+8. Load the plugin scripts. *load-plugins*
This does the same as the command: >
:runtime! plugin/**/*.vim
:runtime! plugin/**/*.lua
-< The result is that all directories in the 'runtimepath' option will be
- searched for the "plugin" sub-directory and all files ending in ".vim"
- and ".lua" will be sourced (in alphabetical order per directory),
- also in subdirectories. First all the "*.vim" files will be sourced and
- then all the "*.lua" files will be sourced. If two files with same
- name but different extensions exists they will be treated in same
- manner. For example when both "foo.vim" and "foo.lua" exists then
- first "foo.vim" will be sourced then "foo.lua" will be sourced.
+< The result is that all directories in 'runtimepath' will be searched
+ for the "plugin" sub-directory and all files ending in ".vim" or
+ ".lua" will be sourced (in alphabetical order per directory),
+ also in subdirectories. First "*.vim" are sourced, then "*.lua" files.
+
However, directories in 'runtimepath' ending in "after" are skipped
here and only loaded after packages, see below.
Loading plugins won't be done when:
@@ -485,7 +482,6 @@ accordingly. Vim proceeds in this order:
- The |--noplugin| command line argument is used.
- The |--clean| command line argument is used.
- The "-u NONE" command line argument is used |-u|.
- - When Vim was compiled without the |+eval| feature.
Note that using "-c 'set noloadplugins'" doesn't work, because the
commands from the command line have not been executed yet. You can
use "--cmd 'set noloadplugins'" or "--cmd 'set loadplugins'" |--cmd|.
@@ -500,38 +496,33 @@ accordingly. Vim proceeds in this order:
if packages have been found, but that should not add a directory
ending in "after".
-8. Set 'shellpipe' and 'shellredir'
+9. Set 'shellpipe' and 'shellredir'
The 'shellpipe' and 'shellredir' options are set according to the
value of the 'shell' option, unless they have been set before.
- This means that Vim will figure out the values of 'shellpipe' and
+ This means that Nvim will figure out the values of 'shellpipe' and
'shellredir' for you, unless you have set them yourself.
-9. Set 'updatecount' to zero, if "-n" command argument used
+10. Set 'updatecount' to zero, if "-n" command argument used
-10. Set binary options
- If the "-b" flag was given to Vim, the options for binary editing will
- be set now. See |-b|.
+11. Set binary options if the |-b| flag was given.
-11. Read the ShaDa file
- See |shada-file|.
+12. Read the |shada-file|.
-12. Read the quickfix file
- If the "-q" flag was given to Vim, the quickfix file is read. If this
- fails, Vim exits.
+13. Read the quickfix file if the |-q| flag was given, or exit on failure.
-13. Open all windows
+14. Open all windows
When the |-o| flag was given, windows will be opened (but not
displayed yet).
When the |-p| flag was given, tab pages will be created (but not
displayed yet).
When switching screens, it happens now. Redrawing starts.
- If the "-q" flag was given to Vim, the first error is jumped to.
+ If the |-q| flag was given, the first error is jumped to.
Buffers for all windows will be loaded, without triggering |BufAdd|
autocommands.
-14. Execute startup commands
- If a "-t" flag was given to Vim, the tag is jumped to.
- The commands given with the |-c| and |+cmd| arguments are executed.
+15. 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.
diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt
index bf649b5940..ebc7ff6b80 100644
--- a/runtime/doc/syntax.txt
+++ b/runtime/doc/syntax.txt
@@ -25,11 +25,15 @@ In the User Manual:
==============================================================================
1. Quick start *:syn-qstart*
- *:syn-enable* *:syntax-enable*
+ *:syn-enable* *:syntax-enable* *:syn-on* *:syntax-on*
This command switches on syntax highlighting: >
:syntax enable
+Alternatively: >
+
+ :syntax on
+
What this command actually does is to execute the command >
:source $VIMRUNTIME/syntax/syntax.vim
@@ -42,19 +46,11 @@ are in the "/usr/vim/vim82/syntax" directory, set $VIMRUNTIME to
This command also sources the |menu.vim| script when the GUI is running or
will start soon. See |'go-M'| about avoiding that.
- *:syn-on* *:syntax-on*
-The `:syntax enable` command will keep most of your current color settings.
-This allows using `:highlight` commands to set your preferred colors before or
-after using this command. If you want Vim to overrule your settings with the
-defaults, use: >
- :syntax on
-<
*:hi-normal* *:highlight-normal*
If you are running in the GUI, you can get white text on a black background
with: >
:highlight Normal guibg=Black guifg=White
For a color terminal see |:hi-normal-cterm|.
-For setting up your own colors syntax highlighting see |syncolor|.
NOTE: The syntax files on MS-Windows have lines that end in <CR><NL>.
The files for Unix end in <NL>. This means you should use the right type of
@@ -277,12 +273,6 @@ located. This is used here as the variable |$VIMRUNTIME|.
|
+- Source first syntax/synload.vim in 'runtimepath'
| |
- | +- Setup the colors for syntax highlighting. If a color scheme is
- | | defined it is loaded again with ":colors {name}". Otherwise
- | | ":runtime! syntax/syncolor.vim" is used. ":syntax on" overrules
- | | existing colors, ":syntax enable" only sets groups that weren't
- | | set yet.
- | |
| +- Set up syntax autocmds to load the appropriate syntax file when
| | the 'syntax' option is set. *synload-1*
| |
@@ -371,9 +361,6 @@ the desired value, or restored to their default by removing the variable using
Remarks:
- Some truly ancient browsers may not show the background colors.
- From most browsers you can also print the file (in color)!
-- The latest TOhtml may actually work with older versions of Vim, but some
- features such as conceal support will not function, and the colors may be
- incorrect for an old Vim without GUI support compiled in.
Here is an example how to run the script over all .c and .h files from a
Unix shell: >
@@ -900,7 +887,7 @@ For Visual Basic use: >
BAAN *baan.vim* *baan-syntax*
-The baan.vim gives syntax support for BaanC of release BaanIV upto SSA ERP LN
+The baan.vim gives syntax support for BaanC of release BaanIV up to SSA ERP LN
for both 3 GL and 4 GL programming. Large number of standard defines/constants
are supported.
@@ -1109,11 +1096,13 @@ The ColdFusion syntax file is based on the HTML syntax file.
CPP *cpp.vim* *ft-cpp-syntax*
-Most of things are same as |ft-c-syntax|.
+Most things are the same as |ft-c-syntax|.
Variable Highlight ~
cpp_no_cpp11 don't highlight C++11 standard items
cpp_no_cpp14 don't highlight C++14 standard items
+cpp_no_cpp17 don't highlight C++17 standard items
+cpp_no_cpp20 don't highlight C++20 standard items
CSH *csh.vim* *ft-csh-syntax*
@@ -1397,11 +1386,17 @@ To select syntax highlighting file for Euphoria, as well as for
auto-detecting the *.e and *.E file extensions as Euphoria file type,
add the following line to your startup file: >
- :let filetype_euphoria="euphoria3"
+ :let g:filetype_euphoria = "euphoria3"
- or
+< or >
- :let filetype_euphoria="euphoria4"
+ :let g:filetype_euphoria = "euphoria4"
+
+Elixir and Euphoria share the *.ex file extension. If the filetype is
+specifically set as Euphoria with the g:filetype_euphoria variable, or the
+file is determined to be Euphoria based on keywords in the file, then the
+filetype will be set as Euphoria. Otherwise, the filetype will default to
+Elixir.
ERLANG *erlang.vim* *ft-erlang-syntax*
@@ -1419,6 +1414,22 @@ To enable highlighting some special atoms, put this in your vimrc: >
:let g:erlang_highlight_special_atoms = 1
+ELIXIR *elixir.vim* *ft-elixir-syntax*
+
+Elixir is a dynamic, functional language for building scalable and maintainable
+applications.
+
+The following file extensions are auto-detected as Elixir file types:
+
+ *.ex, *.exs, *.eex, *.leex, *.lock
+
+Elixir and Euphoria share the *.ex file extension. If the filetype is
+specifically set as Euphoria with the g:filetype_euphoria variable, or the
+file is determined to be Euphoria based on keywords in the file, then the
+filetype will be set as Euphoria. Otherwise, the filetype will default to
+Elixir.
+
+
FLEXWIKI *flexwiki.vim* *ft-flexwiki-syntax*
FlexWiki is an ASP.NET-based wiki package available at http://www.flexwiki.com
@@ -3398,8 +3409,8 @@ syntax highlighting script handles this with the following logic:
Tex: Match Check Control~
Sometimes one actually wants mismatched parentheses, square braces,
- and or curly braces; for example, \text{(1,10] is a range from but
- not including 1 to and including 10}. This wish, of course, conflicts
+ and or curly braces; for example, \text{(1,10]} is a range from but
+ not including 1 to and including 10. This wish, of course, conflicts
with the desire to provide delimiter mismatch detection. To
accommodate these conflicting goals, syntax/tex.vim provides >
g:tex_matchcheck = '[({[]'
@@ -4037,7 +4048,7 @@ match in the same position overrules an earlier one). The "transparent"
argument makes the "myVim" match use the same highlighting as "myString". But
it does not contain anything. If the "contains=NONE" argument would be left
out, then "myVim" would use the contains argument from myString and allow
-"myWord" to be contained, which will be highlighted as a Constant. This
+"myWord" to be contained, which will be highlighted as a Comment. This
happens because a contained match doesn't match inside itself in the same
position, thus the "myVim" match doesn't overrule the "myWord" match here.
@@ -4745,8 +4756,7 @@ in their own color.
This is basically the same as >
:echo g:colors_name
< In case g:colors_name has not been defined :colo will
- output "default". When compiled without the |+eval|
- feature it will output "unknown".
+ output "default".
:colo[rscheme] {name} Load color scheme {name}. This searches 'runtimepath'
for the file "colors/{name}.(vim|lua)". The first one that
@@ -5078,9 +5088,15 @@ Substitute |:substitute| replacement text highlighting
*hl-LineNr*
LineNr Line number for ":number" and ":#" commands, and when 'number'
or 'relativenumber' option is set.
+ *hl-LineNrAbove*
+LineNrAbove Line number for when the 'relativenumber'
+ option is set, above the cursor line.
+ *hl-LineNrBelow*
+LineNrBelow Line number for when the 'relativenumber'
+ option is set, below the cursor line.
*hl-CursorLineNr*
-CursorLineNr Like LineNr when 'cursorline' or 'relativenumber' is set for
- the cursor line.
+CursorLineNr Like LineNr when 'cursorline' is set and 'cursorlineopt'
+ contains "number" or is "both", for the cursor line.
*hl-MatchParen*
MatchParen The character under the cursor or just before it, if it
is a paired bracket, and its match. |pi_paren.txt|
@@ -5275,51 +5291,10 @@ back to their Vim default.
Note that if you are using a color scheme, the colors defined by the color
scheme for syntax highlighting will be lost.
-What this actually does is: >
-
- let g:syntax_cmd = "reset"
- runtime! syntax/syncolor.vim
-
-Note that this uses the 'runtimepath' option.
-
- *syncolor*
-If you want to use different colors for syntax highlighting, you can add a Vim
-script file to set these colors. Put this file in a directory in
-'runtimepath' which comes after $VIMRUNTIME, so that your settings overrule
-the default colors. This way these colors will be used after the ":syntax
-reset" command.
-
-For Unix you can use the file ~/.config/nvim/after/syntax/syncolor.vim.
-Example: >
-
- if &background == "light"
- highlight comment ctermfg=darkgreen guifg=darkgreen
- else
- highlight comment ctermfg=green guifg=green
- endif
-
- *E679*
-Do make sure this syncolor.vim script does not use a "syntax on", set the
-'background' option or uses a "colorscheme" command, because it results in an
-endless loop.
-
Note that when a color scheme is used, there might be some confusion whether
your defined colors are to be used or the colors from the scheme. This
depends on the color scheme file. See |:colorscheme|.
- *syntax_cmd*
-The "syntax_cmd" variable is set to one of these values when the
-syntax/syncolor.vim files are loaded:
- "on" ":syntax on" command. Highlight colors are overruled but
- links are kept
- "enable" ":syntax enable" command. Only define colors for groups that
- don't have highlighting yet. Use ":syntax default".
- "reset" ":syntax reset" command or loading a color scheme. Define all
- the colors.
- "skip" Don't define colors. Used to skip the default settings when a
- syncolor.vim file earlier in 'runtimepath' has already set
- them.
-
==============================================================================
16. Highlighting tags *tag-highlight*
@@ -5404,9 +5379,6 @@ If your syntax causes redrawing to be slow, here are a few hints on making it
faster. To see slowness switch on some features that usually interfere, such
as 'relativenumber' and |folding|.
-Note: this is only available when compiled with the |+profile| feature.
-You many need to build Vim with "huge" features.
-
To find out what patterns are consuming most time, get an overview with this
sequence: >
:syntime on
diff --git a/runtime/doc/tagsrch.txt b/runtime/doc/tagsrch.txt
index 2c1b927e5a..4d938c4a23 100644
--- a/runtime/doc/tagsrch.txt
+++ b/runtime/doc/tagsrch.txt
@@ -367,11 +367,11 @@ be a bug. If you really want the old Vi behavior, set the 't' flag in
'cpoptions'.
*tag-binary-search*
-Vim uses binary searching in the tags file to find the desired tag quickly
-(when enabled at compile time |+tag_binary|). But this only works if the
-tags file was sorted on ASCII byte value. Therefore, if no match was found,
-another try is done with a linear search. If you only want the linear search,
-reset the 'tagbsearch' option. Or better: Sort the tags file!
+Vim uses binary searching in the tags file to find the desired tag quickly.
+But this only works if the tags file was sorted on ASCII byte value.
+Therefore, if no match was found, another try is done with a linear search.
+If you only want the linear search, reset the 'tagbsearch' option. Or better:
+Sort the tags file!
Note that the binary searching is disabled when not looking for a tag with a
specific name. This happens when ignoring case and when a regular expression
@@ -666,9 +666,6 @@ included files (recursively). This can be used to find the definition of a
variable, function or macro. If you only want to search in the current
buffer, use the commands listed at |pattern-searches|.
-These commands are not available when the |+find_in_path| feature was disabled
-at compile time.
-
When a line is encountered that includes another file, that file is searched
before continuing in the current buffer. Files included by included files are
also searched. When an include file could not be found it is silently
diff --git a/runtime/doc/testing.txt b/runtime/doc/testing.txt
index b2ce6d670d..f0bda5aaf8 100644
--- a/runtime/doc/testing.txt
+++ b/runtime/doc/testing.txt
@@ -30,8 +30,7 @@ New tests should be added as new style tests. These use functions such as
|assert_equal()| to keep the test commands and the expected result in one
place.
*old-style-testing*
-In some cases an old style test needs to be used. E.g. when testing Vim
-without the |+eval| feature.
+In some cases an old style test needs to be used.
Find more information in the file src/testdir/README.txt.
@@ -54,6 +53,9 @@ assert_beeps({cmd}) *assert_beeps()*
Also see |assert_fails()|, |assert_nobeep()| and
|assert-return|.
+ Can also be used as a |method|: >
+ GetCmd()->assert_beeps()
+<
*assert_equal()*
assert_equal({expected}, {actual} [, {msg}])
When {expected} and {actual} are not equal an error message is
@@ -70,7 +72,10 @@ assert_equal({expected}, {actual} [, {msg}])
< Will result in a string to be added to |v:errors|:
test.vim line 12: Expected 'foo' but got 'bar' ~
- *assert_equalfile()*
+ Can also be used as a |method|: >
+ mylist->assert_equal([1, 2, 3])
+
+< *assert_equalfile()*
assert_equalfile({fname-one}, {fname-two})
When the files {fname-one} and {fname-two} do not contain
exactly the same text an error message is added to |v:errors|.
@@ -78,6 +83,9 @@ assert_equalfile({fname-one}, {fname-two})
When {fname-one} or {fname-two} does not exist the error will
mention that.
+ Can also be used as a |method|: >
+ GetLog()->assert_equalfile('expected.log')
+
assert_exception({error} [, {msg}]) *assert_exception()*
When v:exception does not contain the string {error} an error
message is added to |v:errors|. Also see |assert-return|.
@@ -98,6 +106,9 @@ assert_fails({cmd} [, {error} [, {msg}]]) *assert_fails()*
Note that beeping is not considered an error, and some failing
commands only beep. Use |assert_beeps()| for those.
+ Can also be used as a |method|: >
+ GetCmd()->assert_fails('E99:')
+
assert_false({actual} [, {msg}]) *assert_false()*
When {actual} is not false an error message is added to
|v:errors|, like with |assert_equal()|.
@@ -107,6 +118,9 @@ assert_false({actual} [, {msg}]) *assert_false()*
When {msg} is omitted an error in the form
"Expected False but got {actual}" is produced.
+ Can also be used as a |method|: >
+ GetResult()->assert_false()
+
assert_inrange({lower}, {upper}, {actual} [, {msg}]) *assert_inrange()*
This asserts number and |Float| values. When {actual} is lower
than {lower} or higher than {upper} an error message is added
@@ -135,6 +149,9 @@ assert_match({pattern}, {actual} [, {msg}])
< Will result in a string to be added to |v:errors|:
test.vim line 12: Pattern '^f.*o$' does not match 'foobar' ~
+ Can also be used as a |method|: >
+ getFile()->assert_match('foo.*')
+<
assert_nobeep({cmd}) *assert_nobeep()*
Run {cmd} and add an error message to |v:errors| if it
produces a beep or visual bell.
@@ -146,16 +163,27 @@ assert_notequal({expected}, {actual} [, {msg}])
|v:errors| when {expected} and {actual} are equal.
Also see |assert-return|.
- *assert_notmatch()*
+ Can also be used as a |method|: >
+ mylist->assert_notequal([1, 2, 3])
+
+< *assert_notmatch()*
assert_notmatch({pattern}, {actual} [, {msg}])
The opposite of `assert_match()`: add an error message to
|v:errors| when {pattern} matches {actual}.
Also see |assert-return|.
+ Can also be used as a |method|: >
+ getFile()->assert_notmatch('bar.*')
+
+
assert_report({msg}) *assert_report()*
- Report a test failure directly, using {msg}.
+ Report a test failure directly, using String {msg}.
Always returns one.
+ Can also be used as a |method|: >
+ GetMessage()->assert_report()
+
+
assert_true({actual} [, {msg}]) *assert_true()*
When {actual} is not true an error message is added to
|v:errors|, like with |assert_equal()|.
@@ -165,5 +193,8 @@ assert_true({actual} [, {msg}]) *assert_true()*
When {msg} is omitted an error in the form "Expected True but
got {actual}" is produced.
+ Can also be used as a |method|: >
+ GetResult()->assert_true()
+<
vim:tw=78:ts=8:noet:ft=help:norl:
diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt
index 416ea3a08a..ac10aeec88 100644
--- a/runtime/doc/treesitter.txt
+++ b/runtime/doc/treesitter.txt
@@ -86,6 +86,18 @@ Node methods *lua-treesitter-node*
tsnode:parent() *tsnode:parent()*
Get the node's immediate parent.
+tsnode:next_sibling() *tsnode:next_sibling()*
+ Get the node's next sibling.
+
+tsnode:prev_sibling() *tsnode:prev_sibling()*
+ Get the node's previous sibling.
+
+tsnode:next_named_sibling() *tsnode:next_named_sibling()*
+ Get the node's next named sibling.
+
+tsnode:prev_named_sibling() *tsnode:prev_named_sibling()*
+ Get the node's previous named sibling.
+
tsnode:iter_children() *tsnode:iter_children()*
Iterates over all the direct children of {tsnode}, regardless of
wether they are named or not.
@@ -169,7 +181,7 @@ a tree, using a simple to write lisp-like format. See
https://tree-sitter.github.io/tree-sitter/using-parsers#query-syntax for more
information on how to write queries.
-Note: The perdicates listed in the web page above differ from those Neovim
+Note: The predicates listed in the web page above differ from those Neovim
supports. See |lua-treesitter-predicates| for a complete list of predicates
supported by Neovim.
@@ -215,9 +227,9 @@ Here is a list of built-in predicates :
((identifier) @foo-bar (#contains @foo-bar "foo" "bar"))
<
`any-of?` *ts-predicate-any-of?*
- Will check if the text is the same as any of the following
+ Will check if the text is the same as any of the following.
This is the recommended way to check if the node matches one
- of many keywords for exemple, as it has been optimized for
+ of many keywords for example, as it has been optimized for
this.
arguments : >
((identifier) @foo (#any-of? @foo "foo" "bar"))
@@ -226,10 +238,22 @@ Here is a list of built-in predicates :
Each predicate has a `not-` prefixed predicate that is just the negation of
the predicate.
+ *vim.treesitter.query.add_predicate()*
+vim.treesitter.query.add_predicate({name}, {handler})
+
+This adds a predicate with the name {name} to be used in queries.
+{handler} should be a function whose signature will be : >
+ handler(match, pattern, bufnr, predicate)
+<
+ *vim.treesitter.query.list_predicates()*
+vim.treesitter.query.list_predicates()
+
+This lists the currently available predicates to use in queries.
+
Treesitter Query Directive *lua-treesitter-directives*
Treesitter queries can also contain `directives`. Directives store metadata for a node
-or match and perform side effects. for example, the |set!| predicate sets metadata on
+or match and perform side effects. For example, the |set!| predicate sets metadata on
the match or node : >
((identifier) @foo (#set! "type" "parameter"))
@@ -249,6 +273,21 @@ Here is a list of built-in directives:
`({capture_id}, {start_row}, {start_col}, {end_row}, {end_col}, {key?})`
The default key is "offset".
+ *vim.treesitter.query.add_directive()*
+vim.treesitter.query.add_directive({name}, {handler})
+
+This adds a directive with the name {name} to be used in queries.
+{handler} should be a function whose signature will be : >
+ handler(match, pattern, bufnr, predicate, metadata)
+Handlers can set match level data by setting directly on the metadata object `metadata.key = value`
+Handlers can set node level data by using the capture id on the metadata table
+`metadata[capture_id].key = value`
+
+ *vim.treesitter.query.list_directives()*
+vim.treesitter.query.list_directives()
+
+This lists the currently available directives to use in queries.
+
Treesitter syntax highlighting (WIP) *lua-treesitter-highlight*
NOTE: This is a partially implemented feature, and not usable as a default
@@ -257,7 +296,7 @@ for those who want to experiment with this feature and contribute to
its development.
Highlights are defined in the same query format as in the tree-sitter highlight
-crate, which some limitations and additions. Set a highlight query for a
+crate, with some limitations and additions. Set a highlight query for a
buffer with this code: >
local query = [[
@@ -294,6 +333,19 @@ identical identifiers, highlighting both as |hl-WarningMsg|: >
((binary_expression left: (identifier) @WarningMsg.left right: (identifier) @WarningMsg.right)
(eq? @WarningMsg.left @WarningMsg.right))
<
+Treesitter Highlighting Priority *lua-treesitter-highlight-priority*
+
+Tree-sitter uses |nvim_buf_set_extmark()| to set highlights with a default
+priority of 100. This enables plugins to set a highlighting priority lower or
+higher than tree-sitter. It is also possible to change the priority of an
+individual query pattern manually by setting its `"priority"` metadata attribute: >
+
+ (
+ (super_important_node) @ImportantHighlight
+ ; Give the whole query highlight priority higher than the default (100)
+ (set! "priority" 105)
+ )
+<
==============================================================================
Lua module: vim.treesitter *lua-treesitter-core*
@@ -393,8 +445,13 @@ get_query_files({lang}, {query_name}, {is_included})
{is_included} Internal parameter, most of the time left
as `nil`
+list_directives() *list_directives()*
+ Return: ~
+ The list of supported directives.
+
list_predicates() *list_predicates()*
- TODO: Documentation
+ Return: ~
+ The list of supported predicates.
parse_query({lang}, {query}) *parse_query()*
Parse {query} as a string. (If the query is in a file, the
@@ -474,11 +531,9 @@ Query:iter_matches({self}, {node}, {source}, {start}, {stop})
for id, node in pairs(match) do
local name = query.captures[id]
-- `node` was captured by the `name` capture in the match
-<
->
- local node_data = metadata[id] -- Node level metadata
-<
->
+
+ local node_data = metadata[id] -- Node level metadata
+
... use the info here ...
end
end
@@ -712,17 +767,4 @@ new({source}, {lang}, {opts}) *languagetree.new()*
the injection language query per
language.
-
-==============================================================================
-Lua module: vim.treesitter.health *treesitter-health*
-
-check_health() *check_health()*
- TODO: Documentation
-
-list_parsers() *list_parsers()*
- Lists the parsers currently installed
-
- Return: ~
- A list of parsers
-
vim:tw=78:ts=8:ft=help:norl:
diff --git a/runtime/doc/usr_05.txt b/runtime/doc/usr_05.txt
index d0206ba82d..2edef0ca23 100644
--- a/runtime/doc/usr_05.txt
+++ b/runtime/doc/usr_05.txt
@@ -175,10 +175,8 @@ This switches on three very clever mechanisms:
*restore-cursor* *last-position-jump* >
- autocmd BufReadPost *
- \ if line("'\"") >= 1 && line("'\"") <= line("$") && &ft !~# 'commit'
- \ | exe "normal! g`\""
- \ | endif
+ autocmd BufRead * autocmd FileType <buffer> ++once
+ \ if &ft !~# 'commit\|rebase' && line("'\"") > 1 && line("'\"") <= line("$") | exe 'normal! g`"' | endif
Another autocommand. This time it is used after reading any file. The
complicated stuff after it checks if the '" mark is defined, and jumps to it
diff --git a/runtime/doc/usr_08.txt b/runtime/doc/usr_08.txt
index 8e69307a94..8ccaa73006 100644
--- a/runtime/doc/usr_08.txt
+++ b/runtime/doc/usr_08.txt
@@ -235,7 +235,7 @@ windows like this:
+----------------------------------+
Clearly the last one should be at the top. Go to that window (using CTRL-W w)
-and the type this command: >
+and then type this command: >
CTRL-W K
diff --git a/runtime/doc/usr_09.txt b/runtime/doc/usr_09.txt
index 757d13e0f3..8084d13b5d 100644
--- a/runtime/doc/usr_09.txt
+++ b/runtime/doc/usr_09.txt
@@ -109,7 +109,7 @@ when the 'wrap' option has been reset (more about that later).
When there are vertically split windows, only the windows on the right side
will have a scrollbar. However, when you move the cursor to a window on the
-left, it will be this one the that scrollbar controls. This takes a bit of
+left, it will be this one that the scrollbar controls. This takes a bit of
time to get used to.
When you work with vertically split windows, consider adding a scrollbar on
the left. This can be done with a menu item, or with the 'guioptions' option:
diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt
index a190bf2f27..5d70834ddc 100644
--- a/runtime/doc/usr_41.txt
+++ b/runtime/doc/usr_41.txt
@@ -118,7 +118,8 @@ Numbers can be decimal, hexadecimal, octal or binary.
A hexadecimal number starts with "0x" or "0X". For example "0x1f" is decimal
31.
-An octal number starts with a zero and another digit. "017" is decimal 15.
+An octal number starts with "0o", "0O" or a zero and another digit. "0o17" is
+decimal 15.
A binary number starts with "0b" or "0B". For example "0b101" is decimal 5.
@@ -127,14 +128,14 @@ number, it will be interpreted as an octal number!
The ":echo" command always prints decimal numbers. Example: >
- :echo 0x7f 036
+ :echo 0x7f 0o36
< 127 30 ~
A number is made negative with a minus sign. This also works for hexadecimal,
octal and binary numbers. A minus sign is also used for subtraction. Compare
this with the previous example: >
- :echo 0x7f -036
+ :echo 0x7f -0o36
< 97 ~
White space in an expression is ignored. However, it's recommended to use it
@@ -142,7 +143,7 @@ for separating items, to make the expression easier to read. For example, to
avoid the confusion with a negative number above, put a space between the
minus sign and the following number: >
- :echo 0x7f - 036
+ :echo 0x7f - 0o36
==============================================================================
*41.2* Variables
@@ -743,6 +744,8 @@ Cursor and mark position: *cursor-functions* *mark-functions*
diff_filler() get the number of filler lines above a line
screenattr() get attribute at a screen line/row
screenchar() get character code at a screen line/row
+ screenchars() get character codes at a screen line/row
+ screenstring() get string of characters at a screen line/row
Working with text in the current buffer: *text-functions*
getline() get a line or list of lines from the buffer
@@ -1022,6 +1025,7 @@ Various: *various-functions*
undotree() return the state of the undo tree
getreg() get contents of a register
+ getreginfo() get information about a register
getregtype() get type of a register
setreg() set contents and type of a register
reg_executing() return the name of the register being executed
diff --git a/runtime/doc/usr_45.txt b/runtime/doc/usr_45.txt
index bc95f3405e..3199c4d8ea 100644
--- a/runtime/doc/usr_45.txt
+++ b/runtime/doc/usr_45.txt
@@ -31,13 +31,6 @@ this command: >
If it replies with "C", this means the default is being used, which is
English.
- Note:
- Using different languages only works when Vim was compiled to handle
- it. To find out if it works, use the ":version" command and check the
- output for "+gettext" and "+multi_lang". If they are there, you are
- OK. If you see "-gettext" or "-multi_lang" you will have to find
- another Vim.
-
What if you would like your messages in a different language? There are
several ways. Which one you should use depends on the capabilities of your
system.
diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt
index ec91b6e29a..b06fa7518c 100644
--- a/runtime/doc/various.txt
+++ b/runtime/doc/various.txt
@@ -14,6 +14,10 @@ Various commands *various*
*CTRL-L*
CTRL-L Clears and redraws the screen. The redraw may happen
later, after processing typeahead.
+ *CTRL-L-default*
+ By default, also clears search highlighting
+ |:nohlsearch| and updates diffs |:diffupdate|.
+ |default-mappings|
*:mod* *:mode*
:mod[e] Clears and redraws the screen.
@@ -162,9 +166,13 @@ g8 Print the hex values of the bytes used in the
If the mark is "=", a line of dashes is printed
around the current line.
-:[range]z#[+-^.=][count] *:z#*
- Like ":z", but number the lines.
- {not in all versions of Vi, not with these arguments}
+ *:z!*
+:[range]z![+-^.=][count]
+ Like ":z:", but when [count] is not specified, it
+ defaults to the Vim window height minus one.
+
+:[range]z[!]#[+-^.=][count] *:z#*
+ Like ":z" or ":z!", but number the lines.
*:=*
:= [flags] Print the last line number.
@@ -456,20 +464,14 @@ defined while executing a function, user command or autocommand, the script in
which it was defined is reported.
*K*
-[count]K Run a program to lookup the keyword under the
- cursor. The name of the program is given with the
- 'keywordprg' (kp) option (default is "man"). The
- keyword is formed of letters, numbers and the
- characters in 'iskeyword'. The keyword under or
- right of the cursor is used. The same can be done
- with the command >
- :!{program} {keyword}
+[count]K Runs the program given by 'keywordprg' to lookup the
+ |word| (defined by 'iskeyword') under or right of the
+ cursor. Default is "man". Works like this: >
+ :tabnew | terminal {program} {keyword}
< Special cases:
- If 'keywordprg' begins with ":" it is invoked as
a Vim command with [count].
- - If 'keywordprg' is empty, the ":help" command is
- used. It's a good idea to include more characters
- in 'iskeyword' then, to be able to find more help.
+ - If 'keywordprg' is empty, |:help| is used.
- When 'keywordprg' is equal to "man", a [count]
before "K" is inserted after the "man" command and
before the keyword. For example, using "2K" while
@@ -506,7 +508,7 @@ gO Show a filetype-specific, navigable "outline" of the
Queued messages are processed during the sleep.
*:sl!* *:sleep!*
-:[N]sl[eep]! [N] [m] Same as above. Unlike Vim, it does not hide the
+:[N]sl[eep]! [N][m] Same as above. Unlike Vim, it does not hide the
cursor. |vim-differences|
==============================================================================
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index 27c4b82aca..64824b2e3f 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -6,16 +6,16 @@
Differences between Nvim and Vim *vim-differences*
-Nvim differs from Vim in many ways, although editor and VimL features are
-mostly identical. This document is a complete and centralized reference of
-the differences.
+Nvim differs from Vim in many ways, although editor and Vimscript (not
+Vim9script) features are mostly identical. This document is a complete and
+centralized reference of the differences.
Type |gO| to see the table of contents.
==============================================================================
1. Configuration *nvim-config*
-- Use `$XDG_CONFIG_HOME/nvim/init.vim` instead of `.vimrc` for configuration.
+- Use `$XDG_CONFIG_HOME/nvim/init.vim` instead of `.vimrc` for your |config|.
- Use `$XDG_CONFIG_HOME/nvim` instead of `.vim` to store configuration files.
- Use `$XDG_DATA_HOME/nvim/shada/main.shada` instead of `.viminfo` for persistent
session information. |shada|
@@ -30,7 +30,7 @@ the differences.
- 'autoread' is enabled
- 'background' defaults to "dark" (unless set automatically by the terminal/UI)
- 'backspace' defaults to "indent,eol,start"
-- 'backupdir' defaults to .,~/.local/share/nvim/backup (|xdg|)
+- 'backupdir' defaults to .,~/.local/share/nvim/backup// (|xdg|), auto-created
- 'belloff' defaults to "all"
- 'compatible' is always disabled
- 'complete' excludes "i"
@@ -41,9 +41,11 @@ the differences.
- 'fillchars' defaults (in effect) to "vert:│,fold:·,sep:│"
- 'formatoptions' defaults to "tcqj"
- 'fsync' is disabled
+- 'hidden' is enabled
- 'history' defaults to 10000 (the maximum)
- 'hlsearch' is enabled
- 'incsearch' is enabled
+- 'joinspaces' is disabled
- 'langnoremap' is enabled
- 'langremap' is disabled
- 'laststatus' defaults to 2 (statusline is always shown)
@@ -56,12 +58,13 @@ the differences.
- 'sidescroll' defaults to 1
- 'smarttab' is enabled
- 'startofline' is disabled
+- 'switchbuf' defaults to "uselast"
- 'tabpagemax' defaults to 50
- 'tags' defaults to "./tags;,tags"
- 'ttimeoutlen' defaults to 50
- 'ttyfast' is always set
-- 'viewoptions' includes "unix,slash"
-- 'undodir' defaults to ~/.local/share/nvim/undo (|xdg|), auto-created
+- 'undodir' defaults to ~/.local/share/nvim/undo// (|xdg|), auto-created
+- 'viewoptions' includes "unix,slash", excludes "options"
- 'viminfo' includes "!"
- 'wildmenu' is enabled
- 'wildoptions' defaults to "pum,tagfile"
@@ -72,23 +75,47 @@ the differences.
- |g:vimsyn_embed| defaults to "l" to enable Lua highlighting
+
+Default Mappings ~
+ *default-mappings*
+Nvim creates the following default mappings at |startup|. You can disable any
+of these in your config by simply removing the mapping, e.g. ":unmap Y".
+>
+ nnoremap Y y$
+ nnoremap <C-L> <Cmd>nohlsearch<Bar>diffupdate<CR><C-L>
+ inoremap <C-U> <C-G>u<C-U>
+ inoremap <C-W> <C-G>u<C-W>
+<
+Default Autocommands ~
+ *default-autocmds*
+Default autocommands exist in the following groups. Use ":autocmd! {group}" to
+remove them and ":autocmd {group}" to see how they're defined.
+
+nvim_terminal:
+- BufReadCmd: Treats "term://" buffers as |terminal| buffers. |terminal-start|
+
+nvim_cmdwin:
+- CmdwinEnter: Limits syntax sync to maxlines=1 in the |cmdwin|.
+
==============================================================================
3. New Features *nvim-features*
MAJOR COMPONENTS ~
API |API|
-Lua scripting |lua|
Job control |job-control|
-Remote plugins |remote-plugin|
+LSP framework |lsp|
+Lua scripting |lua|
+Parsing engine |treesitter|
Providers
Clipboard |provider-clipboard|
Node.js plugins |provider-nodejs|
Python plugins |provider-python|
Ruby plugins |provider-ruby|
+Remote plugins |remote-plugin|
Shared data |shada|
-Embedded terminal |terminal|
-VimL parser |nvim_parse_expression()|
+Terminal emulator |terminal|
+Vimscript parser |nvim_parse_expression()|
XDG base directories |xdg|
USER EXPERIENCE ~
@@ -137,7 +164,7 @@ FEATURES ~
Command-line highlighting:
The expression prompt (|@=|, |c_CTRL-R_=|, |i_CTRL-R_=|) is highlighted
- using a built-in VimL expression parser. |expr-highlight|
+ using a built-in Vimscript expression parser. |expr-highlight|
*E5408* *E5409*
|input()|, |inputdialog()| support custom highlighting. |input()-highlight|
*g:Nvim_color_cmdline*
@@ -150,6 +177,7 @@ Commands:
|:drop| is always available
|:Man| is available by default, with many improvements such as completion
|:sign-define| accepts a `numhl` argument, to highlight the line number
+ |:match| can be invoked before highlight group is defined
Events:
|Signal|
@@ -167,6 +195,7 @@ Functions:
|msgpackdump()|, |msgpackparse()| provide msgpack de/serialization
|stdpath()|
|system()|, |systemlist()| can run {cmd} directly (without 'shell')
+ |matchadd()| can be called before highlight group is defined
Highlight groups:
|highlight-blend| controls blend level for a highlight group
@@ -358,6 +387,14 @@ Startup:
- works by default: "-" file is optional
- works in more cases: |-Es|, file args
+Syntax highlighting:
+ syncolor.vim has been removed. Nvim now sets up default highlighting groups
+ automatically for both light and dark backgrounds, regardless of whether or
+ not syntax highlighting is enabled. This means that |:syntax-on| and
+ |:syntax-enable| are now identical. Users who previously used an
+ after/syntax/syncolor.vim file should transition that file into a
+ colorscheme. |:colorscheme|
+
TUI:
*:set-termcap*
Start Nvim with 'verbose' level 3 to show terminal capabilities: >
@@ -380,7 +417,7 @@ TUI:
UI/Display:
|Visual| selection highlights the character at cursor. |visual-use|
-VimL (Vim script) compatibility:
+Vimscript compatibility:
`count` does not alias to |v:count|
`errmsg` does not alias to |v:errmsg|
`shell_error` does not alias to |v:shell_error|
@@ -423,6 +460,7 @@ Commands:
:Print
:promptfind
:promptrepl
+ :scriptversion (always version 1)
:shell
:sleep! (does not hide the cursor; same as :sleep)
:smile
@@ -434,6 +472,7 @@ Compile-time features:
X11 integration (see |x11-selection|)
Eval:
+ Vim9script
*js_encode()*
*js_decode()*
*v:none* (used by Vim to represent JavaScript "undefined"); use |v:null| instead.
@@ -473,6 +512,7 @@ Options:
'maxmem' Nvim delegates memory-management to the OS.
'maxmemtot' Nvim delegates memory-management to the OS.
'maxcombine' (6 is always used)
+ *'prompt'* *'noprompt'*
*'restorescreen'* *'rs'* *'norestorescreen'* *'nors'*
'shelltype'
*'shortname'* *'sn'* *'noshortname'* *'nosn'*
diff --git a/runtime/doc/visual.txt b/runtime/doc/visual.txt
index f7828f0289..111588e43a 100644
--- a/runtime/doc/visual.txt
+++ b/runtime/doc/visual.txt
@@ -419,7 +419,7 @@ abcdefghijklmnopqrstuvwxyz
abcdefghijklmnSTRINGopqrstuvwxyz
abc STRING defghijklmnopqrstuvwxyz
-abcdef ghi STRING jklmnopqrstuvwxyz
+abcdef ghi STRING jklmnopqrstuvwxyz
abcdefghijklmnSTRINGopqrstuvwxyz
2. fo<C-v>3j$ASTRING<ESC> *v_b_A_example*
diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt
index 3a58cc08d9..e0c33fa2c9 100644
--- a/runtime/doc/windows.txt
+++ b/runtime/doc/windows.txt
@@ -271,7 +271,7 @@ Closing a window
----------------
:q[uit]
-:{count}q[uit]
+:{count}q[uit] *:count_quit*
CTRL-W q *CTRL-W_q*
CTRL-W CTRL-Q *CTRL-W_CTRL-Q*
Without {count}: Quit the current window. If {count} is
@@ -363,7 +363,8 @@ CTRL-W CTRL-C *CTRL-W_CTRL-C*
CTRL-W o *CTRL-W_o* *E445*
CTRL-W CTRL-O *CTRL-W_CTRL-O* *:on* *:only*
Make the current window the only one on the screen. All other
- windows are closed. For {count} see |:quit|.
+ windows are closed. For {count} see the `:quit` command
+ above |:count_quit|.
When the 'hidden' option is set, all buffers in closed windows
become hidden.
diff --git a/runtime/filetype.vim b/runtime/filetype.vim
index 2617d8ffc0..bc3965d4b6 100644
--- a/runtime/filetype.vim
+++ b/runtime/filetype.vim
@@ -1,7 +1,7 @@
" Vim support file to detect file types
"
" Maintainer: Bram Moolenaar <Bram@vim.org>
-" Last Change: 2021 Apr 17
+" Last Change: 2021 Sep 21
" Listen very carefully, I will say this only once
if exists("did_load_filetypes")
@@ -533,8 +533,13 @@ au BufNewFile,BufRead *.drac,*.drc,*lvs,*lpe setf dracula
" Datascript
au BufNewFile,BufRead *.ds setf datascript
-" dsl
-au BufNewFile,BufRead *.dsl setf dsl
+" dsl: DSSSL or Structurizr
+au BufNewFile,BufRead *.dsl
+ \ if getline(1) =~ '^\s*<\!' |
+ \ setf dsl |
+ \ else |
+ \ setf structurizr |
+ \ endif
" DTD (Document Type Definition for XML)
au BufNewFile,BufRead *.dtd setf dtd
@@ -646,6 +651,9 @@ au BufNewFile,BufRead *.mo,*.gdmo setf gdmo
" Gedcom
au BufNewFile,BufRead *.ged,lltxxxxx.txt setf gedcom
+" Gemtext
+au BufNewFile,BufRead *.gmi,*.gemini setf gemtext
+
" Gift (Moodle)
autocmd BufRead,BufNewFile *.gift setf gift
@@ -864,6 +872,12 @@ au BufNewFile,BufRead *.json-patch setf json
" Jupyter Notebook is also json
au BufNewFile,BufRead *.ipynb setf json
+" JSONC
+au BufNewFile,BufRead *.jsonc setf jsonc
+
+" Julia
+au BufNewFile,BufRead *.jl setf julia
+
" Kixtart
au BufNewFile,BufRead *.kix setf kix
@@ -1011,7 +1025,7 @@ au BufNewFile,BufRead *.markdown,*.mdown,*.mkd,*.mkdn,*.mdwn,*.md setf markdown
" Mason
au BufNewFile,BufRead *.mason,*.mhtml,*.comp setf mason
-" Mathematica, Matlab, Murphi or Objective C
+" Mathematica, Matlab, Murphi, Objective C or Octave
au BufNewFile,BufRead *.m call dist#ft#FTm()
" Mathematica notebook
@@ -1157,6 +1171,9 @@ au BufNewFile,BufRead *.ml,*.mli,*.mll,*.mly,.ocamlinit,*.mlt,*.mlp,*.mlip,*.mli
" Occam
au BufNewFile,BufRead *.occ setf occam
+" Octave
+au BufNewFile,BufRead octave.conf,.octaverc,octaverc setf octave
+
" Omnimark
au BufNewFile,BufRead *.xom,*.xin setf omnimark
@@ -1365,6 +1382,9 @@ au BufNewFile,BufRead *.pk setf poke
" Protocols
au BufNewFile,BufRead */etc/protocols setf protocols
+" Pyret
+au BufNewFile,BufRead *.arr setf pyret
+
" Pyrex
au BufNewFile,BufRead *.pyx,*.pxd setf pyrex
@@ -1376,7 +1396,7 @@ au BufNewFile,BufRead *.ptl,*.pyi,SConstruct setf python
" Radiance
au BufNewFile,BufRead *.rad,*.mat setf radiance
-" Raku (formelly Perl6)
+" Raku (formerly Perl6)
au BufNewFile,BufRead *.pm6,*.p6,*.t6,*.pod6,*.raku,*.rakumod,*.rakudoc,*.rakutest setf raku
" Ratpoison config/command files
@@ -1513,6 +1533,9 @@ au BufNewFile,BufRead *.sbt setf sbt
" Scilab
au BufNewFile,BufRead *.sci,*.sce setf scilab
+" scdoc
+au BufNewFile,BufRead *.scd setf scdoc
+
" SCSS
au BufNewFile,BufRead *.scss setf scss
@@ -1602,7 +1625,7 @@ au BufNewFile,BufRead .zshrc,.zshenv,.zlogin,.zlogout,.zcompdump setf zsh
au BufNewFile,BufRead *.zsh setf zsh
" Scheme
-au BufNewFile,BufRead *.scm,*.ss,*.rkt setf scheme
+au BufNewFile,BufRead *.scm,*.ss,*.rkt,*.rktd,*.rktl setf scheme
" Screen RC
au BufNewFile,BufRead .screenrc,screenrc setf screen
diff --git a/runtime/ftplugin/8th.vim b/runtime/ftplugin/8th.vim
index 14301187d6..ad04f9ac84 100644
--- a/runtime/ftplugin/8th.vim
+++ b/runtime/ftplugin/8th.vim
@@ -1,9 +1,10 @@
" Vim ftplugin file
" Language: 8th
" Version: any
-" Last Change: 2015/11/08
+" Last Change: 2021 Sep 20
+" Last Change: 2021/09/20
" Maintainer: Ron Aaron <ron@aaron-tech.com>
-" URL: https://8th-dev.com/
+" URL: https://8th-dev.com/
" Filetypes: *.8th
" NOTE: 8th allows any non-whitespace in a name, so you need to do:
" setlocal iskeyword=!,@,33-35,%,$,38-64,A-Z,91-96,a-z,123-126,128-255
@@ -14,12 +15,13 @@ if exists("b:did_8thplugin")
finish
endif
-" Don't load another plugin for this buffer
+" Don't load another 8th plugin for this buffer
let b:did_8thplugin = 1
setlocal ts=2 sts=2 sw=2 et
-setlocal com=s1:/*,mb:*,ex:*/,:\|,:\\
+setlocal com=s1:/*,mb:*,ex:*/,b:--,be:\\
setlocal fo=tcrqol
setlocal matchpairs+=\::;
setlocal iskeyword=!,@,33-35,%,$,38-64,A-Z,91-96,a-z,123-126,128-255
setlocal suffixesadd=.8th
+let b:undo_ftplugin = "setlocal ts< sts< sw< et< com< fo< mps< isk< sua<"
diff --git a/runtime/ftplugin/c.vim b/runtime/ftplugin/c.vim
index 00937c2383..d4564a4aec 100644
--- a/runtime/ftplugin/c.vim
+++ b/runtime/ftplugin/c.vim
@@ -1,7 +1,7 @@
" Vim filetype plugin file
" Language: C
" Maintainer: Bram Moolenaar <Bram@vim.org>
-" Last Change: 2020 Feb 01
+" Last Change: 2021 Sep 21
" Only do this when not done yet for this buffer
if exists("b:did_ftplugin")
@@ -35,8 +35,11 @@ setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,://
" When the matchit plugin is loaded, this makes the % command skip parens and
" braces in comments properly.
-let b:match_words = '^\s*#\s*if\(\|def\|ndef\)\>:^\s*#\s*elif\>:^\s*#\s*else\>:^\s*#\s*endif\>'
-let b:match_skip = 's:comment\|string\|character\|special'
+if !exists("b:match_words")
+ let b:match_words = '^\s*#\s*if\(\|def\|ndef\)\>:^\s*#\s*elif\>:^\s*#\s*else\>:^\s*#\s*endif\>'
+ let b:match_skip = 's:comment\|string\|character\|special'
+ let b:undo_ftplugin ..= " | unlet! b:match_skip b:match_words"
+endif
" Win32 can filter files in the browse dialog
if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter")
@@ -57,6 +60,7 @@ if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter")
\ "C++ Source Files (*.cpp *.c++)\t*.cpp;*.c++\n" .
\ "All Files (*.*)\t*.*\n"
endif
+ let b:undo_ftplugin ..= " | unlet! b:browsefilter"
endif
let b:man_default_sects = '3,2'
diff --git a/runtime/ftplugin/chicken.vim b/runtime/ftplugin/chicken.vim
index 4dc1e57d0a..84d45bae1e 100644
--- a/runtime/ftplugin/chicken.vim
+++ b/runtime/ftplugin/chicken.vim
@@ -2,6 +2,7 @@
" Last Change: 2018-03-05
" Author: Evan Hanson <evhan@foldling.org>
" Maintainer: Evan Hanson <evhan@foldling.org>
+" Repository: https://git.foldling.org/vim-scheme.git
" URL: https://foldling.org/vim/ftplugin/chicken.vim
" Notes: These are supplemental settings, to be loaded after the core
" Scheme ftplugin file (ftplugin/scheme.vim). Enable it by setting
diff --git a/runtime/ftplugin/dosini.vim b/runtime/ftplugin/dosini.vim
index 0d0f0f8983..6a53dfd096 100644
--- a/runtime/ftplugin/dosini.vim
+++ b/runtime/ftplugin/dosini.vim
@@ -1,5 +1,5 @@
" Vim filetype plugin file
-" Language: Configuration File (ini file) for MSDOS/MS Windows
+" Language: Configuration File (ini file) for MS-DOS/MS Windows
" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
" Latest Revision: 2008-07-09
diff --git a/runtime/ftplugin/eruby.vim b/runtime/ftplugin/eruby.vim
index 3c18bada78..e67b00b278 100644
--- a/runtime/ftplugin/eruby.vim
+++ b/runtime/ftplugin/eruby.vim
@@ -3,7 +3,7 @@
" Maintainer: Tim Pope <vimNOSPAM@tpope.org>
" URL: https://github.com/vim-ruby/vim-ruby
" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
-" Last Change: 2019 Jan 06
+" Last Change: 2020 Jun 28
" Only do this when not done yet for this buffer
if exists("b:did_ftplugin")
@@ -118,7 +118,7 @@ endif
" TODO: comments=
setlocal commentstring=<%#%s%>
-let b:undo_ftplugin = "setl cms< "
+let b:undo_ftplugin = "setl cms< " .
\ " | unlet! b:browsefilter b:match_words | " . s:undo_ftplugin
let &cpo = s:save_cpo
diff --git a/runtime/ftplugin/gprof.vim b/runtime/ftplugin/gprof.vim
index d4547ae9a6..d8974bcc84 100644
--- a/runtime/ftplugin/gprof.vim
+++ b/runtime/ftplugin/gprof.vim
@@ -1,6 +1,7 @@
-" Language: gprof
-" Maintainer: Dominique Pelle <dominique.pelle@gmail.com>
-" Last Change: 2021 Apr 08
+" Language: gprof
+" Maintainer: Dominique Pelle <dominique.pelle@gmail.com>
+" Contributors: Doug Kearns <dougkearns@gmail.com>
+" Last Change: 2021 Sep 19
" When cursor is on one line of the gprof call graph,
" calling this function jumps to this function in the call graph.
@@ -9,7 +10,7 @@ if exists("b:did_ftplugin")
endif
let b:did_ftplugin=1
-fun! <SID>GprofJumpToFunctionIndex()
+func! <SID>GprofJumpToFunctionIndex()
let l:line = getline('.')
if l:line =~ '[\d\+\]$'
" We're in a line in the call graph.
@@ -22,11 +23,14 @@ fun! <SID>GprofJumpToFunctionIndex()
call search('^\[\d\+\].*\d\s\+' . escape(@", '[]*.') . '\>', 'sW')
norm! zz
endif
-endfun
+endfunc
-" Pressing <C-]> on a line in the gprof flat profile or in
-" the call graph, jumps to the corresponding function inside
-" the flat profile.
-map <buffer> <silent> <C-]> :call <SID>GprofJumpToFunctionIndex()<CR>
+if !exists("no_plugin_maps") && !exists("no_gprof_maps")
+ " Pressing <C-]> on a line in the gprof flat profile or in
+ " the call graph, jumps to the corresponding function inside
+ " the flat profile.
+ map <buffer> <silent> <C-]> :call <SID>GprofJumpToFunctionIndex()<CR>
+ let b:undo_ftplugin = "silent! unmap <buffer> <C-]>"
+endif
" vim:sw=2 fdm=indent
diff --git a/runtime/ftplugin/jsonc.vim b/runtime/ftplugin/jsonc.vim
new file mode 100644
index 0000000000..90d52cd0d3
--- /dev/null
+++ b/runtime/ftplugin/jsonc.vim
@@ -0,0 +1,27 @@
+" Vim filetype plugin
+" Language: JSONC (JSON with Comments)
+" Original Author: Izhak Jakov <izhak724@gmail.com>
+" Acknowledgement: Based off of vim-jsonc maintained by Kevin Locke <kevin@kevinlocke.name>
+" https://github.com/kevinoid/vim-jsonc
+" License: MIT
+" Last Change: 2021-07-01
+
+runtime! ftplugin/json.vim
+
+if exists('b:did_ftplugin_jsonc')
+ finish
+else
+ let b:did_ftplugin_jsonc = 1
+endif
+
+" A list of commands that undo buffer local changes made below.
+let s:undo_ftplugin = []
+
+" Set comment (formatting) related options. {{{1
+setlocal commentstring=//%s comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,://
+call add(s:undo_ftplugin, 'commentstring< comments<')
+
+" Let Vim know how to disable the plug-in.
+call map(s:undo_ftplugin, "'execute ' . string(v:val)")
+let b:undo_ftplugin = join(s:undo_ftplugin, ' | ')
+unlet s:undo_ftplugin
diff --git a/runtime/ftplugin/julia.vim b/runtime/ftplugin/julia.vim
new file mode 100644
index 0000000000..32e364e436
--- /dev/null
+++ b/runtime/ftplugin/julia.vim
@@ -0,0 +1,92 @@
+" Vim filetype plugin file
+" Language: Julia
+" Maintainer: Carlo Baldassi <carlobaldassi@gmail.com>
+" Homepage: https://github.com/JuliaEditorSupport/julia-vim
+" Last Change: 2014 may 29
+" adapted from upstream 2021 Aug 4
+
+if exists("b:did_ftplugin")
+ finish
+endif
+let b:did_ftplugin = 1
+
+let s:save_cpo = &cpo
+set cpo-=C
+
+setlocal include=^\\s*\\%(reload\\\|include\\)\\>
+setlocal suffixesadd=.jl
+setlocal comments=:#
+setlocal commentstring=#\ %s
+setlocal cinoptions+=#1
+setlocal define=^\\s*macro\\>
+setlocal fo-=t fo+=croql
+
+let b:julia_vim_loaded = 1
+
+let b:undo_ftplugin = "setlocal include< suffixesadd< comments< commentstring<"
+ \ . " define< fo< shiftwidth< expandtab< indentexpr< indentkeys< cinoptions< completefunc<"
+ \ . " | unlet! b:julia_vim_loaded"
+
+" MatchIt plugin support
+if exists("loaded_matchit")
+ let b:match_ignorecase = 0
+
+ " note: begin_keywords must contain all blocks, in order
+ " for nested-structures-skipping to work properly
+ " note: 'mutable struct' and 'struct' are defined separately because
+ " using \? puts the cursor on 'struct' instead of 'mutable' for some reason
+ let b:julia_begin_keywords = '\%(\.\s*\|@\)\@<!\<\%(function\|macro\|begin\|mutable\s\+struct\|\%(mutable\s\+\)\@<!struct\|\%(abstract\|primitive\)\s\+type\|let\|do\|\%(bare\)\?module\|quote\|if\|for\|while\|try\)\>'
+ " note: the following regex not only recognizes macros, but also local/global keywords.
+ " the purpose is recognizing things like `@inline myfunction()`
+ " or `global myfunction(...)` etc, for matchit and block movement functionality
+ let s:macro_regex = '\%(@\%([#(]\@!\S\)\+\|\<\%(local\|global\)\)\s\+'
+ let s:nomacro = '\%(' . s:macro_regex . '\)\@<!'
+ let s:yesmacro = s:nomacro . '\%('. s:macro_regex . '\)\+'
+ let b:julia_begin_keywordsm = '\%(' . s:yesmacro . b:julia_begin_keywords . '\)\|'
+ \ . '\%(' . s:nomacro . b:julia_begin_keywords . '\)'
+ let b:julia_end_keywords = '\<end\>'
+
+ " note: this function relies heavily on the syntax file
+ function! JuliaGetMatchWords()
+ let [l,c] = [line('.'),col('.')]
+ let attr = synIDattr(synID(l, c, 1),"name")
+ let c1 = c
+ while attr == 'juliaMacro' || expand('<cword>') =~# '\<\%(global\|local\)\>'
+ normal! W
+ if line('.') > l || col('.') == c1
+ call cursor(l, c)
+ return ''
+ endif
+ let attr = synIDattr(synID(l, col('.'), 1),"name")
+ let c1 = col('.')
+ endwhile
+ call cursor(l, c)
+ if attr == 'juliaConditional'
+ return b:julia_begin_keywordsm . ':\<\%(elseif\|else\)\>:' . b:julia_end_keywords
+ elseif attr =~# '\<\%(juliaRepeat\|juliaRepKeyword\)\>'
+ return b:julia_begin_keywordsm . ':\<\%(break\|continue\)\>:' . b:julia_end_keywords
+ elseif attr == 'juliaBlKeyword'
+ return b:julia_begin_keywordsm . ':' . b:julia_end_keywords
+ elseif attr == 'juliaException'
+ return b:julia_begin_keywordsm . ':\<\%(catch\|finally\)\>:' . b:julia_end_keywords
+ endif
+ return '\<\>:\<\>'
+ endfunction
+
+ let b:match_words = 'JuliaGetMatchWords()'
+
+ " we need to skip everything within comments, strings and
+ " the 'begin' and 'end' keywords when they are used as a range rather than as
+ " the delimiter of a block
+ let b:match_skip = 'synIDattr(synID(line("."),col("."),0),"name") =~# '
+ \ . '"\\<julia\\%(Comprehension\\%(For\\|If\\)\\|RangeKeyword\\|Comment\\%([LM]\\|Delim\\)\\|\\%([bs]\\|Shell\\|Printf\\|Doc\\)\\?String\\|StringPrefixed\\|DocStringM\\(Raw\\)\\?\\|RegEx\\|SymbolS\\?\\|Dotted\\)\\>"'
+
+ let b:undo_ftplugin = b:undo_ftplugin
+ \ . " | unlet! b:match_words b:match_skip b:match_ignorecase"
+ \ . " | unlet! b:julia_begin_keywords b:julia_end_keywords"
+ \ . " | delfunction JuliaGetMatchWords"
+
+endif
+
+let &cpo = s:save_cpo
+unlet s:save_cpo
diff --git a/runtime/ftplugin/man.vim b/runtime/ftplugin/man.vim
index 5d3e00d033..fce12012b5 100644
--- a/runtime/ftplugin/man.vim
+++ b/runtime/ftplugin/man.vim
@@ -6,14 +6,6 @@ if exists('b:did_ftplugin') || &filetype !=# 'man'
endif
let b:did_ftplugin = 1
-let s:pager = !exists('b:man_sect')
-
-if s:pager
- call man#init_pager()
-endif
-
-setlocal noswapfile buftype=nofile bufhidden=hide
-setlocal nomodified readonly nomodifiable
setlocal noexpandtab tabstop=8 softtabstop=8 shiftwidth=8
setlocal wrap breakindent linebreak
@@ -32,11 +24,7 @@ if !exists('g:no_plugin_maps') && !exists('g:no_man_maps')
nnoremap <silent> <buffer> k gk
nnoremap <silent> <buffer> gO :call man#show_toc()<CR>
nnoremap <silent> <buffer> <2-LeftMouse> :Man<CR>
- if s:pager
- nnoremap <silent> <buffer> <nowait> q :lclose<CR>:q<CR>
- else
- nnoremap <silent> <buffer> <nowait> q :lclose<CR><C-W>c
- endif
+ nnoremap <silent> <buffer> <nowait> q :lclose<CR><C-W>c
endif
if get(g:, 'ft_man_folding_enable', 0)
diff --git a/runtime/ftplugin/matlab.vim b/runtime/ftplugin/matlab.vim
index a1a282f19e..d3c74b4ecf 100644
--- a/runtime/ftplugin/matlab.vim
+++ b/runtime/ftplugin/matlab.vim
@@ -1,7 +1,8 @@
" Vim filetype plugin file
" Language: matlab
" Maintainer: Jake Wasserman <jwasserman at gmail dot com>
-" Last Change: 2019 Sep 27
+" Update By: Gabriel Dupras
+" Last Change: 2021 Aug 30
" Contributors:
" Charles Campbell
@@ -15,9 +16,9 @@ let s:save_cpo = &cpo
set cpo-=C
if exists("loaded_matchit")
- let s:conditionalEnd = '\%(([^()]*\)\@!\<end\>\%([^()]*)\)\@!'
+ let s:conditionalEnd = '\%(\%(^\|;\)\s*\)\@<=end\>'
let b:match_words=
- \ '\<\%(if\|switch\|for\|while\)\>:\<\%(elseif\|case\|break\|continue\|else\|otherwise\)\>:'.s:conditionalEnd.','.
+ \ '\<\%(if\|switch\|for\|while\|try\)\>:\<\%(elseif\|case\|break\|continue\|else\|otherwise\|catch\)\>:' . s:conditionalEnd . ',' .
\ '\<function\>:\<return\>:\<endfunction\>'
unlet s:conditionalEnd
endif
diff --git a/runtime/ftplugin/ocaml.vim b/runtime/ftplugin/ocaml.vim
index 8a628604fa..20172c9b32 100644
--- a/runtime/ftplugin/ocaml.vim
+++ b/runtime/ftplugin/ocaml.vim
@@ -371,7 +371,7 @@ endfunction
endif
else
let annot_file_name = ''
- "(Pierre Vittet: I have commented 4b because this was chrashing
+ "(Pierre Vittet: I have commented 4b because this was crashing
"my vim (it produced infinite loop))
"
" 4b. anarchy : the renamed _build directory may be higher in the hierarchy
@@ -462,8 +462,8 @@ endfunction
"b. 'search' and 'match' work to find the type information
- "In: - lin1,col1: postion of expression first char
- " - lin2,col2: postion of expression last char
+ "In: - lin1,col1: position of expression first char
+ " - lin2,col2: position of expression last char
"Out: - the pattern to be looked for to find the block
" Must be called in the source buffer (use of line2byte)
function! s:Block_pattern(lin1,lin2,col1,col2)
@@ -581,7 +581,7 @@ endfunction
let res = substitute (a:res, "\n", "", "g" )
"remove double space
let res =substitute(res , " ", " ", "g")
- "remove space at begining of string.
+ "remove space at beginning of string.
let res = substitute(res, "^ *", "", "g")
return res
endfunction
diff --git a/runtime/ftplugin/octave.vim b/runtime/ftplugin/octave.vim
new file mode 100644
index 0000000000..7cab7c212a
--- /dev/null
+++ b/runtime/ftplugin/octave.vim
@@ -0,0 +1,63 @@
+" Vim filetype plugin file
+" Language: GNU Octave
+" Maintainer: Doug Kearns <dougkearns@gmail.com>
+" Last Change: 2021 Sep 02
+
+if exists("b:did_ftplugin")
+ finish
+endif
+let b:did_ftplugin = 1
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+" TODO: update Matlab ftplugin and source it as the base file?
+
+setlocal comments=s:%{,m:\ ,e:%},s:#{,m:\ ,e:#},:%,:#
+setlocal commentstring=#\ %s
+setlocal formatoptions-=t formatoptions+=croql
+
+setlocal keywordprg=info\ octave\ --vi-keys\ --index-search
+
+if exists("loaded_matchit") && !exists("b:match_words")
+ let b:match_words = '\<unwind_protect\>:\<unwind_protect_cleanup\>:\<end_unwind_protect\>'
+ if exists("octave_use_matlab_end")
+ let b:match_words ..= ',' ..
+ \ '\<\%(classdef\|enumeration\|events\|for\|function\|if\|methods\|parfor\|properties\|switch\|while\|try\)\>' ..
+ \ ':' ..
+ \ '\<\%(elseif\|else\|case\|otherwise\|break\|continue\|catch\)\>' ..
+ \ ':' ..
+ \ '\<end\>'
+ else
+ let b:match_words ..= ',' ..
+ \ '\<classdef\>:\<endclassdef\>,' ..
+ \ '\<enumeration\>:\<endenumeration\>,' ..
+ \ '\<events\>:\<endevents\>,' ..
+ \ '\<do\>:\<\%(break\|continue\)\>:\<until\>' ..
+ \ '\<for\>:\<\%(break\|continue\)\>:\<endfor\>,' ..
+ \ '\<function\>:\<return\>:\<endfunction\>,' ..
+ \ '\<if\>:\<\%(elseif\|else\)\>:\<endif\>,' ..
+ \ '\<methods\>:\<endmethods\>,' ..
+ \ '\<parfor\>:\<endparfor\>,' ..
+ \ '\<properties\>:\<endproperties\>,' ..
+ \ '\<switch\>:\<\%(case\|otherwise\)\>:\<endswitch\>,' ..
+ \ '\<while\>:\<\%(break\|continue\)\>:\<endwhile\>,' ..
+ \ '\<try\>:\<catch\>:\<end_try_catch\>'
+ endif
+ " only match in statement position
+ let s:statement_start = escape('\%(\%(^\|;\)\s*\)\@<=', '\')
+ let b:match_words = substitute(b:match_words, '\\<', s:statement_start, 'g')
+endif
+
+if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter")
+ let b:browsefilter = "GNU Octave Source Files (*.m)\t*.m\n" ..
+ \ "All Files (*.*)\t*.*\n"
+endif
+
+let b:undo_ftplugin = "setl com< cms< fo< kp< " ..
+ \ "| unlet! b:browsefilter b:match_words"
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
+
+" vim: nowrap sw=2 sts=2 ts=8 noet:
diff --git a/runtime/ftplugin/ruby.vim b/runtime/ftplugin/ruby.vim
index b4a8eaa0d8..4a476fd8cf 100644
--- a/runtime/ftplugin/ruby.vim
+++ b/runtime/ftplugin/ruby.vim
@@ -3,7 +3,7 @@
" Maintainer: Tim Pope <vimNOSPAM@tpope.org>
" URL: https://github.com/vim-ruby/vim-ruby
" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
-" Last Change: 2019 Nov 06
+" Last Change: 2020 Feb 13
if (exists("b:did_ftplugin"))
finish
@@ -112,7 +112,7 @@ else
if !exists('g:ruby_default_path')
if has("ruby") && has("win32")
ruby ::VIM::command( 'let g:ruby_default_path = split("%s",",")' % $:.join(%q{,}) )
- elseif executable('ruby')
+ elseif executable('ruby') && !empty($HOME)
let g:ruby_default_path = s:query_path($HOME)
else
let g:ruby_default_path = map(split($RUBYLIB,':'), 'v:val ==# "." ? "" : v:val')
diff --git a/runtime/ftplugin/scala.vim b/runtime/ftplugin/scala.vim
index 18e16f1d5b..b484df99f3 100644
--- a/runtime/ftplugin/scala.vim
+++ b/runtime/ftplugin/scala.vim
@@ -3,7 +3,7 @@
" Maintainer: Derek Wyatt
" URL: https://github.com/derekwyatt/vim-scala
" License: Same as Vim
-" Last Change: 02 August 2016
+" Last Change: 11 August 2021
" ----------------------------------------------------------------------------
if exists('b:did_ftplugin') || &cp
@@ -26,8 +26,8 @@ setlocal commentstring=//\ %s
setlocal shiftwidth=2 softtabstop=2 expandtab
-setlocal include='^\s*import'
-setlocal includeexpr='substitute(v:fname,"\\.","/","g")'
+setlocal include=^\\s*import
+setlocal includeexpr=substitute(v:fname,'\\.','/','g')
setlocal path+=src/main/scala,src/test/scala
setlocal suffixesadd=.scala
diff --git a/runtime/ftplugin/scdoc.vim b/runtime/ftplugin/scdoc.vim
new file mode 100644
index 0000000000..2e98e647f4
--- /dev/null
+++ b/runtime/ftplugin/scdoc.vim
@@ -0,0 +1,26 @@
+" scdoc filetype plugin
+" Maintainer: Gregory Anders <greg@gpanders.com>
+" Last Updated: 2021-08-04
+
+" Only do this when not done yet for this buffer
+if exists('b:did_ftplugin')
+ finish
+endif
+
+" Don't load another plugin for this buffer
+let b:did_ftplugin = 1
+
+setlocal comments=b:;
+setlocal commentstring=;%s
+setlocal formatoptions+=t
+setlocal noexpandtab
+setlocal shiftwidth=0
+setlocal softtabstop=0
+setlocal textwidth=80
+
+let b:undo_ftplugin = 'setl com< cms< fo< et< sw< sts< tw<'
+
+if has('conceal')
+ setlocal conceallevel=2
+ let b:undo_ftplugin .= ' cole<'
+endif
diff --git a/runtime/ftplugin/scheme.vim b/runtime/ftplugin/scheme.vim
index 5778594c41..04655bc136 100644
--- a/runtime/ftplugin/scheme.vim
+++ b/runtime/ftplugin/scheme.vim
@@ -1,9 +1,10 @@
" Vim filetype plugin file
" Language: Scheme (R7RS)
-" Last Change: 2019 Nov 18
+" Last Change: 2019-11-19
" Author: Evan Hanson <evhan@foldling.org>
" Maintainer: Evan Hanson <evhan@foldling.org>
" Previous Maintainer: Sergey Khorev <sergey.khorev@gmail.com>
+" Repository: https://git.foldling.org/vim-scheme.git
" URL: https://foldling.org/vim/ftplugin/scheme.vim
if exists('b:did_ftplugin')
@@ -48,7 +49,7 @@ let b:undo_ftplugin = b:undo_ftplugin . ' lispwords<'
let b:did_scheme_ftplugin = 1
if exists('b:is_chicken') || exists('g:is_chicken')
- exe 'ru! ftplugin/chicken.vim'
+ runtime! ftplugin/chicken.vim
endif
unlet b:did_scheme_ftplugin
diff --git a/runtime/ftplugin/systemverilog.vim b/runtime/ftplugin/systemverilog.vim
index e350427022..38ed1ad32a 100644
--- a/runtime/ftplugin/systemverilog.vim
+++ b/runtime/ftplugin/systemverilog.vim
@@ -32,7 +32,7 @@ if exists("loaded_matchit")
\ '\<checker\>:\<endchecker\>,' .
\ '\<class\>:\<endclass\>,' .
\ '\<clocking\>:\<endclocking\>,' .
- \ '\<gruop\>:\<endgruop\>,' .
+ \ '\<group\>:\<endgroup\>,' .
\ '\<interface\>:\<endinterface\>,' .
\ '\<package\>:\<endpackage\>,' .
\ '\<program\>:\<endprogram\>,' .
diff --git a/runtime/ftplugin/tex.vim b/runtime/ftplugin/tex.vim
index 11470012f9..0d68b51d46 100644
--- a/runtime/ftplugin/tex.vim
+++ b/runtime/ftplugin/tex.vim
@@ -28,7 +28,7 @@ let &l:define .= '\|\\\(re\)\=new\(boolean\|command\|counter\|environment\|font'
" Tell Vim how to recognize LaTeX \include{foo} and plain \input bar :
let &l:include .= '\|\\include{'
-" On some file systems, "{" and "}" are inluded in 'isfname'. In case the
+" On some file systems, "{" and "}" are included in 'isfname'. In case the
" TeX file has \include{fname} (LaTeX only), strip everything except "fname".
let &l:includeexpr = "substitute(v:fname, '^.\\{-}{\\|}.*', '', 'g')"
diff --git a/runtime/indent/ada.vim b/runtime/indent/ada.vim
index 1ca7fbacbe..6c8ab05267 100644
--- a/runtime/indent/ada.vim
+++ b/runtime/indent/ada.vim
@@ -219,7 +219,7 @@ function GetAdaIndent()
" Move indent in twice (next 'when' will move back)
let ind = ind + 2 * shiftwidth()
elseif line =~ '^\s*end\s*record\>'
- " Move indent back to tallying 'type' preceeding the 'record'.
+ " Move indent back to tallying 'type' preceding the 'record'.
" Allow indent to be equal to 'end record's.
let ind = s:MainBlockIndent( ind+shiftwidth(), lnum, 'type\>', '' )
elseif line =~ '\(^\s*new\>.*\)\@<!)\s*[;,]\s*$'
diff --git a/runtime/indent/bzl.vim b/runtime/indent/bzl.vim
index 6904bfdedb..cf4cfb5fad 100644
--- a/runtime/indent/bzl.vim
+++ b/runtime/indent/bzl.vim
@@ -1,7 +1,7 @@
" Vim indent file
" Language: Bazel (http://bazel.io)
" Maintainer: David Barnett (https://github.com/google/vim-ft-bzl)
-" Last Change: 2017 Jun 13
+" Last Change: 2021 Jul 08
if exists('b:did_indent')
finish
@@ -41,30 +41,41 @@ function GetBzlIndent(lnum) abort
if exists('g:pyindent_open_paren')
let l:pyindent_open_paren = g:pyindent_open_paren
endif
- let g:pyindent_nested_paren = 'shiftwidth() * 2'
- let g:pyindent_open_paren = 'shiftwidth() * 2'
+ let g:pyindent_nested_paren = 'shiftwidth()'
+ let g:pyindent_open_paren = 'shiftwidth()'
endif
let l:indent = -1
- " Indent inside parens.
- " Align with the open paren unless it is at the end of the line.
- " E.g.
- " open_paren_not_at_EOL(100,
- " (200,
- " 300),
- " 400)
- " open_paren_at_EOL(
- " 100, 200, 300, 400)
call cursor(a:lnum, 1)
let [l:par_line, l:par_col] = searchpairpos('(\|{\|\[', '', ')\|}\|\]', 'bW',
\ "line('.') < " . (a:lnum - s:maxoff) . " ? dummy :" .
\ " synIDattr(synID(line('.'), col('.'), 1), 'name')" .
\ " =~ '\\(Comment\\|String\\)$'")
if l:par_line > 0
- call cursor(l:par_line, 1)
- if l:par_col != col('$') - 1
- let l:indent = l:par_col
+ " Indent inside parens.
+ if searchpair('(\|{\|\[', '', ')\|}\|\]', 'W',
+ \ "line('.') < " . (a:lnum - s:maxoff) . " ? dummy :" .
+ \ " synIDattr(synID(line('.'), col('.'), 1), 'name')" .
+ \ " =~ '\\(Comment\\|String\\)$'") && line('.') == a:lnum
+ " If cursor is at close parens, match indent with open parens.
+ " E.g.
+ " foo(
+ " )
+ let l:indent = indent(l:par_line)
+ else
+ " Align with the open paren unless it is at the end of the line.
+ " E.g.
+ " open_paren_not_at_EOL(100,
+ " (200,
+ " 300),
+ " 400)
+ " open_paren_at_EOL(
+ " 100, 200, 300, 400)
+ call cursor(l:par_line, 1)
+ if l:par_col != col('$') - 1
+ let l:indent = l:par_col
+ endif
endif
endif
diff --git a/runtime/indent/cdl.vim b/runtime/indent/cdl.vim
index 4f9b7a8967..fb4fe27310 100644
--- a/runtime/indent/cdl.vim
+++ b/runtime/indent/cdl.vim
@@ -16,8 +16,8 @@ if exists("*CdlGetIndent")
"finish
endif
-" find out if an "...=..." expresion is an assignment (or a conditional)
-" it scans 'line' first, and then the previos lines
+" find out if an "...=..." expression is an assignment (or a conditional)
+" it scans 'line' first, and then the previous lines
fun! CdlAsignment(lnum, line)
let f = -1
let lnum = a:lnum
@@ -33,7 +33,7 @@ fun! CdlAsignment(lnum, line)
endif
" it's formula if there's a ';', 'elsE', 'theN', 'enDif' or 'expr'
" conditional if there's a '<', '>', 'elseif', 'if', 'and', 'or', 'not',
- " 'memberis', 'childrenof' and other \k\+of funcions
+ " 'memberis', 'childrenof' and other \k\+of functions
let f = line[inicio-1] =~? '[en;]' || strpart(line, inicio-4, 4) =~? 'ndif\|expr'
endw
let lnum = prevnonblank(lnum-1)
@@ -106,7 +106,7 @@ fun! CdlGetIndent(lnum)
elseif c == '(' || c ==? 'f' " '(' or 'if'
let ind = ind + shiftwidth()
else " c == '='
- " if it is an asignment increase indent
+ " if it is an assignment increase indent
if f == -1 " we don't know yet, find out
let f = CdlAsignment(lnum, strpart(line, 0, inicio))
end
@@ -117,11 +117,11 @@ fun! CdlGetIndent(lnum)
endw
" CURRENT LINE, if it starts with a closing element, decrease indent
- " or if it starts with '=' (asignment), increase indent
+ " or if it starts with '=' (assignment), increase indent
if match(thisline, '^\c\s*\(else\|then\|endif\|[);]\)') >= 0
let ind = ind - shiftwidth()
elseif match(thisline, '^\s*=') >= 0
- if f == -1 " we don't know yet if is an asignment, find out
+ if f == -1 " we don't know yet if is an assignment, find out
let f = CdlAsignment(lnum, "")
end
if f == 1 " formula increase it
diff --git a/runtime/indent/config.vim b/runtime/indent/config.vim
index 074f467bee..c987a78d64 100644
--- a/runtime/indent/config.vim
+++ b/runtime/indent/config.vim
@@ -62,8 +62,8 @@ function GetConfigIndent()
let ind = s:GetOffsetOf(line, '\[')
endif
- " if previous line had an unmatched closing parantheses,
- " indent to the matching opening parantheses
+ " if previous line had an unmatched closing parentheses,
+ " indent to the matching opening parentheses
if line =~ '[^(]\+\\\@<!)$'
call search(')', 'bW')
let lnum = searchpair('\\\@<!(', '', ')', 'bWn')
diff --git a/runtime/indent/dtd.vim b/runtime/indent/dtd.vim
index 963ac408ef..30c06aa8b2 100644
--- a/runtime/indent/dtd.vim
+++ b/runtime/indent/dtd.vim
@@ -119,16 +119,16 @@ function GetDTDIndent()
" Next comes the content model. If the token we’ve found isn’t a
" parenthesis it must be either ANY, EMPTY or some random junk. Either
" way, we’re done indenting this element, so set it to that of the first
- " line so that the terminating “>” winds up having the same indention.
+ " line so that the terminating “>” winds up having the same indentation.
if token != '('
return indent
endif
" Now go through the content model. We need to keep track of the nesting
" of parentheses. As soon as we hit 0 we’re done. If that happens we must
- " have a complete content model. Thus set indention to be the same as that
+ " have a complete content model. Thus set indentation to be the same as that
" of the first line so that the terminating “>” winds up having the same
- " indention. Otherwise, we’ll indent to the innermost parentheses not yet
+ " indentation. Otherwise, we’ll indent to the innermost parentheses not yet
" matched.
let [indent_of_innermost, end] = s:indent_to_innermost_parentheses(line, end)
if indent_of_innermost != -1
diff --git a/runtime/indent/erlang.vim b/runtime/indent/erlang.vim
index 625cfde0c1..4e7bf4ef4d 100644
--- a/runtime/indent/erlang.vim
+++ b/runtime/indent/erlang.vim
@@ -57,7 +57,7 @@ endfunction
" ======================
" Indtokens are "indentation tokens". See their exact format in the
-" documentaiton of the s:GetTokensFromLine function.
+" documentation of the s:GetTokensFromLine function.
" Purpose:
" Calculate the new virtual column after the given segment of a line.
@@ -75,7 +75,7 @@ endfunction
" s:CalcVCol("\t'\tx', b", 1, 4, 4) -> 10
function! s:CalcVCol(line, first_index, last_index, vcol, tabstop)
- " We copy the relevent segment of the line, otherwise if the line were
+ " We copy the relevant segment of the line, otherwise if the line were
" e.g. `"\t", term` then the else branch below would consume the `", term`
" part at once.
let line = a:line[a:first_index : a:last_index]
@@ -604,7 +604,7 @@ endfunction
function! s:BeginElementFoundIfEmpty(stack, token, curr_vcol, stored_vcol, sw)
if empty(a:stack)
if a:stored_vcol ==# -1
- call s:Log(' "' . a:token . '" directly preceeds LTI -> return')
+ call s:Log(' "' . a:token . '" directly precedes LTI -> return')
return [1, a:curr_vcol + a:sw]
else
call s:Log(' "' . a:token .
@@ -825,7 +825,7 @@ function! s:ErlangCalcIndent2(lnum, stack)
if ret | return res | endif
if stored_vcol ==# -1
- call s:Log(' End of clause directly preceeds LTI -> return')
+ call s:Log(' End of clause directly precedes LTI -> return')
return 0
else
call s:Log(' End of clause (but not end of line) -> return')
diff --git a/runtime/indent/html.vim b/runtime/indent/html.vim
index 7019bd4a82..d4b91f6421 100644
--- a/runtime/indent/html.vim
+++ b/runtime/indent/html.vim
@@ -1,7 +1,7 @@
" Vim indent script for HTML
" Maintainer: Bram Moolenaar
" Original Author: Andy Wokula <anwoku@yahoo.de>
-" Last Change: 2021 Jan 26
+" Last Change: 2021 Jun 13
" Version: 1.0 "{{{
" Description: HTML indent script with cached state for faster indenting on a
" range of lines.
@@ -62,7 +62,7 @@ let s:tagname = '\w\+\(-\w\+\)*'
" Prefer using buffer-local settings over global settings, so that there can
" be defaults for all HTML files and exceptions for specific types of HTML
" files.
-func! HtmlIndent_CheckUserSettings()
+func HtmlIndent_CheckUserSettings()
"{{{
let inctags = ''
if exists("b:html_indent_inctags")
@@ -178,7 +178,7 @@ let s:endtags = [0,0,0,0,0,0,0] " long enough for the highest index
"}}}
" Add a list of tag names for a pair of <tag> </tag> to "tags".
-func! s:AddITags(tags, taglist)
+func s:AddITags(tags, taglist)
"{{{
for itag in a:taglist
let a:tags[itag] = 1
@@ -187,7 +187,7 @@ func! s:AddITags(tags, taglist)
endfunc "}}}
" Take a list of tag name pairs that are not to be used as tag pairs.
-func! s:RemoveITags(tags, taglist)
+func s:RemoveITags(tags, taglist)
"{{{
for itag in a:taglist
let a:tags[itag] = 1
@@ -196,7 +196,7 @@ func! s:RemoveITags(tags, taglist)
endfunc "}}}
" Add a block tag, that is a tag with a different kind of indenting.
-func! s:AddBlockTag(tag, id, ...)
+func s:AddBlockTag(tag, id, ...)
"{{{
if !(a:id >= 2 && a:id < len(s:endtags))
echoerr 'AddBlockTag ' . a:id
@@ -255,7 +255,7 @@ call s:AddBlockTag('<!--[', 6, '![endif]-->')
" Return non-zero when "tagname" is an opening tag, not being a block tag, for
" which there should be a closing tag. Can be used by scripts that include
" HTML indenting.
-func! HtmlIndent_IsOpenTag(tagname)
+func HtmlIndent_IsOpenTag(tagname)
"{{{
if get(s:indent_tags, a:tagname) == 1
return 1
@@ -264,7 +264,7 @@ func! HtmlIndent_IsOpenTag(tagname)
endfunc "}}}
" Get the value for "tagname", taking care of buffer-local tags.
-func! s:get_tag(tagname)
+func s:get_tag(tagname)
"{{{
let i = get(s:indent_tags, a:tagname)
if (i == 1 || i == -1) && get(b:hi_removed_tags, a:tagname) != 0
@@ -277,7 +277,7 @@ func! s:get_tag(tagname)
endfunc "}}}
" Count the number of start and end tags in "text".
-func! s:CountITags(text)
+func s:CountITags(text)
"{{{
" Store the result in s:curind and s:nextrel.
let s:curind = 0 " relative indent steps for current line [unit &sw]:
@@ -289,7 +289,7 @@ func! s:CountITags(text)
endfunc "}}}
" Count the number of start and end tags in text.
-func! s:CountTagsAndState(text)
+func s:CountTagsAndState(text)
"{{{
" Store the result in s:curind and s:nextrel. Update b:hi_newstate.block.
let s:curind = 0 " relative indent steps for current line [unit &sw]:
@@ -304,7 +304,7 @@ func! s:CountTagsAndState(text)
endfunc "}}}
" Used by s:CountITags() and s:CountTagsAndState().
-func! s:CheckTag(itag)
+func s:CheckTag(itag)
"{{{
" Returns an empty string or "SCRIPT".
" a:itag can be "tag" or "/tag" or "<!--" or "-->"
@@ -338,7 +338,7 @@ func! s:CheckTag(itag)
endfunc "}}}
" Used by s:CheckTag(). Returns an empty string or "SCRIPT".
-func! s:CheckBlockTag(blocktag, ind)
+func s:CheckBlockTag(blocktag, ind)
"{{{
if a:ind > 0
" a block starts here
@@ -366,7 +366,7 @@ func! s:CheckBlockTag(blocktag, ind)
endfunc "}}}
" Used by s:CheckTag().
-func! s:CheckCustomTag(ctag)
+func s:CheckCustomTag(ctag)
"{{{
" Returns 1 if ctag is the tag for a custom element, 0 otherwise.
" a:ctag can be "tag" or "/tag" or "<!--" or "-->"
@@ -396,7 +396,7 @@ func! s:CheckCustomTag(ctag)
endfunc "}}}
" Return the <script> type: either "javascript" or ""
-func! s:GetScriptType(str)
+func s:GetScriptType(str)
"{{{
if a:str == "" || a:str =~ "java"
return "javascript"
@@ -407,7 +407,7 @@ endfunc "}}}
" Look back in the file, starting at a:lnum - 1, to compute a state for the
" start of line a:lnum. Return the new state.
-func! s:FreshState(lnum)
+func s:FreshState(lnum)
"{{{
" A state is to know ALL relevant details about the
" lines 1..a:lnum-1, initial calculating (here!) can be slow, but updating is
@@ -568,24 +568,29 @@ func! s:FreshState(lnum)
endfunc "}}}
" Indent inside a <pre> block: Keep indent as-is.
-func! s:Alien2()
+func s:Alien2()
"{{{
return -1
endfunc "}}}
" Return the indent inside a <script> block for javascript.
-func! s:Alien3()
+func s:Alien3()
"{{{
let lnum = prevnonblank(v:lnum - 1)
while lnum > 1 && getline(lnum) =~ '^\s*/[/*]'
" Skip over comments to avoid that cindent() aligns with the <script> tag
let lnum = prevnonblank(lnum - 1)
endwhile
+ if lnum < b:hi_indent.blocklnr
+ " indent for <script> itself
+ return b:hi_indent.blocktagind
+ endif
if lnum == b:hi_indent.blocklnr
" indent for the first line after <script>
return eval(b:hi_js1indent)
endif
if b:hi_indent.scripttype == "javascript"
+ " indent for further lines
return eval(b:hi_js1indent) + GetJavascriptIndent()
else
return -1
@@ -593,7 +598,7 @@ func! s:Alien3()
endfunc "}}}
" Return the indent inside a <style> block.
-func! s:Alien4()
+func s:Alien4()
"{{{
if prevnonblank(v:lnum-1) == b:hi_indent.blocklnr
" indent for first content line
@@ -603,7 +608,7 @@ func! s:Alien4()
endfunc "}}}
" Indending inside a <style> block. Returns the indent.
-func! s:CSSIndent()
+func s:CSSIndent()
"{{{
" This handles standard CSS and also Closure stylesheets where special lines
" start with @.
@@ -720,13 +725,13 @@ endfunc "}}}
" tag: blah
" tag: blah &&
" tag: blah ||
-func! s:CssUnfinished(text)
+func s:CssUnfinished(text)
"{{{
return a:text =~ '\(||\|&&\|:\|\k\)\s*$'
endfunc "}}}
" Search back for the first unfinished line above "lnum".
-func! s:CssFirstUnfinished(lnum, min_lnum)
+func s:CssFirstUnfinished(lnum, min_lnum)
"{{{
let align_lnum = a:lnum
while align_lnum > a:min_lnum && s:CssUnfinished(getline(align_lnum - 1))
@@ -736,7 +741,7 @@ func! s:CssFirstUnfinished(lnum, min_lnum)
endfunc "}}}
" Find the non-empty line at or before "lnum" that is not a comment.
-func! s:CssPrevNonComment(lnum, stopline)
+func s:CssPrevNonComment(lnum, stopline)
"{{{
" caller starts from a line a:lnum + 1 that is not a comment
let lnum = prevnonblank(a:lnum)
@@ -761,7 +766,7 @@ func! s:CssPrevNonComment(lnum, stopline)
endfunc "}}}
" Check the number of {} and () in line "lnum". Return a dict with the counts.
-func! HtmlIndent_CountBraces(lnum)
+func HtmlIndent_CountBraces(lnum)
"{{{
let brs = substitute(getline(a:lnum), '[''"].\{-}[''"]\|/\*.\{-}\*/\|/\*.*$\|[^{}()]', '', 'g')
let c_open = 0
@@ -794,7 +799,7 @@ func! HtmlIndent_CountBraces(lnum)
endfunc "}}}
" Return the indent for a comment: <!-- -->
-func! s:Alien5()
+func s:Alien5()
"{{{
let curtext = getline(v:lnum)
if curtext =~ '^\s*\zs-->'
@@ -826,7 +831,7 @@ func! s:Alien5()
endfunc "}}}
" Return the indent for conditional comment: <!--[ ![endif]-->
-func! s:Alien6()
+func s:Alien6()
"{{{
let curtext = getline(v:lnum)
if curtext =~ '\s*\zs<!\[endif\]-->'
@@ -840,7 +845,7 @@ func! s:Alien6()
endfunc "}}}
" When the "lnum" line ends in ">" find the line containing the matching "<".
-func! HtmlIndent_FindTagStart(lnum)
+func HtmlIndent_FindTagStart(lnum)
"{{{
" Avoids using the indent of a continuation line.
" Moves the cursor.
@@ -863,7 +868,7 @@ func! HtmlIndent_FindTagStart(lnum)
endfunc "}}}
" Find the unclosed start tag from the current cursor position.
-func! HtmlIndent_FindStartTag()
+func HtmlIndent_FindStartTag()
"{{{
" The cursor must be on or before a closing tag.
" If found, positions the cursor at the match and returns the line number.
@@ -877,7 +882,7 @@ func! HtmlIndent_FindStartTag()
endfunc "}}}
" Moves the cursor from a "<" to the matching ">".
-func! HtmlIndent_FindTagEnd()
+func HtmlIndent_FindTagEnd()
"{{{
" Call this with the cursor on the "<" of a start tag.
" This will move the cursor to the ">" of the matching end tag or, when it's
@@ -897,7 +902,7 @@ func! HtmlIndent_FindTagEnd()
endfunc "}}}
" Indenting inside a start tag. Return the correct indent or -1 if unknown.
-func! s:InsideTag(foundHtmlString)
+func s:InsideTag(foundHtmlString)
"{{{
if a:foundHtmlString
" Inside an attribute string.
@@ -958,7 +963,7 @@ func! s:InsideTag(foundHtmlString)
endfunc "}}}
" THE MAIN INDENT FUNCTION. Return the amount of indent for v:lnum.
-func! HtmlIndent()
+func HtmlIndent()
"{{{
if prevnonblank(v:lnum - 1) < 1
" First non-blank line has no indent.
diff --git a/runtime/indent/json.vim b/runtime/indent/json.vim
index c649e37013..09c7d7a85a 100644
--- a/runtime/indent/json.vim
+++ b/runtime/indent/json.vim
@@ -1,6 +1,6 @@
" Vim indent file
" Language: JSON
-" Mantainer: Eli Parra <eli@elzr.com> https://github.com/elzr/vim-json
+" Maintainer: Eli Parra <eli@elzr.com> https://github.com/elzr/vim-json
" Last Change: 2020 Aug 30
" https://github.com/jakar/vim-json/commit/20b650e22aa750c4ab6a66aa646bdd95d7cd548a#diff-e81fc111b2052e306d126bd9989f7b7c
" Original Author: Rogerz Zhang <rogerz.zhang at gmail.com> http://github.com/rogerz/vim-json
diff --git a/runtime/indent/jsonc.vim b/runtime/indent/jsonc.vim
new file mode 100644
index 0000000000..bf8e501dd5
--- /dev/null
+++ b/runtime/indent/jsonc.vim
@@ -0,0 +1,189 @@
+" Vim indent file
+" Language: JSONC (JSON with Comments)
+" Original Author: Izhak Jakov <izhak724@gmail.com>
+" Acknowledgement: Based off of vim-json maintained by Eli Parra <eli@elzr.com>
+" https://github.com/elzr/vim-json
+" Last Change: 2021-07-01
+
+" 0. Initialization {{{1
+" =================
+
+" Only load this indent file when no other was loaded.
+if exists("b:did_indent")
+ finish
+endif
+let b:did_indent = 1
+
+setlocal nosmartindent
+
+" Now, set up our indentation expression and keys that trigger it.
+setlocal indentexpr=GetJSONCIndent()
+setlocal indentkeys=0{,0},0),0[,0],!^F,o,O,e
+
+" Only define the function once.
+if exists("*GetJSONCIndent")
+ finish
+endif
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+" 1. Variables {{{1
+" ============
+
+let s:line_term = '\s*\%(\%(\/\/\).*\)\=$'
+" Regex that defines blocks.
+let s:block_regex = '\%({\)\s*\%(|\%([*@]\=\h\w*,\=\s*\)\%(,\s*[*@]\=\h\w*\)*|\)\=' . s:line_term
+
+" 2. Auxiliary Functions {{{1
+" ======================
+
+" Check if the character at lnum:col is inside a string.
+function s:IsInString(lnum, col)
+ return synIDattr(synID(a:lnum, a:col, 1), 'name') == 'jsonString'
+endfunction
+
+" Find line above 'lnum' that isn't empty, or in a string.
+function s:PrevNonBlankNonString(lnum)
+ let lnum = prevnonblank(a:lnum)
+ while lnum > 0
+ " If the line isn't empty or in a string, end search.
+ let line = getline(lnum)
+ if !(s:IsInString(lnum, 1) && s:IsInString(lnum, strlen(line)))
+ break
+ endif
+ let lnum = prevnonblank(lnum - 1)
+ endwhile
+ return lnum
+endfunction
+
+" Check if line 'lnum' has more opening brackets than closing ones.
+function s:LineHasOpeningBrackets(lnum)
+ let open_0 = 0
+ let open_2 = 0
+ let open_4 = 0
+ let line = getline(a:lnum)
+ let pos = match(line, '[][(){}]', 0)
+ while pos != -1
+ let idx = stridx('(){}[]', line[pos])
+ if idx % 2 == 0
+ let open_{idx} = open_{idx} + 1
+ else
+ let open_{idx - 1} = open_{idx - 1} - 1
+ endif
+ let pos = match(line, '[][(){}]', pos + 1)
+ endwhile
+ return (open_0 > 0) . (open_2 > 0) . (open_4 > 0)
+endfunction
+
+function s:Match(lnum, regex)
+ let col = match(getline(a:lnum), a:regex) + 1
+ return col > 0 && !s:IsInString(a:lnum, col) ? col : 0
+endfunction
+
+" 3. GetJSONCIndent Function {{{1
+" =========================
+
+function GetJSONCIndent()
+ if !exists("s:inside_comment")
+ let s:inside_comment = 0
+ endif
+
+ " 3.1. Setup {{{2
+ " ----------
+
+ " Set up variables for restoring position in file. Could use v:lnum here.
+ let vcol = col('.')
+
+ " 3.2. Work on the current line {{{2
+ " -----------------------------
+
+
+ " Get the current line.
+ let line = getline(v:lnum)
+ let ind = -1
+ if s:inside_comment == 0
+ " TODO iterate through all the matches in a line
+ let col = matchend(line, '\/\*')
+ if col > 0 && !s:IsInString(v:lnum, col)
+ let s:inside_comment = 1
+ endif
+ endif
+ " If we're in the middle of a comment
+ if s:inside_comment == 1
+ let col = matchend(line, '\*\/')
+ if col > 0 && !s:IsInString(v:lnum, col)
+ let s:inside_comment = 0
+ endif
+ return ind
+ endif
+ if line =~ '^\s*//'
+ return ind
+ endif
+
+ " If we got a closing bracket on an empty line, find its match and indent
+ " according to it.
+ let col = matchend(line, '^\s*[]}]')
+
+ if col > 0 && !s:IsInString(v:lnum, col)
+ call cursor(v:lnum, col)
+ let bs = strpart('{}[]', stridx('}]', line[col - 1]) * 2, 2)
+
+ let pairstart = escape(bs[0], '[')
+ let pairend = escape(bs[1], ']')
+ let pairline = searchpair(pairstart, '', pairend, 'bW')
+
+ if pairline > 0
+ let ind = indent(pairline)
+ else
+ let ind = virtcol('.') - 1
+ endif
+
+ return ind
+ endif
+
+ " If we are in a multi-line string, don't do anything to it.
+ if s:IsInString(v:lnum, matchend(line, '^\s*') + 1)
+ return indent('.')
+ endif
+
+ " 3.3. Work on the previous line. {{{2
+ " -------------------------------
+
+ let lnum = prevnonblank(v:lnum - 1)
+
+ if lnum == 0
+ return 0
+ endif
+
+ " Set up variables for current line.
+ let line = getline(lnum)
+ let ind = indent(lnum)
+
+ " If the previous line ended with a block opening, add a level of indent.
+ " if s:Match(lnum, s:block_regex)
+ " return indent(lnum) + shiftwidth()
+ " endif
+
+ " If the previous line contained an opening bracket, and we are still in it,
+ " add indent depending on the bracket type.
+ if line =~ '[[({]'
+ let counts = s:LineHasOpeningBrackets(lnum)
+ if counts[0] == '1' || counts[1] == '1' || counts[2] == '1'
+ return ind + shiftwidth()
+ else
+ call cursor(v:lnum, vcol)
+ end
+ endif
+
+ " }}}2
+
+ return ind
+endfunction
+
+" }}}1
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
+
+" vim:set sw=2 sts=2 ts=8 noet:
diff --git a/runtime/indent/julia.vim b/runtime/indent/julia.vim
new file mode 100644
index 0000000000..a90cff49e4
--- /dev/null
+++ b/runtime/indent/julia.vim
@@ -0,0 +1,491 @@
+" Vim indent file
+" Language: Julia
+" Maintainer: Carlo Baldassi <carlobaldassi@gmail.com>
+" Homepage: https://github.com/JuliaEditorSupport/julia-vim
+" Last Change: 2016 jun 16
+" Notes: originally based on Bram Molenaar's indent file for vim
+
+setlocal autoindent
+
+setlocal indentexpr=GetJuliaIndent()
+setlocal indentkeys+==end,=else,=catch,=finally,),],}
+setlocal indentkeys-=0#
+setlocal indentkeys-=:
+setlocal indentkeys-=0{
+setlocal indentkeys-=0}
+setlocal nosmartindent
+
+" Only define the function once.
+if exists("*GetJuliaIndent")
+ finish
+endif
+
+let s:skipPatternsBasic = '\<julia\%(Comment\%([LM]\|Delim\)\)\>'
+let s:skipPatterns = '\<julia\%(Comprehension\%(For\|If\)\|RangeKeyword\|Comment\%([LM]\|Delim\)\|\%([bs]\|Shell\|Printf\|Doc\)\?String\|StringPrefixed\|DocStringM\(Raw\)\?\|RegEx\|SymbolS\?\|Macro\|Dotted\)\>'
+
+function JuliaMatch(lnum, str, regex, st, ...)
+ let s = a:st
+ let e = a:0 > 0 ? a:1 : -1
+ let basic_skip = a:0 > 1 ? a:2 : 'all'
+ let skip = basic_skip ==# 'basic' ? s:skipPatternsBasic : s:skipPatterns
+ while 1
+ let f = match(a:str, '\C' . a:regex, s)
+ if e >= 0 && f >= e
+ return -1
+ endif
+ if f >= 0
+ let attr = synIDattr(synID(a:lnum,f+1,1),"name")
+ let attrT = synIDattr(synID(a:lnum,f+1,0),"name")
+ if attr =~# skip || attrT =~# skip
+ let s = f+1
+ continue
+ endif
+ endif
+ break
+ endwhile
+ return f
+endfunction
+
+function GetJuliaNestingStruct(lnum, ...)
+ " Auxiliary function to inspect the block structure of a line
+ let line = getline(a:lnum)
+ let s = a:0 > 0 ? a:1 : 0
+ let e = a:0 > 1 ? a:2 : -1
+ let blocks_stack = []
+ let num_closed_blocks = 0
+ while 1
+ let fb = JuliaMatch(a:lnum, line, '\<\%(if\|else\%(if\)\?\|while\|for\|try\|catch\|finally\|\%(staged\)\?function\|macro\|begin\|mutable\s\+struct\|\%(mutable\s\+\)\@<!struct\|\%(abstract\|primitive\)\s\+type\|let\|\%(bare\)\?module\|quote\|do\)\>', s, e)
+ let fe = JuliaMatch(a:lnum, line, '\<end\>', s, e)
+
+ if fb < 0 && fe < 0
+ " No blocks found
+ break
+ end
+
+ if fb >= 0 && (fb < fe || fe < 0)
+ " The first occurrence is an opening block keyword
+ " Note: some keywords (elseif,else,catch,finally) are both
+ " closing blocks and opening new ones
+
+ let i = JuliaMatch(a:lnum, line, '\<if\>', s)
+ if i >= 0 && i == fb
+ let s = i+1
+ call add(blocks_stack, 'if')
+ continue
+ endif
+ let i = JuliaMatch(a:lnum, line, '\<elseif\>', s)
+ if i >= 0 && i == fb
+ let s = i+1
+ if len(blocks_stack) > 0 && blocks_stack[-1] == 'if'
+ let blocks_stack[-1] = 'elseif'
+ elseif (len(blocks_stack) > 0 && blocks_stack[-1] != 'elseif') || len(blocks_stack) == 0
+ call add(blocks_stack, 'elseif')
+ let num_closed_blocks += 1
+ endif
+ continue
+ endif
+ let i = JuliaMatch(a:lnum, line, '\<else\>', s)
+ if i >= 0 && i == fb
+ let s = i+1
+ if len(blocks_stack) > 0 && blocks_stack[-1] =~# '\<\%(else\)\=if\>'
+ let blocks_stack[-1] = 'else'
+ else
+ call add(blocks_stack, 'else')
+ let num_closed_blocks += 1
+ endif
+ continue
+ endif
+
+ let i = JuliaMatch(a:lnum, line, '\<try\>', s)
+ if i >= 0 && i == fb
+ let s = i+1
+ call add(blocks_stack, 'try')
+ continue
+ endif
+ let i = JuliaMatch(a:lnum, line, '\<catch\>', s)
+ if i >= 0 && i == fb
+ let s = i+1
+ if len(blocks_stack) > 0 && blocks_stack[-1] == 'try'
+ let blocks_stack[-1] = 'catch'
+ else
+ call add(blocks_stack, 'catch')
+ let num_closed_blocks += 1
+ endif
+ continue
+ endif
+ let i = JuliaMatch(a:lnum, line, '\<finally\>', s)
+ if i >= 0 && i == fb
+ let s = i+1
+ if len(blocks_stack) > 0 && (blocks_stack[-1] == 'try' || blocks_stack[-1] == 'catch')
+ let blocks_stack[-1] = 'finally'
+ else
+ call add(blocks_stack, 'finally')
+ let num_closed_blocks += 1
+ endif
+ continue
+ endif
+
+ let i = JuliaMatch(a:lnum, line, '\<\%(bare\)\?module\>', s)
+ if i >= 0 && i == fb
+ let s = i+1
+ if i == 0
+ call add(blocks_stack, 'col1module')
+ else
+ call add(blocks_stack, 'other')
+ endif
+ continue
+ endif
+
+ let i = JuliaMatch(a:lnum, line, '\<\%(while\|for\|function\|macro\|begin\|\%(mutable\s\+\)\?struct\|\%(abstract\|primitive\)\s\+type\|let\|quote\|do\)\>', s)
+ if i >= 0 && i == fb
+ if match(line, '\C\<\%(mutable\|abstract\|primitive\)', i) != -1
+ let s = i+11
+ else
+ let s = i+1
+ endif
+ call add(blocks_stack, 'other')
+ continue
+ endif
+
+ " Note: it should be impossible to get here
+ break
+
+ else
+ " The first occurrence is an 'end'
+
+ let s = fe+1
+ if len(blocks_stack) == 0
+ let num_closed_blocks += 1
+ else
+ call remove(blocks_stack, -1)
+ endif
+ continue
+
+ endif
+
+ " Note: it should be impossible to get here
+ break
+ endwhile
+ let num_open_blocks = len(blocks_stack) - count(blocks_stack, 'col1module')
+ return [num_open_blocks, num_closed_blocks]
+endfunction
+
+function GetJuliaNestingBrackets(lnum, c)
+ " Auxiliary function to inspect the brackets structure of a line
+ let line = getline(a:lnum)[0 : (a:c - 1)]
+ let s = 0
+ let brackets_stack = []
+ let last_closed_bracket = -1
+ while 1
+ let fb = JuliaMatch(a:lnum, line, '[([{]', s)
+ let fe = JuliaMatch(a:lnum, line, '[])}]', s)
+
+ if fb < 0 && fe < 0
+ " No brackets found
+ break
+ end
+
+ if fb >= 0 && (fb < fe || fe < 0)
+ " The first occurrence is an opening bracket
+
+ let i = JuliaMatch(a:lnum, line, '(', s)
+ if i >= 0 && i == fb
+ let s = i+1
+ call add(brackets_stack, ['par',i])
+ continue
+ endif
+
+ let i = JuliaMatch(a:lnum, line, '\[', s)
+ if i >= 0 && i == fb
+ let s = i+1
+ call add(brackets_stack, ['sqbra',i])
+ continue
+ endif
+
+ let i = JuliaMatch(a:lnum, line, '{', s)
+ if i >= 0 && i == fb
+ let s = i+1
+ call add(brackets_stack, ['curbra',i])
+ continue
+ endif
+
+ " Note: it should be impossible to get here
+ break
+
+ else
+ " The first occurrence is a closing bracket
+
+ let i = JuliaMatch(a:lnum, line, ')', s)
+ if i >= 0 && i == fe
+ let s = i+1
+ if len(brackets_stack) > 0 && brackets_stack[-1][0] == 'par'
+ call remove(brackets_stack, -1)
+ else
+ let last_closed_bracket = i + 1
+ endif
+ continue
+ endif
+
+ let i = JuliaMatch(a:lnum, line, ']', s)
+ if i >= 0 && i == fe
+ let s = i+1
+ if len(brackets_stack) > 0 && brackets_stack[-1][0] == 'sqbra'
+ call remove(brackets_stack, -1)
+ else
+ let last_closed_bracket = i + 1
+ endif
+ continue
+ endif
+
+ let i = JuliaMatch(a:lnum, line, '}', s)
+ if i >= 0 && i == fe
+ let s = i+1
+ if len(brackets_stack) > 0 && brackets_stack[-1][0] == 'curbra'
+ call remove(brackets_stack, -1)
+ else
+ let last_closed_bracket = i + 1
+ endif
+ continue
+ endif
+
+ " Note: it should be impossible to get here
+ break
+
+ endif
+
+ " Note: it should be impossible to get here
+ break
+ endwhile
+ let first_open_bracket = -1
+ let last_open_bracket = -1
+ let infuncargs = 0
+ if len(brackets_stack) > 0
+ let first_open_bracket = brackets_stack[0][1]
+ let last_open_bracket = brackets_stack[-1][1]
+ if brackets_stack[-1][0] == 'par' && IsFunctionArgPar(a:lnum, last_open_bracket+1)
+ let infuncargs = 1
+ endif
+ endif
+ return [first_open_bracket, last_open_bracket, last_closed_bracket, infuncargs]
+endfunction
+
+let s:bracketBlocks = '\<julia\%(\%(\%(Printf\)\?Par\|SqBra\%(Idx\)\?\|CurBra\)Block\|ParBlockInRange\|StringVars\%(Par\|SqBra\|CurBra\)\|Dollar\%(Par\|SqBra\)\|QuotedParBlockS\?\)\>'
+
+function IsInBrackets(lnum, c)
+ let stack = map(synstack(a:lnum, a:c), 'synIDattr(v:val, "name")')
+ call filter(stack, 'v:val =~# s:bracketBlocks')
+ return len(stack) > 0
+endfunction
+
+function IsInDocString(lnum)
+ let stack = map(synstack(a:lnum, 1), 'synIDattr(v:val, "name")')
+ call filter(stack, 'v:val =~# "\\<juliaDocString\\(Delim\\|M\\\(Raw\\)\\?\\)\\?\\>"')
+ return len(stack) > 0
+endfunction
+
+function IsInContinuationImportLine(lnum)
+ let stack = map(synstack(a:lnum, 1), 'synIDattr(v:val, "name")')
+ call filter(stack, 'v:val =~# "\\<juliaImportLine\\>"')
+ if len(stack) == 0
+ return 0
+ endif
+ return JuliaMatch(a:lnum, getline(a:lnum), '\<\%(import\|using\|export\)\>', indent(a:lnum)) == -1
+endfunction
+
+function IsFunctionArgPar(lnum, c)
+ if a:c == 0
+ return 0
+ endif
+ let stack = map(synstack(a:lnum, a:c-1), 'synIDattr(v:val, "name")')
+ return len(stack) >= 2 && stack[-2] ==# 'juliaFunctionDef'
+endfunction
+
+function JumpToMatch(lnum, last_closed_bracket)
+ " we use the % command to skip back (tries to ues matchit if possible,
+ " otherwise resorts to vim's default, which is buggy but better than
+ " nothing)
+ call cursor(a:lnum, a:last_closed_bracket)
+ let percmap = maparg("%", "n")
+ if exists("g:loaded_matchit") && percmap =~# 'Match\%(it\|_wrapper\)'
+ normal %
+ else
+ normal! %
+ end
+endfunction
+
+" Auxiliary function to find a line which does not start in the middle of a
+" multiline bracketed expression, to be used as reference for block
+" indentation.
+function LastBlockIndent(lnum)
+ let lnum = a:lnum
+ let ind = 0
+ while lnum > 0
+ let ind = indent(lnum)
+ if ind == 0
+ return [lnum, 0]
+ endif
+ if !IsInBrackets(lnum, 1)
+ break
+ endif
+ let lnum = prevnonblank(lnum - 1)
+ endwhile
+ return [max([lnum,1]), ind]
+endfunction
+
+function GetJuliaIndent()
+ " Do not alter doctrings indentation
+ if IsInDocString(v:lnum)
+ return -1
+ endif
+
+ " Find a non-blank line above the current line.
+ let lnum = prevnonblank(v:lnum - 1)
+
+ " At the start of the file use zero indent.
+ if lnum == 0
+ return 0
+ endif
+
+ let ind = -1
+ let st = -1
+ let lim = -1
+
+ " Multiline bracketed expressions take precedence
+ let align_brackets = get(g:, "julia_indent_align_brackets", 1)
+ let align_funcargs = get(g:, "julia_indent_align_funcargs", 0)
+ let c = len(getline(lnum)) + 1
+ while IsInBrackets(lnum, c)
+ let [first_open_bracket, last_open_bracket, last_closed_bracket, infuncargs] = GetJuliaNestingBrackets(lnum, c)
+
+ " First scenario: the previous line has a hanging open bracket:
+ " set the indentation to match the opening bracket (plus an extra space)
+ " unless we're in a function arguments list or alignment is disabled, in
+ " which case we just add an extra indent
+ if last_open_bracket != -1
+ if (!infuncargs && align_brackets) || (infuncargs && align_funcargs)
+ let st = last_open_bracket
+ let ind = virtcol([lnum, st + 1])
+ else
+ let ind = indent(lnum) + shiftwidth()
+ endif
+
+ " Second scenario: some multiline bracketed expression was closed in the
+ " previous line. But since we know we are still in a bracketed expression,
+ " we need to find the line where the bracket was opened
+ elseif last_closed_bracket != -1
+ call JumpToMatch(lnum, last_closed_bracket)
+ if line(".") == lnum
+ " something wrong here, give up
+ let ind = indent(lnum)
+ else
+ let lnum = line(".")
+ let c = col(".") - 1
+ if c == 0
+ " uhm, give up
+ let ind = 0
+ else
+ " we skipped a bracket set, keep searching for an opening bracket
+ let lim = c
+ continue
+ endif
+ endif
+
+ " Third scenario: nothing special: keep the indentation
+ else
+ let ind = indent(lnum)
+ endif
+
+ " Does the current line start with a closing bracket? Then depending on
+ " the situation we align it with the opening one, or we let the rest of
+ " the code figure it out (the case in which we're closing a function
+ " argument list is special-cased)
+ if JuliaMatch(v:lnum, getline(v:lnum), '[])}]', indent(v:lnum)) == indent(v:lnum) && ind > 0
+ if !align_brackets && !align_funcargs
+ call JumpToMatch(v:lnum, indent(v:lnum))
+ return indent(line("."))
+ elseif (align_brackets && getline(v:lnum)[indent(v:lnum)] != ')') || align_funcargs
+ return ind - 1
+ else " must be a ')' and align_brackets==1 and align_funcargs==0
+ call JumpToMatch(v:lnum, indent(v:lnum))
+ if IsFunctionArgPar(line("."), col("."))
+ let ind = -1
+ else
+ return ind - 1
+ endif
+ endif
+ endif
+
+ break
+ endwhile
+
+ if ind == -1
+ " We are not in a multiline bracketed expression. Thus we look for a
+ " previous line to use as a reference
+ let [lnum,ind] = LastBlockIndent(lnum)
+ let c = len(getline(lnum)) + 1
+ if IsInBrackets(lnum, c)
+ let [first_open_bracket, last_open_bracket, last_closed_bracket, infuncargs] = GetJuliaNestingBrackets(lnum, c)
+ let lim = first_open_bracket
+ endif
+ end
+
+ " Analyse the reference line
+ let [num_open_blocks, num_closed_blocks] = GetJuliaNestingStruct(lnum, st, lim)
+ " Increase indentation for each newly opened block in the reference line
+ let ind += shiftwidth() * num_open_blocks
+
+ " Analyse the current line
+ let [num_open_blocks, num_closed_blocks] = GetJuliaNestingStruct(v:lnum)
+ " Decrease indentation for each closed block in the current line
+ let ind -= shiftwidth() * num_closed_blocks
+
+ " Additional special case: multiline import/using/export statements
+
+ let prevline = getline(lnum)
+ " Are we in a multiline import/using/export statement, right below the
+ " opening line?
+ if IsInContinuationImportLine(v:lnum) && !IsInContinuationImportLine(lnum)
+ if get(g:, 'julia_indent_align_import', 1)
+ " if the opening line has a colon followed by non-comments, use it as
+ " reference point
+ let cind = JuliaMatch(lnum, prevline, ':', indent(lnum), lim)
+ if cind >= 0
+ let nonwhiteind = JuliaMatch(lnum, prevline, '\S', cind+1, -1, 'basic')
+ if nonwhiteind >= 0
+ " return match(prevline, '\S', cind+1) " a bit overkill...
+ return cind + 2
+ endif
+ else
+ " if the opening line is not a naked import/using/export statement, use
+ " it as reference
+ let iind = JuliaMatch(lnum, prevline, '\<import\|using\|export\>', indent(lnum), lim)
+ if iind >= 0
+ " assuming whitespace after using... so no `using(XYZ)` please!
+ let nonwhiteind = JuliaMatch(lnum, prevline, '\S', iind+6, -1, 'basic')
+ if nonwhiteind >= 0
+ return match(prevline, '\S', iind+6)
+ endif
+ endif
+ endif
+ endif
+ let ind += shiftwidth()
+
+ " Or did we just close a multiline import/using/export statement?
+ elseif !IsInContinuationImportLine(v:lnum) && IsInContinuationImportLine(lnum)
+ " find the starting line of the statement
+ let ilnum = 0
+ for iln in range(lnum-1, 1, -1)
+ if !IsInContinuationImportLine(iln)
+ let ilnum = iln
+ break
+ endif
+ endfor
+ if ilnum == 0
+ " something went horribly wrong, give up
+ let ind = indent(lnum)
+ endif
+ let ind = indent(ilnum)
+ endif
+
+ return ind
+endfunction
diff --git a/runtime/indent/lifelines.vim b/runtime/indent/lifelines.vim
index 0d9b2b46e4..e6d61617dc 100644
--- a/runtime/indent/lifelines.vim
+++ b/runtime/indent/lifelines.vim
@@ -11,7 +11,7 @@ endif
let b:did_indent = 1
" LifeLines uses cindent without ; line terminator, C functions
-" declarations, C keywords, C++ formating
+" declarations, C keywords, C++ formatting
setlocal cindent
setlocal cinwords=""
setlocal cinoptions+=+0
diff --git a/runtime/indent/objc.vim b/runtime/indent/objc.vim
index beadca9fa4..a5451a5a11 100644
--- a/runtime/indent/objc.vim
+++ b/runtime/indent/objc.vim
@@ -15,7 +15,7 @@ setlocal cindent
" Set the function to do the work.
setlocal indentexpr=GetObjCIndent()
-" To make a colon (:) suggest an indentation other than a goto/swich label,
+" To make a colon (:) suggest an indentation other than a goto/switch label,
setlocal indentkeys-=:
setlocal indentkeys+=<:>
diff --git a/runtime/indent/pascal.vim b/runtime/indent/pascal.vim
index c7955d669b..1f39fd1cad 100644
--- a/runtime/indent/pascal.vim
+++ b/runtime/indent/pascal.vim
@@ -2,7 +2,7 @@
" Language: Pascal
" Maintainer: Neil Carter <n.carter@swansea.ac.uk>
" Created: 2004 Jul 13
-" Last Change: 2017 Jun 13
+" Last Change: 2021 Jul 01
"
" This is version 2.0, a complete rewrite.
"
@@ -20,6 +20,8 @@ setlocal indentkeys+==end;,==const,==type,==var,==begin,==repeat,==until,==for
setlocal indentkeys+==program,==function,==procedure,==object,==private
setlocal indentkeys+==record,==if,==else,==case
+let b:undo_indent = "setl indentkeys< indentexpr<"
+
if exists("*GetPascalIndent")
finish
endif
diff --git a/runtime/indent/pov.vim b/runtime/indent/pov.vim
index e806756c8e..f74c96b7f7 100644
--- a/runtime/indent/pov.vim
+++ b/runtime/indent/pov.vim
@@ -44,7 +44,7 @@ function GetPoVRayIndent()
return -1
endif
- " Search backwards for the frist non-empty, non-comment line.
+ " Search backwards for the first non-empty, non-comment line.
let plnum = prevnonblank(v:lnum - 1)
let plind = indent(plnum)
while plnum > 0 && synIDattr(synID(plnum, plind+1, 0), "name") =~? "comment"
diff --git a/runtime/indent/python.vim b/runtime/indent/python.vim
index f9236e63c7..307b7f656b 100644
--- a/runtime/indent/python.vim
+++ b/runtime/indent/python.vim
@@ -2,7 +2,7 @@
" Language: Python
" Maintainer: Bram Moolenaar <Bram@vim.org>
" Original Author: David Bustos <bustos@caltech.edu>
-" Last Change: 2019 Feb 21
+" Last Change: 2021 May 26
" Only load this indent file when no other was loaded.
if exists("b:did_indent")
@@ -191,7 +191,7 @@ function GetPythonIndent(lnum)
if getline(a:lnum) =~ '^\s*\(elif\|else\)\>'
" Unless the previous line was a one-liner
- if getline(plnumstart) =~ '^\s*\(for\|if\|try\)\>'
+ if getline(plnumstart) =~ '^\s*\(for\|if\|elif\|try\)\>'
return plindent
endif
diff --git a/runtime/indent/ruby.vim b/runtime/indent/ruby.vim
index 657aa763b1..559d8652a6 100644
--- a/runtime/indent/ruby.vim
+++ b/runtime/indent/ruby.vim
@@ -4,6 +4,7 @@
" Previous Maintainer: Nikolai Weibull <now at bitwi.se>
" URL: https://github.com/vim-ruby/vim-ruby
" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
+" Last Change: 2021 Feb 03
" 0. Initialization {{{1
" =================
@@ -264,7 +265,7 @@ function! GetRubyIndent(...) abort
\ ]
" Most Significant line based on the previous one -- in case it's a
- " contination of something above
+ " continuation of something above
let indent_info.plnum_msl = s:GetMSL(indent_info.plnum)
for callback_name in indent_callback_names
diff --git a/runtime/indent/scala.vim b/runtime/indent/scala.vim
index 6fd8ca9d81..b5eba29543 100644
--- a/runtime/indent/scala.vim
+++ b/runtime/indent/scala.vim
@@ -20,7 +20,10 @@ endif
let s:keepcpo= &cpo
set cpo&vim
-let s:defMatcher = '\%(\%(private\|protected\)\%(\[[^\]]*\]\)\?\s\+\|abstract\s\+\|override\s\+\)*\<def\>'
+let s:annotationMatcher = '@[A-Za-z._]\+\s\+'
+let s:modifierMatcher = s:annotationMatcher . '\|\%(private\|protected\)\%(\[[^\]]*\]\)\?\s\+\|abstract\s\+\|override\s\+\|final\s\+'
+let s:defMatcher = '\%(' . s:modifierMatcher . '\)*\<def\>'
+let s:valMatcher = '\%(' . s:modifierMatcher . '\|lazy\s\+\)*\<va[lr]\>'
let s:funcNameMatcher = '\w\+'
let s:typeSpecMatcher = '\%(\s*\[\_[^\]]*\]\)'
let s:defArgMatcher = '\%((\_.\{-})\)'
@@ -184,7 +187,7 @@ function! scala#NumberOfBraceGroups(line)
endfunction
function! scala#MatchesIncompleteDefValr(line)
- if a:line =~ '^\s*\%(' . s:defMatcher . '\|\<va[lr]\>\).*[=({]\s*$'
+ if a:line =~ '^\s*\%(' . s:defMatcher . '\|' . s:valMatcher . '\).*[=({]\s*$'
return 1
else
return 0
@@ -434,7 +437,7 @@ function! GetScalaIndent()
" If 'val', 'var', 'def' end with =, this is a one-line block
if (prevline =~ '^\s*\<\%(\%(}\?\s*else\s\+\)\?if\|for\|while\)\>.*[)=]\s*$' && scala#NumberOfBraceGroups(prevline) <= 1)
\ || prevline =~ '^\s*' . s:defMatcher . '.*=\s*$'
- \ || prevline =~ '^\s*\<va[lr]\>.*[=]\s*$'
+ \ || prevline =~ '^\s*' . s:valMatcher . '.*[=]\s*$'
\ || prevline =~ '^\s*\%(}\s*\)\?\<else\>\s*$'
\ || prevline =~ '=\s*$'
call scala#ConditionalConfirm("4")
diff --git a/runtime/indent/sqlanywhere.vim b/runtime/indent/sqlanywhere.vim
index 601c567adc..d39fa3240e 100644
--- a/runtime/indent/sqlanywhere.vim
+++ b/runtime/indent/sqlanywhere.vim
@@ -9,7 +9,7 @@
" Notes:
" Indenting keywords are based on Oracle and Sybase Adaptive Server
" Anywhere (ASA). Test indenting was done with ASA stored procedures and
-" fuctions and Oracle packages which contain stored procedures and
+" functions and Oracle packages which contain stored procedures and
" functions.
" This has not been tested against Microsoft SQL Server or
" Sybase Adaptive Server Enterprise (ASE) which use the Transact-SQL
diff --git a/runtime/indent/systemverilog.vim b/runtime/indent/systemverilog.vim
index 590fd4d998..16fb4515c5 100644
--- a/runtime/indent/systemverilog.vim
+++ b/runtime/indent/systemverilog.vim
@@ -64,7 +64,7 @@ function SystemVerilogIndent()
let vverb = 0
endif
- " Indent accoding to last line
+ " Indent according to last line
" End of multiple-line comment
if last_line =~ '\*/\s*$' && last_line !~ '/\*.\{-}\*/'
let ind = ind - offset_comment1
@@ -220,7 +220,7 @@ function SystemVerilogIndent()
endif
- " Return the indention
+ " Return the indentation
return ind
endfunction
diff --git a/runtime/indent/testdir/xml.in b/runtime/indent/testdir/xml.in
index b6333340e2..88ad51e484 100644
--- a/runtime/indent/testdir/xml.in
+++ b/runtime/indent/testdir/xml.in
@@ -15,7 +15,7 @@ text comment
</tag1>
<!--
text comment
-end coment -->
+end comment -->
</tag0>
<!-- END_INDENT -->
diff --git a/runtime/indent/testdir/xml.ok b/runtime/indent/testdir/xml.ok
index cfdf701c11..d5e2289cb3 100644
--- a/runtime/indent/testdir/xml.ok
+++ b/runtime/indent/testdir/xml.ok
@@ -15,7 +15,7 @@
</tag1>
<!--
text comment
- end coment -->
+ end comment -->
</tag0>
<!-- END_INDENT -->
diff --git a/runtime/indent/tex.vim b/runtime/indent/tex.vim
index 8a44ade1ac..d356ba905b 100644
--- a/runtime/indent/tex.vim
+++ b/runtime/indent/tex.vim
@@ -288,7 +288,7 @@ function! GetTeXIndent() " {{{
let ind = ind - shiftwidth()
let stay = 0
endif
- " lines following to '\item' are intented once again:
+ " lines following to '\item' are indented once again:
if line =~ g:tex_items
let ind = ind + shiftwidth()
let stay = 0
diff --git a/runtime/indent/treetop.vim b/runtime/indent/treetop.vim
index 2c6eecf5c4..42ec1c8ad9 100644
--- a/runtime/indent/treetop.vim
+++ b/runtime/indent/treetop.vim
@@ -34,5 +34,5 @@ function GetTreetopIndent()
let ind -= shiftwidth()
end
- retur ind
+ return ind
endfunction
diff --git a/runtime/indent/typescript.vim b/runtime/indent/typescript.vim
index b6b2cb5acf..e899f83d0f 100644
--- a/runtime/indent/typescript.vim
+++ b/runtime/indent/typescript.vim
@@ -460,7 +460,7 @@ function! Fixedgq(lnum, count)
return 1
endif
- " Put all the lines on one line and do normal spliting after that
+ " Put all the lines on one line and do normal splitting after that
if l:count > 1
while l:count > 1
let l:count -= 1
diff --git a/runtime/indent/verilog.vim b/runtime/indent/verilog.vim
index ab3d0ba3e0..e81197c3b4 100644
--- a/runtime/indent/verilog.vim
+++ b/runtime/indent/verilog.vim
@@ -76,7 +76,7 @@ function GetVerilogIndent()
let vverb = 0
endif
- " Indent accoding to last line
+ " Indent according to last line
" End of multiple-line comment
if last_line =~ '\*/\s*$' && last_line !~ '/\*.\{-}\*/'
let ind = ind - offset_comment1
@@ -219,7 +219,7 @@ function GetVerilogIndent()
endif
- " Return the indention
+ " Return the indentation
return ind
endfunction
diff --git a/runtime/indent/yaml.vim b/runtime/indent/yaml.vim
index 8dca5cd763..ed57e68d8b 100644
--- a/runtime/indent/yaml.vim
+++ b/runtime/indent/yaml.vim
@@ -2,7 +2,7 @@
" Language: YAML
" Maintainer: Nikolai Pavlov <zyx.vim@gmail.com>
" Last Update: Lukas Reineke
-" Last Change: 2021 Jan 19
+" Last Change: 2021 Aug 13
" Only load this indent file when no other was loaded.
if exists('b:did_indent')
diff --git a/runtime/keymap/kana.vim b/runtime/keymap/kana.vim
index 23b5f876ac..9aff4eba41 100644
--- a/runtime/keymap/kana.vim
+++ b/runtime/keymap/kana.vim
@@ -364,7 +364,7 @@ ppu っぷ
ppe っぺ
ppo っぽ
-" Proceded by a small `tu' and followed by a small 'ya', 'yu' or 'yo'
+" Preceded by a small `tu' and followed by a small 'ya', 'yu' or 'yo'
kkya っきゃ
kkyu っきゅ
kkyo っきょ
@@ -683,7 +683,7 @@ PPU ップ
PPE ッペ
PPO ッポ
-" Proceded by a small `tu' and followed by a small 'ya', 'yu' or 'yo'
+" Preceded by a small `tu' and followed by a small 'ya', 'yu' or 'yo'
KKYA ッキャ
KKYU ッキュ
KKYO ッキョ
diff --git a/runtime/keymap/korean.vim b/runtime/keymap/korean.vim
index 044e3b9918..64ae519320 100644
--- a/runtime/keymap/korean.vim
+++ b/runtime/keymap/korean.vim
@@ -10,7 +10,7 @@
" BUT, simply mapping each letter of Hangul with sequence of alphabet 1 by 1
" can fail to combine Hangul jamo (conconants and vowels) right.
" For example, sequentially pressing `ㅅㅓㅇㅜㄹㄷㅐㅎㅏㄱㅛ` can not only be
-" combined as `서울대학교`, but alse `성ㅜㄹ댛ㅏㄱ교`, which is totally
+" combined as `서울대학교`, but also `성ㅜㄹ댛ㅏㄱ교`, which is totally
" nonsense.
" Though combining Hangul is deterministic with law that each letter must be
" one of (consonant + vowel) or (consonant + vowel + consonant), there is no
diff --git a/runtime/keymap/russian-jcukenwintype.vim b/runtime/keymap/russian-jcukenwintype.vim
index 25d6286e24..2d5856ad0c 100644
--- a/runtime/keymap/russian-jcukenwintype.vim
+++ b/runtime/keymap/russian-jcukenwintype.vim
@@ -4,7 +4,7 @@
" Useful mainly with utf-8 but may work with other encodings
" Derived from russian-jcuken.vim by Artem Chuprina <ran@ran.pp.ru>
-" Typewriter variant of standart russian layout
+" Typewriter variant of standard russian layout
" Maintainer: Denis Proskurin <danwerspb@gmail.com>
" Last Changed: 2015 May 15
diff --git a/runtime/keymap/russian-typograph.vim b/runtime/keymap/russian-typograph.vim
index a85e861e32..e0fbf22884 100644
--- a/runtime/keymap/russian-typograph.vim
+++ b/runtime/keymap/russian-typograph.vim
@@ -106,7 +106,7 @@ loadkeymap
<char-0x005d> <char-0x044a> " CYRILLIC SMALL LETTER HARD SIGN
<char-0x007d> <char-0x042a> " CYRILLIC CAPITAL LETTER HARD SIGN
-" ALPHABETIC 2st ROW
+" ALPHABETIC 2nd ROW
<char-0x0061> <char-0x0444> " CYRILLIC SMALL LETTER EF
<char-0x0041> <char-0x0424> " CYRILLIC CAPITAL LETTER EF
@@ -131,7 +131,7 @@ loadkeymap
<char-0x0027> <char-0x044d> " CYRILLIC SMALL LETTER E
<char-0x0022> <char-0x042d> " CYRILLIC CAPITAL LETTER E
-" ALPHABETIC 3st ROW
+" ALPHABETIC 3rd ROW
<char-0x007a> <char-0x044f> " CYRILLIC SMALL LETTER YA
<char-0x005a> <char-0x042f> " CYRILLIC CAPITAL LETTER YA
diff --git a/runtime/lua/vim/F.lua b/runtime/lua/vim/F.lua
index 7925ff6e44..1a258546a5 100644
--- a/runtime/lua/vim/F.lua
+++ b/runtime/lua/vim/F.lua
@@ -2,8 +2,8 @@ local F = {}
--- Returns {a} if it is not nil, otherwise returns {b}.
---
---@param a
---@param b
+---@param a
+---@param b
function F.if_nil(a, b)
if a == nil then return b end
return a
@@ -27,5 +27,14 @@ function F.nil_wrap(fn)
end
end
+--- like {...} except preserve the lenght explicitly
+function F.pack_len(...)
+ return {n=select('#', ...), ...}
+end
+
+--- like unpack() but use the length set by F.pack_len if present
+function F.unpack_len(t)
+ return unpack(t, 1, t.n)
+end
return F
diff --git a/runtime/lua/vim/_meta.lua b/runtime/lua/vim/_meta.lua
index b1f935541c..f7d47c1030 100644
--- a/runtime/lua/vim/_meta.lua
+++ b/runtime/lua/vim/_meta.lua
@@ -494,7 +494,6 @@ local convert_value_to_lua = (function()
for _, key_value_str in ipairs(comma_split) do
local key, value = unpack(vim.split(key_value_str, ":"))
key = vim.trim(key)
- value = vim.trim(value)
result[key] = value
end
diff --git a/runtime/lua/vim/diagnostic.lua b/runtime/lua/vim/diagnostic.lua
new file mode 100644
index 0000000000..00945a7fb3
--- /dev/null
+++ b/runtime/lua/vim/diagnostic.lua
@@ -0,0 +1,1381 @@
+local M = {}
+
+M.severity = {
+ ERROR = 1,
+ WARN = 2,
+ INFO = 3,
+ HINT = 4,
+}
+
+vim.tbl_add_reverse_lookup(M.severity)
+
+-- Mappings from qflist/loclist error types to severities
+M.severity.E = M.severity.ERROR
+M.severity.W = M.severity.WARN
+M.severity.I = M.severity.INFO
+M.severity.N = M.severity.HINT
+
+local global_diagnostic_options = {
+ signs = true,
+ underline = true,
+ virtual_text = true,
+ update_in_insert = false,
+ severity_sort = false,
+}
+
+-- Local functions {{{
+
+---@private
+local function to_severity(severity)
+ return type(severity) == 'string' and M.severity[string.upper(severity)] or severity
+end
+
+---@private
+local function filter_by_severity(severity, diagnostics)
+ if not severity then
+ return diagnostics
+ end
+
+ if type(severity) ~= "table" then
+ severity = to_severity(severity)
+ return vim.tbl_filter(function(t) return t.severity == severity end, diagnostics)
+ end
+
+ local min_severity = to_severity(severity.min) or M.severity.HINT
+ local max_severity = to_severity(severity.max) or M.severity.ERROR
+
+ return vim.tbl_filter(function(t) return t.severity <= min_severity and t.severity >= max_severity end, diagnostics)
+end
+
+---@private
+local function prefix_source(source, diagnostics)
+ vim.validate { source = {source, function(v)
+ return v == "always" or v == "if_many"
+ end, "Invalid value for option 'source'" } }
+
+ if source == "if_many" then
+ local sources = {}
+ for _, d in pairs(diagnostics) do
+ if d.source then
+ sources[d.source] = true
+ end
+ end
+ if #vim.tbl_keys(sources) <= 1 then
+ return diagnostics
+ end
+ end
+
+ return vim.tbl_map(function(d)
+ if not d.source then
+ return d
+ end
+
+ local t = vim.deepcopy(d)
+ t.message = string.format("%s: %s", d.source, d.message)
+ return t
+ end, diagnostics)
+end
+
+---@private
+local function reformat_diagnostics(format, diagnostics)
+ vim.validate {
+ format = {format, 'f'},
+ diagnostics = {diagnostics, 't'},
+ }
+
+ local formatted = vim.deepcopy(diagnostics)
+ for _, diagnostic in ipairs(formatted) do
+ diagnostic.message = format(diagnostic)
+ end
+ return formatted
+end
+
+---@private
+local function resolve_optional_value(option, namespace, bufnr)
+ local enabled_val = {}
+
+ if not option then
+ return false
+ elseif option == true then
+ return enabled_val
+ elseif type(option) == 'function' then
+ local val = option(namespace, bufnr)
+ if val == true then
+ return enabled_val
+ else
+ return val
+ end
+ elseif type(option) == 'table' then
+ return option
+ else
+ error("Unexpected option type: " .. vim.inspect(option))
+ end
+end
+
+local all_namespaces = {}
+
+---@private
+local function get_namespace(ns)
+ if not all_namespaces[ns] then
+ local name
+ for k, v in pairs(vim.api.nvim_get_namespaces()) do
+ if ns == v then
+ name = k
+ break
+ end
+ end
+
+ if not name then
+ return vim.notify("namespace does not exist or is anonymous", vim.log.levels.ERROR)
+ end
+
+ all_namespaces[ns] = {
+ name = name,
+ sign_group = string.format("vim.diagnostic.%s", name),
+ opts = {}
+ }
+ end
+ return all_namespaces[ns]
+end
+
+---@private
+local function get_resolved_options(opts, namespace, bufnr)
+ local ns = get_namespace(namespace)
+ local resolved = vim.tbl_extend('keep', opts or {}, ns.opts, global_diagnostic_options)
+ for k in pairs(global_diagnostic_options) do
+ if resolved[k] ~= nil then
+ resolved[k] = resolve_optional_value(resolved[k], namespace, bufnr)
+ end
+ end
+ return resolved
+end
+
+-- Default diagnostic highlights
+local diagnostic_severities = {
+ [M.severity.ERROR] = { ctermfg = 1, guifg = "Red" };
+ [M.severity.WARN] = { ctermfg = 3, guifg = "Orange" };
+ [M.severity.INFO] = { ctermfg = 4, guifg = "LightBlue" };
+ [M.severity.HINT] = { ctermfg = 7, guifg = "LightGrey" };
+}
+
+-- Make a map from DiagnosticSeverity -> Highlight Name
+---@private
+local function make_highlight_map(base_name)
+ local result = {}
+ for k in pairs(diagnostic_severities) do
+ local name = M.severity[k]
+ name = name:sub(1, 1) .. name:sub(2):lower()
+ result[k] = "Diagnostic" .. base_name .. name
+ end
+
+ return result
+end
+
+local virtual_text_highlight_map = make_highlight_map("VirtualText")
+local underline_highlight_map = make_highlight_map("Underline")
+local floating_highlight_map = make_highlight_map("Floating")
+local sign_highlight_map = make_highlight_map("Sign")
+
+---@private
+local define_default_signs = (function()
+ local signs_defined = false
+ return function()
+ if signs_defined then
+ return
+ end
+
+ for severity, sign_hl_name in pairs(sign_highlight_map) do
+ if vim.tbl_isempty(vim.fn.sign_getdefined(sign_hl_name)) then
+ local severity_name = M.severity[severity]
+ vim.fn.sign_define(sign_hl_name, {
+ text = (severity_name or 'U'):sub(1, 1),
+ texthl = sign_hl_name,
+ linehl = '',
+ numhl = '',
+ })
+ end
+ end
+
+ signs_defined = true
+ end
+end)()
+
+---@private
+local function get_bufnr(bufnr)
+ if not bufnr or bufnr == 0 then
+ return vim.api.nvim_get_current_buf()
+ end
+ return bufnr
+end
+
+-- Metatable that automatically creates an empty table when assigning to a missing key
+local bufnr_and_namespace_cacher_mt = {
+ __index = function(t, bufnr)
+ if not bufnr or bufnr == 0 then
+ bufnr = vim.api.nvim_get_current_buf()
+ end
+
+ if rawget(t, bufnr) == nil then
+ rawset(t, bufnr, {})
+ end
+
+ return rawget(t, bufnr)
+ end,
+
+ __newindex = function(t, bufnr, v)
+ if not bufnr or bufnr == 0 then
+ bufnr = vim.api.nvim_get_current_buf()
+ end
+
+ rawset(t, bufnr, v)
+ end,
+}
+
+local diagnostic_cleanup = setmetatable({}, bufnr_and_namespace_cacher_mt)
+local diagnostic_cache = setmetatable({}, bufnr_and_namespace_cacher_mt)
+local diagnostic_cache_extmarks = setmetatable({}, bufnr_and_namespace_cacher_mt)
+local diagnostic_attached_buffers = {}
+local diagnostic_disabled = {}
+local bufs_waiting_to_update = setmetatable({}, bufnr_and_namespace_cacher_mt)
+
+---@private
+local function is_disabled(namespace, bufnr)
+ if type(diagnostic_disabled[bufnr]) == "table" then
+ return diagnostic_disabled[bufnr][namespace]
+ end
+ return diagnostic_disabled[bufnr]
+end
+
+---@private
+local function diagnostic_lines(diagnostics)
+ if not diagnostics then
+ return {}
+ end
+
+ local diagnostics_by_line = {}
+ for _, diagnostic in ipairs(diagnostics) do
+ local line_diagnostics = diagnostics_by_line[diagnostic.lnum]
+ if not line_diagnostics then
+ line_diagnostics = {}
+ diagnostics_by_line[diagnostic.lnum] = line_diagnostics
+ end
+ table.insert(line_diagnostics, diagnostic)
+ end
+ return diagnostics_by_line
+end
+
+---@private
+local function set_diagnostic_cache(namespace, bufnr, diagnostics)
+ for _, diagnostic in ipairs(diagnostics) do
+ diagnostic.severity = diagnostic.severity and to_severity(diagnostic.severity) or M.severity.ERROR
+ diagnostic.end_lnum = diagnostic.end_lnum or diagnostic.lnum
+ diagnostic.end_col = diagnostic.end_col or diagnostic.col
+ diagnostic.namespace = namespace
+ diagnostic.bufnr = bufnr
+ end
+ diagnostic_cache[bufnr][namespace] = diagnostics
+end
+
+---@private
+local function clear_diagnostic_cache(namespace, bufnr)
+ diagnostic_cache[bufnr][namespace] = nil
+end
+
+---@private
+local function restore_extmarks(bufnr, last)
+ for ns, extmarks in pairs(diagnostic_cache_extmarks[bufnr]) do
+ local extmarks_current = vim.api.nvim_buf_get_extmarks(bufnr, ns, 0, -1, {details = true})
+ local found = {}
+ for _, extmark in ipairs(extmarks_current) do
+ -- nvim_buf_set_lines will move any extmark to the line after the last
+ -- nvim_buf_set_text will move any extmark to the last line
+ if extmark[2] ~= last + 1 then
+ found[extmark[1]] = true
+ end
+ end
+ for _, extmark in ipairs(extmarks) do
+ if not found[extmark[1]] then
+ local opts = extmark[4]
+ opts.id = extmark[1]
+ -- HACK: end_row should be end_line
+ if opts.end_row then
+ opts.end_line = opts.end_row
+ opts.end_row = nil
+ end
+ pcall(vim.api.nvim_buf_set_extmark, bufnr, ns, extmark[2], extmark[3], opts)
+ end
+ end
+ end
+end
+
+---@private
+local function save_extmarks(namespace, bufnr)
+ bufnr = bufnr == 0 and vim.api.nvim_get_current_buf() or bufnr
+ if not diagnostic_attached_buffers[bufnr] then
+ vim.api.nvim_buf_attach(bufnr, false, {
+ on_lines = function(_, _, _, _, _, last)
+ restore_extmarks(bufnr, last - 1)
+ end,
+ on_detach = function()
+ diagnostic_cache_extmarks[bufnr] = nil
+ end})
+ diagnostic_attached_buffers[bufnr] = true
+ end
+ diagnostic_cache_extmarks[bufnr][namespace] = vim.api.nvim_buf_get_extmarks(bufnr, namespace, 0, -1, {details = true})
+end
+
+local registered_autocmds = {}
+
+---@private
+local function make_augroup_key(namespace, bufnr)
+ local ns = get_namespace(namespace)
+ return string.format("DiagnosticInsertLeave:%s:%s", bufnr, ns.name)
+end
+
+--- Table of autocmd events to fire the update for displaying new diagnostic information
+local insert_leave_auto_cmds = { "InsertLeave", "CursorHoldI" }
+
+---@private
+local function schedule_display(namespace, bufnr, args)
+ bufs_waiting_to_update[bufnr][namespace] = args
+
+ local key = make_augroup_key(namespace, bufnr)
+ if not registered_autocmds[key] then
+ vim.cmd(string.format("augroup %s", key))
+ vim.cmd(" au!")
+ vim.cmd(
+ string.format(
+ [[autocmd %s <buffer=%s> lua vim.diagnostic._execute_scheduled_display(%s, %s)]],
+ table.concat(insert_leave_auto_cmds, ","),
+ bufnr,
+ namespace,
+ bufnr
+ )
+ )
+ vim.cmd("augroup END")
+
+ registered_autocmds[key] = true
+ end
+end
+
+---@private
+local function clear_scheduled_display(namespace, bufnr)
+ local key = make_augroup_key(namespace, bufnr)
+
+ if registered_autocmds[key] then
+ vim.cmd(string.format("augroup %s", key))
+ vim.cmd(" au!")
+ vim.cmd("augroup END")
+
+ registered_autocmds[key] = nil
+ end
+end
+
+---@private
+--- Open a floating window with the provided diagnostics
+---@param opts table Configuration table
+--- - show_header (boolean, default true): Show "Diagnostics:" header
+--- - all opts for |vim.util.open_floating_preview()| can be used here
+---@param diagnostics table: The diagnostics to display
+---@return table {popup_bufnr, win_id}
+local function show_diagnostics(opts, diagnostics)
+ if not diagnostics or vim.tbl_isempty(diagnostics) then
+ return
+ end
+ local lines = {}
+ local highlights = {}
+ local show_header = vim.F.if_nil(opts.show_header, true)
+ if show_header then
+ table.insert(lines, "Diagnostics:")
+ table.insert(highlights, {0, "Bold"})
+ end
+
+ if opts.format then
+ diagnostics = reformat_diagnostics(opts.format, diagnostics)
+ end
+
+ if opts.source then
+ diagnostics = prefix_source(opts.source, diagnostics)
+ end
+
+ for i, diagnostic in ipairs(diagnostics) do
+ local prefix = string.format("%d. ", i)
+ local hiname = floating_highlight_map[diagnostic.severity]
+ assert(hiname, 'unknown severity: ' .. tostring(diagnostic.severity))
+
+ local message_lines = vim.split(diagnostic.message, '\n', true)
+ table.insert(lines, prefix..message_lines[1])
+ table.insert(highlights, {#prefix, hiname})
+ for j = 2, #message_lines do
+ table.insert(lines, string.rep(' ', #prefix) .. message_lines[j])
+ table.insert(highlights, {0, hiname})
+ end
+ end
+
+ local popup_bufnr, winnr = require('vim.lsp.util').open_floating_preview(lines, 'plaintext', opts)
+ for i, hi in ipairs(highlights) do
+ local prefixlen, hiname = unpack(hi)
+ -- Start highlight after the prefix
+ vim.api.nvim_buf_add_highlight(popup_bufnr, -1, hiname, i-1, prefixlen, -1)
+ end
+
+ return popup_bufnr, winnr
+end
+
+---@private
+local function set_list(loclist, opts)
+ opts = opts or {}
+ local open = vim.F.if_nil(opts.open, true)
+ local title = opts.title or "Diagnostics"
+ local winnr = opts.winnr or 0
+ local bufnr
+ if loclist then
+ bufnr = vim.api.nvim_win_get_buf(winnr)
+ end
+ local diagnostics = M.get(bufnr, opts)
+ local items = M.toqflist(diagnostics)
+ if loclist then
+ vim.fn.setloclist(winnr, {}, ' ', { title = title, items = items })
+ else
+ vim.fn.setqflist({}, ' ', { title = title, items = items })
+ end
+ if open then
+ vim.api.nvim_command(loclist and "lopen" or "copen")
+ end
+end
+
+---@private
+local function clamp_line_numbers(bufnr, diagnostics)
+ local buf_line_count = vim.api.nvim_buf_line_count(bufnr)
+ if buf_line_count == 0 then
+ return
+ end
+
+ for _, diagnostic in ipairs(diagnostics) do
+ diagnostic.lnum = math.max(math.min(diagnostic.lnum, buf_line_count - 1), 0)
+ diagnostic.end_lnum = math.max(math.min(diagnostic.end_lnum, buf_line_count - 1), 0)
+ end
+end
+
+---@private
+local function next_diagnostic(position, search_forward, bufnr, opts, namespace)
+ position[1] = position[1] - 1
+ bufnr = get_bufnr(bufnr)
+ local wrap = vim.F.if_nil(opts.wrap, true)
+ local line_count = vim.api.nvim_buf_line_count(bufnr)
+ local diagnostics = M.get(bufnr, vim.tbl_extend("keep", opts, {namespace = namespace}))
+ clamp_line_numbers(bufnr, diagnostics)
+ local line_diagnostics = diagnostic_lines(diagnostics)
+ for i = 0, line_count do
+ local offset = i * (search_forward and 1 or -1)
+ local lnum = position[1] + offset
+ if lnum < 0 or lnum >= line_count then
+ if not wrap then
+ return
+ end
+ lnum = (lnum + line_count) % line_count
+ end
+ if line_diagnostics[lnum] and not vim.tbl_isempty(line_diagnostics[lnum]) then
+ local sort_diagnostics, is_next
+ if search_forward then
+ sort_diagnostics = function(a, b) return a.col < b.col end
+ is_next = function(diagnostic) return diagnostic.col > position[2] end
+ else
+ sort_diagnostics = function(a, b) return a.col > b.col end
+ is_next = function(diagnostic) return diagnostic.col < position[2] end
+ end
+ table.sort(line_diagnostics[lnum], sort_diagnostics)
+ if i == 0 then
+ for _, v in pairs(line_diagnostics[lnum]) do
+ if is_next(v) then
+ return v
+ end
+ end
+ else
+ return line_diagnostics[lnum][1]
+ end
+ end
+ end
+end
+
+---@private
+local function diagnostic_move_pos(opts, pos)
+ opts = opts or {}
+
+ local enable_popup = vim.F.if_nil(opts.enable_popup, true)
+ local win_id = opts.win_id or vim.api.nvim_get_current_win()
+
+ if not pos then
+ vim.api.nvim_echo({{"No more valid diagnostics to move to", "WarningMsg"}}, true, {})
+ return
+ end
+
+ vim.api.nvim_win_set_cursor(win_id, {pos[1] + 1, pos[2]})
+
+ if enable_popup then
+ -- This is a bit weird... I'm surprised that we need to wait til the next tick to do this.
+ vim.schedule(function()
+ M.show_position_diagnostics(opts.popup_opts, vim.api.nvim_win_get_buf(win_id))
+ end)
+ end
+end
+
+-- }}}
+
+-- Public API {{{
+
+--- Configure diagnostic options globally or for a specific diagnostic
+--- namespace.
+---
+---@note Each of the configuration options below accepts one of the following:
+--- - `false`: Disable this feature
+--- - `true`: Enable this feature, use default settings.
+--- - `table`: Enable this feature with overrides.
+--- - `function`: Function with signature (namespace, bufnr) that returns any of the above.
+---
+---@param opts table Configuration table with the following keys:
+--- - underline: (default true) Use underline for diagnostics. Options:
+--- * severity: Only underline diagnostics matching the given severity
+--- |diagnostic-severity|
+--- - virtual_text: (default true) Use virtual text for diagnostics. Options:
+--- * severity: Only show virtual text for diagnostics matching the given
+--- severity |diagnostic-severity|
+--- * source: (string) Include the diagnostic source in virtual
+--- text. One of "always" or "if_many".
+--- * format: (function) A function that takes a diagnostic as input and
+--- returns a string. The return value is the text used to display
+--- the diagnostic. Example:
+--- <pre>
+--- function(diagnostic)
+--- if diagnostic.severity == vim.diagnostic.severity.ERROR then
+--- return string.format("E: %s", diagnostic.message)
+--- end
+--- return diagnostic.message
+--- end
+--- </pre>
+--- - signs: (default true) Use signs for diagnostics. Options:
+--- * severity: Only show signs for diagnostics matching the given severity
+--- |diagnostic-severity|
+--- - update_in_insert: (default false) Update diagnostics in Insert mode (if false,
+--- diagnostics are updated on InsertLeave)
+--- - severity_sort: (default false) Sort diagnostics by severity. This affects the order in
+--- which signs and virtual text are displayed. When true, higher severities
+--- are displayed before lower severities (e.g. ERROR is displayed before WARN).
+--- Options:
+--- * reverse: (boolean) Reverse sort order
+---@param namespace number|nil Update the options for the given namespace. When omitted, update the
+--- global diagnostic options.
+function M.config(opts, namespace)
+ vim.validate {
+ opts = { opts, 't' },
+ namespace = { namespace, 'n', true },
+ }
+
+ local t
+ if namespace then
+ local ns = get_namespace(namespace)
+ t = ns.opts
+ else
+ t = global_diagnostic_options
+ end
+
+ for opt in pairs(global_diagnostic_options) do
+ if opts[opt] ~= nil then
+ t[opt] = opts[opt]
+ end
+ end
+
+ if namespace then
+ for bufnr, v in pairs(diagnostic_cache) do
+ if vim.api.nvim_buf_is_loaded(bufnr) and v[namespace] then
+ M.show(namespace, bufnr)
+ end
+ end
+ else
+ for bufnr, v in pairs(diagnostic_cache) do
+ if vim.api.nvim_buf_is_loaded(bufnr) then
+ for ns in pairs(v) do
+ M.show(ns, bufnr)
+ end
+ end
+ end
+ end
+end
+
+--- Set diagnostics for the given namespace and buffer.
+---
+---@param namespace number The diagnostic namespace
+---@param bufnr number Buffer number
+---@param diagnostics table A list of diagnostic items |diagnostic-structure|
+---@param opts table|nil Display options to pass to |vim.diagnostic.show()|
+function M.set(namespace, bufnr, diagnostics, opts)
+ vim.validate {
+ namespace = {namespace, 'n'},
+ bufnr = {bufnr, 'n'},
+ diagnostics = {diagnostics, 't'},
+ opts = {opts, 't', true},
+ }
+
+ if vim.tbl_isempty(diagnostics) then
+ return M.reset(namespace, bufnr)
+ end
+
+ if not diagnostic_cleanup[bufnr][namespace] then
+ diagnostic_cleanup[bufnr][namespace] = true
+
+ -- Clean up our data when the buffer unloads.
+ vim.api.nvim_buf_attach(bufnr, false, {
+ on_detach = function(_, b)
+ clear_diagnostic_cache(b, namespace)
+ diagnostic_cleanup[b][namespace] = nil
+ end
+ })
+ end
+
+ set_diagnostic_cache(namespace, bufnr, diagnostics)
+
+ if vim.api.nvim_buf_is_loaded(bufnr) then
+ M.show(namespace, bufnr, diagnostics, opts)
+ elseif opts then
+ M.config(opts, namespace)
+ end
+
+ vim.api.nvim_command("doautocmd <nomodeline> User DiagnosticsChanged")
+end
+
+--- Get current diagnostics.
+---
+---@param bufnr number|nil Buffer number to get diagnostics from. Use 0 for
+--- current buffer or nil for all buffers.
+---@param opts table|nil A table with the following keys:
+--- - namespace: (number) Limit diagnostics to the given namespace.
+--- - lnum: (number) Limit diagnostics to the given line number.
+--- - severity: See |diagnostic-severity|.
+---@return table A list of diagnostic items |diagnostic-structure|.
+function M.get(bufnr, opts)
+ vim.validate {
+ bufnr = { bufnr, 'n', true },
+ opts = { opts, 't', true },
+ }
+
+ opts = opts or {}
+
+ local namespace = opts.namespace
+ local diagnostics = {}
+
+ ---@private
+ local function add(d)
+ if not opts.lnum or d.lnum == opts.lnum then
+ table.insert(diagnostics, d)
+ end
+ end
+
+ if namespace == nil and bufnr == nil then
+ for _, t in pairs(diagnostic_cache) do
+ for _, v in pairs(t) do
+ for _, diagnostic in pairs(v) do
+ add(diagnostic)
+ end
+ end
+ end
+ elseif namespace == nil then
+ for iter_namespace in pairs(diagnostic_cache[bufnr]) do
+ for _, diagnostic in pairs(diagnostic_cache[bufnr][iter_namespace]) do
+ add(diagnostic)
+ end
+ end
+ elseif bufnr == nil then
+ for _, t in pairs(diagnostic_cache) do
+ for _, diagnostic in pairs(t[namespace] or {}) do
+ add(diagnostic)
+ end
+ end
+ else
+ for _, diagnostic in pairs(diagnostic_cache[bufnr][namespace] or {}) do
+ add(diagnostic)
+ end
+ end
+
+ if opts.severity then
+ diagnostics = filter_by_severity(opts.severity, diagnostics)
+ end
+
+ return diagnostics
+end
+
+--- Get the previous diagnostic closest to the cursor position.
+---
+---@param opts table See |vim.diagnostic.goto_next()|
+---@return table Previous diagnostic
+function M.get_prev(opts)
+ opts = opts or {}
+
+ local win_id = opts.win_id or vim.api.nvim_get_current_win()
+ local bufnr = vim.api.nvim_win_get_buf(win_id)
+ local cursor_position = opts.cursor_position or vim.api.nvim_win_get_cursor(win_id)
+
+ return next_diagnostic(cursor_position, false, bufnr, opts, opts.namespace)
+end
+
+--- Return the position of the previous diagnostic in the current buffer.
+---
+---@param opts table See |vim.diagnostic.goto_next()|
+---@return table Previous diagnostic position as a (row, col) tuple.
+function M.get_prev_pos(opts)
+ local prev = M.get_prev(opts)
+ if not prev then
+ return false
+ end
+
+ return {prev.lnum, prev.col}
+end
+
+--- Move to the previous diagnostic in the current buffer.
+---@param opts table See |vim.diagnostic.goto_next()|
+function M.goto_prev(opts)
+ return diagnostic_move_pos(
+ opts,
+ M.get_prev_pos(opts)
+ )
+end
+
+--- Get the next diagnostic closest to the cursor position.
+---
+---@param opts table See |vim.diagnostic.goto_next()|
+---@return table Next diagnostic
+function M.get_next(opts)
+ opts = opts or {}
+
+ local win_id = opts.win_id or vim.api.nvim_get_current_win()
+ local bufnr = vim.api.nvim_win_get_buf(win_id)
+ local cursor_position = opts.cursor_position or vim.api.nvim_win_get_cursor(win_id)
+
+ return next_diagnostic(cursor_position, true, bufnr, opts, opts.namespace)
+end
+
+--- Return the position of the next diagnostic in the current buffer.
+---
+---@param opts table See |vim.diagnostic.goto_next()|
+---@return table Next diagnostic position as a (row, col) tuple.
+function M.get_next_pos(opts)
+ local next = M.get_next(opts)
+ if not next then
+ return false
+ end
+
+ return {next.lnum, next.col}
+end
+
+--- Move to the next diagnostic.
+---
+---@param opts table|nil Configuration table with the following keys:
+--- - namespace: (number) Only consider diagnostics from the given namespace.
+--- - cursor_position: (cursor position) Cursor position as a (row, col) tuple. See
+--- |nvim_win_get_cursor()|. Defaults to the current cursor position.
+--- - wrap: (boolean, default true) Whether to loop around file or not. Similar to 'wrapscan'.
+--- - severity: See |diagnostic-severity|.
+--- - enable_popup: (boolean, default true) Call |vim.diagnostic.show_line_diagnostics()|
+--- on jump.
+--- - popup_opts: (table) Table to pass as {opts} parameter to
+--- |vim.diagnostic.show_line_diagnostics()|
+--- - win_id: (number, default 0) Window ID
+function M.goto_next(opts)
+ return diagnostic_move_pos(
+ opts,
+ M.get_next_pos(opts)
+ )
+end
+
+-- Diagnostic Setters {{{
+
+--- Set signs for given diagnostics.
+---
+---@param namespace number The diagnostic namespace
+---@param bufnr number Buffer number
+---@param diagnostics table A list of diagnostic items |diagnostic-structure|. When omitted the
+--- current diagnostics in the given buffer are used.
+---@param opts table Configuration table with the following keys:
+--- - priority: Set the priority of the signs |sign-priority|.
+---@private
+function M._set_signs(namespace, bufnr, diagnostics, opts)
+ vim.validate {
+ namespace = {namespace, 'n'},
+ bufnr = {bufnr, 'n'},
+ diagnostics = {diagnostics, 't'},
+ opts = {opts, 't', true},
+ }
+
+ bufnr = get_bufnr(bufnr)
+ opts = get_resolved_options({ signs = opts }, namespace, bufnr)
+
+ if opts.signs and opts.signs.severity then
+ diagnostics = filter_by_severity(opts.signs.severity, diagnostics)
+ end
+
+ local ns = get_namespace(namespace)
+
+ define_default_signs()
+
+ -- 10 is the default sign priority when none is explicitly specified
+ local priority = opts.signs and opts.signs.priority or 10
+ local get_priority
+ if opts.severity_sort then
+ if type(opts.severity_sort) == "table" and opts.severity_sort.reverse then
+ get_priority = function(severity)
+ return priority + (severity - vim.diagnostic.severity.ERROR)
+ end
+ else
+ get_priority = function(severity)
+ return priority + (vim.diagnostic.severity.HINT - severity)
+ end
+ end
+ else
+ get_priority = function()
+ return priority
+ end
+ end
+
+ for _, diagnostic in ipairs(diagnostics) do
+ vim.fn.sign_place(
+ 0,
+ ns.sign_group,
+ sign_highlight_map[diagnostic.severity],
+ bufnr,
+ {
+ priority = get_priority(diagnostic.severity),
+ lnum = diagnostic.lnum + 1
+ }
+ )
+ end
+end
+
+--- Set underline for given diagnostics.
+---
+---@param namespace number The diagnostic namespace
+---@param bufnr number Buffer number
+---@param diagnostics table A list of diagnostic items |diagnostic-structure|. When omitted the
+--- current diagnostics in the given buffer are used.
+---@param opts table Configuration table. Currently unused.
+---@private
+function M._set_underline(namespace, bufnr, diagnostics, opts)
+ vim.validate {
+ namespace = {namespace, 'n'},
+ bufnr = {bufnr, 'n'},
+ diagnostics = {diagnostics, 't'},
+ opts = {opts, 't', true},
+ }
+
+ bufnr = get_bufnr(bufnr)
+ opts = get_resolved_options({ underline = opts }, namespace, bufnr).underline
+
+ if opts and opts.severity then
+ diagnostics = filter_by_severity(opts.severity, diagnostics)
+ end
+
+ for _, diagnostic in ipairs(diagnostics) do
+ local higroup = underline_highlight_map[diagnostic.severity]
+
+ if higroup == nil then
+ -- Default to error if we don't have a highlight associated
+ higroup = underline_highlight_map.Error
+ end
+
+ vim.highlight.range(
+ bufnr,
+ namespace,
+ higroup,
+ { diagnostic.lnum, diagnostic.col },
+ { diagnostic.end_lnum, diagnostic.end_col }
+ )
+ end
+end
+
+--- Set virtual text for given diagnostics.
+---
+---@param namespace number The diagnostic namespace
+---@param bufnr number Buffer number
+---@param diagnostics table A list of diagnostic items |diagnostic-structure|. When omitted the
+--- current diagnostics in the given buffer are used.
+---@param opts table|nil Configuration table with the following keys:
+--- - prefix: (string) Prefix to display before virtual text on line.
+--- - spacing: (number) Number of spaces to insert before virtual text.
+--- - source: (string) Include the diagnostic source in virtual text. One of "always" or
+--- "if_many".
+---@private
+function M._set_virtual_text(namespace, bufnr, diagnostics, opts)
+ vim.validate {
+ namespace = {namespace, 'n'},
+ bufnr = {bufnr, 'n'},
+ diagnostics = {diagnostics, 't'},
+ opts = {opts, 't', true},
+ }
+
+ bufnr = get_bufnr(bufnr)
+ opts = get_resolved_options({ virtual_text = opts }, namespace, bufnr).virtual_text
+
+ if opts and opts.format then
+ diagnostics = reformat_diagnostics(opts.format, diagnostics)
+ end
+
+ if opts and opts.source then
+ diagnostics = prefix_source(opts.source, diagnostics)
+ end
+
+ local buffer_line_diagnostics = diagnostic_lines(diagnostics)
+ for line, line_diagnostics in pairs(buffer_line_diagnostics) do
+ if opts and opts.severity then
+ line_diagnostics = filter_by_severity(opts.severity, line_diagnostics)
+ end
+ local virt_texts = M._get_virt_text_chunks(line_diagnostics, opts)
+
+ if virt_texts then
+ vim.api.nvim_buf_set_extmark(bufnr, namespace, line, 0, {
+ hl_mode = "combine",
+ virt_text = virt_texts,
+ })
+ end
+ end
+end
+
+--- Get virtual text chunks to display using |nvim_buf_set_extmark()|.
+---
+--- Exported for backward compatibility with
+--- vim.lsp.diagnostic.get_virtual_text_chunks_for_line(). When that function is eventually removed,
+--- this can be made local.
+---@private
+function M._get_virt_text_chunks(line_diags, opts)
+ if #line_diags == 0 then
+ return nil
+ end
+
+ opts = opts or {}
+ local prefix = opts.prefix or "■"
+ local spacing = opts.spacing or 4
+
+ -- Create a little more space between virtual text and contents
+ local virt_texts = {{string.rep(" ", spacing)}}
+
+ for i = 1, #line_diags - 1 do
+ table.insert(virt_texts, {prefix, virtual_text_highlight_map[line_diags[i].severity]})
+ end
+ local last = line_diags[#line_diags]
+
+ -- TODO(tjdevries): Allow different servers to be shown first somehow?
+ -- TODO(tjdevries): Display server name associated with these?
+ if last.message then
+ table.insert(
+ virt_texts,
+ {
+ string.format("%s %s", prefix, last.message:gsub("\r", ""):gsub("\n", " ")),
+ virtual_text_highlight_map[last.severity]
+ }
+ )
+
+ return virt_texts
+ end
+end
+
+--- Callback scheduled when leaving Insert mode.
+---
+--- This function must be exported publicly so that it is available to be
+--- called from the Vimscript autocommand.
+---
+--- See @ref schedule_display()
+---
+---@private
+function M._execute_scheduled_display(namespace, bufnr)
+ local args = bufs_waiting_to_update[bufnr][namespace]
+ if not args then
+ return
+ end
+
+ -- Clear the args so we don't display unnecessarily.
+ bufs_waiting_to_update[bufnr][namespace] = nil
+
+ M.show(namespace, bufnr, nil, args)
+end
+
+--- Hide currently displayed diagnostics.
+---
+--- This only clears the decorations displayed in the buffer. Diagnostics can
+--- be redisplayed with |vim.diagnostic.show()|. To completely remove
+--- diagnostics, use |vim.diagnostic.reset()|.
+---
+--- To hide diagnostics and prevent them from re-displaying, use
+--- |vim.diagnostic.disable()|.
+---
+---@param namespace number The diagnostic namespace
+---@param bufnr number|nil Buffer number. Defaults to the current buffer.
+function M.hide(namespace, bufnr)
+ vim.validate {
+ namespace = { namespace, 'n' },
+ bufnr = { bufnr, 'n', true },
+ }
+
+ bufnr = get_bufnr(bufnr)
+ diagnostic_cache_extmarks[bufnr][namespace] = {}
+
+ local ns = get_namespace(namespace)
+
+ -- clear sign group
+ vim.fn.sign_unplace(ns.sign_group, {buffer=bufnr})
+
+ -- clear virtual text namespace
+ vim.api.nvim_buf_clear_namespace(bufnr, namespace, 0, -1)
+end
+
+
+--- Display diagnostics for the given namespace and buffer.
+---
+---@param namespace number Diagnostic namespace
+---@param bufnr number|nil Buffer number. Defaults to the current buffer.
+---@param diagnostics table|nil The diagnostics to display. When omitted, use the
+--- saved diagnostics for the given namespace and
+--- buffer. This can be used to display a list of diagnostics
+--- without saving them or to display only a subset of
+--- diagnostics.
+---@param opts table|nil Display options. See |vim.diagnostic.config()|.
+function M.show(namespace, bufnr, diagnostics, opts)
+ vim.validate {
+ namespace = { namespace, 'n' },
+ bufnr = { bufnr, 'n', true },
+ diagnostics = { diagnostics, 't', true },
+ opts = { opts, 't', true },
+ }
+
+ bufnr = get_bufnr(bufnr)
+ if is_disabled(namespace, bufnr) then
+ return
+ end
+
+ M.hide(namespace, bufnr)
+
+ diagnostics = diagnostics or M.get(bufnr, {namespace=namespace})
+
+ if not diagnostics or vim.tbl_isempty(diagnostics) then
+ return
+ end
+
+ opts = get_resolved_options(opts, namespace, bufnr)
+
+ if opts.update_in_insert then
+ clear_scheduled_display(namespace, bufnr)
+ else
+ local mode = vim.api.nvim_get_mode()
+ if string.sub(mode.mode, 1, 1) == 'i' then
+ schedule_display(namespace, bufnr, opts)
+ return
+ end
+ end
+
+ if vim.F.if_nil(opts.severity_sort, false) then
+ if type(opts.severity_sort) == "table" and opts.severity_sort.reverse then
+ table.sort(diagnostics, function(a, b) return a.severity < b.severity end)
+ else
+ table.sort(diagnostics, function(a, b) return a.severity > b.severity end)
+ end
+ end
+
+ clamp_line_numbers(bufnr, diagnostics)
+
+ if opts.underline then
+ M._set_underline(namespace, bufnr, diagnostics, opts.underline)
+ end
+
+ if opts.virtual_text then
+ M._set_virtual_text(namespace, bufnr, diagnostics, opts.virtual_text)
+ end
+
+ if opts.signs then
+ M._set_signs(namespace, bufnr, diagnostics, opts.signs)
+ end
+
+ save_extmarks(namespace, bufnr)
+end
+
+--- Open a floating window with the diagnostics at the given position.
+---
+---@param opts table|nil Configuration table with the same keys as
+--- |vim.lsp.util.open_floating_preview()| in addition to the following:
+--- - namespace: (number) Limit diagnostics to the given namespace
+--- - severity: See |diagnostic-severity|.
+--- - show_header: (boolean, default true) Show "Diagnostics:" header
+--- - source: (string) Include the diagnostic source in
+--- the message. One of "always" or "if_many".
+--- - format: (function) A function that takes a diagnostic as input and returns a
+--- string. The return value is the text used to display the diagnostic.
+---@param bufnr number|nil Buffer number. Defaults to the current buffer.
+---@param position table|nil The (0,0)-indexed position. Defaults to the current cursor position.
+---@return tuple ({popup_bufnr}, {win_id})
+function M.show_position_diagnostics(opts, bufnr, position)
+ vim.validate {
+ opts = { opts, 't', true },
+ bufnr = { bufnr, 'n', true },
+ position = { position, 't', true },
+ }
+
+ opts = opts or {}
+
+ opts.focus_id = "position_diagnostics"
+ bufnr = get_bufnr(bufnr)
+ if not position then
+ local curr_position = vim.api.nvim_win_get_cursor(0)
+ curr_position[1] = curr_position[1] - 1
+ position = curr_position
+ end
+ local match_position_predicate = function(diag)
+ return position[1] == diag.lnum and
+ position[2] >= diag.col and
+ (position[2] <= diag.end_col or position[1] < diag.end_lnum)
+ end
+ local diagnostics = M.get(bufnr, opts)
+ clamp_line_numbers(bufnr, diagnostics)
+ local position_diagnostics = vim.tbl_filter(match_position_predicate, diagnostics)
+ table.sort(position_diagnostics, function(a, b) return a.severity < b.severity end)
+ return show_diagnostics(opts, position_diagnostics)
+end
+
+--- Open a floating window with the diagnostics from the given line.
+---
+---@param opts table Configuration table. See |vim.diagnostic.show_position_diagnostics()|.
+---@param bufnr number|nil Buffer number. Defaults to the current buffer.
+---@param lnum number|nil Line number. Defaults to line number of cursor.
+---@return tuple ({popup_bufnr}, {win_id})
+function M.show_line_diagnostics(opts, bufnr, lnum)
+ vim.validate {
+ opts = { opts, 't', true },
+ bufnr = { bufnr, 'n', true },
+ lnum = { lnum, 'n', true },
+ }
+
+ opts = opts or {}
+ opts.focus_id = "line_diagnostics"
+ bufnr = get_bufnr(bufnr)
+ local diagnostics = M.get(bufnr, opts)
+ clamp_line_numbers(bufnr, diagnostics)
+ lnum = lnum or (vim.api.nvim_win_get_cursor(0)[1] - 1)
+ local line_diagnostics = diagnostic_lines(diagnostics)[lnum]
+ return show_diagnostics(opts, line_diagnostics)
+end
+
+--- Remove all diagnostics from the given namespace.
+---
+--- Unlike |vim.diagnostic.hide()|, this function removes all saved
+--- diagnostics. They cannot be redisplayed using |vim.diagnostic.show()|. To
+--- simply remove diagnostic decorations in a way that they can be
+--- re-displayed, use |vim.diagnostic.hide()|.
+---
+---@param namespace number
+---@param bufnr number|nil Remove diagnostics for the given buffer. When omitted,
+--- diagnostics are removed for all buffers.
+function M.reset(namespace, bufnr)
+ if bufnr == nil then
+ for iter_bufnr, namespaces in pairs(diagnostic_cache) do
+ if namespaces[namespace] then
+ M.reset(namespace, iter_bufnr)
+ end
+ end
+ else
+ clear_diagnostic_cache(namespace, bufnr)
+ M.hide(namespace, bufnr)
+ end
+
+ vim.api.nvim_command("doautocmd <nomodeline> User DiagnosticsChanged")
+end
+
+--- Add all diagnostics to the quickfix list.
+---
+---@param opts table|nil Configuration table with the following keys:
+--- - namespace: (number) Only add diagnostics from the given namespace.
+--- - open: (boolean, default true) Open quickfix list after setting.
+--- - title: (string) Title of quickfix list. Defaults to "Diagnostics".
+--- - severity: See |diagnostic-severity|.
+function M.setqflist(opts)
+ set_list(false, opts)
+end
+
+--- Add buffer diagnostics to the location list.
+---
+---@param opts table|nil Configuration table with the following keys:
+--- - namespace: (number) Only add diagnostics from the given namespace.
+--- - winnr: (number, default 0) Window number to set location list for.
+--- - open: (boolean, default true) Open the location list after setting.
+--- - title: (string) Title of the location list. Defaults to "Diagnostics".
+--- - severity: See |diagnostic-severity|.
+function M.setloclist(opts)
+ set_list(true, opts)
+end
+
+--- Disable diagnostics in the given buffer.
+---
+---@param bufnr number|nil Buffer number. Defaults to the current buffer.
+---@param namespace number|nil Only disable diagnostics for the given namespace.
+function M.disable(bufnr, namespace)
+ vim.validate { bufnr = {bufnr, 'n', true}, namespace = {namespace, 'n', true} }
+ bufnr = get_bufnr(bufnr)
+ if namespace == nil then
+ diagnostic_disabled[bufnr] = true
+ for ns in pairs(diagnostic_cache[bufnr]) do
+ M.hide(ns, bufnr)
+ end
+ else
+ if type(diagnostic_disabled[bufnr]) ~= "table" then
+ diagnostic_disabled[bufnr] = {}
+ end
+ diagnostic_disabled[bufnr][namespace] = true
+ M.hide(namespace, bufnr)
+ end
+end
+
+--- Enable diagnostics in the given buffer.
+---
+---@param bufnr number|nil Buffer number. Defaults to the current buffer.
+---@param namespace number|nil Only enable diagnostics for the given namespace.
+function M.enable(bufnr, namespace)
+ vim.validate { bufnr = {bufnr, 'n', true}, namespace = {namespace, 'n', true} }
+ bufnr = get_bufnr(bufnr)
+ if namespace == nil then
+ diagnostic_disabled[bufnr] = nil
+ for ns in pairs(diagnostic_cache[bufnr]) do
+ M.show(ns, bufnr)
+ end
+ else
+ if type(diagnostic_disabled[bufnr]) ~= "table" then
+ return
+ end
+ diagnostic_disabled[bufnr][namespace] = nil
+ M.show(namespace, bufnr)
+ end
+end
+
+--- Parse a diagnostic from a string.
+---
+--- For example, consider a line of output from a linter:
+--- <pre>
+--- WARNING filename:27:3: Variable 'foo' does not exist
+--- </pre>
+--- This can be parsed into a diagnostic |diagnostic-structure|
+--- with:
+--- <pre>
+--- local s = "WARNING filename:27:3: Variable 'foo' does not exist"
+--- local pattern = "^(%w+) %w+:(%d+):(%d+): (.+)$"
+--- local groups = {"severity", "lnum", "col", "message"}
+--- vim.diagnostic.match(s, pattern, groups, {WARNING = vim.diagnostic.WARN})
+--- </pre>
+---
+---@param str string String to parse diagnostics from.
+---@param pat string Lua pattern with capture groups.
+---@param groups table List of fields in a |diagnostic-structure| to
+--- associate with captures from {pat}.
+---@param severity_map table A table mapping the severity field from {groups}
+--- with an item from |vim.diagnostic.severity|.
+---@param defaults table|nil Table of default values for any fields not listed in {groups}.
+--- When omitted, numeric values default to 0 and "severity" defaults to
+--- ERROR.
+---@return diagnostic |diagnostic-structure| or `nil` if {pat} fails to match {str}.
+function M.match(str, pat, groups, severity_map, defaults)
+ vim.validate {
+ str = { str, 's' },
+ pat = { pat, 's' },
+ groups = { groups, 't' },
+ severity_map = { severity_map, 't', true },
+ defaults = { defaults, 't', true },
+ }
+
+ severity_map = severity_map or M.severity
+
+ local diagnostic = {}
+ local matches = {string.match(str, pat)}
+ if vim.tbl_isempty(matches) then
+ return
+ end
+
+ for i, match in ipairs(matches) do
+ local field = groups[i]
+ if field == "severity" then
+ match = severity_map[match]
+ elseif field == "lnum" or field == "end_lnum" or field == "col" or field == "end_col" then
+ match = assert(tonumber(match)) - 1
+ end
+ diagnostic[field] = match
+ end
+
+ diagnostic = vim.tbl_extend("keep", diagnostic, defaults or {})
+ diagnostic.severity = diagnostic.severity or M.severity.ERROR
+ diagnostic.col = diagnostic.col or 0
+ diagnostic.end_lnum = diagnostic.end_lnum or diagnostic.lnum
+ diagnostic.end_col = diagnostic.end_col or diagnostic.col
+ return diagnostic
+end
+
+local errlist_type_map = {
+ [M.severity.ERROR] = 'E',
+ [M.severity.WARN] = 'W',
+ [M.severity.INFO] = 'I',
+ [M.severity.HINT] = 'N',
+}
+
+--- Convert a list of diagnostics to a list of quickfix items that can be
+--- passed to |setqflist()| or |setloclist()|.
+---
+---@param diagnostics table List of diagnostics |diagnostic-structure|.
+---@return array of quickfix list items |setqflist-what|
+function M.toqflist(diagnostics)
+ vim.validate { diagnostics = {diagnostics, 't'} }
+
+ local list = {}
+ for _, v in ipairs(diagnostics) do
+ local item = {
+ bufnr = v.bufnr,
+ lnum = v.lnum + 1,
+ col = v.col and (v.col + 1) or nil,
+ end_lnum = v.end_lnum and (v.end_lnum + 1) or nil,
+ end_col = v.end_col and (v.end_col + 1) or nil,
+ text = v.message,
+ type = errlist_type_map[v.severity] or 'E',
+ }
+ table.insert(list, item)
+ end
+ table.sort(list, function(a, b)
+ if a.bufnr == b.bufnr then
+ return a.lnum < b.lnum
+ else
+ return a.bufnr < b.bufnr
+ end
+ end)
+ return list
+end
+
+--- Convert a list of quickfix items to a list of diagnostics.
+---
+---@param list table A list of quickfix items from |getqflist()| or
+--- |getloclist()|.
+---@return array of diagnostics |diagnostic-structure|
+function M.fromqflist(list)
+ vim.validate { list = {list, 't'} }
+
+ local diagnostics = {}
+ for _, item in ipairs(list) do
+ if item.valid == 1 then
+ local lnum = math.max(0, item.lnum - 1)
+ local col = item.col > 0 and (item.col - 1) or nil
+ local end_lnum = item.end_lnum > 0 and (item.end_lnum - 1) or lnum
+ local end_col = item.end_col > 0 and (item.end_col - 1) or col
+ local severity = item.type ~= "" and M.severity[item.type] or M.severity.ERROR
+ table.insert(diagnostics, {
+ bufnr = item.bufnr,
+ lnum = lnum,
+ col = col,
+ end_lnum = end_lnum,
+ end_col = end_col,
+ severity = severity,
+ message = item.text,
+ })
+ end
+ end
+ return diagnostics
+end
+
+-- }}}
+
+return M
diff --git a/runtime/lua/vim/highlight.lua b/runtime/lua/vim/highlight.lua
index 0012dce081..236f3165f2 100644
--- a/runtime/lua/vim/highlight.lua
+++ b/runtime/lua/vim/highlight.lua
@@ -2,7 +2,7 @@ local api = vim.api
local highlight = {}
---@private
+---@private
function highlight.create(higroup, hi_info, default)
local options = {}
-- TODO: Add validation
@@ -12,7 +12,7 @@ function highlight.create(higroup, hi_info, default)
vim.cmd(string.format([[highlight %s %s %s]], default and "default" or "", higroup, table.concat(options, " ")))
end
---@private
+---@private
function highlight.link(higroup, link_to, force)
vim.cmd(string.format([[highlight%s link %s %s]], force and "!" or " default", higroup, link_to))
end
@@ -20,11 +20,11 @@ end
--- Highlight range between two positions
---
---@param bufnr number of buffer to apply highlighting to
---@param ns namespace to add highlight to
---@param higroup highlight group to use for highlighting
---@param rtype type of range (:help setreg, default charwise)
---@param inclusive boolean indicating whether the range is end-inclusive (default false)
+---@param bufnr number of buffer to apply highlighting to
+---@param ns namespace to add highlight to
+---@param higroup highlight group to use for highlighting
+---@param rtype type of range (:help setreg, default charwise)
+---@param inclusive boolean indicating whether the range is end-inclusive (default false)
function highlight.range(bufnr, ns, higroup, start, finish, rtype, inclusive)
rtype = rtype or 'v'
inclusive = inclusive or false
@@ -85,7 +85,11 @@ function highlight.on_yank(opts)
highlight.range(bufnr, yank_ns, higroup, pos1, pos2, event.regtype, event.inclusive)
vim.defer_fn(
- function() api.nvim_buf_clear_namespace(bufnr, yank_ns, 0, -1) end,
+ function()
+ if api.nvim_buf_is_valid(bufnr) then
+ api.nvim_buf_clear_namespace(bufnr, yank_ns, 0, -1)
+ end
+ end,
timeout
)
end
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 75faf9bcc7..c7a88a0993 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -55,21 +55,21 @@ lsp._request_name_to_capability = {
-- TODO improve handling of scratch buffers with LSP attached.
---@private
+---@private
--- Concatenates and writes a list of strings to the Vim error buffer.
---
---@param {...} (List of strings) List to write to the buffer
+---@param {...} (List of strings) List to write to the buffer
local function err_message(...)
nvim_err_writeln(table.concat(vim.tbl_flatten{...}))
nvim_command("redraw")
end
---@private
+---@private
--- Returns the buffer number for the given {bufnr}.
---
---@param bufnr (number) Buffer number to resolve. Defaults to the current
+---@param bufnr (number) Buffer number to resolve. Defaults to the current
---buffer if not given.
---@returns bufnr (number) Number of requested buffer
+---@returns bufnr (number) Number of requested buffer
local function resolve_bufnr(bufnr)
validate { bufnr = { bufnr, 'n', true } }
if bufnr == nil or bufnr == 0 then
@@ -78,21 +78,21 @@ local function resolve_bufnr(bufnr)
return bufnr
end
---@private
+---@private
--- Called by the client when trying to call a method that's not
--- supported in any of the servers registered for the current buffer.
---@param method (string) name of the method
+---@param method (string) name of the method
function lsp._unsupported_method(method)
local msg = string.format("method %s is not supported by any of the servers registered for the current buffer", method)
log.warn(msg)
return lsp.rpc_response_error(protocol.ErrorCodes.MethodNotFound, msg)
end
---@private
+---@private
--- Checks whether a given path is a directory.
---
---@param filename (string) path to check
---@returns true if {filename} exists and is a directory, false otherwise
+---@param filename (string) path to check
+---@returns true if {filename} exists and is a directory, false otherwise
local function is_dir(filename)
validate{filename={filename,'s'}}
local stat = uv.fs_stat(filename)
@@ -108,10 +108,10 @@ local valid_encodings = {
}
local client_index = 0
---@private
+---@private
--- Returns a new, unused client id.
---
---@returns (number) client id
+---@returns (number) client id
local function next_client_id()
client_index = client_index + 1
return client_index
@@ -124,11 +124,11 @@ local uninitialized_clients = {}
-- Tracks all buffers attached to a client.
local all_client_active_buffers = {}
---@private
+---@private
--- Invokes a function for each LSP client attached to the buffer {bufnr}.
---
---@param bufnr (Number) of buffer
---@param fn (function({client}, {client_id}, {bufnr}) Function to run on
+---@param bufnr (Number) of buffer
+---@param fn (function({client}, {client_id}, {bufnr}) Function to run on
---each client attached to that buffer.
local function for_each_buffer_client(bufnr, fn)
validate {
@@ -154,11 +154,11 @@ lsp.client_errors = tbl_extend("error", lsp_rpc.client_errors, vim.tbl_add_rever
ON_INIT_CALLBACK_ERROR = table.maxn(lsp_rpc.client_errors) + 1;
})
---@private
+---@private
--- Normalizes {encoding} to valid LSP encoding names.
---
---@param encoding (string) Encoding to normalize
---@returns (string) normalized encoding name
+---@param encoding (string) Encoding to normalize
+---@returns (string) normalized encoding name
local function validate_encoding(encoding)
validate {
encoding = { encoding, 's' };
@@ -167,13 +167,13 @@ local function validate_encoding(encoding)
or error(string.format("Invalid offset encoding %q. Must be one of: 'utf-8', 'utf-16', 'utf-32'", encoding))
end
---@internal
+---@internal
--- Parses a command invocation into the command itself and its args. If there
--- are no arguments, an empty table is returned as the second argument.
---
---@param input (List)
---@returns (string) the command
---@returns (list of strings) its arguments
+---@param input (List)
+---@returns (string) the command
+---@returns (list of strings) its arguments
function lsp._cmd_parts(input)
vim.validate{cmd={
input,
@@ -192,12 +192,12 @@ function lsp._cmd_parts(input)
return cmd, cmd_args
end
---@private
+---@private
--- Augments a validator function with support for optional (nil) values.
---
---@param fn (function(v)) The original validator function; should return a
+---@param fn (function(v)) The original validator function; should return a
---bool.
---@returns (function(v)) The augmented function. Also returns true if {v} is
+---@returns (function(v)) The augmented function. Also returns true if {v} is
---`nil`.
local function optional_validator(fn)
return function(v)
@@ -205,20 +205,20 @@ local function optional_validator(fn)
end
end
---@private
+---@private
--- Validates a client configuration as given to |vim.lsp.start_client()|.
---
---@param config (table)
---@returns (table) "Cleaned" config, containing only the command, its
+---@param config (table)
+---@returns (table) "Cleaned" config, containing only the command, its
---arguments, and a valid encoding.
---
---@see |vim.lsp.start_client()|
+---@see |vim.lsp.start_client()|
local function validate_client_config(config)
validate {
config = { config, 't' };
}
validate {
- root_dir = { config.root_dir, is_dir, "directory" };
+ root_dir = { config.root_dir, optional_validator(is_dir), "directory" };
handlers = { config.handlers, "t", true };
capabilities = { config.capabilities, "t", true };
cmd_cwd = { config.cmd_cwd, optional_validator(is_dir), "directory" };
@@ -253,11 +253,11 @@ local function validate_client_config(config)
}
end
---@private
+---@private
--- Returns full text of buffer {bufnr} as a string.
---
---@param bufnr (number) Buffer handle, or 0 for current.
---@returns Buffer text as string.
+---@param bufnr (number) Buffer handle, or 0 for current.
+---@returns Buffer text as string.
local function buf_get_full_text(bufnr)
local text = table.concat(nvim_buf_get_lines(bufnr, 0, -1, true), '\n')
if nvim_buf_get_option(bufnr, 'eol') then
@@ -266,14 +266,14 @@ local function buf_get_full_text(bufnr)
return text
end
---@private
+---@private
--- Memoizes a function. On first run, the function return value is saved and
--- immediately returned on subsequent runs. If the function returns a multival,
--- only the first returned value will be memoized and returned. The function will only be run once,
--- even if it has side-effects.
---
---@param fn (function) Function to run
---@returns (function) Memoized function
+---@param fn (function) Function to run
+---@returns (function) Memoized function
local function once(fn)
local value
local ran = false
@@ -289,6 +289,7 @@ end
local changetracking = {}
do
+ --@private
--- client_id → state
---
--- state
@@ -380,7 +381,7 @@ do
end
state.pending_change = function()
state.pending_change = nil
- if client.is_stopped() then
+ if client.is_stopped() or not vim.api.nvim_buf_is_valid(bufnr) then
return
end
local contentChanges
@@ -425,11 +426,11 @@ do
end
---@private
+---@private
--- Default handler for the 'textDocument/didOpen' LSP notification.
---
---@param bufnr (Number) Number of the buffer, or 0 for current
---@param client Client object
+---@param bufnr (Number) Number of the buffer, or 0 for current
+---@param client Client object
local function text_document_did_open_handler(bufnr, client)
changetracking.init(client, bufnr)
if not client.resolved_capabilities.text_document_open_close then
@@ -453,15 +454,7 @@ local function text_document_did_open_handler(bufnr, client)
-- Next chance we get, we should re-do the diagnostics
vim.schedule(function()
- vim.lsp.handlers["textDocument/publishDiagnostics"](
- nil,
- "textDocument/publishDiagnostics",
- {
- diagnostics = vim.lsp.diagnostic.get(bufnr, client.id),
- uri = vim.uri_from_bufnr(bufnr),
- },
- client.id
- )
+ vim.lsp.diagnostic.redraw(bufnr, client.id)
end)
end
@@ -555,16 +548,16 @@ end
---
--- The following parameters describe fields in the {config} table.
---
---@param root_dir: (required, string) Directory where the LSP server will base
+---@param root_dir: (string) Directory where the LSP server will base
--- its rootUri on initialization.
---
---@param cmd: (required, string or list treated like |jobstart()|) Base command
+---@param cmd: (required, string or list treated like |jobstart()|) Base command
--- that initiates the LSP client.
---
---@param cmd_cwd: (string, default=|getcwd()|) Directory to launch
+---@param cmd_cwd: (string, default=|getcwd()|) Directory to launch
--- the `cmd` process. Not related to `root_dir`.
---
---@param cmd_env: (table) Environment flags to pass to the LSP on
+---@param cmd_env: (table) Environment flags to pass to the LSP on
--- spawn. Can be specified using keys like a map or as a list with `k=v`
--- pairs or both. Non-string values are coerced to string.
--- Example:
@@ -572,7 +565,7 @@ end
--- { "PRODUCTION=true"; "TEST=123"; PORT = 8080; HOST = "0.0.0.0"; }
--- </pre>
---
---@param capabilities Map overriding the default capabilities defined by
+---@param capabilities Map overriding the default capabilities defined by
--- |vim.lsp.protocol.make_client_capabilities()|, passed to the language
--- server on initialization. Hint: use make_client_capabilities() and modify
--- its result.
@@ -580,37 +573,41 @@ end
--- `{[vim.type_idx]=vim.types.dictionary}`, else it will be encoded as an
--- array.
---
---@param handlers Map of language server method names to |lsp-handler|
+---@param handlers Map of language server method names to |lsp-handler|
---
---@param settings Map with language server specific settings. These are
+---@param settings Map with language server specific settings. These are
--- returned to the language server if requested via `workspace/configuration`.
--- Keys are case-sensitive.
---
---@param init_options Values to pass in the initialization request
+---@param init_options Values to pass in the initialization request
--- as `initializationOptions`. See `initialize` in the LSP spec.
---
---@param name (string, default=client-id) Name in log messages.
+---@param name (string, default=client-id) Name in log messages.
+--
+---@param workspace_folders (table) List of workspace folders passed to the
+--- language server. Defaults to root_dir if not set. See `workspaceFolders` in
+--- the LSP spec
---
---@param get_language_id function(bufnr, filetype) -> language ID as string.
+---@param get_language_id function(bufnr, filetype) -> language ID as string.
--- Defaults to the filetype.
---
---@param offset_encoding (default="utf-16") One of "utf-8", "utf-16",
+---@param offset_encoding (default="utf-16") One of "utf-8", "utf-16",
--- or "utf-32" which is the encoding that the LSP server expects. Client does
--- not verify this is correct.
---
---@param on_error Callback with parameters (code, ...), invoked
+---@param on_error Callback with parameters (code, ...), invoked
--- when the client operation throws an error. `code` is a number describing
--- the error. Other arguments may be passed depending on the error kind. See
--- |vim.lsp.client_errors| for possible errors.
--- Use `vim.lsp.client_errors[code]` to get human-friendly name.
---
---@param before_init Callback with parameters (initialize_params, config)
+---@param before_init Callback with parameters (initialize_params, config)
--- invoked before the LSP "initialize" phase, where `params` contains the
--- parameters being sent to the server and `config` is the config that was
--- passed to |vim.lsp.start_client()|. You can use this to modify parameters before
--- they are sent.
---
---@param on_init Callback (client, initialize_result) invoked after LSP
+---@param on_init Callback (client, initialize_result) invoked after LSP
--- "initialize", where `result` is a table of `capabilities` and anything else
--- the server may send. For example, clangd sends
--- `initialize_result.offsetEncoding` if `capabilities.offsetEncoding` was
@@ -620,24 +617,24 @@ end
--- `workspace/didChangeConfiguration` notification should be sent
--- to the server during on_init.
---
---@param on_exit Callback (code, signal, client_id) invoked on client
+---@param on_exit Callback (code, signal, client_id) invoked on client
--- exit.
--- - code: exit code of the process
--- - signal: number describing the signal used to terminate (if any)
--- - client_id: client handle
---
---@param on_attach Callback (client, bufnr) invoked when client
+---@param on_attach Callback (client, bufnr) invoked when client
--- attaches to a buffer.
---
---@param trace: "off" | "messages" | "verbose" | nil passed directly to the language
+---@param trace: "off" | "messages" | "verbose" | nil passed directly to the language
--- server in the initialize request. Invalid/empty values will default to "off"
---@param flags: A table with flags for the client. The current (experimental) flags are:
+---@param flags: A table with flags for the client. The current (experimental) flags are:
--- - allow_incremental_sync (bool, default true): Allow using incremental sync for buffer edits
--- - debounce_text_changes (number, default nil): Debounce didChange
--- notifications to the server by the given number in milliseconds. No debounce
--- occurs if nil
---
---@returns Client id. |vim.lsp.get_client_by_id()| Note: client may not be
+---@returns Client id. |vim.lsp.get_client_by_id()| Note: client may not be
--- fully initialized. Use `on_init` to do any actions once
--- the client has been initialized.
function lsp.start_client(config)
@@ -660,53 +657,53 @@ function lsp.start_client(config)
local dispatch = {}
- --@private
+ ---@private
--- Returns the handler associated with an LSP method.
--- Returns the default handler if the user hasn't set a custom one.
---
- --@param method (string) LSP method name
- --@returns (fn) The handler for the given method, if defined, or the default from |vim.lsp.handlers|
+ ---@param method (string) LSP method name
+ ---@returns (fn) The handler for the given method, if defined, or the default from |vim.lsp.handlers|
local function resolve_handler(method)
return handlers[method] or default_handlers[method]
end
- --@private
+ ---@private
--- Handles a notification sent by an LSP server by invoking the
--- corresponding handler.
---
- --@param method (string) LSP method name
- --@param params (table) The parameters for that method.
+ ---@param method (string) LSP method name
+ ---@param params (table) The parameters for that method.
function dispatch.notification(method, params)
- local _ = log.debug() and log.debug('notification', method, params)
+ local _ = log.trace() and log.trace('notification', method, params)
local handler = resolve_handler(method)
if handler then
-- Method name is provided here for convenience.
- handler(nil, method, params, client_id)
+ handler(nil, params, {method=method, client_id=client_id})
end
end
- --@private
+ ---@private
--- Handles a request from an LSP server by invoking the corresponding handler.
---
- --@param method (string) LSP method name
- --@param params (table) The parameters for that method
+ ---@param method (string) LSP method name
+ ---@param params (table) The parameters for that method
function dispatch.server_request(method, params)
- local _ = log.debug() and log.debug('server_request', method, params)
+ local _ = log.trace() and log.trace('server_request', method, params)
local handler = resolve_handler(method)
if handler then
- local _ = log.debug() and log.debug("server_request: found handler for", method)
- return handler(nil, method, params, client_id)
+ local _ = log.trace() and log.trace("server_request: found handler for", method)
+ return handler(nil, params, {method=method, client_id=client_id})
end
- local _ = log.debug() and log.debug("server_request: no handler found for", method)
+ local _ = log.warn() and log.warn("server_request: no handler found for", method)
return nil, lsp.rpc_response_error(protocol.ErrorCodes.MethodNotFound)
end
- --@private
+ ---@private
--- Invoked when the client operation throws an error.
---
- --@param code (number) Error code
- --@param err (...) Other arguments may be passed depending on the error kind
- --@see |vim.lsp.client_errors| for possible errors. Use
+ ---@param code (number) Error code
+ ---@param err (...) Other arguments may be passed depending on the error kind
+ ---@see |vim.lsp.client_errors| for possible errors. Use
---`vim.lsp.client_errors[code]` to get a human-friendly name.
function dispatch.on_error(code, err)
local _ = log.error() and log.error(log_prefix, "on_error", { code = lsp.client_errors[code], err = err })
@@ -720,11 +717,11 @@ function lsp.start_client(config)
end
end
- --@private
+ ---@private
--- Invoked on client exit.
---
- --@param code (number) exit code of the process
- --@param signal (number) the signal used to terminate (if any)
+ ---@param code (number) exit code of the process
+ ---@param signal (number) the signal used to terminate (if any)
function dispatch.on_exit(code, signal)
active_clients[client_id] = nil
uninitialized_clients[client_id] = nil
@@ -769,12 +766,20 @@ function lsp.start_client(config)
-- Store the uninitialized_clients for cleanup in case we exit before initialize finishes.
uninitialized_clients[client_id] = client;
- --@private
+ ---@private
local function initialize()
local valid_traces = {
off = 'off'; messages = 'messages'; verbose = 'verbose';
}
local version = vim.version()
+
+ if config.root_dir and not config.workspace_folders then
+ config.workspace_folders = {{
+ uri = vim.uri_from_fname(config.root_dir);
+ name = string.format("%s", config.root_dir);
+ }};
+ end
+
local initialize_params = {
-- The process Id of the parent process that started the server. Is null if
-- the process has not been started by another process. If the parent
@@ -793,7 +798,7 @@ function lsp.start_client(config)
rootPath = config.root_dir;
-- The rootUri of the workspace. Is null if no folder is open. If both
-- `rootPath` and `rootUri` are set `rootUri` wins.
- rootUri = vim.uri_from_fname(config.root_dir);
+ rootUri = config.root_dir and vim.uri_from_fname(config.root_dir);
-- User provided initialization options.
initializationOptions = config.init_options;
-- The capabilities provided by the client (editor or tool)
@@ -815,20 +820,17 @@ function lsp.start_client(config)
-- -- workspace folder in the user interface.
-- name
-- }
- workspaceFolders = {{
- uri = vim.uri_from_fname(config.root_dir);
- name = string.format("%s", config.root_dir);
- }};
+ workspaceFolders = config.workspace_folders,
}
if config.before_init then
-- TODO(ashkan) handle errors here.
pcall(config.before_init, initialize_params, config)
end
- local _ = log.debug() and log.debug(log_prefix, "initialize_params", initialize_params)
+ local _ = log.trace() and log.trace(log_prefix, "initialize_params", initialize_params)
rpc.request('initialize', initialize_params, function(init_err, result)
assert(not init_err, tostring(init_err))
assert(result, "server sent empty result")
- rpc.notify('initialized', {[vim.type_idx]=vim.types.dictionary})
+ rpc.notify('initialized', vim.empty_dict())
client.initialized = true
uninitialized_clients[client_id] = nil
client.workspaceFolders = initialize_params.workspaceFolders
@@ -867,23 +869,23 @@ function lsp.start_client(config)
end)
end
- --@private
+ ---@private
--- Sends a request to the server.
---
--- This is a thin wrapper around {client.rpc.request} with some additional
--- checks for capabilities and handler availability.
---
- --@param method (string) LSP method name.
- --@param params (table) LSP request params.
- --@param handler (function, optional) Response |lsp-handler| for this method.
- --@param bufnr (number) Buffer handle (0 for current).
- --@returns ({status}, [request_id]): {status} is a bool indicating
+ ---@param method (string) LSP method name.
+ ---@param params (table) LSP request params.
+ ---@param handler (function, optional) Response |lsp-handler| for this method.
+ ---@param bufnr (number) Buffer handle (0 for current).
+ ---@returns ({status}, [request_id]): {status} is a bool indicating
---whether the request was successful. If it is `false`, then it will
---always be `false` (the client has shutdown). If it was
---successful, then it will return {request_id} as the
---second result. You can use this with `client.cancel_request(request_id)`
---to cancel the-request.
- --@see |vim.lsp.buf_request()|
+ ---@see |vim.lsp.buf_request()|
function client.request(method, params, handler, bufnr)
if not handler then
handler = resolve_handler(method)
@@ -894,28 +896,28 @@ function lsp.start_client(config)
local _ = log.debug() and log.debug(log_prefix, "client.request", client_id, method, params, handler, bufnr)
return rpc.request(method, params, function(err, result)
- handler(err, method, result, client_id, bufnr)
+ handler(err, result, {method=method, client_id=client_id, bufnr=bufnr, params=params})
end)
end
- --@private
+ ---@private
--- Sends a request to the server and synchronously waits for the response.
---
--- This is a wrapper around {client.request}
---
- --@param method (string) LSP method name.
- --@param params (table) LSP request params.
- --@param timeout_ms (number, optional, default=1000) Maximum time in
+ ---@param method (string) LSP method name.
+ ---@param params (table) LSP request params.
+ ---@param timeout_ms (number, optional, default=1000) Maximum time in
---milliseconds to wait for a result.
- --@param bufnr (number) Buffer handle (0 for current).
- --@returns { err=err, result=result }, a dictionary, where `err` and `result` come from the |lsp-handler|.
+ ---@param bufnr (number) Buffer handle (0 for current).
+ ---@returns { err=err, result=result }, a dictionary, where `err` and `result` come from the |lsp-handler|.
---On timeout, cancel or error, returns `(nil, err)` where `err` is a
---string describing the failure reason. If the request was unsuccessful
---returns `nil`.
- --@see |vim.lsp.buf_request_sync()|
+ ---@see |vim.lsp.buf_request_sync()|
function client.request_sync(method, params, timeout_ms, bufnr)
local request_result = nil
- local function _sync_handler(err, _, result)
+ local function _sync_handler(err, result)
request_result = { err = err, result = result }
end
@@ -934,25 +936,25 @@ function lsp.start_client(config)
return request_result
end
- --@private
+ ---@private
--- Sends a notification to an LSP server.
---
- --@param method (string) LSP method name.
- --@param params (optional, table) LSP request params.
- --@param bufnr (number) Buffer handle, or 0 for current.
- --@returns {status} (bool) true if the notification was successful.
+ ---@param method (string) LSP method name.
+ ---@param params (optional, table) LSP request params.
+ ---@param bufnr (number) Buffer handle, or 0 for current.
+ ---@returns {status} (bool) true if the notification was successful.
---If it is false, then it will always be false
---(the client has shutdown).
function client.notify(...)
return rpc.notify(...)
end
- --@private
+ ---@private
--- Cancels a request with a given request id.
---
- --@param id (number) id of request to cancel
- --@returns true if any client returns true; false otherwise
- --@see |vim.lsp.client.notify()|
+ ---@param id (number) id of request to cancel
+ ---@returns true if any client returns true; false otherwise
+ ---@see |vim.lsp.client.notify()|
function client.cancel_request(id)
validate{id = {id, 'n'}}
return rpc.notify("$/cancelRequest", { id = id })
@@ -961,14 +963,14 @@ function lsp.start_client(config)
-- Track this so that we can escalate automatically if we've alredy tried a
-- graceful shutdown
local graceful_shutdown_failed = false
- --@private
+ ---@private
--- Stops a client, optionally with force.
---
---By default, it will just ask the - server to shutdown without force. If
--- you request to stop a client which has previously been requested to
--- shutdown, it will automatically escalate and force shutdown.
---
- --@param force (bool, optional)
+ ---@param force (bool, optional)
function client.stop(force)
lsp.diagnostic.reset(client_id, all_buffer_active_clients)
@@ -998,18 +1000,18 @@ function lsp.start_client(config)
end)
end
- --@private
+ ---@private
--- Checks whether a client is stopped.
---
- --@returns (bool) true if client is stopped or in the process of being
+ ---@returns (bool) true if client is stopped or in the process of being
---stopped; false otherwise
function client.is_stopped()
return rpc.handle:is_closing()
end
- --@private
+ ---@private
--- Runs the on_attach function from the client's config if it was defined.
- --@param bufnr (number) Buffer number
+ ---@param bufnr (number) Buffer number
function client._on_attach(bufnr)
text_document_did_open_handler(bufnr, client)
if config.on_attach then
@@ -1023,8 +1025,8 @@ function lsp.start_client(config)
return client_id
end
---@private
---@fn text_document_did_change_handler(_, bufnr, changedtick, firstline, lastline, new_lastline, old_byte_size, old_utf32_size, old_utf16_size)
+---@private
+---@fn text_document_did_change_handler(_, bufnr, changedtick, firstline, lastline, new_lastline, old_byte_size, old_utf32_size, old_utf16_size)
--- Notify all attached clients that a buffer has changed.
local text_document_did_change_handler
do
@@ -1074,8 +1076,8 @@ end
---
--- Without calling this, the server won't be notified of changes to a buffer.
---
---- @param bufnr (number) Buffer handle, or 0 for current
---- @param client_id (number) Client id
+---@param bufnr (number) Buffer handle, or 0 for current
+---@param client_id (number) Client id
function lsp.buf_attach_client(bufnr, client_id)
validate {
bufnr = {bufnr, 'n', true};
@@ -1150,23 +1152,23 @@ end
---@param bufnr (number) Buffer handle, or 0 for current
---@param client_id (number) the client id
function lsp.buf_is_attached(bufnr, client_id)
- return (all_buffer_active_clients[bufnr] or {})[client_id] == true
+ return (all_buffer_active_clients[resolve_bufnr(bufnr)] or {})[client_id] == true
end
--- Gets a client by id, or nil if the id is invalid.
--- The returned client may not yet be fully initialized.
--
---@param client_id client id number
+---@param client_id client id number
---
---@returns |vim.lsp.client| object, or nil
+---@returns |vim.lsp.client| object, or nil
function lsp.get_client_by_id(client_id)
return active_clients[client_id] or uninitialized_clients[client_id]
end
--- Returns list of buffers attached to client_id.
--
---@param client_id client id
---@returns list of buffer ids
+---@param client_id client id
+---@returns list of buffer ids
function lsp.get_buffers_by_client_id(client_id)
local active_client_buffers = all_client_active_buffers[client_id]
if active_client_buffers then
@@ -1188,8 +1190,8 @@ end
--- By default asks the server to shutdown, unless stop was requested
--- already for this client, then force-shutdown is attempted.
---
---@param client_id client id or |vim.lsp.client| object, or list thereof
---@param force boolean (optional) shutdown forcefully
+---@param client_id client id or |vim.lsp.client| object, or list thereof
+---@param force boolean (optional) shutdown forcefully
function lsp.stop_client(client_id, force)
local ids = type(client_id) == 'table' and client_id or {client_id}
for _, id in ipairs(ids) do
@@ -1205,7 +1207,7 @@ end
--- Gets all active clients.
---
---@returns Table of |vim.lsp.client| objects
+---@returns Table of |vim.lsp.client| objects
function lsp.get_active_clients()
return vim.tbl_values(active_clients)
end
@@ -1236,13 +1238,13 @@ nvim_command("autocmd VimLeavePre * lua vim.lsp._vim_exit_handler()")
--- Sends an async request for all active clients attached to the
--- buffer.
---
---@param bufnr (number) Buffer handle, or 0 for current.
---@param method (string) LSP method name
---@param params (optional, table) Parameters to send to the server
---@param handler (optional, function) See |lsp-handler|
+---@param bufnr (number) Buffer handle, or 0 for current.
+---@param method (string) LSP method name
+---@param params (optional, table) Parameters to send to the server
+---@param handler (optional, function) See |lsp-handler|
-- If nil, follows resolution strategy defined in |lsp-handler-configuration|
--
---@returns 2-tuple:
+---@returns 2-tuple:
--- - Map of client-id:request-id pairs for all successful requests.
--- - Function which can be used to cancel all the requests. You could instead
--- iterate all clients and call their `cancel_request()` methods.
@@ -1274,7 +1276,7 @@ function lsp.buf_request(bufnr, method, params, handler)
local unsupported_err = lsp._unsupported_method(method)
handler = handler or lsp.handlers[method]
if handler then
- handler(unsupported_err, method, bufnr)
+ handler(unsupported_err, nil, {method=method, bufnr=bufnr})
end
return
end
@@ -1294,14 +1296,14 @@ end
---Parameters are the same as |vim.lsp.buf_request()| but the return result and callback are
---different.
---
---@param bufnr (number) Buffer handle, or 0 for current.
---@param method (string) LSP method name
---@param params (optional, table) Parameters to send to the server
---@param callback (function) The callback to call when all requests are finished.
+---@param bufnr (number) Buffer handle, or 0 for current.
+---@param method (string) LSP method name
+---@param params (optional, table) Parameters to send to the server
+---@param callback (function) The callback to call when all requests are finished.
-- Unlike `buf_request`, this will collect all the responses from each server instead of handling them.
-- A map of client_id:request_result will be provided to the callback
--
---@returns (function) A function that will cancel all requests which is the same as the one returned from `buf_request`.
+---@returns (function) A function that will cancel all requests which is the same as the one returned from `buf_request`.
function lsp.buf_request_all(bufnr, method, params, callback)
local request_results = {}
local result_count = 0
@@ -1314,8 +1316,8 @@ function lsp.buf_request_all(bufnr, method, params, callback)
end
end)
- local function _sync_handler(err, _, result, client_id)
- request_results[client_id] = { error = err, result = result }
+ local function _sync_handler(err, result, ctx)
+ request_results[ctx.client_id] = { error = err, result = result }
result_count = result_count + 1
set_expected_result_count()
@@ -1335,13 +1337,13 @@ end
--- Parameters are the same as |vim.lsp.buf_request()| but the return result is
--- different. Wait maximum of {timeout_ms} (default 1000) ms.
---
---@param bufnr (number) Buffer handle, or 0 for current.
---@param method (string) LSP method name
---@param params (optional, table) Parameters to send to the server
---@param timeout_ms (optional, number, default=1000) Maximum time in
+---@param bufnr (number) Buffer handle, or 0 for current.
+---@param method (string) LSP method name
+---@param params (optional, table) Parameters to send to the server
+---@param timeout_ms (optional, number, default=1000) Maximum time in
--- milliseconds to wait for a result.
---
---@returns Map of client_id:request_result. On timeout, cancel or error,
+---@returns Map of client_id:request_result. On timeout, cancel or error,
--- returns `(nil, err)` where `err` is a string describing the failure
--- reason.
function lsp.buf_request_sync(bufnr, method, params, timeout_ms)
@@ -1364,11 +1366,11 @@ function lsp.buf_request_sync(bufnr, method, params, timeout_ms)
end
--- Send a notification to a server
---@param bufnr [number] (optional): The number of the buffer
---@param method [string]: Name of the request method
---@param params [string]: Arguments to send to the server
+---@param bufnr [number] (optional): The number of the buffer
+---@param method [string]: Name of the request method
+---@param params [string]: Arguments to send to the server
---
---@returns true if any client returns true; false otherwise
+---@returns true if any client returns true; false otherwise
function lsp.buf_notify(bufnr, method, params)
validate {
bufnr = { bufnr, 'n', true };
@@ -1383,14 +1385,14 @@ end
--- Implements 'omnifunc' compatible LSP completion.
---
---@see |complete-functions|
---@see |complete-items|
---@see |CompleteDone|
+---@see |complete-functions|
+---@see |complete-items|
+---@see |CompleteDone|
---
---@param findstart 0 or 1, decides behavior
---@param base If findstart=0, text to match against
+---@param findstart 0 or 1, decides behavior
+---@param base If findstart=0, text to match against
---
---@returns (number) Decided by `findstart`:
+---@returns (number) Decided by `findstart`:
--- - findstart=0: column where the completion starts, or -2 or -3
--- - findstart=1: list of matches (actually just calls |complete()|)
function lsp.omnifunc(findstart, base)
@@ -1421,7 +1423,7 @@ function lsp.omnifunc(findstart, base)
local params = util.make_position_params()
local items = {}
- lsp.buf_request(bufnr, 'textDocument/completion', params, function(err, _, result)
+ lsp.buf_request(bufnr, 'textDocument/completion', params, function(err, result)
if err or not result or vim.fn.mode() ~= "i" then return end
local matches = util.text_document_completion_list_to_complete_items(result, prefix)
-- TODO(ashkan): is this the best way to do this?
@@ -1436,8 +1438,8 @@ end
---Checks whether a client is stopped.
---
---@param client_id (Number)
---@returns true if client is stopped, false otherwise.
+---@param client_id (Number)
+---@returns true if client is stopped, false otherwise.
function lsp.client_is_stopped(client_id)
return active_clients[client_id] == nil
end
@@ -1445,7 +1447,7 @@ end
--- Gets a map of client_id:client pairs for the given buffer, where each value
--- is a |vim.lsp.client| object.
---
---@param bufnr (optional, number): Buffer handle, or 0 for current
+---@param bufnr (optional, number): Buffer handle, or 0 for current
function lsp.buf_get_clients(bufnr)
bufnr = resolve_bufnr(bufnr)
local result = {}
@@ -1470,9 +1472,9 @@ lsp.log_levels = log.levels
---
--- Use `lsp.log_levels` for reverse lookup.
---
---@see |vim.lsp.log_levels|
+---@see |vim.lsp.log_levels|
---
---@param level [number|string] the case insensitive level name or number
+---@param level [number|string] the case insensitive level name or number
function lsp.set_log_level(level)
if type(level) == 'string' or type(level) == 'number' then
log.set_level(level)
@@ -1482,7 +1484,7 @@ function lsp.set_log_level(level)
end
--- Gets the path of the logfile used by the LSP client.
---@returns (String) Path to logfile.
+---@returns (String) Path to logfile.
function lsp.get_log_path()
return log.get_filename()
end
@@ -1493,11 +1495,11 @@ function lsp.for_each_buffer_client(bufnr, fn)
end
--- Function to manage overriding defaults for LSP handlers.
---@param handler (function) See |lsp-handler|
---@param override_config (table) Table containing the keys to override behavior of the {handler}
+---@param handler (function) See |lsp-handler|
+---@param override_config (table) Table containing the keys to override behavior of the {handler}
function lsp.with(handler, override_config)
- return function(err, method, params, client_id, bufnr, config)
- return handler(err, method, params, client_id, bufnr, vim.tbl_deep_extend("force", config or {}, override_config))
+ return function(err, result, ctx, config)
+ return handler(err, result, ctx, vim.tbl_deep_extend("force", config or {}, override_config))
end
end
@@ -1532,8 +1534,34 @@ function lsp._with_extend(name, options, user_config)
return resulting_config
end
--- Define the LspDiagnostics signs if they're not defined already.
-require('vim.lsp.diagnostic')._define_default_signs_and_highlights()
+
+--- Registry for client side commands.
+--- This is an extension point for plugins to handle custom commands which are
+--- not part of the core language server protocol specification.
+---
+--- The registry is a table where the key is a unique command name,
+--- and the value is a function which is called if any LSP action
+--- (code action, code lenses, ...) triggers the command.
+---
+--- If a LSP response contains a command for which no matching entry is
+--- available in this registry, the command will be executed via the LSP server
+--- using `workspace/executeCommand`.
+---
+--- The first argument to the function will be the `Command`:
+-- Command
+-- title: String
+-- command: String
+-- arguments?: any[]
+--
+--- The second argument is the `ctx` of |lsp-handler|
+lsp.commands = setmetatable({}, {
+ __newindex = function(tbl, key, value)
+ assert(type(key) == 'string', "The key for commands in `vim.lsp.commands` must be a string")
+ assert(type(value) == 'function', "Command added to `vim.lsp.commands` must be a function")
+ rawset(tbl, key, value)
+ end;
+})
+
return lsp
-- vim:sw=2 ts=2 et
diff --git a/runtime/lua/vim/lsp/_snippet.lua b/runtime/lua/vim/lsp/_snippet.lua
new file mode 100644
index 0000000000..0140b0aee3
--- /dev/null
+++ b/runtime/lua/vim/lsp/_snippet.lua
@@ -0,0 +1,399 @@
+local P = {}
+
+---Take characters until the target characters (The escape sequence is '\' + char)
+---@param targets string[] The character list for stop consuming text.
+---@param specials string[] If the character isn't contained in targets/specials, '\' will be left.
+P.take_until = function(targets, specials)
+ targets = targets or {}
+ specials = specials or {}
+
+ return function(input, pos)
+ local new_pos = pos
+ local raw = {}
+ local esc = {}
+ while new_pos <= #input do
+ local c = string.sub(input, new_pos, new_pos)
+ if c == '\\' then
+ table.insert(raw, '\\')
+ new_pos = new_pos + 1
+ c = string.sub(input, new_pos, new_pos)
+ if not vim.tbl_contains(targets, c) and not vim.tbl_contains(specials, c) then
+ table.insert(esc, '\\')
+ end
+ table.insert(raw, c)
+ table.insert(esc, c)
+ new_pos = new_pos + 1
+ else
+ if vim.tbl_contains(targets, c) then
+ break
+ end
+ table.insert(raw, c)
+ table.insert(esc, c)
+ new_pos = new_pos + 1
+ end
+ end
+
+ if new_pos == pos then
+ return P.unmatch(pos)
+ end
+
+ return {
+ parsed = true,
+ value = {
+ raw = table.concat(raw, ''),
+ esc = table.concat(esc, '')
+ },
+ pos = new_pos,
+ }
+ end
+end
+
+P.unmatch = function(pos)
+ return {
+ parsed = false,
+ value = nil,
+ pos = pos,
+ }
+end
+
+P.map = function(parser, map)
+ return function(input, pos)
+ local result = parser(input, pos)
+ if result.parsed then
+ return {
+ parsed = true,
+ value = map(result.value),
+ pos = result.pos,
+ }
+ end
+ return P.unmatch(pos)
+ end
+end
+
+P.lazy = function(factory)
+ return function(input, pos)
+ return factory()(input, pos)
+ end
+end
+
+P.token = function(token)
+ return function(input, pos)
+ local maybe_token = string.sub(input, pos, pos + #token - 1)
+ if token == maybe_token then
+ return {
+ parsed = true,
+ value = maybe_token,
+ pos = pos + #token,
+ }
+ end
+ return P.unmatch(pos)
+ end
+end
+
+P.pattern = function(p)
+ return function(input, pos)
+ local maybe_match = string.match(string.sub(input, pos), '^' .. p)
+ if maybe_match then
+ return {
+ parsed = true,
+ value = maybe_match,
+ pos = pos + #maybe_match,
+ }
+ end
+ return P.unmatch(pos)
+ end
+end
+
+P.many = function(parser)
+ return function(input, pos)
+ local values = {}
+ local new_pos = pos
+ while new_pos <= #input do
+ local result = parser(input, new_pos)
+ if not result.parsed then
+ break
+ end
+ table.insert(values, result.value)
+ new_pos = result.pos
+ end
+ if #values > 0 then
+ return {
+ parsed = true,
+ value = values,
+ pos = new_pos,
+ }
+ end
+ return P.unmatch(pos)
+ end
+end
+
+P.any = function(...)
+ local parsers = { ... }
+ return function(input, pos)
+ for _, parser in ipairs(parsers) do
+ local result = parser(input, pos)
+ if result.parsed then
+ return result
+ end
+ end
+ return P.unmatch(pos)
+ end
+end
+
+P.opt = function(parser)
+ return function(input, pos)
+ local result = parser(input, pos)
+ return {
+ parsed = true,
+ value = result.value,
+ pos = result.pos,
+ }
+ end
+end
+
+P.seq = function(...)
+ local parsers = { ... }
+ return function(input, pos)
+ local values = {}
+ local new_pos = pos
+ for _, parser in ipairs(parsers) do
+ local result = parser(input, new_pos)
+ if result.parsed then
+ table.insert(values, result.value)
+ new_pos = result.pos
+ else
+ return P.unmatch(pos)
+ end
+ end
+ return {
+ parsed = true,
+ value = values,
+ pos = new_pos,
+ }
+ end
+end
+
+local Node = {}
+
+Node.Type = {
+ SNIPPET = 0,
+ TABSTOP = 1,
+ PLACEHOLDER = 2,
+ VARIABLE = 3,
+ CHOICE = 4,
+ TRANSFORM = 5,
+ FORMAT = 6,
+ TEXT = 7,
+}
+
+function Node:__tostring()
+ local insert_text = {}
+ if self.type == Node.Type.SNIPPET then
+ for _, c in ipairs(self.children) do
+ table.insert(insert_text, tostring(c))
+ end
+ elseif self.type == Node.Type.CHOICE then
+ table.insert(insert_text, self.items[1])
+ elseif self.type == Node.Type.PLACEHOLDER then
+ for _, c in ipairs(self.children or {}) do
+ table.insert(insert_text, tostring(c))
+ end
+ elseif self.type == Node.Type.TEXT then
+ table.insert(insert_text, self.esc)
+ end
+ return table.concat(insert_text, '')
+end
+
+--@see https://code.visualstudio.com/docs/editor/userdefinedsnippets#_grammar
+
+local S = {}
+S.dollar = P.token('$')
+S.open = P.token('{')
+S.close = P.token('}')
+S.colon = P.token(':')
+S.slash = P.token('/')
+S.comma = P.token(',')
+S.pipe = P.token('|')
+S.plus = P.token('+')
+S.minus = P.token('-')
+S.question = P.token('?')
+S.int = P.map(P.pattern('[0-9]+'), function(value)
+ return tonumber(value, 10)
+end)
+S.var = P.pattern('[%a_][%w_]+')
+S.text = function(targets, specials)
+ return P.map(P.take_until(targets, specials), function(value)
+ return setmetatable({
+ type = Node.Type.TEXT,
+ raw = value.raw,
+ esc = value.esc,
+ }, Node)
+ end)
+end
+
+S.toplevel = P.lazy(function()
+ return P.any(S.placeholder, S.tabstop, S.variable, S.choice)
+end)
+
+S.format = P.any(
+ P.map(P.seq(S.dollar, S.int), function(values)
+ return setmetatable({
+ type = Node.Type.FORMAT,
+ capture_index = values[2],
+ }, Node)
+ end),
+ P.map(P.seq(S.dollar, S.open, S.int, S.close), function(values)
+ return setmetatable({
+ type = Node.Type.FORMAT,
+ capture_index = values[3],
+ }, Node)
+ end),
+ P.map(P.seq(S.dollar, S.open, S.int, S.colon, S.slash, P.any(
+ P.token('upcase'),
+ P.token('downcase'),
+ P.token('capitalize'),
+ P.token('camelcase'),
+ P.token('pascalcase')
+ ), S.close), function(values)
+ return setmetatable({
+ type = Node.Type.FORMAT,
+ capture_index = values[3],
+ modifier = values[6],
+ }, Node)
+ end),
+ P.map(P.seq(S.dollar, S.open, S.int, S.colon, P.any(
+ P.seq(S.question, P.take_until({ ':' }, { '\\' }), S.colon, P.take_until({ '}' }, { '\\' })),
+ P.seq(S.plus, P.take_until({ '}' }, { '\\' })),
+ P.seq(S.minus, P.take_until({ '}' }, { '\\' }))
+ ), S.close), function(values)
+ return setmetatable({
+ type = Node.Type.FORMAT,
+ capture_index = values[3],
+ if_text = values[5][2].esc,
+ else_text = (values[5][4] or {}).esc,
+ }, Node)
+ end)
+)
+
+S.transform = P.map(P.seq(
+ S.slash,
+ P.take_until({ '/' }, { '\\' }),
+ S.slash,
+ P.many(P.any(S.format, S.text({ '$', '/' }, { '\\' }))),
+ S.slash,
+ P.opt(P.pattern('[ig]+'))
+), function(values)
+ return setmetatable({
+ type = Node.Type.TRANSFORM,
+ pattern = values[2].raw,
+ format = values[4],
+ option = values[6],
+ }, Node)
+end)
+
+S.tabstop = P.any(
+ P.map(P.seq(S.dollar, S.int), function(values)
+ return setmetatable({
+ type = Node.Type.TABSTOP,
+ tabstop = values[2],
+ }, Node)
+ end),
+ P.map(P.seq(S.dollar, S.open, S.int, S.close), function(values)
+ return setmetatable({
+ type = Node.Type.TABSTOP,
+ tabstop = values[3],
+ }, Node)
+ end),
+ P.map(P.seq(S.dollar, S.open, S.int, S.transform, S.close), function(values)
+ return setmetatable({
+ type = Node.Type.TABSTOP,
+ tabstop = values[3],
+ transform = values[4],
+ }, Node)
+ end)
+)
+
+S.placeholder = P.any(
+ P.map(P.seq(S.dollar, S.open, S.int, S.colon, P.many(P.any(S.toplevel, S.text({ '$', '}' }, { '\\' }))), S.close), function(values)
+ return setmetatable({
+ type = Node.Type.PLACEHOLDER,
+ tabstop = values[3],
+ children = values[5],
+ }, Node)
+ end)
+)
+
+S.choice = P.map(P.seq(
+ S.dollar,
+ S.open,
+ S.int,
+ S.pipe,
+ P.many(
+ P.map(P.seq(S.text({ ',', '|' }), P.opt(S.comma)), function(values)
+ return values[1].esc
+ end)
+ ),
+ S.pipe,
+ S.close
+), function(values)
+ return setmetatable({
+ type = Node.Type.CHOICE,
+ tabstop = values[3],
+ items = values[5],
+ }, Node)
+end)
+
+S.variable = P.any(
+ P.map(P.seq(S.dollar, S.var), function(values)
+ return setmetatable({
+ type = Node.Type.VARIABLE,
+ name = values[2],
+ }, Node)
+ end),
+ P.map(P.seq(S.dollar, S.open, S.var, S.close), function(values)
+ return setmetatable({
+ type = Node.Type.VARIABLE,
+ name = values[3],
+ }, Node)
+ end),
+ P.map(P.seq(S.dollar, S.open, S.var, S.transform, S.close), function(values)
+ return setmetatable({
+ type = Node.Type.VARIABLE,
+ name = values[3],
+ transform = values[4],
+ }, Node)
+ end),
+ P.map(P.seq(S.dollar, S.open, S.var, S.colon, P.many(P.any(S.toplevel, S.text({ '$', '}' }, { '\\' }))), S.close), function(values)
+ return setmetatable({
+ type = Node.Type.VARIABLE,
+ name = values[3],
+ children = values[5],
+ }, Node)
+ end)
+)
+
+S.snippet = P.map(P.many(P.any(S.toplevel, S.text({ '$' }, { '}', '\\' }))), function(values)
+ return setmetatable({
+ type = Node.Type.SNIPPET,
+ children = values,
+ }, Node)
+end)
+
+local M = {}
+
+---The snippet node type enum
+---@types table<string, number>
+M.NodeType = Node.Type
+
+---Parse snippet string and returns the AST
+---@param input string
+---@return table
+function M.parse(input)
+ local result = S.snippet(input, 1)
+ if not result.parsed then
+ error('snippet parsing failed.')
+ end
+ return result.value
+end
+
+return M
diff --git a/runtime/lua/vim/lsp/buf.lua b/runtime/lua/vim/lsp/buf.lua
index b13d662ccb..245f29943e 100644
--- a/runtime/lua/vim/lsp/buf.lua
+++ b/runtime/lua/vim/lsp/buf.lua
@@ -5,7 +5,7 @@ local util = require 'vim.lsp.util'
local M = {}
---@private
+---@private
--- Returns nil if {status} is false or nil, otherwise returns the rest of the
--- arguments.
local function ok_or_nil(status, ...)
@@ -13,31 +13,31 @@ local function ok_or_nil(status, ...)
return ...
end
---@private
+---@private
--- Swallows errors.
---
---@param fn Function to run
---@param ... Function arguments
---@returns Result of `fn(...)` if there are no errors, otherwise nil.
+---@param fn Function to run
+---@param ... Function arguments
+---@returns Result of `fn(...)` if there are no errors, otherwise nil.
--- Returns nil if errors occur during {fn}, otherwise returns
local function npcall(fn, ...)
return ok_or_nil(pcall(fn, ...))
end
---@private
+---@private
--- Sends an async request to all active clients attached to the current
--- buffer.
---
---@param method (string) LSP method name
---@param params (optional, table) Parameters to send to the server
---@param handler (optional, functionnil) See |lsp-handler|. Follows |lsp-handler-resolution|
+---@param method (string) LSP method name
+---@param params (optional, table) Parameters to send to the server
+---@param handler (optional, functionnil) See |lsp-handler|. Follows |lsp-handler-resolution|
--
---@returns 2-tuple:
+---@returns 2-tuple:
--- - Map of client-id:request-id pairs for all successful requests.
--- - Function which can be used to cancel all the requests. You could instead
--- iterate all clients and call their `cancel_request()` methods.
---
---@see |vim.lsp.buf_request()|
+---@see |vim.lsp.buf_request()|
local function request(method, params, handler)
validate {
method = {method, 's'};
@@ -49,7 +49,7 @@ end
--- Checks whether the language servers attached to the current buffer are
--- ready.
---
---@returns `true` if server responds.
+---@returns `true` if server responds.
function M.server_ready()
return not not vim.lsp.buf_notify(0, "window/progress", {})
end
@@ -62,7 +62,7 @@ function M.hover()
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.
+---@note Many servers do not implement this method. Generally, see |vim.lsp.buf.definition()| instead.
---
function M.declaration()
local params = util.make_position_params()
@@ -100,22 +100,22 @@ end
--- Retrieves the completion items at the current cursor position. Can only be
--- called in Insert mode.
---
---@param context (context support not yet implemented) Additional information
+---@param context (context support not yet implemented) Additional information
--- about the context in which a completion was triggered (how it was triggered,
--- and by which trigger character, if applicable)
---
---@see |vim.lsp.protocol.constants.CompletionTriggerKind|
+---@see |vim.lsp.protocol.constants.CompletionTriggerKind|
function M.completion(context)
local params = util.make_position_params()
params.context = context
return request('textDocument/completion', params)
end
---@private
+---@private
--- If there is more than one client that supports the given method,
--- asks the user to select one.
--
---@returns The client that the user selected or nil
+---@returns The client that the user selected or nil
local function select_client(method)
local clients = vim.tbl_values(vim.lsp.buf_get_clients());
clients = vim.tbl_filter(function (client)
@@ -126,7 +126,7 @@ local function select_client(method)
if #clients > 1 then
local choices = {}
- for k,v in ipairs(clients) do
+ for k,v in pairs(clients) do
table.insert(choices, string.format("%d %s", k, v.name))
end
local user_choice = vim.fn.confirm(
@@ -146,11 +146,11 @@ end
--- Formats the current buffer.
---
---@param options (optional, table) Can be used to specify FormattingOptions.
+---@param options (optional, table) Can be used to specify FormattingOptions.
--- Some unspecified options will be automatically derived from the current
--- Neovim options.
--
---@see https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting
+---@see https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting
function M.formatting(options)
local client = select_client("textDocument/formatting")
if client == nil then return end
@@ -168,9 +168,9 @@ end
--- vim.api.nvim_command[[autocmd BufWritePre <buffer> lua vim.lsp.buf.formatting_sync()]]
--- </pre>
---
---@param options Table with valid `FormattingOptions` entries
---@param timeout_ms (number) Request timeout
---@see |vim.lsp.buf.formatting_seq_sync|
+---@param options Table with valid `FormattingOptions` entries
+---@param timeout_ms (number) Request timeout
+---@see |vim.lsp.buf.formatting_seq_sync|
function M.formatting_sync(options, timeout_ms)
local client = select_client("textDocument/formatting")
if client == nil then return end
@@ -195,18 +195,18 @@ end
--- vim.api.nvim_command[[autocmd BufWritePre <buffer> lua vim.lsp.buf.formatting_seq_sync()]]
--- </pre>
---
---@param options (optional, table) `FormattingOptions` entries
---@param timeout_ms (optional, number) Request timeout
---@param order (optional, table) List of client names. Formatting is requested from clients
+---@param options (optional, table) `FormattingOptions` entries
+---@param timeout_ms (optional, number) Request timeout
+---@param order (optional, table) List of client names. Formatting is requested from clients
---in the following order: first all clients that are not in the `order` list, then
---the remaining clients in the order as they occur in the `order` list.
function M.formatting_seq_sync(options, timeout_ms, order)
local clients = vim.tbl_values(vim.lsp.buf_get_clients());
-- sort the clients according to `order`
- for _, client_name in ipairs(order or {}) do
+ for _, client_name in pairs(order or {}) do
-- if the client exists, move to the end of the list
- for i, client in ipairs(clients) do
+ for i, client in pairs(clients) do
if client.name == client_name then
table.insert(clients, table.remove(clients, i))
break
@@ -215,7 +215,7 @@ function M.formatting_seq_sync(options, timeout_ms, order)
end
-- loop through the clients and make synchronous formatting requests
- for _, client in ipairs(clients) do
+ for _, client in pairs(clients) do
if client.resolved_capabilities.document_formatting then
local params = util.make_formatting_params(options)
local result, err = client.request_sync("textDocument/formatting", params, timeout_ms, vim.api.nvim_get_current_buf())
@@ -230,10 +230,10 @@ end
--- Formats a given range.
---
---@param options Table with valid `FormattingOptions` entries.
---@param start_pos ({number, number}, optional) mark-indexed position.
+---@param options Table with valid `FormattingOptions` entries.
+---@param start_pos ({number, number}, optional) mark-indexed position.
---Defaults to the start of the last visual selection.
---@param end_pos ({number, number}, optional) mark-indexed position.
+---@param end_pos ({number, number}, optional) mark-indexed position.
---Defaults to the end of the last visual selection.
function M.range_formatting(options, start_pos, end_pos)
local client = select_client("textDocument/rangeFormatting")
@@ -246,29 +246,49 @@ end
--- Renames all references to the symbol under the cursor.
---
---@param new_name (string) If not provided, the user will be prompted for a new
+---@param new_name (string) If not provided, the user will be prompted for a new
---name using |input()|.
function M.rename(new_name)
- -- TODO(ashkan) use prepareRename
- -- * result: [`Range`](#range) \| `{ range: Range, placeholder: string }` \| `null` describing the range of the string to rename and optionally a placeholder text of the string content to be renamed. If `null` is returned then it is deemed that a 'textDocument/rename' request is not valid at the given position.
local params = util.make_position_params()
- new_name = new_name or npcall(vfn.input, "New Name: ", vfn.expand('<cword>'))
- if not (new_name and #new_name > 0) then return end
- params.newName = new_name
- request('textDocument/rename', params)
+ local function prepare_rename(err, result)
+ if err == nil and result == nil then
+ vim.notify('nothing to rename', vim.log.levels.INFO)
+ return
+ end
+ if result and result.placeholder then
+ new_name = new_name or npcall(vfn.input, "New Name: ", result.placeholder)
+ elseif result and result.start and result['end'] and
+ result.start.line == result['end'].line then
+ local line = vfn.getline(result.start.line+1)
+ local start_char = result.start.character+1
+ local end_char = result['end'].character
+ new_name = new_name or npcall(vfn.input, "New Name: ", string.sub(line, start_char, end_char))
+ else
+ -- fallback to guessing symbol using <cword>
+ --
+ -- this can happen if the language server does not support prepareRename,
+ -- returns an unexpected response, or requests for "default behavior"
+ --
+ -- see https://microsoft.github.io/language-server-protocol/specification#textDocument_prepareRename
+ new_name = new_name or npcall(vfn.input, "New Name: ", vfn.expand('<cword>'))
+ end
+ if not (new_name and #new_name > 0) then return end
+ params.newName = new_name
+ request('textDocument/rename', params)
+ end
+ request('textDocument/prepareRename', params, prepare_rename)
end
--- Lists all the references to the symbol under the cursor in the quickfix window.
---
---@param context (table) Context for the request
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references
+---@param context (table) Context for the request
+---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references
function M.references(context)
validate { context = { context, 't', true } }
local params = util.make_position_params()
params.context = context or {
includeDeclaration = true;
}
- params[vim.type_idx] = vim.types.dictionary
request('textDocument/references', params)
end
@@ -279,14 +299,14 @@ function M.document_symbol()
request('textDocument/documentSymbol', params)
end
---@private
+---@private
local function pick_call_hierarchy_item(call_hierarchy_items)
if not call_hierarchy_items then return end
if #call_hierarchy_items == 1 then
return call_hierarchy_items[1]
end
local items = {}
- for i, item in ipairs(call_hierarchy_items) do
+ for i, item in pairs(call_hierarchy_items) do
local entry = item.detail or item.name
table.insert(items, string.format("%d. %s", i, entry))
end
@@ -297,16 +317,24 @@ local function pick_call_hierarchy_item(call_hierarchy_items)
return choice
end
---@private
+---@private
local function call_hierarchy(method)
local params = util.make_position_params()
- request('textDocument/prepareCallHierarchy', params, function(err, _, result)
+ request('textDocument/prepareCallHierarchy', params, function(err, result, ctx)
if err then
vim.notify(err.message, vim.log.levels.WARN)
return
end
local call_hierarchy_item = pick_call_hierarchy_item(result)
- vim.lsp.buf_request(0, method, { item = call_hierarchy_item })
+ local client = vim.lsp.get_client_by_id(ctx.client_id)
+ if client then
+ client.request(method, { item = call_hierarchy_item }, nil, ctx.bufnr)
+ else
+ vim.notify(string.format(
+ 'Client with id=%d disappeared during call hierarchy request', ctx.client_id),
+ vim.log.levels.WARN
+ )
+ end
end)
end
@@ -328,8 +356,8 @@ end
---
function M.list_workspace_folders()
local workspace_folders = {}
- for _, client in ipairs(vim.lsp.buf_get_clients()) do
- for _, folder in ipairs(client.workspaceFolders) do
+ for _, client in pairs(vim.lsp.buf_get_clients()) do
+ for _, folder in pairs(client.workspaceFolders) do
table.insert(workspace_folders, folder.name)
end
end
@@ -347,9 +375,9 @@ function M.add_workspace_folder(workspace_folder)
return
end
local params = util.make_workspace_params({{uri = vim.uri_from_fname(workspace_folder); name = workspace_folder}}, {{}})
- for _, client in ipairs(vim.lsp.buf_get_clients()) do
+ for _, client in pairs(vim.lsp.buf_get_clients()) do
local found = false
- for _, folder in ipairs(client.workspaceFolders) do
+ for _, folder in pairs(client.workspaceFolders) do
if folder.name == workspace_folder then
found = true
print(workspace_folder, "is already part of this workspace")
@@ -371,8 +399,8 @@ function M.remove_workspace_folder(workspace_folder)
vim.api.nvim_command("redraw")
if not (workspace_folder and #workspace_folder > 0) then return end
local params = util.make_workspace_params({{}}, {{uri = vim.uri_from_fname(workspace_folder); name = workspace_folder}})
- for _, client in ipairs(vim.lsp.buf_get_clients()) do
- for idx, folder in ipairs(client.workspaceFolders) do
+ for _, client in pairs(vim.lsp.buf_get_clients()) do
+ for idx, folder in pairs(client.workspaceFolders) do
if folder.name == workspace_folder then
vim.lsp.buf_notify(0, 'workspace/didChangeWorkspaceFolders', params)
client.workspaceFolders[idx] = nil
@@ -389,7 +417,7 @@ end
--- call, the user is prompted to enter a string on the command line. An empty
--- string means no filtering is done.
---
---@param query (string, optional)
+---@param query (string, optional)
function M.workspace_symbol(query)
query = query or npcall(vfn.input, "Query: ")
local params = {query = query}
@@ -422,38 +450,157 @@ function M.clear_references()
util.buf_clear_references()
end
---- Selects a code action from the input list that is available at the current
---- cursor position.
+
+---@private
--
---@param context: (table, optional) Valid `CodeActionContext` object
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction
+--- This is not public because the main extension point is
+--- vim.ui.select which can be overridden independently.
+---
+--- Can't call/use vim.lsp.handlers['textDocument/codeAction'] because it expects
+--- `(err, CodeAction[] | Command[], ctx)`, but we want to aggregate the results
+--- from multiple clients to have 1 single UI prompt for the user, yet we still
+--- need to be able to link a `CodeAction|Command` to the right client for
+--- `codeAction/resolve`
+local function on_code_action_results(results, ctx)
+ local action_tuples = {}
+ for client_id, result in pairs(results) do
+ for _, action in pairs(result.result or {}) do
+ table.insert(action_tuples, { client_id, action })
+ end
+ end
+ if #action_tuples == 0 then
+ vim.notify('No code actions available', vim.log.levels.INFO)
+ return
+ end
+
+ ---@private
+ local function apply_action(action, client)
+ if action.edit then
+ util.apply_workspace_edit(action.edit)
+ end
+ if action.command then
+ local command = type(action.command) == 'table' and action.command or action
+ local fn = vim.lsp.commands[command.command]
+ if fn then
+ local enriched_ctx = vim.deepcopy(ctx)
+ enriched_ctx.client_id = client.id
+ fn(command, ctx)
+ else
+ M.execute_command(command)
+ end
+ end
+ end
+
+ ---@private
+ local function on_user_choice(action_tuple)
+ if not action_tuple then
+ return
+ end
+ -- textDocument/codeAction can return either Command[] or CodeAction[]
+ --
+ -- CodeAction
+ -- ...
+ -- edit?: WorkspaceEdit -- <- must be applied before command
+ -- command?: Command
+ --
+ -- Command:
+ -- title: string
+ -- command: string
+ -- arguments?: any[]
+ --
+ local client = vim.lsp.get_client_by_id(action_tuple[1])
+ local action = action_tuple[2]
+ if not action.edit
+ and client
+ and type(client.resolved_capabilities.code_action) == 'table'
+ and client.resolved_capabilities.code_action.resolveProvider then
+
+ client.request('codeAction/resolve', action, function(err, resolved_action)
+ if err then
+ vim.notify(err.code .. ': ' .. err.message, vim.log.levels.ERROR)
+ return
+ end
+ apply_action(resolved_action, client)
+ end)
+ else
+ apply_action(action, client)
+ end
+ end
+
+ vim.ui.select(action_tuples, {
+ prompt = 'Code actions:',
+ format_item = function(action_tuple)
+ local title = action_tuple[2].title:gsub('\r\n', '\\r\\n')
+ return title:gsub('\n', '\\n')
+ end,
+ }, on_user_choice)
+end
+
+
+--- Requests code actions from all clients and calls the handler exactly once
+--- with all aggregated results
+---@private
+local function code_action_request(params)
+ local bufnr = vim.api.nvim_get_current_buf()
+ local method = 'textDocument/codeAction'
+ vim.lsp.buf_request_all(bufnr, method, params, function(results)
+ on_code_action_results(results, { bufnr = bufnr, method = method, params = params })
+ end)
+end
+
+--- Selects a code action available at the current
+--- cursor position.
+---
+---@param context table|nil `CodeActionContext` of the LSP specification:
+--- - diagnostics: (table|nil)
+--- LSP `Diagnostic[]`. Inferred from the current
+--- position if not provided.
+--- - only: (string|nil)
+--- LSP `CodeActionKind` used to filter the code actions.
+--- Most language servers support values like `refactor`
+--- or `quickfix`.
+---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction
function M.code_action(context)
validate { context = { context, 't', true } }
- context = context or { diagnostics = vim.lsp.diagnostic.get_line_diagnostics() }
+ context = context or {}
+ if not context.diagnostics then
+ context.diagnostics = vim.lsp.diagnostic.get_line_diagnostics()
+ end
local params = util.make_range_params()
params.context = context
- request('textDocument/codeAction', params)
+ code_action_request(params)
end
--- Performs |vim.lsp.buf.code_action()| for a given range.
---
---@param context: (table, optional) Valid `CodeActionContext` object
---@param start_pos ({number, number}, optional) mark-indexed position.
+---
+---@param context table|nil `CodeActionContext` of the LSP specification:
+--- - diagnostics: (table|nil)
+--- LSP `Diagnostic[]`. Inferred from the current
+--- position if not provided.
+--- - only: (string|nil)
+--- LSP `CodeActionKind` used to filter the code actions.
+--- Most language servers support values like `refactor`
+--- or `quickfix`.
+---@param start_pos ({number, number}, optional) mark-indexed position.
---Defaults to the start of the last visual selection.
---@param end_pos ({number, number}, optional) mark-indexed position.
+---@param end_pos ({number, number}, optional) mark-indexed position.
---Defaults to the end of the last visual selection.
function M.range_code_action(context, start_pos, end_pos)
validate { context = { context, 't', true } }
- context = context or { diagnostics = vim.lsp.diagnostic.get_line_diagnostics() }
+ context = context or {}
+ if not context.diagnostics then
+ context.diagnostics = vim.lsp.diagnostic.get_line_diagnostics()
+ end
local params = util.make_given_range_params(start_pos, end_pos)
params.context = context
- request('textDocument/codeAction', params)
+ code_action_request(params)
end
--- Executes an LSP server command.
---
---@param command A valid `ExecuteCommandParams` object
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand
+---@param command A valid `ExecuteCommandParams` object
+---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand
function M.execute_command(command)
validate {
command = { command.command, 's' },
diff --git a/runtime/lua/vim/lsp/codelens.lua b/runtime/lua/vim/lsp/codelens.lua
index fbd37e3830..20b203fe99 100644
--- a/runtime/lua/vim/lsp/codelens.lua
+++ b/runtime/lua/vim/lsp/codelens.lua
@@ -22,19 +22,33 @@ local namespaces = setmetatable({}, {
end;
})
---@private
+---@private
M.__namespaces = namespaces
---@private
+---@private
local function execute_lens(lens, bufnr, client_id)
local line = lens.range.start.line
api.nvim_buf_clear_namespace(bufnr, namespaces[client_id], line, line + 1)
+ local command = lens.command
+ local fn = vim.lsp.commands[command.command]
+ if fn then
+ fn(command, { bufnr = bufnr, client_id = client_id })
+ return
+ end
-- Need to use the client that returned the lens → must not use buf_request
local client = vim.lsp.get_client_by_id(client_id)
assert(client, 'Client is required to execute lens, client_id=' .. client_id)
- client.request('workspace/executeCommand', lens.command, function(...)
+ local command_provider = client.server_capabilities.executeCommandProvider
+ local commands = type(command_provider) == 'table' and command_provider.commands or {}
+ if not vim.tbl_contains(commands, command.command) then
+ vim.notify(string.format(
+ "Language server does not support command `%s`. This command may require a client extension.", command.command),
+ vim.log.levels.WARN)
+ return
+ end
+ client.request('workspace/executeCommand', command, function(...)
local result = vim.lsp.handlers['workspace/executeCommand'](...)
M.refresh()
return result
@@ -44,9 +58,10 @@ end
--- Return all lenses for the given buffer
---
+---@param bufnr number Buffer number. 0 can be used for the current buffer.
---@return table (`CodeLens[]`)
function M.get(bufnr)
- local lenses_by_client = lens_cache_by_buf[bufnr]
+ local lenses_by_client = lens_cache_by_buf[bufnr or 0]
if not lenses_by_client then return {} end
local lenses = {}
for _, client_lenses in pairs(lenses_by_client) do
@@ -111,15 +126,19 @@ function M.display(lenses, bufnr, client_id)
local ns = namespaces[client_id]
local num_lines = api.nvim_buf_line_count(bufnr)
for i = 0, num_lines do
- local line_lenses = lenses_by_lnum[i]
+ local line_lenses = lenses_by_lnum[i] or {}
api.nvim_buf_clear_namespace(bufnr, ns, i, i + 1)
local chunks = {}
- for _, lens in pairs(line_lenses or {}) do
+ local num_line_lenses = #line_lenses
+ for j, lens in ipairs(line_lenses) do
local text = lens.command and lens.command.title or 'Unresolved lens ...'
table.insert(chunks, {text, 'LspCodeLens' })
+ if j < num_line_lenses then
+ table.insert(chunks, {' | ', 'LspCodeLensSeparator' })
+ end
end
if #chunks > 0 then
- api.nvim_buf_set_virtual_text(bufnr, ns, i, chunks, {})
+ api.nvim_buf_set_extmark(bufnr, ns, i, 0, { virt_text = chunks })
end
end
end
@@ -147,7 +166,7 @@ function M.save(lenses, bufnr, client_id)
end
---@private
+---@private
local function resolve_lenses(lenses, bufnr, client_id, callback)
lenses = lenses or {}
local num_lens = vim.tbl_count(lenses)
@@ -156,7 +175,7 @@ local function resolve_lenses(lenses, bufnr, client_id, callback)
return
end
- --@private
+ ---@private
local function countdown()
num_lens = num_lens - 1
if num_lens == 0 then
@@ -169,18 +188,18 @@ local function resolve_lenses(lenses, bufnr, client_id, callback)
if lens.command then
countdown()
else
- client.request('codeLens/resolve', lens, function(_, _, result)
+ client.request('codeLens/resolve', lens, function(_, result)
if result and result.command then
lens.command = result.command
-- Eager display to have some sort of incremental feedback
-- Once all lenses got resolved there will be a full redraw for all lenses
-- So that multiple lens per line are properly displayed
- api.nvim_buf_set_virtual_text(
+ api.nvim_buf_set_extmark(
bufnr,
ns,
lens.range.start.line,
- {{ lens.command.title, 'LspCodeLens' },},
- {}
+ 0,
+ { virt_text = {{ lens.command.title, 'LspCodeLens' }} }
)
end
countdown()
@@ -192,17 +211,17 @@ end
--- |lsp-handler| for the method `textDocument/codeLens`
---
-function M.on_codelens(err, _, result, client_id, bufnr)
+function M.on_codelens(err, result, ctx, _)
assert(not err, vim.inspect(err))
- M.save(result, bufnr, client_id)
+ M.save(result, ctx.bufnr, ctx.client_id)
-- Eager display for any resolved (and unresolved) lenses and refresh them
-- once resolved.
- M.display(result, bufnr, client_id)
- resolve_lenses(result, bufnr, client_id, function()
- M.display(result, bufnr, client_id)
- active_refreshes[bufnr] = nil
+ M.display(result, ctx.bufnr, ctx.client_id)
+ resolve_lenses(result, ctx.bufnr, ctx.client_id, function()
+ M.display(result, ctx.bufnr, ctx.client_id)
+ active_refreshes[ctx.bufnr] = nil
end)
end
diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua
index 64dde78f17..c6c08a15d3 100644
--- a/runtime/lua/vim/lsp/diagnostic.lua
+++ b/runtime/lua/vim/lsp/diagnostic.lua
@@ -1,126 +1,19 @@
-local api = vim.api
-local validate = vim.validate
-
-local highlight = vim.highlight
-local log = require('vim.lsp.log')
-local protocol = require('vim.lsp.protocol')
-local util = require('vim.lsp.util')
-
-local if_nil = vim.F.if_nil
-
---@class DiagnosticSeverity
-local DiagnosticSeverity = protocol.DiagnosticSeverity
-
-local to_severity = function(severity)
- if not severity then return nil end
- return type(severity) == 'string' and DiagnosticSeverity[severity] or severity
-end
-
-local filter_to_severity_limit = function(severity, diagnostics)
- local filter_level = to_severity(severity)
- if not filter_level then
- return diagnostics
- end
-
- return vim.tbl_filter(function(t) return t.severity == filter_level end, diagnostics)
-end
-
-local filter_by_severity_limit = function(severity_limit, diagnostics)
- local filter_level = to_severity(severity_limit)
- if not filter_level then
- return diagnostics
- end
-
- return vim.tbl_filter(function(t) return t.severity <= filter_level end, diagnostics)
-end
-
-local to_position = function(position, bufnr)
- vim.validate { position = {position, 't'} }
-
- return {
- position.line,
- util._get_line_byte_from_position(bufnr, position)
- }
-end
-
-
---@brief lsp-diagnostic
---
---@class Diagnostic
---@field range Range
---@field message string
---@field severity DiagnosticSeverity|nil
---@field code number | string
---@field source string
---@field tags DiagnosticTag[]
---@field relatedInformation DiagnosticRelatedInformation[]
+---@class Diagnostic
+---@field range Range
+---@field message string
+---@field severity DiagnosticSeverity|nil
+---@field code number | string
+---@field source string
+---@field tags DiagnosticTag[]
+---@field relatedInformation DiagnosticRelatedInformation[]
local M = {}
--- Diagnostic Highlights {{{
-
--- TODO(tjdevries): Determine how to generate documentation for these
--- and how to configure them to be easy for users.
---
--- For now, just use the following script. It should work pretty good.
---[[
-local levels = {"Error", "Warning", "Information", "Hint" }
-
-local all_info = {
- { "Default", "Used as the base highlight group, other highlight groups link to", },
- { "VirtualText", 'Used for "%s" diagnostic virtual text.\n See |vim.lsp.diagnostic.set_virtual_text()|', },
- { "Underline", 'Used to underline "%s" diagnostics.\n See |vim.lsp.diagnostic.set_underline()|', },
- { "Floating", 'Used to color "%s" diagnostic messages in diagnostics float.\n See |vim.lsp.diagnostic.show_line_diagnostics()|', },
- { "Sign", 'Used for "%s" signs in sing column.\n See |vim.lsp.diagnostic.set_signs()|', },
-}
-
-local results = {}
-for _, info in ipairs(all_info) do
- for _, level in ipairs(levels) do
- local name = info[1]
- local description = info[2]
- local fullname = string.format("Lsp%s%s", name, level)
- table.insert(results, string.format(
- "%78s", string.format("*hl-%s*", fullname))
- )
-
- table.insert(results, fullname)
- table.insert(results, string.format(" %s", description))
- table.insert(results, "")
- end
-end
-
--- print(table.concat(results, '\n'))
-vim.fn.setreg("*", table.concat(results, '\n'))
---]]
-
-local diagnostic_severities = {
- [DiagnosticSeverity.Error] = { guifg = "Red" };
- [DiagnosticSeverity.Warning] = { guifg = "Orange" };
- [DiagnosticSeverity.Information] = { guifg = "LightBlue" };
- [DiagnosticSeverity.Hint] = { guifg = "LightGrey" };
-}
-
--- Make a map from DiagnosticSeverity -> Highlight Name
-local make_highlight_map = function(base_name)
- local result = {}
- for k, _ in pairs(diagnostic_severities) do
- result[k] = "LspDiagnostics" .. base_name .. DiagnosticSeverity[k]
- end
-
- return result
-end
-
-local default_highlight_map = make_highlight_map("Default")
-local virtual_text_highlight_map = make_highlight_map("VirtualText")
-local underline_highlight_map = make_highlight_map("Underline")
-local floating_highlight_map = make_highlight_map("Floating")
-local sign_highlight_map = make_highlight_map("Sign")
-
--- }}}
--- Diagnostic Namespaces {{{
local DEFAULT_CLIENT_ID = -1
-local get_client_id = function(client_id)
+---@private
+local function get_client_id(client_id)
if client_id == nil then
client_id = DEFAULT_CLIENT_ID
end
@@ -128,472 +21,414 @@ local get_client_id = function(client_id)
return client_id
end
-local get_bufnr = function(bufnr)
+---@private
+local function get_bufnr(bufnr)
if not bufnr then
- return api.nvim_get_current_buf()
+ return vim.api.nvim_get_current_buf()
elseif bufnr == 0 then
- return api.nvim_get_current_buf()
+ return vim.api.nvim_get_current_buf()
end
return bufnr
end
-
---- Create a namespace table, used to track a client's buffer local items
-local _make_namespace_table = function(namespace, api_namespace)
- vim.validate { namespace = { namespace, 's' } }
-
- return setmetatable({
- [DEFAULT_CLIENT_ID] = api.nvim_create_namespace(namespace)
- }, {
- __index = function(t, client_id)
- client_id = get_client_id(client_id)
-
- if rawget(t, client_id) == nil then
- local value = string.format("%s:%s", namespace, client_id)
-
- if api_namespace then
- value = api.nvim_create_namespace(value)
- end
-
- rawset(t, client_id, value)
- end
-
- return rawget(t, client_id)
- end
- })
+---@private
+local function severity_lsp_to_vim(severity)
+ if type(severity) == 'string' then
+ severity = vim.lsp.protocol.DiagnosticSeverity[severity]
+ end
+ return severity
end
-local _diagnostic_namespaces = _make_namespace_table("vim_lsp_diagnostics", true)
-local _sign_namespaces = _make_namespace_table("vim_lsp_signs", false)
-
---@private
-function M._get_diagnostic_namespace(client_id)
- return _diagnostic_namespaces[client_id]
+---@private
+local function severity_vim_to_lsp(severity)
+ if type(severity) == 'string' then
+ severity = vim.diagnostic.severity[severity]
+ end
+ return severity
end
---@private
-function M._get_sign_namespace(client_id)
- return _sign_namespaces[client_id]
-end
--- }}}
--- Diagnostic Buffer & Client metatables {{{
-local bufnr_and_client_cacher_mt = {
- __index = function(t, bufnr)
- if bufnr == 0 or bufnr == nil then
- bufnr = vim.api.nvim_get_current_buf()
- end
+---@private
+local function line_byte_from_position(lines, lnum, col, offset_encoding)
+ if not lines or offset_encoding == "utf-8" then
+ return col
+ end
- if rawget(t, bufnr) == nil then
- rawset(t, bufnr, {})
- end
+ local line = lines[lnum + 1]
+ local ok, result = pcall(vim.str_byteindex, line, col, offset_encoding == "utf-16")
+ if ok then
+ return result
+ end
- return rawget(t, bufnr)
- end,
+ return col
+end
- __newindex = function(t, bufnr, v)
- if bufnr == 0 or bufnr == nil then
- bufnr = vim.api.nvim_get_current_buf()
- end
+---@private
+local function get_buf_lines(bufnr)
+ if vim.api.nvim_buf_is_loaded(bufnr) then
+ return vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
+ end
- rawset(t, bufnr, v)
- end,
-}
--- }}}
--- Diagnostic Saving & Caching {{{
-local _diagnostic_cleanup = setmetatable({}, bufnr_and_client_cacher_mt)
-local diagnostic_cache = setmetatable({}, bufnr_and_client_cacher_mt)
-local diagnostic_cache_lines = setmetatable({}, bufnr_and_client_cacher_mt)
-local diagnostic_cache_counts = setmetatable({}, bufnr_and_client_cacher_mt)
+ local filename = vim.api.nvim_buf_get_name(bufnr)
+ local f = io.open(filename)
+ if not f then
+ return
+ end
-local _bufs_waiting_to_update = setmetatable({}, bufnr_and_client_cacher_mt)
+ local content = f:read("*a")
+ if not content then
+ -- Some LSP servers report diagnostics at a directory level, in which case
+ -- io.read() returns nil
+ f:close()
+ return
+ end
---- Store Diagnostic[] by line
----
----@param diagnostics Diagnostic[]
----@return table<number, Diagnostic[]>
-local _diagnostic_lines = function(diagnostics)
- if not diagnostics then return end
+ local lines = vim.split(content, "\n")
+ f:close()
+ return lines
+end
- local diagnostics_by_line = {}
- for _, diagnostic in ipairs(diagnostics) do
+---@private
+local function diagnostic_lsp_to_vim(diagnostics, bufnr, client_id)
+ local buf_lines = get_buf_lines(bufnr)
+ local client = vim.lsp.get_client_by_id(client_id)
+ local offset_encoding = client and client.offset_encoding or "utf-16"
+ return vim.tbl_map(function(diagnostic)
local start = diagnostic.range.start
- local line_diagnostics = diagnostics_by_line[start.line]
- if not line_diagnostics then
- line_diagnostics = {}
- diagnostics_by_line[start.line] = line_diagnostics
- end
- table.insert(line_diagnostics, diagnostic)
+ local _end = diagnostic.range["end"]
+ return {
+ lnum = start.line,
+ col = line_byte_from_position(buf_lines, start.line, start.character, offset_encoding),
+ end_lnum = _end.line,
+ end_col = line_byte_from_position(buf_lines, _end.line, _end.character, offset_encoding),
+ severity = severity_lsp_to_vim(diagnostic.severity),
+ message = diagnostic.message,
+ source = diagnostic.source,
+ user_data = {
+ lsp = {
+ code = diagnostic.code,
+ codeDescription = diagnostic.codeDescription,
+ tags = diagnostic.tags,
+ relatedInformation = diagnostic.relatedInformation,
+ data = diagnostic.data,
+ },
+ },
+ }
+ end, diagnostics)
+end
+
+---@private
+local function diagnostic_vim_to_lsp(diagnostics)
+ return vim.tbl_map(function(diagnostic)
+ return vim.tbl_extend("error", {
+ range = {
+ start = {
+ line = diagnostic.lnum,
+ character = diagnostic.col,
+ },
+ ["end"] = {
+ line = diagnostic.end_lnum,
+ character = diagnostic.end_col,
+ },
+ },
+ severity = severity_vim_to_lsp(diagnostic.severity),
+ message = diagnostic.message,
+ source = diagnostic.source,
+ }, diagnostic.user_data and (diagnostic.user_data.lsp or {}) or {})
+ end, diagnostics)
+end
+
+local _client_namespaces = {}
+
+--- Get the diagnostic namespace associated with an LSP client |vim.diagnostic|.
+---
+---@param client_id number The id of the LSP client
+function M.get_namespace(client_id)
+ vim.validate { client_id = { client_id, 'n' } }
+ if not _client_namespaces[client_id] then
+ local name = string.format("vim.lsp.client-%d", client_id)
+ _client_namespaces[client_id] = vim.api.nvim_create_namespace(name)
end
- return diagnostics_by_line
+ return _client_namespaces[client_id]
end
---- Get the count of M by Severity
+--- Save diagnostics to the current buffer.
---
+--- Handles saving diagnostics from multiple clients in the same buffer.
---@param diagnostics Diagnostic[]
----@return table<DiagnosticSeverity, number>
-local _diagnostic_counts = function(diagnostics)
- if not diagnostics then return end
+---@param bufnr number
+---@param client_id number
+---@private
+function M.save(diagnostics, bufnr, client_id)
+ local namespace = M.get_namespace(client_id)
+ vim.diagnostic.set(namespace, bufnr, diagnostic_lsp_to_vim(diagnostics, bufnr, client_id))
+end
+-- }}}
- local counts = {}
- for _, diagnostic in pairs(diagnostics) do
- if diagnostic.severity then
- local val = counts[diagnostic.severity]
- if val == nil then
- val = 0
- end
+--- |lsp-handler| for the method "textDocument/publishDiagnostics"
+---
+--- See |vim.diagnostic.config()| for configuration options. Handler-specific
+--- configuration can be set using |vim.lsp.with()|:
+--- <pre>
+--- vim.lsp.handlers["textDocument/publishDiagnostics"] = vim.lsp.with(
+--- vim.lsp.diagnostic.on_publish_diagnostics, {
+--- -- Enable underline, use default values
+--- underline = true,
+--- -- Enable virtual text, override spacing to 4
+--- virtual_text = {
+--- spacing = 4,
+--- },
+--- -- Use a function to dynamically turn signs off
+--- -- and on, using buffer local variables
+--- signs = function(bufnr, client_id)
+--- return vim.bo[bufnr].show_signs == false
+--- end,
+--- -- Disable a feature
+--- update_in_insert = false,
+--- }
+--- )
+--- </pre>
+---
+---@param config table Configuration table (see |vim.diagnostic.config()|).
+function M.on_publish_diagnostics(_, result, ctx, config)
+ local client_id = ctx.client_id
+ local uri = result.uri
+ local bufnr = vim.uri_to_bufnr(uri)
- counts[diagnostic.severity] = val + 1
- end
+ if not bufnr then
+ return
end
- return counts
-end
-
---@private
---- Set the different diagnostic cache after `textDocument/publishDiagnostics`
----@param diagnostics Diagnostic[]
----@param bufnr number
----@param client_id number
----@return nil
-local function set_diagnostic_cache(diagnostics, bufnr, client_id)
client_id = get_client_id(client_id)
-
- -- https://microsoft.github.io/language-server-protocol/specifications/specification-current/#diagnostic
- --
- -- The diagnostic's severity. Can be omitted. If omitted it is up to the
- -- client to interpret diagnostics as error, warning, info or hint.
- -- TODO: Replace this with server-specific heuristics to infer severity.
- local buf_line_count = vim.api.nvim_buf_line_count(bufnr)
- for _, diagnostic in ipairs(diagnostics) do
- if diagnostic.severity == nil then
- diagnostic.severity = DiagnosticSeverity.Error
- end
- -- Account for servers that place diagnostics on terminating newline
- if buf_line_count > 0 then
- diagnostic.range.start.line = math.max(math.min(
- diagnostic.range.start.line, buf_line_count - 1
- ), 0)
- diagnostic.range["end"].line = math.max(math.min(
- diagnostic.range["end"].line, buf_line_count - 1
- ), 0)
+ local namespace = M.get_namespace(client_id)
+ local diagnostics = result.diagnostics
+
+ if config then
+ for _, opt in pairs(config) do
+ if type(opt) == 'table' then
+ if not opt.severity and opt.severity_limit then
+ opt.severity = {min=severity_lsp_to_vim(opt.severity_limit)}
+ end
+ end
end
end
- diagnostic_cache[bufnr][client_id] = diagnostics
- diagnostic_cache_lines[bufnr][client_id] = _diagnostic_lines(diagnostics)
- diagnostic_cache_counts[bufnr][client_id] = _diagnostic_counts(diagnostics)
-end
-
+ vim.diagnostic.set(namespace, bufnr, diagnostic_lsp_to_vim(diagnostics, bufnr, client_id), config)
---@private
---- Clear the cached diagnostics
----@param bufnr number
----@param client_id number
-local function clear_diagnostic_cache(bufnr, client_id)
- client_id = get_client_id(client_id)
-
- diagnostic_cache[bufnr][client_id] = nil
- diagnostic_cache_lines[bufnr][client_id] = nil
- diagnostic_cache_counts[bufnr][client_id] = nil
+ -- Keep old autocmd for back compat. This should eventually be removed.
+ vim.api.nvim_command("doautocmd <nomodeline> User LspDiagnosticsChanged")
end
---- Save diagnostics to the current buffer.
+--- Clear diagnotics and diagnostic cache.
+---
+--- Diagnostic producers should prefer |vim.diagnostic.reset()|. However,
+--- this method signature is still used internally in some parts of the LSP
+--- implementation so it's simply marked @private rather than @deprecated.
---
---- Handles saving diagnostics from multiple clients in the same buffer.
----@param diagnostics Diagnostic[]
----@param bufnr number
---@param client_id number
-function M.save(diagnostics, bufnr, client_id)
- validate {
- diagnostics = {diagnostics, 't'},
- bufnr = {bufnr, 'n'},
- client_id = {client_id, 'n', true},
- }
-
- if not diagnostics then return end
-
- bufnr = get_bufnr(bufnr)
- client_id = get_client_id(client_id)
-
- if not _diagnostic_cleanup[bufnr][client_id] then
- _diagnostic_cleanup[bufnr][client_id] = true
-
- -- Clean up our data when the buffer unloads.
- api.nvim_buf_attach(bufnr, false, {
- on_detach = function(_, b)
- clear_diagnostic_cache(b, client_id)
- _diagnostic_cleanup[b][client_id] = nil
+---@param buffer_client_map table map of buffers to active clients
+---@private
+function M.reset(client_id, buffer_client_map)
+ buffer_client_map = vim.deepcopy(buffer_client_map)
+ vim.schedule(function()
+ for bufnr, client_ids in pairs(buffer_client_map) do
+ if client_ids[client_id] then
+ local namespace = M.get_namespace(client_id)
+ vim.diagnostic.reset(namespace, bufnr)
end
- })
- end
-
- set_diagnostic_cache(diagnostics, bufnr, client_id)
+ end
+ end)
end
--- }}}
--- Diagnostic Retrieval {{{
+-- Deprecated Functions {{{
--- Get all diagnostics for clients
---
+---@deprecated Prefer |vim.diagnostic.get()|
+---
---@param client_id number Restrict included diagnostics to the client
--- If nil, diagnostics of all clients are included.
---@return table with diagnostics grouped by bufnr (bufnr: Diagnostic[])
function M.get_all(client_id)
- local diagnostics_by_bufnr = {}
- for bufnr, buf_diagnostics in pairs(diagnostic_cache) do
- diagnostics_by_bufnr[bufnr] = {}
- for cid, client_diagnostics in pairs(buf_diagnostics) do
- if client_id == nil or cid == client_id then
- vim.list_extend(diagnostics_by_bufnr[bufnr], client_diagnostics)
- end
- end
+ local result = {}
+ local namespace
+ if client_id then
+ namespace = M.get_namespace(client_id)
end
- return diagnostics_by_bufnr
+ for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do
+ local diagnostics = diagnostic_vim_to_lsp(vim.diagnostic.get(bufnr, {namespace = namespace}))
+ result[bufnr] = diagnostics
+ end
+ return result
end
--- Return associated diagnostics for bufnr
---
+---@deprecated Prefer |vim.diagnostic.get()|
+---
---@param bufnr number
---@param client_id number|nil If nil, then return all of the diagnostics.
--- Else, return just the diagnostics associated with the client_id.
-function M.get(bufnr, client_id)
+---@param predicate function|nil Optional function for filtering diagnostics
+function M.get(bufnr, client_id, predicate)
+ predicate = predicate or function() return true end
if client_id == nil then
local all_diagnostics = {}
- for iter_client_id, _ in pairs(diagnostic_cache[bufnr]) do
- local iter_diagnostics = M.get(bufnr, iter_client_id)
-
+ vim.lsp.for_each_buffer_client(bufnr, function(_, iter_client_id, _)
+ local iter_diagnostics = vim.tbl_filter(predicate, M.get(bufnr, iter_client_id))
for _, diagnostic in ipairs(iter_diagnostics) do
table.insert(all_diagnostics, diagnostic)
end
- end
-
+ end)
return all_diagnostics
end
- return diagnostic_cache[bufnr][client_id] or {}
+ local namespace = M.get_namespace(client_id)
+ return diagnostic_vim_to_lsp(vim.tbl_filter(predicate, vim.diagnostic.get(bufnr, {namespace=namespace})))
end
--- Get the diagnostics by line
---
----@param bufnr number The buffer number
----@param line_nr number The line number
+--- Marked private as this is used internally by the LSP subsystem, but
+--- most users should instead prefer |vim.diagnostic.get()|.
+---
+---@param bufnr number|nil The buffer number
+---@param line_nr number|nil The line number
---@param opts table|nil Configuration keys
--- - severity: (DiagnosticSeverity, default nil)
--- - Only return diagnostics with this severity. Overrides severity_limit
--- - severity_limit: (DiagnosticSeverity, default nil)
--- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid.
----@param client_id number the client id
+---@param client_id|nil number the client id
---@return table Table with map of line number to list of diagnostics.
--- Structured: { [1] = {...}, [5] = {.... } }
+--- Structured: { [1] = {...}, [5] = {.... } }
+---@private
function M.get_line_diagnostics(bufnr, line_nr, opts, client_id)
opts = opts or {}
-
- bufnr = bufnr or vim.api.nvim_get_current_buf()
- line_nr = line_nr or vim.api.nvim_win_get_cursor(0)[1] - 1
-
- local client_get_diags = function(iter_client_id)
- return (diagnostic_cache_lines[bufnr][iter_client_id] or {})[line_nr] or {}
+ if opts.severity then
+ opts.severity = severity_lsp_to_vim(opts.severity)
+ elseif opts.severity_limit then
+ opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)}
end
- local line_diagnostics
- if client_id == nil then
- line_diagnostics = {}
- for iter_client_id, _ in pairs(diagnostic_cache_lines[bufnr]) do
- for _, diagnostic in ipairs(client_get_diags(iter_client_id)) do
- table.insert(line_diagnostics, diagnostic)
- end
- end
- else
- line_diagnostics = vim.deepcopy(client_get_diags(client_id))
+ if client_id then
+ opts.namespace = M.get_namespace(client_id)
end
- if opts.severity then
- line_diagnostics = filter_to_severity_limit(opts.severity, line_diagnostics)
- elseif opts.severity_limit then
- line_diagnostics = filter_by_severity_limit(opts.severity_limit, line_diagnostics)
+ if not line_nr then
+ line_nr = vim.api.nvim_win_get_cursor(0)[1] - 1
end
- table.sort(line_diagnostics, function(a, b) return a.severity < b.severity end)
+ opts.lnum = line_nr
- return line_diagnostics
+ return diagnostic_vim_to_lsp(vim.diagnostic.get(bufnr, opts))
end
--- Get the counts for a particular severity
---
---- Useful for showing diagnostic counts in statusline. eg:
----
---- <pre>
---- function! LspStatus() abort
---- let sl = ''
---- if luaeval('not vim.tbl_isempty(vim.lsp.buf_get_clients(0))')
---- let sl.='%#MyStatuslineLSP#E:'
---- let sl.='%#MyStatuslineLSPErrors#%{luaeval("vim.lsp.diagnostic.get_count(0, [[Error]])")}'
---- let sl.='%#MyStatuslineLSP# W:'
---- let sl.='%#MyStatuslineLSPWarnings#%{luaeval("vim.lsp.diagnostic.get_count(0, [[Warning]])")}'
---- else
---- let sl.='%#MyStatuslineLSPErrors#off'
---- endif
---- return sl
---- endfunction
---- let &l:statusline = '%#MyStatuslineLSP#LSP '.LspStatus()
---- </pre>
+---@deprecated Prefer |vim.diagnostic.get_count()|
---
---@param bufnr number The buffer number
---@param severity DiagnosticSeverity
---@param client_id number the client id
function M.get_count(bufnr, severity, client_id)
- if client_id == nil then
- local total = 0
- for iter_client_id, _ in pairs(diagnostic_cache_counts[bufnr]) do
- total = total + M.get_count(bufnr, severity, iter_client_id)
- end
-
- return total
+ severity = severity_lsp_to_vim(severity)
+ local opts = { severity = severity }
+ if client_id ~= nil then
+ opts.namespace = M.get_namespace(client_id)
end
- return (diagnostic_cache_counts[bufnr][client_id] or {})[DiagnosticSeverity[severity]] or 0
-end
-
-
--- }}}
--- Diagnostic Movements {{{
-
---- Helper function to iterate through all of the diagnostic lines
----@return table list of diagnostics
-local _iter_diagnostic_lines = function(start, finish, step, bufnr, opts, client_id)
- if bufnr == nil then
- bufnr = vim.api.nvim_get_current_buf()
- end
-
- local wrap = if_nil(opts.wrap, true)
-
- local search = function(search_start, search_finish, search_step)
- for line_nr = search_start, search_finish, search_step do
- local line_diagnostics = M.get_line_diagnostics(bufnr, line_nr, opts, client_id)
- if line_diagnostics and not vim.tbl_isempty(line_diagnostics) then
- return line_diagnostics
- end
- end
- end
-
- local result = search(start, finish, step)
-
- if wrap then
- local wrap_start, wrap_finish
- if step == 1 then
- wrap_start, wrap_finish = 1, start
- else
- wrap_start, wrap_finish = vim.api.nvim_buf_line_count(bufnr), start
- end
-
- if not result then
- result = search(wrap_start, wrap_finish, step)
- end
- end
-
- return result
-end
-
---@private
---- Helper function to ierate through diagnostic lines and return a position
----
----@return table {row, col}
-local function _iter_diagnostic_lines_pos(opts, line_diagnostics)
- opts = opts or {}
-
- local win_id = opts.win_id or vim.api.nvim_get_current_win()
- local bufnr = vim.api.nvim_win_get_buf(win_id)
-
- if line_diagnostics == nil or vim.tbl_isempty(line_diagnostics) then
- return false
- end
-
- local iter_diagnostic = line_diagnostics[1]
- return to_position(iter_diagnostic.range.start, bufnr)
-end
-
---@private
--- Move to the diagnostic position
-local function _iter_diagnostic_move_pos(name, opts, pos)
- opts = opts or {}
-
- local enable_popup = if_nil(opts.enable_popup, true)
- local win_id = opts.win_id or vim.api.nvim_get_current_win()
-
- if not pos then
- print(string.format("%s: No more valid diagnostics to move to.", name))
- return
- end
-
- vim.api.nvim_win_set_cursor(win_id, {pos[1] + 1, pos[2]})
-
- if enable_popup then
- -- This is a bit weird... I'm surprised that we need to wait til the next tick to do this.
- vim.schedule(function()
- M.show_line_diagnostics(opts.popup_opts, vim.api.nvim_win_get_buf(win_id))
- end)
- end
+ return #vim.diagnostic.get(bufnr, opts)
end
--- Get the previous diagnostic closest to the cursor_position
---
+---@deprecated Prefer |vim.diagnostic.get_prev()|
+---
---@param opts table See |vim.lsp.diagnostic.goto_next()|
---@return table Previous diagnostic
function M.get_prev(opts)
- opts = opts or {}
-
- local win_id = opts.win_id or vim.api.nvim_get_current_win()
- local bufnr = vim.api.nvim_win_get_buf(win_id)
- local cursor_position = opts.cursor_position or vim.api.nvim_win_get_cursor(win_id)
-
- return _iter_diagnostic_lines(cursor_position[1] - 2, 0, -1, bufnr, opts, opts.client_id)
+ if opts then
+ if opts.severity then
+ opts.severity = severity_lsp_to_vim(opts.severity)
+ elseif opts.severity_limit then
+ opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)}
+ end
+ end
+ return diagnostic_vim_to_lsp({vim.diagnostic.get_prev(opts)})[1]
end
--- Return the pos, {row, col}, for the prev diagnostic in the current buffer.
+---
+---@deprecated Prefer |vim.diagnostic.get_prev_pos()|
+---
---@param opts table See |vim.lsp.diagnostic.goto_next()|
---@return table Previous diagnostic position
function M.get_prev_pos(opts)
- return _iter_diagnostic_lines_pos(
- opts,
- M.get_prev(opts)
- )
+ if opts then
+ if opts.severity then
+ opts.severity = severity_lsp_to_vim(opts.severity)
+ elseif opts.severity_limit then
+ opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)}
+ end
+ end
+ return vim.diagnostic.get_prev_pos(opts)
end
--- Move to the previous diagnostic
+---
+---@deprecated Prefer |vim.diagnostic.goto_prev()|
+---
---@param opts table See |vim.lsp.diagnostic.goto_next()|
function M.goto_prev(opts)
- return _iter_diagnostic_move_pos(
- "DiagnosticPrevious",
- opts,
- M.get_prev_pos(opts)
- )
+ if opts then
+ if opts.severity then
+ opts.severity = severity_lsp_to_vim(opts.severity)
+ elseif opts.severity_limit then
+ opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)}
+ end
+ end
+ return vim.diagnostic.goto_prev(opts)
end
--- Get the next diagnostic closest to the cursor_position
+---
+---@deprecated Prefer |vim.diagnostic.get_next()|
+---
---@param opts table See |vim.lsp.diagnostic.goto_next()|
---@return table Next diagnostic
function M.get_next(opts)
- opts = opts or {}
-
- local win_id = opts.win_id or vim.api.nvim_get_current_win()
- local bufnr = vim.api.nvim_win_get_buf(win_id)
- local cursor_position = opts.cursor_position or vim.api.nvim_win_get_cursor(win_id)
-
- return _iter_diagnostic_lines(cursor_position[1], vim.api.nvim_buf_line_count(bufnr), 1, bufnr, opts, opts.client_id)
+ if opts then
+ if opts.severity then
+ opts.severity = severity_lsp_to_vim(opts.severity)
+ elseif opts.severity_limit then
+ opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)}
+ end
+ end
+ return diagnostic_vim_to_lsp({vim.diagnostic.get_next(opts)})[1]
end
--- Return the pos, {row, col}, for the next diagnostic in the current buffer.
+---
+---@deprecated Prefer |vim.diagnostic.get_next_pos()|
+---
---@param opts table See |vim.lsp.diagnostic.goto_next()|
---@return table Next diagnostic position
function M.get_next_pos(opts)
- return _iter_diagnostic_lines_pos(
- opts,
- M.get_next(opts)
- )
+ if opts then
+ if opts.severity then
+ opts.severity = severity_lsp_to_vim(opts.severity)
+ elseif opts.severity_limit then
+ opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)}
+ end
+ end
+ return vim.diagnostic.get_next_pos(opts)
end
--- Move to the next diagnostic
+---
+---@deprecated Prefer |vim.diagnostic.goto_next()|
+---
---@param opts table|nil Configuration table. Keys:
--- - {client_id}: (number)
--- - If nil, will consider all clients attached to buffer.
@@ -612,25 +447,20 @@ end
--- - {win_id}: (number, default 0)
--- - Window ID
function M.goto_next(opts)
- return _iter_diagnostic_move_pos(
- "DiagnosticNext",
- opts,
- M.get_next_pos(opts)
- )
+ if opts then
+ if opts.severity then
+ opts.severity = severity_lsp_to_vim(opts.severity)
+ elseif opts.severity_limit then
+ opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)}
+ end
+ end
+ return vim.diagnostic.goto_next(opts)
end
--- }}}
--- Diagnostic Setters {{{
--- Set signs for given diagnostics
---
---- Sign characters can be customized with the following commands:
+---@deprecated Prefer |vim.diagnostic._set_signs()|
---
---- <pre>
---- sign define LspDiagnosticsSignError text=E texthl=LspDiagnosticsSignError linehl= numhl=
---- sign define LspDiagnosticsSignWarning text=W texthl=LspDiagnosticsSignWarning linehl= numhl=
---- sign define LspDiagnosticsSignInformation text=I texthl=LspDiagnosticsSignInformation linehl= numhl=
---- sign define LspDiagnosticsSignHint text=H texthl=LspDiagnosticsSignHint linehl= numhl=
---- </pre>
---@param diagnostics Diagnostic[]
---@param bufnr number The buffer number
---@param client_id number the client id
@@ -639,51 +469,18 @@ end
--- - priority: Set the priority of the signs.
--- - severity_limit (DiagnosticSeverity):
--- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid.
-function M.set_signs(diagnostics, bufnr, client_id, sign_ns, opts)
- opts = opts or {}
- sign_ns = sign_ns or M._get_sign_namespace(client_id)
-
- if not diagnostics then
- diagnostics = diagnostic_cache[bufnr][client_id]
- end
-
- if not diagnostics then
- return
+function M.set_signs(diagnostics, bufnr, client_id, _, opts)
+ local namespace = M.get_namespace(client_id)
+ if opts and not opts.severity and opts.severity_limit then
+ opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)}
end
- bufnr = get_bufnr(bufnr)
- diagnostics = filter_by_severity_limit(opts.severity_limit, diagnostics)
-
- local ok = true
- for _, diagnostic in ipairs(diagnostics) do
-
- ok = ok and pcall(vim.fn.sign_place,
- 0,
- sign_ns,
- sign_highlight_map[diagnostic.severity],
- bufnr,
- {
- priority = opts.priority,
- lnum = diagnostic.range.start.line + 1
- }
- )
- end
-
- if not ok then
- log.debug("Failed to place signs:", diagnostics)
- end
+ vim.diagnostic._set_signs(namespace, bufnr, diagnostic_lsp_to_vim(diagnostics, bufnr, client_id), opts)
end
--- Set underline for given diagnostics
---
---- Underline highlights can be customized by changing the following |:highlight| groups.
----
---- <pre>
---- LspDiagnosticsUnderlineError
---- LspDiagnosticsUnderlineWarning
---- LspDiagnosticsUnderlineInformation
---- LspDiagnosticsUnderlineHint
---- </pre>
+---@deprecated Prefer |vim.diagnostic._set_underline()|
---
---@param diagnostics Diagnostic[]
---@param bufnr number: The buffer number
@@ -692,43 +489,17 @@ end
---@param opts table: Configuration table:
--- - severity_limit (DiagnosticSeverity):
--- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid.
-function M.set_underline(diagnostics, bufnr, client_id, diagnostic_ns, opts)
- opts = opts or {}
-
- diagnostic_ns = diagnostic_ns or M._get_diagnostic_namespace(client_id)
- diagnostics = filter_by_severity_limit(opts.severity_limit, diagnostics)
-
- for _, diagnostic in ipairs(diagnostics) do
- local start = diagnostic.range["start"]
- local finish = diagnostic.range["end"]
- local higroup = underline_highlight_map[diagnostic.severity]
-
- if higroup == nil then
- -- Default to error if we don't have a highlight associated
- higroup = underline_highlight_map[DiagnosticSeverity.Error]
- end
-
- highlight.range(
- bufnr,
- diagnostic_ns,
- higroup,
- to_position(start, bufnr),
- to_position(finish, bufnr)
- )
+function M.set_underline(diagnostics, bufnr, client_id, _, opts)
+ local namespace = M.get_namespace(client_id)
+ if opts and not opts.severity and opts.severity_limit then
+ opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)}
end
+ return vim.diagnostic._set_underline(namespace, bufnr, diagnostic_lsp_to_vim(diagnostics, bufnr, client_id), opts)
end
--- Virtual Text {{{
--- Set virtual text given diagnostics
---
---- Virtual text highlights can be customized by changing the following |:highlight| groups.
----
---- <pre>
---- LspDiagnosticsVirtualTextError
---- LspDiagnosticsVirtualTextWarning
---- LspDiagnosticsVirtualTextInformation
---- LspDiagnosticsVirtualTextHint
---- </pre>
+---@deprecated Prefer |vim.diagnostic._set_virtual_text()|
---
---@param diagnostics Diagnostic[]
---@param bufnr number
@@ -739,460 +510,133 @@ end
--- - spacing (number): Number of spaces to insert before virtual text
--- - severity_limit (DiagnosticSeverity):
--- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid.
-function M.set_virtual_text(diagnostics, bufnr, client_id, diagnostic_ns, opts)
- opts = opts or {}
-
- client_id = get_client_id(client_id)
- diagnostic_ns = diagnostic_ns or M._get_diagnostic_namespace(client_id)
-
- local buffer_line_diagnostics
- if diagnostics then
- buffer_line_diagnostics = _diagnostic_lines(diagnostics)
- else
- buffer_line_diagnostics = diagnostic_cache_lines[bufnr][client_id]
- end
-
- if not buffer_line_diagnostics then
- return nil
- end
-
- for line, line_diagnostics in pairs(buffer_line_diagnostics) do
- line_diagnostics = filter_by_severity_limit(opts.severity_limit, line_diagnostics)
- local virt_texts = M.get_virtual_text_chunks_for_line(bufnr, line, line_diagnostics, opts)
-
- if virt_texts then
- api.nvim_buf_set_virtual_text(bufnr, diagnostic_ns, line, virt_texts, {})
- end
+function M.set_virtual_text(diagnostics, bufnr, client_id, _, opts)
+ local namespace = M.get_namespace(client_id)
+ if opts and not opts.severity and opts.severity_limit then
+ opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)}
end
+ return vim.diagnostic._set_virtual_text(namespace, bufnr, diagnostic_lsp_to_vim(diagnostics, bufnr, client_id), opts)
end
---- Default function to get text chunks to display using `nvim_buf_set_virtual_text`.
+--- Default function to get text chunks to display using |nvim_buf_set_extmark()|.
+---
+---@deprecated Prefer |vim.diagnostic.get_virt_text_chunks()|
+---
---@param bufnr number The buffer to display the virtual text in
---@param line number The line number to display the virtual text on
---@param line_diags Diagnostic[] The diagnostics associated with the line
---@param opts table See {opts} from |vim.lsp.diagnostic.set_virtual_text()|
----@return table chunks, as defined by |nvim_buf_set_virtual_text()|
-function M.get_virtual_text_chunks_for_line(bufnr, line, line_diags, opts)
- assert(bufnr or line)
-
- if #line_diags == 0 then
- return nil
- end
-
- opts = opts or {}
- local prefix = opts.prefix or "■"
- local spacing = opts.spacing or 4
-
- -- Create a little more space between virtual text and contents
- local virt_texts = {{string.rep(" ", spacing)}}
-
- for i = 1, #line_diags - 1 do
- table.insert(virt_texts, {prefix, virtual_text_highlight_map[line_diags[i].severity]})
- end
- local last = line_diags[#line_diags]
-
- -- TODO(tjdevries): Allow different servers to be shown first somehow?
- -- TODO(tjdevries): Display server name associated with these?
- if last.message then
- table.insert(
- virt_texts,
- {
- string.format("%s %s", prefix, last.message:gsub("\r", ""):gsub("\n", " ")),
- virtual_text_highlight_map[last.severity]
- }
- )
-
- return virt_texts
- end
+---@return an array of [text, hl_group] arrays. This can be passed directly to
+--- the {virt_text} option of |nvim_buf_set_extmark()|.
+function M.get_virtual_text_chunks_for_line(bufnr, _, line_diags, opts)
+ return vim.diagnostic._get_virt_text_chunks(diagnostic_lsp_to_vim(line_diags, bufnr), opts)
end
--- }}}
--- }}}
--- Diagnostic Clear {{{
---- Clears the currently displayed diagnostics
----@param bufnr number The buffer number
----@param client_id number the client id
----@param diagnostic_ns number|nil Associated diagnostic namespace
----@param sign_ns number|nil Associated sign namespace
-function M.clear(bufnr, client_id, diagnostic_ns, sign_ns)
- validate { bufnr = { bufnr, 'n' } }
-
- bufnr = (bufnr == 0 and api.nvim_get_current_buf()) or bufnr
-
- if client_id == nil then
- return vim.lsp.for_each_buffer_client(bufnr, function(_, iter_client_id, _)
- return M.clear(bufnr, iter_client_id)
- end)
- end
-
- diagnostic_ns = diagnostic_ns or M._get_diagnostic_namespace(client_id)
- sign_ns = sign_ns or M._get_sign_namespace(client_id)
-
- assert(bufnr, "bufnr is required")
- assert(diagnostic_ns, "Need diagnostic_ns, got nil")
- assert(sign_ns, string.format("Need sign_ns, got nil %s", sign_ns))
- -- clear sign group
- vim.fn.sign_unplace(sign_ns, {buffer=bufnr})
-
- -- clear virtual text namespace
- api.nvim_buf_clear_namespace(bufnr, diagnostic_ns, 0, -1)
-end
--- }}}
--- Diagnostic Insert Leave Handler {{{
-
---- Callback scheduled for after leaving insert mode
+--- Open a floating window with the diagnostics from {position}
---
---- Used to handle
---@private
-function M._execute_scheduled_display(bufnr, client_id)
- local args = _bufs_waiting_to_update[bufnr][client_id]
- if not args then
- return
- end
-
- -- Clear the args so we don't display unnecessarily.
- _bufs_waiting_to_update[bufnr][client_id] = nil
-
- M.display(nil, bufnr, client_id, args)
-end
-
-local registered = {}
-
-local make_augroup_key = function(bufnr, client_id)
- return string.format("LspDiagnosticInsertLeave:%s:%s", bufnr, client_id)
-end
-
---- Table of autocmd events to fire the update for displaying new diagnostic information
-M.insert_leave_auto_cmds = { "InsertLeave", "CursorHoldI" }
-
---- Used to schedule diagnostic updates upon leaving insert mode.
+---@deprecated Prefer |vim.diagnostic.show_position_diagnostics()|
---
---- For parameter description, see |M.display()|
-function M._schedule_display(bufnr, client_id, args)
- _bufs_waiting_to_update[bufnr][client_id] = args
-
- local key = make_augroup_key(bufnr, client_id)
- if not registered[key] then
- vim.cmd(string.format("augroup %s", key))
- vim.cmd(" au!")
- vim.cmd(
- string.format(
- [[autocmd %s <buffer=%s> :lua vim.lsp.diagnostic._execute_scheduled_display(%s, %s)]],
- table.concat(M.insert_leave_auto_cmds, ","),
- bufnr,
- bufnr,
- client_id
- )
- )
- vim.cmd("augroup END")
-
- registered[key] = true
- end
-end
-
-
---- Used in tandem with
----
---- For parameter description, see |M.display()|
-function M._clear_scheduled_display(bufnr, client_id)
- local key = make_augroup_key(bufnr, client_id)
-
- if registered[key] then
- vim.cmd(string.format("augroup %s", key))
- vim.cmd(" au!")
- vim.cmd("augroup END")
-
- registered[key] = nil
- end
-end
--- }}}
-
--- Diagnostic Private Highlight Utilies {{{
---- Get the severity highlight name
---@private
-function M._get_severity_highlight_name(severity)
- return virtual_text_highlight_map[severity]
-end
-
---- Get floating severity highlight name
---@private
-function M._get_floating_severity_highlight_name(severity)
- return floating_highlight_map[severity]
-end
-
---- This should be called to update the highlights for the LSP client.
-function M._define_default_signs_and_highlights()
- --@private
- local function define_default_sign(name, properties)
- if vim.tbl_isempty(vim.fn.sign_getdefined(name)) then
- vim.fn.sign_define(name, properties)
+---@param opts table|nil Configuration keys
+--- - severity: (DiagnosticSeverity, default nil)
+--- - Only return diagnostics with this severity. Overrides severity_limit
+--- - severity_limit: (DiagnosticSeverity, default nil)
+--- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid.
+--- - all opts for |show_diagnostics()| can be used here
+---@param buf_nr number|nil The buffer number
+---@param position table|nil The (0,0)-indexed position
+---@return table {popup_bufnr, win_id}
+function M.show_position_diagnostics(opts, buf_nr, position)
+ if opts then
+ if opts.severity then
+ opts.severity = severity_lsp_to_vim(opts.severity)
+ elseif opts.severity_limit then
+ opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)}
end
end
-
- -- Initialize default diagnostic highlights
- for severity, hi_info in pairs(diagnostic_severities) do
- local default_highlight_name = default_highlight_map[severity]
- highlight.create(default_highlight_name, hi_info, true)
-
- -- Default link all corresponding highlights to the default highlight
- highlight.link(virtual_text_highlight_map[severity], default_highlight_name, false)
- highlight.link(floating_highlight_map[severity], default_highlight_name, false)
- highlight.link(sign_highlight_map[severity], default_highlight_name, false)
- end
-
- -- Create all signs
- for severity, sign_hl_name in pairs(sign_highlight_map) do
- local severity_name = DiagnosticSeverity[severity]
-
- define_default_sign(sign_hl_name, {
- text = (severity_name or 'U'):sub(1, 1),
- texthl = sign_hl_name,
- linehl = '',
- numhl = '',
- })
- end
-
- -- Initialize Underline highlights
- for severity, underline_highlight_name in pairs(underline_highlight_map) do
- highlight.create(underline_highlight_name, {
- cterm = 'underline',
- gui = 'underline',
- guisp = diagnostic_severities[severity].guifg
- }, true)
- end
+ return vim.diagnostic.show_position_diagnostics(opts, buf_nr, position)
end
--- }}}
--- Diagnostic Display {{{
---- |lsp-handler| for the method "textDocument/publishDiagnostics"
+--- Open a floating window with the diagnostics from {line_nr}
---
----@note Each of the configuration options accepts:
---- - `false`: Disable this feature
---- - `true`: Enable this feature, use default settings.
---- - `table`: Enable this feature, use overrides.
---- - `function`: Function with signature (bufnr, client_id) that returns any of the above.
---- <pre>
---- vim.lsp.handlers["textDocument/publishDiagnostics"] = vim.lsp.with(
---- vim.lsp.diagnostic.on_publish_diagnostics, {
---- -- Enable underline, use default values
---- underline = true,
---- -- Enable virtual text, override spacing to 4
---- virtual_text = {
---- spacing = 4,
---- },
---- -- Use a function to dynamically turn signs off
---- -- and on, using buffer local variables
---- signs = function(bufnr, client_id)
---- return vim.bo[bufnr].show_signs == false
---- end,
---- -- Disable a feature
---- update_in_insert = false,
---- }
---- )
---- </pre>
+---@deprecated Prefer |vim.diagnostic.show_line_diagnostics()|
---
----@param config table Configuration table.
---- - underline: (default=true)
---- - Apply underlines to diagnostics.
---- - See |vim.lsp.diagnostic.set_underline()|
---- - virtual_text: (default=true)
---- - Apply virtual text to line endings.
---- - See |vim.lsp.diagnostic.set_virtual_text()|
---- - signs: (default=true)
---- - Apply signs for diagnostics.
---- - See |vim.lsp.diagnostic.set_signs()|
---- - update_in_insert: (default=false)
---- - Update diagnostics in InsertMode or wait until InsertLeave
---- - severity_sort: (default=false)
---- - Sort diagnostics (and thus signs and virtual text)
-function M.on_publish_diagnostics(_, _, params, client_id, _, config)
- local uri = params.uri
- local bufnr = vim.uri_to_bufnr(uri)
-
- if not bufnr then
- return
- end
-
- local diagnostics = params.diagnostics
-
- if config and if_nil(config.severity_sort, false) then
- table.sort(diagnostics, function(a, b) return a.severity > b.severity end)
- end
-
- -- Always save the diagnostics, even if the buf is not loaded.
- -- Language servers may report compile or build errors via diagnostics
- -- Users should be able to find these, even if they're in files which
- -- are not loaded.
- M.save(diagnostics, bufnr, client_id)
-
- -- Unloaded buffers should not handle diagnostics.
- -- When the buffer is loaded, we'll call on_attach, which sends textDocument/didOpen.
- -- This should trigger another publish of the diagnostics.
- --
- -- In particular, this stops a ton of spam when first starting a server for current
- -- unloaded buffers.
- if not api.nvim_buf_is_loaded(bufnr) then
- return
+---@param opts table Configuration table
+--- - all opts for |vim.lsp.diagnostic.get_line_diagnostics()| and
+--- |show_diagnostics()| can be used here
+---@param buf_nr number|nil The buffer number
+---@param line_nr number|nil The line number
+---@param client_id number|nil the client id
+---@return table {popup_bufnr, win_id}
+function M.show_line_diagnostics(opts, buf_nr, line_nr, client_id)
+ if client_id then
+ opts = opts or {}
+ opts.namespace = M.get_namespace(client_id)
end
-
- M.display(diagnostics, bufnr, client_id, config)
+ return vim.diagnostic.show_line_diagnostics(opts, buf_nr, line_nr)
end
---@private
---- Display diagnostics for the buffer, given a configuration.
-function M.display(diagnostics, bufnr, client_id, config)
- config = vim.lsp._with_extend('vim.lsp.diagnostic.on_publish_diagnostics', {
- signs = true,
- underline = true,
- virtual_text = true,
- update_in_insert = false,
- severity_sort = false,
- }, config)
-
- -- TODO(tjdevries): Consider how we can make this a "standardized" kind of thing for |lsp-handlers|.
- -- It seems like we would probably want to do this more often as we expose more of them.
- -- It provides a very nice functional interface for people to override configuration.
- local resolve_optional_value = function(option)
- local enabled_val = {}
-
- if not option then
- return false
- elseif option == true then
- return enabled_val
- elseif type(option) == 'function' then
- local val = option(bufnr, client_id)
- if val == true then
- return enabled_val
- else
- return val
- end
- elseif type(option) == 'table' then
- return option
- else
- error("Unexpected option type: " .. vim.inspect(option))
- end
- end
-
- if resolve_optional_value(config.update_in_insert) then
- M._clear_scheduled_display(bufnr, client_id)
- else
- local mode = vim.api.nvim_get_mode()
-
- if string.sub(mode.mode, 1, 1) == 'i' then
- M._schedule_display(bufnr, client_id, config)
- return
- end
- end
-
- M.clear(bufnr, client_id)
-
- diagnostics = diagnostics or M.get(bufnr, client_id)
-
- vim.api.nvim_command("doautocmd <nomodeline> User LspDiagnosticsChanged")
-
- if not diagnostics or vim.tbl_isempty(diagnostics) then
- return
- end
-
- local underline_opts = resolve_optional_value(config.underline)
- if underline_opts then
- M.set_underline(diagnostics, bufnr, client_id, nil, underline_opts)
- end
-
- local virtual_text_opts = resolve_optional_value(config.virtual_text)
- if virtual_text_opts then
- M.set_virtual_text(diagnostics, bufnr, client_id, nil, virtual_text_opts)
+--- Redraw diagnostics for the given buffer and client
+---
+---@deprecated Prefer |vim.diagnostic.redraw()|
+---
+--- This calls the "textDocument/publishDiagnostics" handler manually using
+--- the cached diagnostics already received from the server. This can be useful
+--- for redrawing diagnostics after making changes in diagnostics
+--- configuration. |lsp-handler-configuration|
+---
+---@param bufnr (optional, number): Buffer handle, defaults to current
+---@param client_id (optional, number): Redraw diagnostics for the given
+--- client. The default is to redraw diagnostics for all attached
+--- clients.
+function M.redraw(bufnr, client_id)
+ bufnr = get_bufnr(bufnr)
+ if not client_id then
+ return vim.lsp.for_each_buffer_client(bufnr, function(client)
+ M.redraw(bufnr, client.id)
+ end)
end
- local signs_opts = resolve_optional_value(config.signs)
- if signs_opts then
- M.set_signs(diagnostics, bufnr, client_id, nil, signs_opts)
- end
+ local namespace = M.get_namespace(client_id)
+ return vim.diagnostic.show(namespace, bufnr)
end
--- }}}
--- Diagnostic User Functions {{{
---- Open a floating window with the diagnostics from {line_nr}
+--- Sets the quickfix list
---
---- The floating window can be customized with the following highlight groups:
---- <pre>
---- LspDiagnosticsFloatingError
---- LspDiagnosticsFloatingWarning
---- LspDiagnosticsFloatingInformation
---- LspDiagnosticsFloatingHint
---- </pre>
----@param opts table Configuration table
---- - show_header (boolean, default true): Show "Diagnostics:" header.
---- - Plus all the opts for |vim.lsp.diagnostic.get_line_diagnostics()|
---- and |vim.lsp.util.open_floating_preview()| can be used here.
----@param bufnr number The buffer number
----@param line_nr number The line number
----@param client_id number|nil the client id
----@return table {popup_bufnr, win_id}
-function M.show_line_diagnostics(opts, bufnr, line_nr, client_id)
+---@deprecated Prefer |vim.diagnostic.setqflist()|
+---
+---@param opts table|nil Configuration table. Keys:
+--- - {open}: (boolean, default true)
+--- - Open quickfix list after set
+--- - {client_id}: (number)
+--- - If nil, will consider all clients attached to buffer.
+--- - {severity}: (DiagnosticSeverity)
+--- - Exclusive severity to consider. Overrides {severity_limit}
+--- - {severity_limit}: (DiagnosticSeverity)
+--- - Limit severity of diagnostics found. E.g. "Warning" means { "Error", "Warning" } will be valid.
+--- - {workspace}: (boolean, default true)
+--- - Set the list with workspace diagnostics
+function M.set_qflist(opts)
opts = opts or {}
-
- local show_header = if_nil(opts.show_header, true)
-
- bufnr = bufnr or 0
- line_nr = line_nr or (vim.api.nvim_win_get_cursor(0)[1] - 1)
-
- local lines = {}
- local highlights = {}
- if show_header then
- table.insert(lines, "Diagnostics:")
- table.insert(highlights, {0, "Bold"})
- end
-
- local line_diagnostics = M.get_line_diagnostics(bufnr, line_nr, opts, client_id)
- if vim.tbl_isempty(line_diagnostics) then return end
-
- for i, diagnostic in ipairs(line_diagnostics) do
- local prefix = string.format("%d. ", i)
- local hiname = M._get_floating_severity_highlight_name(diagnostic.severity)
- assert(hiname, 'unknown severity: ' .. tostring(diagnostic.severity))
-
- local message_lines = vim.split(diagnostic.message, '\n', true)
- table.insert(lines, prefix..message_lines[1])
- table.insert(highlights, {#prefix, hiname})
- for j = 2, #message_lines do
- table.insert(lines, message_lines[j])
- table.insert(highlights, {0, hiname})
- end
+ if opts.severity then
+ opts.severity = severity_lsp_to_vim(opts.severity)
+ elseif opts.severity_limit then
+ opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)}
end
-
- opts.focus_id = "line_diagnostics"
- local popup_bufnr, winnr = util.open_floating_preview(lines, 'plaintext', opts)
- for i, hi in ipairs(highlights) do
- local prefixlen, hiname = unpack(hi)
- -- Start highlight after the prefix
- api.nvim_buf_add_highlight(popup_bufnr, -1, hiname, i-1, prefixlen, -1)
+ if opts.client_id then
+ opts.client_id = nil
+ opts.namespace = M.get_namespace(opts.client_id)
end
-
- return popup_bufnr, winnr
-end
-
-
---- Clear diagnotics and diagnostic cache
----
---- Handles saving diagnostics from multiple clients in the same buffer.
----@param client_id number
----@param buffer_client_map table map of buffers to active clients
-function M.reset(client_id, buffer_client_map)
- buffer_client_map = vim.deepcopy(buffer_client_map)
- vim.schedule(function()
- for bufnr, client_ids in pairs(buffer_client_map) do
- if client_ids[client_id] then
- clear_diagnostic_cache(bufnr, client_id)
- M.clear(bufnr, client_id)
- end
- end
- end)
+ local workspace = vim.F.if_nil(opts.workspace, true)
+ opts.bufnr = not workspace and 0
+ return vim.diagnostic.setqflist(opts)
end
--- Sets the location list
+---
+---@deprecated Prefer |vim.diagnostic.setloclist()|
+---
---@param opts table|nil Configuration table. Keys:
---- - {open_loclist}: (boolean, default true)
+--- - {open}: (boolean, default true)
--- - Open loclist after set
--- - {client_id}: (number)
--- - If nil, will consider all clients attached to buffer.
@@ -1204,29 +648,65 @@ end
--- - Set the list with workspace diagnostics
function M.set_loclist(opts)
opts = opts or {}
- local open_loclist = if_nil(opts.open_loclist, true)
- local current_bufnr = api.nvim_get_current_buf()
- local diags = opts.workspace and M.get_all(opts.client_id) or {
- [current_bufnr] = M.get(current_bufnr, opts.client_id)
- }
- local predicate = function(d)
- local severity = to_severity(opts.severity)
- if severity then
- return d.severity == severity
- end
- local severity_limit = to_severity(opts.severity_limit)
- if severity_limit then
- return d.severity <= severity_limit
- end
- return true
+ if opts.severity then
+ opts.severity = severity_lsp_to_vim(opts.severity)
+ elseif opts.severity_limit then
+ opts.severity = {min=severity_lsp_to_vim(opts.severity_limit)}
end
- local items = util.diagnostics_to_items(diags, predicate)
- local win_id = vim.api.nvim_get_current_win()
- util.set_loclist(items, win_id)
- if open_loclist then
- vim.cmd [[lopen]]
+ if opts.client_id then
+ opts.client_id = nil
+ opts.namespace = M.get_namespace(opts.client_id)
end
+ local workspace = vim.F.if_nil(opts.workspace, false)
+ opts.bufnr = not workspace and 0
+ return vim.diagnostic.setloclist(opts)
end
+
+--- Disable diagnostics for the given buffer and client
+---
+---@deprecated Prefer |vim.diagnostic.disable()|
+---
+---@param bufnr (optional, number): Buffer handle, defaults to current
+---@param client_id (optional, number): Disable diagnostics for the given
+--- client. The default is to disable diagnostics for all attached
+--- clients.
+-- Note that when diagnostics are disabled for a buffer, the server will still
+-- send diagnostic information and the client will still process it. The
+-- diagnostics are simply not displayed to the user.
+function M.disable(bufnr, client_id)
+ if not client_id then
+ return vim.lsp.for_each_buffer_client(bufnr, function(client)
+ M.disable(bufnr, client.id)
+ end)
+ end
+
+ bufnr = get_bufnr(bufnr)
+ local namespace = M.get_namespace(client_id)
+ return vim.diagnostic.disable(bufnr, namespace)
+end
+
+--- Enable diagnostics for the given buffer and client
+---
+---@deprecated Prefer |vim.diagnostic.enable()|
+---
+---@param bufnr (optional, number): Buffer handle, defaults to current
+---@param client_id (optional, number): Enable diagnostics for the given
+--- client. The default is to enable diagnostics for all attached
+--- clients.
+function M.enable(bufnr, client_id)
+ if not client_id then
+ return vim.lsp.for_each_buffer_client(bufnr, function(client)
+ M.enable(bufnr, client.id)
+ end)
+ end
+
+ bufnr = get_bufnr(bufnr)
+ local namespace = M.get_namespace(client_id)
+ return vim.diagnostic.enable(bufnr, namespace)
+end
+
-- }}}
return M
+
+-- vim: fdm=marker
diff --git a/runtime/lua/vim/lsp/handlers.lua b/runtime/lua/vim/lsp/handlers.lua
index 41852b9d88..eff27807be 100644
--- a/runtime/lua/vim/lsp/handlers.lua
+++ b/runtime/lua/vim/lsp/handlers.lua
@@ -3,37 +3,34 @@ local protocol = require 'vim.lsp.protocol'
local util = require 'vim.lsp.util'
local vim = vim
local api = vim.api
-local buf = require 'vim.lsp.buf'
local M = {}
-- FIXME: DOC: Expose in vimdocs
---@private
+---@private
--- Writes to error buffer.
---@param ... (table of strings) Will be concatenated before being written
+---@param ... (table of strings) Will be concatenated before being written
local function err_message(...)
vim.notify(table.concat(vim.tbl_flatten{...}), vim.log.levels.ERROR)
api.nvim_command("redraw")
end
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand
-M['workspace/executeCommand'] = function(err, _)
- if err then
- error("Could not execute code action: "..err.message)
- end
+--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_executeCommand
+M['workspace/executeCommand'] = function(_, _, _, _)
+ -- Error handling is done implicitly by wrapping all handlers; see end of this file
end
--- @msg of type ProgressParams
--- Basically a token of type number/string
-local function progress_handler(_, _, params, client_id)
+---@private
+local function progress_handler(_, result, ctx, _)
+ local client_id = ctx.client_id
local client = vim.lsp.get_client_by_id(client_id)
local client_name = client and client.name or string.format("id=%d", client_id)
if not client then
err_message("LSP[", client_name, "] client has shut down after sending the message")
end
- local val = params.value -- unspecified yet
- local token = params.token -- string or number
+ local val = result.value -- unspecified yet
+ local token = result.token -- string or number
if val.kind then
@@ -61,13 +58,14 @@ local function progress_handler(_, _, params, client_id)
vim.api.nvim_command("doautocmd <nomodeline> User LspProgressUpdate")
end
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#progress
+--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#progress
M['$/progress'] = progress_handler
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_workDoneProgress_create
-M['window/workDoneProgress/create'] = function(_, _, params, client_id)
+--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_workDoneProgress_create
+M['window/workDoneProgress/create'] = function(_, result, ctx)
+ local client_id = ctx.client_id
local client = vim.lsp.get_client_by_id(client_id)
- local token = params.token -- string or number
+ local token = result.token -- string or number
local client_name = client and client.name or string.format("id=%d", client_id)
if not client then
err_message("LSP[", client_name, "] client has shut down after sending the message")
@@ -76,12 +74,12 @@ M['window/workDoneProgress/create'] = function(_, _, params, client_id)
return vim.NIL
end
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_showMessageRequest
-M['window/showMessageRequest'] = function(_, _, params)
+--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_showMessageRequest
+M['window/showMessageRequest'] = function(_, result)
- local actions = params.actions
- print(params.message)
- local option_strings = {params.message, "\nRequest Actions:"}
+ local actions = result.actions
+ print(result.message)
+ local option_strings = {result.message, "\nRequest Actions:"}
for i, action in ipairs(actions) do
local title = action.title:gsub('\r\n', '\\r\\n')
title = title:gsub('\n', '\\n')
@@ -97,8 +95,9 @@ M['window/showMessageRequest'] = function(_, _, params)
end
end
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#client_registerCapability
-M['client/registerCapability'] = function(_, _, _, client_id)
+--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#client_registerCapability
+M['client/registerCapability'] = function(_, _, ctx)
+ local client_id = ctx.client_id
local warning_tpl = "The language server %s triggers a registerCapability "..
"handler despite dynamicRegistration set to false. "..
"Report upstream, this warning is harmless"
@@ -109,42 +108,8 @@ M['client/registerCapability'] = function(_, _, _, client_id)
return vim.NIL
end
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction
-M['textDocument/codeAction'] = function(_, _, actions)
- if actions == nil or vim.tbl_isempty(actions) then
- print("No code actions available")
- return
- end
-
- local option_strings = {"Code Actions:"}
- for i, action in ipairs(actions) do
- local title = action.title:gsub('\r\n', '\\r\\n')
- title = title:gsub('\n', '\\n')
- table.insert(option_strings, string.format("%d. %s", i, title))
- end
-
- local choice = vim.fn.inputlist(option_strings)
- if choice < 1 or choice > #actions then
- return
- end
- local action_chosen = actions[choice]
- -- textDocument/codeAction can return either Command[] or CodeAction[].
- -- If it is a CodeAction, it can have either an edit, a command or both.
- -- Edits should be executed first
- if action_chosen.edit or type(action_chosen.command) == "table" then
- if action_chosen.edit then
- util.apply_workspace_edit(action_chosen.edit)
- end
- if type(action_chosen.command) == "table" then
- buf.execute_command(action_chosen.command)
- end
- else
- buf.execute_command(action_chosen)
- end
-end
-
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit
-M['workspace/applyEdit'] = function(_, _, workspace_edit)
+--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit
+M['workspace/applyEdit'] = function(_, workspace_edit)
if not workspace_edit then return end
-- TODO(ashkan) Do something more with label?
if workspace_edit.label then
@@ -157,30 +122,30 @@ M['workspace/applyEdit'] = function(_, _, workspace_edit)
}
end
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_configuration
-M['workspace/configuration'] = function(err, _, params, client_id)
+--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_configuration
+M['workspace/configuration'] = function(_, result, ctx)
+ local client_id = ctx.client_id
local client = vim.lsp.get_client_by_id(client_id)
if not client then
err_message("LSP[id=", client_id, "] client has shut down after sending the message")
return
end
- if err then error(vim.inspect(err)) end
- if not params.items then
+ if not result.items then
return {}
end
- local result = {}
- for _, item in ipairs(params.items) do
+ local response = {}
+ for _, item in ipairs(result.items) do
if item.section then
local value = util.lookup_section(client.config.settings, item.section) or vim.NIL
-- For empty sections with no explicit '' key, return settings as is
if value == vim.NIL and item.section == '' then
value = client.config.settings or vim.NIL
end
- table.insert(result, value)
+ table.insert(response, value)
end
end
- return result
+ return response
end
M['textDocument/publishDiagnostics'] = function(...)
@@ -191,51 +156,71 @@ M['textDocument/codeLens'] = function(...)
return require('vim.lsp.codelens').on_codelens(...)
end
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references
-M['textDocument/references'] = function(_, _, result)
- if not result then return end
- util.set_qflist(util.locations_to_items(result))
- api.nvim_command("copen")
-end
---@private
---- Prints given list of symbols to the quickfix list.
---@param _ (not used)
---@param _ (not used)
---@param result (list of Symbols) LSP method name
---@param result (table) result of LSP method; a location or a list of locations.
----(`textDocument/definition` can return `Location` or `Location[]`
-local symbol_handler = function(_, _, result, _, bufnr)
- if not result or vim.tbl_isempty(result) then return end
- util.set_qflist(util.symbols_to_items(result, bufnr))
- api.nvim_command("copen")
+---@private
+--- Return a function that converts LSP responses to list items and opens the list
+---
+--- The returned function has an optional {config} parameter that accepts a table
+--- with the following keys:
+---
+--- loclist: (boolean) use the location list (default is to use the quickfix list)
+---
+---@param map_result function `((resp, bufnr) -> list)` to convert the response
+---@param entity name of the resource used in a `not found` error message
+local function response_to_list(map_result, entity)
+ return function(_,result, ctx, config)
+ if not result or vim.tbl_isempty(result) then
+ vim.notify('No ' .. entity .. ' found')
+ else
+ config = config or {}
+ if config.loclist then
+ vim.fn.setloclist(0, {}, ' ', {
+ title = 'Language Server';
+ items = map_result(result, ctx.bufnr);
+ })
+ api.nvim_command("lopen")
+ else
+ vim.fn.setqflist({}, ' ', {
+ title = 'Language Server';
+ items = map_result(result, ctx.bufnr);
+ })
+ api.nvim_command("copen")
+ end
+ end
+ end
end
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentSymbol
-M['textDocument/documentSymbol'] = symbol_handler
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_symbol
-M['workspace/symbol'] = symbol_handler
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename
-M['textDocument/rename'] = function(_, _, result)
+
+--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_references
+M['textDocument/references'] = response_to_list(util.locations_to_items, 'references')
+
+--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentSymbol
+M['textDocument/documentSymbol'] = response_to_list(util.symbols_to_items, 'document symbols')
+
+--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_symbol
+M['workspace/symbol'] = response_to_list(util.symbols_to_items, 'symbols')
+
+--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rename
+M['textDocument/rename'] = function(_, result, _)
if not result then return end
util.apply_workspace_edit(result)
end
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rangeFormatting
-M['textDocument/rangeFormatting'] = function(_, _, result)
+--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_rangeFormatting
+M['textDocument/rangeFormatting'] = function(_, result, ctx, _)
if not result then return end
- util.apply_text_edits(result)
+ util.apply_text_edits(result, ctx.bufnr)
end
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting
-M['textDocument/formatting'] = function(_, _, result)
+--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting
+M['textDocument/formatting'] = function(_, result, ctx, _)
if not result then return end
- util.apply_text_edits(result)
+ util.apply_text_edits(result, ctx.bufnr)
end
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
-M['textDocument/completion'] = function(_, _, result)
+--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
+M['textDocument/completion'] = function(_, result, _, _)
if vim.tbl_isempty(result or {}) then return end
local row, col = unpack(api.nvim_win_get_cursor(0))
local line = assert(api.nvim_buf_get_lines(0, row-1, row, false)[1])
@@ -260,9 +245,9 @@ end
--- - border: (default=nil)
--- - Add borders to the floating window
--- - See |vim.api.nvim_open_win()|
-function M.hover(_, method, result, _, _, config)
+function M.hover(_, result, ctx, config)
config = config or {}
- config.focus_id = method
+ config.focus_id = ctx.method
if not (result and result.contents) then
-- return { 'No information available' }
return
@@ -276,18 +261,18 @@ function M.hover(_, method, result, _, _, config)
return util.open_floating_preview(markdown_lines, "markdown", config)
end
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover
+--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover
M['textDocument/hover'] = M.hover
---@private
+---@private
--- Jumps to a location. Used as a handler for multiple LSP methods.
---@param _ (not used)
---@param method (string) LSP method name
---@param result (table) result of LSP method; a location or a list of locations.
+---@param _ (not used)
+---@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(_, method, result)
+local function location_handler(_, result, ctx, _)
if result == nil or vim.tbl_isempty(result) then
- local _ = log.info() and log.info(method, 'No location found')
+ local _ = log.info() and log.info(ctx.method, 'No location found')
return nil
end
@@ -306,16 +291,17 @@ local function location_handler(_, method, result)
end
end
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_declaration
+--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_declaration
M['textDocument/declaration'] = location_handler
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition
+--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition
M['textDocument/definition'] = location_handler
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_typeDefinition
+--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_typeDefinition
M['textDocument/typeDefinition'] = location_handler
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_implementation
+--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_implementation
M['textDocument/implementation'] = location_handler
---- |lsp-handler| for the method "textDocument/signatureHelp"
+--- |lsp-handler| for the method "textDocument/signatureHelp".
+--- The active parameter is highlighted with |hl-LspSignatureActiveParameter|.
--- <pre>
--- vim.lsp.handlers["textDocument/signatureHelp"] = vim.lsp.with(
--- vim.lsp.handlers.signature_help, {
@@ -328,43 +314,53 @@ M['textDocument/implementation'] = location_handler
--- - border: (default=nil)
--- - Add borders to the floating window
--- - See |vim.api.nvim_open_win()|
-function M.signature_help(_, method, result, _, bufnr, config)
+function M.signature_help(_, result, ctx, config)
config = config or {}
- config.focus_id = method
+ config.focus_id = ctx.method
-- When use `autocmd CompleteDone <silent><buffer> lua vim.lsp.buf.signature_help()` to call signatureHelp handler
-- If the completion item doesn't have signatures It will make noise. Change to use `print` that can use `<silent>` to ignore
if not (result and result.signatures and result.signatures[1]) then
- print('No signature help available')
+ if config.silent ~= true then
+ print('No signature help available')
+ end
return
end
- local ft = api.nvim_buf_get_option(bufnr, 'filetype')
- local lines = util.convert_signature_help_to_markdown_lines(result, ft)
+ local client = vim.lsp.get_client_by_id(ctx.client_id)
+ local triggers = client.resolved_capabilities.signature_help_trigger_characters
+ local ft = api.nvim_buf_get_option(ctx.bufnr, 'filetype')
+ local lines, hl = util.convert_signature_help_to_markdown_lines(result, ft, triggers)
lines = util.trim_empty_lines(lines)
if vim.tbl_isempty(lines) then
- print('No signature help available')
+ if config.silent ~= true then
+ print('No signature help available')
+ end
return
end
- return util.open_floating_preview(lines, "markdown", config)
+ local fbuf, fwin = util.open_floating_preview(lines, "markdown", config)
+ if hl then
+ api.nvim_buf_add_highlight(fbuf, -1, "LspSignatureActiveParameter", 0, unpack(hl))
+ end
+ return fbuf, fwin
end
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp
+--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp
M['textDocument/signatureHelp'] = M.signature_help
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentHighlight
-M['textDocument/documentHighlight'] = function(_, _, result, _, bufnr, _)
+--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_documentHighlight
+M['textDocument/documentHighlight'] = function(_, result, ctx, _)
if not result then return end
- util.buf_highlight_references(bufnr, result)
+ util.buf_highlight_references(ctx.bufnr, result)
end
---@private
+---@private
---
--- Displays call hierarchy in the quickfix window.
---
---@param direction `"from"` for incoming calls and `"to"` for outgoing calls
---@returns `CallHierarchyIncomingCall[]` if {direction} is `"from"`,
---@returns `CallHierarchyOutgoingCall[]` if {direction} is `"to"`,
+---@param direction `"from"` for incoming calls and `"to"` for outgoing calls
+---@returns `CallHierarchyIncomingCall[]` if {direction} is `"from"`,
+---@returns `CallHierarchyOutgoingCall[]` if {direction} is `"to"`,
local make_call_hierarchy_handler = function(direction)
- return function(_, _, result)
+ return function(_, result)
if not result then return end
local items = {}
for _, call_hierarchy_call in pairs(result) do
@@ -383,16 +379,17 @@ local make_call_hierarchy_handler = function(direction)
end
end
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#callHierarchy/incomingCalls
+--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#callHierarchy_incomingCalls
M['callHierarchy/incomingCalls'] = make_call_hierarchy_handler('from')
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#callHierarchy/outgoingCalls
+--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#callHierarchy_outgoingCalls
M['callHierarchy/outgoingCalls'] = make_call_hierarchy_handler('to')
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window/logMessage
-M['window/logMessage'] = function(_, _, result, client_id)
+--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_logMessage
+M['window/logMessage'] = function(_, result, ctx, _)
local message_type = result.type
local message = result.message
+ local client_id = ctx.client_id
local client = vim.lsp.get_client_by_id(client_id)
local client_name = client and client.name or string.format("id=%d", client_id)
if not client then
@@ -402,7 +399,7 @@ M['window/logMessage'] = function(_, _, result, client_id)
log.error(message)
elseif message_type == protocol.MessageType.Warning then
log.warn(message)
- elseif message_type == protocol.MessageType.Info then
+ elseif message_type == protocol.MessageType.Info or message_type == protocol.MessageType.Log then
log.info(message)
else
log.debug(message)
@@ -410,10 +407,11 @@ M['window/logMessage'] = function(_, _, result, client_id)
return result
end
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window/showMessage
-M['window/showMessage'] = function(_, _, result, client_id)
+--see: https://microsoft.github.io/language-server-protocol/specifications/specification-current/#window_showMessage
+M['window/showMessage'] = function(_, result, ctx, _)
local message_type = result.type
local message = result.message
+ local client_id = ctx.client_id
local client = vim.lsp.get_client_by_id(client_id)
local client_name = client and client.name or string.format("id=%d", client_id)
if not client then
@@ -430,16 +428,23 @@ end
-- Add boilerplate error validation and logging for all of these.
for k, fn in pairs(M) do
- M[k] = function(err, method, params, client_id, bufnr, config)
- local _ = log.debug() and log.debug('default_handler', method, {
- params = params, client_id = client_id, err = err, bufnr = bufnr, config = config
+ M[k] = function(err, result, ctx, config)
+ local _ = log.trace() and log.trace('default_handler', ctx.method, {
+ err = err, result = result, ctx=vim.inspect(ctx), config = config
})
if err then
- return err_message(tostring(err))
+ local client = vim.lsp.get_client_by_id(ctx.client_id)
+ local client_name = client and client.name or string.format("client_id=%d", ctx.client_id)
+ -- LSP spec:
+ -- interface ResponseError:
+ -- code: integer;
+ -- message: string;
+ -- data?: string | number | boolean | array | object | null;
+ return err_message(client_name .. ': ' .. tostring(err.code) .. ': ' .. err.message)
end
- return fn(err, method, params, client_id, bufnr, config)
+ return fn(err, result, ctx, config)
end
end
diff --git a/runtime/lua/vim/lsp/health.lua b/runtime/lua/vim/lsp/health.lua
new file mode 100644
index 0000000000..855679a2df
--- /dev/null
+++ b/runtime/lua/vim/lsp/health.lua
@@ -0,0 +1,27 @@
+local M = {}
+
+--- Performs a healthcheck for LSP
+function M.check_health()
+ local report_info = vim.fn['health#report_info']
+ local report_warn = vim.fn['health#report_warn']
+
+ local log = require('vim.lsp.log')
+ local current_log_level = log.get_level()
+ local log_level_string = log.levels[current_log_level]
+ report_info(string.format("LSP log level : %s", log_level_string))
+
+ if current_log_level < log.levels.WARN then
+ report_warn(string.format("Log level %s will cause degraded performance and high disk usage", log_level_string))
+ end
+
+ 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 report_fn = (log_size / 1000000 > 100 and report_warn or report_info)
+ report_fn(string.format("Log size: %d KB", log_size / 1000 ))
+end
+
+return M
+
diff --git a/runtime/lua/vim/lsp/log.lua b/runtime/lua/vim/lsp/log.lua
index 471a311c16..4597f1919a 100644
--- a/runtime/lua/vim/lsp/log.lua
+++ b/runtime/lua/vim/lsp/log.lua
@@ -14,26 +14,38 @@ log.levels = vim.deepcopy(vim.log.levels)
-- Default log level is warn.
local current_log_level = log.levels.WARN
-local log_date_format = "%FT%H:%M:%S%z"
+local log_date_format = "%F %H:%M:%S"
+local format_func = function(arg) return vim.inspect(arg, {newline=''}) end
do
- local path_sep = vim.loop.os_uname().sysname == "Windows" and "\\" or "/"
- --@private
+ local path_sep = vim.loop.os_uname().version:match("Windows") and "\\" or "/"
+ ---@private
local function path_join(...)
return table.concat(vim.tbl_flatten{...}, path_sep)
end
local logfilename = path_join(vim.fn.stdpath('cache'), 'lsp.log')
--- Returns the log filename.
- --@returns (string) log filename
+ ---@returns (string) log filename
function log.get_filename()
return logfilename
end
vim.fn.mkdir(vim.fn.stdpath('cache'), "p")
local logfile = assert(io.open(logfilename, "a+"))
+
+ local log_info = vim.loop.fs_stat(logfilename)
+ if log_info and log_info.size > 1e9 then
+ local warn_msg = string.format(
+ "LSP client log is large (%d MB): %s",
+ log_info.size / (1000 * 1000),
+ logfilename
+ )
+ vim.notify(warn_msg)
+ end
+
-- Start message for logging
- logfile:write(string.format("[ START ] %s ] LSP logging initiated\n", os.date(log_date_format)))
+ logfile:write(string.format("[START][%s] LSP logging initiated\n", os.date(log_date_format)))
for level, levelnr in pairs(log.levels) do
-- Also export the log level on the root object.
log[level] = levelnr
@@ -56,14 +68,14 @@ do
if levelnr < current_log_level then return false end
if argc == 0 then return true end
local info = debug.getinfo(2, "Sl")
- local fileinfo = string.format("%s:%s", info.short_src, info.currentline)
- local parts = { table.concat({"[", level, "]", os.date(log_date_format), "]", fileinfo, "]"}, " ") }
+ local header = string.format("[%s][%s] ...%s:%s", level, os.date(log_date_format), string.sub(info.short_src, #info.short_src - 15), info.currentline)
+ local parts = { header }
for i = 1, argc do
local arg = select(i, ...)
if arg == nil then
table.insert(parts, "nil")
else
- table.insert(parts, vim.inspect(arg, {newline=''}))
+ table.insert(parts, format_func(arg))
end
end
logfile:write(table.concat(parts, '\t'), "\n")
@@ -77,7 +89,7 @@ end
vim.tbl_add_reverse_lookup(log.levels)
--- Sets the current log level.
---@param level (string or number) One of `vim.lsp.log.levels`
+---@param level (string or number) One of `vim.lsp.log.levels`
function log.set_level(level)
if type(level) == 'string' then
current_log_level = assert(log.levels[level:upper()], string.format("Invalid log level: %q", level))
@@ -88,9 +100,21 @@ function log.set_level(level)
end
end
+--- Gets the current log level.
+function log.get_level()
+ return current_log_level
+end
+
+--- Sets formatting function used to format logs
+---@param handle function function to apply to logging arguments, pass vim.inspect for multi-line formatting
+function log.set_format_func(handle)
+ assert(handle == vim.inspect or type(handle) == 'function', "handle must be a function")
+ format_func = handle
+end
+
--- Checks whether the level is sufficient for logging.
---@param level number log level
---@returns (bool) true if would log, false if not
+---@param level number log level
+---@returns (bool) true if would log, false if not
function log.should_log(level)
return level >= current_log_level
end
diff --git a/runtime/lua/vim/lsp/protocol.lua b/runtime/lua/vim/lsp/protocol.lua
index 7e43eb84de..b3aa8b934f 100644
--- a/runtime/lua/vim/lsp/protocol.lua
+++ b/runtime/lua/vim/lsp/protocol.lua
@@ -5,14 +5,14 @@ local if_nil = vim.F.if_nil
local protocol = {}
--[=[
---@private
+---@private
--- Useful for interfacing with:
--- https://github.com/microsoft/language-server-protocol/raw/gh-pages/_specifications/specification-3-14.md
function transform_schema_comments()
nvim.command [[silent! '<,'>g/\/\*\*\|\*\/\|^$/d]]
nvim.command [[silent! '<,'>s/^\(\s*\) \* \=\(.*\)/\1--\2/]]
end
---@private
+---@private
function transform_schema_to_table()
transform_schema_comments()
nvim.command [[silent! '<,'>s/: \S\+//]]
@@ -645,6 +645,10 @@ function protocol.make_client_capabilities()
end)();
};
};
+ dataSupport = true;
+ resolveSupport = {
+ properties = { 'edit', }
+ };
};
completion = {
dynamicRegistration = false;
@@ -691,10 +695,11 @@ function protocol.make_client_capabilities()
signatureHelp = {
dynamicRegistration = false;
signatureInformation = {
+ activeParameterSupport = true;
documentationFormat = { protocol.MarkupKind.Markdown; protocol.MarkupKind.PlainText };
- -- parameterInformation = {
- -- labelOffsetSupport = false;
- -- };
+ parameterInformation = {
+ labelOffsetSupport = true;
+ };
};
};
references = {
@@ -1002,8 +1007,7 @@ function protocol.resolve_capabilities(server_capabilities)
elseif type(server_capabilities.declarationProvider) == 'boolean' then
general_properties.declaration = server_capabilities.declarationProvider
elseif type(server_capabilities.declarationProvider) == 'table' then
- -- TODO: support more detailed declarationProvider options.
- general_properties.declaration = false
+ general_properties.declaration = server_capabilities.declarationProvider
else
error("The server sent invalid declarationProvider")
end
@@ -1013,8 +1017,7 @@ function protocol.resolve_capabilities(server_capabilities)
elseif type(server_capabilities.typeDefinitionProvider) == 'boolean' then
general_properties.type_definition = server_capabilities.typeDefinitionProvider
elseif type(server_capabilities.typeDefinitionProvider) == 'table' then
- -- TODO: support more detailed typeDefinitionProvider options.
- general_properties.type_definition = false
+ general_properties.type_definition = server_capabilities.typeDefinitionProvider
else
error("The server sent invalid typeDefinitionProvider")
end
@@ -1024,8 +1027,7 @@ function protocol.resolve_capabilities(server_capabilities)
elseif type(server_capabilities.implementationProvider) == 'boolean' then
general_properties.implementation = server_capabilities.implementationProvider
elseif type(server_capabilities.implementationProvider) == 'table' then
- -- TODO(ashkan) support more detailed implementation options.
- general_properties.implementation = false
+ general_properties.implementation = server_capabilities.implementationProvider
else
error("The server sent invalid implementationProvider")
end
diff --git a/runtime/lua/vim/lsp/rpc.lua b/runtime/lua/vim/lsp/rpc.lua
index 4c5f02af9d..255eb65dfe 100644
--- a/runtime/lua/vim/lsp/rpc.lua
+++ b/runtime/lua/vim/lsp/rpc.lua
@@ -4,38 +4,10 @@ local log = require('vim.lsp.log')
local protocol = require('vim.lsp.protocol')
local validate, schedule, schedule_wrap = vim.validate, vim.schedule, vim.schedule_wrap
--- TODO replace with a better implementation.
---@private
---- Encodes to JSON.
----
---@param data (table) Data to encode
---@returns (string) Encoded object
-local function json_encode(data)
- local status, result = pcall(vim.fn.json_encode, data)
- if status then
- return result
- else
- return nil, result
- end
-end
---@private
---- Decodes from JSON.
----
---@param data (string) Data to decode
---@returns (table) Decoded JSON object
-local function json_decode(data)
- local status, result = pcall(vim.fn.json_decode, data)
- if status then
- return result
- else
- return nil, result
- end
-end
-
---@private
+---@private
--- Checks whether a given path exists and is a directory.
---@param filename (string) path to check
---@returns (bool)
+---@param filename (string) path to check
+---@returns (bool)
local function is_dir(filename)
local stat = vim.loop.fs_stat(filename)
return stat and stat.type == 'directory' or false
@@ -43,7 +15,7 @@ end
local NIL = vim.NIL
---@private
+---@private
local recursive_convert_NIL
recursive_convert_NIL = function(v, tbl_processed)
if v == NIL then
@@ -63,15 +35,15 @@ recursive_convert_NIL = function(v, tbl_processed)
return v
end
---@private
+---@private
--- Returns its argument, but converts `vim.NIL` to Lua `nil`.
---@param v (any) Argument
---@returns (any)
+---@param v (any) Argument
+---@returns (any)
local function convert_NIL(v)
return recursive_convert_NIL(v, {})
end
---@private
+---@private
--- Merges current process env with the given env and returns the result as
--- a list of "k=v" strings.
---
@@ -81,8 +53,8 @@ end
--- in: { PRODUCTION="false", PATH="/usr/bin/", PORT=123, HOST="0.0.0.0", }
--- out: { "PRODUCTION=false", "PATH=/usr/bin/", "PORT=123", "HOST=0.0.0.0", }
--- </pre>
---@param env (table) table of environment variable assignments
---@returns (table) list of `"k=v"` strings
+---@param env (table) table of environment variable assignments
+---@returns (table) list of `"k=v"` strings
local function env_merge(env)
if env == nil then
return env
@@ -97,11 +69,11 @@ local function env_merge(env)
return final_env
end
---@private
+---@private
--- Embeds the given string into a table and correctly computes `Content-Length`.
---
---@param encoded_message (string)
---@returns (table) table containing encoded message and `Content-Length` attribute
+---@param encoded_message (string)
+---@returns (table) table containing encoded message and `Content-Length` attribute
local function format_message_with_content_length(encoded_message)
return table.concat {
'Content-Length: '; tostring(#encoded_message); '\r\n\r\n';
@@ -109,11 +81,11 @@ local function format_message_with_content_length(encoded_message)
}
end
---@private
+---@private
--- Parses an LSP Message's header
---
---@param header: The header to parse.
---@returns Parsed headers
+---@param header: The header to parse.
+---@returns Parsed headers
local function parse_headers(header)
if type(header) ~= 'string' then
return nil
@@ -141,7 +113,7 @@ end
-- case insensitive pattern.
local header_start_pattern = ("content"):gsub("%w", function(c) return "["..c..c:upper().."]" end)
---@private
+---@private
--- The actual workhorse.
local function request_parser_loop()
local buffer = '' -- only for header part
@@ -203,8 +175,8 @@ local client_errors = vim.tbl_add_reverse_lookup {
--- Constructs an error message from an LSP error object.
---
---@param err (table) The error object
---@returns (string) The formatted error message
+---@param err (table) The error object
+---@returns (string) The formatted error message
local function format_rpc_error(err)
validate {
err = { err, 't' };
@@ -233,9 +205,9 @@ end
--- Creates an RPC response object/table.
---
---@param code RPC error code defined in `vim.lsp.protocol.ErrorCodes`
---@param message (optional) arbitrary message to send to server
---@param data (optional) arbitrary data to send to server
+---@param code RPC error code defined in `vim.lsp.protocol.ErrorCodes`
+---@param message (optional) arbitrary message to send to server
+---@param data (optional) arbitrary data to send to server
local function rpc_response_error(code, message, data)
-- TODO should this error or just pick a sane error (like InternalError)?
local code_name = assert(protocol.ErrorCodes[code], 'Invalid RPC error code')
@@ -250,38 +222,38 @@ end
local default_dispatchers = {}
---@private
+---@private
--- Default dispatcher for notifications sent to an LSP server.
---
---@param method (string) The invoked LSP method
---@param params (table): Parameters for the invoked LSP method
+---@param method (string) The invoked LSP method
+---@param params (table): Parameters for the invoked LSP method
function default_dispatchers.notification(method, params)
local _ = log.debug() and log.debug('notification', method, params)
end
---@private
+---@private
--- Default dispatcher for requests sent to an LSP server.
---
---@param method (string) The invoked LSP method
---@param params (table): Parameters for the invoked LSP method
---@returns `nil` and `vim.lsp.protocol.ErrorCodes.MethodNotFound`.
+---@param method (string) The invoked LSP method
+---@param params (table): Parameters for the invoked LSP method
+---@returns `nil` and `vim.lsp.protocol.ErrorCodes.MethodNotFound`.
function default_dispatchers.server_request(method, params)
local _ = log.debug() and log.debug('server_request', method, params)
return nil, rpc_response_error(protocol.ErrorCodes.MethodNotFound)
end
---@private
+---@private
--- Default dispatcher for when a client exits.
---
---@param code (number): Exit code
---@param signal (number): Number describing the signal used to terminate (if
+---@param code (number): Exit code
+---@param signal (number): Number describing the signal used to terminate (if
---any)
function default_dispatchers.on_exit(code, signal)
local _ = log.info() and log.info("client_exit", { code = code, signal = signal })
end
---@private
+---@private
--- Default dispatcher for client errors.
---
---@param code (number): Error code
---@param err (any): Details about the error
+---@param code (number): Error code
+---@param err (any): Details about the error
---any)
function default_dispatchers.on_error(code, err)
local _ = log.error() and log.error('client_error:', client_errors[code], err)
@@ -290,25 +262,25 @@ end
--- Starts an LSP server process and create an LSP RPC client object to
--- interact with it.
---
---@param cmd (string) Command to start the LSP server.
---@param cmd_args (table) List of additional string arguments to pass to {cmd}.
---@param dispatchers (table, optional) Dispatchers for LSP message types. Valid
+---@param cmd (string) Command to start the LSP server.
+---@param cmd_args (table) List of additional string arguments to pass to {cmd}.
+---@param dispatchers (table, optional) Dispatchers for LSP message types. Valid
---dispatcher names are:
--- - `"notification"`
--- - `"server_request"`
--- - `"on_error"`
--- - `"on_exit"`
---@param extra_spawn_params (table, optional) Additional context for the LSP
+---@param extra_spawn_params (table, optional) Additional context for the LSP
--- server process. May contain:
--- - {cwd} (string) Working directory for the LSP server process
--- - {env} (table) Additional environment variables for LSP server process
---@returns Client RPC object.
+---@returns Client RPC object.
---
---@returns Methods:
+---@returns Methods:
--- - `notify()` |vim.lsp.rpc.notify()|
--- - `request()` |vim.lsp.rpc.request()|
---
---@returns Members:
+---@returns Members:
--- - {pid} (number) The LSP server's PID.
--- - {handle} A handle for low-level interaction with the LSP server process
--- |vim.loop|.
@@ -358,10 +330,10 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params)
local handle, pid
do
- --@private
+ ---@private
--- Callback for |vim.loop.spawn()| Closes all streams and runs the `on_exit` dispatcher.
- --@param code (number) Exit code
- --@param signal (number) Signal that was used to terminate (if any)
+ ---@param code (number) Exit code
+ ---@param signal (number) Signal that was used to terminate (if any)
local function onexit(code, signal)
stdin:close()
stdout:close()
@@ -385,20 +357,17 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params)
end
end
- --@private
+ ---@private
--- Encodes {payload} into a JSON-RPC message and sends it to the remote
--- process.
---
- --@param payload (table) Converted into a JSON string, see |json_encode()|
- --@returns true if the payload could be scheduled, false if the main event-loop is in the process of closing.
+ ---@param payload table
+ ---@returns true if the payload could be scheduled, false if the main event-loop is in the process of closing.
local function encode_and_send(payload)
- local _ = log.debug() and log.debug("rpc.send.payload", payload)
+ local _ = log.debug() and log.debug("rpc.send", payload)
if handle == nil or handle:is_closing() then return false end
- -- TODO(ashkan) remove this once we have a Lua json_encode
- schedule(function()
- local encoded = assert(json_encode(payload))
- stdin:write(format_message_with_content_length(encoded))
- end)
+ local encoded = vim.json.encode(payload)
+ stdin:write(format_message_with_content_length(encoded))
return true
end
@@ -406,9 +375,9 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params)
-- `start()`
--
--- Sends a notification to the LSP server.
- --@param method (string) The invoked LSP method
- --@param params (table): Parameters for the invoked LSP method
- --@returns (bool) `true` if notification could be sent, `false` if not
+ ---@param method (string) The invoked LSP method
+ ---@param params (table): Parameters for the invoked LSP method
+ ---@returns (bool) `true` if notification could be sent, `false` if not
local function notify(method, params)
return encode_and_send {
jsonrpc = "2.0";
@@ -417,7 +386,7 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params)
}
end
- --@private
+ ---@private
--- sends an error object to the remote LSP process.
local function send_response(request_id, err, result)
return encode_and_send {
@@ -433,10 +402,10 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params)
--
--- Sends a request to the LSP server and runs {callback} upon response.
---
- --@param method (string) The invoked LSP method
- --@param params (table) Parameters for the invoked LSP method
- --@param callback (function) Callback to invoke
- --@returns (bool, number) `(true, message_id)` if request could be sent, `false` if not
+ ---@param method (string) The invoked LSP method
+ ---@param params (table) Parameters for the invoked LSP method
+ ---@param callback (function) Callback to invoke
+ ---@returns (bool, number) `(true, message_id)` if request could be sent, `false` if not
local function request(method, params, callback)
validate {
callback = { callback, 'f' };
@@ -463,13 +432,13 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params)
end
end)
- --@private
+ ---@private
local function on_error(errkind, ...)
assert(client_errors[errkind])
-- TODO what to do if this fails?
pcall(dispatchers.on_error, errkind, ...)
end
- --@private
+ ---@private
local function pcall_handler(errkind, status, head, ...)
if not status then
on_error(errkind, head, ...)
@@ -477,7 +446,7 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params)
end
return status, head, ...
end
- --@private
+ ---@private
local function try_call(errkind, fn, ...)
return pcall_handler(errkind, pcall(fn, ...))
end
@@ -486,16 +455,17 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params)
-- time and log them. This would require storing the timestamp. I could call
-- them with an error then, perhaps.
- --@private
+ ---@private
local function handle_body(body)
- local decoded, err = json_decode(body)
- if not decoded then
- -- on_error(client_errors.INVALID_SERVER_JSON, err)
+ local ok, decoded = pcall(vim.json.decode, body)
+ if not ok then
+ on_error(client_errors.INVALID_SERVER_JSON, decoded)
return
end
- local _ = log.debug() and log.debug("decoded", decoded)
+ local _ = log.debug() and log.debug("rpc.receive", decoded)
if type(decoded.method) == 'string' and decoded.id then
+ local err
-- Server Request
decoded.params = convert_NIL(decoded.params)
-- Schedule here so that the users functions don't trigger an error and
@@ -582,8 +552,6 @@ local function start(cmd, cmd_args, dispatchers, extra_spawn_params)
on_error(client_errors.INVALID_SERVER_MESSAGE, decoded)
end
end
- -- TODO(ashkan) remove this once we have a Lua json_decode
- handle_body = schedule_wrap(handle_body)
local request_parser = coroutine.wrap(request_parser_loop)
request_parser()
diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua
index 195e3a0e65..e95f170427 100644
--- a/runtime/lua/vim/lsp/util.lua
+++ b/runtime/lua/vim/lsp/util.lua
@@ -1,4 +1,5 @@
local protocol = require 'vim.lsp.protocol'
+local snippet = require 'vim.lsp._snippet'
local vim = vim
local validate = vim.validate
local api = vim.api
@@ -30,20 +31,12 @@ local default_border = {
{" ", "NormalFloat"},
}
-
-local DiagnosticSeverity = protocol.DiagnosticSeverity
-local loclist_type_map = {
- [DiagnosticSeverity.Error] = 'E',
- [DiagnosticSeverity.Warning] = 'W',
- [DiagnosticSeverity.Information] = 'I',
- [DiagnosticSeverity.Hint] = 'I',
-}
-
-
---@private
--- Check the border given by opts or the default border for the additional
--- size it adds to a float.
---@returns size of border in height and width
+---@private
+--- Check the border given by opts or the default border for the additional
+--- size it adds to a float.
+---@param opts (table, optional) options for the floating window
+--- - border (string or table) the border
+---@returns (table) size of border in the form of { height = height, width = width }
local function get_border_size(opts)
local border = opts and opts.border or default_border
local height = 0
@@ -52,12 +45,16 @@ local function get_border_size(opts)
if type(border) == 'string' then
local border_size = {none = {0, 0}, single = {2, 2}, double = {2, 2}, rounded = {2, 2}, solid = {2, 2}, shadow = {1, 1}}
if border_size[border] == nil then
- error("floating preview border is not correct. Please refer to the docs |vim.api.nvim_open_win()|"
- .. vim.inspect(border))
+ error(string.format("invalid floating preview border: %s. :help vim.api.nvim_open_win()", vim.inspect(border)))
end
height, width = unpack(border_size[border])
else
+ if 8 % #border ~= 0 then
+ error(string.format("invalid floating preview border: %s. :help vim.api.nvim_open_win()", vim.inspect(border)))
+ end
+ ---@private
local function border_width(id)
+ id = (id - 1) % #border + 1
if type(border[id]) == "table" then
-- border specified as a table of <character, highlight group>
return vim.fn.strdisplaywidth(border[id][1])
@@ -65,9 +62,11 @@ local function get_border_size(opts)
-- border specified as a list of border characters
return vim.fn.strdisplaywidth(border[id])
end
- error("floating preview border is not correct. Please refer to the docs |vim.api.nvim_open_win()|" .. vim.inspect(border))
+ error(string.format("invalid floating preview border: %s. :help vim.api.nvim_open_win()", vim.inspect(border)))
end
+ ---@private
local function border_height(id)
+ id = (id - 1) % #border + 1
if type(border[id]) == "table" then
-- border specified as a table of <character, highlight group>
return #border[id][1] > 0 and 1 or 0
@@ -75,7 +74,7 @@ local function get_border_size(opts)
-- border specified as a list of border characters
return #border[id] > 0 and 1 or 0
end
- error("floating preview border is not correct. Please refer to the docs |vim.api.nvim_open_win()|" .. vim.inspect(border))
+ error(string.format("invalid floating preview border: %s. :help vim.api.nvim_open_win()", vim.inspect(border)))
end
height = height + border_height(2) -- top
height = height + border_height(6) -- bottom
@@ -86,7 +85,7 @@ local function get_border_size(opts)
return { height = height, width = width }
end
---@private
+---@private
local function split_lines(value)
return split(value, '\n', true)
end
@@ -95,11 +94,11 @@ end
---
--- CAUTION: Changes in-place!
---
---@param lines (table) Original list of strings
---@param A (table) Start position; a 2-tuple of {line, col} numbers
---@param B (table) End position; a 2-tuple of {line, col} numbers
---@param new_lines A list of strings to replace the original
---@returns (table) The modified {lines} object
+---@param lines (table) Original list of strings
+---@param A (table) Start position; a 2-tuple of {line, col} numbers
+---@param B (table) End position; a 2-tuple of {line, col} numbers
+---@param new_lines A list of strings to replace the original
+---@returns (table) The modified {lines} object
function M.set_lines(lines, A, B, new_lines)
-- 0-indexing to 1-indexing
local i_0 = A[1] + 1
@@ -133,7 +132,7 @@ function M.set_lines(lines, A, B, new_lines)
return lines
end
---@private
+---@private
local function sort_by_key(fn)
return function(a,b)
local ka, kb = fn(a), fn(b)
@@ -147,12 +146,8 @@ local function sort_by_key(fn)
return false
end
end
---@private
-local edit_sort_key = sort_by_key(function(e)
- return {e.A[1], e.A[2], e.i}
-end)
---@private
+---@private
--- Position is a https://microsoft.github.io/language-server-protocol/specifications/specification-current/#position
--- Returns a zero-indexed column, since set_lines() does the conversion to
--- 1-indexed
@@ -175,6 +170,7 @@ local function get_line_byte_from_position(bufnr, position)
if ok then
return result
end
+ return math.min(#lines[1], col)
end
end
return col
@@ -238,53 +234,119 @@ function M.get_progress_messages()
end
--- Applies a list of text edits to a buffer.
---@param text_edits (table) list of `TextEdit` objects
---@param buf_nr (number) Buffer id
+---@param text_edits table list of `TextEdit` objects
+---@param bufnr number Buffer id
+---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textEdit
function M.apply_text_edits(text_edits, bufnr)
if not next(text_edits) then return end
if not api.nvim_buf_is_loaded(bufnr) then
vim.fn.bufload(bufnr)
end
api.nvim_buf_set_option(bufnr, 'buflisted', true)
- local start_line, finish_line = math.huge, -1
- local cleaned = {}
- for i, e in ipairs(text_edits) do
- -- adjust start and end column for UTF-16 encoding of non-ASCII characters
- local start_row = e.range.start.line
- local start_col = get_line_byte_from_position(bufnr, e.range.start)
- local end_row = e.range["end"].line
- local end_col = get_line_byte_from_position(bufnr, e.range['end'])
- start_line = math.min(e.range.start.line, start_line)
- finish_line = math.max(e.range["end"].line, finish_line)
- -- TODO(ashkan) sanity check ranges for overlap.
- table.insert(cleaned, {
- i = i;
- A = {start_row; start_col};
- B = {end_row; end_col};
- lines = vim.split(e.newText, '\n', true);
- })
- end
- -- Reverse sort the orders so we can apply them without interfering with
- -- eachother. Also add i as a sort key to mimic a stable sort.
- table.sort(cleaned, edit_sort_key)
- local lines = api.nvim_buf_get_lines(bufnr, start_line, finish_line + 1, false)
- local fix_eol = api.nvim_buf_get_option(bufnr, 'fixeol')
- local set_eol = fix_eol and api.nvim_buf_line_count(bufnr) <= finish_line + 1
- if set_eol and (#lines == 0 or #lines[#lines] ~= 0) then
- table.insert(lines, '')
+ -- Fix reversed range and indexing each text_edits
+ local index = 0
+ text_edits = vim.tbl_map(function(text_edit)
+ index = index + 1
+ text_edit._index = index
+
+ if text_edit.range.start.line > text_edit.range['end'].line or text_edit.range.start.line == text_edit.range['end'].line and text_edit.range.start.character > text_edit.range['end'].character then
+ local start = text_edit.range.start
+ text_edit.range.start = text_edit.range['end']
+ text_edit.range['end'] = start
+ end
+ return text_edit
+ end, text_edits)
+
+ -- Sort text_edits
+ table.sort(text_edits, function(a, b)
+ if a.range.start.line ~= b.range.start.line then
+ return a.range.start.line > b.range.start.line
+ end
+ if a.range.start.character ~= b.range.start.character then
+ return a.range.start.character > b.range.start.character
+ end
+ if a._index ~= b._index then
+ return a._index > b._index
+ end
+ end)
+
+ -- Some LSP servers may return +1 range of the buffer content but nvim_buf_set_text can't accept it so we should fix it here.
+ local has_eol_text_edit = false
+ local max = vim.api.nvim_buf_line_count(bufnr)
+ local len = vim.str_utfindex(vim.api.nvim_buf_get_lines(bufnr, -2, -1, false)[1] or '')
+ text_edits = vim.tbl_map(function(text_edit)
+ if max <= text_edit.range.start.line then
+ text_edit.range.start.line = max - 1
+ text_edit.range.start.character = len
+ text_edit.newText = '\n' .. text_edit.newText
+ has_eol_text_edit = true
+ end
+ if max <= text_edit.range['end'].line then
+ text_edit.range['end'].line = max - 1
+ text_edit.range['end'].character = len
+ has_eol_text_edit = true
+ end
+ return text_edit
+ end, text_edits)
+
+ -- Some LSP servers are depending on the VSCode behavior.
+ -- The VSCode will re-locate the cursor position after applying TextEdit so we also do it.
+ local is_current_buf = vim.api.nvim_get_current_buf() == bufnr
+ local cursor = (function()
+ if not is_current_buf then
+ return {
+ row = -1,
+ col = -1,
+ }
+ end
+ local cursor = vim.api.nvim_win_get_cursor(0)
+ return {
+ row = cursor[1] - 1,
+ col = cursor[2],
+ }
+ end)()
+
+ -- Apply text edits.
+ local is_cursor_fixed = false
+ for _, text_edit in ipairs(text_edits) do
+ local e = {
+ start_row = text_edit.range.start.line,
+ start_col = get_line_byte_from_position(bufnr, text_edit.range.start),
+ end_row = text_edit.range['end'].line,
+ end_col = get_line_byte_from_position(bufnr, text_edit.range['end']),
+ text = vim.split(text_edit.newText, '\n', true),
+ }
+ vim.api.nvim_buf_set_text(bufnr, e.start_row, e.start_col, e.end_row, e.end_col, e.text)
+
+ local row_count = (e.end_row - e.start_row) + 1
+ if e.end_row < cursor.row then
+ cursor.row = cursor.row + (#e.text - row_count)
+ is_cursor_fixed = true
+ elseif e.end_row == cursor.row and e.end_col <= cursor.col then
+ cursor.row = cursor.row + (#e.text - row_count)
+ cursor.col = #e.text[#e.text] + (cursor.col - e.end_col)
+ if #e.text == 1 then
+ cursor.col = cursor.col + e.start_col
+ end
+ is_cursor_fixed = true
+ end
end
- for i = #cleaned, 1, -1 do
- local e = cleaned[i]
- local A = {e.A[1] - start_line, e.A[2]}
- local B = {e.B[1] - start_line, e.B[2]}
- lines = M.set_lines(lines, A, B, e.lines)
+ if is_cursor_fixed then
+ vim.api.nvim_win_set_cursor(0, {
+ cursor.row + 1,
+ math.min(cursor.col, #(vim.api.nvim_buf_get_lines(bufnr, cursor.row, cursor.row + 1, false)[1] or ''))
+ })
end
- if set_eol and #lines[#lines] == 0 then
- table.remove(lines)
+
+ -- Remove final line if needed
+ local fix_eol = has_eol_text_edit
+ fix_eol = fix_eol and api.nvim_buf_get_option(bufnr, 'fixeol')
+ fix_eol = fix_eol and (vim.api.nvim_buf_get_lines(bufnr, -2, -1, false)[1] or '') == ''
+ if fix_eol then
+ vim.api.nvim_buf_set_lines(bufnr, -2, -1, false, {})
end
- api.nvim_buf_set_lines(bufnr, start_line, finish_line + 1, false, lines)
end
-- local valid_windows_path_characters = "[^<>:\"/\\|?*]"
@@ -294,11 +356,11 @@ end
-- function M.glob_to_regex(glob)
-- end
---@private
+---@private
--- Finds the first line and column of the difference between old and new lines
---@param old_lines table list of lines
---@param new_lines table list of lines
---@returns (int, int) start_line_idx and start_col_idx of range
+---@param old_lines table list of lines
+---@param new_lines table list of lines
+---@returns (int, int) start_line_idx and start_col_idx of range
local function first_difference(old_lines, new_lines, start_line_idx)
local line_count = math.min(#old_lines, #new_lines)
if line_count == 0 then return 1, 1 end
@@ -324,12 +386,12 @@ local function first_difference(old_lines, new_lines, start_line_idx)
end
---@private
+---@private
--- Finds the last line and column of the differences between old and new lines
---@param old_lines table list of lines
---@param new_lines table list of lines
---@param start_char integer First different character idx of range
---@returns (int, int) end_line_idx and end_col_idx of range
+---@param old_lines table list of lines
+---@param new_lines table list of lines
+---@param start_char integer First different character idx of range
+---@returns (int, int) end_line_idx and end_col_idx of range
local function last_difference(old_lines, new_lines, start_char, end_line_idx)
local line_count = math.min(#old_lines, #new_lines)
if line_count == 0 then return 0,0 end
@@ -368,14 +430,14 @@ local function last_difference(old_lines, new_lines, start_char, end_line_idx)
end
---@private
+---@private
--- Get the text of the range defined by start and end line/column
---@param lines table list of lines
---@param start_char integer First different character idx of range
---@param end_char integer Last different character idx of range
---@param start_line integer First different line idx of range
---@param end_line integer Last different line idx of range
---@returns string text extracted from defined region
+---@param lines table list of lines
+---@param start_char integer First different character idx of range
+---@param end_char integer Last different character idx of range
+---@param start_line integer First different line idx of range
+---@param end_line integer Last different line idx of range
+---@returns string text extracted from defined region
local function extract_text(lines, start_line, start_char, end_line, end_char)
if start_line == #lines + end_line + 1 then
if end_line == 0 then return '' end
@@ -395,14 +457,14 @@ local function extract_text(lines, start_line, start_char, end_line, end_char)
return result
end
---@private
+---@private
--- Compute the length of the substituted range
---@param lines table list of lines
---@param start_char integer First different character idx of range
---@param end_char integer Last different character idx of range
---@param start_line integer First different line idx of range
---@param end_line integer Last different line idx of range
---@returns (int, int) end_line_idx and end_col_idx of range
+---@param lines table list of lines
+---@param start_char integer First different character idx of range
+---@param end_char integer Last different character idx of range
+---@param start_line integer First different line idx of range
+---@param end_line integer Last different line idx of range
+---@returns (int, int) end_line_idx and end_col_idx of range
local function compute_length(lines, start_line, start_char, end_line, end_char)
local adj_end_line = #lines + end_line + 1
local adj_end_char
@@ -423,12 +485,12 @@ local function compute_length(lines, start_line, start_char, end_line, end_char)
end
--- Returns the range table for the difference between old and new lines
---@param old_lines table list of lines
---@param new_lines table list of lines
---@param start_line_idx int line to begin search for first difference
---@param end_line_idx int line to begin search for last difference
---@param offset_encoding string encoding requested by language server
---@returns table start_line_idx and start_col_idx of range
+---@param old_lines table list of lines
+---@param new_lines table list of lines
+---@param start_line_idx int line to begin search for first difference
+---@param end_line_idx int line to begin search for last difference
+---@param offset_encoding string encoding requested by language server
+---@returns table start_line_idx and start_col_idx of range
function M.compute_diff(old_lines, new_lines, start_line_idx, end_line_idx, offset_encoding)
local start_line, start_char = first_difference(old_lines, new_lines, start_line_idx)
local end_line, end_char = last_difference(vim.list_slice(old_lines, start_line, #old_lines),
@@ -468,9 +530,9 @@ end
--- Can be used to extract the completion items from a
--- `textDocument/completion` request, which may return one of
--- `CompletionItem[]`, `CompletionList` or null.
---@param result (table) The result of a `textDocument/completion` request
---@returns (table) List of completion items
---@see https://microsoft.github.io/language-server-protocol/specification#textDocument_completion
+---@param result (table) The result of a `textDocument/completion` request
+---@returns (table) List of completion items
+---@see https://microsoft.github.io/language-server-protocol/specification#textDocument_completion
function M.extract_completion_items(result)
if type(result) == 'table' and result.items then
-- result is a `CompletionList`
@@ -514,90 +576,34 @@ function M.apply_text_document_edit(text_document_edit, index)
M.apply_text_edits(text_document_edit.edits, bufnr)
end
---@private
---- Recursively parses snippets in a completion entry.
----
---@param input (string) Snippet text to parse for snippets
---@param inner (bool) Whether this function is being called recursively
---@returns 2-tuple of strings: The first is the parsed result, the second is the
----unparsed rest of the input
-local function parse_snippet_rec(input, inner)
- local res = ""
-
- local close, closeend = nil, nil
- if inner then
- close, closeend = input:find("}", 1, true)
- while close ~= nil and input:sub(close-1,close-1) == "\\" do
- close, closeend = input:find("}", closeend+1, true)
- end
- end
-
- local didx = input:find('$', 1, true)
- if didx == nil and close == nil then
- return input, ""
- elseif close ~=nil and (didx == nil or close < didx) then
- -- No inner placeholders
- return input:sub(0, close-1), input:sub(closeend+1)
- end
-
- res = res .. input:sub(0, didx-1)
- input = input:sub(didx+1)
-
- local tabstop, tabstopend = input:find('^%d+')
- local placeholder, placeholderend = input:find('^{%d+:')
- local choice, choiceend = input:find('^{%d+|')
-
- if tabstop then
- input = input:sub(tabstopend+1)
- elseif choice then
- input = input:sub(choiceend+1)
- close, closeend = input:find("|}", 1, true)
-
- res = res .. input:sub(0, close-1)
- input = input:sub(closeend+1)
- elseif placeholder then
- -- TODO: add support for variables
- input = input:sub(placeholderend+1)
-
- -- placeholders and variables are recursive
- while input ~= "" do
- local r, tail = parse_snippet_rec(input, true)
- r = r:gsub("\\}", "}")
-
- res = res .. r
- input = tail
- end
- else
- res = res .. "$"
- end
-
- return res, input
-end
-
--- Parses snippets in a completion entry.
---
---@param input (string) unparsed snippet
---@returns (string) parsed snippet
+---@param input string unparsed snippet
+---@returns string parsed snippet
function M.parse_snippet(input)
- local res, _ = parse_snippet_rec(input, false)
-
- return res
+ local ok, parsed = pcall(function()
+ return tostring(snippet.parse(input))
+ end)
+ if not ok then
+ return input
+ end
+ return parsed
end
---@private
+---@private
--- Sorts by CompletionItem.sortText.
---
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
+--see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
local function sort_completion_items(items)
table.sort(items, function(a, b)
return (a.sortText or a.label) < (b.sortText or b.label)
end)
end
---@private
+---@private
--- Returns text that should be inserted when selecting completion item. The
--- precedence is as follows: textEdit.newText > insertText > label
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
+--see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
local function get_completion_word(item)
if item.textEdit ~= nil and item.textEdit.newText ~= nil and item.textEdit.newText ~= "" then
local insert_text_format = protocol.InsertTextFormat[item.insertTextFormat]
@@ -617,7 +623,7 @@ local function get_completion_word(item)
return item.label
end
---@private
+---@private
--- Some language servers return complementary candidates whose prefixes do not
--- match are also returned. So we exclude completion candidates whose prefix
--- does not match.
@@ -632,9 +638,9 @@ end
--- the client must handle it properly even if it receives a value outside the
--- specification.
---
---@param completion_item_kind (`vim.lsp.protocol.completionItemKind`)
---@returns (`vim.lsp.protocol.completionItemKind`)
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
+---@param completion_item_kind (`vim.lsp.protocol.completionItemKind`)
+---@returns (`vim.lsp.protocol.completionItemKind`)
+---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion
function M._get_completion_item_kind_name(completion_item_kind)
return protocol.CompletionItemKind[completion_item_kind] or "Unknown"
end
@@ -642,12 +648,12 @@ end
--- Turns the result of a `textDocument/completion` request into vim-compatible
--- |complete-items|.
---
---@param result The result of a `textDocument/completion` call, e.g. from
+---@param result The result of a `textDocument/completion` call, e.g. from
---|vim.lsp.buf.completion()|, which may be one of `CompletionItem[]`,
--- `CompletionList` or `null`
---@param prefix (string) the prefix to filter the completion items
---@returns { matches = complete-items table, incomplete = bool }
---@see |complete-items|
+---@param prefix (string) the prefix to filter the completion items
+---@returns { matches = complete-items table, incomplete = bool }
+---@see |complete-items|
function M.text_document_completion_list_to_complete_items(result, prefix)
local items = M.extract_completion_items(result)
if vim.tbl_isempty(items) then
@@ -697,8 +703,8 @@ end
--- Rename old_fname to new_fname
---
---@param opts (table)
+---
+---@param opts (table)
-- overwrite? bool
-- ignoreIfExists? bool
function M.rename(old_fname, new_fname, opts)
@@ -753,8 +759,8 @@ end
--- Applies a `WorkspaceEdit`.
---
---@param workspace_edit (table) `WorkspaceEdit`
--- @see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit
+---@param workspace_edit (table) `WorkspaceEdit`
+--see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit
function M.apply_workspace_edit(workspace_edit)
if workspace_edit.documentChanges then
for idx, change in ipairs(workspace_edit.documentChanges) do
@@ -793,10 +799,10 @@ end
--- window for `textDocument/hover`, for parsing the result of
--- `textDocument/signatureHelp`, and potentially others.
---
---@param input (`MarkedString` | `MarkedString[]` | `MarkupContent`)
---@param contents (table, optional, default `{}`) List of strings to extend with converted lines
---@returns {contents}, extended with lines of converted markdown.
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover
+---@param input (`MarkedString` | `MarkedString[]` | `MarkupContent`)
+---@param contents (table, optional, default `{}`) List of strings to extend with converted lines
+---@returns {contents}, extended with lines of converted markdown.
+---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover
function M.convert_input_to_markdown_lines(input, contents)
contents = contents or {}
-- MarkedString variation 1
@@ -810,16 +816,16 @@ function M.convert_input_to_markdown_lines(input, contents)
-- If it's plaintext, then wrap it in a <text></text> block
-- Some servers send input.value as empty, so let's ignore this :(
- input.value = input.value or ''
+ local value = input.value or ''
if input.kind == "plaintext" then
-- wrap this in a <text></text> block so that stylize_markdown
-- can properly process it as plaintext
- input.value = string.format("<text>\n%s\n</text>", input.value or "")
+ value = string.format("<text>\n%s\n</text>", value)
end
- -- assert(type(input.value) == 'string')
- list_extend(contents, split_lines(input.value))
+ -- assert(type(value) == 'string')
+ list_extend(contents, split_lines(value))
-- MarkupString variation 2
elseif input.language then
-- Some servers send input.value as empty, so let's ignore this :(
@@ -843,11 +849,12 @@ end
--- Converts `textDocument/SignatureHelp` response to markdown lines.
---
---@param signature_help Response of `textDocument/SignatureHelp`
---@param ft optional filetype that will be use as the `lang` for the label markdown code block
---@returns list of lines of converted markdown.
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp
-function M.convert_signature_help_to_markdown_lines(signature_help, ft)
+---@param signature_help Response of `textDocument/SignatureHelp`
+---@param ft optional filetype that will be use as the `lang` for the label markdown code block
+---@param triggers optional list of trigger characters from the lsp server. used to better determine parameter offsets
+---@returns list of lines of converted markdown.
+---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_signatureHelp
+function M.convert_signature_help_to_markdown_lines(signature_help, ft, triggers)
if not signature_help.signatures then
return
end
@@ -856,6 +863,7 @@ function M.convert_signature_help_to_markdown_lines(signature_help, ft)
--=== 0`. Whenever possible implementors should make an active decision about
--the active signature and shouldn't rely on a default value.
local contents = {}
+ local active_hl
local active_signature = signature_help.activeSignature or 0
-- If the activeSignature is not inside the valid range, then clip it.
if active_signature >= #signature_help.signatures then
@@ -875,11 +883,17 @@ function M.convert_signature_help_to_markdown_lines(signature_help, ft)
M.convert_input_to_markdown_lines(signature.documentation, contents)
end
if signature.parameters and #signature.parameters > 0 then
- local active_parameter = signature_help.activeParameter or 0
- -- If the activeParameter is not inside the valid range, then clip it.
+ local active_parameter = (signature.activeParameter or signature_help.activeParameter or 0)
+ if active_parameter < 0
+ then active_parameter = 0
+ end
+
+ -- If the activeParameter is > #parameters, then set it to the last
+ -- NOTE: this is not fully according to the spec, but a client-side interpretation
if active_parameter >= #signature.parameters then
- active_parameter = 0
+ active_parameter = #signature.parameters - 1
end
+
local parameter = signature.parameters[active_parameter + 1]
if parameter then
--[=[
@@ -900,22 +914,44 @@ function M.convert_signature_help_to_markdown_lines(signature_help, ft)
documentation?: string | MarkupContent;
}
--]=]
- -- TODO highlight parameter
+ if parameter.label then
+ if type(parameter.label) == "table" then
+ active_hl = parameter.label
+ else
+ local offset = 1
+ -- try to set the initial offset to the first found trigger character
+ for _, t in ipairs(triggers or {}) do
+ local trigger_offset = signature.label:find(t, 1, true)
+ if trigger_offset and (offset == 1 or trigger_offset < offset) then
+ offset = trigger_offset
+ end
+ end
+ for p, param in pairs(signature.parameters) do
+ offset = signature.label:find(param.label, offset, true)
+ if not offset then break end
+ if p == active_parameter + 1 then
+ active_hl = {offset - 1, offset + #parameter.label - 1}
+ break
+ end
+ offset = offset + #param.label + 1
+ end
+ end
+ end
if parameter.documentation then
M.convert_input_to_markdown_lines(parameter.documentation, contents)
end
end
end
- return contents
+ return contents, active_hl
end
--- Creates a table with sensible default options for a floating window. The
--- table can be passed to |nvim_open_win()|.
---
---@param width (number) window width (in character cells)
---@param height (number) window height (in character cells)
---@param opts (table, optional)
---@returns (table) Options
+---@param width (number) window width (in character cells)
+---@param height (number) window height (in character cells)
+---@param opts (table, optional)
+---@returns (table) Options
function M.make_floating_popup_options(width, height, opts)
validate {
opts = { opts, 't', true };
@@ -942,7 +978,7 @@ function M.make_floating_popup_options(width, height, opts)
row = -get_border_size(opts).height
end
- if vim.fn.wincol() + width <= api.nvim_get_option('columns') then
+ if vim.fn.wincol() + width + (opts.offset_x or 0) <= api.nvim_get_option('columns') then
anchor = anchor..'W'
col = 0
else
@@ -960,13 +996,14 @@ function M.make_floating_popup_options(width, height, opts)
style = 'minimal',
width = width,
border = opts.border or default_border,
+ zindex = opts.zindex or 50,
}
end
--- Jumps to a location.
---
---@param location (`Location`|`LocationLink`)
---@returns `true` if the jump succeeded
+---@param location (`Location`|`LocationLink`)
+---@returns `true` if the jump succeeded
function M.jump_to_location(location)
-- location may be Location or LocationLink
local uri = location.uri or location.targetUri
@@ -996,8 +1033,8 @@ end
--- - for Location, range is shown (e.g., function definition)
--- - for LocationLink, targetRange is shown (e.g., body of function definition)
---
---@param location a single `Location` or `LocationLink`
---@returns (bufnr,winnr) buffer and window number of floating window or nil
+---@param location a single `Location` or `LocationLink`
+---@returns (bufnr,winnr) buffer and window number of floating window or nil
function M.preview_location(location, opts)
-- location may be LocationLink or Location (more useful for the former)
local uri = location.targetUri or location.uri
@@ -1020,7 +1057,7 @@ function M.preview_location(location, opts)
return M.open_floating_preview(contents, syntax, opts)
end
---@private
+---@private
local function find_window_by_var(name, value)
for _, win in ipairs(api.nvim_list_wins()) do
if npcall(api.nvim_win_get_var, win, name) == value then
@@ -1056,10 +1093,10 @@ function M._trim(contents, opts)
return contents
end
--- Generates a table mapping markdown code block lang to vim syntax,
--- based on g:markdown_fenced_languages
--- @return a table of lang -> syntax mappings
--- @private
+--- Generates a table mapping markdown code block lang to vim syntax,
+--- based on g:markdown_fenced_languages
+---@return a table of lang -> syntax mappings
+---@private
local function get_markdown_fences()
local fences = {}
for _, fence in pairs(vim.g.markdown_fenced_languages or {}) do
@@ -1129,6 +1166,8 @@ function M.stylize_markdown(bufnr, contents, opts)
-- Clean up
contents = M._trim(contents, opts)
+ -- Insert blank line separator after code block?
+ local add_sep = opts.separator == nil and true or opts.separator
local stripped = {}
local highlights = {}
-- keep track of lnums that contain markdown
@@ -1155,9 +1194,24 @@ function M.stylize_markdown(bufnr, contents, opts)
start = start + 1;
finish = #stripped;
})
+ -- add a separator, but not on the last line
+ if add_sep and i < #contents then
+ table.insert(stripped, "---")
+ markdown_lines[#stripped] = true
+ end
else
- table.insert(stripped, line)
- markdown_lines[#stripped] = true
+ -- strip any emty lines or separators prior to this separator in actual markdown
+ if line:match("^---+$") then
+ while markdown_lines[#stripped] and (stripped[#stripped]:match("^%s*$") or stripped[#stripped]:match("^---+$")) do
+ markdown_lines[#stripped] = false
+ table.remove(stripped, #stripped)
+ end
+ end
+ -- add the line if its not an empty line following a separator
+ if not (line:match("^%s*$") and markdown_lines[#stripped] and stripped[#stripped]:match("^---+$")) then
+ table.insert(stripped, line)
+ markdown_lines[#stripped] = true
+ end
i = i + 1
end
end
@@ -1165,7 +1219,7 @@ function M.stylize_markdown(bufnr, contents, opts)
-- Compute size of float needed to show (wrapped) lines
opts.wrap_at = opts.wrap_at or (vim.wo["wrap"] and api.nvim_win_get_width(0))
- local width, height = M._make_floating_popup_size(stripped, opts)
+ local width = M._make_floating_popup_size(stripped, opts)
local sep_line = string.rep("─", math.min(width, opts.wrap_at or width))
@@ -1175,30 +1229,10 @@ function M.stylize_markdown(bufnr, contents, opts)
end
end
- -- Insert blank line separator after code block
- local insert_separator = opts.separator
- if insert_separator == nil then insert_separator = true end
- if insert_separator then
- local offset = 0
- for _, h in ipairs(highlights) do
- h.start = h.start + offset
- h.finish = h.finish + offset
- -- check if a seperator already exists and use that one instead of creating a new one
- if h.finish + 1 <= #stripped then
- if stripped[h.finish + 1] ~= sep_line then
- table.insert(stripped, h.finish + 1, sep_line)
- offset = offset + 1
- height = height + 1
- end
- end
- end
- end
-
-
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, stripped)
local idx = 1
- --@private
+ ---@private
-- keep track of syntaxes we already inlcuded.
-- no need to include the same syntax more than once
local langs = {}
@@ -1247,26 +1281,26 @@ end
--- Creates autocommands to close a preview window when events happen.
---
---@param events (table) list of events
---@param winnr (number) window id of preview window
---@see |autocmd-events|
+---@param events (table) list of events
+---@param winnr (number) window id of preview window
+---@see |autocmd-events|
function M.close_preview_autocmd(events, winnr)
if #events > 0 then
api.nvim_command("autocmd "..table.concat(events, ',').." <buffer> ++once lua pcall(vim.api.nvim_win_close, "..winnr..", true)")
end
end
---@internal
+---@internal
--- Computes size of float needed to show contents (with optional wrapping)
---
---@param contents table of lines to show in window
---@param opts dictionary with optional fields
--- - height of floating window
--- - width of floating window
--- - wrap_at character to wrap at for computing height
--- - max_width maximal width of floating window
--- - max_height maximal height of floating window
---@returns width,height size of float
+---@param contents table of lines to show in window
+---@param opts dictionary with optional fields
+--- - height of floating window
+--- - width of floating window
+--- - wrap_at character to wrap at for computing height
+--- - max_width maximal width of floating window
+--- - max_height maximal height of floating window
+---@returns width,height size of float
function M._make_floating_popup_size(contents, opts)
validate {
contents = { contents, 't' };
@@ -1333,9 +1367,9 @@ end
--- Shows contents in a floating window.
---
---@param contents table of lines to show in window
---@param syntax string of syntax to set for opened buffer
---@param opts dictionary with optional fields
+---@param contents table of lines to show in window
+---@param syntax string of syntax to set for opened buffer
+---@param opts dictionary with optional fields
--- - height of floating window
--- - width of floating window
--- - wrap boolean enable wrapping of long lines (defaults to true)
@@ -1349,7 +1383,7 @@ end
--- - focus_id if a popup with this id is opened, then focus it
--- - close_events list of events that closes the floating window
--- - focusable (boolean, default true): Make float focusable
---@returns bufnr,winnr buffer and window number of the newly created floating
+---@returns bufnr,winnr buffer and window number of the newly created floating
---preview window
function M.open_floating_preview(contents, syntax, opts)
validate {
@@ -1445,7 +1479,7 @@ do --[[ References ]]
--- Removes document highlights from a buffer.
---
- --@param bufnr buffer id
+ ---@param bufnr buffer id
function M.buf_clear_references(bufnr)
validate { bufnr = {bufnr, 'n', true} }
api.nvim_buf_clear_namespace(bufnr, reference_ns, 0, -1)
@@ -1453,8 +1487,9 @@ do --[[ References ]]
--- Shows a list of document highlights for a certain buffer.
---
- --@param bufnr buffer id
- --@param references List of `DocumentHighlight` objects to highlight
+ ---@param bufnr buffer id
+ ---@param references List of `DocumentHighlight` objects to highlight
+ ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-3-17/#documentHighlight
function M.buf_highlight_references(bufnr, references)
validate { bufnr = {bufnr, 'n', true} }
for _, reference in ipairs(references) do
@@ -1475,24 +1510,24 @@ local position_sort = sort_by_key(function(v)
return {v.start.line, v.start.character}
end)
--- Gets the zero-indexed line from the given uri.
+--- Gets the zero-indexed line from the given uri.
+---@param uri string uri of the resource to get the line from
+---@param row number zero-indexed line number
+---@return string the line at row in filename
-- For non-file uris, we load the buffer and get the line.
-- If a loaded buffer exists, then that is used.
-- Otherwise we get the line using libuv which is a lot faster than loading the buffer.
---@param uri string uri of the resource to get the line from
---@param row number zero-indexed line number
---@return string the line at row in filename
function M.get_line(uri, row)
return M.get_lines(uri, { row })[row]
end
--- Gets the zero-indexed lines from the given uri.
+--- Gets the zero-indexed lines from the given uri.
+---@param uri string uri of the resource to get the lines from
+---@param rows number[] zero-indexed line numbers
+---@return table<number string> a table mapping rows to lines
-- For non-file uris, we load the buffer and get the lines.
-- If a loaded buffer exists, then that is used.
-- Otherwise we get the lines using libuv which is a lot faster than loading the buffer.
---@param uri string uri of the resource to get the lines from
---@param rows number[] zero-indexed line numbers
---@return table<number string> a table mapping rows to lines
function M.get_lines(uri, rows)
rows = type(rows) == "table" and rows or { rows }
@@ -1560,8 +1595,11 @@ end
--- Returns the items with the byte position calculated correctly and in sorted
--- order, for display in quickfix and location lists.
---
---@param locations (table) list of `Location`s or `LocationLink`s
---@returns (table) list of items
+--- The result can be passed to the {list} argument of |setqflist()| or
+--- |setloclist()|.
+---
+---@param locations (table) list of `Location`s or `LocationLink`s
+---@returns (table) list of items
function M.locations_to_items(locations)
local items = {}
local grouped = setmetatable({}, {
@@ -1618,7 +1656,9 @@ end
--- Can be obtained with e.g. |vim.lsp.util.locations_to_items()|.
--- Defaults to current window.
---
---@param items (table) list of items
+---@deprecated Use |setloclist()|
+---
+---@param items (table) list of items
function M.set_loclist(items, win_id)
vim.fn.setloclist(win_id or 0, {}, ' ', {
title = 'Language Server';
@@ -1629,7 +1669,9 @@ end
--- Fills quickfix list with given list of items.
--- Can be obtained with e.g. |vim.lsp.util.locations_to_items()|.
---
---@param items (table) list of items
+---@deprecated Use |setqflist()|
+---
+---@param items (table) list of items
function M.set_qflist(items)
vim.fn.setqflist({}, ' ', {
title = 'Language Server';
@@ -1646,9 +1688,9 @@ end
--- Converts symbols to quickfix list items.
---
---@param symbols DocumentSymbol[] or SymbolInformation[]
+---@param symbols DocumentSymbol[] or SymbolInformation[]
function M.symbols_to_items(symbols, bufnr)
- --@private
+ ---@private
local function _symbols_to_items(_symbols, _items, _bufnr)
for _, symbol in ipairs(_symbols) do
if symbol.location then -- SymbolInformation type
@@ -1684,19 +1726,19 @@ function M.symbols_to_items(symbols, bufnr)
end
--- Removes empty lines from the beginning and end.
---@param lines (table) list of lines to trim
---@returns (table) trimmed list of lines
+---@param lines (table) list of lines to trim
+---@returns (table) trimmed list of lines
function M.trim_empty_lines(lines)
local start = 1
for i = 1, #lines do
- if #lines[i] > 0 then
+ if lines[i] ~= nil and #lines[i] > 0 then
start = i
break
end
end
local finish = 1
for i = #lines, 1, -1 do
- if #lines[i] > 0 then
+ if lines[i] ~= nil and #lines[i] > 0 then
finish = i
break
end
@@ -1709,8 +1751,8 @@ end
---
--- CAUTION: Modifies the input in-place!
---
---@param lines (table) list of lines
---@returns (string) filetype or 'markdown' if it was unchanged.
+---@param lines (table) list of lines
+---@returns (string) filetype or 'markdown' if it was unchanged.
function M.try_trim_markdown_code_blocks(lines)
local language_id = lines[1]:match("^```(.*)")
if language_id then
@@ -1733,7 +1775,7 @@ function M.try_trim_markdown_code_blocks(lines)
end
local str_utfindex = vim.str_utfindex
---@private
+---@private
local function make_position_param()
local row, col = unpack(api.nvim_win_get_cursor(0))
row = row - 1
@@ -1747,8 +1789,8 @@ end
--- Creates a `TextDocumentPositionParams` object for the current buffer and cursor position.
---
---@returns `TextDocumentPositionParams` object
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams
+---@returns `TextDocumentPositionParams` object
+---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentPositionParams
function M.make_position_params()
return {
textDocument = M.make_text_document_params();
@@ -1761,7 +1803,7 @@ end
--- `textDocument/codeAction`, `textDocument/colorPresentation`,
--- `textDocument/rangeFormatting`.
---
---@returns { textDocument = { uri = `current_file_uri` }, range = { start =
+---@returns { textDocument = { uri = `current_file_uri` }, range = { start =
---`current_position`, end = `current_position` } }
function M.make_range_params()
local position = make_position_param()
@@ -1774,11 +1816,11 @@ end
--- Using the given range in the current buffer, creates an object that
--- is similar to |vim.lsp.util.make_range_params()|.
---
---@param start_pos ({number, number}, optional) mark-indexed position.
+---@param start_pos ({number, number}, optional) mark-indexed position.
---Defaults to the start of the last visual selection.
---@param end_pos ({number, number}, optional) mark-indexed position.
+---@param end_pos ({number, number}, optional) mark-indexed position.
---Defaults to the end of the last visual selection.
---@returns { textDocument = { uri = `current_file_uri` }, range = { start =
+---@returns { textDocument = { uri = `current_file_uri` }, range = { start =
---`start_position`, end = `end_position` } }
function M.make_given_range_params(start_pos, end_pos)
validate {
@@ -1814,23 +1856,23 @@ end
--- Creates a `TextDocumentIdentifier` object for the current buffer.
---
---@returns `TextDocumentIdentifier`
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentIdentifier
+---@returns `TextDocumentIdentifier`
+---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentIdentifier
function M.make_text_document_params()
return { uri = vim.uri_from_bufnr(0) }
end
--- Create the workspace params
---@param added
---@param removed
+---@param added
+---@param removed
function M.make_workspace_params(added, removed)
return { event = { added = added; removed = removed; } }
end
--- Returns visual width of tabstop.
---
---@see |softtabstop|
---@param bufnr (optional, number): Buffer handle, defaults to current
---@returns (number) tabstop visual width
+---@see |softtabstop|
+---@param bufnr (optional, number): Buffer handle, defaults to current
+---@returns (number) tabstop visual width
function M.get_effective_tabstop(bufnr)
validate { bufnr = {bufnr, 'n', true} }
local bo = bufnr and vim.bo[bufnr] or vim.bo
@@ -1838,11 +1880,11 @@ function M.get_effective_tabstop(bufnr)
return (sts > 0 and sts) or (sts < 0 and bo.shiftwidth) or bo.tabstop
end
---- Creates a `FormattingOptions` object for the current buffer and cursor position.
+--- Creates a `DocumentFormattingParams` object for the current buffer and cursor position.
---
---@param options Table with valid `FormattingOptions` entries
---@returns `FormattingOptions object
---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting
+---@param options Table with valid `FormattingOptions` entries
+---@returns `DocumentFormattingParams` object
+---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting
function M.make_formatting_params(options)
validate { options = {options, 't', true} }
options = vim.tbl_extend('keep', options or {}, {
@@ -1857,10 +1899,10 @@ end
--- Returns the UTF-32 and UTF-16 offsets for a position in a certain buffer.
---
---@param buf buffer id (0 for current)
---@param row 0-indexed line
---@param col 0-indexed byte offset in line
---@returns (number, number) UTF-32 and UTF-16 index of the character in line {row} column {col} in buffer {buf}
+---@param buf buffer id (0 for current)
+---@param row 0-indexed line
+---@param col 0-indexed byte offset in line
+---@returns (number, number) UTF-32 and UTF-16 index of the character in line {row} column {col} in buffer {buf}
function M.character_offset(bufnr, row, col)
local uri = vim.uri_from_bufnr(bufnr)
local line = M.get_line(uri, row)
@@ -1873,9 +1915,9 @@ end
--- Helper function to return nested values in language server settings
---
---@param settings a table of language server settings
---@param section a string indicating the field of the settings table
---@returns (table or string) The value of settings accessed via section
+---@param settings a table of language server settings
+---@param section a string indicating the field of the settings table
+---@returns (table or string) The value of settings accessed via section
function M.lookup_section(settings, section)
for part in vim.gsplit(section, '.', true) do
settings = settings[part]
@@ -1886,40 +1928,6 @@ function M.lookup_section(settings, section)
return settings
end
-
---- Convert diagnostics grouped by bufnr to a list of items for use in the
---- quickfix or location list.
----
---@param diagnostics_by_bufnr table bufnr -> Diagnostic[]
---@param predicate an optional function to filter the diagnostics.
--- If present, only diagnostic items matching will be included.
---@return table (A list of items)
-function M.diagnostics_to_items(diagnostics_by_bufnr, predicate)
- local items = {}
- for bufnr, diagnostics in pairs(diagnostics_by_bufnr or {}) do
- for _, d in pairs(diagnostics) do
- if not predicate or predicate(d) then
- table.insert(items, {
- bufnr = bufnr,
- lnum = d.range.start.line + 1,
- col = d.range.start.character + 1,
- text = d.message,
- type = loclist_type_map[d.severity or DiagnosticSeverity.Error] or 'E'
- })
- end
- end
- end
- table.sort(items, function(a, b)
- if a.bufnr == b.bufnr then
- return a.lnum < b.lnum
- else
- return a.bufnr < b.bufnr
- end
- end)
- return items
-end
-
-
M._get_line_byte_from_position = get_line_byte_from_position
M._warn_once = warn_once
diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
index 0a663628a5..18c1e21049 100644
--- a/runtime/lua/vim/shared.lua
+++ b/runtime/lua/vim/shared.lua
@@ -12,8 +12,8 @@ local vim = vim or {}
--- same functions as those in the input table. Userdata and threads are not
--- copied and will throw an error.
---
---@param orig Table to copy
---@returns New table of copied keys and (nested) values.
+---@param orig Table to copy
+---@returns New table of copied keys and (nested) values.
function vim.deepcopy(orig) end -- luacheck: no unused
vim.deepcopy = (function()
local function _id(v)
@@ -52,14 +52,14 @@ end)()
--- Splits a string at each instance of a separator.
---
---@see |vim.split()|
---@see https://www.lua.org/pil/20.2.html
---@see http://lua-users.org/wiki/StringLibraryTutorial
+---@see |vim.split()|
+---@see https://www.lua.org/pil/20.2.html
+---@see http://lua-users.org/wiki/StringLibraryTutorial
---
---@param s String to split
---@param sep Separator string or pattern
---@param plain If `true` use `sep` literally (passed to String.find)
---@returns Iterator over the split components
+---@param s String to split
+---@param sep Separator string or pattern
+---@param plain If `true` use `sep` literally (passed to String.find)
+---@returns Iterator over the split components
function vim.gsplit(s, sep, plain)
vim.validate{s={s,'s'},sep={sep,'s'},plain={plain,'b',true}}
@@ -101,12 +101,12 @@ end
--- split(x*yz*o, "*", true) --> {'x','yz','o'}
--- </pre>
--
---@see |vim.gsplit()|
+---@see |vim.gsplit()|
---
---@param s String to split
---@param sep Separator string or pattern
---@param plain If `true` use `sep` literally (passed to String.find)
---@returns List-like table of the split components.
+---@param s String to split
+---@param sep Separator string or pattern
+---@param plain If `true` use `sep` literally (passed to String.find)
+---@returns List-like table of the split components.
function vim.split(s,sep,plain)
local t={} for c in vim.gsplit(s, sep, plain) do table.insert(t,c) end
return t
@@ -115,10 +115,10 @@ end
--- Return a list of all keys used in a table.
--- However, the order of the return table of keys is not guaranteed.
---
---@see From https://github.com/premake/premake-core/blob/master/src/base/table.lua
+---@see From https://github.com/premake/premake-core/blob/master/src/base/table.lua
---
---@param t Table
---@returns list of keys
+---@param t Table
+---@returns list of keys
function vim.tbl_keys(t)
assert(type(t) == 'table', string.format("Expected table, got %s", type(t)))
@@ -132,8 +132,8 @@ end
--- Return a list of all values used in a table.
--- However, the order of the return table of values is not guaranteed.
---
---@param t Table
---@returns list of values
+---@param t Table
+---@returns list of values
function vim.tbl_values(t)
assert(type(t) == 'table', string.format("Expected table, got %s", type(t)))
@@ -146,8 +146,8 @@ end
--- Apply a function to all values of a table.
---
---@param func function or callable table
---@param t table
+---@param func function or callable table
+---@param t table
function vim.tbl_map(func, t)
vim.validate{func={func,'c'},t={t,'t'}}
@@ -160,8 +160,8 @@ end
--- Filter a table using a predicate function
---
---@param func function or callable table
---@param t table
+---@param func function or callable table
+---@param t table
function vim.tbl_filter(func, t)
vim.validate{func={func,'c'},t={t,'t'}}
@@ -176,9 +176,9 @@ end
--- Checks if a list-like (vector) table contains `value`.
---
---@param t Table to check
---@param value Value to compare
---@returns true if `t` contains `value`
+---@param t Table to check
+---@param value Value to compare
+---@returns true if `t` contains `value`
function vim.tbl_contains(t, value)
vim.validate{t={t,'t'}}
@@ -192,14 +192,20 @@ end
--- Checks if a table is empty.
---
---@see https://github.com/premake/premake-core/blob/master/src/base/table.lua
+---@see https://github.com/premake/premake-core/blob/master/src/base/table.lua
---
---@param t Table to check
+---@param t Table to check
function vim.tbl_isempty(t)
assert(type(t) == 'table', string.format("Expected table, got %s", type(t)))
return next(t) == nil
end
+--- we only merge empty tables or tables that are not a list
+---@private
+local function can_merge(v)
+ return type(v) == "table" and (vim.tbl_isempty(v) or not vim.tbl_islist(v))
+end
+
local function tbl_extend(behavior, deep_extend, ...)
if (behavior ~= 'error' and behavior ~= 'keep' and behavior ~= 'force') then
error('invalid "behavior": '..tostring(behavior))
@@ -219,8 +225,8 @@ local function tbl_extend(behavior, deep_extend, ...)
vim.validate{["after the second argument"] = {tbl,'t'}}
if tbl then
for k, v in pairs(tbl) do
- if type(v) == 'table' and deep_extend and not vim.tbl_islist(v) then
- ret[k] = tbl_extend(behavior, true, ret[k] or vim.empty_dict(), v)
+ if deep_extend and can_merge(v) and can_merge(ret[k]) then
+ ret[k] = tbl_extend(behavior, true, ret[k], v)
elseif behavior ~= 'force' and ret[k] ~= nil then
if behavior == 'error' then
error('key found in more than one map: '..k)
@@ -236,43 +242,48 @@ end
--- Merges two or more map-like tables.
---
---@see |extend()|
+---@see |extend()|
---
---@param behavior Decides what to do if a key is found in more than one map:
+---@param behavior Decides what to do if a key is found in more than one map:
--- - "error": raise an error
--- - "keep": use value from the leftmost map
--- - "force": use value from the rightmost map
---@param ... Two or more map-like tables.
+---@param ... Two or more map-like tables.
function vim.tbl_extend(behavior, ...)
return tbl_extend(behavior, false, ...)
end
--- Merges recursively two or more map-like tables.
---
---@see |tbl_extend()|
+---@see |tbl_extend()|
---
---@param behavior Decides what to do if a key is found in more than one map:
+---@param behavior Decides what to do if a key is found in more than one map:
--- - "error": raise an error
--- - "keep": use value from the leftmost map
--- - "force": use value from the rightmost map
---@param ... Two or more map-like tables.
+---@param ... Two or more map-like tables.
function vim.tbl_deep_extend(behavior, ...)
return tbl_extend(behavior, true, ...)
end
--- Deep compare values for equality
+---
+--- Tables are compared recursively unless they both provide the `eq` methamethod.
+--- All other types are compared using the equality `==` operator.
+---@param a first value
+---@param b second value
+---@returns `true` if values are equals, else `false`.
function vim.deep_equal(a, b)
if a == b then return true end
if type(a) ~= type(b) then return false end
if type(a) == 'table' then
- -- TODO improve this algorithm's performance.
for k, v in pairs(a) do
if not vim.deep_equal(v, b[k]) then
return false
end
end
- for k, v in pairs(b) do
- if not vim.deep_equal(v, a[k]) then
+ for k, _ in pairs(b) do
+ if a[k] == nil then
return false
end
end
@@ -286,7 +297,7 @@ end
--- `tbl_add_reverse_lookup { A = 1 } == { [1] = 'A', A = 1 }`
--
--Do note that it *modifies* the input.
---@param o table The table to add the reverse to.
+---@param o table The table to add the reverse to.
function vim.tbl_add_reverse_lookup(o)
local keys = vim.tbl_keys(o)
for _, k in ipairs(keys) do
@@ -303,13 +314,13 @@ end
---
--- NOTE: This mutates dst!
---
---@see |vim.tbl_extend()|
+---@see |vim.tbl_extend()|
---
---@param dst list which will be modified and appended to.
---@param src list from which values will be inserted.
---@param start Start index on src. defaults to 1
---@param finish Final index on src. defaults to #src
---@returns dst
+---@param dst list which will be modified and appended to.
+---@param src list from which values will be inserted.
+---@param start Start index on src. defaults to 1
+---@param finish Final index on src. defaults to #src
+---@returns dst
function vim.list_extend(dst, src, start, finish)
vim.validate {
dst = {dst, 't'};
@@ -326,10 +337,10 @@ end
--- Creates a copy of a list-like table such that any nested tables are
--- "unrolled" and appended to the result.
---
---@see From https://github.com/premake/premake-core/blob/master/src/base/table.lua
+---@see From https://github.com/premake/premake-core/blob/master/src/base/table.lua
---
---@param t List-like table
---@returns Flattened copy of the given list-like table.
+---@param t List-like table
+---@returns Flattened copy of the given list-like table.
function vim.tbl_flatten(t)
local result = {}
local function _tbl_flatten(_t)
@@ -353,8 +364,8 @@ end
--- |vim.empty_dict()| or returned as a dict-like |API| or Vimscript result,
--- for example from |rpcrequest()| or |vim.fn|.
---
---@param t Table
---@returns `true` if array-like table, else `false`.
+---@param t Table
+---@returns `true` if array-like table, else `false`.
function vim.tbl_islist(t)
if type(t) ~= 'table' then
return false
@@ -389,9 +400,9 @@ end
--- vim.tbl_count({ 1, 2 }) => 2
--- </pre>
---
---@see https://github.com/Tieske/Penlight/blob/master/lua/pl/tablex.lua
---@param t Table
---@returns Number that is the number of the value in table
+---@see https://github.com/Tieske/Penlight/blob/master/lua/pl/tablex.lua
+---@param t Table
+---@returns Number that is the number of the value in table
function vim.tbl_count(t)
vim.validate{t={t,'t'}}
@@ -402,10 +413,10 @@ end
--- Creates a copy of a table containing only elements from start to end (inclusive)
---
---@param list table table
---@param start integer Start range of slice
---@param finish integer End range of slice
---@returns Copy of table sliced from start to finish (inclusive)
+---@param list table table
+---@param start integer Start range of slice
+---@param finish integer End range of slice
+---@returns Copy of table sliced from start to finish (inclusive)
function vim.list_slice(list, start, finish)
local new_list = {}
for i = start or 1, finish or #list do
@@ -416,9 +427,9 @@ end
--- Trim whitespace (Lua pattern "%s") from both sides of a string.
---
---@see https://www.lua.org/pil/20.2.html
---@param s String to trim
---@returns String with whitespace removed from its beginning and end
+---@see https://www.lua.org/pil/20.2.html
+---@param s String to trim
+---@returns String with whitespace removed from its beginning and end
function vim.trim(s)
vim.validate{s={s,'s'}}
return s:match('^%s*(.*%S)') or ''
@@ -426,9 +437,9 @@ end
--- Escapes magic chars in a Lua pattern.
---
---@see https://github.com/rxi/lume
---@param s String to escape
---@returns %-escaped pattern string
+---@see https://github.com/rxi/lume
+---@param s String to escape
+---@returns %-escaped pattern string
function vim.pesc(s)
vim.validate{s={s,'s'}}
return s:gsub('[%(%)%.%%%+%-%*%?%[%]%^%$]', '%%%1')
@@ -436,9 +447,9 @@ end
--- Tests if `s` starts with `prefix`.
---
---@param s (string) a string
---@param prefix (string) a prefix
---@return (boolean) true if `prefix` is a prefix of s
+---@param s (string) a string
+---@param prefix (string) a prefix
+---@return (boolean) true if `prefix` is a prefix of s
function vim.startswith(s, prefix)
vim.validate { s = {s, 's'}; prefix = {prefix, 's'}; }
return s:sub(1, #prefix) == prefix
@@ -446,9 +457,9 @@ end
--- Tests if `s` ends with `suffix`.
---
---@param s (string) a string
---@param suffix (string) a suffix
---@return (boolean) true if `suffix` is a suffix of s
+---@param s (string) a string
+---@param suffix (string) a suffix
+---@return (boolean) true if `suffix` is a suffix of s
function vim.endswith(s, suffix)
vim.validate { s = {s, 's'}; suffix = {suffix, 's'}; }
return #suffix == 0 or s:sub(-#suffix) == suffix
@@ -480,7 +491,7 @@ end
--- => error('arg1: expected even number, got 3')
--- </pre>
---
---@param opt Map of parameter names to validations. Each key is a parameter
+---@param opt Map of parameter names to validations. Each key is a parameter
--- name; each value is a tuple in one of these forms:
--- 1. (arg_value, type_name, optional)
--- - arg_value: argument value
@@ -564,8 +575,8 @@ do
end
--- Returns true if object `f` can be called as a function.
---
---@param f Any object
---@return true if `f` is callable, else false
+---@param f Any object
+---@return true if `f` is callable, else false
function vim.is_callable(f)
if type(f) == 'function' then return true end
local m = getmetatable(f)
diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua
index de997b2d86..66999c5f7f 100644
--- a/runtime/lua/vim/treesitter.lua
+++ b/runtime/lua/vim/treesitter.lua
@@ -20,6 +20,9 @@ setmetatable(M, {
elseif k == "language" then
t[k] = require"vim.treesitter.language"
return t[k]
+ elseif k == "query" then
+ t[k] = require"vim.treesitter.query"
+ return t[k]
end
end
})
@@ -28,9 +31,9 @@ setmetatable(M, {
---
--- It is not recommended to use this, use vim.treesitter.get_parser() instead.
---
---- @param bufnr The buffer the parser will be tied to
---- @param lang The language of the parser
---- @param opts Options to pass to the created language tree
+---@param bufnr The buffer the parser will be tied to
+---@param lang The language of the parser
+---@param opts Options to pass to the created language tree
function M._create_parser(bufnr, lang, opts)
language.require_language(lang)
if bufnr == 0 then
@@ -71,11 +74,11 @@ end
--- If needed this will create the parser.
--- Unconditionnally attach the provided callback
---
---- @param bufnr The buffer the parser should be tied to
---- @param lang The filetype of this parser
---- @param opts Options object to pass to the created language tree
+---@param bufnr The buffer the parser should be tied to
+---@param lang The filetype of this parser
+---@param opts Options object to pass to the created language tree
---
---- @returns The parser
+---@returns The parser
function M.get_parser(bufnr, lang, opts)
opts = opts or {}
@@ -97,9 +100,9 @@ end
--- Gets a string parser
---
---- @param str The string to parse
---- @param lang The language of this string
---- @param opts Options to pass to the created language tree
+---@param str The string to parse
+---@param lang The language of this string
+---@param opts Options to pass to the created language tree
function M.get_string_parser(str, lang, opts)
vim.validate {
str = { str, 'string' },
diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua
index 84b6a5f135..22b528838c 100644
--- a/runtime/lua/vim/treesitter/highlighter.lua
+++ b/runtime/lua/vim/treesitter/highlighter.lua
@@ -22,8 +22,6 @@ local _link_default_highlight_once = function(from, to)
return from
end
--- These are conventions defined by nvim-treesitter, though it
--- needs to be user extensible also.
TSHighlighter.hl_map = {
["error"] = "Error",
@@ -87,8 +85,10 @@ function TSHighlighterQuery.new(lang, query_string)
hl = _link_default_highlight_once(lang .. hl, hl)
end
- rawset(table, capture, hl)
- return hl
+ local id = a.nvim_get_hl_id_by_name(hl)
+
+ rawset(table, capture, id)
+ return id
end
})
@@ -116,14 +116,14 @@ function TSHighlighterQuery:_get_hl_from_capture(capture)
-- From "Normal.left" only keep "Normal"
return vim.split(name, '.', true)[1], true
else
- return TSHighlighter.hl_map[name] or name, false
+ return TSHighlighter.hl_map[name] or 0, false
end
end
--- Creates a new highlighter using @param tree
---
---- @param tree The language tree to use for highlighting
---- @param opts Table used to configure the highlighter
+---@param tree The language tree to use for highlighting
+---@param opts Table used to configure the highlighter
--- - queries: Table to overwrite queries used by the highlighter
function TSHighlighter.new(tree, opts)
local self = setmetatable({}, TSHighlighter)
@@ -217,7 +217,7 @@ end
--- Gets the query used for @param lang
---
---- @param lang A language used by the highlighter.
+---@param lang A language used by the highlighter.
function TSHighlighter:get_query(lang)
if not self._queries[lang] then
self._queries[lang] = TSHighlighterQuery.new(lang)
@@ -248,7 +248,7 @@ local function on_line_impl(self, buf, line)
end
while line >= state.next_row do
- local capture, node = state.iter()
+ local capture, node, metadata = state.iter()
if capture == nil then break end
@@ -260,7 +260,7 @@ local function on_line_impl(self, buf, line)
{ end_line = end_row, end_col = end_col,
hl_group = hl,
ephemeral = true,
- priority = 100 -- Low but leaves room below
+ priority = tonumber(metadata.priority) or 100 -- Low but leaves room below
})
end
if start_row > line then
diff --git a/runtime/lua/vim/treesitter/language.lua b/runtime/lua/vim/treesitter/language.lua
index 6dc37c7848..89ddd6cd5a 100644
--- a/runtime/lua/vim/treesitter/language.lua
+++ b/runtime/lua/vim/treesitter/language.lua
@@ -6,9 +6,9 @@ local M = {}
---
--- Parsers are searched in the `parser` runtime directory.
---
---- @param lang The language the parser should parse
---- @param path Optional path the parser is located at
---- @param silent Don't throw an error if language not found
+---@param lang The language the parser should parse
+---@param path Optional path the parser is located at
+---@param silent Don't throw an error if language not found
function M.require_language(lang, path, silent)
if vim._ts_has_language(lang) then
return true
@@ -40,7 +40,7 @@ end
---
--- Inspecting provides some useful informations on the language like node names, ...
---
---- @param lang The language.
+---@param lang The language.
function M.inspect_language(lang)
M.require_language(lang)
return vim._ts_inspect_language(lang)
diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua
index 899d90e464..7e392f72a4 100644
--- a/runtime/lua/vim/treesitter/languagetree.lua
+++ b/runtime/lua/vim/treesitter/languagetree.lua
@@ -9,12 +9,12 @@ LanguageTree.__index = LanguageTree
--- The language can contain child languages with in its range,
--- hence the tree.
---
---- @param source Can be a bufnr or a string of text to parse
---- @param lang The language this tree represents
---- @param opts Options table
---- @param opts.injections A table of language to injection query strings.
---- This is useful for overriding the built-in runtime file
---- searching for the injection language query per language.
+---@param source Can be a bufnr or a string of text to parse
+---@param lang The language this tree represents
+---@param opts Options table
+---@param opts.injections A table of language to injection query strings.
+--- This is useful for overriding the built-in runtime file
+--- searching for the injection language query per language.
function LanguageTree.new(source, lang, opts)
language.require_language(lang)
opts = opts or {}
@@ -171,8 +171,8 @@ end
--- Invokes the callback for each LanguageTree and it's children recursively
---
---- @param fn The function to invoke. This is invoked with arguments (tree: LanguageTree, lang: string)
---- @param include_self Whether to include the invoking tree in the results.
+---@param fn The function to invoke. This is invoked with arguments (tree: LanguageTree, lang: string)
+---@param include_self Whether to include the invoking tree in the results.
function LanguageTree:for_each_child(fn, include_self)
if include_self then
fn(self, self._lang)
@@ -187,8 +187,8 @@ end
---
--- Note, this includes the invoking language tree's trees as well.
---
---- @param fn The callback to invoke. The callback is invoked with arguments
---- (tree: TSTree, languageTree: LanguageTree)
+---@param fn The callback to invoke. The callback is invoked with arguments
+--- (tree: TSTree, languageTree: LanguageTree)
function LanguageTree:for_each_tree(fn)
for _, tree in ipairs(self._trees) do
fn(tree, self)
@@ -203,7 +203,7 @@ end
---
--- If the language already exists as a child, it will first be removed.
---
---- @param lang The language to add.
+---@param lang The language to add.
function LanguageTree:add_child(lang)
if self._children[lang] then
self:remove_child(lang)
@@ -219,7 +219,7 @@ end
--- Removes a child language from this tree.
---
---- @param lang The language to remove.
+---@param lang The language to remove.
function LanguageTree:remove_child(lang)
local child = self._children[lang]
@@ -259,7 +259,7 @@ end
---
--- Note, this call invalidates the tree and requires it to be parsed again.
---
---- @param regions A list of regions this tree should manage and parse.
+---@param regions A list of regions this tree should manage and parse.
function LanguageTree:set_included_regions(regions)
-- TODO(vigoux): I don't think string parsers are useful for now
if type(self._source) == "number" then
@@ -299,7 +299,7 @@ end
---
--- TODO: Allow for an offset predicate to tailor the injection range
--- instead of using the entire nodes range.
---- @private
+---@private
function LanguageTree:_get_injections()
if not self._injection_query then return {} end
@@ -449,7 +449,7 @@ function LanguageTree:_on_detach(...)
end
--- Registers callbacks for the parser
---- @param cbs An `nvim_buf_attach`-like table argument with the following keys :
+---@param cbs An `nvim_buf_attach`-like table argument with the following keys :
--- `on_bytes` : see `nvim_buf_attach`, but this will be called _after_ the parsers callback.
--- `on_changedtree` : a callback that will be called every time the tree has syntactical changes.
--- it will only be passed one argument, that is a table of the ranges (as node ranges) that
@@ -497,7 +497,7 @@ end
---
--- This goes down the tree to recursively check childs.
---
---- @param range A range, that is a `{ start_line, start_col, end_line, end_col }` table.
+---@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
if tree_contains(tree, range) then
@@ -510,7 +510,7 @@ end
--- Gets the appropriate language that contains @param range
---
---- @param range A text range, see |LanguageTree:contains|
+---@param range A text range, see |LanguageTree:contains|
function LanguageTree:language_for_range(range)
for _, child in pairs(self._children) do
if child:contains(range) then
diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua
index b81eb18945..66da179ea3 100644
--- a/runtime/lua/vim/treesitter/query.lua
+++ b/runtime/lua/vim/treesitter/query.lua
@@ -36,9 +36,9 @@ end
--- Gets the list of files used to make up a query
---
---- @param lang The language
---- @param query_name The name of the query to load
---- @param is_included Internal parameter, most of the time left as `nil`
+---@param lang The language
+---@param query_name The name of the query to load
+---@param is_included Internal parameter, most of the time left as `nil`
function M.get_query_files(lang, query_name, is_included)
local query_path = string.format('queries/%s/%s.scm', lang, query_name)
local lang_files = dedupe_files(a.nvim_get_runtime_file(query_path, true))
@@ -112,19 +112,19 @@ local explicit_queries = setmetatable({}, {
--- This allows users to override any runtime files and/or configuration
--- set by plugins.
---
---- @param lang string: The language to use for the query
---- @param query_name string: The name of the query (i.e. "highlights")
---- @param text string: The query text (unparsed).
+---@param lang string: The language to use for the query
+---@param query_name string: The name of the query (i.e. "highlights")
+---@param text string: The query text (unparsed).
function M.set_query(lang, query_name, text)
explicit_queries[lang][query_name] = M.parse_query(lang, text)
end
--- Returns the runtime query {query_name} for {lang}.
---
---- @param lang The language to use for the query
---- @param query_name The name of the query (i.e. "highlights")
+---@param lang The language to use for the query
+---@param query_name The name of the query (i.e. "highlights")
---
---- @return The corresponding query, parsed.
+---@return The corresponding query, parsed.
function M.get_query(lang, query_name)
if explicit_queries[lang][query_name] then
return explicit_queries[lang][query_name]
@@ -151,10 +151,10 @@ end
--- -` info.captures` also points to `captures`.
--- - `info.patterns` contains information about predicates.
---
---- @param lang The language
---- @param query A string containing the query (s-expr syntax)
+---@param lang The language
+---@param query A string containing the query (s-expr syntax)
---
---- @returns The query
+---@returns The query
function M.parse_query(lang, query)
language.require_language(lang)
local self = setmetatable({}, Query)
@@ -168,8 +168,8 @@ end
--- Gets the text corresponding to a given node
---
---- @param node the node
---- @param bsource The buffer or string from which the node is extracted
+---@param node the node
+---@param bsource The buffer or string from which the node is extracted
function M.get_node_text(node, source)
local start_row, start_col, start_byte = node:start()
local end_row, end_col, end_byte = node:end_()
@@ -327,9 +327,9 @@ local directive_handlers = {
--- Adds a new predicate to be used in queries
---
---- @param name the name of the predicate, without leading #
---- @param handler the handler function to be used
---- signature will be (match, pattern, bufnr, predicate)
+---@param name the name of the predicate, without leading #
+---@param handler the handler function to be used
+--- signature will be (match, pattern, bufnr, predicate)
function M.add_predicate(name, handler, force)
if predicate_handlers[name] and not force then
error(string.format("Overriding %s", name))
@@ -340,9 +340,9 @@ end
--- Adds a new directive to be used in queries
---
---- @param name the name of the directive, without leading #
---- @param handler the handler function to be used
---- signature will be (match, pattern, bufnr, predicate)
+---@param name the name of the directive, without leading #
+---@param handler the handler function to be used
+--- signature will be (match, pattern, bufnr, predicate)
function M.add_directive(name, handler, force)
if directive_handlers[name] and not force then
error(string.format("Overriding %s", name))
@@ -351,7 +351,12 @@ function M.add_directive(name, handler, force)
directive_handlers[name] = handler
end
---- Returns the list of currently supported predicates
+---@return The list of supported directives.
+function M.list_directives()
+ return vim.tbl_keys(directive_handlers)
+end
+
+---@return The list of supported predicates.
function M.list_predicates()
return vim.tbl_keys(predicate_handlers)
end
@@ -460,13 +465,13 @@ end
--- end
--- </pre>
---
---- @param node The node under which the search will occur
---- @param source The source buffer or string to exctract text from
---- @param start The starting line of the search
---- @param stop The stopping line of the search (end-exclusive)
+---@param node The node under which the search will occur
+---@param source The source buffer or string to exctract text from
+---@param start The starting line of the search
+---@param stop The stopping line of the search (end-exclusive)
---
---- @returns The matching capture id
---- @returns The captured node
+---@returns The matching capture id
+---@returns The captured node
function Query:iter_captures(node, source, start, stop)
if type(source) == "number" and source == 0 then
source = vim.api.nvim_get_current_buf()
@@ -517,13 +522,13 @@ end
--- end
--- </pre>
---
---- @param node The node under which the search will occur
---- @param source The source buffer or string to search
---- @param start The starting line of the search
---- @param stop The stopping line of the search (end-exclusive)
+---@param node The node under which the search will occur
+---@param source The source buffer or string to search
+---@param start The starting line of the search
+---@param stop The stopping line of the search (end-exclusive)
---
---- @returns The matching pattern id
---- @returns The matching match
+---@returns The matching pattern id
+---@returns The matching match
function Query:iter_matches(node, source, start, stop)
if type(source) == "number" and source == 0 then
source = vim.api.nvim_get_current_buf()
diff --git a/runtime/lua/vim/ui.lua b/runtime/lua/vim/ui.lua
new file mode 100644
index 0000000000..5eab20fc54
--- /dev/null
+++ b/runtime/lua/vim/ui.lua
@@ -0,0 +1,36 @@
+local M = {}
+
+--- Prompts the user to pick a single item from a collection of entries
+---
+---@param items table Arbitrary items
+---@param opts table Additional options
+--- - prompt (string|nil)
+--- Text of the prompt. Defaults to `Select one of:`
+--- - format_item (function item -> text)
+--- Function to format an
+--- individual item from `items`. Defaults to `tostring`.
+---@param on_choice function ((item|nil, idx|nil) -> ())
+--- Called once the user made a choice.
+--- `idx` is the 1-based index of `item` within `item`.
+--- `nil` if the user aborted the dialog.
+function M.select(items, opts, on_choice)
+ vim.validate {
+ items = { items, 'table', false },
+ on_choice = { on_choice, 'function', false },
+ }
+ opts = opts or {}
+ local choices = {opts.prompt or 'Select one of:'}
+ local format_item = opts.format_item or tostring
+ for i, item in pairs(items) do
+ table.insert(choices, string.format('%d: %s', i, format_item(item)))
+ end
+ local choice = vim.fn.inputlist(choices)
+ if choice < 1 or choice > #items then
+ on_choice(nil, nil)
+ else
+ on_choice(items[choice], choice)
+ end
+end
+
+
+return M
diff --git a/runtime/lua/vim/uri.lua b/runtime/lua/vim/uri.lua
index f1a12c72ec..a3e79a0f2b 100644
--- a/runtime/lua/vim/uri.lua
+++ b/runtime/lua/vim/uri.lua
@@ -9,7 +9,7 @@ do
local schar = string.char
--- Convert hex to char
- --@private
+ ---@private
local function hex_to_char(hex)
return schar(tonumber(hex, 16))
end
@@ -38,7 +38,7 @@ do
tohex = function(b) return string.format("%02x", b) end
end
- --@private
+ ---@private
local function percent_encode_char(char)
return "%"..tohex(sbyte(char), 2)
end
@@ -50,14 +50,14 @@ do
end
---@private
+---@private
local function is_windows_file_uri(uri)
- return uri:match('^file:///[a-zA-Z]:') ~= nil
+ return uri:match('^file:/+[a-zA-Z]:') ~= nil
end
--- Get a URI from a file path.
---@param path (string): Path to file
---@return URI
+---@param path (string): Path to file
+---@return URI
local function uri_from_fname(path)
local volume_path, fname = path:match("^([a-zA-Z]:)(.*)")
local is_windows = volume_path ~= nil
@@ -74,11 +74,11 @@ local function uri_from_fname(path)
return table.concat(uri_parts)
end
-local URI_SCHEME_PATTERN = '^([a-zA-Z]+[a-zA-Z0-9+-.]*)://.*'
+local URI_SCHEME_PATTERN = '^([a-zA-Z]+[a-zA-Z0-9+-.]*):.*'
--- Get a URI from a bufnr
---@param bufnr (number): Buffer number
---@return URI
+---@param bufnr (number): Buffer number
+---@return URI
local function uri_from_bufnr(bufnr)
local fname = vim.api.nvim_buf_get_name(bufnr)
local scheme = fname:match(URI_SCHEME_PATTERN)
@@ -90,8 +90,8 @@ local function uri_from_bufnr(bufnr)
end
--- Get a filename from a URI
---@param uri (string): The URI
---@return Filename
+---@param uri (string): The URI
+---@return Filename
local function uri_to_fname(uri)
local scheme = assert(uri:match(URI_SCHEME_PATTERN), 'URI must contain a scheme: ' .. uri)
if scheme ~= 'file' then
@@ -100,18 +100,18 @@ local function uri_to_fname(uri)
uri = uri_decode(uri)
-- TODO improve this.
if is_windows_file_uri(uri) then
- uri = uri:gsub('^file:///', '')
+ uri = uri:gsub('^file:/+', '')
uri = uri:gsub('/', '\\')
else
- uri = uri:gsub('^file://', '')
+ uri = uri:gsub('^file:/+', '/')
end
return uri
end
--- Return or create a buffer for a uri.
---@param uri (string): The URI
---@return bufnr.
---@note Creates buffer but does not load it
+---@param uri (string): The URI
+---@return bufnr.
+---@note Creates buffer but does not load it
local function uri_to_bufnr(uri)
local scheme = assert(uri:match(URI_SCHEME_PATTERN), 'URI must contain a scheme: ' .. uri)
if scheme == 'file' then
diff --git a/runtime/nvim.appdata.xml b/runtime/nvim.appdata.xml
index e99c76a930..099c9a57c0 100644
--- a/runtime/nvim.appdata.xml
+++ b/runtime/nvim.appdata.xml
@@ -26,6 +26,7 @@
</screenshots>
<releases>
+ <release date="2021-07-02" version="0.5.0"/>
<release date="2020-08-04" version="0.4.4"/>
<release date="2019-11-06" version="0.4.3"/>
<release date="2019-09-15" version="0.4.2"/>
diff --git a/runtime/optwin.vim b/runtime/optwin.vim
index 633cb9e509..d4c10f7afa 100644
--- a/runtime/optwin.vim
+++ b/runtime/optwin.vim
@@ -440,6 +440,9 @@ if has("syntax")
call append("$", "cursorline\thighlight the screen line of the cursor")
call append("$", "\t(local to window)")
call <SID>BinOptionL("cul")
+ call append("$", "cursorlineopt\tspecifies which area 'cursorline' highlights")
+ call append("$", "\t(local to window)")
+ call <SID>OptionL("culopt")
call append("$", "colorcolumn\tcolumns to highlight")
call append("$", "\t(local to window)")
call <SID>OptionL("cc")
diff --git a/runtime/pack/dist/opt/matchit/doc/matchit.txt b/runtime/pack/dist/opt/matchit/doc/matchit.txt
index 3cd2c8e2a7..58a47780ef 100644
--- a/runtime/pack/dist/opt/matchit/doc/matchit.txt
+++ b/runtime/pack/dist/opt/matchit/doc/matchit.txt
@@ -4,7 +4,7 @@ For instructions on installing this file, type
`:help matchit-install`
inside Vim.
-For Vim version 8.1. Last change: 2020 Mar 01
+For Vim version 8.1. Last change: 2021 May 17
VIM REFERENCE MANUAL by Benji Fisher et al
@@ -322,7 +322,7 @@ should work (and have the same effect as "foobar:barfoo:endfoobar"), although
this has not been thoroughly tested.
You can use |zero-width| patterns such as |\@<=| and |\zs|. (The latter has
-not been thouroughly tested in matchit.vim.) For example, if the keyword "if"
+not been thoroughly tested in matchit.vim.) For example, if the keyword "if"
must occur at the start of the line, with optional white space, you might use
the pattern "\(^\s*\)\@<=if" so that the cursor will end on the "i" instead of
at the start of the line. For another example, if HTML had only one tag then
diff --git a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
index ae1274f81f..8057d7f284 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: 2021 May 16
+" Last Change: 2021 Aug 23
"
" WORK IN PROGRESS - Only the basics work
" Note: On MS-Windows you need a recent version of gdb. The one included with
@@ -127,6 +127,10 @@ func s:StartDebug_internal(dict)
let s:pid = 0
let s:asmwin = 0
+ if exists('#User#TermdebugStartPre')
+ doauto <nomodeline> User TermdebugStartPre
+ endif
+
" Uncomment this line to write logging in "debuglog".
" call ch_logfile('debuglog', 'w')
@@ -173,6 +177,10 @@ func s:StartDebug_internal(dict)
call win_gotoid(curwinid)
endif
endif
+
+ if exists('#User#TermdebugStartPost')
+ doauto <nomodeline> User TermdebugStartPost
+ endif
endfunc
" Use when debugger didn't start or ended.
@@ -181,6 +189,15 @@ func s:CloseBuffers()
unlet! s:gdbwin
endfunc
+func s:CheckGdbRunning()
+ if nvim_get_chan_info(s:gdb_job_id) == {}
+ echoerr string(g:termdebugger) . ' exited unexpectedly'
+ call s:CloseBuffers()
+ return ''
+ endif
+ return 'ok'
+endfunc
+
func s:StartDebug_term(dict)
" Open a terminal window without a job, to run the debugged program in.
execute s:vertical ? 'vnew' : 'new'
@@ -229,7 +246,7 @@ func s:StartDebug_term(dict)
let gdb_args = get(a:dict, 'gdb_args', [])
let proc_args = get(a:dict, 'proc_args', [])
- let cmd = [g:termdebugger, '-quiet', '-tty', pty] + gdb_args
+ let cmd = [g:termdebugger, '-quiet', '-tty', pty, '--eval-command', 'echo startupdone\n'] + gdb_args
"call ch_log('executing "' . join(cmd) . '"')
execute 'new'
let s:gdb_job_id = termopen(cmd, {'on_exit': function('s:EndTermDebug')})
@@ -246,9 +263,28 @@ func s:StartDebug_term(dict)
let s:gdbbuf = gdb_job_info['buffer']
let s:gdbwin = win_getid(winnr())
- " Set arguments to be run. First wait a bit to make detecting gdb a bit
- " more reliable.
- sleep 200m
+ " Wait for the "startupdone" message before sending any commands.
+ let try_count = 0
+ while 1
+ if s:CheckGdbRunning() != 'ok'
+ return
+ endif
+
+ for lnum in range(1, 200)
+ if get(getbufline(s:gdbbuf, lnum), 0, '') =~ 'startupdone'
+ let try_count = 9999
+ break
+ endif
+ endfor
+ let try_count += 1
+ if try_count > 300
+ " done or give up after five seconds
+ break
+ endif
+ sleep 10m
+ endwhile
+
+ " Set arguments to be run.
if len(proc_args)
call chansend(s:gdb_job_id, 'set args ' . join(proc_args) . "\r")
endif
@@ -260,9 +296,7 @@ func s:StartDebug_term(dict)
" why the debugger doesn't work.
let try_count = 0
while 1
- if nvim_get_chan_info(s:gdb_job_id) == {}
- echoerr string(g:termdebugger) . ' exited unexpectedly'
- call s:CloseBuffers()
+ if s:CheckGdbRunning() != 'ok'
return
endif
@@ -309,6 +343,9 @@ func s:StartDebug_term(dict)
" "Type <return> to continue" prompt.
call s:SendCommand('set pagination off')
+ " Set the filetype, this can be used to add mappings.
+ set filetype=termdebug
+
call s:StartDebugCommon(a:dict)
endfunc
@@ -597,6 +634,10 @@ func s:GetAsmAddr(msg)
endfunc
function s:EndTermDebug(job_id, exit_code, event)
+ if exists('#User#TermdebugStopPre')
+ doauto <nomodeline> User TermdebugStopPre
+ endif
+
unlet s:gdbwin
call s:EndDebugCommon()
@@ -631,10 +672,18 @@ func s:EndDebugCommon()
let &columns = s:save_columns
endif
+ if exists('#User#TermdebugStopPost')
+ doauto <nomodeline> User TermdebugStopPost
+ endif
+
au! TermDebug
endfunc
func s:EndPromptDebug(job_id, exit_code, event)
+ if exists('#User#TermdebugStopPre')
+ doauto <nomodeline> User TermdebugStopPre
+ endif
+
let curwinid = win_getid(winnr())
call win_gotoid(s:gdbwin)
close
@@ -777,7 +826,14 @@ func s:InstallCommands()
command Winbar call s:InstallWinbar()
if !exists('g:termdebug_map_K') || g:termdebug_map_K
- let s:k_map_saved = maparg('K', 'n', 0, 1)
+ " let s:k_map_saved = maparg('K', 'n', 0, 1)
+ let s:k_map_saved = {}
+ for map in nvim_get_keymap('n')
+ if map.lhs ==# 'K'
+ let s:k_map_saved = map
+ break
+ endif
+ endfor
nnoremap K :Evaluate<CR>
endif
@@ -821,7 +877,15 @@ func s:DeleteCommands()
if empty(s:k_map_saved)
nunmap K
else
- call mapset('n', 0, s:k_map_saved)
+ " call mapset('n', 0, s:k_map_saved)
+ let mode = s:k_map_saved.mode !=# ' ' ? s:k_map_saved.mode : ''
+ call nvim_set_keymap(mode, 'K', s:k_map_saved.rhs, {
+ \ 'expr': s:k_map_saved.expr ? v:true : v:false,
+ \ 'noremap': s:k_map_saved.noremap ? v:true : v:false,
+ \ 'nowait': s:k_map_saved.nowait ? v:true : v:false,
+ \ 'script': s:k_map_saved.script ? v:true : v:false,
+ \ 'silent': s:k_map_saved.silent ? v:true : v:false,
+ \ })
endif
unlet s:k_map_saved
endif
diff --git a/runtime/plugin/diagnostic.vim b/runtime/plugin/diagnostic.vim
new file mode 100644
index 0000000000..2183623ac8
--- /dev/null
+++ b/runtime/plugin/diagnostic.vim
@@ -0,0 +1,26 @@
+" :help vim.diagnostic
+
+hi default DiagnosticError ctermfg=1 guifg=Red
+hi default DiagnosticWarn ctermfg=3 guifg=Orange
+hi default DiagnosticInfo ctermfg=4 guifg=LightBlue
+hi default DiagnosticHint ctermfg=7 guifg=LightGrey
+
+hi default DiagnosticUnderlineError cterm=underline gui=underline guisp=Red
+hi default DiagnosticUnderlineWarn cterm=underline gui=underline guisp=Orange
+hi default DiagnosticUnderlineInfo cterm=underline gui=underline guisp=LightBlue
+hi default DiagnosticUnderlineHint cterm=underline gui=underline guisp=LightGrey
+
+hi default link DiagnosticVirtualTextError DiagnosticError
+hi default link DiagnosticVirtualTextWarn DiagnosticWarn
+hi default link DiagnosticVirtualTextInfo DiagnosticInfo
+hi default link DiagnosticVirtualTextHint DiagnosticHint
+
+hi default link DiagnosticFloatingError DiagnosticError
+hi default link DiagnosticFloatingWarn DiagnosticWarn
+hi default link DiagnosticFloatingInfo DiagnosticInfo
+hi default link DiagnosticFloatingHint DiagnosticHint
+
+hi default link DiagnosticSignError DiagnosticError
+hi default link DiagnosticSignWarn DiagnosticWarn
+hi default link DiagnosticSignInfo DiagnosticInfo
+hi default link DiagnosticSignHint DiagnosticHint
diff --git a/runtime/plugin/man.vim b/runtime/plugin/man.vim
index 689aa32ef3..b10677593f 100644
--- a/runtime/plugin/man.vim
+++ b/runtime/plugin/man.vim
@@ -5,8 +5,8 @@ if exists('g:loaded_man')
endif
let g:loaded_man = 1
-command! -bang -bar -range=-1 -complete=customlist,man#complete -nargs=* Man
- \ if <bang>0 | set ft=man |
+command! -bang -bar -addr=other -complete=customlist,man#complete -nargs=* Man
+ \ if <bang>0 | call man#init_pager() |
\ else | call man#open_page(<count>, <q-mods>, <f-args>) | endif
augroup man
diff --git a/runtime/plugin/netrwPlugin.vim b/runtime/plugin/netrwPlugin.vim
index 217a7795c9..d309f81484 100644
--- a/runtime/plugin/netrwPlugin.vim
+++ b/runtime/plugin/netrwPlugin.vim
@@ -1,9 +1,9 @@
" netrwPlugin.vim: Handles file transfer and remote directory listing across a network
" PLUGIN SECTION
-" Date: Feb 08, 2016 - Jan 07, 2020
+" Date: Feb 09, 2021
" Maintainer: Charles E Campbell <NcampObell@SdrPchip.AorgM-NOSPAM>
" GetLatestVimScripts: 1075 1 :AutoInstall: netrw.vim
-" Copyright: Copyright (C) 1999-2013 Charles E. Campbell {{{1
+" Copyright: Copyright (C) 1999-2021 Charles E. Campbell {{{1
" Permission is hereby granted to use and distribute this code,
" with or without modifications, provided that this copyright
" notice is copied with it. Like anything else that's free,
@@ -20,7 +20,7 @@
if &cp || exists("g:loaded_netrwPlugin")
finish
endif
-let g:loaded_netrwPlugin = "v170"
+let g:loaded_netrwPlugin = "v171"
let s:keepcpo = &cpo
set cpo&vim
"DechoRemOn
@@ -83,11 +83,11 @@ if !exists("g:netrw_nogx")
endif
nno <silent> <Plug>NetrwBrowseX :call netrw#BrowseX(netrw#GX(),netrw#CheckIfRemote(netrw#GX()))<cr>
endif
- if maparg('gx','v') == ""
+ if maparg('gx','x') == ""
if !hasmapto('<Plug>NetrwBrowseXVis')
- vmap <unique> gx <Plug>NetrwBrowseXVis
+ xmap <unique> gx <Plug>NetrwBrowseXVis
endif
- vno <silent> <Plug>NetrwBrowseXVis :<c-u>call netrw#BrowseXVis()<cr>
+ xno <silent> <Plug>NetrwBrowseXVis :<c-u>call netrw#BrowseXVis()<cr>
endif
endif
if exists("g:netrw_usetab") && g:netrw_usetab
@@ -129,7 +129,9 @@ fun! s:LocalBrowse(dirname)
elseif isdirectory(a:dirname)
" call Decho("(LocalBrowse) dirname<".a:dirname."> ft=".&ft." (isdirectory, not amiga)")
" call Dredir("LocalBrowse ft last set: ","verbose set ft")
- sil! call netrw#LocalBrowseCheck(a:dirname)
+ " Jul 13, 2021: for whatever reason, preceding the following call with
+ " a sil! causes an unbalanced if-endif vim error
+ call netrw#LocalBrowseCheck(a:dirname)
if exists("w:netrw_bannercnt") && line('.') < w:netrw_bannercnt
exe w:netrw_bannercnt
endif
@@ -151,10 +153,22 @@ endfun
" has already been called.
fun! s:VimEnter(dirname)
" call Dfunc("s:VimEnter(dirname<".a:dirname.">) expand(%)<".expand("%").">")
+ if has('nvim') || v:version < 802
+ " Johann Höchtl: reported that the call range... line causes an E488: Trailing characters
+ " error with neovim. I suspect its because neovim hasn't updated with recent
+ " vim patches. As is, this code will have problems with popup terminals
+ " instantiated before the VimEnter event runs.
+ " Ingo Karkat : E488 also in Vim 8.1.1602
let curwin = winnr()
let s:vimentered = 1
windo call s:LocalBrowse(expand("%:p"))
exe curwin."wincmd w"
+ else
+ " the following complicated expression comes courtesy of lacygoill; largely does the same thing as the windo and
+ " wincmd which are commented out, but avoids some side effects. Allows popup terminal before VimEnter.
+ let s:vimentered = 1
+ call range(1, winnr('$'))->map({_, v -> win_execute(win_getid(v), 'call expand("%:p")->s:LocalBrowse()')})
+ endif
" call Dret("s:VimEnter")
endfun
diff --git a/runtime/plugin/tohtml.vim b/runtime/plugin/tohtml.vim
index 2c85b57529..08df19b4f9 100644
--- a/runtime/plugin/tohtml.vim
+++ b/runtime/plugin/tohtml.vim
@@ -62,7 +62,7 @@ let g:loaded_2html_plugin = 'vim8.1_v2'
" 7.3_v14 (Vim 7.3.1246): Allow suppressing line number anchors using
" g:html_line_ids=0. Allow customizing
" important IDs (like line IDs and fold IDs) using
-" g:html_id_expr evalutated when the buffer conversion
+" g:html_id_expr evaluated when the buffer conversion
" is started.
" 7.3_v13 (Vim 7.3.1088): Keep foldmethod at manual in the generated file and
" insert modeline to set it to manual.
diff --git a/runtime/syntax/2html.vim b/runtime/syntax/2html.vim
index 4afdff2899..8adbd76950 100644
--- a/runtime/syntax/2html.vim
+++ b/runtime/syntax/2html.vim
@@ -499,7 +499,7 @@ if s:settings.prevent_copy =~# 'n'
endif
elseif s:settings.line_ids
" if lines are not being numbered the only reason this function gets called
- " is to put the line IDs on each line; "text" will be emtpy but lnr will
+ " is to put the line IDs on each line; "text" will be empty but lnr will
" always be non-zero, however we don't want to use the <input> because that
" won't work as nice for empty text
function! s:HtmlFormat_n(text, style_id, diff_style_id, lnr)
@@ -1034,7 +1034,7 @@ if !s:settings.no_progress
" ProgressBar Indicator
let s:progressbar={}
- " Progessbar specific functions
+ " Progressbar specific functions
func! s:SetProgbarColor()
if hlID("TOhtmlProgress") != 0
diff --git a/runtime/syntax/8th.vim b/runtime/syntax/8th.vim
index ddc1084c9f..d543489b72 100644
--- a/runtime/syntax/8th.vim
+++ b/runtime/syntax/8th.vim
@@ -293,7 +293,7 @@ syn region eighthComment start="\zs\\" end="$" contains=eighthTodo
" Define the default highlighting.
if !exists("did_eighth_syntax_inits")
let did_eighth_syntax_inits=1
- " The default methods for highlighting. Can be overriden later.
+ " The default methods for highlighting. Can be overridden later.
hi def link eighthTodo Todo
hi def link eighthOperators Operator
hi def link eighthMath Number
diff --git a/runtime/syntax/abel.vim b/runtime/syntax/abel.vim
index 67d7e4f786..dbed541ba8 100644
--- a/runtime/syntax/abel.vim
+++ b/runtime/syntax/abel.vim
@@ -59,7 +59,7 @@ syn region abelSpecifier start='istype' end=';' contains=abelTypeIdChar,abelType
syn match abelTypeIdChar "[,']" contained
syn match abelTypeIdEnd ";" contained
-" string contstants and special characters within them
+" string constants and special characters within them
syn match abelSpecial contained "\\['\\]"
syn region abelString start=+'+ skip=+\\"+ end=+'+ contains=abelSpecial
diff --git a/runtime/syntax/ada.vim b/runtime/syntax/ada.vim
index c9d2b06e18..415c9522fb 100644
--- a/runtime/syntax/ada.vim
+++ b/runtime/syntax/ada.vim
@@ -159,7 +159,7 @@ endif
" Section: end {{{1
" Unless special ("end loop", "end if", etc.), "end" marks the end of a
-" begin, package, task etc. Assiging it to adaEnd.
+" begin, package, task etc. Assigning it to adaEnd.
syntax match adaEnd /\<end\>/
syntax keyword adaPreproc pragma
diff --git a/runtime/syntax/ahdl.vim b/runtime/syntax/ahdl.vim
index 664bd3837d..3a40dcfaea 100644
--- a/runtime/syntax/ahdl.vim
+++ b/runtime/syntax/ahdl.vim
@@ -38,7 +38,7 @@ syn keyword ahdlMegafunction lpm_rom lpm_dff lpm_tff clklock pll ntsc
syn keyword ahdlTodo contained TODO
-" String contstants
+" String constants
syn region ahdlString start=+"+ skip=+\\"+ end=+"+
" valid integer number formats (decimal, binary, octal, hex)
diff --git a/runtime/syntax/aptconf.vim b/runtime/syntax/aptconf.vim
index 8cb14321e2..d51e7bdfa9 100644
--- a/runtime/syntax/aptconf.vim
+++ b/runtime/syntax/aptconf.vim
@@ -1,7 +1,7 @@
" Vim syntax file
" Language: APT config file
" Maintainer: Yann Amar <quidame@poivron.org>
-" Last Change: 2015 Dec 22
+" Last Change: 2021 Jul 12
" quit when a syntax file was already loaded
if !exists("main_syntax")
@@ -396,10 +396,13 @@ syn cluster aptconfSynaptic_ contains=aptconfSynaptic,
" }}}
" Unattended Upgrade: {{{
syn keyword aptconfUnattendedUpgrade contained
- \ AutoFixInterruptedDpkg Automatic-Reboot Automatic-Reboot-Time
- \ Automatic-Reboot-WithUsers InstallOnShutdown Mail MailOnlyOnError
- \ MinimalSteps Origins-Pattern Package-Blacklist
- \ Remove-Unused-Dependencies
+ \ Allow-APT-Mark-Fallback Allow-downgrade AutoFixInterruptedDpkg
+ \ Automatic-Reboot Automatic-Reboot-Time Automatic-Reboot-WithUsers
+ \ Debug InstallOnShutdown Mail MailOnlyOnError MailReport MinimalSteps
+ \ OnlyOnACPower Origins-Pattern Package-Blacklist
+ \ Remove-New-Unused-Dependencies Remove-Unused-Dependencies
+ \ Remove-Unused-Kernel-Packages Skip-Updates-On-Metered-Connections
+ \ SyslogEnable SyslogFacility Verbose
syn cluster aptconfUnattendedUpgrade_ contains=aptconfUnattendedUpgrade
" }}}
diff --git a/runtime/syntax/aspvbs.vim b/runtime/syntax/aspvbs.vim
index f0861d8b5a..08db416ef9 100644
--- a/runtime/syntax/aspvbs.vim
+++ b/runtime/syntax/aspvbs.vim
@@ -108,7 +108,7 @@ syn match AspVBSMethods contained "Response\.\w*"
" Colorize boolean constants:
syn keyword AspVBSMethods contained true false
-" AspVBScript Number Contstants
+" AspVBScript Number Constants
" Integer number, or floating point number without a dot.
syn match AspVBSNumber contained "\<\d\+\>"
" Floating point number, with dot
@@ -116,7 +116,7 @@ syn match AspVBSNumber contained "\<\d\+\.\d*\>"
" Floating point number, starting with a dot
syn match AspVBSNumber contained "\.\d\+\>"
-" String and Character Contstants
+" String and Character Constants
" removed (skip=+\\\\\|\\"+) because VB doesn't have backslash escaping in
" strings (or does it?)
syn region AspVBSString contained start=+"+ end=+"+ keepend
@@ -143,7 +143,7 @@ syn cluster AspVBScriptTop contains=AspVBSStatement,AspVBSFunction,AspVBSMethods
syn region AspVBSFold start="^\s*\(class\)\s\+.*$" end="^\s*end\s\+\(class\)\>.*$" fold contained transparent keepend
syn region AspVBSFold start="^\s*\(private\|public\)\=\(\s\+default\)\=\s\+\(sub\|function\)\s\+.*$" end="^\s*end\s\+\(function\|sub\)\>.*$" fold contained transparent keepend
-" Define AspVBScript delimeters
+" Define AspVBScript delimiters
" <%= func("string_with_%>_in_it") %> This is illegal in ASP syntax.
syn region AspVBScriptInsideHtmlTags keepend matchgroup=Delimiter start=+<%=\=+ end=+%>+ contains=@AspVBScriptTop, AspVBSFold
syn region AspVBScriptInsideHtmlTags keepend matchgroup=Delimiter start=+<script\s\+language="\=vbscript"\=[^>]*\s\+runatserver[^>]*>+ end=+</script>+ contains=@AspVBScriptTop
diff --git a/runtime/syntax/c.vim b/runtime/syntax/c.vim
index d07aaf2658..20f8632006 100644
--- a/runtime/syntax/c.vim
+++ b/runtime/syntax/c.vim
@@ -1,7 +1,7 @@
" Vim syntax file
" Language: C
" Maintainer: Bram Moolenaar <Bram@vim.org>
-" Last Change: 2021 Jan 11
+" Last Change: 2021 May 24
" Quit when a (custom) syntax file was already loaded
if exists("b:current_syntax")
@@ -414,6 +414,9 @@ if exists("c_autodoc")
syn cluster cPreProcGroup add=cAutodocReal
endif
+" be able to fold #pragma regions
+syn region cPragma start="^\s*#pragma\s\+region\>" end="^\s*#pragma\s\+endregion\>" transparent keepend extend fold
+
" Highlight User Labels
syn cluster cMultiGroup contains=cIncluded,cSpecial,cCommentSkip,cCommentString,cComment2String,@cCommentGroup,cCommentStartError,cUserCont,cUserLabel,cBitField,cOctalZero,cCppOutWrapper,cCppInWrapper,@cCppOutInGroup,cFormat,cNumber,cFloat,cOctal,cOctalError,cNumbersCom,cCppParen,cCppBracket,cCppString
if s:ft ==# 'c' || exists("cpp_no_cpp11")
diff --git a/runtime/syntax/cfg.vim b/runtime/syntax/cfg.vim
index a50297d418..f347b1379f 100644
--- a/runtime/syntax/cfg.vim
+++ b/runtime/syntax/cfg.vim
@@ -32,7 +32,7 @@ syn match CfgComment "#.*"
syn match CfgComment ";.*"
syn match CfgComment "\/\/.*"
-" Define the default hightlighting.
+" Define the default highlighting.
" Only when an item doesn't have highlighting yet
hi def link CfgOnOff Label
hi def link CfgComment Comment
diff --git a/runtime/syntax/chicken.vim b/runtime/syntax/chicken.vim
index c3f949f823..806d08fbb7 100644
--- a/runtime/syntax/chicken.vim
+++ b/runtime/syntax/chicken.vim
@@ -1,8 +1,9 @@
" Vim syntax file
" Language: Scheme (CHICKEN)
-" Last Change: 2018-02-05
+" Last Change: 2021 Jul 30
" Author: Evan Hanson <evhan@foldling.org>
" Maintainer: Evan Hanson <evhan@foldling.org>
+" Repository: https://git.foldling.org/vim-scheme.git
" URL: https://foldling.org/vim/syntax/chicken.vim
" Notes: This is supplemental syntax, to be loaded after the core Scheme
" syntax file (syntax/scheme.vim). Enable it by setting b:is_chicken=1
@@ -36,9 +37,23 @@ if len(s:c)
syn region c matchgroup=schemeComment start=/#>/ end=/<#/ contains=@c
endif
+# SRFI 26
+syn match schemeSyntax /\(([ \t\n]*\)\@<=\(cut\|cute\)\>/
+
+syn keyword schemeSyntax and-let*
syn keyword schemeSyntax define-record
+syn keyword schemeSyntax set!-values
+syn keyword schemeSyntax fluid-let
+syn keyword schemeSyntax let-optionals
+syn keyword schemeSyntax let-optionals*
+syn keyword schemeSyntax letrec-values
+syn keyword schemeSyntax nth-value
+syn keyword schemeSyntax receive
syn keyword schemeLibrarySyntax declare
+syn keyword schemeLibrarySyntax define-interface
+syn keyword schemeLibrarySyntax functor
+syn keyword schemeLibrarySyntax include-relative
syn keyword schemeLibrarySyntax module
syn keyword schemeLibrarySyntax reexport
syn keyword schemeLibrarySyntax require-library
@@ -52,10 +67,12 @@ syn keyword schemeTypeSyntax define-specialization
syn keyword schemeTypeSyntax define-type
syn keyword schemeTypeSyntax the
-syn keyword schemeExtraSyntax and-let*
syn keyword schemeExtraSyntax match
syn keyword schemeExtraSyntax match-lambda
syn keyword schemeExtraSyntax match-lambda*
+syn keyword schemeExtraSyntax match-let
+syn keyword schemeExtraSyntax match-let*
+syn keyword schemeExtraSyntax match-letrec
syn keyword schemeSpecialSyntax define-compiler-syntax
syn keyword schemeSpecialSyntax define-constant
diff --git a/runtime/syntax/cpp.vim b/runtime/syntax/cpp.vim
index ed38913f29..5437580a0a 100644
--- a/runtime/syntax/cpp.vim
+++ b/runtime/syntax/cpp.vim
@@ -2,7 +2,7 @@
" Language: C++
" Current Maintainer: vim-jp (https://github.com/vim-jp/vim-cpp)
" Previous Maintainer: Ken Shan <ccshan@post.harvard.edu>
-" Last Change: 2021 Jan 12
+" Last Change: 2021 Aug 23
" quit when a syntax file was already loaded
if exists("b:current_syntax")
@@ -44,22 +44,54 @@ if !exists("cpp_no_cpp11")
syn keyword cppConstant ATOMIC_WCHAR_T_LOCK_FREE ATOMIC_SHORT_LOCK_FREE
syn keyword cppConstant ATOMIC_INT_LOCK_FREE ATOMIC_LONG_LOCK_FREE
syn keyword cppConstant ATOMIC_LLONG_LOCK_FREE ATOMIC_POINTER_LOCK_FREE
- syn region cppRawString matchgroup=cppRawStringDelimiter start=+\%(u8\|[uLU]\)\=R"\z([[:alnum:]_{}[\]#<>%:;.?*\+\-/\^&|~!=,"']\{,16}\)(+ end=+)\z1"+ contains=@Spell
+ syn region cppRawString matchgroup=cppRawStringDelimiter start=+\%(u8\|[uLU]\)\=R"\z([[:alnum:]_{}[\]#<>%:;.?*\+\-/\^&|~!=,"']\{,16}\)(+ end=+)\z1"\(sv\|s\|_[_a-zA-Z][_a-zA-Z0-9]*\)\=+ contains=@Spell
syn match cppCast "\<\(const\|static\|dynamic\)_pointer_cast\s*<"me=e-1
syn match cppCast "\<\(const\|static\|dynamic\)_pointer_cast\s*$"
endif
" C++ 14 extensions
if !exists("cpp_no_cpp14")
- syn case ignore
- syn match cppNumber display "\<0b[01]\('\=[01]\+\)*\(u\=l\{0,2}\|ll\=u\)\>"
- syn match cppNumber display "\<[1-9]\('\=\d\+\)*\(u\=l\{0,2}\|ll\=u\)\>" contains=cFloat
- syn match cppNumber display "\<0x\x\('\=\x\+\)*\(u\=l\{0,2}\|ll\=u\)\>"
- syn case match
+ syn match cppNumbers display transparent "\<\d\|\.\d" contains=cppNumber,cppFloat
+ syn match cppNumber display contained "\<0\([Uu]\=\([Ll]\|LL\|ll\)\|\([Ll]\|LL\|ll\)\=[Uu]\|i[fl]\=\|h\|min\|s\|ms\|us\|ns\|_\i*\)\=\>"
+ syn match cppNumber display contained "\<[1-9]\('\=\d\+\)*\([Uu]\=\([Ll]\|LL\|ll\)\|\([Ll]\|LL\|ll\)\=[Uu]\|i[fl]\=\|h\|min\|s\|ms\|us\|ns\|_\i*\)\=\>"
+ syn match cppNumber display contained "\<0\o\+\([Uu]\=\([Ll]\|LL\|ll\)\|\([Ll]\|LL\|ll\)\=[Uu]\|i[fl]\=\|h\|min\|s\|ms\|us\|ns\|_\i*\)\=\>"
+ syn match cppNumber display contained "\<0b[01]\('\=[01]\+\)*\([Uu]\=\([Ll]\|LL\|ll\)\|\([Ll]\|LL\|ll\)\=[Uu]\|i[fl]\=\|h\|min\|s\|ms\|us\|ns\|_\i*\)\=\>"
+ syn match cppNumber display contained "\<0x\x\('\=\x\+\)*\([Uu]\=\([Ll]\|LL\|ll\)\|\([Ll]\|LL\|ll\)\=[Uu]\|i[fl]\=\|h\|min\|s\|ms\|us\|ns\|_\i*\)\=\>"
+ syn match cppFloat display contained "\<\d\+\.\d*\(e[-+]\=\d\+\)\=\([FfLl]\|i[fl]\=\|h\|min\|s\|ms\|us\|ns\|_\i*\)\=\>"
+ syn match cppFloat display contained "\<\.\d\+\(e[-+]\=\d\+\)\=\([FfLl]\|i[fl]\=\|h\|min\|s\|ms\|us\|ns\|_\i*\)\=\>"
+ syn match cppFloat display contained "\<\d\+e[-+]\=\d\+\([FfLl]\|i[fl]\=\|h\|min\|s\|ms\|us\|ns\|_\i*\)\=\>"
+ syn region cppString start=+\(L\|u\|u8\|U\)\="+ skip=+\\\\\|\\"\|\\$+ excludenl end=+"\(sv\|s\|_\i*\)\=+ end='$' contains=cSpecial,cFormat,@Spell
+endif
+
+" C++ 17 extensions
+if !exists("cpp_no_cpp17")
+ syn match cppCast "\<reinterpret_pointer_cast\s*<"me=e-1
+ syn match cppCast "\<reinterpret_pointer_cast\s*$"
+ syn match cppFloat display contained "\<0x\x*\.\x\+p[-+]\=\d\+\([FfLl]\|i[fl]\=\|h\|min\|s\|ms\|us\|ns\|_\i*\)\=\>"
+ syn match cppFloat display contained "\<0x\x\+\.\=p[-+]\=\d\+\([FfLl]\|i[fl]\=\|h\|min\|s\|ms\|us\|ns\|_\i*\)\=\>"
+
+ " TODO: push this up to c.vim if/when supported in C23
+ syn match cppCharacter "u8'[^\\]'"
+ syn match cppCharacter "u8'[^']*'" contains=cSpecial
+ if exists("c_gnu")
+ syn match cppSpecialError "u8'\\[^'\"?\\abefnrtv]'"
+ syn match cppSpecialCharacter "u8'\\['\"?\\abefnrtv]'"
+ else
+ syn match cppSpecialError "u8'\\[^'\"?\\abfnrtv]'"
+ syn match cppSpecialCharacter "u8'\\['\"?\\abfnrtv]'"
+ endif
+ syn match cppSpecialCharacter display "u8'\\\o\{1,3}'"
+ syn match cppSpecialCharacter display "u8'\\x\x\+'"
+
endif
" C++ 20 extensions
if !exists("cpp_no_cpp20")
+ syn match cppNumber display contained "\<0\(y\|d\)\>"
+ syn match cppNumber display contained "\<[1-9]\('\=\d\+\)*\(y\|d\)\>"
+ syn match cppNumber display contained "\<0\o\+\(y\|d\)\>"
+ syn match cppNumber display contained "\<0b[01]\('\=[01]\+\)*\(y\|d\)\>"
+ syn match cppNumber display contained "\<0x\x\('\=\x\+\)*\(y\|d\)\>"
syn keyword cppStatement co_await co_return co_yield requires
syn keyword cppStorageClass consteval constinit
syn keyword cppStructure concept
@@ -67,12 +99,6 @@ if !exists("cpp_no_cpp20")
syn keyword cppModule import module export
endif
-" C++ 17 extensions
-if !exists("cpp_no_cpp17")
- syn match cppCast "\<reinterpret_pointer_cast\s*<"me=e-1
- syn match cppCast "\<reinterpret_pointer_cast\s*$"
-endif
-
" The minimum and maximum operators in GNU C++
syn match cppMinMax "[<>]?"
@@ -87,10 +113,15 @@ hi def link cppType Type
hi def link cppStorageClass StorageClass
hi def link cppStructure Structure
hi def link cppBoolean Boolean
+hi def link cppCharacter cCharacter
+hi def link cppSpecialCharacter cSpecialCharacter
+hi def link cppSpecialError cSpecialError
hi def link cppConstant Constant
hi def link cppRawStringDelimiter Delimiter
hi def link cppRawString String
+hi def link cppString String
hi def link cppNumber Number
+hi def link cppFloat Number
hi def link cppModule Include
let b:current_syntax = "cpp"
diff --git a/runtime/syntax/csc.vim b/runtime/syntax/csc.vim
index 6e5d8b9f37..b1bc4d6a7b 100644
--- a/runtime/syntax/csc.vim
+++ b/runtime/syntax/csc.vim
@@ -141,7 +141,7 @@ sy keyword cscBPMacro contained EndLoop AllMembers SelectedMembers If Else EndIf
sy match cscBPMacro contained "!"
sy match cscBPW "!\s*\a*" contains=cscBPmacro
-" when wanted, highlighting lhs members or erros in asignments (may lag the editing)
+" when wanted, highlighting lhs members or errors in assignments (may lag the editing)
if exists("csc_asignment")
sy match cscEqError '\("[^"]*"\s*\|[^][\t !%()*+,--/:;<=>{}~]\+\s*\|->\s*\)*=\([^=]\@=\|$\)'
sy region cscFormula transparent matchgroup=cscVarName start='\("[^"]*"\|[^][\t !%()*+,--/:;<=>{}~]\+\)\s*=\([^=]\@=\|\n\)' skip='"[^"]*"' end=';' contains=ALLBUT,cscFormula,cscFormulaIn,cscBPMacro,cscCondition
diff --git a/runtime/syntax/cupl.vim b/runtime/syntax/cupl.vim
index 5b93b0db93..54495f8ba5 100644
--- a/runtime/syntax/cupl.vim
+++ b/runtime/syntax/cupl.vim
@@ -23,7 +23,7 @@ syn keyword cuplTodo contained TODO XXX FIXME
" cuplHeaderContents uses default highlighting except for numbers
syn match cuplHeaderContents ".\+;"me=e-1 contains=cuplNumber contained
-" String contstants
+" String constants
syn region cuplString start=+'+ end=+'+
syn region cuplString start=+"+ end=+"+
diff --git a/runtime/syntax/debchangelog.vim b/runtime/syntax/debchangelog.vim
index 220f184bc0..93b03ae06d 100644
--- a/runtime/syntax/debchangelog.vim
+++ b/runtime/syntax/debchangelog.vim
@@ -3,7 +3,7 @@
" Maintainer: Debian Vim Maintainers
" Former Maintainers: Gerfried Fuchs <alfie@ist.org>
" Wichert Akkerman <wakkerma@debian.org>
-" Last Change: 2020 Nov 28
+" Last Change: 2021 Aug 03
" URL: https://salsa.debian.org/vim-team/vim-debian/blob/master/syntax/debchangelog.vim
" Standard syntax initialization
@@ -24,7 +24,7 @@ let s:supported = [
\ 'jessie', 'stretch', 'buster', 'bullseye', 'bookworm',
\ 'trixie', 'sid', 'rc-buggy',
\
- \ 'trusty', 'xenial', 'bionic', 'focal', 'groovy', 'hirsute', 'devel'
+ \ 'trusty', 'xenial', 'bionic', 'focal', 'hirsute', 'impish', 'devel'
\ ]
let s:unsupported = [
\ 'frozen', 'buzz', 'rex', 'bo', 'hamm', 'slink', 'potato',
@@ -34,7 +34,7 @@ let s:unsupported = [
\ 'gutsy', 'hardy', 'intrepid', 'jaunty', 'karmic', 'lucid',
\ 'maverick', 'natty', 'oneiric', 'precise', 'quantal', 'raring', 'saucy',
\ 'utopic', 'vivid', 'wily', 'yakkety', 'zesty', 'artful', 'cosmic',
- \ 'disco', 'eoan'
+ \ 'disco', 'eoan', 'groovy'
\ ]
let &cpo=s:cpo
diff --git a/runtime/syntax/debsources.vim b/runtime/syntax/debsources.vim
index 2352466a3b..8aa96fcb58 100644
--- a/runtime/syntax/debsources.vim
+++ b/runtime/syntax/debsources.vim
@@ -2,7 +2,7 @@
" Language: Debian sources.list
" Maintainer: Debian Vim Maintainers
" Former Maintainer: Matthijs Mohlmann <matthijs@cacholong.nl>
-" Last Change: 2020 Nov 28
+" Last Change: 2021 Aug 03
" URL: https://salsa.debian.org/vim-team/vim-debian/blob/master/syntax/debsources.vim
" Standard syntax initialization
@@ -26,7 +26,7 @@ let s:supported = [
\ 'jessie', 'stretch', 'buster', 'bullseye', 'bookworm',
\ 'trixie', 'sid', 'rc-buggy',
\
- \ 'trusty', 'xenial', 'bionic', 'focal', 'groovy', 'hirsute', 'devel'
+ \ 'trusty', 'xenial', 'bionic', 'focal', 'hirsute', 'impish', 'devel'
\ ]
let s:unsupported = [
\ 'buzz', 'rex', 'bo', 'hamm', 'slink', 'potato',
@@ -36,7 +36,7 @@ let s:unsupported = [
\ 'gutsy', 'hardy', 'intrepid', 'jaunty', 'karmic', 'lucid',
\ 'maverick', 'natty', 'oneiric', 'precise', 'quantal', 'raring', 'saucy',
\ 'utopic', 'vivid', 'wily', 'yakkety', 'zesty', 'artful', 'cosmic',
- \ 'disco', 'eoan'
+ \ 'disco', 'eoan', 'groovy'
\ ]
let &cpo=s:cpo
diff --git a/runtime/syntax/dosbatch.vim b/runtime/syntax/dosbatch.vim
index 249e6f7c46..f003a65909 100644
--- a/runtime/syntax/dosbatch.vim
+++ b/runtime/syntax/dosbatch.vim
@@ -1,5 +1,5 @@
" Vim syntax file
-" Language: MSDOS batch file (with NT command extensions)
+" Language: MS-DOS batch file (with NT command extensions)
" Maintainer: Mike Williams <mrw@eandem.co.uk>
" Filenames: *.bat
" Last Change: 6th September 2009
diff --git a/runtime/syntax/doxygen.vim b/runtime/syntax/doxygen.vim
index cfd5452ee4..167b17cd0f 100644
--- a/runtime/syntax/doxygen.vim
+++ b/runtime/syntax/doxygen.vim
@@ -1,4 +1,4 @@
-" DoxyGen syntax hilighting extension for c/c++/idl/java
+" DoxyGen syntax highlighting extension for c/c++/idl/java
" Language: doxygen on top of c, cpp, idl, java, php
" Maintainer: Michael Geddes <vimmer@frog.wheelycreek.net>
" Author: Michael Geddes
@@ -54,7 +54,7 @@ let s:cpo_save = &cpo
try
set cpo&vim
- " Start of Doxygen syntax hilighting:
+ " Start of Doxygen syntax highlighting:
"
" C/C++ Style line comments
@@ -256,7 +256,7 @@ endif
syn match doxygenLinkRest +[^*@\\]\|\*/\@!\|[@\\]\(endlink\>\)\@!+ contained skipnl nextgroup=doxygenLinkRest,doxygenContinueLinkComment
syn match doxygenContinueLinkComment contained +^\s*\*\=[^/]+me=e-1 nextgroup=doxygenLinkRest
syn match doxygenLinkError "\*/" contained
- " #Link hilighting.
+ " #Link highlighting.
syn match doxygenHashLink /\(\h\w*\)\?#\(\.\w\@=\|\w\+\|::\|()\)\+/ contained contains=doxygenHashSpecial
syn match doxygenHashSpecial /#/ contained
syn match doxygenHyperLink /\(\s\|^\s*\*\?\)\@<=\(http\|https\|ftp\):\/\/[-0-9a-zA-Z_?&=+#%/.!':;@~]\+/ contained
@@ -306,7 +306,7 @@ endif
syn region doxygenFormula contained matchgroup=doxygenFormulaEnds start=+f\[+ end=+[@\\]f]+ contains=doxygenFormulaSpecial,doxygenFormulaOperator,doxygenAtom
syn region doxygenAtom contained transparent matchgroup=doxygenFormulaOperator start=+{+ end=+}+ contains=doxygenAtom,doxygenFormulaSpecial,doxygenFormulaOperator
- " Add TODO hilighting.
+ " Add TODO highlighting.
syn keyword doxygenTODO contained TODO README XXX FIXME
" Supported HTML subset. Not perfect, but okay.
diff --git a/runtime/syntax/focexec.vim b/runtime/syntax/focexec.vim
index a75aed47cb..187fd50dbf 100644
--- a/runtime/syntax/focexec.vim
+++ b/runtime/syntax/focexec.vim
@@ -8,7 +8,7 @@
" this is a very simple syntax file - I will be improving it
" one thing is how to do computes
" I don't like that &vars and FUSE() functions highlight to the same color
-" I think some of these things should get different hilights -
+" I think some of these things should get different highlights -
" should MODIFY commands look different than TABLE?
" quit when a syntax file was already loaded
diff --git a/runtime/syntax/forth.vim b/runtime/syntax/forth.vim
index 9b39a7fd7d..721bceb367 100644
--- a/runtime/syntax/forth.vim
+++ b/runtime/syntax/forth.vim
@@ -181,7 +181,7 @@ syn keyword forthMath DECIMAL HEX BASE
syn match forthInteger '\<-\=[0-9]\+.\=\>'
syn match forthInteger '\<&-\=[0-9]\+.\=\>'
" recognize hex and binary numbers, the '$' and '%' notation is for gforth
-syn match forthInteger '\<\$\x*\x\+\>' " *1* --- dont't mess
+syn match forthInteger '\<\$\x*\x\+\>' " *1* --- don't mess
syn match forthInteger '\<\x*\d\x*\>' " *2* --- this order!
syn match forthInteger '\<%[0-1]*[0-1]\+\>'
syn match forthFloat '\<-\=\d*[.]\=\d\+[DdEe]\d\+\>'
diff --git a/runtime/syntax/gemtext.vim b/runtime/syntax/gemtext.vim
new file mode 100644
index 0000000000..8c2bd29928
--- /dev/null
+++ b/runtime/syntax/gemtext.vim
@@ -0,0 +1,24 @@
+" Vim syntax file
+" Language: Gemtext markup language
+" Maintainer: Suneel Freimuth <suneelfreimuth1@gmail.com>
+" Latest Revision: 2020-11-21
+" Filenames: *.gmi
+
+if exists('b:current_syntax')
+ finish
+endif
+
+syntax match Heading /^#\{1,3}.\+$/
+syntax match List /^\* /
+syntax match LinkURL /^=>\s*\S\+/
+syntax match Quote /^>.\+/
+syntax region Preformatted start=/^```/ end=/```/
+
+highlight default link Heading Special
+highlight default link List Statement
+highlight default link LinkURL Underlined
+highlight default link Quote Constant
+highlight default link Preformatted Identifier
+
+let b:current_syntax = 'gemtext'
+
diff --git a/runtime/syntax/go.vim b/runtime/syntax/go.vim
index e78f8cf27c..0c326254b8 100644
--- a/runtime/syntax/go.vim
+++ b/runtime/syntax/go.vim
@@ -1,58 +1,109 @@
-" Vim syntax file
-" Language: Go
-" Maintainer: David Barnett (https://github.com/google/vim-ft-go)
-" Last Change: 2014 Aug 16
-
-" Options:
-" There are some options for customizing the highlighting; the recommended
-" settings are the default values, but you can write:
-" let OPTION_NAME = 0
-" in your ~/.vimrc file to disable particular options. You can also write:
-" let OPTION_NAME = 1
-" to enable particular options. At present, all options default to on.
+" Copyright 2009 The Go Authors. All rights reserved.
+" Use of this source code is governed by a BSD-style
+" license that can be found in the LICENSE file.
"
-" - g:go_highlight_array_whitespace_error
-" Highlights white space after "[]".
-" - g:go_highlight_chan_whitespace_error
-" Highlights white space around the communications operator that don't
-" follow the standard style.
-" - g:go_highlight_extra_types
-" Highlights commonly used library types (io.Reader, etc.).
-" - g:go_highlight_space_tab_error
-" Highlights instances of tabs following spaces.
-" - g:go_highlight_trailing_whitespace_error
-" Highlights trailing white space.
+" go.vim: Vim syntax file for Go.
+" Language: Go
+" Maintainer: Billie Cleek <bhcleek@gmail.com>
+" Latest Revision: 2021-09-18
+" License: BSD-style. See LICENSE file in source repository.
+" Repository: https://github.com/fatih/vim-go
" Quit when a (custom) syntax file was already loaded
-if exists('b:current_syntax')
+if exists("b:current_syntax")
finish
endif
-if !exists('g:go_highlight_array_whitespace_error')
- let g:go_highlight_array_whitespace_error = 1
-endif
-if !exists('g:go_highlight_chan_whitespace_error')
- let g:go_highlight_chan_whitespace_error = 1
-endif
-if !exists('g:go_highlight_extra_types')
- let g:go_highlight_extra_types = 1
-endif
-if !exists('g:go_highlight_space_tab_error')
- let g:go_highlight_space_tab_error = 1
-endif
-if !exists('g:go_highlight_trailing_whitespace_error')
- let g:go_highlight_trailing_whitespace_error = 1
-endif
+let s:keepcpo = &cpo
+set cpo&vim
+
+function! s:FoldEnable(...) abort
+ if a:0 > 0
+ return index(s:FoldEnable(), a:1) > -1
+ endif
+ return get(g:, 'go_fold_enable', ['block', 'import', 'varconst', 'package_comment'])
+endfunction
+
+function! s:HighlightArrayWhitespaceError() abort
+ return get(g:, 'go_highlight_array_whitespace_error', 0)
+endfunction
+
+function! s:HighlightChanWhitespaceError() abort
+ return get(g:, 'go_highlight_chan_whitespace_error', 0)
+endfunction
+
+function! s:HighlightExtraTypes() abort
+ return get(g:, 'go_highlight_extra_types', 0)
+endfunction
+
+function! s:HighlightSpaceTabError() abort
+ return get(g:, 'go_highlight_space_tab_error', 0)
+endfunction
+
+function! s:HighlightTrailingWhitespaceError() abort
+ return get(g:, 'go_highlight_trailing_whitespace_error', 0)
+endfunction
+
+function! s:HighlightOperators() abort
+ return get(g:, 'go_highlight_operators', 0)
+endfunction
+
+function! s:HighlightFunctions() abort
+ return get(g:, 'go_highlight_functions', 0)
+endfunction
+
+function! s:HighlightFunctionParameters() abort
+ return get(g:, 'go_highlight_function_parameters', 0)
+endfunction
+
+function! s:HighlightFunctionCalls() abort
+ return get(g:, 'go_highlight_function_calls', 0)
+endfunction
+
+function! s:HighlightFields() abort
+ return get(g:, 'go_highlight_fields', 0)
+endfunction
+
+function! s:HighlightTypes() abort
+ return get(g:, 'go_highlight_types', 0)
+endfunction
+
+function! s:HighlightBuildConstraints() abort
+ return get(g:, 'go_highlight_build_constraints', 0)
+endfunction
+
+function! s:HighlightStringSpellcheck() abort
+ return get(g:, 'go_highlight_string_spellcheck', 1)
+endfunction
+
+function! s:HighlightFormatStrings() abort
+ return get(g:, 'go_highlight_format_strings', 1)
+endfunction
+
+function! s:HighlightGenerateTags() abort
+ return get(g:, 'go_highlight_generate_tags', 0)
+endfunction
+
+function! s:HighlightVariableAssignments() abort
+ return get(g:, 'go_highlight_variable_assignments', 0)
+endfunction
+
+function! s:HighlightVariableDeclarations() abort
+ return get(g:, 'go_highlight_variable_declarations', 0)
+endfunction
syn case match
-syn keyword goDirective package import
-syn keyword goDeclaration var const type
-syn keyword goDeclType struct interface
+syn keyword goPackage package
+syn keyword goImport import contained
+syn keyword goVar var contained
+syn keyword goConst const contained
-hi def link goDirective Statement
+hi def link goPackage Statement
+hi def link goImport Statement
+hi def link goVar Keyword
+hi def link goConst Keyword
hi def link goDeclaration Keyword
-hi def link goDeclType Keyword
" Keywords within functions
syn keyword goStatement defer go goto return break continue fallthrough
@@ -78,28 +129,38 @@ hi def link goUnsignedInts Type
hi def link goFloats Type
hi def link goComplexes Type
-" Treat func specially: it's a declaration at the start of a line, but a type
-" elsewhere. Order matters here.
-syn match goType /\<func\>/
-syn match goDeclaration /^func\>/
-
" Predefined functions and values
-syn keyword goBuiltins append cap close complex copy delete imag len
-syn keyword goBuiltins make new panic print println real recover
-syn keyword goConstants iota true false nil
+syn keyword goBuiltins append cap close complex copy delete imag len
+syn keyword goBuiltins make new panic print println real recover
+syn keyword goBoolean true false
+syn keyword goPredefinedIdentifiers nil iota
-hi def link goBuiltins Keyword
-hi def link goConstants Keyword
+hi def link goBuiltins Identifier
+hi def link goBoolean Boolean
+hi def link goPredefinedIdentifiers goBoolean
" Comments; their contents
syn keyword goTodo contained TODO FIXME XXX BUG
syn cluster goCommentGroup contains=goTodo
-syn region goComment start="/\*" end="\*/" contains=@goCommentGroup,@Spell
-syn region goComment start="//" end="$" contains=@goCommentGroup,@Spell
+
+syn region goComment start="//" end="$" contains=goGenerate,@goCommentGroup,@Spell
+if s:FoldEnable('comment')
+ syn region goComment start="/\*" end="\*/" contains=@goCommentGroup,@Spell fold
+ syn match goComment "\v(^\s*//.*\n)+" contains=goGenerate,@goCommentGroup,@Spell fold
+else
+ syn region goComment start="/\*" end="\*/" contains=@goCommentGroup,@Spell
+endif
hi def link goComment Comment
hi def link goTodo Todo
+if s:HighlightGenerateTags()
+ syn match goGenerateVariables contained /\%(\$GOARCH\|\$GOOS\|\$GOFILE\|\$GOLINE\|\$GOPACKAGE\|\$DOLLAR\)\>/
+ syn region goGenerate start="^\s*//go:generate" end="$" contains=goGenerateVariables
+ hi def link goGenerate PreProc
+ hi def link goGenerateVariables Special
+endif
+
" Go escapes
syn match goEscapeOctal display contained "\\[0-7]\{3}"
syn match goEscapeC display contained +\\[abfnrtv\\'"]+
@@ -118,8 +179,30 @@ hi def link goEscapeError Error
" Strings and their contents
syn cluster goStringGroup contains=goEscapeOctal,goEscapeC,goEscapeX,goEscapeU,goEscapeBigU,goEscapeError
-syn region goString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=@goStringGroup
-syn region goRawString start=+`+ end=+`+
+if s:HighlightStringSpellcheck()
+ syn region goString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=@goStringGroup,@Spell
+ syn region goRawString start=+`+ end=+`+ contains=@Spell
+else
+ syn region goString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=@goStringGroup
+ syn region goRawString start=+`+ end=+`+
+endif
+
+if s:HighlightFormatStrings()
+ " [n] notation is valid for specifying explicit argument indexes
+ " 1. Match a literal % not preceded by a %.
+ " 2. Match any number of -, #, 0, space, or +
+ " 3. Match * or [n]* or any number or nothing before a .
+ " 4. Match * or [n]* or any number or nothing after a .
+ " 5. Match [n] or nothing before a verb
+ " 6. Match a formatting verb
+ syn match goFormatSpecifier /\
+ \%([^%]\%(%%\)*\)\
+ \@<=%[-#0 +]*\
+ \%(\%(\%(\[\d\+\]\)\=\*\)\|\d\+\)\=\
+ \%(\.\%(\%(\%(\[\d\+\]\)\=\*\)\|\d\+\)\=\)\=\
+ \%(\[\d\+\]\)\=[vTtbcdoqxXUeEfFgGspw]/ contained containedin=goString,goRawString
+ hi def link goFormatSpecifier goSpecialString
+endif
hi def link goString String
hi def link goRawString String
@@ -131,71 +214,263 @@ syn region goCharacter start=+'+ skip=+\\\\\|\\'+ end=+'+ contains=
hi def link goCharacter Character
" Regions
-syn region goBlock start="{" end="}" transparent fold
syn region goParen start='(' end=')' transparent
+if s:FoldEnable('block')
+ syn region goBlock start="{" end="}" transparent fold
+else
+ syn region goBlock start="{" end="}" transparent
+endif
+
+" import
+if s:FoldEnable('import')
+ syn region goImport start='import (' end=')' transparent fold contains=goImport,goString,goComment
+else
+ syn region goImport start='import (' end=')' transparent contains=goImport,goString,goComment
+endif
+
+" var, const
+if s:FoldEnable('varconst')
+ syn region goVar start='var (' end='^\s*)$' transparent fold
+ \ contains=ALLBUT,goParen,goBlock,goFunction,goTypeName,goReceiverType,goReceiverVar,goParamName,goParamType,goSimpleParams,goPointerOperator
+ syn region goConst start='const (' end='^\s*)$' transparent fold
+ \ contains=ALLBUT,goParen,goBlock,goFunction,goTypeName,goReceiverType,goReceiverVar,goParamName,goParamType,goSimpleParams,goPointerOperator
+else
+ syn region goVar start='var (' end='^\s*)$' transparent
+ \ contains=ALLBUT,goParen,goBlock,goFunction,goTypeName,goReceiverType,goReceiverVar,goParamName,goParamType,goSimpleParams,goPointerOperator
+ syn region goConst start='const (' end='^\s*)$' transparent
+ \ contains=ALLBUT,goParen,goBlock,goFunction,goTypeName,goReceiverType,goReceiverVar,goParamName,goParamType,goSimpleParams,goPointerOperator
+endif
+
+" Single-line var, const, and import.
+syn match goSingleDecl /\%(import\|var\|const\) [^(]\@=/ contains=goImport,goVar,goConst
" Integers
-syn match goDecimalInt "\<\d\+\([Ee]\d\+\)\?\>"
-syn match goHexadecimalInt "\<0x\x\+\>"
-syn match goOctalInt "\<0\o\+\>"
-syn match goOctalError "\<0\o*[89]\d*\>"
+syn match goDecimalInt "\<-\=\(0\|[1-9]_\?\(\d\|\d\+_\?\d\+\)*\)\%([Ee][-+]\=\d\+\)\=\>"
+syn match goDecimalError "\<-\=\(_\(\d\+_*\)\+\|\([1-9]\d*_*\)\+__\(\d\+_*\)\+\|\([1-9]\d*_*\)\+_\+\)\%([Ee][-+]\=\d\+\)\=\>"
+syn match goHexadecimalInt "\<-\=0[xX]_\?\(\x\+_\?\)\+\>"
+syn match goHexadecimalError "\<-\=0[xX]_\?\(\x\+_\?\)*\(\([^ \t0-9A-Fa-f_)]\|__\)\S*\|_\)\>"
+syn match goOctalInt "\<-\=0[oO]\?_\?\(\o\+_\?\)\+\>"
+syn match goOctalError "\<-\=0[0-7oO_]*\(\([^ \t0-7oOxX_/)\]\}\:;]\|[oO]\{2,\}\|__\)\S*\|_\|[oOxX]\)\>"
+syn match goBinaryInt "\<-\=0[bB]_\?\([01]\+_\?\)\+\>"
+syn match goBinaryError "\<-\=0[bB]_\?[01_]*\([^ \t01_)]\S*\|__\S*\|_\)\>"
hi def link goDecimalInt Integer
+hi def link goDecimalError Error
hi def link goHexadecimalInt Integer
+hi def link goHexadecimalError Error
hi def link goOctalInt Integer
+hi def link goOctalError Error
+hi def link goBinaryInt Integer
+hi def link goBinaryError Error
hi def link Integer Number
" Floating point
-syn match goFloat "\<\d\+\.\d*\([Ee][-+]\d\+\)\?\>"
-syn match goFloat "\<\.\d\+\([Ee][-+]\d\+\)\?\>"
-syn match goFloat "\<\d\+[Ee][-+]\d\+\>"
+syn match goFloat "\<-\=\d\+\.\d*\%([Ee][-+]\=\d\+\)\=\>"
+syn match goFloat "\<-\=\.\d\+\%([Ee][-+]\=\d\+\)\=\>"
hi def link goFloat Float
" Imaginary literals
-syn match goImaginary "\<\d\+i\>"
-syn match goImaginary "\<\d\+\.\d*\([Ee][-+]\d\+\)\?i\>"
-syn match goImaginary "\<\.\d\+\([Ee][-+]\d\+\)\?i\>"
-syn match goImaginary "\<\d\+[Ee][-+]\d\+i\>"
+syn match goImaginary "\<-\=\d\+i\>"
+syn match goImaginary "\<-\=\d\+[Ee][-+]\=\d\+i\>"
+syn match goImaginaryFloat "\<-\=\d\+\.\d*\%([Ee][-+]\=\d\+\)\=i\>"
+syn match goImaginaryFloat "\<-\=\.\d\+\%([Ee][-+]\=\d\+\)\=i\>"
hi def link goImaginary Number
+hi def link goImaginaryFloat Float
" Spaces after "[]"
-if go_highlight_array_whitespace_error != 0
- syn match goSpaceError display "\(\[\]\)\@<=\s\+"
+if s:HighlightArrayWhitespaceError()
+ syn match goSpaceError display "\%(\[\]\)\@<=\s\+"
endif
" Spacing errors around the 'chan' keyword
-if go_highlight_chan_whitespace_error != 0
+if s:HighlightChanWhitespaceError()
" receive-only annotation on chan type
- syn match goSpaceError display "\(<-\)\@<=\s\+\(chan\>\)\@="
+ "
+ " \(\<chan\>\)\@<!<- (only pick arrow when it doesn't come after a chan)
+ " this prevents picking up 'chan<- chan<-' but not '<- chan'
+ syn match goSpaceError display "\%(\%(\<chan\>\)\@<!<-\)\@<=\s\+\%(\<chan\>\)\@="
+
" send-only annotation on chan type
- syn match goSpaceError display "\(\<chan\)\@<=\s\+\(<-\)\@="
+ "
+ " \(<-\)\@<!\<chan\> (only pick chan when it doesn't come after an arrow)
+ " this prevents picking up '<-chan <-chan' but not 'chan <-'
+ syn match goSpaceError display "\%(\%(<-\)\@<!\<chan\>\)\@<=\s\+\%(<-\)\@="
+
" value-ignoring receives in a few contexts
- syn match goSpaceError display "\(\(^\|[={(,;]\)\s*<-\)\@<=\s\+"
+ syn match goSpaceError display "\%(\%(^\|[={(,;]\)\s*<-\)\@<=\s\+"
endif
" Extra types commonly seen
-if go_highlight_extra_types != 0
- syn match goExtraType /\<bytes\.\(Buffer\)\>/
- syn match goExtraType /\<io\.\(Reader\|Writer\|ReadWriter\|ReadWriteCloser\)\>/
- syn match goExtraType /\<reflect\.\(Kind\|Type\|Value\)\>/
+if s:HighlightExtraTypes()
+ syn match goExtraType /\<bytes\.\%(Buffer\)\>/
+ syn match goExtraType /\<context\.\%(Context\)\>/
+ syn match goExtraType /\<io\.\%(Reader\|ReadSeeker\|ReadWriter\|ReadCloser\|ReadWriteCloser\|Writer\|WriteCloser\|Seeker\)\>/
+ syn match goExtraType /\<reflect\.\%(Kind\|Type\|Value\)\>/
syn match goExtraType /\<unsafe\.Pointer\>/
endif
" Space-tab error
-if go_highlight_space_tab_error != 0
+if s:HighlightSpaceTabError()
syn match goSpaceError display " \+\t"me=e-1
endif
" Trailing white space error
-if go_highlight_trailing_whitespace_error != 0
+if s:HighlightTrailingWhitespaceError()
syn match goSpaceError display excludenl "\s\+$"
endif
hi def link goExtraType Type
hi def link goSpaceError Error
+
+
+" included from: https://github.com/athom/more-colorful.vim/blob/master/after/syntax/go.vim
+"
+" Comments; their contents
+syn keyword goTodo contained NOTE
+hi def link goTodo Todo
+
+syn match goVarArgs /\.\.\./
+
+" Operators;
+if s:HighlightOperators()
+ " match single-char operators: - + % < > ! & | ^ * =
+ " and corresponding two-char operators: -= += %= <= >= != &= |= ^= *= ==
+ syn match goOperator /[-+%<>!&|^*=]=\?/
+ " match / and /=
+ syn match goOperator /\/\%(=\|\ze[^/*]\)/
+ " match two-char operators: << >> &^
+ " and corresponding three-char operators: <<= >>= &^=
+ syn match goOperator /\%(<<\|>>\|&^\)=\?/
+ " match remaining two-char operators: := && || <- ++ --
+ syn match goOperator /:=\|||\|<-\|++\|--/
+ " match ...
+
+ hi def link goPointerOperator goOperator
+ hi def link goVarArgs goOperator
+endif
+hi def link goOperator Operator
+
+" Functions;
+if s:HighlightFunctions() || s:HighlightFunctionParameters()
+ syn match goDeclaration /\<func\>/ nextgroup=goReceiver,goFunction,goSimpleParams skipwhite skipnl
+ syn match goReceiverVar /\w\+\ze\s\+\%(\w\|\*\)/ nextgroup=goPointerOperator,goReceiverType skipwhite skipnl contained
+ syn match goPointerOperator /\*/ nextgroup=goReceiverType contained skipwhite skipnl
+ syn match goFunction /\w\+/ nextgroup=goSimpleParams contained skipwhite skipnl
+ syn match goReceiverType /\w\+/ contained
+ if s:HighlightFunctionParameters()
+ syn match goSimpleParams /(\%(\w\|\_s\|[*\.\[\],\{\}<>-]\)*)/ contained contains=goParamName,goType nextgroup=goFunctionReturn skipwhite skipnl
+ syn match goFunctionReturn /(\%(\w\|\_s\|[*\.\[\],\{\}<>-]\)*)/ contained contains=goParamName,goType skipwhite skipnl
+ syn match goParamName /\w\+\%(\s*,\s*\w\+\)*\ze\s\+\%(\w\|\.\|\*\|\[\)/ contained nextgroup=goParamType skipwhite skipnl
+ syn match goParamType /\%([^,)]\|\_s\)\+,\?/ contained nextgroup=goParamName skipwhite skipnl
+ \ contains=goVarArgs,goType,goSignedInts,goUnsignedInts,goFloats,goComplexes,goDeclType,goBlock
+ hi def link goReceiverVar goParamName
+ hi def link goParamName Identifier
+ endif
+ syn match goReceiver /(\s*\w\+\%(\s\+\*\?\s*\w\+\)\?\s*)\ze\s*\w/ contained nextgroup=goFunction contains=goReceiverVar skipwhite skipnl
+else
+ syn keyword goDeclaration func
+endif
+hi def link goFunction Function
+
+" Function calls;
+if s:HighlightFunctionCalls()
+ syn match goFunctionCall /\w\+\ze(/ contains=goBuiltins,goDeclaration
+endif
+hi def link goFunctionCall Type
+
+" Fields;
+if s:HighlightFields()
+ " 1. Match a sequence of word characters coming after a '.'
+ " 2. Require the following but dont match it: ( \@= see :h E59)
+ " - The symbols: / - + * % OR
+ " - The symbols: [] {} <> ) OR
+ " - The symbols: \n \r space OR
+ " - The symbols: , : .
+ " 3. Have the start of highlight (hs) be the start of matched
+ " pattern (s) offsetted one to the right (+1) (see :h E401)
+ syn match goField /\.\w\+\
+ \%(\%([\/\-\+*%]\)\|\
+ \%([\[\]{}<\>\)]\)\|\
+ \%([\!=\^|&]\)\|\
+ \%([\n\r\ ]\)\|\
+ \%([,\:.]\)\)\@=/hs=s+1
+endif
+hi def link goField Identifier
+
+" Structs & Interfaces;
+if s:HighlightTypes()
+ syn match goTypeConstructor /\<\w\+{\@=/
+ syn match goTypeDecl /\<type\>/ nextgroup=goTypeName skipwhite skipnl
+ syn match goTypeName /\w\+/ contained nextgroup=goDeclType skipwhite skipnl
+ syn match goDeclType /\<\%(interface\|struct\)\>/ skipwhite skipnl
+ hi def link goReceiverType Type
+else
+ syn keyword goDeclType struct interface
+ syn keyword goDeclaration type
+endif
+hi def link goTypeConstructor Type
+hi def link goTypeName Type
+hi def link goTypeDecl Keyword
+hi def link goDeclType Keyword
+
+" Variable Assignments
+if s:HighlightVariableAssignments()
+ syn match goVarAssign /\v[_.[:alnum:]]+(,\s*[_.[:alnum:]]+)*\ze(\s*([-^+|^\/%&]|\*|\<\<|\>\>|\&\^)?\=[^=])/
+ hi def link goVarAssign Special
+endif
+
+" Variable Declarations
+if s:HighlightVariableDeclarations()
+ syn match goVarDefs /\v\w+(,\s*\w+)*\ze(\s*:\=)/
+ hi def link goVarDefs Special
+endif
+
+" Build Constraints
+if s:HighlightBuildConstraints()
+ syn match goBuildKeyword display contained "+build\|go:build"
+ " Highlight the known values of GOOS, GOARCH, and other +build options.
+ syn keyword goBuildDirectives contained
+ \ android darwin dragonfly freebsd linux nacl netbsd openbsd plan9
+ \ solaris windows 386 amd64 amd64p32 arm armbe arm64 arm64be ppc64
+ \ ppc64le mips mipsle mips64 mips64le mips64p32 mips64p32le ppc
+ \ s390 s390x sparc sparc64 cgo ignore race
+
+ " Other words in the build directive are build tags not listed above, so
+ " avoid highlighting them as comments by using a matchgroup just for the
+ " start of the comment.
+ " The rs=s+2 option lets the \s*+build portion be part of the inner region
+ " instead of the matchgroup so it will be highlighted as a goBuildKeyword.
+ syn region goBuildComment matchgroup=goBuildCommentStart
+ \ start="//\s*+build\s"rs=s+2 end="$"
+ \ contains=goBuildKeyword,goBuildDirectives
+ hi def link goBuildCommentStart Comment
+ hi def link goBuildDirectives Type
+ hi def link goBuildKeyword PreProc
+endif
+
+if s:HighlightBuildConstraints() || s:FoldEnable('package_comment')
+ " One or more line comments that are followed immediately by a "package"
+ " declaration are treated like package documentation, so these must be
+ " matched as comments to avoid looking like working build constraints.
+ " The he, me, and re options let the "package" itself be highlighted by
+ " the usual rules.
+ exe 'syn region goPackageComment start=/\v(\/\/.*\n)+\s*package/'
+ \ . ' end=/\v\n\s*package/he=e-7,me=e-7,re=e-7'
+ \ . ' contains=@goCommentGroup,@Spell'
+ \ . (s:FoldEnable('package_comment') ? ' fold' : '')
+ exe 'syn region goPackageComment start=/\v^\s*\/\*.*\n(.*\n)*\s*\*\/\npackage/'
+ \ . ' end=/\v\*\/\n\s*package/he=e-7,me=e-7,re=e-7'
+ \ . ' contains=@goCommentGroup,@Spell'
+ \ . (s:FoldEnable('package_comment') ? ' fold' : '')
+ hi def link goPackageComment Comment
+endif
+
+" :GoCoverage commands
+hi def link goCoverageNormalText Comment
+
" Search backwards for a global declaration to start processing the syntax.
"syn sync match goSync grouphere NONE /^\(const\|var\|type\|func\)\>/
@@ -203,6 +478,9 @@ hi def link goSpaceError Error
" following as a more expensive/less precise workaround.
syn sync minlines=500
-let b:current_syntax = 'go'
+let b:current_syntax = "go"
+
+let &cpo = s:keepcpo
+unlet s:keepcpo
" vim: sw=2 sts=2 et
diff --git a/runtime/syntax/gprof.vim b/runtime/syntax/gprof.vim
index 880452a84b..d2c5cb4cab 100644
--- a/runtime/syntax/gprof.vim
+++ b/runtime/syntax/gprof.vim
@@ -1,15 +1,16 @@
" Vim syntax file
" Language: Syntax for Gprof Output
" Maintainer: Dominique Pelle <dominique.pelle@gmail.com>
-" Last Change: 2021 Apr 08
+" Last Change: 2021 Sep 19
" Quit when a syntax file was already loaded
if exists("b:current_syntax")
- finish
+ finish
endif
let s:keepcpo= &cpo
set cpo&vim
+syn spell notoplevel
syn case match
syn sync minlines=100
diff --git a/runtime/syntax/gvpr.vim b/runtime/syntax/gvpr.vim
new file mode 100644
index 0000000000..a7378916f9
--- /dev/null
+++ b/runtime/syntax/gvpr.vim
@@ -0,0 +1,85 @@
+" Vim syntax file
+" Language: Graphviz program
+" Maintainer: Matthew Fernandez <matthew.fernandez@gmail.com>
+" Last Change: Tue, 28 Jul 2020 17:20:44 -0700
+
+if exists("b:current_syntax")
+ finish
+endif
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+syn keyword gvArg ARGC ARGV
+syn keyword gvBeg BEGIN BEG_G N E END END_G
+syn keyword gvFunc
+ \ graph fstsubg isDirect isStrict isSubg nEdges nNodes nxtsubg subg
+ \ degreeOf fstnode indegreeOf isNode isSubnode node nxtnode nxtnode_sg
+ \ outDegreeOf subnode
+ \ edge edge_sg fstedge fstedge_sg fstin fstin_sg fstout fstout_sg isEdge
+ \ isEdge_sg isSubedge nxtedge nxtedge_sg nxtin nxtin_sg nxtout nxtout_sg opp
+ \ subedge
+ \ freadG fwriteG readG write[] writeG
+ \ aget aset clone cloneG compOf copy[] copyA delete[] fstAttr getDflt hasAttr
+ \ induce isAttr isIn kindOf lock[] nxtAttr setDflt
+ \ canon gsub html index ishtml length llOf match[] rindex split[] sprintf
+ \ sscanf strcmp sub substr tokens tolower toupper urOf xOf yOf
+ \ closeF openF print[] printf scanf readL
+ \ atan2 cos exp log MAX MIN pow sin[] sqrt
+ \ in[] unset
+ \ colorx exit[] rand srand system
+syn keyword gvCons
+ \ NULL TV_bfs TV_dfs TV_en TV_flat TV_fwd TV_ne TV_prepostdfs TV_prepostfwd
+ \ TV_prepostrev TV_postdfs TV_postfwd tv_postrev TV_rev
+syn keyword gvType char double float int long unsigned void
+ \ string
+ \ edge_t graph_t node_t obj_t
+syn match gvVar
+ \ "\$\(\(F\|G\|NG\|O\|T\|tgtname\|tvedge\|tvnext\|tvroot\|tvtype\)\>\)\?\(\<\)\@!"
+syn keyword gvWord break continue else for forr if return switch while
+
+" numbers adapted from c.vim's cNumbers and friends
+syn match gvNums transparent "\<\d\|\.\d" contains=gvNumber,gvFloat,gvOctal
+syn match gvNumber contained "\d\+\(u\=l\{0,2}\|ll\=u\)\>"
+syn match gvNumber contained "0x\x\+\(u\=l\{0,2}\|ll\=u\)\>"
+syn match gvOctal contained "0\o\+\(u\=l\{0,2}\|ll\=u\)\>" contains=gvOctalZero
+syn match gvOctalZero contained "\<0"
+syn match gvFloat contained "\d\+f"
+syn match gvFloat contained "\d\+\.\d*\(e[-+]\=\d\+\)\=[fl]\="
+syn match gvFloat contained "\.\d\+\(e[-+]\=\d\+\)\=[fl]\=\>"
+syn match gvFloat contained "\d\+e[-+]\=\d\+[fl]\=\>"
+
+syn region gvString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=gvFormat,gvSpecial extend
+syn region gvString start="'" skip="\\\\\|\\'" end="'" contains=gvFormat,gvSpecial extend
+
+" adapted from c.vim's cFormat for c_no_c99
+syn match gvFormat "%\(\d\+\$\)\=[-+' #0*]*\(\d*\|\*\|\*\d\+\$\)\(\.\(\d*\|\*\|\*\d\+\$\)\)\=\([hlL]\|ll\)\=\([bdiuoxXDOUfeEgGcCsSpn]\|\[\^\=.[^]]*\]\)" contained
+
+syn match gvSpecial "\\." contained
+
+syn region gvCComment start="//" skip="\\$" end="$" keepend
+syn region gvCPPComment start="#" skip="\\$" end="$" keepend
+syn region gvCXXComment start="/\*" end="\*/" fold
+
+hi def link gvArg Identifier
+hi def link gvBeg Keyword
+hi def link gvFloat Number
+hi def link gvFunc Identifier
+hi def link gvCons Number
+hi def link gvNumber Number
+hi def link gvType Type
+hi def link gvVar Statement
+hi def link gvWord Keyword
+
+hi def link gvString String
+hi def link gvFormat Special
+hi def link gvSpecial Special
+
+hi def link gvCComment Comment
+hi def link gvCPPComment Comment
+hi def link gvCXXComment Comment
+
+let b:current_syntax = "gvpr"
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
diff --git a/runtime/syntax/hamster.vim b/runtime/syntax/hamster.vim
index 64d9598a71..975562da0f 100644
--- a/runtime/syntax/hamster.vim
+++ b/runtime/syntax/hamster.vim
@@ -9,7 +9,7 @@
" It allows the use of multiple news- and mailserver and combines them to one
" mail- and newsserver for the news/mail-client. It load faster than a normal
" newsreader because many threads can run simultaneous. It contains scorefile
-" for news and mail, a build-in script language, the GUI allows translation to
+" for news and mail, a built-in script language, the GUI allows translation to
" other languages, it can be used in a network and that's not all features...
"
" quit when a syntax file was already loaded
diff --git a/runtime/syntax/help.vim b/runtime/syntax/help.vim
index d3d8f4f435..01915d23d7 100644
--- a/runtime/syntax/help.vim
+++ b/runtime/syntax/help.vim
@@ -1,7 +1,7 @@
" Vim syntax file
" Language: Vim help file
" Maintainer: Bram Moolenaar (Bram@vim.org)
-" Last Change: 2020 Jul 28
+" Last Change: 2021 Jun 13
" Quit when a (custom) syntax file was already loaded
if exists("b:current_syntax")
diff --git a/runtime/syntax/idl.vim b/runtime/syntax/idl.vim
index 6a4ce7e087..2f20dec2d7 100644
--- a/runtime/syntax/idl.vim
+++ b/runtime/syntax/idl.vim
@@ -7,7 +7,7 @@
" This is an experiment. IDL's structure is simple enough to permit a full
" grammar based approach to rather than using a few heuristics. The result
-" is large and somewhat repetative but seems to work.
+" is large and somewhat repetitive but seems to work.
" There are some Microsoft extensions to idl files that are here. Some of
" them are disabled by defining idl_no_ms_extensions.
diff --git a/runtime/syntax/iss.vim b/runtime/syntax/iss.vim
index e41de5db5a..34bb698368 100644
--- a/runtime/syntax/iss.vim
+++ b/runtime/syntax/iss.vim
@@ -2,10 +2,10 @@
" Language: Inno Setup File (iss file) and My InnoSetup extension
" Maintainer: Jason Mills (jmills@cs.mun.ca)
" Previous Maintainer: Dominique Stéphan (dominique@mggen.com)
-" Last Change: 2019 Sep 27
+" Last Change: 2021 Aug 30
"
" Todo:
-" - The paramter String: is matched as flag string (because of case ignore).
+" - The parameter String: is matched as flag string (because of case ignore).
" - Pascal scripting syntax is not recognized.
" - Embedded double quotes confuse string matches. e.g. "asfd""asfa"
diff --git a/runtime/syntax/jsonc.vim b/runtime/syntax/jsonc.vim
new file mode 100644
index 0000000000..d0df16bbf1
--- /dev/null
+++ b/runtime/syntax/jsonc.vim
@@ -0,0 +1,44 @@
+" Vim syntax file
+" Language: JSONC (JSON with Comments)
+" Original Author: Izhak Jakov <izhak724@gmail.com>
+" Acknowledgement: Based off of vim-jsonc maintained by Kevin Locke <kevin@kevinlocke.name>
+" https://github.com/kevinoid/vim-jsonc
+" License: MIT
+" Last Change: 2021-07-01
+
+" Ensure syntax is loaded once, unless nested inside another (main) syntax
+" For description of main_syntax, see https://stackoverflow.com/q/16164549
+if !exists('g:main_syntax')
+ if exists('b:current_syntax') && b:current_syntax ==# 'jsonc'
+ finish
+ endif
+ let g:main_syntax = 'jsonc'
+endif
+
+" Based on vim-json syntax
+runtime! syntax/json.vim
+
+" Remove syntax group for comments treated as errors
+if !exists("g:vim_json_warnings") || g:vim_json_warnings
+ syn clear jsonCommentError
+endif
+
+syn match jsonStringMatch /"\([^"]\|\\\"\)\+"\ze\(\_s*\/\/.*\_s*\)*[}\]]/ contains=jsonString
+syn match jsonStringMatch /"\([^"]\|\\\"\)\+"\ze\_s*\/\*\_.*\*\/\_s*[}\]]/ contains=jsonString
+syn match jsonTrailingCommaError /\(,\)\+\ze\(\_s*\/\/.*\_s*\)*[}\]]/
+syn match jsonTrailingCommaError /\(,\)\+\ze\_s*\/\*\_.*\*\/\_s*[}\]]/
+
+" Define syntax matching comments and their contents
+syn keyword jsonCommentTodo FIXME NOTE TBD TODO XXX
+syn region jsonLineComment start=+\/\/+ end=+$+ contains=@Spell,jsonCommentTodo keepend
+syn region jsonComment start='/\*' end='\*/' contains=@Spell,jsonCommentTodo fold
+
+" Link comment syntax comment to highlighting
+hi! def link jsonLineComment Comment
+hi! def link jsonComment Comment
+
+" Set/Unset syntax to avoid duplicate inclusion and correctly handle nesting
+let b:current_syntax = 'jsonc'
+if g:main_syntax ==# 'jsonc'
+ unlet g:main_syntax
+endif
diff --git a/runtime/syntax/julia.vim b/runtime/syntax/julia.vim
new file mode 100644
index 0000000000..2c2d36a97a
--- /dev/null
+++ b/runtime/syntax/julia.vim
@@ -0,0 +1,550 @@
+" Vim syntax file
+" Language: julia
+" Maintainer: Carlo Baldassi <carlobaldassi@gmail.com>
+" Homepage: https://github.com/JuliaEditorSupport/julia-vim
+" Last Change: 2013 feb 11
+
+if version < 600
+ syntax clear
+elseif exists("b:current_syntax")
+ finish
+endif
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+if version < 704
+ " this is used to disable regex syntax like `\@3<='
+ " on older vim versions
+ function! s:d(x)
+ return ''
+ endfunction
+else
+ function! s:d(x)
+ return string(a:x)
+ endfunction
+endif
+
+scriptencoding utf-8
+
+let s:julia_spellcheck_strings = get(g:, "julia_spellcheck_strings", 0)
+let s:julia_spellcheck_docstrings = get(g:, "julia_spellcheck_docstrings", 1)
+let s:julia_spellcheck_comments = get(g:, "julia_spellcheck_comments", 1)
+
+let s:julia_highlight_operators = get(g:, "julia_highlight_operators", 1)
+
+" List of characters, up to \UFF, which cannot be used in identifiers.
+" (It includes operator characters; we don't consider them identifiers.)
+" This is used mostly in lookbehinds with `\@<=`, e.g. when we need to check
+" that that we're not in the middle of an identifier.
+" It doesn't include a few characters (spaces and all closing parentheses)
+" because those may or may not be valid in the lookbehind on a case-by-case
+" basis.
+let s:nonid_chars = '\U00-\U08' . '\U0A-\U1F'
+ \ . '\U21-\U28' . '\U2A-\U2F' . '\U3A-\U40' . '\U5B-\U5E' . '\U60' . '\U7B\U7C'
+ \ . '\U7E-\UA1' . '\UA7\UA8' . '\UAB-\UAD' . '\UAF\UB1\UB4' . '\UB6-\UB8' . '\UBB\UBF' . '\UD7\UF7'
+
+" The complete list
+let s:nonidS_chars = '[:space:])\U5D}' . s:nonid_chars
+
+
+" List of all valid operator chars up to \UFF (NOTE: they must all be included
+" in s:nonidS_chars, so that if we include that, then this is redundant)
+" It does not include '!' since it can be used in an identifier.
+" The list contains the following characters: '%&*+-/<=>\\^|~¬±×÷'
+let s:op_chars = '\U25\U26\U2A\U2B\U2D\U2F\U3C-\U3E\U5C\U5E\U7C\U7E\UAC\UB1\UD7\UF7'
+
+" List of all valid operator chars above \UFF
+" Written with ranges for performance reasons
+" The list contains the following characters: '…⁝⅋←↑→↓↔↚↛↜↝↞↠↢↣↤↦↩↪↫↬↮↶↷↺↻↼↽⇀⇁⇄⇆⇇⇉⇋⇌⇍⇎⇏⇐⇒⇔⇚⇛⇜⇝⇠⇢⇴⇵⇶⇷⇸⇹⇺⇻⇼⇽⇾⇿∈∉∊∋∌∍∓∔∗∘∙√∛∜∝∤∥∦∧∨∩∪∷∸∺∻∽∾≀≁≂≃≄≅≆≇≈≉≊≋≌≍≎≏≐≑≒≓≔≕≖≗≘≙≚≛≜≝≞≟≠≡≢≣≤≥≦≧≨≩≪≫≬≭≮≯≰≱≲≳≴≵≶≷≸≹≺≻≼≽≾≿⊀⊁⊂⊃⊄⊅⊆⊇⊈⊉⊊⊋⊍⊎⊏⊐⊑⊒⊓⊔⊕⊖⊗⊘⊙⊚⊛⊜⊞⊟⊠⊡⊢⊣⊩⊬⊮⊰⊱⊲⊳⊴⊵⊶⊷⊻⊼⊽⋄⋅⋆⋇⋉⋊⋋⋌⋍⋎⋏⋐⋑⋒⋓⋕⋖⋗⋘⋙⋚⋛⋜⋝⋞⋟⋠⋡⋢⋣⋤⋥⋦⋧⋨⋩⋪⋫⋬⋭⋮⋯⋰⋱⋲⋳⋴⋵⋶⋷⋸⋹⋺⋻⋼⋽⋾⋿⌿▷⟂⟈⟉⟑⟒⟕⟖⟗⟰⟱⟵⟶⟷⟹⟺⟻⟼⟽⟾⟿⤀⤁⤂⤃⤄⤅⤆⤇⤈⤉⤊⤋⤌⤍⤎⤏⤐⤑⤒⤓⤔⤕⤖⤗⤘⤝⤞⤟⤠⥄⥅⥆⥇⥈⥉⥊⥋⥌⥍⥎⥏⥐⥑⥒⥓⥔⥕⥖⥗⥘⥙⥚⥛⥜⥝⥞⥟⥠⥡⥢⥣⥤⥥⥦⥧⥨⥩⥪⥫⥬⥭⥮⥯⥰⦷⦸⦼⦾⦿⧀⧁⧡⧣⧤⧥⧴⧶⧷⧺⧻⨇⨈⨝⨟⨢⨣⨤⨥⨦⨧⨨⨩⨪⨫⨬⨭⨮⨰⨱⨲⨳⨴⨵⨶⨷⨸⨹⨺⨻⨼⨽⩀⩁⩂⩃⩄⩅⩊⩋⩌⩍⩎⩏⩐⩑⩒⩓⩔⩕⩖⩗⩘⩚⩛⩜⩝⩞⩟⩠⩡⩢⩣⩦⩧⩪⩫⩬⩭⩮⩯⩰⩱⩲⩳⩴⩵⩶⩷⩸⩹⩺⩻⩼⩽⩾⩿⪀⪁⪂⪃⪄⪅⪆⪇⪈⪉⪊⪋⪌⪍⪎⪏⪐⪑⪒⪓⪔⪕⪖⪗⪘⪙⪚⪛⪜⪝⪞⪟⪠⪡⪢⪣⪤⪥⪦⪧⪨⪩⪪⪫⪬⪭⪮⪯⪰⪱⪲⪳⪴⪵⪶⪷⪸⪹⪺⪻⪼⪽⪾⪿⫀⫁⫂⫃⫄⫅⫆⫇⫈⫉⫊⫋⫌⫍⫎⫏⫐⫑⫒⫓⫔⫕⫖⫗⫘⫙⫛⫷⫸⫹⫺⬰⬱⬲⬳⬴⬵⬶⬷⬸⬹⬺⬻⬼⬽⬾⬿⭀⭁⭂⭃⭄⭇⭈⭉⭊⭋⭌←↑→↓'
+let s:op_chars_wc = '\U2026\U205D\U214B\U2190-\U2194\U219A-\U219E\U21A0\U21A2-\U21A4\U21A6\U21A9-\U21AC\U21AE\U21B6\U21B7\U21BA-\U21BD\U21C0\U21C1\U21C4\U21C6\U21C7\U21C9\U21CB-\U21D0\U21D2\U21D4\U21DA-\U21DD\U21E0\U21E2\U21F4-\U21FF\U2208-\U220D\U2213\U2214\U2217-\U221D\U2224-\U222A\U2237\U2238\U223A\U223B\U223D\U223E\U2240-\U228B\U228D-\U229C\U229E-\U22A3\U22A9\U22AC\U22AE\U22B0-\U22B7\U22BB-\U22BD\U22C4-\U22C7\U22C9-\U22D3\U22D5-\U22FF\U233F\U25B7\U27C2\U27C8\U27C9\U27D1\U27D2\U27D5-\U27D7\U27F0\U27F1\U27F5-\U27F7\U27F9-\U27FF\U2900-\U2918\U291D-\U2920\U2944-\U2970\U29B7\U29B8\U29BC\U29BE-\U29C1\U29E1\U29E3-\U29E5\U29F4\U29F6\U29F7\U29FA\U29FB\U2A07\U2A08\U2A1D\U2A1F\U2A22-\U2A2E\U2A30-\U2A3D\U2A40-\U2A45\U2A4A-\U2A58\U2A5A-\U2A63\U2A66\U2A67\U2A6A-\U2AD9\U2ADB\U2AF7-\U2AFA\U2B30-\U2B44\U2B47-\U2B4C\UFFE9-\UFFEC'
+
+" Full operators regex
+let s:operators = '\%(' . '\.\%([-+*/^÷%|&⊻]\|//\|\\\|>>\|>>>\?\)\?=' .
+ \ '\|' . '[:<>]=\|||\|&&\||>\|<|\|[<>:]:\|<<\|>>>\?\|//\|[-=]>\|\.\.\.\?' .
+ \ '\|' . '\.\?[!' . s:op_chars . s:op_chars_wc . ']' .
+ \ '\)'
+
+
+" Characters that can be used to start an identifier. Above \UBF we don't
+" bother checking. (If a UTF8 operator is used, it will take precedence anyway.)
+let s:id_charsH = '\%([A-Za-z_\UA2-\UA6\UA9\UAA\UAE\UB0\UB5\UBA]\|[^\U00-\UBF]\)'
+" Characters that can appear in an identifier, starting in 2nd position. Above
+" \UBF we check for operators since we need to stop the identifier if one
+" appears. We don't check for invalid characters though.
+let s:id_charsW = '\%([0-9A-Za-z_!\UA2-\UA6\UA9\UAA\UAE-\UB0\UB2-\UB5\UB8-\UBA\UBC-\UBE]\|[^\U00-\UBF]\@=[^' . s:op_chars_wc . ']\)'
+
+" A valid julia identifier, more or less
+let s:idregex = '\%(' . s:id_charsH . s:id_charsW . '*\)'
+
+
+
+syn case match
+
+syntax cluster juliaExpressions contains=@juliaParItems,@juliaStringItems,@juliaKeywordItems,@juliaBlocksItems,@juliaTypesItems,@juliaConstItems,@juliaMacroItems,@juliaSymbolItems,@juliaOperatorItems,@juliaNumberItems,@juliaCommentItems,@juliaErrorItems,@juliaSyntaxRegions
+syntax cluster juliaExprsPrintf contains=@juliaExpressions,@juliaPrintfItems
+syntax cluster juliaExprsNodot contains=@juliaParItems,@juliaStringItems,@juliaMacroItems,@juliaSymbolItems,@juliaOperatorItems,@juliaCommentItems,juliaIdSymbol
+
+syntax cluster juliaParItems contains=juliaParBlock,juliaSqBraIdxBlock,juliaSqBraBlock,juliaCurBraBlock,juliaQuotedParBlock,juliaQuotedQMarkPar
+syntax cluster juliaKeywordItems contains=juliaKeyword,juliaWhereKeyword,juliaImportLine,juliaInfixKeyword,juliaRepKeyword
+syntax cluster juliaBlocksItems contains=juliaConditionalBlock,juliaWhileBlock,juliaForBlock,juliaBeginBlock,juliaFunctionBlock,juliaMacroBlock,juliaQuoteBlock,juliaTypeBlock,juliaImmutableBlock,juliaExceptionBlock,juliaLetBlock,juliaDoBlock,juliaModuleBlock,juliaStructBlock,juliaMutableStructBlock,juliaAbstractBlock,juliaPrimitiveBlock
+syntax cluster juliaTypesItems contains=juliaBaseTypeBasic,juliaBaseTypeNum,juliaBaseTypeC,juliaBaseTypeError,juliaBaseTypeIter,juliaBaseTypeString,juliaBaseTypeArray,juliaBaseTypeDict,juliaBaseTypeSet,juliaBaseTypeIO,juliaBaseTypeProcess,juliaBaseTypeRange,juliaBaseTypeRegex,juliaBaseTypeFact,juliaBaseTypeFact,juliaBaseTypeSort,juliaBaseTypeRound,juliaBaseTypeSpecial,juliaBaseTypeRandom,juliaBaseTypeDisplay,juliaBaseTypeTime,juliaBaseTypeOther
+
+syntax cluster juliaConstItems contains=juliaConstNum,juliaConstBool,juliaConstEnv,juliaConstMMap,juliaConstC,juliaConstGeneric,juliaConstIO,juliaPossibleEuler
+
+syntax cluster juliaMacroItems contains=juliaPossibleMacro,juliaDollarVar,juliaDollarPar,juliaDollarSqBra
+syntax cluster juliaSymbolItems contains=juliaPossibleSymbol
+syntax cluster juliaNumberItems contains=juliaNumbers
+syntax cluster juliaStringItems contains=juliaChar,juliaString,juliabString,juliasString,juliaShellString,juliaDocString,juliaRegEx
+syntax cluster juliaPrintfItems contains=juliaPrintfParBlock,juliaPrintfString
+syntax cluster juliaOperatorItems contains=juliaOperator,juliaRangeOperator,juliaCTransOperator,juliaTernaryRegion,juliaColon,juliaSemicolon,juliaComma
+syntax cluster juliaCommentItems contains=juliaCommentL,juliaCommentM
+syntax cluster juliaErrorItems contains=juliaErrorPar,juliaErrorEnd,juliaErrorElse,juliaErrorCatch,juliaErrorFinally
+
+syntax cluster juliaSyntaxRegions contains=juliaIdSymbol,juliaTypeOperatorR2,juliaTypeOperatorR3,juliaWhereR,juliaDotted
+
+syntax cluster juliaSpellcheckStrings contains=@spell
+syntax cluster juliaSpellcheckDocStrings contains=@spell
+syntax cluster juliaSpellcheckComments contains=@spell
+
+if !s:julia_spellcheck_docstrings
+ syntax cluster juliaSpellcheckDocStrings remove=@spell
+endif
+if !s:julia_spellcheck_strings
+ syntax cluster juliaSpellcheckStrings remove=@spell
+endif
+if !s:julia_spellcheck_comments
+ syntax cluster juliaSpellcheckComments remove=@spell
+endif
+
+syntax match juliaSemicolon display ";"
+syntax match juliaComma display ","
+syntax match juliaColon display ":"
+
+" A dot can introduce a sort of 'environment' such that words after it are not
+" recognized as keywords. This has low precedence so that it can be overridden
+" by operators
+syntax match juliaDotted transparent "\.\s*[^])}.]" contains=@juliaExprsNodot
+syntax match juliaDottedT contained transparent "\.\s*[^])}.]" contains=@juliaExprsNodot,juliaType
+
+syntax match juliaErrorPar display "[])}]"
+syntax match juliaErrorEnd display "\<end\>"
+syntax match juliaErrorElse display "\<\%(else\|elseif\)\>"
+syntax match juliaErrorCatch display "\<catch\>"
+syntax match juliaErrorFinally display "\<finally\>"
+syntax match juliaErrorSemicol display contained ";"
+
+syntax region juliaParBlock matchgroup=juliaParDelim start="(" end=")" contains=@juliaExpressions,juliaComprehensionFor
+syntax region juliaParBlockInRange matchgroup=juliaParDelim contained start="(" end=")" contains=@juliaExpressions,juliaParBlockInRange,juliaRangeKeyword,juliaComprehensionFor
+syntax region juliaSqBraIdxBlock matchgroup=juliaParDelim start="\[" end="\]" contains=@juliaExpressions,juliaParBlockInRange,juliaRangeKeyword,juliaComprehensionFor,juliaSymbolS,juliaQuotedParBlockS,juliaQuotedQMarkParS
+exec 'syntax region juliaSqBraBlock matchgroup=juliaParDelim start="\%(^\|\s\|' . s:operators . '\)\@'.s:d(3).'<=\[" end="\]" contains=@juliaExpressions,juliaComprehensionFor,juliaSymbolS,juliaQuotedParBlockS,juliaQuotedQMarkParS'
+syntax region juliaCurBraBlock matchgroup=juliaParDelim start="{" end="}" contains=juliaType,juliaDottedT,@juliaExpressions
+
+exec 'syntax match juliaType contained "\%(' . s:idregex . '\.\)*\zs' . s:idregex . '"'
+
+" This is a generic identifier followed by some symbol, either a type
+" operator (<: or >:), or an open parenthesis, or an open curly bracket.
+" It's used to recognize one of the contained regions looking for identifiers
+" only once. Once recognized, those regions no longer need to use the
+" expensive s:idregex.
+exec 'syntax match juliaIdSymbol transparent "' . s:idregex . '\%(\s*[<>]:\|\.\?(\|{\|\"\)\@=" contains=juliaFunctionCall,juliaParamType,juliaStringPrefixed,juliaTypeOperatorR1'
+
+syntax match juliaFunctionCall contained "[^{([:space:]<>\"]\+(\@=" nextgroup=juliaParBlock
+
+exec 'syntax match juliaFunctionDef contained transparent "\%(\<\%(function\|macro\)\)\@'.s:d(8).'<=\s\+\zs' . s:idregex . '\%(\.' . s:idregex . '\)*\ze\s*\%((\|\send\>\|$\)" contains=juliaFunctionName'
+exec 'syntax match juliaFunctionName contained "\%(\<\%(function\|macro\)\s\+\)\@'.s:d(20).'<=\%(' . s:idregex . '\.\)*\zs' . s:idregex . '"'
+
+exec 'syntax match juliaStructR contained transparent "\%(\<\%(\%(mutable\s\+\)\?struct\|\%(abstract\|primitive\)\s\+type\)\s\+\)\@'.s:d(20).'<=\%(' . s:idregex . '\.\)*' . s:idregex . '\>\(\s*(\)\@!" contains=juliaType'
+
+syntax match juliaKeyword display "\<\%(return\|local\|global\|const\)\>"
+syntax match juliaInfixKeyword display "\%(=\s*\)\@<!\<\%(in\|isa\)\>\S\@!\%(\s*=\)\@!"
+
+" The import/export/using keywords introduce a sort of special parsing
+" environment with its own rules
+exec 'syntax region juliaImportLine matchgroup=juliaKeyword excludenl start="\<\%(import\|using\|export\)\>" skip="\%(\%(\<\%(import\|using\|export\)\>\)\|^\)\@'.s:d(6).'<=$" end="$" end="\%([])}]\)\@=" contains=@juliaExpressions,juliaAsKeyword,@juliaContinuationItems,juliaMacroName'
+syntax match juliaAsKeyword display contained "\<as\>"
+
+syntax match juliaRepKeyword display "\<\%(break\|continue\)\>"
+syntax region juliaConditionalBlock matchgroup=juliaConditional start="\<if\>" end="\<end\>" contains=@juliaExpressions,juliaConditionalEIBlock,juliaConditionalEBlock fold
+syntax region juliaConditionalEIBlock matchgroup=juliaConditional transparent contained start="\<elseif\>" end="\<\%(end\|else\|elseif\)\>"me=s-1 contains=@juliaExpressions,juliaConditionalEIBlock,juliaConditionalEBlock
+syntax region juliaConditionalEBlock matchgroup=juliaConditional transparent contained start="\<else\>" end="\<end\>"me=s-1 contains=@juliaExpressions
+syntax region juliaWhileBlock matchgroup=juliaRepeat start="\<while\>" end="\<end\>" contains=@juliaExpressions fold
+syntax region juliaForBlock matchgroup=juliaRepeat start="\<for\>" end="\<end\>" contains=@juliaExpressions,juliaOuter fold
+syntax region juliaBeginBlock matchgroup=juliaBlKeyword start="\<begin\>" end="\<end\>" contains=@juliaExpressions fold
+syntax region juliaFunctionBlock matchgroup=juliaBlKeyword start="\<function\>" end="\<end\>" contains=@juliaExpressions,juliaFunctionDef fold
+syntax region juliaMacroBlock matchgroup=juliaBlKeyword start="\<macro\>" end="\<end\>" contains=@juliaExpressions,juliaFunctionDef fold
+syntax region juliaQuoteBlock matchgroup=juliaBlKeyword start="\<quote\>" end="\<end\>" contains=@juliaExpressions fold
+syntax region juliaStructBlock matchgroup=juliaBlKeyword start="\<struct\>" end="\<end\>" contains=@juliaExpressions,juliaStructR fold
+syntax region juliaMutableStructBlock matchgroup=juliaBlKeyword start="\<mutable\s\+struct\>" end="\<end\>" contains=@juliaExpressions,juliaStructR fold
+syntax region juliaLetBlock matchgroup=juliaBlKeyword start="\<let\>" end="\<end\>" contains=@juliaExpressions fold
+syntax region juliaDoBlock matchgroup=juliaBlKeyword start="\<do\>" end="\<end\>" contains=@juliaExpressions fold
+syntax region juliaModuleBlock matchgroup=juliaBlKeyword start="\<\%(bare\)\?module\>" end="\<end\>" contains=@juliaExpressions fold
+syntax region juliaExceptionBlock matchgroup=juliaException start="\<try\>" end="\<end\>" contains=@juliaExpressions,juliaCatchBlock,juliaFinallyBlock fold
+syntax region juliaCatchBlock matchgroup=juliaException transparent contained start="\<catch\>" end="\<end\>"me=s-1 contains=@juliaExpressions,juliaFinallyBlock
+syntax region juliaFinallyBlock matchgroup=juliaException transparent contained start="\<finally\>" end="\<end\>"me=s-1 contains=@juliaExpressions
+syntax region juliaAbstractBlock matchgroup=juliaBlKeyword start="\<abstract\s\+type\>" end="\<end\>" fold contains=@juliaExpressions,juliaStructR
+syntax region juliaPrimitiveBlock matchgroup=juliaBlKeyword start="\<primitive\s\+type\>" end="\<end\>" fold contains=@juliaExpressions,juliaStructR
+
+exec 'syntax region juliaComprehensionFor matchgroup=juliaComprehensionFor transparent contained start="\%([^[:space:],;:({[]\_s*\)\@'.s:d(80).'<=\<for\>" end="\ze[]);]" contains=@juliaExpressions,juliaComprehensionIf,juliaComprehensionFor'
+syntax match juliaComprehensionIf contained "\<if\>"
+
+exec 'syntax match juliaOuter contained "\<outer\ze\s\+' . s:idregex . '\>"'
+
+syntax match juliaRangeKeyword contained "\<\%(begin\|end\)\>"
+
+syntax match juliaBaseTypeBasic display "\<\%(\%(N\|Named\)\?Tuple\|Symbol\|Function\|Union\%(All\)\?\|Type\%(Name\|Var\)\?\|Any\|ANY\|Vararg\|Ptr\|Exception\|Module\|Expr\|DataType\|\%(LineNumber\|Quote\)Node\|\%(Weak\|Global\)\?Ref\|Method\|Pair\|Val\|Nothing\|Some\|Missing\)\>"
+syntax match juliaBaseTypeNum display "\<\%(U\?Int\%(8\|16\|32\|64\|128\)\?\|Float\%(16\|32\|64\)\|Complex\|Bool\|Char\|Number\|Signed\|Unsigned\|Integer\|AbstractFloat\|Real\|Rational\|\%(Abstract\)\?Irrational\|Enum\|BigInt\|BigFloat\|MathConst\|ComplexF\%(16\|32\|64\)\)\>"
+syntax match juliaBaseTypeC display "\<\%(FileOffset\|C\%(u\?\%(char\|short\|int\|long\(long\)\?\|w\?string\)\|float\|double\|\%(ptrdiff\|s\?size\|wchar\|off\|u\?intmax\)_t\|void\)\)\>"
+syntax match juliaBaseTypeError display "\<\%(\%(Bounds\|Divide\|Domain\|\%(Stack\)\?Overflow\|EOF\|Undef\%(Ref\|Var\)\|System\|Type\|Parse\|Argument\|Key\|Load\|Method\|Inexact\|OutOfMemory\|Init\|Assertion\|ReadOnlyMemory\|StringIndex\)Error\|\%(Interrupt\|Error\|ProcessExited\|Captured\|Composite\|InvalidState\|Missing\|\%(Process\|Task\)Failed\)Exception\|DimensionMismatch\|SegmentationFault\)\>"
+syntax match juliaBaseTypeIter display "\<\%(EachLine\|Enumerate\|Cartesian\%(Index\|Range\)\|LinSpace\|CartesianIndices\)\>"
+syntax match juliaBaseTypeString display "\<\%(DirectIndex\|Sub\|Rep\|Rev\|Abstract\|Substitution\)\?String\>"
+syntax match juliaBaseTypeArray display "\<\%(\%(Sub\)\?Array\|\%(Abstract\|Dense\|Strided\)\?\%(Array\|Matrix\|Vec\%(tor\|OrMat\)\)\|SparseMatrixCSC\|\%(AbstractSparse\|Bit\|Shared\)\%(Array\|Vector\|Matrix\)\|\%\(D\|Bid\|\%(Sym\)\?Trid\)iagonal\|Hermitian\|Symmetric\|UniformScaling\|\%(Lower\|Upper\)Triangular\|\%(Sparse\|Row\)Vector\|VecElement\|Conj\%(Array\|Matrix\|Vector\)\|Index\%(Cartesian\|Linear\|Style\)\|PermutedDimsArray\|Broadcasted\|Adjoint\|Transpose\|LinearIndices\)\>"
+syntax match juliaBaseTypeDict display "\<\%(WeakKey\|Id\|Abstract\)\?Dict\>"
+syntax match juliaBaseTypeSet display "\<\%(\%(Abstract\|Bit\)\?Set\)\>"
+syntax match juliaBaseTypeIO display "\<\%(IO\%(Stream\|Buffer\|Context\)\?\|RawFD\|StatStruct\|FileMonitor\|PollingFileWatcher\|Timer\|Base64\%(Decode\|Encode\)Pipe\|\%(UDP\|TCP\)Socket\|\%(Abstract\)\?Channel\|BufferStream\|ReentrantLock\|GenericIOBuffer\)\>"
+syntax match juliaBaseTypeProcess display "\<\%(Pipe\|Cmd\|PipeBuffer\)\>"
+syntax match juliaBaseTypeRange display "\<\%(Dims\|RangeIndex\|\%(Abstract\|Lin\|Ordinal\|Step\|\%(Abstract\)\?Unit\)Range\|Colon\|ExponentialBackOff\|StepRangeLen\)\>"
+syntax match juliaBaseTypeRegex display "\<Regex\%(Match\)\?\>"
+syntax match juliaBaseTypeFact display "\<\%(Factorization\|BunchKaufman\|\%(Cholesky\|QR\)\%(Pivoted\)\?\|\%(Generalized\)\?\%(Eigen\|SVD\|Schur\)\|Hessenberg\|LDLt\|LQ\|LU\)\>"
+syntax match juliaBaseTypeSort display "\<\%(Insertion\|\(Partial\)\?Quick\|Merge\)Sort\>"
+syntax match juliaBaseTypeRound display "\<Round\%(ingMode\|FromZero\|Down\|Nearest\%(Ties\%(Away\|Up\)\)\?\|ToZero\|Up\)\>"
+syntax match juliaBaseTypeSpecial display "\<\%(LocalProcess\|ClusterManager\)\>"
+syntax match juliaBaseTypeRandom display "\<\%(AbstractRNG\|MersenneTwister\|RandomDevice\)\>"
+syntax match juliaBaseTypeDisplay display "\<\%(Text\(Display\)\?\|\%(Abstract\)\?Display\|MIME\|HTML\)\>"
+syntax match juliaBaseTypeTime display "\<\%(Date\%(Time\)\?\|DateFormat\)\>"
+syntax match juliaBaseTypeOther display "\<\%(RemoteRef\|Task\|Condition\|VersionNumber\|IPv[46]\|SerializationState\|WorkerConfig\|Future\|RemoteChannel\|IPAddr\|Stack\%(Trace\|Frame\)\|\(Caching\|Worker\)Pool\|AbstractSerializer\)\>"
+
+syntax match juliaConstNum display "\%(\<\%(\%(NaN\|Inf\)\%(16\|32\|64\)\?\|pi\|π\)\>\)"
+" Note: recognition of ℯ, which Vim does not consider a valid identifier, is
+" complicated. We detect possible uses by just looking for the character (for
+" performance) and then check that it's actually used by its own.
+" (This also tries to detect preceding number constants; it does so in a crude
+" way.)
+syntax match juliaPossibleEuler "ℯ" contains=juliaEuler
+exec 'syntax match juliaEuler contained "\%(\%(^\|[' . s:nonidS_chars . s:op_chars_wc . ']\)\%(.\?[0-9][.0-9eEf_]*\d\)\?\)\@'.s:d(80).'<=ℯ\ze[' . s:nonidS_chars . s:op_chars_wc . ']"'
+syntax match juliaConstBool display "\<\%(true\|false\)\>"
+syntax match juliaConstEnv display "\<\%(ARGS\|ENV\|ENDIAN_BOM\|LOAD_PATH\|VERSION\|PROGRAM_FILE\|DEPOT_PATH\)\>"
+syntax match juliaConstIO display "\<\%(std\%(out\|in\|err\)\|devnull\)\>"
+syntax match juliaConstC display "\<\%(C_NULL\)\>"
+syntax match juliaConstGeneric display "\<\%(nothing\|Main\|undef\|missing\)\>"
+
+syntax match juliaParamType contained "[^{([:space:]<>\"]\+\ze{" nextgroup=juliaCurBraBlock
+
+syntax match juliaPossibleMacro transparent "@" contains=juliaMacroCall,juliaMacroCallP,juliaPrintfMacro,juliaDocMacro,juliaDocMacroPre
+
+exec 'syntax match juliaMacro contained "@' . s:idregex . '\%(\.' . s:idregex . '\)*"'
+syntax match juliaMacro contained "@[!.~$%^*/\\|<>+-]\ze[^0-9]"
+exec 'syntax region juliaMacroCall contained transparent start="\(@' . s:idregex . '\%(\.' . s:idregex . '\)*\)\@=\1\%([^(]\|$\)" end="\ze\%([])};#]\|$\|\<for\>\|\<end\>\)" contains=@juliaExpressions,juliaMacro,juliaSymbolS,juliaQuotedParBlockS'
+exec 'syntax region juliaMacroCall contained transparent start="\(@.\)\@=\1\%([^(]\|$\)" end="\ze\%([])};#]\|$\|\<for\>\|\<end\>\)" contains=@juliaExpressions,juliaMacro,juliaSymbolS,juliaQuotedParBlockS'
+exec 'syntax region juliaMacroCallP contained transparent start="@' . s:idregex . '\%(\.' . s:idregex . '\)*(" end=")\@'.s:d(1).'<=" contains=juliaMacro,juliaParBlock'
+exec 'syntax region juliaMacroCallP contained transparent start="@.(" end=")\@'.s:d(1).'<=" contains=juliaMacro,juliaParBlock'
+
+exec 'syntax match juliaNumbers transparent "\%(^\|[' . s:nonidS_chars . s:op_chars_wc . ']\)\@'.s:d(1).'<=\d\|\.\d\|im\>" contains=juliaNumber,juliaFloat,juliaComplexUnit'
+
+"integer regexes
+let s:dec_regex = '\d\%(_\?\d\)*\%(\>\|im\>\|\ze\D\)'
+let s:hex_regex = '0x\x\%(_\?\x\)*\%(\>\|im\>\|\ze\X\)'
+let s:bin_regex = '0b[01]\%(_\?[01]\)*\%(\>\|im\>\|\ze[^01]\)'
+let s:oct_regex = '0o\o\%(_\?\o\)*\%(\>\|im\>\|\ze\O\)'
+
+let s:int_regex = '\%(' . s:hex_regex .
+ \ '\|' . s:bin_regex .
+ \ '\|' . s:oct_regex .
+ \ '\|' . s:dec_regex .
+ \ '\)'
+
+"floating point regexes
+" starting with a dot, optional exponent
+let s:float_regex1 = '\.\d\%(_\?\d\)*\%([eEf][-+]\?\d\+\)\?\%(\>\|im\>\|\ze\D\)'
+" with dot, optional exponent
+let s:float_regex2 = '\d\%(_\?\d\)*\.\%(\d\%(_\?\d\)*\)\?\%([eEf][-+]\?\d\+\)\?\%(\>\|im\>\|\ze\D\)'
+" without dot, with exponent
+let s:float_regex3 = '\d\%(_\?\d\)*[eEf][-+]\?\d\+\%(\>\|im\>\|\ze\D\)'
+
+"hex floating point numbers
+" starting with a dot
+let s:hexfloat_regex1 = '0x\.\%\(\x\%(_\?\x\)*\)\?[pP][-+]\?\d\+\%(\>\|im\>\|\ze\X\)'
+" starting with a digit
+let s:hexfloat_regex2 = '0x\x\%(_\?\x\)*\%\(\.\%\(\x\%(_\?\x\)*\)\?\)\?[pP][-+]\?\d\+\%(\>\|im\>\|\ze\X\)'
+
+let s:float_regex = '\%(' . s:float_regex3 .
+ \ '\|' . s:float_regex2 .
+ \ '\|' . s:float_regex1 .
+ \ '\|' . s:hexfloat_regex2 .
+ \ '\|' . s:hexfloat_regex1 .
+ \ '\)'
+
+exec 'syntax match juliaNumber contained "' . s:int_regex . '" contains=juliaComplexUnit'
+exec 'syntax match juliaFloat contained "' . s:float_regex . '" contains=juliaComplexUnit'
+syntax match juliaComplexUnit display contained "\<im\>"
+
+syntax match juliaRangeOperator display ":"
+exec 'syntax match juliaOperator "' . s:operators . '"'
+
+exec 'syntax region juliaTernaryRegion matchgroup=juliaTernaryOperator start="\s\zs?\ze\s" skip="\%(:\(:\|[^:[:space:]'."'".'"({[]\+\s*\ze:\)\|\%(?\s*\)\@'.s:d(6).'<=:(\)" end=":" contains=@juliaExpressions,juliaErrorSemicol'
+
+let s:interp_dollar = '\([' . s:nonidS_chars . s:op_chars_wc . '!]\|^\)\@'.s:d(1).'<=\$'
+
+exec 'syntax match juliaDollarVar display contained "' . s:interp_dollar . s:idregex . '"'
+exec 'syntax region juliaDollarPar matchgroup=juliaDollarVar contained start="' .s:interp_dollar . '(" end=")" contains=@juliaExpressions'
+exec 'syntax region juliaDollarSqBra matchgroup=juliaDollarVar contained start="' .s:interp_dollar . '\[" end="\]" contains=@juliaExpressions,juliaComprehensionFor,juliaSymbolS,juliaQuotedParBlockS'
+
+syntax match juliaChar "'\\\?.'" contains=juliaSpecialChar
+syntax match juliaChar display "'\\\o\{3\}'" contains=juliaOctalEscapeChar
+syntax match juliaChar display "'\\x\x\{2\}'" contains=juliaHexEscapeChar
+syntax match juliaChar display "'\\u\x\{1,4\}'" contains=juliaUniCharSmall
+syntax match juliaChar display "'\\U\x\{1,8\}'" contains=juliaUniCharLarge
+
+exec 'syntax match juliaCTransOperator "[[:space:]}' . s:nonid_chars . s:op_chars_wc . '!]\@'.s:d(1).'<!\.\?' . "'" . 'ᵀ\?"'
+
+" TODO: some of these might be specialized; the rest could be just left to the
+" generic juliaStringPrefixed fallback
+syntax region juliaString matchgroup=juliaStringDelim start=+\z("\(""\)\?\)+ skip=+\%(\\\\\)*\\"+ end=+\z1+ contains=@juliaStringVars,@juliaSpecialChars,@juliaSpellcheckStrings
+syntax region juliaStringPrefixed contained matchgroup=juliaStringDelim start=+[^{([:space:]<>"]\+\z("\(""\)\?\)+ skip=+\%(\\\\\)*\\"+ end=+\z1+ contains=@juliaSpecialCharsRaw
+syntax region juliabString matchgroup=juliaStringDelim start=+\<b\z("\(""\)\?\)+ skip=+\%(\\\\\)*\\"+ end=+\z1+ contains=@juliaSpecialChars
+syntax region juliasString matchgroup=juliaStringDelim start=+\<s\z("\(""\)\?\)+ skip=+\%(\\\\\)*\\"+ end=+\z1+ contains=@juliaSpecialChars
+
+syntax region juliaDocString matchgroup=juliaDocStringDelim fold start=+^"""+ skip=+\%(\\\\\)*\\"+ end=+"""+ contains=@juliaStringVars,@juliaSpecialChars,@juliaSpellcheckDocStrings
+
+exec 'syntax region juliaPrintfMacro contained transparent start="@s\?printf(" end=")\@'.s:d(1).'<=" contains=juliaMacro,juliaPrintfParBlock'
+syntax region juliaPrintfMacro contained transparent start="@s\?printf\s\+" end="\ze\%([])};#]\|$\|\<for\>\)" contains=@juliaExprsPrintf,juliaMacro,juliaSymbolS,juliaQuotedParBlockS
+syntax region juliaPrintfParBlock contained matchgroup=juliaParDelim start="(" end=")" contains=@juliaExprsPrintf
+syntax region juliaPrintfString contained matchgroup=juliaStringDelim start=+"+ skip=+\%(\\\\\)*\\"+ end=+"+ contains=@juliaSpecialChars,@juliaPrintfChars
+
+exec 'syntax region juliaDocMacroPre contained transparent start=+@doc\s\+\%(' . s:idregex . '\%(\.' . s:idregex . '\)*\)\z("\%(""\)\?\)+ skip=+\%(\\\\\)*\\"+ end=+\(\z1\)\@'.s:d(3).'<=+ contains=juliaMacro,juliaDocStringMRaw'
+exec 'syntax region juliaDocMacro contained transparent start=+@doc\s\+\z("\%(""\)\?\)+ skip=+\%(\\\\\)*\\"+ end=+\(\z1\)\@'.s:d(3).'<=+ contains=juliaMacro,juliaDocStringM'
+syntax region juliaDocStringMRaw contained fold matchgroup=juliaDocStringDelim fold start=+\z\("\(""\)\?\)+ skip=+\%(\\\\\)*\\"+ end=+\z1+ contains=@juliaSpellcheckDocStrings
+syntax region juliaDocStringM contained fold matchgroup=juliaDocStringDelim fold start=+\z\("\(""\)\?\)+ skip=+\%(\\\\\)*\\"+ end=+\z1+ contains=@juliaStringVars,@juliaSpecialChars,@juliaSpellcheckDocStrings
+
+syntax region juliaShellString matchgroup=juliaStringDelim start=+`+ skip=+\%(\\\\\)*\\`+ end=+`+ contains=@juliaStringVars,juliaSpecialChar
+
+syntax cluster juliaStringVars contains=juliaStringVarsPar,juliaStringVarsSqBra,juliaStringVarsCurBra,juliaStringVarsPla
+syntax region juliaStringVarsPar contained matchgroup=juliaStringVarDelim start="$(" end=")" contains=@juliaExpressions
+syntax region juliaStringVarsSqBra contained matchgroup=juliaStringVarDelim start="$\[" end="\]" contains=@juliaExpressions,juliaComprehensionFor,juliaSymbolS,juliaQuotedParBlockS
+syntax region juliaStringVarsCurBra contained matchgroup=juliaStringVarDelim start="${" end="}" contains=@juliaExpressions
+exec 'syntax match juliaStringVarsPla contained "\$' . s:idregex . '"'
+
+" TODO improve RegEx
+syntax region juliaRegEx matchgroup=juliaStringDelim start=+\<r\z("\(""\)\?\)+ skip=+\%(\\\\\)*\\"+ end=+\z1[imsx]*+
+
+syntax cluster juliaSpecialChars contains=juliaSpecialChar,juliaDoubleBackslash,juliaEscapedQuote,juliaOctalEscapeChar,juliaHexEscapeChar,juliaUniCharSmall,juliaUniCharLarge
+syntax match juliaSpecialChar display contained "\\."
+syntax match juliaOctalEscapeChar display contained "\\\o\{3\}"
+syntax match juliaHexEscapeChar display contained "\\x\x\{2\}"
+syntax match juliaUniCharSmall display contained "\\u\x\{1,4\}"
+syntax match juliaUniCharLarge display contained "\\U\x\{1,8\}"
+syntax cluster juliaSpecialCharsRaw contains=juliaDoubleBackslash,juliaEscapedQuote
+syntax match juliaDoubleBackslash contained "\\\\"
+syntax match juliaEscapedQuote contained "\\\""
+
+syntax cluster juliaPrintfChars contains=juliaErrorPrintfFmt,juliaPrintfFmt
+syntax match juliaErrorPrintfFmt display contained "\\\?%."
+syntax match juliaPrintfFmt display contained "%\%(\d\+\$\)\=[-+' #0]*\%(\d*\|\*\|\*\d\+\$\)\%(\.\%(\d*\|\*\|\*\d\+\$\)\)\=\%([hlLjqzt]\|ll\|hh\)\=[aAbdiuoxXDOUfFeEgGcCsSpn]"
+syntax match juliaPrintfFmt display contained "%%"
+syntax match juliaPrintfFmt display contained "\\%\%(\d\+\$\)\=[-+' #0]*\%(\d*\|\*\|\*\d\+\$\)\%(\.\%(\d*\|\*\|\*\d\+\$\)\)\=\%([hlLjqzt]\|ll\|hh\)\=[aAbdiuoxXDOUfFeEgGcCsSpn]"hs=s+1
+syntax match juliaPrintfFmt display contained "\\%%"hs=s+1
+
+" this is used to restrict the search for Symbols to when colons appear at all
+" (for performance reasons)
+syntax match juliaPossibleSymbol transparent ":\ze[^:]" contains=juliaSymbol,juliaQuotedParBlock,juliaQuotedQMarkPar,juliaColon
+
+let s:quotable = '\%(' . s:idregex . '\|' . s:operators . '\|[?.]\|' . s:float_regex . '\|' . s:int_regex . '\)'
+let s:quoting_colon = '\%(\%(^\s*\|\s\{6,\}\|[' . s:nonid_chars . s:op_chars_wc . ']\s*\)\@'.s:d(6).'<=\|\%(\<\%(return\|if\|else\%(if\)\?\|while\|try\|begin\)\s\+\)\@'.s:d(9).'<=\)\zs:'
+let s:quoting_colonS = '\s\@'.s:d(1).'<=:'
+
+" note: juliaSymbolS only works within whitespace-sensitive contexts,
+" such as in macro calls without parentheses, or within square brackets.
+" It is used to override the recognition of expressions like `a :b` as
+" ranges rather than symbols in those contexts.
+" (Note that such `a :b` expressions only allows at most 5 spaces between
+" the identifier and the colon anyway.)
+
+exec 'syntax match juliaSymbol contained "' . s:quoting_colon . s:quotable . '"'
+exec 'syntax match juliaSymbolS contained "' . s:quoting_colonS . s:quotable . '"'
+
+" same as above for quoted expressions such as :(expr)
+exec 'syntax region juliaQuotedParBlock matchgroup=juliaQParDelim start="' . s:quoting_colon . '(" end=")" contains=@juliaExpressions'
+exec 'syntax match juliaQuotedQMarkPar "' . s:quoting_colon . '(\s*?\s*)" contains=juliaQuotedQMark'
+exec 'syntax region juliaQuotedParBlockS matchgroup=juliaQParDelim contained start="' . s:quoting_colonS . '(" end=")" contains=@juliaExpressions'
+
+
+syntax match juliaTypeOperatorR1 contained "[^{([:space:]<>\"]\+\%(\s*[<>]:\)\@="
+
+" force precedence over Symbols
+syntax match juliaTypeOperator contained "[<>:]:"
+exec 'syntax match juliaTypeOperatorR2 transparent "[<>:]:\s*\%(' . s:idregex . '\.\)*' . s:idregex . '" contains=juliaTypeOperator,juliaType,juliaDottedT,@juliaExpressions nextgroup=juliaTypeOperator'
+syntax match juliaIsaKeyword contained "\<isa\>"
+exec 'syntax match juliaTypeOperatorR3 transparent "\<isa\s\+\%(' . s:idregex . '\.\)*' . s:idregex . '" contains=juliaIsaKeyword,juliaType,juliaDottedT,@juliaExpressions nextgroup=juliaIsaKeyword'
+
+syntax match juliaWhereKeyword "\<where\>"
+exec 'syntax match juliaWhereR transparent "\<where\s\+' . s:idregex . '" contains=juliaWhereKeyword,juliaType,juliaDottedT,juliaIdSymbol'
+
+syntax region juliaCommentL matchgroup=juliaCommentDelim excludenl start="#\ze\%([^=]\|$\)" end="$" contains=juliaTodo,@juliaSpellcheckComments
+syntax region juliaCommentM matchgroup=juliaCommentDelim fold start="#=\ze\%([^#]\|$\)" end="=#" contains=juliaTodo,juliaCommentM,@juliaSpellcheckComments
+syntax keyword juliaTodo contained TODO FIXME XXX
+
+" detect an end-of-line with only whitespace or comments before it
+let s:eol = '\s*\%(\%(\%(#=\%(=#\@!\|[^=]\|\n\)\{-}=#\)\s*\)\+\)\?\%(#=\@!.*\)\?\n'
+
+" a trailing comma, or colon, or an empty line in an import/using/export
+" multi-line command. Used to recognize the as keyword, and for indentation
+" (this needs to take precedence over normal commas and colons, and comments)
+syntax cluster juliaContinuationItems contains=juliaContinuationComma,juliaContinuationColon,juliaContinuationNone
+exec 'syntax region juliaContinuationComma matchgroup=juliaComma contained start=",\ze'.s:eol.'" end="\n\+\ze." contains=@juliaCommentItems'
+exec 'syntax region juliaContinuationColon matchgroup=juliaColon contained start=":\ze'.s:eol.'" end="\n\+\ze." contains=@juliaCommentItems'
+exec 'syntax region juliaContinuationNone matchgroup=NONE contained start="\%(\<\%(import\|using\|export\)\>\|^\)\@'.s:d(6).'<=\ze'.s:eol.'" end="\n\+\ze." contains=@juliaCommentItems,juliaAsKeyword'
+exec 'syntax match juliaMacroName contained "@' . s:idregex . '\%(\.' . s:idregex . '\)*"'
+
+" the following are disabled by default, but
+" can be enabled by entering e.g.
+" :hi link juliaParDelim Delimiter
+hi def link juliaParDelim juliaNone
+hi def link juliaSemicolon juliaNone
+hi def link juliaComma juliaNone
+hi def link juliaFunctionCall juliaNone
+
+hi def link juliaColon juliaOperator
+
+hi def link juliaFunctionName juliaFunction
+hi def link juliaFunctionName1 juliaFunction
+hi def link juliaMacroName juliaMacro
+
+
+hi def link juliaKeyword Keyword
+hi def link juliaWhereKeyword Keyword
+hi def link juliaInfixKeyword Keyword
+hi def link juliaIsaKeyword Keyword
+hi def link juliaAsKeyword Keyword
+hi def link juliaRepKeyword Keyword
+hi def link juliaBlKeyword Keyword
+hi def link juliaConditional Conditional
+hi def link juliaRepeat Repeat
+hi def link juliaException Exception
+hi def link juliaOuter Keyword
+hi def link juliaBaseTypeBasic Type
+hi def link juliaBaseTypeNum Type
+hi def link juliaBaseTypeC Type
+hi def link juliaBaseTypeError Type
+hi def link juliaBaseTypeIter Type
+hi def link juliaBaseTypeString Type
+hi def link juliaBaseTypeArray Type
+hi def link juliaBaseTypeDict Type
+hi def link juliaBaseTypeSet Type
+hi def link juliaBaseTypeIO Type
+hi def link juliaBaseTypeProcess Type
+hi def link juliaBaseTypeRange Type
+hi def link juliaBaseTypeRegex Type
+hi def link juliaBaseTypeFact Type
+hi def link juliaBaseTypeSort Type
+hi def link juliaBaseTypeRound Type
+hi def link juliaBaseTypeSpecial Type
+hi def link juliaBaseTypeRandom Type
+hi def link juliaBaseTypeDisplay Type
+hi def link juliaBaseTypeTime Type
+hi def link juliaBaseTypeOther Type
+
+hi def link juliaType Type
+hi def link juliaParamType Type
+hi def link juliaTypeOperatorR1 Type
+
+" NOTE: deprecated constants are not highlighted as such. For once,
+" one can still legitimately use them by importing Base.MathConstants.
+" Plus, one-letter variables like `e` and `γ` can be used with other
+" meanings.
+hi def link juliaConstNum Constant
+hi def link juliaEuler Constant
+
+hi def link juliaConstEnv Constant
+hi def link juliaConstC Constant
+hi def link juliaConstLimits Constant
+hi def link juliaConstGeneric Constant
+hi def link juliaRangeKeyword Constant
+hi def link juliaConstBool Boolean
+hi def link juliaConstIO Boolean
+
+hi def link juliaComprehensionFor Keyword
+hi def link juliaComprehensionIf Keyword
+
+hi def link juliaDollarVar Identifier
+
+hi def link juliaFunction Function
+hi def link juliaMacro Macro
+hi def link juliaSymbol Identifier
+hi def link juliaSymbolS Identifier
+hi def link juliaQParDelim Identifier
+hi def link juliaQuotedQMarkPar Identifier
+hi def link juliaQuotedQMark juliaOperatorHL
+
+hi def link juliaNumber Number
+hi def link juliaFloat Float
+hi def link juliaComplexUnit Constant
+
+hi def link juliaChar Character
+
+hi def link juliaString String
+hi def link juliaStringPrefixed juliaString
+hi def link juliabString juliaString
+hi def link juliasString juliaString
+hi def link juliavString juliaString
+hi def link juliarString juliaString
+hi def link juliaipString juliaString
+hi def link juliabigString juliaString
+hi def link juliaMIMEString juliaString
+hi def link juliarawString juliaString
+hi def link juliatestString juliaString
+hi def link juliahtmlString juliaString
+hi def link juliaint128String juliaString
+hi def link juliaPrintfString juliaString
+hi def link juliaShellString juliaString
+hi def link juliaDocString juliaString
+hi def link juliaDocStringM juliaDocString
+hi def link juliaDocStringMRaw juliaDocString
+hi def link juliaStringDelim juliaString
+hi def link juliaDocStringDelim juliaDocString
+hi def link juliaStringVarsPla Identifier
+hi def link juliaStringVarDelim Identifier
+
+hi def link juliaRegEx String
+
+hi def link juliaSpecialChar SpecialChar
+hi def link juliaOctalEscapeChar SpecialChar
+hi def link juliaHexEscapeChar SpecialChar
+hi def link juliaUniCharSmall SpecialChar
+hi def link juliaUniCharLarge SpecialChar
+hi def link juliaDoubleBackslash SpecialChar
+hi def link juliaEscapedQuote SpecialChar
+
+hi def link juliaPrintfFmt SpecialChar
+
+if s:julia_highlight_operators
+ hi! def link juliaOperatorHL Operator
+else
+ hi! def link juliaOperatorHL juliaNone
+endif
+hi def link juliaOperator juliaOperatorHL
+hi def link juliaRangeOperator juliaOperatorHL
+hi def link juliaCTransOperator juliaOperatorHL
+hi def link juliaTernaryOperator juliaOperatorHL
+hi def link juliaTypeOperator juliaOperatorHL
+
+hi def link juliaCommentL Comment
+hi def link juliaCommentM Comment
+hi def link juliaCommentDelim Comment
+hi def link juliaTodo Todo
+
+hi def link juliaErrorPar juliaError
+hi def link juliaErrorEnd juliaError
+hi def link juliaErrorElse juliaError
+hi def link juliaErrorCatch juliaError
+hi def link juliaErrorFinally juliaError
+hi def link juliaErrorSemicol juliaError
+hi def link juliaErrorPrintfFmt juliaError
+
+hi def link juliaError Error
+
+syntax sync fromstart
+
+let b:current_syntax = "julia"
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
diff --git a/runtime/syntax/man.vim b/runtime/syntax/man.vim
index a01bd1c0e7..55b0e16de9 100644
--- a/runtime/syntax/man.vim
+++ b/runtime/syntax/man.vim
@@ -6,7 +6,7 @@ if exists('b:current_syntax')
endif
syntax case ignore
-syntax match manReference display '[^()[:space:]]\+([0-9nx][a-z]*)'
+syntax match manReference display '[^()[:space:]]\+(\%([0-9][a-z]*\|[nlpox]\))'
syntax match manSectionHeading display '^\S.*$'
syntax match manHeader display '^\%1l.*$'
syntax match manSubHeading display '^ \{3\}\S.*$'
@@ -27,11 +27,7 @@ if &filetype != 'man'
finish
endif
-if !exists('b:man_sect')
- call man#init_pager()
-endif
-
-if b:man_sect =~# '^[023]'
+if get(b:, 'man_sect', '') =~# '^[023]'
syntax case match
syntax include @c $VIMRUNTIME/syntax/c.vim
syntax match manCFuncDefinition display '\<\h\w*\>\ze\(\s\|\n\)*(' contained
diff --git a/runtime/syntax/mma.vim b/runtime/syntax/mma.vim
index 0683adc573..d2f22e9be5 100644
--- a/runtime/syntax/mma.vim
+++ b/runtime/syntax/mma.vim
@@ -12,7 +12,7 @@
"
" let filetype_m="mma"
"
-" I also recommend setting the default 'Comment' hilighting to something
+" I also recommend setting the default 'Comment' highlighting to something
" other than the color used for 'Function', since both are plentiful in
" most mathematica files, and they are often the same color (when using
" background=dark).
@@ -109,7 +109,7 @@ syntax match mmaemPHAsis "\%(^\|\s\)(\@<!\*[a-zA-Z0-9]\+\%([- \t':]\+[a-zA-Z0-9]
syntax region mmaComment start=+(\*+ end=+\*)+ skipempty contains=@mmaNotes,mmaItem,@mmaCommentStrings,mmaemPHAsis,mmaComment
" Function Comments:
-" just like a normal comment except the first sentance is Special ala Java
+" just like a normal comment except the first sentence is Special ala Java
" (** *)
" TODO - fix this for nesting, or not...
syntax region mmaFunctionComment start="(\*\*\+" end="\*\+)" contains=@mmaNotes,mmaItem,mmaFunctionTitle,@mmaCommentStrings,mmaemPHAsis,mmaComment
diff --git a/runtime/syntax/objc.vim b/runtime/syntax/objc.vim
index b29313a3cf..7c6e2d5128 100644
--- a/runtime/syntax/objc.vim
+++ b/runtime/syntax/objc.vim
@@ -64,7 +64,7 @@ syn keyword objcStorageClass nullable nonnull null_unspecified
" ObjC type specifier
syn keyword objcTypeSpecifier __kindof __covariant
-" ObjC Type Infomation Parameters
+" ObjC Type Information Parameters
syn keyword objcTypeInfoParams ObjectType KeyType
" shorthand
diff --git a/runtime/syntax/pascal.vim b/runtime/syntax/pascal.vim
index 3ab5c2e661..206df213a6 100644
--- a/runtime/syntax/pascal.vim
+++ b/runtime/syntax/pascal.vim
@@ -3,7 +3,7 @@
" Maintainer: Doug Kearns <dougkearns@gmail.com>
" Previous Maintainers: Xavier Crégut <xavier.cregut@enseeiht.fr>
" Mario Eusebio <bio@dq.fct.unl.pt>
-" Last Change: 2021 Apr 23
+" Last Change: 2021 May 20
" Contributors: Tim Chase <tchase@csc.com>,
" Stas Grabois <stsi@vtrails.com>,
diff --git a/runtime/syntax/php.vim b/runtime/syntax/php.vim
index 7b0085cd6e..80662d6750 100644
--- a/runtime/syntax/php.vim
+++ b/runtime/syntax/php.vim
@@ -1,7 +1,7 @@
" Vim syntax file
" Language: php PHP 3/4/5/7/8
" Maintainer: Tyson Andre <tysonandre775@hotmail.com>
-" Last Change: Dec 22, 2020
+" Last Change: Sep 18, 2021
" URL: https://github.com/TysonAndre/php-vim-syntax
" Former Maintainers:
" Jason Woofenden <jason@jasonwoof.com>
@@ -13,10 +13,32 @@
" than the default colourscheme, because elflord's colours will better
" highlight the break-points (Statements) in your code.
"
+" Note: This embeds a modified copy of the html.vim with (mostly) different symbols,
+" in order to implement php_htmlInStrings=2 can work as expected and correctly parse
+" `<?php $phpStartTag = '<?php';`.
+"
+" Credits for the original version of html.vim prior to modifications
+"
+" Previous Maintainer Jorge Maldonado Ventura <jorgesumle@freakspot.net>
+" Previous Maintainer Claudio Fleiner <claudio@fleiner.com>
+" Repository https://notabug.org/jorgesumle/vim-html-syntax
+" Last Change 2021 Mar 02
+" Included patch #7900 to fix comments
+" Included patch #7916 to fix a few more things
+"
" Options:
" Set to anything to enable:
" php_sql_query SQL syntax highlighting inside strings
" php_htmlInStrings HTML syntax highlighting inside strings
+"
+" By setting this to 2, this will use a local copy of
+" HTML syntax highlighting instead of the official
+" HTML syntax highlighting, and properly highlight
+" `<?php $startTag = '<?php';`.
+" This may become the new default in the future.
+"
+" By setting this to 3 (or any unrecognized value),
+" this will use the official installed top level html syntax highlighting rules.
" php_baselib highlighting baselib functions
" php_asp_tags highlighting ASP-style short tags
" php_parent_error_close highlighting parent error ] or )
@@ -62,6 +84,214 @@ if !exists("main_syntax")
let main_syntax = 'php'
endif
+" Start of copy of html for embedding in strings with {{{
+" This is a clone of https://notabug.org/jorgesumle/vim-html-syntax
+" from 2021 Mar 02 with changed symbols and modifications to rules. See the Note in the file header.
+"
+" The default behavior of php_htmlInStrings causes a bug
+" when you're working with code that contains the string literal `'<?php'`.
+" E.g. code that reads php files or generates the contents of php files or
+" generates snippets to `eval()`.
+"
+" When php_htmlInStrings was set to any value,
+" it would cause the html syntax rules to be embedded inside of the string
+" contents.
+"
+" However, php.vim extends html.vim by allowing the php start tag to be
+" included, meaning that this is parsed as `<?php';`, i.e. the start of a
+" new string literal.
+"
+" Work around that by using a different set of rules that don't allow
+" embedding php in most places (phpInnerHtmlPreProc).
+"
+" The default behavior may be changed to this in the future for constants other
+" than 2 or 3 if there are no issues.
+"
+" Many, but not all syntax rules were changed from html* to phpInnerHtml*
+if exists("php_htmlInStrings") && php_htmlInStrings==2
+ " mark illegal characters
+ syn match phpInnerHtmlError contained "[<>&]"
+
+ " tags
+ syn region phpInnerHtmlString contained start=+"+ end=+"+ contains=phpInnerHtmlSpecialChar,javaScriptExpression,@phpInnerHtmlPreproc
+ syn region phpInnerHtmlString contained start=+'+ end=+'+ contains=phpInnerHtmlSpecialChar,javaScriptExpression,@phpInnerHtmlPreproc
+ syn match phpInnerHtmlValue contained "=[\t ]*[^'" \t>][^ \t>]*"hs=s+1 contains=javaScriptExpression,@phpInnerHtmlPreproc
+ syn region phpInnerHtmlEndTag contained start=+</+ end=+>+ contains=phpInnerHtmlTagN,phpInnerHtmlTagError
+ syn region phpInnerHtmlTag contained start=+<[^/]+ end=+>+ fold contains=phpInnerHtmlTagN,phpInnerHtmlString,htmlArg,phpInnerHtmlValue,phpInnerHtmlTagError,phpInnerHtmlEvent,phpInnerHtmlCssDefinition,@phpInnerHtmlPreproc,@phpInnerHtmlArgCluster
+ syn match phpInnerHtmlTagN contained +<\s*[-a-zA-Z0-9]\++hs=s+1 contains=htmlTagName,htmlSpecialTagName,@phpInnerHtmlTagNameCluster
+ syn match phpInnerHtmlTagN contained +</\s*[-a-zA-Z0-9]\++hs=s+2 contains=htmlTagName,htmlSpecialTagName,@phpInnerHtmlTagNameCluster
+ syn match phpInnerHtmlTagError contained "[^>]<"ms=s+1
+
+
+ " special characters
+ syn match phpInnerHtmlSpecialChar "&#\=[0-9A-Za-z]\{1,8};"
+
+ " Comments (the real ones or the old netscape ones)
+ if exists("html_wrong_comments")
+ syn region phpInnerHtmlComment start=+<!--+ end=+--\s*>+ contains=@Spell
+ else
+ " The HTML 5.2 syntax 8.2.4.41: bogus comment is parser error; browser skips until next &gt
+ syn region phpInnerHtmlComment start=+<!+ end=+>+ contains=phpInnerHtmlCommentError keepend
+ " Idem 8.2.4.42,51: Comment starts with <!-- and ends with -->
+ " Idem 8.2.4.43,44: Except <!--> and <!---> are parser errors
+ " Idem 8.2.4.52: dash-dash-bang (--!>) is error ignored by parser, also closes comment
+ syn region phpInnerHtmlComment matchgroup=phpInnerHtmlComment start=+<!--\%(-\?>\)\@!+ end=+--!\?>+ contains=phpInnerHtmlCommentNested,@phpInnerHtmlPreProc,@Spell keepend
+ " Idem 8.2.4.49: nested comment is parser error, except <!--> is all right
+ syn match phpInnerHtmlCommentNested contained "<!-->\@!"
+ syn match phpInnerHtmlCommentError contained "[^><!]"
+ endif
+ syn region phpInnerHtmlComment start=+<!DOCTYPE+ end=+>+ keepend
+
+ " server-parsed commands
+ syn region phpInnerHtmlPreProc start=+<!--#+ end=+-->+ contains=phpInnerHtmlPreStmt,phpInnerHtmlPreError,phpInnerHtmlPreAttr
+ syn match phpInnerHtmlPreStmt contained "<!--#\(config\|echo\|exec\|fsize\|flastmod\|include\|printenv\|set\|if\|elif\|else\|endif\|geoguide\)\>"
+ syn match phpInnerHtmlPreError contained "<!--#\S*"ms=s+4
+ syn match phpInnerHtmlPreAttr contained "\w\+=[^"]\S\+" contains=phpInnerHtmlPreProcAttrError,phpInnerHtmlPreProcAttrName
+ syn region phpInnerHtmlPreAttr contained start=+\w\+="+ skip=+\\\\\|\\"+ end=+"+ contains=phpInnerHtmlPreProcAttrName keepend
+ syn match phpInnerHtmlPreProcAttrError contained "\w\+="he=e-1
+ syn match phpInnerHtmlPreProcAttrName contained "\(expr\|errmsg\|sizefmt\|timefmt\|var\|cgi\|cmd\|file\|virtual\|value\)="he=e-1
+
+ if !exists("html_no_rendering")
+ " rendering
+ syn cluster phpInnerHtmlTop contains=@Spell,phpInnerHtmlTag,phpInnerHtmlEndTag,phpInnerHtmlSpecialChar,phpInnerHtmlPreProc,phpInnerHtmlComment,phpInnerHtmlLink,javaScript,@phpInnerHtmlPreproc
+
+ syn region phpInnerHtmlStrike start="<del\>" end="</del\_s*>"me=s-1 contains=@phpInnerHtmlTop
+ syn region phpInnerHtmlStrike start="<strike\>" end="</strike\_s*>"me=s-1 contains=@phpInnerHtmlTop
+
+ syn region phpInnerHtmlBold start="<b\>" end="</b\_s*>"me=s-1 contains=@phpInnerHtmlTop,phpInnerHtmlBoldUnderline,phpInnerHtmlBoldItalic
+ syn region phpInnerHtmlBold start="<strong\>" end="</strong\_s*>"me=s-1 contains=@phpInnerHtmlTop,phpInnerHtmlBoldUnderline,phpInnerHtmlBoldItalic
+ syn region phpInnerHtmlBoldUnderline contained start="<u\>" end="</u\_s*>"me=s-1 contains=@phpInnerHtmlTop,phpInnerHtmlBoldUnderlineItalic
+ syn region phpInnerHtmlBoldItalic contained start="<i\>" end="</i\_s*>"me=s-1 contains=@phpInnerHtmlTop,phpInnerHtmlBoldItalicUnderline
+ syn region phpInnerHtmlBoldItalic contained start="<em\>" end="</em\_s*>"me=s-1 contains=@phpInnerHtmlTop,phpInnerHtmlBoldItalicUnderline
+ syn region phpInnerHtmlBoldUnderlineItalic contained start="<i\>" end="</i\_s*>"me=s-1 contains=@phpInnerHtmlTop
+ syn region phpInnerHtmlBoldUnderlineItalic contained start="<em\>" end="</em\_s*>"me=s-1 contains=@phpInnerHtmlTop
+ syn region phpInnerHtmlBoldItalicUnderline contained start="<u\>" end="</u\_s*>"me=s-1 contains=@phpInnerHtmlTop,phpInnerHtmlBoldUnderlineItalic
+
+ syn region phpInnerHtmlUnderline start="<u\>" end="</u\_s*>"me=s-1 contains=@phpInnerHtmlTop,phpInnerHtmlUnderlineBold,phpInnerHtmlUnderlineItalic
+ syn region phpInnerHtmlUnderlineBold contained start="<b\>" end="</b\_s*>"me=s-1 contains=@phpInnerHtmlTop,phpInnerHtmlUnderlineBoldItalic
+ syn region phpInnerHtmlUnderlineBold contained start="<strong\>" end="</strong\_s*>"me=s-1 contains=@phpInnerHtmlTop,phpInnerHtmlUnderlineBoldItalic
+ syn region phpInnerHtmlUnderlineItalic contained start="<i\>" end="</i\_s*>"me=s-1 contains=@phpInnerHtmlTop,phpInnerHtmlUnderlineItalicBold
+ syn region phpInnerHtmlUnderlineItalic contained start="<em\>" end="</em\_s*>"me=s-1 contains=@phpInnerHtmlTop,phpInnerHtmlUnderlineItalicBold
+ syn region phpInnerHtmlUnderlineItalicBold contained start="<b\>" end="</b\_s*>"me=s-1 contains=@phpInnerHtmlTop
+ syn region phpInnerHtmlUnderlineItalicBold contained start="<strong\>" end="</strong\_s*>"me=s-1 contains=@phpInnerHtmlTop
+ syn region phpInnerHtmlUnderlineBoldItalic contained start="<i\>" end="</i\_s*>"me=s-1 contains=@phpInnerHtmlTop
+ syn region phpInnerHtmlUnderlineBoldItalic contained start="<em\>" end="</em\_s*>"me=s-1 contains=@phpInnerHtmlTop
+
+ syn region phpInnerHtmlItalic start="<i\>" end="</i\_s*>"me=s-1 contains=@phpInnerHtmlTop,phpInnerHtmlItalicBold,phpInnerHtmlItalicUnderline
+ syn region phpInnerHtmlItalic start="<em\>" end="</em\_s*>"me=s-1 contains=@phpInnerHtmlTop
+ syn region phpInnerHtmlItalicBold contained start="<b\>" end="</b\_s*>"me=s-1 contains=@phpInnerHtmlTop,phpInnerHtmlItalicBoldUnderline
+ syn region phpInnerHtmlItalicBold contained start="<strong\>" end="</strong\_s*>"me=s-1 contains=@phpInnerHtmlTop,phpInnerHtmlItalicBoldUnderline
+ syn region phpInnerHtmlItalicBoldUnderline contained start="<u\>" end="</u\_s*>"me=s-1 contains=@phpInnerHtmlTop
+ syn region phpInnerHtmlItalicUnderline contained start="<u\>" end="</u\_s*>"me=s-1 contains=@phpInnerHtmlTop,phpInnerHtmlItalicUnderlineBold
+ syn region phpInnerHtmlItalicUnderlineBold contained start="<b\>" end="</b\_s*>"me=s-1 contains=@phpInnerHtmlTop
+ syn region phpInnerHtmlItalicUnderlineBold contained start="<strong\>" end="</strong\_s*>"me=s-1 contains=@phpInnerHtmlTop
+
+ syn match phpInnerHtmlLeadingSpace "^\s\+" contained
+ syn region phpInnerHtmlLink start="<a\>\_[^>]*\<href\>" end="</a\_s*>"me=s-1 contains=@Spell,phpInnerHtmlTag,phpInnerHtmlEndTag,phpInnerHtmlSpecialChar,phpInnerHtmlPreProc,phpInnerHtmlComment,phpInnerHtmlLeadingSpace,phpInnerJavaScript,@phpInnerHtmlPreproc
+ syn region phpInnerHtmlH1 start="<h1\>" end="</h1\_s*>"me=s-1 contains=@phpInnerHtmlTop
+ syn region phpInnerHtmlH2 start="<h2\>" end="</h2\_s*>"me=s-1 contains=@phpInnerHtmlTop
+ syn region phpInnerHtmlH3 start="<h3\>" end="</h3\_s*>"me=s-1 contains=@phpInnerHtmlTop
+ syn region phpInnerHtmlH4 start="<h4\>" end="</h4\_s*>"me=s-1 contains=@phpInnerHtmlTop
+ syn region phpInnerHtmlH5 start="<h5\>" end="</h5\_s*>"me=s-1 contains=@phpInnerHtmlTop
+ syn region phpInnerHtmlH6 start="<h6\>" end="</h6\_s*>"me=s-1 contains=@phpInnerHtmlTop
+ syn region phpInnerHtmlHead start="<head\>" end="</head\_s*>"me=s-1 end="<body\>"me=s-1 end="<h[1-6]\>"me=s-1 contains=phpInnerHtmlTag,phpInnerHtmlEndTag,phpInnerHtmlSpecialChar,phpInnerHtmlPreProc,phpInnerHtmlComment,phpInnerHtmlLink,phpInnerHtmlTitle,phpInnerJavaScript,phpInnerCssStyle,@phpInnerHtmlPreproc
+ syn region phpInnerHtmlTitle start="<title\>" end="</title\_s*>"me=s-1 contains=phpInnerHtmlTag,phpInnerHtmlEndTag,phpInnerHtmlSpecialChar,phpInnerHtmlPreProc,phpInnerHtmlComment,phpInnerJavaScript,@phpInnerHtmlPreproc
+ endif
+
+ if main_syntax != 'java' || exists("javascript")
+ " JAVA SCRIPT
+ " For example, $phpVar = '<img onload="foo()" />';
+ syn include @phpInnerHtmlJavaScript syntax/javascript.vim
+ unlet b:current_syntax
+ syn region phpInnerHtmlScriptTag contained start=+<script+ end=+>+ fold contains=phpInnerHtmlTagN,phpInnerHtmlString,phpInnerHtmlArg,phpInnerHtmlValue,phpInnerHtmlTagError,phpInnerHtmlEvent
+ hi def link phpInnerHtmlScriptTag phpInnerHtmlTag
+
+ " phpInnerHtml events (i.e. arguments that include phpInnerJavascript commands)
+ if exists("html_extended_events")
+ syn region phpInnerHtmlEvent contained start=+\<on\a\+\s*=[\t ]*'+ end=+'+ contains=phpInnerHtmlEventSQ
+ syn region phpInnerHtmlEvent contained start=+\<on\a\+\s*=[\t ]*"+ end=+"+ contains=phpInnerHtmlEventDQ
+ else
+ syn region phpInnerHtmlEvent contained start=+\<on\a\+\s*=[\t ]*'+ end=+'+ keepend contains=phpInnerHtmlEventSQ
+ syn region phpInnerHtmlEvent contained start=+\<on\a\+\s*=[\t ]*"+ end=+"+ keepend contains=phpInnerHtmlEventDQ
+ endif
+ syn region phpInnerHtmlEventSQ contained start=+'+ms=s+1 end=+'+me=s-1 contains=@phpInnerHtmlJavaScript
+ syn region phpInnerHtmlEventDQ contained start=+"+ms=s+1 end=+"+me=s-1 contains=@phpInnerHtmlJavaScript
+ hi def link phpInnerHtmlEventSQ phpInnerHtmlEvent
+ hi def link phpInnerHtmlEventDQ phpInnerHtmlEvent
+
+ " a phpInnerJavascript expression is used as an arg value
+ " syn region phpInnerJavaScriptExpression contained start=+&{+ keepend end=+};+ contains=@phpInnerHtmlJavaScript,@phpInnerHtmlPreproc
+ endif
+
+ syn cluster phpInnerHtmlJavaScript add=@phpInnerHtmlPreproc
+
+ " The default highlighting.
+ " NOTE: For now, this deliberately copies the definitions from html rather than link
+ " to the corresponding html tag name. If html is refactored to rename any
+ " keywords then html highlighting would unexpectedly be cleared.
+ hi def link phpInnerHtmlTag Function
+ hi def link phpInnerHtmlEndTag Identifier
+ hi def link phpInnerHtmlArg Type
+ hi def link phpInnerHtmlValue String
+ hi def link phpInnerHtmlSpecialChar Special
+
+ if !exists("html_no_rendering")
+ hi def link phpInnerHtmlH1 Title
+ hi def link phpInnerHtmlH2 phpInnerHtmlH1
+ hi def link phpInnerHtmlH3 phpInnerHtmlH2
+ hi def link phpInnerHtmlH4 phpInnerHtmlH3
+ hi def link phpInnerHtmlH5 phpInnerHtmlH4
+ hi def link phpInnerHtmlH6 phpInnerHtmlH5
+ hi def link phpInnerHtmlHead PreProc
+ hi def link phpInnerHtmlTitle Title
+ hi def link phpInnerHtmlBoldItalicUnderline phpInnerHtmlBoldUnderlineItalic
+ hi def link phpInnerHtmlUnderlineBold phpInnerHtmlBoldUnderline
+ hi def link phpInnerHtmlUnderlineItalicBold phpInnerHtmlBoldUnderlineItalic
+ hi def link phpInnerHtmlUnderlineBoldItalic phpInnerHtmlBoldUnderlineItalic
+ hi def link phpInnerHtmlItalicUnderline phpInnerHtmlUnderlineItalic
+ hi def link phpInnerHtmlItalicBold phpInnerHtmlBoldItalic
+ hi def link phpInnerHtmlItalicBoldUnderline phpInnerHtmlBoldUnderlineItalic
+ hi def link phpInnerHtmlItalicUnderlineBold phpInnerHtmlBoldUnderlineItalic
+ hi def link phpInnerHtmlLink Underlined
+ hi def link phpInnerHtmlLeadingSpace None
+ if !exists("html_my_rendering")
+ hi def phpInnerHtmlBold term=bold cterm=bold gui=bold
+ hi def phpInnerHtmlBoldUnderline term=bold,underline cterm=bold,underline gui=bold,underline
+ hi def phpInnerHtmlBoldItalic term=bold,italic cterm=bold,italic gui=bold,italic
+ hi def phpInnerHtmlBoldUnderlineItalic term=bold,italic,underline cterm=bold,italic,underline gui=bold,italic,underline
+ hi def phpInnerHtmlUnderline term=underline cterm=underline gui=underline
+ hi def phpInnerHtmlUnderlineItalic term=italic,underline cterm=italic,underline gui=italic,underline
+ hi def phpInnerHtmlItalic term=italic cterm=italic gui=italic
+ if v:version > 800 || v:version == 800 && has("patch1038")
+ hi def phpInnerHtmlStrike term=strikethrough cterm=strikethrough gui=strikethrough
+ else
+ hi def phpInnerHtmlStrike term=underline cterm=underline gui=underline
+ endif
+ endif
+ endif
+
+ hi def link phpInnerHtmlPreStmt PreProc
+ hi def link phpInnerHtmlPreError Error
+ hi def link phpInnerHtmlPreProc PreProc
+ hi def link phpInnerHtmlPreAttr String
+ hi def link phpInnerHtmlPreProcAttrName PreProc
+ hi def link phpInnerHtmlPreProcAttrError Error
+ hi def link phpInnerHtmlString String
+ hi def link phpInnerHtmlStatement Statement
+ hi def link phpInnerHtmlComment Comment
+ hi def link phpInnerHtmlCommentNested phpInnerHtmlError
+ hi def link phpInnerHtmlCommentError phpInnerHtmlError
+ hi def link phpInnerHtmlTagError phpInnerHtmlError
+ hi def link phpInnerHtmlEvent phpInnerJavaScript
+ hi def link phpInnerHtmlError Error
+
+ hi def link phpInnerJavaScript Special
+ hi def link phpInnerJavaScriptExpression phpInnerJavaScript
+ hi def link phpInnerHtmlCssStyleComment Comment
+ hi def link phpInnerHtmlCssDefinition Special
+endif
+
+
runtime! syntax/html.vim
unlet b:current_syntax
@@ -79,6 +309,8 @@ if exists("php_parentError") && !exists("php_parent_error_open") && !exists("php
let php_parent_error_open=1
endif
+" End of copy of html syntax for embedding in php strings }}}
+
syn cluster htmlPreproc add=phpRegion,phpRegionAsp,phpRegionSc
syn include @sqlTop syntax/sql.vim
@@ -90,7 +322,11 @@ if exists( "php_sql_query")
endif
if exists( "php_htmlInStrings")
- syn cluster phpAddStrings add=@htmlTop
+ if php_htmlInStrings==2
+ syn cluster phpAddStrings add=@phpInnerHtmlTop
+ else
+ syn cluster phpAddStrings add=@htmlTop
+ endif
endif
" make sure we can use \ at the beginning of the line to do a continuation
@@ -283,7 +519,7 @@ syn keyword phpStatement return break continue exit goto yield contained
syn keyword phpKeyword var const contained
" Type
-syn keyword phpType void bool boolean int integer real double float string array object NULL callable iterable mixed contained
+syn keyword phpType void bool boolean int integer real double float string array object NULL callable iterable mixed never contained
" Structure
syn keyword phpStructure namespace extends implements instanceof parent self contained
@@ -361,7 +597,7 @@ syn match phpFloatError "\%([eE.][0-9._+-]*\.\|__\|_\(\>\|[eE]\)\|\(\>\|[eE]\)_\
" Number
syn match phpNumber "\%(\.\)\@<!\<\%([1-9]\d*\|0\|0[xX]\(\x_\?\)*\x\)\>\%(\.\)\@!" contained display
-syn match phpNumber "\%(\.\)\@<!\<0\d\+\>\%(\.\)\@!" contained contains=phpOctalError display
+syn match phpNumber "\%(\.\)\@<!\<0\d\+\|0[oO]\d\+\>\%(\.\)\@!" contained contains=phpOctalError display
syn match phpBinaryError "[2-9]" contained display
syn match phpNumber "\%(\.\)\@<!\<0[bB]\(\d_\?\)*\d\>\%(\.\)\@!" contained contains=phpBinaryError display
@@ -446,7 +682,7 @@ syn cluster phpClTop contains=@phpClFunction,phpFoldFunction,phpFoldClass,phpFol
" Php Region
if exists("php_parent_error_open")
if exists("php_noShortTags")
- syn region phpRegion matchgroup=Delimiter start="<?php" end="?>" contains=@phpClTop
+ syn region phpRegion matchgroup=Delimiter start="<?\(php\|=\)" end="?>" contains=@phpClTop
else
syn region phpRegion matchgroup=Delimiter start="<?\(php\)\=" end="?>" contains=@phpClTop
endif
@@ -456,7 +692,7 @@ if exists("php_parent_error_open")
endif
else
if exists("php_noShortTags")
- syn region phpRegion matchgroup=Delimiter start="<?php" end="?>" contains=@phpClTop keepend
+ syn region phpRegion matchgroup=Delimiter start="<?\(php\|=\)" end="?>" contains=@phpClTop keepend
else
syn region phpRegion matchgroup=Delimiter start="<?\(php\)\=" end="?>" contains=@phpClTop keepend
endif
@@ -469,13 +705,13 @@ endif
" Fold
if exists("php_folding") && php_folding==1
" match one line constructs here and skip them at folding
- syn keyword phpSCKeyword abstract final private protected public static contained
+ syn keyword phpSCKeyword abstract final private protected public static readonly contained
syn keyword phpFCKeyword function contained
syn keyword phpDefine fn contained
syn keyword phpStorageClass global contained
syn match phpDefine "\(\s\|^\)\(abstract\s\+\|final\s\+\|private\s\+\|protected\s\+\|public\s\+\|static\s\+\)*function\(\s\+.*[;}]\)\@=" contained contains=phpSCKeyword
syn match phpStructure "\(\s\|^\)\(abstract\s\+\|final\s\+\)*\(trait\|class\)\(\s\+.*}\)\@=" contained
- syn match phpStructure "\(\s\|^\)interface\(\s\+.*}\)\@=" contained
+ syn match phpStructure "\(\s\|^\)\(interface\|enum\)\(\s\+.*}\)\@=" contained
syn match phpException "\(\s\|^\)try\(\s\+.*}\)\@=" contained
syn match phpException "\(\s\|^\)catch\(\s\+.*}\)\@=" contained
syn match phpException "\(\s\|^\)finally\(\s\+.*}\)\@=" contained
@@ -484,15 +720,15 @@ if exists("php_folding") && php_folding==1
syn region phpFoldHtmlInside matchgroup=Delimiter start="?>" end="<?\(php\)\=" contained transparent contains=@htmlTop
syn region phpFoldFunction matchgroup=Storageclass start="^\z(\s*\)\(abstract\s\+\|final\s\+\|private\s\+\|protected\s\+\|public\s\+\|static\s\+\)*function\s\([^};]*$\)\@="rs=e-9 matchgroup=Delimiter end="^\z1}" contains=@phpClFunction,phpFoldHtmlInside,phpFCKeyword contained transparent fold extend
syn region phpFoldFunction matchgroup=Define start="^function\s\([^};]*$\)\@=" matchgroup=Delimiter end="^}" contains=@phpClFunction,phpFoldHtmlInside contained transparent fold extend
- syn region phpFoldClass matchgroup=Structure start="^\z(\s*\)\(abstract\s\+\|final\s\+\)*\(trait\|class\)\s\+\([^}]*$\)\@=" matchgroup=Delimiter end="^\z1}" contains=@phpClFunction,phpFoldFunction,phpSCKeyword contained transparent fold extend
+ syn region phpFoldClass matchgroup=Structure start="^\z(\s*\)\(abstract\s\+\|final\s\+\)*\(trait\|class\|enum\)\s\+\([^}]*$\)\@=" matchgroup=Delimiter end="^\z1}" contains=@phpClFunction,phpFoldFunction,phpSCKeyword contained transparent fold extend
syn region phpFoldInterface matchgroup=Structure start="^\z(\s*\)interface\s\+\([^}]*$\)\@=" matchgroup=Delimiter end="^\z1}" contains=@phpClFunction,phpFoldFunction contained transparent fold extend
syn region phpFoldCatch matchgroup=Exception start="^\z(\s*\)catch\s\+\([^}]*$\)\@=" matchgroup=Delimiter end="^\z1}" contains=@phpClFunction,phpFoldFunction contained transparent fold extend
syn region phpFoldTry matchgroup=Exception start="^\z(\s*\)try\s\+\([^}]*$\)\@=" matchgroup=Delimiter end="^\z1}" contains=@phpClFunction,phpFoldFunction contained transparent fold extend
else
syn keyword phpDefine function fn contained
- syn keyword phpStructure abstract class trait interface contained
+ syn keyword phpStructure abstract class trait interface enum contained
syn keyword phpException catch throw try finally contained
- syn keyword phpStorageClass final global private protected public static contained
+ syn keyword phpStorageClass final global private protected public static readonly contained
if exists("php_folding") && php_folding==2
setlocal foldmethod=syntax
syn region phpFoldHtmlInside matchgroup=Delimiter start="?>" end="<?\(php\)\=" contained transparent contains=@htmlTop
@@ -512,9 +748,9 @@ syntax keyword phpStructure list contained
syntax keyword phpConditional switch contained
syntax keyword phpStatement die contained
-" Highlighting for PHP5's user-definable magic class methods
+" Highlighting for PHP's user-definable magic class methods
syntax keyword phpSpecialFunction containedin=ALLBUT,phpComment,phpStringDouble,phpStringSingle,phpIdentifier
- \ __construct __destruct __call __callStatic __get __set __isset __unset __sleep __wakeup __toString __invoke __set_state __clone __debugInfo
+ \ __construct __destruct __call __callStatic __get __set __isset __unset __sleep __wakeup __toString __invoke __set_state __clone __debugInfo __serialize __unserialize
" Highlighting for __autoload slightly different from line above
syntax keyword phpSpecialFunction containedin=ALLBUT,phpComment,phpStringDouble,phpStringSingle,phpIdentifier,phpMethodsVar
\ __autoload
@@ -638,7 +874,7 @@ endif
" Sync
if php_sync_method==-1
if exists("php_noShortTags")
- syn sync match phpRegionSync grouphere phpRegion "^\s*<?php\s*$"
+ syn sync match phpRegionSync grouphere phpRegion "^\s*<?\(php\|=\)\s*$"
else
syn sync match phpRegionSync grouphere phpRegion "^\s*<?\(php\)\=\s*$"
endif
@@ -658,7 +894,7 @@ endif
syntax match phpDocCustomTags "@[a-zA-Z]*\(\s\+\|\n\|\r\)" containedin=phpComment
syntax region phpDocTags start="{@\(example\|id\|internal\|inheritdoc\|link\|source\|toc\|tutorial\)" end="}" containedin=phpComment
-syntax match phpDocTags "@\(abstract\|access\|author\|category\|copyright\|deprecated\|example\|final\|global\|ignore\|internal\|license\|link\|method\|name\|package\|param\|property\|return\|see\|since\|static\|staticvar\|subpackage\|tutorial\|uses\|var\|version\|contributor\|modified\|filename\|description\|filesource\|throws\)\(\s\+\)\?" containedin=phpComment
+syntax match phpDocTags "@\(abstract\|access\|api\|author\|category\|copyright\|deprecated\|example\|final\|global\|ignore\|internal\|license\|link\|method\|name\|package\|param\|property\(-write\|-read\)\?\|return\|see\|since\|source\|static\|staticvar\|subpackage\|tutorial\|uses\|used-by\|var\|version\|contributor\|modified\|filename\|description\|filesource\|throws\)\(\s\+\)\?" containedin=phpComment
syntax match phpDocTodo "@\(todo\|fixme\|xxx\)\(\s\+\)\?" containedin=phpComment
" Define the default highlighting.
@@ -729,7 +965,6 @@ else
hi def link phpIdentifierSimply Identifier
endif
-
let b:current_syntax = "php"
if main_syntax == 'php'
diff --git a/runtime/syntax/postscr.vim b/runtime/syntax/postscr.vim
index d5dc9a22d6..5af57aa0b1 100644
--- a/runtime/syntax/postscr.vim
+++ b/runtime/syntax/postscr.vim
@@ -6,7 +6,7 @@
" URL: http://www.eandem.co.uk/mrw/vim
"
" Options Flags:
-" postscr_level - language level to use for highligting (1, 2, or 3)
+" postscr_level - language level to use for highlighting (1, 2, or 3)
" postscr_display - include display PS operators
" postscr_ghostscript - include GS extensions
" postscr_fonts - highlight standard font names (a lot for PS 3)
@@ -469,12 +469,12 @@ if postscr_level == 2 || postscr_level == 3
syn keyword postscrConstant contained SubsVector UnderlineThickness FamilyName FontBBox CurMID
syn keyword postscrConstant contained Weight
-" PS2 User paramters
+" PS2 User parameters
syn keyword postscrConstant contained MaxFontItem MinFontCompress MaxUPathItem MaxFormItem MaxPatternItem
syn keyword postscrConstant contained MaxScreenItem MaxOpStack MaxDictStack MaxExecStack MaxLocalVM
syn keyword postscrConstant contained VMReclaim VMThreshold
-" PS2 System paramters
+" PS2 System parameters
syn keyword postscrConstant contained SystemParamsPassword StartJobPassword BuildTime ByteOrder RealFormat
syn keyword postscrConstant contained MaxFontCache CurFontCache MaxOutlineCache CurOutlineCache
syn keyword postscrConstant contained MaxUPathCache CurUPathCache MaxFormCache CurFormCache
@@ -504,7 +504,7 @@ if postscr_level == 2 || postscr_level == 3
syn keyword postscrL2Operator accuratescreens checkscreen pagemargin pageparams setaccuratescreens setpage
syn keyword postscrL2Operator setpagemargin setpageparams
-" Misc compatability operators
+" Misc compatibility operators
syn keyword postscrL2Operator appletalktype buildtime byteorder checkpassword defaulttimeouts diskonline
syn keyword postscrL2Operator diskstatus manualfeed manualfeedtimeout margins mirrorprint pagecount
syn keyword postscrL2Operator pagestackorder printername processcolors sethardwareiomode setjobtimeout
diff --git a/runtime/syntax/redif.vim b/runtime/syntax/redif.vim
index 725067fd32..365192284b 100644
--- a/runtime/syntax/redif.vim
+++ b/runtime/syntax/redif.vim
@@ -1,7 +1,7 @@
" Vim syntax file
" Language: ReDIF
" Maintainer: Axel Castellane <axel.castellane@polytechnique.edu>
-" Last Change: 2013 April 17
+" Last Change: 2021 Jul 28
" Original Author: Axel Castellane
" Source: http://openlib.org/acmes/root/docu/redif_1.html
" File Extension: rdf
diff --git a/runtime/syntax/ruby.vim b/runtime/syntax/ruby.vim
index 0de63d0ef3..13d6d9efd8 100644
--- a/runtime/syntax/ruby.vim
+++ b/runtime/syntax/ruby.vim
@@ -3,7 +3,7 @@
" Maintainer: Doug Kearns <dougkearns@gmail.com>
" URL: https://github.com/vim-ruby/vim-ruby
" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
-" Last Change: 2019 Jul 13
+" Last Change: 2021 Jun 06
" ----------------------------------------------------------------------------
"
" Previous Maintainer: Mirko Nasato
@@ -66,7 +66,7 @@ endfunction
com! -nargs=* SynFold call s:run_syntax_fold(<q-args>)
" Not-Top Cluster {{{1
-syn cluster rubyNotTop contains=@rubyCommentNotTop,@rubyStringNotTop,@rubyRegexpSpecial,@rubyDeclaration,@rubyExceptionHandler,@rubyClassOperator,rubyConditional,rubyModuleName,rubyClassName,rubySymbolDelimiter,rubyParentheses
+syn cluster rubyNotTop contains=@rubyCommentNotTop,@rubyStringNotTop,@rubyRegexpSpecial,@rubyDeclaration,@rubyExceptionHandler,@rubyClassOperator,rubyConditional,rubyModuleName,rubyClassName,rubySymbolDelimiter,rubyParentheses,@Spell
" Whitespace Errors {{{1
if exists("ruby_space_errors")
@@ -92,7 +92,7 @@ if exists("ruby_operators") || exists("ruby_pseudo_operators")
syn match rubyBooleanOperator "\%(\w\|[^\x00-\x7F]\)\@1<!!\|&&\|||"
syn match rubyRangeOperator "\.\.\.\="
syn match rubyAssignmentOperator "=>\@!\|-=\|/=\|\*\*=\|\*=\|&&=\|&=\|||=\||=\|%=\|+=\|>>=\|<<=\|\^="
- syn match rubyAssignmentOperator "=>\@!" containedin=rubyBlockParameterList " TODO: this is inelegant
+ syn match rubyAssignmentOperator "=>\@!" contained containedin=rubyBlockParameterList " TODO: this is inelegant
syn match rubyEqualityOperator "===\|==\|!=\|!\~\|=\~"
syn region rubyBracketOperator matchgroup=rubyOperator start="\%(\%(\w\|[^\x00-\x7F]\)[?!]\=\|[]})]\)\@2<=\[" end="]" contains=ALLBUT,@rubyNotTop
@@ -134,10 +134,10 @@ syn match rubyCurlyBraceEscape "\\[{}]" contained display
syn match rubyAngleBracketEscape "\\[<>]" contained display
syn match rubySquareBracketEscape "\\[[\]]" contained display
-syn region rubyNestedParentheses start="(" skip="\\\\\|\\)" matchgroup=rubyString end=")" transparent contained
-syn region rubyNestedCurlyBraces start="{" skip="\\\\\|\\}" matchgroup=rubyString end="}" transparent contained
-syn region rubyNestedAngleBrackets start="<" skip="\\\\\|\\>" matchgroup=rubyString end=">" transparent contained
-syn region rubyNestedSquareBrackets start="\[" skip="\\\\\|\\\]" matchgroup=rubyString end="\]" transparent contained
+syn region rubyNestedParentheses start="(" skip="\\\\\|\\)" end=")" transparent contained
+syn region rubyNestedCurlyBraces start="{" skip="\\\\\|\\}" end="}" transparent contained
+syn region rubyNestedAngleBrackets start="<" skip="\\\\\|\\>" end=">" transparent contained
+syn region rubyNestedSquareBrackets start="\[" skip="\\\\\|\\\]" end="\]" transparent contained
syn cluster rubySingleCharEscape contains=rubyBackslashEscape,rubyQuoteEscape,rubySpaceEscape,rubyParenthesisEscape,rubyCurlyBraceEscape,rubyAngleBracketEscape,rubySquareBracketEscape
syn cluster rubyNestedBrackets contains=rubyNested.\+
@@ -193,7 +193,7 @@ SynFold ':' syn region rubySymbol matchgroup=rubySymbolDelimiter start="[]})\"':
syn match rubyCapitalizedMethod "\%(\%(^\|[^.]\)\.\s*\)\@<!\<\u\%(\w\|[^\x00-\x7F]\)*\>\%(\s*(\)\@="
-syn region rubyParentheses start="(" end=")" contains=ALLBUT,@rubyNotTop containedin=rubyBlockParameterList
+syn region rubyParentheses start="(" end=")" contains=ALLBUT,@rubyNotTop contained containedin=rubyBlockParameterList
syn region rubyBlockParameterList start="\%(\%(\<do\>\|{\)\_s*\)\@32<=|" end="|" contains=ALLBUT,@rubyNotTop,@rubyProperOperator
if exists('ruby_global_variable_error')
@@ -332,7 +332,7 @@ SynFold '<<' syn region rubyString start=+\%(\%(class\|::\|\.\@1<!\.\)\_s*\|\%([
syn match rubyAliasDeclaration "[^[:space:];#.()]\+" contained contains=rubySymbol,@rubyGlobalVariable nextgroup=rubyAliasDeclaration2 skipwhite
syn match rubyAliasDeclaration2 "[^[:space:];#.()]\+" contained contains=rubySymbol,@rubyGlobalVariable
syn match rubyMethodDeclaration "[^[:space:];#(]\+" contained contains=rubyConstant,rubyBoolean,rubyPseudoVariable,rubyInstanceVariable,rubyClassVariable,rubyGlobalVariable
-syn match rubyClassDeclaration "[^[:space:];#<]\+" contained contains=rubyClassName,rubyScopeOperator nextgroup=rubySuperClassOperator skipwhite skipnl
+syn match rubyClassDeclaration "[^[:space:];#<]\+" contained contains=rubyClassName,rubyScopeOperator nextgroup=rubySuperClassOperator skipwhite
syn match rubyModuleDeclaration "[^[:space:];#<]\+" contained contains=rubyModuleName,rubyScopeOperator
syn match rubyMethodName "\<\%([_[:alpha:]]\|[^\x00-\x7F]\)\%([_[:alnum:]]\|[^\x00-\x7F]\)*[?!=]\=\%([[:alnum:]_.:?!=]\|[^\x00-\x7F]\)\@!" contained containedin=rubyMethodDeclaration
@@ -462,7 +462,7 @@ endif
syn match rubyDefinedOperator "\%#=1\<defined?" display
" 1.9-style Hash Keys and Keyword Parameters {{{1
-syn match rubySymbol "\%([{(|,]\_s*\)\@<=\%(\h\|[^\x00-\x7F]\)\%(\w\|[^\x00-\x7F]\)*[?!]\=::\@!"he=e-1
+syn match rubySymbol "\%(\w\|[^\x00-\x7F]\)\%(\w\|[^\x00-\x7F]\)*[?!]\=::\@!"he=e-1 contained containedin=rubyBlockParameterList,rubyCurlyBlock
syn match rubySymbol "[]})\"':]\@1<!\<\%(\h\|[^\x00-\x7F]\)\%(\w\|[^\x00-\x7F]\)*[!?]\=:[[:space:],;]\@="he=e-1
syn match rubySymbol "[[:space:],{(]\%(\h\|[^\x00-\x7F]\)\%(\w\|[^\x00-\x7F]\)*[!?]\=:[[:space:],;]\@="hs=s+1,he=e-1
diff --git a/runtime/syntax/scala.vim b/runtime/syntax/scala.vim
index c5a175fd77..16e114778d 100644
--- a/runtime/syntax/scala.vim
+++ b/runtime/syntax/scala.vim
@@ -3,7 +3,7 @@
" Maintainer: Derek Wyatt
" URL: https://github.com/derekwyatt/vim-scala
" License: Same as Vim
-" Last Change: 20 May 2016
+" Last Change: 23 August 2021
" ----------------------------------------------------------------------------
if !exists('main_syntax')
@@ -66,7 +66,7 @@ syn match scalaChar /'\\u[A-Fa-f0-9]\{4}'/ contains=scalaUnicodeChar
syn match scalaEscapedChar /\\[\\"'ntbrf]/
syn match scalaUnicodeChar /\\u[A-Fa-f0-9]\{4}/
hi link scalaChar Character
-hi link scalaEscapedChar Function
+hi link scalaEscapedChar Special
hi link scalaUnicodeChar Special
syn match scalaOperator "||"
@@ -102,9 +102,9 @@ syn match scalaTypeTypeDeclaration /(/ contained nextgroup=scalaTypeTypeExtensio
syn match scalaTypeTypeDeclaration /\%(⇒\|=>\)\ze/ contained nextgroup=scalaTypeTypeDeclaration contains=scalaTypeTypeExtension skipwhite
syn match scalaTypeTypeDeclaration /\<[_\.A-Za-z0-9$]\+\>/ contained nextgroup=scalaTypeTypeExtension,scalaTypeTypeEquals skipwhite
syn match scalaTypeTypeEquals /=\ze[^>]/ contained nextgroup=scalaTypeTypePostDeclaration skipwhite
-syn match scalaTypeTypeExtension /)\?\_s*\zs\%(⇒\|=>\|<:\|:>\|=:=\|::\|#\)/ contained nextgroup=scalaTypeTypeDeclaration skipwhite
+syn match scalaTypeTypeExtension /)\?\_s*\zs\%(⇒\|=>\|<:\|:>\|=:=\|::\|#\)/ contained contains=scalaTypeOperator nextgroup=scalaTypeTypeDeclaration skipwhite
syn match scalaTypeTypePostDeclaration /\<[_\.A-Za-z0-9$]\+\>/ contained nextgroup=scalaTypeTypePostExtension skipwhite
-syn match scalaTypeTypePostExtension /\%(⇒\|=>\|<:\|:>\|=:=\|::\)/ contained nextgroup=scalaTypeTypePostDeclaration skipwhite
+syn match scalaTypeTypePostExtension /\%(⇒\|=>\|<:\|:>\|=:=\|::\)/ contained contains=scalaTypeOperator nextgroup=scalaTypeTypePostDeclaration skipwhite
hi link scalaTypeTypeDeclaration Type
hi link scalaTypeTypeExtension Keyword
hi link scalaTypeTypePostDeclaration Special
@@ -113,21 +113,23 @@ hi link scalaTypeTypePostExtension Keyword
syn match scalaTypeDeclaration /(/ contained nextgroup=scalaTypeExtension contains=scalaRoundBrackets skipwhite
syn match scalaTypeDeclaration /\%(⇒\|=>\)\ze/ contained nextgroup=scalaTypeDeclaration contains=scalaTypeExtension skipwhite
syn match scalaTypeDeclaration /\<[_\.A-Za-z0-9$]\+\>/ contained nextgroup=scalaTypeExtension skipwhite
-syn match scalaTypeExtension /)\?\_s*\zs\%(⇒\|=>\|<:\|:>\|=:=\|::\|#\)/ contained nextgroup=scalaTypeDeclaration skipwhite
+syn match scalaTypeExtension /)\?\_s*\zs\%(⇒\|=>\|<:\|:>\|=:=\|::\|#\)/ contained contains=scalaTypeOperator nextgroup=scalaTypeDeclaration skipwhite
hi link scalaTypeDeclaration Type
hi link scalaTypeExtension Keyword
hi link scalaTypePostExtension Keyword
syn match scalaTypeAnnotation /\%([_a-zA-Z0-9$\s]:\_s*\)\ze[_=(\.A-Za-z0-9$]\+/ skipwhite nextgroup=scalaTypeDeclaration contains=scalaRoundBrackets
syn match scalaTypeAnnotation /)\_s*:\_s*\ze[_=(\.A-Za-z0-9$]\+/ skipwhite nextgroup=scalaTypeDeclaration
-hi link scalaTypeAnnotation Normal
+hi clear scalaTypeAnnotation
-syn match scalaCaseFollowing /\<[_\.A-Za-z0-9$]\+\>/ contained
-syn match scalaCaseFollowing /`[^`]\+`/ contained
+syn match scalaCaseFollowing /\<[_\.A-Za-z0-9$]\+\>/ contained contains=scalaCapitalWord
+syn match scalaCaseFollowing /`[^`]\+`/ contained contains=scalaCapitalWord
hi link scalaCaseFollowing Special
-syn keyword scalaKeywordModifier abstract override final lazy implicit implicitly private protected sealed null require super
+syn keyword scalaKeywordModifier abstract override final lazy implicit private protected sealed null super
+syn keyword scalaSpecialFunction implicitly require
hi link scalaKeywordModifier Function
+hi link scalaSpecialFunction Function
syn keyword scalaSpecial this true false ne eq
syn keyword scalaSpecial new nextgroup=scalaInstanceDeclaration skipwhite
@@ -151,14 +153,14 @@ hi link scalaTripleIString String
syn match scalaInterpolation /\$[a-zA-Z0-9_$]\+/ contained
exe 'syn region scalaInterpolationB matchgroup=scalaInterpolationBoundary start=/\${/ end=/}/ contained contains=' . s:ContainedGroup()
hi link scalaInterpolation Function
-hi link scalaInterpolationB Normal
+hi clear scalaInterpolationB
syn region scalaFString matchgroup=scalaInterpolationBrackets start=/f"/ skip=/\\"/ end=/"/ contains=scalaFInterpolation,scalaFInterpolationB,scalaEscapedChar,scalaUnicodeChar
syn match scalaFInterpolation /\$[a-zA-Z0-9_$]\+\(%[-A-Za-z0-9\.]\+\)\?/ contained
exe 'syn region scalaFInterpolationB matchgroup=scalaInterpolationBoundary start=/${/ end=/}\(%[-A-Za-z0-9\.]\+\)\?/ contained contains=' . s:ContainedGroup()
hi link scalaFString String
hi link scalaFInterpolation Function
-hi link scalaFInterpolationB Normal
+hi clear scalaFInterpolationB
syn region scalaTripleString start=/"""/ end=/"""\%([^"]\|$\)/ contains=scalaEscapedChar,scalaUnicodeChar
syn region scalaTripleFString matchgroup=scalaInterpolationBrackets start=/f"""/ end=/"""\%([^"]\|$\)/ contains=scalaFInterpolation,scalaFInterpolationB,scalaEscapedChar,scalaUnicodeChar
@@ -199,7 +201,6 @@ hi link scalaDocLinks Function
hi link scalaParameterAnnotation Function
hi link scalaParamAnnotationValue Keyword
hi link scalaCommentAnnotation Function
-hi link scalaCommentCodeBlockBrackets String
hi link scalaCommentCodeBlock String
hi link scalaTodo Todo
diff --git a/runtime/syntax/scdoc.vim b/runtime/syntax/scdoc.vim
new file mode 100644
index 0000000000..25c9c5433b
--- /dev/null
+++ b/runtime/syntax/scdoc.vim
@@ -0,0 +1,52 @@
+" Syntax file for scdoc files
+" Maintainer: Gregory Anders <greg@gpanders.com>
+" Last Updated: 2021-08-04
+
+if exists('b:current_syntax')
+ finish
+endif
+let b:current_syntax = 'scdoc'
+
+syntax match scdocFirstLineError "\%^.*$"
+syntax match scdocFirstLineValid "\%^\S\+(\d[0-9A-Za-z]*)\%(\s\+\"[^"]*\"\%(\s\+\"[^"]*\"\)\=\)\=$"
+
+syntax region scdocCommentError start="^;\S" end="$" keepend
+syntax region scdocComment start="^; " end="$" keepend
+
+syntax region scdocHeaderError start="^#\{3,}" end="$" keepend
+syntax region scdocHeader start="^#\{1,2}" end="$" keepend
+
+syntax match scdocIndentError "^[ ]\+"
+
+syntax match scdocLineBreak "++$"
+
+syntax match scdocOrderedListMarker "^\s*\.\%(\s\+\S\)\@="
+syntax match scdocListMarker "^\s*-\%(\s\+\S\)\@="
+
+syntax match scdocTableStartMarker "^[\[|\]][\[\-\]]"
+syntax match scdocTableMarker "^[|:][\[\-\] ]"
+
+syntax region scdocBold concealends matchgroup=scdocBoldDelimiter start="\\\@<!\*" end="\\\@<!\*"
+syntax region scdocUnderline concealends matchgroup=scdocUnderlineDelimiter start="\<\\\@<!_" end="\\\@<!_\>"
+syntax region scdocPre matchgroup=scdocPreDelimiter start="^\t*```" end="^\t*```"
+
+hi link scdocFirstLineValid Comment
+hi link scdocComment Comment
+hi link scdocHeader Title
+hi link scdocOrderedListMarker Statement
+hi link scdocListMarker scdocOrderedListMarker
+hi link scdocLineBreak Special
+hi link scdocTableMarker Statement
+hi link scdocTableStartMarker scdocTableMarker
+
+hi link scdocFirstLineError Error
+hi link scdocCommentError Error
+hi link scdocHeaderError Error
+hi link scdocIndentError Error
+
+hi link scdocPreDelimiter Delimiter
+
+hi scdocBold term=bold cterm=bold gui=bold
+hi scdocUnderline term=underline cterm=underline gui=underline
+hi link scdocBoldDelimiter scdocBold
+hi link scdocUnderlineDelimiter scdocUnderline
diff --git a/runtime/syntax/scheme.vim b/runtime/syntax/scheme.vim
index e209729f57..c4454fc57c 100644
--- a/runtime/syntax/scheme.vim
+++ b/runtime/syntax/scheme.vim
@@ -1,10 +1,11 @@
" Vim syntax file
" Language: Scheme (R7RS)
-" Last Change: 2018-01-06
+" Last Change: 2021-01-03
" Author: Evan Hanson <evhan@foldling.org>
" Maintainer: Evan Hanson <evhan@foldling.org>
" Previous Author: Dirk van Deun <dirk@igwe.vub.ac.be>
" Previous Maintainer: Sergey Khorev <sergey.khorev@gmail.com>
+" Repository: https://git.foldling.org/vim-scheme.git
" URL: https://foldling.org/vim/syntax/scheme.vim
if exists('b:current_syntax')
@@ -14,6 +15,8 @@ endif
let s:cpo = &cpo
set cpo&vim
+syn spell notoplevel
+
syn match schemeParentheses "[^ '`\t\n()\[\]";]\+"
syn match schemeParentheses "[)\]]"
@@ -35,7 +38,7 @@ syn region schemeUnquote matchgroup=schemeParentheses start=/,@(/ end=/)/ contai
syn region schemeQuoteForm matchgroup=schemeData start=/(/ end=/)/ contained contains=ALLBUT,schemeQuasiquote,schemeQuasiquoteForm,schemeUnquote,schemeForm,schemeDatumCommentForm,schemeImport,@schemeImportCluster,@schemeSyntaxCluster
syn region schemeQuasiquoteForm matchgroup=schemeData start=/(/ end=/)/ contained contains=ALLBUT,schemeQuote,schemeForm,schemeDatumCommentForm,schemeImport,@schemeImportCluster,@schemeSyntaxCluster
-syn region schemeString start=/\(\\\)\@<!"/ skip=/\\[\\"]/ end=/"/
+syn region schemeString start=/\(\\\)\@<!"/ skip=/\\[\\"]/ end=/"/ contains=@Spell
syn region schemeSymbol start=/\(\\\)\@<!|/ skip=/\\[\\|]/ end=/|/
syn match schemeNumber /\(#[dbeio]\)*[+\-]*\([0-9]\+\|inf.0\|nan.0\)\(\/\|\.\)\?[0-9+\-@\ilns]*\>/
@@ -47,9 +50,9 @@ syn match schemeBoolean /#f\(alse\)\?/
syn match schemeCharacter /#\\.[^ `'\t\n\[\]()]*/
syn match schemeCharacter /#\\x[0-9a-fA-F]\+/
-syn match schemeComment /;.*$/
+syn match schemeComment /;.*$/ contains=@Spell
-syn region schemeMultilineComment start=/#|/ end=/|#/ contains=schemeMultilineComment
+syn region schemeMultilineComment start=/#|/ end=/|#/ contains=schemeMultilineComment,@Spell
syn region schemeForm matchgroup=schemeParentheses start="(" end=")" contains=ALLBUT,schemeUnquote,schemeDatumCommentForm,@schemeImportCluster
syn region schemeForm matchgroup=schemeParentheses start="\[" end="\]" contains=ALLBUT,schemeUnquote,schemeDatumCommentForm,@schemeImportCluster
@@ -63,7 +66,7 @@ else
syn region schemeImport matchgroup=schemeImport start="\(([ \t\n]*\)\@<=\(import\)\>" end=")"me=e-1 contained contains=schemeImportForm,schemeIdentifier,schemeComment,schemeDatumComment
endif
-syn match schemeImportKeyword "\(([ \t\n]*\)\@<=\(except\|only\|prefix\|rename\|srfi\)\>"
+syn match schemeImportKeyword "\(([ \t\n]*\)\@<=\(except\|only\|prefix\|rename\)\>"
syn region schemeImportForm matchgroup=schemeParentheses start="(" end=")" contained contains=schemeIdentifier,schemeComment,schemeDatumComment,@schemeImportCluster
syn cluster schemeImportCluster contains=schemeImportForm,schemeImportKeyword
diff --git a/runtime/syntax/sgml.vim b/runtime/syntax/sgml.vim
index d60040c5d9..00d58d11f2 100644
--- a/runtime/syntax/sgml.vim
+++ b/runtime/syntax/sgml.vim
@@ -174,7 +174,7 @@ syn match sgmlAbbrEndTag +/+
" SGML specific
" abbreviated regions
"
-" No highlighing, highlighing is done by contained elements.
+" No highlighting, highlighting is done by contained elements.
"
" PROVIDES: @sgmlRegionHook
"
@@ -192,7 +192,7 @@ syn match sgmlAbbrRegion
" real (non-empty) elements. We cannot do syntax folding
" as in xml, because end tags may be optional in sgml depending
" on the dtd.
-" No highlighing, highlighing is done by contained elements.
+" No highlighting, highlighting is done by contained elements.
"
" PROVIDES: @sgmlRegionHook
"
@@ -225,7 +225,7 @@ syn region sgmlRegion
"
" <tag id="lola"/>
"
-" TODO use sgmlEmptyTag intead of sgmlTag
+" TODO use sgmlEmptyTag instead of sgmlTag
syn match sgmlEmptyRegion
\ +<[^ /!?>"']\(\_[^"'<>]\|"\_[^"]*"\|'\_[^']*'\)*/>+
\ contains=sgmlEmptyTag
diff --git a/runtime/syntax/sh.vim b/runtime/syntax/sh.vim
index 48a0024b00..0ab9c0ad58 100644
--- a/runtime/syntax/sh.vim
+++ b/runtime/syntax/sh.vim
@@ -2,8 +2,8 @@
" Language: shell (sh) Korn shell (ksh) bash (sh)
" Maintainer: Charles E. Campbell <NcampObell@SdrPchip.AorgM-NOSPAM>
" Previous Maintainer: Lennart Schultz <Lennart.Schultz@ecmwf.int>
-" Last Change: Nov 24, 2020
-" Version: 196
+" Last Change: Feb 18, 2021
+" Version: 198
" URL: http://www.drchip.org/astronaut/vim/index.html#SYNTAX_SH
" For options and settings, please use: :help ft-sh-syntax
" This file includes many ideas from Eric Brunet (eric.brunet@ens.fr) and heredoc fixes from Felipe Contreras
@@ -13,33 +13,35 @@ if exists("b:current_syntax")
finish
endif
-" trying to answer the question: which shell is /bin/sh, really?
-" If the user has not specified any of g:is_kornshell, g:is_bash, g:is_posix, g:is_sh, then guess.
-if getline(1) =~ '\<ksh$'
+" If the shell script itself specifies which shell to use, use it
+if getline(1) =~ '\<ksh\>'
let b:is_kornshell = 1
-elseif getline(1) =~ '\<bash$'
+elseif getline(1) =~ '\<bash\>'
let b:is_bash = 1
-elseif getline(1) =~ '\<dash$'
+elseif getline(1) =~ '\<dash\>'
let b:is_dash = 1
elseif !exists("g:is_kornshell") && !exists("g:is_bash") && !exists("g:is_posix") && !exists("g:is_sh") && !exists("g:is_dash")
+ " user did not specify which shell to use, and
+ " the script itself does not specify which shell to use. FYI: /bin/sh is ambiguous.
+ " Assuming /bin/sh is executable, and if its a link, find out what it links to.
let s:shell = ""
if executable("/bin/sh")
let s:shell = resolve("/bin/sh")
elseif executable("/usr/bin/sh")
let s:shell = resolve("/usr/bin/sh")
endif
- if s:shell =~ 'ksh$'
+ if s:shell =~ '\<ksh\>'
let b:is_kornshell= 1
- elseif s:shell =~ 'bash$'
+ elseif s:shell =~ '\<bash\>'
let b:is_bash = 1
- elseif s:shell =~ 'dash$'
+ elseif s:shell =~ '\<dash\>'
let b:is_dash = 1
endif
unlet s:shell
endif
" handling /bin/sh with is_kornshell/is_sh {{{1
-" b:is_sh is set when "#! /bin/sh" is found;
+" b:is_sh will be set when "#! /bin/sh" is found;
" However, it often is just a masquerade by bash (typically Linux)
" or kornshell (typically workstations with Posix "sh").
" So, when the user sets "g:is_bash", "g:is_kornshell",
@@ -98,12 +100,14 @@ if g:sh_fold_enabled && &fdm == "manual"
setl fdm=syntax
endif
-" set up the syntax-highlighting iskeyword
+" set up the syntax-highlighting for iskeyword
if (v:version == 704 && has("patch-7.4.1142")) || v:version > 704
- if exists("b:is_bash")
- exe "syn iskeyword ".&iskeyword.",-,:"
- else
- exe "syn iskeyword ".&iskeyword.",-"
+ if !exists("g:sh_syntax_isk") || (exists("g:sh_syntax_isk") && g:sh_syntax_isk)
+ if exists("b:is_bash")
+ exe "syn iskeyword ".&iskeyword.",-,:"
+ else
+ exe "syn iskeyword ".&iskeyword.",-"
+ endif
endif
endif
@@ -374,12 +378,11 @@ elseif !exists("g:sh_no_error")
syn region shExDoubleQuote matchGroup=Error start=+\$"+ skip=+\\\\\|\\.+ end=+"+ contains=shStringSpecial
endif
syn region shSingleQuote matchgroup=shQuote start=+'+ end=+'+ contains=@Spell nextgroup=shSpecialStart,shSpecialSQ
-syn region shDoubleQuote matchgroup=shQuote start=+\%(\%(\\\\\)*\\\)\@<!"+ skip=+\\.+ end=+"+ contains=@shDblQuoteList,shStringSpecial,@Spell nextgroup=shSpecialStart
-syn region shDoubleQuote matchgroup=shQuote start=+"+ matchgroup=shSpecial skip=+\\"+ matchgroup=shQuote end=+"+ contained contains=@shDblQuoteList,shStringSpecial,@Spell nextgroup=shSpecialStart
+syn region shDoubleQuote matchgroup=shQuote start=+\%(\%(\\\\\)*\\\)\@<!"+ skip=+\\.+ end=+"+ contains=@shDblQuoteList,shStringSpecial,@Spell nextgroup=shSpecialStart
syn match shStringSpecial "[^[:print:] \t]" contained
-syn match shStringSpecial "[^\\]\zs\%(\\\\\)*\\[\\"'`$()#]" nextgroup=shComment
-syn match shSpecialSQ "[^\\]\zs\%(\\\\\)*\\[\\"'`$()#]" contained nextgroup=shBkslshSnglQuote,@shNoZSList
-syn match shSpecialDQ "[^\\]\zs\%(\\\\\)*\\[\\"'`$()#]" contained nextgroup=shBkslshDblQuote,@shNoZSList
+syn match shStringSpecial "[^\\]\zs\%(\\\\\)*\(\\[\\"'`$()#]\)\+" nextgroup=shComment
+syn match shSpecialSQ "[^\\]\zs\%(\\\\\)*\(\\[\\"'`$()#]\)\+" contained nextgroup=shBkslshSnglQuote,@shNoZSList
+syn match shSpecialDQ "[^\\]\zs\%(\\\\\)*\(\\[\\"'`$()#]\)\+" contained nextgroup=shBkslshDblQuote,@shNoZSList
syn match shSpecialStart "\%(\\\\\)*\\[\\"'`$()#]" contained nextgroup=shBkslshSnglQuote,shBkslshDblQuote,@shNoZSList
syn match shSpecial "^\%(\\\\\)*\\[\\"'`$()#]"
syn match shSpecialNoZS contained "\%(\\\\\)*\\[\\"'`$()#]"
@@ -402,6 +405,7 @@ syn match shQuickComment contained "#.*$"
syn match shBQComment contained "#.\{-}\ze`" contains=@shCommentGroup
" Here Documents: {{{1
+" (modified by Felipe Contreras)
" =========================================
ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc01 start="<<\s*\z([^ \t|>]\+\)" matchgroup=shHereDoc01 end="^\z1\s*$" contains=@shDblQuoteList
ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc02 start="<<-\s*\z([^ \t|>]\+\)" matchgroup=shHereDoc02 end="^\s*\z1\s*$" contains=@shDblQuoteList
diff --git a/runtime/syntax/spup.vim b/runtime/syntax/spup.vim
index 743c7b5711..9284abf63f 100644
--- a/runtime/syntax/spup.vim
+++ b/runtime/syntax/spup.vim
@@ -25,7 +25,7 @@ endif
let s:cpo_save = &cpo
set cpo&vim
-" don't hightlight several keywords like subsections
+" don't highlight several keywords like subsections
"let strict_subsections = 1
" highlight types usually found in DECLARE section
@@ -177,7 +177,7 @@ syn cluster spupOrdinary contains=spupNumber,spupIdentifier,spupSymbol
syn cluster spupOrdinary add=spupError,spupString,spupComment
syn cluster spupTextproc contains=spupTextprocGeneric,spupTextprocError
-" define syncronizing; especially OPERATION sections can become very large
+" define synchronizing; especially OPERATION sections can become very large
syn sync clear
syn sync minlines=100
syn sync maxlines=500
diff --git a/runtime/syntax/st.vim b/runtime/syntax/st.vim
index 8160c7704a..ffa7820fe8 100644
--- a/runtime/syntax/st.vim
+++ b/runtime/syntax/st.vim
@@ -44,7 +44,7 @@ syn match stCharacter "$."
syn case ignore
-" the symols prefixed by a '#'
+" the symbols prefixed by a '#'
syn match stSymbol "\(#\<[a-z_][a-z0-9_]*\>\)"
syn match stSymbol "\(#'[^']*'\)"
@@ -58,7 +58,7 @@ syn match stFloat "\<\d\+e[-+]\=\d\+[fl]\=\>"
syn case match
-" a try to higlight paren mismatches
+" a try to highlight paren mismatches
syn region stParen transparent start='(' end=')' contains=ALLBUT,stParenError
syn match stParenError ")"
syn region stBlock transparent start='\[' end='\]' contains=ALLBUT,stBlockError
diff --git a/runtime/syntax/structurizr.vim b/runtime/syntax/structurizr.vim
new file mode 100644
index 0000000000..73629b1495
--- /dev/null
+++ b/runtime/syntax/structurizr.vim
@@ -0,0 +1,76 @@
+" Vim syntax file
+" Language: Structurizr DSL
+" Maintainer: Bastian Venthur <venthur@debian.org>
+" Last Change: 2021-08-16
+" Remark: For a language reference, see
+" https://github.com/structurizr/dsl
+
+
+if exists("b:current_syntax")
+ finish
+endif
+
+syn case ignore
+
+" comments
+syn match scomment "#.*$"
+syn match scomment "//.*$"
+syn region scomment start="/\*" end="\*/"
+
+" keywords
+syn keyword skeyword animation
+syn keyword skeyword autoLayout
+syn keyword skeyword branding
+syn keyword skeyword component
+syn keyword skeyword configuration
+syn keyword skeyword container
+syn keyword skeyword containerinstance
+syn keyword skeyword custom
+syn keyword skeyword deployment
+syn keyword skeyword deploymentenvironment
+syn keyword skeyword deploymentgroup
+syn keyword skeyword deploymentnode
+syn keyword skeyword dynamic
+syn keyword skeyword element
+syn keyword skeyword enterprise
+syn keyword skeyword exclude
+syn keyword skeyword filtered
+syn keyword skeyword group
+syn keyword skeyword healthcheck
+syn keyword skeyword impliedrelationships
+syn keyword skeyword include
+syn keyword skeyword infrastructurenode
+syn keyword skeyword model
+syn keyword skeyword person
+syn keyword skeyword perspectives
+syn keyword skeyword properties
+syn keyword skeyword relationship
+syn keyword skeyword softwaresystem
+syn keyword skeyword softwaresysteminstance
+syn keyword skeyword styles
+syn keyword skeyword systemcontext
+syn keyword skeyword systemlandscape
+syn keyword skeyword tags
+syn keyword skeyword terminology
+syn keyword skeyword theme
+syn keyword skeyword title
+syn keyword skeyword url
+syn keyword skeyword users
+syn keyword skeyword views
+syn keyword skeyword workspace
+
+syn match skeyword "\!adrs\s\+"
+syn match skeyword "\!constant\s\+"
+syn match skeyword "\!docs\s\+"
+syn match skeyword "\!identifiers\s\+"
+syn match skeyword "\!include\s\+"
+
+syn region sstring oneline start='"' end='"'
+
+syn region sblock start='{' end='}' fold transparent
+
+hi def link sstring string
+hi def link scomment comment
+hi def link skeyword keyword
+
+let b:current_syntax = "structurizr"
diff --git a/runtime/syntax/syncolor.vim b/runtime/syntax/syncolor.vim
deleted file mode 100644
index 5b907a3b83..0000000000
--- a/runtime/syntax/syncolor.vim
+++ /dev/null
@@ -1,87 +0,0 @@
-" Vim syntax support file
-" Maintainer: Bram Moolenaar <Bram@vim.org>
-" Last Change: 2020 Feb 13
-
-" This file sets up the default methods for highlighting.
-" It is loaded from "synload.vim" and from Vim for ":syntax reset".
-" Also used from init_highlight().
-
-if !exists("syntax_cmd") || syntax_cmd == "on"
- " ":syntax on" works like in Vim 5.7: set colors but keep links
- command -nargs=* SynColor hi <args>
- command -nargs=* SynLink hi link <args>
-else
- if syntax_cmd == "enable"
- " ":syntax enable" keeps any existing colors
- command -nargs=* SynColor hi def <args>
- command -nargs=* SynLink hi def link <args>
- elseif syntax_cmd == "reset"
- " ":syntax reset" resets all colors to the default
- command -nargs=* SynColor hi <args>
- command -nargs=* SynLink hi! link <args>
- else
- " User defined syncolor file has already set the colors.
- finish
- endif
-endif
-
-" Many terminals can only use six different colors (plus black and white).
-" Therefore the number of colors used is kept low. It doesn't look nice with
-" too many colors anyway.
-" Careful with "cterm=bold", it changes the color to bright for some terminals.
-" There are two sets of defaults: for a dark and a light background.
-if &background == "dark"
- SynColor Comment term=bold cterm=NONE ctermfg=Cyan ctermbg=NONE gui=NONE guifg=#80a0ff guibg=NONE
- SynColor Constant term=underline cterm=NONE ctermfg=Magenta ctermbg=NONE gui=NONE guifg=#ffa0a0 guibg=NONE
- SynColor Special term=bold cterm=NONE ctermfg=LightRed ctermbg=NONE gui=NONE guifg=Orange guibg=NONE
- SynColor Identifier term=underline cterm=bold ctermfg=Cyan ctermbg=NONE gui=NONE guifg=#40ffff guibg=NONE
- SynColor Statement term=bold cterm=NONE ctermfg=Yellow ctermbg=NONE gui=bold guifg=#ffff60 guibg=NONE
- SynColor PreProc term=underline cterm=NONE ctermfg=LightBlue ctermbg=NONE gui=NONE guifg=#ff80ff guibg=NONE
- SynColor Type term=underline cterm=NONE ctermfg=LightGreen ctermbg=NONE gui=bold guifg=#60ff60 guibg=NONE
- SynColor Underlined term=underline cterm=underline ctermfg=LightBlue gui=underline guifg=#80a0ff
- SynColor Ignore term=NONE cterm=NONE ctermfg=black ctermbg=NONE gui=NONE guifg=bg guibg=NONE
-else
- SynColor Comment term=bold cterm=NONE ctermfg=DarkBlue ctermbg=NONE gui=NONE guifg=Blue guibg=NONE
- SynColor Constant term=underline cterm=NONE ctermfg=DarkRed ctermbg=NONE gui=NONE guifg=Magenta guibg=NONE
- " #6a5acd is SlateBlue
- SynColor Special term=bold cterm=NONE ctermfg=DarkMagenta ctermbg=NONE gui=NONE guifg=#6a5acd guibg=NONE
- SynColor Identifier term=underline cterm=NONE ctermfg=DarkCyan ctermbg=NONE gui=NONE guifg=DarkCyan guibg=NONE
- SynColor Statement term=bold cterm=NONE ctermfg=Brown ctermbg=NONE gui=bold guifg=Brown guibg=NONE
- " #6a0dad is Purple
- SynColor PreProc term=underline cterm=NONE ctermfg=DarkMagenta ctermbg=NONE gui=NONE guifg=#6a0dad guibg=NONE
- SynColor Type term=underline cterm=NONE ctermfg=DarkGreen ctermbg=NONE gui=bold guifg=SeaGreen guibg=NONE
- SynColor Underlined term=underline cterm=underline ctermfg=DarkMagenta gui=underline guifg=SlateBlue
- SynColor Ignore term=NONE cterm=NONE ctermfg=white ctermbg=NONE gui=NONE guifg=bg guibg=NONE
-endif
-SynColor Error term=reverse cterm=NONE ctermfg=White ctermbg=Red gui=NONE guifg=White guibg=Red
-SynColor Todo term=standout cterm=NONE ctermfg=Black ctermbg=Yellow gui=NONE guifg=Blue guibg=Yellow
-
-" Common groups that link to default highlighting.
-" You can specify other highlighting easily.
-SynLink String Constant
-SynLink Character Constant
-SynLink Number Constant
-SynLink Boolean Constant
-SynLink Float Number
-SynLink Function Identifier
-SynLink Conditional Statement
-SynLink Repeat Statement
-SynLink Label Statement
-SynLink Operator Statement
-SynLink Keyword Statement
-SynLink Exception Statement
-SynLink Include PreProc
-SynLink Define PreProc
-SynLink Macro PreProc
-SynLink PreCondit PreProc
-SynLink StorageClass Type
-SynLink Structure Type
-SynLink Typedef Type
-SynLink Tag Special
-SynLink SpecialChar Special
-SynLink Delimiter Special
-SynLink SpecialComment Special
-SynLink Debug Special
-
-delcommand SynColor
-delcommand SynLink
diff --git a/runtime/syntax/synload.vim b/runtime/syntax/synload.vim
index 3863a84c1a..bfcd3b06da 100644
--- a/runtime/syntax/synload.vim
+++ b/runtime/syntax/synload.vim
@@ -14,13 +14,6 @@ endif
" let others know that syntax has been switched on
let syntax_on = 1
-" Set the default highlighting colors. Use a color scheme if specified.
-if exists("colors_name")
- exe "colors " . colors_name
-else
- runtime! syntax/syncolor.vim
-endif
-
" Line continuation is used here, remove 'C' from 'cpoptions'
let s:cpo_save = &cpo
set cpo&vim
diff --git a/runtime/syntax/tmux.vim b/runtime/syntax/tmux.vim
index d5419982ad..4f435ab923 100644
--- a/runtime/syntax/tmux.vim
+++ b/runtime/syntax/tmux.vim
@@ -8,7 +8,7 @@ if exists("b:current_syntax")
finish
endif
-" Explicitly change compatiblity options to Vim's defaults because this file
+" Explicitly change compatibility options to Vim's defaults because this file
" uses line continuations.
let s:original_cpo = &cpo
set cpo&vim
diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim
index 55c47aa34d..f695a1a1bf 100644
--- a/runtime/syntax/vim.vim
+++ b/runtime/syntax/vim.vim
@@ -12,7 +12,7 @@
if exists("b:current_syntax")
finish
endif
-let s:keepcpo= &cpo
+let s:keepcpo = &cpo
set cpo&vim
" vimTodo: contains common special-notices for comments {{{2
@@ -200,7 +200,7 @@ syn keyword vimAugroupKey contained aug[roup]
" Operators: {{{2
" =========
-syn cluster vimOperGroup contains=vimEnvvar,vimFunc,vimFuncVar,vimOper,vimOperParen,vimNumber,vimString,vimRegister,vimContinue,vim9Comment
+syn cluster vimOperGroup contains=vimEnvvar,vimFunc,vimFuncVar,vimOper,vimOperParen,vimNumber,vimString,vimType,vimRegister,vimContinue,vim9Comment
syn match vimOper "\%#=1\(==\|!=\|>=\|<=\|=\~\|!\~\|>\|<\|=\)[?#]\{0,2}" skipwhite nextgroup=vimString,vimSpecFile
syn match vimOper "\(\<is\|\<isnot\)[?#]\{0,2}\>" skipwhite nextgroup=vimString,vimSpecFile
syn match vimOper "||\|&&\|[-+.!]" skipwhite nextgroup=vimString,vimSpecFile
@@ -214,12 +214,13 @@ endif
" =========
syn cluster vimFuncList contains=vimCommand,vimFunctionError,vimFuncKey,Tag,vimFuncSID
syn cluster vimFuncBodyList contains=vimAbb,vimAddress,vimAugroupKey,vimAutoCmd,vimCmplxRepeat,vimComment,vim9Comment,vimContinue,vimCtrlChar,vimEcho,vimEchoHL,vimEnvvar,vimExecute,vimIsCommand,vimFBVar,vimFunc,vimFunction,vimFuncVar,vimGlobal,vimHighlight,vimIsCommand,vimLet,vimLetHereDoc,vimLineComment,vimMap,vimMark,vimNorm,vimNotation,vimNotFunc,vimNumber,vimOper,vimOperParen,vimRegion,vimRegister,vimSearch,vimSet,vimSpecFile,vimString,vimSubst,vimSynLine,vimUnmap,vimUserCommand
-syn match vimFunction "\<fu\%[nction]!\=\s\+\%(<[sS][iI][dD]>\|[sSgGbBwWtTlL]:\)\=\%(\i\|[#.]\|{.\{-1,}}\)*\ze\s*(" contains=@vimFuncList nextgroup=vimFuncBody
+syn match vimFunction "\<\(fu\%[nction]\)!\=\s\+\%(<[sS][iI][dD]>\|[sSgGbBwWtTlL]:\)\=\%(\i\|[#.]\|{.\{-1,}}\)*\ze\s*(" contains=@vimFuncList nextgroup=vimFuncBody
+ syn match vimFunction "\<def!\=\ze\s*(" contains=@vimFuncList nextgroup=vimFuncBody
if exists("g:vimsyn_folding") && g:vimsyn_folding =~# 'f'
syn region vimFuncBody contained fold start="\ze\s*(" matchgroup=vimCommand end="\<\(endf\>\|endfu\%[nction]\>\|enddef\>\)" contains=@vimFuncBodyList
else
- syn region vimFuncBody contained start="\ze\s*(" matchgroup=vimCommand end="\<\(endf\>\|endfu\%[nction]\>\|enddef\>\)" contains=@vimFuncBodyList
+ syn region vimFuncBody contained start="\ze\s*(" matchgroup=vimCommand end="\<\(endf\>\|endfu\%[nction]\>\|enddef\>\)" contains=@vimFuncBodyList
endif
syn match vimFuncVar contained "a:\(\K\k*\|\d\+\)"
syn match vimFuncSID contained "\c<sid>\|\<s:"
@@ -228,6 +229,9 @@ syn match vimFuncBlank contained "\s\+"
syn keyword vimPattern contained start skip end
+" vimTypes : new for vim9
+ syn match vimType ":\s*\zs\<\(bool\|number\|float\|string\|blob\|list<\|dict<\|job\|channel\|func\)\>"
+
" Special Filenames, Modifiers, Extension Removal: {{{2
" ===============================================
syn match vimSpecFile "<c\(word\|WORD\)>" nextgroup=vimSpecFileMod,vimSubst
@@ -355,7 +359,7 @@ syn match vimCmplxRepeat '[^a-zA-Z_/\\()]q[0-9a-zA-Z"]\>'lc=1
syn match vimCmplxRepeat '@[0-9a-z".=@:]\ze\($\|[^a-zA-Z]\>\)'
" Set command and associated set-options (vimOptions) with comment {{{2
-syn region vimSet matchgroup=vimCommand start="\<\%(setl\%[ocal]\|setg\%[lobal]\|se\%[t]\)\>" skip="\%(\\\\\)*\\." end="$" end="|" matchgroup=vimNotation end="<[cC][rR]>" oneline keepend contains=vimSetEqual,vimOption,vimErrSetting,vimComment,vim9Comment,vimSetString,vimSetMod
+syn region vimSet matchgroup=vimCommand start="\<\%(setl\%[ocal]\|setg\%[lobal]\|se\%[t]\)\>" skip="\%(\\\\\)*\\.\n\@!" end="$" end="|" matchgroup=vimNotation end="<[cC][rR]>" keepend contains=vimSetEqual,vimOption,vimErrSetting,vimComment,vim9Comment,vimSetString,vimSetMod
syn region vimSetEqual contained start="[=:]\|[-+^]=" skip="\\\\\|\\\s" end="[| \t]"me=e-1 end="$" contains=vimCtrlChar,vimSetSep,vimNotation,vimEnvvar
syn region vimSetString contained start=+="+hs=s+1 skip=+\\\\\|\\"+ end=+"+ contains=vimCtrlChar
syn match vimSetSep contained "[,:]"
@@ -390,7 +394,7 @@ syn case match
" Maps: {{{2
" ====
syn match vimMap "\<map\>!\=\ze\s*[^(]" skipwhite nextgroup=vimMapMod,vimMapLhs
-syn keyword vimMap cm[ap] cno[remap] im[ap] ino[remap] lm[ap] ln[oremap] nm[ap] nn[oremap] no[remap] om[ap] ono[remap] smap snor[emap] vm[ap] vn[oremap] xm[ap] xn[oremap] skipwhite nextgroup=vimMapBang,vimMapMod,vimMapLhs
+syn keyword vimMap cm[ap] cno[remap] im[ap] ino[remap] lm[ap] ln[oremap] nm[ap] nn[oremap] no[remap] om[ap] ono[remap] smap snor[emap] tno[remap] tm[ap] vm[ap] vmapc[lear] vn[oremap] xm[ap] xn[oremap] skipwhite nextgroup=vimMapBang,vimMapMod,vimMapLhs
syn keyword nvimMap tn[oremap] tm[ap] skipwhite nextgroup=vimMapBang,vimMapMod,vimMapLhs
syn keyword vimMap mapc[lear] smapc[lear]
syn keyword vimUnmap cu[nmap] iu[nmap] lu[nmap] nun[map] ou[nmap] sunm[ap] unm[ap] unm[ap] vu[nmap] xu[nmap] skipwhite nextgroup=vimMapBang,vimMapMod,vimMapLhs
@@ -981,6 +985,7 @@ if !exists("skip_vim_syntax_inits")
hi def link vimSyntax vimCommand
hi def link vimSynType vimSpecial
hi def link vimTodo Todo
+ hi def link vimType Type
hi def link vimUnmap vimMap
hi def link vimUserAttrbCmpltFunc Special
hi def link vimUserAttrbCmplt vimSpecial
diff --git a/runtime/tutor/en/vim-01-beginner.tutor b/runtime/tutor/en/vim-01-beginner.tutor
index 5ae0fde0da..7c0c357e80 100644
--- a/runtime/tutor/en/vim-01-beginner.tutor
+++ b/runtime/tutor/en/vim-01-beginner.tutor
@@ -1,4 +1,4 @@
-# Welcome to the VIM Tutor
+# Welcome to the VIM Tutor
Vim is a very powerful editor that has many commands, too many to explain in
a tutor such as this. This tutor is designed to describe enough of the
@@ -21,7 +21,9 @@ This tutorial is interactive, and there are a few things you should know.
- Type [<Enter>](<Enter>) on links [like this](holy-grail ) to open the linked help section.
- Or simply type [K](K) on any word to find its documentation!
- Sometimes you will be required to modify text like
-this here
+
+ this here
+
Once you have done the changes correctly, the ✗ sign at the left will change
to ✓. I imagine you can already see how neat Vim can be. ;)
Other times, you'll be prompted to run a command (I'll explain this later):
@@ -32,7 +34,6 @@ or press a sequence of keys
~~~ normal
<Esc>0f<Space>d3wP$P
~~~
-
Text within <'s and >'s (like `<Enter>`{normal}) describes a key to press
instead of text to type.
@@ -48,12 +49,12 @@ Now, move to the next lesson (use the `j`{normal} key to scroll down).
j The `j`{normal} key looks like a down arrow.
- 1. Move the cursor around the screen until you are comfortable.
+ 1. Move the cursor around the screen until you are comfortable.
- 2. Hold down the down key (`j`{normal}) until it repeats.
- Now you know how to move to the next lesson.
+ 2. Hold down the down key (`j`{normal}) until it repeats.
+ Now you know how to move to the next lesson.
- 3. Using the down key, move to Lesson 1.2.
+ 3. Using the down key, move to Lesson 1.2.
NOTE: If you are ever unsure about something you typed, press <Esc> to place
you in Normal mode. Then retype the command you wanted.
@@ -63,8 +64,7 @@ NOTE: The cursor keys should also work. But using hjkl you will be able to
# Lesson 1.2: EXITING VIM
-!! NOTE: Before executing any of the steps below,
-read this entire lesson !!
+!! NOTE: Before executing any of the steps below, read this entire lesson !!
1. Press the <Esc> key (to make sure you are in Normal mode).
@@ -72,18 +72,18 @@ read this entire lesson !!
`:q!`{vim} `<Enter>`{normal}.
- This exits the editor, DISCARDING any changes you have made.
+ This exits the editor, DISCARDING any changes you have made.
3. Open vim and get back here by executing the command that got you into
- this tutor. That might be:
+ this tutor. That might be:
- :Tutor <Enter>
+ :Tutor <Enter>
4. If you have these steps memorized and are confident, execute steps
- 1 through 3 to exit and re-enter the editor.
+ 1 through 3 to exit and re-enter the editor.
NOTE: [:q!](:q) <Enter> discards any changes you made. In a few lessons you
- will learn how to save the changes to a file.
+ will learn how to save the changes to a file.
5. Move the cursor down to Lesson 1.3.
@@ -94,7 +94,7 @@ NOTE: [:q!](:q) <Enter> discards any changes you made. In a few lessons you
1. Move the cursor to the line below marked ✗.
2. To fix the errors, move the cursor until it is on top of the
- character to be deleted.
+ character to be deleted.
3. Press [the x key](x) to delete the unwanted character.
@@ -104,8 +104,9 @@ The ccow jumpedd ovverr thhe mooon.
5. Now that the line is correct, go on to Lesson 1.4.
-NOTE: As you go through this tutor, do not try to memorize, learn by
- usage.
+NOTE: As you go through this tutor, do not try to memorize everything,
+ your Vim vocabulary will expand with usage. Consider returning to
+ this tutor periodically for a refresher.
# Lesson 1.4: TEXT EDITING: INSERTION
@@ -114,12 +115,12 @@ NOTE: As you go through this tutor, do not try to memorize, learn by
1. Move the cursor to the first line below marked ✗.
2. To make the first line the same as the second, move the cursor on top
- of the first character AFTER where the text is to be inserted.
+ of the first character AFTER where the text is to be inserted.
3. Press `i`{normal} and type in the necessary additions.
4. As each error is fixed press `<Esc>`{normal} to return to Normal mode.
- Repeat steps 2 through 4 to correct the sentence.
+ Repeat steps 2 through 4 to correct the sentence.
There is text misng this .
There is some text missing from this line.
@@ -136,7 +137,7 @@ There is some text missing from this line.
2. Press [A](A) and type in the necessary additions.
3. As the text has been appended press `<Esc>`{normal} to return to Normal
- mode.
+ mode.
4. Move the cursor to the second line marked ✗ and repeat
steps 2 and 3 to correct this sentence.
@@ -159,7 +160,7 @@ There is also some text missing here.
2. At the shell prompt type this command:
~~~ sh
- $ nvim tutor
+ $ nvim tutor
~~~
'nvim' is the command to start the Nvim editor, 'tutor' is the name of
the file you wish to edit. Use a file that may be changed.
@@ -168,13 +169,12 @@ There is also some text missing here.
4. Save the file with changes and exit Vim with:
~~~ cmd
- :wq
+ :wq
~~~
-
Note you'll need to press `<Enter>` to execute the command.
5. If you have quit vimtutor in step 1 restart the vimtutor and move down
- to the following summary.
+ to the following summary.
6. After reading the above steps and understanding them: do it.
@@ -184,15 +184,11 @@ There is also some text missing here.
h (left) j (down) k (up) l (right)
2. To start Vim from the shell prompt type:
-
~~~ sh
$ nvim FILENAME
~~~
-
- 3. To exit Vim type: `<Esc>`{normal} `:q!`{vim} `<Enter>`{normal} to trash
- all changes.
- OR type: `<Esc>`{normal} `:wq`{vim} `<Enter>`{normal} to save
- the changes.
+ 3. To exit Vim type: `<Esc>`{normal} `:q!`{vim} `<Enter>`{normal} to trash all changes.
+ OR type: `<Esc>`{normal} `:wq`{vim} `<Enter>`{normal} to save the changes.
4. To delete the character at the cursor type: `x`{normal}
@@ -239,8 +235,7 @@ Somebody typed the end of this line twice. end of this line twice.
# Lesson 2.3: ON OPERATORS AND MOTIONS
-Many commands that change text are made from an [operator](operator) and
-a [motion](navigation).
+Many commands that change text are made from an [operator](operator) and a [motion](navigation).
The format for a delete command with the [d](d) delete operator is as follows:
d motion
@@ -318,16 +313,13 @@ it would be easier to simply type two d's to delete a line.
** Press `u`{normal} to undo the last commands, `U`{normal} to fix a whole line. **
- 1. Move the cursor to the line below marked ✗ and place it on the
- first error.
+ 1. Move the cursor to the line below marked ✗ and place it on the first error.
2. Type `x`{normal} to delete the first unwanted character.
3. Now type `u`{normal} to undo the last command executed.
4. This time fix all the errors on the line using the `x`{normal} command.
5. Now type a capital `U`{normal} to return the line to its original state.
- 6. Now type `u`{normal} a few times to undo the `U`{normal} and preceding
- commands.
- 7. Now type `<C-r>`{normal} (Control + R) a few times to redo the commands
- (undo the undos).
+ 6. Now type `u`{normal} a few times to undo the `U`{normal} and preceding commands.
+ 7. Now type `<C-r>`{normal} (Control + R) a few times to redo the commands.
Fiix the errors oon thhis line and reeplace them witth undo.
@@ -341,11 +333,14 @@ Fiix the errors oon thhis line and reeplace them witth undo.
4. To repeat a motion prepend it with a number: `2w`{normal}
5. The format for a change command is:
- operator [number] motion
+
+ operator [number] motion
+
where:
- operator - is what to do, such as [d](d) for delete
- [number] - is an optional count to repeat the motion
- motion - moves over the text to operate on, such as:
+
+ operator - is what to do, such as [d](d) for delete
+ [number] - is an optional count to repeat the motion
+ motion - moves over the text to operate on, such as:
[w](w) (word),
[$]($) (to the end of line), etc.
@@ -403,8 +398,7 @@ NOTE: Remember that you should be learning by doing, not memorization.
3. Type `ce`{normal} and the correct word (in this case, type "ine" ).
- 4. Press `<Esc>`{normal} and move to the next character that needs to be
- changed.
+ 4. Press `<Esc>`{normal} and move to the next character that needs to be changed.
5. Repeat steps 3 and 4 until the first sentence is the same as the second.
@@ -419,7 +413,7 @@ Notice that [c](c)e deletes the word and places you in Insert mode.
1. The change operator works in the same way as delete. The format is:
- c [number] motion
+ c [number] motion
2. The motions are the same, such as `w`{normal} (word) and `$`{normal} (end of line).
@@ -449,7 +443,7 @@ NOTE: You can use the Backspace key to correct mistakes while typing.
4. The format for change is:
- c [number] motion
+ c [number] motion
Now go on to the next lesson.
@@ -460,13 +454,13 @@ Now go on to the next lesson.
NOTE: Read this entire lesson before executing any of the steps!!
- 1. Hold down the `<Ctrl>`{normal} key and press `g`{normal}. We call this
- `<C-g>`{normal}. A message will appear at the bottom of the page with the
- filename and the position in the file. Remember the line number for
- Step 3.
+ 1. Hold down the `<Ctrl>`{normal} key and press `g`{normal}. We call this `<C-g>`{normal}.
+ A message will appear at the bottom of the page with the filename and
+ the position in the file. Remember the line number for Step 3.
NOTE: You may see the cursor position in the lower right corner of the
screen. This happens when the ['ruler']('ruler') option is set.
+
2. Press [G](G) to move you to the bottom of the file.
Type [gg](gg) to move you to the start of the file.
@@ -482,17 +476,16 @@ NOTE: You may see the cursor position in the lower right corner of the
1. In Normal mode type the `/`{normal} character. Notice that it and the
cursor appear at the bottom of the screen as with the `:`{normal} command.
- 2. Now type 'errroor' `<Enter>`{normal}. This is the word you want to search
- for.
+ 2. Now type 'errroor' `<Enter>`{normal}. This is the word you want to search for.
3. To search for the same phrase again, simply type [n](n).
To search for the same phrase in the opposite direction, type [N](N).
- 4. To search for a phrase in the backward direction, use [?](?) instead
- of `/`{normal}.
+ 4. To search for a phrase in the backward direction, use [?](?) instead of `/`{normal}.
- 5. To go back to where you came from press `<C-o>`{normal} (keep `<Ctrl>`{normal} pressed down while pressing the letter `o`{normal}). Repeat to go back
- further. `<C-i>`{normal} goes forward.
+ 5. To go back to where you came from press `<C-o>`{normal}.
+ (keep `<Ctrl>`{normal} pressed down while pressing the letter `o`{normal}).
+ Repeat to go back further. `<C-i>`{normal} goes forward.
"errroor" is not the way to spell error; errroor is an error.
@@ -525,16 +518,14 @@ NOTE: This is very useful in debugging a program with unmatched parentheses!
2. Type
~~~ cmd
- :s/thee/the/
+ :s/thee/the/
~~~
-
- NOTE that the [:s](:s) command only changed the first occurrence of "thee" in the line.
+ NOTE: the [:s](:s) command only changed the first match of "thee" in the line.
3. Now type
~~~ cmd
- :s/thee/the/g
+ :s/thee/the/g
~~~
-
Adding the g [flag](:s_flags) means to substitute globally in the line,
change all occurrences of "thee" in the line.
@@ -542,20 +533,20 @@ Usually thee best time to see thee flowers is in thee spring.
4. To change every occurrence of a character string between two lines, type
~~~ cmd
- :#,#s/old/new/g
+ :#,#s/old/new/g
~~~
where #,# are the line numbers of the range of lines where the
substitution is to be done.
Type
~~~ cmd
- :%s/old/new/g
+ :%s/old/new/g
~~~
to change every occurrence in the whole file.
Type
~~~ cmd
- :%s/old/new/gc
+ :%s/old/new/gc
~~~
to find every occurrence in the whole file, with a prompt whether to
substitute or not.
@@ -564,7 +555,7 @@ Usually thee best time to see thee flowers is in thee spring.
1. `<C-g>`{normal} displays your location and the file status.
`G`{normal} moves to the end of the file.
- number `G`{normal} moves to that line number.
+ number `G`{normal} moves to that line number.
`gg`{normal} moves to the first line.
2. Typing `/`{normal} followed by a phrase searches FORWARD for the phrase.
@@ -643,7 +634,6 @@ NOTE: If you were to exit Vim and start it again with `nvim TEST`, the file
~~~ cmd
:!rm TEST
~~~
-
# Lesson 5.3: SELECTING TEXT TO WRITE
** To save part of the file, type `v`{normal} motion `:w FILENAME`{vim}. **
@@ -655,7 +645,7 @@ NOTE: If you were to exit Vim and start it again with `nvim TEST`, the file
3. Press the `:`{normal} character. At the bottom of the screen
- :'<,'>
+ `:'<,'>`{vim}
will appear.
@@ -669,12 +659,12 @@ NOTE: If you were to exit Vim and start it again with `nvim TEST`, the file
before you press `<Enter>`{normal}.
- 5. Vim will write the selected lines to the file TEST. Use `:!ls`{vim} to see it. Do not remove it yet! We will use it in the next lesson.
+ 5. Vim will write the selected lines to the file TEST. Use `:!ls`{vim} to see it.
+ Do not remove it yet! We will use it in the next lesson.
-NOTE: Pressing [v](v) starts [Visual selection](visual-mode). You can move
- the cursor around to make the selection bigger or smaller. Then you can
- use an operator to do something with the text. For example, `d`{normal}
- deletes the text.
+NOTE: Pressing [v](v) starts [Visual selection](visual-mode). You can move the cursor around to
+ make the selection bigger or smaller. Then you can use an operator to
+ do something with the text. For example, `d`{normal} deletes the text.
# Lesson 5.4: RETRIEVING AND MERGING FILES
@@ -689,8 +679,8 @@ NOTE: After executing Step 2 you will see text from Lesson 5.3. Then move
`:r TEST`{vim}
- where TEST is the name of the file you used.
- The file you retrieve is placed below the cursor line.
+ where TEST is the name of the file you used.
+ The file you retrieve is placed below the cursor line.
3. To verify that a file was retrieved, cursor back and notice that there
are now two copies of Lesson 5.3, the original and the file version.
@@ -706,20 +696,20 @@ NOTE: You can also read the output of an external command. For example,
1. [:!command](:!cmd) executes an external command.
Some useful examples are:
- `:!ls`{vim} - shows a directory listing
- `:!rm FILENAME`{vim} - removes file FILENAME
+ `:!ls`{vim} - shows a directory listing
+ `:!rm FILENAME`{vim} - removes file FILENAME
- 2. [:w](:w) FILENAME writes the current Vim file to disk with
- name FILENAME.
+ 2. [:w](:w) FILENAME writes the current Vim file to disk with
+ name FILENAME.
3. [v](v) motion :w FILENAME saves the Visually selected lines in file
FILENAME.
- 4. [:r](:r) FILENAME retrieves disk file FILENAME and puts it
- below the cursor position.
+ 4. [:r](:r) FILENAME retrieves disk file FILENAME and puts it
+ below the cursor position.
- 5. [:r !dir](:r!) reads the output of the dir command and
- puts it below the cursor position.
+ 5. [:r !dir](:r!) reads the output of the dir command and
+ puts it below the cursor position.
# Lesson 6.1: THE OPEN COMMAND
@@ -747,14 +737,11 @@ Open up a line above this by typing O while the cursor is on this line.
2. Press `e`{normal} until the cursor is on the end of "li".
- 3. Type the lowercase letter `a`{normal} to [append](a) text AFTER the
- cursor.
+ 3. Type the lowercase letter `a`{normal} to [append](a) text AFTER the cursor.
- 4. Complete the word like the line below it. Press `<Esc>`{normal} to exit
- Insert mode.
+ 4. Complete the word like the line below it. Press `<Esc>`{normal} to exit Insert mode.
- 5. Use `e`{normal} to move to the next incomplete word and repeat steps 3
- and 4.
+ 5. Use `e`{normal} to move to the next incomplete word and repeat steps 3 and 4.
This li will allow you to pract appendi text to a line.
This line will allow you to practice appending text to a line.
@@ -767,21 +754,21 @@ NOTE: [a](a), [i](i) and [A](A) all go to the same Insert mode, the only
** Type a capital `R`{normal} to replace more than one character. **
1. Move the cursor to the first line below marked ✗. Move the cursor to
- the beginning of the first "xxx".
+ the beginning of the first "xxx".
2. Now press `R`{normal} ([capital R](R)) and type the number below it in the
- second line, so that it replaces the "xxx".
+ second line, so that it replaces the "xxx".
3. Press `<Esc>`{normal} to leave [Replace mode](mode-replace). Notice that
- the rest of the line remains unmodified.
+ the rest of the line remains unmodified.
4. Repeat the steps to replace the remaining "xxx".
Adding 123 to xxx gives you xxx.
Adding 123 to 456 gives you 579.
-NOTE: Replace mode is like Insert mode, but every typed character deletes an
- existing character.
+NOTE: Replace mode is like Insert mode, but every typed character
+ deletes an existing character.
# Lesson 6.4: COPY AND PASTE TEXT
@@ -875,17 +862,17 @@ NOTE: If you want to ignore case for just one search command, use [\c](/\c)
~~~ cmd
:set invic
~~~
-
# Lesson 7.1: GETTING HELP
** Use the on-line help system. **
-Vim has a comprehensive on-line help system. To get started, try one of
-these three:
- - press the `<HELP>`{normal} key (if you have one)
- - press the `<F1>`{normal} key (if you have one)
- - type
- `:help`{vim}
+Vim has a comprehensive on-line help system.
+
+To get started, try one of these three:
+
+ - press the `<HELP>`{normal} key (if you have one)
+ - press the `<F1>`{normal} key (if you have one)
+ - type `:help`{vim}
Read the text in the help window to find out how the help works.
Type `<C-w><C-w>`{normal} to jump from one window to another.
@@ -907,10 +894,12 @@ Vim has many more features than Vi, but most of them are disabled by
default. To start using more features you have to create a "vimrc" file.
1. Start editing the "vimrc" file.
+
`:call mkdir(stdpath('config'),'p')`{vim}
`:exe 'edit' stdpath('config').'/init.vim'`{vim}
2. Write the file with:
+
`:w`{vim}
You can add all your preferred settings to this "vimrc" file.
@@ -924,17 +913,15 @@ default. To start using more features you have to create a "vimrc" file.
2. Type the start of a command: `:e`{vim}
- 3. Press `<C-d>`{normal} and Vim will show a list of commands that start
- with "e".
+ 3. Press `<C-d>`{normal} and Vim will show a list of commands beginning with "e".
4. Press `<Tab>`{normal} and Vim will complete the command name to ":edit".
5. Now add a space and the start of an existing file name: `:edit FIL`{vim}
- 6. Press `<Tab>`{normal}. Vim will complete the name (if it is unique).
+ 6. Press `<Tab>`{normal}. Vim will complete the name ("FIL" -> "FILE", if it is unique).
-NOTE: Completion works for many commands. It is especially useful for
- `:help`{vim}.
+NOTE: Completion works for many commands. It is especially useful for `:help`{vim}.
# Lesson 7 SUMMARY
@@ -950,7 +937,7 @@ NOTE: Completion works for many commands. It is especially useful for
5. Create a vimrc startup script to keep your preferred settings.
6. While in command mode, press `<C-d>`{normal} to see possible completions.
- Press `<Tab>`{normal} to use one completion.
+ Press `<Tab>`{normal} to use one completion.
# CONCLUSION
@@ -961,13 +948,20 @@ many many more commands. Consult the help often.
There are many resources online to learn more about vim. Here's a bunch of
them:
-- *Learn Vim Progressively*: http://yannesposito.com/Scratch/en/blog/Learn-Vim-Progressively/
-- *Learning Vim in 2014*: http://benmccormick.org/learning-vim-in-2014/
-- *Vimcasts*: http://vimcasts.org/
-- *Vim Video-Tutorials by Derek Wyatt*: http://derekwyatt.org/vim/tutorials/
-- *Learn Vimscript the Hard Way*: http://learnvimscriptthehardway.stevelosh.com/
-- *7 Habits of Effective Text Editing*: http://www.moolenaar.net/habits.html
-- *vim-galore*: https://github.com/mhinz/vim-galore
+- *Learn Vim Progressively*:
+ http://yannesposito.com/Scratch/en/blog/Learn-Vim-Progressively/
+- *Learning Vim in 2013*:
+ http://benmccormick.org/learning-vim-in-2014/
+- *Vimcasts*:
+ http://vimcasts.org/
+- *Vim Video-Tutorials by Derek Wyatt*:
+ http://derekwyatt.org/vim/tutorials/
+- *Learn Vimscript the Hard Way*:
+ http://learnvimscriptthehardway.stevelosh.com/
+- *7 Habits of Effective Text Editing*:
+ http://www.moolenaar.net/habits.html
+- *vim-galore*:
+ https://github.com/mhinz/vim-galore
If you prefer a book, *Practical Vim* by Drew Neil is recommended often
(the sequel, *Modern Vim*, includes material specific to nvim).
@@ -978,3 +972,5 @@ University. E-mail: bware@mines.colorado.edu.
Modified for Vim by Bram Moolenaar.
Modified for vim-tutor-mode by Felipe Morales.
+
+// vim: nowrap
diff --git a/runtime/tutor/en/vim-01-beginner.tutor.json b/runtime/tutor/en/vim-01-beginner.tutor.json
index af22cf2aca..e71ead976d 100644
--- a/runtime/tutor/en/vim-01-beginner.tutor.json
+++ b/runtime/tutor/en/vim-01-beginner.tutor.json
@@ -1,45 +1,45 @@
{
"expect": {
- "24": -1,
+ "25": -1,
"103": "The cow jumped over the moon.",
- "124": "There is some text missing from this line.",
"125": "There is some text missing from this line.",
- "144": "There is some text missing from this line.",
+ "126": "There is some text missing from this line.",
"145": "There is some text missing from this line.",
- "146": "There is also some text missing here.",
+ "146": "There is some text missing from this line.",
"147": "There is also some text missing here.",
- "220": "There are some words that don't belong in this sentence.",
- "236": "Somebody typed the end of this line twice.",
- "276": -1,
- "295": "This line of words is cleaned up.",
+ "148": "There is also some text missing here.",
+ "216": "There are some words that don't belong in this sentence.",
+ "232": "Somebody typed the end of this line twice.",
+ "271": -1,
+ "290": "This line of words is cleaned up.",
+ "304": -1,
+ "305": -1,
+ "306": -1,
+ "307": -1,
+ "308": -1,
"309": -1,
"310": -1,
- "311": -1,
- "312": -1,
- "313": -1,
- "314": -1,
- "315": -1,
- "332": "Fix the errors on this line and replace them with undo.",
- "372": -1,
- "373": -1,
- "374": -1,
- "375": -1,
- "389": "When this line was typed in, someone pressed some wrong keys!",
- "390": "When this line was typed in, someone pressed some wrong keys!",
- "411": "This line has a few words that need changing using the change operator.",
- "412": "This line has a few words that need changing using the change operator.",
- "432": "The end of this line needs to be corrected using the `c$` command.",
- "433": "The end of this line needs to be corrected using the `c$` command.",
- "497": -1,
- "516": -1,
- "541": "Usually the best time to see the flowers is in the spring.",
- "735": -1,
- "740": -1,
- "759": "This line will allow you to practice appending text to a line.",
- "760": "This line will allow you to practice appending text to a line.",
- "780": "Adding 123 to 456 gives you 579.",
- "781": "Adding 123 to 456 gives you 579.",
- "807": "a) This is the first item.",
- "808": "b) This is the second item."
+ "324": "Fix the errors on this line and replace them with undo.",
+ "367": -1,
+ "368": -1,
+ "369": -1,
+ "370": -1,
+ "384": "When this line was typed in, someone pressed some wrong keys!",
+ "385": "When this line was typed in, someone pressed some wrong keys!",
+ "405": "This line has a few words that need changing using the change operator.",
+ "406": "This line has a few words that need changing using the change operator.",
+ "426": "The end of this line needs to be corrected using the `c$` command.",
+ "427": "The end of this line needs to be corrected using the `c$` command.",
+ "490": -1,
+ "509": -1,
+ "532": "Usually the best time to see the flowers is in the spring.",
+ "725": -1,
+ "730": -1,
+ "746": "This line will allow you to practice appending text to a line.",
+ "747": "This line will allow you to practice appending text to a line.",
+ "767": "Adding 123 to 456 gives you 579.",
+ "768": "Adding 123 to 456 gives you 579.",
+ "794": "a) This is the first item.",
+ "795": "b) This is the second item."
}
}
diff --git a/scripts/finddeclarations.pl b/scripts/finddeclarations.pl
deleted file mode 100755
index 1b1a57b9b7..0000000000
--- a/scripts/finddeclarations.pl
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-use warnings;
-
-if ($ARGV[0] eq '--help') {
- print << "EOF";
-Usage:
-
- $0 definitions.c
-EOF
- exit;
-}
-
-my ($cfname, $sfname, $gfname, $cpp) = @ARGV;
-
-my $F;
-
-open $F, "<", $cfname;
-
-my $text = join "", <$F>;
-
-close $F;
-
-my $s = qr/(?>\s*)/aso;
-my $w = qr/(?>\w+)/aso;
-my $argname = qr/$w(?:\[(?>\w+)\])?/aso;
-my $type_regex = qr/(?:$w$s\**$s)+/aso;
-my $arg_regex = qr/(?:$type_regex$s$argname)/aso;
-
-while ($text =~ /
- (?<=\n) # Definition starts at the start of line
- $type_regex # Return type
- $s$w # Function name
- $s\($s
- (?:
- $arg_regex(?:$s,$s$arg_regex)*+
- ($s,$s\.\.\.)? # varargs function
- |void
- )?
- $s\)
- (?:$s FUNC_ATTR_$w(?:\((?>[^)]*)\))?)*+ # Optional attributes
- (?=$s;) # Ending semicolon
- /axsogp) {
- my $match = "${^MATCH}";
- my $s = "${^PREMATCH}";
- $s =~ s/[^\n]++//g;
- my $line = 1 + length $s;
- print "${cfname}:${line}: $match\n";
-}
diff --git a/scripts/gen_vimdoc.py b/scripts/gen_vimdoc.py
index 18a2839702..36e01153f1 100755
--- a/scripts/gen_vimdoc.py
+++ b/scripts/gen_vimdoc.py
@@ -123,11 +123,13 @@ CONFIG = {
'vim.lua',
'shared.lua',
'uri.lua',
+ 'ui.lua',
],
'files': ' '.join([
os.path.join(base_dir, 'src/nvim/lua/vim.lua'),
os.path.join(base_dir, 'runtime/lua/vim/shared.lua'),
os.path.join(base_dir, 'runtime/lua/vim/uri.lua'),
+ os.path.join(base_dir, 'runtime/lua/vim/ui.lua'),
]),
'file_patterns': '*.lua',
'fn_name_prefix': '',
@@ -141,6 +143,7 @@ CONFIG = {
# `shared` functions are exposed on the `vim` module.
'shared': 'vim',
'uri': 'vim',
+ 'ui': 'vim.ui',
},
'append_only': [
'shared.lua',
@@ -187,6 +190,23 @@ CONFIG = {
'module_override': {},
'append_only': [],
},
+ 'diagnostic': {
+ 'mode': 'lua',
+ 'filename': 'diagnostic.txt',
+ 'section_start_token': '*diagnostic-api*',
+ 'section_order': [
+ 'diagnostic.lua',
+ ],
+ 'files': os.path.join(base_dir, 'runtime/lua/vim/diagnostic.lua'),
+ 'file_patterns': '*.lua',
+ 'fn_name_prefix': '',
+ 'section_name': {'diagnostic.lua': 'diagnostic'},
+ 'section_fmt': lambda _: 'Lua module: vim.diagnostic',
+ 'helptag_fmt': lambda _: '*diagnostic-api*',
+ 'fn_helptag_fmt': lambda fstem, name: f'*vim.{fstem}.{name}()*',
+ 'module_override': {},
+ 'append_only': [],
+ },
'treesitter': {
'mode': 'lua',
'filename': 'treesitter.txt',
@@ -197,7 +217,6 @@ CONFIG = {
'query.lua',
'highlighter.lua',
'languagetree.lua',
- 'health.lua',
],
'files': ' '.join([
os.path.join(base_dir, 'runtime/lua/vim/treesitter.lua'),
@@ -950,6 +969,8 @@ def main(config, args):
os.remove(mpack_file)
output_dir = out_dir.format(target=target)
+ log.info("Generating documentation for %s in folder %s",
+ target, output_dir)
debug = args.log_level >= logging.DEBUG
p = subprocess.Popen(
['doxygen', '-'],
@@ -1105,7 +1126,8 @@ def filter_source(filename):
def parse_args():
targets = ', '.join(CONFIG.keys())
- ap = argparse.ArgumentParser()
+ ap = argparse.ArgumentParser(
+ description="Generate helpdoc from source code")
ap.add_argument(
"--log-level", "-l", choices=LOG_LEVELS.keys(),
default=logging.getLevelName(logging.ERROR), help="Set log verbosity"
@@ -1128,7 +1150,7 @@ Doxyfile = textwrap.dedent('''
INPUT_FILTER = "{filter}"
EXCLUDE =
EXCLUDE_SYMLINKS = NO
- EXCLUDE_PATTERNS = */private/*
+ EXCLUDE_PATTERNS = */private/* */health.lua */_*.lua
EXCLUDE_SYMBOLS =
EXTENSION_MAPPING = lua=C
EXTRACT_PRIVATE = NO
@@ -1159,6 +1181,7 @@ if __name__ == "__main__":
print("Setting log level to %s" % args.log_level)
args.log_level = LOG_LEVELS[args.log_level]
log.setLevel(args.log_level)
+ log.addHandler(logging.StreamHandler())
if len(args.source_filter) > 0:
filter_source(args.source_filter[0])
diff --git a/scripts/genvimvim.lua b/scripts/genvimvim.lua
index 2c3701bf0c..ff60b6cce7 100644
--- a/scripts/genvimvim.lua
+++ b/scripts/genvimvim.lua
@@ -1,4 +1,4 @@
-mpack = require('mpack')
+local mpack = require('mpack')
if arg[1] == '--help' then
print('Usage: lua genvimvim.lua src/nvim runtime/syntax/vim/generated.vim')
@@ -52,7 +52,7 @@ local function is_autocmd_cmd(cmd)
or cmd == 'doautoall')
end
-vimcmd_start = 'syn keyword vimCommand contained '
+local vimcmd_start = 'syn keyword vimCommand contained '
w(vimcmd_start)
local prev_cmd = nil
for _, cmd_desc in ipairs(ex_cmds.cmds) do
@@ -123,9 +123,8 @@ end
w('\n\nsyn case match')
local vimfun_start = 'syn keyword vimFuncName contained '
w('\n\n' .. vimfun_start)
-funcs = mpack.unpack(io.open(funcs_file, 'rb'):read("*all"))
-local started = 0
-for name, def in pairs(funcs) do
+local funcs = mpack.unpack(io.open(funcs_file, 'rb'):read("*all"))
+for name, _ in pairs(funcs) do
if name then
if lld.line_length > 850 then
w('\n' .. vimfun_start)
diff --git a/scripts/lintcommit.lua b/scripts/lintcommit.lua
new file mode 100644
index 0000000000..98f9da246c
--- /dev/null
+++ b/scripts/lintcommit.lua
@@ -0,0 +1,205 @@
+-- Usage:
+-- # verbose
+-- nvim -es +"lua require('scripts.lintcommit').main()"
+--
+-- # silent
+-- nvim -es +"lua require('scripts.lintcommit').main({trace=false})"
+--
+-- # self-test
+-- nvim -es +"lua require('scripts.lintcommit')._test()"
+
+local M = {}
+
+local _trace = false
+
+-- Print message
+local function p(s)
+ vim.cmd('set verbose=1')
+ vim.api.nvim_echo({{s, ''}}, false, {})
+ vim.cmd('set verbose=0')
+end
+
+local function die()
+ p('')
+ vim.cmd("cquit 1")
+end
+
+-- Executes and returns the output of `cmd`, or nil on failure.
+--
+-- Prints `cmd` if `trace` is enabled.
+local function run(cmd, or_die)
+ if _trace then
+ p('run: '..vim.inspect(cmd))
+ end
+ local rv = vim.trim(vim.fn.system(cmd)) or ''
+ if vim.v.shell_error ~= 0 then
+ if or_die then
+ p(rv)
+ die()
+ end
+ return nil
+ end
+ return rv
+end
+
+-- Returns nil if the given commit message is valid, or returns a string
+-- message explaining why it is invalid.
+local function validate_commit(commit_message)
+ local commit_split = vim.split(commit_message, ":")
+
+ -- Return true if the type is vim-patch since most of the normal rules don't
+ -- apply.
+ if commit_split[1] == "vim-patch" then
+ return nil
+ end
+
+ -- Check that message isn't too long.
+ if commit_message:len() > 80 then
+ return [[Commit message is too long, a maximum of 80 characters is allowed.]]
+ end
+
+
+ if vim.tbl_count(commit_split) < 2 then
+ return [[Commit message does not include colons.]]
+ end
+
+ local before_colon = commit_split[1]
+ local after_colon = commit_split[2]
+
+ -- Check if commit introduces a breaking change.
+ if vim.endswith(before_colon, "!") then
+ before_colon = before_colon:sub(1, -2)
+ end
+
+ -- 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'}
+ if not vim.tbl_contains(allowed_types, type) then
+ return string.format(
+ 'Invalid commit type "%s". Allowed types are:\n %s',
+ type,
+ vim.inspect(allowed_types))
+ end
+
+ -- Check if scope is empty
+ if before_colon:match("%(") then
+ local scope = vim.trim(before_colon:match("%((.*)%)"))
+ if scope == '' then
+ return [[Scope can't be empty.]]
+ end
+ end
+
+ -- Check that description doesn't end with a period
+ if vim.endswith(after_colon, ".") then
+ return [[Description ends with a period (".").]]
+ end
+
+ -- Check that description has exactly one whitespace after colon, followed by
+ -- a lowercase letter and then any number of letters.
+ if not string.match(after_colon, '^ %l%a*') then
+ return [[There should be one whitespace after the colon and the first letter should lowercase.]]
+ end
+
+ return nil
+end
+
+function M.main(opt)
+ _trace = not opt or not not opt.trace
+
+ local branch = run({'git', 'branch', '--show-current'}, true)
+ -- TODO(justinmk): check $GITHUB_REF
+ local ancestor = run({'git', 'merge-base', 'origin/master', branch})
+ if not ancestor then
+ ancestor = run({'git', 'merge-base', 'upstream/master', branch})
+ end
+ local commits_str = run({'git', 'rev-list', ancestor..'..'..branch}, true)
+
+ local commits = {}
+ for substring in commits_str:gmatch("%S+") do
+ table.insert(commits, substring)
+ end
+
+ local failed = 0
+ for _, commit_id in ipairs(commits) do
+ local msg = run({'git', 'show', '-s', '--format=%s' , commit_id})
+ if vim.v.shell_error ~= 0 then
+ p('Invalid commit-id: '..commit_id..'"')
+ else
+ local invalid_msg = validate_commit(msg)
+ if invalid_msg then
+ failed = failed + 1
+ p(string.format([[
+Invalid commit message: "%s"
+ Commit: %s
+ %s
+ See also:
+ https://github.com/neovim/neovim/blob/master/CONTRIBUTING.md#commit-messages
+ https://www.conventionalcommits.org/en/v1.0.0/
+]],
+ msg,
+ commit_id,
+ invalid_msg))
+ end
+ end
+ end
+
+ if failed > 0 then
+ die() -- Exit with error.
+ else
+ p('')
+ end
+end
+
+function M._test()
+ -- message:expected_result
+ local test_cases = {
+ ['ci: normal message'] = true,
+ ['build: normal message'] = true,
+ ['docs: normal message'] = true,
+ ['feat: normal message'] = true,
+ ['fix: normal message'] = true,
+ ['perf: normal message'] = true,
+ ['refactor: normal message'] = true,
+ ['revert: normal message'] = true,
+ ['test: normal message'] = true,
+ ['chore: normal message'] = true,
+ ['ci(window): message with scope'] = true,
+ ['ci!: message with breaking change'] = true,
+ ['ci(tui)!: message with scope and breaking change'] = true,
+ ['vim-patch:8.2.3374: Pyret files are not recognized (#15642)'] = true,
+ ['vim-patch:8.1.1195,8.2.{3417,3419}'] = true,
+ [':no type before colon 1'] = false,
+ [' :no type before colon 2'] = false,
+ [' :no type before colon 3'] = false,
+ ['ci(empty description):'] = false,
+ ['ci(whitespace as description): '] = false,
+ ['docs(multiple whitespaces as description): '] = false,
+ ['ci no colon after type'] = false,
+ ['test: extra space after colon'] = false,
+ ['ci: tab after colon'] = false,
+ ['ci:no space after colon'] = false,
+ ['ci :extra space before colon'] = false,
+ ['refactor(): empty scope'] = false,
+ ['ci( ): whitespace as scope'] = false,
+ ['chore: 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,
+ }
+
+ local failed = 0
+ for message, expected in pairs(test_cases) do
+ local is_valid = (nil == validate_commit(message))
+ if is_valid ~= expected then
+ failed = failed + 1
+ p(string.format('[ FAIL ]: expected=%s, got=%s\n input: "%s"', expected, is_valid, message))
+ end
+ end
+
+ if failed > 0 then
+ die() -- Exit with error.
+ end
+
+end
+
+return M
diff --git a/scripts/lua2dox.lua b/scripts/lua2dox.lua
index 0b36a1e061..d110e34c6a 100644
--- a/scripts/lua2dox.lua
+++ b/scripts/lua2dox.lua
@@ -50,7 +50,7 @@ However I have put in a hack that will insert the "missing" close paren.
The effect is that you will get the function documented, but not with the parameter list you might expect.
]]
-function class(BaseClass, ClassInitialiser)
+local function class(BaseClass, ClassInitialiser)
local newClass = {} -- a new class newClass
if not ClassInitialiser and type(BaseClass) == 'function' then
ClassInitialiser = BaseClass
@@ -68,15 +68,14 @@ function class(BaseClass, ClassInitialiser)
-- expose a constructor which can be called by <classname>(<args>)
local classMetatable = {}
- classMetatable.__call =
- function(class_tbl, ...)
+ classMetatable.__call = function(class_tbl, ...)
local newInstance = {}
setmetatable(newInstance,newClass)
--if init then
-- init(newInstance,...)
if class_tbl.init then
class_tbl.init(newInstance,...)
- else
+ else
-- make sure that any stuff from the base class is initialized!
if BaseClass and BaseClass.init then
BaseClass.init(newInstance, ...)
@@ -85,10 +84,9 @@ function class(BaseClass, ClassInitialiser)
return newInstance
end
newClass.init = ClassInitialiser
- newClass.is_a =
- function(this, klass)
+ newClass.is_a = function(this, klass)
local thisMetatable = getmetatable(this)
- while thisMetatable do
+ while thisMetatable do
if thisMetatable == klass then
return true
end
@@ -102,12 +100,13 @@ end
--! \class TCore_Clock
--! \brief a clock
-TCore_Clock = class()
+local TCore_Clock = class()
--! \brief get the current time
function TCore_Clock.GetTimeNow()
- if os.gettimeofday then
- return os.gettimeofday()
+ local gettimeofday = os.gettimeofday -- luacheck: ignore 143 Accessing an undefined field of a global variable.
+ if gettimeofday then
+ return gettimeofday()
else
return os.time()
end
@@ -134,20 +133,15 @@ function TCore_Clock.getTimeStamp(this,T0)
end
---! \brief io to console
---!
---! pseudo class (no methods, just to keep documentation tidy)
-TCore_IO = class()
---
--! \brief write to stdout
-function TCore_IO_write(Str)
+local function TCore_IO_write(Str)
if (Str) then
io.write(Str)
end
end
--! \brief write to stdout
-function TCore_IO_writeln(Str)
+local function TCore_IO_writeln(Str)
if (Str) then
io.write(Str)
end
@@ -156,16 +150,16 @@ end
--! \brief trims a string
-function string_trim(Str)
+local function string_trim(Str)
return Str:match("^%s*(.-)%s*$")
end
--! \brief split a string
---!
+--!
--! \param Str
--! \param Pattern
--! \returns table of string fragments
-function string_split(Str, Pattern)
+local function string_split(Str, Pattern)
local splitStr = {}
local fpat = "(.-)" .. Pattern
local last_end = 1
@@ -187,7 +181,7 @@ end
--! \class TCore_Commandline
--! \brief reads/parses commandline
-TCore_Commandline = class()
+local TCore_Commandline = class()
--! \brief constructor
function TCore_Commandline.init(this)
@@ -207,29 +201,21 @@ end
-------------------------------
--! \brief file buffer
---!
+--!
--! an input file buffer
-TStream_Read = class()
+local TStream_Read = class()
--! \brief get contents of file
---!
+--!
--! \param Filename name of file to read (or nil == stdin)
function TStream_Read.getContents(this,Filename)
+ assert(Filename)
-- get lines from file
- local filecontents
- if Filename then
- -- syphon lines to our table
- --TCore_Debug_show_var('Filename',Filename)
- filecontents={}
- for line in io.lines(Filename) do
- table.insert(filecontents,line)
- end
- else
- -- get stuff from stdin as a long string (with crlfs etc)
- filecontents=io.read('*a')
- -- make it a table of lines
- filecontents = TString_split(filecontents,'[\n]') -- note this only works for unix files.
- Filename = 'stdin'
+ -- syphon lines to our table
+ --TCore_Debug_show_var('Filename',Filename)
+ local filecontents={}
+ for line in io.lines(Filename) do
+ table.insert(filecontents,line)
end
if filecontents then
@@ -278,7 +264,7 @@ function TStream_Read.eof(this)
end
--! \brief output stream
-TStream_Write = class()
+local TStream_Write = class()
--! \brief constructor
function TStream_Write.init(this)
@@ -286,17 +272,17 @@ function TStream_Write.init(this)
end
--! \brief write immediately
-function TStream_Write.write(this,Str)
+function TStream_Write.write(_,Str)
TCore_IO_write(Str)
end
--! \brief write immediately
-function TStream_Write.writeln(this,Str)
+function TStream_Write.writeln(_,Str)
TCore_IO_writeln(Str)
end
--! \brief write immediately
-function TStream_Write.writelnComment(this,Str)
+function TStream_Write.writelnComment(_,Str)
TCore_IO_write('// ZZ: ')
TCore_IO_writeln(Str)
end
@@ -311,14 +297,14 @@ end
--! \brief outout tail lines
function TStream_Write.write_tailLines(this)
- for k,line in ipairs(this.tailLine) do
+ for _,line in ipairs(this.tailLine) do
TCore_IO_writeln(line)
end
TCore_IO_write('// Lua2DoX new eof')
end
--! \brief input filter
-TLua2DoX_filter = class()
+local TLua2DoX_filter = class()
--! \brief allow us to do errormessages
function TLua2DoX_filter.warning(this,Line,LineNo,Legend)
@@ -371,12 +357,12 @@ local function checkComment4fn(Fn_magic,MagicLines)
local macro,tail
- for k,line in ipairs(magicLines) do
+ for _, line in ipairs(magicLines) do
macro,tail = getMagicDirective(line)
if macro == 'fn' then
fn_magic = tail
-- TCore_IO_writeln('// found fn "' .. fn_magic .. '"')
- else
+ --else
--TCore_IO_writeln('// not found fn "' .. line .. '"')
end
end
@@ -385,8 +371,6 @@ local function checkComment4fn(Fn_magic,MagicLines)
end
--! \brief run the filter
function TLua2DoX_filter.readfile(this,AppStamp,Filename)
- local err
-
local inStream = TStream_Read()
local outStream = TStream_Write()
this.outStream = outStream -- save to this obj
@@ -401,8 +385,9 @@ function TLua2DoX_filter.readfile(this,AppStamp,Filename)
outStream:writelnTail('// #######################')
outStream:writelnTail()
- local state, offset = '', 0
- while not (err or inStream:eof()) do
+ local state = '' -- luacheck: ignore 231 variable is set but never accessed.
+ local offset = 0
+ while not (inStream:eof()) do
line = string_trim(inStream:getLine())
-- TCore_Debug_show_var('inStream',inStream)
-- TCore_Debug_show_var('line',line )
@@ -427,7 +412,7 @@ function TLua2DoX_filter.readfile(this,AppStamp,Filename)
line = string.sub(line,5) -- nibble head
local comment = ''
local closeSquare,hitend,thisComment
- while (not err) and (not hitend) and (not inStream:eof()) do
+ while (not hitend) and (not inStream:eof()) do
closeSquare = string.find(line,']]')
if not closeSquare then -- need to look on another line
thisComment = line .. '\n'
@@ -544,7 +529,7 @@ function TLua2DoX_filter.readfile(this,AppStamp,Filename)
end
--! \brief this application
-TApp = class()
+local TApp = class()
--! \brief constructor
function TApp.init(this)
@@ -556,16 +541,16 @@ function TApp.init(this)
end
function TApp.getRunStamp(this)
- return this.name .. ' (' .. this.version .. ') '
+ return this.name .. ' (' .. this.version .. ') '
.. this.timestamp
end
function TApp.getVersion(this)
- return this.name .. ' (' .. this.version .. ') '
+ return this.name .. ' (' .. this.version .. ') '
end
function TApp.getCopyright(this)
- return this.copyright
+ return this.copyright
end
local This_app = TApp()
diff --git a/scripts/pvscheck.sh b/scripts/pvscheck.sh
index f3371b485e..904ff81700 100755
--- a/scripts/pvscheck.sh
+++ b/scripts/pvscheck.sh
@@ -373,13 +373,13 @@ run_analysis() {(
analyze \
--lic-file PVS-Studio.lic \
--threads "$(get_jobs_num)" \
- --exclude-path src/nvim/xdiff \
+ --exclude-path src/xdiff \
--output-file PVS-studio.log \
--file build/compile_commands.json \
--sourcetree-root . || true
rm -rf PVS-studio.{xml,err,tsk,html.d}
- local plog_args="PVS-studio.log --srcRoot . --excludedCodes V011"
+ local plog_args="PVS-studio.log --srcRoot . --excludedCodes V011,V1042,V1051,V1074"
plog-converter $plog_args --renderTypes xml --output PVS-studio.xml
plog-converter $plog_args --renderTypes errorfile --output PVS-studio.err
plog-converter $plog_args --renderTypes tasklist --output PVS-studio.tsk
diff --git a/scripts/release.sh b/scripts/release.sh
index 4d1484b77a..4ec959d697 100755
--- a/scripts/release.sh
+++ b/scripts/release.sh
@@ -12,6 +12,7 @@
# - CMakeLists.txt: Unset NVIM_VERSION_PRERELEASE
# - CMakeLists.txt: Unset NVIM_API_PRERELEASE
# - Create test/functional/fixtures/api_level_N.mpack
+# - Add date and version to runtime/nvim.appdata.xml
# - Tag the commit.
# Create the "version bump" commit:
# - CMakeLists.txt: Set NVIM_VERSION_PRERELEASE to "-dev"
@@ -62,6 +63,10 @@ _do_release_commit() {
git add test/functional/fixtures/api_level_$__API_LEVEL.mpack
fi
+ $__sed -i.bk 's,(<releases>),\1\
+ <release date="'"${__DATE}"'" version="'"${__VERSION}"'"/>,' runtime/nvim.appdata.xml
+ git add runtime/nvim.appdata.xml
+
if ! test "$ARG1" = '--use-current-commit' ; then
echo "Building changelog since ${__LAST_TAG}..."
@@ -75,14 +80,12 @@ _do_release_commit() {
_do_bump_commit() {
$__sed -i.bk 's/(NVIM_VERSION_PRERELEASE) ""/\1 "-dev"/' CMakeLists.txt
$__sed -i.bk 's/set\((NVIM_VERSION_PATCH) [[:digit:]]/set(\1 ?/' CMakeLists.txt
- $__sed -i.bk 's,(<releases>),\1\
- <release date="'"${__DATE}"'" version="xxx"/>,' runtime/nvim.appdata.xml
rm CMakeLists.txt.bk
rm runtime/nvim.appdata.xml.bk
nvim +'/NVIM_VERSION' +1new +'exe "norm! iUpdate version numbers!!!"' \
- -O CMakeLists.txt runtime/nvim.appdata.xml
+ -O CMakeLists.txt
- git add CMakeLists.txt runtime/nvim.appdata.xml
+ git add CMakeLists.txt
git commit -m "$__BUMP_MSG"
}
@@ -92,11 +95,7 @@ fi
_do_bump_commit
echo "
Next steps:
- - Update runtime/nvim.appdata.xml on _master_
- Run tests/CI (version_spec.lua)!
- Push the tag:
git push --follow-tags
- - Update the 'stable' tag:
- git push --force upstream HEAD^:refs/tags/stable
- git fetch --tags
- Update website: index.html"
diff --git a/scripts/squash_typos.py b/scripts/squash_typos.py
new file mode 100644
index 0000000000..26be6010a2
--- /dev/null
+++ b/scripts/squash_typos.py
@@ -0,0 +1,223 @@
+#!/usr/bin/env python
+"""
+
+This script squashes a PR tagged with the "typo" label into a single, dedicated
+"squash PR".
+
+"""
+
+import subprocess
+import sys
+import os
+
+
+def get_authors_and_emails_from_pr():
+ """
+
+ Return all contributing authors and their emails for the PR on current branch.
+ This includes co-authors, meaning that if two authors are credited for a
+ single commit, which is possible with GitHub, then both will get credited.
+
+ """
+
+ # Get a list of all authors involved in the pull request (including co-authors).
+ authors = subprocess.check_output(
+ ["gh", "pr", "view", "--json", "commits", "--jq", ".[][].authors.[].name"],
+ text=True,
+ ).splitlines()
+
+ # Get a list of emails of the aforementioned authors.
+ emails = subprocess.check_output(
+ ["gh", "pr", "view", "--json", "commits", "--jq", ".[][].authors.[].email"],
+ text=True,
+ ).splitlines()
+
+ authors_and_emails_unique = {
+ (author, mail) for author, mail in zip(authors, emails)
+ }
+
+ return sorted(authors_and_emails_unique)
+
+
+def rebase_squash_branch_onto_pr():
+ """
+
+ Rebase current branch onto the PR.
+
+ """
+
+ # Check out the pull request.
+ subprocess.call(["gh", "pr", "checkout", os.environ["PR_NUMBER"]])
+
+ # Rebase onto master
+ default_branch = f"{os.environ['GITHUB_BASE_REF']}"
+ subprocess.check_call(["git", "rebase", default_branch])
+
+ # Change back to the original branch.
+ subprocess.call(["git", "switch", "-"])
+
+ # Rebase onto the pull request, aka include the commits in the pull request
+ # in the current branch. Abort with error message if rebase fails.
+
+ try:
+ subprocess.check_call(["git", "rebase", "-"])
+ except subprocess.CalledProcessError:
+ subprocess.call(["git", "rebase", "--abort"])
+ squash_url = subprocess.check_output(
+ ["gh", "pr", "view", "--json", "url", "--jq", ".url"], text=True
+ ).strip()
+
+ subprocess.call(
+ [
+ "gh",
+ "pr",
+ "comment",
+ os.environ["PR_NUMBER"],
+ "--body",
+ f"Your edit conflicts with an already scheduled fix \
+ ({squash_url}). Please check that batch PR whether your fix is \
+ already included; if not, then please wait until the batch PR \
+ is merged and then rebase your PR on top of master.",
+ ]
+ )
+
+ sys.exit(
+ f"\n\nERROR: Your edit conflicts with an already scheduled fix \
+{squash_url} \n\n"
+ )
+
+
+def rebase_squash_branch_onto_master():
+ """
+
+ Rebase current branch onto the master i.e. make sure current branch is up
+ to date. Abort on error.
+
+ """
+
+ default_branch = f"{os.environ['GITHUB_BASE_REF']}"
+ subprocess.check_call(["git", "rebase", default_branch])
+
+
+def squash_all_commits():
+ """
+
+ Squash all commits on the PR into a single commit. Credit all authors by
+ name and email.
+
+ """
+
+ default_branch = f"{os.environ['GITHUB_BASE_REF']}"
+ subprocess.call(["git", "reset", "--soft", default_branch])
+
+ authors_and_emails = get_authors_and_emails_from_pr()
+ commit_message_coauthors = "\n" + "\n".join(
+ [f"Co-authored-by: {i[0]} <{i[1]}>" for i in authors_and_emails]
+ )
+ subprocess.call(
+ ["git", "commit", "-m", "chore: typo fixes", "-m", commit_message_coauthors]
+ )
+
+
+def force_push(branch):
+ """
+
+ Like the name implies, force push <branch>.
+
+ """
+
+ gh_actor = os.environ["GITHUB_ACTOR"]
+ gh_token = os.environ["GITHUB_TOKEN"]
+ gh_repo = os.environ["GITHUB_REPOSITORY"]
+ subprocess.call(
+ [
+ "git",
+ "push",
+ "--force",
+ f"https://{gh_actor}:{gh_token}@github.com/{gh_repo}",
+ branch,
+ ]
+ )
+
+
+def checkout_branch(branch):
+ """
+
+ Create and checkout <branch>. Check if branch exists on remote, if so then
+ sync local branch to remote.
+
+ Return True if remote branch exists, else False.
+
+ """
+
+ # FIXME I'm not sure why the local branch isn't tracking the remote branch
+ # automatically. This works but I'm pretty sure it can be done in a more
+ # "elegant" fashion
+
+ show_ref_output = subprocess.check_output(["git", "show-ref"], text=True).strip()
+
+ if branch in show_ref_output:
+ subprocess.call(["git", "checkout", "-b", branch, f"origin/{branch}"])
+ return True
+
+ subprocess.call(["git", "checkout", "-b", branch])
+ return False
+
+
+def get_all_pr_urls(squash_branch_exists):
+ """
+
+ Return a list of URLs for the pull requests with the typo fixes. If a
+ squash branch exists then extract the URLs from the body text.
+
+ """
+
+ all_pr_urls = ""
+ if squash_branch_exists:
+ all_pr_urls += subprocess.check_output(
+ ["gh", "pr", "view", "--json", "body", "--jq", ".body"], text=True
+ )
+
+ all_pr_urls += subprocess.check_output(
+ ["gh", "pr", "view", os.environ["PR_NUMBER"], "--json", "url", "--jq", ".url"],
+ text=True,
+ ).strip()
+
+ return all_pr_urls
+
+
+def main():
+ squash_branch = "marvim/squash-typos"
+
+ squash_branch_exists = checkout_branch(squash_branch)
+
+ rebase_squash_branch_onto_master()
+ force_push(squash_branch)
+
+ rebase_squash_branch_onto_pr()
+ force_push(squash_branch)
+
+ subprocess.call(
+ [
+ "gh",
+ "pr",
+ "create",
+ "--fill",
+ "--head",
+ squash_branch,
+ "--title",
+ "chore: typo fixes (automated)",
+ ]
+ )
+
+ squash_all_commits()
+ force_push(squash_branch)
+
+ all_pr_urls = get_all_pr_urls(squash_branch_exists)
+ subprocess.call(["gh", "pr", "edit", "--add-label", "typo", "--body", all_pr_urls])
+
+ subprocess.call(["gh", "pr", "close", os.environ["PR_NUMBER"]])
+
+
+if __name__ == "__main__":
+ main()
diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh
index 4fd9711619..f4b817dfff 100755
--- a/scripts/vim-patch.sh
+++ b/scripts/vim-patch.sh
@@ -190,7 +190,7 @@ preprocess_patch() {
2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git a/src/\S*\<\%(testdir/\)\@<!\%('"${na_src}"'\)@norm! d/\v(^diff)|%$ ' +w +q "$file"
# Remove unwanted Vim doc files.
- local na_doc='channel\.txt\|netbeans\.txt\|os_\w\+\.txt\|term\.txt\|todo\.txt\|version\d\.txt\|sponsor\.txt\|intro\.txt\|tags'
+ local na_doc='channel\.txt\|netbeans\.txt\|os_\w\+\.txt\|term\.txt\|todo\.txt\|version\d\.txt\|vim9\.txt\|sponsor\.txt\|intro\.txt\|tags'
2>/dev/null $nvim --cmd 'set dir=/tmp' +'g@^diff --git a/runtime/doc/\<\%('"${na_doc}"'\)\>@norm! d/\v(^diff)|%$ ' +w +q "$file"
# Remove "Last change ..." changes in doc files.
@@ -326,12 +326,14 @@ stage_patch() {
return $ret
}
-hub_pr() {
- hub pull-request -m "$1"
+gh_pr() {
+ gh pr create --title "$1" --body "$2"
}
git_hub_pr() {
- git hub pull new -m "$1"
+ local pr_message
+ pr_message="$(printf '%s\n\n%s\n' "$1" "$2")"
+ git hub pull new -m "${pr_message}"
}
# shellcheck disable=SC2015
@@ -341,14 +343,14 @@ submit_pr() {
local push_first
push_first=1
local submit_fn
- if check_executable hub; then
- submit_fn="hub_pr"
+ if check_executable gh; then
+ submit_fn="gh_pr"
elif check_executable git-hub; then
push_first=0
submit_fn="git_hub_pr"
else
- >&2 echo "${BASENAME}: 'hub' or 'git-hub' not found in PATH or not executable."
- >&2 echo " Get it here: https://hub.github.com/"
+ >&2 echo "${BASENAME}: 'gh' or 'git-hub' not found in PATH or not executable."
+ >&2 echo " Get it here: https://cli.github.com/"
exit 1
fi
@@ -371,9 +373,7 @@ submit_pr() {
patches=(${patches[@]//vim-patch:}) # Remove 'vim-patch:' prefix for each item in array.
local pr_title="${patches[*]}" # Create space-separated string from array.
pr_title="${pr_title// /,}" # Replace spaces with commas.
-
- local pr_message
- pr_message="$(printf 'vim-patch:%s\n\n%s\n' "${pr_title#,}" "${pr_body}")"
+ pr_title="$(printf 'vim-patch:%s' "${pr_title#,}")"
if [[ $push_first -ne 0 ]]; then
echo "Pushing to 'origin/${checked_out_branch}'."
@@ -385,7 +385,7 @@ submit_pr() {
fi
echo "Creating pull request."
- output="$(${submit_fn} "${pr_message}" 2>&1)" &&
+ output="$(${submit_fn} "${pr_title}" "${pr_body}" 2>&1)" &&
msg_ok "${output}" ||
(msg_err "${output}"; false)
diff --git a/scripts/vimpatch.lua b/scripts/vimpatch.lua
index 0924f3d718..11eb285462 100755
--- a/scripts/vimpatch.lua
+++ b/scripts/vimpatch.lua
@@ -5,10 +5,6 @@
local nvim = vim.api
-local function pprint(o)
- print(nvim.nvim_call_function('string', { o }))
-end
-
local function systemlist(...)
local rv = nvim.nvim_call_function('systemlist', ...)
local err = nvim.nvim_get_vvar('shell_error')
diff --git a/src/cjson/fpconv.c b/src/cjson/fpconv.c
new file mode 100644
index 0000000000..b2f7a214c2
--- /dev/null
+++ b/src/cjson/fpconv.c
@@ -0,0 +1,211 @@
+/* fpconv - Floating point conversion routines
+ *
+ * Copyright (c) 2011-2012 Mark Pulford <mark@kyne.com.au>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* JSON uses a '.' decimal separator. strtod() / sprintf() under C libraries
+ * with locale support will break when the decimal separator is a comma.
+ *
+ * fpconv_* will around these issues with a translation buffer if required.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#include "fpconv.h"
+
+/* Workaround for MSVC */
+#ifdef _MSC_VER
+#define inline __inline
+#define snprintf sprintf_s
+#endif
+
+/* Lua CJSON assumes the locale is the same for all threads within a
+ * process and doesn't change after initialisation.
+ *
+ * This avoids the need for per thread storage or expensive checks
+ * for call. */
+static char locale_decimal_point = '.';
+
+/* In theory multibyte decimal_points are possible, but
+ * Lua CJSON only supports UTF-8 and known locales only have
+ * single byte decimal points ([.,]).
+ *
+ * localconv() may not be thread safe (=>crash), and nl_langinfo() is
+ * not supported on some platforms. Use sprintf() instead - if the
+ * locale does change, at least Lua CJSON won't crash. */
+static void fpconv_update_locale(void)
+{
+ char buf[8];
+
+ snprintf(buf, sizeof(buf), "%g", 0.5);
+
+ /* Failing this test might imply the platform has a buggy dtoa
+ * implementation or wide characters */
+ if (buf[0] != '0' || buf[2] != '5' || buf[3] != 0) {
+ fprintf(stderr, "Error: wide characters found or printf() bug.");
+ abort();
+ }
+
+ locale_decimal_point = buf[1];
+}
+
+/* Check for a valid number character: [-+0-9a-yA-Y.]
+ * Eg: -0.6e+5, infinity, 0xF0.F0pF0
+ *
+ * Used to find the probable end of a number. It doesn't matter if
+ * invalid characters are counted - strtod() will find the valid
+ * number if it exists. The risk is that slightly more memory might
+ * be allocated before a parse error occurs. */
+static inline int valid_number_character(char ch)
+{
+ char lower_ch;
+
+ if ('0' <= ch && ch <= '9')
+ return 1;
+ if (ch == '-' || ch == '+' || ch == '.')
+ return 1;
+
+ /* Hex digits, exponent (e), base (p), "infinity",.. */
+ lower_ch = ch | 0x20;
+ if ('a' <= lower_ch && lower_ch <= 'y')
+ return 1;
+
+ return 0;
+}
+
+/* Calculate the size of the buffer required for a strtod locale
+ * conversion. */
+static int strtod_buffer_size(const char *s)
+{
+ const char *p = s;
+
+ while (valid_number_character(*p))
+ p++;
+
+ return p - s;
+}
+
+/* Similar to strtod(), but must be passed the current locale's decimal point
+ * character. Guaranteed to be called at the start of any valid number in a string */
+double fpconv_strtod(const char *nptr, char **endptr)
+{
+ char localbuf[FPCONV_G_FMT_BUFSIZE];
+ char *buf, *endbuf, *dp;
+ int buflen;
+ double value;
+
+ /* System strtod() is fine when decimal point is '.' */
+ if (locale_decimal_point == '.')
+ return strtod(nptr, endptr);
+
+ buflen = strtod_buffer_size(nptr);
+ if (!buflen) {
+ /* No valid characters found, standard strtod() return */
+ *endptr = (char *)nptr;
+ return 0;
+ }
+
+ /* Duplicate number into buffer */
+ if (buflen >= FPCONV_G_FMT_BUFSIZE) {
+ /* Handle unusually large numbers */
+ buf = malloc(buflen + 1);
+ if (!buf) {
+ fprintf(stderr, "Out of memory");
+ abort();
+ }
+ } else {
+ /* This is the common case.. */
+ buf = localbuf;
+ }
+ memcpy(buf, nptr, buflen);
+ buf[buflen] = 0;
+
+ /* Update decimal point character if found */
+ dp = strchr(buf, '.');
+ if (dp)
+ *dp = locale_decimal_point;
+
+ value = strtod(buf, &endbuf);
+ *endptr = (char *)&nptr[endbuf - buf];
+ if (buflen >= FPCONV_G_FMT_BUFSIZE)
+ free(buf);
+
+ return value;
+}
+
+/* "fmt" must point to a buffer of at least 6 characters */
+static void set_number_format(char *fmt, int precision)
+{
+ int d1, d2, i;
+
+ assert(1 <= precision && precision <= 16);
+
+ /* Create printf format (%.14g) from precision */
+ d1 = precision / 10;
+ d2 = precision % 10;
+ fmt[0] = '%';
+ fmt[1] = '.';
+ i = 2;
+ if (d1) {
+ fmt[i++] = '0' + d1;
+ }
+ fmt[i++] = '0' + d2;
+ fmt[i++] = 'g';
+ fmt[i] = 0;
+}
+
+/* Assumes there is always at least 32 characters available in the target buffer */
+int fpconv_g_fmt(char *str, double num, int precision)
+{
+ char buf[FPCONV_G_FMT_BUFSIZE];
+ char fmt[6];
+ int len;
+ char *b;
+
+ set_number_format(fmt, precision);
+
+ /* Pass through when decimal point character is dot. */
+ if (locale_decimal_point == '.')
+ return snprintf(str, FPCONV_G_FMT_BUFSIZE, fmt, num);
+
+ /* snprintf() to a buffer then translate for other decimal point characters */
+ len = snprintf(buf, FPCONV_G_FMT_BUFSIZE, fmt, num);
+
+ /* Copy into target location. Translate decimal point if required */
+ b = buf;
+ do {
+ *str++ = (*b == locale_decimal_point ? '.' : *b);
+ } while(*b++);
+
+ return len;
+}
+
+void fpconv_init()
+{
+ fpconv_update_locale();
+}
+
+/* vi:ai et sw=4 ts=4:
+ */
diff --git a/src/cjson/fpconv.h b/src/cjson/fpconv.h
new file mode 100644
index 0000000000..6ac97808b6
--- /dev/null
+++ b/src/cjson/fpconv.h
@@ -0,0 +1,22 @@
+/* Lua CJSON floating point conversion routines */
+
+/* Buffer required to store the largest string representation of a double.
+ *
+ * Longest double printed with %.14g is 21 characters long:
+ * -1.7976931348623e+308 */
+# define FPCONV_G_FMT_BUFSIZE 32
+
+#ifdef USE_INTERNAL_FPCONV
+static inline void fpconv_init()
+{
+ /* Do nothing - not required */
+}
+#else
+extern void fpconv_init(void);
+#endif
+
+extern int fpconv_g_fmt(char*, double, int);
+extern double fpconv_strtod(const char*, char**);
+
+/* vi:ai et sw=4 ts=4:
+ */
diff --git a/src/cjson/lua_cjson.c b/src/cjson/lua_cjson.c
new file mode 100644
index 0000000000..92d07963bd
--- /dev/null
+++ b/src/cjson/lua_cjson.c
@@ -0,0 +1,1609 @@
+/* Lua CJSON - JSON support for Lua
+ *
+ * Copyright (c) 2010-2012 Mark Pulford <mark@kyne.com.au>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* Caveats:
+ * - JSON "null" values are represented as lightuserdata since Lua
+ * tables cannot contain "nil". Compare with cjson.null.
+ * - Invalid UTF-8 characters are not detected and will be passed
+ * untouched. If required, UTF-8 error checking should be done
+ * outside this library.
+ * - Javascript comments are not part of the JSON spec, and are not
+ * currently supported.
+ *
+ * Note: Decoding is slower than encoding. Lua spends significant
+ * time (30%) managing tables when parsing JSON since it is
+ * difficult to know object/array sizes ahead of time.
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+#include <math.h>
+#include <limits.h>
+#include <lua.h>
+#include <lauxlib.h>
+
+#include "nvim/lua/executor.h"
+
+#include "lua_cjson.h"
+#include "strbuf.h"
+#include "fpconv.h"
+
+#ifndef CJSON_MODNAME
+#define CJSON_MODNAME "cjson"
+#endif
+
+#ifndef CJSON_VERSION
+#define CJSON_VERSION "2.1.0.9"
+#endif
+
+#ifdef _MSC_VER
+#define snprintf sprintf_s
+
+#ifndef isnan
+#include <float.h>
+#define isnan(x) _isnan(x)
+#endif
+
+#endif
+
+/* Workaround for Solaris platforms missing isinf() */
+#if !defined(isinf) && (defined(USE_INTERNAL_ISINF) || defined(MISSING_ISINF))
+#define isinf(x) (!isnan(x) && isnan((x) - (x)))
+#endif
+
+#define DEFAULT_SPARSE_CONVERT 0
+#define DEFAULT_SPARSE_RATIO 2
+#define DEFAULT_SPARSE_SAFE 10
+#define DEFAULT_ENCODE_MAX_DEPTH 1000
+#define DEFAULT_DECODE_MAX_DEPTH 1000
+#define DEFAULT_ENCODE_INVALID_NUMBERS 0
+#define DEFAULT_DECODE_INVALID_NUMBERS 1
+#define DEFAULT_ENCODE_KEEP_BUFFER 1
+#define DEFAULT_ENCODE_NUMBER_PRECISION 14
+#define DEFAULT_ENCODE_EMPTY_TABLE_AS_OBJECT 0
+#define DEFAULT_DECODE_ARRAY_WITH_ARRAY_MT 0
+#define DEFAULT_ENCODE_ESCAPE_FORWARD_SLASH 1
+
+#ifdef DISABLE_INVALID_NUMBERS
+#undef DEFAULT_DECODE_INVALID_NUMBERS
+#define DEFAULT_DECODE_INVALID_NUMBERS 0
+#endif
+
+#ifdef _MSC_VER
+/* Microsoft C compiler lacks strncasecmp and strcasecmp. */
+#define strncasecmp _strnicmp
+#define strcasecmp _stricmp
+#endif
+
+#if LONG_MAX > ((1UL << 31) - 1)
+#define json_lightudata_mask(ludata) \
+ ((void *) ((uintptr_t) (ludata) & ((1UL << 47) - 1)))
+
+#else
+#define json_lightudata_mask(ludata) (ludata)
+#endif
+
+#if LUA_VERSION_NUM > 501
+#define lua_objlen(L,i) lua_rawlen(L, (i))
+#endif
+
+static const char * const *json_empty_array;
+static const char * const *json_array;
+
+typedef enum {
+ T_OBJ_BEGIN,
+ T_OBJ_END,
+ T_ARR_BEGIN,
+ T_ARR_END,
+ T_STRING,
+ T_NUMBER,
+ T_BOOLEAN,
+ T_NULL,
+ T_COLON,
+ T_COMMA,
+ T_END,
+ T_WHITESPACE,
+ T_ERROR,
+ T_UNKNOWN
+} json_token_type_t;
+
+static const char *json_token_type_name[] = {
+ "T_OBJ_BEGIN",
+ "T_OBJ_END",
+ "T_ARR_BEGIN",
+ "T_ARR_END",
+ "T_STRING",
+ "T_NUMBER",
+ "T_BOOLEAN",
+ "T_NULL",
+ "T_COLON",
+ "T_COMMA",
+ "T_END",
+ "T_WHITESPACE",
+ "T_ERROR",
+ "T_UNKNOWN",
+ NULL
+};
+
+typedef struct {
+ json_token_type_t ch2token[256];
+ char escape2char[256]; /* Decoding */
+
+ /* encode_buf is only allocated and used when
+ * encode_keep_buffer is set */
+ strbuf_t encode_buf;
+
+ int encode_sparse_convert;
+ int encode_sparse_ratio;
+ int encode_sparse_safe;
+ int encode_max_depth;
+ int encode_invalid_numbers; /* 2 => Encode as "null" */
+ int encode_number_precision;
+ int encode_keep_buffer;
+ int encode_empty_table_as_object;
+ int encode_escape_forward_slash;
+
+ int decode_invalid_numbers;
+ int decode_max_depth;
+ int decode_array_with_array_mt;
+} json_config_t;
+
+typedef struct {
+ const char *data;
+ const char *ptr;
+ strbuf_t *tmp; /* Temporary storage for strings */
+ json_config_t *cfg;
+ int current_depth;
+} json_parse_t;
+
+typedef struct {
+ json_token_type_t type;
+ int index;
+ union {
+ const char *string;
+ double number;
+ int boolean;
+ } value;
+ int string_len;
+} json_token_t;
+
+static const char *char2escape[256] = {
+ "\\u0000", "\\u0001", "\\u0002", "\\u0003",
+ "\\u0004", "\\u0005", "\\u0006", "\\u0007",
+ "\\b", "\\t", "\\n", "\\u000b",
+ "\\f", "\\r", "\\u000e", "\\u000f",
+ "\\u0010", "\\u0011", "\\u0012", "\\u0013",
+ "\\u0014", "\\u0015", "\\u0016", "\\u0017",
+ "\\u0018", "\\u0019", "\\u001a", "\\u001b",
+ "\\u001c", "\\u001d", "\\u001e", "\\u001f",
+ NULL, NULL, "\\\"", NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, "\\/",
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\\\\", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, "\\u007f",
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+};
+
+/* ===== CONFIGURATION ===== */
+
+static json_config_t *json_fetch_config(lua_State *l)
+{
+ json_config_t *cfg;
+
+ cfg = lua_touserdata(l, lua_upvalueindex(1));
+ if (!cfg)
+ luaL_error(l, "BUG: Unable to fetch CJSON configuration");
+
+ return cfg;
+}
+
+/* Ensure the correct number of arguments have been provided.
+ * Pad with nil to allow other functions to simply check arg[i]
+ * to find whether an argument was provided */
+static json_config_t *json_arg_init(lua_State *l, int args)
+{
+ luaL_argcheck(l, lua_gettop(l) <= args, args + 1,
+ "found too many arguments");
+
+ while (lua_gettop(l) < args)
+ lua_pushnil(l);
+
+ return json_fetch_config(l);
+}
+
+/* Process integer options for configuration functions */
+static int json_integer_option(lua_State *l, int optindex, int *setting,
+ int min, int max)
+{
+ char errmsg[64];
+ int value;
+
+ if (!lua_isnil(l, optindex)) {
+ value = luaL_checkinteger(l, optindex);
+ snprintf(errmsg, sizeof(errmsg), "expected integer between %d and %d", min, max);
+ luaL_argcheck(l, min <= value && value <= max, 1, errmsg);
+ *setting = value;
+ }
+
+ lua_pushinteger(l, *setting);
+
+ return 1;
+}
+
+/* Process enumerated arguments for a configuration function */
+static int json_enum_option(lua_State *l, int optindex, int *setting,
+ const char **options, int bool_true)
+{
+ static const char *bool_options[] = { "off", "on", NULL };
+
+ if (!options) {
+ options = bool_options;
+ bool_true = 1;
+ }
+
+ if (!lua_isnil(l, optindex)) {
+ if (bool_true && lua_isboolean(l, optindex))
+ *setting = lua_toboolean(l, optindex) * bool_true;
+ else
+ *setting = luaL_checkoption(l, optindex, NULL, options);
+ }
+
+ if (bool_true && (*setting == 0 || *setting == bool_true))
+ lua_pushboolean(l, *setting);
+ else
+ lua_pushstring(l, options[*setting]);
+
+ return 1;
+}
+
+/* Configures handling of extremely sparse arrays:
+ * convert: Convert extremely sparse arrays into objects? Otherwise error.
+ * ratio: 0: always allow sparse; 1: never allow sparse; >1: use ratio
+ * safe: Always use an array when the max index <= safe */
+static int json_cfg_encode_sparse_array(lua_State *l)
+{
+ json_config_t *cfg = json_arg_init(l, 3);
+
+ json_enum_option(l, 1, &cfg->encode_sparse_convert, NULL, 1);
+ json_integer_option(l, 2, &cfg->encode_sparse_ratio, 0, INT_MAX);
+ json_integer_option(l, 3, &cfg->encode_sparse_safe, 0, INT_MAX);
+
+ return 3;
+}
+
+/* Configures the maximum number of nested arrays/objects allowed when
+ * encoding */
+static int json_cfg_encode_max_depth(lua_State *l)
+{
+ json_config_t *cfg = json_arg_init(l, 1);
+
+ return json_integer_option(l, 1, &cfg->encode_max_depth, 1, INT_MAX);
+}
+
+/* Configures the maximum number of nested arrays/objects allowed when
+ * encoding */
+static int json_cfg_decode_max_depth(lua_State *l)
+{
+ json_config_t *cfg = json_arg_init(l, 1);
+
+ return json_integer_option(l, 1, &cfg->decode_max_depth, 1, INT_MAX);
+}
+
+/* Configures number precision when converting doubles to text */
+static int json_cfg_encode_number_precision(lua_State *l)
+{
+ json_config_t *cfg = json_arg_init(l, 1);
+
+ return json_integer_option(l, 1, &cfg->encode_number_precision, 1, 16);
+}
+
+/* Configures how to treat empty table when encode lua table */
+static int json_cfg_encode_empty_table_as_object(lua_State *l)
+{
+ json_config_t *cfg = json_arg_init(l, 1);
+
+ return json_enum_option(l, 1, &cfg->encode_empty_table_as_object, NULL, 1);
+}
+
+/* Configures how to decode arrays */
+static int json_cfg_decode_array_with_array_mt(lua_State *l)
+{
+ json_config_t *cfg = json_arg_init(l, 1);
+
+ json_enum_option(l, 1, &cfg->decode_array_with_array_mt, NULL, 1);
+
+ return 1;
+}
+
+/* Configures JSON encoding buffer persistence */
+static int json_cfg_encode_keep_buffer(lua_State *l)
+{
+ json_config_t *cfg = json_arg_init(l, 1);
+ int old_value;
+
+ old_value = cfg->encode_keep_buffer;
+
+ json_enum_option(l, 1, &cfg->encode_keep_buffer, NULL, 1);
+
+ /* Init / free the buffer if the setting has changed */
+ if (old_value ^ cfg->encode_keep_buffer) {
+ if (cfg->encode_keep_buffer)
+ strbuf_init(&cfg->encode_buf, 0);
+ else
+ strbuf_free(&cfg->encode_buf);
+ }
+
+ return 1;
+}
+
+#if defined(DISABLE_INVALID_NUMBERS) && !defined(USE_INTERNAL_FPCONV)
+void json_verify_invalid_number_setting(lua_State *l, int *setting)
+{
+ if (*setting == 1) {
+ *setting = 0;
+ luaL_error(l, "Infinity, NaN, and/or hexadecimal numbers are not supported.");
+ }
+}
+#else
+#define json_verify_invalid_number_setting(l, s) do { } while(0)
+#endif
+
+static int json_cfg_encode_invalid_numbers(lua_State *l)
+{
+ static const char *options[] = { "off", "on", "null", NULL };
+ json_config_t *cfg = json_arg_init(l, 1);
+
+ json_enum_option(l, 1, &cfg->encode_invalid_numbers, options, 1);
+
+ json_verify_invalid_number_setting(l, &cfg->encode_invalid_numbers);
+
+ return 1;
+}
+
+static int json_cfg_decode_invalid_numbers(lua_State *l)
+{
+ json_config_t *cfg = json_arg_init(l, 1);
+
+ json_enum_option(l, 1, &cfg->decode_invalid_numbers, NULL, 1);
+
+ json_verify_invalid_number_setting(l, &cfg->encode_invalid_numbers);
+
+ return 1;
+}
+
+static int json_cfg_encode_escape_forward_slash(lua_State *l)
+{
+ int ret;
+ json_config_t *cfg = json_arg_init(l, 1);
+
+ ret = json_enum_option(l, 1, &cfg->encode_escape_forward_slash, NULL, 1);
+ if (cfg->encode_escape_forward_slash) {
+ char2escape['/'] = "\\/";
+ } else {
+ char2escape['/'] = NULL;
+ }
+ return ret;
+}
+
+static int json_destroy_config(lua_State *l)
+{
+ json_config_t *cfg;
+
+ cfg = lua_touserdata(l, 1);
+ if (cfg)
+ strbuf_free(&cfg->encode_buf);
+ cfg = NULL;
+
+ return 0;
+}
+
+static void json_create_config(lua_State *l)
+{
+ json_config_t *cfg;
+ int i;
+
+ cfg = lua_newuserdata(l, sizeof(*cfg));
+
+ /* Create GC method to clean up strbuf */
+ lua_newtable(l);
+ lua_pushcfunction(l, json_destroy_config);
+ lua_setfield(l, -2, "__gc");
+ lua_setmetatable(l, -2);
+
+ cfg->encode_sparse_convert = DEFAULT_SPARSE_CONVERT;
+ cfg->encode_sparse_ratio = DEFAULT_SPARSE_RATIO;
+ cfg->encode_sparse_safe = DEFAULT_SPARSE_SAFE;
+ cfg->encode_max_depth = DEFAULT_ENCODE_MAX_DEPTH;
+ cfg->decode_max_depth = DEFAULT_DECODE_MAX_DEPTH;
+ cfg->encode_invalid_numbers = DEFAULT_ENCODE_INVALID_NUMBERS;
+ cfg->decode_invalid_numbers = DEFAULT_DECODE_INVALID_NUMBERS;
+ cfg->encode_keep_buffer = DEFAULT_ENCODE_KEEP_BUFFER;
+ cfg->encode_number_precision = DEFAULT_ENCODE_NUMBER_PRECISION;
+ cfg->encode_empty_table_as_object = DEFAULT_ENCODE_EMPTY_TABLE_AS_OBJECT;
+ cfg->decode_array_with_array_mt = DEFAULT_DECODE_ARRAY_WITH_ARRAY_MT;
+ cfg->encode_escape_forward_slash = DEFAULT_ENCODE_ESCAPE_FORWARD_SLASH;
+
+#if DEFAULT_ENCODE_KEEP_BUFFER > 0
+ strbuf_init(&cfg->encode_buf, 0);
+#endif
+
+ /* Decoding init */
+
+ /* Tag all characters as an error */
+ for (i = 0; i < 256; i++)
+ cfg->ch2token[i] = T_ERROR;
+
+ /* Set tokens that require no further processing */
+ cfg->ch2token['{'] = T_OBJ_BEGIN;
+ cfg->ch2token['}'] = T_OBJ_END;
+ cfg->ch2token['['] = T_ARR_BEGIN;
+ cfg->ch2token[']'] = T_ARR_END;
+ cfg->ch2token[','] = T_COMMA;
+ cfg->ch2token[':'] = T_COLON;
+ cfg->ch2token['\0'] = T_END;
+ cfg->ch2token[' '] = T_WHITESPACE;
+ cfg->ch2token['\t'] = T_WHITESPACE;
+ cfg->ch2token['\n'] = T_WHITESPACE;
+ cfg->ch2token['\r'] = T_WHITESPACE;
+
+ /* Update characters that require further processing */
+ cfg->ch2token['f'] = T_UNKNOWN; /* false? */
+ cfg->ch2token['i'] = T_UNKNOWN; /* inf, ininity? */
+ cfg->ch2token['I'] = T_UNKNOWN;
+ cfg->ch2token['n'] = T_UNKNOWN; /* null, nan? */
+ cfg->ch2token['N'] = T_UNKNOWN;
+ cfg->ch2token['t'] = T_UNKNOWN; /* true? */
+ cfg->ch2token['"'] = T_UNKNOWN; /* string? */
+ cfg->ch2token['+'] = T_UNKNOWN; /* number? */
+ cfg->ch2token['-'] = T_UNKNOWN;
+ for (i = 0; i < 10; i++)
+ cfg->ch2token['0' + i] = T_UNKNOWN;
+
+ /* Lookup table for parsing escape characters */
+ for (i = 0; i < 256; i++)
+ cfg->escape2char[i] = 0; /* String error */
+ cfg->escape2char['"'] = '"';
+ cfg->escape2char['\\'] = '\\';
+ cfg->escape2char['/'] = '/';
+ cfg->escape2char['b'] = '\b';
+ cfg->escape2char['t'] = '\t';
+ cfg->escape2char['n'] = '\n';
+ cfg->escape2char['f'] = '\f';
+ cfg->escape2char['r'] = '\r';
+ cfg->escape2char['u'] = 'u'; /* Unicode parsing required */
+}
+
+/* ===== ENCODING ===== */
+
+static void json_encode_exception(lua_State *l, json_config_t *cfg, strbuf_t *json, int lindex,
+ const char *reason)
+{
+ if (!cfg->encode_keep_buffer)
+ strbuf_free(json);
+ luaL_error(l, "Cannot serialise %s: %s",
+ lua_typename(l, lua_type(l, lindex)), reason);
+}
+
+/* json_append_string args:
+ * - lua_State
+ * - JSON strbuf
+ * - String (Lua stack index)
+ *
+ * Returns nothing. Doesn't remove string from Lua stack */
+static void json_append_string(lua_State *l, strbuf_t *json, int lindex)
+{
+ const char *escstr;
+ unsigned i;
+ const char *str;
+ size_t len;
+
+ str = lua_tolstring(l, lindex, &len);
+
+ /* Worst case is len * 6 (all unicode escapes).
+ * This buffer is reused constantly for small strings
+ * If there are any excess pages, they won't be hit anyway.
+ * This gains ~5% speedup. */
+ strbuf_ensure_empty_length(json, len * 6 + 2);
+
+ strbuf_append_char_unsafe(json, '\"');
+ for (i = 0; i < len; i++) {
+ escstr = char2escape[(unsigned char)str[i]];
+ if (escstr)
+ strbuf_append_string(json, escstr);
+ else
+ strbuf_append_char_unsafe(json, str[i]);
+ }
+ strbuf_append_char_unsafe(json, '\"');
+}
+
+/* Find the size of the array on the top of the Lua stack
+ * -1 object (not a pure array)
+ * >=0 elements in array
+ */
+static int lua_array_length(lua_State *l, json_config_t *cfg, strbuf_t *json)
+{
+ double k;
+ int max;
+ int items;
+
+ max = 0;
+ items = 0;
+
+ lua_pushnil(l);
+ /* table, startkey */
+ while (lua_next(l, -2) != 0) {
+ /* table, key, value */
+ if (lua_type(l, -2) == LUA_TNUMBER &&
+ (k = lua_tonumber(l, -2))) {
+ /* Integer >= 1 ? */
+ if (floor(k) == k && k >= 1) {
+ if (k > max)
+ max = k;
+ items++;
+ lua_pop(l, 1);
+ continue;
+ }
+ }
+
+ /* Must not be an array (non integer key) */
+ lua_pop(l, 2);
+ return -1;
+ }
+
+ /* Encode excessively sparse arrays as objects (if enabled) */
+ if (cfg->encode_sparse_ratio > 0 &&
+ max > items * cfg->encode_sparse_ratio &&
+ max > cfg->encode_sparse_safe) {
+ if (!cfg->encode_sparse_convert)
+ json_encode_exception(l, cfg, json, -1, "excessively sparse array");
+
+ return -1;
+ }
+
+ return max;
+}
+
+static void json_check_encode_depth(lua_State *l, json_config_t *cfg,
+ int current_depth, strbuf_t *json)
+{
+ /* Ensure there are enough slots free to traverse a table (key,
+ * value) and push a string for a potential error message.
+ *
+ * Unlike "decode", the key and value are still on the stack when
+ * lua_checkstack() is called. Hence an extra slot for luaL_error()
+ * below is required just in case the next check to lua_checkstack()
+ * fails.
+ *
+ * While this won't cause a crash due to the EXTRA_STACK reserve
+ * slots, it would still be an improper use of the API. */
+ if (current_depth <= cfg->encode_max_depth && lua_checkstack(l, 3))
+ return;
+
+ if (!cfg->encode_keep_buffer)
+ strbuf_free(json);
+
+ luaL_error(l, "Cannot serialise, excessive nesting (%d)",
+ current_depth);
+}
+
+static void json_append_data(lua_State *l, json_config_t *cfg,
+ int current_depth, strbuf_t *json);
+
+/* json_append_array args:
+ * - lua_State
+ * - JSON strbuf
+ * - Size of passwd Lua array (top of stack) */
+static void json_append_array(lua_State *l, json_config_t *cfg, int current_depth,
+ strbuf_t *json, int array_length)
+{
+ int comma, i;
+
+ strbuf_append_char(json, '[');
+
+ comma = 0;
+ for (i = 1; i <= array_length; i++) {
+ if (comma)
+ strbuf_append_char(json, ',');
+ else
+ comma = 1;
+
+ lua_rawgeti(l, -1, i);
+ json_append_data(l, cfg, current_depth, json);
+ lua_pop(l, 1);
+ }
+
+ strbuf_append_char(json, ']');
+}
+
+static void json_append_number(lua_State *l, json_config_t *cfg,
+ strbuf_t *json, int lindex)
+{
+ double num = lua_tonumber(l, lindex);
+ int len;
+
+ if (cfg->encode_invalid_numbers == 0) {
+ /* Prevent encoding invalid numbers */
+ if (isinf(num) || isnan(num))
+ json_encode_exception(l, cfg, json, lindex,
+ "must not be NaN or Infinity");
+ } else if (cfg->encode_invalid_numbers == 1) {
+ /* Encode NaN/Infinity separately to ensure Javascript compatible
+ * values are used. */
+ if (isnan(num)) {
+ strbuf_append_mem(json, "NaN", 3);
+ return;
+ }
+ if (isinf(num)) {
+ if (num < 0)
+ strbuf_append_mem(json, "-Infinity", 9);
+ else
+ strbuf_append_mem(json, "Infinity", 8);
+ return;
+ }
+ } else {
+ /* Encode invalid numbers as "null" */
+ if (isinf(num) || isnan(num)) {
+ strbuf_append_mem(json, "null", 4);
+ return;
+ }
+ }
+
+ strbuf_ensure_empty_length(json, FPCONV_G_FMT_BUFSIZE);
+ len = fpconv_g_fmt(strbuf_empty_ptr(json), num, cfg->encode_number_precision);
+ strbuf_extend_length(json, len);
+}
+
+static void json_append_object(lua_State *l, json_config_t *cfg,
+ int current_depth, strbuf_t *json)
+{
+ int comma, keytype;
+
+ /* Object */
+ strbuf_append_char(json, '{');
+
+ lua_pushnil(l);
+ /* table, startkey */
+ comma = 0;
+ while (lua_next(l, -2) != 0) {
+ if (comma)
+ strbuf_append_char(json, ',');
+ else
+ comma = 1;
+
+ /* table, key, value */
+ keytype = lua_type(l, -2);
+ if (keytype == LUA_TNUMBER) {
+ strbuf_append_char(json, '"');
+ json_append_number(l, cfg, json, -2);
+ strbuf_append_mem(json, "\":", 2);
+ } else if (keytype == LUA_TSTRING) {
+ json_append_string(l, json, -2);
+ strbuf_append_char(json, ':');
+ } else {
+ json_encode_exception(l, cfg, json, -2,
+ "table key must be a number or string");
+ /* never returns */
+ }
+
+ /* table, key, value */
+ json_append_data(l, cfg, current_depth, json);
+ lua_pop(l, 1);
+ /* table, key */
+ }
+
+ strbuf_append_char(json, '}');
+}
+
+/* Serialise Lua data into JSON string. */
+static void json_append_data(lua_State *l, json_config_t *cfg,
+ int current_depth, strbuf_t *json)
+{
+ int len;
+ int as_array = 0;
+ int as_empty_dict = 0;
+ int has_metatable;
+
+ switch (lua_type(l, -1)) {
+ case LUA_TSTRING:
+ json_append_string(l, json, -1);
+ break;
+ case LUA_TNUMBER:
+ json_append_number(l, cfg, json, -1);
+ break;
+ case LUA_TBOOLEAN:
+ if (lua_toboolean(l, -1))
+ strbuf_append_mem(json, "true", 4);
+ else
+ strbuf_append_mem(json, "false", 5);
+ break;
+ case LUA_TTABLE:
+ current_depth++;
+ json_check_encode_depth(l, cfg, current_depth, json);
+
+ has_metatable = lua_getmetatable(l, -1);
+
+ if (has_metatable) {
+
+ nlua_pushref(l, nlua_empty_dict_ref);
+ if (lua_rawequal(l, -2, -1)) {
+ as_empty_dict = true;
+ } else {
+ lua_pop(l, 1);
+ lua_pushlightuserdata(l, json_lightudata_mask(&json_array));
+ lua_rawget(l, LUA_REGISTRYINDEX);
+ as_array = lua_rawequal(l, -1, -2);
+ }
+ lua_pop(l, 2);
+ }
+
+ if (as_array) {
+ len = lua_objlen(l, -1);
+ json_append_array(l, cfg, current_depth, json, len);
+ } else {
+ len = lua_array_length(l, cfg, json);
+
+ if (len > 0 || (len == 0 && !cfg->encode_empty_table_as_object && !as_empty_dict)) {
+ json_append_array(l, cfg, current_depth, json, len);
+ } else {
+ if (has_metatable) {
+ lua_getmetatable(l, -1);
+ lua_pushlightuserdata(l, json_lightudata_mask(
+ &json_empty_array));
+ lua_rawget(l, LUA_REGISTRYINDEX);
+ as_array = lua_rawequal(l, -1, -2);
+ lua_pop(l, 2); /* pop pointer + metatable */
+ if (as_array) {
+ json_append_array(l, cfg, current_depth, json, 0);
+ break;
+ }
+ }
+ json_append_object(l, cfg, current_depth, json);
+ }
+ }
+ break;
+ case LUA_TNIL:
+ strbuf_append_mem(json, "null", 4);
+ break;
+ case LUA_TLIGHTUSERDATA:
+ if (lua_touserdata(l, -1) == &json_array) {
+ json_append_array(l, cfg, current_depth, json, 0);
+ }
+ break;
+ case LUA_TUSERDATA:
+ nlua_pushref(l, nlua_nil_ref);
+ bool is_nil = lua_rawequal(l, -2, -1);
+ lua_pop(l, 1);
+ if (is_nil) {
+ strbuf_append_mem(json, "null", 4);
+ break;
+ } else {
+ FALLTHROUGH;
+ }
+ default:
+ /* Remaining types (LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD,
+ * and LUA_TLIGHTUSERDATA) cannot be serialised */
+ json_encode_exception(l, cfg, json, -1, "type not supported");
+ /* never returns */
+ }
+}
+
+static int json_encode(lua_State *l)
+{
+ json_config_t *cfg = json_fetch_config(l);
+ strbuf_t local_encode_buf;
+ strbuf_t *encode_buf;
+ char *json;
+ int len;
+
+ luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument");
+
+ if (!cfg->encode_keep_buffer) {
+ /* Use private buffer */
+ encode_buf = &local_encode_buf;
+ strbuf_init(encode_buf, 0);
+ } else {
+ /* Reuse existing buffer */
+ encode_buf = &cfg->encode_buf;
+ strbuf_reset(encode_buf);
+ }
+
+ json_append_data(l, cfg, 0, encode_buf);
+ json = strbuf_string(encode_buf, &len);
+
+ lua_pushlstring(l, json, len);
+
+ if (!cfg->encode_keep_buffer)
+ strbuf_free(encode_buf);
+
+ return 1;
+}
+
+/* ===== DECODING ===== */
+
+static void json_process_value(lua_State *l, json_parse_t *json,
+ json_token_t *token);
+
+static int hexdigit2int(char hex)
+{
+ if ('0' <= hex && hex <= '9')
+ return hex - '0';
+
+ /* Force lowercase */
+ hex |= 0x20;
+ if ('a' <= hex && hex <= 'f')
+ return 10 + hex - 'a';
+
+ return -1;
+}
+
+static int decode_hex4(const char *hex)
+{
+ int digit[4];
+ int i;
+
+ /* Convert ASCII hex digit to numeric digit
+ * Note: this returns an error for invalid hex digits, including
+ * NULL */
+ for (i = 0; i < 4; i++) {
+ digit[i] = hexdigit2int(hex[i]);
+ if (digit[i] < 0) {
+ return -1;
+ }
+ }
+
+ return (digit[0] << 12) +
+ (digit[1] << 8) +
+ (digit[2] << 4) +
+ digit[3];
+}
+
+/* Converts a Unicode codepoint to UTF-8.
+ * Returns UTF-8 string length, and up to 4 bytes in *utf8 */
+static int codepoint_to_utf8(char *utf8, int codepoint)
+{
+ /* 0xxxxxxx */
+ if (codepoint <= 0x7F) {
+ utf8[0] = codepoint;
+ return 1;
+ }
+
+ /* 110xxxxx 10xxxxxx */
+ if (codepoint <= 0x7FF) {
+ utf8[0] = (codepoint >> 6) | 0xC0;
+ utf8[1] = (codepoint & 0x3F) | 0x80;
+ return 2;
+ }
+
+ /* 1110xxxx 10xxxxxx 10xxxxxx */
+ if (codepoint <= 0xFFFF) {
+ utf8[0] = (codepoint >> 12) | 0xE0;
+ utf8[1] = ((codepoint >> 6) & 0x3F) | 0x80;
+ utf8[2] = (codepoint & 0x3F) | 0x80;
+ return 3;
+ }
+
+ /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
+ if (codepoint <= 0x1FFFFF) {
+ utf8[0] = (codepoint >> 18) | 0xF0;
+ utf8[1] = ((codepoint >> 12) & 0x3F) | 0x80;
+ utf8[2] = ((codepoint >> 6) & 0x3F) | 0x80;
+ utf8[3] = (codepoint & 0x3F) | 0x80;
+ return 4;
+ }
+
+ return 0;
+}
+
+
+/* Called when index pointing to beginning of UTF-16 code escape: \uXXXX
+ * \u is guaranteed to exist, but the remaining hex characters may be
+ * missing.
+ * Translate to UTF-8 and append to temporary token string.
+ * Must advance index to the next character to be processed.
+ * Returns: 0 success
+ * -1 error
+ */
+static int json_append_unicode_escape(json_parse_t *json)
+{
+ char utf8[4]; /* Surrogate pairs require 4 UTF-8 bytes */
+ int codepoint;
+ int surrogate_low;
+ int len;
+ int escape_len = 6;
+
+ /* Fetch UTF-16 code unit */
+ codepoint = decode_hex4(json->ptr + 2);
+ if (codepoint < 0)
+ return -1;
+
+ /* UTF-16 surrogate pairs take the following 2 byte form:
+ * 11011 x yyyyyyyyyy
+ * When x = 0: y is the high 10 bits of the codepoint
+ * x = 1: y is the low 10 bits of the codepoint
+ *
+ * Check for a surrogate pair (high or low) */
+ if ((codepoint & 0xF800) == 0xD800) {
+ /* Error if the 1st surrogate is not high */
+ if (codepoint & 0x400)
+ return -1;
+
+ /* Ensure the next code is a unicode escape */
+ if (*(json->ptr + escape_len) != '\\' ||
+ *(json->ptr + escape_len + 1) != 'u') {
+ return -1;
+ }
+
+ /* Fetch the next codepoint */
+ surrogate_low = decode_hex4(json->ptr + 2 + escape_len);
+ if (surrogate_low < 0)
+ return -1;
+
+ /* Error if the 2nd code is not a low surrogate */
+ if ((surrogate_low & 0xFC00) != 0xDC00)
+ return -1;
+
+ /* Calculate Unicode codepoint */
+ codepoint = (codepoint & 0x3FF) << 10;
+ surrogate_low &= 0x3FF;
+ codepoint = (codepoint | surrogate_low) + 0x10000;
+ escape_len = 12;
+ }
+
+ /* Convert codepoint to UTF-8 */
+ len = codepoint_to_utf8(utf8, codepoint);
+ if (!len)
+ return -1;
+
+ /* Append bytes and advance parse index */
+ strbuf_append_mem_unsafe(json->tmp, utf8, len);
+ json->ptr += escape_len;
+
+ return 0;
+}
+
+static void json_set_token_error(json_token_t *token, json_parse_t *json,
+ const char *errtype)
+{
+ token->type = T_ERROR;
+ token->index = json->ptr - json->data;
+ token->value.string = errtype;
+}
+
+static void json_next_string_token(json_parse_t *json, json_token_t *token)
+{
+ char *escape2char = json->cfg->escape2char;
+ char ch;
+
+ /* Caller must ensure a string is next */
+ assert(*json->ptr == '"');
+
+ /* Skip " */
+ json->ptr++;
+
+ /* json->tmp is the temporary strbuf used to accumulate the
+ * decoded string value.
+ * json->tmp is sized to handle JSON containing only a string value.
+ */
+ strbuf_reset(json->tmp);
+
+ while ((ch = *json->ptr) != '"') {
+ if (!ch) {
+ /* Premature end of the string */
+ json_set_token_error(token, json, "unexpected end of string");
+ return;
+ }
+
+ /* Handle escapes */
+ if (ch == '\\') {
+ /* Fetch escape character */
+ ch = *(json->ptr + 1);
+
+ /* Translate escape code and append to tmp string */
+ ch = escape2char[(unsigned char)ch];
+ if (ch == 'u') {
+ if (json_append_unicode_escape(json) == 0)
+ continue;
+
+ json_set_token_error(token, json,
+ "invalid unicode escape code");
+ return;
+ }
+ if (!ch) {
+ json_set_token_error(token, json, "invalid escape code");
+ return;
+ }
+
+ /* Skip '\' */
+ json->ptr++;
+ }
+ /* Append normal character or translated single character
+ * Unicode escapes are handled above */
+ strbuf_append_char_unsafe(json->tmp, ch);
+ json->ptr++;
+ }
+ json->ptr++; /* Eat final quote (") */
+
+ strbuf_ensure_null(json->tmp);
+
+ token->type = T_STRING;
+ token->value.string = strbuf_string(json->tmp, &token->string_len);
+}
+
+/* JSON numbers should take the following form:
+ * -?(0|[1-9]|[1-9][0-9]+)(.[0-9]+)?([eE][-+]?[0-9]+)?
+ *
+ * json_next_number_token() uses strtod() which allows other forms:
+ * - numbers starting with '+'
+ * - NaN, -NaN, infinity, -infinity
+ * - hexadecimal numbers
+ * - numbers with leading zeros
+ *
+ * json_is_invalid_number() detects "numbers" which may pass strtod()'s
+ * error checking, but should not be allowed with strict JSON.
+ *
+ * json_is_invalid_number() may pass numbers which cause strtod()
+ * to generate an error.
+ */
+static int json_is_invalid_number(json_parse_t *json)
+{
+ const char *p = json->ptr;
+
+ /* Reject numbers starting with + */
+ if (*p == '+')
+ return 1;
+
+ /* Skip minus sign if it exists */
+ if (*p == '-')
+ p++;
+
+ /* Reject numbers starting with 0x, or leading zeros */
+ if (*p == '0') {
+ int ch2 = *(p + 1);
+
+ if ((ch2 | 0x20) == 'x' || /* Hex */
+ ('0' <= ch2 && ch2 <= '9')) /* Leading zero */
+ return 1;
+
+ return 0;
+ } else if (*p <= '9') {
+ return 0; /* Ordinary number */
+ }
+
+ /* Reject inf/nan */
+ if (!strncasecmp(p, "inf", 3))
+ return 1;
+ if (!strncasecmp(p, "nan", 3))
+ return 1;
+
+ /* Pass all other numbers which may still be invalid, but
+ * strtod() will catch them. */
+ return 0;
+}
+
+static void json_next_number_token(json_parse_t *json, json_token_t *token)
+{
+ char *endptr;
+
+ token->type = T_NUMBER;
+ token->value.number = fpconv_strtod(json->ptr, &endptr);
+ if (json->ptr == endptr)
+ json_set_token_error(token, json, "invalid number");
+ else
+ json->ptr = endptr; /* Skip the processed number */
+
+ return;
+}
+
+/* Fills in the token struct.
+ * T_STRING will return a pointer to the json_parse_t temporary string
+ * T_ERROR will leave the json->ptr pointer at the error.
+ */
+static void json_next_token(json_parse_t *json, json_token_t *token)
+{
+ const json_token_type_t *ch2token = json->cfg->ch2token;
+ int ch;
+
+ /* Eat whitespace. */
+ while (1) {
+ ch = (unsigned char)*(json->ptr);
+ token->type = ch2token[ch];
+ if (token->type != T_WHITESPACE)
+ break;
+ json->ptr++;
+ }
+
+ /* Store location of new token. Required when throwing errors
+ * for unexpected tokens (syntax errors). */
+ token->index = json->ptr - json->data;
+
+ /* Don't advance the pointer for an error or the end */
+ if (token->type == T_ERROR) {
+ json_set_token_error(token, json, "invalid token");
+ return;
+ }
+
+ if (token->type == T_END) {
+ return;
+ }
+
+ /* Found a known single character token, advance index and return */
+ if (token->type != T_UNKNOWN) {
+ json->ptr++;
+ return;
+ }
+
+ /* Process characters which triggered T_UNKNOWN
+ *
+ * Must use strncmp() to match the front of the JSON string.
+ * JSON identifier must be lowercase.
+ * When strict_numbers if disabled, either case is allowed for
+ * Infinity/NaN (since we are no longer following the spec..) */
+ if (ch == '"') {
+ json_next_string_token(json, token);
+ return;
+ } else if (ch == '-' || ('0' <= ch && ch <= '9')) {
+ if (!json->cfg->decode_invalid_numbers && json_is_invalid_number(json)) {
+ json_set_token_error(token, json, "invalid number");
+ return;
+ }
+ json_next_number_token(json, token);
+ return;
+ } else if (!strncmp(json->ptr, "true", 4)) {
+ token->type = T_BOOLEAN;
+ token->value.boolean = 1;
+ json->ptr += 4;
+ return;
+ } else if (!strncmp(json->ptr, "false", 5)) {
+ token->type = T_BOOLEAN;
+ token->value.boolean = 0;
+ json->ptr += 5;
+ return;
+ } else if (!strncmp(json->ptr, "null", 4)) {
+ token->type = T_NULL;
+ json->ptr += 4;
+ return;
+ } else if (json->cfg->decode_invalid_numbers &&
+ json_is_invalid_number(json)) {
+ /* When decode_invalid_numbers is enabled, only attempt to process
+ * numbers we know are invalid JSON (Inf, NaN, hex)
+ * This is required to generate an appropriate token error,
+ * otherwise all bad tokens will register as "invalid number"
+ */
+ json_next_number_token(json, token);
+ return;
+ }
+
+ /* Token starts with t/f/n but isn't recognised above. */
+ json_set_token_error(token, json, "invalid token");
+}
+
+/* This function does not return.
+ * DO NOT CALL WITH DYNAMIC MEMORY ALLOCATED.
+ * The only supported exception is the temporary parser string
+ * json->tmp struct.
+ * json and token should exist on the stack somewhere.
+ * luaL_error() will long_jmp and release the stack */
+static void json_throw_parse_error(lua_State *l, json_parse_t *json,
+ const char *exp, json_token_t *token)
+{
+ const char *found;
+
+ strbuf_free(json->tmp);
+
+ if (token->type == T_ERROR)
+ found = token->value.string;
+ else
+ found = json_token_type_name[token->type];
+
+ /* Note: token->index is 0 based, display starting from 1 */
+ luaL_error(l, "Expected %s but found %s at character %d",
+ exp, found, token->index + 1);
+}
+
+static inline void json_decode_ascend(json_parse_t *json)
+{
+ json->current_depth--;
+}
+
+static void json_decode_descend(lua_State *l, json_parse_t *json, int slots)
+{
+ json->current_depth++;
+
+ if (json->current_depth <= json->cfg->decode_max_depth &&
+ lua_checkstack(l, slots)) {
+ return;
+ }
+
+ strbuf_free(json->tmp);
+ luaL_error(l, "Found too many nested data structures (%d) at character %d",
+ json->current_depth, json->ptr - json->data);
+}
+
+static void json_parse_object_context(lua_State *l, json_parse_t *json)
+{
+ json_token_t token;
+
+ /* 3 slots required:
+ * .., table, key, value */
+ json_decode_descend(l, json, 3);
+
+ lua_newtable(l);
+
+ json_next_token(json, &token);
+
+ /* Handle empty objects */
+ if (token.type == T_OBJ_END) {
+ nlua_pushref(l, nlua_empty_dict_ref); \
+ lua_setmetatable(l, -2); \
+ json_decode_ascend(json);
+ return;
+ }
+
+ while (1) {
+ if (token.type != T_STRING)
+ json_throw_parse_error(l, json, "object key string", &token);
+
+ /* Push key */
+ lua_pushlstring(l, token.value.string, token.string_len);
+
+ json_next_token(json, &token);
+ if (token.type != T_COLON)
+ json_throw_parse_error(l, json, "colon", &token);
+
+ /* Fetch value */
+ json_next_token(json, &token);
+ json_process_value(l, json, &token);
+
+ /* Set key = value */
+ lua_rawset(l, -3);
+
+ json_next_token(json, &token);
+
+ if (token.type == T_OBJ_END) {
+ json_decode_ascend(json);
+ return;
+ }
+
+ if (token.type != T_COMMA)
+ json_throw_parse_error(l, json, "comma or object end", &token);
+
+ json_next_token(json, &token);
+ }
+}
+
+/* Handle the array context */
+static void json_parse_array_context(lua_State *l, json_parse_t *json)
+{
+ json_token_t token;
+ int i;
+
+ /* 2 slots required:
+ * .., table, value */
+ json_decode_descend(l, json, 2);
+
+ lua_newtable(l);
+
+ /* set array_mt on the table at the top of the stack */
+ if (json->cfg->decode_array_with_array_mt) {
+ lua_pushlightuserdata(l, json_lightudata_mask(&json_array));
+ lua_rawget(l, LUA_REGISTRYINDEX);
+ lua_setmetatable(l, -2);
+ }
+
+ json_next_token(json, &token);
+
+ /* Handle empty arrays */
+ if (token.type == T_ARR_END) {
+ json_decode_ascend(json);
+ return;
+ }
+
+ for (i = 1; ; i++) {
+ json_process_value(l, json, &token);
+ lua_rawseti(l, -2, i); /* arr[i] = value */
+
+ json_next_token(json, &token);
+
+ if (token.type == T_ARR_END) {
+ json_decode_ascend(json);
+ return;
+ }
+
+ if (token.type != T_COMMA)
+ json_throw_parse_error(l, json, "comma or array end", &token);
+
+ json_next_token(json, &token);
+ }
+}
+
+/* Handle the "value" context */
+static void json_process_value(lua_State *l, json_parse_t *json,
+ json_token_t *token)
+{
+ switch (token->type) {
+ case T_STRING:
+ lua_pushlstring(l, token->value.string, token->string_len);
+ break;;
+ case T_NUMBER:
+ lua_pushnumber(l, token->value.number);
+ break;;
+ case T_BOOLEAN:
+ lua_pushboolean(l, token->value.boolean);
+ break;;
+ case T_OBJ_BEGIN:
+ json_parse_object_context(l, json);
+ break;;
+ case T_ARR_BEGIN:
+ json_parse_array_context(l, json);
+ break;;
+ case T_NULL:
+ nlua_pushref(l, nlua_nil_ref);
+ break;;
+ default:
+ json_throw_parse_error(l, json, "value", token);
+ }
+}
+
+static int json_decode(lua_State *l)
+{
+ json_parse_t json;
+ json_token_t token;
+ size_t json_len;
+
+ luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument");
+
+ json.cfg = json_fetch_config(l);
+ json.data = luaL_checklstring(l, 1, &json_len);
+ json.current_depth = 0;
+ json.ptr = json.data;
+
+ /* Detect Unicode other than UTF-8 (see RFC 4627, Sec 3)
+ *
+ * CJSON can support any simple data type, hence only the first
+ * character is guaranteed to be ASCII (at worst: '"'). This is
+ * still enough to detect whether the wrong encoding is in use. */
+ if (json_len >= 2 && (!json.data[0] || !json.data[1]))
+ luaL_error(l, "JSON parser does not support UTF-16 or UTF-32");
+
+ /* Ensure the temporary buffer can hold the entire string.
+ * This means we no longer need to do length checks since the decoded
+ * string must be smaller than the entire json string */
+ json.tmp = strbuf_new(json_len);
+
+ json_next_token(&json, &token);
+ json_process_value(l, &json, &token);
+
+ /* Ensure there is no more input left */
+ json_next_token(&json, &token);
+
+ if (token.type != T_END)
+ json_throw_parse_error(l, &json, "the end", &token);
+
+ strbuf_free(json.tmp);
+
+ return 1;
+}
+
+/* ===== INITIALISATION ===== */
+
+#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 502
+/* Compatibility for Lua 5.1 and older LuaJIT.
+ *
+ * compat_luaL_setfuncs() is used to create a module table where the functions
+ * have json_config_t as their first upvalue. Code borrowed from Lua 5.2
+ * source's luaL_setfuncs().
+ */
+static void compat_luaL_setfuncs(lua_State *l, const luaL_Reg *reg, int nup)
+{
+ int i;
+
+ luaL_checkstack(l, nup, "too many upvalues");
+ for (; reg->name != NULL; reg++) { /* fill the table with given functions */
+ for (i = 0; i < nup; i++) /* copy upvalues to the top */
+ lua_pushvalue(l, -nup);
+ lua_pushcclosure(l, reg->func, nup); /* closure with those upvalues */
+ lua_setfield(l, -(nup + 2), reg->name);
+ }
+ lua_pop(l, nup); /* remove upvalues */
+}
+#else
+#define compat_luaL_setfuncs(L, reg, nup) luaL_setfuncs(L, reg, nup)
+#endif
+
+/* Call target function in protected mode with all supplied args.
+ * Assumes target function only returns a single non-nil value.
+ * Convert and return thrown errors as: nil, "error message" */
+static int json_protect_conversion(lua_State *l)
+{
+ int err;
+
+ /* Deliberately throw an error for invalid arguments */
+ luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument");
+
+ /* pcall() the function stored as upvalue(1) */
+ lua_pushvalue(l, lua_upvalueindex(1));
+ lua_insert(l, 1);
+ err = lua_pcall(l, 1, 1, 0);
+ if (!err)
+ return 1;
+
+ if (err == LUA_ERRRUN) {
+ lua_pushnil(l);
+ lua_insert(l, -2);
+ return 2;
+ }
+
+ /* Since we are not using a custom error handler, the only remaining
+ * errors are memory related */
+ return luaL_error(l, "Memory allocation error in CJSON protected call");
+}
+
+/* Return cjson module table */
+int lua_cjson_new(lua_State *l)
+{
+ luaL_Reg reg[] = {
+ { "encode", json_encode },
+ { "decode", json_decode },
+ { "encode_empty_table_as_object", json_cfg_encode_empty_table_as_object },
+ { "decode_array_with_array_mt", json_cfg_decode_array_with_array_mt },
+ { "encode_sparse_array", json_cfg_encode_sparse_array },
+ { "encode_max_depth", json_cfg_encode_max_depth },
+ { "decode_max_depth", json_cfg_decode_max_depth },
+ { "encode_number_precision", json_cfg_encode_number_precision },
+ { "encode_keep_buffer", json_cfg_encode_keep_buffer },
+ { "encode_invalid_numbers", json_cfg_encode_invalid_numbers },
+ { "decode_invalid_numbers", json_cfg_decode_invalid_numbers },
+ { "encode_escape_forward_slash", json_cfg_encode_escape_forward_slash },
+ { "new", lua_cjson_new },
+ { NULL, NULL }
+ };
+
+ /* Initialise number conversions */
+ fpconv_init();
+
+ /* Test if array metatables are in registry */
+ lua_pushlightuserdata(l, json_lightudata_mask(&json_empty_array));
+ lua_rawget(l, LUA_REGISTRYINDEX);
+ if (lua_isnil(l, -1)) {
+ /* Create array metatables.
+ *
+ * If multiple calls to lua_cjson_new() are made,
+ * this prevents overriding the tables at the given
+ * registry's index with a new one.
+ */
+ lua_pop(l, 1);
+
+ /* empty_array_mt */
+ lua_pushlightuserdata(l, json_lightudata_mask(&json_empty_array));
+ lua_newtable(l);
+ lua_rawset(l, LUA_REGISTRYINDEX);
+
+ /* array_mt */
+ lua_pushlightuserdata(l, json_lightudata_mask(&json_array));
+ lua_newtable(l);
+ lua_rawset(l, LUA_REGISTRYINDEX);
+ }
+
+ /* cjson module table */
+ lua_newtable(l);
+
+ /* Register functions with config data as upvalue */
+ json_create_config(l);
+ compat_luaL_setfuncs(l, reg, 1);
+
+ /* Set cjson.null */
+ nlua_pushref(l, nlua_nil_ref);
+ lua_setfield(l, -2, "null");
+
+ /* Set cjson.empty_array_mt */
+ lua_pushlightuserdata(l, json_lightudata_mask(&json_empty_array));
+ lua_rawget(l, LUA_REGISTRYINDEX);
+ lua_setfield(l, -2, "empty_array_mt");
+
+ /* Set cjson.array_mt */
+ lua_pushlightuserdata(l, json_lightudata_mask(&json_array));
+ lua_rawget(l, LUA_REGISTRYINDEX);
+ lua_setfield(l, -2, "array_mt");
+
+ /* Set cjson.empty_array */
+ lua_pushlightuserdata(l, json_lightudata_mask(&json_array));
+ lua_setfield(l, -2, "empty_array");
+
+ /* Set module name / version fields */
+ lua_pushliteral(l, CJSON_MODNAME);
+ lua_setfield(l, -2, "_NAME");
+ lua_pushliteral(l, CJSON_VERSION);
+ lua_setfield(l, -2, "_VERSION");
+
+ return 1;
+}
+
+/* Return cjson.safe module table */
+static int lua_cjson_safe_new(lua_State *l)
+{
+ const char *func[] = { "decode", "encode", NULL };
+ int i;
+
+ lua_cjson_new(l);
+
+ /* Fix new() method */
+ lua_pushcfunction(l, lua_cjson_safe_new);
+ lua_setfield(l, -2, "new");
+
+ for (i = 0; func[i]; i++) {
+ lua_getfield(l, -1, func[i]);
+ lua_pushcclosure(l, json_protect_conversion, 1);
+ lua_setfield(l, -2, func[i]);
+ }
+
+ return 1;
+}
+
+int luaopen_cjson(lua_State *l)
+{
+ lua_cjson_new(l);
+
+#ifdef ENABLE_CJSON_GLOBAL
+ /* Register a global "cjson" table. */
+ lua_pushvalue(l, -1);
+ lua_setglobal(l, CJSON_MODNAME);
+#endif
+
+ /* Return cjson table */
+ return 1;
+}
+
+int luaopen_cjson_safe(lua_State *l)
+{
+ lua_cjson_safe_new(l);
+
+ /* Return cjson.safe table */
+ return 1;
+}
+
+/* vi:ai et sw=4 ts=4:
+ */
diff --git a/src/cjson/lua_cjson.h b/src/cjson/lua_cjson.h
new file mode 100644
index 0000000000..3f70b679be
--- /dev/null
+++ b/src/cjson/lua_cjson.h
@@ -0,0 +1,10 @@
+#ifndef CJSON_LUACJSON_H
+#define CJSON_LUACJSON_H
+
+#include "lua.h"
+
+int lua_cjson_new(lua_State *l);
+int luaopen_cjson(lua_State *l);
+int luaopen_cjson_safe(lua_State *l);
+
+#endif // CJSON_LUACJSON_H
diff --git a/src/cjson/strbuf.c b/src/cjson/strbuf.c
new file mode 100644
index 0000000000..f0f7f4b9a3
--- /dev/null
+++ b/src/cjson/strbuf.c
@@ -0,0 +1,251 @@
+/* strbuf - String buffer routines
+ *
+ * Copyright (c) 2010-2012 Mark Pulford <mark@kyne.com.au>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "strbuf.h"
+
+static void die(const char *fmt, ...)
+{
+ va_list arg;
+
+ va_start(arg, fmt);
+ vfprintf(stderr, fmt, arg);
+ va_end(arg);
+ fprintf(stderr, "\n");
+
+ exit(-1);
+}
+
+void strbuf_init(strbuf_t *s, int len)
+{
+ int size;
+
+ if (len <= 0)
+ size = STRBUF_DEFAULT_SIZE;
+ else
+ size = len + 1; /* \0 terminator */
+
+ s->buf = NULL;
+ s->size = size;
+ s->length = 0;
+ s->increment = STRBUF_DEFAULT_INCREMENT;
+ s->dynamic = 0;
+ s->reallocs = 0;
+ s->debug = 0;
+
+ s->buf = malloc(size);
+ if (!s->buf)
+ die("Out of memory");
+
+ strbuf_ensure_null(s);
+}
+
+strbuf_t *strbuf_new(int len)
+{
+ strbuf_t *s;
+
+ s = malloc(sizeof(strbuf_t));
+ if (!s)
+ die("Out of memory");
+
+ strbuf_init(s, len);
+
+ /* Dynamic strbuf allocation / deallocation */
+ s->dynamic = 1;
+
+ return s;
+}
+
+void strbuf_set_increment(strbuf_t *s, int increment)
+{
+ /* Increment > 0: Linear buffer growth rate
+ * Increment < -1: Exponential buffer growth rate */
+ if (increment == 0 || increment == -1)
+ die("BUG: Invalid string increment");
+
+ s->increment = increment;
+}
+
+static inline void debug_stats(strbuf_t *s)
+{
+ if (s->debug) {
+ fprintf(stderr, "strbuf(%lx) reallocs: %d, length: %d, size: %d\n",
+ (long)s, s->reallocs, s->length, s->size);
+ }
+}
+
+/* If strbuf_t has not been dynamically allocated, strbuf_free() can
+ * be called any number of times strbuf_init() */
+void strbuf_free(strbuf_t *s)
+{
+ debug_stats(s);
+
+ if (s->buf) {
+ free(s->buf);
+ s->buf = NULL;
+ }
+ if (s->dynamic)
+ free(s);
+}
+
+char *strbuf_free_to_string(strbuf_t *s, int *len)
+{
+ char *buf;
+
+ debug_stats(s);
+
+ strbuf_ensure_null(s);
+
+ buf = s->buf;
+ if (len)
+ *len = s->length;
+
+ if (s->dynamic)
+ free(s);
+
+ return buf;
+}
+
+static int calculate_new_size(strbuf_t *s, int len)
+{
+ int reqsize, newsize;
+
+ if (len <= 0)
+ die("BUG: Invalid strbuf length requested");
+
+ /* Ensure there is room for optional NULL termination */
+ reqsize = len + 1;
+
+ /* If the user has requested to shrink the buffer, do it exactly */
+ if (s->size > reqsize)
+ return reqsize;
+
+ newsize = s->size;
+ if (s->increment < 0) {
+ /* Exponential sizing */
+ while (newsize < reqsize)
+ newsize *= -s->increment;
+ } else {
+ /* Linear sizing */
+ newsize = ((newsize + s->increment - 1) / s->increment) * s->increment;
+ }
+
+ return newsize;
+}
+
+
+/* Ensure strbuf can handle a string length bytes long (ignoring NULL
+ * optional termination). */
+void strbuf_resize(strbuf_t *s, int len)
+{
+ int newsize;
+
+ newsize = calculate_new_size(s, len);
+
+ if (s->debug > 1) {
+ fprintf(stderr, "strbuf(%lx) resize: %d => %d\n",
+ (long)s, s->size, newsize);
+ }
+
+ s->size = newsize;
+ s->buf = realloc(s->buf, s->size);
+ if (!s->buf)
+ die("Out of memory");
+ s->reallocs++;
+}
+
+void strbuf_append_string(strbuf_t *s, const char *str)
+{
+ int space, i;
+
+ space = strbuf_empty_length(s);
+
+ for (i = 0; str[i]; i++) {
+ if (space < 1) {
+ strbuf_resize(s, s->length + 1);
+ space = strbuf_empty_length(s);
+ }
+
+ s->buf[s->length] = str[i];
+ s->length++;
+ space--;
+ }
+}
+
+/* strbuf_append_fmt() should only be used when an upper bound
+ * is known for the output string. */
+void strbuf_append_fmt(strbuf_t *s, int len, const char *fmt, ...)
+{
+ va_list arg;
+ int fmt_len;
+
+ strbuf_ensure_empty_length(s, len);
+
+ va_start(arg, fmt);
+ fmt_len = vsnprintf(s->buf + s->length, len, fmt, arg);
+ va_end(arg);
+
+ if (fmt_len < 0)
+ die("BUG: Unable to convert number"); /* This should never happen.. */
+
+ s->length += fmt_len;
+}
+
+/* strbuf_append_fmt_retry() can be used when the there is no known
+ * upper bound for the output string. */
+void strbuf_append_fmt_retry(strbuf_t *s, const char *fmt, ...)
+{
+ va_list arg;
+ int fmt_len, try;
+ int empty_len;
+
+ /* If the first attempt to append fails, resize the buffer appropriately
+ * and try again */
+ for (try = 0; ; try++) {
+ va_start(arg, fmt);
+ /* Append the new formatted string */
+ /* fmt_len is the length of the string required, excluding the
+ * trailing NULL */
+ empty_len = strbuf_empty_length(s);
+ /* Add 1 since there is also space to store the terminating NULL. */
+ fmt_len = vsnprintf(s->buf + s->length, empty_len + 1, fmt, arg);
+ va_end(arg);
+
+ if (fmt_len <= empty_len)
+ break; /* SUCCESS */
+ if (try > 0)
+ die("BUG: length of formatted string changed");
+
+ strbuf_resize(s, s->length + fmt_len);
+ }
+
+ s->length += fmt_len;
+}
+
+/* vi:ai et sw=4 ts=4:
+ */
diff --git a/src/cjson/strbuf.h b/src/cjson/strbuf.h
new file mode 100644
index 0000000000..5df0b7bea3
--- /dev/null
+++ b/src/cjson/strbuf.h
@@ -0,0 +1,159 @@
+/* strbuf - String buffer routines
+ *
+ * Copyright (c) 2010-2012 Mark Pulford <mark@kyne.com.au>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+/* Workaround for MSVC */
+#ifdef _MSC_VER
+#define inline __inline
+#endif
+
+/* Size: Total bytes allocated to *buf
+ * Length: String length, excluding optional NULL terminator.
+ * Increment: Allocation increments when resizing the string buffer.
+ * Dynamic: True if created via strbuf_new()
+ */
+
+typedef struct {
+ char *buf;
+ int size;
+ int length;
+ int increment;
+ int dynamic;
+ int reallocs;
+ int debug;
+} strbuf_t;
+
+#ifndef STRBUF_DEFAULT_SIZE
+#define STRBUF_DEFAULT_SIZE 1023
+#endif
+#ifndef STRBUF_DEFAULT_INCREMENT
+#define STRBUF_DEFAULT_INCREMENT -2
+#endif
+
+/* Initialise */
+extern strbuf_t *strbuf_new(int len);
+extern void strbuf_init(strbuf_t *s, int len);
+extern void strbuf_set_increment(strbuf_t *s, int increment);
+
+/* Release */
+extern void strbuf_free(strbuf_t *s);
+extern char *strbuf_free_to_string(strbuf_t *s, int *len);
+
+/* Management */
+extern void strbuf_resize(strbuf_t *s, int len);
+static int strbuf_empty_length(strbuf_t *s);
+static int strbuf_length(strbuf_t *s);
+static char *strbuf_string(strbuf_t *s, int *len);
+static void strbuf_ensure_empty_length(strbuf_t *s, int len);
+static char *strbuf_empty_ptr(strbuf_t *s);
+static void strbuf_extend_length(strbuf_t *s, int len);
+
+/* Update */
+extern void strbuf_append_fmt(strbuf_t *s, int len, const char *fmt, ...);
+extern void strbuf_append_fmt_retry(strbuf_t *s, const char *format, ...);
+static void strbuf_append_mem(strbuf_t *s, const char *c, int len);
+extern void strbuf_append_string(strbuf_t *s, const char *str);
+static void strbuf_append_char(strbuf_t *s, const char c);
+static void strbuf_ensure_null(strbuf_t *s);
+
+/* Reset string for before use */
+static inline void strbuf_reset(strbuf_t *s)
+{
+ s->length = 0;
+}
+
+static inline int strbuf_allocated(strbuf_t *s)
+{
+ return s->buf != NULL;
+}
+
+/* Return bytes remaining in the string buffer
+ * Ensure there is space for a NULL terminator. */
+static inline int strbuf_empty_length(strbuf_t *s)
+{
+ return s->size - s->length - 1;
+}
+
+static inline void strbuf_ensure_empty_length(strbuf_t *s, int len)
+{
+ if (len > strbuf_empty_length(s))
+ strbuf_resize(s, s->length + len);
+}
+
+static inline char *strbuf_empty_ptr(strbuf_t *s)
+{
+ return s->buf + s->length;
+}
+
+static inline void strbuf_extend_length(strbuf_t *s, int len)
+{
+ s->length += len;
+}
+
+static inline int strbuf_length(strbuf_t *s)
+{
+ return s->length;
+}
+
+static inline void strbuf_append_char(strbuf_t *s, const char c)
+{
+ strbuf_ensure_empty_length(s, 1);
+ s->buf[s->length++] = c;
+}
+
+static inline void strbuf_append_char_unsafe(strbuf_t *s, const char c)
+{
+ s->buf[s->length++] = c;
+}
+
+static inline void strbuf_append_mem(strbuf_t *s, const char *c, int len)
+{
+ strbuf_ensure_empty_length(s, len);
+ memcpy(s->buf + s->length, c, len);
+ s->length += len;
+}
+
+static inline void strbuf_append_mem_unsafe(strbuf_t *s, const char *c, int len)
+{
+ memcpy(s->buf + s->length, c, len);
+ s->length += len;
+}
+
+static inline void strbuf_ensure_null(strbuf_t *s)
+{
+ s->buf[s->length] = 0;
+}
+
+static inline char *strbuf_string(strbuf_t *s, int *len)
+{
+ if (len)
+ *len = s->length;
+
+ return s->buf;
+}
+
+/* vi:ai et sw=4 ts=4:
+ */
diff --git a/src/clint.py b/src/clint.py
index 9b4128a0c9..e7d76366b0 100755
--- a/src/clint.py
+++ b/src/clint.py
@@ -68,7 +68,7 @@ Syntax: clint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
<file> [file] ...
The style guidelines this tries to follow are those in
- http://neovim.io/development-wiki/style-guide/style-guide.xml
+ http://neovim.io/develop/style-guide.xml
Note: This is Google's cpplint.py modified for use with the Neovim project,
which follows the Google C++ coding convention except with the following
@@ -264,7 +264,7 @@ _error_suppressions_2 = set()
# The allowed line length of files.
# This is set by --linelength flag.
-_line_length = 80
+_line_length = 100
# The allowed extensions for file names
# This is set by --extensions flag.
diff --git a/src/mpack/LICENSE-MIT b/src/mpack/LICENSE-MIT
new file mode 100644
index 0000000000..030ba872c5
--- /dev/null
+++ b/src/mpack/LICENSE-MIT
@@ -0,0 +1,22 @@
+Copyright (c) 2016 Thiago de Arruda
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
diff --git a/src/mpack/conv.c b/src/mpack/conv.c
new file mode 100644
index 0000000000..31297a8784
--- /dev/null
+++ b/src/mpack/conv.c
@@ -0,0 +1,378 @@
+// 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 "conv.h"
+
+static int mpack_fits_single(double v);
+static mpack_value_t mpack_pack_ieee754(double v, unsigned m, unsigned e);
+static int mpack_is_be(void) FPURE;
+static double mpack_fmod_pow2_32(double a);
+
+
+#define POW2(n) \
+ ((double)(1 << (n / 2)) * (double)(1 << (n / 2)) * (double)(1 << (n % 2)))
+
+#define MPACK_SWAP_VALUE(val) \
+ do { \
+ mpack_uint32_t lo = val.lo; \
+ val.lo = val.hi; \
+ val.hi = lo; \
+ } while (0)
+
+MPACK_API mpack_token_t mpack_pack_nil(void)
+{
+ mpack_token_t rv;
+ rv.type = MPACK_TOKEN_NIL;
+ return rv;
+}
+
+MPACK_API mpack_token_t mpack_pack_boolean(unsigned v)
+{
+ mpack_token_t rv;
+ rv.type = MPACK_TOKEN_BOOLEAN;
+ rv.data.value.lo = v ? 1 : 0;
+ rv.data.value.hi = 0;
+ return rv;
+}
+
+MPACK_API mpack_token_t mpack_pack_uint(mpack_uintmax_t v)
+{
+ mpack_token_t rv;
+ rv.data.value.lo = v & 0xffffffff;
+ rv.data.value.hi = (mpack_uint32_t)((v >> 31) >> 1);
+ rv.type = MPACK_TOKEN_UINT;
+ return rv;
+}
+
+MPACK_API mpack_token_t mpack_pack_sint(mpack_sintmax_t v)
+{
+ if (v < 0) {
+ mpack_token_t rv;
+ mpack_uintmax_t tc = -((mpack_uintmax_t)(v + 1)) + 1;
+ tc = ~tc + 1;
+ rv = mpack_pack_uint(tc);
+ rv.type = MPACK_TOKEN_SINT;
+ return rv;
+ }
+
+ return mpack_pack_uint((mpack_uintmax_t)v);
+}
+
+MPACK_API mpack_token_t mpack_pack_float_compat(double v)
+{
+ /* ieee754 single-precision limits to determine if "v" can be fully
+ * represented in 4 bytes */
+ mpack_token_t rv;
+
+ if (mpack_fits_single(v)) {
+ rv.length = 4;
+ rv.data.value = mpack_pack_ieee754(v, 23, 8);
+ } else {
+ rv.length = 8;
+ rv.data.value = mpack_pack_ieee754(v, 52, 11);
+ }
+
+ rv.type = MPACK_TOKEN_FLOAT;
+ return rv;
+}
+
+MPACK_API mpack_token_t mpack_pack_float_fast(double v)
+{
+ /* ieee754 single-precision limits to determine if "v" can be fully
+ * represented in 4 bytes */
+ mpack_token_t rv;
+
+ if (mpack_fits_single(v)) {
+ union {
+ float f;
+ mpack_uint32_t m;
+ } conv;
+ conv.f = (float)v;
+ rv.length = 4;
+ rv.data.value.lo = conv.m;
+ rv.data.value.hi = 0;
+ } else {
+ union {
+ double d;
+ mpack_value_t m;
+ } conv;
+ conv.d = v;
+ rv.length = 8;
+ rv.data.value = conv.m;
+ if (mpack_is_be()) {
+ MPACK_SWAP_VALUE(rv.data.value);
+ }
+ }
+
+ rv.type = MPACK_TOKEN_FLOAT;
+ return rv;
+}
+
+MPACK_API mpack_token_t mpack_pack_number(double v)
+{
+ mpack_token_t tok;
+ double vabs;
+ vabs = v < 0 ? -v : v;
+ assert(v <= 9007199254740991. && v >= -9007199254740991.);
+ tok.data.value.hi = (mpack_uint32_t)(vabs / POW2(32));
+ tok.data.value.lo = (mpack_uint32_t)mpack_fmod_pow2_32(vabs);
+
+ if (v < 0) {
+ /* Compute the two's complement */
+ tok.type = MPACK_TOKEN_SINT;
+ tok.data.value.hi = ~tok.data.value.hi;
+ tok.data.value.lo = ~tok.data.value.lo + 1;
+ if (!tok.data.value.lo) tok.data.value.hi++;
+ if (tok.data.value.lo == 0 && tok.data.value.hi == 0) tok.length = 1;
+ else if (tok.data.value.lo < 0x80000000) tok.length = 8;
+ else if (tok.data.value.lo < 0xffff7fff) tok.length = 4;
+ else if (tok.data.value.lo < 0xffffff7f) tok.length = 2;
+ else tok.length = 1;
+ } else {
+ tok.type = MPACK_TOKEN_UINT;
+ if (tok.data.value.hi) tok.length = 8;
+ else if (tok.data.value.lo > 0xffff) tok.length = 4;
+ else if (tok.data.value.lo > 0xff) tok.length = 2;
+ else tok.length = 1;
+ }
+
+ if (mpack_unpack_number(tok) != v) {
+ return mpack_pack_float(v);
+ }
+
+ return tok;
+}
+
+MPACK_API mpack_token_t mpack_pack_chunk(const char *p, mpack_uint32_t l)
+{
+ mpack_token_t rv;
+ rv.type = MPACK_TOKEN_CHUNK;
+ rv.data.chunk_ptr = p;
+ rv.length = l;
+ return rv;
+}
+
+MPACK_API mpack_token_t mpack_pack_str(mpack_uint32_t l)
+{
+ mpack_token_t rv;
+ rv.type = MPACK_TOKEN_STR;
+ rv.length = l;
+ return rv;
+}
+
+MPACK_API mpack_token_t mpack_pack_bin(mpack_uint32_t l)
+{
+ mpack_token_t rv;
+ rv.type = MPACK_TOKEN_BIN;
+ rv.length = l;
+ return rv;
+}
+
+MPACK_API mpack_token_t mpack_pack_ext(int t, mpack_uint32_t l)
+{
+ mpack_token_t rv;
+ rv.type = MPACK_TOKEN_EXT;
+ rv.length = l;
+ rv.data.ext_type = t;
+ return rv;
+}
+
+MPACK_API mpack_token_t mpack_pack_array(mpack_uint32_t l)
+{
+ mpack_token_t rv;
+ rv.type = MPACK_TOKEN_ARRAY;
+ rv.length = l;
+ return rv;
+}
+
+MPACK_API mpack_token_t mpack_pack_map(mpack_uint32_t l)
+{
+ mpack_token_t rv;
+ rv.type = MPACK_TOKEN_MAP;
+ rv.length = l;
+ return rv;
+}
+
+MPACK_API bool mpack_unpack_boolean(mpack_token_t t)
+{
+ return t.data.value.lo || t.data.value.hi;
+}
+
+MPACK_API mpack_uintmax_t mpack_unpack_uint(mpack_token_t t)
+{
+ return (((mpack_uintmax_t)t.data.value.hi << 31) << 1) | t.data.value.lo;
+}
+
+/* unpack signed integer without relying on two's complement as internal
+ * representation */
+MPACK_API mpack_sintmax_t mpack_unpack_sint(mpack_token_t t)
+{
+ mpack_uint32_t hi = t.data.value.hi;
+ mpack_uint32_t lo = t.data.value.lo;
+ mpack_uintmax_t rv = lo;
+ assert(t.length <= sizeof(mpack_sintmax_t));
+
+ if (t.length == 8) {
+ rv |= (((mpack_uintmax_t)hi) << 31) << 1;
+ }
+ /* reverse the two's complement so that lo/hi contain the absolute value.
+ * note that we have to mask ~rv so that it reflects the two's complement
+ * of the appropriate byte length */
+ rv = (~rv & (((mpack_uintmax_t)1 << ((t.length * 8) - 1)) - 1)) + 1;
+ /* negate and return the absolute value, making sure mpack_sintmax_t can
+ * represent the positive cast. */
+ return -((mpack_sintmax_t)(rv - 1)) - 1;
+}
+
+MPACK_API double mpack_unpack_float_compat(mpack_token_t t)
+{
+ mpack_uint32_t sign;
+ mpack_sint32_t exponent, bias;
+ unsigned mantbits;
+ unsigned expbits;
+ double mant;
+
+ if (t.data.value.lo == 0 && t.data.value.hi == 0)
+ /* nothing to do */
+ return 0;
+
+ if (t.length == 4) mantbits = 23, expbits = 8;
+ else mantbits = 52, expbits = 11;
+ bias = (1 << (expbits - 1)) - 1;
+
+ /* restore sign/exponent/mantissa */
+ if (mantbits == 52) {
+ sign = t.data.value.hi >> 31;
+ exponent = (t.data.value.hi >> 20) & ((1 << 11) - 1);
+ mant = (t.data.value.hi & ((1 << 20) - 1)) * POW2(32);
+ mant += t.data.value.lo;
+ } else {
+ sign = t.data.value.lo >> 31;
+ exponent = (t.data.value.lo >> 23) & ((1 << 8) - 1);
+ mant = t.data.value.lo & ((1 << 23) - 1);
+ }
+
+ mant /= POW2(mantbits);
+ if (exponent) mant += 1.0; /* restore leading 1 */
+ else exponent = 1; /* subnormal */
+ exponent -= bias;
+
+ /* restore original value */
+ while (exponent > 0) mant *= 2.0, exponent--;
+ while (exponent < 0) mant /= 2.0, exponent++;
+ return mant * (sign ? -1 : 1);
+}
+
+MPACK_API double mpack_unpack_float_fast(mpack_token_t t)
+{
+ if (t.length == 4) {
+ union {
+ float f;
+ mpack_uint32_t m;
+ } conv;
+ conv.m = t.data.value.lo;
+ return conv.f;
+ } else {
+ union {
+ double d;
+ mpack_value_t m;
+ } conv;
+ conv.m = t.data.value;
+
+ if (mpack_is_be()) {
+ MPACK_SWAP_VALUE(conv.m);
+ }
+
+ return conv.d;
+ }
+}
+
+MPACK_API double mpack_unpack_number(mpack_token_t t)
+{
+ double rv;
+ mpack_uint32_t hi, lo;
+ if (t.type == MPACK_TOKEN_FLOAT) return mpack_unpack_float(t);
+ assert(t.type == MPACK_TOKEN_UINT || t.type == MPACK_TOKEN_SINT);
+ hi = t.data.value.hi;
+ lo = t.data.value.lo;
+ if (t.type == MPACK_TOKEN_SINT) {
+ /* same idea as mpack_unpack_sint, except here we shouldn't rely on
+ * mpack_uintmax_t having 64-bits, operating on the 32-bit words separately.
+ */
+ if (!hi) {
+ assert(t.length <= 4);
+ hi = 0;
+ lo = (~lo & (((mpack_uint32_t)1 << ((t.length * 8) - 1)) - 1));
+ } else {
+ hi = ~hi;
+ lo = ~lo;
+ }
+ lo++;
+ if (!lo) hi++;
+ }
+ rv = (double)lo + POW2(32) * hi;
+ return t.type == MPACK_TOKEN_SINT ? -rv : rv;
+}
+
+static int mpack_fits_single(double v)
+{
+ return (float)v == v;
+}
+
+static mpack_value_t mpack_pack_ieee754(double v, unsigned mantbits,
+ unsigned expbits)
+{
+ mpack_value_t rv = {0, 0};
+ mpack_sint32_t exponent, bias = (1 << (expbits - 1)) - 1;
+ mpack_uint32_t sign;
+ double mant;
+
+ if (v == 0) {
+ rv.lo = 0;
+ rv.hi = 0;
+ goto end;
+ }
+
+ if (v < 0) sign = 1, mant = -v;
+ else sign = 0, mant = v;
+
+ exponent = 0;
+ while (mant >= 2.0) mant /= 2.0, exponent++;
+ while (mant < 1.0 && exponent > -(bias - 1)) mant *= 2.0, exponent--;
+
+ if (mant < 1.0) exponent = -bias; /* subnormal value */
+ else mant = mant - 1.0; /* remove leading 1 */
+ exponent += bias;
+ mant *= POW2(mantbits);
+
+ if (mantbits == 52) {
+ rv.hi = (mpack_uint32_t)(mant / POW2(32));
+ rv.lo = (mpack_uint32_t)(mant - rv.hi * POW2(32));
+ rv.hi |= ((mpack_uint32_t)exponent << 20) | (sign << 31);
+ } else if (mantbits == 23) {
+ rv.hi = 0;
+ rv.lo = (mpack_uint32_t)mant;
+ rv.lo |= ((mpack_uint32_t)exponent << 23) | (sign << 31);
+ }
+
+end:
+ return rv;
+}
+
+static int mpack_is_be(void)
+{
+ union {
+ mpack_uint32_t i;
+ char c[sizeof(mpack_uint32_t)];
+ } test;
+
+ test.i = 1;
+ return test.c[0] == 0;
+}
+
+/* this simplified version of `fmod` that returns the remainder of double
+ * division by 0xffffffff, which is enough for our purposes */
+static double mpack_fmod_pow2_32(double a)
+{
+ return a - ((double)(mpack_uint32_t)(a / POW2(32)) * POW2(32));
+}
diff --git a/src/mpack/conv.h b/src/mpack/conv.h
new file mode 100644
index 0000000000..71f14a067e
--- /dev/null
+++ b/src/mpack/conv.h
@@ -0,0 +1,55 @@
+#ifndef MPACK_CONV_H
+#define MPACK_CONV_H
+
+#include "mpack_core.h"
+
+#if ULLONG_MAX == 0xffffffffffffffff
+typedef long long mpack_sintmax_t;
+typedef unsigned long long mpack_uintmax_t;
+#elif UINT64_MAX == 0xffffffffffffffff
+typedef int64_t mpack_sintmax_t;
+typedef uint64_t mpack_uintmax_t;
+#else
+typedef mpack_sint32_t mpack_sintmax_t;
+typedef mpack_uint32_t mpack_uintmax_t;
+#endif
+
+#ifndef bool
+# define bool unsigned
+#endif
+
+MPACK_API mpack_token_t mpack_pack_nil(void) FUNUSED FPURE;
+MPACK_API mpack_token_t mpack_pack_boolean(unsigned v) FUNUSED FPURE;
+MPACK_API mpack_token_t mpack_pack_uint(mpack_uintmax_t v) FUNUSED FPURE;
+MPACK_API mpack_token_t mpack_pack_sint(mpack_sintmax_t v) FUNUSED FPURE;
+MPACK_API mpack_token_t mpack_pack_float_compat(double v) FUNUSED FPURE;
+MPACK_API mpack_token_t mpack_pack_float_fast(double v) FUNUSED FPURE;
+MPACK_API mpack_token_t mpack_pack_number(double v) FUNUSED FPURE;
+MPACK_API mpack_token_t mpack_pack_chunk(const char *p, mpack_uint32_t l)
+ FUNUSED FPURE FNONULL;
+MPACK_API mpack_token_t mpack_pack_str(mpack_uint32_t l) FUNUSED FPURE;
+MPACK_API mpack_token_t mpack_pack_bin(mpack_uint32_t l) FUNUSED FPURE;
+MPACK_API mpack_token_t mpack_pack_ext(int type, mpack_uint32_t l)
+ FUNUSED FPURE;
+MPACK_API mpack_token_t mpack_pack_array(mpack_uint32_t l) FUNUSED FPURE;
+MPACK_API mpack_token_t mpack_pack_map(mpack_uint32_t l) FUNUSED FPURE;
+MPACK_API bool mpack_unpack_boolean(mpack_token_t t) FUNUSED FPURE;
+MPACK_API mpack_uintmax_t mpack_unpack_uint(mpack_token_t t) FUNUSED FPURE;
+MPACK_API mpack_sintmax_t mpack_unpack_sint(mpack_token_t t) FUNUSED FPURE;
+MPACK_API double mpack_unpack_float_fast(mpack_token_t t) FUNUSED FPURE;
+MPACK_API double mpack_unpack_float_compat(mpack_token_t t) FUNUSED FPURE;
+MPACK_API double mpack_unpack_number(mpack_token_t t) FUNUSED FPURE;
+
+/* The mpack_{pack,unpack}_float_fast functions should work in 99% of the
+ * platforms. When compiling for a platform where floats don't use ieee754 as
+ * the internal format, pass
+ * -Dmpack_{pack,unpack}_float=mpack_{pack,unpack}_float_compat to the
+ * compiler.*/
+#ifndef mpack_pack_float
+# define mpack_pack_float mpack_pack_float_fast
+#endif
+#ifndef mpack_unpack_float
+# define mpack_unpack_float mpack_unpack_float_fast
+#endif
+
+#endif /* MPACK_CONV_H */
diff --git a/src/mpack/lmpack.c b/src/mpack/lmpack.c
new file mode 100644
index 0000000000..4b0e132a3a
--- /dev/null
+++ b/src/mpack/lmpack.c
@@ -0,0 +1,1218 @@
+// 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
+
+/*
+ * This module exports three classes, and each instance of those classes has its
+ * own private registry for temporary reference storage(keeping state between
+ * calls). A private registry makes managing memory much easier since all we
+ * have to do is call luaL_unref passing the registry reference when the
+ * instance is collected by the __gc metamethod.
+ *
+ * This private registry is manipulated with `lmpack_ref` / `lmpack_unref` /
+ * `lmpack_geti`, which are analogous to `luaL_ref` / `luaL_unref` /
+ * `lua_rawgeti` but operate on the private registry passed as argument.
+ *
+ * In order to simplify debug registry leaks during normal operation(with the
+ * leak_test.lua script), these `lmpack_*` registry functions will target the
+ * normal lua registry when MPACK_DEBUG_REGISTRY_LEAK is defined during
+ * compilation.
+ */
+#define LUA_LIB
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <lauxlib.h>
+#include <lua.h>
+#include <luaconf.h>
+
+#include "nvim/macros.h"
+
+#include "lmpack.h"
+
+#include "rpc.h"
+
+#define UNPACKER_META_NAME "mpack.Unpacker"
+#define PACKER_META_NAME "mpack.Packer"
+#define SESSION_META_NAME "mpack.Session"
+#define NIL_NAME "mpack.NIL"
+#define EMPTY_DICT_NAME "mpack.empty_dict"
+
+/*
+ * TODO(tarruda): When targeting lua 5.3 and being compiled with `long long`
+ * support(not -ansi), we should make use of lua 64 bit integers for
+ * representing msgpack integers, since `double` can't represent the full range.
+ */
+
+#ifndef luaL_reg
+/* Taken from Lua5.1's lauxlib.h */
+#define luaL_reg luaL_Reg
+#endif
+
+#if LUA_VERSION_NUM > 501
+#ifndef luaL_register
+#define luaL_register(L,n,f) luaL_setfuncs(L,f,0)
+#endif
+#endif
+
+typedef struct {
+ lua_State *L;
+ mpack_parser_t *parser;
+ int reg, ext, unpacking, mtdict;
+ char *string_buffer;
+} Unpacker;
+
+typedef struct {
+ lua_State *L;
+ mpack_parser_t *parser;
+ int reg, ext, root, packing, mtdict;
+ int is_bin, is_bin_fn;
+} Packer;
+
+typedef struct {
+ lua_State *L;
+ int reg;
+ mpack_rpc_session_t *session;
+ struct {
+ int type;
+ mpack_rpc_message_t msg;
+ int method_or_error;
+ int args_or_result;
+ } unpacked;
+ int unpacker;
+} Session;
+
+static int lmpack_ref(lua_State *L, int reg)
+{
+#ifdef MPACK_DEBUG_REGISTRY_LEAK
+ return luaL_ref(L, LUA_REGISTRYINDEX);
+#else
+ int rv;
+ lua_rawgeti(L, LUA_REGISTRYINDEX, reg);
+ lua_pushvalue(L, -2);
+ rv = luaL_ref(L, -2);
+ lua_pop(L, 2);
+ return rv;
+#endif
+}
+
+static void lmpack_unref(lua_State *L, int reg, int ref)
+{
+#ifdef MPACK_DEBUG_REGISTRY_LEAK
+ luaL_unref(L, LUA_REGISTRYINDEX, ref);
+#else
+ lua_rawgeti(L, LUA_REGISTRYINDEX, reg);
+ luaL_unref(L, -1, ref);
+ lua_pop(L, 1);
+#endif
+}
+
+static void lmpack_geti(lua_State *L, int reg, int ref)
+{
+#ifdef MPACK_DEBUG_REGISTRY_LEAK
+ lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
+#else
+ lua_rawgeti(L, LUA_REGISTRYINDEX, reg);
+ lua_rawgeti(L, -1, ref);
+ lua_replace(L, -2);
+#endif
+}
+
+/* make a shallow copy of the table on stack and remove it after the copy is
+ * done */
+static void lmpack_shallow_copy(lua_State *L)
+{
+ lua_newtable(L);
+ lua_pushnil(L);
+ while (lua_next(L, -3)) {
+ lua_pushvalue(L, -2);
+ lua_insert(L, -2);
+ lua_settable(L, -4);
+ }
+ lua_remove(L, -2);
+}
+
+static mpack_parser_t *lmpack_grow_parser(mpack_parser_t *parser)
+{
+ mpack_parser_t *old = parser;
+ mpack_uint32_t new_capacity = old->capacity * 2;
+ parser = malloc(MPACK_PARSER_STRUCT_SIZE(new_capacity));
+ if (!parser) goto end;
+ mpack_parser_init(parser, new_capacity);
+ mpack_parser_copy(parser, old);
+ free(old);
+end:
+ return parser;
+}
+
+static mpack_rpc_session_t *lmpack_grow_session(mpack_rpc_session_t *session)
+{
+ mpack_rpc_session_t *old = session;
+ mpack_uint32_t new_capacity = old->capacity * 2;
+ session = malloc(MPACK_RPC_SESSION_STRUCT_SIZE(new_capacity));
+ if (!session) goto end;
+ mpack_rpc_session_init(session, new_capacity);
+ mpack_rpc_session_copy(session, old);
+ free(old);
+end:
+ return session;
+}
+
+static Unpacker *lmpack_check_unpacker(lua_State *L, int index)
+{
+ return luaL_checkudata(L, index, UNPACKER_META_NAME);
+}
+
+static Packer *lmpack_check_packer(lua_State *L, int index)
+{
+ return luaL_checkudata(L, index, PACKER_META_NAME);
+}
+
+static Session *lmpack_check_session(lua_State *L, int index)
+{
+ return luaL_checkudata(L, index, SESSION_META_NAME);
+}
+
+static int lmpack_isnil(lua_State *L, int index)
+{
+ int rv;
+ if (!lua_isuserdata(L, index)) return 0;
+ lua_getfield(L, LUA_REGISTRYINDEX, NIL_NAME);
+ rv = lua_rawequal(L, -1, -2);
+ lua_pop(L, 1);
+ return rv;
+}
+
+static int lmpack_isunpacker(lua_State *L, int index)
+{
+ int rv;
+ if (!lua_isuserdata(L, index) || !lua_getmetatable(L, index)) return 0;
+ luaL_getmetatable(L, UNPACKER_META_NAME);
+ rv = lua_rawequal(L, -1, -2);
+ lua_pop(L, 2);
+ return rv;
+}
+
+static void lmpack_pushnil(lua_State *L)
+{
+ lua_getfield(L, LUA_REGISTRYINDEX, NIL_NAME);
+}
+
+/* adapted from
+ * https://github.com/antirez/lua-cmsgpack/blob/master/lua_cmsgpack.c */
+static mpack_uint32_t lmpack_objlen(lua_State *L, int *is_array)
+{
+ size_t len, max;
+ int isarr, type;
+ lua_Number n;
+#ifndef NDEBUG
+ int top = lua_gettop(L);
+ assert(top);
+#endif
+
+ if ((type = lua_type(L, -1)) != LUA_TTABLE) {
+#if LUA_VERSION_NUM >= 502
+ len = lua_rawlen(L, -1);
+#elif LUA_VERSION_NUM == 501
+ len = lua_objlen(L, -1);
+#else
+ #error You have either broken or too old Lua installation. This library requires Lua>=5.1
+#endif
+ goto end;
+ }
+
+ /* count the number of keys and determine if it is an array */
+ len = 0;
+ max = 0;
+ isarr = 1;
+ lua_pushnil(L);
+
+ while (lua_next(L, -2)) {
+ lua_pop(L, 1); /* pop value */
+ isarr = isarr
+ && lua_isnumber(L, -1) /* lua number */
+ && (n = lua_tonumber(L, -1)) > 0 /* greater than 0 */
+ && (size_t)n == n; /* and integer */
+ max = isarr && (size_t)n > max ? (size_t)n : max;
+ len++;
+ }
+
+ // when len==0, the caller should guess the type!
+ if (len > 0) {
+ *is_array = isarr && max == len;
+ }
+
+end:
+ if ((size_t)-1 > (mpack_uint32_t)-1 && len > (mpack_uint32_t)-1)
+ /* msgpack spec doesn't allow lengths > 32 bits */
+ len = (mpack_uint32_t)-1;
+ assert(top == lua_gettop(L));
+ return (mpack_uint32_t)len;
+}
+
+static int lmpack_unpacker_new(lua_State *L)
+{
+ Unpacker *rv;
+
+ if (lua_gettop(L) > 1)
+ return luaL_error(L, "expecting at most 1 table argument");
+
+ rv = lua_newuserdata(L, sizeof(*rv));
+ rv->parser = malloc(sizeof(*rv->parser));
+ if (!rv->parser) return luaL_error(L, "Failed to allocate memory");
+ mpack_parser_init(rv->parser, 0);
+ rv->parser->data.p = rv;
+ rv->string_buffer = NULL;
+ rv->L = L;
+ rv->unpacking = 0;
+ luaL_getmetatable(L, UNPACKER_META_NAME);
+ lua_setmetatable(L, -2);
+
+#ifndef MPACK_DEBUG_REGISTRY_LEAK
+ lua_newtable(L);
+ rv->reg = luaL_ref(L, LUA_REGISTRYINDEX);
+#endif
+ rv->ext = LUA_NOREF;
+
+ lua_getfield(L, LUA_REGISTRYINDEX, EMPTY_DICT_NAME);
+ rv->mtdict = lmpack_ref(L, rv->reg);
+
+ if (lua_istable(L, 1)) {
+ /* parse options */
+ lua_getfield(L, 1, "ext");
+ if (!lua_isnil(L, -1)) {
+ if (!lua_istable(L, -1))
+ return luaL_error(L, "\"ext\" option must be a table");
+ lmpack_shallow_copy(L);
+ }
+ rv->ext = lmpack_ref(L, rv->reg);
+ }
+
+ return 1;
+}
+
+static int lmpack_unpacker_delete(lua_State *L)
+{
+ Unpacker *unpacker = lmpack_check_unpacker(L, 1);
+ if (unpacker->ext != LUA_NOREF)
+ lmpack_unref(L, unpacker->reg, unpacker->ext);
+#ifndef MPACK_DEBUG_REGISTRY_LEAK
+ luaL_unref(L, LUA_REGISTRYINDEX, unpacker->reg);
+#endif
+ free(unpacker->parser);
+ return 0;
+}
+
+static void lmpack_parse_enter(mpack_parser_t *parser, mpack_node_t *node)
+{
+ Unpacker *unpacker = parser->data.p;
+ lua_State *L = unpacker->L;
+
+ switch (node->tok.type) {
+ case MPACK_TOKEN_NIL:
+ lmpack_pushnil(L); break;
+ case MPACK_TOKEN_BOOLEAN:
+ lua_pushboolean(L, (int)mpack_unpack_boolean(node->tok)); break;
+ case MPACK_TOKEN_UINT:
+ case MPACK_TOKEN_SINT:
+ case MPACK_TOKEN_FLOAT:
+ lua_pushnumber(L, mpack_unpack_number(node->tok)); break;
+ case MPACK_TOKEN_CHUNK:
+ assert(unpacker->string_buffer);
+ memcpy(unpacker->string_buffer + MPACK_PARENT_NODE(node)->pos,
+ node->tok.data.chunk_ptr, node->tok.length);
+ break;
+ case MPACK_TOKEN_BIN:
+ case MPACK_TOKEN_STR:
+ case MPACK_TOKEN_EXT:
+ unpacker->string_buffer = malloc(node->tok.length);
+ if (!unpacker->string_buffer) luaL_error(L, "Failed to allocate memory");
+ break;
+ case MPACK_TOKEN_ARRAY:
+ case MPACK_TOKEN_MAP:
+ lua_newtable(L);
+ node->data[0].i = lmpack_ref(L, unpacker->reg);
+ break;
+ }
+}
+
+static void lmpack_parse_exit(mpack_parser_t *parser, mpack_node_t *node)
+{
+ Unpacker *unpacker = parser->data.p;
+ lua_State *L = unpacker->L;
+ mpack_node_t *parent = MPACK_PARENT_NODE(node);
+
+ switch (node->tok.type) {
+ case MPACK_TOKEN_BIN:
+ case MPACK_TOKEN_STR:
+ case MPACK_TOKEN_EXT:
+ lua_pushlstring(L, unpacker->string_buffer, node->tok.length);
+ free(unpacker->string_buffer);
+ unpacker->string_buffer = NULL;
+ if (node->tok.type == MPACK_TOKEN_EXT && unpacker->ext != LUA_NOREF) {
+ /* check if there's a handler for this type */
+ lmpack_geti(L, unpacker->reg, unpacker->ext);
+ lua_rawgeti(L, -1, node->tok.data.ext_type);
+ if (lua_isfunction(L, -1)) {
+ /* stack:
+ *
+ * -1: ext unpacker function
+ * -2: ext unpackers table
+ * -3: ext string
+ *
+ * We want to call the ext unpacker function with the type and string
+ * as arguments, so push those now
+ */
+ lua_pushinteger(L, node->tok.data.ext_type);
+ lua_pushvalue(L, -4);
+ lua_call(L, 2, 1);
+ /* stack:
+ *
+ * -1: returned object
+ * -2: ext unpackers table
+ * -3: ext string
+ */
+ lua_replace(L, -3);
+ } else {
+ /* the last lua_rawgeti should have pushed nil on the stack,
+ * remove it */
+ lua_pop(L, 1);
+ }
+ /* pop the ext unpackers table */
+ lua_pop(L, 1);
+ }
+ break;
+ case MPACK_TOKEN_ARRAY:
+ case MPACK_TOKEN_MAP:
+ lmpack_geti(L, unpacker->reg, (int)node->data[0].i);
+ lmpack_unref(L, unpacker->reg, (int)node->data[0].i);
+ if (node->key_visited == 0 && node->tok.type == MPACK_TOKEN_MAP) {
+ lmpack_geti(L, unpacker->reg, unpacker->mtdict); // [table, mtdict]
+ lua_setmetatable(L, -2); // [table]
+ }
+
+ break;
+ default:
+ break;
+ }
+
+ if (parent && parent->tok.type < MPACK_TOKEN_BIN) {
+ /* At this point the parsed object is on the stack. Add it to the parent
+ * container. First put the container on the stack. */
+ lmpack_geti(L, unpacker->reg, (int)parent->data[0].i);
+
+ if (parent->tok.type == MPACK_TOKEN_ARRAY) {
+ /* Array, save the value on key equal to `parent->pos` */
+ lua_pushnumber(L, (lua_Number)parent->pos);
+ lua_pushvalue(L, -3);
+ lua_settable(L, -3);
+ } else {
+ assert(parent->tok.type == MPACK_TOKEN_MAP);
+ if (parent->key_visited) {
+ /* save the key on the registry */
+ lua_pushvalue(L, -2);
+ parent->data[1].i = lmpack_ref(L, unpacker->reg);
+ } else {
+ /* set the key/value pair */
+ lmpack_geti(L, unpacker->reg, (int)parent->data[1].i);
+ lmpack_unref(L, unpacker->reg, (int)parent->data[1].i);
+ lua_pushvalue(L, -3);
+ lua_settable(L, -3);
+ }
+ }
+ lua_pop(L, 2); /* pop the container/object */
+ }
+}
+
+static int lmpack_unpacker_unpack_str(lua_State *L, Unpacker *unpacker,
+ const char **str, size_t *len)
+{
+ int rv;
+
+ if (unpacker->unpacking) {
+ return luaL_error(L, "Unpacker instance already working. Use another "
+ "Unpacker or the module's \"unpack\" function if you "
+ "need to unpack from the ext handler");
+ }
+
+ do {
+ unpacker->unpacking = 1;
+ rv = mpack_parse(unpacker->parser, str, len, lmpack_parse_enter,
+ lmpack_parse_exit);
+ unpacker->unpacking = 0;
+
+ if (rv == MPACK_NOMEM) {
+ unpacker->parser = lmpack_grow_parser(unpacker->parser);
+ if (!unpacker->parser) {
+ unpacker->unpacking = 0;
+ return luaL_error(L, "failed to grow Unpacker capacity");
+ }
+ }
+ } while (rv == MPACK_NOMEM);
+
+ if (rv == MPACK_ERROR)
+ return luaL_error(L, "invalid msgpack string");
+
+ return rv;
+}
+
+static int lmpack_unpacker_unpack(lua_State *L)
+{
+ int result, argc;
+ lua_Number startpos;
+ size_t len, offset;
+ const char *str, *str_init;
+ Unpacker *unpacker;
+
+ if ((argc = lua_gettop(L)) > 3 || argc < 2)
+ return luaL_error(L, "expecting between 2 and 3 arguments");
+
+ unpacker = lmpack_check_unpacker(L, 1);
+ unpacker->L = L;
+
+ str_init = str = luaL_checklstring(L, 2, &len);
+ startpos = lua_gettop(L) == 3 ? luaL_checknumber(L, 3) : 1;
+
+ luaL_argcheck(L, startpos > 0, 3,
+ "start position must be greater than zero");
+ luaL_argcheck(L, (size_t)startpos == startpos, 3,
+ "start position must be an integer");
+ luaL_argcheck(L, (size_t)startpos <= len, 3,
+ "start position must be less than or equal to the input string length");
+
+ offset = (size_t)startpos - 1 ;
+ str += offset;
+ len -= offset;
+ result = lmpack_unpacker_unpack_str(L, unpacker, &str, &len);
+
+ if (result == MPACK_EOF)
+ /* if we hit EOF, return nil as the object */
+ lua_pushnil(L);
+
+ /* also return the new position in the input string */
+ lua_pushinteger(L, str - str_init + 1);
+ assert(lua_gettop(L) == argc + 2);
+ return 2;
+}
+
+static int lmpack_packer_new(lua_State *L)
+{
+ Packer *rv;
+
+ if (lua_gettop(L) > 1)
+ return luaL_error(L, "expecting at most 1 table argument");
+
+ rv = lua_newuserdata(L, sizeof(*rv));
+ rv->parser = malloc(sizeof(*rv->parser));
+ if (!rv->parser) return luaL_error(L, "failed to allocate parser memory");
+ mpack_parser_init(rv->parser, 0);
+ rv->parser->data.p = rv;
+ rv->L = L;
+ rv->packing = 0;
+ rv->is_bin = 0;
+ rv->is_bin_fn = LUA_NOREF;
+ luaL_getmetatable(L, PACKER_META_NAME);
+ lua_setmetatable(L, -2);
+
+#ifndef MPACK_DEBUG_REGISTRY_LEAK
+ lua_newtable(L);
+ rv->reg = luaL_ref(L, LUA_REGISTRYINDEX);
+#endif
+ rv->ext = LUA_NOREF;
+
+ lua_getfield(L, LUA_REGISTRYINDEX, EMPTY_DICT_NAME);
+ rv->mtdict = lmpack_ref(L, rv->reg);
+
+ if (lua_istable(L, 1)) {
+ /* parse options */
+ lua_getfield(L, 1, "ext");
+ if (!lua_isnil(L, -1)) {
+ if (!lua_istable(L, -1))
+ return luaL_error(L, "\"ext\" option must be a table");
+ lmpack_shallow_copy(L);
+ }
+ rv->ext = lmpack_ref(L, rv->reg);
+ lua_getfield(L, 1, "is_bin");
+ if (!lua_isnil(L, -1)) {
+ if (!lua_isboolean(L, -1) && !lua_isfunction(L, -1))
+ return luaL_error(L,
+ "\"is_bin\" option must be a boolean or function");
+ rv->is_bin = lua_toboolean(L, -1);
+ if (lua_isfunction(L, -1)) rv->is_bin_fn = lmpack_ref(L, rv->reg);
+ else lua_pop(L, 1);
+ } else {
+ lua_pop(L, 1);
+ }
+
+ }
+
+ return 1;
+}
+
+static int lmpack_packer_delete(lua_State *L)
+{
+ Packer *packer = lmpack_check_packer(L, 1);
+ if (packer->ext != LUA_NOREF)
+ lmpack_unref(L, packer->reg, packer->ext);
+#ifndef MPACK_DEBUG_REGISTRY_LEAK
+ luaL_unref(L, LUA_REGISTRYINDEX, packer->reg);
+#endif
+ free(packer->parser);
+ return 0;
+}
+
+static void lmpack_unparse_enter(mpack_parser_t *parser, mpack_node_t *node)
+{
+ int type;
+ Packer *packer = parser->data.p;
+ lua_State *L = packer->L;
+ mpack_node_t *parent = MPACK_PARENT_NODE(node);
+
+ if (parent) {
+ /* get the parent */
+ lmpack_geti(L, packer->reg, (int)parent->data[0].i);
+
+ if (parent->tok.type > MPACK_TOKEN_MAP) {
+ /* strings are a special case, they are packed as single child chunk
+ * node */
+ const char *str = lua_tolstring(L, -1, NULL);
+ node->tok = mpack_pack_chunk(str, parent->tok.length);
+ lua_pop(L, 1);
+ return;
+ }
+
+ if (parent->tok.type == MPACK_TOKEN_ARRAY) {
+ /* push the next index */
+ lua_pushnumber(L, (lua_Number)(parent->pos + 1));
+ /* push the element */
+ lua_gettable(L, -2);
+ } else if (parent->tok.type == MPACK_TOKEN_MAP) {
+ int result;
+ /* push the previous key */
+ lmpack_geti(L, packer->reg, (int)parent->data[1].i);
+ /* push the pair */
+ result = lua_next(L, -2);
+ assert(result); /* should not be here if the map was fully processed */
+ if (parent->key_visited) {
+ /* release the current key */
+ lmpack_unref(L, packer->reg, (int)parent->data[1].i);
+ /* push key to the top */
+ lua_pushvalue(L, -2);
+ /* set the key for the next iteration, leaving value on top */
+ parent->data[1].i = lmpack_ref(L, packer->reg);
+ /* replace key by the value */
+ lua_replace(L, -2);
+ } else {
+ /* pop value */
+ lua_pop(L, 1);
+ }
+ }
+ /* remove parent, leaving only the object which will be serialized */
+ lua_remove(L, -2);
+ } else {
+ /* root object */
+ lmpack_geti(L, packer->reg, packer->root);
+ }
+
+ type = lua_type(L, -1);
+
+ switch (type) {
+ case LUA_TBOOLEAN:
+ node->tok = mpack_pack_boolean((unsigned)lua_toboolean(L, -1));
+ break;
+ case LUA_TNUMBER:
+ node->tok = mpack_pack_number(lua_tonumber(L, -1));
+ break;
+ case LUA_TSTRING: {
+ int is_bin = packer->is_bin;
+ if (is_bin && packer->is_bin_fn != LUA_NOREF) {
+ lmpack_geti(L, packer->reg, packer->is_bin_fn);
+ lua_pushvalue(L, -2);
+ lua_call(L, 1, 1);
+ is_bin = lua_toboolean(L, -1);
+ lua_pop(L, 1);
+ }
+ if (is_bin) node->tok = mpack_pack_bin(lmpack_objlen(L, NULL));
+ else node->tok = mpack_pack_str(lmpack_objlen(L, NULL));
+ break;
+ }
+ case LUA_TTABLE: {
+ mpack_uint32_t len;
+ mpack_node_t *n;
+
+ int has_meta = lua_getmetatable(L, -1);
+ if (packer->ext != LUA_NOREF && has_meta) {
+ /* check if there's a handler for this metatable */
+ lmpack_geti(L, packer->reg, packer->ext);
+ lua_pushvalue(L, -2);
+ lua_gettable(L, -2);
+ if (lua_isfunction(L, -1)) {
+ lua_Number ext = -1;
+ /* stack:
+ *
+ * -1: ext packer function
+ * -2: ext packers table
+ * -3: metatable
+ * -4: original object
+ *
+ * We want to call the ext packer function with the original object as
+ * argument, so push it on the top
+ */
+ lua_pushvalue(L, -4);
+ /* handler should return type code and string */
+ lua_call(L, 1, 2);
+ if (!lua_isnumber(L, -2) || (ext = lua_tonumber(L, -2)) < 0
+ || ext > 127 || (int)ext != ext)
+ luaL_error(L,
+ "the first result from ext packer must be an integer "
+ "between 0 and 127");
+ if (!lua_isstring(L, -1))
+ luaL_error(L,
+ "the second result from ext packer must be a string");
+ node->tok = mpack_pack_ext((int)ext, lmpack_objlen(L, NULL));
+ /* stack:
+ *
+ * -1: ext string
+ * -2: ext type
+ * -3: ext packers table
+ * -4: metatable
+ * -5: original table
+ *
+ * We want to leave only the returned ext string, so
+ * replace -5 with the string and pop 3
+ */
+ lua_replace(L, -5);
+ lua_pop(L, 3);
+ break; /* done */
+ } else {
+ /* stack:
+ *
+ * -1: ext packers table
+ * -2: metatable
+ * -3: original table
+ *
+ * We want to leave only the original table and metatable since they
+ * will be handled below, so pop 1
+ */
+ lua_pop(L, 1);
+ }
+ }
+
+ int is_array = 1;
+ if (has_meta) {
+ // stack: [table, metatable]
+ if (packer->mtdict != LUA_NOREF) {
+ lmpack_geti(L, packer->reg, packer->mtdict); // [table, metatable, mtdict]
+ is_array = !lua_rawequal(L, -1, -2);
+ lua_pop(L, 1); // [table, metatable];
+ }
+ lua_pop(L, 1); // [table]
+ }
+
+ /* check for cycles */
+ n = node;
+ while ((n = MPACK_PARENT_NODE(n))) {
+ lmpack_geti(L, packer->reg, (int)n->data[0].i);
+ if (lua_rawequal(L, -1, -2)) {
+ /* break out of cycles with NIL */
+ node->tok = mpack_pack_nil();
+ lua_pop(L, 2);
+ lmpack_pushnil(L);
+ goto end;
+ }
+ lua_pop(L, 1);
+ }
+
+ len = lmpack_objlen(L, &is_array);
+ if (is_array) {
+ node->tok = mpack_pack_array(len);
+ } else {
+ node->tok = mpack_pack_map(len);
+ /* save nil as the previous key to start iteration */
+ node->data[1].i = LUA_REFNIL;
+ }
+ break;
+ }
+ case LUA_TUSERDATA:
+ if (lmpack_isnil(L, -1)) {
+ node->tok = mpack_pack_nil();
+ break;
+ }
+ FALLTHROUGH;
+ default:
+ {
+ /* #define FMT */
+ char errmsg[50];
+ snprintf(errmsg, 50, "can't serialize object of type %d", type);
+ luaL_error(L, errmsg);
+ }
+ }
+
+end:
+ node->data[0].i = lmpack_ref(L, packer->reg);
+}
+
+static void lmpack_unparse_exit(mpack_parser_t *parser, mpack_node_t *node)
+{
+ Packer *packer = parser->data.p;
+ lua_State *L = packer->L;
+ if (node->tok.type != MPACK_TOKEN_CHUNK) {
+ /* release the object */
+ lmpack_unref(L, packer->reg, (int)node->data[0].i);
+ if (node->tok.type == MPACK_TOKEN_MAP)
+ lmpack_unref(L, packer->reg, (int)node->data[1].i);
+ }
+}
+
+static int lmpack_packer_pack(lua_State *L)
+{
+ char *b;
+ size_t bl;
+ int result, argc;
+ Packer *packer;
+ luaL_Buffer buffer;
+
+ if ((argc = lua_gettop(L)) != 2)
+ return luaL_error(L, "expecting exactly 2 arguments");
+
+ packer = lmpack_check_packer(L, 1);
+ packer->L = L;
+ packer->root = lmpack_ref(L, packer->reg);
+ luaL_buffinit(L, &buffer);
+ b = luaL_prepbuffer(&buffer);
+ bl = LUAL_BUFFERSIZE;
+
+ if (packer->packing) {
+ return luaL_error(L, "Packer instance already working. Use another Packer "
+ "or the module's \"pack\" function if you need to "
+ "pack from the ext handler");
+ }
+
+ do {
+ size_t bl_init = bl;
+ packer->packing = 1;
+ result = mpack_unparse(packer->parser, &b, &bl, lmpack_unparse_enter,
+ lmpack_unparse_exit);
+ packer->packing = 0;
+
+ if (result == MPACK_NOMEM) {
+ packer->parser = lmpack_grow_parser(packer->parser);
+ if (!packer->parser) {
+ packer->packing = 0;
+ return luaL_error(L, "Failed to grow Packer capacity");
+ }
+ }
+
+ luaL_addsize(&buffer, bl_init - bl);
+
+ if (!bl) {
+ /* buffer empty, resize */
+ b = luaL_prepbuffer(&buffer);
+ bl = LUAL_BUFFERSIZE;
+ }
+ } while (result == MPACK_EOF || result == MPACK_NOMEM);
+
+ lmpack_unref(L, packer->reg, packer->root);
+ luaL_pushresult(&buffer);
+ assert(lua_gettop(L) == argc);
+ return 1;
+}
+
+static int lmpack_session_new(lua_State *L)
+{
+ Session *rv = lua_newuserdata(L, sizeof(*rv));
+ rv->session = malloc(sizeof(*rv->session));
+ if (!rv->session) return luaL_error(L, "Failed to allocate memory");
+ mpack_rpc_session_init(rv->session, 0);
+ rv->L = L;
+ luaL_getmetatable(L, SESSION_META_NAME);
+ lua_setmetatable(L, -2);
+#ifndef MPACK_DEBUG_REGISTRY_LEAK
+ lua_newtable(L);
+ rv->reg = luaL_ref(L, LUA_REGISTRYINDEX);
+#endif
+ rv->unpacker = LUA_REFNIL;
+ rv->unpacked.args_or_result = LUA_NOREF;
+ rv->unpacked.method_or_error = LUA_NOREF;
+ rv->unpacked.type = MPACK_EOF;
+
+ if (lua_istable(L, 1)) {
+ /* parse options */
+ lua_getfield(L, 1, "unpack");
+ if (!lmpack_isunpacker(L, -1)) {
+ return luaL_error(L,
+ "\"unpack\" option must be a " UNPACKER_META_NAME " instance");
+ }
+ rv->unpacker = lmpack_ref(L, rv->reg);
+ }
+
+ return 1;
+}
+
+static int lmpack_session_delete(lua_State *L)
+{
+ Session *session = lmpack_check_session(L, 1);
+ lmpack_unref(L, session->reg, session->unpacker);
+#ifndef MPACK_DEBUG_REGISTRY_LEAK
+ luaL_unref(L, LUA_REGISTRYINDEX, session->reg);
+#endif
+ free(session->session);
+ return 0;
+}
+
+static int lmpack_session_receive(lua_State *L)
+{
+ int argc, done, rcount = 3;
+ lua_Number startpos;
+ size_t len;
+ const char *str, *str_init;
+ Session *session;
+ Unpacker *unpacker = NULL;
+
+ if ((argc = lua_gettop(L)) > 3 || argc < 2)
+ return luaL_error(L, "expecting between 2 and 3 arguments");
+
+ session = lmpack_check_session(L, 1);
+ str_init = str = luaL_checklstring(L, 2, &len);
+ startpos = lua_gettop(L) == 3 ? luaL_checknumber(L, 3) : 1;
+
+ luaL_argcheck(L, startpos > 0, 3,
+ "start position must be greater than zero");
+ luaL_argcheck(L, (size_t)startpos == startpos, 3,
+ "start position must be an integer");
+ luaL_argcheck(L, (size_t)startpos <= len, 3,
+ "start position must be less than or equal to the input string length");
+
+ str += (size_t)startpos - 1;
+
+ if (session->unpacker != LUA_REFNIL) {
+ lmpack_geti(L, session->reg, session->unpacker);
+ unpacker = lmpack_check_unpacker(L, -1);
+ unpacker->L = L;
+ rcount += 2;
+ lua_pop(L, 1);
+ }
+
+ for (;;) {
+ int result;
+
+ if (session->unpacked.type == MPACK_EOF) {
+ session->unpacked.type =
+ mpack_rpc_receive(session->session, &str, &len, &session->unpacked.msg);
+
+ if (!unpacker || session->unpacked.type == MPACK_EOF)
+ break;
+ }
+
+ result = lmpack_unpacker_unpack_str(L, unpacker, &str, &len);
+
+ if (result == MPACK_EOF) break;
+
+ if (session->unpacked.method_or_error == LUA_NOREF) {
+ session->unpacked.method_or_error = lmpack_ref(L, session->reg);
+ } else {
+ session->unpacked.args_or_result = lmpack_ref(L, session->reg);
+ break;
+ }
+ }
+
+ done = session->unpacked.type != MPACK_EOF
+ && (session->unpacked.args_or_result != LUA_NOREF || !unpacker);
+
+ if (!done) {
+ lua_pushnil(L);
+ lua_pushnil(L);
+ if (unpacker) {
+ lua_pushnil(L);
+ lua_pushnil(L);
+ }
+ goto end;
+ }
+
+ switch (session->unpacked.type) {
+ case MPACK_RPC_REQUEST:
+ lua_pushstring(L, "request");
+ lua_pushnumber(L, session->unpacked.msg.id);
+ break;
+ case MPACK_RPC_RESPONSE:
+ lua_pushstring(L, "response");
+ lmpack_geti(L, session->reg, (int)session->unpacked.msg.data.i);
+ break;
+ case MPACK_RPC_NOTIFICATION:
+ lua_pushstring(L, "notification");
+ lua_pushnil(L);
+ break;
+ default:
+ /* In most cases the only sane thing to do when receiving invalid
+ * msgpack-rpc is to close the connection, so handle all errors with
+ * this generic message. Later may add more detailed information. */
+ return luaL_error(L, "invalid msgpack-rpc string");
+ }
+
+ session->unpacked.type = MPACK_EOF;
+
+ if (unpacker) {
+ lmpack_geti(L, session->reg, session->unpacked.method_or_error);
+ lmpack_geti(L, session->reg, session->unpacked.args_or_result);
+ lmpack_unref(L, session->reg, session->unpacked.method_or_error);
+ lmpack_unref(L, session->reg, session->unpacked.args_or_result);
+ session->unpacked.method_or_error = LUA_NOREF;
+ session->unpacked.args_or_result = LUA_NOREF;
+ }
+
+end:
+ lua_pushinteger(L, str - str_init + 1);
+ return rcount;
+}
+
+static int lmpack_session_request(lua_State *L)
+{
+ int result;
+ char buf[16], *b = buf;
+ size_t bl = sizeof(buf);
+ Session *session;
+ mpack_data_t data;
+
+ if (lua_gettop(L) > 2 || lua_gettop(L) < 1)
+ return luaL_error(L, "expecting 1 or 2 arguments");
+
+ session = lmpack_check_session(L, 1);
+ data.i = lua_isnoneornil(L, 2) ? LUA_NOREF : lmpack_ref(L, session->reg);
+ do {
+ result = mpack_rpc_request(session->session, &b, &bl, data);
+ if (result == MPACK_NOMEM) {
+ session->session = lmpack_grow_session(session->session);
+ if (!session->session)
+ return luaL_error(L, "Failed to grow Session capacity");
+ }
+ } while (result == MPACK_NOMEM);
+
+ assert(result == MPACK_OK);
+ lua_pushlstring(L, buf, sizeof(buf) - bl);
+ return 1;
+}
+
+static int lmpack_session_reply(lua_State *L)
+{
+ int result;
+ char buf[16], *b = buf;
+ size_t bl = sizeof(buf);
+ Session *session;
+ lua_Number id;
+
+ if (lua_gettop(L) != 2)
+ return luaL_error(L, "expecting exactly 2 arguments");
+
+ session = lmpack_check_session(L, 1);
+ id = lua_tonumber(L, 2);
+ luaL_argcheck(L, ((size_t)id == id && id >= 0 && id <= 0xffffffff), 2,
+ "invalid request id");
+ result = mpack_rpc_reply(session->session, &b, &bl, (mpack_uint32_t)id);
+ assert(result == MPACK_OK);
+ lua_pushlstring(L, buf, sizeof(buf) - bl);
+ return 1;
+}
+
+static int lmpack_session_notify(lua_State *L)
+{
+ int result;
+ char buf[16], *b = buf;
+ size_t bl = sizeof(buf);
+ Session *session;
+
+ if (lua_gettop(L) != 1)
+ return luaL_error(L, "expecting exactly 1 argument");
+
+ session = lmpack_check_session(L, 1);
+ result = mpack_rpc_notify(session->session, &b, &bl);
+ assert(result == MPACK_OK);
+ lua_pushlstring(L, buf, sizeof(buf) - bl);
+ return 1;
+}
+
+static int lmpack_nil_tostring(lua_State* L)
+{
+ lua_pushfstring(L, NIL_NAME, lua_topointer(L, 1));
+ return 1;
+}
+
+static int lmpack_unpack(lua_State *L)
+{
+ int result;
+ size_t len;
+ const char *str;
+ Unpacker unpacker;
+ mpack_parser_t parser;
+
+ if (lua_gettop(L) != 1)
+ return luaL_error(L, "expecting exactly 1 argument");
+
+ str = luaL_checklstring(L, 1, &len);
+
+ /* initialize unpacker */
+ lua_newtable(L);
+ unpacker.reg = luaL_ref(L, LUA_REGISTRYINDEX);
+ unpacker.ext = LUA_NOREF;
+ unpacker.parser = &parser;
+ mpack_parser_init(unpacker.parser, 0);
+ unpacker.parser->data.p = &unpacker;
+ unpacker.string_buffer = NULL;
+ unpacker.L = L;
+
+ lua_getfield(L, LUA_REGISTRYINDEX, EMPTY_DICT_NAME);
+ unpacker.mtdict = lmpack_ref(L, unpacker.reg);
+
+ result = mpack_parse(&parser, &str, &len, lmpack_parse_enter,
+ lmpack_parse_exit);
+
+ luaL_unref(L, LUA_REGISTRYINDEX, unpacker.reg);
+
+ if (result == MPACK_NOMEM)
+ return luaL_error(L, "object was too deep to unpack");
+ else if (result == MPACK_EOF)
+ return luaL_error(L, "incomplete msgpack string");
+ else if (result == MPACK_ERROR)
+ return luaL_error(L, "invalid msgpack string");
+ else if (result == MPACK_OK && len)
+ return luaL_error(L, "trailing data in msgpack string");
+
+ assert(result == MPACK_OK);
+ return 1;
+}
+
+static int lmpack_pack(lua_State *L)
+{
+ char *b;
+ size_t bl;
+ int result;
+ Packer packer;
+ mpack_parser_t parser;
+ luaL_Buffer buffer;
+
+ if (lua_gettop(L) != 1)
+ return luaL_error(L, "expecting exactly 1 argument");
+
+ /* initialize packer */
+ lua_newtable(L);
+ packer.reg = luaL_ref(L, LUA_REGISTRYINDEX);
+ packer.ext = LUA_NOREF;
+ packer.parser = &parser;
+ mpack_parser_init(packer.parser, 0);
+ packer.parser->data.p = &packer;
+ packer.is_bin = 0;
+ packer.L = L;
+ packer.root = lmpack_ref(L, packer.reg);
+
+ lua_getfield(L, LUA_REGISTRYINDEX, EMPTY_DICT_NAME);
+ packer.mtdict = lmpack_ref(L, packer.reg);
+
+
+ luaL_buffinit(L, &buffer);
+ b = luaL_prepbuffer(&buffer);
+ bl = LUAL_BUFFERSIZE;
+
+ do {
+ size_t bl_init = bl;
+ result = mpack_unparse(packer.parser, &b, &bl, lmpack_unparse_enter,
+ lmpack_unparse_exit);
+
+ if (result == MPACK_NOMEM) {
+ lmpack_unref(L, packer.reg, packer.root);
+ luaL_unref(L, LUA_REGISTRYINDEX, packer.reg);
+ return luaL_error(L, "object was too deep to pack");
+ }
+
+ luaL_addsize(&buffer, bl_init - bl);
+
+ if (!bl) {
+ /* buffer empty, resize */
+ b = luaL_prepbuffer(&buffer);
+ bl = LUAL_BUFFERSIZE;
+ }
+ } while (result == MPACK_EOF);
+
+ lmpack_unref(L, packer.reg, packer.root);
+ luaL_unref(L, LUA_REGISTRYINDEX, packer.reg);
+ luaL_pushresult(&buffer);
+ return 1;
+}
+
+static const luaL_reg unpacker_methods[] = {
+ {"__call", lmpack_unpacker_unpack},
+ {"__gc", lmpack_unpacker_delete},
+ {NULL, NULL}
+};
+
+static const luaL_reg packer_methods[] = {
+ {"__call", lmpack_packer_pack},
+ {"__gc", lmpack_packer_delete},
+ {NULL, NULL}
+};
+
+static const luaL_reg session_methods[] = {
+ {"receive", lmpack_session_receive},
+ {"request", lmpack_session_request},
+ {"reply", lmpack_session_reply},
+ {"notify", lmpack_session_notify},
+ {"__gc", lmpack_session_delete},
+ {NULL, NULL}
+};
+
+static const luaL_reg mpack_functions[] = {
+ {"Unpacker", lmpack_unpacker_new},
+ {"Packer", lmpack_packer_new},
+ {"Session", lmpack_session_new},
+ {"unpack", lmpack_unpack},
+ {"pack", lmpack_pack},
+ {NULL, NULL}
+};
+
+int luaopen_mpack(lua_State *L)
+{
+ /* Unpacker */
+ luaL_newmetatable(L, UNPACKER_META_NAME);
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "__index");
+ luaL_register(L, NULL, unpacker_methods);
+ lua_pop(L, 1);
+ /* Packer */
+ luaL_newmetatable(L, PACKER_META_NAME);
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "__index");
+ luaL_register(L, NULL, packer_methods);
+ lua_pop(L, 1);
+ /* Session */
+ luaL_newmetatable(L, SESSION_META_NAME);
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "__index");
+ luaL_register(L, NULL, session_methods);
+ lua_pop(L, 1);
+ /* NIL */
+ /* Check if NIL is already stored in the registry */
+ lua_getfield(L, LUA_REGISTRYINDEX, NIL_NAME);
+ /* If it isn't, create it */
+ if (lua_isnil(L, -1)) {
+ /* Use a constant userdata to represent NIL */
+ (void)lua_newuserdata(L, sizeof(void *));
+ /* Create a metatable for NIL userdata */
+ lua_createtable(L, 0, 1);
+ lua_pushstring(L, "__tostring");
+ lua_pushcfunction(L, lmpack_nil_tostring);
+ lua_settable(L, -3);
+ /* Assign the metatable to the userdata object */
+ lua_setmetatable(L, -2);
+ /* Save NIL on the registry so we can access it easily from other functions */
+ lua_setfield(L, LUA_REGISTRYINDEX, NIL_NAME);
+ }
+
+ lua_pop(L, 1);
+
+ /* module */
+ lua_newtable(L);
+ luaL_register(L, NULL, mpack_functions);
+ /* save NIL on the module */
+ lua_getfield(L, LUA_REGISTRYINDEX, NIL_NAME);
+ lua_setfield(L, -2, "NIL");
+ return 1;
+}
diff --git a/src/mpack/lmpack.h b/src/mpack/lmpack.h
new file mode 100644
index 0000000000..e35f40fab6
--- /dev/null
+++ b/src/mpack/lmpack.h
@@ -0,0 +1,3 @@
+#include <lua.h>
+
+int luaopen_mpack(lua_State *L);
diff --git a/src/mpack/mpack_core.c b/src/mpack/mpack_core.c
new file mode 100644
index 0000000000..f8ca63b7a3
--- /dev/null
+++ b/src/mpack/mpack_core.c
@@ -0,0 +1,578 @@
+// 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 <string.h>
+
+#include "mpack_core.h"
+
+#define UNUSED(p) (void)p;
+#define ADVANCE(buf, buflen) ((*buflen)--, (unsigned char)*((*buf)++))
+#define TLEN(val, range_start) ((mpack_uint32_t)(1 << (val - range_start)))
+#ifndef MIN
+# define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
+#endif
+
+static int mpack_rtoken(const char **buf, size_t *buflen,
+ mpack_token_t *tok);
+static int mpack_rpending(const char **b, size_t *nl, mpack_tokbuf_t *tb);
+static int mpack_rvalue(mpack_token_type_t t, mpack_uint32_t l,
+ const char **b, size_t *bl, mpack_token_t *tok);
+static int mpack_rblob(mpack_token_type_t t, mpack_uint32_t l,
+ const char **b, size_t *bl, mpack_token_t *tok);
+static int mpack_wtoken(const mpack_token_t *tok, char **b, size_t *bl);
+static int mpack_wpending(char **b, size_t *bl, mpack_tokbuf_t *tb);
+static int mpack_wpint(char **b, size_t *bl, mpack_value_t v);
+static int mpack_wnint(char **b, size_t *bl, mpack_value_t v);
+static int mpack_wfloat(char **b, size_t *bl, const mpack_token_t *v);
+static int mpack_wstr(char **buf, size_t *buflen, mpack_uint32_t len);
+static int mpack_wbin(char **buf, size_t *buflen, mpack_uint32_t len);
+static int mpack_wext(char **buf, size_t *buflen, int type,
+ mpack_uint32_t len);
+static int mpack_warray(char **buf, size_t *buflen, mpack_uint32_t len);
+static int mpack_wmap(char **buf, size_t *buflen, mpack_uint32_t len);
+static int mpack_w1(char **b, size_t *bl, mpack_uint32_t v);
+static int mpack_w2(char **b, size_t *bl, mpack_uint32_t v);
+static int mpack_w4(char **b, size_t *bl, mpack_uint32_t v);
+static mpack_value_t mpack_byte(unsigned char b);
+static int mpack_value(mpack_token_type_t t, mpack_uint32_t l,
+ mpack_value_t v, mpack_token_t *tok);
+static int mpack_blob(mpack_token_type_t t, mpack_uint32_t l, int et,
+ mpack_token_t *tok);
+
+MPACK_API void mpack_tokbuf_init(mpack_tokbuf_t *tokbuf)
+{
+ tokbuf->ppos = 0;
+ tokbuf->plen = 0;
+ tokbuf->passthrough = 0;
+}
+
+MPACK_API int mpack_read(mpack_tokbuf_t *tokbuf, const char **buf,
+ size_t *buflen, mpack_token_t *tok)
+{
+ int status;
+ size_t initial_ppos, ptrlen, advanced;
+ const char *ptr, *ptr_save;
+ assert(*buf && *buflen);
+
+ if (tokbuf->passthrough) {
+ /* pass data from str/bin/ext directly as a MPACK_TOKEN_CHUNK, adjusting
+ * *buf and *buflen */
+ tok->type = MPACK_TOKEN_CHUNK;
+ tok->data.chunk_ptr = *buf;
+ tok->length = MIN((mpack_uint32_t)*buflen, tokbuf->passthrough);
+ tokbuf->passthrough -= tok->length;
+ *buf += tok->length;
+ *buflen -= tok->length;
+ goto done;
+ }
+
+ initial_ppos = tokbuf->ppos;
+
+ if (tokbuf->plen) {
+ if (!mpack_rpending(buf, buflen, tokbuf)) {
+ return MPACK_EOF;
+ }
+ ptr = tokbuf->pending;
+ ptrlen = tokbuf->ppos;
+ } else {
+ ptr = *buf;
+ ptrlen = *buflen;
+ }
+
+ ptr_save = ptr;
+
+ if ((status = mpack_rtoken(&ptr, &ptrlen, tok))) {
+ if (status != MPACK_EOF) return MPACK_ERROR;
+ /* need more data */
+ assert(!tokbuf->plen);
+ /* read the remainder of *buf to tokbuf->pending so it can be parsed
+ * later with more data. only required when tokbuf->plen == 0 or else
+ * it would have been done already. */
+ tokbuf->plen = tok->length + 1;
+ assert(tokbuf->plen <= sizeof(tokbuf->pending));
+ tokbuf->ppos = 0;
+ status = mpack_rpending(buf, buflen, tokbuf);
+ assert(!status);
+ return MPACK_EOF;
+ }
+
+ advanced = (size_t)(ptr - ptr_save) - initial_ppos;
+ tokbuf->plen = tokbuf->ppos = 0;
+ *buflen -= advanced;
+ *buf += advanced;
+
+ if (tok->type > MPACK_TOKEN_MAP) {
+ tokbuf->passthrough = tok->length;
+ }
+
+done:
+ return MPACK_OK;
+}
+
+MPACK_API int mpack_write(mpack_tokbuf_t *tokbuf, char **buf, size_t *buflen,
+ const mpack_token_t *t)
+{
+ int status;
+ char *ptr;
+ size_t ptrlen;
+ mpack_token_t tok = tokbuf->plen ? tokbuf->pending_tok : *t;
+ assert(*buf && *buflen);
+
+ if (tok.type == MPACK_TOKEN_CHUNK) {
+ size_t written, pending, count;
+ if (!tokbuf->plen) tokbuf->ppos = 0;
+ written = tokbuf->ppos;
+ pending = tok.length - written;
+ count = MIN(pending, *buflen);
+ memcpy(*buf, tok.data.chunk_ptr + written, count);
+ *buf += count;
+ *buflen -= count;
+ tokbuf->ppos += count;
+ tokbuf->plen = count == pending ? 0 : tok.length;
+ if (count == pending) {
+ return MPACK_OK;
+ } else {
+ tokbuf->pending_tok = tok;
+ return MPACK_EOF;
+ }
+ }
+
+ if (tokbuf->plen) return mpack_wpending(buf, buflen, tokbuf);
+
+ if (*buflen < MPACK_MAX_TOKEN_LEN) {
+ ptr = tokbuf->pending;
+ ptrlen = sizeof(tokbuf->pending);
+ } else {
+ ptr = *buf;
+ ptrlen = *buflen;
+ }
+
+ if ((status = mpack_wtoken(&tok, &ptr, &ptrlen))) return status;
+
+ if (*buflen < MPACK_MAX_TOKEN_LEN) {
+ size_t toklen = sizeof(tokbuf->pending) - ptrlen;
+ size_t write_cnt = MIN(toklen, *buflen);
+ memcpy(*buf, tokbuf->pending, write_cnt);
+ *buf += write_cnt;
+ *buflen -= write_cnt;
+ if (write_cnt < toklen) {
+ assert(!*buflen);
+ tokbuf->plen = toklen;
+ tokbuf->ppos = write_cnt;
+ tokbuf->pending_tok = tok;
+ return MPACK_EOF;
+ }
+ } else {
+ *buflen -= (size_t)(ptr - *buf);
+ *buf = ptr;
+ }
+
+ return MPACK_OK;
+}
+
+static int mpack_rtoken(const char **buf, size_t *buflen,
+ mpack_token_t *tok)
+{
+ unsigned char t = ADVANCE(buf, buflen);
+ if (t < 0x80) {
+ /* positive fixint */
+ return mpack_value(MPACK_TOKEN_UINT, 1, mpack_byte(t), tok);
+ } else if (t < 0x90) {
+ /* fixmap */
+ return mpack_blob(MPACK_TOKEN_MAP, t & 0xf, 0, tok);
+ } else if (t < 0xa0) {
+ /* fixarray */
+ return mpack_blob(MPACK_TOKEN_ARRAY, t & 0xf, 0, tok);
+ } else if (t < 0xc0) {
+ /* fixstr */
+ return mpack_blob(MPACK_TOKEN_STR, t & 0x1f, 0, tok);
+ } else if (t < 0xe0) {
+ switch (t) {
+ case 0xc0: /* nil */
+ return mpack_value(MPACK_TOKEN_NIL, 0, mpack_byte(0), tok);
+ case 0xc2: /* false */
+ return mpack_value(MPACK_TOKEN_BOOLEAN, 1, mpack_byte(0), tok);
+ case 0xc3: /* true */
+ return mpack_value(MPACK_TOKEN_BOOLEAN, 1, mpack_byte(1), tok);
+ case 0xc4: /* bin 8 */
+ case 0xc5: /* bin 16 */
+ case 0xc6: /* bin 32 */
+ return mpack_rblob(MPACK_TOKEN_BIN, TLEN(t, 0xc4), buf, buflen, tok);
+ case 0xc7: /* ext 8 */
+ case 0xc8: /* ext 16 */
+ case 0xc9: /* ext 32 */
+ return mpack_rblob(MPACK_TOKEN_EXT, TLEN(t, 0xc7), buf, buflen, tok);
+ case 0xca: /* float 32 */
+ case 0xcb: /* float 64 */
+ return mpack_rvalue(MPACK_TOKEN_FLOAT, TLEN(t, 0xc8), buf, buflen, tok);
+ case 0xcc: /* uint 8 */
+ case 0xcd: /* uint 16 */
+ case 0xce: /* uint 32 */
+ case 0xcf: /* uint 64 */
+ return mpack_rvalue(MPACK_TOKEN_UINT, TLEN(t, 0xcc), buf, buflen, tok);
+ case 0xd0: /* int 8 */
+ case 0xd1: /* int 16 */
+ case 0xd2: /* int 32 */
+ case 0xd3: /* int 64 */
+ return mpack_rvalue(MPACK_TOKEN_SINT, TLEN(t, 0xd0), buf, buflen, tok);
+ case 0xd4: /* fixext 1 */
+ case 0xd5: /* fixext 2 */
+ case 0xd6: /* fixext 4 */
+ case 0xd7: /* fixext 8 */
+ case 0xd8: /* fixext 16 */
+ if (*buflen == 0) {
+ /* require only one extra byte for the type code */
+ tok->length = 1;
+ return MPACK_EOF;
+ }
+ tok->length = TLEN(t, 0xd4);
+ tok->type = MPACK_TOKEN_EXT;
+ tok->data.ext_type = ADVANCE(buf, buflen);
+ return MPACK_OK;
+ case 0xd9: /* str 8 */
+ case 0xda: /* str 16 */
+ case 0xdb: /* str 32 */
+ return mpack_rblob(MPACK_TOKEN_STR, TLEN(t, 0xd9), buf, buflen, tok);
+ case 0xdc: /* array 16 */
+ case 0xdd: /* array 32 */
+ return mpack_rblob(MPACK_TOKEN_ARRAY, TLEN(t, 0xdb), buf, buflen, tok);
+ case 0xde: /* map 16 */
+ case 0xdf: /* map 32 */
+ return mpack_rblob(MPACK_TOKEN_MAP, TLEN(t, 0xdd), buf, buflen, tok);
+ default:
+ return MPACK_ERROR;
+ }
+ } else {
+ /* negative fixint */
+ return mpack_value(MPACK_TOKEN_SINT, 1, mpack_byte(t), tok);
+ }
+}
+
+static int mpack_rpending(const char **buf, size_t *buflen,
+ mpack_tokbuf_t *state)
+{
+ size_t count;
+ assert(state->ppos < state->plen);
+ count = MIN(state->plen - state->ppos, *buflen);
+ memcpy(state->pending + state->ppos, *buf, count);
+ state->ppos += count;
+ if (state->ppos < state->plen) {
+ /* consume buffer since no token will be parsed yet. */
+ *buf += *buflen;
+ *buflen = 0;
+ return 0;
+ }
+ return 1;
+}
+
+static int mpack_rvalue(mpack_token_type_t type, mpack_uint32_t remaining,
+ const char **buf, size_t *buflen, mpack_token_t *tok)
+{
+ if (*buflen < remaining) {
+ tok->length = remaining;
+ return MPACK_EOF;
+ }
+
+ mpack_value(type, remaining, mpack_byte(0), tok);
+
+ while (remaining) {
+ mpack_uint32_t byte = ADVANCE(buf, buflen), byte_idx, byte_shift;
+ byte_idx = (mpack_uint32_t)--remaining;
+ byte_shift = (byte_idx % 4) * 8;
+ tok->data.value.lo |= byte << byte_shift;
+ if (remaining == 4) {
+ /* unpacked the first half of a 8-byte value, shift what was parsed to the
+ * "hi" field and reset "lo" for the trailing 4 bytes. */
+ tok->data.value.hi = tok->data.value.lo;
+ tok->data.value.lo = 0;
+ }
+ }
+
+ if (type == MPACK_TOKEN_SINT) {
+ mpack_uint32_t hi = tok->data.value.hi;
+ mpack_uint32_t lo = tok->data.value.lo;
+ mpack_uint32_t msb = (tok->length == 8 && hi >> 31) ||
+ (tok->length == 4 && lo >> 31) ||
+ (tok->length == 2 && lo >> 15) ||
+ (tok->length == 1 && lo >> 7);
+ if (!msb) {
+ tok->type = MPACK_TOKEN_UINT;
+ }
+ }
+
+ return MPACK_OK;
+}
+
+static int mpack_rblob(mpack_token_type_t type, mpack_uint32_t tlen,
+ const char **buf, size_t *buflen, mpack_token_t *tok)
+{
+ mpack_token_t l;
+ mpack_uint32_t required = tlen + (type == MPACK_TOKEN_EXT ? 1 : 0);
+
+ if (*buflen < required) {
+ tok->length = required;
+ return MPACK_EOF;
+ }
+
+ l.data.value.lo = 0;
+ mpack_rvalue(MPACK_TOKEN_UINT, tlen, buf, buflen, &l);
+ tok->type = type;
+ tok->length = l.data.value.lo;
+
+ if (type == MPACK_TOKEN_EXT) {
+ tok->data.ext_type = ADVANCE(buf, buflen);
+ }
+
+ return MPACK_OK;
+}
+
+static int mpack_wtoken(const mpack_token_t *tok, char **buf,
+ size_t *buflen)
+{
+ switch (tok->type) {
+ case MPACK_TOKEN_NIL:
+ return mpack_w1(buf, buflen, 0xc0);
+ case MPACK_TOKEN_BOOLEAN:
+ return mpack_w1(buf, buflen, tok->data.value.lo ? 0xc3 : 0xc2);
+ case MPACK_TOKEN_UINT:
+ return mpack_wpint(buf, buflen, tok->data.value);
+ case MPACK_TOKEN_SINT:
+ return mpack_wnint(buf, buflen, tok->data.value);
+ case MPACK_TOKEN_FLOAT:
+ return mpack_wfloat(buf, buflen, tok);
+ case MPACK_TOKEN_BIN:
+ return mpack_wbin(buf, buflen, tok->length);
+ case MPACK_TOKEN_STR:
+ return mpack_wstr(buf, buflen, tok->length);
+ case MPACK_TOKEN_EXT:
+ return mpack_wext(buf, buflen, tok->data.ext_type, tok->length);
+ case MPACK_TOKEN_ARRAY:
+ return mpack_warray(buf, buflen, tok->length);
+ case MPACK_TOKEN_MAP:
+ return mpack_wmap(buf, buflen, tok->length);
+ default:
+ return MPACK_ERROR;
+ }
+}
+
+static int mpack_wpending(char **buf, size_t *buflen, mpack_tokbuf_t *state)
+{
+ size_t count;
+ assert(state->ppos < state->plen);
+ count = MIN(state->plen - state->ppos, *buflen);
+ memcpy(*buf, state->pending + state->ppos, count);
+ state->ppos += count;
+ *buf += count;
+ *buflen -= count;
+ if (state->ppos == state->plen) {
+ state->plen = 0;
+ return MPACK_OK;
+ }
+ return MPACK_EOF;
+}
+
+static int mpack_wpint(char **buf, size_t *buflen, mpack_value_t val)
+{
+ mpack_uint32_t hi = val.hi;
+ mpack_uint32_t lo = val.lo;
+
+ if (hi) {
+ /* uint 64 */
+ return mpack_w1(buf, buflen, 0xcf) ||
+ mpack_w4(buf, buflen, hi) ||
+ mpack_w4(buf, buflen, lo);
+ } else if (lo > 0xffff) {
+ /* uint 32 */
+ return mpack_w1(buf, buflen, 0xce) ||
+ mpack_w4(buf, buflen, lo);
+ } else if (lo > 0xff) {
+ /* uint 16 */
+ return mpack_w1(buf, buflen, 0xcd) ||
+ mpack_w2(buf, buflen, lo);
+ } else if (lo > 0x7f) {
+ /* uint 8 */
+ return mpack_w1(buf, buflen, 0xcc) ||
+ mpack_w1(buf, buflen, lo);
+ } else {
+ return mpack_w1(buf, buflen, lo);
+ }
+}
+
+static int mpack_wnint(char **buf, size_t *buflen, mpack_value_t val)
+{
+ mpack_uint32_t hi = val.hi;
+ mpack_uint32_t lo = val.lo;
+
+ if (lo < 0x80000000) {
+ /* int 64 */
+ return mpack_w1(buf, buflen, 0xd3) ||
+ mpack_w4(buf, buflen, hi) ||
+ mpack_w4(buf, buflen, lo);
+ } else if (lo < 0xffff7fff) {
+ /* int 32 */
+ return mpack_w1(buf, buflen, 0xd2) ||
+ mpack_w4(buf, buflen, lo);
+ } else if (lo < 0xffffff7f) {
+ /* int 16 */
+ return mpack_w1(buf, buflen, 0xd1) ||
+ mpack_w2(buf, buflen, lo);
+ } else if (lo < 0xffffffe0) {
+ /* int 8 */
+ return mpack_w1(buf, buflen, 0xd0) ||
+ mpack_w1(buf, buflen, lo);
+ } else {
+ /* negative fixint */
+ return mpack_w1(buf, buflen, (mpack_uint32_t)(0x100 + lo));
+ }
+}
+
+static int mpack_wfloat(char **buf, size_t *buflen,
+ const mpack_token_t *tok)
+{
+ if (tok->length == 4) {
+ return mpack_w1(buf, buflen, 0xca) ||
+ mpack_w4(buf, buflen, tok->data.value.lo);
+ } else if (tok->length == 8) {
+ return mpack_w1(buf, buflen, 0xcb) ||
+ mpack_w4(buf, buflen, tok->data.value.hi) ||
+ mpack_w4(buf, buflen, tok->data.value.lo);
+ } else {
+ return MPACK_ERROR;
+ }
+}
+
+static int mpack_wstr(char **buf, size_t *buflen, mpack_uint32_t len)
+{
+ if (len < 0x20) {
+ return mpack_w1(buf, buflen, 0xa0 | len);
+ } else if (len < 0x100) {
+ return mpack_w1(buf, buflen, 0xd9) ||
+ mpack_w1(buf, buflen, len);
+ } else if (len < 0x10000) {
+ return mpack_w1(buf, buflen, 0xda) ||
+ mpack_w2(buf, buflen, len);
+ } else {
+ return mpack_w1(buf, buflen, 0xdb) ||
+ mpack_w4(buf, buflen, len);
+ }
+}
+
+static int mpack_wbin(char **buf, size_t *buflen, mpack_uint32_t len)
+{
+ if (len < 0x100) {
+ return mpack_w1(buf, buflen, 0xc4) ||
+ mpack_w1(buf, buflen, len);
+ } else if (len < 0x10000) {
+ return mpack_w1(buf, buflen, 0xc5) ||
+ mpack_w2(buf, buflen, len);
+ } else {
+ return mpack_w1(buf, buflen, 0xc6) ||
+ mpack_w4(buf, buflen, len);
+ }
+}
+
+static int mpack_wext(char **buf, size_t *buflen, int type,
+ mpack_uint32_t len)
+{
+ mpack_uint32_t t;
+ assert(type >= 0 && type < 0x80);
+ t = (mpack_uint32_t)type;
+ switch (len) {
+ case 1: mpack_w1(buf, buflen, 0xd4); return mpack_w1(buf, buflen, t);
+ case 2: mpack_w1(buf, buflen, 0xd5); return mpack_w1(buf, buflen, t);
+ case 4: mpack_w1(buf, buflen, 0xd6); return mpack_w1(buf, buflen, t);
+ case 8: mpack_w1(buf, buflen, 0xd7); return mpack_w1(buf, buflen, t);
+ case 16: mpack_w1(buf, buflen, 0xd8); return mpack_w1(buf, buflen, t);
+ default:
+ if (len < 0x100) {
+ return mpack_w1(buf, buflen, 0xc7) ||
+ mpack_w1(buf, buflen, len) ||
+ mpack_w1(buf, buflen, t);
+ } else if (len < 0x10000) {
+ return mpack_w1(buf, buflen, 0xc8) ||
+ mpack_w2(buf, buflen, len) ||
+ mpack_w1(buf, buflen, t);
+ } else {
+ return mpack_w1(buf, buflen, 0xc9) ||
+ mpack_w4(buf, buflen, len) ||
+ mpack_w1(buf, buflen, t);
+ }
+ }
+}
+
+static int mpack_warray(char **buf, size_t *buflen, mpack_uint32_t len)
+{
+ if (len < 0x10) {
+ return mpack_w1(buf, buflen, 0x90 | len);
+ } else if (len < 0x10000) {
+ return mpack_w1(buf, buflen, 0xdc) ||
+ mpack_w2(buf, buflen, len);
+ } else {
+ return mpack_w1(buf, buflen, 0xdd) ||
+ mpack_w4(buf, buflen, len);
+ }
+}
+
+static int mpack_wmap(char **buf, size_t *buflen, mpack_uint32_t len)
+{
+ if (len < 0x10) {
+ return mpack_w1(buf, buflen, 0x80 | len);
+ } else if (len < 0x10000) {
+ return mpack_w1(buf, buflen, 0xde) ||
+ mpack_w2(buf, buflen, len);
+ } else {
+ return mpack_w1(buf, buflen, 0xdf) ||
+ mpack_w4(buf, buflen, len);
+ }
+}
+
+static int mpack_w1(char **b, size_t *bl, mpack_uint32_t v)
+{
+ (*bl)--;
+ *(*b)++ = (char)(v & 0xff);
+ return MPACK_OK;
+}
+
+static int mpack_w2(char **b, size_t *bl, mpack_uint32_t v)
+{
+ *bl -= 2;
+ *(*b)++ = (char)((v >> 8) & 0xff);
+ *(*b)++ = (char)(v & 0xff);
+ return MPACK_OK;
+}
+
+static int mpack_w4(char **b, size_t *bl, mpack_uint32_t v)
+{
+ *bl -= 4;
+ *(*b)++ = (char)((v >> 24) & 0xff);
+ *(*b)++ = (char)((v >> 16) & 0xff);
+ *(*b)++ = (char)((v >> 8) & 0xff);
+ *(*b)++ = (char)(v & 0xff);
+ return MPACK_OK;
+}
+
+static int mpack_value(mpack_token_type_t type, mpack_uint32_t length,
+ mpack_value_t value, mpack_token_t *tok)
+{
+ tok->type = type;
+ tok->length = length;
+ tok->data.value = value;
+ return MPACK_OK;
+}
+
+static int mpack_blob(mpack_token_type_t type, mpack_uint32_t length,
+ int ext_type, mpack_token_t *tok)
+{
+ tok->type = type;
+ tok->length = length;
+ tok->data.ext_type = ext_type;
+ return MPACK_OK;
+}
+
+static mpack_value_t mpack_byte(unsigned char byte)
+{
+ mpack_value_t rv;
+ rv.lo = byte;
+ rv.hi = 0;
+ return rv;
+}
diff --git a/src/mpack/mpack_core.h b/src/mpack/mpack_core.h
new file mode 100644
index 0000000000..9edd13c41e
--- /dev/null
+++ b/src/mpack/mpack_core.h
@@ -0,0 +1,87 @@
+#ifndef MPACK_CORE_H
+#define MPACK_CORE_H
+
+#ifndef MPACK_API
+# define MPACK_API extern
+#endif
+
+#include <assert.h>
+#include <limits.h>
+#include <stddef.h>
+
+#ifdef __GNUC__
+# define FPURE __attribute__((const))
+# define FNONULL __attribute__((nonnull))
+# define FNONULL_ARG(x) __attribute__((nonnull x))
+# define FUNUSED __attribute__((unused))
+#else
+# define FPURE
+# define FNONULL
+# define FNONULL_ARG(x)
+# define FUNUSED
+#endif
+
+#if UINT_MAX == 0xffffffff
+typedef int mpack_sint32_t;
+typedef unsigned int mpack_uint32_t;
+#elif ULONG_MAX == 0xffffffff
+typedef long mpack_sint32_t;
+typedef unsigned long mpack_uint32_t;
+#else
+# error "can't find unsigned 32-bit integer type"
+#endif
+
+typedef struct mpack_value_s {
+ mpack_uint32_t lo, hi;
+} mpack_value_t;
+
+
+enum {
+ MPACK_OK = 0,
+ MPACK_EOF = 1,
+ MPACK_ERROR = 2
+};
+
+#define MPACK_MAX_TOKEN_LEN 9 /* 64-bit ints/floats plus type code */
+
+typedef enum {
+ MPACK_TOKEN_NIL = 1,
+ MPACK_TOKEN_BOOLEAN = 2,
+ MPACK_TOKEN_UINT = 3,
+ MPACK_TOKEN_SINT = 4,
+ MPACK_TOKEN_FLOAT = 5,
+ MPACK_TOKEN_CHUNK = 6,
+ MPACK_TOKEN_ARRAY = 7,
+ MPACK_TOKEN_MAP = 8,
+ MPACK_TOKEN_BIN = 9,
+ MPACK_TOKEN_STR = 10,
+ MPACK_TOKEN_EXT = 11
+} mpack_token_type_t;
+
+typedef struct mpack_token_s {
+ mpack_token_type_t type; /* Type of token */
+ mpack_uint32_t length; /* Byte length for str/bin/ext/chunk/float/int/uint.
+ Item count for array/map. */
+ union {
+ mpack_value_t value; /* 32-bit parts of primitives (bool,int,float) */
+ const char *chunk_ptr; /* Chunk of data from str/bin/ext */
+ int ext_type; /* Type field for ext tokens */
+ } data;
+} mpack_token_t;
+
+typedef struct mpack_tokbuf_s {
+ char pending[MPACK_MAX_TOKEN_LEN];
+ mpack_token_t pending_tok;
+ size_t ppos, plen;
+ mpack_uint32_t passthrough;
+} mpack_tokbuf_t;
+
+#define MPACK_TOKBUF_INITIAL_VALUE { { 0 }, { 0, 0, { { 0, 0 } } }, 0, 0, 0 }
+
+MPACK_API void mpack_tokbuf_init(mpack_tokbuf_t *tb) FUNUSED FNONULL;
+MPACK_API int mpack_read(mpack_tokbuf_t *tb, const char **b, size_t *bl,
+ mpack_token_t *tok) FUNUSED FNONULL;
+MPACK_API int mpack_write(mpack_tokbuf_t *tb, char **b, size_t *bl,
+ const mpack_token_t *tok) FUNUSED FNONULL;
+
+#endif /* MPACK_CORE_H */
diff --git a/src/mpack/object.c b/src/mpack/object.c
new file mode 100644
index 0000000000..e2d893bc88
--- /dev/null
+++ b/src/mpack/object.c
@@ -0,0 +1,198 @@
+// 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 <string.h>
+
+#include "object.h"
+
+static int mpack_parser_full(mpack_parser_t *w);
+static mpack_node_t *mpack_parser_push(mpack_parser_t *w);
+static mpack_node_t *mpack_parser_pop(mpack_parser_t *w);
+
+MPACK_API void mpack_parser_init(mpack_parser_t *parser,
+ mpack_uint32_t capacity)
+{
+ mpack_tokbuf_init(&parser->tokbuf);
+ parser->data.p = NULL;
+ parser->capacity = capacity ? capacity : MPACK_MAX_OBJECT_DEPTH;
+ parser->size = 0;
+ parser->exiting = 0;
+ memset(parser->items, 0, sizeof(mpack_node_t) * (parser->capacity + 1));
+ parser->items[0].pos = (size_t)-1;
+ parser->status = 0;
+}
+
+#define MPACK_EXCEPTION_CHECK(parser) \
+ do { \
+ if (parser->status == MPACK_EXCEPTION) { \
+ return MPACK_EXCEPTION; \
+ } \
+ } while (0)
+
+#define MPACK_WALK(action) \
+ do { \
+ mpack_node_t *n; \
+ \
+ if (parser->exiting) goto exit; \
+ if (mpack_parser_full(parser)) return MPACK_NOMEM; \
+ n = mpack_parser_push(parser); \
+ action; \
+ MPACK_EXCEPTION_CHECK(parser); \
+ parser->exiting = 1; \
+ return MPACK_EOF; \
+ \
+exit: \
+ parser->exiting = 0; \
+ while ((n = mpack_parser_pop(parser))) { \
+ exit_cb(parser, n); \
+ MPACK_EXCEPTION_CHECK(parser); \
+ if (!parser->size) return MPACK_OK; \
+ } \
+ \
+ return MPACK_EOF; \
+ } while (0)
+
+MPACK_API int mpack_parse_tok(mpack_parser_t *parser, mpack_token_t tok,
+ mpack_walk_cb enter_cb, mpack_walk_cb exit_cb)
+{
+ MPACK_EXCEPTION_CHECK(parser);
+ MPACK_WALK({n->tok = tok; enter_cb(parser, n);});
+}
+
+MPACK_API int mpack_unparse_tok(mpack_parser_t *parser, mpack_token_t *tok,
+ mpack_walk_cb enter_cb, mpack_walk_cb exit_cb)
+{
+ MPACK_EXCEPTION_CHECK(parser);
+ MPACK_WALK({enter_cb(parser, n); *tok = n->tok;});
+}
+
+MPACK_API int mpack_parse(mpack_parser_t *parser, const char **buf,
+ size_t *buflen, mpack_walk_cb enter_cb, mpack_walk_cb exit_cb)
+{
+ int status = MPACK_EOF;
+ MPACK_EXCEPTION_CHECK(parser);
+
+ while (*buflen && status) {
+ mpack_token_t tok;
+ mpack_tokbuf_t *tb = &parser->tokbuf;
+ const char *buf_save = *buf;
+ size_t buflen_save = *buflen;
+
+ if ((status = mpack_read(tb, buf, buflen, &tok)) == MPACK_EOF) continue;
+ else if (status == MPACK_ERROR) goto rollback;
+
+ do {
+ status = mpack_parse_tok(parser, tok, enter_cb, exit_cb);
+ MPACK_EXCEPTION_CHECK(parser);
+ } while (parser->exiting);
+
+ if (status != MPACK_NOMEM) continue;
+
+rollback:
+ /* restore buf/buflen so the next call will try to read the same token */
+ *buf = buf_save;
+ *buflen = buflen_save;
+ break;
+ }
+
+ return status;
+}
+
+MPACK_API int mpack_unparse(mpack_parser_t *parser, char **buf, size_t *buflen,
+ mpack_walk_cb enter_cb, mpack_walk_cb exit_cb)
+{
+ int status = MPACK_EOF;
+ MPACK_EXCEPTION_CHECK(parser);
+
+ while (*buflen && status) {
+ int write_status;
+ mpack_token_t tok;
+ mpack_tokbuf_t *tb = &parser->tokbuf;
+
+ if (!tb->plen)
+ parser->status = mpack_unparse_tok(parser, &tok, enter_cb, exit_cb);
+
+ MPACK_EXCEPTION_CHECK(parser);
+
+ status = parser->status;
+
+ if (status == MPACK_NOMEM)
+ break;
+
+ if (parser->exiting) {
+ write_status = mpack_write(tb, buf, buflen, &tok);
+ status = write_status ? write_status : status;
+ }
+ }
+
+ return status;
+}
+
+MPACK_API void mpack_parser_copy(mpack_parser_t *dst, mpack_parser_t *src)
+{
+ mpack_uint32_t i;
+ mpack_uint32_t dst_capacity = dst->capacity;
+ assert(src->capacity <= dst_capacity);
+ /* copy all fields except the stack */
+ memcpy(dst, src, sizeof(mpack_one_parser_t) - sizeof(mpack_node_t));
+ /* reset capacity */
+ dst->capacity = dst_capacity;
+ /* copy the stack */
+ for (i = 0; i <= src->capacity; i++) {
+ dst->items[i] = src->items[i];
+ }
+}
+
+static int mpack_parser_full(mpack_parser_t *parser)
+{
+ return parser->size == parser->capacity;
+}
+
+static mpack_node_t *mpack_parser_push(mpack_parser_t *parser)
+{
+ mpack_node_t *top;
+ assert(parser->size < parser->capacity);
+ top = parser->items + parser->size + 1;
+ top->data[0].p = NULL;
+ top->data[1].p = NULL;
+ top->pos = 0;
+ top->key_visited = 0;
+ /* increase size and invoke callback, passing parent node if any */
+ parser->size++;
+ return top;
+}
+
+static mpack_node_t *mpack_parser_pop(mpack_parser_t *parser)
+{
+ mpack_node_t *top, *parent;
+ assert(parser->size);
+ top = parser->items + parser->size;
+
+ if (top->tok.type > MPACK_TOKEN_CHUNK && top->pos < top->tok.length) {
+ /* continue processing children */
+ return NULL;
+ }
+
+ parent = MPACK_PARENT_NODE(top);
+ if (parent) {
+ /* we use parent->tok.length to keep track of how many children remain.
+ * update it to reflect the processed node. */
+ if (top->tok.type == MPACK_TOKEN_CHUNK) {
+ parent->pos += top->tok.length;
+ } else if (parent->tok.type == MPACK_TOKEN_MAP) {
+ /* maps allow up to 2^32 - 1 pairs, so to allow this many items in a
+ * 32-bit length variable we use an additional flag to determine if the
+ * key of a certain position was visited */
+ if (parent->key_visited) {
+ parent->pos++;
+ }
+ parent->key_visited = !parent->key_visited;
+ } else {
+ parent->pos++;
+ }
+ }
+
+ parser->size--;
+ return top;
+}
+
diff --git a/src/mpack/object.h b/src/mpack/object.h
new file mode 100644
index 0000000000..5327e56e18
--- /dev/null
+++ b/src/mpack/object.h
@@ -0,0 +1,86 @@
+#ifndef MPACK_OBJECT_H
+#define MPACK_OBJECT_H
+
+#include "mpack_core.h"
+#include "conv.h"
+
+#ifndef MPACK_MAX_OBJECT_DEPTH
+# define MPACK_MAX_OBJECT_DEPTH 32
+#endif
+
+#define MPACK_PARENT_NODE(n) (((n) - 1)->pos == (size_t)-1 ? NULL : (n) - 1)
+
+#define MPACK_THROW(parser) \
+ do { \
+ parser->status = MPACK_EXCEPTION; \
+ return; \
+ } while (0)
+
+enum {
+ MPACK_EXCEPTION = -1,
+ MPACK_NOMEM = MPACK_ERROR + 1
+};
+
+/* Storing integer in pointers in undefined behavior according to the C
+ * standard. Define a union type to accomodate arbitrary user data associated
+ * with nodes(and with requests in rpc.h). */
+typedef union {
+ void *p;
+ mpack_uintmax_t u;
+ mpack_sintmax_t i;
+ double d;
+} mpack_data_t;
+
+typedef struct mpack_node_s {
+ mpack_token_t tok;
+ size_t pos;
+ /* flag to determine if the key was visited when traversing a map */
+ int key_visited;
+ /* allow 2 instances mpack_data_t per node. the reason is that when
+ * serializing, the user may need to keep track of traversal state besides the
+ * parent node reference */
+ mpack_data_t data[2];
+} mpack_node_t;
+
+#define MPACK_PARSER_STRUCT(c) \
+ struct { \
+ mpack_data_t data; \
+ mpack_uint32_t size, capacity; \
+ int status; \
+ int exiting; \
+ mpack_tokbuf_t tokbuf; \
+ mpack_node_t items[c + 1]; \
+ }
+
+/* Some compilers warn against anonymous structs:
+ * https://github.com/libmpack/libmpack/issues/6 */
+typedef MPACK_PARSER_STRUCT(0) mpack_one_parser_t;
+
+#define MPACK_PARSER_STRUCT_SIZE(c) \
+ (sizeof(mpack_node_t) * c + \
+ sizeof(mpack_one_parser_t))
+
+typedef MPACK_PARSER_STRUCT(MPACK_MAX_OBJECT_DEPTH) mpack_parser_t;
+typedef void(*mpack_walk_cb)(mpack_parser_t *w, mpack_node_t *n);
+
+MPACK_API void mpack_parser_init(mpack_parser_t *p, mpack_uint32_t c)
+ FUNUSED FNONULL;
+
+MPACK_API int mpack_parse_tok(mpack_parser_t *walker, mpack_token_t tok,
+ mpack_walk_cb enter_cb, mpack_walk_cb exit_cb)
+ FUNUSED FNONULL_ARG((1,3,4));
+MPACK_API int mpack_unparse_tok(mpack_parser_t *walker, mpack_token_t *tok,
+ mpack_walk_cb enter_cb, mpack_walk_cb exit_cb)
+ FUNUSED FNONULL_ARG((1,2,3,4));
+
+MPACK_API int mpack_parse(mpack_parser_t *parser, const char **b, size_t *bl,
+ mpack_walk_cb enter_cb, mpack_walk_cb exit_cb)
+ FUNUSED FNONULL_ARG((1,2,3,4,5));
+MPACK_API int mpack_unparse(mpack_parser_t *parser, char **b, size_t *bl,
+ mpack_walk_cb enter_cb, mpack_walk_cb exit_cb)
+ FUNUSED FNONULL_ARG((1,2,3,4,5));
+
+MPACK_API void mpack_parser_copy(mpack_parser_t *d, mpack_parser_t *s)
+ FUNUSED FNONULL;
+
+#endif /* MPACK_OBJECT_H */
diff --git a/src/mpack/rpc.c b/src/mpack/rpc.c
new file mode 100644
index 0000000000..2d251284ba
--- /dev/null
+++ b/src/mpack/rpc.c
@@ -0,0 +1,334 @@
+// 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 <string.h>
+
+#include "rpc.h"
+
+enum {
+ MPACK_RPC_RECEIVE_ARRAY = 1,
+ MPACK_RPC_RECEIVE_TYPE,
+ MPACK_RPC_RECEIVE_ID
+};
+
+static mpack_rpc_header_t mpack_rpc_request_hdr(void);
+static mpack_rpc_header_t mpack_rpc_reply_hdr(void);
+static mpack_rpc_header_t mpack_rpc_notify_hdr(void);
+static int mpack_rpc_put(mpack_rpc_session_t *s, mpack_rpc_message_t m);
+static int mpack_rpc_pop(mpack_rpc_session_t *s, mpack_rpc_message_t *m);
+static void mpack_rpc_reset_hdr(mpack_rpc_header_t *hdr);
+
+MPACK_API void mpack_rpc_session_init(mpack_rpc_session_t *session,
+ mpack_uint32_t capacity)
+{
+ session->capacity = capacity ? capacity : MPACK_RPC_MAX_REQUESTS;
+ session->request_id = 0;
+ mpack_tokbuf_init(&session->reader);
+ mpack_tokbuf_init(&session->writer);
+ mpack_rpc_reset_hdr(&session->receive);
+ mpack_rpc_reset_hdr(&session->send);
+ memset(session->slots, 0,
+ sizeof(struct mpack_rpc_slot_s) * session->capacity);
+}
+
+MPACK_API int mpack_rpc_receive_tok(mpack_rpc_session_t *session,
+ mpack_token_t tok, mpack_rpc_message_t *msg)
+{
+ int type;
+
+ if (session->receive.index == 0) {
+ if (tok.type != MPACK_TOKEN_ARRAY)
+ /* not an array */
+ return MPACK_RPC_EARRAY;
+
+ if (tok.length < 3 || tok.length > 4)
+ /* invalid array length */
+ return MPACK_RPC_EARRAYL;
+
+ session->receive.toks[0] = tok;
+ session->receive.index++;
+ return MPACK_EOF; /* get the type */
+ }
+
+ if (session->receive.index == 1) {
+
+ if (tok.type != MPACK_TOKEN_UINT || tok.length > 1 || tok.data.value.lo > 2)
+ /* invalid type */
+ return MPACK_RPC_ETYPE;
+
+ if (tok.data.value.lo < 2 && session->receive.toks[0].length != 4)
+ /* request or response with array length != 4 */
+ return MPACK_RPC_EARRAYL;
+
+ if (tok.data.value.lo == 2 && session->receive.toks[0].length != 3)
+ /* notification with array length != 3 */
+ return MPACK_RPC_EARRAYL;
+
+ session->receive.toks[1] = tok;
+ session->receive.index++;
+
+ if (tok.data.value.lo < 2) return MPACK_EOF;
+
+ type = MPACK_RPC_NOTIFICATION;
+ goto end;
+ }
+
+ assert(session->receive.index == 2);
+
+ if (tok.type != MPACK_TOKEN_UINT || tok.length > 4)
+ /* invalid request/response id */
+ return MPACK_RPC_EMSGID;
+
+ msg->id = tok.data.value.lo;
+ msg->data.p = NULL;
+ type = (int)session->receive.toks[1].data.value.lo + MPACK_RPC_REQUEST;
+
+ if (type == MPACK_RPC_RESPONSE && !mpack_rpc_pop(session, msg))
+ /* response with invalid id */
+ return MPACK_RPC_ERESPID;
+
+end:
+ mpack_rpc_reset_hdr(&session->receive);
+ return type;
+}
+
+MPACK_API int mpack_rpc_request_tok(mpack_rpc_session_t *session,
+ mpack_token_t *tok, mpack_data_t data)
+{
+ if (session->send.index == 0) {
+ int status;
+ mpack_rpc_message_t msg;
+ do {
+ msg.id = session->request_id;
+ msg.data = data;
+ session->send = mpack_rpc_request_hdr();
+ session->send.toks[2].type = MPACK_TOKEN_UINT;
+ session->send.toks[2].data.value.lo = msg.id;
+ session->send.toks[2].data.value.hi = 0;
+ *tok = session->send.toks[0];
+ status = mpack_rpc_put(session, msg);
+ if (status == -1) return MPACK_NOMEM;
+ session->request_id = (session->request_id + 1) % 0xffffffff;
+ } while (!status);
+ session->send.index++;
+ return MPACK_EOF;
+ }
+
+ if (session->send.index == 1) {
+ *tok = session->send.toks[1];
+ session->send.index++;
+ return MPACK_EOF;
+ }
+
+ assert(session->send.index == 2);
+ *tok = session->send.toks[2];
+ mpack_rpc_reset_hdr(&session->send);
+ return MPACK_OK;
+}
+
+MPACK_API int mpack_rpc_reply_tok(mpack_rpc_session_t *session,
+ mpack_token_t *tok, mpack_uint32_t id)
+{
+ if (session->send.index == 0) {
+ session->send = mpack_rpc_reply_hdr();
+ session->send.toks[2].type = MPACK_TOKEN_UINT;
+ session->send.toks[2].data.value.lo = id;
+ session->send.toks[2].data.value.hi = 0;
+ *tok = session->send.toks[0];
+ session->send.index++;
+ return MPACK_EOF;
+ }
+
+ if (session->send.index == 1) {
+ *tok = session->send.toks[1];
+ session->send.index++;
+ return MPACK_EOF;
+ }
+
+ assert(session->send.index == 2);
+ *tok = session->send.toks[2];
+ mpack_rpc_reset_hdr(&session->send);
+ return MPACK_OK;
+}
+
+MPACK_API int mpack_rpc_notify_tok(mpack_rpc_session_t *session,
+ mpack_token_t *tok)
+{
+ if (session->send.index == 0) {
+ session->send = mpack_rpc_notify_hdr();
+ *tok = session->send.toks[0];
+ session->send.index++;
+ return MPACK_EOF;
+ }
+
+ assert(session->send.index == 1);
+ *tok = session->send.toks[1];
+ mpack_rpc_reset_hdr(&session->send);
+ return MPACK_OK;
+}
+
+MPACK_API int mpack_rpc_receive(mpack_rpc_session_t *session, const char **buf,
+ size_t *buflen, mpack_rpc_message_t *msg)
+{
+ int status;
+
+ do {
+ mpack_token_t tok;
+ status = mpack_read(&session->reader, buf, buflen, &tok);
+ if (status) break;
+ status = mpack_rpc_receive_tok(session, tok, msg);
+ if (status >= MPACK_RPC_REQUEST) break;
+ } while (*buflen);
+
+ return status;
+}
+
+MPACK_API int mpack_rpc_request(mpack_rpc_session_t *session, char **buf,
+ size_t *buflen, mpack_data_t data)
+{
+ int status = MPACK_EOF;
+
+ while (status && *buflen) {
+ int write_status;
+ mpack_token_t tok;
+ if (!session->writer.plen) {
+ status = mpack_rpc_request_tok(session, &tok, data);
+ }
+ if (status == MPACK_NOMEM) break;
+ write_status = mpack_write(&session->writer, buf, buflen, &tok);
+ status = write_status ? write_status : status;
+ }
+
+ return status;
+}
+
+MPACK_API int mpack_rpc_reply(mpack_rpc_session_t *session, char **buf,
+ size_t *buflen, mpack_uint32_t id)
+{
+ int status = MPACK_EOF;
+
+ while (status && *buflen) {
+ int write_status;
+ mpack_token_t tok;
+ if (!session->writer.plen) {
+ status = mpack_rpc_reply_tok(session, &tok, id);
+ }
+ write_status = mpack_write(&session->writer, buf, buflen, &tok);
+ status = write_status ? write_status : status;
+ }
+
+ return status;
+}
+
+MPACK_API int mpack_rpc_notify(mpack_rpc_session_t *session, char **buf,
+ size_t *buflen)
+{
+ int status = MPACK_EOF;
+
+ while (status && *buflen) {
+ int write_status;
+ mpack_token_t tok;
+ if (!session->writer.plen) {
+ status = mpack_rpc_notify_tok(session, &tok);
+ }
+ write_status = mpack_write(&session->writer, buf, buflen, &tok);
+ status = write_status ? write_status : status;
+ }
+
+ return status;
+}
+
+MPACK_API void mpack_rpc_session_copy(mpack_rpc_session_t *dst,
+ mpack_rpc_session_t *src)
+{
+ mpack_uint32_t i;
+ mpack_uint32_t dst_capacity = dst->capacity;
+ assert(src->capacity <= dst_capacity);
+ /* copy all fields except slots */
+ memcpy(dst, src, sizeof(mpack_rpc_one_session_t) -
+ sizeof(struct mpack_rpc_slot_s));
+ /* reset capacity */
+ dst->capacity = dst_capacity;
+ /* reinsert requests */
+ memset(dst->slots, 0, sizeof(struct mpack_rpc_slot_s) * dst->capacity);
+ for (i = 0; i < src->capacity; i++) {
+ if (src->slots[i].used) mpack_rpc_put(dst, src->slots[i].msg);
+ }
+}
+
+static mpack_rpc_header_t mpack_rpc_request_hdr(void)
+{
+ mpack_rpc_header_t hdr;
+ hdr.index = 0;
+ hdr.toks[0].type = MPACK_TOKEN_ARRAY;
+ hdr.toks[0].length = 4;
+ hdr.toks[1].type = MPACK_TOKEN_UINT;
+ hdr.toks[1].data.value.lo = 0;
+ hdr.toks[1].data.value.hi = 0;
+ return hdr;
+}
+
+static mpack_rpc_header_t mpack_rpc_reply_hdr(void)
+{
+ mpack_rpc_header_t hdr = mpack_rpc_request_hdr();
+ hdr.toks[1].data.value.lo = 1;
+ hdr.toks[1].data.value.hi = 0;
+ return hdr;
+}
+
+static mpack_rpc_header_t mpack_rpc_notify_hdr(void)
+{
+ mpack_rpc_header_t hdr = mpack_rpc_request_hdr();
+ hdr.toks[0].length = 3;
+ hdr.toks[1].data.value.lo = 2;
+ hdr.toks[1].data.value.hi = 0;
+ return hdr;
+}
+
+static int mpack_rpc_put(mpack_rpc_session_t *session, mpack_rpc_message_t msg)
+{
+ struct mpack_rpc_slot_s *slot = NULL;
+ mpack_uint32_t i;
+ mpack_uint32_t hash = msg.id % session->capacity;
+
+ for (i = 0; i < session->capacity; i++) {
+ if (!session->slots[hash].used || session->slots[hash].msg.id == msg.id) {
+ slot = session->slots + hash;
+ break;
+ }
+ hash = hash > 0 ? hash - 1 : session->capacity - 1;
+ }
+
+ if (!slot) return -1; /* no space */
+ if (slot->msg.id == msg.id && slot->used) return 0; /* duplicate key */
+ slot->msg = msg;
+ slot->used = 1;
+ return 1;
+}
+
+static int mpack_rpc_pop(mpack_rpc_session_t *session, mpack_rpc_message_t *msg)
+{
+ struct mpack_rpc_slot_s *slot = NULL;
+ mpack_uint32_t i;
+ mpack_uint32_t hash = msg->id % session->capacity;
+
+ for (i = 0; i < session->capacity; i++) {
+ if (session->slots[hash].used && session->slots[hash].msg.id == msg->id) {
+ slot = session->slots + hash;
+ break;
+ }
+ hash = hash > 0 ? hash - 1 : session->capacity - 1;
+ }
+
+ if (!slot) return 0;
+
+ *msg = slot->msg;
+ slot->used = 0;
+
+ return 1;
+}
+
+static void mpack_rpc_reset_hdr(mpack_rpc_header_t *hdr)
+{
+ hdr->index = 0;
+}
diff --git a/src/mpack/rpc.h b/src/mpack/rpc.h
new file mode 100644
index 0000000000..c1e8d656b5
--- /dev/null
+++ b/src/mpack/rpc.h
@@ -0,0 +1,83 @@
+#ifndef MPACK_RPC_H
+#define MPACK_RPC_H
+
+#include "mpack_core.h"
+#include "object.h"
+
+#ifndef MPACK_RPC_MAX_REQUESTS
+# define MPACK_RPC_MAX_REQUESTS 32
+#endif
+
+enum {
+ MPACK_RPC_REQUEST = MPACK_NOMEM + 1,
+ MPACK_RPC_RESPONSE,
+ MPACK_RPC_NOTIFICATION,
+ MPACK_RPC_ERROR
+};
+
+enum {
+ MPACK_RPC_EARRAY = MPACK_RPC_ERROR,
+ MPACK_RPC_EARRAYL,
+ MPACK_RPC_ETYPE,
+ MPACK_RPC_EMSGID,
+ MPACK_RPC_ERESPID
+};
+
+typedef struct mpack_rpc_header_s {
+ mpack_token_t toks[3];
+ int index;
+} mpack_rpc_header_t;
+
+typedef struct mpack_rpc_message_s {
+ mpack_uint32_t id;
+ mpack_data_t data;
+} mpack_rpc_message_t;
+
+struct mpack_rpc_slot_s {
+ int used;
+ mpack_rpc_message_t msg;
+};
+
+#define MPACK_RPC_SESSION_STRUCT(c) \
+ struct { \
+ mpack_tokbuf_t reader, writer; \
+ mpack_rpc_header_t receive, send; \
+ mpack_uint32_t request_id, capacity; \
+ struct mpack_rpc_slot_s slots[c]; \
+ }
+
+/* Some compilers warn against anonymous structs:
+ * https://github.com/libmpack/libmpack/issues/6 */
+typedef MPACK_RPC_SESSION_STRUCT(1) mpack_rpc_one_session_t;
+
+#define MPACK_RPC_SESSION_STRUCT_SIZE(c) \
+ (sizeof(struct mpack_rpc_slot_s) * (c - 1) + \
+ sizeof(mpack_rpc_one_session_t))
+
+typedef MPACK_RPC_SESSION_STRUCT(MPACK_RPC_MAX_REQUESTS) mpack_rpc_session_t;
+
+MPACK_API void mpack_rpc_session_init(mpack_rpc_session_t *s, mpack_uint32_t c)
+ FUNUSED FNONULL;
+
+MPACK_API int mpack_rpc_receive_tok(mpack_rpc_session_t *s, mpack_token_t t,
+ mpack_rpc_message_t *msg) FUNUSED FNONULL;
+MPACK_API int mpack_rpc_request_tok(mpack_rpc_session_t *s, mpack_token_t *t,
+ mpack_data_t d) FUNUSED FNONULL_ARG((1,2));
+MPACK_API int mpack_rpc_reply_tok(mpack_rpc_session_t *s, mpack_token_t *t,
+ mpack_uint32_t i) FUNUSED FNONULL;
+MPACK_API int mpack_rpc_notify_tok(mpack_rpc_session_t *s, mpack_token_t *t)
+ FUNUSED FNONULL;
+
+MPACK_API int mpack_rpc_receive(mpack_rpc_session_t *s, const char **b,
+ size_t *bl, mpack_rpc_message_t *m) FUNUSED FNONULL;
+MPACK_API int mpack_rpc_request(mpack_rpc_session_t *s, char **b, size_t *bl,
+ mpack_data_t d) FUNUSED FNONULL_ARG((1,2,3));
+MPACK_API int mpack_rpc_reply(mpack_rpc_session_t *s, char **b, size_t *bl,
+ mpack_uint32_t i) FNONULL FUNUSED;
+MPACK_API int mpack_rpc_notify(mpack_rpc_session_t *s, char **b, size_t *bl)
+ FNONULL FUNUSED;
+
+MPACK_API void mpack_rpc_session_copy(mpack_rpc_session_t *d,
+ mpack_rpc_session_t *s) FUNUSED FNONULL;
+
+#endif /* MPACK_RPC_H */
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index e4d7115654..e35e7ce2d4 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -29,7 +29,7 @@ set(API_UI_EVENTS_GENERATOR ${GENERATOR_DIR}/gen_api_ui_events.lua)
set(GENERATOR_C_GRAMMAR ${GENERATOR_DIR}/c_grammar.lua)
set(API_METADATA ${PROJECT_BINARY_DIR}/api_metadata.mpack)
set(FUNCS_DATA ${PROJECT_BINARY_DIR}/funcs_data.mpack)
-set(MSGPACK_LUA_C_BINDINGS ${GENERATED_DIR}/msgpack_lua_c_bindings.generated.c)
+set(LUA_API_C_BINDINGS ${GENERATED_DIR}/lua_api_c_bindings.generated.c)
set(HEADER_GENERATOR ${GENERATOR_DIR}/gen_declarations.lua)
set(GENERATED_INCLUDES_DIR ${PROJECT_BINARY_DIR}/include)
set(GENERATED_API_DISPATCH ${GENERATED_DIR}/api/private/dispatch_wrappers.generated.h)
@@ -56,6 +56,8 @@ set(VIM_MODULE_FILE ${GENERATED_DIR}/lua/vim_module.generated.h)
set(LUA_VIM_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/src/nvim/lua/vim.lua)
set(LUA_SHARED_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/runtime/lua/vim/shared.lua)
set(LUA_INSPECT_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/runtime/lua/vim/inspect.lua)
+set(LUA_F_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/runtime/lua/vim/F.lua)
+set(LUA_META_MODULE_SOURCE ${PROJECT_SOURCE_DIR}/runtime/lua/vim/_meta.lua)
set(CHAR_BLOB_GENERATOR ${GENERATOR_DIR}/gen_char_blob.lua)
set(LINT_SUPPRESS_FILE ${PROJECT_BINARY_DIR}/errors.json)
set(LINT_SUPPRESS_URL_BASE "https://raw.githubusercontent.com/neovim/doc/gh-pages/reports/clint")
@@ -85,8 +87,8 @@ file(MAKE_DIRECTORY ${LINT_SUPPRESSES_ROOT}/src)
file(GLOB NVIM_SOURCES *.c)
file(GLOB NVIM_HEADERS *.h)
-file(GLOB XDIFF_SOURCES xdiff/*.c)
-file(GLOB XDIFF_HEADERS xdiff/*.h)
+file(GLOB EXTERNAL_SOURCES ../xdiff/*.c ../mpack/*.c ../cjson/*.c)
+file(GLOB EXTERNAL_HEADERS ../xdiff/*.h ../mpack/*.h ../cjson/*.h)
foreach(subdir
os
@@ -169,8 +171,8 @@ foreach(sfile ${CONV_SOURCES})
message(FATAL_ERROR "${sfile} doesn't exist (it was added to CONV_SOURCES)")
endif()
endforeach()
-# xdiff: inlined external project, we don't maintain it. #9306
-list(APPEND CONV_SOURCES ${XDIFF_SOURCES})
+# xdiff, mpack, lua-cjson: inlined external project, we don't maintain it. #9306
+list(APPEND CONV_SOURCES ${EXTERNAL_SOURCES})
if(NOT MSVC)
set_source_files_properties(
@@ -305,11 +307,11 @@ add_custom_command(OUTPUT ${GENERATED_UNICODE_TABLES}
add_custom_command(
OUTPUT ${GENERATED_API_DISPATCH} ${GENERATED_FUNCS_METADATA}
- ${API_METADATA} ${MSGPACK_LUA_C_BINDINGS}
+ ${API_METADATA} ${LUA_API_C_BINDINGS}
COMMAND ${LUA_PRG} ${API_DISPATCH_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}
${GENERATED_API_DISPATCH}
${GENERATED_FUNCS_METADATA} ${API_METADATA}
- ${MSGPACK_LUA_C_BINDINGS}
+ ${LUA_API_C_BINDINGS}
${API_HEADERS}
DEPENDS
${API_HEADERS}
@@ -325,15 +327,19 @@ add_custom_command(
${LUA_VIM_MODULE_SOURCE} vim_module
${LUA_SHARED_MODULE_SOURCE} shared_module
${LUA_INSPECT_MODULE_SOURCE} inspect_module
+ ${LUA_F_MODULE_SOURCE} lua_F_module
+ ${LUA_META_MODULE_SOURCE} lua_meta_module
DEPENDS
${CHAR_BLOB_GENERATOR}
${LUA_VIM_MODULE_SOURCE}
${LUA_SHARED_MODULE_SOURCE}
${LUA_INSPECT_MODULE_SOURCE}
+ ${LUA_F_MODULE_SOURCE}
+ ${LUA_META_MODULE_SOURCE}
)
list(APPEND NVIM_GENERATED_SOURCES
- "${MSGPACK_LUA_C_BINDINGS}"
+ "${LUA_API_C_BINDINGS}"
)
add_custom_command(
@@ -465,7 +471,7 @@ endif()
add_executable(nvim ${NVIM_GENERATED_FOR_SOURCES} ${NVIM_GENERATED_FOR_HEADERS}
${NVIM_GENERATED_SOURCES} ${NVIM_SOURCES} ${NVIM_HEADERS}
- ${XDIFF_SOURCES} ${XDIFF_HEADERS})
+ ${EXTERNAL_SOURCES} ${EXTERNAL_HEADERS})
target_link_libraries(nvim ${NVIM_EXEC_LINK_LIBRARIES})
install_helper(TARGETS nvim)
@@ -596,7 +602,7 @@ add_library(
EXCLUDE_FROM_ALL
${NVIM_SOURCES} ${NVIM_GENERATED_SOURCES}
${NVIM_HEADERS} ${NVIM_GENERATED_FOR_SOURCES} ${NVIM_GENERATED_FOR_HEADERS}
- ${XDIFF_SOURCES} ${XDIFF_HEADERS}
+ ${EXTERNAL_SOURCES} ${EXTERNAL_HEADERS}
)
set_property(TARGET libnvim APPEND PROPERTY
INCLUDE_DIRECTORIES ${LUA_PREFERRED_INCLUDE_DIRS})
@@ -626,7 +632,7 @@ else()
EXCLUDE_FROM_ALL
${NVIM_SOURCES} ${NVIM_GENERATED_SOURCES}
${NVIM_HEADERS} ${NVIM_GENERATED_FOR_SOURCES} ${NVIM_GENERATED_FOR_HEADERS}
- ${XDIFF_SOURCES} ${XDIFF_HEADERS}
+ ${EXTERNAL_SOURCES} ${EXTERNAL_HEADERS}
${UNIT_TEST_FIXTURES}
)
target_link_libraries(nvim-test ${NVIM_TEST_LINK_LIBRARIES})
diff --git a/src/nvim/README.md b/src/nvim/README.md
index affc5c79cc..4efb42b896 100644
--- a/src/nvim/README.md
+++ b/src/nvim/README.md
@@ -75,8 +75,108 @@ Logs will be written to `${HOME}/logs/*san.PID` then.
For more information: https://github.com/google/sanitizers/wiki/SanitizerCommonFlags
-TUI debugging
--------------
+Debug: Performance
+------------------
+
+### Profiling (easy)
+
+For debugging performance bottlenecks in any code, there is a simple (and very
+effective) approach:
+
+1. Run the slow code in a loop.
+2. Break execution ~5 times and save the stacktrace.
+3. The cause of the bottleneck will (almost always) appear in most of the stacktraces.
+
+### Profiling (fancy)
+
+For more advanced profiling, consider `perf` + `flamegraph`.
+
+### USDT profiling (powerful)
+
+Or you can use USDT probes via `NVIM_PROBE` ([#12036](https://github.com/neovim/neovim/pull/12036)).
+
+> USDT is basically a way to define stable probe points in userland binaries.
+> The benefit of bcc is the ability to define logic to go along with the probe
+> points.
+
+Tools:
+- bpftrace provides an awk-like language to the kernel bytecode, BPF.
+- BCC provides a subset of C. Provides more complex logic than bpftrace, but takes a bit more effort.
+
+Example using bpftrace to track slow vim functions, and print out any files
+that were opened during the trace. At the end, it prints a histogram of
+function timing:
+
+ #!/usr/bin/env bpftrace
+
+ BEGIN {
+ @depth = -1;
+ }
+
+ tracepoint:sched:sched_process_fork /@pidmap[args->parent_pid]/ {
+ @pidmap[args->child_pid] = 1;
+ }
+
+ tracepoint:sched:sched_process_exit /@pidmap[args->pid]/ {
+ delete(@pidmap[args->pid]);
+ }
+
+ usdt:build/bin/nvim:neovim:eval__call_func__entry {
+ @pidmap[pid] = 1;
+ @depth++;
+ @funcentry[@depth] = nsecs;
+ }
+
+ usdt:build/bin/nvim:neovim:eval__call_func__return {
+ $func = str(arg0);
+ $msecs = (nsecs - @funcentry[@depth]) / 1000000;
+
+ @time_histo = hist($msecs);
+
+ if ($msecs >= 1000) {
+ printf("%u ms for %s\n", $msecs, $func);
+ print(@files);
+ }
+
+ clear(@files);
+ delete(@funcentry[@depth]);
+ @depth--;
+ }
+
+ tracepoint:syscalls:sys_enter_open,
+ tracepoint:syscalls:sys_enter_openat {
+ if (@pidmap[pid] == 1 && @depth >= 0) {
+ @files[str(args->filename)] = count();
+ }
+ }
+
+ END {
+ clear(@depth);
+ }
+
+ $ sudo bpftrace funcslower.bt
+ 1527 ms for Slower
+ @files[/usr/lib/libstdc++.so.6]: 2
+ @files[/etc/fish/config.fish]: 2
+ <snip>
+
+ ^C
+ @time_histo:
+ [0] 71430 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|
+ [1] 346 | |
+ [2, 4) 208 | |
+ [4, 8) 91 | |
+ [8, 16) 22 | |
+ [16, 32) 85 | |
+ [32, 64) 7 | |
+ [64, 128) 0 | |
+ [128, 256) 0 | |
+ [256, 512) 6 | |
+ [512, 1K) 1 | |
+ [1K, 2K) 5 | |
+
+Debug: TUI
+----------
### TUI troubleshoot
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index b371c08d2a..0ef2776263 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -3,40 +3,39 @@
// Some of this code was adapted from 'if_py_both.h' from the original
// vim source
+#include <lauxlib.h>
+#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
-#include <limits.h>
-
-#include <lauxlib.h>
#include "nvim/api/buffer.h"
-#include "nvim/api/private/helpers.h"
#include "nvim/api/private/defs.h"
-#include "nvim/lua/executor.h"
-#include "nvim/vim.h"
+#include "nvim/api/private/helpers.h"
#include "nvim/buffer.h"
+#include "nvim/buffer_updates.h"
#include "nvim/change.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
+#include "nvim/decoration.h"
+#include "nvim/ex_cmds.h"
+#include "nvim/ex_docmd.h"
+#include "nvim/extmark.h"
+#include "nvim/fileio.h"
#include "nvim/getchar.h"
+#include "nvim/lua/executor.h"
+#include "nvim/map.h"
+#include "nvim/map_defs.h"
+#include "nvim/mark.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/misc1.h"
-#include "nvim/ex_cmds.h"
-#include "nvim/map_defs.h"
-#include "nvim/map.h"
-#include "nvim/mark.h"
-#include "nvim/ops.h"
-#include "nvim/extmark.h"
-#include "nvim/decoration.h"
-#include "nvim/fileio.h"
#include "nvim/move.h"
+#include "nvim/ops.h"
#include "nvim/syntax.h"
-#include "nvim/window.h"
#include "nvim/undo.h"
-#include "nvim/ex_docmd.h"
-#include "nvim/buffer_updates.h"
+#include "nvim/vim.h"
+#include "nvim/window.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/buffer.c.generated.h"
@@ -149,11 +148,8 @@ Integer nvim_buf_line_count(Buffer buffer, Error *err)
/// @param[out] err Error details, if any
/// @return False if attach failed (invalid parameter, or buffer isn't loaded);
/// otherwise True. TODO: LUA_API_NO_EVAL
-Boolean nvim_buf_attach(uint64_t channel_id,
- Buffer buffer,
- Boolean send_buffer,
- DictionaryOf(LuaRef) opts,
- Error *err)
+Boolean nvim_buf_attach(uint64_t channel_id, Buffer buffer, Boolean send_buffer,
+ DictionaryOf(LuaRef) opts, Error *err)
FUNC_API_SINCE(4)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -237,9 +233,7 @@ error:
/// @param[out] err Error details, if any
/// @return False if detach failed (because the buffer isn't loaded);
/// otherwise True.
-Boolean nvim_buf_detach(uint64_t channel_id,
- Buffer buffer,
- Error *err)
+Boolean nvim_buf_detach(uint64_t channel_id, Buffer buffer, Error *err)
FUNC_API_SINCE(4) FUNC_API_REMOTE_ONLY
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -252,8 +246,7 @@ Boolean nvim_buf_detach(uint64_t channel_id,
return true;
}
-void nvim__buf_redraw_range(Buffer buffer, Integer first, Integer last,
- Error *err)
+void nvim__buf_redraw_range(Buffer buffer, Integer first, Integer last, Error *err)
FUNC_API_LUA_ONLY
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -315,7 +308,7 @@ ArrayOf(String) nvim_buf_get_lines(uint64_t channel_id,
}
rv.size = (size_t)(end - start);
- rv.items = xcalloc(sizeof(Object), rv.size);
+ rv.items = xcalloc(rv.size, sizeof(Object));
if (!buf_collect_lines(buf, rv.size, start,
(channel_id != VIML_INTERNAL_CALL), &rv, err)) {
@@ -376,13 +369,8 @@ static bool check_string_array(Array arr, bool disallow_nl, Error *err)
/// @param strict_indexing Whether out-of-bounds should be an error.
/// @param replacement Array of lines to use as replacement
/// @param[out] err Error details, if any
-void nvim_buf_set_lines(uint64_t channel_id,
- Buffer buffer,
- Integer start,
- Integer end,
- Boolean strict_indexing,
- ArrayOf(String) replacement,
- Error *err)
+void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integer end,
+ Boolean strict_indexing, ArrayOf(String) replacement, Error *err)
FUNC_API_SINCE(1)
FUNC_API_CHECK_TEXTLOCK
{
@@ -554,10 +542,8 @@ end:
/// @param end_column Last column
/// @param replacement Array of lines to use as replacement
/// @param[out] err Error details, if any
-void nvim_buf_set_text(uint64_t channel_id, Buffer buffer,
- Integer start_row, Integer start_col,
- Integer end_row, Integer end_col,
- ArrayOf(String) replacement, Error *err)
+void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, Integer start_col,
+ Integer end_row, Integer end_col, ArrayOf(String) replacement, Error *err)
FUNC_API_SINCE(7)
{
FIXED_TEMP_ARRAY(scratch, 1);
@@ -617,17 +603,17 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer,
// calculate byte size of old region before it gets modified/deleted
if (start_row == end_row) {
- old_byte = (bcount_t)end_col - start_col;
+ old_byte = (bcount_t)end_col - start_col;
} else {
- const char *bufline;
- old_byte += (bcount_t)strlen(str_at_start) - start_col;
- for (int64_t i = 1; i < end_row - start_row; i++) {
- int64_t lnum = start_row + i;
+ const char *bufline;
+ old_byte += (bcount_t)strlen(str_at_start) - start_col;
+ for (int64_t i = 1; i < end_row - start_row; i++) {
+ int64_t lnum = start_row + i;
- bufline = (char *)ml_get_buf(buf, lnum, false);
- old_byte += (bcount_t)(strlen(bufline))+1;
- }
- old_byte += (bcount_t)end_col+1;
+ bufline = (char *)ml_get_buf(buf, lnum, false);
+ old_byte += (bcount_t)(strlen(bufline))+1;
+ }
+ old_byte += (bcount_t)end_col+1;
}
String first_item = replacement.items[0].data.string;
@@ -824,7 +810,7 @@ Object nvim_buf_get_var(Buffer buffer, String name, Error *err)
buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) {
- return (Object) OBJECT_INIT;
+ return (Object)OBJECT_INIT;
}
return dict_get_value(buf->b_vars, name, err);
@@ -872,8 +858,8 @@ ArrayOf(Dictionary) nvim_buf_get_keymap(Buffer buffer, String mode, Error *err)
/// @see |nvim_set_keymap()|
///
/// @param buffer Buffer handle, or 0 for current buffer
-void nvim_buf_set_keymap(Buffer buffer, String mode, String lhs, String rhs,
- Dictionary opts, Error *err)
+void nvim_buf_set_keymap(Buffer buffer, String mode, String lhs, String rhs, Dictionary opts,
+ Error *err)
FUNC_API_SINCE(6)
{
modify_keymap(buffer, false, mode, lhs, rhs, opts, err);
@@ -980,7 +966,7 @@ Object nvim_buf_get_option(Buffer buffer, String name, Error *err)
buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) {
- return (Object) OBJECT_INIT;
+ return (Object)OBJECT_INIT;
}
return get_option_from(buf, SREQ_BUF, name, err);
@@ -994,8 +980,7 @@ Object nvim_buf_get_option(Buffer buffer, String name, Error *err)
/// @param name Option name
/// @param value Option value
/// @param[out] err Error details, if any
-void nvim_buf_set_option(uint64_t channel_id, Buffer buffer,
- String name, Object value, Error *err)
+void nvim_buf_set_option(uint64_t channel_id, Buffer buffer, String name, Object value, Error *err)
FUNC_API_SINCE(1)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -1044,7 +1029,7 @@ void nvim_buf_set_name(Buffer buffer, String name, Error *err)
// Using aucmd_*: autocommands will be executed by rename_buffer
aco_save_T aco;
aucmd_prepbuf(&aco, buf);
- int ren_ret = rename_buffer((char_u *) name.data);
+ int ren_ret = rename_buffer((char_u *)name.data);
aucmd_restbuf(&aco);
if (try_end(err)) {
@@ -1105,12 +1090,11 @@ void nvim_buf_delete(Buffer buffer, Dictionary opts, Error *err)
return;
}
- int result = do_buffer(
- unload ? DOBUF_UNLOAD : DOBUF_WIPE,
- DOBUF_FIRST,
- FORWARD,
- buf->handle,
- force);
+ int result = do_buffer(unload ? DOBUF_UNLOAD : DOBUF_WIPE,
+ DOBUF_FIRST,
+ FORWARD,
+ buf->handle,
+ force);
if (result == FAIL) {
api_set_error(err, kErrorTypeException, "Failed to unload buffer.");
@@ -1213,8 +1197,7 @@ static Array extmark_to_array(ExtmarkInfo extmark, bool id, bool add_dict)
ADD(chunk, STRING_OBJ(cstr_to_string(vtc->text)));
if (vtc->hl_id > 0) {
ADD(chunk,
- STRING_OBJ(cstr_to_string(
- (const char *)syn_id2name(vtc->hl_id))));
+ STRING_OBJ(cstr_to_string((const char *)syn_id2name(vtc->hl_id))));
}
ADD(chunks, ARRAY_OBJ(chunk));
}
@@ -1232,7 +1215,7 @@ static Array extmark_to_array(ExtmarkInfo extmark, bool id, bool add_dict)
return rv;
}
-/// Returns position for a given extmark id
+/// Gets the position (0-indexed) of an extmark.
///
/// @param buffer Buffer handle, or 0 for current buffer
/// @param ns_id Namespace id from |nvim_create_namespace()|
@@ -1240,7 +1223,8 @@ static Array extmark_to_array(ExtmarkInfo extmark, bool id, bool add_dict)
/// @param opts Optional parameters. Keys:
/// - details: Whether to include the details dict
/// @param[out] err Error details, if any
-/// @return (row, col) tuple or empty list () if extmark id was absent
+/// @return 0-indexed (row, col) tuple or empty list () if extmark id was
+/// absent
ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id,
Integer id, Dictionary opts,
Error *err)
@@ -1320,18 +1304,17 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id,
///
/// @param buffer Buffer handle, or 0 for current buffer
/// @param ns_id Namespace id from |nvim_create_namespace()|
-/// @param start Start of range, given as (row, col) or valid extmark id
-/// (whose position defines the bound)
-/// @param end End of range, given as (row, col) or valid extmark id
-/// (whose position defines the bound)
+/// @param start Start of range: a 0-indexed (row, col) or valid extmark id
+/// (whose position defines the bound). |api-indexing|
+/// @param end End of range (inclusive): a 0-indexed (row, col) or valid
+/// extmark id (whose position defines the bound). |api-indexing|
/// @param opts Optional parameters. Keys:
/// - limit: Maximum number of marks to return
/// - details Whether to include the details dict
/// @param[out] err Error details, if any
/// @return List of [extmark_id, row, col] tuples in "traversal order".
-Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id,
- Object start, Object end,
- Dictionary opts, Error *err)
+Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object end, Dictionary opts,
+ Error *err)
FUNC_API_SINCE(7)
{
Array rv = ARRAY_DICT_INIT;
@@ -1424,17 +1407,27 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id,
///
/// @param buffer Buffer handle, or 0 for current buffer
/// @param ns_id Namespace id from |nvim_create_namespace()|
-/// @param line Line where to place the mark, 0-based
-/// @param col Column where to place the mark, 0-based
+/// @param line Line where to place the mark, 0-based. |api-indexing|
+/// @param col Column where to place the mark, 0-based. |api-indexing|
/// @param opts Optional parameters.
/// - id : id of the extmark to edit.
/// - end_line : ending line of the mark, 0-based inclusive.
/// - end_col : ending col of the mark, 0-based exclusive.
/// - hl_group : name of the highlight group used to highlight
/// this mark.
+/// - hl_eol : when true, for a multiline highlight covering the
+/// EOL of a line, continue the highlight for the rest
+/// of the screen line (just like for diff and
+/// cursorline highlight).
/// - virt_text : virtual text to link to this mark.
-/// - virt_text_pos : positioning of virtual text. Possible
-/// values:
+/// A list of [text, highlight] tuples, each representing a
+/// text chunk with specified highlight. `highlight` element
+/// can either be a a single highlight group, or an array of
+/// multiple highlight groups that will be stacked
+/// (highest priority last). A highlight group can be supplied
+/// either as a string or as an integer, the latter which
+/// can be obtained using |nvim_get_hl_id_by_name|.
+/// - virt_text_pos : position of virtual text. Possible values:
/// - "eol": right after eol character (default)
/// - "overlay": display over the specified column, without
/// shifting the underlying text.
@@ -1453,10 +1446,28 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id,
/// default
/// - "combine": combine with background text color
/// - "blend": blend with background text color.
-/// - hl_eol : when true, for a multiline highlight covering the
-/// EOL of a line, continue the highlight for the rest
-/// of the screen line (just like for diff and
-/// cursorline highlight).
+///
+/// - virt_lines : virtual lines to add next to this mark
+/// This should be an array over lines, where each line in
+/// turn is an array over [text, highlight] tuples. In
+/// general, buffer and window options do not affect the
+/// display of the text. In particular 'wrap'
+/// and 'linebreak' options do not take effect, so
+/// the number of extra screen lines will always match
+/// the size of the array. However the 'tabstop' buffer
+/// option is still used for hard tabs. By default lines are
+/// placed below the buffer line containing the mark.
+///
+/// Note: currently virtual lines are limited to one block
+/// per buffer. Thus setting a new mark disables any previous
+/// `virt_lines` decoration. However plugins should not rely
+/// on this behaviour, as this limitation is planned to be
+/// removed.
+///
+/// - virt_lines_above: place virtual lines above instead.
+/// - virt_lines_leftcol: Place extmarks in the leftmost
+/// column of the window, bypassing
+/// sign and number columns.
///
/// - ephemeral : for use with |nvim_set_decoration_provider|
/// callbacks. The mark will only be used for the current
@@ -1473,14 +1484,12 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id,
/// example treesitter highlighting uses a value of 100.
/// @param[out] err Error details, if any
/// @return Id of the created/updated extmark
-Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
- Integer line, Integer col,
+Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer col,
Dictionary opts, Error *err)
FUNC_API_SINCE(7)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) {
- api_set_error(err, kErrorTypeValidation, "Invalid buffer id");
return 0;
}
@@ -1500,6 +1509,10 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
bool end_right_gravity = false;
bool end_gravity_set = false;
+ VirtLines virt_lines = KV_INITIAL_VALUE;
+ bool virt_lines_above = false;
+ bool virt_lines_leftcol = false;
+
for (size_t i = 0; i < opts.size; i++) {
String k = opts.items[i].key;
Object *v = &opts.items[i].value;
@@ -1540,19 +1553,18 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
} else if (strequal("hl_group", k.data)) {
String hl_group;
switch (v->type) {
- case kObjectTypeString:
- hl_group = v->data.string;
- decor.hl_id = syn_check_group(
- (char_u *)(hl_group.data),
- (int)hl_group.size);
- break;
- case kObjectTypeInteger:
- decor.hl_id = (int)v->data.integer;
- break;
- default:
- api_set_error(err, kErrorTypeValidation,
- "hl_group is not valid.");
- goto error;
+ case kObjectTypeString:
+ hl_group = v->data.string;
+ decor.hl_id = syn_check_group((char_u *)(hl_group.data),
+ (int)hl_group.size);
+ break;
+ case kObjectTypeInteger:
+ decor.hl_id = (int)v->data.integer;
+ break;
+ default:
+ api_set_error(err, kErrorTypeValidation,
+ "hl_group is not valid.");
+ goto error;
}
} else if (strequal("virt_text", k.data)) {
if (v->type != kObjectTypeArray) {
@@ -1560,7 +1572,8 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
"virt_text is not an Array");
goto error;
}
- decor.virt_text = parse_virt_text(v->data.array, err);
+ decor.virt_text = parse_virt_text(v->data.array, err,
+ &decor.virt_text_width);
if (ERROR_SET(err)) {
goto error;
}
@@ -1597,6 +1610,36 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
if (ERROR_SET(err)) {
goto error;
}
+ } else if (strequal("virt_lines", k.data)) {
+ if (v->type != kObjectTypeArray) {
+ api_set_error(err, kErrorTypeValidation,
+ "virt_lines is not an Array");
+ goto error;
+ }
+ Array a = v->data.array;
+ for (size_t j = 0; j < a.size; j++) {
+ if (a.items[j].type != kObjectTypeArray) {
+ api_set_error(err, kErrorTypeValidation,
+ "virt_text_line item is not an Array");
+ goto error;
+ }
+ int dummig;
+ VirtText jtem = parse_virt_text(a.items[j].data.array, err, &dummig);
+ kv_push(virt_lines, jtem);
+ if (ERROR_SET(err)) {
+ goto error;
+ }
+ }
+ } else if (strequal("virt_lines_above", k.data)) {
+ virt_lines_above = api_object_to_bool(*v, "virt_lines_above", false, err);
+ if (ERROR_SET(err)) {
+ goto error;
+ }
+ } else if (strequal("virt_lines_leftcol", k.data)) {
+ virt_lines_leftcol = api_object_to_bool(*v, "virt_lines_leftcol", false, err);
+ if (ERROR_SET(err)) {
+ goto error;
+ }
} else if (strequal("hl_eol", k.data)) {
decor.hl_eol = api_object_to_bool(*v, "hl_eol", false, err);
if (ERROR_SET(err)) {
@@ -1685,8 +1728,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
if (col2 >= 0) {
if (line2 >= 0 && line2 < buf->b_ml.ml_line_count) {
- len = ephemeral ? MAXCOL : STRLEN(
- ml_get_buf(buf, (linenr_T)line2 + 1, false));
+ len = ephemeral ? MAXCOL : STRLEN(ml_get_buf(buf, (linenr_T)line2 + 1, false));
} else if (line2 == buf->b_ml.ml_line_count) {
// We are trying to add an extmark past final newline
len = 0;
@@ -1706,7 +1748,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
decor.col = 0;
for (size_t i = 0; i < kv_size(decor.virt_text); i++) {
decor.col
- += (int)mb_string2cells((char_u *)kv_A(decor.virt_text, i).text);
+ += (int)mb_string2cells((char_u *)kv_A(decor.virt_text, i).text);
}
}
@@ -1735,9 +1777,23 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id,
goto error;
}
- id = extmark_set(buf, (uint64_t)ns_id, id, (int)line, (colnr_T)col,
- line2, col2, d, right_gravity,
- end_right_gravity, kExtmarkNoUndo);
+ if (kv_size(virt_lines) && buf->b_virt_line_mark) {
+ mtpos_t pos = marktree_lookup(buf->b_marktree, buf->b_virt_line_mark, NULL);
+ clear_virt_lines(buf, pos.row); // handles pos.row == -1
+ }
+
+ uint64_t mark = extmark_set(buf, (uint64_t)ns_id, &id, (int)line, (colnr_T)col,
+ line2, col2, d, right_gravity,
+ end_right_gravity, kExtmarkNoUndo);
+
+ if (kv_size(virt_lines)) {
+ buf->b_virt_lines = virt_lines;
+ buf->b_virt_line_mark = mark;
+ buf->b_virt_line_pos = -1;
+ buf->b_virt_line_above = virt_lines_above;
+ buf->b_virt_line_leftcol = virt_lines_leftcol;
+ redraw_buf_line_later(buf, MIN(buf->b_ml.ml_line_count, line+1+(virt_lines_above?0:1)));
+ }
}
return (Integer)id;
@@ -1754,10 +1810,7 @@ error:
/// @param id Extmark id
/// @param[out] err Error details, if any
/// @return true if the extmark was found, else false
-Boolean nvim_buf_del_extmark(Buffer buffer,
- Integer ns_id,
- Integer id,
- Error *err)
+Boolean nvim_buf_del_extmark(Buffer buffer, Integer ns_id, Integer id, Error *err)
FUNC_API_SINCE(7)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -1803,13 +1856,8 @@ Boolean nvim_buf_del_extmark(Buffer buffer,
/// or -1 to highlight to end of line
/// @param[out] err Error details, if any
/// @return The ns_id that was used
-Integer nvim_buf_add_highlight(Buffer buffer,
- Integer ns_id,
- String hl_group,
- Integer line,
- Integer col_start,
- Integer col_end,
- Error *err)
+Integer nvim_buf_add_highlight(Buffer buffer, Integer ns_id, String hl_group, Integer line,
+ Integer col_start, Integer col_end, Error *err)
FUNC_API_SINCE(1)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@@ -1849,7 +1897,7 @@ Integer nvim_buf_add_highlight(Buffer buffer,
end_line++;
}
- extmark_set(buf, ns, 0,
+ extmark_set(buf, ns, NULL,
(int)line, (colnr_T)col_start,
end_line, (colnr_T)col_end,
decor_hl(hl_id), true, false, kExtmarkNoUndo);
@@ -1868,10 +1916,7 @@ Integer nvim_buf_add_highlight(Buffer buffer,
/// @param line_end End of range of lines to clear (exclusive) or -1 to clear
/// to end of buffer.
/// @param[out] err Error details, if any
-void nvim_buf_clear_namespace(Buffer buffer,
- Integer ns_id,
- Integer line_start,
- Integer line_end,
+void nvim_buf_clear_namespace(Buffer buffer, Integer ns_id, Integer line_start, Integer line_end,
Error *err)
FUNC_API_SINCE(5)
{
@@ -1892,80 +1937,6 @@ void nvim_buf_clear_namespace(Buffer buffer,
(int)line_end-1, MAXCOL);
}
-/// Set the virtual text (annotation) for a buffer line.
-///
-/// By default (and currently the only option) the text will be placed after
-/// the buffer text. Virtual text will never cause reflow, rather virtual
-/// text will be truncated at the end of the screen line. The virtual text will
-/// begin one cell (|lcs-eol| or space) after the ordinary text.
-///
-/// Namespaces are used to support batch deletion/updating of virtual text.
-/// To create a namespace, use |nvim_create_namespace()|. Virtual text is
-/// cleared using |nvim_buf_clear_namespace()|. The same `ns_id` can be used for
-/// both virtual text and highlights added by |nvim_buf_add_highlight()|, both
-/// can then be cleared with a single call to |nvim_buf_clear_namespace()|. If
-/// the virtual text never will be cleared by an API call, pass `ns_id = -1`.
-///
-/// As a shorthand, `ns_id = 0` can be used to create a new namespace for the
-/// virtual text, the allocated id is then returned.
-///
-/// @param buffer Buffer handle, or 0 for current buffer
-/// @param ns_id Namespace to use or 0 to create a namespace,
-/// or -1 for a ungrouped annotation
-/// @param line Line to annotate with virtual text (zero-indexed)
-/// @param chunks A list of [text, hl_group] arrays, each representing a
-/// text chunk with specified highlight. `hl_group` element
-/// can be omitted for no highlight.
-/// @param opts Optional parameters. Currently not used.
-/// @param[out] err Error details, if any
-/// @return The ns_id that was used
-Integer nvim_buf_set_virtual_text(Buffer buffer,
- Integer src_id,
- Integer line,
- Array chunks,
- Dictionary opts,
- Error *err)
- FUNC_API_SINCE(5)
-{
- buf_T *buf = find_buffer_by_handle(buffer, err);
- if (!buf) {
- return 0;
- }
-
- if (line < 0 || line >= MAXLNUM) {
- api_set_error(err, kErrorTypeValidation, "Line number outside range");
- return 0;
- }
-
- if (opts.size > 0) {
- api_set_error(err, kErrorTypeValidation, "opts dict isn't empty");
- return 0;
- }
-
- uint64_t ns_id = src2ns(&src_id);
-
- VirtText virt_text = parse_virt_text(chunks, err);
- if (ERROR_SET(err)) {
- return 0;
- }
-
-
- VirtText *existing = decor_find_virttext(buf, (int)line, ns_id);
-
- if (existing) {
- clear_virttext(existing);
- *existing = virt_text;
- return src_id;
- }
-
- Decoration *decor = xcalloc(1, sizeof(*decor));
- decor->virt_text = virt_text;
-
- extmark_set(buf, ns_id, 0, (int)line, 0, -1, -1, decor, true,
- false, kExtmarkNoUndo);
- return src_id;
-}
-
/// 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 3989386bb9..332fc0ba96 100644
--- a/src/nvim/api/deprecated.c
+++ b/src/nvim/api/deprecated.c
@@ -1,16 +1,17 @@
// 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 <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
-#include <limits.h>
-#include "nvim/api/deprecated.h"
#include "nvim/api/buffer.h"
-#include "nvim/api/vim.h"
-#include "nvim/api/private/helpers.h"
+#include "nvim/api/deprecated.h"
#include "nvim/api/private/defs.h"
+#include "nvim/api/private/helpers.h"
+#include "nvim/api/vim.h"
+#include "nvim/extmark.h"
#include "nvim/lua/executor.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -68,10 +69,7 @@ Integer nvim_buf_get_number(Buffer buffer, Error *err)
/// @param line_end End of range of lines to clear (exclusive) or -1 to clear
/// to end of file.
/// @param[out] err Error details, if any
-void nvim_buf_clear_highlight(Buffer buffer,
- Integer ns_id,
- Integer line_start,
- Integer line_end,
+void nvim_buf_clear_highlight(Buffer buffer, Integer ns_id, Integer line_start, Integer line_end,
Error *err)
FUNC_API_SINCE(1)
FUNC_API_DEPRECATED_SINCE(7)
@@ -80,6 +78,83 @@ void nvim_buf_clear_highlight(Buffer buffer,
}
+/// Set the virtual text (annotation) for a buffer line.
+///
+/// @deprecated use nvim_buf_set_extmark to use full virtual text
+/// functionality.
+///
+/// The text will be placed after the buffer text. Virtual text will never
+/// cause reflow, rather virtual text will be truncated at the end of the screen
+/// line. The virtual text will begin one cell (|lcs-eol| or space) after the
+/// ordinary text.
+///
+/// Namespaces are used to support batch deletion/updating of virtual text.
+/// To create a namespace, use |nvim_create_namespace()|. Virtual text is
+/// cleared using |nvim_buf_clear_namespace()|. The same `ns_id` can be used for
+/// both virtual text and highlights added by |nvim_buf_add_highlight()|, both
+/// can then be cleared with a single call to |nvim_buf_clear_namespace()|. If
+/// the virtual text never will be cleared by an API call, pass `ns_id = -1`.
+///
+/// As a shorthand, `ns_id = 0` can be used to create a new namespace for the
+/// virtual text, the allocated id is then returned.
+///
+/// @param buffer Buffer handle, or 0 for current buffer
+/// @param ns_id Namespace to use or 0 to create a namespace,
+/// or -1 for a ungrouped annotation
+/// @param line Line to annotate with virtual text (zero-indexed)
+/// @param chunks A list of [text, hl_group] arrays, each representing a
+/// text chunk with specified highlight. `hl_group` element
+/// can be omitted for no highlight.
+/// @param opts Optional parameters. Currently not used.
+/// @param[out] err Error details, if any
+/// @return The ns_id that was used
+Integer nvim_buf_set_virtual_text(Buffer buffer, Integer src_id, Integer line, Array chunks,
+ Dictionary opts, Error *err)
+ FUNC_API_SINCE(5)
+ FUNC_API_DEPRECATED_SINCE(8)
+{
+ buf_T *buf = find_buffer_by_handle(buffer, err);
+ if (!buf) {
+ return 0;
+ }
+
+ if (line < 0 || line >= MAXLNUM) {
+ api_set_error(err, kErrorTypeValidation, "Line number outside range");
+ return 0;
+ }
+
+ if (opts.size > 0) {
+ api_set_error(err, kErrorTypeValidation, "opts dict isn't empty");
+ return 0;
+ }
+
+ uint64_t ns_id = src2ns(&src_id);
+ int width;
+
+ VirtText virt_text = parse_virt_text(chunks, err, &width);
+ if (ERROR_SET(err)) {
+ return 0;
+ }
+
+
+ Decoration *existing = decor_find_virttext(buf, (int)line, ns_id);
+
+ if (existing) {
+ clear_virttext(&existing->virt_text);
+ existing->virt_text = virt_text;
+ existing->virt_text_width = width;
+ return src_id;
+ }
+
+ Decoration *decor = xcalloc(1, sizeof(*decor));
+ decor->virt_text = virt_text;
+ decor->virt_text_width = width;
+
+ extmark_set(buf, ns_id, NULL, (int)line, 0, -1, -1, decor, true,
+ false, kExtmarkNoUndo);
+ return src_id;
+}
+
/// Inserts a sequence of lines to a buffer at a certain index
///
/// @deprecated use nvim_buf_set_lines(buffer, lnum, lnum, true, lines)
@@ -89,10 +164,7 @@ void nvim_buf_clear_highlight(Buffer buffer,
/// the end of the buffer.
/// @param lines Array of lines
/// @param[out] err Error details, if any
-void buffer_insert(Buffer buffer,
- Integer lnum,
- ArrayOf(String) lines,
- Error *err)
+void buffer_insert(Buffer buffer, Integer lnum, ArrayOf(String) lines, Error *err)
{
// "lnum" will be the index of the line after inserting,
// no matter if it is negative or not
@@ -186,7 +258,7 @@ ArrayOf(String) buffer_get_line_slice(Buffer buffer,
{
start = convert_index(start) + !include_start;
end = convert_index(end) + include_end;
- return nvim_buf_get_lines(0, buffer, start , end, false, err);
+ return nvim_buf_get_lines(0, buffer, start, end, false, err);
}
/// Replaces a line range on the buffer
@@ -204,13 +276,8 @@ ArrayOf(String) buffer_get_line_slice(Buffer buffer,
/// @param replacement Array of lines to use as replacement (0-length
// array will delete the line range)
/// @param[out] err Error details, if any
-void buffer_set_line_slice(Buffer buffer,
- Integer start,
- Integer end,
- Boolean include_start,
- Boolean include_end,
- ArrayOf(String) replacement,
- Error *err)
+void buffer_set_line_slice(Buffer buffer, Integer start, Integer end, Boolean include_start,
+ Boolean include_end, ArrayOf(String) replacement, Error *err)
{
start = convert_index(start) + !include_start;
end = convert_index(end) + include_end;
diff --git a/src/nvim/api/private/dispatch.c b/src/nvim/api/private/dispatch.c
index eae4581f42..5e93ccce17 100644
--- a/src/nvim/api/private/dispatch.c
+++ b/src/nvim/api/private/dispatch.c
@@ -1,43 +1,40 @@
// 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 <inttypes.h>
-#include <stdbool.h>
#include <assert.h>
+#include <inttypes.h>
#include <msgpack.h>
+#include <stdbool.h>
-#include "nvim/map.h"
-#include "nvim/log.h"
-#include "nvim/vim.h"
-#include "nvim/msgpack_rpc/helpers.h"
+#include "nvim/api/buffer.h"
+#include "nvim/api/deprecated.h"
+#include "nvim/api/private/defs.h"
#include "nvim/api/private/dispatch.h"
#include "nvim/api/private/helpers.h"
-#include "nvim/api/private/defs.h"
-
-#include "nvim/api/buffer.h"
#include "nvim/api/tabpage.h"
#include "nvim/api/ui.h"
#include "nvim/api/vim.h"
#include "nvim/api/window.h"
-#include "nvim/api/deprecated.h"
+#include "nvim/log.h"
+#include "nvim/map.h"
+#include "nvim/msgpack_rpc/helpers.h"
+#include "nvim/vim.h"
-static Map(String, MsgpackRpcRequestHandler) *methods = NULL;
+static Map(String, MsgpackRpcRequestHandler) methods = MAP_INIT;
-static void msgpack_rpc_add_method_handler(String method,
- MsgpackRpcRequestHandler handler)
+static void msgpack_rpc_add_method_handler(String method, MsgpackRpcRequestHandler handler)
{
- map_put(String, MsgpackRpcRequestHandler)(methods, method, handler);
+ map_put(String, MsgpackRpcRequestHandler)(&methods, method, handler);
}
/// @param name API method name
/// @param name_len name size (includes terminating NUL)
-MsgpackRpcRequestHandler msgpack_rpc_get_handler_for(const char *name,
- size_t name_len,
+MsgpackRpcRequestHandler msgpack_rpc_get_handler_for(const char *name, size_t name_len,
Error *error)
{
String m = { .data = (char *)name, .size = name_len };
MsgpackRpcRequestHandler rv =
- map_get(String, MsgpackRpcRequestHandler)(methods, m);
+ map_get(String, MsgpackRpcRequestHandler)(&methods, m);
if (!rv.fn) {
api_set_error(error, kErrorTypeException, "Invalid method: %.*s",
@@ -48,5 +45,5 @@ MsgpackRpcRequestHandler msgpack_rpc_get_handler_for(const char *name,
}
#ifdef INCLUDE_GENERATED_DECLARATIONS
-#include "api/private/dispatch_wrappers.generated.h"
+# include "api/private/dispatch_wrappers.generated.h"
#endif
diff --git a/src/nvim/api/private/handle.c b/src/nvim/api/private/handle.c
deleted file mode 100644
index eb96192af2..0000000000
--- a/src/nvim/api/private/handle.c
+++ /dev/null
@@ -1,40 +0,0 @@
-// 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 <assert.h>
-#include <stdint.h>
-
-#include "nvim/vim.h"
-#include "nvim/map.h"
-#include "nvim/api/private/handle.h"
-
-#define HANDLE_INIT(name) name##_handles = pmap_new(handle_T)()
-
-#define HANDLE_IMPL(type, name) \
- static PMap(handle_T) *name##_handles = NULL; /* NOLINT */ \
- \
- type *handle_get_##name(handle_T handle) \
- { \
- return pmap_get(handle_T)(name##_handles, handle); \
- } \
- \
- void handle_register_##name(type *name) \
- { \
- pmap_put(handle_T)(name##_handles, name->handle, name); \
- } \
- \
- void handle_unregister_##name(type *name) \
- { \
- pmap_del(handle_T)(name##_handles, name->handle); \
- }
-
-HANDLE_IMPL(buf_T, buffer)
-HANDLE_IMPL(win_T, window)
-HANDLE_IMPL(tabpage_T, tabpage)
-
-void handle_init(void)
-{
- HANDLE_INIT(buffer);
- HANDLE_INIT(window);
- HANDLE_INIT(tabpage);
-}
diff --git a/src/nvim/api/private/handle.h b/src/nvim/api/private/handle.h
deleted file mode 100644
index 26e9dc3314..0000000000
--- a/src/nvim/api/private/handle.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef NVIM_API_PRIVATE_HANDLE_H
-#define NVIM_API_PRIVATE_HANDLE_H
-
-#include "nvim/vim.h"
-#include "nvim/buffer_defs.h"
-#include "nvim/api/private/defs.h"
-
-#define HANDLE_DECLS(type, name) \
- type *handle_get_##name(handle_T handle); \
- void handle_register_##name(type *name); \
- void handle_unregister_##name(type *name);
-
-// handle_get_buffer handle_register_buffer, handle_unregister_buffer
-HANDLE_DECLS(buf_T, buffer)
-// handle_get_window handle_register_window, handle_unregister_window
-HANDLE_DECLS(win_T, window)
-// handle_get_tabpage handle_register_tabpage, handle_unregister_tabpage
-HANDLE_DECLS(tabpage_T, tabpage)
-
-void handle_init(void);
-
-
-#endif // NVIM_API_PRIVATE_HANDLE_H
-
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index c7d261ba18..193f1dd572 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -7,43 +7,42 @@
#include <stdlib.h>
#include <string.h>
-#include "nvim/api/private/helpers.h"
#include "nvim/api/private/defs.h"
-#include "nvim/api/private/handle.h"
+#include "nvim/api/private/helpers.h"
#include "nvim/api/vim.h"
-#include "nvim/msgpack_rpc/helpers.h"
-#include "nvim/lua/executor.h"
#include "nvim/ascii.h"
#include "nvim/assert.h"
-#include "nvim/charset.h"
-#include "nvim/syntax.h"
-#include "nvim/vim.h"
#include "nvim/buffer.h"
-#include "nvim/window.h"
-#include "nvim/memline.h"
-#include "nvim/memory.h"
+#include "nvim/charset.h"
+#include "nvim/decoration.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
-#include "nvim/map_defs.h"
-#include "nvim/map.h"
#include "nvim/extmark.h"
-#include "nvim/decoration.h"
+#include "nvim/fileio.h"
+#include "nvim/getchar.h"
+#include "nvim/lib/kvec.h"
+#include "nvim/lua/executor.h"
+#include "nvim/map.h"
+#include "nvim/map_defs.h"
+#include "nvim/memline.h"
+#include "nvim/memory.h"
+#include "nvim/msgpack_rpc/helpers.h"
#include "nvim/option.h"
#include "nvim/option_defs.h"
-#include "nvim/version.h"
-#include "nvim/lib/kvec.h"
-#include "nvim/getchar.h"
-#include "nvim/fileio.h"
+#include "nvim/syntax.h"
#include "nvim/ui.h"
+#include "nvim/version.h"
+#include "nvim/vim.h"
+#include "nvim/window.h"
/// Helper structure for vim_to_object
typedef struct {
- kvec_t(Object) stack; ///< Object stack.
+ kvec_withinit_t(Object, 2) stack; ///< Object stack.
} EncodedData;
#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "api/private/helpers.c.generated.h"
# include "api/private/funcs_metadata.generated.h"
+# include "api/private/helpers.c.generated.h"
# include "api/private/ui_events_metadata.generated.h"
#endif
@@ -211,8 +210,7 @@ dictitem_T *dict_check_writable(dict_T *dict, String key, bool del, Error *err)
/// @param retval If true the old value will be converted and returned.
/// @param[out] err Details of an error that may have occurred
/// @return The old value if `retval` is true and the key was present, else NIL
-Object dict_set_var(dict_T *dict, String key, Object value, bool del,
- bool retval, Error *err)
+Object dict_set_var(dict_T *dict, String key, Object value, bool del, bool retval, Error *err)
{
Object rv = OBJECT_INIT;
dictitem_T *di = dict_check_writable(dict, key, del, err);
@@ -327,8 +325,7 @@ Object get_option_from(void *from, int type, String name, Error *err)
/// @param type One of `SREQ_GLOBAL`, `SREQ_WIN` or `SREQ_BUF`
/// @param name The option name
/// @param[out] err Details of an error that may have occurred
-void set_option_to(uint64_t channel_id, void *to, int type,
- String name, Object value, Error *err)
+void set_option_to(uint64_t channel_id, void *to, int type, String name, Object value, Error *err)
{
if (name.size == 0) {
api_set_error(err, kErrorTypeValidation, "Empty option name");
@@ -419,57 +416,63 @@ void set_option_to(uint64_t channel_id, void *to, int type,
#define TYPVAL_ENCODE_ALLOW_SPECIALS false
#define TYPVAL_ENCODE_CONV_NIL(tv) \
- kv_push(edata->stack, NIL)
+ kvi_push(edata->stack, NIL)
#define TYPVAL_ENCODE_CONV_BOOL(tv, num) \
- kv_push(edata->stack, BOOLEAN_OBJ((Boolean)(num)))
+ kvi_push(edata->stack, BOOLEAN_OBJ((Boolean)(num)))
#define TYPVAL_ENCODE_CONV_NUMBER(tv, num) \
- kv_push(edata->stack, INTEGER_OBJ((Integer)(num)))
+ kvi_push(edata->stack, INTEGER_OBJ((Integer)(num)))
#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER TYPVAL_ENCODE_CONV_NUMBER
#define TYPVAL_ENCODE_CONV_FLOAT(tv, flt) \
- kv_push(edata->stack, FLOAT_OBJ((Float)(flt)))
+ kvi_push(edata->stack, FLOAT_OBJ((Float)(flt)))
#define TYPVAL_ENCODE_CONV_STRING(tv, str, len) \
- do { \
- const size_t len_ = (size_t)(len); \
- const char *const str_ = (const char *)(str); \
- assert(len_ == 0 || str_ != NULL); \
- kv_push(edata->stack, STRING_OBJ(((String) { \
- .data = xmemdupz((len_?str_:""), len_), \
- .size = len_ \
- }))); \
- } while (0)
+ do { \
+ const size_t len_ = (size_t)(len); \
+ const char *const str_ = (const char *)(str); \
+ assert(len_ == 0 || str_ != NULL); \
+ kvi_push(edata->stack, STRING_OBJ(cbuf_to_string((len_?str_:""), len_))); \
+ } while (0)
#define TYPVAL_ENCODE_CONV_STR_STRING TYPVAL_ENCODE_CONV_STRING
#define TYPVAL_ENCODE_CONV_EXT_STRING(tv, str, len, type) \
- TYPVAL_ENCODE_CONV_NIL(tv)
+ TYPVAL_ENCODE_CONV_NIL(tv)
+
+#define TYPVAL_ENCODE_CONV_BLOB(tv, blob, len) \
+ do { \
+ const size_t len_ = (size_t)(len); \
+ const blob_T *const blob_ = (blob); \
+ kvi_push(edata->stack, STRING_OBJ(((String) { \
+ .data = len_ != 0 ? xmemdup(blob_->bv_ga.ga_data, len_) : NULL, \
+ .size = len_ \
+ }))); \
+ } while (0)
#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \
- do { \
- TYPVAL_ENCODE_CONV_NIL(tv); \
- goto typval_encode_stop_converting_one_item; \
- } while (0)
+ do { \
+ TYPVAL_ENCODE_CONV_NIL(tv); \
+ goto typval_encode_stop_converting_one_item; \
+ } while (0)
#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(tv, len)
#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(tv, len)
#define TYPVAL_ENCODE_CONV_FUNC_END(tv)
#define TYPVAL_ENCODE_CONV_EMPTY_LIST(tv) \
- kv_push(edata->stack, ARRAY_OBJ(((Array) { .capacity = 0, .size = 0 })))
+ kvi_push(edata->stack, ARRAY_OBJ(((Array) { .capacity = 0, .size = 0 })))
#define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \
- kv_push(edata->stack, \
- DICTIONARY_OBJ(((Dictionary) { .capacity = 0, .size = 0 })))
+ kvi_push(edata->stack, \
+ DICTIONARY_OBJ(((Dictionary) { .capacity = 0, .size = 0 })))
-static inline void typval_encode_list_start(EncodedData *const edata,
- const size_t len)
+static inline void typval_encode_list_start(EncodedData *const edata, const size_t len)
FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL
{
- kv_push(edata->stack, ARRAY_OBJ(((Array) {
+ kvi_push(edata->stack, ARRAY_OBJ(((Array) {
.capacity = len,
.size = 0,
.items = xmalloc(len * sizeof(*((Object)OBJECT_INIT).data.array.items)),
@@ -477,7 +480,7 @@ static inline void typval_encode_list_start(EncodedData *const edata,
}
#define TYPVAL_ENCODE_CONV_LIST_START(tv, len) \
- typval_encode_list_start(edata, (size_t)(len))
+ typval_encode_list_start(edata, (size_t)(len))
#define TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START(tv, mpsv)
@@ -492,7 +495,7 @@ static inline void typval_encode_between_list_items(EncodedData *const edata)
}
#define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(tv) \
- typval_encode_between_list_items(edata)
+ typval_encode_between_list_items(edata)
static inline void typval_encode_list_end(EncodedData *const edata)
FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL
@@ -505,22 +508,21 @@ static inline void typval_encode_list_end(EncodedData *const edata)
}
#define TYPVAL_ENCODE_CONV_LIST_END(tv) \
- typval_encode_list_end(edata)
+ typval_encode_list_end(edata)
-static inline void typval_encode_dict_start(EncodedData *const edata,
- const size_t len)
+static inline void typval_encode_dict_start(EncodedData *const edata, const size_t len)
FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL
{
- kv_push(edata->stack, DICTIONARY_OBJ(((Dictionary) {
+ kvi_push(edata->stack, DICTIONARY_OBJ(((Dictionary) {
.capacity = len,
.size = 0,
.items = xmalloc(len * sizeof(
- *((Object)OBJECT_INIT).data.dictionary.items)),
+ *((Object)OBJECT_INIT).data.dictionary.items)),
})));
}
#define TYPVAL_ENCODE_CONV_DICT_START(tv, dict, len) \
- typval_encode_dict_start(edata, (size_t)(len))
+ typval_encode_dict_start(edata, (size_t)(len))
#define TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START(tv, dict, mpsv)
@@ -535,16 +537,16 @@ static inline void typval_encode_after_key(EncodedData *const edata)
assert(dict->data.dictionary.size < dict->data.dictionary.capacity);
if (key.type == kObjectTypeString) {
dict->data.dictionary.items[dict->data.dictionary.size].key
- = key.data.string;
+ = key.data.string;
} else {
api_free_object(key);
dict->data.dictionary.items[dict->data.dictionary.size].key
- = STATIC_CSTR_TO_STRING("__INVALID_KEY__");
+ = STATIC_CSTR_TO_STRING("__INVALID_KEY__");
}
}
#define TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(tv, dict) \
- typval_encode_after_key(edata)
+ typval_encode_after_key(edata)
static inline void typval_encode_between_dict_items(EncodedData *const edata)
FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL
@@ -557,7 +559,7 @@ static inline void typval_encode_between_dict_items(EncodedData *const edata)
}
#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(tv, dict) \
- typval_encode_between_dict_items(edata)
+ typval_encode_between_dict_items(edata)
static inline void typval_encode_dict_end(EncodedData *const edata)
FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL
@@ -570,10 +572,10 @@ static inline void typval_encode_dict_end(EncodedData *const edata)
}
#define TYPVAL_ENCODE_CONV_DICT_END(tv, dict) \
- typval_encode_dict_end(edata)
+ typval_encode_dict_end(edata)
#define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) \
- TYPVAL_ENCODE_CONV_NIL(val)
+ TYPVAL_ENCODE_CONV_NIL(val)
#define TYPVAL_ENCODE_SCOPE static
#define TYPVAL_ENCODE_NAME object
@@ -588,6 +590,7 @@ static inline void typval_encode_dict_end(EncodedData *const edata)
#undef TYPVAL_ENCODE_CONV_STRING
#undef TYPVAL_ENCODE_CONV_STR_STRING
#undef TYPVAL_ENCODE_CONV_EXT_STRING
+#undef TYPVAL_ENCODE_CONV_BLOB
#undef TYPVAL_ENCODE_CONV_NUMBER
#undef TYPVAL_ENCODE_CONV_FLOAT
#undef TYPVAL_ENCODE_CONV_FUNC_START
@@ -619,14 +622,15 @@ static inline void typval_encode_dict_end(EncodedData *const edata)
/// @return The converted value
Object vim_to_object(typval_T *obj)
{
- EncodedData edata = { .stack = KV_INITIAL_VALUE };
+ EncodedData edata;
+ kvi_init(edata.stack);
const int evo_ret = encode_vim_to_object(&edata, obj,
"vim_to_object argument");
(void)evo_ret;
assert(evo_ret == OK);
Object ret = kv_A(edata.stack, 0);
assert(kv_size(edata.stack) == 1);
- kv_destroy(edata.stack);
+ kvi_destroy(edata.stack);
return ret;
}
@@ -700,15 +704,15 @@ String cchar_to_string(char c)
/// empty String is returned
String cstr_to_string(const char *str)
{
- if (str == NULL) {
- return (String)STRING_INIT;
- }
+ if (str == NULL) {
+ return (String)STRING_INIT;
+ }
- size_t len = strlen(str);
- return (String){
- .data = xmemdupz(str, len),
- .size = len,
- };
+ size_t len = strlen(str);
+ return (String){
+ .data = xmemdupz(str, len),
+ .size = len,
+ };
}
/// Copies buffer to an allocated String.
@@ -809,8 +813,8 @@ Array string_to_array(const String input, bool crlf)
/// @param buffer Buffer handle for a specific buffer, or 0 for the current
/// buffer, or -1 to signify global behavior ("all buffers")
/// @param is_unmap When true, removes the mapping that matches {lhs}.
-void modify_keymap(Buffer buffer, bool is_unmap, String mode, String lhs,
- String rhs, Dictionary opts, Error *err)
+void modify_keymap(Buffer buffer, bool is_unmap, String mode, String lhs, String rhs,
+ Dictionary opts, Error *err)
{
char *err_msg = NULL; // the error message to report, if any
char *err_arg = NULL; // argument for the error message format string
@@ -908,21 +912,21 @@ void modify_keymap(Buffer buffer, bool is_unmap, String mode, String lhs,
}
switch (buf_do_map(maptype_val, &parsed_args, mode_val, 0, target_buf)) {
- case 0:
- break;
- case 1:
- api_set_error(err, kErrorTypeException, (char *)e_invarg, 0);
- goto fail_and_free;
- case 2:
- api_set_error(err, kErrorTypeException, (char *)e_nomap, 0);
- goto fail_and_free;
- case 5:
- api_set_error(err, kErrorTypeException,
- "E227: mapping already exists for %s", parsed_args.lhs);
- goto fail_and_free;
- default:
- assert(false && "Unrecognized return code!");
- goto fail_and_free;
+ case 0:
+ break;
+ case 1:
+ api_set_error(err, kErrorTypeException, (char *)e_invarg, 0);
+ goto fail_and_free;
+ case 2:
+ api_set_error(err, kErrorTypeException, (char *)e_nomap, 0);
+ goto fail_and_free;
+ case 5:
+ api_set_error(err, kErrorTypeException,
+ "E227: mapping already exists for %s", parsed_args.lhs);
+ goto fail_and_free;
+ default:
+ assert(false && "Unrecognized return code!");
+ goto fail_and_free;
} // switch
xfree(lhs_buf);
@@ -978,44 +982,44 @@ Integer parse_keymap_opts(Dictionary opts, MapArguments *out, Error *err)
bool was_valid_opt = false;
switch (optname[0]) {
- // note: strncmp up to and including the null terminator, so that
- // "nowaitFoobar" won't match against "nowait"
-
- // don't recognize 'buffer' as a key; user shouldn't provide <buffer>
- // when calling nvim_set_keymap or nvim_buf_set_keymap, since it can be
- // inferred from which function they called
- case 'n':
- if (STRNCMP(optname, "noremap", 8) == 0) {
- was_valid_opt = true;
- out->noremap = key_and_val->value.data.boolean;
- } else if (STRNCMP(optname, "nowait", 7) == 0) {
- was_valid_opt = true;
- out->nowait = key_and_val->value.data.boolean;
- }
- break;
- case 's':
- if (STRNCMP(optname, "silent", 7) == 0) {
- was_valid_opt = true;
- out->silent = key_and_val->value.data.boolean;
- } else if (STRNCMP(optname, "script", 7) == 0) {
- was_valid_opt = true;
- out->script = key_and_val->value.data.boolean;
- }
- break;
- case 'e':
- if (STRNCMP(optname, "expr", 5) == 0) {
- was_valid_opt = true;
- out->expr = key_and_val->value.data.boolean;
- }
- break;
- case 'u':
- if (STRNCMP(optname, "unique", 7) == 0) {
- was_valid_opt = true;
- out->unique = key_and_val->value.data.boolean;
- }
- break;
- default:
- break;
+ // note: strncmp up to and including the null terminator, so that
+ // "nowaitFoobar" won't match against "nowait"
+
+ // don't recognize 'buffer' as a key; user shouldn't provide <buffer>
+ // when calling nvim_set_keymap or nvim_buf_set_keymap, since it can be
+ // inferred from which function they called
+ case 'n':
+ if (STRNCMP(optname, "noremap", 8) == 0) {
+ was_valid_opt = true;
+ out->noremap = key_and_val->value.data.boolean;
+ } else if (STRNCMP(optname, "nowait", 7) == 0) {
+ was_valid_opt = true;
+ out->nowait = key_and_val->value.data.boolean;
+ }
+ break;
+ case 's':
+ if (STRNCMP(optname, "silent", 7) == 0) {
+ was_valid_opt = true;
+ out->silent = key_and_val->value.data.boolean;
+ } else if (STRNCMP(optname, "script", 7) == 0) {
+ was_valid_opt = true;
+ out->script = key_and_val->value.data.boolean;
+ }
+ break;
+ case 'e':
+ if (STRNCMP(optname, "expr", 5) == 0) {
+ was_valid_opt = true;
+ out->expr = key_and_val->value.data.boolean;
+ }
+ break;
+ case 'u':
+ if (STRNCMP(optname, "unique", 7) == 0) {
+ was_valid_opt = true;
+ out->unique = key_and_val->value.data.boolean;
+ }
+ break;
+ default:
+ break;
} // switch
if (!was_valid_opt) {
err_msg = "Invalid key: %s";
@@ -1042,8 +1046,7 @@ fail_with_message:
/// @param[out] l Lines are copied here
/// @param err[out] Error, if any
/// @return true unless `err` was set
-bool buf_collect_lines(buf_T *buf, size_t n, int64_t start, bool replace_nl,
- Array *l, Error *err)
+bool buf_collect_lines(buf_T *buf, size_t n, int64_t start, bool replace_nl, Array *l, Error *err)
{
for (size_t i = 0; i < n; i++) {
int64_t lnum = start + (int64_t)i;
@@ -1081,96 +1084,96 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err)
tv->v_lock = VAR_UNLOCKED;
switch (obj.type) {
- case kObjectTypeNil:
- tv->v_type = VAR_SPECIAL;
- tv->vval.v_special = kSpecialVarNull;
- break;
-
- case kObjectTypeBoolean:
- tv->v_type = VAR_BOOL;
- tv->vval.v_bool = obj.data.boolean? kBoolVarTrue: kBoolVarFalse;
- break;
-
- case kObjectTypeBuffer:
- case kObjectTypeWindow:
- case kObjectTypeTabpage:
- case kObjectTypeInteger:
- STATIC_ASSERT(sizeof(obj.data.integer) <= sizeof(varnumber_T),
- "Integer size must be <= VimL number size");
- tv->v_type = VAR_NUMBER;
- tv->vval.v_number = (varnumber_T)obj.data.integer;
- break;
-
- case kObjectTypeFloat:
- tv->v_type = VAR_FLOAT;
- tv->vval.v_float = obj.data.floating;
- break;
-
- case kObjectTypeString:
- tv->v_type = VAR_STRING;
- if (obj.data.string.data == NULL) {
- tv->vval.v_string = NULL;
- } else {
- tv->vval.v_string = xmemdupz(obj.data.string.data,
- obj.data.string.size);
- }
- break;
-
- case kObjectTypeArray: {
- list_T *const list = tv_list_alloc((ptrdiff_t)obj.data.array.size);
+ case kObjectTypeNil:
+ tv->v_type = VAR_SPECIAL;
+ tv->vval.v_special = kSpecialVarNull;
+ break;
+
+ case kObjectTypeBoolean:
+ tv->v_type = VAR_BOOL;
+ tv->vval.v_bool = obj.data.boolean? kBoolVarTrue: kBoolVarFalse;
+ break;
+
+ case kObjectTypeBuffer:
+ case kObjectTypeWindow:
+ case kObjectTypeTabpage:
+ case kObjectTypeInteger:
+ STATIC_ASSERT(sizeof(obj.data.integer) <= sizeof(varnumber_T),
+ "Integer size must be <= VimL number size");
+ tv->v_type = VAR_NUMBER;
+ tv->vval.v_number = (varnumber_T)obj.data.integer;
+ break;
+
+ case kObjectTypeFloat:
+ tv->v_type = VAR_FLOAT;
+ tv->vval.v_float = obj.data.floating;
+ break;
+
+ case kObjectTypeString:
+ tv->v_type = VAR_STRING;
+ if (obj.data.string.data == NULL) {
+ tv->vval.v_string = NULL;
+ } else {
+ tv->vval.v_string = xmemdupz(obj.data.string.data,
+ obj.data.string.size);
+ }
+ break;
- for (uint32_t i = 0; i < obj.data.array.size; i++) {
- Object item = obj.data.array.items[i];
- typval_T li_tv;
+ case kObjectTypeArray: {
+ list_T *const list = tv_list_alloc((ptrdiff_t)obj.data.array.size);
- if (!object_to_vim(item, &li_tv, err)) {
- tv_list_free(list);
- return false;
- }
+ for (uint32_t i = 0; i < obj.data.array.size; i++) {
+ Object item = obj.data.array.items[i];
+ typval_T li_tv;
- tv_list_append_owned_tv(list, li_tv);
+ if (!object_to_vim(item, &li_tv, err)) {
+ tv_list_free(list);
+ return false;
}
- tv_list_ref(list);
- tv->v_type = VAR_LIST;
- tv->vval.v_list = list;
- break;
+ tv_list_append_owned_tv(list, li_tv);
}
+ tv_list_ref(list);
- case kObjectTypeDictionary: {
- dict_T *const dict = tv_dict_alloc();
+ tv->v_type = VAR_LIST;
+ tv->vval.v_list = list;
+ break;
+ }
- for (uint32_t i = 0; i < obj.data.dictionary.size; i++) {
- KeyValuePair item = obj.data.dictionary.items[i];
- String key = item.key;
+ case kObjectTypeDictionary: {
+ dict_T *const dict = tv_dict_alloc();
- if (key.size == 0) {
- api_set_error(err, kErrorTypeValidation,
- "Empty dictionary keys aren't allowed");
- // cleanup
- tv_dict_free(dict);
- return false;
- }
+ for (uint32_t i = 0; i < obj.data.dictionary.size; i++) {
+ KeyValuePair item = obj.data.dictionary.items[i];
+ String key = item.key;
- dictitem_T *const di = tv_dict_item_alloc(key.data);
+ if (key.size == 0) {
+ api_set_error(err, kErrorTypeValidation,
+ "Empty dictionary keys aren't allowed");
+ // cleanup
+ tv_dict_free(dict);
+ return false;
+ }
- if (!object_to_vim(item.value, &di->di_tv, err)) {
- // cleanup
- tv_dict_item_free(di);
- tv_dict_free(dict);
- return false;
- }
+ dictitem_T *const di = tv_dict_item_alloc(key.data);
- tv_dict_add(dict, di);
+ if (!object_to_vim(item.value, &di->di_tv, err)) {
+ // cleanup
+ tv_dict_item_free(di);
+ tv_dict_free(dict);
+ return false;
}
- dict->dv_refcount++;
- tv->v_type = VAR_DICT;
- tv->vval.v_dict = dict;
- break;
+ tv_dict_add(dict, di);
}
- default:
- abort();
+ dict->dv_refcount++;
+
+ tv->v_type = VAR_DICT;
+ tv->vval.v_dict = dict;
+ break;
+ }
+ default:
+ abort();
}
return true;
@@ -1188,33 +1191,33 @@ void api_free_string(String value)
void api_free_object(Object value)
{
switch (value.type) {
- case kObjectTypeNil:
- case kObjectTypeBoolean:
- case kObjectTypeInteger:
- case kObjectTypeFloat:
- case kObjectTypeBuffer:
- case kObjectTypeWindow:
- case kObjectTypeTabpage:
- break;
-
- case kObjectTypeString:
- api_free_string(value.data.string);
- break;
-
- case kObjectTypeArray:
- api_free_array(value.data.array);
- break;
-
- case kObjectTypeDictionary:
- api_free_dictionary(value.data.dictionary);
- break;
-
- case kObjectTypeLuaRef:
- api_free_luaref(value.data.luaref);
- break;
-
- default:
- abort();
+ case kObjectTypeNil:
+ case kObjectTypeBoolean:
+ case kObjectTypeInteger:
+ case kObjectTypeFloat:
+ case kObjectTypeBuffer:
+ case kObjectTypeWindow:
+ case kObjectTypeTabpage:
+ break;
+
+ case kObjectTypeString:
+ api_free_string(value.data.string);
+ break;
+
+ case kObjectTypeArray:
+ api_free_array(value.data.array);
+ break;
+
+ case kObjectTypeDictionary:
+ api_free_dictionary(value.data.dictionary);
+ break;
+
+ case kObjectTypeLuaRef:
+ api_free_luaref(value.data.luaref);
+ break;
+
+ default:
+ abort();
}
}
@@ -1377,36 +1380,30 @@ Dictionary copy_dictionary(Dictionary dict)
Object copy_object(Object obj)
{
switch (obj.type) {
- case kObjectTypeBuffer:
- case kObjectTypeTabpage:
- case kObjectTypeWindow:
- case kObjectTypeNil:
- case kObjectTypeBoolean:
- case kObjectTypeInteger:
- case kObjectTypeFloat:
- return obj;
-
- case kObjectTypeString:
- return STRING_OBJ(copy_string(obj.data.string));
-
- case kObjectTypeArray:
- return ARRAY_OBJ(copy_array(obj.data.array));
-
- case kObjectTypeDictionary: {
- return DICTIONARY_OBJ(copy_dictionary(obj.data.dictionary));
- }
- default:
- abort();
+ case kObjectTypeBuffer:
+ case kObjectTypeTabpage:
+ case kObjectTypeWindow:
+ case kObjectTypeNil:
+ case kObjectTypeBoolean:
+ case kObjectTypeInteger:
+ case kObjectTypeFloat:
+ return obj;
+
+ case kObjectTypeString:
+ return STRING_OBJ(copy_string(obj.data.string));
+
+ case kObjectTypeArray:
+ return ARRAY_OBJ(copy_array(obj.data.array));
+
+ case kObjectTypeDictionary:
+ return DICTIONARY_OBJ(copy_dictionary(obj.data.dictionary));
+ default:
+ abort();
}
}
-static void set_option_value_for(char *key,
- int numval,
- char *stringval,
- int opt_flags,
- int opt_type,
- void *from,
- Error *err)
+static void set_option_value_for(char *key, int numval, char *stringval, int opt_flags,
+ int opt_type, void *from, Error *err)
{
win_T *save_curwin = NULL;
tabpage_T *save_curtab = NULL;
@@ -1415,29 +1412,30 @@ static void set_option_value_for(char *key,
try_start();
switch (opt_type)
{
- case SREQ_WIN:
- if (switch_win(&save_curwin, &save_curtab, (win_T *)from,
- win_find_tabpage((win_T *)from), false) == FAIL)
- {
- if (try_end(err)) {
- return;
- }
- api_set_error(err,
- kErrorTypeException,
- "Problem while switching windows");
+ case SREQ_WIN:
+ if (switch_win_noblock(&save_curwin, &save_curtab, (win_T *)from,
+ win_find_tabpage((win_T *)from), true)
+ == FAIL) {
+ restore_win_noblock(save_curwin, save_curtab, true);
+ if (try_end(err)) {
return;
}
- set_option_value_err(key, numval, stringval, opt_flags, err);
- restore_win(save_curwin, save_curtab, true);
- break;
- case SREQ_BUF:
- aucmd_prepbuf(&aco, (buf_T *)from);
- set_option_value_err(key, numval, stringval, opt_flags, err);
- aucmd_restbuf(&aco);
- break;
- case SREQ_GLOBAL:
- set_option_value_err(key, numval, stringval, opt_flags, err);
- break;
+ api_set_error(err,
+ kErrorTypeException,
+ "Problem while switching windows");
+ return;
+ }
+ set_option_value_err(key, numval, stringval, opt_flags, err);
+ restore_win_noblock(save_curwin, save_curtab, true);
+ break;
+ case SREQ_BUF:
+ aucmd_prepbuf(&aco, (buf_T *)from);
+ set_option_value_err(key, numval, stringval, opt_flags, err);
+ aucmd_restbuf(&aco);
+ break;
+ case SREQ_GLOBAL:
+ set_option_value_err(key, numval, stringval, opt_flags, err);
+ break;
}
if (ERROR_SET(err)) {
@@ -1448,11 +1446,7 @@ static void set_option_value_for(char *key,
}
-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, int numval, char *stringval, int opt_flags, Error *err)
{
char *errmsg;
@@ -1511,8 +1505,7 @@ ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf)
// Check for correct mode
if (int_mode & current_maphash->m_mode) {
mapblock_fill_dict(dict, current_maphash, buffer_value, false);
- ADD(mappings, vim_to_object(
- (typval_T[]) { { .v_type = VAR_DICT, .vval.v_dict = dict } }));
+ ADD(mappings, vim_to_object((typval_T[]) { { .v_type = VAR_DICT, .vval.v_dict = dict } }));
tv_dict_clear(dict);
}
@@ -1548,13 +1541,13 @@ bool extmark_get_index_from_obj(buf_T *buf, Integer ns_id, Object obj, int
if (obj.type == kObjectTypeInteger) {
Integer id = obj.data.integer;
if (id == 0) {
- *row = 0;
- *col = 0;
- return true;
+ *row = 0;
+ *col = 0;
+ return true;
} else if (id == -1) {
- *row = MAXLNUM;
- *col = MAXCOL;
- return true;
+ *row = MAXLNUM;
+ *col = MAXCOL;
+ return true;
} else if (id < 0) {
api_set_error(err, kErrorTypeValidation, "Mark id must be positive");
return false;
@@ -1570,7 +1563,7 @@ bool extmark_get_index_from_obj(buf_T *buf, Integer ns_id, Object obj, int
return false;
}
- // Check if it is a position
+ // Check if it is a position
} else if (obj.type == kObjectTypeArray) {
Array pos = obj.data.array;
if (pos.size != 2
@@ -1592,9 +1585,10 @@ bool extmark_get_index_from_obj(buf_T *buf, Integer ns_id, Object obj, int
}
}
-VirtText parse_virt_text(Array chunks, Error *err)
+VirtText parse_virt_text(Array chunks, Error *err, int *width)
{
VirtText virt_text = KV_INITIAL_VALUE;
+ int w = 0;
for (size_t i = 0; i < chunks.size; i++) {
if (chunks.items[i].type != kObjectTypeArray) {
api_set_error(err, kErrorTypeValidation, "Chunk is not an array");
@@ -1602,26 +1596,44 @@ VirtText parse_virt_text(Array chunks, Error *err)
}
Array chunk = chunks.items[i].data.array;
if (chunk.size == 0 || chunk.size > 2
- || chunk.items[0].type != kObjectTypeString
- || (chunk.size == 2 && chunk.items[1].type != kObjectTypeString)) {
+ || chunk.items[0].type != kObjectTypeString) {
api_set_error(err, kErrorTypeValidation,
"Chunk is not an array with one or two strings");
goto free_exit;
}
String str = chunk.items[0].data.string;
- char *text = transstr(str.size > 0 ? str.data : ""); // allocates
int hl_id = 0;
if (chunk.size == 2) {
- String hl = chunk.items[1].data.string;
- if (hl.size > 0) {
- hl_id = syn_check_group((char_u *)hl.data, (int)hl.size);
+ Object hl = chunk.items[1];
+ if (hl.type == kObjectTypeArray) {
+ Array arr = hl.data.array;
+ for (size_t j = 0; j < arr.size; j++) {
+ hl_id = object_to_hl_id(arr.items[j], "virt_text highlight", err);
+ if (ERROR_SET(err)) {
+ goto free_exit;
+ }
+ if (j < arr.size-1) {
+ kv_push(virt_text, ((VirtTextChunk){ .text = NULL,
+ .hl_id = hl_id }));
+ }
+ }
+ } else {
+ hl_id = object_to_hl_id(hl, "virt_text highlight", err);
+ if (ERROR_SET(err)) {
+ goto free_exit;
+ }
}
}
+
+ char *text = transstr(str.size > 0 ? str.data : "", false); // allocates
+ w += (int)mb_string2cells((char_u *)text);
+
kv_push(virt_text, ((VirtTextChunk){ .text = text, .hl_id = hl_id }));
}
+ *width = w;
return virt_text;
free_exit:
@@ -1635,8 +1647,7 @@ free_exit:
/// @param what The name of the object, used for error message
/// @param nil_value What to return if the type is nil.
/// @param err Set if there was an error in converting to a bool
-bool api_object_to_bool(Object obj, const char *what,
- bool nil_value, Error *err)
+bool api_object_to_bool(Object obj, const char *what, bool nil_value, Error *err)
{
if (obj.type == kObjectTypeBoolean) {
return obj.data.boolean;
@@ -1656,7 +1667,7 @@ int object_to_hl_id(Object obj, const char *what, Error *err)
String str = obj.data.string;
return str.size ? syn_check_group((char_u *)str.data, (int)str.size) : 0;
} else if (obj.type == kObjectTypeInteger) {
- return (int)obj.data.integer;
+ return MAX((int)obj.data.integer, 0);
} else {
api_set_error(err, kErrorTypeValidation,
"%s is not a valid highlight", what);
@@ -1687,6 +1698,7 @@ HlMessage parse_hl_msg(Array chunks, Error *err)
if (chunk.size == 2) {
String hl = chunk.items[1].data.string;
if (hl.size > 0) {
+ // TODO(bfredl): use object_to_hl_id and allow integer
int hl_id = syn_check_group((char_u *)hl.data, (int)hl.size);
attr = hl_id > 0 ? syn_id2attr(hl_id) : 0;
}
@@ -1705,7 +1717,7 @@ const char *describe_ns(NS ns_id)
{
String name;
handle_T id;
- map_foreach(namespace_ids, name, id, {
+ map_foreach(&namespace_ids, name, id, {
if ((NS)id == ns_id && name.size) {
return name.data;
}
@@ -1738,7 +1750,7 @@ static bool parse_float_relative(String relative, FloatRelative *out)
char *str = relative.data;
if (striequal(str, "editor")) {
*out = kFloatRelativeEditor;
- } else if (striequal(str, "win")) {
+ } else if (striequal(str, "win")) {
*out = kFloatRelativeWindow;
} else if (striequal(str, "cursor")) {
*out = kFloatRelativeCursor;
@@ -1772,7 +1784,7 @@ static void parse_border_style(Object style, FloatConfig *fconfig, Error *err)
{ "shadow", { "", "", " ", " ", " ", " ", " ", "" }, true },
{ "rounded", { "╭", "─", "╮", "│", "╯", "─", "╰", "│" }, false },
{ "solid", { " ", " ", " ", " ", " ", " ", " ", " " }, false },
- { NULL, { { NUL } } , false },
+ { NULL, { { NUL } }, false },
};
schar_T *chars = fconfig->border_chars;
@@ -1790,7 +1802,7 @@ static void parse_border_style(Object style, FloatConfig *fconfig, Error *err)
}
for (size_t i = 0; i < size; i++) {
Object iytem = arr.items[i];
- String string = NULL_STRING;
+ String string;
int hl_id = 0;
if (iytem.type == kObjectTypeArray) {
Array iarr = iytem.data.array;
@@ -1809,7 +1821,6 @@ static void parse_border_style(Object style, FloatConfig *fconfig, Error *err)
return;
}
}
-
} else if (iytem.type == kObjectTypeString) {
string = iytem.data.string;
} else {
@@ -1868,8 +1879,8 @@ static void parse_border_style(Object style, FloatConfig *fconfig, Error *err)
}
}
-bool parse_float_config(Dictionary config, FloatConfig *fconfig, bool reconf,
- bool new_win, Error *err)
+bool parse_float_config(Dictionary config, FloatConfig *fconfig, bool reconf, bool new_win,
+ Error *err)
{
// TODO(bfredl): use a get/has_key interface instead and get rid of extra
// flags
@@ -1970,13 +1981,13 @@ bool parse_float_config(Dictionary config, FloatConfig *fconfig, bool reconf,
has_bufpos = true;
} else if (!strcmp(key, "external")) {
has_external = fconfig->external
- = api_object_to_bool(val, "'external' key", false, err);
+ = api_object_to_bool(val, "'external' key", false, err);
if (ERROR_SET(err)) {
return false;
}
} else if (!strcmp(key, "focusable")) {
fconfig->focusable
- = api_object_to_bool(val, "'focusable' key", true, err);
+ = api_object_to_bool(val, "'focusable' key", true, err);
if (ERROR_SET(err)) {
return false;
}
@@ -2003,13 +2014,13 @@ bool parse_float_config(Dictionary config, FloatConfig *fconfig, bool reconf,
fconfig->style = kWinStyleUnused;
} else if (striequal(val.data.string.data, "minimal")) {
fconfig->style = kWinStyleMinimal;
- } else {
+ } else {
api_set_error(err, kErrorTypeValidation,
"Invalid value of 'style' key");
}
} else if (strequal(key, "noautocmd") && new_win) {
fconfig->noautocmd
- = api_object_to_bool(val, "'noautocmd' key", false, err);
+ = api_object_to_bool(val, "'noautocmd' key", false, err);
if (ERROR_SET(err)) {
return false;
}
diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h
index 055abb797f..ecce6afa26 100644
--- a/src/nvim/api/private/helpers.h
+++ b/src/nvim/api/private/helpers.h
@@ -101,6 +101,14 @@
#define api_free_window(value)
#define api_free_tabpage(value)
+EXTERN PMap(handle_T) buffer_handles INIT(= MAP_INIT);
+EXTERN PMap(handle_T) window_handles INIT(= MAP_INIT);
+EXTERN PMap(handle_T) tabpage_handles INIT(= MAP_INIT);
+
+#define handle_get_buffer(h) pmap_get(handle_T)(&buffer_handles, (h))
+#define handle_get_window(h) pmap_get(handle_T)(&window_handles, (h))
+#define handle_get_tabpage(h) pmap_get(handle_T)(&tabpage_handles, (h))
+
/// Structure used for saving state for :try
///
/// Used when caller is supposed to be operating when other VimL code is being
diff --git a/src/nvim/api/tabpage.c b/src/nvim/api/tabpage.c
index 5f727dbc38..14b6be8eeb 100644
--- a/src/nvim/api/tabpage.c
+++ b/src/nvim/api/tabpage.c
@@ -5,10 +5,10 @@
#include <stdint.h>
#include <stdlib.h>
-#include "nvim/api/tabpage.h"
-#include "nvim/api/vim.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
+#include "nvim/api/tabpage.h"
+#include "nvim/api/vim.h"
#include "nvim/memory.h"
#include "nvim/window.h"
@@ -53,7 +53,7 @@ Object nvim_tabpage_get_var(Tabpage tabpage, String name, Error *err)
tabpage_T *tab = find_tab_by_handle(tabpage, err);
if (!tab) {
- return (Object) OBJECT_INIT;
+ return (Object)OBJECT_INIT;
}
return dict_get_value(tab->tp_vars, name, err);
@@ -65,10 +65,7 @@ Object nvim_tabpage_get_var(Tabpage tabpage, String name, Error *err)
/// @param name Variable name
/// @param value Variable value
/// @param[out] err Error details, if any
-void nvim_tabpage_set_var(Tabpage tabpage,
- String name,
- Object value,
- Error *err)
+void nvim_tabpage_set_var(Tabpage tabpage, String name, Object value, Error *err)
FUNC_API_SINCE(1)
{
tabpage_T *tab = find_tab_by_handle(tabpage, err);
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index 51f1af4eb5..9b200dcba2 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -2,22 +2,22 @@
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <assert.h>
+#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
-#include <stdbool.h>
-#include "nvim/vim.h"
-#include "nvim/ui.h"
-#include "nvim/memory.h"
-#include "nvim/map.h"
-#include "nvim/msgpack_rpc/channel.h"
-#include "nvim/api/ui.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
-#include "nvim/popupmnu.h"
+#include "nvim/api/ui.h"
#include "nvim/cursor_shape.h"
#include "nvim/highlight.h"
+#include "nvim/map.h"
+#include "nvim/memory.h"
+#include "nvim/msgpack_rpc/channel.h"
+#include "nvim/popupmnu.h"
#include "nvim/screen.h"
+#include "nvim/ui.h"
+#include "nvim/vim.h"
#include "nvim/window.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -37,24 +37,18 @@ typedef struct {
bool wildmenu_active;
} UIData;
-static PMap(uint64_t) *connected_uis = NULL;
-
-void remote_ui_init(void)
- FUNC_API_NOEXPORT
-{
- connected_uis = pmap_new(uint64_t)();
-}
+static PMap(uint64_t) connected_uis = MAP_INIT;
void remote_ui_disconnect(uint64_t channel_id)
FUNC_API_NOEXPORT
{
- UI *ui = pmap_get(uint64_t)(connected_uis, channel_id);
+ UI *ui = pmap_get(uint64_t)(&connected_uis, channel_id);
if (!ui) {
return;
}
UIData *data = ui->data;
api_free_array(data->buffer); // Destroy pending screen updates.
- pmap_del(uint64_t)(connected_uis, channel_id);
+ pmap_del(uint64_t)(&connected_uis, channel_id);
xfree(ui->data);
ui->data = NULL; // Flag UI as "stopped".
ui_detach_impl(ui, channel_id);
@@ -73,7 +67,7 @@ void remote_ui_wait_for_attach(void)
}
LOOP_PROCESS_EVENTS_UNTIL(&main_loop, channel->events, -1,
- pmap_has(uint64_t)(connected_uis, CHAN_STDIO));
+ pmap_has(uint64_t)(&connected_uis, CHAN_STDIO));
}
/// Activates UI events on the channel.
@@ -91,11 +85,11 @@ void remote_ui_wait_for_attach(void)
/// @param height Requested screen rows
/// @param options |ui-option| map
/// @param[out] err Error details, if any
-void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height,
- Dictionary options, Error *err)
+void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dictionary options,
+ Error *err)
FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
{
- if (pmap_has(uint64_t)(connected_uis, channel_id)) {
+ if (pmap_has(uint64_t)(&connected_uis, channel_id)) {
api_set_error(err, kErrorTypeException,
"UI already attached to channel: %" PRId64, channel_id);
return;
@@ -158,7 +152,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height,
}
if (ui->ui_ext[kUIMessages]) {
- // This uses attribute indicies, so ext_linegrid is needed.
+ // This uses attribute indices, so ext_linegrid is needed.
ui->ui_ext[kUILinegrid] = true;
// Cmdline uses the messages area, so it should be externalized too.
ui->ui_ext[kUICmdline] = true;
@@ -172,13 +166,12 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height,
data->wildmenu_active = false;
ui->data = data;
- pmap_put(uint64_t)(connected_uis, channel_id, ui);
+ pmap_put(uint64_t)(&connected_uis, channel_id, ui);
ui_attach_impl(ui, channel_id);
}
/// @deprecated
-void ui_attach(uint64_t channel_id, Integer width, Integer height,
- Boolean enable_rgb, Error *err)
+void ui_attach(uint64_t channel_id, Integer width, Integer height, Boolean enable_rgb, Error *err)
{
Dictionary opts = ARRAY_DICT_INIT;
PUT(opts, "rgb", BOOLEAN_OBJ(enable_rgb));
@@ -195,7 +188,7 @@ void ui_attach(uint64_t channel_id, Integer width, Integer height,
void nvim_ui_detach(uint64_t channel_id, Error *err)
FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
{
- if (!pmap_has(uint64_t)(connected_uis, channel_id)) {
+ if (!pmap_has(uint64_t)(&connected_uis, channel_id)) {
api_set_error(err, kErrorTypeException,
"UI not attached to channel: %" PRId64, channel_id);
return;
@@ -204,11 +197,10 @@ void nvim_ui_detach(uint64_t channel_id, Error *err)
}
-void nvim_ui_try_resize(uint64_t channel_id, Integer width,
- Integer height, Error *err)
+void nvim_ui_try_resize(uint64_t channel_id, Integer width, Integer height, Error *err)
FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
{
- if (!pmap_has(uint64_t)(connected_uis, channel_id)) {
+ if (!pmap_has(uint64_t)(&connected_uis, channel_id)) {
api_set_error(err, kErrorTypeException,
"UI not attached to channel: %" PRId64, channel_id);
return;
@@ -220,28 +212,26 @@ void nvim_ui_try_resize(uint64_t channel_id, Integer width,
return;
}
- UI *ui = pmap_get(uint64_t)(connected_uis, channel_id);
+ UI *ui = pmap_get(uint64_t)(&connected_uis, channel_id);
ui->width = (int)width;
ui->height = (int)height;
ui_refresh();
}
-void nvim_ui_set_option(uint64_t channel_id, String name,
- Object value, Error *error)
+void nvim_ui_set_option(uint64_t channel_id, String name, Object value, Error *error)
FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
{
- if (!pmap_has(uint64_t)(connected_uis, channel_id)) {
+ if (!pmap_has(uint64_t)(&connected_uis, channel_id)) {
api_set_error(error, kErrorTypeException,
"UI not attached to channel: %" PRId64, channel_id);
return;
}
- UI *ui = pmap_get(uint64_t)(connected_uis, channel_id);
+ UI *ui = pmap_get(uint64_t)(&connected_uis, channel_id);
ui_set_option(ui, false, name, value, error);
}
-static void ui_set_option(UI *ui, bool init, String name, Object value,
- Error *error)
+static void ui_set_option(UI *ui, bool init, String name, Object value, Error *error)
{
if (strequal(name.data, "override")) {
if (value.type != kObjectTypeBoolean) {
@@ -306,11 +296,11 @@ static void ui_set_option(UI *ui, bool init, String name, Object value,
/// @param width The new requested width.
/// @param height The new requested height.
/// @param[out] err Error details, if any
-void nvim_ui_try_resize_grid(uint64_t channel_id, Integer grid, Integer width,
- Integer height, Error *err)
+void nvim_ui_try_resize_grid(uint64_t channel_id, Integer grid, Integer width, Integer height,
+ Error *err)
FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY
{
- if (!pmap_has(uint64_t)(connected_uis, channel_id)) {
+ if (!pmap_has(uint64_t)(&connected_uis, channel_id)) {
api_set_error(err, kErrorTypeException,
"UI not attached to channel: %" PRId64, channel_id);
return;
@@ -328,7 +318,7 @@ void nvim_ui_try_resize_grid(uint64_t channel_id, Integer grid, Integer width,
void nvim_ui_pum_set_height(uint64_t channel_id, Integer height, Error *err)
FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY
{
- if (!pmap_has(uint64_t)(connected_uis, channel_id)) {
+ if (!pmap_has(uint64_t)(&connected_uis, channel_id)) {
api_set_error(err, kErrorTypeException,
"UI not attached to channel: %" PRId64, channel_id);
return;
@@ -339,7 +329,7 @@ void nvim_ui_pum_set_height(uint64_t channel_id, Integer height, Error *err)
return;
}
- UI *ui = pmap_get(uint64_t)(connected_uis, channel_id);
+ UI *ui = pmap_get(uint64_t)(&connected_uis, channel_id);
if (!ui->ui_ext[kUIPopupmenu]) {
api_set_error(err, kErrorTypeValidation,
"It must support the ext_popupmenu option");
@@ -365,17 +355,17 @@ void nvim_ui_pum_set_height(uint64_t channel_id, Integer height, Error *err)
/// @param row Popupmenu row.
/// @param col Popupmenu height.
/// @param[out] err Error details, if any.
-void nvim_ui_pum_set_bounds(uint64_t channel_id, Float width, Float height,
- Float row, Float col, Error *err)
+void nvim_ui_pum_set_bounds(uint64_t channel_id, Float width, Float height, Float row, Float col,
+ Error *err)
FUNC_API_SINCE(7) FUNC_API_REMOTE_ONLY
{
- if (!pmap_has(uint64_t)(connected_uis, channel_id)) {
+ if (!pmap_has(uint64_t)(&connected_uis, channel_id)) {
api_set_error(err, kErrorTypeException,
"UI not attached to channel: %" PRId64, channel_id);
return;
}
- UI *ui = pmap_get(uint64_t)(connected_uis, channel_id);
+ UI *ui = pmap_get(uint64_t)(&connected_uis, channel_id);
if (!ui->ui_ext[kUIPopupmenu]) {
api_set_error(err, kErrorTypeValidation,
"UI must support the ext_popupmenu option");
@@ -430,8 +420,7 @@ static void remote_ui_grid_clear(UI *ui, Integer grid)
push_call(ui, name, args);
}
-static void remote_ui_grid_resize(UI *ui, Integer grid,
- Integer width, Integer height)
+static void remote_ui_grid_resize(UI *ui, Integer grid, Integer width, Integer height)
{
Array args = ARRAY_DICT_INIT;
if (ui->ui_ext[kUILinegrid]) {
@@ -443,9 +432,8 @@ static void remote_ui_grid_resize(UI *ui, Integer grid,
push_call(ui, name, args);
}
-static void remote_ui_grid_scroll(UI *ui, Integer grid, Integer top,
- Integer bot, Integer left, Integer right,
- Integer rows, Integer cols)
+static void remote_ui_grid_scroll(UI *ui, Integer grid, Integer top, Integer bot, Integer left,
+ Integer right, Integer rows, Integer cols)
{
if (ui->ui_ext[kUILinegrid]) {
Array args = ARRAY_DICT_INIT;
@@ -480,8 +468,7 @@ static void remote_ui_grid_scroll(UI *ui, Integer grid, Integer top,
}
}
-static void remote_ui_default_colors_set(UI *ui, Integer rgb_fg,
- Integer rgb_bg, Integer rgb_sp,
+static void remote_ui_default_colors_set(UI *ui, Integer rgb_fg, Integer rgb_bg, Integer rgb_sp,
Integer cterm_fg, Integer cterm_bg)
{
if (!ui->ui_ext[kUITermColors]) {
@@ -511,8 +498,8 @@ static void remote_ui_default_colors_set(UI *ui, Integer rgb_fg,
}
}
-static void remote_ui_hl_attr_define(UI *ui, Integer id, HlAttrs rgb_attrs,
- HlAttrs cterm_attrs, Array info)
+static void remote_ui_hl_attr_define(UI *ui, Integer id, HlAttrs rgb_attrs, HlAttrs cterm_attrs,
+ Array info)
{
if (!ui->ui_ext[kUILinegrid]) {
return;
@@ -549,8 +536,7 @@ static void remote_ui_highlight_set(UI *ui, int id)
}
/// "true" cursor used only for input focus
-static void remote_ui_grid_cursor_goto(UI *ui, Integer grid, Integer row,
- Integer col)
+static void remote_ui_grid_cursor_goto(UI *ui, Integer grid, Integer row, Integer col)
{
if (ui->ui_ext[kUILinegrid]) {
Array args = ARRAY_DICT_INIT;
@@ -590,11 +576,9 @@ static void remote_ui_put(UI *ui, const char *cell)
push_call(ui, "put", args);
}
-static void remote_ui_raw_line(UI *ui, Integer grid, Integer row,
- Integer startcol, Integer endcol,
- Integer clearcol, Integer clearattr,
- LineFlags flags, const schar_T *chunk,
- const sattr_T *attrs)
+static void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Integer endcol,
+ Integer clearcol, Integer clearattr, LineFlags flags,
+ const schar_T *chunk, const sattr_T *attrs)
{
UIData *data = ui->data;
if (ui->ui_ext[kUILinegrid]) {
@@ -735,7 +719,7 @@ static void remote_ui_event(UI *ui, char *name, Array args, bool *args_consumed)
if (ui->ui_ext[kUIWildmenu]) {
if (strequal(name, "popupmenu_show")) {
data->wildmenu_active = (args.items[4].data.integer == -1)
- || !ui->ui_ext[kUIPopupmenu];
+ || !ui->ui_ext[kUIPopupmenu];
if (data->wildmenu_active) {
Array new_args = ARRAY_DICT_INIT;
Array items = args.items[0].data.array;
diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h
index 35d39a34d7..03fe5c5058 100644
--- a/src/nvim/api/ui_events.in.h
+++ b/src/nvim/api/ui_events.in.h
@@ -119,7 +119,8 @@ void msg_set_pos(Integer grid, Integer row, Boolean scrolled, String sep_char)
FUNC_API_SINCE(6) FUNC_API_BRIDGE_IMPL FUNC_API_COMPOSITOR_IMPL;
void win_viewport(Integer grid, Window win, Integer topline,
- Integer botline, Integer curline, Integer curcol)
+ Integer botline, Integer curline, Integer curcol,
+ Integer line_count)
FUNC_API_SINCE(7) FUNC_API_REMOTE_ONLY;
void popupmenu_show(Array items, Integer selected,
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 349cc0e7da..3be45d0cf7 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -3,54 +3,54 @@
#include <assert.h>
#include <inttypes.h>
+#include <limits.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
-#include <limits.h>
-#include "nvim/api/vim.h"
-#include "nvim/ascii.h"
-#include "nvim/api/private/helpers.h"
+#include "nvim/api/buffer.h"
+#include "nvim/api/deprecated.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/dispatch.h"
-#include "nvim/api/buffer.h"
+#include "nvim/api/private/helpers.h"
+#include "nvim/api/vim.h"
#include "nvim/api/window.h"
-#include "nvim/api/deprecated.h"
-#include "nvim/msgpack_rpc/channel.h"
-#include "nvim/msgpack_rpc/helpers.h"
-#include "nvim/lua/executor.h"
-#include "nvim/vim.h"
+#include "nvim/ascii.h"
#include "nvim/buffer.h"
#include "nvim/context.h"
-#include "nvim/file_search.h"
-#include "nvim/highlight.h"
-#include "nvim/window.h"
-#include "nvim/types.h"
-#include "nvim/ex_cmds2.h"
-#include "nvim/ex_docmd.h"
-#include "nvim/screen.h"
-#include "nvim/memline.h"
-#include "nvim/mark.h"
-#include "nvim/memory.h"
-#include "nvim/message.h"
-#include "nvim/popupmnu.h"
+#include "nvim/decoration.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/userfunc.h"
+#include "nvim/ex_cmds2.h"
+#include "nvim/ex_docmd.h"
+#include "nvim/file_search.h"
#include "nvim/fileio.h"
+#include "nvim/getchar.h"
+#include "nvim/highlight.h"
+#include "nvim/lua/executor.h"
+#include "nvim/mark.h"
+#include "nvim/memline.h"
+#include "nvim/memory.h"
+#include "nvim/message.h"
#include "nvim/move.h"
+#include "nvim/msgpack_rpc/channel.h"
+#include "nvim/msgpack_rpc/helpers.h"
#include "nvim/ops.h"
#include "nvim/option.h"
-#include "nvim/state.h"
-#include "nvim/decoration.h"
-#include "nvim/syntax.h"
-#include "nvim/getchar.h"
#include "nvim/os/input.h"
#include "nvim/os/process.h"
+#include "nvim/popupmnu.h"
+#include "nvim/screen.h"
+#include "nvim/state.h"
+#include "nvim/syntax.h"
+#include "nvim/types.h"
+#include "nvim/ui.h"
+#include "nvim/vim.h"
#include "nvim/viml/parser/expressions.h"
#include "nvim/viml/parser/parser.h"
-#include "nvim/ui.h"
+#include "nvim/window.h"
#define LINE_BUFFER_SIZE 4096
@@ -58,22 +58,16 @@
# include "api/vim.c.generated.h"
#endif
-void api_vim_init(void)
- FUNC_API_NOEXPORT
-{
- namespace_ids = map_new(String, handle_T)();
-}
-
void api_vim_free_all_mem(void)
FUNC_API_NOEXPORT
{
String name;
handle_T id;
- map_foreach(namespace_ids, name, id, {
+ map_foreach(&namespace_ids, name, id, {
(void)id;
xfree(name.data);
})
- map_free(String, handle_T)(namespace_ids);
+ map_destroy(String, handle_T)(&namespace_ids);
}
/// Executes Vimscript (multiline block of Ex-commands), like anonymous
@@ -217,7 +211,7 @@ Dictionary nvim__get_hl_defs(Integer ns_id, Error *err)
///
/// @param ns_id number of namespace for this highlight
/// @param name highlight group name, like ErrorMsg
-/// @param val highlight definiton map, like |nvim_get_hl_by_name|.
+/// @param val highlight definition map, like |nvim_get_hl_by_name|.
/// in addition the following keys are also recognized:
/// `default`: don't override existing definition,
/// like `hi default`
@@ -281,9 +275,9 @@ static void on_redraw_event(void **argv)
///
/// On execution error: does not fail, but updates v:errmsg.
///
-/// If you need to input sequences like <C-o> use |nvim_replace_termcodes| to
-/// replace the termcodes and then pass the resulting string to nvim_feedkeys.
-/// You'll also want to enable escape_csi.
+/// To input sequences like <C-o> use |nvim_replace_termcodes()| (typically
+/// with escape_csi=true) to replace |keycodes|, then pass the result to
+/// nvim_feedkeys().
///
/// Example:
/// <pre>
@@ -307,12 +301,18 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_csi)
for (size_t i = 0; i < mode.size; ++i) {
switch (mode.data[i]) {
- case 'n': remap = false; break;
- case 'm': remap = true; break;
- case 't': typed = true; break;
- case 'i': insert = true; break;
- case 'x': execute = true; break;
- case '!': dangerous = true; break;
+ case 'n':
+ remap = false; break;
+ case 'm':
+ remap = true; break;
+ case 't':
+ typed = true; break;
+ case 'i':
+ insert = true; break;
+ case 'x':
+ execute = true; break;
+ case '!':
+ dangerous = true; break;
}
}
@@ -322,11 +322,11 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_csi)
char *keys_esc;
if (escape_csi) {
- // Need to escape K_SPECIAL and CSI before putting the string in the
- // typeahead buffer.
- keys_esc = (char *)vim_strsave_escape_csi((char_u *)keys.data);
+ // Need to escape K_SPECIAL and CSI before putting the string in the
+ // typeahead buffer.
+ keys_esc = (char *)vim_strsave_escape_csi((char_u *)keys.data);
} else {
- keys_esc = keys.data;
+ keys_esc = keys.data;
}
ins_typebuf((char_u *)keys_esc, (remap ? REMAP_YES : REMAP_NONE),
insert ? 0 : typebuf.tb_len, !typed, false);
@@ -335,7 +335,7 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_csi)
}
if (escape_csi) {
- xfree(keys_esc);
+ xfree(keys_esc);
}
if (execute) {
@@ -384,7 +384,7 @@ Integer nvim_input(String keys)
/// by calling it multiple times in a loop: the intermediate mouse
/// positions will be ignored. It should be used to implement real-time
/// mouse input in a GUI. The deprecated pseudokey form
-/// ("<LeftMouse><col,row>") of |nvim_input()| has the same limitiation.
+/// ("<LeftMouse><col,row>") of |nvim_input()| has the same limitation.
///
/// @param button Mouse button: one of "left", "right", "middle", "wheel".
/// @param action For ordinary buttons, one of "press", "drag", "release".
@@ -397,8 +397,8 @@ Integer nvim_input(String keys)
/// @param row Mouse row-position (zero-based, like redraw events)
/// @param col Mouse column-position (zero-based, like redraw events)
/// @param[out] err Error details, if any
-void nvim_input_mouse(String button, String action, String modifier,
- Integer grid, Integer row, Integer col, Error *err)
+void nvim_input_mouse(String button, String action, String modifier, Integer grid, Integer row,
+ Integer col, Error *err)
FUNC_API_SINCE(6) FUNC_API_FAST
{
if (button.data == NULL || action.data == NULL) {
@@ -475,8 +475,7 @@ error:
/// @param special Replace |keycodes|, e.g. <CR> becomes a "\n" char.
/// @see replace_termcodes
/// @see cpoptions
-String nvim_replace_termcodes(String str, Boolean from_part, Boolean do_lt,
- Boolean special)
+String nvim_replace_termcodes(String str, Boolean from_part, Boolean do_lt, Boolean special)
FUNC_API_SINCE(1)
{
if (str.size == 0) {
@@ -505,32 +504,32 @@ Object nvim_eval(String expr, Error *err)
Object rv = OBJECT_INIT;
TRY_WRAP({
- // Initialize `force_abort` and `suppress_errthrow` at the top level.
- if (!recursive) {
- force_abort = false;
- suppress_errthrow = false;
- current_exception = NULL;
- // `did_emsg` is set by emsg(), which cancels execution.
- did_emsg = false;
- }
- recursive++;
- try_start();
+ // Initialize `force_abort` and `suppress_errthrow` at the top level.
+ if (!recursive) {
+ force_abort = false;
+ suppress_errthrow = false;
+ current_exception = NULL;
+ // `did_emsg` is set by emsg(), which cancels execution.
+ did_emsg = false;
+ }
+ recursive++;
+ try_start();
- typval_T rettv;
- int ok = eval0((char_u *)expr.data, &rettv, NULL, true);
+ typval_T rettv;
+ int ok = eval0((char_u *)expr.data, &rettv, NULL, true);
- if (!try_end(err)) {
- if (ok == FAIL) {
- // Should never happen, try_end() should get the error. #8371
- api_set_error(err, kErrorTypeException,
- "Failed to evaluate expression: '%.*s'", 256, expr.data);
- } else {
- rv = vim_to_object(&rettv);
+ if (!try_end(err)) {
+ if (ok == FAIL) {
+ // Should never happen, try_end() should get the error. #8371
+ api_set_error(err, kErrorTypeException,
+ "Failed to evaluate expression: '%.*s'", 256, expr.data);
+ } else {
+ rv = vim_to_object(&rettv);
+ }
}
- }
- tv_clear(&rettv);
- recursive--;
+ tv_clear(&rettv);
+ recursive--;
});
return rv;
@@ -558,7 +557,7 @@ Object nvim_exec_lua(String code, Array args, Error *err)
/// Notify the user with a message
///
/// Relays the call to vim.notify . By default forwards your message in the
-/// echo area but can be overriden to trigger desktop notifications.
+/// echo area but can be overridden to trigger desktop notifications.
///
/// @param msg Message to display to the user
/// @param log_level The log level
@@ -603,28 +602,31 @@ static Object _call_function(String fn, Array args, dict_T *self, Error *err)
}
TRY_WRAP({
- // Initialize `force_abort` and `suppress_errthrow` at the top level.
- if (!recursive) {
- force_abort = false;
- suppress_errthrow = false;
- current_exception = NULL;
- // `did_emsg` is set by emsg(), which cancels execution.
- did_emsg = false;
- }
- recursive++;
- try_start();
- typval_T rettv;
- int dummy;
- // call_func() retval is deceptive, ignore it. Instead we set `msg_list`
- // (see above) to capture abort-causing non-exception errors.
- (void)call_func((char_u *)fn.data, (int)fn.size, &rettv, (int)args.size,
- vim_args, NULL, curwin->w_cursor.lnum, curwin->w_cursor.lnum,
- &dummy, true, NULL, self);
- if (!try_end(err)) {
- rv = vim_to_object(&rettv);
- }
- tv_clear(&rettv);
- recursive--;
+ // Initialize `force_abort` and `suppress_errthrow` at the top level.
+ if (!recursive) {
+ force_abort = false;
+ suppress_errthrow = false;
+ current_exception = NULL;
+ // `did_emsg` is set by emsg(), which cancels execution.
+ did_emsg = false;
+ }
+ recursive++;
+ try_start();
+ typval_T rettv;
+ funcexe_T funcexe = FUNCEXE_INIT;
+ funcexe.firstline = curwin->w_cursor.lnum;
+ funcexe.lastline = curwin->w_cursor.lnum;
+ funcexe.evaluate = true;
+ funcexe.selfdict = self;
+ // call_func() retval is deceptive, ignore it. Instead we set `msg_list`
+ // (see above) to capture abort-causing non-exception errors.
+ (void)call_func((char_u *)fn.data, (int)fn.size, &rettv, (int)args.size,
+ vim_args, &funcexe);
+ if (!try_end(err)) {
+ rv = vim_to_object(&rettv);
+ }
+ tv_clear(&rettv);
+ recursive--;
});
free_vim_args:
@@ -666,31 +668,28 @@ Object nvim_call_dict_function(Object dict, String fn, Array args, Error *err)
typval_T rettv;
bool mustfree = false;
switch (dict.type) {
- case kObjectTypeString: {
- try_start();
- if (eval0((char_u *)dict.data.string.data, &rettv, NULL, true) == FAIL) {
- api_set_error(err, kErrorTypeException,
- "Failed to evaluate dict expression");
- }
- if (try_end(err)) {
- return rv;
- }
- // Evaluation of the string arg created a new dict or increased the
- // refcount of a dict. Not necessary for a RPC dict.
- mustfree = true;
- break;
- }
- case kObjectTypeDictionary: {
- if (!object_to_vim(dict, &rettv, err)) {
- goto end;
- }
- break;
+ case kObjectTypeString:
+ try_start();
+ if (eval0((char_u *)dict.data.string.data, &rettv, NULL, true) == FAIL) {
+ api_set_error(err, kErrorTypeException,
+ "Failed to evaluate dict expression");
}
- default: {
- api_set_error(err, kErrorTypeValidation,
- "dict argument type must be String or Dictionary");
+ if (try_end(err)) {
return rv;
}
+ // Evaluation of the string arg created a new dict or increased the
+ // refcount of a dict. Not necessary for a RPC dict.
+ mustfree = true;
+ break;
+ case kObjectTypeDictionary:
+ if (!object_to_vim(dict, &rettv, err)) {
+ goto end;
+ }
+ break;
+ default:
+ api_set_error(err, kErrorTypeValidation,
+ "dict argument type must be String or Dictionary");
+ return rv;
}
dict_T *self_dict = rettv.vval.v_dict;
if (rettv.v_type != VAR_DICT || !self_dict) {
@@ -753,47 +752,10 @@ Integer nvim_strwidth(String text, Error *err)
/// Gets the paths contained in 'runtimepath'.
///
/// @return List of paths
-ArrayOf(String) nvim_list_runtime_paths(void)
+ArrayOf(String) nvim_list_runtime_paths(Error *err)
FUNC_API_SINCE(1)
{
- // TODO(bfredl): this should just work:
- // return nvim_get_runtime_file(NULL_STRING, true);
-
- Array rv = ARRAY_DICT_INIT;
-
- char_u *rtp = p_rtp;
-
- if (*rtp == NUL) {
- // No paths
- return rv;
- }
-
- // Count the number of paths in rtp
- while (*rtp != NUL) {
- if (*rtp == ',') {
- rv.size++;
- }
- rtp++;
- }
- rv.size++;
-
- // Allocate memory for the copies
- rv.items = xmalloc(sizeof(*rv.items) * rv.size);
- // Reset the position
- rtp = p_rtp;
- // Start copying
- for (size_t i = 0; i < rv.size; i++) {
- rv.items[i].type = kObjectTypeString;
- rv.items[i].data.string.data = xmalloc(MAXPATHL);
- // Copy the path from 'runtimepath' to rv.items[i]
- size_t length = copy_option_part(&rtp,
- (char_u *)rv.items[i].data.string.data,
- MAXPATHL,
- ",");
- rv.items[i].data.string.size = length;
- }
-
- return rv;
+ return nvim_get_runtime_file(NULL_STRING, true, err);
}
/// Find files in runtime directories
@@ -805,10 +767,6 @@ ArrayOf(String) nvim_list_runtime_paths(void)
///
/// It is not an error to not find any files. An empty array is returned then.
///
-/// To find a directory, `name` must end with a forward slash, like
-/// "rplugin/python/". Without the slash it would instead look for an ordinary
-/// file called "rplugin/python".
-///
/// @param name pattern of files to search for
/// @param all whether to return all matches or only the first
/// @return list of absolute paths to the found files
@@ -818,11 +776,7 @@ ArrayOf(String) nvim_get_runtime_file(String name, Boolean all, Error *err)
{
Array rv = ARRAY_DICT_INIT;
- int flags = DIP_START | (all ? DIP_ALL : 0);
-
- if (name.size == 0 || name.data[name.size-1] == '/') {
- flags |= DIP_DIR;
- }
+ int flags = DIP_DIRFILE | (all ? DIP_ALL : 0);
do_in_runtimepath((char_u *)(name.size ? name.data : ""),
flags, find_runtime_cb, &rv);
@@ -1260,7 +1214,7 @@ fail:
///
/// By default (and currently the only option) the terminal will not be
/// connected to an external process. Instead, input send on the channel
-/// will be echoed directly by the terminal. This is useful to disply
+/// will be echoed directly by the terminal. This is useful to display
/// ANSI terminal sequences returned as part of a rpc message, or similar.
///
/// Note: to directly initiate the terminal using the right size, display the
@@ -1290,7 +1244,7 @@ Integer nvim_open_term(Buffer buffer, Dictionary opts, Error *err)
TerminalOptions topts;
Channel *chan = channel_alloc(kChannelStreamInternal);
topts.data = chan;
- // NB: overriden in terminal_check_size if a window is already
+ // NB: overridden in terminal_check_size if a window is already
// displaying the buffer
topts.width = (uint16_t)MAX(curwin->w_width_inner - win_col_off(curwin), 0);
topts.height = (uint16_t)curwin->w_height_inner;
@@ -1468,8 +1422,7 @@ void nvim_chan_send(Integer chan, String data, Error *err)
/// @param[out] err Error details, if any
///
/// @return Window handle, or 0 on error
-Window nvim_open_win(Buffer buffer, Boolean enter, Dictionary config,
- Error *err)
+Window nvim_open_win(Buffer buffer, Boolean enter, Dictionary config, Error *err)
FUNC_API_SINCE(6)
FUNC_API_CHECK_TEXTLOCK
{
@@ -1554,10 +1507,10 @@ void nvim_set_current_tabpage(Tabpage tabpage, Error *err)
}
}
-/// Creates a new namespace, or gets an existing one.
+/// Creates a new *namespace*, or gets an existing one.
///
/// Namespaces are used for buffer highlights and virtual text, see
-/// |nvim_buf_add_highlight()| and |nvim_buf_set_virtual_text()|.
+/// |nvim_buf_add_highlight()| and |nvim_buf_set_extmark()|.
///
/// Namespaces can be named or anonymous. If `name` matches an existing
/// namespace, the associated id is returned. If `name` is an empty string
@@ -1568,14 +1521,14 @@ void nvim_set_current_tabpage(Tabpage tabpage, Error *err)
Integer nvim_create_namespace(String name)
FUNC_API_SINCE(5)
{
- handle_T id = map_get(String, handle_T)(namespace_ids, name);
+ handle_T id = map_get(String, handle_T)(&namespace_ids, name);
if (id > 0) {
return id;
}
id = next_namespace_id++;
if (name.size > 0) {
String name_alloc = copy_string(name);
- map_put(String, handle_T)(namespace_ids, name_alloc, id);
+ map_put(String, handle_T)(&namespace_ids, name_alloc, id);
}
return (Integer)id;
}
@@ -1590,7 +1543,7 @@ Dictionary nvim_get_namespaces(void)
String name;
handle_T id;
- map_foreach(namespace_ids, name, id, {
+ map_foreach(&namespace_ids, name, id, {
PUT(retval, name.data, INTEGER_OBJ(id));
})
@@ -1627,7 +1580,7 @@ Boolean nvim_paste(String data, Boolean crlf, Integer phase, Error *err)
bool cancel = false;
if (phase < -1 || phase > 3) {
- api_set_error(err, kErrorTypeValidation, "Invalid phase: %"PRId64, phase);
+ api_set_error(err, kErrorTypeValidation, "Invalid phase: %" PRId64, phase);
return false;
}
Array args = ARRAY_DICT_INIT;
@@ -1691,12 +1644,11 @@ theend:
/// @param after If true insert after cursor (like |p|), or before (like |P|).
/// @param follow If true place cursor at end of inserted text.
/// @param[out] err Error details, if any
-void nvim_put(ArrayOf(String) lines, String type, Boolean after,
- Boolean follow, Error *err)
+void nvim_put(ArrayOf(String) lines, String type, Boolean after, Boolean follow, Error *err)
FUNC_API_SINCE(6)
FUNC_API_CHECK_TEXTLOCK
{
- yankreg_T *reg = xcalloc(sizeof(yankreg_T), 1);
+ yankreg_T *reg = xcalloc(1, sizeof(yankreg_T));
if (!prepare_yankreg_from_object(reg, type, lines.size)) {
api_set_error(err, kErrorTypeValidation, "Invalid type: '%s'", type.data);
goto cleanup;
@@ -1933,8 +1885,7 @@ ArrayOf(Dictionary) nvim_get_keymap(String mode)
/// as keys excluding |<buffer>| but including |noremap|.
/// Values are Booleans. Unknown key is an error.
/// @param[out] err Error details, if any.
-void nvim_set_keymap(String mode, String lhs, String rhs,
- Dictionary opts, Error *err)
+void nvim_set_keymap(String mode, String lhs, String rhs, Dictionary opts, Error *err)
FUNC_API_SINCE(6)
{
modify_keymap(-1, false, mode, lhs, rhs, opts, err);
@@ -2031,10 +1982,8 @@ Array nvim_get_api_info(uint64_t channel_id)
/// .png or .svg format is preferred.
///
/// @param[out] err Error details, if any
-void nvim_set_client_info(uint64_t channel_id, String name,
- Dictionary version, String type,
- Dictionary methods, Dictionary attributes,
- Error *err)
+void nvim_set_client_info(uint64_t channel_id, String name, Dictionary version, String type,
+ Dictionary methods, Dictionary attributes, Error *err)
FUNC_API_SINCE(4) FUNC_API_REMOTE_ONLY
{
Dictionary info = ARRAY_DICT_INIT;
@@ -2060,27 +2009,28 @@ void nvim_set_client_info(uint64_t channel_id, String name,
rpc_set_client_info(channel_id, info);
}
-/// Get information about a channel.
+/// Gets information about a channel.
///
/// @returns Dictionary describing a channel, with these keys:
-/// - "stream" the stream underlying the channel
+/// - "id" Channel id.
+/// - "argv" (optional) Job arguments list.
+/// - "stream" Stream underlying the channel.
/// - "stdio" stdin and stdout of this Nvim instance
/// - "stderr" stderr of this Nvim instance
/// - "socket" TCP/IP socket or named pipe
-/// - "job" job with communication over its stdio
-/// - "mode" how data received on the channel is interpreted
-/// - "bytes" send and receive raw bytes
-/// - "terminal" a |terminal| instance interprets ASCII sequences
-/// - "rpc" |RPC| communication on the channel is active
-/// - "pty" Name of pseudoterminal, if one is used (optional).
-/// On a POSIX system, this will be a device path like
-/// /dev/pts/1. Even if the name is unknown, the key will
-/// still be present to indicate a pty is used. This is
-/// currently the case when using winpty on windows.
-/// - "buffer" buffer with connected |terminal| instance (optional)
-/// - "client" information about the client on the other end of the
-/// RPC channel, if it has added it using
-/// |nvim_set_client_info()|. (optional)
+/// - "job" Job with communication over its stdio.
+/// - "mode" How data received on the channel is interpreted.
+/// - "bytes" Send and receive raw bytes.
+/// - "terminal" |terminal| instance interprets ASCII sequences.
+/// - "rpc" |RPC| communication on the channel is active.
+/// - "pty" (optional) Name of pseudoterminal. On a POSIX system this
+/// is a device path like "/dev/pts/1". If the name is unknown,
+/// the key will still be present if a pty is used (e.g. for
+/// winpty on Windows).
+/// - "buffer" (optional) Buffer with connected |terminal| instance.
+/// - "client" (optional) Info about the peer (client on the other end of
+/// the RPC channel), if provided by it via
+/// |nvim_set_client_info()|.
///
Dictionary nvim_get_chan_info(Integer chan, Error *err)
FUNC_API_SINCE(4)
@@ -2161,9 +2111,9 @@ Array nvim_call_atomic(uint64_t channel_id, Array calls, Error *err)
Array args = call.items[1].data.array;
MsgpackRpcRequestHandler handler =
- msgpack_rpc_get_handler_for(name.data,
- name.size,
- &nested_error);
+ msgpack_rpc_get_handler_for(name.data,
+ name.size,
+ &nested_error);
if (ERROR_SET(&nested_error)) {
break;
@@ -2237,7 +2187,7 @@ typedef kvec_withinit_t(ExprASTConvStackItem, 16) ExprASTConvStack;
/// - "arg": String, error message argument.
/// - "len": Amount of bytes successfully parsed. With flags equal to ""
/// that should be equal to the length of expr string.
-/// (“Sucessfully parsed” here means “participated in AST
+/// (“Successfully parsed” here means “participated in AST
/// creation”, not “till the first error”.)
/// - "ast": AST, either nil or a dictionary with these keys:
/// - "type": node type, one of the value names from ExprASTNodeType
@@ -2279,29 +2229,29 @@ typedef kvec_withinit_t(ExprASTConvStackItem, 16) ExprASTConvStack;
/// - "svalue": String, value for "SingleQuotedString" and
/// "DoubleQuotedString" nodes.
/// @param[out] err Error details, if any
-Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight,
- Error *err)
+Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight, Error *err)
FUNC_API_SINCE(4) FUNC_API_FAST
{
int pflags = 0;
for (size_t i = 0 ; i < flags.size ; i++) {
switch (flags.data[i]) {
- case 'm': { pflags |= kExprFlagsMulti; break; }
- case 'E': { pflags |= kExprFlagsDisallowEOC; break; }
- case 'l': { pflags |= kExprFlagsParseLet; break; }
- case NUL: {
- api_set_error(err, kErrorTypeValidation, "Invalid flag: '\\0' (%u)",
- (unsigned)flags.data[i]);
- return (Dictionary)ARRAY_DICT_INIT;
- }
- default: {
- api_set_error(err, kErrorTypeValidation, "Invalid flag: '%c' (%u)",
- flags.data[i], (unsigned)flags.data[i]);
- return (Dictionary)ARRAY_DICT_INIT;
- }
+ case 'm':
+ pflags |= kExprFlagsMulti; break;
+ case 'E':
+ pflags |= kExprFlagsDisallowEOC; break;
+ case 'l':
+ pflags |= kExprFlagsParseLet; break;
+ case NUL:
+ api_set_error(err, kErrorTypeValidation, "Invalid flag: '\\0' (%u)",
+ (unsigned)flags.data[i]);
+ return (Dictionary)ARRAY_DICT_INIT;
+ default:
+ api_set_error(err, kErrorTypeValidation, "Invalid flag: '%c' (%u)",
+ flags.data[i], (unsigned)flags.data[i]);
+ return (Dictionary)ARRAY_DICT_INIT;
}
}
- ParserLine plines[] = {
+ ParserLine parser_lines[] = {
{
.data = expr.data,
.size = expr.size,
@@ -2309,20 +2259,19 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight,
},
{ NULL, 0, false },
};
- ParserLine *plines_p = plines;
+ ParserLine *plines_p = parser_lines;
ParserHighlight colors;
kvi_init(colors);
ParserHighlight *const colors_p = (highlight ? &colors : NULL);
ParserState pstate;
- viml_parser_init(
- &pstate, parser_simple_get_line, &plines_p, colors_p);
+ viml_parser_init(&pstate, parser_simple_get_line, &plines_p, colors_p);
ExprAST east = viml_pexpr_parse(&pstate, pflags);
const size_t ret_size = (
- 2 // "ast", "len"
- + (size_t)(east.err.msg != NULL) // "error"
- + (size_t)highlight // "highlight"
- + 0);
+ 2 // "ast", "len"
+ + (size_t)(east.err.msg != NULL) // "error"
+ + (size_t)highlight // "highlight"
+ + 0);
Dictionary ret = {
.items = xmalloc(ret_size * sizeof(ret.items[0])),
.size = 0,
@@ -2335,7 +2284,7 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight,
ret.items[ret.size++] = (KeyValuePair) {
.key = STATIC_CSTR_TO_STRING("len"),
.value = INTEGER_OBJ((Integer)(pstate.pos.line == 1
- ? plines[0].size
+ ? parser_lines[0].size
: pstate.pos.col)),
};
if (east.err.msg != NULL) {
@@ -2409,23 +2358,23 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight,
} else {
if (cur_item.ret_node_p->type == kObjectTypeNil) {
const size_t ret_node_items_size = (size_t)(
- 3 // "type", "start" and "len"
- + (node->children != NULL) // "children"
- + (node->type == kExprNodeOption
- || node->type == kExprNodePlainIdentifier) // "scope"
- + (node->type == kExprNodeOption
- || node->type == kExprNodePlainIdentifier
- || node->type == kExprNodePlainKey
- || node->type == kExprNodeEnvironment) // "ident"
- + (node->type == kExprNodeRegister) // "name"
- + (3 // "cmp_type", "ccs_strategy", "invert"
- * (node->type == kExprNodeComparison))
- + (node->type == kExprNodeInteger) // "ivalue"
- + (node->type == kExprNodeFloat) // "fvalue"
- + (node->type == kExprNodeDoubleQuotedString
- || node->type == kExprNodeSingleQuotedString) // "svalue"
- + (node->type == kExprNodeAssignment) // "augmentation"
- + 0);
+ 3 // "type", "start" and "len"
+ + (node->children != NULL) // "children"
+ + (node->type == kExprNodeOption
+ || node->type == kExprNodePlainIdentifier) // "scope"
+ + (node->type == kExprNodeOption
+ || node->type == kExprNodePlainIdentifier
+ || node->type == kExprNodePlainKey
+ || node->type == kExprNodeEnvironment) // "ident"
+ + (node->type == kExprNodeRegister) // "name"
+ + (3 // "cmp_type", "ccs_strategy", "invert"
+ * (node->type == kExprNodeComparison))
+ + (node->type == kExprNodeInteger) // "ivalue"
+ + (node->type == kExprNodeFloat) // "fvalue"
+ + (node->type == kExprNodeDoubleQuotedString
+ || node->type == kExprNodeSingleQuotedString) // "svalue"
+ + (node->type == kExprNodeAssignment) // "augmentation"
+ + 0);
Dictionary ret_node = {
.items = xmalloc(ret_node_items_size * sizeof(ret_node.items[0])),
.capacity = ret_node_items_size,
@@ -2479,151 +2428,138 @@ Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight,
.value = INTEGER_OBJ((Integer)node->len),
};
switch (node->type) {
- case kExprNodeDoubleQuotedString:
- case kExprNodeSingleQuotedString: {
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("svalue"),
- .value = STRING_OBJ(((String) {
- .data = node->data.str.value,
- .size = node->data.str.size,
- })),
- };
- break;
- }
- case kExprNodeOption: {
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("scope"),
- .value = INTEGER_OBJ(node->data.opt.scope),
- };
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("ident"),
- .value = STRING_OBJ(((String) {
- .data = xmemdupz(node->data.opt.ident,
- node->data.opt.ident_len),
- .size = node->data.opt.ident_len,
- })),
- };
- break;
- }
- case kExprNodePlainIdentifier: {
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("scope"),
- .value = INTEGER_OBJ(node->data.var.scope),
- };
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("ident"),
- .value = STRING_OBJ(((String) {
- .data = xmemdupz(node->data.var.ident,
- node->data.var.ident_len),
- .size = node->data.var.ident_len,
- })),
- };
- break;
- }
- case kExprNodePlainKey: {
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("ident"),
- .value = STRING_OBJ(((String) {
- .data = xmemdupz(node->data.var.ident,
- node->data.var.ident_len),
- .size = node->data.var.ident_len,
- })),
- };
- break;
- }
- case kExprNodeEnvironment: {
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("ident"),
- .value = STRING_OBJ(((String) {
- .data = xmemdupz(node->data.env.ident,
- node->data.env.ident_len),
- .size = node->data.env.ident_len,
- })),
- };
- break;
- }
- case kExprNodeRegister: {
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("name"),
- .value = INTEGER_OBJ(node->data.reg.name),
- };
- break;
- }
- case kExprNodeComparison: {
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("cmp_type"),
- .value = STRING_OBJ(cstr_to_string(
- eltkn_cmp_type_tab[node->data.cmp.type])),
- };
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("ccs_strategy"),
- .value = STRING_OBJ(cstr_to_string(
- ccs_tab[node->data.cmp.ccs])),
- };
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("invert"),
- .value = BOOLEAN_OBJ(node->data.cmp.inv),
- };
- break;
- }
- case kExprNodeFloat: {
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("fvalue"),
- .value = FLOAT_OBJ(node->data.flt.value),
- };
- break;
- }
- case kExprNodeInteger: {
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("ivalue"),
- .value = INTEGER_OBJ((Integer)(
- node->data.num.value > API_INTEGER_MAX
+ case kExprNodeDoubleQuotedString:
+ case kExprNodeSingleQuotedString:
+ ret_node->items[ret_node->size++] = (KeyValuePair) {
+ .key = STATIC_CSTR_TO_STRING("svalue"),
+ .value = STRING_OBJ(((String) {
+ .data = node->data.str.value,
+ .size = node->data.str.size,
+ })),
+ };
+ break;
+ case kExprNodeOption:
+ ret_node->items[ret_node->size++] = (KeyValuePair) {
+ .key = STATIC_CSTR_TO_STRING("scope"),
+ .value = INTEGER_OBJ(node->data.opt.scope),
+ };
+ ret_node->items[ret_node->size++] = (KeyValuePair) {
+ .key = STATIC_CSTR_TO_STRING("ident"),
+ .value = STRING_OBJ(((String) {
+ .data = xmemdupz(node->data.opt.ident,
+ node->data.opt.ident_len),
+ .size = node->data.opt.ident_len,
+ })),
+ };
+ break;
+ case kExprNodePlainIdentifier:
+ ret_node->items[ret_node->size++] = (KeyValuePair) {
+ .key = STATIC_CSTR_TO_STRING("scope"),
+ .value = INTEGER_OBJ(node->data.var.scope),
+ };
+ ret_node->items[ret_node->size++] = (KeyValuePair) {
+ .key = STATIC_CSTR_TO_STRING("ident"),
+ .value = STRING_OBJ(((String) {
+ .data = xmemdupz(node->data.var.ident,
+ node->data.var.ident_len),
+ .size = node->data.var.ident_len,
+ })),
+ };
+ break;
+ case kExprNodePlainKey:
+ ret_node->items[ret_node->size++] = (KeyValuePair) {
+ .key = STATIC_CSTR_TO_STRING("ident"),
+ .value = STRING_OBJ(((String) {
+ .data = xmemdupz(node->data.var.ident,
+ node->data.var.ident_len),
+ .size = node->data.var.ident_len,
+ })),
+ };
+ break;
+ case kExprNodeEnvironment:
+ ret_node->items[ret_node->size++] = (KeyValuePair) {
+ .key = STATIC_CSTR_TO_STRING("ident"),
+ .value = STRING_OBJ(((String) {
+ .data = xmemdupz(node->data.env.ident,
+ node->data.env.ident_len),
+ .size = node->data.env.ident_len,
+ })),
+ };
+ break;
+ case kExprNodeRegister:
+ ret_node->items[ret_node->size++] = (KeyValuePair) {
+ .key = STATIC_CSTR_TO_STRING("name"),
+ .value = INTEGER_OBJ(node->data.reg.name),
+ };
+ break;
+ case kExprNodeComparison:
+ ret_node->items[ret_node->size++] = (KeyValuePair) {
+ .key = STATIC_CSTR_TO_STRING("cmp_type"),
+ .value = STRING_OBJ(cstr_to_string(eltkn_cmp_type_tab[node->data.cmp.type])),
+ };
+ ret_node->items[ret_node->size++] = (KeyValuePair) {
+ .key = STATIC_CSTR_TO_STRING("ccs_strategy"),
+ .value = STRING_OBJ(cstr_to_string(ccs_tab[node->data.cmp.ccs])),
+ };
+ ret_node->items[ret_node->size++] = (KeyValuePair) {
+ .key = STATIC_CSTR_TO_STRING("invert"),
+ .value = BOOLEAN_OBJ(node->data.cmp.inv),
+ };
+ break;
+ case kExprNodeFloat:
+ ret_node->items[ret_node->size++] = (KeyValuePair) {
+ .key = STATIC_CSTR_TO_STRING("fvalue"),
+ .value = FLOAT_OBJ(node->data.flt.value),
+ };
+ break;
+ case kExprNodeInteger:
+ ret_node->items[ret_node->size++] = (KeyValuePair) {
+ .key = STATIC_CSTR_TO_STRING("ivalue"),
+ .value = INTEGER_OBJ((Integer)(
+ node->data.num.value > API_INTEGER_MAX
? API_INTEGER_MAX
: (Integer)node->data.num.value)),
- };
- break;
- }
- case kExprNodeAssignment: {
- const ExprAssignmentType asgn_type = node->data.ass.type;
- ret_node->items[ret_node->size++] = (KeyValuePair) {
- .key = STATIC_CSTR_TO_STRING("augmentation"),
- .value = STRING_OBJ(
- asgn_type == kExprAsgnPlain
+ };
+ break;
+ case kExprNodeAssignment: {
+ const ExprAssignmentType asgn_type = node->data.ass.type;
+ ret_node->items[ret_node->size++] = (KeyValuePair) {
+ .key = STATIC_CSTR_TO_STRING("augmentation"),
+ .value = STRING_OBJ(asgn_type == kExprAsgnPlain
? (String)STRING_INIT
: cstr_to_string(expr_asgn_type_tab[asgn_type])),
- };
- break;
- }
- case kExprNodeMissing:
- case kExprNodeOpMissing:
- case kExprNodeTernary:
- case kExprNodeTernaryValue:
- case kExprNodeSubscript:
- case kExprNodeListLiteral:
- case kExprNodeUnaryPlus:
- case kExprNodeBinaryPlus:
- case kExprNodeNested:
- case kExprNodeCall:
- case kExprNodeComplexIdentifier:
- case kExprNodeUnknownFigure:
- case kExprNodeLambda:
- case kExprNodeDictLiteral:
- case kExprNodeCurlyBracesIdentifier:
- case kExprNodeComma:
- case kExprNodeColon:
- case kExprNodeArrow:
- case kExprNodeConcat:
- case kExprNodeConcatOrSubscript:
- case kExprNodeOr:
- case kExprNodeAnd:
- case kExprNodeUnaryMinus:
- case kExprNodeBinaryMinus:
- case kExprNodeNot:
- case kExprNodeMultiplication:
- case kExprNodeDivision:
- case kExprNodeMod: {
- break;
- }
+ };
+ break;
+ }
+ case kExprNodeMissing:
+ case kExprNodeOpMissing:
+ case kExprNodeTernary:
+ case kExprNodeTernaryValue:
+ case kExprNodeSubscript:
+ case kExprNodeListLiteral:
+ case kExprNodeUnaryPlus:
+ case kExprNodeBinaryPlus:
+ case kExprNodeNested:
+ case kExprNodeCall:
+ case kExprNodeComplexIdentifier:
+ case kExprNodeUnknownFigure:
+ case kExprNodeLambda:
+ case kExprNodeDictLiteral:
+ case kExprNodeCurlyBracesIdentifier:
+ case kExprNodeComma:
+ case kExprNodeColon:
+ case kExprNodeArrow:
+ case kExprNodeConcat:
+ case kExprNodeConcatOrSubscript:
+ case kExprNodeOr:
+ case kExprNodeAnd:
+ case kExprNodeUnaryMinus:
+ case kExprNodeBinaryMinus:
+ case kExprNodeNot:
+ case kExprNodeMultiplication:
+ case kExprNodeDivision:
+ case kExprNodeMod:
+ break;
}
assert(cur_item.ret_node_p->data.dictionary.size
== cur_item.ret_node_p->data.dictionary.capacity);
@@ -2853,8 +2789,8 @@ Object nvim_get_proc(Integer pid, Error *err)
/// `insert`.
/// @param opts Optional parameters. Reserved for future use.
/// @param[out] err Error details, if any
-void nvim_select_popupmenu_item(Integer item, Boolean insert, Boolean finish,
- Dictionary opts, Error *err)
+void nvim_select_popupmenu_item(Integer item, Boolean insert, Boolean finish, Dictionary opts,
+ Error *err)
FUNC_API_SINCE(6)
{
if (opts.size > 0) {
@@ -2925,7 +2861,7 @@ void nvim__screenshot(String path)
/// Note: this function should not be called often. Rather, the callbacks
/// themselves can be used to throttle unneeded callbacks. the `on_start`
/// callback can return `false` to disable the provider until the next redraw.
-/// Similarily, return `false` in `on_win` will skip the `on_lines` calls
+/// Similarly, return `false` in `on_win` will skip the `on_lines` calls
/// for that window (but any extmarks set in `on_win` will still be used).
/// A plugin managing multiple sources of decoration should ideally only set
/// one provider, and merge the sources internally. You can use multiple `ns_id`
@@ -2951,8 +2887,7 @@ void nvim__screenshot(String path)
/// ["win", winid, bufnr, row]
/// - on_end: called at the end of a redraw cycle
/// ["end", tick]
-void nvim_set_decoration_provider(Integer ns_id, DictionaryOf(LuaRef) opts,
- Error *err)
+void nvim_set_decoration_provider(Integer ns_id, DictionaryOf(LuaRef) opts, Error *err)
FUNC_API_SINCE(7) FUNC_API_LUA_ONLY
{
DecorProvider *p = get_decor_provider((NS)ns_id, true);
diff --git a/src/nvim/api/vim.h b/src/nvim/api/vim.h
index d6873da6d2..4fd353ce5c 100644
--- a/src/nvim/api/vim.h
+++ b/src/nvim/api/vim.h
@@ -6,7 +6,7 @@
#include "nvim/api/private/defs.h"
#include "nvim/map.h"
-EXTERN Map(String, handle_T) *namespace_ids INIT(= NULL);
+EXTERN Map(String, handle_T) namespace_ids INIT(= MAP_INIT);
EXTERN handle_T next_namespace_id INIT(= 1);
#ifdef INCLUDE_GENERATED_DECLARATIONS
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index 094328b5b0..99ba297111 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -1,25 +1,25 @@
// 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 <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
-#include <limits.h>
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
-#include "nvim/lua/executor.h"
-#include "nvim/ex_docmd.h"
-#include "nvim/vim.h"
#include "nvim/api/window.h"
#include "nvim/ascii.h"
#include "nvim/buffer.h"
#include "nvim/cursor.h"
+#include "nvim/ex_docmd.h"
#include "nvim/globals.h"
+#include "nvim/lua/executor.h"
#include "nvim/move.h"
#include "nvim/option.h"
#include "nvim/screen.h"
#include "nvim/syntax.h"
+#include "nvim/vim.h"
#include "nvim/window.h"
/// Gets the current buffer in a window
@@ -222,7 +222,7 @@ Object nvim_win_get_var(Window window, String name, Error *err)
win_T *win = find_window_by_handle(window, err);
if (!win) {
- return (Object) OBJECT_INIT;
+ return (Object)OBJECT_INIT;
}
return dict_get_value(win->w_vars, name, err);
@@ -275,7 +275,7 @@ Object nvim_win_get_option(Window window, String name, Error *err)
win_T *win = find_window_by_handle(window, err);
if (!win) {
- return (Object) OBJECT_INIT;
+ return (Object)OBJECT_INIT;
}
return get_option_from(win, SREQ_WIN, name, err);
@@ -289,8 +289,7 @@ Object nvim_win_get_option(Window window, String name, Error *err)
/// @param name Option name
/// @param value Option value
/// @param[out] err Error details, if any
-void nvim_win_set_option(uint64_t channel_id, Window window,
- String name, Object value, Error *err)
+void nvim_win_set_option(uint64_t channel_id, Window window, String name, Object value, Error *err)
FUNC_API_SINCE(1)
{
win_T *win = find_window_by_handle(window, err);
@@ -394,7 +393,7 @@ void nvim_win_set_config(Window window, Dictionary config, Error *err)
return;
}
bool new_float = !win->w_floating;
- // reuse old values, if not overriden
+ // reuse old values, if not overridden
FloatConfig fconfig = new_float ? FLOAT_CONFIG_INIT : win->w_float_config;
if (!parse_float_config(config, &fconfig, !new_float, false, err)) {
@@ -452,8 +451,7 @@ Dictionary nvim_win_get_config(Window window, Error *err)
PUT(rv, "bufpos", ARRAY_OBJ(pos));
}
}
- PUT(rv, "anchor", STRING_OBJ(cstr_to_string(
- float_anchor_str[config->anchor])));
+ PUT(rv, "anchor", STRING_OBJ(cstr_to_string(float_anchor_str[config->anchor])));
PUT(rv, "row", FLOAT_OBJ(config->row));
PUT(rv, "col", FLOAT_OBJ(config->col));
PUT(rv, "zindex", INTEGER_OBJ(config->zindex));
@@ -463,8 +461,7 @@ Dictionary nvim_win_get_config(Window window, Error *err)
for (size_t i = 0; i < 8; i++) {
Array tuple = ARRAY_DICT_INIT;
- String s = cstrn_to_string(
- (const char *)config->border_chars[i], sizeof(schar_T));
+ String s = cstrn_to_string((const char *)config->border_chars[i], sizeof(schar_T));
int hi_id = config->border_hl_ids[i];
char_u *hi_name = syn_id2name(hi_id);
diff --git a/src/nvim/arabic.c b/src/nvim/arabic.c
index 9fba38a49f..5dcc3d3d0d 100644
--- a/src/nvim/arabic.c
+++ b/src/nvim/arabic.c
@@ -15,9 +15,9 @@
#include <stdbool.h>
-#include "nvim/vim.h"
-#include "nvim/ascii.h"
#include "nvim/arabic.h"
+#include "nvim/ascii.h"
+#include "nvim/vim.h"
// Arabic ISO-10646-1 character set definition
@@ -253,44 +253,44 @@
static bool A_is_a(int cur_c)
{
switch (cur_c) {
- case a_HAMZA:
- case a_ALEF_MADDA:
- case a_ALEF_HAMZA_ABOVE:
- case a_WAW_HAMZA:
- case a_ALEF_HAMZA_BELOW:
- case a_YEH_HAMZA:
- case a_ALEF:
- case a_BEH:
- case a_TEH_MARBUTA:
- case a_TEH:
- case a_THEH:
- case a_JEEM:
- case a_HAH:
- case a_KHAH:
- case a_DAL:
- case a_THAL:
- case a_REH:
- case a_ZAIN:
- case a_SEEN:
- case a_SHEEN:
- case a_SAD:
- case a_DAD:
- case a_TAH:
- case a_ZAH:
- case a_AIN:
- case a_GHAIN:
- case a_TATWEEL:
- case a_FEH:
- case a_QAF:
- case a_KAF:
- case a_LAM:
- case a_MEEM:
- case a_NOON:
- case a_HEH:
- case a_WAW:
- case a_ALEF_MAKSURA:
- case a_YEH:
- return true;
+ case a_HAMZA:
+ case a_ALEF_MADDA:
+ case a_ALEF_HAMZA_ABOVE:
+ case a_WAW_HAMZA:
+ case a_ALEF_HAMZA_BELOW:
+ case a_YEH_HAMZA:
+ case a_ALEF:
+ case a_BEH:
+ case a_TEH_MARBUTA:
+ case a_TEH:
+ case a_THEH:
+ case a_JEEM:
+ case a_HAH:
+ case a_KHAH:
+ case a_DAL:
+ case a_THAL:
+ case a_REH:
+ case a_ZAIN:
+ case a_SEEN:
+ case a_SHEEN:
+ case a_SAD:
+ case a_DAD:
+ case a_TAH:
+ case a_ZAH:
+ case a_AIN:
+ case a_GHAIN:
+ case a_TATWEEL:
+ case a_FEH:
+ case a_QAF:
+ case a_KAF:
+ case a_LAM:
+ case a_MEEM:
+ case a_NOON:
+ case a_HEH:
+ case a_WAW:
+ case a_ALEF_MAKSURA:
+ case a_YEH:
+ return true;
}
return false;
@@ -300,43 +300,43 @@ static bool A_is_a(int cur_c)
static bool A_is_s(int cur_c)
{
switch (cur_c) {
- case a_s_HAMZA:
- case a_s_ALEF_MADDA:
- case a_s_ALEF_HAMZA_ABOVE:
- case a_s_WAW_HAMZA:
- case a_s_ALEF_HAMZA_BELOW:
- case a_s_YEH_HAMZA:
- case a_s_ALEF:
- case a_s_BEH:
- case a_s_TEH_MARBUTA:
- case a_s_TEH:
- case a_s_THEH:
- case a_s_JEEM:
- case a_s_HAH:
- case a_s_KHAH:
- case a_s_DAL:
- case a_s_THAL:
- case a_s_REH:
- case a_s_ZAIN:
- case a_s_SEEN:
- case a_s_SHEEN:
- case a_s_SAD:
- case a_s_DAD:
- case a_s_TAH:
- case a_s_ZAH:
- case a_s_AIN:
- case a_s_GHAIN:
- case a_s_FEH:
- case a_s_QAF:
- case a_s_KAF:
- case a_s_LAM:
- case a_s_MEEM:
- case a_s_NOON:
- case a_s_HEH:
- case a_s_WAW:
- case a_s_ALEF_MAKSURA:
- case a_s_YEH:
- return true;
+ case a_s_HAMZA:
+ case a_s_ALEF_MADDA:
+ case a_s_ALEF_HAMZA_ABOVE:
+ case a_s_WAW_HAMZA:
+ case a_s_ALEF_HAMZA_BELOW:
+ case a_s_YEH_HAMZA:
+ case a_s_ALEF:
+ case a_s_BEH:
+ case a_s_TEH_MARBUTA:
+ case a_s_TEH:
+ case a_s_THEH:
+ case a_s_JEEM:
+ case a_s_HAH:
+ case a_s_KHAH:
+ case a_s_DAL:
+ case a_s_THAL:
+ case a_s_REH:
+ case a_s_ZAIN:
+ case a_s_SEEN:
+ case a_s_SHEEN:
+ case a_s_SAD:
+ case a_s_DAD:
+ case a_s_TAH:
+ case a_s_ZAH:
+ case a_s_AIN:
+ case a_s_GHAIN:
+ case a_s_FEH:
+ case a_s_QAF:
+ case a_s_KAF:
+ case a_s_LAM:
+ case a_s_MEEM:
+ case a_s_NOON:
+ case a_s_HEH:
+ case a_s_WAW:
+ case a_s_ALEF_MAKSURA:
+ case a_s_YEH:
+ return true;
}
return false;
@@ -346,46 +346,46 @@ static bool A_is_s(int cur_c)
static bool A_is_f(int cur_c)
{
switch (cur_c) {
- case a_f_ALEF_MADDA:
- case a_f_ALEF_HAMZA_ABOVE:
- case a_f_WAW_HAMZA:
- case a_f_ALEF_HAMZA_BELOW:
- case a_f_YEH_HAMZA:
- case a_f_ALEF:
- case a_f_BEH:
- case a_f_TEH_MARBUTA:
- case a_f_TEH:
- case a_f_THEH:
- case a_f_JEEM:
- case a_f_HAH:
- case a_f_KHAH:
- case a_f_DAL:
- case a_f_THAL:
- case a_f_REH:
- case a_f_ZAIN:
- case a_f_SEEN:
- case a_f_SHEEN:
- case a_f_SAD:
- case a_f_DAD:
- case a_f_TAH:
- case a_f_ZAH:
- case a_f_AIN:
- case a_f_GHAIN:
- case a_f_FEH:
- case a_f_QAF:
- case a_f_KAF:
- case a_f_LAM:
- case a_f_MEEM:
- case a_f_NOON:
- case a_f_HEH:
- case a_f_WAW:
- case a_f_ALEF_MAKSURA:
- case a_f_YEH:
- case a_f_LAM_ALEF_MADDA_ABOVE:
- case a_f_LAM_ALEF_HAMZA_ABOVE:
- case a_f_LAM_ALEF_HAMZA_BELOW:
- case a_f_LAM_ALEF:
- return true;
+ case a_f_ALEF_MADDA:
+ case a_f_ALEF_HAMZA_ABOVE:
+ case a_f_WAW_HAMZA:
+ case a_f_ALEF_HAMZA_BELOW:
+ case a_f_YEH_HAMZA:
+ case a_f_ALEF:
+ case a_f_BEH:
+ case a_f_TEH_MARBUTA:
+ case a_f_TEH:
+ case a_f_THEH:
+ case a_f_JEEM:
+ case a_f_HAH:
+ case a_f_KHAH:
+ case a_f_DAL:
+ case a_f_THAL:
+ case a_f_REH:
+ case a_f_ZAIN:
+ case a_f_SEEN:
+ case a_f_SHEEN:
+ case a_f_SAD:
+ case a_f_DAD:
+ case a_f_TAH:
+ case a_f_ZAH:
+ case a_f_AIN:
+ case a_f_GHAIN:
+ case a_f_FEH:
+ case a_f_QAF:
+ case a_f_KAF:
+ case a_f_LAM:
+ case a_f_MEEM:
+ case a_f_NOON:
+ case a_f_HEH:
+ case a_f_WAW:
+ case a_f_ALEF_MAKSURA:
+ case a_f_YEH:
+ case a_f_LAM_ALEF_MADDA_ABOVE:
+ case a_f_LAM_ALEF_HAMZA_ABOVE:
+ case a_f_LAM_ALEF_HAMZA_BELOW:
+ case a_f_LAM_ALEF:
+ return true;
}
return false;
}
@@ -394,43 +394,80 @@ static bool A_is_f(int cur_c)
static int chg_c_a2s(int cur_c)
{
switch (cur_c) {
- case a_HAMZA: return a_s_HAMZA;
- case a_ALEF_MADDA: return a_s_ALEF_MADDA;
- case a_ALEF_HAMZA_ABOVE: return a_s_ALEF_HAMZA_ABOVE;
- case a_WAW_HAMZA: return a_s_WAW_HAMZA;
- case a_ALEF_HAMZA_BELOW: return a_s_ALEF_HAMZA_BELOW;
- case a_YEH_HAMZA: return a_s_YEH_HAMZA;
- case a_ALEF: return a_s_ALEF;
- case a_TEH_MARBUTA: return a_s_TEH_MARBUTA;
- case a_DAL: return a_s_DAL;
- case a_THAL: return a_s_THAL;
- case a_REH: return a_s_REH;
- case a_ZAIN: return a_s_ZAIN;
- case a_TATWEEL: return cur_c; // exceptions
- case a_WAW: return a_s_WAW;
- case a_ALEF_MAKSURA: return a_s_ALEF_MAKSURA;
- case a_BEH: return a_s_BEH;
- case a_TEH: return a_s_TEH;
- case a_THEH: return a_s_THEH;
- case a_JEEM: return a_s_JEEM;
- case a_HAH: return a_s_HAH;
- case a_KHAH: return a_s_KHAH;
- case a_SEEN: return a_s_SEEN;
- case a_SHEEN: return a_s_SHEEN;
- case a_SAD: return a_s_SAD;
- case a_DAD: return a_s_DAD;
- case a_TAH: return a_s_TAH;
- case a_ZAH: return a_s_ZAH;
- case a_AIN: return a_s_AIN;
- case a_GHAIN: return a_s_GHAIN;
- case a_FEH: return a_s_FEH;
- case a_QAF: return a_s_QAF;
- case a_KAF: return a_s_KAF;
- case a_LAM: return a_s_LAM;
- case a_MEEM: return a_s_MEEM;
- case a_NOON: return a_s_NOON;
- case a_HEH: return a_s_HEH;
- case a_YEH: return a_s_YEH;
+ case a_HAMZA:
+ return a_s_HAMZA;
+ case a_ALEF_MADDA:
+ return a_s_ALEF_MADDA;
+ case a_ALEF_HAMZA_ABOVE:
+ return a_s_ALEF_HAMZA_ABOVE;
+ case a_WAW_HAMZA:
+ return a_s_WAW_HAMZA;
+ case a_ALEF_HAMZA_BELOW:
+ return a_s_ALEF_HAMZA_BELOW;
+ case a_YEH_HAMZA:
+ return a_s_YEH_HAMZA;
+ case a_ALEF:
+ return a_s_ALEF;
+ case a_TEH_MARBUTA:
+ return a_s_TEH_MARBUTA;
+ case a_DAL:
+ return a_s_DAL;
+ case a_THAL:
+ return a_s_THAL;
+ case a_REH:
+ return a_s_REH;
+ case a_ZAIN:
+ return a_s_ZAIN;
+ case a_TATWEEL:
+ return cur_c; // exceptions
+ case a_WAW:
+ return a_s_WAW;
+ case a_ALEF_MAKSURA:
+ return a_s_ALEF_MAKSURA;
+ case a_BEH:
+ return a_s_BEH;
+ case a_TEH:
+ return a_s_TEH;
+ case a_THEH:
+ return a_s_THEH;
+ case a_JEEM:
+ return a_s_JEEM;
+ case a_HAH:
+ return a_s_HAH;
+ case a_KHAH:
+ return a_s_KHAH;
+ case a_SEEN:
+ return a_s_SEEN;
+ case a_SHEEN:
+ return a_s_SHEEN;
+ case a_SAD:
+ return a_s_SAD;
+ case a_DAD:
+ return a_s_DAD;
+ case a_TAH:
+ return a_s_TAH;
+ case a_ZAH:
+ return a_s_ZAH;
+ case a_AIN:
+ return a_s_AIN;
+ case a_GHAIN:
+ return a_s_GHAIN;
+ case a_FEH:
+ return a_s_FEH;
+ case a_QAF:
+ return a_s_QAF;
+ case a_KAF:
+ return a_s_KAF;
+ case a_LAM:
+ return a_s_LAM;
+ case a_MEEM:
+ return a_s_MEEM;
+ case a_NOON:
+ return a_s_NOON;
+ case a_HEH:
+ return a_s_HEH;
+ case a_YEH:
+ return a_s_YEH;
}
return 0;
}
@@ -439,43 +476,80 @@ static int chg_c_a2s(int cur_c)
static int chg_c_a2i(int cur_c)
{
switch (cur_c) {
- case a_YEH_HAMZA: return a_i_YEH_HAMZA;
- case a_HAMZA: return a_s_HAMZA; // exceptions
- case a_ALEF_MADDA: return a_s_ALEF_MADDA; // exceptions
- case a_ALEF_HAMZA_ABOVE: return a_s_ALEF_HAMZA_ABOVE; // exceptions
- case a_WAW_HAMZA: return a_s_WAW_HAMZA; // exceptions
- case a_ALEF_HAMZA_BELOW: return a_s_ALEF_HAMZA_BELOW; // exceptions
- case a_ALEF: return a_s_ALEF; // exceptions
- case a_TEH_MARBUTA: return a_s_TEH_MARBUTA; // exceptions
- case a_DAL: return a_s_DAL; // exceptions
- case a_THAL: return a_s_THAL; // exceptions
- case a_REH: return a_s_REH; // exceptions
- case a_ZAIN: return a_s_ZAIN; // exceptions
- case a_TATWEEL: return cur_c; // exceptions
- case a_WAW: return a_s_WAW; // exceptions
- case a_ALEF_MAKSURA: return a_s_ALEF_MAKSURA; // exceptions
- case a_BEH: return a_i_BEH;
- case a_TEH: return a_i_TEH;
- case a_THEH: return a_i_THEH;
- case a_JEEM: return a_i_JEEM;
- case a_HAH: return a_i_HAH;
- case a_KHAH: return a_i_KHAH;
- case a_SEEN: return a_i_SEEN;
- case a_SHEEN: return a_i_SHEEN;
- case a_SAD: return a_i_SAD;
- case a_DAD: return a_i_DAD;
- case a_TAH: return a_i_TAH;
- case a_ZAH: return a_i_ZAH;
- case a_AIN: return a_i_AIN;
- case a_GHAIN: return a_i_GHAIN;
- case a_FEH: return a_i_FEH;
- case a_QAF: return a_i_QAF;
- case a_KAF: return a_i_KAF;
- case a_LAM: return a_i_LAM;
- case a_MEEM: return a_i_MEEM;
- case a_NOON: return a_i_NOON;
- case a_HEH: return a_i_HEH;
- case a_YEH: return a_i_YEH;
+ case a_YEH_HAMZA:
+ return a_i_YEH_HAMZA;
+ case a_HAMZA:
+ return a_s_HAMZA; // exceptions
+ case a_ALEF_MADDA:
+ return a_s_ALEF_MADDA; // exceptions
+ case a_ALEF_HAMZA_ABOVE:
+ return a_s_ALEF_HAMZA_ABOVE; // exceptions
+ case a_WAW_HAMZA:
+ return a_s_WAW_HAMZA; // exceptions
+ case a_ALEF_HAMZA_BELOW:
+ return a_s_ALEF_HAMZA_BELOW; // exceptions
+ case a_ALEF:
+ return a_s_ALEF; // exceptions
+ case a_TEH_MARBUTA:
+ return a_s_TEH_MARBUTA; // exceptions
+ case a_DAL:
+ return a_s_DAL; // exceptions
+ case a_THAL:
+ return a_s_THAL; // exceptions
+ case a_REH:
+ return a_s_REH; // exceptions
+ case a_ZAIN:
+ return a_s_ZAIN; // exceptions
+ case a_TATWEEL:
+ return cur_c; // exceptions
+ case a_WAW:
+ return a_s_WAW; // exceptions
+ case a_ALEF_MAKSURA:
+ return a_s_ALEF_MAKSURA; // exceptions
+ case a_BEH:
+ return a_i_BEH;
+ case a_TEH:
+ return a_i_TEH;
+ case a_THEH:
+ return a_i_THEH;
+ case a_JEEM:
+ return a_i_JEEM;
+ case a_HAH:
+ return a_i_HAH;
+ case a_KHAH:
+ return a_i_KHAH;
+ case a_SEEN:
+ return a_i_SEEN;
+ case a_SHEEN:
+ return a_i_SHEEN;
+ case a_SAD:
+ return a_i_SAD;
+ case a_DAD:
+ return a_i_DAD;
+ case a_TAH:
+ return a_i_TAH;
+ case a_ZAH:
+ return a_i_ZAH;
+ case a_AIN:
+ return a_i_AIN;
+ case a_GHAIN:
+ return a_i_GHAIN;
+ case a_FEH:
+ return a_i_FEH;
+ case a_QAF:
+ return a_i_QAF;
+ case a_KAF:
+ return a_i_KAF;
+ case a_LAM:
+ return a_i_LAM;
+ case a_MEEM:
+ return a_i_MEEM;
+ case a_NOON:
+ return a_i_NOON;
+ case a_HEH:
+ return a_i_HEH;
+ case a_YEH:
+ return a_i_YEH;
}
return 0;
}
@@ -484,43 +558,80 @@ static int chg_c_a2i(int cur_c)
static int chg_c_a2m(int cur_c)
{
switch (cur_c) {
- case a_HAMZA: return a_s_HAMZA; // exception
- case a_ALEF_MADDA: return a_f_ALEF_MADDA; // exception
- case a_ALEF_HAMZA_ABOVE: return a_f_ALEF_HAMZA_ABOVE; // exception
- case a_WAW_HAMZA: return a_f_WAW_HAMZA; // exception
- case a_ALEF_HAMZA_BELOW: return a_f_ALEF_HAMZA_BELOW; // exception
- case a_YEH_HAMZA: return a_m_YEH_HAMZA;
- case a_ALEF: return a_f_ALEF; // exception
- case a_BEH: return a_m_BEH;
- case a_TEH_MARBUTA: return a_f_TEH_MARBUTA; // exception
- case a_TEH: return a_m_TEH;
- case a_THEH: return a_m_THEH;
- case a_JEEM: return a_m_JEEM;
- case a_HAH: return a_m_HAH;
- case a_KHAH: return a_m_KHAH;
- case a_DAL: return a_f_DAL; // exception
- case a_THAL: return a_f_THAL; // exception
- case a_REH: return a_f_REH; // exception
- case a_ZAIN: return a_f_ZAIN; // exception
- case a_SEEN: return a_m_SEEN;
- case a_SHEEN: return a_m_SHEEN;
- case a_SAD: return a_m_SAD;
- case a_DAD: return a_m_DAD;
- case a_TAH: return a_m_TAH;
- case a_ZAH: return a_m_ZAH;
- case a_AIN: return a_m_AIN;
- case a_GHAIN: return a_m_GHAIN;
- case a_TATWEEL: return cur_c; // exception
- case a_FEH: return a_m_FEH;
- case a_QAF: return a_m_QAF;
- case a_KAF: return a_m_KAF;
- case a_LAM: return a_m_LAM;
- case a_MEEM: return a_m_MEEM;
- case a_NOON: return a_m_NOON;
- case a_HEH: return a_m_HEH;
- case a_WAW: return a_f_WAW; // exception
- case a_ALEF_MAKSURA: return a_f_ALEF_MAKSURA; // exception
- case a_YEH: return a_m_YEH;
+ case a_HAMZA:
+ return a_s_HAMZA; // exception
+ case a_ALEF_MADDA:
+ return a_f_ALEF_MADDA; // exception
+ case a_ALEF_HAMZA_ABOVE:
+ return a_f_ALEF_HAMZA_ABOVE; // exception
+ case a_WAW_HAMZA:
+ return a_f_WAW_HAMZA; // exception
+ case a_ALEF_HAMZA_BELOW:
+ return a_f_ALEF_HAMZA_BELOW; // exception
+ case a_YEH_HAMZA:
+ return a_m_YEH_HAMZA;
+ case a_ALEF:
+ return a_f_ALEF; // exception
+ case a_BEH:
+ return a_m_BEH;
+ case a_TEH_MARBUTA:
+ return a_f_TEH_MARBUTA; // exception
+ case a_TEH:
+ return a_m_TEH;
+ case a_THEH:
+ return a_m_THEH;
+ case a_JEEM:
+ return a_m_JEEM;
+ case a_HAH:
+ return a_m_HAH;
+ case a_KHAH:
+ return a_m_KHAH;
+ case a_DAL:
+ return a_f_DAL; // exception
+ case a_THAL:
+ return a_f_THAL; // exception
+ case a_REH:
+ return a_f_REH; // exception
+ case a_ZAIN:
+ return a_f_ZAIN; // exception
+ case a_SEEN:
+ return a_m_SEEN;
+ case a_SHEEN:
+ return a_m_SHEEN;
+ case a_SAD:
+ return a_m_SAD;
+ case a_DAD:
+ return a_m_DAD;
+ case a_TAH:
+ return a_m_TAH;
+ case a_ZAH:
+ return a_m_ZAH;
+ case a_AIN:
+ return a_m_AIN;
+ case a_GHAIN:
+ return a_m_GHAIN;
+ case a_TATWEEL:
+ return cur_c; // exception
+ case a_FEH:
+ return a_m_FEH;
+ case a_QAF:
+ return a_m_QAF;
+ case a_KAF:
+ return a_m_KAF;
+ case a_LAM:
+ return a_m_LAM;
+ case a_MEEM:
+ return a_m_MEEM;
+ case a_NOON:
+ return a_m_NOON;
+ case a_HEH:
+ return a_m_HEH;
+ case a_WAW:
+ return a_f_WAW; // exception
+ case a_ALEF_MAKSURA:
+ return a_f_ALEF_MAKSURA; // exception
+ case a_YEH:
+ return a_m_YEH;
}
return 0;
}
@@ -538,43 +649,80 @@ static int chg_c_a2f(int cur_c)
// a_f_LAM_ALEF_HAMZA_BELOW;
switch (cur_c) {
- case a_HAMZA: return a_s_HAMZA; // exception
- case a_ALEF_MADDA: return a_f_ALEF_MADDA;
- case a_ALEF_HAMZA_ABOVE: return a_f_ALEF_HAMZA_ABOVE;
- case a_WAW_HAMZA: return a_f_WAW_HAMZA;
- case a_ALEF_HAMZA_BELOW: return a_f_ALEF_HAMZA_BELOW;
- case a_YEH_HAMZA: return a_f_YEH_HAMZA;
- case a_ALEF: return a_f_ALEF;
- case a_BEH: return a_f_BEH;
- case a_TEH_MARBUTA: return a_f_TEH_MARBUTA;
- case a_TEH: return a_f_TEH;
- case a_THEH: return a_f_THEH;
- case a_JEEM: return a_f_JEEM;
- case a_HAH: return a_f_HAH;
- case a_KHAH: return a_f_KHAH;
- case a_DAL: return a_f_DAL;
- case a_THAL: return a_f_THAL;
- case a_REH: return a_f_REH;
- case a_ZAIN: return a_f_ZAIN;
- case a_SEEN: return a_f_SEEN;
- case a_SHEEN: return a_f_SHEEN;
- case a_SAD: return a_f_SAD;
- case a_DAD: return a_f_DAD;
- case a_TAH: return a_f_TAH;
- case a_ZAH: return a_f_ZAH;
- case a_AIN: return a_f_AIN;
- case a_GHAIN: return a_f_GHAIN;
- case a_TATWEEL: return cur_c; // exception
- case a_FEH: return a_f_FEH;
- case a_QAF: return a_f_QAF;
- case a_KAF: return a_f_KAF;
- case a_LAM: return a_f_LAM;
- case a_MEEM: return a_f_MEEM;
- case a_NOON: return a_f_NOON;
- case a_HEH: return a_f_HEH;
- case a_WAW: return a_f_WAW;
- case a_ALEF_MAKSURA: return a_f_ALEF_MAKSURA;
- case a_YEH: return a_f_YEH;
+ case a_HAMZA:
+ return a_s_HAMZA; // exception
+ case a_ALEF_MADDA:
+ return a_f_ALEF_MADDA;
+ case a_ALEF_HAMZA_ABOVE:
+ return a_f_ALEF_HAMZA_ABOVE;
+ case a_WAW_HAMZA:
+ return a_f_WAW_HAMZA;
+ case a_ALEF_HAMZA_BELOW:
+ return a_f_ALEF_HAMZA_BELOW;
+ case a_YEH_HAMZA:
+ return a_f_YEH_HAMZA;
+ case a_ALEF:
+ return a_f_ALEF;
+ case a_BEH:
+ return a_f_BEH;
+ case a_TEH_MARBUTA:
+ return a_f_TEH_MARBUTA;
+ case a_TEH:
+ return a_f_TEH;
+ case a_THEH:
+ return a_f_THEH;
+ case a_JEEM:
+ return a_f_JEEM;
+ case a_HAH:
+ return a_f_HAH;
+ case a_KHAH:
+ return a_f_KHAH;
+ case a_DAL:
+ return a_f_DAL;
+ case a_THAL:
+ return a_f_THAL;
+ case a_REH:
+ return a_f_REH;
+ case a_ZAIN:
+ return a_f_ZAIN;
+ case a_SEEN:
+ return a_f_SEEN;
+ case a_SHEEN:
+ return a_f_SHEEN;
+ case a_SAD:
+ return a_f_SAD;
+ case a_DAD:
+ return a_f_DAD;
+ case a_TAH:
+ return a_f_TAH;
+ case a_ZAH:
+ return a_f_ZAH;
+ case a_AIN:
+ return a_f_AIN;
+ case a_GHAIN:
+ return a_f_GHAIN;
+ case a_TATWEEL:
+ return cur_c; // exception
+ case a_FEH:
+ return a_f_FEH;
+ case a_QAF:
+ return a_f_QAF;
+ case a_KAF:
+ return a_f_KAF;
+ case a_LAM:
+ return a_f_LAM;
+ case a_MEEM:
+ return a_f_MEEM;
+ case a_NOON:
+ return a_f_NOON;
+ case a_HEH:
+ return a_f_HEH;
+ case a_WAW:
+ return a_f_WAW;
+ case a_ALEF_MAKSURA:
+ return a_f_ALEF_MAKSURA;
+ case a_YEH:
+ return a_f_YEH;
}
return 0;
}
@@ -586,29 +734,52 @@ static int chg_c_a2f(int cur_c)
static int chg_c_i2m(int cur_c)
{
switch (cur_c) {
- case a_i_YEH_HAMZA: return a_m_YEH_HAMZA;
- case a_i_BEH: return a_m_BEH;
- case a_i_TEH: return a_m_TEH;
- case a_i_THEH: return a_m_THEH;
- case a_i_JEEM: return a_m_JEEM;
- case a_i_HAH: return a_m_HAH;
- case a_i_KHAH: return a_m_KHAH;
- case a_i_SEEN: return a_m_SEEN;
- case a_i_SHEEN: return a_m_SHEEN;
- case a_i_SAD: return a_m_SAD;
- case a_i_DAD: return a_m_DAD;
- case a_i_TAH: return a_m_TAH;
- case a_i_ZAH: return a_m_ZAH;
- case a_i_AIN: return a_m_AIN;
- case a_i_GHAIN: return a_m_GHAIN;
- case a_i_FEH: return a_m_FEH;
- case a_i_QAF: return a_m_QAF;
- case a_i_KAF: return a_m_KAF;
- case a_i_LAM: return a_m_LAM;
- case a_i_MEEM: return a_m_MEEM;
- case a_i_NOON: return a_m_NOON;
- case a_i_HEH: return a_m_HEH;
- case a_i_YEH: return a_m_YEH;
+ case a_i_YEH_HAMZA:
+ return a_m_YEH_HAMZA;
+ case a_i_BEH:
+ return a_m_BEH;
+ case a_i_TEH:
+ return a_m_TEH;
+ case a_i_THEH:
+ return a_m_THEH;
+ case a_i_JEEM:
+ return a_m_JEEM;
+ case a_i_HAH:
+ return a_m_HAH;
+ case a_i_KHAH:
+ return a_m_KHAH;
+ case a_i_SEEN:
+ return a_m_SEEN;
+ case a_i_SHEEN:
+ return a_m_SHEEN;
+ case a_i_SAD:
+ return a_m_SAD;
+ case a_i_DAD:
+ return a_m_DAD;
+ case a_i_TAH:
+ return a_m_TAH;
+ case a_i_ZAH:
+ return a_m_ZAH;
+ case a_i_AIN:
+ return a_m_AIN;
+ case a_i_GHAIN:
+ return a_m_GHAIN;
+ case a_i_FEH:
+ return a_m_FEH;
+ case a_i_QAF:
+ return a_m_QAF;
+ case a_i_KAF:
+ return a_m_KAF;
+ case a_i_LAM:
+ return a_m_LAM;
+ case a_i_MEEM:
+ return a_m_MEEM;
+ case a_i_NOON:
+ return a_m_NOON;
+ case a_i_HEH:
+ return a_m_HEH;
+ case a_i_YEH:
+ return a_m_YEH;
}
return 0;
}
@@ -618,43 +789,66 @@ static int chg_c_i2m(int cur_c)
static int chg_c_f2m(int cur_c)
{
switch (cur_c) {
- // NOTE: these encodings are multi-positional, no ?
- // case a_f_ALEF_MADDA:
- // case a_f_ALEF_HAMZA_ABOVE:
- // case a_f_ALEF_HAMZA_BELOW:
- case a_f_YEH_HAMZA: return a_m_YEH_HAMZA;
- case a_f_WAW_HAMZA: // exceptions
- case a_f_ALEF:
- case a_f_TEH_MARBUTA:
- case a_f_DAL:
- case a_f_THAL:
- case a_f_REH:
- case a_f_ZAIN:
- case a_f_WAW:
- case a_f_ALEF_MAKSURA:
- return cur_c;
- case a_f_BEH: return a_m_BEH;
- case a_f_TEH: return a_m_TEH;
- case a_f_THEH: return a_m_THEH;
- case a_f_JEEM: return a_m_JEEM;
- case a_f_HAH: return a_m_HAH;
- case a_f_KHAH: return a_m_KHAH;
- case a_f_SEEN: return a_m_SEEN;
- case a_f_SHEEN: return a_m_SHEEN;
- case a_f_SAD: return a_m_SAD;
- case a_f_DAD: return a_m_DAD;
- case a_f_TAH: return a_m_TAH;
- case a_f_ZAH: return a_m_ZAH;
- case a_f_AIN: return a_m_AIN;
- case a_f_GHAIN: return a_m_GHAIN;
- case a_f_FEH: return a_m_FEH;
- case a_f_QAF: return a_m_QAF;
- case a_f_KAF: return a_m_KAF;
- case a_f_LAM: return a_m_LAM;
- case a_f_MEEM: return a_m_MEEM;
- case a_f_NOON: return a_m_NOON;
- case a_f_HEH: return a_m_HEH;
- case a_f_YEH: return a_m_YEH;
+ // NOTE: these encodings are multi-positional, no ?
+ // case a_f_ALEF_MADDA:
+ // case a_f_ALEF_HAMZA_ABOVE:
+ // case a_f_ALEF_HAMZA_BELOW:
+ case a_f_YEH_HAMZA:
+ return a_m_YEH_HAMZA;
+ case a_f_WAW_HAMZA: // exceptions
+ case a_f_ALEF:
+ case a_f_TEH_MARBUTA:
+ case a_f_DAL:
+ case a_f_THAL:
+ case a_f_REH:
+ case a_f_ZAIN:
+ case a_f_WAW:
+ case a_f_ALEF_MAKSURA:
+ return cur_c;
+ case a_f_BEH:
+ return a_m_BEH;
+ case a_f_TEH:
+ return a_m_TEH;
+ case a_f_THEH:
+ return a_m_THEH;
+ case a_f_JEEM:
+ return a_m_JEEM;
+ case a_f_HAH:
+ return a_m_HAH;
+ case a_f_KHAH:
+ return a_m_KHAH;
+ case a_f_SEEN:
+ return a_m_SEEN;
+ case a_f_SHEEN:
+ return a_m_SHEEN;
+ case a_f_SAD:
+ return a_m_SAD;
+ case a_f_DAD:
+ return a_m_DAD;
+ case a_f_TAH:
+ return a_m_TAH;
+ case a_f_ZAH:
+ return a_m_ZAH;
+ case a_f_AIN:
+ return a_m_AIN;
+ case a_f_GHAIN:
+ return a_m_GHAIN;
+ case a_f_FEH:
+ return a_m_FEH;
+ case a_f_QAF:
+ return a_m_QAF;
+ case a_f_KAF:
+ return a_m_KAF;
+ case a_f_LAM:
+ return a_m_LAM;
+ case a_f_MEEM:
+ return a_m_MEEM;
+ case a_f_NOON:
+ return a_m_NOON;
+ case a_f_HEH:
+ return a_m_HEH;
+ case a_f_YEH:
+ return a_m_YEH;
// NOTE: these encodings are multi-positional, no ?
// case a_f_LAM_ALEF_MADDA_ABOVE:
// case a_f_LAM_ALEF_HAMZA_ABOVE:
@@ -668,10 +862,14 @@ static int chg_c_f2m(int cur_c)
static int chg_c_laa2i(int hid_c)
{
switch (hid_c) {
- case a_ALEF_MADDA: return a_s_LAM_ALEF_MADDA_ABOVE;
- case a_ALEF_HAMZA_ABOVE: return a_s_LAM_ALEF_HAMZA_ABOVE;
- case a_ALEF_HAMZA_BELOW: return a_s_LAM_ALEF_HAMZA_BELOW;
- case a_ALEF: return a_s_LAM_ALEF;
+ case a_ALEF_MADDA:
+ return a_s_LAM_ALEF_MADDA_ABOVE;
+ case a_ALEF_HAMZA_ABOVE:
+ return a_s_LAM_ALEF_HAMZA_ABOVE;
+ case a_ALEF_HAMZA_BELOW:
+ return a_s_LAM_ALEF_HAMZA_BELOW;
+ case a_ALEF:
+ return a_s_LAM_ALEF;
}
return 0;
}
@@ -680,10 +878,14 @@ static int chg_c_laa2i(int hid_c)
static int chg_c_laa2f(int hid_c)
{
switch (hid_c) {
- case a_ALEF_MADDA: return a_f_LAM_ALEF_MADDA_ABOVE;
- case a_ALEF_HAMZA_ABOVE: return a_f_LAM_ALEF_HAMZA_ABOVE;
- case a_ALEF_HAMZA_BELOW: return a_f_LAM_ALEF_HAMZA_BELOW;
- case a_ALEF: return a_f_LAM_ALEF;
+ case a_ALEF_MADDA:
+ return a_f_LAM_ALEF_MADDA_ABOVE;
+ case a_ALEF_HAMZA_ABOVE:
+ return a_f_LAM_ALEF_HAMZA_ABOVE;
+ case a_ALEF_HAMZA_BELOW:
+ return a_f_LAM_ALEF_HAMZA_BELOW;
+ case a_ALEF:
+ return a_f_LAM_ALEF;
}
return 0;
}
@@ -708,8 +910,7 @@ static int half_shape(int c)
// in: "prev_c1" is the first composing char for the previous char
// (not shaped)
// in: "next_c" is the next character (not shaped).
-int arabic_shape(int c, int *ccp, int *c1p, int prev_c, int prev_c1,
- int next_c)
+int arabic_shape(int c, int *ccp, int *c1p, int prev_c, int prev_c1, int next_c)
{
// Deal only with Arabic character, pass back all others
if (!A_is_ok(c)) {
@@ -786,14 +987,14 @@ bool arabic_maycombine(int two)
{
if (p_arshape && !p_tbidi) {
return two == a_ALEF_MADDA
- || two == a_ALEF_HAMZA_ABOVE
- || two == a_ALEF_HAMZA_BELOW
- || two == a_ALEF;
+ || two == a_ALEF_HAMZA_ABOVE
+ || two == a_ALEF_HAMZA_BELOW
+ || two == a_ALEF;
}
return false;
}
-// A_firstc_laa returns first character of LAA combination if it ex.ists
+// A_firstc_laa returns first character of LAA combination if it exists
// in: "c" base character
// in: "c1" first composing character
static int A_firstc_laa(int c, int c1)
diff --git a/src/nvim/ascii.h b/src/nvim/ascii.h
index f41068ea70..7b5e82cd3f 100644
--- a/src/nvim/ascii.h
+++ b/src/nvim/ascii.h
@@ -169,6 +169,14 @@ static inline bool ascii_isbdigit(int c)
return (c == '0' || c == '1');
}
+/// Checks if `c` is an octal digit, that is, 0-7.
+///
+/// @see {ascii_isdigit}
+static inline bool ascii_isodigit(int c)
+{
+ return (c >= '0' && c <= '7');
+}
+
/// Checks if `c` is a white-space character, that is,
/// one of \f, \n, \r, \t, \v.
///
diff --git a/src/nvim/aucmd.c b/src/nvim/aucmd.c
index 32c77fa288..af519dcba9 100644
--- a/src/nvim/aucmd.c
+++ b/src/nvim/aucmd.c
@@ -1,15 +1,16 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
-#include "nvim/os/os.h"
-#include "nvim/fileio.h"
-#include "nvim/vim.h"
-#include "nvim/main.h"
-#include "nvim/ui.h"
#include "nvim/aucmd.h"
+#include "nvim/buffer.h"
#include "nvim/eval.h"
+#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
-#include "nvim/buffer.h"
+#include "nvim/fileio.h"
+#include "nvim/main.h"
+#include "nvim/os/os.h"
+#include "nvim/ui.h"
+#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "aucmd.c.generated.h"
@@ -35,6 +36,29 @@ void do_autocmd_uienter(uint64_t chanid, bool attached)
recursive = false;
}
+void init_default_autocmds(void)
+{
+ // open terminals when opening files that start with term://
+#define PROTO "term://"
+ do_cmdline_cmd("augroup nvim_terminal");
+ do_cmdline_cmd("autocmd BufReadCmd " PROTO "* ++nested "
+ "if !exists('b:term_title')|call termopen("
+ // Capture the command string
+ "matchstr(expand(\"<amatch>\"), "
+ "'\\c\\m" PROTO "\\%(.\\{-}//\\%(\\d\\+:\\)\\?\\)\\?\\zs.*'), "
+ // capture the working directory
+ "{'cwd': expand(get(matchlist(expand(\"<amatch>\"), "
+ "'\\c\\m" PROTO "\\(.\\{-}\\)//'), 1, ''))})"
+ "|endif");
+ do_cmdline_cmd("augroup END");
+#undef PROTO
+
+ // limit syntax synchronization in the command window
+ do_cmdline_cmd("augroup nvim_cmdwin");
+ do_cmdline_cmd("autocmd! CmdwinEnter [:>] syntax sync minlines=1 maxlines=1");
+ do_cmdline_cmd("augroup END");
+}
+
static void focusgained_event(void **argv)
{
bool *gainedp = argv[0];
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index 145f6f5601..e7b2ad9000 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -3,10 +3,9 @@
// autocmd.c: Autocommand related functions
-#include "nvim/autocmd.h"
-
-#include "nvim/api/private/handle.h"
+#include "nvim/api/private/helpers.h"
#include "nvim/ascii.h"
+#include "nvim/autocmd.h"
#include "nvim/buffer.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
@@ -25,8 +24,8 @@
#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
-#include "auevents_name_map.generated.h"
-#include "autocmd.c.generated.h"
+# include "auevents_name_map.generated.h"
+# include "autocmd.c.generated.h"
#endif
//
@@ -326,8 +325,7 @@ static void au_del_group(char_u *name)
event = (event_T)((int)event + 1)) {
for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next) {
if (ap->group == i && ap->pat != NULL) {
- give_warning(
- (char_u *)_("W19: Deleting augroup that is still in use"), true);
+ give_warning((char_u *)_("W19: Deleting augroup that is still in use"), true);
in_use = true;
event = NUM_EVENTS;
break;
@@ -761,13 +759,8 @@ static int au_get_grouparg(char_u **argp)
// If *cmd == NUL: show entries.
// If forceit == true: delete entries.
// If group is not AUGROUP_ALL: only use this group.
-static int do_autocmd_event(event_T event,
- char_u *pat,
- bool once,
- int nested,
- char_u *cmd,
- int forceit,
- int group)
+static int do_autocmd_event(event_T event, char_u *pat, bool once, int nested, char_u *cmd,
+ int forceit, int group)
{
AutoPat *ap;
AutoPat **prev_ap;
@@ -847,11 +840,10 @@ static int do_autocmd_event(event_T event,
if (is_buflocal) {
// normalize pat into standard "<buffer>#N" form
- snprintf(
- (char *)buflocal_pat,
- BUFLOCAL_PAT_LEN,
- "<buffer=%d>",
- buflocal_nr);
+ snprintf((char *)buflocal_pat,
+ BUFLOCAL_PAT_LEN,
+ "<buffer=%d>",
+ buflocal_nr);
pat = buflocal_pat; // can modify pat and patlen
patlen = (int)STRLEN(buflocal_pat); // but not endpat
@@ -889,7 +881,6 @@ static int do_autocmd_event(event_T event,
} else if (*cmd == NUL) {
// Show autocmd's for this autopat, or buflocals <buffer=X>
show_autocmd(ap, event);
-
} else if (ap->next == NULL) {
// Add autocmd to this autopat, if it's the last one.
break;
@@ -965,11 +956,11 @@ static int do_autocmd_event(event_T event,
return OK;
}
-// Implementation of ":doautocmd [group] event [fname]".
-// Return OK for success, FAIL for failure;
-int do_doautocmd(char_u *arg,
- bool do_msg, // give message for no matching autocmds?
- bool *did_something)
+/// Implementation of ":doautocmd [group] event [fname]".
+/// Return OK for success, FAIL for failure;
+///
+/// @param do_msg give message for no matching autocmds?
+int do_doautocmd(char_u *arg, bool do_msg, bool *did_something)
{
char_u *fname;
int nothing_done = true;
@@ -1150,7 +1141,7 @@ void aucmd_prepbuf(aco_save_T *aco, buf_T *buf)
block_autocmds(); // We don't want BufEnter/WinEnter autocommands.
if (need_append) {
win_append(lastwin, aucmd_win);
- handle_register_window(aucmd_win);
+ pmap_put(handle_T)(&window_handles, aucmd_win->handle, aucmd_win);
win_config_float(aucmd_win, aucmd_win->w_float_config);
}
// Prevent chdir() call in win_enter_ext(), through do_autochdir()
@@ -1188,10 +1179,10 @@ void aucmd_restbuf(aco_save_T *aco)
}
}
}
- win_found:
+win_found:
win_remove(curwin, NULL);
- handle_unregister_window(curwin);
+ pmap_del(handle_T)(&window_handles, curwin->handle);
if (curwin->w_grid_alloc.chars != NULL) {
ui_comp_remove_grid(&curwin->w_grid_alloc);
ui_call_win_hide(curwin->w_grid_alloc.handle);
@@ -1268,11 +1259,7 @@ void aucmd_restbuf(aco_save_T *aco)
/// @param buf Buffer for <abuf>
///
/// @return true if some commands were executed.
-bool apply_autocmds(event_T event,
- char_u *fname,
- char_u *fname_io,
- bool force,
- buf_T *buf)
+bool apply_autocmds(event_T event, char_u *fname, char_u *fname_io, bool force, buf_T *buf)
{
return apply_autocmds_group(event, fname, fname_io, force, AUGROUP_ALL, buf,
NULL);
@@ -1289,11 +1276,7 @@ bool apply_autocmds(event_T event,
/// @param exarg Ex command arguments
///
/// @return true if some commands were executed.
-bool apply_autocmds_exarg(event_T event,
- char_u *fname,
- char_u *fname_io,
- bool force,
- buf_T *buf,
+bool apply_autocmds_exarg(event_T event, char_u *fname, char_u *fname_io, bool force, buf_T *buf,
exarg_T *eap)
{
return apply_autocmds_group(event, fname, fname_io, force, AUGROUP_ALL, buf,
@@ -1313,11 +1296,7 @@ bool apply_autocmds_exarg(event_T event,
/// @param[in,out] retval caller's retval
///
/// @return true if some autocommands were executed
-bool apply_autocmds_retval(event_T event,
- char_u *fname,
- char_u *fname_io,
- bool force,
- buf_T *buf,
+bool apply_autocmds_retval(event_T event, char_u *fname, char_u *fname_io, bool force, buf_T *buf,
int *retval)
{
if (should_abort(*retval)) {
@@ -1344,8 +1323,7 @@ bool has_event(event_T event) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
/// the current mode.
bool has_cursorhold(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
- return has_event(
- (get_real_state() == NORMAL_BUSY ? EVENT_CURSORHOLD : EVENT_CURSORHOLDI));
+ return has_event((get_real_state() == NORMAL_BUSY ? EVENT_CURSORHOLD : EVENT_CURSORHOLDI));
// return first_autopat[] != NULL;
}
@@ -1376,13 +1354,8 @@ bool trigger_cursorhold(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
/// @param eap Ex command arguments
///
/// @return true if some commands were executed.
-static bool apply_autocmds_group(event_T event,
- char_u *fname,
- char_u *fname_io,
- bool force,
- int group,
- buf_T *buf,
- exarg_T *eap)
+static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io, bool force,
+ int group, buf_T *buf, exarg_T *eap)
{
char_u *sfname = NULL; // short file name
char_u *tail;
@@ -1724,7 +1697,7 @@ BYPASS_AU:
void block_autocmds(void)
{
// Remember the value of v:termresponse.
- if (is_autocmd_blocked()) {
+ if (!is_autocmd_blocked()) {
old_termresponse = get_vim_var_str(VV_TERMRESPONSE);
}
autocmd_blocked++;
@@ -1737,7 +1710,7 @@ void unblock_autocmds(void)
// When v:termresponse was set while autocommands were blocked, trigger
// the autocommands now. Esp. useful when executing a shell command
// during startup (nvim -d).
- if (is_autocmd_blocked()
+ if (!is_autocmd_blocked()
&& get_vim_var_str(VV_TERMRESPONSE) != old_termresponse) {
apply_autocmds(EVENT_TERMRESPONSE, NULL, NULL, false, curbuf);
}
@@ -1769,19 +1742,18 @@ void auto_next_pat(AutoPatCmd *apc, int stop_at_last)
&& (apc->group == AUGROUP_ALL || apc->group == ap->group)) {
// execution-condition
if (ap->buflocal_nr == 0
- ? match_file_pat(
- NULL,
- &ap->reg_prog,
- apc->fname,
- apc->sfname,
- apc->tail,
- ap->allow_dirs)
+ ? match_file_pat(NULL,
+ &ap->reg_prog,
+ apc->fname,
+ apc->sfname,
+ apc->tail,
+ ap->allow_dirs)
: ap->buflocal_nr == apc->arg_bufnr) {
const char *const name = event_nr2name(apc->event);
s = _("%s Autocommands for \"%s\"");
const size_t sourcing_name_len
- = (STRLEN(s) + strlen(name) + (size_t)ap->patlen + 1);
+ = (STRLEN(s) + strlen(name) + (size_t)ap->patlen + 1);
sourcing_name = xmalloc(sourcing_name_len);
snprintf((char *)sourcing_name, sourcing_name_len, s, name,
@@ -1885,9 +1857,7 @@ char_u *getnextac(int c, void *cookie, int indent, bool do_concat)
/// @param event event that occurred.
/// @param sfname filename the event occurred in.
/// @param buf buffer the file is open in
-bool has_autocmd(event_T event,
- char_u *sfname,
- buf_T *buf) FUNC_ATTR_WARN_UNUSED_RESULT
+bool has_autocmd(event_T event, char_u *sfname, buf_T *buf) FUNC_ATTR_WARN_UNUSED_RESULT
{
AutoPat *ap;
char_u *fname;
@@ -1910,13 +1880,12 @@ bool has_autocmd(event_T event,
for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next) {
if (ap->pat != NULL && ap->cmds != NULL
&& (ap->buflocal_nr == 0
- ? match_file_pat(
- NULL,
- &ap->reg_prog,
- fname,
- sfname,
- tail,
- ap->allow_dirs)
+ ? match_file_pat(NULL,
+ &ap->reg_prog,
+ fname,
+ sfname,
+ tail,
+ ap->allow_dirs)
: buf != NULL && ap->buflocal_nr == buf->b_fnum)) {
retval = true;
break;
@@ -1948,11 +1917,8 @@ char_u *get_augroup_name(expand_T *xp, int idx)
return (char_u *)AUGROUP_NAME(idx);
}
-char_u *set_context_in_autocmd(
- expand_T *xp,
- char_u *arg,
- int doautocmd // true for :doauto*, false for :autocmd
-)
+/// @param doautocmd true for :doauto*, false for :autocmd
+char_u *set_context_in_autocmd(expand_T *xp, char_u *arg, int doautocmd)
{
char_u *p;
int group;
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index f1f32076bf..3c86f55260 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -19,33 +19,34 @@
// The current implementation remembers all file names ever used.
//
+#include <assert.h>
+#include <inttypes.h>
#include <stdbool.h>
#include <string.h>
-#include <inttypes.h>
-#include <assert.h>
-#include "nvim/api/private/handle.h"
#include "nvim/api/private/helpers.h"
#include "nvim/api/vim.h"
#include "nvim/ascii.h"
#include "nvim/assert.h"
-#include "nvim/channel.h"
-#include "nvim/vim.h"
#include "nvim/buffer.h"
+#include "nvim/buffer_updates.h"
#include "nvim/change.h"
+#include "nvim/channel.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
#include "nvim/diff.h"
#include "nvim/digraph.h"
#include "nvim/eval.h"
-#include "nvim/ex_cmds2.h"
#include "nvim/ex_cmds.h"
+#include "nvim/ex_cmds2.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
#include "nvim/ex_getln.h"
-#include "nvim/fileio.h"
+#include "nvim/extmark.h"
#include "nvim/file_search.h"
+#include "nvim/fileio.h"
#include "nvim/fold.h"
+#include "nvim/garray.h"
#include "nvim/getchar.h"
#include "nvim/hashtab.h"
#include "nvim/highlight.h"
@@ -53,20 +54,22 @@
#include "nvim/indent_c.h"
#include "nvim/main.h"
#include "nvim/mark.h"
-#include "nvim/extmark.h"
#include "nvim/mbyte.h"
-#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
-#include "nvim/garray.h"
#include "nvim/move.h"
#include "nvim/option.h"
+#include "nvim/os/input.h"
+#include "nvim/os/os.h"
+#include "nvim/os/time.h"
#include "nvim/os_unix.h"
#include "nvim/path.h"
+#include "nvim/plines.h"
#include "nvim/quickfix.h"
#include "nvim/regexp.h"
#include "nvim/screen.h"
+#include "nvim/shada.h"
#include "nvim/sign.h"
#include "nvim/spell.h"
#include "nvim/strings.h"
@@ -74,12 +77,8 @@
#include "nvim/ui.h"
#include "nvim/undo.h"
#include "nvim/version.h"
+#include "nvim/vim.h"
#include "nvim/window.h"
-#include "nvim/shada.h"
-#include "nvim/os/os.h"
-#include "nvim/os/time.h"
-#include "nvim/os/input.h"
-#include "nvim/buffer_updates.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "buffer.c.generated.h"
@@ -100,15 +99,15 @@ typedef enum {
kBffInitChangedtick = 2,
} BufFreeFlags;
-// Read data from buffer for retrying.
-static int
-read_buffer(
- int read_stdin, // read file from stdin, otherwise fifo
- exarg_T *eap, // for forced 'ff' and 'fenc' or NULL
- int flags) // extra flags for readfile()
+/// Read data from buffer for retrying.
+///
+/// @param read_stdin read file from stdin, otherwise fifo
+/// @param eap for forced 'ff' and 'fenc' or NULL
+/// @param flags extra flags for readfile()
+static int read_buffer(int read_stdin, exarg_T *eap, int flags)
{
- int retval = OK;
- linenr_T line_count;
+ int retval = OK;
+ linenr_T line_count;
//
// Read from the buffer which the text is already filled in and append at
@@ -116,11 +115,10 @@ read_buffer(
// 'fileencoding' was guessed wrong.
//
line_count = curbuf->b_ml.ml_line_count;
- retval = readfile(
- read_stdin ? NULL : curbuf->b_ffname,
- read_stdin ? NULL : curbuf->b_fname,
- (linenr_T)line_count, (linenr_T)0, (linenr_T)MAXLNUM, eap,
- flags | READ_BUFFER);
+ retval = readfile(read_stdin ? NULL : curbuf->b_ffname,
+ read_stdin ? NULL : curbuf->b_fname,
+ (linenr_T)line_count, (linenr_T)0, (linenr_T)MAXLNUM, eap,
+ flags | READ_BUFFER);
if (retval == OK) {
// Delete the binary lines.
while (--line_count >= 0) {
@@ -139,7 +137,7 @@ read_buffer(
if (read_stdin) {
// Set or reset 'modified' before executing autocommands, so that
// it can be changed there.
- if (!readonlymode && !BUFEMPTY()) {
+ if (!readonlymode && !buf_is_empty(curbuf)) {
changed();
} else if (retval != FAIL) {
unchanged(curbuf, false, true);
@@ -151,17 +149,18 @@ read_buffer(
return retval;
}
-// Open current buffer, that is: open the memfile and read the file into
-// memory.
-// Return FAIL for failure, OK otherwise.
-int open_buffer(
- int read_stdin, // read file from stdin
- exarg_T *eap, // for forced 'ff' and 'fenc' or NULL
- int flags // extra flags for readfile()
-)
+/// Open current buffer, that is: open the memfile and read the file into
+/// memory.
+///
+/// @param read_stdin read file from stdin
+/// @param eap for forced 'ff' and 'fenc' or NULL
+/// @param flags extra flags for readfile()
+///
+/// @return FAIL for failure, OK otherwise.
+int open_buffer(int read_stdin, exarg_T *eap, int flags)
{
int retval = OK;
- bufref_T old_curbuf;
+ bufref_T old_curbuf;
long old_tw = curbuf->b_p_tw;
int read_fifo = false;
@@ -171,8 +170,9 @@ int open_buffer(
* user may have reset the flag by hand.
*/
if (readonlymode && curbuf->b_ffname != NULL
- && (curbuf->b_flags & BF_NEVERLOADED))
+ && (curbuf->b_flags & BF_NEVERLOADED)) {
curbuf->b_p_ro = true;
+ }
if (ml_open(curbuf) == FAIL) {
/*
@@ -229,8 +229,7 @@ int open_buffer(
|| (S_ISCHR(perm)
&& is_dev_fd_file(curbuf->b_ffname))
# endif
- )
- ) {
+ )) {
read_fifo = true;
}
if (read_fifo) {
@@ -269,8 +268,8 @@ int open_buffer(
*/
curbuf->b_p_bin = true;
retval = readfile(NULL, NULL, (linenr_T)0,
- (linenr_T)0, (linenr_T)MAXLNUM, NULL,
- flags | (READ_NEW + READ_STDIN));
+ (linenr_T)0, (linenr_T)MAXLNUM, NULL,
+ flags | (READ_NEW + READ_STDIN));
curbuf->b_p_bin = save_bin;
if (retval == OK) {
retval = read_buffer(true, eap, flags);
@@ -433,8 +432,9 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
del_buf = true;
unload_buf = true;
wipe_buf = true;
- } else if (buf->b_p_bh[0] == 'u') // 'bufhidden' == "unload"
+ } else if (buf->b_p_bh[0] == 'u') { // 'bufhidden' == "unload"
unload_buf = true;
+ }
}
if (buf->terminal && (unload_buf || del_buf || wipe_buf)) {
@@ -533,7 +533,7 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
}
if (buf->terminal) {
- terminal_close(buf->terminal, NULL);
+ terminal_close(buf->terminal, -1);
}
// Always remove the buffer when there is no file name.
@@ -541,12 +541,10 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last)
del_buf = true;
}
- /*
- * Free all things allocated for this buffer.
- * Also calls the "BufDelete" autocommands when del_buf is TRUE.
- */
- /* Remember if we are closing the current buffer. Restore the number of
- * windows, so that autocommands in buf_freeall() don't get confused. */
+ // Free all things allocated for this buffer.
+ // Also calls the "BufDelete" autocommands when del_buf is true.
+ // Remember if we are closing the current buffer. Restore the number of
+ // windows, so that autocommands in buf_freeall() don't get confused.
bool is_curbuf = (buf == curbuf);
// When closing the current buffer stop Visual mode before freeing
@@ -760,7 +758,7 @@ void buf_freeall(buf_T *buf, int flags)
*/
static void free_buffer(buf_T *buf)
{
- handle_unregister_buffer(buf);
+ pmap_del(handle_T)(&buffer_handles, buf->b_fnum);
buf_free_count++;
// b:changedtick uses an item in buf_T.
free_buffer_stuff(buf, kBffClearWinInfo);
@@ -810,8 +808,8 @@ static void free_buffer_stuff(buf_T *buf, int free_flags)
// Avoid losing b:changedtick when deleting buffer: clearing variables
// implies using clear_tv() on b:changedtick and that sets changedtick to
// zero.
- hashitem_T *const changedtick_hi = hash_find(
- &buf->b_vars->dv_hashtab, (const char_u *)"changedtick");
+ hashitem_T *const changedtick_hi = hash_find(&buf->b_vars->dv_hashtab,
+ (const char_u *)"changedtick");
assert(changedtick_hi != NULL);
hash_remove(&buf->b_vars->dv_hashtab, changedtick_hi);
}
@@ -823,6 +821,7 @@ static void free_buffer_stuff(buf_T *buf, int free_flags)
uc_clear(&buf->b_ucmds); // clear local user commands
buf_delete_signs(buf, (char_u *)"*"); // delete any signs
extmark_free_all(buf); // delete any extmarks
+ clear_virt_lines(buf, -1);
map_clear_int(buf, MAP_ALL_MODES, true, false); // clear local mappings
map_clear_int(buf, MAP_ALL_MODES, true, true); // clear local abbrevs
XFREE_CLEAR(buf->b_start_fenc);
@@ -835,7 +834,7 @@ static void free_buffer_stuff(buf_T *buf, int free_flags)
*/
static void clear_wininfo(buf_T *buf)
{
- wininfo_T *wip;
+ wininfo_T *wip;
while (buf->b_wininfo != NULL) {
wip = buf->b_wininfo;
@@ -901,7 +900,10 @@ void handle_swap_exists(bufref_T *old_curbuf)
if (old_curbuf == NULL
|| !bufref_valid(old_curbuf)
|| old_curbuf->br_buf == curbuf) {
+ // Block autocommands here because curwin->w_buffer is NULL.
+ block_autocmds();
buf = buflist_new(NULL, NULL, 1L, BLN_CURBUF | BLN_LISTED);
+ unblock_autocmds();
} else {
buf = old_curbuf->br_buf;
}
@@ -943,34 +945,28 @@ void handle_swap_exists(bufref_T *old_curbuf)
swap_exists_action = SEA_NONE; // -V519
}
-/*
- * do_bufdel() - delete or unload buffer(s)
- *
- * addr_count == 0: ":bdel" - delete current buffer
- * addr_count == 1: ":N bdel" or ":bdel N [N ..]" - first delete
- * buffer "end_bnr", then any other arguments.
- * addr_count == 2: ":N,N bdel" - delete buffers in range
- *
- * command can be DOBUF_UNLOAD (":bunload"), DOBUF_WIPE (":bwipeout") or
- * DOBUF_DEL (":bdel")
- *
- * Returns error message or NULL
- */
-char_u *
-do_bufdel(
- int command,
- char_u *arg, // pointer to extra arguments
- int addr_count,
- int start_bnr, // first buffer number in a range
- int end_bnr, // buffer nr or last buffer nr in a range
- int forceit
-)
+/// do_bufdel() - delete or unload buffer(s)
+///
+/// addr_count == 0: ":bdel" - delete current buffer
+/// addr_count == 1: ":N bdel" or ":bdel N [N ..]" - first delete
+/// buffer "end_bnr", then any other arguments.
+/// addr_count == 2: ":N,N bdel" - delete buffers in range
+///
+/// command can be DOBUF_UNLOAD (":bunload"), DOBUF_WIPE (":bwipeout") or
+/// DOBUF_DEL (":bdel")
+///
+/// @param arg pointer to extra arguments
+/// @param start_bnr first buffer number in a range
+/// @param end_bnr buffer nr or last buffer nr in a range
+///
+/// @return error message or NULL
+char_u *do_bufdel(int command, char_u *arg, int addr_count, int start_bnr, int end_bnr, int forceit)
{
int do_current = 0; // delete current buffer?
int deleted = 0; // number of buffers deleted
- char_u *errormsg = NULL; // return value
+ char_u *errormsg = NULL; // return value
int bnr; // buffer number
- char_u *p;
+ char_u *p;
if (addr_count == 0) {
(void)do_buffer(command, DOBUF_CURRENT, FORWARD, 0, forceit);
@@ -1074,7 +1070,7 @@ do_bufdel(
static int empty_curbuf(int close_others, int forceit, int action)
{
int retval;
- buf_T *buf = curbuf;
+ buf_T *buf = curbuf;
if (action == DOBUF_UNLOAD) {
EMSG(_("E90: Cannot unload last buffer"));
@@ -1091,7 +1087,7 @@ static int empty_curbuf(int close_others, int forceit, int action)
setpcmark();
retval = do_ecmd(0, NULL, NULL, NULL, ECMD_ONE,
- forceit ? ECMD_FORCEIT : 0, curwin);
+ forceit ? ECMD_FORCEIT : 0, curwin);
// do_ecmd() may create a new buffer, then we have to delete
// the old one. But do_ecmd() may have done that already, check
@@ -1106,40 +1102,39 @@ static int empty_curbuf(int close_others, int forceit, int action)
return retval;
}
-/*
- * Implementation of the commands for the buffer list.
- *
- * action == DOBUF_GOTO go to specified buffer
- * action == DOBUF_SPLIT split window and go to specified buffer
- * action == DOBUF_UNLOAD unload specified buffer(s)
- * action == DOBUF_DEL delete specified buffer(s) from buffer list
- * action == DOBUF_WIPE delete specified buffer(s) really
- *
- * start == DOBUF_CURRENT go to "count" buffer from current buffer
- * start == DOBUF_FIRST go to "count" buffer from first buffer
- * start == DOBUF_LAST go to "count" buffer from last buffer
- * start == DOBUF_MOD go to "count" modified buffer from current buffer
- *
- * Return FAIL or OK.
- */
-int
-do_buffer(
- int action,
- int start,
- int dir, // FORWARD or BACKWARD
- int count, // buffer number or number of buffers
- int forceit // true for :...!
-)
+
+/// Implementation of the commands for the buffer list.
+///
+/// action == DOBUF_GOTO go to specified buffer
+/// action == DOBUF_SPLIT split window and go to specified buffer
+/// action == DOBUF_UNLOAD unload specified buffer(s)
+/// action == DOBUF_DEL delete specified buffer(s) from buffer list
+/// action == DOBUF_WIPE delete specified buffer(s) really
+///
+/// start == DOBUF_CURRENT go to "count" buffer from current buffer
+/// start == DOBUF_FIRST go to "count" buffer from first buffer
+/// start == DOBUF_LAST go to "count" buffer from last buffer
+/// start == DOBUF_MOD go to "count" modified buffer from current buffer
+///
+/// @param dir FORWARD or BACKWARD
+/// @param count buffer number or number of buffers
+/// @param forceit true for :...!
+///
+/// @return FAIL or OK.
+int do_buffer(int action, int start, int dir, int count, int forceit)
{
- buf_T *buf;
- buf_T *bp;
+ buf_T *buf;
+ buf_T *bp;
int unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL
|| action == DOBUF_WIPE);
switch (start) {
- case DOBUF_FIRST: buf = firstbuf; break;
- case DOBUF_LAST: buf = lastbuf; break;
- default: buf = curbuf; break;
+ case DOBUF_FIRST:
+ buf = firstbuf; break;
+ case DOBUF_LAST:
+ buf = lastbuf; break;
+ default:
+ buf = curbuf; break;
}
if (start == DOBUF_MOD) { // find next modified buffer
while (count-- > 0) {
@@ -1219,8 +1214,8 @@ do_buffer(
return FAIL;
}
- if (!forceit && (buf->terminal || bufIsChanged(buf))) {
- if ((p_confirm || cmdmod.confirm) && p_write && !buf->terminal) {
+ if (!forceit && bufIsChanged(buf)) {
+ if ((p_confirm || cmdmod.confirm) && p_write) {
dialog_changed(buf, false);
if (!bufref_valid(&bufref)) {
// Autocommand deleted buffer, oops! It's not changed now.
@@ -1232,22 +1227,22 @@ do_buffer(
return FAIL;
}
} else {
- if (buf->terminal) {
- if (p_confirm || cmdmod.confirm) {
- if (!dialog_close_terminal(buf)) {
- return FAIL;
- }
- } else {
- EMSG2(_("E89: %s will be killed (add ! to override)"),
- (char *)buf->b_fname);
- return FAIL;
- }
- } else {
- EMSGN(_("E89: No write since last change for buffer %" PRId64
- " (add ! to override)"),
- buf->b_fnum);
+ EMSGN(_("E89: No write since last change for buffer %" PRId64
+ " (add ! to override)"),
+ buf->b_fnum);
+ return FAIL;
+ }
+ }
+
+ if (!forceit && buf->terminal && terminal_running(buf->terminal)) {
+ if (p_confirm || cmdmod.confirm) {
+ if (!dialog_close_terminal(buf)) {
return FAIL;
}
+ } else {
+ EMSG2(_("E89: %s will be killed (add ! to override)"),
+ (char *)buf->b_fname);
+ return FAIL;
}
}
@@ -1460,15 +1455,15 @@ do_buffer(
/*
* Set current buffer to "buf". Executes autocommands and closes current
* buffer. "action" tells how to close the current buffer:
- * DOBUF_GOTO free or hide it
- * DOBUF_SPLIT nothing
- * DOBUF_UNLOAD unload it
- * DOBUF_DEL delete it
- * DOBUF_WIPE wipe it out
+ * DOBUF_GOTO free or hide it
+ * DOBUF_SPLIT nothing
+ * DOBUF_UNLOAD unload it
+ * DOBUF_DEL delete it
+ * DOBUF_WIPE wipe it out
*/
void set_curbuf(buf_T *buf, int action)
{
- buf_T *prevbuf;
+ buf_T *prevbuf;
int unload = (action == DOBUF_UNLOAD || action == DOBUF_DEL
|| action == DOBUF_WIPE);
long old_tw = curbuf->b_p_tw;
@@ -1489,7 +1484,7 @@ void set_curbuf(buf_T *buf, int action)
set_bufref(&prevbufref, prevbuf);
set_bufref(&newbufref, buf);
- // Autocommands may delete the curren buffer and/or the buffer we wan to go
+ // Autocommands may delete the curren buffer and/or the buffer we want to go
// to. In those cases don't close the buffer.
if (!apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, false, curbuf)
|| (bufref_valid(&prevbufref) && bufref_valid(&newbufref)
@@ -1501,7 +1496,7 @@ void set_curbuf(buf_T *buf, int action)
close_windows(prevbuf, false);
}
if (bufref_valid(&prevbufref) && !aborting()) {
- win_T *previouswin = curwin;
+ win_T *previouswin = curwin;
if (prevbuf == curbuf) {
u_sync(false);
}
@@ -1523,8 +1518,7 @@ void set_curbuf(buf_T *buf, int action)
* If curwin->w_buffer is null, enter_buffer() will make it valid again */
if ((buf_valid(buf) && buf != curbuf
&& !aborting()
- ) || curwin->w_buffer == NULL
- ) {
+ ) || curwin->w_buffer == NULL) {
enter_buffer(buf);
if (old_tw != curbuf->b_p_tw) {
check_colorcolumn(curwin);
@@ -1670,7 +1664,7 @@ static int top_file_num = 1; ///< highest file number
/// Initialize b:changedtick and changedtick_val attribute
///
-/// @param[out] buf Buffer to intialize for.
+/// @param[out] buf Buffer to initialize for.
static inline void buf_init_changedtick(buf_T *const buf)
FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL
{
@@ -1706,12 +1700,11 @@ static inline void buf_init_changedtick(buf_T *const buf)
/// @param bufnr
///
/// @return pointer to the buffer
-buf_T *buflist_new(char_u *ffname_arg, char_u *sfname_arg, linenr_T lnum,
- int flags)
+buf_T *buflist_new(char_u *ffname_arg, char_u *sfname_arg, linenr_T lnum, int flags)
{
char_u *ffname = ffname_arg;
char_u *sfname = sfname_arg;
- buf_T *buf;
+ buf_T *buf;
fname_expand(curbuf, &ffname, &sfname); // will allocate ffname
@@ -1751,7 +1744,7 @@ buf_T *buflist_new(char_u *ffname_arg, char_u *sfname_arg, linenr_T lnum,
/*
* If the current buffer has no name and no contents, use the current
- * buffer. Otherwise: Need to allocate a new buffer structure.
+ * buffer. Otherwise: Need to allocate a new buffer structure.
*
* This is the ONLY place where a new buffer structure is allocated!
* (A spell file buffer is allocated in spell.c, but that's not a normal
@@ -1783,7 +1776,7 @@ buf_T *buflist_new(char_u *ffname_arg, char_u *sfname_arg, linenr_T lnum,
buf = xcalloc(1, sizeof(buf_T));
// init b: variables
buf->b_vars = tv_dict_alloc();
- buf->b_signcols_max = -1;
+ buf->b_signcols_valid = false;
init_var_dict(buf->b_vars, &buf->b_bufvar, VAR_SCOPE);
buf_init_changedtick(buf);
}
@@ -1841,7 +1834,7 @@ buf_T *buflist_new(char_u *ffname_arg, char_u *sfname_arg, linenr_T lnum,
lastbuf = buf;
buf->b_fnum = top_file_num++;
- handle_register_buffer(buf);
+ pmap_put(handle_T)(&buffer_handles, buf->b_fnum, buf);
if (top_file_num < 0) { // wrap around (may cause duplicates)
EMSG(_("W14: Warning: List of file names overflow"));
if (emsg_silent == 0) {
@@ -1918,7 +1911,7 @@ bool curbuf_reusable(void)
return (curbuf != NULL
&& curbuf->b_ffname == NULL
&& curbuf->b_nwindows <= 1
- && (curbuf->b_ml.ml_mfp == NULL || BUFEMPTY())
+ && (curbuf->b_ml.ml_mfp == NULL || buf_is_empty(curbuf))
&& !bt_quickfix(curbuf)
&& !curbufIsChanged());
}
@@ -2006,9 +1999,9 @@ void free_buf_options(buf_T *buf, int free_p_ff)
/// Return FAIL for failure, OK for success.
int buflist_getfile(int n, linenr_T lnum, int options, int forceit)
{
- buf_T *buf;
- win_T *wp = NULL;
- pos_T *fpos;
+ buf_T *buf;
+ win_T *wp = NULL;
+ pos_T *fpos;
colnr_T col;
buf = buflist_findnr(n);
@@ -2039,8 +2032,9 @@ int buflist_getfile(int n, linenr_T lnum, int options, int forceit)
fpos = buflist_findfpos(buf);
lnum = fpos->lnum;
col = fpos->col;
- } else
+ } else {
col = 0;
+ }
if (options & GETF_SWITCH) {
// If 'switchbuf' contains "useopen": jump to first window containing
@@ -2058,7 +2052,7 @@ int buflist_getfile(int n, linenr_T lnum, int options, int forceit)
// If 'switchbuf' contains "split", "vsplit" or "newtab" and the
// current buffer isn't empty: open new tab or window
if (wp == NULL && (swb_flags & (SWB_VSPLIT | SWB_SPLIT | SWB_NEWTAB))
- && !BUFEMPTY()) {
+ && !buf_is_empty(curbuf)) {
if (swb_flags & SWB_NEWTAB) {
tabpage_new();
} else if (win_split(0, (swb_flags & SWB_VSPLIT) ? WSP_VERT : 0)
@@ -2090,7 +2084,7 @@ int buflist_getfile(int n, linenr_T lnum, int options, int forceit)
// Go to the last known line number for the current buffer.
void buflist_getfpos(void)
{
- pos_T *fpos;
+ pos_T *fpos;
fpos = buflist_findfpos(curbuf);
@@ -2113,8 +2107,8 @@ void buflist_getfpos(void)
*/
buf_T *buflist_findname_exp(char_u *fname)
{
- char_u *ffname;
- buf_T *buf = NULL;
+ char_u *ffname;
+ buf_T *buf = NULL;
// First make the name into a full path name
ffname = (char_u *)FullName_save((char *)fname,
@@ -2124,7 +2118,7 @@ buf_T *buflist_findname_exp(char_u *fname)
#else
false
#endif
- );
+ );
if (ffname != NULL) {
buf = buflist_findname(ffname);
xfree(ffname);
@@ -2150,8 +2144,7 @@ buf_T *buflist_findname(char_u *ffname)
* getting it twice for the same file.
* Returns NULL if not found.
*/
-static buf_T *buflist_findname_file_id(char_u *ffname, FileID *file_id,
- bool file_id_valid)
+static buf_T *buflist_findname_file_id(char_u *ffname, FileID *file_id, bool file_id_valid)
{
// Start at the last buffer, expect to find a match sooner.
FOR_ALL_BUFFERS_BACKWARDS(buf) {
@@ -2166,21 +2159,21 @@ static buf_T *buflist_findname_file_id(char_u *ffname, FileID *file_id,
/// Find file in buffer list by a regexp pattern.
/// Return fnum of the found buffer.
/// Return < 0 for error.
-int buflist_findpat(
- const char_u *pattern,
- const char_u *pattern_end, // pointer to first char after pattern
- bool unlisted, // find unlisted buffers
- bool diffmode, // find diff-mode buffers only
- bool curtab_only // find buffers in current tab only
-)
+///
+/// @param pattern_end pointer to first char after pattern
+/// @param unlisted find unlisted buffers
+/// @param diffmode find diff-mode buffers only
+/// @param curtab_only find buffers in current tab only
+int buflist_findpat(const char_u *pattern, const char_u *pattern_end, bool unlisted, bool diffmode,
+ bool curtab_only)
FUNC_ATTR_NONNULL_ARG(1)
{
int match = -1;
int find_listed;
- char_u *pat;
- char_u *patend;
+ char_u *pat;
+ char_u *patend;
int attempt;
- char_u *p;
+ char_u *p;
int toggledollar;
if (pattern_end == pattern + 1 && (*pattern == '%' || *pattern == '#')) {
@@ -2284,13 +2277,12 @@ int buflist_findpat(
}
typedef struct {
- buf_T *buf;
- char_u *match;
+ buf_T *buf;
+ char_u *match;
} bufmatch_T;
/// Compare functions for qsort() below, that compares b_last_used.
-static int
-buf_time_compare(const void *s1, const void *s2)
+static int buf_time_compare(const void *s1, const void *s2)
{
buf_T *buf1 = *(buf_T **)s1;
buf_T *buf2 = *(buf_T **)s2;
@@ -2310,10 +2302,10 @@ int ExpandBufnames(char_u *pat, int *num_file, char_u ***file, int options)
{
int count = 0;
int round;
- char_u *p;
+ char_u *p;
int attempt;
- char_u *patc;
- bufmatch_T *matches = NULL;
+ char_u *patc;
+ bufmatch_T *matches = NULL;
*num_file = 0; // return values in case of FAIL
*file = NULL;
@@ -2327,8 +2319,9 @@ int ExpandBufnames(char_u *pat, int *num_file, char_u ***file, int options)
patc = xmalloc(STRLEN(pat) + 11);
STRCPY(patc, "\\(^\\|[\\/]\\)");
STRCPY(patc + 11, pat + 1);
- } else
+ } else {
patc = pat;
+ }
/*
* attempt == 0: try match with '\<', match at start of word
@@ -2449,8 +2442,8 @@ static char_u *buflist_match(regmatch_T *rmp, buf_T *buf, bool ignore_case)
/// @return "name" when there is a match, NULL when not.
static char_u *fname_match(regmatch_T *rmp, char_u *name, bool ignore_case)
{
- char_u *match = NULL;
- char_u *p;
+ char_u *match = NULL;
+ char_u *p;
if (name != NULL) {
// Ignore case when 'fileignorecase' or the argument is set.
@@ -2480,27 +2473,23 @@ buf_T *buflist_findnr(int nr)
return handle_get_buffer((handle_T)nr);
}
-/*
- * Get name of file 'n' in the buffer list.
- * When the file has no name an empty string is returned.
- * home_replace() is used to shorten the file name (used for marks).
- * Returns a pointer to allocated memory, of NULL when failed.
- */
-char_u *
-buflist_nr2name(
- int n,
- int fullname,
- int helptail // for help buffers return tail only
-)
+/// Get name of file 'n' in the buffer list.
+/// When the file has no name an empty string is returned.
+/// home_replace() is used to shorten the file name (used for marks).
+///
+/// @param helptail for help buffers return tail only
+///
+/// @return a pointer to allocated memory, of NULL when failed.
+char_u *buflist_nr2name(int n, int fullname, int helptail)
{
- buf_T *buf;
+ buf_T *buf;
buf = buflist_findnr(n);
if (buf == NULL) {
return NULL;
}
return home_replace_save(helptail ? buf : NULL,
- fullname ? buf->b_ffname : buf->b_fname);
+ fullname ? buf->b_ffname : buf->b_fname);
}
/// Set the line and column numbers for the given buffer and window
@@ -2512,12 +2501,11 @@ buflist_nr2name(
/// options are touched.
/// @param[in] col Column number to be set.
/// @param[in] copy_options If true save the local window option values.
-void buflist_setfpos(buf_T *const buf, win_T *const win,
- linenr_T lnum, colnr_T col,
+void buflist_setfpos(buf_T *const buf, win_T *const win, linenr_T lnum, colnr_T col,
bool copy_options)
FUNC_ATTR_NONNULL_ARG(1)
{
- wininfo_T *wip;
+ wininfo_T *wip;
for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next) {
if (wip->wi_win == win) {
@@ -2594,11 +2582,10 @@ static bool wininfo_other_tab_diff(wininfo_T *wip)
// When "skip_diff_buffer" is true avoid windows with 'diff' set that is in
// another tab page.
// Returns NULL when there isn't any info.
-static wininfo_T *find_wininfo(buf_T *buf, bool need_options,
- bool skip_diff_buffer)
+static wininfo_T *find_wininfo(buf_T *buf, bool need_options, bool skip_diff_buffer)
FUNC_ATTR_NONNULL_ALL
{
- wininfo_T *wip;
+ wininfo_T *wip;
for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next) {
if (wip->wi_win == curwin
@@ -2655,8 +2642,9 @@ void get_winopts(buf_T *buf)
curwin->w_fold_manual = wip->wi_fold_manual;
curwin->w_foldinvalid = true;
cloneFoldGrowArray(&wip->wi_folds, &curwin->w_folds);
- } else
+ } else {
copy_winopt(&curwin->w_allbuf_opt, &curwin->w_onebuf_opt);
+ }
if (curwin->w_float_config.style == kWinStyleMinimal) {
didset_window_options(curwin);
@@ -2694,7 +2682,7 @@ linenr_T buflist_findlnum(buf_T *buf)
// List all known file names (for :files and :buffers command).
void buflist_list(exarg_T *eap)
{
- buf_T *buf = firstbuf;
+ buf_T *buf = firstbuf;
int len;
int i;
@@ -2720,7 +2708,7 @@ void buflist_list(exarg_T *eap)
buf != NULL && !got_int;
buf = buflist_data != NULL
? (++p < buflist_data + buflist.ga_len ? *p : NULL)
- : buf->b_next) {
+ : buf->b_next) {
const bool is_terminal = buf->terminal;
const bool job_running = buf->terminal && terminal_running(buf->terminal);
@@ -2762,18 +2750,17 @@ void buflist_list(exarg_T *eap)
}
msg_putchar('\n');
- len = vim_snprintf(
- (char *)IObuff, IOSIZE - 20, "%3d%c%c%c%c%c \"%s\"",
- buf->b_fnum,
- buf->b_p_bl ? ' ' : 'u',
- buf == curbuf ? '%' : (curwin->w_alt_fnum == buf->b_fnum ? '#' : ' '),
- buf->b_ml.ml_mfp == NULL ? ' ' : (buf->b_nwindows == 0 ? 'h' : 'a'),
- ro_char,
- changed_char,
- NameBuff);
+ len = vim_snprintf((char *)IObuff, IOSIZE - 20, "%3d%c%c%c%c%c \"%s\"",
+ buf->b_fnum,
+ buf->b_p_bl ? ' ' : 'u',
+ buf == curbuf ? '%' : (curwin->w_alt_fnum == buf->b_fnum ? '#' : ' '),
+ buf->b_ml.ml_mfp == NULL ? ' ' : (buf->b_nwindows == 0 ? 'h' : 'a'),
+ ro_char,
+ changed_char,
+ NameBuff);
if (len > IOSIZE - 20) {
- len = IOSIZE - 20;
+ len = IOSIZE - 20;
}
// put "line 999" in column 40 or after the file name
@@ -2787,7 +2774,7 @@ void buflist_list(exarg_T *eap)
vim_snprintf((char *)IObuff + len, (size_t)(IOSIZE - len),
_("line %" PRId64),
buf == curbuf ? (int64_t)curwin->w_cursor.lnum
- : (int64_t)buflist_findlnum(buf));
+ : (int64_t)buflist_findlnum(buf));
}
msg_outtrans(IObuff);
@@ -2807,7 +2794,7 @@ void buflist_list(exarg_T *eap)
*/
int buflist_name_nr(int fnum, char_u **fname, linenr_T *lnum)
{
- buf_T *buf;
+ buf_T *buf;
buf = buflist_findnr(fnum);
if (buf == NULL || buf->b_fname == NULL) {
@@ -2820,21 +2807,18 @@ int buflist_name_nr(int fnum, char_u **fname, linenr_T *lnum)
return OK;
}
-// Set the file name for "buf" to "ffname_arg", short file name to
-// "sfname_arg".
-// The file name with the full path is also remembered, for when :cd is used.
-// Returns FAIL for failure (file name already in use by other buffer)
-// OK otherwise.
-int setfname(
- buf_T *buf,
- char_u *ffname_arg,
- char_u *sfname_arg,
- bool message // give message when buffer already exists
-)
+/// Set the file name for "buf" to "ffname_arg", short file name to
+/// "sfname_arg".
+/// The file name with the full path is also remembered, for when :cd is used.
+///
+/// @param message give message when buffer already exists
+///
+/// @return FAIL for failure (file name already in use by other buffer) OK otherwise.
+int setfname(buf_T *buf, char_u *ffname_arg, char_u *sfname_arg, bool message)
{
char_u *ffname = ffname_arg;
char_u *sfname = sfname_arg;
- buf_T *obuf = NULL;
+ buf_T *obuf = NULL;
FileID file_id;
bool file_id_valid = false;
@@ -2901,7 +2885,7 @@ int setfname(
*/
void buf_set_name(int fnum, char_u *name)
{
- buf_T *buf;
+ buf_T *buf;
buf = buflist_findnr(fnum);
if (buf != NULL) {
@@ -2948,7 +2932,7 @@ void buf_name_changed(buf_T *buf)
*/
buf_T *setaltfname(char_u *ffname, char_u *sfname, linenr_T lnum)
{
- buf_T *buf;
+ buf_T *buf;
// Create a buffer. 'buflisted' is not set if it's a new buffer
buf = buflist_new(ffname, sfname, lnum, 0);
@@ -2958,15 +2942,13 @@ buf_T *setaltfname(char_u *ffname, char_u *sfname, linenr_T lnum)
return buf;
}
-/*
- * Get alternate file name for current window.
- * Return NULL if there isn't any, and give error message if requested.
- */
-char_u * getaltfname(
- bool errmsg // give error message
-)
+/// Get alternate file name for current window.
+/// Return NULL if there isn't any, and give error message if requested.
+///
+/// @param errmsg give error message
+char_u *getaltfname(bool errmsg)
{
- char_u *fname;
+ char_u *fname;
linenr_T dummy;
if (buflist_name_nr(0, &fname, &dummy) == FAIL) {
@@ -2986,7 +2968,7 @@ char_u * getaltfname(
*/
int buflist_add(char_u *fname, int flags)
{
- buf_T *buf;
+ buf_T *buf;
buf = buflist_new(fname, NULL, (linenr_T)0, flags);
if (buf != NULL) {
@@ -3039,8 +3021,7 @@ bool otherfile(char_u *ffname)
/// @param ffname full path name to check
/// @param file_id_p information about the file at "ffname".
/// @param file_id_valid whether a valid "file_id_p" was passed in.
-static bool otherfile_buf(buf_T *buf, char_u *ffname, FileID *file_id_p,
- bool file_id_valid)
+static bool otherfile_buf(buf_T *buf, char_u *ffname, FileID *file_id_p, bool file_id_valid)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
// no name is different
@@ -3104,20 +3085,15 @@ static bool buf_same_file_id(buf_T *buf, FileID *file_id)
return buf->file_id_valid && os_fileid_equal(&(buf->file_id), file_id);
}
-/*
- * Print info about the current buffer.
- */
-void
-fileinfo(
- int fullname, // when non-zero print full path
- int shorthelp,
- int dont_truncate
-)
+/// Print info about the current buffer.
+///
+/// @param fullname when non-zero print full path
+void fileinfo(int fullname, int shorthelp, int dont_truncate)
{
- char_u *name;
+ char_u *name;
int n;
- char_u *p;
- char_u *buffer;
+ char_u *p;
+ char_u *buffer;
size_t len;
buffer = xmalloc(IOSIZE);
@@ -3125,8 +3101,9 @@ fileinfo(
if (fullname > 1) { // 2 CTRL-G: include buffer number
vim_snprintf((char *)buffer, IOSIZE, "buf %d: ", curbuf->b_fnum);
p = buffer + STRLEN(buffer);
- } else
+ } else {
p = buffer;
+ }
*p++ = '"';
if (buf_spname(curbuf) != NULL) {
@@ -3141,12 +3118,13 @@ fileinfo(
(size_t)(IOSIZE - (p - buffer)), true);
}
+ bool dontwrite = bt_dontwrite(curbuf);
vim_snprintf_add((char *)buffer, IOSIZE, "\"%s%s%s%s%s%s",
curbufIsChanged()
? (shortmess(SHM_MOD) ? " [+]" : _(" [Modified]")) : " ",
- (curbuf->b_flags & BF_NOTEDITED) && !bt_dontwrite(curbuf)
+ (curbuf->b_flags & BF_NOTEDITED) && !dontwrite
? _("[Not edited]") : "",
- (curbuf->b_flags & BF_NEW) && !bt_dontwrite(curbuf)
+ (curbuf->b_flags & BF_NEW) && !dontwrite
? new_file_message() : "",
(curbuf->b_flags & BF_READERR)
? _("[Read errors]") : "",
@@ -3177,14 +3155,14 @@ fileinfo(
}
} else {
vim_snprintf_add((char *)buffer, IOSIZE,
- _("line %" PRId64 " of %" PRId64 " --%d%%-- col "),
- (int64_t)curwin->w_cursor.lnum,
- (int64_t)curbuf->b_ml.ml_line_count,
- n);
+ _("line %" PRId64 " of %" PRId64 " --%d%%-- col "),
+ (int64_t)curwin->w_cursor.lnum,
+ (int64_t)curbuf->b_ml.ml_line_count,
+ n);
validate_virtcol();
len = STRLEN(buffer);
col_print(buffer + len, IOSIZE - len,
- (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1);
+ (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1);
}
(void)append_arg_number(curwin, buffer, IOSIZE, !shortmess(SHM_FILE));
@@ -3286,21 +3264,28 @@ void maketitle(void)
buf_p += MIN(size, SPACE_FOR_FNAME);
} else {
buf_p += transstr_buf((const char *)path_tail(curbuf->b_fname),
- buf_p, SPACE_FOR_FNAME + 1);
+ buf_p, SPACE_FOR_FNAME + 1, true);
}
switch (bufIsChanged(curbuf)
| (curbuf->b_p_ro << 1)
| (!MODIFIABLE(curbuf) << 2)) {
- case 0: break;
- case 1: buf_p = strappend(buf_p, " +"); break;
- case 2: buf_p = strappend(buf_p, " ="); break;
- case 3: buf_p = strappend(buf_p, " =+"); break;
- case 4:
- case 6: buf_p = strappend(buf_p, " -"); break;
- case 5:
- case 7: buf_p = strappend(buf_p, " -+"); break;
- default: abort();
+ case 0:
+ break;
+ case 1:
+ buf_p = strappend(buf_p, " +"); break;
+ case 2:
+ buf_p = strappend(buf_p, " ="); break;
+ case 3:
+ buf_p = strappend(buf_p, " =+"); break;
+ case 4:
+ case 6:
+ buf_p = strappend(buf_p, " -"); break;
+ case 5:
+ case 7:
+ buf_p = strappend(buf_p, " -+"); break;
+ default:
+ abort();
}
if (curbuf->b_fname != NULL) {
@@ -3328,7 +3313,7 @@ void maketitle(void)
// room for the server name. When there is no room (very long
// file name) use (...).
if ((size_t)(buf_p - buf) < SPACE_FOR_DIR) {
- char *const tbuf = transstr(buf_p);
+ char *const tbuf = transstr(buf_p, true);
const size_t free_space = SPACE_FOR_DIR - (size_t)(buf_p - buf) + 1;
const size_t dir_len = xstrlcpy(buf_p, tbuf, free_space);
buf_p += MIN(dir_len, free_space - 1);
@@ -3444,14 +3429,14 @@ void resettitle(void)
ui_flush();
}
-# if defined(EXITFREE)
+#if defined(EXITFREE)
void free_titles(void)
{
xfree(lasttitle);
xfree(lasticon);
}
-# endif
+#endif
/// Enumeration specifying the valid numeric bases that can
/// be used when printing numbers in the status line.
@@ -3486,17 +3471,8 @@ typedef enum {
/// @param tabtab Tab clicks definition (can be NULL).
///
/// @return The final width of the statusline
-int build_stl_str_hl(
- win_T *wp,
- char_u *out,
- size_t outlen,
- char_u *fmt,
- int use_sandbox,
- char_u fillchar,
- int maxwidth,
- stl_hlrec_t **hltab,
- StlClickRecord **tabtab
-)
+int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use_sandbox,
+ char_u fillchar, int maxwidth, stl_hlrec_t **hltab, StlClickRecord **tabtab)
{
static size_t stl_items_len = 20; // Initial value, grows as needed.
static stl_item_t *stl_items = NULL;
@@ -3508,7 +3484,7 @@ int build_stl_str_hl(
#define TMPLEN 70
char_u buf_tmp[TMPLEN];
char_u win_tmp[TMPLEN];
- char_u *usefmt = fmt;
+ char_u *usefmt = fmt;
const int save_must_redraw = must_redraw;
const int save_redr_type = curwin->w_redr_type;
@@ -3587,19 +3563,19 @@ int build_stl_str_hl(
// Proceed character by character through the statusline format string
- // fmt_p is the current positon in the input buffer
+ // fmt_p is the current position in the input buffer
for (char_u *fmt_p = usefmt; *fmt_p; ) {
if (curitem == (int)stl_items_len) {
- size_t new_len = stl_items_len * 3 / 2;
+ size_t new_len = stl_items_len * 3 / 2;
- stl_items = xrealloc(stl_items, sizeof(stl_item_t) * new_len);
- stl_groupitems = xrealloc(stl_groupitems, sizeof(int) * new_len);
- stl_hltab = xrealloc(stl_hltab, sizeof(stl_hlrec_t) * new_len);
- stl_tabtab = xrealloc(stl_tabtab, sizeof(StlClickRecord) * new_len);
- stl_separator_locations =
- xrealloc(stl_separator_locations, sizeof(int) * new_len);
+ stl_items = xrealloc(stl_items, sizeof(stl_item_t) * new_len);
+ stl_groupitems = xrealloc(stl_groupitems, sizeof(int) * new_len);
+ stl_hltab = xrealloc(stl_hltab, sizeof(stl_hlrec_t) * new_len);
+ stl_tabtab = xrealloc(stl_tabtab, sizeof(StlClickRecord) * new_len);
+ stl_separator_locations =
+ xrealloc(stl_separator_locations, sizeof(int) * new_len);
- stl_items_len = new_len;
+ stl_items_len = new_len;
}
if (*fmt_p != NUL && *fmt_p != '%') {
@@ -3609,8 +3585,9 @@ int build_stl_str_hl(
// Copy the formatting verbatim until we reach the end of the string
// or find a formatting item (denoted by `%`)
// or run out of room in our output buffer.
- while (*fmt_p != NUL && *fmt_p != '%' && out_p < out_end_p)
+ while (*fmt_p != NUL && *fmt_p != '%' && out_p < out_end_p) {
*out_p++ = *fmt_p++;
+ }
// If we have processed the entire format string or run out of
// room in our output buffer, exit the loop.
@@ -3753,17 +3730,18 @@ int build_stl_str_hl(
stl_items[idx].start = t;
}
}
- // If the group is shorter than the minimum width, add padding characters.
+ // If the group is shorter than the minimum width, add padding characters.
} else if (
- abs(stl_items[stl_groupitems[groupdepth]].minwid) > group_len) {
+ abs(stl_items[stl_groupitems[groupdepth]].minwid) > group_len) {
long min_group_width = stl_items[stl_groupitems[groupdepth]].minwid;
// If the group is left-aligned, add characters to the right.
if (min_group_width < 0) {
min_group_width = 0 - min_group_width;
- while (group_len++ < min_group_width && out_p < out_end_p)
+ while (group_len++ < min_group_width && out_p < out_end_p) {
*out_p++ = fillchar;
- // If the group is right-aligned, shift everything to the right and
- // prepend with filler characters.
+ }
+ // If the group is right-aligned, shift everything to the right and
+ // prepend with filler characters.
} else {
// { Move the group to the right
memmove(t + min_group_width - group_len, t, (size_t)(out_p - t));
@@ -3868,7 +3846,7 @@ int build_stl_str_hl(
if (*fmt_p == STL_CLICK_FUNC) {
fmt_p++;
- char *t = (char *) fmt_p;
+ char *t = (char *)fmt_p;
while (*fmt_p != STL_CLICK_FUNC && *fmt_p) {
fmt_p++;
}
@@ -3911,9 +3889,9 @@ int build_stl_str_hl(
// Denotes end of expanded %{} block
if (*fmt_p == '}' && evaldepth > 0) {
- fmt_p++;
- evaldepth--;
- continue;
+ fmt_p++;
+ evaldepth--;
+ continue;
}
// An invalid item was specified.
@@ -3936,7 +3914,6 @@ int build_stl_str_hl(
case STL_FILEPATH:
case STL_FULLPATH:
case STL_FILENAME:
- {
// Set fillable to false so that ' ' in the filename will not
// get replaced with the fillchar
fillable = false;
@@ -3944,7 +3921,7 @@ int build_stl_str_hl(
STRLCPY(NameBuff, buf_spname(wp->w_buffer), MAXPATHL);
} else {
char_u *t = (opt == STL_FULLPATH) ? wp->w_buffer->b_ffname
- : wp->w_buffer->b_fname;
+ : wp->w_buffer->b_fname;
home_replace(wp->w_buffer, t, NameBuff, MAXPATHL, true);
}
trans_characters(NameBuff, MAXPATHL);
@@ -3954,7 +3931,6 @@ int build_stl_str_hl(
str = path_tail(NameBuff);
}
break;
- }
case STL_VIM_EXPR: // '{'
{
char_u *block_start = fmt_p - 1;
@@ -4037,17 +4013,17 @@ int build_stl_str_hl(
size_t str_length = strlen((const char *)str);
size_t fmt_length = strlen((const char *)fmt_p);
size_t new_fmt_len = parsed_usefmt
- + str_length + fmt_length + 3;
+ + str_length + fmt_length + 3;
char_u *new_fmt = (char_u *)xmalloc(new_fmt_len * sizeof(char_u));
char_u *new_fmt_p = new_fmt;
new_fmt_p = (char_u *)memcpy(new_fmt_p, usefmt, parsed_usefmt)
- + parsed_usefmt;
- new_fmt_p = (char_u *)memcpy(new_fmt_p , str, str_length)
- + str_length;
+ + parsed_usefmt;
+ new_fmt_p = (char_u *)memcpy(new_fmt_p, str, str_length)
+ + str_length;
new_fmt_p = (char_u *)memcpy(new_fmt_p, "%}", 2) + 2;
- new_fmt_p = (char_u *)memcpy(new_fmt_p , fmt_p, fmt_length)
- + fmt_length;
+ new_fmt_p = (char_u *)memcpy(new_fmt_p, fmt_p, fmt_length)
+ + fmt_length;
*new_fmt_p = 0;
new_fmt_p = NULL;
@@ -4078,8 +4054,7 @@ int build_stl_str_hl(
break;
case STL_VIRTCOL:
- case STL_VIRTCOL_ALT:
- {
+ case STL_VIRTCOL_ALT: {
// In list mode virtcol needs to be recomputed
colnr_T virtcol = wp->w_virtcol;
if (wp->w_p_list && wp->w_p_lcs_chars.tab1 == NUL) {
@@ -4091,8 +4066,9 @@ int build_stl_str_hl(
// Don't display %V if it's the same as %c.
if (opt == STL_VIRTCOL_ALT
&& (virtcol == (colnr_T)(!(State & INSERT) && empty_line
- ? 0 : (int)wp->w_cursor.col + 1)))
+ ? 0 : (int)wp->w_cursor.col + 1))) {
break;
+ }
num = (long)virtcol;
break;
}
@@ -4143,8 +4119,7 @@ int build_stl_str_hl(
case STL_OFFSET_X:
base = kNumBaseHexadecimal;
FALLTHROUGH;
- case STL_OFFSET:
- {
+ case STL_OFFSET: {
long l = ml_find_line_or_offset(wp->w_buffer, wp->w_cursor.lnum, NULL,
false);
num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) || l < 0 ?
@@ -4175,9 +4150,10 @@ int build_stl_str_hl(
case STL_HELPFLAG:
case STL_HELPFLAG_ALT:
itemisflag = true;
- if (wp->w_buffer->b_help)
+ if (wp->w_buffer->b_help) {
str = (char_u *)((opt == STL_HELPFLAG_ALT) ? ",HLP"
- : _("[Help]"));
+ : _("[Help]"));
+ }
break;
case STL_FILETYPE:
@@ -4193,7 +4169,6 @@ int build_stl_str_hl(
break;
case STL_FILETYPE_ALT:
- {
itemisflag = true;
// Copy the filetype if it is not null and the formatted string will fit
// in the temporary buffer
@@ -4209,20 +4184,21 @@ int build_stl_str_hl(
str = buf_tmp;
}
break;
- }
case STL_PREVIEWFLAG:
case STL_PREVIEWFLAG_ALT:
itemisflag = true;
- if (wp->w_p_pvw)
+ if (wp->w_p_pvw) {
str = (char_u *)((opt == STL_PREVIEWFLAG_ALT) ? ",PRV"
- : _("[Preview]"));
+ : _("[Preview]"));
+ }
break;
case STL_QUICKFIX:
- if (bt_quickfix(wp->w_buffer))
+ if (bt_quickfix(wp->w_buffer)) {
str = (char_u *)(wp->w_llist_ref
? _(msg_loclist)
: _(msg_qflist));
+ }
break;
case STL_MODIFIED:
@@ -4231,17 +4207,22 @@ int build_stl_str_hl(
switch ((opt == STL_MODIFIED_ALT)
+ bufIsChanged(wp->w_buffer) * 2
+ (!MODIFIABLE(wp->w_buffer)) * 4) {
- case 2: str = (char_u *)"[+]"; break;
- case 3: str = (char_u *)",+"; break;
- case 4: str = (char_u *)"[-]"; break;
- case 5: str = (char_u *)",-"; break;
- case 6: str = (char_u *)"[+-]"; break;
- case 7: str = (char_u *)",+-"; break;
+ case 2:
+ str = (char_u *)"[+]"; break;
+ case 3:
+ str = (char_u *)",+"; break;
+ case 4:
+ str = (char_u *)"[-]"; break;
+ case 5:
+ str = (char_u *)",-"; break;
+ case 6:
+ str = (char_u *)"[+-]"; break;
+ case 7:
+ str = (char_u *)",+-"; break;
}
break;
- case STL_HIGHLIGHT:
- {
+ case STL_HIGHLIGHT: {
// { The name of the highlight is surrounded by `#`
char_u *t = fmt_p;
while (*fmt_p != '#' && *fmt_p != NUL) {
@@ -4253,7 +4234,7 @@ int build_stl_str_hl(
if (*fmt_p == '#') {
stl_items[curitem].type = Highlight;
stl_items[curitem].start = out_p;
- stl_items[curitem].minwid = -syn_namen2id(t, (int)(fmt_p - t));
+ stl_items[curitem].minwid = -syn_name2id_len(t, (size_t)(fmt_p - t));
curitem++;
fmt_p++;
}
@@ -4275,8 +4256,9 @@ int build_stl_str_hl(
if (itemisflag) {
if ((t[0] && t[1])
&& ((!prevchar_isitem && *t == ',')
- || (prevchar_isflag && *t == ' ')))
+ || (prevchar_isflag && *t == ' '))) {
t++;
+ }
prevchar_isflag = true;
}
// }
@@ -4329,8 +4311,9 @@ int build_stl_str_hl(
// Change a space by fillchar, unless fillchar is '-' and a
// digit follows.
if (fillable && out_p[-1] == ' '
- && (!ascii_isdigit(*t) || fillchar != '-'))
+ && (!ascii_isdigit(*t) || fillchar != '-')) {
out_p[-1] = fillchar;
+ }
}
// }
@@ -4339,7 +4322,7 @@ int build_stl_str_hl(
*out_p++ = fillchar;
}
- // Otherwise if the item is a number, copy that to the output buffer.
+ // Otherwise if the item is a number, copy that to the output buffer.
} else if (num >= 0) {
if (out_p + 20 > out_end_p) {
break; // not sufficient space
@@ -4368,7 +4351,7 @@ int build_stl_str_hl(
// Note: We have to cast the base because the compiler uses
// unsigned ints for the enum values.
long num_chars = 1;
- for (long n = num; n >= (int) base; n /= (int) base) {
+ for (long n = num; n >= (int)base; n /= (int)base) {
num_chars++;
}
@@ -4408,17 +4391,17 @@ int build_stl_str_hl(
// }
vim_snprintf((char *)out_p, remaining_buf_len, (char *)nstr,
- 0, num, n);
+ 0, num, n);
} else {
vim_snprintf((char *)out_p, remaining_buf_len, (char *)nstr,
- minwid, num);
+ minwid, num);
}
// Advance the output buffer position to the end of the
// number we just printed
out_p += STRLEN(out_p);
- // Otherwise, there was nothing to print so mark the item as empty
+ // Otherwise, there was nothing to print so mark the item as empty
} else {
stl_items[curitem].type = Empty;
}
@@ -4458,7 +4441,7 @@ int build_stl_str_hl(
if (itemcnt == 0) {
trunc_p = out;
- // Otherwise, look for the truncation item
+ // Otherwise, look for the truncation item
} else {
// Default to truncating at the first item
trunc_p = stl_items[0].start;
@@ -4505,7 +4488,7 @@ int build_stl_str_hl(
*trunc_p++ = '>';
*trunc_p = 0;
- // Truncate at the truncation point we found
+ // Truncate at the truncation point we found
} else {
// { Determine how many bytes to remove
long trunc_len = 0;
@@ -4546,8 +4529,8 @@ int build_stl_str_hl(
// to be moved backwards.
if (stl_items[i].start >= trunc_end_p) {
stl_items[i].start -= item_offset;
- // Anything inside the truncated area is set to start
- // at the `<` truncation character.
+ // Anything inside the truncated area is set to start
+ // at the `<` truncation character.
} else {
stl_items[i].start = trunc_p;
}
@@ -4556,9 +4539,9 @@ int build_stl_str_hl(
}
width = maxwidth;
- // If there is room left in our statusline, and room left in our buffer,
- // add characters at the separate marker (if there is one) to
- // fill up the available space.
+ // If there is room left in our statusline, and room left in our buffer,
+ // add characters at the separate marker (if there is one) to
+ // fill up the available space.
} else if (width < maxwidth
&& STRLEN(out) + (size_t)(maxwidth - width) + 1 < outlen) {
// Find how many separators there are, which we will use when
@@ -4577,7 +4560,7 @@ int build_stl_str_hl(
if (num_separators) {
int standard_spaces = (maxwidth - width) / num_separators;
int final_spaces = (maxwidth - width) -
- standard_spaces * (num_separators - 1);
+ standard_spaces * (num_separators - 1);
for (int i = 0; i < num_separators; i++) {
int dislocation = (i == (num_separators - 1))
@@ -4676,7 +4659,7 @@ void get_rel_pos(win_T *wp, char_u *buf, int buflen)
long below; // number of lines below window
above = wp->w_topline - 1;
- above += diff_check_fill(wp, wp->w_topline) - wp->w_topfill;
+ above += win_get_fill(wp, wp->w_topline) - wp->w_topfill;
if (wp->w_topline == 1 && wp->w_topfill >= 1) {
// All buffer lines are displayed and there is an indication
// of filler lines, that can be considered seeing all lines.
@@ -4735,7 +4718,7 @@ static bool append_arg_number(win_T *wp, char_u *buf, int buflen, bool add_file)
// When resolving a link both "*sfname" and "*ffname" will point to the same
// allocated memory.
// The "*ffname" and "*sfname" pointer values on call will not be freed.
-// Note that the resulting "*ffname" pointer should be considered not allocaed.
+// Note that the resulting "*ffname" pointer should be considered not allocated.
void fname_expand(buf_T *buf, char_u **ffname, char_u **sfname)
{
if (*ffname == NULL) { // no file name given, nothing to do
@@ -4764,7 +4747,7 @@ void fname_expand(buf_T *buf, char_u **ffname, char_u **sfname)
*/
char_u *alist_name(aentry_T *aep)
{
- buf_T *bp;
+ buf_T *bp;
// Use the name from the associated buffer if it exists.
bp = buflist_findnr(aep->ae_fnum);
@@ -4774,35 +4757,31 @@ char_u *alist_name(aentry_T *aep)
return bp->b_fname;
}
-/*
- * do_arg_all(): Open up to 'count' windows, one for each argument.
- */
-void
-do_arg_all(
- int count,
- int forceit, // hide buffers in current windows
- int keep_tabs // keep current tabs, for ":tab drop file"
-)
+/// do_arg_all(): Open up to 'count' windows, one for each argument.
+///
+/// @param forceit hide buffers in current windows
+/// @param keep_tabs keep current tabs, for ":tab drop file"
+void do_arg_all(int count, int forceit, int keep_tabs)
{
- char_u *opened; // Array of weight for which args are open:
- // 0: not opened
- // 1: opened in other tab
- // 2: opened in curtab
- // 3: opened in curtab and curwin
+ char_u *opened; // Array of weight for which args are open:
+ // 0: not opened
+ // 1: opened in other tab
+ // 2: opened in curtab
+ // 3: opened in curtab and curwin
int opened_len; // length of opened[]
int use_firstwin = false; // use first window for arglist
bool tab_drop_empty_window = false;
int split_ret = OK;
bool p_ea_save;
- alist_T *alist; // argument list to be used
- buf_T *buf;
- tabpage_T *tpnext;
+ alist_T *alist; // argument list to be used
+ buf_T *buf;
+ tabpage_T *tpnext;
int had_tab = cmdmod.tab;
- win_T *old_curwin, *last_curwin;
- tabpage_T *old_curtab, *last_curtab;
- win_T *new_curwin = NULL;
- tabpage_T *new_curtab = NULL;
+ win_T *old_curwin, *last_curwin;
+ tabpage_T *old_curtab, *last_curtab;
+ win_T *new_curwin = NULL;
+ tabpage_T *new_curtab = NULL;
assert(firstwin != NULL); // satisfy coverity
@@ -4948,7 +4927,7 @@ do_arg_all(
win_enter(lastwin, false);
// ":tab drop file" should re-use an empty window to avoid "--remote-tab"
// leaving an empty tab page when executed locally.
- if (keep_tabs && BUFEMPTY() && curbuf->b_nwindows == 1
+ if (keep_tabs && buf_is_empty(curbuf) && curbuf->b_nwindows == 1
&& curbuf->b_ffname == NULL && !curbuf->b_changed) {
use_firstwin = true;
tab_drop_empty_window = true;
@@ -5044,10 +5023,10 @@ do_arg_all(
xfree(opened);
}
-// Return TRUE if "buf" is a prompt buffer.
-int bt_prompt(buf_T *buf)
+/// @return true if "buf" is a prompt buffer.
+bool bt_prompt(buf_T *buf)
{
- return buf != NULL && buf->b_p_bt[0] == 'p';
+ return buf != NULL && buf->b_p_bt[0] == 'p';
}
/*
@@ -5055,8 +5034,8 @@ int bt_prompt(buf_T *buf)
*/
void ex_buffer_all(exarg_T *eap)
{
- buf_T *buf;
- win_T *wp, *wpnext;
+ buf_T *buf;
+ win_T *wp, *wpnext;
int split_ret = OK;
bool p_ea_save;
int open_wins = 0;
@@ -5064,7 +5043,7 @@ void ex_buffer_all(exarg_T *eap)
long count; // Maximum number of windows to open.
int all; // When true also load inactive buffers.
int had_tab = cmdmod.tab;
- tabpage_T *tpnext;
+ tabpage_T *tpnext;
if (eap->addr_count == 0) { // make as many windows as possible
count = 9999;
@@ -5098,8 +5077,8 @@ void ex_buffer_all(exarg_T *eap)
: wp->w_width != Columns)
|| (had_tab > 0 && wp != firstwin))
&& !ONE_WINDOW
- && !(wp->w_closing || wp->w_buffer->b_locked > 0)
- ) {
+ && !(wp->w_closing ||
+ wp->w_buffer->b_locked > 0)) {
win_close(wp, false);
wpnext = firstwin; // just in case an autocommand does
// something strange with windows
@@ -5190,8 +5169,9 @@ void ex_buffer_all(exarg_T *eap)
* discarded by a new aborting error, interrupt, or uncaught
* exception. */
leave_cleanup(&cs);
- } else
+ } else {
handle_swap_exists(NULL);
+ }
}
os_breakcheck();
@@ -5240,8 +5220,8 @@ void ex_buffer_all(exarg_T *eap)
* do_modelines() - process mode lines for the current file
*
* "flags" can be:
- * OPT_WINONLY only set options local to window
- * OPT_NOWIN don't set options local to window
+ * OPT_WINONLY only set options local to window
+ * OPT_NOWIN don't set options local to window
*
* Returns immediately if the "ml" option isn't set.
*/
@@ -5262,15 +5242,16 @@ void do_modelines(int flags)
}
entered++;
- for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count && lnum <= nmlines;
- lnum++) {
+ for (lnum = 1; curbuf->b_p_ml && lnum <= curbuf->b_ml.ml_line_count
+ && lnum <= nmlines; lnum++) {
if (chk_modeline(lnum, flags) == FAIL) {
nmlines = 0;
}
}
- for (lnum = curbuf->b_ml.ml_line_count; lnum > 0 && lnum > nmlines
- && lnum > curbuf->b_ml.ml_line_count - nmlines; lnum--) {
+ for (lnum = curbuf->b_ml.ml_line_count; curbuf->b_p_ml && lnum > 0
+ && lnum > nmlines && lnum > curbuf->b_ml.ml_line_count - nmlines;
+ lnum--) {
if (chk_modeline(lnum, flags) == FAIL) {
nmlines = 0;
}
@@ -5278,32 +5259,29 @@ void do_modelines(int flags)
entered--;
}
-/*
- * chk_modeline() - check a single line for a mode string
- * Return FAIL if an error encountered.
- */
-static int
-chk_modeline(
- linenr_T lnum,
- int flags // Same as for do_modelines().
-)
+/// chk_modeline() - check a single line for a mode string
+/// Return FAIL if an error encountered.
+///
+/// @param flags Same as for do_modelines().
+static int chk_modeline(linenr_T lnum, int flags)
{
- char_u *s;
- char_u *e;
- char_u *linecopy; // local copy of any modeline found
+ char_u *s;
+ char_u *e;
+ char_u *linecopy; // local copy of any modeline found
int prev;
intmax_t vers;
int end;
int retval = OK;
- char_u *save_sourcing_name;
+ char_u *save_sourcing_name;
linenr_T save_sourcing_lnum;
prev = -1;
for (s = ml_get(lnum); *s != NUL; s++) {
if (prev == -1 || ascii_isspace(prev)) {
if ((prev != -1 && STRNCMP(s, "ex:", (size_t)3) == 0)
- || STRNCMP(s, "vi:", (size_t)3) == 0)
+ || STRNCMP(s, "vi:", (size_t)3) == 0) {
break;
+ }
// Accept both "vim" and "Vim".
if ((s[0] == 'v' || s[0] == 'V') && s[1] == 'i' && s[2] == 'm') {
if (s[3] == '<' || s[3] == '=' || s[3] == '>') {
@@ -5477,8 +5455,10 @@ bool buf_hide(const buf_T *const buf)
switch (buf->b_p_bh[0]) {
case 'u': // "unload"
case 'w': // "wipe"
- case 'd': return false; // "delete"
- case 'h': return true; // "hide"
+ case 'd':
+ return false; // "delete"
+ case 'h':
+ return true; // "hide"
}
return p_hid || cmdmod.hide;
}
@@ -5544,36 +5524,38 @@ bool find_win_for_buf(buf_T *buf, win_T **wp, tabpage_T **tp)
int buf_signcols(buf_T *buf)
{
- if (buf->b_signcols_max == -1) {
- sign_entry_T *sign; // a sign in the sign list
- buf->b_signcols_max = 0;
- int linesum = 0;
- linenr_T curline = 0;
-
- FOR_ALL_SIGNS_IN_BUF(buf, sign) {
- if (sign->se_lnum > curline) {
- if (linesum > buf->b_signcols_max) {
- buf->b_signcols_max = linesum;
- }
- curline = sign->se_lnum;
- linesum = 0;
- }
- if (sign->se_has_text_or_icon) {
- linesum++;
- }
- }
- if (linesum > buf->b_signcols_max) {
- buf->b_signcols_max = linesum;
+ if (!buf->b_signcols_valid) {
+ sign_entry_T *sign; // a sign in the sign list
+ int signcols = 0;
+ int linesum = 0;
+ linenr_T curline = 0;
+
+ FOR_ALL_SIGNS_IN_BUF(buf, sign) {
+ if (sign->se_lnum > curline) {
+ if (linesum > signcols) {
+ signcols = linesum;
}
+ curline = sign->se_lnum;
+ linesum = 0;
+ }
+ if (sign->se_has_text_or_icon) {
+ linesum++;
+ }
+ }
+ if (linesum > signcols) {
+ signcols = linesum;
+ }
- // Check if we need to redraw
- if (buf->b_signcols_max != buf->b_signcols) {
- buf->b_signcols = buf->b_signcols_max;
- redraw_buf_later(buf, NOT_VALID);
- }
+ // Check if we need to redraw
+ if (signcols != buf->b_signcols) {
+ buf->b_signcols = signcols;
+ redraw_buf_later(buf, NOT_VALID);
}
- return buf->b_signcols;
+ buf->b_signcols_valid = true;
+ }
+
+ return buf->b_signcols;
}
// Get "buf->b_fname", use "[No Name]" if it is NULL.
@@ -5653,16 +5635,12 @@ bool buf_contents_changed(buf_T *buf)
return differ;
}
-/*
- * Wipe out a buffer and decrement the last buffer number if it was used for
- * this buffer. Call this to wipe out a temp buffer that does not contain any
- * marks.
- */
-void
-wipe_buffer(
- buf_T *buf,
- bool aucmd // When true trigger autocommands.
-)
+/// Wipe out a buffer and decrement the last buffer number if it was used for
+/// this buffer. Call this to wipe out a temp buffer that does not contain any
+/// marks.
+///
+/// @param aucmd When true trigger autocommands.
+void wipe_buffer(buf_T *buf, bool aucmd)
{
if (!aucmd) {
// Don't trigger BufDelete autocommands here.
@@ -5691,3 +5669,4 @@ void buf_open_scratch(handle_T bufnr, char *bufname)
set_option_value("swf", 0L, NULL, OPT_LOCAL);
RESET_BINDING(curwin);
}
+
diff --git a/src/nvim/buffer.h b/src/nvim/buffer.h
index ac7ead5f92..02a2ac36f7 100644
--- a/src/nvim/buffer.h
+++ b/src/nvim/buffer.h
@@ -9,6 +9,7 @@
#include "nvim/func_attr.h"
#include "nvim/eval.h"
#include "nvim/macros.h"
+#include "nvim/memline.h"
// Values for buflist_getfile()
enum getf_values {
@@ -128,4 +129,10 @@ static inline void buf_inc_changedtick(buf_T *const buf)
buf_set_changedtick(buf, buf_get_changedtick(buf) + 1);
}
+static inline bool buf_is_empty(buf_T *buf)
+{
+ return buf->b_ml.ml_line_count == 1
+ && *ml_get_buf(buf, (linenr_T)1, false) == '\0';
+}
+
#endif // NVIM_BUFFER_H
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index e3e538bd12..0264a60117 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -226,8 +226,12 @@ typedef struct {
# define w_p_cuc w_onebuf_opt.wo_cuc // 'cursorcolumn'
int wo_cul;
# define w_p_cul w_onebuf_opt.wo_cul // 'cursorline'
+ char_u *wo_culopt;
+# define w_p_culopt w_onebuf_opt.wo_culopt // 'cursorlineopt'
char_u *wo_cc;
# define w_p_cc w_onebuf_opt.wo_cc // 'colorcolumn'
+ char_u *wo_sbr;
+# define w_p_sbr w_onebuf_opt.wo_sbr // 'showbreak'
char_u *wo_stl;
#define w_p_stl w_onebuf_opt.wo_stl // 'statusline'
int wo_scb;
@@ -525,6 +529,8 @@ struct file_buffer {
int b_flags; // various BF_ flags
int b_locked; // Buffer is being closed or referenced, don't
// let autocommands wipe it out.
+ int b_ro_locked; // Non-zero when the buffer can't be changed.
+ // Used for FileChangedRO
//
// b_ffname has the full path of the file (NULL for no name).
@@ -849,8 +855,8 @@ struct file_buffer {
// may use a different synblock_T.
sign_entry_T *b_signlist; // list of placed signs
- int b_signcols_max; // cached maximum number of sign columns
int b_signcols; // last calculated number of sign columns
+ bool b_signcols_valid; // calculated sign columns is valid
Terminal *terminal; // Terminal instance associated with the buffer
@@ -859,8 +865,14 @@ struct file_buffer {
int b_mapped_ctrl_c; // modes where CTRL-C is mapped
MarkTree b_marktree[1];
- Map(uint64_t, ExtmarkItem) *b_extmark_index;
- Map(uint64_t, ExtmarkNs) *b_extmark_ns; // extmark namespaces
+ Map(uint64_t, ExtmarkItem) b_extmark_index[1];
+ Map(uint64_t, ExtmarkNs) b_extmark_ns[1]; // extmark namespaces
+
+ VirtLines b_virt_lines;
+ uint64_t b_virt_line_mark;
+ int b_virt_line_pos;
+ bool b_virt_line_above;
+ bool b_virt_line_leftcol;
// array of channel_id:s which have asked to receive updates for this
// buffer.
@@ -1208,6 +1220,7 @@ struct window_S {
int tab3; ///< third tab character
int lead;
int trail;
+ int *multispace;
int conceal;
} w_p_lcs_chars;
@@ -1294,7 +1307,7 @@ struct window_S {
/*
* w_cline_height is the number of physical lines taken by the buffer line
- * that the cursor is on. We use this to avoid extra calls to plines().
+ * that the cursor is on. We use this to avoid extra calls to plines_win().
*/
int w_cline_height; // current size of cursor line
bool w_cline_folded; // cursor line is folded
@@ -1384,12 +1397,14 @@ struct window_S {
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
+ char_u w_p_culopt_flags; // flags for cursorline highlighting
long w_p_siso; // 'sidescrolloff' local value
long w_p_so; // 'scrolloff' local value
int w_briopt_min; // minimum width for breakindent
int w_briopt_shift; // additional shift for breakindent
bool w_briopt_sbr; // sbr in 'briopt'
+ int w_briopt_list; // additional indent for lists
// transform a pointer to a "onebuf" option into a "allbuf" option
#define GLOBAL_WO(p) ((char *)p + sizeof(winopt_T))
diff --git a/src/nvim/buffer_updates.c b/src/nvim/buffer_updates.c
index 5c573530d1..ee1b7ebc95 100644
--- a/src/nvim/buffer_updates.c
+++ b/src/nvim/buffer_updates.c
@@ -1,14 +1,14 @@
// 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/assert.h"
+#include "nvim/buffer.h"
#include "nvim/buffer_updates.h"
#include "nvim/extmark.h"
+#include "nvim/lua/executor.h"
#include "nvim/memline.h"
-#include "nvim/api/private/helpers.h"
#include "nvim/msgpack_rpc/channel.h"
-#include "nvim/lua/executor.h"
-#include "nvim/assert.h"
-#include "nvim/buffer.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "buffer_updates.c.generated.h"
@@ -17,8 +17,7 @@
// Register a channel. Return True if the channel was added, or already added.
// Return False if the channel couldn't be added because the buffer is
// unloaded.
-bool buf_updates_register(buf_T *buf, uint64_t channel_id,
- BufUpdateCallbacks cb, bool send_buffer)
+bool buf_updates_register(buf_T *buf, uint64_t channel_id, BufUpdateCallbacks cb, bool send_buffer)
{
// must fail if the buffer isn't loaded
if (buf->b_ml.ml_mfp == NULL) {
@@ -50,7 +49,7 @@ bool buf_updates_register(buf_T *buf, uint64_t channel_id,
if (send_buffer) {
Array args = ARRAY_DICT_INIT;
args.size = 6;
- args.items = xcalloc(sizeof(Object), args.size);
+ args.items = xcalloc(args.size, sizeof(Object));
// the first argument is always the buffer handle
args.items[0] = BUFFER_OBJ(buf->handle);
@@ -68,7 +67,7 @@ bool buf_updates_register(buf_T *buf, uint64_t channel_id,
if (line_count >= 1) {
linedata.size = line_count;
- linedata.items = xcalloc(sizeof(Object), line_count);
+ linedata.items = xcalloc(line_count, sizeof(Object));
buf_collect_lines(buf, line_count, 1, true, &linedata, NULL);
}
@@ -86,16 +85,16 @@ bool buf_updates_register(buf_T *buf, uint64_t channel_id,
bool buf_updates_active(buf_T *buf)
{
- return kv_size(buf->update_channels) || kv_size(buf->update_callbacks);
+ return kv_size(buf->update_channels) || kv_size(buf->update_callbacks);
}
void buf_updates_send_end(buf_T *buf, uint64_t channelid)
{
- Array args = ARRAY_DICT_INIT;
- args.size = 1;
- args.items = xcalloc(sizeof(Object), args.size);
- args.items[0] = BUFFER_OBJ(buf->handle);
- rpc_send_event(channelid, "nvim_buf_detach_event", args);
+ Array args = ARRAY_DICT_INIT;
+ args.size = 1;
+ args.items = xcalloc(args.size, sizeof(Object));
+ args.items[0] = BUFFER_OBJ(buf->handle);
+ rpc_send_event(channelid, "nvim_buf_detach_event", args);
}
void buf_updates_unregister(buf_T *buf, uint64_t channelid)
@@ -187,11 +186,8 @@ 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)
+void buf_updates_send_changes(buf_T *buf, linenr_T firstline, int64_t num_added,
+ int64_t num_removed, bool send_tick)
{
size_t deleted_codepoints, deleted_codeunits;
size_t deleted_bytes = ml_flush_deleted_bytes(buf, &deleted_codepoints,
@@ -211,7 +207,7 @@ void buf_updates_send_changes(buf_T *buf,
// send through the changes now channel contents now
Array args = ARRAY_DICT_INIT;
args.size = 6;
- args.items = xcalloc(sizeof(Object), args.size);
+ args.items = xcalloc(args.size, sizeof(Object));
// the first argument is always the buffer handle
args.items[0] = BUFFER_OBJ(buf->handle);
@@ -228,11 +224,11 @@ void buf_updates_send_changes(buf_T *buf,
// linedata of lines being swapped in
Array linedata = ARRAY_DICT_INIT;
if (num_added > 0) {
- STATIC_ASSERT(SIZE_MAX >= MAXLNUM, "size_t smaller than MAXLNUM");
- linedata.size = (size_t)num_added;
- linedata.items = xcalloc(sizeof(Object), (size_t)num_added);
- buf_collect_lines(buf, (size_t)num_added, firstline, true, &linedata,
- NULL);
+ STATIC_ASSERT(SIZE_MAX >= MAXLNUM, "size_t smaller than MAXLNUM");
+ linedata.size = (size_t)num_added;
+ linedata.items = xcalloc((size_t)num_added, sizeof(Object));
+ buf_collect_lines(buf, (size_t)num_added, firstline, true, &linedata,
+ NULL);
}
args.items[4] = ARRAY_OBJ(linedata);
args.items[5] = BOOLEAN_OBJ(false);
@@ -248,7 +244,7 @@ void buf_updates_send_changes(buf_T *buf,
// change notifications are so frequent that many dead channels will be
// cleared up quickly.
if (badchannelid != 0) {
- ELOG("Disabling buffer updates for dead channel %"PRIu64, badchannelid);
+ ELOG("Disabling buffer updates for dead channel %" PRIu64, badchannelid);
buf_updates_unregister(buf, badchannelid);
}
@@ -302,18 +298,16 @@ void buf_updates_send_changes(buf_T *buf,
kv_size(buf->update_callbacks) = j;
}
-void buf_updates_send_splice(
- buf_T *buf,
- int start_row, colnr_T start_col, bcount_t start_byte,
- int old_row, colnr_T old_col, bcount_t old_byte,
- int new_row, colnr_T new_col, bcount_t new_byte)
+void buf_updates_send_splice(buf_T *buf, int start_row, colnr_T start_col, bcount_t start_byte,
+ int old_row, colnr_T old_col, bcount_t old_byte, int new_row,
+ colnr_T new_col, bcount_t new_byte)
{
if (!buf_updates_active(buf)
|| (old_byte == 0 && new_byte == 0)) {
return;
}
- // notify each of the active callbakcs
+ // notify each of the active callbacks
size_t j = 0;
for (size_t i = 0; i < kv_size(buf->update_callbacks); i++) {
BufUpdateCallbacks cb = kv_A(buf->update_callbacks, i);
@@ -392,18 +386,18 @@ void buf_updates_changedtick(buf_T *buf)
void buf_updates_changedtick_single(buf_T *buf, uint64_t channel_id)
{
- Array args = ARRAY_DICT_INIT;
- args.size = 2;
- args.items = xcalloc(sizeof(Object), args.size);
+ Array args = ARRAY_DICT_INIT;
+ args.size = 2;
+ args.items = xcalloc(args.size, sizeof(Object));
- // the first argument is always the buffer handle
- args.items[0] = BUFFER_OBJ(buf->handle);
+ // the first argument is always the buffer handle
+ args.items[0] = BUFFER_OBJ(buf->handle);
- // next argument is b:changedtick
- args.items[1] = INTEGER_OBJ(buf_get_changedtick(buf));
+ // next argument is b:changedtick
+ args.items[1] = INTEGER_OBJ(buf_get_changedtick(buf));
- // don't try and clean up dead channels here
- rpc_send_event(channel_id, "nvim_buf_changedtick_event", args);
+ // don't try and clean up dead channels here
+ rpc_send_event(channel_id, "nvim_buf_changedtick_event", args);
}
void buffer_update_callbacks_free(BufUpdateCallbacks cb)
diff --git a/src/nvim/change.c b/src/nvim/change.c
index c0183d4317..4ac5edeaa9 100644
--- a/src/nvim/change.c
+++ b/src/nvim/change.c
@@ -12,16 +12,17 @@
#include "nvim/diff.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
+#include "nvim/extmark.h"
#include "nvim/fileio.h"
#include "nvim/fold.h"
#include "nvim/indent.h"
#include "nvim/indent_c.h"
#include "nvim/mark.h"
-#include "nvim/extmark.h"
#include "nvim/memline.h"
#include "nvim/misc1.h"
#include "nvim/move.h"
#include "nvim/option.h"
+#include "nvim/plines.h"
#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/state.h"
@@ -40,25 +41,25 @@
/// "col" is the column for the message; non-zero when in insert mode and
/// 'showmode' is on.
/// Careful: may trigger autocommands that reload the buffer.
-void change_warning(int col)
+void change_warning(buf_T *buf, int col)
{
static char *w_readonly = N_("W10: Warning: Changing a readonly file");
- if (curbuf->b_did_warn == false
+ if (buf->b_did_warn == false
&& curbufIsChanged() == 0
&& !autocmd_busy
- && curbuf->b_p_ro) {
- curbuf_lock++;
- apply_autocmds(EVENT_FILECHANGEDRO, NULL, NULL, false, curbuf);
- curbuf_lock--;
- if (!curbuf->b_p_ro) {
- return;
+ && buf->b_p_ro) {
+ buf->b_ro_locked++;
+ apply_autocmds(EVENT_FILECHANGEDRO, NULL, NULL, false, buf);
+ buf->b_ro_locked--;
+ if (!buf->b_p_ro) {
+ return;
}
// Do what msg() does, but with a column offset if the warning should
// be after the mode message.
msg_start();
if (msg_row == Rows - 1) {
- msg_col = col;
+ msg_col = col;
}
msg_source(HL_ATTR(HLF_W));
msg_ext_set_kind("wmsg");
@@ -70,10 +71,10 @@ void change_warning(int col)
ui_flush();
os_delay(1002L, true); // give the user time to think about it
}
- curbuf->b_did_warn = true;
+ buf->b_did_warn = true;
redraw_cmdline = false; // don't redraw and erase the message
if (msg_row < Rows - 1) {
- showmode();
+ showmode();
}
}
}
@@ -91,14 +92,13 @@ void changed(void)
// Give a warning about changing a read-only file. This may also
// check-out the file, thus change "curbuf"!
- change_warning(0);
+ change_warning(curbuf, 0);
// Create a swap file if that is wanted.
// Don't do this for "nofile" and "nowrite" buffer types.
if (curbuf->b_may_swap
- && !bt_dontwrite(curbuf)
- ) {
- int save_need_wait_return = need_wait_return;
+ && !bt_dontwrite(curbuf)) {
+ bool save_need_wait_return = need_wait_return;
need_wait_return = false;
ml_open_file(curbuf);
@@ -139,11 +139,10 @@ void changed_internal(void)
/// Common code for when a change was made.
/// See changed_lines() for the arguments.
/// Careful: may trigger autocommands that reload the buffer.
-static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume,
- long xtra)
+static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume, long xtra)
{
int i;
- pos_T *p;
+ pos_T *p;
int add;
// mark the buffer as modified
@@ -161,18 +160,18 @@ static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume,
// don't have an entry yet.
if (curbuf->b_new_change || curbuf->b_changelistlen == 0) {
if (curbuf->b_changelistlen == 0) {
- add = true;
+ add = true;
} else {
// Don't create a new entry when the line number is the same
// as the last one and the column is not too far away. Avoids
// creating many entries for typing "xxxxx".
p = &curbuf->b_changelist[curbuf->b_changelistlen - 1].mark;
if (p->lnum != lnum) {
- add = true;
+ add = true;
} else {
int cols = comp_textwidth(false);
if (cols == 0) {
- cols = 79;
+ cols = 79;
}
add = (p->col + cols < col || col + cols < p->col);
}
@@ -218,7 +217,7 @@ static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume,
if (wp->w_buffer == curbuf) {
// Mark this window to be redrawn later.
if (wp->w_redr_type < VALID) {
- wp->w_redr_type = VALID;
+ wp->w_redr_type = VALID;
}
// Check if a change in the buffer has invalidated the cached
@@ -234,11 +233,11 @@ static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume,
// inserting lines just above a closed fold. */
bool folded = hasFoldingWin(wp, lnum, &lnum, NULL, false, NULL);
if (wp->w_cursor.lnum == lnum) {
- wp->w_cline_folded = folded;
+ wp->w_cline_folded = folded;
}
folded = hasFoldingWin(wp, lnume, NULL, &lnume, false, NULL);
if (wp->w_cursor.lnum == lnume) {
- wp->w_cline_folded = folded;
+ wp->w_cline_folded = folded;
}
// If the changed line is in a range of previously folded lines,
@@ -246,14 +245,14 @@ static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume,
if (wp->w_cursor.lnum <= lnum) {
i = find_wl_entry(wp, lnum);
if (i >= 0 && wp->w_cursor.lnum > wp->w_lines[i].wl_lnum) {
- changed_line_abv_curs_win(wp);
+ changed_line_abv_curs_win(wp);
}
}
if (wp->w_cursor.lnum > lnum) {
- changed_line_abv_curs_win(wp);
+ changed_line_abv_curs_win(wp);
} else if (wp->w_cursor.lnum == lnum && wp->w_cursor.col >= col) {
- changed_cline_bef_curs_win(wp);
+ changed_cline_bef_curs_win(wp);
}
if (wp->w_botline >= lnum) {
// Assume that botline doesn't change (inserted lines make
@@ -290,13 +289,21 @@ static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume,
set_topline(wp, wp->w_topline);
}
- // Relative numbering may require updating more. Cursor line
- // highlighting probably needs to be updated if it's below the
- // change.
- if (wp->w_p_rnu
- || (wp->w_p_cul && lnum <= wp->w_last_cursorline)) {
+ // Relative numbering may require updating more.
+ if (wp->w_p_rnu) {
redraw_later(wp, SOME_VALID);
}
+
+ // Cursor line highlighting probably need to be updated with
+ // "VALID" if it's below the change.
+ // If the cursor line is inside the change we need to redraw more.
+ if (wp->w_p_cul) {
+ if (xtra == 0) {
+ redraw_later(wp, VALID);
+ } else if (lnum <= wp->w_last_cursorline) {
+ redraw_later(wp, SOME_VALID);
+ }
+ }
}
}
@@ -318,9 +325,9 @@ static void changedOneline(buf_T *buf, linenr_T lnum)
if (buf->b_mod_set) {
// find the maximum area that must be redisplayed
if (lnum < buf->b_mod_top) {
- buf->b_mod_top = lnum;
+ buf->b_mod_top = lnum;
} else if (lnum >= buf->b_mod_bot) {
- buf->b_mod_bot = lnum + 1;
+ buf->b_mod_bot = lnum + 1;
}
} else {
// set the area that must be redisplayed to one line
@@ -352,7 +359,7 @@ void changed_bytes(linenr_T lnum, colnr_T col)
redraw_later(wp, VALID);
wlnum = diff_lnum_win(lnum, wp);
if (wlnum > 0) {
- changedOneline(wp->w_buffer, wlnum);
+ changedOneline(wp->w_buffer, wlnum);
}
}
}
@@ -454,17 +461,15 @@ void changed_lines_buf(buf_T *buf, linenr_T lnum, linenr_T lnume, long xtra)
/// When only inserting lines, "lnum" and "lnume" are equal.
/// Takes care of calling changed() and updating b_mod_*.
/// Careful: may trigger autocommands that reload the buffer.
-void
-changed_lines(
- linenr_T lnum, // first line with change
- colnr_T col, // column in first line with change
- linenr_T lnume, // line below last changed line
- long xtra, // number of extra lines (negative when deleting)
- bool do_buf_event // some callers like undo/redo call changed_lines()
- // and then increment changedtick *again*. This flag
- // allows these callers to send the nvim_buf_lines_event
- // events after they're done modifying changedtick.
-)
+///
+/// @param lnum first line with change
+/// @param col column in first line with change
+/// @param lnume line below last changed line
+/// @param xtra number of extra lines (negative when deleting)
+/// @param do_buf_event some callers like undo/redo call changed_lines() and
+/// then increment changedtick *again*. This flag allows these callers to send
+/// the nvim_buf_lines_event events after they're done modifying changedtick.
+void changed_lines(linenr_T lnum, colnr_T col, linenr_T lnume, long xtra, bool do_buf_event)
{
changed_lines_buf(curbuf, lnum, lnume, xtra);
@@ -585,9 +590,9 @@ void ins_char_bytes(char_u *buf, size_t charlen)
// cells. May result in adding spaces to fill a gap.
colnr_T vcol;
getvcol(curwin, &curwin->w_cursor, NULL, &vcol, NULL);
- colnr_T new_vcol = vcol + chartabsize(buf, vcol);
+ colnr_T new_vcol = vcol + win_chartabsize(curwin, buf, vcol);
while (oldp[col + oldlen] != NUL && vcol < new_vcol) {
- vcol += chartabsize(oldp + col + oldlen, vcol);
+ vcol += win_chartabsize(curwin, oldp + col + oldlen, vcol);
// Don't need to remove a TAB that takes us to the right
// position.
if (vcol > new_vcol && oldp[col + oldlen] == TAB) {
@@ -600,7 +605,7 @@ void ins_char_bytes(char_u *buf, size_t charlen)
}
}
curwin->w_p_list = old_list;
- } else if (oldp[col] != NUL) {
+ } else if (oldp[col] != NUL) {
// normal replace
oldlen = (size_t)(*mb_ptr2len)(oldp + col);
}
@@ -648,8 +653,7 @@ void ins_char_bytes(char_u *buf, size_t charlen)
// show the match for right parens and braces.
if (p_sm && (State & INSERT)
&& msg_silent == 0
- && !ins_compl_active()
- ) {
+ && !ins_compl_active()) {
showmatch(utf_ptr2char(buf));
}
@@ -665,7 +669,7 @@ void ins_char_bytes(char_u *buf, size_t charlen)
/// Caller must have prepared for undo.
void ins_str(char_u *s)
{
- char_u *oldp, *newp;
+ char_u *oldp, *newp;
int newlen = (int)STRLEN(s);
int oldlen;
colnr_T col;
@@ -712,7 +716,7 @@ int del_chars(long count, int fixpos)
{
int bytes = 0;
long i;
- char_u *p;
+ char_u *p;
int l;
p = get_cursor_pos_ptr();
@@ -779,11 +783,10 @@ int del_bytes(colnr_T count, bool fixpos_arg, bool use_delcombine)
int movelen = oldlen - col - count + 1; // includes trailing NUL
if (movelen <= 1) {
// If we just took off the last character of a non-blank line, and
- // fixpos is TRUE, we don't want to end up positioned at the NUL,
+ // fixpos is true, we don't want to end up positioned at the NUL,
// unless "restart_edit" is set or 'virtualedit' contains "onemore".
if (col > 0 && fixpos && restart_edit == 0
- && (ve_flags & VE_ONEMORE) == 0
- ) {
+ && (ve_flags & VE_ONEMORE) == 0) {
curwin->w_cursor.col--;
curwin->w_cursor.coladd = 0;
curwin->w_cursor.col -= utf_head_off(oldp, oldp + curwin->w_cursor.col);
@@ -947,12 +950,10 @@ int copy_indent(int size, char_u *src)
/// "second_line_indent": indent for after ^^D in Insert mode or if flag
/// OPENLINE_COM_LIST
///
+/// @param dir FORWARD or BACKWARD
+///
/// @return true on success, false on failure
-int open_line(
- int dir, // FORWARD or BACKWARD
- int flags,
- int second_line_indent
-)
+int open_line(int dir, int flags, int second_line_indent)
{
char_u *next_line = NULL; // copy of the next line
char_u *p_extra = NULL; // what goes to next line
@@ -994,9 +995,9 @@ int open_line(
// the line, replacing what was there before and pushing the right
// stuff onto the replace stack. -- webb.
if (curwin->w_cursor.lnum < orig_line_count) {
- next_line = vim_strsave(ml_get(curwin->w_cursor.lnum + 1));
+ next_line = vim_strsave(ml_get(curwin->w_cursor.lnum + 1));
} else {
- next_line = vim_strsave((char_u *)"");
+ next_line = vim_strsave((char_u *)"");
}
// In VREPLACE mode, a NL replaces the rest of the line, and starts
@@ -1014,8 +1015,7 @@ int open_line(
}
if ((State & INSERT)
- && !(State & VREPLACE_FLAG)
- ) {
+ && !(State & VREPLACE_FLAG)) {
p_extra = saved_line + curwin->w_cursor.col;
if (do_si) { // need first char after new line break
p = skipwhite(p_extra);
@@ -1034,14 +1034,13 @@ int open_line(
// the prior line, and it should be truncated. Do this even if 'ai' is not
// set because automatically inserting a comment leader also sets did_ai.
if (dir == FORWARD && did_ai) {
- trunc_line = true;
+ trunc_line = true;
}
// 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
- ) {
+ || do_si) {
// count white space on current line
newindent = get_indent_str_vtab(saved_line,
curbuf->b_p_ts,
@@ -1057,15 +1056,15 @@ int open_line(
// "if (condition) {"
if (!trunc_line && do_si && *saved_line != NUL
&& (p_extra == NULL || first_char != '{')) {
- char_u *ptr;
+ char_u *ptr;
char_u last_char;
old_cursor = curwin->w_cursor;
ptr = saved_line;
if (flags & OPENLINE_DO_COM) {
- lead_len = get_leader_len(ptr, NULL, false, true);
+ lead_len = get_leader_len(ptr, NULL, false, true);
} else {
- lead_len = 0;
+ lead_len = 0;
}
if (dir == FORWARD) {
// Skip preprocessor directives, unless they are
@@ -1110,17 +1109,17 @@ int open_line(
// Find last non-blank in line
p = ptr + STRLEN(ptr) - 1;
while (p > ptr && ascii_iswhite(*p)) {
- p--;
+ p--;
}
last_char = *p;
// find the character just before the '{' or ';'
if (last_char == '{' || last_char == ';') {
if (p > ptr) {
- p--;
+ p--;
}
while (p > ptr && ascii_iswhite(*p)) {
- p--;
+ p--;
}
}
// Try to catch lines that are split over multiple
@@ -1142,12 +1141,12 @@ int open_line(
if (last_char == '{') {
did_si = true; // do indent
no_si = true; // don't delete it when '{' typed
- // Look for "if" and the like, use 'cinwords'.
- // Don't do this if the previous line ended in ';' or
- // '}'.
+ // Look for "if" and the like, use 'cinwords'.
+ // Don't do this if the previous line ended in ';' or
+ // '}'.
} else if (last_char != ';' && last_char != '}'
&& cin_is_cinword(ptr)) {
- did_si = true;
+ did_si = true;
}
}
} else { // dir == BACKWARD
@@ -1196,15 +1195,15 @@ int open_line(
lead_len = 0;
}
if (lead_len > 0) {
- char_u *lead_repl = NULL; // replaces comment leader
+ char_u *lead_repl = NULL; // replaces comment leader
int lead_repl_len = 0; // length of *lead_repl
char_u lead_middle[COM_MAX_LEN]; // middle-comment string
char_u lead_end[COM_MAX_LEN]; // end-comment string
- char_u *comment_end = NULL; // where lead_end has been found
+ char_u *comment_end = NULL; // where lead_end has been found
int extra_space = false; // append extra space
int current_flag;
int require_blank = false; // requires blank after middle
- char_u *p2;
+ char_u *p2;
// If the comment leader has the start, middle or end flag, it may not
// be used or may be replaced with the middle leader.
@@ -1295,7 +1294,7 @@ int open_line(
// Doing "O" on the end of a comment inserts the middle leader.
// Find the string for the middle leader, searching backwards.
while (p > curbuf->b_p_com && *p != ',') {
- p--;
+ p--;
}
for (lead_repl = p; lead_repl > curbuf->b_p_com
&& lead_repl[-1] != ':'; lead_repl--) {
@@ -1309,13 +1308,13 @@ int open_line(
// Check whether we allow automatic ending of comments
for (p2 = p; *p2 && *p2 != ':'; p2++) {
if (*p2 == COM_AUTO_END) {
- end_comment_pending = -1; // means we want to set it
+ end_comment_pending = -1; // means we want to set it
}
}
if (end_comment_pending == -1) {
// Find last character in end-comment string
while (*p2 && *p2 != ',') {
- p2++;
+ p2++;
}
end_comment_pending = p2[-1];
}
@@ -1325,7 +1324,7 @@ int open_line(
// Comment leader for first line only: Don't repeat leader
// when using "O", blank out leader when using "o".
if (dir == BACKWARD) {
- lead_len = 0;
+ lead_len = 0;
} else {
lead_repl = (char_u *)"";
lead_repl_len = 0;
@@ -1336,11 +1335,11 @@ int open_line(
if (lead_len > 0) {
// allocate buffer (may concatenate p_extra later)
int bytes = lead_len
- + lead_repl_len
- + extra_space
- + extra_len
- + (second_line_indent > 0 ? second_line_indent : 0)
- + 1;
+ + lead_repl_len
+ + extra_space
+ + extra_len
+ + (second_line_indent > 0 ? second_line_indent : 0)
+ + 1;
assert(bytes >= 0);
leader = xmalloc((size_t)bytes);
allocated = leader; // remember to free it later
@@ -1354,11 +1353,11 @@ int open_line(
for (p = lead_flags; *p != NUL && *p != ':'; ) {
if (*p == COM_RIGHT || *p == COM_LEFT) {
- c = *p++;
+ c = *p++;
} else if (ascii_isdigit(*p) || *p == '-') {
- off = getdigits_int(&p, true, 0);
+ off = getdigits_int(&p, true, 0);
} else {
- p++;
+ p++;
}
}
if (c == COM_RIGHT) { // right adjusted leader
@@ -1374,7 +1373,7 @@ int open_line(
int repl_size = vim_strnsize(lead_repl,
lead_repl_len);
int old_size = 0;
- char_u *endp = p;
+ char_u *endp = p;
int l;
while (old_size < repl_size && p > leader) {
@@ -1383,14 +1382,14 @@ int open_line(
}
l = lead_repl_len - (int)(endp - p);
if (l != 0) {
- memmove(endp + l, endp,
- (size_t)((leader + lead_len) - endp));
+ memmove(endp + l, endp,
+ (size_t)((leader + lead_len) - endp));
}
lead_len += l;
}
memmove(p, lead_repl, (size_t)lead_repl_len);
if (p + lead_repl_len > leader + lead_len) {
- p[lead_repl_len] = NUL;
+ p[lead_repl_len] = NUL;
}
// blank-out any other chars from the old leader.
@@ -1408,7 +1407,7 @@ int open_line(
lead_len -= l;
*p = ' ';
} else if (!ascii_iswhite(*p)) {
- *p = ' ';
+ *p = ' ';
}
}
} else { // left adjusted leader
@@ -1425,12 +1424,12 @@ int open_line(
for (i = 0; i < lead_len && p[i] != NUL; i += l) {
l = (*mb_ptr2len)(p + i);
if (vim_strnsize(p, i + l) > repl_size) {
- break;
+ break;
}
}
if (i != lead_repl_len) {
- memmove(p + lead_repl_len, p + i,
- (size_t)(lead_len - i - (p - leader)));
+ memmove(p + lead_repl_len, p + i,
+ (size_t)(lead_len - i - (p - leader)));
lead_len += lead_repl_len - i;
}
}
@@ -1467,8 +1466,7 @@ int open_line(
// Recompute the indent, it may have changed.
if (curbuf->b_p_ai
- || do_si
- ) {
+ || do_si) {
newindent = get_indent_str_vtab(leader,
curbuf->b_p_ts,
curbuf->b_p_vts_array, false);
@@ -1488,7 +1486,7 @@ int open_line(
&& leader[lead_len - 1] == ' ') {
// Don't do it when there is a tab before the space
if (vim_strchr(skipwhite(leader), '\t') != NULL) {
- break;
+ break;
}
lead_len--;
off--;
@@ -1497,7 +1495,7 @@ int open_line(
// If the leader ends in white space, don't add an
// extra space
if (lead_len > 0 && ascii_iswhite(leader[lead_len - 1])) {
- extra_space = false;
+ extra_space = false;
}
leader[lead_len] = NUL;
}
@@ -1512,8 +1510,7 @@ int open_line(
// if a new indent will be set below, remove the indent that
// is in the comment leader
if (newindent
- || did_si
- ) {
+ || did_si) {
while (lead_len && ascii_iswhite(*leader)) {
lead_len--;
newcol--;
@@ -1550,7 +1547,7 @@ int open_line(
// When in REPLACE mode, put the deleted blanks on the replace stack,
// preceded by a NUL, so they can be put back when a BS is entered.
if (REPLACE_NORMAL(State)) {
- replace_push(NUL); // end of extra blanks
+ replace_push(NUL); // end of extra blanks
}
if (curbuf->b_p_ai || (flags & OPENLINE_DELSPACES)) {
while ((*p_extra == ' ' || *p_extra == '\t')
@@ -1568,7 +1565,7 @@ int open_line(
}
if (p_extra == NULL) {
- p_extra = (char_u *)""; // append empty line
+ p_extra = (char_u *)""; // append empty line
}
// concatenate leader and p_extra, if there is a leader
@@ -1632,8 +1629,7 @@ int open_line(
inhibit_delete_count++;
if (newindent
- || did_si
- ) {
+ || did_si) {
curwin->w_cursor.lnum++;
if (did_si) {
int sw = get_sw_value(curbuf);
@@ -1697,9 +1693,8 @@ int open_line(
// TODO(vigoux): maybe there is issues there with expandtabs ?
int cols_spliced = 0;
if (new_len < curwin->w_cursor.col) {
- extmark_splice_cols(
- curbuf, (int)curwin->w_cursor.lnum - 1,
- new_len, curwin->w_cursor.col - new_len, 0, kExtmarkUndo);
+ extmark_splice_cols(curbuf, (int)curwin->w_cursor.lnum - 1,
+ new_len, curwin->w_cursor.col - new_len, 0, kExtmarkUndo);
cols_spliced = curwin->w_cursor.col - new_len;
}
@@ -1732,7 +1727,7 @@ int open_line(
}
if (did_append) {
changed_lines(curwin->w_cursor.lnum, 0, curwin->w_cursor.lnum, 1L, true);
- // bail out and just get the final lenght of the line we just manipulated
+ // bail out and just get the final length of the line we just manipulated
bcount_t extra = (bcount_t)STRLEN(ml_get(curwin->w_cursor.lnum));
extmark_splice(curbuf, (int)curwin->w_cursor.lnum-1, 0,
0, 0, 0, 1, 0, 1+extra, kExtmarkUndo);
@@ -1806,7 +1801,7 @@ theend:
/// If "fixpos" is true fix the cursor position when done.
void truncate_line(int fixpos)
{
- char_u *newp;
+ char_u *newp;
linenr_T lnum = curwin->w_cursor.lnum;
colnr_T col = curwin->w_cursor.col;
@@ -1828,18 +1823,18 @@ void truncate_line(int fixpos)
/// Delete "nlines" lines at the cursor.
/// Saves the lines for undo first if "undo" is true.
-void del_lines(long nlines, int undo)
+void del_lines(long nlines, bool undo)
{
long n;
linenr_T first = curwin->w_cursor.lnum;
if (nlines <= 0) {
- return;
+ return;
}
// save the deleted lines for undo
if (undo && u_savedel(first, nlines) == FAIL) {
- return;
+ return;
}
for (n = 0; n < nlines; ) {
@@ -1852,7 +1847,7 @@ void del_lines(long nlines, int undo)
// If we delete the last line in the file, stop
if (first > curbuf->b_ml.ml_line_count) {
- break;
+ break;
}
}
diff --git a/src/nvim/channel.c b/src/nvim/channel.c
index 60af11e94b..30243a3102 100644
--- a/src/nvim/channel.c
+++ b/src/nvim/channel.c
@@ -12,11 +12,11 @@
#include "nvim/msgpack_rpc/server.h"
#include "nvim/os/shell.h"
#ifdef WIN32
-# include "nvim/os/pty_conpty_win.h"
# include "nvim/os/os_win_console.h"
+# include "nvim/os/pty_conpty_win.h"
#endif
-#include "nvim/path.h"
#include "nvim/ascii.h"
+#include "nvim/path.h"
static bool did_stdio = false;
@@ -32,13 +32,9 @@ static uint64_t next_chan_id = CHAN_STDERR+1;
/// Teardown the module
void channel_teardown(void)
{
- if (!channels) {
- return;
- }
-
Channel *channel;
- map_foreach_value(channels, channel, {
+ map_foreach_value(&channels, channel, {
channel_close(channel->id, kChannelPartAll, NULL);
});
}
@@ -70,7 +66,7 @@ bool channel_close(uint64_t id, ChannelPart part, const char **error)
if (part == kChannelPartRpc || part == kChannelPartAll) {
close_main = true;
if (chan->is_rpc) {
- rpc_close(chan);
+ rpc_close(chan);
} else if (part == kChannelPartRpc) {
*error = (const char *)e_invstream;
return false;
@@ -82,68 +78,68 @@ bool channel_close(uint64_t id, ChannelPart part, const char **error)
}
switch (chan->streamtype) {
- case kChannelStreamSocket:
- if (!close_main) {
- *error = (const char *)e_invstream;
- return false;
- }
- stream_may_close(&chan->stream.socket);
- break;
+ case kChannelStreamSocket:
+ if (!close_main) {
+ *error = (const char *)e_invstream;
+ return false;
+ }
+ stream_may_close(&chan->stream.socket);
+ break;
- case kChannelStreamProc:
- proc = (Process *)&chan->stream.proc;
- if (part == kChannelPartStdin || close_main) {
- stream_may_close(&proc->in);
- }
- if (part == kChannelPartStdout || close_main) {
- stream_may_close(&proc->out);
- }
- if (part == kChannelPartStderr || part == kChannelPartAll) {
- stream_may_close(&proc->err);
- }
- if (proc->type == kProcessTypePty && part == kChannelPartAll) {
- pty_process_close_master(&chan->stream.pty);
- }
+ case kChannelStreamProc:
+ proc = (Process *)&chan->stream.proc;
+ if (part == kChannelPartStdin || close_main) {
+ stream_may_close(&proc->in);
+ }
+ if (part == kChannelPartStdout || close_main) {
+ stream_may_close(&proc->out);
+ }
+ if (part == kChannelPartStderr || part == kChannelPartAll) {
+ stream_may_close(&proc->err);
+ }
+ if (proc->type == kProcessTypePty && part == kChannelPartAll) {
+ pty_process_close_master(&chan->stream.pty);
+ }
- break;
+ break;
- case kChannelStreamStdio:
- if (part == kChannelPartStdin || close_main) {
- stream_may_close(&chan->stream.stdio.in);
- }
- if (part == kChannelPartStdout || close_main) {
- stream_may_close(&chan->stream.stdio.out);
- }
- if (part == kChannelPartStderr) {
- *error = (const char *)e_invstream;
- return false;
- }
- break;
+ case kChannelStreamStdio:
+ if (part == kChannelPartStdin || close_main) {
+ stream_may_close(&chan->stream.stdio.in);
+ }
+ if (part == kChannelPartStdout || close_main) {
+ stream_may_close(&chan->stream.stdio.out);
+ }
+ if (part == kChannelPartStderr) {
+ *error = (const char *)e_invstream;
+ return false;
+ }
+ break;
- case kChannelStreamStderr:
- if (part != kChannelPartAll && part != kChannelPartStderr) {
- *error = (const char *)e_invstream;
- return false;
- }
- if (!chan->stream.err.closed) {
- chan->stream.err.closed = true;
- // Don't close on exit, in case late error messages
- if (!exiting) {
- fclose(stderr);
- }
- channel_decref(chan);
+ case kChannelStreamStderr:
+ if (part != kChannelPartAll && part != kChannelPartStderr) {
+ *error = (const char *)e_invstream;
+ return false;
+ }
+ if (!chan->stream.err.closed) {
+ chan->stream.err.closed = true;
+ // Don't close on exit, in case late error messages
+ if (!exiting) {
+ fclose(stderr);
}
- break;
+ channel_decref(chan);
+ }
+ break;
- case kChannelStreamInternal:
- if (!close_main) {
- *error = (const char *)e_invstream;
- return false;
- }
- break;
+ case kChannelStreamInternal:
+ if (!close_main) {
+ *error = (const char *)e_invstream;
+ return false;
+ }
+ break;
- default:
- abort();
+ default:
+ abort();
}
return true;
@@ -152,7 +148,6 @@ bool channel_close(uint64_t id, ChannelPart part, const char **error)
/// Initializes the module
void channel_init(void)
{
- channels = pmap_new(uint64_t)();
channel_alloc(kChannelStreamStderr);
rpc_init();
}
@@ -177,7 +172,7 @@ Channel *channel_alloc(ChannelStreamType type)
chan->exit_status = -1;
chan->streamtype = type;
assert(chan->id <= VARNUMBER_MAX);
- pmap_put(uint64_t)(channels, chan->id, chan);
+ pmap_put(uint64_t)(&channels, chan->id, chan);
return chan;
}
@@ -245,11 +240,15 @@ static void free_channel_event(void **argv)
rpc_free(chan);
}
+ if (chan->streamtype == kChannelStreamProc) {
+ process_free(&chan->stream.proc);
+ }
+
callback_reader_free(&chan->on_data);
callback_reader_free(&chan->on_stderr);
callback_free(&chan->on_exit);
- pmap_del(uint64_t)(channels, chan->id);
+ pmap_del(uint64_t)(&channels, chan->id);
multiqueue_free(chan->events);
xfree(chan);
}
@@ -259,7 +258,7 @@ static void channel_destroy_early(Channel *chan)
if ((chan->id != --next_chan_id)) {
abort();
}
- pmap_del(uint64_t)(channels, chan->id);
+ pmap_del(uint64_t)(&channels, chan->id);
chan->id = 0;
if ((--chan->refcount != 0)) {
@@ -289,6 +288,9 @@ static void close_cb(Stream *stream, void *data)
/// `on_stdout` is ignored
/// @param[in] detach True if the job should not be killed when nvim exits,
/// ignored if `pty` is true
+/// @param[in] stdin_mode Stdin mode. Either kChannelStdinPipe to open a
+/// channel for stdin or kChannelStdinNull to leave
+/// stdin disconnected.
/// @param[in] cwd Initial working directory for the job. Nvim's working
/// directory if `cwd` is NULL
/// @param[in] pty_width Width of the pty, ignored if `pty` is false
@@ -299,12 +301,10 @@ static void close_cb(Stream *stream, void *data)
/// < 0 if the job can't start
///
/// @returns [allocated] channel
-Channel *channel_job_start(char **argv, CallbackReader on_stdout,
- CallbackReader on_stderr, Callback on_exit,
- bool pty, bool rpc, bool overlapped, bool detach,
- const char *cwd,
- uint16_t pty_width, uint16_t pty_height,
- dict_T *env, varnumber_T *status_out)
+Channel *channel_job_start(char **argv, CallbackReader on_stdout, CallbackReader on_stderr,
+ Callback on_exit, bool pty, bool rpc, bool overlapped, bool detach,
+ ChannelStdinMode stdin_mode, const char *cwd, uint16_t pty_width,
+ uint16_t pty_height, dict_T *env, varnumber_T *status_out)
{
assert(cwd == NULL || os_isdir_executable(cwd));
@@ -345,7 +345,7 @@ Channel *channel_job_start(char **argv, CallbackReader on_stdout,
proc->overlapped = overlapped;
char *cmd = xstrdup(proc->argv[0]);
- bool has_out, has_err;
+ bool has_in, has_out, has_err;
if (proc->type == kProcessTypePty) {
has_out = true;
has_err = false;
@@ -353,7 +353,17 @@ Channel *channel_job_start(char **argv, CallbackReader on_stdout,
has_out = rpc || callback_reader_set(chan->on_data);
has_err = callback_reader_set(chan->on_stderr);
}
- int status = process_spawn(proc, true, has_out, has_err);
+
+ switch (stdin_mode) {
+ case kChannelStdinPipe:
+ has_in = true;
+ break;
+ case kChannelStdinNull:
+ has_in = false;
+ break;
+ }
+
+ int status = process_spawn(proc, has_in, has_out, has_err);
if (status) {
EMSG3(_(e_jobspawn), os_strerror(status), cmd);
xfree(cmd);
@@ -369,7 +379,9 @@ Channel *channel_job_start(char **argv, CallbackReader on_stdout,
tv_dict_free(proc->env);
}
- wstream_init(&proc->in, 0);
+ if (has_in) {
+ wstream_init(&proc->in, 0);
+ }
if (has_out) {
rstream_init(&proc->out, 0);
}
@@ -395,8 +407,7 @@ Channel *channel_job_start(char **argv, CallbackReader on_stdout,
}
-uint64_t channel_connect(bool tcp, const char *address,
- bool rpc, CallbackReader on_output,
+uint64_t channel_connect(bool tcp, const char *address, bool rpc, CallbackReader on_output,
int timeout, const char **error)
{
Channel *channel;
@@ -456,8 +467,7 @@ void channel_from_connection(SocketWatcher *watcher)
/// Creates an API channel from stdin/stdout. This is used when embedding
/// Neovim
-uint64_t channel_from_stdio(bool rpc, CallbackReader on_output,
- const char **error)
+uint64_t channel_from_stdio(bool rpc, CallbackReader on_output, const char **error)
FUNC_ATTR_NONNULL_ALL
{
if (!headless_mode && !embedded_mode) {
@@ -500,8 +510,8 @@ uint64_t channel_from_stdio(bool rpc, CallbackReader on_output,
}
/// @param data will be consumed
-size_t channel_send(uint64_t id, char *data, size_t len,
- bool data_owned, const char **error)
+size_t channel_send(uint64_t id, char *data, size_t len, bool data_owned, const char **error)
+ FUNC_ATTR_NONNULL_ALL
{
Channel *chan = find_channel(id);
size_t written = 0;
@@ -569,22 +579,20 @@ static inline list_T *buffer_to_tv_list(const char *const buf, const size_t len)
return l;
}
-void on_channel_data(Stream *stream, RBuffer *buf, size_t count,
- void *data, bool eof)
+void on_channel_data(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof)
{
Channel *chan = data;
on_channel_output(stream, chan, buf, count, eof, &chan->on_data);
}
-void on_job_stderr(Stream *stream, RBuffer *buf, size_t count,
- void *data, bool eof)
+void on_job_stderr(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof)
{
Channel *chan = data;
on_channel_output(stream, chan, buf, count, eof, &chan->on_stderr);
}
-static void on_channel_output(Stream *stream, Channel *chan, RBuffer *buf,
- size_t count, bool eof, CallbackReader *reader)
+static void on_channel_output(Stream *stream, Channel *chan, RBuffer *buf, size_t count, bool eof,
+ CallbackReader *reader)
{
// stub variable, to keep reading consistent with the order of events, only
// consider the count parameter.
@@ -683,9 +691,7 @@ static void channel_process_exit_cb(Process *proc, int status, void *data)
{
Channel *chan = data;
if (chan->term) {
- char msg[sizeof("\r\n[Process exited ]") + NUMBUFLEN];
- snprintf(msg, sizeof msg, "\r\n[Process exited %d]", proc->status);
- terminal_close(chan->term, msg);
+ terminal_close(chan->term, status);
}
// If process did not exit, we only closed the handle of a detached process.
@@ -839,32 +845,43 @@ Dictionary channel_info(uint64_t id)
const char *stream_desc, *mode_desc;
switch (chan->streamtype) {
- case kChannelStreamProc:
- stream_desc = "job";
- if (chan->stream.proc.type == kProcessTypePty) {
- const char *name = pty_process_tty_name(&chan->stream.pty);
- PUT(info, "pty", STRING_OBJ(cstr_to_string(name)));
+ case kChannelStreamProc: {
+ stream_desc = "job";
+ if (chan->stream.proc.type == kProcessTypePty) {
+ const char *name = pty_process_tty_name(&chan->stream.pty);
+ PUT(info, "pty", STRING_OBJ(cstr_to_string(name)));
+ }
+
+ char **p = chan->stream.proc.argv;
+ Array argv = ARRAY_DICT_INIT;
+ if (p != NULL) {
+ while (*p != NULL) {
+ ADD(argv, STRING_OBJ(cstr_to_string(*p)));
+ p++;
}
- break;
+ }
+ PUT(info, "argv", ARRAY_OBJ(argv));
+ break;
+ }
- case kChannelStreamStdio:
- stream_desc = "stdio";
- break;
+ case kChannelStreamStdio:
+ stream_desc = "stdio";
+ break;
- case kChannelStreamStderr:
- stream_desc = "stderr";
- break;
+ case kChannelStreamStderr:
+ stream_desc = "stderr";
+ break;
- case kChannelStreamInternal:
- PUT(info, "internal", BOOLEAN_OBJ(true));
- FALLTHROUGH;
+ case kChannelStreamInternal:
+ PUT(info, "internal", BOOLEAN_OBJ(true));
+ FALLTHROUGH;
- case kChannelStreamSocket:
- stream_desc = "socket";
- break;
+ case kChannelStreamSocket:
+ stream_desc = "socket";
+ break;
- default:
- abort();
+ default:
+ abort();
}
PUT(info, "stream", STRING_OBJ(cstr_to_string(stream_desc)));
@@ -886,7 +903,7 @@ Array channel_all_info(void)
{
Channel *channel;
Array ret = ARRAY_DICT_INIT;
- map_foreach_value(channels, channel, {
+ map_foreach_value(&channels, channel, {
ADD(ret, DICTIONARY_OBJ(channel_info(channel->id)));
});
return ret;
diff --git a/src/nvim/channel.h b/src/nvim/channel.h
index 9d26852ce5..9bc0df3615 100644
--- a/src/nvim/channel.h
+++ b/src/nvim/channel.h
@@ -28,6 +28,10 @@ typedef enum {
kChannelPartAll
} ChannelPart;
+typedef enum {
+ kChannelStdinPipe,
+ kChannelStdinNull,
+} ChannelStdinMode;
typedef struct {
Stream in;
@@ -85,7 +89,7 @@ struct Channel {
bool callback_scheduled;
};
-EXTERN PMap(uint64_t) *channels INIT(= NULL);
+EXTERN PMap(uint64_t) channels INIT(= MAP_INIT);
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "channel.h.generated.h"
@@ -94,7 +98,7 @@ EXTERN PMap(uint64_t) *channels INIT(= NULL);
/// @returns Channel with the id or NULL if not found
static inline Channel *find_channel(uint64_t id)
{
- return pmap_get(uint64_t)(channels, id);
+ return pmap_get(uint64_t)(&channels, id);
}
static inline Stream *channel_instream(Channel *chan)
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index e2d844a351..f899ebf57c 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -6,14 +6,15 @@
/// Code related to character sets.
#include <assert.h>
+#include <inttypes.h>
#include <string.h>
#include <wctype.h>
-#include <inttypes.h>
-#include "nvim/vim.h"
#include "nvim/ascii.h"
#include "nvim/charset.h"
+#include "nvim/cursor.h"
#include "nvim/func_attr.h"
+#include "nvim/garray.h"
#include "nvim/indent.h"
#include "nvim/main.h"
#include "nvim/mark.h"
@@ -21,14 +22,14 @@
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/misc1.h"
-#include "nvim/garray.h"
#include "nvim/move.h"
#include "nvim/option.h"
#include "nvim/os_unix.h"
+#include "nvim/path.h"
+#include "nvim/plines.h"
#include "nvim/state.h"
#include "nvim/strings.h"
-#include "nvim/path.h"
-#include "nvim/cursor.h"
+#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "charset.c.generated.h"
@@ -40,11 +41,11 @@ static bool chartab_initialized = false;
// b_chartab[] is an array with 256 bits, each bit representing one of the
// characters 0-255.
#define SET_CHARTAB(buf, c) \
- (buf)->b_chartab[(unsigned)(c) >> 6] |= (1ull << ((c) & 0x3f))
+ (buf)->b_chartab[(unsigned)(c) >> 6] |= (1ull << ((c) & 0x3f))
#define RESET_CHARTAB(buf, c) \
- (buf)->b_chartab[(unsigned)(c) >> 6] &= ~(1ull << ((c) & 0x3f))
+ (buf)->b_chartab[(unsigned)(c) >> 6] &= ~(1ull << ((c) & 0x3f))
#define GET_CHARTAB_TAB(chartab, c) \
- ((chartab)[(unsigned)(c) >> 6] & (1ull << ((c) & 0x3f)))
+ ((chartab)[(unsigned)(c) >> 6] & (1ull << ((c) & 0x3f)))
// Table used below, see init_chartab() for an explanation
static char_u g_chartab[256];
@@ -211,7 +212,7 @@ int buf_init_chartab(buf_T *buf, int global)
if (i == 0) {
// (re)set ID flag
if (tilde) {
- g_chartab[c] &= (uint8_t)~CT_ID_CHAR;
+ g_chartab[c] &= (uint8_t) ~CT_ID_CHAR;
} else {
g_chartab[c] |= CT_ID_CHAR;
}
@@ -223,7 +224,7 @@ int buf_init_chartab(buf_T *buf, int global)
if (tilde) {
g_chartab[c] = (uint8_t)((g_chartab[c] & ~CT_CELL_MASK)
+ ((dy_flags & DY_UHEX) ? 4 : 2));
- g_chartab[c] &= (uint8_t)~CT_PRINT_CHAR;
+ g_chartab[c] &= (uint8_t) ~CT_PRINT_CHAR;
} else {
g_chartab[c] = (uint8_t)((g_chartab[c] & ~CT_CELL_MASK) + 1);
g_chartab[c] |= CT_PRINT_CHAR;
@@ -232,7 +233,7 @@ int buf_init_chartab(buf_T *buf, int global)
} else if (i == 2) {
// (re)set fname flag
if (tilde) {
- g_chartab[c] &= (uint8_t)~CT_FNAME_CHAR;
+ g_chartab[c] &= (uint8_t) ~CT_FNAME_CHAR;
} else {
g_chartab[c] |= CT_FNAME_CHAR;
}
@@ -309,7 +310,7 @@ void trans_characters(char_u *buf, int bufsize)
///
/// @return number of bytes needed to hold a translation of `s`, NUL byte not
/// included.
-size_t transstr_len(const char *const s)
+size_t transstr_len(const char *const s, bool untab)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
{
const char *p = s;
@@ -330,6 +331,9 @@ size_t transstr_len(const char *const s)
}
}
p += l;
+ } else if (*p == TAB && !untab) {
+ len += 1;
+ p++;
} else {
const int b2c_l = byte2cells((uint8_t)(*p++));
// Illegal byte sequence may occupy up to 4 characters.
@@ -345,9 +349,10 @@ size_t transstr_len(const char *const s)
/// @param[out] buf Buffer to which result should be saved.
/// @param[in] len Buffer length. Resulting string may not occupy more then
/// len - 1 bytes (one for trailing NUL byte).
+/// @param[in] untab remove tab characters
///
/// @return length of the resulting string, without the NUL byte.
-size_t transstr_buf(const char *const s, char *const buf, const size_t len)
+size_t transstr_buf(const char *const s, char *const buf, const size_t len, bool untab)
FUNC_ATTR_NONNULL_ALL
{
const char *p = s;
@@ -378,6 +383,8 @@ size_t transstr_buf(const char *const s, char *const buf, const size_t len)
}
}
p += l;
+ } else if (*p == TAB && !untab) {
+ *buf_p++ = *p++;
} else {
const char *const tb = (const char *)transchar_byte((uint8_t)(*p++));
const size_t tb_len = strlen(tb);
@@ -400,14 +407,14 @@ size_t transstr_buf(const char *const s, char *const buf, const size_t len)
/// @param[in] s String to replace characters from.
///
/// @return [allocated] translated string
-char *transstr(const char *const s)
+char *transstr(const char *const s, bool untab)
FUNC_ATTR_NONNULL_RET
{
// Compute the length of the result, taking account of unprintable
// multi-byte characters.
- const size_t len = transstr_len((const char *)s) + 1;
+ const size_t len = transstr_len((const char *)s, untab) + 1;
char *const buf = xmalloc(len);
- transstr_buf(s, buf, len);
+ transstr_buf(s, buf, len, untab);
return buf;
}
@@ -416,7 +423,7 @@ char *transstr(const char *const s)
///
/// When "buf" is NULL, return an allocated string.
/// Otherwise, put the result in buf, limited by buflen, and return buf.
-char_u* str_foldcase(char_u *str, int orglen, char_u *buf, int buflen)
+char_u *str_foldcase(char_u *str, int orglen, char_u *buf, int buflen)
FUNC_ATTR_NONNULL_RET
{
garray_T ga;
@@ -733,80 +740,6 @@ int vim_strnsize(char_u *s, int len)
return size;
}
-/// Return the number of characters 'c' will take on the screen, taking
-/// into account the size of a tab.
-/// Use a define to make it fast, this is used very often!!!
-/// Also see getvcol() below.
-///
-/// @param p
-/// @param col
-///
-/// @return Number of characters.
-#define RET_WIN_BUF_CHARTABSIZE(wp, buf, p, col) \
- if (*(p) == TAB && (!(wp)->w_p_list || wp->w_p_lcs_chars.tab1)) { \
- return tabstop_padding(col, (buf)->b_p_ts, (buf)->b_p_vts_array); \
- } else { \
- return ptr2cells(p); \
- }
-
-int chartabsize(char_u *p, colnr_T col)
-{
- RET_WIN_BUF_CHARTABSIZE(curwin, curbuf, p, col)
-}
-
-static int win_chartabsize(win_T *wp, char_u *p, colnr_T col)
-{
- RET_WIN_BUF_CHARTABSIZE(wp, wp->w_buffer, p, col)
-}
-
-/// Return the number of characters the string 's' will take on the screen,
-/// taking into account the size of a tab.
-///
-/// @param s
-///
-/// @return Number of characters the string will take on the screen.
-int linetabsize(char_u *s)
-{
- return linetabsize_col(0, s);
-}
-
-/// Like linetabsize(), but starting at column "startcol".
-///
-/// @param startcol
-/// @param s
-///
-/// @return Number of characters the string will take on the screen.
-int linetabsize_col(int startcol, char_u *s)
-{
- colnr_T col = startcol;
- char_u *line = s; /* pointer to start of line, for breakindent */
-
- while (*s != NUL) {
- col += lbr_chartabsize_adv(line, &s, col);
- }
- return (int)col;
-}
-
-/// Like linetabsize(), but for a given window instead of the current one.
-///
-/// @param wp
-/// @param line
-/// @param len
-///
-/// @return Number of characters the string will take on the screen.
-unsigned int win_linetabsize(win_T *wp, char_u *line, colnr_T len)
-{
- colnr_T col = 0;
-
- for (char_u *s = line;
- *s != NUL && (len == MAXCOL || s < line + len);
- MB_PTR_ADV(s)) {
- col += win_lbr_chartabsize(wp, line, s, col, NULL);
- }
-
- return (unsigned int)col;
-}
-
/// Check that "c" is a normal identifier character:
/// Letters and characters from the 'isident' option.
///
@@ -936,229 +869,6 @@ bool vim_isprintc_strict(int c)
return c > 0 && (g_chartab[c] & CT_PRINT_CHAR);
}
-/// like chartabsize(), but also check for line breaks on the screen
-///
-/// @param line
-/// @param s
-/// @param col
-///
-/// @return The number of characters taken up on the screen.
-int lbr_chartabsize(char_u *line, unsigned char *s, colnr_T col)
-{
- if (!curwin->w_p_lbr && (*p_sbr == NUL) && !curwin->w_p_bri) {
- if (curwin->w_p_wrap) {
- return win_nolbr_chartabsize(curwin, s, col, NULL);
- }
- RET_WIN_BUF_CHARTABSIZE(curwin, curbuf, s, col)
- }
- return win_lbr_chartabsize(curwin, line == NULL ? s: line, s, col, NULL);
-}
-
-/// Call lbr_chartabsize() and advance the pointer.
-///
-/// @param line
-/// @param s
-/// @param col
-///
-/// @return The number of characters take up on the screen.
-int lbr_chartabsize_adv(char_u *line, char_u **s, colnr_T col)
-{
- int retval;
-
- retval = lbr_chartabsize(line, *s, col);
- MB_PTR_ADV(*s);
- return retval;
-}
-
-/// This function is used very often, keep it fast!!!!
-///
-/// If "headp" not NULL, set *headp to the size of what we for 'showbreak'
-/// string at start of line. Warning: *headp is only set if it's a non-zero
-/// value, init to 0 before calling.
-///
-/// @param wp
-/// @param line
-/// @param s
-/// @param col
-/// @param headp
-///
-/// @return The number of characters taken up on the screen.
-int win_lbr_chartabsize(win_T *wp, char_u *line, char_u *s, colnr_T col, int *headp)
-{
- colnr_T col2;
- colnr_T col_adj = 0; /* col + screen size of tab */
- colnr_T colmax;
- int added;
- int mb_added = 0;
- int numberextra;
- char_u *ps;
- int n;
-
- // No 'linebreak', 'showbreak' and 'breakindent': return quickly.
- if (!wp->w_p_lbr && !wp->w_p_bri && (*p_sbr == NUL)) {
- if (wp->w_p_wrap) {
- return win_nolbr_chartabsize(wp, s, col, headp);
- }
- RET_WIN_BUF_CHARTABSIZE(wp, wp->w_buffer, s, col)
- }
-
- // First get normal size, without 'linebreak'
- int size = win_chartabsize(wp, s, col);
- int c = *s;
- if (*s == TAB) {
- col_adj = size - 1;
- }
-
- // If 'linebreak' set check at a blank before a non-blank if the line
- // needs a break here
- if (wp->w_p_lbr
- && vim_isbreak(c)
- && !vim_isbreak((int)s[1])
- && wp->w_p_wrap
- && (wp->w_width_inner != 0)) {
- // Count all characters from first non-blank after a blank up to next
- // non-blank after a blank.
- numberextra = win_col_off(wp);
- col2 = col;
- colmax = (colnr_T)(wp->w_width_inner - numberextra - col_adj);
-
- if (col >= colmax) {
- colmax += col_adj;
- n = colmax + win_col_off2(wp);
-
- if (n > 0) {
- colmax += (((col - colmax) / n) + 1) * n - col_adj;
- }
- }
-
- for (;;) {
- ps = s;
- MB_PTR_ADV(s);
- c = *s;
-
- if (!(c != NUL
- && (vim_isbreak(c) || col2 == col || !vim_isbreak((int)(*ps))))) {
- break;
- }
-
- col2 += win_chartabsize(wp, s, col2);
-
- if (col2 >= colmax) { /* doesn't fit */
- size = colmax - col + col_adj;
- break;
- }
- }
- } else if ((size == 2)
- && (MB_BYTE2LEN(*s) > 1)
- && wp->w_p_wrap
- && in_win_border(wp, col)) {
- // Count the ">" in the last column.
- ++size;
- mb_added = 1;
- }
-
- // May have to add something for 'breakindent' and/or 'showbreak'
- // string at start of line.
- // Set *headp to the size of what we add.
- added = 0;
-
- if ((*p_sbr != NUL || wp->w_p_bri) && wp->w_p_wrap && (col != 0)) {
- colnr_T sbrlen = 0;
- int numberwidth = win_col_off(wp);
-
- numberextra = numberwidth;
- col += numberextra + mb_added;
-
- if (col >= (colnr_T)wp->w_width_inner) {
- col -= wp->w_width_inner;
- numberextra = wp->w_width_inner - (numberextra - win_col_off2(wp));
- if (col >= numberextra && numberextra > 0) {
- col %= numberextra;
- }
- if (*p_sbr != NUL) {
- sbrlen = (colnr_T)MB_CHARLEN(p_sbr);
- if (col >= sbrlen) {
- col -= sbrlen;
- }
- }
- if (col >= numberextra && numberextra > 0) {
- col %= numberextra;
- } else if (col > 0 && numberextra > 0) {
- col += numberwidth - win_col_off2(wp);
- }
-
- numberwidth -= win_col_off2(wp);
- }
-
- if (col == 0 || (col + size + sbrlen > (colnr_T)wp->w_width_inner)) {
- if (*p_sbr != NUL) {
- if (size + sbrlen + numberwidth > (colnr_T)wp->w_width_inner) {
- // Calculate effective window width.
- int width = (colnr_T)wp->w_width_inner - sbrlen - numberwidth;
- int prev_width = col ? ((colnr_T)wp->w_width_inner - (sbrlen + col))
- : 0;
-
- if (width <= 0) {
- width = 1;
- }
- added += ((size - prev_width) / width) * vim_strsize(p_sbr);
- if ((size - prev_width) % width) {
- // Wrapped, add another length of 'sbr'.
- added += vim_strsize(p_sbr);
- }
- } else {
- added += vim_strsize(p_sbr);
- }
- }
-
- if (wp->w_p_bri)
- added += get_breakindent_win(wp, line);
-
- size += added;
- if (col != 0) {
- added = 0;
- }
- }
- }
-
- if (headp != NULL) {
- *headp = added + mb_added;
- }
- return size;
-}
-
-/// Like win_lbr_chartabsize(), except that we know 'linebreak' is off and
-/// 'wrap' is on. This means we need to check for a double-byte character that
-/// doesn't fit at the end of the screen line.
-///
-/// @param wp
-/// @param s
-/// @param col
-/// @param headp
-///
-/// @return The number of characters take up on the screen.
-static int win_nolbr_chartabsize(win_T *wp, char_u *s, colnr_T col, int *headp)
-{
- int n;
-
- if ((*s == TAB) && (!wp->w_p_list || wp->w_p_lcs_chars.tab1)) {
- return tabstop_padding(col,
- wp->w_buffer->b_p_ts,
- wp->w_buffer->b_p_vts_array);
- }
- n = ptr2cells(s);
-
- // Add one cell for a double-width character in the last column of the
- // window, displayed with a ">".
- if ((n == 2) && (MB_BYTE2LEN(*s) > 1) && in_win_border(wp, col)) {
- if (headp != NULL) {
- *headp = 1;
- }
- return 3;
- }
- return n;
-}
-
/// Check that virtual column "vcol" is in the rightmost column of window "wp".
///
/// @param wp window
@@ -1202,12 +912,11 @@ bool in_win_border(win_T *wp, colnr_T vcol)
/// @param start
/// @param cursor
/// @param end
-void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor,
- colnr_T *end)
+void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *end)
{
colnr_T vcol;
char_u *ptr; // points to current char
- char_u *posptr; // points to char at pos->col
+ char_u *posptr; // points to char at pos->col
char_u *line; // start of the line
int incr;
int head;
@@ -1237,7 +946,7 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor,
// Also use this when 'list' is set but tabs take their normal size.
if ((!wp->w_p_list || (wp->w_p_lcs_chars.tab1 != NUL))
&& !wp->w_p_lbr
- && (*p_sbr == NUL)
+ && *get_showbreak_value(wp) == NUL
&& !wp->w_p_bri ) {
for (;;) {
head = 0;
@@ -1355,8 +1064,7 @@ colnr_T getvcol_nolist(pos_T *posp)
/// @param start
/// @param cursor
/// @param end
-void getvvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor,
- colnr_T *end)
+void getvvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *end)
{
colnr_T col;
colnr_T coladd;
@@ -1411,8 +1119,7 @@ void getvvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor,
/// @param pos2
/// @param left
/// @param right
-void getvcols(win_T *wp, pos_T *pos1, pos_T *pos2, colnr_T *left,
- colnr_T *right)
+void getvcols(win_T *wp, pos_T *pos1, pos_T *pos2, colnr_T *left, colnr_T *right)
{
colnr_T from1;
colnr_T from2;
@@ -1446,15 +1153,29 @@ void getvcols(win_T *wp, pos_T *pos1, pos_T *pos2, colnr_T *left,
/// skipwhite: skip over ' ' and '\t'.
///
-/// @param[in] q String to skip in.
+/// @param[in] p String to skip in.
///
/// @return Pointer to character after the skipped whitespace.
-char_u *skipwhite(const char_u *q)
+char_u *skipwhite(const char_u *const p)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
FUNC_ATTR_NONNULL_RET
{
- const char_u *p = q;
- while (ascii_iswhite(*p)) {
+ return skipwhite_len(p, STRLEN(p));
+}
+
+/// Like `skipwhite`, but skip up to `len` characters.
+/// @see skipwhite
+///
+/// @param[in] p String to skip in.
+/// @param[in] len Max length to skip.
+///
+/// @return Pointer to character after the skipped whitespace, or the `len`-th
+/// character in the string.
+char_u *skipwhite_len(const char_u *p, size_t len)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
+ FUNC_ATTR_NONNULL_RET
+{
+ for (; len > 0 && ascii_iswhite(*p); len--) {
p++;
}
return (char_u *)p;
@@ -1494,7 +1215,7 @@ char_u *skipdigits(const char_u *q)
/// @param q pointer to string
///
/// @return Pointer to the character after the skipped digits.
-const char* skipbin(const char *q)
+const char *skipbin(const char *q)
FUNC_ATTR_PURE
FUNC_ATTR_NONNULL_ALL
FUNC_ATTR_NONNULL_RET
@@ -1513,7 +1234,7 @@ const char* skipbin(const char *q)
///
/// @return Pointer to the character after the skipped digits and hex
/// characters.
-char_u* skiphex(char_u *q)
+char_u *skiphex(char_u *q)
{
char_u *p = q;
while (ascii_isxdigit(*p)) {
@@ -1528,7 +1249,7 @@ char_u* skiphex(char_u *q)
/// @param q
///
/// @return Pointer to the digit or (NUL after the string).
-char_u* skiptodigit(char_u *q)
+char_u *skiptodigit(char_u *q)
{
char_u *p = q;
while (*p != NUL && !ascii_isdigit(*p)) {
@@ -1543,7 +1264,7 @@ char_u* skiptodigit(char_u *q)
/// @param q pointer to string
///
/// @return Pointer to the binary character or (NUL after the string).
-const char* skiptobin(const char *q)
+const char *skiptobin(const char *q)
FUNC_ATTR_PURE
FUNC_ATTR_NONNULL_ALL
FUNC_ATTR_NONNULL_RET
@@ -1561,7 +1282,7 @@ const char* skiptobin(const char *q)
/// @param q
///
/// @return Pointer to the hex character or (NUL after the string).
-char_u* skiptohex(char_u *q)
+char_u *skiptohex(char_u *q)
{
char_u *p = q;
while (*p != NUL && !ascii_isxdigit(*p)) {
@@ -1590,7 +1311,7 @@ char_u *skiptowhite(const char_u *p)
/// @param p
///
/// @return Pointer to the next whitespace character.
-char_u* skiptowhite_esc(char_u *p) {
+char_u *skiptowhite_esc(char_u *p) {
while (*p != ' ' && *p != '\t' && *p != NUL) {
if (((*p == '\\') || (*p == Ctrl_V)) && (*(p + 1) != NUL)) {
++p;
@@ -1600,6 +1321,18 @@ char_u* skiptowhite_esc(char_u *p) {
return p;
}
+/// Skip over text until '\n' or NUL.
+///
+/// @param[in] p Text to skip over.
+///
+/// @return Pointer to the next '\n' or NUL character.
+char_u *skip_to_newline(const char_u *const p)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
+ FUNC_ATTR_NONNULL_RET
+{
+ return (char_u *)xstrchrnul((const char *)p, NL);
+}
+
/// Gets a number from a string and skips over it, signalling overflow.
///
/// @param[out] pp A pointer to a pointer to char_u.
@@ -1681,6 +1414,8 @@ bool vim_isblankline(char_u *lbuf)
/// If "prep" is not NULL, returns a flag to indicate the type of the number:
/// 0 decimal
/// '0' octal
+/// 'O' octal
+/// 'o' octal
/// 'B' bin
/// 'b' bin
/// 'X' hex
@@ -1692,68 +1427,81 @@ bool vim_isblankline(char_u *lbuf)
/// If "what" contains STR2NR_OCT recognize octal numbers.
/// If "what" contains STR2NR_HEX recognize hex numbers.
/// If "what" contains STR2NR_FORCE always assume bin/oct/hex.
+/// If "what" contains STR2NR_QUOTE ignore embedded single quotes
/// If maxlen > 0, check at a maximum maxlen chars.
+/// If strict is true, check the number strictly. return *len = 0 if fail.
///
/// @param start
/// @param prep Returns guessed type of number 0 = decimal, 'x' or 'X' is
-/// hexadecimal, '0' = octal, 'b' or 'B' is binary. When using
-/// STR2NR_FORCE is always zero.
+/// hexadecimal, '0', 'o' or 'O' is octal, 'b' or 'B' is binary.
+/// When using STR2NR_FORCE is always zero.
/// @param len Returns the detected length of number.
/// @param what Recognizes what number passed, @see ChStr2NrFlags.
/// @param nptr Returns the signed result.
/// @param unptr Returns the unsigned result.
/// @param maxlen Max length of string to check.
-void vim_str2nr(const char_u *const start, int *const prep, int *const len,
- const int what, varnumber_T *const nptr,
- uvarnumber_T *const unptr, const int maxlen)
+/// @param strict If true, fail if the number has unexpected trailing
+/// alpha-numeric chars: *len is set to 0 and nothing else is
+/// returned.
+void vim_str2nr(const char_u *const start, int *const prep, int *const len, const int what,
+ varnumber_T *const nptr, uvarnumber_T *const unptr, const int maxlen,
+ const bool strict)
FUNC_ATTR_NONNULL_ARG(1)
{
const char *ptr = (const char *)start;
#define STRING_ENDED(ptr) \
- (!(maxlen == 0 || (int)((ptr) - (const char *)start) < maxlen))
+ (!(maxlen == 0 || (int)((ptr) - (const char *)start) < maxlen))
int pre = 0; // default is decimal
const bool negative = (ptr[0] == '-');
uvarnumber_T un = 0;
+ if (len != NULL) {
+ *len = 0;
+ }
+
if (negative) {
ptr++;
}
if (what & STR2NR_FORCE) {
- // When forcing main consideration is skipping the prefix. Octal and decimal
- // numbers have no prefixes to skip. pre is not set.
- switch ((unsigned)what & (~(unsigned)STR2NR_FORCE)) {
- case STR2NR_HEX: {
- if (!STRING_ENDED(ptr + 2)
- && ptr[0] == '0'
- && (ptr[1] == 'x' || ptr[1] == 'X')
- && ascii_isxdigit(ptr[2])) {
- ptr += 2;
- }
- goto vim_str2nr_hex;
+ // When forcing main consideration is skipping the prefix. Decimal numbers
+ // have no prefixes to skip. pre is not set.
+ switch (what & ~(STR2NR_FORCE | STR2NR_QUOTE)) {
+ case STR2NR_HEX:
+ if (!STRING_ENDED(ptr + 2)
+ && ptr[0] == '0'
+ && (ptr[1] == 'x' || ptr[1] == 'X')
+ && ascii_isxdigit(ptr[2])) {
+ ptr += 2;
}
- case STR2NR_BIN: {
- if (!STRING_ENDED(ptr + 2)
- && ptr[0] == '0'
- && (ptr[1] == 'b' || ptr[1] == 'B')
- && ascii_isbdigit(ptr[2])) {
- ptr += 2;
- }
- goto vim_str2nr_bin;
- }
- case STR2NR_OCT: {
- goto vim_str2nr_oct;
- }
- case 0: {
- goto vim_str2nr_dec;
+ goto vim_str2nr_hex;
+ case STR2NR_BIN:
+ if (!STRING_ENDED(ptr + 2)
+ && ptr[0] == '0'
+ && (ptr[1] == 'b' || ptr[1] == 'B')
+ && ascii_isbdigit(ptr[2])) {
+ ptr += 2;
}
- default: {
- abort();
+ goto vim_str2nr_bin;
+ // Make STR2NR_OOCT work the same as STR2NR_OCT when forcing.
+ case STR2NR_OCT:
+ case STR2NR_OOCT:
+ case STR2NR_OCT | STR2NR_OOCT:
+ if (!STRING_ENDED(ptr + 2)
+ && ptr[0] == '0'
+ && (ptr[1] == 'o' || ptr[1] == 'O')
+ && ascii_isodigit(ptr[2])) {
+ ptr += 2;
}
+ goto vim_str2nr_oct;
+ case 0:
+ goto vim_str2nr_dec;
+ default:
+ abort();
}
- } else if ((what & (STR2NR_HEX|STR2NR_OCT|STR2NR_BIN))
- && !STRING_ENDED(ptr + 1)
- && ptr[0] == '0' && ptr[1] != '8' && ptr[1] != '9') {
+ } else if ((what & (STR2NR_HEX | STR2NR_OCT | STR2NR_OOCT | STR2NR_BIN))
+ && !STRING_ENDED(ptr + 1) && ptr[0] == '0' && ptr[1] != '8'
+ && ptr[1] != '9') {
pre = ptr[1];
// Detect hexadecimal: 0x or 0X followed by hex digit.
if ((what & STR2NR_HEX)
@@ -1771,10 +1519,18 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
ptr += 2;
goto vim_str2nr_bin;
}
- // Detect octal number: zero followed by octal digits without '8' or '9'.
+ // Detect octal: 0o or 0O followed by octal digits (without '8' or '9').
+ if ((what & STR2NR_OOCT)
+ && !STRING_ENDED(ptr + 2)
+ && (pre == 'O' || pre == 'o')
+ && ascii_isodigit(ptr[2])) {
+ ptr += 2;
+ goto vim_str2nr_oct;
+ }
+ // Detect old octal format: 0 followed by octal digits.
pre = 0;
if (!(what & STR2NR_OCT)
- || !('0' <= ptr[1] && ptr[1] <= '7')) {
+ || !ascii_isodigit(ptr[1])) {
goto vim_str2nr_dec;
}
for (int i = 2; !STRING_ENDED(ptr + i) && ascii_isdigit(ptr[i]); i++) {
@@ -1788,11 +1544,22 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
goto vim_str2nr_dec;
}
- // Do the string-to-numeric conversion "manually" to avoid sscanf quirks.
+ // Do the conversion manually to avoid sscanf() quirks.
abort(); // Should’ve used goto earlier.
#define PARSE_NUMBER(base, cond, conv) \
do { \
- while (!STRING_ENDED(ptr) && (cond)) { \
+ const char *const after_prefix = ptr; \
+ while (!STRING_ENDED(ptr)) { \
+ if ((what & STR2NR_QUOTE) && ptr > after_prefix && *ptr == '\'') { \
+ ptr++; \
+ if (!STRING_ENDED(ptr) && (cond)) { \
+ continue; \
+ } \
+ ptr--; \
+ } \
+ if (!(cond)) { \
+ break; \
+ } \
const uvarnumber_T digit = (uvarnumber_T)(conv); \
/* avoid ubsan error for overflow */ \
if (un < UVARNUMBER_MAX / base \
@@ -1809,7 +1576,7 @@ vim_str2nr_bin:
PARSE_NUMBER(2, (*ptr == '0' || *ptr == '1'), (*ptr - '0'));
goto vim_str2nr_proceed;
vim_str2nr_oct:
- PARSE_NUMBER(8, ('0' <= *ptr && *ptr <= '7'), (*ptr - '0'));
+ PARSE_NUMBER(8, (ascii_isodigit(*ptr)), (*ptr - '0'));
goto vim_str2nr_proceed;
vim_str2nr_dec:
PARSE_NUMBER(10, (ascii_isdigit(*ptr)), (*ptr - '0'));
@@ -1820,6 +1587,12 @@ vim_str2nr_hex:
#undef PARSE_NUMBER
vim_str2nr_proceed:
+ // Check for an alpha-numeric character immediately following, that is
+ // most likely a typo.
+ if (strict && ptr - (const char *)start != maxlen && ASCII_ISALNUM(*ptr)) {
+ return;
+ }
+
if (prep != NULL) {
*prep = pre;
}
diff --git a/src/nvim/charset.h b/src/nvim/charset.h
index e657ce19b6..2fef4d78a2 100644
--- a/src/nvim/charset.h
+++ b/src/nvim/charset.h
@@ -23,13 +23,20 @@ typedef enum {
STR2NR_BIN = (1 << 0), ///< Allow binary numbers.
STR2NR_OCT = (1 << 1), ///< Allow octal numbers.
STR2NR_HEX = (1 << 2), ///< Allow hexadecimal numbers.
+ STR2NR_OOCT = (1 << 3), ///< Octal with prefix "0o": 0o777
/// Force one of the above variants.
///
/// STR2NR_FORCE|STR2NR_DEC is actually not different from supplying zero
/// as flags, but still present for completeness.
- STR2NR_FORCE = (1 << 3),
+ ///
+ /// STR2NR_FORCE|STR2NR_OCT|STR2NR_OOCT is the same as STR2NR_FORCE|STR2NR_OCT
+ /// or STR2NR_FORCE|STR2NR_OOCT.
+ STR2NR_FORCE = (1 << 7),
/// Recognize all formats vim_str2nr() can recognize.
- STR2NR_ALL = STR2NR_BIN | STR2NR_OCT | STR2NR_HEX,
+ STR2NR_ALL = STR2NR_BIN | STR2NR_OCT | STR2NR_HEX | STR2NR_OOCT,
+ /// Disallow octals numbers without the 0o prefix.
+ STR2NR_NO_OCT = STR2NR_BIN | STR2NR_HEX | STR2NR_OOCT,
+ STR2NR_QUOTE = (1 << 4), ///< Ignore embedded single quotes.
} ChStr2NrFlags;
#ifdef INCLUDE_GENERATED_DECLARATIONS
diff --git a/src/nvim/context.c b/src/nvim/context.c
index 4162daa6ca..1db7938ef4 100644
--- a/src/nvim/context.c
+++ b/src/nvim/context.c
@@ -3,13 +3,13 @@
// Context: snapshot of the entire editor state as one big object/map
+#include "nvim/api/private/helpers.h"
+#include "nvim/api/vim.h"
#include "nvim/context.h"
#include "nvim/eval/encode.h"
#include "nvim/ex_docmd.h"
#include "nvim/option.h"
#include "nvim/shada.h"
-#include "nvim/api/vim.h"
-#include "nvim/api/private/helpers.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "context.c.generated.h"
diff --git a/src/nvim/cursor.c b/src/nvim/cursor.c
index 5d2210dc7d..e334fd166e 100644
--- a/src/nvim/cursor.c
+++ b/src/nvim/cursor.c
@@ -1,24 +1,25 @@
// 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 <stdbool.h>
#include <inttypes.h>
+#include <stdbool.h>
+#include "nvim/ascii.h"
#include "nvim/assert.h"
#include "nvim/change.h"
-#include "nvim/cursor.h"
#include "nvim/charset.h"
+#include "nvim/cursor.h"
+#include "nvim/extmark.h"
#include "nvim/fold.h"
+#include "nvim/mark.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/misc1.h"
#include "nvim/move.h"
+#include "nvim/plines.h"
#include "nvim/screen.h"
-#include "nvim/extmark.h"
#include "nvim/state.h"
#include "nvim/vim.h"
-#include "nvim/ascii.h"
-#include "nvim/mark.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "cursor.c.generated.h"
@@ -62,7 +63,7 @@ int coladvance_force(colnr_T wcol)
if (wcol == MAXCOL) {
curwin->w_valid &= ~VALID_VIRTCOL;
} else {
- /* Virtcol is valid */
+ // Virtcol is valid
curwin->w_valid |= VALID_VIRTCOL;
curwin->w_virtcol = wcol;
}
@@ -82,27 +83,25 @@ int coladvance(colnr_T wcol)
{
int rc = getvpos(&curwin->w_cursor, wcol);
- if (wcol == MAXCOL || rc == FAIL)
+ if (wcol == MAXCOL || rc == FAIL) {
curwin->w_valid &= ~VALID_VIRTCOL;
- else if (*get_cursor_pos_ptr() != TAB) {
- /* Virtcol is valid when not on a TAB */
+ } else if (*get_cursor_pos_ptr() != TAB) {
+ // Virtcol is valid when not on a TAB
curwin->w_valid |= VALID_VIRTCOL;
curwin->w_virtcol = wcol;
}
return rc;
}
-static int coladvance2(
- pos_T *pos,
- bool addspaces, // change the text to achieve our goal?
- bool finetune, // change char offset for the exact column
- colnr_T wcol_arg // column to move to (can be negative)
-)
+/// @param addspaces change the text to achieve our goal?
+/// @param finetune change char offset for the exact column
+/// @param wcol_arg column to move to (can be negative)
+static int coladvance2(pos_T *pos, bool addspaces, bool finetune, colnr_T wcol_arg)
{
colnr_T wcol = wcol_arg;
int idx;
- char_u *ptr;
- char_u *line;
+ char_u *ptr;
+ char_u *line;
colnr_T col = 0;
int csize = 0;
int one_more;
@@ -120,8 +119,9 @@ static int coladvance2(
if ((addspaces || finetune) && !VIsual_active) {
curwin->w_curswant = linetabsize(line) + one_more;
- if (curwin->w_curswant > 0)
+ if (curwin->w_curswant > 0) {
--curwin->w_curswant;
+ }
}
} else {
int width = curwin->w_width_inner - win_col_off(curwin);
@@ -129,10 +129,12 @@ static int coladvance2(
if (finetune
&& curwin->w_p_wrap
&& curwin->w_width_inner != 0
- && wcol >= (colnr_T)width) {
+ && wcol >= (colnr_T)width
+ && width > 0) {
csize = linetabsize(line);
- if (csize > 0)
+ if (csize > 0) {
csize--;
+ }
if (wcol / width > (colnr_T)csize / width
&& ((State & INSERT) == 0 || (int)wcol > csize + 1)) {
@@ -146,7 +148,7 @@ static int coladvance2(
ptr = line;
while (col <= wcol && *ptr != NUL) {
- /* Count a tab for what it's worth (if list mode not on) */
+ // Count a tab for what it's worth (if list mode not on)
csize = win_lbr_chartabsize(curwin, line, ptr, col, &head);
MB_PTR_ADV(ptr);
col += csize;
@@ -160,7 +162,7 @@ static int coladvance2(
*/
if (col > wcol || (!virtual_active() && one_more == 0)) {
idx -= 1;
- /* Don't count the chars from 'showbreak'. */
+ // Don't count the chars from 'showbreak'.
csize -= head;
col -= csize;
}
@@ -173,7 +175,7 @@ static int coladvance2(
* filled with spaces. */
if (line[idx] == NUL) {
- /* Append spaces */
+ // Append spaces
int correct = wcol - col;
size_t newline_size;
STRICT_ADD(idx, correct, &newline_size, size_t);
@@ -186,13 +188,14 @@ static int coladvance2(
idx += correct;
col = wcol;
} else {
- /* Break a tab */
+ // Break a tab
int linelen = (int)STRLEN(line);
- int correct = wcol - col - csize + 1; /* negative!! */
- char_u *newline;
+ int correct = wcol - col - csize + 1; // negative!!
+ char_u *newline;
- if (-correct > csize)
+ if (-correct > csize) {
return FAIL;
+ }
size_t n;
STRICT_ADD(linelen - 1, csize, &n, size_t);
@@ -214,16 +217,17 @@ static int coladvance2(
}
}
- if (idx < 0)
+ if (idx < 0) {
pos->col = 0;
- else
+ } else {
pos->col = idx;
+ }
pos->coladd = 0;
if (finetune) {
if (wcol == MAXCOL) {
- /* The width of the last character is used to set coladd. */
+ // The width of the last character is used to set coladd.
if (!one_more) {
colnr_T scol, ecol;
@@ -317,15 +321,15 @@ void check_pos(buf_T *buf, pos_T *pos)
colnr_T len;
if (pos->lnum > buf->b_ml.ml_line_count) {
- pos->lnum = buf->b_ml.ml_line_count;
+ pos->lnum = buf->b_ml.ml_line_count;
}
if (pos->col > 0) {
- line = ml_get_buf(buf, pos->lnum, false);
- len = (colnr_T)STRLEN(line);
- if (pos->col > len) {
- pos->col = len;
- }
+ line = ml_get_buf(buf, pos->lnum, false);
+ len = (colnr_T)STRLEN(line);
+ if (pos->col > len) {
+ pos->col = len;
+ }
}
}
@@ -338,11 +342,13 @@ void check_cursor_lnum(void)
/* If there is a closed fold at the end of the file, put the cursor in
* its first line. Otherwise in the last line. */
if (!hasFolding(curbuf->b_ml.ml_line_count,
- &curwin->w_cursor.lnum, NULL))
+ &curwin->w_cursor.lnum, NULL)) {
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+ }
}
- if (curwin->w_cursor.lnum <= 0)
+ if (curwin->w_cursor.lnum <= 0) {
curwin->w_cursor.lnum = 1;
+ }
}
/*
@@ -428,8 +434,9 @@ void adjust_cursor_col(void)
{
if (curwin->w_cursor.col > 0
&& (!VIsual_active || *p_sel == 'o')
- && gchar_cursor() == NUL)
+ && gchar_cursor() == NUL) {
--curwin->w_cursor.col;
+ }
}
/*
@@ -471,14 +478,15 @@ bool leftcol_changed(void)
coladvance(s - 1);
} else if (s < curwin->w_leftcol) {
retval = true;
- if (coladvance(e + 1) == FAIL) { /* there isn't another character */
- curwin->w_leftcol = s; /* adjust w_leftcol instead */
+ if (coladvance(e + 1) == FAIL) { // there isn't another character
+ curwin->w_leftcol = s; // adjust w_leftcol instead
changed_cline_bef_curs();
}
}
- if (retval)
+ if (retval) {
curwin->w_set_curswant = true;
+ }
redraw_later(curwin, NOT_VALID);
return retval;
}
diff --git a/src/nvim/cursor_shape.c b/src/nvim/cursor_shape.c
index 0d21080aa5..128bc480da 100644
--- a/src/nvim/cursor_shape.c
+++ b/src/nvim/cursor_shape.c
@@ -3,15 +3,16 @@
#include <assert.h>
#include <stdint.h>
-#include "nvim/vim.h"
+
+#include "nvim/api/private/helpers.h"
#include "nvim/ascii.h"
+#include "nvim/charset.h"
#include "nvim/cursor_shape.h"
#include "nvim/ex_getln.h"
-#include "nvim/charset.h"
#include "nvim/strings.h"
#include "nvim/syntax.h"
-#include "nvim/api/private/helpers.h"
#include "nvim/ui.h"
+#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "cursor_shape.c.generated.h"
@@ -56,10 +57,14 @@ Array mode_style_array(void)
if (cur->used_for & SHAPE_CURSOR) {
String shape_str;
switch (cur->shape) {
- case SHAPE_BLOCK: shape_str = cstr_to_string("block"); break;
- case SHAPE_VER: shape_str = cstr_to_string("vertical"); break;
- case SHAPE_HOR: shape_str = cstr_to_string("horizontal"); break;
- default: shape_str = cstr_to_string("unknown");
+ case SHAPE_BLOCK:
+ shape_str = cstr_to_string("block"); break;
+ case SHAPE_VER:
+ shape_str = cstr_to_string("vertical"); break;
+ case SHAPE_HOR:
+ shape_str = cstr_to_string("horizontal"); break;
+ default:
+ shape_str = cstr_to_string("unknown");
}
PUT(dic, "cursor_shape", STRING_OBJ(shape_str));
PUT(dic, "cell_percentage", INTEGER_OBJ(cur->percentage));
@@ -90,12 +95,12 @@ Array mode_style_array(void)
/// @returns error message for an illegal option, NULL otherwise.
char_u *parse_shape_opt(int what)
{
- char_u *modep;
- char_u *colonp;
- char_u *commap;
- char_u *slashp;
- char_u *p = NULL;
- char_u *endp;
+ char_u *modep;
+ char_u *colonp;
+ char_u *commap;
+ char_u *slashp;
+ char_u *p = NULL;
+ char_u *endp;
int idx = 0; // init for GCC
int all_idx;
int len;
@@ -142,14 +147,18 @@ char_u *parse_shape_opt(int what)
if (len == 1 && TOLOWER_ASC(modep[0]) == 'a') {
all_idx = SHAPE_IDX_COUNT - 1;
} else {
- for (idx = 0; idx < SHAPE_IDX_COUNT; ++idx)
- if (STRNICMP(modep, shape_table[idx].name, len) == 0)
+ for (idx = 0; idx < SHAPE_IDX_COUNT; ++idx) {
+ if (STRNICMP(modep, shape_table[idx].name, len) == 0) {
break;
+ }
+ }
if (idx == SHAPE_IDX_COUNT
- || (shape_table[idx].used_for & what) == 0)
+ || (shape_table[idx].used_for & what) == 0) {
return (char_u *)N_("E546: Illegal mode");
- if (len == 2 && modep[0] == 'v' && modep[1] == 'e')
+ }
+ if (len == 2 && modep[0] == 'v' && modep[1] == 'e') {
found_ve = true;
+ }
}
modep += len + 1;
}
@@ -158,7 +167,7 @@ char_u *parse_shape_opt(int what)
idx = all_idx--;
}
- /* Parse the part after the colon */
+ // Parse the part after the colon
for (p = colonp + 1; *p && *p != ','; ) {
{
/*
@@ -166,20 +175,22 @@ char_u *parse_shape_opt(int what)
*/
i = *p;
len = 0;
- if (STRNICMP(p, "ver", 3) == 0)
+ if (STRNICMP(p, "ver", 3) == 0) {
len = 3;
- else if (STRNICMP(p, "hor", 3) == 0)
+ } else if (STRNICMP(p, "hor", 3) == 0) {
len = 3;
- else if (STRNICMP(p, "blinkwait", 9) == 0)
+ } else if (STRNICMP(p, "blinkwait", 9) == 0) {
len = 9;
- else if (STRNICMP(p, "blinkon", 7) == 0)
+ } else if (STRNICMP(p, "blinkon", 7) == 0) {
len = 7;
- else if (STRNICMP(p, "blinkoff", 8) == 0)
+ } else if (STRNICMP(p, "blinkoff", 8) == 0) {
len = 8;
+ }
if (len != 0) {
p += len;
- if (!ascii_isdigit(*p))
+ if (!ascii_isdigit(*p)) {
return (char_u *)N_("E548: digit expected");
+ }
int n = getdigits_int(&p, false, 0);
if (len == 3) { // "ver" or "hor"
if (n == 0) {
@@ -194,44 +205,49 @@ char_u *parse_shape_opt(int what)
shape_table[idx].percentage = n;
}
} else if (round == 2) {
- if (len == 9)
+ if (len == 9) {
shape_table[idx].blinkwait = n;
- else if (len == 7)
+ } else if (len == 7) {
shape_table[idx].blinkon = n;
- else
+ } else {
shape_table[idx].blinkoff = n;
+ }
}
} else if (STRNICMP(p, "block", 5) == 0) {
- if (round == 2)
+ if (round == 2) {
shape_table[idx].shape = SHAPE_BLOCK;
+ }
p += 5;
- } else { /* must be a highlight group name then */
+ } else { // must be a highlight group name then
endp = vim_strchr(p, '-');
- if (commap == NULL) { /* last part */
- if (endp == NULL)
- endp = p + STRLEN(p); /* find end of part */
+ if (commap == NULL) { // last part
+ if (endp == NULL) {
+ endp = p + STRLEN(p); // find end of part
+ }
} else if (endp > commap || endp == NULL) {
endp = commap;
}
slashp = vim_strchr(p, '/');
if (slashp != NULL && slashp < endp) {
- /* "group/langmap_group" */
+ // "group/langmap_group"
i = syn_check_group(p, (int)(slashp - p));
p = slashp + 1;
}
if (round == 2) {
shape_table[idx].id = syn_check_group(p,
- (int)(endp - p));
+ (int)(endp - p));
shape_table[idx].id_lm = shape_table[idx].id;
- if (slashp != NULL && slashp < endp)
+ if (slashp != NULL && slashp < endp) {
shape_table[idx].id = i;
+ }
}
p = endp;
}
- } /* if (what != SHAPE_MOUSE) */
+ } // if (what != SHAPE_MOUSE)
- if (*p == '-')
+ if (*p == '-') {
++p;
+ }
}
}
modep = p;
@@ -241,7 +257,7 @@ char_u *parse_shape_opt(int what)
}
}
- /* If the 's' flag is not given, use the 'v' cursor for 's' */
+ // If the 's' flag is not given, use the 'v' cursor for 's'
if (!found_ve) {
{
shape_table[SHAPE_IDX_VE].shape = shape_table[SHAPE_IDX_V].shape;
diff --git a/src/nvim/debugger.c b/src/nvim/debugger.c
new file mode 100644
index 0000000000..0ddf163176
--- /dev/null
+++ b/src/nvim/debugger.c
@@ -0,0 +1,837 @@
+// 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
+
+/// @file debugger.c
+///
+/// Vim script debugger functions
+
+#include "nvim/ascii.h"
+#include "nvim/charset.h"
+#include "nvim/debugger.h"
+#include "nvim/eval.h"
+#include "nvim/ex_docmd.h"
+#include "nvim/ex_getln.h"
+#include "nvim/fileio.h"
+#include "nvim/getchar.h"
+#include "nvim/globals.h"
+#include "nvim/os/os.h"
+#include "nvim/pos.h"
+#include "nvim/regexp.h"
+#include "nvim/screen.h"
+#include "nvim/types.h"
+#include "nvim/vim.h"
+
+/// batch mode debugging: don't save and restore typeahead.
+static bool debug_greedy = false;
+
+static char *debug_oldval = NULL; // old and newval for debug expressions
+static char *debug_newval = NULL;
+
+/// The list of breakpoints: dbg_breakp.
+/// This is a grow-array of structs.
+struct debuggy {
+ int dbg_nr; ///< breakpoint number
+ int dbg_type; ///< DBG_FUNC or DBG_FILE or DBG_EXPR
+ char_u *dbg_name; ///< function, expression or file name
+ regprog_T *dbg_prog; ///< regexp program
+ linenr_T dbg_lnum; ///< line number in function or file
+ int dbg_forceit; ///< ! used
+ typval_T *dbg_val; ///< last result of watchexpression
+ int dbg_level; ///< stored nested level for expr
+};
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "debugger.c.generated.h"
+#endif
+
+/// Debug mode. Repeatedly get Ex commands, until told to continue normal
+/// execution.
+void do_debug(char_u *cmd)
+{
+ int save_msg_scroll = msg_scroll;
+ int save_State = State;
+ int save_did_emsg = did_emsg;
+ const bool save_cmd_silent = cmd_silent;
+ int save_msg_silent = msg_silent;
+ int save_emsg_silent = emsg_silent;
+ bool save_redir_off = redir_off;
+ tasave_T typeaheadbuf;
+ bool typeahead_saved = false;
+ int save_ignore_script = 0;
+ int save_ex_normal_busy;
+ int n;
+ char_u *cmdline = NULL;
+ char_u *p;
+ char *tail = NULL;
+ static int last_cmd = 0;
+#define CMD_CONT 1
+#define CMD_NEXT 2
+#define CMD_STEP 3
+#define CMD_FINISH 4
+#define CMD_QUIT 5
+#define CMD_INTERRUPT 6
+#define CMD_BACKTRACE 7
+#define CMD_FRAME 8
+#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
+ cmd_silent = false; // display commands
+ msg_silent = false; // display messages
+ emsg_silent = false; // display error messages
+ redir_off = true; // don't redirect debug commands
+
+ State = NORMAL;
+ debug_mode = true;
+
+ if (!debug_did_msg) {
+ MSG(_("Entering Debug mode. Type \"cont\" to continue."));
+ }
+ if (debug_oldval != NULL) {
+ smsg(_("Oldval = \"%s\""), debug_oldval);
+ xfree(debug_oldval);
+ debug_oldval = NULL;
+ }
+ if (debug_newval != NULL) {
+ smsg(_("Newval = \"%s\""), debug_newval);
+ xfree(debug_newval);
+ debug_newval = NULL;
+ }
+ if (sourcing_name != NULL) {
+ msg(sourcing_name);
+ }
+ if (sourcing_lnum != 0) {
+ smsg(_("line %" PRId64 ": %s"), (int64_t)sourcing_lnum, cmd);
+ } else {
+ smsg(_("cmd: %s"), cmd);
+ }
+ // Repeat getting a command and executing it.
+ for (;; ) {
+ msg_scroll = true;
+ need_wait_return = false;
+ // Save the current typeahead buffer and replace it with an empty one.
+ // This makes sure we get input from the user here and don't interfere
+ // with the commands being executed. Reset "ex_normal_busy" to avoid
+ // the side effects of using ":normal". Save the stuff buffer and make
+ // it empty. Set ignore_script to avoid reading from script input.
+ save_ex_normal_busy = ex_normal_busy;
+ ex_normal_busy = 0;
+ if (!debug_greedy) {
+ save_typeahead(&typeaheadbuf);
+ typeahead_saved = true;
+ save_ignore_script = ignore_script;
+ ignore_script = true;
+ }
+
+ xfree(cmdline);
+ cmdline = (char_u *)getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL,
+ CALLBACK_NONE);
+
+ if (typeahead_saved) {
+ restore_typeahead(&typeaheadbuf);
+ ignore_script = save_ignore_script;
+ }
+ ex_normal_busy = save_ex_normal_busy;
+
+ cmdline_row = msg_row;
+ msg_starthere();
+ if (cmdline != NULL) {
+ // If this is a debug command, set "last_cmd".
+ // If not, reset "last_cmd".
+ // For a blank line use previous command.
+ p = skipwhite(cmdline);
+ if (*p != NUL) {
+ switch (*p) {
+ case 'c':
+ last_cmd = CMD_CONT;
+ tail = "ont";
+ break;
+ case 'n':
+ last_cmd = CMD_NEXT;
+ tail = "ext";
+ break;
+ case 's':
+ last_cmd = CMD_STEP;
+ tail = "tep";
+ break;
+ case 'f':
+ last_cmd = 0;
+ if (p[1] == 'r') {
+ last_cmd = CMD_FRAME;
+ tail = "rame";
+ } else {
+ last_cmd = CMD_FINISH;
+ tail = "inish";
+ }
+ break;
+ case 'q':
+ last_cmd = CMD_QUIT;
+ tail = "uit";
+ break;
+ case 'i':
+ last_cmd = CMD_INTERRUPT;
+ tail = "nterrupt";
+ break;
+ case 'b':
+ last_cmd = CMD_BACKTRACE;
+ if (p[1] == 't') {
+ tail = "t";
+ } else {
+ tail = "acktrace";
+ }
+ break;
+ case 'w':
+ last_cmd = CMD_BACKTRACE;
+ tail = "here";
+ break;
+ case 'u':
+ last_cmd = CMD_UP;
+ tail = "p";
+ break;
+ case 'd':
+ last_cmd = CMD_DOWN;
+ tail = "own";
+ break;
+ default:
+ last_cmd = 0;
+ }
+ if (last_cmd != 0) {
+ // Check that the tail matches.
+ p++;
+ while (*p != NUL && *p == *tail) {
+ p++;
+ tail++;
+ }
+ if (ASCII_ISALPHA(*p) && last_cmd != CMD_FRAME) {
+ last_cmd = 0;
+ }
+ }
+ }
+
+ if (last_cmd != 0) {
+ // Execute debug command: decided where to break next and return.
+ switch (last_cmd) {
+ case CMD_CONT:
+ debug_break_level = -1;
+ break;
+ case CMD_NEXT:
+ debug_break_level = ex_nesting_level;
+ break;
+ case CMD_STEP:
+ debug_break_level = 9999;
+ break;
+ case CMD_FINISH:
+ debug_break_level = ex_nesting_level - 1;
+ break;
+ case CMD_QUIT:
+ got_int = true;
+ debug_break_level = -1;
+ break;
+ case CMD_INTERRUPT:
+ got_int = true;
+ debug_break_level = 9999;
+ // Do not repeat ">interrupt" cmd, continue stepping.
+ last_cmd = CMD_STEP;
+ break;
+ case CMD_BACKTRACE:
+ do_showbacktrace(cmd);
+ continue;
+ case CMD_FRAME:
+ if (*p == NUL) {
+ do_showbacktrace(cmd);
+ } else {
+ p = skipwhite(p);
+ do_setdebugtracelevel(p);
+ }
+ continue;
+ case CMD_UP:
+ debug_backtrace_level++;
+ do_checkbacktracelevel();
+ continue;
+ case CMD_DOWN:
+ debug_backtrace_level--;
+ do_checkbacktracelevel();
+ continue;
+ }
+ // Going out reset backtrace_level
+ debug_backtrace_level = 0;
+ break;
+ }
+
+ // don't debug this command
+ n = debug_break_level;
+ debug_break_level = -1;
+ (void)do_cmdline(cmdline, getexline, NULL,
+ DOCMD_VERBOSE|DOCMD_EXCRESET);
+ debug_break_level = n;
+ }
+ lines_left = (int)(Rows - 1);
+ }
+ xfree(cmdline);
+
+ RedrawingDisabled--;
+ no_wait_return--;
+ redraw_all_later(NOT_VALID);
+ need_wait_return = false;
+ msg_scroll = save_msg_scroll;
+ lines_left = (int)(Rows - 1);
+ State = save_State;
+ debug_mode = false;
+ did_emsg = save_did_emsg;
+ cmd_silent = save_cmd_silent;
+ msg_silent = save_msg_silent;
+ emsg_silent = save_emsg_silent;
+ redir_off = save_redir_off;
+
+ // Only print the message again when typing a command before coming back here.
+ debug_did_msg = true;
+}
+
+static int get_maxbacktrace_level(void)
+{
+ int maxbacktrace = 0;
+
+ if (sourcing_name != NULL) {
+ char *p = (char *)sourcing_name;
+ char *q;
+ while ((q = strstr(p, "..")) != NULL) {
+ p = q + 2;
+ maxbacktrace++;
+ }
+ }
+ return maxbacktrace;
+}
+
+static void do_setdebugtracelevel(char_u *arg)
+{
+ int level = atoi((char *)arg);
+ if (*arg == '+' || level < 0) {
+ debug_backtrace_level += level;
+ } else {
+ debug_backtrace_level = level;
+ }
+
+ do_checkbacktracelevel();
+}
+
+static void do_checkbacktracelevel(void)
+{
+ if (debug_backtrace_level < 0) {
+ debug_backtrace_level = 0;
+ MSG(_("frame is zero"));
+ } else {
+ int max = get_maxbacktrace_level();
+ if (debug_backtrace_level > max) {
+ debug_backtrace_level = max;
+ smsg(_("frame at highest level: %d"), max);
+ }
+ }
+}
+
+static void do_showbacktrace(char_u *cmd)
+{
+ if (sourcing_name != NULL) {
+ int i = 0;
+ int max = get_maxbacktrace_level();
+ char *cur = (char *)sourcing_name;
+ while (!got_int) {
+ char *next = strstr(cur, "..");
+ if (next != NULL) {
+ *next = NUL;
+ }
+ if (i == max - debug_backtrace_level) {
+ smsg("->%d %s", max - i, cur);
+ } else {
+ smsg(" %d %s", max - i, cur);
+ }
+ i++;
+ if (next == NULL) {
+ break;
+ }
+ *next = '.';
+ cur = next + 2;
+ }
+ }
+ if (sourcing_lnum != 0) {
+ smsg(_("line %" PRId64 ": %s"), (int64_t)sourcing_lnum, cmd);
+ } else {
+ smsg(_("cmd: %s"), cmd);
+ }
+}
+
+/// ":debug".
+void ex_debug(exarg_T *eap)
+{
+ int debug_break_level_save = debug_break_level;
+
+ debug_break_level = 9999;
+ do_cmdline_cmd((char *)eap->arg);
+ debug_break_level = debug_break_level_save;
+}
+
+static char_u *debug_breakpoint_name = NULL;
+static linenr_T debug_breakpoint_lnum;
+
+/// When debugging or a breakpoint is set on a skipped command, no debug prompt
+/// is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
+/// debug_skipped_name is then set to the source name in the breakpoint case. If
+/// a skipped command decides itself that a debug prompt should be displayed, it
+/// can do so by calling dbg_check_skipped().
+static int debug_skipped;
+static char_u *debug_skipped_name;
+
+/// Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
+/// at or below the break level. But only when the line is actually
+/// executed. Return true and set breakpoint_name for skipped commands that
+/// decide to execute something themselves.
+/// Called from do_one_cmd() before executing a command.
+void dbg_check_breakpoint(exarg_T *eap)
+{
+ char_u *p;
+
+ debug_skipped = false;
+ if (debug_breakpoint_name != NULL) {
+ if (!eap->skip) {
+ // replace K_SNR with "<SNR>"
+ if (debug_breakpoint_name[0] == K_SPECIAL
+ && debug_breakpoint_name[1] == KS_EXTRA
+ && debug_breakpoint_name[2] == (int)KE_SNR) {
+ p = (char_u *)"<SNR>";
+ } else {
+ p = (char_u *)"";
+ }
+ smsg(_("Breakpoint in \"%s%s\" line %" PRId64),
+ p,
+ debug_breakpoint_name + (*p == NUL ? 0 : 3),
+ (int64_t)debug_breakpoint_lnum);
+ debug_breakpoint_name = NULL;
+ do_debug(eap->cmd);
+ } else {
+ debug_skipped = true;
+ debug_skipped_name = debug_breakpoint_name;
+ debug_breakpoint_name = NULL;
+ }
+ } else if (ex_nesting_level <= debug_break_level) {
+ if (!eap->skip) {
+ do_debug(eap->cmd);
+ } else {
+ debug_skipped = true;
+ debug_skipped_name = NULL;
+ }
+ }
+}
+
+/// Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
+/// set.
+///
+/// @return true when the debug mode is entered this time.
+bool dbg_check_skipped(exarg_T *eap)
+{
+ int prev_got_int;
+
+ if (debug_skipped) {
+ // Save the value of got_int and reset it. We don't want a previous
+ // interruption cause flushing the input buffer.
+ prev_got_int = got_int;
+ got_int = false;
+ debug_breakpoint_name = debug_skipped_name;
+ // eap->skip is true
+ eap->skip = false;
+ dbg_check_breakpoint(eap);
+ eap->skip = true;
+ got_int |= prev_got_int;
+ return true;
+ }
+ return false;
+}
+
+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])
+static int last_breakp = 0; // nr of last defined breakpoint
+
+// Profiling uses file and func names similar to breakpoints.
+static garray_T prof_ga = { 0, 0, sizeof(struct debuggy), 4, NULL };
+#define DBG_FUNC 1
+#define DBG_FILE 2
+#define DBG_EXPR 3
+
+/// Evaluate the "bp->dbg_name" expression and return the result.
+/// Disables error messages.
+static typval_T *eval_expr_no_emsg(struct debuggy *const bp)
+ FUNC_ATTR_NONNULL_ALL
+{
+ // Disable error messages, a bad expression would make Vim unusable.
+ emsg_off++;
+ typval_T *const tv = eval_expr(bp->dbg_name);
+ emsg_off--;
+ return tv;
+}
+
+/// Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
+/// in the entry just after the last one in dbg_breakp. Note that "dbg_name"
+/// is allocated.
+/// Returns FAIL for failure.
+///
+/// @param arg
+/// @param gap either &dbg_breakp or &prof_ga
+static int dbg_parsearg(char_u *arg, garray_T *gap)
+{
+ char_u *p = arg;
+ char_u *q;
+ struct debuggy *bp;
+ bool here = false;
+
+ ga_grow(gap, 1);
+
+ bp = &DEBUGGY(gap, gap->ga_len);
+
+ // Find "func" or "file".
+ if (STRNCMP(p, "func", 4) == 0) {
+ bp->dbg_type = DBG_FUNC;
+ } else if (STRNCMP(p, "file", 4) == 0) {
+ bp->dbg_type = DBG_FILE;
+ } else if (gap != &prof_ga && STRNCMP(p, "here", 4) == 0) {
+ if (curbuf->b_ffname == NULL) {
+ EMSG(_(e_noname));
+ return FAIL;
+ }
+ bp->dbg_type = DBG_FILE;
+ here = true;
+ } else if (gap != &prof_ga && STRNCMP(p, "expr", 4) == 0) {
+ bp->dbg_type = DBG_EXPR;
+ } else {
+ EMSG2(_(e_invarg2), p);
+ return FAIL;
+ }
+ p = skipwhite(p + 4);
+
+ // Find optional line number.
+ if (here) {
+ bp->dbg_lnum = curwin->w_cursor.lnum;
+ } else if (gap != &prof_ga && ascii_isdigit(*p)) {
+ bp->dbg_lnum = getdigits_long(&p, true, 0);
+ p = skipwhite(p);
+ } else {
+ bp->dbg_lnum = 0;
+ }
+
+ // Find the function or file name. Don't accept a function name with ().
+ if ((!here && *p == NUL)
+ || (here && *p != NUL)
+ || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL)) {
+ EMSG2(_(e_invarg2), arg);
+ return FAIL;
+ }
+
+ if (bp->dbg_type == DBG_FUNC) {
+ bp->dbg_name = vim_strsave(p);
+ } else if (here) {
+ bp->dbg_name = vim_strsave(curbuf->b_ffname);
+ } else if (bp->dbg_type == DBG_EXPR) {
+ bp->dbg_name = vim_strsave(p);
+ bp->dbg_val = eval_expr_no_emsg(bp);
+ } else {
+ // Expand the file name in the same way as do_source(). This means
+ // doing it twice, so that $DIR/file gets expanded when $DIR is
+ // "~/dir".
+ q = expand_env_save(p);
+ if (q == NULL) {
+ return FAIL;
+ }
+ p = expand_env_save(q);
+ xfree(q);
+ if (p == NULL) {
+ return FAIL;
+ }
+ if (*p != '*') {
+ bp->dbg_name = (char_u *)fix_fname((char *)p);
+ xfree(p);
+ } else {
+ bp->dbg_name = p;
+ }
+ }
+
+ if (bp->dbg_name == NULL) {
+ return FAIL;
+ }
+ return OK;
+}
+
+/// ":breakadd". Also used for ":profile".
+void ex_breakadd(exarg_T *eap)
+{
+ struct debuggy *bp;
+ garray_T *gap;
+
+ gap = &dbg_breakp;
+ if (eap->cmdidx == CMD_profile) {
+ gap = &prof_ga;
+ }
+
+ if (dbg_parsearg(eap->arg, gap) == OK) {
+ bp = &DEBUGGY(gap, gap->ga_len);
+ bp->dbg_forceit = eap->forceit;
+
+ if (bp->dbg_type != DBG_EXPR) {
+ char_u *pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, false);
+ if (pat != NULL) {
+ bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
+ xfree(pat);
+ }
+ if (pat == NULL || bp->dbg_prog == NULL) {
+ xfree(bp->dbg_name);
+ } else {
+ if (bp->dbg_lnum == 0) { // default line number is 1
+ bp->dbg_lnum = 1;
+ }
+ if (eap->cmdidx != CMD_profile) {
+ DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
+ debug_tick++;
+ }
+ gap->ga_len++;
+ }
+ } else {
+ // DBG_EXPR
+ DEBUGGY(gap, gap->ga_len++).dbg_nr = ++last_breakp;
+ debug_tick++;
+ }
+ }
+}
+
+/// ":debuggreedy".
+void ex_debuggreedy(exarg_T *eap)
+{
+ if (eap->addr_count == 0 || eap->line2 != 0) {
+ debug_greedy = true;
+ } else {
+ debug_greedy = false;
+ }
+}
+
+/// ":breakdel" and ":profdel".
+void ex_breakdel(exarg_T *eap)
+{
+ struct debuggy *bp, *bpi;
+ int nr;
+ int todel = -1;
+ bool del_all = false;
+ linenr_T best_lnum = 0;
+ garray_T *gap;
+
+ gap = &dbg_breakp;
+ if (eap->cmdidx == CMD_profdel) {
+ gap = &prof_ga;
+ }
+
+ if (ascii_isdigit(*eap->arg)) {
+ // ":breakdel {nr}"
+ nr = atoi((char *)eap->arg);
+ for (int i = 0; i < gap->ga_len; i++) {
+ if (DEBUGGY(gap, i).dbg_nr == nr) {
+ todel = i;
+ break;
+ }
+ }
+ } else if (*eap->arg == '*') {
+ todel = 0;
+ del_all = true;
+ } else {
+ // ":breakdel {func|file|expr} [lnum] {name}"
+ if (dbg_parsearg(eap->arg, gap) == FAIL) {
+ return;
+ }
+ bp = &DEBUGGY(gap, gap->ga_len);
+ for (int i = 0; i < gap->ga_len; i++) {
+ bpi = &DEBUGGY(gap, i);
+ if (bp->dbg_type == bpi->dbg_type
+ && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
+ && (bp->dbg_lnum == bpi->dbg_lnum
+ || (bp->dbg_lnum == 0
+ && (best_lnum == 0
+ || bpi->dbg_lnum < best_lnum)))) {
+ todel = i;
+ best_lnum = bpi->dbg_lnum;
+ }
+ }
+ xfree(bp->dbg_name);
+ }
+
+ if (todel < 0) {
+ EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
+ } else {
+ while (!GA_EMPTY(gap)) {
+ xfree(DEBUGGY(gap, todel).dbg_name);
+ if (DEBUGGY(gap, todel).dbg_type == DBG_EXPR
+ && DEBUGGY(gap, todel).dbg_val != NULL) {
+ tv_free(DEBUGGY(gap, todel).dbg_val);
+ }
+ vim_regfree(DEBUGGY(gap, todel).dbg_prog);
+ gap->ga_len--;
+ if (todel < gap->ga_len) {
+ memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
+ (size_t)(gap->ga_len - todel) * sizeof(struct debuggy));
+ }
+ if (eap->cmdidx == CMD_breakdel) {
+ debug_tick++;
+ }
+ if (!del_all) {
+ break;
+ }
+ }
+
+ // If all breakpoints were removed clear the array.
+ if (GA_EMPTY(gap)) {
+ ga_clear(gap);
+ }
+ }
+}
+
+/// ":breaklist".
+void ex_breaklist(exarg_T *eap)
+{
+ struct debuggy *bp;
+
+ if (GA_EMPTY(&dbg_breakp)) {
+ MSG(_("No breakpoints defined"));
+ } else {
+ for (int i = 0; i < dbg_breakp.ga_len; i++) {
+ bp = &BREAKP(i);
+ if (bp->dbg_type == DBG_FILE) {
+ home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, true);
+ }
+ if (bp->dbg_type != DBG_EXPR) {
+ smsg(_("%3d %s %s line %" PRId64),
+ bp->dbg_nr,
+ bp->dbg_type == DBG_FUNC ? "func" : "file",
+ bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff,
+ (int64_t)bp->dbg_lnum);
+ } else {
+ smsg(_("%3d expr %s"), bp->dbg_nr, bp->dbg_name);
+ }
+ }
+ }
+}
+
+/// Find a breakpoint for a function or sourced file.
+/// Returns line number at which to break; zero when no matching breakpoint.
+///
+/// @param file true for a file, false for a function
+/// @param fname file or function name
+/// @param after after this line number
+linenr_T dbg_find_breakpoint(bool file, char_u *fname, linenr_T after)
+{
+ return debuggy_find(file, fname, after, &dbg_breakp, NULL);
+}
+
+/// @param file true for a file, false for a function
+/// @param fname file or function name
+/// @param fp[out] forceit
+///
+/// @returns true if profiling is on for a function or sourced file.
+bool has_profiling(bool file, char_u *fname, bool *fp)
+{
+ return debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
+ != (linenr_T)0;
+}
+
+/// Common code for dbg_find_breakpoint() and has_profiling().
+///
+/// @param file true for a file, false for a function
+/// @param fname file or function name
+/// @param after after this line number
+/// @param gap either &dbg_breakp or &prof_ga
+/// @param fp if not NULL: return forceit
+static linenr_T debuggy_find(bool file, char_u *fname, linenr_T after, garray_T *gap, bool *fp)
+{
+ struct debuggy *bp;
+ linenr_T lnum = 0;
+ char_u *name = fname;
+ int prev_got_int;
+
+ // Return quickly when there are no breakpoints.
+ if (GA_EMPTY(gap)) {
+ return (linenr_T)0;
+ }
+
+ // Replace K_SNR in function name with "<SNR>".
+ if (!file && fname[0] == K_SPECIAL) {
+ name = xmalloc(STRLEN(fname) + 3);
+ STRCPY(name, "<SNR>");
+ STRCPY(name + 5, fname + 3);
+ }
+
+ for (int i = 0; i < gap->ga_len; i++) {
+ // Skip entries that are not useful or are for a line that is beyond
+ // an already found breakpoint.
+ bp = &DEBUGGY(gap, i);
+ if ((bp->dbg_type == DBG_FILE) == file
+ && bp->dbg_type != DBG_EXPR
+ && (gap == &prof_ga
+ || (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))) {
+ // Save the value of got_int and reset it. We don't want a
+ // previous interruption cancel matching, only hitting CTRL-C
+ // while matching should abort it.
+ prev_got_int = got_int;
+ got_int = false;
+ if (vim_regexec_prog(&bp->dbg_prog, false, name, (colnr_T)0)) {
+ lnum = bp->dbg_lnum;
+ if (fp != NULL) {
+ *fp = bp->dbg_forceit;
+ }
+ }
+ got_int |= prev_got_int;
+ } else if (bp->dbg_type == DBG_EXPR) {
+ bool line = false;
+
+ typval_T *const tv = eval_expr_no_emsg(bp);
+ if (tv != NULL) {
+ if (bp->dbg_val == NULL) {
+ debug_oldval = typval_tostring(NULL);
+ bp->dbg_val = tv;
+ debug_newval = typval_tostring(bp->dbg_val);
+ line = true;
+ } else {
+ if (typval_compare(tv, bp->dbg_val, EXPR_IS, false) == OK
+ && tv->vval.v_number == false) {
+ line = true;
+ debug_oldval = typval_tostring(bp->dbg_val);
+ // Need to evaluate again, typval_compare() overwrites "tv".
+ typval_T *const v = eval_expr_no_emsg(bp);
+ debug_newval = typval_tostring(v);
+ tv_free(bp->dbg_val);
+ bp->dbg_val = v;
+ }
+ tv_free(tv);
+ }
+ } else if (bp->dbg_val != NULL) {
+ debug_oldval = typval_tostring(bp->dbg_val);
+ debug_newval = typval_tostring(NULL);
+ tv_free(bp->dbg_val);
+ bp->dbg_val = NULL;
+ line = true;
+ }
+
+ if (line) {
+ lnum = after > 0 ? after : 1;
+ break;
+ }
+ }
+ }
+ if (name != fname) {
+ xfree(name);
+ }
+
+ return lnum;
+}
+
+/// Called when a breakpoint was encountered.
+void dbg_breakpoint(char_u *name, linenr_T lnum)
+{
+ // We need to check if this line is actually executed in do_one_cmd()
+ debug_breakpoint_name = name;
+ debug_breakpoint_lnum = lnum;
+}
diff --git a/src/nvim/debugger.h b/src/nvim/debugger.h
new file mode 100644
index 0000000000..1f1139b3bc
--- /dev/null
+++ b/src/nvim/debugger.h
@@ -0,0 +1,11 @@
+#ifndef NVIM_DEBUGGER_H
+#define NVIM_DEBUGGER_H
+
+#include <stdbool.h>
+
+#include "nvim/ex_cmds_defs.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "debugger.h.generated.h"
+#endif
+#endif // NVIM_DEBUGGER_H
diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c
index f3000f4430..561be9968a 100644
--- a/src/nvim/decoration.c
+++ b/src/nvim/decoration.c
@@ -1,24 +1,19 @@
// 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/vim.h"
-#include "nvim/lua/executor.h"
-#include "nvim/extmark.h"
#include "nvim/decoration.h"
+#include "nvim/extmark.h"
+#include "nvim/highlight.h"
+#include "nvim/lua/executor.h"
#include "nvim/screen.h"
#include "nvim/syntax.h"
-#include "nvim/highlight.h"
+#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "decoration.c.generated.h"
#endif
-static PMap(uint64_t) *hl_decors;
-
-void decor_init(void)
-{
- hl_decors = pmap_new(uint64_t)();
-}
+static PMap(uint64_t) hl_decors;
/// Add highlighting to a buffer, bounded by two cursor positions,
/// with an offset.
@@ -30,14 +25,10 @@ void decor_init(void)
/// @param src_id src_id to use or 0 to use a new src_id group,
/// or -1 for ungrouped highlight.
/// @param hl_id Highlight group id
-/// @param pos_start Cursor position to start the hightlighting at
+/// @param pos_start Cursor position to start the highlighting at
/// @param pos_end Cursor position to end the highlighting at
/// @param offset Move the whole highlighting this many columns to the right
-void bufhl_add_hl_pos_offset(buf_T *buf,
- int src_id,
- int hl_id,
- lpos_T pos_start,
- lpos_T pos_end,
+void bufhl_add_hl_pos_offset(buf_T *buf, int src_id, int hl_id, lpos_T pos_start, lpos_T pos_end,
colnr_T offset)
{
colnr_T hl_start = 0;
@@ -46,7 +37,7 @@ void bufhl_add_hl_pos_offset(buf_T *buf,
decor->priority = DECOR_PRIORITY_BASE;
// TODO(bfredl): if decoration had blocky mode, we could avoid this loop
- for (linenr_T lnum = pos_start.lnum; lnum <= pos_end.lnum; lnum ++) {
+ for (linenr_T lnum = pos_start.lnum; lnum <= pos_end.lnum; lnum++) {
int end_off = 0;
if (pos_start.lnum < lnum && lnum < pos_end.lnum) {
// TODO(bfredl): This is quite ad-hoc, but the space between |num| and
@@ -68,7 +59,7 @@ void bufhl_add_hl_pos_offset(buf_T *buf,
hl_start = pos_start.col + offset;
hl_end = pos_end.col + offset;
}
- (void)extmark_set(buf, (uint64_t)src_id, 0,
+ (void)extmark_set(buf, (uint64_t)src_id, NULL,
(int)lnum-1, hl_start, (int)lnum-1+end_off, hl_end,
decor, true, false, kExtmarkNoUndo);
}
@@ -77,7 +68,7 @@ void bufhl_add_hl_pos_offset(buf_T *buf,
Decoration *decor_hl(int hl_id)
{
assert(hl_id > 0);
- Decoration **dp = (Decoration **)pmap_ref(uint64_t)(hl_decors,
+ Decoration **dp = (Decoration **)pmap_ref(uint64_t)(&hl_decors,
(uint64_t)hl_id, true);
if (*dp) {
return *dp;
@@ -119,7 +110,7 @@ void clear_virttext(VirtText *text)
*text = (VirtText)KV_INITIAL_VALUE;
}
-VirtText *decor_find_virttext(buf_T *buf, int row, uint64_t ns_id)
+Decoration *decor_find_virttext(buf_T *buf, int row, uint64_t ns_id)
{
MarkTreeIter itr[1] = { 0 };
marktree_itr_get(buf->b_marktree, row, 0, itr);
@@ -132,7 +123,7 @@ VirtText *decor_find_virttext(buf_T *buf, int row, uint64_t ns_id)
mark.id, false);
if (item && (ns_id == 0 || ns_id == item->ns_id)
&& item->decor && kv_size(item->decor->virt_text)) {
- return &item->decor->virt_text;
+ return item->decor;
}
marktree_itr_next(buf->b_marktree, itr);
}
@@ -150,7 +141,7 @@ bool decor_redraw_reset(buf_T *buf, DecorState *state)
}
}
kv_size(state->active) = 0;
- return buf->b_extmark_index;
+ return map_size(buf->b_extmark_index);
}
@@ -177,7 +168,7 @@ bool decor_redraw_start(buf_T *buf, int top_row, DecorState *state)
ExtmarkItem *item = map_ref(uint64_t, ExtmarkItem)(buf->b_extmark_index,
start_id, false);
if (!item || !item->decor) {
- // TODO(bfredl): dedicated flag for being a decoration?
+ // TODO(bfredl): dedicated flag for being a decoration?
goto next_mark;
}
Decoration *decor = item->decor;
@@ -218,21 +209,18 @@ bool decor_redraw_line(buf_T *buf, int row, DecorState *state)
}
state->row = row;
state->col_until = -1;
+ state->eol_col = -1;
return true; // TODO(bfredl): be more precise
}
-static void decor_add(DecorState *state, int start_row, int start_col,
- int end_row, int end_col, Decoration *decor, bool owned)
+static void decor_add(DecorState *state, int start_row, int start_col, int end_row, int end_col,
+ Decoration *decor, bool owned)
{
int attr_id = decor->hl_id > 0 ? syn_id2attr(decor->hl_id) : 0;
DecorRange range = { start_row, start_col, end_row, end_col,
*decor, attr_id,
- kv_size(decor->virt_text) && owned, -1 };
-
- if (decor->virt_text_pos == kVTEndOfLine) {
- range.win_col = -2; // handled separately
- }
+ kv_size(decor->virt_text) && owned, -1 };
kv_pushp(state->active);
size_t index;
@@ -246,8 +234,7 @@ static void decor_add(DecorState *state, int start_row, int start_col,
kv_A(state->active, index) = range;
}
-int decor_redraw_col(buf_T *buf, int col, int win_col, bool hidden,
- DecorState *state)
+int decor_redraw_col(buf_T *buf, int col, int win_col, bool hidden, DecorState *state)
{
if (col <= state->col_until) {
return state->current;
@@ -265,7 +252,7 @@ int decor_redraw_col(buf_T *buf, int col, int win_col, bool hidden,
}
if ((mark.id&MARKTREE_END_FLAG)) {
- // TODO(bfredl): check decoration flag
+ // TODO(bfredl): check decoration flag
goto next_mark;
}
mtpos_t endpos = marktree_lookup(buf->b_marktree,
@@ -274,7 +261,7 @@ int decor_redraw_col(buf_T *buf, int col, int win_col, bool hidden,
ExtmarkItem *item = map_ref(uint64_t, ExtmarkItem)(buf->b_extmark_index,
mark.id, false);
if (!item || !item->decor) {
- // TODO(bfredl): dedicated flag for being a decoration?
+ // TODO(bfredl): dedicated flag for being a decoration?
goto next_mark;
}
Decoration *decor = item->decor;
@@ -345,33 +332,25 @@ void decor_redraw_end(DecorState *state)
state->buf = NULL;
}
-VirtText decor_redraw_eol(buf_T *buf, DecorState *state, int *eol_attr,
- bool *aligned)
+bool decor_redraw_eol(buf_T *buf, DecorState *state, int *eol_attr, int eol_col)
{
decor_redraw_col(buf, MAXCOL, MAXCOL, false, state);
- VirtText text = VIRTTEXT_EMPTY;
+ state->eol_col = eol_col;
+ bool has_virttext = false;
for (size_t i = 0; i < kv_size(state->active); i++) {
DecorRange item = kv_A(state->active, i);
if (item.start_row == state->row && kv_size(item.decor.virt_text)) {
- if (!kv_size(text) && item.decor.virt_text_pos == kVTEndOfLine) {
- text = item.decor.virt_text;
- } else if (item.decor.virt_text_pos == kVTRightAlign
- || item.decor.virt_text_pos == kVTWinCol) {
- *aligned = true;
- }
+ has_virttext = true;
}
-
if (item.decor.hl_eol && item.start_row <= state->row) {
*eol_attr = hl_combine_attr(*eol_attr, item.attr_id);
}
}
-
- return text;
+ return has_virttext;
}
-void decor_add_ephemeral(int start_row, int start_col, int end_row, int end_col,
- Decoration *decor)
+void decor_add_ephemeral(int start_row, int start_col, int end_row, int end_col, Decoration *decor)
{
if (end_row == -1) {
end_row = start_row;
@@ -433,3 +412,35 @@ void decor_free_all_mem(void)
}
kv_destroy(decor_providers);
}
+
+
+int decor_virtual_lines(win_T *wp, linenr_T lnum)
+{
+ buf_T *buf = wp->w_buffer;
+ if (!buf->b_virt_line_mark) {
+ return 0;
+ }
+ if (buf->b_virt_line_pos < 0) {
+ mtpos_t pos = marktree_lookup(buf->b_marktree, buf->b_virt_line_mark, NULL);
+ if (pos.row < 0) {
+ buf->b_virt_line_mark = 0;
+ }
+ buf->b_virt_line_pos = pos.row + (buf->b_virt_line_above ? 0 : 1);
+ }
+
+ return (lnum-1 == buf->b_virt_line_pos) ? (int)kv_size(buf->b_virt_lines) : 0;
+}
+
+void clear_virt_lines(buf_T *buf, int row)
+{
+ if (row > -1) {
+ redraw_buf_line_later(buf, MIN(buf->b_ml.ml_line_count,
+ row+1+(buf->b_virt_line_above?0:1)));
+ }
+ for (size_t i = 0; i < kv_size(buf->b_virt_lines); i++) {
+ clear_virttext(&kv_A(buf->b_virt_lines, i));
+ }
+ kv_destroy(buf->b_virt_lines); // re-initializes
+ buf->b_virt_line_pos = -1;
+ buf->b_virt_line_mark = 0;
+}
diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h
index 4cebc0b731..35f5af87ed 100644
--- a/src/nvim/decoration.h
+++ b/src/nvim/decoration.h
@@ -7,14 +7,6 @@
// actual Decoration data is in extmark_defs.h
-typedef struct {
- char *text;
- int hl_id;
-} VirtTextChunk;
-
-typedef kvec_t(VirtTextChunk) VirtText;
-#define VIRTTEXT_EMPTY ((VirtText)KV_INITIAL_VALUE)
-
typedef uint16_t DecorPriority;
#define DECOR_PRIORITY_BASE 0x1000
@@ -34,19 +26,20 @@ typedef enum {
struct Decoration
{
- int hl_id; // highlight group
VirtText virt_text;
+ int hl_id; // highlight group
VirtTextPos virt_text_pos;
- bool virt_text_hide;
HlMode hl_mode;
+ bool virt_text_hide;
bool hl_eol;
+ bool shared; // shared decoration, don't free
// TODO(bfredl): style, signs, etc
DecorPriority priority;
- bool shared; // shared decoration, don't free
int col; // fixed col value, like win_col
+ int virt_text_width; // width of virt_text
};
-#define DECORATION_INIT { 0, KV_INITIAL_VALUE, kVTEndOfLine, false, \
- kHlModeUnknown, false, DECOR_PRIORITY_BASE, false, 0 }
+#define DECORATION_INIT { KV_INITIAL_VALUE, 0, kVTEndOfLine, kHlModeUnknown, \
+ false, false, false, DECOR_PRIORITY_BASE, 0, 0 }
typedef struct {
int start_row;
@@ -67,6 +60,8 @@ typedef struct {
int row;
int col_until;
int current;
+
+ int eol_col;
VirtText *virt_text;
} DecorState;
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index 5f8b81822b..5c43b2498e 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -13,14 +13,12 @@
#include <inttypes.h>
#include <stdbool.h>
-#include "nvim/vim.h"
-#include "xdiff/xdiff.h"
#include "nvim/ascii.h"
-#include "nvim/diff.h"
#include "nvim/buffer.h"
#include "nvim/change.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
+#include "nvim/diff.h"
#include "nvim/eval.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_docmd.h"
@@ -29,19 +27,21 @@
#include "nvim/mark.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
+#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
-#include "nvim/memory.h"
#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/option.h"
+#include "nvim/os/os.h"
+#include "nvim/os/shell.h"
#include "nvim/path.h"
#include "nvim/screen.h"
#include "nvim/strings.h"
#include "nvim/undo.h"
+#include "nvim/vim.h"
#include "nvim/window.h"
-#include "nvim/os/os.h"
-#include "nvim/os/shell.h"
+#include "xdiff/xdiff.h"
static int diff_busy = false; // using diff structs, don't change them
static bool diff_need_update = false; // ex_diffupdate needs to be called
@@ -72,22 +72,22 @@ static TriState diff_a_works = kNone;
// used for diff input
typedef struct {
- char_u *din_fname; // used for external diff
- mmfile_t din_mmfile; // used for internal diff
+ char_u *din_fname; // used for external diff
+ mmfile_t din_mmfile; // used for internal diff
} diffin_T;
// used for diff result
typedef struct {
- char_u *dout_fname; // used for external diff
- garray_T dout_ga; // used for internal diff
+ char_u *dout_fname; // used for external diff
+ garray_T dout_ga; // used for internal diff
} diffout_T;
// two diff inputs and one result
typedef struct {
- diffin_T dio_orig; // original file input
- diffin_T dio_new; // new file input
- diffout_T dio_diff; // diff result
- int dio_internal; // using internal diff
+ diffin_T dio_orig; // original file input
+ diffin_T dio_new; // new file input
+ diffout_T dio_diff; // diff result
+ int dio_internal; // using internal diff
} diffio_T;
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -119,7 +119,6 @@ void diff_buf_delete(buf_T *buf)
/// @param win
void diff_buf_adjust(win_T *win)
{
-
if (!win->w_p_diff) {
// When there is no window showing a diff for this buffer, remove
// it from the diffs.
@@ -242,8 +241,7 @@ void diff_invalidate(buf_T *buf)
/// @param line2
/// @param amount
/// @param amount_after
-void diff_mark_adjust(linenr_T line1, linenr_T line2, long amount,
- long amount_after)
+void diff_mark_adjust(linenr_T line1, linenr_T line2, long amount, long amount_after)
{
// Handle all tab pages that use the current buffer in a diff.
FOR_ALL_TABS(tp) {
@@ -267,8 +265,8 @@ void diff_mark_adjust(linenr_T line1, linenr_T line2, long amount,
/// @param line2
/// @param amount
/// @amount_after
-static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1,
- linenr_T line2, long amount, long amount_after)
+static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1, linenr_T line2, long amount,
+ long amount_after)
{
if (diff_internal()) {
// Will update diffs before redrawing. Set _invalid to update the
@@ -299,7 +297,7 @@ static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1,
diff_T *dp = tp->tp_first_diff;
linenr_T last;
- linenr_T lnum_deleted = line1; // lnum of remaining deletion
+ linenr_T lnum_deleted = line1; // lnum of remaining deletion
int n;
int off;
for (;;) {
@@ -323,8 +321,8 @@ static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1,
dnext->df_lnum[i] = line1;
} else {
dnext->df_lnum[i] = line1
- + (dprev->df_lnum[i] + dprev->df_count[i])
- - (dprev->df_lnum[idx] + dprev->df_count[idx]);
+ + (dprev->df_lnum[i] + dprev->df_count[i])
+ - (dprev->df_lnum[idx] + dprev->df_count[idx]);
}
dnext->df_count[i] = deleted;
}
@@ -509,7 +507,7 @@ static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1,
/// @param dp
///
/// @return The new diff block.
-static diff_T* diff_alloc_new(tabpage_T *tp, diff_T *dprev, diff_T *dp)
+static diff_T *diff_alloc_new(tabpage_T *tp, diff_T *dprev, diff_T *dp)
{
diff_T *dnew = xmalloc(sizeof(*dnew));
@@ -639,12 +637,18 @@ static int diff_check_sanity(tabpage_T *tp, diff_T *dp)
/// @param dofold Also recompute the folds
void diff_redraw(bool dofold)
{
+ win_T *wp_other = NULL;
+ bool used_max_fill = false;
+
need_diff_redraw = false;
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (!wp->w_p_diff) {
continue;
}
redraw_later(wp, SOME_VALID);
+ if (wp != curwin) {
+ wp_other = wp;
+ }
if (dofold && foldmethodIsDiff(wp)) {
foldUpdateAll(wp);
}
@@ -658,10 +662,18 @@ void diff_redraw(bool dofold)
wp->w_topfill = (n < 0 ? 0 : n);
} else if ((n > 0) && (n > wp->w_topfill)) {
wp->w_topfill = n;
+ if (wp == curwin) {
+ used_max_fill = true;
+ }
}
check_topfill(wp, false);
}
}
+ if (wp_other != NULL && used_max_fill && curwin->w_p_scb) {
+ // The current window was set to used the maximum number of filler
+ // lines, may need to reduce them.
+ diff_set_topline(wp_other, curwin);
+ }
}
static void clear_diffin(diffin_T *din)
@@ -690,10 +702,10 @@ static void clear_diffout(diffout_T *dout)
/// @return FAIL for failure.
static int diff_write_buffer(buf_T *buf, diffin_T *din)
{
- linenr_T lnum;
- char_u *s;
- long len = 0;
- char_u *ptr;
+ linenr_T lnum;
+ char_u *s;
+ long len = 0;
+ char_u *ptr;
// xdiff requires one big block of memory with all the text.
for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) {
@@ -720,7 +732,7 @@ static int diff_write_buffer(buf_T *buf, diffin_T *din)
for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) {
for (s = ml_get_buf(buf, lnum, false); *s != NUL; ) {
if (diff_flags & DIFF_ICASE) {
- char_u cbuf[MB_MAXBYTES + 1];
+ char_u cbuf[MB_MAXBYTES + 1];
// xdiff doesn't support ignoring case, fold-case the text.
int c = PTR2CHAR(s);
@@ -775,12 +787,10 @@ static int diff_write(buf_T *buf, diffin_T *din)
/// @param dio
/// @param idx_orig
/// @param eap can be NULL
-static void diff_try_update(diffio_T *dio,
- int idx_orig,
- exarg_T *eap)
+static void diff_try_update(diffio_T *dio, int idx_orig, exarg_T *eap)
{
buf_T *buf;
- int idx_new;
+ int idx_new;
if (dio->dio_internal) {
ga_init(&dio->dio_diff.dout_ga, sizeof(char *), 1000);
@@ -918,7 +928,7 @@ void ex_diffupdate(exarg_T *eap)
}
// Only use the internal method if it did not fail for one of the buffers.
- diffio_T diffio;
+ diffio_T diffio;
memset(&diffio, 0, sizeof(diffio));
diffio.dio_internal = diff_internal() && !diff_internal_failed();
@@ -1034,9 +1044,9 @@ static int check_external_diff(diffio_T *diffio)
///
static int diff_file_internal(diffio_T *diffio)
{
- xpparam_t param;
- xdemitconf_t emit_cfg;
- xdemitcb_t emit_cb;
+ xpparam_t param;
+ xdemitconf_t emit_cfg;
+ xdemitcb_t emit_cb;
memset(&param, 0, sizeof(param));
memset(&emit_cfg, 0, sizeof(emit_cfg));
@@ -1059,7 +1069,7 @@ static int diff_file_internal(diffio_T *diffio)
emit_cfg.ctxlen = 0; // don't need any diff_context here
emit_cb.priv = &diffio->dio_diff;
- emit_cb.outf = xdiff_out;
+ emit_cb.out_line = xdiff_out;
if (xdl_diff(&diffio->dio_orig.din_mmfile,
&diffio->dio_new.din_mmfile,
&param, &emit_cfg, &emit_cb) < 0) {
@@ -1076,9 +1086,9 @@ static int diff_file_internal(diffio_T *diffio)
/// @return OK or FAIL
static int diff_file(diffio_T *dio)
{
- char *tmp_orig = (char *)dio->dio_orig.din_fname;
- char *tmp_new = (char *)dio->dio_new.din_fname;
- char *tmp_diff = (char *)dio->dio_diff.dout_fname;
+ char *tmp_orig = (char *)dio->dio_orig.din_fname;
+ char *tmp_new = (char *)dio->dio_new.din_fname;
+ char *tmp_diff = (char *)dio->dio_diff.dout_fname;
if (*p_dex != NUL) {
// Use 'diffexpr' to generate the diff file.
eval_diff(tmp_orig, tmp_new, tmp_diff);
@@ -1109,9 +1119,9 @@ static int diff_file(diffio_T *dio)
(diff_flags & DIFF_IBLANK) ? "-B " : "",
(diff_flags & DIFF_ICASE) ? "-i " : "",
tmp_orig, tmp_new);
- append_redir(cmd, len, (char *) p_srr, tmp_diff);
+ append_redir(cmd, len, (char *)p_srr, tmp_diff);
block_autocmds(); // Avoid ShellCmdPost stuff
- (void)call_shell((char_u *) cmd,
+ (void)call_shell((char_u *)cmd,
kShellOptFilter | kShellOptSilent | kShellOptDoOut,
NULL);
unblock_autocmds();
@@ -1157,8 +1167,8 @@ void ex_diffpatch(exarg_T *eap)
#ifdef UNIX
// Get the absolute path of the patchfile, changing directory below.
fullname = FullName_save((char *)eap->arg, false);
- esc_name = vim_strsave_shellescape(
- (fullname != NULL ? (char_u *)fullname : eap->arg), true, true);
+ esc_name =
+ vim_strsave_shellescape((fullname != NULL ? (char_u *)fullname : eap->arg), true, true);
#else
esc_name = vim_strsave_shellescape(eap->arg, true, true);
#endif
@@ -1310,8 +1320,8 @@ void ex_diffsplit(exarg_T *eap)
if (bufref_valid(&old_curbuf)) {
// Move the cursor position to that of the old window.
- curwin->w_cursor.lnum = diff_get_corresponding_line(
- old_curbuf.br_buf, old_curwin->w_cursor.lnum);
+ curwin->w_cursor.lnum = diff_get_corresponding_line(old_curbuf.br_buf,
+ old_curwin->w_cursor.lnum);
}
}
// Now that lines are folded scroll to show the cursor at the same
@@ -1330,15 +1340,15 @@ void ex_diffthis(exarg_T *eap)
static void set_diff_option(win_T *wp, int value)
{
- win_T *old_curwin = curwin;
-
- curwin = wp;
- curbuf = curwin->w_buffer;
- curbuf_lock++;
- set_option_value("diff", (long)value, NULL, OPT_LOCAL);
- curbuf_lock--;
- curwin = old_curwin;
- curbuf = curwin->w_buffer;
+ win_T *old_curwin = curwin;
+
+ curwin = wp;
+ curbuf = curwin->w_buffer;
+ curbuf->b_ro_locked++;
+ set_option_value("diff", (long)value, NULL, OPT_LOCAL);
+ curbuf->b_ro_locked--;
+ curwin = old_curwin;
+ curbuf = curwin->w_buffer;
}
@@ -1710,8 +1720,7 @@ static void diff_read(int idx_orig, int idx_new, diffout_T *dout)
/// @param dp
/// @param idx_orig
/// @param idx_new
-static void diff_copy_entry(diff_T *dprev, diff_T *dp, int idx_orig,
- int idx_new)
+static void diff_copy_entry(diff_T *dprev, diff_T *dp, int idx_orig, int idx_new)
{
long off;
@@ -1755,7 +1764,7 @@ void diff_clear(tabpage_T *tp)
/// @return diff status.
int diff_check(win_T *wp, linenr_T lnum)
{
- int idx; // index in tp_diffbuf[] for this buffer
+ int idx; // index in tp_diffbuf[] for this buffer
diff_T *dp;
int maxcount;
int i;
@@ -1869,7 +1878,7 @@ int diff_check(win_T *wp, linenr_T lnum)
/// @param idx1 first entry in diff "dp"
/// @param idx2 second entry in diff "dp"
///
-/// @return true if two entires are equal.
+/// @return true if two entries are equal.
static bool diff_equal_entry(diff_T *dp, int idx1, int idx2)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1)
{
@@ -1898,8 +1907,7 @@ static bool diff_equal_entry(diff_T *dp, int idx1, int idx2)
// Compare the characters at "p1" and "p2". If they are equal (possibly
// ignoring case) return true and set "len" to the number of bytes.
-static bool diff_equal_char(const char_u *const p1, const char_u *const p2,
- int *const len)
+static bool diff_equal_char(const char_u *const p1, const char_u *const p2, int *const len)
{
const int l = utfc_ptr2len(p1);
@@ -1977,26 +1985,6 @@ static int diff_cmp(char_u *s1, char_u *s2)
return 0;
}
-/// Return the number of filler lines above "lnum".
-///
-/// @param wp
-/// @param lnum
-///
-/// @return Number of filler lines above lnum
-int diff_check_fill(win_T *wp, linenr_T lnum)
-{
- // be quick when there are no filler lines
- if (!(diff_flags & DIFF_FILLER)) {
- return 0;
- }
- int n = diff_check(wp, lnum);
-
- if (n <= 0) {
- return 0;
- }
- return n;
-}
-
/// Set the topline of "towin" to match the position in "fromwin", so that they
/// show the same diff'ed lines.
///
@@ -2022,6 +2010,7 @@ 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]) {
@@ -2247,6 +2236,13 @@ bool diffopt_closeoff(void)
return (diff_flags & DIFF_CLOSE_OFF) != 0;
}
+// Return true if 'diffopt' contains "filler".
+bool diffopt_filler(void)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ return (diff_flags & DIFF_FILLER) != 0;
+}
+
/// Find the difference within a changed line.
///
/// @param wp window whose current buffer to check
@@ -2523,7 +2519,7 @@ void ex_diffgetput(exarg_T *eap)
if ((curtab->tp_diffbuf[i] != curbuf)
&& (curtab->tp_diffbuf[i] != NULL)
&& ((eap->cmdidx != CMD_diffput)
- || MODIFIABLE(curtab->tp_diffbuf[i]))) {
+ || MODIFIABLE(curtab->tp_diffbuf[i]))) {
EMSG(_("E101: More than two buffers in diff mode, don't know "
"which one to use"));
return;
@@ -2603,7 +2599,7 @@ void ex_diffgetput(exarg_T *eap)
// FileChangedRO autocommand, which may do nasty things and mess
// everything up.
if (!curbuf->b_changed) {
- change_warning(0);
+ change_warning(curbuf, 0);
if (diff_buf_idx(curbuf) != idx_to) {
EMSG(_("E787: Buffer changed unexpectedly"));
goto theend;
@@ -2669,7 +2665,7 @@ void ex_diffgetput(exarg_T *eap)
}
}
- buf_empty = BUFEMPTY();
+ buf_empty = buf_is_empty(curbuf);
added = 0;
for (i = 0; i < count; ++i) {
@@ -2944,7 +2940,7 @@ static linenr_T diff_get_corresponding_line_int(buf_T *buf1, linenr_T lnum1)
return curwin->w_cursor.lnum;
}
baseline = (dp->df_lnum[idx1] + dp->df_count[idx1])
- - (dp->df_lnum[idx2] + dp->df_count[idx2]);
+ - (dp->df_lnum[idx2] + dp->df_count[idx2]);
}
// If we get here then the cursor is after the last diff
@@ -3021,15 +3017,12 @@ linenr_T diff_lnum_win(linenr_T lnum, win_T *wp)
/// Handle an ED style diff line.
/// Return FAIL if the line does not contain diff info.
///
-static int parse_diff_ed(char_u *line,
- linenr_T *lnum_orig,
- long *count_orig,
- linenr_T *lnum_new,
- long *count_new)
+static int parse_diff_ed(char_u *line, linenr_T *lnum_orig, long *count_orig, linenr_T *lnum_new,
+ long *count_new)
{
char_u *p;
- long f1, l1, f2, l2;
- int difftype;
+ long f1, l1, f2, l2;
+ int difftype;
// The line must be one of three formats:
// change: {first}[,{last}]c{first}[,{last}]
@@ -3079,14 +3072,11 @@ static int parse_diff_ed(char_u *line,
/// Parses unified diff with zero(!) context lines.
/// Return FAIL if there is no diff information in "line".
///
-static int parse_diff_unified(char_u *line,
- linenr_T *lnum_orig,
- long *count_orig,
- linenr_T *lnum_new,
- long *count_new)
+static int parse_diff_unified(char_u *line, linenr_T *lnum_orig, long *count_orig,
+ linenr_T *lnum_new, long *count_new)
{
char_u *p;
- long oldline, oldcount, newline, newcount;
+ long oldline, oldcount, newline, newcount;
// Parse unified diff hunk header:
// @@ -oldline,oldcount +newline,newcount @@
@@ -3139,7 +3129,7 @@ static int parse_diff_unified(char_u *line,
static int xdiff_out(void *priv, mmbuffer_t *mb, int nbuf)
{
diffout_T *dout = (diffout_T *)priv;
- char_u *p;
+ char_u *p;
// The header line always comes by itself, text lines in at least two
// parts. We drop the text part.
diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c
index dd32cef1e3..b0fc4ee463 100644
--- a/src/nvim/digraph.c
+++ b/src/nvim/digraph.c
@@ -6,26 +6,26 @@
/// code for digraphs
#include <assert.h>
-#include <stdbool.h>
#include <inttypes.h>
+#include <stdbool.h>
-#include "nvim/vim.h"
#include "nvim/ascii.h"
-#include "nvim/digraph.h"
#include "nvim/charset.h"
+#include "nvim/digraph.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
+#include "nvim/garray.h"
#include "nvim/getchar.h"
-#include "nvim/misc1.h"
#include "nvim/mbyte.h"
-#include "nvim/message.h"
#include "nvim/memory.h"
-#include "nvim/garray.h"
+#include "nvim/message.h"
+#include "nvim/misc1.h"
#include "nvim/normal.h"
+#include "nvim/os/input.h"
#include "nvim/screen.h"
#include "nvim/strings.h"
-#include "nvim/os/input.h"
+#include "nvim/vim.h"
typedef int result_T;
@@ -40,7 +40,7 @@ typedef struct digraph {
# include "digraph.c.generated.h"
#endif
// digraphs added by the user
-static garray_T user_digraphs = {0, 0, (int)sizeof(digr_T), 10, NULL};
+static garray_T user_digraphs = { 0, 0, (int)sizeof(digr_T), 10, NULL };
/// Note: Characters marked with XX are not included literally, because some
/// compilers cannot handle them (Amiga SAS/C is the most picky one).
@@ -49,7 +49,7 @@ static digr_T digraphdefault[] =
// digraphs for Unicode from RFC1345
// (also work for ISO-8859-1 aka latin1)
{
- { 'N', 'U', 0x0a }, // LF for NUL
+ { 'N', 'U', 0x0a }, // LF for NUL
{ 'S', 'H', 0x01 },
{ 'S', 'X', 0x02 },
{ 'E', 'X', 0x03 },
@@ -1452,12 +1452,12 @@ static digr_T digraphdefault[] =
/// @return The digraph.
int do_digraph(int c)
{
- static int backspaced; // character before K_BS
+ static int backspaced; // character before K_BS
static int lastchar; // last typed character
if (c == -1) { // init values
backspaced = -1;
- } else if (p_dg) {
+ } else if (p_dg) {
if (backspaced >= 0) {
c = getdigraph(backspaced, c, false);
}
@@ -1502,10 +1502,10 @@ char_u *get_digraph_for_char(int val_arg)
/// Get a digraph. Used after typing CTRL-K on the command line or in normal
/// mode.
///
-/// @param cmdline TRUE when called from the cmdline
+/// @param cmdline true when called from the cmdline
///
/// @returns composed character, or NUL when ESC was used.
-int get_digraph(int cmdline)
+int get_digraph(bool cmdline)
{
int cc;
no_mapping++;
@@ -1557,7 +1557,7 @@ static int getexactdigraph(int char1, int char2, bool meta_char)
// Search user digraphs first.
digr_T *dp = (digr_T *)user_digraphs.ga_data;
for (int i = 0; i < user_digraphs.ga_len; ++i) {
- if (((int) dp->char1 == char1) && ((int) dp->char2 == char2)) {
+ if (((int)dp->char1 == char1) && ((int)dp->char2 == char2)) {
retval = dp->result;
break;
}
@@ -1569,7 +1569,7 @@ static int getexactdigraph(int char1, int char2, bool meta_char)
dp = digraphdefault;
for (int i = 0; dp->char1 != 0; ++i) {
- if (((int) dp->char1 == char1) && ((int) dp->char2 == char2)) {
+ if (((int)dp->char1 == char1) && ((int)dp->char2 == char2)) {
retval = dp->result;
break;
}
@@ -1821,7 +1821,7 @@ typedef struct {
/// @return NULL if OK, an error message for failure. This only needs to be
/// used when setting the option, not later when the value has already
/// been checked.
-char_u* keymap_init(void)
+char_u *keymap_init(void)
{
curbuf->b_kmap_state &= ~KEYMAP_INIT;
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 1579f3ff98..45edbec4a6 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -6,59 +6,60 @@
*/
#include <assert.h>
-#include <string.h>
#include <inttypes.h>
#include <stdbool.h>
+#include <string.h>
-#include "nvim/vim.h"
#include "nvim/ascii.h"
-#include "nvim/edit.h"
#include "nvim/buffer.h"
#include "nvim/change.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
#include "nvim/digraph.h"
+#include "nvim/edit.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
+#include "nvim/event/loop.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
+#include "nvim/extmark.h"
#include "nvim/fileio.h"
#include "nvim/fold.h"
#include "nvim/getchar.h"
#include "nvim/indent.h"
#include "nvim/indent_c.h"
+#include "nvim/keymap.h"
#include "nvim/main.h"
-#include "nvim/extmark.h"
+#include "nvim/mark.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
-#include "nvim/keymap.h"
+#include "nvim/mouse.h"
#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/ops.h"
#include "nvim/option.h"
+#include "nvim/os/input.h"
+#include "nvim/os/time.h"
#include "nvim/path.h"
+#include "nvim/plines.h"
#include "nvim/popupmnu.h"
#include "nvim/quickfix.h"
#include "nvim/regexp.h"
#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/spell.h"
-#include "nvim/strings.h"
#include "nvim/state.h"
+#include "nvim/strings.h"
#include "nvim/syntax.h"
#include "nvim/tag.h"
-#include "nvim/ui.h"
-#include "nvim/mouse.h"
#include "nvim/terminal.h"
+#include "nvim/ui.h"
#include "nvim/undo.h"
+#include "nvim/vim.h"
#include "nvim/window.h"
-#include "nvim/event/loop.h"
-#include "nvim/mark.h"
-#include "nvim/os/input.h"
-#include "nvim/os/time.h"
// Definitions used for CTRL-X submode.
// Note: If you change CTRL-X submode, you must also maintain ctrl_x_msgs[]
@@ -83,6 +84,7 @@
#define CTRL_X_SPELL 14
#define CTRL_X_LOCAL_MSG 15 ///< only used in "ctrl_x_msgs"
#define CTRL_X_EVAL 16 ///< for builtin function complete()
+#define CTRL_X_CMDLINE_CTRL_X 17 ///< CTRL-X typed in CTRL_X_CMDLINE
#define CTRL_X_MSG(i) ctrl_x_msgs[(i) & ~CTRL_X_WANT_IDENT]
#define CTRL_X_MODE_LINE_OR_EVAL(m) \
@@ -108,6 +110,7 @@ static char *ctrl_x_msgs[] =
N_(" Spelling suggestion (s^N^P)"),
N_(" Keyword Local completion (^N^P)"),
NULL, // CTRL_X_EVAL doesn't use msg.
+ N_(" Command-line completion (^V^N^P)"),
};
static char *ctrl_x_mode_names[] = {
@@ -127,7 +130,8 @@ static char *ctrl_x_mode_names[] = {
"omni",
"spell",
NULL, // CTRL_X_LOCAL_MSG only used in "ctrl_x_msgs"
- "eval"
+ "eval",
+ "cmdline",
};
static char e_hitend[] = N_("Hit end of paragraph");
@@ -139,13 +143,13 @@ static char e_compldel[] = N_("E840: Completion function deleted text");
*/
typedef struct compl_S compl_T;
struct compl_S {
- compl_T *cp_next;
- compl_T *cp_prev;
- char_u *cp_str; // matched text
- char_u *(cp_text[CPT_COUNT]); // text for the menu
- typval_T cp_user_data;
- char_u *cp_fname; // file containing the match, allocated when
- // cp_flags has CP_FREE_FNAME
+ compl_T *cp_next;
+ compl_T *cp_prev;
+ char_u *cp_str; // matched text
+ char_u *(cp_text[CPT_COUNT]); // text for the menu
+ typval_T cp_user_data;
+ char_u *cp_fname; // file containing the match, allocated when
+ // cp_flags has CP_FREE_FNAME
int cp_flags; // CP_ values
int cp_number; // sequence number
};
@@ -157,10 +161,10 @@ struct compl_S {
* "compl_shown_match" is different from compl_curr_match during
* ins_compl_get_exp().
*/
-static compl_T *compl_first_match = NULL;
-static compl_T *compl_curr_match = NULL;
-static compl_T *compl_shown_match = NULL;
-static compl_T *compl_old_match = NULL;
+static compl_T *compl_first_match = NULL;
+static compl_T *compl_curr_match = NULL;
+static compl_T *compl_shown_match = NULL;
+static compl_T *compl_old_match = NULL;
/* After using a cursor key <Enter> selects a match in the popup menu,
* otherwise it inserts a line break. */
@@ -168,10 +172,9 @@ static int compl_enter_selects = FALSE;
/* When "compl_leader" is not NULL only matches that start with this string
* are used. */
-static char_u *compl_leader = NULL;
+static char_u *compl_leader = NULL;
-static int compl_get_longest = FALSE; /* put longest common string
- in compl_leader */
+static bool compl_get_longest = false; // put longest common string in compl_leader
static int compl_no_insert = FALSE; /* FALSE: select & insert
TRUE: noinsert */
@@ -195,19 +198,19 @@ static bool compl_started = false;
static int ctrl_x_mode = CTRL_X_NORMAL;
static int compl_matches = 0;
-static char_u *compl_pattern = NULL;
+static char_u *compl_pattern = NULL;
static Direction compl_direction = FORWARD;
static Direction compl_shows_dir = FORWARD;
static int compl_pending = 0; // > 1 for postponed CTRL-N
static pos_T compl_startpos;
static colnr_T compl_col = 0; /* column where the text starts
* that is being completed */
-static char_u *compl_orig_text = NULL; /* text as it was before
- * completion started */
+static char_u *compl_orig_text = NULL; /* text as it was before
+ * completion started */
static int compl_cont_mode = 0;
static expand_T compl_xp;
-static int compl_opt_refresh_always = FALSE;
+static bool compl_opt_refresh_always = false;
static int pum_selected_item = -1;
@@ -256,8 +259,8 @@ static colnr_T Insstart_textlen; // length of line when insert started
static colnr_T Insstart_blank_vcol; // vcol for first inserted blank
static bool update_Insstart_orig = true; // set Insstart_orig to Insstart
-static char_u *last_insert = NULL; // the text of the previous insert,
- // K_SPECIAL and CSI are escaped
+static char_u *last_insert = NULL; // the text of the previous insert,
+ // K_SPECIAL and CSI are escaped
static int last_insert_skip; // nr of chars in front of previous insert
static int new_insert_skip; // nr of chars in front of current insert
static int did_restart_edit; // "restart_edit" when calling edit()
@@ -309,7 +312,7 @@ static void insert_enter(InsertState *s)
s->ptr = (char_u *)"i";
}
- set_vim_var_string(VV_INSERTMODE, (char *) s->ptr, 1);
+ set_vim_var_string(VV_INSERTMODE, (char *)s->ptr, 1);
set_vim_var_string(VV_CHAR, NULL, -1);
ins_apply_autocmds(EVENT_INSERTENTER);
@@ -467,7 +470,7 @@ static void insert_enter(InsertState *s)
}
if (!p_im && did_restart_edit == 0) {
- change_warning(s->i == 0 ? 0 : s->i + 1);
+ change_warning(curbuf, s->i == 0 ? 0 : s->i + 1);
}
ui_cursor_shape(); // may show different cursor shape
@@ -761,7 +764,8 @@ static int insert_execute(VimState *state, int key)
s->c = do_digraph(s->c);
- if ((s->c == Ctrl_V || s->c == Ctrl_Q) && ctrl_x_mode == CTRL_X_CMDLINE) {
+ if ((s->c == Ctrl_V || s->c == Ctrl_Q)
+ && (ctrl_x_mode == CTRL_X_CMDLINE || ctrl_x_mode == CTRL_X_CMDLINE_CTRL_X)) {
insert_do_complete(s);
return 1;
}
@@ -790,15 +794,22 @@ static int insert_execute(VimState *state, int key)
}
}
- if (curwin->w_p_rl)
+ if (curwin->w_p_rl) {
switch (s->c) {
- case K_LEFT: s->c = K_RIGHT; break;
- case K_S_LEFT: s->c = K_S_RIGHT; break;
- case K_C_LEFT: s->c = K_C_RIGHT; break;
- case K_RIGHT: s->c = K_LEFT; break;
- case K_S_RIGHT: s->c = K_S_LEFT; break;
- case K_C_RIGHT: s->c = K_C_LEFT; break;
+ case K_LEFT:
+ s->c = K_RIGHT; break;
+ case K_S_LEFT:
+ s->c = K_S_RIGHT; break;
+ case K_C_LEFT:
+ s->c = K_C_RIGHT; break;
+ case K_RIGHT:
+ s->c = K_LEFT; break;
+ case K_S_RIGHT:
+ s->c = K_S_LEFT; break;
+ case K_C_RIGHT:
+ s->c = K_C_LEFT; break;
}
+ }
// If 'keymodel' contains "startsel", may start selection. If it
// does, a CTRL-O and c will be stuffed, we need to get these
@@ -1287,8 +1298,9 @@ normalchar:
// If the new value is already inserted or an empty string
// then don't insert any character.
- if (s->c == NUL)
+ if (s->c == NUL) {
break;
+ }
}
// Try to perform smart-indenting.
ins_try_si(s->c);
@@ -1308,8 +1320,8 @@ normalchar:
// special character. Let CTRL-] expand abbreviations without
// inserting it.
if (vim_iswordc(s->c)
- // Add ABBR_OFF for characters above 0x100, this is
- // what check_abbr() expects.
+ // Add ABBR_OFF for characters above 0x100, this is
+ // what check_abbr() expects.
|| (!echeck_abbr((s->c >= 0x100) ? (s->c + ABBR_OFF) : s->c)
&& s->c != Ctrl_RSB)) {
insert_special(s->c, false, false);
@@ -1414,21 +1426,20 @@ bool edit(int cmdchar, bool startln, long count)
return s->c == Ctrl_O;
}
-/*
- * Redraw for Insert mode.
- * This is postponed until getting the next character to make '$' in the 'cpo'
- * option work correctly.
- * Only redraw when there are no characters available. This speeds up
- * inserting sequences of characters (e.g., for CTRL-R).
- */
-static void ins_redraw(
- bool ready // not busy with something
-)
+/// Redraw for Insert mode.
+/// This is postponed until getting the next character to make '$' in the 'cpo'
+/// option work correctly.
+/// Only redraw when there are no characters available. This speeds up
+/// inserting sequences of characters (e.g., for CTRL-R).
+///
+/// @param ready not busy with something
+static void ins_redraw(bool ready)
{
bool conceal_cursor_moved = false;
- if (char_avail())
+ if (char_avail()) {
return;
+ }
// Trigger CursorMoved if the cursor moved. Not when the popup menu is
// visible, the command might delete it.
@@ -1651,11 +1662,11 @@ static void init_prompt(int cmdchar_todo)
check_cursor();
}
-// Return TRUE if the cursor is in the editable position of the prompt line.
-int prompt_curpos_editable(void)
+/// @return true if the cursor is in the editable position of the prompt line.
+bool prompt_curpos_editable(void)
{
- return curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count
- && curwin->w_cursor.col >= (int)STRLEN(prompt_text());
+ return curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count
+ && curwin->w_cursor.col >= (int)STRLEN(prompt_text());
}
/*
@@ -1684,8 +1695,9 @@ void display_dollar(colnr_T col)
{
colnr_T save_col;
- if (!redrawing())
+ if (!redrawing()) {
return;
+ }
save_col = curwin->w_cursor.col;
curwin->w_cursor.col = col;
@@ -1713,34 +1725,28 @@ static void undisplay_dollar(void)
}
}
-/*
- * Insert an indent (for <Tab> or CTRL-T) or delete an indent (for CTRL-D).
- * Keep the cursor on the same character.
- * type == INDENT_INC increase indent (for CTRL-T or <Tab>)
- * type == INDENT_DEC decrease indent (for CTRL-D)
- * type == INDENT_SET set indent to "amount"
- * if round is TRUE, round the indent to 'shiftwidth' (only with _INC and _Dec).
- */
-void
-change_indent (
- int type,
- int amount,
- int round,
- int replaced, // replaced character, put on replace stack
- int call_changed_bytes // call changed_bytes()
-)
+/// Insert an indent (for <Tab> or CTRL-T) or delete an indent (for CTRL-D).
+/// Keep the cursor on the same character.
+/// type == INDENT_INC increase indent (for CTRL-T or <Tab>)
+/// type == INDENT_DEC decrease indent (for CTRL-D)
+/// type == INDENT_SET set indent to "amount"
+///
+/// @param round if TRUE, round the indent to 'shiftwidth' (only with _INC and _Dec).
+/// @param replaced replaced character, put on replace stack
+/// @param call_changed_bytes call changed_bytes()
+void change_indent(int type, int amount, int round, int replaced, int call_changed_bytes)
{
int vcol;
int last_vcol;
int insstart_less; // reduction for Insstart.col
int new_cursor_col;
int i;
- char_u *ptr;
+ char_u *ptr;
int save_p_list;
int start_col;
colnr_T vc;
colnr_T orig_col = 0; // init for GCC
- char_u *new_line, *orig_line = NULL; // init for GCC
+ char_u *new_line, *orig_line = NULL; // init for GCC
// VREPLACE mode needs to know what the line was like before changing
if (State & VREPLACE_FLAG) {
@@ -1772,8 +1778,9 @@ change_indent (
* If the cursor is in the indent, compute how many screen columns the
* cursor is to the left of the first non-blank.
*/
- if (new_cursor_col < 0)
+ if (new_cursor_col < 0) {
vcol = get_indent() - vcol;
+ }
if (new_cursor_col > 0) { // can't fix replace stack
start_col = -1;
@@ -1782,9 +1789,9 @@ change_indent (
/*
* Set the new indent. The cursor will be put on the first non-blank.
*/
- if (type == INDENT_SET)
+ if (type == INDENT_SET) {
(void)set_indent(amount, call_changed_bytes ? SIN_CHANGED : 0);
- else {
+ } else {
int save_State = State;
// Avoid being called recursively.
@@ -1810,12 +1817,13 @@ change_indent (
* When changing the indent while the cursor is touching it, reset
* Insstart_col to 0.
*/
- if (new_cursor_col == 0)
+ if (new_cursor_col == 0) {
insstart_less = MAXCOL;
+ }
new_cursor_col += curwin->w_cursor.col;
- } else if (!(State & INSERT))
+ } else if (!(State & INSERT)) {
new_cursor_col = curwin->w_cursor.col;
- else {
+ } else {
/*
* Compute the screen column where the cursor should be.
*/
@@ -1862,10 +1870,11 @@ change_indent (
curwin->w_p_list = save_p_list;
- if (new_cursor_col <= 0)
+ if (new_cursor_col <= 0) {
curwin->w_cursor.col = 0;
- else
+ } else {
curwin->w_cursor.col = (colnr_T)new_cursor_col;
+ }
curwin->w_set_curswant = TRUE;
changed_cline_bef_curs();
@@ -1874,15 +1883,17 @@ change_indent (
*/
if (State & INSERT) {
if (curwin->w_cursor.lnum == Insstart.lnum && Insstart.col != 0) {
- if ((int)Insstart.col <= insstart_less)
+ if ((int)Insstart.col <= insstart_less) {
Insstart.col = 0;
- else
+ } else {
Insstart.col -= insstart_less;
+ }
}
- if ((int)ai_col <= insstart_less)
+ if ((int)ai_col <= insstart_less) {
ai_col = 0;
- else
+ } else {
ai_col -= insstart_less;
+ }
}
/*
@@ -1974,10 +1985,11 @@ void backspace_until_column(int col)
{
while ((int)curwin->w_cursor.col > col) {
curwin->w_cursor.col--;
- if (State & REPLACE_FLAG)
+ if (State & REPLACE_FLAG) {
replace_do_bs(col);
- else if (!del_char_after_col(col))
+ } else if (!del_char_after_col(col)) {
break;
+ }
}
}
@@ -2019,20 +2031,22 @@ static bool del_char_after_col(int limit_col)
*/
static void ins_ctrl_x(void)
{
- /* CTRL-X after CTRL-X CTRL-V doesn't do anything, so that CTRL-X
- * CTRL-V works like CTRL-N */
- if (ctrl_x_mode != CTRL_X_CMDLINE) {
- /* if the next ^X<> won't ADD nothing, then reset
- * compl_cont_status */
- if (compl_cont_status & CONT_N_ADDS)
+ if (ctrl_x_mode != CTRL_X_CMDLINE && ctrl_x_mode != CTRL_X_CMDLINE_CTRL_X) {
+ // if the next ^X<> won't ADD nothing, then reset compl_cont_status
+ if (compl_cont_status & CONT_N_ADDS) {
compl_cont_status |= CONT_INTRPT;
- else
+ } else {
compl_cont_status = 0;
+ }
// We're not sure which CTRL-X mode it will be yet
ctrl_x_mode = CTRL_X_NOT_DEFINED_YET;
edit_submode = (char_u *)_(CTRL_X_MSG(ctrl_x_mode));
edit_submode_pre = NULL;
showmode();
+ } else {
+ // CTRL-X in CTRL-X CTRL-V mode behaves differently to make CTRL-X
+ // CTRL-V look like CTRL-N
+ ctrl_x_mode = CTRL_X_CMDLINE_CTRL_X;
}
}
@@ -2042,7 +2056,8 @@ bool ctrl_x_mode_not_default(void)
return ctrl_x_mode != CTRL_X_NORMAL;
}
-// Whether CTRL-X was typed without a following character.
+// Whether CTRL-X was typed without a following character,
+// not including when in CTRL-X CTRL-V mode.
bool ctrl_x_mode_not_defined_yet(void)
{
return ctrl_x_mode == CTRL_X_NOT_DEFINED_YET;
@@ -2094,12 +2109,14 @@ bool vim_is_ctrl_x_key(int c)
case 0: // Not in any CTRL-X mode
return c == Ctrl_N || c == Ctrl_P || c == Ctrl_X;
case CTRL_X_NOT_DEFINED_YET:
+ case CTRL_X_CMDLINE_CTRL_X:
return c == Ctrl_X || c == Ctrl_Y || c == Ctrl_E
|| c == Ctrl_L || c == Ctrl_F || c == Ctrl_RSB
|| c == Ctrl_I || c == Ctrl_D || c == Ctrl_P
|| c == Ctrl_N || c == Ctrl_T || c == Ctrl_V
|| c == Ctrl_Q || c == Ctrl_U || c == Ctrl_O
- || c == Ctrl_S || c == Ctrl_K || c == 's';
+ || c == Ctrl_S || c == Ctrl_K || c == 's'
+ || c == Ctrl_Z;
case CTRL_X_SCROLL:
return c == Ctrl_Y || c == Ctrl_E;
case CTRL_X_WHOLE_LINE:
@@ -2153,6 +2170,7 @@ static bool ins_compl_accept_char(int c)
return vim_isfilec(c) && !vim_ispathsep(c);
case CTRL_X_CMDLINE:
+ case CTRL_X_CMDLINE_CTRL_X:
case CTRL_X_OMNI:
// Command line and Omni completion can work with just about any
// printable character, but do stop at white space.
@@ -2171,8 +2189,8 @@ static bool ins_compl_accept_char(int c)
/// the rest of the word to be in -- webb
///
/// @param[in] cont_s_ipos next ^X<> will set initial_pos
-int ins_compl_add_infercase(char_u *str_arg, int len, bool icase, char_u *fname,
- Direction dir, bool cont_s_ipos)
+int ins_compl_add_infercase(char_u *str_arg, int len, bool icase, char_u *fname, Direction dir,
+ bool cont_s_ipos)
FUNC_ATTR_NONNULL_ARG(1)
{
char_u *str = str_arg;
@@ -2315,15 +2333,12 @@ int ins_compl_add_infercase(char_u *str_arg, int len, bool icase, char_u *fname,
/// @return NOTDONE if the given string is already in the list of completions,
/// otherwise it is added to the list and OK is returned. FAIL will be
/// returned in case of error.
-static int ins_compl_add(char_u *const str, int len,
- char_u *const fname,
- char_u *const *const cptext,
- const bool cptext_allocated,
- typval_T *user_data,
- const Direction cdir, int flags_arg, const bool adup)
+static int ins_compl_add(char_u *const str, int len, char_u *const fname,
+ char_u *const *const cptext, const bool cptext_allocated,
+ typval_T *user_data, const Direction cdir, int flags_arg, const bool adup)
FUNC_ATTR_NONNULL_ARG(1)
{
- compl_T *match;
+ compl_T *match;
const Direction dir = (cdir == kDirectionNotSet ? compl_direction : cdir);
int flags = flags_arg;
@@ -2419,9 +2434,9 @@ static int ins_compl_add(char_u *const str, int len,
/*
* Link the new match structure in the list of matches.
*/
- if (compl_first_match == NULL)
+ if (compl_first_match == NULL) {
match->cp_next = match->cp_prev = NULL;
- else if (dir == FORWARD) {
+ } else if (dir == FORWARD) {
match->cp_next = compl_curr_match->cp_next;
match->cp_prev = compl_curr_match;
} else { // BACKWARD
@@ -2453,7 +2468,7 @@ static int ins_compl_add(char_u *const str, int len,
///
/// @param match completion match
/// @param str character string to check
-/// @param len lenth of "str"
+/// @param len length of "str"
static bool ins_compl_equal(compl_T *match, char_u *str, size_t len)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
@@ -2471,7 +2486,7 @@ static bool ins_compl_equal(compl_T *match, char_u *str, size_t len)
*/
static void ins_compl_longest_match(compl_T *match)
{
- char_u *p, *s;
+ char_u *p, *s;
int c1, c2;
int had_match;
@@ -2485,8 +2500,9 @@ static void ins_compl_longest_match(compl_T *match)
/* When the match isn't there (to avoid matching itself) remove it
* again after redrawing. */
- if (!had_match)
+ if (!had_match) {
ins_compl_delete();
+ }
compl_used_match = false;
} else {
// Reduce the text if this match differs from compl_leader.
@@ -2515,8 +2531,9 @@ static void ins_compl_longest_match(compl_T *match)
/* When the match isn't there (to avoid matching itself) remove it
* again after redrawing. */
- if (!had_match)
+ if (!had_match) {
ins_compl_delete();
+ }
}
compl_used_match = false;
@@ -2600,8 +2617,9 @@ void set_completion(colnr_T startcol, list_T *list)
ins_compl_free();
compl_direction = FORWARD;
- if (startcol > curwin->w_cursor.col)
+ if (startcol > curwin->w_cursor.col) {
startcol = curwin->w_cursor.col;
+ }
compl_col = startcol;
compl_length = (int)curwin->w_cursor.col - (int)startcol;
// compl_pattern doesn't need to be set
@@ -2724,8 +2742,8 @@ static void trigger_complete_changed_event(int cur)
/// Also adjusts "compl_shown_match" to an entry that is actually displayed.
void ins_compl_show_pum(void)
{
- compl_T *compl;
- compl_T *shown_compl = NULL;
+ compl_T *compl;
+ compl_T *shown_compl = NULL;
bool did_find_shown_match = false;
bool shown_match_ok = false;
int i;
@@ -2734,8 +2752,9 @@ void ins_compl_show_pum(void)
int lead_len = 0;
bool array_changed = false;
- if (!pum_wanted() || !pum_enough_matches())
+ if (!pum_wanted() || !pum_enough_matches()) {
return;
+ }
// Dirty hard-coded hack: remove any matchparen highlighting.
do_cmdline_cmd("if exists('g:loaded_matchparen')|3match none|endif");
@@ -2766,8 +2785,9 @@ void ins_compl_show_pum(void)
}
compl = compl->cp_next;
} while (compl != NULL && compl != compl_first_match);
- if (compl_match_arraysize == 0)
+ if (compl_match_arraysize == 0) {
return;
+ }
assert(compl_match_arraysize >= 0);
compl_match_array = xcalloc(compl_match_arraysize, sizeof(pumitem_T));
@@ -2798,18 +2818,20 @@ void ins_compl_show_pum(void)
cur = i;
}
- if (compl->cp_text[CPT_ABBR] != NULL)
+ if (compl->cp_text[CPT_ABBR] != NULL) {
compl_match_array[i].pum_text =
compl->cp_text[CPT_ABBR];
- else
+ } else {
compl_match_array[i].pum_text = compl->cp_str;
+ }
compl_match_array[i].pum_kind = compl->cp_text[CPT_KIND];
compl_match_array[i].pum_info = compl->cp_text[CPT_INFO];
- if (compl->cp_text[CPT_MENU] != NULL)
+ if (compl->cp_text[CPT_MENU] != NULL) {
compl_match_array[i++].pum_extra =
compl->cp_text[CPT_MENU];
- else
+ } else {
compl_match_array[i++].pum_extra = compl->cp_fname;
+ }
}
if (compl == compl_shown_match) {
@@ -2866,23 +2888,18 @@ void ins_compl_show_pum(void)
#define DICT_FIRST (1) // use just first element in "dict"
#define DICT_EXACT (2) // "dict" is the exact name of a file
-/*
- * Add any identifiers that match the given pattern in the list of dictionary
- * files "dict_start" to the list of completions.
- */
-static void
-ins_compl_dictionaries (
- char_u *dict_start,
- char_u *pat,
- int flags, // DICT_FIRST and/or DICT_EXACT
- int thesaurus // Thesaurus completion
-)
-{
- char_u *dict = dict_start;
- char_u *ptr;
- char_u *buf;
+/// Add any identifiers that match the given pattern in the list of dictionary
+/// files "dict_start" to the list of completions.
+///
+/// @param flags DICT_FIRST and/or DICT_EXACT
+/// @param thesaurus Thesaurus completion
+static void ins_compl_dictionaries(char_u *dict_start, char_u *pat, int flags, int thesaurus)
+{
+ char_u *dict = dict_start;
+ char_u *ptr;
+ char_u *buf;
regmatch_T regmatch;
- char_u **files;
+ char_u **files;
int count;
int save_p_scs;
Direction dir = compl_direction;
@@ -2890,10 +2907,11 @@ ins_compl_dictionaries (
if (*dict == NUL) {
/* When 'dictionary' is empty and spell checking is enabled use
* "spell". */
- if (!thesaurus && curwin->w_p_spell)
+ if (!thesaurus && curwin->w_p_spell) {
dict = (char_u *)"spell";
- else
+ } else {
return;
+ }
}
buf = xmalloc(LSIZE);
@@ -2901,8 +2919,9 @@ ins_compl_dictionaries (
// If 'infercase' is set, don't use 'smartcase' here
save_p_scs = p_scs;
- if (curbuf->b_p_inf)
+ if (curbuf->b_p_inf) {
p_scs = FALSE;
+ }
/* When invoked to match whole lines for CTRL-X CTRL-L adjust the pattern
* to only match at the start of a line. Otherwise just match the
@@ -2918,8 +2937,9 @@ ins_compl_dictionaries (
xfree(ptr);
} else {
regmatch.regprog = vim_regcomp(pat, p_magic ? RE_MAGIC : 0);
- if (regmatch.regprog == NULL)
+ if (regmatch.regprog == NULL) {
goto theend;
+ }
}
// ignore case depends on 'ignorecase', 'smartcase' and "pat"
@@ -2934,30 +2954,34 @@ ins_compl_dictionaries (
* backticks (for security, the 'dict' option may have been set in
* a modeline). */
copy_option_part(&dict, buf, LSIZE, ",");
- if (!thesaurus && STRCMP(buf, "spell") == 0)
+ if (!thesaurus && STRCMP(buf, "spell") == 0) {
count = -1;
- else if (vim_strchr(buf, '`') != NULL
- || expand_wildcards(1, &buf, &count, &files,
- EW_FILE|EW_SILENT) != OK)
+ } else if (vim_strchr(buf, '`') != NULL
+ || expand_wildcards(1, &buf, &count, &files,
+ EW_FILE|EW_SILENT) != OK) {
count = 0;
+ }
}
if (count == -1) {
/* Complete from active spelling. Skip "\<" in the pattern, we
* don't use it as a RE. */
- if (pat[0] == '\\' && pat[1] == '<')
+ if (pat[0] == '\\' && pat[1] == '<') {
ptr = pat + 2;
- else
+ } else {
ptr = pat;
+ }
spell_dump_compl(ptr, regmatch.rm_ic, &dir, 0);
} else if (count > 0) { // avoid warning for using "files" uninit
ins_compl_files(count, files, thesaurus, flags,
- &regmatch, buf, &dir);
- if (flags != DICT_EXACT)
+ &regmatch, buf, &dir);
+ if (flags != DICT_EXACT) {
FreeWild(count, files);
+ }
}
- if (flags != 0)
+ if (flags != 0) {
break;
+ }
}
theend:
@@ -2966,14 +2990,13 @@ theend:
xfree(buf);
}
-static void ins_compl_files(int count, char_u **files, int thesaurus,
- int flags, regmatch_T *regmatch, char_u *buf,
- Direction *dir)
+static void ins_compl_files(int count, char_u **files, int thesaurus, int flags,
+ regmatch_T *regmatch, char_u *buf, Direction *dir)
FUNC_ATTR_NONNULL_ARG(2, 7)
{
- char_u *ptr;
+ char_u *ptr;
int i;
- FILE *fp;
+ FILE *fp;
int add_r;
for (i = 0; i < count && !got_int && !compl_interrupted; i++) {
@@ -3016,8 +3039,9 @@ static void ins_compl_files(int count, char_u **files, int thesaurus,
/* Find start of the next word. Skip white
* space and punctuation. */
ptr = find_word_start(ptr);
- if (*ptr == NUL || *ptr == NL)
+ if (*ptr == NUL || *ptr == NL) {
break;
+ }
wstart = ptr;
// Find end of the word.
@@ -3095,11 +3119,12 @@ char_u *find_word_end(char_u *ptr)
*/
static char_u *find_line_end(char_u *ptr)
{
- char_u *s;
+ char_u *s;
s = ptr + STRLEN(ptr);
- while (s > ptr && (s[-1] == CAR || s[-1] == NL))
+ while (s > ptr && (s[-1] == CAR || s[-1] == NL)) {
--s;
+ }
return s;
}
@@ -3113,8 +3138,9 @@ static void ins_compl_free(void)
XFREE_CLEAR(compl_pattern);
XFREE_CLEAR(compl_leader);
- if (compl_first_match == NULL)
+ if (compl_first_match == NULL) {
return;
+ }
ins_compl_del_pum();
pum_clear();
@@ -3276,9 +3302,9 @@ void get_complete_info(list_T *what_list, dict_T *retdict)
tv_dict_add_str(di, S_LEN("info"),
(char *)EMPTY_IF_NULL(match->cp_text[CPT_INFO]));
if (match->cp_user_data.v_type == VAR_UNKNOWN) {
- tv_dict_add_str(di, S_LEN("user_data"), "");
+ tv_dict_add_str(di, S_LEN("user_data"), "");
} else {
- tv_dict_add_tv(di, S_LEN("user_data"), &match->cp_user_data);
+ tv_dict_add_tv(di, S_LEN("user_data"), &match->cp_user_data);
}
}
match = match->cp_next;
@@ -3301,7 +3327,7 @@ void get_complete_info(list_T *what_list, dict_T *retdict)
}
// Return Insert completion mode name string
-static char_u * ins_compl_mode(void)
+static char_u *ins_compl_mode(void)
{
if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET || compl_started) {
return (char_u *)ctrl_x_mode_names[ctrl_x_mode & ~CTRL_X_WANT_IDENT];
@@ -3318,12 +3344,10 @@ static char_u * ins_compl_mode(void)
*/
static int ins_compl_bs(void)
{
- char_u *line;
- char_u *p;
-
- line = get_cursor_line_ptr();
- p = line + curwin->w_cursor.col;
+ char_u *line = get_cursor_line_ptr();
+ char_u *p = line + curwin->w_cursor.col;
MB_PTR_BACK(line, p);
+ ptrdiff_t p_off = p - line;
// Stop completion when the whole word was deleted. For Omni completion
// allow the word to be deleted, we won't match everything.
@@ -3339,11 +3363,16 @@ static int ins_compl_bs(void)
/* Deleted more than what was used to find matches or didn't finish
* finding all matches: need to look for matches all over again. */
if (curwin->w_cursor.col <= compl_col + compl_length
- || ins_compl_need_restart())
+ || ins_compl_need_restart()) {
ins_compl_restart();
+ }
+
+ // ins_compl_restart() calls update_screen(0) which may invalidate the pointer
+ // TODO(bfredl): get rid of random update_screen() calls deep inside completion logic
+ line = get_cursor_line_ptr();
xfree(compl_leader);
- compl_leader = vim_strnsave(line + compl_col, (int)(p - line) - compl_col);
+ compl_leader = vim_strnsave(line + compl_col, (int)p_off - compl_col);
ins_compl_new_leader();
if (compl_shown_match != NULL) {
// Make sure current match is not a hidden item.
@@ -3397,8 +3426,9 @@ static void ins_compl_new_leader(void)
/* Don't let Enter select the original text when there is no popup menu.
* Don't let Enter select when use user function and refresh_always is set */
- if (compl_match_array == NULL || ins_compl_need_restart())
+ if (compl_match_array == NULL || ins_compl_need_restart()) {
compl_enter_selects = FALSE;
+ }
}
/*
@@ -3409,8 +3439,9 @@ static int ins_compl_len(void)
{
int off = (int)curwin->w_cursor.col - (int)compl_col;
- if (off < 0)
+ if (off < 0) {
return 0;
+ }
return off;
}
@@ -3423,7 +3454,7 @@ static void ins_compl_addleader(int c)
int cc;
if (stop_arrow() == FAIL) {
- return;
+ return;
}
if ((cc = utf_char2len(c)) > 1) {
char_u buf[MB_MAXBYTES + 1];
@@ -3488,10 +3519,10 @@ static void ins_compl_set_original_text(char_u *str)
*/
static void ins_compl_addfrommatch(void)
{
- char_u *p;
+ char_u *p;
int len = (int)curwin->w_cursor.col - (int)compl_col;
int c;
- compl_T *cp;
+ compl_T *cp;
assert(compl_shown_match != NULL);
p = compl_shown_match->cp_str;
if ((int)STRLEN(p) <= len) { // the match is too short
@@ -3503,15 +3534,17 @@ static void ins_compl_addfrommatch(void)
&& cp != compl_first_match; cp = cp->cp_next) {
if (compl_leader == NULL
|| ins_compl_equal(cp, compl_leader,
- (int)STRLEN(compl_leader))) {
+ (int)STRLEN(compl_leader))) {
p = cp->cp_str;
break;
}
}
- if (p == NULL || (int)STRLEN(p) <= len)
+ if (p == NULL || (int)STRLEN(p) <= len) {
return;
- } else
+ }
+ } else {
return;
+ }
}
p += len;
c = PTR2CHAR(p);
@@ -3533,8 +3566,9 @@ static bool ins_compl_prep(int c)
/* Forget any previous 'special' messages if this is actually
* a ^X mode key - bar ^R, in which case we wait to see what it gives us.
*/
- if (c != Ctrl_R && vim_is_ctrl_x_key(c))
+ if (c != Ctrl_R && vim_is_ctrl_x_key(c)) {
edit_submode_extra = NULL;
+ }
// Ignore end of Select mode mapping and mouse scroll buttons.
if (c == K_SELECT || c == K_MOUSEDOWN || c == K_MOUSEUP
@@ -3543,6 +3577,26 @@ static bool ins_compl_prep(int c)
return retval;
}
+ if (ctrl_x_mode == CTRL_X_CMDLINE_CTRL_X && c != Ctrl_X) {
+ if (c == Ctrl_V || c == Ctrl_Q || c == Ctrl_Z || ins_compl_pum_key(c)
+ || !vim_is_ctrl_x_key(c)) {
+ // Not starting another completion mode.
+ ctrl_x_mode = CTRL_X_CMDLINE;
+
+ // CTRL-X CTRL-Z should stop completion without inserting anything
+ if (c == Ctrl_Z) {
+ retval = true;
+ }
+ } else {
+ ctrl_x_mode = CTRL_X_CMDLINE;
+
+ // Other CTRL-X keys first stop completion, then start another
+ // completion mode.
+ ins_compl_prep(' ');
+ ctrl_x_mode = CTRL_X_NOT_DEFINED_YET;
+ }
+ }
+
// Set "compl_get_longest" when finding the first matches.
if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET
|| (ctrl_x_mode == CTRL_X_NORMAL && !compl_started)) {
@@ -3559,10 +3613,11 @@ static bool ins_compl_prep(int c)
case Ctrl_E:
case Ctrl_Y:
ctrl_x_mode = CTRL_X_SCROLL;
- if (!(State & REPLACE_FLAG))
+ if (!(State & REPLACE_FLAG)) {
edit_submode = (char_u *)_(" (insert) Scroll (^E/^Y)");
- else
+ } else {
edit_submode = (char_u *)_(" (replace) Scroll (^E/^Y)");
+ }
edit_submode_pre = NULL;
showmode();
break;
@@ -3608,6 +3663,12 @@ static bool ins_compl_prep(int c)
case Ctrl_Q:
ctrl_x_mode = CTRL_X_CMDLINE;
break;
+ case Ctrl_Z:
+ ctrl_x_mode = CTRL_X_NORMAL;
+ edit_submode = NULL;
+ showmode();
+ retval = true;
+ break;
case Ctrl_P:
case Ctrl_N:
/* ^X^P means LOCAL expansion if nothing interrupted (eg we
@@ -3617,10 +3678,11 @@ static bool ins_compl_prep(int c)
* ^X^F^X^P or ^P^X^X^P, see below)
* nothing changes if interrupting mode 0, (eg, the flag
* doesn't change when going to ADDING mode -- Acevedo */
- if (!(compl_cont_status & CONT_INTRPT))
+ if (!(compl_cont_status & CONT_INTRPT)) {
compl_cont_status |= CONT_LOCAL;
- else if (compl_cont_mode != 0)
+ } else if (compl_cont_mode != 0) {
compl_cont_status &= ~CONT_LOCAL;
+ }
FALLTHROUGH;
default:
/* If we have typed at least 2 ^X's... for modes != 0, we set
@@ -3634,10 +3696,11 @@ static bool ins_compl_prep(int c)
* In mode 0 an extra ^X is needed since ^X^P goes to ADDING
* mode -- Acevedo */
if (c == Ctrl_X) {
- if (compl_cont_mode != 0)
+ if (compl_cont_mode != 0) {
compl_cont_status = 0;
- else
+ } else {
compl_cont_mode = CTRL_X_NOT_DEFINED_YET;
+ }
}
ctrl_x_mode = CTRL_X_NORMAL;
edit_submode = NULL;
@@ -3680,10 +3743,11 @@ static bool ins_compl_prep(int c)
* When using the longest match, edited the match or used
* CTRL-E then don't use the current match.
*/
- if (compl_curr_match != NULL && compl_used_match && c != Ctrl_E)
+ if (compl_curr_match != NULL && compl_used_match && c != Ctrl_E) {
ptr = compl_curr_match->cp_str;
- else
+ } else {
ptr = NULL;
+ }
ins_compl_fixRedoBufForLeader(ptr);
}
@@ -3765,16 +3829,18 @@ static bool ins_compl_prep(int c)
/*
* Indent now if a key was typed that is in 'cinkeys'.
*/
- if (want_cindent && in_cinkeys(KEY_COMPLETE, ' ', inindent(0)))
+ if (want_cindent && in_cinkeys(KEY_COMPLETE, ' ', inindent(0))) {
do_c_expr_indent();
+ }
// Trigger the CompleteDone event to give scripts a chance to act
// upon the end of completion.
ins_apply_autocmds(EVENT_COMPLETEDONE);
}
- } else if (ctrl_x_mode == CTRL_X_LOCAL_MSG)
+ } else if (ctrl_x_mode == CTRL_X_LOCAL_MSG) {
/* Trigger the CompleteDone event to give scripts a chance to act
* upon the (possibly failed) completion. */
ins_apply_autocmds(EVENT_COMPLETEDONE);
+ }
/* reset continue_* if we left expansion-mode, if we stay they'll be
* (re)set properly in ins_complete() */
@@ -3794,8 +3860,8 @@ static bool ins_compl_prep(int c)
static void ins_compl_fixRedoBufForLeader(char_u *ptr_arg)
{
int len;
- char_u *p;
- char_u *ptr = ptr_arg;
+ char_u *p;
+ char_u *ptr = ptr_arg;
if (ptr == NULL) {
if (compl_leader != NULL) {
@@ -3822,7 +3888,7 @@ static void ins_compl_fixRedoBufForLeader(char_u *ptr_arg)
/*
* Loops through the list of windows, loaded-buffers or non-loaded-buffers
* (depending on flag) starting from buf and looking for a non-scanned
- * buffer (other than curbuf). curbuf is special, if it is called with
+ * buffer (other than curbuf). curbuf is special, if it is called with
* buf=curbuf then it has to be the first call for a given flag/expansion.
*
* Returns the buffer to scan, if any, otherwise returns curbuf -- Acevedo
@@ -3837,10 +3903,11 @@ static buf_T *ins_compl_next_buf(buf_T *buf, int flag)
}
assert(wp);
while ((wp = (wp->w_next != NULL ? wp->w_next : firstwin)) != curwin
- && wp->w_buffer->b_scanned)
+ && wp->w_buffer->b_scanned) {
;
+ }
buf = wp->w_buffer;
- } else
+ } else {
/* 'b' (just loaded buffers), 'u' (just non-loaded buffers) or 'U'
* (unlisted buffers)
* When completing whole lines skip unloaded buffers. */
@@ -3849,19 +3916,19 @@ static buf_T *ins_compl_next_buf(buf_T *buf, int flag)
? buf->b_p_bl
: (!buf->b_p_bl
|| (buf->b_ml.ml_mfp == NULL) != (flag == 'u')))
- || buf->b_scanned))
+ || buf->b_scanned)) {
;
+ }
+ }
return buf;
}
-// Execute user defined complete function 'completefunc' or 'omnifunc', and
-// get matches in "matches".
-static void
-expand_by_function(
- int type, // CTRL_X_OMNI or CTRL_X_FUNCTION
- char_u *base
-)
+/// Execute user defined complete function 'completefunc' or 'omnifunc', and
+/// get matches in "matches".
+///
+/// @param type CTRL_X_OMNI or CTRL_X_FUNCTION
+static void expand_by_function(int type, char_u *base)
{
list_T *matchlist = NULL;
dict_T *matchdict = NULL;
@@ -3919,10 +3986,11 @@ expand_by_function(
goto theend;
}
- if (matchlist != NULL)
+ if (matchlist != NULL) {
ins_compl_add_list(matchlist);
- else if (matchdict != NULL)
+ } else if (matchdict != NULL) {
ins_compl_add_dict(matchdict);
+ }
theend:
// Restore State, it might have been changed.
@@ -3959,8 +4027,8 @@ static void ins_compl_add_list(list_T *const list)
*/
static void ins_compl_add_dict(dict_T *dict)
{
- dictitem_T *di_refresh;
- dictitem_T *di_words;
+ dictitem_T *di_refresh;
+ dictitem_T *di_words;
// Check for optional "refresh" item.
compl_opt_refresh_always = false;
@@ -4018,7 +4086,7 @@ int ins_compl_add_tv(typval_T *const tv, const Direction dir, bool fast)
flags |= CP_EQUAL;
}
} else {
- word = (const char *)tv_get_string_chk(tv);
+ word = tv_get_string_chk(tv);
memset(cptext, 0, sizeof(cptext));
}
if (word == NULL || (!empty && *word == NUL)) {
@@ -4043,7 +4111,7 @@ static int ins_compl_get_exp(pos_T *ini)
static pos_T first_match_pos;
static pos_T last_match_pos;
static char_u *e_cpt = (char_u *)""; // curr. entry in 'complete'
- static int found_all = false; // Found all matches of a
+ static bool found_all = false; // Found all matches of a
// certain type.
static buf_T *ins_buf = NULL; // buffer being scanned
@@ -4060,7 +4128,8 @@ static int ins_compl_get_exp(pos_T *ini)
char_u *ptr;
char_u *dict = NULL;
int dict_f = 0;
- int set_match_pos;
+ bool set_match_pos;
+ pos_T prev_pos = { 0, 0, 0 };
int l_ctrl_x_mode = ctrl_x_mode;
assert(curbuf != NULL);
@@ -4069,7 +4138,7 @@ static int ins_compl_get_exp(pos_T *ini)
FOR_ALL_BUFFERS(buf) {
buf->b_scanned = false;
}
- found_all = FALSE;
+ found_all = false;
ins_buf = curbuf;
e_cpt = (compl_cont_status & CONT_LOCAL)
? (char_u *)"." : curbuf->b_p_cpt;
@@ -4084,7 +4153,7 @@ static int ins_compl_get_exp(pos_T *ini)
// For ^N/^P loop over all the flags/windows/buffers in 'complete'
for (;; ) {
found_new_match = FAIL;
- set_match_pos = FALSE;
+ set_match_pos = false;
assert(l_ctrl_x_mode == ctrl_x_mode);
@@ -4094,9 +4163,10 @@ static int ins_compl_get_exp(pos_T *ini)
if ((l_ctrl_x_mode == CTRL_X_NORMAL
|| CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode))
&& (!compl_started || found_all)) {
- found_all = FALSE;
- while (*e_cpt == ',' || *e_cpt == ' ')
+ found_all = false;
+ while (*e_cpt == ',' || *e_cpt == ' ') {
e_cpt++;
+ }
if (*e_cpt == '.' && !curbuf->b_scanned) {
ins_buf = curbuf;
first_match_pos = *ini;
@@ -4117,7 +4187,7 @@ static int ins_compl_get_exp(pos_T *ini)
set_match_pos = true;
} else if (vim_strchr((char_u *)"buwU", *e_cpt) != NULL
&& (ins_buf =
- ins_compl_next_buf(ins_buf, *e_cpt)) != curbuf) {
+ ins_compl_next_buf(ins_buf, *e_cpt)) != curbuf) {
// Scan a buffer, but not the current one.
if (ins_buf->b_ml.ml_mfp != NULL) { // loaded buffer
compl_started = true;
@@ -4148,10 +4218,11 @@ static int ins_compl_get_exp(pos_T *ini)
if (CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode)) {
type = -1;
} else if (*e_cpt == 'k' || *e_cpt == 's') {
- if (*e_cpt == 'k')
+ if (*e_cpt == 'k') {
type = CTRL_X_DICTIONARY;
- else
+ } else {
type = CTRL_X_THESAURUS;
+ }
if (*++e_cpt != ',' && *e_cpt != NUL) {
dict = e_cpt;
dict_f = DICT_FIRST;
@@ -4172,9 +4243,10 @@ static int ins_compl_get_exp(pos_T *ini)
// in any case e_cpt is advanced to the next entry
(void)copy_option_part(&e_cpt, IObuff, IOSIZE, ",");
- found_all = TRUE;
- if (type == -1)
+ found_all = true;
+ if (type == -1) {
continue;
+ }
}
}
@@ -4200,18 +4272,17 @@ static int ins_compl_get_exp(pos_T *ini)
case CTRL_X_DICTIONARY:
case CTRL_X_THESAURUS:
- ins_compl_dictionaries(
- dict != NULL ? dict
- : (type == CTRL_X_THESAURUS
+ ins_compl_dictionaries(dict != NULL ? dict
+ : (type == CTRL_X_THESAURUS
? (*curbuf->b_p_tsr == NUL
? p_tsr
: curbuf->b_p_tsr)
- : (*curbuf->b_p_dict == NUL
+ : (*curbuf->b_p_dict == NUL
? p_dict
: curbuf->b_p_dict)),
- compl_pattern,
- dict != NULL ? dict_f
- : 0, type == CTRL_X_THESAURUS);
+ compl_pattern,
+ dict != NULL ? dict_f
+ : 0, type == CTRL_X_THESAURUS);
dict = NULL;
break;
@@ -4241,7 +4312,7 @@ static int ins_compl_get_exp(pos_T *ini)
#ifdef BACKSLASH_IN_FILENAME
if (curbuf->b_p_csl[0] != NUL) {
for (int i = 0; i < num_matches; i++) {
- char_u *ptr = matches[i];
+ char_u *ptr = matches[i];
while (*ptr != NUL) {
if (curbuf->b_p_csl[0] == 's' && *ptr == '\\') {
*ptr = '/';
@@ -4258,10 +4329,12 @@ static int ins_compl_get_exp(pos_T *ini)
break;
case CTRL_X_CMDLINE:
+ case CTRL_X_CMDLINE_CTRL_X:
if (expand_cmdline(&compl_xp, compl_pattern,
- (int)STRLEN(compl_pattern),
- &num_matches, &matches) == EXPAND_OK)
- ins_compl_add_matches(num_matches, matches, FALSE);
+ (int)STRLEN(compl_pattern),
+ &num_matches, &matches) == EXPAND_OK) {
+ ins_compl_add_matches(num_matches, matches, false);
+ }
break;
case CTRL_X_FUNCTION:
@@ -4271,27 +4344,31 @@ static int ins_compl_get_exp(pos_T *ini)
case CTRL_X_SPELL:
num_matches = expand_spelling(first_match_pos.lnum,
- compl_pattern, &matches);
- if (num_matches > 0)
+ compl_pattern, &matches);
+ if (num_matches > 0) {
ins_compl_add_matches(num_matches, matches, p_ic);
+ }
break;
default: // normal ^P/^N and ^X^L
// If 'infercase' is set, don't use 'smartcase' here
save_p_scs = p_scs;
assert(ins_buf);
- if (ins_buf->b_p_inf)
+ if (ins_buf->b_p_inf) {
p_scs = FALSE;
+ }
// Buffers other than curbuf are scanned from the beginning or the
// end but never from the middle, thus setting nowrapscan in this
// buffers is a good idea, on the other hand, we always set
// wrapscan for curbuf to avoid missing matches -- Acevedo,Webb
save_p_ws = p_ws;
- if (ins_buf != curbuf)
+ if (ins_buf != curbuf) {
p_ws = false;
- else if (*e_cpt == '.')
+ } else if (*e_cpt == '.') {
p_ws = true;
+ }
+ bool looped_around = false;
for (;; ) {
bool cont_s_ipos = false;
@@ -4320,10 +4397,30 @@ static int ins_compl_get_exp(pos_T *ini)
} else if (first_match_pos.lnum == last_match_pos.lnum
&& first_match_pos.col == last_match_pos.col) {
found_new_match = FAIL;
+ } else if ((compl_direction == FORWARD)
+ && (prev_pos.lnum > pos->lnum
+ || (prev_pos.lnum == pos->lnum
+ && prev_pos.col >= pos->col))) {
+ if (looped_around) {
+ found_new_match = FAIL;
+ } else {
+ looped_around = true;
+ }
+ } else if ((compl_direction != FORWARD)
+ && (prev_pos.lnum < pos->lnum
+ || (prev_pos.lnum == pos->lnum
+ && prev_pos.col <= pos->col))) {
+ if (looped_around) {
+ found_new_match = FAIL;
+ } else {
+ looped_around = true;
+ }
}
+ prev_pos = *pos;
if (found_new_match == FAIL) {
- if (ins_buf == curbuf)
- found_all = TRUE;
+ if (ins_buf == curbuf) {
+ found_all = true;
+ }
break;
}
@@ -4398,13 +4495,13 @@ static int ins_compl_get_exp(pos_T *ini)
IObuff[len] = NUL;
ptr = IObuff;
}
- if (len == compl_length)
+ if (len == compl_length) {
continue;
+ }
}
}
- if (ins_compl_add_infercase(
- ptr, len, p_ic, ins_buf == curbuf ? NULL : ins_buf->b_sfname,
- 0, cont_s_ipos) != NOTDONE) {
+ if (ins_compl_add_infercase(ptr, len, p_ic, ins_buf == curbuf ? NULL : ins_buf->b_sfname,
+ 0, cont_s_ipos) != NOTDONE) {
found_new_match = OK;
break;
}
@@ -4424,8 +4521,9 @@ static int ins_compl_get_exp(pos_T *ini)
if ((l_ctrl_x_mode != CTRL_X_NORMAL
&& !CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode))
|| found_new_match != FAIL) {
- if (got_int)
+ if (got_int) {
break;
+ }
// Fill the popup menu as soon as possible.
if (type != -1) {
ins_compl_check_keys(0, false);
@@ -4517,21 +4615,16 @@ static dict_T *ins_compl_dict_alloc(compl_T *match)
{
// { word, abbr, menu, kind, info }
dict_T *dict = tv_dict_alloc_lock(VAR_FIXED);
- tv_dict_add_str(
- dict, S_LEN("word"),
- (const char *)EMPTY_IF_NULL(match->cp_str));
- tv_dict_add_str(
- dict, S_LEN("abbr"),
- (const char *)EMPTY_IF_NULL(match->cp_text[CPT_ABBR]));
- tv_dict_add_str(
- dict, S_LEN("menu"),
- (const char *)EMPTY_IF_NULL(match->cp_text[CPT_MENU]));
- tv_dict_add_str(
- dict, S_LEN("kind"),
- (const char *)EMPTY_IF_NULL(match->cp_text[CPT_KIND]));
- tv_dict_add_str(
- dict, S_LEN("info"),
- (const char *)EMPTY_IF_NULL(match->cp_text[CPT_INFO]));
+ tv_dict_add_str(dict, S_LEN("word"),
+ (const char *)EMPTY_IF_NULL(match->cp_str));
+ tv_dict_add_str(dict, S_LEN("abbr"),
+ (const char *)EMPTY_IF_NULL(match->cp_text[CPT_ABBR]));
+ tv_dict_add_str(dict, S_LEN("menu"),
+ (const char *)EMPTY_IF_NULL(match->cp_text[CPT_MENU]));
+ tv_dict_add_str(dict, S_LEN("kind"),
+ (const char *)EMPTY_IF_NULL(match->cp_text[CPT_KIND]));
+ tv_dict_add_str(dict, S_LEN("info"),
+ (const char *)EMPTY_IF_NULL(match->cp_text[CPT_INFO]));
if (match->cp_user_data.v_type == VAR_UNKNOWN) {
tv_dict_add_str(dict, S_LEN("user_data"), "");
} else {
@@ -4540,30 +4633,25 @@ static dict_T *ins_compl_dict_alloc(compl_T *match)
return dict;
}
-/*
- * Fill in the next completion in the current direction.
- * If "allow_get_expansion" is TRUE, then we may call ins_compl_get_exp() to
- * get more completions. If it is FALSE, then we just do nothing when there
- * are no more completions in a given direction. The latter case is used when
- * we are still in the middle of finding completions, to allow browsing
- * through the ones found so far.
- * Return the total number of matches, or -1 if still unknown -- webb.
- *
- * compl_curr_match is currently being used by ins_compl_get_exp(), so we use
- * compl_shown_match here.
- *
- * Note that this function may be called recursively once only. First with
- * "allow_get_expansion" TRUE, which calls ins_compl_get_exp(), which in turn
- * calls this function with "allow_get_expansion" FALSE.
- */
-static int
-ins_compl_next (
- int allow_get_expansion,
- int count, // Repeat completion this many times; should
- // be at least 1
- int insert_match, // Insert the newly selected match
- int in_compl_func // Called from complete_check()
-)
+/// Fill in the next completion in the current direction.
+/// If "allow_get_expansion" is TRUE, then we may call ins_compl_get_exp() to
+/// get more completions. If it is FALSE, then we just do nothing when there
+/// are no more completions in a given direction. The latter case is used when
+/// we are still in the middle of finding completions, to allow browsing
+/// through the ones found so far.
+/// @return the total number of matches, or -1 if still unknown -- webb.
+///
+/// compl_curr_match is currently being used by ins_compl_get_exp(), so we use
+/// compl_shown_match here.
+///
+/// Note that this function may be called recursively once only. First with
+/// "allow_get_expansion" TRUE, which calls ins_compl_get_exp(), which in turn
+/// calls this function with "allow_get_expansion" FALSE.
+///
+/// @param count Repeat completion this many times; should be at least 1
+/// @param insert_match Insert the newly selected match
+/// @param in_compl_func Called from complete_check()
+static int ins_compl_next(int allow_get_expansion, int count, int insert_match, int in_compl_func)
{
int num_matches = -1;
int todo = count;
@@ -4573,8 +4661,9 @@ ins_compl_next (
/* When user complete function return -1 for findstart which is next
* time of 'always', compl_shown_match become NULL. */
- if (compl_shown_match == NULL)
+ if (compl_shown_match == NULL) {
return -1;
+ }
if (compl_leader != NULL
&& (compl_shown_match->cp_flags & CP_ORIGINAL_TEXT) == 0) {
@@ -4591,21 +4680,23 @@ ins_compl_next (
* backward, find the last match. */
if (compl_shows_dir == BACKWARD
&& !ins_compl_equal(compl_shown_match,
- compl_leader, (int)STRLEN(compl_leader))
+ compl_leader, (int)STRLEN(compl_leader))
&& (compl_shown_match->cp_next == NULL
|| compl_shown_match->cp_next == compl_first_match)) {
while (!ins_compl_equal(compl_shown_match,
- compl_leader, (int)STRLEN(compl_leader))
+ compl_leader, (int)STRLEN(compl_leader))
&& compl_shown_match->cp_prev != NULL
- && compl_shown_match->cp_prev != compl_first_match)
+ && compl_shown_match->cp_prev != compl_first_match) {
compl_shown_match = compl_shown_match->cp_prev;
+ }
}
}
if (allow_get_expansion && insert_match
- && (!(compl_get_longest || compl_restarting) || compl_used_match))
+ && (!(compl_get_longest || compl_restarting) || compl_used_match)) {
// Delete old text to be replaced
ins_compl_delete();
+ }
// When finding the longest common text we stick at the original text,
// don't let CTRL-N or CTRL-P move to the first match.
@@ -4633,19 +4724,21 @@ ins_compl_next (
} else {
if (!allow_get_expansion) {
if (advance) {
- if (compl_shows_dir == BACKWARD)
+ if (compl_shows_dir == BACKWARD) {
compl_pending -= todo + 1;
- else
+ } else {
compl_pending += todo + 1;
+ }
}
return -1;
}
if (!compl_no_select && advance) {
- if (compl_shows_dir == BACKWARD)
+ if (compl_shows_dir == BACKWARD) {
--compl_pending;
- else
+ } else {
++compl_pending;
+ }
}
// Find matches.
@@ -4661,8 +4754,9 @@ ins_compl_next (
if (compl_pending < 0 && compl_shown_match->cp_prev != NULL) {
compl_shown_match = compl_shown_match->cp_prev;
++compl_pending;
- } else
+ } else {
break;
+ }
}
found_end = false;
}
@@ -4727,8 +4821,8 @@ ins_compl_next (
if (compl_shown_match->cp_fname != NULL) {
char *lead = _("match in file");
int space = sc_col - vim_strsize((char_u *)lead) - 2;
- char_u *s;
- char_u *e;
+ char_u *s;
+ char_u *e;
if (space > 0) {
// We need the tail that fits. With double-byte encoding going
@@ -4796,7 +4890,7 @@ void ins_compl_check_keys(int frequency, int in_compl_func)
c = safe_vgetc(); // Eat the character
compl_shows_dir = ins_compl_key2dir(c);
(void)ins_compl_next(false, ins_compl_key2count(c),
- c != K_UP && c != K_DOWN, in_compl_func);
+ c != K_UP && c != K_DOWN, in_compl_func);
} else {
/* Need to get the character to have KeyTyped set. We'll put it
* back with vungetc() below. But skip K_IGNORE. */
@@ -4804,8 +4898,9 @@ void ins_compl_check_keys(int frequency, int in_compl_func)
if (c != K_IGNORE) {
/* Don't interrupt completion when the character wasn't typed,
* e.g., when doing @q to replay keys. */
- if (c != Ctrl_R && KeyTyped)
+ if (c != Ctrl_R && KeyTyped) {
compl_interrupted = TRUE;
+ }
vungetc(c);
}
@@ -4901,7 +4996,7 @@ static bool ins_compl_use_match(int c)
*/
static int ins_complete(int c, bool enable_pum)
{
- char_u *line;
+ char_u *line;
int startcol = 0; // column where searched text starts
colnr_T curs_col; // cursor column
int n;
@@ -4960,9 +5055,8 @@ static int ins_complete(int c, bool enable_pum)
* mode but first we need to redefine compl_startpos */
if (compl_cont_status & CONT_S_IPOS) {
compl_cont_status |= CONT_SOL;
- compl_startpos.col = (colnr_T)(skipwhite(
- line + compl_length
- + compl_startpos.col) - line);
+ compl_startpos.col = (colnr_T)(skipwhite(line + compl_length
+ + compl_startpos.col) - line);
}
compl_col = compl_startpos.col;
}
@@ -4976,14 +5070,17 @@ static int ins_complete(int c, bool enable_pum)
compl_col = curwin->w_cursor.col - compl_length;
}
compl_cont_status |= CONT_ADDING | CONT_N_ADDS;
- if (compl_length < 1)
+ if (compl_length < 1) {
compl_cont_status &= CONT_LOCAL;
+ }
} else if (CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode)) {
compl_cont_status = CONT_ADDING | CONT_N_ADDS;
- } else
+ } else {
compl_cont_status = 0;
- } else
+ }
+ } else {
compl_cont_status &= CONT_LOCAL;
+ }
if (!(compl_cont_status & CONT_ADDING)) { // normal expansion
compl_cont_mode = ctrl_x_mode;
@@ -5002,27 +5099,30 @@ static int ins_complete(int c, bool enable_pum)
if ((compl_cont_status & CONT_SOL)
|| ctrl_x_mode == CTRL_X_PATH_DEFINES) {
if (!(compl_cont_status & CONT_ADDING)) {
- while (--startcol >= 0 && vim_isIDc(line[startcol]))
+ while (--startcol >= 0 && vim_isIDc(line[startcol])) {
;
+ }
compl_col += ++startcol;
compl_length = curs_col - startcol;
}
- if (p_ic)
+ if (p_ic) {
compl_pattern = str_foldcase(line + compl_col, compl_length, NULL, 0);
- else
+ } else {
compl_pattern = vim_strnsave(line + compl_col, compl_length);
+ }
} else if (compl_cont_status & CONT_ADDING) {
- char_u *prefix = (char_u *)"\\<";
+ char_u *prefix = (char_u *)"\\<";
// we need up to 2 extra chars for the prefix
compl_pattern = xmalloc(quote_meta(NULL, line + compl_col,
- compl_length) + 2);
+ compl_length) + 2);
if (!vim_iswordp(line + compl_col)
|| (compl_col > 0
&& (
- vim_iswordp(mb_prevptr(line, line + compl_col))
- )))
+ vim_iswordp(mb_prevptr(line, line + compl_col))
+ ))) {
prefix = (char_u *)"";
+ }
STRCPY((char *)compl_pattern, prefix);
(void)quote_meta(compl_pattern + STRLEN(prefix),
line + compl_col, compl_length);
@@ -5057,10 +5157,10 @@ static int ins_complete(int c, bool enable_pum)
STRCAT((char *)compl_pattern, "\\k");
} else {
compl_pattern = xmalloc(quote_meta(NULL, line + compl_col,
- compl_length) + 2);
+ compl_length) + 2);
STRCPY((char *)compl_pattern, "\\<");
(void)quote_meta(compl_pattern + 2, line + compl_col,
- compl_length);
+ compl_length);
}
}
} else if (CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode)) {
@@ -5077,7 +5177,7 @@ static int ins_complete(int c, bool enable_pum)
} else if (ctrl_x_mode == CTRL_X_FILES) {
// Go back to just before the first filename character.
if (startcol > 0) {
- char_u *p = line + startcol;
+ char_u *p = line + startcol;
MB_PTR_BACK(line, p);
while (p > line && vim_isfilec(PTR2CHAR(p))) {
@@ -5093,7 +5193,7 @@ static int ins_complete(int c, bool enable_pum)
compl_col += startcol;
compl_length = (int)curs_col - startcol;
compl_pattern = addstar(line + compl_col, compl_length, EXPAND_FILES);
- } else if (ctrl_x_mode == CTRL_X_CMDLINE) {
+ } else if (ctrl_x_mode == CTRL_X_CMDLINE || ctrl_x_mode == CTRL_X_CMDLINE_CTRL_X) {
compl_pattern = vim_strnsave(line, curs_col);
set_cmd_context(&compl_xp, compl_pattern,
(int)STRLEN(compl_pattern), curs_col, false);
@@ -5112,10 +5212,10 @@ static int ins_complete(int c, bool enable_pum)
* Call user defined function 'completefunc' with "a:findstart"
* set to 1 to obtain the length of text to use for completion.
*/
- char_u *funcname;
+ char_u *funcname;
pos_T pos;
- win_T *curwin_save;
- buf_T *curbuf_save;
+ win_T *curwin_save;
+ buf_T *curbuf_save;
const int save_State = State;
/* Call 'completefunc' or 'omnifunc' and get pattern length as a
@@ -5157,8 +5257,9 @@ static int ins_complete(int c, bool enable_pum)
/* Return value -2 means the user complete function wants to
* cancel the complete without an error.
* Return value -3 does the same as -2 and leaves CTRL-X mode.*/
- if (col == -2)
+ if (col == -2) {
return FAIL;
+ }
if (col == -3) {
ctrl_x_mode = CTRL_X_NORMAL;
edit_submode = NULL;
@@ -5168,17 +5269,17 @@ static int ins_complete(int c, bool enable_pum)
return FAIL;
}
- /*
- * Reset extended parameters of completion, when start new
- * completion.
- */
- compl_opt_refresh_always = FALSE;
+ // Reset extended parameters of completion, when start new
+ // completion.
+ compl_opt_refresh_always = false;
- if (col < 0)
+ if (col < 0) {
col = curs_col;
+ }
compl_col = col;
- if (compl_col > curs_col)
+ if (compl_col > curs_col) {
compl_col = curs_col;
+ }
/* Setup variables for completion. Need to obtain "line" again,
* it may have become invalid. */
@@ -5189,9 +5290,9 @@ static int ins_complete(int c, bool enable_pum)
if (spell_bad_len > 0) {
assert(spell_bad_len <= INT_MAX);
compl_col = curs_col - (int)spell_bad_len;
- }
- else
+ } else {
compl_col = spell_word_start(startcol);
+ }
if (compl_col >= (colnr_T)startcol) {
compl_length = 0;
compl_col = curs_col;
@@ -5226,10 +5327,11 @@ static int ins_complete(int c, bool enable_pum)
compl_startpos.col = compl_col;
}
- if (compl_cont_status & CONT_LOCAL)
+ if (compl_cont_status & CONT_LOCAL) {
edit_submode = (char_u *)_(ctrl_x_msgs[CTRL_X_LOCAL_MSG]);
- else
+ } else {
edit_submode = (char_u *)_(CTRL_X_MSG(ctrl_x_mode));
+ }
/* If any of the original typed text has been changed we need to fix
* the redo buffer. */
@@ -5334,14 +5436,15 @@ static int ins_complete(int c, bool enable_pum)
* Translations may need more than twice that. */
static char_u match_ref[81];
- if (compl_matches > 0)
+ if (compl_matches > 0) {
vim_snprintf((char *)match_ref, sizeof(match_ref),
- _("match %d of %d"),
- compl_curr_match->cp_number, compl_matches);
- else
+ _("match %d of %d"),
+ compl_curr_match->cp_number, compl_matches);
+ } else {
vim_snprintf((char *)match_ref, sizeof(match_ref),
- _("match %d"),
- compl_curr_match->cp_number);
+ _("match %d"),
+ compl_curr_match->cp_number);
+ }
edit_submode_extra = match_ref;
edit_submode_highl = HLF_R;
if (dollar_vcol >= 0) {
@@ -5393,8 +5496,9 @@ static unsigned quote_meta(char_u *dest, char_u *src, int len)
case '*':
case '[':
if (ctrl_x_mode == CTRL_X_DICTIONARY
- || ctrl_x_mode == CTRL_X_THESAURUS)
+ || ctrl_x_mode == CTRL_X_THESAURUS) {
break;
+ }
FALLTHROUGH;
case '~':
if (!p_magic) { // quote these only if magic is set
@@ -5403,8 +5507,9 @@ static unsigned quote_meta(char_u *dest, char_u *src, int len)
FALLTHROUGH;
case '\\':
if (ctrl_x_mode == CTRL_X_DICTIONARY
- || ctrl_x_mode == CTRL_X_THESAURUS)
+ || ctrl_x_mode == CTRL_X_THESAURUS) {
break;
+ }
FALLTHROUGH;
case '^': // currently it's not needed.
case '$':
@@ -5429,8 +5534,9 @@ static unsigned quote_meta(char_u *dest, char_u *src, int len)
}
}
}
- if (dest != NULL)
+ if (dest != NULL) {
*dest = NUL;
+ }
return m;
}
@@ -5446,12 +5552,13 @@ int get_literal(void)
int cc;
int nc;
int i;
- int hex = FALSE;
- int octal = FALSE;
+ bool hex = false;
+ bool octal = false;
int unicode = 0;
- if (got_int)
+ if (got_int) {
return Ctrl_C;
+ }
no_mapping++; // don't map the next key hits
cc = 0;
@@ -5459,29 +5566,31 @@ int get_literal(void)
for (;; ) {
nc = plain_vgetc();
if (!(State & CMDLINE)
- && MB_BYTE2LEN_CHECK(nc) == 1
- )
+ && MB_BYTE2LEN_CHECK(nc) == 1) {
add_to_showcmd(nc);
- if (nc == 'x' || nc == 'X')
- hex = TRUE;
- else if (nc == 'o' || nc == 'O')
- octal = TRUE;
- else if (nc == 'u' || nc == 'U')
+ }
+ if (nc == 'x' || nc == 'X') {
+ hex = true;
+ } else if (nc == 'o' || nc == 'O') {
+ octal = true;
+ } else if (nc == 'u' || nc == 'U') {
unicode = nc;
- else {
+ } else {
if (hex
- || unicode != 0
- ) {
- if (!ascii_isxdigit(nc))
+ || unicode != 0) {
+ if (!ascii_isxdigit(nc)) {
break;
+ }
cc = cc * 16 + hex2nr(nc);
} else if (octal) {
- if (nc < '0' || nc > '7')
+ if (nc < '0' || nc > '7') {
break;
+ }
cc = cc * 8 + nc - '0';
} else {
- if (!ascii_isdigit(nc))
+ if (!ascii_isdigit(nc)) {
break;
+ }
cc = cc * 10 + nc - '0';
}
@@ -5489,9 +5598,9 @@ int get_literal(void)
}
if (cc > 255
- && unicode == 0
- )
+ && unicode == 0) {
cc = 255; // limit range to 0-255
+ }
nc = 0;
if (hex) { // hex: up to two chars
@@ -5521,8 +5630,9 @@ int get_literal(void)
}
--no_mapping;
- if (nc)
+ if (nc) {
vungetc(nc);
+ }
got_int = false; // CTRL-C typed after CTRL-V is not an interrupt
return cc;
}
@@ -5532,7 +5642,7 @@ int get_literal(void)
/// @param ctrlv `c` was typed after CTRL-V
static void insert_special(int c, int allow_modmask, int ctrlv)
{
- char_u *p;
+ char_u *p;
int len;
// Special function key, translate into "<Key>". Up to the last '>' is
@@ -5548,16 +5658,18 @@ static void insert_special(int c, int allow_modmask, int ctrlv)
len = (int)STRLEN(p);
c = p[len - 1];
if (len > 2) {
- if (stop_arrow() == FAIL)
+ if (stop_arrow() == FAIL) {
return;
+ }
p[len - 1] = NUL;
ins_str(p);
AppendToRedobuffLit(p, -1);
ctrlv = FALSE;
}
}
- if (stop_arrow() == OK)
+ if (stop_arrow() == OK) {
insertchar(c, ctrlv ? INSCHAR_CTRLV : 0, -1);
+ }
}
/*
@@ -5569,29 +5681,28 @@ static void insert_special(int c, int allow_modmask, int ctrlv)
* stop and defer processing to the "normal" mechanism.
* '0' and '^' are special, because they can be followed by CTRL-D.
*/
-# define ISSPECIAL(c) ((c) < ' ' || (c) >= DEL || (c) == '0' || (c) == '^')
+#define ISSPECIAL(c) ((c) < ' ' || (c) >= DEL || (c) == '0' || (c) == '^')
#define WHITECHAR(cc) ( \
- ascii_iswhite(cc) \
- && !utf_iscomposing(utf_ptr2char(get_cursor_pos_ptr() + 1)))
+ ascii_iswhite(cc) \
+ && !utf_iscomposing(utf_ptr2char(get_cursor_pos_ptr() + 1)))
-/*
- * "flags": INSCHAR_FORMAT - force formatting
- * INSCHAR_CTRLV - char typed just after CTRL-V
- * INSCHAR_NO_FEX - don't use 'formatexpr'
- *
- * NOTE: passes the flags value straight through to internal_format() which,
- * beside INSCHAR_FORMAT (above), is also looking for these:
- * INSCHAR_DO_COM - format comments
- * INSCHAR_COM_LIST - format comments with num list or 2nd line indent
- */
-void insertchar(
- int c, // character to insert or NUL
- int flags, // INSCHAR_FORMAT, etc.
- int second_indent // indent for second line if >= 0
-)
+///
+/// "flags": INSCHAR_FORMAT - force formatting
+/// INSCHAR_CTRLV - char typed just after CTRL-V
+/// INSCHAR_NO_FEX - don't use 'formatexpr'
+///
+/// NOTE: passes the flags value straight through to internal_format() which,
+/// beside INSCHAR_FORMAT (above), is also looking for these:
+/// INSCHAR_DO_COM - format comments
+/// INSCHAR_COM_LIST - format comments with num list or 2nd line indent
+///
+/// @param c character to insert or NUL
+/// @param flags INSCHAR_FORMAT, etc.
+/// @param second_indent indent for second line if >= 0
+void insertchar(int c, int flags, int second_indent)
{
- char_u *p;
+ char_u *p;
int force_format = flags & INSCHAR_FORMAT;
const int textwidth = comp_textwidth(force_format);
@@ -5603,14 +5714,14 @@ void insertchar(
* - Always do this when 'formatoptions' has the 'a' flag and the line
* ends in white space.
* - Otherwise:
- * - Don't do this if inserting a blank
- * - Don't do this if an existing character is being replaced, unless
- * we're in VREPLACE mode.
- * - Do this if the cursor is not on the line where insert started
- * or - 'formatoptions' doesn't have 'l' or the line was not too long
- * before the insert.
- * - 'formatoptions' doesn't have 'b' or a blank was inserted at or
- * before 'textwidth'
+ * - Don't do this if inserting a blank
+ * - Don't do this if an existing character is being replaced, unless
+ * we're in VREPLACE mode.
+ * - Do this if the cursor is not on the line where insert started
+ * or - 'formatoptions' doesn't have 'l' or the line was not too long
+ * before the insert.
+ * - 'formatoptions' doesn't have 'b' or a blank was inserted at or
+ * before 'textwidth'
*/
if (textwidth > 0
&& (force_format
@@ -5627,7 +5738,7 @@ void insertchar(
// when 'formatexpr' isn't set or it returns non-zero.
bool do_internal = true;
colnr_T virtcol = get_nolist_virtcol()
- + char2cells(c != NUL ? c : gchar_cursor());
+ + char2cells(c != NUL ? c : gchar_cursor());
if (*curbuf->b_p_fex != NUL && (flags & INSCHAR_NO_FEX) == 0
&& (force_format || virtcol > (colnr_T)textwidth)) {
@@ -5636,8 +5747,9 @@ void insertchar(
// was called.
ins_need_undo = true;
}
- if (do_internal)
+ if (do_internal) {
internal_format(textwidth, second_indent, flags, c == NUL, c);
+ }
}
if (c == NUL) { // only formatting was wanted
@@ -5646,7 +5758,7 @@ void insertchar(
// Check whether this character should end a comment.
if (did_ai && c == end_comment_pending) {
- char_u *line;
+ char_u *line;
char_u lead_end[COM_MAX_LEN]; // end-comment string
int middle_len, end_len;
int i;
@@ -5675,8 +5787,9 @@ void insertchar(
// Skip white space before the cursor
i = curwin->w_cursor.col;
- while (--i >= 0 && ascii_iswhite(line[i]))
+ while (--i >= 0 && ascii_iswhite(line[i])) {
;
+ }
i++;
// Skip to before the middle leader
@@ -5753,10 +5866,12 @@ void insertchar(
if (flags & INSCHAR_CTRLV) {
redo_literal(*buf);
i = 1;
- } else
+ } else {
i = 0;
- if (buf[i] != NUL)
+ }
+ if (buf[i] != NUL) {
AppendToRedobuffLit(buf + i, -1);
+ }
} else {
int cc;
@@ -5778,20 +5893,13 @@ void insertchar(
}
}
-/*
- * Format text at the current insert position.
- *
- * If the INSCHAR_COM_LIST flag is present, then the value of second_indent
- * will be the comment leader length sent to open_line().
- */
-static void
-internal_format (
- int textwidth,
- int second_indent,
- int flags,
- int format_only,
- int c // character to be inserted (can be NUL)
-)
+/// Format text at the current insert position.
+///
+/// If the INSCHAR_COM_LIST flag is present, then the value of second_indent
+/// will be the comment leader length sent to open_line().
+///
+/// @param c character to be inserted (can be NUL)
+static void internal_format(int textwidth, int second_indent, int flags, int format_only, int c)
{
int cc;
int save_char = NUL;
@@ -5814,8 +5922,7 @@ internal_format (
* deleted. Replace it with an 'x' temporarily.
*/
if (!curbuf->b_p_ai
- && !(State & VREPLACE_FLAG)
- ) {
+ && !(State & VREPLACE_FLAG)) {
cc = gchar_cursor();
if (ascii_iswhite(cc)) {
save_char = cc;
@@ -5834,14 +5941,15 @@ internal_format (
colnr_T len;
colnr_T virtcol;
int orig_col = 0;
- char_u *saved_text = NULL;
+ char_u *saved_text = NULL;
colnr_T col;
colnr_T end_col;
virtcol = get_nolist_virtcol()
+ char2cells(c != NUL ? c : gchar_cursor());
- if (virtcol <= (colnr_T)textwidth)
+ if (virtcol <= (colnr_T)textwidth) {
break;
+ }
if (no_leader) {
do_comments = false;
@@ -5889,10 +5997,11 @@ internal_format (
|| (flags & INSCHAR_FORMAT)
|| curwin->w_cursor.lnum != Insstart.lnum
|| curwin->w_cursor.col >= Insstart.col) {
- if (curwin->w_cursor.col == startcol && c != NUL)
+ if (curwin->w_cursor.col == startcol && c != NUL) {
cc = c;
- else
+ } else {
cc = gchar_cursor();
+ }
if (WHITECHAR(cc)) {
// remember position of blank just before text
end_col = curwin->w_cursor.col;
@@ -5947,8 +6056,9 @@ internal_format (
end_foundcol = end_col + 1;
foundcol = curwin->w_cursor.col;
- if (curwin->w_cursor.col <= (colnr_T)wantcol)
+ if (curwin->w_cursor.col <= (colnr_T)wantcol) {
break;
+ }
} else if ((cc >= 0x100 || !utf_allow_break_before(cc))
&& fo_multibyte) {
int ncc;
@@ -5969,14 +6079,16 @@ internal_format (
if (curwin->w_cursor.col != skip_pos && allow_break) {
foundcol = curwin->w_cursor.col;
end_foundcol = foundcol;
- if (curwin->w_cursor.col <= (colnr_T)wantcol)
+ if (curwin->w_cursor.col <= (colnr_T)wantcol) {
break;
+ }
}
curwin->w_cursor.col = col;
}
- if (curwin->w_cursor.col == 0)
+ if (curwin->w_cursor.col == 0) {
break;
+ }
ncc = cc;
col = curwin->w_cursor.col;
@@ -6038,8 +6150,9 @@ internal_format (
}
}
}
- if (curwin->w_cursor.col == 0)
+ if (curwin->w_cursor.col == 0) {
break;
+ }
dec_cursor();
}
@@ -6068,11 +6181,13 @@ internal_format (
*/
curwin->w_cursor.col = foundcol;
while ((cc = gchar_cursor(), WHITECHAR(cc))
- && (!fo_white_par || curwin->w_cursor.col < startcol))
+ && (!fo_white_par || curwin->w_cursor.col < startcol)) {
inc_cursor();
+ }
startcol -= curwin->w_cursor.col;
- if (startcol < 0)
+ if (startcol < 0) {
startcol = 0;
+ }
if (State & VREPLACE_FLAG) {
/*
@@ -6099,12 +6214,13 @@ internal_format (
* Only insert/delete lines, but don't really redraw the window.
*/
open_line(FORWARD, OPENLINE_DELSPACES + OPENLINE_MARKFIX
- + (fo_white_par ? OPENLINE_KEEPTRAIL : 0)
- + (do_comments ? OPENLINE_DO_COM : 0)
- + ((flags & INSCHAR_COM_LIST) ? OPENLINE_COM_LIST : 0)
- , ((flags & INSCHAR_COM_LIST) ? second_indent : old_indent));
- if (!(flags & INSCHAR_COM_LIST))
+ + (fo_white_par ? OPENLINE_KEEPTRAIL : 0)
+ + (do_comments ? OPENLINE_DO_COM : 0)
+ + ((flags & INSCHAR_COM_LIST) ? OPENLINE_COM_LIST : 0)
+ , ((flags & INSCHAR_COM_LIST) ? second_indent : old_indent));
+ if (!(flags & INSCHAR_COM_LIST)) {
old_indent = 0;
+ }
replace_offset = 0;
if (first_line) {
@@ -6155,8 +6271,9 @@ internal_format (
*/
curwin->w_cursor.col += startcol;
len = (colnr_T)STRLEN(get_cursor_line_ptr());
- if (curwin->w_cursor.col > len)
+ if (curwin->w_cursor.col > len) {
curwin->w_cursor.col = len;
+ }
}
haveto_redraw = true;
@@ -6181,27 +6298,26 @@ internal_format (
}
}
-/*
- * Called after inserting or deleting text: When 'formatoptions' includes the
- * 'a' flag format from the current line until the end of the paragraph.
- * Keep the cursor at the same position relative to the text.
- * The caller must have saved the cursor line for undo, following ones will be
- * saved here.
- */
-void auto_format(
- bool trailblank, // when true also format with trailing blank
- bool prev_line // may start in previous line
-)
+/// Called after inserting or deleting text: When 'formatoptions' includes the
+/// 'a' flag format from the current line until the end of the paragraph.
+/// Keep the cursor at the same position relative to the text.
+/// The caller must have saved the cursor line for undo, following ones will be
+/// saved here.
+///
+/// @param trailblank when true also format with trailing blank
+/// @param prev_line may start in previous line
+void auto_format(bool trailblank, bool prev_line)
{
pos_T pos;
colnr_T len;
- char_u *old;
- char_u *new, *pnew;
+ char_u *old;
+ char_u *new, *pnew;
int wasatend;
int cc;
- if (!has_format_option(FO_AUTO))
+ if (!has_format_option(FO_AUTO)) {
return;
+ }
pos = curwin->w_cursor;
old = get_cursor_line_ptr();
@@ -6219,8 +6335,9 @@ void auto_format(
dec_cursor();
cc = gchar_cursor();
if (!WHITECHAR(cc) && curwin->w_cursor.col > 0
- && has_format_option(FO_ONE_LETTER))
+ && has_format_option(FO_ONE_LETTER)) {
dec_cursor();
+ }
cc = gchar_cursor();
if (WHITECHAR(cc)) {
curwin->w_cursor = pos;
@@ -6232,8 +6349,9 @@ void auto_format(
/* With the 'c' flag in 'formatoptions' and 't' missing: only format
* comments. */
if (has_format_option(FO_WRAP_COMS) && !has_format_option(FO_WRAP)
- && get_leader_len(old, NULL, FALSE, TRUE) == 0)
+ && get_leader_len(old, NULL, false, true) == 0) {
return;
+ }
/*
* May start formatting in a previous line, so that after "x" a word is
@@ -6242,8 +6360,9 @@ void auto_format(
*/
if (prev_line && !paragraph_start(curwin->w_cursor.lnum)) {
--curwin->w_cursor.lnum;
- if (u_save_cursor() == FAIL)
+ if (u_save_cursor() == FAIL) {
return;
+ }
}
/*
@@ -6286,14 +6405,12 @@ void auto_format(
check_cursor();
}
-/*
- * When an extra space was added to continue a paragraph for auto-formatting,
- * delete it now. The space must be under the cursor, just after the insert
- * position.
- */
-static void check_auto_format(
- bool end_insert // true when ending Insert mode
-)
+/// When an extra space was added to continue a paragraph for auto-formatting,
+/// delete it now. The space must be under the cursor, just after the insert
+/// position.
+///
+/// @param end_insert true when ending Insert mode
+static void check_auto_format(bool end_insert)
{
int c = ' ';
int cc;
@@ -6318,16 +6435,14 @@ static void check_auto_format(
}
}
-/*
- * Find out textwidth to be used for formatting:
- * if 'textwidth' option is set, use it
- * else if 'wrapmargin' option is set, use curwin->w_width_inner-'wrapmargin'
- * if invalid value, use 0.
- * Set default to window width (maximum 79) for "gq" operator.
- */
-int comp_textwidth(
- bool ff // force formatting (for "gq" command)
-)
+/// Find out textwidth to be used for formatting:
+/// if 'textwidth' option is set, use it
+/// else if 'wrapmargin' option is set, use curwin->w_width_inner-'wrapmargin'
+/// if invalid value, use 0.
+/// Set default to window width (maximum 79) for "gq" operator.
+///
+/// @param ff force formatting (for "gq" command)
+int comp_textwidth(bool ff)
{
int textwidth = curbuf->b_p_tw;
if (textwidth == 0 && curbuf->b_p_wm) {
@@ -6340,11 +6455,13 @@ int comp_textwidth(
textwidth -= win_fdccol_count(curwin);
textwidth -= win_signcol_count(curwin);
- if (curwin->w_p_nu || curwin->w_p_rnu)
+ if (curwin->w_p_nu || curwin->w_p_rnu) {
textwidth -= 8;
+ }
}
- if (textwidth < 0)
+ if (textwidth < 0) {
textwidth = 0;
+ }
if (ff && textwidth == 0) {
textwidth = curwin->w_width_inner - 1;
if (textwidth > 79) {
@@ -6371,17 +6488,18 @@ static void redo_literal(int c)
}
}
-// start_arrow() is called when an arrow key is used in insert mode.
-// For undo/redo it resembles hitting the <ESC> key.
-static void start_arrow(
- pos_T *end_insert_pos // can be NULL
-)
+/// start_arrow() is called when an arrow key is used in insert mode.
+/// For undo/redo it resembles hitting the <ESC> key.
+///
+/// @param end_insert_pos can be NULL
+static void start_arrow(pos_T *end_insert_pos)
{
start_arrow_common(end_insert_pos, true);
}
/// Like start_arrow() but with end_change argument.
-/// Will prepare for redo of CTRL-G U if "end_change" is FALSE.
+/// Will prepare for redo of CTRL-G U if "end_change" is false.
+///
/// @param end_insert_pos can be NULL
/// @param end_change end undoable change
static void start_arrow_with_change(pos_T *end_insert_pos, bool end_change)
@@ -6426,9 +6544,10 @@ static void check_spell_redraw(void)
static void spell_back_to_badword(void)
{
pos_T tpos = curwin->w_cursor;
- spell_bad_len = spell_move_to(curwin, BACKWARD, TRUE, TRUE, NULL);
- if (curwin->w_cursor.col != tpos.col)
+ spell_bad_len = spell_move_to(curwin, BACKWARD, true, true, NULL);
+ if (curwin->w_cursor.col != tpos.col) {
start_arrow(&tpos);
+ }
}
/*
@@ -6443,7 +6562,7 @@ int stop_arrow(void)
if (Insstart.col > Insstart_orig.col && !ins_need_undo) {
// Don't update the original insert position when moved to the
// right, except when nothing was inserted yet.
- update_Insstart_orig = FALSE;
+ update_Insstart_orig = false;
}
Insstart_textlen = (colnr_T)linetabsize(get_cursor_line_ptr());
@@ -6471,20 +6590,16 @@ int stop_arrow(void)
return arrow_used || ins_need_undo ? FAIL : OK;
}
-/*
- * Do a few things to stop inserting.
- * "end_insert_pos" is where insert ended. It is NULL when we already jumped
- * to another window/buffer.
- */
-static void
-stop_insert (
- pos_T *end_insert_pos,
- int esc, // called by ins_esc()
- int nomove // <c-\><c-o>, don't move cursor
-)
+/// Do a few things to stop inserting.
+/// "end_insert_pos" is where insert ended. It is NULL when we already jumped
+/// to another window/buffer.
+///
+/// @param esc called by ins_esc()
+/// @param nomove <c-\><c-o>, don't move cursor
+static void stop_insert(pos_T *end_insert_pos, int esc, int nomove)
{
int cc;
- char_u *ptr;
+ char_u *ptr;
stop_redo_ins();
replace_flush(); // abandon replace stack
@@ -6500,8 +6615,9 @@ stop_insert (
xfree(last_insert);
last_insert = ptr;
last_insert_skip = new_insert_skip;
- } else
+ } else {
xfree(ptr);
+ }
if (!arrow_used && end_insert_pos != NULL) {
// Auto-format now. It may seem strange to do this when stopping an
@@ -6518,21 +6634,24 @@ stop_insert (
if (curwin->w_cursor.col > 0 && gchar_cursor() == NUL) {
dec_cursor();
cc = gchar_cursor();
- if (!ascii_iswhite(cc))
+ if (!ascii_iswhite(cc)) {
curwin->w_cursor = tpos;
+ }
}
auto_format(true, false);
if (ascii_iswhite(cc)) {
- if (gchar_cursor() != NUL)
+ if (gchar_cursor() != NUL) {
inc_cursor();
+ }
/* If the cursor is still at the same character, also keep
* the "coladd". */
if (gchar_cursor() == NUL
&& curwin->w_cursor.lnum == tpos.lnum
- && curwin->w_cursor.col == tpos.col)
+ && curwin->w_cursor.col == tpos.col) {
curwin->w_cursor.coladd = tpos.coladd;
+ }
}
}
@@ -6553,8 +6672,9 @@ stop_insert (
curwin->w_cursor = *end_insert_pos;
check_cursor_col(); // make sure it is not past the line
for (;; ) {
- if (gchar_cursor() == NUL && curwin->w_cursor.col > 0)
+ if (gchar_cursor() == NUL && curwin->w_cursor.col > 0) {
--curwin->w_cursor.col;
+ }
cc = gchar_cursor();
if (!ascii_iswhite(cc)) {
break;
@@ -6606,7 +6726,7 @@ stop_insert (
*/
void set_last_insert(int c)
{
- char_u *s;
+ char_u *s;
xfree(last_insert);
last_insert = xmalloc(MB_MAXBYTES * 3 + 5);
@@ -6660,25 +6780,26 @@ char_u *add_char2buf(int c, char_u *s)
/*
* move cursor to start of line
- * if flags & BL_WHITE move to first non-white
- * if flags & BL_SOL move to first non-white if startofline is set,
- * otherwise keep "curswant" column
- * if flags & BL_FIX don't leave the cursor on a NUL.
+ * if flags & BL_WHITE move to first non-white
+ * if flags & BL_SOL move to first non-white if startofline is set,
+ * otherwise keep "curswant" column
+ * if flags & BL_FIX don't leave the cursor on a NUL.
*/
void beginline(int flags)
{
- if ((flags & BL_SOL) && !p_sol)
+ if ((flags & BL_SOL) && !p_sol) {
coladvance(curwin->w_curswant);
- else {
+ } else {
curwin->w_cursor.col = 0;
curwin->w_cursor.coladd = 0;
if (flags & (BL_WHITE | BL_SOL)) {
- char_u *ptr;
+ char_u *ptr;
for (ptr = get_cursor_line_ptr(); ascii_iswhite(*ptr)
- && !((flags & BL_FIX) && ptr[1] == NUL); ++ptr)
+ && !((flags & BL_FIX) && ptr[1] == NUL); ++ptr) {
++curwin->w_cursor.col;
+ }
}
curwin->w_set_curswant = TRUE;
}
@@ -6694,7 +6815,7 @@ void beginline(int flags)
int oneright(void)
{
- char_u *ptr;
+ char_u *ptr;
int l;
if (virtual_active()) {
@@ -6735,8 +6856,9 @@ int oneleft(void)
int width;
int v = getviscol();
- if (v == 0)
+ if (v == 0) {
return FAIL;
+ }
// We might get stuck on 'showbreak', skip over it.
width = 1;
@@ -6766,8 +6888,9 @@ int oneleft(void)
return OK;
}
- if (curwin->w_cursor.col == 0)
+ if (curwin->w_cursor.col == 0) {
return FAIL;
+ }
curwin->w_set_curswant = TRUE;
--curwin->w_cursor.col;
@@ -6778,11 +6901,8 @@ int oneleft(void)
return OK;
}
-int
-cursor_up (
- long n,
- int upd_topline // When TRUE: update topline
-)
+/// @oaram upd_topline When TRUE: update topline
+int cursor_up(long n, int upd_topline)
{
linenr_T lnum;
@@ -6793,9 +6913,9 @@ cursor_up (
if (lnum <= 1) {
return FAIL;
}
- if (n >= lnum)
+ if (n >= lnum) {
lnum = 1;
- else if (hasAnyFolding(curwin)) {
+ } else if (hasAnyFolding(curwin)) {
/*
* Count each sequence of folded lines as one logical line.
*/
@@ -6815,10 +6935,12 @@ cursor_up (
(void)hasFolding(lnum, &lnum, NULL);
}
}
- if (lnum < 1)
+ if (lnum < 1) {
lnum = 1;
- } else
+ }
+ } else {
lnum -= n;
+ }
curwin->w_cursor.lnum = lnum;
}
@@ -6832,14 +6954,10 @@ cursor_up (
return OK;
}
-/*
- * Cursor down a number of logical lines.
- */
-int
-cursor_down (
- long n,
- int upd_topline // When TRUE: update topline
-)
+/// Cursor down a number of logical lines.
+///
+/// @param upd_topline When TRUE: update topline
+int cursor_down(long n, int upd_topline)
{
linenr_T lnum;
@@ -6852,24 +6970,28 @@ cursor_down (
if (lnum >= curbuf->b_ml.ml_line_count) {
return FAIL;
}
- if (lnum + n >= curbuf->b_ml.ml_line_count)
+ if (lnum + n >= curbuf->b_ml.ml_line_count) {
lnum = curbuf->b_ml.ml_line_count;
- else if (hasAnyFolding(curwin)) {
+ } else if (hasAnyFolding(curwin)) {
linenr_T last;
// count each sequence of folded lines as one logical line
while (n--) {
- if (hasFolding(lnum, NULL, &last))
+ if (hasFolding(lnum, NULL, &last)) {
lnum = last + 1;
- else
+ } else {
++lnum;
- if (lnum >= curbuf->b_ml.ml_line_count)
+ }
+ if (lnum >= curbuf->b_ml.ml_line_count) {
break;
+ }
}
- if (lnum > curbuf->b_ml.ml_line_count)
+ if (lnum > curbuf->b_ml.ml_line_count) {
lnum = curbuf->b_ml.ml_line_count;
- } else
+ }
+ } else {
lnum += n;
+ }
curwin->w_cursor.lnum = lnum;
}
@@ -6883,20 +7005,18 @@ cursor_down (
return OK;
}
-/*
- * Stuff the last inserted text in the read buffer.
- * Last_insert actually is a copy of the redo buffer, so we
- * first have to remove the command.
- */
-int stuff_inserted(
- int c, // Command character to be inserted
- long count, // Repeat this many times
- int no_esc // Don't add an ESC at the end
-)
-{
- char_u *esc_ptr;
- char_u *ptr;
- char_u *last_ptr;
+/// Stuff the last inserted text in the read buffer.
+/// Last_insert actually is a copy of the redo buffer, so we
+/// first have to remove the command.
+///
+/// @param c Command character to be inserted
+/// @param count Repeat this many times
+/// @param no_esc Don't add an ESC at the end
+int stuff_inserted(int c, long count, int no_esc)
+{
+ char_u *esc_ptr;
+ char_u *ptr;
+ char_u *last_ptr;
char_u last = NUL;
ptr = get_last_insert();
@@ -6934,8 +7054,9 @@ int stuff_inserted(
}
} while (--count > 0);
- if (last)
+ if (last) {
*last_ptr = last;
+ }
if (esc_ptr != NULL) {
*esc_ptr = ESC; // put the ESC back
@@ -6951,8 +7072,9 @@ int stuff_inserted(
char_u *get_last_insert(void)
{
- if (last_insert == NULL)
+ if (last_insert == NULL) {
return NULL;
+ }
return last_insert + last_insert_skip;
}
@@ -6962,11 +7084,12 @@ char_u *get_last_insert(void)
*/
char_u *get_last_insert_save(void)
{
- char_u *s;
+ char_u *s;
int len;
- if (last_insert == NULL)
+ if (last_insert == NULL) {
return NULL;
+ }
s = vim_strsave(last_insert + last_insert_skip);
len = (int)STRLEN(s);
if (len > 0 && s[len - 1] == ESC) { // remove trailing ESC
@@ -6994,7 +7117,7 @@ static bool echeck_abbr(int c)
}
return check_abbr(c, get_cursor_line_ptr(), curwin->w_cursor.col,
- curwin->w_cursor.lnum == Insstart.lnum ? Insstart.col : 0);
+ curwin->w_cursor.lnum == Insstart.lnum ? Insstart.col : 0);
}
/*
@@ -7012,7 +7135,7 @@ static bool echeck_abbr(int c)
* that were deleted (always white space).
*/
-static char_u *replace_stack = NULL;
+static char_u *replace_stack = NULL;
static ssize_t replace_stack_nr = 0; // next entry in replace stack
static ssize_t replace_stack_len = 0; // max. number of entries
@@ -7051,8 +7174,9 @@ int replace_push_mb(char_u *p)
int l = (*mb_ptr2len)(p);
int j;
- for (j = l - 1; j >= 0; --j)
+ for (j = l - 1; j >= 0; --j) {
replace_push(p[j]);
+ }
return l;
}
@@ -7064,23 +7188,22 @@ static int replace_pop(void)
return (replace_stack_nr == 0) ? -1 : (int)replace_stack[--replace_stack_nr];
}
-/*
- * Join the top two items on the replace stack. This removes to "off"'th NUL
- * encountered.
- */
-static void replace_join(
- int off // offset for which NUL to remove
-)
+/// Join the top two items on the replace stack. This removes to "off"'th NUL
+/// encountered.
+///
+/// @param off offset for which NUL to remove
+static void replace_join(int off)
{
int i;
- for (i = replace_stack_nr; --i >= 0; )
+ for (i = replace_stack_nr; --i >= 0; ) {
if (replace_stack[i] == NUL && off-- <= 0) {
--replace_stack_nr;
memmove(replace_stack + i, replace_stack + i + 1,
- (size_t)(replace_stack_nr - i));
+ (size_t)(replace_stack_nr - i));
return;
}
+ }
}
/*
@@ -7113,8 +7236,9 @@ static void mb_replace_pop_ins(int cc)
if ((n = MB_BYTE2LEN(cc)) > 1) {
buf[0] = cc;
- for (i = 1; i < n; ++i)
+ for (i = 1; i < n; ++i) {
buf[i] = replace_pop();
+ }
ins_bytes_len(buf, n);
} else {
ins_char(cc);
@@ -7176,7 +7300,7 @@ static void replace_do_bs(int limit_col)
int ins_len;
int orig_vcols = 0;
colnr_T start_vcol;
- char_u *p;
+ char_u *p;
int i;
int vcol;
const int l_State = State;
@@ -7187,7 +7311,7 @@ static void replace_do_bs(int limit_col)
// Get the number of screen cells used by the character we are
// going to delete.
getvcol(curwin, &curwin->w_cursor, NULL, &start_vcol, NULL);
- orig_vcols = chartabsize(get_cursor_pos_ptr(), start_vcol);
+ orig_vcols = win_chartabsize(curwin, get_cursor_pos_ptr(), start_vcol);
}
(void)del_char_after_col(limit_col);
if (l_State & VREPLACE_FLAG) {
@@ -7201,8 +7325,8 @@ static void replace_do_bs(int limit_col)
p = get_cursor_pos_ptr();
ins_len = (int)STRLEN(p) - orig_len;
vcol = start_vcol;
- for (i = 0; i < ins_len; ++i) {
- vcol += chartabsize(p + i, vcol);
+ for (i = 0; i < ins_len; i++) {
+ vcol += win_chartabsize(curwin, p + i, vcol);
i += (*mb_ptr2len)(p) - 1;
}
vcol -= start_vcol;
@@ -7219,8 +7343,9 @@ static void replace_do_bs(int limit_col)
// mark the buffer as changed and prepare for displaying
changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col);
- } else if (cc == 0)
+ } else if (cc == 0) {
(void)del_char_after_col(limit_col);
+ }
}
/// Check that C-indenting is on.
@@ -7238,23 +7363,25 @@ static bool cindent_on(void)
*/
void fixthisline(IndentGetter get_the_indent)
{
- int amount = get_the_indent();
+ int amount = get_the_indent();
- if (amount >= 0) {
- change_indent(INDENT_SET, amount, false, 0, true);
- if (linewhite(curwin->w_cursor.lnum)) {
- did_ai = true; // delete the indent if the line stays empty
- }
+ if (amount >= 0) {
+ change_indent(INDENT_SET, amount, false, 0, true);
+ if (linewhite(curwin->w_cursor.lnum)) {
+ did_ai = true; // delete the indent if the line stays empty
}
+ }
}
void fix_indent(void) {
- if (p_paste)
+ if (p_paste) {
return;
- if (curbuf->b_p_lisp && curbuf->b_p_ai)
+ }
+ if (curbuf->b_p_lisp && curbuf->b_p_ai) {
fixthisline(get_lisp_indent);
- else if (cindent_on())
+ } else if (cindent_on()) {
do_c_expr_indent();
+ }
}
/// Check that "cinkeys" contains the key "keytyped",
@@ -7277,7 +7404,7 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty)
int try_match_word;
char_u *p;
char_u *line;
- int icase;
+ bool icase;
if (keytyped == NUL) {
// Can happen with CTRL-Y and CTRL-E on a short line.
@@ -7295,9 +7422,12 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty)
* 'when' and a '*' or '!' before the key.
*/
switch (when) {
- case '*': try_match = (*look == '*'); break;
- case '!': try_match = (*look == '!'); break;
- default: try_match = (*look != '*'); break;
+ case '*':
+ try_match = (*look == '*'); break;
+ case '!':
+ try_match = (*look == '!'); break;
+ default:
+ try_match = (*look != '*'); break;
}
if (*look == '*' || *look == '!') {
look++;
@@ -7322,8 +7452,8 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty)
}
look += 2;
- // 'o' means "o" command, open forward.
- // 'O' means "O" command, open backward.
+ // 'o' means "o" command, open forward.
+ // 'O' means "O" command, open backward.
} else if (*look == 'o') {
if (try_match && keytyped == KEY_OPEN_FORW) {
return true;
@@ -7335,8 +7465,8 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty)
}
look++;
- // 'e' means to check for "else" at start of line and just before the
- // cursor.
+ // 'e' means to check for "else" at start of line and just before the
+ // cursor.
} else if (*look == 'e') {
if (try_match && keytyped == 'e' && curwin->w_cursor.col >= 4) {
p = get_cursor_line_ptr();
@@ -7347,9 +7477,9 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty)
}
look++;
- // ':' only causes an indent if it is at the end of a label or case
- // statement, or when it was before typing the ':' (to fix
- // class::method for C++).
+ // ':' only causes an indent if it is at the end of a label or case
+ // statement, or when it was before typing the ':' (to fix
+ // class::method for C++).
} else if (*look == ':') {
if (try_match && keytyped == ':') {
p = get_cursor_line_ptr();
@@ -7363,8 +7493,8 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty)
&& p[curwin->w_cursor.col - 2] == ':') {
p[curwin->w_cursor.col - 1] = ' ';
const bool i = cin_iscase(p, false)
- || cin_isscopedecl(p)
- || cin_islabel();
+ || cin_isscopedecl(p)
+ || cin_islabel();
p = get_cursor_line_ptr();
p[curwin->w_cursor.col - 1] = ':';
if (i) {
@@ -7374,7 +7504,7 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty)
}
look++;
- // Is it a key in <>, maybe?
+ // Is it a key in <>, maybe?
} else if (*look == '<') {
if (try_match) {
// make up some named keys <o>, <O>, <e>, <0>, <>>, <<>, <*>,
@@ -7389,10 +7519,12 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty)
return true;
}
}
- while (*look && *look != '>')
+ while (*look && *look != '>') {
look++;
- while (*look == '>')
+ }
+ while (*look == '>') {
look++;
+ }
}
/*
* Is it a word: "=word"?
@@ -7400,13 +7532,15 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty)
else if (*look == '=' && look[1] != ',' && look[1] != NUL) {
++look;
if (*look == '~') {
- icase = TRUE;
- ++look;
- } else
- icase = FALSE;
+ icase = true;
+ look++;
+ } else {
+ icase = false;
+ }
p = vim_strchr(look, ',');
- if (p == NULL)
+ if (p == NULL) {
p = look + STRLEN(look);
+ }
if ((try_match || try_match_word)
&& curwin->w_cursor.col >= (colnr_T)(p - look)) {
bool match = false;
@@ -7427,8 +7561,9 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty)
if (s + (p - look) <= line + curwin->w_cursor.col
&& (icase
? mb_strnicmp(s, look, (size_t)(p - look))
- : STRNCMP(s, look, p - look)) == 0)
+ : STRNCMP(s, look, p - look)) == 0) {
match = true;
+ }
} else {
// TODO(@brammool): multi-byte
if (keytyped == (int)p[-1]
@@ -7459,7 +7594,7 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty)
}
look = p;
- // Ok, it's a boring generic character.
+ // Ok, it's a boring generic character.
} else {
if (try_match && *look == keytyped) {
return true;
@@ -7489,15 +7624,15 @@ int hkmap(int c)
PEIsofit, PEI, ZADIsofit, ZADI, KOF, RESH, hSHIN, TAV
};
static char_u map[26] =
- {(char_u)hALEF /*a*/, (char_u)BET /*b*/, (char_u)hKAF /*c*/,
- (char_u)DALET /*d*/, (char_u)-1 /*e*/, (char_u)PEIsofit /*f*/,
- (char_u)GIMEL /*g*/, (char_u)HEI /*h*/, (char_u)IUD /*i*/,
- (char_u)HET /*j*/, (char_u)KOF /*k*/, (char_u)LAMED /*l*/,
- (char_u)MEM /*m*/, (char_u)NUN /*n*/, (char_u)SAMEH /*o*/,
- (char_u)PEI /*p*/, (char_u)-1 /*q*/, (char_u)RESH /*r*/,
- (char_u)ZAIN /*s*/, (char_u)TAV /*t*/, (char_u)TET /*u*/,
- (char_u)VAV /*v*/, (char_u)hSHIN /*w*/, (char_u)-1 /*x*/,
- (char_u)AIN /*y*/, (char_u)ZADI /*z*/};
+ { (char_u)hALEF /*a*/, (char_u)BET /*b*/, (char_u)hKAF /*c*/,
+ (char_u)DALET /*d*/, (char_u)-1 /*e*/, (char_u)PEIsofit /*f*/,
+ (char_u)GIMEL /*g*/, (char_u)HEI /*h*/, (char_u)IUD /*i*/,
+ (char_u)HET /*j*/, (char_u)KOF /*k*/, (char_u)LAMED /*l*/,
+ (char_u)MEM /*m*/, (char_u)NUN /*n*/, (char_u)SAMEH /*o*/,
+ (char_u)PEI /*p*/, (char_u)-1 /*q*/, (char_u)RESH /*r*/,
+ (char_u)ZAIN /*s*/, (char_u)TAV /*t*/, (char_u)TET /*u*/,
+ (char_u)VAV /*v*/, (char_u)hSHIN /*w*/, (char_u)-1 /*x*/,
+ (char_u)AIN /*y*/, (char_u)ZADI /*z*/ };
if (c == 'N' || c == 'M' || c == 'P' || c == 'C' || c == 'Z') {
return (int)(map[CharOrd(c)] - 1 + p_aleph);
@@ -7522,21 +7657,30 @@ int hkmap(int c)
}
} else {
switch (c) {
- case '`': return ';';
- case '/': return '.';
- case '\'': return ',';
- case 'q': return '/';
- case 'w': return '\'';
+ case '`':
+ return ';';
+ case '/':
+ return '.';
+ case '\'':
+ return ',';
+ case 'q':
+ return '/';
+ case 'w':
+ return '\'';
// Hebrew letters - set offset from 'a'
- case ',': c = '{'; break;
- case '.': c = 'v'; break;
- case ';': c = 't'; break;
+ case ',':
+ c = '{'; break;
+ case '.':
+ c = 'v'; break;
+ case ';':
+ c = 't'; break;
default: {
static char str[] = "zqbcxlsjphmkwonu ydafe rig";
- if (c < 'a' || c > 'z')
+ if (c < 'a' || c > 'z') {
return c;
+ }
c = str[CharOrdLow(c)];
break;
}
@@ -7548,7 +7692,7 @@ int hkmap(int c)
static void ins_reg(void)
{
- int need_redraw = FALSE;
+ bool need_redraw = false;
int regname;
int literally = 0;
int vis_active = VIsual_active;
@@ -7659,13 +7803,15 @@ static void ins_ctrl_g(void)
// CTRL-G k and CTRL-G <Up>: cursor up to Insstart.col
case K_UP:
case Ctrl_K:
- case 'k': ins_up(TRUE);
+ case 'k':
+ ins_up(true);
break;
// CTRL-G j and CTRL-G <Down>: cursor down to Insstart.col
case K_DOWN:
case Ctrl_J:
- case 'j': ins_down(TRUE);
+ case 'j':
+ ins_down(true);
break;
// CTRL-G u: start new undoable edit
@@ -7687,7 +7833,8 @@ static void ins_ctrl_g(void)
break;
// Unknown CTRL-G command, reserved for future expansion.
- default: vim_beep(BO_CTRLG);
+ default:
+ vim_beep(BO_CTRLG);
}
}
@@ -7745,8 +7892,9 @@ static bool ins_esc(long *count, int cmdchar, bool nomove)
*/
if (*count > 0) {
line_breakcheck();
- if (got_int)
+ if (got_int) {
*count = 0;
+ }
}
if (--*count > 0) { // repeat what was typed
@@ -7795,8 +7943,7 @@ static bool ins_esc(long *count, int cmdchar, bool nomove)
|| (gchar_cursor() == NUL
&& !VIsual_active
))
- && !revins_on
- ) {
+ && !revins_on) {
if (curwin->w_cursor.coladd > 0 || ve_flags == VE_ALL) {
oneleft();
if (restart_edit != NUL) {
@@ -7835,8 +7982,9 @@ static bool ins_esc(long *count, int cmdchar, bool nomove)
static void ins_ctrl_(void)
{
if (revins_on && revins_chars && revins_scol >= 0) {
- while (gchar_cursor() != NUL && revins_chars--)
+ while (gchar_cursor() != NUL && revins_chars--) {
++curwin->w_cursor.col;
+ }
}
p_ri = !p_ri;
revins_on = (State == INSERT && p_ri);
@@ -7845,8 +7993,9 @@ static void ins_ctrl_(void)
revins_legal++;
revins_chars = 0;
undisplay_dollar();
- } else
+ } else {
revins_scol = -1;
+ }
p_hkmap = curwin->w_p_rl ^ p_ri; // be consistent!
showmode();
}
@@ -7869,8 +8018,9 @@ static bool ins_start_select(int c)
case K_KPAGEUP:
case K_PAGEDOWN:
case K_KPAGEDOWN:
- if (!(mod_mask & MOD_MASK_SHIFT))
+ if (!(mod_mask & MOD_MASK_SHIFT)) {
break;
+ }
FALLTHROUGH;
case K_S_LEFT:
case K_S_RIGHT:
@@ -7919,12 +8069,13 @@ static void ins_insert(int replaceState)
*/
static void ins_ctrl_o(void)
{
- if (State & VREPLACE_FLAG)
+ if (State & VREPLACE_FLAG) {
restart_edit = 'V';
- else if (State & REPLACE_FLAG)
+ } else if (State & REPLACE_FLAG) {
restart_edit = 'R';
- else
+ } else {
restart_edit = 'I';
+ }
if (virtual_active()) {
ins_at_eol = false; // cursor always keeps its column
} else {
@@ -7934,15 +8085,16 @@ static void ins_ctrl_o(void)
/*
* If the cursor is on an indent, ^T/^D insert/delete one
- * shiftwidth. Otherwise ^T/^D behave like a "<<" or ">>".
+ * shiftwidth. Otherwise ^T/^D behave like a "<<" or ">>".
* Always round the indent to 'shiftwidth', this is compatible
* with vi. But vi only supports ^T and ^D after an
* autoindent, we support it everywhere.
*/
static void ins_shift(int c, int lastc)
{
- if (stop_arrow() == FAIL)
+ if (stop_arrow() == FAIL) {
return;
+ }
AppendCharToRedobuff(c);
/*
@@ -7960,8 +8112,9 @@ static void ins_shift(int c, int lastc)
old_indent = get_indent(); // remember curr. indent
}
change_indent(INDENT_SET, 0, TRUE, 0, TRUE);
- } else
+ } else {
change_indent(c == Ctrl_D ? INDENT_DEC : INDENT_INC, 0, TRUE, 0, TRUE);
+ }
if (did_ai && *skipwhite(get_cursor_line_ptr()) != NUL) {
did_ai = false;
@@ -8024,7 +8177,7 @@ static void ins_bs_one(colnr_T *vcolp)
/// Handle Backspace, delete-word and delete-line in Insert mode.
///
-/// @param c charcter that was typed
+/// @param c character that was typed
/// @param mode backspace mode to use
/// @param[in,out] inserted_space_p whether a space was the last
// character inserted
@@ -8047,7 +8200,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p)
// can't backup past first character in buffer
// can't backup past starting point unless 'backspace' > 1
// can backup to a previous line if 'backspace' == 0
- if (BUFEMPTY()
+ if (buf_is_empty(curbuf)
|| (!revins_on
&& ((curwin->w_cursor.lnum == 1 && curwin->w_cursor.col == 0)
|| (!can_bs(BS_START)
@@ -8123,20 +8276,22 @@ static bool ins_bs(int c, int mode, int *inserted_space_p)
// again when auto-formatting.
if (has_format_option(FO_AUTO)
&& has_format_option(FO_WHITE_PAR)) {
- char_u *ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum,
- TRUE);
+ char_u *ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, true);
int len;
len = (int)STRLEN(ptr);
- if (len > 0 && ptr[len - 1] == ' ')
+ if (len > 0 && ptr[len - 1] == ' ') {
ptr[len - 1] = NUL;
+ }
}
do_join(2, FALSE, FALSE, FALSE, false);
- if (temp == NUL && gchar_cursor() != NUL)
+ if (temp == NUL && gchar_cursor() != NUL) {
inc_cursor();
- } else
+ }
+ } else {
dec_cursor();
+ }
/*
* In REPLACE mode we have to put back the text that was replaced
@@ -8178,12 +8333,12 @@ static bool ins_bs(int c, int mode, int *inserted_space_p)
&& (curbuf->b_p_ai
|| cindent_on()
)
- && !revins_on
- ) {
+ && !revins_on) {
save_col = curwin->w_cursor.col;
beginline(BL_WHITE);
- if (curwin->w_cursor.col < save_col)
+ if (curwin->w_cursor.col < save_col) {
mincol = curwin->w_cursor.col;
+ }
curwin->w_cursor.col = save_col;
}
@@ -8213,7 +8368,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p)
getvcol(curwin, &curwin->w_cursor, NULL, NULL, &want_vcol);
inc_cursor();
if (p_sta && in_indent) {
- ts = (int)get_sw_value(curbuf);
+ ts = get_sw_value(curbuf);
want_vcol = (want_vcol / ts) * ts;
} else {
want_vcol = tabstop_start(want_vcol,
@@ -8239,8 +8394,9 @@ static bool ins_bs(int c, int mode, int *inserted_space_p)
ins_char(' ');
} else {
ins_str((char_u *)" ");
- if ((State & REPLACE_FLAG))
+ if ((State & REPLACE_FLAG)) {
replace_push(NUL);
+ }
}
getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
}
@@ -8251,7 +8407,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p)
ins_bs_one(&vcol);
}
} else {
- // Delete upto starting point, start of line or previous word.
+ // Delete up to starting point, start of line or previous word.
int prev_cclass = 0;
int cclass = mb_get_class(get_cursor_pos_ptr());
@@ -8294,8 +8450,9 @@ static bool ins_bs(int c, int mode, int *inserted_space_p)
revins_chars--;
revins_legal++;
}
- if (revins_on && gchar_cursor() == NUL)
+ if (revins_on && gchar_cursor() == NUL) {
break;
+ }
}
// Just a single backspace?:
if (mode == BACKSPACE_CHAR) {
@@ -8349,12 +8506,12 @@ static bool ins_bs(int c, int mode, int *inserted_space_p)
static void ins_mouse(int c)
{
pos_T tpos;
- win_T *old_curwin = curwin;
+ win_T *old_curwin = curwin;
undisplay_dollar();
tpos = curwin->w_cursor;
if (do_mouse(NULL, c, BACKWARD, 1, 0)) {
- win_T *new_curwin = curwin;
+ win_T *new_curwin = curwin;
if (curwin != old_curwin && win_valid(old_curwin)) {
// Mouse took us to another window. We need to go back to the
@@ -8394,21 +8551,22 @@ static void ins_mousescroll(int dir)
curwin = wp;
curbuf = curwin->w_buffer;
}
- if (curwin == old_curwin)
+ if (curwin == old_curwin) {
undisplay_dollar();
+ }
// Don't scroll the window in which completion is being done.
if (!pum_visible()
- || curwin != old_curwin
- ) {
+ || curwin != old_curwin) {
if (dir == MSCR_DOWN || dir == MSCR_UP) {
- if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
+ if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)) {
scroll_redraw(dir,
- (long)(curwin->w_botline - curwin->w_topline));
- else
+ (curwin->w_botline - curwin->w_topline));
+ } else {
scroll_redraw(dir, 3L);
+ }
} else {
- mouse_scroll_horiz(dir);
+ mouse_scroll_horiz(dir);
}
}
@@ -8430,8 +8588,9 @@ static void ins_left(void)
pos_T tpos;
const bool end_change = dont_sync_undo == kFalse; // end undoable change
- if ((fdo_flags & FDO_HOR) && KeyTyped)
+ if ((fdo_flags & FDO_HOR) && KeyTyped) {
foldOpenCursor();
+ }
undisplay_dollar();
tpos = curwin->w_cursor;
if (oneleft() == OK) {
@@ -8461,12 +8620,14 @@ static void ins_home(int c)
{
pos_T tpos;
- if ((fdo_flags & FDO_HOR) && KeyTyped)
+ if ((fdo_flags & FDO_HOR) && KeyTyped) {
foldOpenCursor();
+ }
undisplay_dollar();
tpos = curwin->w_cursor;
- if (c == K_C_HOME)
+ if (c == K_C_HOME) {
curwin->w_cursor.lnum = 1;
+ }
curwin->w_cursor.col = 0;
curwin->w_cursor.coladd = 0;
curwin->w_curswant = 0;
@@ -8477,12 +8638,14 @@ static void ins_end(int c)
{
pos_T tpos;
- if ((fdo_flags & FDO_HOR) && KeyTyped)
+ if ((fdo_flags & FDO_HOR) && KeyTyped) {
foldOpenCursor();
+ }
undisplay_dollar();
tpos = curwin->w_cursor;
- if (c == K_C_END)
+ if (c == K_C_END) {
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+ }
coladvance(MAXCOL);
curwin->w_curswant = MAXCOL;
@@ -8530,8 +8693,9 @@ static void ins_right(void)
}
revins_legal++;
- if (revins_chars)
+ if (revins_chars) {
revins_chars--;
+ }
} else if (vim_strchr(p_ww, ']') != NULL
&& curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) {
// if 'whichwrap' set for cursor in insert mode, may move the
@@ -8567,9 +8731,8 @@ static void ins_s_right(void)
dont_sync_undo = kFalse;
}
-static void ins_up(
- bool startcol // when true move to Insstart.col
-)
+/// @param startcol when true move to Insstart.col
+static void ins_up(bool startcol)
{
pos_T tpos;
linenr_T old_topline = curwin->w_topline;
@@ -8578,12 +8741,13 @@ static void ins_up(
undisplay_dollar();
tpos = curwin->w_cursor;
if (cursor_up(1L, TRUE) == OK) {
- if (startcol)
+ if (startcol) {
coladvance(getvcol_nolist(&Insstart));
+ }
if (old_topline != curwin->w_topline
- || old_topfill != curwin->w_topfill
- )
+ || old_topfill != curwin->w_topfill) {
redraw_later(curwin, VALID);
+ }
start_arrow(&tpos);
can_cindent = true;
} else {
@@ -8615,9 +8779,8 @@ static void ins_pageup(void)
}
}
-static void ins_down(
- bool startcol // when true move to Insstart.col
-)
+/// @param startcol when true move to Insstart.col
+static void ins_down(bool startcol)
{
pos_T tpos;
linenr_T old_topline = curwin->w_topline;
@@ -8626,12 +8789,13 @@ static void ins_down(
undisplay_dollar();
tpos = curwin->w_cursor;
if (cursor_down(1L, TRUE) == OK) {
- if (startcol)
+ if (startcol) {
coladvance(getvcol_nolist(&Insstart));
+ }
if (old_topline != curwin->w_topline
- || old_topfill != curwin->w_topfill
- )
+ || old_topfill != curwin->w_topfill) {
redraw_later(curwin, VALID);
+ }
start_arrow(&tpos);
can_cindent = true;
} else {
@@ -8687,15 +8851,15 @@ static bool ins_tab(void)
// When nothing special, insert TAB like a normal character.
if (!curbuf->b_p_et
&& !(
- p_sta
- && ind
- // These five lines mean 'tabstop' != 'shiftwidth'
- && ((tabstop_count(curbuf->b_p_vts_array) > 1)
- || (tabstop_count(curbuf->b_p_vts_array) == 1
- && tabstop_first(curbuf->b_p_vts_array)
- != get_sw_value(curbuf))
- || (tabstop_count(curbuf->b_p_vts_array) == 0
- && curbuf->b_p_ts != get_sw_value(curbuf))))
+ p_sta
+ && ind
+ // These five lines mean 'tabstop' != 'shiftwidth'
+ && ((tabstop_count(curbuf->b_p_vts_array) > 1)
+ || (tabstop_count(curbuf->b_p_vts_array) == 1
+ && tabstop_first(curbuf->b_p_vts_array)
+ != get_sw_value(curbuf))
+ || (tabstop_count(curbuf->b_p_vts_array) == 0
+ && curbuf->b_p_ts != get_sw_value(curbuf))))
&& tabstop_count(curbuf->b_p_vsts_array) == 0 && get_sts_value() == 0) {
return true;
}
@@ -8711,7 +8875,7 @@ static bool ins_tab(void)
AppendToRedobuff("\t");
if (p_sta && ind) { // insert tab in indent, use 'shiftwidth'
- temp = (int)get_sw_value(curbuf);
+ temp = get_sw_value(curbuf);
temp -= get_nolist_virtcol() % temp;
} else if (tabstop_count(curbuf->b_p_vsts_array) > 0
|| curbuf->b_p_sts != 0) {
@@ -8727,7 +8891,7 @@ static bool ins_tab(void)
}
/*
- * Insert the first space with ins_char(). It will delete one char in
+ * Insert the first space with ins_char(). It will delete one char in
* replace mode. Insert the rest with ins_str(); it will not delete any
* chars. For VREPLACE mode, we use ins_char() for all characters.
*/
@@ -8749,11 +8913,11 @@ static bool ins_tab(void)
if (!curbuf->b_p_et && (tabstop_count(curbuf->b_p_vsts_array) > 0
|| get_sts_value() > 0
|| (p_sta && ind))) {
- char_u *ptr;
- char_u *saved_line = NULL; // init for GCC
+ char_u *ptr;
+ char_u *saved_line = NULL; // init for GCC
pos_T pos;
pos_T fpos;
- pos_T *cursor;
+ pos_T *cursor;
colnr_T want_vcol, vcol;
int change_col = -1;
int save_list = curwin->w_p_list;
@@ -8800,8 +8964,9 @@ static bool ins_tab(void)
// and 'linebreak' adding extra virtual columns.
while (ascii_iswhite(*ptr)) {
i = lbr_chartabsize(NULL, (char_u *)"\t", vcol);
- if (vcol + i > want_vcol)
+ if (vcol + i > want_vcol) {
break;
+ }
if (*ptr != TAB) {
*ptr = TAB;
if (change_col < 0) {
@@ -8865,12 +9030,13 @@ static bool ins_tab(void)
// Insert each char in saved_line from changed_col to
// ptr-cursor
ins_bytes_len(saved_line + change_col,
- cursor->col - change_col);
+ cursor->col - change_col);
}
}
- if (State & VREPLACE_FLAG)
+ if (State & VREPLACE_FLAG) {
xfree(saved_line);
+ }
curwin->w_p_list = save_list;
}
@@ -8896,9 +9062,9 @@ static bool ins_eol(int c)
* nothing to put back when the NL is deleted.
*/
if ((State & REPLACE_FLAG)
- && !(State & VREPLACE_FLAG)
- )
+ && !(State & VREPLACE_FLAG)) {
replace_push(NUL);
+ }
/*
* In VREPLACE mode, a NL replaces the rest of the line, and starts
@@ -9008,8 +9174,8 @@ int ins_copychar(linenr_T lnum)
{
int c;
int temp;
- char_u *ptr, *prev_ptr;
- char_u *line;
+ char_u *ptr, *prev_ptr;
+ char_u *line;
if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) {
vim_beep(BO_COPY);
@@ -9025,8 +9191,9 @@ int ins_copychar(linenr_T lnum)
prev_ptr = ptr;
temp += lbr_chartabsize_adv(line, &ptr, (colnr_T)temp);
}
- if ((colnr_T)temp > curwin->w_virtcol)
+ if ((colnr_T)temp > curwin->w_virtcol) {
ptr = prev_ptr;
+ }
c = utf_ptr2char(ptr);
if (c == NUL) {
@@ -9043,10 +9210,11 @@ static int ins_ctrl_ey(int tc)
int c = tc;
if (ctrl_x_mode == CTRL_X_SCROLL) {
- if (c == Ctrl_Y)
+ if (c == Ctrl_Y) {
scrolldown_clamp();
- else
+ } else {
scrollup_clamp();
+ }
redraw_later(curwin, VALID);
} else {
c = ins_copychar(curwin->w_cursor.lnum + (c == Ctrl_Y ? -1 : 1));
@@ -9079,10 +9247,10 @@ static int ins_ctrl_ey(int tc)
*/
static void ins_try_si(int c)
{
- pos_T *pos, old_pos;
- char_u *ptr;
+ pos_T *pos, old_pos;
+ char_u *ptr;
int i;
- int temp;
+ bool temp;
/*
* do some very smart indenting when entering '{' or '}'
@@ -9108,20 +9276,20 @@ static void ins_try_si(int c)
}
curwin->w_cursor.lnum = pos->lnum;
curwin->w_cursor.col = i;
- if (ptr[i] == ')' && (pos = findmatch(NULL, '(')) != NULL)
+ if (ptr[i] == ')' && (pos = findmatch(NULL, '(')) != NULL) {
curwin->w_cursor = *pos;
+ }
i = get_indent();
curwin->w_cursor = old_pos;
- if (State & VREPLACE_FLAG)
+ if (State & VREPLACE_FLAG) {
change_indent(INDENT_SET, i, FALSE, NUL, TRUE);
- else
+ } else {
(void)set_indent(i, SIN_CHANGED);
+ }
} else if (curwin->w_cursor.col > 0) {
- /*
- * when inserting '{' after "O" reduce indent, but not
- * more than indent of previous line
- */
- temp = TRUE;
+ // when inserting '{' after "O" reduce indent, but not
+ // more than indent of previous line
+ temp = true;
if (c == '{' && can_si_back && curwin->w_cursor.lnum > 1) {
old_pos = curwin->w_cursor;
i = get_indent();
@@ -9133,12 +9301,14 @@ static void ins_try_si(int c)
break;
}
}
- if (get_indent() >= i)
- temp = FALSE;
+ if (get_indent() >= i) {
+ temp = false;
+ }
curwin->w_cursor = old_pos;
}
- if (temp)
+ if (temp) {
shift_line(TRUE, FALSE, 1, TRUE);
+ }
}
}
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index ff019d1e07..768b82b464 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -20,12 +20,12 @@
#include "nvim/charset.h"
#include "nvim/cursor.h"
#include "nvim/edit.h"
-#include "nvim/eval/userfunc.h"
#include "nvim/eval.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/executor.h"
#include "nvim/eval/gc.h"
#include "nvim/eval/typval.h"
+#include "nvim/eval/userfunc.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
@@ -65,8 +65,11 @@ static char *e_missbrac = N_("E111: Missing ']'");
static char *e_dictrange = N_("E719: Cannot use [:] with a Dictionary");
static char *e_illvar = N_("E461: Illegal variable name: %s");
static char *e_cannot_mod = N_("E995: Cannot modify existing variable");
+static char *e_nowhitespace
+ = N_("E274: No white space allowed before parenthesis");
static char *e_invalwindow = N_("E957: Invalid window number");
static char *e_lock_unlock = N_("E940: Cannot lock or unlock variable %s");
+static char *e_write2 = N_("E80: Error while writing: %s");
// TODO(ZyX-I): move to eval/executor
static char *e_letwrong = N_("E734: Wrong variable type for %s=");
@@ -94,7 +97,7 @@ typedef struct {
dict_T sv_dict;
} scriptvar_T;
-static garray_T ga_scripts = {0, 0, sizeof(scriptvar_T *), 4, NULL};
+static garray_T ga_scripts = { 0, 0, sizeof(scriptvar_T *), 4, NULL };
#define SCRIPT_SV(id) (((scriptvar_T **)ga_scripts.ga_data)[(id) - 1])
#define SCRIPT_VARS(id) (SCRIPT_SV(id)->sv_dict.dv_hashtab)
@@ -110,7 +113,9 @@ typedef struct {
int fi_semicolon; // TRUE if ending in '; var]'
int fi_varcount; // nr of variables in the list
listwatch_T fi_lw; // keep an eye on the item used.
- list_T *fi_list; // list being used
+ list_T *fi_list; // list being used
+ int fi_bi; // index of blob
+ blob_T *fi_blob; // blob being used
} forinfo_T;
// values for vv_flags:
@@ -134,7 +139,7 @@ typedef struct {
// The reason to use this table anyway is for very quick access to the
// variables with the VV_ defines.
static struct vimvar {
- char *vv_name; ///< Name of the variable, without v:.
+ char *vv_name; ///< Name of the variable, without v:.
TV_DICTITEM_STRUCT(17) vv_di; ///< Value and name for key (max 16 chars).
char vv_flags; ///< Flags: #VV_COMPAT, #VV_RO, #VV_RO_SBX.
} vimvars[] =
@@ -225,6 +230,7 @@ static struct vimvar {
VV(VV_TYPE_DICT, "t_dict", VAR_NUMBER, VV_RO),
VV(VV_TYPE_FLOAT, "t_float", VAR_NUMBER, VV_RO),
VV(VV_TYPE_BOOL, "t_bool", VAR_NUMBER, VV_RO),
+ VV(VV_TYPE_BLOB, "t_blob", VAR_NUMBER, VV_RO),
VV(VV_EVENT, "event", VAR_DICT, VV_RO),
VV(VV_ECHOSPACE, "echospace", VAR_NUMBER, VV_RO),
VV(VV_ARGV, "argv", VAR_LIST, VV_RO),
@@ -236,6 +242,7 @@ static struct vimvar {
VV(VV__NULL_STRING, "_null_string", VAR_STRING, VV_RO),
VV(VV__NULL_LIST, "_null_list", VAR_LIST, VV_RO),
VV(VV__NULL_DICT, "_null_dict", VAR_DICT, VV_RO),
+ VV(VV__NULL_BLOB, "_null_blob", VAR_BLOB, VV_RO),
VV(VV_LUA, "lua", VAR_PARTIAL, VV_RO),
};
#undef VV
@@ -249,6 +256,7 @@ static struct vimvar {
#define vv_str vv_di.di_tv.vval.v_string
#define vv_list vv_di.di_tv.vval.v_list
#define vv_dict vv_di.di_tv.vval.v_dict
+#define vv_blob vv_di.di_tv.vval.v_blob
#define vv_partial vv_di.di_tv.vval.v_partial
#define vv_tv vv_di.di_tv
@@ -265,7 +273,7 @@ static partial_T *vvlua_partial;
#endif
static uint64_t last_timer_id = 1;
-static PMap(uint64_t) *timers = NULL;
+static PMap(uint64_t) timers = MAP_INIT;
static const char *const msgpack_type_names[] = {
[kMPNil] = "nil",
@@ -326,8 +334,7 @@ void eval_init(void)
{
vimvars[VV_VERSION].vv_nr = VIM_VERSION_100;
- timers = pmap_new(uint64_t)();
- struct vimvar *p;
+ struct vimvar *p;
init_var_dict(&globvardict, &globvars_var, VAR_DEF_SCOPE);
init_var_dict(&vimvardict, &vimvars_var, VAR_SCOPE);
@@ -339,12 +346,13 @@ void eval_init(void)
p = &vimvars[i];
assert(STRLEN(p->vv_name) <= 16);
STRCPY(p->vv_di.di_key, p->vv_name);
- if (p->vv_flags & VV_RO)
+ if (p->vv_flags & VV_RO) {
p->vv_di.di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
- else if (p->vv_flags & VV_RO_SBX)
+ } else if (p->vv_flags & VV_RO_SBX) {
p->vv_di.di_flags = DI_FLAGS_RO_SBX | DI_FLAGS_FIX;
- else
+ } else {
p->vv_di.di_flags = DI_FLAGS_FIX;
+ }
// add to v: scope dict, unless the value is not always available
if (p->vv_type != VAR_UNKNOWN) {
@@ -392,6 +400,7 @@ void eval_init(void)
set_vim_var_nr(VV_TYPE_DICT, VAR_TYPE_DICT);
set_vim_var_nr(VV_TYPE_FLOAT, VAR_TYPE_FLOAT);
set_vim_var_nr(VV_TYPE_BOOL, VAR_TYPE_BOOL);
+ set_vim_var_nr(VV_TYPE_BLOB, VAR_TYPE_BLOB);
set_vim_var_bool(VV_FALSE, kBoolVarFalse);
set_vim_var_bool(VV_TRUE, kBoolVarTrue);
@@ -416,7 +425,7 @@ void eval_init(void)
#if defined(EXITFREE)
void eval_clear(void)
{
- struct vimvar *p;
+ struct vimvar *p;
for (size_t i = 0; i < ARRAY_SIZE(vimvars); i++) {
p = &vimvars[i];
@@ -443,10 +452,12 @@ void eval_clear(void)
/* Script-local variables. First clear all the variables and in a second
* loop free the scriptvar_T, because a variable in one script might hold
* a reference to the whole scope of another script. */
- for (int i = 1; i <= ga_scripts.ga_len; ++i)
+ for (int i = 1; i <= ga_scripts.ga_len; ++i) {
vars_clear(&SCRIPT_VARS(i));
- for (int i = 1; i <= ga_scripts.ga_len; ++i)
+ }
+ for (int i = 1; i <= ga_scripts.ga_len; ++i) {
xfree(SCRIPT_SV(i));
+ }
ga_clear(&ga_scripts);
// unreferenced lists and dicts
@@ -473,20 +484,16 @@ void set_internal_string_var(const char *name, char_u *value)
set_var(name, strlen(name), &tv, true);
}
-static lval_T *redir_lval = NULL;
+static lval_T *redir_lval = NULL;
static garray_T redir_ga; // Only valid when redir_lval is not NULL.
static char_u *redir_endp = NULL;
-static char_u *redir_varname = NULL;
+static char_u *redir_varname = NULL;
-/*
- * Start recording command output to a variable
- * Returns OK if successfully completed the setup. FAIL otherwise.
- */
-int
-var_redir_start(
- char_u *name,
- int append // append to an existing variable
-)
+/// Start recording command output to a variable
+/// Returns OK if successfully completed the setup. FAIL otherwise.
+///
+/// @param append append to an existing variable
+int var_redir_start(char_u *name, int append)
{
int save_emsg;
int err;
@@ -559,8 +566,9 @@ void var_redir_str(char_u *value, int value_len)
{
int len;
- if (redir_lval == NULL)
+ if (redir_lval == NULL) {
return;
+ }
if (value_len == -1) {
len = (int)STRLEN(value); // Append the entire string
@@ -647,8 +655,7 @@ int eval_printexpr(const char *const fname, const char *const args)
return OK;
}
-void eval_diff(const char *const origfile, const char *const newfile,
- const char *const outfile)
+void eval_diff(const char *const origfile, const char *const newfile, const char *const outfile)
{
bool err = false;
@@ -661,8 +668,7 @@ void eval_diff(const char *const origfile, const char *const newfile,
set_vim_var_string(VV_FNAME_OUT, NULL, -1);
}
-void eval_patch(const char *const origfile, const char *const difffile,
- const char *const outfile)
+void eval_patch(const char *const origfile, const char *const difffile, const char *const outfile)
{
bool err = false;
@@ -675,18 +681,13 @@ void eval_patch(const char *const origfile, const char *const difffile,
set_vim_var_string(VV_FNAME_OUT, NULL, -1);
}
-/*
- * Top level evaluation function, returning a boolean.
- * Sets "error" to TRUE if there was an error.
- * Return TRUE or FALSE.
- */
-int
-eval_to_bool(
- char_u *arg,
- bool *error,
- char_u **nextcmd,
- int skip // only parse, don't execute
-)
+/// Top level evaluation function, returning a boolean.
+/// Sets "error" to TRUE if there was an error.
+///
+/// @param skip only parse, don't execute
+///
+/// @return TRUE or FALSE.
+int eval_to_bool(char_u *arg, bool *error, char_u **nextcmd, int skip)
{
typval_T tv;
bool retval = false;
@@ -733,19 +734,18 @@ static int eval1_emsg(char_u **arg, typval_T *rettv, bool evaluate)
return ret;
}
-int eval_expr_typval(const typval_T *expr, typval_T *argv,
- int argc, typval_T *rettv)
+int eval_expr_typval(const typval_T *expr, typval_T *argv, int argc, typval_T *rettv)
FUNC_ATTR_NONNULL_ARG(1, 2, 4)
{
- int dummy;
+ funcexe_T funcexe = FUNCEXE_INIT;
if (expr->v_type == VAR_FUNC) {
const char_u *const s = expr->vval.v_string;
if (s == NULL || *s == NUL) {
return FAIL;
}
- if (call_func(s, -1, rettv, argc, argv, NULL,
- 0L, 0L, &dummy, true, NULL, NULL) == FAIL) {
+ funcexe.evaluate = true;
+ if (call_func(s, -1, rettv, argc, argv, &funcexe) == FAIL) {
return FAIL;
}
} else if (expr->v_type == VAR_PARTIAL) {
@@ -754,8 +754,9 @@ int eval_expr_typval(const typval_T *expr, typval_T *argv,
if (s == NULL || *s == NUL) {
return FAIL;
}
- if (call_func(s, -1, rettv, argc, argv, NULL,
- 0L, 0L, &dummy, true, partial, NULL) == FAIL) {
+ funcexe.evaluate = true;
+ funcexe.partial = partial;
+ if (call_func(s, -1, rettv, argc, argv, &funcexe) == FAIL) {
return FAIL;
}
} else {
@@ -802,8 +803,7 @@ bool eval_expr_to_bool(const typval_T *expr, bool *error)
///
/// @return [allocated] string result of evaluation or NULL in case of error or
/// when skipping.
-char *eval_to_string_skip(const char *arg, const char **nextcmd,
- const bool skip)
+char *eval_to_string_skip(const char *arg, const char **nextcmd, const bool skip)
FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_WARN_UNUSED_RESULT
{
typval_T tv;
@@ -837,13 +837,13 @@ int skip_expr(char_u **pp)
return eval1(pp, &rettv, FALSE);
}
-/*
- * Top level evaluation function, returning a string.
- * When "convert" is TRUE convert a List into a sequence of lines and convert
- * a Float to a String.
- * Return pointer to allocated memory, or NULL for failure.
- */
-char_u *eval_to_string(char_u *arg, char_u **nextcmd, int convert)
+/// Top level evaluation function, returning a string.
+///
+/// @param convert when true convert a List into a sequence of lines and convert
+/// a Float to a String.
+///
+/// @return pointer to allocated memory, or NULL for failure.
+char_u *eval_to_string(char_u *arg, char_u **nextcmd, bool convert)
{
typval_T tv;
char *retval;
@@ -881,7 +881,7 @@ char_u *eval_to_string(char_u *arg, char_u **nextcmd, int convert)
*/
char_u *eval_to_string_safe(char_u *arg, char_u **nextcmd, int use_sandbox)
{
- char_u *retval;
+ char_u *retval;
funccal_entry_T funccal_entry;
save_funccal(&funccal_entry);
@@ -907,7 +907,7 @@ varnumber_T eval_to_number(char_u *expr)
{
typval_T rettv;
varnumber_T retval;
- char_u *p = skipwhite(expr);
+ char_u *p = skipwhite(expr);
++emsg_off;
@@ -942,8 +942,9 @@ typval_T *eval_expr(char_u *arg)
void prepare_vimvar(int idx, typval_T *save_tv)
{
*save_tv = vimvars[idx].vv_tv;
- if (vimvars[idx].vv_type == VAR_UNKNOWN)
+ if (vimvars[idx].vv_type == VAR_UNKNOWN) {
hash_add(&vimvarht, vimvars[idx].vv_di.di_key);
+ }
}
/*
@@ -952,7 +953,7 @@ void prepare_vimvar(int idx, typval_T *save_tv)
*/
void restore_vimvar(int idx, typval_T *save_tv)
{
- hashitem_T *hi;
+ hashitem_T *hi;
vimvars[idx].vv_tv = *save_tv;
if (vimvars[idx].vv_type == VAR_UNKNOWN) {
@@ -985,15 +986,16 @@ list_T *eval_spell_expr(char_u *badword, char_u *expr)
{
typval_T save_val;
typval_T rettv;
- list_T *list = NULL;
- char_u *p = skipwhite(expr);
+ list_T *list = NULL;
+ char_u *p = skipwhite(expr);
// Set "v:val" to the bad word.
prepare_vimvar(VV_VAL, &save_val);
vimvars[VV_VAL].vv_type = VAR_STRING;
vimvars[VV_VAL].vv_str = badword;
- if (p_verbose == 0)
+ if (p_verbose == 0) {
++emsg_off;
+ }
if (eval1(&p, &rettv, true) == OK) {
if (rettv.v_type != VAR_LIST) {
@@ -1003,8 +1005,9 @@ list_T *eval_spell_expr(char_u *badword, char_u *expr)
}
}
- if (p_verbose == 0)
+ if (p_verbose == 0) {
--emsg_off;
+ }
restore_vimvar(VV_VAL, &save_val);
return list;
@@ -1043,15 +1046,9 @@ int get_spellword(list_T *const list, const char **ret_word)
// should have type VAR_UNKNOWN.
//
// Return OK or FAIL.
-int call_vim_function(
- const char_u *func,
- int argc,
- typval_T *argv,
- typval_T *rettv
-)
+int call_vim_function(const char_u *func, int argc, typval_T *argv, typval_T *rettv)
FUNC_ATTR_NONNULL_ALL
{
- int doesrange;
int ret;
int len = (int)STRLEN(func);
partial_T *pt = NULL;
@@ -1067,9 +1064,12 @@ int call_vim_function(
}
rettv->v_type = VAR_UNKNOWN; // tv_clear() uses this.
- ret = call_func(func, len, rettv, argc, argv, NULL,
- curwin->w_cursor.lnum, curwin->w_cursor.lnum,
- &doesrange, true, pt, NULL);
+ funcexe_T funcexe = FUNCEXE_INIT;
+ funcexe.firstline = curwin->w_cursor.lnum;
+ funcexe.lastline = curwin->w_cursor.lnum;
+ funcexe.evaluate = true;
+ funcexe.partial = pt;
+ ret = call_func(func, len, rettv, argc, argv, &funcexe);
fail:
if (ret == FAIL) {
@@ -1085,8 +1085,7 @@ fail:
/// @param[in] argv Array with typval_T arguments.
///
/// @return -1 when calling function fails, result of function otherwise.
-varnumber_T call_func_retnr(const char_u *func, int argc,
- typval_T *argv)
+varnumber_T call_func_retnr(const char_u *func, int argc, typval_T *argv)
FUNC_ATTR_NONNULL_ALL
{
typval_T rettv;
@@ -1107,8 +1106,7 @@ varnumber_T call_func_retnr(const char_u *func, int argc,
///
/// @return [allocated] NULL when calling function fails, allocated string
/// otherwise.
-char *call_func_retstr(const char *const func, int argc,
- typval_T *argv)
+char *call_func_retstr(const char *const func, int argc, typval_T *argv)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_MALLOC
{
typval_T rettv;
@@ -1148,14 +1146,12 @@ void *call_func_retlist(const char_u *func, int argc, typval_T *argv)
return rettv.vval.v_list;
}
-/*
- * Prepare profiling for entering a child or something else that is not
- * counted for the script/function itself.
- * Should always be called in pair with prof_child_exit().
- */
-void prof_child_enter(
- proftime_T *tm // place to store waittime
-)
+/// Prepare profiling for entering a child or something else that is not
+/// counted for the script/function itself.
+/// Should always be called in pair with prof_child_exit().
+///
+/// @param tm place to store waittime
+void prof_child_enter(proftime_T *tm)
{
funccall_T *fc = get_current_funccal();
@@ -1166,13 +1162,11 @@ void prof_child_enter(
script_prof_save(tm);
}
-/*
- * Take care of time spent in a child.
- * Should always be called after prof_child_enter().
- */
-void prof_child_exit(
- proftime_T *tm // where waittime was stored
-)
+/// Take care of time spent in a child.
+/// Should always be called after prof_child_enter().
+///
+/// @param tm where waittime was stored
+void prof_child_exit(proftime_T *tm)
{
funccall_T *fc = get_current_funccal();
@@ -1200,8 +1194,9 @@ int eval_foldexpr(char_u *arg, int *cp)
int use_sandbox = was_set_insecurely(curwin, (char_u *)"foldexpr", OPT_LOCAL);
++emsg_off;
- if (use_sandbox)
+ if (use_sandbox) {
++sandbox;
+ }
++textlock;
*cp = NUL;
if (eval0(arg, &tv, NULL, true) == FAIL) {
@@ -1224,8 +1219,9 @@ int eval_foldexpr(char_u *arg, int *cp)
tv_clear(&tv);
}
--emsg_off;
- if (use_sandbox)
+ if (use_sandbox) {
--sandbox;
+ }
--textlock;
return (int)retval;
@@ -1251,8 +1247,7 @@ void ex_const(exarg_T *eap)
// marker, then the leading indentation before the lines (matching the
// indentation in the 'cmd' line) is stripped.
// Returns a List with {lines} or NULL.
-static list_T *
-heredoc_get(exarg_T *eap, char_u *cmd)
+static list_T *heredoc_get(exarg_T *eap, char_u *cmd)
{
char_u *marker;
char_u *p;
@@ -1316,29 +1311,29 @@ heredoc_get(exarg_T *eap, char_u *cmd)
// marker
if (marker_indent_len > 0
&& STRNCMP(theline, *eap->cmdlinep, marker_indent_len) == 0) {
- mi = marker_indent_len;
+ mi = marker_indent_len;
}
if (STRCMP(marker, theline + mi) == 0) {
xfree(theline);
break;
}
if (text_indent_len == -1 && *theline != NUL) {
- // set the text indent from the first line.
- p = theline;
- text_indent_len = 0;
- while (ascii_iswhite(*p)) {
- p++;
- text_indent_len++;
- }
- text_indent = vim_strnsave(theline, text_indent_len);
+ // set the text indent from the first line.
+ p = theline;
+ text_indent_len = 0;
+ while (ascii_iswhite(*p)) {
+ p++;
+ text_indent_len++;
+ }
+ text_indent = vim_strnsave(theline, text_indent_len);
}
// with "trim": skip the indent matching the first line
if (text_indent != NULL) {
- for (ti = 0; ti < text_indent_len; ti++) {
- if (theline[ti] != text_indent[ti]) {
- break;
- }
+ for (ti = 0; ti < text_indent_len; ti++) {
+ if (theline[ti] != text_indent[ti]) {
+ break;
}
+ }
}
tv_list_append_string(l, (char *)(theline + ti), -1);
@@ -1368,14 +1363,14 @@ void ex_let(exarg_T *eap)
static void ex_let_const(exarg_T *eap, const bool is_const)
{
- char_u *arg = eap->arg;
- char_u *expr = NULL;
+ char_u *arg = eap->arg;
+ char_u *expr = NULL;
typval_T rettv;
int i;
int var_count = 0;
int semicolon = 0;
char_u op[2];
- char_u *argend;
+ char_u *argend;
int first = TRUE;
argend = (char_u *)skip_var_list(arg, &var_count, &semicolon);
@@ -1433,8 +1428,9 @@ static void ex_let_const(exarg_T *eap, const bool is_const)
expr = skipwhite(expr + 1);
}
- if (eap->skip)
+ if (eap->skip) {
++emsg_skip;
+ }
i = eval0(expr, &rettv, &eap->nextcmd, !eap->skip);
if (eap->skip) {
if (i != FAIL) {
@@ -1449,24 +1445,20 @@ static void ex_let_const(exarg_T *eap, const bool is_const)
}
}
-/*
- * Assign the typevalue "tv" to the variable or variables at "arg_start".
- * Handles both "var" with any type and "[var, var; var]" with a list type.
- * When "nextchars" is not NULL it points to a string with characters that
- * must appear after the variable(s). Use "+", "-" or "." for add, subtract
- * or concatenate.
- * Returns OK or FAIL;
- */
-static int
-ex_let_vars(
- char_u *arg_start,
- typval_T *tv,
- int copy, // copy values from "tv", don't move
- int semicolon, // from skip_var_list()
- int var_count, // from skip_var_list()
- int is_const, // lock variables for :const
- char_u *nextchars
-)
+/// Assign the typevalue "tv" to the variable or variables at "arg_start".
+/// Handles both "var" with any type and "[var, var; var]" with a list type.
+/// When "op" is not NULL it points to a string with characters that
+/// must appear after the variable(s). Use "+", "-" or "." for add, subtract
+/// or concatenate.
+///
+/// @param copy copy values from "tv", don't move
+/// @param semicolon from skip_var_list()
+/// @param var_count from skip_var_list()
+/// @param is_const lock variables for :const
+///
+/// @return OK or FAIL;
+static int ex_let_vars(char_u *arg_start, typval_T *tv, int copy, int semicolon, int var_count,
+ int is_const, char_u *op)
{
char_u *arg = arg_start;
typval_T ltv;
@@ -1475,7 +1467,7 @@ ex_let_vars(
/*
* ":let var = expr" or ":for var in list"
*/
- if (ex_let_one(arg, tv, copy, is_const, nextchars, nextchars) == NULL) {
+ if (ex_let_one(arg, tv, copy, is_const, op, op) == NULL) {
return FAIL;
}
return OK;
@@ -1506,7 +1498,7 @@ ex_let_vars(
while (*arg != ']') {
arg = skipwhite(arg + 1);
arg = ex_let_one(arg, TV_LIST_ITEM_TV(item), true, is_const,
- (const char_u *)",;]", nextchars);
+ (const char_u *)",;]", op);
if (arg == NULL) {
return FAIL;
}
@@ -1528,8 +1520,8 @@ ex_let_vars(
ltv.vval.v_list = rest_list;
tv_list_ref(rest_list);
- arg = ex_let_one(skipwhite(arg + 1), &ltv, false, is_const,
- (char_u *)"]", nextchars);
+ arg = ex_let_one(skipwhite(arg + 1), &ltv, false, is_const, (char_u *)"]",
+ op);
tv_clear(&ltv);
if (arg == NULL) {
return FAIL;
@@ -1551,8 +1543,7 @@ ex_let_vars(
* for "[var, var; var]" set "semicolon".
* Return NULL for an error.
*/
-static const char_u *skip_var_list(const char_u *arg, int *var_count,
- int *semicolon)
+static const char_u *skip_var_list(const char_u *arg, int *var_count, int *semicolon)
{
const char_u *p;
const char_u *s;
@@ -1570,9 +1561,9 @@ static const char_u *skip_var_list(const char_u *arg, int *var_count,
++*var_count;
p = skipwhite(s);
- if (*p == ']')
+ if (*p == ']') {
break;
- else if (*p == ';') {
+ } else if (*p == ';') {
if (*semicolon == 1) {
EMSG(_("E452: Double ; in list of variables"));
return NULL;
@@ -1584,8 +1575,9 @@ static const char_u *skip_var_list(const char_u *arg, int *var_count,
}
}
return p + 1;
- } else
+ } else {
return skip_var_one(arg);
+ }
}
/*
@@ -1594,21 +1586,21 @@ static const char_u *skip_var_list(const char_u *arg, int *var_count,
*/
static const char_u *skip_var_one(const char_u *arg)
{
- if (*arg == '@' && arg[1] != NUL)
+ if (*arg == '@' && arg[1] != NUL) {
return arg + 2;
+ }
return find_name_end(*arg == '$' || *arg == '&' ? arg + 1 : arg,
- NULL, NULL, FNE_INCL_BR | FNE_CHECK_START);
+ NULL, NULL, FNE_INCL_BR | FNE_CHECK_START);
}
/*
* List variables for hashtab "ht" with prefix "prefix".
* If "empty" is TRUE also list NULL strings as empty strings.
*/
-void list_hashtable_vars(hashtab_T *ht, const char *prefix, int empty,
- int *first)
+void list_hashtable_vars(hashtab_T *ht, const char *prefix, int empty, int *first)
{
- hashitem_T *hi;
- dictitem_T *di;
+ hashitem_T *hi;
+ dictitem_T *di;
int todo;
todo = (int)ht->ht_used;
@@ -1725,18 +1717,27 @@ static const char *list_arg_vars(exarg_T *eap, const char *arg, int *first)
} else {
// handle d.key, l[idx], f(expr)
const char *const arg_subsc = arg;
- if (handle_subscript(&arg, &tv, true, true) == FAIL) {
+ if (handle_subscript(&arg, &tv, true, true, (const char_u *)name,
+ (const char_u **)&name)
+ == FAIL) {
error = true;
} else {
if (arg == arg_subsc && len == 2 && name[1] == ':') {
switch (*name) {
- case 'g': list_glob_vars(first); break;
- case 'b': list_buf_vars(first); break;
- case 'w': list_win_vars(first); break;
- case 't': list_tab_vars(first); break;
- case 'v': list_vim_vars(first); break;
- case 's': list_script_vars(first); break;
- case 'l': list_func_vars(first); break;
+ case 'g':
+ list_glob_vars(first); break;
+ case 'b':
+ list_buf_vars(first); break;
+ case 'w':
+ list_win_vars(first); break;
+ case 't':
+ list_tab_vars(first); break;
+ case 'v':
+ list_vim_vars(first); break;
+ case 's':
+ list_script_vars(first); break;
+ case 'l':
+ list_func_vars(first); break;
default:
EMSG2(_("E738: Can't list variables for %s"), name);
}
@@ -1779,8 +1780,7 @@ static const char *list_arg_vars(exarg_T *eap, const char *arg, int *first)
///
/// @return a pointer to the char just after the var name or NULL in case of
/// error.
-static char_u *ex_let_one(char_u *arg, typval_T *const tv,
- const bool copy, const bool is_const,
+static char_u *ex_let_one(char_u *arg, typval_T *const tv, const bool copy, const bool is_const,
const char_u *const endchars, const char_u *const op)
FUNC_ATTR_NONNULL_ARG(1, 2) FUNC_ATTR_WARN_UNUSED_RESULT
{
@@ -1838,9 +1838,9 @@ static char_u *ex_let_one(char_u *arg, typval_T *const tv,
xfree(tofree);
}
}
- // ":let &option = expr": Set option value.
- // ":let &l:option = expr": Set local option value.
- // ":let &g:option = expr": Set global option value.
+ // ":let &option = expr": Set option value.
+ // ":let &l:option = expr": Set local option value.
+ // ":let &g:option = expr": Set global option value.
} else if (*arg == '&') {
if (is_const) {
EMSG(_("E996: Cannot lock an option"));
@@ -1875,11 +1875,16 @@ static char_u *ex_let_one(char_u *arg, typval_T *const tv,
} else {
if (opt_type == 1) { // number
switch (*op) {
- case '+': n = numval + n; break;
- case '-': n = numval - n; break;
- case '*': n = numval * n; break;
- case '/': n = num_divide(numval, n); break;
- case '%': n = num_modulus(numval, n); break;
+ case '+':
+ n = numval + n; break;
+ case '-':
+ n = numval - n; break;
+ case '*':
+ n = numval * n; break;
+ case '/':
+ n = num_divide(numval, n); break;
+ case '%':
+ n = num_modulus(numval, n); break;
}
} else if (opt_type == 0 && stringval != NULL) { // string
char *const oldstringval = stringval;
@@ -1898,7 +1903,7 @@ static char_u *ex_let_one(char_u *arg, typval_T *const tv,
*p = c1;
xfree(stringval);
}
- // ":let @r = expr": Set register contents.
+ // ":let @r = expr": Set register contents.
} else if (*arg == '@') {
if (is_const) {
EMSG(_("E996: Cannot lock a register"));
@@ -1911,7 +1916,7 @@ static char_u *ex_let_one(char_u *arg, typval_T *const tv,
&& vim_strchr(endchars, *skipwhite(arg + 1)) == NULL) {
EMSG(_(e_letunexp));
} else {
- char_u *s;
+ char_u *s;
char_u *ptofree = NULL;
const char *p = tv_get_string_chk(tv);
@@ -1948,8 +1953,9 @@ static char_u *ex_let_one(char_u *arg, typval_T *const tv,
}
}
clear_lval(&lv);
- } else
+ } else {
EMSG2(_(e_invarg2), arg);
+ }
return arg_end;
}
@@ -1979,16 +1985,15 @@ static char_u *ex_let_one(char_u *arg, typval_T *const tv,
///
/// @return A pointer to just after the name, including indexes. Returns NULL
/// for a parsing error, but it is still needed to free items in lp.
-char_u *get_lval(char_u *const name, typval_T *const rettv,
- lval_T *const lp, const bool unlet, const bool skip,
- const int flags, const int fne_flags)
+char_u *get_lval(char_u *const name, typval_T *const rettv, lval_T *const lp, const bool unlet,
+ const bool skip, const int flags, const int fne_flags)
FUNC_ATTR_NONNULL_ARG(1, 3)
{
- dictitem_T *v;
+ dictitem_T *v;
typval_T var1;
typval_T var2;
int empty1 = FALSE;
- listitem_T *ni;
+ listitem_T *ni;
hashtab_T *ht = NULL;
int quiet = flags & GLV_QUIET;
@@ -2056,23 +2061,23 @@ char_u *get_lval(char_u *const name, typval_T *const rettv,
return NULL;
}
- /*
- * Loop until no more [idx] or .key is following.
- */
+ // Loop until no more [idx] or .key is following.
lp->ll_tv = &v->di_tv;
var1.v_type = VAR_UNKNOWN;
var2.v_type = VAR_UNKNOWN;
while (*p == '[' || (*p == '.' && lp->ll_tv->v_type == VAR_DICT)) {
if (!(lp->ll_tv->v_type == VAR_LIST && lp->ll_tv->vval.v_list != NULL)
- && !(lp->ll_tv->v_type == VAR_DICT
- && lp->ll_tv->vval.v_dict != NULL)) {
- if (!quiet)
- EMSG(_("E689: Can only index a List or Dictionary"));
+ && !(lp->ll_tv->v_type == VAR_DICT && lp->ll_tv->vval.v_dict != NULL)
+ && !(lp->ll_tv->v_type == VAR_BLOB && lp->ll_tv->vval.v_blob != NULL)) {
+ if (!quiet) {
+ EMSG(_("E689: Can only index a List, Dictionary or Blob"));
+ }
return NULL;
}
if (lp->ll_range) {
- if (!quiet)
+ if (!quiet) {
EMSG(_("E708: [:] must come last"));
+ }
return NULL;
}
@@ -2116,10 +2121,11 @@ char_u *get_lval(char_u *const name, typval_T *const rettv,
tv_clear(&var1);
return NULL;
}
- if (rettv != NULL && (rettv->v_type != VAR_LIST
- || rettv->vval.v_list == NULL)) {
+ if (rettv != NULL
+ && !(rettv->v_type == VAR_LIST && rettv->vval.v_list != NULL)
+ && !(rettv->v_type == VAR_BLOB && rettv->vval.v_blob != NULL)) {
if (!quiet) {
- EMSG(_("E709: [:] requires a List value"));
+ EMSG(_("E709: [:] requires a List or Blob value"));
}
tv_clear(&var1);
return NULL;
@@ -2223,7 +2229,7 @@ char_u *get_lval(char_u *const name, typval_T *const rettv,
}
tv_clear(&var1);
break;
- // existing variable, need to check if it can be changed
+ // existing variable, need to check if it can be changed
} else if (!(flags & GLV_READ_ONLY) && var_check_ro(lp->ll_di->di_flags,
(const char *)name,
(size_t)(p - name))) {
@@ -2233,6 +2239,38 @@ char_u *get_lval(char_u *const name, typval_T *const rettv,
tv_clear(&var1);
lp->ll_tv = &lp->ll_di->di_tv;
+ } else if (lp->ll_tv->v_type == VAR_BLOB) {
+ // Get the number and item for the only or first index of the List.
+ if (empty1) {
+ lp->ll_n1 = 0;
+ } else {
+ // Is number or string.
+ lp->ll_n1 = (long)tv_get_number(&var1);
+ }
+ tv_clear(&var1);
+
+ const int bloblen = tv_blob_len(lp->ll_tv->vval.v_blob);
+ if (lp->ll_n1 < 0 || lp->ll_n1 > bloblen
+ || (lp->ll_range && lp->ll_n1 == bloblen)) {
+ if (!quiet) {
+ EMSGN(_(e_blobidx), lp->ll_n1);
+ }
+ tv_clear(&var2);
+ return NULL;
+ }
+ if (lp->ll_range && !lp->ll_empty2) {
+ lp->ll_n2 = (long)tv_get_number(&var2);
+ tv_clear(&var2);
+ if (lp->ll_n2 < 0 || lp->ll_n2 >= bloblen || lp->ll_n2 < lp->ll_n1) {
+ if (!quiet) {
+ EMSGN(_(e_blobidx), lp->ll_n2);
+ }
+ return NULL;
+ }
+ }
+ lp->ll_blob = lp->ll_tv->vval.v_blob;
+ lp->ll_tv = NULL;
+ break;
} else {
// Get the number and item for the only or first index of the List.
if (empty1) {
@@ -2270,8 +2308,9 @@ char_u *get_lval(char_u *const name, typval_T *const rettv,
if (lp->ll_n2 < 0) {
ni = tv_list_find(lp->ll_list, lp->ll_n2);
if (ni == NULL) {
- if (!quiet)
+ if (!quiet) {
EMSGN(_(e_listidx), lp->ll_n2);
+ }
return NULL;
}
lp->ll_n2 = tv_list_idx_of_item(lp->ll_list, ni);
@@ -2316,17 +2355,60 @@ void clear_lval(lval_T *lp)
* "op" is NULL, "+" for "+=", "-" for "-=", "*" for "*=", "/" for "/=",
* "%" for "%=", "." for ".=" or "=" for "=".
*/
-static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv,
- int copy, const bool is_const, const char *op)
+static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, const bool is_const,
+ const char *op)
{
int cc;
- listitem_T *ri;
- dictitem_T *di;
+ listitem_T *ri;
+ dictitem_T *di;
if (lp->ll_tv == NULL) {
cc = *endp;
*endp = NUL;
- if (op != NULL && *op != '=') {
+ if (lp->ll_blob != NULL) {
+ if (op != NULL && *op != '=') {
+ EMSG2(_(e_letwrong), op);
+ return;
+ }
+ if (var_check_lock(lp->ll_blob->bv_lock, lp->ll_name, TV_CSTRING)) {
+ return;
+ }
+
+ if (lp->ll_range && rettv->v_type == VAR_BLOB) {
+ if (lp->ll_empty2) {
+ lp->ll_n2 = tv_blob_len(lp->ll_blob) - 1;
+ }
+
+ if (lp->ll_n2 - lp->ll_n1 + 1 != tv_blob_len(rettv->vval.v_blob)) {
+ EMSG(_("E972: Blob value does not have the right number of bytes"));
+ return;
+ }
+ if (lp->ll_empty2) {
+ lp->ll_n2 = tv_blob_len(lp->ll_blob);
+ }
+
+ for (int il = lp->ll_n1, ir = 0; il <= lp->ll_n2; il++) {
+ tv_blob_set(lp->ll_blob, il, tv_blob_get(rettv->vval.v_blob, ir++));
+ }
+ } else {
+ bool error = false;
+ const char_u val = tv_get_number_chk(rettv, &error);
+ if (!error) {
+ garray_T *const gap = &lp->ll_blob->bv_ga;
+
+ // Allow for appending a byte. Setting a byte beyond
+ // the end is an error otherwise.
+ if (lp->ll_n1 < gap->ga_len || lp->ll_n1 == gap->ga_len) {
+ ga_grow(&lp->ll_blob->bv_ga, 1);
+ tv_blob_set(lp->ll_blob, lp->ll_n1, val);
+ if (lp->ll_n1 == gap->ga_len) {
+ gap->ga_len++;
+ }
+ }
+ // error for invalid range was already given in get_lval()
+ }
+ }
+ } else if (op != NULL && *op != '=') {
typval_T tv;
if (is_const) {
@@ -2483,16 +2565,17 @@ notify:
*/
void *eval_for_line(const char_u *arg, bool *errp, char_u **nextcmdp, int skip)
{
- forinfo_T *fi = xcalloc(1, sizeof(forinfo_T));
+ forinfo_T *fi = xcalloc(1, sizeof(forinfo_T));
const char_u *expr;
typval_T tv;
- list_T *l;
+ list_T *l;
*errp = true; // Default: there is an error.
expr = skip_var_list(arg, &fi->fi_varcount, &fi->fi_semicolon);
- if (expr == NULL)
+ if (expr == NULL) {
return fi;
+ }
expr = skipwhite(expr);
if (expr[0] != 'i' || expr[1] != 'n' || !ascii_iswhite(expr[2])) {
@@ -2500,29 +2583,44 @@ void *eval_for_line(const char_u *arg, bool *errp, char_u **nextcmdp, int skip)
return fi;
}
- if (skip)
+ if (skip) {
++emsg_skip;
+ }
if (eval0(skipwhite(expr + 2), &tv, nextcmdp, !skip) == OK) {
*errp = false;
if (!skip) {
- l = tv.vval.v_list;
- if (tv.v_type != VAR_LIST) {
- EMSG(_(e_listreq));
- tv_clear(&tv);
- } else if (l == NULL) {
- // a null list is like an empty list: do nothing
+ if (tv.v_type == VAR_LIST) {
+ l = tv.vval.v_list;
+ if (l == NULL) {
+ // a null list is like an empty list: do nothing
+ tv_clear(&tv);
+ } else {
+ // No need to increment the refcount, it's already set for
+ // the list being used in "tv".
+ fi->fi_list = l;
+ tv_list_watch_add(l, &fi->fi_lw);
+ fi->fi_lw.lw_item = tv_list_first(l);
+ }
+ } else if (tv.v_type == VAR_BLOB) {
+ fi->fi_bi = 0;
+ if (tv.vval.v_blob != NULL) {
+ typval_T btv;
+
+ // Make a copy, so that the iteration still works when the
+ // blob is changed.
+ tv_blob_copy(&tv, &btv);
+ fi->fi_blob = btv.vval.v_blob;
+ }
tv_clear(&tv);
} else {
- /* No need to increment the refcount, it's already set for the
- * list being used in "tv". */
- fi->fi_list = l;
- tv_list_watch_add(l, &fi->fi_lw);
- fi->fi_lw.lw_item = tv_list_first(l);
+ EMSG(_(e_listblobreq));
+ tv_clear(&tv);
}
}
}
- if (skip)
+ if (skip) {
--emsg_skip;
+ }
return fi;
}
@@ -2539,6 +2637,19 @@ bool next_for_item(void *fi_void, char_u *arg)
{
forinfo_T *fi = (forinfo_T *)fi_void;
+ if (fi->fi_blob != NULL) {
+ if (fi->fi_bi >= tv_blob_len(fi->fi_blob)) {
+ return false;
+ }
+ typval_T tv;
+ tv.v_type = VAR_NUMBER;
+ tv.v_lock = VAR_FIXED;
+ tv.vval.v_number = tv_blob_get(fi->fi_blob, fi->fi_bi);
+ fi->fi_bi++;
+ return ex_let_vars(arg, &tv, true,
+ fi->fi_semicolon, fi->fi_varcount, false, NULL) == OK;
+ }
+
listitem_T *item = fi->fi_lw.lw_item;
if (item == NULL) {
return false;
@@ -2556,12 +2667,15 @@ bool next_for_item(void *fi_void, char_u *arg)
*/
void free_for_info(void *fi_void)
{
- forinfo_T *fi = (forinfo_T *)fi_void;
+ forinfo_T *fi = (forinfo_T *)fi_void;
if (fi != NULL && fi->fi_list != NULL) {
tv_list_watch_remove(fi->fi_list, &fi->fi_lw);
tv_list_unref(fi->fi_list);
}
+ if (fi != NULL && fi->fi_blob != NULL) {
+ tv_blob_unref(fi->fi_blob);
+ }
xfree(fi);
}
@@ -2571,7 +2685,7 @@ void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx)
{
int got_eq = FALSE;
int c;
- char_u *p;
+ char_u *p;
if (cmdidx == CMD_let || cmdidx == CMD_const) {
xp->xp_context = EXPAND_USER_VARS;
@@ -2586,11 +2700,12 @@ void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx)
}
return;
}
- } else
+ } else {
xp->xp_context = cmdidx == CMD_call ? EXPAND_FUNCTIONS
- : EXPAND_EXPRESSION;
+ : EXPAND_EXPRESSION;
+ }
while ((xp->xp_pattern = vim_strpbrk(arg,
- (char_u *)"\"'+-*/%.=!?~|&$([<>,#")) != NULL) {
+ (char_u *)"\"'+-*/%.=!?~|&$([<>,#")) != NULL) {
c = *xp->xp_pattern;
if (c == '&') {
c = xp->xp_pattern[1];
@@ -2600,9 +2715,9 @@ void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx)
? EXPAND_EXPRESSION : EXPAND_NOTHING;
} else if (c != ' ') {
xp->xp_context = EXPAND_SETTINGS;
- if ((c == 'l' || c == 'g') && xp->xp_pattern[2] == ':')
+ if ((c == 'l' || c == 'g') && xp->xp_pattern[2] == ':') {
xp->xp_pattern += 2;
-
+ }
}
} else if (c == '$') {
// environment variable
@@ -2636,14 +2751,17 @@ void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx)
if (xp->xp_pattern[1] == '|') {
++xp->xp_pattern;
xp->xp_context = EXPAND_EXPRESSION;
- } else
+ } else {
xp->xp_context = EXPAND_COMMANDS;
- } else
+ }
+ } else {
xp->xp_context = EXPAND_EXPRESSION;
- } else
+ }
+ } else {
/* Doesn't look like something valid, expand as an expression
* anyway. */
xp->xp_context = EXPAND_EXPRESSION;
+ }
arg = xp->xp_pattern;
if (*arg != NUL) {
while ((c = *++arg) != NUL && (c == ' ' || c == '\t')) {
@@ -2705,8 +2823,7 @@ void ex_lockvar(exarg_T *eap)
/// @param[in] deep Levels to (un)lock for :(un)lockvar, -1 to (un)lock
/// everything.
/// @param[in] callback Appropriate handler for the command.
-static void ex_unletlock(exarg_T *eap, char_u *argstart, int deep,
- ex_unletlock_callback callback)
+static void ex_unletlock(exarg_T *eap, char_u *argstart, int deep, ex_unletlock_callback callback)
FUNC_ATTR_NONNULL_ALL
{
char_u *arg = argstart;
@@ -2770,8 +2887,7 @@ static void ex_unletlock(exarg_T *eap, char_u *argstart, int deep,
/// @param[in] deep Unused.
///
/// @return OK on success, or FAIL on failure.
-static int do_unlet_var(lval_T *lp, char_u *name_end, exarg_T *eap,
- int deep FUNC_ATTR_UNUSED)
+static int do_unlet_var(lval_T *lp, char_u *name_end, exarg_T *eap, int deep FUNC_ATTR_UNUSED)
FUNC_ATTR_NONNULL_ALL
{
int forceit = eap->forceit;
@@ -2875,7 +2991,7 @@ int do_unlet(const char *const name, const size_t name_len, const bool forceit)
if (ht == &globvarht) {
d = &globvardict;
} else if (ht == &compat_hashtab) {
- d = &vimvardict;
+ d = &vimvardict;
} else {
dictitem_T *const di = find_var_in_ht(ht, *name, "", 0, false);
d = di->di_tv.vval.v_dict;
@@ -2918,8 +3034,9 @@ int do_unlet(const char *const name, const size_t name_len, const bool forceit)
return OK;
}
}
- if (forceit)
+ if (forceit) {
return OK;
+ }
EMSG2(_("E108: No such variable: \"%s\""), name);
return FAIL;
}
@@ -2936,8 +3053,7 @@ int do_unlet(const char *const name, const size_t name_len, const bool forceit)
/// @param[in] deep Levels to (un)lock, -1 to (un)lock everything.
///
/// @return OK on success, or FAIL on failure.
-static int do_lock_var(lval_T *lp, char_u *name_end FUNC_ATTR_UNUSED,
- exarg_T *eap, int deep)
+static int do_lock_var(lval_T *lp, char_u *name_end FUNC_ATTR_UNUSED, exarg_T *eap, int deep)
FUNC_ATTR_NONNULL_ARG(1, 3)
{
bool lock = eap->cmdidx == CMD_lockvar;
@@ -2953,9 +3069,8 @@ static int do_lock_var(lval_T *lp, char_u *name_end FUNC_ATTR_UNUSED,
ret = FAIL;
} else {
// Normal name or expanded name.
- dictitem_T *const di = find_var(
- (const char *)lp->ll_name, lp->ll_name_len, NULL,
- true);
+ dictitem_T *const di = find_var((const char *)lp->ll_name, lp->ll_name_len, NULL,
+ true);
if (di == NULL) {
ret = FAIL;
} else if ((di->di_flags & DI_FLAGS_FIX)
@@ -2971,24 +3086,24 @@ static int do_lock_var(lval_T *lp, char_u *name_end FUNC_ATTR_UNUSED,
} else {
di->di_flags &= ~DI_FLAGS_LOCK;
}
- tv_item_lock(&di->di_tv, deep, lock);
+ tv_item_lock(&di->di_tv, deep, lock, false);
}
}
} else if (lp->ll_range) {
- listitem_T *li = lp->ll_li;
+ listitem_T *li = lp->ll_li;
// (un)lock a range of List items.
while (li != NULL && (lp->ll_empty2 || lp->ll_n2 >= lp->ll_n1)) {
- tv_item_lock(TV_LIST_ITEM_TV(li), deep, lock);
+ tv_item_lock(TV_LIST_ITEM_TV(li), deep, lock, false);
li = TV_LIST_ITEM_NEXT(lp->ll_list, li);
lp->ll_n1++;
}
} else if (lp->ll_list != NULL) {
// (un)lock a List item.
- tv_item_lock(TV_LIST_ITEM_TV(lp->ll_li), deep, lock);
+ tv_item_lock(TV_LIST_ITEM_TV(lp->ll_li), deep, lock, false);
} else {
// (un)lock a Dictionary item.
- tv_item_lock(&lp->ll_di->di_tv, deep, lock);
+ tv_item_lock(&lp->ll_di->di_tv, deep, lock, false);
}
return ret;
@@ -3015,7 +3130,7 @@ void del_menutrans_vars(void)
*/
-static char_u *varnamebuf = NULL;
+static char_u *varnamebuf = NULL;
static size_t varnamebuflen = 0;
/*
@@ -3049,7 +3164,7 @@ char_u *get_user_var_name(expand_T *xp, int idx)
static size_t wdone;
static size_t tdone;
static size_t vidx;
- static hashitem_T *hi;
+ static hashitem_T *hi;
if (idx == 0) {
gdone = bdone = wdone = vidx = 0;
@@ -3058,14 +3173,17 @@ char_u *get_user_var_name(expand_T *xp, int idx)
// Global variables
if (gdone < globvarht.ht_used) {
- if (gdone++ == 0)
+ if (gdone++ == 0) {
hi = globvarht.ht_array;
- else
+ } else {
++hi;
- while (HASHITEM_EMPTY(hi))
+ }
+ while (HASHITEM_EMPTY(hi)) {
++hi;
- if (STRNCMP("g:", xp->xp_pattern, 2) == 0)
+ }
+ if (STRNCMP("g:", xp->xp_pattern, 2) == 0) {
return cat_prefix_varname('g', hi->hi_key);
+ }
return hi->hi_key;
}
@@ -3075,12 +3193,14 @@ char_u *get_user_var_name(expand_T *xp, int idx)
? &prevwin->w_buffer->b_vars->dv_hashtab
: &curbuf->b_vars->dv_hashtab;
if (bdone < ht->ht_used) {
- if (bdone++ == 0)
+ if (bdone++ == 0) {
hi = ht->ht_array;
- else
+ } else {
++hi;
- while (HASHITEM_EMPTY(hi))
+ }
+ while (HASHITEM_EMPTY(hi)) {
++hi;
+ }
return cat_prefix_varname('b', hi->hi_key);
}
@@ -3090,24 +3210,28 @@ char_u *get_user_var_name(expand_T *xp, int idx)
? &prevwin->w_vars->dv_hashtab
: &curwin->w_vars->dv_hashtab;
if (wdone < ht->ht_used) {
- if (wdone++ == 0)
+ if (wdone++ == 0) {
hi = ht->ht_array;
- else
+ } else {
++hi;
- while (HASHITEM_EMPTY(hi))
+ }
+ while (HASHITEM_EMPTY(hi)) {
++hi;
+ }
return cat_prefix_varname('w', hi->hi_key);
}
// t: variables
ht = &curtab->tp_vars->dv_hashtab;
if (tdone < ht->ht_used) {
- if (tdone++ == 0)
+ if (tdone++ == 0) {
hi = ht->ht_array;
- else
+ } else {
++hi;
- while (HASHITEM_EMPTY(hi))
+ }
+ while (HASHITEM_EMPTY(hi)) {
++hi;
+ }
return cat_prefix_varname('t', hi->hi_key);
}
@@ -3143,6 +3267,64 @@ static int pattern_match(char_u *pat, char_u *text, bool ic)
return matches;
}
+/// Handle a name followed by "(". Both for just "name(arg)" and for
+/// "expr->name(arg)".
+//
+/// @param arg Points to "(", will be advanced
+/// @param basetv "expr" for "expr->name(arg)"
+//
+/// @return OK or FAIL.
+static int eval_func(char_u **const arg, char_u *const name, const int name_len,
+ typval_T *const rettv, const bool evaluate, typval_T *const basetv)
+ FUNC_ATTR_NONNULL_ARG(1, 2, 4)
+{
+ char_u *s = name;
+ int len = name_len;
+
+ if (!evaluate) {
+ check_vars((const char *)s, len);
+ }
+
+ // If "s" is the name of a variable of type VAR_FUNC
+ // use its contents.
+ partial_T *partial;
+ s = deref_func_name((const char *)s, &len, &partial, !evaluate);
+
+ // Need to make a copy, in case evaluating the arguments makes
+ // the name invalid.
+ s = xmemdupz(s, len);
+
+ // Invoke the function.
+ funcexe_T funcexe = FUNCEXE_INIT;
+ funcexe.firstline = curwin->w_cursor.lnum;
+ funcexe.lastline = curwin->w_cursor.lnum;
+ funcexe.evaluate = evaluate;
+ funcexe.partial = partial;
+ funcexe.basetv = basetv;
+ int ret = get_func_tv(s, len, rettv, arg, &funcexe);
+
+ xfree(s);
+
+ // If evaluate is false rettv->v_type was not set in
+ // get_func_tv, but it's needed in handle_subscript() to parse
+ // what follows. So set it here.
+ if (rettv->v_type == VAR_UNKNOWN && !evaluate && **arg == '(') {
+ rettv->vval.v_string = (char_u *)tv_empty_string;
+ rettv->v_type = VAR_FUNC;
+ }
+
+ // Stop the expression evaluation when immediately
+ // aborting on error, or when an interrupt occurred or
+ // an exception was thrown but not caught.
+ if (evaluate && aborting()) {
+ if (ret == OK) {
+ tv_clear(rettv);
+ }
+ ret = FAIL;
+ }
+ return ret;
+}
+
// TODO(ZyX-I): move to eval/expressions
/*
@@ -3161,7 +3343,9 @@ static int pattern_match(char_u *pat, char_u *text, bool ic)
int eval0(char_u *arg, typval_T *rettv, char_u **nextcmd, int evaluate)
{
int ret;
- char_u *p;
+ char_u *p;
+ const int did_emsg_before = did_emsg;
+ const int called_emsg_before = called_emsg;
p = skipwhite(arg);
ret = eval1(&p, rettv, evaluate);
@@ -3171,14 +3355,17 @@ int eval0(char_u *arg, typval_T *rettv, char_u **nextcmd, int evaluate)
}
// Report the invalid expression unless the expression evaluation has
// been cancelled due to an aborting error, an interrupt, or an
- // exception.
- if (!aborting()) {
+ // exception, or we already gave a more specific error.
+ // Also check called_emsg for when using assert_fails().
+ if (!aborting() && did_emsg == did_emsg_before
+ && called_emsg == called_emsg_before) {
emsgf(_(e_invexpr2), arg);
}
ret = FAIL;
}
- if (nextcmd != NULL)
+ if (nextcmd != NULL) {
*nextcmd = check_nextcmd(p);
+ }
return ret;
}
@@ -3187,7 +3374,7 @@ int eval0(char_u *arg, typval_T *rettv, char_u **nextcmd, int evaluate)
/*
* Handle top level expression:
- * expr2 ? expr1 : expr1
+ * expr2 ? expr1 : expr1
*
* "arg" must point to the first non-white of the expression.
* "arg" is advanced to the next non-white after the recognized expression.
@@ -3204,8 +3391,9 @@ int eval1(char_u **arg, typval_T *rettv, int evaluate)
/*
* Get the first variable.
*/
- if (eval2(arg, rettv, evaluate) == FAIL)
+ if (eval2(arg, rettv, evaluate) == FAIL) {
return FAIL;
+ }
if ((*arg)[0] == '?') {
result = FALSE;
@@ -3250,8 +3438,9 @@ int eval1(char_u **arg, typval_T *rettv, int evaluate)
}
return FAIL;
}
- if (evaluate && !result)
+ if (evaluate && !result) {
*rettv = var2;
+ }
}
return OK;
@@ -3261,7 +3450,7 @@ int eval1(char_u **arg, typval_T *rettv, int evaluate)
/*
* Handle first level expression:
- * expr2 || expr2 || expr2 logical OR
+ * expr2 || expr2 || expr2 logical OR
*
* "arg" must point to the first non-white of the expression.
* "arg" is advanced to the next non-white after the recognized expression.
@@ -3278,8 +3467,9 @@ static int eval2(char_u **arg, typval_T *rettv, int evaluate)
/*
* Get the first variable.
*/
- if (eval3(arg, rettv, evaluate) == FAIL)
+ if (eval3(arg, rettv, evaluate) == FAIL) {
return FAIL;
+ }
/*
* Repeat until there is no following "||".
@@ -3302,8 +3492,9 @@ static int eval2(char_u **arg, typval_T *rettv, int evaluate)
* Get the second variable.
*/
*arg = skipwhite(*arg + 2);
- if (eval3(arg, &var2, evaluate && !result) == FAIL)
+ if (eval3(arg, &var2, evaluate && !result) == FAIL) {
return FAIL;
+ }
/*
* Compute the result.
@@ -3330,7 +3521,7 @@ static int eval2(char_u **arg, typval_T *rettv, int evaluate)
/*
* Handle second level expression:
- * expr3 && expr3 && expr3 logical AND
+ * expr3 && expr3 && expr3 logical AND
*
* "arg" must point to the first non-white of the expression.
* "arg" is advanced to the next non-white after the recognized expression.
@@ -3347,8 +3538,9 @@ static int eval3(char_u **arg, typval_T *rettv, int evaluate)
/*
* Get the first variable.
*/
- if (eval4(arg, rettv, evaluate) == FAIL)
+ if (eval4(arg, rettv, evaluate) == FAIL) {
return FAIL;
+ }
/*
* Repeat until there is no following "&&".
@@ -3371,8 +3563,9 @@ static int eval3(char_u **arg, typval_T *rettv, int evaluate)
* Get the second variable.
*/
*arg = skipwhite(*arg + 2);
- if (eval4(arg, &var2, evaluate && result) == FAIL)
+ if (eval4(arg, &var2, evaluate && result) == FAIL) {
return FAIL;
+ }
/*
* Compute the result.
@@ -3399,16 +3592,16 @@ static int eval3(char_u **arg, typval_T *rettv, int evaluate)
/*
* Handle third level expression:
- * var1 == var2
- * var1 =~ var2
- * var1 != var2
- * var1 !~ var2
- * var1 > var2
- * var1 >= var2
- * var1 < var2
- * var1 <= var2
- * var1 is var2
- * var1 isnot var2
+ * var1 == var2
+ * var1 =~ var2
+ * var1 != var2
+ * var1 !~ var2
+ * var1 > var2
+ * var1 >= var2
+ * var1 < var2
+ * var1 <= var2
+ * var1 is var2
+ * var1 isnot var2
*
* "arg" must point to the first non-white of the expression.
* "arg" is advanced to the next non-white after the recognized expression.
@@ -3418,7 +3611,7 @@ static int eval3(char_u **arg, typval_T *rettv, int evaluate)
static int eval4(char_u **arg, typval_T *rettv, int evaluate)
{
typval_T var2;
- char_u *p;
+ char_u *p;
exprtype_T type = EXPR_UNKNOWN;
int len = 2;
bool ic;
@@ -3426,8 +3619,9 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate)
/*
* Get the first variable.
*/
- if (eval5(arg, rettv, evaluate) == FAIL)
+ if (eval5(arg, rettv, evaluate) == FAIL) {
return FAIL;
+ }
p = *arg;
switch (p[0]) {
@@ -3461,14 +3655,15 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate)
type = EXPR_SEQUAL;
}
break;
- case 'i': if (p[1] == 's') {
+ case 'i':
+ if (p[1] == 's') {
if (p[2] == 'n' && p[3] == 'o' && p[4] == 't') {
len = 5;
}
if (!isalnum(p[len]) && p[len] != '_') {
type = len == 2 ? EXPR_IS : EXPR_ISNOT;
}
- }
+ }
break;
}
@@ -3508,10 +3703,10 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate)
/*
* Handle fourth level expression:
- * + number addition
- * - number subtraction
- * . string concatenation
- * .. string concatenation
+ * + number addition
+ * - number subtraction
+ * . string concatenation
+ * .. string concatenation
*
* "arg" must point to the first non-white of the expression.
* "arg" is advanced to the next non-white after the recognized expression.
@@ -3525,23 +3720,25 @@ static int eval5(char_u **arg, typval_T *rettv, int evaluate)
int op;
varnumber_T n1, n2;
float_T f1 = 0, f2 = 0;
- char_u *p;
+ char_u *p;
/*
* Get the first variable.
*/
- if (eval6(arg, rettv, evaluate, FALSE) == FAIL)
+ if (eval6(arg, rettv, evaluate, FALSE) == FAIL) {
return FAIL;
+ }
/*
* Repeat computing, until no '+', '-' or '.' is following.
*/
for (;; ) {
op = **arg;
- if (op != '+' && op != '-' && op != '.')
+ if (op != '+' && op != '-' && op != '.') {
break;
+ }
- if ((op != '+' || rettv->v_type != VAR_LIST)
+ if ((op != '+' || (rettv->v_type != VAR_LIST && rettv->v_type != VAR_BLOB))
&& (op == '.' || rettv->v_type != VAR_FLOAT)) {
// For "list + ...", an illegal use of the first operand as
// a number cannot be determined before evaluating the 2nd
@@ -3587,6 +3784,21 @@ static int eval5(char_u **arg, typval_T *rettv, int evaluate)
tv_clear(rettv);
rettv->v_type = VAR_STRING;
rettv->vval.v_string = p;
+ } else if (op == '+' && rettv->v_type == VAR_BLOB
+ && var2.v_type == VAR_BLOB) {
+ const blob_T *const b1 = rettv->vval.v_blob;
+ const blob_T *const b2 = var2.vval.v_blob;
+ blob_T *const b = tv_blob_alloc();
+
+ for (int i = 0; i < tv_blob_len(b1); i++) {
+ ga_append(&b->bv_ga, tv_blob_get(b1, i));
+ }
+ for (int i = 0; i < tv_blob_len(b2); i++) {
+ ga_append(&b->bv_ga, tv_blob_get(b2, i));
+ }
+
+ tv_clear(rettv);
+ tv_blob_set_ret(rettv, b);
} else if (op == '+' && rettv->v_type == VAR_LIST
&& var2.v_type == VAR_LIST) {
// Concatenate Lists.
@@ -3607,14 +3819,17 @@ static int eval5(char_u **arg, typval_T *rettv, int evaluate)
} else {
n1 = tv_get_number_chk(rettv, &error);
if (error) {
- /* This can only happen for "list + non-list". For
- * "non-list + ..." or "something - ...", we returned
- * before evaluating the 2nd operand. */
+ // This can only happen for "list + non-list" or
+ // "blob + non-blob". For "non-list + ..." or
+ // "something - ...", we returned before evaluating the
+ // 2nd operand.
tv_clear(rettv);
+ tv_clear(&var2);
return FAIL;
}
- if (var2.v_type == VAR_FLOAT)
+ if (var2.v_type == VAR_FLOAT) {
f1 = n1;
+ }
}
if (var2.v_type == VAR_FLOAT) {
f2 = var2.vval.v_float;
@@ -3626,24 +3841,27 @@ static int eval5(char_u **arg, typval_T *rettv, int evaluate)
tv_clear(&var2);
return FAIL;
}
- if (rettv->v_type == VAR_FLOAT)
+ if (rettv->v_type == VAR_FLOAT) {
f2 = n2;
+ }
}
tv_clear(rettv);
// If there is a float on either side the result is a float.
if (rettv->v_type == VAR_FLOAT || var2.v_type == VAR_FLOAT) {
- if (op == '+')
+ if (op == '+') {
f1 = f1 + f2;
- else
+ } else {
f1 = f1 - f2;
+ }
rettv->v_type = VAR_FLOAT;
rettv->vval.v_float = f1;
} else {
- if (op == '+')
+ if (op == '+') {
n1 = n1 + n2;
- else
+ } else {
n1 = n1 - n2;
+ }
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = n1;
}
@@ -3682,8 +3900,9 @@ static int eval6(char_u **arg, typval_T *rettv, int evaluate, int want_string)
/*
* Get the first variable.
*/
- if (eval7(arg, rettv, evaluate, want_string) == FAIL)
+ if (eval7(arg, rettv, evaluate, want_string) == FAIL) {
return FAIL;
+ }
/*
* Repeat computing, until no '*', '/' or '%' is following.
@@ -3714,8 +3933,9 @@ static int eval6(char_u **arg, typval_T *rettv, int evaluate, int want_string)
* Get the second variable.
*/
*arg = skipwhite(*arg + 1);
- if (eval7(arg, &var2, evaluate, FALSE) == FAIL)
+ if (eval7(arg, &var2, evaluate, FALSE) == FAIL) {
return FAIL;
+ }
if (evaluate) {
if (var2.v_type == VAR_FLOAT) {
@@ -3748,15 +3968,15 @@ static int eval6(char_u **arg, typval_T *rettv, int evaluate, int want_string)
f1 = (f2 == 0
? (
#ifdef NAN
- f1 == 0
+ f1 == 0
? NAN
:
#endif
- (f1 > 0
+ (f1 > 0
? INFINITY
: -INFINITY)
- )
- : f1 / f2);
+ )
+ : f1 / f2);
} else {
EMSG(_("E804: Cannot use '%' with Float"));
return FAIL;
@@ -3782,44 +4002,43 @@ static int eval6(char_u **arg, typval_T *rettv, int evaluate, int want_string)
// TODO(ZyX-I): move to eval/expressions
-// Handle sixth level expression:
-// number number constant
-// "string" string constant
-// 'string' literal string constant
-// &option-name option value
-// @r register contents
-// identifier variable value
-// function() function call
-// $VAR environment variable
-// (expression) nested expression
-// [expr, expr] List
-// {key: val, key: val} Dictionary
-// #{key: val, key: val} Dictionary with literal keys
-//
-// Also handle:
-// ! in front logical NOT
-// - in front unary minus
-// + in front unary plus (ignored)
-// trailing [] subscript in String or List
-// trailing .name entry in Dictionary
-//
-// "arg" must point to the first non-white of the expression.
-// "arg" is advanced to the next non-white after the recognized expression.
-//
-// Return OK or FAIL.
-static int eval7(
- char_u **arg,
- typval_T *rettv,
- int evaluate,
- int want_string // after "." operator
-)
+/// Handle sixth level expression:
+/// number number constant
+/// 0zFFFFFFFF Blob constant
+/// "string" string constant
+/// 'string' literal string constant
+/// &option-name option value
+/// @r register contents
+/// identifier variable value
+/// function() function call
+/// $VAR environment variable
+/// (expression) nested expression
+/// [expr, expr] List
+/// {key: val, key: val} Dictionary
+/// #{key: val, key: val} Dictionary with literal keys
+///
+/// Also handle:
+/// ! in front logical NOT
+/// - in front unary minus
+/// + in front unary plus (ignored)
+/// trailing [] subscript in String or List
+/// trailing .name entry in Dictionary
+/// trailing ->name() method call
+///
+/// "arg" must point to the first non-white of the expression.
+/// "arg" is advanced to the next non-white after the recognized expression.
+///
+/// @param want_string after "." operator
+///
+/// @return OK or FAIL.
+static int eval7(char_u **arg, typval_T *rettv, int evaluate, int want_string)
{
varnumber_T n;
int len;
- char_u *s;
- char_u *start_leader, *end_leader;
+ char_u *s;
+ const char_u *start_leader, *end_leader;
int ret = OK;
- char_u *alias;
+ char_u *alias;
// Initialise variable so that tv_clear() can't mistake this for a
// string and free a string that isn't there.
@@ -3843,8 +4062,7 @@ static int eval7(
case '6':
case '7':
case '8':
- case '9':
- {
+ case '9': {
char_u *p = skipdigits(*arg + 1);
int get_float = false;
@@ -3874,13 +4092,48 @@ static int eval7(
if (get_float) {
float_T f;
- *arg += string2float((char *) *arg, &f);
+ *arg += string2float((char *)*arg, &f);
if (evaluate) {
rettv->v_type = VAR_FLOAT;
rettv->vval.v_float = f;
}
+ } else if (**arg == '0' && ((*arg)[1] == 'z' || (*arg)[1] == 'Z')) {
+ blob_T *blob = NULL;
+ // Blob constant: 0z0123456789abcdef
+ if (evaluate) {
+ blob = tv_blob_alloc();
+ }
+ char_u *bp;
+ for (bp = *arg + 2; ascii_isxdigit(bp[0]); bp += 2) {
+ if (!ascii_isxdigit(bp[1])) {
+ if (blob != NULL) {
+ EMSG(_("E973: Blob literal should have an even number of hex "
+ "characters"));
+ ga_clear(&blob->bv_ga);
+ XFREE_CLEAR(blob);
+ }
+ ret = FAIL;
+ break;
+ }
+ if (blob != NULL) {
+ ga_append(&blob->bv_ga, (hex2nr(*bp) << 4) + hex2nr(*(bp + 1)));
+ }
+ if (bp[2] == '.' && ascii_isxdigit(bp[3])) {
+ bp++;
+ }
+ }
+ if (blob != NULL) {
+ tv_blob_set_ret(rettv, blob);
+ }
+ *arg = bp;
} else {
- vim_str2nr(*arg, NULL, &len, STR2NR_ALL, &n, NULL, 0);
+ // decimal, hex or octal number
+ vim_str2nr(*arg, NULL, &len, STR2NR_ALL, &n, NULL, 0, true);
+ if (len == 0) {
+ EMSG2(_(e_invexpr2), *arg);
+ ret = FAIL;
+ break;
+ }
*arg += len;
if (evaluate) {
rettv->v_type = VAR_NUMBER;
@@ -3891,15 +4144,18 @@ static int eval7(
}
// String constant: "string".
- case '"': ret = get_string_tv(arg, rettv, evaluate);
+ case '"':
+ ret = get_string_tv(arg, rettv, evaluate);
break;
// Literal string constant: 'str''ing'.
- case '\'': ret = get_lit_string_tv(arg, rettv, evaluate);
+ case '\'':
+ ret = get_lit_string_tv(arg, rettv, evaluate);
break;
// List: [expr, expr]
- case '[': ret = get_list_tv(arg, rettv, evaluate);
+ case '[':
+ ret = get_list_tv(arg, rettv, evaluate);
break;
// Dictionary: #{key: val, key: val}
@@ -3914,23 +4170,25 @@ static int eval7(
// Lambda: {arg, arg -> expr}
// Dictionary: {'key': val, 'key': val}
- case '{': ret = get_lambda_tv(arg, rettv, evaluate);
- if (ret == NOTDONE) {
- ret = dict_get_tv(arg, rettv, evaluate, false);
- }
+ case '{':
+ ret = get_lambda_tv(arg, rettv, evaluate);
+ if (ret == NOTDONE) {
+ ret = dict_get_tv(arg, rettv, evaluate, false);
+ }
break;
// Option value: &name
- case '&': {
+ case '&':
ret = get_option_tv((const char **)arg, rettv, evaluate);
break;
- }
// Environment variable: $VAR.
- case '$': ret = get_env_tv(arg, rettv, evaluate);
+ case '$':
+ ret = get_env_tv(arg, rettv, evaluate);
break;
// Register contents: @r.
- case '@': ++*arg;
+ case '@':
+ ++*arg;
if (evaluate) {
rettv->v_type = VAR_STRING;
rettv->vval.v_string = get_reg_contents(**arg, kGRegExprSrc);
@@ -3941,7 +4199,8 @@ static int eval7(
break;
// nested expression: (expression).
- case '(': *arg = skipwhite(*arg + 1);
+ case '(':
+ *arg = skipwhite(*arg + 1);
ret = eval1(arg, rettv, evaluate); // recursive!
if (**arg == ')') {
++*arg;
@@ -3952,7 +4211,8 @@ static int eval7(
}
break;
- default: ret = NOTDONE;
+ default:
+ ret = NOTDONE;
break;
}
@@ -3969,44 +4229,7 @@ static int eval7(
ret = FAIL;
} else {
if (**arg == '(') { // recursive!
- partial_T *partial;
-
- if (!evaluate) {
- check_vars((const char *)s, len);
- }
-
- // If "s" is the name of a variable of type VAR_FUNC
- // use its contents.
- s = deref_func_name((const char *)s, &len, &partial, !evaluate);
-
- // Need to make a copy, in case evaluating the arguments makes
- // the name invalid.
- s = xmemdupz(s, len);
-
- // Invoke the function.
- ret = get_func_tv(s, len, rettv, arg,
- curwin->w_cursor.lnum, curwin->w_cursor.lnum,
- &len, evaluate, partial, NULL);
-
- xfree(s);
-
- // If evaluate is false rettv->v_type was not set in
- // get_func_tv, but it's needed in handle_subscript() to parse
- // what follows. So set it here.
- if (rettv->v_type == VAR_UNKNOWN && !evaluate && **arg == '(') {
- rettv->vval.v_string = (char_u *)tv_empty_string;
- rettv->v_type = VAR_FUNC;
- }
-
- // Stop the expression evaluation when immediately
- // aborting on error, or when an interrupt occurred or
- // an exception was thrown but not caught.
- if (evaluate && aborting()) {
- if (ret == OK) {
- tv_clear(rettv);
- }
- ret = FAIL;
- }
+ ret = eval_func(arg, s, len, rettv, evaluate, NULL);
} else if (evaluate) {
ret = get_var_tv((const char *)s, len, rettv, NULL, true, false);
} else {
@@ -4020,111 +4243,277 @@ static int eval7(
*arg = skipwhite(*arg);
// Handle following '[', '(' and '.' for expr[expr], expr.name,
- // expr(expr).
+ // expr(expr), expr->name(expr)
if (ret == OK) {
- ret = handle_subscript((const char **)arg, rettv, evaluate, true);
+ ret = handle_subscript((const char **)arg, rettv, evaluate, true,
+ start_leader, &end_leader);
}
// Apply logical NOT and unary '-', from right to left, ignore '+'.
if (ret == OK && evaluate && end_leader > start_leader) {
- bool error = false;
- varnumber_T val = 0;
- float_T f = 0.0;
+ ret = eval7_leader(rettv, start_leader, &end_leader);
+ }
+ return ret;
+}
+/// Apply the leading "!" and "-" before an eval7 expression to "rettv".
+/// Adjusts "end_leaderp" until it is at "start_leader".
+/// @return OK on success, FAIL on failure.
+static int eval7_leader(typval_T *const rettv, const char_u *const start_leader,
+ const char_u **const end_leaderp)
+ FUNC_ATTR_NONNULL_ALL
+{
+ const char_u *end_leader = *end_leaderp;
+ int ret = OK;
+ bool error = false;
+ varnumber_T val = 0;
+ float_T f = 0.0;
+
+ if (rettv->v_type == VAR_FLOAT) {
+ f = rettv->vval.v_float;
+ } else {
+ val = tv_get_number_chk(rettv, &error);
+ }
+ if (error) {
+ tv_clear(rettv);
+ ret = FAIL;
+ } else {
+ while (end_leader > start_leader) {
+ end_leader--;
+ if (*end_leader == '!') {
+ if (rettv->v_type == VAR_FLOAT) {
+ f = !f;
+ } else {
+ val = !val;
+ }
+ } else if (*end_leader == '-') {
+ if (rettv->v_type == VAR_FLOAT) {
+ f = -f;
+ } else {
+ val = -val;
+ }
+ }
+ }
if (rettv->v_type == VAR_FLOAT) {
- f = rettv->vval.v_float;
+ tv_clear(rettv);
+ rettv->vval.v_float = f;
} else {
- val = tv_get_number_chk(rettv, &error);
- }
- if (error) {
tv_clear(rettv);
- ret = FAIL;
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = val;
+ }
+ }
+
+ *end_leaderp = end_leader;
+ return ret;
+}
+
+/// Call the function referred to in "rettv".
+/// @param lua_funcname If `rettv` refers to a v:lua function, this must point
+/// to the name of the Lua function to call (after the
+/// "v:lua." prefix).
+/// @return OK on success, FAIL on failure.
+static int call_func_rettv(char_u **const arg, typval_T *const rettv, const bool evaluate,
+ dict_T *const selfdict, typval_T *const basetv,
+ const char_u *const lua_funcname)
+ FUNC_ATTR_NONNULL_ARG(1, 2)
+{
+ partial_T *pt = NULL;
+ typval_T functv;
+ const char_u *funcname;
+ bool is_lua = false;
+
+ // need to copy the funcref so that we can clear rettv
+ if (evaluate) {
+ functv = *rettv;
+ rettv->v_type = VAR_UNKNOWN;
+
+ // Invoke the function. Recursive!
+ if (functv.v_type == VAR_PARTIAL) {
+ pt = functv.vval.v_partial;
+ is_lua = is_luafunc(pt);
+ funcname = is_lua ? lua_funcname : partial_name(pt);
} else {
- while (end_leader > start_leader) {
- --end_leader;
- if (*end_leader == '!') {
- if (rettv->v_type == VAR_FLOAT) {
- f = !f;
- } else {
- val = !val;
- }
- } else if (*end_leader == '-') {
- if (rettv->v_type == VAR_FLOAT) {
- f = -f;
- } else {
- val = -val;
- }
- }
+ funcname = functv.vval.v_string;
+ }
+ } else {
+ funcname = (char_u *)"";
+ }
+
+ funcexe_T funcexe = FUNCEXE_INIT;
+ funcexe.firstline = curwin->w_cursor.lnum;
+ funcexe.lastline = curwin->w_cursor.lnum;
+ funcexe.evaluate = evaluate;
+ funcexe.partial = pt;
+ funcexe.selfdict = selfdict;
+ funcexe.basetv = basetv;
+ const int ret = get_func_tv(funcname, is_lua ? *arg - funcname : -1, rettv,
+ (char_u **)arg, &funcexe);
+
+ // Clear the funcref afterwards, so that deleting it while
+ // evaluating the arguments is possible (see test55).
+ if (evaluate) {
+ tv_clear(&functv);
+ }
+
+ return ret;
+}
+
+/// Evaluate "->method()".
+/// @param verbose if true, give error messages.
+/// @note "*arg" points to the '-'.
+/// @return FAIL or OK. @note "*arg" is advanced to after the ')'.
+static int eval_lambda(char_u **const arg, typval_T *const rettv, const bool evaluate,
+ const bool verbose)
+ FUNC_ATTR_NONNULL_ALL
+{
+ // Skip over the ->.
+ *arg += 2;
+ typval_T base = *rettv;
+ rettv->v_type = VAR_UNKNOWN;
+
+ int ret = get_lambda_tv(arg, rettv, evaluate);
+ if (ret == NOTDONE) {
+ return FAIL;
+ } else if (**arg != '(') {
+ if (verbose) {
+ if (*skipwhite(*arg) == '(') {
+ EMSG(_(e_nowhitespace));
+ } else {
+ EMSG2(_(e_missingparen), "lambda");
}
- if (rettv->v_type == VAR_FLOAT) {
- tv_clear(rettv);
- rettv->vval.v_float = f;
+ }
+ tv_clear(rettv);
+ ret = FAIL;
+ } else {
+ ret = call_func_rettv(arg, rettv, evaluate, NULL, &base, NULL);
+ }
+
+ // Clear the funcref afterwards, so that deleting it while
+ // evaluating the arguments is possible (see test55).
+ if (evaluate) {
+ tv_clear(&base);
+ }
+
+ return ret;
+}
+
+/// Evaluate "->method()" or "->v:lua.method()".
+/// @note "*arg" points to the '-'.
+/// @return FAIL or OK. "*arg" is advanced to after the ')'.
+static int eval_method(char_u **const arg, typval_T *const rettv, const bool evaluate,
+ const bool verbose)
+ FUNC_ATTR_NONNULL_ALL
+{
+ // Skip over the ->.
+ *arg += 2;
+ typval_T base = *rettv;
+ rettv->v_type = VAR_UNKNOWN;
+
+ // Locate the method name.
+ int len;
+ char_u *name = *arg;
+ char_u *lua_funcname = NULL;
+ if (STRNCMP(name, "v:lua.", 6) == 0) {
+ lua_funcname = name + 6;
+ *arg = (char_u *)skip_luafunc_name((const char *)lua_funcname);
+ *arg = skipwhite(*arg); // to detect trailing whitespace later
+ len = *arg - lua_funcname;
+ } else {
+ char_u *alias;
+ len = get_name_len((const char **)arg, (char **)&alias, evaluate, true);
+ if (alias != NULL) {
+ name = alias;
+ }
+ }
+
+ int ret;
+ if (len <= 0) {
+ if (verbose) {
+ if (lua_funcname == NULL) {
+ EMSG(_("E260: Missing name after ->"));
} else {
- tv_clear(rettv);
- rettv->v_type = VAR_NUMBER;
- rettv->vval.v_number = val;
+ EMSG2(_(e_invexpr2), name);
+ }
+ }
+ ret = FAIL;
+ } else {
+ if (**arg != '(') {
+ if (verbose) {
+ EMSG2(_(e_missingparen), name);
}
+ ret = FAIL;
+ } else if (ascii_iswhite((*arg)[-1])) {
+ if (verbose) {
+ EMSG(_(e_nowhitespace));
+ }
+ ret = FAIL;
+ } else if (lua_funcname != NULL) {
+ if (evaluate) {
+ rettv->v_type = VAR_PARTIAL;
+ rettv->vval.v_partial = vvlua_partial;
+ rettv->vval.v_partial->pt_refcount++;
+ }
+ ret = call_func_rettv(arg, rettv, evaluate, NULL, &base, lua_funcname);
+ } else {
+ ret = eval_func(arg, name, len, rettv, evaluate, &base);
}
}
+ // Clear the funcref afterwards, so that deleting it while
+ // evaluating the arguments is possible (see test55).
+ if (evaluate) {
+ tv_clear(&base);
+ }
+
return ret;
}
// TODO(ZyX-I): move to eval/expressions
-/*
- * Evaluate an "[expr]" or "[expr:expr]" index. Also "dict.key".
- * "*arg" points to the '[' or '.'.
- * Returns FAIL or OK. "*arg" is advanced to after the ']'.
- */
-static int
-eval_index(
- char_u **arg,
- typval_T *rettv,
- int evaluate,
- int verbose // give error messages
-)
+/// Evaluate an "[expr]" or "[expr:expr]" index. Also "dict.key".
+/// "*arg" points to the '[' or '.'.
+/// Returns FAIL or OK. "*arg" is advanced to after the ']'.
+///
+/// @param verbose give error messages
+static int eval_index(char_u **arg, typval_T *rettv, int evaluate, int verbose)
{
bool empty1 = false;
bool empty2 = false;
long n1, n2 = 0;
ptrdiff_t len = -1;
int range = false;
- char_u *key = NULL;
+ char_u *key = NULL;
switch (rettv->v_type) {
- case VAR_FUNC:
- case VAR_PARTIAL: {
- if (verbose) {
- EMSG(_("E695: Cannot index a Funcref"));
- }
- return FAIL;
- }
- case VAR_FLOAT: {
- if (verbose) {
- EMSG(_(e_float_as_string));
- }
- return FAIL;
+ case VAR_FUNC:
+ case VAR_PARTIAL:
+ if (verbose) {
+ EMSG(_("E695: Cannot index a Funcref"));
}
- case VAR_BOOL:
- case VAR_SPECIAL: {
- if (verbose) {
- EMSG(_("E909: Cannot index a special variable"));
- }
- return FAIL;
+ return FAIL;
+ case VAR_FLOAT:
+ if (verbose) {
+ EMSG(_(e_float_as_string));
}
- case VAR_UNKNOWN: {
- if (evaluate) {
- return FAIL;
- }
- FALLTHROUGH;
+ return FAIL;
+ case VAR_BOOL:
+ case VAR_SPECIAL:
+ if (verbose) {
+ EMSG(_("E909: Cannot index a special variable"));
}
- case VAR_STRING:
- case VAR_NUMBER:
- case VAR_LIST:
- case VAR_DICT: {
- break;
+ return FAIL;
+ case VAR_UNKNOWN:
+ if (evaluate) {
+ return FAIL;
}
+ FALLTHROUGH;
+ case VAR_STRING:
+ case VAR_NUMBER:
+ case VAR_LIST:
+ case VAR_DICT:
+ case VAR_BLOB:
+ break;
}
typval_T var1 = TV_INITIAL_VALUE;
@@ -4134,10 +4523,12 @@ eval_index(
* dict.name
*/
key = *arg + 1;
- for (len = 0; ASCII_ISALNUM(key[len]) || key[len] == '_'; ++len)
+ for (len = 0; ASCII_ISALNUM(key[len]) || key[len] == '_'; ++len) {
;
- if (len == 0)
+ }
+ if (len == 0) {
return FAIL;
+ }
*arg = skipwhite(key + len);
} else {
/*
@@ -4209,133 +4600,177 @@ eval_index(
}
switch (rettv->v_type) {
- case VAR_NUMBER:
- case VAR_STRING: {
- const char *const s = tv_get_string(rettv);
- char *v;
- len = (ptrdiff_t)strlen(s);
- if (range) {
- // The resulting variable is a substring. If the indexes
- // are out of range the result is empty.
+ case VAR_NUMBER:
+ case VAR_STRING: {
+ const char *const s = tv_get_string(rettv);
+ char *v;
+ len = (ptrdiff_t)strlen(s);
+ if (range) {
+ // The resulting variable is a substring. If the indexes
+ // are out of range the result is empty.
+ if (n1 < 0) {
+ n1 = len + n1;
if (n1 < 0) {
- n1 = len + n1;
- if (n1 < 0) {
- n1 = 0;
- }
- }
- if (n2 < 0) {
- n2 = len + n2;
- } else if (n2 >= len) {
- n2 = len;
- }
- if (n1 >= len || n2 < 0 || n1 > n2) {
- v = NULL;
- } else {
- v = xmemdupz(s + n1, (size_t)(n2 - n1 + 1));
+ n1 = 0;
}
+ }
+ if (n2 < 0) {
+ n2 = len + n2;
+ } else if (n2 >= len) {
+ n2 = len;
+ }
+ if (n1 >= len || n2 < 0 || n1 > n2) {
+ v = NULL;
} else {
- // The resulting variable is a string of a single
- // character. If the index is too big or negative the
- // result is empty.
- if (n1 >= len || n1 < 0) {
- v = NULL;
- } else {
- v = xmemdupz(s + n1, 1);
- }
+ v = xmemdupz(s + n1, (size_t)(n2 - n1 + 1));
+ }
+ } else {
+ // The resulting variable is a string of a single
+ // character. If the index is too big or negative the
+ // result is empty.
+ if (n1 >= len || n1 < 0) {
+ v = NULL;
+ } else {
+ v = xmemdupz(s + n1, 1);
}
- tv_clear(rettv);
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = (char_u *)v;
- break;
}
- case VAR_LIST: {
- len = tv_list_len(rettv->vval.v_list);
+ tv_clear(rettv);
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = (char_u *)v;
+ break;
+ }
+ case VAR_BLOB:
+ len = tv_blob_len(rettv->vval.v_blob);
+ if (range) {
+ // The resulting variable is a sub-blob. If the indexes
+ // are out of range the result is empty.
if (n1 < 0) {
n1 = len + n1;
- }
- if (!empty1 && (n1 < 0 || n1 >= len)) {
- // For a range we allow invalid values and return an empty
- // list. A list index out of range is an error.
- if (!range) {
- if (verbose) {
- EMSGN(_(e_listidx), n1);
- }
- return FAIL;
+ if (n1 < 0) {
+ n1 = 0;
}
- n1 = len;
}
- if (range) {
- list_T *l;
- listitem_T *item;
-
- if (n2 < 0) {
- n2 = len + n2;
- } else if (n2 >= len) {
- n2 = len - 1;
- }
- if (!empty2 && (n2 < 0 || n2 + 1 < n1)) {
- n2 = -1;
- }
- l = tv_list_alloc(n2 - n1 + 1);
- item = tv_list_find(rettv->vval.v_list, n1);
- while (n1++ <= n2) {
- tv_list_append_tv(l, TV_LIST_ITEM_TV(item));
- item = TV_LIST_ITEM_NEXT(rettv->vval.v_list, item);
- }
+ if (n2 < 0) {
+ n2 = len + n2;
+ } else if (n2 >= len) {
+ n2 = len - 1;
+ }
+ if (n1 >= len || n2 < 0 || n1 > n2) {
tv_clear(rettv);
- tv_list_set_ret(rettv, l);
+ rettv->v_type = VAR_BLOB;
+ rettv->vval.v_blob = NULL;
} else {
- tv_copy(TV_LIST_ITEM_TV(tv_list_find(rettv->vval.v_list, n1)), &var1);
+ blob_T *const blob = tv_blob_alloc();
+ ga_grow(&blob->bv_ga, n2 - n1 + 1);
+ blob->bv_ga.ga_len = n2 - n1 + 1;
+ for (long i = n1; i <= n2; i++) {
+ tv_blob_set(blob, i - n1, tv_blob_get(rettv->vval.v_blob, i));
+ }
tv_clear(rettv);
- *rettv = var1;
+ tv_blob_set_ret(rettv, blob);
+ }
+ } else {
+ // The resulting variable is a byte value.
+ // If the index is too big or negative that is an error.
+ if (n1 < 0) {
+ n1 = len + n1;
+ }
+ if (n1 < len && n1 >= 0) {
+ const int v = (int)tv_blob_get(rettv->vval.v_blob, n1);
+ tv_clear(rettv);
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = v;
+ } else {
+ EMSGN(_(e_blobidx), n1);
}
- break;
}
- case VAR_DICT: {
- if (range) {
+ break;
+ case VAR_LIST:
+ len = tv_list_len(rettv->vval.v_list);
+ if (n1 < 0) {
+ n1 = len + n1;
+ }
+ if (!empty1 && (n1 < 0 || n1 >= len)) {
+ // For a range we allow invalid values and return an empty
+ // list. A list index out of range is an error.
+ if (!range) {
if (verbose) {
- EMSG(_(e_dictrange));
- }
- if (len == -1) {
- tv_clear(&var1);
+ EMSGN(_(e_listidx), n1);
}
return FAIL;
}
+ n1 = len;
+ }
+ if (range) {
+ list_T *l;
+ listitem_T *item;
- if (len == -1) {
- key = (char_u *)tv_get_string_chk(&var1);
- if (key == NULL) {
- tv_clear(&var1);
- return FAIL;
- }
+ if (n2 < 0) {
+ n2 = len + n2;
+ } else if (n2 >= len) {
+ n2 = len - 1;
}
-
- dictitem_T *const item = tv_dict_find(rettv->vval.v_dict,
- (const char *)key, len);
-
- if (item == NULL && verbose) {
- emsgf(_(e_dictkey), key);
+ if (!empty2 && (n2 < 0 || n2 + 1 < n1)) {
+ n2 = -1;
+ }
+ l = tv_list_alloc(n2 - n1 + 1);
+ item = tv_list_find(rettv->vval.v_list, n1);
+ while (n1++ <= n2) {
+ tv_list_append_tv(l, TV_LIST_ITEM_TV(item));
+ item = TV_LIST_ITEM_NEXT(rettv->vval.v_list, item);
+ }
+ tv_clear(rettv);
+ tv_list_set_ret(rettv, l);
+ } else {
+ tv_copy(TV_LIST_ITEM_TV(tv_list_find(rettv->vval.v_list, n1)), &var1);
+ tv_clear(rettv);
+ *rettv = var1;
+ }
+ break;
+ case VAR_DICT: {
+ if (range) {
+ if (verbose) {
+ EMSG(_(e_dictrange));
}
if (len == -1) {
tv_clear(&var1);
}
- if (item == NULL || tv_is_luafunc(&item->di_tv)) {
+ return FAIL;
+ }
+
+ if (len == -1) {
+ key = (char_u *)tv_get_string_chk(&var1);
+ if (key == NULL) {
+ tv_clear(&var1);
return FAIL;
}
+ }
- tv_copy(&item->di_tv, &var1);
- tv_clear(rettv);
- *rettv = var1;
- break;
+ dictitem_T *const item = tv_dict_find(rettv->vval.v_dict,
+ (const char *)key, len);
+
+ if (item == NULL && verbose) {
+ emsgf(_(e_dictkey), key);
}
- case VAR_BOOL:
- case VAR_SPECIAL:
- case VAR_FUNC:
- case VAR_FLOAT:
- case VAR_PARTIAL:
- case VAR_UNKNOWN: {
- break; // Not evaluating, skipping over subscript
+ if (len == -1) {
+ tv_clear(&var1);
}
+ if (item == NULL || tv_is_luafunc(&item->di_tv)) {
+ return FAIL;
+ }
+
+ tv_copy(&item->di_tv, &var1);
+ tv_clear(rettv);
+ *rettv = var1;
+ break;
+ }
+ case VAR_BOOL:
+ case VAR_SPECIAL:
+ case VAR_FUNC:
+ case VAR_FLOAT:
+ case VAR_PARTIAL:
+ case VAR_UNKNOWN:
+ break; // Not evaluating, skipping over subscript
}
}
@@ -4352,12 +4787,11 @@ eval_index(
/// @param[in] evaluate If not true, rettv is not populated.
///
/// @return OK or FAIL.
-int get_option_tv(const char **const arg, typval_T *const rettv,
- const bool evaluate)
+int get_option_tv(const char **const arg, typval_T *const rettv, const bool evaluate)
FUNC_ATTR_NONNULL_ARG(1)
{
long numval;
- char_u *stringval;
+ char_u *stringval;
int opt_type;
int c;
bool working = (**arg == '+'); // has("+option")
@@ -4388,7 +4822,7 @@ int get_option_tv(const char **const arg, typval_T *const rettv,
EMSG2(_("E113: Unknown option: %s"), *arg);
}
ret = FAIL;
- } else if (rettv != NULL) {
+ } else if (rettv != NULL) {
if (opt_type == -2) { // hidden string option
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
@@ -4402,8 +4836,9 @@ int get_option_tv(const char **const arg, typval_T *const rettv,
rettv->v_type = VAR_STRING;
rettv->vval.v_string = stringval;
}
- } else if (working && (opt_type == -2 || opt_type == -1))
+ } else if (working && (opt_type == -2 || opt_type == -1)) {
ret = FAIL;
+ }
*option_end = c; // put back for error messages
*arg = option_end;
@@ -4417,7 +4852,7 @@ int get_option_tv(const char **const arg, typval_T *const rettv,
*/
static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate)
{
- char_u *p;
+ char_u *p;
unsigned int extra = 0;
/*
@@ -4459,12 +4894,18 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate)
for (p = *arg + 1; *p != NUL && *p != '"'; ) {
if (*p == '\\') {
switch (*++p) {
- case 'b': *name++ = BS; ++p; break;
- case 'e': *name++ = ESC; ++p; break;
- case 'f': *name++ = FF; ++p; break;
- case 'n': *name++ = NL; ++p; break;
- case 'r': *name++ = CAR; ++p; break;
- case 't': *name++ = TAB; ++p; break;
+ case 'b':
+ *name++ = BS; ++p; break;
+ case 'e':
+ *name++ = ESC; ++p; break;
+ case 'f':
+ *name++ = FF; ++p; break;
+ case 'n':
+ *name++ = NL; ++p; break;
+ case 'r':
+ *name++ = CAR; ++p; break;
+ case 't':
+ *name++ = TAB; ++p; break;
case 'X': // hex: "\x1", "\x12"
case 'x':
@@ -4505,11 +4946,13 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate)
case '4':
case '5':
case '6':
- case '7': *name = *p++ - '0';
+ case '7':
+ *name = *p++ - '0';
if (*p >= '0' && *p <= '7') {
*name = (*name << 3) + *p++ - '0';
- if (*p >= '0' && *p <= '7')
+ if (*p >= '0' && *p <= '7') {
*name = (*name << 3) + *p++ - '0';
+ }
}
++name;
break;
@@ -4526,12 +4969,13 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate)
}
FALLTHROUGH;
- default: MB_COPY_CHAR(p, name);
+ default:
+ MB_COPY_CHAR(p, name);
break;
}
- } else
+ } else {
MB_COPY_CHAR(p, name);
-
+ }
}
*name = NUL;
if (*p != NUL) { // just in case
@@ -4548,8 +4992,8 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate)
*/
static int get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate)
{
- char_u *p;
- char_u *str;
+ char_u *p;
+ char_u *str;
int reduce = 0;
/*
@@ -4557,8 +5001,9 @@ static int get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate)
*/
for (p = *arg + 1; *p != NUL; MB_PTR_ADV(p)) {
if (*p == '\'') {
- if (p[1] != '\'')
+ if (p[1] != '\'') {
break;
+ }
++reduce;
++p;
}
@@ -4584,8 +5029,9 @@ static int get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate)
for (p = *arg + 1; *p != NUL; ) {
if (*p == '\'') {
- if (p[1] != '\'')
+ if (p[1] != '\'') {
break;
+ }
++p;
}
MB_COPY_CHAR(p, str);
@@ -4638,7 +5084,7 @@ void partial_unref(partial_T *pt)
/// Return OK or FAIL.
static int get_list_tv(char_u **arg, typval_T *rettv, int evaluate)
{
- list_T *l = NULL;
+ list_T *l = NULL;
if (evaluate) {
l = tv_list_alloc(kListLenShouldKnow);
@@ -4682,23 +5128,20 @@ failret:
return OK;
}
-bool func_equal(
- typval_T *tv1,
- typval_T *tv2,
- bool ic // ignore case
-) {
+/// @param ic ignore case
+bool func_equal(typval_T *tv1, typval_T *tv2, bool ic) {
char_u *s1, *s2;
dict_T *d1, *d2;
int a1, a2;
// empty and NULL function name considered the same
s1 = tv1->v_type == VAR_FUNC ? tv1->vval.v_string
- : partial_name(tv1->vval.v_partial);
+ : partial_name(tv1->vval.v_partial);
if (s1 != NULL && *s1 == NUL) {
s1 = NULL;
}
s2 = tv2->v_type == VAR_FUNC ? tv2->vval.v_string
- : partial_name(tv2->vval.v_partial);
+ : partial_name(tv2->vval.v_partial);
if (s2 != NULL && *s2 == NUL) {
s2 = NULL;
}
@@ -4759,9 +5202,9 @@ int get_copyID(void)
* are no longer used. But for composite items it's possible that it becomes
* unused while the reference count is > 0: When there is a recursive
* reference. Example:
- * :let l = [1, 2, 3]
- * :let d = {9: l}
- * :let l[1] = d
+ * :let l = [1, 2, 3]
+ * :let d = {9: l}
+ * :let l[1] = d
*
* Since this is quite unusual we handle this with garbage collection: every
* once in a while find out which lists and dicts are not referenced from any
@@ -4769,7 +5212,7 @@ int get_copyID(void)
*
* Here is a good reference text about garbage collection (refers to Python
* but it applies to all reference-counting mechanisms):
- * http://python.ca/nas/python/gc/
+ * http://python.ca/nas/python/gc/
*/
/// Do garbage collection for lists and dicts.
@@ -4883,7 +5326,7 @@ bool garbage_collect(bool testing)
// Channels
{
Channel *data;
- map_foreach_value(channels, data, {
+ map_foreach_value(&channels, data, {
set_ref_in_callback_reader(&data->on_data, copyID, NULL, NULL);
set_ref_in_callback_reader(&data->on_stderr, copyID, NULL, NULL);
set_ref_in_callback(&data->on_exit, copyID, NULL, NULL);
@@ -4893,7 +5336,7 @@ bool garbage_collect(bool testing)
// Timers
{
timer_T *timer;
- map_foreach_value(timers, timer, {
+ map_foreach_value(&timers, timer, {
set_ref_in_callback(&timer->callback, copyID, NULL, NULL);
})
}
@@ -4945,8 +5388,7 @@ bool garbage_collect(bool testing)
// This may call us back recursively.
did_free = free_unref_funccal(copyID, testing) || did_free;
} else if (p_verbose > 0) {
- verb_msg(_(
- "Not enough memory to set references, garbage collection aborted!"));
+ verb_msg(_("Not enough memory to set references, garbage collection aborted!"));
}
#undef ABORTING
return did_free;
@@ -5040,8 +5482,7 @@ bool set_ref_in_ht(hashtab_T *ht, int copyID, list_stack_T **list_stack)
// it is added to ht_stack, if it contains a list it is added to
// list_stack.
HASHTAB_ITER(cur_ht, hi, {
- abort = abort || set_ref_in_item(
- &TV_DICT_HI2DI(hi)->di_tv, copyID, &ht_stack, list_stack);
+ abort = abort || set_ref_in_item(&TV_DICT_HI2DI(hi)->di_tv, copyID, &ht_stack, list_stack);
});
}
@@ -5107,86 +5548,85 @@ bool set_ref_in_list(list_T *l, int copyID, ht_stack_T **ht_stack)
/// @param list_stack Used to add lists to be marked. Can be NULL.
///
/// @returns true if setting references failed somehow.
-bool set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack,
- list_stack_T **list_stack)
+bool set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack, list_stack_T **list_stack)
FUNC_ATTR_WARN_UNUSED_RESULT
{
bool abort = false;
switch (tv->v_type) {
- case VAR_DICT: {
- dict_T *dd = tv->vval.v_dict;
- if (dd != NULL && dd->dv_copyID != copyID) {
- // Didn't see this dict yet.
- dd->dv_copyID = copyID;
- if (ht_stack == NULL) {
- abort = set_ref_in_ht(&dd->dv_hashtab, copyID, list_stack);
- } else {
- ht_stack_T *const newitem = xmalloc(sizeof(ht_stack_T));
- newitem->ht = &dd->dv_hashtab;
- newitem->prev = *ht_stack;
- *ht_stack = newitem;
- }
+ case VAR_DICT: {
+ dict_T *dd = tv->vval.v_dict;
+ if (dd != NULL && dd->dv_copyID != copyID) {
+ // Didn't see this dict yet.
+ dd->dv_copyID = copyID;
+ if (ht_stack == NULL) {
+ abort = set_ref_in_ht(&dd->dv_hashtab, copyID, list_stack);
+ } else {
+ ht_stack_T *const newitem = xmalloc(sizeof(ht_stack_T));
+ newitem->ht = &dd->dv_hashtab;
+ newitem->prev = *ht_stack;
+ *ht_stack = newitem;
+ }
- QUEUE *w = NULL;
- DictWatcher *watcher = NULL;
- QUEUE_FOREACH(w, &dd->watchers, {
+ QUEUE *w = NULL;
+ DictWatcher *watcher = NULL;
+ QUEUE_FOREACH(w, &dd->watchers, {
watcher = tv_dict_watcher_node_data(w);
set_ref_in_callback(&watcher->callback, copyID, ht_stack, list_stack);
})
- }
- break;
}
+ break;
+ }
- case VAR_LIST: {
- list_T *ll = tv->vval.v_list;
- if (ll != NULL && ll->lv_copyID != copyID) {
- // Didn't see this list yet.
- ll->lv_copyID = copyID;
- if (list_stack == NULL) {
- abort = set_ref_in_list(ll, copyID, ht_stack);
- } else {
- list_stack_T *const newitem = xmalloc(sizeof(list_stack_T));
- newitem->list = ll;
- newitem->prev = *list_stack;
- *list_stack = newitem;
- }
+ case VAR_LIST: {
+ list_T *ll = tv->vval.v_list;
+ if (ll != NULL && ll->lv_copyID != copyID) {
+ // Didn't see this list yet.
+ ll->lv_copyID = copyID;
+ if (list_stack == NULL) {
+ abort = set_ref_in_list(ll, copyID, ht_stack);
+ } else {
+ list_stack_T *const newitem = xmalloc(sizeof(list_stack_T));
+ newitem->list = ll;
+ newitem->prev = *list_stack;
+ *list_stack = newitem;
}
- break;
}
+ break;
+ }
- case VAR_PARTIAL: {
- partial_T *pt = tv->vval.v_partial;
+ case VAR_PARTIAL: {
+ partial_T *pt = tv->vval.v_partial;
- // A partial does not have a copyID, because it cannot contain itself.
- if (pt != NULL) {
- abort = set_ref_in_func(pt->pt_name, pt->pt_func, copyID);
- if (pt->pt_dict != NULL) {
- typval_T dtv;
+ // A partial does not have a copyID, because it cannot contain itself.
+ if (pt != NULL) {
+ abort = set_ref_in_func(pt->pt_name, pt->pt_func, copyID);
+ if (pt->pt_dict != NULL) {
+ typval_T dtv;
- dtv.v_type = VAR_DICT;
- dtv.vval.v_dict = pt->pt_dict;
- abort = abort || set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
- }
+ dtv.v_type = VAR_DICT;
+ dtv.vval.v_dict = pt->pt_dict;
+ abort = abort || set_ref_in_item(&dtv, copyID, ht_stack, list_stack);
+ }
- for (int i = 0; i < pt->pt_argc; i++) {
- abort = abort || set_ref_in_item(&pt->pt_argv[i], copyID,
- ht_stack, list_stack);
- }
+ for (int i = 0; i < pt->pt_argc; i++) {
+ abort = abort || set_ref_in_item(&pt->pt_argv[i], copyID,
+ ht_stack, list_stack);
}
- break;
- }
- case VAR_FUNC:
- abort = set_ref_in_func(tv->vval.v_string, NULL, copyID);
- break;
- case VAR_UNKNOWN:
- case VAR_BOOL:
- case VAR_SPECIAL:
- case VAR_FLOAT:
- case VAR_NUMBER:
- case VAR_STRING: {
- break;
}
+ break;
+ }
+ case VAR_FUNC:
+ abort = set_ref_in_func(tv->vval.v_string, NULL, copyID);
+ break;
+ case VAR_UNKNOWN:
+ case VAR_BOOL:
+ case VAR_SPECIAL:
+ case VAR_FLOAT:
+ case VAR_NUMBER:
+ case VAR_STRING:
+ case VAR_BLOB:
+ break;
}
return abort;
}
@@ -5262,15 +5702,14 @@ static int get_literal_key(char_u **arg, typval_T *tv)
// Allocate a variable for a Dictionary and fill it from "*arg".
// "literal" is true for *{key: val}
// Return OK or FAIL. Returns NOTDONE for {expr}.
-static int dict_get_tv(char_u **arg, typval_T *rettv, int evaluate,
- bool literal)
+static int dict_get_tv(char_u **arg, typval_T *rettv, int evaluate, bool literal)
{
- dict_T *d = NULL;
+ dict_T *d = NULL;
typval_T tvkey;
typval_T tv;
- char_u *key = NULL;
- dictitem_T *item;
- char_u *start = skipwhite(*arg + 1);
+ char_u *key = NULL;
+ dictitem_T *item;
+ char_u *start = skipwhite(*arg + 1);
char buf[NUMBUFLEN];
/*
@@ -5340,8 +5779,9 @@ static int dict_get_tv(char_u **arg, typval_T *rettv, int evaluate,
}
tv_clear(&tvkey);
- if (**arg == '}')
+ if (**arg == '}') {
break;
+ }
if (**arg != ',') {
EMSG2(_("E722: Missing comma in Dictionary: %s"), *arg);
goto failret;
@@ -5394,7 +5834,7 @@ size_t string2float(const char *const text, float_T *const ret_value)
return 3;
}
*ret_value = strtod(text, &s);
- return (size_t) (s - text);
+ return (size_t)(s - text);
}
/// Get the value of an environment variable.
@@ -5408,8 +5848,8 @@ static int get_env_tv(char_u **arg, typval_T *rettv, int evaluate)
{
char_u *name;
char_u *string = NULL;
- int len;
- int cc;
+ int len;
+ int cc;
++*arg;
name = *arg;
@@ -5441,8 +5881,7 @@ static int get_env_tv(char_u **arg, typval_T *rettv, int evaluate)
}
/// Get the argument list for a given window
-void get_arglist_as_rettv(aentry_T *arglist, int argcount,
- typval_T *rettv)
+void get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv)
{
tv_list_alloc_ret(rettv, argcount);
if (arglist != NULL) {
@@ -5487,21 +5926,28 @@ static void ga_concat_esc(garray_T *gap, const char_u *p, int clen)
ga_concat(gap, buf);
} else {
switch (*p) {
- case BS: ga_concat(gap, (char_u *)"\\b"); break;
- case ESC: ga_concat(gap, (char_u *)"\\e"); break;
- case FF: ga_concat(gap, (char_u *)"\\f"); break;
- case NL: ga_concat(gap, (char_u *)"\\n"); break;
- case TAB: ga_concat(gap, (char_u *)"\\t"); break;
- case CAR: ga_concat(gap, (char_u *)"\\r"); break;
- case '\\': ga_concat(gap, (char_u *)"\\\\"); break;
- default:
- if (*p < ' ') {
- vim_snprintf((char *)buf, NUMBUFLEN, "\\x%02x", *p);
- ga_concat(gap, buf);
- } else {
- ga_append(gap, *p);
- }
- break;
+ case BS:
+ ga_concat(gap, (char_u *)"\\b"); break;
+ case ESC:
+ ga_concat(gap, (char_u *)"\\e"); break;
+ case FF:
+ ga_concat(gap, (char_u *)"\\f"); break;
+ case NL:
+ ga_concat(gap, (char_u *)"\\n"); break;
+ case TAB:
+ ga_concat(gap, (char_u *)"\\t"); break;
+ case CAR:
+ ga_concat(gap, (char_u *)"\\r"); break;
+ case '\\':
+ ga_concat(gap, (char_u *)"\\\\"); break;
+ default:
+ if (*p < ' ') {
+ vim_snprintf((char *)buf, NUMBUFLEN, "\\x%02x", *p);
+ ga_concat(gap, buf);
+ } else {
+ ga_append(gap, *p);
+ }
+ break;
}
}
}
@@ -5542,8 +5988,7 @@ static void ga_concat_shorten_esc(garray_T *gap, const char_u *str)
}
// Fill "gap" with information about an assert error.
-void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv,
- char_u *exp_str, typval_T *exp_tv,
+void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv, char_u *exp_str, typval_T *exp_tv,
typval_T *got_tv, assert_type_T atype)
{
char_u *tofree;
@@ -5748,7 +6193,7 @@ int assert_inrange(typval_T *argvars)
char msg[55];
vim_snprintf(msg, sizeof(msg),
"range %" PRIdVARNUMBER " - %" PRIdVARNUMBER ",",
- lower, upper);
+ lower, upper); // -V576
fill_assert_error(&ga, &argvars[3], (char_u *)msg, NULL, &argvars[2],
ASSERT_INRANGE);
assert_error(&ga);
@@ -5809,8 +6254,7 @@ int assert_exception(typval_T *argvars)
return 0;
}
-static void assert_append_cmd_or_arg(garray_T *gap, typval_T *argvars,
- const char *cmd)
+static void assert_append_cmd_or_arg(garray_T *gap, typval_T *argvars, const char *cmd)
FUNC_ATTR_NONNULL_ALL
{
if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN) {
@@ -5855,9 +6299,9 @@ int assert_fails(typval_T *argvars)
FUNC_ATTR_NONNULL_ALL
{
const char *const cmd = tv_get_string_chk(&argvars[0]);
- garray_T ga;
+ garray_T ga;
int ret = 0;
- int save_trylevel = trylevel;
+ int save_trylevel = trylevel;
// trylevel must be zero for a ":throw" command to be considered failed
trylevel = 0;
@@ -5923,7 +6367,7 @@ int assert_match_common(typval_T *argvars, assert_type_T atype)
/// Find a window: When using a Window ID in any tab page, when using a number
/// in the current tab page.
-win_T * find_win_by_nr_or_id(typval_T *vp)
+win_T *find_win_by_nr_or_id(typval_T *vp)
{
int nr = (int)tv_get_number_chk(vp, NULL);
@@ -5939,14 +6383,15 @@ win_T * find_win_by_nr_or_id(typval_T *vp)
*/
void filter_map(typval_T *argvars, typval_T *rettv, int map)
{
- typval_T *expr;
- list_T *l = NULL;
- dictitem_T *di;
- hashtab_T *ht;
- hashitem_T *hi;
- dict_T *d = NULL;
+ typval_T *expr;
+ list_T *l = NULL;
+ dictitem_T *di;
+ hashtab_T *ht;
+ hashitem_T *hi;
+ dict_T *d = NULL;
typval_T save_val;
typval_T save_key;
+ blob_T *b = NULL;
int rem = false;
int todo;
char_u *ermsg = (char_u *)(map ? "map()" : "filter()");
@@ -5956,7 +6401,12 @@ void filter_map(typval_T *argvars, typval_T *rettv, int map)
int save_did_emsg;
int idx = 0;
- if (argvars[0].v_type == VAR_LIST) {
+ if (argvars[0].v_type == VAR_BLOB) {
+ tv_copy(&argvars[0], rettv);
+ if ((b = argvars[0].vval.v_blob) == NULL) {
+ return;
+ }
+ } else if (argvars[0].v_type == VAR_LIST) {
tv_copy(&argvars[0], rettv);
if ((l = argvars[0].vval.v_list) == NULL
|| (!map
@@ -5970,7 +6420,7 @@ void filter_map(typval_T *argvars, typval_T *rettv, int map)
return;
}
} else {
- EMSG2(_(e_listdictarg), ermsg);
+ EMSG2(_(e_listdictblobarg), ermsg);
return;
}
@@ -6020,6 +6470,34 @@ void filter_map(typval_T *argvars, typval_T *rettv, int map)
}
}
hash_unlock(ht);
+ } else if (argvars[0].v_type == VAR_BLOB) {
+ vimvars[VV_KEY].vv_type = VAR_NUMBER;
+
+ for (int i = 0; i < b->bv_ga.ga_len; i++) {
+ typval_T tv;
+ tv.v_type = VAR_NUMBER;
+ const varnumber_T val = tv_blob_get(b, i);
+ tv.vval.v_number = val;
+ vimvars[VV_KEY].vv_nr = idx;
+ if (filter_map_one(&tv, expr, map, &rem) == FAIL || did_emsg) {
+ break;
+ }
+ if (tv.v_type != VAR_NUMBER) {
+ EMSG(_(e_invalblob));
+ return;
+ }
+ if (map) {
+ if (tv.vval.v_number != val) {
+ tv_blob_set(b, i, tv.vval.v_number);
+ }
+ } else if (rem) {
+ char_u *const p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
+ memmove(p + i, p + i + 1, (size_t)b->bv_ga.ga_len - i - 1);
+ b->bv_ga.ga_len--;
+ i--;
+ }
+ idx++;
+ }
} else {
assert(argvars[0].v_type == VAR_LIST);
vimvars[VV_KEY].vv_type = VAR_NUMBER;
@@ -6087,11 +6565,10 @@ theend:
return retval;
}
-void common_function(typval_T *argvars, typval_T *rettv,
- bool is_funcref, FunPtr fptr)
+void common_function(typval_T *argvars, typval_T *rettv, bool is_funcref, FunPtr fptr)
{
- char_u *s;
- char_u *name;
+ char_u *s;
+ char_u *name;
bool use_string = false;
partial_T *arg_pt = NULL;
char_u *trans_name = NULL;
@@ -6128,7 +6605,7 @@ void common_function(typval_T *argvars, typval_T *rettv,
// Don't check an autoload name for existence here.
} else if (trans_name != NULL
&& (is_funcref ? find_func(trans_name) == NULL
- : !translated_function_exists((const char *)trans_name))) {
+ : !translated_function_exists((const char *)trans_name))) {
emsgf(_("E700: Unknown function: %s"), s);
} else {
int dict_idx = 0;
@@ -6304,8 +6781,7 @@ dict_T *get_buffer_info(buf_T *buf)
/// be NULL, in this case "$" results in zero return.
///
/// @return Line number or 0 in case of error.
-linenr_T tv_get_lnum_buf(const typval_T *const tv,
- const buf_T *const buf)
+linenr_T tv_get_lnum_buf(const typval_T *const tv, const buf_T *const buf)
FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_WARN_UNUSED_RESULT
{
if (tv->v_type == VAR_STRING
@@ -6317,8 +6793,7 @@ linenr_T tv_get_lnum_buf(const typval_T *const tv,
return tv_get_number_chk(tv, NULL);
}
-void get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg,
- typval_T *rettv)
+void get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
{
if (what_arg->v_type == VAR_UNKNOWN) {
tv_list_alloc_ret(rettv, kListLenMayKnow);
@@ -6389,12 +6864,10 @@ dict_T *get_win_info(win_T *wp, int16_t tpnr, int16_t winnr)
return dict;
}
-// Find window specified by "vp" in tabpage "tp".
-win_T *
-find_win_by_nr(
- typval_T *vp,
- tabpage_T *tp // NULL for current tab page
-)
+/// Find window specified by "vp" in tabpage "tp".
+///
+/// @param tp NULL for current tab page
+win_T *find_win_by_nr(typval_T *vp, tabpage_T *tp)
{
int nr = (int)tv_get_number_chk(vp, NULL);
@@ -6408,7 +6881,7 @@ find_win_by_nr(
// This method accepts NULL as an alias for curtab.
if (tp == NULL) {
- tp = curtab;
+ tp = curtab;
}
FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
@@ -6449,15 +6922,10 @@ win_T *find_tabwin(typval_T *wvp, typval_T *tvp)
return wp;
}
-/*
- * getwinvar() and gettabwinvar()
- */
-void
-getwinvar(
- typval_T *argvars,
- typval_T *rettv,
- int off // 1 for gettabwinvar()
-)
+/// getwinvar() and gettabwinvar()
+///
+/// @param off 1 for gettabwinvar()
+void getwinvar(typval_T *argvars, typval_T *rettv, int off)
{
win_T *win, *oldcurwin;
dictitem_T *v;
@@ -6528,9 +6996,7 @@ getwinvar(
* prompt. The third argument to f_inputdialog() specifies the value to return
* when the user cancels the prompt.
*/
-void get_user_input(const typval_T *const argvars,
- typval_T *const rettv,
- const bool inputdialog,
+void get_user_input(const typval_T *const argvars, typval_T *const rettv, const bool inputdialog,
const bool secret)
FUNC_ATTR_NONNULL_ALL
{
@@ -6665,8 +7131,7 @@ void get_user_input(const typval_T *const argvars,
/// a dictionary, will give an error if not.
/// @param[out] rettv Location where result will be saved.
/// @param[in] what What to save in rettv.
-void dict_list(typval_T *const tv, typval_T *const rettv,
- const DictListType what)
+void dict_list(typval_T *const tv, typval_T *const rettv, const DictListType what)
{
if (tv->v_type != VAR_DICT) {
EMSG(_(e_dictreq));
@@ -6682,32 +7147,30 @@ void dict_list(typval_T *const tv, typval_T *const rettv,
typval_T tv_item = { .v_lock = VAR_UNLOCKED };
switch (what) {
- case kDictListKeys: {
- tv_item.v_type = VAR_STRING;
- tv_item.vval.v_string = vim_strsave(di->di_key);
- break;
- }
- case kDictListValues: {
- tv_copy(&di->di_tv, &tv_item);
- break;
- }
- case kDictListItems: {
- // items()
- list_T *const sub_l = tv_list_alloc(2);
- tv_item.v_type = VAR_LIST;
- tv_item.vval.v_list = sub_l;
- tv_list_ref(sub_l);
-
- tv_list_append_owned_tv(sub_l, (typval_T) {
+ case kDictListKeys:
+ tv_item.v_type = VAR_STRING;
+ tv_item.vval.v_string = vim_strsave(di->di_key);
+ break;
+ case kDictListValues:
+ tv_copy(&di->di_tv, &tv_item);
+ break;
+ case kDictListItems: {
+ // items()
+ list_T *const sub_l = tv_list_alloc(2);
+ tv_item.v_type = VAR_LIST;
+ tv_item.vval.v_list = sub_l;
+ tv_list_ref(sub_l);
+
+ tv_list_append_owned_tv(sub_l, (typval_T) {
.v_type = VAR_STRING,
.v_lock = VAR_UNLOCKED,
.vval.v_string = (char_u *)xstrdup((const char *)di->di_key),
});
- tv_list_append_tv(sub_l, &di->di_tv);
+ tv_list_append_tv(sub_l, &di->di_tv);
- break;
- }
+ break;
+ }
}
tv_list_append_owned_tv(rettv->vval.v_list, tv_item);
@@ -6788,9 +7251,7 @@ char **tv_to_argv(typval_T *cmd_tv, const char **cmd, bool *executable)
/// @param mp The maphash that contains the mapping information
/// @param buffer_value The "buffer" value
/// @param compatible True for compatible with old maparg() dict
-void mapblock_fill_dict(dict_T *const dict,
- const mapblock_T *const mp,
- long buffer_value,
+void mapblock_fill_dict(dict_T *const dict, const mapblock_T *const mp, long buffer_value,
bool compatible)
FUNC_ATTR_NONNULL_ALL
{
@@ -6828,8 +7289,7 @@ void mapblock_fill_dict(dict_T *const dict,
tv_dict_add_allocated_str(dict, S_LEN("mode"), mapmode);
}
-int matchadd_dict_arg(typval_T *tv, const char **conceal_char,
- win_T **win)
+int matchadd_dict_arg(typval_T *tv, const char **conceal_char, win_T **win)
{
dictitem_T *di;
@@ -6877,18 +7337,18 @@ void screenchar_adjust_grid(ScreenGrid **grid, int *row, int *col)
}
/// Set line or list of lines in buffer "buf".
-void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append,
- const typval_T *lines, typval_T *rettv)
+void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append, const typval_T *lines,
+ typval_T *rettv)
FUNC_ATTR_NONNULL_ARG(4, 5)
{
linenr_T lnum = lnum_arg + (append ? 1 : 0);
const char *line = NULL;
- list_T *l = NULL;
- listitem_T *li = NULL;
- long added = 0;
+ list_T *l = NULL;
+ listitem_T *li = NULL;
+ long added = 0;
linenr_T append_lnum;
- buf_T *curbuf_save = NULL;
- win_T *curwin_save = NULL;
+ buf_T *curbuf_save = NULL;
+ win_T *curwin_save = NULL;
const bool is_curbuf = buf == curbuf;
// When using the current buffer ml_mfp will be set if needed. Useful when
@@ -6988,8 +7448,8 @@ void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append,
}
if (!is_curbuf) {
- curbuf = curbuf_save;
- curwin = curwin_save;
+ curbuf = curbuf_save;
+ curwin = curwin_save;
}
}
@@ -7014,8 +7474,8 @@ void setwinvar(typval_T *argvars, typval_T *rettv, int off)
typval_T *varp = &argvars[off + 2];
if (win != NULL && varname != NULL && varp != NULL) {
- win_T *save_curwin;
- tabpage_T *save_curtab;
+ win_T *save_curwin;
+ tabpage_T *save_curtab;
bool need_switch_win = tp != curtab || win != curwin;
if (!need_switch_win
|| switch_win(&save_curwin, &save_curtab, win, tp, true) == OK) {
@@ -7083,8 +7543,7 @@ static list_T *string_to_list(const char *str, size_t len, const bool keepempty)
}
// os_system wrapper. Handles 'verbose', :profile, and v:shell_error.
-void get_system_output_as_rettv(typval_T *argvars, typval_T *rettv,
- bool retlist)
+void get_system_output_as_rettv(typval_T *argvars, typval_T *rettv, bool retlist)
{
proftime_T wait_time;
bool profiling = do_profiling == PROF_YES;
@@ -7139,14 +7598,14 @@ void get_system_output_as_rettv(typval_T *argvars, typval_T *rettv,
xfree(input);
- set_vim_var_nr(VV_SHELL_ERROR, (long) status);
+ set_vim_var_nr(VV_SHELL_ERROR, (long)status);
if (res == NULL) {
if (retlist) {
// return an empty list when there's no output
tv_list_alloc_ret(rettv, 0);
} else {
- rettv->vval.v_string = (char_u *) xstrdup("");
+ rettv->vval.v_string = (char_u *)xstrdup("");
}
return;
}
@@ -7178,7 +7637,7 @@ void get_system_output_as_rettv(typval_T *argvars, typval_T *rettv,
*d = NUL;
#endif
- rettv->vval.v_string = (char_u *) res;
+ rettv->vval.v_string = (char_u *)res;
}
}
@@ -7231,62 +7690,62 @@ bool callback_from_typval(Callback *const callback, typval_T *const arg)
return true;
}
-bool callback_call(Callback *const callback, const int argcount_in,
- typval_T *const argvars_in, typval_T *const rettv)
+bool callback_call(Callback *const callback, const int argcount_in, typval_T *const argvars_in,
+ typval_T *const rettv)
FUNC_ATTR_NONNULL_ALL
{
partial_T *partial;
char_u *name;
switch (callback->type) {
- case kCallbackFuncref:
- name = callback->data.funcref;
- partial = NULL;
- break;
+ case kCallbackFuncref:
+ name = callback->data.funcref;
+ partial = NULL;
+ break;
- case kCallbackPartial:
- partial = callback->data.partial;
- name = partial_name(partial);
- break;
+ case kCallbackPartial:
+ partial = callback->data.partial;
+ name = partial_name(partial);
+ break;
- case kCallbackNone:
- return false;
- break;
+ case kCallbackNone:
+ return false;
+ break;
- default:
- abort();
+ default:
+ abort();
}
- int dummy;
- return call_func(name, -1, rettv, argcount_in, argvars_in,
- NULL, curwin->w_cursor.lnum, curwin->w_cursor.lnum, &dummy,
- true, partial, NULL);
+ funcexe_T funcexe = FUNCEXE_INIT;
+ funcexe.firstline = curwin->w_cursor.lnum;
+ funcexe.lastline = curwin->w_cursor.lnum;
+ funcexe.evaluate = true;
+ funcexe.partial = partial;
+ return call_func(name, -1, rettv, argcount_in, argvars_in, &funcexe);
}
-static bool set_ref_in_callback(Callback *callback, int copyID,
- ht_stack_T **ht_stack,
+static bool set_ref_in_callback(Callback *callback, int copyID, ht_stack_T **ht_stack,
list_stack_T **list_stack)
{
typval_T tv;
switch (callback->type) {
- case kCallbackFuncref:
- case kCallbackNone:
- break;
+ case kCallbackFuncref:
+ case kCallbackNone:
+ break;
- case kCallbackPartial:
- tv.v_type = VAR_PARTIAL;
- tv.vval.v_partial = callback->data.partial;
- return set_ref_in_item(&tv, copyID, ht_stack, list_stack);
- break;
+ case kCallbackPartial:
+ tv.v_type = VAR_PARTIAL;
+ tv.vval.v_partial = callback->data.partial;
+ return set_ref_in_item(&tv, copyID, ht_stack, list_stack);
+ break;
- default:
- abort();
+ default:
+ abort();
}
return false;
}
-static bool set_ref_in_callback_reader(CallbackReader *reader, int copyID,
- ht_stack_T **ht_stack,
+static bool set_ref_in_callback_reader(CallbackReader *reader, int copyID, ht_stack_T **ht_stack,
list_stack_T **list_stack)
{
if (set_ref_in_callback(&reader->cb, copyID, ht_stack, list_stack)) {
@@ -7304,7 +7763,7 @@ static bool set_ref_in_callback_reader(CallbackReader *reader, int copyID,
timer_T *find_timer_by_nr(varnumber_T xx)
{
- return pmap_get(uint64_t)(timers, xx);
+ return pmap_get(uint64_t)(&timers, xx);
}
void add_timer_info(typval_T *rettv, timer_T *timer)
@@ -7331,9 +7790,9 @@ void add_timer_info(typval_T *rettv, timer_T *timer)
void add_timer_info_all(typval_T *rettv)
{
- tv_list_alloc_ret(rettv, timers->table->n_occupied);
+ tv_list_alloc_ret(rettv, map_size(&timers));
timer_T *timer;
- map_foreach_value(timers, timer, {
+ map_foreach_value(&timers, timer, {
if (!timer->stopped) {
add_timer_info(rettv, timer);
}
@@ -7393,9 +7852,7 @@ void timer_due_cb(TimeWatcher *tw, void *data)
timer_decref(timer);
}
-uint64_t timer_start(const long timeout,
- const int repeat_count,
- const Callback *const callback)
+uint64_t timer_start(const long timeout, const int repeat_count, const Callback *const callback)
{
timer_T *timer = xmalloc(sizeof *timer);
timer->refcount = 1;
@@ -7413,7 +7870,7 @@ uint64_t timer_start(const long timeout,
timer->tw.blockable = true;
time_watcher_start(&timer->tw, timer_due_cb, timeout, timeout);
- pmap_put(uint64_t)(timers, timer->timer_id, timer);
+ pmap_put(uint64_t)(&timers, timer->timer_id, timer);
return timer->timer_id;
}
@@ -7435,7 +7892,7 @@ static void timer_close_cb(TimeWatcher *tw, void *data)
timer_T *timer = (timer_T *)data;
multiqueue_free(timer->tw.events);
callback_free(&timer->callback);
- pmap_del(uint64_t)(timers, timer->timer_id);
+ pmap_del(uint64_t)(&timers, timer->timer_id);
timer_decref(timer);
}
@@ -7449,7 +7906,7 @@ static void timer_decref(timer_T *timer)
void timer_stop_all(void)
{
timer_T *timer;
- map_foreach_value(timers, timer, {
+ map_foreach_value(&timers, timer, {
timer_stop(timer);
})
}
@@ -7466,8 +7923,7 @@ void timer_teardown(void)
/// @param[in] binary Whether to write in binary mode.
///
/// @return true in case of success, false otherwise.
-bool write_list(FileDescriptor *const fp, const list_T *const list,
- const bool binary)
+bool write_list(FileDescriptor *const fp, const list_T *const list, const bool binary)
FUNC_ATTR_NONNULL_ARG(1)
{
int error = 0;
@@ -7512,10 +7968,61 @@ bool write_list(FileDescriptor *const fp, const list_T *const list,
}
return true;
write_list_error:
- emsgf(_("E80: Error while writing: %s"), os_strerror(error));
+ emsgf(_(e_write2), os_strerror(error));
return false;
}
+/// Write a blob to file with descriptor `fp`.
+///
+/// @param[in] fp File to write to.
+/// @param[in] blob Blob to write.
+///
+/// @return true on success, or false on failure.
+bool write_blob(FileDescriptor *const fp, const blob_T *const blob)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ int error = 0;
+ const int len = tv_blob_len(blob);
+ if (len > 0) {
+ const ptrdiff_t written = file_write(fp, blob->bv_ga.ga_data, (size_t)len);
+ if (written < (ptrdiff_t)len) {
+ error = (int)written;
+ goto write_blob_error;
+ }
+ }
+ error = file_flush(fp);
+ if (error != 0) {
+ goto write_blob_error;
+ }
+ return true;
+write_blob_error:
+ EMSG2(_(e_write2), os_strerror(error));
+ return false;
+}
+
+/// Read a blob from a file `fd`.
+///
+/// @param[in] fd File to read from.
+/// @param[in,out] blob Blob to write to.
+///
+/// @return true on success, or false on failure.
+bool read_blob(FILE *const fd, blob_T *const blob)
+ FUNC_ATTR_NONNULL_ALL
+{
+ FileInfo file_info;
+ if (!os_fileinfo_fd(fileno(fd), &file_info)) {
+ return false;
+ }
+ const int size = (int)os_fileinfo_size(&file_info);
+ ga_grow(&blob->bv_ga, size);
+ blob->bv_ga.ga_len = size;
+ if (fread(blob->bv_ga.ga_data, 1, blob->bv_ga.ga_len, fd)
+ < (size_t)blob->bv_ga.ga_len) {
+ return false;
+ }
+ return true;
+}
+
/// Saves a typval_T as a string.
///
/// For lists or buffers, replaces NLs with NUL and separates items with NLs.
@@ -7614,16 +8121,15 @@ char *save_tv_as_string(typval_T *tv, ptrdiff_t *const len, bool endnl)
/// @param[out] ret_fnum Set to fnum for marks.
///
/// @return Pointer to position or NULL in case of error (e.g. invalid type).
-pos_T *var2fpos(const typval_T *const tv, const bool dollar_lnum,
- int *const ret_fnum)
+pos_T *var2fpos(const typval_T *const tv, const bool dollar_lnum, int *const ret_fnum)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
static pos_T pos;
- pos_T *pp;
+ pos_T *pp;
// Argument can be [lnum, col, coladd].
if (tv->v_type == VAR_LIST) {
- list_T *l;
+ list_T *l;
int len;
bool error = false;
listitem_T *li;
@@ -7841,10 +8347,7 @@ int get_id_len(const char **const arg)
* If the name contains 'magic' {}'s, expand them and return the
* expanded name in an allocated string via 'alias' - caller must free.
*/
-int get_name_len(const char **const arg,
- char **alias,
- bool evaluate,
- bool verbose)
+int get_name_len(const char **const arg, char **alias, bool evaluate, bool verbose)
{
int len;
@@ -7863,8 +8366,8 @@ int get_name_len(const char **const arg,
}
// Find the end of the name; check for {} construction.
- char_u *expr_start;
- char_u *expr_end;
+ char_u *expr_start;
+ char_u *expr_end;
const char *p = (const char *)find_name_end((char_u *)(*arg),
(const char_u **)&expr_start,
(const char_u **)&expr_end,
@@ -7906,8 +8409,8 @@ int get_name_len(const char **const arg,
// "flags" can have FNE_INCL_BR and FNE_CHECK_START.
// Return a pointer to just after the name. Equal to "arg" if there is no
// valid name.
-const char_u *find_name_end(const char_u *arg, const char_u **expr_start,
- const char_u **expr_end, int flags)
+const char_u *find_name_end(const char_u *arg, const char_u **expr_start, const char_u **expr_end,
+ int flags)
{
int mb_nest = 0;
int br_nest = 0;
@@ -7988,30 +8491,31 @@ const char_u *find_name_end(const char_u *arg, const char_u **expr_start,
* Note that this can call itself recursively, to deal with
* constructs like foo{bar}{baz}{bam}
* The four pointer arguments point to "foo{expre}ss{ion}bar"
- * "in_start" ^
- * "expr_start" ^
- * "expr_end" ^
- * "in_end" ^
+ * "in_start" ^
+ * "expr_start" ^
+ * "expr_end" ^
+ * "in_end" ^
*
* Returns a new allocated string, which the caller must free.
* Returns NULL for failure.
*/
-static char_u *make_expanded_name(const char_u *in_start, char_u *expr_start,
- char_u *expr_end, char_u *in_end)
+static char_u *make_expanded_name(const char_u *in_start, char_u *expr_start, char_u *expr_end,
+ char_u *in_end)
{
char_u c1;
- char_u *retval = NULL;
- char_u *temp_result;
- char_u *nextcmd = NULL;
+ char_u *retval = NULL;
+ char_u *temp_result;
+ char_u *nextcmd = NULL;
- if (expr_end == NULL || in_end == NULL)
+ if (expr_end == NULL || in_end == NULL) {
return NULL;
+ }
*expr_start = NUL;
*expr_end = NUL;
c1 = *in_end;
*in_end = NUL;
- temp_result = eval_to_string(expr_start + 1, &nextcmd, FALSE);
+ temp_result = eval_to_string(expr_start + 1, &nextcmd, false);
if (temp_result != NULL && nextcmd == NULL) {
retval = xmalloc(STRLEN(temp_result) + (expr_start - in_start)
+ (in_end - expr_end) + 1);
@@ -8032,7 +8536,7 @@ static char_u *make_expanded_name(const char_u *in_start, char_u *expr_start,
if (expr_start != NULL) {
// Further expansion!
temp_result = make_expanded_name(retval, expr_start,
- expr_end, temp_result);
+ expr_end, temp_result);
xfree(retval);
retval = temp_result;
}
@@ -8108,8 +8612,9 @@ void set_vim_var_char(int c)
*/
void set_vcount(long count, long count1, int set_prevcount)
{
- if (set_prevcount)
+ if (set_prevcount) {
vimvars[VV_PREVCOUNT].vv_nr = vimvars[VV_COUNT].vv_nr;
+ }
vimvars[VV_COUNT].vv_nr = count;
vimvars[VV_COUNT1].vv_nr = count1;
}
@@ -8151,19 +8656,18 @@ void set_vim_var_special(const VimVarIndex idx, const SpecialVarValue val)
///
/// @param[in] idx Index of variable to set.
/// @param[in] val Value to set to. Will be copied.
-/// @param[in] len Legth of that value or -1 in which case strlen() will be
+/// @param[in] len Length of that value or -1 in which case strlen() will be
/// used.
-void set_vim_var_string(const VimVarIndex idx, const char *const val,
- const ptrdiff_t len)
+void set_vim_var_string(const VimVarIndex idx, const char *const val, const ptrdiff_t len)
{
tv_clear(&vimvars[idx].vv_di.di_tv);
vimvars[idx].vv_type = VAR_STRING;
if (val == NULL) {
vimvars[idx].vv_str = NULL;
} else if (len == -1) {
- vimvars[idx].vv_str = (char_u *) xstrdup(val);
+ vimvars[idx].vv_str = (char_u *)xstrdup(val);
} else {
- vimvars[idx].vv_str = (char_u *) xstrndup(val, (size_t) len);
+ vimvars[idx].vv_str = (char_u *)xstrndup(val, (size_t)len);
}
}
@@ -8239,8 +8743,9 @@ void set_reg_var(int c)
*/
char_u *v_exception(char_u *oldval)
{
- if (oldval == NULL)
+ if (oldval == NULL) {
return vimvars[VV_EXCEPTION].vv_str;
+ }
vimvars[VV_EXCEPTION].vv_str = oldval;
return NULL;
@@ -8254,8 +8759,9 @@ char_u *v_exception(char_u *oldval)
*/
char_u *v_throwpoint(char_u *oldval)
{
- if (oldval == NULL)
+ if (oldval == NULL) {
return vimvars[VV_THROWPOINT].vv_str;
+ }
vimvars[VV_THROWPOINT].vv_str = oldval;
return NULL;
@@ -8277,13 +8783,15 @@ char_u *set_cmdarg(exarg_T *eap, char_u *oldarg)
}
size_t len = 0;
- if (eap->force_bin == FORCE_BIN)
+ if (eap->force_bin == FORCE_BIN) {
len = 6;
- else if (eap->force_bin == FORCE_NOBIN)
+ } else if (eap->force_bin == FORCE_NOBIN) {
len = 8;
+ }
- if (eap->read_edit)
+ if (eap->read_edit) {
len += 7;
+ }
if (eap->force_ff != 0) {
len += 10; // " ++ff=unix"
@@ -8298,15 +8806,17 @@ char_u *set_cmdarg(exarg_T *eap, char_u *oldarg)
const size_t newval_len = len + 1;
char_u *newval = xmalloc(newval_len);
- if (eap->force_bin == FORCE_BIN)
- sprintf((char *)newval, " ++bin");
- else if (eap->force_bin == FORCE_NOBIN)
- sprintf((char *)newval, " ++nobin");
- else
+ if (eap->force_bin == FORCE_BIN) {
+ snprintf((char *)newval, newval_len, " ++bin");
+ } else if (eap->force_bin == FORCE_NOBIN) {
+ snprintf((char *)newval, newval_len, " ++nobin");
+ } else {
*newval = NUL;
+ }
- if (eap->read_edit)
+ if (eap->read_edit) {
STRCAT(newval, " ++edit");
+ }
if (eap->force_ff != 0) {
snprintf((char *)newval + STRLEN(newval), newval_len, " ++ff=%s",
@@ -8329,20 +8839,20 @@ char_u *set_cmdarg(exarg_T *eap, char_u *oldarg)
return oldval;
}
-// Get the value of internal variable "name".
-// Return OK or FAIL. If OK is returned "rettv" must be cleared.
-int get_var_tv(
- const char *name,
- int len, // length of "name"
- typval_T *rettv, // NULL when only checking existence
- dictitem_T **dip, // non-NULL when typval's dict item is needed
- int verbose, // may give error message
- int no_autoload // do not use script autoloading
-)
+/// Get the value of internal variable "name".
+/// Return OK or FAIL. If OK is returned "rettv" must be cleared.
+///
+/// @param len length of "name"
+/// @param rettv NULL when only checking existence
+/// @param dip non-NULL when typval's dict item is needed
+/// @param verbose may give error message
+/// @param no_autoload do not use script autoloading
+int get_var_tv(const char *name, int len, typval_T *rettv, dictitem_T **dip, int verbose,
+ int no_autoload)
{
int ret = OK;
- typval_T *tv = NULL;
- dictitem_T *v;
+ typval_T *tv = NULL;
+ dictitem_T *v;
v = find_var(name, (size_t)len, NULL, no_autoload);
if (v != NULL) {
@@ -8394,13 +8904,23 @@ static bool tv_is_luafunc(typval_T *tv)
return tv->v_type == VAR_PARTIAL && is_luafunc(tv->vval.v_partial);
}
-/// check the function name after "v:lua."
-int check_luafunc_name(const char *str, bool paren)
+/// Skips one character past the end of the name of a v:lua function.
+/// @param p Pointer to the char AFTER the "v:lua." prefix.
+/// @return Pointer to the char one past the end of the function's name.
+const char *skip_luafunc_name(const char *p)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
- const char *p = str;
while (ASCII_ISALNUM(*p) || *p == '_' || *p == '.' || *p == '\'') {
p++;
}
+ return p;
+}
+
+/// check the function name after "v:lua."
+int check_luafunc_name(const char *const str, const bool paren)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ const char *const p = skip_luafunc_name(str);
if (*p != (paren ? '(' : NUL)) {
return 0;
} else {
@@ -8408,24 +8928,24 @@ int check_luafunc_name(const char *str, bool paren)
}
}
-/// Handle expr[expr], expr[expr:expr] subscript and .name lookup.
-/// Also handle function call with Funcref variable: func(expr)
-/// Can all be combined: dict.func(expr)[idx]['func'](expr)
-int
-handle_subscript(
- const char **const arg,
- typval_T *rettv,
- int evaluate, // do more than finding the end
- int verbose // give error messages
-)
+/// Handle:
+/// - expr[expr], expr[expr:expr] subscript
+/// - ".name" lookup
+/// - function call with Funcref variable: func(expr)
+/// - method call: var->method()
+///
+/// Can all be combined in any order: dict.func(expr)[idx]['func'](expr)->len()
+///
+/// @param evaluate do more than finding the end
+/// @param verbose give error messages
+/// @param start_leader start of '!' and '-' prefixes
+/// @param end_leaderp end of '!' and '-' prefixes
+int handle_subscript(const char **const arg, typval_T *rettv, int evaluate, int verbose,
+ const char_u *const start_leader, const char_u **const end_leaderp)
{
int ret = OK;
- dict_T *selfdict = NULL;
- const char_u *s;
- int len;
- typval_T functv;
- int slen = 0;
- bool lua = false;
+ dict_T *selfdict = NULL;
+ const char_u *lua_funcname = NULL;
if (tv_is_luafunc(rettv)) {
if (**arg != '.') {
@@ -8434,55 +8954,29 @@ handle_subscript(
} else {
(*arg)++;
- lua = true;
- s = (char_u *)(*arg);
- slen = check_luafunc_name(*arg, true);
- if (slen == 0) {
+ lua_funcname = (char_u *)(*arg);
+ const int len = check_luafunc_name(*arg, true);
+ if (len == 0) {
tv_clear(rettv);
ret = FAIL;
}
- (*arg) += slen;
+ (*arg) += len;
}
}
-
+ // "." is ".name" lookup when we found a dict.
while (ret == OK
- && (**arg == '['
- || (**arg == '.' && rettv->v_type == VAR_DICT)
- || (**arg == '(' && (!evaluate || tv_is_func(*rettv))))
- && !ascii_iswhite(*(*arg - 1))) {
+ && (((**arg == '[' || (**arg == '.' && rettv->v_type == VAR_DICT)
+ || (**arg == '(' && (!evaluate || tv_is_func(*rettv))))
+ && !ascii_iswhite(*(*arg - 1)))
+ || (**arg == '-' && (*arg)[1] == '>'))) {
if (**arg == '(') {
- partial_T *pt = NULL;
- // need to copy the funcref so that we can clear rettv
- if (evaluate) {
- functv = *rettv;
- rettv->v_type = VAR_UNKNOWN;
-
- // Invoke the function. Recursive!
- if (functv.v_type == VAR_PARTIAL) {
- pt = functv.vval.v_partial;
- if (!lua) {
- s = partial_name(pt);
- }
- } else {
- s = functv.vval.v_string;
- }
- } else {
- s = (char_u *)"";
- }
- ret = get_func_tv(s, lua ? slen : -1, rettv, (char_u **)arg,
- curwin->w_cursor.lnum, curwin->w_cursor.lnum,
- &len, evaluate, pt, selfdict);
-
- // Clear the funcref afterwards, so that deleting it while
- // evaluating the arguments is possible (see test55).
- if (evaluate) {
- tv_clear(&functv);
- }
+ ret = call_func_rettv((char_u **)arg, rettv, evaluate, selfdict, NULL,
+ lua_funcname);
- /* Stop the expression evaluation when immediately aborting on
- * error, or when an interrupt occurred or an exception was thrown
- * but not caught. */
+ // Stop the expression evaluation when immediately aborting on
+ // error, or when an interrupt occurred or an exception was thrown
+ // but not caught.
if (aborting()) {
if (ret == OK) {
tv_clear(rettv);
@@ -8491,14 +8985,31 @@ handle_subscript(
}
tv_dict_unref(selfdict);
selfdict = NULL;
+ } else if (**arg == '-') {
+ // Expression "-1.0->method()" applies the leader "-" before
+ // applying ->.
+ if (evaluate && *end_leaderp > start_leader) {
+ ret = eval7_leader(rettv, start_leader, end_leaderp);
+ }
+ if (ret == OK) {
+ if ((*arg)[2] == '{') {
+ // expr->{lambda}()
+ ret = eval_lambda((char_u **)arg, rettv, evaluate, verbose);
+ } else {
+ // expr->name()
+ ret = eval_method((char_u **)arg, rettv, evaluate, verbose);
+ }
+ }
} else { // **arg == '[' || **arg == '.'
tv_dict_unref(selfdict);
if (rettv->v_type == VAR_DICT) {
selfdict = rettv->vval.v_dict;
- if (selfdict != NULL)
+ if (selfdict != NULL) {
++selfdict->dv_refcount;
- } else
+ }
+ } else {
selfdict = NULL;
+ }
if (eval_index((char_u **)arg, rettv, evaluate, verbose) == FAIL) {
tv_clear(rettv);
ret = FAIL;
@@ -8531,8 +9042,8 @@ void set_selfdict(typval_T *const rettv, dict_T *const selfdict)
// Careful: "a:0" variables don't have a name.
// When "htp" is not NULL we are writing to the variable, set "htp" to the
// hashtab_T used.
-dictitem_T *find_var(const char *const name, const size_t name_len,
- hashtab_T **htp, int no_autoload)
+dictitem_T *find_var(const char *const name, const size_t name_len, hashtab_T **htp,
+ int no_autoload)
{
const char *varname;
hashtab_T *const ht = find_var_ht(name, name_len, &varname);
@@ -8566,26 +9077,31 @@ dictitem_T *find_var(const char *const name, const size_t name_len,
///
/// @return pointer to the dictionary item with the found variable or NULL if it
/// was not found.
-dictitem_T *find_var_in_ht(hashtab_T *const ht,
- int htname,
- const char *const varname,
- const size_t varname_len,
- int no_autoload)
+dictitem_T *find_var_in_ht(hashtab_T *const ht, int htname, const char *const varname,
+ const size_t varname_len, int no_autoload)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
- hashitem_T *hi;
+ hashitem_T *hi;
if (varname_len == 0) {
// Must be something like "s:", otherwise "ht" would be NULL.
switch (htname) {
- case 's': return (dictitem_T *)&SCRIPT_SV(current_sctx.sc_sid)->sv_var;
- case 'g': return (dictitem_T *)&globvars_var;
- case 'v': return (dictitem_T *)&vimvars_var;
- case 'b': return (dictitem_T *)&curbuf->b_bufvar;
- case 'w': return (dictitem_T *)&curwin->w_winvar;
- case 't': return (dictitem_T *)&curtab->tp_winvar;
- case 'l': return get_funccal_local_var();
- case 'a': return get_funccal_args_var();
+ case 's':
+ return (dictitem_T *)&SCRIPT_SV(current_sctx.sc_sid)->sv_var;
+ case 'g':
+ return (dictitem_T *)&globvars_var;
+ case 'v':
+ return (dictitem_T *)&vimvars_var;
+ case 'b':
+ return (dictitem_T *)&curbuf->b_bufvar;
+ case 'w':
+ return (dictitem_T *)&curwin->w_winvar;
+ case 't':
+ return (dictitem_T *)&curtab->tp_winvar;
+ case 'l':
+ return get_funccal_local_var();
+ case 'a':
+ return get_funccal_args_var();
}
return NULL;
}
@@ -8620,8 +9136,8 @@ dictitem_T *find_var_in_ht(hashtab_T *const ht,
/// @param[out] d Scope dictionary.
///
/// @return Scope hashtab, NULL if name is not valid.
-static hashtab_T *find_var_ht_dict(const char *name, const size_t name_len,
- const char **varname, dict_T **d)
+static hashtab_T *find_var_ht_dict(const char *name, const size_t name_len, const char **varname,
+ dict_T **d)
{
hashitem_T *hi;
funccall_T *funccal = get_funccal();
@@ -8692,8 +9208,7 @@ end:
/// prefix.
///
/// @return Scope hashtab, NULL if name is not valid.
-hashtab_T *find_var_ht(const char *name, const size_t name_len,
- const char **varname)
+hashtab_T *find_var_ht(const char *name, const size_t name_len, const char **varname)
{
dict_T *d;
return find_var_ht_dict(name, name_len, varname, &d);
@@ -8706,7 +9221,7 @@ hashtab_T *find_var_ht(const char *name, const size_t name_len,
*/
char_u *get_var_value(const char *const name)
{
- dictitem_T *v;
+ dictitem_T *v;
v = find_var(name, strlen(name), NULL, false);
if (v == NULL) {
@@ -8721,7 +9236,7 @@ char_u *get_var_value(const char *const name)
*/
void new_script_vars(scid_T id)
{
- hashtab_T *ht;
+ hashtab_T *ht;
scriptvar_T *sv;
ga_grow(&ga_scripts, (int)(id - ga_scripts.ga_len));
@@ -8731,8 +9246,9 @@ void new_script_vars(scid_T id)
* at its init value. Also reset "v_dict", it's always the same. */
for (int i = 1; i <= ga_scripts.ga_len; ++i) {
ht = &SCRIPT_VARS(i);
- if (ht->ht_mask == HT_INIT_SIZE - 1)
+ if (ht->ht_mask == HT_INIT_SIZE - 1) {
ht->ht_array = ht->ht_smallarray;
+ }
sv = SCRIPT_SV(i);
sv->sv_var.di_tv.vval.v_dict = &sv->sv_dict;
}
@@ -8791,8 +9307,8 @@ void vars_clear(hashtab_T *ht)
void vars_clear_ext(hashtab_T *ht, int free_val)
{
int todo;
- hashitem_T *hi;
- dictitem_T *v;
+ hashitem_T *hi;
+ dictitem_T *v;
hash_lock(ht);
todo = (int)ht->ht_used;
@@ -8822,7 +9338,7 @@ void vars_clear_ext(hashtab_T *ht, int free_val)
*/
static void delete_var(hashtab_T *ht, hashitem_T *hi)
{
- dictitem_T *di = TV_DICT_HI2DI(hi);
+ dictitem_T *di = TV_DICT_HI2DI(hi);
hash_remove(ht, hi);
tv_clear(&di->di_tv);
@@ -8843,9 +9359,8 @@ static void list_one_var(dictitem_T *v, const char *prefix, int *first)
/// @param[in] name_len Length of the name. May be -1, in this case strlen()
/// will be used.
/// @param[in,out] first When true clear rest of screen and set to false.
-static void list_one_var_a(const char *prefix, const char *name,
- const ptrdiff_t name_len, const int type,
- const char *string, int *first)
+static void list_one_var_a(const char *prefix, const char *name, const ptrdiff_t name_len,
+ const int type, const char *string, int *first)
{
// don't use msg() or msg_attr() to avoid overwriting "v:statusmsg"
msg_start();
@@ -8861,14 +9376,17 @@ static void list_one_var_a(const char *prefix, const char *name,
msg_putchar('*');
} else if (type == VAR_LIST) {
msg_putchar('[');
- if (*string == '[')
+ if (*string == '[') {
++string;
+ }
} else if (type == VAR_DICT) {
msg_putchar('{');
- if (*string == '{')
+ if (*string == '{') {
++string;
- } else
+ }
+ } else {
msg_putchar(' ');
+ }
msg_outtrans((char_u *)string);
@@ -8890,8 +9408,7 @@ static void list_one_var_a(const char *prefix, const char *name,
/// @param[in] name_len Length of the variable name.
/// @param tv Variable value.
/// @param[in] copy True if value in tv is to be copied.
-void set_var(const char *name, const size_t name_len, typval_T *const tv,
- const bool copy)
+void set_var(const char *name, const size_t name_len, typval_T *const tv, const bool copy)
FUNC_ATTR_NONNULL_ALL
{
set_var_const(name, name_len, tv, copy, false);
@@ -8907,13 +9424,12 @@ void set_var(const char *name, const size_t name_len, typval_T *const tv,
/// @param tv Variable value.
/// @param[in] copy True if value in tv is to be copied.
/// @param[in] is_const True if value in tv is to be locked.
-static void set_var_const(const char *name, const size_t name_len,
- typval_T *const tv, const bool copy,
- const bool is_const)
+static void set_var_const(const char *name, const size_t name_len, typval_T *const tv,
+ const bool copy, const bool is_const)
FUNC_ATTR_NONNULL_ALL
{
- dictitem_T *v;
- hashtab_T *ht;
+ dictitem_T *v;
+ hashtab_T *ht;
dict_T *dict;
const char *varname;
@@ -8957,7 +9473,7 @@ static void set_var_const(const char *name, const size_t name_len,
const char *const val = tv_get_string(tv);
// Careful: when assigning to v:errmsg and tv_get_string()
- // causes an error message the variable will alrady be set.
+ // causes an error message the variable will already be set.
if (v->di_tv.vval.v_string == NULL) {
v->di_tv.vval.v_string = (char_u *)xstrdup(val);
}
@@ -9031,7 +9547,10 @@ static void set_var_const(const char *name, const size_t name_len,
}
if (is_const) {
- tv_item_lock(&v->di_tv, 1, true);
+ // Like :lockvar! name: lock the value and what it contains, but only
+ // if the reference count is up to one. That locks only literal
+ // values.
+ tv_item_lock(&v->di_tv, DICT_MAXNEST, true, true);
}
}
@@ -9054,8 +9573,7 @@ static void set_var_const(const char *name, const size_t name_len,
///
/// @return True if variable is read-only: either always or in sandbox when
/// sandbox is enabled, false otherwise.
-bool var_check_ro(const int flags, const char *name,
- size_t name_len)
+bool var_check_ro(const int flags, const char *name, size_t name_len)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
const char *error_message = NULL;
@@ -9098,8 +9616,7 @@ bool var_check_ro(const int flags, const char *name,
/// gettext.
///
/// @return True if variable is fixed, false otherwise.
-bool var_check_fixed(const int flags, const char *name,
- size_t name_len)
+bool var_check_fixed(const int flags, const char *name, size_t name_len)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
if (flags & DI_FLAGS_FIX) {
@@ -9183,11 +9700,8 @@ bool valid_varname(const char *varname)
/// a copy with (`copy[0] isnot copy[1]`), with non-zero it
/// will emit a copy with (`copy[0] is copy[1]`) like in the
/// original list. Not used when deep is false.
-int var_item_copy(const vimconv_T *const conv,
- typval_T *const from,
- typval_T *const to,
- const bool deep,
- const int copyID)
+int var_item_copy(const vimconv_T *const conv, typval_T *const from, typval_T *const to,
+ const bool deep, const int copyID)
FUNC_ATTR_NONNULL_ARG(2, 3)
{
static int recurse = 0;
@@ -9219,7 +9733,7 @@ int var_item_copy(const vimconv_T *const conv,
from->vval.v_string,
NULL))
== NULL) {
- to->vval.v_string = (char_u *) xstrdup((char *) from->vval.v_string);
+ to->vval.v_string = (char_u *)xstrdup((char *)from->vval.v_string);
}
}
break;
@@ -9239,6 +9753,9 @@ int var_item_copy(const vimconv_T *const conv,
ret = FAIL;
}
break;
+ case VAR_BLOB:
+ tv_blob_copy(from, to);
+ break;
case VAR_DICT:
to->v_type = VAR_DICT;
to->v_lock = VAR_UNLOCKED;
@@ -9264,20 +9781,22 @@ int var_item_copy(const vimconv_T *const conv,
}
/*
- * ":echo expr1 ..." print each argument separated with a space, add a
- * newline at the end.
- * ":echon expr1 ..." print each argument plain.
+ * ":echo expr1 ..." print each argument separated with a space, add a
+ * newline at the end.
+ * ":echon expr1 ..." print each argument plain.
*/
void ex_echo(exarg_T *eap)
{
- char_u *arg = eap->arg;
+ char_u *arg = eap->arg;
typval_T rettv;
bool atstart = true;
bool need_clear = true;
const int did_emsg_before = did_emsg;
+ const int called_emsg_before = called_emsg;
- if (eap->skip)
+ if (eap->skip) {
++emsg_skip;
+ }
while (*arg != NUL && *arg != '|' && *arg != '\n' && !got_int) {
// If eval1() causes an error message the text from the command may
// still need to be cleared. E.g., "echo 22,44".
@@ -9289,7 +9808,8 @@ void ex_echo(exarg_T *eap)
// Report the invalid expression unless the expression evaluation
// has been cancelled due to an aborting error, an interrupt, or an
// exception.
- if (!aborting() && did_emsg == did_emsg_before) {
+ if (!aborting() && did_emsg == did_emsg_before
+ && called_emsg == called_emsg_before) {
EMSG2(_(e_invexpr2), p);
}
need_clr_eos = false;
@@ -9347,9 +9867,9 @@ void ex_echohl(exarg_T *eap)
}
/*
- * ":execute expr1 ..." execute the result of an expression.
- * ":echomsg expr1 ..." Print a message
- * ":echoerr expr1 ..." Print an error
+ * ":execute expr1 ..." execute the result of an expression.
+ * ":echomsg expr1 ..." Print a message
+ * ":echoerr expr1 ..." Print an error
* Each gets spaces around each argument and a newline at the end for
* echo commands
*/
@@ -9363,8 +9883,9 @@ void ex_execute(exarg_T *eap)
ga_init(&ga, 1, 80);
- if (eap->skip)
+ if (eap->skip) {
++emsg_skip;
+ }
while (*arg != NUL && *arg != '|' && *arg != '\n') {
ret = eval1_emsg(&arg, &rettv, !eap->skip);
if (ret == FAIL) {
@@ -9410,17 +9931,20 @@ void ex_execute(exarg_T *eap)
save_did_emsg = did_emsg;
msg_ext_set_kind("echoerr");
EMSG((char_u *)ga.ga_data);
- if (!force_abort)
+ if (!force_abort) {
did_emsg = save_did_emsg;
- } else if (eap->cmdidx == CMD_execute)
+ }
+ } else if (eap->cmdidx == CMD_execute) {
do_cmdline((char_u *)ga.ga_data,
- eap->getline, eap->cookie, DOCMD_NOWAIT|DOCMD_VERBOSE);
+ eap->getline, eap->cookie, DOCMD_NOWAIT|DOCMD_VERBOSE);
+ }
}
ga_clear(&ga);
- if (eap->skip)
+ if (eap->skip) {
--emsg_skip;
+ }
eap->nextcmd = check_nextcmd(arg);
}
@@ -9498,10 +10022,10 @@ void func_do_profile(ufunc_T *fp)
*/
void func_dump_profile(FILE *fd)
{
- hashitem_T *hi;
+ hashitem_T *hi;
int todo;
- ufunc_T *fp;
- ufunc_T **sorttab;
+ ufunc_T *fp;
+ ufunc_T **sorttab;
int st_len = 0;
todo = (int)func_hashtab.ht_used;
@@ -9527,7 +10051,7 @@ void func_dump_profile(FILE *fd)
bool should_free;
const LastSet last_set = (LastSet){
.script_ctx = fp->uf_script_ctx,
- .channel_id = 0,
+ .channel_id = 0,
};
char_u *p = get_scriptname(last_set, &should_free);
fprintf(fd, " Defined: %s:%" PRIdLINENR "\n",
@@ -9547,10 +10071,11 @@ void func_dump_profile(FILE *fd)
fprintf(fd, "count total (s) self (s)\n");
for (int i = 0; i < fp->uf_lines.ga_len; ++i) {
- if (FUNCLINE(fp, i) == NULL)
+ if (FUNCLINE(fp, i) == NULL) {
continue;
+ }
prof_func_line(fd, fp->uf_tml_count[i],
- &fp->uf_tml_total[i], &fp->uf_tml_self[i], TRUE);
+ &fp->uf_tml_total[i], &fp->uf_tml_self[i], TRUE);
fprintf(fd, "%s\n", FUNCLINE(fp, i));
}
fprintf(fd, "\n");
@@ -9560,65 +10085,58 @@ void func_dump_profile(FILE *fd)
if (st_len > 0) {
qsort((void *)sorttab, (size_t)st_len, sizeof(ufunc_T *),
- prof_total_cmp);
+ prof_total_cmp);
prof_sort_list(fd, sorttab, st_len, "TOTAL", FALSE);
qsort((void *)sorttab, (size_t)st_len, sizeof(ufunc_T *),
- prof_self_cmp);
+ prof_self_cmp);
prof_sort_list(fd, sorttab, st_len, "SELF", TRUE);
}
xfree(sorttab);
}
-static void
-prof_sort_list(
- FILE *fd,
- ufunc_T **sorttab,
- int st_len,
- char *title,
- int prefer_self // when equal print only self time
-)
+/// @param prefer_self when equal print only self time
+static void prof_sort_list(FILE *fd, ufunc_T **sorttab, int st_len, char *title, int prefer_self)
{
int i;
- ufunc_T *fp;
+ ufunc_T *fp;
fprintf(fd, "FUNCTIONS SORTED ON %s TIME\n", title);
fprintf(fd, "count total (s) self (s) function\n");
for (i = 0; i < 20 && i < st_len; ++i) {
fp = sorttab[i];
prof_func_line(fd, fp->uf_tm_count, &fp->uf_tm_total, &fp->uf_tm_self,
- prefer_self);
- if (fp->uf_name[0] == K_SPECIAL)
+ prefer_self);
+ if (fp->uf_name[0] == K_SPECIAL) {
fprintf(fd, " <SNR>%s()\n", fp->uf_name + 3);
- else
+ } else {
fprintf(fd, " %s()\n", fp->uf_name);
+ }
}
fprintf(fd, "\n");
}
-/*
- * Print the count and times for one function or function line.
- */
-static void prof_func_line(
- FILE *fd,
- int count,
- proftime_T *total,
- proftime_T *self,
- int prefer_self // when equal print only self time
-)
+/// Print the count and times for one function or function line.
+///
+/// @param prefer_self when equal print only self time
+static void prof_func_line(FILE *fd, int count, proftime_T *total, proftime_T *self,
+ int prefer_self)
{
if (count > 0) {
fprintf(fd, "%5d ", count);
- if (prefer_self && profile_equal(*total, *self))
+ if (prefer_self && profile_equal(*total, *self)) {
fprintf(fd, " ");
- else
+ } else {
fprintf(fd, "%s ", profile_msg(*total));
- if (!prefer_self && profile_equal(*total, *self))
+ }
+ if (!prefer_self && profile_equal(*total, *self)) {
fprintf(fd, " ");
- else
+ } else {
fprintf(fd, "%s ", profile_msg(*self));
- } else
+ }
+ } else {
fprintf(fd, " ");
+ }
}
/*
@@ -9676,8 +10194,7 @@ char *autoload_name(const char *const name, const size_t name_len)
/// @param[in] reload If true, load script again when already loaded.
///
/// @return true if a package was loaded.
-bool script_autoload(const char *const name, const size_t name_len,
- const bool reload)
+bool script_autoload(const char *const name, const size_t name_len, const bool reload)
{
// If there is no '#' after name[0] there is no package name.
const char *p = memchr(name, AUTOLOAD_CHAR, name_len);
@@ -9724,8 +10241,8 @@ bool script_autoload(const char *const name, const size_t name_len,
*/
void func_line_start(void *cookie)
{
- funccall_T *fcp = (funccall_T *)cookie;
- ufunc_T *fp = fcp->func;
+ funccall_T *fcp = (funccall_T *)cookie;
+ ufunc_T *fp = fcp->func;
if (fp->uf_profiling && sourcing_lnum >= 1
&& sourcing_lnum <= fp->uf_lines.ga_len) {
@@ -9746,11 +10263,12 @@ void func_line_start(void *cookie)
*/
void func_line_exec(void *cookie)
{
- funccall_T *fcp = (funccall_T *)cookie;
- ufunc_T *fp = fcp->func;
+ funccall_T *fcp = (funccall_T *)cookie;
+ ufunc_T *fp = fcp->func;
- if (fp->uf_profiling && fp->uf_tml_idx >= 0)
+ if (fp->uf_profiling && fp->uf_tml_idx >= 0) {
fp->uf_tml_execed = TRUE;
+ }
}
/*
@@ -9758,8 +10276,8 @@ void func_line_exec(void *cookie)
*/
void func_line_end(void *cookie)
{
- funccall_T *fcp = (funccall_T *)cookie;
- ufunc_T *fp = fcp->func;
+ funccall_T *fcp = (funccall_T *)cookie;
+ ufunc_T *fp = fcp->func;
if (fp->uf_profiling && fp->uf_tml_idx >= 0) {
if (fp->uf_tml_execed) {
@@ -9770,7 +10288,7 @@ void func_line_end(void *cookie)
profile_add(fp->uf_tml_total[fp->uf_tml_idx], fp->uf_tml_start);
fp->uf_tml_self[fp->uf_tml_idx] =
profile_self(fp->uf_tml_self[fp->uf_tml_idx], fp->uf_tml_start,
- fp->uf_tml_children);
+ fp->uf_tml_children);
}
fp->uf_tml_idx = -1;
}
@@ -9781,10 +10299,11 @@ static var_flavour_T var_flavour(char_u *varname)
char_u *p = varname;
if (ASCII_ISUPPER(*p)) {
- while (*(++p))
+ while (*(++p)) {
if (ASCII_ISLOWER(*p)) {
return VAR_FLAVOUR_SESSION;
}
+ }
return VAR_FLAVOUR_SHADA;
} else {
return VAR_FLAVOUR_DEFAULT;
@@ -9802,26 +10321,26 @@ static var_flavour_T var_flavour(char_u *varname)
///
/// @return Pointer that needs to be passed to next `var_shada_iter` invocation
/// or NULL to indicate that iteration is over.
-const void *var_shada_iter(const void *const iter, const char **const name,
- typval_T *rettv, var_flavour_T flavour)
+const void *var_shada_iter(const void *const iter, const char **const name, typval_T *rettv,
+ var_flavour_T flavour)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(2, 3)
{
const hashitem_T *hi;
const hashitem_T *hifirst = globvarht.ht_array;
- const size_t hinum = (size_t) globvarht.ht_mask + 1;
+ const size_t hinum = (size_t)globvarht.ht_mask + 1;
*name = NULL;
if (iter == NULL) {
hi = globvarht.ht_array;
- while ((size_t) (hi - hifirst) < hinum
+ while ((size_t)(hi - hifirst) < hinum
&& (HASHITEM_EMPTY(hi)
|| !(var_flavour(hi->hi_key) & flavour))) {
hi++;
}
- if ((size_t) (hi - hifirst) == hinum) {
+ if ((size_t)(hi - hifirst) == hinum) {
return NULL;
}
} else {
- hi = (const hashitem_T *) iter;
+ hi = (const hashitem_T *)iter;
}
*name = (char *)TV_DICT_HI2DI(hi)->di_key;
tv_copy(&TV_DICT_HI2DI(hi)->di_tv, rettv);
@@ -9850,9 +10369,8 @@ int store_session_globals(FILE *fd)
&& var_flavour(this_var->di_key) == VAR_FLAVOUR_SESSION) {
// Escape special characters with a backslash. Turn a LF and
// CR into \n and \r.
- char_u *const p = vim_strsave_escaped(
- (const char_u *)tv_get_string(&this_var->di_tv),
- (const char_u *)"\\\"\n\r");
+ char_u *const p = vim_strsave_escaped((const char_u *)tv_get_string(&this_var->di_tv),
+ (const char_u *)"\\\"\n\r");
for (char_u *t = p; *t != NUL; t++) {
if (*t == '\n') {
*t = 'n';
@@ -9863,10 +10381,10 @@ int store_session_globals(FILE *fd)
if ((fprintf(fd, "let %s = %c%s%c",
this_var->di_key,
((this_var->di_tv.v_type == VAR_STRING) ? '"'
- : ' '),
+ : ' '),
p,
((this_var->di_tv.v_type == VAR_STRING) ? '"'
- : ' ')) < 0)
+ : ' ')) < 0)
|| put_eol(fd) == FAIL) {
xfree(p);
return FAIL;
@@ -9933,26 +10451,24 @@ void reset_v_option_vars(void)
set_vim_var_string(VV_OPTION_TYPE, NULL, -1);
}
-/*
- * Adjust a filename, according to a string of modifiers.
- * *fnamep must be NUL terminated when called. When returning, the length is
- * determined by *fnamelen.
- * Returns VALID_ flags or -1 for failure.
- * When there is an error, *fnamep is set to NULL.
- */
-int
-modify_fname(
- char_u *src, // string with modifiers
- bool tilde_file, // "~" is a file name, not $HOME
- size_t *usedlen, // characters after src that are used
- char_u **fnamep, // file name so far
- char_u **bufp, // buffer for allocated file name or NULL
- size_t *fnamelen // length of fnamep
-)
+/// Adjust a filename, according to a string of modifiers.
+/// *fnamep must be NUL terminated when called. When returning, the length is
+/// determined by *fnamelen.
+/// Returns VALID_ flags or -1 for failure.
+/// When there is an error, *fnamep is set to NULL.
+///
+/// @param src string with modifiers
+/// @param tilde_file "~" is a file name, not $HOME
+/// @param usedlen characters after src that are used
+/// @param fnamep file name so far
+/// @param bufp buffer for allocated file name or NULL
+/// @param fnamelen length of fnamep
+int modify_fname(char_u *src, bool tilde_file, size_t *usedlen, char_u **fnamep, char_u **bufp,
+ size_t *fnamelen)
{
int valid = 0;
- char_u *tail;
- char_u *s, *p, *pbuf;
+ char_u *tail;
+ char_u *s, *p, *pbuf;
char_u dirname[MAXPATHL];
int c;
int has_fullname = 0;
@@ -9974,13 +10490,13 @@ repeat:
# endif
|| (*fnamep)[1] == NUL)
#endif
- && !(tilde_file && (*fnamep)[1] == NUL)
- ) {
+ && !(tilde_file && (*fnamep)[1] == NUL)) {
*fnamep = expand_env_save(*fnamep);
xfree(*bufp); // free any allocated file name
*bufp = *fnamep;
- if (*fnamep == NULL)
+ if (*fnamep == NULL) {
return -1;
+ }
}
// When "/." or "/.." is used: force expansion to get rid of it.
@@ -10000,8 +10516,9 @@ repeat:
*fnamep = (char_u *)FullName_save((char *)(*fnamep), *p != NUL);
xfree(*bufp); // free any allocated file name
*bufp = *fnamep;
- if (*fnamep == NULL)
+ if (*fnamep == NULL) {
return -1;
+ }
}
// Append a path separator to a directory.
@@ -10010,8 +10527,9 @@ repeat:
*fnamep = vim_strnsave(*fnamep, STRLEN(*fnamep) + 2);
xfree(*bufp); // free any allocated file name
*bufp = *fnamep;
- if (*fnamep == NULL)
+ if (*fnamep == NULL) {
return -1;
+ }
add_pathsep((char *)*fnamep);
}
}
@@ -10028,12 +10546,14 @@ repeat:
pbuf = NULL;
// Need full path first (use expand_env() to remove a "~/")
if (!has_fullname) {
- if (c == '.' && **fnamep == '~')
+ if (c == '.' && **fnamep == '~') {
p = pbuf = expand_env_save(*fnamep);
- else
+ } else {
p = pbuf = (char_u *)FullName_save((char *)*fnamep, FALSE);
- } else
+ }
+ } else {
p = *fnamep;
+ }
has_fullname = 0;
@@ -10160,7 +10680,7 @@ repeat:
&& (src[*usedlen + 1] == 's'
|| (src[*usedlen + 1] == 'g' && src[*usedlen + 2] == 's'))) {
int sep;
- char_u *flags;
+ char_u *flags;
int didit = FALSE;
flags = (char_u *)"";
@@ -10224,17 +10744,16 @@ repeat:
/// When "sub" is NULL "expr" is used, must be a VAR_FUNC or VAR_PARTIAL.
/// "flags" can be "g" to do a global substitute.
/// Returns an allocated string, NULL for error.
-char_u *do_string_sub(char_u *str, char_u *pat, char_u *sub,
- typval_T *expr, char_u *flags)
+char_u *do_string_sub(char_u *str, char_u *pat, char_u *sub, typval_T *expr, char_u *flags)
{
int sublen;
regmatch_T regmatch;
int do_all;
- char_u *tail;
- char_u *end;
+ char_u *tail;
+ char_u *end;
garray_T ga;
- char_u *save_cpo;
- char_u *zero_width = NULL;
+ char_u *save_cpo;
+ char_u *zero_width = NULL;
// Make 'cpoptions' empty, so that the 'l' flag doesn't work here
save_cpo = p_cpo;
@@ -10270,7 +10789,7 @@ char_u *do_string_sub(char_u *str, char_u *pat, char_u *sub,
// - The text after the match.
sublen = vim_regsub(&regmatch, sub, expr, tail, false, true, false);
ga_grow(&ga, (int)((end - tail) + sublen -
- (regmatch.endp[0] - regmatch.startp[0])));
+ (regmatch.endp[0] - regmatch.startp[0])));
// copy the text up to where the match is
int i = (int)(regmatch.startp[0] - tail);
@@ -10280,14 +10799,17 @@ char_u *do_string_sub(char_u *str, char_u *pat, char_u *sub,
+ ga.ga_len + i, true, true, false);
ga.ga_len += i + sublen - 1;
tail = regmatch.endp[0];
- if (*tail == NUL)
+ if (*tail == NUL) {
break;
- if (!do_all)
+ }
+ if (!do_all) {
break;
+ }
}
- if (ga.ga_data != NULL)
+ if (ga.ga_data != NULL) {
STRCPY((char *)ga.ga_data + ga.ga_len, tail);
+ }
vim_regfree(regmatch.regprog);
}
@@ -10307,9 +10829,7 @@ char_u *do_string_sub(char_u *str, char_u *pat, char_u *sub,
/// common code for getting job callbacks for jobstart, termopen and rpcstart
///
/// @return true/false on success/failure.
-bool common_job_callbacks(dict_T *vopts,
- CallbackReader *on_stdout,
- CallbackReader *on_stderr,
+bool common_job_callbacks(dict_T *vopts, CallbackReader *on_stdout, CallbackReader *on_stderr,
Callback *on_exit)
{
if (tv_dict_get_callback(vopts, S_LEN("on_stdout"), &on_stdout->cb)
@@ -10370,8 +10890,7 @@ void script_host_eval(char *name, typval_T *argvars, typval_T *rettv)
/// @param discard Clears the value returned by the provider and returns
/// an empty typval_T.
-typval_T eval_call_provider(char *provider, char *method, list_T *arguments,
- bool discard)
+typval_T eval_call_provider(char *provider, char *method, list_T *arguments, bool discard)
{
if (!eval_has_provider(provider)) {
emsgf("E319: No \"%s\" provider found. Run \":checkhealth provider\"",
@@ -10410,19 +10929,11 @@ typval_T eval_call_provider(char *provider, char *method, list_T *arguments,
typval_T rettv = { .v_type = VAR_UNKNOWN, .v_lock = VAR_UNLOCKED };
tv_list_ref(arguments);
- int dummy;
- (void)call_func((const char_u *)func,
- name_len,
- &rettv,
- 2,
- argvars,
- NULL,
- curwin->w_cursor.lnum,
- curwin->w_cursor.lnum,
- &dummy,
- true,
- NULL,
- NULL);
+ funcexe_T funcexe = FUNCEXE_INIT;
+ funcexe.firstline = curwin->w_cursor.lnum;
+ funcexe.lastline = curwin->w_cursor.lnum;
+ funcexe.evaluate = true;
+ (void)call_func((const char_u *)func, name_len, &rettv, 2, argvars, &funcexe);
tv_list_unref(arguments);
// Restore caller scope information
@@ -10542,59 +11053,59 @@ void ex_checkhealth(exarg_T *eap)
void invoke_prompt_callback(void)
{
- typval_T rettv;
- typval_T argv[2];
- char_u *text;
- char_u *prompt;
- linenr_T lnum = curbuf->b_ml.ml_line_count;
-
- // Add a new line for the prompt before invoking the callback, so that
- // text can always be inserted above the last line.
- ml_append(lnum, (char_u *)"", 0, false);
- curwin->w_cursor.lnum = lnum + 1;
- curwin->w_cursor.col = 0;
-
- if (curbuf->b_prompt_callback.type == kCallbackNone) {
- return;
- }
- text = ml_get(lnum);
- prompt = prompt_text();
- if (STRLEN(text) >= STRLEN(prompt)) {
- text += STRLEN(prompt);
- }
- argv[0].v_type = VAR_STRING;
- argv[0].vval.v_string = vim_strsave(text);
- argv[1].v_type = VAR_UNKNOWN;
+ typval_T rettv;
+ typval_T argv[2];
+ char_u *text;
+ char_u *prompt;
+ linenr_T lnum = curbuf->b_ml.ml_line_count;
+
+ // Add a new line for the prompt before invoking the callback, so that
+ // text can always be inserted above the last line.
+ ml_append(lnum, (char_u *)"", 0, false);
+ curwin->w_cursor.lnum = lnum + 1;
+ curwin->w_cursor.col = 0;
+
+ if (curbuf->b_prompt_callback.type == kCallbackNone) {
+ return;
+ }
+ text = ml_get(lnum);
+ prompt = prompt_text();
+ if (STRLEN(text) >= STRLEN(prompt)) {
+ text += STRLEN(prompt);
+ }
+ argv[0].v_type = VAR_STRING;
+ argv[0].vval.v_string = vim_strsave(text);
+ argv[1].v_type = VAR_UNKNOWN;
- callback_call(&curbuf->b_prompt_callback, 1, argv, &rettv);
- tv_clear(&argv[0]);
- tv_clear(&rettv);
+ callback_call(&curbuf->b_prompt_callback, 1, argv, &rettv);
+ tv_clear(&argv[0]);
+ tv_clear(&rettv);
}
// Return true When the interrupt callback was invoked.
bool invoke_prompt_interrupt(void)
{
- typval_T rettv;
- typval_T argv[1];
+ typval_T rettv;
+ typval_T argv[1];
- if (curbuf->b_prompt_interrupt.type == kCallbackNone) {
- return false;
- }
- argv[0].v_type = VAR_UNKNOWN;
+ if (curbuf->b_prompt_interrupt.type == kCallbackNone) {
+ return false;
+ }
+ argv[0].v_type = VAR_UNKNOWN;
- got_int = false; // don't skip executing commands
- callback_call(&curbuf->b_prompt_interrupt, 0, argv, &rettv);
- tv_clear(&rettv);
- return true;
+ got_int = false; // don't skip executing commands
+ callback_call(&curbuf->b_prompt_interrupt, 0, argv, &rettv);
+ tv_clear(&rettv);
+ return true;
}
-// Compare "typ1" and "typ2". Put the result in "typ1".
-int typval_compare(
- typval_T *typ1, // first operand
- typval_T *typ2, // second operand
- exprtype_T type, // operator
- bool ic // ignore case
-)
+/// Compare "typ1" and "typ2". Put the result in "typ1".
+///
+/// @param typ1 first operand
+/// @param typ2 second operand
+/// @param type operator
+/// @param ic ignore case
+int typval_compare(typval_T *typ1, typval_T *typ2, exprtype_T type, bool ic)
FUNC_ATTR_NONNULL_ALL
{
varnumber_T n1, n2;
@@ -10604,10 +11115,33 @@ int typval_compare(
// For "is" a different type always means false, for "notis"
// it means true.
n1 = type == EXPR_ISNOT;
+ } else if (typ1->v_type == VAR_BLOB || typ2->v_type == VAR_BLOB) {
+ if (type_is) {
+ n1 = typ1->v_type == typ2->v_type
+ && typ1->vval.v_blob == typ2->vval.v_blob;
+ if (type == EXPR_ISNOT) {
+ n1 = !n1;
+ }
+ } else if (typ1->v_type != typ2->v_type
+ || (type != EXPR_EQUAL && type != EXPR_NEQUAL)) {
+ if (typ1->v_type != typ2->v_type) {
+ EMSG(_("E977: Can only compare Blob with Blob"));
+ } else {
+ EMSG(_(e_invalblob));
+ }
+ tv_clear(typ1);
+ return FAIL;
+ } else {
+ // Compare two Blobs for being equal or unequal.
+ n1 = tv_blob_equal(typ1->vval.v_blob, typ2->vval.v_blob);
+ if (type == EXPR_NEQUAL) {
+ n1 = !n1;
+ }
+ }
} else if (typ1->v_type == VAR_LIST || typ2->v_type == VAR_LIST) {
if (type_is) {
n1 = typ1->v_type == typ2->v_type
- && typ1->vval.v_list == typ2->vval.v_list;
+ && typ1->vval.v_list == typ2->vval.v_list;
if (type == EXPR_ISNOT) {
n1 = !n1;
}
@@ -10630,7 +11164,7 @@ int typval_compare(
} else if (typ1->v_type == VAR_DICT || typ2->v_type == VAR_DICT) {
if (type_is) {
n1 = typ1->v_type == typ2->v_type
- && typ1->vval.v_dict == typ2->vval.v_dict;
+ && typ1->vval.v_dict == typ2->vval.v_dict;
if (type == EXPR_ISNOT) {
n1 = !n1;
}
@@ -10685,17 +11219,24 @@ int typval_compare(
const float_T f2 = tv_get_float(typ2);
n1 = false;
switch (type) {
- case EXPR_IS:
- case EXPR_EQUAL: n1 = f1 == f2; break;
- case EXPR_ISNOT:
- case EXPR_NEQUAL: n1 = f1 != f2; break;
- case EXPR_GREATER: n1 = f1 > f2; break;
- case EXPR_GEQUAL: n1 = f1 >= f2; break;
- case EXPR_SMALLER: n1 = f1 < f2; break;
- case EXPR_SEQUAL: n1 = f1 <= f2; break;
- case EXPR_UNKNOWN:
- case EXPR_MATCH:
- case EXPR_NOMATCH: break; // avoid gcc warning
+ case EXPR_IS:
+ case EXPR_EQUAL:
+ n1 = f1 == f2; break;
+ case EXPR_ISNOT:
+ case EXPR_NEQUAL:
+ n1 = f1 != f2; break;
+ case EXPR_GREATER:
+ n1 = f1 > f2; break;
+ case EXPR_GEQUAL:
+ n1 = f1 >= f2; break;
+ case EXPR_SMALLER:
+ n1 = f1 < f2; break;
+ case EXPR_SEQUAL:
+ n1 = f1 <= f2; break;
+ case EXPR_UNKNOWN:
+ case EXPR_MATCH:
+ case EXPR_NOMATCH:
+ break; // avoid gcc warning
}
} else if ((typ1->v_type == VAR_NUMBER || typ2->v_type == VAR_NUMBER)
&& type != EXPR_MATCH && type != EXPR_NOMATCH) {
@@ -10704,17 +11245,24 @@ int typval_compare(
n1 = tv_get_number(typ1);
n2 = tv_get_number(typ2);
switch (type) {
- case EXPR_IS:
- case EXPR_EQUAL: n1 = n1 == n2; break;
- case EXPR_ISNOT:
- case EXPR_NEQUAL: n1 = n1 != n2; break;
- case EXPR_GREATER: n1 = n1 > n2; break;
- case EXPR_GEQUAL: n1 = n1 >= n2; break;
- case EXPR_SMALLER: n1 = n1 < n2; break;
- case EXPR_SEQUAL: n1 = n1 <= n2; break;
- case EXPR_UNKNOWN:
- case EXPR_MATCH:
- case EXPR_NOMATCH: break; // avoid gcc warning
+ case EXPR_IS:
+ case EXPR_EQUAL:
+ n1 = n1 == n2; break;
+ case EXPR_ISNOT:
+ case EXPR_NEQUAL:
+ n1 = n1 != n2; break;
+ case EXPR_GREATER:
+ n1 = n1 > n2; break;
+ case EXPR_GEQUAL:
+ n1 = n1 >= n2; break;
+ case EXPR_SMALLER:
+ n1 = n1 < n2; break;
+ case EXPR_SEQUAL:
+ n1 = n1 <= n2; break;
+ case EXPR_UNKNOWN:
+ case EXPR_MATCH:
+ case EXPR_NOMATCH:
+ break; // avoid gcc warning
}
} else {
char buf1[NUMBUFLEN];
@@ -10729,23 +11277,30 @@ int typval_compare(
}
n1 = false;
switch (type) {
- case EXPR_IS:
- case EXPR_EQUAL: n1 = i == 0; break;
- case EXPR_ISNOT:
- case EXPR_NEQUAL: n1 = i != 0; break;
- case EXPR_GREATER: n1 = i > 0; break;
- case EXPR_GEQUAL: n1 = i >= 0; break;
- case EXPR_SMALLER: n1 = i < 0; break;
- case EXPR_SEQUAL: n1 = i <= 0; break;
-
- case EXPR_MATCH:
- case EXPR_NOMATCH:
- n1 = pattern_match((char_u *)s2, (char_u *)s1, ic);
- if (type == EXPR_NOMATCH) {
- n1 = !n1;
- }
- break;
- case EXPR_UNKNOWN: break; // avoid gcc warning
+ case EXPR_IS:
+ case EXPR_EQUAL:
+ n1 = i == 0; break;
+ case EXPR_ISNOT:
+ case EXPR_NEQUAL:
+ n1 = i != 0; break;
+ case EXPR_GREATER:
+ n1 = i > 0; break;
+ case EXPR_GEQUAL:
+ n1 = i >= 0; break;
+ case EXPR_SMALLER:
+ n1 = i < 0; break;
+ case EXPR_SEQUAL:
+ n1 = i <= 0; break;
+
+ case EXPR_MATCH:
+ case EXPR_NOMATCH:
+ n1 = pattern_match((char_u *)s2, (char_u *)s1, ic);
+ if (type == EXPR_NOMATCH) {
+ n1 = !n1;
+ }
+ break;
+ case EXPR_UNKNOWN:
+ break; // avoid gcc warning
}
}
tv_clear(typ1);
@@ -10780,7 +11335,9 @@ bool var_exists(const char *var)
n = get_var_tv(name, len, &tv, NULL, false, true) == OK;
if (n) {
// Handle d.key, l[idx], f(expr).
- n = handle_subscript(&var, &tv, true, false) == OK;
+ n = handle_subscript(&var, &tv, true, false, (const char_u *)name,
+ (const char_u **)&name)
+ == OK;
if (n) {
tv_clear(&tv);
}
diff --git a/src/nvim/eval.h b/src/nvim/eval.h
index 41120b3c78..2452a0a8c8 100644
--- a/src/nvim/eval.h
+++ b/src/nvim/eval.h
@@ -63,6 +63,7 @@ typedef struct lval_S {
dict_T *ll_dict; ///< The Dictionary or NULL.
dictitem_T *ll_di; ///< The dictitem or NULL.
char_u *ll_newkey; ///< New key for Dict in allocated memory or NULL.
+ blob_T *ll_blob; ///< The Blob or NULL.
} lval_T;
/// enum used by var_flavour()
@@ -154,6 +155,7 @@ typedef enum {
VV_TYPE_DICT,
VV_TYPE_FLOAT,
VV_TYPE_BOOL,
+ VV_TYPE_BLOB,
VV_EVENT,
VV_ECHOSPACE,
VV_ARGV,
@@ -165,6 +167,7 @@ typedef enum {
VV__NULL_STRING, // String with NULL value. For test purposes only.
VV__NULL_LIST, // List with NULL value. For test purposes only.
VV__NULL_DICT, // Dictionary with NULL value. For test purposes only.
+ VV__NULL_BLOB, // Blob with NULL value. For test purposes only.
VV_LUA,
} VimVarIndex;
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index 33c6fae5cf..c6ac27b269 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -5,6 +5,9 @@
-- args Number of arguments, list with maximum and minimum number of arguments
-- or list with a minimum number of arguments only. Defaults to zero
-- arguments.
+-- base For methods: the argument to use as the base argument (1-indexed):
+-- base->method()
+-- Defaults to BASE_NONE (function cannot be used as a method).
-- func Name of the C function which implements the VimL function. Defaults to
-- `f_{funcname}`.
@@ -12,111 +15,115 @@ local varargs = function(nr)
return {nr}
end
+-- Usable with the base key: use the last function argument as the method base.
+-- Value is from funcs.h file. "BASE_" prefix is omitted.
+local LAST = "BASE_LAST"
+
return {
funcs={
- abs={args=1},
- acos={args=1, func="float_op_wrapper", data="&acos"}, -- WJMc
- add={args=2},
- ['and']={args=2},
+ abs={args=1, base=1},
+ acos={args=1, base=1, func="float_op_wrapper", data="&acos"}, -- WJMc
+ add={args=2, base=1},
+ ['and']={args=2, base=1},
api_info={},
- append={args=2},
- appendbufline={args=3},
+ append={args=2, base=LAST},
+ appendbufline={args=3, base=LAST},
argc={args={0, 1}},
argidx={},
arglistid={args={0, 2}},
argv={args={0, 2}},
- asin={args=1, func="float_op_wrapper", data="&asin"}, -- WJMc
- assert_beeps={args={1}},
- assert_equal={args={2, 3}},
- assert_equalfile={args={2, 3}},
+ asin={args=1, base=1, func="float_op_wrapper", data="&asin"}, -- WJMc
+ assert_beeps={args={1}, base=1},
+ assert_equal={args={2, 3}, base=2},
+ assert_equalfile={args={2, 3}, base=1},
assert_exception={args={1, 2}},
- assert_fails={args={1, 3}},
- assert_false={args={1, 2}},
- assert_inrange={args={3, 4}},
- assert_match={args={2, 3}},
+ assert_fails={args={1, 3}, base=1},
+ assert_false={args={1, 2}, base=1},
+ assert_inrange={args={3, 4}, base=3},
+ assert_match={args={2, 3}, base=2},
assert_nobeep={args={1}},
- assert_notequal={args={2, 3}},
- assert_notmatch={args={2, 3}},
- assert_report={args=1},
- assert_true={args={1, 2}},
- atan={args=1, func="float_op_wrapper", data="&atan"},
- atan2={args=2},
+ assert_notequal={args={2, 3}, base=2},
+ assert_notmatch={args={2, 3}, base=2},
+ assert_report={args=1, base=1},
+ assert_true={args={1, 2}, base=1},
+ atan={args=1, base=1, func="float_op_wrapper", data="&atan"},
+ atan2={args=2, base=1},
browse={args=4},
browsedir={args=2},
- bufadd={args=1},
- bufexists={args=1},
- buffer_exists={args=1, func='f_bufexists'}, -- obsolete
+ bufadd={args=1, base=1},
+ bufexists={args=1, base=1},
+ buffer_exists={args=1, base=1, func='f_bufexists'}, -- obsolete
buffer_name={args={0, 1}, func='f_bufname'}, -- obsolete
buffer_number={args={0, 1}, func='f_bufnr'}, -- obsolete
- buflisted={args=1},
- bufload={args=1},
- bufloaded={args=1},
- bufname={args={0, 1}},
- bufnr={args={0, 2}},
- bufwinid={args=1},
- bufwinnr={args=1},
- byte2line={args=1},
- byteidx={args=2},
- byteidxcomp={args=2},
- call={args={2, 3}},
- ceil={args=1, func="float_op_wrapper", data="&ceil"},
+ buflisted={args=1, base=1},
+ bufload={args=1, base=1},
+ bufloaded={args=1, base=1},
+ bufname={args={0, 1}, base=1},
+ bufnr={args={0, 2}, base=1},
+ bufwinid={args=1, base=1},
+ bufwinnr={args=1, base=1},
+ byte2line={args=1, base=1},
+ byteidx={args=2, base=1},
+ byteidxcomp={args=2, base=1},
+ call={args={2, 3}, base=1},
+ ceil={args=1, base=1, func="float_op_wrapper", data="&ceil"},
changenr={},
chanclose={args={1, 2}},
chansend={args=2},
- char2nr={args={1, 2}},
+ char2nr={args={1, 2}, base=1},
charidx={args={2, 3}},
- cindent={args=1},
- clearmatches={args={0, 1}},
- col={args=1},
- complete={args=2},
- complete_add={args=1},
+ cindent={args=1, base=1},
+ clearmatches={args={0, 1}, base=1},
+ col={args=1, base=1},
+ complete={args=2, base=2},
+ complete_add={args=1, base=1},
complete_check={},
- complete_info={args={0, 1}},
- confirm={args={1, 4}},
- copy={args=1},
- cos={args=1, func="float_op_wrapper", data="&cos"},
- cosh={args=1, func="float_op_wrapper", data="&cosh"},
- count={args={2, 4}},
+ complete_info={args={0, 1}, base=1},
+ confirm={args={1, 4}, base=1},
+ copy={args=1, base=1},
+ cos={args=1, base=1, func="float_op_wrapper", data="&cos"},
+ cosh={args=1, base=1, func="float_op_wrapper", data="&cosh"},
+ count={args={2, 4}, base=1},
cscope_connection={args={0, 3}},
ctxget={args={0, 1}},
ctxpop={},
ctxpush={args={0, 1}},
ctxset={args={1, 2}},
ctxsize={},
- cursor={args={1, 3}},
- debugbreak={args={1, 1}},
- deepcopy={args={1, 2}},
- delete={args={1,2}},
- deletebufline={args={2,3}},
+ cursor={args={1, 3}, base=1},
+ debugbreak={args={1, 1}, base=1},
+ deepcopy={args={1, 2}, base=1},
+ delete={args={1,2}, base=1},
+ deletebufline={args={2,3}, base=1},
dictwatcheradd={args=3},
dictwatcherdel={args=3},
did_filetype={},
- diff_filler={args=1},
- diff_hlID={args=2},
- empty={args=1},
+ diff_filler={args=1, base=1},
+ diff_hlID={args=2, base=1},
+ empty={args=1, base=1},
environ={},
escape={args=2},
- eval={args=1},
+ eval={args=1, base=1},
eventhandler={},
executable={args=1},
execute={args={1, 2}},
exepath={args=1},
exists={args=1},
- exp={args=1, func="float_op_wrapper", data="&exp"},
+ exp={args=1, base=1, func="float_op_wrapper", data="&exp"},
expand={args={1, 3}},
expandcmd={args=1},
- extend={args={2, 3}},
+ extend={args={2, 3}, base=1},
feedkeys={args={1, 2}},
file_readable={args=1, func='f_filereadable'}, -- obsolete
filereadable={args=1},
filewritable={args=1},
- filter={args=2},
+ filter={args=2, base=1},
finddir={args={1, 3}},
findfile={args={1, 3}},
flatten={args={1, 2}},
- float2nr={args=1},
- floor={args=1, func="float_op_wrapper", data="&floor"},
- fmod={args=2},
+ float2nr={args=1, base=1},
+ floor={args=1, base=1, func="float_op_wrapper", data="&floor"},
+ fmod={args=2, base=1},
fnameescape={args=1},
fnamemodify={args=2},
foldclosed={args=1},
@@ -128,7 +135,7 @@ return {
funcref={args={1, 3}},
['function']={args={1, 3}},
garbagecollect={args={0, 1}},
- get={args={2, 3}},
+ get={args={2, 3}, base=1},
getbufinfo={args={0, 1}},
getbufline={args={2, 3}},
getbufvar={args={2, 3}},
@@ -136,6 +143,7 @@ return {
getchar={args={0, 1}},
getcharmod={},
getcharsearch={},
+ getcharstr={args={0, 1}},
getcmdline={},
getcmdpos={},
getcmdtype={},
@@ -154,10 +162,12 @@ return {
getloclist={args={1, 2}},
getmarklist={args={0, 1}},
getmatches={args={0, 1}},
+ getmousepos={},
getpid={},
getpos={args=1},
getqflist={args={0, 1}},
getreg={args={0, 3}},
+ getreginfo={args={0, 1}, base=1},
getregtype={args={0, 1}},
gettabinfo={args={0, 1}},
gettabvar={args={2, 3}},
@@ -172,7 +182,7 @@ return {
glob2regpat={args=1},
globpath={args={2, 5}},
has={args=1},
- has_key={args=2},
+ has_key={args=2, base=1},
haslocaldir={args={0,2}},
hasmapto={args={1, 3}},
highlightID={args=1, func='f_hlID'}, -- obsolete
@@ -186,22 +196,22 @@ return {
hostname={},
iconv={args=3},
indent={args=1},
- index={args={2, 4}},
+ index={args={2, 4}, base=1},
input={args={1, 3}},
inputdialog={args={1, 3}},
inputlist={args=1},
inputrestore={},
inputsave={},
inputsecret={args={1, 2}},
- insert={args={2, 3}},
+ insert={args={2, 3}, base=1},
interrupt={args=0},
- invert={args=1},
+ invert={args=1, base=1},
isdirectory={args=1},
- isinf={args=1},
+ isinf={args=1, base=1},
islocked={args=1},
- isnan={args=1},
+ isnan={args=1, base=1},
id={args=1},
- items={args=1},
+ items={args=1, base=1},
jobclose={args={1, 2}, func="f_chanclose"},
jobpid={args=1},
jobresize={args=3},
@@ -209,12 +219,12 @@ return {
jobstart={args={1, 2}},
jobstop={args=1},
jobwait={args={1, 2}},
- join={args={1, 2}},
+ join={args={1, 2}, base=1},
json_decode={args=1},
json_encode={args=1},
- keys={args=1},
+ keys={args=1, base=1},
last_buffer_nr={}, -- obsolete
- len={args=1},
+ len={args=1, base=1},
libcall={args=3},
libcallnr={args=3},
line={args={1, 2}},
@@ -222,10 +232,10 @@ return {
lispindent={args=1},
list2str={args={1, 2}},
localtime={},
- log={args=1, func="float_op_wrapper", data="&log"},
- log10={args=1, func="float_op_wrapper", data="&log10"},
+ log={args=1, base=1, func="float_op_wrapper", data="&log"},
+ log10={args=1, base=1, func="float_op_wrapper", data="&log10"},
luaeval={args={1, 2}},
- map={args=2},
+ map={args=2, base=1},
maparg={args={1, 4}},
mapcheck={args={1, 3}},
match={args={2, 4}},
@@ -237,20 +247,20 @@ return {
matchlist={args={2, 4}},
matchstr={args={2, 4}},
matchstrpos={args={2,4}},
- max={args=1},
+ max={args=1, base=1},
menu_get={args={1, 2}},
- min={args=1},
+ min={args=1, base=1},
mkdir={args={1, 3}},
mode={args={0, 1}},
- msgpackdump={args=1},
+ msgpackdump={args={1, 2}},
msgpackparse={args=1},
nextnonblank={args=1},
nr2char={args={1, 2}},
- ['or']={args=2},
+ ['or']={args=2, base=1},
pathshorten={args=1},
- pow={args=2},
+ pow={args=2, base=1},
prevnonblank={args=1},
- printf={args=varargs(1)},
+ printf={args=varargs(1), base=2},
prompt_getprompt={args=1},
prompt_setcallback={args={2, 2}},
prompt_setinterrupt={args={2, 2}},
@@ -269,12 +279,12 @@ return {
reltime={args={0, 2}},
reltimefloat={args=1},
reltimestr={args=1},
- remove={args={2, 3}},
+ remove={args={2, 3}, base=1},
rename={args=2},
- ['repeat']={args=2},
+ ['repeat']={args=2, base=1},
resolve={args=1},
- reverse={args=1},
- round={args=1, func="float_op_wrapper", data="&round"},
+ reverse={args=1, base=1},
+ round={args=1, base=1, func="float_op_wrapper", data="&round"},
rpcnotify={args=varargs(2)},
rpcrequest={args=varargs(2)},
rpcstart={args={1, 2}},
@@ -282,9 +292,11 @@ return {
rubyeval={args=1},
screenattr={args=2},
screenchar={args=2},
+ screenchars={args=2},
screencol={},
screenpos={args=3},
screenrow={},
+ screenstring={args=2},
search={args={1, 4}},
searchcount={args={0,1}},
searchdecl={args={1, 3}},
@@ -323,51 +335,51 @@ return {
sign_unplace={args={1, 2}},
sign_unplacelist={args={1}},
simplify={args=1},
- sin={args=1, func="float_op_wrapper", data="&sin"},
- sinh={args=1, func="float_op_wrapper", data="&sinh"},
+ sin={args=1, base=1, func="float_op_wrapper", data="&sin"},
+ sinh={args=1, base=1, func="float_op_wrapper", data="&sinh"},
sockconnect={args={2,3}},
- sort={args={1, 3}},
+ sort={args={1, 3}, base=1},
soundfold={args=1},
stdioopen={args=1},
spellbadword={args={0, 1}},
spellsuggest={args={1, 3}},
- split={args={1, 3}},
- sqrt={args=1, func="float_op_wrapper", data="&sqrt"},
+ split={args={1, 3}, base=1},
+ sqrt={args=1, base=1, func="float_op_wrapper", data="&sqrt"},
stdpath={args=1},
- str2float={args=1},
- str2list={args={1, 2}},
- str2nr={args={1, 2}},
+ str2float={args=1, base=1},
+ str2list={args={1, 2}, base=1},
+ str2nr={args={1, 3}},
strcharpart={args={2, 3}},
strchars={args={1,2}},
strdisplaywidth={args={1, 2}},
strftime={args={1, 2}},
strgetchar={args={2, 2}},
stridx={args={2, 3}},
- string={args=1},
- strlen={args=1},
+ string={args=1, base=1},
+ strlen={args=1, base=1},
strpart={args={2, 4}},
strptime={args=2},
strridx={args={2, 3}},
- strtrans={args=1},
- strwidth={args=1},
+ strtrans={args=1, base=1},
+ strwidth={args=1, base=1},
submatch={args={1, 2}},
- substitute={args=4},
+ substitute={args=4, base=1},
swapinfo={args={1}},
swapname={args={1}},
synID={args=3},
- synIDattr={args={2, 3}},
- synIDtrans={args=1},
+ synIDattr={args={2, 3}, base=1},
+ synIDtrans={args=1, base=1},
synconcealed={args=2},
synstack={args=2},
- system={args={1, 2}},
- systemlist={args={1, 3}},
+ system={args={1, 2}, base=1},
+ systemlist={args={1, 3}, base=1},
tabpagebuflist={args={0, 1}},
tabpagenr={args={0, 1}},
tabpagewinnr={args={1, 2}},
tagfiles={},
taglist={args={1, 2}},
- tan={args=1, func="float_op_wrapper", data="&tan"},
- tanh={args=1, func="float_op_wrapper", data="&tanh"},
+ tan={args=1, base=1, func="float_op_wrapper", data="&tan"},
+ tanh={args=1, base=1, func="float_op_wrapper", data="&tanh"},
tempname={},
termopen={args={1, 2}},
test_garbagecollect_now={},
@@ -381,12 +393,12 @@ return {
toupper={args=1},
tr={args=3},
trim={args={1,3}},
- trunc={args=1, func="float_op_wrapper", data="&trunc"},
- type={args=1},
+ trunc={args=1, base=1, func="float_op_wrapper", data="&trunc"},
+ type={args=1, base=1},
undofile={args=1},
undotree={},
- uniq={args={1, 3}},
- values={args=1},
+ uniq={args={1, 3}, base=1},
+ values={args=1, base=1},
virtcol={args=1},
visualmode={args={0, 1}},
wait={args={2,3}},
@@ -400,7 +412,7 @@ return {
win_id2win={args=1},
win_screenpos={args=1},
win_splitmove={args={2, 3}},
- winbufnr={args=1},
+ winbufnr={args=1, base=1},
wincol={},
windowsversion={},
winheight={args=1},
@@ -413,6 +425,6 @@ return {
winwidth={args=1},
wordcount={},
writefile={args={2, 3}},
- xor={args=2},
+ xor={args=2, base=1},
},
}
diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c
index bd4dc87d31..c8734c9b9c 100644
--- a/src/nvim/eval/decode.c
+++ b/src/nvim/eval/decode.c
@@ -1,20 +1,19 @@
// 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 <stddef.h>
-
#include <msgpack.h>
+#include <stddef.h>
-#include "nvim/eval/typval.h"
+#include "nvim/ascii.h"
+#include "nvim/charset.h" // vim_str2nr
#include "nvim/eval.h"
#include "nvim/eval/decode.h"
#include "nvim/eval/encode.h"
-#include "nvim/ascii.h"
-#include "nvim/macros.h"
-#include "nvim/message.h"
+#include "nvim/eval/typval.h"
#include "nvim/globals.h"
-#include "nvim/charset.h" // vim_str2nr
#include "nvim/lib/kvec.h"
+#include "nvim/macros.h"
+#include "nvim/message.h"
#include "nvim/vim.h" // OK, FAIL
/// Helper structure for container_struct
@@ -52,8 +51,7 @@ typedef kvec_t(ContainerStackItem) ContainerStack;
/// @param[out] rettv Location where created dictionary will be saved.
/// @param[in] type Type of the dictionary.
/// @param[in] val Value associated with the _VAL key.
-static inline void create_special_dict(typval_T *const rettv,
- const MessagePackType type,
+static inline void create_special_dict(typval_T *const rettv, const MessagePackType type,
typval_T val)
FUNC_ATTR_NONNULL_ALL
{
@@ -97,12 +95,9 @@ static inline void create_special_dict(typval_T *const rettv,
/// value when decoder is restarted, otherwise unused.
///
/// @return OK in case of success, FAIL in case of error.
-static inline int json_decoder_pop(ValuesStackItem obj,
- ValuesStack *const stack,
- ContainerStack *const container_stack,
- const char **const pp,
- bool *const next_map_special,
- bool *const didcomma,
+static inline int json_decoder_pop(ValuesStackItem obj, ValuesStack *const stack,
+ ContainerStack *const container_stack, const char **const pp,
+ bool *const next_map_special, bool *const didcomma,
bool *const didcolon)
FUNC_ATTR_NONNULL_ALL
{
@@ -114,9 +109,9 @@ static inline int json_decoder_pop(ValuesStackItem obj,
const char *val_location = *pp;
if (obj.val.v_type == last_container.container.v_type
// vval.v_list and vval.v_dict should have the same size and offset
- && ((void *) obj.val.vval.v_list
- == (void *) last_container.container.vval.v_list)) {
- (void) kv_pop(*container_stack);
+ && ((void *)obj.val.vval.v_list
+ == (void *)last_container.container.vval.v_list)) {
+ (void)kv_pop(*container_stack);
val_location = last_container.s;
last_container = kv_last(*container_stack);
}
@@ -142,8 +137,7 @@ static inline int json_decoder_pop(ValuesStackItem obj,
assert(!(key.is_special_string
|| key.val.vval.v_string == NULL
|| *key.val.vval.v_string == NUL));
- dictitem_T *const obj_di = tv_dict_item_alloc(
- (const char *)key.val.vval.v_string);
+ dictitem_T *const obj_di = tv_dict_item_alloc((const char *)key.val.vval.v_string);
tv_clear(&key.val);
if (tv_dict_add(last_container.container.vval.v_dict, obj_di)
== FAIL) {
@@ -179,9 +173,9 @@ static inline int json_decoder_pop(ValuesStackItem obj,
tv_clear(&obj.val);
// Restart
- (void) kv_pop(*container_stack);
+ (void)kv_pop(*container_stack);
ValuesStackItem last_container_val =
- kv_A(*stack, last_container.stack_index);
+ kv_A(*stack, last_container.stack_index);
while (kv_size(*stack) > last_container.stack_index) {
tv_clear(&(kv_pop(*stack).val));
}
@@ -197,7 +191,7 @@ static inline int json_decoder_pop(ValuesStackItem obj,
}
#define LENP(p, e) \
- ((int) ((e) - (p))), (p)
+ ((int)((e) - (p))), (p)
#define OBJ(obj_tv, is_sp_string, didcomma_, didcolon_) \
((ValuesStackItem) { \
.is_special_string = (is_sp_string), \
@@ -229,8 +223,7 @@ static inline int json_decoder_pop(ValuesStackItem obj,
///
/// @return [allocated] list which should contain key-value pairs. Return value
/// may be safely ignored.
-list_T *decode_create_map_special_dict(typval_T *const ret_tv,
- const ptrdiff_t len)
+list_T *decode_create_map_special_dict(typval_T *const ret_tv, const ptrdiff_t len)
FUNC_ATTR_NONNULL_ALL
{
list_T *const list = tv_list_alloc(len);
@@ -246,22 +239,22 @@ list_T *decode_create_map_special_dict(typval_T *const ret_tv,
/// Convert char* string to typval_T
///
/// Depending on whether string has (no) NUL bytes, it may use a special
-/// dictionary or decode string to VAR_STRING.
+/// dictionary, VAR_BLOB, or decode string to VAR_STRING.
///
/// @param[in] s String to decode.
/// @param[in] len String length.
/// @param[in] hasnul Whether string has NUL byte, not or it was not yet
/// determined.
-/// @param[in] binary If true, save special string type as kMPBinary,
-/// otherwise kMPString.
+/// @param[in] binary Determines decode type if string has NUL bytes.
+/// If true convert string to VAR_BLOB, otherwise to the
+/// kMPString special type.
/// @param[in] s_allocated If true, then `s` was allocated and can be saved in
/// a returned structure. If it is not saved there, it
/// will be freed.
///
/// @return Decoded string.
-typval_T decode_string(const char *const s, const size_t len,
- const TriState hasnul, const bool binary,
- const bool s_allocated)
+typval_T decode_string(const char *const s, const size_t len, const TriState hasnul,
+ const bool binary, const bool s_allocated)
FUNC_ATTR_WARN_UNUSED_RESULT
{
assert(s != NULL || len == 0);
@@ -269,21 +262,28 @@ typval_T decode_string(const char *const s, const size_t len,
? ((s != NULL) && (memchr(s, NUL, len) != NULL))
: (bool)hasnul);
if (really_hasnul) {
- list_T *const list = tv_list_alloc(kListLenMayKnow);
- tv_list_ref(list);
typval_T tv;
- create_special_dict(&tv, binary ? kMPBinary : kMPString, ((typval_T) {
- .v_type = VAR_LIST,
- .v_lock = VAR_UNLOCKED,
- .vval = { .v_list = list },
- }));
- const int elw_ret = encode_list_write((void *)list, s, len);
- if (s_allocated) {
- xfree((void *)s);
- }
- if (elw_ret == -1) {
- tv_clear(&tv);
- return (typval_T) { .v_type = VAR_UNKNOWN, .v_lock = VAR_UNLOCKED };
+ tv.v_lock = VAR_UNLOCKED;
+ if (binary) {
+ tv_blob_alloc_ret(&tv);
+ ga_concat_len(&tv.vval.v_blob->bv_ga, s, len);
+ } else {
+ list_T *const list = tv_list_alloc(kListLenMayKnow);
+ tv_list_ref(list);
+ create_special_dict(&tv, kMPString,
+ ((typval_T){
+ .v_type = VAR_LIST,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_list = list },
+ }));
+ const int elw_ret = encode_list_write((void *)list, s, len);
+ if (s_allocated) {
+ xfree((void *)s);
+ }
+ if (elw_ret == -1) {
+ tv_clear(&tv);
+ return (typval_T) { .v_type = VAR_UNKNOWN, .v_lock = VAR_UNLOCKED };
+ }
}
return tv;
} else {
@@ -291,7 +291,7 @@ typval_T decode_string(const char *const s, const size_t len,
.v_type = VAR_STRING,
.v_lock = VAR_UNLOCKED,
.vval = { .v_string = (char_u *)(
- (s == NULL || s_allocated) ? (char *)s : xmemdupz(s, len)) },
+ (s == NULL || s_allocated) ? (char *)s : xmemdupz(s, len)) },
};
}
}
@@ -315,11 +315,9 @@ typval_T decode_string(const char *const s, const size_t len,
///
/// @return OK in case of success, FAIL in case of error.
static inline int parse_json_string(const char *const buf, const size_t buf_len,
- const char **const pp,
- ValuesStack *const stack,
+ const char **const pp, ValuesStack *const stack,
ContainerStack *const container_stack,
- bool *const next_map_special,
- bool *const didcomma,
+ bool *const next_map_special, bool *const didcomma,
bool *const didcolon)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE
{
@@ -333,55 +331,52 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len,
p++;
if (p == e) {
emsgf(_("E474: Unfinished escape sequence: %.*s"),
- (int) buf_len, buf);
+ (int)buf_len, buf);
goto parse_json_string_fail;
}
switch (*p) {
- case 'u': {
- if (p + 4 >= e) {
- emsgf(_("E474: Unfinished unicode escape sequence: %.*s"),
- (int) buf_len, buf);
- goto parse_json_string_fail;
- } else if (!ascii_isxdigit(p[1])
- || !ascii_isxdigit(p[2])
- || !ascii_isxdigit(p[3])
- || !ascii_isxdigit(p[4])) {
- emsgf(_("E474: Expected four hex digits after \\u: %.*s"),
- LENP(p - 1, e));
- goto parse_json_string_fail;
- }
- // One UTF-8 character below U+10000 can take up to 3 bytes,
- // above up to 6, but they are encoded using two \u escapes.
- len += 3;
- p += 5;
- break;
- }
- case '\\':
- case '/':
- case '"':
- case 't':
- case 'b':
- case 'n':
- case 'r':
- case 'f': {
- len++;
- p++;
- break;
- }
- default: {
- emsgf(_("E474: Unknown escape sequence: %.*s"), LENP(p - 1, e));
+ case 'u':
+ if (p + 4 >= e) {
+ emsgf(_("E474: Unfinished unicode escape sequence: %.*s"),
+ (int)buf_len, buf);
+ goto parse_json_string_fail;
+ } else if (!ascii_isxdigit(p[1])
+ || !ascii_isxdigit(p[2])
+ || !ascii_isxdigit(p[3])
+ || !ascii_isxdigit(p[4])) {
+ emsgf(_("E474: Expected four hex digits after \\u: %.*s"),
+ LENP(p - 1, e));
goto parse_json_string_fail;
}
+ // One UTF-8 character below U+10000 can take up to 3 bytes,
+ // above up to 6, but they are encoded using two \u escapes.
+ len += 3;
+ p += 5;
+ break;
+ case '\\':
+ case '/':
+ case '"':
+ case 't':
+ case 'b':
+ case 'n':
+ case 'r':
+ case 'f':
+ len++;
+ p++;
+ break;
+ default:
+ emsgf(_("E474: Unknown escape sequence: %.*s"), LENP(p - 1, e));
+ goto parse_json_string_fail;
}
} else {
- uint8_t p_byte = (uint8_t) *p;
+ uint8_t p_byte = (uint8_t)*p;
// unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
if (p_byte < 0x20) {
emsgf(_("E474: ASCII control characters cannot be present "
"inside string: %.*s"), LENP(p, e));
goto parse_json_string_fail;
}
- const int ch = utf_ptr2char((char_u *) p);
+ const int ch = utf_ptr2char((char_u *)p);
// All characters above U+007F are encoded using two or more bytes
// and thus cannot possibly be equal to *p. But utf_ptr2char({0xFF,
// 0}) will return 0xFF, even though 0xFF cannot start any UTF-8
@@ -389,7 +384,7 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len,
//
// The only exception is U+00C3 which is represented as 0xC3 0x83.
if (ch >= 0x80 && p_byte == ch
- && !(ch == 0xC3 && p + 1 < e && (uint8_t) p[1] == 0x83)) {
+ && !(ch == 0xC3 && p + 1 < e && (uint8_t)p[1] == 0x83)) {
emsgf(_("E474: Only UTF-8 strings allowed: %.*s"), LENP(p, e));
goto parse_json_string_fail;
} else if (ch > 0x10FFFF) {
@@ -397,14 +392,14 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len,
"are allowed to appear unescaped: %.*s"), LENP(p, e));
goto parse_json_string_fail;
}
- const size_t ch_len = (size_t) utf_char2len(ch);
- assert(ch_len == (size_t) (ch ? utf_ptr2len((char_u *) p) : 1));
+ const size_t ch_len = (size_t)utf_char2len(ch);
+ assert(ch_len == (size_t)(ch ? utf_ptr2len((char_u *)p) : 1));
len += ch_len;
p += ch_len;
}
}
if (p == e || *p != '"') {
- emsgf(_("E474: Expected string end: %.*s"), (int) buf_len, buf);
+ emsgf(_("E474: Expected string end: %.*s"), (int)buf_len, buf);
goto parse_json_string_fail;
}
if (len == 0) {
@@ -421,7 +416,7 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len,
#define PUT_FST_IN_PAIR(fst_in_pair, str_end) \
do { \
if (fst_in_pair != 0) { \
- str_end += utf_char2bytes(fst_in_pair, (char_u *) str_end); \
+ str_end += utf_char2bytes(fst_in_pair, (char_u *)str_end); \
fst_in_pair = 0; \
} \
} while (0)
@@ -432,56 +427,55 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len,
if (*t == '\\') {
t++;
switch (*t) {
- case 'u': {
- const char ubuf[] = { t[1], t[2], t[3], t[4] };
- t += 4;
- uvarnumber_T ch;
- vim_str2nr((char_u *)ubuf, NULL, NULL,
- STR2NR_HEX | STR2NR_FORCE, NULL, &ch, 4);
- if (ch == 0) {
- hasnul = true;
- }
- if (SURROGATE_HI_START <= ch && ch <= SURROGATE_HI_END) {
- PUT_FST_IN_PAIR(fst_in_pair, str_end);
- fst_in_pair = (int) ch;
- } else if (SURROGATE_LO_START <= ch && ch <= SURROGATE_LO_END
- && fst_in_pair != 0) {
- const int full_char = (
- (int) (ch - SURROGATE_LO_START)
- + ((fst_in_pair - SURROGATE_HI_START) << 10)
- + SURROGATE_FIRST_CHAR);
- str_end += utf_char2bytes(full_char, (char_u *) str_end);
- fst_in_pair = 0;
- } else {
- PUT_FST_IN_PAIR(fst_in_pair, str_end);
- str_end += utf_char2bytes((int) ch, (char_u *) str_end);
- }
- break;
+ case 'u': {
+ const char ubuf[] = { t[1], t[2], t[3], t[4] };
+ t += 4;
+ uvarnumber_T ch;
+ vim_str2nr((char_u *)ubuf, NULL, NULL,
+ STR2NR_HEX | STR2NR_FORCE, NULL, &ch, 4, true);
+ if (ch == 0) {
+ hasnul = true;
}
- case '\\':
- case '/':
- case '"':
- case 't':
- case 'b':
- case 'n':
- case 'r':
- case 'f': {
- static const char escapes[] = {
- ['\\'] = '\\',
- ['/'] = '/',
- ['"'] = '"',
- ['t'] = TAB,
- ['b'] = BS,
- ['n'] = NL,
- ['r'] = CAR,
- ['f'] = FF,
- };
- *str_end++ = escapes[(int) *t];
- break;
- }
- default: {
- abort();
+ if (SURROGATE_HI_START <= ch && ch <= SURROGATE_HI_END) {
+ PUT_FST_IN_PAIR(fst_in_pair, str_end);
+ fst_in_pair = (int)ch;
+ } else if (SURROGATE_LO_START <= ch && ch <= SURROGATE_LO_END
+ && fst_in_pair != 0) {
+ const int full_char = (
+ (int)(ch - SURROGATE_LO_START)
+ + ((fst_in_pair - SURROGATE_HI_START) << 10)
+ + SURROGATE_FIRST_CHAR);
+ str_end += utf_char2bytes(full_char, (char_u *)str_end);
+ fst_in_pair = 0;
+ } else {
+ PUT_FST_IN_PAIR(fst_in_pair, str_end);
+ str_end += utf_char2bytes((int)ch, (char_u *)str_end);
}
+ break;
+ }
+ case '\\':
+ case '/':
+ case '"':
+ case 't':
+ case 'b':
+ case 'n':
+ case 'r':
+ case 'f': {
+ static const char escapes[] = {
+ ['\\'] = '\\',
+ ['/'] = '/',
+ ['"'] = '"',
+ ['t'] = TAB,
+ ['b'] = BS,
+ ['n'] = NL,
+ ['r'] = CAR,
+ ['f'] = FF,
+ };
+ *str_end++ = escapes[(int)*t];
+ break;
+ }
+ default:
+ abort();
}
} else {
*str_end++ = *t;
@@ -490,8 +484,7 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len,
PUT_FST_IN_PAIR(fst_in_pair, str_end);
#undef PUT_FST_IN_PAIR
*str_end = NUL;
- typval_T obj = decode_string(
- str, (size_t)(str_end - str), hasnul ? kTrue : kFalse, false, true);
+ typval_T obj = decode_string(str, (size_t)(str_end - str), hasnul ? kTrue : kFalse, false, true);
if (obj.v_type == VAR_UNKNOWN) {
goto parse_json_string_fail;
}
@@ -528,11 +521,9 @@ parse_json_string_ret:
///
/// @return OK in case of success, FAIL in case of error.
static inline int parse_json_number(const char *const buf, const size_t buf_len,
- const char **const pp,
- ValuesStack *const stack,
+ const char **const pp, ValuesStack *const stack,
ContainerStack *const container_stack,
- bool *const next_map_special,
- bool *const didcomma,
+ bool *const next_map_special, bool *const didcomma,
bool *const didcolon)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE
{
@@ -597,25 +588,25 @@ parse_json_number_check:
.v_type = VAR_NUMBER,
.v_lock = VAR_UNLOCKED,
};
- const size_t exp_num_len = (size_t) (p - s);
+ const size_t exp_num_len = (size_t)(p - s);
if (fracs || exps) {
// Convert floating-point number
const size_t num_len = string2float(s, &tv.vval.v_float);
if (exp_num_len != num_len) {
emsgf(_("E685: internal error: while converting number \"%.*s\" "
"to float string2float consumed %zu bytes in place of %zu"),
- (int) exp_num_len, s, num_len, exp_num_len);
+ (int)exp_num_len, s, num_len, exp_num_len);
}
tv.v_type = VAR_FLOAT;
} else {
// Convert integer
varnumber_T nr;
int num_len;
- vim_str2nr((char_u *) s, NULL, &num_len, 0, &nr, NULL, (int) (p - s));
- if ((int) exp_num_len != num_len) {
+ vim_str2nr((char_u *)s, NULL, &num_len, 0, &nr, NULL, (int)(p - s), true);
+ if ((int)exp_num_len != num_len) {
emsgf(_("E685: internal error: while converting number \"%.*s\" "
"to integer vim_str2nr consumed %i bytes in place of %zu"),
- (int) exp_num_len, s, num_len, exp_num_len);
+ (int)exp_num_len, s, num_len, exp_num_len);
}
tv.vval.v_number = nr;
}
@@ -656,8 +647,7 @@ parse_json_number_ret:
/// @param[out] rettv Location where to save results.
///
/// @return OK in case of success, FAIL otherwise.
-int json_decode_string(const char *const buf, const size_t buf_len,
- typval_T *const rettv)
+int json_decode_string(const char *const buf, const size_t buf_len, typval_T *const rettv)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
const char *p = buf;
@@ -680,219 +670,212 @@ int json_decode_string(const char *const buf, const size_t buf_len,
json_decode_string_cycle_start:
assert(*p == '{' || next_map_special == false);
switch (*p) {
- case '}':
- case ']': {
- if (kv_size(container_stack) == 0) {
- emsgf(_("E474: No container to close: %.*s"), LENP(p, e));
- goto json_decode_string_fail;
- }
- ContainerStackItem last_container = kv_last(container_stack);
- if (*p == '}' && last_container.container.v_type != VAR_DICT) {
- emsgf(_("E474: Closing list with curly bracket: %.*s"), LENP(p, e));
- goto json_decode_string_fail;
- } else if (*p == ']' && last_container.container.v_type != VAR_LIST) {
- emsgf(_("E474: Closing dictionary with square bracket: %.*s"),
- LENP(p, e));
- goto json_decode_string_fail;
- } else if (didcomma) {
- emsgf(_("E474: Trailing comma: %.*s"), LENP(p, e));
- goto json_decode_string_fail;
- } else if (didcolon) {
- emsgf(_("E474: Expected value after colon: %.*s"), LENP(p, e));
- goto json_decode_string_fail;
- } else if (last_container.stack_index != kv_size(stack) - 1) {
- assert(last_container.stack_index < kv_size(stack) - 1);
- emsgf(_("E474: Expected value: %.*s"), LENP(p, e));
- goto json_decode_string_fail;
- }
- if (kv_size(stack) == 1) {
- p++;
- (void) kv_pop(container_stack);
- goto json_decode_string_after_cycle;
- } else {
- if (json_decoder_pop(kv_pop(stack), &stack, &container_stack, &p,
- &next_map_special, &didcomma, &didcolon)
- == FAIL) {
- goto json_decode_string_fail;
- }
- assert(!next_map_special);
- break;
- }
+ case '}':
+ case ']': {
+ if (kv_size(container_stack) == 0) {
+ emsgf(_("E474: No container to close: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
}
- case ',': {
- if (kv_size(container_stack) == 0) {
- emsgf(_("E474: Comma not inside container: %.*s"), LENP(p, e));
+ ContainerStackItem last_container = kv_last(container_stack);
+ if (*p == '}' && last_container.container.v_type != VAR_DICT) {
+ emsgf(_("E474: Closing list with curly bracket: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ } else if (*p == ']' && last_container.container.v_type != VAR_LIST) {
+ emsgf(_("E474: Closing dictionary with square bracket: %.*s"),
+ LENP(p, e));
+ goto json_decode_string_fail;
+ } else if (didcomma) {
+ emsgf(_("E474: Trailing comma: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ } else if (didcolon) {
+ emsgf(_("E474: Expected value after colon: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ } else if (last_container.stack_index != kv_size(stack) - 1) {
+ assert(last_container.stack_index < kv_size(stack) - 1);
+ emsgf(_("E474: Expected value: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ }
+ if (kv_size(stack) == 1) {
+ p++;
+ (void)kv_pop(container_stack);
+ goto json_decode_string_after_cycle;
+ } else {
+ if (json_decoder_pop(kv_pop(stack), &stack, &container_stack, &p,
+ &next_map_special, &didcomma, &didcolon)
+ == FAIL) {
goto json_decode_string_fail;
}
- ContainerStackItem last_container = kv_last(container_stack);
- if (didcomma) {
- emsgf(_("E474: Duplicate comma: %.*s"), LENP(p, e));
- goto json_decode_string_fail;
- } else if (didcolon) {
- emsgf(_("E474: Comma after colon: %.*s"), LENP(p, e));
- goto json_decode_string_fail;
- } else if (last_container.container.v_type == VAR_DICT
- && last_container.stack_index != kv_size(stack) - 1) {
- emsgf(_("E474: Using comma in place of colon: %.*s"), LENP(p, e));
- goto json_decode_string_fail;
- } else if (last_container.special_val == NULL
+ assert(!next_map_special);
+ break;
+ }
+ }
+ case ',': {
+ if (kv_size(container_stack) == 0) {
+ emsgf(_("E474: Comma not inside container: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ }
+ ContainerStackItem last_container = kv_last(container_stack);
+ if (didcomma) {
+ emsgf(_("E474: Duplicate comma: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ } else if (didcolon) {
+ emsgf(_("E474: Comma after colon: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ } else if (last_container.container.v_type == VAR_DICT
+ && last_container.stack_index != kv_size(stack) - 1) {
+ emsgf(_("E474: Using comma in place of colon: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ } else if (last_container.special_val == NULL
? (last_container.container.v_type == VAR_DICT
? (DICT_LEN(last_container.container.vval.v_dict) == 0)
: (tv_list_len(last_container.container.vval.v_list)
== 0))
- : (tv_list_len(last_container.special_val) == 0)) {
- emsgf(_("E474: Leading comma: %.*s"), LENP(p, e));
- goto json_decode_string_fail;
- }
- didcomma = true;
- continue;
+ : (tv_list_len(last_container.special_val) == 0)) {
+ emsgf(_("E474: Leading comma: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
}
- case ':': {
- if (kv_size(container_stack) == 0) {
- emsgf(_("E474: Colon not inside container: %.*s"), LENP(p, e));
- goto json_decode_string_fail;
- }
- ContainerStackItem last_container = kv_last(container_stack);
- if (last_container.container.v_type != VAR_DICT) {
- emsgf(_("E474: Using colon not in dictionary: %.*s"), LENP(p, e));
- goto json_decode_string_fail;
- } else if (last_container.stack_index != kv_size(stack) - 2) {
- emsgf(_("E474: Unexpected colon: %.*s"), LENP(p, e));
- goto json_decode_string_fail;
- } else if (didcomma) {
- emsgf(_("E474: Colon after comma: %.*s"), LENP(p, e));
- goto json_decode_string_fail;
- } else if (didcolon) {
- emsgf(_("E474: Duplicate colon: %.*s"), LENP(p, e));
- goto json_decode_string_fail;
- }
- didcolon = true;
- continue;
+ didcomma = true;
+ continue;
+ }
+ case ':': {
+ if (kv_size(container_stack) == 0) {
+ emsgf(_("E474: Colon not inside container: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
}
- case ' ':
- case TAB:
- case NL:
- case CAR: {
- continue;
+ ContainerStackItem last_container = kv_last(container_stack);
+ if (last_container.container.v_type != VAR_DICT) {
+ emsgf(_("E474: Using colon not in dictionary: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ } else if (last_container.stack_index != kv_size(stack) - 2) {
+ emsgf(_("E474: Unexpected colon: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ } else if (didcomma) {
+ emsgf(_("E474: Colon after comma: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
+ } else if (didcolon) {
+ emsgf(_("E474: Duplicate colon: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
}
- case 'n': {
- if ((p + 3) >= e || strncmp(p + 1, "ull", 3) != 0) {
- emsgf(_("E474: Expected null: %.*s"), LENP(p, e));
- goto json_decode_string_fail;
- }
- p += 3;
- POP(((typval_T) {
- .v_type = VAR_SPECIAL,
- .v_lock = VAR_UNLOCKED,
- .vval = { .v_special = kSpecialVarNull },
- }), false);
- break;
+ didcolon = true;
+ continue;
+ }
+ case ' ':
+ case TAB:
+ case NL:
+ case CAR:
+ continue;
+ case 'n':
+ if ((p + 3) >= e || strncmp(p + 1, "ull", 3) != 0) {
+ emsgf(_("E474: Expected null: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
}
- case 't': {
- if ((p + 3) >= e || strncmp(p + 1, "rue", 3) != 0) {
- emsgf(_("E474: Expected true: %.*s"), LENP(p, e));
- goto json_decode_string_fail;
- }
- p += 3;
- POP(((typval_T) {
- .v_type = VAR_BOOL,
- .v_lock = VAR_UNLOCKED,
- .vval = { .v_bool = kBoolVarTrue },
- }), false);
- break;
+ p += 3;
+ POP(((typval_T) {
+ .v_type = VAR_SPECIAL,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_special = kSpecialVarNull },
+ }), false);
+ break;
+ case 't':
+ if ((p + 3) >= e || strncmp(p + 1, "rue", 3) != 0) {
+ emsgf(_("E474: Expected true: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
}
- case 'f': {
- if ((p + 4) >= e || strncmp(p + 1, "alse", 4) != 0) {
- emsgf(_("E474: Expected false: %.*s"), LENP(p, e));
- goto json_decode_string_fail;
- }
- p += 4;
- POP(((typval_T) {
- .v_type = VAR_BOOL,
- .v_lock = VAR_UNLOCKED,
- .vval = { .v_bool = kBoolVarFalse },
- }), false);
- break;
+ p += 3;
+ POP(((typval_T) {
+ .v_type = VAR_BOOL,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_bool = kBoolVarTrue },
+ }), false);
+ break;
+ case 'f':
+ if ((p + 4) >= e || strncmp(p + 1, "alse", 4) != 0) {
+ emsgf(_("E474: Expected false: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
}
- case '"': {
- if (parse_json_string(buf, buf_len, &p, &stack, &container_stack,
- &next_map_special, &didcomma, &didcolon)
- == FAIL) {
- // Error message was already given
- goto json_decode_string_fail;
- }
- if (next_map_special) {
- goto json_decode_string_cycle_start;
- }
- break;
+ p += 4;
+ POP(((typval_T) {
+ .v_type = VAR_BOOL,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_bool = kBoolVarFalse },
+ }), false);
+ break;
+ case '"':
+ if (parse_json_string(buf, buf_len, &p, &stack, &container_stack,
+ &next_map_special, &didcomma, &didcolon)
+ == FAIL) {
+ // Error message was already given
+ goto json_decode_string_fail;
}
- case '-':
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9': {
- if (parse_json_number(buf, buf_len, &p, &stack, &container_stack,
- &next_map_special, &didcomma, &didcolon)
- == FAIL) {
- // Error message was already given
- goto json_decode_string_fail;
- }
- if (next_map_special) {
- goto json_decode_string_cycle_start;
- }
- break;
+ if (next_map_special) {
+ goto json_decode_string_cycle_start;
}
- case '[': {
- list_T *list = tv_list_alloc(kListLenMayKnow);
- tv_list_ref(list);
- typval_T tv = {
- .v_type = VAR_LIST,
- .v_lock = VAR_UNLOCKED,
- .vval = { .v_list = list },
- };
- kv_push(container_stack, ((ContainerStackItem) {
+ break;
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (parse_json_number(buf, buf_len, &p, &stack, &container_stack,
+ &next_map_special, &didcomma, &didcolon)
+ == FAIL) {
+ // Error message was already given
+ goto json_decode_string_fail;
+ }
+ if (next_map_special) {
+ goto json_decode_string_cycle_start;
+ }
+ break;
+ case '[': {
+ list_T *list = tv_list_alloc(kListLenMayKnow);
+ tv_list_ref(list);
+ typval_T tv = {
+ .v_type = VAR_LIST,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_list = list },
+ };
+ kv_push(container_stack, ((ContainerStackItem) {
.stack_index = kv_size(stack),
.s = p,
.container = tv,
.special_val = NULL,
}));
- kv_push(stack, OBJ(tv, false, didcomma, didcolon));
- break;
+ kv_push(stack, OBJ(tv, false, didcomma, didcolon));
+ break;
+ }
+ case '{': {
+ typval_T tv;
+ list_T *val_list = NULL;
+ if (next_map_special) {
+ next_map_special = false;
+ val_list = decode_create_map_special_dict(&tv, kListLenMayKnow);
+ } else {
+ dict_T *dict = tv_dict_alloc();
+ dict->dv_refcount++;
+ tv = (typval_T) {
+ .v_type = VAR_DICT,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_dict = dict },
+ };
}
- case '{': {
- typval_T tv;
- list_T *val_list = NULL;
- if (next_map_special) {
- next_map_special = false;
- val_list = decode_create_map_special_dict(&tv, kListLenMayKnow);
- } else {
- dict_T *dict = tv_dict_alloc();
- dict->dv_refcount++;
- tv = (typval_T) {
- .v_type = VAR_DICT,
- .v_lock = VAR_UNLOCKED,
- .vval = { .v_dict = dict },
- };
- }
- kv_push(container_stack, ((ContainerStackItem) {
+ kv_push(container_stack, ((ContainerStackItem) {
.stack_index = kv_size(stack),
.s = p,
.container = tv,
.special_val = val_list,
}));
- kv_push(stack, OBJ(tv, false, didcomma, didcolon));
- break;
- }
- default: {
- emsgf(_("E474: Unidentified byte: %.*s"), LENP(p, e));
- goto json_decode_string_fail;
- }
+ kv_push(stack, OBJ(tv, false, didcomma, didcolon));
+ break;
+ }
+ default:
+ emsgf(_("E474: Unidentified byte: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
}
didcomma = false;
didcolon = false;
@@ -904,23 +887,21 @@ json_decode_string_cycle_start:
json_decode_string_after_cycle:
for (; p < e; p++) {
switch (*p) {
- case NL:
- case ' ':
- case TAB:
- case CAR: {
- break;
- }
- default: {
- emsgf(_("E474: Trailing characters: %.*s"), LENP(p, e));
- goto json_decode_string_fail;
- }
+ case NL:
+ case ' ':
+ case TAB:
+ case CAR:
+ break;
+ default:
+ emsgf(_("E474: Trailing characters: %.*s"), LENP(p, e));
+ goto json_decode_string_fail;
}
}
if (kv_size(stack) == 1 && kv_size(container_stack) == 0) {
*rettv = kv_pop(stack).val;
goto json_decode_string_ret;
}
- emsgf(_("E474: Unexpected end of input: %.*s"), (int) buf_len, buf);
+ emsgf(_("E474: Unexpected end of input: %.*s"), (int)buf_len, buf);
json_decode_string_fail:
ret = FAIL;
while (kv_size(stack)) {
@@ -944,192 +925,183 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
switch (mobj.type) {
- case MSGPACK_OBJECT_NIL: {
+ case MSGPACK_OBJECT_NIL:
+ *rettv = (typval_T) {
+ .v_type = VAR_SPECIAL,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_special = kSpecialVarNull },
+ };
+ break;
+ case MSGPACK_OBJECT_BOOLEAN:
+ *rettv = (typval_T) {
+ .v_type = VAR_BOOL,
+ .v_lock = VAR_UNLOCKED,
+ .vval = {
+ .v_bool = mobj.via.boolean ? kBoolVarTrue : kBoolVarFalse
+ },
+ };
+ break;
+ case MSGPACK_OBJECT_POSITIVE_INTEGER:
+ if (mobj.via.u64 <= VARNUMBER_MAX) {
*rettv = (typval_T) {
- .v_type = VAR_SPECIAL,
+ .v_type = VAR_NUMBER,
.v_lock = VAR_UNLOCKED,
- .vval = { .v_special = kSpecialVarNull },
+ .vval = { .v_number = (varnumber_T)mobj.via.u64 },
};
- break;
+ } else {
+ list_T *const list = tv_list_alloc(4);
+ tv_list_ref(list);
+ create_special_dict(rettv, kMPInteger, ((typval_T) {
+ .v_type = VAR_LIST,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_list = list },
+ }));
+ uint64_t n = mobj.via.u64;
+ tv_list_append_number(list, 1);
+ tv_list_append_number(list, (varnumber_T)((n >> 62) & 0x3));
+ tv_list_append_number(list, (varnumber_T)((n >> 31) & 0x7FFFFFFF));
+ tv_list_append_number(list, (varnumber_T)(n & 0x7FFFFFFF));
}
- case MSGPACK_OBJECT_BOOLEAN: {
+ break;
+ case MSGPACK_OBJECT_NEGATIVE_INTEGER:
+ if (mobj.via.i64 >= VARNUMBER_MIN) { // -V547
*rettv = (typval_T) {
- .v_type = VAR_BOOL,
+ .v_type = VAR_NUMBER,
.v_lock = VAR_UNLOCKED,
- .vval = {
- .v_bool = mobj.via.boolean ? kBoolVarTrue : kBoolVarFalse
- },
+ .vval = { .v_number = (varnumber_T)mobj.via.i64 },
};
- break;
- }
- case MSGPACK_OBJECT_POSITIVE_INTEGER: {
- if (mobj.via.u64 <= VARNUMBER_MAX) {
- *rettv = (typval_T) {
- .v_type = VAR_NUMBER,
- .v_lock = VAR_UNLOCKED,
- .vval = { .v_number = (varnumber_T) mobj.via.u64 },
- };
- } else {
- list_T *const list = tv_list_alloc(4);
- tv_list_ref(list);
- create_special_dict(rettv, kMPInteger, ((typval_T) {
- .v_type = VAR_LIST,
- .v_lock = VAR_UNLOCKED,
- .vval = { .v_list = list },
- }));
- uint64_t n = mobj.via.u64;
- tv_list_append_number(list, 1);
- tv_list_append_number(list, (varnumber_T)((n >> 62) & 0x3));
- tv_list_append_number(list, (varnumber_T)((n >> 31) & 0x7FFFFFFF));
- tv_list_append_number(list, (varnumber_T)(n & 0x7FFFFFFF));
- }
- break;
- }
- case MSGPACK_OBJECT_NEGATIVE_INTEGER: {
- if (mobj.via.i64 >= VARNUMBER_MIN) { // -V547
- *rettv = (typval_T) {
- .v_type = VAR_NUMBER,
- .v_lock = VAR_UNLOCKED,
- .vval = { .v_number = (varnumber_T) mobj.via.i64 },
- };
- } else {
- list_T *const list = tv_list_alloc(4);
- tv_list_ref(list);
- create_special_dict(rettv, kMPInteger, ((typval_T) {
- .v_type = VAR_LIST,
- .v_lock = VAR_UNLOCKED,
- .vval = { .v_list = list },
- }));
- uint64_t n = -((uint64_t)mobj.via.i64);
- tv_list_append_number(list, -1);
- tv_list_append_number(list, (varnumber_T)((n >> 62) & 0x3));
- tv_list_append_number(list, (varnumber_T)((n >> 31) & 0x7FFFFFFF));
- tv_list_append_number(list, (varnumber_T)(n & 0x7FFFFFFF));
- }
- break;
+ } else {
+ list_T *const list = tv_list_alloc(4);
+ tv_list_ref(list);
+ create_special_dict(rettv, kMPInteger, ((typval_T) {
+ .v_type = VAR_LIST,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_list = list },
+ }));
+ uint64_t n = -((uint64_t)mobj.via.i64);
+ tv_list_append_number(list, -1);
+ tv_list_append_number(list, (varnumber_T)((n >> 62) & 0x3));
+ tv_list_append_number(list, (varnumber_T)((n >> 31) & 0x7FFFFFFF));
+ tv_list_append_number(list, (varnumber_T)(n & 0x7FFFFFFF));
}
+ break;
#ifdef NVIM_MSGPACK_HAS_FLOAT32
- case MSGPACK_OBJECT_FLOAT32:
- case MSGPACK_OBJECT_FLOAT64:
+ case MSGPACK_OBJECT_FLOAT32:
+ case MSGPACK_OBJECT_FLOAT64:
#else
- case MSGPACK_OBJECT_FLOAT:
+ case MSGPACK_OBJECT_FLOAT:
#endif
- {
- *rettv = (typval_T) {
- .v_type = VAR_FLOAT,
- .v_lock = VAR_UNLOCKED,
- .vval = { .v_float = mobj.via.f64 },
- };
- break;
+ *rettv = (typval_T) {
+ .v_type = VAR_FLOAT,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_float = mobj.via.f64 },
+ };
+ break;
+ case MSGPACK_OBJECT_STR:
+ *rettv = decode_string(mobj.via.bin.ptr, mobj.via.bin.size, kTrue, false,
+ false);
+ if (rettv->v_type == VAR_UNKNOWN) {
+ return FAIL;
}
- case MSGPACK_OBJECT_STR: {
- *rettv = decode_string(mobj.via.bin.ptr, mobj.via.bin.size, kTrue, false,
- false);
- if (rettv->v_type == VAR_UNKNOWN) {
- return FAIL;
- }
- break;
+ break;
+ case MSGPACK_OBJECT_BIN:
+ *rettv = decode_string(mobj.via.bin.ptr, mobj.via.bin.size, kNone, true,
+ false);
+ if (rettv->v_type == VAR_UNKNOWN) {
+ return FAIL;
}
- case MSGPACK_OBJECT_BIN: {
- *rettv = decode_string(mobj.via.bin.ptr, mobj.via.bin.size, kNone, true,
- false);
- if (rettv->v_type == VAR_UNKNOWN) {
+ break;
+ case MSGPACK_OBJECT_ARRAY: {
+ list_T *const list = tv_list_alloc((ptrdiff_t)mobj.via.array.size);
+ tv_list_ref(list);
+ *rettv = (typval_T) {
+ .v_type = VAR_LIST,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_list = list },
+ };
+ for (size_t i = 0; i < mobj.via.array.size; i++) {
+ // Not populated yet, need to create list item to push.
+ tv_list_append_owned_tv(list, (typval_T) { .v_type = VAR_UNKNOWN });
+ if (msgpack_to_vim(mobj.via.array.ptr[i],
+ TV_LIST_ITEM_TV(tv_list_last(list)))
+ == FAIL) {
return FAIL;
}
- break;
}
- case MSGPACK_OBJECT_ARRAY: {
- list_T *const list = tv_list_alloc((ptrdiff_t)mobj.via.array.size);
- tv_list_ref(list);
- *rettv = (typval_T) {
- .v_type = VAR_LIST,
- .v_lock = VAR_UNLOCKED,
- .vval = { .v_list = list },
- };
- for (size_t i = 0; i < mobj.via.array.size; i++) {
- // Not populated yet, need to create list item to push.
- tv_list_append_owned_tv(list, (typval_T) { .v_type = VAR_UNKNOWN });
- if (msgpack_to_vim(mobj.via.array.ptr[i],
- TV_LIST_ITEM_TV(tv_list_last(list)))
- == FAIL) {
- return FAIL;
- }
+ break;
+ }
+ case MSGPACK_OBJECT_MAP: {
+ for (size_t i = 0; i < mobj.via.map.size; i++) {
+ if (mobj.via.map.ptr[i].key.type != MSGPACK_OBJECT_STR
+ || mobj.via.map.ptr[i].key.via.str.size == 0
+ || memchr(mobj.via.map.ptr[i].key.via.str.ptr, NUL,
+ mobj.via.map.ptr[i].key.via.str.size) != NULL) {
+ goto msgpack_to_vim_generic_map;
}
- break;
}
- case MSGPACK_OBJECT_MAP: {
- for (size_t i = 0; i < mobj.via.map.size; i++) {
- if (mobj.via.map.ptr[i].key.type != MSGPACK_OBJECT_STR
- || mobj.via.map.ptr[i].key.via.str.size == 0
- || memchr(mobj.via.map.ptr[i].key.via.str.ptr, NUL,
- mobj.via.map.ptr[i].key.via.str.size) != NULL) {
- goto msgpack_to_vim_generic_map;
- }
+ dict_T *const dict = tv_dict_alloc();
+ dict->dv_refcount++;
+ *rettv = (typval_T) {
+ .v_type = VAR_DICT,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_dict = dict },
+ };
+ for (size_t i = 0; i < mobj.via.map.size; i++) {
+ dictitem_T *const di = xmallocz(offsetof(dictitem_T, di_key)
+ + mobj.via.map.ptr[i].key.via.str.size);
+ memcpy(&di->di_key[0], mobj.via.map.ptr[i].key.via.str.ptr,
+ mobj.via.map.ptr[i].key.via.str.size);
+ di->di_tv.v_type = VAR_UNKNOWN;
+ if (tv_dict_add(dict, di) == FAIL) {
+ // Duplicate key: fallback to generic map
+ tv_clear(rettv);
+ xfree(di);
+ goto msgpack_to_vim_generic_map;
}
- dict_T *const dict = tv_dict_alloc();
- dict->dv_refcount++;
- *rettv = (typval_T) {
- .v_type = VAR_DICT,
- .v_lock = VAR_UNLOCKED,
- .vval = { .v_dict = dict },
- };
- for (size_t i = 0; i < mobj.via.map.size; i++) {
- dictitem_T *const di = xmallocz(offsetof(dictitem_T, di_key)
- + mobj.via.map.ptr[i].key.via.str.size);
- memcpy(&di->di_key[0], mobj.via.map.ptr[i].key.via.str.ptr,
- mobj.via.map.ptr[i].key.via.str.size);
- di->di_tv.v_type = VAR_UNKNOWN;
- if (tv_dict_add(dict, di) == FAIL) {
- // Duplicate key: fallback to generic map
- tv_clear(rettv);
- xfree(di);
- goto msgpack_to_vim_generic_map;
- }
- if (msgpack_to_vim(mobj.via.map.ptr[i].val, &di->di_tv) == FAIL) {
- return FAIL;
- }
+ if (msgpack_to_vim(mobj.via.map.ptr[i].val, &di->di_tv) == FAIL) {
+ return FAIL;
}
- break;
+ }
+ break;
msgpack_to_vim_generic_map: {}
- list_T *const list = decode_create_map_special_dict(
- rettv, (ptrdiff_t)mobj.via.map.size);
- for (size_t i = 0; i < mobj.via.map.size; i++) {
- list_T *const kv_pair = tv_list_alloc(2);
- tv_list_append_list(list, kv_pair);
+ list_T *const list = decode_create_map_special_dict(rettv, (ptrdiff_t)mobj.via.map.size);
+ for (size_t i = 0; i < mobj.via.map.size; i++) {
+ list_T *const kv_pair = tv_list_alloc(2);
+ tv_list_append_list(list, kv_pair);
- typval_T key_tv = { .v_type = VAR_UNKNOWN };
- if (msgpack_to_vim(mobj.via.map.ptr[i].key, &key_tv) == FAIL) {
- tv_clear(&key_tv);
- return FAIL;
- }
- tv_list_append_owned_tv(kv_pair, key_tv);
+ typval_T key_tv = { .v_type = VAR_UNKNOWN };
+ if (msgpack_to_vim(mobj.via.map.ptr[i].key, &key_tv) == FAIL) {
+ tv_clear(&key_tv);
+ return FAIL;
+ }
+ tv_list_append_owned_tv(kv_pair, key_tv);
- typval_T val_tv = { .v_type = VAR_UNKNOWN };
- if (msgpack_to_vim(mobj.via.map.ptr[i].val, &val_tv) == FAIL) {
- tv_clear(&val_tv);
- return FAIL;
- }
- tv_list_append_owned_tv(kv_pair, val_tv);
+ typval_T val_tv = { .v_type = VAR_UNKNOWN };
+ if (msgpack_to_vim(mobj.via.map.ptr[i].val, &val_tv) == FAIL) {
+ tv_clear(&val_tv);
+ return FAIL;
}
- break;
+ tv_list_append_owned_tv(kv_pair, val_tv);
}
- case MSGPACK_OBJECT_EXT: {
- list_T *const list = tv_list_alloc(2);
- tv_list_ref(list);
- tv_list_append_number(list, mobj.via.ext.type);
- list_T *const ext_val_list = tv_list_alloc(kListLenMayKnow);
- tv_list_append_list(list, ext_val_list);
- create_special_dict(rettv, kMPExt, ((typval_T) {
+ break;
+ }
+ case MSGPACK_OBJECT_EXT: {
+ list_T *const list = tv_list_alloc(2);
+ tv_list_ref(list);
+ tv_list_append_number(list, mobj.via.ext.type);
+ list_T *const ext_val_list = tv_list_alloc(kListLenMayKnow);
+ tv_list_append_list(list, ext_val_list);
+ create_special_dict(rettv, kMPExt, ((typval_T) {
.v_type = VAR_LIST,
.v_lock = VAR_UNLOCKED,
.vval = { .v_list = list },
}));
- if (encode_list_write((void *) ext_val_list, mobj.via.ext.ptr,
- mobj.via.ext.size) == -1) {
- return FAIL;
- }
- break;
+ if (encode_list_write((void *)ext_val_list, mobj.via.ext.ptr,
+ mobj.via.ext.size) == -1) {
+ return FAIL;
}
+ break;
+ }
}
return OK;
}
diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c
index a4d7af7971..1c0afc89f5 100644
--- a/src/nvim/eval/encode.c
+++ b/src/nvim/eval/encode.c
@@ -7,27 +7,27 @@
///
/// Split out from eval.c.
-#include <msgpack.h>
-#include <inttypes.h>
-#include <stddef.h>
#include <assert.h>
+#include <inttypes.h>
#include <math.h>
+#include <msgpack.h>
+#include <stddef.h>
-#include "nvim/eval/encode.h"
+#include "nvim/ascii.h"
#include "nvim/buffer_defs.h"
+#include "nvim/charset.h" // vim_isprintc()
#include "nvim/eval.h"
+#include "nvim/eval/encode.h"
#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_encode.h"
#include "nvim/garray.h"
-#include "nvim/mbyte.h"
+#include "nvim/lib/kvec.h"
+#include "nvim/macros.h"
#include "nvim/math.h"
-#include "nvim/message.h"
+#include "nvim/mbyte.h"
#include "nvim/memory.h"
-#include "nvim/charset.h" // vim_isprintc()
-#include "nvim/macros.h"
-#include "nvim/ascii.h"
+#include "nvim/message.h"
#include "nvim/vim.h" // For _()
-#include "nvim/lib/kvec.h"
-#include "nvim/eval/typval_encode.h"
#define ga_concat(a, b) ga_concat(a, (char_u *)b)
#define utf_ptr2char(b) utf_ptr2char((char_u *)b)
@@ -47,6 +47,14 @@ const char *const encode_special_var_names[] = {
# include "eval/encode.c.generated.h"
#endif
+/// Msgpack callback for writing to a Blob
+int encode_blob_write(void *const data, const char *const buf, const size_t len)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ ga_concat_len(&((blob_T *)data)->bv_ga, buf, len);
+ return (int)len;
+}
+
/// Msgpack callback for writing to readfile()-style list
int encode_list_write(void *const data, const char *const buf, const size_t len)
FUNC_ATTR_NONNULL_ARG(1)
@@ -54,7 +62,7 @@ int encode_list_write(void *const data, const char *const buf, const size_t len)
if (len == 0) {
return 0;
}
- list_T *const list = (list_T *) data;
+ list_T *const list = (list_T *)data;
const char *const end = buf + len;
const char *line_end = buf;
listitem_T *li = tv_list_last(list);
@@ -66,8 +74,7 @@ int encode_list_write(void *const data, const char *const buf, const size_t len)
const size_t line_length = (size_t)(line_end - buf);
char *str = (char *)TV_LIST_ITEM_TV(li)->vval.v_string;
const size_t li_len = (str == NULL ? 0 : strlen(str));
- TV_LIST_ITEM_TV(li)->vval.v_string = xrealloc(
- str, li_len + line_length + 1);
+ TV_LIST_ITEM_TV(li)->vval.v_string = xrealloc(str, li_len + line_length + 1);
str = (char *)TV_LIST_ITEM_TV(li)->vval.v_string + li_len;
memcpy(str, buf, line_length);
str[line_length] = 0;
@@ -78,7 +85,7 @@ int encode_list_write(void *const data, const char *const buf, const size_t len)
while (line_end < end) {
const char *line_start = line_end;
- line_end = xmemscan(line_start, NL, (size_t) (end - line_start));
+ line_end = xmemscan(line_start, NL, (size_t)(end - line_start));
char *str = NULL;
if (line_end != line_start) {
const size_t line_length = (size_t)(line_end - line_start);
@@ -125,75 +132,70 @@ static int conv_error(const char *const msg, const MPConvStack *const mpstack,
}
MPConvStackVal v = kv_A(*mpstack, i);
switch (v.type) {
- case kMPConvDict: {
- typval_T key_tv = {
- .v_type = VAR_STRING,
- .vval = { .v_string = (v.data.d.hi == NULL
+ case kMPConvDict: {
+ typval_T key_tv = {
+ .v_type = VAR_STRING,
+ .vval = { .v_string = (v.data.d.hi == NULL
? v.data.d.dict->dv_hashtab.ht_array
: (v.data.d.hi - 1))->hi_key },
- };
- char *const key = encode_tv2string(&key_tv, NULL);
- vim_snprintf((char *) IObuff, IOSIZE, key_msg, key);
- xfree(key);
- ga_concat(&msg_ga, IObuff);
- break;
- }
- case kMPConvPairs:
- case kMPConvList: {
- const int idx = (v.data.l.li == tv_list_first(v.data.l.list)
+ };
+ char *const key = encode_tv2string(&key_tv, NULL);
+ vim_snprintf((char *)IObuff, IOSIZE, key_msg, key);
+ xfree(key);
+ ga_concat(&msg_ga, IObuff);
+ break;
+ }
+ case kMPConvPairs:
+ case kMPConvList: {
+ const int idx = (v.data.l.li == tv_list_first(v.data.l.list)
? 0
: (v.data.l.li == NULL
? tv_list_len(v.data.l.list) - 1
- : (int)tv_list_idx_of_item(
- v.data.l.list,
- TV_LIST_ITEM_PREV(v.data.l.list,
- v.data.l.li))));
- const listitem_T *const li = (v.data.l.li == NULL
+ : (int)tv_list_idx_of_item(v.data.l.list,
+ TV_LIST_ITEM_PREV(v.data.l.list,
+ v.data.l.li))));
+ const listitem_T *const li = (v.data.l.li == NULL
? tv_list_last(v.data.l.list)
: TV_LIST_ITEM_PREV(v.data.l.list,
v.data.l.li));
- if (v.type == kMPConvList
- || li == NULL
- || (TV_LIST_ITEM_TV(li)->v_type != VAR_LIST
- && tv_list_len(TV_LIST_ITEM_TV(li)->vval.v_list) <= 0)) {
- vim_snprintf((char *)IObuff, IOSIZE, idx_msg, idx);
- ga_concat(&msg_ga, IObuff);
- } else {
- assert(li != NULL);
- listitem_T *const first_item =
- tv_list_first(TV_LIST_ITEM_TV(li)->vval.v_list);
- assert(first_item != NULL);
- typval_T key_tv = *TV_LIST_ITEM_TV(first_item);
- char *const key = encode_tv2echo(&key_tv, NULL);
- vim_snprintf((char *) IObuff, IOSIZE, key_pair_msg, key, idx);
- xfree(key);
- ga_concat(&msg_ga, IObuff);
- }
- break;
+ if (v.type == kMPConvList
+ || li == NULL
+ || (TV_LIST_ITEM_TV(li)->v_type != VAR_LIST
+ && tv_list_len(TV_LIST_ITEM_TV(li)->vval.v_list) <= 0)) {
+ vim_snprintf((char *)IObuff, IOSIZE, idx_msg, idx);
+ ga_concat(&msg_ga, IObuff);
+ } else {
+ assert(li != NULL);
+ listitem_T *const first_item =
+ tv_list_first(TV_LIST_ITEM_TV(li)->vval.v_list);
+ assert(first_item != NULL);
+ typval_T key_tv = *TV_LIST_ITEM_TV(first_item);
+ char *const key = encode_tv2echo(&key_tv, NULL);
+ vim_snprintf((char *)IObuff, IOSIZE, key_pair_msg, key, idx);
+ xfree(key);
+ ga_concat(&msg_ga, IObuff);
}
- case kMPConvPartial: {
- switch (v.data.p.stage) {
- case kMPConvPartialArgs: {
- abort();
- break;
- }
- case kMPConvPartialSelf: {
- ga_concat(&msg_ga, partial_arg_msg);
- break;
- }
- case kMPConvPartialEnd: {
- ga_concat(&msg_ga, partial_self_msg);
- break;
- }
- }
+ break;
+ }
+ case kMPConvPartial:
+ switch (v.data.p.stage) {
+ case kMPConvPartialArgs:
+ abort();
break;
- }
- case kMPConvPartialList: {
- const int idx = (int)(v.data.a.arg - v.data.a.argv) - 1;
- vim_snprintf((char *)IObuff, IOSIZE, partial_arg_i_msg, idx);
- ga_concat(&msg_ga, IObuff);
+ case kMPConvPartialSelf:
+ ga_concat(&msg_ga, partial_arg_msg);
+ break;
+ case kMPConvPartialEnd:
+ ga_concat(&msg_ga, partial_self_msg);
break;
}
+ break;
+ case kMPConvPartialList: {
+ const int idx = (int)(v.data.a.arg - v.data.a.argv) - 1;
+ vim_snprintf((char *)IObuff, IOSIZE, partial_arg_i_msg, idx);
+ ga_concat(&msg_ga, IObuff);
+ break;
+ }
}
}
emsgf(msg, _(objname), (kv_size(*mpstack) == 0
@@ -211,8 +213,7 @@ static int conv_error(const char *const msg, const MPConvStack *const mpstack,
/// zero.
///
/// @return true in case of success, false in case of failure.
-bool encode_vim_list_to_buf(const list_T *const list, size_t *const ret_len,
- char **const ret_buf)
+bool encode_vim_list_to_buf(const list_T *const list, size_t *const ret_len, char **const ret_buf)
FUNC_ATTR_NONNULL_ARG(2, 3) FUNC_ATTR_WARN_UNUSED_RESULT
{
size_t len = 0;
@@ -256,8 +257,8 @@ bool encode_vim_list_to_buf(const list_T *const list, size_t *const ret_len,
/// @return OK when reading was finished, FAIL in case of error (i.e. list item
/// was not a string), NOTDONE if reading was successful, but there are
/// more bytes to read.
-int encode_read_from_list(ListReaderState *const state, char *const buf,
- const size_t nbuf, size_t *const read_bytes)
+int encode_read_from_list(ListReaderState *const state, char *const buf, const size_t nbuf,
+ size_t *const read_bytes)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
char *const buf_end = buf + nbuf;
@@ -268,13 +269,13 @@ int encode_read_from_list(ListReaderState *const state, char *const buf,
for (size_t i = state->offset; i < state->li_length && p < buf_end; i++) {
assert(TV_LIST_ITEM_TV(state->li)->vval.v_string != NULL);
const char ch = (char)(
- TV_LIST_ITEM_TV(state->li)->vval.v_string[state->offset++]);
+ TV_LIST_ITEM_TV(state->li)->vval.v_string[state->offset++]);
*p++ = (char)((char)ch == (char)NL ? (char)NUL : (char)ch);
}
if (p < buf_end) {
state->li = TV_LIST_ITEM_NEXT(state->list, state->li);
if (state->li == NULL) {
- *read_bytes = (size_t) (p - buf);
+ *read_bytes = (size_t)(p - buf);
return OK;
}
*p++ = NL;
@@ -296,157 +297,181 @@ int encode_read_from_list(ListReaderState *const state, char *const buf,
}
#define TYPVAL_ENCODE_CONV_STRING(tv, buf, len) \
- do { \
- const char *const buf_ = (const char *) buf; \
- if (buf == NULL) { \
- ga_concat(gap, "''"); \
- } else { \
- const size_t len_ = (len); \
- ga_grow(gap, (int) (2 + len_ + memcnt(buf_, '\'', len_))); \
- ga_append(gap, '\''); \
- for (size_t i_ = 0; i_ < len_; i_++) { \
- if (buf_[i_] == '\'') { \
- ga_append(gap, '\''); \
- } \
- ga_append(gap, buf_[i_]); \
+ do { \
+ const char *const buf_ = (const char *)buf; \
+ if (buf == NULL) { \
+ ga_concat(gap, "''"); \
+ } else { \
+ const size_t len_ = (len); \
+ ga_grow(gap, (int)(2 + len_ + memcnt(buf_, '\'', len_))); \
+ ga_append(gap, '\''); \
+ for (size_t i_ = 0; i_ < len_; i_++) { \
+ if (buf_[i_] == '\'') { \
+ ga_append(gap, '\''); \
} \
- ga_append(gap, '\''); \
+ ga_append(gap, buf_[i_]); \
} \
- } while (0)
+ ga_append(gap, '\''); \
+ } \
+ } while (0)
#define TYPVAL_ENCODE_CONV_STR_STRING(tv, buf, len) \
- TYPVAL_ENCODE_CONV_STRING(tv, buf, len)
+ TYPVAL_ENCODE_CONV_STRING(tv, buf, len)
#define TYPVAL_ENCODE_CONV_EXT_STRING(tv, buf, len, type)
-#define TYPVAL_ENCODE_CONV_NUMBER(tv, num) \
- do { \
+#define TYPVAL_ENCODE_CONV_BLOB(tv, blob, len) \
+ do { \
+ const blob_T *const blob_ = (blob); \
+ const int len_ = (len); \
+ if (len_ == 0) { \
+ ga_concat(gap, "0z"); \
+ } else { \
+ /* Allocate space for "0z", the two hex chars per byte, and a */ \
+ /* "." separator after every eight hex chars. */ \
+ /* Example: "0z00112233.44556677.8899" */ \
+ ga_grow(gap, 2 + 2 * len_ + (len_ - 1) / 4); \
+ ga_concat(gap, "0z"); \
char numbuf[NUMBUFLEN]; \
- vim_snprintf(numbuf, ARRAY_SIZE(numbuf), "%" PRId64, (int64_t) (num)); \
- ga_concat(gap, numbuf); \
- } while (0)
+ for (int i_ = 0; i_ < len_; i_++) { \
+ if (i_ > 0 && (i_ & 3) == 0) { \
+ ga_append(gap, '.'); \
+ } \
+ vim_snprintf((char *)numbuf, ARRAY_SIZE(numbuf), "%02X", \
+ (int)tv_blob_get(blob_, i_)); \
+ ga_concat(gap, numbuf); \
+ } \
+ } \
+ } while (0)
+
+#define TYPVAL_ENCODE_CONV_NUMBER(tv, num) \
+ do { \
+ char numbuf[NUMBUFLEN]; \
+ vim_snprintf(numbuf, ARRAY_SIZE(numbuf), "%" PRId64, (int64_t)(num)); \
+ ga_concat(gap, numbuf); \
+ } while (0)
#define TYPVAL_ENCODE_CONV_FLOAT(tv, flt) \
- do { \
- const float_T flt_ = (flt); \
- switch (xfpclassify(flt_)) { \
- case FP_NAN: { \
- ga_concat(gap, (char_u *) "str2float('nan')"); \
- break; \
- } \
- case FP_INFINITE: { \
- if (flt_ < 0) { \
- ga_append(gap, '-'); \
- } \
- ga_concat(gap, (char_u *) "str2float('inf')"); \
- break; \
- } \
- default: { \
- char numbuf[NUMBUFLEN]; \
- vim_snprintf(numbuf, ARRAY_SIZE(numbuf), "%g", flt_); \
- ga_concat(gap, (char_u *) numbuf); \
- } \
+ do { \
+ const float_T flt_ = (flt); \
+ switch (xfpclassify(flt_)) { \
+ case FP_NAN: { \
+ ga_concat(gap, (char_u *)"str2float('nan')"); \
+ break; \
+ } \
+ case FP_INFINITE: { \
+ if (flt_ < 0) { \
+ ga_append(gap, '-'); \
} \
- } while (0)
+ ga_concat(gap, (char_u *)"str2float('inf')"); \
+ break; \
+ } \
+ default: { \
+ char numbuf[NUMBUFLEN]; \
+ vim_snprintf(numbuf, ARRAY_SIZE(numbuf), "%g", flt_); \
+ ga_concat(gap, (char_u *)numbuf); \
+ } \
+ } \
+ } while (0)
#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \
- do { \
- const char *const fun_ = (const char *)(fun); \
- if (fun_ == NULL) { \
- internal_error("string(): NULL function name"); \
- ga_concat(gap, "function(NULL"); \
- } else { \
- ga_concat(gap, "function("); \
- TYPVAL_ENCODE_CONV_STRING(tv, fun_, strlen(fun_)); \
- }\
- } while (0)
+ do { \
+ const char *const fun_ = (const char *)(fun); \
+ if (fun_ == NULL) { \
+ internal_error("string(): NULL function name"); \
+ ga_concat(gap, "function(NULL"); \
+ } else { \
+ ga_concat(gap, "function("); \
+ TYPVAL_ENCODE_CONV_STRING(tv, fun_, strlen(fun_)); \
+ }\
+ } while (0)
#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(tv, len) \
- do { \
- if (len != 0) { \
- ga_concat(gap, ", "); \
- } \
- } while (0)
+ do { \
+ if (len != 0) { \
+ ga_concat(gap, ", "); \
+ } \
+ } while (0)
#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(tv, len) \
- do { \
- if ((ptrdiff_t)len != -1) { \
- ga_concat(gap, ", "); \
- } \
- } while (0)
+ do { \
+ if ((ptrdiff_t)len != -1) { \
+ ga_concat(gap, ", "); \
+ } \
+ } while (0)
#define TYPVAL_ENCODE_CONV_FUNC_END(tv) \
- ga_append(gap, ')')
+ ga_append(gap, ')')
#define TYPVAL_ENCODE_CONV_EMPTY_LIST(tv) \
- ga_concat(gap, "[]")
+ ga_concat(gap, "[]")
#define TYPVAL_ENCODE_CONV_LIST_START(tv, len) \
- ga_append(gap, '[')
+ ga_append(gap, '[')
#define TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START(tv, mpsv)
#define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \
- ga_concat(gap, "{}")
+ ga_concat(gap, "{}")
#define TYPVAL_ENCODE_CONV_NIL(tv) \
- ga_concat(gap, "v:null")
+ ga_concat(gap, "v:null")
#define TYPVAL_ENCODE_CONV_BOOL(tv, num) \
- ga_concat(gap, ((num)? "v:true": "v:false"))
+ ga_concat(gap, ((num)? "v:true": "v:false"))
#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(tv, num)
#define TYPVAL_ENCODE_CONV_DICT_START(tv, dict, len) \
- ga_append(gap, '{')
+ ga_append(gap, '{')
#define TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START(tv, dict, mpsv)
#define TYPVAL_ENCODE_CONV_DICT_END(tv, dict) \
- ga_append(gap, '}')
+ ga_append(gap, '}')
#define TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(tv, dict) \
- ga_concat(gap, ": ")
+ ga_concat(gap, ": ")
#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(tv, dict) \
- ga_concat(gap, ", ")
+ ga_concat(gap, ", ")
#define TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK(label, key)
#define TYPVAL_ENCODE_CONV_LIST_END(tv) \
- ga_append(gap, ']')
+ ga_append(gap, ']')
#define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(tv) \
- TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(tv, NULL)
+ TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(tv, NULL)
#define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) \
- do { \
- if (!did_echo_string_emsg) { \
- /* Only give this message once for a recursive call to avoid */ \
- /* flooding the user with errors. */ \
- did_echo_string_emsg = true; \
- EMSG(_("E724: unable to correctly dump variable " \
- "with self-referencing container")); \
- } \
- char ebuf[NUMBUFLEN + 7]; \
- 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)) { \
- break; \
- } \
- } else if (conv_type == kMPConvList) { \
- if ((void *) mpval.data.l.list == (void *) (val)) { \
- break; \
- } \
+ do { \
+ if (!did_echo_string_emsg) { \
+ /* Only give this message once for a recursive call to avoid */ \
+ /* flooding the user with errors. */ \
+ did_echo_string_emsg = true; \
+ EMSG(_("E724: unable to correctly dump variable " \
+ "with self-referencing container")); \
+ } \
+ char ebuf[NUMBUFLEN + 7]; \
+ 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)) { \
+ break; \
+ } \
+ } else if (conv_type == kMPConvList) { \
+ if ((void *)mpval.data.l.list == (void *)(val)) { \
+ break; \
} \
} \
} \
- vim_snprintf(ebuf, ARRAY_SIZE(ebuf), "{E724@%zu}", backref); \
- ga_concat(gap, &ebuf[0]); \
- } while (0)
+ } \
+ vim_snprintf(ebuf, ARRAY_SIZE(ebuf), "{E724@%zu}", backref); \
+ ga_concat(gap, &ebuf[0]); \
+ } while (0)
#define TYPVAL_ENCODE_ALLOW_SPECIALS false
@@ -462,31 +487,31 @@ int encode_read_from_list(ListReaderState *const state, char *const buf,
#undef TYPVAL_ENCODE_CONV_RECURSE
#define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) \
- do { \
- char ebuf[NUMBUFLEN + 7]; \
- 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) { \
- break; \
- } \
- } else if (conv_type == kMPConvList) { \
- if ((void *) mpval.data.l.list == (void *) val) { \
- break; \
- } \
+ do { \
+ char ebuf[NUMBUFLEN + 7]; \
+ 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) { \
+ break; \
+ } \
+ } else if (conv_type == kMPConvList) { \
+ if ((void *)mpval.data.l.list == (void *)val) { \
+ break; \
} \
} \
} \
- if (conv_type == kMPConvDict) { \
- vim_snprintf(ebuf, ARRAY_SIZE(ebuf), "{...@%zu}", backref); \
- } else { \
- vim_snprintf(ebuf, ARRAY_SIZE(ebuf), "[...@%zu]", backref); \
- } \
- ga_concat(gap, &ebuf[0]); \
- return OK; \
- } while (0)
+ } \
+ if (conv_type == kMPConvDict) { \
+ vim_snprintf(ebuf, ARRAY_SIZE(ebuf), "{...@%zu}", backref); \
+ } else { \
+ vim_snprintf(ebuf, ARRAY_SIZE(ebuf), "[...@%zu]", backref); \
+ } \
+ ga_concat(gap, &ebuf[0]); \
+ return OK; \
+ } while (0)
#define TYPVAL_ENCODE_SCOPE
#define TYPVAL_ENCODE_NAME echo
@@ -500,56 +525,56 @@ int encode_read_from_list(ListReaderState *const state, char *const buf,
#undef TYPVAL_ENCODE_CONV_RECURSE
#define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) \
- do { \
- if (!did_echo_string_emsg) { \
- /* Only give this message once for a recursive call to avoid */ \
- /* flooding the user with errors. */ \
- did_echo_string_emsg = true; \
- EMSG(_("E724: unable to correctly dump variable " \
- "with self-referencing container")); \
- } \
- } while (0)
+ do { \
+ if (!did_echo_string_emsg) { \
+ /* Only give this message once for a recursive call to avoid */ \
+ /* flooding the user with errors. */ \
+ did_echo_string_emsg = true; \
+ EMSG(_("E724: unable to correctly dump variable " \
+ "with self-referencing container")); \
+ } \
+ } while (0)
#undef TYPVAL_ENCODE_ALLOW_SPECIALS
#define TYPVAL_ENCODE_ALLOW_SPECIALS true
#undef TYPVAL_ENCODE_CONV_NIL
#define TYPVAL_ENCODE_CONV_NIL(tv) \
- ga_concat(gap, "null")
+ ga_concat(gap, "null")
#undef TYPVAL_ENCODE_CONV_BOOL
#define TYPVAL_ENCODE_CONV_BOOL(tv, num) \
- ga_concat(gap, ((num)? "true": "false"))
+ ga_concat(gap, ((num)? "true": "false"))
#undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER
#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(tv, num) \
- do { \
- char numbuf[NUMBUFLEN]; \
- vim_snprintf(numbuf, ARRAY_SIZE(numbuf), "%" PRIu64, (num)); \
- ga_concat(gap, numbuf); \
- } while (0)
+ do { \
+ char numbuf[NUMBUFLEN]; \
+ vim_snprintf(numbuf, ARRAY_SIZE(numbuf), "%" PRIu64, (num)); \
+ ga_concat(gap, numbuf); \
+ } while (0)
#undef TYPVAL_ENCODE_CONV_FLOAT
#define TYPVAL_ENCODE_CONV_FLOAT(tv, flt) \
- do { \
- const float_T flt_ = (flt); \
- switch (xfpclassify(flt_)) { \
- case FP_NAN: { \
- EMSG(_("E474: Unable to represent NaN value in JSON")); \
- return FAIL; \
- } \
- case FP_INFINITE: { \
- EMSG(_("E474: Unable to represent infinity in JSON")); \
- return FAIL; \
- } \
- default: { \
- char numbuf[NUMBUFLEN]; \
- vim_snprintf(numbuf, ARRAY_SIZE(numbuf), "%g", flt_); \
- ga_concat(gap, (char_u *) numbuf); \
- break; \
- } \
- } \
- } while (0)
+ do { \
+ const float_T flt_ = (flt); \
+ switch (xfpclassify(flt_)) { \
+ case FP_NAN: { \
+ EMSG(_("E474: Unable to represent NaN value in JSON")); \
+ return FAIL; \
+ } \
+ case FP_INFINITE: { \
+ EMSG(_("E474: Unable to represent infinity in JSON")); \
+ return FAIL; \
+ } \
+ default: { \
+ char numbuf[NUMBUFLEN]; \
+ vim_snprintf(numbuf, ARRAY_SIZE(numbuf), "%g", flt_); \
+ ga_concat(gap, (char_u *)numbuf); \
+ break; \
+ } \
+ } \
+ } while (0)
/// Escape sequences used in JSON
static const char escapes[][3] = {
@@ -571,8 +596,7 @@ static const char xdigits[] = "0123456789ABCDEF";
/// @param[in] len Converted string length.
///
/// @return OK in case of success, FAIL otherwise.
-static inline int convert_to_json_string(garray_T *const gap,
- const char *const buf,
+static inline int convert_to_json_string(garray_T *const gap, const char *const buf,
const size_t len)
FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_ALWAYS_INLINE
{
@@ -590,49 +614,47 @@ static inline int convert_to_json_string(garray_T *const gap,
// 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: utf_ptr2len(utf_buf + i));
assert(shift > 0);
i += shift;
switch (ch) {
- case BS:
- case TAB:
- case NL:
- case FF:
- case CAR:
- case '"':
- case '\\': {
- str_len += 2;
- break;
- }
- default: {
- if (ch > 0x7F && shift == 1) {
- emsgf(_("E474: String \"%.*s\" contains byte that does not start "
- "any UTF-8 character"),
- (int)(utf_len - (i - shift)), utf_buf + i - shift);
- xfree(tofree);
- return FAIL;
- } else if ((SURROGATE_HI_START <= ch && ch <= SURROGATE_HI_END)
- || (SURROGATE_LO_START <= ch && ch <= SURROGATE_LO_END)) {
- emsgf(_("E474: UTF-8 string contains code point which belongs "
- "to a surrogate pair: %.*s"),
- (int)(utf_len - (i - shift)), utf_buf + i - shift);
- xfree(tofree);
- return FAIL;
- } else if (ENCODE_RAW(ch)) {
- str_len += shift;
- } else {
- str_len += ((sizeof("\\u1234") - 1)
- * (size_t) (1 + (ch >= SURROGATE_FIRST_CHAR)));
- }
- break;
+ case BS:
+ case TAB:
+ case NL:
+ case FF:
+ case CAR:
+ case '"':
+ case '\\':
+ str_len += 2;
+ break;
+ default:
+ if (ch > 0x7F && shift == 1) {
+ emsgf(_("E474: String \"%.*s\" contains byte that does not start "
+ "any UTF-8 character"),
+ (int)(utf_len - (i - shift)), utf_buf + i - shift);
+ xfree(tofree);
+ return FAIL;
+ } else if ((SURROGATE_HI_START <= ch && ch <= SURROGATE_HI_END)
+ || (SURROGATE_LO_START <= ch && ch <= SURROGATE_LO_END)) {
+ emsgf(_("E474: UTF-8 string contains code point which belongs "
+ "to a surrogate pair: %.*s"),
+ (int)(utf_len - (i - shift)), utf_buf + i - shift);
+ xfree(tofree);
+ return FAIL;
+ } else if (ENCODE_RAW(ch)) {
+ str_len += shift;
+ } else {
+ str_len += ((sizeof("\\u1234") - 1)
+ * (size_t)(1 + (ch >= SURROGATE_FIRST_CHAR)));
}
+ break;
}
}
ga_append(gap, '"');
- ga_grow(gap, (int) str_len);
+ ga_grow(gap, (int)str_len);
for (size_t i = 0; i < utf_len;) {
const int ch = utf_ptr2char(utf_buf + i);
const size_t shift = (ch == 0? 1: utf_char2len(ch));
@@ -640,46 +662,44 @@ static inline int convert_to_json_string(garray_T *const gap,
// Is false on invalid unicode, but this should already be handled.
assert(ch == 0 || shift == utf_ptr2len(utf_buf + i));
switch (ch) {
- case BS:
- case TAB:
- case NL:
- case FF:
- case CAR:
- case '"':
- case '\\': {
- ga_concat_len(gap, escapes[ch], 2);
- break;
- }
- default: {
- if (ENCODE_RAW(ch)) {
- ga_concat_len(gap, utf_buf + i, shift);
- } else if (ch < SURROGATE_FIRST_CHAR) {
- ga_concat_len(gap, ((const char[]) {
- '\\', 'u',
- xdigits[(ch >> (4 * 3)) & 0xF],
- xdigits[(ch >> (4 * 2)) & 0xF],
- xdigits[(ch >> (4 * 1)) & 0xF],
- xdigits[(ch >> (4 * 0)) & 0xF],
- }), sizeof("\\u1234") - 1);
- } else {
- const int tmp = ch - SURROGATE_FIRST_CHAR;
- const int hi = SURROGATE_HI_START + ((tmp >> 10) & ((1 << 10) - 1));
- const int lo = SURROGATE_LO_END + ((tmp >> 0) & ((1 << 10) - 1));
- ga_concat_len(gap, ((const char[]) {
- '\\', 'u',
- xdigits[(hi >> (4 * 3)) & 0xF],
- xdigits[(hi >> (4 * 2)) & 0xF],
- xdigits[(hi >> (4 * 1)) & 0xF],
- xdigits[(hi >> (4 * 0)) & 0xF],
- '\\', 'u',
- xdigits[(lo >> (4 * 3)) & 0xF],
- xdigits[(lo >> (4 * 2)) & 0xF],
- xdigits[(lo >> (4 * 1)) & 0xF],
- xdigits[(lo >> (4 * 0)) & 0xF],
- }), (sizeof("\\u1234") - 1) * 2);
- }
- break;
+ case BS:
+ case TAB:
+ case NL:
+ case FF:
+ case CAR:
+ case '"':
+ case '\\':
+ ga_concat_len(gap, escapes[ch], 2);
+ break;
+ default:
+ if (ENCODE_RAW(ch)) {
+ ga_concat_len(gap, utf_buf + i, shift);
+ } else if (ch < SURROGATE_FIRST_CHAR) {
+ ga_concat_len(gap, ((const char[]) {
+ '\\', 'u',
+ xdigits[(ch >> (4 * 3)) & 0xF],
+ xdigits[(ch >> (4 * 2)) & 0xF],
+ xdigits[(ch >> (4 * 1)) & 0xF],
+ xdigits[(ch >> (4 * 0)) & 0xF],
+ }), sizeof("\\u1234") - 1);
+ } else {
+ const int tmp = ch - SURROGATE_FIRST_CHAR;
+ const int hi = SURROGATE_HI_START + ((tmp >> 10) & ((1 << 10) - 1));
+ const int lo = SURROGATE_LO_END + ((tmp >> 0) & ((1 << 10) - 1));
+ ga_concat_len(gap, ((const char[]) {
+ '\\', 'u',
+ xdigits[(hi >> (4 * 3)) & 0xF],
+ xdigits[(hi >> (4 * 2)) & 0xF],
+ xdigits[(hi >> (4 * 1)) & 0xF],
+ xdigits[(hi >> (4 * 0)) & 0xF],
+ '\\', 'u',
+ xdigits[(lo >> (4 * 3)) & 0xF],
+ xdigits[(lo >> (4 * 2)) & 0xF],
+ xdigits[(lo >> (4 * 1)) & 0xF],
+ xdigits[(lo >> (4 * 0)) & 0xF],
+ }), (sizeof("\\u1234") - 1) * 2);
}
+ break;
}
i += shift;
}
@@ -691,25 +711,47 @@ static inline int convert_to_json_string(garray_T *const gap,
#undef TYPVAL_ENCODE_CONV_STRING
#define TYPVAL_ENCODE_CONV_STRING(tv, buf, len) \
- do { \
- if (convert_to_json_string(gap, (const char *) (buf), (len)) != OK) { \
- return FAIL; \
- } \
- } while (0)
+ do { \
+ if (convert_to_json_string(gap, (const char *)(buf), (len)) != OK) { \
+ return FAIL; \
+ } \
+ } while (0)
#undef TYPVAL_ENCODE_CONV_EXT_STRING
#define TYPVAL_ENCODE_CONV_EXT_STRING(tv, buf, len, type) \
- do { \
- xfree(buf); \
- EMSG(_("E474: Unable to convert EXT string to JSON")); \
- return FAIL; \
- } while (0)
+ do { \
+ xfree(buf); \
+ EMSG(_("E474: Unable to convert EXT string to JSON")); \
+ return FAIL; \
+ } while (0)
+
+#undef TYPVAL_ENCODE_CONV_BLOB
+#define TYPVAL_ENCODE_CONV_BLOB(tv, blob, len) \
+ do { \
+ const blob_T *const blob_ = (blob); \
+ const int len_ = (len); \
+ if (len_ == 0) { \
+ ga_concat(gap, "[]"); \
+ } else { \
+ ga_append(gap, '['); \
+ char numbuf[NUMBUFLEN]; \
+ for (int i_ = 0; i_ < len_; i_++) { \
+ if (i_ > 0) { \
+ ga_concat(gap, ", "); \
+ } \
+ vim_snprintf((char *)numbuf, ARRAY_SIZE(numbuf), "%d", \
+ (int)tv_blob_get(blob_, i_)); \
+ ga_concat(gap, numbuf); \
+ } \
+ ga_append(gap, ']'); \
+ } \
+ } while (0)
#undef TYPVAL_ENCODE_CONV_FUNC_START
#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \
- return conv_error(_("E474: Error while dumping %s, %s: " \
- "attempt to dump function reference"), \
- mpstack, objname)
+ return conv_error(_("E474: Error while dumping %s, %s: " \
+ "attempt to dump function reference"), \
+ mpstack, objname)
/// Check whether given key can be used in json_encode()
///
@@ -750,12 +792,12 @@ 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)) { \
- EMSG(_("E474: Invalid key in special dictionary")); \
- goto label; \
- } \
- } while (0)
+ do { \
+ if (!encode_check_json_key(&key)) { \
+ EMSG(_("E474: Invalid key in special dictionary")); \
+ goto label; \
+ } \
+ } while (0)
#define TYPVAL_ENCODE_SCOPE static
#define TYPVAL_ENCODE_NAME json
@@ -770,6 +812,7 @@ bool encode_check_json_key(const typval_T *const tv)
#undef TYPVAL_ENCODE_CONV_STRING
#undef TYPVAL_ENCODE_CONV_STR_STRING
#undef TYPVAL_ENCODE_CONV_EXT_STRING
+#undef TYPVAL_ENCODE_CONV_BLOB
#undef TYPVAL_ENCODE_CONV_NUMBER
#undef TYPVAL_ENCODE_CONV_FLOAT
#undef TYPVAL_ENCODE_CONV_FUNC_START
@@ -812,10 +855,10 @@ char *encode_tv2string(typval_T *tv, size_t *len)
assert(evs_ret == OK);
did_echo_string_emsg = false;
if (len != NULL) {
- *len = (size_t) ga.ga_len;
+ *len = (size_t)ga.ga_len;
}
ga_append(&ga, '\0');
- return (char *) ga.ga_data;
+ return (char *)ga.ga_data;
}
/// Return a string with the string representation of a variable.
@@ -840,10 +883,10 @@ char *encode_tv2echo(typval_T *tv, size_t *len)
assert(eve_ret == OK);
}
if (len != NULL) {
- *len = (size_t) ga.ga_len;
+ *len = (size_t)ga.ga_len;
}
ga_append(&ga, '\0');
- return (char *) ga.ga_data;
+ return (char *)ga.ga_data;
}
/// Return a string with the string representation of a variable.
@@ -872,81 +915,90 @@ char *encode_tv2json(typval_T *tv, size_t *len)
}
#define TYPVAL_ENCODE_CONV_STRING(tv, buf, len) \
- do { \
- if (buf == NULL) { \
- msgpack_pack_bin(packer, 0); \
- } else { \
- const size_t len_ = (len); \
- msgpack_pack_bin(packer, len_); \
- msgpack_pack_bin_body(packer, buf, len_); \
- } \
- } while (0)
+ do { \
+ if (buf == NULL) { \
+ msgpack_pack_bin(packer, 0); \
+ } else { \
+ const size_t len_ = (len); \
+ msgpack_pack_bin(packer, len_); \
+ msgpack_pack_bin_body(packer, buf, len_); \
+ } \
+ } while (0)
#define TYPVAL_ENCODE_CONV_STR_STRING(tv, buf, len) \
- do { \
- if (buf == NULL) { \
- msgpack_pack_str(packer, 0); \
- } else { \
- const size_t len_ = (len); \
- msgpack_pack_str(packer, len_); \
- msgpack_pack_str_body(packer, buf, len_); \
- } \
- } while (0)
+ do { \
+ if (buf == NULL) { \
+ msgpack_pack_str(packer, 0); \
+ } else { \
+ const size_t len_ = (len); \
+ msgpack_pack_str(packer, len_); \
+ msgpack_pack_str_body(packer, buf, len_); \
+ } \
+ } while (0)
#define TYPVAL_ENCODE_CONV_EXT_STRING(tv, buf, len, type) \
- do { \
- 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_body(packer, buf, len_); \
- } \
- } while (0)
+ do { \
+ 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_body(packer, buf, len_); \
+ } \
+ } while (0)
+
+#define TYPVAL_ENCODE_CONV_BLOB(tv, blob, len) \
+ do { \
+ const size_t len_ = (size_t)(len); \
+ msgpack_pack_bin(packer, len_); \
+ if (len_ > 0) { \
+ msgpack_pack_bin_body(packer, (blob)->bv_ga.ga_data, len_); \
+ } \
+ } while (0)
#define TYPVAL_ENCODE_CONV_NUMBER(tv, num) \
- msgpack_pack_int64(packer, (int64_t)(num))
+ msgpack_pack_int64(packer, (int64_t)(num))
#define TYPVAL_ENCODE_CONV_FLOAT(tv, flt) \
- msgpack_pack_double(packer, (double)(flt))
+ msgpack_pack_double(packer, (double)(flt))
#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \
- return conv_error(_("E5004: Error while dumping %s, %s: " \
- "attempt to dump function reference"), \
- mpstack, objname)
+ return conv_error(_("E5004: Error while dumping %s, %s: " \
+ "attempt to dump function reference"), \
+ mpstack, objname)
#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(tv, len)
#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(tv, len)
#define TYPVAL_ENCODE_CONV_FUNC_END(tv)
#define TYPVAL_ENCODE_CONV_EMPTY_LIST(tv) \
- msgpack_pack_array(packer, 0)
+ msgpack_pack_array(packer, 0)
#define TYPVAL_ENCODE_CONV_LIST_START(tv, len) \
- msgpack_pack_array(packer, (size_t)(len))
+ msgpack_pack_array(packer, (size_t)(len))
#define TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START(tv, mpsv)
#define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \
- msgpack_pack_map(packer, 0)
+ msgpack_pack_map(packer, 0)
#define TYPVAL_ENCODE_CONV_NIL(tv) \
- msgpack_pack_nil(packer)
+ msgpack_pack_nil(packer)
#define TYPVAL_ENCODE_CONV_BOOL(tv, num) \
- do { \
- if (num) { \
- msgpack_pack_true(packer); \
- } else { \
- msgpack_pack_false(packer); \
- } \
- } while (0)
+ do { \
+ if (num) { \
+ msgpack_pack_true(packer); \
+ } else { \
+ msgpack_pack_false(packer); \
+ } \
+ } while (0)
#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER(tv, num) \
- msgpack_pack_uint64(packer, (num))
+ msgpack_pack_uint64(packer, (num))
#define TYPVAL_ENCODE_CONV_DICT_START(tv, dict, len) \
- msgpack_pack_map(packer, (size_t)(len))
+ msgpack_pack_map(packer, (size_t)(len))
#define TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START(tv, dict, mpsv)
@@ -963,9 +1015,9 @@ char *encode_tv2json(typval_T *tv, size_t *len)
#define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(tv)
#define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) \
- return conv_error(_("E5005: Unable to dump %s: " \
- "container references itself in %s"), \
- mpstack, objname)
+ return conv_error(_("E5005: Unable to dump %s: " \
+ "container references itself in %s"), \
+ mpstack, objname)
#define TYPVAL_ENCODE_ALLOW_SPECIALS true
@@ -982,6 +1034,7 @@ char *encode_tv2json(typval_T *tv, size_t *len)
#undef TYPVAL_ENCODE_CONV_STRING
#undef TYPVAL_ENCODE_CONV_STR_STRING
#undef TYPVAL_ENCODE_CONV_EXT_STRING
+#undef TYPVAL_ENCODE_CONV_BLOB
#undef TYPVAL_ENCODE_CONV_NUMBER
#undef TYPVAL_ENCODE_CONV_FLOAT
#undef TYPVAL_ENCODE_CONV_FUNC_START
diff --git a/src/nvim/eval/executor.c b/src/nvim/eval/executor.c
index bbba9d12f2..8eceda84cf 100644
--- a/src/nvim/eval/executor.c
+++ b/src/nvim/eval/executor.c
@@ -1,12 +1,12 @@
// 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/eval/typval.h"
-#include "nvim/eval/executor.h"
#include "nvim/eval.h"
+#include "nvim/eval/executor.h"
+#include "nvim/eval/typval.h"
+#include "nvim/globals.h"
#include "nvim/message.h"
#include "nvim/vim.h"
-#include "nvim/globals.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/executor.c.generated.h"
@@ -16,110 +16,131 @@ static char *e_letwrong = N_("E734: Wrong variable type for %s=");
char *e_listidx = N_("E684: list index out of range: %" PRId64);
-/// Hanle tv1 += tv2, -=, *=, /=, %=, .=
+/// Handle tv1 += tv2, -=, *=, /=, %=, .=
///
/// @param[in,out] tv1 First operand, modified typval.
/// @param[in] tv2 Second operand.
/// @param[in] op Used operator.
///
/// @return OK or FAIL.
-int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2,
- const char *const op)
+int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2, const char *const op)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NO_SANITIZE_UNDEFINED
{
// Can't do anything with a Funcref, a Dict or special value on the right.
if (tv2->v_type != VAR_FUNC && tv2->v_type != VAR_DICT
&& tv2->v_type != VAR_BOOL && tv2->v_type != VAR_SPECIAL) {
switch (tv1->v_type) {
- case VAR_DICT:
- case VAR_FUNC:
- case VAR_PARTIAL:
- case VAR_BOOL:
- case VAR_SPECIAL: {
+ case VAR_DICT:
+ case VAR_FUNC:
+ case VAR_PARTIAL:
+ case VAR_BOOL:
+ case VAR_SPECIAL:
+ break;
+ case VAR_BLOB:
+ if (*op != '+' || tv2->v_type != VAR_BLOB) {
break;
}
- case VAR_LIST: {
- if (*op != '+' || tv2->v_type != VAR_LIST) {
- break;
+ // Blob += Blob
+ if (tv1->vval.v_blob != NULL && tv2->vval.v_blob != NULL) {
+ blob_T *const b1 = tv1->vval.v_blob;
+ blob_T *const b2 = tv2->vval.v_blob;
+ for (int i = 0; i < tv_blob_len(b2); i++) {
+ ga_append(&b1->bv_ga, (char)tv_blob_get(b2, i));
}
- // List += List
- if (tv1->vval.v_list != NULL && tv2->vval.v_list != NULL) {
- tv_list_extend(tv1->vval.v_list, tv2->vval.v_list, NULL);
- }
- return OK;
}
- case VAR_NUMBER:
- case VAR_STRING: {
- if (tv2->v_type == VAR_LIST) {
- break;
- }
- if (vim_strchr((char_u *)"+-*/%", *op) != NULL) {
- // nr += nr or nr -= nr, nr *= nr, nr /= nr, nr %= nr
- varnumber_T n = tv_get_number(tv1);
- if (tv2->v_type == VAR_FLOAT) {
- float_T f = (float_T)n;
+ return OK;
+ case VAR_LIST:
+ if (*op != '+' || tv2->v_type != VAR_LIST) {
+ break;
+ }
+ // List += List
+ if (tv1->vval.v_list != NULL && tv2->vval.v_list != NULL) {
+ tv_list_extend(tv1->vval.v_list, tv2->vval.v_list, NULL);
+ }
+ return OK;
+ case VAR_NUMBER:
+ case VAR_STRING:
+ if (tv2->v_type == VAR_LIST) {
+ break;
+ }
+ if (vim_strchr((char_u *)"+-*/%", *op) != NULL) {
+ // nr += nr or nr -= nr, nr *= nr, nr /= nr, nr %= nr
+ varnumber_T n = tv_get_number(tv1);
+ if (tv2->v_type == VAR_FLOAT) {
+ float_T f = (float_T)n;
- if (*op == '%') {
- break;
- }
- switch (*op) {
- case '+': f += tv2->vval.v_float; break;
- case '-': f -= tv2->vval.v_float; break;
- case '*': f *= tv2->vval.v_float; break;
- case '/': f /= tv2->vval.v_float; break;
- }
- tv_clear(tv1);
- tv1->v_type = VAR_FLOAT;
- tv1->vval.v_float = f;
- } else {
- switch (*op) {
- case '+': n += tv_get_number(tv2); break;
- case '-': n -= tv_get_number(tv2); break;
- case '*': n *= tv_get_number(tv2); break;
- case '/': n = num_divide(n, tv_get_number(tv2)); break;
- case '%': n = num_modulus(n, tv_get_number(tv2)); break;
- }
- tv_clear(tv1);
- tv1->v_type = VAR_NUMBER;
- tv1->vval.v_number = n;
+ if (*op == '%') {
+ break;
+ }
+ switch (*op) {
+ case '+':
+ f += tv2->vval.v_float; break;
+ case '-':
+ f -= tv2->vval.v_float; break;
+ case '*':
+ f *= tv2->vval.v_float; break;
+ case '/':
+ f /= tv2->vval.v_float; break;
}
+ tv_clear(tv1);
+ tv1->v_type = VAR_FLOAT;
+ tv1->vval.v_float = f;
} else {
- // str .= str
- if (tv2->v_type == VAR_FLOAT) {
- break;
+ switch (*op) {
+ case '+':
+ n += tv_get_number(tv2); break;
+ case '-':
+ n -= tv_get_number(tv2); break;
+ case '*':
+ n *= tv_get_number(tv2); break;
+ case '/':
+ n = num_divide(n, tv_get_number(tv2)); break;
+ case '%':
+ n = num_modulus(n, tv_get_number(tv2)); break;
}
- const char *tvs = tv_get_string(tv1);
- char numbuf[NUMBUFLEN];
- char *const s = (char *)concat_str(
- (const char_u *)tvs, (const char_u *)tv_get_string_buf(tv2,
- numbuf));
tv_clear(tv1);
- tv1->v_type = VAR_STRING;
- tv1->vval.v_string = (char_u *)s;
+ tv1->v_type = VAR_NUMBER;
+ tv1->vval.v_number = n;
}
- return OK;
- }
- case VAR_FLOAT: {
- if (*op == '%' || *op == '.'
- || (tv2->v_type != VAR_FLOAT
- && tv2->v_type != VAR_NUMBER
- && tv2->v_type != VAR_STRING)) {
+ } else {
+ // str .= str
+ if (tv2->v_type == VAR_FLOAT) {
break;
}
- const float_T f = (tv2->v_type == VAR_FLOAT
+ const char *tvs = tv_get_string(tv1);
+ char numbuf[NUMBUFLEN];
+ char *const s =
+ (char *)concat_str((const char_u *)tvs, (const char_u *)tv_get_string_buf(tv2,
+ numbuf));
+ tv_clear(tv1);
+ tv1->v_type = VAR_STRING;
+ tv1->vval.v_string = (char_u *)s;
+ }
+ return OK;
+ case VAR_FLOAT: {
+ if (*op == '%' || *op == '.'
+ || (tv2->v_type != VAR_FLOAT
+ && tv2->v_type != VAR_NUMBER
+ && tv2->v_type != VAR_STRING)) {
+ break;
+ }
+ const float_T f = (tv2->v_type == VAR_FLOAT
? tv2->vval.v_float
: (float_T)tv_get_number(tv2));
- switch (*op) {
- case '+': tv1->vval.v_float += f; break;
- case '-': tv1->vval.v_float -= f; break;
- case '*': tv1->vval.v_float *= f; break;
- case '/': tv1->vval.v_float /= f; break;
- }
- return OK;
- }
- case VAR_UNKNOWN: {
- abort();
+ switch (*op) {
+ case '+':
+ tv1->vval.v_float += f; break;
+ case '-':
+ tv1->vval.v_float -= f; break;
+ case '*':
+ tv1->vval.v_float *= f; break;
+ case '/':
+ tv1->vval.v_float /= f; break;
}
+ return OK;
+ }
+ case VAR_UNKNOWN:
+ abort();
}
}
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 1ba31bfe68..5569d74413 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -47,6 +47,7 @@
#include "nvim/os/input.h"
#include "nvim/os/shell.h"
#include "nvim/path.h"
+#include "nvim/plines.h"
#include "nvim/popupmnu.h"
#include "nvim/quickfix.h"
#include "nvim/regexp.h"
@@ -79,22 +80,23 @@ KHASH_MAP_INIT_STR(functions, VimLFuncDef)
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/funcs.c.generated.h"
-#ifdef _MSC_VER
+# ifdef _MSC_VER
// This prevents MSVC from replacing the functions with intrinsics,
// and causing errors when trying to get their addresses in funcs.generated.h
-#pragma function(ceil)
-#pragma function(floor)
-#endif
+# pragma function(ceil)
+# pragma function(floor)
+# endif
PRAGMA_DIAG_PUSH_IGNORE_MISSING_PROTOTYPES
PRAGMA_DIAG_PUSH_IGNORE_IMPLICIT_FALLTHROUGH
-#include "funcs.generated.h"
+# include "funcs.generated.h"
PRAGMA_DIAG_POP
PRAGMA_DIAG_POP
#endif
static char *e_listarg = N_("E686: Argument of %s must be a List");
+static char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob");
static char *e_invalwindow = N_("E957: Invalid window number");
/// Dummy va_list for passing to vim_snprintf
@@ -113,12 +115,14 @@ char_u *get_function_name(expand_T *xp, int idx)
static int intidx = -1;
char_u *name;
- if (idx == 0)
+ if (idx == 0) {
intidx = -1;
+ }
if (intidx < 0) {
name = get_user_func_name(xp, idx);
if (name != NULL) {
- if (*name != '<' && STRNCMP("g:", xp->xp_pattern, 2) == 0) {
+ if (*name != NUL && *name != '<'
+ && STRNCMP("g:", xp->xp_pattern, 2) == 0) {
return cat_prefix_varname('g', name);
}
return name;
@@ -152,12 +156,14 @@ char_u *get_expr_name(expand_T *xp, int idx)
static int intidx = -1;
char_u *name;
- if (idx == 0)
+ if (idx == 0) {
intidx = -1;
+ }
if (intidx < 0) {
name = get_function_name(xp, idx);
- if (name != NULL)
+ if (name != NULL) {
return name;
+ }
}
return get_user_var_name(xp, ++intidx);
}
@@ -174,6 +180,52 @@ const VimLFuncDef *find_internal_func(const char *const name)
return find_internal_func_gperf(name, len);
}
+int call_internal_func(const char_u *const fname, const int argcount, typval_T *const argvars,
+ typval_T *const rettv)
+ FUNC_ATTR_NONNULL_ALL
+{
+ const VimLFuncDef *const fdef = find_internal_func((const char *)fname);
+ if (fdef == NULL) {
+ return ERROR_UNKNOWN;
+ } else if (argcount < fdef->min_argc) {
+ return ERROR_TOOFEW;
+ } else if (argcount > fdef->max_argc) {
+ return ERROR_TOOMANY;
+ }
+ argvars[argcount].v_type = VAR_UNKNOWN;
+ fdef->func(argvars, rettv, fdef->data);
+ return ERROR_NONE;
+}
+
+/// Invoke a method for base->method().
+int call_internal_method(const char_u *const fname, const int argcount, typval_T *const argvars,
+ typval_T *const rettv, typval_T *const basetv)
+ FUNC_ATTR_NONNULL_ALL
+{
+ const VimLFuncDef *const fdef = find_internal_func((const char *)fname);
+ if (fdef == NULL) {
+ return ERROR_UNKNOWN;
+ } else if (fdef->base_arg == BASE_NONE) {
+ return ERROR_NOTMETHOD;
+ } else if (argcount + 1 < fdef->min_argc) {
+ return ERROR_TOOFEW;
+ } else if (argcount + 1 > fdef->max_argc) {
+ return ERROR_TOOMANY;
+ }
+
+ typval_T argv[MAX_FUNC_ARGS + 1];
+ const ptrdiff_t base_index
+ = fdef->base_arg == BASE_LAST ? argcount : fdef->base_arg - 1;
+ memcpy(argv, argvars, base_index * sizeof(typval_T));
+ argv[base_index] = *basetv;
+ memcpy(argv + base_index + 1, argvars + base_index,
+ (argcount - base_index) * sizeof(typval_T));
+ argv[argcount + 1].v_type = VAR_UNKNOWN;
+
+ fdef->func(argv, rettv, fdef->data);
+ return ERROR_NONE;
+}
+
/*
* Return TRUE for a non-zero Number and a non-empty String.
*/
@@ -196,7 +248,7 @@ static int non_zero_arg(typval_T *argvars)
static void float_op_wrapper(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
float_T f;
- float_T (*function)(float_T) = (float_T (*)(float_T))fptr;
+ float_T (*function)(float_T) = (float_T (*)(float_T)) fptr;
rettv->v_type = VAR_FLOAT;
if (tv_get_float_chk(argvars, &f)) {
@@ -273,8 +325,20 @@ static void f_add(typval_T *argvars, typval_T *rettv, FunPtr fptr)
tv_list_append_tv(l, &argvars[1]);
tv_copy(&argvars[0], rettv);
}
+ } else if (argvars[0].v_type == VAR_BLOB) {
+ blob_T *const b = argvars[0].vval.v_blob;
+ if (b != NULL
+ && !var_check_lock(b->bv_lock, N_("add() argument"), TV_TRANSLATE)) {
+ bool error = false;
+ const varnumber_T n = tv_get_number_chk(&argvars[1], &error);
+
+ if (!error) {
+ ga_append(&b->bv_ga, (int)n);
+ tv_copy(&argvars[0], rettv);
+ }
+ }
} else {
- EMSG(_(e_listreq));
+ EMSG(_(e_listblobreq));
}
}
@@ -382,8 +446,7 @@ static void f_argv(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_string = NULL;
int idx = tv_get_number_chk(&argvars[0], NULL);
if (arglist != NULL && idx >= 0 && idx < argcount) {
- rettv->vval.v_string = (char_u *)xstrdup(
- (const char *)alist_name(&arglist[idx]));
+ rettv->vval.v_string = (char_u *)xstrdup((const char *)alist_name(&arglist[idx]));
} else if (idx == -1) {
get_arglist_as_rettv(arglist, argcount, rettv);
}
@@ -425,13 +488,13 @@ static void f_assert_notequal(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// "assert_report(msg)
static void f_assert_report(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- garray_T ga;
+ garray_T ga;
- prepare_assert_error(&ga);
- ga_concat(&ga, (const char_u *)tv_get_string(&argvars[0]));
- assert_error(&ga);
- ga_clear(&ga);
- rettv->vval.v_number = 1;
+ prepare_assert_error(&ga);
+ ga_concat(&ga, (const char_u *)tv_get_string(&argvars[0]));
+ assert_error(&ga);
+ ga_clear(&ga);
+ rettv->vval.v_number = 1;
}
/// "assert_exception(string[, msg])" function
@@ -515,11 +578,11 @@ static void f_browsedir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static buf_T *find_buffer(typval_T *avar)
{
- buf_T *buf = NULL;
+ buf_T *buf = NULL;
- if (avar->v_type == VAR_NUMBER)
+ if (avar->v_type == VAR_NUMBER) {
buf = buflist_findnr((int)avar->vval.v_number);
- else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL) {
+ } else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL) {
buf = buflist_findname_exp(avar->vval.v_string);
if (buf == NULL) {
/* No full path name match, try a match with a URL or a "nofile"
@@ -560,7 +623,7 @@ static void f_bufexists(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_buflisted(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- buf_T *buf;
+ buf_T *buf;
buf = find_buffer(&argvars[0]);
rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
@@ -586,7 +649,7 @@ static void f_bufload(typval_T *argvars, typval_T *unused, FunPtr fptr)
*/
static void f_bufloaded(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- buf_T *buf;
+ buf_T *buf;
buf = find_buffer(&argvars[0]);
rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
@@ -688,19 +751,23 @@ static void f_bufwinnr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
buf_T *tv_get_buf(typval_T *tv, int curtab_only)
{
- char_u *name = tv->vval.v_string;
+ char_u *name = tv->vval.v_string;
int save_magic;
- char_u *save_cpo;
- buf_T *buf;
+ char_u *save_cpo;
+ buf_T *buf;
- if (tv->v_type == VAR_NUMBER)
+ if (tv->v_type == VAR_NUMBER) {
return buflist_findnr((int)tv->vval.v_number);
- if (tv->v_type != VAR_STRING)
+ }
+ if (tv->v_type != VAR_STRING) {
return NULL;
- if (name == NULL || *name == NUL)
+ }
+ if (name == NULL || *name == NUL) {
return curbuf;
- if (name[0] == '$' && name[1] == NUL)
+ }
+ if (name[0] == '$' && name[1] == NUL) {
return lastbuf;
+ }
// Ignore 'magic' and 'cpoptions' here to make scripts portable
save_magic = p_magic;
@@ -736,7 +803,7 @@ buf_T *tv_get_buf_from_arg(typval_T *const tv) FUNC_ATTR_NONNULL_ALL
/// Get the buffer from "arg" and give an error and return NULL if it is not
/// valid.
-buf_T * get_buf_arg(typval_T *arg)
+buf_T *get_buf_arg(typval_T *arg)
{
buf_T *buf;
@@ -814,9 +881,9 @@ static void f_call(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
bool owned = false;
- char_u *func;
- partial_T *partial = NULL;
- dict_T *selfdict = NULL;
+ char_u *func;
+ partial_T *partial = NULL;
+ dict_T *selfdict = NULL;
if (argvars[0].v_type == VAR_FUNC) {
func = argvars[0].vval.v_string;
} else if (argvars[0].v_type == VAR_PARTIAL) {
@@ -866,7 +933,7 @@ static void f_chanclose(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
if (argvars[0].v_type != VAR_NUMBER || (argvars[1].v_type != VAR_STRING
- && argvars[1].v_type != VAR_UNKNOWN)) {
+ && argvars[1].v_type != VAR_UNKNOWN)) {
EMSG(_(e_invarg));
return;
}
@@ -911,7 +978,17 @@ static void f_chansend(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
ptrdiff_t input_len = 0;
- char *input = save_tv_as_string(&argvars[1], &input_len, false);
+ char *input = NULL;
+ if (argvars[1].v_type == VAR_BLOB) {
+ const blob_T *const b = argvars[1].vval.v_blob;
+ input_len = tv_blob_len(b);
+ if (input_len > 0) {
+ input = xmemdup(b->bv_ga.ga_data, input_len);
+ }
+ } else {
+ input = save_tv_as_string(&argvars[1], &input_len, false);
+ }
+
if (!input) {
// Either the error has been handled by save_tv_as_string(),
// or there is no input to send.
@@ -936,8 +1013,7 @@ static void f_char2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
- rettv->vval.v_number = utf_ptr2char(
- (const char_u *)tv_get_string(&argvars[0]));
+ rettv->vval.v_number = utf_ptr2char((const char_u *)tv_get_string(&argvars[0]));
}
// "charidx()" function
@@ -1000,11 +1076,12 @@ static void f_cindent(typval_T *argvars, typval_T *rettv, FunPtr fptr)
curwin->w_cursor.lnum = lnum;
rettv->vval.v_number = get_c_indent();
curwin->w_cursor = pos;
- } else
+ } else {
rettv->vval.v_number = -1;
+ }
}
-static win_T * get_optional_window(typval_T *argvars, int idx)
+static win_T *get_optional_window(typval_T *argvars, int idx)
{
win_T *win = curwin;
@@ -1036,7 +1113,7 @@ static void f_clearmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_col(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
colnr_T col = 0;
- pos_T *fp;
+ pos_T *fp;
int fnum = curbuf->b_fnum;
fp = var2fpos(&argvars[0], FALSE, &fnum);
@@ -1053,14 +1130,17 @@ static void f_col(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// col(".") when the cursor is on the NUL at the end of the line
// because of "coladd" can be seen as an extra column.
if (virtual_active() && fp == &curwin->w_cursor) {
- char_u *p = get_cursor_pos_ptr();
+ char_u *p = get_cursor_pos_ptr();
- if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
- curwin->w_virtcol - curwin->w_cursor.coladd)) {
+ if (curwin->w_cursor.coladd
+ >= (colnr_T)win_chartabsize(curwin, p,
+ (curwin->w_virtcol
+ - curwin->w_cursor.coladd))) {
int l;
- if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
+ if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL) {
col += l;
+ }
}
}
}
@@ -1078,10 +1158,11 @@ static void f_complete(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- /* Check for undo allowed here, because if something was already inserted
- * the line was already saved for undo and this check isn't done. */
- if (!undo_allowed())
+ // Check for undo allowed here, because if something was already inserted
+ // the line was already saved for undo and this check isn't done.
+ if (!undo_allowed(curbuf)) {
return;
+ }
if (argvars[1].v_type != VAR_LIST) {
EMSG(_(e_invarg));
@@ -1165,11 +1246,16 @@ static void f_confirm(typval_T *argvars, typval_T *rettv, FunPtr fptr)
error = true;
} else {
switch (TOUPPER_ASC(*typestr)) {
- case 'E': type = VIM_ERROR; break;
- case 'Q': type = VIM_QUESTION; break;
- case 'I': type = VIM_INFO; break;
- case 'W': type = VIM_WARNING; break;
- case 'G': type = VIM_GENERIC; break;
+ case 'E':
+ type = VIM_ERROR; break;
+ case 'Q':
+ type = VIM_QUESTION; break;
+ case 'I':
+ type = VIM_INFO; break;
+ case 'W':
+ type = VIM_WARNING; break;
+ case 'G':
+ type = VIM_GENERIC; break;
}
}
}
@@ -1181,8 +1267,8 @@ static void f_confirm(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
if (!error) {
- rettv->vval.v_number = do_dialog(
- type, NULL, (char_u *)message, (char_u *)buttons, def, NULL, false);
+ rettv->vval.v_number = do_dialog(type, NULL, (char_u *)message, (char_u *)buttons, def, NULL,
+ false);
}
}
@@ -1232,8 +1318,8 @@ static void f_count(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
} else if (argvars[0].v_type == VAR_LIST) {
- listitem_T *li;
- list_T *l;
+ listitem_T *li;
+ list_T *l;
long idx;
if ((l = argvars[0].vval.v_list) != NULL) {
@@ -1248,8 +1334,9 @@ static void f_count(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
}
- if (error)
+ if (error) {
li = NULL;
+ }
}
for (; li != NULL; li = TV_LIST_ITEM_NEXT(l, li)) {
@@ -1260,8 +1347,8 @@ static void f_count(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
} else if (argvars[0].v_type == VAR_DICT) {
int todo;
- dict_T *d;
- hashitem_T *hi;
+ dict_T *d;
+ hashitem_T *hi;
if ((d = argvars[0].vval.v_dict) != NULL) {
if (argvars[2].v_type != VAR_UNKNOWN) {
@@ -1715,7 +1802,7 @@ static void f_did_filetype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_diff_filler(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
+ rettv->vval.v_number = MAX(0, diff_check(curwin, tv_get_lnum(argvars)));
}
/*
@@ -1780,53 +1867,45 @@ static void f_empty(typval_T *argvars, typval_T *rettv, FunPtr fptr)
bool n = true;
switch (argvars[0].v_type) {
- case VAR_STRING:
- case VAR_FUNC: {
- n = argvars[0].vval.v_string == NULL
- || *argvars[0].vval.v_string == NUL;
- break;
- }
- case VAR_PARTIAL: {
+ case VAR_STRING:
+ case VAR_FUNC:
+ n = argvars[0].vval.v_string == NULL
+ || *argvars[0].vval.v_string == NUL;
+ break;
+ case VAR_PARTIAL:
+ n = false;
+ break;
+ case VAR_NUMBER:
+ n = argvars[0].vval.v_number == 0;
+ break;
+ case VAR_FLOAT:
+ n = argvars[0].vval.v_float == 0.0;
+ break;
+ case VAR_LIST:
+ n = (tv_list_len(argvars[0].vval.v_list) == 0);
+ break;
+ case VAR_DICT:
+ n = (tv_dict_len(argvars[0].vval.v_dict) == 0);
+ break;
+ case VAR_BOOL:
+ switch (argvars[0].vval.v_bool) {
+ case kBoolVarTrue:
n = false;
break;
- }
- case VAR_NUMBER: {
- n = argvars[0].vval.v_number == 0;
- break;
- }
- case VAR_FLOAT: {
- n = argvars[0].vval.v_float == 0.0;
- break;
- }
- case VAR_LIST: {
- n = (tv_list_len(argvars[0].vval.v_list) == 0);
- break;
- }
- case VAR_DICT: {
- n = (tv_dict_len(argvars[0].vval.v_dict) == 0);
- break;
- }
- case VAR_BOOL: {
- switch (argvars[0].vval.v_bool) {
- case kBoolVarTrue: {
- n = false;
- break;
- }
- case kBoolVarFalse: {
- n = true;
- break;
- }
- }
- break;
- }
- case VAR_SPECIAL: {
- n = argvars[0].vval.v_special == kSpecialVarNull;
- break;
- }
- case VAR_UNKNOWN: {
- internal_error("f_empty(UNKNOWN)");
+ case kBoolVarFalse:
+ n = true;
break;
}
+ break;
+ case VAR_SPECIAL:
+ n = argvars[0].vval.v_special == kSpecialVarNull;
+ break;
+ case VAR_BLOB:
+ n = (tv_blob_len(argvars[0].vval.v_blob) == 0);
+ break;
+ case VAR_UNKNOWN:
+ internal_error("f_empty(UNKNOWN)");
+ break;
}
rettv->vval.v_number = n;
@@ -1886,9 +1965,8 @@ static void f_escape(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
char buf[NUMBUFLEN];
- rettv->vval.v_string = vim_strsave_escaped(
- (const char_u *)tv_get_string(&argvars[0]),
- (const char_u *)tv_get_string_buf(&argvars[1], buf));
+ rettv->vval.v_string = vim_strsave_escaped((const char_u *)tv_get_string(&argvars[0]),
+ (const char_u *)tv_get_string_buf(&argvars[1], buf));
rettv->v_type = VAR_STRING;
}
@@ -1921,7 +1999,7 @@ static void f_eval(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (expr_start != NULL && !aborting()) {
EMSG2(_(e_invexpr2), expr_start);
}
- need_clr_eos = FALSE;
+ need_clr_eos = false;
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
} else if (*s != NUL) {
@@ -1969,8 +2047,7 @@ static char_u *get_list_line(int c, void *cookie, int indent, bool do_concat)
return (char_u *)(s == NULL ? NULL : xstrdup(s));
}
-static void execute_common(typval_T *argvars, typval_T *rettv, FunPtr fptr,
- int arg_off)
+static void execute_common(typval_T *argvars, typval_T *rettv, FunPtr fptr, int arg_off)
{
const int save_msg_silent = msg_silent;
const int save_emsg_silent = emsg_silent;
@@ -2076,7 +2153,7 @@ static void f_win_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// Update the status line if the cursor moved.
if (win_valid(wp) && !equalpos(curpos, wp->w_cursor)) {
- wp->w_redr_status = true;
+ wp->w_redr_status = true;
}
}
}
@@ -2144,7 +2221,7 @@ static void f_exists(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_expand(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
size_t len;
- char_u *errormsg;
+ char_u *errormsg;
int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
expand_T xpc;
bool error = false;
@@ -2443,8 +2520,9 @@ static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what)
if (*fname != NUL && !error) {
do {
- if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
+ if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST) {
xfree(fresult);
+ }
fresult = find_file_in_path_option(first ? (char_u *)fname : NULL,
first ? strlen(fname) : 0,
0, first, path,
@@ -2460,8 +2538,9 @@ static void findfilendir(typval_T *argvars, typval_T *rettv, int find_what)
} while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
}
- if (rettv->v_type == VAR_STRING)
+ if (rettv->v_type == VAR_STRING) {
rettv->vval.v_string = fresult;
+ }
}
@@ -2528,8 +2607,7 @@ static void f_fmod(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_fnameescape(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- rettv->vval.v_string = (char_u *)vim_strsave_fnameescape(
- tv_get_string(&argvars[0]), false);
+ rettv->vval.v_string = (char_u *)vim_strsave_fnameescape(tv_get_string(&argvars[0]), false);
rettv->v_type = VAR_STRING;
}
@@ -2617,14 +2695,14 @@ static void f_foldlevel(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_foldtext(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- linenr_T foldstart;
- linenr_T foldend;
- char_u *dashes;
- linenr_T lnum;
- char_u *s;
- char_u *r;
- int len;
- char *txt;
+ linenr_T foldstart;
+ linenr_T foldend;
+ char_u *dashes;
+ linenr_T lnum;
+ char_u *s;
+ char_u *r;
+ int len;
+ char *txt;
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
@@ -2647,8 +2725,9 @@ static void f_foldtext(typval_T *argvars, typval_T *rettv, FunPtr fptr)
s = skipwhite(s + 2);
if (*skipwhite(s) == NUL && lnum + 1 < foldend) {
s = skipwhite(ml_get(lnum + 1));
- if (*s == '*')
+ if (*s == '*') {
s = skipwhite(s + 1);
+ }
}
}
unsigned long count = (unsigned long)(foldend - foldstart + 1);
@@ -2671,7 +2750,7 @@ static void f_foldtext(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_foldtextresult(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *text;
+ char_u *text;
char_u buf[FOLD_TEXT_LEN];
static bool entered = false;
@@ -2733,14 +2812,30 @@ static void f_garbagecollect(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- listitem_T *li;
- list_T *l;
- dictitem_T *di;
- dict_T *d;
- typval_T *tv = NULL;
+ listitem_T *li;
+ list_T *l;
+ dictitem_T *di;
+ dict_T *d;
+ typval_T *tv = NULL;
bool what_is_dict = false;
- if (argvars[0].v_type == VAR_LIST) {
+ if (argvars[0].v_type == VAR_BLOB) {
+ bool error = false;
+ int idx = tv_get_number_chk(&argvars[1], &error);
+
+ if (!error) {
+ rettv->v_type = VAR_NUMBER;
+ if (idx < 0) {
+ idx = tv_blob_len(argvars[0].vval.v_blob) + idx;
+ }
+ if (idx < 0 || idx >= tv_blob_len(argvars[0].vval.v_blob)) {
+ rettv->vval.v_number = -1;
+ } else {
+ rettv->vval.v_number = tv_blob_get(argvars[0].vval.v_blob, idx);
+ tv = rettv;
+ }
+ }
+ } else if (argvars[0].v_type == VAR_LIST) {
if ((l = argvars[0].vval.v_list) != NULL) {
bool error = false;
@@ -2801,7 +2896,7 @@ static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
} else {
- EMSG2(_(e_listdictarg), "get()");
+ EMSG2(_(e_listdictblobarg), "get()");
}
if (tv == NULL) {
@@ -2880,11 +2975,7 @@ static void f_getbufinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
* buffer.
* If 'retlist' is TRUE, then the lines are returned as a Vim List.
*/
-static void get_buffer_lines(buf_T *buf,
- linenr_T start,
- linenr_T end,
- int retlist,
- typval_T *rettv)
+static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retlist, typval_T *rettv)
{
rettv->v_type = (retlist ? VAR_LIST : VAR_STRING);
rettv->vval.v_string = NULL;
@@ -3027,10 +3118,9 @@ static void f_getchangelist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
-/*
- * "getchar()" function
- */
-static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+// "getchar()" and "getcharstr()" functions
+static void getchar_common(typval_T *argvars, typval_T *rettv)
+ FUNC_ATTR_NONNULL_ALL
{
varnumber_T n;
bool error = false;
@@ -3097,6 +3187,7 @@ static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} else {
i += utf_char2bytes(n, temp + i);
}
+ assert(i < 10);
temp[i++] = NUL;
rettv->v_type = VAR_STRING;
rettv->vval.v_string = vim_strsave(temp);
@@ -3105,21 +3196,21 @@ static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int row = mouse_row;
int col = mouse_col;
int grid = mouse_grid;
- win_T *win;
linenr_T lnum;
- win_T *wp;
+ win_T *wp;
int winnr = 1;
if (row >= 0 && col >= 0) {
- /* Find the window at the mouse coordinates and compute the
- * text position. */
- win = mouse_find_win(&grid, &row, &col);
+ // Find the window at the mouse coordinates and compute the
+ // text position.
+ win_T *const win = mouse_find_win(&grid, &row, &col);
if (win == NULL) {
return;
}
(void)mouse_comp_pos(win, &row, &col, &lnum);
- for (wp = firstwin; wp != win; wp = wp->w_next)
+ for (wp = firstwin; wp != win; wp = wp->w_next) {
++winnr;
+ }
set_vim_var_nr(VV_MOUSE_WIN, winnr);
set_vim_var_nr(VV_MOUSE_WINID, wp->handle);
set_vim_var_nr(VV_MOUSE_LNUM, lnum);
@@ -3129,6 +3220,32 @@ static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
+// "getchar()" function
+static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ getchar_common(argvars, rettv);
+}
+
+// "getcharstr()" function
+static void f_getcharstr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ getchar_common(argvars, rettv);
+
+ if (rettv->v_type == VAR_NUMBER) {
+ char_u temp[7]; // mbyte-char: 6, NUL: 1
+ const varnumber_T n = rettv->vval.v_number;
+ int i = 0;
+
+ if (n != 0) {
+ i += utf_char2bytes(n, temp);
+ }
+ assert(i < 7);
+ temp[i++] = NUL;
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = vim_strsave(temp);
+ }
+}
+
/*
* "getcharmod()" function
*/
@@ -3192,11 +3309,11 @@ static void f_getcmdwintype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// "getcompletion()" function
static void f_getcompletion(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *pat;
- expand_T xpc;
- bool filtered = false;
- int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
- | WILD_NO_BEEP;
+ char_u *pat;
+ expand_T xpc;
+ bool filtered = false;
+ int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
+ | WILD_NO_BEEP;
if (argvars[1].v_type != VAR_STRING) {
EMSG2(_(e_invarg2), "type must be a string");
@@ -3290,7 +3407,7 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
char_u *from = NULL; // The original string to copy
tabpage_T *tp = curtab; // The tabpage to look at.
- win_T *win = curwin; // The window to look at.
+ win_T *win = curwin; // The window to look at.
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
@@ -3353,29 +3470,29 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
cwd = xmalloc(MAXPATHL);
switch (scope) {
- case kCdScopeWindow:
- assert(win);
- from = win->w_localdir;
- if (from) {
- break;
- }
- FALLTHROUGH;
- case kCdScopeTab:
- assert(tp);
- from = tp->tp_localdir;
- if (from) {
- break;
- }
- FALLTHROUGH;
- case kCdScopeGlobal:
- if (globaldir) { // `globaldir` is not always set.
- from = globaldir;
- } else if (os_dirname(cwd, MAXPATHL) == FAIL) { // Get the OS CWD.
- from = (char_u *)""; // Return empty string on failure.
- }
+ case kCdScopeWindow:
+ assert(win);
+ from = win->w_localdir;
+ if (from) {
+ break;
+ }
+ FALLTHROUGH;
+ case kCdScopeTab:
+ assert(tp);
+ from = tp->tp_localdir;
+ if (from) {
break;
- case kCdScopeInvalid: // We should never get here
- abort();
+ }
+ FALLTHROUGH;
+ case kCdScopeGlobal:
+ if (globaldir) { // `globaldir` is not always set.
+ from = globaldir;
+ } else if (os_dirname(cwd, MAXPATHL) == FAIL) { // Get the OS CWD.
+ from = (char_u *)""; // Return empty string on failure.
+ }
+ break;
+ case kCdScopeInvalid: // We should never get here
+ abort();
}
if (from) {
@@ -3468,8 +3585,8 @@ static void f_getftime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_getftype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *type = NULL;
- char *t;
+ char_u *type = NULL;
+ char *t;
const char *fname = tv_get_string(&argvars[0]);
@@ -3596,7 +3713,7 @@ static void f_getmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (cur->match.regprog == NULL) {
// match added with matchaddpos()
for (i = 0; i < MAXPOSMATCH; i++) {
- llpos_T *llpos;
+ llpos_T *llpos;
char buf[30]; // use 30 to avoid compiler warning
llpos = &cur->pos.pos[i];
@@ -3633,6 +3750,59 @@ static void f_getmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
+// "getmousepos()" function
+void f_getmousepos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ dict_T *d;
+ win_T *wp;
+ int row = mouse_row;
+ int col = mouse_col;
+ int grid = mouse_grid;
+ varnumber_T winid = 0;
+ varnumber_T winrow = 0;
+ varnumber_T wincol = 0;
+ linenr_T line = 0;
+ varnumber_T column = 0;
+
+ tv_dict_alloc_ret(rettv);
+ d = rettv->vval.v_dict;
+
+ tv_dict_add_nr(d, S_LEN("screenrow"), (varnumber_T)mouse_row + 1);
+ tv_dict_add_nr(d, S_LEN("screencol"), (varnumber_T)mouse_col + 1);
+
+ wp = mouse_find_win(&grid, &row, &col);
+ if (wp != NULL) {
+ int height = wp->w_height + wp->w_status_height;
+ // The height is adjusted by 1 when there is a bottom border. This is not
+ // 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
+ if (row >= 0 && row < wp->w_height && col >= 0 && col < wp->w_width) {
+ char_u *p;
+ int count;
+
+ mouse_comp_pos(wp, &row, &col, &line);
+
+ // limit to text length plus one
+ p = ml_get_buf(wp->w_buffer, line, false);
+ count = (int)STRLEN(p);
+ if (col > count) {
+ col = count;
+ }
+
+ column = col + 1;
+ }
+ }
+ }
+ tv_dict_add_nr(d, S_LEN("winid"), winid);
+ tv_dict_add_nr(d, S_LEN("winrow"), winrow);
+ tv_dict_add_nr(d, S_LEN("wincol"), wincol);
+ tv_dict_add_nr(d, S_LEN("line"), (varnumber_T)line);
+ tv_dict_add_nr(d, S_LEN("column"), column);
+}
+
/*
* "getpid()" function
*/
@@ -3657,12 +3827,10 @@ static void getpos_both(typval_T *argvars, typval_T *rettv, bool getcurpos)
tv_list_append_number(l, ((fp != NULL)
? (varnumber_T)fp->lnum
: (varnumber_T)0));
- tv_list_append_number(
- l, ((fp != NULL)
+ tv_list_append_number(l, ((fp != NULL)
? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
- : (varnumber_T)0));
- tv_list_append_number(
- l, (fp != NULL) ? (varnumber_T)fp->coladd : (varnumber_T)0);
+ : (varnumber_T)0));
+ tv_list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd : (varnumber_T)0);
if (getcurpos) {
const int save_set_curswant = curwin->w_set_curswant;
const colnr_T save_curswant = curwin->w_curswant;
@@ -3867,18 +4035,18 @@ static void f_gettabwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// "gettagstack()" function
static void f_gettagstack(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- win_T *wp = curwin; // default is current window
+ win_T *wp = curwin; // default is current window
- tv_dict_alloc_ret(rettv);
+ tv_dict_alloc_ret(rettv);
- if (argvars[0].v_type != VAR_UNKNOWN) {
- wp = find_win_by_nr_or_id(&argvars[0]);
- if (wp == NULL) {
- return;
- }
+ if (argvars[0].v_type != VAR_UNKNOWN) {
+ wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp == NULL) {
+ return;
}
+ }
- get_tagstack(wp, rettv->vval.v_dict);
+ get_tagstack(wp, rettv->vval.v_dict);
}
/// "getwininfo()" function
@@ -3996,12 +4164,11 @@ static void f_win_screenpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
//
// Move the window wp into a new split of targetwin in a given direction
//
-static void win_move_into_split(win_T *wp, win_T *targetwin,
- int size, int flags)
+static void win_move_into_split(win_T *wp, win_T *targetwin, int size, int flags)
{
- int dir;
- int height = wp->w_height;
- win_T *oldwin = curwin;
+ int dir;
+ int height = wp->w_height;
+ win_T *oldwin = curwin;
if (wp == targetwin) {
return;
@@ -4037,9 +4204,9 @@ static void win_move_into_split(win_T *wp, win_T *targetwin,
// "win_splitmove()" function
static void f_win_splitmove(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- win_T *wp;
- win_T *targetwin;
- int flags = 0, size = 0;
+ win_T *wp;
+ win_T *targetwin;
+ int flags = 0, size = 0;
wp = find_win_by_nr_or_id(&argvars[0]);
targetwin = find_win_by_nr_or_id(&argvars[1]);
@@ -4053,8 +4220,8 @@ static void f_win_splitmove(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
if (argvars[2].v_type != VAR_UNKNOWN) {
- dict_T *d;
- dictitem_T *di;
+ dict_T *d;
+ dictitem_T *di;
if (argvars[2].v_type != VAR_DICT || argvars[2].vval.v_dict == NULL) {
EMSG(_(e_invarg));
@@ -4133,11 +4300,12 @@ static void f_glob(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (!error) {
ExpandInit(&xpc);
xpc.xp_context = EXPAND_FILES;
- if (p_wic)
+ if (p_wic) {
options += WILD_ICASE;
+ }
if (rettv->v_type == VAR_STRING) {
- rettv->vval.v_string = ExpandOne(
- &xpc, (char_u *)tv_get_string(&argvars[0]), NULL, options, WILD_ALL);
+ rettv->vval.v_string = ExpandOne(&xpc, (char_u *)tv_get_string(&argvars[0]), NULL, options,
+ WILD_ALL);
} else {
ExpandOne(&xpc, (char_u *)tv_get_string(&argvars[0]), NULL, options,
WILD_ALL_KEEP);
@@ -4148,8 +4316,9 @@ static void f_glob(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
ExpandCleanup(&xpc);
}
- } else
+ } else {
rettv->vval.v_string = NULL;
+ }
}
/// "globpath()" function
@@ -4327,6 +4496,7 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr)
"user_commands",
"vartabs",
"vertsplit",
+ "vimscript-1",
"virtualedit",
"visual",
"visualextra",
@@ -4408,8 +4578,9 @@ static void f_has_key(typval_T *argvars, typval_T *rettv, FunPtr fptr)
EMSG(_(e_dictreq));
return;
}
- if (argvars[0].vval.v_dict == NULL)
+ if (argvars[0].vval.v_dict == NULL) {
return;
+ }
rettv->vval.v_number = tv_dict_find(argvars[0].vval.v_dict,
tv_get_string(&argvars[1]),
@@ -4440,7 +4611,7 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
};
tabpage_T *tp = curtab; // The tabpage to look at.
- win_T *win = curwin; // The window to look at.
+ win_T *win = curwin; // The window to look at.
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
@@ -4499,20 +4670,20 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
switch (scope) {
- case kCdScopeWindow:
- assert(win);
- rettv->vval.v_number = win->w_localdir ? 1 : 0;
- break;
- case kCdScopeTab:
- assert(tp);
- rettv->vval.v_number = tp->tp_localdir ? 1 : 0;
- break;
- case kCdScopeGlobal:
- // The global scope never has a local directory
- break;
- case kCdScopeInvalid:
- // We should never get here
- abort();
+ case kCdScopeWindow:
+ assert(win);
+ rettv->vval.v_number = win->w_localdir ? 1 : 0;
+ break;
+ case kCdScopeTab:
+ assert(tp);
+ rettv->vval.v_number = tp->tp_localdir ? 1 : 0;
+ break;
+ case kCdScopeGlobal:
+ // The global scope never has a local directory
+ break;
+ case kCdScopeInvalid:
+ // We should never get here
+ abort();
}
}
@@ -4635,8 +4806,7 @@ static void f_histnr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_hlID(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- rettv->vval.v_number = syn_name2id(
- (const char_u *)tv_get_string(&argvars[0]));
+ rettv->vval.v_number = syn_name2id((const char_u *)tv_get_string(&argvars[0]));
}
/*
@@ -4644,8 +4814,7 @@ static void f_hlID(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_hlexists(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- rettv->vval.v_number = highlight_exists(
- (const char_u *)tv_get_string(&argvars[0]));
+ rettv->vval.v_number = highlight_exists((const char_u *)tv_get_string(&argvars[0]));
}
/*
@@ -4672,11 +4841,9 @@ static void f_iconv(typval_T *argvars, typval_T *rettv, FunPtr fptr)
const char *const str = tv_get_string(&argvars[0]);
char buf1[NUMBUFLEN];
- char_u *const from = enc_canonize(enc_skip(
- (char_u *)tv_get_string_buf(&argvars[1], buf1)));
+ char_u *const from = enc_canonize(enc_skip((char_u *)tv_get_string_buf(&argvars[1], buf1)));
char buf2[NUMBUFLEN];
- char_u *const to = enc_canonize(enc_skip(
- (char_u *)tv_get_string_buf(&argvars[2], buf2)));
+ char_u *const to = enc_canonize(enc_skip((char_u *)tv_get_string_buf(&argvars[2], buf2)));
vimconv.vc_type = CONV_NONE;
convert_setup(&vimconv, from, to);
@@ -4714,8 +4881,38 @@ static void f_index(typval_T *argvars, typval_T *rettv, FunPtr fptr)
bool ic = false;
rettv->vval.v_number = -1;
- if (argvars[0].v_type != VAR_LIST) {
- EMSG(_(e_listreq));
+ if (argvars[0].v_type == VAR_BLOB) {
+ bool error = false;
+ int start = 0;
+
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ start = tv_get_number_chk(&argvars[2], &error);
+ if (error) {
+ return;
+ }
+ }
+ blob_T *const b = argvars[0].vval.v_blob;
+ if (b == NULL) {
+ return;
+ }
+ if (start < 0) {
+ start = tv_blob_len(b) + start;
+ if (start < 0) {
+ start = 0;
+ }
+ }
+ for (idx = start; idx < tv_blob_len(b); idx++) {
+ typval_T tv;
+ tv.v_type = VAR_NUMBER;
+ tv.vval.v_number = tv_blob_get(b, idx);
+ if (tv_equal(&tv, &argvars[1], ic, false)) {
+ rettv->vval.v_number = idx;
+ return;
+ }
+ }
+ return;
+ } else if (argvars[0].v_type != VAR_LIST) {
+ EMSG(_(e_listblobreq));
return;
}
list_T *const l = argvars[0].vval.v_list;
@@ -4844,8 +5041,46 @@ static void f_insert(typval_T *argvars, typval_T *rettv, FunPtr fptr)
list_T *l;
bool error = false;
- if (argvars[0].v_type != VAR_LIST) {
- EMSG2(_(e_listarg), "insert()");
+ if (argvars[0].v_type == VAR_BLOB) {
+ blob_T *const b = argvars[0].vval.v_blob;
+
+ if (b == NULL
+ || var_check_lock(b->bv_lock, N_("insert() argument"),
+ TV_TRANSLATE)) {
+ return;
+ }
+
+ long before = 0;
+ const int len = tv_blob_len(b);
+
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ before = (long)tv_get_number_chk(&argvars[2], &error);
+ if (error) {
+ return; // type error; errmsg already given
+ }
+ if (before < 0 || before > len) {
+ EMSG2(_(e_invarg2), tv_get_string(&argvars[2]));
+ return;
+ }
+ }
+ const int val = tv_get_number_chk(&argvars[1], &error);
+ if (error) {
+ return;
+ }
+ if (val < 0 || val > 255) {
+ EMSG2(_(e_invarg2), tv_get_string(&argvars[1]));
+ return;
+ }
+
+ ga_grow(&b->bv_ga, 1);
+ char_u *const p = (char_u *)b->bv_ga.ga_data;
+ memmove(p + before + 1, p + before, (size_t)len - before);
+ *(p + before) = val;
+ b->bv_ga.ga_len++;
+
+ tv_copy(&argvars[0], rettv);
+ } else if (argvars[0].v_type != VAR_LIST) {
+ EMSG2(_(e_listblobarg), "insert()");
} else if (!var_check_lock(tv_list_locked((l = argvars[0].vval.v_list)),
N_("insert() argument"), TV_TRANSLATE)) {
long before = 0;
@@ -4873,8 +5108,7 @@ static void f_insert(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
// "interrupt()" function
-static void f_interrupt(typval_T *argvars FUNC_ATTR_UNUSED,
- typval_T *rettv FUNC_ATTR_UNUSED,
+static void f_interrupt(typval_T *argvars FUNC_ATTR_UNUSED, typval_T *rettv FUNC_ATTR_UNUSED,
FunPtr fptr FUNC_ATTR_UNUSED)
{
got_int = true;
@@ -4902,7 +5136,7 @@ static void f_isdirectory(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_islocked(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
lval_T lv;
- dictitem_T *di;
+ dictitem_T *di;
rettv->vval.v_number = -1;
const char_u *const end = get_lval((char_u *)tv_get_string(&argvars[0]),
@@ -4954,7 +5188,7 @@ static void f_isinf(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_isnan(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
- && xisnan(argvars[0].vval.v_float);
+ && xisnan(argvars[0].vval.v_float);
}
/// "id()" function
@@ -5062,9 +5296,7 @@ static const char *required_env_vars[] = {
NULL
};
-static dict_T *create_environment(const dictitem_T *job_env,
- const bool clear_env,
- const bool pty,
+static dict_T *create_environment(const dictitem_T *job_env, const bool clear_env, const bool pty,
const char * const pty_term_name)
{
dict_T * env = tv_dict_alloc();
@@ -5181,6 +5413,7 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
bool pty = false;
bool clear_env = false;
bool overlapped = false;
+ ChannelStdinMode stdin_mode = kChannelStdinPipe;
CallbackReader on_stdout = CALLBACK_READER_INIT,
on_stderr = CALLBACK_READER_INIT;
Callback on_exit = CALLBACK_NONE;
@@ -5195,6 +5428,17 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
clear_env = tv_dict_get_number(job_opts, "clear_env") != 0;
overlapped = tv_dict_get_number(job_opts, "overlapped") != 0;
+ char *s = tv_dict_get_string(job_opts, "stdin", false);
+ if (s) {
+ if (!strncmp(s, "null", NUMBUFLEN)) {
+ stdin_mode = kChannelStdinNull;
+ } else if (!strncmp(s, "pipe", NUMBUFLEN)) {
+ // Nothing to do, default value
+ } else {
+ EMSG3(_(e_invargNval), "stdin", s);
+ }
+ }
+
if (pty && rpc) {
EMSG2(_(e_invarg2), "job cannot have both 'pty' and 'rpc' options set");
shell_free_argv(argv);
@@ -5251,8 +5495,8 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
env = create_environment(job_env, clear_env, pty, term_name);
Channel *chan = channel_job_start(argv, on_stdout, on_stderr, on_exit, pty,
- rpc, overlapped, detach, cwd, width, height,
- env, &rettv->vval.v_number);
+ rpc, overlapped, detach, stdin_mode, cwd,
+ width, height, env, &rettv->vval.v_number);
if (chan) {
channel_create_event(chan, NULL);
}
@@ -5301,7 +5545,7 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
if (argvars[0].v_type != VAR_LIST || (argvars[1].v_type != VAR_NUMBER
- && argvars[1].v_type != VAR_UNKNOWN)) {
+ && argvars[1].v_type != VAR_UNKNOWN)) {
EMSG(_(e_invarg));
return;
}
@@ -5316,14 +5560,19 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv, FunPtr fptr)
TV_LIST_ITER_CONST(args, arg, {
Channel *chan = NULL;
if (TV_LIST_ITEM_TV(arg)->v_type != VAR_NUMBER
- || !(chan = find_job(TV_LIST_ITEM_TV(arg)->vval.v_number, false))) {
+ || !(chan = find_channel(TV_LIST_ITEM_TV(arg)->vval.v_number))
+ || chan->streamtype != kChannelStreamProc) {
+ jobs[i] = NULL; // Invalid job.
+ } else if (process_is_stopped(&chan->stream.proc)) {
+ // Job is stopped but not fully destroyed.
+ // Ensure all callbacks on its event queue are executed. #15402
+ process_wait(&chan->stream.proc, -1, NULL);
jobs[i] = NULL; // Invalid job.
} else {
jobs[i] = chan;
channel_incref(chan);
if (chan->stream.proc.status < 0) {
- // Process any pending events on the job's queue before temporarily
- // replacing it.
+ // Flush any events in the job's queue before temporarily replacing it.
multiqueue_process_events(chan->events);
multiqueue_replace_parent(chan->events, waiting_jobs);
}
@@ -5482,29 +5731,27 @@ static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_len(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
switch (argvars[0].v_type) {
- case VAR_STRING:
- case VAR_NUMBER: {
- rettv->vval.v_number = (varnumber_T)strlen(
- tv_get_string(&argvars[0]));
- break;
- }
- case VAR_LIST: {
- rettv->vval.v_number = tv_list_len(argvars[0].vval.v_list);
- break;
- }
- case VAR_DICT: {
- rettv->vval.v_number = tv_dict_len(argvars[0].vval.v_dict);
- break;
- }
- case VAR_UNKNOWN:
- case VAR_BOOL:
- case VAR_SPECIAL:
- case VAR_FLOAT:
- case VAR_PARTIAL:
- case VAR_FUNC: {
- EMSG(_("E701: Invalid type for len()"));
- break;
- }
+ case VAR_STRING:
+ case VAR_NUMBER:
+ rettv->vval.v_number = (varnumber_T)strlen(tv_get_string(&argvars[0]));
+ break;
+ case VAR_BLOB:
+ rettv->vval.v_number = tv_blob_len(argvars[0].vval.v_blob);
+ break;
+ case VAR_LIST:
+ rettv->vval.v_number = tv_list_len(argvars[0].vval.v_list);
+ break;
+ case VAR_DICT:
+ rettv->vval.v_number = tv_dict_len(argvars[0].vval.v_dict);
+ break;
+ case VAR_UNKNOWN:
+ case VAR_BOOL:
+ case VAR_SPECIAL:
+ case VAR_FLOAT:
+ case VAR_PARTIAL:
+ case VAR_FUNC:
+ EMSG(_("E701: Invalid type for len()"));
+ break;
}
}
@@ -5549,7 +5796,7 @@ static void libcall_common(typval_T *argvars, typval_T *rettv, int out_type)
}
if (out_type == VAR_NUMBER) {
- rettv->vval.v_number = (varnumber_T)int_out;
+ rettv->vval.v_number = (varnumber_T)int_out;
}
}
@@ -5679,7 +5926,7 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
int mode;
int abbr = FALSE;
int get_dict = FALSE;
- mapblock_T *mp;
+ mapblock_T *mp;
int buffer_local;
// Return empty string for failure.
@@ -5721,11 +5968,9 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
if (*rhs == NUL) {
rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
} else {
- rettv->vval.v_string = (char_u *)str2special_save(
- (char *)rhs, false, false);
+ rettv->vval.v_string = (char_u *)str2special_save((char *)rhs, false, false);
}
}
-
} else {
tv_dict_alloc_ret(rettv);
if (rhs != NULL) {
@@ -5775,19 +6020,19 @@ static void f_mapcheck(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void find_some_match(typval_T *const argvars, typval_T *const rettv,
const SomeMatchType type)
{
- char_u *str = NULL;
- long len = 0;
- char_u *expr = NULL;
+ char_u *str = NULL;
+ long len = 0;
+ char_u *expr = NULL;
regmatch_T regmatch;
- char_u *save_cpo;
+ char_u *save_cpo;
long start = 0;
long nth = 1;
colnr_T startcol = 0;
bool match = false;
- list_T *l = NULL;
- listitem_T *li = NULL;
+ list_T *l = NULL;
+ listitem_T *li = NULL;
long idx = 0;
- char_u *tofree = NULL;
+ char_u *tofree = NULL;
// Make 'cpoptions' empty, the 'l' flag should not be used here.
save_cpo = p_cpo;
@@ -5795,30 +6040,26 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv,
rettv->vval.v_number = -1;
switch (type) {
- // matchlist(): return empty list when there are no matches.
- case kSomeMatchList: {
- tv_list_alloc_ret(rettv, kListLenMayKnow);
- break;
- }
- // matchstrpos(): return ["", -1, -1, -1]
- case kSomeMatchStrPos: {
- tv_list_alloc_ret(rettv, 4);
- tv_list_append_string(rettv->vval.v_list, "", 0);
- tv_list_append_number(rettv->vval.v_list, -1);
- tv_list_append_number(rettv->vval.v_list, -1);
- tv_list_append_number(rettv->vval.v_list, -1);
- break;
- }
- case kSomeMatchStr: {
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = NULL;
- break;
- }
- case kSomeMatch:
- case kSomeMatchEnd: {
- // Do nothing: zero is default.
- break;
- }
+ // matchlist(): return empty list when there are no matches.
+ case kSomeMatchList:
+ tv_list_alloc_ret(rettv, kListLenMayKnow);
+ break;
+ // matchstrpos(): return ["", -1, -1, -1]
+ case kSomeMatchStrPos:
+ tv_list_alloc_ret(rettv, 4);
+ tv_list_append_string(rettv->vval.v_list, "", 0);
+ tv_list_append_number(rettv->vval.v_list, -1);
+ tv_list_append_number(rettv->vval.v_list, -1);
+ tv_list_append_number(rettv->vval.v_list, -1);
+ break;
+ case kSomeMatchStr:
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
+ break;
+ case kSomeMatch:
+ case kSomeMatchEnd:
+ // Do nothing: zero is default.
+ break;
}
if (argvars[0].v_type == VAR_LIST) {
@@ -5851,10 +6092,12 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv,
}
li = tv_list_find(l, idx);
} else {
- if (start < 0)
+ if (start < 0) {
start = 0;
- if (start > len)
+ }
+ if (start > len) {
goto theend;
+ }
// When "count" argument is there ignore matches before "start",
// otherwise skip part of the string. Differs when pattern is "^"
// or "\<".
@@ -5894,10 +6137,12 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv,
match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
- if (match && --nth <= 0)
+ if (match && --nth <= 0) {
break;
- if (l == NULL && !match)
+ }
+ if (l == NULL && !match) {
break;
+ }
// Advance to just after the match.
if (l != NULL) {
@@ -5907,74 +6152,70 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv,
startcol = (colnr_T)(regmatch.startp[0]
+ (*mb_ptr2len)(regmatch.startp[0]) - str);
if (startcol > (colnr_T)len || str + startcol <= regmatch.startp[0]) {
- match = false;
- break;
+ match = false;
+ break;
}
}
}
if (match) {
switch (type) {
- case kSomeMatchStrPos: {
- list_T *const ret_l = rettv->vval.v_list;
- listitem_T *li1 = tv_list_first(ret_l);
- listitem_T *li2 = TV_LIST_ITEM_NEXT(ret_l, li1);
- listitem_T *li3 = TV_LIST_ITEM_NEXT(ret_l, li2);
- listitem_T *li4 = TV_LIST_ITEM_NEXT(ret_l, li3);
- xfree(TV_LIST_ITEM_TV(li1)->vval.v_string);
-
- const size_t rd = (size_t)(regmatch.endp[0] - regmatch.startp[0]);
- TV_LIST_ITEM_TV(li1)->vval.v_string = xmemdupz(
- (const char *)regmatch.startp[0], rd);
- TV_LIST_ITEM_TV(li3)->vval.v_number = (varnumber_T)(
- regmatch.startp[0] - expr);
- TV_LIST_ITEM_TV(li4)->vval.v_number = (varnumber_T)(
- regmatch.endp[0] - expr);
- if (l != NULL) {
- TV_LIST_ITEM_TV(li2)->vval.v_number = (varnumber_T)idx;
- }
- break;
- }
- case kSomeMatchList: {
- // Return list with matched string and submatches.
- for (int i = 0; i < NSUBEXP; i++) {
- if (regmatch.endp[i] == NULL) {
- tv_list_append_string(rettv->vval.v_list, NULL, 0);
- } else {
- tv_list_append_string(rettv->vval.v_list,
- (const char *)regmatch.startp[i],
- (regmatch.endp[i] - regmatch.startp[i]));
- }
- }
- break;
+ case kSomeMatchStrPos: {
+ list_T *const ret_l = rettv->vval.v_list;
+ listitem_T *li1 = tv_list_first(ret_l);
+ listitem_T *li2 = TV_LIST_ITEM_NEXT(ret_l, li1);
+ listitem_T *li3 = TV_LIST_ITEM_NEXT(ret_l, li2);
+ listitem_T *li4 = TV_LIST_ITEM_NEXT(ret_l, li3);
+ xfree(TV_LIST_ITEM_TV(li1)->vval.v_string);
+
+ const size_t rd = (size_t)(regmatch.endp[0] - regmatch.startp[0]);
+ TV_LIST_ITEM_TV(li1)->vval.v_string = xmemdupz((const char *)regmatch.startp[0], rd);
+ TV_LIST_ITEM_TV(li3)->vval.v_number = (varnumber_T)(
+ regmatch.startp[0] - expr);
+ TV_LIST_ITEM_TV(li4)->vval.v_number = (varnumber_T)(
+ regmatch.endp[0] - expr);
+ if (l != NULL) {
+ TV_LIST_ITEM_TV(li2)->vval.v_number = (varnumber_T)idx;
}
- case kSomeMatchStr: {
- // Return matched string.
- if (l != NULL) {
- tv_copy(TV_LIST_ITEM_TV(li), rettv);
+ break;
+ }
+ case kSomeMatchList:
+ // Return list with matched string and submatches.
+ for (int i = 0; i < NSUBEXP; i++) {
+ if (regmatch.endp[i] == NULL) {
+ tv_list_append_string(rettv->vval.v_list, NULL, 0);
} else {
- rettv->vval.v_string = (char_u *)xmemdupz(
- (const char *)regmatch.startp[0],
- (size_t)(regmatch.endp[0] - regmatch.startp[0]));
+ tv_list_append_string(rettv->vval.v_list,
+ (const char *)regmatch.startp[i],
+ (regmatch.endp[i] - regmatch.startp[i]));
}
- break;
}
- case kSomeMatch:
- case kSomeMatchEnd: {
- if (l != NULL) {
- rettv->vval.v_number = idx;
+ break;
+ case kSomeMatchStr:
+ // Return matched string.
+ if (l != NULL) {
+ tv_copy(TV_LIST_ITEM_TV(li), rettv);
+ } else {
+ rettv->vval.v_string = (char_u *)xmemdupz((const char *)regmatch.startp[0],
+ (size_t)(regmatch.endp[0] -
+ regmatch.startp[0]));
+ }
+ break;
+ case kSomeMatch:
+ case kSomeMatchEnd:
+ if (l != NULL) {
+ rettv->vval.v_number = idx;
+ } else {
+ if (type == kSomeMatch) {
+ rettv->vval.v_number =
+ (varnumber_T)(regmatch.startp[0] - str);
} else {
- if (type == kSomeMatch) {
- rettv->vval.v_number =
- (varnumber_T)(regmatch.startp[0] - str);
- } else {
- rettv->vval.v_number =
- (varnumber_T)(regmatch.endp[0] - str);
- }
- rettv->vval.v_number += (varnumber_T)(str - expr);
+ rettv->vval.v_number =
+ (varnumber_T)(regmatch.endp[0] - str);
}
- break;
+ rettv->vval.v_number += (varnumber_T)(str - expr);
}
+ break;
}
}
vim_regfree(regmatch.regprog);
@@ -6123,7 +6364,7 @@ static void f_matcharg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_matchdelete(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- win_T *win = get_optional_window(argvars, 1);
+ win_T *win = get_optional_window(argvars, 1);
if (win == NULL) {
rettv->vval.v_number = -1;
} else {
@@ -6171,8 +6412,7 @@ static void f_matchstrpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// vval.v_number, type is not touched. Returns zero for
/// empty lists/dictionaries.
/// @param[in] domax Determines whether maximal or minimal value is desired.
-static void max_min(const typval_T *const tv, typval_T *const rettv,
- const bool domax)
+static void max_min(const typval_T *const tv, typval_T *const rettv, const bool domax)
FUNC_ATTR_NONNULL_ALL
{
bool error = false;
@@ -6298,9 +6538,16 @@ static void f_msgpackdump(typval_T *argvars, typval_T *rettv, FunPtr fptr)
EMSG2(_(e_listarg), "msgpackdump()");
return;
}
- list_T *const ret_list = tv_list_alloc_ret(rettv, kListLenMayKnow);
list_T *const list = argvars[0].vval.v_list;
- msgpack_packer *lpacker = msgpack_packer_new(ret_list, &encode_list_write);
+ msgpack_packer *packer;
+ if (argvars[1].v_type != VAR_UNKNOWN
+ && strequal(tv_get_string(&argvars[1]), "B")) {
+ tv_blob_alloc_ret(rettv);
+ packer = msgpack_packer_new(rettv->vval.v_blob, &encode_blob_write);
+ } else {
+ packer = msgpack_packer_new(tv_list_alloc_ret(rettv, kListLenMayKnow),
+ &encode_list_write);
+ }
const char *const msg = _("msgpackdump() argument, index %i");
// Assume that translation will not take more then 4 times more space
char msgbuf[sizeof("msgpackdump() argument, index ") * 4 + NUMBUFLEN];
@@ -6308,23 +6555,47 @@ static void f_msgpackdump(typval_T *argvars, typval_T *rettv, FunPtr fptr)
TV_LIST_ITER(list, li, {
vim_snprintf(msgbuf, sizeof(msgbuf), (char *)msg, idx);
idx++;
- if (encode_vim_to_msgpack(lpacker, TV_LIST_ITEM_TV(li), msgbuf) == FAIL) {
+ if (encode_vim_to_msgpack(packer, TV_LIST_ITEM_TV(li), msgbuf) == FAIL) {
break;
}
});
- msgpack_packer_free(lpacker);
+ msgpack_packer_free(packer);
}
-/// "msgpackparse" function
-static void f_msgpackparse(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+static int msgpackparse_convert_item(const msgpack_object data, const msgpack_unpack_return result,
+ list_T *const ret_list, const bool fail_if_incomplete)
FUNC_ATTR_NONNULL_ALL
{
- if (argvars[0].v_type != VAR_LIST) {
- EMSG2(_(e_listarg), "msgpackparse()");
- return;
+ switch (result) {
+ case MSGPACK_UNPACK_PARSE_ERROR:
+ EMSG2(_(e_invarg2), "Failed to parse msgpack string");
+ return FAIL;
+ case MSGPACK_UNPACK_NOMEM_ERROR:
+ EMSG(_(e_outofmem));
+ return FAIL;
+ case MSGPACK_UNPACK_CONTINUE:
+ if (fail_if_incomplete) {
+ EMSG2(_(e_invarg2), "Incomplete msgpack string");
+ return FAIL;
+ }
+ return NOTDONE;
+ case MSGPACK_UNPACK_SUCCESS: {
+ typval_T tv = { .v_type = VAR_UNKNOWN };
+ if (msgpack_to_vim(data, &tv) == FAIL) {
+ EMSG2(_(e_invarg2), "Failed to convert msgpack string");
+ return FAIL;
+ }
+ tv_list_append_owned_tv(ret_list, tv);
+ return OK;
}
- list_T *const ret_list = tv_list_alloc_ret(rettv, kListLenMayKnow);
- const list_T *const list = argvars[0].vval.v_list;
+ default:
+ abort();
+ }
+}
+
+static void msgpackparse_unpack_list(const list_T *const list, list_T *const ret_list)
+ FUNC_ATTR_NONNULL_ARG(2)
+{
if (tv_list_len(list) == 0) {
return;
}
@@ -6343,43 +6614,28 @@ static void f_msgpackparse(typval_T *argvars, typval_T *rettv, FunPtr fptr)
do {
if (!msgpack_unpacker_reserve_buffer(unpacker, IOSIZE)) {
EMSG(_(e_outofmem));
- goto f_msgpackparse_exit;
+ goto end;
}
size_t read_bytes;
- const int rlret = encode_read_from_list(
- &lrstate, msgpack_unpacker_buffer(unpacker), IOSIZE, &read_bytes);
+ const int rlret = encode_read_from_list(&lrstate, msgpack_unpacker_buffer(unpacker), IOSIZE,
+ &read_bytes);
if (rlret == FAIL) {
EMSG2(_(e_invarg2), "List item is not a string");
- goto f_msgpackparse_exit;
+ goto end;
}
msgpack_unpacker_buffer_consumed(unpacker, read_bytes);
if (read_bytes == 0) {
break;
}
while (unpacker->off < unpacker->used) {
- const msgpack_unpack_return result = msgpack_unpacker_next(unpacker,
- &unpacked);
- if (result == MSGPACK_UNPACK_PARSE_ERROR) {
- EMSG2(_(e_invarg2), "Failed to parse msgpack string");
- goto f_msgpackparse_exit;
- }
- if (result == MSGPACK_UNPACK_NOMEM_ERROR) {
- EMSG(_(e_outofmem));
- goto f_msgpackparse_exit;
- }
- if (result == MSGPACK_UNPACK_SUCCESS) {
- typval_T tv = { .v_type = VAR_UNKNOWN };
- if (msgpack_to_vim(unpacked.data, &tv) == FAIL) {
- EMSG2(_(e_invarg2), "Failed to convert msgpack string");
- goto f_msgpackparse_exit;
- }
- tv_list_append_owned_tv(ret_list, tv);
- }
- if (result == MSGPACK_UNPACK_CONTINUE) {
- if (rlret == OK) {
- EMSG2(_(e_invarg2), "Incomplete msgpack string");
- }
+ const msgpack_unpack_return result
+ = msgpack_unpacker_next(unpacker, &unpacked);
+ const int conv_result = msgpackparse_convert_item(unpacked.data, result,
+ ret_list, rlret == OK);
+ if (conv_result == NOTDONE) {
break;
+ } else if (conv_result == FAIL) {
+ goto end;
}
}
if (rlret == OK) {
@@ -6387,10 +6643,46 @@ static void f_msgpackparse(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
} while (true);
-f_msgpackparse_exit:
- msgpack_unpacked_destroy(&unpacked);
+end:
msgpack_unpacker_free(unpacker);
- return;
+ msgpack_unpacked_destroy(&unpacked);
+}
+
+static void msgpackparse_unpack_blob(const blob_T *const blob, list_T *const ret_list)
+ FUNC_ATTR_NONNULL_ARG(2)
+{
+ const int len = tv_blob_len(blob);
+ if (len == 0) {
+ return;
+ }
+ msgpack_unpacked unpacked;
+ msgpack_unpacked_init(&unpacked);
+ for (size_t offset = 0; offset < (size_t)len;) {
+ const msgpack_unpack_return result
+ = msgpack_unpack_next(&unpacked, blob->bv_ga.ga_data, len, &offset);
+ if (msgpackparse_convert_item(unpacked.data, result, ret_list, true)
+ != OK) {
+ break;
+ }
+ }
+
+ msgpack_unpacked_destroy(&unpacked);
+}
+
+/// "msgpackparse" function
+static void f_msgpackparse(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+ FUNC_ATTR_NONNULL_ALL
+{
+ if (argvars[0].v_type != VAR_LIST && argvars[0].v_type != VAR_BLOB) {
+ EMSG2(_(e_listblobarg), "msgpackparse()");
+ return;
+ }
+ list_T *const ret_list = tv_list_alloc_ret(rettv, kListLenMayKnow);
+ if (argvars[0].v_type == VAR_LIST) {
+ msgpackparse_unpack_list(argvars[0].vval.v_list, ret_list);
+ } else {
+ msgpackparse_unpack_blob(argvars[0].vval.v_blob, ret_list);
+ }
}
/*
@@ -6525,53 +6817,51 @@ static void f_printf(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
// "prompt_setcallback({buffer}, {callback})" function
-static void f_prompt_setcallback(typval_T *argvars,
- typval_T *rettv, FunPtr fptr)
+static void f_prompt_setcallback(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- buf_T *buf;
- Callback prompt_callback = { .type = kCallbackNone };
+ buf_T *buf;
+ Callback prompt_callback = { .type = kCallbackNone };
- if (check_secure()) {
- return;
- }
- buf = tv_get_buf(&argvars[0], false);
- if (buf == NULL) {
- return;
- }
+ if (check_secure()) {
+ return;
+ }
+ buf = tv_get_buf(&argvars[0], false);
+ if (buf == NULL) {
+ return;
+ }
- if (argvars[1].v_type != VAR_STRING || *argvars[1].vval.v_string != NUL) {
- if (!callback_from_typval(&prompt_callback, &argvars[1])) {
- return;
- }
+ if (argvars[1].v_type != VAR_STRING || *argvars[1].vval.v_string != NUL) {
+ if (!callback_from_typval(&prompt_callback, &argvars[1])) {
+ return;
}
+ }
- callback_free(&buf->b_prompt_callback);
- buf->b_prompt_callback = prompt_callback;
+ callback_free(&buf->b_prompt_callback);
+ buf->b_prompt_callback = prompt_callback;
}
// "prompt_setinterrupt({buffer}, {callback})" function
-static void f_prompt_setinterrupt(typval_T *argvars,
- typval_T *rettv, FunPtr fptr)
+static void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- buf_T *buf;
- Callback interrupt_callback = { .type = kCallbackNone };
+ buf_T *buf;
+ Callback interrupt_callback = { .type = kCallbackNone };
- if (check_secure()) {
- return;
- }
- buf = tv_get_buf(&argvars[0], false);
- if (buf == NULL) {
- return;
- }
+ if (check_secure()) {
+ return;
+ }
+ buf = tv_get_buf(&argvars[0], false);
+ if (buf == NULL) {
+ return;
+ }
- if (argvars[1].v_type != VAR_STRING || *argvars[1].vval.v_string != NUL) {
- if (!callback_from_typval(&interrupt_callback, &argvars[1])) {
- return;
- }
+ if (argvars[1].v_type != VAR_STRING || *argvars[1].vval.v_string != NUL) {
+ if (!callback_from_typval(&interrupt_callback, &argvars[1])) {
+ return;
}
+ }
- callback_free(&buf->b_prompt_interrupt);
- buf->b_prompt_interrupt= interrupt_callback;
+ callback_free(&buf->b_prompt_interrupt);
+ buf->b_prompt_interrupt= interrupt_callback;
}
/// "prompt_getprompt({buffer})" function
@@ -6595,23 +6885,22 @@ void f_prompt_getprompt(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
// "prompt_setprompt({buffer}, {text})" function
-static void f_prompt_setprompt(typval_T *argvars,
- typval_T *rettv, FunPtr fptr)
+static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- buf_T *buf;
- const char_u *text;
+ buf_T *buf;
+ const char_u *text;
- if (check_secure()) {
- return;
- }
- buf = tv_get_buf(&argvars[0], false);
- if (buf == NULL) {
- return;
- }
+ if (check_secure()) {
+ return;
+ }
+ buf = tv_get_buf(&argvars[0], false);
+ if (buf == NULL) {
+ return;
+ }
- text = (const char_u *)tv_get_string(&argvars[1]);
- xfree(buf->b_prompt_text);
- buf->b_prompt_text = vim_strsave(text);
+ text = (const char_u *)tv_get_string(&argvars[1]);
+ xfree(buf->b_prompt_text);
+ buf->b_prompt_text = vim_strsave(text);
}
// "pum_getpos()" function
@@ -6626,8 +6915,9 @@ static void f_pum_getpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_pumvisible(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- if (pum_visible())
+ if (pum_visible()) {
rettv->vval.v_number = 1;
+ }
}
/*
@@ -6801,11 +7091,12 @@ static void f_readdir(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
bool binary = false;
- FILE *fd;
+ bool blob = false;
+ FILE *fd;
char_u buf[(IOSIZE/256) * 256]; // rounded to avoid odd + 1
int io_size = sizeof(buf);
int readlen; // size of last fread()
- char_u *prev = NULL; // previously read bytes, if any
+ char_u *prev = NULL; // previously read bytes, if any
long prevlen = 0; // length of data in prev
long prevsize = 0; // size of prev buffer
long maxline = MAXLNUM;
@@ -6813,22 +7104,41 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (argvars[1].v_type != VAR_UNKNOWN) {
if (strcmp(tv_get_string(&argvars[1]), "b") == 0) {
binary = true;
+ } else if (strcmp(tv_get_string(&argvars[1]), "B") == 0) {
+ blob = true;
}
if (argvars[2].v_type != VAR_UNKNOWN) {
maxline = tv_get_number(&argvars[2]);
}
}
- list_T *const l = tv_list_alloc_ret(rettv, kListLenUnknown);
-
// Always open the file in binary mode, library functions have a mind of
// their own about CR-LF conversion.
const char *const fname = tv_get_string(&argvars[0]);
+
+ if (os_isdir((const char_u *)fname)) {
+ EMSG2(_(e_isadir2), fname);
+ return;
+ }
if (*fname == NUL || (fd = os_fopen(fname, READBIN)) == NULL) {
EMSG2(_(e_notopen), *fname == NUL ? _("<empty>") : fname);
return;
}
+ if (blob) {
+ tv_blob_alloc_ret(rettv);
+ if (!read_blob(fd, rettv->vval.v_blob)) {
+ EMSG2(_(e_notread), fname);
+ // An empty blob is returned on error.
+ tv_blob_free(rettv->vval.v_blob);
+ rettv->vval.v_blob = NULL;
+ }
+ fclose(fd);
+ return;
+ }
+
+ list_T *const l = tv_list_alloc_ret(rettv, kListLenUnknown);
+
while (maxline < 0 || tv_list_len(l) < maxline) {
readlen = (int)fread(buf, 1, io_size, fd);
@@ -6843,7 +7153,7 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
p++) {
if (*p == '\n' || readlen <= 0) {
- char_u *s = NULL;
+ char_u *s = NULL;
size_t len = p - start;
// Finished a line. Remove CRs before NL.
@@ -6893,16 +7203,17 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
} else if (*p == NUL) {
*p = '\n';
- // Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
- // when finding the BF and check the previous two bytes.
+ // Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
+ // when finding the BF and check the previous two bytes.
} else if (*p == 0xbf && !binary) {
// Find the two bytes before the 0xbf. If p is at buf, or buf + 1,
// these may be in the "prev" string.
char_u back1 = p >= buf + 1 ? p[-1]
- : prevlen >= 1 ? prev[prevlen - 1] : NUL;
+ : prevlen >= 1 ? prev[prevlen - 1] : NUL;
char_u back2 = p >= buf + 2 ? p[-2]
- : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
- : prevlen >= 2 ? prev[prevlen - 2] : NUL;
+ : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
+ : prevlen >=
+ 2 ? prev[prevlen - 2] : NUL;
if (back2 == 0xef && back1 == 0xbb) {
char_u *dest = p - 2;
@@ -6920,8 +7231,9 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// adjust_prevlen must be 1 or 2.
dest = buf;
}
- if (readlen > p - buf + 1)
+ if (readlen > p - buf + 1) {
memmove(dest, p + 1, readlen - (p - buf) - 1);
+ }
readlen -= 3 - adjust_prevlen;
prevlen -= adjust_prevlen;
p = dest - 1;
@@ -6940,9 +7252,9 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
* fragment of a line, so the first allocation is made
* small, to avoid repeatedly 'allocing' large and
* 'reallocing' small. */
- if (prevsize == 0)
+ if (prevsize == 0) {
prevsize = (long)(p - start);
- else {
+ } else {
long grow50pc = (prevsize * 3) / 2;
long growmin = (long)((p - start) * 2 + prevlen);
prevsize = grow50pc > growmin ? grow50pc : growmin;
@@ -6959,6 +7271,61 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
fclose(fd);
}
+/// "getreginfo()" function
+static void f_getreginfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ const char *strregname;
+ if (argvars[0].v_type != VAR_UNKNOWN) {
+ strregname = tv_get_string_chk(&argvars[0]);
+ if (strregname == NULL) {
+ return;
+ }
+ } else {
+ strregname = (const char *)get_vim_var_str(VV_REG);
+ }
+
+ int regname = (strregname == NULL ? '"' : *strregname);
+ if (regname == 0 || regname == '@') {
+ regname = '"';
+ }
+
+ tv_dict_alloc_ret(rettv);
+ dict_T *const dict = rettv->vval.v_dict;
+
+ list_T *const list = get_reg_contents(regname, kGRegExprSrc | kGRegList);
+ if (list == NULL) {
+ return;
+ }
+ tv_dict_add_list(dict, S_LEN("regcontents"), list);
+
+ char buf[NUMBUFLEN + 2];
+ buf[0] = NUL;
+ buf[1] = NUL;
+ colnr_T reglen = 0;
+ switch (get_reg_type(regname, &reglen)) {
+ case kMTLineWise:
+ buf[0] = 'V';
+ break;
+ case kMTCharWise:
+ buf[0] = 'v';
+ break;
+ case kMTBlockWise:
+ vim_snprintf(buf, sizeof(buf), "%c%d", Ctrl_V, reglen + 1);
+ break;
+ case kMTUnknown:
+ abort();
+ }
+ tv_dict_add_str(dict, S_LEN("regtype"), buf);
+
+ buf[0] = get_register_name(get_unname_register());
+ buf[1] = NUL;
+ if (regname == '"') {
+ tv_dict_add_str(dict, S_LEN("points_to"), buf);
+ } else {
+ tv_dict_add_bool(dict, S_LEN("isunnamed"), regname == buf[0] ? kBoolVarTrue : kBoolVarFalse);
+ }
+}
+
// "reg_executing()" function
static void f_reg_executing(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
@@ -7042,7 +7409,7 @@ static void f_reltime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// results, if varnumber_T or proftime_T change, the union cast will need
// to be revised.
STATIC_ASSERT(sizeof(u.prof) == sizeof(u) && sizeof(u.split) == sizeof(u),
- "type punning will produce incorrect results on this platform");
+ "type punning will produce incorrect results on this platform");
tv_list_alloc_ret(rettv, 2);
tv_list_append_number(rettv->vval.v_list, u.split.high);
@@ -7067,13 +7434,13 @@ static void f_reltimestr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_remove(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- list_T *l;
- listitem_T *item, *item2;
- listitem_T *li;
+ list_T *l;
+ listitem_T *item, *item2;
+ listitem_T *li;
long idx;
long end;
- dict_T *d;
- dictitem_T *di;
+ dict_T *d;
+ dictitem_T *di;
const char *const arg_errmsg = N_("remove() argument");
if (argvars[0].v_type == VAR_DICT) {
@@ -7097,8 +7464,64 @@ static void f_remove(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
}
+ } else if (argvars[0].v_type == VAR_BLOB) {
+ blob_T *const b = argvars[0].vval.v_blob;
+
+ if (b != NULL && var_check_lock(b->bv_lock, arg_errmsg, TV_TRANSLATE)) {
+ return;
+ }
+
+ bool error = false;
+ idx = (long)tv_get_number_chk(&argvars[1], &error);
+
+ if (!error) {
+ const int len = tv_blob_len(b);
+
+ if (idx < 0) {
+ // count from the end
+ idx = len + idx;
+ }
+ if (idx < 0 || idx >= len) {
+ EMSGN(_(e_blobidx), idx);
+ return;
+ }
+ if (argvars[2].v_type == VAR_UNKNOWN) {
+ // Remove one item, return its value.
+ char_u *const p = (char_u *)b->bv_ga.ga_data;
+ rettv->vval.v_number = (varnumber_T)(*(p + idx));
+ memmove(p + idx, p + idx + 1, (size_t)len - idx - 1);
+ b->bv_ga.ga_len--;
+ } else {
+ // Remove range of items, return blob with values.
+ end = (long)tv_get_number_chk(&argvars[2], &error);
+ if (error) {
+ return;
+ }
+ if (end < 0) {
+ // count from the end
+ end = len + end;
+ }
+ if (end >= len || idx > end) {
+ EMSGN(_(e_blobidx), end);
+ return;
+ }
+ blob_T *const blob = tv_blob_alloc();
+ blob->bv_ga.ga_len = end - idx + 1;
+ ga_grow(&blob->bv_ga, end - idx + 1);
+
+ char_u *const p = (char_u *)b->bv_ga.ga_data;
+ memmove((char_u *)blob->bv_ga.ga_data, p + idx,
+ (size_t)(end - idx + 1));
+ tv_blob_set_ret(rettv, blob);
+
+ if (len - end - 1 > 0) {
+ memmove(p + idx, p + end + 1, (size_t)(len - end - 1));
+ }
+ b->bv_ga.ga_len -= end - idx + 1;
+ }
+ }
} else if (argvars[0].v_type != VAR_LIST) {
- EMSG2(_(e_listdictarg), "remove()");
+ EMSG2(_(e_listdictblobarg), "remove()");
} else if (!var_check_lock(tv_list_locked((l = argvars[0].vval.v_list)),
arg_errmsg, TV_TRANSLATE)) {
bool error = false;
@@ -7151,9 +7574,8 @@ static void f_rename(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = -1;
} else {
char buf[NUMBUFLEN];
- rettv->vval.v_number = vim_rename(
- (const char_u *)tv_get_string(&argvars[0]),
- (const char_u *)tv_get_string_buf(&argvars[1], buf));
+ rettv->vval.v_number = vim_rename((const char_u *)tv_get_string(&argvars[0]),
+ (const char_u *)tv_get_string_buf(&argvars[1], buf));
}
}
@@ -7372,13 +7794,25 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_reverse(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- list_T *l;
- if (argvars[0].v_type != VAR_LIST) {
- EMSG2(_(e_listarg), "reverse()");
- } else if (!var_check_lock(tv_list_locked((l = argvars[0].vval.v_list)),
- N_("reverse() argument"), TV_TRANSLATE)) {
- tv_list_reverse(l);
- tv_list_set_ret(rettv, l);
+ if (argvars[0].v_type == VAR_BLOB) {
+ blob_T *const b = argvars[0].vval.v_blob;
+ const int len = tv_blob_len(b);
+
+ for (int i = 0; i < len / 2; i++) {
+ const char_u tmp = tv_blob_get(b, i);
+ tv_blob_set(b, i, tv_blob_get(b, len - i - 1));
+ tv_blob_set(b, len - i - 1, tmp);
+ }
+ tv_blob_set_ret(rettv, b);
+ } else if (argvars[0].v_type != VAR_LIST) {
+ EMSG2(_(e_listblobarg), "reverse()");
+ } else {
+ list_T *const l = argvars[0].vval.v_list;
+ if (!var_check_lock(tv_list_locked(l), N_("reverse() argument"),
+ TV_TRANSLATE)) {
+ tv_list_reverse(l);
+ tv_list_set_ret(rettv, l);
+ }
}
}
@@ -7409,30 +7843,40 @@ static int get_search_arg(typval_T *varp, int *flagsp)
}
while (*flags != NUL) {
switch (*flags) {
- case 'b': dir = BACKWARD; break;
- case 'w': p_ws = true; break;
- case 'W': p_ws = false; break;
- default: {
- mask = 0;
- if (flagsp != NULL) {
- switch (*flags) {
- case 'c': mask = SP_START; break;
- case 'e': mask = SP_END; break;
- case 'm': mask = SP_RETCOUNT; break;
- case 'n': mask = SP_NOMOVE; break;
- case 'p': mask = SP_SUBPAT; break;
- case 'r': mask = SP_REPEAT; break;
- case 's': mask = SP_SETPCMARK; break;
- case 'z': mask = SP_COLUMN; break;
- }
- }
- if (mask == 0) {
- emsgf(_(e_invarg2), flags);
- dir = 0;
- } else {
- *flagsp |= mask;
+ case 'b':
+ dir = BACKWARD; break;
+ case 'w':
+ p_ws = true; break;
+ case 'W':
+ p_ws = false; break;
+ default:
+ mask = 0;
+ if (flagsp != NULL) {
+ switch (*flags) {
+ case 'c':
+ mask = SP_START; break;
+ case 'e':
+ mask = SP_END; break;
+ case 'm':
+ mask = SP_RETCOUNT; break;
+ case 'n':
+ mask = SP_NOMOVE; break;
+ case 'p':
+ mask = SP_SUBPAT; break;
+ case 'r':
+ mask = SP_REPEAT; break;
+ case 's':
+ mask = SP_SETPCMARK; break;
+ case 'z':
+ mask = SP_COLUMN; break;
}
}
+ if (mask == 0) {
+ emsgf(_(e_invarg2), flags);
+ dir = 0;
+ } else {
+ *flagsp |= mask;
+ }
}
if (dir == 0) {
break;
@@ -7511,12 +7955,14 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, (char_u *)pat, 1,
options, RE_SEARCH, &sia);
if (subpatnum != FAIL) {
- if (flags & SP_SUBPAT)
+ if (flags & SP_SUBPAT) {
retval = subpatnum;
- else
+ } else {
retval = pos.lnum;
- if (flags & SP_SETPCMARK)
+ }
+ if (flags & SP_SETPCMARK) {
setpcmark();
+ }
curwin->w_cursor = pos;
if (match_pos != NULL) {
// Store the match cursor position
@@ -7654,10 +8100,10 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
msg_ext_set_kind("rpc_error");
if (name) {
- emsgf_multiline("Error invoking '%s' on channel %"PRIu64" (%s):\n%s",
+ emsgf_multiline("Error invoking '%s' on channel %" PRIu64 " (%s):\n%s",
method, chan_id, name, err.msg);
} else {
- emsgf_multiline("Error invoking '%s' on channel %"PRIu64":\n%s",
+ emsgf_multiline("Error invoking '%s' on channel %" PRIu64 ":\n%s",
method, chan_id, err.msg);
}
@@ -7732,8 +8178,9 @@ static void f_rpcstart(typval_T *argvars, typval_T *rettv, FunPtr fptr)
Channel *chan = channel_job_start(argv, CALLBACK_READER_INIT,
CALLBACK_READER_INIT, CALLBACK_NONE,
- false, true, false, false, NULL, 0, 0,
- NULL, &rettv->vval.v_number);
+ false, true, false, false,
+ kChannelStdinPipe, NULL, 0, 0, NULL,
+ &rettv->vval.v_number);
if (chan) {
channel_create_event(chan, NULL);
}
@@ -7769,9 +8216,7 @@ static void f_rpcstop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
-/*
- * "screenattr()" function
- */
+// "screenattr()" function
static void f_screenattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
int c;
@@ -7789,9 +8234,7 @@ static void f_screenattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = c;
}
-/*
- * "screenchar()" function
- */
+// "screenchar()" function
static void f_screenchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
int c;
@@ -7809,11 +8252,34 @@ static void f_screenchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = c;
}
-/*
- * "screencol()" function
- *
- * First column is 1 to be consistent with virtcol().
- */
+// "screenchars()" function
+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) {
+ tv_list_alloc_ret(rettv, 0);
+ return;
+ }
+ ScreenGrid *grid = &default_grid;
+ screenchar_adjust_grid(&grid, &row, &col);
+ int pcc[MAX_MCO];
+ int c = utfc_ptr2char(grid->chars[grid->line_offset[row] + col], pcc);
+ int composing_len = 0;
+ while (pcc[composing_len] != 0) {
+ composing_len++;
+ }
+ tv_list_alloc_ret(rettv, composing_len + 1);
+ tv_list_append_number(rettv->vval.v_list, c);
+ for (int i = 0; i < composing_len; i++) {
+ tv_list_append_number(rettv->vval.v_list, pcc[i]);
+ }
+}
+
+// "screencol()" function
+//
+// First column is 1 to be consistent with virtcol().
static void f_screencol(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
rettv->vval.v_number = ui_current_col() + 1;
@@ -7845,17 +8311,29 @@ static void f_screenpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
tv_dict_add_nr(dict, S_LEN("endcol"), ecol);
}
-/*
- * "screenrow()" function
- */
+// "screenrow()" function
static void f_screenrow(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
rettv->vval.v_number = ui_current_row() + 1;
}
-/*
- * "search()" function
- */
+// "screenstring()" function
+static void f_screenstring(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ rettv->vval.v_string = NULL;
+ 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) {
+ return;
+ }
+ ScreenGrid *grid = &default_grid;
+ screenchar_adjust_grid(&grid, &row, &col);
+ rettv->vval.v_string = vim_strsave(grid->chars[grid->line_offset[row] + col]);
+}
+
+// "search()" function
static void f_search(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
int flags = 0;
@@ -7958,9 +8436,8 @@ static int searchpair_cmn(typval_T *argvars, pos_T *match_pos)
}
}
- retval = do_searchpair(
- spat, mpat, epat, dir, skip,
- flags, match_pos, lnum_stop, time_limit);
+ retval = do_searchpair(spat, mpat, epat, dir, skip,
+ flags, match_pos, lnum_stop, time_limit);
theend:
p_ws = save_p_ws;
@@ -8001,22 +8478,19 @@ static void f_searchpairpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
* Used by searchpair(), see its documentation for the details.
* Returns 0 or -1 for no match,
*/
-long
-do_searchpair(
- const char *spat, // start pattern
- const char *mpat, // middle pattern
- const char *epat, // end pattern
- int dir, // BACKWARD or FORWARD
- const typval_T *skip, // skip expression
- int flags, // SP_SETPCMARK and other SP_ values
- pos_T *match_pos,
- linenr_T lnum_stop, // stop at this line if not zero
- long time_limit // stop after this many msec
-)
+long do_searchpair(const char *spat, // start pattern
+ const char *mpat, // middle pattern
+ const char *epat, // end pattern
+ int dir, // BACKWARD or FORWARD
+ const typval_T *skip, // skip expression
+ int flags, // SP_SETPCMARK and other SP_ values
+ pos_T *match_pos, linenr_T lnum_stop, // stop at this line if not zero
+ long time_limit // stop after this many msec
+ )
FUNC_ATTR_NONNULL_ARG(1, 2, 3)
{
- char_u *save_cpo;
- char_u *pat, *pat2 = NULL, *pat3 = NULL;
+ char_u *save_cpo;
+ char_u *pat, *pat2 = NULL, *pat3 = NULL;
long retval = 0;
pos_T pos;
pos_T firstpos;
@@ -8078,8 +8552,9 @@ do_searchpair(
break;
}
- if (firstpos.lnum == 0)
+ if (firstpos.lnum == 0) {
firstpos = pos;
+ }
if (equalpos(pos, foundpos)) {
// Found the same position again. Can happen with a pattern that
// has "\zs" at the end and searching backwards. Advance one
@@ -8108,8 +8583,9 @@ do_searchpair(
retval = -1;
break;
}
- if (r)
+ if (r) {
continue;
+ }
}
if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2)) {
@@ -8136,8 +8612,9 @@ do_searchpair(
setpcmark();
}
curwin->w_cursor = pos;
- if (!(flags & SP_REPEAT))
+ if (!(flags & SP_REPEAT)) {
break;
+ }
nest = 1; // search for next unmatched
}
}
@@ -8269,16 +8746,16 @@ static void f_serverstop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// "setbufline()" function
static void f_setbufline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- linenr_T lnum;
- buf_T *buf;
+ linenr_T lnum;
+ buf_T *buf;
- buf = tv_get_buf(&argvars[0], false);
- if (buf == NULL) {
- rettv->vval.v_number = 1; // FAIL
- } else {
- lnum = tv_get_lnum_buf(&argvars[1], buf);
- set_buffer_lines(buf, lnum, false, &argvars[2], rettv);
- }
+ buf = tv_get_buf(&argvars[0], false);
+ if (buf == NULL) {
+ rettv->vval.v_number = 1; // FAIL
+ } else {
+ lnum = tv_get_lnum_buf(&argvars[1], buf);
+ set_buffer_lines(buf, lnum, false, &argvars[2], rettv);
+ }
}
/*
@@ -8329,8 +8806,8 @@ static void f_setbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_setcharsearch(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- dict_T *d;
- dictitem_T *di;
+ dict_T *d;
+ dictitem_T *di;
if (argvars[0].v_type != VAR_DICT) {
EMSG(_(e_dictreq));
@@ -8510,7 +8987,7 @@ skip_args:
*/
static void f_setloclist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- win_T *win;
+ win_T *win;
rettv->vval.v_number = -1;
@@ -8632,7 +9109,7 @@ static void f_setpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
pos_T pos;
int fnum;
- colnr_T curswant = -1;
+ colnr_T curswant = -1;
rettv->vval.v_number = -1;
const char *const name = tv_get_string_chk(argvars);
@@ -8650,7 +9127,7 @@ static void f_setpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
check_cursor();
rettv->vval.v_number = 0;
- } else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL) {
+ } else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL) {
// set mark
if (setmark_pos((uint8_t)name[1], &pos, fnum) == OK) {
rettv->vval.v_number = 0;
@@ -8670,6 +9147,36 @@ static void f_setqflist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
set_qf_ll_list(NULL, argvars, rettv);
}
+/// Translate a register type string to the yank type and block length
+static int get_yank_type(char_u **const pp, MotionType *const yank_type, long *const block_len)
+ FUNC_ATTR_NONNULL_ALL
+{
+ char_u *stropt = *pp;
+ switch (*stropt) {
+ case 'v':
+ case 'c': // character-wise selection
+ *yank_type = kMTCharWise;
+ break;
+ case 'V':
+ case 'l': // line-wise selection
+ *yank_type = kMTLineWise;
+ break;
+ case 'b':
+ case Ctrl_V: // block-wise selection
+ *yank_type = kMTBlockWise;
+ if (ascii_isdigit(stropt[1])) {
+ stropt++;
+ *block_len = getdigits_long(&stropt, false, 0) - 1;
+ stropt--;
+ }
+ break;
+ default:
+ return FAIL;
+ }
+ *pp = stropt;
+ return OK;
+}
+
/*
* "setreg()" function
*/
@@ -8694,45 +9201,75 @@ static void f_setreg(typval_T *argvars, typval_T *rettv, FunPtr fptr)
regname = '"';
}
+ const typval_T *regcontents = NULL;
+ int pointreg = 0;
+ if (argvars[1].v_type == VAR_DICT) {
+ dict_T *const d = argvars[1].vval.v_dict;
+
+ if (tv_dict_len(d) == 0) {
+ // Empty dict, clear the register (like setreg(0, []))
+ char_u *lstval[2] = { NULL, NULL };
+ write_reg_contents_lst(regname, lstval, false, kMTUnknown, -1);
+ return;
+ }
+
+ dictitem_T *const di = tv_dict_find(d, "regcontents", -1);
+ if (di != NULL) {
+ regcontents = &di->di_tv;
+ }
+
+ const char *stropt = tv_dict_get_string(d, "regtype", false);
+ if (stropt != NULL) {
+ const int ret = get_yank_type((char_u **)&stropt, &yank_type, &block_len);
+
+ if (ret == FAIL || *(++stropt) != NUL) {
+ EMSG2(_(e_invargval), "value");
+ return;
+ }
+ }
+
+ if (regname == '"') {
+ stropt = tv_dict_get_string(d, "points_to", false);
+ if (stropt != NULL) {
+ pointreg = *stropt;
+ regname = pointreg;
+ }
+ } else if (tv_dict_get_number(d, "isunnamed")) {
+ pointreg = regname;
+ }
+ } else {
+ regcontents = &argvars[1];
+ }
+
bool set_unnamed = false;
if (argvars[2].v_type != VAR_UNKNOWN) {
+ if (yank_type != kMTUnknown) {
+ EMSG2(_(e_toomanyarg), "setreg");
+ return;
+ }
+
const char *stropt = tv_get_string_chk(&argvars[2]);
if (stropt == NULL) {
return; // Type error.
}
for (; *stropt != NUL; stropt++) {
switch (*stropt) {
- case 'a': case 'A': { // append
- append = true;
- break;
- }
- case 'v': case 'c': { // character-wise selection
- yank_type = kMTCharWise;
- break;
- }
- case 'V': case 'l': { // line-wise selection
- yank_type = kMTLineWise;
- break;
- }
- case 'b': case Ctrl_V: { // block-wise selection
- yank_type = kMTBlockWise;
- if (ascii_isdigit(stropt[1])) {
- stropt++;
- block_len = getdigits_long((char_u **)&stropt, true, 0) - 1;
- stropt--;
- }
- break;
- }
- case 'u': case '"': { // unnamed register
- set_unnamed = true;
- break;
- }
+ case 'a':
+ case 'A': // append
+ append = true;
+ break;
+ case 'u':
+ case '"': // unnamed register
+ set_unnamed = true;
+ break;
+ default:
+ get_yank_type((char_u **)&stropt, &yank_type, &block_len);
}
}
}
- if (argvars[1].v_type == VAR_LIST) {
- list_T *ll = argvars[1].vval.v_list;
+ if (regcontents != NULL && regcontents->v_type == VAR_LIST) {
+ list_T *const ll = regcontents->vval.v_list;
// If the list is NULL handle like an empty list.
const int len = tv_list_len(ll);
@@ -8768,19 +9305,23 @@ free_lstval:
xfree(*--curallocval);
}
xfree(lstval);
- } else {
- const char *strval = tv_get_string_chk(&argvars[1]);
+ } else if (regcontents != NULL) {
+ const char *const strval = tv_get_string_chk(regcontents);
if (strval == NULL) {
return;
}
write_reg_contents_ex(regname, (const char_u *)strval, STRLEN(strval),
append, yank_type, block_len);
}
+ if (pointreg != 0) {
+ get_yank_register(pointreg, YREG_YANK);
+ }
rettv->vval.v_number = 0;
if (set_unnamed) {
// Discard the result. We already handle the error case.
- if (op_reg_set_previous(regname)) { }
+ if (op_reg_set_previous(regname)) {
+ }
}
}
@@ -8828,54 +9369,54 @@ static void f_settabwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// "settagstack()" function
static void f_settagstack(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- static char *e_invact2 = N_("E962: Invalid action: '%s'");
- win_T *wp;
- dict_T *d;
- int action = 'r';
+ static char *e_invact2 = N_("E962: Invalid action: '%s'");
+ win_T *wp;
+ dict_T *d;
+ int action = 'r';
- rettv->vval.v_number = -1;
+ rettv->vval.v_number = -1;
- // first argument: window number or id
- wp = find_win_by_nr_or_id(&argvars[0]);
- if (wp == NULL) {
- return;
- }
+ // first argument: window number or id
+ wp = find_win_by_nr_or_id(&argvars[0]);
+ if (wp == NULL) {
+ return;
+ }
- // second argument: dict with items to set in the tag stack
- if (argvars[1].v_type != VAR_DICT) {
- EMSG(_(e_dictreq));
- return;
- }
- d = argvars[1].vval.v_dict;
- if (d == NULL) {
+ // second argument: dict with items to set in the tag stack
+ if (argvars[1].v_type != VAR_DICT) {
+ EMSG(_(e_dictreq));
+ return;
+ }
+ d = argvars[1].vval.v_dict;
+ if (d == NULL) {
+ return;
+ }
+
+ // third argument: action - 'a' for append and 'r' for replace.
+ // default is to replace the stack.
+ if (argvars[2].v_type == VAR_UNKNOWN) {
+ action = 'r';
+ } else if (argvars[2].v_type == VAR_STRING) {
+ const char *actstr;
+ actstr = tv_get_string_chk(&argvars[2]);
+ if (actstr == NULL) {
return;
}
-
- // third argument: action - 'a' for append and 'r' for replace.
- // default is to replace the stack.
- if (argvars[2].v_type == VAR_UNKNOWN) {
- action = 'r';
- } else if (argvars[2].v_type == VAR_STRING) {
- const char *actstr;
- actstr = tv_get_string_chk(&argvars[2]);
- if (actstr == NULL) {
- return;
- }
- if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't')
- && actstr[1] == NUL) {
- action = *actstr;
- } else {
- EMSG2(_(e_invact2), actstr);
- return;
- }
+ if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't')
+ && actstr[1] == NUL) {
+ action = *actstr;
} else {
- EMSG(_(e_stringreq));
- return;
+ EMSG2(_(e_invact2), actstr);
+ return;
}
+ } else {
+ EMSG(_(e_stringreq));
+ return;
+ }
- if (set_tagstack(wp, d, action) == OK) {
- rettv->vval.v_number = 0;
- }
+ if (set_tagstack(wp, d, action) == OK) {
+ rettv->vval.v_number = 0;
+ }
}
/*
@@ -8890,7 +9431,7 @@ static void f_setwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_sha256(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
const char *p = tv_get_string(&argvars[0]);
- const char *hash = sha256_bytes((const uint8_t *)p, strlen(p) , NULL, 0);
+ const char *hash = sha256_bytes((const uint8_t *)p, strlen(p), NULL, 0);
// make a copy of the hash (sha256_bytes returns a static buffer)
rettv->vval.v_string = (char_u *)xstrdup(hash);
@@ -8904,8 +9445,9 @@ static void f_shellescape(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
const bool do_special = non_zero_arg(&argvars[1]);
- rettv->vval.v_string = vim_strsave_shellescape(
- (const char_u *)tv_get_string(&argvars[0]), do_special, do_special);
+ rettv->vval.v_string = vim_strsave_shellescape((const char_u *)tv_get_string(
+ &argvars[0]), do_special,
+ do_special);
rettv->v_type = VAR_STRING;
}
@@ -8955,8 +9497,9 @@ static void f_sign_define(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- rettv->vval.v_number = sign_define_from_dict(
- name, argvars[1].v_type == VAR_DICT ? argvars[1].vval.v_dict : NULL);
+ rettv->vval.v_number = sign_define_from_dict(name,
+ argvars[1].v_type ==
+ VAR_DICT ? argvars[1].vval.v_dict : NULL);
}
/// "sign_getdefined()" function
@@ -9088,8 +9631,8 @@ static void f_sign_place(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- rettv->vval.v_number = sign_place_from_dict(
- &argvars[0], &argvars[1], &argvars[2], &argvars[3], dict);
+ rettv->vval.v_number = sign_place_from_dict(&argvars[0], &argvars[1], &argvars[2], &argvars[3],
+ dict);
}
/// "sign_placelist()" function. Place multiple signs.
@@ -9108,8 +9651,7 @@ static void f_sign_placelist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
TV_LIST_ITER_CONST(argvars[0].vval.v_list, li, {
sign_id = -1;
if (TV_LIST_ITEM_TV(li)->v_type == VAR_DICT) {
- sign_id = sign_place_from_dict(
- NULL, NULL, NULL, NULL, TV_LIST_ITEM_TV(li)->vval.v_dict);
+ sign_id = sign_place_from_dict(NULL, NULL, NULL, NULL, TV_LIST_ITEM_TV(li)->vval.v_dict);
} else {
EMSG(_(e_dictreq));
}
@@ -9378,7 +9920,6 @@ static int item_compare2(const void *s1, const void *s2, bool keep_zero)
int res;
typval_T rettv;
typval_T argv[3];
- int dummy;
const char *func_name;
partial_T *partial = sortinfo->item_compare_partial;
@@ -9402,10 +9943,11 @@ static int item_compare2(const void *s1, const void *s2, bool keep_zero)
tv_copy(TV_LIST_ITEM_TV(si2->item), &argv[1]);
rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this
- res = call_func((const char_u *)func_name,
- -1,
- &rettv, 2, argv, NULL, 0L, 0L, &dummy, true,
- partial, sortinfo->item_compare_selfdict);
+ funcexe_T funcexe = FUNCEXE_INIT;
+ funcexe.evaluate = true;
+ funcexe.partial = partial;
+ funcexe.selfdict = sortinfo->item_compare_selfdict;
+ res = call_func((const char_u *)func_name, -1, &rettv, 2, argv, &funcexe);
tv_clear(&argv[0]);
tv_clear(&argv[1]);
@@ -9445,7 +9987,7 @@ static int item_compare2_not_keeping_zero(const void *s1, const void *s2)
*/
static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)
{
- ListSortItem *ptrs;
+ ListSortItem *ptrs;
long len;
long i;
@@ -9632,7 +10174,7 @@ static void f_uniq(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
// "reltimefloat()" function
-static void f_reltimefloat(typval_T *argvars , typval_T *rettv, FunPtr fptr)
+static void f_reltimefloat(typval_T *argvars, typval_T *rettv, FunPtr fptr)
FUNC_ATTR_NONNULL_ALL
{
proftime_T tm;
@@ -9707,10 +10249,12 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, FunPtr fptr)
tv_list_append_string(rettv->vval.v_list, word, len);
tv_list_append_string(rettv->vval.v_list,
(attr == HLF_SPB ? "bad"
- : attr == HLF_SPR ? "rare"
- : attr == HLF_SPL ? "local"
- : attr == HLF_SPC ? "caps"
- : NULL), -1);
+ : attr == HLF_SPR ? "rare"
+ : attr == HLF_SPL ? "local"
+ : attr ==
+ HLF_SPC ? "caps"
+ :
+ NULL), -1);
}
/*
@@ -9767,7 +10311,7 @@ f_spellsuggest_return:
static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- char_u *save_cpo;
+ char_u *save_cpo;
int match;
colnr_T col = 0;
bool keepempty = false;
@@ -9904,7 +10448,7 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
int base = 10;
varnumber_T n;
- int what;
+ int what = 0;
if (argvars[1].v_type != VAR_UNKNOWN) {
base = tv_get_number(&argvars[1]);
@@ -9912,6 +10456,9 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
EMSG(_(e_invarg));
return;
}
+ if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2])) {
+ what |= STR2NR_QUOTE;
+ }
}
char_u *p = skipwhite((const char_u *)tv_get_string(&argvars[0]));
@@ -9920,23 +10467,18 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
p = skipwhite(p + 1);
}
switch (base) {
- case 2: {
- what = STR2NR_BIN | STR2NR_FORCE;
- break;
- }
- case 8: {
- what = STR2NR_OCT | STR2NR_FORCE;
- break;
- }
- case 16: {
- what = STR2NR_HEX | STR2NR_FORCE;
- break;
- }
- default: {
- what = 0;
- }
+ case 2:
+ what |= STR2NR_BIN | STR2NR_FORCE;
+ break;
+ case 8:
+ what |= STR2NR_OCT | STR2NR_OOCT | STR2NR_FORCE;
+ break;
+ case 16:
+ what |= STR2NR_HEX | STR2NR_FORCE;
+ break;
}
- vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
+ vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, false);
+ // Text after the number is silently ignored.
if (isneg) {
rettv->vval.v_number = -n;
} else {
@@ -9967,7 +10509,7 @@ static void f_strftime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
} else {
vimconv_T conv;
- char_u *enc;
+ char_u *enc;
conv.vc_type = CONV_NONE;
enc = enc_locale();
@@ -10312,7 +10854,7 @@ static void f_strridx(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_strtrans(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
rettv->v_type = VAR_STRING;
- rettv->vval.v_string = (char_u *)transstr(tv_get_string(&argvars[0]));
+ rettv->vval.v_string = (char_u *)transstr(tv_get_string(&argvars[0]), true);
}
/*
@@ -10443,53 +10985,46 @@ static void f_synIDattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
const char *p = NULL;
switch (TOLOWER_ASC(what[0])) {
- case 'b': {
- if (TOLOWER_ASC(what[1]) == 'g') { // bg[#]
- p = highlight_color(id, what, modec);
- } else { // bold
- p = highlight_has_attr(id, HL_BOLD, modec);
- }
- break;
- }
- case 'f': { // fg[#] or font
+ case 'b':
+ if (TOLOWER_ASC(what[1]) == 'g') { // bg[#]
p = highlight_color(id, what, modec);
- break;
- }
- case 'i': {
- if (TOLOWER_ASC(what[1]) == 'n') { // inverse
- p = highlight_has_attr(id, HL_INVERSE, modec);
- } else { // italic
- p = highlight_has_attr(id, HL_ITALIC, modec);
- }
- break;
+ } else { // bold
+ p = highlight_has_attr(id, HL_BOLD, modec);
}
- case 'n': { // name
- p = get_highlight_name_ext(NULL, id - 1, false);
- break;
- }
- case 'r': { // reverse
+ break;
+ case 'f': // fg[#] or font
+ p = highlight_color(id, what, modec);
+ break;
+ case 'i':
+ if (TOLOWER_ASC(what[1]) == 'n') { // inverse
p = highlight_has_attr(id, HL_INVERSE, modec);
- break;
+ } else { // italic
+ p = highlight_has_attr(id, HL_ITALIC, modec);
}
- case 's': {
- if (TOLOWER_ASC(what[1]) == 'p') { // sp[#]
- p = highlight_color(id, what, modec);
- } else if (TOLOWER_ASC(what[1]) == 't'
- && TOLOWER_ASC(what[2]) == 'r') { // strikethrough
- p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
- } else { // standout
- p = highlight_has_attr(id, HL_STANDOUT, modec);
- }
- break;
+ break;
+ case 'n': // name
+ p = get_highlight_name_ext(NULL, id - 1, false);
+ break;
+ case 'r': // reverse
+ p = highlight_has_attr(id, HL_INVERSE, modec);
+ break;
+ case 's':
+ if (TOLOWER_ASC(what[1]) == 'p') { // sp[#]
+ p = highlight_color(id, what, modec);
+ } else if (TOLOWER_ASC(what[1]) == 't'
+ && TOLOWER_ASC(what[2]) == 'r') { // strikethrough
+ p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
+ } else { // standout
+ p = highlight_has_attr(id, HL_STANDOUT, modec);
}
- case 'u': {
- if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c') { // underline
- p = highlight_has_attr(id, HL_UNDERLINE, modec);
- } else { // undercurl
- p = highlight_has_attr(id, HL_UNDERCURL, modec);
- }
- break;
+ break;
+ case 'u':
+ if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c') { // underline
+ p = highlight_has_attr(id, HL_UNDERLINE, modec);
+ } else { // undercurl
+ p = highlight_has_attr(id, HL_UNDERCURL, modec);
}
+ break;
}
rettv->v_type = VAR_STRING;
@@ -10599,7 +11134,7 @@ static void f_systemlist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- win_T *wp = NULL;
+ win_T *wp = NULL;
if (argvars[0].v_type == VAR_UNKNOWN) {
wp = firstwin;
@@ -10652,9 +11187,9 @@ static void f_tabpagenr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static int get_winnr(tabpage_T *tp, typval_T *argvar)
{
- win_T *twin;
+ win_T *twin;
int nr = 1;
- win_T *wp;
+ win_T *wp;
twin = (tp == curtab) ? curwin : tp->tp_curwin;
if (argvar->v_type != VAR_UNKNOWN) {
@@ -10700,7 +11235,7 @@ static int get_winnr(tabpage_T *tp, typval_T *argvar)
}
}
- if (nr > 0)
+ if (nr > 0) {
for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
wp != twin; wp = wp->w_next) {
if (wp == NULL) {
@@ -10710,6 +11245,7 @@ static int get_winnr(tabpage_T *tp, typval_T *argvar)
}
++nr;
}
+ }
return nr;
}
@@ -10849,10 +11385,11 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr)
const bool rpc = false;
const bool overlapped = false;
const bool detach = false;
+ ChannelStdinMode stdin_mode = kChannelStdinPipe;
uint16_t term_width = MAX(0, curwin->w_width_inner - win_col_off(curwin));
Channel *chan = channel_job_start(argv, on_stdout, on_stderr, on_exit,
- pty, rpc, overlapped, detach, cwd,
- term_width, curwin->w_height_inner,
+ pty, rpc, overlapped, detach, stdin_mode,
+ cwd, term_width, curwin->w_height_inner,
env, &rettv->vval.v_number);
if (rettv->vval.v_number <= 0) {
return;
@@ -10891,8 +11428,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
// "test_garbagecollect_now()" function
-static void f_test_garbagecollect_now(typval_T *argvars,
- typval_T *rettv, FunPtr fptr)
+static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
// This is dangerous, any Lists and Dicts used internally may be freed
// while still in use.
@@ -10900,9 +11436,7 @@ static void f_test_garbagecollect_now(typval_T *argvars,
}
// "test_write_list_log()" function
-static void f_test_write_list_log(typval_T *const argvars,
- typval_T *const rettv,
- FunPtr fptr)
+static void f_test_write_list_log(typval_T *const argvars, typval_T *const rettv, FunPtr fptr)
{
const char *const fname = tv_get_string_chk(&argvars[0]);
if (fname == NULL) {
@@ -10977,24 +11511,24 @@ static void f_timer_start(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
rettv->vval.v_number =
- timer_start(tv_get_number(&argvars[0]), repeat, &callback);
+ 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)
{
- if (argvars[0].v_type != VAR_NUMBER) {
- EMSG(_(e_number_exp));
- return;
- }
+ if (argvars[0].v_type != VAR_NUMBER) {
+ EMSG(_(e_number_exp));
+ return;
+ }
- timer_T *timer = find_timer_by_nr(tv_get_number(&argvars[0]));
- if (timer == NULL) {
- return;
- }
+ timer_T *timer = find_timer_by_nr(tv_get_number(&argvars[0]));
+ if (timer == NULL) {
+ return;
+ }
- timer_stop(timer);
+ timer_stop(timer);
}
static void f_timer_stopall(typval_T *argvars, typval_T *unused, FunPtr fptr)
@@ -11195,19 +11729,28 @@ static void f_type(typval_T *argvars, typval_T *rettv, FunPtr fptr)
int n = -1;
switch (argvars[0].v_type) {
- case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
- case VAR_STRING: n = VAR_TYPE_STRING; break;
- case VAR_PARTIAL:
- case VAR_FUNC: n = VAR_TYPE_FUNC; break;
- case VAR_LIST: n = VAR_TYPE_LIST; break;
- case VAR_DICT: n = VAR_TYPE_DICT; break;
- case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
- case VAR_BOOL: n = VAR_TYPE_BOOL; break;
- case VAR_SPECIAL:n = VAR_TYPE_SPECIAL; break;
- case VAR_UNKNOWN: {
- internal_error("f_type(UNKNOWN)");
- break;
- }
+ case VAR_NUMBER:
+ n = VAR_TYPE_NUMBER; break;
+ case VAR_STRING:
+ n = VAR_TYPE_STRING; break;
+ case VAR_PARTIAL:
+ case VAR_FUNC:
+ n = VAR_TYPE_FUNC; break;
+ case VAR_LIST:
+ n = VAR_TYPE_LIST; break;
+ case VAR_DICT:
+ n = VAR_TYPE_DICT; break;
+ case VAR_FLOAT:
+ n = VAR_TYPE_FLOAT; break;
+ case VAR_BOOL:
+ n = VAR_TYPE_BOOL; break;
+ case VAR_SPECIAL:
+ n = VAR_TYPE_SPECIAL; break;
+ case VAR_BLOB:
+ n = VAR_TYPE_BLOB; break;
+ case VAR_UNKNOWN:
+ internal_error("f_type(UNKNOWN)");
+ break;
}
rettv->vval.v_number = n;
}
@@ -11267,7 +11810,7 @@ static void f_values(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_virtcol(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
colnr_T vcol = 0;
- pos_T *fp;
+ pos_T *fp;
int fnum = curbuf->b_fnum;
fp = var2fpos(&argvars[0], FALSE, &fnum);
@@ -11352,6 +11895,9 @@ static void f_win_gettype(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_string = vim_strsave((char_u *)"popup");
} else if (wp == curwin && cmdwin_type != 0) {
rettv->vval.v_string = vim_strsave((char_u *)"command");
+ } else if (bt_quickfix(wp->w_buffer)) {
+ rettv->vval.v_string = vim_strsave((char_u *)(wp->w_llist_ref != NULL ?
+ "loclist" : "quickfix"));
}
}
@@ -11515,10 +12061,12 @@ static void f_winrestview(typval_T *argvars, typval_T *rettv, FunPtr fptr)
win_new_width(curwin, curwin->w_width);
changed_window_setting();
- if (curwin->w_topline <= 0)
+ if (curwin->w_topline <= 0) {
curwin->w_topline = 1;
- if (curwin->w_topline > curbuf->b_ml.ml_line_count)
+ }
+ if (curwin->w_topline > curbuf->b_ml.ml_line_count) {
curwin->w_topline = curbuf->b_ml.ml_line_count;
+ }
check_topfill(curwin, true);
}
}
@@ -11528,7 +12076,7 @@ static void f_winrestview(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_winsaveview(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- dict_T *dict;
+ dict_T *dict;
tv_dict_alloc_ret(rettv);
dict = rettv->vval.v_dict;
@@ -11579,16 +12127,17 @@ static void f_writefile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
- if (argvars[0].v_type != VAR_LIST) {
- EMSG2(_(e_listarg), "writefile()");
+ if (argvars[0].v_type == VAR_LIST) {
+ TV_LIST_ITER_CONST(argvars[0].vval.v_list, li, {
+ if (!tv_check_str_or_nr(TV_LIST_ITEM_TV(li))) {
+ return;
+ }
+ });
+ } else if (argvars[0].v_type != VAR_BLOB) {
+ EMSG2(_(e_invarg2),
+ _("writefile() first argument must be a List or a Blob"));
return;
}
- const list_T *const list = argvars[0].vval.v_list;
- TV_LIST_ITER_CONST(list, li, {
- if (!tv_check_str_or_nr(TV_LIST_ITEM_TV(li))) {
- return;
- }
- });
bool binary = false;
bool append = false;
@@ -11600,15 +12149,18 @@ static void f_writefile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
for (const char *p = flags; *p; p++) {
switch (*p) {
- case 'b': { binary = true; break; }
- case 'a': { append = true; break; }
- case 's': { do_fsync = true; break; }
- case 'S': { do_fsync = false; break; }
- default: {
- // Using %s, p and not %c, *p to preserve multibyte characters
- emsgf(_("E5060: Unknown flag: %s"), p);
- return;
- }
+ case 'b':
+ binary = true; break;
+ case 'a':
+ append = true; break;
+ case 's':
+ do_fsync = true; break;
+ case 'S':
+ do_fsync = false; break;
+ default:
+ // Using %s, p and not %c, *p to preserve multibyte characters
+ emsgf(_("E5060: Unknown flag: %s"), p);
+ return;
}
}
}
@@ -11628,7 +12180,13 @@ static void f_writefile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
emsgf(_("E482: Can't open file %s for writing: %s"),
fname, os_strerror(error));
} else {
- if (write_list(&fp, list, binary)) {
+ bool write_ok;
+ if (argvars[0].v_type == VAR_BLOB) {
+ write_ok = write_blob(&fp, argvars[0].vval.v_blob);
+ } else {
+ write_ok = write_list(&fp, argvars[0].vval.v_list, binary);
+ }
+ if (write_ok) {
rettv->vval.v_number = 0;
}
if ((error = file_close(&fp, do_fsync)) != 0) {
diff --git a/src/nvim/eval/funcs.h b/src/nvim/eval/funcs.h
index a343290734..c6a0cb959e 100644
--- a/src/nvim/eval/funcs.h
+++ b/src/nvim/eval/funcs.h
@@ -9,11 +9,16 @@ typedef void (*FunPtr)(void);
/// Prototype of C function that implements VimL function
typedef void (*VimLFunc)(typval_T *args, typval_T *rvar, FunPtr data);
+/// Special flags for base_arg @see VimLFuncDef
+#define BASE_NONE 0 ///< Not a method (no base argument).
+#define BASE_LAST UINT8_MAX ///< Use the last argument as the method base.
+
/// Structure holding VimL function definition
typedef struct fst {
char *name; ///< Name of the function.
uint8_t min_argc; ///< Minimal number of arguments.
uint8_t max_argc; ///< Maximal number of arguments.
+ uint8_t base_arg; ///< Method base arg # (1-indexed), BASE_NONE or BASE_LAST.
VimLFunc func; ///< Function implementation.
FunPtr data; ///< Userdata for function implementation.
} VimLFuncDef;
diff --git a/src/nvim/eval/gc.c b/src/nvim/eval/gc.c
index 2bbf78d827..633e6abacf 100644
--- a/src/nvim/eval/gc.c
+++ b/src/nvim/eval/gc.c
@@ -1,8 +1,8 @@
// 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/eval/typval.h"
#include "nvim/eval/gc.h"
+#include "nvim/eval/typval.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/gc.c.generated.h"
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
index 7221dc8bc9..075b50a366 100644
--- a/src/nvim/eval/typval.c
+++ b/src/nvim/eval/typval.c
@@ -1,36 +1,36 @@
// 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 <stdio.h>
+#include <assert.h>
+#include <stdbool.h>
#include <stddef.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <assert.h>
-#include <stdbool.h>
-#include "nvim/lib/queue.h"
-#include "nvim/eval/typval.h"
-#include "nvim/eval/gc.h"
-#include "nvim/eval/executor.h"
+#include "nvim/ascii.h"
+#include "nvim/assert.h"
+#include "nvim/charset.h"
+#include "nvim/eval.h"
#include "nvim/eval/encode.h"
+#include "nvim/eval/executor.h"
+#include "nvim/eval/gc.h"
+#include "nvim/eval/typval.h"
#include "nvim/eval/typval_encode.h"
-#include "nvim/eval.h"
#include "nvim/eval/userfunc.h"
-#include "nvim/lua/executor.h"
-#include "nvim/types.h"
-#include "nvim/assert.h"
-#include "nvim/memory.h"
-#include "nvim/globals.h"
-#include "nvim/hashtab.h"
-#include "nvim/vim.h"
-#include "nvim/ascii.h"
-#include "nvim/pos.h"
-#include "nvim/charset.h"
#include "nvim/garray.h"
#include "nvim/gettext.h"
+#include "nvim/globals.h"
+#include "nvim/hashtab.h"
+#include "nvim/lib/queue.h"
+#include "nvim/lua/executor.h"
#include "nvim/macros.h"
#include "nvim/mbyte.h"
+#include "nvim/memory.h"
#include "nvim/message.h"
+#include "nvim/pos.h"
+#include "nvim/types.h"
+#include "nvim/vim.h"
// TODO(ZyX-I): Move line_breakcheck out of misc1
#include "nvim/misc1.h" // For line_breakcheck
#include "nvim/os/fileio.h"
@@ -71,11 +71,11 @@ void list_write_log(const char *const fname)
char buf[10 + 1 + ((16 + 3) * 3) + (8 + 2) + 2];
// act : hex " c:" len "[]" "\n\0"
const ListLogEntry entry = chunk->entries[i];
- const size_t snp_len = (size_t)snprintf(
- buf, sizeof(buf),
- "%-10.10s: l:%016" PRIxPTR "[%08d] 1:%016" PRIxPTR " 2:%016" PRIxPTR
- "\n",
- entry.action, entry.l, entry.len, entry.li1, entry.li2);
+ const size_t snp_len = (size_t)snprintf(buf, sizeof(buf),
+ "%-10.10s: l:%016" PRIxPTR "[%08d] 1:%016" PRIxPTR " 2:%016" PRIxPTR
+ "\n",
+ entry.action, entry.l, entry.len, entry.li1,
+ entry.li2);
assert(snp_len + 1 == sizeof(buf));
const ptrdiff_t fw_ret = file_write(&fp, buf, snp_len);
if (fw_ret != (ptrdiff_t)snp_len) {
@@ -100,7 +100,7 @@ void list_write_log(const char *const fname)
}
}
-#ifdef EXITFREE
+# ifdef EXITFREE
/// Free list log
void list_free_log(void)
{
@@ -110,7 +110,7 @@ void list_free_log(void)
chunk = list_log_first;
}
}
-#endif
+# endif
#endif
//{{{2 List item
@@ -343,8 +343,7 @@ void tv_list_unref(list_T *const l)
/// @param[out] l List to remove from.
/// @param[in] item First item to remove.
/// @param[in] item2 Last item to remove.
-void tv_list_drop_items(list_T *const l, listitem_T *const item,
- listitem_T *const item2)
+void tv_list_drop_items(list_T *const l, listitem_T *const item, listitem_T *const item2)
FUNC_ATTR_NONNULL_ALL
{
list_log(l, item, item2, "drop");
@@ -369,8 +368,7 @@ void tv_list_drop_items(list_T *const l, listitem_T *const item,
}
/// Like tv_list_drop_items, but also frees all removed items
-void tv_list_remove_items(list_T *const l, listitem_T *const item,
- listitem_T *const item2)
+void tv_list_remove_items(list_T *const l, listitem_T *const item, listitem_T *const item2)
FUNC_ATTR_NONNULL_ALL
{
list_log(l, item, item2, "remove");
@@ -393,9 +391,8 @@ void tv_list_remove_items(list_T *const l, listitem_T *const item,
/// @param[in] item2 Last item to move.
/// @param[out] tgt_l List to move to.
/// @param[in] cnt Number of items moved.
-void tv_list_move_items(list_T *const l, listitem_T *const item,
- listitem_T *const item2, list_T *const tgt_l,
- const int cnt)
+void tv_list_move_items(list_T *const l, listitem_T *const item, listitem_T *const item2,
+ list_T *const tgt_l, const int cnt)
FUNC_ATTR_NONNULL_ALL
{
list_log(l, item, item2, "move");
@@ -418,8 +415,7 @@ void tv_list_move_items(list_T *const l, listitem_T *const item,
/// @param[in,out] ni Item to insert.
/// @param[in] item Item to insert before. If NULL, inserts at the end of the
/// list.
-void tv_list_insert(list_T *const l, listitem_T *const ni,
- listitem_T *const item)
+void tv_list_insert(list_T *const l, listitem_T *const ni, listitem_T *const item)
FUNC_ATTR_NONNULL_ARG(1, 2)
{
if (item == NULL) {
@@ -449,8 +445,7 @@ void tv_list_insert(list_T *const l, listitem_T *const ni,
/// allocated listitem_T and inserted.
/// @param[in] item Item to insert before. If NULL, inserts at the end of the
/// list.
-void tv_list_insert_tv(list_T *const l, typval_T *const tv,
- listitem_T *const item)
+void tv_list_insert_tv(list_T *const l, typval_T *const tv, listitem_T *const item)
{
listitem_T *const ni = tv_list_item_alloc();
@@ -544,8 +539,7 @@ void tv_list_append_dict(list_T *const l, dict_T *const dict)
/// @param[in] len Length of the appended string. May be -1, in this
/// case string is considered to be usual zero-terminated
/// string or NULL “empty” string.
-void tv_list_append_string(list_T *const l, const char *const str,
- const ssize_t len)
+void tv_list_append_string(list_T *const l, const char *const str, const ssize_t len)
FUNC_ATTR_NONNULL_ARG(1)
{
tv_list_append_owned_tv(l, (typval_T) {
@@ -601,8 +595,8 @@ void tv_list_append_number(list_T *const l, const varnumber_T n)
///
/// @return Copied list. May be NULL in case original list is NULL or some
/// failure happens. The refcount of the new list is set to 1.
-list_T *tv_list_copy(const vimconv_T *const conv, list_T *const orig,
- const bool deep, const int copyID)
+list_T *tv_list_copy(const vimconv_T *const conv, list_T *const orig, const bool deep,
+ const int copyID)
FUNC_ATTR_WARN_UNUSED_RESULT
{
if (orig == NULL) {
@@ -697,8 +691,7 @@ int tv_list_flatten(list_T *list, long maxdepth)
/// @param[out] l1 List to extend.
/// @param[in] l2 List to extend with.
/// @param[in] bef If not NULL, extends before this item.
-void tv_list_extend(list_T *const l1, list_T *const l2,
- listitem_T *const bef)
+void tv_list_extend(list_T *const l1, list_T *const l2, listitem_T *const bef)
FUNC_ATTR_NONNULL_ARG(1)
{
int todo = tv_list_len(l2);
@@ -758,8 +751,8 @@ typedef struct {
/// @param[in] join_gap Garray to keep each list item string.
///
/// @return OK in case of success, FAIL otherwise.
-static int list_join_inner(garray_T *const gap, list_T *const l,
- const char *const sep, garray_T *const join_gap)
+static int list_join_inner(garray_T *const gap, list_T *const l, const char *const sep,
+ garray_T *const join_gap)
FUNC_ATTR_NONNULL_ALL
{
size_t sumlen = 0;
@@ -836,7 +829,7 @@ int tv_list_join(garray_T *const gap, list_T *const l, const char *const sep)
return retval;
}
-/// Chech whether two lists are equal
+/// Check whether two lists are equal
///
/// @param[in] l1 First list to compare.
/// @param[in] l2 Second list to compare.
@@ -844,8 +837,7 @@ int tv_list_join(garray_T *const gap, list_T *const l, const char *const sep)
/// @param[in] recursive True when used recursively.
///
/// @return True if lists are equal, false otherwise.
-bool tv_list_equal(list_T *const l1, list_T *const l2, const bool ic,
- const bool recursive)
+bool tv_list_equal(list_T *const l1, list_T *const l2, const bool ic, const bool recursive)
FUNC_ATTR_WARN_UNUSED_RESULT
{
if (l1 == l2) {
@@ -915,8 +907,7 @@ void tv_list_reverse(list_T *const l)
/// true list will not be modified. Must be initialized to false
/// by the caller.
void tv_list_item_sort(list_T *const l, ListSortItem *const ptrs,
- const ListSorter item_compare_func,
- bool *errp)
+ const ListSorter item_compare_func, bool *errp)
FUNC_ATTR_NONNULL_ARG(3, 4)
{
const int len = tv_list_len(l);
@@ -968,7 +959,7 @@ listitem_T *tv_list_find(list_T *const l, int n)
}
int idx;
- listitem_T *item;
+ listitem_T *item;
// When there is a cached index may start search from there.
if (l->lv_idx_item != NULL) {
@@ -1127,17 +1118,14 @@ bool tv_callback_equal(const Callback *cb1, const Callback *cb2)
return false;
}
switch (cb1->type) {
- case kCallbackFuncref: {
- return STRCMP(cb1->data.funcref, cb2->data.funcref) == 0;
- }
- case kCallbackPartial: {
- // FIXME: this is inconsistent with tv_equal but is needed for precision
- // maybe change dictwatcheradd to return a watcher id instead?
- return cb1->data.partial == cb2->data.partial;
- }
- case kCallbackNone: {
- return true;
- }
+ case kCallbackFuncref:
+ return STRCMP(cb1->data.funcref, cb2->data.funcref) == 0;
+ case kCallbackPartial:
+ // FIXME: this is inconsistent with tv_equal but is needed for precision
+ // maybe change dictwatcheradd to return a watcher id instead?
+ return cb1->data.partial == cb2->data.partial;
+ case kCallbackNone:
+ return true;
}
abort();
return false;
@@ -1148,18 +1136,15 @@ void callback_free(Callback *callback)
FUNC_ATTR_NONNULL_ALL
{
switch (callback->type) {
- case kCallbackFuncref: {
- func_unref(callback->data.funcref);
- xfree(callback->data.funcref);
- break;
- }
- case kCallbackPartial: {
- partial_unref(callback->data.partial);
- break;
- }
- case kCallbackNone: {
- break;
- }
+ case kCallbackFuncref:
+ func_unref(callback->data.funcref);
+ xfree(callback->data.funcref);
+ break;
+ case kCallbackPartial:
+ partial_unref(callback->data.partial);
+ break;
+ case kCallbackNone:
+ break;
}
callback->type = kCallbackNone;
callback->data.funcref = NULL;
@@ -1170,20 +1155,20 @@ void callback_put(Callback *cb, typval_T *tv)
FUNC_ATTR_NONNULL_ALL
{
switch (cb->type) {
- case kCallbackPartial:
- tv->v_type = VAR_PARTIAL;
- tv->vval.v_partial = cb->data.partial;
- cb->data.partial->pt_refcount++;
- break;
- case kCallbackFuncref:
- tv->v_type = VAR_FUNC;
- tv->vval.v_string = vim_strsave(cb->data.funcref);
- func_ref(cb->data.funcref);
- break;
- default:
- tv->v_type = VAR_SPECIAL;
- tv->vval.v_special = kSpecialVarNull;
- break;
+ case kCallbackPartial:
+ tv->v_type = VAR_PARTIAL;
+ tv->vval.v_partial = cb->data.partial;
+ cb->data.partial->pt_refcount++;
+ break;
+ case kCallbackFuncref:
+ tv->v_type = VAR_FUNC;
+ tv->vval.v_string = vim_strsave(cb->data.funcref);
+ func_ref(cb->data.funcref);
+ break;
+ default:
+ tv->v_type = VAR_SPECIAL;
+ tv->vval.v_special = kSpecialVarNull;
+ break;
}
}
@@ -1193,17 +1178,17 @@ void callback_copy(Callback *dest, Callback *src)
{
dest->type = src->type;
switch (src->type) {
- case kCallbackPartial:
- dest->data.partial = src->data.partial;
- dest->data.partial->pt_refcount++;
- break;
- case kCallbackFuncref:
- dest->data.funcref = vim_strsave(src->data.funcref);
- func_ref(src->data.funcref);
- break;
- default:
- dest->data.funcref = NULL;
- break;
+ case kCallbackPartial:
+ dest->data.partial = src->data.partial;
+ dest->data.partial->pt_refcount++;
+ break;
+ case kCallbackFuncref:
+ dest->data.funcref = vim_strsave(src->data.funcref);
+ func_ref(src->data.funcref);
+ break;
+ default:
+ dest->data.funcref = NULL;
+ break;
}
}
@@ -1216,8 +1201,7 @@ void callback_copy(Callback *dest, Callback *src)
///
/// @return True on success, false if relevant watcher was not found.
bool tv_dict_watcher_remove(dict_T *const dict, const char *const key_pattern,
- const size_t key_pattern_len,
- Callback callback)
+ const size_t key_pattern_len, Callback callback)
FUNC_ATTR_NONNULL_ARG(2)
{
if (dict == NULL) {
@@ -1280,8 +1264,8 @@ static bool tv_dict_watcher_matches(DictWatcher *watcher, const char *const key)
/// @param[in] key Key which was modified.
/// @param[in] newtv New key value.
/// @param[in] oldtv Old key value.
-void tv_dict_watcher_notify(dict_T *const dict, const char *const key,
- typval_T *const newtv, typval_T *const oldtv)
+void tv_dict_watcher_notify(dict_T *const dict, const char *const key, typval_T *const newtv,
+ typval_T *const oldtv)
FUNC_ATTR_NONNULL_ARG(1, 2)
{
typval_T argv[3];
@@ -1540,8 +1524,7 @@ void tv_dict_unref(dict_T *const d)
/// @param[in] len Key length. If negative, then strlen(key) is used.
///
/// @return found item or NULL if nothing was found.
-dictitem_T *tv_dict_find(const dict_T *const d, const char *const key,
- const ptrdiff_t len)
+dictitem_T *tv_dict_find(const dict_T *const d, const char *const key, const ptrdiff_t len)
FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
if (d == NULL) {
@@ -1628,8 +1611,7 @@ char **tv_dict_to_env(dict_T *denv)
/// @return NULL if key does not exist, empty string in case of type error,
/// string item value otherwise. If returned value is not NULL, it may
/// be allocated depending on `save` argument.
-char *tv_dict_get_string(const dict_T *const d, const char *const key,
- const bool save)
+char *tv_dict_get_string(const dict_T *const d, const char *const key, const bool save)
FUNC_ATTR_WARN_UNUSED_RESULT
{
static char numbuf[NUMBUFLEN];
@@ -1649,8 +1631,7 @@ char *tv_dict_get_string(const dict_T *const d, const char *const key,
///
/// @return NULL if key does not exist, empty string in case of type error,
/// string item value otherwise.
-const char *tv_dict_get_string_buf(const dict_T *const d, const char *const key,
- char *const numbuf)
+const char *tv_dict_get_string_buf(const dict_T *const d, const char *const key, char *const numbuf)
FUNC_ATTR_WARN_UNUSED_RESULT
{
const dictitem_T *const di = tv_dict_find(d, key, -1);
@@ -1672,10 +1653,8 @@ const char *tv_dict_get_string_buf(const dict_T *const d, const char *const key,
/// @return `def` when key does not exist,
/// NULL in case of type error,
/// string item value in case of success.
-const char *tv_dict_get_string_buf_chk(const dict_T *const d,
- const char *const key,
- const ptrdiff_t key_len,
- char *const numbuf,
+const char *tv_dict_get_string_buf_chk(const dict_T *const d, const char *const key,
+ const ptrdiff_t key_len, char *const numbuf,
const char *const def)
FUNC_ATTR_WARN_UNUSED_RESULT
{
@@ -1695,8 +1674,7 @@ const char *tv_dict_get_string_buf_chk(const dict_T *const d,
/// will be left.
///
/// @return true/false on success/failure.
-bool tv_dict_get_callback(dict_T *const d,
- const char *const key, const ptrdiff_t key_len,
+bool tv_dict_get_callback(dict_T *const d, const char *const key, const ptrdiff_t key_len,
Callback *const result)
FUNC_ATTR_NONNULL_ARG(2, 4) FUNC_ATTR_WARN_UNUSED_RESULT
{
@@ -1743,8 +1721,8 @@ int tv_dict_add(dict_T *const d, dictitem_T *const item)
/// @param list List to add. Will have reference count incremented.
///
/// @return OK in case of success, FAIL when key already exists.
-int tv_dict_add_list(dict_T *const d, const char *const key,
- const size_t key_len, list_T *const list)
+int tv_dict_add_list(dict_T *const d, const char *const key, const size_t key_len,
+ list_T *const list)
FUNC_ATTR_NONNULL_ALL
{
dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
@@ -1766,15 +1744,14 @@ int tv_dict_add_list(dict_T *const d, const char *const key,
/// @param[in] key_len Key length.
///
/// @return FAIL if out of memory or key already exists.
-int tv_dict_add_tv(dict_T *d, const char *key, const size_t key_len,
- typval_T *tv)
+int tv_dict_add_tv(dict_T *d, const char *key, const size_t key_len, typval_T *tv)
{
dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
tv_copy(tv, &item->di_tv);
if (tv_dict_add(d, item) == FAIL) {
- tv_dict_item_free(item);
- return FAIL;
+ tv_dict_item_free(item);
+ return FAIL;
}
return OK;
}
@@ -1787,8 +1764,8 @@ int tv_dict_add_tv(dict_T *d, const char *key, const size_t key_len,
/// @param dict Dictionary to add. Will have reference count incremented.
///
/// @return OK in case of success, FAIL when key already exists.
-int tv_dict_add_dict(dict_T *const d, const char *const key,
- const size_t key_len, dict_T *const dict)
+int tv_dict_add_dict(dict_T *const d, const char *const key, const size_t key_len,
+ dict_T *const dict)
FUNC_ATTR_NONNULL_ALL
{
dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
@@ -1811,8 +1788,8 @@ int tv_dict_add_dict(dict_T *const d, const char *const key,
/// @param[in] nr Number to add.
///
/// @return OK in case of success, FAIL when key already exists.
-int tv_dict_add_nr(dict_T *const d, const char *const key,
- const size_t key_len, const varnumber_T nr)
+int tv_dict_add_nr(dict_T *const d, const char *const key, const size_t key_len,
+ const varnumber_T nr)
{
dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
@@ -1833,8 +1810,8 @@ int tv_dict_add_nr(dict_T *const d, const char *const key,
/// @param[in] nr Floating point number to add.
///
/// @return OK in case of success, FAIL when key already exists.
-int tv_dict_add_float(dict_T *const d, const char *const key,
- const size_t key_len, const float_T nr)
+int tv_dict_add_float(dict_T *const d, const char *const key, const size_t key_len,
+ const float_T nr)
{
dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
@@ -1855,8 +1832,7 @@ int tv_dict_add_float(dict_T *const d, const char *const key,
/// @param[in] val BoolVarValue to add.
///
/// @return OK in case of success, FAIL when key already exists.
-int tv_dict_add_bool(dict_T *const d, const char *const key,
- const size_t key_len, BoolVarValue val)
+int tv_dict_add_bool(dict_T *const d, const char *const key, const size_t key_len, BoolVarValue val)
{
dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
@@ -1872,8 +1848,7 @@ int tv_dict_add_bool(dict_T *const d, const char *const key,
/// Add a string entry to dictionary
///
/// @see tv_dict_add_allocated_str
-int tv_dict_add_str(dict_T *const d,
- const char *const key, const size_t key_len,
+int tv_dict_add_str(dict_T *const d, const char *const key, const size_t key_len,
const char *const val)
FUNC_ATTR_NONNULL_ARG(1, 2)
{
@@ -1889,8 +1864,7 @@ int tv_dict_add_str(dict_T *const d,
/// @param[in] len Use this many bytes from `val`, or -1 for whole string.
///
/// @return OK in case of success, FAIL when key already exists.
-int tv_dict_add_str_len(dict_T *const d,
- const char *const key, const size_t key_len,
+int tv_dict_add_str_len(dict_T *const d, const char *const key, const size_t key_len,
const char *const val, int len)
FUNC_ATTR_NONNULL_ARG(1, 2)
{
@@ -1914,8 +1888,7 @@ int tv_dict_add_str_len(dict_T *const d,
/// @param[in] val String to add.
///
/// @return OK in case of success, FAIL when key already exists.
-int tv_dict_add_allocated_str(dict_T *const d,
- const char *const key, const size_t key_len,
+int tv_dict_add_allocated_str(dict_T *const d, const char *const key, const size_t key_len,
char *const val)
FUNC_ATTR_NONNULL_ARG(1, 2)
{
@@ -1958,8 +1931,7 @@ void tv_dict_clear(dict_T *const d)
/// e*, including "error": duplicate key gives an error.
/// f*, including "force": duplicate d2 keys override d1.
/// other, including "keep": duplicate d2 keys ignored.
-void tv_dict_extend(dict_T *const d1, dict_T *const d2,
- const char *const action)
+void tv_dict_extend(dict_T *const d1, dict_T *const d2, const char *const action)
FUNC_ATTR_NONNULL_ALL
{
const bool watched = tv_dict_is_watched(d1);
@@ -2021,8 +1993,7 @@ void tv_dict_extend(dict_T *const d1, dict_T *const d2,
/// @param[in] d2 Second dictionary.
/// @param[in] ic True if case is to be ignored.
/// @param[in] recursive True when used recursively.
-bool tv_dict_equal(dict_T *const d1, dict_T *const d2,
- const bool ic, const bool recursive)
+bool tv_dict_equal(dict_T *const d1, dict_T *const d2, const bool ic, const bool recursive)
FUNC_ATTR_WARN_UNUSED_RESULT
{
if (d1 == d2) {
@@ -2057,9 +2028,7 @@ bool tv_dict_equal(dict_T *const d1, dict_T *const d2,
/// @return Copied dictionary. May be NULL in case original dictionary is NULL
/// or some failure happens. The refcount of the new dictionary is set
/// to 1.
-dict_T *tv_dict_copy(const vimconv_T *const conv,
- dict_T *const orig,
- const bool deep,
+dict_T *tv_dict_copy(const vimconv_T *const conv, dict_T *const orig, const bool deep,
const int copyID)
{
if (orig == NULL) {
@@ -2125,6 +2094,77 @@ void tv_dict_set_keys_readonly(dict_T *const dict)
});
}
+//{{{1 Blobs
+//{{{2 Alloc/free
+
+/// Allocate an empty blob.
+///
+/// Caller should take care of the reference count.
+///
+/// @return [allocated] new blob.
+blob_T *tv_blob_alloc(void)
+ FUNC_ATTR_NONNULL_RET
+{
+ blob_T *const blob = xcalloc(1, sizeof(blob_T));
+ ga_init(&blob->bv_ga, 1, 100);
+ return blob;
+}
+
+/// Free a blob. Ignores the reference count.
+///
+/// @param[in,out] b Blob to free.
+void tv_blob_free(blob_T *const b)
+ FUNC_ATTR_NONNULL_ALL
+{
+ ga_clear(&b->bv_ga);
+ xfree(b);
+}
+
+/// Unreference a blob.
+///
+/// Decrements the reference count and frees blob when it becomes zero.
+///
+/// @param[in,out] b Blob to operate on.
+void tv_blob_unref(blob_T *const b)
+{
+ if (b != NULL && --b->bv_refcount <= 0) {
+ tv_blob_free(b);
+ }
+}
+
+//{{{2 Operations on the whole blob
+
+/// Check whether two blobs are equal.
+///
+/// @param[in] b1 First blob.
+/// @param[in] b2 Second blob.
+///
+/// @return true if blobs are equal, false otherwise.
+bool tv_blob_equal(const blob_T *const b1, const blob_T *const b2)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ const int len1 = tv_blob_len(b1);
+ const int len2 = tv_blob_len(b2);
+
+ // empty and NULL are considered the same
+ if (len1 == 0 && len2 == 0) {
+ return true;
+ }
+ if (b1 == b2) {
+ return true;
+ }
+ if (len1 != len2) {
+ return false;
+ }
+
+ for (int i = 0; i < b1->bv_ga.ga_len; i++) {
+ if (tv_blob_get(b1, i) != tv_blob_get(b2, i)) {
+ return false;
+ }
+ }
+ return true;
+}
+
//{{{1 Generic typval operations
//{{{2 Init/alloc/clear
//{{{3 Alloc
@@ -2169,49 +2209,93 @@ void tv_dict_alloc_ret(typval_T *const ret_tv)
tv_dict_set_ret(ret_tv, d);
}
+/// Allocate an empty blob for a return value.
+///
+/// Also sets reference count.
+///
+/// @param[out] ret_tv Structure where blob is saved.
+void tv_blob_alloc_ret(typval_T *const ret_tv)
+ FUNC_ATTR_NONNULL_ALL
+{
+ blob_T *const b = tv_blob_alloc();
+ tv_blob_set_ret(ret_tv, b);
+}
+
+/// Copy a blob typval to a different typval.
+///
+/// @param[in] from Blob object to copy from.
+/// @param[out] to Blob object to copy to.
+void tv_blob_copy(typval_T *const from, typval_T *const to)
+ FUNC_ATTR_NONNULL_ALL
+{
+ assert(from->v_type == VAR_BLOB);
+
+ to->v_type = VAR_BLOB;
+ to->v_lock = VAR_UNLOCKED;
+ if (from->vval.v_blob == NULL) {
+ to->vval.v_blob = NULL;
+ } else {
+ tv_blob_alloc_ret(to);
+ int len = from->vval.v_blob->bv_ga.ga_len;
+
+ if (len > 0) {
+ to->vval.v_blob->bv_ga.ga_data
+ = xmemdup(from->vval.v_blob->bv_ga.ga_data, (size_t)len);
+ }
+ to->vval.v_blob->bv_ga.ga_len = len;
+ to->vval.v_blob->bv_ga.ga_maxlen = len;
+ }
+}
+
//{{{3 Clear
#define TYPVAL_ENCODE_ALLOW_SPECIALS false
#define TYPVAL_ENCODE_CONV_NIL(tv) \
- do { \
- tv->vval.v_special = kSpecialVarNull; \
- tv->v_lock = VAR_UNLOCKED; \
- } while (0)
+ do { \
+ 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; \
- } while (0)
+ do { \
+ 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; \
- } while (0)
+ do { \
+ (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; \
- } while (0)
+ do { \
+ 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; \
- } while (0)
+ do { \
+ xfree(buf); \
+ tv->vval.v_string = NULL; \
+ tv->v_lock = VAR_UNLOCKED; \
+ } while (0)
#define TYPVAL_ENCODE_CONV_STR_STRING(tv, buf, len)
#define TYPVAL_ENCODE_CONV_EXT_STRING(tv, buf, len, type)
-static inline int _nothing_conv_func_start(typval_T *const tv,
- char_u *const fun)
+#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; \
+ } while (0)
+
+static inline int _nothing_conv_func_start(typval_T *const tv, char_u *const fun)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ARG(1)
{
tv->v_lock = VAR_UNLOCKED;
@@ -2232,11 +2316,11 @@ static inline int _nothing_conv_func_start(typval_T *const tv,
return NOTDONE;
}
#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \
- do { \
- if (_nothing_conv_func_start(tv, fun) != NOTDONE) { \
- return OK; \
- } \
- } while (0)
+ do { \
+ if (_nothing_conv_func_start(tv, fun) != NOTDONE) { \
+ return OK; \
+ } \
+ } while (0)
#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(tv, len)
#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(tv, len)
@@ -2264,14 +2348,13 @@ static inline void _nothing_conv_func_end(typval_T *const tv, const int copyID)
#define TYPVAL_ENCODE_CONV_FUNC_END(tv) _nothing_conv_func_end(tv, 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; \
- } while (0)
-
-static inline void _nothing_conv_empty_dict(typval_T *const tv,
- dict_T **const dictp)
+ do { \
+ 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)
FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ARG(2)
{
tv_dict_unref(*dictp);
@@ -2281,13 +2364,13 @@ static inline void _nothing_conv_empty_dict(typval_T *const tv,
}
}
#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)); \
- } while (0)
+ do { \
+ 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, MPConvStackVal *const mpsv)
+static inline int _nothing_conv_real_list_after_start(typval_T *const tv,
+ MPConvStackVal *const mpsv)
FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_WARN_UNUSED_RESULT
{
assert(tv != NULL);
@@ -2303,11 +2386,11 @@ static inline int _nothing_conv_real_list_after_start(
#define TYPVAL_ENCODE_CONV_LIST_START(tv, len)
#define TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START(tv, mpsv) \
- do { \
- if (_nothing_conv_real_list_after_start(tv, &mpsv) != NOTDONE) { \
- goto typval_encode_stop_converting_one_item; \
- } \
- } while (0)
+ do { \
+ if (_nothing_conv_real_list_after_start(tv, &mpsv) != NOTDONE) { \
+ goto typval_encode_stop_converting_one_item; \
+ } \
+ } while (0)
#define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(tv)
@@ -2324,9 +2407,9 @@ static inline void _nothing_conv_list_end(typval_T *const tv)
}
#define TYPVAL_ENCODE_CONV_LIST_END(tv) _nothing_conv_list_end(tv)
-static inline int _nothing_conv_real_dict_after_start(
- typval_T *const tv, dict_T **const dictp, const void *const nodictvar,
- MPConvStackVal *const mpsv)
+static inline int _nothing_conv_real_dict_after_start(typval_T *const tv, dict_T **const dictp,
+ const void *const nodictvar,
+ MPConvStackVal *const mpsv)
FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_WARN_UNUSED_RESULT
{
if (tv != NULL) {
@@ -2343,20 +2426,18 @@ static inline int _nothing_conv_real_dict_after_start(
#define TYPVAL_ENCODE_CONV_DICT_START(tv, dict, len)
#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) { \
- goto typval_encode_stop_converting_one_item; \
- } \
- } while (0)
+ do { \
+ 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)
#define TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK(tv, dict)
#define TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(tv, dict)
#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(tv, dict)
-static inline void _nothing_conv_dict_end(typval_T *const tv,
- dict_T **const dictp,
+static inline void _nothing_conv_dict_end(typval_T *const tv, dict_T **const dictp,
const void *const nodictvar)
FUNC_ATTR_ALWAYS_INLINE
{
@@ -2366,8 +2447,8 @@ static inline void _nothing_conv_dict_end(typval_T *const tv,
}
}
#define TYPVAL_ENCODE_CONV_DICT_END(tv, dict) \
- _nothing_conv_dict_end(tv, (dict_T **)&dict, \
- (void *)&TYPVAL_ENCODE_NODICT_VAR)
+ _nothing_conv_dict_end(tv, (dict_T **)&dict, \
+ (void *)&TYPVAL_ENCODE_NODICT_VAR)
#define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type)
@@ -2392,6 +2473,7 @@ static inline void _nothing_conv_dict_end(typval_T *const tv,
#undef TYPVAL_ENCODE_CONV_STRING
#undef TYPVAL_ENCODE_CONV_STR_STRING
#undef TYPVAL_ENCODE_CONV_EXT_STRING
+#undef TYPVAL_ENCODE_CONV_BLOB
#undef TYPVAL_ENCODE_CONV_FUNC_START
#undef TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS
#undef TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF
@@ -2437,33 +2519,30 @@ void tv_free(typval_T *tv)
{
if (tv != NULL) {
switch (tv->v_type) {
- case VAR_PARTIAL: {
- partial_unref(tv->vval.v_partial);
- break;
- }
- case VAR_FUNC: {
- func_unref(tv->vval.v_string);
- FALLTHROUGH;
- }
- case VAR_STRING: {
- xfree(tv->vval.v_string);
- break;
- }
- case VAR_LIST: {
- tv_list_unref(tv->vval.v_list);
- break;
- }
- case VAR_DICT: {
- tv_dict_unref(tv->vval.v_dict);
- break;
- }
- case VAR_BOOL:
- case VAR_SPECIAL:
- case VAR_NUMBER:
- case VAR_FLOAT:
- case VAR_UNKNOWN: {
- break;
- }
+ case VAR_PARTIAL:
+ partial_unref(tv->vval.v_partial);
+ break;
+ case VAR_FUNC:
+ func_unref(tv->vval.v_string);
+ FALLTHROUGH;
+ case VAR_STRING:
+ xfree(tv->vval.v_string);
+ break;
+ case VAR_BLOB:
+ tv_blob_unref(tv->vval.v_blob);
+ break;
+ case VAR_LIST:
+ tv_list_unref(tv->vval.v_list);
+ break;
+ case VAR_DICT:
+ tv_dict_unref(tv->vval.v_dict);
+ break;
+ case VAR_BOOL:
+ case VAR_SPECIAL:
+ case VAR_NUMBER:
+ case VAR_FLOAT:
+ case VAR_UNKNOWN:
+ break;
}
xfree(tv);
}
@@ -2487,42 +2566,41 @@ void tv_copy(const typval_T *const from, typval_T *const to)
to->v_lock = VAR_UNLOCKED;
memmove(&to->vval, &from->vval, sizeof(to->vval));
switch (from->v_type) {
- case VAR_NUMBER:
- case VAR_FLOAT:
- case VAR_BOOL:
- case VAR_SPECIAL: {
- break;
- }
- case VAR_STRING:
- case VAR_FUNC: {
- if (from->vval.v_string != NULL) {
- to->vval.v_string = vim_strsave(from->vval.v_string);
- if (from->v_type == VAR_FUNC) {
- func_ref(to->vval.v_string);
- }
- }
- break;
- }
- case VAR_PARTIAL: {
- if (to->vval.v_partial != NULL) {
- to->vval.v_partial->pt_refcount++;
+ case VAR_NUMBER:
+ case VAR_FLOAT:
+ case VAR_BOOL:
+ case VAR_SPECIAL:
+ break;
+ case VAR_STRING:
+ case VAR_FUNC:
+ if (from->vval.v_string != NULL) {
+ to->vval.v_string = vim_strsave(from->vval.v_string);
+ if (from->v_type == VAR_FUNC) {
+ func_ref(to->vval.v_string);
}
- break;
}
- case VAR_LIST: {
- tv_list_ref(to->vval.v_list);
- break;
+ break;
+ case VAR_PARTIAL:
+ if (to->vval.v_partial != NULL) {
+ to->vval.v_partial->pt_refcount++;
}
- case VAR_DICT: {
- if (from->vval.v_dict != NULL) {
- to->vval.v_dict->dv_refcount++;
- }
- break;
+ break;
+ case VAR_BLOB:
+ if (from->vval.v_blob != NULL) {
+ to->vval.v_blob->bv_refcount++;
}
- case VAR_UNKNOWN: {
- emsgf(_(e_intern2), "tv_copy(UNKNOWN)");
- break;
+ break;
+ case VAR_LIST:
+ tv_list_ref(to->vval.v_list);
+ break;
+ case VAR_DICT:
+ if (from->vval.v_dict != NULL) {
+ to->vval.v_dict->dv_refcount++;
}
+ break;
+ case VAR_UNKNOWN:
+ emsgf(_(e_intern2), "tv_copy(UNKNOWN)");
+ break;
}
}
@@ -2533,7 +2611,9 @@ void tv_copy(const typval_T *const from, typval_T *const to)
/// @param[out] tv Item to (un)lock.
/// @param[in] deep Levels to (un)lock, -1 to (un)lock everything.
/// @param[in] lock True if it is needed to lock an item, false to unlock.
-void tv_item_lock(typval_T *const tv, const int deep, const bool lock)
+/// @param[in] check_refcount If true, do not lock a list or dict with a
+/// reference count larger than 1.
+void tv_item_lock(typval_T *const tv, const int deep, const bool lock, const bool check_refcount)
FUNC_ATTR_NONNULL_ALL
{
// TODO(ZyX-I): Make this not recursive
@@ -2560,44 +2640,49 @@ void tv_item_lock(typval_T *const tv, const int deep, const bool lock)
CHANGE_LOCK(lock, tv->v_lock);
switch (tv->v_type) {
- case VAR_LIST: {
- list_T *const l = tv->vval.v_list;
- if (l != NULL) {
- CHANGE_LOCK(lock, l->lv_lock);
- if (deep < 0 || deep > 1) {
- // Recursive: lock/unlock the items the List contains.
- TV_LIST_ITER(l, li, {
- tv_item_lock(TV_LIST_ITEM_TV(li), deep - 1, lock);
+ case VAR_BLOB: {
+ blob_T *const b = tv->vval.v_blob;
+ if (b != NULL && !(check_refcount && b->bv_refcount > 1)) {
+ CHANGE_LOCK(lock, b->bv_lock);
+ }
+ break;
+ }
+ case VAR_LIST: {
+ list_T *const l = tv->vval.v_list;
+ if (l != NULL && !(check_refcount && l->lv_refcount > 1)) {
+ CHANGE_LOCK(lock, l->lv_lock);
+ if (deep < 0 || deep > 1) {
+ // Recursive: lock/unlock the items the List contains.
+ TV_LIST_ITER(l, li, {
+ tv_item_lock(TV_LIST_ITEM_TV(li), deep - 1, lock, check_refcount);
});
- }
}
- break;
}
- case VAR_DICT: {
- dict_T *const d = tv->vval.v_dict;
- if (d != NULL) {
- CHANGE_LOCK(lock, d->dv_lock);
- if (deep < 0 || deep > 1) {
- // recursive: lock/unlock the items the List contains
- TV_DICT_ITER(d, di, {
- tv_item_lock(&di->di_tv, deep - 1, lock);
+ break;
+ }
+ case VAR_DICT: {
+ dict_T *const d = tv->vval.v_dict;
+ if (d != NULL && !(check_refcount && d->dv_refcount > 1)) {
+ CHANGE_LOCK(lock, d->dv_lock);
+ if (deep < 0 || deep > 1) {
+ // recursive: lock/unlock the items the List contains
+ TV_DICT_ITER(d, di, {
+ tv_item_lock(&di->di_tv, deep - 1, lock, check_refcount);
});
- }
}
- break;
- }
- case VAR_NUMBER:
- case VAR_FLOAT:
- case VAR_STRING:
- case VAR_FUNC:
- case VAR_PARTIAL:
- case VAR_BOOL:
- case VAR_SPECIAL: {
- break;
- }
- case VAR_UNKNOWN: {
- abort();
}
+ break;
+ }
+ case VAR_NUMBER:
+ case VAR_FLOAT:
+ case VAR_STRING:
+ case VAR_FUNC:
+ case VAR_PARTIAL:
+ case VAR_BOOL:
+ case VAR_SPECIAL:
+ break;
+ case VAR_UNKNOWN:
+ abort();
}
#undef CHANGE_LOCK
recurse--;
@@ -2639,32 +2724,32 @@ bool tv_islocked(const typval_T *const tv)
/// gettext.
///
/// @return true if variable is locked, false otherwise.
-bool tv_check_lock(const typval_T *tv, const char *name,
- size_t name_len)
+bool tv_check_lock(const typval_T *tv, const char *name, size_t name_len)
FUNC_ATTR_WARN_UNUSED_RESULT
{
VarLockStatus lock = VAR_UNLOCKED;
switch (tv->v_type) {
- // case VAR_BLOB:
- // if (tv->vval.v_blob != NULL)
- // lock = tv->vval.v_blob->bv_lock;
- // break;
- case VAR_LIST:
- if (tv->vval.v_list != NULL) {
- lock = tv->vval.v_list->lv_lock;
- }
- break;
- case VAR_DICT:
- if (tv->vval.v_dict != NULL) {
- lock = tv->vval.v_dict->dv_lock;
- }
- break;
- default:
- break;
+ case VAR_BLOB:
+ if (tv->vval.v_blob != NULL) {
+ lock = tv->vval.v_blob->bv_lock;
+ }
+ break;
+ case VAR_LIST:
+ if (tv->vval.v_list != NULL) {
+ lock = tv->vval.v_list->lv_lock;
+ }
+ break;
+ case VAR_DICT:
+ if (tv->vval.v_dict != NULL) {
+ lock = tv->vval.v_dict->dv_lock;
+ }
+ break;
+ default:
+ break;
}
return var_check_lock(tv->v_lock, name, name_len)
- || (lock != VAR_UNLOCKED && var_check_lock(lock, name, name_len));
+ || (lock != VAR_UNLOCKED && var_check_lock(lock, name, name_len));
}
/// @return true if variable "name" is locked (immutable)
@@ -2672,17 +2757,14 @@ bool var_check_lock(VarLockStatus lock, const char *name, size_t name_len)
{
const char *error_message = NULL;
switch (lock) {
- case VAR_UNLOCKED: {
- return false;
- }
- case VAR_LOCKED: {
- error_message = N_("E741: Value is locked: %.*s");
- break;
- }
- case VAR_FIXED: {
- error_message = N_("E742: Cannot change value of %.*s");
- break;
- }
+ case VAR_UNLOCKED:
+ return false;
+ case VAR_LOCKED:
+ error_message = N_("E741: Value is locked: %.*s");
+ break;
+ case VAR_FIXED:
+ error_message = N_("E742: Cannot change value of %.*s");
+ break;
}
assert(error_message != NULL);
@@ -2718,8 +2800,7 @@ static int tv_equal_recurse_limit;
/// @param[in] recursive True when used recursively.
///
/// @return true if values are equal.
-bool tv_equal(typval_T *const tv1, typval_T *const tv2, const bool ic,
- const bool recursive)
+bool tv_equal(typval_T *const tv1, typval_T *const tv2, const bool ic, const bool recursive)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
// TODO(ZyX-I): Make this not recursive
@@ -2744,55 +2825,52 @@ bool tv_equal(typval_T *const tv1, typval_T *const tv2, const bool ic,
}
switch (tv1->v_type) {
- case VAR_LIST: {
- recursive_cnt++;
- const bool r = tv_list_equal(tv1->vval.v_list, tv2->vval.v_list, ic,
- true);
- recursive_cnt--;
- return r;
- }
- case VAR_DICT: {
- recursive_cnt++;
- const bool r = tv_dict_equal(tv1->vval.v_dict, tv2->vval.v_dict, ic,
- true);
- recursive_cnt--;
- return r;
- }
- case VAR_PARTIAL:
- case VAR_FUNC: {
- if ((tv1->v_type == VAR_PARTIAL && tv1->vval.v_partial == NULL)
- || (tv2->v_type == VAR_PARTIAL && tv2->vval.v_partial == NULL)) {
- return false;
- }
- recursive_cnt++;
- const bool r = func_equal(tv1, tv2, ic);
- recursive_cnt--;
- return r;
- }
- case VAR_NUMBER: {
- return tv1->vval.v_number == tv2->vval.v_number;
- }
- case VAR_FLOAT: {
- return tv1->vval.v_float == tv2->vval.v_float;
- }
- case VAR_STRING: {
- char buf1[NUMBUFLEN];
- char buf2[NUMBUFLEN];
- const char *s1 = tv_get_string_buf(tv1, buf1);
- const char *s2 = tv_get_string_buf(tv2, buf2);
- return mb_strcmp_ic((bool)ic, s1, s2) == 0;
- }
- case VAR_BOOL: {
- return tv1->vval.v_bool == tv2->vval.v_bool;
- }
- case VAR_SPECIAL: {
- return tv1->vval.v_special == tv2->vval.v_special;
- }
- case VAR_UNKNOWN: {
- // VAR_UNKNOWN can be the result of an invalid expression, let’s say it
- // does not equal anything, not even self.
+ case VAR_LIST: {
+ recursive_cnt++;
+ const bool r = tv_list_equal(tv1->vval.v_list, tv2->vval.v_list, ic,
+ true);
+ recursive_cnt--;
+ return r;
+ }
+ case VAR_DICT: {
+ recursive_cnt++;
+ const bool r = tv_dict_equal(tv1->vval.v_dict, tv2->vval.v_dict, ic,
+ true);
+ recursive_cnt--;
+ return r;
+ }
+ case VAR_PARTIAL:
+ case VAR_FUNC: {
+ if ((tv1->v_type == VAR_PARTIAL && tv1->vval.v_partial == NULL)
+ || (tv2->v_type == VAR_PARTIAL && tv2->vval.v_partial == NULL)) {
return false;
}
+ recursive_cnt++;
+ const bool r = func_equal(tv1, tv2, ic);
+ recursive_cnt--;
+ return r;
+ }
+ case VAR_BLOB:
+ return tv_blob_equal(tv1->vval.v_blob, tv2->vval.v_blob);
+ case VAR_NUMBER:
+ return tv1->vval.v_number == tv2->vval.v_number;
+ case VAR_FLOAT:
+ return tv1->vval.v_float == tv2->vval.v_float;
+ case VAR_STRING: {
+ char buf1[NUMBUFLEN];
+ char buf2[NUMBUFLEN];
+ const char *s1 = tv_get_string_buf(tv1, buf1);
+ const char *s2 = tv_get_string_buf(tv2, buf2);
+ return mb_strcmp_ic((bool)ic, s1, s2) == 0;
+ }
+ case VAR_BOOL:
+ return tv1->vval.v_bool == tv2->vval.v_bool;
+ case VAR_SPECIAL:
+ return tv1->vval.v_special == tv2->vval.v_special;
+ case VAR_UNKNOWN:
+ // VAR_UNKNOWN can be the result of an invalid expression, let’s say it
+ // does not equal anything, not even self.
+ return false;
}
abort();
@@ -2814,39 +2892,34 @@ bool tv_check_str_or_nr(const typval_T *const tv)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
switch (tv->v_type) {
- case VAR_NUMBER:
- case VAR_STRING: {
- return true;
- }
- case VAR_FLOAT: {
- EMSG(_("E805: Expected a Number or a String, Float found"));
- return false;
- }
- case VAR_PARTIAL:
- case VAR_FUNC: {
- EMSG(_("E703: Expected a Number or a String, Funcref found"));
- return false;
- }
- case VAR_LIST: {
- EMSG(_("E745: Expected a Number or a String, List found"));
- return false;
- }
- case VAR_DICT: {
- EMSG(_("E728: Expected a Number or a String, Dictionary found"));
- return false;
- }
- case VAR_BOOL: {
- EMSG(_("E5299: Expected a Number or a String, Boolean found"));
- return false;
- }
- case VAR_SPECIAL: {
- EMSG(_("E5300: Expected a Number or a String"));
- return false;
- }
- case VAR_UNKNOWN: {
- EMSG2(_(e_intern2), "tv_check_str_or_nr(UNKNOWN)");
- return false;
- }
+ case VAR_NUMBER:
+ case VAR_STRING:
+ return true;
+ case VAR_FLOAT:
+ EMSG(_("E805: Expected a Number or a String, Float found"));
+ return false;
+ case VAR_PARTIAL:
+ case VAR_FUNC:
+ EMSG(_("E703: Expected a Number or a String, Funcref found"));
+ return false;
+ case VAR_LIST:
+ EMSG(_("E745: Expected a Number or a String, List found"));
+ return false;
+ case VAR_DICT:
+ EMSG(_("E728: Expected a Number or a String, Dictionary found"));
+ return false;
+ case VAR_BLOB:
+ EMSG(_("E974: Expected a Number or a String, Blob found"));
+ return false;
+ case VAR_BOOL:
+ EMSG(_("E5299: Expected a Number or a String, Boolean found"));
+ return false;
+ case VAR_SPECIAL:
+ EMSG(_("E5300: Expected a Number or a String"));
+ return false;
+ case VAR_UNKNOWN:
+ EMSG2(_(e_intern2), "tv_check_str_or_nr(UNKNOWN)");
+ return false;
}
abort();
return false;
@@ -2860,6 +2933,7 @@ static const char *const num_errors[] = {
[VAR_LIST]=N_("E745: Using a List as a Number"),
[VAR_DICT]=N_("E728: Using a Dictionary as a Number"),
[VAR_FLOAT]=N_("E805: Using a Float as a Number"),
+ [VAR_BLOB]=N_("E974: Using a Blob as a Number"),
[VAR_UNKNOWN]=N_("E685: using an invalid value as a Number"),
};
@@ -2877,21 +2951,20 @@ bool tv_check_num(const typval_T *const tv)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
switch (tv->v_type) {
- case VAR_NUMBER:
- case VAR_BOOL:
- case VAR_SPECIAL:
- case VAR_STRING: {
- return true;
- }
- case VAR_FUNC:
- case VAR_PARTIAL:
- case VAR_LIST:
- case VAR_DICT:
- case VAR_FLOAT:
- case VAR_UNKNOWN: {
- EMSG(_(num_errors[tv->v_type]));
- return false;
- }
+ case VAR_NUMBER:
+ case VAR_BOOL:
+ case VAR_SPECIAL:
+ case VAR_STRING:
+ return true;
+ case VAR_FUNC:
+ case VAR_PARTIAL:
+ case VAR_LIST:
+ case VAR_DICT:
+ case VAR_FLOAT:
+ case VAR_BLOB:
+ case VAR_UNKNOWN:
+ EMSG(_(num_errors[tv->v_type]));
+ return false;
}
abort();
return false;
@@ -2905,6 +2978,7 @@ static const char *const str_errors[] = {
[VAR_LIST]=N_("E730: using List as a String"),
[VAR_DICT]=N_("E731: using Dictionary as a String"),
[VAR_FLOAT]=((const char *)e_float_as_string),
+ [VAR_BLOB]=N_("E976: using Blob as a String"),
[VAR_UNKNOWN]=N_("E908: using an invalid value as a String"),
};
@@ -2922,21 +2996,20 @@ bool tv_check_str(const typval_T *const tv)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
switch (tv->v_type) {
- case VAR_NUMBER:
- case VAR_BOOL:
- case VAR_SPECIAL:
- case VAR_STRING: {
- return true;
- }
- case VAR_PARTIAL:
- case VAR_FUNC:
- case VAR_LIST:
- case VAR_DICT:
- case VAR_FLOAT:
- case VAR_UNKNOWN: {
- EMSG(_(str_errors[tv->v_type]));
- return false;
- }
+ case VAR_NUMBER:
+ case VAR_BOOL:
+ case VAR_SPECIAL:
+ case VAR_STRING:
+ return true;
+ case VAR_PARTIAL:
+ case VAR_FUNC:
+ case VAR_LIST:
+ case VAR_DICT:
+ case VAR_FLOAT:
+ case VAR_BLOB:
+ case VAR_UNKNOWN:
+ EMSG(_(str_errors[tv->v_type]));
+ return false;
}
abort();
return false;
@@ -2976,34 +3049,31 @@ varnumber_T tv_get_number_chk(const typval_T *const tv, bool *const ret_error)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1)
{
switch (tv->v_type) {
- case VAR_FUNC:
- case VAR_PARTIAL:
- case VAR_LIST:
- case VAR_DICT:
- case VAR_FLOAT: {
- EMSG(_(num_errors[tv->v_type]));
- break;
- }
- case VAR_NUMBER: {
- return tv->vval.v_number;
- }
- case VAR_STRING: {
- varnumber_T n = 0;
- if (tv->vval.v_string != NULL) {
- vim_str2nr(tv->vval.v_string, NULL, NULL, STR2NR_ALL, &n, NULL, 0);
- }
- return n;
- }
- case VAR_BOOL: {
- return tv->vval.v_bool == kBoolVarTrue ? 1 : 0;
- }
- case VAR_SPECIAL: {
- return 0;
- }
- case VAR_UNKNOWN: {
- emsgf(_(e_intern2), "tv_get_number(UNKNOWN)");
- break;
- }
+ case VAR_FUNC:
+ case VAR_PARTIAL:
+ case VAR_LIST:
+ case VAR_DICT:
+ case VAR_BLOB:
+ case VAR_FLOAT:
+ EMSG(_(num_errors[tv->v_type]));
+ break;
+ case VAR_NUMBER:
+ return tv->vval.v_number;
+ case VAR_STRING: {
+ varnumber_T n = 0;
+ if (tv->vval.v_string != NULL) {
+ vim_str2nr(tv->vval.v_string, NULL, NULL, STR2NR_ALL, &n, NULL, 0,
+ false);
+ }
+ return n;
+ }
+ case VAR_BOOL:
+ return tv->vval.v_bool == kBoolVarTrue ? 1 : 0;
+ case VAR_SPECIAL:
+ return 0;
+ case VAR_UNKNOWN:
+ emsgf(_(e_intern2), "tv_get_number(UNKNOWN)");
+ break;
}
if (ret_error != NULL) {
*ret_error = true;
@@ -3043,41 +3113,35 @@ float_T tv_get_float(const typval_T *const tv)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
switch (tv->v_type) {
- case VAR_NUMBER: {
- return (float_T)(tv->vval.v_number);
- }
- case VAR_FLOAT: {
- return tv->vval.v_float;
- }
- case VAR_PARTIAL:
- case VAR_FUNC: {
- EMSG(_("E891: Using a Funcref as a Float"));
- break;
- }
- case VAR_STRING: {
- EMSG(_("E892: Using a String as a Float"));
- break;
- }
- case VAR_LIST: {
- EMSG(_("E893: Using a List as a Float"));
- break;
- }
- case VAR_DICT: {
- EMSG(_("E894: Using a Dictionary as a Float"));
- break;
- }
- case VAR_BOOL: {
- EMSG(_("E362: Using a boolean value as a Float"));
- break;
- }
- case VAR_SPECIAL: {
- EMSG(_("E907: Using a special value as a Float"));
- break;
- }
- case VAR_UNKNOWN: {
- emsgf(_(e_intern2), "tv_get_float(UNKNOWN)");
- break;
- }
+ case VAR_NUMBER:
+ return (float_T)(tv->vval.v_number);
+ case VAR_FLOAT:
+ return tv->vval.v_float;
+ case VAR_PARTIAL:
+ case VAR_FUNC:
+ EMSG(_("E891: Using a Funcref as a Float"));
+ break;
+ case VAR_STRING:
+ EMSG(_("E892: Using a String as a Float"));
+ break;
+ case VAR_LIST:
+ EMSG(_("E893: Using a List as a Float"));
+ break;
+ case VAR_DICT:
+ EMSG(_("E894: Using a Dictionary as a Float"));
+ break;
+ case VAR_BOOL:
+ EMSG(_("E362: Using a boolean value as a Float"));
+ break;
+ case VAR_SPECIAL:
+ EMSG(_("E907: Using a special value as a Float"));
+ break;
+ case VAR_BLOB:
+ EMSG(_("E975: Using a Blob as a Float"));
+ break;
+ case VAR_UNKNOWN:
+ emsgf(_(e_intern2), "tv_get_float(UNKNOWN)");
+ break;
}
return 0;
}
@@ -3110,33 +3174,29 @@ const char *tv_get_string_buf_chk(const typval_T *const tv, char *const buf)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
switch (tv->v_type) {
- case VAR_NUMBER: {
- snprintf(buf, NUMBUFLEN, "%" PRIdVARNUMBER, tv->vval.v_number); // -V576
- return buf;
- }
- case VAR_STRING: {
- if (tv->vval.v_string != NULL) {
- return (const char *)tv->vval.v_string;
- }
- return "";
- }
- case VAR_BOOL: {
- STRCPY(buf, encode_bool_var_names[tv->vval.v_bool]);
- return buf;
- }
- case VAR_SPECIAL: {
- STRCPY(buf, encode_special_var_names[tv->vval.v_special]);
- return buf;
- }
- case VAR_PARTIAL:
- case VAR_FUNC:
- case VAR_LIST:
- case VAR_DICT:
- case VAR_FLOAT:
- case VAR_UNKNOWN: {
- EMSG(_(str_errors[tv->v_type]));
- return false;
- }
+ case VAR_NUMBER:
+ snprintf(buf, NUMBUFLEN, "%" PRIdVARNUMBER, tv->vval.v_number); // -V576
+ return buf;
+ case VAR_STRING:
+ if (tv->vval.v_string != NULL) {
+ return (const char *)tv->vval.v_string;
+ }
+ return "";
+ case VAR_BOOL:
+ STRCPY(buf, encode_bool_var_names[tv->vval.v_bool]);
+ return buf;
+ case VAR_SPECIAL:
+ STRCPY(buf, encode_special_var_names[tv->vval.v_special]);
+ return buf;
+ case VAR_PARTIAL:
+ case VAR_FUNC:
+ case VAR_LIST:
+ case VAR_DICT:
+ case VAR_FLOAT:
+ case VAR_BLOB:
+ case VAR_UNKNOWN:
+ EMSG(_(str_errors[tv->v_type]));
+ return false;
}
return NULL;
}
diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h
index 050b84efec..5aecaccee9 100644
--- a/src/nvim/eval/typval.h
+++ b/src/nvim/eval/typval.h
@@ -55,7 +55,7 @@ enum ListLenSpecials {
#define VARNUMBER_MAX INT64_MAX
#define UVARNUMBER_MAX UINT64_MAX
-/// Mimimal possible value of varnumber_T variable
+/// Minimal possible value of varnumber_T variable
#define VARNUMBER_MIN INT64_MIN
/// %d printf format specifier for varnumber_T
@@ -64,6 +64,7 @@ enum ListLenSpecials {
typedef struct listvar_S list_T;
typedef struct dictvar_S dict_T;
typedef struct partial_S partial_T;
+typedef struct blobvar_S blob_T;
typedef struct ufunc ufunc_T;
@@ -123,6 +124,7 @@ typedef enum {
VAR_SPECIAL, ///< Special value (null), .v_special
///< is used.
VAR_PARTIAL, ///< Partial, .v_partial is used.
+ VAR_BLOB, ///< Blob, .v_blob is used.
} VarType;
/// Structure that holds an internal variable value
@@ -138,6 +140,7 @@ typedef struct {
list_T *v_list; ///< List for VAR_LIST, can be NULL.
dict_T *v_dict; ///< Dictionary for VAR_DICT, can be NULL.
partial_T *v_partial; ///< Closure: function with args.
+ blob_T *v_blob; ///< Blob for VAR_BLOB, can be NULL.
} vval; ///< Actual value.
} typval_T;
@@ -252,6 +255,13 @@ struct dictvar_S {
LuaRef lua_table_ref;
};
+/// Structure to hold info about a Blob
+struct blobvar_S {
+ garray_T bv_ga; ///< Growarray with the data.
+ int bv_refcount; ///< Reference count.
+ VarLockStatus bv_lock; ///< VAR_UNLOCKED, VAR_LOCKED, VAR_FIXED.
+};
+
/// Type used for script ID
typedef int scid_T;
/// Format argument for scid_T
@@ -322,7 +332,7 @@ struct ufunc {
int uf_prof_initialized;
// Managing cfuncs
cfunc_T uf_cb; ///< C function extension callback
- cfunc_free_T uf_cb_free; ///< C function extesion free callback
+ cfunc_free_T uf_cb_free; ///< C function extension free callback
void *uf_cb_state; ///< State of C function extension.
// Profiling the function as a whole.
int uf_tm_count; ///< nr of calls
@@ -711,6 +721,65 @@ static inline bool tv_dict_is_watched(const dict_T *const d)
return d && !QUEUE_EMPTY(&d->watchers);
}
+static inline void tv_blob_set_ret(typval_T *const tv, blob_T *const b)
+ REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ARG(1);
+
+/// Set a blob as the return value.
+///
+/// Increments the reference count.
+///
+/// @param[out] tv Object to receive the blob.
+/// @param[in,out] b Blob to pass to the object.
+static inline void tv_blob_set_ret(typval_T *const tv, blob_T *const b)
+{
+ tv->v_type = VAR_BLOB;
+ tv->vval.v_blob = b;
+ if (b != NULL) {
+ b->bv_refcount++;
+ }
+}
+
+static inline int tv_blob_len(const blob_T *const b)
+ REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
+
+/// Get the length of the data in the blob, in bytes.
+///
+/// @param[in] b Blob to check.
+static inline int tv_blob_len(const blob_T *const b)
+{
+ if (b == NULL) {
+ return 0;
+ }
+ return b->bv_ga.ga_len;
+}
+
+static inline char_u tv_blob_get(const blob_T *const b, int idx)
+ REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT;
+
+/// Get the byte at index `idx` in the blob.
+///
+/// @param[in] b Blob to index. Cannot be NULL.
+/// @param[in] idx Index in a blob. Must be valid.
+///
+/// @return Byte value at the given index.
+static inline char_u tv_blob_get(const blob_T *const b, int idx)
+{
+ return ((char_u *)b->bv_ga.ga_data)[idx];
+}
+
+static inline void tv_blob_set(blob_T *const b, int idx, char_u c)
+ REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL;
+
+/// Store the byte `c` at index `idx` in the blob.
+///
+/// @param[in] b Blob to index. Cannot be NULL.
+/// @param[in] idx Index in a blob. Must be valid.
+/// @param[in] c Value to store.
+static inline void tv_blob_set(blob_T *const b, int idx, char_u c)
+{
+ ((char_u *)b->bv_ga.ga_data)[idx] = c;
+}
+
/// Initialize VimL object
///
/// Initializes to unlocked VAR_UNKNOWN object.
diff --git a/src/nvim/eval/typval_encode.c.h b/src/nvim/eval/typval_encode.c.h
index 91c948ce7e..cd1be1eecc 100644
--- a/src/nvim/eval/typval_encode.c.h
+++ b/src/nvim/eval/typval_encode.c.h
@@ -83,6 +83,13 @@
/// @param len String length.
/// @param type EXT type.
+/// @def TYPVAL_ENCODE_CONV_BLOB
+/// @brief Macros used to convert a blob
+///
+/// @param tv Pointer to typval where value is stored. May not be NULL.
+/// @param blob Pointer to the blob to convert.
+/// @param len Blob length.
+
/// @def TYPVAL_ENCODE_CONV_FUNC_START
/// @brief Macros used when starting to convert a funcref or a partial
///
@@ -330,6 +337,11 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
TYPVAL_ENCODE_CONV_FLOAT(tv, tv->vval.v_float);
break;
}
+ case VAR_BLOB: {
+ TYPVAL_ENCODE_CONV_BLOB(tv, tv->vval.v_blob,
+ tv_blob_len(tv->vval.v_blob));
+ break;
+ }
case VAR_FUNC: {
TYPVAL_ENCODE_CONV_FUNC_START(tv, tv->vval.v_string);
TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(tv, 0);
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index 5ffc06ec44..657777d7db 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -5,6 +5,7 @@
#include "nvim/ascii.h"
#include "nvim/charset.h"
+#include "nvim/debugger.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
#include "nvim/eval/encode.h"
@@ -12,7 +13,6 @@
#include "nvim/ex_cmds2.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
-#include "nvim/ex_getln.h"
#include "nvim/fileio.h"
#include "nvim/getchar.h"
#include "nvim/globals.h"
@@ -39,7 +39,7 @@
#define FC_CFUNC 0x800 // C function extension
#ifdef INCLUDE_GENERATED_DECLARATIONS
-#include "eval/userfunc.c.generated.h"
+# include "eval/userfunc.c.generated.h"
#endif
hashtab_T func_hashtab;
@@ -54,26 +54,25 @@ static funccall_T *current_funccal = NULL;
// item in it is still being used.
static funccall_T *previous_funccal = NULL;
-static char *e_funcexts = N_(
- "E122: Function %s already exists, add ! to replace it");
+static char *e_funcexts = N_("E122: Function %s already exists, add ! to replace it");
static char *e_funcdict = N_("E717: Dictionary entry already exists");
static char *e_funcref = N_("E718: Funcref required");
static char *e_nofunc = N_("E130: Unknown function: %s");
void func_init(void)
{
- hash_init(&func_hashtab);
+ hash_init(&func_hashtab);
}
/// Get function arguments.
-static int get_function_args(char_u **argp, char_u endchar, garray_T *newargs,
- int *varargs, garray_T *default_args, bool skip)
+static int get_function_args(char_u **argp, char_u endchar, garray_T *newargs, int *varargs,
+ garray_T *default_args, bool skip)
{
- bool mustend = false;
- char_u *arg = *argp;
- char_u *p = arg;
- int c;
- int i;
+ bool mustend = false;
+ char_u *arg = *argp;
+ char_u *p = arg;
+ int c;
+ int i;
if (newargs != NULL) {
ga_init(newargs, (int)sizeof(char_u *), 3);
@@ -145,7 +144,7 @@ static int get_function_args(char_u **argp, char_u endchar, garray_T *newargs,
*p = NUL;
expr = vim_strsave(expr);
((char_u **)(default_args->ga_data))
- [default_args->ga_len] = expr;
+ [default_args->ga_len] = expr;
default_args->ga_len++;
*p = c;
} else {
@@ -199,18 +198,18 @@ static void register_closure(ufunc_T *fp)
current_funccal->fc_refcount++;
ga_grow(&current_funccal->fc_funcs, 1);
((ufunc_T **)current_funccal->fc_funcs.ga_data)
- [current_funccal->fc_funcs.ga_len++] = fp;
+ [current_funccal->fc_funcs.ga_len++] = fp;
}
/// Get a name for a lambda. Returned in static memory.
-char_u * get_lambda_name(void)
+char_u *get_lambda_name(void)
{
- static char_u name[30];
- static int lambda_no = 0;
+ static char_u name[30];
+ static int lambda_no = 0;
- snprintf((char *)name, sizeof(name), "<lambda>%d", ++lambda_no);
- return name;
+ snprintf((char *)name, sizeof(name), "<lambda>%d", ++lambda_no);
+ return name;
}
/// Parse a lambda expression and get a Funcref from "*arg".
@@ -218,16 +217,16 @@ char_u * get_lambda_name(void)
/// @return OK or FAIL. Returns NOTDONE for dict or {expr}.
int get_lambda_tv(char_u **arg, typval_T *rettv, bool evaluate)
{
- garray_T newargs = GA_EMPTY_INIT_VALUE;
- garray_T *pnewargs;
- ufunc_T *fp = NULL;
+ garray_T newargs = GA_EMPTY_INIT_VALUE;
+ garray_T *pnewargs;
+ ufunc_T *fp = NULL;
partial_T *pt = NULL;
- int varargs;
- int ret;
- char_u *start = skipwhite(*arg + 1);
- char_u *s, *e;
- bool *old_eval_lavars = eval_lavars_used;
- bool eval_lavars = false;
+ int varargs;
+ int ret;
+ char_u *start = skipwhite(*arg + 1);
+ char_u *s, *e;
+ bool *old_eval_lavars = eval_lavars_used;
+ bool eval_lavars = false;
// First, check if this is a lambda expression. "->" must exists.
ret = get_function_args(&start, '-', NULL, NULL, NULL, true);
@@ -347,8 +346,7 @@ errret:
/// was not found.
///
/// @return name of the function.
-char_u *deref_func_name(const char *name, int *lenp,
- partial_T **const partialp, bool no_autoload)
+char_u *deref_func_name(const char *name, int *lenp, partial_T **const partialp, bool no_autoload)
FUNC_ATTR_NONNULL_ARG(1, 2)
{
if (partialp != NULL) {
@@ -408,46 +406,41 @@ void emsg_funcname(char *ermsg, const char_u *name)
* Allocate a variable for the result of a function.
* Return OK or FAIL.
*/
-int
-get_func_tv(
- const char_u *name, // name of the function
- int len, // length of "name" or -1 to use strlen()
- typval_T *rettv,
- char_u **arg, // argument, pointing to the '('
- linenr_T firstline, // first line of range
- linenr_T lastline, // last line of range
- int *doesrange, // return: function handled range
- int evaluate,
- partial_T *partial, // for extra arguments
- dict_T *selfdict // Dictionary for "self"
-)
-{
- char_u *argp;
+int get_func_tv(const char_u *name, // name of the function
+ int len, // length of "name" or -1 to use strlen()
+ typval_T *rettv, char_u **arg, // argument, pointing to the '('
+ funcexe_T *funcexe // various values
+ )
+{
+ char_u *argp;
int ret = OK;
- typval_T argvars[MAX_FUNC_ARGS + 1]; /* vars for arguments */
- int argcount = 0; /* number of arguments found */
+ typval_T argvars[MAX_FUNC_ARGS + 1]; // vars for arguments
+ int argcount = 0; // number of arguments found
/*
* Get the arguments.
*/
argp = *arg;
- while (argcount < MAX_FUNC_ARGS - (partial == NULL ? 0 : partial->pt_argc)) {
+ while (argcount < MAX_FUNC_ARGS
+ - (funcexe->partial == NULL ? 0 : funcexe->partial->pt_argc)) {
argp = skipwhite(argp + 1); // skip the '(' or ','
if (*argp == ')' || *argp == ',' || *argp == NUL) {
break;
}
- if (eval1(&argp, &argvars[argcount], evaluate) == FAIL) {
+ if (eval1(&argp, &argvars[argcount], funcexe->evaluate) == FAIL) {
ret = FAIL;
break;
}
++argcount;
- if (*argp != ',')
+ if (*argp != ',') {
break;
+ }
}
- if (*argp == ')')
+ if (*argp == ')') {
++argp;
- else
+ } else {
ret = FAIL;
+ }
if (ret == OK) {
int i = 0;
@@ -463,9 +456,7 @@ get_func_tv(
((typval_T **)funcargs.ga_data)[funcargs.ga_len++] = &argvars[i];
}
}
- ret = call_func(name, len, rettv, argcount, argvars, NULL,
- firstline, lastline, doesrange, evaluate,
- partial, selfdict);
+ ret = call_func(name, len, rettv, argcount, argvars, funcexe);
funcargs.ga_len -= i;
} else if (!aborting()) {
@@ -517,8 +508,7 @@ static inline bool eval_fname_sid(const char *const name)
///
/// @return transformed name: either `fname_buf` or a pointer to an allocated
/// memory.
-static char_u *fname_trans_sid(const char_u *const name,
- char_u *const fname_buf,
+static char_u *fname_trans_sid(const char_u *const name, char_u *const fname_buf,
char_u **const tofree, int *const error)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
@@ -558,11 +548,12 @@ static char_u *fname_trans_sid(const char_u *const name,
/// @return NULL for unknown function.
ufunc_T *find_func(const char_u *name)
{
- hashitem_T *hi;
+ hashitem_T *hi;
hi = hash_find(&func_hashtab, name);
- if (!HASHITEM_EMPTY(hi))
+ if (!HASHITEM_EMPTY(hi)) {
return HI2UF(hi);
+ }
return NULL;
}
@@ -576,8 +567,9 @@ static void cat_func_name(char_u *buf, ufunc_T *fp)
if (fp->uf_name[0] == K_SPECIAL) {
STRCPY(buf, "<SNR>");
STRCAT(buf, fp->uf_name + 3);
- } else
+ } else {
STRCPY(buf, fp->uf_name);
+ }
}
/*
@@ -667,7 +659,6 @@ static void cleanup_function_call(funccall_T *fc)
if (may_free_fc && fc->l_varlist.lv_refcount // NOLINT(runtime/deprecated)
== DO_NOT_FREE_CNT) {
fc->l_varlist.lv_first = NULL; // NOLINT(runtime/deprecated)
-
} else {
free_fc = false;
@@ -812,23 +803,22 @@ static void func_clear_free(ufunc_T *fp, bool force)
/// @param[in] firstline First line of range.
/// @param[in] lastline Last line of range.
/// @param selfdict Dictionary for "self" for dictionary functions.
-void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
- typval_T *rettv, linenr_T firstline, linenr_T lastline,
- dict_T *selfdict)
+void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv,
+ linenr_T firstline, linenr_T lastline, dict_T *selfdict)
FUNC_ATTR_NONNULL_ARG(1, 3, 4)
{
- char_u *save_sourcing_name;
+ char_u *save_sourcing_name;
linenr_T save_sourcing_lnum;
bool using_sandbox = false;
- funccall_T *fc;
+ funccall_T *fc;
int save_did_emsg;
static int depth = 0;
- dictitem_T *v;
+ dictitem_T *v;
int fixvar_idx = 0; // index in fixvar[]
int ai;
bool islambda = false;
char_u numbuf[NUMBUFLEN];
- char_u *name;
+ char_u *name;
typval_T *tv_to_free[MAX_FUNC_ARGS];
int tv_to_free_len = 0;
proftime_T wait_start;
@@ -954,7 +944,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
def_rettv.vval.v_number = -1;
default_expr = ((char_u **)(fp->uf_def_args.ga_data))
- [ai + fp->uf_def_args.ga_len];
+ [ai + fp->uf_def_args.ga_len];
if (eval1(&default_expr, &def_rettv, true) == FAIL) {
default_arg_err = true;
break;
@@ -1140,7 +1130,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
call_start = profile_sub_wait(wait_start, call_start); // -V614
fp->uf_tm_total = profile_add(fp->uf_tm_total, call_start);
fp->uf_tm_self = profile_self(fp->uf_tm_self, call_start,
- fp->uf_tm_children);
+ fp->uf_tm_children);
if (fc->caller != NULL && fc->caller->func->uf_profiling) {
fc->caller->func->uf_tm_children =
profile_add(fc->caller->func->uf_tm_children, call_start);
@@ -1158,19 +1148,19 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
++no_wait_return;
verbose_enter_scroll();
- if (aborting())
+ if (aborting()) {
smsg(_("%s aborted"), sourcing_name);
- else if (fc->rettv->v_type == VAR_NUMBER)
+ } else if (fc->rettv->v_type == VAR_NUMBER) {
smsg(_("%s returning #%" PRId64 ""),
sourcing_name, (int64_t)fc->rettv->vval.v_number);
- else {
+ } else {
char_u buf[MSG_BUF_LEN];
// The value may be very long. Skip the middle part, so that we
// have some idea how it starts and ends. smsg() would always
// truncate it at the end. Don't want errors such as E724 here.
emsg_off++;
- char_u *s = (char_u *) encode_tv2string(fc->rettv, NULL);
+ char_u *s = (char_u *)encode_tv2string(fc->rettv, NULL);
char_u *tofree = s;
emsg_off--;
if (s != NULL) {
@@ -1274,8 +1264,8 @@ void set_current_funccal(funccall_T *fc)
#if defined(EXITFREE)
void free_all_functions(void)
{
- hashitem_T *hi;
- ufunc_T *fp;
+ hashitem_T *hi;
+ ufunc_T *fp;
uint64_t skipped = 0;
uint64_t todo = 1;
uint64_t used;
@@ -1362,12 +1352,10 @@ static bool builtin_function(const char *name, int len)
return p == NULL;
}
-int func_call(char_u *name, typval_T *args, partial_T *partial,
- dict_T *selfdict, typval_T *rettv)
+int func_call(char_u *name, typval_T *args, partial_T *partial, dict_T *selfdict, typval_T *rettv)
{
typval_T argv[MAX_FUNC_ARGS + 1];
int argc = 0;
- int dummy;
int r = 0;
TV_LIST_ITER(args->vval.v_list, item, {
@@ -1380,9 +1368,13 @@ int func_call(char_u *name, typval_T *args, partial_T *partial,
tv_copy(TV_LIST_ITEM_TV(item), &argv[argc++]);
});
- r = call_func(name, -1, rettv, argc, argv, NULL,
- curwin->w_cursor.lnum, curwin->w_cursor.lnum,
- &dummy, true, partial, selfdict);
+ funcexe_T funcexe = FUNCEXE_INIT;
+ funcexe.firstline = curwin->w_cursor.lnum;
+ funcexe.lastline = curwin->w_cursor.lnum;
+ funcexe.evaluate = true;
+ funcexe.partial = partial;
+ funcexe.selfdict = selfdict;
+ r = call_func(name, -1, rettv, argc, argv, &funcexe);
func_call_skip_call:
// Free the arguments.
@@ -1399,56 +1391,63 @@ static void user_func_error(int error, const char_u *name)
FUNC_ATTR_NONNULL_ALL
{
switch (error) {
- case ERROR_UNKNOWN:
- emsg_funcname(N_("E117: Unknown function: %s"), name);
- break;
- case ERROR_DELETED:
- emsg_funcname(N_("E933: Function was deleted: %s"), name);
- break;
- case ERROR_TOOMANY:
- emsg_funcname(_(e_toomanyarg), name);
- break;
- case ERROR_TOOFEW:
- emsg_funcname(N_("E119: Not enough arguments for function: %s"),
- name);
- break;
- case ERROR_SCRIPT:
- emsg_funcname(N_("E120: Using <SID> not in a script context: %s"),
- name);
- break;
- case ERROR_DICT:
- emsg_funcname(N_("E725: Calling dict function without Dictionary: %s"),
- name);
- break;
+ case ERROR_UNKNOWN:
+ emsg_funcname(N_("E117: Unknown function: %s"), name);
+ break;
+ case ERROR_NOTMETHOD:
+ emsg_funcname(N_("E276: Cannot use function as a method: %s"), name);
+ break;
+ case ERROR_DELETED:
+ emsg_funcname(N_("E933: Function was deleted: %s"), name);
+ break;
+ case ERROR_TOOMANY:
+ emsg_funcname(_(e_toomanyarg), name);
+ break;
+ case ERROR_TOOFEW:
+ emsg_funcname(N_("E119: Not enough arguments for function: %s"),
+ name);
+ break;
+ case ERROR_SCRIPT:
+ emsg_funcname(N_("E120: Using <SID> not in a script context: %s"),
+ name);
+ break;
+ case ERROR_DICT:
+ emsg_funcname(N_("E725: Calling dict function without Dictionary: %s"),
+ name);
+ break;
+ }
+}
+
+/// Used by call_func to add a method base (if any) to a function argument list
+/// as the first argument. @see call_func
+static void argv_add_base(typval_T *const basetv, typval_T **const argvars, int *const argcount,
+ typval_T *const new_argvars, int *const argv_base)
+ FUNC_ATTR_NONNULL_ARG(2, 3, 4, 5)
+{
+ if (basetv != NULL) {
+ // Method call: base->Method()
+ memmove(&new_argvars[1], *argvars, sizeof(typval_T) * (*argcount));
+ new_argvars[0] = *basetv;
+ (*argcount)++;
+ *argvars = new_argvars;
+ *argv_base = 1;
}
}
/// Call a function with its resolved parameters
///
-/// "argv_func", when not NULL, can be used to fill in arguments only when the
-/// invoked function uses them. It is called like this:
-/// new_argcount = argv_func(current_argcount, argv, called_func_argcount)
-///
/// @return FAIL if function cannot be called, else OK (even if an error
/// occurred while executing the function! Set `msg_list` to capture
/// the error, see do_cmdline()).
-int
-call_func(
- const char_u *funcname, // name of the function
- int len, // length of "name" or -1 to use strlen()
- typval_T *rettv, // [out] value goes here
- int argcount_in, // number of "argvars"
- typval_T *argvars_in, // vars for arguments, must have "argcount"
- // PLUS ONE elements!
- ArgvFunc argv_func, // function to fill in argvars
- linenr_T firstline, // first line of range
- linenr_T lastline, // last line of range
- int *doesrange, // [out] function handled range
- bool evaluate,
- partial_T *partial, // optional, can be NULL
- dict_T *selfdict_in // Dictionary for "self"
-)
- FUNC_ATTR_NONNULL_ARG(1, 3, 5, 9)
+int call_func(const char_u *funcname, // name of the function
+ int len, // length of "name" or -1 to use strlen()
+ typval_T *rettv, // [out] value goes here
+ int argcount_in, // number of "argvars"
+ typval_T *argvars_in, // vars for arguments, must have "argcount"
+ // PLUS ONE elements!
+ funcexe_T *funcexe // more arguments
+ )
+ FUNC_ATTR_NONNULL_ARG(1, 3, 5, 6)
{
int ret = FAIL;
int error = ERROR_NONE;
@@ -1459,9 +1458,12 @@ call_func(
char_u *name = NULL;
int argcount = argcount_in;
typval_T *argvars = argvars_in;
- dict_T *selfdict = selfdict_in;
- typval_T argv[MAX_FUNC_ARGS + 1]; // used when "partial" is not NULL
+ dict_T *selfdict = funcexe->selfdict;
+ typval_T argv[MAX_FUNC_ARGS + 1]; // used when "partial" or
+ // "funcexe->basetv" is not NULL
int argv_clear = 0;
+ int argv_base = 0;
+ partial_T *partial = funcexe->partial;
// Initialize rettv so that it is safe for caller to invoke clear_tv(rettv)
// even when call_func() returns FAIL.
@@ -1480,14 +1482,15 @@ call_func(
fname = fname_trans_sid(name, fname_buf, &tofree, &error);
}
- *doesrange = false;
+ if (funcexe->doesrange != NULL) {
+ *funcexe->doesrange = false;
+ }
if (partial != NULL) {
// When the function has a partial with a dict and there is a dict
// argument, use the dict argument. That is backwards compatible.
// When the dict was bound explicitly use the one from the partial.
- if (partial->pt_dict != NULL
- && (selfdict_in == NULL || !partial->pt_auto)) {
+ if (partial->pt_dict != NULL && (selfdict == NULL || !partial->pt_auto)) {
selfdict = partial->pt_dict;
}
if (error == ERROR_NONE && partial->pt_argc > 0) {
@@ -1506,7 +1509,7 @@ call_func(
}
}
- if (error == ERROR_NONE && evaluate) {
+ if (error == ERROR_NONE && funcexe->evaluate) {
char_u *rfname = fname;
// Ignore "g:" before a function name.
@@ -1521,7 +1524,12 @@ call_func(
if (is_luafunc(partial)) {
if (len > 0) {
error = ERROR_NONE;
+ argv_add_base(funcexe->basetv, &argvars, &argcount, argv, &argv_base);
nlua_typval_call((const char *)funcname, len, argvars, argcount, rettv);
+ } else {
+ // v:lua was called directly; show its name in the emsg
+ XFREE_CLEAR(name);
+ funcname = (const char_u *)"v:lua";
}
} else if (fp != NULL || !builtin_function((const char *)rfname, -1)) {
// User defined function.
@@ -1531,7 +1539,7 @@ call_func(
// Trigger FuncUndefined event, may load the function.
if (fp == NULL
- && apply_autocmds(EVENT_FUNCUNDEFINED, rfname, rfname, TRUE, NULL)
+ && apply_autocmds(EVENT_FUNCUNDEFINED, rfname, rfname, true, NULL)
&& !aborting()) {
// executed an autocommand, search for the function again
fp = find_func(rfname);
@@ -1549,13 +1557,16 @@ call_func(
cfunc_T cb = fp->uf_cb;
error = (*cb)(argcount, argvars, rettv, fp->uf_cb_state);
} else if (fp != NULL) {
- if (argv_func != NULL) {
+ if (funcexe->argv_func != NULL) {
// postponed filling in the arguments, do it now
- argcount = argv_func(argcount, argvars, argv_clear,
- fp->uf_args.ga_len);
+ argcount = funcexe->argv_func(argcount, argvars, argv_clear,
+ fp->uf_args.ga_len);
}
- if (fp->uf_flags & FC_RANGE) {
- *doesrange = true;
+
+ argv_add_base(funcexe->basetv, &argvars, &argcount, argv, &argv_base);
+
+ if (fp->uf_flags & FC_RANGE && funcexe->doesrange != NULL) {
+ *funcexe->doesrange = true;
}
if (argcount < fp->uf_args.ga_len - fp->uf_def_args.ga_len) {
error = ERROR_TOOFEW;
@@ -1565,25 +1576,20 @@ call_func(
error = ERROR_DICT;
} else {
// Call the user function.
- call_user_func(fp, argcount, argvars, rettv, firstline, lastline,
+ call_user_func(fp, argcount, argvars, rettv, funcexe->firstline,
+ funcexe->lastline,
(fp->uf_flags & FC_DICT) ? selfdict : NULL);
error = ERROR_NONE;
}
}
+ } else if (funcexe->basetv != NULL) {
+ // expr->method(): Find the method name in the table, call its
+ // implementation with the base as one of the arguments.
+ error = call_internal_method(fname, argcount, argvars, rettv,
+ funcexe->basetv);
} else {
// Find the function name in the table, call its implementation.
- const VimLFuncDef *const fdef = find_internal_func((const char *)fname);
- if (fdef != NULL) {
- if (argcount < fdef->min_argc) {
- error = ERROR_TOOFEW;
- } else if (argcount > fdef->max_argc) {
- error = ERROR_TOOMANY;
- } else {
- argvars[argcount].v_type = VAR_UNKNOWN;
- fdef->func(argvars, rettv, fdef->data);
- error = ERROR_NONE;
- }
- }
+ error = call_internal_func(fname, argcount, argvars, rettv);
}
/*
* The function call (or "FuncUndefined" autocommand sequence) might
@@ -1597,8 +1603,9 @@ call_func(
*/
update_force_abort();
}
- if (error == ERROR_NONE)
+ if (error == ERROR_NONE) {
ret = OK;
+ }
theend:
// Report an error unless the argument evaluation or function call has been
@@ -1607,9 +1614,11 @@ theend:
user_func_error(error, (name != NULL) ? name : funcname);
}
+ // clear the copies made from the partial
while (argv_clear > 0) {
- tv_clear(&argv[--argv_clear]);
+ tv_clear(&argv[--argv_clear + argv_base]);
}
+
xfree(tofree);
xfree(name);
@@ -1624,8 +1633,9 @@ theend:
static void list_func_head(ufunc_T *fp, int indent, bool force)
{
msg_start();
- if (indent)
+ if (indent) {
MSG_PUTS(" ");
+ }
MSG_PUTS(force ? "function! " : "function ");
if (fp->uf_name[0] == K_SPECIAL) {
MSG_PUTS_ATTR("<SNR>", HL_ATTR(HLF_8));
@@ -1681,25 +1691,22 @@ static void list_func_head(ufunc_T *fp, int indent, bool force)
/// Advances "pp" to just after the function name (if no error).
///
/// @return the function name in allocated memory, or NULL for failure.
-char_u *
-trans_function_name(
- char_u **pp,
- bool skip, // only find the end, don't evaluate
- int flags,
- funcdict_T *fdp, // return: info about dictionary used
- partial_T **partial // return: partial of a FuncRef
-)
+char_u *trans_function_name(char_u **pp, bool skip, // only find the end, don't evaluate
+ int flags, funcdict_T *fdp, // return: info about dictionary used
+ partial_T **partial // return: partial of a FuncRef
+ )
FUNC_ATTR_NONNULL_ARG(1)
{
- char_u *name = NULL;
+ char_u *name = NULL;
const char_u *start;
const char_u *end;
int lead;
int len;
lval_T lv;
- if (fdp != NULL)
+ if (fdp != NULL) {
memset(fdp, 0, sizeof(funcdict_T));
+ }
start = *pp;
/* Check for hard coded <SNR>: already translated function ID (from a user
@@ -1722,8 +1729,9 @@ trans_function_name(
end = get_lval((char_u *)start, NULL, &lv, false, skip, flags | GLV_READ_ONLY,
lead > 2 ? 0 : FNE_CHECK_START);
if (end == start) {
- if (!skip)
+ if (!skip) {
EMSG(_("E129: Function name required"));
+ }
goto theend;
}
if (end == NULL || (lv.ll_tv != NULL && (lead > 2 || lv.ll_range))) {
@@ -1789,7 +1797,7 @@ trans_function_name(
goto theend;
}
- /* Check if the name is a Funcref. If so, use the value. */
+ // Check if the name is a Funcref. If so, use the value.
if (lv.ll_exp_name != NULL) {
len = (int)strlen(lv.ll_exp_name);
name = deref_func_name(lv.ll_exp_name, &len, partial,
@@ -1898,31 +1906,31 @@ theend:
*/
void ex_function(exarg_T *eap)
{
- char_u *theline;
- char_u *line_to_free = NULL;
+ char_u *theline;
+ char_u *line_to_free = NULL;
int c;
int saved_did_emsg;
- int saved_wait_return = need_wait_return;
- char_u *name = NULL;
- char_u *p;
- char_u *arg;
- char_u *line_arg = NULL;
+ bool saved_wait_return = need_wait_return;
+ char_u *name = NULL;
+ char_u *p;
+ char_u *arg;
+ char_u *line_arg = NULL;
garray_T newargs;
garray_T default_args;
garray_T newlines;
int varargs = false;
int flags = 0;
- ufunc_T *fp;
+ ufunc_T *fp;
bool overwrite = false;
int indent;
int nesting;
- dictitem_T *v;
+ dictitem_T *v;
funcdict_T fudi;
static int func_nr = 0; // number for nameless function
int paren;
- hashtab_T *ht;
+ hashtab_T *ht;
int todo;
- hashitem_T *hi;
+ hashitem_T *hi;
linenr_T sourcing_lnum_off;
linenr_T sourcing_lnum_top;
bool is_heredoc = false;
@@ -1975,15 +1983,17 @@ void ex_function(exarg_T *eap)
--todo;
fp = HI2UF(hi);
if (!isdigit(*fp->uf_name)
- && vim_regexec(&regmatch, fp->uf_name, 0))
+ && vim_regexec(&regmatch, fp->uf_name, 0)) {
list_func_head(fp, false, false);
+ }
}
}
vim_regfree(regmatch.regprog);
}
}
- if (*p == '/')
+ if (*p == '/') {
++p;
+ }
eap->nextcmd = check_nextcmd(p);
return;
}
@@ -2017,8 +2027,9 @@ void ex_function(exarg_T *eap)
}
xfree(fudi.fd_newkey);
return;
- } else
+ } else {
eap->skip = TRUE;
+ }
}
/* An error in a function call during evaluation of an expression in magic
@@ -2038,8 +2049,9 @@ void ex_function(exarg_T *eap)
goto ret_free;
}
eap->nextcmd = check_nextcmd(p);
- if (eap->nextcmd != NULL)
+ if (eap->nextcmd != NULL) {
*p = NUL;
+ }
if (!eap->skip && !got_int) {
fp = find_func(name);
if (fp != NULL) {
@@ -2066,8 +2078,9 @@ void ex_function(exarg_T *eap)
msg_putchar('\n');
msg_puts(eap->forceit ? "endfunction" : " endfunction");
}
- } else
+ } else {
emsg_funcname(N_("E123: Undefined function: %s"), name);
+ }
}
goto ret_free;
}
@@ -2094,17 +2107,20 @@ void ex_function(exarg_T *eap)
if (!eap->skip) {
/* Check the name of the function. Unless it's a dictionary function
* (that we are overwriting). */
- if (name != NULL)
+ if (name != NULL) {
arg = name;
- else
+ } else {
arg = fudi.fd_newkey;
+ }
if (arg != NULL && (fudi.fd_di == NULL || !tv_is_func(fudi.fd_di->di_tv))) {
int j = (*arg == K_SPECIAL) ? 3 : 0;
while (arg[j] != NUL && (j == 0 ? eval_isnamec1(arg[j])
- : eval_isnamec(arg[j])))
+ : eval_isnamec(arg[j]))) {
++j;
- if (arg[j] != NUL)
+ }
+ if (arg[j] != NUL) {
emsg_funcname((char *)e_invarg2, arg);
+ }
}
// Disallow using the g: dict.
if (fudi.fd_dict != NULL && fudi.fd_dict->dv_scope == VAR_DEF_SCOPE) {
@@ -2139,7 +2155,7 @@ void ex_function(exarg_T *eap)
p += 7;
if (current_funccal == NULL) {
emsg_funcname(N_
- ("E932: Closure function should not be at top level: %s"),
+ ("E932: Closure function should not be at top level: %s"),
name == NULL ? (char_u *)"" : name);
goto erret;
}
@@ -2164,14 +2180,16 @@ void ex_function(exarg_T *eap)
* whole function before telling him it doesn't work! For a script we
* need to skip the body to be able to find what follows. */
if (!eap->skip && !eap->forceit) {
- if (fudi.fd_dict != NULL && fudi.fd_newkey == NULL)
+ if (fudi.fd_dict != NULL && fudi.fd_newkey == NULL) {
EMSG(_(e_funcdict));
- else if (name != NULL && find_func(name) != NULL)
+ } else if (name != NULL && find_func(name) != NULL) {
emsg_funcname(e_funcexts, name);
+ }
}
- if (!eap->skip && did_emsg)
+ if (!eap->skip && did_emsg) {
goto erret;
+ }
if (!ui_has(kUICmdline)) {
msg_putchar('\n'); // don't overwrite the function name
@@ -2195,9 +2213,9 @@ void ex_function(exarg_T *eap)
// Use eap->arg, split up in parts by line breaks.
theline = line_arg;
p = vim_strchr(theline, '\n');
- if (p == NULL)
+ if (p == NULL) {
line_arg += STRLEN(line_arg);
- else {
+ } else {
*p = NUL;
line_arg = p + 1;
}
@@ -2225,7 +2243,7 @@ void ex_function(exarg_T *eap)
// Detect line continuation: sourcing_lnum increased more than one.
sourcing_lnum_off = get_sourced_lnum(eap->getline, eap->cookie);
if (sourcing_lnum < sourcing_lnum_off) {
- sourcing_lnum_off -= sourcing_lnum;
+ sourcing_lnum_off -= sourcing_lnum;
} else {
sourcing_lnum_off = 0;
}
@@ -2289,13 +2307,14 @@ void ex_function(exarg_T *eap)
/* Increase indent inside "if", "while", "for" and "try", decrease
* at "end". */
- if (indent > 2 && STRNCMP(p, "end", 3) == 0)
+ if (indent > 2 && STRNCMP(p, "end", 3) == 0) {
indent -= 2;
- else if (STRNCMP(p, "if", 2) == 0
- || STRNCMP(p, "wh", 2) == 0
- || STRNCMP(p, "for", 3) == 0
- || STRNCMP(p, "try", 3) == 0)
+ } else if (STRNCMP(p, "if", 2) == 0
+ || STRNCMP(p, "wh", 2) == 0
+ || STRNCMP(p, "for", 3) == 0
+ || STRNCMP(p, "try", 3) == 0) {
indent += 2;
+ }
// Check for defining a function inside this function.
if (checkforcmd(&p, "function", 2)) {
@@ -2345,10 +2364,11 @@ void ex_function(exarg_T *eap)
&& (!ASCII_ISALPHA(p[2]) || p[2] == 's')))) {
// ":python <<" continues until a dot, like ":append"
p = skipwhite(arg + 2);
- if (*p == NUL)
+ if (*p == NUL) {
skip_until = vim_strsave((char_u *)".");
- else
+ } else {
skip_until = vim_strsave(p);
+ }
}
// Check for ":let v =<< [trim] EOF"
@@ -2391,8 +2411,9 @@ void ex_function(exarg_T *eap)
/* Add NULL lines for continuation lines, so that the line count is
* equal to the index in the growarray. */
- while (sourcing_lnum_off-- > 0)
+ while (sourcing_lnum_off-- > 0) {
((char_u **)(newlines.ga_data))[newlines.ga_len++] = NULL;
+ }
// Check for end of eap->arg.
if (line_arg != NULL && *line_arg == NUL) {
@@ -2402,8 +2423,9 @@ void ex_function(exarg_T *eap)
/* Don't define the function when skipping commands or when an error was
* detected. */
- if (eap->skip || did_emsg)
+ if (eap->skip || did_emsg) {
goto erret;
+ }
/*
* If there are no errors, add the function
@@ -2412,7 +2434,7 @@ void ex_function(exarg_T *eap)
v = find_var((const char *)name, STRLEN(name), &ht, false);
if (v != NULL && v->di_tv.v_type == VAR_FUNC) {
emsg_funcname(N_("E707: Function name conflicts with variable: %s"),
- name);
+ name);
goto erret;
}
@@ -2428,7 +2450,7 @@ void ex_function(exarg_T *eap)
}
if (fp->uf_calls > 0) {
emsg_funcname(N_("E127: Cannot redefine function %s: It is in use"),
- name);
+ name);
goto erret;
}
if (fp->uf_refcount > 1) {
@@ -2476,7 +2498,7 @@ void ex_function(exarg_T *eap)
if (fp == NULL) {
if (fudi.fd_dict == NULL && vim_strchr(name, AUTOLOAD_CHAR) != NULL) {
int slen, plen;
- char_u *scriptname;
+ char_u *scriptname;
// Check that the autoload name matches the script name.
int j = FAIL;
@@ -2486,14 +2508,14 @@ void ex_function(exarg_T *eap)
plen = (int)STRLEN(p);
slen = (int)STRLEN(sourcing_name);
if (slen > plen && fnamecmp(p,
- sourcing_name + slen - plen) == 0)
+ sourcing_name + slen - plen) == 0) {
j = OK;
+ }
xfree(scriptname);
}
if (j == FAIL) {
- EMSG2(_(
- "E746: Function name does not match script file name: %s"),
- name);
+ EMSG2(_("E746: Function name does not match script file name: %s"),
+ name);
goto erret;
}
}
@@ -2634,8 +2656,8 @@ bool function_exists(const char *const name, bool no_deref)
char_u *get_user_func_name(expand_T *xp, int idx)
{
static size_t done;
- static hashitem_T *hi;
- ufunc_T *fp;
+ static hashitem_T *hi;
+ ufunc_T *fp;
if (idx == 0) {
done = 0;
@@ -2643,10 +2665,12 @@ char_u *get_user_func_name(expand_T *xp, int idx)
}
assert(hi);
if (done < func_hashtab.ht_used) {
- if (done++ > 0)
+ if (done++ > 0) {
++hi;
- while (HASHITEM_EMPTY(hi))
+ }
+ while (HASHITEM_EMPTY(hi)) {
++hi;
+ }
fp = HI2UF(hi);
if ((fp->uf_flags & FC_DICT)
@@ -2661,8 +2685,9 @@ char_u *get_user_func_name(expand_T *xp, int idx)
cat_func_name(IObuff, fp);
if (xp->xp_context != EXPAND_USER_FUNC) {
STRCAT(IObuff, "(");
- if (!fp->uf_varargs && GA_EMPTY(&fp->uf_args))
+ if (!fp->uf_varargs && GA_EMPTY(&fp->uf_args)) {
STRCAT(IObuff, ")");
+ }
}
return IObuff;
}
@@ -2672,17 +2697,18 @@ char_u *get_user_func_name(expand_T *xp, int idx)
/// ":delfunction {name}"
void ex_delfunction(exarg_T *eap)
{
- ufunc_T *fp = NULL;
- char_u *p;
- char_u *name;
+ ufunc_T *fp = NULL;
+ char_u *p;
+ char_u *name;
funcdict_T fudi;
p = eap->arg;
name = trans_function_name(&p, eap->skip, 0, &fudi, NULL);
xfree(fudi.fd_newkey);
if (name == NULL) {
- if (fudi.fd_dict != NULL && !eap->skip)
+ if (fudi.fd_dict != NULL && !eap->skip) {
EMSG(_(e_funcref));
+ }
return;
}
if (!ends_excmd(*skipwhite(p))) {
@@ -2691,11 +2717,13 @@ void ex_delfunction(exarg_T *eap)
return;
}
eap->nextcmd = check_nextcmd(p);
- if (eap->nextcmd != NULL)
+ if (eap->nextcmd != NULL) {
*p = NUL;
+ }
- if (!eap->skip)
+ if (!eap->skip) {
fp = find_func(name);
+ }
xfree(name);
if (!eap->skip) {
@@ -2713,7 +2741,7 @@ void ex_delfunction(exarg_T *eap)
// the reference count, and 1 is the initial refcount.
if (fp->uf_refcount > 2) {
EMSG2(_("Cannot delete function %s: It is being used internally"),
- eap->arg);
+ eap->arg);
return;
}
@@ -2761,8 +2789,8 @@ void func_unref(char_u *name)
abort();
}
#else
- internal_error("func_unref()");
- abort();
+ internal_error("func_unref()");
+ abort();
#endif
}
func_ptr_unref(fp);
@@ -2843,7 +2871,7 @@ static int can_free_funccal(funccall_T *fc, int copyID)
*/
void ex_return(exarg_T *eap)
{
- char_u *arg = eap->arg;
+ char_u *arg = eap->arg;
typval_T rettv;
int returning = FALSE;
@@ -2852,8 +2880,9 @@ void ex_return(exarg_T *eap)
return;
}
- if (eap->skip)
+ if (eap->skip) {
++emsg_skip;
+ }
eap->nextcmd = NULL;
if ((*arg != NUL && *arg != '|' && *arg != '\n')
@@ -2883,25 +2912,26 @@ void ex_return(exarg_T *eap)
eap->nextcmd = check_nextcmd(arg);
}
- if (eap->skip)
+ if (eap->skip) {
--emsg_skip;
+ }
}
// TODO(ZyX-I): move to eval/ex_cmds
/*
- * ":1,25call func(arg1, arg2)" function call.
+ * ":1,25call func(arg1, arg2)" function call.
*/
void ex_call(exarg_T *eap)
{
- char_u *arg = eap->arg;
- char_u *startarg;
- char_u *name;
- char_u *tofree;
+ char_u *arg = eap->arg;
+ char_u *startarg;
+ char_u *name;
+ char_u *tofree;
int len;
typval_T rettv;
linenr_T lnum;
- int doesrange;
+ bool doesrange;
bool failed = false;
funcdict_T fudi;
partial_T *partial = NULL;
@@ -2947,7 +2977,7 @@ void ex_call(exarg_T *eap)
rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this.
if (*startarg != '(') {
- EMSG2(_("E107: Missing parentheses: %s"), eap->arg);
+ EMSG2(_(e_missingparen), eap->arg);
goto end;
}
@@ -2965,15 +2995,22 @@ void ex_call(exarg_T *eap)
curwin->w_cursor.coladd = 0;
}
arg = startarg;
- if (get_func_tv(name, -1, &rettv, &arg,
- eap->line1, eap->line2, &doesrange,
- true, partial, fudi.fd_dict) == FAIL) {
+
+ funcexe_T funcexe = FUNCEXE_INIT;
+ funcexe.firstline = eap->line1;
+ funcexe.lastline = eap->line2;
+ funcexe.doesrange = &doesrange;
+ funcexe.evaluate = true;
+ funcexe.partial = partial;
+ funcexe.selfdict = fudi.fd_dict;
+ if (get_func_tv(name, -1, &rettv, &arg, &funcexe) == FAIL) {
failed = true;
break;
}
// Handle a function returning a Funcref, Dictionary or List.
- if (handle_subscript((const char **)&arg, &rettv, true, true)
+ if (handle_subscript((const char **)&arg, &rettv, true, true,
+ (const char_u *)name, (const char_u **)&name)
== FAIL) {
failed = true;
break;
@@ -3029,22 +3066,22 @@ int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv)
current_funccal->returned = false;
}
- /*
- * Cleanup (and inactivate) conditionals, but stop when a try conditional
- * not in its finally clause (which then is to be executed next) is found.
- * In this case, make the ":return" pending for execution at the ":endtry".
- * Otherwise, return normally.
- */
- idx = cleanup_conditionals(eap->cstack, 0, TRUE);
+ //
+ // Cleanup (and deactivate) conditionals, but stop when a try conditional
+ // not in its finally clause (which then is to be executed next) is found.
+ // In this case, make the ":return" pending for execution at the ":endtry".
+ // Otherwise, return normally.
+ //
+ idx = cleanup_conditionals(eap->cstack, 0, true);
if (idx >= 0) {
cstack->cs_pending[idx] = CSTP_RETURN;
- if (!is_cmd && !reanimate)
+ if (!is_cmd && !reanimate) {
/* A pending return again gets pending. "rettv" points to an
* allocated variable with the rettv of the original ":return"'s
* argument if present or is NULL else. */
cstack->cs_rettv[idx] = rettv;
- else {
+ } else {
/* When undoing a return in order to make it pending, get the stored
* return rettv. */
if (reanimate) {
@@ -3056,8 +3093,9 @@ int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv)
// Store the value of the pending return.
cstack->cs_rettv[idx] = xcalloc(1, sizeof(typval_T));
*(typval_T *)cstack->cs_rettv[idx] = *(typval_T *)rettv;
- } else
+ } else {
cstack->cs_rettv[idx] = NULL;
+ }
if (reanimate) {
/* The pending return value could be overwritten by a ":return"
@@ -3077,8 +3115,9 @@ int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv)
if (!reanimate && rettv != NULL) {
tv_clear(current_funccal->rettv);
*current_funccal->rettv = *(typval_T *)rettv;
- if (!is_cmd)
+ if (!is_cmd) {
xfree(rettv);
+ }
}
}
@@ -3095,7 +3134,7 @@ char_u *get_return_cmd(void *rettv)
char_u *tofree = NULL;
if (rettv != NULL) {
- tofree = s = (char_u *) encode_tv2echo((typval_T *) rettv, NULL);
+ tofree = s = (char_u *)encode_tv2echo((typval_T *)rettv, NULL);
}
if (s == NULL) {
s = (char_u *)"";
@@ -3103,8 +3142,9 @@ char_u *get_return_cmd(void *rettv)
STRCPY(IObuff, ":return ");
STRLCPY(IObuff + 8, s, IOSIZE - 8);
- if (STRLEN(s) + 8 >= IOSIZE)
+ if (STRLEN(s) + 8 >= IOSIZE) {
STRCPY(IObuff + IOSIZE - 4, "...");
+ }
xfree(tofree);
return vim_strsave(IObuff);
}
@@ -3116,19 +3156,20 @@ char_u *get_return_cmd(void *rettv)
*/
char_u *get_func_line(int c, void *cookie, int indent, bool do_concat)
{
- funccall_T *fcp = (funccall_T *)cookie;
- ufunc_T *fp = fcp->func;
- char_u *retval;
- garray_T *gap; // growarray with function lines
+ funccall_T *fcp = (funccall_T *)cookie;
+ ufunc_T *fp = fcp->func;
+ char_u *retval;
+ garray_T *gap; // growarray with function lines
// If breakpoints have been added/deleted need to check for it.
if (fcp->dbg_tick != debug_tick) {
fcp->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name,
- sourcing_lnum);
+ sourcing_lnum);
fcp->dbg_tick = debug_tick;
}
- if (do_profiling == PROF_YES)
+ if (do_profiling == PROF_YES) {
func_line_end(cookie);
+ }
gap = &fp->uf_lines;
if (((fp->uf_flags & FC_ABORT) && did_emsg && !aborted_in_try())
@@ -3145,8 +3186,9 @@ char_u *get_func_line(int c, void *cookie, int indent, bool do_concat)
} else {
retval = vim_strsave(((char_u **)(gap->ga_data))[fcp->linenr++]);
sourcing_lnum = fcp->linenr;
- if (do_profiling == PROF_YES)
+ if (do_profiling == PROF_YES) {
func_line_start(cookie);
+ }
}
}
@@ -3168,7 +3210,7 @@ char_u *get_func_line(int c, void *cookie, int indent, bool do_concat)
*/
int func_has_ended(void *cookie)
{
- funccall_T *fcp = (funccall_T *)cookie;
+ funccall_T *fcp = (funccall_T *)cookie;
/* Ignore the "abort" flag if the abortion behavior has been changed due to
* an error inside a try conditional. */
@@ -3424,8 +3466,7 @@ hashitem_T *find_hi_in_scoped_ht(const char *name, hashtab_T **pht)
}
/// Search variable in parent scope.
-dictitem_T *find_var_in_scoped_ht(const char *name, const size_t namelen,
- int no_autoload)
+dictitem_T *find_var_in_scoped_ht(const char *name, const size_t namelen, int no_autoload)
{
if (current_funccal == NULL || current_funccal->func->uf_scoped == NULL) {
return NULL;
@@ -3459,54 +3500,54 @@ dictitem_T *find_var_in_scoped_ht(const char *name, const size_t namelen,
/// Set "copyID + 1" in previous_funccal and callers.
bool set_ref_in_previous_funccal(int copyID)
{
- bool abort = false;
-
- for (funccall_T *fc = previous_funccal; !abort && fc != NULL;
+ for (funccall_T *fc = previous_funccal; fc != NULL;
fc = fc->caller) {
fc->fc_copyID = copyID + 1;
- abort = abort
- || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID + 1, NULL)
- || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID + 1, NULL)
- || set_ref_in_list(&fc->l_varlist, copyID + 1, NULL);
+ if (set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID + 1, NULL)
+ || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID + 1, NULL)
+ || set_ref_in_list(&fc->l_varlist, copyID + 1, NULL)) {
+ return true;
+ }
}
- return abort;
+ return false;
}
static bool set_ref_in_funccal(funccall_T *fc, int copyID)
{
- bool abort = false;
-
if (fc->fc_copyID != copyID) {
fc->fc_copyID = copyID;
- abort = abort
- || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID, NULL)
- || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID, NULL)
- || set_ref_in_list(&fc->l_varlist, copyID, NULL)
- || set_ref_in_func(NULL, fc->func, copyID);
+ if (set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID, NULL)
+ || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID, NULL)
+ || set_ref_in_list(&fc->l_varlist, copyID, NULL)
+ || set_ref_in_func(NULL, fc->func, copyID)) {
+ return true;
+ }
}
- return abort;
+ return false;
}
/// Set "copyID" in all local vars and arguments in the call stack.
bool set_ref_in_call_stack(int copyID)
{
- bool abort = false;
-
- for (funccall_T *fc = current_funccal; !abort && fc != NULL;
+ for (funccall_T *fc = current_funccal; fc != NULL;
fc = fc->caller) {
- abort = abort || set_ref_in_funccal(fc, copyID);
+ if (set_ref_in_funccal(fc, copyID)) {
+ return true;
+ }
}
// Also go through the funccal_stack.
- for (funccal_entry_T *entry = funccal_stack; !abort && entry != NULL;
+ for (funccal_entry_T *entry = funccal_stack; entry != NULL;
entry = entry->next) {
- for (funccall_T *fc = entry->top_funccal; !abort && fc != NULL;
+ for (funccall_T *fc = entry->top_funccal; fc != NULL;
fc = fc->caller) {
- abort = abort || set_ref_in_funccal(fc, copyID);
+ if (set_ref_in_funccal(fc, copyID)) {
+ return true;
+ }
}
}
- return abort;
+ return false;
}
/// Set "copyID" in all functions available by name.
@@ -3514,7 +3555,6 @@ bool set_ref_in_functions(int copyID)
{
int todo;
hashitem_T *hi = NULL;
- bool abort = false;
ufunc_T *fp;
todo = (int)func_hashtab.ht_used;
@@ -3522,24 +3562,25 @@ bool set_ref_in_functions(int copyID)
if (!HASHITEM_EMPTY(hi)) {
todo--;
fp = HI2UF(hi);
- if (!func_name_refcount(fp->uf_name)) {
- abort = abort || set_ref_in_func(NULL, fp, copyID);
+ if (!func_name_refcount(fp->uf_name)
+ && set_ref_in_func(NULL, fp, copyID)) {
+ return true;
}
}
}
- return abort;
+ return false;
}
/// Set "copyID" in all function arguments.
bool set_ref_in_func_args(int copyID)
{
- bool abort = false;
-
for (int i = 0; i < funcargs.ga_len; i++) {
- abort = abort || set_ref_in_item(((typval_T **)funcargs.ga_data)[i],
- copyID, NULL, NULL);
+ if (set_ref_in_item(((typval_T **)funcargs.ga_data)[i],
+ copyID, NULL, NULL)) {
+ return true;
+ }
}
- return abort;
+ return false;
}
/// Mark all lists and dicts referenced through function "name" with "copyID".
diff --git a/src/nvim/eval/userfunc.h b/src/nvim/eval/userfunc.h
index e8ad0bf1da..3f111343d2 100644
--- a/src/nvim/eval/userfunc.h
+++ b/src/nvim/eval/userfunc.h
@@ -28,11 +28,37 @@ typedef enum {
ERROR_OTHER,
ERROR_BOTH,
ERROR_DELETED,
+ ERROR_NOTMETHOD,
} FnameTransError;
+/// Used in funcexe_T. Returns the new argcount.
typedef int (*ArgvFunc)(int current_argcount, typval_T *argv, int argskip,
int called_func_argcount);
+/// Structure passed between functions dealing with function call execution.
+typedef struct {
+ ArgvFunc argv_func; ///< when not NULL, can be used to fill in arguments only
+ ///< when the invoked function uses them
+ linenr_T firstline; ///< first line of range
+ linenr_T lastline; ///< last line of range
+ bool *doesrange; ///< [out] if not NULL: function handled range
+ bool evaluate; ///< actually evaluate expressions
+ partial_T *partial; ///< for extra arguments
+ dict_T *selfdict; ///< Dictionary for "self"
+ typval_T *basetv; ///< base for base->method()
+} funcexe_T;
+
+#define FUNCEXE_INIT (funcexe_T) { \
+ .argv_func = NULL, \
+ .firstline = 0, \
+ .lastline = 0, \
+ .doesrange = NULL, \
+ .evaluate = false, \
+ .partial = NULL, \
+ .selfdict = NULL, \
+ .basetv = NULL, \
+}
+
#define FUNCARG(fp, j) ((char_u **)(fp->uf_args.ga_data))[j]
#define FUNCLINE(fp, j) ((char_u **)(fp->uf_lines.ga_data))[j]
diff --git a/src/nvim/event/libuv_process.c b/src/nvim/event/libuv_process.c
index c02f730431..0251ea9957 100644
--- a/src/nvim/event/libuv_process.c
+++ b/src/nvim/event/libuv_process.c
@@ -2,14 +2,13 @@
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <assert.h>
-
#include <uv.h>
+#include "nvim/event/libuv_process.h"
#include "nvim/event/loop.h"
+#include "nvim/event/process.h"
#include "nvim/event/rstream.h"
#include "nvim/event/wstream.h"
-#include "nvim/event/process.h"
-#include "nvim/event/libuv_process.h"
#include "nvim/log.h"
#include "nvim/macros.h"
#include "nvim/os/os.h"
@@ -68,7 +67,7 @@ int libuv_process_spawn(LibuvProcess *uvproc)
#ifdef WIN32
// pipe must be readable for IOCP to work on Windows.
uvproc->uvstdio[1].flags |= proc->overlapped ?
- (UV_READABLE_PIPE | UV_OVERLAPPED_PIPE) : 0;
+ (UV_READABLE_PIPE | UV_OVERLAPPED_PIPE) : 0;
#endif
uvproc->uvstdio[1].data.stream = STRUCT_CAST(uv_stream_t,
&proc->out.uv.pipe);
diff --git a/src/nvim/event/loop.c b/src/nvim/event/loop.c
index e341513ae1..892c46dd04 100644
--- a/src/nvim/event/loop.c
+++ b/src/nvim/event/loop.c
@@ -3,7 +3,6 @@
#include <stdarg.h>
#include <stdint.h>
-
#include <uv.h>
#include "nvim/event/loop.h"
diff --git a/src/nvim/event/multiqueue.c b/src/nvim/event/multiqueue.c
index f534fc483f..a90cbc4e80 100644
--- a/src/nvim/event/multiqueue.c
+++ b/src/nvim/event/multiqueue.c
@@ -49,8 +49,6 @@
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
-
-
#include <uv.h>
#include "nvim/event/multiqueue.h"
@@ -89,7 +87,7 @@ typedef struct {
# include "event/multiqueue.c.generated.h"
#endif
-static Event NILEVENT = { .handler = NULL, .argv = {NULL} };
+static Event NILEVENT = { .handler = NULL, .argv = { NULL } };
MultiQueue *multiqueue_new_parent(PutCallback put_cb, void *data)
{
@@ -104,8 +102,7 @@ MultiQueue *multiqueue_new_child(MultiQueue *parent)
return multiqueue_new(parent, NULL, NULL);
}
-static MultiQueue *multiqueue_new(MultiQueue *parent, PutCallback put_cb,
- void *data)
+static MultiQueue *multiqueue_new(MultiQueue *parent, PutCallback put_cb, void *data)
{
MultiQueue *rv = xmalloc(sizeof(MultiQueue));
QUEUE_INIT(&rv->headtail);
diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c
index b93d6cc0ab..dae4dad16d 100644
--- a/src/nvim/event/process.c
+++ b/src/nvim/event/process.c
@@ -3,20 +3,19 @@
#include <assert.h>
#include <stdlib.h>
-
#include <uv.h>
-#include "nvim/os/shell.h"
+#include "nvim/event/libuv_process.h"
#include "nvim/event/loop.h"
+#include "nvim/event/process.h"
#include "nvim/event/rstream.h"
#include "nvim/event/wstream.h"
-#include "nvim/event/process.h"
-#include "nvim/event/libuv_process.h"
-#include "nvim/os/process.h"
-#include "nvim/os/pty_process.h"
#include "nvim/globals.h"
-#include "nvim/macros.h"
#include "nvim/log.h"
+#include "nvim/macros.h"
+#include "nvim/os/process.h"
+#include "nvim/os/pty_process.h"
+#include "nvim/os/shell.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "event/process.c.generated.h"
@@ -62,14 +61,14 @@ int process_spawn(Process *proc, bool in, bool out, bool err)
int status;
switch (proc->type) {
- case kProcessTypeUv:
- status = libuv_process_spawn((LibuvProcess *)proc);
- break;
- case kProcessTypePty:
- status = pty_process_spawn((PtyProcess *)proc);
- break;
- default:
- abort();
+ case kProcessTypeUv:
+ status = libuv_process_spawn((LibuvProcess *)proc);
+ break;
+ case kProcessTypePty:
+ status = pty_process_spawn((PtyProcess *)proc);
+ break;
+ default:
+ abort();
}
if (status) {
@@ -88,7 +87,7 @@ int process_spawn(Process *proc, bool in, bool out, bool err)
} else {
process_close(proc);
}
- shell_free_argv(proc->argv);
+ process_free(proc);
proc->status = -1;
return status;
}
@@ -139,9 +138,8 @@ void process_teardown(Loop *loop) FUNC_ATTR_NONNULL_ALL
}
// Wait until all children exit and all close events are processed.
- LOOP_PROCESS_EVENTS_UNTIL(
- loop, loop->events, -1,
- kl_empty(loop->children) && multiqueue_empty(loop->events));
+ LOOP_PROCESS_EVENTS_UNTIL(loop, loop->events, -1,
+ kl_empty(loop->children) && multiqueue_empty(loop->events));
pty_process_teardown(loop);
}
@@ -189,7 +187,7 @@ int process_wait(Process *proc, int ms, MultiQueue *events)
// We can only return if all streams/handles are closed and the job
// exited.
LOOP_PROCESS_EVENTS_UNTIL(proc->loop, events, -1,
- proc->refcount == 1);
+ proc->refcount == 1);
} else {
LOOP_PROCESS_EVENTS(proc->loop, events, 0);
}
@@ -200,9 +198,9 @@ int process_wait(Process *proc, int ms, MultiQueue *events)
if (proc->refcount == 1) {
// Job exited, free its resources.
decref(proc);
- if (events) {
- // the decref call created an exit event, process it now
- multiqueue_process_events(events);
+ if (proc->events) {
+ // decref() created an exit event, process it now.
+ multiqueue_process_events(proc->events);
}
} else {
proc->refcount--;
@@ -222,16 +220,16 @@ void process_stop(Process *proc) FUNC_ATTR_NONNULL_ALL
proc->exit_signal = SIGTERM;
switch (proc->type) {
- case kProcessTypeUv:
- os_proc_tree_kill(proc->pid, SIGTERM);
- break;
- case kProcessTypePty:
- // close all streams for pty processes to send SIGHUP to the process
- process_close_streams(proc);
- pty_process_close_master((PtyProcess *)proc);
- break;
- default:
- abort();
+ case kProcessTypeUv:
+ os_proc_tree_kill(proc->pid, SIGTERM);
+ break;
+ case kProcessTypePty:
+ // close all streams for pty processes to send SIGHUP to the process
+ process_close_streams(proc);
+ pty_process_close_master((PtyProcess *)proc);
+ break;
+ default:
+ abort();
}
// (Re)start timer to verify that stopped process(es) died.
@@ -239,6 +237,15 @@ void process_stop(Process *proc) FUNC_ATTR_NONNULL_ALL
KILL_TIMEOUT_MS, 0);
}
+// Frees process-owned resources.
+void process_free(Process *proc) FUNC_ATTR_NONNULL_ALL
+{
+ if (proc->argv != NULL) {
+ shell_free_argv(proc->argv);
+ proc->argv = NULL;
+ }
+}
+
/// Sends SIGKILL (or SIGTERM..SIGKILL for PTY jobs) to processes that did
/// not terminate after process_stop().
static void children_kill_cb(uv_timer_t *handle)
@@ -269,9 +276,12 @@ static void children_kill_cb(uv_timer_t *handle)
static void process_close_event(void **argv)
{
Process *proc = argv[0];
- shell_free_argv(proc->argv);
- if (proc->cb) { // "on_exit" for jobstart(). See channel_job_start().
+ if (proc->cb) {
+ // User (hint: channel_job_start) is responsible for calling
+ // process_free().
proc->cb(proc, proc->status, proc->data);
+ } else {
+ process_free(proc);
}
}
@@ -313,14 +323,14 @@ static void process_close(Process *proc)
}
switch (proc->type) {
- case kProcessTypeUv:
- libuv_process_close((LibuvProcess *)proc);
- break;
- case kProcessTypePty:
- pty_process_close((PtyProcess *)proc);
- break;
- default:
- abort();
+ case kProcessTypeUv:
+ libuv_process_close((LibuvProcess *)proc);
+ break;
+ case kProcessTypePty:
+ pty_process_close((PtyProcess *)proc);
+ break;
+ default:
+ abort();
}
}
@@ -357,7 +367,7 @@ static void flush_stream(Process *proc, Stream *stream)
// Poll for data and process the generated events.
loop_poll_events(proc->loop, 0);
if (stream->events) {
- multiqueue_process_events(stream->events);
+ multiqueue_process_events(stream->events);
}
// Stream can be closed if it is empty.
diff --git a/src/nvim/event/process.h b/src/nvim/event/process.h
index 24debdb276..20c02e4900 100644
--- a/src/nvim/event/process.h
+++ b/src/nvim/event/process.h
@@ -26,6 +26,7 @@ struct process {
char **argv;
dict_T *env;
Stream in, out, err;
+ /// Exit handler. If set, user must call process_free().
process_exit_cb cb;
internal_process_cb internal_exit_cb, internal_close_cb;
bool closed, detach, overlapped;
diff --git a/src/nvim/event/rstream.c b/src/nvim/event/rstream.c
index efa56932d2..f070c8179f 100644
--- a/src/nvim/event/rstream.c
+++ b/src/nvim/event/rstream.c
@@ -2,19 +2,18 @@
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <assert.h>
-#include <stdint.h>
#include <stdbool.h>
+#include <stdint.h>
#include <stdlib.h>
-
#include <uv.h>
-#include "nvim/event/rstream.h"
#include "nvim/ascii.h"
-#include "nvim/vim.h"
-#include "nvim/memory.h"
+#include "nvim/event/loop.h"
+#include "nvim/event/rstream.h"
#include "nvim/log.h"
+#include "nvim/memory.h"
#include "nvim/misc1.h"
-#include "nvim/event/loop.h"
+#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "event/rstream.c.generated.h"
@@ -160,14 +159,13 @@ static void fread_idle_cb(uv_idle_t *handle)
}
// Synchronous read
- uv_fs_read(
- handle->loop,
- &req,
- stream->fd,
- &stream->uvbuf,
- 1,
- (int64_t) stream->fpos,
- NULL);
+ uv_fs_read(handle->loop,
+ &req,
+ stream->fd,
+ &stream->uvbuf,
+ 1,
+ (int64_t)stream->fpos,
+ NULL);
uv_fs_req_cleanup(&req);
@@ -178,7 +176,7 @@ static void fread_idle_cb(uv_idle_t *handle)
}
// no errors (req.result (ssize_t) is positive), it's safe to cast.
- size_t nread = (size_t) req.result;
+ size_t nread = (size_t)req.result;
rbuffer_produced(stream->buffer, nread);
stream->fpos += nread;
invoke_read_cb(stream, nread, false);
diff --git a/src/nvim/event/socket.c b/src/nvim/event/socket.c
index 23228aa63a..7948a7be83 100644
--- a/src/nvim/event/socket.c
+++ b/src/nvim/event/socket.c
@@ -3,30 +3,28 @@
#include <assert.h>
#include <stdint.h>
-
#include <uv.h>
+#include "nvim/ascii.h"
+#include "nvim/charset.h"
#include "nvim/event/loop.h"
-#include "nvim/event/socket.h"
#include "nvim/event/rstream.h"
+#include "nvim/event/socket.h"
#include "nvim/event/wstream.h"
-#include "nvim/os/os.h"
-#include "nvim/ascii.h"
-#include "nvim/vim.h"
-#include "nvim/strings.h"
-#include "nvim/path.h"
+#include "nvim/log.h"
+#include "nvim/macros.h"
#include "nvim/main.h"
#include "nvim/memory.h"
-#include "nvim/macros.h"
-#include "nvim/charset.h"
-#include "nvim/log.h"
+#include "nvim/os/os.h"
+#include "nvim/path.h"
+#include "nvim/strings.h"
+#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "event/socket.c.generated.h"
#endif
-int socket_watcher_init(Loop *loop, SocketWatcher *watcher,
- const char *endpoint)
+int socket_watcher_init(Loop *loop, SocketWatcher *watcher, const char *endpoint)
FUNC_ATTR_NONNULL_ALL
{
xstrlcpy(watcher->addr, endpoint, sizeof(watcher->addr));
@@ -56,9 +54,9 @@ int socket_watcher_init(Loop *loop, SocketWatcher *watcher,
int retval = uv_getaddrinfo(&loop->uv, &request, NULL, addr, port,
&(struct addrinfo){
- .ai_family = AF_UNSPEC,
- .ai_socktype = SOCK_STREAM,
- });
+ .ai_family = AF_UNSPEC,
+ .ai_socktype = SOCK_STREAM,
+ });
if (retval != 0) {
ELOG("Host lookup failed: %s", endpoint);
return retval;
@@ -106,7 +104,7 @@ int socket_watcher_start(SocketWatcher *watcher, int backlog, socket_cb cb)
uv_tcp_getsockname(&watcher->uv.tcp.handle, (struct sockaddr *)&sas,
&(int){ sizeof(sas) });
uint16_t port = (uint16_t)(
- (sas.ss_family == AF_INET)
+ (sas.ss_family == AF_INET)
? (STRUCT_CAST(struct sockaddr_in, &sas))->sin_port
: (STRUCT_CAST(struct sockaddr_in6, &sas))->sin6_port);
// v:servername uses the string from watcher->addr
@@ -183,7 +181,7 @@ static void connection_cb(uv_stream_t *handle, int status)
{
SocketWatcher *watcher = handle->data;
CREATE_EVENT(watcher->events, connection_event, 2, watcher,
- (void *)(uintptr_t)status);
+ (void *)(uintptr_t)status);
}
static void close_cb(uv_handle_t *handle)
@@ -203,9 +201,8 @@ static void connect_cb(uv_connect_t *req, int status)
}
}
-bool socket_connect(Loop *loop, Stream *stream,
- bool is_tcp, const char *address,
- int timeout, const char **error)
+bool socket_connect(Loop *loop, Stream *stream, bool is_tcp, const char *address, int timeout,
+ const char **error)
{
bool success = false;
int status;
@@ -243,7 +240,6 @@ tcp_retry:
uv_tcp_nodelay(tcp, true);
uv_tcp_connect(&req, tcp, addrinfo->ai_addr, connect_cb);
uv_stream = (uv_stream_t *)tcp;
-
} else {
uv_pipe_t *pipe = &stream->uv.pipe;
uv_pipe_init(&loop->uv, pipe, 0);
diff --git a/src/nvim/event/stream.c b/src/nvim/event/stream.c
index 1e9e530a42..b34fd73d52 100644
--- a/src/nvim/event/stream.c
+++ b/src/nvim/event/stream.c
@@ -2,15 +2,14 @@
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <assert.h>
-#include <stdio.h>
#include <stdbool.h>
-
+#include <stdio.h>
#include <uv.h>
+#include "nvim/event/stream.h"
#include "nvim/log.h"
-#include "nvim/rbuffer.h"
#include "nvim/macros.h"
-#include "nvim/event/stream.h"
+#include "nvim/rbuffer.h"
#ifdef WIN32
# include "nvim/os/os_win_console.h"
#endif
@@ -19,9 +18,9 @@
# include "event/stream.c.generated.h"
#endif
-// For compatbility with libuv < 1.19.0 (tested on 1.18.0)
+// For compatibility with libuv < 1.19.0 (tested on 1.18.0)
#if UV_VERSION_MINOR < 19
-#define uv_stream_get_write_queue_size(stream) stream->write_queue_size
+# define uv_stream_get_write_queue_size(stream) stream->write_queue_size
#endif
/// Sets the stream associated with `fd` to "blocking" mode.
@@ -77,7 +76,7 @@ void stream_init(Loop *loop, Stream *stream, int fd, uv_stream_t *uvstream)
uv_pipe_open(&stream->uv.pipe, fd);
stream->uvstream = STRUCT_CAST(uv_stream_t, &stream->uv.pipe);
#ifdef WIN32
- }
+ }
#endif
}
}
diff --git a/src/nvim/event/time.c b/src/nvim/event/time.c
index b7e30e392b..aa7b9cf2a1 100644
--- a/src/nvim/event/time.c
+++ b/src/nvim/event/time.c
@@ -2,7 +2,6 @@
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <stdint.h>
-
#include <uv.h>
#include "nvim/event/loop.h"
@@ -23,8 +22,7 @@ void time_watcher_init(Loop *loop, TimeWatcher *watcher, void *data)
watcher->blockable = false;
}
-void time_watcher_start(TimeWatcher *watcher, time_cb cb, uint64_t timeout,
- uint64_t repeat)
+void time_watcher_start(TimeWatcher *watcher, time_cb cb, uint64_t timeout, uint64_t repeat)
FUNC_ATTR_NONNULL_ALL
{
watcher->cb = cb;
diff --git a/src/nvim/event/wstream.c b/src/nvim/event/wstream.c
index 2baa667e7d..d81ffa5c15 100644
--- a/src/nvim/event/wstream.c
+++ b/src/nvim/event/wstream.c
@@ -2,17 +2,16 @@
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <assert.h>
-#include <stdint.h>
#include <stdbool.h>
+#include <stdint.h>
#include <stdlib.h>
-
#include <uv.h>
-#include "nvim/log.h"
#include "nvim/event/loop.h"
#include "nvim/event/wstream.h"
-#include "nvim/vim.h"
+#include "nvim/log.h"
#include "nvim/memory.h"
+#include "nvim/vim.h"
#define DEFAULT_MAXMEM 1024 * 1024 * 2000
@@ -117,10 +116,7 @@ err:
/// @param cb Pointer to function that will be responsible for freeing
/// the buffer data(passing 'free' will work as expected).
/// @return The allocated WBuffer instance
-WBuffer *wstream_new_buffer(char *data,
- size_t size,
- size_t refcount,
- wbuffer_data_finalizer cb)
+WBuffer *wstream_new_buffer(char *data, size_t size, size_t refcount, wbuffer_data_finalizer cb)
FUNC_ATTR_NONNULL_ARG(1)
{
WBuffer *rv = xmalloc(sizeof(WBuffer));
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 4af7794317..bbc1dd9717 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -7,54 +7,58 @@
#include <assert.h>
#include <float.h>
-#include <stdbool.h>
-#include <string.h>
-#include <stdlib.h>
#include <inttypes.h>
#include <math.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include "nvim/api/buffer.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/vim.h"
-#include "nvim/api/buffer.h"
-#include "nvim/log.h"
-#include "nvim/vim.h"
#include "nvim/ascii.h"
-#include "nvim/ex_cmds.h"
#include "nvim/buffer.h"
+#include "nvim/buffer_updates.h"
#include "nvim/change.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
+#include "nvim/decoration.h"
#include "nvim/diff.h"
#include "nvim/digraph.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
+#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
#include "nvim/ex_getln.h"
+#include "nvim/extmark.h"
#include "nvim/fileio.h"
#include "nvim/fold.h"
+#include "nvim/garray.h"
#include "nvim/getchar.h"
#include "nvim/highlight.h"
#include "nvim/indent.h"
-#include "nvim/buffer_updates.h"
+#include "nvim/log.h"
#include "nvim/main.h"
#include "nvim/mark.h"
-#include "nvim/extmark.h"
-#include "nvim/decoration.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
+#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
-#include "nvim/garray.h"
-#include "nvim/memory.h"
-#include "nvim/move.h"
#include "nvim/mouse.h"
+#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/ops.h"
#include "nvim/option.h"
+#include "nvim/os/input.h"
+#include "nvim/os/os.h"
+#include "nvim/os/shell.h"
+#include "nvim/os/time.h"
#include "nvim/os_unix.h"
#include "nvim/path.h"
+#include "nvim/plines.h"
#include "nvim/quickfix.h"
#include "nvim/regexp.h"
#include "nvim/screen.h"
@@ -65,11 +69,8 @@
#include "nvim/tag.h"
#include "nvim/ui.h"
#include "nvim/undo.h"
+#include "nvim/vim.h"
#include "nvim/window.h"
-#include "nvim/os/os.h"
-#include "nvim/os/shell.h"
-#include "nvim/os/input.h"
-#include "nvim/os/time.h"
/// Case matching style to use for :substitute
@@ -103,7 +104,7 @@ typedef struct {
// the preview window
typedef struct {
kvec_t(SubResult) subresults;
- linenr_T lines_needed; // lines neede in the preview window
+ linenr_T lines_needed; // lines needed in the preview window
} PreviewLines;
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -146,17 +147,17 @@ void do_ascii(const exarg_T *const eap)
dig = get_digraph_for_char(cval);
if (dig != NULL) {
- iobuff_len += (
- vim_snprintf((char *)IObuff + iobuff_len,
- sizeof(IObuff) - iobuff_len,
- _("<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s"),
- transchar(c), buf1, buf2, cval, cval, cval, dig));
+ iobuff_len += (
+ vim_snprintf((char *)IObuff + iobuff_len,
+ sizeof(IObuff) - iobuff_len,
+ _("<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s"),
+ transchar(c), buf1, buf2, cval, cval, cval, dig));
} else {
- iobuff_len += (
- vim_snprintf((char *)IObuff + iobuff_len,
- sizeof(IObuff) - iobuff_len,
- _("<%s>%s%s %d, Hex %02x, Octal %03o"),
- transchar(c), buf1, buf2, cval, cval, cval));
+ iobuff_len += (
+ vim_snprintf((char *)IObuff + iobuff_len,
+ sizeof(IObuff) - iobuff_len,
+ _("<%s>%s%s %d, Hex %02x, Octal %03o"),
+ transchar(c), buf1, buf2, cval, cval, cval));
}
c = cc[ci++];
@@ -196,21 +197,21 @@ void do_ascii(const exarg_T *const eap)
dig = get_digraph_for_char(c);
if (dig != NULL) {
- iobuff_len += (
- vim_snprintf((char *)IObuff + iobuff_len,
- sizeof(IObuff) - iobuff_len,
- (c < 0x10000
+ iobuff_len += (
+ vim_snprintf((char *)IObuff + iobuff_len,
+ sizeof(IObuff) - iobuff_len,
+ (c < 0x10000
? _("> %d, Hex %04x, Oct %o, Digr %s")
: _("> %d, Hex %08x, Oct %o, Digr %s")),
- c, c, c, dig));
+ c, c, c, dig));
} else {
- iobuff_len += (
- vim_snprintf((char *)IObuff + iobuff_len,
- sizeof(IObuff) - iobuff_len,
- (c < 0x10000
+ iobuff_len += (
+ vim_snprintf((char *)IObuff + iobuff_len,
+ sizeof(IObuff) - iobuff_len,
+ (c < 0x10000
? _("> %d, Hex %04x, Octal %o")
: _("> %d, Hex %08x, Octal %o")),
- c, c, c));
+ c, c, c));
}
if (ci == MAX_MCO) {
break;
@@ -237,26 +238,29 @@ void ex_align(exarg_T *eap)
int width;
if (curwin->w_p_rl) {
- /* switch left and right aligning */
- if (eap->cmdidx == CMD_right)
+ // switch left and right aligning
+ if (eap->cmdidx == CMD_right) {
eap->cmdidx = CMD_left;
- else if (eap->cmdidx == CMD_left)
+ } else if (eap->cmdidx == CMD_left) {
eap->cmdidx = CMD_right;
+ }
}
width = atoi((char *)eap->arg);
save_curpos = curwin->w_cursor;
- if (eap->cmdidx == CMD_left) { /* width is used for new indent */
- if (width >= 0)
+ if (eap->cmdidx == CMD_left) { // width is used for new indent
+ if (width >= 0) {
indent = width;
+ }
} else {
/*
* if 'textwidth' set, use it
* else if 'wrapmargin' set, use it
* if invalid value, use 80
*/
- if (width <= 0)
+ if (width <= 0) {
width = curbuf->b_p_tw;
+ }
if (width == 0 && curbuf->b_p_wm > 0) {
width = curwin->w_width_inner - curbuf->b_p_wm;
}
@@ -265,31 +269,33 @@ void ex_align(exarg_T *eap)
}
}
- if (u_save((linenr_T)(eap->line1 - 1), (linenr_T)(eap->line2 + 1)) == FAIL)
+ if (u_save((linenr_T)(eap->line1 - 1), (linenr_T)(eap->line2 + 1)) == FAIL) {
return;
+ }
for (curwin->w_cursor.lnum = eap->line1;
curwin->w_cursor.lnum <= eap->line2; ++curwin->w_cursor.lnum) {
- if (eap->cmdidx == CMD_left) /* left align */
+ if (eap->cmdidx == CMD_left) { // left align
new_indent = indent;
- else {
- has_tab = FALSE; /* avoid uninit warnings */
+ } else {
+ has_tab = FALSE; // avoid uninit warnings
len = linelen(eap->cmdidx == CMD_right ? &has_tab
- : NULL) - get_indent();
+ : NULL) - get_indent();
- if (len <= 0) /* skip blank lines */
+ if (len <= 0) { // skip blank lines
continue;
+ }
- if (eap->cmdidx == CMD_center)
+ if (eap->cmdidx == CMD_center) {
new_indent = (width - len) / 2;
- else {
- new_indent = width - len; /* right align */
+ } else {
+ new_indent = width - len; // right align
/*
* Make sure that embedded TABs don't make the text go too far
* to the right.
*/
- if (has_tab)
+ if (has_tab) {
while (new_indent > 0) {
(void)set_indent(new_indent, 0);
if (linelen(NULL) <= width) {
@@ -305,11 +311,13 @@ void ex_align(exarg_T *eap)
}
--new_indent;
}
+ }
}
}
- if (new_indent < 0)
+ if (new_indent < 0) {
new_indent = 0;
- (void)set_indent(new_indent, 0); /* set indent */
+ }
+ (void)set_indent(new_indent, 0); // set indent
}
changed_lines(eap->line1, 0, eap->line2 + 1, 0L, true);
curwin->w_cursor = save_curpos;
@@ -321,9 +329,9 @@ void ex_align(exarg_T *eap)
*/
static int linelen(int *has_tab)
{
- char_u *line;
- char_u *first;
- char_u *last;
+ char_u *line;
+ char_u *first;
+ char_u *last;
int save;
int len;
@@ -355,8 +363,8 @@ static int linelen(int *has_tab)
/* Buffer for two lines used during sorting. They are allocated to
* contain the longest line being sorted. */
-static char_u *sortbuf1;
-static char_u *sortbuf2;
+static char_u *sortbuf1;
+static char_u *sortbuf2;
static int sort_lc; ///< sort using locale
static int sort_ic; ///< ignore case
@@ -399,11 +407,13 @@ static int sort_compare(const void *s1, const void *s2)
/* If the user interrupts, there's no way to stop qsort() immediately, but
* if we return 0 every time, qsort will assume it's done sorting and
* exit. */
- if (sort_abort)
+ if (sort_abort) {
return 0;
+ }
fast_breakcheck();
- if (got_int)
+ if (got_int) {
sort_abort = TRUE;
+ }
// When sorting numbers "start_col_nr" is the number, not the column
// number.
@@ -435,9 +445,10 @@ static int sort_compare(const void *s1, const void *s2)
result = string_compare(sortbuf1, sortbuf2);
}
- /* If two lines have the same value, preserve the original line order. */
- if (result == 0)
+ // If two lines have the same value, preserve the original line order.
+ if (result == 0) {
return (int)(l1.lnum - l2.lnum);
+ }
return result;
}
@@ -450,9 +461,9 @@ void ex_sort(exarg_T *eap)
long maxlen = 0;
size_t count = (size_t)(eap->line2 - eap->line1 + 1);
size_t i;
- char_u *p;
- char_u *s;
- char_u *s2;
+ char_u *p;
+ char_u *s;
+ char_u *s2;
char_u c; // temporary character storage
bool unique = false;
long deleted;
@@ -598,7 +609,7 @@ void ex_sort(exarg_T *eap)
} else {
nrs[lnum - eap->line1].st_u.num.is_number = true;
vim_str2nr(s, NULL, NULL, sort_what,
- &nrs[lnum - eap->line1].st_u.num.value, NULL, 0);
+ &nrs[lnum - eap->line1].st_u.num.value, NULL, 0, false);
}
} else {
s = skipwhite(p);
@@ -622,10 +633,12 @@ void ex_sort(exarg_T *eap)
nrs[lnum - eap->line1].lnum = lnum;
- if (regmatch.regprog != NULL)
+ if (regmatch.regprog != NULL) {
fast_breakcheck();
- if (got_int)
+ }
+ if (got_int) {
goto sortend;
+ }
}
// Allocate a buffer that can hold the longest line.
@@ -635,8 +648,9 @@ void ex_sort(exarg_T *eap)
// Sort the array of line numbers. Note: can't be interrupted!
qsort((void *)nrs, count, sizeof(sorti_T), sort_compare);
- if (sort_abort)
+ if (sort_abort) {
goto sortend;
+ }
bcount_t old_count = 0, new_count = 0;
@@ -664,8 +678,9 @@ void ex_sort(exarg_T *eap)
new_count += bytelen;
}
fast_breakcheck();
- if (got_int)
+ if (got_int) {
goto sortend;
+ }
}
// delete the original lines if appending worked
@@ -714,7 +729,7 @@ sortend:
void ex_retab(exarg_T *eap)
{
linenr_T lnum;
- int got_tab = FALSE;
+ bool got_tab = false;
long num_spaces = 0;
long num_tabs;
long len;
@@ -723,18 +738,18 @@ void ex_retab(exarg_T *eap)
long start_col = 0; // For start of white-space string
long start_vcol = 0; // For start of white-space string
long old_len;
- char_u *ptr;
- char_u *new_line = (char_u *)1; // init to non-NULL
- int did_undo; // called u_save for current line
+ char_u *ptr;
+ char_u *new_line = (char_u *)1; // init to non-NULL
+ bool did_undo; // called u_save for current line
long *new_vts_array = NULL;
char_u *new_ts_str; // string value of tab argument
int save_list;
- linenr_T first_line = 0; /* first changed line */
- linenr_T last_line = 0; /* last changed line */
+ linenr_T first_line = 0; // first changed line
+ linenr_T last_line = 0; // last changed line
save_list = curwin->w_p_list;
- curwin->w_p_list = 0; /* don't want list mode here */
+ curwin->w_p_list = 0; // don't want list mode here
new_ts_str = eap->arg;
if (!tabstop_set(eap->arg, &new_vts_array)) {
@@ -757,23 +772,24 @@ void ex_retab(exarg_T *eap)
ptr = ml_get(lnum);
col = 0;
vcol = 0;
- did_undo = FALSE;
+ did_undo = false;
for (;; ) {
if (ascii_iswhite(ptr[col])) {
if (!got_tab && num_spaces == 0) {
- /* First consecutive white-space */
+ // First consecutive white-space
start_vcol = vcol;
start_col = col;
}
- if (ptr[col] == ' ')
+ if (ptr[col] == ' ') {
num_spaces++;
- else
- got_tab = TRUE;
+ } else {
+ got_tab = true;
+ }
} else {
if (got_tab || (eap->forceit && num_spaces > 1)) {
- /* Retabulate this string of white-space */
+ // Retabulate this string of white-space
- /* len is virtual length of white string */
+ // len is virtual length of white string
len = num_spaces = vcol - start_vcol;
num_tabs = 0;
if (!curbuf->b_p_et) {
@@ -795,16 +811,17 @@ void ex_retab(exarg_T *eap)
}
}
- /* len is actual number of white characters used */
+ // len is actual number of white characters used
len = num_spaces + num_tabs;
old_len = (long)STRLEN(ptr);
long new_len = old_len - col + start_col + len + 1;
new_line = xmalloc(new_len);
- if (start_col > 0)
+ if (start_col > 0) {
memmove(new_line, ptr, (size_t)start_col);
+ }
memmove(new_line + start_col + len,
- ptr + col, (size_t)(old_len - col + 1));
+ ptr + col, (size_t)(old_len - col + 1));
ptr = new_line + start_col;
for (col = 0; col < len; col++) {
ptr[col] = (col < num_tabs) ? '\t' : ' ';
@@ -823,20 +840,23 @@ void ex_retab(exarg_T *eap)
col = start_col + len;
}
}
- got_tab = FALSE;
+ got_tab = false;
num_spaces = 0;
}
- if (ptr[col] == NUL)
+ if (ptr[col] == NUL) {
break;
- vcol += chartabsize(ptr + col, (colnr_T)vcol);
+ }
+ vcol += win_chartabsize(curwin, ptr + col, (colnr_T)vcol);
col += utfc_ptr2len(ptr + col);
}
- if (new_line == NULL) /* out of memory */
+ if (new_line == NULL) { // out of memory
break;
+ }
line_breakcheck();
}
- if (got_int)
+ if (got_int) {
EMSG(_(e_interr));
+ }
// If a single value was given then it can be considered equal to
// either the value of 'tabstop' or the value of 'vartabstop'.
@@ -854,7 +874,7 @@ void ex_retab(exarg_T *eap)
changed_lines(first_line, 0, last_line + 1, 0L, true);
}
- curwin->w_p_list = save_list; /* restore 'list' */
+ curwin->w_p_list = save_list; // restore 'list'
if (new_ts_str != NULL) { // set the new tabstop
// If 'vartabstop' is in use or if the value given to retab has more
@@ -886,7 +906,7 @@ void ex_retab(exarg_T *eap)
*/
int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
{
- char_u *str;
+ char_u *str;
linenr_T l;
linenr_T extra; // Num lines added before line1
linenr_T num_lines; // Num lines moved
@@ -921,14 +941,16 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
* First we copy the old text to its new location -- webb
* Also copy the flag that ":global" command uses.
*/
- if (u_save(dest, dest + 1) == FAIL)
+ if (u_save(dest, dest + 1) == FAIL) {
return FAIL;
+ }
for (extra = 0, l = line1; l <= line2; l++) {
str = vim_strsave(ml_get(l + extra));
ml_append(dest + l - line1, str, (colnr_T)0, false);
xfree(str);
- if (dest < line1)
+ if (dest < line1) {
extra++;
+ }
}
/*
@@ -984,17 +1006,19 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
/*
* Now we delete the original text -- webb
*/
- if (u_save(line1 + extra - 1, line2 + extra + 1) == FAIL)
+ if (u_save(line1 + extra - 1, line2 + extra + 1) == FAIL) {
return FAIL;
+ }
for (l = line1; l <= line2; l++) {
ml_delete(line1 + extra, true);
}
if (!global_busy && num_lines > p_report) {
- if (num_lines == 1)
+ if (num_lines == 1) {
MSG(_("1 line moved"));
- else
+ } else {
smsg(_("%" PRId64 " lines moved"), (int64_t)num_lines);
+ }
}
extmark_move_region(curbuf, line1-1, 0, start_byte,
@@ -1005,16 +1029,18 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
/*
* Leave the cursor on the last of the moved lines.
*/
- if (dest >= line1)
+ if (dest >= line1) {
curwin->w_cursor.lnum = dest;
- else
+ } else {
curwin->w_cursor.lnum = dest + (line2 - line1) + 1;
+ }
if (line1 < dest) {
dest += num_lines + 1;
last_line = curbuf->b_ml.ml_line_count;
- if (dest > last_line + 1)
+ if (dest > last_line + 1) {
dest = last_line + 1;
+ }
changed_lines(line1, 0, dest, 0L, false);
} else {
changed_lines(dest + 1, 0, line1 + num_lines, 0L, false);
@@ -1032,7 +1058,7 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
void ex_copy(linenr_T line1, linenr_T line2, linenr_T n)
{
linenr_T count;
- char_u *p;
+ char_u *p;
count = line2 - line1 + 1;
curbuf->b_op_start.lnum = n + 1;
@@ -1050,8 +1076,9 @@ void ex_copy(linenr_T line1, linenr_T line2, linenr_T n)
* line1 = start of source (while copying)
* line2 = end of source (while copying)
*/
- if (u_save(n, n + 1) == FAIL)
+ if (u_save(n, n + 1) == FAIL) {
return;
+ }
curwin->w_cursor.lnum = n;
while (line1 <= line2) {
@@ -1061,14 +1088,17 @@ void ex_copy(linenr_T line1, linenr_T line2, linenr_T n)
ml_append(curwin->w_cursor.lnum, p, (colnr_T)0, false);
xfree(p);
- /* situation 2: skip already copied lines */
- if (line1 == n)
+ // situation 2: skip already copied lines
+ if (line1 == n) {
line1 = curwin->w_cursor.lnum;
+ }
++line1;
- if (curwin->w_cursor.lnum < line1)
+ if (curwin->w_cursor.lnum < line1) {
++line1;
- if (curwin->w_cursor.lnum < line2)
+ }
+ if (curwin->w_cursor.lnum < line2) {
++line2;
+ }
++curwin->w_cursor.lnum;
}
@@ -1077,7 +1107,7 @@ void ex_copy(linenr_T line1, linenr_T line2, linenr_T n)
msgmore((long)count);
}
-static char_u *prevcmd = NULL; /* the previous command */
+static char_u *prevcmd = NULL; // the previous command
#if defined(EXITFREE)
void free_prev_shellcmd(void)
@@ -1088,12 +1118,11 @@ void free_prev_shellcmd(void)
#endif
/*
- * Handle the ":!cmd" command. Also for ":r !cmd" and ":w !cmd"
+ * Handle the ":!cmd" command. Also for ":r !cmd" and ":w !cmd"
* Bangs in the argument are replaced with the previously entered command.
* Remember the argument.
*/
-void do_bang(int addr_count, exarg_T *eap, bool forceit,
- bool do_in, bool do_out)
+void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out)
FUNC_ATTR_NONNULL_ALL
{
char_u *arg = eap->arg; // command
@@ -1101,9 +1130,9 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit,
linenr_T line2 = eap->line2; // end of range
char_u *newcmd = NULL; // the new command
bool free_newcmd = false; // need to free() newcmd
- char_u *t;
- char_u *p;
- char_u *trailarg;
+ char_u *t;
+ char_u *p;
+ char_u *trailarg;
int len;
int scroll_save = msg_scroll;
@@ -1115,8 +1144,8 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit,
return;
}
- if (addr_count == 0) { /* :! */
- msg_scroll = FALSE; /* don't scroll here */
+ if (addr_count == 0) { // :!
+ msg_scroll = FALSE; // don't scroll here
autowrite_all();
msg_scroll = scroll_save;
}
@@ -1129,8 +1158,9 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit,
trailarg = arg;
do {
len = (int)STRLEN(trailarg) + 1;
- if (newcmd != NULL)
+ if (newcmd != NULL) {
len += (int)STRLEN(newcmd);
+ }
if (ins_prevcmd) {
if (prevcmd == NULL) {
EMSG(_(e_noprev));
@@ -1141,10 +1171,12 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit,
}
t = xmalloc(len);
*t = NUL;
- if (newcmd != NULL)
+ if (newcmd != NULL) {
STRCAT(t, newcmd);
- if (ins_prevcmd)
+ }
+ if (ins_prevcmd) {
STRCAT(t, prevcmd);
+ }
p = t + STRLEN(t);
STRCAT(t, trailarg);
xfree(newcmd);
@@ -1157,9 +1189,9 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit,
trailarg = NULL;
while (*p) {
if (*p == '!') {
- if (p > newcmd && p[-1] == '\\')
+ if (p > newcmd && p[-1] == '\\') {
STRMOVE(p - 1, p);
- else {
+ } else {
trailarg = p;
*trailarg++ = NUL;
ins_prevcmd = true;
@@ -1173,7 +1205,7 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit,
xfree(prevcmd);
prevcmd = newcmd;
- if (bangredo) { /* put cmd in redo buffer for ! command */
+ if (bangredo) { // put cmd in redo buffer for ! command
/* If % or # appears in the command, it must have been escaped.
* Reescape them, so that redoing them does not substitute them by the
* buffername. */
@@ -1194,8 +1226,8 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit,
STRCAT(newcmd, p_shq);
free_newcmd = true;
}
- if (addr_count == 0) { /* :! */
- /* echo the command */
+ if (addr_count == 0) { // :!
+ // echo the command
msg_start();
msg_putchar(':');
msg_putchar('!');
@@ -1204,49 +1236,48 @@ void do_bang(int addr_count, exarg_T *eap, bool forceit,
ui_cursor_goto(msg_row, msg_col);
do_shell(newcmd, 0);
- } else { /* :range! */
+ } else { // :range!
/* Careful: This may recursively call do_bang() again! (because of
* autocommands) */
do_filter(line1, line2, eap, newcmd, do_in, do_out);
- apply_autocmds(EVENT_SHELLFILTERPOST, NULL, NULL, FALSE, curbuf);
+ apply_autocmds(EVENT_SHELLFILTERPOST, NULL, NULL, false, curbuf);
}
- if (free_newcmd)
+ if (free_newcmd) {
xfree(newcmd);
+ }
}
-// do_filter: filter lines through a command given by the user
-//
-// We mostly use temp files and the call_shell() routine here. This would
-// normally be done using pipes on a Unix system, but this is more portable
-// to non-Unix systems. The call_shell() routine needs to be able
-// to deal with redirection somehow, and should handle things like looking
-// at the PATH env. variable, and adding reasonable extensions to the
-// command name given by the user. All reasonable versions of call_shell()
-// do this.
-// Alternatively, if on Unix and redirecting input or output, but not both,
-// and the 'shelltemp' option isn't set, use pipes.
-// We use input redirection if do_in is true.
-// We use output redirection if do_out is true.
-static void do_filter(
- linenr_T line1,
- linenr_T line2,
- exarg_T *eap, /* for forced 'ff' and 'fenc' */
- char_u *cmd,
- bool do_in,
- bool do_out)
+/// do_filter: filter lines through a command given by the user
+///
+/// We mostly use temp files and the call_shell() routine here. This would
+/// normally be done using pipes on a Unix system, but this is more portable
+/// to non-Unix systems. The call_shell() routine needs to be able
+/// to deal with redirection somehow, and should handle things like looking
+/// at the PATH env. variable, and adding reasonable extensions to the
+/// command name given by the user. All reasonable versions of call_shell()
+/// do this.
+/// Alternatively, if on Unix and redirecting input or output, but not both,
+/// and the 'shelltemp' option isn't set, use pipes.
+/// We use input redirection if do_in is true.
+/// We use output redirection if do_out is true.
+///
+/// @param eap for forced 'ff' and 'fenc'
+static void do_filter(linenr_T line1, linenr_T line2, exarg_T *eap, char_u *cmd, bool do_in,
+ bool do_out)
{
- char_u *itmp = NULL;
- char_u *otmp = NULL;
+ char_u *itmp = NULL;
+ char_u *otmp = NULL;
linenr_T linecount;
linenr_T read_linecount;
pos_T cursor_save;
- char_u *cmd_buf;
- buf_T *old_curbuf = curbuf;
+ char_u *cmd_buf;
+ buf_T *old_curbuf = curbuf;
int shell_flags = 0;
const int stmp = p_stmp;
- if (*cmd == NUL) /* no filter command */
+ if (*cmd == NUL) { // no filter command
return;
+ }
cursor_save = curwin->w_cursor;
@@ -1269,8 +1300,9 @@ static void do_filter(
* pipe only need to do 3.
*/
- if (do_out)
+ if (do_out) {
shell_flags |= kShellOptDoOut;
+ }
if (!do_in && do_out && !stmp) {
// Use a pipe to fetch stdout of the command, do not use a temp file.
@@ -1289,7 +1321,7 @@ static void do_filter(
curbuf->b_op_end.lnum = line2;
curwin->w_cursor.lnum = line2;
} else if ((do_in && (itmp = vim_tempname()) == NULL)
- || (do_out && (otmp = vim_tempname()) == NULL)) {
+ || (do_out && (otmp = vim_tempname()) == NULL)) {
EMSG(_(e_notmp));
goto filterend;
}
@@ -1298,7 +1330,7 @@ static void do_filter(
* The writing and reading of temp files will not be shown.
* Vi also doesn't do this and the messages are not very informative.
*/
- ++no_wait_return; /* don't call wait_return() while busy */
+ ++no_wait_return; // don't call wait_return() while busy
if (itmp != NULL && buf_write(curbuf, itmp, NULL, line1, line2, eap,
false, false, false, true) == FAIL) {
msg_putchar('\n'); // Keep message from buf_write().
@@ -1308,18 +1340,20 @@ static void do_filter(
}
goto filterend;
}
- if (curbuf != old_curbuf)
+ if (curbuf != old_curbuf) {
goto filterend;
+ }
- if (!do_out)
+ if (!do_out) {
msg_putchar('\n');
+ }
- /* Create the shell command in allocated memory. */
+ // Create the shell command in allocated memory.
cmd_buf = make_filter_cmd(cmd, itmp, otmp);
ui_cursor_goto(Rows - 1, 0);
if (do_out) {
- if (u_save((linenr_T)(line2), (linenr_T)(line2 + 1)) == FAIL) {
+ if (u_save((line2), (linenr_T)(line2 + 1)) == FAIL) {
xfree(cmd_buf);
goto error;
}
@@ -1350,8 +1384,9 @@ static void do_filter(
}
goto error;
}
- if (curbuf != old_curbuf)
+ if (curbuf != old_curbuf) {
goto filterend;
+ }
}
read_linecount = curbuf->b_ml.ml_line_count - read_linecount;
@@ -1385,11 +1420,11 @@ static void do_filter(
* Adjust '[ and '] (set by buf_write()).
*/
curwin->w_cursor.lnum = line1;
- del_lines(linecount, TRUE);
- curbuf->b_op_start.lnum -= linecount; /* adjust '[ */
- curbuf->b_op_end.lnum -= linecount; /* adjust '] */
- write_lnum_adjust(-linecount); /* adjust last line
- for next write */
+ del_lines(linecount, true);
+ curbuf->b_op_start.lnum -= linecount; // adjust '[
+ curbuf->b_op_end.lnum -= linecount; // adjust ']
+ write_lnum_adjust(-linecount); // adjust last line
+ // for next write
foldUpdate(curwin, curbuf->b_op_start.lnum, curbuf->b_op_end.lnum);
} else {
/*
@@ -1399,22 +1434,24 @@ static void do_filter(
curwin->w_cursor.lnum = curbuf->b_op_end.lnum;
}
- beginline(BL_WHITE | BL_FIX); /* cursor on first non-blank */
+ beginline(BL_WHITE | BL_FIX); // cursor on first non-blank
--no_wait_return;
if (linecount > p_report) {
if (do_in) {
vim_snprintf((char *)msg_buf, sizeof(msg_buf),
- _("%" PRId64 " lines filtered"), (int64_t)linecount);
- if (msg(msg_buf) && !msg_scroll)
- /* save message to display it after redraw */
+ _("%" PRId64 " lines filtered"), (int64_t)linecount);
+ if (msg(msg_buf) && !msg_scroll) {
+ // save message to display it after redraw
set_keep_msg(msg_buf, 0);
- } else
+ }
+ } else {
msgmore((long)linecount);
+ }
}
} else {
error:
- /* put cursor back in same position for ":w !cmd" */
+ // put cursor back in same position for ":w !cmd"
curwin->w_cursor = cursor_save;
--no_wait_return;
wait_return(FALSE);
@@ -1426,21 +1463,21 @@ filterend:
--no_wait_return;
EMSG(_("E135: *Filter* Autocommands must not change current buffer"));
}
- if (itmp != NULL)
+ if (itmp != NULL) {
os_remove((char *)itmp);
- if (otmp != NULL)
+ }
+ if (otmp != NULL) {
os_remove((char *)otmp);
+ }
xfree(itmp);
xfree(otmp);
}
-// Call a shell to execute a command.
-// When "cmd" is NULL start an interactive shell.
-void
-do_shell(
- char_u *cmd,
- int flags // may be SHELL_DOOUT when output is redirected
-)
+/// Call a shell to execute a command.
+/// When "cmd" is NULL start an interactive shell.
+///
+/// @param flags may be SHELL_DOOUT when output is redirected
+void do_shell(char_u *cmd, int flags)
{
// Disallow shell commands from .exrc and .vimrc in current directory for
// security reasons.
@@ -1482,7 +1519,7 @@ do_shell(
msg_row = Rows - 1;
msg_col = 0;
- apply_autocmds(EVENT_SHELLCMDPOST, NULL, NULL, FALSE, curbuf);
+ apply_autocmds(EVENT_SHELLCMDPOST, NULL, NULL, false, curbuf);
}
#if !defined(UNIX)
@@ -1522,11 +1559,11 @@ char_u *make_filter_cmd(char_u *cmd, char_u *itmp, char_u *otmp)
size_t len = STRLEN(cmd) + 1; // At least enough space for cmd + NULL.
- len += is_fish_shell ? sizeof("begin; ""; end") - 1
- : sizeof("("")") - 1;
+ len += is_fish_shell ? sizeof("begin; " "; end") - 1
+ : sizeof("(" ")") - 1;
if (itmp != NULL) {
- len += STRLEN(itmp) + sizeof(" { "" < "" } ") - 1;
+ len += STRLEN(itmp) + sizeof(" { " " < " " } ") - 1;
}
if (otmp != NULL) {
len += STRLEN(otmp) + STRLEN(p_srr) + 2; // two extra spaces (" "),
@@ -1574,9 +1611,9 @@ char_u *make_filter_cmd(char_u *cmd, char_u *itmp, char_u *otmp)
}
#endif
if (otmp != NULL) {
- append_redir(buf, len, (char *) p_srr, (char *) otmp);
+ append_redir(buf, len, (char *)p_srr, (char *)otmp);
}
- return (char_u *) buf;
+ return (char_u *)buf;
}
/// Append output redirection for the given file to the end of the buffer
@@ -1588,8 +1625,8 @@ char_u *make_filter_cmd(char_u *cmd, char_u *itmp, char_u *otmp)
/// a space, opt, a space and then fname if `%s` is not found
/// there.
/// @param[in] fname File name to append.
-void append_redir(char *const buf, const size_t buflen,
- const char *const opt, const char *const fname)
+void append_redir(char *const buf, const size_t buflen, const char *const opt,
+ const char *const fname)
{
char *const end = buf + strlen(buf);
// find "%s"
@@ -1603,9 +1640,9 @@ void append_redir(char *const buf, const size_t buflen,
}
if (p != NULL) {
*end = ' '; // not really needed? Not with sh, ksh or bash
- vim_snprintf(end + 1, (size_t) (buflen - (end + 1 - buf)), opt, fname);
+ vim_snprintf(end + 1, (size_t)(buflen - (end + 1 - buf)), opt, fname);
} else {
- vim_snprintf(end, (size_t) (buflen - (end - buf)), " %s %s", opt, fname);
+ vim_snprintf(end, (size_t)(buflen - (end - buf)), " %s %s", opt, fname);
}
}
@@ -1635,28 +1672,30 @@ void print_line(linenr_T lnum, int use_number, int list)
msg_start();
silent_mode = FALSE;
- info_message = TRUE; /* use mch_msg(), not mch_errmsg() */
+ info_message = true; // use mch_msg(), not mch_errmsg()
print_line_no_prefix(lnum, use_number, list);
if (save_silent) {
msg_putchar('\n');
ui_flush();
silent_mode = save_silent;
}
- info_message = FALSE;
+ info_message = false;
}
int rename_buffer(char_u *new_fname)
{
- char_u *fname, *sfname, *xfname;
- buf_T *buf;
+ char_u *fname, *sfname, *xfname;
+ buf_T *buf;
buf = curbuf;
- apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, FALSE, curbuf);
- /* buffer changed, don't change name now */
- if (buf != curbuf)
+ apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, false, curbuf);
+ // buffer changed, don't change name now
+ if (buf != curbuf) {
return FAIL;
- if (aborting()) /* autocmds may abort script processing */
+ }
+ if (aborting()) { // autocmds may abort script processing
return FAIL;
+ }
/*
* The name of the current buffer will be changed.
* A new (unlisted) buffer entry needs to be made to hold the old file
@@ -1683,8 +1722,8 @@ int rename_buffer(char_u *new_fname)
}
xfree(fname);
xfree(sfname);
- apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, FALSE, curbuf);
- /* Change directories when the 'acd' option is set. */
+ apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, false, curbuf);
+ // Change directories when the 'acd' option is set.
do_autochdir();
return OK;
}
@@ -1722,8 +1761,9 @@ void ex_file(exarg_T *eap)
*/
void ex_update(exarg_T *eap)
{
- if (curbufIsChanged())
+ if (curbufIsChanged()) {
(void)do_write(eap);
+ }
}
/*
@@ -1755,15 +1795,16 @@ void ex_write(exarg_T *eap)
int do_write(exarg_T *eap)
{
int other;
- char_u *fname = NULL; /* init to shut up gcc */
- char_u *ffname;
+ char_u *fname = NULL; // init to shut up gcc
+ char_u *ffname;
int retval = FAIL;
- char_u *free_fname = NULL;
- buf_T *alt_buf = NULL;
- int name_was_missing;
+ char_u *free_fname = NULL;
+ buf_T *alt_buf = NULL;
+ int name_was_missing;
- if (not_writing()) /* check 'write' option */
+ if (not_writing()) { // check 'write' option
return FAIL;
+ }
ffname = eap->arg;
if (*ffname == NUL) {
@@ -1779,8 +1820,9 @@ int do_write(exarg_T *eap)
* When out-of-memory, keep unexpanded file name, because we MUST be
* able to write the file in this situation.
*/
- if (free_fname != NULL)
+ if (free_fname != NULL) {
ffname = free_fname;
+ }
other = otherfile(ffname);
}
@@ -1789,10 +1831,11 @@ int do_write(exarg_T *eap)
*/
if (other) {
if (vim_strchr(p_cpo, CPO_ALTWRITE) != NULL
- || eap->cmdidx == CMD_saveas)
+ || eap->cmdidx == CMD_saveas) {
alt_buf = setaltfname(ffname, fname, (linenr_T)1);
- else
+ } else {
alt_buf = buflist_findname(ffname);
+ }
if (alt_buf != NULL && alt_buf->b_ml.ml_mfp != NULL) {
/* Overwriting a file that is loaded in another buffer is not a
* good idea. */
@@ -1823,8 +1866,9 @@ int do_write(exarg_T *eap)
&& !p_wa) {
if (p_confirm || cmdmod.confirm) {
if (vim_dialog_yesno(VIM_QUESTION, NULL,
- (char_u *)_("Write partial file?"), 2) != VIM_YES)
+ (char_u *)_("Write partial file?"), 2) != VIM_YES) {
goto theend;
+ }
eap->forceit = TRUE;
} else {
EMSG(_("E140: Use ! to write partial buffer"));
@@ -1835,12 +1879,12 @@ int do_write(exarg_T *eap)
if (check_overwrite(eap, curbuf, fname, ffname, other) == OK) {
if (eap->cmdidx == CMD_saveas && alt_buf != NULL) {
- buf_T *was_curbuf = curbuf;
+ buf_T *was_curbuf = curbuf;
- apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, FALSE, curbuf);
- apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, FALSE, alt_buf);
+ apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, false, curbuf);
+ apply_autocmds(EVENT_BUFFILEPRE, NULL, NULL, false, alt_buf);
if (curbuf != was_curbuf || aborting()) {
- /* buffer changed, don't change name now */
+ // buffer changed, don't change name now
retval = FAIL;
goto theend;
}
@@ -1859,14 +1903,14 @@ int do_write(exarg_T *eap)
alt_buf->b_sfname = curbuf->b_sfname;
curbuf->b_sfname = fname;
buf_name_changed(curbuf);
- apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, FALSE, curbuf);
- apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, FALSE, alt_buf);
+ apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, false, curbuf);
+ apply_autocmds(EVENT_BUFFILEPOST, NULL, NULL, false, alt_buf);
if (!alt_buf->b_p_bl) {
alt_buf->b_p_bl = TRUE;
apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, alt_buf);
}
if (curbuf != was_curbuf || aborting()) {
- /* buffer changed, don't write the file */
+ // buffer changed, don't write the file
retval = FAIL;
goto theend;
}
@@ -1886,13 +1930,13 @@ int do_write(exarg_T *eap)
name_was_missing = curbuf->b_ffname == NULL;
retval = buf_write(curbuf, ffname, fname, eap->line1, eap->line2,
- eap, eap->append, eap->forceit, TRUE, FALSE);
+ eap, eap->append, eap->forceit, TRUE, FALSE);
- /* After ":saveas fname" reset 'readonly'. */
+ // After ":saveas fname" reset 'readonly'.
if (eap->cmdidx == CMD_saveas) {
if (retval == OK) {
curbuf->b_p_ro = FALSE;
- redraw_tabline = TRUE;
+ redraw_tabline = true;
}
}
@@ -1908,21 +1952,16 @@ theend:
return retval;
}
-/*
- * Check if it is allowed to overwrite a file. If b_flags has BF_NOTEDITED,
- * BF_NEW or BF_READERR, check for overwriting current file.
- * May set eap->forceit if a dialog says it's OK to overwrite.
- * Return OK if it's OK, FAIL if it is not.
- */
-int
-check_overwrite(
- exarg_T *eap,
- buf_T *buf,
- char_u *fname, // file name to be used (can differ from
- // buf->ffname)
- char_u *ffname, // full path version of fname
- int other // writing under other name
-)
+/// Check if it is allowed to overwrite a file. If b_flags has BF_NOTEDITED,
+/// BF_NEW or BF_READERR, check for overwriting current file.
+/// May set eap->forceit if a dialog says it's OK to overwrite.
+///
+/// @param fname file name to be used (can differ from buf->ffname)
+/// @param ffname full path version of fname
+/// @param other writing under other name
+///
+/// @return OK if it's OK, FAIL if it is not.
+int check_overwrite(exarg_T *eap, buf_T *buf, char_u *fname, char_u *ffname, int other)
{
/*
* write to other file or b_flags set or not writing the whole file:
@@ -1948,8 +1987,9 @@ check_overwrite(
char_u buff[DIALOG_MSG_SIZE];
dialog_msg(buff, _("Overwrite existing file \"%s\"?"), fname);
- if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 2) != VIM_YES)
+ if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 2) != VIM_YES) {
return FAIL;
+ }
eap->forceit = TRUE;
} else {
EMSG(_(e_exists));
@@ -1957,11 +1997,11 @@ check_overwrite(
}
}
- /* For ":w! filename" check that no swap file exists for "filename". */
+ // For ":w! filename" check that no swap file exists for "filename".
if (other && !emsg_silent) {
- char_u *dir;
- char_u *p;
- char_u *swapname;
+ char_u *dir;
+ char_u *p;
+ char_u *swapname;
/* We only try the first entry in 'directory', without checking if
* it's writable. If the "." directory is not writable the write
@@ -1983,8 +2023,8 @@ check_overwrite(
char_u buff[DIALOG_MSG_SIZE];
dialog_msg(buff,
- _("Swap file \"%s\" exists, overwrite anyway?"),
- swapname);
+ _("Swap file \"%s\" exists, overwrite anyway?"),
+ swapname);
if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 2)
!= VIM_YES) {
xfree(swapname);
@@ -1993,7 +2033,7 @@ check_overwrite(
eap->forceit = TRUE;
} else {
EMSG2(_("E768: Swap file exists: %s (:silent! overrides)"),
- swapname);
+ swapname);
xfree(swapname);
return FAIL;
}
@@ -2011,14 +2051,16 @@ void ex_wnext(exarg_T *eap)
{
int i;
- if (eap->cmd[1] == 'n')
+ if (eap->cmd[1] == 'n') {
i = curwin->w_arg_idx + (int)eap->line2;
- else
+ } else {
i = curwin->w_arg_idx - (int)eap->line2;
+ }
eap->line1 = 1;
eap->line2 = curbuf->b_ml.ml_line_count;
- if (do_write(eap) != FAIL)
+ if (do_write(eap) != FAIL) {
do_argfile(eap, i);
+ }
}
/*
@@ -2058,7 +2100,7 @@ void do_wqall(exarg_T *eap)
++error;
} else if (check_readonly(&eap->forceit, buf)
|| check_overwrite(eap, buf, buf->b_fname, buf->b_ffname,
- FALSE) == FAIL) {
+ FALSE) == FAIL) {
++error;
} else {
bufref_T bufref;
@@ -2071,11 +2113,12 @@ void do_wqall(exarg_T *eap)
buf = firstbuf;
}
}
- eap->forceit = save_forceit; /* check_overwrite() may set it */
+ eap->forceit = save_forceit; // check_overwrite() may set it
}
if (exiting) {
- if (!error)
- getout(0); /* exit Vim */
+ if (!error) {
+ getout(0); // exit Vim
+ }
not_exiting();
}
}
@@ -2086,8 +2129,9 @@ void do_wqall(exarg_T *eap)
*/
int not_writing(void)
{
- if (p_write)
+ if (p_write) {
return FALSE;
+ }
EMSG(_("E142: File not written: Writing is disabled by 'write' option"));
return TRUE;
}
@@ -2107,28 +2151,30 @@ static int check_readonly(int *forceit, buf_T *buf)
if ((p_confirm || cmdmod.confirm) && buf->b_fname != NULL) {
char_u buff[DIALOG_MSG_SIZE];
- if (buf->b_p_ro)
+ if (buf->b_p_ro) {
dialog_msg(buff,
- _(
- "'readonly' option is set for \"%s\".\nDo you wish to write anyway?"),
- buf->b_fname);
- else
+ _( "'readonly' option is set for \"%s\".\nDo you wish to write anyway?"),
+ buf->b_fname);
+ } else {
dialog_msg(buff,
- _(
- "File permissions of \"%s\" are read-only.\nIt may still be possible to write it.\nDo you wish to try?"),
- buf->b_fname);
+ _(
+ "File permissions of \"%s\" are read-only.\nIt may still be possible to write it.\nDo you wish to try?"),
+ buf->b_fname);
+ }
if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 2) == VIM_YES) {
- /* Set forceit, to force the writing of a readonly file */
+ // Set forceit, to force the writing of a readonly file
*forceit = TRUE;
return FALSE;
- } else
+ } else {
return TRUE;
- } else if (buf->b_p_ro)
+ }
+ } else if (buf->b_p_ro) {
EMSG(_(e_readonly));
- else
+ } else {
EMSG2(_("E505: \"%s\" is read-only (add ! to override)"),
- buf->b_fname);
+ buf->b_fname);
+ }
return TRUE;
}
@@ -2144,14 +2190,13 @@ static int check_readonly(int *forceit, buf_T *buf)
// GETFILE_NOT_WRITTEN for "not written" error,
// GETFILE_SAME_FILE for success
// GETFILE_OPEN_OTHER for successfully opening another file.
-int getfile(int fnum, char_u *ffname_arg, char_u *sfname_arg, int setpm,
- linenr_T lnum, int forceit)
+int getfile(int fnum, char_u *ffname_arg, char_u *sfname_arg, int setpm, linenr_T lnum, int forceit)
{
char_u *ffname = ffname_arg;
char_u *sfname = sfname_arg;
int other;
int retval;
- char_u *free_me = NULL;
+ char_u *free_me = NULL;
if (text_locked()) {
return GETFILE_ERROR;
@@ -2161,12 +2206,13 @@ int getfile(int fnum, char_u *ffname_arg, char_u *sfname_arg, int setpm,
}
if (fnum == 0) {
- /* make ffname full path, set sfname */
+ // make ffname full path, set sfname
fname_expand(curbuf, &ffname, &sfname);
other = otherfile(ffname);
- free_me = ffname; /* has been allocated, free() later */
- } else
+ free_me = ffname; // has been allocated, free() later
+ } else {
other = (fnum != curbuf->b_fnum);
+ }
if (other) {
no_wait_return++; // don't wait for autowrite message
@@ -2183,10 +2229,12 @@ int getfile(int fnum, char_u *ffname_arg, char_u *sfname_arg, int setpm,
goto theend;
}
}
- if (other)
+ if (other) {
--no_wait_return;
- if (setpm)
+ }
+ if (setpm) {
setpcmark();
+ }
if (!other) {
if (lnum != 0) {
curwin->w_cursor.lnum = lnum;
@@ -2218,7 +2266,7 @@ theend:
/// - NULL to start an empty buffer
/// @param sfname the short file name (or NULL)
/// @param eap contains the command to be executed after loading the file
-/// and forced 'ff' and 'fenc'
+/// and forced 'ff' and 'fenc'. Can be NULL!
/// @param newlnum if > 0: put cursor on this line number (if possible)
/// ECMD_LASTL: use last position in loaded file
/// ECMD_LAST: use last position in all files
@@ -2236,55 +2284,52 @@ theend:
/// info of the previous buffer for "oldwin" is stored.
///
/// @return FAIL for failure, OK otherwise
-int do_ecmd(
- int fnum,
- char_u *ffname,
- char_u *sfname,
- exarg_T *eap, /* can be NULL! */
- linenr_T newlnum,
- int flags,
- win_T *oldwin
-)
+int do_ecmd(int fnum, char_u *ffname, char_u *sfname, exarg_T *eap, linenr_T newlnum, int flags,
+ win_T *oldwin)
{
- int other_file; /* TRUE if editing another file */
- int oldbuf; /* TRUE if using existing buffer */
- int auto_buf = FALSE; /* TRUE if autocommands brought us
- into the buffer unexpectedly */
- char_u *new_name = NULL;
- int did_set_swapcommand = FALSE;
- buf_T *buf;
- bufref_T bufref;
- bufref_T old_curbuf;
- char_u *free_fname = NULL;
+ bool other_file; // true if editing another file
+ int oldbuf; // TRUE if using existing buffer
+ bool auto_buf = false; // true if autocommands brought us
+ // into the buffer unexpectedly
+ char_u *new_name = NULL;
+ bool did_set_swapcommand = false;
+ buf_T *buf;
+ bufref_T bufref;
+ bufref_T old_curbuf;
+ char_u *free_fname = NULL;
int retval = FAIL;
long n;
pos_T orig_pos;
linenr_T topline = 0;
int newcol = -1;
int solcol = -1;
- pos_T *pos;
- char_u *command = NULL;
- int did_get_winopts = FALSE;
+ pos_T *pos;
+ char_u *command = NULL;
+ bool did_get_winopts = false;
int readfile_flags = 0;
bool did_inc_redrawing_disabled = false;
long *so_ptr = curwin->w_p_so >= 0 ? &curwin->w_p_so : &p_so;
- if (eap != NULL)
+ if (eap != NULL) {
command = eap->do_ecmd_cmd;
+ }
set_bufref(&old_curbuf, curbuf);
if (fnum != 0) {
- if (fnum == curbuf->b_fnum) /* file is already being edited */
- return OK; /* nothing to do */
- other_file = TRUE;
+ if (fnum == curbuf->b_fnum) { // file is already being edited
+ return OK; // nothing to do
+ }
+ other_file = true;
} else {
- /* if no short name given, use ffname for short name */
- if (sfname == NULL)
+ // if no short name given, use ffname for short name
+ if (sfname == NULL) {
sfname = ffname;
+ }
#ifdef USE_FNAME_CASE
- if (sfname != NULL)
+ if (sfname != NULL) {
path_fix_case(sfname); // set correct case for sfname
+ }
#endif
if ((flags & (ECMD_ADDBUF | ECMD_ALTBUF))
@@ -2292,19 +2337,19 @@ int do_ecmd(
goto theend;
}
- if (ffname == NULL)
- other_file = TRUE;
- /* there is no file name */
- else if (*ffname == NUL && curbuf->b_ffname == NULL)
- other_file = FALSE;
- else {
- if (*ffname == NUL) { /* re-edit with same file name */
+ if (ffname == NULL) {
+ other_file = true;
+ } else if (*ffname == NUL && curbuf->b_ffname == NULL) { // there is no file name
+ other_file = false;
+ } else {
+ if (*ffname == NUL) { // re-edit with same file name
ffname = curbuf->b_ffname;
sfname = curbuf->b_fname;
}
- free_fname = (char_u *)fix_fname((char *)ffname); /* may expand to full path name */
- if (free_fname != NULL)
+ free_fname = (char_u *)fix_fname((char *)ffname); // may expand to full path name
+ if (free_fname != NULL) {
ffname = free_fname;
+ }
other_file = otherfile(ffname);
}
}
@@ -2350,7 +2395,7 @@ int do_ecmd(
vim_snprintf(p, len, "%" PRId64 "G", (int64_t)newlnum);
}
set_vim_var_string(VV_SWAPCOMMAND, p, -1);
- did_set_swapcommand = TRUE;
+ did_set_swapcommand = true;
xfree(p);
}
@@ -2378,13 +2423,14 @@ int do_ecmd(
if (command != NULL) {
tlnum = atol((char *)command);
- if (tlnum <= 0)
+ if (tlnum <= 0) {
tlnum = 1L;
+ }
}
// Add BLN_NOCURWIN to avoid a new wininfo items are associated
// with the current window.
const buf_T *const newbuf
- = buflist_new(ffname, sfname, tlnum, BLN_LISTED | BLN_NOCURWIN);
+ = buflist_new(ffname, sfname, tlnum, BLN_LISTED | BLN_NOCURWIN);
if (newbuf != NULL && (flags & ECMD_ALTBUF)) {
curwin->w_alt_fnum = newbuf->b_fnum;
}
@@ -2398,8 +2444,9 @@ int do_ecmd(
}
set_bufref(&old_curbuf, curbuf);
}
- if (buf == NULL)
+ if (buf == NULL) {
goto theend;
+ }
if (buf->b_ml.ml_mfp == NULL) {
// No memfile yet.
oldbuf = false;
@@ -2458,7 +2505,7 @@ int do_ecmd(
delbuf_msg(new_name); // Frees new_name.
goto theend;
}
- if (aborting()) { /* autocmds may abort script processing */
+ if (aborting()) { // autocmds may abort script processing
xfree(new_name);
goto theend;
}
@@ -2480,10 +2527,9 @@ int do_ecmd(
// Close the link to the current buffer. This will set
// oldwin->w_buffer to NULL.
u_sync(false);
- const bool did_decrement = close_buffer(
- oldwin, curbuf,
- (flags & ECMD_HIDE) || curbuf->terminal ? 0 : DOBUF_UNLOAD,
- false);
+ const bool did_decrement = close_buffer(oldwin, curbuf,
+ (flags & ECMD_HIDE) || curbuf->terminal ? 0 : DOBUF_UNLOAD,
+ false);
// Autocommands may have closed the window.
if (win_valid(the_curwin)) {
@@ -2524,7 +2570,7 @@ int do_ecmd(
curbuf = buf;
++curbuf->b_nwindows;
- /* Set 'fileformat', 'binary' and 'fenc' when forced. */
+ // Set 'fileformat', 'binary' and 'fenc' when forced.
if (!oldbuf && eap != NULL) {
set_file_options(TRUE, eap);
set_forced_fenc(eap);
@@ -2536,8 +2582,7 @@ int do_ecmd(
* before, reset the local window options to the global
* values. Also restores old folding stuff. */
get_winopts(curbuf);
- did_get_winopts = TRUE;
-
+ did_get_winopts = true;
}
xfree(new_name);
au_new_curbuf.br_buf = NULL;
@@ -2569,10 +2614,12 @@ int do_ecmd(
/* If autocommands change buffers under our fingers, forget about
* editing the file. */
- if (buf != curbuf)
+ if (buf != curbuf) {
goto theend;
- if (aborting()) /* autocmds may abort script processing */
+ }
+ if (aborting()) { // autocmds may abort script processing
goto theend;
+ }
/* Since we are starting to edit a file, consider the filetype to be
* unset. Helps for when an autocommand changes files and expects syntax
@@ -2580,14 +2627,14 @@ int do_ecmd(
did_filetype = FALSE;
/*
- * other_file oldbuf
- * FALSE FALSE re-edit same file, buffer is re-used
- * FALSE TRUE re-edit same file, nothing changes
- * TRUE FALSE start editing new file, new buffer
- * TRUE TRUE start editing in existing buffer (nothing to do)
+ * other_file oldbuf
+ * FALSE FALSE re-edit same file, buffer is re-used
+ * FALSE TRUE re-edit same file, nothing changes
+ * TRUE FALSE start editing new file, new buffer
+ * TRUE TRUE start editing in existing buffer (nothing to do)
*/
- if (!other_file && !oldbuf) { /* re-use the buffer */
- set_last_cursor(curwin); /* may set b_last_cursor */
+ if (!other_file && !oldbuf) { // re-use the buffer
+ set_last_cursor(curwin); // may set b_last_cursor
if (newlnum == ECMD_LAST || newlnum == ECMD_LASTL) {
newlnum = curwin->w_cursor.lnum;
solcol = curwin->w_cursor.col;
@@ -2607,7 +2654,7 @@ int do_ecmd(
&& (p_ur < 0 || curbuf->b_ml.ml_line_count <= p_ur)) {
// Sync first so that this is a separate undo-able action.
u_sync(false);
- if (u_savecommon(0, curbuf->b_ml.ml_line_count + 1, 0, true)
+ if (u_savecommon(curbuf, 0, curbuf->b_ml.ml_line_count + 1, 0, true)
== FAIL) {
xfree(new_name);
goto theend;
@@ -2633,12 +2680,14 @@ int do_ecmd(
/* If autocommands change buffers under our fingers, forget about
* re-editing the file. Should do the buf_clear_file(), but perhaps
* the autocommands changed the buffer... */
- if (buf != curbuf)
+ if (buf != curbuf) {
goto theend;
- if (aborting()) /* autocmds may abort script processing */
+ }
+ if (aborting()) { // autocmds may abort script processing
goto theend;
+ }
buf_clear_file(curbuf);
- curbuf->b_op_start.lnum = 0; /* clear '[ and '] marks */
+ curbuf->b_op_start.lnum = 0; // clear '[ and '] marks
curbuf->b_op_end.lnum = 0;
}
@@ -2646,7 +2695,7 @@ int do_ecmd(
* If we get here we are sure to start editing
*/
- /* Assume success now */
+ // Assume success now
retval = OK;
/*
@@ -2670,7 +2719,7 @@ int do_ecmd(
}
}
- /* Change directories when the 'acd' option is set. */
+ // Change directories when the 'acd' option is set.
do_autochdir();
/*
@@ -2679,18 +2728,20 @@ int do_ecmd(
*/
orig_pos = curwin->w_cursor;
topline = curwin->w_topline;
- if (!oldbuf) { /* need to read the file */
+ if (!oldbuf) { // need to read the file
swap_exists_action = SEA_DIALOG;
- curbuf->b_flags |= BF_CHECK_RO; /* set/reset 'ro' flag */
+ curbuf->b_flags |= BF_CHECK_RO; // set/reset 'ro' flag
/*
* Open the buffer and read the file.
*/
- if (should_abort(open_buffer(FALSE, eap, readfile_flags)))
+ if (should_abort(open_buffer(FALSE, eap, readfile_flags))) {
retval = FAIL;
+ }
- if (swap_exists_action == SEA_QUIT)
+ if (swap_exists_action == SEA_QUIT) {
retval = FAIL;
+ }
handle_swap_exists(&old_curbuf);
} else {
/* Read the modelines, but only to set window-local options. Any
@@ -2699,9 +2750,9 @@ int do_ecmd(
do_modelines(OPT_WINONLY);
apply_autocmds_retval(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf,
- &retval);
+ &retval);
apply_autocmds_retval(EVENT_BUFWINENTER, NULL, NULL, FALSE, curbuf,
- &retval);
+ &retval);
}
check_arg_idx(curwin);
@@ -2717,10 +2768,11 @@ int do_ecmd(
newcol = curwin->w_cursor.col;
}
}
- if (curwin->w_topline == topline)
+ if (curwin->w_topline == topline) {
topline = 0;
+ }
- /* Even when cursor didn't move we need to recompute topline. */
+ // Even when cursor didn't move we need to recompute topline.
changed_line_abv_curs();
maketitle();
@@ -2736,68 +2788,74 @@ int do_ecmd(
/* If the window options were changed may need to set the spell language.
* Can only do this after the buffer has been properly setup. */
- if (did_get_winopts && curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
+ if (did_get_winopts && curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL) {
(void)did_set_spelllang(curwin);
+ }
if (command == NULL) {
- if (newcol >= 0) { /* position set by autocommands */
+ if (newcol >= 0) { // position set by autocommands
curwin->w_cursor.lnum = newlnum;
curwin->w_cursor.col = newcol;
check_cursor();
- } else if (newlnum > 0) { /* line number from caller or old position */
+ } else if (newlnum > 0) { // line number from caller or old position
curwin->w_cursor.lnum = newlnum;
check_cursor_lnum();
if (solcol >= 0 && !p_sol) {
- /* 'sol' is off: Use last known column. */
+ // 'sol' is off: Use last known column.
curwin->w_cursor.col = solcol;
check_cursor_col();
curwin->w_cursor.coladd = 0;
curwin->w_set_curswant = TRUE;
- } else
+ } else {
beginline(BL_SOL | BL_FIX);
- } else { /* no line number, go to last line in Ex mode */
- if (exmode_active)
+ }
+ } else { // no line number, go to last line in Ex mode
+ if (exmode_active) {
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+ }
beginline(BL_WHITE | BL_FIX);
}
}
- /* Check if cursors in other windows on the same buffer are still valid */
- check_lnums(FALSE);
+ // Check if cursors in other windows on the same buffer are still valid
+ check_lnums(false);
/*
* Did not read the file, need to show some info about the file.
* Do this after setting the cursor.
*/
if (oldbuf
- && !auto_buf
- ) {
+ && !auto_buf) {
int msg_scroll_save = msg_scroll;
/* Obey the 'O' flag in 'cpoptions': overwrite any previous file
* message. */
- if (shortmess(SHM_OVERALL) && !exiting && p_verbose == 0)
+ if (shortmess(SHM_OVERALL) && !exiting && p_verbose == 0) {
msg_scroll = FALSE;
- if (!msg_scroll) /* wait a bit when overwriting an error msg */
- check_for_delay(FALSE);
+ }
+ if (!msg_scroll) { // wait a bit when overwriting an error msg
+ check_for_delay(false);
+ }
msg_start();
msg_scroll = msg_scroll_save;
- msg_scrolled_ign = TRUE;
+ msg_scrolled_ign = true;
if (!shortmess(SHM_FILEINFO)) {
fileinfo(false, true, false);
}
- msg_scrolled_ign = FALSE;
+ msg_scrolled_ign = false;
}
curbuf->b_last_used = time(NULL);
- if (command != NULL)
+ if (command != NULL) {
do_cmdline(command, NULL, NULL, DOCMD_VERBOSE);
+ }
- if (curbuf->b_kmap_state & KEYMAP_INIT)
+ if (curbuf->b_kmap_state & KEYMAP_INIT) {
(void)keymap_init();
+ }
RedrawingDisabled--;
did_inc_redrawing_disabled = false;
@@ -2812,10 +2870,11 @@ int do_ecmd(
redraw_curbuf_later(NOT_VALID); // redraw this buffer later
}
- if (p_im)
- need_start_insertmode = TRUE;
+ if (p_im) {
+ need_start_insertmode = true;
+ }
- /* Change directories when the 'acd' option is set. */
+ // Change directories when the 'acd' option is set.
do_autochdir();
@@ -2837,65 +2896,72 @@ theend:
static void delbuf_msg(char_u *name)
{
EMSG2(_("E143: Autocommands unexpectedly deleted new buffer %s"),
- name == NULL ? (char_u *)"" : name);
+ name == NULL ? (char_u *)"" : name);
xfree(name);
au_new_curbuf.br_buf = NULL;
au_new_curbuf.br_buf_free_count = 0;
}
-static int append_indent = 0; /* autoindent for first line */
+static int append_indent = 0; // autoindent for first line
/*
* ":insert" and ":append", also used by ":change"
*/
void ex_append(exarg_T *eap)
{
- char_u *theline;
+ char_u *theline;
bool did_undo = false;
linenr_T lnum = eap->line2;
int indent = 0;
- char_u *p;
+ char_u *p;
int vcol;
int empty = (curbuf->b_ml.ml_flags & ML_EMPTY);
- /* the ! flag toggles autoindent */
- if (eap->forceit)
+ // the ! flag toggles autoindent
+ if (eap->forceit) {
curbuf->b_p_ai = !curbuf->b_p_ai;
+ }
- /* First autoindent comes from the line we start on */
- if (eap->cmdidx != CMD_change && curbuf->b_p_ai && lnum > 0)
+ // First autoindent comes from the line we start on
+ if (eap->cmdidx != CMD_change && curbuf->b_p_ai && lnum > 0) {
append_indent = get_indent_lnum(lnum);
+ }
- if (eap->cmdidx != CMD_append)
+ if (eap->cmdidx != CMD_append) {
--lnum;
+ }
// when the buffer is empty need to delete the dummy line
- if (empty && lnum == 1)
+ if (empty && lnum == 1) {
lnum = 0;
+ }
- State = INSERT; /* behave like in Insert mode */
- if (curbuf->b_p_iminsert == B_IMODE_LMAP)
+ State = INSERT; // behave like in Insert mode
+ if (curbuf->b_p_iminsert == B_IMODE_LMAP) {
State |= LANGMAP;
+ }
for (;; ) {
msg_scroll = TRUE;
- need_wait_return = FALSE;
+ need_wait_return = false;
if (curbuf->b_p_ai) {
if (append_indent >= 0) {
indent = append_indent;
append_indent = -1;
- } else if (lnum > 0)
+ } else if (lnum > 0) {
indent = get_indent_lnum(lnum);
+ }
}
- ex_keep_indent = FALSE;
if (eap->getline == NULL) {
/* No getline() function, use the lines that follow. This ends
* when there is no more. */
- if (eap->nextcmd == NULL || *eap->nextcmd == NUL)
+ if (eap->nextcmd == NULL || *eap->nextcmd == NUL) {
break;
+ }
p = vim_strchr(eap->nextcmd, NL);
- if (p == NULL)
+ if (p == NULL) {
p = eap->nextcmd + STRLEN(eap->nextcmd);
+ }
theline = vim_strnsave(eap->nextcmd, p - eap->nextcmd);
if (*p != NUL) {
p++;
@@ -2906,28 +2972,25 @@ void ex_append(exarg_T *eap)
// when getline() returns.
int save_State = State;
State = CMDLINE;
- theline = eap->getline(
- eap->cstack->cs_looplevel > 0 ? -1 :
- NUL, eap->cookie, indent, true);
+ theline = eap->getline(eap->cstack->cs_looplevel > 0 ? -1 :
+ NUL, eap->cookie, indent, true);
State = save_State;
}
lines_left = Rows - 1;
- if (theline == NULL)
+ if (theline == NULL) {
break;
+ }
- /* Using ^ CTRL-D in getexmodeline() makes us repeat the indent. */
- if (ex_keep_indent)
- append_indent = indent;
-
- /* Look for the "." after automatic indent. */
+ // Look for the "." after automatic indent.
vcol = 0;
for (p = theline; indent > vcol; ++p) {
- if (*p == ' ')
+ if (*p == ' ') {
++vcol;
- else if (*p == TAB)
+ } else if (*p == TAB) {
vcol += 8 - vcol % 8;
- else
+ } else {
break;
+ }
}
if ((p[0] == '.' && p[1] == NUL)
|| (!did_undo && u_save(lnum, lnum + 1 + (empty ? 1 : 0))
@@ -2936,9 +2999,10 @@ void ex_append(exarg_T *eap)
break;
}
- /* don't use autoindent if nothing was typed. */
- if (p[0] == NUL)
+ // don't use autoindent if nothing was typed.
+ if (p[0] == NUL) {
theline[0] = NUL;
+ }
did_undo = true;
ml_append(lnum, theline, (colnr_T)0, false);
@@ -2954,8 +3018,9 @@ void ex_append(exarg_T *eap)
}
State = NORMAL;
- if (eap->forceit)
+ if (eap->forceit) {
curbuf->b_p_ai = !curbuf->b_p_ai;
+ }
/* "start" is set to eap->line2+1 unless that position is invalid (when
* eap->line2 pointed to the end of the buffer and nothing was appended)
@@ -2963,8 +3028,9 @@ void ex_append(exarg_T *eap)
* it is the same than "start" -- Acevedo */
curbuf->b_op_start.lnum = (eap->line2 < curbuf->b_ml.ml_line_count) ?
eap->line2 + 1 : curbuf->b_ml.ml_line_count;
- if (eap->cmdidx != CMD_append)
+ if (eap->cmdidx != CMD_append) {
--curbuf->b_op_start.lnum;
+ }
curbuf->b_op_end.lnum = (eap->line2 < lnum)
? lnum : curbuf->b_op_start.lnum;
curbuf->b_op_start.col = curbuf->b_op_end.col = 0;
@@ -2972,8 +3038,8 @@ void ex_append(exarg_T *eap)
check_cursor_lnum();
beginline(BL_SOL | BL_FIX);
- need_wait_return = FALSE; /* don't use wait_return() now */
- ex_no_reprint = TRUE;
+ need_wait_return = false; // don't use wait_return() now
+ ex_no_reprint = true;
}
/*
@@ -2984,33 +3050,36 @@ void ex_change(exarg_T *eap)
linenr_T lnum;
if (eap->line2 >= eap->line1
- && u_save(eap->line1 - 1, eap->line2 + 1) == FAIL)
+ && u_save(eap->line1 - 1, eap->line2 + 1) == FAIL) {
return;
+ }
- /* the ! flag toggles autoindent */
- if (eap->forceit ? !curbuf->b_p_ai : curbuf->b_p_ai)
+ // the ! flag toggles autoindent
+ if (eap->forceit ? !curbuf->b_p_ai : curbuf->b_p_ai) {
append_indent = get_indent_lnum(eap->line1);
+ }
for (lnum = eap->line2; lnum >= eap->line1; --lnum) {
- if (curbuf->b_ml.ml_flags & ML_EMPTY) /* nothing to delete */
+ if (curbuf->b_ml.ml_flags & ML_EMPTY) { // nothing to delete
break;
+ }
ml_delete(eap->line1, false);
}
- /* make sure the cursor is not beyond the end of the file now */
+ // make sure the cursor is not beyond the end of the file now
check_cursor_lnum();
- deleted_lines_mark(eap->line1, (long)(eap->line2 - lnum));
+ deleted_lines_mark(eap->line1, (eap->line2 - lnum));
- /* ":append" on the line above the deleted lines. */
+ // ":append" on the line above the deleted lines.
eap->line2 = eap->line1;
ex_append(eap);
}
void ex_z(exarg_T *eap)
{
- char_u *x;
- int64_t bigness;
- char_u *kind;
+ char_u *x;
+ int64_t bigness;
+ char_u *kind;
int minus = 0;
linenr_T start, end, curs, i;
int j;
@@ -3019,7 +3088,7 @@ void ex_z(exarg_T *eap)
// Vi compatible: ":z!" uses display height, without a count uses
// 'scroll'
if (eap->forceit) {
- bigness = curwin->w_height_inner;
+ bigness = Rows - 1;
} else if (ONE_WINDOW) {
bigness = curwin->w_p_scr * 2;
} else {
@@ -3032,10 +3101,12 @@ void ex_z(exarg_T *eap)
x = eap->arg;
kind = x;
if (*kind == '-' || *kind == '+' || *kind == '='
- || *kind == '^' || *kind == '.')
+ || *kind == '^' || *kind == '.') {
++x;
- while (*x == '-' || *x == '+')
+ }
+ while (*x == '-' || *x == '+') {
++x;
+ }
if (*x != 0) {
if (!ascii_isdigit(*x)) {
@@ -3055,10 +3126,12 @@ void ex_z(exarg_T *eap)
}
}
- /* the number of '-' and '+' multiplies the distance */
- if (*kind == '-' || *kind == '+')
- for (x = kind + 1; *x == *kind; ++x)
+ // the number of '-' and '+' multiplies the distance
+ if (*kind == '-' || *kind == '+') {
+ for (x = kind + 1; *x == *kind; ++x) {
;
+ }
+ }
switch (*kind) {
case '-':
@@ -3086,22 +3159,25 @@ void ex_z(exarg_T *eap)
curs = end;
break;
- default: /* '+' */
+ default: // '+'
start = lnum;
- if (*kind == '+')
+ if (*kind == '+') {
start += bigness * (linenr_T)(x - kind - 1) + 1;
- else if (eap->addr_count == 0)
+ } else if (eap->addr_count == 0) {
++start;
+ }
end = start + bigness - 1;
curs = end;
break;
}
- if (start < 1)
+ if (start < 1) {
start = 1;
+ }
- if (end > curbuf->b_ml.ml_line_count)
+ if (end > curbuf->b_ml.ml_line_count) {
end = curbuf->b_ml.ml_line_count;
+ }
if (curs > curbuf->b_ml.ml_line_count) {
curs = curbuf->b_ml.ml_line_count;
@@ -3113,8 +3189,9 @@ void ex_z(exarg_T *eap)
if (minus && i == lnum) {
msg_putchar('\n');
- for (j = 1; j < Columns; j++)
+ for (j = 1; j < Columns; j++) {
msg_putchar('-');
+ }
}
print_line(i, eap->flags & EXFLAG_NR, eap->flags & EXFLAG_LIST);
@@ -3122,8 +3199,9 @@ void ex_z(exarg_T *eap)
if (minus && i == lnum) {
msg_putchar('\n');
- for (j = 1; j < Columns; j++)
+ for (j = 1; j < Columns; j++) {
msg_putchar('-');
+ }
}
}
@@ -3157,7 +3235,7 @@ int check_secure(void)
}
/// Previous substitute replacement string
-static SubReplacementString old_sub = {NULL, 0, NULL};
+static SubReplacementString old_sub = { NULL, 0, NULL };
static int global_need_beginline; // call beginline() after ":g"
@@ -3194,8 +3272,7 @@ void sub_set_replacement(SubReplacementString sub)
/// @param[in] save Save pattern to options, history
///
/// @returns true if :substitute can be replaced with a join command
-static bool sub_joining_lines(exarg_T *eap, char_u *pat, char_u *sub,
- char_u *cmd, bool save)
+static bool sub_joining_lines(exarg_T *eap, char_u *pat, char_u *sub, char_u *cmd, bool save)
FUNC_ATTR_NONNULL_ARG(1, 3, 4)
{
// TODO(vim): find a generic solution to make line-joining operations more
@@ -3222,8 +3299,8 @@ static bool sub_joining_lines(exarg_T *eap, char_u *pat, char_u *sub,
// The number of lines joined is the number of lines in the range
linenr_T joined_lines_count = eap->line2 - eap->line1 + 1
- // plus one extra line if not at the end of file.
- + (eap->line2 < curbuf->b_ml.ml_line_count ? 1 : 0);
+ // plus one extra line if not at the end of file.
+ + (eap->line2 < curbuf->b_ml.ml_line_count ? 1 : 0);
if (joined_lines_count > 1) {
do_join(joined_lines_count, FALSE, TRUE, FALSE, true);
sub_nsubs = joined_lines_count - 1;
@@ -3290,8 +3367,7 @@ static char_u *sub_grow_buf(char_u **new_start, int needed_len)
/// @param[in,out] which_pat pattern type from which to get default search
///
/// @returns pointer to the end of the flags, which may be the end of the string
-static char_u *sub_parse_flags(char_u *cmd, subflags_T *subflags,
- int *which_pat)
+static char_u *sub_parse_flags(char_u *cmd, subflags_T *subflags, int *which_pat)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
{
// Find trailing options. When '&' is used, keep old options.
@@ -3363,8 +3439,7 @@ static int check_regexp_delim(int c)
///
/// @param do_buf_event If `true`, send buffer updates.
/// @return buffer used for 'inccommand' preview
-static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
- bool do_buf_event, handle_T bufnr)
+static buf_T *do_sub(exarg_T *eap, proftime_T timeout, bool do_buf_event, handle_T bufnr)
{
long i = 0;
regmmatch_T regmatch;
@@ -3382,8 +3457,8 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
int delimiter;
bool has_second_delim = false;
int sublen;
- int got_quit = false;
- int got_match = false;
+ bool got_quit = false;
+ bool got_match = false;
int which_pat;
char_u *cmd = eap->arg;
linenr_T first_line = 0; // first changed line
@@ -3409,12 +3484,12 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
}
start_nsubs = sub_nsubs;
- if (eap->cmdidx == CMD_tilde)
- which_pat = RE_LAST; /* use last used regexp */
- else
- which_pat = RE_SUBST; /* use last substitute regexp */
-
- /* new pattern and substitution */
+ if (eap->cmdidx == CMD_tilde) {
+ which_pat = RE_LAST; // use last used regexp
+ } else {
+ which_pat = RE_SUBST; // use last substitute regexp
+ }
+ // new pattern and substitution
if (eap->cmd[0] == 's' && *cmd != NUL && !ascii_iswhite(*cmd)
&& vim_strchr((char_u *)"0123456789cegriIp|\"", *cmd) == NULL) {
// don't accept alphanumeric for separator
@@ -3452,11 +3527,11 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
* Small incompatibility: vi sees '\n' as end of the command, but in
* Vim we want to use '\n' to find/substitute a NUL.
*/
- sub = cmd; /* remember the start of the substitution */
+ sub = cmd; // remember the start of the substitution
while (cmd[0]) {
- if (cmd[0] == delimiter) { /* end delimiter found */
- *cmd++ = NUL; /* replace it with a NUL */
+ if (cmd[0] == delimiter) { // end delimiter found
+ *cmd++ = NUL; // replace it with a NUL
break;
}
if (cmd[0] == '\\' && cmd[1] != 0) { // skip escaped characters
@@ -3467,18 +3542,18 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
if (!eap->skip && !preview) {
sub_set_replacement((SubReplacementString) {
- .sub = xstrdup((char *) sub),
+ .sub = xstrdup((char *)sub),
.timestamp = os_time(),
.additional_elements = NULL,
});
}
- } else if (!eap->skip) { /* use previous pattern and substitution */
- if (old_sub.sub == NULL) { /* there is no previous command */
+ } else if (!eap->skip) { // use previous pattern and substitution
+ if (old_sub.sub == NULL) { // there is no previous command
EMSG(_(e_nopresub));
return NULL;
}
- pat = NULL; /* search_regcomp() will use previous pattern */
- sub = (char_u *) old_sub.sub;
+ pat = NULL; // search_regcomp() will use previous pattern
+ sub = (char_u *)old_sub.sub;
/* Vi compatibility quirk: repeating with ":s" keeps the cursor in the
* last column after using "$". */
@@ -3504,15 +3579,16 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
}
eap->line1 = eap->line2;
eap->line2 += i - 1;
- if (eap->line2 > curbuf->b_ml.ml_line_count)
+ if (eap->line2 > curbuf->b_ml.ml_line_count) {
eap->line2 = curbuf->b_ml.ml_line_count;
+ }
}
/*
* check for trailing command or garbage
*/
cmd = skipwhite(cmd);
- if (*cmd && *cmd != '"') { /* if not end-of-line or comment */
+ if (*cmd && *cmd != '"') { // if not end-of-line or comment
eap->nextcmd = check_nextcmd(cmd);
if (eap->nextcmd == NULL) {
EMSG(_(e_trailing));
@@ -3570,9 +3646,9 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
colnr_T copycol;
colnr_T matchcol;
colnr_T prev_matchcol = MAXCOL;
- char_u *new_end, *new_start = NULL;
- char_u *p1;
- int did_sub = FALSE;
+ char_u *new_end, *new_start = NULL;
+ char_u *p1;
+ bool did_sub = false;
int lastone;
long nmatch_tl = 0; // nr of lines matched below lnum
int do_again; // do it again after joining lines
@@ -3582,29 +3658,29 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
/*
* The new text is build up step by step, to avoid too much
* copying. There are these pieces:
- * sub_firstline The old text, unmodified.
- * copycol Column in the old text where we started
- * looking for a match; from here old text still
- * needs to be copied to the new text.
- * matchcol Column number of the old text where to look
- * for the next match. It's just after the
- * previous match or one further.
- * prev_matchcol Column just after the previous match (if any).
- * Mostly equal to matchcol, except for the first
- * match and after skipping an empty match.
- * regmatch.*pos Where the pattern matched in the old text.
- * new_start The new text, all that has been produced so
- * far.
- * new_end The new text, where to append new text.
+ * sub_firstline The old text, unmodified.
+ * copycol Column in the old text where we started
+ * looking for a match; from here old text still
+ * needs to be copied to the new text.
+ * matchcol Column number of the old text where to look
+ * for the next match. It's just after the
+ * previous match or one further.
+ * prev_matchcol Column just after the previous match (if any).
+ * Mostly equal to matchcol, except for the first
+ * match and after skipping an empty match.
+ * regmatch.*pos Where the pattern matched in the old text.
+ * new_start The new text, all that has been produced so
+ * far.
+ * new_end The new text, where to append new text.
*
- * lnum The line number where we found the start of
- * the match. Can be below the line we searched
- * when there is a \n before a \zs in the
- * pattern.
- * sub_firstlnum The line number in the buffer where to look
- * for a match. Can be different from "lnum"
- * when the pattern or substitute string contains
- * line breaks.
+ * lnum The line number where we found the start of
+ * the match. Can be below the line we searched
+ * when there is a \n before a \zs in the
+ * pattern.
+ * sub_firstlnum The line number in the buffer where to look
+ * for a match. Can be different from "lnum"
+ * when the pattern or substitute string contains
+ * line breaks.
*
* Special situations:
* - When the substitute string contains a line break, the part up
@@ -3627,10 +3703,10 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
copycol = 0;
matchcol = 0;
- /* At first match, remember current cursor position. */
+ // At first match, remember current cursor position.
if (!got_match) {
setpcmark();
- got_match = TRUE;
+ got_match = true;
}
/*
@@ -3720,11 +3796,12 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
skip_match = true;
}
sub_nsubs++;
- did_sub = TRUE;
- /* Skip the substitution, unless an expression is used,
- * then it is evaluated in the sandbox. */
- if (!(sub[0] == '\\' && sub[1] == '='))
+ did_sub = true;
+ // Skip the substitution, unless an expression is used,
+ // then it is evaluated in the sandbox.
+ if (!(sub[0] == '\\' && sub[1] == '=')) {
goto skip;
+ }
}
if (subflags.do_ask && !preview) {
@@ -3734,7 +3811,7 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
* properly */
int save_State = State;
State = CONFIRM;
- setmouse(); /* disable mouse in xterm */
+ setmouse(); // disable mouse in xterm
curwin->w_cursor.col = regmatch.startpos[0].col;
if (curwin->w_p_crb) {
@@ -3743,15 +3820,17 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
/* When 'cpoptions' contains "u" don't sync undo when
* asking for confirmation. */
- if (vim_strchr(p_cpo, CPO_UNDO) != NULL)
+ if (vim_strchr(p_cpo, CPO_UNDO) != NULL) {
++no_u_sync;
+ }
/*
* Loop until 'y', 'n', 'q', CTRL-E or CTRL-Y typed.
*/
while (subflags.do_ask) {
if (exmode_active) {
- char_u *resp;
+ char *prompt;
+ char_u *resp;
colnr_T sc, ec;
print_line_no_prefix(lnum, subflags.do_number, subflags.do_list);
@@ -3767,13 +3846,14 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
sc += numw;
ec += numw;
}
- msg_start();
- for (i = 0; i < (long)sc; ++i)
- msg_putchar(' ');
- for (; i <= (long)ec; ++i)
- msg_putchar('^');
- resp = getexmodeline('?', NULL, 0, true);
+ prompt = xmallocz(ec + 1);
+ memset(prompt, ' ', sc);
+ memset(prompt + sc, '^', ec - sc + 1);
+ resp = (char_u *)getcmdline_prompt(NUL, prompt, 0, EXPAND_NOTHING,
+ NULL, CALLBACK_NONE);
+ msg_putchar('\n');
+ xfree(prompt);
if (resp != NULL) {
typed = *resp;
xfree(resp);
@@ -3823,8 +3903,9 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
redraw_later(curwin, SOME_VALID);
curwin->w_p_fen = save_p_fen;
- if (msg_row == Rows - 1)
- msg_didout = FALSE; /* avoid a scroll-up */
+ if (msg_row == Rows - 1) {
+ msg_didout = false; // avoid a scroll-up
+ }
msg_starthere();
i = msg_scroll;
msg_scroll = 0; /* truncate msg when
@@ -3835,7 +3916,7 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
_("replace with %s (y/n/a/q/l/^E/^Y)?"), sub);
msg_no_more = FALSE;
msg_scroll = i;
- showruler(TRUE);
+ showruler(true);
ui_cursor_goto(msg_row, msg_col);
RedrawingDisabled = temp;
@@ -3843,8 +3924,8 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
typed = plain_vgetc();
no_mapping--;
- /* clear the question */
- msg_didout = FALSE; /* don't scroll up */
+ // clear the question
+ msg_didout = false; // don't scroll up
msg_col = 0;
gotocmdline(true);
p_lz = save_p_lz;
@@ -3860,10 +3941,12 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
got_quit = true;
break;
}
- if (typed == 'n')
+ if (typed == 'n') {
break;
- if (typed == 'y')
+ }
+ if (typed == 'y') {
break;
+ }
if (typed == 'l') {
// last: replace and then stop
subflags.do_all = false;
@@ -3874,15 +3957,17 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
subflags.do_ask = false;
break;
}
- if (typed == Ctrl_E)
+ if (typed == Ctrl_E) {
scrollup_clamp();
- else if (typed == Ctrl_Y)
+ } else if (typed == Ctrl_Y) {
scrolldown_clamp();
+ }
}
State = save_State;
setmouse();
- if (vim_strchr(p_cpo, CPO_UNDO) != NULL)
+ if (vim_strchr(p_cpo, CPO_UNDO) != NULL) {
--no_u_sync;
+ }
if (typed == 'n') {
/* For a multi-line match, put matchcol at the NUL at
@@ -3896,8 +3981,9 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
}
goto skip;
}
- if (got_quit)
+ if (got_quit) {
goto skip;
+ }
}
/* Move the cursor to the start of the match, so that we can
@@ -3913,28 +3999,28 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
}
#define ADJUST_SUB_FIRSTLNUM() \
- do { \
- /* For a multi-line match, make a copy of the last matched */ \
- /* line and continue in that one. */ \
- if (nmatch > 1) { \
- sub_firstlnum += nmatch - 1; \
- xfree(sub_firstline); \
- sub_firstline = vim_strsave(ml_get(sub_firstlnum)); \
- /* When going beyond the last line, stop substituting. */ \
- if (sub_firstlnum <= line2) { \
- do_again = true; \
- } else { \
- subflags.do_all = false; \
- } \
- } \
- if (skip_match) { \
- /* Already hit end of the buffer, sub_firstlnum is one */ \
- /* less than what it ought to be. */ \
- xfree(sub_firstline); \
- sub_firstline = vim_strsave((char_u *)""); \
- copycol = 0; \
- } \
- } while (0)
+ do { \
+ /* For a multi-line match, make a copy of the last matched */ \
+ /* line and continue in that one. */ \
+ if (nmatch > 1) { \
+ sub_firstlnum += nmatch - 1; \
+ xfree(sub_firstline); \
+ sub_firstline = vim_strsave(ml_get(sub_firstlnum)); \
+ /* When going beyond the last line, stop substituting. */ \
+ if (sub_firstlnum <= line2) { \
+ do_again = true; \
+ } else { \
+ subflags.do_all = false; \
+ } \
+ } \
+ if (skip_match) { \
+ /* Already hit end of the buffer, sub_firstlnum is one */ \
+ /* less than what it ought to be. */ \
+ xfree(sub_firstline); \
+ sub_firstline = vim_strsave((char_u *)""); \
+ copycol = 0; \
+ } \
+ } while (0)
// Save the line numbers for the preview buffer
// NOTE: If the pattern matches a final newline, the next line will
@@ -3999,7 +4085,7 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
+ copy_len + sublen + 1);
// copy the text up to the part that matched
- memmove(new_end, sub_firstline + copycol, (size_t)copy_len);
+ memmove(new_end, sub_firstline + copycol, copy_len);
new_end += copy_len;
// Finally, at this point we can know where the match actually will
@@ -4147,8 +4233,9 @@ skip:
* it in the buffer.
*/
++lnum;
- if (u_savedel(lnum, nmatch_tl) != OK)
+ if (u_savedel(lnum, nmatch_tl) != OK) {
break;
+ }
for (i = 0; i < nmatch_tl; i++) {
ml_delete(lnum, false);
}
@@ -4174,7 +4261,7 @@ skip:
}
sub_firstlnum = lnum;
- xfree(sub_firstline); /* free the temp buffer */
+ xfree(sub_firstline); // free the temp buffer
sub_firstline = new_start;
new_start = NULL;
matchcol = (colnr_T)STRLEN(sub_firstline) - matchcol;
@@ -4182,9 +4269,10 @@ skip:
- prev_matchcol;
copycol = 0;
}
- if (nmatch == -1 && !lastone)
+ if (nmatch == -1 && !lastone) {
nmatch = vim_regexec_multi(&regmatch, curwin, curbuf,
sub_firstlnum, matchcol, NULL, NULL);
+ }
/*
* 5. break if there isn't another match in this line
@@ -4193,23 +4281,24 @@ skip:
/* If the match found didn't start where we were
* searching, do the next search in the line where we
* found the match. */
- if (nmatch == -1)
+ if (nmatch == -1) {
lnum -= regmatch.startpos[0].lnum;
+ }
#define PUSH_PREVIEW_LINES() \
- do { \
- linenr_T match_lines = current_match.end.lnum \
- - current_match.start.lnum +1; \
- if (preview_lines.subresults.size > 0) { \
- linenr_T last = kv_last(preview_lines.subresults).end.lnum; \
- if (last == current_match.start.lnum) { \
- preview_lines.lines_needed += match_lines - 1; \
- } \
- } else { \
- preview_lines.lines_needed += match_lines; \
- } \
- kv_push(preview_lines.subresults, current_match); \
- } while (0)
+ do { \
+ linenr_T match_lines = current_match.end.lnum \
+ - current_match.start.lnum +1; \
+ if (preview_lines.subresults.size > 0) { \
+ linenr_T last = kv_last(preview_lines.subresults).end.lnum; \
+ if (last == current_match.start.lnum) { \
+ preview_lines.lines_needed += match_lines - 1; \
+ } \
+ } else { \
+ preview_lines.lines_needed += match_lines; \
+ } \
+ kv_push(preview_lines.subresults, current_match); \
+ } while (0)
// Push the match to preview_lines.
PUSH_PREVIEW_LINES();
@@ -4252,7 +4341,7 @@ skip:
do_buf_event);
}
- xfree(sub_firstline); /* may have to free allocated copy of the line */
+ xfree(sub_firstline); // may have to free allocated copy of the line
// ":s/pat//n" doesn't move the cursor
if (subflags.do_count) {
@@ -4260,7 +4349,7 @@ skip:
}
if (sub_nsubs > start_nsubs) {
- /* Set the '[ and '] marks. */
+ // Set the '[ and '] marks.
curbuf->b_op_start.lnum = eap->line1;
curbuf->b_op_end.lnum = line2;
curbuf->b_op_start.col = curbuf->b_op_end.col = 0;
@@ -4339,15 +4428,13 @@ skip:
#undef PUSH_PREVIEW_LINES
} // NOLINT(readability/fn_size)
-/*
- * Give message for number of substitutions.
- * Can also be used after a ":global" command.
- * Return TRUE if a message was given.
- */
-bool
-do_sub_msg (
- bool count_only /* used 'n' flag for ":s" */
-)
+/// Give message for number of substitutions.
+/// Can also be used after a ":global" command.
+///
+/// @param count_only used 'n' flag for ":s"
+///
+/// @return true if a message was given.
+bool do_sub_msg(bool count_only)
{
/*
* Only report substitutions when:
@@ -4358,27 +4445,31 @@ do_sub_msg (
if (((sub_nsubs > p_report && (KeyTyped || sub_nlines > 1 || p_report < 1))
|| count_only)
&& messaging()) {
- if (got_int)
+ if (got_int) {
STRCPY(msg_buf, _("(Interrupted) "));
- else
+ } else {
*msg_buf = NUL;
- if (sub_nsubs == 1)
+ }
+ if (sub_nsubs == 1) {
vim_snprintf_add((char *)msg_buf, sizeof(msg_buf),
- "%s", count_only ? _("1 match") : _("1 substitution"));
- else
+ "%s", count_only ? _("1 match") : _("1 substitution"));
+ } else {
vim_snprintf_add((char *)msg_buf, sizeof(msg_buf),
- count_only ? _("%" PRId64 " matches")
- : _("%" PRId64 " substitutions"),
- (int64_t)sub_nsubs);
- if (sub_nlines == 1)
+ count_only ? _("%" PRId64 " matches")
+ : _("%" PRId64 " substitutions"),
+ (int64_t)sub_nsubs);
+ }
+ if (sub_nlines == 1) {
vim_snprintf_add((char *)msg_buf, sizeof(msg_buf),
- "%s", _(" on 1 line"));
- else
+ "%s", _(" on 1 line"));
+ } else {
vim_snprintf_add((char *)msg_buf, sizeof(msg_buf),
- _(" on %" PRId64 " lines"), (int64_t)sub_nlines);
- if (msg(msg_buf))
- /* save message to display it after redraw */
+ _(" on %" PRId64 " lines"), (int64_t)sub_nlines);
+ }
+ if (msg(msg_buf)) {
+ // save message to display it after redraw
set_keep_msg(msg_buf, 0);
+ }
return true;
}
if (got_int) {
@@ -4417,13 +4508,13 @@ static void global_exe_one(char_u *const cmd, const linenr_T lnum)
*/
void ex_global(exarg_T *eap)
{
- linenr_T lnum; /* line number according to old situation */
+ linenr_T lnum; // line number according to old situation
int ndone = 0;
- int type; /* first char of cmd: 'v' or 'g' */
- char_u *cmd; /* command argument */
+ int type; // first char of cmd: 'v' or 'g'
+ char_u *cmd; // command argument
- char_u delim; /* delimiter, normally '/' */
- char_u *pat;
+ char_u delim; // delimiter, normally '/'
+ char_u *pat;
regmmatch_T regmatch;
int match;
int which_pat;
@@ -4437,17 +4528,18 @@ void ex_global(exarg_T *eap)
return;
}
- if (eap->forceit) /* ":global!" is like ":vglobal" */
+ if (eap->forceit) { // ":global!" is like ":vglobal"
type = 'v';
- else
+ } else {
type = *eap->cmd;
+ }
cmd = eap->arg;
- which_pat = RE_LAST; /* default: use last used regexp */
+ which_pat = RE_LAST; // default: use last used regexp
/*
* undocumented vi feature:
- * "\/" and "\?": use previous search pattern.
- * "\&": use previous substitute pattern.
+ * "\/" and "\?": use previous search pattern.
+ * "\&": use previous substitute pattern.
*/
if (*cmd == '\\') {
++cmd;
@@ -4455,10 +4547,11 @@ void ex_global(exarg_T *eap)
EMSG(_(e_backslash));
return;
}
- if (*cmd == '&')
- which_pat = RE_SUBST; /* use previous substitute pattern */
- else
- which_pat = RE_SEARCH; /* use previous search pattern */
+ if (*cmd == '&') {
+ which_pat = RE_SUBST; // use previous substitute pattern
+ } else {
+ which_pat = RE_SEARCH; // use previous search pattern
+ }
++cmd;
pat = (char_u *)"";
} else if (*cmd == NUL) {
@@ -4467,13 +4560,15 @@ void ex_global(exarg_T *eap)
} else if (check_regexp_delim(*cmd) == FAIL) {
return;
} else {
- delim = *cmd; /* get the delimiter */
- if (delim)
- ++cmd; /* skip delimiter if there is one */
- pat = cmd; /* remember start of pattern */
+ delim = *cmd; // get the delimiter
+ if (delim) {
+ ++cmd; // skip delimiter if there is one
+ }
+ pat = cmd; // remember start of pattern
cmd = skip_regexp(cmd, delim, p_magic, &eap->arg);
- if (cmd[0] == delim) /* end delimiter found */
- *cmd++ = NUL; /* replace it with a NUL */
+ if (cmd[0] == delim) { // end delimiter found
+ *cmd++ = NUL; // replace it with a NUL
+ }
}
if (search_regcomp(pat, RE_BOTH, which_pat, SEARCH_HIS, &regmatch) == FAIL) {
@@ -4577,19 +4672,17 @@ void global_exe(char_u *cmd)
#if defined(EXITFREE)
void free_old_sub(void)
{
- sub_set_replacement((SubReplacementString) {NULL, 0, NULL});
+ sub_set_replacement((SubReplacementString) { NULL, 0, NULL });
}
#endif
-/*
- * Set up for a tagpreview.
- * Return TRUE when it was created.
- */
-bool
-prepare_tagpreview (
- bool undo_sync /* sync undo when leaving the window */
-)
+/// Set up for a tagpreview.
+///
+/// @param undo_sync sync undo when leaving the window
+///
+/// @return true when it was created.
+bool prepare_tagpreview(bool undo_sync)
{
/*
* If there is already a preview window open, use that one.
@@ -4608,8 +4701,9 @@ prepare_tagpreview (
* There is no preview window open yet. Create one.
*/
if (win_split(g_do_tagpreview > 0 ? g_do_tagpreview : 0, 0)
- == FAIL)
+ == FAIL) {
return false;
+ }
curwin->w_p_pvw = TRUE;
curwin->w_p_wfh = TRUE;
RESET_BINDING(curwin); /* don't take over 'scrollbind'
@@ -4630,20 +4724,20 @@ prepare_tagpreview (
*/
void ex_help(exarg_T *eap)
{
- char_u *arg;
- char_u *tag;
- FILE *helpfd; /* file descriptor of help file */
+ char_u *arg;
+ char_u *tag;
+ FILE *helpfd; // file descriptor of help file
int n;
int i;
- win_T *wp;
+ win_T *wp;
int num_matches;
- char_u **matches;
- char_u *p;
+ char_u **matches;
+ char_u *p;
int empty_fnum = 0;
int alt_fnum = 0;
- buf_T *buf;
+ buf_T *buf;
int len;
- char_u *lang;
+ char_u *lang;
const bool old_KeyTyped = KeyTyped;
if (eap != NULL) {
@@ -4666,49 +4760,57 @@ void ex_help(exarg_T *eap)
return;
}
- if (eap->skip) /* not executing commands */
+ if (eap->skip) { // not executing commands
return;
- } else
+ }
+ } else {
arg = (char_u *)"";
+ }
- /* remove trailing blanks */
+ // remove trailing blanks
p = arg + STRLEN(arg) - 1;
- while (p > arg && ascii_iswhite(*p) && p[-1] != '\\')
+ while (p > arg && ascii_iswhite(*p) && p[-1] != '\\') {
*p-- = NUL;
+ }
- /* Check for a specified language */
+ // Check for a specified language
lang = check_help_lang(arg);
- /* When no argument given go to the index. */
- if (*arg == NUL)
+ // When no argument given go to the index.
+ if (*arg == NUL) {
arg = (char_u *)"help.txt";
+ }
/*
* Check if there is a match for the argument.
*/
n = find_help_tags(arg, &num_matches, &matches,
- eap != NULL && eap->forceit);
+ eap != NULL && eap->forceit);
i = 0;
- if (n != FAIL && lang != NULL)
- /* Find first item with the requested language. */
+ if (n != FAIL && lang != NULL) {
+ // Find first item with the requested language.
for (i = 0; i < num_matches; ++i) {
len = (int)STRLEN(matches[i]);
if (len > 3 && matches[i][len - 3] == '@'
- && STRICMP(matches[i] + len - 2, lang) == 0)
+ && STRICMP(matches[i] + len - 2, lang) == 0) {
break;
+ }
}
+ }
if (i >= num_matches || n == FAIL) {
- if (lang != NULL)
+ if (lang != NULL) {
EMSG3(_("E661: Sorry, no '%s' help for %s"), lang, arg);
- else
+ } else {
EMSG2(_("E149: Sorry, no help for %s"), arg);
- if (n != FAIL)
+ }
+ if (n != FAIL) {
FreeWild(num_matches, matches);
+ }
return;
}
- /* The first match (in the requested language) is the best match. */
+ // The first match (in the requested language) is the best match.
tag = vim_strsave(matches[i]);
FreeWild(num_matches, matches);
@@ -4717,8 +4819,7 @@ void ex_help(exarg_T *eap)
* Always open a new one for ":tab help".
*/
if (!bt_help(curwin->w_buffer)
- || cmdmod.tab != 0
- ) {
+ || cmdmod.tab != 0) {
if (cmdmod.tab != 0) {
wp = NULL;
} else {
@@ -4746,13 +4847,16 @@ void ex_help(exarg_T *eap)
* narrow. */
n = WSP_HELP;
if (cmdmod.split == 0 && curwin->w_width != Columns
- && curwin->w_width < 80)
+ && curwin->w_width < 80) {
n |= WSP_TOP;
- if (win_split(0, n) == FAIL)
+ }
+ if (win_split(0, n) == FAIL) {
goto erret;
+ }
- if (curwin->w_height < p_hh)
+ if (curwin->w_height < p_hh) {
win_setheight((int)p_hh);
+ }
/*
* Open help file (do_ecmd() will set b_help flag, readfile() will
@@ -4761,18 +4865,19 @@ void ex_help(exarg_T *eap)
*/
alt_fnum = curbuf->b_fnum;
(void)do_ecmd(0, NULL, NULL, NULL, ECMD_LASTL,
- ECMD_HIDE + ECMD_SET_HELP,
- NULL /* buffer is still open, don't store info */
- );
- if (!cmdmod.keepalt)
+ ECMD_HIDE + ECMD_SET_HELP,
+ NULL // buffer is still open, don't store info
+ );
+ if (!cmdmod.keepalt) {
curwin->w_alt_fnum = alt_fnum;
+ }
empty_fnum = curbuf->b_fnum;
}
}
- if (!p_im)
- restart_edit = 0; /* don't want insert mode in help file */
-
+ if (!p_im) {
+ 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;
@@ -4789,9 +4894,10 @@ void ex_help(exarg_T *eap)
}
}
- /* keep the previous alternate file */
- if (alt_fnum != 0 && curwin->w_alt_fnum == empty_fnum && !cmdmod.keepalt)
+ // keep the previous alternate file
+ if (alt_fnum != 0 && curwin->w_alt_fnum == empty_fnum && !cmdmod.keepalt) {
curwin->w_alt_fnum = alt_fnum;
+ }
erret:
xfree(tag);
@@ -4809,37 +4915,37 @@ char_u *check_help_lang(char_u *arg)
if (len >= 3 && arg[len - 3] == '@' && ASCII_ISALPHA(arg[len - 2])
&& ASCII_ISALPHA(arg[len - 1])) {
- arg[len - 3] = NUL; /* remove the '@' */
+ arg[len - 3] = NUL; // remove the '@'
return arg + len - 2;
}
return NULL;
}
-/*
- * Return a heuristic indicating how well the given string matches. The
- * smaller the number, the better the match. This is the order of priorities,
- * from best match to worst match:
- * - Match with least alpha-numeric characters is better.
- * - Match with least total characters is better.
- * - Match towards the start is better.
- * - Match starting with "+" is worse (feature instead of command)
- * Assumption is made that the matched_string passed has already been found to
- * match some string for which help is requested. webb.
- */
-int
-help_heuristic(
- char_u *matched_string,
- int offset, // offset for match
- int wrong_case // no matching case
-)
+/// Return a heuristic indicating how well the given string matches. The
+/// smaller the number, the better the match. This is the order of priorities,
+/// from best match to worst match:
+/// - Match with least alphanumeric characters is better.
+/// - Match with least total characters is better.
+/// - Match towards the start is better.
+/// - Match starting with "+" is worse (feature instead of command)
+/// Assumption is made that the matched_string passed has already been found to
+/// match some string for which help is requested. webb.
+///
+/// @param offset offset for match
+/// @param wrong_case no matching case
+///
+/// @return a heuristic indicating how well the given string matches.
+int help_heuristic(char_u *matched_string, int offset, int wrong_case)
{
int num_letters;
- char_u *p;
+ char_u *p;
num_letters = 0;
- for (p = matched_string; *p; p++)
- if (ASCII_ISALNUM(*p))
+ for (p = matched_string; *p; p++) {
+ if (ASCII_ISALNUM(*p)) {
num_letters++;
+ }
+ }
/*
* Multiply the number of letters by 100 to give it a much bigger
@@ -4874,8 +4980,8 @@ help_heuristic(
*/
static int help_compare(const void *s1, const void *s2)
{
- char *p1;
- char *p2;
+ char *p1;
+ char *p2;
p1 = *(char **)s1 + strlen(*(char **)s1) + 1;
p2 = *(char **)s2 + strlen(*(char **)s2) + 1;
@@ -4886,39 +4992,38 @@ static int help_compare(const void *s1, const void *s2)
// the number of matches in num_matches.
// The matches will be sorted with a "best" match algorithm.
// When "keep_lang" is true try keeping the language of the current buffer.
-int find_help_tags(const char_u *arg, int *num_matches, char_u ***matches,
- bool keep_lang)
+int find_help_tags(const char_u *arg, int *num_matches, char_u ***matches, bool keep_lang)
{
int i;
static const char *(mtable[]) = {
- "*", "g*", "[*", "]*",
- "/*", "/\\*", "\"*", "**",
- "/\\(\\)", "/\\%(\\)",
- "?", ":?", "?<CR>", "g?", "g?g?", "g??",
- "-?", "q?", "v_g?",
- "/\\?", "/\\z(\\)", "\\=", ":s\\=",
- "[count]", "[quotex]",
- "[range]", ":[range]",
- "[pattern]", "\\|", "\\%$",
- "s/\\~", "s/\\U", "s/\\L",
- "s/\\1", "s/\\2", "s/\\3", "s/\\9"
+ "*", "g*", "[*", "]*",
+ "/*", "/\\*", "\"*", "**",
+ "/\\(\\)", "/\\%(\\)",
+ "?", ":?", "?<CR>", "g?", "g?g?", "g??",
+ "-?", "q?", "v_g?",
+ "/\\?", "/\\z(\\)", "\\=", ":s\\=",
+ "[count]", "[quotex]",
+ "[range]", ":[range]",
+ "[pattern]", "\\|", "\\%$",
+ "s/\\~", "s/\\U", "s/\\L",
+ "s/\\1", "s/\\2", "s/\\3", "s/\\9"
};
static const char *(rtable[]) = {
- "star", "gstar", "[star", "]star",
- "/star", "/\\\\star", "quotestar", "starstar",
- "/\\\\(\\\\)", "/\\\\%(\\\\)",
- "?", ":?", "?<CR>", "g?", "g?g?", "g??",
- "-?", "q?", "v_g?",
- "/\\\\?", "/\\\\z(\\\\)", "\\\\=", ":s\\\\=",
- "\\[count]", "\\[quotex]",
- "\\[range]", ":\\[range]",
- "\\[pattern]", "\\\\bar", "/\\\\%\\$",
- "s/\\\\\\~", "s/\\\\U", "s/\\\\L",
- "s/\\\\1", "s/\\\\2", "s/\\\\3", "s/\\\\9"
+ "star", "gstar", "[star", "]star",
+ "/star", "/\\\\star", "quotestar", "starstar",
+ "/\\\\(\\\\)", "/\\\\%(\\\\)",
+ "?", ":?", "?<CR>", "g?", "g?g?", "g??",
+ "-?", "q?", "v_g?",
+ "/\\\\?", "/\\\\z(\\\\)", "\\\\=", ":s\\\\=",
+ "\\[count]", "\\[quotex]",
+ "\\[range]", ":\\[range]",
+ "\\[pattern]", "\\\\bar", "/\\\\%\\$",
+ "s/\\\\\\~", "s/\\\\U", "s/\\\\L",
+ "s/\\\\1", "s/\\\\2", "s/\\\\3", "s/\\\\9"
};
static const char *(expr_table[]) = {
- "!=?", "!~?", "<=?", "<?", "==?", "=~?",
- ">=?", ">?", "is?", "isnot?"
+ "!=?", "!~?", "<=?", "<?", "==?", "=~?",
+ ">=?", ">?", "is?", "isnot?"
};
char_u *d = IObuff; // assume IObuff is long enough!
@@ -4951,7 +5056,7 @@ int find_help_tags(const char_u *arg, int *num_matches, char_u ***matches,
}
}
- if (i < 0) { /* no match in table */
+ if (i < 0) { // no match in table
/* Replace "\S" with "/\\S", etc. Otherwise every tag is matched.
* Also replace "\%^" and "\%(", they match every tag too.
* Also "\zs", "\z1", etc.
@@ -4963,9 +5068,10 @@ int find_help_tags(const char_u *arg, int *num_matches, char_u ***matches,
&& arg[2] != NUL))) {
STRCPY(d, "/\\\\");
STRCPY(d + 3, arg + 1);
- /* Check for "/\\_$", should be "/\\_\$" */
- if (d[3] == '_' && d[4] == '$')
+ // Check for "/\\_$", should be "/\\_\$"
+ if (d[3] == '_' && d[4] == '$') {
STRCPY(d + 4, "\\$");
+ }
} else {
/* Replace:
* "[:...:]" with "\[:...:]"
@@ -4974,12 +5080,13 @@ int find_help_tags(const char_u *arg, int *num_matches, char_u ***matches,
*/
if ((arg[0] == '[' && (arg[1] == ':'
|| (arg[1] == '+' && arg[2] == '+')))
- || (arg[0] == '\\' && arg[1] == '{'))
+ || (arg[0] == '\\' && arg[1] == '{')) {
*d++ = '\\';
+ }
// If tag starts with "('", skip the "(". Fixes CTRL-] on ('option'.
if (*arg == '(' && arg[1] == '\'') {
- arg++;
+ arg++;
}
for (const char_u *s = arg; *s; s++) {
// Replace "|" with "bar" and '"' with "quote" to match the name of
@@ -4992,19 +5099,24 @@ int find_help_tags(const char_u *arg, int *num_matches, char_u ***matches,
break;
}
switch (*s) {
- case '|': STRCPY(d, "bar");
+ case '|':
+ STRCPY(d, "bar");
d += 3;
continue;
- case '"': STRCPY(d, "quote");
+ case '"':
+ STRCPY(d, "quote");
d += 5;
continue;
- case '*': *d++ = '.';
+ case '*':
+ *d++ = '.';
break;
- case '?': *d++ = '.';
+ case '?':
+ *d++ = '.';
continue;
case '$':
case '.':
- case '~': *d++ = '\\';
+ case '~':
+ *d++ = '\\';
break;
}
@@ -5015,31 +5127,36 @@ int find_help_tags(const char_u *arg, int *num_matches, char_u ***matches,
*/
if (*s < ' ' || (*s == '^' && s[1] && (ASCII_ISALPHA(s[1])
|| vim_strchr((char_u *)
- "?@[\\]^",
- s[1]) != NULL))) {
- if (d > IObuff && d[-1] != '_' && d[-1] != '\\')
- *d++ = '_'; /* prepend a '_' to make x_CTRL-x */
+ "?@[\\]^",
+ s[1]) != NULL))) {
+ if (d > IObuff && d[-1] != '_' && d[-1] != '\\') {
+ *d++ = '_'; // prepend a '_' to make x_CTRL-x
+ }
STRCPY(d, "CTRL-");
d += 5;
if (*s < ' ') {
*d++ = *s + '@';
- if (d[-1] == '\\')
- *d++ = '\\'; /* double a backslash */
- } else
+ if (d[-1] == '\\') {
+ *d++ = '\\'; // double a backslash
+ }
+ } else {
*d++ = *++s;
- if (s[1] != NUL && s[1] != '_')
- *d++ = '_'; /* append a '_' */
+ }
+ if (s[1] != NUL && s[1] != '_') {
+ *d++ = '_'; // append a '_'
+ }
continue;
- } else if (*s == '^') /* "^" or "CTRL-^" or "^_" */
+ } else if (*s == '^') { // "^" or "CTRL-^" or "^_"
*d++ = '\\';
-
+ }
/*
* Insert a backslash before a backslash after a slash, for search
* pattern tags: "/\|" --> "/\\|".
*/
else if (s[0] == '\\' && s[1] != '\\'
- && *arg == '/' && s == arg + 1)
+ && *arg == '/' && s == arg + 1) {
*d++ = '\\';
+ }
/* "CTRL-\_" -> "CTRL-\\_" to avoid the special meaning of "\_" in
* "CTRL-\_CTRL-N" */
@@ -5071,16 +5188,16 @@ int find_help_tags(const char_u *arg, int *num_matches, char_u ***matches,
if (*IObuff == '`') {
if (d > IObuff + 2 && d[-1] == '`') {
- /* remove the backticks from `command` */
+ // remove the backticks from `command`
memmove(IObuff, IObuff + 1, STRLEN(IObuff));
d[-2] = NUL;
} else if (d > IObuff + 3 && d[-2] == '`' && d[-1] == ',') {
- /* remove the backticks and comma from `command`, */
+ // remove the backticks and comma from `command`,
memmove(IObuff, IObuff + 1, STRLEN(IObuff));
d[-3] = NUL;
} else if (d > IObuff + 4 && d[-3] == '`'
&& d[-2] == '\\' && d[-1] == '.') {
- /* remove the backticks and dot from `command`\. */
+ // remove the backticks and dot from `command`\.
memmove(IObuff, IObuff + 1, STRLEN(IObuff));
d[-4] = NUL;
}
@@ -5099,10 +5216,11 @@ int find_help_tags(const char_u *arg, int *num_matches, char_u ***matches,
/* Sort the matches found on the heuristic number that is after the
* tag name. */
qsort((void *)*matches, (size_t)*num_matches,
- sizeof(char_u *), help_compare);
- /* Delete more than TAG_MANY to reduce the size of the listing. */
- while (*num_matches > TAG_MANY)
+ sizeof(char_u *), help_compare);
+ // Delete more than TAG_MANY to reduce the size of the listing.
+ while (*num_matches > TAG_MANY) {
xfree((*matches)[--*num_matches]);
+ }
}
return OK;
}
@@ -5154,14 +5272,14 @@ static void prepare_help_buffer(void)
void fix_help_buffer(void)
{
linenr_T lnum;
- char_u *line;
+ char_u *line;
bool in_example = false;
// Set filetype to "help".
if (STRCMP(curbuf->b_p_ft, "help") != 0) {
- curbuf_lock++;
+ curbuf->b_ro_locked++;
set_option_value("ft", 0L, "help", OPT_LOCAL);
- curbuf_lock--;
+ curbuf->b_ro_locked--;
}
if (!syntax_present(curwin)) {
@@ -5169,23 +5287,23 @@ void fix_help_buffer(void)
line = ml_get_buf(curbuf, lnum, false);
const size_t len = STRLEN(line);
if (in_example && len > 0 && !ascii_iswhite(line[0])) {
- /* End of example: non-white or '<' in first column. */
+ // End of example: non-white or '<' in first column.
if (line[0] == '<') {
- /* blank-out a '<' in the first column */
- line = ml_get_buf(curbuf, lnum, TRUE);
+ // blank-out a '<' in the first column
+ line = ml_get_buf(curbuf, lnum, true);
line[0] = ' ';
}
in_example = false;
}
if (!in_example && len > 0) {
if (line[len - 1] == '>' && (len == 1 || line[len - 2] == ' ')) {
- /* blank-out a '>' in the last column (start of example) */
- line = ml_get_buf(curbuf, lnum, TRUE);
+ // blank-out a '>' in the last column (start of example)
+ line = ml_get_buf(curbuf, lnum, true);
line[len - 1] = ' ';
in_example = true;
} else if (line[len - 1] == '~') {
- /* blank-out a '~' at the end of line (header marker) */
- line = ml_get_buf(curbuf, lnum, TRUE);
+ // blank-out a '~' at the end of line (header marker)
+ line = ml_get_buf(curbuf, lnum, true);
line[len - 1] = ' ';
}
}
@@ -5202,12 +5320,12 @@ void fix_help_buffer(void)
&& ASCII_ISALPHA(fname[5])
&& ASCII_ISALPHA(fname[6])
&& TOLOWER_ASC(fname[7]) == 'x'
- && fname[8] == NUL)
- ) {
- for (lnum = 1; lnum < curbuf->b_ml.ml_line_count; ++lnum) {
- line = ml_get_buf(curbuf, lnum, FALSE);
- if (strstr((char *)line, "*local-additions*") == NULL)
+ && fname[8] == NUL)) {
+ for (lnum = 1; lnum < curbuf->b_ml.ml_line_count; lnum++) {
+ line = ml_get_buf(curbuf, lnum, false);
+ if (strstr((char *)line, "*local-additions*") == NULL) {
continue;
+ }
/* Go through all directories in 'runtimepath', skipping
* $VIMRUNTIME. */
@@ -5218,10 +5336,10 @@ void fix_help_buffer(void)
if (rt != NULL
&& path_full_compare(rt, NameBuff, false, true) != kEqualFiles) {
int fcount;
- char_u **fnames;
- char_u *s;
+ char_u **fnames;
+ char_u *s;
vimconv_T vc;
- char_u *cp;
+ char_u *cp;
// Find all "doc/ *.txt" files in this directory.
if (!add_pathsep((char *)NameBuff)
@@ -5233,9 +5351,9 @@ void fix_help_buffer(void)
// Note: We cannot just do `&NameBuff` because it is a statically sized array
// so `NameBuff == &NameBuff` according to C semantics.
- char_u *buff_list[1] = {NameBuff};
+ char_u *buff_list[1] = { NameBuff };
if (gen_expand_wildcards(1, buff_list, &fcount,
- &fnames, EW_FILE|EW_SILENT) == OK
+ &fnames, EW_FILE|EW_SILENT) == OK
&& fcount > 0) {
// If foo.abx is found use it instead of foo.txt in
// the same directory.
@@ -5292,8 +5410,9 @@ void fix_help_buffer(void)
IObuff[0] = '|';
*s = '|';
while (*s != NUL) {
- if (*s == '\r' || *s == '\n')
+ if (*s == '\r' || *s == '\n') {
*s = NUL;
+ }
/* The text is utf-8 when a byte
* above 127 is found and no
* illegal byte sequence is found.
@@ -5312,10 +5431,9 @@ void fix_help_buffer(void)
* conversion to the current
* 'encoding' may be required. */
vc.vc_type = CONV_NONE;
- convert_setup(
- &vc,
- (char_u *)(this_utf == kTrue ? "utf-8" : "latin1"),
- p_enc);
+ convert_setup(&vc,
+ (char_u *)(this_utf == kTrue ? "utf-8" : "latin1"),
+ p_enc);
if (vc.vc_type == CONV_NONE) {
// No conversion needed.
cp = IObuff;
@@ -5372,15 +5490,15 @@ void ex_viusage(exarg_T *eap)
/// French)
/// @param add_help_tags Whether to add the "help-tags" tag
/// @param ignore_writeerr ignore write error
-static void helptags_one(char_u *dir, const char_u *ext, const char_u *tagfname,
- bool add_help_tags, bool ignore_writeerr)
+static void helptags_one(char_u *dir, const char_u *ext, const char_u *tagfname, bool add_help_tags,
+ bool ignore_writeerr)
FUNC_ATTR_NONNULL_ALL
{
garray_T ga;
int filecount;
- char_u **files;
- char_u *p1, *p2;
- char_u *s;
+ char_u **files;
+ char_u *p1, *p2;
+ char_u *s;
TriState utf8 = kNone;
bool mix = false; // detected mixed encodings
@@ -5395,9 +5513,9 @@ static void helptags_one(char_u *dir, const char_u *ext, const char_u *tagfname,
// Note: We cannot just do `&NameBuff` because it is a statically sized array
// so `NameBuff == &NameBuff` according to C semantics.
- char_u *buff_list[1] = {NameBuff};
+ char_u *buff_list[1] = { NameBuff };
if (gen_expand_wildcards(1, buff_list, &filecount, &files,
- EW_FILE|EW_SILENT) == FAIL
+ EW_FILE|EW_SILENT) == FAIL
|| filecount == 0) {
if (!got_int) {
EMSG2(_("E151: No match: %s"), NameBuff);
@@ -5431,8 +5549,9 @@ static void helptags_one(char_u *dir, const char_u *ext, const char_u *tagfname,
if (add_help_tags
|| path_full_compare((char_u *)"$VIMRUNTIME/doc",
dir, false, true) == kEqualFiles) {
- s = xmalloc(18 + STRLEN(tagfname));
- sprintf((char *)s, "help-tags\t%s\t1\n", tagfname);
+ size_t s_len = 18 + STRLEN(tagfname);
+ s = xmalloc(s_len);
+ snprintf((char *)s, s_len, "help-tags\t%s\t1\n", tagfname);
GA_APPEND(char_u *, &ga, s);
}
@@ -5468,9 +5587,8 @@ static void helptags_one(char_u *dir, const char_u *ext, const char_u *tagfname,
if (utf8 == kNone) { // first file
utf8 = this_utf8;
} else if (utf8 != this_utf8) {
- EMSG2(_(
- "E670: Mix of help file encodings within a language: %s"),
- files[fi]);
+ EMSG2(_("E670: Mix of help file encodings within a language: %s"),
+ files[fi]);
mix = !got_int;
got_int = TRUE;
}
@@ -5494,10 +5612,11 @@ static void helptags_one(char_u *dir, const char_u *ext, const char_u *tagfname,
&& (vim_strchr((char_u *)" \t\n\r", s[1]) != NULL
|| s[1] == '\0')) {
*p2 = '\0';
- ++p1;
- s = xmalloc((p2 - p1) + STRLEN(fname) + 2);
+ p1++;
+ size_t s_len= (p2 - p1) + STRLEN(fname) + 2;
+ s = xmalloc(s_len);
GA_APPEND(char_u *, &ga, s);
- sprintf((char *)s, "%s\t%s", p1, fname);
+ snprintf((char *)s, s_len, "%s\t%s", p1, fname);
// find next '*'
p2 = vim_strchr(p2 + 1, '*');
@@ -5525,8 +5644,8 @@ static void helptags_one(char_u *dir, const char_u *ext, const char_u *tagfname,
if (*p2 == '\t') {
*p2 = NUL;
vim_snprintf((char *)NameBuff, MAXPATHL,
- _("E154: Duplicate tag \"%s\" in file %s/%s"),
- ((char_u **)ga.ga_data)[i], dir, p2 + 1);
+ _("E154: Duplicate tag \"%s\" in file %s/%s"),
+ ((char_u **)ga.ga_data)[i], dir, p2 + 1);
EMSG(NameBuff);
*p2 = '\t';
break;
@@ -5568,8 +5687,7 @@ static void helptags_one(char_u *dir, const char_u *ext, const char_u *tagfname,
}
/// Generate tags in one help directory, taking care of translations.
-static void do_helptags(char_u *dirname, bool add_help_tags,
- bool ignore_writeerr)
+static void do_helptags(char_u *dirname, bool add_help_tags, bool ignore_writeerr)
FUNC_ATTR_NONNULL_ALL
{
int len;
@@ -5590,7 +5708,7 @@ static void do_helptags(char_u *dirname, bool add_help_tags,
// Note: We cannot just do `&NameBuff` because it is a statically sized array
// so `NameBuff == &NameBuff` according to C semantics.
- char_u *buff_list[1] = {NameBuff};
+ char_u *buff_list[1] = { NameBuff };
if (gen_expand_wildcards(1, buff_list, &filecount, &files,
EW_FILE|EW_SILENT) == FAIL
|| filecount == 0) {
@@ -5608,18 +5726,19 @@ static void do_helptags(char_u *dirname, bool add_help_tags,
continue;
}
if (STRICMP(files[i] + len - 4, ".txt") == 0) {
- /* ".txt" -> language "en" */
+ // ".txt" -> language "en"
lang[0] = 'e';
lang[1] = 'n';
} else if (files[i][len - 4] == '.'
&& ASCII_ISALPHA(files[i][len - 3])
&& ASCII_ISALPHA(files[i][len - 2])
&& TOLOWER_ASC(files[i][len - 1]) == 'x') {
- /* ".abx" -> language "ab" */
+ // ".abx" -> language "ab"
lang[0] = TOLOWER_ASC(files[i][len - 3]);
lang[1] = TOLOWER_ASC(files[i][len - 2]);
- } else
+ } else {
continue;
+ }
// Did we find this language already?
for (j = 0; j < ga.ga_len; j += 2) {
@@ -5643,11 +5762,11 @@ static void do_helptags(char_u *dirname, bool add_help_tags,
fname[5] = ((char_u *)ga.ga_data)[j];
fname[6] = ((char_u *)ga.ga_data)[j + 1];
if (fname[5] == 'e' && fname[6] == 'n') {
- /* English is an exception: use ".txt" and "tags". */
+ // English is an exception: use ".txt" and "tags".
fname[4] = NUL;
STRCPY(ext, ".txt");
} else {
- /* Language "ab" uses ".abx" and "tags-ab". */
+ // Language "ab" uses ".abx" and "tags-ab".
STRCPY(ext, ".xxx");
ext[1] = fname[5];
ext[2] = fname[6];
@@ -5662,7 +5781,7 @@ static void do_helptags(char_u *dirname, bool add_help_tags,
static void helptags_cb(char_u *fname, void *cookie)
FUNC_ATTR_NONNULL_ALL
{
- do_helptags(fname, *(bool *)cookie, true);
+ do_helptags(fname, *(bool *)cookie, true);
}
/*
@@ -5674,7 +5793,7 @@ void ex_helptags(exarg_T *eap)
char_u *dirname;
bool add_help_tags = false;
- /* Check for ":helptags ++t {dir}". */
+ // Check for ":helptags ++t {dir}".
if (STRNCMP(eap->arg, "++t", 3) == 0 && ascii_iswhite(eap->arg[3])) {
add_help_tags = true;
eap->arg = skipwhite(eap->arg + 3);
@@ -5730,9 +5849,8 @@ int sub_preview_win(buf_T *preview_buf)
/// Shows the effects of the :substitute command being typed ('inccommand').
/// If inccommand=split, shows a preview window and later restores the layout.
-static buf_T *show_sub(exarg_T *eap, pos_T old_cusr,
- PreviewLines *preview_lines, int hl_id, int src_id,
- handle_T bufnr)
+static buf_T *show_sub(exarg_T *eap, pos_T old_cusr, PreviewLines *preview_lines, int hl_id,
+ int src_id, handle_T bufnr)
FUNC_ATTR_NONNULL_ALL
{
win_T *save_curwin = curwin;
@@ -5881,12 +5999,12 @@ static buf_T *show_sub(exarg_T *eap, pos_T old_cusr,
/// Closes any open windows for inccommand preview buffer.
void close_preview_windows(void)
{
- block_autocmds();
- buf_T *buf = preview_bufnr ? buflist_findnr(preview_bufnr) : NULL;
- if (buf != NULL) {
- close_windows(buf, false);
- }
- unblock_autocmds();
+ block_autocmds();
+ buf_T *buf = preview_bufnr ? buflist_findnr(preview_bufnr) : NULL;
+ if (buf != NULL) {
+ close_windows(buf, false);
+ }
+ unblock_autocmds();
}
/// :substitute command
@@ -5934,7 +6052,9 @@ void ex_substitute(exarg_T *eap)
if (save_changedtick != buf_get_changedtick(curbuf)) {
// Undo invisibly. This also moves the cursor!
- if (!u_undo_and_forget(1)) { abort(); }
+ if (!u_undo_and_forget(1)) {
+ abort();
+ }
// Restore newhead. It is meaningless when curhead is valid, but we must
// restore it so that undotree() is identical before/after the preview.
curbuf->b_u_newhead = save_b_u_newhead;
@@ -6005,7 +6125,7 @@ char_u *skip_vimgrep_pat(char_u *p, char_u **s, int *flags)
/// List v:oldfiles in a nice way.
void ex_oldfiles(exarg_T *eap)
{
- list_T *l = get_vim_var_list(VV_OLDFILES);
+ list_T *l = get_vim_var_list(VV_OLDFILES);
long nr = 0;
if (l == NULL) {
diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua
index 7b971f464f..c388373ac1 100644
--- a/src/nvim/ex_cmds.lua
+++ b/src/nvim/ex_cmds.lua
@@ -3271,7 +3271,7 @@ module.cmds = {
},
{
command='z',
- flags=bit.bor(RANGE, WHOLEFOLD, EXTRA, FLAGS, TRLBAR, CMDWIN),
+ flags=bit.bor(RANGE, WHOLEFOLD, BANG, EXTRA, FLAGS, TRLBAR, CMDWIN),
addr_type='ADDR_LINES',
func='ex_z',
},
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 9d500a8ddb..46b86fbc84 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -6,62 +6,58 @@
/// Some more functions for command line commands
#include <assert.h>
+#include <fcntl.h>
#include <inttypes.h>
#include <stdbool.h>
#include <string.h>
-#include <fcntl.h>
-#include "nvim/vim.h"
#include "nvim/ascii.h"
+#include "nvim/vim.h"
#ifdef HAVE_LOCALE_H
# include <locale.h>
#endif
-#include "nvim/ex_cmds2.h"
+#include "nvim/api/private/defs.h"
+#include "nvim/api/private/helpers.h"
#include "nvim/buffer.h"
#include "nvim/change.h"
#include "nvim/charset.h"
+#include "nvim/debugger.h"
#include "nvim/eval/userfunc.h"
#include "nvim/ex_cmds.h"
-#include "nvim/ex_docmd.h"
+#include "nvim/ex_cmds2.h"
#include "nvim/ex_eval.h"
#include "nvim/ex_getln.h"
#include "nvim/fileio.h"
-#include "nvim/getchar.h"
-#include "nvim/globals.h"
+#include "nvim/garray.h"
+#include "nvim/lua/executor.h"
#include "nvim/mark.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
+#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
-#include "nvim/garray.h"
-#include "nvim/memory.h"
#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/ops.h"
#include "nvim/option.h"
+#include "nvim/os/fs_defs.h"
+#include "nvim/os/shell.h"
#include "nvim/os_unix.h"
#include "nvim/path.h"
+#include "nvim/profile.h"
#include "nvim/quickfix.h"
#include "nvim/regexp.h"
-#include "nvim/screen.h"
#include "nvim/strings.h"
#include "nvim/undo.h"
#include "nvim/version.h"
#include "nvim/window.h"
-#include "nvim/profile.h"
-#include "nvim/os/os.h"
-#include "nvim/os/shell.h"
-#include "nvim/os/fs_defs.h"
-#include "nvim/api/private/helpers.h"
-#include "nvim/api/private/defs.h"
-#include "nvim/lua/executor.h"
/// Growarray to store info about already sourced scripts.
/// Also store the dev/ino, so that we don't have to stat() each
/// script when going through the list.
typedef struct scriptitem_S {
- char_u *sn_name;
+ char_u *sn_name;
bool file_id_valid;
FileID file_id;
bool sn_prof_on; ///< true when script is/was profiled
@@ -113,822 +109,20 @@ struct source_cookie {
vimconv_T conv; ///< type of conversion
};
-# define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
+#define PRL_ITEM(si, idx) (((sn_prl_T *)(si)->sn_prl_ga.ga_data)[(idx)])
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ex_cmds2.c.generated.h"
#endif
-/// batch mode debugging: don't save and restore typeahead.
-static bool debug_greedy = false;
-
-static char *debug_oldval = NULL; // old and newval for debug expressions
-static char *debug_newval = NULL;
-
-/// Debug mode. Repeatedly get Ex commands, until told to continue normal
-/// execution.
-void do_debug(char_u *cmd)
-{
- int save_msg_scroll = msg_scroll;
- int save_State = State;
- int save_did_emsg = did_emsg;
- const bool save_cmd_silent = cmd_silent;
- int save_msg_silent = msg_silent;
- int save_emsg_silent = emsg_silent;
- int save_redir_off = redir_off;
- tasave_T typeaheadbuf;
- bool typeahead_saved = false;
- int save_ignore_script = 0;
- int save_ex_normal_busy;
- int n;
- char_u *cmdline = NULL;
- char_u *p;
- char *tail = NULL;
- static int last_cmd = 0;
-#define CMD_CONT 1
-#define CMD_NEXT 2
-#define CMD_STEP 3
-#define CMD_FINISH 4
-#define CMD_QUIT 5
-#define CMD_INTERRUPT 6
-#define CMD_BACKTRACE 7
-#define CMD_FRAME 8
-#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
- cmd_silent = false; // display commands
- msg_silent = false; // display messages
- emsg_silent = false; // display error messages
- redir_off = true; // don't redirect debug commands
-
- State = NORMAL;
- debug_mode = true;
-
- if (!debug_did_msg) {
- MSG(_("Entering Debug mode. Type \"cont\" to continue."));
- }
- if (debug_oldval != NULL) {
- smsg(_("Oldval = \"%s\""), debug_oldval);
- xfree(debug_oldval);
- debug_oldval = NULL;
- }
- if (debug_newval != NULL) {
- smsg(_("Newval = \"%s\""), debug_newval);
- xfree(debug_newval);
- debug_newval = NULL;
- }
- if (sourcing_name != NULL) {
- msg(sourcing_name);
- }
- if (sourcing_lnum != 0) {
- smsg(_("line %" PRId64 ": %s"), (int64_t)sourcing_lnum, cmd);
- } else {
- smsg(_("cmd: %s"), cmd);
- }
- // Repeat getting a command and executing it.
- for (;; ) {
- msg_scroll = true;
- need_wait_return = false;
- // Save the current typeahead buffer and replace it with an empty one.
- // This makes sure we get input from the user here and don't interfere
- // with the commands being executed. Reset "ex_normal_busy" to avoid
- // the side effects of using ":normal". Save the stuff buffer and make
- // it empty. Set ignore_script to avoid reading from script input.
- save_ex_normal_busy = ex_normal_busy;
- ex_normal_busy = 0;
- if (!debug_greedy) {
- save_typeahead(&typeaheadbuf);
- typeahead_saved = true;
- save_ignore_script = ignore_script;
- ignore_script = true;
- }
-
- xfree(cmdline);
- cmdline = (char_u *)getcmdline_prompt('>', NULL, 0, EXPAND_NOTHING, NULL,
- CALLBACK_NONE);
-
- if (typeahead_saved) {
- restore_typeahead(&typeaheadbuf);
- ignore_script = save_ignore_script;
- }
- ex_normal_busy = save_ex_normal_busy;
-
- cmdline_row = msg_row;
- msg_starthere();
- if (cmdline != NULL) {
- // If this is a debug command, set "last_cmd".
- // If not, reset "last_cmd".
- // For a blank line use previous command.
- p = skipwhite(cmdline);
- if (*p != NUL) {
- switch (*p) {
- case 'c': last_cmd = CMD_CONT;
- tail = "ont";
- break;
- case 'n': last_cmd = CMD_NEXT;
- tail = "ext";
- break;
- case 's': last_cmd = CMD_STEP;
- tail = "tep";
- break;
- case 'f':
- last_cmd = 0;
- if (p[1] == 'r') {
- last_cmd = CMD_FRAME;
- tail = "rame";
- } else {
- last_cmd = CMD_FINISH;
- tail = "inish";
- }
- break;
- case 'q': last_cmd = CMD_QUIT;
- tail = "uit";
- break;
- case 'i': last_cmd = CMD_INTERRUPT;
- tail = "nterrupt";
- break;
- case 'b':
- last_cmd = CMD_BACKTRACE;
- if (p[1] == 't') {
- tail = "t";
- } else {
- tail = "acktrace";
- }
- break;
- case 'w':
- last_cmd = CMD_BACKTRACE;
- tail = "here";
- break;
- case 'u':
- last_cmd = CMD_UP;
- tail = "p";
- break;
- case 'd':
- last_cmd = CMD_DOWN;
- tail = "own";
- break;
- default: last_cmd = 0;
- }
- if (last_cmd != 0) {
- // Check that the tail matches.
- p++;
- while (*p != NUL && *p == *tail) {
- p++;
- tail++;
- }
- if (ASCII_ISALPHA(*p) && last_cmd != CMD_FRAME) {
- last_cmd = 0;
- }
- }
- }
-
- if (last_cmd != 0) {
- // Execute debug command: decided where to break next and return.
- switch (last_cmd) {
- case CMD_CONT:
- debug_break_level = -1;
- break;
- case CMD_NEXT:
- debug_break_level = ex_nesting_level;
- break;
- case CMD_STEP:
- debug_break_level = 9999;
- break;
- case CMD_FINISH:
- debug_break_level = ex_nesting_level - 1;
- break;
- case CMD_QUIT:
- got_int = true;
- debug_break_level = -1;
- break;
- case CMD_INTERRUPT:
- got_int = true;
- debug_break_level = 9999;
- // Do not repeat ">interrupt" cmd, continue stepping.
- last_cmd = CMD_STEP;
- break;
- case CMD_BACKTRACE:
- do_showbacktrace(cmd);
- continue;
- case CMD_FRAME:
- if (*p == NUL) {
- do_showbacktrace(cmd);
- } else {
- p = skipwhite(p);
- do_setdebugtracelevel(p);
- }
- continue;
- case CMD_UP:
- debug_backtrace_level++;
- do_checkbacktracelevel();
- continue;
- case CMD_DOWN:
- debug_backtrace_level--;
- do_checkbacktracelevel();
- continue;
- }
- // Going out reset backtrace_level
- debug_backtrace_level = 0;
- break;
- }
-
- // don't debug this command
- n = debug_break_level;
- debug_break_level = -1;
- (void)do_cmdline(cmdline, getexline, NULL,
- DOCMD_VERBOSE|DOCMD_EXCRESET);
- debug_break_level = n;
- }
- lines_left = (int)(Rows - 1);
- }
- xfree(cmdline);
-
- RedrawingDisabled--;
- no_wait_return--;
- redraw_all_later(NOT_VALID);
- need_wait_return = false;
- msg_scroll = save_msg_scroll;
- lines_left = (int)(Rows - 1);
- State = save_State;
- debug_mode = false;
- did_emsg = save_did_emsg;
- cmd_silent = save_cmd_silent;
- msg_silent = save_msg_silent;
- emsg_silent = save_emsg_silent;
- redir_off = save_redir_off;
-
- // Only print the message again when typing a command before coming back here.
- debug_did_msg = true;
-}
-
-static int get_maxbacktrace_level(void)
-{
- int maxbacktrace = 0;
-
- if (sourcing_name != NULL) {
- char *p = (char *)sourcing_name;
- char *q;
- while ((q = strstr(p, "..")) != NULL) {
- p = q + 2;
- maxbacktrace++;
- }
- }
- return maxbacktrace;
-}
-
-static void do_setdebugtracelevel(char_u *arg)
-{
- int level = atoi((char *)arg);
- if (*arg == '+' || level < 0) {
- debug_backtrace_level += level;
- } else {
- debug_backtrace_level = level;
- }
-
- do_checkbacktracelevel();
-}
-
-static void do_checkbacktracelevel(void)
-{
- if (debug_backtrace_level < 0) {
- debug_backtrace_level = 0;
- MSG(_("frame is zero"));
- } else {
- int max = get_maxbacktrace_level();
- if (debug_backtrace_level > max) {
- debug_backtrace_level = max;
- smsg(_("frame at highest level: %d"), max);
- }
- }
-}
-
-static void do_showbacktrace(char_u *cmd)
-{
- if (sourcing_name != NULL) {
- int i = 0;
- int max = get_maxbacktrace_level();
- char *cur = (char *)sourcing_name;
- while (!got_int) {
- char *next = strstr(cur, "..");
- if (next != NULL) {
- *next = NUL;
- }
- if (i == max - debug_backtrace_level) {
- smsg("->%d %s", max - i, cur);
- } else {
- smsg(" %d %s", max - i, cur);
- }
- i++;
- if (next == NULL) {
- break;
- }
- *next = '.';
- cur = next + 2;
- }
- }
- if (sourcing_lnum != 0) {
- smsg(_("line %" PRId64 ": %s"), (int64_t)sourcing_lnum, cmd);
- } else {
- smsg(_("cmd: %s"), cmd);
- }
-}
-
-
-/// ":debug".
-void ex_debug(exarg_T *eap)
-{
- int debug_break_level_save = debug_break_level;
-
- debug_break_level = 9999;
- do_cmdline_cmd((char *)eap->arg);
- debug_break_level = debug_break_level_save;
-}
-
-static char_u *debug_breakpoint_name = NULL;
-static linenr_T debug_breakpoint_lnum;
-
-/// When debugging or a breakpoint is set on a skipped command, no debug prompt
-/// is shown by do_one_cmd(). This situation is indicated by debug_skipped, and
-/// debug_skipped_name is then set to the source name in the breakpoint case. If
-/// a skipped command decides itself that a debug prompt should be displayed, it
-/// can do so by calling dbg_check_skipped().
-static int debug_skipped;
-static char_u *debug_skipped_name;
-
-/// Go to debug mode when a breakpoint was encountered or "ex_nesting_level" is
-/// at or below the break level. But only when the line is actually
-/// executed. Return true and set breakpoint_name for skipped commands that
-/// decide to execute something themselves.
-/// Called from do_one_cmd() before executing a command.
-void dbg_check_breakpoint(exarg_T *eap)
-{
- char_u *p;
-
- debug_skipped = false;
- if (debug_breakpoint_name != NULL) {
- if (!eap->skip) {
- // replace K_SNR with "<SNR>"
- if (debug_breakpoint_name[0] == K_SPECIAL
- && debug_breakpoint_name[1] == KS_EXTRA
- && debug_breakpoint_name[2] == (int)KE_SNR) {
- p = (char_u *)"<SNR>";
- } else {
- p = (char_u *)"";
- }
- smsg(_("Breakpoint in \"%s%s\" line %" PRId64),
- p,
- debug_breakpoint_name + (*p == NUL ? 0 : 3),
- (int64_t)debug_breakpoint_lnum);
- debug_breakpoint_name = NULL;
- do_debug(eap->cmd);
- } else {
- debug_skipped = true;
- debug_skipped_name = debug_breakpoint_name;
- debug_breakpoint_name = NULL;
- }
- } else if (ex_nesting_level <= debug_break_level) {
- if (!eap->skip) {
- do_debug(eap->cmd);
- } else {
- debug_skipped = true;
- debug_skipped_name = NULL;
- }
- }
-}
-
-/// Go to debug mode if skipped by dbg_check_breakpoint() because eap->skip was
-/// set.
-///
-/// @return true when the debug mode is entered this time.
-bool dbg_check_skipped(exarg_T *eap)
-{
- int prev_got_int;
-
- if (debug_skipped) {
- // Save the value of got_int and reset it. We don't want a previous
- // interruption cause flushing the input buffer.
- prev_got_int = got_int;
- got_int = false;
- debug_breakpoint_name = debug_skipped_name;
- // eap->skip is true
- eap->skip = false;
- dbg_check_breakpoint(eap);
- eap->skip = true;
- got_int |= prev_got_int;
- return true;
- }
- return false;
-}
-
-/// The list of breakpoints: dbg_breakp.
-/// This is a grow-array of structs.
-struct debuggy {
- int dbg_nr; ///< breakpoint number
- int dbg_type; ///< DBG_FUNC or DBG_FILE or DBG_EXPR
- char_u *dbg_name; ///< function, expression or file name
- regprog_T *dbg_prog; ///< regexp program
- linenr_T dbg_lnum; ///< line number in function or file
- int dbg_forceit; ///< ! used
- typval_T *dbg_val; ///< last result of watchexpression
- int dbg_level; ///< stored nested level for expr
-};
-
-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])
-static int last_breakp = 0; // nr of last defined breakpoint
-
-// Profiling uses file and func names similar to breakpoints.
-static garray_T prof_ga = { 0, 0, sizeof(struct debuggy), 4, NULL };
-#define DBG_FUNC 1
-#define DBG_FILE 2
-#define DBG_EXPR 3
-
-
-/// Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them
-/// in the entry just after the last one in dbg_breakp. Note that "dbg_name"
-/// is allocated.
-/// Returns FAIL for failure.
-///
-/// @param arg
-/// @param gap either &dbg_breakp or &prof_ga
-static int dbg_parsearg(char_u *arg, garray_T *gap)
-{
- char_u *p = arg;
- char_u *q;
- struct debuggy *bp;
- bool here = false;
-
- ga_grow(gap, 1);
-
- bp = &DEBUGGY(gap, gap->ga_len);
-
- // Find "func" or "file".
- if (STRNCMP(p, "func", 4) == 0) {
- bp->dbg_type = DBG_FUNC;
- } else if (STRNCMP(p, "file", 4) == 0) {
- bp->dbg_type = DBG_FILE;
- } else if (gap != &prof_ga && STRNCMP(p, "here", 4) == 0) {
- if (curbuf->b_ffname == NULL) {
- EMSG(_(e_noname));
- return FAIL;
- }
- bp->dbg_type = DBG_FILE;
- here = true;
- } else if (gap != &prof_ga && STRNCMP(p, "expr", 4) == 0) {
- bp->dbg_type = DBG_EXPR;
- } else {
- EMSG2(_(e_invarg2), p);
- return FAIL;
- }
- p = skipwhite(p + 4);
-
- // Find optional line number.
- if (here) {
- bp->dbg_lnum = curwin->w_cursor.lnum;
- } else if (gap != &prof_ga && ascii_isdigit(*p)) {
- bp->dbg_lnum = getdigits_long(&p, true, 0);
- p = skipwhite(p);
- } else {
- bp->dbg_lnum = 0;
- }
-
- // Find the function or file name. Don't accept a function name with ().
- if ((!here && *p == NUL)
- || (here && *p != NUL)
- || (bp->dbg_type == DBG_FUNC && strstr((char *)p, "()") != NULL)) {
- EMSG2(_(e_invarg2), arg);
- return FAIL;
- }
-
- if (bp->dbg_type == DBG_FUNC) {
- bp->dbg_name = vim_strsave(p);
- } else if (here) {
- bp->dbg_name = vim_strsave(curbuf->b_ffname);
- } else if (bp->dbg_type == DBG_EXPR) {
- bp->dbg_name = vim_strsave(p);
- bp->dbg_val = eval_expr(bp->dbg_name);
- } else {
- // Expand the file name in the same way as do_source(). This means
- // doing it twice, so that $DIR/file gets expanded when $DIR is
- // "~/dir".
- q = expand_env_save(p);
- if (q == NULL) {
- return FAIL;
- }
- p = expand_env_save(q);
- xfree(q);
- if (p == NULL) {
- return FAIL;
- }
- if (*p != '*') {
- bp->dbg_name = (char_u *)fix_fname((char *)p);
- xfree(p);
- } else {
- bp->dbg_name = p;
- }
- }
-
- if (bp->dbg_name == NULL) {
- return FAIL;
- }
- return OK;
-}
-
-/// ":breakadd". Also used for ":profile".
-void ex_breakadd(exarg_T *eap)
-{
- struct debuggy *bp;
- garray_T *gap;
-
- gap = &dbg_breakp;
- if (eap->cmdidx == CMD_profile) {
- gap = &prof_ga;
- }
-
- if (dbg_parsearg(eap->arg, gap) == OK) {
- bp = &DEBUGGY(gap, gap->ga_len);
- bp->dbg_forceit = eap->forceit;
-
- if (bp->dbg_type != DBG_EXPR) {
- char_u *pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, false);
- if (pat != NULL) {
- bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
- xfree(pat);
- }
- if (pat == NULL || bp->dbg_prog == NULL) {
- xfree(bp->dbg_name);
- } else {
- if (bp->dbg_lnum == 0) { // default line number is 1
- bp->dbg_lnum = 1;
- }
- if (eap->cmdidx != CMD_profile) {
- DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
- debug_tick++;
- }
- gap->ga_len++;
- }
- } else {
- // DBG_EXPR
- DEBUGGY(gap, gap->ga_len++).dbg_nr = ++last_breakp;
- debug_tick++;
- }
- }
-}
-
-/// ":debuggreedy".
-void ex_debuggreedy(exarg_T *eap)
-{
- if (eap->addr_count == 0 || eap->line2 != 0) {
- debug_greedy = true;
- } else {
- debug_greedy = false;
- }
-}
-
-/// ":breakdel" and ":profdel".
-void ex_breakdel(exarg_T *eap)
-{
- struct debuggy *bp, *bpi;
- int nr;
- int todel = -1;
- bool del_all = false;
- linenr_T best_lnum = 0;
- garray_T *gap;
-
- gap = &dbg_breakp;
- if (eap->cmdidx == CMD_profdel) {
- gap = &prof_ga;
- }
-
- if (ascii_isdigit(*eap->arg)) {
- // ":breakdel {nr}"
- nr = atoi((char *)eap->arg);
- for (int i = 0; i < gap->ga_len; i++) {
- if (DEBUGGY(gap, i).dbg_nr == nr) {
- todel = i;
- break;
- }
- }
- } else if (*eap->arg == '*') {
- todel = 0;
- del_all = true;
- } else {
- // ":breakdel {func|file|expr} [lnum] {name}"
- if (dbg_parsearg(eap->arg, gap) == FAIL) {
- return;
- }
- bp = &DEBUGGY(gap, gap->ga_len);
- for (int i = 0; i < gap->ga_len; i++) {
- bpi = &DEBUGGY(gap, i);
- if (bp->dbg_type == bpi->dbg_type
- && STRCMP(bp->dbg_name, bpi->dbg_name) == 0
- && (bp->dbg_lnum == bpi->dbg_lnum
- || (bp->dbg_lnum == 0
- && (best_lnum == 0
- || bpi->dbg_lnum < best_lnum)))) {
- todel = i;
- best_lnum = bpi->dbg_lnum;
- }
- }
- xfree(bp->dbg_name);
- }
-
- if (todel < 0) {
- EMSG2(_("E161: Breakpoint not found: %s"), eap->arg);
- } else {
- while (!GA_EMPTY(gap)) {
- xfree(DEBUGGY(gap, todel).dbg_name);
- if (DEBUGGY(gap, todel).dbg_type == DBG_EXPR
- && DEBUGGY(gap, todel).dbg_val != NULL) {
- tv_free(DEBUGGY(gap, todel).dbg_val);
- }
- vim_regfree(DEBUGGY(gap, todel).dbg_prog);
- gap->ga_len--;
- if (todel < gap->ga_len) {
- memmove(&DEBUGGY(gap, todel), &DEBUGGY(gap, todel + 1),
- (size_t)(gap->ga_len - todel) * sizeof(struct debuggy));
- }
- if (eap->cmdidx == CMD_breakdel) {
- debug_tick++;
- }
- if (!del_all) {
- break;
- }
- }
-
- // If all breakpoints were removed clear the array.
- if (GA_EMPTY(gap)) {
- ga_clear(gap);
- }
- }
-}
-
-/// ":breaklist".
-void ex_breaklist(exarg_T *eap)
-{
- struct debuggy *bp;
-
- if (GA_EMPTY(&dbg_breakp)) {
- MSG(_("No breakpoints defined"));
- } else {
- for (int i = 0; i < dbg_breakp.ga_len; i++) {
- bp = &BREAKP(i);
- if (bp->dbg_type == DBG_FILE) {
- home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, true);
- }
- if (bp->dbg_type != DBG_EXPR) {
- smsg(_("%3d %s %s line %" PRId64),
- bp->dbg_nr,
- bp->dbg_type == DBG_FUNC ? "func" : "file",
- bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff,
- (int64_t)bp->dbg_lnum);
- } else {
- smsg(_("%3d expr %s"), bp->dbg_nr, bp->dbg_name);
- }
- }
- }
-}
-
-/// Find a breakpoint for a function or sourced file.
-/// Returns line number at which to break; zero when no matching breakpoint.
-linenr_T
-dbg_find_breakpoint(
- bool file, // true for a file, false for a function
- char_u *fname, // file or function name
- linenr_T after // after this line number
-)
-{
- return debuggy_find(file, fname, after, &dbg_breakp, NULL);
-}
-
-/// @param file true for a file, false for a function
-/// @param fname file or function name
-/// @param fp[out] forceit
-///
-/// @returns true if profiling is on for a function or sourced file.
-bool has_profiling(bool file, char_u *fname, bool *fp)
-{
- return debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
- != (linenr_T)0;
-}
-
-/// Common code for dbg_find_breakpoint() and has_profiling().
-static linenr_T
-debuggy_find(
- bool file, // true for a file, false for a function
- char_u *fname, // file or function name
- linenr_T after, // after this line number
- garray_T *gap, // either &dbg_breakp or &prof_ga
- bool *fp // if not NULL: return forceit
-)
-{
- struct debuggy *bp;
- linenr_T lnum = 0;
- char_u *name = fname;
- int prev_got_int;
-
- // Return quickly when there are no breakpoints.
- if (GA_EMPTY(gap)) {
- return (linenr_T)0;
- }
-
- // Replace K_SNR in function name with "<SNR>".
- if (!file && fname[0] == K_SPECIAL) {
- name = xmalloc(STRLEN(fname) + 3);
- STRCPY(name, "<SNR>");
- STRCPY(name + 5, fname + 3);
- }
-
- for (int i = 0; i < gap->ga_len; i++) {
- // Skip entries that are not useful or are for a line that is beyond
- // an already found breakpoint.
- bp = &DEBUGGY(gap, i);
- if ((bp->dbg_type == DBG_FILE) == file
- && bp->dbg_type != DBG_EXPR
- && (gap == &prof_ga
- || (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))) {
- // Save the value of got_int and reset it. We don't want a
- // previous interruption cancel matching, only hitting CTRL-C
- // while matching should abort it.
- prev_got_int = got_int;
- got_int = false;
- if (vim_regexec_prog(&bp->dbg_prog, false, name, (colnr_T)0)) {
- lnum = bp->dbg_lnum;
- if (fp != NULL) {
- *fp = bp->dbg_forceit;
- }
- }
- got_int |= prev_got_int;
- } else if (bp->dbg_type == DBG_EXPR) {
- bool line = false;
-
- prev_got_int = got_int;
- got_int = false;
-
- typval_T *tv = eval_expr(bp->dbg_name);
- if (tv != NULL) {
- if (bp->dbg_val == NULL) {
- debug_oldval = typval_tostring(NULL);
- bp->dbg_val = tv;
- debug_newval = typval_tostring(bp->dbg_val);
- line = true;
- } else {
- if (typval_compare(tv, bp->dbg_val, EXPR_IS, false) == OK
- && tv->vval.v_number == false) {
- line = true;
- debug_oldval = typval_tostring(bp->dbg_val);
- // Need to evaluate again, typval_compare() overwrites "tv".
- typval_T *v = eval_expr(bp->dbg_name);
- debug_newval = typval_tostring(v);
- tv_free(bp->dbg_val);
- bp->dbg_val = v;
- }
- tv_free(tv);
- }
- } else if (bp->dbg_val != NULL) {
- debug_oldval = typval_tostring(bp->dbg_val);
- debug_newval = typval_tostring(NULL);
- tv_free(bp->dbg_val);
- bp->dbg_val = NULL;
- line = true;
- }
-
- if (line) {
- lnum = after > 0 ? after : 1;
- break;
- }
-
- got_int |= prev_got_int;
- }
- }
- if (name != fname) {
- xfree(name);
- }
-
- return lnum;
-}
-
-/// Called when a breakpoint was encountered.
-void dbg_breakpoint(char_u *name, linenr_T lnum)
-{
- // We need to check if this line is actually executed in do_one_cmd()
- debug_breakpoint_name = name;
- debug_breakpoint_lnum = lnum;
-}
-
-static char_u *profile_fname = NULL;
+static char_u *profile_fname = NULL;
/// ":profile cmd args"
void ex_profile(exarg_T *eap)
{
static proftime_T pause_time;
- char_u *e;
+ char_u *e;
int len;
e = skiptowhite(eap->arg);
@@ -1083,7 +277,7 @@ void set_context_in_profile_cmd(expand_T *xp, const char *arg)
/// Dump the profiling info.
void profile_dump(void)
{
- FILE *fd;
+ FILE *fd;
if (profile_fname != NULL) {
fd = os_fopen((char *)profile_fname, "w");
@@ -1123,7 +317,7 @@ static void profile_reset(void)
}
// Reset functions.
- size_t n = func_hashtab.ht_used;
+ size_t n = func_hashtab.ht_used;
hashitem_T *hi = func_hashtab.ht_array;
for (; n > (size_t)0; hi++) {
@@ -1168,11 +362,11 @@ static void profile_init(scriptitem_T *si)
}
/// Save time when starting to invoke another script or function.
-void script_prof_save(
- proftime_T *tm // place to store wait time
-)
+///
+/// @param tm place to store wait time
+void script_prof_save(proftime_T *tm)
{
- scriptitem_T *si;
+ scriptitem_T *si;
if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len) {
si = &SCRIPT_ITEM(current_sctx.sc_sid);
@@ -1186,7 +380,7 @@ void script_prof_save(
/// Count time spent in children after invoking another script or function.
void script_prof_restore(proftime_T *tm)
{
- scriptitem_T *si;
+ scriptitem_T *si;
if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len) {
si = &SCRIPT_ITEM(current_sctx.sc_sid);
@@ -1218,9 +412,9 @@ void prof_inchar_exit(void)
/// Dump the profiling results for all scripts in file "fd".
static void script_dump_profile(FILE *fd)
{
- scriptitem_T *si;
- FILE *sfd;
- sn_prl_T *pp;
+ scriptitem_T *si;
+ FILE *sfd;
+ sn_prl_T *pp;
for (int id = 1; id <= script_items.ga_len; id++) {
si = &SCRIPT_ITEM(id);
@@ -1460,7 +654,7 @@ bool dialog_close_terminal(buf_T *buf)
int ret = vim_dialog_yesnocancel(VIM_QUESTION, NULL, buff, 1);
- return (ret == VIM_YES) ? true : false;
+ return ret == VIM_YES;
}
/// Return true if the buffer "buf" can be abandoned, either by making it
@@ -1505,7 +699,7 @@ bool check_changed_any(bool hidden, bool unload)
int i;
int bufnum = 0;
size_t bufcount = 0;
- int *bufnrs;
+ int *bufnrs;
// Make a list of all buffers, with the most important ones first.
FOR_ALL_BUFFERS(buf) {
@@ -1635,7 +829,7 @@ int check_fname(void)
int buf_write_all(buf_T *buf, int forceit)
{
int retval;
- buf_T *old_curbuf = curbuf;
+ buf_T *old_curbuf = curbuf;
retval = (buf_write(buf, buf->b_ffname, buf->b_fname,
(linenr_T)1, buf->b_ml.ml_line_count, NULL,
@@ -1658,7 +852,7 @@ int buf_write_all(buf_T *buf, int forceit)
/// Return a pointer to the start of the next argument.
static char_u *do_one_arg(char_u *str)
{
- char_u *p;
+ char_u *p;
bool inbacktick;
inbacktick = false;
@@ -1742,8 +936,8 @@ static int do_arglist(char_u *str, int what, int after, bool will_edit)
{
garray_T new_ga;
int exp_count;
- char_u **exp_files;
- char_u *p;
+ char_u **exp_files;
+ char_u *p;
int match;
int arg_escaped = true;
@@ -1843,9 +1037,8 @@ static bool editing_arg_idx(win_T *win)
|| (win->w_buffer->b_fnum
!= WARGLIST(win)[win->w_arg_idx].ae_fnum
&& (win->w_buffer->b_ffname == NULL
- || !(path_full_compare(
- alist_name(&WARGLIST(win)[win->w_arg_idx]),
- win->w_buffer->b_ffname, true, true) & kEqualFiles))));
+ || !(path_full_compare(alist_name(&WARGLIST(win)[win->w_arg_idx]),
+ win->w_buffer->b_ffname, true, true) & kEqualFiles))));
}
/// Check if window "win" is editing the w_arg_idx file in its argument list.
@@ -1908,7 +1101,7 @@ void ex_args(exarg_T *eap)
xfree(items);
}
} else if (eap->cmdidx == CMD_arglocal) {
- garray_T *gap = &curwin->w_alist->al_ga;
+ garray_T *gap = &curwin->w_alist->al_ga;
// ":argslocal": make a local copy of the global argument list.
ga_grow(gap, GARGCOUNT);
@@ -1964,7 +1157,7 @@ void ex_argument(exarg_T *eap)
void do_argfile(exarg_T *eap, int argn)
{
int other;
- char_u *p;
+ char_u *p;
int old_arg_idx = curwin->w_arg_idx;
if (argn < 0 || argn >= ARGCOUNT) {
@@ -2116,9 +1309,9 @@ void ex_argdelete(exarg_T *eap)
curwin->w_arg_idx = (int)eap->line1;
}
if (ARGCOUNT == 0) {
- curwin->w_arg_idx = 0;
+ curwin->w_arg_idx = 0;
} else if (curwin->w_arg_idx >= ARGCOUNT) {
- curwin->w_arg_idx = ARGCOUNT - 1;
+ curwin->w_arg_idx = ARGCOUNT - 1;
}
}
} else {
@@ -2131,11 +1324,11 @@ void ex_argdelete(exarg_T *eap)
void ex_listdo(exarg_T *eap)
{
int i;
- win_T *wp;
- tabpage_T *tp;
+ win_T *wp;
+ tabpage_T *tp;
int next_fnum = 0;
- char_u *save_ei = NULL;
- char_u *p_shm_save;
+ char_u *save_ei = NULL;
+ char_u *p_shm_save;
if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo) {
// Don't do syntax HL autocommands. Skipping the syntax file is a
@@ -2416,9 +1609,9 @@ char_u *get_arglist_name(expand_T *xp FUNC_ATTR_UNUSED, int idx)
/// ":compiler[!] {name}"
void ex_compiler(exarg_T *eap)
{
- char_u *buf;
- char_u *old_cur_comp = NULL;
- char_u *p;
+ char_u *buf;
+ char_u *old_cur_comp = NULL;
+ char_u *p;
if (*eap->arg == NUL) {
// List all compiler scripts.
@@ -2447,10 +1640,10 @@ void ex_compiler(exarg_T *eap)
do_unlet(S_LEN("b:current_compiler"), true);
snprintf((char *)buf, bufsize, "compiler/%s.vim", eap->arg);
- if (source_in_path(p_rtp, buf, DIP_ALL) == FAIL) {
+ if (source_runtime(buf, DIP_ALL) == FAIL) {
// Try lua compiler
snprintf((char *)buf, bufsize, "compiler/%s.lua", eap->arg);
- if (source_in_path(p_rtp, buf, DIP_ALL) == FAIL) {
+ if (source_runtime(buf, DIP_ALL) == FAIL) {
EMSG2(_("E666: compiler not supported: %s"), eap->arg);
}
}
@@ -2509,9 +1702,9 @@ void init_pyxversion(void)
// otherwise return 0.
static int requires_py_version(char_u *filename)
{
- FILE *file;
- int requires_py_version = 0;
- int i, lines;
+ FILE *file;
+ int requires_py_version = 0;
+ int i, lines;
lines = (int)p_mls;
if (lines < 0) {
@@ -2635,44 +1828,42 @@ static void cmd_source(char_u *fname, exarg_T *eap)
}
}
-typedef struct {
- linenr_T curr_lnum;
- const linenr_T final_lnum;
-} GetBufferLineCookie;
-
-/// Get one line from the current selection in the buffer.
-/// Called by do_cmdline() when it's called from cmd_source_buffer().
+/// Concatenate VimL line if it starts with a line continuation into a growarray
+/// (excluding the continuation chars and leading whitespace)
///
-/// @return pointer to allocated line, or NULL for end-of-file or
-/// some error.
-static char_u *get_buffer_line(int c, void *cookie, int indent, bool do_concat)
-{
- GetBufferLineCookie *p = cookie;
- if (p->curr_lnum > p->final_lnum) {
- return NULL;
- }
- char_u *curr_line = ml_get(p->curr_lnum);
- p->curr_lnum++;
- return (char_u *)xstrdup((const char *)curr_line);
-}
-
-static void cmd_source_buffer(const exarg_T *eap)
+/// @note Growsize of the growarray may be changed to speed up concatenations!
+///
+/// @param ga the growarray to append to
+/// @param init_growsize the starting growsize value of the growarray
+/// @param p pointer to the beginning of the line to consider
+/// @param len the length of this line
+///
+/// @return true if this line did begin with a continuation (the next line
+/// should also be considered, if it exists); false otherwise
+static bool concat_continued_line(garray_T *const ga, const int init_growsize,
+ const char_u *const p, size_t len)
FUNC_ATTR_NONNULL_ALL
{
- GetBufferLineCookie cookie = {
- .curr_lnum = eap->line1,
- .final_lnum = eap->line2,
- };
- if (curbuf != NULL && curbuf->b_fname
- && path_with_extension((const char *)curbuf->b_fname, "lua")) {
- nlua_source_using_linegetter(get_buffer_line, (void *)&cookie,
- ":source (no file)");
- } else {
- source_using_linegetter((void *)&cookie, get_buffer_line,
- ":source (no file)");
+ const char_u *const line = skipwhite_len(p, len);
+ len -= (size_t)(line - p);
+ // Skip lines starting with '\" ', concat lines starting with '\'
+ if (len >= 3 && STRNCMP(line, "\"\\ ", 3) == 0) {
+ return true;
+ } else if (len == 0 || line[0] != '\\') {
+ return false;
+ }
+ if (ga->ga_len > init_growsize) {
+ ga_set_growsize(ga, MAX(ga->ga_len, 8000));
}
+ ga_concat_len(ga, (const char *)line + 1, len - 1);
+ return true;
}
+typedef struct {
+ linenr_T curr_lnum;
+ const linenr_T final_lnum;
+} GetBufferLineCookie;
+
/// ":source" and associated commands.
///
/// @return address holding the next breakpoint line for a source cookie
@@ -2725,22 +1916,30 @@ typedef struct {
static char_u *get_str_line(int c, void *cookie, int indent, bool do_concat)
{
GetStrLineCookie *p = cookie;
- size_t i = p->offset;
- if (strlen((char *)p->buf) <= p->offset) {
+ if (STRLEN(p->buf) <= p->offset) {
return NULL;
}
- while (!(p->buf[i] == '\n' || p->buf[i] == '\0')) {
- i++;
+ const char_u *line = p->buf + p->offset;
+ const char_u *eol = skip_to_newline(line);
+ garray_T ga;
+ ga_init(&ga, sizeof(char_u), 400);
+ ga_concat_len(&ga, (const char *)line, (size_t)(eol - line));
+ if (do_concat && vim_strchr(p_cpo, CPO_CONCAT) == NULL) {
+ while (eol[0] != NUL) {
+ line = eol + 1;
+ const char_u *const next_eol = skip_to_newline(line);
+ if (!concat_continued_line(&ga, 400, line, (size_t)(next_eol - line))) {
+ break;
+ }
+ eol = next_eol;
+ }
}
- size_t line_length = i - p->offset;
- char_u *buf = xmemdupz(p->buf + p->offset, line_length);
- p->offset = i + 1;
- return buf;
+ ga_append(&ga, NUL);
+ p->offset = (size_t)(eol - p->buf) + 1;
+ return ga.ga_data;
}
-static int source_using_linegetter(void *cookie,
- LineGetter fgetline,
- const char *traceback_name)
+static int source_using_linegetter(void *cookie, LineGetter fgetline, const char *traceback_name)
{
char_u *save_sourcing_name = sourcing_name;
linenr_T save_sourcing_lnum = sourcing_lnum;
@@ -2749,9 +1948,9 @@ static int source_using_linegetter(void *cookie,
sourcing_name = (char_u *)traceback_name;
} else {
snprintf((char *)sourcing_name_buf, sizeof(sourcing_name_buf),
- "%s called at %s:%"PRIdLINENR, traceback_name, save_sourcing_name,
+ "%s called at %s:%" PRIdLINENR, traceback_name, save_sourcing_name,
save_sourcing_lnum);
- sourcing_name = sourcing_name_buf;
+ sourcing_name = sourcing_name_buf; // -V507 reassigned below, before return.
}
sourcing_lnum = 0;
@@ -2770,14 +1969,48 @@ static int source_using_linegetter(void *cookie,
return retval;
}
+static void cmd_source_buffer(const exarg_T *const eap)
+ FUNC_ATTR_NONNULL_ALL
+{
+ if (curbuf == NULL) {
+ return;
+ }
+ garray_T ga;
+ ga_init(&ga, sizeof(char_u), 400);
+ const linenr_T final_lnum = eap->line2;
+ // Copy the contents to be executed.
+ for (linenr_T curr_lnum = eap->line1; curr_lnum <= final_lnum; curr_lnum++) {
+ // Adjust growsize to current length to speed up concatenating many lines.
+ if (ga.ga_len > 400) {
+ ga_set_growsize(&ga, MAX(ga.ga_len, 8000));
+ }
+ ga_concat(&ga, ml_get(curr_lnum));
+ ga_append(&ga, NL);
+ }
+ ((char_u *)ga.ga_data)[ga.ga_len - 1] = NUL;
+ const GetStrLineCookie cookie = {
+ .buf = ga.ga_data,
+ .offset = 0,
+ };
+ if (curbuf->b_fname
+ && path_with_extension((const char *)curbuf->b_fname, "lua")) {
+ nlua_source_using_linegetter(get_str_line, (void *)&cookie,
+ ":source (no file)");
+ } else {
+ source_using_linegetter((void *)&cookie, get_str_line,
+ ":source (no file)");
+ }
+ ga_clear(&ga);
+}
+
/// Executes lines in `src` as Ex commands.
///
/// @see do_source()
int do_source_str(const char *cmd, const char *traceback_name)
{
GetStrLineCookie cookie = {
- .buf = (char_u *)cmd,
- .offset = 0,
+ .buf = (char_u *)cmd,
+ .offset = 0,
};
return source_using_linegetter((void *)&cookie, get_str_line, traceback_name);
}
@@ -2797,16 +2030,16 @@ int do_source_str(const char *cmd, const char *traceback_name)
int do_source(char_u *fname, int check_other, int is_vimrc)
{
struct source_cookie cookie;
- char_u *save_sourcing_name;
+ char_u *save_sourcing_name;
linenr_T save_sourcing_lnum;
- char_u *p;
- char_u *fname_exp;
- char_u *firstline = NULL;
+ char_u *p;
+ char_u *fname_exp;
+ char_u *firstline = NULL;
int retval = FAIL;
static scid_T last_current_SID = 0;
static int last_current_SID_seq = 0;
int save_debug_break_level = debug_break_level;
- scriptitem_T *si = NULL;
+ scriptitem_T *si = NULL;
proftime_T wait_start;
bool trigger_source_post = false;
@@ -2879,7 +2112,7 @@ int do_source(char_u *fname, int check_other, int is_vimrc)
verbose_leave();
}
if (is_vimrc == DOSO_VIMRC) {
- vimrc_found(fname_exp, (char_u *)"MYVIMRC");
+ vimrc_found((char *)fname_exp, "MYVIMRC");
}
#ifdef USE_CRNL
@@ -3107,7 +2340,7 @@ void ex_scriptnames(exarg_T *eap)
}
}
-# if defined(BACKSLASH_IN_FILENAME)
+#if defined(BACKSLASH_IN_FILENAME)
/// Fix slashes in the list of script names for 'shellslash'.
void scriptnames_slash_adjust(void)
{
@@ -3118,7 +2351,7 @@ void scriptnames_slash_adjust(void)
}
}
-# endif
+#endif
/// Get a pointer to a script name. Used for ":verbose set".
/// Message appended to "Last set from "
@@ -3127,35 +2360,35 @@ char_u *get_scriptname(LastSet last_set, bool *should_free)
*should_free = false;
switch (last_set.script_ctx.sc_sid) {
- case SID_MODELINE:
- return (char_u *)_("modeline");
- case SID_CMDARG:
- return (char_u *)_("--cmd argument");
- case SID_CARG:
- return (char_u *)_("-c argument");
- case SID_ENV:
- return (char_u *)_("environment variable");
- case SID_ERROR:
- return (char_u *)_("error handler");
- case SID_WINLAYOUT:
- return (char_u *)_("changed window size");
- case SID_LUA:
- return (char_u *)_("Lua");
- case SID_API_CLIENT:
- vim_snprintf((char *)IObuff, IOSIZE,
- _("API client (channel id %" PRIu64 ")"),
- last_set.channel_id);
- return IObuff;
- case SID_STR:
- return (char_u *)_("anonymous :source");
- default:
- *should_free = true;
- return home_replace_save(NULL,
- SCRIPT_ITEM(last_set.script_ctx.sc_sid).sn_name);
+ case SID_MODELINE:
+ return (char_u *)_("modeline");
+ case SID_CMDARG:
+ return (char_u *)_("--cmd argument");
+ case SID_CARG:
+ return (char_u *)_("-c argument");
+ case SID_ENV:
+ return (char_u *)_("environment variable");
+ case SID_ERROR:
+ return (char_u *)_("error handler");
+ case SID_WINLAYOUT:
+ return (char_u *)_("changed window size");
+ case SID_LUA:
+ return (char_u *)_("Lua");
+ case SID_API_CLIENT:
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("API client (channel id %" PRIu64 ")"),
+ last_set.channel_id);
+ return IObuff;
+ case SID_STR:
+ return (char_u *)_("anonymous :source");
+ default:
+ *should_free = true;
+ return home_replace_save(NULL,
+ SCRIPT_ITEM(last_set.script_ctx.sc_sid).sn_name);
}
}
-# if defined(EXITFREE)
+#if defined(EXITFREE)
void free_scriptnames(void)
{
profile_reset();
@@ -3163,11 +2396,11 @@ void free_scriptnames(void)
# define FREE_SCRIPTNAME(item) xfree((item)->sn_name)
GA_DEEP_CLEAR(&script_items, scriptitem_T, FREE_SCRIPTNAME);
}
-# endif
+#endif
linenr_T get_sourced_lnum(LineGetter fgetline, void *cookie)
{
- return fgetline == getsourceline
+ return fgetline == getsourceline
? ((struct source_cookie *)cookie)->sourcing_lnum
: sourcing_lnum;
}
@@ -3227,26 +2460,11 @@ char_u *getsourceline(int c, void *cookie, int indent, bool do_concat)
ga_init(&ga, (int)sizeof(char_u), 400);
ga_concat(&ga, line);
- if (*p == '\\') {
- ga_concat(&ga, p + 1);
- }
- for (;; ) {
+ while (sp->nextline != NULL
+ && concat_continued_line(&ga, 400, sp->nextline,
+ STRLEN(sp->nextline))) {
xfree(sp->nextline);
sp->nextline = get_one_sourceline(sp);
- if (sp->nextline == NULL) {
- break;
- }
- p = skipwhite(sp->nextline);
- if (*p == '\\') {
- // Adjust the growsize to the current length to speed up
- // concatenating many lines.
- if (ga.ga_len > 400) {
- ga_set_growsize(&ga, (ga.ga_len > 8000) ? 8000 : ga.ga_len);
- }
- ga_concat(&ga, p + 1);
- } else if (p[0] != '"' || p[1] != '\\' || p[2] != ' ') {
- break;
- }
}
ga_append(&ga, NUL);
xfree(line);
@@ -3255,7 +2473,7 @@ char_u *getsourceline(int c, void *cookie, int indent, bool do_concat)
}
if (line != NULL && sp->conv.vc_type != CONV_NONE) {
- char_u *s;
+ char_u *s;
// Convert the encoding of the script line.
s = string_convert(&sp->conv, line, NULL);
@@ -3281,7 +2499,7 @@ static char_u *get_one_sourceline(struct source_cookie *sp)
garray_T ga;
int len;
int c;
- char_u *buf;
+ char_u *buf;
#ifdef USE_CRNL
int has_cr; // CR-LF found
#endif
@@ -3384,8 +2602,8 @@ retry:
/// until later and we need to store the time now.
void script_line_start(void)
{
- scriptitem_T *si;
- sn_prl_T *pp;
+ scriptitem_T *si;
+ sn_prl_T *pp;
if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len) {
return;
@@ -3416,7 +2634,7 @@ void script_line_start(void)
/// Called when actually executing a function line.
void script_line_exec(void)
{
- scriptitem_T *si;
+ scriptitem_T *si;
if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len) {
return;
@@ -3430,8 +2648,8 @@ void script_line_exec(void)
/// Called when done with a function line.
void script_line_end(void)
{
- scriptitem_T *si;
- sn_prl_T *pp;
+ scriptitem_T *si;
+ sn_prl_T *pp;
if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len) {
return;
@@ -3456,8 +2674,8 @@ void script_line_end(void)
/// Without the multi-byte feature it's simply ignored.
void ex_scriptencoding(exarg_T *eap)
{
- struct source_cookie *sp;
- char_u *name;
+ struct source_cookie *sp;
+ char_u *name;
if (!getline_equal(eap->getline, eap->cookie, getsourceline)) {
EMSG(_("E167: :scriptencoding used outside of a sourced file"));
@@ -3501,7 +2719,7 @@ void do_finish(exarg_T *eap, int reanimate)
eap->cookie))->finished = false;
}
- // Cleanup (and inactivate) conditionals, but stop when a try conditional
+ // Cleanup (and deactivate) conditionals, but stop when a try conditional
// not in its finally clause (which then is to be executed next) is found.
// In this case, make the ":finish" pending for execution at the ":endtry".
// Otherwise, finish normally.
@@ -3522,14 +2740,13 @@ void do_finish(exarg_T *eap, int reanimate)
bool source_finished(LineGetter fgetline, void *cookie)
{
return getline_equal(fgetline, cookie, getsourceline)
- && ((struct source_cookie *)getline_cookie(
- fgetline, cookie))->finished;
+ && ((struct source_cookie *)getline_cookie(fgetline, cookie))->finished;
}
/// ":checktime [buffer]"
void ex_checktime(exarg_T *eap)
{
- buf_T *buf;
+ buf_T *buf;
int save_no_check_timestamps = no_check_timestamps;
no_check_timestamps = 0;
@@ -3569,17 +2786,17 @@ char *get_mess_lang(void)
{
char *p;
-# ifdef HAVE_GET_LOCALE_VAL
-# if defined(LC_MESSAGES)
+#ifdef HAVE_GET_LOCALE_VAL
+# if defined(LC_MESSAGES)
p = get_locale_val(LC_MESSAGES);
-# else
+# else
// This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
// may be set to the LCID number. LC_COLLATE is the best guess, LC_TIME
// and LC_MONETARY may be set differently for a Japanese working in the
// US.
p = get_locale_val(LC_COLLATE);
-# endif
-# else
+# endif
+#else
p = os_getenv("LC_ALL");
if (!is_valid_mess_lang(p)) {
p = os_getenv("LC_MESSAGES");
@@ -3587,7 +2804,7 @@ char *get_mess_lang(void)
p = os_getenv("LANG");
}
}
-# endif
+#endif
return is_valid_mess_lang(p) ? p : NULL;
}
@@ -3596,7 +2813,7 @@ char *get_mess_lang(void)
/// Get the language used for messages from the environment.
static char_u *get_mess_env(void)
{
- char_u *p;
+ char_u *p;
p = (char_u *)os_getenv("LC_ALL");
if (p == NULL) {
@@ -3625,37 +2842,37 @@ void set_lang_var(void)
{
const char *loc;
-# ifdef HAVE_GET_LOCALE_VAL
+#ifdef HAVE_GET_LOCALE_VAL
loc = get_locale_val(LC_CTYPE);
-# else
+#else
// setlocale() not supported: use the default value
loc = "C";
-# endif
+#endif
set_vim_var_string(VV_CTYPE, loc, -1);
// When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
// back to LC_CTYPE if it's empty.
-# ifdef HAVE_WORKING_LIBINTL
+#ifdef HAVE_WORKING_LIBINTL
loc = (char *)get_mess_env();
-# elif defined(LC_MESSAGES)
+#elif defined(LC_MESSAGES)
loc = get_locale_val(LC_MESSAGES);
-# else
+#else
// In Windows LC_MESSAGES is not defined fallback to LC_CTYPE
loc = get_locale_val(LC_CTYPE);
-# endif
+#endif
set_vim_var_string(VV_LANG, loc, -1);
-# ifdef HAVE_GET_LOCALE_VAL
+#ifdef HAVE_GET_LOCALE_VAL
loc = get_locale_val(LC_TIME);
-# endif
+#endif
set_vim_var_string(VV_LC_TIME, loc, -1);
-# ifdef HAVE_GET_LOCALE_VAL
+#ifdef HAVE_GET_LOCALE_VAL
loc = get_locale_val(LC_COLLATE);
-# else
+#else
// setlocale() not supported: use the default value
loc = "C";
-# endif
+#endif
set_vim_var_string(VV_COLLATE, loc, -1);
}
@@ -3667,16 +2884,16 @@ void set_lang_var(void)
///
void ex_language(exarg_T *eap)
{
- char *loc;
- char_u *p;
- char_u *name;
+ char *loc;
+ char_u *p;
+ char_u *name;
int what = LC_ALL;
- char *whatstr = "";
-#ifdef LC_MESSAGES
-# define VIM_LC_MESSAGES LC_MESSAGES
-#else
-# define VIM_LC_MESSAGES 6789
-#endif
+ char *whatstr = "";
+# ifdef LC_MESSAGES
+# define VIM_LC_MESSAGES LC_MESSAGES
+# else
+# define VIM_LC_MESSAGES 6789
+# endif
name = eap->arg;
@@ -3705,43 +2922,43 @@ void ex_language(exarg_T *eap)
}
if (*name == NUL) {
-#ifdef HAVE_WORKING_LIBINTL
+# ifdef HAVE_WORKING_LIBINTL
if (what == VIM_LC_MESSAGES) {
p = get_mess_env();
} else {
-#endif
- p = (char_u *)setlocale(what, NULL);
-#ifdef HAVE_WORKING_LIBINTL
- }
-#endif
+# endif
+ p = (char_u *)setlocale(what, NULL);
+# ifdef HAVE_WORKING_LIBINTL
+ }
+# endif
if (p == NULL || *p == NUL) {
p = (char_u *)"Unknown";
}
smsg(_("Current %slanguage: \"%s\""), whatstr, p);
} else {
-#ifndef LC_MESSAGES
+# ifndef LC_MESSAGES
if (what == VIM_LC_MESSAGES) {
loc = "";
} else {
-#endif
- loc = setlocale(what, (char *)name);
-#ifdef LC_NUMERIC
- // Make sure strtod() uses a decimal point, not a comma.
- setlocale(LC_NUMERIC, "C");
-#endif
-#ifndef LC_MESSAGES
- }
-#endif
+# endif
+ loc = setlocale(what, (char *)name);
+# ifdef LC_NUMERIC
+ // Make sure strtod() uses a decimal point, not a comma.
+ setlocale(LC_NUMERIC, "C");
+# endif
+# ifndef LC_MESSAGES
+ }
+# endif
if (loc == NULL) {
EMSG2(_("E197: Cannot set language to \"%s\""), name);
} else {
-#ifdef HAVE_NL_MSG_CAT_CNTR
+# ifdef HAVE_NL_MSG_CAT_CNTR
// Need to do this for GNU gettext, otherwise cached translations
// will be used again.
extern int _nl_msg_cat_cntr;
_nl_msg_cat_cntr++;
-#endif
+# endif
// Reset $LC_ALL, otherwise it would overrule everything.
os_setenv("LC_ALL", "", 1);
@@ -3770,7 +2987,7 @@ void ex_language(exarg_T *eap)
static char_u **locales = NULL; // Array of all available locales
-#ifndef WIN32
+# ifndef WIN32
static bool did_init_locales = false;
/// Return an array of strings for all available locales + NULL for the
@@ -3778,7 +2995,7 @@ static bool did_init_locales = false;
static char_u **find_locales(void)
{
garray_T locales_ga;
- char_u *loc;
+ char_u *loc;
char *saveptr = NULL;
// Find all available locales by running command "locale -a". If this
@@ -3805,20 +3022,20 @@ static char_u **find_locales(void)
((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
return (char_u **)locales_ga.ga_data;
}
-#endif
+# endif
/// Lazy initialization of all available locales.
static void init_locales(void)
{
-#ifndef WIN32
+# ifndef WIN32
if (!did_init_locales) {
did_init_locales = true;
locales = find_locales();
}
-#endif
+# endif
}
-# if defined(EXITFREE)
+# if defined(EXITFREE)
void free_locales(void)
{
int i;
@@ -3830,7 +3047,7 @@ void free_locales(void)
}
}
-# endif
+# endif
/// Function given to ExpandGeneric() to obtain the possible arguments of the
/// ":language" command.
@@ -3916,7 +3133,7 @@ static void script_host_do_range(char *name, exarg_T *eap)
/// ":drop"
/// Opens the first argument in a window. When there are two or more arguments
/// the argument list is redefined.
-void ex_drop(exarg_T *eap)
+void ex_drop(exarg_T *eap)
{
bool split = false;
buf_T *buf;
diff --git a/src/nvim/ex_cmds_defs.h b/src/nvim/ex_cmds_defs.h
index f928c61ea4..d64b14c9c5 100644
--- a/src/nvim/ex_cmds_defs.h
+++ b/src/nvim/ex_cmds_defs.h
@@ -58,7 +58,7 @@
#define EX_SBOXOK 0x40000 // allowed in the sandbox
#define EX_CMDWIN 0x80000 // allowed in cmdline window; when missing
// disallows editing another buffer when
- // curbuf_lock is set
+ // current buffer is locked
#define EX_MODIFY 0x100000 // forbidden in non-'modifiable' buffer
#define EX_FLAGS 0x200000 // allow flags after count in argument
#define EX_FILES (EX_XFILE | EX_EXTRA) // multiple extra files allowed
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 27c98a13a6..dff3b4223b 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -4,33 +4,43 @@
// ex_docmd.c: functions for executing an Ex command line.
#include <assert.h>
-#include <string.h>
+#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
-#include <inttypes.h>
+#include <string.h>
-#include "nvim/vim.h"
+#include "nvim/api/private/helpers.h"
#include "nvim/ascii.h"
-#include "nvim/ex_docmd.h"
#include "nvim/buffer.h"
#include "nvim/change.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
+#include "nvim/debugger.h"
#include "nvim/diff.h"
#include "nvim/digraph.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
#include "nvim/eval/userfunc.h"
+#include "nvim/event/rstream.h"
+#include "nvim/event/wstream.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds2.h"
+#include "nvim/ex_cmds_defs.h"
+#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
#include "nvim/ex_getln.h"
+#include "nvim/ex_session.h"
+#include "nvim/file_search.h"
#include "nvim/fileio.h"
#include "nvim/fold.h"
#include "nvim/func_attr.h"
+#include "nvim/garray.h"
#include "nvim/getchar.h"
+#include "nvim/globals.h"
#include "nvim/hardcopy.h"
#include "nvim/if_cscope.h"
+#include "nvim/keymap.h"
+#include "nvim/lua/executor.h"
#include "nvim/main.h"
#include "nvim/mark.h"
#include "nvim/mbyte.h"
@@ -39,20 +49,21 @@
#include "nvim/menu.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
-#include "nvim/ex_session.h"
-#include "nvim/keymap.h"
-#include "nvim/file_search.h"
-#include "nvim/garray.h"
+#include "nvim/mouse.h"
#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/ops.h"
#include "nvim/option.h"
+#include "nvim/os/input.h"
+#include "nvim/os/os.h"
+#include "nvim/os/time.h"
#include "nvim/os_unix.h"
#include "nvim/path.h"
#include "nvim/quickfix.h"
#include "nvim/regexp.h"
#include "nvim/screen.h"
#include "nvim/search.h"
+#include "nvim/shada.h"
#include "nvim/sign.h"
#include "nvim/spell.h"
#include "nvim/spellfile.h"
@@ -63,47 +74,37 @@
#include "nvim/ui.h"
#include "nvim/undo.h"
#include "nvim/version.h"
+#include "nvim/vim.h"
#include "nvim/window.h"
-#include "nvim/os/os.h"
-#include "nvim/os/input.h"
-#include "nvim/os/time.h"
-#include "nvim/ex_cmds_defs.h"
-#include "nvim/mouse.h"
-#include "nvim/event/rstream.h"
-#include "nvim/event/wstream.h"
-#include "nvim/shada.h"
-#include "nvim/lua/executor.h"
-#include "nvim/globals.h"
-#include "nvim/api/private/helpers.h"
static int quitmore = 0;
static bool ex_pressedreturn = false;
typedef struct ucmd {
- char_u *uc_name; // The command name
+ char_u *uc_name; // The command name
uint32_t uc_argt; // The argument type
- char_u *uc_rep; // The command's replacement string
+ char_u *uc_rep; // The command's replacement string
long uc_def; // The default value for a range/count
int uc_compl; // completion type
cmd_addr_T uc_addr_type; // The command's address type
sctx_T uc_script_ctx; // SCTX where the command was defined
- char_u *uc_compl_arg; // completion argument if any
+ char_u *uc_compl_arg; // completion argument if any
} ucmd_T;
-#define UC_BUFFER 1 /* -buffer: local to current buffer */
+#define UC_BUFFER 1 // -buffer: local to current buffer
-static garray_T ucmds = {0, 0, sizeof(ucmd_T), 4, NULL};
+static garray_T ucmds = { 0, 0, sizeof(ucmd_T), 4, NULL };
#define USER_CMD(i) (&((ucmd_T *)(ucmds.ga_data))[i])
#define USER_CMD_GA(gap, i) (&((ucmd_T *)((gap)->ga_data))[i])
-/* Wether a command index indicates a user command. */
-# define IS_USER_CMDIDX(idx) ((int)(idx) < 0)
+// Whether a command index indicates a user command.
+#define IS_USER_CMDIDX(idx) ((int)(idx) < 0)
-/* Struct for storing a line inside a while/for loop */
+// Struct for storing a line inside a while/for loop
typedef struct {
- char_u *line; /* command line */
- linenr_T lnum; /* sourcing_lnum of the line */
+ char_u *line; // command line
+ linenr_T lnum; // sourcing_lnum of the line
} wcmd_T;
#define FREE_WCMD(wcmd) xfree((wcmd)->line)
@@ -114,27 +115,27 @@ typedef struct {
* reads more lines that may come from the while/for loop.
*/
struct loop_cookie {
- garray_T *lines_gap; // growarray with line info
+ garray_T *lines_gap; // growarray with line info
int current_line; // last read line from growarray
int repeating; // TRUE when looping a second time
// When "repeating" is FALSE use "getline" and "cookie" to get lines
- char_u *(*getline)(int, void *, int, bool);
- void *cookie;
+ char_u *(*getline)(int, void *, int, bool);
+ void *cookie;
};
-/* Struct to save a few things while debugging. Used in do_cmdline() only. */
+// Struct to save a few things while debugging. Used in do_cmdline() only.
struct dbg_stuff {
int trylevel;
int force_abort;
- except_T *caught_stack;
- char_u *vv_exception;
- char_u *vv_throwpoint;
+ except_T *caught_stack;
+ char_u *vv_exception;
+ char_u *vv_throwpoint;
int did_emsg;
int got_int;
int need_rethrow;
int check_cstack;
- except_T *current_exception;
+ except_T *current_exception;
};
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -152,7 +153,7 @@ struct dbg_stuff {
# include "ex_cmds_defs.generated.h"
#endif
-static char_u dollar_command[2] = {'$', 0};
+static char_u dollar_command[2] = { '$', 0 };
static void save_dbg_stuff(struct dbg_stuff *dsp)
{
@@ -186,23 +187,21 @@ static void restore_dbg_stuff(struct dbg_stuff *dsp)
}
/// Repeatedly get commands for Ex mode, until the ":vi" command is given.
-void do_exmode(int improved)
+void do_exmode(void)
{
int save_msg_scroll;
int prev_msg_row;
linenr_T prev_line;
int changedtick;
- if (improved)
- exmode_active = EXMODE_VIM;
- else
- exmode_active = EXMODE_NORMAL;
+ exmode_active = true;
State = NORMAL;
/* When using ":global /pat/ visual" and then "Q" we return to continue
* the :global command. */
- if (global_busy)
+ if (global_busy) {
return;
+ }
save_msg_scroll = msg_scroll;
RedrawingDisabled++; // don't redisplay the window
@@ -210,9 +209,9 @@ void do_exmode(int improved)
MSG(_("Entering Ex mode. Type \"visual\" to go to Normal mode."));
while (exmode_active) {
- /* Check for a ":normal" command and no more characters left. */
+ // Check for a ":normal" command and no more characters left.
if (ex_normal_busy > 0 && typebuf.tb_len == 0) {
- exmode_active = 0;
+ exmode_active = false;
break;
}
msg_scroll = true;
@@ -235,18 +234,20 @@ void do_exmode(int improved)
/* go up one line, to overwrite the ":<CR>" line, so the
* output doesn't contain empty lines. */
msg_row = prev_msg_row;
- if (prev_msg_row == Rows - 1)
+ if (prev_msg_row == Rows - 1) {
msg_row--;
+ }
}
msg_col = 0;
print_line_no_prefix(curwin->w_cursor.lnum, FALSE, FALSE);
msg_clr_eos();
}
- } else if (ex_pressedreturn && !ex_no_reprint) { /* must be at EOF */
- if (curbuf->b_ml.ml_flags & ML_EMPTY)
+ } else if (ex_pressedreturn && !ex_no_reprint) { // must be at EOF
+ if (curbuf->b_ml.ml_flags & ML_EMPTY) {
EMSG(_(e_emptybuf));
- else
+ } else {
EMSG(_("E501: At end-of-file"));
+ }
}
}
@@ -303,40 +304,41 @@ int do_cmdline_cmd(const char *cmd)
/// DOCMD_KEYTYPED - Don't reset KeyTyped.
/// DOCMD_EXCRESET - Reset the exception environment (used for debugging).
/// DOCMD_KEEPLINE - Store first typed line (for repeating with ".").
+/// DOCMD_PREVIEW - During 'inccommand' preview.
+///
+/// @param cookie argument for fgetline()
///
/// @return FAIL if cmdline could not be executed, OK otherwise
-int do_cmdline(char_u *cmdline, LineGetter fgetline,
- void *cookie, /* argument for fgetline() */
- int flags)
-{
- char_u *next_cmdline; /* next cmd to execute */
- char_u *cmdline_copy = NULL; /* copy of cmd line */
- int used_getline = FALSE; /* used "fgetline" to obtain command */
- static int recursive = 0; /* recursive depth */
- int msg_didout_before_start = 0;
- int count = 0; /* line number count */
- int did_inc = FALSE; /* incremented RedrawingDisabled */
+int do_cmdline(char_u *cmdline, LineGetter fgetline, void *cookie, int flags)
+{
+ char_u *next_cmdline; // next cmd to execute
+ char_u *cmdline_copy = NULL; // copy of cmd line
+ bool used_getline = false; // used "fgetline" to obtain command
+ static int recursive = 0; // recursive depth
+ bool msg_didout_before_start = false;
+ int count = 0; // line number count
+ int did_inc = FALSE; // incremented RedrawingDisabled
int retval = OK;
cstack_T cstack = { // conditional stack
.cs_idx = -1,
};
garray_T lines_ga; // keep lines for ":while"/":for"
int current_line = 0; // active line in lines_ga
- char_u *fname = NULL; // function or script name
+ char_u *fname = NULL; // function or script name
linenr_T *breakpoint = NULL; // ptr to breakpoint field in cookie
- int *dbg_tick = NULL; // ptr to dbg_tick field in cookie
+ int *dbg_tick = NULL; // ptr to dbg_tick field in cookie
struct dbg_stuff debug_saved; // saved things for debug mode
int initial_trylevel;
- struct msglist **saved_msg_list = NULL;
- struct msglist *private_msg_list;
+ struct msglist **saved_msg_list = NULL;
+ struct msglist *private_msg_list;
// "fgetline" and "cookie" passed to do_one_cmd()
- char_u *(*cmd_getline)(int, void *, int, bool);
- void *cmd_cookie;
+ char_u *(*cmd_getline)(int, void *, int, bool);
+ void *cmd_cookie;
struct loop_cookie cmd_loop_cookie;
- void *real_cookie;
+ void *real_cookie;
int getline_is_func;
- static int call_depth = 0; /* recursiveness */
+ static int call_depth = 0; // recursiveness
/* For every pair of do_cmdline()/do_one_cmd() calls, use an extra memory
* location for storing error messages to be converted to an exception.
@@ -366,10 +368,11 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
real_cookie = getline_cookie(fgetline, cookie);
- /* Inside a function use a higher nesting level. */
+ // Inside a function use a higher nesting level.
getline_is_func = getline_equal(fgetline, cookie, get_func_line);
- if (getline_is_func && ex_nesting_level == func_level(real_cookie))
+ if (getline_is_func && ex_nesting_level == func_level(real_cookie)) {
++ex_nesting_level;
+ }
/* Get the function or script name and the address where the next breakpoint
* line and the debug tick for a function or script are stored. */
@@ -425,13 +428,14 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
do {
getline_is_func = getline_equal(fgetline, cookie, get_func_line);
- /* stop skipping cmds for an error msg after all endif/while/for */
+ // stop skipping cmds for an error msg after all endif/while/for
if (next_cmdline == NULL
&& !force_abort
&& cstack.cs_idx < 0
- && !(getline_is_func && func_has_abort(real_cookie))
- )
+ && !(getline_is_func &&
+ func_has_abort(real_cookie))) {
did_emsg = FALSE;
+ }
/*
* 1. If repeating a line in a loop, get a line from lines_ga.
@@ -439,7 +443,7 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
* 3. If a line is given: Make a copy, so we can mess with it.
*/
- /* 1. If repeating, get a previous line from lines_ga. */
+ // 1. If repeating, get a previous line from lines_ga.
if (cstack.cs_looplevel > 0 && current_line < lines_ga.ga_len) {
/* Each '|' separated command is stored separately in lines_ga, to
* be able to jump to it. Don't use next_cmdline now. */
@@ -448,49 +452,50 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
/* Check if a function has returned or, unless it has an unclosed
* try conditional, aborted. */
if (getline_is_func) {
- if (do_profiling == PROF_YES)
+ if (do_profiling == PROF_YES) {
func_line_end(real_cookie);
+ }
if (func_has_ended(real_cookie)) {
retval = FAIL;
break;
}
} else if (do_profiling == PROF_YES
- && getline_equal(fgetline, cookie, getsourceline))
+ && getline_equal(fgetline, cookie, getsourceline)) {
script_line_end();
+ }
- /* Check if a sourced file hit a ":finish" command. */
+ // Check if a sourced file hit a ":finish" command.
if (source_finished(fgetline, cookie)) {
retval = FAIL;
break;
}
- /* If breakpoints have been added/deleted need to check for it. */
+ // If breakpoints have been added/deleted need to check for it.
if (breakpoint != NULL && dbg_tick != NULL
&& *dbg_tick != debug_tick) {
- *breakpoint = dbg_find_breakpoint(
- getline_equal(fgetline, cookie, getsourceline),
- fname, sourcing_lnum);
+ *breakpoint = dbg_find_breakpoint(getline_equal(fgetline, cookie, getsourceline),
+ fname, sourcing_lnum);
*dbg_tick = debug_tick;
}
next_cmdline = ((wcmd_T *)(lines_ga.ga_data))[current_line].line;
sourcing_lnum = ((wcmd_T *)(lines_ga.ga_data))[current_line].lnum;
- /* Did we encounter a breakpoint? */
+ // Did we encounter a breakpoint?
if (breakpoint != NULL && *breakpoint != 0
&& *breakpoint <= sourcing_lnum) {
dbg_breakpoint(fname, sourcing_lnum);
- /* Find next breakpoint. */
- *breakpoint = dbg_find_breakpoint(
- getline_equal(fgetline, cookie, getsourceline),
- fname, sourcing_lnum);
+ // Find next breakpoint.
+ *breakpoint = dbg_find_breakpoint(getline_equal(fgetline, cookie, getsourceline),
+ fname, sourcing_lnum);
*dbg_tick = debug_tick;
}
if (do_profiling == PROF_YES) {
- if (getline_is_func)
+ if (getline_is_func) {
func_line_start(real_cookie);
- else if (getline_equal(fgetline, cookie, getsourceline))
+ } else if (getline_equal(fgetline, cookie, getsourceline)) {
script_line_start();
+ }
}
}
@@ -512,7 +517,7 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
cmd_cookie = cookie;
}
- /* 2. If no line given, get an allocated line with fgetline(). */
+ // 2. If no line given, get an allocated line with fgetline().
if (next_cmdline == NULL) {
/*
* Need to set msg_didout for the first line after an ":if",
@@ -535,20 +540,21 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
retval = FAIL;
break;
}
- used_getline = TRUE;
+ used_getline = true;
/*
* Keep the first typed line. Clear it when more lines are typed.
*/
if (flags & DOCMD_KEEPLINE) {
xfree(repeat_cmdline);
- if (count == 0)
+ if (count == 0) {
repeat_cmdline = vim_strsave(next_cmdline);
- else
+ } else {
repeat_cmdline = NULL;
+ }
}
}
- /* 3. Make a copy of the command so we can mess with it. */
+ // 3. Make a copy of the command so we can mess with it.
else if (cmdline_copy == NULL) {
next_cmdline = vim_strsave(next_cmdline);
}
@@ -565,7 +571,7 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
&& (cstack.cs_looplevel || has_loop_cmd(next_cmdline))) {
store_loop_line(&lines_ga, next_cmdline);
}
- did_endif = FALSE;
+ did_endif = false;
if (count++ == 0) {
/*
@@ -576,10 +582,10 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
*/
if (!(flags & DOCMD_NOWAIT) && !recursive) {
msg_didout_before_start = msg_didout;
- msg_didany = FALSE; /* no output yet */
+ msg_didany = false; // no output yet
msg_start();
- msg_scroll = TRUE; /* put messages below each other */
- ++no_wait_return; /* don't wait for return until finished */
+ msg_scroll = TRUE; // put messages below each other
+ ++no_wait_return; // don't wait for return until finished
++RedrawingDisabled;
did_inc = TRUE;
}
@@ -601,14 +607,15 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
recursive--;
// Ignore trailing '|'-separated commands in preview-mode ('inccommand').
- if (State & CMDPREVIEW) {
+ if ((State & CMDPREVIEW) && (flags & DOCMD_PREVIEW)) {
next_cmdline = NULL;
}
- if (cmd_cookie == (void *)&cmd_loop_cookie)
+ if (cmd_cookie == (void *)&cmd_loop_cookie) {
/* Use "current_line" from "cmd_loop_cookie", it may have been
* incremented when defining a function. */
current_line = cmd_loop_cookie.current_line;
+ }
if (next_cmdline == NULL) {
XFREE_CLEAR(cmdline_copy);
@@ -630,11 +637,12 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
}
- /* reset did_emsg for a function that is not aborted by an error */
+ // 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)
- && !func_has_abort(real_cookie))
+ && !func_has_abort(real_cookie)) {
did_emsg = FALSE;
+ }
if (cstack.cs_looplevel > 0) {
++current_line;
@@ -659,24 +667,24 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
&& cstack.cs_line[cstack.cs_idx] >= 0
&& (cstack.cs_flags[cstack.cs_idx] & CSF_ACTIVE)) {
current_line = cstack.cs_line[cstack.cs_idx];
- /* remember we jumped there */
+ // remember we jumped there
cstack.cs_lflags |= CSL_HAD_LOOP;
- line_breakcheck(); /* check if CTRL-C typed */
+ line_breakcheck(); // check if CTRL-C typed
/* Check for the next breakpoint at or after the ":while"
* or ":for". */
if (breakpoint != NULL) {
- *breakpoint = dbg_find_breakpoint(
- getline_equal(fgetline, cookie, getsourceline),
- fname,
- ((wcmd_T *)lines_ga.ga_data)[current_line].lnum-1);
+ *breakpoint = dbg_find_breakpoint(getline_equal(fgetline, cookie, getsourceline),
+ fname,
+ ((wcmd_T *)lines_ga.ga_data)[current_line].lnum-1);
*dbg_tick = debug_tick;
}
} else {
- /* can only get here with ":endwhile" or ":endfor" */
- if (cstack.cs_idx >= 0)
+ // can only get here with ":endwhile" or ":endfor"
+ if (cstack.cs_idx >= 0) {
rewind_conditionals(&cstack, cstack.cs_idx - 1,
- CSF_WHILE | CSF_FOR, &cstack.cs_looplevel);
+ CSF_WHILE | CSF_FOR, &cstack.cs_looplevel);
+ }
}
}
/*
@@ -729,9 +737,8 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
force_abort = false;
}
- /* Convert an interrupt to an exception if appropriate. */
+ // Convert an interrupt to an exception if appropriate.
(void)do_intthrow(&cstack);
-
}
/*
* Continue executing command lines when:
@@ -750,14 +757,13 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
* the :endtry to be missed. */
&& (cstack.cs_trylevel == 0 || did_emsg_syntax)
&& used_getline
- && (getline_equal(fgetline, cookie, getexmodeline)
- || getline_equal(fgetline, cookie, getexline)))
+ && getline_equal(fgetline, cookie, getexline))
&& (next_cmdline != NULL
|| cstack.cs_idx >= 0
|| (flags & DOCMD_REPEAT)));
xfree(cmdline_copy);
- did_emsg_syntax = FALSE;
+ did_emsg_syntax = false;
GA_DEEP_CLEAR(&lines_ga, wcmd_T, FREE_WCMD);
if (cstack.cs_idx >= 0) {
@@ -770,14 +776,15 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
&& !source_finished(fgetline, cookie))
|| (getline_equal(fgetline, cookie, get_func_line)
&& !func_has_ended(real_cookie)))) {
- if (cstack.cs_flags[cstack.cs_idx] & CSF_TRY)
+ if (cstack.cs_flags[cstack.cs_idx] & CSF_TRY) {
EMSG(_(e_endtry));
- else if (cstack.cs_flags[cstack.cs_idx] & CSF_WHILE)
+ } else if (cstack.cs_flags[cstack.cs_idx] & CSF_WHILE) {
EMSG(_(e_endwhile));
- else if (cstack.cs_flags[cstack.cs_idx] & CSF_FOR)
+ } else if (cstack.cs_flags[cstack.cs_idx] & CSF_FOR) {
EMSG(_(e_endfor));
- else
+ } else {
EMSG(_(e_endif));
+ }
}
/*
@@ -790,10 +797,11 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
do {
int idx = cleanup_conditionals(&cstack, 0, TRUE);
- if (idx >= 0)
- --idx; /* remove try block not in its finally clause */
+ if (idx >= 0) {
+ --idx; // remove try block not in its finally clause
+ }
rewind_conditionals(&cstack, idx, CSF_WHILE | CSF_FOR,
- &cstack.cs_looplevel);
+ &cstack.cs_looplevel);
} while (cstack.cs_idx >= 0);
trylevel = initial_trylevel;
}
@@ -825,8 +833,8 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
switch (current_exception->type) {
case ET_USER:
vim_snprintf((char *)IObuff, IOSIZE,
- _("E605: Exception not caught: %s"),
- current_exception->value);
+ _("E605: Exception not caught: %s"),
+ current_exception->value);
p = vim_strsave(IObuff);
break;
case ET_ERROR:
@@ -890,27 +898,30 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
check_cstack = true;
}
} else {
- /* When leaving a function, reduce nesting level. */
- if (getline_equal(fgetline, cookie, get_func_line))
+ // When leaving a function, reduce nesting level.
+ if (getline_equal(fgetline, cookie, get_func_line)) {
--ex_nesting_level;
+ }
/*
* Go to debug mode when returning from a function in which we are
* single-stepping.
*/
if ((getline_equal(fgetline, cookie, getsourceline)
|| getline_equal(fgetline, cookie, get_func_line))
- && ex_nesting_level + 1 <= debug_break_level)
+ && ex_nesting_level + 1 <= debug_break_level) {
do_debug(getline_equal(fgetline, cookie, getsourceline)
? (char_u *)_("End of sourced file")
: (char_u *)_("End of function"));
+ }
}
/*
* Restore the exception environment (done after returning from the
* debugger).
*/
- if (flags & DOCMD_EXCRESET)
+ if (flags & DOCMD_EXCRESET) {
restore_dbg_stuff(&debug_saved);
+ }
msg_list = saved_msg_list;
@@ -929,10 +940,9 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
* wait for hit-return. Also for an error situation.
*/
if (retval == FAIL
- || (did_endif && KeyTyped && !did_emsg)
- ) {
- need_wait_return = FALSE;
- msg_didany = FALSE; /* don't wait when restarting edit */
+ || (did_endif && KeyTyped && !did_emsg)) {
+ need_wait_return = false;
+ msg_didany = false; // don't wait when restarting edit
} else if (need_wait_return) {
/*
* The msg_start() above clears msg_didout. The wait_return we do
@@ -944,7 +954,7 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
}
}
- did_endif = FALSE; /* in case do_cmdline used recursively */
+ did_endif = false; // in case do_cmdline used recursively
call_depth--;
end_batch_changes();
@@ -956,14 +966,14 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline,
*/
static char_u *get_loop_line(int c, void *cookie, int indent, bool do_concat)
{
- struct loop_cookie *cp = (struct loop_cookie *)cookie;
- wcmd_T *wp;
- char_u *line;
+ struct loop_cookie *cp = (struct loop_cookie *)cookie;
+ wcmd_T *wp;
+ char_u *line;
if (cp->current_line + 1 >= cp->lines_gap->ga_len) {
- if (cp->repeating)
- return NULL; /* trying to read past ":endwhile"/":endfor" */
-
+ if (cp->repeating) {
+ return NULL; // trying to read past ":endwhile"/":endfor"
+ }
// First time inside the ":while"/":for": get line normally.
if (cp->getline == NULL) {
line = getcmdline(c, 0L, indent, do_concat);
@@ -995,13 +1005,11 @@ static void store_loop_line(garray_T *gap, char_u *line)
p->lnum = sourcing_lnum;
}
-/*
- * If "fgetline" is get_loop_line(), return TRUE if the getline it uses equals
- * "func". * Otherwise return TRUE when "fgetline" equals "func".
- */
-int getline_equal(LineGetter fgetline,
- void *cookie, /* argument for fgetline() */
- LineGetter func)
+/// If "fgetline" is get_loop_line(), return TRUE if the getline it uses equals
+/// "func". * Otherwise return TRUE when "fgetline" equals "func".
+///
+/// @param cookie argument for fgetline()
+int getline_equal(LineGetter fgetline, void *cookie, LineGetter func)
{
LineGetter gp;
struct loop_cookie *cp;
@@ -1018,13 +1026,11 @@ int getline_equal(LineGetter fgetline,
return gp == func;
}
-/*
- * If "fgetline" is get_loop_line(), return the cookie used by the original
- * getline function. Otherwise return "cookie".
- */
-void * getline_cookie(LineGetter fgetline,
- void *cookie /* argument for fgetline() */
- )
+/// If "fgetline" is get_loop_line(), return the cookie used by the original
+/// getline function. Otherwise return "cookie".
+///
+/// @param cookie argument for fgetline()
+void *getline_cookie(LineGetter fgetline, void *cookie)
{
LineGetter gp;
struct loop_cookie *cp;
@@ -1053,16 +1059,18 @@ static int compute_buffer_local_count(int addr_type, int lnum, int offset)
int count = offset;
buf = firstbuf;
- while (buf->b_next != NULL && buf->b_fnum < lnum)
+ while (buf->b_next != NULL && buf->b_fnum < lnum) {
buf = buf->b_next;
+ }
while (count != 0) {
count += (count < 0) ? 1 : -1;
nextbuf = (offset < 0) ? buf->b_prev : buf->b_next;
- if (nextbuf == NULL)
+ if (nextbuf == NULL) {
break;
+ }
buf = nextbuf;
- if (addr_type == ADDR_LOADED_BUFFERS)
- /* skip over unloaded buffers */
+ if (addr_type == ADDR_LOADED_BUFFERS) {
+ // skip over unloaded buffers
while (buf->b_ml.ml_mfp == NULL) {
nextbuf = (offset < 0) ? buf->b_prev : buf->b_next;
if (nextbuf == NULL) {
@@ -1070,13 +1078,15 @@ static int compute_buffer_local_count(int addr_type, int lnum, int offset)
}
buf = nextbuf;
}
+ }
}
// we might have gone too far, last buffer is not loaded
if (addr_type == ADDR_LOADED_BUFFERS) {
while (buf->b_ml.ml_mfp == NULL) {
nextbuf = (offset >= 0) ? buf->b_prev : buf->b_next;
- if (nextbuf == NULL)
+ if (nextbuf == NULL) {
break;
+ }
buf = nextbuf;
}
}
@@ -1092,8 +1102,9 @@ static int current_win_nr(const win_T *win)
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
++nr;
- if (wp == win)
+ if (wp == win) {
break;
+ }
}
return nr;
}
@@ -1104,8 +1115,9 @@ static int current_tab_nr(tabpage_T *tab)
FOR_ALL_TABS(tp) {
++nr;
- if (tp == tab)
+ if (tp == tab) {
break;
+ }
}
return nr;
}
@@ -1120,87 +1132,87 @@ static int current_tab_nr(tabpage_T *tab)
static void get_wincmd_addr_type(char_u *arg, exarg_T *eap)
{
switch (*arg) {
- case 'S':
- case Ctrl_S:
- case 's':
- case Ctrl_N:
- case 'n':
- case 'j':
- case Ctrl_J:
- case 'k':
- case Ctrl_K:
- case 'T':
- case Ctrl_R:
- case 'r':
- case 'R':
- case 'K':
- case 'J':
- case '+':
- case '-':
- case Ctrl__:
- case '_':
- case '|':
- case ']':
- case Ctrl_RSB:
- case 'g':
- case Ctrl_G:
- case Ctrl_V:
- case 'v':
- case 'h':
- case Ctrl_H:
- case 'l':
- case Ctrl_L:
- case 'H':
- case 'L':
- case '>':
- case '<':
- case '}':
- case 'f':
- case 'F':
- case Ctrl_F:
- case 'i':
- case Ctrl_I:
- case 'd':
- case Ctrl_D:
- // window size or any count
- eap->addr_type = ADDR_OTHER; // -V1037
- break;
+ case 'S':
+ case Ctrl_S:
+ case 's':
+ case Ctrl_N:
+ case 'n':
+ case 'j':
+ case Ctrl_J:
+ case 'k':
+ case Ctrl_K:
+ case 'T':
+ case Ctrl_R:
+ case 'r':
+ case 'R':
+ case 'K':
+ case 'J':
+ case '+':
+ case '-':
+ case Ctrl__:
+ case '_':
+ case '|':
+ case ']':
+ case Ctrl_RSB:
+ case 'g':
+ case Ctrl_G:
+ case Ctrl_V:
+ case 'v':
+ case 'h':
+ case Ctrl_H:
+ case 'l':
+ case Ctrl_L:
+ case 'H':
+ case 'L':
+ case '>':
+ case '<':
+ case '}':
+ case 'f':
+ case 'F':
+ case Ctrl_F:
+ case 'i':
+ case Ctrl_I:
+ case 'd':
+ case Ctrl_D:
+ // window size or any count
+ eap->addr_type = ADDR_OTHER; // -V1037
+ break;
- case Ctrl_HAT:
- case '^':
- // buffer number
- eap->addr_type = ADDR_BUFFERS;
- break;
+ case Ctrl_HAT:
+ case '^':
+ // buffer number
+ eap->addr_type = ADDR_BUFFERS;
+ break;
- case Ctrl_Q:
- case 'q':
- case Ctrl_C:
- case 'c':
- case Ctrl_O:
- case 'o':
- case Ctrl_W:
- case 'w':
- case 'W':
- case 'x':
- case Ctrl_X:
- // window number
- eap->addr_type = ADDR_WINDOWS;
- break;
+ case Ctrl_Q:
+ case 'q':
+ case Ctrl_C:
+ case 'c':
+ case Ctrl_O:
+ case 'o':
+ case Ctrl_W:
+ case 'w':
+ case 'W':
+ case 'x':
+ case Ctrl_X:
+ // window number
+ eap->addr_type = ADDR_WINDOWS;
+ break;
- case Ctrl_Z:
- case 'z':
- case 'P':
- case 't':
- case Ctrl_T:
- case 'b':
- case Ctrl_B:
- case 'p':
- case Ctrl_P:
- case '=':
- case CAR:
- // no count
- eap->addr_type = ADDR_NONE;
- break;
+ case Ctrl_Z:
+ case 'z':
+ case 'P':
+ case 't':
+ case Ctrl_T:
+ case 'b':
+ case Ctrl_B:
+ case 'p':
+ case Ctrl_P:
+ case '=':
+ case CAR:
+ // no count
+ eap->addr_type = ADDR_NONE;
+ break;
}
}
@@ -1221,54 +1233,51 @@ static char_u *skip_colon_white(const char_u *p, bool skipleadingwhite)
return (char_u *)p;
}
-/*
- * Execute one Ex command.
- *
- * If 'sourcing' is TRUE, the command will be included in the error message.
- *
- * 1. skip comment lines and leading space
- * 2. handle command modifiers
- * 3. skip over the range to find the command
- * 4. parse the range
- * 5. parse the command
- * 6. parse arguments
- * 7. switch on command name
- *
- * Note: "fgetline" can be NULL.
- *
- * This function may be called recursively!
- */
-static char_u * do_one_cmd(char_u **cmdlinep,
- int flags,
- cstack_T *cstack,
- LineGetter fgetline,
- void *cookie /* argument for fgetline() */
- )
-{
- char_u *p;
+/// Execute one Ex command.
+///
+/// If 'sourcing' is TRUE, the command will be included in the error message.
+///
+/// 1. skip comment lines and leading space
+/// 2. handle command modifiers
+/// 3. skip over the range to find the command
+/// 4. parse the range
+/// 5. parse the command
+/// 6. parse arguments
+/// 7. switch on command name
+///
+/// Note: "fgetline" can be NULL.
+///
+/// This function may be called recursively!
+///
+/// @param cookie argument for fgetline()
+static char_u *do_one_cmd(char_u **cmdlinep, int flags, cstack_T *cstack, LineGetter fgetline,
+ void *cookie)
+{
+ char_u *p;
linenr_T lnum;
long n;
- char_u *errormsg = NULL; // error message
- char_u *after_modifier = NULL;
+ char_u *errormsg = NULL; // error message
+ char_u *after_modifier = NULL;
exarg_T ea;
const int save_msg_scroll = msg_scroll;
cmdmod_T save_cmdmod;
const int save_reg_executing = reg_executing;
- char_u *cmd;
+ char_u *cmd;
memset(&ea, 0, sizeof(ea));
ea.line1 = 1;
ea.line2 = 1;
ex_nesting_level++;
- /* When the last file has not been edited :q has to be typed twice. */
+ // When the last file has not been edited :q has to be typed twice.
if (quitmore
- /* avoid that a function call in 'statusline' does this */
+ // avoid that a function call in 'statusline' does this
&& !getline_equal(fgetline, cookie, get_func_line)
- /* avoid that an autocommand, e.g. QuitPre, does this */
- && !getline_equal(fgetline, cookie, getnextac)
- )
+ // avoid that an autocommand, e.g. QuitPre, does this
+ && !getline_equal(fgetline, cookie,
+ getnextac)) {
--quitmore;
+ }
/*
* Reset browse, confirm, etc.. They are restored when returning, for
@@ -1425,13 +1434,14 @@ static char_u * do_one_cmd(char_u **cmdlinep,
ea.line2 = curbuf->b_ml.ml_line_count;
}
- if (ea.line2 < 0)
+ if (ea.line2 < 0) {
errormsg = (char_u *)_(e_invrange);
- else {
- if (ea.line2 == 0)
+ } else {
+ if (ea.line2 == 0) {
curwin->w_cursor.lnum = 1;
- else
+ } else {
curwin->w_cursor.lnum = ea.line2;
+ }
beginline(BL_SOL | BL_FIX);
}
}
@@ -1448,7 +1458,7 @@ static char_u * do_one_cmd(char_u **cmdlinep,
++p;
}
p = vim_strnsave(ea.cmd, p - ea.cmd);
- int ret = apply_autocmds(EVENT_CMDUNDEFINED, p, p, TRUE, NULL);
+ int ret = apply_autocmds(EVENT_CMDUNDEFINED, p, p, true, NULL);
xfree(p);
// If the autocommands did something and didn't cause an error, try
// finding the command again.
@@ -1456,8 +1466,9 @@ static char_u * do_one_cmd(char_u **cmdlinep,
}
if (p == NULL) {
- if (!ea.skip)
+ if (!ea.skip) {
errormsg = (char_u *)_("E464: Ambiguous use of user-defined command");
+ }
goto doend;
}
// Check for wrong commands.
@@ -1479,8 +1490,8 @@ static char_u * do_one_cmd(char_u **cmdlinep,
// set when Not Implemented
const int ni = !IS_USER_CMDIDX(ea.cmdidx)
- && (cmdnames[ea.cmdidx].cmd_func == ex_ni
- || cmdnames[ea.cmdidx].cmd_func == ex_script_ni);
+ && (cmdnames[ea.cmdidx].cmd_func == ex_ni
+ || cmdnames[ea.cmdidx].cmd_func == ex_script_ni);
// Forced commands.
@@ -1506,7 +1517,7 @@ static char_u * do_one_cmd(char_u **cmdlinep,
if (!MODIFIABLE(curbuf) && (ea.argt & EX_MODIFY)
// allow :put in terminals
&& (!curbuf->terminal || ea.cmdidx != CMD_put)) {
- /* Command not allowed in non-'modifiable' buffer */
+ // Command not allowed in non-'modifiable' buffer
errormsg = (char_u *)_(e_modifiable);
goto doend;
}
@@ -1518,7 +1529,7 @@ static char_u * do_one_cmd(char_u **cmdlinep,
goto doend;
}
- // Disallow editing another buffer when "curbuf_lock" is set.
+ // Disallow editing another buffer when "curbuf->b_ro_locked" is set.
// Do allow ":checktime" (it is postponed).
// Do allow ":edit" (check for an argument later).
// Do allow ":file" with no arguments (check for an argument later).
@@ -1565,8 +1576,9 @@ static char_u * do_one_cmd(char_u **cmdlinep,
ea.line1 = ea.line2;
ea.line2 = lnum;
}
- if ((errormsg = invalid_range(&ea)) != NULL)
+ if ((errormsg = invalid_range(&ea)) != NULL) {
goto doend;
+ }
}
if ((ea.addr_type == ADDR_OTHER) && ea.addr_count == 0) {
@@ -1589,19 +1601,21 @@ static char_u * do_one_cmd(char_u **cmdlinep,
* option here, so things like % get expanded.
*/
p = replace_makeprg(&ea, p, cmdlinep);
- if (p == NULL)
+ if (p == NULL) {
goto doend;
+ }
/*
* Skip to start of argument.
* Don't do this for the ":!" command, because ":!! -l" needs the space.
*/
- if (ea.cmdidx == CMD_bang)
+ if (ea.cmdidx == CMD_bang) {
ea.arg = p;
- else
+ } else {
ea.arg = skipwhite(p);
+ }
- // ":file" cannot be run with an argument when "curbuf_lock" is set
+ // ":file" cannot be run with an argument when "curbuf->b_ro_locked" is set
if (ea.cmdidx == CMD_file && *ea.arg != NUL && curbuf_locked()) {
goto doend;
}
@@ -1620,14 +1634,14 @@ static char_u * do_one_cmd(char_u **cmdlinep,
}
if (ea.cmdidx == CMD_write || ea.cmdidx == CMD_update) {
- if (*ea.arg == '>') { /* append */
- if (*++ea.arg != '>') { /* typed wrong */
+ if (*ea.arg == '>') { // append
+ if (*++ea.arg != '>') { // typed wrong
errormsg = (char_u *)_("E494: Use w or w>>");
goto doend;
}
ea.arg = skipwhite(ea.arg + 1);
ea.append = TRUE;
- } else if (*ea.arg == '!' && ea.cmdidx == CMD_write) { /* :w !filter */
+ } else if (*ea.arg == '!' && ea.cmdidx == CMD_write) { // :w !filter
++ea.arg;
ea.usefilter = TRUE;
}
@@ -1635,9 +1649,9 @@ static char_u * do_one_cmd(char_u **cmdlinep,
if (ea.cmdidx == CMD_read) {
if (ea.forceit) {
- ea.usefilter = TRUE; /* :r! filter if ea.forceit */
+ ea.usefilter = TRUE; // :r! filter if ea.forceit
ea.forceit = FALSE;
- } else if (*ea.arg == '!') { /* :r !filter */
+ } else if (*ea.arg == '!') { // :r !filter
++ea.arg;
ea.usefilter = TRUE;
}
@@ -1645,7 +1659,7 @@ static char_u * do_one_cmd(char_u **cmdlinep,
if (ea.cmdidx == CMD_lshift || ea.cmdidx == CMD_rshift) {
ea.amount = 1;
- while (*ea.arg == *ea.cmd) { /* count number of '>' or '<' */
+ while (*ea.arg == *ea.cmd) { // count number of '>' or '<'
++ea.arg;
++ea.amount;
}
@@ -1696,67 +1710,67 @@ static char_u * do_one_cmd(char_u **cmdlinep,
ea.line1 = 1;
switch (ea.addr_type) {
- case ADDR_LINES:
- case ADDR_OTHER:
- ea.line2 = curbuf->b_ml.ml_line_count;
- break;
- case ADDR_LOADED_BUFFERS:
- buf = firstbuf;
- while (buf->b_next != NULL && buf->b_ml.ml_mfp == NULL) {
- buf = buf->b_next;
- }
- ea.line1 = buf->b_fnum;
- buf = lastbuf;
- while (buf->b_prev != NULL && buf->b_ml.ml_mfp == NULL) {
- buf = buf->b_prev;
- }
- ea.line2 = buf->b_fnum;
- break;
- case ADDR_BUFFERS:
- ea.line1 = firstbuf->b_fnum;
- ea.line2 = lastbuf->b_fnum;
- break;
- case ADDR_WINDOWS:
- ea.line2 = LAST_WIN_NR;
- break;
- case ADDR_TABS:
- ea.line2 = LAST_TAB_NR;
- break;
- case ADDR_TABS_RELATIVE:
+ case ADDR_LINES:
+ case ADDR_OTHER:
+ ea.line2 = curbuf->b_ml.ml_line_count;
+ break;
+ case ADDR_LOADED_BUFFERS:
+ buf = firstbuf;
+ while (buf->b_next != NULL && buf->b_ml.ml_mfp == NULL) {
+ buf = buf->b_next;
+ }
+ ea.line1 = buf->b_fnum;
+ buf = lastbuf;
+ while (buf->b_prev != NULL && buf->b_ml.ml_mfp == NULL) {
+ buf = buf->b_prev;
+ }
+ ea.line2 = buf->b_fnum;
+ break;
+ case ADDR_BUFFERS:
+ ea.line1 = firstbuf->b_fnum;
+ ea.line2 = lastbuf->b_fnum;
+ break;
+ case ADDR_WINDOWS:
+ ea.line2 = LAST_WIN_NR;
+ break;
+ case ADDR_TABS:
+ ea.line2 = LAST_TAB_NR;
+ break;
+ case ADDR_TABS_RELATIVE:
+ ea.line2 = 1;
+ break;
+ case ADDR_ARGUMENTS:
+ if (ARGCOUNT == 0) {
+ ea.line1 = ea.line2 = 0;
+ } else {
+ ea.line2 = ARGCOUNT;
+ }
+ break;
+ case ADDR_QUICKFIX_VALID:
+ ea.line2 = qf_get_valid_size(&ea);
+ if (ea.line2 == 0) {
ea.line2 = 1;
- break;
- case ADDR_ARGUMENTS:
- if (ARGCOUNT == 0) {
- ea.line1 = ea.line2 = 0;
- } else {
- ea.line2 = ARGCOUNT;
- }
- break;
- case ADDR_QUICKFIX_VALID:
- ea.line2 = qf_get_valid_size(&ea);
- if (ea.line2 == 0) {
- ea.line2 = 1;
- }
- break;
- case ADDR_NONE:
- case ADDR_UNSIGNED:
- case ADDR_QUICKFIX:
- IEMSG(_("INTERNAL: Cannot use EX_DFLALL "
- "with ADDR_NONE, ADDR_UNSIGNED or ADDR_QUICKFIX"));
- break;
+ }
+ break;
+ case ADDR_NONE:
+ case ADDR_UNSIGNED:
+ case ADDR_QUICKFIX:
+ IEMSG(_("INTERNAL: Cannot use EX_DFLALL "
+ "with ADDR_NONE, ADDR_UNSIGNED or ADDR_QUICKFIX"));
+ break;
}
}
// accept numbered register only when no count allowed (:put)
if ((ea.argt & EX_REGSTR)
&& *ea.arg != NUL
- /* Do not allow register = for user commands */
+ // Do not allow register = for user commands
&& (!IS_USER_CMDIDX(ea.cmdidx) || *ea.arg != '=')
&& !((ea.argt & EX_COUNT) && ascii_isdigit(*ea.arg))) {
if (valid_yank_reg(*ea.arg, (ea.cmdidx != CMD_put
&& !IS_USER_CMDIDX(ea.cmdidx)))) {
ea.regname = *ea.arg++;
- /* for '=' register: accept the rest of the line as an expression */
+ // for '=' register: accept the rest of the line as an expression
if (ea.arg[-1] == '=' && ea.arg[0] != NUL) {
set_expr_line(vim_strsave(ea.arg));
ea.arg += STRLEN(ea.arg);
@@ -1780,8 +1794,9 @@ static char_u * do_one_cmd(char_u **cmdlinep,
}
if (ea.addr_type != ADDR_LINES) { // e.g. :buffer 2, :sleep 3
ea.line2 = n;
- if (ea.addr_count == 0)
+ if (ea.addr_count == 0) {
ea.addr_count = 1;
+ }
} else {
ea.line1 = ea.line2;
ea.line2 += n - 1;
@@ -1819,7 +1834,7 @@ static char_u * do_one_cmd(char_u **cmdlinep,
*/
if (ea.skip) {
switch (ea.cmdidx) {
- /* commands that need evaluation */
+ // commands that need evaluation
case CMD_while:
case CMD_endwhile:
case CMD_for:
@@ -1920,20 +1935,20 @@ static char_u * do_one_cmd(char_u **cmdlinep,
* number. Don't do this for a user command.
*/
if ((ea.argt & EX_BUFNAME) && *ea.arg != NUL && ea.addr_count == 0
- && !IS_USER_CMDIDX(ea.cmdidx)
- ) {
+ && !IS_USER_CMDIDX(ea.cmdidx)) {
/*
* :bdelete, :bwipeout and :bunload take several arguments, separated
* by spaces: find next space (skipping over escaped characters).
* The others take one argument: ignore trailing spaces.
*/
if (ea.cmdidx == CMD_bdelete || ea.cmdidx == CMD_bwipeout
- || ea.cmdidx == CMD_bunload)
+ || ea.cmdidx == CMD_bunload) {
p = skiptowhite_esc(ea.arg);
- else {
+ } else {
p = ea.arg + STRLEN(ea.arg);
- while (p > ea.arg && ascii_iswhite(p[-1]))
+ while (p > ea.arg && ascii_iswhite(p[-1])) {
--p;
+ }
}
ea.line2 = buflist_findpat(ea.arg, p, (ea.argt & EX_BUFUNL) != 0,
false, false);
@@ -1966,8 +1981,9 @@ static char_u * do_one_cmd(char_u **cmdlinep,
*/
ea.errmsg = NULL;
(cmdnames[ea.cmdidx].cmd_func)(&ea);
- if (ea.errmsg != NULL)
+ if (ea.errmsg != NULL) {
errormsg = (char_u *)_(ea.errmsg);
+ }
}
/*
@@ -1977,14 +1993,15 @@ static char_u * do_one_cmd(char_u **cmdlinep,
* exception, or reanimate a returned function or finished script file and
* return or finish it again.
*/
- if (need_rethrow)
+ if (need_rethrow) {
do_throw(cstack);
- else if (check_cstack) {
- if (source_finished(fgetline, cookie))
+ } else if (check_cstack) {
+ if (source_finished(fgetline, cookie)) {
do_finish(&ea, TRUE);
- else if (getline_equal(fgetline, cookie, get_func_line)
- && current_func_returned())
+ } else if (getline_equal(fgetline, cookie, get_func_line)
+ && current_func_returned()) {
do_return(&ea, TRUE, FALSE, NULL);
+ }
}
need_rethrow = check_cstack = FALSE;
@@ -2006,7 +2023,7 @@ doend:
emsg(errormsg);
}
do_errthrow(cstack,
- (ea.cmdidx != CMD_SIZE && !IS_USER_CMDIDX(ea.cmdidx))
+ (ea.cmdidx != CMD_SIZE && !IS_USER_CMDIDX(ea.cmdidx))
? cmdnames[(int)ea.cmdidx].cmd_name
: (char_u *)NULL);
@@ -2018,8 +2035,9 @@ doend:
sandbox--;
}
- if (ea.nextcmd && *ea.nextcmd == NUL) /* not really a next command */
+ if (ea.nextcmd && *ea.nextcmd == NUL) { // not really a next command
ea.nextcmd = NULL;
+ }
--ex_nesting_level;
@@ -2056,8 +2074,7 @@ int parse_command_modifiers(exarg_T *eap, char_u **errormsg, bool skip_only)
// in ex mode, an empty line works like :+
if (*eap->cmd == NUL && exmode_active
- && (getline_equal(eap->getline, eap->cookie, getexmodeline)
- || getline_equal(eap->getline, eap->cookie, getexline))
+ && getline_equal(eap->getline, eap->cookie, getexline)
&& curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) {
eap->cmd = (char_u *)"+";
if (!skip_only) {
@@ -2079,12 +2096,15 @@ int parse_command_modifiers(exarg_T *eap, char_u **errormsg, bool skip_only)
p = skip_range(eap->cmd, NULL);
switch (*p) {
// When adding an entry, also modify cmd_exists().
- case 'a': if (!checkforcmd(&eap->cmd, "aboveleft", 3))
+ case 'a':
+ if (!checkforcmd(&eap->cmd, "aboveleft", 3)) {
break;
+ }
cmdmod.split |= WSP_ABOVE;
continue;
- case 'b': if (checkforcmd(&eap->cmd, "belowright", 3)) {
+ case 'b':
+ if (checkforcmd(&eap->cmd, "belowright", 3)) {
cmdmod.split |= WSP_BELOW;
continue;
}
@@ -2098,15 +2118,18 @@ int parse_command_modifiers(exarg_T *eap, char_u **errormsg, bool skip_only)
cmdmod.split |= WSP_BOT;
continue;
- case 'c': if (!checkforcmd(&eap->cmd, "confirm", 4))
+ case 'c':
+ if (!checkforcmd(&eap->cmd, "confirm", 4)) {
break;
+ }
cmdmod.confirm = true;
continue;
- case 'k': if (checkforcmd(&eap->cmd, "keepmarks", 3)) {
+ case 'k':
+ if (checkforcmd(&eap->cmd, "keepmarks", 3)) {
cmdmod.keepmarks = true;
continue;
- }
+ }
if (checkforcmd(&eap->cmd, "keepalt", 5)) {
cmdmod.keepalt = true;
continue;
@@ -2154,17 +2177,20 @@ int parse_command_modifiers(exarg_T *eap, char_u **errormsg, bool skip_only)
}
// ":hide" and ":hide | cmd" are not modifiers
- case 'h': if (p != eap->cmd || !checkforcmd(&p, "hide", 3)
- || *p == NUL || ends_excmd(*p))
+ case 'h':
+ if (p != eap->cmd || !checkforcmd(&p, "hide", 3)
+ || *p == NUL || ends_excmd(*p)) {
break;
+ }
eap->cmd = p;
cmdmod.hide = true;
continue;
- case 'l': if (checkforcmd(&eap->cmd, "lockmarks", 3)) {
+ case 'l':
+ if (checkforcmd(&eap->cmd, "lockmarks", 3)) {
cmdmod.lockmarks = true;
continue;
- }
+ }
if (!checkforcmd(&eap->cmd, "leftabove", 5)) {
break;
@@ -2189,12 +2215,15 @@ int parse_command_modifiers(exarg_T *eap, char_u **errormsg, bool skip_only)
cmdmod.noswapfile = true;
continue;
- case 'r': if (!checkforcmd(&eap->cmd, "rightbelow", 6))
+ case 'r':
+ if (!checkforcmd(&eap->cmd, "rightbelow", 6)) {
break;
+ }
cmdmod.split |= WSP_BELOW;
continue;
- case 's': if (checkforcmd(&eap->cmd, "sandbox", 3)) {
+ case 's':
+ if (checkforcmd(&eap->cmd, "sandbox", 3)) {
if (!skip_only) {
if (!eap->did_sandbox) {
sandbox++;
@@ -2202,7 +2231,7 @@ int parse_command_modifiers(exarg_T *eap, char_u **errormsg, bool skip_only)
eap->did_sandbox = true;
}
continue;
- }
+ }
if (!checkforcmd(&eap->cmd, "silent", 3)) {
break;
}
@@ -2222,32 +2251,34 @@ int parse_command_modifiers(exarg_T *eap, char_u **errormsg, bool skip_only)
}
continue;
- case 't': if (checkforcmd(&p, "tab", 3)) {
- if (!skip_only) {
- long tabnr = get_address(
- eap, &eap->cmd, ADDR_TABS, eap->skip, skip_only, false, 1);
+ case 't':
+ if (checkforcmd(&p, "tab", 3)) {
+ if (!skip_only) {
+ long tabnr = get_address(eap, &eap->cmd, ADDR_TABS, eap->skip, skip_only, false, 1);
- if (tabnr == MAXLNUM) {
- cmdmod.tab = tabpage_index(curtab) + 1;
- } else {
- if (tabnr < 0 || tabnr > LAST_TAB_NR) {
- *errormsg = (char_u *)_(e_invrange);
- return false;
+ if (tabnr == MAXLNUM) {
+ cmdmod.tab = tabpage_index(curtab) + 1;
+ } else {
+ if (tabnr < 0 || tabnr > LAST_TAB_NR) {
+ *errormsg = (char_u *)_(e_invrange);
+ return false;
+ }
+ cmdmod.tab = tabnr + 1;
}
- cmdmod.tab = tabnr + 1;
}
+ eap->cmd = p;
+ continue;
}
- eap->cmd = p;
- continue;
- }
if (!checkforcmd(&eap->cmd, "topleft", 2)) {
break;
}
cmdmod.split |= WSP_TOP;
continue;
- case 'u': if (!checkforcmd(&eap->cmd, "unsilent", 3))
+ case 'u':
+ if (!checkforcmd(&eap->cmd, "unsilent", 3)) {
break;
+ }
if (!skip_only) {
if (eap->save_msg_silent == -1) {
eap->save_msg_silent = msg_silent;
@@ -2256,12 +2287,14 @@ int parse_command_modifiers(exarg_T *eap, char_u **errormsg, bool skip_only)
}
continue;
- case 'v': if (checkforcmd(&eap->cmd, "vertical", 4)) {
+ case 'v':
+ if (checkforcmd(&eap->cmd, "vertical", 4)) {
cmdmod.split |= WSP_VERT;
continue;
- }
- if (!checkforcmd(&p, "verbose", 4))
+ }
+ if (!checkforcmd(&p, "verbose", 4)) {
break;
+ }
if (!skip_only) {
if (eap->verbose_save < 0) {
eap->verbose_save = p_verbose;
@@ -2333,40 +2366,40 @@ int parse_cmd_address(exarg_T *eap, char_u **errormsg, bool silent)
for (;;) {
eap->line1 = eap->line2;
switch (eap->addr_type) {
- case ADDR_LINES:
- case ADDR_OTHER:
- // default is current line number
- eap->line2 = curwin->w_cursor.lnum;
- break;
- case ADDR_WINDOWS:
- eap->line2 = CURRENT_WIN_NR;
- break;
- case ADDR_ARGUMENTS:
- eap->line2 = curwin->w_arg_idx + 1;
- if (eap->line2 > ARGCOUNT) {
- eap->line2 = ARGCOUNT;
- }
- break;
- case ADDR_LOADED_BUFFERS:
- case ADDR_BUFFERS:
- eap->line2 = curbuf->b_fnum;
- break;
- case ADDR_TABS:
- eap->line2 = CURRENT_TAB_NR;
- break;
- case ADDR_TABS_RELATIVE:
- case ADDR_UNSIGNED:
- eap->line2 = 1;
- break;
- case ADDR_QUICKFIX:
- eap->line2 = qf_get_cur_idx(eap);
- break;
- case ADDR_QUICKFIX_VALID:
- eap->line2 = qf_get_cur_valid_idx(eap);
- break;
- case ADDR_NONE:
- // Will give an error later if a range is found.
- break;
+ case ADDR_LINES:
+ case ADDR_OTHER:
+ // default is current line number
+ eap->line2 = curwin->w_cursor.lnum;
+ break;
+ case ADDR_WINDOWS:
+ eap->line2 = CURRENT_WIN_NR;
+ break;
+ case ADDR_ARGUMENTS:
+ eap->line2 = curwin->w_arg_idx + 1;
+ if (eap->line2 > ARGCOUNT) {
+ eap->line2 = ARGCOUNT;
+ }
+ break;
+ case ADDR_LOADED_BUFFERS:
+ case ADDR_BUFFERS:
+ eap->line2 = curbuf->b_fnum;
+ break;
+ case ADDR_TABS:
+ eap->line2 = CURRENT_TAB_NR;
+ break;
+ case ADDR_TABS_RELATIVE:
+ case ADDR_UNSIGNED:
+ eap->line2 = 1;
+ break;
+ case ADDR_QUICKFIX:
+ eap->line2 = qf_get_cur_idx(eap);
+ break;
+ case ADDR_QUICKFIX_VALID:
+ eap->line2 = qf_get_cur_valid_idx(eap);
+ break;
+ case ADDR_NONE:
+ // Will give an error later if a range is found.
+ break;
}
eap->cmd = skipwhite(eap->cmd);
lnum = get_address(eap, &eap->cmd, eap->addr_type, eap->skip, silent,
@@ -2378,65 +2411,65 @@ int parse_cmd_address(exarg_T *eap, char_u **errormsg, bool silent)
if (*eap->cmd == '%') { // '%' - all lines
eap->cmd++;
switch (eap->addr_type) {
- case ADDR_LINES:
- case ADDR_OTHER:
- eap->line1 = 1;
- eap->line2 = curbuf->b_ml.ml_line_count;
- break;
- case ADDR_LOADED_BUFFERS: {
- buf_T *buf = firstbuf;
+ case ADDR_LINES:
+ case ADDR_OTHER:
+ eap->line1 = 1;
+ eap->line2 = curbuf->b_ml.ml_line_count;
+ break;
+ case ADDR_LOADED_BUFFERS: {
+ buf_T *buf = firstbuf;
- while (buf->b_next != NULL && buf->b_ml.ml_mfp == NULL) {
- buf = buf->b_next;
- }
- eap->line1 = buf->b_fnum;
- buf = lastbuf;
- while (buf->b_prev != NULL && buf->b_ml.ml_mfp == NULL) {
- buf = buf->b_prev;
- }
- eap->line2 = buf->b_fnum;
- break;
+ while (buf->b_next != NULL && buf->b_ml.ml_mfp == NULL) {
+ buf = buf->b_next;
}
- case ADDR_BUFFERS:
- eap->line1 = firstbuf->b_fnum;
- eap->line2 = lastbuf->b_fnum;
- break;
- case ADDR_WINDOWS:
- case ADDR_TABS:
- if (IS_USER_CMDIDX(eap->cmdidx)) {
- eap->line1 = 1;
- eap->line2 = eap->addr_type == ADDR_WINDOWS
+ eap->line1 = buf->b_fnum;
+ buf = lastbuf;
+ while (buf->b_prev != NULL && buf->b_ml.ml_mfp == NULL) {
+ buf = buf->b_prev;
+ }
+ eap->line2 = buf->b_fnum;
+ break;
+ }
+ case ADDR_BUFFERS:
+ eap->line1 = firstbuf->b_fnum;
+ eap->line2 = lastbuf->b_fnum;
+ break;
+ case ADDR_WINDOWS:
+ case ADDR_TABS:
+ if (IS_USER_CMDIDX(eap->cmdidx)) {
+ eap->line1 = 1;
+ eap->line2 = eap->addr_type == ADDR_WINDOWS
? LAST_WIN_NR : LAST_TAB_NR;
- } else {
- // there is no Vim command which uses '%' and
- // ADDR_WINDOWS or ADDR_TABS
- *errormsg = (char_u *)_(e_invrange);
- return FAIL;
- }
- break;
- case ADDR_TABS_RELATIVE:
- case ADDR_UNSIGNED:
- case ADDR_QUICKFIX:
+ } else {
+ // there is no Vim command which uses '%' and
+ // ADDR_WINDOWS or ADDR_TABS
*errormsg = (char_u *)_(e_invrange);
return FAIL;
- case ADDR_ARGUMENTS:
- if (ARGCOUNT == 0) {
- eap->line1 = eap->line2 = 0;
- } else {
- eap->line1 = 1;
- eap->line2 = ARGCOUNT;
- }
- break;
- case ADDR_QUICKFIX_VALID:
+ }
+ break;
+ case ADDR_TABS_RELATIVE:
+ case ADDR_UNSIGNED:
+ case ADDR_QUICKFIX:
+ *errormsg = (char_u *)_(e_invrange);
+ return FAIL;
+ case ADDR_ARGUMENTS:
+ if (ARGCOUNT == 0) {
+ eap->line1 = eap->line2 = 0;
+ } else {
eap->line1 = 1;
- eap->line2 = qf_get_valid_size(eap);
- if (eap->line2 == 0) {
- eap->line2 = 1;
- }
- break;
- case ADDR_NONE:
- // Will give an error later if a range is found.
- break;
+ eap->line2 = ARGCOUNT;
+ }
+ break;
+ case ADDR_QUICKFIX_VALID:
+ eap->line1 = 1;
+ eap->line2 = qf_get_valid_size(eap);
+ if (eap->line2 == 0) {
+ eap->line2 = 1;
+ }
+ break;
+ case ADDR_NONE:
+ // Will give an error later if a range is found.
+ break;
}
eap->addr_count++;
} else if (*eap->cmd == '*') {
@@ -2492,22 +2525,21 @@ int parse_cmd_address(exarg_T *eap, char_u **errormsg, bool silent)
return OK;
}
-/*
- * Check for an Ex command with optional tail.
- * If there is a match advance "pp" to the argument and return TRUE.
- */
-int
-checkforcmd(
- char_u **pp, // start of command
- char *cmd, // name of command
- int len // required length
-)
+/// Check for an Ex command with optional tail.
+/// If there is a match advance "pp" to the argument and return TRUE.
+///
+/// @param pp start of command
+/// @param cmd name of command
+/// @param len required length
+int checkforcmd(char_u **pp, char *cmd, int len)
{
int i;
- for (i = 0; cmd[i] != NUL; ++i)
- if (((char_u *)cmd)[i] != (*pp)[i])
+ for (i = 0; cmd[i] != NUL; ++i) {
+ if (((char_u *)cmd)[i] != (*pp)[i]) {
break;
+ }
+ }
if (i >= len && !isalpha((*pp)[i])) {
*pp = skipwhite(*pp + i);
return TRUE;
@@ -2532,8 +2564,9 @@ static void append_command(char_u *cmd)
s += 2;
STRCPY(d, "<a0>");
d += 4;
- } else
+ } else {
MB_COPY_CHAR(s, d);
+ }
}
*d = NUL;
}
@@ -2547,7 +2580,7 @@ static char_u *find_command(exarg_T *eap, int *full)
FUNC_ATTR_NONNULL_ARG(1)
{
int len;
- char_u *p;
+ char_u *p;
int i;
/*
@@ -2555,8 +2588,8 @@ static char_u *find_command(exarg_T *eap, int *full)
* Exceptions:
* - the 'k' command can directly be followed by any character.
* - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r'
- * but :sre[wind] is another command, as are :scr[iptnames],
- * :scs[cope], :sim[alt], :sig[ns] and :sil[ent].
+ * but :sre[wind] is another command, as are :scr[iptnames],
+ * :scs[cope], :sim[alt], :sig[ns] and :sil[ent].
* - the "d" command can directly be followed by 'l' or 'p' flag.
*/
p = eap->cmd;
@@ -2576,29 +2609,36 @@ static char_u *find_command(exarg_T *eap, int *full)
eap->cmdidx = CMD_substitute;
++p;
} else {
- while (ASCII_ISALPHA(*p))
+ while (ASCII_ISALPHA(*p)) {
++p;
- /* for python 3.x support ":py3", ":python3", ":py3file", etc. */
- if (eap->cmd[0] == 'p' && eap->cmd[1] == 'y')
- while (ASCII_ISALNUM(*p))
+ }
+ // for python 3.x support ":py3", ":python3", ":py3file", etc.
+ if (eap->cmd[0] == 'p' && eap->cmd[1] == 'y') {
+ while (ASCII_ISALNUM(*p)) {
++p;
+ }
+ }
- /* check for non-alpha command */
- if (p == eap->cmd && vim_strchr((char_u *)"@!=><&~#", *p) != NULL)
+ // check for non-alpha command
+ if (p == eap->cmd && vim_strchr((char_u *)"@!=><&~#", *p) != NULL) {
++p;
+ }
len = (int)(p - eap->cmd);
if (*eap->cmd == 'd' && (p[-1] == 'l' || p[-1] == 'p')) {
/* Check for ":dl", ":dell", etc. to ":deletel": that's
* :delete with the 'l' flag. Same for 'p'. */
- for (i = 0; i < len; ++i)
- if (eap->cmd[i] != ((char_u *)"delete")[i])
+ for (i = 0; i < len; ++i) {
+ if (eap->cmd[i] != ((char_u *)"delete")[i]) {
break;
+ }
+ }
if (i == len - 1) {
--len;
- if (p[-1] == 'l')
+ if (p[-1] == 'l') {
eap->flags |= EXFLAG_LIST;
- else
+ } else {
eap->flags |= EXFLAG_PRINT;
+ }
}
}
@@ -2606,7 +2646,7 @@ static char_u *find_command(exarg_T *eap, int *full)
const int c1 = eap->cmd[0];
const int c2 = len == 1 ? NUL : eap->cmd[1];
- if (command_count != (int)CMD_SIZE) {
+ if (command_count != CMD_SIZE) {
iemsg((char *)_("E943: Command table needs to be updated, run 'make'"));
getout(1);
}
@@ -2621,55 +2661,55 @@ static char_u *find_command(exarg_T *eap, int *full)
eap->cmdidx = CMD_bang;
}
- for (; (int)eap->cmdidx < (int)CMD_SIZE;
- eap->cmdidx = (cmdidx_T)((int)eap->cmdidx + 1))
+ for (; (int)eap->cmdidx < CMD_SIZE;
+ eap->cmdidx = (cmdidx_T)((int)eap->cmdidx + 1)) {
if (STRNCMP(cmdnames[(int)eap->cmdidx].cmd_name, (char *)eap->cmd,
- (size_t)len) == 0) {
+ (size_t)len) == 0) {
if (full != NULL
- && cmdnames[(int)eap->cmdidx].cmd_name[len] == NUL)
+ && cmdnames[(int)eap->cmdidx].cmd_name[len] == NUL) {
*full = TRUE;
+ }
break;
}
+ }
// Look for a user defined command as a last resort.
if ((eap->cmdidx == CMD_SIZE)
&& *eap->cmd >= 'A' && *eap->cmd <= 'Z') {
- /* User defined commands may contain digits. */
- while (ASCII_ISALNUM(*p))
+ // User defined commands may contain digits.
+ while (ASCII_ISALNUM(*p)) {
++p;
+ }
p = find_ucmd(eap, p, full, NULL, NULL);
}
- if (p == eap->cmd)
+ if (p == eap->cmd) {
eap->cmdidx = CMD_SIZE;
+ }
}
return p;
}
-/*
- * Search for a user command that matches "eap->cmd".
- * Return cmdidx in "eap->cmdidx", flags in "eap->argt", idx in "eap->useridx".
- * Return a pointer to just after the command.
- * Return NULL if there is no matching command.
- */
-static char_u *
-find_ucmd (
- exarg_T *eap,
- char_u *p, // end of the command (possibly including count)
- int *full, // set to TRUE for a full match
- expand_T *xp, // used for completion, NULL otherwise
- int *complp // completion flags or NULL
-)
+/// Search for a user command that matches "eap->cmd".
+/// Return cmdidx in "eap->cmdidx", flags in "eap->argt", idx in "eap->useridx".
+/// Return a pointer to just after the command.
+/// Return NULL if there is no matching command.
+///
+/// @param *p end of the command (possibly including count)
+/// @param full set to TRUE for a full match
+/// @param xp used for completion, NULL otherwise
+/// @param complp completion flags or NULL
+static char_u *find_ucmd(exarg_T *eap, char_u *p, int *full, expand_T *xp, int *complp)
{
int len = (int)(p - eap->cmd);
int j, k, matchlen = 0;
- ucmd_T *uc;
- int found = FALSE;
- int possible = FALSE;
- char_u *cp, *np; /* Point into typed cmd and test name */
- garray_T *gap;
- int amb_local = FALSE; /* Found ambiguous buffer-local command,
- only full match global is accepted. */
+ ucmd_T *uc;
+ bool found = false;
+ bool possible = false;
+ char_u *cp, *np; // Point into typed cmd and test name
+ garray_T *gap;
+ bool amb_local = false; // Found ambiguous buffer-local command,
+ // only full match global is accepted.
/*
* Look for buffer-local user commands first, then global ones.
@@ -2681,16 +2721,18 @@ find_ucmd (
cp = eap->cmd;
np = uc->uc_name;
k = 0;
- while (k < len && *np != NUL && *cp++ == *np++)
+ while (k < len && *np != NUL && *cp++ == *np++) {
k++;
+ }
if (k == len || (*np == NUL && ascii_isdigit(eap->cmd[k]))) {
/* If finding a second match, the command is ambiguous. But
* not if a buffer-local command wasn't a full match and a
* global command is a full match. */
if (k == len && found && *np != NUL) {
- if (gap == &ucmds)
+ if (gap == &ucmds) {
return NULL;
- amb_local = TRUE;
+ }
+ amb_local = true;
}
if (!found || (k == len && *np == NUL)) {
@@ -2698,15 +2740,17 @@ find_ucmd (
* be another command including the digit that we
* should use instead.
*/
- if (k == len)
- found = TRUE;
- else
- possible = TRUE;
+ if (k == len) {
+ found = true;
+ } else {
+ possible = true;
+ }
- if (gap == &ucmds)
+ if (gap == &ucmds) {
eap->cmdidx = CMD_USER;
- else
+ } else {
eap->cmdidx = CMD_USER_BUF;
+ }
eap->argt = uc->uc_argt;
eap->useridx = j;
eap->addr_type = uc->uc_addr_type;
@@ -2723,39 +2767,43 @@ find_ucmd (
* if this is an exact match. */
matchlen = k;
if (k == len && *np == NUL) {
- if (full != NULL)
+ if (full != NULL) {
*full = TRUE;
- amb_local = FALSE;
+ }
+ amb_local = false;
break;
}
}
}
}
- /* Stop if we found a full match or searched all. */
- if (j < gap->ga_len || gap == &ucmds)
+ // Stop if we found a full match or searched all.
+ if (j < gap->ga_len || gap == &ucmds) {
break;
+ }
gap = &ucmds;
}
- /* Only found ambiguous matches. */
+ // Only found ambiguous matches.
if (amb_local) {
- if (xp != NULL)
+ if (xp != NULL) {
xp->xp_context = EXPAND_UNSUCCESSFUL;
+ }
return NULL;
}
/* The match we found may be followed immediately by a number. Move "p"
* back to point to it. */
- if (found || possible)
+ if (found || possible) {
return p + (matchlen - len);
+ }
return p;
}
static struct cmdmod {
- char *name;
+ char *name;
int minlen;
- int has_count; /* :123verbose :3tab */
+ int has_count; // :123verbose :3tab
} cmdmods[] = {
{ "aboveleft", 3, false },
{ "belowright", 3, false },
@@ -2788,7 +2836,7 @@ static struct cmdmod {
*/
int modifier_len(char_u *cmd)
{
- char_u *p = cmd;
+ char_u *p = cmd;
if (ascii_isdigit(*cmd)) {
p = skipwhite(skipdigits(cmd + 1));
@@ -2817,13 +2865,13 @@ int modifier_len(char_u *cmd)
int cmd_exists(const char *const name)
{
exarg_T ea;
- char_u *p;
+ char_u *p;
// Check command modifiers.
for (int i = 0; i < (int)ARRAY_SIZE(cmdmods); i++) {
int j;
for (j = 0; name[j] != NUL; j++) {
- if (name[j] != (char)cmdmods[i].name[j]) {
+ if (name[j] != cmdmods[i].name[j]) {
break;
}
}
@@ -2838,26 +2886,26 @@ int cmd_exists(const char *const name)
ea.cmdidx = (cmdidx_T)0;
int full = false;
p = find_command(&ea, &full);
- if (p == NULL)
+ if (p == NULL) {
return 3;
- if (ascii_isdigit(*name) && ea.cmdidx != CMD_match)
+ }
+ if (ascii_isdigit(*name) && ea.cmdidx != CMD_match) {
return 0;
- if (*skipwhite(p) != NUL)
- return 0; /* trailing garbage */
+ }
+ if (*skipwhite(p) != NUL) {
+ return 0; // trailing garbage
+ }
return ea.cmdidx == CMD_SIZE ? 0 : (full ? 2 : 1);
}
-/*
- * This is all pretty much copied from do_one_cmd(), with all the extra stuff
- * we don't need/want deleted. Maybe this could be done better if we didn't
- * repeat all this stuff. The only problem is that they may not stay
- * perfectly compatible with each other, but then the command line syntax
- * probably won't change that much -- webb.
- */
-const char * set_one_cmd_context(
- expand_T *xp,
- const char *buff // buffer for command string
-)
+/// This is all pretty much copied from do_one_cmd(), with all the extra stuff
+/// we don't need/want deleted. Maybe this could be done better if we didn't
+/// repeat all this stuff. The only problem is that they may not stay
+/// perfectly compatible with each other, but then the command line syntax
+/// probably won't change that much -- webb.
+///
+/// @param buff buffer for command string
+const char *set_one_cmd_context(expand_T *xp, const char *buff)
{
size_t len = 0;
exarg_T ea;
@@ -2876,9 +2924,10 @@ const char * set_one_cmd_context(
}
xp->xp_pattern = (char_u *)cmd;
- if (*cmd == NUL)
+ if (*cmd == NUL) {
return NULL;
- if (*cmd == '"') { /* ignore comment lines */
+ }
+ if (*cmd == '"') { // ignore comment lines
xp->xp_context = EXPAND_NOTHING;
return NULL;
}
@@ -2900,9 +2949,9 @@ const char * set_one_cmd_context(
return NULL;
}
- if (*cmd == '|' || *cmd == '\n')
- return cmd + 1; /* There's another command */
-
+ if (*cmd == '|' || *cmd == '\n') {
+ return cmd + 1; // There's another command
+ }
/*
* Isolate the command and search for it in the command table.
* Exceptions:
@@ -2942,7 +2991,7 @@ const char * set_one_cmd_context(
xp->xp_context = EXPAND_UNSUCCESSFUL;
return NULL;
}
- for (ea.cmdidx = (cmdidx_T)0; (int)ea.cmdidx < (int)CMD_SIZE;
+ for (ea.cmdidx = (cmdidx_T)0; (int)ea.cmdidx < CMD_SIZE;
ea.cmdidx = (cmdidx_T)((int)ea.cmdidx + 1)) {
if (STRNCMP(cmdnames[(int)ea.cmdidx].cmd_name, cmd, len) == 0) {
break;
@@ -2956,12 +3005,13 @@ const char * set_one_cmd_context(
}
}
- /*
- * If the cursor is touching the command, and it ends in an alpha-numeric
- * character, complete the command name.
- */
- if (*p == NUL && ASCII_ISALNUM(p[-1]))
+ //
+ // If the cursor is touching the command, and it ends in an alphanumeric
+ // character, complete the command name.
+ //
+ if (*p == NUL && ASCII_ISALNUM(p[-1])) {
return NULL;
+ }
if (ea.cmdidx == CMD_SIZE) {
if (*cmd == 's' && vim_strchr((const char_u *)"cgriI", cmd[1]) != NULL) {
@@ -2976,12 +3026,12 @@ const char * set_one_cmd_context(
}
}
if (ea.cmdidx == CMD_SIZE) {
- /* Not still touching the command and it was an illegal one */
+ // Not still touching the command and it was an illegal one
xp->xp_context = EXPAND_UNSUCCESSFUL;
return NULL;
}
- xp->xp_context = EXPAND_NOTHING; /* Default now that we're past command */
+ xp->xp_context = EXPAND_NOTHING; // Default now that we're past command
if (*p == '!') { // forced commands
forceit = true;
@@ -3054,9 +3104,10 @@ const char * set_one_cmd_context(
*/
if ((ea.argt & EX_TRLBAR) && !usefilter) {
p = arg;
- /* ":redir @" is not the start of a comment */
- if (ea.cmdidx == CMD_redir && p[0] == '@' && p[1] == '"')
+ // ":redir @" is not the start of a comment
+ if (ea.cmdidx == CMD_redir && p[0] == '@' && p[1] == '"') {
p += 2;
+ }
while (*p) {
if (*p == Ctrl_V) {
if (p[1] != NUL) {
@@ -3066,9 +3117,10 @@ const char * set_one_cmd_context(
|| *p == '|'
|| *p == '\n') {
if (*(p - 1) != '\\') {
- if (*p == '|' || *p == '\n')
+ if (*p == '|' || *p == '\n') {
return p + 1;
- return NULL; /* It's a comment */
+ }
+ return NULL; // It's a comment
}
}
MB_PTR_ADV(p);
@@ -3080,7 +3132,7 @@ const char * set_one_cmd_context(
return NULL;
}
- /* Find start of last argument (argument just before cursor): */
+ // Find start of last argument (argument just before cursor):
p = buff;
xp->xp_pattern = (char_u *)p;
len = strlen(buff);
@@ -3121,10 +3173,10 @@ const char * set_one_cmd_context(
/* An argument can contain just about everything, except
* characters that end the command and white space. */
else if (c == '|'
- || c == '\n'
- || c == '"'
- || ascii_iswhite(c)) {
- len = 0; /* avoid getting stuck when space is in 'isfname' */
+ || c == '\n'
+ || c == '"'
+ || ascii_iswhite(c)) {
+ len = 0; // avoid getting stuck when space is in 'isfname'
while (*p != NUL) {
c = utf_ptr2char((const char_u *)p);
if (c == '`' || vim_isfilec_or_wc(c)) {
@@ -3152,7 +3204,7 @@ const char * set_one_cmd_context(
}
xp->xp_context = EXPAND_FILES;
- /* For a shell command more chars need to be escaped. */
+ // For a shell command more chars need to be escaped.
if (usefilter || ea.cmdidx == CMD_bang || ea.cmdidx == CMD_terminal) {
#ifndef BACKSLASH_IN_FILENAME
xp->xp_shell = TRUE;
@@ -3179,7 +3231,7 @@ const char * set_one_cmd_context(
}
}
}
- /* Check for user names */
+ // Check for user names.
if (*xp->xp_pattern == '~') {
for (p = (const char *)xp->xp_pattern + 1; *p != NUL && *p != '/'; p++) {
}
@@ -3201,8 +3253,9 @@ const char * set_one_cmd_context(
case CMD_find:
case CMD_sfind:
case CMD_tabfind:
- if (xp->xp_context == EXPAND_FILES)
+ if (xp->xp_context == EXPAND_FILES) {
xp->xp_context = EXPAND_FILES_IN_PATH;
+ }
break;
case CMD_cd:
case CMD_chdir:
@@ -3267,7 +3320,7 @@ const char * set_one_cmd_context(
case CMD_match:
if (*arg == NUL || !ends_excmd(*arg)) {
- /* also complete "None" */
+ // also complete "None"
set_context_in_echohl_cmd(xp, arg);
arg = (const char *)skipwhite(skiptowhite((const char_u *)arg));
if (*arg != NUL) {
@@ -3283,7 +3336,7 @@ const char * set_one_cmd_context(
*/
case CMD_command:
- /* Check for attributes */
+ // Check for attributes
while (*arg == '-') {
arg++; // Skip "-".
p = (const char *)skiptowhite((const char_u *)arg);
@@ -3346,8 +3399,9 @@ const char * set_one_cmd_context(
}
arg++;
}
- if (arg[0] != NUL)
+ if (arg[0] != NUL) {
return arg + 1;
+ }
break;
}
case CMD_and:
@@ -3532,9 +3586,9 @@ const char * set_one_cmd_context(
} else if (context == EXPAND_COMMANDS) {
return arg;
} else if (context == EXPAND_MAPPINGS) {
- return (const char *)set_context_in_map_cmd(
- xp, (char_u *)"map", (char_u *)arg, forceit, false, false,
- CMD_map);
+ return (const char *)set_context_in_map_cmd(xp, (char_u *)"map", (char_u *)arg, forceit,
+ false, false,
+ CMD_map);
}
// Find start of last argument.
p = arg;
@@ -3552,17 +3606,26 @@ const char * set_one_cmd_context(
xp->xp_context = context;
}
break;
- case CMD_map: case CMD_noremap:
- case CMD_nmap: case CMD_nnoremap:
- case CMD_vmap: case CMD_vnoremap:
- case CMD_omap: case CMD_onoremap:
- case CMD_imap: case CMD_inoremap:
- case CMD_cmap: case CMD_cnoremap:
- case CMD_lmap: case CMD_lnoremap:
- case CMD_smap: case CMD_snoremap:
- case CMD_xmap: case CMD_xnoremap:
- return (const char *)set_context_in_map_cmd(
- xp, (char_u *)cmd, (char_u *)arg, forceit, false, false, ea.cmdidx);
+ case CMD_map:
+ case CMD_noremap:
+ case CMD_nmap:
+ case CMD_nnoremap:
+ case CMD_vmap:
+ case CMD_vnoremap:
+ case CMD_omap:
+ case CMD_onoremap:
+ case CMD_imap:
+ case CMD_inoremap:
+ case CMD_cmap:
+ case CMD_cnoremap:
+ case CMD_lmap:
+ case CMD_lnoremap:
+ case CMD_smap:
+ case CMD_snoremap:
+ case CMD_xmap:
+ case CMD_xnoremap:
+ return (const char *)set_context_in_map_cmd(xp, (char_u *)cmd, (char_u *)arg, forceit, false,
+ false, ea.cmdidx);
case CMD_unmap:
case CMD_nunmap:
case CMD_vunmap:
@@ -3572,8 +3635,8 @@ const char * set_one_cmd_context(
case CMD_lunmap:
case CMD_sunmap:
case CMD_xunmap:
- return (const char *)set_context_in_map_cmd(
- xp, (char_u *)cmd, (char_u *)arg, forceit, false, true, ea.cmdidx);
+ return (const char *)set_context_in_map_cmd(xp, (char_u *)cmd, (char_u *)arg, forceit, false,
+ true, ea.cmdidx);
case CMD_mapclear:
case CMD_nmapclear:
case CMD_vmapclear:
@@ -3587,27 +3650,45 @@ const char * set_one_cmd_context(
xp->xp_pattern = (char_u *)arg;
break;
- case CMD_abbreviate: case CMD_noreabbrev:
- case CMD_cabbrev: case CMD_cnoreabbrev:
- case CMD_iabbrev: case CMD_inoreabbrev:
- return (const char *)set_context_in_map_cmd(
- xp, (char_u *)cmd, (char_u *)arg, forceit, true, false, ea.cmdidx);
+ case CMD_abbreviate:
+ case CMD_noreabbrev:
+ case CMD_cabbrev:
+ case CMD_cnoreabbrev:
+ case CMD_iabbrev:
+ case CMD_inoreabbrev:
+ return (const char *)set_context_in_map_cmd(xp, (char_u *)cmd, (char_u *)arg, forceit, true,
+ false, ea.cmdidx);
case CMD_unabbreviate:
case CMD_cunabbrev:
case CMD_iunabbrev:
- return (const char *)set_context_in_map_cmd(
- xp, (char_u *)cmd, (char_u *)arg, forceit, true, true, ea.cmdidx);
- case CMD_menu: case CMD_noremenu: case CMD_unmenu:
- case CMD_amenu: case CMD_anoremenu: case CMD_aunmenu:
- case CMD_nmenu: case CMD_nnoremenu: case CMD_nunmenu:
- case CMD_vmenu: case CMD_vnoremenu: case CMD_vunmenu:
- case CMD_omenu: case CMD_onoremenu: case CMD_ounmenu:
- case CMD_imenu: case CMD_inoremenu: case CMD_iunmenu:
- case CMD_cmenu: case CMD_cnoremenu: case CMD_cunmenu:
- case CMD_tmenu: case CMD_tunmenu:
- case CMD_popup: case CMD_emenu:
- return (const char *)set_context_in_menu_cmd(
- xp, cmd, (char_u *)arg, forceit);
+ return (const char *)set_context_in_map_cmd(xp, (char_u *)cmd, (char_u *)arg, forceit, true,
+ true, ea.cmdidx);
+ case CMD_menu:
+ case CMD_noremenu:
+ case CMD_unmenu:
+ case CMD_amenu:
+ case CMD_anoremenu:
+ case CMD_aunmenu:
+ case CMD_nmenu:
+ case CMD_nnoremenu:
+ case CMD_nunmenu:
+ case CMD_vmenu:
+ case CMD_vnoremenu:
+ case CMD_vunmenu:
+ case CMD_omenu:
+ case CMD_onoremenu:
+ case CMD_ounmenu:
+ case CMD_imenu:
+ case CMD_inoremenu:
+ case CMD_iunmenu:
+ case CMD_cmenu:
+ case CMD_cnoremenu:
+ case CMD_cunmenu:
+ case CMD_tmenu:
+ case CMD_tunmenu:
+ case CMD_popup:
+ case CMD_emenu:
+ return (const char *)set_context_in_menu_cmd(xp, cmd, (char_u *)arg, forceit);
case CMD_colorscheme:
xp->xp_context = EXPAND_COLORS;
@@ -3697,17 +3778,17 @@ const char * set_one_cmd_context(
return NULL;
}
-// Skip a range specifier of the form: addr [,addr] [;addr] ..
-//
-// Backslashed delimiters after / or ? will be skipped, and commands will
-// not be expanded between /'s and ?'s or after "'".
-//
-// Also skip white space and ":" characters.
-// Returns the "cmd" pointer advanced to beyond the range.
-char_u *skip_range(
- const char_u *cmd,
- int *ctx // pointer to xp_context or NULL
-)
+/// Skip a range specifier of the form: addr [,addr] [;addr] ..
+///
+/// Backslashed delimiters after / or ? will be skipped, and commands will
+/// not be expanded between /'s and ?'s or after "'".
+///
+/// Also skip white space and ":" characters.
+///
+/// @param ctx pointer to xp_context or NULL
+///
+/// @return the "cmd" pointer advanced to beyond the range.
+char_u *skip_range(const char_u *cmd, int *ctx)
{
unsigned delim;
@@ -3724,14 +3805,18 @@ char_u *skip_range(
}
} else if (*cmd == '/' || *cmd == '?') {
delim = *cmd++;
- while (*cmd != NUL && *cmd != delim)
- if (*cmd++ == '\\' && *cmd != NUL)
+ while (*cmd != NUL && *cmd != delim) {
+ if (*cmd++ == '\\' && *cmd != NUL) {
++cmd;
- if (*cmd == NUL && ctx != NULL)
+ }
+ }
+ if (*cmd == NUL && ctx != NULL) {
*ctx = EXPAND_NOTHING;
+ }
}
- if (*cmd != NUL)
+ if (*cmd != NUL) {
++cmd;
+ }
}
// Skip ":" and white space.
@@ -3749,28 +3834,28 @@ static void addr_error(cmd_addr_T addr_type)
}
}
-// Get a single EX address
-//
-// Set ptr to the next character after the part that was interpreted.
-// Set ptr to NULL when an error is encountered.
-// This may set the last used search pattern.
-//
-// Return MAXLNUM when no Ex address was found.
-static linenr_T get_address(exarg_T *eap,
- char_u **ptr,
- cmd_addr_T addr_type,
- int skip, // only skip the address, don't use it
- bool silent, // no errors or side effects
- int to_other_file, // flag: may jump to other file
- int address_count) // 1 for first, >1 after comma
+/// Get a single EX address
+///
+/// Set ptr to the next character after the part that was interpreted.
+/// Set ptr to NULL when an error is encountered.
+/// This may set the last used search pattern.
+///
+/// @param skip only skip the address, don't use it
+/// @param silent no errors or side effects
+/// @param to_other_file flag: may jump to other file
+/// @param address_count 1 for first, >1 after comma
+///
+/// @return MAXLNUM when no Ex address was found.
+static linenr_T get_address(exarg_T *eap, char_u **ptr, cmd_addr_T addr_type, int skip, bool silent,
+ int to_other_file, int address_count)
FUNC_ATTR_NONNULL_ALL
{
int c;
int i;
long n;
- char_u *cmd;
+ char_u *cmd;
pos_T pos;
- pos_T *fp;
+ pos_T *fp;
linenr_T lnum;
buf_T *buf;
@@ -3778,94 +3863,94 @@ static linenr_T get_address(exarg_T *eap,
lnum = MAXLNUM;
do {
switch (*cmd) {
- case '.': /* '.' - Cursor position */
+ case '.': // '.' - Cursor position
++cmd;
switch (addr_type) {
- case ADDR_LINES:
- case ADDR_OTHER:
- lnum = curwin->w_cursor.lnum;
- break;
- case ADDR_WINDOWS:
- lnum = CURRENT_WIN_NR;
- break;
- case ADDR_ARGUMENTS:
- lnum = curwin->w_arg_idx + 1;
- break;
- case ADDR_LOADED_BUFFERS:
- case ADDR_BUFFERS:
- lnum = curbuf->b_fnum;
- break;
- case ADDR_TABS:
- lnum = CURRENT_TAB_NR;
- break;
- case ADDR_NONE:
- case ADDR_TABS_RELATIVE:
- case ADDR_UNSIGNED:
- addr_error(addr_type);
- cmd = NULL;
- goto error;
- break;
- case ADDR_QUICKFIX:
- lnum = qf_get_cur_idx(eap);
- break;
- case ADDR_QUICKFIX_VALID:
- lnum = qf_get_cur_valid_idx(eap);
- break;
+ case ADDR_LINES:
+ case ADDR_OTHER:
+ lnum = curwin->w_cursor.lnum;
+ break;
+ case ADDR_WINDOWS:
+ lnum = CURRENT_WIN_NR;
+ break;
+ case ADDR_ARGUMENTS:
+ lnum = curwin->w_arg_idx + 1;
+ break;
+ case ADDR_LOADED_BUFFERS:
+ case ADDR_BUFFERS:
+ lnum = curbuf->b_fnum;
+ break;
+ case ADDR_TABS:
+ lnum = CURRENT_TAB_NR;
+ break;
+ case ADDR_NONE:
+ case ADDR_TABS_RELATIVE:
+ case ADDR_UNSIGNED:
+ addr_error(addr_type);
+ cmd = NULL;
+ goto error;
+ break;
+ case ADDR_QUICKFIX:
+ lnum = qf_get_cur_idx(eap);
+ break;
+ case ADDR_QUICKFIX_VALID:
+ lnum = qf_get_cur_valid_idx(eap);
+ break;
}
break;
- case '$': /* '$' - last line */
+ case '$': // '$' - last line
++cmd;
switch (addr_type) {
- case ADDR_LINES:
- case ADDR_OTHER:
- lnum = curbuf->b_ml.ml_line_count;
- break;
- case ADDR_WINDOWS:
- lnum = LAST_WIN_NR;
- break;
- case ADDR_ARGUMENTS:
- lnum = ARGCOUNT;
- break;
- case ADDR_LOADED_BUFFERS:
- buf = lastbuf;
- while (buf->b_ml.ml_mfp == NULL) {
- if (buf->b_prev == NULL) {
- break;
- }
- buf = buf->b_prev;
- }
- lnum = buf->b_fnum;
- break;
- case ADDR_BUFFERS:
- lnum = lastbuf->b_fnum;
- break;
- case ADDR_TABS:
- lnum = LAST_TAB_NR;
- break;
- case ADDR_NONE:
- case ADDR_TABS_RELATIVE:
- case ADDR_UNSIGNED:
- addr_error(addr_type);
- cmd = NULL;
- goto error;
- break;
- case ADDR_QUICKFIX:
- lnum = qf_get_size(eap);
- if (lnum == 0) {
- lnum = 1;
- }
- break;
- case ADDR_QUICKFIX_VALID:
- lnum = qf_get_valid_size(eap);
- if (lnum == 0) {
- lnum = 1;
+ case ADDR_LINES:
+ case ADDR_OTHER:
+ lnum = curbuf->b_ml.ml_line_count;
+ break;
+ case ADDR_WINDOWS:
+ lnum = LAST_WIN_NR;
+ break;
+ case ADDR_ARGUMENTS:
+ lnum = ARGCOUNT;
+ break;
+ case ADDR_LOADED_BUFFERS:
+ buf = lastbuf;
+ while (buf->b_ml.ml_mfp == NULL) {
+ if (buf->b_prev == NULL) {
+ break;
}
- break;
+ buf = buf->b_prev;
+ }
+ lnum = buf->b_fnum;
+ break;
+ case ADDR_BUFFERS:
+ lnum = lastbuf->b_fnum;
+ break;
+ case ADDR_TABS:
+ lnum = LAST_TAB_NR;
+ break;
+ case ADDR_NONE:
+ case ADDR_TABS_RELATIVE:
+ case ADDR_UNSIGNED:
+ addr_error(addr_type);
+ cmd = NULL;
+ goto error;
+ break;
+ case ADDR_QUICKFIX:
+ lnum = qf_get_size(eap);
+ if (lnum == 0) {
+ lnum = 1;
+ }
+ break;
+ case ADDR_QUICKFIX_VALID:
+ lnum = qf_get_valid_size(eap);
+ if (lnum == 0) {
+ lnum = 1;
+ }
+ break;
}
break;
- case '\'': /* ''' - mark */
+ case '\'': // ''' - mark
if (*++cmd == NUL) {
cmd = NULL;
goto error;
@@ -3875,17 +3960,17 @@ static linenr_T get_address(exarg_T *eap,
cmd = NULL;
goto error;
}
- if (skip)
+ if (skip) {
++cmd;
- else {
+ } else {
/* Only accept a mark in another file when it is
* used by itself: ":'M". */
fp = getmark(*cmd, to_other_file && cmd[1] == NUL);
++cmd;
- if (fp == (pos_T *)-1)
- /* Jumped to another file. */
+ if (fp == (pos_T *)-1) {
+ // Jumped to another file.
lnum = curwin->w_cursor.lnum;
- else {
+ } else {
if (check_mark(fp) == FAIL) {
cmd = NULL;
goto error;
@@ -3896,17 +3981,18 @@ static linenr_T get_address(exarg_T *eap,
break;
case '/':
- case '?': /* '/' or '?' - search */
+ case '?': // '/' or '?' - search
c = *cmd++;
if (addr_type != ADDR_LINES) {
addr_error(addr_type);
cmd = NULL;
goto error;
}
- if (skip) { /* skip "/pat/" */
+ if (skip) { // skip "/pat/"
cmd = skip_regexp(cmd, c, p_magic, NULL);
- if (*cmd == c)
+ if (*cmd == c) {
++cmd;
+ }
} else {
int flags;
@@ -3938,23 +4024,23 @@ static linenr_T get_address(exarg_T *eap,
}
lnum = curwin->w_cursor.lnum;
curwin->w_cursor = pos;
- /* adjust command string pointer */
+ // adjust command string pointer
cmd += searchcmdlen;
}
break;
- case '\\': /* "\?", "\/" or "\&", repeat search */
+ case '\\': // "\?", "\/" or "\&", repeat search
++cmd;
if (addr_type != ADDR_LINES) {
addr_error(addr_type);
cmd = NULL;
goto error;
}
- if (*cmd == '&')
+ if (*cmd == '&') {
i = RE_SUBST;
- else if (*cmd == '?' || *cmd == '/')
+ } else if (*cmd == '?' || *cmd == '/') {
i = RE_SEARCH;
- else {
+ } else {
EMSG(_(e_backslash));
cmd = NULL;
goto error;
@@ -3992,37 +4078,37 @@ static linenr_T get_address(exarg_T *eap,
if (lnum == MAXLNUM) {
switch (addr_type) {
- case ADDR_LINES:
- case ADDR_OTHER:
- // "+1" is same as ".+1"
- lnum = curwin->w_cursor.lnum;
- break;
- case ADDR_WINDOWS:
- lnum = CURRENT_WIN_NR;
- break;
- case ADDR_ARGUMENTS:
- lnum = curwin->w_arg_idx + 1;
- break;
- case ADDR_LOADED_BUFFERS:
- case ADDR_BUFFERS:
- lnum = curbuf->b_fnum;
- break;
- case ADDR_TABS:
- lnum = CURRENT_TAB_NR;
- break;
- case ADDR_TABS_RELATIVE:
- lnum = 1;
- break;
- case ADDR_QUICKFIX:
- lnum = qf_get_cur_idx(eap);
- break;
- case ADDR_QUICKFIX_VALID:
- lnum = qf_get_cur_valid_idx(eap);
- break;
- case ADDR_NONE:
- case ADDR_UNSIGNED:
- lnum = 0;
- break;
+ case ADDR_LINES:
+ case ADDR_OTHER:
+ // "+1" is same as ".+1"
+ lnum = curwin->w_cursor.lnum;
+ break;
+ case ADDR_WINDOWS:
+ lnum = CURRENT_WIN_NR;
+ break;
+ case ADDR_ARGUMENTS:
+ lnum = curwin->w_arg_idx + 1;
+ break;
+ case ADDR_LOADED_BUFFERS:
+ case ADDR_BUFFERS:
+ lnum = curbuf->b_fnum;
+ break;
+ case ADDR_TABS:
+ lnum = CURRENT_TAB_NR;
+ break;
+ case ADDR_TABS_RELATIVE:
+ lnum = 1;
+ break;
+ case ADDR_QUICKFIX:
+ lnum = qf_get_cur_idx(eap);
+ break;
+ case ADDR_QUICKFIX_VALID:
+ lnum = qf_get_cur_valid_idx(eap);
+ break;
+ case ADDR_NONE:
+ case ADDR_UNSIGNED:
+ lnum = 0;
+ break;
}
}
@@ -4042,8 +4128,7 @@ static linenr_T get_address(exarg_T *eap,
cmd = NULL;
goto error;
} else if (addr_type == ADDR_LOADED_BUFFERS || addr_type == ADDR_BUFFERS) {
- lnum = compute_buffer_local_count(
- addr_type, lnum, (i == '-') ? -1 * n : n);
+ lnum = compute_buffer_local_count(addr_type, lnum, (i == '-') ? -1 * n : n);
} else {
// Relative line addressing, need to adjust for folded lines
// now, but only do it after the first address.
@@ -4071,12 +4156,13 @@ error:
static void get_flags(exarg_T *eap)
{
while (vim_strchr((char_u *)"lp#", *eap->arg) != NULL) {
- if (*eap->arg == 'l')
+ if (*eap->arg == 'l') {
eap->flags |= EXFLAG_LIST;
- else if (*eap->arg == 'p')
+ } else if (*eap->arg == 'p') {
eap->flags |= EXFLAG_PRINT;
- else
+ } else {
eap->flags |= EXFLAG_NR;
+ }
eap->arg = skipwhite(eap->arg + 1);
}
}
@@ -4084,9 +4170,9 @@ static void get_flags(exarg_T *eap)
/// Stub function for command which is Not Implemented. NI!
void ex_ni(exarg_T *eap)
{
- if (!eap->skip)
- eap->errmsg = (char_u *)N_(
- "E319: The command is not available in this version");
+ if (!eap->skip) {
+ eap->errmsg = (char_u *)N_("E319: The command is not available in this version");
+ }
}
/// Stub function for script command which is Not Implemented. NI!
@@ -4114,77 +4200,77 @@ static char_u *invalid_range(exarg_T *eap)
if (eap->argt & EX_RANGE) {
switch (eap->addr_type) {
- case ADDR_LINES:
- if (eap->line2 > (curbuf->b_ml.ml_line_count
- + (eap->cmdidx == CMD_diffget))) {
- return (char_u *)_(e_invrange);
- }
- break;
- case ADDR_ARGUMENTS:
- // add 1 if ARGCOUNT is 0
- if (eap->line2 > ARGCOUNT + (!ARGCOUNT)) {
- return (char_u *)_(e_invrange);
- }
- break;
- case ADDR_BUFFERS:
- if (eap->line1 < firstbuf->b_fnum
- || eap->line2 > lastbuf->b_fnum) {
- return (char_u *)_(e_invrange);
- }
- break;
- case ADDR_LOADED_BUFFERS:
- buf = firstbuf;
- while (buf->b_ml.ml_mfp == NULL) {
- if (buf->b_next == NULL) {
- return (char_u *)_(e_invrange);
- }
- buf = buf->b_next;
- }
- if (eap->line1 < buf->b_fnum) {
- return (char_u *)_(e_invrange);
- }
- buf = lastbuf;
- while (buf->b_ml.ml_mfp == NULL) {
- if (buf->b_prev == NULL) {
- return (char_u *)_(e_invrange);
- }
- buf = buf->b_prev;
- }
- if (eap->line2 > buf->b_fnum) {
- return (char_u *)_(e_invrange);
- }
- break;
- case ADDR_WINDOWS:
- if (eap->line2 > LAST_WIN_NR) {
- return (char_u *)_(e_invrange);
- }
- break;
- case ADDR_TABS:
- if (eap->line2 > LAST_TAB_NR) {
- return (char_u *)_(e_invrange);
- }
- break;
- case ADDR_TABS_RELATIVE:
- case ADDR_OTHER:
- // Any range is OK.
- break;
- case ADDR_QUICKFIX:
- assert(eap->line2 >= 0);
- // No error for value that is too big, will use the last entry.
- if (eap->line2 <= 0) {
+ case ADDR_LINES:
+ if (eap->line2 > (curbuf->b_ml.ml_line_count
+ + (eap->cmdidx == CMD_diffget))) {
+ return (char_u *)_(e_invrange);
+ }
+ break;
+ case ADDR_ARGUMENTS:
+ // add 1 if ARGCOUNT is 0
+ if (eap->line2 > ARGCOUNT + (!ARGCOUNT)) {
+ return (char_u *)_(e_invrange);
+ }
+ break;
+ case ADDR_BUFFERS:
+ if (eap->line1 < firstbuf->b_fnum
+ || eap->line2 > lastbuf->b_fnum) {
+ return (char_u *)_(e_invrange);
+ }
+ break;
+ case ADDR_LOADED_BUFFERS:
+ buf = firstbuf;
+ while (buf->b_ml.ml_mfp == NULL) {
+ if (buf->b_next == NULL) {
return (char_u *)_(e_invrange);
}
- break;
- case ADDR_QUICKFIX_VALID:
- if ((eap->line2 != 1 && (size_t)eap->line2 > qf_get_valid_size(eap))
- || eap->line2 < 0) {
+ buf = buf->b_next;
+ }
+ if (eap->line1 < buf->b_fnum) {
+ return (char_u *)_(e_invrange);
+ }
+ buf = lastbuf;
+ while (buf->b_ml.ml_mfp == NULL) {
+ if (buf->b_prev == NULL) {
return (char_u *)_(e_invrange);
}
- break;
- case ADDR_UNSIGNED:
- case ADDR_NONE:
- // Will give an error elsewhere.
- break;
+ buf = buf->b_prev;
+ }
+ if (eap->line2 > buf->b_fnum) {
+ return (char_u *)_(e_invrange);
+ }
+ break;
+ case ADDR_WINDOWS:
+ if (eap->line2 > LAST_WIN_NR) {
+ return (char_u *)_(e_invrange);
+ }
+ break;
+ case ADDR_TABS:
+ if (eap->line2 > LAST_TAB_NR) {
+ return (char_u *)_(e_invrange);
+ }
+ break;
+ case ADDR_TABS_RELATIVE:
+ case ADDR_OTHER:
+ // Any range is OK.
+ break;
+ case ADDR_QUICKFIX:
+ assert(eap->line2 >= 0);
+ // No error for value that is too big, will use the last entry.
+ if (eap->line2 <= 0) {
+ return (char_u *)_(e_invrange);
+ }
+ break;
+ case ADDR_QUICKFIX_VALID:
+ if ((eap->line2 != 1 && (size_t)eap->line2 > qf_get_valid_size(eap))
+ || eap->line2 < 0) {
+ return (char_u *)_(e_invrange);
+ }
+ break;
+ case ADDR_UNSIGNED:
+ case ADDR_NONE:
+ // Will give an error elsewhere.
+ break;
}
}
return NULL;
@@ -4212,15 +4298,16 @@ static void correct_range(exarg_T *eap)
*/
static char_u *skip_grep_pat(exarg_T *eap)
{
- char_u *p = eap->arg;
+ char_u *p = eap->arg;
if (*p != NUL && (eap->cmdidx == CMD_vimgrep || eap->cmdidx == CMD_lvimgrep
|| eap->cmdidx == CMD_vimgrepadd
|| eap->cmdidx == CMD_lvimgrepadd
|| grep_internal(eap->cmdidx))) {
p = skip_vimgrep_pat(p, NULL, NULL);
- if (p == NULL)
+ if (p == NULL) {
p = eap->arg;
+ }
}
return p;
}
@@ -4231,10 +4318,10 @@ static char_u *skip_grep_pat(exarg_T *eap)
*/
static char_u *replace_makeprg(exarg_T *eap, char_u *p, char_u **cmdlinep)
{
- char_u *new_cmdline;
- char_u *program;
- char_u *pos;
- char_u *ptr;
+ char_u *new_cmdline;
+ char_u *program;
+ char_u *pos;
+ char_u *ptr;
int len;
int i;
@@ -4248,24 +4335,27 @@ static char_u *replace_makeprg(exarg_T *eap, char_u *p, char_u **cmdlinep)
&& !grep_internal(eap->cmdidx)) {
if (eap->cmdidx == CMD_grep || eap->cmdidx == CMD_lgrep
|| eap->cmdidx == CMD_grepadd || eap->cmdidx == CMD_lgrepadd) {
- if (*curbuf->b_p_gp == NUL)
+ if (*curbuf->b_p_gp == NUL) {
program = p_gp;
- else
+ } else {
program = curbuf->b_p_gp;
+ }
} else {
- if (*curbuf->b_p_mp == NUL)
+ if (*curbuf->b_p_mp == NUL) {
program = p_mp;
- else
+ } else {
program = curbuf->b_p_mp;
+ }
}
p = skipwhite(p);
if ((pos = (char_u *)strstr((char *)program, "$*")) != NULL) {
- /* replace $* by given arguments */
+ // replace $* by given arguments
i = 1;
- while ((pos = (char_u *)strstr((char *)pos + 2, "$*")) != NULL)
+ while ((pos = (char_u *)strstr((char *)pos + 2, "$*")) != NULL) {
++i;
+ }
len = (int)STRLEN(p);
new_cmdline = xmalloc(STRLEN(program) + i * (len - 2) + 1);
ptr = new_cmdline;
@@ -4285,7 +4375,7 @@ static char_u *replace_makeprg(exarg_T *eap, char_u *p, char_u **cmdlinep)
}
msg_make(p);
- /* 'eap->cmd' is not set here, because it is not used at CMD_make */
+ // 'eap->cmd' is not set here, because it is not used at CMD_make
xfree(*cmdlinep);
*cmdlinep = new_cmdline;
p = new_cmdline;
@@ -4298,13 +4388,13 @@ static char_u *replace_makeprg(exarg_T *eap, char_u *p, char_u **cmdlinep)
// Return FAIL for failure, OK otherwise.
int expand_filename(exarg_T *eap, char_u **cmdlinep, char_u **errormsgp)
{
- int has_wildcards; /* need to expand wildcards */
- char_u *repl;
+ int has_wildcards; // need to expand wildcards
+ char_u *repl;
size_t srclen;
- char_u *p;
+ char_u *p;
int escaped;
- /* Skip a regexp pattern for ":vimgrep[add] pat file..." */
+ // Skip a regexp pattern for ":vimgrep[add] pat file..."
p = skip_grep_pat(eap);
/*
@@ -4314,12 +4404,13 @@ int expand_filename(exarg_T *eap, char_u **cmdlinep, char_u **errormsgp)
*/
has_wildcards = path_has_wildcard(p);
while (*p != NUL) {
- /* Skip over `=expr`, wildcards in it are not expanded. */
+ // Skip over `=expr`, wildcards in it are not expanded.
if (p[0] == '`' && p[1] == '=') {
p += 2;
(void)skip_expr(&p);
- if (*p == '`')
+ if (*p == '`') {
++p;
+ }
continue;
}
/*
@@ -4335,10 +4426,11 @@ int expand_filename(exarg_T *eap, char_u **cmdlinep, char_u **errormsgp)
* Try to find a match at this position.
*/
repl = eval_vars(p, eap->arg, &srclen, &(eap->do_ecmd_lnum),
- errormsgp, &escaped);
- if (*errormsgp != NULL) /* error detected */
+ errormsgp, &escaped);
+ if (*errormsgp != NULL) { // error detected
return FAIL;
- if (repl == NULL) { /* no match found */
+ }
+ if (repl == NULL) { // no match found
p += srclen;
continue;
}
@@ -4368,9 +4460,8 @@ int expand_filename(exarg_T *eap, char_u **cmdlinep, char_u **errormsgp)
&& eap->cmdidx != CMD_lmake
&& eap->cmdidx != CMD_make
&& eap->cmdidx != CMD_terminal
- && !(eap->argt & EX_NOSPC)
- ) {
- char_u *l;
+ && !(eap->argt & EX_NOSPC)) {
+ char_u *l;
#ifdef BACKSLASH_IN_FILENAME
/* Don't escape a backslash here, because rem_backslash() doesn't
* remove it later. */
@@ -4380,13 +4471,14 @@ int expand_filename(exarg_T *eap, char_u **cmdlinep, char_u **errormsgp)
# define ESCAPE_CHARS escape_chars
#endif
- for (l = repl; *l; ++l)
+ for (l = repl; *l; ++l) {
if (vim_strchr(ESCAPE_CHARS, *l) != NULL) {
l = vim_strsave_escaped(repl, ESCAPE_CHARS);
xfree(repl);
repl = l;
break;
}
+ }
}
// For a shell command a '!' must be escaped.
@@ -4394,7 +4486,7 @@ int expand_filename(exarg_T *eap, char_u **cmdlinep, char_u **errormsgp)
|| eap->cmdidx == CMD_bang
|| eap->cmdidx == CMD_terminal)
&& vim_strpbrk(repl, (char_u *)"!") != NULL) {
- char_u *l;
+ char_u *l;
l = vim_strsave_escaped(repl, (char_u *)"!");
xfree(repl);
@@ -4421,12 +4513,12 @@ int expand_filename(exarg_T *eap, char_u **cmdlinep, char_u **errormsgp)
*/
if (vim_strchr(eap->arg, '$') != NULL
|| vim_strchr(eap->arg, '~') != NULL) {
- expand_env_esc(eap->arg, NameBuff, MAXPATHL,
- TRUE, TRUE, NULL);
+ expand_env_esc(eap->arg, NameBuff, MAXPATHL, true, true, NULL);
has_wildcards = path_has_wildcard(NameBuff);
p = NameBuff;
- } else
+ } else {
p = NULL;
+ }
if (p != NULL) {
(void)repl_cmdline(eap, eap->arg, STRLEN(eap->arg), p, cmdlinep);
}
@@ -4448,8 +4540,9 @@ int expand_filename(exarg_T *eap, char_u **cmdlinep, char_u **errormsgp)
ExpandInit(&xpc);
xpc.xp_context = EXPAND_FILES;
- if (p_wic)
+ if (p_wic) {
options += WILD_ICASE;
+ }
p = ExpandOne(&xpc, eap->arg, NULL, options, WILD_EXPAND_FREE);
if (p == NULL) {
return FAIL;
@@ -4468,8 +4561,8 @@ int expand_filename(exarg_T *eap, char_u **cmdlinep, char_u **errormsgp)
* "repl" is the replacement string.
* Returns a pointer to the character after the replaced string.
*/
-static char_u *repl_cmdline(exarg_T *eap, char_u *src, size_t srclen,
- char_u *repl, char_u **cmdlinep)
+static char_u *repl_cmdline(exarg_T *eap, char_u *src, size_t srclen, char_u *repl,
+ char_u **cmdlinep)
{
/*
* The new command line is build in new_cmdline[].
@@ -4478,8 +4571,9 @@ static char_u *repl_cmdline(exarg_T *eap, char_u *src, size_t srclen,
*/
size_t len = STRLEN(repl);
size_t i = (size_t)(src - *cmdlinep) + STRLEN(src + srclen) + len + 3;
- if (eap->nextcmd != NULL)
- i += STRLEN(eap->nextcmd); /* add space for next command */
+ if (eap->nextcmd != NULL) {
+ i += STRLEN(eap->nextcmd); // add space for next command
+ }
char_u *new_cmdline = xmalloc(i);
/*
@@ -4488,23 +4582,24 @@ static char_u *repl_cmdline(exarg_T *eap, char_u *src, size_t srclen,
* Copy what came after the expanded part.
* Copy the next commands, if there are any.
*/
- i = (size_t)(src - *cmdlinep); /* length of part before match */
+ i = (size_t)(src - *cmdlinep); // length of part before match
memmove(new_cmdline, *cmdlinep, i);
memmove(new_cmdline + i, repl, len);
- i += len; /* remember the end of the string */
+ i += len; // remember the end of the string
STRCPY(new_cmdline + i, src + srclen);
- src = new_cmdline + i; /* remember where to continue */
+ src = new_cmdline + i; // remember where to continue
- if (eap->nextcmd != NULL) { /* append next command */
+ if (eap->nextcmd != NULL) { // append next command
i = STRLEN(new_cmdline) + 1;
STRCPY(new_cmdline + i, eap->nextcmd);
eap->nextcmd = new_cmdline + i;
}
eap->cmd = new_cmdline + (eap->cmd - *cmdlinep);
eap->arg = new_cmdline + (eap->arg - *cmdlinep);
- if (eap->do_ecmd_cmd != NULL && eap->do_ecmd_cmd != dollar_command)
+ if (eap->do_ecmd_cmd != NULL && eap->do_ecmd_cmd != dollar_command) {
eap->do_ecmd_cmd = new_cmdline + (eap->do_ecmd_cmd - *cmdlinep);
+ }
xfree(*cmdlinep);
*cmdlinep = new_cmdline;
@@ -4516,7 +4611,7 @@ static char_u *repl_cmdline(exarg_T *eap, char_u *src, size_t srclen,
*/
void separate_nextcmd(exarg_T *eap)
{
- char_u *p;
+ char_u *p;
p = skip_grep_pat(eap);
@@ -4539,16 +4634,16 @@ void separate_nextcmd(exarg_T *eap)
break;
}
} else if (
- // Check for '"': start of comment or '|': next command */
- // :@" does not start a comment!
- // :redir @" doesn't either.
- (*p == '"'
- && !(eap->argt & EX_NOTRLCOM)
- && (eap->cmdidx != CMD_at || p != eap->arg)
- && (eap->cmdidx != CMD_redir
- || p != eap->arg + 1 || p[-1] != '@'))
- || *p == '|'
- || *p == '\n') {
+ // Check for '"': start of comment or '|': next command */
+ // :@" does not start a comment!
+ // :redir @" doesn't either.
+ (*p == '"'
+ && !(eap->argt & EX_NOTRLCOM)
+ && (eap->cmdidx != CMD_at || p != eap->arg)
+ && (eap->cmdidx != CMD_redir
+ || p != eap->arg + 1 || p[-1] != '@'))
+ || *p == '|'
+ || *p == '\n') {
// We remove the '\' before the '|', unless EX_CTRLV is used
// AND 'b' is present in 'cpoptions'.
if ((vim_strchr(p_cpo, CPO_BAR) == NULL
@@ -4576,38 +4671,36 @@ static char_u *getargcmd(char_u **argp)
char_u *arg = *argp;
char_u *command = NULL;
- if (*arg == '+') { /* +[command] */
+ if (*arg == '+') { // +[command]
++arg;
- if (ascii_isspace(*arg) || *arg == '\0')
+ if (ascii_isspace(*arg) || *arg == '\0') {
command = dollar_command;
- else {
+ } else {
command = arg;
arg = skip_cmd_arg(command, TRUE);
- if (*arg != NUL)
- *arg++ = NUL; /* terminate command with NUL */
+ if (*arg != NUL) {
+ *arg++ = NUL; // terminate command with NUL
+ }
}
- arg = skipwhite(arg); /* skip over spaces */
+ arg = skipwhite(arg); // skip over spaces
*argp = arg;
}
return command;
}
-/*
- * Find end of "+command" argument. Skip over "\ " and "\\".
- */
-static char_u *
-skip_cmd_arg (
- char_u *p,
- int rembs /* TRUE to halve the number of backslashes */
-)
+/// Find end of "+command" argument. Skip over "\ " and "\\".
+///
+/// @param rembs TRUE to halve the number of backslashes
+static char_u *skip_cmd_arg(char_u *p, int rembs)
{
while (*p && !ascii_isspace(*p)) {
if (*p == '\\' && p[1] != NUL) {
- if (rembs)
+ if (rembs) {
STRMOVE(p, p + 1);
- else
+ } else {
++p;
+ }
}
MB_PTR_ADV(p);
}
@@ -4635,25 +4728,27 @@ int get_bad_opt(const char_u *p, exarg_T *eap)
*/
static int getargopt(exarg_T *eap)
{
- char_u *arg = eap->arg + 2;
- int *pp = NULL;
+ char_u *arg = eap->arg + 2;
+ int *pp = NULL;
int bad_char_idx;
- char_u *p;
+ char_u *p;
- /* ":edit ++[no]bin[ary] file" */
+ // ":edit ++[no]bin[ary] file"
if (STRNCMP(arg, "bin", 3) == 0 || STRNCMP(arg, "nobin", 5) == 0) {
if (*arg == 'n') {
arg += 2;
eap->force_bin = FORCE_NOBIN;
- } else
+ } else {
eap->force_bin = FORCE_BIN;
- if (!checkforcmd(&arg, "binary", 3))
+ }
+ if (!checkforcmd(&arg, "binary", 3)) {
return FAIL;
+ }
eap->arg = skipwhite(arg);
return OK;
}
- /* ":read ++edit file" */
+ // ":read ++edit file"
if (STRNCMP(arg, "edit", 4) == 0) {
eap->read_edit = TRUE;
eap->arg = skipwhite(arg + 4);
@@ -4667,18 +4762,20 @@ static int getargopt(exarg_T *eap)
arg += 10;
pp = &eap->force_ff;
} else if (STRNCMP(arg, "enc", 3) == 0) {
- if (STRNCMP(arg, "encoding", 8) == 0)
+ if (STRNCMP(arg, "encoding", 8) == 0) {
arg += 8;
- else
+ } else {
arg += 3;
+ }
pp = &eap->force_enc;
} else if (STRNCMP(arg, "bad", 3) == 0) {
arg += 3;
pp = &bad_char_idx;
}
- if (pp == NULL || *arg != '=')
+ if (pp == NULL || *arg != '=') {
return FAIL;
+ }
++arg;
*pp = (int)(arg - eap->cmd);
@@ -4692,9 +4789,10 @@ static int getargopt(exarg_T *eap)
}
eap->force_ff = eap->cmd[eap->force_ff];
} else if (pp == &eap->force_enc) {
- /* Make 'fileencoding' lower case. */
- for (p = eap->cmd + eap->force_enc; *p != NUL; ++p)
+ // Make 'fileencoding' lower case.
+ for (p = eap->cmd + eap->force_enc; *p != NUL; ++p) {
*p = TOLOWER_ASC(*p);
+ }
} else {
/* Check ++bad= argument. Must be a single-byte character, "keep" or
* "drop". */
@@ -4717,8 +4815,8 @@ static int get_tabpage_arg(exarg_T *eap)
if (eap->arg && *eap->arg != NUL) {
char_u *p = eap->arg;
char_u *p_save;
- int relative = 0; // argument +N/-N means: go to N places to the
- // right/left relative to the current position.
+ int relative = 0; // argument +N/-N means: go to N places to the
+ // right/left relative to the current position.
if (*p == '-') {
relative = -1;
@@ -4745,8 +4843,7 @@ static int get_tabpage_arg(exarg_T *eap)
} else {
if (*p_save == NUL) {
tab_number = 1;
- }
- else if (p == p_save || *p_save == '-' || *p != NUL || tab_number == 0) {
+ } else if (p == p_save || *p_save == '-' || *p != NUL || tab_number == 0) {
// No numbers as argument.
eap->errmsg = e_invarg;
goto theend;
@@ -4776,8 +4873,9 @@ static int get_tabpage_arg(exarg_T *eap)
switch (eap->cmdidx) {
case CMD_tabnext:
tab_number = tabpage_index(curtab) + 1;
- if (tab_number > LAST_TAB_NR)
+ if (tab_number > LAST_TAB_NR) {
tab_number = 1;
+ }
break;
case CMD_tabmove:
tab_number = LAST_TAB_NR;
@@ -4796,7 +4894,7 @@ theend:
*/
static void ex_abbreviate(exarg_T *eap)
{
- do_exmap(eap, TRUE); /* almost the same as mapping */
+ do_exmap(eap, TRUE); // almost the same as mapping
}
/*
@@ -4847,10 +4945,11 @@ static void ex_autocmd(exarg_T *eap)
if (secure) {
secure = 2;
eap->errmsg = e_curdir;
- } else if (eap->cmdidx == CMD_autocmd)
+ } else if (eap->cmdidx == CMD_autocmd) {
do_autocmd(eap->arg, eap->forceit);
- else
+ } else {
do_augroup(eap->arg, eap->forceit);
+ }
}
/*
@@ -4876,16 +4975,16 @@ static void ex_doautocmd(exarg_T *eap)
*/
static void ex_bunload(exarg_T *eap)
{
- eap->errmsg = do_bufdel(
- eap->cmdidx == CMD_bdelete ? DOBUF_DEL
- : eap->cmdidx == CMD_bwipeout ? DOBUF_WIPE
- : DOBUF_UNLOAD, eap->arg,
- eap->addr_count, (int)eap->line1, (int)eap->line2, eap->forceit);
+ eap->errmsg = do_bufdel(eap->cmdidx == CMD_bdelete ? DOBUF_DEL
+ : eap->cmdidx == CMD_bwipeout ? DOBUF_WIPE
+ : DOBUF_UNLOAD,
+ eap->arg,
+ eap->addr_count, (int)eap->line1, (int)eap->line2, eap->forceit);
}
/*
- * :[N]buffer [N] to buffer N
- * :[N]sbuffer [N] to buffer N
+ * :[N]buffer [N] to buffer N
+ * :[N]sbuffer [N] to buffer N
*/
static void ex_buffer(exarg_T *eap)
{
@@ -4904,8 +5003,8 @@ static void ex_buffer(exarg_T *eap)
}
/*
- * :[N]bmodified [N] to next mod. buffer
- * :[N]sbmodified [N] to next mod. buffer
+ * :[N]bmodified [N] to next mod. buffer
+ * :[N]sbmodified [N] to next mod. buffer
*/
static void ex_bmodified(exarg_T *eap)
{
@@ -4916,8 +5015,8 @@ static void ex_bmodified(exarg_T *eap)
}
/*
- * :[N]bnext [N] to next buffer
- * :[N]sbnext [N] split and to next buffer
+ * :[N]bnext [N] to next buffer
+ * :[N]sbnext [N] split and to next buffer
*/
static void ex_bnext(exarg_T *eap)
{
@@ -4928,10 +5027,10 @@ static void ex_bnext(exarg_T *eap)
}
/*
- * :[N]bNext [N] to previous buffer
- * :[N]bprevious [N] to previous buffer
- * :[N]sbNext [N] split and to previous buffer
- * :[N]sbprevious [N] split and to previous buffer
+ * :[N]bNext [N] to previous buffer
+ * :[N]bprevious [N] to previous buffer
+ * :[N]sbNext [N] split and to previous buffer
+ * :[N]sbprevious [N] split and to previous buffer
*/
static void ex_bprevious(exarg_T *eap)
{
@@ -4942,10 +5041,10 @@ static void ex_bprevious(exarg_T *eap)
}
/*
- * :brewind to first buffer
- * :bfirst to first buffer
- * :sbrewind split and to first buffer
- * :sbfirst split and to first buffer
+ * :brewind to first buffer
+ * :bfirst to first buffer
+ * :sbrewind split and to first buffer
+ * :sbfirst split and to first buffer
*/
static void ex_brewind(exarg_T *eap)
{
@@ -4956,8 +5055,8 @@ static void ex_brewind(exarg_T *eap)
}
/*
- * :blast to last buffer
- * :sblast split and to last buffer
+ * :blast to last buffer
+ * :sblast split and to last buffer
*/
static void ex_blast(exarg_T *eap)
{
@@ -4991,28 +5090,23 @@ char_u *find_nextcmd(const char_u *p)
/// Return NULL if it isn't, the following character if it is.
char_u *check_nextcmd(char_u *p)
{
- char_u *s = skipwhite(p);
+ char_u *s = skipwhite(p);
- if (*s == '|' || *s == '\n') {
- return (s + 1);
- } else {
- return NULL;
- }
+ if (*s == '|' || *s == '\n') {
+ return (s + 1);
+ } else {
+ return NULL;
+ }
}
-/*
- * - if there are more files to edit
- * - and this is the last window
- * - and forceit not used
- * - and not repeated twice on a row
- * return FAIL and give error message if 'message' TRUE
- * return OK otherwise
- */
-static int
-check_more(
- int message, // when FALSE check only, no messages
- bool forceit
-)
+/// - if there are more files to edit
+/// - and this is the last window
+/// - and forceit not used
+/// - and not repeated twice on a row
+/// @return FAIL and give error message if 'message' TRUE, return OK otherwise
+///
+/// @param message when FALSE check only, no messages
+static int check_more(int message, bool forceit)
{
int n = ARGCOUNT - curwin->w_arg_idx - 1;
@@ -5022,21 +5116,24 @@ check_more(
if ((p_confirm || cmdmod.confirm) && curbuf->b_fname != NULL) {
char_u buff[DIALOG_MSG_SIZE];
- if (n == 1)
+ if (n == 1) {
STRLCPY(buff, _("1 more file to edit. Quit anyway?"),
- DIALOG_MSG_SIZE);
- else
+ DIALOG_MSG_SIZE);
+ } else {
vim_snprintf((char *)buff, DIALOG_MSG_SIZE,
- _("%d more files to edit. Quit anyway?"), n);
- if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 1) == VIM_YES)
+ _("%d more files to edit. Quit anyway?"), n);
+ }
+ if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 1) == VIM_YES) {
return OK;
+ }
return FAIL;
}
- if (n == 1)
+ if (n == 1) {
EMSG(_("E173: 1 more file to edit"));
- else
+ } else {
EMSGN(_("E173: %" PRId64 " more files to edit"), n);
- quitmore = 2; /* next try to quit is allowed */
+ }
+ quitmore = 2; // next try to quit is allowed
}
return FAIL;
}
@@ -5048,38 +5145,40 @@ check_more(
*/
char_u *get_command_name(expand_T *xp, int idx)
{
- if (idx >= (int)CMD_SIZE)
+ if (idx >= CMD_SIZE) {
return get_user_command_name(idx);
+ }
return cmdnames[idx].cmd_name;
}
-static int uc_add_command(char_u *name, size_t name_len, char_u *rep,
- uint32_t argt, long def, int flags, int compl,
- char_u *compl_arg, cmd_addr_T addr_type, bool force)
+static int uc_add_command(char_u *name, size_t name_len, char_u *rep, uint32_t argt, long def,
+ int flags, int compl, char_u *compl_arg, cmd_addr_T addr_type, bool force)
FUNC_ATTR_NONNULL_ARG(1, 3)
{
- ucmd_T *cmd = NULL;
+ ucmd_T *cmd = NULL;
int i;
int cmp = 1;
- char_u *rep_buf = NULL;
- garray_T *gap;
+ char_u *rep_buf = NULL;
+ garray_T *gap;
replace_termcodes(rep, STRLEN(rep), &rep_buf, false, false, true,
CPO_TO_CPO_FLAGS);
if (rep_buf == NULL) {
- /* Can't replace termcodes - try using the string as is */
+ // Can't replace termcodes - try using the string as is
rep_buf = vim_strsave(rep);
}
- /* get address of growarray: global or in curbuf */
+ // get address of growarray: global or in curbuf
if (flags & UC_BUFFER) {
gap = &curbuf->b_ucmds;
- if (gap->ga_itemsize == 0)
+ if (gap->ga_itemsize == 0) {
ga_init(gap, (int)sizeof(ucmd_T), 4);
- } else
+ }
+ } else {
gap = &ucmds;
+ }
- /* Search for the command in the already defined commands. */
+ // Search for the command in the already defined commands.
for (i = 0; i < gap->ga_len; ++i) {
size_t len;
@@ -5087,10 +5186,11 @@ static int uc_add_command(char_u *name, size_t name_len, char_u *rep,
len = STRLEN(cmd->uc_name);
cmp = STRNCMP(name, cmd->uc_name, name_len);
if (cmp == 0) {
- if (name_len < len)
+ if (name_len < len) {
cmp = -1;
- else if (name_len > len)
+ } else if (name_len > len) {
cmp = 1;
+ }
}
if (cmp == 0) {
@@ -5109,12 +5209,13 @@ static int uc_add_command(char_u *name, size_t name_len, char_u *rep,
break;
}
- /* Stop as soon as we pass the name to add */
- if (cmp < 0)
+ // Stop as soon as we pass the name to add
+ if (cmp < 0) {
break;
+ }
}
- /* Extend the array unless we're replacing an existing command */
+ // Extend the array unless we're replacing an existing command
if (cmp != 0) {
ga_grow(gap, 1);
@@ -5225,7 +5326,7 @@ static void uc_list(char_u *name, size_t name_len)
{
int i, j;
bool found = false;
- ucmd_T *cmd;
+ ucmd_T *cmd;
uint32_t a;
// In cmdwin, the alternative buffer should be used.
@@ -5251,8 +5352,9 @@ static void uc_list(char_u *name, size_t name_len)
}
found = true;
msg_putchar('\n');
- if (got_int)
+ if (got_int) {
break;
+ }
// Special cases
int len = 4;
@@ -5291,21 +5393,21 @@ static void uc_list(char_u *name, size_t name_len)
// Arguments
switch (a & (EX_EXTRA | EX_NOSPC | EX_NEEDARG)) {
- case 0:
- IObuff[len++] = '0';
- break;
- case (EX_EXTRA):
- IObuff[len++] = '*';
- break;
- case (EX_EXTRA | EX_NOSPC):
- IObuff[len++] = '?';
- break;
- case (EX_EXTRA | EX_NEEDARG):
- IObuff[len++] = '+';
- break;
- case (EX_EXTRA | EX_NOSPC | EX_NEEDARG):
- IObuff[len++] = '1';
- break;
+ case 0:
+ IObuff[len++] = '0';
+ break;
+ case (EX_EXTRA):
+ IObuff[len++] = '*';
+ break;
+ case (EX_EXTRA | EX_NOSPC):
+ IObuff[len++] = '?';
+ break;
+ case (EX_EXTRA | EX_NEEDARG):
+ IObuff[len++] = '+';
+ break;
+ case (EX_EXTRA | EX_NOSPC | EX_NEEDARG):
+ IObuff[len++] = '1';
+ break;
}
do {
@@ -5373,21 +5475,22 @@ static void uc_list(char_u *name, size_t name_len)
break;
}
}
- if (gap == &ucmds || i < gap->ga_len)
+ if (gap == &ucmds || i < gap->ga_len) {
break;
+ }
gap = &ucmds;
}
- if (!found)
+ if (!found) {
MSG(_("No user-defined commands found"));
+ }
}
-static int uc_scan_attr(char_u *attr, size_t len, uint32_t *argt, long *def,
- int *flags, int *complp, char_u **compl_arg,
- cmd_addr_T *addr_type_arg)
+static int uc_scan_attr(char_u *attr, size_t len, uint32_t *argt, long *def, int *flags,
+ int *complp, char_u **compl_arg, cmd_addr_T *addr_type_arg)
FUNC_ATTR_NONNULL_ALL
{
- char_u *p;
+ char_u *p;
if (len == 0) {
EMSG(_("E175: No attribute specified"));
@@ -5405,7 +5508,7 @@ static int uc_scan_attr(char_u *attr, size_t len, uint32_t *argt, long *def,
*argt |= EX_TRLBAR;
} else {
int i;
- char_u *val = NULL;
+ char_u *val = NULL;
size_t vallen = 0;
size_t attrlen = len;
@@ -5473,17 +5576,20 @@ invalid_count:
if (val != NULL) {
p = val;
- if (*def >= 0)
+ if (*def >= 0) {
goto two_count;
+ }
*def = getdigits_long(&p, true, 0);
- if (p != val + vallen)
+ if (p != val + vallen) {
goto invalid_count;
+ }
}
- if (*def < 0)
+ if (*def < 0) {
*def = 0;
+ }
} else if (STRNICMP(attr, "complete", attrlen) == 0) {
if (val == NULL) {
EMSG(_("E179: argument required for -complete"));
@@ -5518,26 +5624,28 @@ invalid_count:
return OK;
}
+static char e_complete_used_without_nargs[] = N_("E1208: -complete used without -nargs");
+
/*
* ":command ..."
*/
static void ex_command(exarg_T *eap)
{
- char_u *name;
- char_u *end;
- char_u *p;
+ char_u *name;
+ char_u *end;
+ char_u *p;
uint32_t argt = 0;
long def = -1;
int flags = 0;
- int compl = EXPAND_NOTHING;
- char_u *compl_arg = NULL;
+ int compl = EXPAND_NOTHING;
+ char_u *compl_arg = NULL;
cmd_addr_T addr_type_arg = ADDR_NONE;
int has_attr = (eap->arg[0] == '-');
int name_len;
p = eap->arg;
- /* Check for attributes */
+ // Check for attributes
while (*p == '-') {
++p;
end = skiptowhite(p);
@@ -5569,10 +5677,10 @@ static void ex_command(exarg_T *eap)
uc_list(name, end - name);
} else if (!ASCII_ISUPPER(*name)) {
EMSG(_("E183: User defined commands must start with an uppercase letter"));
- return;
} else if (name_len <= 4 && STRNCMP(name, "Next", name_len) == 0) {
EMSG(_("E841: Reserved name, cannot be used for user defined command"));
- return;
+ } else if (compl > 0 && (argt & EX_EXTRA) == 0) {
+ EMSG(_(e_complete_used_without_nargs));
} else {
uc_add_command(name, end - name, p, argt, def, flags, compl, compl_arg,
addr_type_arg, eap->forceit);
@@ -5589,7 +5697,7 @@ void ex_comclear(exarg_T *eap)
uc_clear(&curbuf->b_ucmds);
}
-static void free_ucmd(ucmd_T* cmd) {
+static void free_ucmd(ucmd_T * cmd) {
xfree(cmd->uc_name);
xfree(cmd->uc_rep);
xfree(cmd->uc_compl_arg);
@@ -5606,20 +5714,22 @@ void uc_clear(garray_T *gap)
static void ex_delcommand(exarg_T *eap)
{
int i = 0;
- ucmd_T *cmd = NULL;
+ ucmd_T *cmd = NULL;
int cmp = -1;
- garray_T *gap;
+ garray_T *gap;
gap = &curbuf->b_ucmds;
for (;; ) {
for (i = 0; i < gap->ga_len; ++i) {
cmd = USER_CMD_GA(gap, i);
cmp = STRCMP(eap->arg, cmd->uc_name);
- if (cmp <= 0)
+ if (cmp <= 0) {
break;
+ }
}
- if (gap == &ucmds || cmp == 0)
+ if (gap == &ucmds || cmp == 0) {
break;
+ }
gap = &ucmds;
}
@@ -5634,8 +5744,9 @@ static void ex_delcommand(exarg_T *eap)
--gap->ga_len;
- if (i < gap->ga_len)
+ if (i < gap->ga_len) {
memmove(cmd, cmd + 1, (gap->ga_len - i) * sizeof(ucmd_T));
+ }
}
/*
@@ -5648,9 +5759,9 @@ static char_u *uc_split_args(char_u *arg, size_t *lenp)
char_u *q;
int len;
- /* Precalculate length */
+ // Precalculate length
p = arg;
- len = 2; /* Initial and final quotes */
+ len = 2; // Initial and final quotes
while (*p) {
if (p[0] == '\\' && p[1] == '\\') {
@@ -5664,9 +5775,10 @@ static char_u *uc_split_args(char_u *arg, size_t *lenp)
p += 1;
} else if (ascii_iswhite(*p)) {
p = skipwhite(p);
- if (*p == NUL)
+ if (*p == NUL) {
break;
- len += 3; /* "," */
+ }
+ len += 3; // ","
} else {
const int charlen = utfc_ptr2len(p);
@@ -5693,8 +5805,9 @@ static char_u *uc_split_args(char_u *arg, size_t *lenp)
*q++ = *p++;
} else if (ascii_iswhite(*p)) {
p = skipwhite(p);
- if (*p == NUL)
+ if (*p == NUL) {
break;
+ }
*q++ = '"';
*q++ = ',';
*q++ = '"';
@@ -5727,28 +5840,22 @@ static size_t add_cmd_modifier(char_u *buf, char *mod_str, bool *multi_mods)
return result;
}
-/*
- * Check for a <> code in a user command.
- * "code" points to the '<'. "len" the length of the <> (inclusive).
- * "buf" is where the result is to be added.
- * "split_buf" points to a buffer used for splitting, caller should free it.
- * "split_len" is the length of what "split_buf" contains.
- * Returns the length of the replacement, which has been added to "buf".
- * Returns -1 if there was no match, and only the "<" has been copied.
- */
-static size_t
-uc_check_code(
- char_u *code,
- size_t len,
- char_u *buf,
- ucmd_T *cmd, /* the user command we're expanding */
- exarg_T *eap, /* ex arguments */
- char_u **split_buf,
- size_t *split_len
-)
+/// Check for a <> code in a user command.
+///
+/// @param code points to the '<'. "len" the length of the <> (inclusive).
+/// @param buf is where the result is to be added.
+/// @param cmd the user command we're expanding
+/// @param eap ex arguments
+/// @param split_buf points to a buffer used for splitting, caller should free it.
+/// @param split_len is the length of what "split_buf" contains.
+///
+/// @return the length of the replacement, which has been added to "buf".
+/// Return -1 if there was no match, and only the "<" has been copied.
+static size_t uc_check_code(char_u *code, size_t len, char_u *buf, ucmd_T *cmd, exarg_T *eap,
+ char_u **split_buf, size_t *split_len)
{
size_t result = 0;
- char_u *p = code + 1;
+ char_u *p = code + 1;
size_t l = len - 2;
int quote = 0;
enum {
@@ -5795,14 +5902,16 @@ uc_check_code(
switch (type) {
case ct_ARGS:
- /* Simple case first */
+ // Simple case first
if (*eap->arg == NUL) {
if (quote == 1) {
result = 2;
- if (buf != NULL)
+ if (buf != NULL) {
STRCPY(buf, "''");
- } else
+ }
+ } else {
result = 0;
+ }
break;
}
@@ -5813,12 +5922,13 @@ uc_check_code(
}
switch (quote) {
- case 0: /* No quoting, no splitting */
+ case 0: // No quoting, no splitting
result = STRLEN(eap->arg);
- if (buf != NULL)
+ if (buf != NULL) {
STRCPY(buf, eap->arg);
+ }
break;
- case 1: /* Quote, but don't split */
+ case 1: // Quote, but don't split
result = STRLEN(eap->arg) + 2;
for (p = eap->arg; *p; p++) {
if (*p == '\\' || *p == '"') {
@@ -5838,14 +5948,16 @@ uc_check_code(
}
break;
- case 2: /* Quote and split (<f-args>) */
- /* This is hard, so only do it once, and cache the result */
- if (*split_buf == NULL)
+ case 2: // Quote and split (<f-args>)
+ // This is hard, so only do it once, and cache the result
+ if (*split_buf == NULL) {
*split_buf = uc_split_args(eap->arg, split_len);
+ }
result = *split_len;
- if (buf != NULL && result != 0)
+ if (buf != NULL && result != 0) {
STRCPY(buf, *split_buf);
+ }
break;
}
@@ -5853,23 +5965,26 @@ uc_check_code(
case ct_BANG:
result = eap->forceit ? 1 : 0;
- if (quote)
+ if (quote) {
result += 2;
+ }
if (buf != NULL) {
- if (quote)
+ if (quote) {
*buf++ = '"';
- if (eap->forceit)
+ }
+ if (eap->forceit) {
*buf++ = '!';
- if (quote)
+ }
+ if (quote) {
*buf = '"';
+ }
}
break;
case ct_LINE1:
case ct_LINE2:
case ct_RANGE:
- case ct_COUNT:
- {
+ case ct_COUNT: {
char num_buf[20];
long num = (type == ct_LINE1) ? eap->line1 :
(type == ct_LINE2) ? eap->line2 :
@@ -5881,23 +5996,25 @@ uc_check_code(
num_len = STRLEN(num_buf);
result = num_len;
- if (quote)
+ if (quote) {
result += 2;
+ }
if (buf != NULL) {
- if (quote)
+ if (quote) {
*buf++ = '"';
+ }
STRCPY(buf, num_buf);
buf += num_len;
- if (quote)
+ if (quote) {
*buf = '"';
+ }
}
break;
}
- case ct_MODS:
- {
+ case ct_MODS: {
result = quote ? 2 : 0;
if (buf != NULL) {
if (quote) {
@@ -5979,29 +6096,35 @@ uc_check_code(
case ct_REGISTER:
result = eap->regname ? 1 : 0;
- if (quote)
+ if (quote) {
result += 2;
+ }
if (buf != NULL) {
- if (quote)
+ if (quote) {
*buf++ = '\'';
- if (eap->regname)
+ }
+ if (eap->regname) {
*buf++ = eap->regname;
- if (quote)
+ }
+ if (quote) {
*buf = '\'';
+ }
}
break;
case ct_LT:
result = 1;
- if (buf != NULL)
+ if (buf != NULL) {
*buf = '<';
+ }
break;
default:
- /* Not recognized: just copy the '<' and return -1. */
+ // Not recognized: just copy the '<' and return -1.
result = (size_t)-1;
- if (buf != NULL)
+ if (buf != NULL) {
*buf = '<';
+ }
break;
}
@@ -6010,24 +6133,25 @@ uc_check_code(
static void do_ucmd(exarg_T *eap)
{
- char_u *buf;
- char_u *p;
- char_u *q;
+ char_u *buf;
+ char_u *p;
+ char_u *q;
- char_u *start;
- char_u *end = NULL;
- char_u *ksp;
+ char_u *start;
+ char_u *end = NULL;
+ char_u *ksp;
size_t len, totlen;
size_t split_len = 0;
- char_u *split_buf = NULL;
- ucmd_T *cmd;
+ char_u *split_buf = NULL;
+ ucmd_T *cmd;
const sctx_T save_current_sctx = current_sctx;
- if (eap->cmdidx == CMD_USER)
+ if (eap->cmdidx == CMD_USER) {
cmd = USER_CMD(eap->useridx);
- else
+ } else {
cmd = USER_CMD_GA(&curbuf->b_ucmds, eap->useridx);
+ }
/*
* Replace <> in the command by the arguments.
@@ -6036,14 +6160,15 @@ static void do_ucmd(exarg_T *eap)
*/
buf = NULL;
for (;; ) {
- p = cmd->uc_rep; /* source */
- q = buf; /* destination */
+ p = cmd->uc_rep; // source
+ q = buf; // destination
totlen = 0;
for (;; ) {
start = vim_strchr(p, '<');
- if (start != NULL)
+ if (start != NULL) {
end = vim_strchr(start + 1, '>');
+ }
if (buf != NULL) {
for (ksp = p; *ksp != NUL && *ksp != K_SPECIAL; ksp++) {
}
@@ -6065,41 +6190,44 @@ static void do_ucmd(exarg_T *eap)
}
}
- /* break if there no <item> is found */
- if (start == NULL || end == NULL)
+ // break if there no <item> is found
+ if (start == NULL || end == NULL) {
break;
+ }
- /* Include the '>' */
+ // Include the '>'
++end;
- /* Take everything up to the '<' */
+ // Take everything up to the '<'
len = start - p;
- if (buf == NULL)
+ if (buf == NULL) {
totlen += len;
- else {
+ } else {
memmove(q, p, len);
q += len;
}
len = uc_check_code(start, end - start, q, cmd, eap,
- &split_buf, &split_len);
+ &split_buf, &split_len);
if (len == (size_t)-1) {
- /* no match, continue after '<' */
+ // no match, continue after '<'
p = start + 1;
len = 1;
- } else
+ } else {
p = end;
- if (buf == NULL)
+ }
+ if (buf == NULL) {
totlen += len;
- else
+ } else {
q += len;
+ }
}
- if (buf != NULL) { /* second time here, finished */
+ if (buf != NULL) { // second time here, finished
STRCPY(q, p);
break;
}
- totlen += STRLEN(p); /* Add on the trailing characters */
+ totlen += STRLEN(p); // Add on the trailing characters
buf = xmalloc(totlen + 1);
}
@@ -6113,7 +6241,7 @@ static void do_ucmd(exarg_T *eap)
static char_u *get_user_command_name(int idx)
{
- return get_user_commands(NULL, idx - (int)CMD_SIZE);
+ return get_user_commands(NULL, idx - CMD_SIZE);
}
/*
* Function given to ExpandGeneric() to obtain the list of user address type names.
@@ -6150,12 +6278,13 @@ char_u *get_user_commands(expand_T *xp FUNC_ATTR_UNUSED, int idx)
*/
char_u *get_user_cmd_flags(expand_T *xp, int idx)
{
- static char *user_cmd_flags[] = {"addr", "bang", "bar",
- "buffer", "complete", "count",
- "nargs", "range", "register"};
+ static char *user_cmd_flags[] = { "addr", "bang", "bar",
+ "buffer", "complete", "count",
+ "nargs", "range", "register" };
- if (idx >= (int)ARRAY_SIZE(user_cmd_flags))
+ if (idx >= (int)ARRAY_SIZE(user_cmd_flags)) {
return NULL;
+ }
return (char_u *)user_cmd_flags[idx];
}
@@ -6164,10 +6293,11 @@ char_u *get_user_cmd_flags(expand_T *xp, int idx)
*/
char_u *get_user_cmd_nargs(expand_T *xp, int idx)
{
- static char *user_cmd_nargs[] = {"0", "1", "*", "?", "+"};
+ static char *user_cmd_nargs[] = { "0", "1", "*", "?", "+" };
- if (idx >= (int)ARRAY_SIZE(user_cmd_nargs))
+ if (idx >= (int)ARRAY_SIZE(user_cmd_nargs)) {
return NULL;
+ }
return (char_u *)user_cmd_nargs[idx];
}
@@ -6223,8 +6353,8 @@ int parse_addr_type_arg(char_u *value, int vallen, cmd_addr_T *addr_type_arg)
* copied to allocated memory and stored in "*compl_arg".
* Returns FAIL if something is wrong.
*/
-int parse_compl_arg(const char_u *value, int vallen, int *complp,
- uint32_t *argt, char_u **compl_arg)
+int parse_compl_arg(const char_u *value, int vallen, int *complp, uint32_t *argt,
+ char_u **compl_arg)
FUNC_ATTR_NONNULL_ALL
{
const char_u *arg = NULL;
@@ -6232,7 +6362,7 @@ int parse_compl_arg(const char_u *value, int vallen, int *complp,
int i;
int valend = vallen;
- /* Look for any argument part - which is the part after any ',' */
+ // Look for any argument part - which is the part after any ','
for (i = 0; i < vallen; ++i) {
if (value[i] == ',') {
arg = &value[i + 1];
@@ -6283,17 +6413,17 @@ int parse_compl_arg(const char_u *value, int vallen, int *complp,
int cmdcomplete_str_to_type(const char *complete_str)
{
- for (int i = 0; i < (int)(ARRAY_SIZE(command_complete)); i++) {
- char *cmd_compl = get_command_complete(i);
- if (cmd_compl == NULL) {
- continue;
- }
- if (strcmp(complete_str, command_complete[i]) == 0) {
- return i;
- }
+ for (int i = 0; i < (int)(ARRAY_SIZE(command_complete)); i++) {
+ char *cmd_compl = get_command_complete(i);
+ if (cmd_compl == NULL) {
+ continue;
+ }
+ if (strcmp(complete_str, command_complete[i]) == 0) {
+ return i;
}
+ }
- return EXPAND_NOTHING;
+ return EXPAND_NOTHING;
}
static void ex_colorscheme(exarg_T *eap)
@@ -6302,18 +6432,20 @@ static void ex_colorscheme(exarg_T *eap)
char_u *expr = vim_strsave((char_u *)"g:colors_name");
char_u *p = NULL;
- ++emsg_off;
- p = eval_to_string(expr, NULL, FALSE);
- --emsg_off;
+ emsg_off++;
+ p = eval_to_string(expr, NULL, false);
+ emsg_off--;
xfree(expr);
if (p != NULL) {
MSG(p);
xfree(p);
- } else
+ } else {
MSG("default");
- } else if (load_colors(eap->arg) == FAIL)
+ }
+ } else if (load_colors(eap->arg) == FAIL) {
EMSG2(_("E185: Cannot find color scheme '%s'"), eap->arg);
+ }
}
static void ex_highlight(exarg_T *eap)
@@ -6371,7 +6503,7 @@ static void ex_quit(exarg_T *eap)
cmdwin_result = Ctrl_C;
return;
}
- /* Don't quit while editing the command line. */
+ // Don't quit while editing the command line.
if (text_locked()) {
text_locked_msg();
return;
@@ -6383,8 +6515,9 @@ static void ex_quit(exarg_T *eap)
int wnr = eap->line2;
for (wp = firstwin; wp->w_next != NULL; wp = wp->w_next) {
- if (--wnr <= 0)
+ if (--wnr <= 0) {
break;
+ }
}
} else {
wp = curwin;
@@ -6446,7 +6579,7 @@ static void ex_quit_all(exarg_T *eap)
return;
}
- /* Don't quit while editing the command line. */
+ // Don't quit while editing the command line.
if (text_locked()) {
text_locked_msg();
return;
@@ -6483,8 +6616,9 @@ static void ex_close(exarg_T *eap)
break;
}
}
- if (win == NULL)
+ if (win == NULL) {
win = lastwin;
+ }
ex_win_close(eap->forceit, win, NULL);
}
}
@@ -6503,19 +6637,14 @@ static void ex_pclose(exarg_T *eap)
}
}
-/*
- * Close window "win" and take care of handling closing the last window for a
- * modified buffer.
- */
-void
-ex_win_close(
- int forceit,
- win_T *win,
- tabpage_T *tp /* NULL or the tab page "win" is in */
-)
+/// Close window "win" and take care of handling closing the last window for a
+/// modified buffer.
+///
+/// @param tp NULL or the tab page "win" is in
+void ex_win_close(int forceit, win_T *win, tabpage_T *tp)
{
int need_hide;
- buf_T *buf = win->w_buffer;
+ buf_T *buf = win->w_buffer;
// Never close the autocommand window.
if (win == aucmd_win) {
@@ -6554,13 +6683,13 @@ ex_win_close(
*/
static void ex_tabclose(exarg_T *eap)
{
- tabpage_T *tp;
+ tabpage_T *tp;
- if (cmdwin_type != 0)
+ if (cmdwin_type != 0) {
cmdwin_result = K_IGNORE;
- else if (first_tabpage->tp_next == NULL)
+ } else if (first_tabpage->tp_next == NULL) {
EMSG(_("E784: Cannot close last tab page"));
- else {
+ } else {
int tab_number = get_tabpage_arg(eap);
if (eap->errmsg == NULL) {
tp = find_tabpage(tab_number);
@@ -6584,7 +6713,7 @@ static void ex_tabonly(exarg_T *eap)
if (cmdwin_type != 0) {
cmdwin_result = K_IGNORE;
} else if (first_tabpage->tp_next == NULL) {
- MSG(_("Already only one tab page"));
+ MSG(_("Already only one tab page"));
} else {
int tab_number = get_tabpage_arg(eap);
if (eap->errmsg == NULL) {
@@ -6639,7 +6768,7 @@ void tabpage_close(int forceit)
void tabpage_close_other(tabpage_T *tp, int forceit)
{
int done = 0;
- win_T *wp;
+ win_T *wp;
int h = tabline_height();
char_u prev_idx[NUMBUFLEN];
@@ -6652,13 +6781,15 @@ void tabpage_close_other(tabpage_T *tp, int forceit)
/* Autocommands may delete the tab page under our fingers and we may
* fail to close a window with a modified buffer. */
- if (!valid_tabpage(tp) || tp->tp_firstwin == wp)
+ if (!valid_tabpage(tp) || tp->tp_firstwin == wp) {
break;
+ }
}
- redraw_tabline = TRUE;
- if (h != tabline_height())
+ redraw_tabline = true;
+ if (h != tabline_height()) {
shell_new_rows();
+ }
}
/*
@@ -6672,10 +6803,11 @@ static void ex_only(exarg_T *eap)
if (eap->addr_count > 0) {
wnr = eap->line2;
for (wp = firstwin; --wnr > 0;) {
- if (wp->w_next == NULL)
+ if (wp->w_next == NULL) {
break;
- else
+ } else {
wp = wp->w_next;
+ }
}
} else {
wp = curwin;
@@ -6692,34 +6824,35 @@ static void ex_only(exarg_T *eap)
*/
void ex_all(exarg_T *eap)
{
- if (eap->addr_count == 0)
+ if (eap->addr_count == 0) {
eap->line2 = 9999;
+ }
do_arg_all((int)eap->line2, eap->forceit, eap->cmdidx == CMD_drop);
}
static void ex_hide(exarg_T *eap)
{
- // ":hide" or ":hide | cmd": hide current window
- if (!eap->skip) {
- if (eap->addr_count == 0) {
- win_close(curwin, false); // don't free buffer
- } else {
- int winnr = 0;
- win_T *win = NULL;
-
- FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- winnr++;
- if (winnr == eap->line2) {
- win = wp;
- break;
- }
- }
- if (win == NULL) {
- win = lastwin;
- }
- win_close(win, false);
+ // ":hide" or ":hide | cmd": hide current window
+ if (!eap->skip) {
+ if (eap->addr_count == 0) {
+ win_close(curwin, false); // don't free buffer
+ } else {
+ int winnr = 0;
+ win_T *win = NULL;
+
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ winnr++;
+ if (winnr == eap->line2) {
+ win = wp;
+ break;
}
+ }
+ if (win == NULL) {
+ win = lastwin;
+ }
+ win_close(win, false);
}
+ }
}
/// ":stop" and ":suspend": Suspend Vim.
@@ -6750,7 +6883,7 @@ static void ex_exit(exarg_T *eap)
cmdwin_result = Ctrl_C;
return;
}
- /* Don't quit while editing the command line. */
+ // Don't quit while editing the command line.
if (text_locked()) {
text_locked_msg();
return;
@@ -6784,25 +6917,26 @@ static void ex_exit(exarg_T *eap)
*/
static void ex_print(exarg_T *eap)
{
- if (curbuf->b_ml.ml_flags & ML_EMPTY)
+ if (curbuf->b_ml.ml_flags & ML_EMPTY) {
EMSG(_(e_emptybuf));
- else {
+ } else {
for (; !got_int; os_breakcheck()) {
print_line(eap->line1,
- (eap->cmdidx == CMD_number || eap->cmdidx == CMD_pound
- || (eap->flags & EXFLAG_NR)),
- eap->cmdidx == CMD_list || (eap->flags & EXFLAG_LIST));
- if (++eap->line1 > eap->line2)
+ (eap->cmdidx == CMD_number || eap->cmdidx == CMD_pound
+ || (eap->flags & EXFLAG_NR)),
+ eap->cmdidx == CMD_list || (eap->flags & EXFLAG_LIST));
+ if (++eap->line1 > eap->line2) {
break;
- ui_flush(); /* show one line at a time */
+ }
+ ui_flush(); // show one line at a time
}
setpcmark();
- /* put cursor at last line */
+ // put cursor at last line
curwin->w_cursor.lnum = eap->line2;
beginline(BL_SOL | BL_FIX);
}
- ex_no_reprint = TRUE;
+ ex_no_reprint = true;
}
static void ex_goto(exarg_T *eap)
@@ -6815,7 +6949,7 @@ static void ex_goto(exarg_T *eap)
*/
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);
}
@@ -6860,11 +6994,11 @@ void alist_new(void)
*/
void alist_expand(int *fnum_list, int fnum_len)
{
- char_u **old_arg_files;
+ char_u **old_arg_files;
int old_arg_count;
- char_u **new_arg_files;
+ char_u **new_arg_files;
int new_arg_file_count;
- char_u *save_p_su = p_su;
+ char_u *save_p_su = p_su;
int i;
/* Don't use 'suffixes' here. This should work like the shell did the
@@ -6872,15 +7006,16 @@ void alist_expand(int *fnum_list, int fnum_len)
* can't set the options. */
p_su = empty_option;
old_arg_files = xmalloc(sizeof(*old_arg_files) * GARGCOUNT);
- for (i = 0; i < GARGCOUNT; ++i)
+ for (i = 0; i < GARGCOUNT; ++i) {
old_arg_files[i] = vim_strsave(GARGLIST[i].ae_fname);
+ }
old_arg_count = GARGCOUNT;
if (expand_wildcards(old_arg_count, old_arg_files,
- &new_arg_file_count, &new_arg_files,
- EW_FILE|EW_NOTFOUND|EW_ADDSLASH|EW_NOERROR) == OK
+ &new_arg_file_count, &new_arg_files,
+ EW_FILE|EW_NOTFOUND|EW_ADDSLASH|EW_NOERROR) == OK
&& new_arg_file_count > 0) {
alist_set(&global_alist, new_arg_file_count, new_arg_files,
- TRUE, fnum_list, fnum_len);
+ TRUE, fnum_list, fnum_len);
FreeWild(old_arg_count, old_arg_files);
}
p_su = save_p_su;
@@ -6909,15 +7044,17 @@ void alist_set(alist_T *al, int count, char_u **files, int use_curbuf, int *fnum
if (got_int) {
/* When adding many buffers this can take a long time. Allow
* interrupting here. */
- while (i < count)
+ while (i < count) {
xfree(files[i++]);
+ }
break;
}
/* May set buffer name of a buffer previously used for the
* argument list, so that it's re-used by alist_add. */
- if (fnum_list != NULL && i < fnum_len)
+ if (fnum_list != NULL && i < fnum_len) {
buf_set_name(fnum_list[i], files[i]);
+ }
alist_add(al, files[i], use_curbuf ? 2 : 1);
os_breakcheck();
@@ -6931,26 +7068,23 @@ void alist_set(alist_T *al, int count, char_u **files, int use_curbuf, int *fnum
recursive--;
}
-/*
- * Add file "fname" to argument list "al".
- * "fname" must have been allocated and "al" must have been checked for room.
- */
-void
-alist_add(
- alist_T *al,
- char_u *fname,
- int set_fnum /* 1: set buffer number; 2: re-use curbuf */
-)
-{
- if (fname == NULL) /* don't add NULL file names */
+/// Add file "fname" to argument list "al".
+/// "fname" must have been allocated and "al" must have been checked for room.
+///
+/// @param set_fnum 1: set buffer number; 2: re-use curbuf
+void alist_add(alist_T *al, char_u *fname, int set_fnum)
+{
+ if (fname == NULL) { // don't add NULL file names
return;
+ }
#ifdef BACKSLASH_IN_FILENAME
slash_adjust(fname);
#endif
AARGLIST(al)[al->al_ga.ga_len].ae_fname = fname;
- if (set_fnum > 0)
+ if (set_fnum > 0) {
AARGLIST(al)[al->al_ga.ga_len].ae_fnum =
buflist_add(fname, BLN_LISTED | (set_fnum == 2 ? BLN_CURBUF : 0));
+ }
++al->al_ga.ga_len;
}
@@ -6992,9 +7126,9 @@ static void ex_recover(exarg_T *eap)
// Set recoverymode right away to avoid the ATTENTION prompt.
recoverymode = true;
if (!check_changed(curbuf, (p_awa ? CCGD_AW : 0)
- | CCGD_MULTWIN
- | (eap->forceit ? CCGD_FORCEIT : 0)
- | CCGD_EXCMD)
+ | CCGD_MULTWIN
+ | (eap->forceit ? CCGD_FORCEIT : 0)
+ | CCGD_EXCMD)
&& (*eap->arg == NUL
|| setfname(curbuf, eap->arg, NULL, true) == OK)) {
@@ -7012,40 +7146,43 @@ static void ex_wrongmodifier(exarg_T *eap)
}
/*
- * :sview [+command] file split window with new file, read-only
- * :split [[+command] file] split window with current or new file
- * :vsplit [[+command] file] split window vertically with current or new file
- * :new [[+command] file] split window with no or new file
- * :vnew [[+command] file] split vertically window with no or new file
- * :sfind [+command] file split window with file in 'path'
+ * :sview [+command] file split window with new file, read-only
+ * :split [[+command] file] split window with current or new file
+ * :vsplit [[+command] file] split window vertically with current or new file
+ * :new [[+command] file] split window with no or new file
+ * :vnew [[+command] file] split vertically window with no or new file
+ * :sfind [+command] file split window with file in 'path'
*
- * :tabedit open new Tab page with empty window
- * :tabedit [+command] file open new Tab page and edit "file"
- * :tabnew [[+command] file] just like :tabedit
- * :tabfind [+command] file open new Tab page and find "file"
+ * :tabedit open new Tab page with empty window
+ * :tabedit [+command] file open new Tab page and edit "file"
+ * :tabnew [[+command] file] just like :tabedit
+ * :tabfind [+command] file open new Tab page and find "file"
*/
void ex_splitview(exarg_T *eap)
{
- win_T *old_curwin = curwin;
- char_u *fname = NULL;
+ win_T *old_curwin = curwin;
+ char_u *fname = NULL;
const bool use_tab = eap->cmdidx == CMD_tabedit
- || eap->cmdidx == CMD_tabfind
- || eap->cmdidx == CMD_tabnew;
+ || eap->cmdidx == CMD_tabfind
+ || eap->cmdidx == CMD_tabnew;
/* A ":split" in the quickfix window works like ":new". Don't want two
* quickfix windows. But it's OK when doing ":tab split". */
if (bt_quickfix(curbuf) && cmdmod.tab == 0) {
- if (eap->cmdidx == CMD_split)
+ if (eap->cmdidx == CMD_split) {
eap->cmdidx = CMD_new;
- if (eap->cmdidx == CMD_vsplit)
+ }
+ if (eap->cmdidx == CMD_vsplit) {
eap->cmdidx = CMD_vnew;
+ }
}
if (eap->cmdidx == CMD_sfind || eap->cmdidx == CMD_tabfind) {
fname = find_file_in_path(eap->arg, STRLEN(eap->arg),
FNAME_MESS, TRUE, curbuf->b_ffname);
- if (fname == NULL)
+ if (fname == NULL) {
goto theend;
+ }
eap->arg = fname;
}
@@ -7056,17 +7193,18 @@ void ex_splitview(exarg_T *eap)
if (win_new_tabpage(cmdmod.tab != 0 ? cmdmod.tab : eap->addr_count == 0
? 0 : (int)eap->line2 + 1, eap->arg) != FAIL) {
do_exedit(eap, old_curwin);
- apply_autocmds(EVENT_TABNEWENTERED, NULL, NULL, FALSE, curbuf);
+ apply_autocmds(EVENT_TABNEWENTERED, NULL, NULL, false, curbuf);
- /* set the alternate buffer for the window we came from */
+ // set the alternate buffer for the window we came from
if (curwin != old_curwin
&& win_valid(old_curwin)
&& old_curwin->w_buffer != curbuf
- && !cmdmod.keepalt)
+ && !cmdmod.keepalt) {
old_curwin->w_alt_fnum = curbuf->b_fnum;
+ }
}
} else if (win_split(eap->addr_count > 0 ? (int)eap->line2 : 0,
- *eap->cmd == 'v' ? WSP_VERT : 0) != FAIL) {
+ *eap->cmd == 'v' ? WSP_VERT : 0) != FAIL) {
/* Reset 'scrollbind' when editing another file, but keep it when
* doing ":split" without arguments. */
if (*eap->arg != NUL
@@ -7173,7 +7311,7 @@ static void ex_tabs(exarg_T *eap)
FOR_ALL_TABS(tp) {
if (got_int) {
- break;
+ break;
}
msg_putchar('\n');
@@ -7192,13 +7330,13 @@ static void ex_tabs(exarg_T *eap)
msg_putchar(' ');
msg_putchar(bufIsChanged(wp->w_buffer) ? '+' : ' ');
msg_putchar(' ');
- if (buf_spname(wp->w_buffer) != NULL)
+ if (buf_spname(wp->w_buffer) != NULL) {
STRLCPY(IObuff, buf_spname(wp->w_buffer), IOSIZE);
- else
- home_replace(wp->w_buffer, wp->w_buffer->b_fname,
- IObuff, IOSIZE, TRUE);
+ } else {
+ home_replace(wp->w_buffer, wp->w_buffer->b_fname, IObuff, IOSIZE, true);
+ }
msg_outtrans(IObuff);
- ui_flush(); /* output one line at a time */
+ ui_flush(); // output one line at a time
os_breakcheck();
}
}
@@ -7226,12 +7364,13 @@ static void ex_mode(exarg_T *eap)
static void ex_resize(exarg_T *eap)
{
int n;
- win_T *wp = curwin;
+ win_T *wp = curwin;
if (eap->addr_count > 0) {
n = eap->line2;
- for (wp = firstwin; wp->w_next != NULL && --n > 0; wp = wp->w_next)
+ for (wp = firstwin; wp->w_next != NULL && --n > 0; wp = wp->w_next) {
;
+ }
}
n = atol((char *)eap->arg);
@@ -7257,7 +7396,7 @@ static void ex_resize(exarg_T *eap)
*/
static void ex_find(exarg_T *eap)
{
- char_u *fname;
+ char_u *fname;
int count;
fname = find_file_in_path(eap->arg, STRLEN(eap->arg),
@@ -7285,14 +7424,10 @@ static void ex_edit(exarg_T *eap)
do_exedit(eap, NULL);
}
-/*
- * ":edit <file>" command and alikes.
- */
-void
-do_exedit(
- exarg_T *eap,
- win_T *old_curwin /* curwin before doing a split or NULL */
-)
+/// ":edit <file>" command and alikes.
+///
+/// @param old_curwin curwin before doing a split or NULL
+void do_exedit(exarg_T *eap, win_T *old_curwin)
{
int n;
int need_hide;
@@ -7302,10 +7437,10 @@ do_exedit(
*/
if (exmode_active && (eap->cmdidx == CMD_visual
|| eap->cmdidx == CMD_view)) {
- exmode_active = 0;
+ exmode_active = false;
ex_pressedreturn = false;
if (*eap->arg == NUL) {
- /* Special case: ":global/pat/visual\NLvi-commands" */
+ // Special case: ":global/pat/visual\NLvi-commands"
if (global_busy) {
int rd = RedrawingDisabled;
int nwr = no_wait_return;
@@ -7318,7 +7453,7 @@ do_exedit(
RedrawingDisabled = 0;
no_wait_return = 0;
- need_wait_return = FALSE;
+ need_wait_return = false;
msg_scroll = 0;
redraw_all_later(NOT_VALID);
@@ -7337,23 +7472,25 @@ do_exedit(
|| eap->cmdidx == CMD_tabedit
|| eap->cmdidx == CMD_vnew
) && *eap->arg == NUL) {
- /* ":new" or ":tabnew" without argument: edit an new empty buffer */
+ // ":new" or ":tabnew" without argument: edit an new empty buffer
setpcmark();
(void)do_ecmd(0, NULL, NULL, eap, ECMD_ONE,
- ECMD_HIDE + (eap->forceit ? ECMD_FORCEIT : 0),
- old_curwin == NULL ? curwin : NULL);
+ ECMD_HIDE + (eap->forceit ? ECMD_FORCEIT : 0),
+ old_curwin == NULL ? curwin : NULL);
} else if ((eap->cmdidx != CMD_split && eap->cmdidx != CMD_vsplit)
|| *eap->arg != NUL) {
- /* Can't edit another file when "curbuf_lock" is set. Only ":edit"
- * can bring us here, others are stopped earlier. */
- if (*eap->arg != NUL && curbuf_locked())
+ // Can't edit another file when "curbuf->b_ro_lockec" is set. Only ":edit"
+ // can bring us here, others are stopped earlier.
+ if (*eap->arg != NUL && curbuf_locked()) {
return;
+ }
n = readonlymode;
- if (eap->cmdidx == CMD_view || eap->cmdidx == CMD_sview)
- readonlymode = TRUE;
- else if (eap->cmdidx == CMD_enew)
- readonlymode = FALSE; /* 'readonly' doesn't make sense in an
- empty buffer */
+ if (eap->cmdidx == CMD_view || eap->cmdidx == CMD_sview) {
+ readonlymode = true;
+ } else if (eap->cmdidx == CMD_enew) {
+ readonlymode = false; // 'readonly' doesn't make sense
+ // in an empty buffer
+ }
if (eap->cmdidx != CMD_balt && eap->cmdidx != CMD_badd) {
setpcmark();
}
@@ -7392,12 +7529,14 @@ do_exedit(
}
readonlymode = n;
} else {
- if (eap->do_ecmd_cmd != NULL)
+ if (eap->do_ecmd_cmd != NULL) {
do_cmdline_cmd((char *)eap->do_ecmd_cmd);
+ }
n = curwin->w_arg_idx_invalid;
check_arg_idx(curwin);
- if (n != curwin->w_arg_idx_invalid)
+ if (n != curwin->w_arg_idx_invalid) {
maketitle();
+ }
}
/*
@@ -7409,10 +7548,11 @@ do_exedit(
&& curwin != old_curwin
&& win_valid(old_curwin)
&& old_curwin->w_buffer != curbuf
- && !cmdmod.keepalt)
+ && !cmdmod.keepalt) {
old_curwin->w_alt_fnum = curbuf->b_fnum;
+ }
- ex_no_reprint = TRUE;
+ ex_no_reprint = true;
}
/// ":gui" and ":gvim" when there is no GUI.
@@ -7425,10 +7565,11 @@ static void ex_nogui(exarg_T *eap)
static void ex_swapname(exarg_T *eap)
{
- if (curbuf->b_ml.ml_mfp == NULL || curbuf->b_ml.ml_mfp->mf_fname == NULL)
+ if (curbuf->b_ml.ml_mfp == NULL || curbuf->b_ml.ml_mfp->mf_fname == NULL) {
MSG(_("No swap file"));
- else
+ } else {
msg(curbuf->b_ml.ml_mfp->mf_fname);
+ }
}
/*
@@ -7438,8 +7579,8 @@ static void ex_swapname(exarg_T *eap)
*/
static void ex_syncbind(exarg_T *eap)
{
- win_T *save_curwin = curwin;
- buf_T *save_curbuf = curbuf;
+ win_T *save_curwin = curwin;
+ buf_T *save_curbuf = curbuf;
long topline;
long y;
linenr_T old_linenr = curwin->w_cursor.lnum;
@@ -7475,10 +7616,11 @@ static void ex_syncbind(exarg_T *eap)
if (curwin->w_p_scb) {
curbuf = curwin->w_buffer;
y = topline - curwin->w_topline;
- if (y > 0)
+ if (y > 0) {
scrollup(y, TRUE);
- else
+ } else {
scrolldown(-y, TRUE);
+ }
curwin->w_scbind_pos = topline;
redraw_later(curwin, VALID);
cursor_correct();
@@ -7488,7 +7630,7 @@ static void ex_syncbind(exarg_T *eap)
curwin = save_curwin;
curbuf = save_curbuf;
if (curwin->w_p_scb) {
- did_syncbind = TRUE;
+ did_syncbind = true;
checkpcmark();
if (old_linenr != curwin->w_cursor.lnum) {
char_u ctrl_o[2];
@@ -7519,13 +7661,13 @@ static void ex_read(exarg_T *eap)
return;
}
i = readfile(curbuf->b_ffname, curbuf->b_fname,
- eap->line2, (linenr_T)0, (linenr_T)MAXLNUM, eap, 0);
+ eap->line2, (linenr_T)0, (linenr_T)MAXLNUM, eap, 0);
} else {
- if (vim_strchr(p_cpo, CPO_ALTREAD) != NULL)
+ if (vim_strchr(p_cpo, CPO_ALTREAD) != NULL) {
(void)setaltfname(eap->arg, eap->arg, (linenr_T)1);
+ }
i = readfile(eap->arg, NULL,
- eap->line2, (linenr_T)0, (linenr_T)MAXLNUM, eap, 0);
-
+ eap->line2, (linenr_T)0, (linenr_T)MAXLNUM, eap, 0);
}
if (i != OK) {
if (!aborting()) {
@@ -7535,10 +7677,11 @@ static void ex_read(exarg_T *eap)
if (empty && exmode_active) {
/* Delete the empty line that remains. Historically ex does
* this but vi doesn't. */
- if (eap->line2 == 0)
+ if (eap->line2 == 0) {
lnum = curbuf->b_ml.ml_line_count;
- else
+ } else {
lnum = 1;
+ }
if (*ml_get(lnum) == NUL && u_savedel(lnum, 1L) == OK) {
ml_delete(lnum, false);
if (curwin->w_cursor.lnum > 1
@@ -7553,7 +7696,7 @@ static void ex_read(exarg_T *eap)
}
}
-static char_u *prev_dir = NULL;
+static char_u *prev_dir = NULL;
#if defined(EXITFREE)
void free_cd_dir(void)
@@ -7613,21 +7756,22 @@ void post_chdir(CdScope scope, bool trigger_dirchanged)
/// `:cd`, `:tcd`, `:lcd`, `:chdir`, `:tchdir` and `:lchdir`.
void ex_cd(exarg_T *eap)
{
- char_u *new_dir;
- char_u *tofree;
+ char_u *new_dir;
+ char_u *tofree;
new_dir = eap->arg;
#if !defined(UNIX)
- /* for non-UNIX ":cd" means: print current directory */
- if (*new_dir == NUL)
+ // for non-UNIX ":cd" means: print current directory
+ if (*new_dir == NUL) {
ex_pwd(NULL);
- else
+ } else
#endif
{
- if (allbuf_locked())
+ if (allbuf_locked()) {
return;
+ }
- /* ":cd -": Change to previous directory */
+ // ":cd -": Change to previous directory
if (STRCMP(new_dir, "-") == 0) {
if (prev_dir == NULL) {
EMSG(_("E186: No previous directory"));
@@ -7636,12 +7780,13 @@ void ex_cd(exarg_T *eap)
new_dir = prev_dir;
}
- /* Save current directory for next ":cd -" */
+ // Save current directory for next ":cd -"
tofree = prev_dir;
- if (os_dirname(NameBuff, MAXPATHL) == OK)
+ if (os_dirname(NameBuff, MAXPATHL) == OK) {
prev_dir = vim_strsave(NameBuff);
- else
+ } else {
prev_dir = NULL;
+ }
#if defined(UNIX)
// On Unix ":cd" means: go to home directory.
@@ -7690,8 +7835,9 @@ static void ex_pwd(exarg_T *eap)
slash_adjust(NameBuff);
#endif
msg(NameBuff);
- } else
+ } else {
EMSG(_("E187: Unknown"));
+ }
}
/*
@@ -7710,15 +7856,19 @@ static void ex_sleep(exarg_T *eap)
if (cursor_valid()) {
n = curwin->w_winrow + curwin->w_wrow - msg_scrolled;
- if (n >= 0)
+ if (n >= 0) {
ui_cursor_goto(n, curwin->w_wincol + curwin->w_wcol);
+ }
}
len = eap->line2;
switch (*eap->arg) {
- case 'm': break;
- case NUL: len *= 1000L; break;
- default: EMSG2(_(e_invarg2), eap->arg); return;
+ case 'm':
+ break;
+ case NUL:
+ len *= 1000L; break;
+ default:
+ EMSG2(_(e_invarg2), eap->arg); return;
}
do_sleep(len);
}
@@ -7745,16 +7895,18 @@ void do_sleep(long msec)
static void do_exmap(exarg_T *eap, int isabbrev)
{
int mode;
- char_u *cmdp;
+ char_u *cmdp;
cmdp = eap->cmd;
mode = get_map_mode(&cmdp, eap->forceit || isabbrev);
switch (do_map((*cmdp == 'n') ? 2 : (*cmdp == 'u'),
- eap->arg, mode, isabbrev)) {
- case 1: EMSG(_(e_invarg));
+ eap->arg, mode, isabbrev)) {
+ case 1:
+ EMSG(_(e_invarg));
break;
- case 2: EMSG(isabbrev ? _(e_noabbr) : _(e_nomap));
+ case 2:
+ EMSG(isabbrev ? _(e_noabbr) : _(e_nomap));
break;
}
}
@@ -7784,25 +7936,26 @@ static void ex_winsize(exarg_T *eap)
static void ex_wincmd(exarg_T *eap)
{
int xchar = NUL;
- char_u *p;
+ char_u *p;
if (*eap->arg == 'g' || *eap->arg == Ctrl_G) {
- /* CTRL-W g and CTRL-W CTRL-G have an extra command character */
+ // CTRL-W g and CTRL-W CTRL-G have an extra command character
if (eap->arg[1] == NUL) {
EMSG(_(e_invarg));
return;
}
xchar = eap->arg[1];
p = eap->arg + 2;
- } else
+ } else {
p = eap->arg + 1;
+ }
eap->nextcmd = check_nextcmd(p);
p = skipwhite(p);
- if (*p != NUL && *p != '"' && eap->nextcmd == NULL)
+ if (*p != NUL && *p != '"' && eap->nextcmd == NULL) {
EMSG(_(e_invarg));
- else if (!eap->skip) {
- /* Pass flags on for ":vertical wincmd ]". */
+ } else if (!eap->skip) {
+ // Pass flags on for ":vertical wincmd ]".
postponed_split_flags = cmdmod.split;
postponed_split_tab = cmdmod.tab;
do_window(*eap->arg, eap->addr_count > 0 ? eap->line2 : 0L, xchar);
@@ -7831,8 +7984,9 @@ static void ex_operators(exarg_T *eap)
beginline(BL_SOL | BL_FIX);
}
- if (VIsual_active)
+ if (VIsual_active) {
end_visual_mode();
+ }
switch (eap->cmdidx) {
case CMD_delete:
@@ -7845,13 +7999,14 @@ static void ex_operators(exarg_T *eap)
(void)op_yank(&oa, true, false);
break;
- default: /* CMD_rshift or CMD_lshift */
+ default: // CMD_rshift or CMD_lshift
if (
- (eap->cmdidx == CMD_rshift) ^ curwin->w_p_rl
- )
+ (eap->cmdidx == CMD_rshift) ^ curwin->w_p_rl
+ ) {
oa.op_type = OP_RSHIFT;
- else
+ } else {
oa.op_type = OP_LSHIFT;
+ }
op_shift(&oa, FALSE, eap->amount);
break;
}
@@ -7864,7 +8019,7 @@ static void ex_operators(exarg_T *eap)
*/
static void ex_put(exarg_T *eap)
{
- /* ":0put" works like ":1put!". */
+ // ":0put" works like ":1put!".
if (eap->line2 == 0) {
eap->line2 = 1;
eap->forceit = TRUE;
@@ -7895,10 +8050,12 @@ static void ex_copymove(exarg_T *eap)
}
if (eap->cmdidx == CMD_move) {
- if (do_move(eap->line1, eap->line2, n) == FAIL)
+ if (do_move(eap->line1, eap->line2, n) == FAIL) {
return;
- } else
+ }
+ } else {
ex_copy(eap->line1, eap->line2, n);
+ }
u_clearline();
beginline(BL_SOL | BL_FIX);
ex_may_print(eap);
@@ -7911,8 +8068,8 @@ void ex_may_print(exarg_T *eap)
{
if (eap->flags != 0) {
print_line(curwin->w_cursor.lnum, (eap->flags & EXFLAG_NR),
- (eap->flags & EXFLAG_LIST));
- ex_no_reprint = TRUE;
+ (eap->flags & EXFLAG_LIST));
+ ex_no_reprint = true;
}
}
@@ -7933,8 +8090,9 @@ static void ex_join(exarg_T *eap)
{
curwin->w_cursor.lnum = eap->line1;
if (eap->line1 == eap->line2) {
- if (eap->addr_count >= 2) /* :2,2join does nothing */
+ if (eap->addr_count >= 2) { // :2,2join does nothing
return;
+ }
if (eap->line2 == curbuf->b_ml.ml_line_count) {
beep_flush();
return;
@@ -7962,22 +8120,23 @@ static void ex_at(exarg_T *eap)
c = '@';
}
- /* Put the register in the typeahead buffer with the "silent" flag. */
+ // Put the register in the typeahead buffer with the "silent" flag.
if (do_execreg(c, TRUE, vim_strchr(p_cpo, CPO_EXECBUF) != NULL, TRUE)
== FAIL) {
beep_flush();
} else {
- int save_efr = exec_from_reg;
+ bool save_efr = exec_from_reg;
- exec_from_reg = TRUE;
+ exec_from_reg = true;
/*
* Execute from the typeahead buffer.
* Continue until the stuff buffer is empty and all added characters
* have been consumed.
*/
- while (!stuff_empty() || typebuf.tb_len > prev_len)
+ while (!stuff_empty() || typebuf.tb_len > prev_len) {
(void)do_cmdline(NULL, getexline, NULL, DOCMD_NOWAIT|DOCMD_VERBOSE);
+ }
exec_from_reg = save_efr;
}
@@ -8007,16 +8166,16 @@ static void ex_wundo(exarg_T *eap)
{
char_u hash[UNDO_HASH_SIZE];
- u_compute_hash(hash);
- u_write_undo((char *) eap->arg, eap->forceit, curbuf, hash);
+ u_compute_hash(curbuf, hash);
+ u_write_undo((char *)eap->arg, eap->forceit, curbuf, hash);
}
static void ex_rundo(exarg_T *eap)
{
char_u hash[UNDO_HASH_SIZE];
- u_compute_hash(hash);
- u_read_undo((char *) eap->arg, hash, NULL);
+ u_compute_hash(curbuf, hash);
+ u_read_undo((char *)eap->arg, hash, NULL);
}
/// ":redo".
@@ -8031,18 +8190,23 @@ static void ex_later(exarg_T *eap)
long count = 0;
bool sec = false;
bool file = false;
- char_u *p = eap->arg;
+ char_u *p = eap->arg;
if (*p == NUL) {
count = 1;
} else if (isdigit(*p)) {
count = getdigits_long(&p, false, 0);
switch (*p) {
- case 's': ++p; sec = true; break;
- case 'm': ++p; sec = true; count *= 60; break;
- case 'h': ++p; sec = true; count *= 60 * 60; break;
- case 'd': ++p; sec = true; count *= 24 * 60 * 60; break;
- case 'f': ++p; file = true; break;
+ case 's':
+ ++p; sec = true; break;
+ case 'm':
+ ++p; sec = true; count *= 60; break;
+ case 'h':
+ ++p; sec = true; count *= 60 * 60; break;
+ case 'd':
+ ++p; sec = true; count *= 24 * 60 * 60; break;
+ case 'f':
+ ++p; file = true; break;
}
}
@@ -8059,43 +8223,46 @@ static void ex_later(exarg_T *eap)
*/
static void ex_redir(exarg_T *eap)
{
- char *mode;
- char_u *fname;
- char_u *arg = eap->arg;
+ char *mode;
+ char_u *fname;
+ char_u *arg = eap->arg;
- if (STRICMP(eap->arg, "END") == 0)
+ if (STRICMP(eap->arg, "END") == 0) {
close_redir();
- else {
+ } else {
if (*arg == '>') {
++arg;
if (*arg == '>') {
++arg;
mode = "a";
- } else
+ } else {
mode = "w";
+ }
arg = skipwhite(arg);
close_redir();
- /* Expand environment variables and "~/". */
+ // Expand environment variables and "~/".
fname = expand_env_save(arg);
- if (fname == NULL)
+ if (fname == NULL) {
return;
+ }
redir_fd = open_exfile(fname, eap->forceit, mode);
xfree(fname);
} else if (*arg == '@') {
- /* redirect to a register a-z (resp. A-Z for appending) */
+ // redirect to a register a-z (resp. A-Z for appending)
close_redir();
++arg;
if (valid_yank_reg(*arg, true) && *arg != '_') {
redir_reg = *arg++;
- if (*arg == '>' && arg[1] == '>') /* append */
+ if (*arg == '>' && arg[1] == '>') { // append
arg += 2;
- else {
- /* Can use both "@a" and "@a>". */
- if (*arg == '>')
+ } else {
+ // Can use both "@a" and "@a>".
+ if (*arg == '>') {
arg++;
+ }
// Make register empty when not using @A-@Z and the
// command is valid.
if (*arg == NUL && !isupper(redir_reg)) {
@@ -8110,30 +8277,33 @@ static void ex_redir(exarg_T *eap)
} else if (*arg == '=' && arg[1] == '>') {
int append;
- /* redirect to a variable */
+ // redirect to a variable
close_redir();
arg += 2;
if (*arg == '>') {
++arg;
append = TRUE;
- } else
+ } else {
append = FALSE;
+ }
- if (var_redir_start(skipwhite(arg), append) == OK)
+ if (var_redir_start(skipwhite(arg), append) == OK) {
redir_vname = 1;
+ }
}
- /* TODO: redirect to a buffer */
- else
+ // TODO: redirect to a buffer
+ else {
EMSG2(_(e_invarg2), eap->arg);
+ }
}
/* Make sure redirection is not off. Can happen for cmdline completion
* that indirectly invokes a command to catch its output. */
if (redir_fd != NULL
- || redir_reg || redir_vname
- )
- redir_off = FALSE;
+ || redir_reg || redir_vname) {
+ redir_off = false;
+ }
}
/// ":redraw": force redraw
@@ -8153,19 +8323,19 @@ static void ex_redraw(exarg_T *eap)
redraw_all_later(NOT_VALID);
}
update_screen(eap->forceit ? NOT_VALID
- : VIsual_active ? INVERTED : 0);
+ : VIsual_active ? INVERTED : 0);
if (need_maketitle) {
maketitle();
}
RedrawingDisabled = r;
p_lz = p;
- /* Reset msg_didout, so that a message that's there is overwritten. */
- msg_didout = FALSE;
+ // Reset msg_didout, so that a message that's there is overwritten.
+ msg_didout = false;
msg_col = 0;
- /* No need to wait after an intentional redraw. */
- need_wait_return = FALSE;
+ // No need to wait after an intentional redraw.
+ need_wait_return = false;
ui_flush();
}
@@ -8181,13 +8351,13 @@ static void ex_redrawstatus(exarg_T *eap)
RedrawingDisabled = 0;
p_lz = FALSE;
- if (eap->forceit)
+ if (eap->forceit) {
status_redraw_all();
- else
+ } else {
status_redraw_curbuf();
- update_screen(
- VIsual_active ? INVERTED :
- 0);
+ }
+ update_screen(VIsual_active ? INVERTED :
+ 0);
RedrawingDisabled = r;
p_lz = p;
ui_flush();
@@ -8239,21 +8409,17 @@ int vim_mkdir_emsg(const char *const name, const int prot)
return OK;
}
-/*
- * Open a file for writing for an Ex command, with some checks.
- * Return file descriptor, or NULL on failure.
- */
-FILE *
-open_exfile (
- char_u *fname,
- int forceit,
- char *mode /* "w" for create new file or "a" for append */
-)
+/// Open a file for writing for an Ex command, with some checks.
+///
+/// @param mode "w" for create new file or "a" for append
+///
+/// @return file descriptor, or NULL on failure.
+FILE *open_exfile(char_u *fname, int forceit, char *mode)
{
- FILE *fd;
+ FILE *fd;
#ifdef UNIX
- /* with Unix it is possible to open a directory */
+ // with Unix it is possible to open a directory
if (os_isdir(fname)) {
EMSG2(_(e_isadir2), fname);
return NULL;
@@ -8278,17 +8444,18 @@ static void ex_mark(exarg_T *eap)
{
pos_T pos;
- if (*eap->arg == NUL) /* No argument? */
+ if (*eap->arg == NUL) { // No argument?
EMSG(_(e_argreq));
- else if (eap->arg[1] != NUL) /* more than one character? */
+ } else if (eap->arg[1] != NUL) { // more than one character?
EMSG(_(e_trailing));
- else {
- pos = curwin->w_cursor; /* save curwin->w_cursor */
+ } else {
+ pos = curwin->w_cursor; // save curwin->w_cursor
curwin->w_cursor.lnum = eap->line2;
beginline(BL_WHITE | BL_FIX);
- if (setmark(*eap->arg) == FAIL) /* set mark */
+ if (setmark(*eap->arg) == FAIL) { // set mark
EMSG(_("E191: Argument must be a letter or forward/backward quote"));
- curwin->w_cursor = pos; /* restore curwin->w_cursor */
+ }
+ curwin->w_cursor = pos; // restore curwin->w_cursor
}
}
@@ -8348,7 +8515,9 @@ void restore_current_state(save_state_T *sst)
finish_op = sst->save_finish_op;
opcount = sst->save_opcount;
reg_executing = sst->save_reg_executing;
- msg_didout |= sst->save_msg_didout; // don't reset msg_didout now
+
+ // don't reset msg_didout now
+ msg_didout |= sst->save_msg_didout;
// Restore the state (needed when called from a function executed for
// 'indentexpr'). Update the mouse and cursor, they may have changed.
@@ -8366,9 +8535,9 @@ static void ex_normal(exarg_T *eap)
return;
}
save_state_T save_state;
- char_u *arg = NULL;
+ char_u *arg = NULL;
int l;
- char_u *p;
+ char_u *p;
if (ex_normal_lock > 0) {
EMSG(_(e_secure));
@@ -8385,12 +8554,14 @@ static void ex_normal(exarg_T *eap)
{
int len = 0;
- /* Count the number of characters to be escaped. */
+ // Count the number of characters to be escaped.
for (p = eap->arg; *p != NUL; ++p) {
- for (l = (*mb_ptr2len)(p) - 1; l > 0; --l)
- if (*++p == K_SPECIAL /* trailbyte K_SPECIAL or CSI */
- )
+ for (l = (*mb_ptr2len)(p) - 1; l > 0; --l) {
+ if (*++p == K_SPECIAL // trailbyte K_SPECIAL or CSI
+ ) {
len += 2;
+ }
+ }
}
if (len > 0) {
arg = xmalloc(STRLEN(eap->arg) + len + 1);
@@ -8426,7 +8597,7 @@ static void ex_normal(exarg_T *eap)
} while (eap->addr_count > 0 && eap->line1 <= eap->line2 && !got_int);
}
- /* Might not return to the main loop when in an event handler. */
+ // Might not return to the main loop when in an event handler.
update_topline_cursor();
restore_current_state(&save_state);
@@ -8457,16 +8628,18 @@ static void ex_startinsert(exarg_T *eap)
return;
}
- if (eap->cmdidx == CMD_startinsert)
+ if (eap->cmdidx == CMD_startinsert) {
restart_edit = 'a';
- else if (eap->cmdidx == CMD_startreplace)
+ } else if (eap->cmdidx == CMD_startreplace) {
restart_edit = 'R';
- else
+ } else {
restart_edit = 'V';
+ }
if (!eap->forceit) {
- if (eap->cmdidx == CMD_startinsert)
+ if (eap->cmdidx == CMD_startinsert) {
restart_edit = 'i';
+ }
curwin->w_curswant = 0; // avoid MAXCOL
}
@@ -8516,7 +8689,7 @@ void exec_normal(bool was_typed)
static void ex_checkpath(exarg_T *eap)
{
- find_pattern_in_path(NULL, 0, 0, FALSE, FALSE, CHECK_PATH, 1L,
+ find_pattern_in_path(NULL, 0, 0, false, false, CHECK_PATH, 1L,
eap->forceit ? ACTION_SHOW_ALL : ACTION_SHOW,
(linenr_T)1, (linenr_T)MAXLNUM);
}
@@ -8533,25 +8706,26 @@ static void ex_psearch(exarg_T *eap)
static void ex_findpat(exarg_T *eap)
{
- int whole = TRUE;
+ bool whole = true;
long n;
- char_u *p;
+ char_u *p;
int action;
switch (cmdnames[eap->cmdidx].cmd_name[2]) {
- case 'e': /* ":psearch", ":isearch" and ":dsearch" */
- if (cmdnames[eap->cmdidx].cmd_name[0] == 'p')
+ case 'e': // ":psearch", ":isearch" and ":dsearch"
+ if (cmdnames[eap->cmdidx].cmd_name[0] == 'p') {
action = ACTION_GOTO;
- else
+ } else {
action = ACTION_SHOW;
+ }
break;
- case 'i': /* ":ilist" and ":dlist" */
+ case 'i': // ":ilist" and ":dlist"
action = ACTION_SHOW_ALL;
break;
- case 'u': /* ":ijump" and ":djump" */
+ case 'u': // ":ijump" and ":djump"
action = ACTION_GOTO;
break;
- default: /* ":isplit" and ":dsplit" */
+ default: // ":isplit" and ":dsplit"
action = ACTION_SPLIT;
break;
}
@@ -8577,10 +8751,11 @@ static void ex_findpat(exarg_T *eap)
}
}
}
- if (!eap->skip)
+ if (!eap->skip) {
find_pattern_in_path(eap->arg, 0, STRLEN(eap->arg), whole, !eap->forceit,
*eap->cmd == 'd' ? FIND_DEFINE : FIND_ANY,
n, action, eap->line1, eap->line2);
+ }
}
@@ -8589,7 +8764,7 @@ static void ex_findpat(exarg_T *eap)
*/
static void ex_ptag(exarg_T *eap)
{
- g_do_tagpreview = p_pvh; /* will be reset to 0 in ex_tag_cmd() */
+ g_do_tagpreview = p_pvh; // will be reset to 0 in ex_tag_cmd()
ex_tag_cmd(eap, cmdnames[eap->cmdidx].cmd_name + 1);
}
@@ -8598,7 +8773,7 @@ static void ex_ptag(exarg_T *eap)
*/
static void ex_pedit(exarg_T *eap)
{
- win_T *curwin_save = curwin;
+ win_T *curwin_save = curwin;
// Open the preview window or popup and make it the current window.
g_do_tagpreview = p_pvh;
@@ -8642,21 +8817,28 @@ static void ex_tag_cmd(exarg_T *eap, char_u *name)
int cmd;
switch (name[1]) {
- case 'j': cmd = DT_JUMP; // ":tjump"
+ case 'j':
+ cmd = DT_JUMP; // ":tjump"
break;
- case 's': cmd = DT_SELECT; // ":tselect"
+ case 's':
+ cmd = DT_SELECT; // ":tselect"
break;
case 'p': // ":tprevious"
- case 'N': cmd = DT_PREV; // ":tNext"
+ case 'N':
+ cmd = DT_PREV; // ":tNext"
break;
- case 'n': cmd = DT_NEXT; // ":tnext"
+ case 'n':
+ cmd = DT_NEXT; // ":tnext"
break;
- case 'o': cmd = DT_POP; // ":pop"
+ case 'o':
+ cmd = DT_POP; // ":pop"
break;
case 'f': // ":tfirst"
- case 'r': cmd = DT_FIRST; // ":trewind"
+ case 'r':
+ cmd = DT_FIRST; // ":trewind"
break;
- case 'l': cmd = DT_LAST; // ":tlast"
+ case 'l':
+ cmd = DT_LAST; // ":tlast"
break;
default: // ":tag"
if (p_cst && *eap->arg != NUL) {
@@ -8672,7 +8854,7 @@ static void ex_tag_cmd(exarg_T *eap, char_u *name)
}
do_tag(eap->arg, cmd, eap->addr_count > 0 ? (int)eap->line2 : 1,
- eap->forceit, TRUE);
+ eap->forceit, TRUE);
}
enum {
@@ -8731,58 +8913,57 @@ ssize_t find_cmdline_var(const char_u *src, size_t *usedlen)
return -1;
}
-/*
- * Evaluate cmdline variables.
- *
- * change '%' to curbuf->b_ffname
- * '#' to curwin->w_alt_fnum
- * '<cword>' to word under the cursor
- * '<cWORD>' to WORD under the cursor
- * '<cexpr>' to C-expression under the cursor
- * '<cfile>' to path name under the cursor
- * '<sfile>' to sourced file name
- * '<slnum>' to sourced file line number
- * '<afile>' to file name for autocommand
- * '<abuf>' to buffer number for autocommand
- * '<amatch>' to matching name for autocommand
- *
- * When an error is detected, "errormsg" is set to a non-NULL pointer (may be
- * "" for error without a message) and NULL is returned.
- * Returns an allocated string if a valid match was found.
- * Returns NULL if no match was found. "usedlen" then still contains the
- * number of characters to skip.
- */
-char_u *
-eval_vars (
- char_u *src, /* pointer into commandline */
- char_u *srcstart, /* beginning of valid memory for src */
- size_t *usedlen, /* characters after src that are used */
- linenr_T *lnump, /* line number for :e command, or NULL */
- char_u **errormsg, /* pointer to error message */
- int *escaped /* return value has escaped white space (can
- * be NULL) */
-)
+/// Evaluate cmdline variables.
+///
+/// change '%' to curbuf->b_ffname
+/// '#' to curwin->w_alt_fnum
+/// '<cword>' to word under the cursor
+/// '<cWORD>' to WORD under the cursor
+/// '<cexpr>' to C-expression under the cursor
+/// '<cfile>' to path name under the cursor
+/// '<sfile>' to sourced file name
+/// '<slnum>' to sourced file line number
+/// '<afile>' to file name for autocommand
+/// '<abuf>' to buffer number for autocommand
+/// '<amatch>' to matching name for autocommand
+///
+/// When an error is detected, "errormsg" is set to a non-NULL pointer (may be
+/// "" for error without a message) and NULL is returned.
+///
+/// @param src pointer into commandline
+/// @param srcstart beginning of valid memory for src
+/// @param usedlen characters after src that are used
+/// @param lnump line number for :e command, or NULL
+/// @param errormsg pointer to error message
+/// @param escaped return value has escaped white space (can be NULL)
+///
+/// @return an allocated string if a valid match was found.
+/// Returns NULL if no match was found. "usedlen" then still contains the
+/// number of characters to skip.
+char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnump,
+ char_u **errormsg, int *escaped)
{
int i;
- char_u *s;
- char_u *result;
- char_u *resultbuf = NULL;
+ char_u *s;
+ char_u *result;
+ char_u *resultbuf = NULL;
size_t resultlen;
- buf_T *buf;
+ buf_T *buf;
int valid = VALID_HEAD | VALID_PATH; // Assume valid result.
bool tilde_file = false;
- int skip_mod = false;
+ bool skip_mod = false;
char strbuf[30];
*errormsg = NULL;
- if (escaped != NULL)
+ if (escaped != NULL) {
*escaped = FALSE;
+ }
/*
* Check if there is something to do.
*/
ssize_t spec_idx = find_cmdline_var(src, usedlen);
- if (spec_idx < 0) { /* no match */
+ if (spec_idx < 0) { // no match
*usedlen = 1;
return NULL;
}
@@ -8793,7 +8974,7 @@ eval_vars (
*/
if (src > srcstart && src[-1] == '\\') {
*usedlen = 0;
- STRMOVE(src - 1, src); /* remove backslash */
+ STRMOVE(src - 1, src); // remove backslash
return NULL;
}
@@ -8803,9 +8984,8 @@ eval_vars (
if (spec_idx == SPEC_CWORD
|| spec_idx == SPEC_CCWORD
|| spec_idx == SPEC_CEXPR) {
- resultlen = find_ident_under_cursor(
- &result,
- spec_idx == SPEC_CWORD
+ resultlen = find_ident_under_cursor(&result,
+ spec_idx == SPEC_CWORD
? (FIND_IDENT | FIND_STRING)
: (spec_idx == SPEC_CEXPR
? (FIND_IDENT | FIND_STRING | FIND_EVAL)
@@ -8814,13 +8994,13 @@ eval_vars (
*errormsg = (char_u *)"";
return NULL;
}
- //
- // '#': Alternate file name
- // '%': Current file name
- // File name under the cursor
- // File name for autocommand
- // and following modifiers
- //
+ //
+ // '#': Alternate file name
+ // '%': Current file name
+ // File name under the cursor
+ // File name for autocommand
+ // and following modifiers
+ //
} else {
switch (spec_idx) {
case SPEC_PERC: // '%': current file
@@ -8833,14 +9013,15 @@ eval_vars (
}
break;
- case SPEC_HASH: /* '#' or "#99": alternate file */
- if (src[1] == '#') { /* "##": the argument list */
+ case SPEC_HASH: // '#' or "#99": alternate file
+ if (src[1] == '#') { // "##": the argument list
result = arg_all();
resultbuf = result;
*usedlen = 2;
- if (escaped != NULL)
+ if (escaped != NULL) {
*escaped = TRUE;
- skip_mod = TRUE;
+ }
+ skip_mod = true;
break;
}
s = src + 1;
@@ -8856,7 +9037,7 @@ eval_vars (
if (src[1] == '<' && i != 0) {
if (*usedlen < 2) {
- /* Should we give an error message for #<text? */
+ // Should we give an error message for #<text?
*usedlen = 1;
return NULL;
}
@@ -8872,12 +9053,12 @@ eval_vars (
}
buf = buflist_findnr(i);
if (buf == NULL) {
- *errormsg = (char_u *)_(
- "E194: No alternate file name to substitute for '#'");
+ *errormsg = (char_u *)_("E194: No alternate file name to substitute for '#'");
return NULL;
}
- if (lnump != NULL)
+ if (lnump != NULL) {
*lnump = ECMD_LAST;
+ }
if (buf->b_fname == NULL) {
result = (char_u *)"";
valid = 0; // Must have ":p:h" to be valid
@@ -8888,13 +9069,13 @@ eval_vars (
}
break;
- case SPEC_CFILE: /* file name under cursor */
+ case SPEC_CFILE: // file name under cursor
result = file_name_at_cursor(FNAME_MESS|FNAME_HYP, 1L, NULL);
if (result == NULL) {
*errormsg = (char_u *)"";
return NULL;
}
- resultbuf = result; /* remember allocated string */
+ resultbuf = result; // remember allocated string
break;
case SPEC_AFILE: // file name for autocommand
@@ -8911,37 +9092,33 @@ eval_vars (
}
result = autocmd_fname;
if (result == NULL) {
- *errormsg = (char_u *)_(
- "E495: no autocommand file name to substitute for \"<afile>\"");
+ *errormsg = (char_u *)_("E495: no autocommand file name to substitute for \"<afile>\"");
return NULL;
}
result = path_try_shorten_fname(result);
break;
- case SPEC_ABUF: /* buffer number for autocommand */
+ case SPEC_ABUF: // buffer number for autocommand
if (autocmd_bufnr <= 0) {
- *errormsg = (char_u *)_(
- "E496: no autocommand buffer number to substitute for \"<abuf>\"");
+ *errormsg = (char_u *)_("E496: no autocommand buffer number to substitute for \"<abuf>\"");
return NULL;
}
snprintf(strbuf, sizeof(strbuf), "%d", autocmd_bufnr);
result = (char_u *)strbuf;
break;
- case SPEC_AMATCH: /* match name for autocommand */
+ case SPEC_AMATCH: // match name for autocommand
result = autocmd_match;
if (result == NULL) {
- *errormsg = (char_u *)_(
- "E497: no autocommand match name to substitute for \"<amatch>\"");
+ *errormsg = (char_u *)_("E497: no autocommand match name to substitute for \"<amatch>\"");
return NULL;
}
break;
- case SPEC_SFILE: /* file name for ":so" command */
+ case SPEC_SFILE: // file name for ":so" command
result = sourcing_name;
if (result == NULL) {
- *errormsg = (char_u *)_(
- "E498: no :source file name to substitute for \"<sfile>\"");
+ *errormsg = (char_u *)_("E498: no :source file name to substitute for \"<sfile>\"");
return NULL;
}
break;
@@ -9001,15 +9178,16 @@ eval_vars (
}
if (resultlen == 0 || valid != VALID_HEAD + VALID_PATH) {
- if (valid != VALID_HEAD + VALID_PATH)
- /* xgettext:no-c-format */
- *errormsg = (char_u *)_(
- "E499: Empty file name for '%' or '#', only works with \":p:h\"");
- else
+ if (valid != VALID_HEAD + VALID_PATH) {
+ // xgettext:no-c-format
+ *errormsg = (char_u *)_("E499: Empty file name for '%' or '#', only works with \":p:h\"");
+ } else {
*errormsg = (char_u *)_("E500: Evaluates to an empty string");
+ }
result = NULL;
- } else
+ } else {
result = vim_strnsave(result, resultlen);
+ }
xfree(resultbuf);
return result;
}
@@ -9023,8 +9201,8 @@ static char_u *arg_all(void)
{
int len;
int idx;
- char_u *retval = NULL;
- char_u *p;
+ char_u *retval = NULL;
+ char_u *p;
/*
* Do this loop two times:
@@ -9039,9 +9217,10 @@ static char_u *arg_all(void)
continue;
}
if (len > 0) {
- /* insert a space in between names */
- if (retval != NULL)
+ // insert a space in between names
+ if (retval != NULL) {
retval[len] = ' ';
+ }
++len;
}
for (; *p != NUL; p++) {
@@ -9063,13 +9242,13 @@ static char_u *arg_all(void)
}
}
- /* second time: break here */
+ // second time: break here
if (retval != NULL) {
retval[len] = NUL;
break;
}
- /* allocate memory */
+ // allocate memory
retval = xmalloc(len + 1);
}
@@ -9083,29 +9262,30 @@ static char_u *arg_all(void)
*/
char_u *expand_sfile(char_u *arg)
{
- char_u *errormsg;
+ char_u *errormsg;
size_t len;
- char_u *result;
- char_u *newres;
- char_u *repl;
+ char_u *result;
+ char_u *newres;
+ char_u *repl;
size_t srclen;
- char_u *p;
+ char_u *p;
result = vim_strsave(arg);
for (p = result; *p; ) {
- if (STRNCMP(p, "<sfile>", 7) != 0)
+ if (STRNCMP(p, "<sfile>", 7) != 0) {
++p;
- else {
- /* replace "<sfile>" with the sourced file name, and do ":" stuff */
+ } else {
+ // replace "<sfile>" with the sourced file name, and do ":" stuff
repl = eval_vars(p, result, &srclen, NULL, &errormsg, NULL);
if (errormsg != NULL) {
- if (*errormsg)
+ if (*errormsg) {
emsg(errormsg);
+ }
xfree(result);
return NULL;
}
- if (repl == NULL) { /* no match (cannot happen) */
+ if (repl == NULL) { // no match (cannot happen)
p += srclen;
continue;
}
@@ -9118,7 +9298,7 @@ char_u *expand_sfile(char_u *arg)
xfree(repl);
xfree(result);
result = newres;
- p = newres + len; /* continue after the match */
+ p = newres + len; // continue after the match
}
}
@@ -9130,15 +9310,16 @@ char_u *expand_sfile(char_u *arg)
*/
static void ex_shada(exarg_T *eap)
{
- char_u *save_shada;
+ char_u *save_shada;
save_shada = p_shada;
- if (*p_shada == NUL)
+ if (*p_shada == NUL) {
p_shada = (char_u *)"'100";
+ }
if (eap->cmdidx == CMD_rviminfo || eap->cmdidx == CMD_rshada) {
- (void) shada_read_everything((char *) eap->arg, eap->forceit, false);
+ (void)shada_read_everything((char *)eap->arg, eap->forceit, false);
} else {
- shada_write_file((char *) eap->arg, eap->forceit);
+ shada_write_file((char *)eap->arg, eap->forceit);
}
p_shada = save_shada;
}
@@ -9149,8 +9330,9 @@ static void ex_shada(exarg_T *eap)
*/
void dialog_msg(char_u *buff, char *format, char_u *fname)
{
- if (fname == NULL)
+ if (fname == NULL) {
fname = (char_u *)_("Untitled");
+ }
vim_snprintf((char *)buff, DIALOG_MSG_SIZE, format, fname);
}
@@ -9180,10 +9362,12 @@ static void ex_behave(exarg_T *eap)
*/
char_u *get_behave_arg(expand_T *xp, int idx)
{
- if (idx == 0)
+ if (idx == 0) {
return (char_u *)"mswin";
- if (idx == 1)
+ }
+ if (idx == 1) {
return (char_u *)"xterm";
+ }
return NULL;
}
@@ -9220,12 +9404,12 @@ static TriState filetype_indent = kNone;
*/
static void ex_filetype(exarg_T *eap)
{
- char_u *arg = eap->arg;
+ char_u *arg = eap->arg;
bool plugin = false;
bool indent = false;
if (*eap->arg == NUL) {
- /* Print current status. */
+ // Print current status.
smsg("filetype detection:%s plugin:%s indent:%s",
filetype_detect == kTrue ? "ON" : "OFF",
filetype_plugin == kTrue ? (filetype_detect == kTrue ? "ON" : "(on)") : "OFF", // NOLINT(whitespace/line_length)
@@ -9233,7 +9417,7 @@ static void ex_filetype(exarg_T *eap)
return;
}
- /* Accept "plugin" and "indent" in any order. */
+ // Accept "plugin" and "indent" in any order.
for (;; ) {
if (STRNCMP(arg, "plugin", 6) == 0) {
plugin = true;
@@ -9278,8 +9462,9 @@ static void ex_filetype(exarg_T *eap)
source_runtime((char_u *)FTOFF_FILE, DIP_ALL);
filetype_detect = kFalse;
}
- } else
+ } else {
EMSG2(_(e_invarg2), arg);
+ }
}
/// Set all :filetype options ON if user did not explicitly set any to OFF.
@@ -9329,10 +9514,11 @@ static void ex_set(exarg_T *eap)
{
int flags = 0;
- if (eap->cmdidx == CMD_setlocal)
+ if (eap->cmdidx == CMD_setlocal) {
flags = OPT_LOCAL;
- else if (eap->cmdidx == CMD_setglobal)
+ } else if (eap->cmdidx == CMD_setglobal) {
flags = OPT_GLOBAL;
+ }
(void)do_set(eap->arg, flags);
}
@@ -9532,16 +9718,16 @@ bool cmd_can_preview(char_u *cmd)
char_u *end = find_command(&ea, NULL);
switch (ea.cmdidx) {
- case CMD_substitute:
- case CMD_smagic:
- case CMD_snomagic:
- // Only preview once the pattern delimiter has been typed
- if (*end && !ASCII_ISALNUM(*end)) {
- return true;
- }
- break;
- default:
- break;
+ case CMD_substitute:
+ case CMD_smagic:
+ case CMD_snomagic:
+ // Only preview once the pattern delimiter has been typed
+ if (*end && !ASCII_ISALNUM(*end)) {
+ return true;
+ }
+ break;
+ default:
+ break;
}
return false;
@@ -9572,11 +9758,16 @@ Dictionary commands_array(buf_T *buf)
PUT(d, "register", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_REGSTR)));
switch (cmd->uc_argt & (EX_EXTRA | EX_NOSPC | EX_NEEDARG)) {
- case 0: arg[0] = '0'; break;
- case(EX_EXTRA): arg[0] = '*'; break;
- case(EX_EXTRA | EX_NOSPC): arg[0] = '?'; break;
- case(EX_EXTRA | EX_NEEDARG): arg[0] = '+'; break;
- case(EX_EXTRA | EX_NOSPC | EX_NEEDARG): arg[0] = '1'; break;
+ case 0:
+ arg[0] = '0'; break;
+ case (EX_EXTRA):
+ arg[0] = '*'; break;
+ case (EX_EXTRA | EX_NOSPC):
+ arg[0] = '?'; break;
+ case (EX_EXTRA | EX_NEEDARG):
+ arg[0] = '+'; break;
+ case (EX_EXTRA | EX_NOSPC | EX_NEEDARG):
+ arg[0] = '1'; break;
}
PUT(d, "nargs", STRING_OBJ(cstr_to_string(arg)));
diff --git a/src/nvim/ex_docmd.h b/src/nvim/ex_docmd.h
index f6bd2adcd5..8a78ca0337 100644
--- a/src/nvim/ex_docmd.h
+++ b/src/nvim/ex_docmd.h
@@ -11,21 +11,18 @@
#define DOCMD_KEYTYPED 0x08 // don't reset KeyTyped
#define DOCMD_EXCRESET 0x10 // reset exception environment (for debugging
#define DOCMD_KEEPLINE 0x20 // keep typed line for repeating with "."
+#define DOCMD_PREVIEW 0x40 // during 'inccommand' preview
/* defines for eval_vars() */
#define VALID_PATH 1
#define VALID_HEAD 2
-/* Values for exmode_active (0 is no exmode) */
-#define EXMODE_NORMAL 1
-#define EXMODE_VIM 2
-
// Structure used to save the current state. Used when executing Normal mode
// commands while in any other mode.
typedef struct {
int save_msg_scroll;
int save_restart_edit;
- int save_msg_didout;
+ bool save_msg_didout;
int save_State;
int save_insertmode;
bool save_finish_op;
diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c
index 5ca88002f1..21ddf7399b 100644
--- a/src/nvim/ex_eval.c
+++ b/src/nvim/ex_eval.c
@@ -7,22 +7,23 @@
///
/// Functions for Ex command line for the +eval feature.
#include <assert.h>
-#include <stdbool.h>
#include <inttypes.h>
#include <limits.h>
+#include <stdbool.h>
-#include "nvim/vim.h"
#include "nvim/ascii.h"
-#include "nvim/ex_eval.h"
#include "nvim/charset.h"
+#include "nvim/debugger.h"
#include "nvim/eval.h"
#include "nvim/eval/userfunc.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_docmd.h"
-#include "nvim/message.h"
+#include "nvim/ex_eval.h"
#include "nvim/memory.h"
+#include "nvim/message.h"
#include "nvim/regexp.h"
#include "nvim/strings.h"
+#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ex_eval.c.generated.h"
@@ -110,8 +111,9 @@ int aborting(void)
*/
void update_force_abort(void)
{
- if (cause_abort)
+ if (cause_abort) {
force_abort = TRUE;
+ }
}
/*
@@ -210,7 +212,7 @@ bool cause_errthrow(const char_u *mesg, bool severe, bool *ignore)
* not skipped. Errors in those commands may affect what of the subsequent
* commands are regarded part of catch and finally clauses. Catching the
* exception would then cause execution of commands not intended by the
- * user, who wouldn't even get aware of the problem. Therefor, discard the
+ * user, who wouldn't even get aware of the problem. Therefore, discard the
* exception currently being thrown to prevent it from being caught. Just
* execute finally clauses and terminate.
*/
@@ -247,8 +249,9 @@ bool cause_errthrow(const char_u *mesg, bool severe, bool *ignore)
*/
if (msg_list != NULL) {
plist = msg_list;
- while (*plist != NULL)
+ while (*plist != NULL) {
plist = &(*plist)->next;
+ }
elem = xmalloc(sizeof(struct msglist));
elem->msg = vim_strsave(mesg);
@@ -256,19 +259,20 @@ bool cause_errthrow(const char_u *mesg, bool severe, bool *ignore)
elem->throw_msg = NULL;
*plist = elem;
if (plist == msg_list || severe) {
- char_u *tmsg;
+ char_u *tmsg;
- /* Skip the extra "Vim " prefix for message "E458". */
+ // Skip the extra "Vim " prefix for message "E458".
tmsg = elem->msg;
if (STRNCMP(tmsg, "Vim E", 5) == 0
&& ascii_isdigit(tmsg[5])
&& ascii_isdigit(tmsg[6])
&& ascii_isdigit(tmsg[7])
&& tmsg[8] == ':'
- && tmsg[9] == ' ')
+ && tmsg[9] == ' ') {
(*msg_list)->throw_msg = &tmsg[4];
- else
+ } else {
(*msg_list)->throw_msg = tmsg;
+ }
}
}
return true;
@@ -280,7 +284,7 @@ bool cause_errthrow(const char_u *mesg, bool severe, bool *ignore)
*/
static void free_msglist(struct msglist *l)
{
- struct msglist *messages, *next;
+ struct msglist *messages, *next;
messages = l;
while (messages != NULL) {
@@ -319,16 +323,18 @@ void do_errthrow(cstack_T *cstack, char_u *cmdname)
/* If no exception is to be thrown or the conversion should be done after
* returning to a previous invocation of do_one_cmd(), do nothing. */
- if (msg_list == NULL || *msg_list == NULL)
+ if (msg_list == NULL || *msg_list == NULL) {
return;
+ }
- if (throw_exception(*msg_list, ET_ERROR, cmdname) == FAIL)
+ if (throw_exception(*msg_list, ET_ERROR, cmdname) == FAIL) {
free_msglist(*msg_list);
- else {
- if (cstack != NULL)
+ } else {
+ if (cstack != NULL) {
do_throw(cstack);
- else
+ } else {
need_rethrow = TRUE;
+ }
}
*msg_list = NULL;
}
@@ -356,36 +362,35 @@ int do_intthrow(cstack_T *cstack)
}
} else {
#endif
- // Throw an interrupt exception, so that everything will be aborted
- // (except for executing finally clauses), until the interrupt exception
- // is caught; if still uncaught at the top level, the script processing
- // will be terminated then. - If an interrupt exception is already
- // being thrown, do nothing.
-
- if (current_exception) {
- if (current_exception->type == ET_INTERRUPT) {
- return false;
- }
+ // Throw an interrupt exception, so that everything will be aborted
+ // (except for executing finally clauses), until the interrupt exception
+ // is caught; if still uncaught at the top level, the script processing
+ // will be terminated then. - If an interrupt exception is already
+ // being thrown, do nothing.
- // An interrupt exception replaces any user or error exception.
- discard_current_exception();
- }
- if (throw_exception("Vim:Interrupt", ET_INTERRUPT, NULL) != FAIL) {
- do_throw(cstack);
+ if (current_exception) {
+ if (current_exception->type == ET_INTERRUPT) {
+ return false;
}
-#ifdef THROW_TEST
+
+ // An interrupt exception replaces any user or error exception.
+ discard_current_exception();
}
+ if (throw_exception("Vim:Interrupt", ET_INTERRUPT, NULL) != FAIL) {
+ do_throw(cstack);
+ }
+#ifdef THROW_TEST
+}
#endif
return true;
}
// Get an exception message that is to be stored in current_exception->value.
-char_u *get_exception_string(void *value, except_type_T type, char_u *cmdname,
- int *should_free)
+char_u *get_exception_string(void *value, except_type_T type, char_u *cmdname, int *should_free)
{
- char_u *ret, *mesg;
- char_u *p, *val;
+ char_u *ret, *mesg;
+ char_u *p, *val;
if (type == ET_ERROR) {
*should_free = true;
@@ -433,7 +438,7 @@ char_u *get_exception_string(void *value, except_type_T type, char_u *cmdname,
}
} else {
*should_free = FALSE;
- ret = (char_u *) value;
+ ret = (char_u *)value;
}
return ret;
@@ -446,7 +451,7 @@ char_u *get_exception_string(void *value, except_type_T type, char_u *cmdname,
// error exception.
static int throw_exception(void *value, except_type_T type, char_u *cmdname)
{
- except_T *excp;
+ except_T *excp;
int should_free;
/*
@@ -465,14 +470,16 @@ static int throw_exception(void *value, except_type_T type, char_u *cmdname)
excp = xmalloc(sizeof(except_T));
- if (type == ET_ERROR)
+ if (type == ET_ERROR) {
/* Store the original message and prefix the exception value with
* "Vim:" or, if a command name is given, "Vim(cmdname):". */
excp->messages = (struct msglist *)value;
+ }
excp->value = get_exception_string(value, type, cmdname, &should_free);
- if (excp->value == NULL && should_free)
+ if (excp->value == NULL && should_free) {
goto nomem;
+ }
excp->type = type;
excp->throw_name = vim_strsave(sourcing_name == NULL
@@ -482,24 +489,27 @@ static int throw_exception(void *value, except_type_T type, char_u *cmdname)
if (p_verbose >= 13 || debug_break_level > 0) {
int save_msg_silent = msg_silent;
- if (debug_break_level > 0)
- msg_silent = FALSE; /* display messages */
- else
+ if (debug_break_level > 0) {
+ msg_silent = FALSE; // display messages
+ } else {
verbose_enter();
+ }
++no_wait_return;
- if (debug_break_level > 0 || *p_vfile == NUL)
- msg_scroll = TRUE; /* always scroll up, don't overwrite */
-
+ if (debug_break_level > 0 || *p_vfile == NUL) {
+ msg_scroll = TRUE; // always scroll up, don't overwrite
+ }
smsg(_("Exception thrown: %s"), excp->value);
msg_puts("\n"); // don't overwrite this either
- if (debug_break_level > 0 || *p_vfile == NUL)
+ if (debug_break_level > 0 || *p_vfile == NUL) {
cmdline_row = msg_row;
+ }
--no_wait_return;
- if (debug_break_level > 0)
+ if (debug_break_level > 0) {
msg_silent = save_msg_silent;
- else
+ } else {
verbose_leave();
+ }
}
current_exception = excp;
@@ -520,7 +530,7 @@ fail:
*/
static void discard_exception(except_T *excp, bool was_finished)
{
- char_u *saved_IObuff;
+ char_u *saved_IObuff;
if (current_exception == excp) {
current_exception = NULL;
@@ -534,13 +544,15 @@ static void discard_exception(except_T *excp, bool was_finished)
int save_msg_silent = msg_silent;
saved_IObuff = vim_strsave(IObuff);
- if (debug_break_level > 0)
- msg_silent = FALSE; /* display messages */
- else
+ if (debug_break_level > 0) {
+ msg_silent = FALSE; // display messages
+ } else {
verbose_enter();
+ }
++no_wait_return;
- if (debug_break_level > 0 || *p_vfile == NUL)
- msg_scroll = TRUE; /* always scroll up, don't overwrite */
+ if (debug_break_level > 0 || *p_vfile == NUL) {
+ msg_scroll = TRUE; // always scroll up, don't overwrite
+ }
smsg(was_finished ? _("Exception finished: %s")
: _("Exception discarded: %s"),
excp->value);
@@ -557,10 +569,12 @@ static void discard_exception(except_T *excp, bool was_finished)
xstrlcpy((char *)IObuff, (const char *)saved_IObuff, IOSIZE);
xfree(saved_IObuff);
}
- if (excp->type != ET_INTERRUPT)
+ if (excp->type != ET_INTERRUPT) {
xfree(excp->value);
- if (excp->type == ET_ERROR)
+ }
+ if (excp->type == ET_ERROR) {
free_msglist(excp->messages);
+ }
xfree(excp->throw_name);
xfree(excp);
}
@@ -585,7 +599,7 @@ static void catch_exception(except_T *excp)
{
excp->caught = caught_stack;
caught_stack = excp;
- set_vim_var_string(VV_EXCEPTION, (char *) excp->value, -1);
+ set_vim_var_string(VV_EXCEPTION, (char *)excp->value, -1);
if (*excp->throw_name != NUL) {
if (excp->throw_lnum != 0) {
vim_snprintf((char *)IObuff, IOSIZE, _("%s, line %" PRId64),
@@ -593,7 +607,7 @@ static void catch_exception(except_T *excp)
} else {
vim_snprintf((char *)IObuff, IOSIZE, "%s", excp->throw_name);
}
- set_vim_var_string(VV_THROWPOINT, (char *) IObuff, -1);
+ set_vim_var_string(VV_THROWPOINT, (char *)IObuff, -1);
} else {
// throw_name not set on an exception from a command that was typed.
set_vim_var_string(VV_THROWPOINT, NULL, -1);
@@ -602,24 +616,27 @@ static void catch_exception(except_T *excp)
if (p_verbose >= 13 || debug_break_level > 0) {
int save_msg_silent = msg_silent;
- if (debug_break_level > 0)
- msg_silent = FALSE; /* display messages */
- else
+ if (debug_break_level > 0) {
+ msg_silent = FALSE; // display messages
+ } else {
verbose_enter();
+ }
++no_wait_return;
- if (debug_break_level > 0 || *p_vfile == NUL)
- msg_scroll = TRUE; /* always scroll up, don't overwrite */
-
+ if (debug_break_level > 0 || *p_vfile == NUL) {
+ msg_scroll = TRUE; // always scroll up, don't overwrite
+ }
smsg(_("Exception caught: %s"), excp->value);
msg_puts("\n"); // don't overwrite this either
- if (debug_break_level > 0 || *p_vfile == NUL)
+ if (debug_break_level > 0 || *p_vfile == NUL) {
cmdline_row = msg_row;
+ }
--no_wait_return;
- if (debug_break_level > 0)
+ if (debug_break_level > 0) {
msg_silent = save_msg_silent;
- else
+ } else {
verbose_leave();
+ }
}
}
@@ -633,7 +650,7 @@ static void finish_exception(except_T *excp)
}
caught_stack = caught_stack->caught;
if (caught_stack != NULL) {
- set_vim_var_string(VV_EXCEPTION, (char *) caught_stack->value, -1);
+ set_vim_var_string(VV_EXCEPTION, (char *)caught_stack->value, -1);
if (*caught_stack->throw_name != NUL) {
if (caught_stack->throw_lnum != 0) {
vim_snprintf((char *)IObuff, IOSIZE,
@@ -643,7 +660,7 @@ static void finish_exception(except_T *excp)
vim_snprintf((char *)IObuff, IOSIZE, "%s",
caught_stack->throw_name);
}
- set_vim_var_string(VV_THROWPOINT, (char *) IObuff, -1);
+ set_vim_var_string(VV_THROWPOINT, (char *)IObuff, -1);
} else {
// throw_name not set on an exception from a command that was
// typed.
@@ -687,7 +704,7 @@ static void report_pending(int action, int pending, void *value)
case RP_RESUME:
mesg = _("%s resumed");
break;
- /* case RP_DISCARD: */
+ // case RP_DISCARD:
default:
mesg = _("%s discarded");
break;
@@ -707,7 +724,7 @@ static void report_pending(int action, int pending, void *value)
s = ":finish";
break;
case CSTP_RETURN:
- /* ":return" command producing value, allocated */
+ // ":return" command producing value, allocated
s = (char *)get_return_cmd(value);
break;
@@ -717,30 +734,34 @@ static void report_pending(int action, int pending, void *value)
mesg, _("Exception"));
mesg = (char *)concat_str(IObuff, (char_u *)": %s");
s = (char *)((except_T *)value)->value;
- } else if ((pending & CSTP_ERROR) && (pending & CSTP_INTERRUPT))
+ } else if ((pending & CSTP_ERROR) && (pending & CSTP_INTERRUPT)) {
s = _("Error and interrupt");
- else if (pending & CSTP_ERROR)
+ } else if (pending & CSTP_ERROR) {
s = _("Error");
- else /* if (pending & CSTP_INTERRUPT) */
+ } else { // if (pending & CSTP_INTERRUPT)
s = _("Interrupt");
+ }
}
save_msg_silent = msg_silent;
- if (debug_break_level > 0)
- msg_silent = FALSE; /* display messages */
+ if (debug_break_level > 0) {
+ msg_silent = FALSE; // display messages
+ }
++no_wait_return;
- msg_scroll = TRUE; /* always scroll up, don't overwrite */
+ msg_scroll = TRUE; // always scroll up, don't overwrite
smsg(mesg, s);
msg_puts("\n"); // don't overwrite this either
cmdline_row = msg_row;
--no_wait_return;
- if (debug_break_level > 0)
+ if (debug_break_level > 0) {
msg_silent = save_msg_silent;
+ }
- if (pending == CSTP_RETURN)
+ if (pending == CSTP_RETURN) {
xfree(s);
- else if (pending & CSTP_THROW)
+ } else if (pending & CSTP_THROW) {
xfree(mesg);
+ }
}
/*
@@ -750,11 +771,13 @@ static void report_pending(int action, int pending, void *value)
void report_make_pending(int pending, void *value)
{
if (p_verbose >= 14 || debug_break_level > 0) {
- if (debug_break_level <= 0)
+ if (debug_break_level <= 0) {
verbose_enter();
+ }
report_pending(RP_MAKE, pending, value);
- if (debug_break_level <= 0)
+ if (debug_break_level <= 0) {
verbose_leave();
+ }
}
}
@@ -765,11 +788,13 @@ void report_make_pending(int pending, void *value)
void report_resume_pending(int pending, void *value)
{
if (p_verbose >= 14 || debug_break_level > 0) {
- if (debug_break_level <= 0)
+ if (debug_break_level <= 0) {
verbose_enter();
+ }
report_pending(RP_RESUME, pending, value);
- if (debug_break_level <= 0)
+ if (debug_break_level <= 0) {
verbose_leave();
+ }
}
}
@@ -780,11 +805,13 @@ void report_resume_pending(int pending, void *value)
void report_discard_pending(int pending, void *value)
{
if (p_verbose >= 14 || debug_break_level > 0) {
- if (debug_break_level <= 0)
+ if (debug_break_level <= 0) {
verbose_enter();
+ }
report_pending(RP_DISCARD, pending, value);
- if (debug_break_level <= 0)
+ if (debug_break_level <= 0) {
verbose_leave();
+ }
}
}
@@ -807,9 +834,9 @@ void ex_if(exarg_T *eap)
int result;
cstack_T *const cstack = eap->cstack;
- if (cstack->cs_idx == CSTACK_LEN - 1)
+ if (cstack->cs_idx == CSTACK_LEN - 1) {
eap->errmsg = (char_u *)N_("E579: :if nesting too deep");
- else {
+ } else {
++cstack->cs_idx;
cstack->cs_flags[cstack->cs_idx] = 0;
@@ -819,11 +846,13 @@ void ex_if(exarg_T *eap)
result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip);
if (!skip && !error) {
- if (result)
+ if (result) {
cstack->cs_flags[cstack->cs_idx] = CSF_ACTIVE | CSF_TRUE;
- } else
- /* set TRUE, so this conditional will never get active */
+ }
+ } else {
+ // set TRUE, so this conditional will never get active
cstack->cs_flags[cstack->cs_idx] = CSF_TRUE;
+ }
}
}
@@ -832,24 +861,23 @@ void ex_if(exarg_T *eap)
*/
void ex_endif(exarg_T *eap)
{
- did_endif = TRUE;
+ did_endif = true;
if (eap->cstack->cs_idx < 0
|| (eap->cstack->cs_flags[eap->cstack->cs_idx]
- & (CSF_WHILE | CSF_FOR | CSF_TRY)))
+ & (CSF_WHILE | CSF_FOR | CSF_TRY))) {
eap->errmsg = (char_u *)N_("E580: :endif without :if");
- else {
- /*
- * When debugging or a breakpoint was encountered, display the debug
- * prompt (if not already done). This shows the user that an ":endif"
- * is executed when the ":if" or a previous ":elseif" was not TRUE.
- * Handle a ">quit" debug command as if an interrupt had occurred before
- * the ":endif". That is, throw an interrupt exception if appropriate.
- * Doing this here prevents an exception for a parsing error being
- * discarded by throwing the interrupt exception later on.
- */
+ } else {
+ // When debugging or a breakpoint was encountered, display the debug
+ // prompt (if not already done). This shows the user that an ":endif"
+ // is executed when the ":if" or a previous ":elseif" was not TRUE.
+ // Handle a ">quit" debug command as if an interrupt had occurred before
+ // the ":endif". That is, throw an interrupt exception if appropriate.
+ // Doing this here prevents an exception for a parsing error being
+ // discarded by throwing the interrupt exception later on.
if (!(eap->cstack->cs_flags[eap->cstack->cs_idx] & CSF_TRUE)
- && dbg_check_skipped(eap))
+ && dbg_check_skipped(eap)) {
(void)do_intthrow(eap->cstack);
+ }
--eap->cstack->cs_idx;
}
@@ -884,13 +912,15 @@ void ex_else(exarg_T *eap)
skip = TRUE;
}
- /* if skipping or the ":if" was TRUE, reset ACTIVE, otherwise set it */
+ // if skipping or the ":if" was TRUE, reset ACTIVE, otherwise set it
if (skip || cstack->cs_flags[cstack->cs_idx] & CSF_TRUE) {
- if (eap->errmsg == NULL)
+ if (eap->errmsg == NULL) {
cstack->cs_flags[cstack->cs_idx] = CSF_TRUE;
- skip = TRUE; /* don't evaluate an ":elseif" */
- } else
+ }
+ skip = TRUE; // don't evaluate an ":elseif"
+ } else {
cstack->cs_flags[cstack->cs_idx] = CSF_ACTIVE;
+ }
/*
* When debugging or a breakpoint was encountered, display the debug prompt
@@ -917,15 +947,18 @@ void ex_else(exarg_T *eap)
* case, the parsing error will be ignored by emsg(). */
if (!skip && !error) {
- if (result)
+ if (result) {
cstack->cs_flags[cstack->cs_idx] = CSF_ACTIVE | CSF_TRUE;
- else
+ } else {
cstack->cs_flags[cstack->cs_idx] = 0;
- } else if (eap->errmsg == NULL)
- /* set TRUE, so this conditional will never get active */
+ }
+ } else if (eap->errmsg == NULL) {
+ // set TRUE, so this conditional will never get active
cstack->cs_flags[cstack->cs_idx] = CSF_TRUE;
- } else
+ }
+ } else {
cstack->cs_flags[cstack->cs_idx] |= CSF_ELSE;
+ }
}
/*
@@ -938,9 +971,9 @@ void ex_while(exarg_T *eap)
int result;
cstack_T *const cstack = eap->cstack;
- if (cstack->cs_idx == CSTACK_LEN - 1)
+ if (cstack->cs_idx == CSTACK_LEN - 1) {
eap->errmsg = (char_u *)N_("E585: :while/:for nesting too deep");
- else {
+ } else {
/*
* The loop flag is set when we have jumped back from the matching
* ":endwhile" or ":endfor". When not set, need to initialise this
@@ -972,16 +1005,17 @@ void ex_while(exarg_T *eap)
fi = cstack->cs_forinfo[cstack->cs_idx];
error = FALSE;
} else {
- /* Evaluate the argument and get the info in a structure. */
+ // Evaluate the argument and get the info in a structure.
fi = eval_for_line(eap->arg, &error, &eap->nextcmd, skip);
cstack->cs_forinfo[cstack->cs_idx] = fi;
}
- /* use the element at the start of the list and advance */
- if (!error && fi != NULL && !skip)
+ // use the element at the start of the list and advance
+ if (!error && fi != NULL && !skip) {
result = next_for_item(fi, eap->arg);
- else
+ } else {
result = FALSE;
+ }
if (!result) {
free_for_info(fi);
@@ -1003,8 +1037,9 @@ void ex_while(exarg_T *eap)
* the list, show the debug prompt at the ":endwhile"/":endfor" as
* if there was a ":break" in a ":while"/":for" evaluating to
* TRUE. */
- if (!skip && !error)
+ if (!skip && !error) {
cstack->cs_flags[cstack->cs_idx] |= CSF_TRUE;
+ }
}
}
}
@@ -1017,12 +1052,12 @@ void ex_continue(exarg_T *eap)
int idx;
cstack_T *const cstack = eap->cstack;
- if (cstack->cs_looplevel <= 0 || cstack->cs_idx < 0)
+ if (cstack->cs_looplevel <= 0 || cstack->cs_idx < 0) {
eap->errmsg = (char_u *)N_("E586: :continue without :while or :for");
- else {
+ } else {
/* Try to find the matching ":while". This might stop at a try
* conditional not in its finally clause (which is then to be executed
- * next). Therefor, inactivate all conditionals except the ":while"
+ * next). Therefore, deactivate all conditionals except the ":while"
* itself (if reached). */
idx = cleanup_conditionals(cstack, CSF_WHILE | CSF_FOR, FALSE);
assert(idx >= 0);
@@ -1033,7 +1068,7 @@ void ex_continue(exarg_T *eap)
* Set CSL_HAD_CONT, so do_cmdline() will jump back to the
* matching ":while".
*/
- cstack->cs_lflags |= CSL_HAD_CONT; /* let do_cmdline() handle it */
+ cstack->cs_lflags |= CSL_HAD_CONT; // let do_cmdline() handle it
} else {
/* If a try conditional not in its finally clause is reached first,
* make the ":continue" pending for execution at the ":endtry". */
@@ -1051,14 +1086,14 @@ void ex_break(exarg_T *eap)
int idx;
cstack_T *const cstack = eap->cstack;
- if (cstack->cs_looplevel <= 0 || cstack->cs_idx < 0)
+ if (cstack->cs_looplevel <= 0 || cstack->cs_idx < 0) {
eap->errmsg = (char_u *)N_("E587: :break without :while or :for");
- else {
- /* Inactivate conditionals until the matching ":while" or a try
- * conditional not in its finally clause (which is then to be
- * executed next) is found. In the latter case, make the ":break"
- * pending for execution at the ":endtry". */
- idx = cleanup_conditionals(cstack, CSF_WHILE | CSF_FOR, TRUE);
+ } else {
+ // Deactivate conditionals until the matching ":while" or a try
+ // conditional not in its finally clause (which is then to be
+ // executed next) is found. In the latter case, make the ":break"
+ // pending for execution at the ":endtry". */
+ idx = cleanup_conditionals(cstack, CSF_WHILE | CSF_FOR, true);
if (idx >= 0 && !(cstack->cs_flags[idx] & (CSF_WHILE | CSF_FOR))) {
cstack->cs_pending[idx] = CSTP_BREAK;
report_make_pending(CSTP_BREAK, NULL);
@@ -1073,7 +1108,7 @@ void ex_endwhile(exarg_T *eap)
{
cstack_T *const cstack = eap->cstack;
int idx;
- char_u *err;
+ char_u *err;
int csf;
int fl;
@@ -1085,24 +1120,26 @@ void ex_endwhile(exarg_T *eap)
csf = CSF_FOR;
}
- if (cstack->cs_looplevel <= 0 || cstack->cs_idx < 0)
+ if (cstack->cs_looplevel <= 0 || cstack->cs_idx < 0) {
eap->errmsg = err;
- else {
+ } else {
fl = cstack->cs_flags[cstack->cs_idx];
if (!(fl & csf)) {
/* If we are in a ":while" or ":for" but used the wrong endloop
* command, do not rewind to the next enclosing ":for"/":while". */
- if (fl & CSF_WHILE)
+ if (fl & CSF_WHILE) {
eap->errmsg = (char_u *)_("E732: Using :endfor with :while");
- else if (fl & CSF_FOR)
+ } else if (fl & CSF_FOR) {
eap->errmsg = (char_u *)_("E733: Using :endwhile with :for");
+ }
}
if (!(fl & (CSF_WHILE | CSF_FOR))) {
- if (!(fl & CSF_TRY))
+ if (!(fl & CSF_TRY)) {
eap->errmsg = e_endif;
- else if (fl & CSF_FINALLY)
+ } else if (fl & CSF_FINALLY) {
eap->errmsg = e_endtry;
- /* Try to find the matching ":while" and report what's missing. */
+ }
+ // Try to find the matching ":while" and report what's missing.
for (idx = cstack->cs_idx; idx > 0; --idx) {
fl = cstack->cs_flags[idx];
if ((fl & CSF_TRY) && !(fl & CSF_FINALLY)) {
@@ -1111,10 +1148,11 @@ void ex_endwhile(exarg_T *eap)
eap->errmsg = err;
return;
}
- if (fl & csf)
+ if (fl & csf) {
break;
+ }
}
- /* Cleanup and rewind all contained (and unclosed) conditionals. */
+ // Cleanup and rewind all contained (and unclosed) conditionals.
(void)cleanup_conditionals(cstack, CSF_WHILE | CSF_FOR, FALSE);
rewind_conditionals(cstack, idx, CSF_TRY, &cstack->cs_trylevel);
}
@@ -1130,8 +1168,9 @@ void ex_endwhile(exarg_T *eap)
*/
else if (cstack->cs_flags[cstack->cs_idx] & CSF_TRUE
&& !(cstack->cs_flags[cstack->cs_idx] & CSF_ACTIVE)
- && dbg_check_skipped(eap))
+ && dbg_check_skipped(eap)) {
(void)do_intthrow(cstack);
+ }
/*
* Set loop flag, so do_cmdline() will jump back to the matching
@@ -1179,15 +1218,15 @@ void do_throw(cstack_T *cstack)
int idx;
int inactivate_try = FALSE;
- /*
- * Cleanup and inactivate up to the next surrounding try conditional that
- * is not in its finally clause. Normally, do not inactivate the try
- * conditional itself, so that its ACTIVE flag can be tested below. But
- * if a previous error or interrupt has not been converted to an exception,
- * inactivate the try conditional, too, as if the conversion had been done,
- * and reset the did_emsg or got_int flag, so this won't happen again at
- * the next surrounding try conditional.
- */
+ //
+ // Cleanup and deactivate up to the next surrounding try conditional that
+ // is not in its finally clause. Normally, do not deactivate the try
+ // conditional itself, so that its ACTIVE flag can be tested below. But
+ // if a previous error or interrupt has not been converted to an exception,
+ // deactivate the try conditional, too, as if the conversion had been done,
+ // and reset the did_emsg or got_int flag, so this won't happen again at
+ // the next surrounding try conditional.
+ //
#ifndef THROW_ON_ERROR_TRUE
if (did_emsg && !THROW_ON_ERROR) {
inactivate_try = TRUE;
@@ -1216,13 +1255,14 @@ void do_throw(cstack_T *cstack)
* the matching catch clause or the finally clause.
*/
if (!(cstack->cs_flags[idx] & CSF_CAUGHT)) {
- if (cstack->cs_flags[idx] & CSF_ACTIVE)
+ if (cstack->cs_flags[idx] & CSF_ACTIVE) {
cstack->cs_flags[idx] |= CSF_THROWN;
- else
+ } else {
/* THROWN may have already been set for a catchable exception
* that has been discarded. Ensure it is reset for the new
* exception. */
cstack->cs_flags[idx] &= ~CSF_THROWN;
+ }
}
cstack->cs_flags[idx] &= ~CSF_ACTIVE;
cstack->cs_exception[idx] = current_exception;
@@ -1237,9 +1277,9 @@ void ex_try(exarg_T *eap)
int skip;
cstack_T *const cstack = eap->cstack;
- if (cstack->cs_idx == CSTACK_LEN - 1)
+ if (cstack->cs_idx == CSTACK_LEN - 1) {
eap->errmsg = (char_u *)N_("E601: :try nesting too deep");
- else {
+ } else {
++cstack->cs_idx;
++cstack->cs_trylevel;
cstack->cs_flags[cstack->cs_idx] = CSF_TRY;
@@ -1278,7 +1318,6 @@ void ex_try(exarg_T *eap)
emsg_silent = 0;
}
}
-
}
}
@@ -1291,13 +1330,13 @@ void ex_catch(exarg_T *eap)
int give_up = FALSE;
int skip = FALSE;
int caught = FALSE;
- char_u *end;
+ char_u *end;
char_u save_char = 0;
- char_u *save_cpo;
+ char_u *save_cpo;
regmatch_T regmatch;
int prev_got_int;
cstack_T *const cstack = eap->cstack;
- char_u *pat;
+ char_u *pat;
if (cstack->cs_trylevel <= 0 || cstack->cs_idx < 0) {
eap->errmsg = (char_u *)N_("E603: :catch without :try");
@@ -1309,20 +1348,23 @@ void ex_catch(exarg_T *eap)
eap->errmsg = get_end_emsg(cstack);
skip = TRUE;
}
- for (idx = cstack->cs_idx; idx > 0; --idx)
- if (cstack->cs_flags[idx] & CSF_TRY)
+ for (idx = cstack->cs_idx; idx > 0; --idx) {
+ if (cstack->cs_flags[idx] & CSF_TRY) {
break;
+ }
+ }
if (cstack->cs_flags[idx] & CSF_FINALLY) {
/* Give up for a ":catch" after ":finally" and ignore it.
* Just parse. */
eap->errmsg = (char_u *)N_("E604: :catch after :finally");
give_up = TRUE;
- } else
+ } else {
rewind_conditionals(cstack, idx, CSF_WHILE | CSF_FOR,
- &cstack->cs_looplevel);
+ &cstack->cs_looplevel);
+ }
}
- if (ends_excmd(*eap->arg)) { /* no argument, catch all errors */
+ if (ends_excmd(*eap->arg)) { // no argument, catch all errors
pat = (char_u *)".*";
end = NULL;
eap->nextcmd = find_nextcmd(eap->arg);
@@ -1390,7 +1432,7 @@ void ex_catch(exarg_T *eap)
prev_got_int = got_int;
got_int = FALSE;
caught = vim_regexec_nl(&regmatch, current_exception->value,
- (colnr_T)0);
+ (colnr_T)0);
got_int |= prev_got_int;
vim_regfree(regmatch.regprog);
}
@@ -1430,8 +1472,9 @@ void ex_catch(exarg_T *eap)
}
}
- if (end != NULL)
+ if (end != NULL) {
eap->nextcmd = find_nextcmd(end);
+ }
}
/*
@@ -1444,28 +1487,31 @@ void ex_finally(exarg_T *eap)
int pending = CSTP_NONE;
cstack_T *const cstack = eap->cstack;
- if (cstack->cs_trylevel <= 0 || cstack->cs_idx < 0)
+ if (cstack->cs_trylevel <= 0 || cstack->cs_idx < 0) {
eap->errmsg = (char_u *)N_("E606: :finally without :try");
- else {
+ } else {
if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) {
eap->errmsg = get_end_emsg(cstack);
- for (idx = cstack->cs_idx - 1; idx > 0; --idx)
- if (cstack->cs_flags[idx] & CSF_TRY)
+ for (idx = cstack->cs_idx - 1; idx > 0; --idx) {
+ if (cstack->cs_flags[idx] & CSF_TRY) {
break;
+ }
+ }
/* Make this error pending, so that the commands in the following
* finally clause can be executed. This overrules also a pending
* ":continue", ":break", ":return", or ":finish". */
pending = CSTP_ERROR;
- } else
+ } else {
idx = cstack->cs_idx;
+ }
if (cstack->cs_flags[idx] & CSF_FINALLY) {
- /* Give up for a multiple ":finally" and ignore it. */
+ // Give up for a multiple ":finally" and ignore it.
eap->errmsg = (char_u *)N_("E607: multiple :finally");
return;
}
rewind_conditionals(cstack, idx, CSF_WHILE | CSF_FOR,
- &cstack->cs_looplevel);
+ &cstack->cs_looplevel);
/*
* Don't do something when the corresponding try block never got active
@@ -1517,7 +1563,7 @@ void ex_finally(exarg_T *eap)
if (pending == CSTP_ERROR || did_emsg || got_int || current_exception) {
if (cstack->cs_pending[cstack->cs_idx] == CSTP_RETURN) {
report_discard_pending(CSTP_RETURN,
- cstack->cs_rettv[cstack->cs_idx]);
+ cstack->cs_rettv[cstack->cs_idx]);
discard_pending_return(cstack->cs_rettv[cstack->cs_idx]);
}
if (pending == CSTP_ERROR && !did_emsg) {
@@ -1564,7 +1610,7 @@ void ex_endtry(exarg_T *eap)
int skip;
int rethrow = FALSE;
int pending = CSTP_NONE;
- void *rettv = NULL;
+ void *rettv = NULL;
cstack_T *const cstack = eap->cstack;
if (cstack->cs_trylevel <= 0 || cstack->cs_idx < 0) {
@@ -1585,13 +1631,13 @@ void ex_endtry(exarg_T *eap)
if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) {
eap->errmsg = get_end_emsg(cstack);
- /* Find the matching ":try" and report what's missing. */
+ // Find the matching ":try" and report what's missing.
idx = cstack->cs_idx;
do
--idx;
while (idx > 0 && !(cstack->cs_flags[idx] & CSF_TRY));
rewind_conditionals(cstack, idx, CSF_WHILE | CSF_FOR,
- &cstack->cs_looplevel);
+ &cstack->cs_looplevel);
skip = TRUE;
/*
@@ -1656,10 +1702,11 @@ void ex_endtry(exarg_T *eap)
if (!skip) {
pending = cstack->cs_pending[idx];
cstack->cs_pending[idx] = CSTP_NONE;
- if (pending == CSTP_RETURN)
+ if (pending == CSTP_RETURN) {
rettv = cstack->cs_rettv[idx];
- else if (pending & CSTP_THROW)
+ } else if (pending & CSTP_THROW) {
current_exception = cstack->cs_exception[idx];
+ }
}
/*
@@ -1679,8 +1726,8 @@ void ex_endtry(exarg_T *eap)
if (!skip) {
report_resume_pending(pending,
- (pending == CSTP_RETURN) ? rettv :
- (pending & CSTP_THROW) ? (void *)current_exception : NULL);
+ (pending == CSTP_RETURN) ? rettv :
+ (pending & CSTP_THROW) ? (void *)current_exception : NULL);
switch (pending) {
case CSTP_NONE:
break;
@@ -1788,7 +1835,7 @@ void enter_cleanup(cleanup_T *csp)
did_emsg = got_int = need_rethrow = false;
current_exception = NULL;
- /* Report if required by the 'verbose' option or when debugging. */
+ // Report if required by the 'verbose' option or when debugging.
report_make_pending(pending, csp->exception);
} else {
csp->pending = CSTP_NONE;
@@ -1815,8 +1862,9 @@ void leave_cleanup(cleanup_T *csp)
{
int pending = csp->pending;
- if (pending == CSTP_NONE) /* nothing to do */
+ if (pending == CSTP_NONE) { // nothing to do
return;
+ }
/* If there was an aborting error, an interrupt, or an uncaught exception
* after the corresponding call to enter_cleanup(), discard what has been
@@ -1832,8 +1880,9 @@ void leave_cleanup(cleanup_T *csp)
/* If an error was about to be converted to an exception when
* enter_cleanup() was called, free the message list. */
- if (msg_list != NULL)
+ if (msg_list != NULL) {
free_global_msglist();
+ }
}
/*
* If there was no new error, interrupt, or throw between the calls
@@ -1846,9 +1895,9 @@ void leave_cleanup(cleanup_T *csp)
* called, we need to rethrow it. Make it the exception currently
* being thrown.
*/
- if (pending & CSTP_THROW)
+ if (pending & CSTP_THROW) {
current_exception = csp->exception;
-
+ }
/*
* If an error was about to be converted to an exception when
* enter_cleanup() was called, let "cause_abort" take the part of
@@ -1871,8 +1920,7 @@ void leave_cleanup(cleanup_T *csp)
}
// Report if required by the 'verbose' option or when debugging.
- report_resume_pending(
- pending, ((pending & CSTP_THROW) ? (void *)current_exception : NULL));
+ report_resume_pending(pending, ((pending & CSTP_THROW) ? (void *)current_exception : NULL));
}
}
@@ -1920,7 +1968,7 @@ int cleanup_conditionals(cstack_T *cstack, int searched_cond, int inclusive)
case CSTP_RETURN:
report_discard_pending(CSTP_RETURN,
- cstack->cs_rettv[idx]);
+ cstack->cs_rettv[idx]);
discard_pending_return(cstack->cs_rettv[idx]);
cstack->cs_pending[idx] = CSTP_NONE;
break;
@@ -1948,15 +1996,17 @@ int cleanup_conditionals(cstack_T *cstack, int searched_cond, int inclusive)
*/
if (!(cstack->cs_flags[idx] & CSF_FINALLY)) {
if ((cstack->cs_flags[idx] & CSF_ACTIVE)
- && (cstack->cs_flags[idx] & CSF_CAUGHT))
+ && (cstack->cs_flags[idx] & CSF_CAUGHT)) {
finish_exception((except_T *)cstack->cs_exception[idx]);
+ }
/* Stop at this try conditional - except the try block never
* got active (because of an inactive surrounding conditional
* or when the ":try" appeared after an error or interrupt or
* throw). */
if (cstack->cs_flags[idx] & CSF_TRUE) {
- if (searched_cond == 0 && !inclusive)
+ if (searched_cond == 0 && !inclusive) {
break;
+ }
stop = TRUE;
}
}
@@ -1967,13 +2017,15 @@ int cleanup_conditionals(cstack_T *cstack, int searched_cond, int inclusive)
* If "inclusive" is TRUE and "searched_cond" is CSF_TRY|CSF_SILENT,
* check first whether "emsg_silent" needs to be restored. */
if (cstack->cs_flags[idx] & searched_cond) {
- if (!inclusive)
+ if (!inclusive) {
break;
+ }
stop = TRUE;
}
cstack->cs_flags[idx] &= ~CSF_ACTIVE;
- if (stop && searched_cond != (CSF_TRY | CSF_SILENT))
+ if (stop && searched_cond != (CSF_TRY | CSF_SILENT)) {
break;
+ }
/*
* When leaving a try conditional that reset "emsg_silent" on its
@@ -1982,7 +2034,7 @@ int cleanup_conditionals(cstack_T *cstack, int searched_cond, int inclusive)
*/
if ((cstack->cs_flags[idx] & CSF_TRY)
&& (cstack->cs_flags[idx] & CSF_SILENT)) {
- eslist_T *elem;
+ eslist_T *elem;
elem = cstack->cs_emsg_silent_list;
cstack->cs_emsg_silent_list = elem->next;
@@ -1990,8 +2042,9 @@ int cleanup_conditionals(cstack_T *cstack, int searched_cond, int inclusive)
xfree(elem);
cstack->cs_flags[idx] &= ~CSF_SILENT;
}
- if (stop)
+ if (stop) {
break;
+ }
}
return idx;
}
@@ -2001,10 +2054,12 @@ int cleanup_conditionals(cstack_T *cstack, int searched_cond, int inclusive)
*/
static char_u *get_end_emsg(cstack_T *cstack)
{
- if (cstack->cs_flags[cstack->cs_idx] & CSF_WHILE)
+ if (cstack->cs_flags[cstack->cs_idx] & CSF_WHILE) {
return e_endwhile;
- if (cstack->cs_flags[cstack->cs_idx] & CSF_FOR)
+ }
+ if (cstack->cs_flags[cstack->cs_idx] & CSF_FOR) {
return e_endfor;
+ }
return e_endif;
}
@@ -2016,14 +2071,15 @@ static char_u *get_end_emsg(cstack_T *cstack)
* type.
* Also free "for info" structures where needed.
*/
-void rewind_conditionals(cstack_T *cstack, int idx, int cond_type,
- int *cond_level)
+void rewind_conditionals(cstack_T *cstack, int idx, int cond_type, int *cond_level)
{
while (cstack->cs_idx > idx) {
- if (cstack->cs_flags[cstack->cs_idx] & cond_type)
+ if (cstack->cs_flags[cstack->cs_idx] & cond_type) {
--*cond_level;
- if (cstack->cs_flags[cstack->cs_idx] & CSF_FOR)
+ }
+ if (cstack->cs_flags[cstack->cs_idx] & CSF_FOR) {
free_for_info(cstack->cs_forinfo[cstack->cs_idx]);
+ }
--cstack->cs_idx;
}
}
@@ -2043,18 +2099,21 @@ int has_loop_cmd(char_u *p)
{
int len;
- /* skip modifiers, white space and ':' */
+ // skip modifiers, white space and ':'
for (;; ) {
- while (*p == ' ' || *p == '\t' || *p == ':')
+ while (*p == ' ' || *p == '\t' || *p == ':') {
++p;
+ }
len = modifier_len(p);
- if (len == 0)
+ if (len == 0) {
break;
+ }
p += len;
}
if ((p[0] == 'w' && p[1] == 'h')
- || (p[0] == 'f' && p[1] == 'o' && p[2] == 'r'))
+ || (p[0] == 'f' && p[1] == 'o' && p[2] == 'r')) {
return TRUE;
+ }
return FALSE;
}
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index f63987136f..a9990df58f 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -6,49 +6,56 @@
*/
#include <assert.h>
+#include <inttypes.h>
#include <stdbool.h>
-#include <string.h>
#include <stdlib.h>
-#include <inttypes.h>
+#include <string.h>
-#include "nvim/assert.h"
-#include "nvim/log.h"
-#include "nvim/vim.h"
-#include "nvim/ascii.h"
+#include "nvim/api/private/helpers.h"
#include "nvim/arabic.h"
-#include "nvim/ex_getln.h"
+#include "nvim/ascii.h"
+#include "nvim/assert.h"
#include "nvim/buffer.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
+#include "nvim/cursor_shape.h"
#include "nvim/digraph.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
#include "nvim/eval/userfunc.h"
+#include "nvim/event/loop.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
+#include "nvim/ex_getln.h"
#include "nvim/fileio.h"
#include "nvim/func_attr.h"
+#include "nvim/garray.h"
#include "nvim/getchar.h"
#include "nvim/highlight.h"
+#include "nvim/highlight_defs.h"
#include "nvim/if_cscope.h"
#include "nvim/indent.h"
+#include "nvim/keymap.h"
+#include "nvim/lib/kvec.h"
+#include "nvim/log.h"
+#include "nvim/lua/executor.h"
#include "nvim/main.h"
#include "nvim/mark.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
+#include "nvim/memory.h"
#include "nvim/menu.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
-#include "nvim/memory.h"
-#include "nvim/cursor_shape.h"
-#include "nvim/keymap.h"
-#include "nvim/garray.h"
-#include "nvim/move.h"
#include "nvim/mouse.h"
+#include "nvim/move.h"
#include "nvim/ops.h"
#include "nvim/option.h"
+#include "nvim/os/input.h"
+#include "nvim/os/os.h"
+#include "nvim/os/time.h"
#include "nvim/os_unix.h"
#include "nvim/path.h"
#include "nvim/popupmnu.h"
@@ -56,22 +63,15 @@
#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/sign.h"
-#include "nvim/strings.h"
#include "nvim/state.h"
+#include "nvim/strings.h"
#include "nvim/syntax.h"
#include "nvim/tag.h"
-#include "nvim/window.h"
#include "nvim/ui.h"
-#include "nvim/os/input.h"
-#include "nvim/os/os.h"
-#include "nvim/event/loop.h"
-#include "nvim/os/time.h"
-#include "nvim/lib/kvec.h"
-#include "nvim/api/private/helpers.h"
-#include "nvim/highlight_defs.h"
-#include "nvim/lua/executor.h"
-#include "nvim/viml/parser/parser.h"
+#include "nvim/vim.h"
#include "nvim/viml/parser/expressions.h"
+#include "nvim/viml/parser/parser.h"
+#include "nvim/window.h"
/// Command-line colors: one chunk
///
@@ -110,21 +110,21 @@ typedef enum {
* structure.
*/
struct cmdline_info {
- char_u *cmdbuff; // pointer to command line buffer
+ char_u *cmdbuff; // pointer to command line buffer
int cmdbufflen; // length of cmdbuff
int cmdlen; // number of chars in command line
int cmdpos; // current cursor position
int cmdspos; // cursor column on screen
int cmdfirstc; // ':', '/', '?', '=', '>' or NUL
int cmdindent; // number of spaces before cmdline
- char_u *cmdprompt; // message in front of cmdline
+ char_u *cmdprompt; // message in front of cmdline
int cmdattr; // attributes for prompt
int overstrike; // Typing mode on the command line. Shared by
// getcmdline() and put_on_cmdline().
- expand_T *xpc; // struct being used for expansion, xp_pattern
- // may point into cmdbuff
+ expand_T *xpc; // struct being used for expansion, xp_pattern
+ // may point into cmdbuff
int xp_context; // type of expansion
- char_u *xp_arg; // user-defined expansion arg
+ char_u *xp_arg; // user-defined expansion arg
int input_fn; // when TRUE Invoked for input() function
unsigned prompt_id; ///< Prompt number, used to disable coloring on errors.
Callback highlight_callback; ///< Callback used for coloring user input.
@@ -140,25 +140,25 @@ static unsigned last_prompt_id = 0;
// Struct to store the viewstate during 'incsearch' highlighting.
typedef struct {
- colnr_T vs_curswant;
- colnr_T vs_leftcol;
- linenr_T vs_topline;
- int vs_topfill;
- linenr_T vs_botline;
- int vs_empty_rows;
+ colnr_T vs_curswant;
+ colnr_T vs_leftcol;
+ linenr_T vs_topline;
+ int vs_topfill;
+ linenr_T vs_botline;
+ int vs_empty_rows;
} viewstate_T;
// Struct to store the state of 'incsearch' highlighting.
typedef struct {
- pos_T search_start; // where 'incsearch' starts searching
- pos_T save_cursor;
+ pos_T search_start; // where 'incsearch' starts searching
+ pos_T save_cursor;
viewstate_T init_viewstate;
viewstate_T old_viewstate;
- pos_T match_start;
- pos_T match_end;
- bool did_incsearch;
- bool incsearch_postponed;
- int magic_save;
+ pos_T match_start;
+ pos_T match_end;
+ bool did_incsearch;
+ bool incsearch_postponed;
+ int magic_save;
} incsearch_state_T;
typedef struct command_line_state {
@@ -178,9 +178,9 @@ typedef struct command_line_state {
int did_wild_list; // did wild_list() recently
int wim_index; // index in wim_flags[]
int res;
- int save_msg_scroll;
- int save_State; // remember State when called
- char_u *save_p_icm;
+ int save_msg_scroll;
+ int save_State; // remember State when called
+ char_u *save_p_icm;
int some_key_typed; // one of the keys was typed
// mouse drag and release events are ignored, unless they are
// preceded with a mouse down event
@@ -198,9 +198,9 @@ typedef struct cmdline_info CmdlineInfo;
* TODO: make it local to getcmdline() and pass it around. */
static struct cmdline_info ccline;
-static int cmd_showtail; /* Only show path tail in lists ? */
+static int cmd_showtail; // Only show path tail in lists ?
-static int new_cmdpos; /* position set by set_cmdline_pos() */
+static int new_cmdpos; // position set by set_cmdline_pos()
/// currently displayed block of context
static Array cmdline_block = ARRAY_DICT_INIT;
@@ -210,11 +210,11 @@ static Array cmdline_block = ARRAY_DICT_INIT;
*/
typedef void *(*user_expand_func_T)(const char_u *, int, typval_T *);
-static histentry_T *(history[HIST_COUNT]) = {NULL, NULL, NULL, NULL, NULL};
-static int hisidx[HIST_COUNT] = {-1, -1, -1, -1, -1}; /* lastused entry */
-static int hisnum[HIST_COUNT] = {0, 0, 0, 0, 0};
-/* identifying (unique) number of newest history entry */
-static int hislen = 0; /* actual length of history tables */
+static histentry_T *(history[HIST_COUNT]) = { NULL, NULL, NULL, NULL, NULL };
+static int hisidx[HIST_COUNT] = { -1, -1, -1, -1, -1 }; // lastused entry
+static int hisnum[HIST_COUNT] = { 0, 0, 0, 0, 0 };
+// identifying (unique) number of newest history entry
+static int hislen = 0; // actual length of history tables
/// Flag for command_line_handle_key to ignore <C-c>
///
@@ -275,9 +275,8 @@ static void init_incsearch_state(incsearch_state_T *s)
// Return true when 'incsearch' highlighting is to be done.
// Sets search_first_line and search_last_line to the address range.
-static bool do_incsearch_highlighting(int firstc, int *search_delim,
- incsearch_state_T *s, int *skiplen,
- int *patlen)
+static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_state_T *s,
+ int *skiplen, int *patlen)
FUNC_ATTR_NONNULL_ALL
{
char_u *cmd;
@@ -384,7 +383,7 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim,
// Don't do 'hlsearch' highlighting if the pattern matches everything.
if (!use_last_pat) {
char_u c = *end;
- int empty;
+ int empty;
*end = NUL;
empty = empty_pattern(p);
@@ -425,8 +424,7 @@ theend:
}
// May do 'incsearch' highlighting if desired.
-static void may_do_incsearch_highlighting(int firstc, long count,
- incsearch_state_T *s)
+static void may_do_incsearch_highlighting(int firstc, long count, incsearch_state_T *s)
{
pos_T end_pos;
proftime_T tm;
@@ -472,7 +470,7 @@ static void may_do_incsearch_highlighting(int firstc, long count,
// Use the previous pattern for ":s//".
next_char = ccline.cmdbuff[skiplen + patlen];
use_last_pat = patlen == 0 && skiplen > 0
- && ccline.cmdbuff[skiplen - 1] == next_char;
+ && ccline.cmdbuff[skiplen - 1] == next_char;
// If there is no pattern, don't do anything.
if (patlen == 0 && !use_last_pat) {
@@ -624,8 +622,7 @@ static int may_add_char_to_search(int firstc, int *c, incsearch_state_T *s)
return OK;
}
-static void finish_incsearch_highlighting(int gotesc, incsearch_state_T *s,
- bool call_update_screen)
+static void finish_incsearch_highlighting(int gotesc, incsearch_state_T *s, bool call_update_screen)
{
if (s->did_incsearch) {
s->did_incsearch = false;
@@ -872,7 +869,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
&& s->firstc != NUL
&& (s->some_key_typed || s->histype == HIST_SEARCH)) {
add_to_history(s->histype, ccline.cmdbuff, true,
- s->histype == HIST_SEARCH ? s->firstc : NUL);
+ s->histype == HIST_SEARCH ? s->firstc : NUL);
if (s->firstc == ':') {
xfree(new_last_cmdline);
new_last_cmdline = vim_strsave(ccline.cmdbuff);
@@ -973,12 +970,18 @@ static int command_line_execute(VimState *state, int key)
// typed by the user directly, not when the result of a
// mapping.
switch (s->c) {
- case K_RIGHT: s->c = K_LEFT; break;
- case K_S_RIGHT: s->c = K_S_LEFT; break;
- case K_C_RIGHT: s->c = K_C_LEFT; break;
- case K_LEFT: s->c = K_RIGHT; break;
- case K_S_LEFT: s->c = K_S_RIGHT; break;
- case K_C_LEFT: s->c = K_C_RIGHT; break;
+ case K_RIGHT:
+ s->c = K_LEFT; break;
+ case K_S_RIGHT:
+ s->c = K_S_LEFT; break;
+ case K_C_RIGHT:
+ s->c = K_C_LEFT; break;
+ case K_LEFT:
+ s->c = K_RIGHT; break;
+ case K_S_LEFT:
+ s->c = K_S_RIGHT; break;
+ case K_C_LEFT:
+ s->c = K_C_RIGHT; break;
}
}
}
@@ -1078,7 +1081,7 @@ static int command_line_execute(VimState *state, int key)
redrawcmd();
save_p_ls = -1;
wild_menu_showing = 0;
- // don't redraw statusline if WM_LIST is showing
+ // don't redraw statusline if WM_LIST is showing
} else if (wild_menu_showing != WM_LIST) {
win_redraw_last_status(topframe);
wild_menu_showing = 0; // must be before redraw_statuslines #8385
@@ -1155,7 +1158,7 @@ static int command_line_execute(VimState *state, int key)
s->c = (int)p_wc;
KeyTyped = true; // in case the key was mapped
} else if (STRNCMP(s->xpc.xp_pattern, upseg + 1, 3) == 0
- && s->c == K_DOWN) {
+ && s->c == K_DOWN) {
// If in a direct ancestor, strip off one ../ to go down
int found = false;
@@ -1242,7 +1245,7 @@ static int command_line_execute(VimState *state, int key)
vungetc(s->c);
s->c = Ctrl_BSL;
} else if (s->c == 'e') {
- char_u *p = NULL;
+ char_u *p = NULL;
int len;
// Replace the command line with the result of an expression.
@@ -1318,7 +1321,7 @@ static int command_line_execute(VimState *state, int key)
|| s->c == '\r'
|| s->c == K_KENTER
|| (s->c == ESC
- && (!KeyTyped || vim_strchr(p_cpo, CPO_ESC) != NULL))) {
+ && (!KeyTyped || vim_strchr(p_cpo, CPO_ESC) != NULL))) {
// In Ex mode a backslash escapes a newline.
if (exmode_active
&& s->c != ESC
@@ -1419,7 +1422,7 @@ static int command_line_execute(VimState *state, int key)
}
(void)showmatches(&s->xpc, p_wmnu
- && ((wim_flags[s->wim_index] & WIM_LIST) == 0));
+ && ((wim_flags[s->wim_index] & WIM_LIST) == 0));
redrawcmd();
s->did_wild_list = true;
@@ -1464,7 +1467,7 @@ static int command_line_execute(VimState *state, int key)
}
}
- if (s->c == NUL || s->c == K_ZERO) {
+ if (s->c == NUL || s->c == K_ZERO) {
// NUL is stored as NL
s->c = NL;
}
@@ -1476,8 +1479,7 @@ static int command_line_execute(VimState *state, int key)
// May adjust 'incsearch' highlighting for typing CTRL-G and CTRL-T, go to next
// or previous match.
// Returns FAIL when calling command_line_not_changed.
-static int may_do_command_line_next_incsearch(int firstc, long count,
- incsearch_state_T *s,
+static int may_do_command_line_next_incsearch(int firstc, long count, incsearch_state_T *s,
bool next_match)
FUNC_ATTR_NONNULL_ALL
{
@@ -1500,7 +1502,7 @@ static int may_do_command_line_next_incsearch(int firstc, long count,
ui_busy_start();
ui_flush();
- pos_T t;
+ pos_T t;
char_u *pat;
int search_flags = SEARCH_NOOF;
char_u save;
@@ -1656,7 +1658,7 @@ static int command_line_handle_key(CommandLineState *s)
if (s->c == K_DEL) {
ccline.cmdpos += mb_off_next(ccline.cmdbuff,
- ccline.cmdbuff + ccline.cmdpos);
+ ccline.cmdbuff + ccline.cmdpos);
}
if (ccline.cmdpos > 0) {
@@ -1980,8 +1982,9 @@ static int command_line_handle_key(CommandLineState *s)
return command_line_not_changed(s);
case Ctrl_A: // all matches
- if (nextwild(&s->xpc, WILD_ALL, 0, s->firstc != '@') == FAIL)
+ if (nextwild(&s->xpc, WILD_ALL, 0, s->firstc != '@') == FAIL) {
break;
+ }
return command_line_changed(s);
case Ctrl_L:
@@ -1999,7 +2002,7 @@ static int command_line_handle_key(CommandLineState *s)
case Ctrl_P: // previous match
if (s->xpc.xp_numfiles > 0) {
if (nextwild(&s->xpc, (s->c == Ctrl_P) ? WILD_PREV : WILD_NEXT,
- 0, s->firstc != '@') == FAIL) {
+ 0, s->firstc != '@') == FAIL) {
break;
}
return command_line_not_changed(s);
@@ -2033,7 +2036,7 @@ static int command_line_handle_key(CommandLineState *s)
if (s->hiscnt != s->save_hiscnt) {
// jumped to other entry
- char_u *p;
+ char_u *p;
int len = 0;
int old_firstc;
@@ -2251,7 +2254,7 @@ static int command_line_changed(CommandLineState *s)
State |= CMDPREVIEW;
emsg_silent++; // Block error reporting as the command may be incomplete
msg_silent++; // Block messages, namely ones that prompt
- do_cmdline(ccline.cmdbuff, NULL, NULL, DOCMD_KEEPLINE|DOCMD_NOWAIT);
+ do_cmdline(ccline.cmdbuff, NULL, NULL, DOCMD_KEEPLINE|DOCMD_NOWAIT|DOCMD_PREVIEW);
msg_silent--; // Unblock messages
emsg_silent--; // Unblock error reporting
@@ -2261,13 +2264,12 @@ static int command_line_changed(CommandLineState *s)
update_topline(curwin);
redrawcmdline();
-
} else if (State & CMDPREVIEW) {
State = (State & ~CMDPREVIEW);
close_preview_windows();
update_screen(SOME_VALID); // Clear 'inccommand' preview.
} else {
- if (s->xpc.xp_context == EXPAND_NOTHING) {
+ if (s->xpc.xp_context == EXPAND_NOTHING && (KeyTyped || vpeekc() == NUL)) {
may_do_incsearch_highlighting(s->firstc, s->count, &s->is_state);
}
}
@@ -2298,32 +2300,27 @@ static void abandon_cmdline(void)
redraw_cmdline = true;
}
-/*
- * getcmdline() - accept a command line starting with firstc.
- *
- * firstc == ':' get ":" command line.
- * firstc == '/' or '?' get search pattern
- * firstc == '=' get expression
- * firstc == '@' get text for input() function
- * firstc == '>' get text for debug mode
- * firstc == NUL get text for :insert command
- * firstc == -1 like NUL, and break on CTRL-C
- *
- * The line is collected in ccline.cmdbuff, which is reallocated to fit the
- * command line.
- *
- * Careful: getcmdline() can be called recursively!
- *
- * Return pointer to allocated string if there is a commandline, NULL
- * otherwise.
- */
-char_u *
-getcmdline (
- int firstc,
- long count, // only used for incremental search
- int indent, // indent for inside conditionals
- bool do_concat FUNC_ATTR_UNUSED
-)
+/// getcmdline() - accept a command line starting with firstc.
+///
+/// firstc == ':' get ":" command line.
+/// firstc == '/' or '?' get search pattern
+/// firstc == '=' get expression
+/// firstc == '@' get text for input() function
+/// firstc == '>' get text for debug mode
+/// firstc == NUL get text for :insert command
+/// firstc == -1 like NUL, and break on CTRL-C
+///
+/// The line is collected in ccline.cmdbuff, which is reallocated to fit the
+/// command line.
+///
+/// Careful: getcmdline() can be called recursively!
+///
+/// Return pointer to allocated string if there is a commandline, NULL
+/// otherwise.
+///
+/// @param count only used for incremental search
+/// @param indent indent for inside conditionals
+char_u *getcmdline(int firstc, long count, int indent, bool do_concat FUNC_ATTR_UNUSED)
{
// Be prepared for situations where cmdline can be invoked recursively.
// That includes cmd mappings, event handlers, as well as update_screen()
@@ -2348,9 +2345,8 @@ getcmdline (
/// @param[in] highlight_callback Callback used for highlighting user input.
///
/// @return [allocated] Command line or NULL.
-char *getcmdline_prompt(const char firstc, const char *const prompt,
- const int attr, const int xp_context,
- const char *const xp_arg,
+char *getcmdline_prompt(const char firstc, const char *const prompt, const int attr,
+ const int xp_context, const char *const xp_arg,
const Callback highlight_callback)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_MALLOC
{
@@ -2390,8 +2386,9 @@ char *getcmdline_prompt(const char firstc, const char *const prompt,
* another window or buffer. Used when editing the command line etc.
*/
int text_locked(void) {
- if (cmdwin_type != 0)
+ if (cmdwin_type != 0) {
return TRUE;
+ }
return textlock != 0;
}
@@ -2404,7 +2401,7 @@ void text_locked_msg(void)
EMSG(_(get_text_locked_msg()));
}
-char_u * get_text_locked_msg(void) {
+char_u *get_text_locked_msg(void) {
if (cmdwin_type != 0) {
return e_cmdwin;
} else {
@@ -2412,13 +2409,11 @@ char_u * get_text_locked_msg(void) {
}
}
-/*
- * Check if "curbuf_lock" or "allbuf_lock" is set and return TRUE when it is
- * and give an error message.
- */
+/// Check if "curbuf->b_ro_locked" or "allbuf_lock" is set and
+/// return TRUE when it is and give an error message.
int curbuf_locked(void)
{
- if (curbuf_lock > 0) {
+ if (curbuf->b_ro_locked > 0) {
EMSG(_("E788: Not allowed to edit another buffer now"));
return TRUE;
}
@@ -2440,8 +2435,9 @@ int allbuf_locked(void)
static int cmdline_charsize(int idx)
{
- if (cmdline_star > 0) /* showing '*', always 1 position */
+ if (cmdline_star > 0) { // showing '*', always 1 position
return 1;
+ }
return ptr2cells(ccline.cmdbuff + idx);
}
@@ -2461,8 +2457,9 @@ static int cmd_screencol(int bytepos)
int col = cmd_startcol();
if (KeyTyped) {
m = Columns * Rows;
- if (m < 0) /* overflow, Columns or Rows at weird value */
+ if (m < 0) { // overflow, Columns or Rows at weird value
m = MAXCOL;
+ }
} else {
m = MAXCOL;
}
@@ -2494,282 +2491,18 @@ static void correct_screencol(int idx, int cells, int *col)
}
}
-/*
- * Get an Ex command line for the ":" command.
- */
-char_u *
-getexline(
- int c, // normally ':', NUL for ":append"
- void *cookie,
- int indent, // indent for inside conditionals
- bool do_concat
-)
+/// Get an Ex command line for the ":" command.
+///
+/// @param c normally ':', NUL for ":append"
+/// @param indent indent for inside conditionals
+char_u *getexline(int c, void *cookie, int indent, bool do_concat)
{
- /* When executing a register, remove ':' that's in front of each line. */
- if (exec_from_reg && vpeekc() == ':')
+ // When executing a register, remove ':' that's in front of each line.
+ if (exec_from_reg && vpeekc() == ':') {
(void)vgetc();
-
- return getcmdline(c, 1L, indent, do_concat);
-}
-
-/*
- * Get an Ex command line for Ex mode.
- * In Ex mode we only use the OS supplied line editing features and no
- * mappings or abbreviations.
- * Returns a string in allocated memory or NULL.
- */
-char_u *
-getexmodeline(
- int promptc, // normally ':', NUL for ":append" and '?'
- // for :s prompt
- void *cookie,
- int indent, // indent for inside conditionals
- bool do_concat
-)
-{
- garray_T line_ga;
- char_u *pend;
- int startcol = 0;
- int c1 = 0;
- int escaped = FALSE; /* CTRL-V typed */
- int vcol = 0;
- char_u *p;
- int prev_char;
- int len;
-
- /* always start in column 0; write a newline if necessary */
- compute_cmdrow();
- if ((msg_col || msg_didout) && promptc != '?')
- msg_putchar('\n');
- if (promptc == ':') {
- /* indent that is only displayed, not in the line itself */
- if (p_prompt)
- msg_putchar(':');
- while (indent-- > 0)
- msg_putchar(' ');
- startcol = msg_col;
}
- ga_init(&line_ga, 1, 30);
-
- /* autoindent for :insert and :append is in the line itself */
- if (promptc <= 0) {
- vcol = indent;
- while (indent >= 8) {
- ga_append(&line_ga, TAB);
- msg_puts(" ");
- indent -= 8;
- }
- while (indent-- > 0) {
- ga_append(&line_ga, ' ');
- msg_putchar(' ');
- }
- }
- no_mapping++;
-
- /*
- * Get the line, one character at a time.
- */
- got_int = FALSE;
- while (!got_int) {
- ga_grow(&line_ga, 40);
-
- /* Get one character at a time. Don't use inchar(), it can't handle
- * special characters. */
- prev_char = c1;
-
- // Check for a ":normal" command and no more characters left.
- if (ex_normal_busy > 0 && typebuf.tb_len == 0) {
- c1 = '\n';
- } else {
- c1 = vgetc();
- }
-
- /*
- * Handle line editing.
- * Previously this was left to the system, putting the terminal in
- * cooked mode, but then CTRL-D and CTRL-T can't be used properly.
- */
- if (got_int) {
- msg_putchar('\n');
- break;
- }
-
- if (!escaped) {
- /* CR typed means "enter", which is NL */
- if (c1 == '\r')
- c1 = '\n';
-
- if (c1 == BS || c1 == K_BS || c1 == DEL || c1 == K_DEL || c1 == K_KDEL) {
- if (!GA_EMPTY(&line_ga)) {
- p = (char_u *)line_ga.ga_data;
- p[line_ga.ga_len] = NUL;
- len = utf_head_off(p, p + line_ga.ga_len - 1) + 1;
- line_ga.ga_len -= len;
- goto redraw;
- }
- continue;
- }
-
- if (c1 == Ctrl_U) {
- msg_col = startcol;
- msg_clr_eos();
- line_ga.ga_len = 0;
- goto redraw;
- }
-
- int num_spaces;
- if (c1 == Ctrl_T) {
- int sw = get_sw_value(curbuf);
-
- p = (char_u *)line_ga.ga_data;
- p[line_ga.ga_len] = NUL;
- indent = get_indent_str(p, 8, FALSE);
- num_spaces = sw - indent % sw;
-add_indent:
- if (num_spaces > 0) {
- ga_grow(&line_ga, num_spaces + 1);
- p = (char_u *)line_ga.ga_data;
- char_u *s = skipwhite(p);
-
- // Insert spaces after leading whitespaces.
- long move_len = line_ga.ga_len - (s - p) + 1;
- assert(move_len >= 0);
- memmove(s + num_spaces, s, (size_t)move_len);
- memset(s, ' ', (size_t)num_spaces);
-
- line_ga.ga_len += num_spaces;
- }
-redraw:
- /* redraw the line */
- msg_col = startcol;
- vcol = 0;
- p = (char_u *)line_ga.ga_data;
- p[line_ga.ga_len] = NUL;
- while (p < (char_u *)line_ga.ga_data + line_ga.ga_len) {
- if (*p == TAB) {
- do {
- msg_putchar(' ');
- } while (++vcol % 8);
- p++;
- } else {
- len = utfc_ptr2len(p);
- msg_outtrans_len(p, len);
- vcol += ptr2cells(p);
- p += len;
- }
- }
- msg_clr_eos();
- cmd_cursor_goto(msg_row, msg_col);
- continue;
- }
-
- if (c1 == Ctrl_D) {
- /* Delete one shiftwidth. */
- p = (char_u *)line_ga.ga_data;
- if (prev_char == '0' || prev_char == '^') {
- if (prev_char == '^')
- ex_keep_indent = TRUE;
- indent = 0;
- p[--line_ga.ga_len] = NUL;
- } else {
- p[line_ga.ga_len] = NUL;
- indent = get_indent_str(p, 8, FALSE);
- if (indent == 0) {
- continue;
- }
- --indent;
- indent -= indent % get_sw_value(curbuf);
- }
-
- // reduce the line's indentation
- char_u *from = skipwhite(p);
- char_u *to = from;
- int old_indent;
- while ((old_indent = get_indent_str(p, 8, FALSE)) > indent) {
- *--to = NUL;
- }
- long move_len = line_ga.ga_len - (from - p) + 1;
- assert(move_len > 0);
- memmove(to, from, (size_t)move_len);
- line_ga.ga_len -= (int)(from - to);
-
- // Removed to much indentation, fix it before redrawing.
- num_spaces = indent - old_indent;
- goto add_indent;
- }
-
- if (c1 == Ctrl_V || c1 == Ctrl_Q) {
- escaped = TRUE;
- continue;
- }
-
- if (IS_SPECIAL(c1)) {
- // Ignore other special key codes
- continue;
- }
- }
-
- if (IS_SPECIAL(c1)) {
- c1 = '?';
- }
- len = utf_char2bytes(c1, (char_u *)line_ga.ga_data + line_ga.ga_len);
- if (c1 == '\n') {
- msg_putchar('\n');
- } else if (c1 == TAB) {
- // Don't use chartabsize(), 'ts' can be different.
- do {
- msg_putchar(' ');
- } while (++vcol % 8);
- } else {
- msg_outtrans_len(((char_u *)line_ga.ga_data) + line_ga.ga_len, len);
- vcol += char2cells(c1);
- }
- line_ga.ga_len += len;
- escaped = FALSE;
-
- cmd_cursor_goto(msg_row, msg_col);
- pend = (char_u *)(line_ga.ga_data) + line_ga.ga_len;
-
- /* We are done when a NL is entered, but not when it comes after an
- * odd number of backslashes, that results in a NUL. */
- if (!GA_EMPTY(&line_ga) && pend[-1] == '\n') {
- int bcount = 0;
-
- while (line_ga.ga_len - 2 >= bcount && pend[-2 - bcount] == '\\')
- ++bcount;
-
- if (bcount > 0) {
- /* Halve the number of backslashes: "\NL" -> "NUL", "\\NL" ->
- * "\NL", etc. */
- line_ga.ga_len -= (bcount + 1) / 2;
- pend -= (bcount + 1) / 2;
- pend[-1] = '\n';
- }
-
- if ((bcount & 1) == 0) {
- --line_ga.ga_len;
- --pend;
- *pend = NUL;
- break;
- }
- }
- }
-
- no_mapping--;
-
- /* make following messages go to the next line */
- msg_didout = FALSE;
- msg_col = 0;
- if (msg_row < Rows - 1) {
- msg_row++;
- }
- emsg_on_display = false; // don't want os_delay()
-
- if (got_int)
- ga_clear(&line_ga);
-
- return (char_u *)line_ga.ga_data;
+ return getcmdline(c, 1L, indent, do_concat);
}
bool cmdline_overstrike(void)
@@ -2794,10 +2527,11 @@ static void alloc_cmdbuff(int len)
/*
* give some extra space to avoid having to allocate all the time
*/
- if (len < 80)
+ if (len < 80) {
len = 100;
- else
+ } else {
len += 20;
+ }
ccline.cmdbuff = xmalloc((size_t)len);
ccline.cmdbufflen = len;
@@ -2813,7 +2547,7 @@ static void realloc_cmdbuff(int len)
}
char_u *p = ccline.cmdbuff;
- alloc_cmdbuff(len); /* will get some more */
+ alloc_cmdbuff(len); // will get some more
/* There isn't always a NUL after the command, but it may need to be
* there, thus copy up to the NUL and add a NUL. */
memmove(ccline.cmdbuff, p, (size_t)ccline.cmdlen);
@@ -2828,20 +2562,21 @@ static void realloc_cmdbuff(int len)
/* If xp_pattern points inside the old cmdbuff it needs to be adjusted
* to point into the newly allocated memory. */
- if (i >= 0 && i <= ccline.cmdlen)
+ if (i >= 0 && i <= ccline.cmdlen) {
ccline.xpc->xp_pattern = ccline.cmdbuff + i;
+ }
}
}
-static char_u *arshape_buf = NULL;
+static char_u *arshape_buf = NULL;
-# if defined(EXITFREE)
+#if defined(EXITFREE)
void free_arshape_buf(void)
{
xfree(arshape_buf);
}
-# endif
+#endif
enum { MAX_CB_ERRORS = 1 };
@@ -2855,7 +2590,7 @@ static void color_expr_cmdline(const CmdlineInfo *const colored_ccline,
ColoredCmdline *const ret_ccline_colors)
FUNC_ATTR_NONNULL_ALL
{
- ParserLine plines[] = {
+ ParserLine parser_lines[] = {
{
.data = (const char *)colored_ccline->cmdbuff,
.size = STRLEN(colored_ccline->cmdbuff),
@@ -2863,12 +2598,11 @@ static void color_expr_cmdline(const CmdlineInfo *const colored_ccline,
},
{ NULL, 0, false },
};
- ParserLine *plines_p = plines;
+ ParserLine *plines_p = parser_lines;
ParserHighlight colors;
kvi_init(colors);
ParserState pstate;
- viml_parser_init(
- &pstate, parser_simple_get_line, &plines_p, &colors);
+ viml_parser_init(&pstate, parser_simple_get_line, &plines_p, &colors);
ExprAST east = viml_pexpr_parse(&pstate, kExprFlagsDisallowEOC);
viml_pexpr_free_ast(east);
viml_parser_destroy(&pstate);
@@ -2888,9 +2622,9 @@ static void color_expr_cmdline(const CmdlineInfo *const colored_ccline,
const int id = syn_name2id((const char_u *)chunk.group);
const int attr = (id == 0 ? 0 : syn_id2attr(id));
kv_push(ret_ccline_colors->colors, ((CmdlineColorChunk) {
- .start = (int)chunk.start.col,
- .end = (int)chunk.end_col,
- .attr = attr,
+ .start = (int)chunk.start.col,
+ .end = (int)chunk.end_col,
+ .attr = attr,
}));
prev_end = chunk.end_col;
}
@@ -2978,8 +2712,7 @@ static bool color_cmdline(CmdlineInfo *colored_ccline)
color_cb = colored_ccline->highlight_callback;
} else if (colored_ccline->cmdfirstc == ':') {
try_enter(&tstate);
- err_errmsg = N_(
- "E5408: Unable to get g:Nvim_color_cmdline callback: %s");
+ err_errmsg = N_("E5408: Unable to get g:Nvim_color_cmdline callback: %s");
dgc_ret = tv_dict_get_callback(&globvardict, S_LEN("Nvim_color_cmdline"),
&color_cb);
tl_ret = try_leave(&tstate, &err);
@@ -3047,7 +2780,7 @@ static bool color_cmdline(CmdlineInfo *colored_ccline)
}
bool error = false;
const varnumber_T start = (
- tv_get_number_chk(TV_LIST_ITEM_TV(tv_list_first(l)), &error));
+ tv_get_number_chk(TV_LIST_ITEM_TV(tv_list_first(l)), &error));
if (error) {
goto color_cmdline_error;
} else if (!(prev_end <= start && start < colored_ccline->cmdlen)) {
@@ -3067,8 +2800,8 @@ static bool color_cmdline(CmdlineInfo *colored_ccline)
.attr = 0,
}));
}
- const varnumber_T end = tv_get_number_chk(
- TV_LIST_ITEM_TV(TV_LIST_ITEM_NEXT(l, tv_list_first(l))), &error);
+ const varnumber_T end =
+ tv_get_number_chk(TV_LIST_ITEM_TV(TV_LIST_ITEM_NEXT(l, tv_list_first(l))), &error);
if (error) {
goto color_cmdline_error;
} else if (!(start < end && end <= colored_ccline->cmdlen)) {
@@ -3084,8 +2817,7 @@ static bool color_cmdline(CmdlineInfo *colored_ccline)
goto color_cmdline_error;
}
prev_end = end;
- const char *const group = tv_get_string_chk(
- TV_LIST_ITEM_TV(tv_list_last(l)));
+ const char *const group = tv_get_string_chk(TV_LIST_ITEM_TV(tv_list_last(l)));
if (group == NULL) {
goto color_cmdline_error;
}
@@ -3403,8 +3135,8 @@ void putcmdline(char c, int shift)
}
msg_no_more = false;
} else if (ccline.redraw_state != kCmdRedrawAll) {
- ui_call_cmdline_special_char(cchar_to_string((char)(c)), shift,
- ccline.level);
+ ui_call_cmdline_special_char(cchar_to_string((char)(c)), shift,
+ ccline.level);
}
cursorcmd();
ccline.special_char = c;
@@ -3444,15 +3176,16 @@ void put_on_cmdline(char_u *str, int len, int redraw)
int m;
int c;
- if (len < 0)
+ if (len < 0) {
len = (int)STRLEN(str);
+ }
realloc_cmdbuff(ccline.cmdlen + len + 1);
if (!ccline.overstrike) {
memmove(ccline.cmdbuff + ccline.cmdpos + len,
- ccline.cmdbuff + ccline.cmdpos,
- (size_t)(ccline.cmdlen - ccline.cmdpos));
+ ccline.cmdbuff + ccline.cmdpos,
+ (size_t)(ccline.cmdlen - ccline.cmdpos));
ccline.cmdlen += len;
} else {
// Count nr of characters in the new string.
@@ -3494,11 +3227,12 @@ void put_on_cmdline(char_u *str, int len, int redraw)
if (arabic_combine(utf_ptr2char(ccline.cmdbuff + ccline.cmdpos - i), c)) {
ccline.cmdpos -= i;
len += i;
- } else
+ } else {
i = 0;
+ }
}
if (i != 0) {
- /* Also backup the cursor position. */
+ // Also backup the cursor position.
i = ptr2cells(ccline.cmdbuff + ccline.cmdpos);
ccline.cmdspos -= i;
msg_col -= i;
@@ -3514,9 +3248,10 @@ void put_on_cmdline(char_u *str, int len, int redraw)
i = cmdline_row;
cursorcmd();
draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos);
- /* Avoid clearing the rest of the line too often. */
- if (cmdline_row != i || ccline.overstrike)
+ // Avoid clearing the rest of the line too often.
+ if (cmdline_row != i || ccline.overstrike) {
msg_clr_eos();
+ }
msg_no_more = FALSE;
}
if (KeyTyped) {
@@ -3610,8 +3345,8 @@ void restore_cmdline_alloc(char_u *p)
/// @returns FAIL for failure, OK otherwise
static bool cmdline_paste(int regname, bool literally, bool remcr)
{
- char_u *arg;
- char_u *p;
+ char_u *arg;
+ char_u *p;
bool allocated;
struct cmdline_info save_ccline;
@@ -3626,8 +3361,9 @@ static bool cmdline_paste(int regname, bool literally, bool remcr)
/* A register containing CTRL-R can cause an endless loop. Allow using
* CTRL-C to break the loop. */
line_breakcheck();
- if (got_int)
+ if (got_int) {
return FAIL;
+ }
/* Need to save and restore ccline. And set "textlock" to avoid nasty
@@ -3639,18 +3375,19 @@ static bool cmdline_paste(int regname, bool literally, bool remcr)
restore_cmdline(&save_ccline);
if (i) {
- /* Got the value of a special register in "arg". */
- if (arg == NULL)
+ // Got the value of a special register in "arg".
+ if (arg == NULL) {
return FAIL;
+ }
/* When 'incsearch' is set and CTRL-R CTRL-W used: skip the duplicate
* part of the word. */
p = arg;
if (p_is && regname == Ctrl_W) {
- char_u *w;
+ char_u *w;
int len;
- /* Locate start of last word in the cmd buffer. */
+ // Locate start of last word in the cmd buffer.
for (w = ccline.cmdbuff + ccline.cmdpos; w > ccline.cmdbuff; ) {
len = utf_head_off(ccline.cmdbuff, w - 1) + 1;
if (!vim_iswordc(utf_ptr2char(w - len))) {
@@ -3659,13 +3396,15 @@ static bool cmdline_paste(int regname, bool literally, bool remcr)
w -= len;
}
len = (int)((ccline.cmdbuff + ccline.cmdpos) - w);
- if (p_ic ? STRNICMP(w, arg, len) == 0 : STRNCMP(w, arg, len) == 0)
+ if (p_ic ? STRNICMP(w, arg, len) == 0 : STRNCMP(w, arg, len) == 0) {
p += len;
+ }
}
cmdline_paste_str(p, literally);
- if (allocated)
+ if (allocated) {
xfree(arg);
+ }
return OK;
}
@@ -3682,9 +3421,9 @@ void cmdline_paste_str(char_u *s, int literally)
{
int c, cv;
- if (literally)
+ if (literally) {
put_on_cmdline(s, -1, TRUE);
- else
+ } else {
while (*s != NUL) {
cv = *s;
if (cv == Ctrl_V && s[1]) {
@@ -3698,6 +3437,7 @@ void cmdline_paste_str(char_u *s, int literally)
}
stuffcharReadbuff(c);
}
+ }
}
/// Delete characters on the command line, from "from" to the current position.
@@ -3715,9 +3455,10 @@ static void cmdline_del(int from)
// overwritten.
void redrawcmdline(void)
{
- if (cmd_silent)
+ if (cmd_silent) {
return;
- need_wait_return = FALSE;
+ }
+ need_wait_return = false;
compute_cmdrow();
redrawcmd();
cursorcmd();
@@ -3728,8 +3469,9 @@ static void redrawcmdprompt(void)
{
int i;
- if (cmd_silent)
+ if (cmd_silent) {
return;
+ }
if (ui_has(kUICmdline)) {
ccline.redraw_state = kCmdRedrawAll;
return;
@@ -3756,15 +3498,16 @@ static void redrawcmdprompt(void)
*/
void redrawcmd(void)
{
- if (cmd_silent)
+ if (cmd_silent) {
return;
+ }
if (ui_has(kUICmdline)) {
draw_cmdline(0, ccline.cmdlen);
return;
}
- /* when 'incsearch' is set there may be no command line while redrawing */
+ // when 'incsearch' is set there may be no command line while redrawing
if (ccline.cmdbuff == NULL) {
cmd_cursor_goto(cmdline_row, 0);
msg_clr_eos();
@@ -3776,7 +3519,7 @@ void redrawcmd(void)
msg_start();
redrawcmdprompt();
- /* Don't use more prompt, truncate the cmdline if it doesn't fit. */
+ // Don't use more prompt, truncate the cmdline if it doesn't fit.
msg_no_more = TRUE;
draw_cmdline(0, ccline.cmdlen);
msg_clr_eos();
@@ -3792,7 +3535,7 @@ void redrawcmd(void)
* An emsg() before may have set msg_scroll. This is used in normal mode,
* in cmdline mode we can reset them now.
*/
- msg_scroll = FALSE; /* next message overwrites cmdline */
+ msg_scroll = FALSE; // next message overwrites cmdline
// Typing ':' at the more prompt may set skip_redraw. We don't want this
// in cmdline mode.
@@ -3815,8 +3558,9 @@ void compute_cmdrow(void)
static void cursorcmd(void)
{
- if (cmd_silent)
+ if (cmd_silent) {
return;
+ }
if (ui_has(kUICmdline)) {
if (ccline.redraw_state < kCmdRedrawPos) {
@@ -3904,28 +3648,27 @@ static int sort_func_compare(const void *s1, const void *s2)
char_u *p1 = *(char_u **)s1;
char_u *p2 = *(char_u **)s2;
- if (*p1 != '<' && *p2 == '<') return -1;
- if (*p1 == '<' && *p2 != '<') return 1;
+ if (*p1 != '<' && *p2 == '<') {
+ return -1;
+ }
+ if (*p1 == '<' && *p2 != '<') {
+ return 1;
+ }
return STRCMP(p1, p2);
}
-/*
- * Return FAIL if this is not an appropriate context in which to do
- * completion of anything, return OK if it is (even if there are no matches).
- * For the caller, this means that the character is just passed through like a
- * normal character (instead of being expanded). This allows :s/^I^D etc.
- */
-static int
-nextwild (
- expand_T *xp,
- int type,
- int options, /* extra options for ExpandOne() */
- int escape /* if TRUE, escape the returned matches */
-)
+/// Return FAIL if this is not an appropriate context in which to do
+/// completion of anything, return OK if it is (even if there are no matches).
+/// For the caller, this means that the character is just passed through like a
+/// normal character (instead of being expanded). This allows :s/^I^D etc.
+///
+/// @param options extra options for ExpandOne()
+/// @param escape if TRUE, escape the returned matches
+static int nextwild(expand_T *xp, int type, int options, int escape)
{
int i, j;
- char_u *p1;
- char_u *p2;
+ char_u *p1;
+ char_u *p2;
int difflen;
if (xp->xp_numfiles == -1) {
@@ -3935,10 +3678,10 @@ nextwild (
if (xp->xp_context == EXPAND_UNSUCCESSFUL) {
beep_flush();
- return OK; /* Something illegal on command line */
+ return OK; // Something illegal on command line
}
if (xp->xp_context == EXPAND_NOTHING) {
- /* Caller can use the character as a normal char instead */
+ // Caller can use the character as a normal char instead
return FAIL;
}
@@ -3958,12 +3701,12 @@ nextwild (
// Translate string into pattern and expand it.
p1 = addstar(xp->xp_pattern, xp->xp_pattern_len, xp->xp_context);
const int use_options = (
- options
- | WILD_HOME_REPLACE
- | WILD_ADD_SLASH
- | WILD_SILENT
- | (escape ? WILD_ESCAPE : 0)
- | (p_wic ? WILD_ICASE : 0));
+ options
+ | WILD_HOME_REPLACE
+ | WILD_ADD_SLASH
+ | WILD_SILENT
+ | (escape ? WILD_ESCAPE : 0)
+ | (p_wic ? WILD_ICASE : 0));
p2 = ExpandOne(xp, p1, vim_strnsave(&ccline.cmdbuff[i], xp->xp_pattern_len),
use_options, type);
xfree(p1);
@@ -4008,67 +3751,62 @@ nextwild (
/* When expanding a ":map" command and no matches are found, assume that
* the key is supposed to be inserted literally */
- if (xp->xp_context == EXPAND_MAPPINGS && p2 == NULL)
+ if (xp->xp_context == EXPAND_MAPPINGS && p2 == NULL) {
return FAIL;
+ }
- if (xp->xp_numfiles <= 0 && p2 == NULL)
+ if (xp->xp_numfiles <= 0 && p2 == NULL) {
beep_flush();
- else if (xp->xp_numfiles == 1)
- /* free expanded pattern */
+ } else if (xp->xp_numfiles == 1) {
+ // free expanded pattern
(void)ExpandOne(xp, NULL, NULL, 0, WILD_FREE);
+ }
return OK;
}
-/*
- * Do wildcard expansion on the string 'str'.
- * Chars that should not be expanded must be preceded with a backslash.
- * Return a pointer to allocated memory containing the new string.
- * Return NULL for failure.
- *
- * "orig" is the originally expanded string, copied to allocated memory. It
- * should either be kept in orig_save or freed. When "mode" is WILD_NEXT or
- * WILD_PREV "orig" should be NULL.
- *
- * Results are cached in xp->xp_files and xp->xp_numfiles, except when "mode"
- * is WILD_EXPAND_FREE or WILD_ALL.
- *
- * mode = WILD_FREE: just free previously expanded matches
- * mode = WILD_EXPAND_FREE: normal expansion, do not keep matches
- * mode = WILD_EXPAND_KEEP: normal expansion, keep matches
- * mode = WILD_NEXT: use next match in multiple match, wrap to first
- * mode = WILD_PREV: use previous match in multiple match, wrap to first
- * mode = WILD_ALL: return all matches concatenated
- * mode = WILD_LONGEST: return longest matched part
- * mode = WILD_ALL_KEEP: get all matches, keep matches
- *
- * options = WILD_LIST_NOTFOUND: list entries without a match
- * options = WILD_HOME_REPLACE: do home_replace() for buffer names
- * options = WILD_USE_NL: Use '\n' for WILD_ALL
- * options = WILD_NO_BEEP: Don't beep for multiple matches
- * options = WILD_ADD_SLASH: add a slash after directory names
- * options = WILD_KEEP_ALL: don't remove 'wildignore' entries
- * options = WILD_SILENT: don't print warning messages
- * options = WILD_ESCAPE: put backslash before special chars
- * options = WILD_ICASE: ignore case for files
- *
- * The variables xp->xp_context and xp->xp_backslash must have been set!
- */
-char_u *
-ExpandOne (
- expand_T *xp,
- char_u *str,
- char_u *orig, /* allocated copy of original of expanded string */
- int options,
- int mode
-)
+/// Do wildcard expansion on the string 'str'.
+/// Chars that should not be expanded must be preceded with a backslash.
+/// Return a pointer to allocated memory containing the new string.
+/// Return NULL for failure.
+///
+/// "orig" is the originally expanded string, copied to allocated memory. It
+/// should either be kept in orig_save or freed. When "mode" is WILD_NEXT or
+/// WILD_PREV "orig" should be NULL.
+///
+/// Results are cached in xp->xp_files and xp->xp_numfiles, except when "mode"
+/// is WILD_EXPAND_FREE or WILD_ALL.
+///
+/// mode = WILD_FREE: just free previously expanded matches
+/// mode = WILD_EXPAND_FREE: normal expansion, do not keep matches
+/// mode = WILD_EXPAND_KEEP: normal expansion, keep matches
+/// mode = WILD_NEXT: use next match in multiple match, wrap to first
+/// mode = WILD_PREV: use previous match in multiple match, wrap to first
+/// mode = WILD_ALL: return all matches concatenated
+/// mode = WILD_LONGEST: return longest matched part
+/// mode = WILD_ALL_KEEP: get all matches, keep matches
+///
+/// options = WILD_LIST_NOTFOUND: list entries without a match
+/// options = WILD_HOME_REPLACE: do home_replace() for buffer names
+/// options = WILD_USE_NL: Use '\n' for WILD_ALL
+/// options = WILD_NO_BEEP: Don't beep for multiple matches
+/// options = WILD_ADD_SLASH: add a slash after directory names
+/// options = WILD_KEEP_ALL: don't remove 'wildignore' entries
+/// options = WILD_SILENT: don't print warning messages
+/// options = WILD_ESCAPE: put backslash before special chars
+/// options = WILD_ICASE: ignore case for files
+///
+/// The variables xp->xp_context and xp->xp_backslash must have been set!
+///
+/// @param orig allocated copy of original of expanded string
+char_u *ExpandOne(expand_T *xp, char_u *str, char_u *orig, int options, int mode)
{
- char_u *ss = NULL;
+ char_u *ss = NULL;
static int findex;
- static char_u *orig_save = NULL; /* kept value of orig */
+ static char_u *orig_save = NULL; // kept value of orig
int orig_saved = FALSE;
int i;
- int non_suf_match; /* number without matching suffix */
+ int non_suf_match; // number without matching suffix
/*
* first handle the case of using an old match
@@ -4076,27 +3814,31 @@ ExpandOne (
if (mode == WILD_NEXT || mode == WILD_PREV) {
if (xp->xp_numfiles > 0) {
if (mode == WILD_PREV) {
- if (findex == -1)
+ if (findex == -1) {
findex = xp->xp_numfiles;
+ }
--findex;
- } else /* mode == WILD_NEXT */
+ } else { // mode == WILD_NEXT
++findex;
+ }
/*
* When wrapping around, return the original string, set findex to
* -1.
*/
if (findex < 0) {
- if (orig_save == NULL)
+ if (orig_save == NULL) {
findex = xp->xp_numfiles - 1;
- else
+ } else {
findex = -1;
+ }
}
if (findex >= xp->xp_numfiles) {
- if (orig_save == NULL)
+ if (orig_save == NULL) {
findex = 0;
- else
+ } else {
findex = -1;
+ }
}
if (compl_match_array) {
compl_selected = findex;
@@ -4109,8 +3851,9 @@ ExpandOne (
return vim_strsave(orig_save);
}
return vim_strsave(xp->xp_files[findex]);
- } else
+ } else {
return NULL;
+ }
}
if (mode == WILD_CANCEL) {
@@ -4120,7 +3863,7 @@ ExpandOne (
xp->xp_files[findex]);
}
- /* free old names */
+ // free old names
if (xp->xp_numfiles != -1 && mode != WILD_ALL && mode != WILD_LONGEST) {
FreeWild(xp->xp_numfiles, xp->xp_files);
xp->xp_numfiles = -1;
@@ -4128,8 +3871,9 @@ ExpandOne (
}
findex = 0;
- if (mode == WILD_FREE) /* only release file name */
+ if (mode == WILD_FREE) { // only release file name
return NULL;
+ }
if (xp->xp_numfiles == -1 && mode != WILD_APPLY && mode != WILD_CANCEL) {
xfree(orig_save);
@@ -4140,20 +3884,22 @@ ExpandOne (
* Do the expansion.
*/
if (ExpandFromContext(xp, str, &xp->xp_numfiles, &xp->xp_files,
- options) == FAIL) {
+ options) == FAIL) {
#ifdef FNAME_ILLEGAL
/* Illegal file name has been silently skipped. But when there
* are wildcards, the real problem is that there was no match,
* causing the pattern to be added, which has illegal characters.
*/
- if (!(options & WILD_SILENT) && (options & WILD_LIST_NOTFOUND))
+ if (!(options & WILD_SILENT) && (options & WILD_LIST_NOTFOUND)) {
EMSG2(_(e_nomatch2), str);
+ }
#endif
} else if (xp->xp_numfiles == 0) {
- if (!(options & WILD_SILENT))
+ if (!(options & WILD_SILENT)) {
EMSG2(_(e_nomatch2), str);
+ }
} else {
- /* Escape the matches for use on the command line. */
+ // Escape the matches for use on the command line.
ExpandEscape(xp, str, xp->xp_numfiles, xp->xp_files, options);
/*
@@ -4161,10 +3907,11 @@ ExpandOne (
*/
if (mode != WILD_ALL && mode != WILD_ALL_KEEP
&& mode != WILD_LONGEST) {
- if (xp->xp_numfiles)
+ if (xp->xp_numfiles) {
non_suf_match = xp->xp_numfiles;
- else
+ } else {
non_suf_match = 1;
+ }
if ((xp->xp_context == EXPAND_FILES
|| xp->xp_context == EXPAND_DIRECTORIES)
&& xp->xp_numfiles > 1) {
@@ -4174,9 +3921,11 @@ ExpandOne (
* expand_wildcards, only need to check the first two.
*/
non_suf_match = 0;
- for (i = 0; i < 2; ++i)
- if (match_suffix(xp->xp_files[i]))
+ for (i = 0; i < 2; ++i) {
+ if (match_suffix(xp->xp_files[i])) {
++non_suf_match;
+ }
+ }
}
if (non_suf_match != 1) {
/* Can we ever get here unless it's while expanding
@@ -4184,13 +3933,15 @@ ExpandOne (
* together. Don't really want to wait for this message
* (and possibly have to hit return to continue!).
*/
- if (!(options & WILD_SILENT))
+ if (!(options & WILD_SILENT)) {
EMSG(_(e_toomany));
- else if (!(options & WILD_NO_BEEP))
+ } else if (!(options & WILD_NO_BEEP)) {
beep_flush();
+ }
}
- if (!(non_suf_match != 1 && mode == WILD_EXPAND_FREE))
+ if (!(non_suf_match != 1 && mode == WILD_EXPAND_FREE)) {
ss = vim_strsave(xp->xp_files[0]);
+ }
}
}
}
@@ -4232,23 +3983,27 @@ ExpandOne (
// TODO(philix): use xstpcpy instead of strcat in a loop (ExpandOne)
if (mode == WILD_ALL && xp->xp_numfiles > 0) {
size_t len = 0;
- for (i = 0; i < xp->xp_numfiles; ++i)
+ for (i = 0; i < xp->xp_numfiles; ++i) {
len += STRLEN(xp->xp_files[i]) + 1;
+ }
ss = xmalloc(len);
*ss = NUL;
for (i = 0; i < xp->xp_numfiles; ++i) {
STRCAT(ss, xp->xp_files[i]);
- if (i != xp->xp_numfiles - 1)
+ if (i != xp->xp_numfiles - 1) {
STRCAT(ss, (options & WILD_USE_NL) ? "\n" : " ");
+ }
}
}
- if (mode == WILD_EXPAND_FREE || mode == WILD_ALL)
+ if (mode == WILD_EXPAND_FREE || mode == WILD_ALL) {
ExpandCleanup(xp);
+ }
- /* Free "orig" if it wasn't stored in "orig_save". */
- if (!orig_saved)
+ // Free "orig" if it wasn't stored in "orig_save".
+ if (!orig_saved) {
xfree(orig);
+ }
return ss;
}
@@ -4278,13 +4033,14 @@ void ExpandCleanup(expand_T *xp)
void ExpandEscape(expand_T *xp, char_u *str, int numfiles, char_u **files, int options)
{
int i;
- char_u *p;
+ char_u *p;
/*
* May change home directory back to "~"
*/
- if (options & WILD_HOME_REPLACE)
+ if (options & WILD_HOME_REPLACE) {
tilde_replace(str, numfiles, files);
+ }
if (options & WILD_ESCAPE) {
if (xp->xp_context == EXPAND_FILES
@@ -4297,7 +4053,7 @@ void ExpandEscape(expand_T *xp, char_u *str, int numfiles, char_u **files, int o
* and wildmatch characters, except '~'.
*/
for (i = 0; i < numfiles; ++i) {
- /* for ":set path=" we need to escape spaces twice */
+ // for ":set path=" we need to escape spaces twice
if (xp->xp_backslash == XP_BS_THREE) {
p = vim_strsave_escaped(files[i], (char_u *)" ");
xfree(files[i]);
@@ -4319,15 +4075,17 @@ void ExpandEscape(expand_T *xp, char_u *str, int numfiles, char_u **files, int o
/* If 'str' starts with "\~", replace "~" at start of
* files[i] with "\~". */
- if (str[0] == '\\' && str[1] == '~' && files[i][0] == '~')
+ if (str[0] == '\\' && str[1] == '~' && files[i][0] == '~') {
escape_fname(&files[i]);
+ }
}
xp->xp_backslash = XP_BS_NONE;
/* If the first file starts with a '+' escape it. Otherwise it
* could be seen as "+cmd". */
- if (*files[0] == '+')
+ if (*files[0] == '+') {
escape_fname(&files[0]);
+ }
} else if (xp->xp_context == EXPAND_TAGS) {
/*
* Insert a backslash before characters in a tag name that
@@ -4349,12 +4107,11 @@ void ExpandEscape(expand_T *xp, char_u *str, int numfiles, char_u **files, int o
/// if true then it escapes for a shell command.
///
/// @return [allocated] escaped file name.
-char *vim_strsave_fnameescape(const char *const fname,
- const bool shell FUNC_ATTR_UNUSED)
+char *vim_strsave_fnameescape(const char *const fname, const bool shell FUNC_ATTR_UNUSED)
FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL
{
#ifdef BACKSLASH_IN_FILENAME
-#define PATH_ESC_CHARS " \t\n*?[{`%#'\"|!<"
+# define PATH_ESC_CHARS " \t\n*?[{`%#'\"|!<"
char_u buf[sizeof(PATH_ESC_CHARS)];
int j = 0;
@@ -4368,10 +4125,10 @@ char *vim_strsave_fnameescape(const char *const fname,
char *p = (char *)vim_strsave_escaped((const char_u *)fname,
(const char_u *)buf);
#else
-#define PATH_ESC_CHARS ((char_u *)" \t\n*?[{`$\\%#'\"|!<")
-#define SHELL_ESC_CHARS ((char_u *)" \t\n*?[{`$\\%#'\"|!<>();&")
- char *p = (char *)vim_strsave_escaped(
- (const char_u *)fname, (shell ? SHELL_ESC_CHARS : PATH_ESC_CHARS));
+# define PATH_ESC_CHARS ((char_u *)" \t\n*?[{`$\\%#'\"|!<")
+# define SHELL_ESC_CHARS ((char_u *)" \t\n*?[{`$\\%#'\"|!<>();&")
+ char *p =
+ (char *)vim_strsave_escaped((const char_u *)fname, (shell ? SHELL_ESC_CHARS : PATH_ESC_CHARS));
if (shell && csh_like_shell()) {
// For csh and similar shells need to put two backslashes before '!'.
// One is taken by Vim, one by the shell.
@@ -4410,7 +4167,7 @@ static void escape_fname(char_u **pp)
void tilde_replace(char_u *orig_pat, int num_files, char_u **files)
{
int i;
- char_u *p;
+ char_u *p;
if (orig_pat[0] == '~' && vim_ispathsep(orig_pat[1])) {
for (i = 0; i < num_files; ++i) {
@@ -4437,12 +4194,12 @@ static int showmatches(expand_T *xp, int wildmenu)
#define L_SHOWFILE(m) (showtail \
? sm_gettail(files_found[m], false) : files_found[m])
int num_files;
- char_u **files_found;
+ char_u **files_found;
int i, j, k;
int maxlen;
int lines;
int columns;
- char_u *p;
+ char_u *p;
int lastlen;
int attr;
int showtail;
@@ -4450,11 +4207,11 @@ static int showmatches(expand_T *xp, int wildmenu)
if (xp->xp_numfiles == -1) {
set_expand_context(xp);
i = expand_cmdline(xp, ccline.cmdbuff, ccline.cmdpos,
- &num_files, &files_found);
+ &num_files, &files_found);
showtail = expand_showtail(xp);
- if (i != EXPAND_OK)
+ if (i != EXPAND_OK) {
return i;
-
+ }
} else {
num_files = xp->xp_numfiles;
files_found = xp->xp_files;
@@ -4487,13 +4244,13 @@ static int showmatches(expand_T *xp, int wildmenu)
}
if (!wildmenu) {
- msg_didany = FALSE; /* lines_left will be set */
- msg_start(); /* prepare for paging */
+ msg_didany = false; // lines_left will be set
+ msg_start(); // prepare for paging
msg_putchar('\n');
ui_flush();
cmdline_row = msg_row;
- msg_didany = FALSE; /* lines_left will be set again */
- msg_start(); /* prepare for paging */
+ msg_didany = false; // lines_left will be set again
+ msg_start(); // prepare for paging
}
if (got_int) {
@@ -4509,10 +4266,12 @@ static int showmatches(expand_T *xp, int wildmenu)
|| xp->xp_context == EXPAND_BUFFERS)) {
home_replace(NULL, files_found[i], NameBuff, MAXPATHL, TRUE);
j = vim_strsize(NameBuff);
- } else
+ } else {
j = vim_strsize(L_SHOWFILE(i));
- if (j > maxlen)
+ }
+ if (j > maxlen) {
maxlen = j;
+ }
}
if (xp->xp_context == EXPAND_TAGS_LISTFILES) {
@@ -4536,7 +4295,7 @@ static int showmatches(expand_T *xp, int wildmenu)
MSG_PUTS_ATTR(_(" kind file\n"), HL_ATTR(HLF_T));
}
- /* list the files line by line */
+ // list the files line by line
for (i = 0; i < lines; ++i) {
lastlen = 999;
for (k = i; k < num_files; k += lines) {
@@ -4549,12 +4308,13 @@ static int showmatches(expand_T *xp, int wildmenu)
msg_puts_long_attr(p + 2, HL_ATTR(HLF_D));
break;
}
- for (j = maxlen - lastlen; --j >= 0; )
+ for (j = maxlen - lastlen; --j >= 0; ) {
msg_putchar(' ');
+ }
if (xp->xp_context == EXPAND_FILES
|| xp->xp_context == EXPAND_SHELLCMD
|| xp->xp_context == EXPAND_BUFFERS) {
- /* highlight directories */
+ // highlight directories
if (xp->xp_numfiles != -1) {
// Expansion was done before and special characters
// were escaped, need to halve backslashes. Also
@@ -4575,7 +4335,7 @@ static int showmatches(expand_T *xp, int wildmenu)
p = L_SHOWFILE(k);
} else {
home_replace(NULL, files_found[k], NameBuff, MAXPATHL,
- TRUE);
+ TRUE);
p = NameBuff;
}
} else {
@@ -4584,11 +4344,11 @@ static int showmatches(expand_T *xp, int wildmenu)
}
lastlen = msg_outtrans_attr(p, j ? attr : 0);
}
- if (msg_col > 0) { /* when not wrapped around */
+ if (msg_col > 0) { // when not wrapped around
msg_clr_eos();
msg_putchar('\n');
}
- ui_flush(); /* show one line at a time */
+ ui_flush(); // show one line at a time
if (got_int) {
got_int = FALSE;
break;
@@ -4599,11 +4359,12 @@ static int showmatches(expand_T *xp, int wildmenu)
* we redraw the command below the lines that we have just listed
* This is a bit tricky, but it saves a lot of screen updating.
*/
- cmdline_row = msg_row; /* will put it back later */
+ cmdline_row = msg_row; // will put it back later
}
- if (xp->xp_numfiles == -1)
+ if (xp->xp_numfiles == -1) {
FreeWild(num_files, files_found);
+ }
return EXPAND_OK;
}
@@ -4614,8 +4375,8 @@ static int showmatches(expand_T *xp, int wildmenu)
*/
char_u *sm_gettail(char_u *s, bool eager)
{
- char_u *p;
- char_u *t = s;
+ char_u *p;
+ char_u *t = s;
int had_sep = FALSE;
for (p = s; *p != NUL; ) {
@@ -4645,26 +4406,29 @@ char_u *sm_gettail(char_u *s, bool eager)
*/
static int expand_showtail(expand_T *xp)
{
- char_u *s;
- char_u *end;
+ char_u *s;
+ char_u *end;
- /* When not completing file names a "/" may mean something different. */
+ // When not completing file names a "/" may mean something different.
if (xp->xp_context != EXPAND_FILES
&& xp->xp_context != EXPAND_SHELLCMD
- && xp->xp_context != EXPAND_DIRECTORIES)
+ && xp->xp_context != EXPAND_DIRECTORIES) {
return FALSE;
+ }
end = path_tail(xp->xp_pattern);
- if (end == xp->xp_pattern) /* there is no path separator */
+ if (end == xp->xp_pattern) { // there is no path separator
return FALSE;
+ }
for (s = xp->xp_pattern; s < end; s++) {
/* Skip escaped wildcards. Only when the backslash is not a path
* separator, on DOS the '*' "path\*\file" must not be skipped. */
- if (rem_backslash(s))
+ if (rem_backslash(s)) {
++s;
- else if (vim_strchr((char_u *)"*?[", *s) != NULL)
+ } else if (vim_strchr((char_u *)"*?[", *s) != NULL) {
return FALSE;
+ }
}
return TRUE;
}
@@ -4680,10 +4444,10 @@ static int expand_showtail(expand_T *xp)
char_u *addstar(char_u *fname, size_t len, int context)
FUNC_ATTR_NONNULL_RET
{
- char_u *retval;
+ char_u *retval;
size_t i, j;
size_t new_len;
- char_u *tail;
+ char_u *tail;
int ends_in_star;
if (context != EXPAND_FILES
@@ -4711,19 +4475,20 @@ char_u *addstar(char_u *fname, size_t len, int context)
} else {
new_len = len + 2; // +2 for '^' at start, NUL at end
for (i = 0; i < len; i++) {
- if (fname[i] == '*' || fname[i] == '~')
+ if (fname[i] == '*' || fname[i] == '~') {
new_len++; /* '*' needs to be replaced by ".*"
'~' needs to be replaced by "\~" */
-
- /* Buffer names are like file names. "." should be literal */
- if (context == EXPAND_BUFFERS && fname[i] == '.')
- new_len++; /* "." becomes "\." */
-
+ }
+ // Buffer names are like file names. "." should be literal
+ if (context == EXPAND_BUFFERS && fname[i] == '.') {
+ new_len++; // "." becomes "\."
+ }
/* Custom expansion takes care of special things, match
* backslashes literally (perhaps also for other types?) */
if ((context == EXPAND_USER_DEFINED
- || context == EXPAND_USER_LIST) && fname[i] == '\\')
- new_len++; /* '\' becomes "\\" */
+ || context == EXPAND_USER_LIST) && fname[i] == '\\') {
+ new_len++; // '\' becomes "\\"
+ }
}
retval = xmalloc(new_len);
{
@@ -4735,22 +4500,30 @@ char_u *addstar(char_u *fname, size_t len, int context)
if (context != EXPAND_USER_DEFINED
&& context != EXPAND_USER_LIST
&& fname[i] == '\\'
- && ++i == len)
+ && ++i == len) {
break;
+ }
switch (fname[i]) {
- case '*': retval[j++] = '.';
+ case '*':
+ retval[j++] = '.';
break;
- case '~': retval[j++] = '\\';
+ case '~':
+ retval[j++] = '\\';
break;
- case '?': retval[j] = '.';
+ case '?':
+ retval[j] = '.';
continue;
- case '.': if (context == EXPAND_BUFFERS)
+ case '.':
+ if (context == EXPAND_BUFFERS) {
retval[j++] = '\\';
+ }
break;
- case '\\': if (context == EXPAND_USER_DEFINED
- || context == EXPAND_USER_LIST)
+ case '\\':
+ if (context == EXPAND_USER_DEFINED
+ || context == EXPAND_USER_LIST) {
retval[j++] = '\\';
+ }
break;
}
retval[j] = fname[i];
@@ -4783,10 +4556,11 @@ char_u *addstar(char_u *fname, size_t len, int context)
if ((*retval != '~' || tail != retval)
&& !ends_in_star
&& vim_strchr(tail, '$') == NULL
- && vim_strchr(retval, '`') == NULL)
+ && vim_strchr(retval, '`') == NULL) {
retval[len++] = '*';
- else if (len > 0 && retval[len - 1] == '$')
+ } else if (len > 0 && retval[len - 1] == '$') {
--len;
+ }
retval[len] = NUL;
}
return retval;
@@ -4796,66 +4570,62 @@ char_u *addstar(char_u *fname, size_t len, int context)
* Must parse the command line so far to work out what context we are in.
* Completion can then be done based on that context.
* This routine sets the variables:
- * xp->xp_pattern The start of the pattern to be expanded within
- * the command line (ends at the cursor).
- * xp->xp_context The type of thing to expand. Will be one of:
+ * xp->xp_pattern The start of the pattern to be expanded within
+ * the command line (ends at the cursor).
+ * xp->xp_context The type of thing to expand. Will be one of:
*
- * EXPAND_UNSUCCESSFUL Used sometimes when there is something illegal on
- * the command line, like an unknown command. Caller
- * should beep.
- * EXPAND_NOTHING Unrecognised context for completion, use char like
- * a normal char, rather than for completion. eg
- * :s/^I/
- * EXPAND_COMMANDS Cursor is still touching the command, so complete
- * it.
- * EXPAND_BUFFERS Complete file names for :buf and :sbuf commands.
- * EXPAND_FILES After command with EX_XFILE set, or after setting
- * with P_EXPAND set. eg :e ^I, :w>>^I
- * EXPAND_DIRECTORIES In some cases this is used instead of the latter
- * when we know only directories are of interest. eg
- * :set dir=^I
- * EXPAND_SHELLCMD After ":!cmd", ":r !cmd" or ":w !cmd".
- * EXPAND_SETTINGS Complete variable names. eg :set d^I
+ * EXPAND_UNSUCCESSFUL Used sometimes when there is something illegal on
+ * the command line, like an unknown command. Caller
+ * should beep.
+ * EXPAND_NOTHING Unrecognised context for completion, use char like
+ * a normal char, rather than for completion. eg
+ * :s/^I/
+ * EXPAND_COMMANDS Cursor is still touching the command, so complete
+ * it.
+ * EXPAND_BUFFERS Complete file names for :buf and :sbuf commands.
+ * EXPAND_FILES After command with EX_XFILE set, or after setting
+ * with P_EXPAND set. eg :e ^I, :w>>^I
+ * EXPAND_DIRECTORIES In some cases this is used instead of the latter
+ * when we know only directories are of interest. eg
+ * :set dir=^I
+ * EXPAND_SHELLCMD After ":!cmd", ":r !cmd" or ":w !cmd".
+ * EXPAND_SETTINGS Complete variable names. eg :set d^I
* EXPAND_BOOL_SETTINGS Complete boolean variables only, eg :set no^I
- * EXPAND_TAGS Complete tags from the files in p_tags. eg :ta a^I
+ * EXPAND_TAGS Complete tags from the files in p_tags. eg :ta a^I
* EXPAND_TAGS_LISTFILES As above, but list filenames on ^D, after :tselect
- * EXPAND_HELP Complete tags from the file 'helpfile'/tags
- * EXPAND_EVENTS Complete event names
- * EXPAND_SYNTAX Complete :syntax command arguments
- * EXPAND_HIGHLIGHT Complete highlight (syntax) group names
- * EXPAND_AUGROUP Complete autocommand group names
- * EXPAND_USER_VARS Complete user defined variable names, eg :unlet a^I
- * EXPAND_MAPPINGS Complete mapping and abbreviation names,
- * eg :unmap a^I , :cunab x^I
- * EXPAND_FUNCTIONS Complete internal or user defined function names,
- * eg :call sub^I
- * EXPAND_USER_FUNC Complete user defined function names, eg :delf F^I
- * EXPAND_EXPRESSION Complete internal or user defined function/variable
- * names in expressions, eg :while s^I
- * EXPAND_ENV_VARS Complete environment variable names
- * EXPAND_USER Complete user names
+ * EXPAND_HELP Complete tags from the file 'helpfile'/tags
+ * EXPAND_EVENTS Complete event names
+ * EXPAND_SYNTAX Complete :syntax command arguments
+ * EXPAND_HIGHLIGHT Complete highlight (syntax) group names
+ * EXPAND_AUGROUP Complete autocommand group names
+ * EXPAND_USER_VARS Complete user defined variable names, eg :unlet a^I
+ * EXPAND_MAPPINGS Complete mapping and abbreviation names,
+ * eg :unmap a^I , :cunab x^I
+ * EXPAND_FUNCTIONS Complete internal or user defined function names,
+ * eg :call sub^I
+ * EXPAND_USER_FUNC Complete user defined function names, eg :delf F^I
+ * EXPAND_EXPRESSION Complete internal or user defined function/variable
+ * names in expressions, eg :while s^I
+ * EXPAND_ENV_VARS Complete environment variable names
+ * EXPAND_USER Complete user names
*/
static void set_expand_context(expand_T *xp)
{
- /* only expansion for ':', '>' and '=' command-lines */
+ // only expansion for ':', '>' and '=' command-lines
if (ccline.cmdfirstc != ':'
&& ccline.cmdfirstc != '>' && ccline.cmdfirstc != '='
- && !ccline.input_fn
- ) {
+ && !ccline.input_fn) {
xp->xp_context = EXPAND_NOTHING;
return;
}
set_cmd_context(xp, ccline.cmdbuff, ccline.cmdlen, ccline.cmdpos, true);
}
-void
-set_cmd_context (
- expand_T *xp,
- char_u *str, // start of command line
- int len, // length of command line (excl. NUL)
- int col, // position of cursor
- int use_ccline // use ccline for info
-)
+/// @param str start of command line
+/// @param len length of command line (excl. NUL)
+/// @param col position of cursor
+/// @param use_ccline use ccline for info
+void set_cmd_context(expand_T *xp, char_u *str, int len, int col, int use_ccline)
{
char_u old_char = NUL;
@@ -4863,8 +4633,9 @@ set_cmd_context (
* Avoid a UMR warning from Purify, only save the character if it has been
* written before.
*/
- if (col < len)
+ if (col < len) {
old_char = str[col];
+ }
str[col] = NUL;
const char *nextcomm = (const char *)str;
@@ -4889,35 +4660,31 @@ set_cmd_context (
str[col] = old_char;
}
-/*
- * Expand the command line "str" from context "xp".
- * "xp" must have been set by set_cmd_context().
- * xp->xp_pattern points into "str", to where the text that is to be expanded
- * starts.
- * Returns EXPAND_UNSUCCESSFUL when there is something illegal before the
- * cursor.
- * Returns EXPAND_NOTHING when there is nothing to expand, might insert the
- * key that triggered expansion literally.
- * Returns EXPAND_OK otherwise.
- */
-int
-expand_cmdline (
- expand_T *xp,
- char_u *str, /* start of command line */
- int col, /* position of cursor */
- int *matchcount, /* return: nr of matches */
- char_u ***matches /* return: array of pointers to matches */
-)
+/// Expand the command line "str" from context "xp".
+/// "xp" must have been set by set_cmd_context().
+/// xp->xp_pattern points into "str", to where the text that is to be expanded
+/// starts.
+/// Returns EXPAND_UNSUCCESSFUL when there is something illegal before the
+/// cursor.
+/// Returns EXPAND_NOTHING when there is nothing to expand, might insert the
+/// key that triggered expansion literally.
+/// Returns EXPAND_OK otherwise.
+///
+/// @param str start of command line
+/// @param col position of cursor
+/// @param matchcount return: nr of matches
+/// @param matches return: array of pointers to matches
+int expand_cmdline(expand_T *xp, char_u *str, int col, int *matchcount, char_u ***matches)
{
- char_u *file_str = NULL;
+ char_u *file_str = NULL;
int options = WILD_ADD_SLASH|WILD_SILENT;
if (xp->xp_context == EXPAND_UNSUCCESSFUL) {
beep_flush();
- return EXPAND_UNSUCCESSFUL; /* Something illegal on command line */
+ return EXPAND_UNSUCCESSFUL; // Something illegal on command line
}
if (xp->xp_context == EXPAND_NOTHING) {
- /* Caller can use the character as a normal char instead */
+ // Caller can use the character as a normal char instead
return EXPAND_NOTHING;
}
@@ -4926,10 +4693,11 @@ expand_cmdline (
xp->xp_pattern_len = (size_t)((str + col) - xp->xp_pattern);
file_str = addstar(xp->xp_pattern, xp->xp_pattern_len, xp->xp_context);
- if (p_wic)
+ if (p_wic) {
options += WILD_ICASE;
+ }
- /* find all files that match the description */
+ // find all files that match the description
if (ExpandFromContext(xp, file_str, matchcount, matches, options) == FAIL) {
*matchcount = 0;
*matches = NULL;
@@ -4993,31 +4761,28 @@ static void cleanup_help_tags(int num_file, char_u **file)
typedef char_u *(*ExpandFunc)(expand_T *, int);
-/*
- * Do the expansion based on xp->xp_context and "pat".
- */
-static int
-ExpandFromContext (
- expand_T *xp,
- char_u *pat,
- int *num_file,
- char_u ***file,
- int options // WILD_ flags
-)
+/// Do the expansion based on xp->xp_context and "pat".
+///
+/// @param options WILD_ flags
+static int ExpandFromContext(expand_T *xp, char_u *pat, int *num_file, char_u ***file, int options)
{
regmatch_T regmatch;
int ret;
int flags;
- flags = EW_DIR; /* include directories */
- if (options & WILD_LIST_NOTFOUND)
+ flags = EW_DIR; // include directories
+ if (options & WILD_LIST_NOTFOUND) {
flags |= EW_NOTFOUND;
- if (options & WILD_ADD_SLASH)
+ }
+ if (options & WILD_ADD_SLASH) {
flags |= EW_ADDSLASH;
- if (options & WILD_KEEP_ALL)
+ }
+ if (options & WILD_KEEP_ALL) {
flags |= EW_KEEPALL;
- if (options & WILD_SILENT)
+ }
+ if (options & WILD_SILENT) {
flags |= EW_SILENT;
+ }
if (options & WILD_NOERROR) {
flags |= EW_NOERROR;
}
@@ -5038,32 +4803,38 @@ ExpandFromContext (
if (xp->xp_backslash != XP_BS_NONE) {
free_pat = TRUE;
pat = vim_strsave(pat);
- for (i = 0; pat[i]; ++i)
+ for (i = 0; pat[i]; ++i) {
if (pat[i] == '\\') {
if (xp->xp_backslash == XP_BS_THREE
&& pat[i + 1] == '\\'
&& pat[i + 2] == '\\'
- && pat[i + 3] == ' ')
+ && pat[i + 3] == ' ') {
STRMOVE(pat + i, pat + i + 3);
+ }
if (xp->xp_backslash == XP_BS_ONE
- && pat[i + 1] == ' ')
+ && pat[i + 1] == ' ') {
STRMOVE(pat + i, pat + i + 1);
+ }
}
+ }
}
- if (xp->xp_context == EXPAND_FILES)
+ if (xp->xp_context == EXPAND_FILES) {
flags |= EW_FILE;
- else if (xp->xp_context == EXPAND_FILES_IN_PATH)
+ } else if (xp->xp_context == EXPAND_FILES_IN_PATH) {
flags |= (EW_FILE | EW_PATH);
- else
+ } else {
flags = (flags | EW_DIR) & ~EW_FILE;
- if (options & WILD_ICASE)
+ }
+ if (options & WILD_ICASE) {
flags |= EW_ICASE;
+ }
- /* Expand wildcards, supporting %:h and the like. */
+ // Expand wildcards, supporting %:h and the like.
ret = expand_wildcards_eval(&pat, num_file, file, flags);
- if (free_pat)
+ if (free_pat) {
xfree(pat);
+ }
#ifdef BACKSLASH_IN_FILENAME
if (p_csl[0] != NUL && (options & WILD_IGNORE_COMPLETESLASH) == 0) {
for (int i = 0; i < *num_file; i++) {
@@ -5104,8 +4875,9 @@ ExpandFromContext (
ExpandOldSetting(num_file, file);
return OK;
}
- if (xp->xp_context == EXPAND_BUFFERS)
+ if (xp->xp_context == EXPAND_BUFFERS) {
return ExpandBufnames(pat, num_file, file, options);
+ }
if (xp->xp_context == EXPAND_DIFF_BUFFERS) {
return ExpandBufnames(pat, num_file, file, options | BUF_DIFF_FILTER);
}
@@ -5158,20 +4930,21 @@ ExpandFromContext (
}
regmatch.regprog = vim_regcomp(pat, p_magic ? RE_MAGIC : 0);
- if (regmatch.regprog == NULL)
+ if (regmatch.regprog == NULL) {
return FAIL;
+ }
- /* set ignore-case according to p_ic, p_scs and pat */
+ // set ignore-case according to p_ic, p_scs and pat
regmatch.rm_ic = ignorecase(pat);
if (xp->xp_context == EXPAND_SETTINGS
- || xp->xp_context == EXPAND_BOOL_SETTINGS)
+ || xp->xp_context == EXPAND_BOOL_SETTINGS) {
ret = ExpandSettings(xp, &regmatch, num_file, file);
- else if (xp->xp_context == EXPAND_MAPPINGS)
+ } else if (xp->xp_context == EXPAND_MAPPINGS) {
ret = ExpandMappings(&regmatch, num_file, file);
- else if (xp->xp_context == EXPAND_USER_DEFINED)
+ } else if (xp->xp_context == EXPAND_USER_DEFINED) {
ret = ExpandUserDefined(xp, &regmatch, num_file, file);
- else {
+ } else {
static struct expgen {
int context;
ExpandFunc func;
@@ -5217,7 +4990,7 @@ ExpandFromContext (
* right function to do the expansion.
*/
ret = FAIL;
- for (i = 0; i < (int)ARRAY_SIZE(tab); ++i)
+ for (i = 0; i < (int)ARRAY_SIZE(tab); ++i) {
if (xp->xp_context == tab[i].context) {
if (tab[i].ic) {
regmatch.rm_ic = TRUE;
@@ -5227,6 +5000,7 @@ ExpandFromContext (
ret = OK;
break;
}
+ }
}
vim_regfree(regmatch.regprog);
@@ -5235,39 +5009,36 @@ ExpandFromContext (
return ret;
}
-/*
- * Expand a list of names.
- *
- * Generic function for command line completion. It calls a function to
- * obtain strings, one by one. The strings are matched against a regexp
- * program. Matching strings are copied into an array, which is returned.
- */
-static void ExpandGeneric(
- expand_T *xp,
- regmatch_T *regmatch,
- int *num_file,
- char_u ***file,
- CompleteListItemGetter func, /* returns a string from the list */
- int escaped
- )
+/// Expand a list of names.
+///
+/// Generic function for command line completion. It calls a function to
+/// obtain strings, one by one. The strings are matched against a regexp
+/// program. Matching strings are copied into an array, which is returned.
+///
+/// @param func returns a string from the list
+static void ExpandGeneric(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file,
+ CompleteListItemGetter func, int escaped)
{
int i;
size_t count = 0;
- char_u *str;
+ char_u *str;
// count the number of matching names
for (i = 0;; ++i) {
str = (*func)(xp, i);
- if (str == NULL) // end of list
+ if (str == NULL) { // end of list
break;
- if (*str == NUL) // skip empty strings
+ }
+ if (*str == NUL) { // skip empty strings
continue;
+ }
if (vim_regexec(regmatch, str, (colnr_T)0)) {
++count;
}
}
- if (count == 0)
+ if (count == 0) {
return;
+ }
assert(count < INT_MAX);
*num_file = (int)count;
*file = (char_u **)xmalloc(count * sizeof(char_u *));
@@ -5299,16 +5070,17 @@ static void ExpandGeneric(
}
}
- /* Sort the results. Keep menu's in the specified order. */
+ // Sort the results. Keep menu's in the specified order.
if (xp->xp_context != EXPAND_MENUNAMES && xp->xp_context != EXPAND_MENUS) {
if (xp->xp_context == EXPAND_EXPRESSION
|| xp->xp_context == EXPAND_FUNCTIONS
- || xp->xp_context == EXPAND_USER_FUNC)
- /* <SNR> functions should be sorted to the end. */
+ || xp->xp_context == EXPAND_USER_FUNC) {
+ // <SNR> functions should be sorted to the end.
qsort((void *)*file, (size_t)*num_file, sizeof(char_u *),
- sort_func_compare);
- else
+ sort_func_compare);
+ } else {
sort_strings(*file, *num_file);
+ }
}
/* Reset the variables used for special highlight names expansion, so that
@@ -5324,26 +5096,27 @@ static void ExpandGeneric(
/// *file will either be set to NULL or point to
/// allocated memory.
/// @param flagsarg is a combination of EW_* flags.
-static void expand_shellcmd(char_u *filepat, int *num_file, char_u ***file,
- int flagsarg)
+static void expand_shellcmd(char_u *filepat, int *num_file, char_u ***file, int flagsarg)
FUNC_ATTR_NONNULL_ALL
{
- char_u *pat;
+ char_u *pat;
int i;
- char_u *path = NULL;
+ char_u *path = NULL;
garray_T ga;
char_u *buf = xmalloc(MAXPATHL);
size_t l;
- char_u *s, *e;
+ char_u *s, *e;
int flags = flagsarg;
int ret;
bool did_curdir = false;
// for ":set path=" and ":set tags=" halve backslashes for escaped space
pat = vim_strsave(filepat);
- for (i = 0; pat[i]; ++i)
- if (pat[i] == '\\' && pat[i + 1] == ' ')
+ for (i = 0; pat[i]; ++i) {
+ if (pat[i] == '\\' && pat[i + 1] == ' ') {
STRMOVE(pat + i, pat + i + 1);
+ }
+ }
flags |= EW_FILE | EW_EXEC | EW_SHELLCMD;
@@ -5401,7 +5174,7 @@ static void expand_shellcmd(char_u *filepat, int *num_file, char_u ***file,
l = STRLEN(buf);
STRLCPY(buf + l, pat, MAXPATHL - l);
- /* Expand matches in one directory of $PATH. */
+ // Expand matches in one directory of $PATH.
ret = expand_wildcards(1, &buf, num_file, file, flags);
if (ret == OK) {
ga_grow(&ga, *num_file);
@@ -5428,8 +5201,9 @@ static void expand_shellcmd(char_u *filepat, int *num_file, char_u ***file,
xfree(*file);
}
}
- if (*e != NUL)
+ if (*e != NUL) {
++e;
+ }
}
*file = ga.ga_data;
*num_file = ga.ga_len;
@@ -5444,8 +5218,8 @@ static void expand_shellcmd(char_u *filepat, int *num_file, char_u ***file,
/// Call "user_expand_func()" to invoke a user defined Vim script function and
/// return the result (either a string, a List or NULL).
-static void * call_user_expand_func(user_expand_func_T user_expand_func,
- expand_T *xp, int *num_file, char_u ***file)
+static void *call_user_expand_func(user_expand_func_T user_expand_func, expand_T *xp, int *num_file,
+ char_u ***file)
FUNC_ATTR_NONNULL_ALL
{
char_u keep = 0;
@@ -5454,8 +5228,9 @@ static void * call_user_expand_func(user_expand_func_T user_expand_func,
const sctx_T save_current_sctx = current_sctx;
struct cmdline_info save_ccline;
- if (xp->xp_arg == NULL || xp->xp_arg[0] == '\0' || xp->xp_line == NULL)
+ if (xp->xp_arg == NULL || xp->xp_arg[0] == '\0' || xp->xp_line == NULL) {
return NULL;
+ }
*num_file = 0;
*file = NULL;
@@ -5473,7 +5248,7 @@ static void * call_user_expand_func(user_expand_func_T user_expand_func,
args[1].vval.v_string = xp->xp_line;
args[2].vval.v_number = xp->xp_col;
- /* Save the cmdline, we don't know what the function may do. */
+ // Save the cmdline, we don't know what the function may do.
save_ccline = ccline;
ccline.cmdbuff = NULL;
ccline.cmdprompt = NULL;
@@ -5496,11 +5271,11 @@ static void * call_user_expand_func(user_expand_func_T user_expand_func,
*/
static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file)
{
- char_u *e;
- garray_T ga;
+ char_u *e;
+ garray_T ga;
- char_u *const retstr = call_user_expand_func(
- (user_expand_func_T)call_func_retstr, xp, num_file, file);
+ char_u *const retstr = call_user_expand_func((user_expand_func_T)call_func_retstr, xp, num_file,
+ file);
if (retstr == NULL) {
return FAIL;
@@ -5509,13 +5284,14 @@ static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, int *num_file,
ga_init(&ga, (int)sizeof(char *), 3);
for (char_u *s = retstr; *s != NUL; s = e) {
e = vim_strchr(s, '\n');
- if (e == NULL)
+ if (e == NULL) {
e = s + STRLEN(s);
+ }
const char_u keep = *e;
*e = NUL;
const bool skip = xp->xp_pattern[0]
- && vim_regexec(regmatch, s, (colnr_T)0) == 0;
+ && vim_regexec(regmatch, s, (colnr_T)0) == 0;
*e = keep;
if (!skip) {
GA_APPEND(char_u *, &ga, vim_strnsave(s, (size_t)(e - s)));
@@ -5536,8 +5312,8 @@ static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, int *num_file,
*/
static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file)
{
- list_T *const retlist = call_user_expand_func(
- (user_expand_func_T)call_func_retlist, xp, num_file, file);
+ list_T *const retlist = call_user_expand_func((user_expand_func_T)call_func_retlist, xp, num_file,
+ file);
if (retlist == NULL) {
return FAIL;
}
@@ -5551,8 +5327,7 @@ static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file)
continue; // Skip non-string items and empty strings.
}
- GA_APPEND(char *, &ga, xstrdup(
- (const char *)TV_LIST_ITEM_TV(li)->vval.v_string));
+ GA_APPEND(char *, &ga, xstrdup((const char *)TV_LIST_ITEM_TV(li)->vval.v_string));
});
tv_list_unref(retlist);
@@ -5570,8 +5345,7 @@ static int ExpandUserList(expand_T *xp, int *num_file, char_u ***file)
/// 'packpath'/pack/ * /opt/ * /{dirnames}/{pat}.vim
/// When "flags" has DIP_LUA: search also performed for .lua files
/// "dirnames" is an array with one or more directory names.
-static int ExpandRTDir(char_u *pat, int flags, int *num_file, char_u ***file,
- char *dirnames[])
+static int ExpandRTDir(char_u *pat, int flags, int *num_file, char_u ***file, char *dirnames[])
{
*num_file = 0;
*file = NULL;
@@ -5665,8 +5439,9 @@ static int ExpandRTDir(char_u *pat, int flags, int *num_file, char_u ***file,
}
}
- if (GA_EMPTY(&ga))
+ if (GA_EMPTY(&ga)) {
return FAIL;
+ }
/* Sort and remove duplicates which can happen when specifying multiple
* directories in dirnames. */
@@ -5759,7 +5534,7 @@ void globpath(char_u *path, char_u *file, garray_T *ga, int expand_options)
/*********************************
-* Command line history stuff *
+* Command line history stuff *
*********************************/
/// Translate a history character to the associated type number
@@ -5767,26 +5542,20 @@ static HistoryType hist_char2type(const int c)
FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT
{
switch (c) {
- case ':': {
- return HIST_CMD;
- }
- case '=': {
- return HIST_EXPR;
- }
- case '@': {
- return HIST_INPUT;
- }
- case '>': {
- return HIST_DEBUG;
- }
- case NUL:
- case '/':
- case '?': {
- return HIST_SEARCH;
- }
- default: {
- return HIST_INVALID;
- }
+ case ':':
+ return HIST_CMD;
+ case '=':
+ return HIST_EXPR;
+ case '@':
+ return HIST_INPUT;
+ case '>':
+ return HIST_DEBUG;
+ case NUL:
+ case '/':
+ case '?':
+ return HIST_SEARCH;
+ default:
+ return HIST_INVALID;
}
// Silence -Wreturn-type
return 0;
@@ -5823,10 +5592,12 @@ static char_u *get_history_arg(expand_T *xp, int idx)
compl[0] = (char_u)short_names[idx];
return compl;
}
- if (idx < short_names_count + history_name_count)
+ if (idx < short_names_count + history_name_count) {
return (char_u *)history_names[idx - short_names_count];
- if (idx == short_names_count + history_name_count)
+ }
+ if (idx == short_names_count + history_name_count) {
return (char_u *)"all";
+ }
return NULL;
}
@@ -5904,49 +5675,48 @@ static inline void clear_hist_entry(histentry_T *hisptr)
memset(hisptr, 0, sizeof(*hisptr));
}
-/*
- * Check if command line 'str' is already in history.
- * If 'move_to_front' is TRUE, matching entry is moved to end of history.
- */
-static int
-in_history (
- int type,
- char_u *str,
- int move_to_front, // Move the entry to the front if it exists
- int sep
-)
+/// Check if command line 'str' is already in history.
+/// If 'move_to_front' is TRUE, matching entry is moved to end of history.
+///
+/// @param move_to_front Move the entry to the front if it exists
+static int in_history(int type, char_u *str, int move_to_front, int sep)
{
int i;
int last_i = -1;
- char_u *p;
+ char_u *p;
- if (hisidx[type] < 0)
+ if (hisidx[type] < 0) {
return FALSE;
+ }
i = hisidx[type];
do {
- if (history[type][i].hisstr == NULL)
+ if (history[type][i].hisstr == NULL) {
return FALSE;
+ }
/* For search history, check that the separator character matches as
* well. */
p = history[type][i].hisstr;
if (STRCMP(str, p) == 0
&& (type != HIST_SEARCH || sep == p[STRLEN(p) + 1])) {
- if (!move_to_front)
+ if (!move_to_front) {
return TRUE;
+ }
last_i = i;
break;
}
- if (--i < 0)
+ if (--i < 0) {
i = hislen - 1;
+ }
} while (i != hisidx[type]);
if (last_i >= 0) {
list_T *const list = history[type][i].additional_elements;
str = history[type][i].hisstr;
while (i != hisidx[type]) {
- if (++i >= hislen)
+ if (++i >= hislen) {
i = 0;
+ }
history[type][last_i] = history[type][i];
last_i = i;
}
@@ -5972,8 +5742,7 @@ in_history (
///
/// @return Any value from HistoryType enum, including HIST_INVALID. May not
/// return HIST_DEFAULT unless return_default is true.
-HistoryType get_histtype(const char *const name, const size_t len,
- const bool return_default)
+HistoryType get_histtype(const char *const name, const size_t len, const bool return_default)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
// No argument: use current history.
@@ -5994,20 +5763,15 @@ HistoryType get_histtype(const char *const name, const size_t len,
return HIST_INVALID;
}
-static int last_maptick = -1; /* last seen maptick */
+static int last_maptick = -1; // last seen maptick
-/*
- * Add the given string to the given history. If the string is already in the
- * history then it is moved to the front. "histype" may be one of he HIST_
- * values.
- */
-void
-add_to_history (
- int histype,
- char_u *new_entry,
- int in_map, /* consider maptick when inside a mapping */
- int sep /* separator character used (search hist) */
-)
+/// Add the given string to the given history. If the string is already in the
+/// history then it is moved to the front. "histype" may be one of he HIST_
+/// values.
+///
+/// @parma in_map consider maptick when inside a mapping
+/// @param sep separator character used (search hist)
+void add_to_history(int histype, char_u *new_entry, int in_map, int sep)
{
histentry_T *hisptr;
@@ -6016,8 +5780,9 @@ add_to_history (
}
assert(histype != HIST_DEFAULT);
- if (cmdmod.keeppatterns && histype == HIST_SEARCH)
+ if (cmdmod.keeppatterns && histype == HIST_SEARCH) {
return;
+ }
/*
* Searches inside the same mapping overwrite each other, so that only
@@ -6030,14 +5795,16 @@ add_to_history (
hisptr = &history[HIST_SEARCH][hisidx[HIST_SEARCH]];
hist_free_entry(hisptr);
--hisnum[histype];
- if (--hisidx[HIST_SEARCH] < 0)
+ if (--hisidx[HIST_SEARCH] < 0) {
hisidx[HIST_SEARCH] = hislen - 1;
+ }
}
last_maptick = -1;
}
if (!in_history(histype, new_entry, true, sep)) {
- if (++hisidx[histype] == hislen)
+ if (++hisidx[histype] == hislen) {
hisidx[histype] = 0;
+ }
hisptr = &history[histype][hisidx[histype]];
hist_free_entry(hisptr);
@@ -6049,8 +5816,9 @@ add_to_history (
hisptr->hisstr[len + 1] = (char_u)sep;
hisptr->hisnum = ++hisnum[histype];
- if (histype == HIST_SEARCH && in_map)
+ if (histype == HIST_SEARCH && in_map) {
last_maptick = maptick;
+ }
}
}
@@ -6062,8 +5830,9 @@ add_to_history (
int get_history_idx(int histype)
{
if (hislen == 0 || histype < 0 || histype >= HIST_COUNT
- || hisidx[histype] < 0)
+ || hisidx[histype] < 0) {
return -1;
+ }
return history[histype][hisidx[histype]].hisnum;
}
@@ -6098,8 +5867,9 @@ char_u *get_cmdline_str(void)
}
struct cmdline_info *p = get_ccline_ptr();
- if (p == NULL)
+ if (p == NULL) {
return NULL;
+ }
return vim_strnsave(p->cmdbuff, (size_t)p->cmdlen);
}
@@ -6113,8 +5883,9 @@ int get_cmdline_pos(void)
{
struct cmdline_info *p = get_ccline_ptr();
- if (p == NULL)
+ if (p == NULL) {
return -1;
+ }
return p->cmdpos;
}
@@ -6127,15 +5898,17 @@ int set_cmdline_pos(int pos)
{
struct cmdline_info *p = get_ccline_ptr();
- if (p == NULL)
+ if (p == NULL) {
return 1;
+ }
/* The position is not set directly but after CTRL-\ e or CTRL-R = has
* changed the command line. */
- if (pos < 0)
+ if (pos < 0) {
new_cmdpos = 0;
- else
+ } else {
new_cmdpos = pos;
+ }
return 0;
}
@@ -6149,10 +5922,12 @@ int get_cmdline_type(void)
{
struct cmdline_info *p = get_ccline_ptr();
- if (p == NULL)
+ if (p == NULL) {
return NUL;
- if (p->cmdfirstc == NUL)
+ }
+ if (p->cmdfirstc == NUL) {
return (p->input_fn) ? '@' : '-';
+ }
return p->cmdfirstc;
}
@@ -6169,26 +5944,32 @@ static int calc_hist_idx(int histype, int num)
int wrapped = FALSE;
if (hislen == 0 || histype < 0 || histype >= HIST_COUNT
- || (i = hisidx[histype]) < 0 || num == 0)
+ || (i = hisidx[histype]) < 0 || num == 0) {
return -1;
+ }
hist = history[histype];
if (num > 0) {
- while (hist[i].hisnum > num)
+ while (hist[i].hisnum > num) {
if (--i < 0) {
- if (wrapped)
+ if (wrapped) {
break;
+ }
i += hislen;
wrapped = TRUE;
}
- if (hist[i].hisnum == num && hist[i].hisstr != NULL)
+ }
+ if (hist[i].hisnum == num && hist[i].hisstr != NULL) {
return i;
- } else if (-num <= hislen) {
+ }
+ } else if (-num <= hislen) {
i += num + 1;
- if (i < 0)
+ if (i < 0) {
i += hislen;
- if (hist[i].hisstr != NULL)
+ }
+ if (hist[i].hisstr != NULL) {
return i;
+ }
}
return -1;
}
@@ -6200,10 +5981,11 @@ static int calc_hist_idx(int histype, int num)
char_u *get_history_entry(int histype, int idx)
{
idx = calc_hist_idx(histype, idx);
- if (idx >= 0)
+ if (idx >= 0) {
return history[histype][idx].hisstr;
- else
+ } else {
return (char_u *)"";
+ }
}
/// Clear all entries in a history
@@ -6240,7 +6022,7 @@ int del_history_entry(int histype, char_u *str)
bool found = false;
regmatch.regprog = NULL;
- regmatch.rm_ic = FALSE; /* always match case */
+ regmatch.rm_ic = FALSE; // always match case
if (hislen != 0
&& histype >= 0
&& histype < HIST_COUNT
@@ -6251,8 +6033,9 @@ int del_history_entry(int histype, char_u *str)
i = last = idx;
do {
hisptr = &history[histype][i];
- if (hisptr->hisstr == NULL)
+ if (hisptr->hisstr == NULL) {
break;
+ }
if (vim_regexec(&regmatch, hisptr->hisstr, (colnr_T)0)) {
found = true;
hist_free_entry(hisptr);
@@ -6261,14 +6044,17 @@ int del_history_entry(int histype, char_u *str)
history[histype][last] = *hisptr;
clear_hist_entry(hisptr);
}
- if (--last < 0)
+ if (--last < 0) {
last += hislen;
+ }
}
- if (--i < 0)
+ if (--i < 0) {
i += hislen;
+ }
} while (i != idx);
- if (history[histype][idx].hisstr == NULL)
+ if (history[histype][idx].hisstr == NULL) {
hisidx[histype] = -1;
+ }
}
vim_regfree(regmatch.regprog);
return found;
@@ -6283,16 +6069,18 @@ int del_history_idx(int histype, int idx)
int i, j;
i = calc_hist_idx(histype, idx);
- if (i < 0)
+ if (i < 0) {
return FALSE;
+ }
idx = hisidx[histype];
hist_free_entry(&history[histype][i]);
/* When deleting the last added search string in a mapping, reset
* last_maptick, so that the last added search string isn't deleted again.
*/
- if (histype == HIST_SEARCH && maptick == last_maptick && i == idx)
+ if (histype == HIST_SEARCH && maptick == last_maptick && i == idx) {
last_maptick = -1;
+ }
while (i != idx) {
j = (i + 1) % hislen;
@@ -6323,7 +6111,7 @@ int get_list_range(char_u **str, int *num1, int *num2)
*str = skipwhite(*str);
if (**str == '-' || ascii_isdigit(**str)) { // parse "from" part of range
- vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0);
+ vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0, false);
*str += len;
*num1 = (int)num;
first = true;
@@ -6331,7 +6119,7 @@ int get_list_range(char_u **str, int *num1, int *num2)
*str = skipwhite(*str);
if (**str == ',') { // parse "to" part of range
*str = skipwhite(*str + 1);
- vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0);
+ vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0, false);
if (len > 0) {
*num2 = (int)num;
*str = skipwhite(*str + len);
@@ -6356,8 +6144,8 @@ void ex_history(exarg_T *eap)
int hisidx2 = -1;
int idx;
int i, j, k;
- char_u *end;
- char_u *arg = eap->arg;
+ char_u *end;
+ char_u *arg = eap->arg;
if (hislen == 0) {
MSG(_("'history' option is zero"));
@@ -6367,8 +6155,9 @@ void ex_history(exarg_T *eap)
if (!(ascii_isdigit(*arg) || *arg == '-' || *arg == ',')) {
end = arg;
while (ASCII_ISALPHA(*end)
- || vim_strchr((char_u *)":=@>/?", *end) != NULL)
+ || vim_strchr((char_u *)":=@>/?", *end) != NULL) {
end++;
+ }
histype1 = get_histtype((const char *)arg, (size_t)(end - arg), false);
if (histype1 == HIST_INVALID) {
if (STRNICMP(arg, "all", end - arg) == 0) {
@@ -6378,8 +6167,9 @@ void ex_history(exarg_T *eap)
EMSG(_(e_trailing));
return;
}
- } else
+ } else {
histype2 = histype1;
+ }
} else {
end = arg;
}
@@ -6397,14 +6187,17 @@ void ex_history(exarg_T *eap)
hist = history[histype1];
j = hisidx1;
k = hisidx2;
- if (j < 0)
+ if (j < 0) {
j = (-j > hislen) ? 0 : hist[(hislen+j+idx+1) % hislen].hisnum;
- if (k < 0)
+ }
+ if (k < 0) {
k = (-k > hislen) ? 0 : hist[(hislen+k+idx+1) % hislen].hisnum;
- if (idx >= 0 && j <= k)
+ }
+ if (idx >= 0 && j <= k) {
for (i = idx + 1; !got_int; ++i) {
- if (i == hislen)
+ if (i == hislen) {
i = 0;
+ }
if (hist[i].hisstr != NULL
&& hist[i].hisnum >= j && hist[i].hisnum <= k) {
msg_putchar('\n');
@@ -6419,9 +6212,11 @@ void ex_history(exarg_T *eap)
msg_outtrans(IObuff);
ui_flush();
}
- if (i == idx)
+ if (i == idx) {
break;
+ }
}
+ }
}
}
@@ -6430,24 +6225,18 @@ int hist_type2char(int type)
FUNC_ATTR_CONST
{
switch (type) {
- case HIST_CMD: {
- return ':';
- }
- case HIST_SEARCH: {
- return '/';
- }
- case HIST_EXPR: {
- return '=';
- }
- case HIST_INPUT: {
- return '@';
- }
- case HIST_DEBUG: {
- return '>';
- }
- default: {
- abort();
- }
+ case HIST_CMD:
+ return ':';
+ case HIST_SEARCH:
+ return '/';
+ case HIST_EXPR:
+ return '=';
+ case HIST_INPUT:
+ return '@';
+ case HIST_DEBUG:
+ return '>';
+ default:
+ abort();
}
return NUL;
}
@@ -6461,23 +6250,22 @@ int hist_type2char(int type)
static int open_cmdwin(void)
{
struct cmdline_info save_ccline;
- bufref_T old_curbuf;
- bufref_T bufref;
- win_T *old_curwin = curwin;
- win_T *wp;
+ bufref_T old_curbuf;
+ bufref_T bufref;
+ win_T *old_curwin = curwin;
+ win_T *wp;
int i;
linenr_T lnum;
garray_T winsizes;
char_u typestr[2];
int save_restart_edit = restart_edit;
int save_State = State;
- int save_exmode = exmode_active;
+ bool save_exmode = exmode_active;
int save_cmdmsg_rl = cmdmsg_rl;
- /* Can't do this recursively. Can't do it when typing a password. */
+ // Can't do this recursively. Can't do it when typing a password.
if (cmdwin_type != 0
- || cmdline_star > 0
- ) {
+ || cmdline_star > 0) {
beep_flush();
return K_IGNORE;
}
@@ -6513,7 +6301,7 @@ static int open_cmdwin(void)
curwin->w_p_fen = false;
// Don't allow switching to another buffer.
- curbuf_lock++;
+ curbuf->b_ro_locked++;
// Showing the prompt may have set need_wait_return, reset it.
need_wait_return = false;
@@ -6521,12 +6309,12 @@ static int open_cmdwin(void)
const int histtype = hist_char2type(cmdwin_type);
if (histtype == HIST_CMD || histtype == HIST_DEBUG) {
if (p_wc == TAB) {
- add_map((char_u *)"<buffer> <Tab> <C-X><C-V>", INSERT);
- add_map((char_u *)"<buffer> <Tab> a<C-X><C-V>", NORMAL);
+ add_map((char_u *)"<buffer> <Tab> <C-X><C-V>", INSERT, false);
+ add_map((char_u *)"<buffer> <Tab> a<C-X><C-V>", NORMAL, false);
}
set_option_value("ft", 0L, "vim", OPT_LOCAL);
}
- curbuf_lock--;
+ curbuf->b_ro_locked--;
// Reset 'textwidth' after setting 'filetype' (the Vim filetype plugin
// sets 'textwidth' to 78).
@@ -6539,8 +6327,9 @@ static int open_cmdwin(void)
if (i >= 0) {
lnum = 0;
do {
- if (++i == hislen)
+ if (++i == hislen) {
i = 0;
+ }
if (history[histtype][i].hisstr != NULL) {
ml_append(lnum++, history[histtype][i].hisstr, (colnr_T)0, false);
}
@@ -6565,7 +6354,7 @@ static int open_cmdwin(void)
save_cmdline(&save_ccline);
// No Ex mode here!
- exmode_active = 0;
+ exmode_active = false;
State = NORMAL;
setmouse();
@@ -6614,10 +6403,11 @@ static int open_cmdwin(void)
cmdwin_result = Ctrl_C;
EMSG(_("E199: Active window or buffer deleted"));
} else {
- /* autocmds may abort script processing */
- if (aborting() && cmdwin_result != K_IGNORE)
+ // autocmds may abort script processing
+ if (aborting() && cmdwin_result != K_IGNORE) {
cmdwin_result = Ctrl_C;
- /* Set the new command line from the cmdline buffer. */
+ }
+ // Set the new command line from the cmdline buffer.
xfree(ccline.cmdbuff);
if (cmdwin_result == K_XF1 || cmdwin_result == K_XF2) { // :qa[!] typed
const char *p = (cmdwin_result == K_XF2) ? "qa" : "qa!";
@@ -6637,8 +6427,9 @@ static int open_cmdwin(void)
/* :q or :close, don't execute any command
* and don't modify the cmd window. */
ccline.cmdbuff = NULL;
- } else
+ } else {
ccline.cmdbuff = vim_strsave(get_cursor_line_ptr());
+ }
if (ccline.cmdbuff == NULL) {
ccline.cmdbuff = vim_strsave((char_u *)"");
ccline.cmdlen = 0;
@@ -6649,8 +6440,9 @@ static int open_cmdwin(void)
ccline.cmdlen = (int)STRLEN(ccline.cmdbuff);
ccline.cmdbufflen = ccline.cmdlen + 1;
ccline.cmdpos = curwin->w_cursor.col;
- if (ccline.cmdpos > ccline.cmdlen)
+ if (ccline.cmdpos > ccline.cmdlen) {
ccline.cmdpos = ccline.cmdlen;
+ }
if (cmdwin_result == K_IGNORE) {
ccline.cmdspos = cmd_screencol(ccline.cmdpos);
redrawcmd();
@@ -6716,13 +6508,12 @@ char *script_get(exarg_T *const eap, size_t *const lenp)
}
const char *const end_pattern = (
- cmd[2] != NUL
+ cmd[2] != NUL
? (const char *)skipwhite((const char_u *)cmd + 2)
: ".");
for (;;) {
- char *const theline = (char *)eap->getline(
- eap->cstack->cs_looplevel > 0 ? -1 :
- NUL, eap->cookie, 0, true);
+ char *const theline = (char *)eap->getline(eap->cstack->cs_looplevel > 0 ? -1 :
+ NUL, eap->cookie, 0, true);
if (theline == NULL || strcmp(end_pattern, theline) == 0) {
xfree(theline);
@@ -6764,8 +6555,8 @@ char *script_get(exarg_T *const eap, size_t *const lenp)
///
/// @return Pointer used in next iteration or NULL to indicate that iteration
/// was finished.
-const void *hist_iter(const void *const iter, const uint8_t history_type,
- const bool zero, histentry_T *const hist)
+const void *hist_iter(const void *const iter, const uint8_t history_type, const bool zero,
+ histentry_T *const hist)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(4)
{
*hist = (histentry_T) {
@@ -6776,7 +6567,7 @@ const void *hist_iter(const void *const iter, const uint8_t history_type,
}
histentry_T *const hstart = &(history[history_type][0]);
histentry_T *const hlast = (
- &(history[history_type][hisidx[history_type]]));
+ &(history[history_type][hisidx[history_type]]));
const histentry_T *const hend = &(history[history_type][hislen - 1]);
histentry_T *hiter;
if (iter == NULL) {
@@ -6792,7 +6583,7 @@ const void *hist_iter(const void *const iter, const uint8_t history_type,
} while (hfirst != hlast);
hiter = hfirst;
} else {
- hiter = (histentry_T *) iter;
+ hiter = (histentry_T *)iter;
}
if (hiter == NULL) {
return NULL;
@@ -6805,7 +6596,7 @@ const void *hist_iter(const void *const iter, const uint8_t history_type,
return NULL;
}
hiter++;
- return (const void *) ((hiter > hend) ? hstart : hiter);
+ return (const void *)((hiter > hend) ? hstart : hiter);
}
/// Get array of history items
diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c
index 67b8e7e92f..4aadd77d45 100644
--- a/src/nvim/ex_session.c
+++ b/src/nvim/ex_session.c
@@ -8,13 +8,11 @@
// :mksession
#include <assert.h>
-#include <string.h>
+#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
-#include <inttypes.h>
+#include <string.h>
-#include "nvim/vim.h"
-#include "nvim/globals.h"
#include "nvim/ascii.h"
#include "nvim/buffer.h"
#include "nvim/cursor.h"
@@ -28,6 +26,7 @@
#include "nvim/fileio.h"
#include "nvim/fold.h"
#include "nvim/getchar.h"
+#include "nvim/globals.h"
#include "nvim/keymap.h"
#include "nvim/misc1.h"
#include "nvim/move.h"
@@ -36,6 +35,7 @@
#include "nvim/os/os.h"
#include "nvim/os/time.h"
#include "nvim/path.h"
+#include "nvim/vim.h"
#include "nvim/window.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -63,7 +63,7 @@ static int put_view_curpos(FILE *fd, const win_T *wp, char *spaces)
static int ses_winsizes(FILE *fd, int restore_size, win_T *tab_firstwin)
{
int n = 0;
- win_T *wp;
+ win_T *wp;
if (restore_size && (ssop_flags & SSOP_WINSIZE)) {
for (wp = tab_firstwin; wp != NULL; wp = wp->w_next) {
@@ -105,7 +105,7 @@ static int ses_winsizes(FILE *fd, int restore_size, win_T *tab_firstwin)
// Returns FAIL when writing the commands to "fd" fails.
static int ses_win_rec(FILE *fd, frame_T *fr)
{
- frame_T *frc;
+ frame_T *frc;
int count = 0;
if (fr->fr_layout != FR_LEAF) {
@@ -149,7 +149,7 @@ static int ses_win_rec(FILE *fd, frame_T *fr)
// Returns NULL when there none.
static frame_T *ses_skipframe(frame_T *fr)
{
- frame_T *frc;
+ frame_T *frc;
FOR_ALL_FRAMES(frc, fr) {
if (ses_do_frame(frc)) {
@@ -200,11 +200,10 @@ static int ses_do_win(win_T *wp)
/// @param flagp
///
/// @returns FAIL if writing fails.
-static int ses_arglist(FILE *fd, char *cmd, garray_T *gap, int fullname,
- unsigned *flagp)
+static int ses_arglist(FILE *fd, char *cmd, garray_T *gap, int fullname, unsigned *flagp)
{
- char_u *buf = NULL;
- char_u *s;
+ char_u *buf = NULL;
+ char_u *s;
if (fprintf(fd, "%s\n%s\n", cmd, "%argdel") < 0) {
return FAIL;
@@ -297,17 +296,15 @@ static int ses_put_fname(FILE *fd, char_u *name, unsigned *flagp)
return retval;
}
-// Write commands to "fd" to restore the view of a window.
-// Caller must make sure 'scrolloff' is zero.
-static int put_view(
- FILE *fd,
- win_T *wp,
- int add_edit, // add ":edit" command to view
- unsigned *flagp, // vop_flags or ssop_flags
- int current_arg_idx // current argument index of the window, use
-) // -1 if unknown
+/// Write commands to "fd" to restore the view of a window.
+/// Caller must make sure 'scrolloff' is zero.
+///
+/// @param add_edit add ":edit" command to view
+/// @param flagp vop_flags or ssop_flags
+/// @param current_arg_idx current argument index of the window, use -1 if unknown
+static int put_view(FILE *fd, win_T *wp, int add_edit, unsigned *flagp, int current_arg_idx)
{
- win_T *save_curwin;
+ win_T *save_curwin;
int f;
int do_cursor;
int did_next = false;
@@ -348,8 +345,8 @@ static int put_view(
// Load the file.
//
if (wp->w_buffer->b_ffname != NULL
- && (!bt_nofile(wp->w_buffer) || wp->w_buffer->terminal)
- ) {
+ && (!bt_nofile(wp->w_buffer) ||
+ wp->w_buffer->terminal)) {
// Editing a file in this buffer: use ":edit file".
// This may have side effects! (e.g., compressed or network file).
//
@@ -434,8 +431,8 @@ static int put_view(
//
if ((*flagp & SSOP_FOLDS)
&& wp->w_buffer->b_ffname != NULL
- && (bt_normal(wp->w_buffer) || bt_help(wp->w_buffer))
- ) {
+ && (bt_normal(wp->w_buffer) ||
+ bt_help(wp->w_buffer))) {
if (put_folds(fd, wp) == FAIL) {
return FAIL;
}
@@ -453,11 +450,11 @@ static int put_view(
}
} else if (fprintf(fd,
"let s:l = %" PRIdLINENR " - ((%" PRIdLINENR
- " * winheight(0) + %" PRId64 ") / %" PRId64 ")\n",
+ " * winheight(0) + %d) / %d)\n",
wp->w_cursor.lnum,
wp->w_cursor.lnum - wp->w_topline,
- (int64_t)(wp->w_height_inner / 2),
- (int64_t)wp->w_height_inner) < 0) {
+ (wp->w_height_inner / 2),
+ wp->w_height_inner) < 0) {
return FAIL;
}
if (fprintf(fd,
@@ -525,12 +522,12 @@ static int makeopens(FILE *fd, char_u *dirnow)
int only_save_windows = true;
int nr;
int restore_size = true;
- win_T *wp;
- char_u *sname;
- win_T *edited_win = NULL;
+ win_T *wp;
+ char_u *sname;
+ win_T *edited_win = NULL;
int tabnr;
- win_T *tab_firstwin;
- frame_T *tab_topframe;
+ win_T *tab_firstwin;
+ frame_T *tab_topframe;
int cur_arg_idx = 0;
int next_arg_idx = 0;
@@ -583,22 +580,6 @@ static int makeopens(FILE *fd, char_u *dirnow)
return FAIL;
}
- // Now put the other buffers into the buffer list.
- FOR_ALL_BUFFERS(buf) {
- if (!(only_save_windows && buf->b_nwindows == 0)
- && !(buf->b_help && !(ssop_flags & SSOP_HELP))
- && buf->b_fname != NULL
- && buf->b_p_bl) {
- if (fprintf(fd, "badd +%" PRId64 " ",
- buf->b_wininfo == NULL
- ? (int64_t)1L
- : (int64_t)buf->b_wininfo->wi_fpos.lnum) < 0
- || ses_fname(fd, buf, &ssop_flags, true) == FAIL) {
- return FAIL;
- }
- }
- }
-
// the global argument list
if (ses_arglist(fd, "argglobal", &global_alist.al_ga,
!(ssop_flags & SSOP_CURDIR), &ssop_flags) == FAIL) {
@@ -674,8 +655,7 @@ static int makeopens(FILE *fd, char_u *dirnow)
if (ses_do_win(wp)
&& wp->w_buffer->b_ffname != NULL
&& !bt_help(wp->w_buffer)
- && !bt_nofile(wp->w_buffer)
- ) {
+ && !bt_nofile(wp->w_buffer)) {
if (need_tabnext && put_line(fd, "tabnext") == FAIL) {
return FAIL;
}
@@ -813,12 +793,31 @@ static int makeopens(FILE *fd, char_u *dirnow)
return FAIL;
}
+ // Now put the remaining buffers into the buffer list.
+ // This is near the end, so that when 'hidden' is set we don't create extra
+ // buffers. If the buffer was already created with another command the
+ // ":badd" will have no effect.
+ FOR_ALL_BUFFERS(buf) {
+ if (!(only_save_windows && buf->b_nwindows == 0)
+ && !(buf->b_help && !(ssop_flags & SSOP_HELP))
+ && buf->b_fname != NULL
+ && buf->b_p_bl) {
+ if (fprintf(fd, "badd +%" PRId64 " ",
+ buf->b_wininfo == NULL
+ ? (int64_t)1L
+ : (int64_t)buf->b_wininfo->wi_fpos.lnum) < 0
+ || ses_fname(fd, buf, &ssop_flags, true) == FAIL) {
+ return FAIL;
+ }
+ }
+ }
+
//
// Wipe out an empty unnamed buffer we started in.
//
if (fprintf(fd, "%s",
"if exists('s:wipebuf') "
- "&& len(win_findbuf(s:wipebuf)) == 0"
+ "&& len(win_findbuf(s:wipebuf)) == 0 "
"&& getbufvar(s:wipebuf, '&buftype') isnot# 'terminal'\n"
" silent exe 'bwipe ' . s:wipebuf\n"
"endif\n"
@@ -874,12 +873,12 @@ void ex_loadview(exarg_T *eap)
/// - SSOP_SLASH: filenames are written with "/" slash
void ex_mkrc(exarg_T *eap)
{
- FILE *fd;
+ FILE *fd;
int failed = false;
int view_session = false; // :mkview, :mksession
int using_vdir = false; // using 'viewdir'?
char *viewFile = NULL;
- unsigned *flagp;
+ unsigned *flagp;
if (eap->cmdidx == CMD_mksession || eap->cmdidx == CMD_mkview) {
view_session = true;
diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c
index 2906a2196b..cf01c305d7 100644
--- a/src/nvim/extmark.c
+++ b/src/nvim/extmark.c
@@ -19,7 +19,7 @@
// Marks live in namespaces that allow plugins/users to segregate marks
// from other users.
//
-// Deleting marks only happens when explicitly calling extmark_del, deleteing
+// Deleting marks only happens when explicitly calling extmark_del, deleting
// over a range of marks will only move the marks. Deleting on a mark will
// leave it in same position unless it is on the EOL of a line.
//
@@ -29,55 +29,43 @@
// code for redrawing the line with the deleted decoration.
#include <assert.h>
+
#include "nvim/api/vim.h"
-#include "nvim/vim.h"
+#include "nvim/buffer.h"
+#include "nvim/buffer_updates.h"
#include "nvim/charset.h"
-#include "nvim/extmark.h"
#include "nvim/decoration.h"
-#include "nvim/buffer_updates.h"
-#include "nvim/memline.h"
-#include "nvim/pos.h"
+#include "nvim/extmark.h"
#include "nvim/globals.h"
-#include "nvim/map.h"
#include "nvim/lib/kbtree.h"
+#include "nvim/map.h"
+#include "nvim/memline.h"
+#include "nvim/pos.h"
#include "nvim/undo.h"
-#include "nvim/buffer.h"
+#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "extmark.c.generated.h"
#endif
static ExtmarkNs *buf_ns_ref(buf_T *buf, uint64_t ns_id, bool put) {
- if (!buf->b_extmark_ns) {
- if (!put) {
- return NULL;
- }
- buf->b_extmark_ns = map_new(uint64_t, ExtmarkNs)();
- buf->b_extmark_index = map_new(uint64_t, ExtmarkItem)();
- }
-
- ExtmarkNs *ns = map_ref(uint64_t, ExtmarkNs)(buf->b_extmark_ns, ns_id, put);
- if (put && ns->map == NULL) {
- ns->map = map_new(uint64_t, uint64_t)();
- ns->free_id = 1;
- }
- return ns;
+ return map_ref(uint64_t, ExtmarkNs)(buf->b_extmark_ns, ns_id, put);
}
/// Create or update an extmark
///
/// must not be used during iteration!
-/// @returns the mark id
-uint64_t extmark_set(buf_T *buf, uint64_t ns_id, uint64_t id,
- int row, colnr_T col, int end_row, colnr_T end_col,
- Decoration *decor, bool right_gravity,
- bool end_right_gravity, ExtmarkOp op)
+/// @returns the internal mark id
+uint64_t extmark_set(buf_T *buf, uint64_t ns_id, uint64_t *idp, int row, colnr_T col, int end_row,
+ colnr_T end_col, Decoration *decor, bool right_gravity, bool end_right_gravity,
+ ExtmarkOp op)
{
ExtmarkNs *ns = buf_ns_ref(buf, ns_id, true);
assert(ns != NULL);
mtpos_t old_pos;
uint64_t mark = 0;
+ uint64_t id = idp ? *idp : 0;
if (id == 0) {
id = ns->free_id++;
@@ -131,7 +119,11 @@ revised:
if (decor) {
decor_redraw(buf, row, end_row > -1 ? end_row : row, decor);
}
- return id;
+
+ if (idp) {
+ *idp = id;
+ }
+ return mark;
}
static bool extmark_setraw(buf_T *buf, uint64_t mark, int row, colnr_T col)
@@ -182,6 +174,10 @@ bool extmark_del(buf_T *buf, uint64_t ns_id, uint64_t id)
decor_free(item.decor);
}
+ if (mark == buf->b_virt_line_mark) {
+ clear_virt_lines(buf, pos.row);
+ }
+
map_del(uint64_t, uint64_t)(ns->map, id);
map_del(uint64_t, ExtmarkItem)(buf->b_extmark_index, mark);
@@ -191,11 +187,9 @@ bool extmark_del(buf_T *buf, uint64_t ns_id, uint64_t id)
// Free extmarks in a ns between lines
// if ns = 0, it means clear all namespaces
-bool extmark_clear(buf_T *buf, uint64_t ns_id,
- int l_row, colnr_T l_col,
- int u_row, colnr_T u_col)
+bool extmark_clear(buf_T *buf, uint64_t ns_id, int l_row, colnr_T l_col, int u_row, colnr_T u_col)
{
- if (!buf->b_extmark_ns) {
+ if (!map_size(buf->b_extmark_ns)) {
return false;
}
@@ -215,12 +209,9 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id,
}
// the value is either zero or the lnum (row+1) if highlight was present.
- static Map(uint64_t, ssize_t) *delete_set = NULL;
+ static Map(uint64_t, ssize_t) delete_set = MAP_INIT;
typedef struct { Decoration *decor; int row1; } DecorItem;
static kvec_t(DecorItem) decors;
- if (delete_set == NULL) {
- delete_set = map_new(uint64_t, ssize_t)();
- }
MarkTreeIter itr[1] = { 0 };
marktree_itr_get(buf->b_marktree, l_row, l_col, itr);
@@ -231,7 +222,7 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id,
|| (mark.row == u_row && mark.col > u_col)) {
break;
}
- ssize_t *del_status = map_ref(uint64_t, ssize_t)(delete_set, mark.id,
+ ssize_t *del_status = map_ref(uint64_t, ssize_t)(&delete_set, mark.id,
false);
if (del_status) {
marktree_del_itr(buf->b_marktree, itr, false);
@@ -240,11 +231,14 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id,
decor_redraw(buf, it.row1, mark.row, it.decor);
decor_free(it.decor);
}
- map_del(uint64_t, ssize_t)(delete_set, mark.id);
+ map_del(uint64_t, ssize_t)(&delete_set, mark.id);
continue;
}
uint64_t start_id = mark.id & ~MARKTREE_END_FLAG;
+ if (start_id == buf->b_virt_line_mark) {
+ clear_virt_lines(buf, mark.row);
+ }
ExtmarkItem item = map_get(uint64_t, ExtmarkItem)(buf->b_extmark_index,
start_id);
@@ -261,14 +255,14 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id,
kv_push(decors,
((DecorItem) { .decor = item.decor, .row1 = mark.row }));
}
- map_put(uint64_t, ssize_t)(delete_set, other, decor_id);
+ map_put(uint64_t, ssize_t)(&delete_set, other, decor_id);
} else if (item.decor) {
decor_redraw(buf, mark.row, mark.row, item.decor);
decor_free(item.decor);
}
ExtmarkNs *my_ns = all_ns ? buf_ns_ref(buf, item.ns_id, false) : ns;
map_del(uint64_t, uint64_t)(my_ns->map, item.mark_id);
- map_del(uint64_t, ExtmarkItem)(buf->b_extmark_index, mark.id);
+ map_del(uint64_t, ExtmarkItem)(buf->b_extmark_index, start_id);
marktree_del_itr(buf->b_marktree, itr, false);
} else {
marktree_itr_next(buf->b_marktree, itr);
@@ -276,7 +270,7 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id,
}
uint64_t id;
ssize_t decor_id;
- map_foreach(delete_set, id, decor_id, {
+ map_foreach(&delete_set, id, decor_id, {
mtpos_t pos = marktree_lookup(buf->b_marktree, id, itr);
assert(itr->node);
marktree_del_itr(buf->b_marktree, itr, false);
@@ -286,7 +280,7 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id,
decor_free(it.decor);
}
});
- map_clear(uint64_t, ssize_t)(delete_set);
+ map_clear(uint64_t, ssize_t)(&delete_set);
kv_size(decors) = 0;
return marks_cleared;
}
@@ -297,10 +291,8 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id,
// will be searched to the start, or end
// dir can be set to control the order of the array
// amount = amount of marks to find or -1 for all
-ExtmarkInfoArray extmark_get(buf_T *buf, uint64_t ns_id,
- int l_row, colnr_T l_col,
- int u_row, colnr_T u_col,
- int64_t amount, bool reverse)
+ExtmarkInfoArray extmark_get(buf_T *buf, uint64_t ns_id, int l_row, colnr_T l_col, int u_row,
+ colnr_T u_col, int64_t amount, bool reverse)
{
ExtmarkInfoArray array = KV_INITIAL_VALUE;
MarkTreeIter itr[1];
@@ -383,7 +375,7 @@ ExtmarkInfo extmark_from_id(buf_T *buf, uint64_t ns_id, uint64_t id)
// free extmarks from the buffer
void extmark_free_all(buf_T *buf)
{
- if (!buf->b_extmark_ns) {
+ if (!map_size(buf->b_extmark_ns)) {
return;
}
@@ -395,25 +387,24 @@ void extmark_free_all(buf_T *buf)
map_foreach(buf->b_extmark_ns, id, ns, {
(void)id;
- map_free(uint64_t, uint64_t)(ns.map);
+ map_destroy(uint64_t, uint64_t)(ns.map);
});
- map_free(uint64_t, ExtmarkNs)(buf->b_extmark_ns);
- buf->b_extmark_ns = NULL;
+ map_destroy(uint64_t, ExtmarkNs)(buf->b_extmark_ns);
+ map_init(uint64_t, ExtmarkNs, buf->b_extmark_ns);
map_foreach(buf->b_extmark_index, id, item, {
(void)id;
decor_free(item.decor);
});
- map_free(uint64_t, ExtmarkItem)(buf->b_extmark_index);
- buf->b_extmark_index = NULL;
+ map_destroy(uint64_t, ExtmarkItem)(buf->b_extmark_index);
+ map_init(uint64_t, ExtmarkItem, buf->b_extmark_index);
}
// Save info for undo/redo of set marks
-static void u_extmark_set(buf_T *buf, uint64_t mark,
- int row, colnr_T col)
+static void u_extmark_set(buf_T *buf, uint64_t mark, int row, colnr_T col)
{
- u_header_T *uhp = u_force_get_undo_header(buf);
+ u_header_T *uhp = u_force_get_undo_header(buf);
if (!uhp) {
return;
}
@@ -435,11 +426,9 @@ static void u_extmark_set(buf_T *buf, uint64_t mark,
///
/// useful when we cannot simply reverse the operation. This will do nothing on
/// redo, enforces correct position when undo.
-void u_extmark_copy(buf_T *buf,
- int l_row, colnr_T l_col,
- int u_row, colnr_T u_col)
+void u_extmark_copy(buf_T *buf, int l_row, colnr_T l_col, int u_row, colnr_T u_col)
{
- u_header_T *uhp = u_force_get_undo_header(buf);
+ u_header_T *uhp = u_force_get_undo_header(buf);
if (!uhp) {
return;
}
@@ -483,7 +472,6 @@ void extmark_apply_undo(ExtmarkUndoObject undo_info, bool undo)
splice.new_row, splice.new_col, splice.new_byte,
splice.old_row, splice.old_col, splice.old_byte,
kExtmarkNoUndo);
-
} else {
extmark_splice_impl(curbuf,
splice.start_row, splice.start_col, splice.start_byte,
@@ -491,14 +479,14 @@ void extmark_apply_undo(ExtmarkUndoObject undo_info, bool undo)
splice.new_row, splice.new_col, splice.new_byte,
kExtmarkNoUndo);
}
- // kExtmarkSavePos
+ // kExtmarkSavePos
} else if (undo_info.type == kExtmarkSavePos) {
ExtmarkSavePos pos = undo_info.data.savepos;
if (undo) {
if (pos.old_row >= 0) {
extmark_setraw(curbuf, pos.mark, pos.old_row, pos.old_col);
}
- // Redo
+ // Redo
} else {
if (pos.row >= 0) {
extmark_setraw(curbuf, pos.mark, pos.row, pos.col);
@@ -520,15 +508,12 @@ void extmark_apply_undo(ExtmarkUndoObject undo_info, bool undo)
kExtmarkNoUndo);
}
}
+ curbuf->b_virt_line_pos = -1;
}
// 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,
+void extmark_adjust(buf_T *buf, linenr_T line1, linenr_T line2, long amount, long amount_after,
ExtmarkOp undo)
{
if (curbuf_splice_pending) {
@@ -553,7 +538,7 @@ void extmark_adjust(buf_T *buf,
}
if (new_row > 0) {
new_byte = ml_find_line_or_offset(buf, line1+new_row, NULL, true)
- - start_byte;
+ - start_byte;
}
extmark_splice_impl(buf,
(int)line1-1, 0, start_byte,
@@ -578,10 +563,8 @@ void extmark_adjust(buf_T *buf,
// the end column of the new region.
// @param new_byte Byte extent of the new region.
// @param undo
-void extmark_splice(buf_T *buf,
- int start_row, colnr_T start_col,
- int old_row, colnr_T old_col, bcount_t old_byte,
- int new_row, colnr_T new_col, bcount_t new_byte,
+void extmark_splice(buf_T *buf, int start_row, colnr_T start_col, int old_row, colnr_T old_col,
+ bcount_t old_byte, int new_row, colnr_T new_col, bcount_t new_byte,
ExtmarkOp undo)
{
long offset = ml_find_line_or_offset(buf, start_row + 1, NULL, true);
@@ -600,13 +583,12 @@ void extmark_splice(buf_T *buf,
undo);
}
-void extmark_splice_impl(buf_T *buf,
- int start_row, colnr_T start_col, bcount_t start_byte,
- int old_row, colnr_T old_col, bcount_t old_byte,
- int new_row, colnr_T new_col, bcount_t new_byte,
- ExtmarkOp undo)
+void extmark_splice_impl(buf_T *buf, int start_row, colnr_T start_col, bcount_t start_byte,
+ int old_row, colnr_T old_col, bcount_t old_byte, int new_row,
+ colnr_T new_col, bcount_t new_byte, ExtmarkOp undo)
{
- curbuf->deleted_bytes2 = 0;
+ buf->deleted_bytes2 = 0;
+ buf->b_virt_line_pos = -1;
buf_updates_send_splice(buf, start_row, start_col, start_byte,
old_row, old_col, old_byte,
new_row, new_col, new_byte);
@@ -628,7 +610,7 @@ void extmark_splice_impl(buf_T *buf,
new_row, new_col);
if (undo == kExtmarkUndo) {
- u_header_T *uhp = u_force_get_undo_header(buf);
+ u_header_T *uhp = u_force_get_undo_header(buf);
if (!uhp) {
return;
}
@@ -637,7 +619,7 @@ void extmark_splice_impl(buf_T *buf,
// TODO(bfredl): this is quite rudimentary. We merge small (within line)
// inserts with each other and small deletes with each other. Add full
// merge algorithm later.
- if (old_row == 0 && new_row == 0 && kv_size(uhp->uh_extmark)) {
+ if (old_row == 0 && new_row == 0 && kv_size(uhp->uh_extmark)) {
ExtmarkUndoObject *item = &kv_A(uhp->uh_extmark,
kv_size(uhp->uh_extmark)-1);
if (item->type == kExtmarkSplice) {
@@ -685,24 +667,20 @@ void extmark_splice_impl(buf_T *buf,
}
}
-void extmark_splice_cols(buf_T *buf,
- int start_row, colnr_T start_col,
- colnr_T old_col, colnr_T new_col,
- ExtmarkOp undo)
+void extmark_splice_cols(buf_T *buf, int start_row, colnr_T start_col, colnr_T old_col,
+ colnr_T new_col, ExtmarkOp undo)
{
extmark_splice(buf, start_row, start_col,
0, old_col, old_col,
0, new_col, new_col, undo);
}
-void extmark_move_region(
- buf_T *buf,
- int start_row, colnr_T start_col, bcount_t start_byte,
- int extent_row, colnr_T extent_col, bcount_t extent_byte,
- int new_row, colnr_T new_col, bcount_t new_byte,
- ExtmarkOp undo)
+void extmark_move_region(buf_T *buf, int start_row, colnr_T start_col, bcount_t start_byte,
+ int extent_row, colnr_T extent_col, bcount_t extent_byte, int new_row,
+ colnr_T new_col, bcount_t new_byte, ExtmarkOp undo)
{
- curbuf->deleted_bytes2 = 0;
+ buf->deleted_bytes2 = 0;
+ buf->b_virt_line_pos = -1;
// TODO(bfredl): this is not synced to the buffer state inside the callback.
// But unless we make the undo implementation smarter, this is not ensured
// anyway.
@@ -720,7 +698,7 @@ void extmark_move_region(
if (undo == kExtmarkUndo) {
- u_header_T *uhp = u_force_get_undo_header(buf);
+ u_header_T *uhp = u_force_get_undo_header(buf);
if (!uhp) {
return;
}
diff --git a/src/nvim/extmark_defs.h b/src/nvim/extmark_defs.h
index 784280dace..2da4f3dc00 100644
--- a/src/nvim/extmark_defs.h
+++ b/src/nvim/extmark_defs.h
@@ -6,6 +6,16 @@
typedef struct Decoration Decoration;
+typedef struct {
+ char *text;
+ int hl_id;
+} VirtTextChunk;
+
+typedef kvec_t(VirtTextChunk) VirtText;
+#define VIRTTEXT_EMPTY ((VirtText)KV_INITIAL_VALUE)
+typedef kvec_t(VirtText) VirtLines;
+
+
typedef struct
{
uint64_t ns_id;
@@ -23,8 +33,8 @@ typedef kvec_t(ExtmarkUndoObject) extmark_undo_vec_t;
typedef enum {
kExtmarkNOOP, // Extmarks shouldn't be moved
- kExtmarkUndo, // Operation should be reversable/undoable
- kExtmarkNoUndo, // Operation should not be reversable
+ kExtmarkUndo, // Operation should be reversible/undoable
+ kExtmarkNoUndo, // Operation should not be reversible
kExtmarkUndoNoRedo, // Operation should be undoable, but not redoable
} ExtmarkOp;
diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c
index 8beba38509..d364895ea4 100644
--- a/src/nvim/file_search.c
+++ b/src/nvim/file_search.c
@@ -44,50 +44,50 @@
// functions.
#include <assert.h>
-#include <string.h>
-#include <stdbool.h>
#include <inttypes.h>
#include <limits.h>
+#include <stdbool.h>
+#include <string.h>
-#include "nvim/vim.h"
-#include "nvim/eval.h"
#include "nvim/ascii.h"
-#include "nvim/file_search.h"
#include "nvim/charset.h"
+#include "nvim/eval.h"
+#include "nvim/file_search.h"
#include "nvim/fileio.h"
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
#include "nvim/option.h"
+#include "nvim/os/fs_defs.h"
+#include "nvim/os/input.h"
+#include "nvim/os/os.h"
#include "nvim/os_unix.h"
#include "nvim/path.h"
#include "nvim/strings.h"
#include "nvim/tag.h"
+#include "nvim/vim.h"
#include "nvim/window.h"
-#include "nvim/os/os.h"
-#include "nvim/os/input.h"
-#include "nvim/os/fs_defs.h"
-static char_u *ff_expand_buffer = NULL; /* used for expanding filenames */
+static char_u *ff_expand_buffer = NULL; // used for expanding filenames
/*
* type for the directory search stack
*/
typedef struct ff_stack {
- struct ff_stack *ffs_prev;
+ struct ff_stack *ffs_prev;
/* the fix part (no wildcards) and the part containing the wildcards
* of the search path
*/
- char_u *ffs_fix_path;
- char_u *ffs_wc_path;
+ char_u *ffs_fix_path;
+ char_u *ffs_wc_path;
/* files/dirs found in the above directory, matched by the first wildcard
* of wc_part
*/
- char_u **ffs_filearray;
+ char_u **ffs_filearray;
int ffs_filearray_size;
- char_u ffs_filearray_cur; /* needed for partly handled dirs */
+ char_u ffs_filearray_cur; // needed for partly handled dirs
/* to store status of partly handled directories
* 0: we work on this directory for the first time
@@ -100,7 +100,7 @@ typedef struct ff_stack {
*/
int ffs_level;
- /* Did we already expand '**' to an empty string? */
+ // Did we already expand '**' to an empty string?
int ffs_star_star_empty;
} ff_stack_T;
@@ -108,19 +108,19 @@ typedef struct ff_stack {
* type for already visited directories or files.
*/
typedef struct ff_visited {
- struct ff_visited *ffv_next;
+ struct ff_visited *ffv_next;
/* Visited directories are different if the wildcard string are
* different. So we have to save it.
*/
- char_u *ffv_wc_path;
+ char_u *ffv_wc_path;
// use FileID for comparison (needed because of links), else use filename.
bool file_id_valid;
FileID file_id;
/* The memory for this struct is allocated according to the length of
* ffv_fname.
*/
- char_u ffv_fname[1]; /* actually longer */
+ char_u ffv_fname[1]; // actually longer
} ff_visited_T;
/*
@@ -138,13 +138,12 @@ typedef struct ff_visited {
* visited lists.
*/
typedef struct ff_visited_list_hdr {
- struct ff_visited_list_hdr *ffvl_next;
+ struct ff_visited_list_hdr *ffvl_next;
- /* the filename the attached visited list is for */
- char_u *ffvl_filename;
-
- ff_visited_T *ffvl_visited_list;
+ // the filename the attached visited list is for
+ char_u *ffvl_filename;
+ ff_visited_T *ffvl_visited_list;
} ff_visited_list_hdr_T;
@@ -156,38 +155,38 @@ typedef struct ff_visited_list_hdr {
/*
* The search context:
- * ffsc_stack_ptr: the stack for the dirs to search
+ * ffsc_stack_ptr: the stack for the dirs to search
* ffsc_visited_list: the currently active visited list
* ffsc_dir_visited_list: the currently active visited list for search dirs
* ffsc_visited_lists_list: the list of all visited lists
* ffsc_dir_visited_lists_list: the list of all visited lists for search dirs
* ffsc_file_to_search: the file to search for
- * ffsc_start_dir: the starting directory, if search path was relative
- * ffsc_fix_path: the fix part of the given path (without wildcards)
- * Needed for upward search.
- * ffsc_wc_path: the part of the given path containing wildcards
- * ffsc_level: how many levels of dirs to search downwards
- * ffsc_stopdirs_v: array of stop directories for upward search
- * ffsc_find_what: FINDFILE_BOTH, FINDFILE_DIR or FINDFILE_FILE
- * ffsc_tagfile: searching for tags file, don't use 'suffixesadd'
+ * ffsc_start_dir: the starting directory, if search path was relative
+ * ffsc_fix_path: the fix part of the given path (without wildcards)
+ * Needed for upward search.
+ * ffsc_wc_path: the part of the given path containing wildcards
+ * ffsc_level: how many levels of dirs to search downwards
+ * ffsc_stopdirs_v: array of stop directories for upward search
+ * ffsc_find_what: FINDFILE_BOTH, FINDFILE_DIR or FINDFILE_FILE
+ * ffsc_tagfile: searching for tags file, don't use 'suffixesadd'
*/
typedef struct ff_search_ctx_T {
- ff_stack_T *ffsc_stack_ptr;
- ff_visited_list_hdr_T *ffsc_visited_list;
- ff_visited_list_hdr_T *ffsc_dir_visited_list;
- ff_visited_list_hdr_T *ffsc_visited_lists_list;
- ff_visited_list_hdr_T *ffsc_dir_visited_lists_list;
- char_u *ffsc_file_to_search;
- char_u *ffsc_start_dir;
- char_u *ffsc_fix_path;
- char_u *ffsc_wc_path;
+ ff_stack_T *ffsc_stack_ptr;
+ ff_visited_list_hdr_T *ffsc_visited_list;
+ ff_visited_list_hdr_T *ffsc_dir_visited_list;
+ ff_visited_list_hdr_T *ffsc_visited_lists_list;
+ ff_visited_list_hdr_T *ffsc_dir_visited_lists_list;
+ char_u *ffsc_file_to_search;
+ char_u *ffsc_start_dir;
+ char_u *ffsc_fix_path;
+ char_u *ffsc_wc_path;
int ffsc_level;
- char_u **ffsc_stopdirs_v;
+ char_u **ffsc_stopdirs_v;
int ffsc_find_what;
int ffsc_tagfile;
} ff_search_ctx_T;
-/* locally needed functions */
+// locally needed functions
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "file_search.c.generated.h"
@@ -195,104 +194,98 @@ typedef struct ff_search_ctx_T {
static char_u e_pathtoolong[] = N_("E854: path too long for completion");
-/*
- * Initialization routine for vim_findfile().
- *
- * Returns the newly allocated search context or NULL if an error occurred.
- *
- * Don't forget to clean up by calling vim_findfile_cleanup() if you are done
- * with the search context.
- *
- * Find the file 'filename' in the directory 'path'.
- * The parameter 'path' may contain wildcards. If so only search 'level'
- * directories deep. The parameter 'level' is the absolute maximum and is
- * not related to restricts given to the '**' wildcard. If 'level' is 100
- * and you use '**200' vim_findfile() will stop after 100 levels.
- *
- * 'filename' cannot contain wildcards! It is used as-is, no backslashes to
- * escape special characters.
- *
- * If 'stopdirs' is not NULL and nothing is found downward, the search is
- * restarted on the next higher directory level. This is repeated until the
- * start-directory of a search is contained in 'stopdirs'. 'stopdirs' has the
- * format ";*<dirname>*\(;<dirname>\)*;\=$".
- *
- * If the 'path' is relative, the starting dir for the search is either VIM's
- * current dir or if the path starts with "./" the current files dir.
- * If the 'path' is absolute, the starting dir is that part of the path before
- * the first wildcard.
- *
- * Upward search is only done on the starting dir.
- *
- * If 'free_visited' is TRUE the list of already visited files/directories is
- * cleared. Set this to FALSE if you just want to search from another
- * directory, but want to be sure that no directory from a previous search is
- * searched again. This is useful if you search for a file at different places.
- * The list of visited files/dirs can also be cleared with the function
- * vim_findfile_free_visited().
- *
- * Set the parameter 'find_what' to FINDFILE_DIR if you want to search for
- * directories only, FINDFILE_FILE for files only, FINDFILE_BOTH for both.
- *
- * A search context returned by a previous call to vim_findfile_init() can be
- * passed in the parameter "search_ctx_arg". This context is reused and
- * reinitialized with the new parameters. The list of already visited
- * directories from this context is only deleted if the parameter
- * "free_visited" is true. Be aware that the passed "search_ctx_arg" is freed
- * if the reinitialization fails.
- *
- * If you don't have a search context from a previous call "search_ctx_arg"
- * must be NULL.
- *
- * This function silently ignores a few errors, vim_findfile() will have
- * limited functionality then.
- */
-void *
-vim_findfile_init (
- char_u *path,
- char_u *filename,
- char_u *stopdirs,
- int level,
- int free_visited,
- int find_what,
- void *search_ctx_arg,
- int tagfile, /* expanding names of tags files */
- char_u *rel_fname /* file name to use for "." */
-)
+/// Initialization routine for vim_findfile().
+///
+/// Returns the newly allocated search context or NULL if an error occurred.
+///
+/// Don't forget to clean up by calling vim_findfile_cleanup() if you are done
+/// with the search context.
+///
+/// Find the file 'filename' in the directory 'path'.
+/// The parameter 'path' may contain wildcards. If so only search 'level'
+/// directories deep. The parameter 'level' is the absolute maximum and is
+/// not related to restricts given to the '**' wildcard. If 'level' is 100
+/// and you use '**200' vim_findfile() will stop after 100 levels.
+///
+/// 'filename' cannot contain wildcards! It is used as-is, no backslashes to
+/// escape special characters.
+///
+/// If 'stopdirs' is not NULL and nothing is found downward, the search is
+/// restarted on the next higher directory level. This is repeated until the
+/// start-directory of a search is contained in 'stopdirs'. 'stopdirs' has the
+/// format ";*<dirname>*\(;<dirname>\)*;\=$".
+///
+/// If the 'path' is relative, the starting dir for the search is either VIM's
+/// current dir or if the path starts with "./" the current files dir.
+/// If the 'path' is absolute, the starting dir is that part of the path before
+/// the first wildcard.
+///
+/// Upward search is only done on the starting dir.
+///
+/// If 'free_visited' is TRUE the list of already visited files/directories is
+/// cleared. Set this to FALSE if you just want to search from another
+/// directory, but want to be sure that no directory from a previous search is
+/// searched again. This is useful if you search for a file at different places.
+/// The list of visited files/dirs can also be cleared with the function
+/// vim_findfile_free_visited().
+///
+/// Set the parameter 'find_what' to FINDFILE_DIR if you want to search for
+/// directories only, FINDFILE_FILE for files only, FINDFILE_BOTH for both.
+///
+/// A search context returned by a previous call to vim_findfile_init() can be
+/// passed in the parameter "search_ctx_arg". This context is reused and
+/// reinitialized with the new parameters. The list of already visited
+/// directories from this context is only deleted if the parameter
+/// "free_visited" is true. Be aware that the passed "search_ctx_arg" is freed
+/// if the reinitialization fails.
+///
+/// If you don't have a search context from a previous call "search_ctx_arg"
+/// must be NULL.
+///
+/// This function silently ignores a few errors, vim_findfile() will have
+/// limited functionality then.
+///
+/// @param tagfile expanding names of tags files
+/// @param rel_fname file name to use for "."
+void *vim_findfile_init(char_u *path, char_u *filename, char_u *stopdirs, int level,
+ int free_visited, int find_what, void *search_ctx_arg, int tagfile,
+ char_u *rel_fname)
{
- char_u *wc_part;
- ff_stack_T *sptr;
- ff_search_ctx_T *search_ctx;
+ char_u *wc_part;
+ ff_stack_T *sptr;
+ ff_search_ctx_T *search_ctx;
/* If a search context is given by the caller, reuse it, else allocate a
* new one.
*/
- if (search_ctx_arg != NULL)
+ if (search_ctx_arg != NULL) {
search_ctx = search_ctx_arg;
- else {
+ } else {
search_ctx = xcalloc(1, sizeof(ff_search_ctx_T));
}
search_ctx->ffsc_find_what = find_what;
search_ctx->ffsc_tagfile = tagfile;
- /* clear the search context, but NOT the visited lists */
+ // clear the search context, but NOT the visited lists
ff_clear(search_ctx);
- /* clear visited list if wanted */
- if (free_visited == TRUE)
+ // clear visited list if wanted
+ if (free_visited == TRUE) {
vim_findfile_free_visited(search_ctx);
- else {
+ } else {
/* Reuse old visited lists. Get the visited list for the given
* filename. If no list for the current filename exists, creates a new
* one. */
search_ctx->ffsc_visited_list = ff_get_visited_list(filename,
- &search_ctx->ffsc_visited_lists_list);
- if (search_ctx->ffsc_visited_list == NULL)
+ &search_ctx->ffsc_visited_lists_list);
+ if (search_ctx->ffsc_visited_list == NULL) {
goto error_return;
+ }
search_ctx->ffsc_dir_visited_list = ff_get_visited_list(filename,
- &search_ctx->ffsc_dir_visited_lists_list);
- if (search_ctx->ffsc_dir_visited_list == NULL)
+ &search_ctx->ffsc_dir_visited_lists_list);
+ if (search_ctx->ffsc_dir_visited_list == NULL) {
goto error_return;
+ }
}
if (ff_expand_buffer == NULL) {
@@ -308,16 +301,18 @@ vim_findfile_init (
size_t len = (size_t)(path_tail(rel_fname) - rel_fname);
if (!vim_isAbsName(rel_fname) && len + 1 < MAXPATHL) {
- /* Make the start dir an absolute path name. */
+ // Make the start dir an absolute path name.
STRLCPY(ff_expand_buffer, rel_fname, len + 1);
search_ctx->ffsc_start_dir = (char_u *)FullName_save((char *)ff_expand_buffer, FALSE);
- } else
+ } else {
search_ctx->ffsc_start_dir = vim_strnsave(rel_fname, len);
- if (*++path != NUL)
+ }
+ if (*++path != NUL) {
++path;
+ }
} else if (*path == NUL || !vim_isAbsName(path)) {
#ifdef BACKSLASH_IN_FILENAME
- /* "c:dir" needs "c:" to be expanded, otherwise use current dir */
+ // "c:dir" needs "c:" to be expanded, otherwise use current dir
if (*path != NUL && path[1] == ':') {
char_u drive[3];
@@ -332,8 +327,9 @@ vim_findfile_init (
path += 2;
} else
#endif
- if (os_dirname(ff_expand_buffer, MAXPATHL) == FAIL)
+ if (os_dirname(ff_expand_buffer, MAXPATHL) == FAIL) {
goto error_return;
+ }
search_ctx->ffsc_start_dir = vim_strsave(ff_expand_buffer);
@@ -342,8 +338,9 @@ vim_findfile_init (
* directory (but not for "//machine/dir"). Only use the drive name. */
if ((*path == '/' || *path == '\\')
&& path[1] != path[0]
- && search_ctx->ffsc_start_dir[1] == ':')
+ && search_ctx->ffsc_start_dir[1] == ':') {
search_ctx->ffsc_start_dir[2] = NUL;
+ }
#endif
}
@@ -357,21 +354,22 @@ vim_findfile_init (
* ff_path_in_stoplist() for details.
*/
if (stopdirs != NULL) {
- char_u *walker = stopdirs;
+ char_u *walker = stopdirs;
- while (*walker == ';')
+ while (*walker == ';') {
walker++;
+ }
size_t dircount = 1;
search_ctx->ffsc_stopdirs_v = xmalloc(sizeof(char_u *));
do {
- char_u *helper;
- void *ptr;
+ char_u *helper;
+ void *ptr;
helper = walker;
ptr = xrealloc(search_ctx->ffsc_stopdirs_v,
- (dircount + 1) * sizeof(char_u *));
+ (dircount + 1) * sizeof(char_u *));
search_ctx->ffsc_stopdirs_v = ptr;
walker = vim_strchr(walker, ';');
if (walker) {
@@ -379,15 +377,15 @@ vim_findfile_init (
search_ctx->ffsc_stopdirs_v[dircount-1] =
vim_strnsave(helper, (size_t)(walker - helper));
walker++;
- } else
+ } else {
/* this might be "", which means ascent till top
* of directory tree.
*/
search_ctx->ffsc_stopdirs_v[dircount-1] =
vim_strsave(helper);
+ }
dircount++;
-
} while (walker != NULL);
search_ctx->ffsc_stopdirs_v[dircount-1] = NULL;
}
@@ -402,9 +400,9 @@ vim_findfile_init (
if (wc_part != NULL) {
int64_t llevel;
int len;
- char *errpt;
+ char *errpt;
- /* save the fix part of the path */
+ // save the fix part of the path
assert(wc_part - path >= 0);
search_ctx->ffsc_fix_path = vim_strnsave(path, (size_t)(wc_part - path));
@@ -428,27 +426,30 @@ vim_findfile_init (
ff_expand_buffer[len++] = *wc_part++;
llevel = strtol((char *)wc_part, &errpt, 10);
- if ((char_u *)errpt != wc_part && llevel > 0 && llevel < 255)
+ if ((char_u *)errpt != wc_part && llevel > 0 && llevel < 255) {
ff_expand_buffer[len++] = (char_u)llevel;
- else if ((char_u *)errpt != wc_part && llevel == 0)
- /* restrict is 0 -> remove already added '**' */
+ } else if ((char_u *)errpt != wc_part && llevel == 0) {
+ // restrict is 0 -> remove already added '**'
len -= 2;
- else
+ } else {
ff_expand_buffer[len++] = FF_MAX_STAR_STAR_EXPAND;
+ }
wc_part = (char_u *)errpt;
if (*wc_part != NUL && !vim_ispathsep(*wc_part)) {
EMSG2(_(
- "E343: Invalid path: '**[number]' must be at the end of the path or be followed by '%s'."),
- PATHSEPSTR);
+ "E343: Invalid path: '**[number]' must be at the end of the path or be followed by '%s'."),
+ PATHSEPSTR);
goto error_return;
}
- } else
+ } else {
ff_expand_buffer[len++] = *wc_part++;
+ }
}
ff_expand_buffer[len] = NUL;
search_ctx->ffsc_wc_path = vim_strsave(ff_expand_buffer);
- } else
+ } else {
search_ctx->ffsc_fix_path = vim_strsave(path);
+ }
if (search_ctx->ffsc_start_dir == NULL) {
/* store the fix part as startdir.
@@ -458,7 +459,7 @@ vim_findfile_init (
search_ctx->ffsc_fix_path[0] = NUL;
}
- /* create an absolute path */
+ // create an absolute path
if (STRLEN(search_ctx->ffsc_start_dir)
+ STRLEN(search_ctx->ffsc_fix_path) + 3 >= MAXPATHL) {
EMSG(_(e_pathtoolong));
@@ -505,8 +506,8 @@ vim_findfile_init (
}
sptr = ff_create_stack_element(ff_expand_buffer,
- search_ctx->ffsc_wc_path,
- level, 0);
+ search_ctx->ffsc_wc_path,
+ level, 0);
ff_push(search_ctx, sptr);
search_ctx->ffsc_file_to_search = vim_strsave(filename);
@@ -527,7 +528,7 @@ error_return:
*/
char_u *vim_findfile_stopdir(char_u *buf)
{
- char_u *r_ptr = buf;
+ char_u *r_ptr = buf;
while (*r_ptr != NUL && *r_ptr != ';') {
if (r_ptr[0] == '\\' && r_ptr[1] == ';') {
@@ -541,8 +542,9 @@ char_u *vim_findfile_stopdir(char_u *buf)
if (*r_ptr == ';') {
*r_ptr = 0;
r_ptr++;
- } else if (*r_ptr == NUL)
+ } else if (*r_ptr == NUL) {
r_ptr = NULL;
+ }
return r_ptr;
}
@@ -551,8 +553,9 @@ char_u *vim_findfile_stopdir(char_u *buf)
*/
void vim_findfile_cleanup(void *ctx)
{
- if (ctx == NULL)
+ if (ctx == NULL) {
return;
+ }
vim_findfile_free_visited(ctx);
ff_clear(ctx);
@@ -573,17 +576,18 @@ void vim_findfile_cleanup(void *ctx)
*/
char_u *vim_findfile(void *search_ctx_arg)
{
- char_u *file_path;
- char_u *rest_of_wildcards;
- char_u *path_end = NULL;
- ff_stack_T *stackp = NULL;
+ char_u *file_path;
+ char_u *rest_of_wildcards;
+ char_u *path_end = NULL;
+ ff_stack_T *stackp = NULL;
size_t len;
- char_u *p;
- char_u *suf;
+ char_u *p;
+ char_u *suf;
ff_search_ctx_T *search_ctx;
- if (search_ctx_arg == NULL)
+ if (search_ctx_arg == NULL) {
return NULL;
+ }
search_ctx = (ff_search_ctx_T *)search_ctx_arg;
@@ -593,24 +597,27 @@ char_u *vim_findfile(void *search_ctx_arg)
*/
file_path = xmalloc(MAXPATHL);
- /* store the end of the start dir -- needed for upward search */
- if (search_ctx->ffsc_start_dir != NULL)
+ // store the end of the start dir -- needed for upward search
+ if (search_ctx->ffsc_start_dir != NULL) {
path_end = &search_ctx->ffsc_start_dir[
- STRLEN(search_ctx->ffsc_start_dir)];
+ STRLEN(search_ctx->ffsc_start_dir)];
+ }
- /* upward search loop */
+ // upward search loop
for (;; ) {
- /* downward search loop */
+ // downward search loop
for (;; ) {
- /* check if user user wants to stop the search*/
+ // check if user user wants to stop the search
os_breakcheck();
- if (got_int)
+ if (got_int) {
break;
+ }
- /* get directory to work on from stack */
+ // get directory to work on from stack
stackp = ff_pop(search_ctx);
- if (stackp == NULL)
+ if (stackp == NULL) {
break;
+ }
/*
* TODO: decide if we leave this test in
@@ -633,10 +640,10 @@ char_u *vim_findfile(void *search_ctx_arg)
*/
if (stackp->ffs_filearray == NULL
&& ff_check_visited(&search_ctx->ffsc_dir_visited_list
- ->ffvl_visited_list,
- stackp->ffs_fix_path
- , stackp->ffs_wc_path
- ) == FAIL) {
+ ->ffvl_visited_list,
+ stackp->ffs_fix_path
+ , stackp->ffs_wc_path
+ ) == FAIL) {
#ifdef FF_VERBOSE
if (p_verbose >= 5) {
verbose_enter_scroll();
@@ -659,7 +666,7 @@ char_u *vim_findfile(void *search_ctx_arg)
}
#endif
- /* check depth */
+ // check depth
if (stackp->ffs_level <= 0) {
ff_free_stack_element(stackp);
continue;
@@ -725,13 +732,14 @@ char_u *vim_findfile(void *search_ctx_arg)
}
if (*p == 0) {
- /* remove '**<numb> from wildcards */
+ // remove '**<numb> from wildcards
STRMOVE(rest_of_wildcards, rest_of_wildcards + 3);
- } else
+ } else {
rest_of_wildcards += 3;
+ }
if (stackp->ffs_star_star_empty == 0) {
- /* if not done before, expand '**' to empty */
+ // if not done before, expand '**' to empty
stackp->ffs_star_star_empty = 1;
dirptrs[1] = stackp->ffs_fix_path;
}
@@ -754,8 +762,9 @@ char_u *vim_findfile(void *search_ctx_arg)
}
file_path[len] = NUL;
- if (vim_ispathsep(*rest_of_wildcards))
+ if (vim_ispathsep(*rest_of_wildcards)) {
rest_of_wildcards++;
+ }
}
/*
@@ -766,23 +775,25 @@ char_u *vim_findfile(void *search_ctx_arg)
stackp->ffs_filearray = xmalloc(sizeof(char *));
stackp->ffs_filearray[0] = vim_strsave(dirptrs[0]);
stackp->ffs_filearray_size = 1;
- } else
+ } else {
/* Add EW_NOTWILD because the expanded path may contain
* wildcard characters that are to be taken literally.
* This is a bit of a hack. */
expand_wildcards((dirptrs[1] == NULL) ? 1 : 2, dirptrs,
- &stackp->ffs_filearray_size,
- &stackp->ffs_filearray,
- EW_DIR|EW_ADDSLASH|EW_SILENT|EW_NOTWILD);
+ &stackp->ffs_filearray_size,
+ &stackp->ffs_filearray,
+ EW_DIR|EW_ADDSLASH|EW_SILENT|EW_NOTWILD);
+ }
stackp->ffs_filearray_cur = 0;
stackp->ffs_stage = 0;
- } else
+ } else {
rest_of_wildcards = &stackp->ffs_wc_path[
- STRLEN(stackp->ffs_wc_path)];
+ STRLEN(stackp->ffs_wc_path)];
+ }
if (stackp->ffs_stage == 0) {
- /* this is the first time we work on this directory */
+ // this is the first time we work on this directory
if (*rest_of_wildcards == NUL) {
/*
* We don't have further wildcards to expand, so we have to
@@ -791,9 +802,9 @@ char_u *vim_findfile(void *search_ctx_arg)
for (int i = stackp->ffs_filearray_cur;
i < stackp->ffs_filearray_size; ++i) {
if (!path_with_url((char *)stackp->ffs_filearray[i])
- && !os_isdir(stackp->ffs_filearray[i]))
- continue; /* not a directory */
-
+ && !os_isdir(stackp->ffs_filearray[i])) {
+ continue; // not a directory
+ }
// prepare the filename to be checked for existence below
if (STRLEN(stackp->ffs_filearray[i]) + 1
+ STRLEN(search_ctx->ffsc_file_to_search) >= MAXPATHL) {
@@ -812,12 +823,13 @@ char_u *vim_findfile(void *search_ctx_arg)
* from 'suffixesadd'.
*/
len = STRLEN(file_path);
- if (search_ctx->ffsc_tagfile)
+ if (search_ctx->ffsc_tagfile) {
suf = (char_u *)"";
- else
+ } else {
suf = curbuf->b_p_sua;
+ }
for (;; ) {
- /* if file exists and we didn't already find it */
+ // if file exists and we didn't already find it
if ((path_with_url((char *)file_path)
|| (os_path_exists(file_path)
&& (search_ctx->ffsc_find_what
@@ -826,19 +838,17 @@ char_u *vim_findfile(void *search_ctx_arg)
== FINDFILE_DIR)
== os_isdir(file_path)))))
#ifndef FF_VERBOSE
- && (ff_check_visited(
- &search_ctx->ffsc_visited_list->ffvl_visited_list,
- file_path
- , (char_u *)""
- ) == OK)
+ && (ff_check_visited(&search_ctx->ffsc_visited_list->ffvl_visited_list,
+ file_path
+ , (char_u *)""
+ ) == OK)
#endif
) {
#ifdef FF_VERBOSE
- if (ff_check_visited(
- &search_ctx->ffsc_visited_list->ffvl_visited_list,
- file_path
- , (char_u *)""
- ) == FAIL) {
+ if (ff_check_visited(&search_ctx->ffsc_visited_list->ffvl_visited_list,
+ file_path
+ , (char_u *)""
+ ) == FAIL) {
if (p_verbose >= 5) {
verbose_enter_scroll();
smsg("Already: %s", file_path);
@@ -849,19 +859,21 @@ char_u *vim_findfile(void *search_ctx_arg)
}
#endif
- /* push dir to examine rest of subdirs later */
+ // push dir to examine rest of subdirs later
assert(i < UCHAR_MAX - 1);
stackp->ffs_filearray_cur = (char_u)(i + 1);
ff_push(search_ctx, stackp);
- if (!path_with_url((char *)file_path))
+ if (!path_with_url((char *)file_path)) {
simplify_filename(file_path);
+ }
if (os_dirname(ff_expand_buffer, MAXPATHL)
== OK) {
p = path_shorten_fname(file_path,
- ff_expand_buffer);
- if (p != NULL)
+ ff_expand_buffer);
+ if (p != NULL) {
STRMOVE(file_path, p);
+ }
}
#ifdef FF_VERBOSE
if (p_verbose >= 5) {
@@ -874,12 +886,13 @@ char_u *vim_findfile(void *search_ctx_arg)
return file_path;
}
- /* Not found or found already, try next suffix. */
- if (*suf == NUL)
+ // Not found or found already, try next suffix.
+ if (*suf == NUL) {
break;
+ }
assert(MAXPATHL >= len);
copy_option_part(&suf, file_path + len,
- MAXPATHL - len, ",");
+ MAXPATHL - len, ",");
}
}
} else {
@@ -889,14 +902,13 @@ char_u *vim_findfile(void *search_ctx_arg)
*/
for (int i = stackp->ffs_filearray_cur;
i < stackp->ffs_filearray_size; ++i) {
- if (!os_isdir(stackp->ffs_filearray[i]))
- continue; /* not a directory */
-
+ if (!os_isdir(stackp->ffs_filearray[i])) {
+ continue; // not a directory
+ }
ff_push(search_ctx,
- ff_create_stack_element(
- stackp->ffs_filearray[i],
- rest_of_wildcards,
- stackp->ffs_level - 1, 0));
+ ff_create_stack_element(stackp->ffs_filearray[i],
+ rest_of_wildcards,
+ stackp->ffs_level - 1, 0));
}
}
stackp->ffs_filearray_cur = 0;
@@ -911,19 +923,20 @@ char_u *vim_findfile(void *search_ctx_arg)
for (int i = stackp->ffs_filearray_cur;
i < stackp->ffs_filearray_size; ++i) {
if (fnamecmp(stackp->ffs_filearray[i],
- stackp->ffs_fix_path) == 0)
- continue; /* don't repush same directory */
- if (!os_isdir(stackp->ffs_filearray[i]))
- continue; /* not a directory */
+ stackp->ffs_fix_path) == 0) {
+ continue; // don't repush same directory
+ }
+ if (!os_isdir(stackp->ffs_filearray[i])) {
+ continue; // not a directory
+ }
ff_push(search_ctx,
- ff_create_stack_element(stackp->ffs_filearray[i],
- stackp->ffs_wc_path, stackp->ffs_level - 1, 1));
+ ff_create_stack_element(stackp->ffs_filearray[i],
+ stackp->ffs_wc_path, stackp->ffs_level - 1, 1));
}
}
- /* we are done with the current directory */
+ // we are done with the current directory
ff_free_stack_element(stackp);
-
}
/* If we reached this, we didn't find anything downwards.
@@ -931,26 +944,30 @@ char_u *vim_findfile(void *search_ctx_arg)
*/
if (search_ctx->ffsc_start_dir
&& search_ctx->ffsc_stopdirs_v != NULL && !got_int) {
- ff_stack_T *sptr;
+ ff_stack_T *sptr;
- /* is the last starting directory in the stop list? */
+ // is the last starting directory in the stop list?
if (ff_path_in_stoplist(search_ctx->ffsc_start_dir,
- (int)(path_end - search_ctx->ffsc_start_dir),
- search_ctx->ffsc_stopdirs_v) == TRUE)
+ (int)(path_end - search_ctx->ffsc_start_dir),
+ search_ctx->ffsc_stopdirs_v) == TRUE) {
break;
+ }
- /* cut of last dir */
+ // cut of last dir
while (path_end > search_ctx->ffsc_start_dir
- && vim_ispathsep(*path_end))
+ && vim_ispathsep(*path_end)) {
path_end--;
+ }
while (path_end > search_ctx->ffsc_start_dir
- && !vim_ispathsep(path_end[-1]))
+ && !vim_ispathsep(path_end[-1])) {
path_end--;
+ }
*path_end = 0;
path_end--;
- if (*search_ctx->ffsc_start_dir == 0)
+ if (*search_ctx->ffsc_start_dir == 0) {
break;
+ }
if (STRLEN(search_ctx->ffsc_start_dir) + 1
+ STRLEN(search_ctx->ffsc_fix_path) >= MAXPATHL) {
@@ -962,12 +979,13 @@ char_u *vim_findfile(void *search_ctx_arg)
}
STRCAT(file_path, search_ctx->ffsc_fix_path);
- /* create a new stack entry */
+ // create a new stack entry
sptr = ff_create_stack_element(file_path,
- search_ctx->ffsc_wc_path, search_ctx->ffsc_level, 0);
+ search_ctx->ffsc_wc_path, search_ctx->ffsc_level, 0);
ff_push(search_ctx, sptr);
- } else
+ } else {
break;
+ }
}
fail:
@@ -983,8 +1001,9 @@ void vim_findfile_free_visited(void *search_ctx_arg)
{
ff_search_ctx_T *search_ctx;
- if (search_ctx_arg == NULL)
+ if (search_ctx_arg == NULL) {
return;
+ }
search_ctx = (ff_search_ctx_T *)search_ctx_arg;
vim_findfile_free_visited_list(&search_ctx->ffsc_visited_lists_list);
@@ -1023,11 +1042,12 @@ static void ff_free_visited_list(ff_visited_T *vl)
* Returns the already visited list for the given filename. If none is found it
* allocates a new one.
*/
-static ff_visited_list_hdr_T *ff_get_visited_list(char_u *filename, ff_visited_list_hdr_T **list_headp)
+static ff_visited_list_hdr_T *ff_get_visited_list(char_u *filename,
+ ff_visited_list_hdr_T **list_headp)
{
- ff_visited_list_hdr_T *retptr = NULL;
+ ff_visited_list_hdr_T *retptr = NULL;
- /* check if a visited list for the given filename exists */
+ // check if a visited list for the given filename exists
if (*list_headp != NULL) {
retptr = *list_headp;
while (retptr != NULL) {
@@ -1115,7 +1135,7 @@ static bool ff_wc_equal(char_u *s1, char_u *s2)
*/
static int ff_check_visited(ff_visited_T **visited_list, char_u *fname, char_u *wc_path)
{
- ff_visited_T *vp;
+ ff_visited_T *vp;
bool url = false;
FileID file_id;
@@ -1131,7 +1151,7 @@ static int ff_check_visited(ff_visited_T **visited_list, char_u *fname, char_u *
}
}
- /* check against list of already visited files */
+ // check against list of already visited files
for (vp = *visited_list; vp != NULL; vp = vp->ffv_next) {
if ((url && fnamecmp(vp->ffv_fname, ff_expand_buffer) == 0)
|| (!url && vp->file_id_valid
@@ -1158,10 +1178,11 @@ static int ff_check_visited(ff_visited_T **visited_list, char_u *fname, char_u *
STRCPY(vp->ffv_fname, ff_expand_buffer);
}
- if (wc_path != NULL)
+ if (wc_path != NULL) {
vp->ffv_wc_path = vim_strsave(wc_path);
- else
+ } else {
vp->ffv_wc_path = NULL;
+ }
vp->ffv_next = *visited_list;
*visited_list = vp;
@@ -1172,7 +1193,8 @@ static int ff_check_visited(ff_visited_T **visited_list, char_u *fname, char_u *
/*
* create stack element from given path pieces
*/
-static ff_stack_T *ff_create_stack_element(char_u *fix_part, char_u *wc_part, int level, int star_star_empty)
+static ff_stack_T *ff_create_stack_element(char_u *fix_part, char_u *wc_part, int level,
+ int star_star_empty)
{
ff_stack_T *new = xmalloc(sizeof(ff_stack_T));
@@ -1184,13 +1206,15 @@ static ff_stack_T *ff_create_stack_element(char_u *fix_part, char_u *wc_part, in
new->ffs_level = level;
new->ffs_star_star_empty = star_star_empty;
- /* the following saves NULL pointer checks in vim_findfile */
- if (fix_part == NULL)
+ // the following saves NULL pointer checks in vim_findfile
+ if (fix_part == NULL) {
fix_part = (char_u *)"";
+ }
new->ffs_fix_path = vim_strsave(fix_part);
- if (wc_part == NULL)
+ if (wc_part == NULL) {
wc_part = (char_u *)"";
+ }
new->ffs_wc_path = vim_strsave(wc_part);
return new;
@@ -1215,11 +1239,12 @@ static void ff_push(ff_search_ctx_T *search_ctx, ff_stack_T *stack_ptr)
*/
static ff_stack_T *ff_pop(ff_search_ctx_T *search_ctx)
{
- ff_stack_T *sptr;
+ ff_stack_T *sptr;
sptr = search_ctx->ffsc_stack_ptr;
- if (search_ctx->ffsc_stack_ptr != NULL)
+ if (search_ctx->ffsc_stack_ptr != NULL) {
search_ctx->ffsc_stack_ptr = search_ctx->ffsc_stack_ptr->ffs_prev;
+ }
return sptr;
}
@@ -1249,11 +1274,12 @@ static void ff_free_stack_element(ff_stack_T *const stack_ptr)
*/
static void ff_clear(ff_search_ctx_T *search_ctx)
{
- ff_stack_T *sptr;
+ ff_stack_T *sptr;
- /* clear up stack */
- while ((sptr = ff_pop(search_ctx)) != NULL)
+ // clear up stack
+ while ((sptr = ff_pop(search_ctx)) != NULL) {
ff_free_stack_element(sptr);
+ }
xfree(search_ctx->ffsc_file_to_search);
xfree(search_ctx->ffsc_start_dir);
@@ -1271,7 +1297,7 @@ static void ff_clear(ff_search_ctx_T *search_ctx)
}
search_ctx->ffsc_stopdirs_v = NULL;
- /* reset everything */
+ // reset everything
search_ctx->ffsc_file_to_search = NULL;
search_ctx->ffsc_start_dir = NULL;
search_ctx->ffsc_fix_path = NULL;
@@ -1287,13 +1313,15 @@ static int ff_path_in_stoplist(char_u *path, int path_len, char_u **stopdirs_v)
{
int i = 0;
- /* eat up trailing path separators, except the first */
- while (path_len > 1 && vim_ispathsep(path[path_len - 1]))
+ // eat up trailing path separators, except the first
+ while (path_len > 1 && vim_ispathsep(path[path_len - 1])) {
path_len--;
+ }
- /* if no path consider it as match */
- if (path_len == 0)
+ // if no path consider it as match
+ if (path_len == 0) {
return TRUE;
+ }
for (i = 0; stopdirs_v[i] != NULL; i++) {
if ((int)STRLEN(stopdirs_v[i]) > path_len) {
@@ -1302,49 +1330,46 @@ static int ff_path_in_stoplist(char_u *path, int path_len, char_u **stopdirs_v)
* '/home/r' would also match '/home/rks'
*/
if (fnamencmp(stopdirs_v[i], path, path_len) == 0
- && vim_ispathsep(stopdirs_v[i][path_len]))
+ && vim_ispathsep(stopdirs_v[i][path_len])) {
return TRUE;
+ }
} else {
- if (fnamecmp(stopdirs_v[i], path) == 0)
+ if (fnamecmp(stopdirs_v[i], path) == 0) {
return TRUE;
+ }
}
}
return FALSE;
}
-/*
- * Find the file name "ptr[len]" in the path. Also finds directory names.
- *
- * On the first call set the parameter 'first' to TRUE to initialize
- * the search. For repeating calls to FALSE.
- *
- * Repeating calls will return other files called 'ptr[len]' from the path.
- *
- * Only on the first call 'ptr' and 'len' are used. For repeating calls they
- * don't need valid values.
- *
- * If nothing found on the first call the option FNAME_MESS will issue the
- * message:
- * 'Can't find file "<file>" in path'
- * On repeating calls:
- * 'No more file "<file>" found in path'
- *
- * options:
- * FNAME_MESS give error message when not found
- *
- * Uses NameBuff[]!
- *
- * Returns an allocated string for the file name. NULL for error.
- *
- */
-char_u *
-find_file_in_path (
- char_u *ptr, /* file name */
- size_t len, /* length of file name */
- int options,
- int first, /* use count'th matching file name */
- char_u *rel_fname /* file name searching relative to */
-)
+/// Find the file name "ptr[len]" in the path. Also finds directory names.
+///
+/// On the first call set the parameter 'first' to TRUE to initialize
+/// the search. For repeating calls to FALSE.
+///
+/// Repeating calls will return other files called 'ptr[len]' from the path.
+///
+/// Only on the first call 'ptr' and 'len' are used. For repeating calls they
+/// don't need valid values.
+///
+/// If nothing found on the first call the option FNAME_MESS will issue the
+/// message:
+/// 'Can't find file "<file>" in path'
+/// On repeating calls:
+/// 'No more file "<file>" found in path'
+///
+/// options:
+/// FNAME_MESS give error message when not found
+///
+/// Uses NameBuff[]!
+///
+/// @param ptr file name
+/// @param len length of file name
+/// @param first use count'th matching file name
+/// @param rel_fname file name searching relative to
+///
+/// @return an allocated string for the file name. NULL for error.
+char_u *find_file_in_path(char_u *ptr, size_t len, int options, int first, char_u *rel_fname)
{
return find_file_in_path_option(ptr, len, options, first,
(*curbuf->b_p_path == NUL
@@ -1353,8 +1378,8 @@ find_file_in_path (
FINDFILE_BOTH, rel_fname, curbuf->b_p_sua);
}
-static char_u *ff_file_to_find = NULL;
-static void *fdip_search_ctx = NULL;
+static char_u *ff_file_to_find = NULL;
+static void *fdip_search_ctx = NULL;
#if defined(EXITFREE)
void free_findfile(void)
@@ -1366,46 +1391,41 @@ void free_findfile(void)
#endif
-/*
- * Find the directory name "ptr[len]" in the path.
- *
- * options:
- * FNAME_MESS give error message when not found
- * FNAME_UNESC unescape backslashes
- *
- * Uses NameBuff[]!
- *
- * Returns an allocated string for the file name. NULL for error.
- */
-char_u *
-find_directory_in_path (
- char_u *ptr, /* file name */
- size_t len, /* length of file name */
- int options,
- char_u *rel_fname /* file name searching relative to */
-)
+/// Find the directory name "ptr[len]" in the path.
+///
+/// options:
+/// FNAME_MESS give error message when not found
+/// FNAME_UNESC unescape backslashes
+///
+/// Uses NameBuff[]!
+///
+/// @param ptr file name
+/// @param len length of file name
+/// @param rel_fname file name searching relative to
+///
+/// @return an allocated string for the file name. NULL for error.
+char_u *find_directory_in_path(char_u *ptr, size_t len, int options, char_u *rel_fname)
{
return find_file_in_path_option(ptr, len, options, TRUE, p_cdpath,
FINDFILE_DIR, rel_fname, (char_u *)"");
}
-char_u *
-find_file_in_path_option (
- char_u *ptr, /* file name */
- size_t len, /* length of file name */
- int options,
- int first, /* use count'th matching file name */
- char_u *path_option, /* p_path or p_cdpath */
- int find_what, /* FINDFILE_FILE, _DIR or _BOTH */
- char_u *rel_fname, /* file name we are looking relative to. */
- char_u *suffixes /* list of suffixes, 'suffixesadd' option */
-)
+/// @param ptr file name
+/// @param len length of file name
+/// @param first use count'th matching file name
+/// @param path_option p_path or p_cdpath
+/// @param find_what FINDFILE_FILE, _DIR or _BOTH
+/// @param rel_fname file name we are looking relative to.
+/// @param suffixes list of suffixes, 'suffixesadd' option
+char_u *find_file_in_path_option(char_u *ptr, size_t len, int options, int first,
+ char_u *path_option, int find_what, char_u *rel_fname,
+ char_u *suffixes)
{
- static char_u *dir;
+ static char_u *dir;
static int did_findfile_init = FALSE;
char_u save_char;
- char_u *file_name = NULL;
- char_u *buf = NULL;
+ char_u *file_name = NULL;
+ char_u *buf = NULL;
int rel_to_curdir;
if (rel_fname != NULL && path_with_url((const char *)rel_fname)) {
@@ -1414,7 +1434,7 @@ find_file_in_path_option (
}
if (first == TRUE) {
- /* copy file name into NameBuff, expanding environment variables */
+ // copy file name into NameBuff, expanding environment variables
save_char = ptr[len];
ptr[len] = NUL;
expand_env_esc(ptr, NameBuff, MAXPATHL, false, true, NULL);
@@ -1485,11 +1505,12 @@ find_file_in_path_option (
&& (find_what == FINDFILE_BOTH
|| ((find_what == FINDFILE_DIR)
== os_isdir(NameBuff))))) {
- file_name = vim_strsave(NameBuff);
- goto theend;
+ file_name = vim_strsave(NameBuff);
+ goto theend;
}
- if (*buf == NUL)
+ if (*buf == NUL) {
break;
+ }
assert(MAXPATHL >= l);
copy_option_part(&buf, NameBuff + l, MAXPATHL - l, ",");
}
@@ -1502,7 +1523,7 @@ find_file_in_path_option (
* Otherwise continue to find the next match.
*/
if (first == TRUE) {
- /* vim_findfile_free_visited can handle a possible NULL pointer */
+ // vim_findfile_free_visited can handle a possible NULL pointer
vim_findfile_free_visited(fdip_search_ctx);
dir = path_option;
did_findfile_init = FALSE;
@@ -1511,12 +1532,13 @@ find_file_in_path_option (
for (;; ) {
if (did_findfile_init) {
file_name = vim_findfile(fdip_search_ctx);
- if (file_name != NULL)
+ if (file_name != NULL) {
break;
+ }
did_findfile_init = FALSE;
} else {
- char_u *r_ptr;
+ char_u *r_ptr;
if (dir == NULL || *dir == NUL) {
/* We searched all paths of the option, now we can
@@ -1528,36 +1550,39 @@ find_file_in_path_option (
buf = xmalloc(MAXPATHL);
- /* copy next path */
+ // copy next path
buf[0] = 0;
copy_option_part(&dir, buf, MAXPATHL, " ,");
- /* get the stopdir string */
+ // get the stopdir string
r_ptr = vim_findfile_stopdir(buf);
fdip_search_ctx = vim_findfile_init(buf, ff_file_to_find,
- r_ptr, 100, FALSE, find_what,
- fdip_search_ctx, FALSE, rel_fname);
- if (fdip_search_ctx != NULL)
+ r_ptr, 100, FALSE, find_what,
+ fdip_search_ctx, FALSE, rel_fname);
+ if (fdip_search_ctx != NULL) {
did_findfile_init = TRUE;
+ }
xfree(buf);
}
}
}
if (file_name == NULL && (options & FNAME_MESS)) {
if (first == TRUE) {
- if (find_what == FINDFILE_DIR)
+ if (find_what == FINDFILE_DIR) {
EMSG2(_("E344: Can't find directory \"%s\" in cdpath"),
- ff_file_to_find);
- else
+ ff_file_to_find);
+ } else {
EMSG2(_("E345: Can't find file \"%s\" in path"),
- ff_file_to_find);
+ ff_file_to_find);
+ }
} else {
- if (find_what == FINDFILE_DIR)
+ if (find_what == FINDFILE_DIR) {
EMSG2(_("E346: No more directory \"%s\" found in cdpath"),
- ff_file_to_find);
- else
+ ff_file_to_find);
+ } else {
EMSG2(_("E347: No more file \"%s\" found in path"),
- ff_file_to_find);
+ ff_file_to_find);
+ }
}
}
@@ -1581,22 +1606,18 @@ void do_autocmd_dirchanged(char *new_dir, CdScope scope, bool changed_window)
char buf[8];
switch (scope) {
- case kCdScopeGlobal: {
- snprintf(buf, sizeof(buf), "global");
- break;
- }
- case kCdScopeTab: {
- snprintf(buf, sizeof(buf), "tab");
- break;
- }
- case kCdScopeWindow: {
- snprintf(buf, sizeof(buf), "window");
- break;
- }
- case kCdScopeInvalid: {
- // Should never happen.
- abort();
- }
+ case kCdScopeGlobal:
+ snprintf(buf, sizeof(buf), "global");
+ break;
+ case kCdScopeTab:
+ snprintf(buf, sizeof(buf), "tab");
+ break;
+ case kCdScopeWindow:
+ snprintf(buf, sizeof(buf), "window");
+ break;
+ case kCdScopeInvalid:
+ // Should never happen.
+ abort();
}
tv_dict_add_str(dict, S_LEN("scope"), buf); // -V614
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 29c29a2884..f5a4efc371 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -5,15 +5,13 @@
#include <assert.h>
#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
#include <stdbool.h>
#include <string.h>
-#include <inttypes.h>
-#include <fcntl.h>
-#include "nvim/vim.h"
-#include "nvim/api/private/handle.h"
+#include "nvim/api/private/helpers.h"
#include "nvim/ascii.h"
-#include "nvim/fileio.h"
#include "nvim/buffer.h"
#include "nvim/buffer_updates.h"
#include "nvim/change.h"
@@ -25,8 +23,10 @@
#include "nvim/ex_cmds.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
+#include "nvim/fileio.h"
#include "nvim/fold.h"
#include "nvim/func_attr.h"
+#include "nvim/garray.h"
#include "nvim/getchar.h"
#include "nvim/hashtab.h"
#include "nvim/iconv.h"
@@ -36,10 +36,13 @@
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
-#include "nvim/garray.h"
#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/option.h"
+#include "nvim/os/input.h"
+#include "nvim/os/os.h"
+#include "nvim/os/os_defs.h"
+#include "nvim/os/time.h"
#include "nvim/os_unix.h"
#include "nvim/path.h"
#include "nvim/quickfix.h"
@@ -47,37 +50,34 @@
#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/sha256.h"
+#include "nvim/shada.h"
#include "nvim/state.h"
#include "nvim/strings.h"
+#include "nvim/types.h"
#include "nvim/ui.h"
#include "nvim/ui_compositor.h"
-#include "nvim/types.h"
#include "nvim/undo.h"
+#include "nvim/vim.h"
#include "nvim/window.h"
-#include "nvim/shada.h"
-#include "nvim/os/os.h"
-#include "nvim/os/os_defs.h"
-#include "nvim/os/time.h"
-#include "nvim/os/input.h"
-#define BUFSIZE 8192 /* size of normal write buffer */
-#define SMBUFSIZE 256 /* size of emergency write buffer */
+#define BUFSIZE 8192 // size of normal write buffer
+#define SMBUFSIZE 256 // size of emergency write buffer
// For compatibility with libuv < 1.20.0 (tested on 1.18.0)
#ifndef UV_FS_COPYFILE_FICLONE
-#define UV_FS_COPYFILE_FICLONE 0
+# define UV_FS_COPYFILE_FICLONE 0
#endif
#define HAS_BW_FLAGS
-#define FIO_LATIN1 0x01 /* convert Latin1 */
-#define FIO_UTF8 0x02 /* convert UTF-8 */
-#define FIO_UCS2 0x04 /* convert UCS-2 */
-#define FIO_UCS4 0x08 /* convert UCS-4 */
-#define FIO_UTF16 0x10 /* convert UTF-16 */
-#define FIO_ENDIAN_L 0x80 /* little endian */
-#define FIO_NOCONVERT 0x2000 /* skip encoding conversion */
-#define FIO_UCSBOM 0x4000 /* check for BOM at start of file */
-#define FIO_ALL -1 /* allow all formats */
+#define FIO_LATIN1 0x01 // convert Latin1
+#define FIO_UTF8 0x02 // convert UTF-8
+#define FIO_UCS2 0x04 // convert UCS-2
+#define FIO_UCS4 0x08 // convert UCS-4
+#define FIO_UTF16 0x10 // convert UTF-16
+#define FIO_ENDIAN_L 0x80 // little endian
+#define FIO_NOCONVERT 0x2000 // skip encoding conversion
+#define FIO_UCSBOM 0x4000 // check for BOM at start of file
+#define FIO_ALL -1 // allow all formats
/* When converting, a read() or write() may leave some bytes to be converted
* for the next call. The value is guessed... */
@@ -92,7 +92,7 @@
*/
struct bw_info {
int bw_fd; // file descriptor
- char_u *bw_buf; // buffer with data to be written
+ char_u *bw_buf; // buffer with data to be written
int bw_len; // length of data
#ifdef HAS_BW_FLAGS
int bw_flags; // FIO_ flags
@@ -100,22 +100,21 @@ struct bw_info {
char_u bw_rest[CONV_RESTLEN]; // not converted bytes
int bw_restlen; // nr of bytes in bw_rest[]
int bw_first; // first write call
- char_u *bw_conv_buf; // buffer for writing converted chars
+ char_u *bw_conv_buf; // buffer for writing converted chars
int bw_conv_buflen; // size of bw_conv_buf
int bw_conv_error; // set for conversion error
linenr_T bw_conv_error_lnum; // first line with error or zero
linenr_T bw_start_lnum; // line number at start of buffer
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
iconv_t bw_iconv_fd; // descriptor for iconv() or -1
-# endif
+#endif
};
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "fileio.c.generated.h"
#endif
-static char *e_auchangedbuf = N_(
- "E812: Autocommands changed buffer or buffer name");
+static char *e_auchangedbuf = N_("E812: Autocommands changed buffer or buffer name");
void filemess(buf_T *buf, char_u *name, char_u *s, int attr)
{
@@ -131,56 +130,50 @@ void filemess(buf_T *buf, char_u *name, char_u *s, int attr)
// For further ones overwrite the previous one, reset msg_scroll before
// calling filemess().
msg_scroll_save = msg_scroll;
- if (shortmess(SHM_OVERALL) && !exiting && p_verbose == 0)
+ if (shortmess(SHM_OVERALL) && !exiting && p_verbose == 0) {
msg_scroll = FALSE;
- if (!msg_scroll) /* wait a bit when overwriting an error msg */
- check_for_delay(FALSE);
+ }
+ if (!msg_scroll) { // wait a bit when overwriting an error msg
+ check_for_delay(false);
+ }
msg_start();
msg_scroll = msg_scroll_save;
- msg_scrolled_ign = TRUE;
- /* may truncate the message to avoid a hit-return prompt */
+ msg_scrolled_ign = true;
+ // may truncate the message to avoid a hit-return prompt
msg_outtrans_attr(msg_may_trunc(FALSE, IObuff), attr);
msg_clr_eos();
ui_flush();
- msg_scrolled_ign = FALSE;
+ 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.
- * 2. Each block is filled with characters from the file with a single read().
- * 3. The lines are inserted in the buffer with ml_append().
- *
- * (caller must check that fname != NULL, unless READ_STDIN is used)
- *
- * "lines_to_skip" is the number of lines that must be skipped
- * "lines_to_read" is the number of lines that are appended
- * When not recovering lines_to_skip is 0 and lines_to_read MAXLNUM.
- *
- * flags:
- * READ_NEW starting to edit a new buffer
- * READ_FILTER reading filter output
- * READ_STDIN read from stdin instead of a file
- * READ_BUFFER read from curbuf instead of a file (converting after reading
- * stdin)
- * READ_DUMMY read into a dummy buffer (to check if file contents changed)
- * READ_KEEP_UNDO don't clear undo info or read it from a file
- * READ_FIFO read from fifo/socket instead of a file
- *
- * return FAIL for failure, NOTDONE for directory (failure), or OK
- */
-int
-readfile(
- char_u *fname,
- char_u *sfname,
- linenr_T from,
- linenr_T lines_to_skip,
- linenr_T lines_to_read,
- exarg_T *eap, // can be NULL!
- int flags
-)
+/// Read lines from file "fname" into the buffer after line "from".
+///
+/// 1. We allocate blocks with try_malloc, as big as possible.
+/// 2. Each block is filled with characters from the file with a single read().
+/// 3. The lines are inserted in the buffer with ml_append().
+///
+/// (caller must check that fname != NULL, unless READ_STDIN is used)
+///
+/// "lines_to_skip" is the number of lines that must be skipped
+/// "lines_to_read" is the number of lines that are appended
+/// When not recovering lines_to_skip is 0 and lines_to_read MAXLNUM.
+///
+/// flags:
+/// READ_NEW starting to edit a new buffer
+/// READ_FILTER reading filter output
+/// READ_STDIN read from stdin instead of a file
+/// READ_BUFFER read from curbuf instead of a file (converting after reading
+/// stdin)
+/// READ_DUMMY read into a dummy buffer (to check if file contents changed)
+/// READ_KEEP_UNDO don't clear undo info or read it from a file
+/// READ_FIFO read from fifo/socket instead of a file
+///
+/// @param eap can be NULL!
+///
+/// @return FAIL for failure, NOTDONE for directory (failure), or OK
+int readfile(char_u *fname, char_u *sfname, linenr_T from, linenr_T lines_to_skip,
+ linenr_T lines_to_read, exarg_T *eap, int flags)
{
int fd = 0;
int newfile = (flags & READ_NEW);
@@ -191,35 +184,34 @@ readfile(
int read_fifo = (flags & READ_FIFO);
int set_options = newfile || read_buffer
|| (eap != NULL && eap->read_edit);
- linenr_T read_buf_lnum = 1; /* next line to read from curbuf */
- colnr_T read_buf_col = 0; /* next char to read from this line */
+ linenr_T read_buf_lnum = 1; // next line to read from curbuf
+ colnr_T read_buf_col = 0; // next char to read from this line
char_u c;
linenr_T lnum = from;
- char_u *ptr = NULL; /* pointer into read buffer */
- char_u *buffer = NULL; /* read buffer */
- char_u *new_buffer = NULL; /* init to shut up gcc */
- char_u *line_start = NULL; /* init to shut up gcc */
- int wasempty; /* buffer was empty before reading */
+ char_u *ptr = NULL; // pointer into read buffer
+ char_u *buffer = NULL; // read buffer
+ char_u *new_buffer = NULL; // init to shut up gcc
+ char_u *line_start = NULL; // init to shut up gcc
+ int wasempty; // buffer was empty before reading
colnr_T len;
long size = 0;
uint8_t *p = NULL;
off_T filesize = 0;
- int skip_read = false;
+ bool skip_read = false;
context_sha256_T sha_ctx;
int read_undo_file = false;
int split = 0; // number of split lines
linenr_T linecnt;
- int error = FALSE; /* errors encountered */
- int ff_error = EOL_UNKNOWN; /* file format with errors */
- long linerest = 0; /* remaining chars in line */
+ bool error = false; // errors encountered
+ int ff_error = EOL_UNKNOWN; // file format with errors
+ long linerest = 0; // remaining chars in line
int perm = 0;
#ifdef UNIX
- int swap_mode = -1; /* protection bits for swap file */
+ int swap_mode = -1; // protection bits for swap file
#endif
int fileformat = 0; // end-of-line format
bool keep_fileformat = false;
FileInfo file_info;
- int file_readonly;
linenr_T skip_count = 0;
linenr_T read_count = 0;
int msg_save = msg_scroll;
@@ -234,33 +226,32 @@ readfile(
int bad_char_behavior = BAD_REPLACE;
/* BAD_KEEP, BAD_DROP or character to
* replace with */
- char_u *tmpname = NULL; /* name of 'charconvert' output file */
+ char_u *tmpname = NULL; // name of 'charconvert' output file
int fio_flags = 0;
- char_u *fenc; // fileencoding to use
+ char_u *fenc; // fileencoding to use
bool fenc_alloced; // fenc_next is in allocated memory
- char_u *fenc_next = NULL; // next item in 'fencs' or NULL
+ char_u *fenc_next = NULL; // next item in 'fencs' or NULL
bool advance_fenc = false;
long real_size = 0;
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
iconv_t iconv_fd = (iconv_t)-1; // descriptor for iconv() or -1
- int did_iconv = false; // TRUE when iconv() failed and trying
+ bool did_iconv = false; // true when iconv() failed and trying
// 'charconvert' next
-# endif
- int converted = FALSE; /* TRUE if conversion done */
- int notconverted = FALSE; /* TRUE if conversion wanted but it
- wasn't possible */
+#endif
+ bool converted = false; // true if conversion done
+ bool notconverted = false; // true if conversion wanted but it wasn't possible
char_u conv_rest[CONV_RESTLEN];
- int conv_restlen = 0; /* nr of bytes in conv_rest[] */
- buf_T *old_curbuf;
- char_u *old_b_ffname;
- char_u *old_b_fname;
+ int conv_restlen = 0; // nr of bytes in conv_rest[]
+ buf_T *old_curbuf;
+ char_u *old_b_ffname;
+ char_u *old_b_fname;
int using_b_ffname;
int using_b_fname;
static char *msg_is_a_directory = N_("is a directory");
au_did_filetype = false; // reset before triggering any autocommands
- curbuf->b_no_eol_lnum = 0; /* in case it was set by the previous read */
+ curbuf->b_no_eol_lnum = 0; // in case it was set by the previous read
/*
* If there is no file name yet, use the one for the read file.
@@ -273,8 +264,9 @@ readfile(
&& fname != NULL
&& vim_strchr(p_cpo, CPO_FNAMER) != NULL
&& !(flags & READ_DUMMY)) {
- if (set_rw_fname(fname, sfname) == FAIL)
+ if (set_rw_fname(fname, sfname) == FAIL) {
return FAIL;
+ }
}
/* Remember the initial values of curbuf, curbuf->b_ffname and
@@ -290,10 +282,10 @@ readfile(
/* After reading a file the cursor line changes but we don't want to
* display the line. */
- ex_no_reprint = TRUE;
+ ex_no_reprint = true;
- /* don't display the file info for another buffer now */
- need_fileinfo = FALSE;
+ // don't display the file info for another buffer now
+ need_fileinfo = false;
// For Unix: Use the short file name whenever possible.
// Avoids problems with networks and when directory names are changed.
@@ -315,7 +307,7 @@ readfile(
pos = curbuf->b_op_start;
- /* Set '[ mark to the line above where the lines go (line 1 if zero). */
+ // Set '[ mark to the line above where the lines go (line 1 if zero).
curbuf->b_op_start.lnum = ((from == 0) ? 1 : from);
curbuf->b_op_start.col = 0;
@@ -346,11 +338,11 @@ readfile(
curbuf->b_op_start = pos;
}
- if ((shortmess(SHM_OVER) || curbuf->b_help) && p_verbose == 0)
- msg_scroll = FALSE; /* overwrite previous file message */
- else
- msg_scroll = TRUE; /* don't overwrite previous file message */
-
+ if ((shortmess(SHM_OVER) || curbuf->b_help) && p_verbose == 0) {
+ msg_scroll = FALSE; // overwrite previous file message
+ } else {
+ msg_scroll = TRUE; // don't overwrite previous file message
+ }
// If the name is too long we might crash further on, quit here.
if (fname != NULL && *fname != NUL) {
size_t namelen = STRLEN(fname);
@@ -381,10 +373,10 @@ readfile(
if (perm >= 0 && !S_ISREG(perm) // not a regular file ...
&& !S_ISFIFO(perm) // ... or fifo
&& !S_ISSOCK(perm) // ... or socket
-# ifdef OPEN_CHR_FILES
+#ifdef OPEN_CHR_FILES
&& !(S_ISCHR(perm) && is_dev_fd_file(fname))
// ... or a character special file named /dev/fd/<n>
-# endif
+#endif
) {
if (S_ISDIR(perm)) {
filemess(curbuf, fname, (char_u *)_(msg_is_a_directory), 0);
@@ -397,7 +389,7 @@ readfile(
}
}
- /* Set default or forced 'fileformat' and 'binary'. */
+ // Set default or forced 'fileformat' and 'binary'.
set_file_options(set_options, eap);
/*
@@ -407,8 +399,9 @@ readfile(
* Only set/reset b_p_ro when BF_CHECK_RO is set.
*/
check_readonly = (newfile && (curbuf->b_flags & BF_CHECK_RO));
- if (check_readonly && !readonlymode)
+ if (check_readonly && !readonlymode) {
curbuf->b_p_ro = FALSE;
+ }
if (newfile && !read_stdin && !read_buffer && !read_fifo) {
// Remember time of file.
@@ -442,7 +435,7 @@ readfile(
}
// Check readonly.
- file_readonly = false;
+ bool file_readonly = false;
if (!read_buffer && !read_stdin) {
if (!newfile || readonlymode || !(perm & 0222)
|| !os_file_is_writable((char *)fname)) {
@@ -466,7 +459,7 @@ readfile(
* "nofile" or "nowrite" buffer type. */
if (!bt_dontwrite(curbuf)) {
check_need_swap(newfile);
- /* SwapExists autocommand may mess things up */
+ // SwapExists autocommand may mess things up
if (curbuf != old_curbuf
|| (using_b_ffname
&& (old_b_ffname != curbuf->b_ffname))
@@ -493,19 +486,20 @@ readfile(
// remember the current fileformat
save_file_ff(curbuf);
- if (aborting()) /* autocmds may abort script processing */
+ if (aborting()) { // autocmds may abort script processing
return FAIL;
- return OK; /* a new file is not an error */
+ }
+ return OK; // a new file is not an error
} else {
filemess(curbuf, sfname, (char_u *)(
- (fd == UV_EFBIG) ? _("[File too big]") :
-# if defined(UNIX) && defined(EOVERFLOW)
- // libuv only returns -errno in Unix and in Windows open() does not
- // set EOVERFLOW
- (fd == -EOVERFLOW) ? _("[File too big]") :
-# endif
- _("[Permission Denied]")), 0);
- curbuf->b_p_ro = TRUE; /* must use "w!" now */
+ (fd == UV_EFBIG) ? _("[File too big]") :
+#if defined(UNIX) && defined(EOVERFLOW)
+ // libuv only returns -errno in Unix and in Windows open() does not
+ // set EOVERFLOW
+ (fd == -EOVERFLOW) ? _("[File too big]") :
+#endif
+ _("[Permission Denied]")), 0);
+ curbuf->b_p_ro = TRUE; // must use "w!" now
}
return FAIL;
@@ -513,10 +507,11 @@ readfile(
/*
* Only set the 'ro' flag for readonly files the first time they are
- * loaded. Help files always get readonly mode
+ * loaded. Help files always get readonly mode
*/
- if ((check_readonly && file_readonly) || curbuf->b_help)
+ if ((check_readonly && file_readonly) || curbuf->b_help) {
curbuf->b_p_ro = TRUE;
+ }
if (set_options) {
/* Don't change 'eol' if reading from buffer as it will already be
@@ -573,12 +568,13 @@ readfile(
// If "Quit" selected at ATTENTION dialog, don't load the file.
if (swap_exists_action == SEA_QUIT) {
- if (!read_buffer && !read_stdin)
+ if (!read_buffer && !read_stdin) {
close(fd);
+ }
return FAIL;
}
- ++no_wait_return; /* don't wait for return yet */
+ ++no_wait_return; // don't wait for return yet
/*
* Set '[ mark to the line above where the lines go (line 1 if zero).
@@ -627,10 +623,10 @@ readfile(
msg_scroll = m;
}
- if (aborting()) { /* autocmds may abort script processing */
+ if (aborting()) { // autocmds may abort script processing
--no_wait_return;
msg_scroll = msg_save;
- curbuf->b_p_ro = TRUE; /* must use "w!" now */
+ curbuf->b_p_ro = TRUE; // must use "w!" now
return FAIL;
}
/*
@@ -646,16 +642,17 @@ readfile(
|| (fd = os_open((char *)fname, O_RDONLY, 0)) < 0)) {
--no_wait_return;
msg_scroll = msg_save;
- if (fd < 0)
+ if (fd < 0) {
EMSG(_("E200: *ReadPre autocommands made the file unreadable"));
- else
+ } else {
EMSG(_("E201: *ReadPre autocommands must not change current buffer"));
- curbuf->b_p_ro = TRUE; /* must use "w!" now */
+ }
+ curbuf->b_p_ro = TRUE; // must use "w!" now
return FAIL;
}
}
- /* Autocommands may add lines to the file, need to check if it is empty */
+ // Autocommands may add lines to the file, need to check if it is empty
wasempty = (curbuf->b_ml.ml_flags & ML_EMPTY);
if (!recoverymode && !filtering && !(flags & READ_DUMMY)) {
@@ -664,7 +661,7 @@ readfile(
}
}
- msg_scroll = FALSE; /* overwrite the file message */
+ msg_scroll = FALSE; // overwrite the file message
/*
* Set linecnt now, before the "retry" caused by a wrong guess for
@@ -672,13 +669,15 @@ readfile(
*/
linecnt = curbuf->b_ml.ml_line_count;
- /* "++bad=" argument. */
+ // "++bad=" argument.
if (eap != NULL && eap->bad_char != 0) {
bad_char_behavior = eap->bad_char;
- if (set_options)
+ if (set_options) {
curbuf->b_bad_char = eap->bad_char;
- } else
+ }
+ } else {
curbuf->b_bad_char = 0;
+ }
/*
* Decide which 'encoding' to use or use first.
@@ -715,16 +714,16 @@ readfile(
* - "fileformat" check failed: try another
*
* Variables set for special retry actions:
- * "file_rewind" Rewind the file to start reading it again.
- * "advance_fenc" Advance "fenc" using "fenc_next".
- * "skip_read" Re-use already read bytes (BOM detected).
- * "did_iconv" iconv() conversion failed, try 'charconvert'.
+ * "file_rewind" Rewind the file to start reading it again.
+ * "advance_fenc" Advance "fenc" using "fenc_next".
+ * "skip_read" Re-use already read bytes (BOM detected).
+ * "did_iconv" iconv() conversion failed, try 'charconvert'.
* "keep_fileformat" Don't reset "fileformat".
*
* Other status indicators:
- * "tmpname" When != NULL did conversion with 'charconvert'.
- * Output file has to be deleted afterwards.
- * "iconv_fd" When != -1 did conversion with iconv().
+ * "tmpname" When != NULL did conversion with 'charconvert'.
+ * Output file has to be deleted afterwards.
+ * "iconv_fd" When != -1 did conversion with iconv().
*/
retry:
@@ -759,21 +758,23 @@ retry:
if (eap != NULL && eap->force_ff != 0) {
fileformat = get_fileformat_force(curbuf, eap);
try_unix = try_dos = try_mac = FALSE;
- } else if (curbuf->b_p_bin)
- fileformat = EOL_UNIX; /* binary: use Unix format */
- else if (*p_ffs == NUL)
- fileformat = get_fileformat(curbuf); /* use format from buffer */
- else
- fileformat = EOL_UNKNOWN; /* detect from file */
+ } else if (curbuf->b_p_bin) {
+ fileformat = EOL_UNIX; // binary: use Unix format
+ } else if (*p_ffs ==
+ NUL) {
+ fileformat = get_fileformat(curbuf); // use format from buffer
+ } else {
+ fileformat = EOL_UNKNOWN; // detect from file
+ }
}
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
if (iconv_fd != (iconv_t)-1) {
- /* aborted conversion with iconv(), close the descriptor */
+ // aborted conversion with iconv(), close the descriptor
iconv_close(iconv_fd);
iconv_fd = (iconv_t)-1;
}
-# endif
+#endif
if (advance_fenc) {
/*
@@ -782,17 +783,19 @@ retry:
advance_fenc = false;
if (eap != NULL && eap->force_enc != 0) {
- /* Conversion given with "++cc=" wasn't possible, read
- * without conversion. */
- notconverted = TRUE;
+ // Conversion given with "++cc=" wasn't possible, read
+ // without conversion.
+ notconverted = true;
conv_error = 0;
- if (fenc_alloced)
+ if (fenc_alloced) {
xfree(fenc);
+ }
fenc = (char_u *)"";
fenc_alloced = false;
} else {
- if (fenc_alloced)
+ if (fenc_alloced) {
xfree(fenc);
+ }
if (fenc_next != NULL) {
fenc = next_fenc(&fenc_next, &fenc_alloced);
} else {
@@ -813,7 +816,6 @@ retry:
fio_flags = 0;
converted = need_conversion(fenc);
if (converted) {
-
/* "ucs-bom" means we need to check the first bytes of the file
* for a BOM. */
if (STRCMP(fenc, ENC_UCSBOM) == 0) {
@@ -831,14 +833,13 @@ retry:
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
// Try using iconv() if we can't convert internally.
if (fio_flags == 0
- && !did_iconv
- ) {
+ && !did_iconv) {
iconv_fd = (iconv_t)my_iconv_open((char_u *)"utf-8", fenc);
}
-# endif
+#endif
/*
* Use the 'charconvert' expression when conversion is required
@@ -846,13 +847,13 @@ retry:
*/
if (fio_flags == 0 && !read_stdin && !read_buffer && *p_ccv != NUL
&& !read_fifo
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
&& iconv_fd == (iconv_t)-1
-# endif
+#endif
) {
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
did_iconv = false;
-# endif
+#endif
/* Skip conversion when it's already done (retry for wrong
* "fileformat"). */
if (tmpname == NULL) {
@@ -861,9 +862,9 @@ retry:
// Conversion failed. Try another one.
advance_fenc = true;
if (fd < 0) {
- /* Re-opening the original file failed! */
+ // Re-opening the original file failed!
EMSG(_("E202: Conversion made file unreadable!"));
- error = TRUE;
+ error = true;
goto failed;
}
goto retry;
@@ -871,9 +872,9 @@ retry:
}
} else {
if (fio_flags == 0
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
&& iconv_fd == (iconv_t)-1
-# endif
+#endif
) {
/* Conversion wanted but we can't.
* Try the next conversion in 'fileencodings' */
@@ -901,8 +902,9 @@ retry:
&& !read_fifo
&& !read_stdin
&& !read_buffer);
- if (read_undo_file)
+ if (read_undo_file) {
sha256_start(&sha_ctx);
+ }
}
while (!error && !got_int) {
@@ -936,11 +938,12 @@ retry:
}
}
if (new_buffer == NULL) {
- error = TRUE;
+ error = true;
break;
}
- if (linerest) /* copy characters from the previous buffer */
+ if (linerest) { // copy characters from the previous buffer
memmove(new_buffer, ptr - linerest, (size_t)linerest);
+ }
xfree(buffer);
buffer = new_buffer;
ptr = buffer + linerest;
@@ -957,11 +960,11 @@ retry:
* ucs-4 to utf-8: 4 bytes become up to 6 bytes, size must be
* multiple of 4 */
real_size = (int)size;
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
if (iconv_fd != (iconv_t)-1) {
size = size / ICONV_MULT;
} else {
-# endif
+#endif
if (fio_flags & FIO_LATIN1) {
size = size / 2;
} else if (fio_flags & (FIO_UCS2 | FIO_UTF16)) {
@@ -971,9 +974,9 @@ retry:
} else if (fio_flags == FIO_UCSBOM) {
size = size / ICONV_MULT; // worst case
}
-# ifdef HAVE_ICONV
- }
-# endif
+#ifdef HAVE_ICONV
+ }
+#endif
if (conv_restlen > 0) {
// Insert unconverted bytes from previous line.
memmove(ptr, conv_rest, conv_restlen); // -V614
@@ -986,9 +989,9 @@ retry:
* Read bytes from curbuf. Used for converting text read
* from stdin.
*/
- if (read_buf_lnum > from)
+ if (read_buf_lnum > from) {
size = 0;
- else {
+ } else {
int n, ni;
long tlen;
@@ -1002,10 +1005,11 @@ retry:
* below. */
n = (int)(size - tlen);
for (ni = 0; ni < n; ++ni) {
- if (p[ni] == NL)
+ if (p[ni] == NL) {
ptr[tlen++] = NUL;
- else
+ } else {
ptr[tlen++] = p[ni];
+ }
}
read_buf_col += n;
break;
@@ -1013,18 +1017,20 @@ retry:
/* Append whole line and new-line. Change NL
* to NUL to reverse the effect done below. */
for (ni = 0; ni < n; ++ni) {
- if (p[ni] == NL)
+ if (p[ni] == NL) {
ptr[tlen++] = NUL;
- else
+ } else {
ptr[tlen++] = p[ni];
+ }
}
ptr[tlen++] = NL;
read_buf_col = 0;
if (++read_buf_lnum > from) {
/* When the last line didn't have an
* end-of-line don't add it now either. */
- if (!curbuf->b_p_eol)
+ if (!curbuf->b_p_eol) {
--tlen;
+ }
size = tlen;
break;
}
@@ -1039,30 +1045,33 @@ retry:
}
if (size <= 0) {
- if (size < 0) /* read error */
- error = TRUE;
- else if (conv_restlen > 0) {
+ if (size < 0) { // read error
+ error = true;
+ } else if (conv_restlen > 0) {
/*
* Reached end-of-file but some trailing bytes could
* not be converted. Truncated file?
*/
- /* When we did a conversion report an error. */
+ // When we did a conversion report an error.
if (fio_flags != 0
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
|| iconv_fd != (iconv_t)-1
-# endif
+#endif
) {
- if (can_retry)
+ if (can_retry) {
goto rewind_retry;
- if (conv_error == 0)
+ }
+ if (conv_error == 0) {
conv_error = curbuf->b_ml.ml_line_count
- linecnt + 1;
+ }
}
- /* Remember the first linenr with an illegal byte */
- else if (illegal_byte == 0)
+ // Remember the first linenr with an illegal byte
+ else if (illegal_byte == 0) {
illegal_byte = curbuf->b_ml.ml_line_count
- linecnt + 1;
+ }
if (bad_char_behavior == BAD_DROP) {
*(ptr - conv_restlen) = NUL;
conv_restlen = 0;
@@ -1072,9 +1081,9 @@ retry:
* leave the UTF8 checking code to do it, as it
* works slightly differently. */
if (bad_char_behavior != BAD_KEEP && (fio_flags != 0
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
|| iconv_fd != (iconv_t)-1
-# endif
+#endif
)) {
while (conv_restlen > 0) {
*(--ptr) = bad_char_behavior;
@@ -1082,18 +1091,18 @@ retry:
}
}
fio_flags = 0; // don't convert this
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
if (iconv_fd != (iconv_t)-1) {
iconv_close(iconv_fd);
iconv_fd = (iconv_t)-1;
}
-# endif
+#endif
}
}
}
}
- skip_read = FALSE;
+ skip_read = false;
/*
* At start of file: Check for BOM.
@@ -1106,17 +1115,18 @@ retry:
|| (!curbuf->b_p_bomb
&& tmpname == NULL
&& (*fenc == 'u' || *fenc == NUL)))) {
- char_u *ccname;
+ char_u *ccname;
int blen;
- /* no BOM detection in a short file or in binary mode */
- if (size < 2 || curbuf->b_p_bin)
+ // no BOM detection in a short file or in binary mode
+ if (size < 2 || curbuf->b_p_bin) {
ccname = NULL;
- else
+ } else {
ccname = check_for_bom(ptr, size, &blen,
- fio_flags == FIO_UCSBOM ? FIO_ALL : get_fio_flags(fenc));
+ fio_flags == FIO_UCSBOM ? FIO_ALL : get_fio_flags(fenc));
+ }
if (ccname != NULL) {
- /* Remove BOM from the text */
+ // Remove BOM from the text
filesize += blen;
size -= blen;
memmove(ptr, ptr + blen, (size_t)size);
@@ -1131,36 +1141,38 @@ retry:
// No BOM detected: retry with next encoding.
advance_fenc = true;
} else {
- /* BOM detected: set "fenc" and jump back */
- if (fenc_alloced)
+ // BOM detected: set "fenc" and jump back
+ if (fenc_alloced) {
xfree(fenc);
+ }
fenc = ccname;
fenc_alloced = false;
}
- /* retry reading without getting new bytes or rewinding */
- skip_read = TRUE;
+ // retry reading without getting new bytes or rewinding
+ skip_read = true;
goto retry;
}
}
- /* Include not converted bytes. */
+ // Include not converted bytes.
ptr -= conv_restlen;
size += conv_restlen;
conv_restlen = 0;
/*
* Break here for a read error or end-of-file.
*/
- if (size <= 0)
+ if (size <= 0) {
break;
+ }
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
if (iconv_fd != (iconv_t)-1) {
/*
* Attempt conversion of the read bytes to 'encoding' using
* iconv().
*/
- const char *fromp;
- char *top;
+ const char *fromp;
+ char *top;
size_t from_size;
size_t to_size;
@@ -1176,16 +1188,18 @@ retry:
* alternative (help files).
*/
while ((iconv(iconv_fd, (void *)&fromp, &from_size,
- &top, &to_size)
+ &top, &to_size)
== (size_t)-1 && ICONV_ERRNO != ICONV_EINVAL)
|| from_size > CONV_RESTLEN) {
- if (can_retry)
+ if (can_retry) {
goto rewind_retry;
- if (conv_error == 0)
+ }
+ if (conv_error == 0) {
conv_error = readfile_linenr(linecnt,
- ptr, (char_u *)top);
+ ptr, (char_u *)top);
+ }
- /* Deal with a bad byte and continue with the next. */
+ // Deal with a bad byte and continue with the next.
++fromp;
--from_size;
if (bad_char_behavior == BAD_KEEP) {
@@ -1204,17 +1218,17 @@ retry:
conv_restlen = (int)from_size;
}
- /* move the linerest to before the converted characters */
+ // move the linerest to before the converted characters
line_start = ptr - linerest;
memmove(line_start, buffer, (size_t)linerest);
- size = (long)((char_u *)top - ptr);
+ size = ((char_u *)top - ptr);
}
-# endif
+#endif
if (fio_flags != 0) {
unsigned int u8c;
- char_u *dest;
- char_u *tail = NULL;
+ char_u *dest;
+ char_u *tail = NULL;
// Convert Unicode or Latin1 to UTF-8.
// Go from end to start through the buffer, because the number
@@ -1225,22 +1239,25 @@ retry:
if (fio_flags == FIO_LATIN1 || fio_flags == FIO_UTF8) {
p = ptr + size;
if (fio_flags == FIO_UTF8) {
- /* Check for a trailing incomplete UTF-8 sequence */
+ // Check for a trailing incomplete UTF-8 sequence
tail = ptr + size - 1;
- while (tail > ptr && (*tail & 0xc0) == 0x80)
+ while (tail > ptr && (*tail & 0xc0) == 0x80) {
--tail;
- if (tail + utf_byte2len(*tail) <= ptr + size)
+ }
+ if (tail + utf_byte2len(*tail) <= ptr + size) {
tail = NULL;
- else
+ } else {
p = tail;
+ }
}
} else if (fio_flags & (FIO_UCS2 | FIO_UTF16)) {
- /* Check for a trailing byte */
+ // Check for a trailing byte
p = ptr + (size & ~1);
- if (size & 1)
+ if (size & 1) {
tail = p;
+ }
if ((fio_flags & FIO_UTF16) && p > ptr) {
- /* Check for a trailing leading word */
+ // Check for a trailing leading word
if (fio_flags & FIO_ENDIAN_L) {
u8c = (*--p << 8);
u8c += *--p;
@@ -1248,16 +1265,18 @@ retry:
u8c = *--p;
u8c += (*--p << 8);
}
- if (u8c >= 0xd800 && u8c <= 0xdbff)
+ if (u8c >= 0xd800 && u8c <= 0xdbff) {
tail = p;
- else
+ } else {
p += 2;
+ }
}
- } else { /* FIO_UCS4 */
- /* Check for trailing 1, 2 or 3 bytes */
+ } else { // FIO_UCS4
+ // Check for trailing 1, 2 or 3 bytes
p = ptr + (size & ~3);
- if (size & 3)
+ if (size & 3) {
tail = p;
+ }
}
/* If there is a trailing incomplete sequence move it to
@@ -1270,9 +1289,9 @@ retry:
while (p > ptr) {
- if (fio_flags & FIO_LATIN1)
+ if (fio_flags & FIO_LATIN1) {
u8c = *--p;
- else if (fio_flags & (FIO_UCS2 | FIO_UTF16)) {
+ } else if (fio_flags & (FIO_UCS2 | FIO_UTF16)) {
if (fio_flags & FIO_ENDIAN_L) {
u8c = (*--p << 8);
u8c += *--p;
@@ -1285,16 +1304,20 @@ retry:
int u16c;
if (p == ptr) {
- /* Missing leading word. */
- if (can_retry)
+ // Missing leading word.
+ if (can_retry) {
goto rewind_retry;
- if (conv_error == 0)
+ }
+ if (conv_error == 0) {
conv_error = readfile_linenr(linecnt,
- ptr, p);
- if (bad_char_behavior == BAD_DROP)
+ ptr, p);
+ }
+ if (bad_char_behavior == BAD_DROP) {
continue;
- if (bad_char_behavior != BAD_KEEP)
+ }
+ if (bad_char_behavior != BAD_KEEP) {
u8c = bad_char_behavior;
+ }
}
/* found second word of double-word, get the first
@@ -1309,17 +1332,21 @@ retry:
u8c = 0x10000 + ((u16c & 0x3ff) << 10)
+ (u8c & 0x3ff);
- /* Check if the word is indeed a leading word. */
+ // Check if the word is indeed a leading word.
if (u16c < 0xd800 || u16c > 0xdbff) {
- if (can_retry)
+ if (can_retry) {
goto rewind_retry;
- if (conv_error == 0)
+ }
+ if (conv_error == 0) {
conv_error = readfile_linenr(linecnt,
- ptr, p);
- if (bad_char_behavior == BAD_DROP)
+ ptr, p);
+ }
+ if (bad_char_behavior == BAD_DROP) {
continue;
- if (bad_char_behavior != BAD_KEEP)
+ }
+ if (bad_char_behavior != BAD_KEEP) {
u8c = bad_char_behavior;
+ }
}
}
} else if (fio_flags & FIO_UCS4) {
@@ -1328,16 +1355,16 @@ retry:
u8c += (unsigned)(*--p) << 16;
u8c += (unsigned)(*--p) << 8;
u8c += *--p;
- } else { /* big endian */
+ } else { // big endian
u8c = *--p;
u8c += (unsigned)(*--p) << 8;
u8c += (unsigned)(*--p) << 16;
u8c += (unsigned)(*--p) << 24;
}
- } else { /* UTF-8 */
- if (*--p < 0x80)
+ } else { // UTF-8
+ if (*--p < 0x80) {
u8c = *p;
- else {
+ } else {
len = utf_head_off(ptr, p);
p -= len;
u8c = utf_ptr2char(p);
@@ -1345,15 +1372,19 @@ retry:
/* Not a valid UTF-8 character, retry with
* another fenc when possible, otherwise just
* report the error. */
- if (can_retry)
+ if (can_retry) {
goto rewind_retry;
- if (conv_error == 0)
+ }
+ if (conv_error == 0) {
conv_error = readfile_linenr(linecnt,
- ptr, p);
- if (bad_char_behavior == BAD_DROP)
+ ptr, p);
+ }
+ if (bad_char_behavior == BAD_DROP) {
continue;
- if (bad_char_behavior != BAD_KEEP)
+ }
+ if (bad_char_behavior != BAD_KEEP) {
u8c = bad_char_behavior;
+ }
}
}
}
@@ -1366,7 +1397,7 @@ retry:
// move the linerest to before the converted characters
line_start = dest - linerest;
memmove(line_start, buffer, (size_t)linerest);
- size = (long)((ptr + real_size) - dest);
+ size = ((ptr + real_size) - dest);
ptr = dest;
} else if (!curbuf->b_p_bin) {
bool incomplete_tail = false;
@@ -1407,57 +1438,61 @@ retry:
/* Illegal byte. If we can try another encoding
* do that, unless at EOF where a truncated
* file is more likely than a conversion error. */
- if (can_retry && !incomplete_tail)
+ if (can_retry && !incomplete_tail) {
break;
-# ifdef HAVE_ICONV
+ }
+#ifdef HAVE_ICONV
// When we did a conversion report an error.
if (iconv_fd != (iconv_t)-1 && conv_error == 0) {
conv_error = readfile_linenr(linecnt, ptr, p);
}
-# endif
- /* Remember the first linenr with an illegal byte */
- if (conv_error == 0 && illegal_byte == 0)
+#endif
+ // Remember the first linenr with an illegal byte
+ if (conv_error == 0 && illegal_byte == 0) {
illegal_byte = readfile_linenr(linecnt, ptr, p);
+ }
- /* Drop, keep or replace the bad byte. */
+ // Drop, keep or replace the bad byte.
if (bad_char_behavior == BAD_DROP) {
memmove(p, p + 1, todo - 1);
--p;
--size;
- } else if (bad_char_behavior != BAD_KEEP)
+ } else if (bad_char_behavior != BAD_KEEP) {
*p = bad_char_behavior;
- } else
+ }
+ } else {
p += l - 1;
+ }
}
}
if (p < ptr + size && !incomplete_tail) {
- /* Detected a UTF-8 error. */
+ // Detected a UTF-8 error.
rewind_retry:
// Retry reading with another conversion.
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
if (*p_ccv != NUL && iconv_fd != (iconv_t)-1) {
// iconv() failed, try 'charconvert'
did_iconv = true;
} else {
-# endif
+#endif
// use next item from 'fileencodings'
advance_fenc = true;
-# ifdef HAVE_ICONV
- }
-# endif
+#ifdef HAVE_ICONV
+ }
+#endif
file_rewind = true;
goto retry;
}
}
- /* count the number of characters (after conversion!) */
+ // count the number of characters (after conversion!)
filesize += size;
/*
* when reading the first part of a file: guess EOL type
*/
if (fileformat == EOL_UNKNOWN) {
- /* First try finding a NL, for Dos and Unix */
+ // First try finding a NL, for Dos and Unix
if (try_dos || try_unix) {
// Reset the carriage return counter.
if (try_mac) {
@@ -1467,32 +1502,36 @@ rewind_retry:
for (p = ptr; p < ptr + size; ++p) {
if (*p == NL) {
if (!try_unix
- || (try_dos && p > ptr && p[-1] == CAR))
+ || (try_dos && p > ptr && p[-1] == CAR)) {
fileformat = EOL_DOS;
- else
+ } else {
fileformat = EOL_UNIX;
+ }
break;
} else if (*p == CAR && try_mac) {
try_mac++;
}
}
- /* Don't give in to EOL_UNIX if EOL_MAC is more likely */
+ // Don't give in to EOL_UNIX if EOL_MAC is more likely
if (fileformat == EOL_UNIX && try_mac) {
- /* Need to reset the counters when retrying fenc. */
+ // Need to reset the counters when retrying fenc.
try_mac = 1;
try_unix = 1;
- for (; p >= ptr && *p != CAR; p--)
+ for (; p >= ptr && *p != CAR; p--) {
;
+ }
if (p >= ptr) {
for (p = ptr; p < ptr + size; ++p) {
- if (*p == NL)
+ if (*p == NL) {
try_unix++;
- else if (*p == CAR)
+ } else if (*p == CAR) {
try_mac++;
+ }
}
- if (try_mac > try_unix)
+ if (try_mac > try_unix) {
fileformat = EOL_MAC;
+ }
}
} else if (fileformat == EOL_UNKNOWN && try_mac == 1) {
// Looking for CR but found no end-of-line markers at all:
@@ -1501,13 +1540,15 @@ rewind_retry:
}
}
- /* No NL found: may use Mac format */
- if (fileformat == EOL_UNKNOWN && try_mac)
+ // No NL found: may use Mac format
+ if (fileformat == EOL_UNKNOWN && try_mac) {
fileformat = EOL_MAC;
+ }
- /* Still nothing found? Use first format in 'ffs' */
- if (fileformat == EOL_UNKNOWN)
+ // Still nothing found? Use first format in 'ffs'
+ if (fileformat == EOL_UNKNOWN) {
fileformat = default_fileformat();
+ }
// May set 'p_ff' if editing a new file.
if (set_options) {
@@ -1523,44 +1564,48 @@ rewind_retry:
if (fileformat == EOL_MAC) {
--ptr;
while (++ptr, --size >= 0) {
- /* catch most common case first */
- if ((c = *ptr) != NUL && c != CAR && c != NL)
+ // catch most common case first
+ if ((c = *ptr) != NUL && c != CAR && c != NL) {
continue;
- if (c == NUL)
- *ptr = NL; /* NULs are replaced by newlines! */
- else if (c == NL)
- *ptr = CAR; /* NLs are replaced by CRs! */
- else {
+ }
+ if (c == NUL) {
+ *ptr = NL; // NULs are replaced by newlines!
+ } else if (c == NL) {
+ *ptr = CAR; // NLs are replaced by CRs!
+ } else {
if (skip_count == 0) {
- *ptr = NUL; /* end of line */
- len = (colnr_T) (ptr - line_start + 1);
+ *ptr = NUL; // end of line
+ len = (colnr_T)(ptr - line_start + 1);
if (ml_append(lnum, line_start, len, newfile) == FAIL) {
- error = TRUE;
+ error = true;
break;
}
- if (read_undo_file)
+ if (read_undo_file) {
sha256_update(&sha_ctx, line_start, len);
+ }
++lnum;
if (--read_count == 0) {
- error = TRUE; /* break loop */
- line_start = ptr; /* nothing left to write */
+ error = true; // break loop
+ line_start = ptr; // nothing left to write
break;
}
- } else
+ } else {
--skip_count;
+ }
line_start = ptr + 1;
}
}
} else {
--ptr;
while (++ptr, --size >= 0) {
- if ((c = *ptr) != NUL && c != NL) /* catch most common case */
+ if ((c = *ptr) != NUL && c != NL) { // catch most common case
continue;
- if (c == NUL)
- *ptr = NL; /* NULs are replaced by newlines! */
- else {
+ }
+ if (c == NUL) {
+ *ptr = NL; // NULs are replaced by newlines!
+ } else {
if (skip_count == 0) {
- *ptr = NUL; /* end of line */
+ *ptr = NUL; // end of line
len = (colnr_T)(ptr - line_start + 1);
if (fileformat == EOL_DOS) {
if (ptr > line_start && ptr[-1] == CAR) {
@@ -1577,8 +1622,9 @@ rewind_retry:
&& (read_buffer
|| vim_lseek(fd, (off_T)0L, SEEK_SET) == 0)) {
fileformat = EOL_UNIX;
- if (set_options)
+ if (set_options) {
set_fileformat(EOL_UNIX, OPT_LOCAL);
+ }
file_rewind = true;
keep_fileformat = true;
goto retry;
@@ -1587,31 +1633,34 @@ rewind_retry:
}
}
if (ml_append(lnum, line_start, len, newfile) == FAIL) {
- error = TRUE;
+ error = true;
break;
}
- if (read_undo_file)
+ if (read_undo_file) {
sha256_update(&sha_ctx, line_start, len);
+ }
++lnum;
if (--read_count == 0) {
- error = TRUE; /* break loop */
- line_start = ptr; /* nothing left to write */
+ error = true; // break loop
+ line_start = ptr; // nothing left to write
break;
}
- } else
+ } else {
--skip_count;
+ }
line_start = ptr + 1;
}
}
}
- linerest = (long)(ptr - line_start);
+ linerest = (ptr - line_start);
os_breakcheck();
}
failed:
- /* not an error, max. number of lines reached */
- if (error && read_count == 0)
- error = FALSE;
+ // not an error, max. number of lines reached
+ if (error && read_count == 0) {
+ error = false;
+ }
/*
* If we get EOF in the middle of a line, note the fact and
@@ -1625,16 +1674,18 @@ failed:
&& fileformat == EOL_DOS
&& *line_start == Ctrl_Z
&& ptr == line_start + 1)) {
- /* remember for when writing */
- if (set_options)
+ // remember for when writing
+ if (set_options) {
curbuf->b_p_eol = FALSE;
+ }
*ptr = NUL;
len = (colnr_T)(ptr - line_start + 1);
- if (ml_append(lnum, line_start, len, newfile) == FAIL)
- error = TRUE;
- else {
- if (read_undo_file)
+ if (ml_append(lnum, line_start, len, newfile) == FAIL) {
+ error = true;
+ } else {
+ if (read_undo_file) {
sha256_update(&sha_ctx, line_start, len);
+ }
read_no_eol_lnum = ++lnum;
}
}
@@ -1646,13 +1697,14 @@ failed:
// Also for ":read ++edit file".
set_string_option_direct("fenc", -1, fenc, OPT_FREE | OPT_LOCAL, 0);
}
- if (fenc_alloced)
+ if (fenc_alloced) {
xfree(fenc);
-# ifdef HAVE_ICONV
+ }
+#ifdef HAVE_ICONV
if (iconv_fd != (iconv_t)-1) {
iconv_close(iconv_fd);
}
-# endif
+#endif
if (!read_buffer && !read_stdin) {
close(fd); // errors are ignored
@@ -1679,13 +1731,13 @@ failed:
os_remove((char *)tmpname); // delete converted file
xfree(tmpname);
}
- --no_wait_return; /* may wait for return now */
+ --no_wait_return; // may wait for return now
/*
* In recovery mode everything but autocommands is skipped.
*/
if (!recoverymode) {
- /* need to delete the last line, which comes from the empty buffer */
+ // need to delete the last line, which comes from the empty buffer
if (newfile && wasempty && !(curbuf->b_ml.ml_flags & ML_EMPTY)) {
ml_delete(curbuf->b_ml.ml_line_count, false);
linecnt--;
@@ -1695,8 +1747,9 @@ failed:
curbuf->deleted_codepoints = 0;
curbuf->deleted_codeunits = 0;
linecnt = curbuf->b_ml.ml_line_count - linecnt;
- if (filesize == 0)
+ if (filesize == 0) {
linecnt = 0;
+ }
if (newfile || read_buffer) {
redraw_curbuf_later(NOT_VALID);
/* After reading the text into the buffer the diff info needs to
@@ -1705,8 +1758,9 @@ failed:
/* All folds in the window are invalid now. Mark them for update
* before triggering autocommands. */
foldUpdateAll(curwin);
- } else if (linecnt) /* appended at least one line */
+ } else if (linecnt) { // appended at least one line
appended_lines_mark(from, linecnt);
+ }
/*
* If we were reading from the same terminal as where messages go,
@@ -1720,12 +1774,13 @@ failed:
if (got_int) {
if (!(flags & READ_DUMMY)) {
filemess(curbuf, sfname, (char_u *)_(e_interr), 0);
- if (newfile)
- curbuf->b_p_ro = TRUE; /* must use "w!" now */
+ if (newfile) {
+ curbuf->b_p_ro = TRUE; // must use "w!" now
+ }
}
msg_scroll = msg_save;
check_marks_read();
- return OK; /* an interrupt isn't really an error */
+ return OK; // an interrupt isn't really an error
}
if (!filtering && !(flags & READ_DUMMY)) {
@@ -1742,7 +1797,7 @@ failed:
c = TRUE;
}
# ifdef OPEN_CHR_FILES
- if (S_ISCHR(perm)) { /* or character special */
+ if (S_ISCHR(perm)) { // or character special
STRCAT(IObuff, _("[character special]"));
c = TRUE;
}
@@ -1773,24 +1828,25 @@ failed:
}
if (conv_error != 0) {
sprintf((char *)IObuff + STRLEN(IObuff),
- _("[CONVERSION ERROR in line %" PRId64 "]"), (int64_t)conv_error);
+ _("[CONVERSION ERROR in line %" PRId64 "]"), (int64_t)conv_error);
c = TRUE;
} else if (illegal_byte > 0) {
sprintf((char *)IObuff + STRLEN(IObuff),
- _("[ILLEGAL BYTE in line %" PRId64 "]"), (int64_t)illegal_byte);
+ _("[ILLEGAL BYTE in line %" PRId64 "]"), (int64_t)illegal_byte);
c = TRUE;
- } else if (error) {
+ } else if (error) {
STRCAT(IObuff, _("[READ ERRORS]"));
c = TRUE;
}
- if (msg_add_fileformat(fileformat))
+ if (msg_add_fileformat(fileformat)) {
c = TRUE;
+ }
msg_add_lines(c, (long)linecnt, filesize);
XFREE_CLEAR(keep_msg);
p = NULL;
- msg_scrolled_ign = TRUE;
+ msg_scrolled_ign = true;
if (!read_stdin && !read_buffer) {
p = msg_trunc_attr(IObuff, FALSE, 0);
@@ -1805,28 +1861,30 @@ failed:
// - When the screen was scrolled but there is no wait-return prompt.
set_keep_msg(p, 0);
}
- msg_scrolled_ign = FALSE;
+ msg_scrolled_ign = false;
}
- /* with errors writing the file requires ":w!" */
+ // with errors writing the file requires ":w!"
if (newfile && (error
|| conv_error != 0
|| (illegal_byte > 0 && bad_char_behavior != BAD_KEEP)
- ))
+ )) {
curbuf->b_p_ro = TRUE;
+ }
- u_clearline(); /* cannot use "U" command after adding lines */
+ u_clearline(); // cannot use "U" command after adding lines
/*
* In Ex mode: cursor at last new line.
* Otherwise: cursor at first new line.
*/
- if (exmode_active)
+ if (exmode_active) {
curwin->w_cursor.lnum = from + linecnt;
- else
+ } else {
curwin->w_cursor.lnum = from + 1;
+ }
check_cursor_lnum();
- beginline(BL_WHITE | BL_FIX); /* on first non-blank */
+ beginline(BL_WHITE | BL_FIX); // on first non-blank
/*
* Set '[ and '] marks to the newly read lines.
@@ -1835,7 +1893,6 @@ failed:
curbuf->b_op_start.col = 0;
curbuf->b_op_end.lnum = from + linecnt;
curbuf->b_op_end.col = 0;
-
}
msg_scroll = msg_save;
@@ -1854,8 +1911,9 @@ failed:
/* When reloading a buffer put the cursor at the first line that is
* different. */
- if (flags & READ_KEEP_UNDO)
+ if (flags & READ_KEEP_UNDO) {
u_find_first_changed();
+ }
/*
* When opening a new file locate undo info and read it.
@@ -1873,8 +1931,9 @@ failed:
/* Save the fileformat now, otherwise the buffer will be considered
* modified if the format/encoding was automatically detected. */
- if (set_options)
+ if (set_options) {
save_file_ff(curbuf);
+ }
/*
* The output from the autocommands should not overwrite anything and
@@ -1906,8 +1965,9 @@ failed:
}
}
- if (recoverymode && error)
+ if (recoverymode && error) {
return FAIL;
+ }
return OK;
}
@@ -1930,25 +1990,24 @@ 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.
- */
-static linenr_T
-readfile_linenr(
- linenr_T linecnt, // line count before reading more bytes
- char_u *p, // start of more bytes read
- char_u *endp // end of more bytes read
-)
+/// 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.
+///
+/// @param linecnt line count before reading more bytes
+/// @param p start of more bytes read
+/// @param endp end of more bytes read
+static linenr_T readfile_linenr(linenr_T linecnt, char_u *p, char_u *endp)
{
- char_u *s;
+ char_u *s;
linenr_T lnum;
lnum = curbuf->b_ml.ml_line_count - linecnt + 1;
- for (s = p; s < endp; ++s)
- if (*s == '\n')
+ for (s = p; s < endp; ++s) {
+ if (*s == '\n') {
++lnum;
+ }
+ }
return lnum;
}
@@ -1977,15 +2036,16 @@ void prep_exarg(exarg_T *eap, const buf_T *buf)
*/
void set_file_options(int set_options, exarg_T *eap)
{
- /* set default 'fileformat' */
+ // set default 'fileformat'
if (set_options) {
- if (eap != NULL && eap->force_ff != 0)
+ if (eap != NULL && eap->force_ff != 0) {
set_fileformat(get_fileformat_force(curbuf, eap), OPT_LOCAL);
- else if (*p_ffs != NUL)
+ } else if (*p_ffs != NUL) {
set_fileformat(default_fileformat(), OPT_LOCAL);
+ }
}
- /* set or reset 'binary' */
+ // set or reset 'binary'
if (eap != NULL && eap->force_bin != 0) {
int oldval = curbuf->b_p_bin;
@@ -2015,8 +2075,8 @@ void set_forced_fenc(exarg_T *eap)
static char_u *next_fenc(char_u **pp, bool *alloced)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
{
- char_u *p;
- char_u *r;
+ char_u *p;
+ char_u *r;
*alloced = false;
if (**pp == NUL) {
@@ -2038,29 +2098,26 @@ static char_u *next_fenc(char_u **pp, bool *alloced)
return r;
}
-/*
- * Convert a file with the 'charconvert' expression.
- * This closes the file which is to be read, converts it and opens the
- * resulting file for reading.
- * Returns name of the resulting converted file (the caller should delete it
- * after reading it).
- * Returns NULL if the conversion failed ("*fdp" is not set) .
- */
-static char_u *
-readfile_charconvert (
- char_u *fname, /* name of input file */
- char_u *fenc, /* converted from */
- int *fdp /* in/out: file descriptor of file */
-)
+/// Convert a file with the 'charconvert' expression.
+/// This closes the file which is to be read, converts it and opens the
+/// resulting file for reading.
+///
+/// @param fname name of input file
+/// @param fenc converted from
+/// @param fdp in/out: file descriptor of file
+///
+/// @return name of the resulting converted file (the caller should delete it after reading it).
+/// Returns NULL if the conversion failed ("*fdp" is not set) .
+static char_u *readfile_charconvert(char_u *fname, char_u *fenc, int *fdp)
{
- char_u *tmpname;
- char_u *errmsg = NULL;
+ char_u *tmpname;
+ char_u *errmsg = NULL;
tmpname = vim_tempname();
- if (tmpname == NULL)
+ if (tmpname == NULL) {
errmsg = (char_u *)_("Can't find temp file for conversion");
- else {
- close(*fdp); /* close the input file, ignore errors */
+ } else {
+ close(*fdp); // close the input file, ignore errors
*fdp = -1;
if (eval_charconvert((char *)fenc, "utf-8",
(char *)fname, (char *)tmpname) == FAIL) {
@@ -2081,7 +2138,7 @@ readfile_charconvert (
}
}
- /* If the input file is closed, open it (caller should check for error). */
+ // If the input file is closed, open it (caller should check for error).
if (*fdp < 0) {
*fdp = os_open((char *)fname, O_RDONLY, 0);
}
@@ -2111,45 +2168,35 @@ char *new_file_message(void)
return shortmess(SHM_NEW) ? _("[New]") : _("[New File]");
}
-/*
- * buf_write() - write to file "fname" lines "start" through "end"
- *
- * We do our own buffering here because fwrite() is so slow.
- *
- * If "forceit" is true, we don't care for errors when attempting backups.
- * In case of an error everything possible is done to restore the original
- * file. But when "forceit" is TRUE, we risk losing it.
- *
- * When "reset_changed" is TRUE and "append" == FALSE and "start" == 1 and
- * "end" == curbuf->b_ml.ml_line_count, reset curbuf->b_changed.
- *
- * This function must NOT use NameBuff (because it's called by autowrite()).
- *
- * return FAIL for failure, OK otherwise
- */
-int
-buf_write(
- buf_T *buf,
- char_u *fname,
- char_u *sfname,
- linenr_T start,
- linenr_T end,
- exarg_T *eap, /* for forced 'ff' and 'fenc', can be
- NULL! */
- int append, /* append to the file */
- int forceit,
- int reset_changed,
- int filtering
-)
+/// buf_write() - write to file "fname" lines "start" through "end"
+///
+/// We do our own buffering here because fwrite() is so slow.
+///
+/// If "forceit" is true, we don't care for errors when attempting backups.
+/// In case of an error everything possible is done to restore the original
+/// file. But when "forceit" is TRUE, we risk losing it.
+///
+/// When "reset_changed" is TRUE and "append" == FALSE and "start" == 1 and
+/// "end" == curbuf->b_ml.ml_line_count, reset curbuf->b_changed.
+///
+/// This function must NOT use NameBuff (because it's called by autowrite()).
+///
+///
+/// @param eap for forced 'ff' and 'fenc', can be NULL!
+/// @param append append to the file
+///
+/// @return FAIL for failure, OK otherwise
+int buf_write(buf_T *buf, char_u *fname, char_u *sfname, linenr_T start, linenr_T end, exarg_T *eap,
+ int append, int forceit, int reset_changed, int filtering)
{
int fd;
- char_u *backup = NULL;
- int backup_copy = FALSE; /* copy the original file? */
+ char_u *backup = NULL;
+ int backup_copy = FALSE; // copy the original file?
int dobackup;
- char_u *ffname;
- char_u *wfname = NULL; /* name of file to write to */
- char_u *s;
- char_u *ptr;
+ char_u *ffname;
+ char_u *wfname = NULL; // name of file to write to
+ char_u *s;
+ char_u *ptr;
char_u c;
int len;
linenr_T lnum;
@@ -2164,9 +2211,9 @@ buf_write(
char *errmsg = NULL;
int errmsgarg = 0;
bool errmsg_allocated = false;
- char_u *buffer;
+ char_u *buffer;
char_u smallbuf[SMBUFSIZE];
- char_u *backup_ext;
+ char_u *backup_ext;
int bufsize;
long perm; // file permissions
int retval = OK;
@@ -2178,21 +2225,21 @@ buf_write(
int prev_got_int = got_int;
int checking_conversion;
bool file_readonly = false; // overwritten file is read-only
- static char *err_readonly =
+ static char *err_readonly =
"is read-only (cannot override: \"W\" in 'cpoptions')";
#if defined(UNIX)
- int made_writable = FALSE; /* 'w' bit has been set */
+ int made_writable = FALSE; // 'w' bit has been set
#endif
- /* writing everything */
+ // writing everything
int whole = (start == 1 && end == buf->b_ml.ml_line_count);
linenr_T old_line_count = buf->b_ml.ml_line_count;
int fileformat;
int write_bin;
- struct bw_info write_info; /* info for buf_write_bytes() */
+ struct bw_info write_info; // info for buf_write_bytes()
int converted = FALSE;
int notconverted = FALSE;
- char_u *fenc; /* effective 'fileencoding' */
- char_u *fenc_tofree = NULL; /* allocated "fenc" */
+ char_u *fenc; // effective 'fileencoding'
+ char_u *fenc_tofree = NULL; // allocated "fenc"
#ifdef HAS_BW_FLAGS
int wb_flags = 0;
#endif
@@ -2204,8 +2251,9 @@ buf_write(
context_sha256_T sha_ctx;
unsigned int bkc = get_bkc_value(buf);
- if (fname == NULL || *fname == NUL) /* safety check */
+ if (fname == NULL || *fname == NUL) { // safety check
return FAIL;
+ }
if (buf->b_ml.ml_mfp == NULL) {
/* This can happen during startup when there is a stray "w" in the
* vimrc file. */
@@ -2217,27 +2265,28 @@ buf_write(
* Disallow writing from .exrc and .vimrc in current directory for
* security reasons.
*/
- if (check_secure())
+ if (check_secure()) {
return FAIL;
+ }
- /* Avoid a crash for a long name. */
+ // Avoid a crash for a long name.
if (STRLEN(fname) >= MAXPATHL) {
EMSG(_(e_longname));
return FAIL;
}
- /* must init bw_conv_buf and bw_iconv_fd before jumping to "fail" */
+ // must init bw_conv_buf and bw_iconv_fd before jumping to "fail"
write_info.bw_conv_buf = NULL;
write_info.bw_conv_error = FALSE;
write_info.bw_conv_error_lnum = 0;
write_info.bw_restlen = 0;
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
write_info.bw_iconv_fd = (iconv_t)-1;
-# endif
+#endif
/* After writing a file changedtick changes but we don't want to display
* the line. */
- ex_no_reprint = TRUE;
+ ex_no_reprint = true;
/*
* If there is no file name yet, use the one for the written file.
@@ -2254,13 +2303,15 @@ buf_write(
&& !filtering
&& (!append || vim_strchr(p_cpo, CPO_FNAMEAPP) != NULL)
&& vim_strchr(p_cpo, CPO_FNAMEW) != NULL) {
- if (set_rw_fname(fname, sfname) == FAIL)
+ if (set_rw_fname(fname, sfname) == FAIL) {
return FAIL;
- buf = curbuf; /* just in case autocmds made "buf" invalid */
+ }
+ buf = curbuf; // just in case autocmds made "buf" invalid
}
- if (sfname == NULL)
+ if (sfname == NULL) {
sfname = fname;
+ }
// For Unix: Use the short file name whenever possible.
// Avoids problems with networks and when directory names are changed.
@@ -2271,12 +2322,13 @@ buf_write(
fname = sfname;
#endif
- if (buf->b_ffname != NULL && fnamecmp(ffname, buf->b_ffname) == 0)
+ if (buf->b_ffname != NULL && fnamecmp(ffname, buf->b_ffname) == 0) {
overwriting = TRUE;
- else
+ } else {
overwriting = FALSE;
+ }
- ++no_wait_return; /* don't wait for return yet */
+ ++no_wait_return; // don't wait for return yet
/*
* Set '[ and '] marks to the lines to be written.
@@ -2302,14 +2354,18 @@ buf_write(
* Set curbuf to the buffer to be written.
* Careful: The autocommands may call buf_write() recursively!
*/
- if (ffname == buf->b_ffname)
+ if (ffname == buf->b_ffname) {
buf_ffname = TRUE;
- if (sfname == buf->b_sfname)
+ }
+ if (sfname == buf->b_sfname) {
buf_sfname = TRUE;
- if (fname == buf->b_ffname)
+ }
+ if (fname == buf->b_ffname) {
buf_fname_f = TRUE;
- if (fname == buf->b_sfname)
+ }
+ if (fname == buf->b_sfname) {
buf_fname_s = TRUE;
+ }
// Set curwin/curbuf to buf and save a few things.
aucmd_prepbuf(&aco, buf);
@@ -2317,21 +2373,22 @@ buf_write(
if (append) {
if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEAPPENDCMD,
- sfname, sfname, FALSE, curbuf, eap))) {
- if (overwriting && bt_nofile(curbuf))
+ sfname, sfname, FALSE, curbuf, eap))) {
+ if (overwriting && bt_nofile(curbuf)) {
nofile_err = TRUE;
- else
+ } else {
apply_autocmds_exarg(EVENT_FILEAPPENDPRE,
- sfname, sfname, FALSE, curbuf, eap);
+ sfname, sfname, FALSE, curbuf, eap);
+ }
}
} else if (filtering) {
apply_autocmds_exarg(EVENT_FILTERWRITEPRE,
- NULL, sfname, FALSE, curbuf, eap);
- } else if (reset_changed && whole) {
+ NULL, sfname, FALSE, curbuf, eap);
+ } else if (reset_changed && whole) {
int was_changed = curbufIsChanged();
did_cmd = apply_autocmds_exarg(EVENT_BUFWRITECMD,
- sfname, sfname, FALSE, curbuf, eap);
+ sfname, sfname, FALSE, curbuf, eap);
if (did_cmd) {
if (was_changed && !curbufIsChanged()) {
/* Written everything correctly and BufWriteCmd has reset
@@ -2341,24 +2398,26 @@ buf_write(
u_update_save_nr(curbuf);
}
} else {
- if (overwriting && bt_nofile(curbuf))
+ if (overwriting && bt_nofile(curbuf)) {
nofile_err = TRUE;
- else
+ } else {
apply_autocmds_exarg(EVENT_BUFWRITEPRE,
- sfname, sfname, FALSE, curbuf, eap);
+ sfname, sfname, FALSE, curbuf, eap);
+ }
}
} else {
if (!(did_cmd = apply_autocmds_exarg(EVENT_FILEWRITECMD,
- sfname, sfname, FALSE, curbuf, eap))) {
- if (overwriting && bt_nofile(curbuf))
+ sfname, sfname, FALSE, curbuf, eap))) {
+ if (overwriting && bt_nofile(curbuf)) {
nofile_err = TRUE;
- else
+ } else {
apply_autocmds_exarg(EVENT_FILEWRITEPRE,
- sfname, sfname, FALSE, curbuf, eap);
+ sfname, sfname, FALSE, curbuf, eap);
+ }
}
}
- /* restore curwin/curbuf and a few other things */
+ // restore curwin/curbuf and a few other things
aucmd_restbuf(&aco);
// In three situations we return here and don't write the file:
@@ -2370,41 +2429,45 @@ buf_write(
}
if (buf == NULL || (buf->b_ml.ml_mfp == NULL && !empty_memline)
|| did_cmd || nofile_err
- || aborting()
- ) {
+ || aborting()) {
--no_wait_return;
msg_scroll = msg_save;
- if (nofile_err)
+ if (nofile_err) {
EMSG(_("E676: No matching autocommands for acwrite buffer"));
+ }
if (nofile_err
- || aborting()
- )
+ || aborting()) {
/* An aborting error, interrupt or exception in the
* autocommands. */
return FAIL;
+ }
if (did_cmd) {
- if (buf == NULL)
+ if (buf == NULL) {
/* The buffer was deleted. We assume it was written
* (can't retry anyway). */
return OK;
+ }
if (overwriting) {
- /* Assume the buffer was written, update the timestamp. */
+ // Assume the buffer was written, update the timestamp.
ml_timestamp(buf);
- if (append)
+ if (append) {
buf->b_flags &= ~BF_NEW;
- else
+ } else {
buf->b_flags &= ~BF_WRITE_MASK;
+ }
}
if (reset_changed && buf->b_changed && !append
- && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL))
+ && (overwriting || vim_strchr(p_cpo, CPO_PLUS) != NULL)) {
/* Buffer still changed, the autocommands didn't work
* properly. */
return FAIL;
+ }
return OK;
}
- if (!aborting())
+ if (!aborting()) {
EMSG(_("E203: Autocommands deleted or unloaded buffer to be written"));
+ }
return FAIL;
}
@@ -2415,11 +2478,11 @@ buf_write(
* changed the number of lines that are to be written (tricky!).
*/
if (buf->b_ml.ml_line_count != old_line_count) {
- if (whole) /* write all */
+ if (whole) { // write all
end = buf->b_ml.ml_line_count;
- else if (buf->b_ml.ml_line_count > old_line_count) /* more lines */
+ } else if (buf->b_ml.ml_line_count > old_line_count) { // more lines
end += buf->b_ml.ml_line_count - old_line_count;
- else { /* less lines */
+ } else { // less lines
end -= old_line_count - buf->b_ml.ml_line_count;
if (end < start) {
--no_wait_return;
@@ -2434,30 +2497,36 @@ buf_write(
* The autocommands may have changed the name of the buffer, which may
* be kept in fname, ffname and sfname.
*/
- if (buf_ffname)
+ if (buf_ffname) {
ffname = buf->b_ffname;
- if (buf_sfname)
+ }
+ if (buf_sfname) {
sfname = buf->b_sfname;
- if (buf_fname_f)
+ }
+ if (buf_fname_f) {
fname = buf->b_ffname;
- if (buf_fname_s)
+ }
+ if (buf_fname_s) {
fname = buf->b_sfname;
+ }
}
- if (shortmess(SHM_OVER) && !exiting)
- msg_scroll = FALSE; /* overwrite previous file message */
- else
- msg_scroll = TRUE; /* don't overwrite previous file message */
- if (!filtering)
+ if (shortmess(SHM_OVER) && !exiting) {
+ msg_scroll = FALSE; // overwrite previous file message
+ } else {
+ msg_scroll = TRUE; // don't overwrite previous file message
+ }
+ if (!filtering) {
filemess(buf,
#ifndef UNIX
- sfname,
+ sfname,
#else
- fname,
+ fname,
#endif
- (char_u *)"", 0); /* show that we are busy */
- msg_scroll = FALSE; /* always overwrite the file message now */
+ (char_u *)"", 0); // show that we are busy
+ }
+ msg_scroll = FALSE; // always overwrite the file message now
buffer = verbose_try_malloc(BUFSIZE);
// can't allocate big buffer, use small one (to be able to write when out of
@@ -2465,8 +2534,9 @@ buf_write(
if (buffer == NULL) {
buffer = smallbuf;
bufsize = SMBUFSIZE;
- } else
+ } else {
bufsize = BUFSIZE;
+ }
/*
* Get information about original file (if there is one).
@@ -2478,7 +2548,7 @@ buf_write(
newfile = TRUE;
} else {
perm = file_info_old.stat.st_mode;
- if (!S_ISREG(file_info_old.stat.st_mode)) { /* not a file */
+ if (!S_ISREG(file_info_old.stat.st_mode)) { // not a file
if (S_ISDIR(file_info_old.stat.st_mode)) {
SET_ERRMSG_NUM("E502", _("is a directory"));
goto fail;
@@ -2540,8 +2610,9 @@ buf_write(
*/
if (overwriting) {
retval = check_mtime(buf, &file_info_old);
- if (retval == FAIL)
+ if (retval == FAIL) {
goto fail;
+ }
}
}
@@ -2549,16 +2620,18 @@ buf_write(
/*
* For systems that support ACL: get the ACL from the original file.
*/
- if (!newfile)
+ if (!newfile) {
acl = mch_get_acl(fname);
+ }
#endif
/*
* If 'backupskip' is not empty, don't make a backup for some files.
*/
dobackup = (p_wb || p_bk || *p_pm != NUL);
- if (dobackup && *p_bsk != NUL && match_file_list(p_bsk, sfname, ffname))
+ if (dobackup && *p_bsk != NUL && match_file_list(p_bsk, sfname, ffname)) {
dobackup = FALSE;
+ }
/*
* Save the value of got_int and reset it. We don't want a previous
@@ -2568,7 +2641,7 @@ buf_write(
prev_got_int = got_int;
got_int = FALSE;
- /* Mark the buffer as 'being saved' to prevent changed buffer warnings */
+ // Mark the buffer as 'being saved' to prevent changed buffer warnings
buf->b_saving = true;
/*
@@ -2583,9 +2656,9 @@ buf_write(
FileInfo file_info;
const bool no_prepend_dot = false;
- if ((bkc & BKC_YES) || append) { /* "yes" */
+ if ((bkc & BKC_YES) || append) { // "yes"
backup_copy = TRUE;
- } else if ((bkc & BKC_AUTO)) { /* "auto" */
+ } else if ((bkc & BKC_AUTO)) { // "auto"
int i;
/*
@@ -2613,11 +2686,11 @@ buf_write(
}
}
fd = os_open((char *)IObuff,
- O_CREAT|O_WRONLY|O_EXCL|O_NOFOLLOW, perm);
- if (fd < 0) /* can't write in directory */
+ O_CREAT|O_WRONLY|O_EXCL|O_NOFOLLOW, perm);
+ if (fd < 0) { // can't write in directory
backup_copy = TRUE;
- else {
-# ifdef UNIX
+ } else {
+#ifdef UNIX
os_fchown(fd, file_info_old.stat.st_uid, file_info_old.stat.st_gid);
if (!os_fileinfo((char *)IObuff, &file_info)
|| file_info.stat.st_uid != file_info_old.stat.st_uid
@@ -2625,7 +2698,7 @@ buf_write(
|| (long)file_info.stat.st_mode != perm) {
backup_copy = TRUE;
}
-# endif
+#endif
/* Close the file before removing it, on MS-Windows we
* can't delete an open file. */
close(fd);
@@ -2638,38 +2711,39 @@ buf_write(
* Break symlinks and/or hardlinks if we've been asked to.
*/
if ((bkc & BKC_BREAKSYMLINK) || (bkc & BKC_BREAKHARDLINK)) {
-# ifdef UNIX
+#ifdef UNIX
bool file_info_link_ok = os_fileinfo_link((char *)fname, &file_info);
- /* Symlinks. */
+ // Symlinks.
if ((bkc & BKC_BREAKSYMLINK)
&& file_info_link_ok
&& !os_fileinfo_id_equal(&file_info, &file_info_old)) {
backup_copy = FALSE;
}
- /* Hardlinks. */
+ // Hardlinks.
if ((bkc & BKC_BREAKHARDLINK)
&& os_fileinfo_hardlinks(&file_info_old) > 1
&& (!file_info_link_ok
|| os_fileinfo_id_equal(&file_info, &file_info_old))) {
backup_copy = FALSE;
}
-# endif
+#endif
}
- /* make sure we have a valid backup extension to use */
- if (*p_bex == NUL)
+ // make sure we have a valid backup extension to use
+ if (*p_bex == NUL) {
backup_ext = (char_u *)".bak";
- else
+ } else {
backup_ext = p_bex;
+ }
if (backup_copy) {
char_u *wp;
int some_error = false;
- char_u *dirp;
- char_u *rootname;
- char_u *p;
+ char_u *dirp;
+ char_u *rootname;
+ char_u *p;
/*
* Try to make the backup in each directory in the 'bdir' option.
@@ -2688,9 +2762,22 @@ buf_write(
/*
* Isolate one directory name, using an entry in 'bdir'.
*/
- (void)copy_option_part(&dirp, IObuff, IOSIZE, ",");
- p = IObuff + STRLEN(IObuff);
- if (after_pathsep((char *)IObuff, (char *)p) && p[-1] == p[-2]) {
+ size_t dir_len = copy_option_part(&dirp, IObuff, IOSIZE, ",");
+ p = IObuff + dir_len;
+ bool trailing_pathseps = after_pathsep((char *)IObuff, (char *)p) && p[-1] == p[-2];
+ if (trailing_pathseps) {
+ IObuff[dir_len - 2] = NUL;
+ }
+ if (*dirp == NUL && !os_isdir(IObuff)) {
+ int ret;
+ char *failed_dir;
+ if ((ret = os_mkdir_recurse((char *)IObuff, 0755, &failed_dir)) != 0) {
+ EMSG3(_("E303: Unable to create directory \"%s\" for backup file: %s"),
+ failed_dir, os_strerror(ret));
+ xfree(failed_dir);
+ }
+ }
+ if (trailing_pathseps) {
// Ends with '//', Use Full path
if ((p = (char_u *)make_percent_swname((char *)IObuff, (char *)fname))
!= NULL) {
@@ -2702,7 +2789,7 @@ buf_write(
rootname = get_file_in_dir(fname, IObuff);
if (rootname == NULL) {
- some_error = TRUE; /* out of memory */
+ some_error = TRUE; // out of memory
goto nobackup;
}
@@ -2718,7 +2805,7 @@ buf_write(
if (backup == NULL) {
xfree(rootname);
- some_error = TRUE; /* out of memory */
+ some_error = TRUE; // out of memory
goto nobackup;
}
@@ -2761,7 +2848,7 @@ buf_write(
* Try to create the backup file
*/
if (backup != NULL) {
- /* remove old backup, if present */
+ // remove old backup, if present
os_remove((char *)backup);
// set file protection same as original file, but
@@ -2802,8 +2889,7 @@ buf_write(
nobackup:
if (backup == NULL && errmsg == NULL) {
- SET_ERRMSG(_(
- "E509: Cannot create backup file (add ! to override)"));
+ SET_ERRMSG(_("E509: Cannot create backup file (add ! to override)"));
}
// Ignore errors when forceit is TRUE.
if ((some_error || errmsg != NULL) && !forceit) {
@@ -2812,9 +2898,9 @@ nobackup:
}
SET_ERRMSG(NULL);
} else {
- char_u *dirp;
- char_u *p;
- char_u *rootname;
+ char_u *dirp;
+ char_u *p;
+ char_u *rootname;
/*
* Make a backup by renaming the original file.
@@ -2840,9 +2926,22 @@ nobackup:
/*
* Isolate one directory name and make the backup file name.
*/
- (void)copy_option_part(&dirp, IObuff, IOSIZE, ",");
- p = IObuff + STRLEN(IObuff);
- if (after_pathsep((char *)IObuff, (char *)p) && p[-1] == p[-2]) {
+ size_t dir_len = copy_option_part(&dirp, IObuff, IOSIZE, ",");
+ p = IObuff + dir_len;
+ bool trailing_pathseps = after_pathsep((char *)IObuff, (char *)p) && p[-1] == p[-2];
+ if (trailing_pathseps) {
+ IObuff[dir_len - 2] = NUL;
+ }
+ if (*dirp == NUL && !os_isdir(IObuff)) {
+ int ret;
+ char *failed_dir;
+ if ((ret = os_mkdir_recurse((char *)IObuff, 0755, &failed_dir)) != 0) {
+ EMSG3(_("E303: Unable to create directory \"%s\" for backup file: %s"),
+ failed_dir, os_strerror(ret));
+ xfree(failed_dir);
+ }
+ }
+ if (trailing_pathseps) {
// path ends with '//', use full path
if ((p = (char_u *)make_percent_swname((char *)IObuff, (char *)fname))
!= NULL) {
@@ -2871,8 +2970,9 @@ nobackup:
*/
if (!p_bk && os_path_exists(backup)) {
p = backup + STRLEN(backup) - 1 - STRLEN(backup_ext);
- if (p < backup) /* empty file name ??? */
+ if (p < backup) { // empty file name ???
p = backup;
+ }
*p = 'z';
while (*p > 'a' && os_path_exists(backup)) {
(*p)--;
@@ -2925,10 +3025,12 @@ nobackup:
status_redraw_all(); // redraw status lines later
}
- if (end > buf->b_ml.ml_line_count)
+ if (end > buf->b_ml.ml_line_count) {
end = buf->b_ml.ml_line_count;
- if (buf->b_ml.ml_flags & ML_EMPTY)
+ }
+ if (buf->b_ml.ml_flags & ML_EMPTY) {
start = end + 1;
+ }
// If the original file is being overwritten, there is a small chance that
// we crash in the middle of writing. Therefore the file is preserved now.
@@ -2983,12 +3085,12 @@ nobackup:
if (converted && wb_flags == 0) {
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
// Use iconv() conversion when conversion is needed and it's not done
// internally.
write_info.bw_iconv_fd = (iconv_t)my_iconv_open(fenc, (char_u *)"utf-8");
if (write_info.bw_iconv_fd != (iconv_t)-1) {
- /* We're going to use iconv(), allocate a buffer to convert in. */
+ // We're going to use iconv(), allocate a buffer to convert in.
write_info.bw_conv_buflen = bufsize * ICONV_MULT;
write_info.bw_conv_buf = verbose_try_malloc(write_info.bw_conv_buflen);
if (!write_info.bw_conv_buf) {
@@ -2996,7 +3098,7 @@ nobackup:
}
write_info.bw_first = TRUE;
} else
-# endif
+#endif
/*
* When the file needs to be converted with 'charconvert' after
@@ -3012,14 +3114,12 @@ nobackup:
}
}
if (converted && wb_flags == 0
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
&& write_info.bw_iconv_fd == (iconv_t)-1
-# endif
- && wfname == fname
- ) {
+#endif
+ && wfname == fname) {
if (!forceit) {
- SET_ERRMSG(_(
- "E213: Cannot convert (add ! to write without conversion)"));
+ SET_ERRMSG(_("E213: Cannot convert (add ! to write without conversion)"));
goto restore_backup;
}
notconverted = TRUE;
@@ -3054,7 +3154,7 @@ nobackup:
O_WRONLY |
(append ?
(forceit ? (O_APPEND | O_CREAT) : O_APPEND)
- : (O_CREAT | O_TRUNC))
+ : (O_CREAT | O_TRUNC))
, perm < 0 ? 0666 : (perm & 0777))) < 0) {
// A forced write will try to create a new file if the old one
// is still readonly. This may also happen when the directory
@@ -3070,28 +3170,28 @@ nobackup:
SET_ERRMSG(_("E166: Can't open linked file for writing"));
} else {
#endif
- SET_ERRMSG_ARG(_("E212: Can't open file for writing: %s"), fd);
- if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL
- && perm >= 0) {
+ SET_ERRMSG_ARG(_("E212: Can't open file for writing: %s"), fd);
+ if (forceit && vim_strchr(p_cpo, CPO_FWRITE) == NULL
+ && perm >= 0) {
#ifdef UNIX
- // we write to the file, thus it should be marked
- // writable after all
- if (!(perm & 0200)) {
- made_writable = true;
- }
- perm |= 0200;
- if (file_info_old.stat.st_uid != getuid()
- || file_info_old.stat.st_gid != getgid()) {
- perm &= 0777;
- }
+ // we write to the file, thus it should be marked
+ // writable after all
+ if (!(perm & 0200)) {
+ made_writable = true;
+ }
+ perm |= 0200;
+ if (file_info_old.stat.st_uid != getuid()
+ || file_info_old.stat.st_gid != getgid()) {
+ perm &= 0777;
+ }
#endif
- if (!append) { // don't remove when appending
- os_remove((char *)wfname);
- }
- continue;
+ if (!append) { // don't remove when appending
+ os_remove((char *)wfname);
}
-#ifdef UNIX
+ continue;
}
+#ifdef UNIX
+ }
#endif
}
@@ -3256,7 +3356,7 @@ restore_backup:
// Stop when writing done or an error was encountered.
if (!checking_conversion || end == 0) {
- break;
+ break;
}
// If no error happened until now, writing should be ok, so loop to
@@ -3345,17 +3445,15 @@ restore_backup:
if (errmsg == NULL) {
if (write_info.bw_conv_error) {
if (write_info.bw_conv_error_lnum == 0) {
- SET_ERRMSG(_(
- "E513: write error, conversion failed "
- "(make 'fenc' empty to override)"));
+ SET_ERRMSG(_("E513: write error, conversion failed "
+ "(make 'fenc' empty to override)"));
} else {
errmsg_allocated = true;
SET_ERRMSG(xmalloc(300));
- vim_snprintf(
- errmsg, 300,
- _("E513: write error, conversion failed in line %" PRIdLINENR
- " (make 'fenc' empty to override)"),
- write_info.bw_conv_error_lnum);
+ vim_snprintf(errmsg, 300,
+ _("E513: write error, conversion failed in line %" PRIdLINENR
+ " (make 'fenc' empty to override)"),
+ write_info.bw_conv_error_lnum);
}
} else if (got_int) {
SET_ERRMSG(_(e_interr));
@@ -3394,11 +3492,11 @@ restore_backup:
goto fail;
}
- lnum -= start; /* compute number of written lines */
- --no_wait_return; /* may wait for return now */
+ lnum -= start; // compute number of written lines
+ --no_wait_return; // may wait for return now
#if !defined(UNIX)
- fname = sfname; /* use shortname now, for the messages */
+ fname = sfname; // use shortname now, for the messages
#endif
if (!filtering) {
add_quoted_fname((char *)IObuff, IOSIZE, buf, (const char *)fname);
@@ -3406,9 +3504,10 @@ restore_backup:
if (write_info.bw_conv_error) {
STRCAT(IObuff, _(" CONVERSION ERROR"));
c = TRUE;
- if (write_info.bw_conv_error_lnum != 0)
+ if (write_info.bw_conv_error_lnum != 0) {
vim_snprintf_add((char *)IObuff, IOSIZE, _(" in line %" PRId64 ";"),
- (int64_t)write_info.bw_conv_error_lnum);
+ (int64_t)write_info.bw_conv_error_lnum);
+ }
} else if (notconverted) {
STRCAT(IObuff, _("[NOT converted]"));
c = TRUE;
@@ -3427,15 +3526,17 @@ restore_backup:
msg_add_eol();
c = TRUE;
}
- /* may add [unix/dos/mac] */
- if (msg_add_fileformat(fileformat))
+ // may add [unix/dos/mac]
+ if (msg_add_fileformat(fileformat)) {
c = TRUE;
- msg_add_lines(c, (long)lnum, nchars); /* add line/char count */
+ }
+ msg_add_lines(c, (long)lnum, nchars); // add line/char count
if (!shortmess(SHM_WRITE)) {
- if (append)
+ if (append) {
STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [a]") : _(" appended"));
- else
+ } else {
STRCAT(IObuff, shortmess(SHM_WRI) ? _(" [w]") : _(" written"));
+ }
}
set_keep_msg(msg_trunc_attr(IObuff, FALSE, 0), 0);
@@ -3463,10 +3564,11 @@ restore_backup:
*/
if (overwriting) {
ml_timestamp(buf);
- if (append)
+ if (append) {
buf->b_flags &= ~BF_NEW;
- else
+ } else {
buf->b_flags &= ~BF_WRITE_MASK;
+ }
}
/*
@@ -3502,11 +3604,12 @@ restore_backup:
if (org == NULL
|| (empty_fd = os_open(org,
- O_CREAT | O_EXCL | O_NOFOLLOW,
- perm < 0 ? 0666 : (perm & 0777))) < 0)
+ O_CREAT | O_EXCL | O_NOFOLLOW,
+ perm < 0 ? 0666 : (perm & 0777))) < 0) {
EMSG(_("E206: patchmode: can't touch empty original file"));
- else
+ } else {
close(empty_fd);
+ }
}
if (org != NULL) {
os_setperm(org, os_getperm((const char *)fname) & 0777);
@@ -3529,23 +3632,24 @@ restore_backup:
* Finish up. We get here either after failure or success.
*/
fail:
- --no_wait_return; /* may wait for return now */
+ --no_wait_return; // may wait for return now
nofail:
- /* Done saving, we accept changed buffer warnings again */
+ // Done saving, we accept changed buffer warnings again
buf->b_saving = false;
xfree(backup);
- if (buffer != smallbuf)
+ if (buffer != smallbuf) {
xfree(buffer);
+ }
xfree(fenc_tofree);
xfree(write_info.bw_conv_buf);
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
if (write_info.bw_iconv_fd != (iconv_t)-1) {
iconv_close(write_info.bw_iconv_fd);
write_info.bw_iconv_fd = (iconv_t)-1;
}
-# endif
+#endif
#ifdef HAVE_ACL
mch_free_acl(acl);
#endif
@@ -3577,9 +3681,8 @@ nofail:
const int attr = HL_ATTR(HLF_E); // Set highlight for error messages.
MSG_PUTS_ATTR(_("\nWARNING: Original file may be lost or damaged\n"),
attr | MSG_HIST);
- MSG_PUTS_ATTR(_(
- "don't quit the editor until the file is successfully written!"),
- attr | MSG_HIST);
+ MSG_PUTS_ATTR(_("don't quit the editor until the file is successfully written!"),
+ attr | MSG_HIST);
/* Update the timestamp to avoid an "overwrite changed file"
* prompt when writing again. */
@@ -3605,7 +3708,7 @@ nofail:
if (!should_abort(retval)) {
aco_save_T aco;
- curbuf->b_no_eol_lnum = 0; /* in case it was set by the previous read */
+ curbuf->b_no_eol_lnum = 0; // in case it was set by the previous read
/*
* Apply POST autocommands.
@@ -3613,24 +3716,26 @@ nofail:
*/
aucmd_prepbuf(&aco, buf);
- if (append)
+ if (append) {
apply_autocmds_exarg(EVENT_FILEAPPENDPOST, fname, fname,
- FALSE, curbuf, eap);
- else if (filtering)
+ FALSE, curbuf, eap);
+ } else if (filtering) {
apply_autocmds_exarg(EVENT_FILTERWRITEPOST, NULL, fname,
- FALSE, curbuf, eap);
- else if (reset_changed && whole)
+ FALSE, curbuf, eap);
+ } else if (reset_changed && whole) {
apply_autocmds_exarg(EVENT_BUFWRITEPOST, fname, fname,
- FALSE, curbuf, eap);
- else
+ FALSE, curbuf, eap);
+ } else {
apply_autocmds_exarg(EVENT_FILEWRITEPOST, fname, fname,
- FALSE, curbuf, eap);
+ FALSE, curbuf, eap);
+ }
- /* restore curwin/curbuf and a few other things */
+ // restore curwin/curbuf and a few other things
aucmd_restbuf(&aco);
- if (aborting()) /* autocmds may abort script processing */
+ if (aborting()) { // autocmds may abort script processing
retval = FALSE;
+ }
}
got_int |= prev_got_int;
@@ -3647,16 +3752,18 @@ nofail:
*/
static int set_rw_fname(char_u *fname, char_u *sfname)
{
- buf_T *buf = curbuf;
+ buf_T *buf = curbuf;
- /* It's like the unnamed buffer is deleted.... */
- if (curbuf->b_p_bl)
- apply_autocmds(EVENT_BUFDELETE, NULL, NULL, FALSE, curbuf);
- apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, FALSE, curbuf);
- if (aborting()) /* autocmds may abort script processing */
+ // It's like the unnamed buffer is deleted....
+ if (curbuf->b_p_bl) {
+ apply_autocmds(EVENT_BUFDELETE, NULL, NULL, false, curbuf);
+ }
+ apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, false, curbuf);
+ if (aborting()) { // autocmds may abort script processing
return FAIL;
+ }
if (curbuf != buf) {
- /* We are in another buffer now, don't do the renaming. */
+ // We are in another buffer now, don't do the renaming.
EMSG(_(e_auchangedbuf));
return FAIL;
}
@@ -3665,14 +3772,16 @@ static int set_rw_fname(char_u *fname, char_u *sfname)
curbuf->b_flags |= BF_NOTEDITED;
}
- /* ....and a new named one is created */
- apply_autocmds(EVENT_BUFNEW, NULL, NULL, FALSE, curbuf);
- if (curbuf->b_p_bl)
- apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, curbuf);
- if (aborting()) /* autocmds may abort script processing */
+ // ....and a new named one is created
+ apply_autocmds(EVENT_BUFNEW, NULL, NULL, false, curbuf);
+ if (curbuf->b_p_bl) {
+ apply_autocmds(EVENT_BUFADD, NULL, NULL, false, curbuf);
+ }
+ if (aborting()) { // autocmds may abort script processing
return FAIL;
+ }
- /* Do filetype detection now if 'filetype' is empty. */
+ // Do filetype detection now if 'filetype' is empty.
if (*curbuf->b_p_ft == NUL) {
if (au_has_group((char_u *)"filetypedetect")) {
(void)do_doautocmd((char_u *)"filetypedetect BufRead", false, NULL);
@@ -3691,8 +3800,8 @@ static int set_rw_fname(char_u *fname, char_u *sfname)
/// @param[in] buf_len ret_buf length.
/// @param[in] buf buf_T file name is coming from.
/// @param[in] fname File name to write.
-static void add_quoted_fname(char *const ret_buf, const size_t buf_len,
- const buf_T *const buf, const char *fname)
+static void add_quoted_fname(char *const ret_buf, const size_t buf_len, const buf_T *const buf,
+ const char *fname)
FUNC_ATTR_NONNULL_ARG(1)
{
if (fname == NULL) {
@@ -3735,25 +3844,26 @@ static bool msg_add_fileformat(int eol_type)
*/
void msg_add_lines(int insert_space, long lnum, off_T nchars)
{
- char_u *p;
+ char_u *p;
p = IObuff + STRLEN(IObuff);
- if (insert_space)
+ if (insert_space) {
*p++ = ' ';
- if (shortmess(SHM_LINES)) {
- sprintf((char *)p, "%" PRId64 "L, %" PRId64 "C",
- (int64_t)lnum, (int64_t)nchars);
}
- else {
- if (lnum == 1)
+ if (shortmess(SHM_LINES)) {
+ sprintf((char *)p, "%" PRId64 "L, %" PRId64 "C",
+ (int64_t)lnum, (int64_t)nchars);
+ } else {
+ if (lnum == 1) {
STRCPY(p, _("1 line, "));
- else
+ } else {
sprintf((char *)p, _("%" PRId64 " lines, "), (int64_t)lnum);
+ }
p += STRLEN(p);
- if (nchars == 1)
+ if (nchars == 1) {
STRCPY(p, _("1 character"));
- else {
+ } else {
sprintf((char *)p, _("%" PRId64 " characters"), (int64_t)nchars);
}
}
@@ -3765,7 +3875,7 @@ void msg_add_lines(int insert_space, long lnum, off_T nchars)
static void msg_add_eol(void)
{
STRCAT(IObuff,
- shortmess(SHM_LAST) ? _("[noeol]") : _("[Incomplete last line]"));
+ shortmess(SHM_LAST) ? _("[noeol]") : _("[Incomplete last line]"));
}
/*
@@ -3816,17 +3926,17 @@ static bool time_differs(long t1, long t2) FUNC_ATTR_CONST
static int buf_write_bytes(struct bw_info *ip)
{
int wlen;
- char_u *buf = ip->bw_buf; /* data to write */
- int len = ip->bw_len; /* length of data */
+ char_u *buf = ip->bw_buf; // data to write
+ int len = ip->bw_len; // length of data
#ifdef HAS_BW_FLAGS
- int flags = ip->bw_flags; /* extra flags */
+ int flags = ip->bw_flags; // extra flags
#endif
/*
* Skip conversion when writing the BOM.
*/
if (!(flags & FIO_NOCONVERT)) {
- char_u *p;
+ char_u *p;
unsigned c;
int n;
@@ -3834,9 +3944,10 @@ static int buf_write_bytes(struct bw_info *ip)
/*
* Convert latin1 in the buffer to UTF-8 in the file.
*/
- p = ip->bw_conv_buf; /* translate to buffer */
- for (wlen = 0; wlen < len; ++wlen)
+ p = ip->bw_conv_buf; // translate to buffer
+ for (wlen = 0; wlen < len; ++wlen) {
p += utf_char2bytes(buf[wlen], p);
+ }
buf = ip->bw_conv_buf;
len = (int)(p - ip->bw_conv_buf);
} else if (flags & (FIO_UCS4 | FIO_UTF16 | FIO_UCS2 | FIO_LATIN1)) {
@@ -3844,10 +3955,11 @@ static int buf_write_bytes(struct bw_info *ip)
* Convert UTF-8 bytes in the buffer to UCS-2, UCS-4, UTF-16 or
* Latin1 chars in the file.
*/
- if (flags & FIO_LATIN1)
- p = buf; /* translate in-place (can only get shorter) */
- else
- p = ip->bw_conv_buf; /* translate to buffer */
+ if (flags & FIO_LATIN1) {
+ p = buf; // translate in-place (can only get shorter)
+ } else {
+ p = ip->bw_conv_buf; // translate to buffer
+ }
for (wlen = 0; wlen < len; wlen += n) {
if (wlen == 0 && ip->bw_restlen != 0) {
int l;
@@ -3856,30 +3968,33 @@ static int buf_write_bytes(struct bw_info *ip)
* buf[] to get a full sequence. Might still be too
* short! */
l = CONV_RESTLEN - ip->bw_restlen;
- if (l > len)
+ if (l > len) {
l = len;
+ }
memmove(ip->bw_rest + ip->bw_restlen, buf, (size_t)l);
n = utf_ptr2len_len(ip->bw_rest, ip->bw_restlen + l);
if (n > ip->bw_restlen + len) {
/* We have an incomplete byte sequence at the end to
* be written. We can't convert it without the
* remaining bytes. Keep them for the next call. */
- if (ip->bw_restlen + len > CONV_RESTLEN)
+ if (ip->bw_restlen + len > CONV_RESTLEN) {
return FAIL;
+ }
ip->bw_restlen += len;
break;
}
- if (n > 1)
+ if (n > 1) {
c = utf_ptr2char(ip->bw_rest);
- else
+ } else {
c = ip->bw_rest[0];
+ }
if (n >= ip->bw_restlen) {
n -= ip->bw_restlen;
ip->bw_restlen = 0;
} else {
ip->bw_restlen -= n;
memmove(ip->bw_rest, ip->bw_rest + n,
- (size_t)ip->bw_restlen);
+ (size_t)ip->bw_restlen);
n = 0;
}
} else {
@@ -3888,42 +4003,45 @@ static int buf_write_bytes(struct bw_info *ip)
/* We have an incomplete byte sequence at the end to
* be written. We can't convert it without the
* remaining bytes. Keep them for the next call. */
- if (len - wlen > CONV_RESTLEN)
+ if (len - wlen > CONV_RESTLEN) {
return FAIL;
+ }
ip->bw_restlen = len - wlen;
memmove(ip->bw_rest, buf + wlen,
- (size_t)ip->bw_restlen);
+ (size_t)ip->bw_restlen);
break;
}
- if (n > 1)
+ if (n > 1) {
c = utf_ptr2char(buf + wlen);
- else
+ } else {
c = buf[wlen];
+ }
}
if (ucs2bytes(c, &p, flags) && !ip->bw_conv_error) {
ip->bw_conv_error = TRUE;
ip->bw_conv_error_lnum = ip->bw_start_lnum;
}
- if (c == NL)
+ if (c == NL) {
++ip->bw_start_lnum;
+ }
}
- if (flags & FIO_LATIN1)
+ if (flags & FIO_LATIN1) {
len = (int)(p - buf);
- else {
+ } else {
buf = ip->bw_conv_buf;
len = (int)(p - ip->bw_conv_buf);
}
}
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
if (ip->bw_iconv_fd != (iconv_t)-1) {
- const char *from;
+ const char *from;
size_t fromlen;
- char *to;
+ char *to;
size_t tolen;
- /* Convert with iconv(). */
+ // Convert with iconv().
if (ip->bw_restlen > 0) {
char *fp;
@@ -3946,7 +4064,7 @@ static int buf_write_bytes(struct bw_info *ip)
if (ip->bw_first) {
size_t save_len = tolen;
- /* output the initial shift state sequence */
+ // output the initial shift state sequence
(void)iconv(ip->bw_iconv_fd, NULL, NULL, &to, &tolen);
/* There is a bug in iconv() on Linux (which appears to be
@@ -3969,15 +4087,16 @@ static int buf_write_bytes(struct bw_info *ip)
return FAIL;
}
- /* copy remainder to ip->bw_rest[] to be used for the next call. */
- if (fromlen > 0)
+ // copy remainder to ip->bw_rest[] to be used for the next call.
+ if (fromlen > 0) {
memmove(ip->bw_rest, (void *)from, fromlen);
+ }
ip->bw_restlen = (int)fromlen;
buf = ip->bw_conv_buf;
len = (int)((char_u *)to - ip->bw_conv_buf);
}
-# endif
+#endif
}
if (ip->bw_fd < 0) {
@@ -3997,7 +4116,7 @@ static int buf_write_bytes(struct bw_info *ip)
/// @return true for an error, false when it's OK.
static bool ucs2bytes(unsigned c, char_u **pp, int flags) FUNC_ATTR_NONNULL_ALL
{
- char_u *p = *pp;
+ char_u *p = *pp;
bool error = false;
int cc;
@@ -4043,12 +4162,13 @@ static bool ucs2bytes(unsigned c, char_u **pp, int flags) FUNC_ATTR_NONNULL_ALL
*p++ = (c >> 8);
*p++ = c;
}
- } else { /* Latin1 */
+ } else { // Latin1
if (c >= 0x100) {
error = true;
*p++ = 0xBF;
- } else
+ } else {
*p++ = c;
+ }
}
*pp = p;
@@ -4103,25 +4223,29 @@ static int get_fio_flags(const char_u *name)
prop = enc_canon_props(name);
if (prop & ENC_UNICODE) {
if (prop & ENC_2BYTE) {
- if (prop & ENC_ENDIAN_L)
+ if (prop & ENC_ENDIAN_L) {
return FIO_UCS2 | FIO_ENDIAN_L;
+ }
return FIO_UCS2;
}
if (prop & ENC_4BYTE) {
- if (prop & ENC_ENDIAN_L)
+ if (prop & ENC_ENDIAN_L) {
return FIO_UCS4 | FIO_ENDIAN_L;
+ }
return FIO_UCS4;
}
if (prop & ENC_2WORD) {
- if (prop & ENC_ENDIAN_L)
+ if (prop & ENC_ENDIAN_L) {
return FIO_UTF16 | FIO_ENDIAN_L;
+ }
return FIO_UTF16;
}
return FIO_UTF8;
}
- if (prop & ENC_LATIN1)
+ if (prop & ENC_LATIN1) {
return FIO_LATIN1;
- /* must be ENC_DBCS, requires iconv() */
+ }
+ // must be ENC_DBCS, requires iconv()
return 0;
}
@@ -4135,34 +4259,37 @@ static int get_fio_flags(const char_u *name)
*/
static char_u *check_for_bom(char_u *p, long size, int *lenp, int flags)
{
- char *name = NULL;
+ char *name = NULL;
int len = 2;
if (p[0] == 0xef && p[1] == 0xbb && size >= 3 && p[2] == 0xbf
&& (flags == FIO_ALL || flags == FIO_UTF8 || flags == 0)) {
- name = "utf-8"; /* EF BB BF */
+ name = "utf-8"; // EF BB BF
len = 3;
} else if (p[0] == 0xff && p[1] == 0xfe) {
if (size >= 4 && p[2] == 0 && p[3] == 0
&& (flags == FIO_ALL || flags == (FIO_UCS4 | FIO_ENDIAN_L))) {
- name = "ucs-4le"; /* FF FE 00 00 */
+ name = "ucs-4le"; // FF FE 00 00
len = 4;
- } else if (flags == (FIO_UCS2 | FIO_ENDIAN_L))
- name = "ucs-2le"; /* FF FE */
- else if (flags == FIO_ALL || flags == (FIO_UTF16 | FIO_ENDIAN_L))
- /* utf-16le is preferred, it also works for ucs-2le text */
- name = "utf-16le"; /* FF FE */
+ } else if (flags == (FIO_UCS2 | FIO_ENDIAN_L)) {
+ name = "ucs-2le"; // FF FE
+ } else if (flags == FIO_ALL ||
+ flags == (FIO_UTF16 | FIO_ENDIAN_L)) {
+ // utf-16le is preferred, it also works for ucs-2le text
+ name = "utf-16le"; // FF FE
+ }
} else if (p[0] == 0xfe && p[1] == 0xff
&& (flags == FIO_ALL || flags == FIO_UCS2 || flags ==
FIO_UTF16)) {
- /* Default to utf-16, it works also for ucs-2 text. */
- if (flags == FIO_UCS2)
- name = "ucs-2"; /* FE FF */
- else
- name = "utf-16"; /* FE FF */
+ // Default to utf-16, it works also for ucs-2 text.
+ if (flags == FIO_UCS2) {
+ name = "ucs-2"; // FE FF
+ } else {
+ name = "utf-16"; // FE FF
+ }
} else if (size >= 4 && p[0] == 0 && p[1] == 0 && p[2] == 0xfe
&& p[3] == 0xff && (flags == FIO_ALL || flags == FIO_UCS4)) {
- name = "ucs-4"; /* 00 00 FE FF */
+ name = "ucs-4"; // 00 00 FE FF
len = 4;
}
@@ -4177,15 +4304,16 @@ static char_u *check_for_bom(char_u *p, long size, int *lenp, int flags)
static int make_bom(char_u *buf, char_u *name)
{
int flags;
- char_u *p;
+ char_u *p;
flags = get_fio_flags(name);
- /* Can't put a BOM in a non-Unicode file. */
- if (flags == FIO_LATIN1 || flags == 0)
+ // Can't put a BOM in a non-Unicode file.
+ if (flags == FIO_LATIN1 || flags == 0) {
return 0;
+ }
- if (flags == FIO_UTF8) { /* UTF-8 */
+ if (flags == FIO_UTF8) { // UTF-8
buf[0] = 0xef;
buf[1] = 0xbb;
buf[2] = 0xbf;
@@ -4205,7 +4333,7 @@ static int make_bom(char_u *buf, char_u *name)
/// name.
void shorten_buf_fname(buf_T *buf, char_u *dirname, int force)
{
- char_u *p;
+ char_u *p;
if (buf->b_fname != NULL
&& !bt_nofile(buf)
@@ -4234,14 +4362,14 @@ void shorten_fnames(int force)
os_dirname(dirname, MAXPATHL);
FOR_ALL_BUFFERS(buf) {
- shorten_buf_fname(buf, dirname, force);
+ shorten_buf_fname(buf, dirname, force);
// Always make the swap file name a full path, a "nofile" buffer may
// also have a swap file.
mf_fullname(buf->b_ml.ml_mfp);
}
status_redraw_all();
- redraw_tabline = TRUE;
+ redraw_tabline = true;
}
/// Get new filename ended by given extension.
@@ -4507,11 +4635,11 @@ int vim_rename(const char_u *from, const char_u *to)
int fd_in;
int fd_out;
int n;
- char *errmsg = NULL;
- char *buffer;
+ char *errmsg = NULL;
+ char *buffer;
long perm;
#ifdef HAVE_ACL
- vim_acl_T acl; /* ACL from original file */
+ vim_acl_T acl; // ACL from original file
#endif
bool use_tmp_file = false;
@@ -4551,8 +4679,9 @@ int vim_rename(const char_u *from, const char_u *to)
* Find a name that doesn't exist and is in the same directory.
* Rename "from" to "tempname" and then rename "tempname" to "to".
*/
- if (STRLEN(from) >= MAXPATHL - 5)
+ if (STRLEN(from) >= MAXPATHL - 5) {
return -1;
+ }
STRCPY(tempname, from);
for (n = 123; n < 99999; n++) {
char * tail = (char *)path_tail(tempname);
@@ -4587,8 +4716,9 @@ int vim_rename(const char_u *from, const char_u *to)
/*
* First try a normal rename, return if it works.
*/
- if (os_rename(from, to) == OK)
+ if (os_rename(from, to) == OK) {
return 0;
+ }
/*
* Rename() failed, try copying the file.
@@ -4606,9 +4736,9 @@ int vim_rename(const char_u *from, const char_u *to)
return -1;
}
- /* Create the new file with same permissions as the original. */
+ // Create the new file with same permissions as the original.
fd_out = os_open((char *)to,
- O_CREAT|O_EXCL|O_WRONLY|O_NOFOLLOW, (int)perm);
+ O_CREAT|O_EXCL|O_WRONLY|O_NOFOLLOW, (int)perm);
if (fd_out < 0) {
close(fd_in);
#ifdef HAVE_ACL
@@ -4629,16 +4759,18 @@ int vim_rename(const char_u *from, const char_u *to)
return -1;
}
- while ((n = read_eintr(fd_in, buffer, BUFSIZE)) > 0)
+ while ((n = read_eintr(fd_in, buffer, BUFSIZE)) > 0) {
if (write_eintr(fd_out, buffer, n) != n) {
errmsg = _("E208: Error writing to \"%s\"");
break;
}
+ }
xfree(buffer);
close(fd_in);
- if (close(fd_out) < 0)
+ if (close(fd_out) < 0) {
errmsg = _("E209: Error closing \"%s\"");
+ }
if (n < 0) {
errmsg = _("E210: Error reading \"%s\"");
to = from;
@@ -4660,23 +4792,23 @@ int vim_rename(const char_u *from, const char_u *to)
static int already_warned = FALSE;
-// Check if any not hidden buffer has been changed.
-// Postpone the check if there are characters in the stuff buffer, a global
-// command is being executed, a mapping is being executed or an autocommand is
-// busy.
-// Returns TRUE if some message was written (screen should be redrawn and
-// cursor positioned).
-int
-check_timestamps(
- int focus // called for GUI focus event
-)
+/// Check if any not hidden buffer has been changed.
+/// Postpone the check if there are characters in the stuff buffer, a global
+/// command is being executed, a mapping is being executed or an autocommand is
+/// busy.
+///
+/// @param focus called for GUI focus event
+///
+/// @return TRUE if some message was written (screen should be redrawn and cursor positioned).
+int check_timestamps(int focus)
{
int didit = 0;
/* Don't check timestamps while system() or another low-level function may
* cause us to lose and gain focus. */
- if (no_check_timestamps > 0)
+ if (no_check_timestamps > 0) {
return FALSE;
+ }
/* Avoid doing a check twice. The OK/Reload dialog can cause a focus
* event and we would keep on checking if the file is steadily growing.
@@ -4687,8 +4819,8 @@ check_timestamps(
}
if (!stuff_empty() || global_busy || !typebuf_typed()
- || autocmd_busy || curbuf_lock > 0 || allbuf_lock > 0
- ) {
+ || autocmd_busy || curbuf->b_ro_locked > 0 ||
+ allbuf_lock > 0) {
need_check_timestamps = true; // check later
} else {
no_wait_return++;
@@ -4728,12 +4860,12 @@ check_timestamps(
*/
static int move_lines(buf_T *frombuf, buf_T *tobuf)
{
- buf_T *tbuf = curbuf;
+ buf_T *tbuf = curbuf;
int retval = OK;
linenr_T lnum;
- char_u *p;
+ char_u *p;
- /* Copy the lines in "frombuf" to "tobuf". */
+ // Copy the lines in "frombuf" to "tobuf".
curbuf = tobuf;
for (lnum = 1; lnum <= frombuf->b_ml.ml_line_count; lnum++) {
p = vim_strsave(ml_get_buf(frombuf, lnum, false));
@@ -4745,7 +4877,7 @@ static int move_lines(buf_T *frombuf, buf_T *tobuf)
xfree(p);
}
- /* Delete all the lines in "frombuf". */
+ // Delete all the lines in "frombuf".
if (retval != FAIL) {
curbuf = frombuf;
for (lnum = curbuf->b_ml.ml_line_count; lnum > 0; lnum--) {
@@ -4773,17 +4905,17 @@ int buf_check_timestamp(buf_T *buf)
FUNC_ATTR_NONNULL_ALL
{
int retval = 0;
- char_u *path;
- char *mesg = NULL;
- char *mesg2 = "";
+ char_u *path;
+ char *mesg = NULL;
+ char *mesg2 = "";
bool helpmesg = false;
bool reload = false;
bool can_reload = false;
uint64_t orig_size = buf->b_orig_size;
int orig_mode = buf->b_orig_mode;
static bool busy = false;
- char_u *s;
- char *reason;
+ char_u *s;
+ char *reason;
bufref_T bufref;
set_bufref(&bufref, buf);
@@ -4796,9 +4928,9 @@ int buf_check_timestamp(buf_T *buf)
|| buf->b_ml.ml_mfp == NULL
|| !bt_normal(buf)
|| buf->b_saving
- || busy
- )
+ || busy) {
return 0;
+ }
FileInfo file_info;
bool file_info_ok;
@@ -4884,24 +5016,22 @@ int buf_check_timestamp(buf_T *buf)
// changed.
if (reason[2] == 'n') {
mesg = _(
- "W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as well");
+ "W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as well");
mesg2 = _("See \":help W12\" for more info.");
} else if (reason[1] == 'h') {
- mesg = _(
- "W11: Warning: File \"%s\" has changed since editing started");
+ mesg = _("W11: Warning: File \"%s\" has changed since editing started");
mesg2 = _("See \":help W11\" for more info.");
} else if (*reason == 'm') {
- mesg = _(
- "W16: Warning: Mode of file \"%s\" has changed since editing started");
+ mesg = _("W16: Warning: Mode of file \"%s\" has changed since editing started");
mesg2 = _("See \":help W16\" for more info.");
- } else
+ } else {
/* Only timestamp changed, store it to avoid a warning
* in check_mtime() later. */
buf->b_mtime_read = buf->b_mtime;
+ }
}
}
}
-
} else if ((buf->b_flags & BF_NEW) && !(buf->b_flags & BF_NEW_W)
&& os_path_exists(buf->b_ffname)) {
retval = 1;
@@ -4926,8 +5056,8 @@ int buf_check_timestamp(buf_T *buf)
xstrlcat(tbuf, "\n", tbuf_len - 1);
xstrlcat(tbuf, mesg2, tbuf_len - 1);
}
- if (do_dialog(VIM_WARNING, (char_u *) _("Warning"), (char_u *) tbuf,
- (char_u *) _("&OK\n&Load File"), 1, NULL, true) == 2) {
+ if (do_dialog(VIM_WARNING, (char_u *)_("Warning"), (char_u *)tbuf,
+ (char_u *)_("&OK\n&Load File"), 1, NULL, true) == 2) {
reload = true;
}
} else if (State > NORMAL_BUSY || (State & CMDLINE) || already_warned) {
@@ -4963,17 +5093,14 @@ int buf_check_timestamp(buf_T *buf)
}
if (reload) {
- /* Reload the buffer. */
+ // Reload the buffer.
buf_reload(buf, orig_mode);
if (buf->b_p_udf && buf->b_ffname != NULL) {
char_u hash[UNDO_HASH_SIZE];
- buf_T *save_curbuf = curbuf;
- /* Any existing undo file is unusable, write it now. */
- curbuf = buf;
- u_compute_hash(hash);
- u_write_undo(NULL, FALSE, buf, hash);
- curbuf = save_curbuf;
+ // Any existing undo file is unusable, write it now.
+ u_compute_hash(buf, hash);
+ u_write_undo(NULL, false, buf, hash);
}
}
@@ -4997,13 +5124,13 @@ void buf_reload(buf_T *buf, int orig_mode)
pos_T old_cursor;
linenr_T old_topline;
int old_ro = buf->b_p_ro;
- buf_T *savebuf;
+ buf_T *savebuf;
bufref_T bufref;
int saved = OK;
aco_save_T aco;
int flags = READ_NEW;
- /* set curwin/curbuf for "buf" and save some things */
+ // set curwin/curbuf for "buf" and save some things
aucmd_prepbuf(&aco, buf);
// We only want to read the text from the file, not reset the syntax
@@ -5015,10 +5142,10 @@ void buf_reload(buf_T *buf, int orig_mode)
old_topline = curwin->w_topline;
if (p_ur < 0 || curbuf->b_ml.ml_line_count <= p_ur) {
- /* Save all the text, so that the reload can be undone.
- * Sync first so that this is a separate undo-able action. */
- u_sync(FALSE);
- saved = u_savecommon(0, curbuf->b_ml.ml_line_count + 1, 0, TRUE);
+ // Save all the text, so that the reload can be undone.
+ // Sync first so that this is a separate undo-able action.
+ u_sync(false);
+ saved = u_savecommon(curbuf, 0, curbuf->b_ml.ml_line_count + 1, 0, true);
flags |= READ_KEEP_UNDO;
}
@@ -5027,14 +5154,14 @@ void buf_reload(buf_T *buf, int orig_mode)
// buffer contents. But if reading the file fails we should keep
// the old contents. Can't use memory only, the file might be
// too big. Use a hidden buffer to move the buffer contents to.
- if (BUFEMPTY() || saved == FAIL) {
+ if (buf_is_empty(curbuf) || saved == FAIL) {
savebuf = NULL;
} else {
// Allocate a buffer without putting it in the buffer list.
savebuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
set_bufref(&bufref, savebuf);
if (savebuf != NULL && buf == curbuf) {
- /* Open the memline. */
+ // Open the memline.
curbuf = savebuf;
curwin->w_buffer = savebuf;
saved = ml_open(curbuf);
@@ -5044,7 +5171,7 @@ void buf_reload(buf_T *buf, int orig_mode)
if (savebuf == NULL || saved == FAIL || buf != curbuf
|| move_lines(buf, savebuf) == FAIL) {
EMSG2(_("E462: Could not prepare for reloading \"%s\""),
- buf->b_fname);
+ buf->b_fname);
saved = FAIL;
}
}
@@ -5060,7 +5187,7 @@ void buf_reload(buf_T *buf, int orig_mode)
if (savebuf != NULL && bufref_valid(&bufref) && buf == curbuf) {
// Put the text back from the save buffer. First
// delete any lines that readfile() added.
- while (!BUFEMPTY()) {
+ while (!buf_is_empty(curbuf)) {
if (ml_delete(buf->b_ml.ml_line_count, false) == FAIL) {
break;
}
@@ -5087,21 +5214,22 @@ void buf_reload(buf_T *buf, int orig_mode)
wipe_buffer(savebuf, false);
}
- /* Invalidate diff info if necessary. */
+ // Invalidate diff info if necessary.
diff_invalidate(curbuf);
/* Restore the topline and cursor position and check it (lines may
* have been removed). */
- if (old_topline > curbuf->b_ml.ml_line_count)
+ if (old_topline > curbuf->b_ml.ml_line_count) {
curwin->w_topline = curbuf->b_ml.ml_line_count;
- else
+ } else {
curwin->w_topline = old_topline;
+ }
curwin->w_cursor = old_cursor;
check_cursor();
update_topline(curwin);
keep_filetype = false;
- /* Update folds unless they are defined manually. */
+ // Update folds unless they are defined manually.
FOR_ALL_TAB_WINDOWS(tp, wp) {
if (wp->w_buffer == curwin->w_buffer
&& !foldmethodIsManual(wp)) {
@@ -5112,15 +5240,16 @@ void buf_reload(buf_T *buf, int orig_mode)
/* If the mode didn't change and 'readonly' was set, keep the old
* value; the user probably used the ":view" command. But don't
* reset it, might have had a read error. */
- if (orig_mode == curbuf->b_orig_mode)
+ if (orig_mode == curbuf->b_orig_mode) {
curbuf->b_p_ro |= old_ro;
+ }
- /* Modelines must override settings done by autocommands. */
+ // Modelines must override settings done by autocommands.
do_modelines(0);
- /* restore curwin/curbuf and a few other things */
+ // restore curwin/curbuf and a few other things
aucmd_restbuf(&aco);
- /* Careful: autocommands may have made "buf" invalid! */
+ // Careful: autocommands may have made "buf" invalid!
}
void buf_store_file_info(buf_T *buf, FileInfo *file_info)
@@ -5137,8 +5266,9 @@ void buf_store_file_info(buf_T *buf, FileInfo *file_info)
*/
void write_lnum_adjust(linenr_T offset)
{
- if (curbuf->b_no_eol_lnum != 0) /* only if there is a missing eol */
+ if (curbuf->b_no_eol_lnum != 0) { // only if there is a missing eol
curbuf->b_no_eol_lnum += offset;
+ }
}
#if defined(BACKSLASH_IN_FILENAME)
@@ -5146,7 +5276,7 @@ void write_lnum_adjust(linenr_T offset)
/// unless when it looks like a URL.
void forward_slash(char_u *fname)
{
- char_u *p;
+ char_u *p;
if (path_with_url((const char *)fname)) {
return;
@@ -5321,18 +5451,19 @@ char_u *vim_tempname(void)
/// @param allow_dirs Allow matching with dir
///
/// @return true if there is a match, false otherwise
-bool match_file_pat(char_u *pattern, regprog_T **prog, char_u *fname,
- char_u *sfname, char_u *tail, int allow_dirs)
+bool match_file_pat(char_u *pattern, regprog_T **prog, char_u *fname, char_u *sfname, char_u *tail,
+ int allow_dirs)
{
regmatch_T regmatch;
bool result = false;
- regmatch.rm_ic = p_fic; /* ignore case if 'fileignorecase' is set */
+ regmatch.rm_ic = p_fic; // ignore case if 'fileignorecase' is set
{
- if (prog != NULL)
+ if (prog != NULL) {
regmatch.regprog = *prog;
- else
+ } else {
regmatch.regprog = vim_regcomp(pattern, RE_MAGIC);
+ }
}
/*
@@ -5371,11 +5502,11 @@ bool match_file_list(char_u *list, char_u *sfname, char_u *ffname)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1, 3)
{
char_u buf[100];
- char_u *tail;
- char_u *regpat;
+ char_u *tail;
+ char_u *regpat;
char allow_dirs;
bool match;
- char_u *p;
+ char_u *p;
tail = path_tail(sfname);
@@ -5402,25 +5533,27 @@ bool match_file_list(char_u *list, char_u *sfname, char_u *ffname)
/// allow_dirs, otherwise FALSE is put there -- webb.
/// Handle backslashes before special characters, like "\*" and "\ ".
///
-/// Returns NULL on failure.
-char_u * file_pat_to_reg_pat(
- const char_u *pat,
- const char_u *pat_end, // first char after pattern or NULL
- char *allow_dirs, // Result passed back out in here
- int no_bslash // Don't use a backward slash as pathsep
-)
+/// @param pat_end first char after pattern or NULL
+/// @param allow_dirs Result passed back out in here
+/// @param no_bslash Don't use a backward slash as pathsep
+///
+/// @return NULL on failure.
+char_u *file_pat_to_reg_pat(const char_u *pat, const char_u *pat_end, char *allow_dirs,
+ int no_bslash)
FUNC_ATTR_NONNULL_ARG(1)
{
const char_u *endp;
- char_u *reg_pat;
+ char_u *reg_pat;
const char_u *p;
int nested = 0;
- int add_dollar = TRUE;
+ bool add_dollar = true;
- if (allow_dirs != NULL)
+ if (allow_dirs != NULL) {
*allow_dirs = FALSE;
- if (pat_end == NULL)
+ }
+ if (pat_end == NULL) {
pat_end = pat + STRLEN(pat);
+ }
if (pat_end == pat) {
return (char_u *)xstrdup("^$");
@@ -5436,12 +5569,12 @@ char_u * file_pat_to_reg_pat(
case '{':
case '}':
case '~':
- size += 2; /* extra backslash */
+ size += 2; // extra backslash
break;
#ifdef BACKSLASH_IN_FILENAME
case '\\':
case '/':
- size += 4; /* could become "[\/]" */
+ size += 4; // could become "[\/]"
break;
#endif
default:
@@ -5453,11 +5586,13 @@ char_u * file_pat_to_reg_pat(
size_t i = 0;
- if (pat[0] == '*')
- while (pat[0] == '*' && pat < pat_end - 1)
+ if (pat[0] == '*') {
+ while (pat[0] == '*' && pat < pat_end - 1) {
pat++;
- else
+ }
+ } else {
reg_pat[i++] = '^';
+ }
endp = pat_end - 1;
if (endp >= pat && *endp == '*') {
while (endp - pat > 0 && *endp == '*') {
@@ -5470,8 +5605,9 @@ char_u * file_pat_to_reg_pat(
case '*':
reg_pat[i++] = '.';
reg_pat[i++] = '*';
- while (p[1] == '*') /* "**" matches like "*" */
+ while (p[1] == '*') { // "**" matches like "*"
++p;
+ }
break;
case '.':
case '~':
@@ -5482,8 +5618,9 @@ char_u * file_pat_to_reg_pat(
reg_pat[i++] = '.';
break;
case '\\':
- if (p[1] == NUL)
+ if (p[1] == NUL) {
break;
+ }
#ifdef BACKSLASH_IN_FILENAME
if (!no_bslash) {
/* translate:
@@ -5498,8 +5635,9 @@ char_u * file_pat_to_reg_pat(
reg_pat[i++] = '\\';
reg_pat[i++] = '/';
reg_pat[i++] = ']';
- if (allow_dirs != NULL)
+ if (allow_dirs != NULL) {
*allow_dirs = TRUE;
+ }
break;
}
}
@@ -5532,8 +5670,9 @@ char_u * file_pat_to_reg_pat(
#ifdef BACKSLASH_IN_FILENAME
&& (!no_bslash || *p != '\\')
#endif
- )
+ ) {
*allow_dirs = TRUE;
+ }
reg_pat[i++] = '\\';
reg_pat[i++] = *p;
}
@@ -5544,8 +5683,9 @@ char_u * file_pat_to_reg_pat(
reg_pat[i++] = '\\';
reg_pat[i++] = '/';
reg_pat[i++] = ']';
- if (allow_dirs != NULL)
+ if (allow_dirs != NULL) {
*allow_dirs = TRUE;
+ }
break;
#endif
case '{':
@@ -5562,8 +5702,9 @@ char_u * file_pat_to_reg_pat(
if (nested) {
reg_pat[i++] = '\\';
reg_pat[i++] = '|';
- } else
+ } else {
reg_pat[i++] = ',';
+ }
break;
default:
if (allow_dirs != NULL && vim_ispathsep(*p)) {
@@ -5573,8 +5714,9 @@ char_u * file_pat_to_reg_pat(
break;
}
}
- if (add_dollar)
+ if (add_dollar) {
reg_pat[i++] = '$';
+ }
reg_pat[i] = NUL;
if (nested != 0) {
if (nested < 0) {
@@ -5598,8 +5740,9 @@ long read_eintr(int fd, void *buf, size_t bufsize)
for (;; ) {
ret = read(fd, buf, bufsize);
- if (ret >= 0 || errno != EINTR)
+ if (ret >= 0 || errno != EINTR) {
break;
+ }
}
return ret;
}
@@ -5618,10 +5761,12 @@ long write_eintr(int fd, void *buf, size_t bufsize)
while (ret < (long)bufsize) {
wlen = write(fd, (char *)buf + ret, bufsize - ret);
if (wlen < 0) {
- if (errno != EINTR)
+ if (errno != EINTR) {
break;
- } else
+ }
+ } else {
ret += wlen;
+ }
}
return ret;
}
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index ad8418034a..06b8049176 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -7,12 +7,11 @@
* fold.c: code for folding
*/
-#include <string.h>
#include <inttypes.h>
+#include <string.h>
-#include "nvim/vim.h"
#include "nvim/ascii.h"
-#include "nvim/fold.h"
+#include "nvim/buffer_updates.h"
#include "nvim/change.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
@@ -20,26 +19,28 @@
#include "nvim/eval.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_session.h"
+#include "nvim/extmark.h"
+#include "nvim/fold.h"
#include "nvim/func_attr.h"
+#include "nvim/garray.h"
#include "nvim/indent.h"
-#include "nvim/buffer_updates.h"
-#include "nvim/extmark.h"
#include "nvim/mark.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
-#include "nvim/garray.h"
#include "nvim/move.h"
+#include "nvim/ops.h"
#include "nvim/option.h"
+#include "nvim/plines.h"
#include "nvim/screen.h"
#include "nvim/strings.h"
#include "nvim/syntax.h"
#include "nvim/undo.h"
-#include "nvim/ops.h"
+#include "nvim/vim.h"
-/* local declarations. {{{1 */
-/* typedef fold_T {{{2 */
+// local declarations. {{{1
+// typedef fold_T {{{2
/*
* The toplevel folds for each window are stored in the w_folds growarray.
* Each toplevel fold can contain an array of second level folds in the
@@ -57,20 +58,20 @@ typedef struct {
// folds too
} fold_T;
-#define FD_OPEN 0 /* fold is open (nested ones can be closed) */
-#define FD_CLOSED 1 /* fold is closed */
-#define FD_LEVEL 2 /* depends on 'foldlevel' (nested folds too) */
+#define FD_OPEN 0 // fold is open (nested ones can be closed)
+#define FD_CLOSED 1 // fold is closed
+#define FD_LEVEL 2 // depends on 'foldlevel' (nested folds too)
-#define MAX_LEVEL 20 /* maximum fold depth */
+#define MAX_LEVEL 20 // maximum fold depth
-/* Define "fline_T", passed to get fold level for a line. {{{2 */
+// Define "fline_T", passed to get fold level for a line. {{{2
typedef struct {
- win_T *wp; /* window */
- linenr_T lnum; /* current line number */
- linenr_T off; /* offset between lnum and real line number */
- linenr_T lnum_save; /* line nr used by foldUpdateIEMSRecurse() */
- int lvl; /* current level (-1 for undefined) */
- int lvl_next; /* level used for next line */
+ win_T *wp; // window
+ linenr_T lnum; // current line number
+ linenr_T off; // offset between lnum and real line number
+ linenr_T lnum_save; // line nr used by foldUpdateIEMSRecurse()
+ int lvl; // current level (-1 for undefined)
+ int lvl_next; // level used for next line
int start; /* number of folds that are forced to start at
this line. */
int end; /* level of fold that is forced to end below
@@ -82,10 +83,10 @@ typedef struct {
// Flag is set when redrawing is needed.
static bool fold_changed;
-/* Function used by foldUpdateIEMSRecurse */
+// Function used by foldUpdateIEMSRecurse
typedef void (*LevelGetter)(fline_T *);
-/* static functions {{{2 */
+// static functions {{{2
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "fold.c.generated.h"
@@ -109,17 +110,17 @@ static linenr_T invalid_bot = (linenr_T)0;
static linenr_T prev_lnum = 0;
static int prev_lnum_lvl = -1;
-/* Flags used for "done" argument of setManualFold. */
+// Flags used for "done" argument of setManualFold.
#define DONE_NOTHING 0
-#define DONE_ACTION 1 /* did close or open a fold */
-#define DONE_FOLD 2 /* did find a fold */
+#define DONE_ACTION 1 // did close or open a fold
+#define DONE_FOLD 2 // did find a fold
static size_t foldstartmarkerlen;
static char_u *foldendmarker;
static size_t foldendmarkerlen;
-/* Exported folding functions. {{{1 */
-/* copyFoldingState() {{{2 */
+// Exported folding functions. {{{1
+// copyFoldingState() {{{2
/*
* Copy that folding state from window "wp_from" to window "wp_to".
*/
@@ -130,24 +131,22 @@ void copyFoldingState(win_T *wp_from, win_T *wp_to)
cloneFoldGrowArray(&wp_from->w_folds, &wp_to->w_folds);
}
-/* hasAnyFolding() {{{2 */
+// hasAnyFolding() {{{2
/*
* Return TRUE if there may be folded lines in the current window.
*/
int hasAnyFolding(win_T *win)
{
- /* very simple now, but can become more complex later */
+ // very simple now, but can become more complex later
return !win->w_buffer->terminal && win->w_p_fen
&& (!foldmethodIsManual(win) || !GA_EMPTY(&win->w_folds));
}
-/* hasFolding() {{{2 */
-/*
- * Return TRUE if line "lnum" in the current window is part of a closed
- * fold.
- * When returning TRUE, *firstp and *lastp are set to the first and last
- * lnum of the sequence of folded lines (skipped when NULL).
- */
+// hasFolding() {{{2
+/// When returning true, *firstp and *lastp are set to the first and last
+/// lnum of the sequence of folded lines (skipped when NULL).
+///
+/// @return true if line "lnum" in the current window is part of a closed fold.
bool hasFolding(linenr_T lnum, linenr_T *firstp, linenr_T *lastp)
{
return hasFoldingWin(curwin, lnum, firstp, lastp, true, NULL);
@@ -162,20 +161,14 @@ bool hasFolding(linenr_T lnum, linenr_T *firstp, linenr_T *lastp)
/// @param[out] infop where to store fold info
///
/// @return true if range contains folds
-bool hasFoldingWin(
- win_T *const win,
- const linenr_T lnum,
- linenr_T *const firstp,
- linenr_T *const lastp,
- const bool cache,
- foldinfo_T *const infop
-)
+bool hasFoldingWin(win_T *const win, const linenr_T lnum, linenr_T *const firstp,
+ linenr_T *const lastp, const bool cache, foldinfo_T *const infop)
{
bool had_folded = false;
linenr_T first = 0;
linenr_T last = 0;
linenr_T lnum_rel = lnum;
- fold_T *fp;
+ fold_T *fp;
int level = 0;
bool use_level = false;
bool maybe_small = false;
@@ -185,8 +178,9 @@ bool hasFoldingWin(
// Return quickly when there is no folding at all in this window.
if (!hasAnyFolding(win)) {
- if (infop != NULL)
+ if (infop != NULL) {
infop->fi_level = 0;
+ }
return false;
}
@@ -209,21 +203,23 @@ bool hasFoldingWin(
*/
garray_T *gap = &win->w_folds;
for (;; ) {
- if (!foldFind(gap, lnum_rel, &fp))
+ if (!foldFind(gap, lnum_rel, &fp)) {
break;
+ }
- /* Remember lowest level of fold that starts in "lnum". */
- if (lnum_rel == fp->fd_top && low_level == 0)
+ // Remember lowest level of fold that starts in "lnum".
+ if (lnum_rel == fp->fd_top && low_level == 0) {
low_level = level + 1;
+ }
first += fp->fd_top;
last += fp->fd_top;
- /* is this fold closed? */
+ // is this fold closed?
had_folded = check_closed(win, fp, &use_level, level,
- &maybe_small, lnum - lnum_rel);
+ &maybe_small, lnum - lnum_rel);
if (had_folded) {
- /* Fold closed: Set last and quit loop. */
+ // Fold closed: Set last and quit loop.
last += fp->fd_len - 1;
break;
}
@@ -248,10 +244,12 @@ bool hasFoldingWin(
if (last > win->w_buffer->b_ml.ml_line_count) {
last = win->w_buffer->b_ml.ml_line_count;
}
- if (lastp != NULL)
+ if (lastp != NULL) {
*lastp = last;
- if (firstp != NULL)
+ }
+ if (firstp != NULL) {
*firstp = first;
+ }
if (infop != NULL) {
infop->fi_level = level + 1;
infop->fi_lnum = first;
@@ -260,7 +258,7 @@ bool hasFoldingWin(
return true;
}
-/* foldLevel() {{{2 */
+// foldLevel() {{{2
/*
* Return fold level at line number "lnum" in the current window.
*/
@@ -268,16 +266,18 @@ int foldLevel(linenr_T lnum)
{
/* While updating the folds lines between invalid_top and invalid_bot have
* an undefined fold level. Otherwise update the folds first. */
- if (invalid_top == (linenr_T)0)
+ if (invalid_top == (linenr_T)0) {
checkupdate(curwin);
- else if (lnum == prev_lnum && prev_lnum_lvl >= 0)
+ } else if (lnum == prev_lnum && prev_lnum_lvl >= 0) {
return prev_lnum_lvl;
- else if (lnum >= invalid_top && lnum <= invalid_bot)
+ } else if (lnum >= invalid_top && lnum <= invalid_bot) {
return -1;
+ }
- /* Return quickly when there is no folding at all in this window. */
- if (!hasAnyFolding(curwin))
+ // Return quickly when there is no folding at all in this window.
+ if (!hasAnyFolding(curwin)) {
return 0;
+ }
return foldLevelWin(curwin, lnum);
}
@@ -307,7 +307,7 @@ foldinfo_T fold_info(win_T *win, linenr_T lnum)
linenr_T last;
if (hasFoldingWin(win, lnum, NULL, &last, false, &info)) {
- info.fi_lines = (long)(last - lnum + 1);
+ info.fi_lines = (last - lnum + 1);
} else {
info.fi_lines = 0;
}
@@ -315,7 +315,7 @@ foldinfo_T fold_info(win_T *win, linenr_T lnum)
return info;
}
-/* foldmethodIsManual() {{{2 */
+// foldmethodIsManual() {{{2
/*
* Return TRUE if 'foldmethod' is "manual"
*/
@@ -324,7 +324,7 @@ int foldmethodIsManual(win_T *wp)
return wp->w_p_fdm[3] == 'u';
}
-/* foldmethodIsIndent() {{{2 */
+// foldmethodIsIndent() {{{2
/*
* Return TRUE if 'foldmethod' is "indent"
*/
@@ -333,7 +333,7 @@ int foldmethodIsIndent(win_T *wp)
return wp->w_p_fdm[0] == 'i';
}
-/* foldmethodIsExpr() {{{2 */
+// foldmethodIsExpr() {{{2
/*
* Return TRUE if 'foldmethod' is "expr"
*/
@@ -342,7 +342,7 @@ int foldmethodIsExpr(win_T *wp)
return wp->w_p_fdm[1] == 'x';
}
-/* foldmethodIsMarker() {{{2 */
+// foldmethodIsMarker() {{{2
/*
* Return TRUE if 'foldmethod' is "marker"
*/
@@ -351,7 +351,7 @@ int foldmethodIsMarker(win_T *wp)
return wp->w_p_fdm[2] == 'r';
}
-/* foldmethodIsSyntax() {{{2 */
+// foldmethodIsSyntax() {{{2
/*
* Return TRUE if 'foldmethod' is "syntax"
*/
@@ -360,7 +360,7 @@ int foldmethodIsSyntax(win_T *wp)
return wp->w_p_fdm[0] == 's';
}
-/* foldmethodIsDiff() {{{2 */
+// foldmethodIsDiff() {{{2
/*
* Return TRUE if 'foldmethod' is "diff"
*/
@@ -377,7 +377,7 @@ void closeFold(pos_T pos, long count)
setFoldRepeat(pos, count, false);
}
-/* closeFoldRecurse() {{{2 */
+// closeFoldRecurse() {{{2
/*
* Close fold for current window at line "lnum" recursively.
*/
@@ -386,19 +386,15 @@ void closeFoldRecurse(pos_T pos)
(void)setManualFold(pos, false, true, NULL);
}
-/* opFoldRange() {{{2 */
-/*
- * Open or Close folds for current window in lines "first" to "last".
- * Used for "zo", "zO", "zc" and "zC" in Visual mode.
- */
-void
-opFoldRange(
- pos_T firstpos,
- pos_T lastpos,
- int opening, // TRUE to open, FALSE to close
- int recurse, // TRUE to do it recursively
- int had_visual // TRUE when Visual selection used
-)
+// opFoldRange() {{{2
+///
+/// Open or Close folds for current window in lines "first" to "last".
+/// Used for "zo", "zO", "zc" and "zC" in Visual mode.
+///
+/// @param opening TRUE to open, FALSE to close
+/// @param recurse TRUE to do it recursively
+/// @param had_visual TRUE when Visual selection used
+void opFoldRange(pos_T firstpos, pos_T lastpos, int opening, int recurse, int had_visual)
{
int done = DONE_NOTHING; // avoid error messages
linenr_T first = firstpos.lnum;
@@ -411,8 +407,9 @@ opFoldRange(
lnum_next = lnum;
/* Opening one level only: next fold to open is after the one going to
* be opened. */
- if (opening && !recurse)
+ if (opening && !recurse) {
(void)hasFolding(lnum, NULL, &lnum_next);
+ }
(void)setManualFold(temp, opening, recurse, &done);
// Closing one level only: next line to close a fold is after just
// closed fold.
@@ -420,14 +417,16 @@ opFoldRange(
(void)hasFolding(lnum, NULL, &lnum_next);
}
}
- if (done == DONE_NOTHING)
+ if (done == DONE_NOTHING) {
EMSG(_(e_nofold));
- /* Force a redraw to remove the Visual highlighting. */
- if (had_visual)
+ }
+ // Force a redraw to remove the Visual highlighting.
+ if (had_visual) {
redraw_curbuf_later(INVERTED);
+ }
}
-/* openFold() {{{2 */
+// openFold() {{{2
/*
* Open fold for current window at line "lnum".
* Repeat "count" times.
@@ -437,7 +436,7 @@ void openFold(pos_T pos, long count)
setFoldRepeat(pos, count, true);
}
-/* openFoldRecurse() {{{2 */
+// openFoldRecurse() {{{2
/*
* Open fold for current window at line "lnum" recursively.
*/
@@ -446,7 +445,7 @@ void openFoldRecurse(pos_T pos)
(void)setManualFold(pos, true, true, NULL);
}
-/* foldOpenCursor() {{{2 */
+// foldOpenCursor() {{{2
/*
* Open folds until the cursor line is not in a closed fold.
*/
@@ -455,7 +454,7 @@ void foldOpenCursor(void)
int done;
checkupdate(curwin);
- if (hasAnyFolding(curwin))
+ if (hasAnyFolding(curwin)) {
for (;; ) {
done = DONE_NOTHING;
(void)setManualFold(curwin->w_cursor, true, false, &done);
@@ -463,9 +462,10 @@ void foldOpenCursor(void)
break;
}
}
+ }
}
-/* newFoldLevel() {{{2 */
+// newFoldLevel() {{{2
/*
* Set new foldlevel for current window.
*/
@@ -488,7 +488,7 @@ void newFoldLevel(void)
static void newFoldLevelWin(win_T *wp)
{
- fold_T *fp;
+ fold_T *fp;
checkupdate(wp);
if (wp->w_fold_manual) {
@@ -496,62 +496,65 @@ static void newFoldLevelWin(win_T *wp)
* manual open/close will then change the flags to FD_OPEN or
* FD_CLOSED for those folds that don't use 'foldlevel'. */
fp = (fold_T *)wp->w_folds.ga_data;
- for (int i = 0; i < wp->w_folds.ga_len; ++i)
+ for (int i = 0; i < wp->w_folds.ga_len; ++i) {
fp[i].fd_flags = FD_LEVEL;
+ }
wp->w_fold_manual = false;
}
changed_window_setting_win(wp);
}
-/* foldCheckClose() {{{2 */
+// foldCheckClose() {{{2
/*
* Apply 'foldlevel' to all folds that don't contain the cursor.
*/
void foldCheckClose(void)
{
- if (*p_fcl != NUL) { /* can only be "all" right now */
+ if (*p_fcl != NUL) { // can only be "all" right now
checkupdate(curwin);
if (checkCloseRec(&curwin->w_folds, curwin->w_cursor.lnum,
- (int)curwin->w_p_fdl))
+ (int)curwin->w_p_fdl)) {
changed_window_setting();
+ }
}
}
-/* checkCloseRec() {{{2 */
+// checkCloseRec() {{{2
static int checkCloseRec(garray_T *gap, linenr_T lnum, int level)
{
- fold_T *fp;
+ fold_T *fp;
int retval = FALSE;
fp = (fold_T *)gap->ga_data;
for (int i = 0; i < gap->ga_len; ++i) {
- /* Only manually opened folds may need to be closed. */
+ // Only manually opened folds may need to be closed.
if (fp[i].fd_flags == FD_OPEN) {
if (level <= 0 && (lnum < fp[i].fd_top
|| lnum >= fp[i].fd_top + fp[i].fd_len)) {
fp[i].fd_flags = FD_LEVEL;
retval = TRUE;
- } else
+ } else {
retval |= checkCloseRec(&fp[i].fd_nested, lnum - fp[i].fd_top,
- level - 1);
+ level - 1);
+ }
}
}
return retval;
}
-/* foldCreateAllowed() {{{2 */
-/*
- * Return TRUE if it's allowed to manually create or delete a fold.
- * Give an error message and return FALSE if not.
- */
-int foldManualAllowed(int create)
+// foldCreateAllowed() {{{2
+/// Return TRUE if it's allowed to manually create or delete a fold.
+/// Give an error message and return FALSE if not.
+int foldManualAllowed(bool create)
{
- if (foldmethodIsManual(curwin) || foldmethodIsMarker(curwin))
+ if (foldmethodIsManual(curwin) || foldmethodIsMarker(curwin)) {
return TRUE;
- if (create)
+ }
+ if (create) {
EMSG(_("E350: Cannot create fold with current 'foldmethod'"));
- else
+ } else {
EMSG(_("E351: Cannot delete fold with current 'foldmethod'"));
+ }
return FALSE;
}
@@ -560,8 +563,8 @@ int foldManualAllowed(int create)
/// window.
void foldCreate(win_T *wp, pos_T start, pos_T end)
{
- fold_T *fp;
- garray_T *gap;
+ fold_T *fp;
+ garray_T *gap;
garray_T fold_ga;
int i;
int cont;
@@ -658,13 +661,14 @@ void foldCreate(win_T *wp, pos_T start, pos_T end)
((fold_T *)fold_ga.ga_data)[j].fd_top -= start_rel.lnum;
}
}
- /* Move remaining entries to after the new fold. */
- if (i < gap->ga_len)
+ // Move remaining entries to after the new fold.
+ if (i < gap->ga_len) {
memmove(fp + 1, (fold_T *)gap->ga_data + i,
sizeof(fold_T) * (size_t)(gap->ga_len - i));
+ }
gap->ga_len = gap->ga_len + 1 - cont;
- /* insert new fold */
+ // insert new fold
fp->fd_nested = fold_ga;
fp->fd_top = start_rel.lnum;
fp->fd_len = end_rel.lnum - start_rel.lnum + 1;
@@ -692,16 +696,11 @@ void foldCreate(win_T *wp, pos_T start, pos_T end)
/// @param end delete all folds from start to end when not 0
/// @param recursive delete recursively if true
/// @param had_visual true when Visual selection used
-void deleteFold(
- win_T *const wp,
- const linenr_T start,
- const linenr_T end,
- const int recursive,
- const bool had_visual // true when Visual selection used
-)
-{
- fold_T *fp;
- fold_T *found_fp = NULL;
+void deleteFold(win_T *const wp, const linenr_T start, const linenr_T end, const int recursive,
+ const bool had_visual)
+{
+ fold_T *fp;
+ fold_T *found_fp = NULL;
linenr_T found_off = 0;
bool maybe_small = false;
int level = 0;
@@ -719,9 +718,10 @@ void deleteFold(
linenr_T lnum_off = 0;
bool use_level = false;
for (;; ) {
- if (!foldFind(gap, lnum - lnum_off, &fp))
+ if (!foldFind(gap, lnum - lnum_off, &fp)) {
break;
- /* lnum is inside this fold, remember info */
+ }
+ // lnum is inside this fold, remember info
found_ga = gap;
found_fp = fp;
found_off = lnum_off;
@@ -732,7 +732,7 @@ void deleteFold(
break;
}
- /* check nested folds */
+ // check nested folds
gap = &fp->fd_nested;
lnum_off += fp->fd_top;
++level;
@@ -790,7 +790,7 @@ void deleteFold(
}
}
-/* clearFolding() {{{2 */
+// clearFolding() {{{2
/*
* Remove all folding for window "win".
*/
@@ -800,7 +800,7 @@ void clearFolding(win_T *win)
win->w_foldinvalid = false;
}
-/* foldUpdate() {{{2 */
+// foldUpdate() {{{2
/*
* Update folds for changes in the buffer of a window.
* Note that inserted/deleted lines must have already been taken care of by
@@ -836,7 +836,7 @@ void foldUpdate(win_T *wp, linenr_T top, linenr_T bot)
|| foldmethodIsSyntax(wp)) {
int save_got_int = got_int;
- /* reset got_int here, otherwise it won't work */
+ // reset got_int here, otherwise it won't work
got_int = FALSE;
foldUpdateIEMS(wp, top, bot);
got_int |= save_got_int;
@@ -856,7 +856,7 @@ void foldUpdateAfterInsert(void)
foldOpenCursor();
}
-/* foldUpdateAll() {{{2 */
+// foldUpdateAll() {{{2
/*
* Update all lines in a window for folding.
* Used when a fold setting changes or after reloading the buffer.
@@ -870,19 +870,17 @@ void foldUpdateAll(win_T *win)
}
// foldMoveTo() {{{2
-//
-// If "updown" is false: Move to the start or end of the fold.
-// If "updown" is true: move to fold at the same level.
-// If not moved return FAIL.
-int foldMoveTo(
- const bool updown,
- const int dir, // FORWARD or BACKWARD
- const long count
-)
+///
+/// If "updown" is false: Move to the start or end of the fold.
+/// If "updown" is true: move to fold at the same level.
+/// @return FAIL if not moved.
+///
+/// @param dir FORWARD or BACKWARD
+int foldMoveTo(const bool updown, const int dir, const long count)
{
int retval = FAIL;
linenr_T lnum;
- fold_T *fp;
+ fold_T *fp;
checkupdate(curwin);
@@ -909,12 +907,14 @@ int foldMoveTo(
/* When moving up, consider a fold above the cursor; when
* moving down consider a fold below the cursor. */
if (dir == FORWARD) {
- if (fp - (fold_T *)gap->ga_data >= gap->ga_len)
+ if (fp - (fold_T *)gap->ga_data >= gap->ga_len) {
break;
+ }
--fp;
} else {
- if (fp == (fold_T *)gap->ga_data)
+ if (fp == (fold_T *)gap->ga_data) {
break;
+ }
}
/* don't look for contained folds, they will always move
* the cursor too far. */
@@ -922,31 +922,34 @@ int foldMoveTo(
}
if (!last) {
- /* Check if this fold is closed. */
+ // Check if this fold is closed.
if (check_closed(curwin, fp, &use_level, level,
&maybe_small, lnum_off)) {
last = true;
}
- /* "[z" and "]z" stop at closed fold */
- if (last && !updown)
+ // "[z" and "]z" stop at closed fold
+ if (last && !updown) {
break;
+ }
}
if (updown) {
if (dir == FORWARD) {
- /* to start of next fold if there is one */
+ // to start of next fold if there is one
if (fp + 1 - (fold_T *)gap->ga_data < gap->ga_len) {
lnum = fp[1].fd_top + lnum_off;
- if (lnum > curwin->w_cursor.lnum)
+ if (lnum > curwin->w_cursor.lnum) {
lnum_found = lnum;
+ }
}
} else {
- /* to end of previous fold if there is one */
+ // to end of previous fold if there is one
if (fp > (fold_T *)gap->ga_data) {
lnum = fp[-1].fd_top + lnum_off + fp[-1].fd_len - 1;
- if (lnum < curwin->w_cursor.lnum)
+ if (lnum < curwin->w_cursor.lnum) {
lnum_found = lnum;
+ }
}
}
} else {
@@ -954,37 +957,42 @@ int foldMoveTo(
* nested folds. */
if (dir == FORWARD) {
lnum = fp->fd_top + lnum_off + fp->fd_len - 1;
- if (lnum > curwin->w_cursor.lnum)
+ if (lnum > curwin->w_cursor.lnum) {
lnum_found = lnum;
+ }
} else {
lnum = fp->fd_top + lnum_off;
- if (lnum < curwin->w_cursor.lnum)
+ if (lnum < curwin->w_cursor.lnum) {
lnum_found = lnum;
+ }
}
}
- if (last)
+ if (last) {
break;
+ }
- /* Check nested folds (if any). */
+ // Check nested folds (if any).
gap = &fp->fd_nested;
lnum_off += fp->fd_top;
++level;
}
if (lnum_found != curwin->w_cursor.lnum) {
- if (retval == FAIL)
+ if (retval == FAIL) {
setpcmark();
+ }
curwin->w_cursor.lnum = lnum_found;
curwin->w_cursor.col = 0;
retval = OK;
- } else
+ } else {
break;
+ }
}
return retval;
}
-/* foldInitWin() {{{2 */
+// foldInitWin() {{{2
/*
* Init the fold info in a new window.
*/
@@ -993,7 +1001,7 @@ void foldInitWin(win_T *new_win)
ga_init(&new_win->w_folds, (int)sizeof(fold_T), 10);
}
-/* find_wl_entry() {{{2 */
+// find_wl_entry() {{{2
/*
* Find an entry in the win->w_lines[] array for buffer line "lnum".
* Only valid entries are considered (for entries where wl_valid is FALSE the
@@ -1004,27 +1012,31 @@ int find_wl_entry(win_T *win, linenr_T lnum)
{
int i;
- for (i = 0; i < win->w_lines_valid; ++i)
+ for (i = 0; i < win->w_lines_valid; ++i) {
if (win->w_lines[i].wl_valid) {
- if (lnum < win->w_lines[i].wl_lnum)
+ if (lnum < win->w_lines[i].wl_lnum) {
return -1;
- if (lnum <= win->w_lines[i].wl_lastlnum)
+ }
+ if (lnum <= win->w_lines[i].wl_lastlnum) {
return i;
+ }
}
+ }
return -1;
}
-/* foldAdjustVisual() {{{2 */
+// foldAdjustVisual() {{{2
/*
* Adjust the Visual area to include any fold at the start or end completely.
*/
void foldAdjustVisual(void)
{
- pos_T *start, *end;
- char_u *ptr;
+ pos_T *start, *end;
+ char_u *ptr;
- if (!VIsual_active || !hasAnyFolding(curwin))
+ if (!VIsual_active || !hasAnyFolding(curwin)) {
return;
+ }
if (ltoreq(VIsual, curwin->w_cursor)) {
start = &VIsual;
@@ -1033,8 +1045,9 @@ void foldAdjustVisual(void)
start = &curwin->w_cursor;
end = &VIsual;
}
- if (hasFolding(start->lnum, &start->lnum, NULL))
+ if (hasFolding(start->lnum, &start->lnum, NULL)) {
start->col = 0;
+ }
if (hasFolding(end->lnum, NULL, &end->lnum)) {
ptr = ml_get(end->lnum);
end->col = (colnr_T)STRLEN(ptr);
@@ -1046,7 +1059,7 @@ void foldAdjustVisual(void)
}
}
-/* cursor_foldstart() {{{2 */
+// cursor_foldstart() {{{2
/*
* Move the cursor to the first line of a closed fold.
*/
@@ -1055,20 +1068,21 @@ void foldAdjustCursor(void)
(void)hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL);
}
-/* Internal functions for "fold_T" {{{1 */
-/* cloneFoldGrowArray() {{{2 */
+// Internal functions for "fold_T" {{{1
+// cloneFoldGrowArray() {{{2
/*
* Will "clone" (i.e deep copy) a garray_T of folds.
*/
void cloneFoldGrowArray(garray_T *from, garray_T *to)
{
- fold_T *from_p;
- fold_T *to_p;
+ fold_T *from_p;
+ fold_T *to_p;
ga_init(to, from->ga_itemsize, from->ga_growsize);
- if (GA_EMPTY(from))
+ if (GA_EMPTY(from)) {
return;
+ }
ga_grow(to, from->ga_len);
@@ -1087,17 +1101,16 @@ void cloneFoldGrowArray(garray_T *from, garray_T *to)
}
}
-/* foldFind() {{{2 */
-/*
- * Search for line "lnum" in folds of growarray "gap".
- * Set *fpp to the fold struct for the fold that contains "lnum" or
- * the first fold below it (careful: it can be beyond the end of the array!).
- * Returns FALSE when there is no fold that contains "lnum".
- */
+// foldFind() {{{2
+/// Search for line "lnum" in folds of growarray "gap".
+/// Set *fpp to the fold struct for the fold that contains "lnum" or
+/// the first fold below it (careful: it can be beyond the end of the array!).
+///
+/// @return false when there is no fold that contains "lnum".
static bool foldFind(const garray_T *gap, linenr_T lnum, fold_T **fpp)
{
linenr_T low, high;
- fold_T *fp;
+ fold_T *fp;
if (gap->ga_len == 0) {
*fpp = NULL;
@@ -1114,39 +1127,40 @@ static bool foldFind(const garray_T *gap, linenr_T lnum, fold_T **fpp)
high = gap->ga_len - 1;
while (low <= high) {
linenr_T i = (low + high) / 2;
- if (fp[i].fd_top > lnum)
- /* fold below lnum, adjust high */
+ if (fp[i].fd_top > lnum) {
+ // fold below lnum, adjust high
high = i - 1;
- else if (fp[i].fd_top + fp[i].fd_len <= lnum)
- /* fold above lnum, adjust low */
+ } else if (fp[i].fd_top + fp[i].fd_len <= lnum) {
+ // fold above lnum, adjust low
low = i + 1;
- else {
- /* lnum is inside this fold */
+ } else {
+ // lnum is inside this fold
*fpp = fp + i;
- return TRUE;
+ return true;
}
}
*fpp = fp + low;
return false;
}
-/* foldLevelWin() {{{2 */
+// foldLevelWin() {{{2
/*
* Return fold level at line number "lnum" in window "wp".
*/
static int foldLevelWin(win_T *wp, linenr_T lnum)
{
- fold_T *fp;
+ fold_T *fp;
linenr_T lnum_rel = lnum;
int level = 0;
- garray_T *gap;
+ garray_T *gap;
- /* Recursively search for a fold that contains "lnum". */
+ // Recursively search for a fold that contains "lnum".
gap = &wp->w_folds;
for (;; ) {
- if (!foldFind(gap, lnum_rel, &fp))
+ if (!foldFind(gap, lnum_rel, &fp)) {
break;
- /* Check nested folds. Line number is relative to containing fold. */
+ }
+ // Check nested folds. Line number is relative to containing fold.
gap = &fp->fd_nested;
lnum_rel -= fp->fd_top;
++level;
@@ -1155,19 +1169,19 @@ static int foldLevelWin(win_T *wp, linenr_T lnum)
return level;
}
-/* checkupdate() {{{2 */
+// checkupdate() {{{2
/*
* Check if the folds in window "wp" are invalid and update them if needed.
*/
static void checkupdate(win_T *wp)
{
if (wp->w_foldinvalid) {
- foldUpdate(wp, (linenr_T)1, (linenr_T)MAXLNUM); /* will update all */
+ foldUpdate(wp, (linenr_T)1, (linenr_T)MAXLNUM); // will update all
wp->w_foldinvalid = false;
}
}
-/* setFoldRepeat() {{{2 */
+// setFoldRepeat() {{{2
/*
* Open or close fold for current window at line "lnum".
* Repeat "count" times.
@@ -1181,26 +1195,23 @@ static void setFoldRepeat(pos_T pos, long count, int do_open)
done = DONE_NOTHING;
(void)setManualFold(pos, do_open, false, &done);
if (!(done & DONE_ACTION)) {
- /* Only give an error message when no fold could be opened. */
- if (n == 0 && !(done & DONE_FOLD))
+ // Only give an error message when no fold could be opened.
+ if (n == 0 && !(done & DONE_FOLD)) {
EMSG(_(e_nofold));
+ }
break;
}
}
}
-/* setManualFold() {{{2 */
-/*
- * Open or close the fold in the current window which contains "lnum".
- * Also does this for other windows in diff mode when needed.
- */
-static linenr_T
-setManualFold(
- pos_T pos,
- int opening, // TRUE when opening, FALSE when closing
- int recurse, // TRUE when closing/opening recursive
- int *donep
-)
+// setManualFold() {{{2
+///
+/// Open or close the fold in the current window which contains "lnum".
+/// Also does this for other windows in diff mode when needed.
+///
+/// @param opening TRUE when opening, FALSE when closing
+/// @param recurse TRUE when closing/opening recursive
+static linenr_T setManualFold(pos_T pos, int opening, int recurse, int *donep)
{
linenr_T lnum = pos.lnum;
if (foldmethodIsDiff(curwin) && curwin->w_p_scb) {
@@ -1223,33 +1234,28 @@ setManualFold(
return setManualFoldWin(curwin, lnum, opening, recurse, donep);
}
-/* setManualFoldWin() {{{2 */
-/*
- * Open or close the fold in window "wp" which contains "lnum".
- * "donep", when not NULL, points to flag that is set to DONE_FOLD when some
- * fold was found and to DONE_ACTION when some fold was opened or closed.
- * When "donep" is NULL give an error message when no fold was found for
- * "lnum", but only if "wp" is "curwin".
- * Return the line number of the next line that could be closed.
- * It's only valid when "opening" is TRUE!
- */
-static linenr_T
-setManualFoldWin(
- win_T *wp,
- linenr_T lnum,
- int opening, // TRUE when opening, FALSE when closing
- int recurse, // TRUE when closing/opening recursive
- int *donep
-)
-{
- fold_T *fp;
- fold_T *fp2;
- fold_T *found = NULL;
+// setManualFoldWin() {{{2
+/// Open or close the fold in window "wp" which contains "lnum".
+/// "donep", when not NULL, points to flag that is set to DONE_FOLD when some
+/// fold was found and to DONE_ACTION when some fold was opened or closed.
+/// When "donep" is NULL give an error message when no fold was found for
+/// "lnum", but only if "wp" is "curwin".
+///
+/// @param opening TRUE when opening, FALSE when closing
+/// @param recurse TRUE when closing/opening recursive
+///
+/// @return the line number of the next line that could be closed.
+/// It's only valid when "opening" is TRUE!
+static linenr_T setManualFoldWin(win_T *wp, linenr_T lnum, int opening, int recurse, int *donep)
+{
+ fold_T *fp;
+ fold_T *fp2;
+ fold_T *found = NULL;
int j;
int level = 0;
int use_level = FALSE;
int found_fold = FALSE;
- garray_T *gap;
+ garray_T *gap;
linenr_T next = MAXLNUM;
linenr_T off = 0;
int done = 0;
@@ -1269,43 +1275,47 @@ setManualFoldWin(
break;
}
- /* lnum is inside this fold */
+ // lnum is inside this fold
found_fold = TRUE;
- /* If there is a following fold, continue there next time. */
- if (fp + 1 < (fold_T *)gap->ga_data + gap->ga_len)
+ // If there is a following fold, continue there next time.
+ if (fp + 1 < (fold_T *)gap->ga_data + gap->ga_len) {
next = fp[1].fd_top + off;
+ }
- /* Change from level-dependent folding to manual. */
+ // Change from level-dependent folding to manual.
if (use_level || fp->fd_flags == FD_LEVEL) {
use_level = TRUE;
- if (level >= wp->w_p_fdl)
+ if (level >= wp->w_p_fdl) {
fp->fd_flags = FD_CLOSED;
- else
+ } else {
fp->fd_flags = FD_OPEN;
+ }
fp2 = (fold_T *)fp->fd_nested.ga_data;
- for (j = 0; j < fp->fd_nested.ga_len; ++j)
+ for (j = 0; j < fp->fd_nested.ga_len; ++j) {
fp2[j].fd_flags = FD_LEVEL;
+ }
}
- /* Simple case: Close recursively means closing the fold. */
+ // Simple case: Close recursively means closing the fold.
if (!opening && recurse) {
if (fp->fd_flags != FD_CLOSED) {
done |= DONE_ACTION;
fp->fd_flags = FD_CLOSED;
}
} else if (fp->fd_flags == FD_CLOSED) {
- /* When opening, open topmost closed fold. */
+ // When opening, open topmost closed fold.
if (opening) {
fp->fd_flags = FD_OPEN;
done |= DONE_ACTION;
- if (recurse)
+ if (recurse) {
foldOpenNested(fp);
+ }
}
break;
}
- /* fold is open, check nested folds */
+ // fold is open, check nested folds
found = fp;
gap = &fp->fd_nested;
lnum -= fp->fd_top;
@@ -1313,31 +1323,34 @@ setManualFoldWin(
++level;
}
if (found_fold) {
- /* When closing and not recurse, close deepest open fold. */
+ // When closing and not recurse, close deepest open fold.
if (!opening && found != NULL) {
found->fd_flags = FD_CLOSED;
done |= DONE_ACTION;
}
wp->w_fold_manual = true;
- if (done & DONE_ACTION)
+ if (done & DONE_ACTION) {
changed_window_setting_win(wp);
+ }
done |= DONE_FOLD;
- } else if (donep == NULL && wp == curwin)
+ } else if (donep == NULL && wp == curwin) {
EMSG(_(e_nofold));
+ }
- if (donep != NULL)
+ if (donep != NULL) {
*donep |= done;
+ }
return next;
}
-/* foldOpenNested() {{{2 */
+// foldOpenNested() {{{2
/*
* Open all nested folds in fold "fpr" recursively.
*/
static void foldOpenNested(fold_T *fpr)
{
- fold_T *fp;
+ fold_T *fp;
fp = (fold_T *)fpr->fd_nested.ga_data;
for (int i = 0; i < fpr->fd_nested.ga_len; ++i) {
@@ -1367,15 +1380,16 @@ static void deleteFoldEntry(win_T *const wp, garray_T *const gap, const int idx,
int moved = fp->fd_nested.ga_len;
ga_grow(gap, moved - 1);
{
- /* Get "fp" again, the array may have been reallocated. */
+ // Get "fp" again, the array may have been reallocated.
fp = (fold_T *)gap->ga_data + idx;
// adjust fd_top and fd_flags for the moved folds
fold_T *nfp = (fold_T *)fp->fd_nested.ga_data;
for (int i = 0; i < moved; i++) {
nfp[i].fd_top += fp->fd_top;
- if (fp->fd_flags == FD_LEVEL)
+ if (fp->fd_flags == FD_LEVEL) {
nfp[i].fd_flags = FD_LEVEL;
+ }
if (fp->fd_small == kNone) {
nfp[i].fd_small = kNone;
}
@@ -1394,17 +1408,17 @@ static void deleteFoldEntry(win_T *const wp, garray_T *const gap, const int idx,
}
}
-/* deleteFoldRecurse() {{{2 */
+// deleteFoldRecurse() {{{2
/*
* Delete nested folds in a fold.
*/
void deleteFoldRecurse(buf_T *bp, garray_T *gap)
{
-# define DELETE_FOLD_NESTED(fd) deleteFoldRecurse(bp, &((fd)->fd_nested))
+#define DELETE_FOLD_NESTED(fd) deleteFoldRecurse(bp, &((fd)->fd_nested))
GA_DEEP_CLEAR(gap, fold_T, DELETE_FOLD_NESTED);
}
-/* foldMarkAdjust() {{{2 */
+// foldMarkAdjust() {{{2
/*
* Update line numbers of folds for inserted/deleted lines.
*/
@@ -1412,8 +1426,9 @@ void foldMarkAdjust(win_T *wp, linenr_T line1, linenr_T line2, long amount, long
{
/* If deleting marks from line1 to line2, but not deleting all those
* lines, set line2 so that only deleted lines have their folds removed. */
- if (amount == MAXLNUM && line2 >= line1 && line2 - line1 >= -amount_after)
+ if (amount == MAXLNUM && line2 >= line1 && line2 - line1 >= -amount_after) {
line2 = line1 - amount_after - 1;
+ }
/* If appending a line in Insert mode, it should be included in the fold
* just above the line. */
if ((State & INSERT) && amount == (linenr_T)1 && line2 == MAXLNUM) {
@@ -1423,12 +1438,10 @@ void foldMarkAdjust(win_T *wp, linenr_T line1, linenr_T line2, long amount, long
}
// foldMarkAdjustRecurse() {{{2
-static void foldMarkAdjustRecurse(
- win_T *wp, garray_T *gap,
- linenr_T line1, linenr_T line2, long amount, long amount_after
-)
+static void foldMarkAdjustRecurse(win_T *wp, garray_T *gap, linenr_T line1, linenr_T line2,
+ long amount, long amount_after)
{
- fold_T *fp;
+ fold_T *fp;
linenr_T last;
linenr_T top;
@@ -1438,12 +1451,13 @@ static void foldMarkAdjustRecurse(
/* In Insert mode an inserted line at the top of a fold is considered part
* of the fold, otherwise it isn't. */
- if ((State & INSERT) && amount == (linenr_T)1 && line2 == MAXLNUM)
+ if ((State & INSERT) && amount == (linenr_T)1 && line2 == MAXLNUM) {
top = line1 + 1;
- else
+ } else {
top = line1;
+ }
- /* Find the fold containing or just below "line1". */
+ // Find the fold containing or just below "line1".
(void)foldFind(gap, line1, &fp);
/*
@@ -1452,26 +1466,28 @@ static void foldMarkAdjustRecurse(
for (int i = (int)(fp - (fold_T *)gap->ga_data); i < gap->ga_len; ++i, ++fp) {
/*
* Check for these situations:
- * 1 2 3
- * 1 2 3
- * line1 2 3 4 5
- * 2 3 4 5
- * 2 3 4 5
- * line2 2 3 4 5
- * 3 5 6
- * 3 5 6
+ * 1 2 3
+ * 1 2 3
+ * line1 2 3 4 5
+ * 2 3 4 5
+ * 2 3 4 5
+ * line2 2 3 4 5
+ * 3 5 6
+ * 3 5 6
*/
- last = fp->fd_top + fp->fd_len - 1; /* last line of fold */
+ last = fp->fd_top + fp->fd_len - 1; // last line of fold
- /* 1. fold completely above line1: nothing to do */
- if (last < line1)
+ // 1. fold completely above line1: nothing to do
+ if (last < line1) {
continue;
+ }
- /* 6. fold below line2: only adjust for amount_after */
+ // 6. fold below line2: only adjust for amount_after
if (fp->fd_top > line2) {
- if (amount_after == 0)
+ if (amount_after == 0) {
break;
+ }
fp->fd_top += amount_after;
} else {
if (fp->fd_top >= top && last <= line2) {
@@ -1490,13 +1506,14 @@ static void foldMarkAdjustRecurse(
foldMarkAdjustRecurse(wp, &fp->fd_nested, line1 - fp->fd_top,
line2 - fp->fd_top, amount, amount_after);
if (last <= line2) {
- /* 2. fold contains line1, line2 is below fold */
- if (amount == MAXLNUM)
+ // 2. fold contains line1, line2 is below fold
+ if (amount == MAXLNUM) {
fp->fd_len = line1 - fp->fd_top;
- else
+ } else {
fp->fd_len += amount;
+ }
} else {
- /* 3. fold contains line1 and line2 */
+ // 3. fold contains line1 and line2
fp->fd_len += amount_after;
}
} else {
@@ -1521,7 +1538,7 @@ static void foldMarkAdjustRecurse(
}
}
-/* getDeepestNesting() {{{2 */
+// getDeepestNesting() {{{2
/*
* Get the lowest 'foldlevel' value that makes the deepest nested fold in the
* current window open.
@@ -1536,13 +1553,14 @@ static int getDeepestNestingRecurse(garray_T *gap)
{
int level;
int maxlevel = 0;
- fold_T *fp;
+ fold_T *fp;
fp = (fold_T *)gap->ga_data;
for (int i = 0; i < gap->ga_len; ++i) {
level = getDeepestNestingRecurse(&fp[i].fd_nested) + 1;
- if (level > maxlevel)
+ if (level > maxlevel) {
maxlevel = level;
+ }
}
return maxlevel;
@@ -1557,14 +1575,8 @@ static int getDeepestNestingRecurse(garray_T *gap)
/// @param[out] maybe_smallp true: outer this had fd_small == kNone
/// @param lnum_off line number offset for fp->fd_top
/// @return true if fold is closed
-static bool check_closed(
- win_T *const wp,
- fold_T *const fp,
- bool *const use_levelp,
- const int level,
- bool *const maybe_smallp,
- const linenr_T lnum_off
-)
+static bool check_closed(win_T *const wp, fold_T *const fp, bool *const use_levelp, const int level,
+ bool *const maybe_smallp, const linenr_T lnum_off)
{
bool closed = false;
@@ -1597,13 +1609,9 @@ static bool check_closed(
// checkSmall() {{{2
/// Update fd_small field of fold "fp".
-/// @param lnum_off offset for fp->fd_top
-static void
-checkSmall(
- win_T *const wp,
- fold_T *const fp,
- const linenr_T lnum_off // offset for fp->fd_top
-)
+///
+/// @param lnum_off offset for fp->fd_top
+static void checkSmall(win_T *const wp, fold_T *const fp, const linenr_T lnum_off)
{
if (fp->fd_small == kNone) {
// Mark any nested folds to maybe-small
@@ -1635,7 +1643,7 @@ static void setSmallMaybe(garray_T *gap)
}
}
-/* foldCreateMarkers() {{{2 */
+// foldCreateMarkers() {{{2
/*
* Create a fold from line "start" to line "end" (inclusive) in the current
* window by adding markers.
@@ -1664,17 +1672,16 @@ static void foldCreateMarkers(win_T *wp, pos_T start, pos_T end)
buf_updates_send_changes(buf, start.lnum, num_changed, num_changed, true);
}
-/* foldAddMarker() {{{2 */
+// foldAddMarker() {{{2
/*
* Add "marker[markerlen]" in 'commentstring' to line "lnum".
*/
-static void foldAddMarker(
- buf_T *buf, pos_T pos, const char_u *marker, size_t markerlen)
+static void foldAddMarker(buf_T *buf, pos_T pos, const char_u *marker, size_t markerlen)
{
- char_u *cms = buf->b_p_cms;
- char_u *line;
- char_u *newline;
- char_u *p = (char_u *)strstr((char *)buf->b_p_cms, "%s");
+ char_u *cms = buf->b_p_cms;
+ char_u *line;
+ char_u *newline;
+ char_u *p = (char_u *)strstr((char *)buf->b_p_cms, "%s");
bool line_is_comment = false;
linenr_T lnum = pos.lnum;
@@ -1706,17 +1713,11 @@ static void foldAddMarker(
}
}
-/* deleteFoldMarkers() {{{2 */
-/*
- * Delete the markers for a fold, causing it to be deleted.
- */
-static void
-deleteFoldMarkers(
- win_T *wp,
- fold_T *fp,
- int recursive,
- linenr_T lnum_off // offset for fp->fd_top
-)
+// deleteFoldMarkers() {{{2
+/// Delete the markers for a fold, causing it to be deleted.
+///
+/// @param lnum_off offset for fp->fd_top
+static void deleteFoldMarkers(win_T *wp, fold_T *fp, int recursive, linenr_T lnum_off)
{
if (recursive) {
for (int i = 0; i < fp->fd_nested.ga_len; i++) {
@@ -1736,13 +1737,11 @@ deleteFoldMarkers(
// Delete 'commentstring' if it matches.
// If the marker is not found, there is no error message. Could be a missing
// close-marker.
-static void foldDelMarker(
- buf_T *buf, linenr_T lnum, char_u *marker, size_t markerlen
-)
+static void foldDelMarker(buf_T *buf, linenr_T lnum, char_u *marker, size_t markerlen)
{
- char_u *newline;
- char_u *cms = buf->b_p_cms;
- char_u *cms2;
+ char_u *newline;
+ char_u *cms = buf->b_p_cms;
+ char_u *cms2;
// end marker may be missing and fold extends below the last line
if (lnum > buf->b_ml.ml_line_count) {
@@ -1753,12 +1752,13 @@ static void foldDelMarker(
if (STRNCMP(p, marker, markerlen) != 0) {
continue;
}
- /* Found the marker, include a digit if it's there. */
+ // Found the marker, include a digit if it's there.
size_t len = markerlen;
- if (ascii_isdigit(p[len]))
+ if (ascii_isdigit(p[len])) {
++len;
+ }
if (*cms != NUL) {
- /* Also delete 'commentstring' if it matches. */
+ // Also delete 'commentstring' if it matches.
cms2 = (char_u *)strstr((char *)cms, "%s");
if (p - line >= cms2 - cms
&& STRNCMP(p - (cms2 - cms), cms, cms2 - cms) == 0
@@ -1768,7 +1768,7 @@ static void foldDelMarker(
}
}
if (u_save(lnum - 1, lnum + 1) == OK) {
- /* Make new line: text-before-marker + text-after-marker */
+ // Make new line: text-before-marker + text-after-marker
newline = xmalloc(STRLEN(line) - len + 1);
assert(p >= line);
memcpy(newline, line, (size_t)(p - line));
@@ -1790,34 +1790,35 @@ static void foldDelMarker(
/// @return the text for a closed fold
///
/// Otherwise the result is in allocated memory.
-char_u *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume,
- foldinfo_T foldinfo, char_u *buf)
+char_u *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, foldinfo_T foldinfo, char_u *buf)
FUNC_ATTR_NONNULL_ARG(1)
{
- char_u *text = NULL;
- /* an error occurred when evaluating 'fdt' setting */
+ char_u *text = NULL;
+ // an error occurred when evaluating 'fdt' setting
static int got_fdt_error = FALSE;
int save_did_emsg = did_emsg;
- static win_T *last_wp = NULL;
+ static win_T *last_wp = NULL;
static linenr_T last_lnum = 0;
- if (last_wp == NULL || last_wp != wp || last_lnum > lnum || last_lnum == 0)
- /* window changed, try evaluating foldtext setting once again */
+ if (last_wp == NULL || last_wp != wp || last_lnum > lnum || last_lnum == 0) {
+ // window changed, try evaluating foldtext setting once again
got_fdt_error = FALSE;
+ }
- if (!got_fdt_error)
- /* a previous error should not abort evaluating 'foldexpr' */
+ if (!got_fdt_error) {
+ // a previous error should not abort evaluating 'foldexpr'
did_emsg = FALSE;
+ }
if (*wp->w_p_fdt != NUL) {
char dashes[MAX_LEVEL + 2];
- win_T *save_curwin;
+ win_T *save_curwin;
int level;
- char_u *p;
+ char_u *p;
// Set "v:foldstart" and "v:foldend".
- set_vim_var_nr(VV_FOLDSTART, (varnumber_T) lnum);
- set_vim_var_nr(VV_FOLDEND, (varnumber_T) lnume);
+ set_vim_var_nr(VV_FOLDSTART, (varnumber_T)lnum);
+ set_vim_var_nr(VV_FOLDEND, (varnumber_T)lnume);
// Set "v:folddashes" to a string of "level" dashes.
// Set "v:foldlevel" to "level".
@@ -1828,22 +1829,22 @@ char_u *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume,
memset(dashes, '-', (size_t)level);
dashes[level] = NUL;
set_vim_var_string(VV_FOLDDASHES, dashes, -1);
- set_vim_var_nr(VV_FOLDLEVEL, (varnumber_T) level);
+ set_vim_var_nr(VV_FOLDLEVEL, (varnumber_T)level);
- /* skip evaluating foldtext on errors */
+ // skip evaluating foldtext on errors
if (!got_fdt_error) {
save_curwin = curwin;
curwin = wp;
curbuf = wp->w_buffer;
emsg_silent++; // handle exceptions, but don't display errors
- text = eval_to_string_safe(
- wp->w_p_fdt, NULL,
- was_set_insecurely(wp, (char_u *)"foldtext", OPT_LOCAL));
+ text = eval_to_string_safe(wp->w_p_fdt, NULL,
+ was_set_insecurely(wp, (char_u *)"foldtext", OPT_LOCAL));
emsg_silent--;
- if (text == NULL || did_emsg)
+ if (text == NULL || did_emsg) {
got_fdt_error = TRUE;
+ }
curwin = save_curwin;
curbuf = curwin->w_buffer;
@@ -1852,8 +1853,9 @@ char_u *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume,
last_wp = wp;
set_vim_var_string(VV_FOLDDASHES, NULL, -1);
- if (!did_emsg && save_did_emsg)
+ if (!did_emsg && save_did_emsg) {
did_emsg = save_did_emsg;
+ }
if (text != NULL) {
/* Replace unprintable characters, if there are any. But
@@ -1866,13 +1868,14 @@ char_u *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume,
break;
}
p += len - 1;
- } else if (*p == TAB)
+ } else if (*p == TAB) {
*p = ' ';
- else if (ptr2cells(p) > 1)
+ } else if (ptr2cells(p) > 1) {
break;
+ }
}
if (*p != NUL) {
- p = (char_u *)transstr((const char *)text);
+ p = (char_u *)transstr((const char *)text, true);
xfree(text);
text = p;
}
@@ -1890,35 +1893,37 @@ char_u *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume,
return text;
}
-/* foldtext_cleanup() {{{2 */
+// foldtext_cleanup() {{{2
/*
* Remove 'foldmarker' and 'commentstring' from "str" (in-place).
*/
void foldtext_cleanup(char_u *str)
{
- char_u *s;
- char_u *p;
- int did1 = FALSE;
- int did2 = FALSE;
+ char_u *s;
+ char_u *p;
+ bool did1 = false;
+ bool did2 = false;
- /* Ignore leading and trailing white space in 'commentstring'. */
+ // Ignore leading and trailing white space in 'commentstring'.
char_u *cms_start = skipwhite(curbuf->b_p_cms);
size_t cms_slen = STRLEN(cms_start);
- while (cms_slen > 0 && ascii_iswhite(cms_start[cms_slen - 1]))
+ while (cms_slen > 0 && ascii_iswhite(cms_start[cms_slen - 1])) {
--cms_slen;
+ }
- /* locate "%s" in 'commentstring', use the part before and after it. */
+ // locate "%s" in 'commentstring', use the part before and after it.
char_u *cms_end = (char_u *)strstr((char *)cms_start, "%s");
size_t cms_elen = 0;
if (cms_end != NULL) {
cms_elen = cms_slen - (size_t)(cms_end - cms_start);
cms_slen = (size_t)(cms_end - cms_start);
- /* exclude white space before "%s" */
- while (cms_slen > 0 && ascii_iswhite(cms_start[cms_slen - 1]))
+ // exclude white space before "%s"
+ while (cms_slen > 0 && ascii_iswhite(cms_start[cms_slen - 1])) {
--cms_slen;
+ }
- /* skip "%s" and white space after it */
+ // skip "%s" and white space after it
s = skipwhite(cms_end + 2);
cms_elen -= (size_t)(s - cms_end);
cms_end = s;
@@ -1927,18 +1932,21 @@ void foldtext_cleanup(char_u *str)
for (s = str; *s != NUL; ) {
size_t len = 0;
- if (STRNCMP(s, curwin->w_p_fmr, foldstartmarkerlen) == 0)
+ if (STRNCMP(s, curwin->w_p_fmr, foldstartmarkerlen) == 0) {
len = foldstartmarkerlen;
- else if (STRNCMP(s, foldendmarker, foldendmarkerlen) == 0)
+ } else if (STRNCMP(s, foldendmarker, foldendmarkerlen) == 0) {
len = foldendmarkerlen;
+ }
if (len > 0) {
- if (ascii_isdigit(s[len]))
+ if (ascii_isdigit(s[len])) {
++len;
+ }
/* May remove 'commentstring' start. Useful when it's a double
* quote and we already removed a double quote. */
- for (p = s; p > str && ascii_iswhite(p[-1]); --p)
+ for (p = s; p > str && ascii_iswhite(p[-1]); --p) {
;
+ }
if (p >= str + cms_slen
&& STRNCMP(p - cms_slen, cms_start, cms_slen) == 0) {
len += (size_t)(s - p) + cms_slen;
@@ -1947,16 +1955,17 @@ void foldtext_cleanup(char_u *str)
} else if (cms_end != NULL) {
if (!did1 && cms_slen > 0 && STRNCMP(s, cms_start, cms_slen) == 0) {
len = cms_slen;
- did1 = TRUE;
+ did1 = true;
} else if (!did2 && cms_elen > 0
&& STRNCMP(s, cms_end, cms_elen) == 0) {
len = cms_elen;
- did2 = TRUE;
+ did2 = true;
}
}
if (len != 0) {
- while (ascii_iswhite(s[len]))
+ while (ascii_iswhite(s[len])) {
++len;
+ }
STRMOVE(s, s + len);
} else {
MB_PTR_ADV(s);
@@ -1964,10 +1973,10 @@ void foldtext_cleanup(char_u *str)
}
}
-/* Folding by indent, expr, marker and syntax. {{{1 */
-/* Function declarations. {{{2 */
+// Folding by indent, expr, marker and syntax. {{{1
+// Function declarations. {{{2
-/* foldUpdateIEMS() {{{2 */
+// foldUpdateIEMS() {{{2
/*
* Update the folding for window "wp", at least from lines "top" to "bot".
* IEMS = "Indent Expr Marker Syntax"
@@ -1976,28 +1985,30 @@ static void foldUpdateIEMS(win_T *const wp, linenr_T top, linenr_T bot)
{
fline_T fline;
LevelGetter getlevel = NULL;
- fold_T *fp;
+ fold_T *fp;
- /* Avoid problems when being called recursively. */
- if (invalid_top != (linenr_T)0)
+ // Avoid problems when being called recursively.
+ if (invalid_top != (linenr_T)0) {
return;
+ }
if (wp->w_foldinvalid) {
- /* Need to update all folds. */
+ // Need to update all folds.
top = 1;
bot = wp->w_buffer->b_ml.ml_line_count;
wp->w_foldinvalid = false;
- /* Mark all folds a maybe-small. */
+ // Mark all folds a maybe-small.
setSmallMaybe(&wp->w_folds);
}
- /* add the context for "diff" folding */
+ // add the context for "diff" folding
if (foldmethodIsDiff(wp)) {
- if (top > diff_context)
+ if (top > diff_context) {
top -= diff_context;
- else
+ } else {
top = 1;
+ }
bot += diff_context;
}
@@ -2022,7 +2033,7 @@ static void foldUpdateIEMS(win_T *const wp, linenr_T top, linenr_T bot)
if (foldmethodIsMarker(wp)) {
getlevel = foldlevelMarker;
- /* Init marker variables to speed up foldlevelMarker(). */
+ // Init marker variables to speed up foldlevelMarker().
parseMarker(wp);
/* Need to get the level of the line above top, it is used if there is
@@ -2031,7 +2042,7 @@ static void foldUpdateIEMS(win_T *const wp, linenr_T top, linenr_T bot)
// Get the fold level at top - 1.
const int level = foldLevelWin(wp, top - 1);
- /* The fold may end just above the top, check for that. */
+ // The fold may end just above the top, check for that.
fline.lnum = top - 1;
fline.lvl = level;
getlevel(&fline);
@@ -2039,10 +2050,11 @@ static void foldUpdateIEMS(win_T *const wp, linenr_T top, linenr_T bot)
/* If a fold started here, we already had the level, if it stops
* here, we need to use lvl_next. Could also start and end a fold
* in the same line. */
- if (fline.lvl > level)
+ if (fline.lvl > level) {
fline.lvl = level - (fline.lvl - fline.lvl_next);
- else
+ } else {
fline.lvl = fline.lvl_next;
+ }
}
fline.lnum = top;
getlevel(&fline);
@@ -2052,14 +2064,16 @@ static void foldUpdateIEMS(win_T *const wp, linenr_T top, linenr_T bot)
getlevel = foldlevelExpr;
/* start one line back, because a "<1" may indicate the end of a
* fold in the topline */
- if (top > 1)
+ if (top > 1) {
--fline.lnum;
- } else if (foldmethodIsSyntax(wp))
+ }
+ } else if (foldmethodIsSyntax(wp)) {
getlevel = foldlevelSyntax;
- else if (foldmethodIsDiff(wp))
+ } else if (foldmethodIsDiff(wp)) {
getlevel = foldlevelDiff;
- else
+ } else {
getlevel = foldlevelIndent;
+ }
/* Backup to a line for which the fold level is defined. Since it's
* always defined for line one, we will stop there. */
@@ -2069,8 +2083,9 @@ static void foldUpdateIEMS(win_T *const wp, linenr_T top, linenr_T bot)
* the next line, but we search backwards here. */
fline.lvl_next = -1;
getlevel(&fline);
- if (fline.lvl >= 0)
+ if (fline.lvl >= 0) {
break;
+ }
}
}
@@ -2083,14 +2098,15 @@ static void foldUpdateIEMS(win_T *const wp, linenr_T top, linenr_T bot)
*/
if (foldlevelSyntax == getlevel) {
garray_T *gap = &wp->w_folds;
- fold_T *fpn = NULL;
+ fold_T *fpn = NULL;
int current_fdl = 0;
linenr_T fold_start_lnum = 0;
linenr_T lnum_rel = fline.lnum;
while (current_fdl < fline.lvl) {
- if (!foldFind(gap, lnum_rel, &fpn))
+ if (!foldFind(gap, lnum_rel, &fpn)) {
break;
+ }
++current_fdl;
fold_start_lnum += fpn->fd_top;
@@ -2100,8 +2116,9 @@ static void foldUpdateIEMS(win_T *const wp, linenr_T top, linenr_T bot)
if (fpn != NULL && current_fdl == fline.lvl) {
linenr_T fold_end_lnum = fold_start_lnum + fpn->fd_len;
- if (fold_end_lnum > bot)
+ if (fold_end_lnum > bot) {
bot = fold_end_lnum;
+ }
}
}
@@ -2114,34 +2131,37 @@ static void foldUpdateIEMS(win_T *const wp, linenr_T top, linenr_T bot)
while (!got_int) {
/* Always stop at the end of the file ("end" can be past the end of
* the file). */
- if (fline.lnum > wp->w_buffer->b_ml.ml_line_count)
+ if (fline.lnum > wp->w_buffer->b_ml.ml_line_count) {
break;
+ }
if (fline.lnum > end) {
/* For "marker", "expr" and "syntax" methods: If a change caused
* a fold to be removed, we need to continue at least until where
* it ended. */
if (getlevel != foldlevelMarker
&& getlevel != foldlevelSyntax
- && getlevel != foldlevelExpr)
+ && getlevel != foldlevelExpr) {
break;
+ }
if ((start <= end
&& foldFind(&wp->w_folds, end, &fp)
&& fp->fd_top + fp->fd_len - 1 > end)
|| (fline.lvl == 0
&& foldFind(&wp->w_folds, fline.lnum, &fp)
- && fp->fd_top < fline.lnum))
+ && fp->fd_top < fline.lnum)) {
end = fp->fd_top + fp->fd_len - 1;
- else if (getlevel == foldlevelSyntax
- && foldLevelWin(wp, fline.lnum) != fline.lvl)
+ } else if (getlevel == foldlevelSyntax
+ && foldLevelWin(wp, fline.lnum) != fline.lvl) {
/* For "syntax" method: Compare the foldlevel that the syntax
* tells us to the foldlevel from the existing folds. If they
* don't match continue updating folds. */
end = fline.lnum;
- else
+ } else {
break;
+ }
}
- /* A level 1 fold starts at a line with foldlevel > 0. */
+ // A level 1 fold starts at a line with foldlevel > 0.
if (fline.lvl > 0) {
invalid_top = fline.lnum;
invalid_bot = end;
@@ -2149,8 +2169,9 @@ static void foldUpdateIEMS(win_T *const wp, linenr_T top, linenr_T bot)
FD_LEVEL);
start = fline.lnum;
} else {
- if (fline.lnum == wp->w_buffer->b_ml.ml_line_count)
+ if (fline.lnum == wp->w_buffer->b_ml.ml_line_count) {
break;
+ }
++fline.lnum;
fline.lvl = fline.lvl_next;
getlevel(&fline);
@@ -2160,56 +2181,58 @@ static void foldUpdateIEMS(win_T *const wp, linenr_T top, linenr_T bot)
// There can't be any folds from start until end now.
foldRemove(wp, &wp->w_folds, start, end);
- /* If some fold changed, need to redraw and position cursor. */
- if (fold_changed && wp->w_p_fen)
+ // If some fold changed, need to redraw and position cursor.
+ if (fold_changed && wp->w_p_fen) {
changed_window_setting_win(wp);
+ }
/* If we updated folds past "bot", need to redraw more lines. Don't do
* this in other situations, the changed lines will be redrawn anyway and
* this method can cause the whole window to be updated. */
if (end != bot) {
- if (wp->w_redraw_top == 0 || wp->w_redraw_top > top)
+ if (wp->w_redraw_top == 0 || wp->w_redraw_top > top) {
wp->w_redraw_top = top;
- if (wp->w_redraw_bot < end)
+ }
+ if (wp->w_redraw_bot < end) {
wp->w_redraw_bot = end;
+ }
}
invalid_top = (linenr_T)0;
}
-/* foldUpdateIEMSRecurse() {{{2 */
-/*
- * Update a fold that starts at "flp->lnum". At this line there is always a
- * valid foldlevel, and its level >= "level".
- * "flp" is valid for "flp->lnum" when called and it's valid when returning.
- * "flp->lnum" is set to the lnum just below the fold, if it ends before
- * "bot", it's "bot" plus one if the fold continues and it's bigger when using
- * the marker method and a text change made following folds to change.
- * When returning, "flp->lnum_save" is the line number that was used to get
- * the level when the level at "flp->lnum" is invalid.
- * Remove any folds from "startlnum" up to here at this level.
- * Recursively update nested folds.
- * Below line "bot" there are no changes in the text.
- * "flp->lnum", "flp->lnum_save" and "bot" are relative to the start of the
- * outer fold.
- * "flp->off" is the offset to the real line number in the buffer.
- *
- * All this would be a lot simpler if all folds in the range would be deleted
- * and then created again. But we would lose all information about the
- * folds, even when making changes that don't affect the folding (e.g. "vj~").
- *
- * Returns bot, which may have been increased for lines that also need to be
- * updated as a result of a detected change in the fold.
- */
-static linenr_T foldUpdateIEMSRecurse(
- garray_T *const gap, const int level, const linenr_T startlnum,
- fline_T *const flp, LevelGetter getlevel, linenr_T bot,
- const char topflags // containing fold flags
-)
+// foldUpdateIEMSRecurse() {{{2
+/// Update a fold that starts at "flp->lnum". At this line there is always a
+/// valid foldlevel, and its level >= "level".
+///
+/// "flp" is valid for "flp->lnum" when called and it's valid when returning.
+/// "flp->lnum" is set to the lnum just below the fold, if it ends before
+/// "bot", it's "bot" plus one if the fold continues and it's bigger when using
+/// the marker method and a text change made following folds to change.
+/// When returning, "flp->lnum_save" is the line number that was used to get
+/// the level when the level at "flp->lnum" is invalid.
+/// Remove any folds from "startlnum" up to here at this level.
+/// Recursively update nested folds.
+/// Below line "bot" there are no changes in the text.
+/// "flp->lnum", "flp->lnum_save" and "bot" are relative to the start of the
+/// outer fold.
+/// "flp->off" is the offset to the real line number in the buffer.
+///
+/// All this would be a lot simpler if all folds in the range would be deleted
+/// and then created again. But we would lose all information about the
+/// folds, even when making changes that don't affect the folding (e.g. "vj~").
+///
+/// @param topflags containing fold flags
+///
+/// @return bot, which may have been increased for lines that also need to be
+/// updated as a result of a detected change in the fold.
+static linenr_T foldUpdateIEMSRecurse(garray_T *const gap, const int level,
+ const linenr_T startlnum, fline_T *const flp,
+ LevelGetter getlevel, linenr_T bot, const char topflags)
{
linenr_T ll;
- fold_T *fp = NULL;
- fold_T *fp2;
+ fold_T *fp = NULL;
+ fold_T *fp2;
int lvl = level;
linenr_T startlnum2 = startlnum;
const linenr_T firstlnum = flp->lnum; // first lnum we got
@@ -2247,7 +2270,7 @@ static linenr_T foldUpdateIEMSRecurse(
*/
flp->lnum_save = flp->lnum;
while (!got_int) {
- /* Updating folds can be slow, check for CTRL-C. */
+ // Updating folds can be slow, check for CTRL-C.
line_breakcheck();
/* Set "lvl" to the level of line "flp->lnum". When flp->start is set
@@ -2255,11 +2278,13 @@ static linenr_T foldUpdateIEMSRecurse(
* force the fold to end. Do the same when had_end is set: Previous
* line was marked as end of a fold. */
lvl = flp->lvl;
- if (lvl > MAX_LEVEL)
+ if (lvl > MAX_LEVEL) {
lvl = MAX_LEVEL;
+ }
if (flp->lnum > firstlnum
- && (level > lvl - flp->start || level >= flp->had_end))
+ && (level > lvl - flp->start || level >= flp->had_end)) {
lvl = 0;
+ }
if (flp->lnum > bot && !finish && fp != NULL) {
/* For "marker" and "syntax" methods:
@@ -2270,8 +2295,9 @@ static linenr_T foldUpdateIEMSRecurse(
*/
if (getlevel != foldlevelMarker
&& getlevel != foldlevelExpr
- && getlevel != foldlevelSyntax)
+ && getlevel != foldlevelSyntax) {
break;
+ }
i = 0;
fp2 = fp;
if (lvl >= level) {
@@ -2312,10 +2338,11 @@ static linenr_T foldUpdateIEMSRecurse(
while (!got_int) {
/* set concat to 1 if it's allowed to concatenated this fold
* with a previous one that touches it. */
- if (flp->start != 0 || flp->had_end <= MAX_LEVEL)
+ if (flp->start != 0 || flp->had_end <= MAX_LEVEL) {
concat = 0;
- else
+ } else {
concat = 1;
+ }
/* Find an existing fold to re-use. Preferably one that
* includes startlnum, otherwise one that ends just before
@@ -2342,14 +2369,14 @@ static linenr_T foldUpdateIEMSRecurse(
// nested folds (with relative line numbers) down.
foldMarkAdjustRecurse(flp->wp, &fp->fd_nested,
(linenr_T)0, (linenr_T)MAXLNUM,
- (long)(fp->fd_top - firstlnum), 0L);
+ (fp->fd_top - firstlnum), 0L);
} else {
// Will move fold down, move nested folds relatively up.
foldMarkAdjustRecurse(flp->wp, &fp->fd_nested,
(linenr_T)0,
- (long)(firstlnum - fp->fd_top - 1),
+ (firstlnum - fp->fd_top - 1),
(linenr_T)MAXLNUM,
- (long)(fp->fd_top - firstlnum));
+ (fp->fd_top - firstlnum));
}
fp->fd_len += fp->fd_top - firstlnum;
fp->fd_top = firstlnum;
@@ -2412,7 +2439,7 @@ static linenr_T foldUpdateIEMSRecurse(
* to stop just above startlnum. */
fp->fd_len = startlnum - fp->fd_top;
foldMarkAdjustRecurse(flp->wp, &fp->fd_nested,
- (linenr_T)fp->fd_len, (linenr_T)MAXLNUM,
+ fp->fd_len, (linenr_T)MAXLNUM,
(linenr_T)MAXLNUM, 0L);
fold_changed = true;
}
@@ -2438,10 +2465,12 @@ static linenr_T foldUpdateIEMSRecurse(
fp->fd_flags = FD_OPEN;
} else if (i <= 0) {
fp->fd_flags = topflags;
- if (topflags != FD_LEVEL)
+ if (topflags != FD_LEVEL) {
flp->wp->w_fold_manual = true;
- } else
+ }
+ } else {
fp->fd_flags = (fp - 1)->fd_flags;
+ }
fp->fd_small = kNone;
// If using the "marker", "expr" or "syntax" method, we
// need to continue until the end of the fold is found.
@@ -2490,7 +2519,7 @@ static linenr_T foldUpdateIEMSRecurse(
bot += fp->fd_top;
startlnum2 = flp->lnum;
- /* This fold may end at the same line, don't incr. flp->lnum. */
+ // This fold may end at the same line, don't incr. flp->lnum.
} else {
/*
* Get the level of the next line, then continue the loop to check
@@ -2501,20 +2530,23 @@ static linenr_T foldUpdateIEMSRecurse(
flp->lnum = flp->lnum_save;
ll = flp->lnum + 1;
while (!got_int) {
- /* Make the previous level available to foldlevel(). */
+ // Make the previous level available to foldlevel().
prev_lnum = flp->lnum;
prev_lnum_lvl = flp->lvl;
- if (++flp->lnum > linecount)
+ if (++flp->lnum > linecount) {
break;
+ }
flp->lvl = flp->lvl_next;
getlevel(flp);
- if (flp->lvl >= 0 || flp->had_end <= MAX_LEVEL)
+ if (flp->lvl >= 0 || flp->had_end <= MAX_LEVEL) {
break;
+ }
}
prev_lnum = 0;
- if (flp->lnum > linecount)
+ if (flp->lnum > linecount) {
break;
+ }
/* leave flp->lnum_save to lnum of the line that was used to get
* the level, flp->lnum to the lnum of the next line. */
@@ -2523,8 +2555,9 @@ static linenr_T foldUpdateIEMSRecurse(
}
}
- if (fp == NULL) /* only happens when got_int is set */
+ if (fp == NULL) { // only happens when got_int is set
return bot;
+ }
/*
* Get here when:
@@ -2573,18 +2606,19 @@ static linenr_T foldUpdateIEMSRecurse(
}
}
- /* delete following folds that end before the current line */
+ // delete following folds that end before the current line
for (;; ) {
fp2 = fp + 1;
if (fp2 >= (fold_T *)gap->ga_data + gap->ga_len
- || fp2->fd_top > flp->lnum)
+ || fp2->fd_top > flp->lnum) {
break;
+ }
if (fp2->fd_top + fp2->fd_len > flp->lnum) {
if (fp2->fd_top < flp->lnum) {
// Make fold that includes lnum start at lnum.
foldMarkAdjustRecurse(flp->wp, &fp2->fd_nested,
- (linenr_T)0, (long)(flp->lnum - fp2->fd_top - 1),
- (linenr_T)MAXLNUM, (long)(fp2->fd_top-flp->lnum));
+ (linenr_T)0, (flp->lnum - fp2->fd_top - 1),
+ (linenr_T)MAXLNUM, (fp2->fd_top-flp->lnum));
fp2->fd_len -= flp->lnum - fp2->fd_top;
fp2->fd_top = flp->lnum;
fold_changed = true;
@@ -2602,19 +2636,20 @@ static linenr_T foldUpdateIEMSRecurse(
/* Need to redraw the lines we inspected, which might be further down than
* was asked for. */
- if (bot < flp->lnum - 1)
+ if (bot < flp->lnum - 1) {
bot = flp->lnum - 1;
+ }
return bot;
}
-/* foldInsert() {{{2 */
+// foldInsert() {{{2
/*
* Insert a new fold in "gap" at position "i".
*/
static void foldInsert(garray_T *gap, int i)
{
- fold_T *fp;
+ fold_T *fp;
ga_grow(gap, 1);
@@ -2626,7 +2661,7 @@ static void foldInsert(garray_T *gap, int i)
ga_init(&fp->fd_nested, (int)sizeof(fold_T), 10);
}
-/* foldSplit() {{{2 */
+// foldSplit() {{{2
/*
* Split the "i"th fold in "gap", which starts before "top" and ends below
* "bot" in two pieces, one ending above "top" and the other starting below
@@ -2634,14 +2669,12 @@ static void foldInsert(garray_T *gap, int i)
* The caller must first have taken care of any nested folds from "top" to
* "bot"!
*/
-static void foldSplit(buf_T *buf, garray_T *const gap,
- const int i, const linenr_T top,
- const linenr_T bot
- )
+static void foldSplit(buf_T *buf, garray_T *const gap, const int i, const linenr_T top,
+ const linenr_T bot)
{
- fold_T *fp2;
+ fold_T *fp2;
- /* The fold continues below bot, need to split it. */
+ // The fold continues below bot, need to split it.
foldInsert(gap, i + 1);
fold_T *const fp = (fold_T *)gap->ga_data + i;
@@ -2674,7 +2707,7 @@ static void foldSplit(buf_T *buf, garray_T *const gap,
fold_changed = true;
}
-/* foldRemove() {{{2 */
+// foldRemove() {{{2
/*
* Remove folds within the range "top" to and including "bot".
* Check for these situations:
@@ -2693,11 +2726,9 @@ static void foldSplit(buf_T *buf, garray_T *const gap,
* 5: made to start below "bot".
* 6: not changed
*/
-static void foldRemove(
- win_T *const wp, garray_T *gap, linenr_T top, linenr_T bot
-)
+static void foldRemove(win_T *const wp, garray_T *gap, linenr_T top, linenr_T bot)
{
- fold_T *fp = NULL;
+ fold_T *fp = NULL;
if (bot < top) {
return; // nothing to do
@@ -2730,10 +2761,9 @@ static void foldRemove(
fold_changed = true;
if (fp->fd_top + fp->fd_len - 1 > bot) {
// 5: Make fold that includes bot start below bot.
- foldMarkAdjustRecurse(
- wp, &fp->fd_nested,
- (linenr_T)0, (long)(bot - fp->fd_top),
- (linenr_T)MAXLNUM, (long)(fp->fd_top - bot - 1));
+ foldMarkAdjustRecurse(wp, &fp->fd_nested,
+ (linenr_T)0, (bot - fp->fd_top),
+ (linenr_T)MAXLNUM, (fp->fd_top - bot - 1));
fp->fd_len -= bot - fp->fd_top + 1;
fp->fd_top = bot + 1;
break;
@@ -2746,10 +2776,7 @@ static void foldRemove(
}
// foldReverseOrder() {{{2
-static void foldReverseOrder(
- garray_T *gap,
- const linenr_T start_arg,
- const linenr_T end_arg)
+static void foldReverseOrder(garray_T *gap, const linenr_T start_arg, const linenr_T end_arg)
{
linenr_T start = start_arg;
linenr_T end = end_arg;
@@ -2804,11 +2831,8 @@ static void truncate_fold(win_T *const wp, fold_T *fp, linenr_T end)
#define VALID_FOLD(fp, gap) \
((gap)->ga_len > 0 && (fp) < ((fold_T *)(gap)->ga_data + (gap)->ga_len))
#define FOLD_INDEX(fp, gap) ((size_t)(fp - ((fold_T *)(gap)->ga_data)))
-void foldMoveRange(
- win_T *const wp, garray_T *gap,
- const linenr_T line1, const linenr_T line2,
- const linenr_T dest
-)
+void foldMoveRange(win_T *const wp, garray_T *gap, const linenr_T line1, const linenr_T line2,
+ const linenr_T dest)
{
fold_T *fp;
const linenr_T range_len = line2 - line1 + 1;
@@ -2908,7 +2932,7 @@ void foldMoveRange(
#undef VALID_FOLD
#undef FOLD_INDEX
-/* foldMerge() {{{2 */
+// foldMerge() {{{2
/*
* Merge two adjacent folds (and the nested ones in them).
* This only works correctly when the folds are really adjacent! Thus "fp1"
@@ -2918,11 +2942,11 @@ void foldMoveRange(
*/
static void foldMerge(win_T *const wp, fold_T *fp1, garray_T *gap, fold_T *fp2)
{
- fold_T *fp3;
- fold_T *fp4;
+ fold_T *fp3;
+ fold_T *fp4;
int idx;
- garray_T *gap1 = &fp1->fd_nested;
- garray_T *gap2 = &fp2->fd_nested;
+ garray_T *gap1 = &fp1->fd_nested;
+ garray_T *gap2 = &fp2->fd_nested;
/* If the last nested fold in fp1 touches the first nested fold in fp2,
* merge them recursively. */
@@ -2930,7 +2954,7 @@ static void foldMerge(win_T *const wp, fold_T *fp1, garray_T *gap, fold_T *fp2)
foldMerge(wp, fp3, gap2, fp4);
}
- /* Move nested folds in fp2 to the end of fp1. */
+ // Move nested folds in fp2 to the end of fp1.
if (!GA_EMPTY(gap2)) {
ga_grow(gap1, gap2->ga_len);
for (idx = 0; idx < gap2->ga_len; ++idx) {
@@ -2947,7 +2971,7 @@ static void foldMerge(win_T *const wp, fold_T *fp1, garray_T *gap, fold_T *fp2)
fold_changed = true;
}
-/* foldlevelIndent() {{{2 */
+// foldlevelIndent() {{{2
/*
* Low level function to get the foldlevel for the "indent" method.
* Doesn't use any caching.
@@ -2955,43 +2979,45 @@ static void foldMerge(win_T *const wp, fold_T *fp1, garray_T *gap, fold_T *fp2)
*/
static void foldlevelIndent(fline_T *flp)
{
- char_u *s;
- buf_T *buf;
+ char_u *s;
+ buf_T *buf;
linenr_T lnum = flp->lnum + flp->off;
buf = flp->wp->w_buffer;
- s = skipwhite(ml_get_buf(buf, lnum, FALSE));
+ s = skipwhite(ml_get_buf(buf, lnum, false));
/* empty line or lines starting with a character in 'foldignore': level
* depends on surrounding lines */
if (*s == NUL || vim_strchr(flp->wp->w_p_fdi, *s) != NULL) {
- /* first and last line can't be undefined, use level 0 */
- if (lnum == 1 || lnum == buf->b_ml.ml_line_count)
+ // first and last line can't be undefined, use level 0
+ if (lnum == 1 || lnum == buf->b_ml.ml_line_count) {
flp->lvl = 0;
- else
+ } else {
flp->lvl = -1;
+ }
} else {
flp->lvl = get_indent_buf(buf, lnum) / get_sw_value(buf);
}
if (flp->lvl > flp->wp->w_p_fdn) {
- flp->lvl = (int) MAX(0, flp->wp->w_p_fdn);
+ flp->lvl = (int)MAX(0, flp->wp->w_p_fdn);
}
}
-/* foldlevelDiff() {{{2 */
+// foldlevelDiff() {{{2
/*
* Low level function to get the foldlevel for the "diff" method.
* Doesn't use any caching.
*/
static void foldlevelDiff(fline_T *flp)
{
- if (diff_infold(flp->wp, flp->lnum + flp->off))
+ if (diff_infold(flp->wp, flp->lnum + flp->off)) {
flp->lvl = 1;
- else
+ } else {
flp->lvl = 0;
+ }
}
-/* foldlevelExpr() {{{2 */
+// foldlevelExpr() {{{2
/*
* Low level function to get the foldlevel for the "expr" method.
* Doesn't use any caching.
@@ -2999,20 +3025,21 @@ static void foldlevelDiff(fline_T *flp)
*/
static void foldlevelExpr(fline_T *flp)
{
- win_T *win;
+ win_T *win;
int c;
linenr_T lnum = flp->lnum + flp->off;
win = curwin;
curwin = flp->wp;
curbuf = flp->wp->w_buffer;
- set_vim_var_nr(VV_LNUM, (varnumber_T) lnum);
+ set_vim_var_nr(VV_LNUM, (varnumber_T)lnum);
flp->start = 0;
flp->had_end = flp->end;
flp->end = MAX_LEVEL + 1;
- if (lnum <= 1)
+ if (lnum <= 1) {
flp->lvl = 0;
+ }
/* KeyTyped may be reset to 0 when calling a function which invokes
* do_cmdline(). To make 'foldopen' work correctly restore KeyTyped. */
@@ -3021,46 +3048,54 @@ static void foldlevelExpr(fline_T *flp)
KeyTyped = save_keytyped;
switch (c) {
- /* "a1", "a2", .. : add to the fold level */
- case 'a': if (flp->lvl >= 0) {
+ // "a1", "a2", .. : add to the fold level
+ case 'a':
+ if (flp->lvl >= 0) {
flp->lvl += n;
flp->lvl_next = flp->lvl;
- }
+ }
flp->start = n;
break;
- /* "s1", "s2", .. : subtract from the fold level */
- case 's': if (flp->lvl >= 0) {
- if (n > flp->lvl)
+ // "s1", "s2", .. : subtract from the fold level
+ case 's':
+ if (flp->lvl >= 0) {
+ if (n > flp->lvl) {
flp->lvl_next = 0;
- else
+ } else {
flp->lvl_next = flp->lvl - n;
+ }
flp->end = flp->lvl_next + 1;
- }
+ }
break;
- /* ">1", ">2", .. : start a fold with a certain level */
- case '>': flp->lvl = n;
+ // ">1", ">2", .. : start a fold with a certain level
+ case '>':
+ flp->lvl = n;
flp->lvl_next = n;
flp->start = 1;
break;
- /* "<1", "<2", .. : end a fold with a certain level */
- case '<': flp->lvl_next = n - 1;
+ // "<1", "<2", .. : end a fold with a certain level
+ case '<':
+ flp->lvl_next = n - 1;
flp->end = n;
break;
- /* "=": No change in level */
- case '=': flp->lvl_next = flp->lvl;
+ // "=": No change in level
+ case '=':
+ flp->lvl_next = flp->lvl;
break;
- /* "-1", "0", "1", ..: set fold level */
- default: if (n < 0)
+ // "-1", "0", "1", ..: set fold level
+ default:
+ if (n < 0) {
/* Use the current level for the next line, so that "a1"
* will work there. */
flp->lvl_next = flp->lvl;
- else
+ } else {
flp->lvl_next = n;
+ }
flp->lvl = n;
break;
}
@@ -3072,15 +3107,16 @@ static void foldlevelExpr(fline_T *flp)
flp->lvl = 0;
flp->lvl_next = 0;
}
- if (lnum == curbuf->b_ml.ml_line_count)
+ if (lnum == curbuf->b_ml.ml_line_count) {
flp->lvl_next = 0;
+ }
}
curwin = win;
curbuf = curwin->w_buffer;
}
-/* parseMarker() {{{2 */
+// parseMarker() {{{2
/*
* Parse 'foldmarker' and set "foldendmarker", "foldstartmarkerlen" and
* "foldendmarkerlen".
@@ -3093,7 +3129,7 @@ static void parseMarker(win_T *wp)
foldendmarkerlen = STRLEN(foldendmarker);
}
-/* foldlevelMarker() {{{2 */
+// foldlevelMarker() {{{2
/*
* Low level function to get the foldlevel for the "marker" method.
* "foldendmarker", "foldstartmarkerlen" and "foldendmarkerlen" must have been
@@ -3105,38 +3141,39 @@ static void parseMarker(win_T *wp)
*/
static void foldlevelMarker(fline_T *flp)
{
- char_u *startmarker;
+ char_u *startmarker;
int cstart;
int cend;
int start_lvl = flp->lvl;
- char_u *s;
+ char_u *s;
int n;
- /* cache a few values for speed */
+ // cache a few values for speed
startmarker = flp->wp->w_p_fmr;
cstart = *startmarker;
++startmarker;
cend = *foldendmarker;
- /* Default: no start found, next level is same as current level */
+ // Default: no start found, next level is same as current level
flp->start = 0;
flp->lvl_next = flp->lvl;
- s = ml_get_buf(flp->wp->w_buffer, flp->lnum + flp->off, FALSE);
+ s = ml_get_buf(flp->wp->w_buffer, flp->lnum + flp->off, false);
while (*s) {
if (*s == cstart
&& STRNCMP(s + 1, startmarker, foldstartmarkerlen - 1) == 0) {
- /* found startmarker: set flp->lvl */
+ // found startmarker: set flp->lvl
s += foldstartmarkerlen;
if (ascii_isdigit(*s)) {
n = atoi((char *)s);
if (n > 0) {
flp->lvl = n;
flp->lvl_next = n;
- if (n <= start_lvl)
+ if (n <= start_lvl) {
flp->start = 1;
- else
+ } else {
flp->start = n - start_lvl;
+ }
}
} else {
++flp->lvl;
@@ -3145,16 +3182,17 @@ static void foldlevelMarker(fline_T *flp)
}
} else if (*s == cend && STRNCMP(s + 1, foldendmarker + 1,
foldendmarkerlen - 1) == 0) {
- /* found endmarker: set flp->lvl_next */
+ // found endmarker: set flp->lvl_next
s += foldendmarkerlen;
if (ascii_isdigit(*s)) {
n = atoi((char *)s);
if (n > 0) {
flp->lvl = n;
flp->lvl_next = n - 1;
- /* never start a fold with an end marker */
- if (flp->lvl_next > start_lvl)
+ // never start a fold with an end marker
+ if (flp->lvl_next > start_lvl) {
flp->lvl_next = start_lvl;
+ }
}
} else {
flp->lvl_next--;
@@ -3164,12 +3202,13 @@ static void foldlevelMarker(fline_T *flp)
}
}
- /* The level can't go negative, must be missing a start marker. */
- if (flp->lvl_next < 0)
+ // The level can't go negative, must be missing a start marker.
+ if (flp->lvl_next < 0) {
flp->lvl_next = 0;
+ }
}
-/* foldlevelSyntax() {{{2 */
+// foldlevelSyntax() {{{2
/*
* Low level function to get the foldlevel for the "syntax" method.
* Doesn't use any caching.
@@ -3179,20 +3218,20 @@ static void foldlevelSyntax(fline_T *flp)
linenr_T lnum = flp->lnum + flp->off;
int n;
- /* Use the maximum fold level at the start of this line and the next. */
+ // Use the maximum fold level at the start of this line and the next.
flp->lvl = syn_get_foldlevel(flp->wp, lnum);
flp->start = 0;
if (lnum < flp->wp->w_buffer->b_ml.ml_line_count) {
n = syn_get_foldlevel(flp->wp, lnum + 1);
if (n > flp->lvl) {
- flp->start = n - flp->lvl; /* fold(s) start here */
+ flp->start = n - flp->lvl; // fold(s) start here
flp->lvl = n;
}
}
}
-/* functions for storing the fold state in a View {{{1 */
-/* put_folds() {{{2 */
+// functions for storing the fold state in a View {{{1
+// put_folds() {{{2
/*
* Write commands to "fd" to restore the manual folds in window "wp".
@@ -3208,14 +3247,15 @@ int put_folds(FILE *fd, win_T *wp)
}
}
- /* If some folds are manually opened/closed, need to restore that. */
- if (wp->w_fold_manual)
+ // If some folds are manually opened/closed, need to restore that.
+ if (wp->w_fold_manual) {
return put_foldopen_recurse(fd, wp, &wp->w_folds, (linenr_T)0);
+ }
return OK;
}
-/* put_folds_recurse() {{{2 */
+// put_folds_recurse() {{{2
/*
* Write commands to "fd" to recreate manually created folds.
* Returns FAIL when writing failed.
@@ -3224,20 +3264,22 @@ static int put_folds_recurse(FILE *fd, garray_T *gap, linenr_T off)
{
fold_T *fp = (fold_T *)gap->ga_data;
for (int i = 0; i < gap->ga_len; i++) {
- /* Do nested folds first, they will be created closed. */
- if (put_folds_recurse(fd, &fp->fd_nested, off + fp->fd_top) == FAIL)
+ // Do nested folds first, they will be created closed.
+ if (put_folds_recurse(fd, &fp->fd_nested, off + fp->fd_top) == FAIL) {
return FAIL;
+ }
if (fprintf(fd, "%" PRId64 ",%" PRId64 "fold",
(int64_t)(fp->fd_top + off),
(int64_t)(fp->fd_top + off + fp->fd_len - 1)) < 0
- || put_eol(fd) == FAIL)
+ || put_eol(fd) == FAIL) {
return FAIL;
+ }
++fp;
}
return OK;
}
-/* put_foldopen_recurse() {{{2 */
+// put_foldopen_recurse() {{{2
/*
* Write commands to "fd" to open and close manually opened/closed folds.
* Returns FAIL when writing failed.
@@ -3250,19 +3292,22 @@ static int put_foldopen_recurse(FILE *fd, win_T *wp, garray_T *gap, linenr_T off
for (int i = 0; i < gap->ga_len; i++) {
if (fp->fd_flags != FD_LEVEL) {
if (!GA_EMPTY(&fp->fd_nested)) {
- /* open nested folds while this fold is open */
+ // open nested folds while this fold is open
if (fprintf(fd, "%" PRId64, (int64_t)(fp->fd_top + off)) < 0
|| put_eol(fd) == FAIL
- || put_line(fd, "normal! zo") == FAIL)
+ || put_line(fd, "normal! zo") == FAIL) {
return FAIL;
+ }
if (put_foldopen_recurse(fd, wp, &fp->fd_nested,
- off + fp->fd_top)
- == FAIL)
+ off + fp->fd_top)
+ == FAIL) {
return FAIL;
- /* close the parent when needed */
+ }
+ // close the parent when needed
if (fp->fd_flags == FD_CLOSED) {
- if (put_fold_open_close(fd, fp, off) == FAIL)
+ if (put_fold_open_close(fd, fp, off) == FAIL) {
return FAIL;
+ }
}
} else {
/* Open or close the leaf according to the window foldlevel.
@@ -3270,9 +3315,11 @@ static int put_foldopen_recurse(FILE *fd, win_T *wp, garray_T *gap, linenr_T off
* the parent. */
level = foldLevelWin(wp, off + fp->fd_top);
if ((fp->fd_flags == FD_CLOSED && wp->w_p_fdl >= level)
- || (fp->fd_flags != FD_CLOSED && wp->w_p_fdl < level))
- if (put_fold_open_close(fd, fp, off) == FAIL)
+ || (fp->fd_flags != FD_CLOSED && wp->w_p_fdl < level)) {
+ if (put_fold_open_close(fd, fp, off) == FAIL) {
return FAIL;
+ }
+ }
}
}
++fp;
@@ -3281,7 +3328,7 @@ static int put_foldopen_recurse(FILE *fd, win_T *wp, garray_T *gap, linenr_T off
return OK;
}
-/* put_fold_open_close() {{{2 */
+// put_fold_open_close() {{{2
/*
* Write the open or close command to "fd".
* Returns FAIL when writing failed.
@@ -3291,11 +3338,12 @@ static int put_fold_open_close(FILE *fd, fold_T *fp, linenr_T off)
if (fprintf(fd, "%" PRId64, (int64_t)(fp->fd_top + off)) < 0
|| put_eol(fd) == FAIL
|| fprintf(fd, "normal! z%c",
- fp->fd_flags == FD_CLOSED ? 'c' : 'o') < 0
- || put_eol(fd) == FAIL)
+ fp->fd_flags == FD_CLOSED ? 'c' : 'o') < 0
+ || put_eol(fd) == FAIL) {
return FAIL;
+ }
return OK;
}
-/* }}}1 */
+// }}}1
diff --git a/src/nvim/fold.h b/src/nvim/fold.h
index 95c4b0c1dc..37fab4da60 100644
--- a/src/nvim/fold.h
+++ b/src/nvim/fold.h
@@ -21,6 +21,8 @@ typedef struct foldinfo {
long fi_lines;
} foldinfo_T;
+#define FOLDINFO_INIT { 0, 0, 0, 0 }
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "fold.h.generated.h"
diff --git a/src/nvim/garray.c b/src/nvim/garray.c
index 1cfc2b6176..bc3b7211c9 100644
--- a/src/nvim/garray.c
+++ b/src/nvim/garray.c
@@ -5,16 +5,16 @@
///
/// Functions for handling growing arrays.
-#include <string.h>
#include <inttypes.h>
+#include <string.h>
-#include "nvim/vim.h"
#include "nvim/ascii.h"
+#include "nvim/garray.h"
#include "nvim/log.h"
#include "nvim/memory.h"
#include "nvim/path.h"
-#include "nvim/garray.h"
#include "nvim/strings.h"
+#include "nvim/vim.h"
// #include "nvim/globals.h"
#include "nvim/memline.h"
@@ -146,11 +146,11 @@ void ga_remove_duplicate_strings(garray_T *gap)
char_u *ga_concat_strings_sep(const garray_T *gap, const char *sep)
FUNC_ATTR_NONNULL_RET
{
- const size_t nelem = (size_t) gap->ga_len;
+ const size_t nelem = (size_t)gap->ga_len;
const char **strings = gap->ga_data;
if (nelem == 0) {
- return (char_u *) xstrdup("");
+ return (char_u *)xstrdup("");
}
size_t len = 0;
@@ -169,7 +169,7 @@ char_u *ga_concat_strings_sep(const garray_T *gap, const char *sep)
}
strcpy(s, strings[nelem - 1]);
- return (char_u *) ret;
+ return (char_u *)ret;
}
/// For a growing array that contains a list of strings: concatenate all the
@@ -178,7 +178,7 @@ char_u *ga_concat_strings_sep(const garray_T *gap, const char *sep)
/// @param gap
///
/// @returns the concatenated strings
-char_u* ga_concat_strings(const garray_T *gap) FUNC_ATTR_NONNULL_RET
+char_u *ga_concat_strings(const garray_T *gap) FUNC_ATTR_NONNULL_RET
{
return ga_concat_strings_sep(gap, ",");
}
@@ -198,7 +198,7 @@ void ga_concat(garray_T *gap, const char_u *restrict s)
return;
}
- ga_concat_len(gap, (const char *restrict) s, strlen((char *) s));
+ ga_concat_len(gap, (const char *restrict)s, strlen((char *)s));
}
/// Concatenate a string to a growarray which contains characters
@@ -206,15 +206,14 @@ void ga_concat(garray_T *gap, const char_u *restrict s)
/// @param[out] gap Growarray to modify.
/// @param[in] s String to concatenate.
/// @param[in] len String length.
-void ga_concat_len(garray_T *const gap, const char *restrict s,
- const size_t len)
+void ga_concat_len(garray_T *const gap, const char *restrict s, const size_t len)
FUNC_ATTR_NONNULL_ALL
{
if (len) {
- ga_grow(gap, (int) len);
+ ga_grow(gap, (int)len);
char *data = gap->ga_data;
memcpy(data + gap->ga_len, s, len);
- gap->ga_len += (int) len;
+ gap->ga_len += (int)len;
}
}
diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua
index d2a7c16186..99d80cdebc 100644
--- a/src/nvim/generators/gen_api_dispatch.lua
+++ b/src/nvim/generators/gen_api_dispatch.lua
@@ -7,7 +7,7 @@ if arg[1] == '--help' then
print(' 2: dispatch output file (dispatch_wrappers.generated.h)')
print(' 3: functions metadata output file (funcs_metadata.generated.h)')
print(' 4: API metadata output file (api_metadata.mpack)')
- print(' 5: lua C bindings output file (msgpack_lua_c_bindings.generated.c)')
+ print(' 5: lua C bindings output file (lua_api_c_bindings.generated.c)')
print(' rest: C files where API functions are defined')
end
assert(#arg >= 4)
@@ -247,7 +247,7 @@ for i = 1, #functions do
(j - 1)..'].type == kObjectTypeInteger) {')
output:write('\n '..converted..' = (Float)args.items['..(j - 1)..'].data.integer;')
end
- -- accept empty lua tables as empty dictionarys
+ -- accept empty lua tables as empty dictionaries
if rt:match('^Dictionary') then
output:write('\n } else if (args.items['..(j - 1)..'].type == kObjectTypeArray && args.items['..(j - 1)..'].data.array.size == 0) {') --luacheck: ignore 631
output:write('\n '..converted..' = (Dictionary)ARRAY_DICT_INIT;')
@@ -321,8 +321,6 @@ end
output:write([[
void msgpack_rpc_init_method_table(void)
{
- methods = map_new(String, MsgpackRpcRequestHandler)();
-
]])
for i = 1, #functions do
@@ -380,7 +378,7 @@ output:write('\n')
local lua_c_functions = {}
local function process_function(fn)
- local lua_c_function_name = ('nlua_msgpack_%s'):format(fn.name)
+ local lua_c_function_name = ('nlua_api_%s'):format(fn.name)
write_shifted_output(output, string.format([[
static int %s(lua_State *lstate)
diff --git a/src/nvim/generators/gen_eval.lua b/src/nvim/generators/gen_eval.lua
index 679895421a..945fa5099f 100644
--- a/src/nvim/generators/gen_eval.lua
+++ b/src/nvim/generators/gen_eval.lua
@@ -42,7 +42,7 @@ gperfpipe:write([[
%language=ANSI-C
%global-table
%readonly-tables
-%define initializer-suffix ,0,0,NULL,NULL
+%define initializer-suffix ,0,0,BASE_NONE,NULL,NULL
%define word-array-name functions
%define hash-function-name hash_internal_func_gperf
%define lookup-function-name find_internal_func_gperf
@@ -59,9 +59,10 @@ for name, def in pairs(funcs) do
elseif #args == 1 then
args[2] = 'MAX_FUNC_ARGS'
end
+ local base = def.base or "BASE_NONE"
local func = def.func or ('f_' .. name)
local data = def.data or "NULL"
- gperfpipe:write(('%s, %s, %s, &%s, (FunPtr)%s\n')
- :format(name, args[1], args[2], func, data))
+ gperfpipe:write(('%s, %s, %s, %s, &%s, (FunPtr)%s\n')
+ :format(name, args[1], args[2], base, func, data))
end
gperfpipe:close()
diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua
index d80a6219eb..0454c54faf 100644
--- a/src/nvim/generators/gen_options.lua
+++ b/src/nvim/generators/gen_options.lua
@@ -69,8 +69,6 @@ local get_flags = function(o)
{'alloced'},
{'nodefault'},
{'no_mkrc'},
- {'vi_def'},
- {'vim'},
{'secure'},
{'gettext'},
{'noglob'},
@@ -120,8 +118,11 @@ local get_value = function(v)
return '(char_u *) ' .. value_dumpers[type(v)](v)
end
-local get_defaults = function(d)
- return ('{' .. get_value(d.vi) .. ', ' .. get_value(d.vim) .. '}')
+local get_defaults = function(d,n)
+ if d == nil then
+ error("option '"..n.."' should have a default value")
+ end
+ return get_value(d)
end
local defines = {}
@@ -170,11 +171,11 @@ local dump_option = function(i, o)
if o.defaults.condition then
w(get_cond(o.defaults.condition))
end
- w(' .def_val=' .. get_defaults(o.defaults.if_true))
+ w(' .def_val=' .. get_defaults(o.defaults.if_true, o.full_name))
if o.defaults.condition then
if o.defaults.if_false then
w('#else')
- w(' .def_val=' .. get_defaults(o.defaults.if_false))
+ w(' .def_val=' .. get_defaults(o.defaults.if_false, o.full_name))
end
w('#endif')
end
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 5c2eed363e..beb4ff4da6 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -11,22 +11,25 @@
*/
#include <assert.h>
+#include <inttypes.h>
#include <stdbool.h>
#include <string.h>
-#include <inttypes.h>
-#include "nvim/assert.h"
-#include "nvim/vim.h"
#include "nvim/ascii.h"
-#include "nvim/getchar.h"
+#include "nvim/assert.h"
#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
+#include "nvim/event/loop.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
+#include "nvim/ex_session.h"
#include "nvim/func_attr.h"
+#include "nvim/garray.h"
+#include "nvim/getchar.h"
+#include "nvim/keymap.h"
#include "nvim/lua/executor.h"
#include "nvim/main.h"
#include "nvim/mbyte.h"
@@ -34,24 +37,21 @@
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
-#include "nvim/keymap.h"
-#include "nvim/garray.h"
#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/ops.h"
#include "nvim/option.h"
+#include "nvim/os/fileio.h"
+#include "nvim/os/input.h"
+#include "nvim/os/os.h"
+#include "nvim/plines.h"
#include "nvim/regexp.h"
#include "nvim/screen.h"
-#include "nvim/ex_session.h"
#include "nvim/state.h"
#include "nvim/strings.h"
#include "nvim/ui.h"
#include "nvim/undo.h"
-#include "nvim/event/loop.h"
-#include "nvim/os/input.h"
-#include "nvim/os/os.h"
-#include "nvim/os/fileio.h"
-#include "nvim/api/private/handle.h"
+#include "nvim/vim.h"
/// Index in scriptin
@@ -163,7 +163,7 @@ static size_t last_recorded_len = 0; // number of last recorded chars
*/
void free_buff(buffheader_T *buf)
{
- buffblock_T *p, *np;
+ buffblock_T *p, *np;
for (p = buf->bh_first.b_next; p != NULL; p = np) {
np = p->b_next;
@@ -172,17 +172,15 @@ void free_buff(buffheader_T *buf)
buf->bh_first.b_next = NULL;
}
-/*
- * Return the contents of a buffer as a single string.
- * K_SPECIAL and CSI in the returned string are escaped.
- */
-static char_u *get_buffcont(buffheader_T *buffer,
- int dozero // count == zero is not an error
- )
+/// Return the contents of a buffer as a single string.
+/// K_SPECIAL and CSI in the returned string are escaped.
+///
+/// @param dozero count == zero is not an error
+static char_u *get_buffcont(buffheader_T *buffer, int dozero)
{
size_t count = 0;
- char_u *p = NULL;
- char_u *p2;
+ char_u *p = NULL;
+ char_u *p2;
// compute the total length of the string
for (const buffblock_T *bp = buffer->bh_first.b_next;
@@ -211,7 +209,7 @@ static char_u *get_buffcont(buffheader_T *buffer,
*/
char_u *get_recorded(void)
{
- char_u *p;
+ char_u *p;
size_t len;
p = get_buffcont(&recordbuff, TRUE);
@@ -231,8 +229,9 @@ char_u *get_recorded(void)
* When stopping recording from Insert mode with CTRL-O q, also remove the
* CTRL-O.
*/
- if (len > 0 && restart_edit != 0 && p[len - 1] == Ctrl_O)
+ if (len > 0 && restart_edit != 0 && p[len - 1] == Ctrl_O) {
p[len - 1] = NUL;
+ }
return p;
}
@@ -253,8 +252,7 @@ char_u *get_inserted(void)
/// @param[out] buf Buffer to add to.
/// @param[in] s String to add.
/// @param[in] slen String length or -1 for NUL-terminated string.
-static void add_buff(buffheader_T *const buf, const char *const s,
- ptrdiff_t slen)
+static void add_buff(buffheader_T *const buf, const char *const s, ptrdiff_t slen)
{
if (slen < 0) {
slen = (ptrdiff_t)strlen(s);
@@ -354,8 +352,9 @@ static int read_readbuffers(int advance)
int c;
c = read_readbuf(&readbuf1, advance);
- if (c == NUL)
+ if (c == NUL) {
c = read_readbuf(&readbuf2, advance);
+ }
return c;
}
@@ -583,8 +582,9 @@ void AppendToRedobuffLit(const char_u *str, int len)
*/
void AppendCharToRedobuff(int c)
{
- if (!block_redo)
+ if (!block_redo) {
add_char_buff(&redobuff, c);
+ }
}
/*
@@ -592,8 +592,9 @@ void AppendCharToRedobuff(int c)
*/
void AppendNumberToRedobuff(long n)
{
- if (!block_redo)
+ if (!block_redo) {
add_num_buff(&redobuff, n);
+ }
}
/*
@@ -840,6 +841,14 @@ static void init_typebuf(void)
}
}
+void init_default_mappings(void)
+{
+ add_map((char_u *)"Y y$", NORMAL, true);
+ add_map((char_u *)"<C-L> <Cmd>nohlsearch<Bar>diffupdate<CR><C-L>", NORMAL, true);
+ add_map((char_u *)"<C-U> <C-G>u<C-U>", INSERT, true);
+ add_map((char_u *)"<C-W> <C-G>u<C-W>", INSERT, true);
+}
+
// Insert a string in position 'offset' in the typeahead buffer (for "@r"
// and ":normal" command, vgetorpeek() and check_termcode())
//
@@ -857,10 +866,9 @@ static void init_typebuf(void)
// If silent is true, cmd_silent is set when the characters are obtained.
//
// return FAIL for failure, OK otherwise
-int ins_typebuf(char_u *str, int noremap, int offset,
- bool nottyped, bool silent)
+int ins_typebuf(char_u *str, int noremap, int offset, bool nottyped, bool silent)
{
- char_u *s1, *s2;
+ char_u *s1, *s2;
int newlen;
int addlen;
int i;
@@ -869,8 +877,9 @@ int ins_typebuf(char_u *str, int noremap, int offset,
int nrm;
init_typebuf();
- if (++typebuf.tb_change_cnt == 0)
+ if (++typebuf.tb_change_cnt == 0) {
typebuf.tb_change_cnt = 1;
+ }
addlen = (int)STRLEN(str);
@@ -916,12 +925,13 @@ int ins_typebuf(char_u *str, int noremap, int offset,
typebuf.tb_buf = s1;
memmove(s2 + newoff, typebuf.tb_noremap + typebuf.tb_off,
- (size_t)offset);
+ (size_t)offset);
memmove(s2 + newoff + offset + addlen,
- typebuf.tb_noremap + typebuf.tb_off + offset,
- (size_t)(typebuf.tb_len - offset));
- if (typebuf.tb_noremap != noremapbuf_init)
+ typebuf.tb_noremap + typebuf.tb_off + offset,
+ (size_t)(typebuf.tb_len - offset));
+ if (typebuf.tb_noremap != noremapbuf_init) {
xfree(typebuf.tb_noremap);
+ }
typebuf.tb_noremap = s2;
typebuf.tb_off = newoff;
@@ -940,26 +950,29 @@ int ins_typebuf(char_u *str, int noremap, int offset,
/*
* Adjust typebuf.tb_noremap[] for the new characters:
* If noremap == REMAP_NONE or REMAP_SCRIPT: new characters are
- * (sometimes) not remappable
+ * (sometimes) not remappable
* If noremap == REMAP_YES: all the new characters are mappable
* If noremap > 0: "noremap" characters are not remappable, the rest
- * mappable
+ * mappable
*/
- if (noremap == REMAP_SKIP)
+ if (noremap == REMAP_SKIP) {
nrm = 1;
- else if (noremap < 0)
+ } else if (noremap < 0) {
nrm = addlen;
- else
+ } else {
nrm = noremap;
- for (i = 0; i < addlen; ++i)
+ }
+ for (i = 0; i < addlen; ++i) {
typebuf.tb_noremap[typebuf.tb_off + i + offset] =
- (char_u)((--nrm >= 0) ? val : RM_YES);
+ (char_u)((--nrm >= 0) ? val : RM_YES);
+ }
/* tb_maplen and tb_silent only remember the length of mapped and/or
* silent mappings at the start of the buffer, assuming that a mapped
* sequence doesn't result in typed characters. */
- if (nottyped || typebuf.tb_maplen > offset)
+ if (nottyped || typebuf.tb_maplen > offset) {
typebuf.tb_maplen += addlen;
+ }
if (silent || typebuf.tb_silent > offset) {
typebuf.tb_silent += addlen;
cmd_silent = true;
@@ -991,18 +1004,16 @@ void ins_char_typebuf(int c)
(void)ins_typebuf(buf, KeyNoremap, 0, !KeyTyped, cmd_silent);
}
-/*
- * Return TRUE if the typeahead buffer was changed (while waiting for a
- * character to arrive). Happens when a message was received from a client or
- * from feedkeys().
- * But check in a more generic way to avoid trouble: When "typebuf.tb_buf"
- * changed it was reallocated and the old pointer can no longer be used.
- * Or "typebuf.tb_off" may have been changed and we would overwrite characters
- * that was just added.
- */
-bool typebuf_changed(
- int tb_change_cnt // old value of typebuf.tb_change_cnt
-)
+/// Return TRUE if the typeahead buffer was changed (while waiting for a
+/// character to arrive). Happens when a message was received from a client or
+/// from feedkeys().
+/// But check in a more generic way to avoid trouble: When "typebuf.tb_buf"
+/// changed it was reallocated and the old pointer can no longer be used.
+/// Or "typebuf.tb_off" may have been changed and we would overwrite characters
+/// that was just added.
+///
+/// @param tb_change_cnt old value of typebuf.tb_change_cnt
+bool typebuf_changed(int tb_change_cnt)
{
return tb_change_cnt != 0 && (typebuf.tb_change_cnt != tb_change_cnt
|| typebuf_was_filled
@@ -1043,8 +1054,9 @@ void del_typebuf(int len, int offset)
* Easy case: Just increase typebuf.tb_off.
*/
if (offset == 0 && typebuf.tb_buflen - (typebuf.tb_off + len)
- >= 3 * MAXMAPLEN + 3)
+ >= 3 * MAXMAPLEN + 3) {
typebuf.tb_off += len;
+ }
/*
* Have to move the characters in typebuf.tb_buf[] and typebuf.tb_noremap[]
*/
@@ -1055,9 +1067,9 @@ void del_typebuf(int len, int offset)
*/
if (typebuf.tb_off > MAXMAPLEN) {
memmove(typebuf.tb_buf + MAXMAPLEN,
- typebuf.tb_buf + typebuf.tb_off, (size_t)offset);
+ typebuf.tb_buf + typebuf.tb_off, (size_t)offset);
memmove(typebuf.tb_noremap + MAXMAPLEN,
- typebuf.tb_noremap + typebuf.tb_off, (size_t)offset);
+ typebuf.tb_noremap + typebuf.tb_off, (size_t)offset);
typebuf.tb_off = MAXMAPLEN;
}
// adjust typebuf.tb_buf (include the NUL at the end)
@@ -1067,8 +1079,8 @@ void del_typebuf(int len, int offset)
typebuf.tb_buf + i + len, (size_t)bytes);
// adjust typebuf.tb_noremap[]
memmove(typebuf.tb_noremap + typebuf.tb_off + offset,
- typebuf.tb_noremap + i + len,
- (size_t)(typebuf.tb_len - offset));
+ typebuf.tb_noremap + i + len,
+ (size_t)(typebuf.tb_len - offset));
}
if (typebuf.tb_maplen > offset) { // adjust tb_maplen
@@ -1160,8 +1172,9 @@ static void gotchars(const char_u *chars, size_t len)
void may_sync_undo(void)
{
if ((!(State & (INSERT + CMDLINE)) || arrow_used)
- && scriptin[curscript] == NULL)
- u_sync(FALSE);
+ && scriptin[curscript] == NULL) {
+ u_sync(false);
+ }
}
/*
@@ -1177,8 +1190,9 @@ void alloc_typebuf(void)
typebuf.tb_maplen = 0;
typebuf.tb_silent = 0;
typebuf.tb_no_abbr_cnt = 0;
- if (++typebuf.tb_change_cnt == 0)
+ if (++typebuf.tb_change_cnt == 0) {
typebuf.tb_change_cnt = 1;
+ }
}
/*
@@ -1256,13 +1270,10 @@ void restore_typeahead(tasave_T *tp)
readbuf2 = tp->save_readbuf2;
}
-/*
- * Open a new script file for the ":source!" command.
- */
-void openscript(
- char_u *name,
- bool directly // when true execute directly
-)
+/// Open a new script file for the ":source!" command.
+///
+/// @param directly when true execute directly
+void openscript(char_u *name, bool directly)
{
if (curscript + 1 == NSCRIPT) {
EMSG(_(e_nesting));
@@ -1343,15 +1354,17 @@ static void closescript(void)
file_free(scriptin[curscript], false);
scriptin[curscript] = NULL;
- if (curscript > 0)
+ if (curscript > 0) {
--curscript;
+ }
}
#if defined(EXITFREE)
void close_all_scripts(void)
{
- while (scriptin[0] != NULL)
+ while (scriptin[0] != NULL) {
closescript();
+ }
}
#endif
@@ -1452,60 +1465,81 @@ int vgetc(void)
continue;
}
c = TO_SPECIAL(c2, c);
-
}
// a keypad or special function key was not mapped, use it like
// its ASCII equivalent
switch (c) {
- case K_KPLUS: c = '+'; break;
- case K_KMINUS: c = '-'; break;
- case K_KDIVIDE: c = '/'; break;
- case K_KMULTIPLY: c = '*'; break;
- case K_KENTER: c = CAR; break;
- case K_KPOINT: c = '.'; break;
- case K_KCOMMA: c = ','; break;
- case K_KEQUAL: c = '='; break;
- case K_K0: c = '0'; break;
- case K_K1: c = '1'; break;
- case K_K2: c = '2'; break;
- case K_K3: c = '3'; break;
- case K_K4: c = '4'; break;
- case K_K5: c = '5'; break;
- case K_K6: c = '6'; break;
- case K_K7: c = '7'; break;
- case K_K8: c = '8'; break;
- case K_K9: c = '9'; break;
-
- case K_XHOME:
- case K_ZHOME:
- if (mod_mask == MOD_MASK_SHIFT) {
- c = K_S_HOME;
- mod_mask = 0;
- } else if (mod_mask == MOD_MASK_CTRL) {
- c = K_C_HOME;
- mod_mask = 0;
- } else {
- c = K_HOME;
- }
- break;
- case K_XEND:
- case K_ZEND:
- if (mod_mask == MOD_MASK_SHIFT) {
- c = K_S_END;
- mod_mask = 0;
- } else if (mod_mask == MOD_MASK_CTRL) {
- c = K_C_END;
- mod_mask = 0;
- } else {
- c = K_END;
- }
- break;
+ case K_KPLUS:
+ c = '+'; break;
+ case K_KMINUS:
+ c = '-'; break;
+ case K_KDIVIDE:
+ c = '/'; break;
+ case K_KMULTIPLY:
+ c = '*'; break;
+ case K_KENTER:
+ c = CAR; break;
+ case K_KPOINT:
+ c = '.'; break;
+ case K_KCOMMA:
+ c = ','; break;
+ case K_KEQUAL:
+ c = '='; break;
+ case K_K0:
+ c = '0'; break;
+ case K_K1:
+ c = '1'; break;
+ case K_K2:
+ c = '2'; break;
+ case K_K3:
+ c = '3'; break;
+ case K_K4:
+ c = '4'; break;
+ case K_K5:
+ c = '5'; break;
+ case K_K6:
+ c = '6'; break;
+ case K_K7:
+ c = '7'; break;
+ case K_K8:
+ c = '8'; break;
+ case K_K9:
+ c = '9'; break;
+
+ case K_XHOME:
+ case K_ZHOME:
+ if (mod_mask == MOD_MASK_SHIFT) {
+ c = K_S_HOME;
+ mod_mask = 0;
+ } else if (mod_mask == MOD_MASK_CTRL) {
+ c = K_C_HOME;
+ mod_mask = 0;
+ } else {
+ c = K_HOME;
+ }
+ break;
+ case K_XEND:
+ case K_ZEND:
+ if (mod_mask == MOD_MASK_SHIFT) {
+ c = K_S_END;
+ mod_mask = 0;
+ } else if (mod_mask == MOD_MASK_CTRL) {
+ c = K_C_END;
+ mod_mask = 0;
+ } else {
+ c = K_END;
+ }
+ break;
- case K_XUP: c = K_UP; break;
- case K_XDOWN: c = K_DOWN; break;
- case K_XLEFT: c = K_LEFT; break;
- case K_XRIGHT: c = K_RIGHT; break;
+ case K_XUP:
+ c = K_UP; break;
+ case K_XDOWN:
+ c = K_DOWN; break;
+ case K_XLEFT:
+ c = K_LEFT; break;
+ case K_XRIGHT:
+ c = K_RIGHT; break;
}
// For a multi-byte character get all the bytes and return the
@@ -1555,8 +1589,8 @@ int vgetc(void)
*/
may_garbage_collect = false;
- // Exec lua callbacks for on_keystroke
- nlua_execute_log_keystroke(c);
+ // Execute Lua on_key callbacks.
+ nlua_execute_on_key(c);
return c;
}
@@ -1600,8 +1634,9 @@ int plain_vgetc(void)
*/
int vpeekc(void)
{
- if (old_char != -1)
+ if (old_char != -1) {
return old_char;
+ }
return vgetorpeek(false);
}
@@ -1615,8 +1650,9 @@ int vpeekc_any(void)
int c;
c = vpeekc();
- if (c == NUL && typebuf.tb_len > 0)
+ if (c == NUL && typebuf.tb_len > 0) {
c = ESC;
+ }
return c;
}
@@ -1670,10 +1706,10 @@ static int vgetorpeek(bool advance)
{
int c, c1;
int keylen;
- char_u *s;
- mapblock_T *mp;
- mapblock_T *mp2;
- mapblock_T *mp_match;
+ char_u *s;
+ mapblock_T *mp;
+ mapblock_T *mp2;
+ mapblock_T *mp_match;
int mp_match_len = 0;
bool timedout = false; // waited for more than 1 second
// for mapping to complete
@@ -1692,7 +1728,7 @@ static int vgetorpeek(bool advance)
/*
* This function doesn't work very well when called recursively. This may
* happen though, because of:
- * 1. The call to add_to_showcmd(). char_avail() is then used to check if
+ * 1. The call to add_to_showcmd(). char_avail() is then used to check if
* there is a character available, which calls this function. In that
* case we must return NUL, to indicate no character is available.
* 2. A GUI callback function writes to the screen, causing a
@@ -1701,16 +1737,17 @@ static int vgetorpeek(bool advance)
* thus it should be OK. But don't get a key from the user then.
*/
if (vgetc_busy > 0
- && ex_normal_busy == 0
- )
+ && ex_normal_busy == 0) {
return NUL;
+ }
local_State = get_real_state();
++vgetc_busy;
- if (advance)
+ if (advance) {
KeyStuffed = FALSE;
+ }
init_typebuf();
start_stuff();
@@ -1723,8 +1760,9 @@ static int vgetorpeek(bool advance)
*/
if (typeahead_char != 0) {
c = typeahead_char;
- if (advance)
+ if (advance) {
typeahead_char = 0;
+ }
} else {
c = read_readbuffers(advance);
}
@@ -1794,7 +1832,7 @@ static int vgetorpeek(bool advance)
* - typebuf.tb_buf[typebuf.tb_off] should not be remapped
* - in insert or cmdline mode and 'paste' option set
* - waiting for "hit return to continue" and CR or SPACE
- * typed
+ * typed
* - waiting for a char with --more--
* - in Ctrl-X mode, and we get a valid char for that mode
*/
@@ -1813,8 +1851,8 @@ static int vgetorpeek(bool advance)
&& State != CONFIRM
&& !((ctrl_x_mode_not_default() && vim_is_ctrl_x_key(c1))
|| ((compl_cont_status & CONT_LOCAL)
- && (c1 == Ctrl_N || c1 == Ctrl_P)))
- ) {
+ && (c1 == Ctrl_N ||
+ c1 == Ctrl_P)))) {
if (c1 == K_SPECIAL) {
nolmaplen = 2;
} else {
@@ -1856,14 +1894,16 @@ static int vgetorpeek(bool advance)
// find the match length of this mapping
for (mlen = 1; mlen < typebuf.tb_len; mlen++) {
c2 = typebuf.tb_buf[typebuf.tb_off + mlen];
- if (nomap > 0)
+ if (nomap > 0) {
--nomap;
- else if (c2 == K_SPECIAL)
+ } else if (c2 == K_SPECIAL) {
nomap = 2;
- else
+ } else {
LANGMAP_ADJUST(c2, TRUE);
- if (mp->m_keys[mlen] != c2)
+ }
+ if (mp->m_keys[mlen] != c2) {
break;
+ }
}
/* Don't allow mapping the first byte(s) of a
@@ -1894,17 +1934,21 @@ static int vgetorpeek(bool advance)
&& (mp->m_keys[0] != K_SPECIAL
|| mp->m_keys[1] != KS_EXTRA
|| mp->m_keys[2]
- != (int)KE_SNR))
+ != (int)KE_SNR)) {
continue;
+ }
/*
* If one of the typed keys cannot be
* remapped, skip the entry.
*/
- for (n = mlen; --n >= 0; )
- if (*s++ & (RM_NONE|RM_ABBR))
+ for (n = mlen; --n >= 0; ) {
+ if (*s++ & (RM_NONE|RM_ABBR)) {
break;
- if (n >= 0)
+ }
+ }
+ if (n >= 0) {
continue;
+ }
if (keylen > typebuf.tb_len) {
if (!timedout && !(mp_match != NULL
@@ -2022,10 +2066,11 @@ static int vgetorpeek(bool advance)
*/
if (++mapdepth >= p_mmd) {
EMSG(_("E223: recursive mapping"));
- if (State & CMDLINE)
+ if (State & CMDLINE) {
redrawcmdline();
- else
+ } else {
setcursor();
+ }
flush_buffers(FLUSH_MINIMAL);
mapdepth = 0; // for next one
c = -1;
@@ -2082,9 +2127,9 @@ static int vgetorpeek(bool advance)
* If m_noremap is set, don't remap the whole 'to'
* part.
*/
- if (s == NULL)
+ if (s == NULL) {
i = FAIL;
- else {
+ } else {
int noremap;
// If this is a LANGMAP mapping, then we didn't record the keys
@@ -2093,20 +2138,22 @@ static int vgetorpeek(bool advance)
gotchars(s, STRLEN(s));
}
- if (save_m_noremap != REMAP_YES)
+ if (save_m_noremap != REMAP_YES) {
noremap = save_m_noremap;
- else if (
- STRNCMP(s, save_m_keys != NULL
+ } else if (
+ STRNCMP(s, save_m_keys != NULL
? save_m_keys : mp->m_keys,
- (size_t)keylen)
- != 0)
+ (size_t)keylen)
+ != 0) {
noremap = REMAP_YES;
- else
+ } else {
noremap = REMAP_SKIP;
+ }
i = ins_typebuf(s, noremap,
- 0, TRUE, cmd_silent || save_m_silent);
- if (save_m_expr)
+ 0, TRUE, cmd_silent || save_m_silent);
+ if (save_m_expr) {
xfree(s);
+ }
}
xfree(save_m_keys);
xfree(save_m_str);
@@ -2144,7 +2191,7 @@ static int vgetorpeek(bool advance)
&& (c = inchar(typebuf.tb_buf + typebuf.tb_off + typebuf.tb_len,
3, 25L)) == 0) {
colnr_T col = 0, vcol;
- char_u *ptr;
+ char_u *ptr;
if (mode_displayed) {
unshowmode(true);
@@ -2230,20 +2277,22 @@ 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.
- * 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 & INSERT))
+ // 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 & INSERT)) {
c = Ctrl_L;
- else if ((State & CMDLINE)
- || (cmdwin_type > 0 && tc == ESC)
- )
+ } else if (exmode_active) {
+ c = '\n';
+ } else if ((State & CMDLINE) || (cmdwin_type > 0 && tc == ESC)) {
c = Ctrl_C;
- else
+ } else {
c = ESC;
+ }
tc = c;
break;
}
@@ -2289,11 +2338,13 @@ static int vgetorpeek(bool advance)
curwin->w_wcol = new_wcol;
curwin->w_wrow = new_wrow;
push_showcmd();
- if (typebuf.tb_len > SHOWCMD_COLS)
+ if (typebuf.tb_len > SHOWCMD_COLS) {
i = typebuf.tb_len - SHOWCMD_COLS;
- while (i < typebuf.tb_len)
+ }
+ while (i < typebuf.tb_len) {
(void)add_to_showcmd(typebuf.tb_buf[typebuf.tb_off
+ i++]);
+ }
curwin->w_wcol = old_wcol;
curwin->w_wrow = old_wrow;
}
@@ -2336,8 +2387,9 @@ static int vgetorpeek(bool advance)
typebuf.tb_buflen - typebuf.tb_off - typebuf.tb_len - 1,
wait_time);
- if (i != 0)
+ if (i != 0) {
pop_showcmd();
+ }
if (c1 == 1) {
if (State & INSERT) {
edit_unputchar();
@@ -2373,8 +2425,8 @@ static int vgetorpeek(bool advance)
/*
* The "INSERT" message is taken care of here:
- * if we return an ESC to exit insert mode, the message is deleted
- * if we don't return an ESC but deleted the message before, redisplay it
+ * if we return an ESC to exit insert mode, the message is deleted
+ * if we don't return an ESC but deleted the message before, redisplay it
*/
if (advance && p_smd && msg_silent == 0 && (State & INSERT)) {
if (c == ESC && !mode_deleted && !no_mapping && mode_displayed) {
@@ -2408,34 +2460,30 @@ static int vgetorpeek(bool advance)
return c;
}
-/*
- * inchar() - get one character from
- * 1. a scriptfile
- * 2. the keyboard
- *
- * As much characters as we can get (upto 'maxlen') are put in "buf" and
- * NUL terminated (buffer length must be 'maxlen' + 1).
- * Minimum for "maxlen" is 3!!!!
- *
- * "tb_change_cnt" is the value of typebuf.tb_change_cnt if "buf" points into
- * it. When typebuf.tb_change_cnt changes (e.g., when a message is received
- * from a remote client) "buf" can no longer be used. "tb_change_cnt" is 0
- * otherwise.
- *
- * If we got an interrupt all input is read until none is available.
- *
- * If wait_time == 0 there is no waiting for the char.
- * If wait_time == n we wait for n msec for a character to arrive.
- * If wait_time == -1 we wait forever for a character to arrive.
- *
- * Return the number of obtained characters.
- * Return -1 when end of input script reached.
- */
-int inchar(
- char_u *buf,
- int maxlen,
- long wait_time // milli seconds
-)
+/// inchar() - get one character from
+/// 1. a scriptfile
+/// 2. the keyboard
+///
+/// As much characters as we can get (up to 'maxlen') are put in "buf" and
+/// NUL terminated (buffer length must be 'maxlen' + 1).
+/// Minimum for "maxlen" is 3!!!!
+///
+/// "tb_change_cnt" is the value of typebuf.tb_change_cnt if "buf" points into
+/// it. When typebuf.tb_change_cnt changes (e.g., when a message is received
+/// from a remote client) "buf" can no longer be used. "tb_change_cnt" is 0
+/// otherwise.
+///
+/// If we got an interrupt all input is read until none is available.
+///
+/// If wait_time == 0 there is no waiting for the char.
+/// If wait_time == n we wait for n msec for a character to arrive.
+/// If wait_time == -1 we wait forever for a character to arrive.
+///
+/// Return the number of obtained characters.
+/// Return -1 when end of input script reached.
+///
+/// @param wait_time milli seconds
+int inchar(char_u *buf, int maxlen, long wait_time)
{
int len = 0; // Init for GCC.
int retesc = false; // Return ESC with gotint.
@@ -2541,10 +2589,10 @@ int fix_input_buffer(char_u *buf, int len)
// Reading from script, need to process special bytes
int i;
- char_u *p = buf;
+ char_u *p = buf;
// Two characters are special: NUL and K_SPECIAL.
- // Replace NUL by K_SPECIAL KS_ZERO KE_FILLER
+ // Replace NUL by K_SPECIAL KS_ZERO KE_FILLER
// Replace K_SPECIAL by K_SPECIAL KS_SPECIAL KE_FILLER
// Replace CSI by K_SPECIAL KS_EXTRA KE_CSI
for (i = len; --i >= 0; ++p) {
@@ -2585,9 +2633,8 @@ int fix_input_buffer(char_u *buf, int len)
/// @param[in] orig_rhs_len `strlen` of orig_rhs.
/// @param[in] cpo_flags See param docs for @ref replace_termcodes.
/// @param[out] mapargs MapArguments struct holding the replaced strings.
-void set_maparg_lhs_rhs(const char_u *orig_lhs, const size_t orig_lhs_len,
- const char_u *orig_rhs, const size_t orig_rhs_len,
- int cpo_flags, MapArguments *mapargs)
+void set_maparg_lhs_rhs(const char_u *orig_lhs, const size_t orig_lhs_len, const char_u *orig_rhs,
+ const size_t orig_rhs_len, int cpo_flags, MapArguments *mapargs)
{
char_u *lhs_buf = NULL;
char_u *rhs_buf = NULL;
@@ -2754,11 +2801,10 @@ int str_to_mapargs(const char_u *strargs, bool is_unmap, MapArguments *mapargs)
/// @param mode @see do_map
/// @param is_abbrev @see do_map
/// @param buf Target Buffer
-int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
- buf_T *buf)
+int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T *buf)
{
- mapblock_T *mp, **mpp;
- char_u *p;
+ mapblock_T *mp, **mpp;
+ char_u *p;
int n;
int len = 0; // init for GCC
int did_it = false;
@@ -2767,8 +2813,8 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
int retval = 0;
int hash;
int new_hash;
- mapblock_T **abbr_table;
- mapblock_T **map_table;
+ mapblock_T **abbr_table;
+ mapblock_T **map_table;
int noremap;
map_table = maphash;
@@ -3138,15 +3184,15 @@ int do_map(int maptype, char_u *arg, int mode, bool is_abbrev)
MapArguments parsed_args;
int result = str_to_mapargs(arg, maptype == 1, &parsed_args);
switch (result) {
- case 0:
- break;
- case 1:
- // invalid arguments
- goto free_and_return;
- default:
- assert(false && "Unknown return code from str_to_mapargs!");
- result = -1;
- goto free_and_return;
+ case 0:
+ break;
+ case 1:
+ // invalid arguments
+ goto free_and_return;
+ default:
+ assert(false && "Unknown return code from str_to_mapargs!");
+ result = -1;
+ goto free_and_return;
} // switch
result = buf_do_map(maptype, &parsed_args, mode, is_abbrev, curbuf);
@@ -3163,7 +3209,7 @@ free_and_return:
*/
static void mapblock_free(mapblock_T **mpp)
{
- mapblock_T *mp;
+ mapblock_T *mp;
mp = *mpp;
xfree(mp->m_keys);
@@ -3189,7 +3235,7 @@ static void validate_maphash(void)
*/
int get_map_mode(char_u **cmdp, bool forceit)
{
- char_u *p;
+ char_u *p;
int modec;
int mode;
@@ -3243,21 +3289,19 @@ void map_clear_mode(char_u *cmdp, char_u *arg, int forceit, int abbr)
mode = get_map_mode(&cmdp, forceit);
map_clear_int(curbuf, mode,
- local,
- abbr);
+ local,
+ abbr);
}
-/*
- * Clear all mappings in "mode".
- */
-void map_clear_int(
- buf_T *buf, // buffer for local mappings
- int mode, // mode in which to delete
- bool local, // true for buffer-local mappings
- bool abbr // true for abbreviations
-)
+/// Clear all mappings in "mode".
+///
+/// @param buf, buffer for local mappings
+/// @param mode mode in which to delete
+/// @param local true for buffer-local mappings
+/// @param abbr true for abbreviations
+void map_clear_int(buf_T *buf, int mode, bool local, bool abbr)
{
- mapblock_T *mp, **mpp;
+ mapblock_T *mp, **mpp;
int hash;
int new_hash;
@@ -3274,10 +3318,11 @@ void map_clear_int(
mpp = &first_abbr;
}
} else {
- if (local)
+ if (local) {
mpp = &buf->b_maphash[hash];
- else
+ } else {
mpp = &maphash[hash];
+ }
}
while (*mpp != NULL) {
mp = *mpp;
@@ -3355,10 +3400,8 @@ char *map_mode_to_chars(int mode)
return (char *)mapmode.ga_data;
}
-static void showmap(
- mapblock_T *mp,
- bool local // true for buffer-local map
-)
+/// @param local true for buffer-local map
+static void showmap(mapblock_T *mp, bool local)
{
size_t len = 1;
@@ -3380,8 +3423,9 @@ static void showmap(
xfree(mapchars);
}
- while (++len <= 3)
+ while (++len <= 3) {
msg_putchar(' ');
+ }
// Display the LHS. Get length of what we write.
len = (size_t)msg_outtrans_special(mp->m_keys, true, 0);
@@ -3398,10 +3442,11 @@ static void showmap(
msg_putchar(' ');
}
- if (local)
+ if (local) {
msg_putchar('@');
- else
+ } else {
msg_putchar(' ');
+ }
/* Use FALSE below if we only want things like <Up> to show up as such on
* the rhs, and not M-x etc, TRUE gets both -- webb */
@@ -3431,8 +3476,7 @@ static void showmap(
/// @param[in] abbr true if checking abbreviations in place of mappings.
///
/// @return true if there is at least one mapping with given parameters.
-bool map_to_exists(const char *const str, const char *const modechars,
- const bool abbr)
+bool map_to_exists(const char *const str, const char *const modechars, const bool abbr)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
{
int mode = 0;
@@ -3477,7 +3521,7 @@ bool map_to_exists(const char *const str, const char *const modechars,
/// @return true if there is at least one mapping with given parameters.
int map_to_exists_mode(const char *const rhs, const int mode, const bool abbr)
{
- mapblock_T *mp;
+ mapblock_T *mp;
int hash;
bool exp_buffer = false;
@@ -3523,29 +3567,25 @@ static int expand_mapmodes = 0;
static bool expand_isabbrev = false;
static bool expand_buffer = false;
-/*
- * Work out what to complete when doing command line completion of mapping
- * or abbreviation names.
- */
-char_u *set_context_in_map_cmd(
- expand_T *xp,
- char_u *cmd,
- char_u *arg,
- bool forceit, // true if '!' given
- bool isabbrev, // true if abbreviation
- bool isunmap, // true if unmap/unabbrev command
- cmdidx_T cmdidx
-)
+/// Work out what to complete when doing command line completion of mapping
+/// or abbreviation names.
+///
+/// @param forceit true if '!' given
+/// @param isabbrev true if abbreviation
+/// @param isunmap true if unmap/unabbrev command
+char_u *set_context_in_map_cmd(expand_T *xp, char_u *cmd, char_u *arg, bool forceit, bool isabbrev,
+ bool isunmap, cmdidx_T cmdidx)
{
- if (forceit && cmdidx != CMD_map && cmdidx != CMD_unmap)
+ if (forceit && cmdidx != CMD_map && cmdidx != CMD_unmap) {
xp->xp_context = EXPAND_NOTHING;
- else {
- if (isunmap)
+ } else {
+ if (isunmap) {
expand_mapmodes = get_map_mode(&cmd, forceit || isabbrev);
- else {
+ } else {
expand_mapmodes = INSERT + CMDLINE;
- if (!isabbrev)
+ if (!isabbrev) {
expand_mapmodes += VISUAL + SELECTMODE + NORMAL + OP_PENDING;
+ }
}
expand_isabbrev = isabbrev;
xp->xp_context = EXPAND_MAPPINGS;
@@ -3593,11 +3633,11 @@ char_u *set_context_in_map_cmd(
// Return OK if matches found, FAIL otherwise.
int ExpandMappings(regmatch_T *regmatch, int *num_file, char_u ***file)
{
- mapblock_T *mp;
+ mapblock_T *mp;
int hash;
int count;
int round;
- char_u *p;
+ char_u *p;
int i;
validate_maphash();
@@ -3632,10 +3672,11 @@ int ExpandMappings(regmatch_T *regmatch, int *num_file, char_u ***file)
}
if (vim_regexec(regmatch, p, (colnr_T)0)) {
- if (round == 1)
+ if (round == 1) {
++count;
- else
+ } else {
(*file)[count++] = vim_strsave(p);
+ }
}
}
@@ -3645,17 +3686,18 @@ int ExpandMappings(regmatch_T *regmatch, int *num_file, char_u ***file)
break; // for (hash)
}
mp = first_abbr;
- } else if (expand_buffer)
+ } else if (expand_buffer) {
mp = curbuf->b_maphash[hash];
- else
+ } else {
mp = maphash[hash];
+ }
for (; mp; mp = mp->m_next) {
if (mp->m_mode & expand_mapmodes) {
p = translate_mapping(mp->m_keys, CPO_TO_CPO_FLAGS);
if (p != NULL && vim_regexec(regmatch, p, (colnr_T)0)) {
- if (round == 1)
+ if (round == 1) {
++count;
- else {
+ } else {
(*file)[count++] = p;
p = NULL;
}
@@ -3675,9 +3717,9 @@ int ExpandMappings(regmatch_T *regmatch, int *num_file, char_u ***file)
} // for (round)
if (count > 1) {
- char_u **ptr1;
- char_u **ptr2;
- char_u **ptr3;
+ char_u **ptr1;
+ char_u **ptr2;
+ char_u **ptr3;
// Sort the matches
sort_strings(*file, count);
@@ -3688,9 +3730,9 @@ int ExpandMappings(regmatch_T *regmatch, int *num_file, char_u ***file)
ptr3 = ptr1 + count;
while (ptr2 < ptr3) {
- if (STRCMP(*ptr1, *ptr2))
+ if (STRCMP(*ptr1, *ptr2)) {
*++ptr1 = *ptr2++;
- else {
+ } else {
xfree(*ptr2++);
count--;
}
@@ -3722,10 +3764,10 @@ bool check_abbr(int c, char_u *ptr, int col, int mincol)
int len;
int scol; // starting column of the abbr.
int j;
- char_u *s;
+ char_u *s;
char_u tb[MB_MAXBYTES + 4];
- mapblock_T *mp;
- mapblock_T *mp2;
+ mapblock_T *mp;
+ mapblock_T *mp2;
int clen = 0; // length in characters
bool is_id = true;
@@ -3769,8 +3811,9 @@ bool check_abbr(int c, char_u *ptr, int col, int mincol)
scol = (int)(p - ptr);
}
- if (scol < mincol)
+ if (scol < mincol) {
scol = mincol;
+ }
if (scol < col) { // there is a word in front of the cursor
ptr += scol;
len = col - scol;
@@ -3848,17 +3891,19 @@ bool check_abbr(int c, char_u *ptr, int col, int mincol)
// insert the last typed char
(void)ins_typebuf(tb, 1, 0, true, mp->m_silent);
}
- if (mp->m_expr)
+ if (mp->m_expr) {
s = eval_map_expr(mp->m_str, c);
- else
+ } else {
s = mp->m_str;
+ }
if (s != NULL) {
// insert the to string
(void)ins_typebuf(s, mp->m_noremap, 0, true, mp->m_silent);
// no abbrev. for these chars
typebuf.tb_no_abbr_cnt += (int)STRLEN(s) + j + 1;
- if (mp->m_expr)
+ if (mp->m_expr) {
xfree(s);
+ }
}
tb[0] = Ctrl_H;
@@ -3873,20 +3918,16 @@ bool check_abbr(int c, char_u *ptr, int col, int mincol)
return false;
}
-/*
- * Evaluate the RHS of a mapping or abbreviations and take care of escaping
- * special characters.
- */
-static char_u *
-eval_map_expr (
- char_u *str,
- int c // NUL or typed character for abbreviation
-)
+/// Evaluate the RHS of a mapping or abbreviations and take care of escaping
+/// special characters.
+///
+/// @param c NUL or typed character for abbreviation
+static char_u *eval_map_expr(char_u *str, int c)
{
- char_u *res;
- char_u *p;
- char_u *expr;
- char_u *save_cmd;
+ char_u *res;
+ char_u *p;
+ char_u *expr;
+ char_u *save_cmd;
pos_T save_cursor;
int save_msg_col;
int save_msg_row;
@@ -3906,9 +3947,9 @@ eval_map_expr (
save_cursor = curwin->w_cursor;
save_msg_col = msg_col;
save_msg_row = msg_row;
- p = eval_to_string(expr, NULL, FALSE);
- --textlock;
- --ex_normal_lock;
+ p = eval_to_string(expr, NULL, false);
+ textlock--;
+ ex_normal_lock--;
curwin->w_cursor = save_cursor;
msg_col = save_msg_col;
msg_row = save_msg_row;
@@ -3916,8 +3957,9 @@ eval_map_expr (
restore_cmdline_alloc(save_cmd);
xfree(expr);
- if (p == NULL)
+ if (p == NULL) {
return NULL;
+ }
// Escape CSI in the result to be able to use the string as typeahead.
res = vim_strsave_escape_csi(p);
xfree(p);
@@ -3960,7 +4002,7 @@ char_u *vim_strsave_escape_csi(char_u *p)
*/
void vim_unescape_csi(char_u *p)
{
- char_u *s = p, *d = p;
+ char_u *s = p, *d = p;
while (*s != NUL) {
if (s[0] == K_SPECIAL && s[1] == KS_SPECIAL && s[2] == KE_FILLER) {
@@ -3970,26 +4012,23 @@ void vim_unescape_csi(char_u *p)
&& s[1] == KS_EXTRA && s[2] == (int)KE_CSI) {
*d++ = CSI;
s += 3;
- } else
+ } else {
*d++ = *s++;
+ }
}
*d = NUL;
}
-/*
- * Write map commands for the current mappings to an .exrc file.
- * Return FAIL on error, OK otherwise.
- */
-int
-makemap(
- FILE *fd,
- buf_T *buf // buffer for local mappings or NULL
-)
+/// Write map commands for the current mappings to an .exrc file.
+/// Return FAIL on error, OK otherwise.
+///
+/// @param buf buffer for local mappings or NULL
+int makemap(FILE *fd, buf_T *buf)
{
- mapblock_T *mp;
+ mapblock_T *mp;
char_u c1, c2, c3;
- char_u *p;
- char *cmd;
+ char_u *p;
+ char *cmd;
int abbr;
int hash;
bool did_cpo = false;
@@ -4199,13 +4238,14 @@ makemap(
// return FAIL for failure, OK otherwise
int put_escstr(FILE *fd, char_u *strstart, int what)
{
- char_u *str = strstart;
+ char_u *str = strstart;
int c;
// :map xx <Nop>
if (*str == NUL && what == 1) {
- if (fprintf(fd, "<Nop>") < 0)
+ if (fprintf(fd, "<Nop>") < 0) {
return FAIL;
+ }
return OK;
}
@@ -4214,9 +4254,11 @@ int put_escstr(FILE *fd, char_u *strstart, int what)
// K_SPECIAL and CSI bytes.
const char *p = mb_unescape((const char **)&str);
if (p != NULL) {
- while (*p != NUL)
- if (fputc(*p++, fd) < 0)
+ while (*p != NUL) {
+ if (fputc(*p++, fd) < 0) {
return FAIL;
+ }
+ }
--str;
continue;
}
@@ -4251,11 +4293,13 @@ int put_escstr(FILE *fd, char_u *strstart, int what)
*/
if (c == NL) {
if (what == 2) {
- if (fprintf(fd, "\\\026\n") < 0)
+ if (fprintf(fd, "\\\026\n") < 0) {
return FAIL;
+ }
} else {
- if (fprintf(fd, "<NL>") < 0)
+ if (fprintf(fd, "<NL>") < 0) {
return FAIL;
+ }
}
continue;
}
@@ -4272,39 +4316,38 @@ int put_escstr(FILE *fd, char_u *strstart, int what)
* A space in the lhs of a :map needs a CTRL-V.
*/
if (what == 2 && (ascii_iswhite(c) || c == '"' || c == '\\')) {
- if (putc('\\', fd) < 0)
+ if (putc('\\', fd) < 0) {
return FAIL;
+ }
} else if (c < ' ' || c > '~' || c == '|'
|| (what == 0 && c == ' ')
|| (what == 1 && str == strstart && c == ' ')
|| (what != 2 && c == '<')) {
- if (putc(Ctrl_V, fd) < 0)
+ if (putc(Ctrl_V, fd) < 0) {
return FAIL;
+ }
}
- if (putc(c, fd) < 0)
+ if (putc(c, fd) < 0) {
return FAIL;
+ }
}
return OK;
}
-/*
- * Check the string "keys" against the lhs of all mappings.
- * Return pointer to rhs of mapping (mapblock->m_str).
- * NULL when no mapping found.
- */
-char_u *
-check_map (
- char_u *keys,
- int mode,
- int exact, // require exact match
- int ign_mod, // ignore preceding modifier
- int abbr, // do abbreviations
- mapblock_T **mp_ptr, // return: pointer to mapblock or NULL
- int *local_ptr // return: buffer-local mapping or NULL
-)
+/// Check the string "keys" against the lhs of all mappings.
+/// Return pointer to rhs of mapping (mapblock->m_str).
+/// NULL when no mapping found.
+///
+/// @param exact require exact match
+/// @param ign_mod ignore preceding modifier
+/// @param abbr do abbreviations
+/// @param mp_ptr return: pointer to mapblock or NULL
+/// @param local_ptr return: buffer-local mapping or NULL
+char_u *check_map(char_u *keys, int mode, int exact, int ign_mod, int abbr, mapblock_T **mp_ptr,
+ int *local_ptr)
{
int len, minlen;
- mapblock_T *mp;
+ mapblock_T *mp;
validate_maphash();
@@ -4339,10 +4382,12 @@ check_map (
}
minlen = keylen < len ? keylen : len;
if (STRNCMP(s, keys, minlen) == 0) {
- if (mp_ptr != NULL)
+ if (mp_ptr != NULL) {
*mp_ptr = mp;
- if (local_ptr != NULL)
+ }
+ if (local_ptr != NULL) {
*local_ptr = local;
+ }
return mp->m_str;
}
}
@@ -4354,37 +4399,41 @@ check_map (
}
-/*
- * Add a mapping "map" for mode "mode".
- * Need to put string in allocated memory, because do_map() will modify it.
- */
-void add_map(char_u *map, int mode)
+/// Add a mapping. Unlike @ref do_map this copies the {map} argument, so
+/// static or read-only strings can be used.
+///
+/// @param map C-string containing the arguments of the map/abbrev command,
+/// i.e. everything except the initial `:[X][nore]map`.
+/// @param mode Bitflags representing the mode in which to set the mapping.
+/// See @ref get_map_mode.
+/// @param nore If true, make a non-recursive mapping.
+void add_map(char_u *map, int mode, bool nore)
{
- char_u *s;
- char_u *cpo_save = p_cpo;
+ char_u *s;
+ char_u *cpo_save = p_cpo;
p_cpo = (char_u *)""; // Allow <> notation
+ // Need to put string in allocated memory, because do_map() will modify it.
s = vim_strsave(map);
- (void)do_map(0, s, mode, FALSE);
+ (void)do_map(nore ? 2 : 0, s, mode, false);
xfree(s);
p_cpo = cpo_save;
}
-// Translate an internal mapping/abbreviation representation into the
-// corresponding external one recognized by :map/:abbrev commands.
-//
-// This function is called when expanding mappings/abbreviations on the
-// command-line.
-//
-// It uses a growarray to build the translation string since the latter can be
-// wider than the original description. The caller has to free the string
-// afterwards.
-//
-// Returns NULL when there is a problem.
-static char_u * translate_mapping (
- char_u *str,
- int cpo_flags // Value of various flags present in &cpo
-)
+/// Translate an internal mapping/abbreviation representation into the
+/// corresponding external one recognized by :map/:abbrev commands.
+///
+/// This function is called when expanding mappings/abbreviations on the
+/// command-line.
+///
+/// It uses a growarray to build the translation string since the latter can be
+/// wider than the original description. The caller has to free the string
+/// afterwards.
+///
+/// @param cpo_flags Value of various flags present in &cpo
+///
+/// @return NULL when there is a problem.
+static char_u *translate_mapping(char_u *str, int cpo_flags)
{
garray_T ga;
ga_init(&ga, 1, 40);
@@ -4432,8 +4481,9 @@ static bool typebuf_match_len(const uint8_t *str, int *mlen)
{
int i;
for (i = 0; i < typebuf.tb_len && str[i]; i++) {
- if (str[i] != typebuf.tb_buf[typebuf.tb_off + i])
+ if (str[i] != typebuf.tb_buf[typebuf.tb_off + i]) {
break;
+ }
}
*mlen = i;
return str[i] == NUL; // matched the whole string
@@ -4454,7 +4504,7 @@ mapblock_T *get_maphash(int index, buf_T *buf)
}
/// Get command argument for <Cmd> key
-char_u * getcmdkeycmd(int promptc, void *cookie, int indent, bool do_concat)
+char_u *getcmdkeycmd(int promptc, void *cookie, int indent, bool do_concat)
{
garray_T line_ga;
int c1 = -1, c2;
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 7c7ce5e65f..4d54907a75 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -138,14 +138,14 @@ EXTERN int mod_mask INIT(= 0x0); // current key modifiers
// update_screen().
EXTERN int cmdline_row;
-EXTERN int redraw_cmdline INIT(= false); // cmdline must be redrawn
-EXTERN int clear_cmdline INIT(= false); // cmdline must be cleared
-EXTERN int mode_displayed INIT(= false); // mode is being displayed
-EXTERN int cmdline_star INIT(= false); // cmdline is crypted
-EXTERN int redrawing_cmdline INIT(= false); // cmdline is being redrawn
-EXTERN int cmdline_was_last_drawn INIT(= false); // cmdline was last drawn
+EXTERN bool redraw_cmdline INIT(= false); // cmdline must be redrawn
+EXTERN bool clear_cmdline INIT(= false); // cmdline must be cleared
+EXTERN bool mode_displayed INIT(= false); // mode is being displayed
+EXTERN int cmdline_star INIT(= false); // cmdline is encrypted
+EXTERN bool redrawing_cmdline INIT(= false); // cmdline is being redrawn
+EXTERN bool cmdline_was_last_drawn INIT(= false); // cmdline was last drawn
-EXTERN int exec_from_reg INIT(= false); // executing register
+EXTERN bool exec_from_reg INIT(= false); // executing register
// When '$' is included in 'cpoptions' option set:
// When a change command is given that deletes only part of a line, a dollar
@@ -165,7 +165,7 @@ EXTERN int compl_interrupted INIT(= false);
// Set when doing something for completion that may call edit() recursively,
// which is not allowed. Also used to disable folding during completion
-EXTERN int compl_busy INIT(= false);
+EXTERN bool compl_busy INIT(= false);
// List of flags for method of completion.
EXTERN int compl_cont_status INIT(= 0);
@@ -201,23 +201,23 @@ 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 int keep_msg_more INIT(= false); // keep_msg was set by msgmore()
-EXTERN int need_fileinfo INIT(= false); // do fileinfo() after redraw
+EXTERN bool keep_msg_more INIT(= false); // keep_msg was set by msgmore()
+EXTERN bool need_fileinfo INIT(= false); // do fileinfo() after redraw
EXTERN int msg_scroll INIT(= false); // msg_start() will scroll
-EXTERN int msg_didout INIT(= false); // msg_outstr() was used in line
-EXTERN int msg_didany INIT(= false); // msg_outstr() was used at all
-EXTERN int msg_nowait INIT(= false); // don't wait for this msg
+EXTERN bool msg_didout INIT(= false); // msg_outstr() was used in line
+EXTERN bool msg_didany INIT(= false); // msg_outstr() was used at all
+EXTERN bool msg_nowait INIT(= false); // don't wait for this msg
EXTERN int emsg_off INIT(= 0); // don't display errors for now,
// unless 'debug' is set.
-EXTERN int info_message INIT(= false); // printing informative message
+EXTERN bool info_message INIT(= false); // printing informative message
EXTERN bool msg_hist_off INIT(= false); // don't add messages to history
-EXTERN int need_clr_eos INIT(= false); // need to clear text before
+EXTERN bool need_clr_eos INIT(= false); // need to clear text before
// displaying a message.
EXTERN int emsg_skip INIT(= 0); // don't display errors for
// expression that is skipped
EXTERN bool emsg_severe INIT(= false); // use message of next of several
// emsg() calls for throw
-EXTERN int did_endif INIT(= false); // just had ":endif"
+EXTERN bool did_endif INIT(= false); // just had ":endif"
EXTERN dict_T vimvardict; // Dictionary with v: variables
EXTERN dict_T globvardict; // Dictionary with g: variables
/// g: value
@@ -225,25 +225,24 @@ EXTERN dict_T globvardict; // Dictionary with g: variables
EXTERN int did_emsg; // set by emsg() when the message
// is displayed or thrown
EXTERN bool called_vim_beep; // set if vim_beep() is called
-EXTERN int did_emsg_syntax; // did_emsg set because of a
+EXTERN bool did_emsg_syntax; // did_emsg set because of a
// syntax error
EXTERN int called_emsg; // always set by emsg()
EXTERN int ex_exitval INIT(= 0); // exit value for ex mode
EXTERN bool emsg_on_display INIT(= false); // there is an error message
-EXTERN int rc_did_emsg INIT(= false); // vim_regcomp() called emsg()
+EXTERN bool rc_did_emsg INIT(= false); // vim_regcomp() called emsg()
-EXTERN int no_wait_return INIT(= 0); // don't wait for return for now
-EXTERN int need_wait_return INIT(= 0); // need to wait for return later
-EXTERN int did_wait_return INIT(= false); // wait_return() was used and
- // nothing written since then
-EXTERN int need_maketitle INIT(= true); // call maketitle() soon
+EXTERN int no_wait_return INIT(= 0); // don't wait for return for now
+EXTERN bool need_wait_return INIT(= false); // need to wait for return later
+EXTERN bool did_wait_return INIT(= false); // wait_return() was used and
+ // nothing written since then
+EXTERN bool need_maketitle INIT(= true); // call maketitle() soon
EXTERN int quit_more INIT(= false); // 'q' hit at "--more--" msg
-EXTERN int ex_keep_indent INIT(= false); // getexmodeline(): keep indent
EXTERN int vgetc_busy INIT(= 0); // when inside vgetc() then > 0
-EXTERN int didset_vim INIT(= false); // did set $VIM ourselves
-EXTERN int didset_vimruntime INIT(= false); // idem for $VIMRUNTIME
+EXTERN bool didset_vim INIT(= false); // did set $VIM ourselves
+EXTERN bool didset_vimruntime INIT(= false); // idem for $VIMRUNTIME
/// Lines left before a "more" message. Ex mode needs to be able to reset this
/// after you type something.
@@ -369,7 +368,7 @@ EXTERN colnr_T search_match_endcol; // col nr of match end
EXTERN linenr_T search_first_line INIT(= 0); // for :{FIRST},{last}s/pat
EXTERN linenr_T search_last_line INIT(= MAXLNUM); // for :{first},{LAST}s/pat
-EXTERN int no_smartcase INIT(= false); // don't use 'smartcase' once
+EXTERN bool no_smartcase INIT(= false); // don't use 'smartcase' once
EXTERN int need_check_timestamps INIT(= false); // need to check file
// timestamps asap
@@ -450,7 +449,7 @@ EXTERN frame_T *topframe; // top of the window frame tree
EXTERN tabpage_T *first_tabpage;
EXTERN tabpage_T *lastused_tabpage;
EXTERN tabpage_T *curtab;
-EXTERN int redraw_tabline INIT(= false); // need to redraw tabline
+EXTERN bool redraw_tabline INIT(= false); // need to redraw tabline
// Iterates over all tabs in the tab list
# define FOR_ALL_TABS(tp) for (tabpage_T *tp = first_tabpage; tp != NULL; tp = tp->tp_next)
@@ -502,15 +501,12 @@ EXTERN volatile int full_screen INIT(= false);
/// Non-zero when only "safe" commands are allowed, e.g. when sourcing .exrc or
/// .vimrc in current directory.
-EXTERN int secure INIT(= false);
+EXTERN int secure INIT(= 0);
/// Non-zero when changing text and jumping to another window/buffer is not
/// allowed.
EXTERN int textlock INIT(= 0);
-/// Non-zero when the current buffer can't be changed. Used for FileChangedRO.
-EXTERN int curbuf_lock INIT(= 0);
-
/// Non-zero when no buffer name can be changed, no buffer can be deleted and
/// current directory can't be changed. Used for SwapExists et al.
EXTERN int allbuf_lock INIT(= 0);
@@ -528,6 +524,8 @@ EXTERN pos_T VIsual;
EXTERN int VIsual_active INIT(= false);
/// Whether Select mode is active.
EXTERN int VIsual_select INIT(= false);
+/// Restart Select mode when next cmd finished
+EXTERN int restart_VIsual_select INIT(= 0);
/// Whether to restart the selection after a Select-mode mapping or menu.
EXTERN int VIsual_reselect;
/// Type of Visual mode.
@@ -559,7 +557,7 @@ EXTERN int end_comment_pending INIT(= NUL);
// know that it should not attempt to perform scrollbinding due to the scroll
// that was a result of the ":syncbind." (Otherwise, check_scrollbind() will
// undo some of the work done by ":syncbind.") -ralston
-EXTERN int did_syncbind INIT(= false);
+EXTERN bool did_syncbind INIT(= false);
// This flag is set when a smart indent has been performed. When the next typed
// character is a '{' the inserted tab will be deleted again.
@@ -624,8 +622,8 @@ EXTERN long opcount INIT(= 0); // count for pending operator
EXTERN int motion_force INIT(=0); // motion force for pending operator
// Ex Mode (Q) state
-EXTERN int exmode_active INIT(= 0); // Zero, EXMODE_NORMAL or EXMODE_VIM.
-EXTERN int ex_no_reprint INIT(=false); // No need to print after z or p.
+EXTERN bool exmode_active INIT(= false); // true if Ex mode is active
+EXTERN bool ex_no_reprint INIT(=false); // No need to print after z or p.
EXTERN int reg_recording INIT(= 0); // register for recording or zero
EXTERN int reg_executing INIT(= 0); // register being executed or zero
@@ -646,7 +644,7 @@ EXTERN int arrow_used; // Normally false, set to true after
EXTERN bool ins_at_eol INIT(= false); // put cursor after eol when
// restarting edit after CTRL-O
-EXTERN int no_abbr INIT(= true); // true when no abbreviations loaded
+EXTERN bool no_abbr INIT(= true); // true when no abbreviations loaded
EXTERN int mapped_ctrl_c INIT(= 0); // Modes where CTRL-C is mapped.
@@ -666,7 +664,7 @@ EXTERN bool cmd_silent INIT(= false); // don't echo the command line
EXTERN int swap_exists_action INIT(= SEA_NONE);
// For dialog when swap file already
// exists.
-EXTERN int swap_exists_did_quit INIT(= false);
+EXTERN bool swap_exists_did_quit INIT(= false);
// Selected "quit" at the dialog.
EXTERN char_u IObuff[IOSIZE]; ///< Buffer for sprintf, I/O, etc.
@@ -703,14 +701,14 @@ EXTERN bool do_redraw INIT(= false); // extra redraw once
EXTERN bool must_redraw_pum INIT(= false); // redraw pum. NB: must_redraw
// should also be set.
-EXTERN int need_highlight_changed INIT(= true);
+EXTERN bool need_highlight_changed INIT(= true);
EXTERN FILE *scriptout INIT(= NULL); ///< Stream to write script to.
// volatile because it is used in a signal handler.
EXTERN volatile int got_int INIT(= false); // set to true when interrupt
// signal occurred
-EXTERN int bangredo INIT(= false); // set to true with ! command
+EXTERN bool bangredo INIT(= false); // set to true with ! command
EXTERN int searchcmdlen; // length of previous search cmd
EXTERN int reg_do_extmatch INIT(= 0); // Used when compiling regexp:
// REX_SET to allow \z\(...\),
@@ -720,14 +718,14 @@ EXTERN reg_extmatch_T *re_extmatch_in INIT(= NULL);
// Set by vim_regexec() to store \z\(...\) matches
EXTERN reg_extmatch_T *re_extmatch_out INIT(= NULL);
-EXTERN int did_outofmem_msg INIT(= false);
+EXTERN bool did_outofmem_msg INIT(= false);
// set after out of memory msg
-EXTERN int did_swapwrite_msg INIT(= false);
+EXTERN bool did_swapwrite_msg INIT(= false);
// set after swap write error msg
EXTERN int global_busy INIT(= 0); // set when :global is executing
-EXTERN int listcmd_busy INIT(= false); // set when :argdo, :windo or
+EXTERN bool listcmd_busy INIT(= false); // set when :argdo, :windo or
// :bufdo is executing
-EXTERN int need_start_insertmode INIT(= false);
+EXTERN bool need_start_insertmode INIT(= false);
// start insert mode soon
EXTERN char_u *last_cmdline INIT(= NULL); // last command line (for ":)
EXTERN char_u *repeat_cmdline INIT(= NULL); // command line for "."
@@ -735,16 +733,16 @@ EXTERN char_u *new_last_cmdline INIT(= NULL); // new value for last_cmdline
EXTERN char_u *autocmd_fname INIT(= NULL); // fname for <afile> on cmdline
EXTERN int autocmd_bufnr INIT(= 0); // fnum for <abuf> on cmdline
EXTERN char_u *autocmd_match INIT(= NULL); // name for <amatch> on cmdline
-EXTERN int did_cursorhold INIT(= false); // set when CursorHold t'gerd
+EXTERN bool did_cursorhold INIT(= false); // set when CursorHold t'gerd
EXTERN int postponed_split INIT(= 0); // for CTRL-W CTRL-] command
EXTERN int postponed_split_flags INIT(= 0); // args for win_split()
EXTERN int postponed_split_tab INIT(= 0); // cmdmod.tab
EXTERN int g_do_tagpreview INIT(= 0); // for tag preview commands:
// height of preview window
-EXTERN int g_tag_at_cursor INIT(= false); // whether the tag command comes
- // from the command line (0) or was
- // invoked as a normal command (1)
+EXTERN bool g_tag_at_cursor INIT(= false); // whether the tag command comes
+ // from the command line (0) or was
+ // invoked as a normal command (1)
EXTERN int replace_offset INIT(= 0); // offset for replace_push()
@@ -758,7 +756,7 @@ EXTERN int keep_help_flag INIT(= false); // doing :ta from help file
// everywhere.
EXTERN char_u *empty_option INIT(= (char_u *)"");
-EXTERN int redir_off INIT(= false); // no redirection for a moment
+EXTERN bool redir_off INIT(= false); // no redirection for a moment
EXTERN FILE *redir_fd INIT(= NULL); // message redirection file
EXTERN int redir_reg INIT(= 0); // message redirection register
EXTERN int redir_vname INIT(= 0); // message redirection variable
@@ -792,8 +790,8 @@ extern char_u *compiled_sys;
EXTERN char_u *globaldir INIT(= NULL);
// Whether 'keymodel' contains "stopsel" and "startsel".
-EXTERN int km_stopsel INIT(= false);
-EXTERN int km_startsel INIT(= false);
+EXTERN bool km_stopsel INIT(= false);
+EXTERN bool km_startsel INIT(= false);
EXTERN int cedit_key INIT(= -1); ///< key value of 'cedit' option
EXTERN int cmdwin_type INIT(= 0); ///< type of cmdline window or 0
@@ -941,13 +939,18 @@ EXTERN char_u e_readonlyvar[] INIT(= N_(
"E46: Cannot change read-only variable \"%.*s\""));
EXTERN char_u e_stringreq[] INIT(= N_("E928: String required"));
EXTERN char_u e_dictreq[] INIT(= N_("E715: Dictionary required"));
+EXTERN char_u e_blobidx[] INIT(= N_("E979: Blob index out of range: %" PRId64));
+EXTERN char_u e_invalblob[] INIT(= N_("E978: Invalid operation for Blob"));
EXTERN char_u e_toomanyarg[] INIT(= N_(
"E118: Too many arguments for function: %s"));
EXTERN char_u e_dictkey[] INIT(= N_(
"E716: Key not present in Dictionary: \"%s\""));
EXTERN char_u e_listreq[] INIT(= N_("E714: List required"));
+EXTERN char_u e_listblobreq[] INIT(= N_("E897: List or Blob required"));
EXTERN char_u e_listdictarg[] INIT(= N_(
"E712: Argument of %s must be a List or Dictionary"));
+EXTERN char_u e_listdictblobarg[] INIT(= N_(
+ "E896: Argument of %s must be a List, Dictionary or Blob"));
EXTERN char_u e_readerrf[] INIT(= N_("E47: Error while reading errorfile"));
EXTERN char_u e_sandbox[] INIT(= N_("E48: Not allowed in sandbox"));
EXTERN char_u e_secure[] INIT(= N_("E523: Not allowed here"));
@@ -974,6 +977,7 @@ EXTERN char_u e_write[] INIT(= N_("E80: Error while writing"));
EXTERN char_u e_zerocount[] INIT(= N_("E939: Positive count required"));
EXTERN char_u e_usingsid[] INIT(= N_(
"E81: Using <SID> not in a script context"));
+EXTERN char_u e_missingparen[] INIT(= N_("E107: Missing parentheses: %s"));
EXTERN char_u e_maxmempat[] INIT(= N_(
"E363: pattern uses more memory than 'maxmempattern'"));
EXTERN char_u e_emptybuf[] INIT(= N_("E749: empty buffer"));
diff --git a/src/nvim/grid_defs.h b/src/nvim/grid_defs.h
index 724363674c..dee096214f 100644
--- a/src/nvim/grid_defs.h
+++ b/src/nvim/grid_defs.h
@@ -86,7 +86,7 @@ struct ScreenGrid {
int zindex;
// Below is state owned by the compositor. Should generally not be set/read
- // outside this module, except for specific compatibilty hacks
+ // outside this module, except for specific compatibility hacks
// position of the grid on the composed screen.
int comp_row;
diff --git a/src/nvim/hardcopy.c b/src/nvim/hardcopy.c
index abba5425e7..df2c494ace 100644
--- a/src/nvim/hardcopy.c
+++ b/src/nvim/hardcopy.c
@@ -6,35 +6,35 @@
*/
#include <assert.h>
-#include <string.h>
#include <inttypes.h>
+#include <string.h>
-#include "nvim/vim.h"
#include "nvim/ascii.h"
+#include "nvim/vim.h"
#ifdef HAVE_LOCALE_H
# include <locale.h>
#endif
-#include "nvim/hardcopy.h"
#include "nvim/buffer.h"
#include "nvim/charset.h"
#include "nvim/eval.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_docmd.h"
#include "nvim/fileio.h"
+#include "nvim/garray.h"
+#include "nvim/hardcopy.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/garray.h"
#include "nvim/option.h"
+#include "nvim/os/input.h"
+#include "nvim/os/os.h"
#include "nvim/path.h"
#include "nvim/screen.h"
#include "nvim/strings.h"
#include "nvim/syntax.h"
#include "nvim/ui.h"
#include "nvim/version.h"
-#include "nvim/os/os.h"
-#include "nvim/os/input.h"
/*
* To implement printing on a platform, the following functions must be
@@ -98,20 +98,20 @@
static option_table_T printer_opts[OPT_PRINT_NUM_OPTIONS]
=
{
- {"top", TRUE, 0, NULL, 0, FALSE},
- {"bottom", TRUE, 0, NULL, 0, FALSE},
- {"left", TRUE, 0, NULL, 0, FALSE},
- {"right", TRUE, 0, NULL, 0, FALSE},
- {"header", TRUE, 0, NULL, 0, FALSE},
- {"syntax", FALSE, 0, NULL, 0, FALSE},
- {"number", FALSE, 0, NULL, 0, FALSE},
- {"wrap", FALSE, 0, NULL, 0, FALSE},
- {"duplex", FALSE, 0, NULL, 0, FALSE},
- {"portrait", FALSE, 0, NULL, 0, FALSE},
- {"paper", FALSE, 0, NULL, 0, FALSE},
- {"collate", FALSE, 0, NULL, 0, FALSE},
- {"jobsplit", FALSE, 0, NULL, 0, FALSE},
- {"formfeed", FALSE, 0, NULL, 0, FALSE},
+ { "top", TRUE, 0, NULL, 0, FALSE },
+ { "bottom", TRUE, 0, NULL, 0, FALSE },
+ { "left", TRUE, 0, NULL, 0, FALSE },
+ { "right", TRUE, 0, NULL, 0, FALSE },
+ { "header", TRUE, 0, NULL, 0, FALSE },
+ { "syntax", FALSE, 0, NULL, 0, FALSE },
+ { "number", FALSE, 0, NULL, 0, FALSE },
+ { "wrap", FALSE, 0, NULL, 0, FALSE },
+ { "duplex", FALSE, 0, NULL, 0, FALSE },
+ { "portrait", FALSE, 0, NULL, 0, FALSE },
+ { "paper", FALSE, 0, NULL, 0, FALSE },
+ { "collate", FALSE, 0, NULL, 0, FALSE },
+ { "jobsplit", FALSE, 0, NULL, 0, FALSE },
+ { "formfeed", FALSE, 0, NULL, 0, FALSE },
}
;
@@ -140,22 +140,22 @@ static uint32_t curr_bg;
static uint32_t curr_fg;
static int page_count;
-# define OPT_MBFONT_USECOURIER 0
-# define OPT_MBFONT_ASCII 1
-# define OPT_MBFONT_REGULAR 2
-# define OPT_MBFONT_BOLD 3
-# define OPT_MBFONT_OBLIQUE 4
-# define OPT_MBFONT_BOLDOBLIQUE 5
-# define OPT_MBFONT_NUM_OPTIONS 6
+#define OPT_MBFONT_USECOURIER 0
+#define OPT_MBFONT_ASCII 1
+#define OPT_MBFONT_REGULAR 2
+#define OPT_MBFONT_BOLD 3
+#define OPT_MBFONT_OBLIQUE 4
+#define OPT_MBFONT_BOLDOBLIQUE 5
+#define OPT_MBFONT_NUM_OPTIONS 6
static option_table_T mbfont_opts[OPT_MBFONT_NUM_OPTIONS] =
{
- {"c", FALSE, 0, NULL, 0, FALSE},
- {"a", FALSE, 0, NULL, 0, FALSE},
- {"r", FALSE, 0, NULL, 0, FALSE},
- {"b", FALSE, 0, NULL, 0, FALSE},
- {"i", FALSE, 0, NULL, 0, FALSE},
- {"o", FALSE, 0, NULL, 0, FALSE},
+ { "c", FALSE, 0, NULL, 0, FALSE },
+ { "a", FALSE, 0, NULL, 0, FALSE },
+ { "r", FALSE, 0, NULL, 0, FALSE },
+ { "b", FALSE, 0, NULL, 0, FALSE },
+ { "i", FALSE, 0, NULL, 0, FALSE },
+ { "o", FALSE, 0, NULL, 0, FALSE },
};
/*
@@ -183,31 +183,31 @@ struct prt_ps_font_S {
int uline_width;
int bbox_min_y;
int bbox_max_y;
- char *(ps_fontname[4]);
+ char *(ps_fontname[4]);
};
/* Structures to map user named encoding and mapping to PS equivalents for
* building CID font name */
struct prt_ps_encoding_S {
- char *encoding;
- char *cmap_encoding;
+ char *encoding;
+ char *cmap_encoding;
int needs_charset;
};
struct prt_ps_charset_S {
- char *charset;
- char *cmap_charset;
+ char *charset;
+ char *cmap_charset;
int has_charset;
};
// Collections of encodings and charsets for multi-byte printing
struct prt_ps_mbfont_S {
int num_encodings;
- struct prt_ps_encoding_S *encodings;
+ struct prt_ps_encoding_S *encodings;
int num_charsets;
- struct prt_ps_charset_S *charsets;
- char *ascii_enc;
- char *defcs;
+ struct prt_ps_charset_S *charsets;
+ char *ascii_enc;
+ char *defcs;
};
// Types of PS resource file currently used
@@ -234,14 +234,14 @@ struct prt_ps_resource_S {
};
struct prt_dsc_comment_S {
- char *string;
+ char *string;
int len;
int type;
};
struct prt_dsc_line_S {
int type;
- char_u *string;
+ char_u *string;
int len;
};
@@ -286,15 +286,14 @@ char_u *parse_printmbfont(void)
* Returns an error message for an illegal option, NULL otherwise.
* Only used for the printer at the moment...
*/
-static char_u *parse_list_options(char_u *option_str, option_table_T *table,
- size_t table_size)
+static char_u *parse_list_options(char_u *option_str, option_table_T *table, size_t table_size)
{
option_table_T *old_opts;
- char_u *ret = NULL;
- char_u *stringp;
- char_u *colonp;
- char_u *commap;
- char_u *p;
+ char_u *ret = NULL;
+ char_u *stringp;
+ char_u *colonp;
+ char_u *commap;
+ char_u *p;
size_t idx = 0; // init for GCC
int len;
@@ -317,14 +316,17 @@ static char_u *parse_list_options(char_u *option_str, option_table_T *table,
break;
}
commap = vim_strchr(stringp, ',');
- if (commap == NULL)
+ if (commap == NULL) {
commap = option_str + STRLEN(option_str);
+ }
len = (int)(colonp - stringp);
- for (idx = 0; idx < table_size; ++idx)
- if (STRNICMP(stringp, table[idx].name, len) == 0)
+ for (idx = 0; idx < table_size; ++idx) {
+ if (STRNICMP(stringp, table[idx].name, len) == 0) {
break;
+ }
+ }
if (idx == table_size) {
ret = (char_u *)N_("E551: Illegal component");
@@ -347,8 +349,9 @@ static char_u *parse_list_options(char_u *option_str, option_table_T *table,
table[idx].strlen = (int)(commap - p);
stringp = commap;
- if (*stringp == ',')
+ if (*stringp == ',') {
++stringp;
+ }
}
if (ret != NULL) {
@@ -401,16 +404,18 @@ static void prt_get_attr(int hl_id, prt_text_attr_T *pattr, int modec)
colorindex = atoi(color);
}
- if (colorindex >= 0 && colorindex < t_colors)
+ if (colorindex >= 0 && colorindex < t_colors) {
fg_color = prt_get_term_color(colorindex);
- else
+ } else {
fg_color = PRCOLOR_BLACK;
+ }
}
- if (fg_color == PRCOLOR_WHITE)
+ if (fg_color == PRCOLOR_WHITE) {
fg_color = PRCOLOR_BLACK;
- else if (*p_bg == 'd')
+ } else if (*p_bg == 'd') {
fg_color = darken_rgb(fg_color);
+ }
pattr->fg_color = fg_color;
pattr->bg_color = PRCOLOR_WHITE;
@@ -432,8 +437,7 @@ static void prt_set_bg(uint32_t bg)
}
}
-static void prt_set_font(const TriState bold, const TriState italic,
- const TriState underline)
+static void prt_set_font(const TriState bold, const TriState italic, const TriState underline)
{
if (curr_bold != bold
|| curr_italic != italic
@@ -446,8 +450,8 @@ static void prt_set_font(const TriState bold, const TriState italic,
}
// Print the line number in the left margin.
-static void prt_line_number(prt_settings_T *const psettings,
- const int page_line, const linenr_T lnum)
+static void prt_line_number(prt_settings_T *const psettings, const int page_line,
+ const linenr_T lnum)
{
prt_set_fg(psettings->number.fg_color);
prt_set_bg(psettings->number.bg_color);
@@ -504,18 +508,19 @@ int prt_get_unit(int idx)
int i;
static char *(units[4]) = PRT_UNIT_NAMES;
- if (printer_opts[idx].present)
- for (i = 0; i < 4; ++i)
+ if (printer_opts[idx].present) {
+ for (i = 0; i < 4; ++i) {
if (STRNICMP(printer_opts[idx].string, units[i], 2) == 0) {
u = i;
break;
}
+ }
+ }
return u;
}
// Print the page header.
-static void prt_header(prt_settings_T *const psettings, const int pagenum,
- const linenr_T lnum)
+static void prt_header(prt_settings_T *const psettings, const int pagenum, const linenr_T lnum)
{
int width = psettings->chars_per_line;
@@ -548,8 +553,8 @@ static void prt_header(prt_settings_T *const psettings, const int pagenum,
use_sandbox = was_set_insecurely(curwin, (char_u *)"printheader", 0);
build_stl_str_hl(curwin, tbuf, (size_t)width + IOSIZE,
- p_header, use_sandbox,
- ' ', width, NULL, NULL);
+ p_header, use_sandbox,
+ ' ', width, NULL, NULL);
// Reset line numbers
curwin->w_cursor.lnum = tmp_lnum;
@@ -616,17 +621,19 @@ void ex_hardcopy(exarg_T *eap)
settings.has_color = TRUE;
if (*eap->arg == '>') {
- char_u *errormsg = NULL;
+ char_u *errormsg = NULL;
// Expand things like "%.ps".
if (expand_filename(eap, eap->cmdlinep, &errormsg) == FAIL) {
- if (errormsg != NULL)
+ if (errormsg != NULL) {
EMSG(errormsg);
+ }
return;
}
settings.outfile = skipwhite(eap->arg + 1);
- } else if (*eap->arg != NUL)
+ } else if (*eap->arg != NUL) {
settings.arguments = eap->arg;
+ }
/*
* Initialise for printing. Ask the user for settings, unless forceit is
@@ -636,24 +643,26 @@ void ex_hardcopy(exarg_T *eap)
* PS.)
*/
if (mch_print_init(&settings,
- curbuf->b_fname == NULL
+ curbuf->b_fname == NULL
? (char_u *)buf_spname(curbuf)
: curbuf->b_sfname == NULL
? curbuf->b_fname
: curbuf->b_sfname,
- eap->forceit) == FAIL)
+ eap->forceit) == FAIL) {
return;
+ }
settings.modec = 'c';
- if (!syntax_present(curwin))
+ if (!syntax_present(curwin)) {
settings.do_syntax = FALSE;
- else if (printer_opts[OPT_PRINT_SYNTAX].present
- && TOLOWER_ASC(printer_opts[OPT_PRINT_SYNTAX].string[0]) != 'a')
+ } else if (printer_opts[OPT_PRINT_SYNTAX].present
+ && TOLOWER_ASC(printer_opts[OPT_PRINT_SYNTAX].string[0]) != 'a') {
settings.do_syntax =
(TOLOWER_ASC(printer_opts[OPT_PRINT_SYNTAX].string[0]) == 'y');
- else
+ } else {
settings.do_syntax = settings.has_color;
+ }
// Set up printing attributes for line numbers
settings.number.fg_color = PRCOLOR_BLACK;
@@ -675,8 +684,9 @@ void ex_hardcopy(exarg_T *eap)
/*
* Estimate the total lines to be printed
*/
- for (lnum = eap->line1; lnum <= eap->line2; lnum++)
+ for (lnum = eap->line1; lnum <= eap->line2; lnum++) {
bytes_to_print += STRLEN(skipwhite(ml_get(lnum)));
+ }
if (bytes_to_print == 0) {
MSG(_("No text to be printed"));
goto print_fail_no_begin;
@@ -697,8 +707,9 @@ void ex_hardcopy(exarg_T *eap)
jobsplit = (printer_opts[OPT_PRINT_JOBSPLIT].present
&& TOLOWER_ASC(printer_opts[OPT_PRINT_JOBSPLIT].string[0]) == 'y');
- if (!mch_print_begin(&settings))
+ if (!mch_print_begin(&settings)) {
goto print_fail_no_begin;
+ }
/*
* Loop over collated copies: 1 2 3, 1 2 3, ...
@@ -718,8 +729,9 @@ void ex_hardcopy(exarg_T *eap)
if (jobsplit && collated_copies > 0) {
// Splitting jobs: Stop a previous job and start a new one.
mch_print_end(&settings);
- if (!mch_print_begin(&settings))
+ if (!mch_print_begin(&settings)) {
goto print_fail_no_begin;
+ }
}
/*
@@ -746,34 +758,38 @@ void ex_hardcopy(exarg_T *eap)
// Check for interrupt character every page.
os_breakcheck();
- if (got_int || settings.user_abort)
+ if (got_int || settings.user_abort) {
goto print_fail;
+ }
assert(prtpos.bytes_printed <= SIZE_MAX / 100);
sprintf((char *)IObuff, _("Printing page %d (%zu%%)"),
page_count + 1 + side,
prtpos.bytes_printed * 100 / bytes_to_print);
- if (!mch_print_begin_page(IObuff))
+ if (!mch_print_begin_page(IObuff)) {
goto print_fail;
+ }
- if (settings.n_collated_copies > 1)
+ if (settings.n_collated_copies > 1) {
sprintf((char *)IObuff + STRLEN(IObuff),
- _(" Copy %d of %d"),
- collated_copies + 1,
- settings.n_collated_copies);
+ _(" Copy %d of %d"),
+ collated_copies + 1,
+ settings.n_collated_copies);
+ }
prt_message(IObuff);
/*
* Output header if required
*/
- if (prt_header_height() > 0)
+ if (prt_header_height() > 0) {
prt_header(&settings, page_count + 1 + side,
- prtpos.file_line);
+ prtpos.file_line);
+ }
for (page_line = 0; page_line < settings.lines_per_page;
++page_line) {
prtpos.column = hardcopy_line(&settings,
- page_line, &prtpos);
+ page_line, &prtpos);
if (prtpos.column == 0) {
// finished a file line
prtpos.bytes_printed +=
@@ -803,19 +819,21 @@ void ex_hardcopy(exarg_T *eap)
if (prtpos.file_line > eap->line2 && settings.duplex
&& side == 0
&& uncollated_copies + 1 < settings.n_uncollated_copies) {
- if (!mch_print_blank_page())
+ if (!mch_print_blank_page()) {
goto print_fail;
+ }
}
}
- if (settings.duplex && prtpos.file_line <= eap->line2)
+ if (settings.duplex && prtpos.file_line <= eap->line2) {
++page_count;
+ }
// Remember the position where the next page starts.
page_prtpos = prtpos;
}
vim_snprintf((char *)IObuff, IOSIZE, _("Printed: %s"),
- settings.jobname);
+ settings.jobname);
prt_message(IObuff);
}
@@ -837,7 +855,7 @@ print_fail_no_begin:
static colnr_T hardcopy_line(prt_settings_T *psettings, int page_line, prt_pos_T *ppos)
{
colnr_T col;
- char_u *line;
+ char_u *line;
int need_break = FALSE;
int outputlen;
int tab_spaces;
@@ -848,8 +866,9 @@ static colnr_T hardcopy_line(prt_settings_T *psettings, int page_line, prt_pos_T
if (ppos->column == 0 || ppos->ff) {
print_pos = 0;
tab_spaces = 0;
- if (!ppos->ff && prt_use_number())
+ if (!ppos->ff && prt_use_number()) {
prt_line_number(psettings, page_line, ppos->file_line);
+ }
ppos->ff = FALSE;
} else {
// left over from wrap halfway through a tab
@@ -870,10 +889,11 @@ static colnr_T hardcopy_line(prt_settings_T *psettings, int page_line, prt_pos_T
// syntax highlighting stuff.
if (psettings->do_syntax) {
id = syn_get_id(curwin, ppos->file_line, col, 1, NULL, FALSE);
- if (id > 0)
+ if (id > 0) {
id = syn_get_final_id(id);
- else
+ } else {
id = 0;
+ }
// Get the line again, a multi-line regexp may invalidate it.
line = ml_get(ppos->file_line);
@@ -900,8 +920,9 @@ static colnr_T hardcopy_line(prt_settings_T *psettings, int page_line, prt_pos_T
need_break = mch_print_text_out((char_u *)" ", 1);
print_pos++;
tab_spaces--;
- if (need_break)
+ if (need_break) {
break;
+ }
}
// Keep the TAB if we didn't finish it.
if (need_break && tab_spaces > 0) {
@@ -930,8 +951,9 @@ static colnr_T hardcopy_line(prt_settings_T *psettings, int page_line, prt_pos_T
&& (line[col] == NUL
|| (printer_opts[OPT_PRINT_WRAP].present
&& TOLOWER_ASC(printer_opts[OPT_PRINT_WRAP].string[0])
- == 'n')))
+ == 'n'))) {
return 0;
+ }
return col;
}
@@ -1000,7 +1022,7 @@ static struct prt_ps_font_S prt_ps_courier_font =
600,
-100, 50,
-250, 805,
- {"Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique"}
+ { "Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique" }
};
// Generic font metrics for multi-byte fonts
@@ -1009,7 +1031,7 @@ static struct prt_ps_font_S prt_ps_mb_font =
1000,
-100, 50,
-250, 805,
- {NULL, NULL, NULL, NULL}
+ { NULL, NULL, NULL, NULL }
};
// Pointer to current font set being used
@@ -1027,25 +1049,25 @@ static struct prt_ps_font_S *prt_ps_font;
// Japanese encodings and charsets
static struct prt_ps_encoding_S j_encodings[] =
{
- {"iso-2022-jp", NULL, (CS_JIS_C_1978|CS_JIS_X_1983|CS_JIS_X_1990|
- CS_NEC)},
- {"euc-jp", "EUC", (CS_JIS_C_1978|CS_JIS_X_1983|CS_JIS_X_1990)},
- {"sjis", "RKSJ", (CS_JIS_C_1978|CS_JIS_X_1983|CS_MSWINDOWS|
- CS_KANJITALK6|CS_KANJITALK7)},
- {"cp932", "RKSJ", CS_JIS_X_1983},
- {"ucs-2", "UCS2", CS_JIS_X_1990},
- {"utf-8", "UTF8", CS_JIS_X_1990}
+ { "iso-2022-jp", NULL, (CS_JIS_C_1978|CS_JIS_X_1983|CS_JIS_X_1990|
+ CS_NEC) },
+ { "euc-jp", "EUC", (CS_JIS_C_1978|CS_JIS_X_1983|CS_JIS_X_1990) },
+ { "sjis", "RKSJ", (CS_JIS_C_1978|CS_JIS_X_1983|CS_MSWINDOWS|
+ CS_KANJITALK6|CS_KANJITALK7) },
+ { "cp932", "RKSJ", CS_JIS_X_1983 },
+ { "ucs-2", "UCS2", CS_JIS_X_1990 },
+ { "utf-8", "UTF8", CS_JIS_X_1990 }
};
static struct prt_ps_charset_S j_charsets[] =
{
- {"JIS_C_1978", "78", CS_JIS_C_1978},
- {"JIS_X_1983", NULL, CS_JIS_X_1983},
- {"JIS_X_1990", "Hojo", CS_JIS_X_1990},
- {"NEC", "Ext", CS_NEC},
- {"MSWINDOWS", "90ms", CS_MSWINDOWS},
- {"CP932", "90ms", CS_JIS_X_1983},
- {"KANJITALK6", "83pv", CS_KANJITALK6},
- {"KANJITALK7", "90pv", CS_KANJITALK7}
+ { "JIS_C_1978", "78", CS_JIS_C_1978 },
+ { "JIS_X_1983", NULL, CS_JIS_X_1983 },
+ { "JIS_X_1990", "Hojo", CS_JIS_X_1990 },
+ { "NEC", "Ext", CS_NEC },
+ { "MSWINDOWS", "90ms", CS_MSWINDOWS },
+ { "CP932", "90ms", CS_JIS_X_1983 },
+ { "KANJITALK6", "83pv", CS_KANJITALK6 },
+ { "KANJITALK7", "90pv", CS_KANJITALK7 }
};
#define CS_GB_2312_80 (0x01)
@@ -1059,23 +1081,23 @@ static struct prt_ps_charset_S j_charsets[] =
// Simplified Chinese encodings and charsets
static struct prt_ps_encoding_S sc_encodings[] =
{
- {"iso-2022", NULL, (CS_GB_2312_80|CS_GBT_12345_90)},
- {"gb18030", NULL, CS_GBK2K},
- {"euc-cn", "EUC", (CS_GB_2312_80|CS_GBT_12345_90|CS_SC_MAC|
- CS_GBT_90_MAC)},
- {"gbk", "EUC", CS_GBK},
- {"ucs-2", "UCS2", CS_SC_ISO10646},
- {"utf-8", "UTF8", CS_SC_ISO10646}
+ { "iso-2022", NULL, (CS_GB_2312_80|CS_GBT_12345_90) },
+ { "gb18030", NULL, CS_GBK2K },
+ { "euc-cn", "EUC", (CS_GB_2312_80|CS_GBT_12345_90|CS_SC_MAC|
+ CS_GBT_90_MAC) },
+ { "gbk", "EUC", CS_GBK },
+ { "ucs-2", "UCS2", CS_SC_ISO10646 },
+ { "utf-8", "UTF8", CS_SC_ISO10646 }
};
static struct prt_ps_charset_S sc_charsets[] =
{
- {"GB_2312-80", "GB", CS_GB_2312_80},
- {"GBT_12345-90","GBT", CS_GBT_12345_90},
- {"MAC", "GBpc", CS_SC_MAC},
- {"GBT-90_MAC", "GBTpc", CS_GBT_90_MAC},
- {"GBK", "GBK", CS_GBK},
- {"GB18030", "GBK2K", CS_GBK2K},
- {"ISO10646", "UniGB", CS_SC_ISO10646}
+ { "GB_2312-80", "GB", CS_GB_2312_80 },
+ { "GBT_12345-90", "GBT", CS_GBT_12345_90 },
+ { "MAC", "GBpc", CS_SC_MAC },
+ { "GBT-90_MAC", "GBTpc", CS_GBT_90_MAC },
+ { "GBK", "GBK", CS_GBK },
+ { "GB18030", "GBK2K", CS_GBK2K },
+ { "ISO10646", "UniGB", CS_SC_ISO10646 }
};
#define CS_CNS_PLANE_1 (0x01)
@@ -1095,33 +1117,33 @@ static struct prt_ps_charset_S sc_charsets[] =
// Traditional Chinese encodings and charsets
static struct prt_ps_encoding_S tc_encodings[] =
{
- {"iso-2022", NULL, (CS_CNS_PLANE_1|CS_CNS_PLANE_2)},
- {"euc-tw", "EUC", CS_CNS_PLANE_1_2},
- {"big5", "B5", (CS_B5|CS_ETEN|CS_HK_GCCS|CS_HK_SCS|
- CS_HK_SCS_ETEN|CS_MTHKL|CS_MTHKS|CS_DLHKL|
- CS_DLHKS)},
- {"cp950", "B5", CS_B5},
- {"ucs-2", "UCS2", CS_TC_ISO10646},
- {"utf-8", "UTF8", CS_TC_ISO10646},
- {"utf-16", "UTF16", CS_TC_ISO10646},
- {"utf-32", "UTF32", CS_TC_ISO10646}
+ { "iso-2022", NULL, (CS_CNS_PLANE_1|CS_CNS_PLANE_2) },
+ { "euc-tw", "EUC", CS_CNS_PLANE_1_2 },
+ { "big5", "B5", (CS_B5|CS_ETEN|CS_HK_GCCS|CS_HK_SCS|
+ CS_HK_SCS_ETEN|CS_MTHKL|CS_MTHKS|CS_DLHKL|
+ CS_DLHKS) },
+ { "cp950", "B5", CS_B5 },
+ { "ucs-2", "UCS2", CS_TC_ISO10646 },
+ { "utf-8", "UTF8", CS_TC_ISO10646 },
+ { "utf-16", "UTF16", CS_TC_ISO10646 },
+ { "utf-32", "UTF32", CS_TC_ISO10646 }
};
static struct prt_ps_charset_S tc_charsets[] =
{
- {"CNS_1992_1", "CNS1", CS_CNS_PLANE_1},
- {"CNS_1992_2", "CNS2", CS_CNS_PLANE_2},
- {"CNS_1993", "CNS", CS_CNS_PLANE_1_2},
- {"BIG5", NULL, CS_B5},
- {"CP950", NULL, CS_B5},
- {"ETEN", "ETen", CS_ETEN},
- {"HK_GCCS", "HKgccs", CS_HK_GCCS},
- {"SCS", "HKscs", CS_HK_SCS},
- {"SCS_ETEN", "ETHK", CS_HK_SCS_ETEN},
- {"MTHKL", "HKm471", CS_MTHKL},
- {"MTHKS", "HKm314", CS_MTHKS},
- {"DLHKL", "HKdla", CS_DLHKL},
- {"DLHKS", "HKdlb", CS_DLHKS},
- {"ISO10646", "UniCNS", CS_TC_ISO10646}
+ { "CNS_1992_1", "CNS1", CS_CNS_PLANE_1 },
+ { "CNS_1992_2", "CNS2", CS_CNS_PLANE_2 },
+ { "CNS_1993", "CNS", CS_CNS_PLANE_1_2 },
+ { "BIG5", NULL, CS_B5 },
+ { "CP950", NULL, CS_B5 },
+ { "ETEN", "ETen", CS_ETEN },
+ { "HK_GCCS", "HKgccs", CS_HK_GCCS },
+ { "SCS", "HKscs", CS_HK_SCS },
+ { "SCS_ETEN", "ETHK", CS_HK_SCS_ETEN },
+ { "MTHKL", "HKm471", CS_MTHKL },
+ { "MTHKS", "HKm314", CS_MTHKS },
+ { "DLHKL", "HKdla", CS_DLHKL },
+ { "DLHKS", "HKdlb", CS_DLHKS },
+ { "ISO10646", "UniCNS", CS_TC_ISO10646 }
};
#define CS_KR_X_1992 (0x01)
@@ -1132,24 +1154,24 @@ static struct prt_ps_charset_S tc_charsets[] =
// Korean encodings and charsets
static struct prt_ps_encoding_S k_encodings[] =
{
- {"iso-2022-kr", NULL, CS_KR_X_1992},
- {"euc-kr", "EUC", (CS_KR_X_1992|CS_KR_MAC)},
- {"johab", "Johab", CS_KR_X_1992},
- {"cp1361", "Johab", CS_KR_X_1992},
- {"uhc", "UHC", CS_KR_X_1992_MS},
- {"cp949", "UHC", CS_KR_X_1992_MS},
- {"ucs-2", "UCS2", CS_KR_ISO10646},
- {"utf-8", "UTF8", CS_KR_ISO10646}
+ { "iso-2022-kr", NULL, CS_KR_X_1992 },
+ { "euc-kr", "EUC", (CS_KR_X_1992|CS_KR_MAC) },
+ { "johab", "Johab", CS_KR_X_1992 },
+ { "cp1361", "Johab", CS_KR_X_1992 },
+ { "uhc", "UHC", CS_KR_X_1992_MS },
+ { "cp949", "UHC", CS_KR_X_1992_MS },
+ { "ucs-2", "UCS2", CS_KR_ISO10646 },
+ { "utf-8", "UTF8", CS_KR_ISO10646 }
};
static struct prt_ps_charset_S k_charsets[] =
{
- {"KS_X_1992", "KSC", CS_KR_X_1992},
- {"CP1361", "KSC", CS_KR_X_1992},
- {"MAC", "KSCpc", CS_KR_MAC},
- {"MSWINDOWS", "KSCms", CS_KR_X_1992_MS},
- {"CP949", "KSCms", CS_KR_X_1992_MS},
- {"WANSUNG", "KSCms", CS_KR_X_1992_MS},
- {"ISO10646", "UniKS", CS_KR_ISO10646}
+ { "KS_X_1992", "KSC", CS_KR_X_1992 },
+ { "CP1361", "KSC", CS_KR_X_1992 },
+ { "MAC", "KSCpc", CS_KR_MAC },
+ { "MSWINDOWS", "KSCms", CS_KR_X_1992_MS },
+ { "CP949", "KSCms", CS_KR_X_1992_MS },
+ { "WANSUNG", "KSCms", CS_KR_X_1992_MS },
+ { "ISO10646", "UniKS", CS_KR_ISO10646 }
};
static struct prt_ps_mbfont_S prt_ps_mbfonts[] =
@@ -1196,7 +1218,7 @@ static struct prt_ps_mbfont_S prt_ps_mbfonts[] =
*
* VIM Prolog CIDProlog
* 6.2 1.3
- * 7.0 1.4 1.0
+ * 7.0 1.4 1.0
*/
#define PRT_PROLOG_VERSION ((char_u *)"1.4")
#define PRT_CID_PROLOG_VERSION ((char_u *)"1.0")
@@ -1224,11 +1246,11 @@ static struct prt_ps_mbfont_S prt_ps_mbfonts[] =
#define SIZEOF_CSTR(s) (sizeof(s) - 1)
static struct prt_dsc_comment_S prt_dsc_table[] =
{
- {PRT_DSC_TITLE, SIZEOF_CSTR(PRT_DSC_TITLE), PRT_DSC_TITLE_TYPE},
- {PRT_DSC_VERSION, SIZEOF_CSTR(PRT_DSC_VERSION),
- PRT_DSC_VERSION_TYPE},
- {PRT_DSC_ENDCOMMENTS, SIZEOF_CSTR(PRT_DSC_ENDCOMMENTS),
- PRT_DSC_ENDCOMMENTS_TYPE}
+ { PRT_DSC_TITLE, SIZEOF_CSTR(PRT_DSC_TITLE), PRT_DSC_TITLE_TYPE },
+ { PRT_DSC_VERSION, SIZEOF_CSTR(PRT_DSC_VERSION),
+ PRT_DSC_VERSION_TYPE },
+ { PRT_DSC_ENDCOMMENTS, SIZEOF_CSTR(PRT_DSC_ENDCOMMENTS),
+ PRT_DSC_ENDCOMMENTS_TYPE }
};
@@ -1359,14 +1381,15 @@ static void prt_write_boolean(int b)
static void prt_def_font(char *new_name, char *encoding, int height, char *font)
{
vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
- "/_%s /VIM-%s /%s ref\n", new_name, encoding, font);
+ "/_%s /VIM-%s /%s ref\n", new_name, encoding, font);
prt_write_file(prt_line_buffer);
- if (prt_out_mbyte)
+ if (prt_out_mbyte) {
sprintf((char *)prt_line_buffer, "/%s %d %f /_%s sffs\n",
- new_name, height, 500./prt_ps_courier_font.wx, new_name);
- else
+ new_name, height, 500./prt_ps_courier_font.wx, new_name);
+ } else {
vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
- "/%s %d /_%s ffs\n", new_name, height, new_name);
+ "/%s %d /_%s ffs\n", new_name, height, new_name);
+ }
prt_write_file(prt_line_buffer);
}
@@ -1376,10 +1399,10 @@ static void prt_def_font(char *new_name, char *encoding, int height, char *font)
static void prt_def_cidfont(char *new_name, int height, char *cidfont)
{
vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
- "/_%s /%s[/%s] vim_composefont\n", new_name, prt_cmap, cidfont);
+ "/_%s /%s[/%s] vim_composefont\n", new_name, prt_cmap, cidfont);
prt_write_file(prt_line_buffer);
vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
- "/%s %d /_%s ffs\n", new_name, height, new_name);
+ "/%s %d /_%s ffs\n", new_name, height, new_name);
prt_write_file(prt_line_buffer);
}
@@ -1389,7 +1412,7 @@ static void prt_def_cidfont(char *new_name, int height, char *cidfont)
static void prt_dup_cidfont(char *original_name, char *new_name)
{
vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
- "/%s %s d\n", new_name, original_name);
+ "/%s %s d\n", new_name, original_name);
prt_write_file(prt_line_buffer);
}
@@ -1402,10 +1425,12 @@ static void prt_real_bits(double real, int precision, int *pinteger, int *pfract
{
int integer = (int)real;
double fraction = real - integer;
- if (real < integer)
+ if (real < integer) {
fraction = -fraction;
- for (int i = 0; i < precision; i++)
+ }
+ for (int i = 0; i < precision; i++) {
fraction *= 10.0;
+ }
*pinteger = integer;
*pfraction = (int)(fraction + 0.5);
@@ -1447,7 +1472,7 @@ static void prt_write_real(double val, int prec)
static void prt_def_var(char *name, double value, int prec)
{
vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
- "/%s ", name);
+ "/%s ", name);
prt_write_file(prt_line_buffer);
prt_write_real(value, prec);
sprintf((char *)prt_line_buffer, "d\n");
@@ -1500,16 +1525,18 @@ static void prt_flush_buffer(void)
prt_write_string("ul\n");
}
// Draw the text
- if (prt_out_mbyte)
+ if (prt_out_mbyte) {
prt_write_string("<");
- else
+ } else {
prt_write_string("(");
+ }
assert(prt_ps_buffer.ga_len >= 0);
prt_write_file_raw_len(prt_ps_buffer.ga_data, (size_t)prt_ps_buffer.ga_len);
- if (prt_out_mbyte)
+ if (prt_out_mbyte) {
prt_write_string(">");
- else
+ } else {
prt_write_string(")");
+ }
// Add a moveto if need be and use the appropriate show procedure
if (prt_do_moveto) {
prt_write_real(prt_pos_x_moveto, 2);
@@ -1529,15 +1556,16 @@ static void prt_resource_name(char_u *filename, void *cookie)
{
char_u *resource_filename = cookie;
- if (STRLEN(filename) >= MAXPATHL)
+ if (STRLEN(filename) >= MAXPATHL) {
*resource_filename = NUL;
- else
+ } else {
STRCPY(resource_filename, filename);
+ }
}
static int prt_find_resource(char *name, struct prt_ps_resource_S *resource)
{
- char_u *buffer;
+ char_u *buffer;
int retval;
buffer = xmallocz(MAXPATHL);
@@ -1568,15 +1596,17 @@ static int prt_resfile_next_line(void)
// Move to start of next line and then find end of line
idx = prt_resfile.line_end + 1;
while (idx < prt_resfile.len) {
- if (prt_resfile.buffer[idx] != PSLF && prt_resfile.buffer[idx] != PSCR)
+ if (prt_resfile.buffer[idx] != PSLF && prt_resfile.buffer[idx] != PSCR) {
break;
+ }
idx++;
}
prt_resfile.line_start = idx;
while (idx < prt_resfile.len) {
- if (prt_resfile.buffer[idx] == PSLF || prt_resfile.buffer[idx] == PSCR)
+ if (prt_resfile.buffer[idx] == PSLF || prt_resfile.buffer[idx] == PSCR) {
break;
+ }
idx++;
}
prt_resfile.line_end = idx;
@@ -1592,7 +1622,7 @@ static int prt_resfile_strncmp(int offset, const char *string, int len)
return 1;
}
return STRNCMP(&prt_resfile.buffer[prt_resfile.line_start + offset],
- string, len);
+ string, len);
}
static int prt_resfile_skip_nonws(int offset)
@@ -1601,8 +1631,9 @@ static int prt_resfile_skip_nonws(int offset)
idx = prt_resfile.line_start + offset;
while (idx < prt_resfile.line_end) {
- if (isspace(prt_resfile.buffer[idx]))
+ if (isspace(prt_resfile.buffer[idx])) {
return idx - prt_resfile.line_start;
+ }
idx++;
}
return -1;
@@ -1614,8 +1645,9 @@ static int prt_resfile_skip_ws(int offset)
idx = prt_resfile.line_start + offset;
while (idx < prt_resfile.line_end) {
- if (!isspace(prt_resfile.buffer[idx]))
+ if (!isspace(prt_resfile.buffer[idx])) {
return idx - prt_resfile.line_start;
+ }
idx++;
}
return -1;
@@ -1685,10 +1717,10 @@ static bool prt_open_resource(struct prt_ps_resource_S *resource)
// Parse first line to ensure valid resource file
prt_resfile.len = (int)fread((char *)prt_resfile.buffer, sizeof(char_u),
- PRT_FILE_BUFFER_LEN, fd_resource);
+ PRT_FILE_BUFFER_LEN, fd_resource);
if (ferror(fd_resource)) {
EMSG2(_("E457: Can't read PostScript resource file \"%s\""),
- resource->filename);
+ resource->filename);
fclose(fd_resource);
return false;
}
@@ -1702,7 +1734,7 @@ static bool prt_open_resource(struct prt_ps_resource_S *resource)
int offset = 0;
if (prt_resfile_strncmp(offset, PRT_RESOURCE_HEADER,
- (int)STRLEN(PRT_RESOURCE_HEADER)) != 0) {
+ (int)STRLEN(PRT_RESOURCE_HEADER)) != 0) {
EMSG2(_("E618: file \"%s\" is not a PostScript resource file"),
resource->filename);
return false;
@@ -1719,7 +1751,7 @@ static bool prt_open_resource(struct prt_ps_resource_S *resource)
return false;
}
if (prt_resfile_strncmp(offset, PRT_RESOURCE_RESOURCE,
- (int)STRLEN(PRT_RESOURCE_RESOURCE)) != 0) {
+ (int)STRLEN(PRT_RESOURCE_RESOURCE)) != 0) {
EMSG2(_("E619: file \"%s\" is not a supported PostScript resource file"),
resource->filename);
return false;
@@ -1767,7 +1799,7 @@ static bool prt_open_resource(struct prt_ps_resource_S *resource)
break;
case PRT_DSC_ENDCOMMENTS_TYPE:
- // Wont find title or resource after this comment, stop searching
+ // Won't find title or resource after this comment, stop searching
seen_all = true;
break;
@@ -1786,8 +1818,7 @@ static bool prt_open_resource(struct prt_ps_resource_S *resource)
return true;
}
-static bool prt_check_resource(const struct prt_ps_resource_S *resource,
- const char_u *version)
+static bool prt_check_resource(const struct prt_ps_resource_S *resource, const char_u *version)
FUNC_ATTR_NONNULL_ALL
{
// Version number m.n should match, the revision number does not matter
@@ -1809,14 +1840,14 @@ static void prt_dsc_start(void)
static void prt_dsc_noarg(char *comment)
{
vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
- "%%%%%s\n", comment);
+ "%%%%%s\n", comment);
prt_write_file(prt_line_buffer);
}
static void prt_dsc_textline(char *comment, char *text)
{
vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
- "%%%%%s: %s\n", comment, text);
+ "%%%%%s: %s\n", comment, text);
prt_write_file(prt_line_buffer);
}
@@ -1824,7 +1855,7 @@ static void prt_dsc_text(char *comment, char *text)
{
// TODO(vim): - should scan 'text' for any chars needing escaping!
vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
- "%%%%%s: (%s)\n", comment, text);
+ "%%%%%s: (%s)\n", comment, text);
prt_write_file(prt_line_buffer);
}
@@ -1835,7 +1866,7 @@ static void prt_dsc_ints(char *comment, int count, int *ints)
int i;
vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
- "%%%%%s:", comment);
+ "%%%%%s:", comment);
prt_write_file(prt_line_buffer);
for (i = 0; i < count; i++) {
@@ -1846,23 +1877,21 @@ static void prt_dsc_ints(char *comment, int count, int *ints)
prt_write_string("\n");
}
-static void prt_dsc_resources(
- const char *comment, // if NULL add to previous
- const char *type,
- const char *string
-)
+/// @param comment if NULL add to previous
+static void prt_dsc_resources(const char *comment, const char *type, const char *string)
FUNC_ATTR_NONNULL_ARG(2, 3)
{
- if (comment != NULL)
+ if (comment != NULL) {
vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
- "%%%%%s: %s", comment, type);
- else
+ "%%%%%s: %s", comment, type);
+ } else {
vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
- "%%%%+ %s", type);
+ "%%%%+ %s", type);
+ }
prt_write_file(prt_line_buffer);
vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
- " %s\n", string);
+ " %s\n", string);
prt_write_file(prt_line_buffer);
}
@@ -1871,10 +1900,12 @@ static void prt_dsc_font_resource(char *resource, struct prt_ps_font_S *ps_font)
int i;
prt_dsc_resources(resource, "font",
- ps_font->ps_fontname[PRT_PS_FONT_ROMAN]);
- for (i = PRT_PS_FONT_BOLD; i <= PRT_PS_FONT_BOLDOBLIQUE; i++)
- if (ps_font->ps_fontname[i] != NULL)
+ ps_font->ps_fontname[PRT_PS_FONT_ROMAN]);
+ for (i = PRT_PS_FONT_BOLD; i <= PRT_PS_FONT_BOLDOBLIQUE; i++) {
+ if (ps_font->ps_fontname[i] != NULL) {
prt_dsc_resources(NULL, "font", ps_font->ps_fontname[i]);
+ }
+ }
}
static void prt_dsc_requirements(int duplex, int tumble, int collate, int color, int num_copies)
@@ -1882,21 +1913,25 @@ static void prt_dsc_requirements(int duplex, int tumble, int collate, int color,
/* Only output the comment if we need to.
* Note: tumble is ignored if we are not duplexing
*/
- if (!(duplex || collate || color || (num_copies > 1)))
+ if (!(duplex || collate || color || (num_copies > 1))) {
return;
+ }
sprintf((char *)prt_line_buffer, "%%%%Requirements:");
prt_write_file(prt_line_buffer);
if (duplex) {
prt_write_string(" duplex");
- if (tumble)
+ if (tumble) {
prt_write_string("(tumble)");
+ }
}
- if (collate)
+ if (collate) {
prt_write_string(" collate");
- if (color)
+ }
+ if (color) {
prt_write_string(" color");
+ }
if (num_copies > 1) {
prt_write_string(" numcopies(");
// Note: no space wanted so don't use prt_write_int()
@@ -1908,23 +1943,26 @@ static void prt_dsc_requirements(int duplex, int tumble, int collate, int color,
prt_write_string("\n");
}
-static void prt_dsc_docmedia(char *paper_name, double width, double height, double weight, char *colour, char *type)
+static void prt_dsc_docmedia(char *paper_name, double width, double height, double weight,
+ char *colour, char *type)
{
vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer),
- "%%%%DocumentMedia: %s ", paper_name);
+ "%%%%DocumentMedia: %s ", paper_name);
prt_write_file(prt_line_buffer);
prt_write_real(width, 2);
prt_write_real(height, 2);
prt_write_real(weight, 2);
- if (colour == NULL)
+ if (colour == NULL) {
prt_write_string("()");
- else
+ } else {
prt_write_string(colour);
+ }
prt_write_string(" ");
- if (type == NULL)
+ if (type == NULL) {
prt_write_string("()");
- else
+ } else {
prt_write_string(type);
+ }
prt_write_string("\n");
}
@@ -1938,8 +1976,9 @@ void mch_print_cleanup(void)
* one style).
*/
for (i = PRT_PS_FONT_ROMAN; i <= PRT_PS_FONT_BOLDOBLIQUE; i++) {
- if (prt_ps_mb_font.ps_fontname[i] != NULL)
+ if (prt_ps_mb_font.ps_fontname[i] != NULL) {
xfree(prt_ps_mb_font.ps_fontname[i]);
+ }
prt_ps_mb_font.ps_fontname[i] = NULL;
}
}
@@ -1993,7 +2032,8 @@ static double to_device_units(int idx, double physsize, int def_number)
/*
* Calculate margins for given width and height from printoptions settings.
*/
-static void prt_page_margins(double width, double height, double *left, double *right, double *top, double *bottom)
+static void prt_page_margins(double width, double height, double *left, double *right, double *top,
+ double *bottom)
{
*left = to_device_units(OPT_PRINT_LEFT, width, 10);
*right = width - to_device_units(OPT_PRINT_RIGHT, width, 5);
@@ -2015,11 +2055,13 @@ static int prt_get_cpl(void)
/* If we are outputting multi-byte characters then line numbers will be
* printed with half width characters
*/
- if (prt_out_mbyte)
+ if (prt_out_mbyte) {
prt_number_width /= 2;
+ }
prt_left_margin += prt_number_width;
- } else
+ } else {
prt_number_width = 0.0;
+ }
return (int)((prt_right_margin - prt_left_margin) / prt_char_width);
}
@@ -2044,11 +2086,11 @@ static int prt_get_lpp(void)
* case where the font height can exceed the line height.
*/
prt_bgcol_offset = PRT_PS_FONT_TO_USER(prt_line_height,
- prt_ps_font->bbox_min_y);
+ prt_ps_font->bbox_min_y);
if ((prt_ps_font->bbox_max_y - prt_ps_font->bbox_min_y) < 1000.0) {
prt_bgcol_offset -= PRT_PS_FONT_TO_USER(prt_line_height,
- (1000.0 - (prt_ps_font->bbox_max_y -
- prt_ps_font->bbox_min_y)) / 2);
+ (1000.0 - (prt_ps_font->bbox_max_y -
+ prt_ps_font->bbox_min_y)) / 2);
}
// Get height for topmost line based on background rect offset.
@@ -2063,11 +2105,12 @@ static int prt_get_lpp(void)
return lpp - prt_header_height();
}
-static int prt_match_encoding(char *p_encoding, struct prt_ps_mbfont_S *p_cmap, struct prt_ps_encoding_S **pp_mbenc)
+static int prt_match_encoding(char *p_encoding, struct prt_ps_mbfont_S *p_cmap,
+ struct prt_ps_encoding_S **pp_mbenc)
{
int mbenc;
int enc_len;
- struct prt_ps_encoding_S *p_mbenc;
+ struct prt_ps_encoding_S *p_mbenc;
*pp_mbenc = NULL;
// Look for recognised encoding
@@ -2083,7 +2126,8 @@ static int prt_match_encoding(char *p_encoding, struct prt_ps_mbfont_S *p_cmap,
return FALSE;
}
-static int prt_match_charset(char *p_charset, struct prt_ps_mbfont_S *p_cmap, struct prt_ps_charset_S **pp_mbchar)
+static int prt_match_charset(char *p_charset, struct prt_ps_mbfont_S *p_cmap,
+ struct prt_ps_charset_S **pp_mbchar)
{
int mbchar;
int char_len;
@@ -2108,24 +2152,25 @@ static int prt_match_charset(char *p_charset, struct prt_ps_mbfont_S *p_cmap, st
int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit)
{
int i;
- char *paper_name;
+ char *paper_name;
int paper_strlen;
int fontsize;
- char_u *p;
+ char_u *p;
int props;
int cmap = 0;
- char_u *p_encoding;
+ char_u *p_encoding;
struct prt_ps_encoding_S *p_mbenc;
struct prt_ps_encoding_S *p_mbenc_first;
- struct prt_ps_charset_S *p_mbchar = NULL;
+ struct prt_ps_charset_S *p_mbchar = NULL;
/*
* Set up font and encoding.
*/
p_encoding = enc_skip(p_penc);
- if (*p_encoding == NUL)
+ if (*p_encoding == NUL) {
p_encoding = enc_skip(p_enc);
+ }
/* Look for a multi-byte font that matches the encoding and character set.
* Only look if multi-byte character set is defined, or using multi-byte
@@ -2136,16 +2181,18 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit)
if (!(props & ENC_8BIT) && ((*p_pmcs != NUL) || !(props & ENC_UNICODE))) {
p_mbenc_first = NULL;
int effective_cmap = 0;
- for (cmap = 0; cmap < (int)ARRAY_SIZE(prt_ps_mbfonts); cmap++)
+ for (cmap = 0; cmap < (int)ARRAY_SIZE(prt_ps_mbfonts); cmap++) {
if (prt_match_encoding((char *)p_encoding, &prt_ps_mbfonts[cmap],
&p_mbenc)) {
if (p_mbenc_first == NULL) {
p_mbenc_first = p_mbenc;
effective_cmap = cmap;
}
- if (prt_match_charset((char *)p_pmcs, &prt_ps_mbfonts[cmap], &p_mbchar))
+ if (prt_match_charset((char *)p_pmcs, &prt_ps_mbfonts[cmap], &p_mbchar)) {
break;
+ }
}
+ }
// Use first encoding matched if no charset matched
if (p_mbenc_first != NULL && p_mbchar == NULL) {
@@ -2205,7 +2252,6 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit)
prt_build_cid_fontname(PRT_PS_FONT_BOLD,
mbfont_opts[OPT_MBFONT_BOLD].string,
mbfont_opts[OPT_MBFONT_BOLD].strlen);
-
}
if (mbfont_opts[OPT_MBFONT_OBLIQUE].present) {
prt_build_cid_fontname(PRT_PS_FONT_OBLIQUE,
@@ -2221,8 +2267,8 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit)
// Check if need to use Courier for ASCII code range, and if so pick up
// the encoding to use
prt_use_courier = (
- mbfont_opts[OPT_MBFONT_USECOURIER].present
- && (TOLOWER_ASC(mbfont_opts[OPT_MBFONT_USECOURIER].string[0]) == 'y'));
+ mbfont_opts[OPT_MBFONT_USECOURIER].present
+ && (TOLOWER_ASC(mbfont_opts[OPT_MBFONT_USECOURIER].string[0]) == 'y'));
if (prt_use_courier) {
// Use national ASCII variant unless ASCII wanted
if (mbfont_opts[OPT_MBFONT_ASCII].present
@@ -2252,13 +2298,16 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit)
paper_name = "A4";
paper_strlen = 2;
}
- for (i = 0; i < (int)PRT_MEDIASIZE_LEN; ++i)
+ for (i = 0; i < (int)PRT_MEDIASIZE_LEN; ++i) {
if (STRLEN(prt_mediasize[i].name) == (unsigned)paper_strlen
&& STRNICMP(prt_mediasize[i].name, paper_name,
- paper_strlen) == 0)
+ paper_strlen) == 0) {
break;
- if (i == PRT_MEDIASIZE_LEN)
+ }
+ }
+ if (i == PRT_MEDIASIZE_LEN) {
i = 0;
+ }
prt_media = i;
/*
@@ -2280,7 +2329,7 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit)
// needs to be done before the cpl and lpp are calculated.
double left, right, top, bottom;
prt_page_margins(prt_page_width, prt_page_height, &left, &right, &top,
- &bottom);
+ &bottom);
prt_left_margin = left;
prt_right_margin = right;
prt_top_margin = top;
@@ -2290,9 +2339,11 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit)
* Set up the font size.
*/
fontsize = PRT_PS_DEFAULT_FONTSIZE;
- for (p = p_pfn; (p = vim_strchr(p, ':')) != NULL; ++p)
- if (p[1] == 'h' && ascii_isdigit(p[2]))
+ for (p = p_pfn; (p = vim_strchr(p, ':')) != NULL; ++p) {
+ if (p[1] == 'h' && ascii_isdigit(p[2])) {
fontsize = atoi((char *)p + 2);
+ }
+ }
prt_font_metrics(fontsize);
/*
@@ -2340,8 +2391,9 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit)
prt_duplex = FALSE;
psettings->duplex = 0;
} else if (STRNICMP(printer_opts[OPT_PRINT_DUPLEX].string, "short", 5)
- == 0)
+ == 0) {
prt_tumble = TRUE;
+ }
}
// For now user abort not supported
@@ -2369,8 +2421,9 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit)
}
prt_bufsiz = psettings->chars_per_line;
- if (prt_out_mbyte)
+ if (prt_out_mbyte) {
prt_bufsiz *= 2;
+ }
ga_init(&prt_ps_buffer, (int)sizeof(char), prt_bufsiz);
prt_page_num = 0;
@@ -2389,7 +2442,7 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit)
static int prt_add_resource(struct prt_ps_resource_S *resource)
{
- FILE* fd_resource;
+ FILE * fd_resource;
char_u resource_buffer[512];
size_t bytes_read;
@@ -2398,22 +2451,31 @@ static int prt_add_resource(struct prt_ps_resource_S *resource)
EMSG2(_("E456: Can't open file \"%s\""), resource->filename);
return FALSE;
}
- prt_dsc_resources("BeginResource", prt_resource_types[resource->type],
- (char *)resource->title);
+ switch (resource->type) {
+ case PRT_RESOURCE_TYPE_PROCSET:
+ case PRT_RESOURCE_TYPE_ENCODING:
+ case PRT_RESOURCE_TYPE_CMAP:
+ prt_dsc_resources("BeginResource", prt_resource_types[resource->type],
+ (char *)resource->title);
+ break;
+ default:
+ return FALSE;
+ }
prt_dsc_textline("BeginDocument", (char *)resource->filename);
for (;; ) {
bytes_read = fread((char *)resource_buffer, sizeof(char_u),
- sizeof(resource_buffer), fd_resource);
+ sizeof(resource_buffer), fd_resource);
if (ferror(fd_resource)) {
EMSG2(_("E457: Can't read PostScript resource file \"%s\""),
- resource->filename);
+ resource->filename);
fclose(fd_resource);
return FALSE;
}
- if (bytes_read == 0)
+ if (bytes_read == 0) {
break;
+ }
prt_write_file_raw_len(resource_buffer, bytes_read);
if (prt_file_error) {
fclose(fd_resource);
@@ -2439,8 +2501,8 @@ int mch_print_begin(prt_settings_T *psettings)
struct prt_ps_resource_S res_prolog;
struct prt_ps_resource_S res_encoding;
char buffer[256];
- char_u *p_encoding;
- char_u *p;
+ char_u *p_encoding;
+ char_u *p;
struct prt_ps_resource_S res_cidfont;
struct prt_ps_resource_S res_cmap;
int retval = FALSE;
@@ -2460,8 +2522,9 @@ int mch_print_begin(prt_settings_T *psettings)
char *p_time = os_ctime(ctime_buf, sizeof(ctime_buf));
// Note: os_ctime() adds a \n so we have to remove it :-(
p = vim_strchr((char_u *)p_time, '\n');
- if (p != NULL)
+ if (p != NULL) {
*p = NUL;
+ }
prt_dsc_textline("CreationDate", p_time);
prt_dsc_textline("DocumentData", "Clean8Bit");
prt_dsc_textline("Orientation", "Portrait");
@@ -2471,8 +2534,8 @@ int mch_print_begin(prt_settings_T *psettings)
* user coordinate system! We have to recalculate right and bottom
* coordinates based on the font metrics for the bbox to be accurate. */
prt_page_margins(prt_mediasize[prt_media].width,
- prt_mediasize[prt_media].height,
- &left, &right, &top, &bottom);
+ prt_mediasize[prt_media].height,
+ &left, &right, &top, &bottom);
bbox[0] = (int)left;
if (prt_portrait) {
/* In portrait printing the fixed point is the top left corner so we
@@ -2507,9 +2570,10 @@ int mch_print_begin(prt_settings_T *psettings)
}
if (prt_out_mbyte) {
prt_dsc_font_resource((prt_use_courier ? NULL
- : "DocumentNeededResources"), &prt_ps_mb_font);
- if (!prt_custom_cmap)
+ : "DocumentNeededResources"), &prt_ps_mb_font);
+ if (!prt_custom_cmap) {
prt_dsc_resources(NULL, "cmap", prt_cmap);
+ }
}
// Search for external resources VIM supplies
@@ -2517,20 +2581,24 @@ int mch_print_begin(prt_settings_T *psettings)
EMSG(_("E456: Can't find PostScript resource file \"prolog.ps\""));
return FALSE;
}
- if (!prt_open_resource(&res_prolog))
+ if (!prt_open_resource(&res_prolog)) {
return FALSE;
- if (!prt_check_resource(&res_prolog, PRT_PROLOG_VERSION))
+ }
+ if (!prt_check_resource(&res_prolog, PRT_PROLOG_VERSION)) {
return FALSE;
+ }
if (prt_out_mbyte) {
// Look for required version of multi-byte printing procset
if (!prt_find_resource("cidfont", &res_cidfont)) {
EMSG(_("E456: Can't find PostScript resource file \"cidfont.ps\""));
return FALSE;
}
- if (!prt_open_resource(&res_cidfont))
+ if (!prt_open_resource(&res_cidfont)) {
return FALSE;
- if (!prt_check_resource(&res_cidfont, PRT_CID_PROLOG_VERSION))
+ }
+ if (!prt_check_resource(&res_cidfont, PRT_CID_PROLOG_VERSION)) {
return FALSE;
+ }
}
/* Find an encoding to use for printing.
@@ -2554,28 +2622,31 @@ int mch_print_begin(prt_settings_T *psettings)
p_encoding = (char_u *)"latin1";
if (!prt_find_resource((char *)p_encoding, &res_encoding)) {
EMSG2(_("E456: Can't find PostScript resource file \"%s.ps\""),
- p_encoding);
+ p_encoding);
return FALSE;
}
}
}
- if (!prt_open_resource(&res_encoding))
+ if (!prt_open_resource(&res_encoding)) {
return FALSE;
+ }
/* For the moment there are no checks on encoding resource files to
* perform */
} else {
p_encoding = enc_skip(p_penc);
- if (*p_encoding == NUL)
+ if (*p_encoding == NUL) {
p_encoding = enc_skip(p_enc);
+ }
if (prt_use_courier) {
// Include ASCII range encoding vector
if (!prt_find_resource(prt_ascii_encoding, &res_encoding)) {
EMSG2(_("E456: Can't find PostScript resource file \"%s.ps\""),
- prt_ascii_encoding);
+ prt_ascii_encoding);
return FALSE;
}
- if (!prt_open_resource(&res_encoding))
+ if (!prt_open_resource(&res_encoding)) {
return FALSE;
+ }
/* For the moment there are no checks on encoding resource files to
* perform */
}
@@ -2596,11 +2667,12 @@ int mch_print_begin(prt_settings_T *psettings)
// Find user supplied CMap
if (!prt_find_resource(prt_cmap, &res_cmap)) {
EMSG2(_("E456: Can't find PostScript resource file \"%s.ps\""),
- prt_cmap);
+ prt_cmap);
return FALSE;
}
- if (!prt_open_resource(&res_cmap))
+ if (!prt_open_resource(&res_cmap)) {
return FALSE;
+ }
}
// List resources supplied
@@ -2628,8 +2700,8 @@ int mch_print_begin(prt_settings_T *psettings)
prt_dsc_resources(NULL, "encoding", buffer);
}
prt_dsc_requirements(prt_duplex, prt_tumble, prt_collate,
- psettings->do_syntax
- , prt_num_copies);
+ psettings->do_syntax
+ , prt_num_copies);
prt_dsc_noarg("EndComments");
/*
@@ -2643,9 +2715,10 @@ int mch_print_begin(prt_settings_T *psettings)
}
if (prt_out_mbyte) {
prt_dsc_font_resource((prt_use_courier ? NULL : "PageResources"),
- &prt_ps_mb_font);
- if (!prt_custom_cmap)
+ &prt_ps_mb_font);
+ if (!prt_custom_cmap) {
prt_dsc_resources(NULL, "cmap", prt_cmap);
+ }
}
// Paper will be used for all pages
@@ -2672,11 +2745,13 @@ int mch_print_begin(prt_settings_T *psettings)
}
}
- if (!prt_out_mbyte || prt_use_courier)
+ if (!prt_out_mbyte || prt_use_courier) {
/* There will be only one Roman font encoding to be included in the PS
* file. */
- if (!prt_add_resource(&res_encoding))
+ if (!prt_add_resource(&res_encoding)) {
return FALSE;
+ }
+ }
prt_dsc_noarg("EndProlog");
@@ -2702,44 +2777,47 @@ int mch_print_begin(prt_settings_T *psettings)
if (!prt_out_mbyte || prt_use_courier) {
/* When using Courier for ASCII range when printing multi-byte, need to
* pick up ASCII encoding to use with it. */
- if (prt_use_courier)
+ if (prt_use_courier) {
p_encoding = (char_u *)prt_ascii_encoding;
+ }
prt_dsc_resources("IncludeResource", "font",
- prt_ps_courier_font.ps_fontname[PRT_PS_FONT_ROMAN]);
+ prt_ps_courier_font.ps_fontname[PRT_PS_FONT_ROMAN]);
prt_def_font("F0", (char *)p_encoding, (int)prt_line_height,
- prt_ps_courier_font.ps_fontname[PRT_PS_FONT_ROMAN]);
+ prt_ps_courier_font.ps_fontname[PRT_PS_FONT_ROMAN]);
prt_dsc_resources("IncludeResource", "font",
- prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLD]);
+ prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLD]);
prt_def_font("F1", (char *)p_encoding, (int)prt_line_height,
- prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLD]);
+ prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLD]);
prt_dsc_resources("IncludeResource", "font",
- prt_ps_courier_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
+ prt_ps_courier_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
prt_def_font("F2", (char *)p_encoding, (int)prt_line_height,
- prt_ps_courier_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
+ prt_ps_courier_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
prt_dsc_resources("IncludeResource", "font",
- prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
+ prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
prt_def_font("F3", (char *)p_encoding, (int)prt_line_height,
- prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
+ prt_ps_courier_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
}
if (prt_out_mbyte) {
- /* Define the CID fonts to be used in the job. Typically CJKV fonts do
+ /* Define the CID fonts to be used in the job. Typically CJKV fonts do
* not have an italic form being a western style, so where no font is
* defined for these faces VIM falls back to an existing face.
* Note: if using Courier for the ASCII range then the printout will
* have bold/italic/bolditalic regardless of the setting of printmbfont.
*/
prt_dsc_resources("IncludeResource", "font",
- prt_ps_mb_font.ps_fontname[PRT_PS_FONT_ROMAN]);
- if (!prt_custom_cmap)
+ prt_ps_mb_font.ps_fontname[PRT_PS_FONT_ROMAN]);
+ if (!prt_custom_cmap) {
prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
+ }
prt_def_cidfont("CF0", (int)prt_line_height,
- prt_ps_mb_font.ps_fontname[PRT_PS_FONT_ROMAN]);
+ prt_ps_mb_font.ps_fontname[PRT_PS_FONT_ROMAN]);
if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD] != NULL) {
prt_dsc_resources("IncludeResource", "font",
- prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD]);
- if (!prt_custom_cmap)
+ prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD]);
+ if (!prt_custom_cmap) {
prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
+ }
prt_def_cidfont("CF1", (int)prt_line_height,
prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD]);
} else {
@@ -2748,9 +2826,10 @@ int mch_print_begin(prt_settings_T *psettings)
}
if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE] != NULL) {
prt_dsc_resources("IncludeResource", "font",
- prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
- if (!prt_custom_cmap)
+ prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
+ if (!prt_custom_cmap) {
prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
+ }
prt_def_cidfont("CF2", (int)prt_line_height,
prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE]);
} else {
@@ -2759,9 +2838,10 @@ int mch_print_begin(prt_settings_T *psettings)
}
if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE] != NULL) {
prt_dsc_resources("IncludeResource", "font",
- prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
- if (!prt_custom_cmap)
+ prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
+ if (!prt_custom_cmap) {
prt_dsc_resources("IncludeResource", "cmap", prt_cmap);
+ }
prt_def_cidfont("CF3", (int)prt_line_height,
prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]);
} else {
@@ -2772,9 +2852,9 @@ int mch_print_begin(prt_settings_T *psettings)
// Misc constant vars used for underlining and background rects
prt_def_var("UO", PRT_PS_FONT_TO_USER(prt_line_height,
- prt_ps_font->uline_offset), 2);
+ prt_ps_font->uline_offset), 2);
prt_def_var("UW", PRT_PS_FONT_TO_USER(prt_line_height,
- prt_ps_font->uline_width), 2);
+ prt_ps_font->uline_width), 2);
prt_def_var("BO", prt_bgcol_offset, 2);
prt_dsc_noarg("EndSetup");
@@ -2810,7 +2890,7 @@ void mch_print_end(prt_settings_T *psettings)
prt_message((char_u *)_("Sending to printer..."));
// Not printing to a file: use 'printexpr' to print the file.
- if (eval_printexpr((char *) prt_ps_file_name, (char *) psettings->arguments)
+ if (eval_printexpr((char *)prt_ps_file_name, (char *)psettings->arguments)
== FAIL) {
EMSG(_("E365: Failed to print PostScript file"));
} else {
@@ -2845,10 +2925,11 @@ int mch_print_begin_page(char_u *str)
prt_write_string("sv\n0 g\n");
prt_in_ascii = !prt_out_mbyte;
- if (prt_out_mbyte)
+ if (prt_out_mbyte) {
prt_write_string("CF0 sf\n");
- else
+ } else {
prt_write_string("F0 sf\n");
+ }
prt_fgcol = PRCOLOR_BLACK;
prt_bgcol = PRCOLOR_WHITE;
prt_font = PRT_PS_FONT_ROMAN;
@@ -2975,9 +3056,9 @@ int mch_print_text_out(char_u *const textp, size_t len)
b = prt_fgcol & 0xff;
prt_write_real(r / 255.0, 3);
- if (r == g && g == b)
+ if (r == g && g == b) {
prt_write_string("g\n");
- else {
+ } else {
prt_write_real(g / 255.0, 3);
prt_write_real(b / 255.0, 3);
prt_write_string("r\n");
@@ -2995,8 +3076,9 @@ int mch_print_text_out(char_u *const textp, size_t len)
}
prt_need_bgcol = false;
- if (prt_need_underline)
+ if (prt_need_underline) {
prt_do_underline = prt_underline;
+ }
prt_need_underline = false;
prt_attribute_change = false;
@@ -3034,14 +3116,22 @@ int mch_print_text_out(char_u *const textp, size_t len)
*/
ga_append(&prt_ps_buffer, '\\');
switch (ch) {
- case BS: ga_append(&prt_ps_buffer, 'b'); break;
- case TAB: ga_append(&prt_ps_buffer, 't'); break;
- case NL: ga_append(&prt_ps_buffer, 'n'); break;
- case FF: ga_append(&prt_ps_buffer, 'f'); break;
- case CAR: ga_append(&prt_ps_buffer, 'r'); break;
- case '(': ga_append(&prt_ps_buffer, '('); break;
- case ')': ga_append(&prt_ps_buffer, ')'); break;
- case '\\': ga_append(&prt_ps_buffer, '\\'); break;
+ case BS:
+ ga_append(&prt_ps_buffer, 'b'); break;
+ case TAB:
+ ga_append(&prt_ps_buffer, 't'); break;
+ case NL:
+ ga_append(&prt_ps_buffer, 'n'); break;
+ case FF:
+ ga_append(&prt_ps_buffer, 'f'); break;
+ case CAR:
+ ga_append(&prt_ps_buffer, 'r'); break;
+ case '(':
+ ga_append(&prt_ps_buffer, '('); break;
+ case ')':
+ ga_append(&prt_ps_buffer, ')'); break;
+ case '\\':
+ ga_append(&prt_ps_buffer, '\\'); break;
default:
sprintf((char *)ch_buff, "%03o", (unsigned int)ch);
@@ -3050,8 +3140,9 @@ int mch_print_text_out(char_u *const textp, size_t len)
ga_append(&prt_ps_buffer, (char)ch_buff[2]);
break;
}
- } else
+ } else {
ga_append(&prt_ps_buffer, (char)ch);
+ }
}
// Need to free any translated characters
@@ -3063,7 +3154,7 @@ int mch_print_text_out(char_u *const textp, size_t len)
// The downside of fp - use relative error on right margin check
const double next_pos = prt_pos_x + prt_char_width;
const bool need_break = (next_pos > prt_right_margin)
- && ((next_pos - prt_right_margin) > (prt_right_margin * 1e-5));
+ && ((next_pos - prt_right_margin) > (prt_right_margin * 1e-5));
if (need_break) {
prt_flush_buffer();
@@ -3072,15 +3163,16 @@ int mch_print_text_out(char_u *const textp, size_t len)
return need_break;
}
-void mch_print_set_font(const TriState iBold, const TriState iItalic,
- const TriState iUnderline)
+void mch_print_set_font(const TriState iBold, const TriState iItalic, const TriState iUnderline)
{
int font = 0;
- if (iBold)
+ if (iBold) {
font |= 0x01;
- if (iItalic)
+ }
+ if (iItalic) {
font |= 0x02;
+ }
if (font != prt_font) {
prt_font = font;
diff --git a/src/nvim/hashtab.c b/src/nvim/hashtab.c
index 526bc284a4..a8e5de839a 100644
--- a/src/nvim/hashtab.c
+++ b/src/nvim/hashtab.c
@@ -22,15 +22,15 @@
/// memory).
#include <assert.h>
+#include <inttypes.h>
#include <stdbool.h>
#include <string.h>
-#include <inttypes.h>
-#include "nvim/vim.h"
#include "nvim/ascii.h"
#include "nvim/hashtab.h"
-#include "nvim/message.h"
#include "nvim/memory.h"
+#include "nvim/message.h"
+#include "nvim/vim.h"
// Magic value for algorithm that walks through the array.
#define PERTURB_SHIFT 5
@@ -102,8 +102,7 @@ hashitem_T *hash_find(const hashtab_T *const ht, const char_u *const key)
///
/// @warning Returned pointer becomes invalid as soon as the hash table
/// is changed in any way.
-hashitem_T *hash_find_len(const hashtab_T *const ht, const char *const key,
- const size_t len)
+hashitem_T *hash_find_len(const hashtab_T *const ht, const char *const key, const size_t len)
{
return hash_lookup(ht, key, len, hash_hash_len(key, len));
}
@@ -119,8 +118,7 @@ hashitem_T *hash_find_len(const hashtab_T *const ht, const char *const key,
/// used for that key.
/// WARNING: Returned pointer becomes invalid as soon as the hash table
/// is changed in any way.
-hashitem_T *hash_lookup(const hashtab_T *const ht,
- const char *const key, const size_t key_len,
+hashitem_T *hash_lookup(const hashtab_T *const ht, const char *const key, const size_t key_len,
const hash_T hash)
{
#ifdef HT_DEBUG
@@ -336,7 +334,7 @@ static void hash_may_resize(hashtab_T *ht, size_t minitems)
bool newarray_is_small = newsize == HT_INIT_SIZE;
bool keep_smallarray = newarray_is_small
- && ht->ht_array == ht->ht_smallarray;
+ && ht->ht_array == ht->ht_smallarray;
// Make sure that oldarray and newarray do not overlap,
// so that copying is possible.
@@ -387,7 +385,7 @@ static void hash_may_resize(hashtab_T *ht, size_t minitems)
}
#define HASH_CYCLE_BODY(hash, p) \
- hash = hash * 101 + *p++
+ hash = hash * 101 + *p++
/// Get the hash number for a key.
///
diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c
index 79e474fa2e..bb325b3f25 100644
--- a/src/nvim/highlight.c
+++ b/src/nvim/highlight.c
@@ -3,9 +3,11 @@
// highlight.c: low level code for UI and syntax highlighting
-#include "nvim/vim.h"
+#include "nvim/api/private/defs.h"
+#include "nvim/api/private/helpers.h"
#include "nvim/highlight.h"
#include "nvim/highlight_defs.h"
+#include "nvim/lua/executor.h"
#include "nvim/map.h"
#include "nvim/message.h"
#include "nvim/option.h"
@@ -13,9 +15,7 @@
#include "nvim/screen.h"
#include "nvim/syntax.h"
#include "nvim/ui.h"
-#include "nvim/api/private/defs.h"
-#include "nvim/api/private/helpers.h"
-#include "nvim/lua/executor.h"
+#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "highlight.c.generated.h"
@@ -25,28 +25,22 @@ static bool hlstate_active = false;
static kvec_t(HlEntry) attr_entries = KV_INITIAL_VALUE;
-static Map(HlEntry, int) *attr_entry_ids;
-static Map(int, int) *combine_attr_entries;
-static Map(int, int) *blend_attr_entries;
-static Map(int, int) *blendthrough_attr_entries;
+static Map(HlEntry, int) attr_entry_ids = MAP_INIT;
+static Map(int, int) combine_attr_entries = MAP_INIT;
+static Map(int, int) blend_attr_entries = MAP_INIT;
+static Map(int, int) blendthrough_attr_entries = MAP_INIT;
/// highlight entries private to a namespace
-static Map(ColorKey, ColorItem) *ns_hl;
+static Map(ColorKey, ColorItem) ns_hl;
void highlight_init(void)
{
- attr_entry_ids = map_new(HlEntry, int)();
- combine_attr_entries = map_new(int, int)();
- blend_attr_entries = map_new(int, int)();
- blendthrough_attr_entries = map_new(int, int)();
- ns_hl = map_new(ColorKey, ColorItem)();
-
// index 0 is no attribute, add dummy entry:
kv_push(attr_entries, ((HlEntry){ .attr = HLATTRS_INIT, .kind = kHlUnknown,
.id1 = 0, .id2 = 0 }));
}
-/// @return TRUE if hl table was reset
+/// @return true if hl table was reset
bool highlight_use_hlstate(void)
{
if (hlstate_active) {
@@ -71,7 +65,7 @@ static int get_attr_entry(HlEntry entry)
entry.id2 = 0;
}
- int id = map_get(HlEntry, int)(attr_entry_ids, entry);
+ int id = map_get(HlEntry, int)(&attr_entry_ids, entry);
if (id > 0) {
return id;
}
@@ -104,7 +98,7 @@ static int get_attr_entry(HlEntry entry)
id = (int)next_id;
kv_push(attr_entries, entry);
- map_put(HlEntry, int)(attr_entry_ids, entry, id);
+ map_put(HlEntry, int)(&attr_entry_ids, entry, id);
Array inspect = hl_inspect(id);
@@ -154,7 +148,7 @@ void ns_hl_def(NS ns_id, int hl_id, HlAttrs attrs, int link_id)
{
DecorProvider *p = get_decor_provider(ns_id, true);
if ((attrs.rgb_ae_attr & HL_DEFAULT)
- && map_has(ColorKey, ColorItem)(ns_hl, ColorKey(ns_id, hl_id))) {
+ && map_has(ColorKey, ColorItem)(&ns_hl, ColorKey(ns_id, hl_id))) {
return;
}
int attr_id = link_id > 0 ? -1 : hl_get_syn_attr(ns_id, hl_id, attrs);
@@ -162,7 +156,7 @@ void ns_hl_def(NS ns_id, int hl_id, HlAttrs attrs, int link_id)
.link_id = link_id,
.version = p->hl_valid,
.is_default = (attrs.rgb_ae_attr & HL_DEFAULT) };
- map_put(ColorKey, ColorItem)(ns_hl, ColorKey(ns_id, hl_id), it);
+ map_put(ColorKey, ColorItem)(&ns_hl, ColorKey(ns_id, hl_id), it);
}
int ns_get_hl(NS ns_id, int hl_id, bool link, bool nodefault)
@@ -177,7 +171,7 @@ int ns_get_hl(NS ns_id, int hl_id, bool link, bool nodefault)
}
DecorProvider *p = get_decor_provider(ns_id, true);
- ColorItem it = map_get(ColorKey, ColorItem)(ns_hl, ColorKey(ns_id, hl_id));
+ ColorItem it = map_get(ColorKey, ColorItem)(&ns_hl, ColorKey(ns_id, hl_id));
// TODO(bfredl): map_ref true even this?
bool valid_cache = it.version >= p->hl_valid;
@@ -220,7 +214,7 @@ int ns_get_hl(NS ns_id, int hl_id, bool link, bool nodefault)
it.attr_id = fallback ? -1 : hl_get_syn_attr((int)ns_id, hl_id, attrs);
it.version = p->hl_valid-tmp;
it.is_default = attrs.rgb_ae_attr & HL_DEFAULT;
- map_put(ColorKey, ColorItem)(ns_hl, ColorKey(ns_id, hl_id), it);
+ map_put(ColorKey, ColorItem)(&ns_hl, ColorKey(ns_id, hl_id), it);
}
if (it.is_default && nodefault) {
@@ -367,19 +361,19 @@ void update_window_hl(win_T *wp, bool invalid)
int hl_get_underline(void)
{
return get_attr_entry((HlEntry){
- .attr = (HlAttrs){
- .cterm_ae_attr = (int16_t)HL_UNDERLINE,
- .cterm_fg_color = 0,
- .cterm_bg_color = 0,
- .rgb_ae_attr = (int16_t)HL_UNDERLINE,
- .rgb_fg_color = -1,
- .rgb_bg_color = -1,
- .rgb_sp_color = -1,
- .hl_blend = -1,
- },
- .kind = kHlUI,
- .id1 = 0,
- .id2 = 0,
+ .attr = (HlAttrs){
+ .cterm_ae_attr = (int16_t)HL_UNDERLINE,
+ .cterm_fg_color = 0,
+ .cterm_bg_color = 0,
+ .rgb_ae_attr = (int16_t)HL_UNDERLINE,
+ .rgb_fg_color = -1,
+ .rgb_bg_color = -1,
+ .rgb_sp_color = -1,
+ .hl_blend = -1,
+ },
+ .kind = kHlUI,
+ .id1 = 0,
+ .id2 = 0,
});
}
@@ -395,28 +389,28 @@ void clear_hl_tables(bool reinit)
{
if (reinit) {
kv_size(attr_entries) = 1;
- map_clear(HlEntry, int)(attr_entry_ids);
- map_clear(int, int)(combine_attr_entries);
- map_clear(int, int)(blend_attr_entries);
- map_clear(int, int)(blendthrough_attr_entries);
+ map_clear(HlEntry, int)(&attr_entry_ids);
+ map_clear(int, int)(&combine_attr_entries);
+ map_clear(int, int)(&blend_attr_entries);
+ map_clear(int, int)(&blendthrough_attr_entries);
memset(highlight_attr_last, -1, sizeof(highlight_attr_last));
highlight_attr_set_all();
highlight_changed();
screen_invalidate_highlights();
} else {
kv_destroy(attr_entries);
- map_free(HlEntry, int)(attr_entry_ids);
- map_free(int, int)(combine_attr_entries);
- map_free(int, int)(blend_attr_entries);
- map_free(int, int)(blendthrough_attr_entries);
- map_free(ColorKey, ColorItem)(ns_hl);
+ map_destroy(HlEntry, int)(&attr_entry_ids);
+ map_destroy(int, int)(&combine_attr_entries);
+ map_destroy(int, int)(&blend_attr_entries);
+ map_destroy(int, int)(&blendthrough_attr_entries);
+ map_destroy(ColorKey, ColorItem)(&ns_hl);
}
}
void hl_invalidate_blends(void)
{
- map_clear(int, int)(blend_attr_entries);
- map_clear(int, int)(blendthrough_attr_entries);
+ map_clear(int, int)(&blend_attr_entries);
+ map_clear(int, int)(&blendthrough_attr_entries);
highlight_changed();
update_window_hl(curwin, true);
}
@@ -437,7 +431,7 @@ int hl_combine_attr(int char_attr, int prim_attr)
// TODO(bfredl): could use a struct for clearer intent.
int combine_tag = (char_attr << 16) + prim_attr;
- int id = map_get(int, int)(combine_attr_entries, combine_tag);
+ int id = map_get(int, int)(&combine_attr_entries, combine_tag);
if (id > 0) {
return id;
}
@@ -494,7 +488,7 @@ int hl_combine_attr(int char_attr, int prim_attr)
id = get_attr_entry((HlEntry){ .attr = new_en, .kind = kHlCombine,
.id1 = char_attr, .id2 = prim_attr });
if (id > 0) {
- map_put(int, int)(combine_attr_entries, combine_tag, id);
+ map_put(int, int)(&combine_attr_entries, combine_tag, id);
}
return id;
@@ -550,8 +544,8 @@ int hl_blend_attrs(int back_attr, int front_attr, bool *through)
int combine_tag = (back_attr << 16) + front_attr;
Map(int, int) *map = (*through
- ? blendthrough_attr_entries
- : blend_attr_entries);
+ ? &blendthrough_attr_entries
+ : &blend_attr_entries);
int id = map_get(int, int)(map, combine_tag);
if (id > 0) {
return id;
@@ -654,23 +648,23 @@ static int hl_cterm2rgb_color(int nr)
};
static char_u ansi_table[16][4] = {
// R G B idx
- { 0, 0, 0, 1 } , // black
- { 224, 0, 0, 2 } , // dark red
- { 0, 224, 0, 3 } , // dark green
- { 224, 224, 0, 4 } , // dark yellow / brown
- { 0, 0, 224, 5 } , // dark blue
- { 224, 0, 224, 6 } , // dark magenta
- { 0, 224, 224, 7 } , // dark cyan
- { 224, 224, 224, 8 } , // light grey
-
- { 128, 128, 128, 9 } , // dark grey
- { 255, 64, 64, 10 } , // light red
- { 64, 255, 64, 11 } , // light green
- { 255, 255, 64, 12 } , // yellow
- { 64, 64, 255, 13 } , // light blue
- { 255, 64, 255, 14 } , // light magenta
- { 64, 255, 255, 15 } , // light cyan
- { 255, 255, 255, 16 } , // white
+ { 0, 0, 0, 1 }, // black
+ { 224, 0, 0, 2 }, // dark red
+ { 0, 224, 0, 3 }, // dark green
+ { 224, 224, 0, 4 }, // dark yellow / brown
+ { 0, 0, 224, 5 }, // dark blue
+ { 224, 0, 224, 6 }, // dark magenta
+ { 0, 224, 224, 7 }, // dark cyan
+ { 224, 224, 224, 8 }, // light grey
+
+ { 128, 128, 128, 9 }, // dark grey
+ { 255, 64, 64, 10 }, // light red
+ { 64, 255, 64, 11 }, // light green
+ { 255, 255, 64, 12 }, // yellow
+ { 64, 64, 255, 13 }, // light blue
+ { 255, 64, 255, 14 }, // light magenta
+ { 64, 255, 255, 15 }, // light cyan
+ { 255, 255, 255, 16 }, // white
};
int r = 0;
@@ -796,7 +790,7 @@ Dictionary hlattrs2dict(HlAttrs ae, bool use_rgb)
}
if (ae.hl_blend > -1) {
- PUT(hl, "blend", INTEGER_OBJ(ae.hl_blend));
+ PUT(hl, "blend", INTEGER_OBJ(ae.hl_blend));
}
return hl;
@@ -853,7 +847,7 @@ HlAttrs dict2hlattrs(Dictionary dict, bool use_rgb, int *link_id, Error *err)
err)) {
cterm_mask |= flags[m].flag;
}
- break;
+ break;
}
}
}
@@ -921,9 +915,9 @@ HlAttrs dict2hlattrs(Dictionary dict, bool use_rgb, int *link_id, Error *err)
hlattrs.rgb_fg_color = fg;
hlattrs.rgb_sp_color = sp;
hlattrs.cterm_bg_color =
- ctermbg == -1 ? cterm_normal_bg_color : ctermbg + 1;
+ ctermbg == -1 ? cterm_normal_bg_color : ctermbg + 1;
hlattrs.cterm_fg_color =
- ctermfg == -1 ? cterm_normal_fg_color : ctermfg + 1;
+ ctermfg == -1 ? cterm_normal_fg_color : ctermfg + 1;
hlattrs.cterm_ae_attr = cterm_mask;
} else {
hlattrs.cterm_ae_attr = cterm_mask;
@@ -951,34 +945,34 @@ static void hl_inspect_impl(Array *arr, int attr)
HlEntry e = kv_A(attr_entries, attr);
switch (e.kind) {
- case kHlSyntax:
- PUT(item, "kind", STRING_OBJ(cstr_to_string("syntax")));
- PUT(item, "hi_name",
- STRING_OBJ(cstr_to_string((char *)syn_id2name(e.id1))));
- break;
-
- case kHlUI:
- PUT(item, "kind", STRING_OBJ(cstr_to_string("ui")));
- const char *ui_name = (e.id1 == -1) ? "Normal" : hlf_names[e.id1];
- PUT(item, "ui_name", STRING_OBJ(cstr_to_string(ui_name)));
- PUT(item, "hi_name",
- STRING_OBJ(cstr_to_string((char *)syn_id2name(e.id2))));
- break;
-
- case kHlTerminal:
- PUT(item, "kind", STRING_OBJ(cstr_to_string("term")));
- break;
-
- case kHlCombine:
- case kHlBlend:
- case kHlBlendThrough:
- // attribute combination is associative, so flatten to an array
- hl_inspect_impl(arr, e.id1);
- hl_inspect_impl(arr, e.id2);
- return;
-
- case kHlUnknown:
- return;
+ case kHlSyntax:
+ PUT(item, "kind", STRING_OBJ(cstr_to_string("syntax")));
+ PUT(item, "hi_name",
+ STRING_OBJ(cstr_to_string((char *)syn_id2name(e.id1))));
+ break;
+
+ case kHlUI:
+ PUT(item, "kind", STRING_OBJ(cstr_to_string("ui")));
+ const char *ui_name = (e.id1 == -1) ? "Normal" : hlf_names[e.id1];
+ PUT(item, "ui_name", STRING_OBJ(cstr_to_string(ui_name)));
+ PUT(item, "hi_name",
+ STRING_OBJ(cstr_to_string((char *)syn_id2name(e.id2))));
+ break;
+
+ case kHlTerminal:
+ PUT(item, "kind", STRING_OBJ(cstr_to_string("term")));
+ break;
+
+ case kHlCombine:
+ case kHlBlend:
+ case kHlBlendThrough:
+ // attribute combination is associative, so flatten to an array
+ hl_inspect_impl(arr, e.id1);
+ hl_inspect_impl(arr, e.id2);
+ return;
+
+ case kHlUnknown:
+ return;
}
PUT(item, "id", INTEGER_OBJ(attr));
ADD(*arr, DICTIONARY_OBJ(item));
diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h
index ed4aefb577..a0e8bad11f 100644
--- a/src/nvim/highlight_defs.h
+++ b/src/nvim/highlight_defs.h
@@ -63,7 +63,9 @@ typedef enum {
, HLF_M // "--More--" message
, HLF_CM // Mode (e.g., "-- INSERT --")
, HLF_N // line number for ":number" and ":#" commands
- , HLF_CLN // current line number
+ , HLF_LNA // LineNrAbove
+ , HLF_LNB // LineNrBelow
+ , HLF_CLN // current line number when 'cursorline' is set
, HLF_R // return to continue message and yes/no questions
, HLF_S // status lines
, HLF_SNC // status lines of not-current windows
@@ -118,6 +120,8 @@ EXTERN const char *hlf_names[] INIT(= {
[HLF_M] = "MoreMsg",
[HLF_CM] = "ModeMsg",
[HLF_N] = "LineNr",
+ [HLF_LNA] = "LineNrAbove",
+ [HLF_LNB] = "LineNrBelow",
[HLF_CLN] = "CursorLineNr",
[HLF_R] = "Question",
[HLF_S] = "StatusLine",
diff --git a/src/nvim/indent.c b/src/nvim/indent.c
index 8fa61515ef..a3ee3983e5 100644
--- a/src/nvim/indent.c
+++ b/src/nvim/indent.c
@@ -7,24 +7,25 @@
#include "nvim/ascii.h"
#include "nvim/assert.h"
+#include "nvim/buffer.h"
#include "nvim/change.h"
-#include "nvim/indent.h"
-#include "nvim/eval.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
-#include "nvim/mark.h"
+#include "nvim/eval.h"
#include "nvim/extmark.h"
+#include "nvim/indent.h"
+#include "nvim/mark.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/misc1.h"
#include "nvim/move.h"
#include "nvim/option.h"
+#include "nvim/plines.h"
#include "nvim/regexp.h"
#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/strings.h"
#include "nvim/undo.h"
-#include "nvim/buffer.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -62,10 +63,10 @@ int get_indent_buf(buf_T *buf, linenr_T lnum)
}
-// 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.
-int get_indent_str(const char_u *ptr, int ts, int list)
+/// 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.
+int get_indent_str(const char_u *ptr, int ts, bool list)
FUNC_ATTR_NONNULL_ALL
{
int count = 0;
@@ -91,9 +92,9 @@ int get_indent_str(const char_u *ptr, int ts, int list)
return count;
}
-// Count the size (in window cells) of the indent in line "ptr", using
-// variable tabstops.
-// if "list" is true, count only screen size for tabs.
+/// Count the size (in window cells) of the indent in line "ptr", using
+/// variable tabstops.
+/// if "list" is true, count only screen size for tabs.
int get_indent_str_vtab(const char_u *ptr, long ts, long *vts, bool list)
{
int count = 0;
@@ -432,7 +433,7 @@ int get_number_indent(linenr_T lnum)
// Return appropriate space number for breakindent, taking influencing
// parameters into account. Window must be specified, since it is not
// necessarily always the current one.
-int get_breakindent_win(win_T *wp, const char_u *line)
+int get_breakindent_win(win_T *wp, char_u *line)
FUNC_ATTR_NONNULL_ALL
{
static int prev_indent = 0; // Cached indent value.
@@ -443,8 +444,8 @@ int get_breakindent_win(win_T *wp, const char_u *line)
int bri = 0;
// window width minus window margin space, i.e. what rests for text
const int eff_wwidth = wp->w_width_inner
- - ((wp->w_p_nu || wp->w_p_rnu)
- && (vim_strchr(p_cpo, CPO_NUMCOL) == NULL)
+ - ((wp->w_p_nu || wp->w_p_rnu)
+ && (vim_strchr(p_cpo, CPO_NUMCOL) == NULL)
? number_width(wp) + 1 : 0);
// used cached indent, unless pointer or 'tabstop' changed
@@ -462,12 +463,33 @@ int get_breakindent_win(win_T *wp, const char_u *line)
}
bri = prev_indent + wp->w_briopt_shift;
+ // Add offset for number column, if 'n' is in 'cpoptions'
+ bri += win_col_off2(wp);
+
+ // add additional indent for numbered lists
+ if (wp->w_briopt_list != 0) {
+ regmatch_T regmatch = {
+ .regprog = vim_regcomp(curbuf->b_p_flp,
+ RE_MAGIC + RE_STRING + RE_AUTO + RE_STRICT),
+ };
+
+ if (regmatch.regprog != NULL) {
+ regmatch.rm_ic = false;
+ if (vim_regexec(&regmatch, line, 0)) {
+ if (wp->w_briopt_list > 0) {
+ bri += wp->w_briopt_list;
+ } else {
+ bri = (int)(*regmatch.endp - *regmatch.startp);
+ }
+ }
+ vim_regfree(regmatch.regprog);
+ }
+ }
+
// indent minus the length of the showbreak string
if (wp->w_briopt_sbr) {
- bri -= vim_strsize(p_sbr);
+ bri -= vim_strsize(get_showbreak_value(wp));
}
- // Add offset for number column, if 'n' is in 'cpoptions'
- bri += win_col_off2(wp);
// never indent past left window margin
if (bri < 0) {
@@ -488,7 +510,7 @@ int get_breakindent_win(win_T *wp, const char_u *line)
// the line.
int inindent(int extra)
{
- char_u *ptr;
+ char_u *ptr;
colnr_T col;
for (col = 0, ptr = get_cursor_line_ptr(); ascii_iswhite(*ptr); ++col) {
@@ -511,15 +533,14 @@ int get_expr_indent(void)
colnr_T save_curswant;
int save_set_curswant;
int save_State;
- int use_sandbox = was_set_insecurely(
- curwin, (char_u *)"indentexpr", OPT_LOCAL);
+ int use_sandbox = was_set_insecurely(curwin, (char_u *)"indentexpr", OPT_LOCAL);
// Save and restore cursor position and curswant, in case it was changed
// * via :normal commands.
save_pos = curwin->w_cursor;
save_curswant = curwin->w_curswant;
save_set_curswant = curwin->w_set_curswant;
- set_vim_var_nr(VV_LNUM, (varnumber_T) curwin->w_cursor.lnum);
+ set_vim_var_nr(VV_LNUM, (varnumber_T)curwin->w_cursor.lnum);
if (use_sandbox) {
sandbox++;
@@ -700,11 +721,11 @@ int get_lisp_indent(void)
quotecount = 0;
if (vi_lisp || ((*that != '"') && (*that != '\'')
- && (*that != '#') && ((*that < '0') || (*that > '9')))) {
+ && (*that != '#') && ((*that < '0') || (*that > '9')))) {
while (*that
&& (!ascii_iswhite(*that) || quotecount || parencount)
&& (!((*that == '(' || *that == '[')
- && !quotecount && !parencount && vi_lisp))) {
+ && !quotecount && !parencount && vi_lisp))) {
if (*that == '"') {
quotecount = !quotecount;
}
diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c
index 6dacace0a4..b724d82f7c 100644
--- a/src/nvim/keymap.c
+++ b/src/nvim/keymap.c
@@ -5,16 +5,16 @@
#include <inttypes.h>
#include <limits.h>
-#include "nvim/vim.h"
#include "nvim/ascii.h"
-#include "nvim/keymap.h"
#include "nvim/charset.h"
-#include "nvim/memory.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
+#include "nvim/keymap.h"
+#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/strings.h"
#include "nvim/mouse.h"
+#include "nvim/strings.h"
+#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "keymap.c.generated.h"
@@ -51,48 +51,48 @@ static const struct modmasktable {
static char_u modifier_keys_table[] =
{
- /* mod mask with modifier without modifier */
- MOD_MASK_SHIFT, '&', '9', '@', '1', /* begin */
- MOD_MASK_SHIFT, '&', '0', '@', '2', /* cancel */
- MOD_MASK_SHIFT, '*', '1', '@', '4', /* command */
- MOD_MASK_SHIFT, '*', '2', '@', '5', /* copy */
- MOD_MASK_SHIFT, '*', '3', '@', '6', /* create */
- MOD_MASK_SHIFT, '*', '4', 'k', 'D', /* delete char */
- MOD_MASK_SHIFT, '*', '5', 'k', 'L', /* delete line */
- MOD_MASK_SHIFT, '*', '7', '@', '7', /* end */
- MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_END, '@', '7', /* end */
- MOD_MASK_SHIFT, '*', '9', '@', '9', /* exit */
- MOD_MASK_SHIFT, '*', '0', '@', '0', /* find */
- MOD_MASK_SHIFT, '#', '1', '%', '1', /* help */
- MOD_MASK_SHIFT, '#', '2', 'k', 'h', /* home */
- MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_HOME, 'k', 'h', /* home */
- MOD_MASK_SHIFT, '#', '3', 'k', 'I', /* insert */
- MOD_MASK_SHIFT, '#', '4', 'k', 'l', /* left arrow */
- MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_LEFT, 'k', 'l', /* left arrow */
- MOD_MASK_SHIFT, '%', 'a', '%', '3', /* message */
- MOD_MASK_SHIFT, '%', 'b', '%', '4', /* move */
- MOD_MASK_SHIFT, '%', 'c', '%', '5', /* next */
- MOD_MASK_SHIFT, '%', 'd', '%', '7', /* options */
- MOD_MASK_SHIFT, '%', 'e', '%', '8', /* previous */
- MOD_MASK_SHIFT, '%', 'f', '%', '9', /* print */
- MOD_MASK_SHIFT, '%', 'g', '%', '0', /* redo */
- MOD_MASK_SHIFT, '%', 'h', '&', '3', /* replace */
- MOD_MASK_SHIFT, '%', 'i', 'k', 'r', /* right arr. */
- MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_RIGHT, 'k', 'r', /* right arr. */
- MOD_MASK_SHIFT, '%', 'j', '&', '5', /* resume */
- MOD_MASK_SHIFT, '!', '1', '&', '6', /* save */
- MOD_MASK_SHIFT, '!', '2', '&', '7', /* suspend */
- MOD_MASK_SHIFT, '!', '3', '&', '8', /* undo */
- MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_UP, 'k', 'u', /* up arrow */
- MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_DOWN, 'k', 'd', /* down arrow */
-
- /* vt100 F1 */
+ // mod mask with modifier without modifier
+ MOD_MASK_SHIFT, '&', '9', '@', '1', // begin
+ MOD_MASK_SHIFT, '&', '0', '@', '2', // cancel
+ MOD_MASK_SHIFT, '*', '1', '@', '4', // command
+ MOD_MASK_SHIFT, '*', '2', '@', '5', // copy
+ MOD_MASK_SHIFT, '*', '3', '@', '6', // create
+ MOD_MASK_SHIFT, '*', '4', 'k', 'D', // delete char
+ MOD_MASK_SHIFT, '*', '5', 'k', 'L', // delete line
+ MOD_MASK_SHIFT, '*', '7', '@', '7', // end
+ MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_END, '@', '7', // end
+ MOD_MASK_SHIFT, '*', '9', '@', '9', // exit
+ MOD_MASK_SHIFT, '*', '0', '@', '0', // find
+ MOD_MASK_SHIFT, '#', '1', '%', '1', // help
+ MOD_MASK_SHIFT, '#', '2', 'k', 'h', // home
+ MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_HOME, 'k', 'h', // home
+ MOD_MASK_SHIFT, '#', '3', 'k', 'I', // insert
+ MOD_MASK_SHIFT, '#', '4', 'k', 'l', // left arrow
+ MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_LEFT, 'k', 'l', // left arrow
+ MOD_MASK_SHIFT, '%', 'a', '%', '3', // message
+ MOD_MASK_SHIFT, '%', 'b', '%', '4', // move
+ MOD_MASK_SHIFT, '%', 'c', '%', '5', // next
+ MOD_MASK_SHIFT, '%', 'd', '%', '7', // options
+ MOD_MASK_SHIFT, '%', 'e', '%', '8', // previous
+ MOD_MASK_SHIFT, '%', 'f', '%', '9', // print
+ MOD_MASK_SHIFT, '%', 'g', '%', '0', // redo
+ MOD_MASK_SHIFT, '%', 'h', '&', '3', // replace
+ MOD_MASK_SHIFT, '%', 'i', 'k', 'r', // right arr.
+ MOD_MASK_CTRL, KS_EXTRA, (int)KE_C_RIGHT, 'k', 'r', // right arr.
+ MOD_MASK_SHIFT, '%', 'j', '&', '5', // resume
+ MOD_MASK_SHIFT, '!', '1', '&', '6', // save
+ MOD_MASK_SHIFT, '!', '2', '&', '7', // suspend
+ MOD_MASK_SHIFT, '!', '3', '&', '8', // undo
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_UP, 'k', 'u', // up arrow
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_DOWN, 'k', 'd', // down arrow
+
+ // vt100 F1
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF1, KS_EXTRA, (int)KE_XF1,
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF2, KS_EXTRA, (int)KE_XF2,
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF3, KS_EXTRA, (int)KE_XF3,
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_XF4, KS_EXTRA, (int)KE_XF4,
- MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F1, 'k', '1', /* F1 */
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F1, 'k', '1', // F1
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F2, 'k', '2',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F3, 'k', '3',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F4, 'k', '4',
@@ -101,7 +101,7 @@ static char_u modifier_keys_table[] =
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F7, 'k', '7',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F8, 'k', '8',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F9, 'k', '9',
- MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F10, 'k', ';', /* F10 */
+ MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F10, 'k', ';', // F10
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F11, 'F', '1',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F12, 'F', '2',
@@ -133,7 +133,7 @@ static char_u modifier_keys_table[] =
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F36, 'F', 'Q',
MOD_MASK_SHIFT, KS_EXTRA, (int)KE_S_F37, 'F', 'R',
- /* TAB pseudo code*/
+ // TAB pseudo code
MOD_MASK_SHIFT, 'k', 'B', KS_EXTRA, (int)KE_TAB,
NUL
@@ -397,22 +397,38 @@ int handle_x_keys(const int key)
FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT
{
switch (key) {
- case K_XUP: return K_UP;
- case K_XDOWN: return K_DOWN;
- case K_XLEFT: return K_LEFT;
- case K_XRIGHT: return K_RIGHT;
- case K_XHOME: return K_HOME;
- case K_ZHOME: return K_HOME;
- case K_XEND: return K_END;
- case K_ZEND: return K_END;
- case K_XF1: return K_F1;
- case K_XF2: return K_F2;
- case K_XF3: return K_F3;
- case K_XF4: return K_F4;
- case K_S_XF1: return K_S_F1;
- case K_S_XF2: return K_S_F2;
- case K_S_XF3: return K_S_F3;
- case K_S_XF4: return K_S_F4;
+ case K_XUP:
+ return K_UP;
+ case K_XDOWN:
+ return K_DOWN;
+ case K_XLEFT:
+ return K_LEFT;
+ case K_XRIGHT:
+ return K_RIGHT;
+ case K_XHOME:
+ return K_HOME;
+ case K_ZHOME:
+ return K_HOME;
+ case K_XEND:
+ return K_END;
+ case K_ZEND:
+ return K_END;
+ case K_XF1:
+ return K_F1;
+ case K_XF2:
+ return K_F2;
+ case K_XF3:
+ return K_F3;
+ case K_XF4:
+ return K_F4;
+ case K_S_XF1:
+ return K_S_F1;
+ case K_S_XF2:
+ return K_S_F2;
+ case K_S_XF3:
+ return K_S_F3;
+ case K_S_XF4:
+ return K_S_F4;
}
return key;
}
@@ -427,31 +443,33 @@ char_u *get_special_key_name(int c, int modifiers)
int i, idx;
int table_idx;
- char_u *s;
+ char_u *s;
string[0] = '<';
idx = 1;
- /* Key that stands for a normal character. */
- if (IS_SPECIAL(c) && KEY2TERMCAP0(c) == KS_KEY)
+ // Key that stands for a normal character.
+ if (IS_SPECIAL(c) && KEY2TERMCAP0(c) == KS_KEY) {
c = KEY2TERMCAP1(c);
+ }
/*
* Translate shifted special keys into unshifted keys and set modifier.
* Same for CTRL and ALT modifiers.
*/
if (IS_SPECIAL(c)) {
- for (i = 0; modifier_keys_table[i] != 0; i += MOD_KEYS_ENTRY_SIZE)
- if ( KEY2TERMCAP0(c) == (int)modifier_keys_table[i + 1]
- && (int)KEY2TERMCAP1(c) == (int)modifier_keys_table[i + 2]) {
+ for (i = 0; modifier_keys_table[i] != 0; i += MOD_KEYS_ENTRY_SIZE) {
+ if (KEY2TERMCAP0(c) == (int)modifier_keys_table[i + 1]
+ && (int)KEY2TERMCAP1(c) == (int)modifier_keys_table[i + 2]) {
modifiers |= modifier_keys_table[i];
c = TERMCAP2KEY(modifier_keys_table[i + 3],
- modifier_keys_table[i + 4]);
+ modifier_keys_table[i + 4]);
break;
}
+ }
}
- /* try to find the key in the special key table */
+ // try to find the key in the special key table
table_idx = find_special_key_in_table(c);
/*
@@ -459,14 +477,13 @@ char_u *get_special_key_name(int c, int modifiers)
* extract modifiers.
*/
if (c > 0
- && (*mb_char2len)(c) == 1
- ) {
+ && (*mb_char2len)(c) == 1) {
if (table_idx < 0
&& (!vim_isprintc(c) || (c & 0x7f) == ' ')
&& (c & 0x80)) {
c &= 0x7f;
modifiers |= MOD_MASK_ALT;
- /* try again, to find the un-alted key in the special key table */
+ // try again, to find the un-alted key in the special key table
table_idx = find_special_key_in_table(c);
}
if (table_idx < 0 && !vim_isprintc(c) && c < ' ') {
@@ -475,15 +492,16 @@ char_u *get_special_key_name(int c, int modifiers)
}
}
- /* translate the modifier into a string */
- for (i = 0; mod_mask_table[i].name != 'A'; i++)
+ // translate the modifier into a string
+ for (i = 0; mod_mask_table[i].name != 'A'; i++) {
if ((modifiers & mod_mask_table[i].mod_mask)
== mod_mask_table[i].mod_flag) {
string[idx++] = mod_mask_table[i].name;
string[idx++] = (char_u)'-';
}
+ }
- if (table_idx < 0) { /* unknown special key, may output t_xx */
+ if (table_idx < 0) { // unknown special key, may output t_xx
if (IS_SPECIAL(c)) {
string[idx++] = 't';
string[idx++] = '_';
@@ -497,16 +515,17 @@ char_u *get_special_key_name(int c, int modifiers)
string[idx++] = (char_u)c;
} else {
s = transchar(c);
- while (*s)
+ while (*s) {
string[idx++] = *s++;
+ }
}
}
} else { // use name of special key
size_t len = STRLEN(key_names_table[table_idx].name);
if ((int)len + idx + 2 <= MAX_KEY_NAME_LEN) {
- STRCPY(string + idx, key_names_table[table_idx].name);
- idx += (int)len;
+ STRCPY(string + idx, key_names_table[table_idx].name);
+ idx += (int)len;
}
}
string[idx++] = '>';
@@ -525,9 +544,8 @@ char_u *get_special_key_name(int c, int modifiers)
/// @param[in] in_string Inside a double quoted string
///
/// @return Number of characters added to dst, zero for no match.
-unsigned int trans_special(const char_u **srcp, const size_t src_len,
- char_u *const dst, const bool keycode,
- const bool in_string)
+unsigned int trans_special(const char_u **srcp, const size_t src_len, char_u *const dst,
+ const bool keycode, const bool in_string)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
int modifiers = 0;
@@ -543,7 +561,7 @@ unsigned int trans_special(const char_u **srcp, const size_t src_len,
/// Put the character sequence for "key" with "modifiers" into "dst" and return
/// the resulting length.
-/// When "keycode" is TRUE prefer key code, e.g. K_DEL instead of DEL.
+/// When "keycode" is true prefer key code, e.g. K_DEL instead of DEL.
/// The sequence is not NUL terminated.
/// This is how characters in a string are encoded.
unsigned int special_to_buf(int key, int modifiers, bool keycode, char_u *dst)
@@ -582,9 +600,8 @@ unsigned int special_to_buf(int key, int modifiers, bool keycode, char_u *dst)
/// @param[in] in_string In string, double quote is escaped
///
/// @return Key and modifiers or 0 if there is no match.
-int find_special_key(const char_u **srcp, const size_t src_len, int *const modp,
- const bool keycode, const bool keep_x_key,
- const bool in_string)
+int find_special_key(const char_u **srcp, const size_t src_len, int *const modp, const bool keycode,
+ const bool keep_x_key, const bool in_string)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
const char_u *last_dash;
@@ -628,7 +645,11 @@ int find_special_key(const char_u **srcp, const size_t src_len, int *const modp,
if (end - bp > 3 && bp[0] == 't' && bp[1] == '_') {
bp += 3; // skip t_xx, xx may be '-' or '>'
} else if (end - bp > 4 && STRNICMP(bp, "char-", 5) == 0) {
- vim_str2nr(bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0);
+ vim_str2nr(bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0, true);
+ if (l == 0) {
+ EMSG(_(e_invarg));
+ return 0;
+ }
bp += l + 5;
break;
}
@@ -637,7 +658,7 @@ int find_special_key(const char_u **srcp, const size_t src_len, int *const modp,
if (bp <= end && *bp == '>') { // found matching '>'
end_of_name = bp + 1;
- /* Which modifiers are given? */
+ // Which modifiers are given?
modifiers = 0x0;
for (bp = src + 1; bp < last_dash; bp++) {
if (*bp != '-') {
@@ -654,7 +675,11 @@ int find_special_key(const char_u **srcp, const size_t src_len, int *const modp,
if (STRNICMP(last_dash + 1, "char-", 5) == 0
&& ascii_isdigit(last_dash[6])) {
// <Char-123> or <Char-033> or <Char-0x33>
- vim_str2nr(last_dash + 6, NULL, NULL, STR2NR_ALL, NULL, &n, 0);
+ vim_str2nr(last_dash + 6, NULL, &l, STR2NR_ALL, NULL, &n, 0, true);
+ if (l == 0) {
+ EMSG(_(e_invarg));
+ return 0;
+ }
key = (int)n;
} else {
int off = 1;
@@ -787,13 +812,14 @@ int get_mouse_button(int code, bool *is_click, bool *is_drag)
{
int i;
- for (i = 0; mouse_table[i].pseudo_code; i++)
+ for (i = 0; mouse_table[i].pseudo_code; i++) {
if (code == mouse_table[i].pseudo_code) {
*is_click = mouse_table[i].is_click;
*is_drag = mouse_table[i].is_drag;
return mouse_table[i].button;
}
- return 0; /* Shouldn't get here */
+ }
+ return 0; // Shouldn't get here
}
/// Replace any terminal code strings with the equivalent internal
@@ -821,9 +847,8 @@ int get_mouse_button(int code, bool *is_click, bool *is_drag)
/// @return Pointer to an allocated memory in case of success, "from" in case of
/// failure. In case of success returned pointer is also saved to
/// "bufp".
-char_u *replace_termcodes(const char_u *from, const size_t from_len,
- char_u **bufp, const bool from_part, const bool do_lt,
- const bool special, int cpo_flags)
+char_u *replace_termcodes(const char_u *from, const size_t from_len, char_u **bufp,
+ const bool from_part, const bool do_lt, const bool special, int cpo_flags)
FUNC_ATTR_NONNULL_ALL
{
ssize_t i;
@@ -833,7 +858,7 @@ char_u *replace_termcodes(const char_u *from, const size_t from_len,
const char_u *src;
const char_u *const end = from + from_len - 1;
int do_backslash; // backslash is a special character
- char_u *result; // buffer for resulting string
+ char_u *result; // buffer for resulting string
do_backslash = !(cpo_flags&FLAG_CPO_BSLASH);
@@ -889,7 +914,7 @@ char_u *replace_termcodes(const char_u *from, const size_t from_len,
}
if (special) {
- char_u *p, *s, len;
+ char_u *p, *s, len;
// Replace <Leader> by the value of "mapleader".
// Replace <LocalLeader> by the value of "maplocalleader".
diff --git a/src/nvim/keymap.h b/src/nvim/keymap.h
index d31196d412..9fc44f6f84 100644
--- a/src/nvim/keymap.h
+++ b/src/nvim/keymap.h
@@ -9,11 +9,11 @@
* Any special key code sequences are replaced by these codes.
*/
-/*
- * For MSDOS some keys produce codes larger than 0xff. They are split into two
- * chars, the first one is K_NUL.
- */
-#define K_NUL (0xce) // for MSDOS: special key follows
+//
+// For MS-DOS some keys produce codes larger than 0xff. They are split into two
+// chars, the first one is K_NUL.
+//
+#define K_NUL (0xce) // for MS-DOS: special key follows
/*
* K_SPECIAL is the first byte of a special key code and is always followed by
diff --git a/src/nvim/log.c b/src/nvim/log.c
index 324382a0f7..5539e3d6c5 100644
--- a/src/nvim/log.c
+++ b/src/nvim/log.c
@@ -17,9 +17,9 @@
#include "auto/config.h"
#include "nvim/log.h"
-#include "nvim/types.h"
#include "nvim/os/os.h"
#include "nvim/os/time.h"
+#include "nvim/types.h"
#define LOG_FILE_ENV "NVIM_LOG_FILE"
@@ -124,8 +124,8 @@ void log_unlock(void)
/// @param line_num Source line number, or -1
/// @param eol Append linefeed "\n"
/// @param fmt printf-style format string
-bool logmsg(int log_level, const char *context, const char *func_name,
- int line_num, bool eol, const char *fmt, ...)
+bool logmsg(int log_level, const char *context, const char *func_name, int line_num, bool eol,
+ const char *fmt, ...)
FUNC_ATTR_UNUSED FUNC_ATTR_PRINTF(6, 7)
{
if (log_level < MIN_LOG_LEVEL) {
@@ -215,8 +215,7 @@ FILE *open_log_file(void)
}
#ifdef HAVE_EXECINFO_BACKTRACE
-void log_callstack_to_file(FILE *log_file, const char *const func_name,
- const int line_num)
+void log_callstack_to_file(FILE *log_file, const char *const func_name, const int line_num)
{
void *trace[100];
int trace_size = backtrace(trace, ARRAY_SIZE(trace));
@@ -268,8 +267,7 @@ end:
#endif
static bool do_log_to_file(FILE *log_file, int log_level, const char *context,
- const char *func_name, int line_num, bool eol,
- const char *fmt, ...)
+ const char *func_name, int line_num, bool eol, const char *fmt, ...)
FUNC_ATTR_PRINTF(7, 8)
{
va_list args;
@@ -281,9 +279,8 @@ static bool do_log_to_file(FILE *log_file, int log_level, const char *context,
return ret;
}
-static bool v_do_log_to_file(FILE *log_file, int log_level,
- const char *context, const char *func_name,
- int line_num, bool eol, const char *fmt,
+static bool v_do_log_to_file(FILE *log_file, int log_level, const char *context,
+ const char *func_name, int line_num, bool eol, const char *fmt,
va_list args)
{
static const char *log_levels[] = {
@@ -317,10 +314,10 @@ static bool v_do_log_to_file(FILE *log_file, int log_level,
? fprintf(log_file, "%s %s.%03d %-5" PRId64 " %s",
log_levels[log_level], date_time, millis, pid,
(context == NULL ? "?:" : context))
- : fprintf(log_file, "%s %s.%03d %-5" PRId64 " %s%s:%d: ",
- log_levels[log_level], date_time, millis, pid,
- (context == NULL ? "" : context),
- func_name, line_num);
+ : fprintf(log_file, "%s %s.%03d %-5" PRId64 " %s%s:%d: ",
+ log_levels[log_level], date_time, millis, pid,
+ (context == NULL ? "" : context),
+ func_name, line_num);
if (rv < 0) {
return false;
}
diff --git a/src/nvim/log.h b/src/nvim/log.h
index 17d754c033..654b682de8 100644
--- a/src/nvim/log.h
+++ b/src/nvim/log.h
@@ -7,7 +7,7 @@
#include "auto/config.h"
#include "nvim/macros.h"
-// USDT probes. Example invokation:
+// USDT probes. Example invocation:
// NVIM_PROBE(nvim_foo_bar, 1, string.data);
#if defined(HAVE_SYS_SDT_H)
#include <sys/sdt.h> // NOLINT
diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c
index ce8c9b0d06..fac5bab664 100644
--- a/src/nvim/lua/converter.c
+++ b/src/nvim/lua/converter.c
@@ -1,33 +1,31 @@
// 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 <assert.h>
+#include <lauxlib.h>
#include <lua.h>
#include <lualib.h>
-#include <lauxlib.h>
-#include <assert.h>
-#include <stdint.h>
#include <stdbool.h>
+#include <stdint.h>
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
+#include "nvim/assert.h"
#include "nvim/func_attr.h"
#include "nvim/memory.h"
-#include "nvim/assert.h"
// FIXME: vim.h is not actually needed, but otherwise it states MAXPATHL is
// redefined
-#include "nvim/vim.h"
-#include "nvim/globals.h"
-#include "nvim/message.h"
+#include "nvim/ascii.h"
+#include "nvim/eval/decode.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/userfunc.h"
-#include "nvim/ascii.h"
-#include "nvim/macros.h"
-
+#include "nvim/globals.h"
#include "nvim/lib/kvec.h"
-#include "nvim/eval/decode.h"
-
#include "nvim/lua/converter.h"
#include "nvim/lua/executor.h"
+#include "nvim/macros.h"
+#include "nvim/message.h"
+#include "nvim/vim.h"
/// Determine, which keys lua table contains
typedef struct {
@@ -49,7 +47,7 @@ typedef struct {
#define VAL_IDX_VALUE false
#define LUA_PUSH_STATIC_STRING(lstate, s) \
- lua_pushlstring(lstate, s, sizeof(s) - 1)
+ lua_pushlstring(lstate, s, sizeof(s) - 1)
static LuaTableProps nlua_traverse_table(lua_State *const lstate)
@@ -71,57 +69,56 @@ static LuaTableProps nlua_traverse_table(lua_State *const lstate)
lua_pushnil(lstate);
while (lua_next(lstate, -2)) {
switch (lua_type(lstate, -2)) {
- case LUA_TSTRING: {
- size_t len;
- const char *s = lua_tolstring(lstate, -2, &len);
- if (memchr(s, NUL, len) != NULL) {
- ret.has_string_with_nul = true;
- }
- ret.string_keys_num++;
- break;
+ case LUA_TSTRING: {
+ size_t len;
+ const char *s = lua_tolstring(lstate, -2, &len);
+ if (memchr(s, NUL, len) != NULL) {
+ ret.has_string_with_nul = true;
}
- case LUA_TNUMBER: {
- const lua_Number n = lua_tonumber(lstate, -2);
- if (n > (lua_Number)SIZE_MAX || n <= 0
- || ((lua_Number)((size_t)n)) != n) {
- other_keys_num++;
- } else {
- const size_t idx = (size_t)n;
- if (idx > ret.maxidx) {
- ret.maxidx = idx;
- }
+ ret.string_keys_num++;
+ break;
+ }
+ case LUA_TNUMBER: {
+ const lua_Number n = lua_tonumber(lstate, -2);
+ if (n > (lua_Number)SIZE_MAX || n <= 0
+ || ((lua_Number)((size_t)n)) != n) {
+ other_keys_num++;
+ } else {
+ const size_t idx = (size_t)n;
+ if (idx > ret.maxidx) {
+ ret.maxidx = idx;
}
- break;
}
- case LUA_TBOOLEAN: {
- const bool b = lua_toboolean(lstate, -2);
- if (b == TYPE_IDX_VALUE) {
- if (lua_type(lstate, -1) == LUA_TNUMBER) {
- lua_Number n = lua_tonumber(lstate, -1);
- if (n == (lua_Number)kObjectTypeFloat
- || n == (lua_Number)kObjectTypeArray
- || n == (lua_Number)kObjectTypeDictionary) {
- ret.has_type_key = true;
- ret.type = (ObjectType)n;
- } else {
- other_keys_num++;
- }
+ break;
+ }
+ case LUA_TBOOLEAN: {
+ const bool b = lua_toboolean(lstate, -2);
+ if (b == TYPE_IDX_VALUE) {
+ if (lua_type(lstate, -1) == LUA_TNUMBER) {
+ lua_Number n = lua_tonumber(lstate, -1);
+ if (n == (lua_Number)kObjectTypeFloat
+ || n == (lua_Number)kObjectTypeArray
+ || n == (lua_Number)kObjectTypeDictionary) {
+ ret.has_type_key = true;
+ ret.type = (ObjectType)n;
} else {
other_keys_num++;
}
} else {
- has_val_key = true;
- val_type = lua_type(lstate, -1);
- if (val_type == LUA_TNUMBER) {
- ret.val = lua_tonumber(lstate, -1);
- }
+ other_keys_num++;
+ }
+ } else {
+ has_val_key = true;
+ val_type = lua_type(lstate, -1);
+ if (val_type == LUA_TNUMBER) {
+ ret.val = lua_tonumber(lstate, -1);
}
- break;
- }
- default: {
- other_keys_num++;
- break;
}
+ break;
+ }
+ default:
+ other_keys_num++;
+ break;
}
tsize++;
lua_pop(lstate, 1);
@@ -196,8 +193,9 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
{
bool ret = true;
const int initial_size = lua_gettop(lstate);
- kvec_t(TVPopStackItem) stack = KV_INITIAL_VALUE;
- kv_push(stack, ((TVPopStackItem) { ret_tv, false, false, 0 }));
+ kvec_withinit_t(TVPopStackItem, 2) stack = KV_INITIAL_VALUE;
+ kvi_init(stack);
+ kvi_push(stack, ((TVPopStackItem) { ret_tv, false, false, 0 }));
while (ret && kv_size(stack)) {
if (!lua_checkstack(lstate, lua_gettop(lstate) + 3)) {
emsgf(_("E1502: Lua failed to grow stack to %i"), lua_gettop(lstate) + 3);
@@ -234,7 +232,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
tv_list_append_owned_tv(kv_pair, (typval_T) {
.v_type = VAR_UNKNOWN,
});
- kv_push(stack, cur);
+ kvi_push(stack, cur);
tv_list_append_list(cur.tv->vval.v_list, kv_pair);
cur = (TVPopStackItem) {
.tv = TV_LIST_ITEM_TV(tv_list_last(kv_pair)),
@@ -247,7 +245,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
if (tv_dict_add(cur.tv->vval.v_dict, di) == FAIL) {
abort();
}
- kv_push(stack, cur);
+ kvi_push(stack, cur);
cur = (TVPopStackItem) { &di->di_tv, false, false, 0 };
}
} else {
@@ -265,7 +263,7 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
tv_list_append_owned_tv(cur.tv->vval.v_list, (typval_T) {
.v_type = VAR_UNKNOWN,
});
- kv_push(stack, cur);
+ kvi_push(stack, cur);
// TODO(ZyX-I): Use indexes, here list item *will* be reallocated.
cur = (TVPopStackItem) {
.tv = TV_LIST_ITEM_TV(tv_list_last(cur.tv->vval.v_list)),
@@ -282,159 +280,149 @@ bool nlua_pop_typval(lua_State *lstate, typval_T *ret_tv)
.vval = { .v_number = 0 },
};
switch (lua_type(lstate, -1)) {
- case LUA_TNIL: {
- cur.tv->v_type = VAR_SPECIAL;
- cur.tv->vval.v_special = kSpecialVarNull;
- break;
- }
- case LUA_TBOOLEAN: {
- cur.tv->v_type = VAR_BOOL;
- cur.tv->vval.v_bool = (lua_toboolean(lstate, -1)
+ case LUA_TNIL:
+ cur.tv->v_type = VAR_SPECIAL;
+ cur.tv->vval.v_special = kSpecialVarNull;
+ break;
+ case LUA_TBOOLEAN:
+ cur.tv->v_type = VAR_BOOL;
+ cur.tv->vval.v_bool = (lua_toboolean(lstate, -1)
? kBoolVarTrue
: kBoolVarFalse);
- break;
+ break;
+ case LUA_TSTRING: {
+ size_t len;
+ const char *s = lua_tolstring(lstate, -1, &len);
+ *cur.tv = decode_string(s, len, kNone, true, false);
+ if (cur.tv->v_type == VAR_UNKNOWN) {
+ ret = false;
}
- case LUA_TSTRING: {
- size_t len;
- const char *s = lua_tolstring(lstate, -1, &len);
- *cur.tv = decode_string(s, len, kNone, true, false);
- if (cur.tv->v_type == VAR_UNKNOWN) {
- ret = false;
- }
- break;
+ break;
+ }
+ case LUA_TNUMBER: {
+ const lua_Number n = lua_tonumber(lstate, -1);
+ if (n > (lua_Number)VARNUMBER_MAX || n < (lua_Number)VARNUMBER_MIN
+ || ((lua_Number)((varnumber_T)n)) != n) {
+ cur.tv->v_type = VAR_FLOAT;
+ cur.tv->vval.v_float = (float_T)n;
+ } else {
+ cur.tv->v_type = VAR_NUMBER;
+ cur.tv->vval.v_number = (varnumber_T)n;
}
- case LUA_TNUMBER: {
- const lua_Number n = lua_tonumber(lstate, -1);
- if (n > (lua_Number)VARNUMBER_MAX || n < (lua_Number)VARNUMBER_MIN
- || ((lua_Number)((varnumber_T)n)) != n) {
- cur.tv->v_type = VAR_FLOAT;
- cur.tv->vval.v_float = (float_T)n;
- } else {
- cur.tv->v_type = VAR_NUMBER;
- cur.tv->vval.v_number = (varnumber_T)n;
- }
- break;
+ break;
+ }
+ case LUA_TTABLE: {
+ // Only need to track table refs if we have a metatable associated.
+ LuaRef table_ref = LUA_NOREF;
+ if (lua_getmetatable(lstate, -1)) {
+ lua_pop(lstate, 1);
+ table_ref = nlua_ref(lstate, -1);
}
- case LUA_TTABLE: {
- // Only need to track table refs if we have a metatable associated.
- LuaRef table_ref = LUA_NOREF;
- if (lua_getmetatable(lstate, -1)) {
- lua_pop(lstate, 1);
- table_ref = nlua_ref(lstate, -1);
- }
- const LuaTableProps table_props = nlua_traverse_table(lstate);
+ const LuaTableProps table_props = nlua_traverse_table(lstate);
- for (size_t i = 0; i < kv_size(stack); i++) {
- const TVPopStackItem item = kv_A(stack, i);
- if (item.container && lua_rawequal(lstate, -1, item.idx)) {
- tv_copy(item.tv, cur.tv);
- cur.container = false;
- goto nlua_pop_typval_table_processing_end;
- }
+ for (size_t i = 0; i < kv_size(stack); i++) {
+ const TVPopStackItem item = kv_A(stack, i);
+ if (item.container && lua_rawequal(lstate, -1, item.idx)) {
+ tv_copy(item.tv, cur.tv);
+ cur.container = false;
+ goto nlua_pop_typval_table_processing_end;
}
+ }
- switch (table_props.type) {
- case kObjectTypeArray: {
- cur.tv->v_type = VAR_LIST;
- cur.tv->vval.v_list = tv_list_alloc((ptrdiff_t)table_props.maxidx);
+ switch (table_props.type) {
+ case kObjectTypeArray:
+ cur.tv->v_type = VAR_LIST;
+ cur.tv->vval.v_list = tv_list_alloc((ptrdiff_t)table_props.maxidx);
+ cur.tv->vval.v_list->lua_table_ref = table_ref;
+ tv_list_ref(cur.tv->vval.v_list);
+ if (table_props.maxidx != 0) {
+ cur.container = true;
+ cur.idx = lua_gettop(lstate);
+ kvi_push(stack, cur);
+ }
+ break;
+ case kObjectTypeDictionary:
+ if (table_props.string_keys_num == 0) {
+ cur.tv->v_type = VAR_DICT;
+ cur.tv->vval.v_dict = tv_dict_alloc();
+ cur.tv->vval.v_dict->dv_refcount++;
+ cur.tv->vval.v_dict->lua_table_ref = table_ref;
+ } else {
+ cur.special = table_props.has_string_with_nul;
+ if (table_props.has_string_with_nul) {
+ decode_create_map_special_dict(cur.tv, (ptrdiff_t)table_props.string_keys_num);
+ assert(cur.tv->v_type == VAR_DICT);
+ dictitem_T *const val_di = tv_dict_find(cur.tv->vval.v_dict,
+ S_LEN("_VAL"));
+ assert(val_di != NULL);
+ cur.tv = &val_di->di_tv;
cur.tv->vval.v_list->lua_table_ref = table_ref;
- tv_list_ref(cur.tv->vval.v_list);
- if (table_props.maxidx != 0) {
- cur.container = true;
- cur.idx = lua_gettop(lstate);
- kv_push(stack, cur);
- }
- break;
- }
- case kObjectTypeDictionary: {
- if (table_props.string_keys_num == 0) {
- cur.tv->v_type = VAR_DICT;
- cur.tv->vval.v_dict = tv_dict_alloc();
- cur.tv->vval.v_dict->dv_refcount++;
- cur.tv->vval.v_dict->lua_table_ref = table_ref;
- } else {
- cur.special = table_props.has_string_with_nul;
- if (table_props.has_string_with_nul) {
- decode_create_map_special_dict(
- cur.tv, (ptrdiff_t)table_props.string_keys_num);
- assert(cur.tv->v_type == VAR_DICT);
- dictitem_T *const val_di = tv_dict_find(cur.tv->vval.v_dict,
- S_LEN("_VAL"));
- assert(val_di != NULL);
- cur.tv = &val_di->di_tv;
- cur.tv->vval.v_list->lua_table_ref = table_ref;
- assert(cur.tv->v_type == VAR_LIST);
- } else {
- cur.tv->v_type = VAR_DICT;
- cur.tv->vval.v_dict = tv_dict_alloc();
- cur.tv->vval.v_dict->dv_refcount++;
- cur.tv->vval.v_dict->lua_table_ref = table_ref;
- }
- cur.container = true;
- cur.idx = lua_gettop(lstate);
- kv_push(stack, cur);
- lua_pushnil(lstate);
- }
- break;
- }
- case kObjectTypeFloat: {
- cur.tv->v_type = VAR_FLOAT;
- cur.tv->vval.v_float = (float_T)table_props.val;
- break;
- }
- case kObjectTypeNil: {
- EMSG(_("E5100: Cannot convert given lua table: table "
- "should either have a sequence of positive integer keys "
- "or contain only string keys"));
- ret = false;
- break;
- }
- default: {
- abort();
+ assert(cur.tv->v_type == VAR_LIST);
+ } else {
+ cur.tv->v_type = VAR_DICT;
+ cur.tv->vval.v_dict = tv_dict_alloc();
+ cur.tv->vval.v_dict->dv_refcount++;
+ cur.tv->vval.v_dict->lua_table_ref = table_ref;
}
+ cur.container = true;
+ cur.idx = lua_gettop(lstate);
+ kvi_push(stack, cur);
+ lua_pushnil(lstate);
}
-nlua_pop_typval_table_processing_end:
break;
- }
- case LUA_TFUNCTION: {
- LuaCFunctionState *state = xmalloc(sizeof(LuaCFunctionState));
- state->lua_callable.func_ref = nlua_ref(lstate, -1);
-
- char_u *name = register_cfunc(
- &nlua_CFunction_func_call,
- &nlua_CFunction_func_free,
- state);
-
- cur.tv->v_type = VAR_FUNC;
- cur.tv->vval.v_string = vim_strsave(name);
+ case kObjectTypeFloat:
+ cur.tv->v_type = VAR_FLOAT;
+ cur.tv->vval.v_float = (float_T)table_props.val;
break;
- }
- case LUA_TUSERDATA: {
- // TODO(bfredl): check mt.__call and convert to function?
- nlua_pushref(lstate, nlua_nil_ref);
- bool is_nil = lua_rawequal(lstate, -2, -1);
- lua_pop(lstate, 1);
- if (is_nil) {
- cur.tv->v_type = VAR_SPECIAL;
- cur.tv->vval.v_special = kSpecialVarNull;
- } else {
- EMSG(_("E5101: Cannot convert given lua type"));
- ret = false;
- }
+ case kObjectTypeNil:
+ EMSG(_("E5100: Cannot convert given lua table: table "
+ "should either have a sequence of positive integer keys "
+ "or contain only string keys"));
+ ret = false;
break;
+ default:
+ abort();
}
- default: {
+nlua_pop_typval_table_processing_end:
+ break;
+ }
+ case LUA_TFUNCTION: {
+ LuaCFunctionState *state = xmalloc(sizeof(LuaCFunctionState));
+ state->lua_callable.func_ref = nlua_ref(lstate, -1);
+
+ char_u *name = register_cfunc(&nlua_CFunction_func_call,
+ &nlua_CFunction_func_free,
+ state);
+
+ cur.tv->v_type = VAR_FUNC;
+ cur.tv->vval.v_string = vim_strsave(name);
+ break;
+ }
+ case LUA_TUSERDATA: {
+ // TODO(bfredl): check mt.__call and convert to function?
+ nlua_pushref(lstate, nlua_nil_ref);
+ bool is_nil = lua_rawequal(lstate, -2, -1);
+ lua_pop(lstate, 1);
+ if (is_nil) {
+ cur.tv->v_type = VAR_SPECIAL;
+ cur.tv->vval.v_special = kSpecialVarNull;
+ } else {
EMSG(_("E5101: Cannot convert given lua type"));
ret = false;
- break;
}
+ break;
+ }
+ default:
+ EMSG(_("E5101: Cannot convert given lua type"));
+ ret = false;
+ break;
}
if (!cur.container) {
lua_pop(lstate, 1);
}
}
- kv_destroy(stack);
+ kvi_destroy(stack);
if (!ret) {
tv_clear(ret_tv);
*ret_tv = (typval_T) {
@@ -453,89 +441,97 @@ static bool typval_conv_special = false;
#define TYPVAL_ENCODE_ALLOW_SPECIALS true
#define TYPVAL_ENCODE_CONV_NIL(tv) \
- do { \
- if (typval_conv_special) { \
- lua_pushnil(lstate); \
- } else { \
- nlua_pushref(lstate, nlua_nil_ref); \
- } \
- } while (0)
+ do { \
+ if (typval_conv_special) { \
+ lua_pushnil(lstate); \
+ } else { \
+ nlua_pushref(lstate, nlua_nil_ref); \
+ } \
+ } while (0)
#define TYPVAL_ENCODE_CONV_BOOL(tv, num) \
- lua_pushboolean(lstate, (bool)(num))
+ lua_pushboolean(lstate, (bool)(num))
#define TYPVAL_ENCODE_CONV_NUMBER(tv, num) \
- lua_pushnumber(lstate, (lua_Number)(num))
+ lua_pushnumber(lstate, (lua_Number)(num))
#define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER TYPVAL_ENCODE_CONV_NUMBER
#define TYPVAL_ENCODE_CONV_FLOAT(tv, flt) \
- TYPVAL_ENCODE_CONV_NUMBER(tv, flt)
+ TYPVAL_ENCODE_CONV_NUMBER(tv, flt)
#define TYPVAL_ENCODE_CONV_STRING(tv, str, len) \
- lua_pushlstring(lstate, (const char *)(str), (len))
+ lua_pushlstring(lstate, (const char *)(str), (len))
#define TYPVAL_ENCODE_CONV_STR_STRING TYPVAL_ENCODE_CONV_STRING
#define TYPVAL_ENCODE_CONV_EXT_STRING(tv, str, len, type) \
- TYPVAL_ENCODE_CONV_NIL(tv)
+ TYPVAL_ENCODE_CONV_NIL(tv)
+
+#define TYPVAL_ENCODE_CONV_BLOB(tv, blob, len) \
+ do { \
+ const blob_T *const blob_ = (blob); \
+ lua_pushlstring(lstate, \
+ blob_ != NULL ? (const char *)blob_->bv_ga.ga_data : "", \
+ (size_t)(len)); \
+ } while (0)
#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \
- do { \
- TYPVAL_ENCODE_CONV_NIL(tv); \
- goto typval_encode_stop_converting_one_item; \
- } while (0)
+ do { \
+ TYPVAL_ENCODE_CONV_NIL(tv); \
+ goto typval_encode_stop_converting_one_item; \
+ } while (0)
#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(tv, len)
#define TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(tv, len)
#define TYPVAL_ENCODE_CONV_FUNC_END(tv)
#define TYPVAL_ENCODE_CONV_EMPTY_LIST(tv) \
- lua_createtable(lstate, 0, 0)
+ lua_createtable(lstate, 0, 0)
#define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \
- do { \
- if (typval_conv_special) { \
- nlua_create_typed_table(lstate, 0, 0, kObjectTypeDictionary); \
- } else { \
- lua_createtable(lstate, 0, 0); \
- nlua_pushref(lstate, nlua_empty_dict_ref); \
- lua_setmetatable(lstate, -2); \
- } \
- } while (0)
+ do { \
+ if (typval_conv_special) { \
+ nlua_create_typed_table(lstate, 0, 0, kObjectTypeDictionary); \
+ } else { \
+ lua_createtable(lstate, 0, 0); \
+ nlua_pushref(lstate, nlua_empty_dict_ref); \
+ lua_setmetatable(lstate, -2); \
+ } \
+ } while (0)
#define TYPVAL_ENCODE_CONV_LIST_START(tv, len) \
- do { \
- if (!lua_checkstack(lstate, lua_gettop(lstate) + 3)) { \
- emsgf(_("E5102: Lua failed to grow stack to %i"), \
- lua_gettop(lstate) + 3); \
- return false; \
- } \
- lua_createtable(lstate, (int)(len), 0); \
- lua_pushnumber(lstate, 1); \
- } while (0)
+ do { \
+ if (!lua_checkstack(lstate, lua_gettop(lstate) + 3)) { \
+ emsgf(_("E5102: Lua failed to grow stack to %i"), \
+ lua_gettop(lstate) + 3); \
+ return false; \
+ } \
+ lua_createtable(lstate, (int)(len), 0); \
+ lua_pushnumber(lstate, 1); \
+ } while (0)
#define TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START(tv, mpsv)
#define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(tv) \
- do { \
- lua_Number idx = lua_tonumber(lstate, -2); \
- lua_rawset(lstate, -3); \
- lua_pushnumber(lstate, idx + 1); \
- } while (0)
+ do { \
+ lua_Number idx = lua_tonumber(lstate, -2); \
+ lua_rawset(lstate, -3); \
+ lua_pushnumber(lstate, idx + 1); \
+ } while (0)
#define TYPVAL_ENCODE_CONV_LIST_END(tv) \
- lua_rawset(lstate, -3)
+ lua_rawset(lstate, -3)
#define TYPVAL_ENCODE_CONV_DICT_START(tv, dict, len) \
- do { \
- if (!lua_checkstack(lstate, lua_gettop(lstate) + 3)) { \
- emsgf(_("E5102: Lua failed to grow stack to %i"), \
- lua_gettop(lstate) + 3); \
- return false; \
- } \
- lua_createtable(lstate, 0, (int)(len)); \
- } while (0)
+ do { \
+ if (!lua_checkstack(lstate, lua_gettop(lstate) + 3)) { \
+ emsgf(_("E5102: Lua failed to grow stack to %i"), \
+ lua_gettop(lstate) + 3); \
+ return false; \
+ } \
+ lua_createtable(lstate, 0, (int)(len)); \
+ } while (0)
#define TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK(label, kv_pair)
@@ -544,26 +540,26 @@ static bool typval_conv_special = false;
#define TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(tv, dict)
#define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(tv, dict) \
- lua_rawset(lstate, -3)
+ lua_rawset(lstate, -3)
#define TYPVAL_ENCODE_CONV_DICT_END(tv, dict) \
- TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(tv, dict)
+ TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(tv, dict)
#define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) \
- do { \
- for (size_t backref = kv_size(*mpstack); backref; backref--) { \
- const MPConvStackVal mpval = kv_A(*mpstack, backref - 1); \
- if (mpval.type == conv_type) { \
- if (conv_type == kMPConvDict \
+ do { \
+ for (size_t backref = kv_size(*mpstack); backref; backref--) { \
+ const MPConvStackVal mpval = kv_A(*mpstack, backref - 1); \
+ if (mpval.type == conv_type) { \
+ if (conv_type == kMPConvDict \
? (void *)mpval.data.d.dict == (void *)(val) \
: (void *)mpval.data.l.list == (void *)(val)) { \
- lua_pushvalue(lstate, \
- -((int)((kv_size(*mpstack) - backref + 1) * 2))); \
- break; \
- } \
+ lua_pushvalue(lstate, \
+ -((int)((kv_size(*mpstack) - backref + 1) * 2))); \
+ break; \
} \
} \
- } while (0)
+ } \
+ } while (0)
#define TYPVAL_ENCODE_SCOPE static
#define TYPVAL_ENCODE_NAME lua
@@ -578,6 +574,7 @@ static bool typval_conv_special = false;
#undef TYPVAL_ENCODE_CONV_STRING
#undef TYPVAL_ENCODE_CONV_STR_STRING
#undef TYPVAL_ENCODE_CONV_EXT_STRING
+#undef TYPVAL_ENCODE_CONV_BLOB
#undef TYPVAL_ENCODE_CONV_NUMBER
#undef TYPVAL_ENCODE_CONV_FLOAT
#undef TYPVAL_ENCODE_CONV_FUNC_START
@@ -664,9 +661,7 @@ static inline void nlua_push_type(lua_State *lstate, ObjectType type)
/// @param[in] narr Number of “array” entries to be populated later.
/// @param[in] nrec Number of “dictionary” entries to be populated later.
/// @param[in] type Type of the table.
-static inline void nlua_create_typed_table(lua_State *lstate,
- const size_t narr,
- const size_t nrec,
+static inline void nlua_create_typed_table(lua_State *lstate, const size_t narr, const size_t nrec,
const ObjectType type)
FUNC_ATTR_NONNULL_ALL
{
@@ -723,8 +718,7 @@ void nlua_push_Boolean(lua_State *lstate, const Boolean b, bool special)
/// Convert given Dictionary to lua table
///
/// Leaves converted table on top of the stack.
-void nlua_push_Dictionary(lua_State *lstate, const Dictionary dict,
- bool special)
+void nlua_push_Dictionary(lua_State *lstate, const Dictionary dict, bool special)
FUNC_ATTR_NONNULL_ALL
{
if (dict.size == 0 && special) {
@@ -757,11 +751,11 @@ void nlua_push_Array(lua_State *lstate, const Array array, bool special)
}
#define GENERATE_INDEX_FUNCTION(type) \
-void nlua_push_##type(lua_State *lstate, const type item, bool special) \
+ void nlua_push_##type(lua_State *lstate, const type item, bool special) \
FUNC_ATTR_NONNULL_ALL \
-{ \
- lua_pushnumber(lstate, (lua_Number)(item)); \
-}
+ { \
+ lua_pushnumber(lstate, (lua_Number)(item)); \
+ }
GENERATE_INDEX_FUNCTION(Buffer)
GENERATE_INDEX_FUNCTION(Window)
@@ -776,23 +770,22 @@ void nlua_push_Object(lua_State *lstate, const Object obj, bool special)
FUNC_ATTR_NONNULL_ALL
{
switch (obj.type) {
- case kObjectTypeNil: {
- if (special) {
- lua_pushnil(lstate);
- } else {
- nlua_pushref(lstate, nlua_nil_ref);
- }
- break;
- }
- case kObjectTypeLuaRef: {
- nlua_pushref(lstate, obj.data.luaref);
- break;
+ case kObjectTypeNil:
+ if (special) {
+ lua_pushnil(lstate);
+ } else {
+ nlua_pushref(lstate, nlua_nil_ref);
}
+ break;
+ case kObjectTypeLuaRef: {
+ nlua_pushref(lstate, obj.data.luaref);
+ break;
+ }
#define ADD_TYPE(type, data_key) \
- case kObjectType##type: { \
- nlua_push_##type(lstate, obj.data.data_key, special); \
- break; \
- }
+case kObjectType##type: { \
+ nlua_push_##type(lstate, obj.data.data_key, special); \
+ break; \
+}
ADD_TYPE(Boolean, boolean)
ADD_TYPE(Integer, integer)
ADD_TYPE(Float, floating)
@@ -801,10 +794,10 @@ void nlua_push_Object(lua_State *lstate, const Object obj, bool special)
ADD_TYPE(Dictionary, dictionary)
#undef ADD_TYPE
#define ADD_REMOTE_TYPE(type) \
- case kObjectType##type: { \
- nlua_push_##type(lstate, (type)obj.data.integer, special); \
- break; \
- }
+case kObjectType##type: { \
+ nlua_push_##type(lstate, (type)obj.data.integer, special); \
+ break; \
+}
ADD_REMOTE_TYPE(Buffer)
ADD_REMOTE_TYPE(Window)
ADD_REMOTE_TYPE(Tabpage)
@@ -873,8 +866,7 @@ Boolean nlua_pop_Boolean(lua_State *lstate, Error *err)
/// @param[in] type Type to check.
///
/// @return @see nlua_traverse_table().
-static inline LuaTableProps nlua_check_type(lua_State *const lstate,
- Error *const err,
+static inline LuaTableProps nlua_check_type(lua_State *const lstate, Error *const err,
const ObjectType type)
FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_WARN_UNUSED_RESULT
{
@@ -927,8 +919,7 @@ Float nlua_pop_Float(lua_State *lstate, Error *err)
/// @param lstate Lua state.
/// @param[in] table_props nlua_traverse_table() output.
/// @param[out] err Location where error will be saved.
-static Array nlua_pop_Array_unchecked(lua_State *const lstate,
- const LuaTableProps table_props,
+static Array nlua_pop_Array_unchecked(lua_State *const lstate, const LuaTableProps table_props,
Error *const err)
{
Array ret = { .size = table_props.maxidx, .items = NULL };
@@ -980,10 +971,8 @@ Array nlua_pop_Array(lua_State *lstate, Error *err)
/// @param lstate Lua interpreter state.
/// @param[in] table_props nlua_traverse_table() output.
/// @param[out] err Location where error will be saved.
-static Dictionary nlua_pop_Dictionary_unchecked(lua_State *lstate,
- const LuaTableProps table_props,
- bool ref,
- Error *err)
+static Dictionary nlua_pop_Dictionary_unchecked(lua_State *lstate, const LuaTableProps table_props,
+ bool ref, Error *err)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
Dictionary ret = { .size = table_props.string_keys_num, .items = NULL };
@@ -1060,15 +1049,16 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Error *const err)
{
Object ret = NIL;
const int initial_size = lua_gettop(lstate);
- kvec_t(ObjPopStackItem) stack = KV_INITIAL_VALUE;
- kv_push(stack, ((ObjPopStackItem) { &ret, false }));
+ kvec_withinit_t(ObjPopStackItem, 2) stack = KV_INITIAL_VALUE;
+ kvi_init(stack);
+ kvi_push(stack, ((ObjPopStackItem) { &ret, false }));
while (!ERROR_SET(err) && kv_size(stack)) {
- if (!lua_checkstack(lstate, lua_gettop(lstate) + 3)) {
- api_set_error(err, kErrorTypeException, "Lua failed to grow stack");
- break;
- }
ObjPopStackItem cur = kv_pop(stack);
if (cur.container) {
+ if (!lua_checkstack(lstate, lua_gettop(lstate) + 3)) {
+ api_set_error(err, kErrorTypeException, "Lua failed to grow stack");
+ break;
+ }
if (cur.obj->type == kObjectTypeDictionary) {
// stack: …, dict, key
if (cur.obj->data.dictionary.size
@@ -1095,7 +1085,7 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Error *const err)
.data = xmemdupz(s, len),
.size = len,
};
- kv_push(stack, cur);
+ kvi_push(stack, cur);
cur = (ObjPopStackItem) {
.obj = &cur.obj->data.dictionary.items[idx].value,
.container = false,
@@ -1117,7 +1107,7 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Error *const err)
lua_pop(lstate, 2);
continue;
}
- kv_push(stack, cur);
+ kvi_push(stack, cur);
cur = (ObjPopStackItem) {
.obj = &cur.obj->data.array.items[idx],
.container = false,
@@ -1127,119 +1117,110 @@ Object nlua_pop_Object(lua_State *const lstate, bool ref, Error *const err)
assert(!cur.container);
*cur.obj = NIL;
switch (lua_type(lstate, -1)) {
- case LUA_TNIL: {
- break;
- }
- case LUA_TBOOLEAN: {
- *cur.obj = BOOLEAN_OBJ(lua_toboolean(lstate, -1));
- break;
- }
- case LUA_TSTRING: {
- size_t len;
- const char *s = lua_tolstring(lstate, -1, &len);
- *cur.obj = STRING_OBJ(((String) {
+ case LUA_TNIL:
+ break;
+ case LUA_TBOOLEAN:
+ *cur.obj = BOOLEAN_OBJ(lua_toboolean(lstate, -1));
+ break;
+ case LUA_TSTRING: {
+ size_t len;
+ const char *s = lua_tolstring(lstate, -1, &len);
+ *cur.obj = STRING_OBJ(((String) {
.data = xmemdupz(s, len),
.size = len,
}));
- break;
+ break;
+ }
+ case LUA_TNUMBER: {
+ const lua_Number n = lua_tonumber(lstate, -1);
+ if (n > (lua_Number)API_INTEGER_MAX || n < (lua_Number)API_INTEGER_MIN
+ || ((lua_Number)((Integer)n)) != n) {
+ *cur.obj = FLOAT_OBJ((Float)n);
+ } else {
+ *cur.obj = INTEGER_OBJ((Integer)n);
}
- case LUA_TNUMBER: {
- const lua_Number n = lua_tonumber(lstate, -1);
- if (n > (lua_Number)API_INTEGER_MAX || n < (lua_Number)API_INTEGER_MIN
- || ((lua_Number)((Integer)n)) != n) {
- *cur.obj = FLOAT_OBJ((Float)n);
- } else {
- *cur.obj = INTEGER_OBJ((Integer)n);
+ break;
+ }
+ case LUA_TTABLE: {
+ const LuaTableProps table_props = nlua_traverse_table(lstate);
+
+ switch (table_props.type) {
+ case kObjectTypeArray:
+ *cur.obj = ARRAY_OBJ(((Array) {
+ .items = NULL,
+ .size = 0,
+ .capacity = 0,
+ }));
+ if (table_props.maxidx != 0) {
+ cur.obj->data.array.items =
+ xcalloc(table_props.maxidx,
+ sizeof(cur.obj->data.array.items[0]));
+ cur.obj->data.array.capacity = table_props.maxidx;
+ cur.container = true;
+ kvi_push(stack, cur);
}
break;
- }
- case LUA_TTABLE: {
- const LuaTableProps table_props = nlua_traverse_table(lstate);
-
- switch (table_props.type) {
- case kObjectTypeArray: {
- *cur.obj = ARRAY_OBJ(((Array) {
- .items = NULL,
- .size = 0,
- .capacity = 0,
- }));
- if (table_props.maxidx != 0) {
- cur.obj->data.array.items =
- xcalloc(table_props.maxidx,
- sizeof(cur.obj->data.array.items[0]));
- cur.obj->data.array.capacity = table_props.maxidx;
- cur.container = true;
- kv_push(stack, cur);
- }
- break;
- }
- case kObjectTypeDictionary: {
- *cur.obj = DICTIONARY_OBJ(((Dictionary) {
- .items = NULL,
- .size = 0,
- .capacity = 0,
- }));
- if (table_props.string_keys_num != 0) {
- cur.obj->data.dictionary.items =
- xcalloc(table_props.string_keys_num,
- sizeof(cur.obj->data.dictionary.items[0]));
- cur.obj->data.dictionary.capacity = table_props.string_keys_num;
- cur.container = true;
- kv_push(stack, cur);
- lua_pushnil(lstate);
- }
- break;
- }
- case kObjectTypeFloat: {
- *cur.obj = FLOAT_OBJ((Float)table_props.val);
- break;
- }
- case kObjectTypeNil: {
- api_set_error(err, kErrorTypeValidation,
- "Cannot convert given lua table");
- break;
- }
- default: {
- abort();
- }
+ case kObjectTypeDictionary:
+ *cur.obj = DICTIONARY_OBJ(((Dictionary) {
+ .items = NULL,
+ .size = 0,
+ .capacity = 0,
+ }));
+ if (table_props.string_keys_num != 0) {
+ cur.obj->data.dictionary.items =
+ xcalloc(table_props.string_keys_num,
+ sizeof(cur.obj->data.dictionary.items[0]));
+ cur.obj->data.dictionary.capacity = table_props.string_keys_num;
+ cur.container = true;
+ kvi_push(stack, cur);
+ lua_pushnil(lstate);
}
break;
- }
-
- case LUA_TFUNCTION: {
- if (ref) {
- *cur.obj = LUAREF_OBJ(nlua_ref(lstate, -1));
- } else {
- goto type_error;
- }
+ case kObjectTypeFloat:
+ *cur.obj = FLOAT_OBJ((Float)table_props.val);
+ break;
+ case kObjectTypeNil:
+ api_set_error(err, kErrorTypeValidation,
+ "Cannot convert given lua table");
break;
+ default:
+ abort();
}
+ break;
+ }
- case LUA_TUSERDATA: {
- nlua_pushref(lstate, nlua_nil_ref);
- bool is_nil = lua_rawequal(lstate, -2, -1);
- lua_pop(lstate, 1);
- if (is_nil) {
- *cur.obj = NIL;
- } else {
- api_set_error(err, kErrorTypeValidation,
- "Cannot convert userdata");
- }
- break;
+ case LUA_TFUNCTION:
+ if (ref) {
+ *cur.obj = LUAREF_OBJ(nlua_ref(lstate, -1));
+ } else {
+ goto type_error;
}
+ break;
- default: {
-type_error:
+ case LUA_TUSERDATA: {
+ nlua_pushref(lstate, nlua_nil_ref);
+ bool is_nil = lua_rawequal(lstate, -2, -1);
+ lua_pop(lstate, 1);
+ if (is_nil) {
+ *cur.obj = NIL;
+ } else {
api_set_error(err, kErrorTypeValidation,
- "Cannot convert given lua type");
- break;
+ "Cannot convert userdata");
}
+ break;
+ }
+
+ default:
+type_error:
+ api_set_error(err, kErrorTypeValidation,
+ "Cannot convert given lua type");
+ break;
}
if (!cur.container) {
lua_pop(lstate, 1);
}
}
- kv_destroy(stack);
+ kvi_destroy(stack);
if (ERROR_SET(err)) {
api_free_object(ret);
ret = NIL;
@@ -1257,14 +1238,14 @@ LuaRef nlua_pop_LuaRef(lua_State *const lstate, Error *err)
}
#define GENERATE_INDEX_FUNCTION(type) \
-type nlua_pop_##type(lua_State *lstate, Error *err) \
+ type nlua_pop_##type(lua_State *lstate, Error *err) \
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT \
-{ \
- type ret; \
- ret = (type)lua_tonumber(lstate, -1); \
- lua_pop(lstate, 1); \
- return ret; \
-}
+ { \
+ type ret; \
+ ret = (type)lua_tonumber(lstate, -1); \
+ lua_pop(lstate, 1); \
+ return ret; \
+ }
GENERATE_INDEX_FUNCTION(Buffer)
GENERATE_INDEX_FUNCTION(Window)
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 4d4286354b..9333d781cd 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -1,58 +1,60 @@
// 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 <lauxlib.h>
#include <lua.h>
#include <lualib.h>
-#include <lauxlib.h>
-#include "nvim/assert.h"
-#include "nvim/version.h"
-#include "nvim/misc1.h"
-#include "nvim/getchar.h"
-#include "nvim/garray.h"
-#include "nvim/func_attr.h"
+#include "luv/luv.h"
+#include "mpack/lmpack.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
-#include "nvim/api/private/handle.h"
#include "nvim/api/vim.h"
-#include "nvim/msgpack_rpc/channel.h"
-#include "nvim/vim.h"
-#include "nvim/extmark.h"
-#include "nvim/ex_getln.h"
-#include "nvim/ex_cmds2.h"
-#include "nvim/map.h"
-#include "nvim/message.h"
-#include "nvim/memline.h"
-#include "nvim/buffer_defs.h"
-#include "nvim/regexp.h"
-#include "nvim/macros.h"
-#include "nvim/screen.h"
-#include "nvim/cursor.h"
-#include "nvim/undo.h"
#include "nvim/ascii.h"
+#include "nvim/assert.h"
+#include "nvim/buffer_defs.h"
#include "nvim/change.h"
+#include "nvim/cursor.h"
#include "nvim/eval/userfunc.h"
-#include "nvim/event/time.h"
#include "nvim/event/loop.h"
-
-#include "nvim/os/os.h"
-
+#include "nvim/event/time.h"
+#include "nvim/ex_cmds2.h"
+#include "nvim/ex_getln.h"
+#include "nvim/extmark.h"
+#include "nvim/func_attr.h"
+#include "nvim/garray.h"
+#include "nvim/getchar.h"
#include "nvim/lua/converter.h"
#include "nvim/lua/executor.h"
#include "nvim/lua/treesitter.h"
-
-#include "luv/luv.h"
+#include "nvim/lua/xdiff.h"
+#include "nvim/macros.h"
+#include "nvim/map.h"
+#include "nvim/memline.h"
+#include "nvim/message.h"
+#include "nvim/misc1.h"
+#include "nvim/msgpack_rpc/channel.h"
+#include "nvim/os/os.h"
+#include "nvim/regexp.h"
+#include "nvim/screen.h"
+#include "nvim/undo.h"
+#include "nvim/version.h"
+#include "nvim/vim.h"
+#include "cjson/lua_cjson.h"
static int in_fast_callback = 0;
+// Initialized in nlua_init().
+static lua_State *global_lstate = NULL;
+
typedef struct {
Error err;
String lua_err_str;
} LuaError;
#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "lua/vim_module.generated.h"
# include "lua/executor.c.generated.h"
+# include "lua/vim_module.generated.h"
#endif
#define PUSH_ALL_TYPVALS(lstate, args, argcount, special) \
@@ -65,7 +67,8 @@ typedef struct {
}
#if __has_feature(address_sanitizer)
- PMap(handle_T) *nlua_ref_markers = NULL;
+static PMap(handle_T) nlua_ref_markers = MAP_INIT;
+static bool nlua_track_refs = false;
# define NLUA_TRACK_REFS
#endif
@@ -85,7 +88,7 @@ static void nlua_error(lua_State *const lstate, const char *const msg)
lua_pop(lstate, 1);
}
-/// Return version of current neovim build
+/// Gets the version of the current Nvim build.
///
/// @param lstate Lua interpreter state.
static int nlua_nvim_version(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
@@ -144,12 +147,12 @@ static int nlua_stricmp(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
return 1;
}
-/// convert byte index to UTF-32 and UTF-16 indicies
+/// convert byte index to UTF-32 and UTF-16 indices
///
/// Expects a string and an optional index. If no index is supplied, the length
/// of the string is returned.
///
-/// Returns two values: the UTF-32 and UTF-16 indicies.
+/// Returns two values: the UTF-32 and UTF-16 indices.
static int nlua_str_utfindex(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
{
size_t s1_len;
@@ -173,7 +176,7 @@ static int nlua_str_utfindex(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
return 2;
}
-/// convert UTF-32 or UTF-16 indicies to byte index.
+/// convert UTF-32 or UTF-16 indices to byte index.
///
/// Expects up to three args: string, index and use_utf16.
/// If use_utf16 is not supplied it defaults to false (use UTF-32)
@@ -211,8 +214,7 @@ static void nlua_luv_error_event(void **argv)
xfree(error);
}
-static int nlua_luv_cfpcall(lua_State *lstate, int nargs, int nresult,
- int flags)
+static int nlua_luv_cfpcall(lua_State *lstate, int nargs, int nresult, int flags)
FUNC_ATTR_NONNULL_ALL
{
int retval;
@@ -234,7 +236,7 @@ static int nlua_luv_cfpcall(lua_State *lstate, int nargs, int nresult,
multiqueue_put(main_loop.events, nlua_luv_error_event,
1, xstrdup(error));
- lua_pop(lstate, 1); // error mesage
+ lua_pop(lstate, 1); // error message
retval = -status;
} else { // LUA_OK
if (nresult == LUA_MULTRET) {
@@ -250,7 +252,7 @@ static int nlua_luv_cfpcall(lua_State *lstate, int nargs, int nresult,
static void nlua_schedule_event(void **argv)
{
LuaRef cb = (LuaRef)(ptrdiff_t)argv[0];
- lua_State *const lstate = nlua_enter();
+ lua_State *const lstate = global_lstate;
nlua_pushref(lstate, cb);
nlua_unref(lstate, cb);
if (lua_pcall(lstate, 0, 0, 0)) {
@@ -295,8 +297,7 @@ static void dummy_timer_close_cb(TimeWatcher *tw, void *data)
xfree(tw);
}
-static bool nlua_wait_condition(lua_State *lstate, int *status,
- bool *callback_result)
+static bool nlua_wait_condition(lua_State *lstate, int *status, bool *callback_result)
{
lua_pushvalue(lstate, 2);
*status = lua_pcall(lstate, 0, 1, 0);
@@ -331,9 +332,8 @@ static int nlua_wait(lua_State *lstate)
}
if (!is_function) {
- lua_pushliteral(
- lstate,
- "vim.wait: if passed, condition must be a function");
+ lua_pushliteral(lstate,
+ "vim.wait: if passed, condition must be a function");
return lua_error(lstate);
}
}
@@ -360,23 +360,20 @@ static int nlua_wait(lua_State *lstate)
time_watcher_init(&main_loop, tw, NULL);
tw->events = loop_events;
tw->blockable = true;
- time_watcher_start(
- tw,
- dummy_timer_due_cb,
- (uint64_t)interval,
- (uint64_t)interval);
+ time_watcher_start(tw,
+ dummy_timer_due_cb,
+ (uint64_t)interval,
+ (uint64_t)interval);
int pcall_status = 0;
bool callback_result = false;
- LOOP_PROCESS_EVENTS_UNTIL(
- &main_loop,
- loop_events,
- (int)timeout,
- is_function ? nlua_wait_condition(
- lstate,
- &pcall_status,
- &callback_result) : false || got_int);
+ LOOP_PROCESS_EVENTS_UNTIL(&main_loop,
+ loop_events,
+ (int)timeout,
+ is_function ? nlua_wait_condition(lstate,
+ &pcall_status,
+ &callback_result) : false || got_int);
// Stop dummy timer
time_watcher_stop(tw);
@@ -502,6 +499,8 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
lua_setfield(lstate, -2, "__tostring");
lua_setmetatable(lstate, -2);
nlua_nil_ref = nlua_ref(lstate, -1);
+ lua_pushvalue(lstate, -1);
+ lua_setfield(lstate, LUA_REGISTRYINDEX, "mpack.NIL");
lua_setfield(lstate, -2, "NIL");
// vim._empty_dict_mt
@@ -509,11 +508,33 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
lua_pushcfunction(lstate, &nlua_empty_dict_tostring);
lua_setfield(lstate, -2, "__tostring");
nlua_empty_dict_ref = nlua_ref(lstate, -1);
+ lua_pushvalue(lstate, -1);
+ lua_setfield(lstate, LUA_REGISTRYINDEX, "mpack.empty_dict");
lua_setfield(lstate, -2, "_empty_dict_mt");
+ // vim.mpack
+ luaopen_mpack(lstate);
+ lua_pushvalue(lstate, -1);
+ lua_setfield(lstate, -3, "mpack");
+
+ // package.loaded.mpack = vim.mpack
+ // otherwise luv will be reinitialized when require'mpack'
+ lua_getglobal(lstate, "package");
+ lua_getfield(lstate, -1, "loaded");
+ lua_pushvalue(lstate, -3);
+ lua_setfield(lstate, -2, "mpack");
+ lua_pop(lstate, 3);
+
// internal vim._treesitter... API
nlua_add_treesitter(lstate);
+ // vim.diff
+ lua_pushcfunction(lstate, &nlua_xdl_diff);
+ lua_setfield(lstate, -2, "diff");
+
+ lua_cjson_new(lstate);
+ lua_setfield(lstate, -2, "json");
+
lua_setglobal(lstate, "vim");
{
@@ -536,8 +557,17 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
return 1;
}
// [package, loaded, inspect]
-
lua_setfield(lstate, -2, "vim.inspect"); // [package, loaded]
+
+ code = (char *)&lua_F_module[0];
+ if (luaL_loadbuffer(lstate, code, strlen(code), "@vim/F.lua")
+ || lua_pcall(lstate, 0, 1, 0)) {
+ nlua_error(lstate, _("E5106: Error while creating vim.F module: %.*s"));
+ return 1;
+ }
+ // [package, loaded, module]
+ lua_setfield(lstate, -2, "vim.F"); // [package, loaded]
+
lua_pop(lstate, 2); // []
}
@@ -550,22 +580,34 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
}
}
+ {
+ lua_getglobal(lstate, "package"); // [package]
+ lua_getfield(lstate, -1, "loaded"); // [package, loaded]
+
+ const char *code = (char *)&lua_meta_module[0];
+ if (luaL_loadbuffer(lstate, code, strlen(code), "@vim/_meta.lua")
+ || lua_pcall(lstate, 0, 1, 0)) {
+ nlua_error(lstate, _("E5106: Error while creating vim._meta module: %.*s"));
+ return 1;
+ }
+ // [package, loaded, module]
+ lua_setfield(lstate, -2, "vim._meta"); // [package, loaded]
+
+ lua_pop(lstate, 2); // []
+ }
+
return 0;
}
-/// Initialize lua interpreter
-///
-/// Crashes Nvim if initialization fails. Should be called once per lua
-/// interpreter instance.
+/// Initialize global lua interpreter
///
-/// @return New lua interpreter instance.
-static lua_State *nlua_init(void)
- FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT
+/// Crashes Nvim if initialization fails.
+void nlua_init(void)
{
#ifdef NLUA_TRACK_REFS
const char *env = os_getenv("NVIM_LUA_NOTRACK");
if (!env || !*env) {
- nlua_ref_markers = pmap_new(handle_T)();
+ nlua_track_refs = true;
}
#endif
@@ -577,28 +619,9 @@ static lua_State *nlua_init(void)
luaL_openlibs(lstate);
nlua_state_init(lstate);
- return lstate;
+ global_lstate = lstate;
}
-// only to be used by nlua_enter and nlua_free_all_mem!
-static lua_State *global_lstate = NULL;
-
-/// Enter lua interpreter
-///
-/// Calls nlua_init() if needed. Is responsible for pre-lua call initalization
-/// like updating `package.[c]path` with directories derived from &runtimepath.
-///
-/// @return Interpreter instance to use. Will either be initialized now or
-/// taken from previous initialization.
-static lua_State *nlua_enter(void)
- FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT
-{
- if (global_lstate == NULL) {
- global_lstate = nlua_init();
- }
- lua_State *const lstate = global_lstate;
- return lstate;
-}
void nlua_free_all_mem(void)
{
@@ -615,10 +638,10 @@ void nlua_free_all_mem(void)
fprintf(stderr, "%d lua references were leaked!", nlua_refcount);
}
- if (nlua_ref_markers) {
+ if (nlua_track_refs) {
// in case there are leaked luarefs, leak the associated memory
// to get LeakSanitizer stacktraces on exit
- pmap_free(handle_T)(nlua_ref_markers);
+ pmap_destroy(handle_T)(&nlua_ref_markers);
}
#endif
@@ -635,22 +658,19 @@ static void nlua_print_event(void **argv)
const size_t start = i;
while (i < len) {
switch (str[i]) {
- case NUL: {
- str[i] = NL;
- i++;
- continue;
- }
- case NL: {
- // TODO(bfredl): use proper multiline msg? Probably should implement
- // print() in lua in terms of nvim_message(), when it is available.
- str[i] = NUL;
- i++;
- break;
- }
- default: {
- i++;
- continue;
- }
+ case NUL:
+ str[i] = NL;
+ i++;
+ continue;
+ case NL:
+ // TODO(bfredl): use proper multiline msg? Probably should implement
+ // print() in lua in terms of nvim_message(), when it is available.
+ str[i] = NUL;
+ i++;
+ break;
+ default:
+ i++;
+ continue;
}
break;
}
@@ -691,8 +711,7 @@ static int nlua_print(lua_State *const lstate)
size_t len;
const char *const s = lua_tolstring(lstate, -1, &len);
if (s == NULL) {
- PRINT_ERROR(
- "<Unknown error: lua_tolstring returned NULL for tostring result>");
+ PRINT_ERROR("<Unknown error: lua_tolstring returned NULL for tostring result>");
}
ga_concat_len(&msg_ga, s, len);
if (curargidx < nargs) {
@@ -800,13 +819,13 @@ int nlua_call(lua_State *lstate)
try_start();
typval_T rettv;
- int dummy;
+ funcexe_T funcexe = FUNCEXE_INIT;
+ funcexe.firstline = curwin->w_cursor.lnum;
+ funcexe.lastline = curwin->w_cursor.lnum;
+ funcexe.evaluate = true;
// call_func() retval is deceptive, ignore it. Instead we set `msg_list`
// (TRY_WRAP) to capture abort-causing non-exception errors.
- (void)call_func(name, (int)name_len, &rettv, nargs,
- vim_args, NULL,
- curwin->w_cursor.lnum, curwin->w_cursor.lnum,
- &dummy, true, NULL, NULL);
+ (void)call_func(name, (int)name_len, &rettv, nargs, vim_args, &funcexe);
if (!try_end(&err)) {
nlua_push_typval(lstate, &rettv, false);
}
@@ -865,7 +884,7 @@ static int nlua_rpc(lua_State *lstate, bool request)
} else {
if (!rpc_send_event(chan_id, name, args)) {
api_set_error(&err, kErrorTypeValidation,
- "Invalid channel: %"PRIu64, chan_id);
+ "Invalid channel: %" PRIu64, chan_id);
}
}
@@ -1017,10 +1036,10 @@ LuaRef nlua_ref(lua_State *lstate, int index)
if (ref > 0) {
nlua_refcount++;
#ifdef NLUA_TRACK_REFS
- if (nlua_ref_markers) {
- // dummy allocation to make LeakSanitizer track our luarefs
- pmap_put(handle_T)(nlua_ref_markers, ref, xmalloc(3));
- }
+ if (nlua_track_refs) {
+ // dummy allocation to make LeakSanitizer track our luarefs
+ pmap_put(handle_T)(&nlua_ref_markers, ref, xmalloc(3));
+ }
#endif
}
return ref;
@@ -1033,8 +1052,8 @@ void nlua_unref(lua_State *lstate, LuaRef ref)
nlua_refcount--;
#ifdef NLUA_TRACK_REFS
// NB: don't remove entry from map to track double-unref
- if (nlua_ref_markers) {
- xfree(pmap_get(handle_T)(nlua_ref_markers, ref));
+ if (nlua_track_refs) {
+ xfree(pmap_get(handle_T)(&nlua_ref_markers, ref));
}
#endif
luaL_unref(lstate, LUA_REGISTRYINDEX, ref);
@@ -1043,8 +1062,7 @@ void nlua_unref(lua_State *lstate, LuaRef ref)
void api_free_luaref(LuaRef ref)
{
- lua_State *const lstate = nlua_enter();
- nlua_unref(lstate, ref);
+ nlua_unref(global_lstate, ref);
}
/// push a value referenced in the registry
@@ -1064,7 +1082,7 @@ LuaRef api_new_luaref(LuaRef original_ref)
return LUA_NOREF;
}
- lua_State *const lstate = nlua_enter();
+ lua_State *const lstate = global_lstate;
nlua_pushref(lstate, original_ref);
LuaRef new_ref = nlua_ref(lstate, -1);
lua_pop(lstate, 1);
@@ -1081,8 +1099,7 @@ LuaRef api_new_luaref(LuaRef original_ref)
/// @param[out] ret_tv Location where result will be saved.
///
/// @return Result of the execution.
-void nlua_typval_eval(const String str, typval_T *const arg,
- typval_T *const ret_tv)
+void nlua_typval_eval(const String str, typval_T *const arg, typval_T *const ret_tv)
FUNC_ATTR_NONNULL_ALL
{
#define EVALHEADER "local _A=select(1,...) return ("
@@ -1104,8 +1121,8 @@ void nlua_typval_eval(const String str, typval_T *const arg,
}
}
-void nlua_typval_call(const char *str, size_t len, typval_T *const args,
- int argcount, typval_T *ret_tv)
+void nlua_typval_call(const char *str, size_t len, typval_T *const args, int argcount,
+ typval_T *ret_tv)
FUNC_ATTR_NONNULL_ALL
{
#define CALLHEADER "return "
@@ -1131,9 +1148,8 @@ void nlua_typval_call(const char *str, size_t len, typval_T *const args,
}
}
-static void nlua_typval_exec(const char *lcmd, size_t lcmd_len,
- const char *name, typval_T *const args,
- int argcount, bool special, typval_T *ret_tv)
+static void nlua_typval_exec(const char *lcmd, size_t lcmd_len, const char *name,
+ typval_T *const args, int argcount, bool special, typval_T *ret_tv)
{
if (check_secure()) {
if (ret_tv) {
@@ -1143,7 +1159,7 @@ static void nlua_typval_exec(const char *lcmd, size_t lcmd_len,
return;
}
- lua_State *const lstate = nlua_enter();
+ lua_State *const lstate = global_lstate;
if (luaL_loadbuffer(lstate, lcmd, lcmd_len, name)) {
nlua_error(lstate, _("E5107: Error loading lua %.*s"));
return;
@@ -1161,8 +1177,7 @@ static void nlua_typval_exec(const char *lcmd, size_t lcmd_len,
}
}
-int nlua_source_using_linegetter(LineGetter fgetline,
- void *cookie, char *name)
+int nlua_source_using_linegetter(LineGetter fgetline, void *cookie, char *name)
{
const linenr_T save_sourcing_lnum = sourcing_lnum;
const sctx_T save_current_sctx = current_sctx;
@@ -1198,13 +1213,8 @@ int nlua_source_using_linegetter(LineGetter fgetline,
/// @param[in] argcount Count of typval arguments
/// @param[in] argvars Typval Arguments
/// @param[out] rettv The return value from the called function.
-int typval_exec_lua_callable(
- lua_State *lstate,
- LuaCallable lua_cb,
- int argcount,
- typval_T *argvars,
- typval_T *rettv
-)
+int typval_exec_lua_callable(lua_State *lstate, LuaCallable lua_cb, int argcount, typval_T *argvars,
+ typval_T *rettv)
{
LuaRef cb = lua_cb.func_ref;
@@ -1233,7 +1243,7 @@ int typval_exec_lua_callable(
/// @return Return value of the execution.
Object nlua_exec(const String str, const Array args, Error *err)
{
- lua_State *const lstate = nlua_enter();
+ lua_State *const lstate = global_lstate;
if (luaL_loadbuffer(lstate, str.data, str.size, "<nvim>")) {
size_t len;
@@ -1267,10 +1277,9 @@ Object nlua_exec(const String str, const Array args, Error *err)
/// if false, discard return value
/// @param err Error details, if any (if NULL, errors are echoed)
/// @return Return value of function, if retval was set. Otherwise NIL.
-Object nlua_call_ref(LuaRef ref, const char *name, Array args,
- bool retval, Error *err)
+Object nlua_call_ref(LuaRef ref, const char *name, Array args, bool retval, Error *err)
{
- lua_State *const lstate = nlua_enter();
+ lua_State *const lstate = global_lstate;
nlua_pushref(lstate, ref);
int nargs = (int)args.size;
if (name != NULL) {
@@ -1346,7 +1355,7 @@ void ex_luado(exarg_T *const eap)
const char *const cmd = (const char *)eap->arg;
const size_t cmd_len = strlen(cmd);
- lua_State *const lstate = nlua_enter();
+ lua_State *const lstate = global_lstate;
#define DOSTART "return function(line, linenr) "
#define DOEND " end"
@@ -1431,7 +1440,7 @@ void ex_luafile(exarg_T *const eap)
bool nlua_exec_file(const char *path)
FUNC_ATTR_NONNULL_ALL
{
- lua_State *const lstate = nlua_enter();
+ lua_State *const lstate = global_lstate;
if (luaL_loadfile(lstate, path)) {
nlua_error(lstate, _("E5112: Error while creating lua chunk: %.*s"));
@@ -1475,12 +1484,9 @@ static void nlua_add_treesitter(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
lua_setfield(lstate, -2, "_ts_get_language_version");
}
-int nlua_expand_pat(expand_T *xp,
- char_u *pat,
- int *num_results,
- char_u ***results)
+int nlua_expand_pat(expand_T *xp, char_u *pat, int *num_results, char_u ***results)
{
- lua_State *const lstate = nlua_enter();
+ lua_State *const lstate = global_lstate;
int ret = OK;
// [ vim ]
@@ -1490,13 +1496,12 @@ int nlua_expand_pat(expand_T *xp,
lua_getfield(lstate, -1, "_expand_pat");
luaL_checktype(lstate, -1, LUA_TFUNCTION);
- // [ vim, vim._log_keystroke, buf ]
+ // [ vim, vim._on_key, buf ]
lua_pushlstring(lstate, (const char *)pat, STRLEN(pat));
if (lua_pcall(lstate, 1, 2, 0) != 0) {
- nlua_error(
- lstate,
- _("Error executing vim._expand_pat: %.*s"));
+ nlua_error(lstate,
+ _("Error executing vim._expand_pat: %.*s"));
return FAIL;
}
@@ -1527,10 +1532,9 @@ int nlua_expand_pat(expand_T *xp,
goto cleanup_array;
}
- GA_APPEND(
- char_u *,
- &result_array,
- vim_strsave((char_u *)v.data.string.data));
+ GA_APPEND(char_u *,
+ &result_array,
+ vim_strsave((char_u *)v.data.string.data));
}
xp->xp_pattern += prefix_len;
@@ -1684,26 +1688,22 @@ static int regex_match_line(lua_State *lstate)
// Required functions for lua c functions as VimL callbacks
-int nlua_CFunction_func_call(
- int argcount,
- typval_T *argvars,
- typval_T *rettv,
- void *state)
+int nlua_CFunction_func_call(int argcount, typval_T *argvars, typval_T *rettv, void *state)
{
- lua_State *const lstate = nlua_enter();
- LuaCFunctionState *funcstate = (LuaCFunctionState *)state;
+ lua_State *const lstate = global_lstate;
+ LuaCFunctionState *funcstate = (LuaCFunctionState *)state;
- return typval_exec_lua_callable(lstate, funcstate->lua_callable,
- argcount, argvars, rettv);
+ return typval_exec_lua_callable(lstate, funcstate->lua_callable,
+ argcount, argvars, rettv);
}
void nlua_CFunction_func_free(void *state)
{
- lua_State *const lstate = nlua_enter();
- LuaCFunctionState *funcstate = (LuaCFunctionState *)state;
+ lua_State *const lstate = global_lstate;
+ LuaCFunctionState *funcstate = (LuaCFunctionState *)state;
- nlua_unref(lstate, funcstate->lua_callable.func_ref);
- xfree(funcstate);
+ nlua_unref(lstate, funcstate->lua_callable.func_ref);
+ xfree(funcstate);
}
bool nlua_is_table_from_lua(typval_T *const arg)
@@ -1730,7 +1730,7 @@ char_u *nlua_register_table_as_callable(typval_T *const arg)
return NULL;
}
- lua_State *const lstate = nlua_enter();
+ lua_State *const lstate = global_lstate;
#ifndef NDEBUG
int top = lua_gettop(lstate);
@@ -1764,12 +1764,12 @@ char_u *nlua_register_table_as_callable(typval_T *const arg)
return name;
}
-void nlua_execute_log_keystroke(int c)
+void nlua_execute_on_key(int c)
{
char_u buf[NUMBUFLEN];
size_t buf_len = special_to_buf(c, mod_mask, false, buf);
- lua_State *const lstate = nlua_enter();
+ lua_State *const lstate = global_lstate;
#ifndef NDEBUG
int top = lua_gettop(lstate);
@@ -1778,17 +1778,16 @@ void nlua_execute_log_keystroke(int c)
// [ vim ]
lua_getglobal(lstate, "vim");
- // [ vim, vim._log_keystroke ]
- lua_getfield(lstate, -1, "_log_keystroke");
+ // [ vim, vim._on_key]
+ lua_getfield(lstate, -1, "_on_key");
luaL_checktype(lstate, -1, LUA_TFUNCTION);
- // [ vim, vim._log_keystroke, buf ]
+ // [ vim, vim._on_key, buf ]
lua_pushlstring(lstate, (const char *)buf, buf_len);
if (lua_pcall(lstate, 1, 0, 0)) {
- nlua_error(
- lstate,
- _("Error executing vim.log_keystroke lua callback: %.*s"));
+ nlua_error(lstate,
+ _("Error executing vim.on_key Lua callback: %.*s"));
}
// [ vim ]
diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c
index e3fa48f530..37929093e3 100644
--- a/src/nvim/lua/treesitter.c
+++ b/src/nvim/lua/treesitter.c
@@ -5,22 +5,20 @@
// NB: this file mostly contains a generic lua interface for tree-sitter
// trees and nodes, and could be broken out as a reusable lua package
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <inttypes.h>
#include <assert.h>
-
+#include <inttypes.h>
+#include <lauxlib.h>
#include <lua.h>
#include <lualib.h>
-#include <lauxlib.h>
-
-#include "tree_sitter/api.h"
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include "nvim/api/private/helpers.h"
+#include "nvim/buffer.h"
#include "nvim/lua/treesitter.h"
-#include "nvim/api/private/handle.h"
#include "nvim/memline.h"
-#include "nvim/buffer.h"
+#include "tree_sitter/api.h"
#define TS_META_PARSER "treesitter_parser"
#define TS_META_TREE "treesitter_tree"
@@ -80,6 +78,10 @@ static struct luaL_Reg node_meta[] = {
{ "parent", node_parent },
{ "iter_children", node_iter_children },
{ "_rawquery", node_rawquery },
+ { "next_sibling", node_next_sibling },
+ { "prev_sibling", node_prev_sibling },
+ { "next_named_sibling", node_next_named_sibling },
+ { "prev_named_sibling", node_prev_named_sibling },
{ NULL, NULL }
};
@@ -101,7 +103,7 @@ static struct luaL_Reg treecursor_meta[] = {
{ NULL, NULL }
};
-static PMap(cstr_t) *langs;
+static PMap(cstr_t) langs = MAP_INIT;
static void build_meta(lua_State *L, const char *tname, const luaL_Reg *meta)
{
@@ -119,8 +121,6 @@ static void build_meta(lua_State *L, const char *tname, const luaL_Reg *meta)
/// all global state is stored in the regirstry of the lua_State
void tslua_init(lua_State *L)
{
- langs = pmap_new(cstr_t)();
-
// type metatables
build_meta(L, TS_META_PARSER, parser_meta);
build_meta(L, TS_META_TREE, tree_meta);
@@ -133,7 +133,7 @@ void tslua_init(lua_State *L)
int tslua_has_language(lua_State *L)
{
const char *lang_name = luaL_checkstring(L, 1);
- lua_pushboolean(L, pmap_has(cstr_t)(langs, lang_name));
+ lua_pushboolean(L, pmap_has(cstr_t)(&langs, lang_name));
return 1;
}
@@ -142,7 +142,7 @@ int tslua_add_language(lua_State *L)
const char *path = luaL_checkstring(L, 1);
const char *lang_name = luaL_checkstring(L, 2);
- if (pmap_has(cstr_t)(langs, lang_name)) {
+ if (pmap_has(cstr_t)(&langs, lang_name)) {
return 0;
}
@@ -177,15 +177,14 @@ int tslua_add_language(lua_State *L)
uint32_t lang_version = ts_language_version(lang);
if (lang_version < TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION
|| lang_version > TREE_SITTER_LANGUAGE_VERSION) {
- return luaL_error(
- L,
- "ABI version mismatch for %s: supported between %d and %d, found %d",
- path,
- TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION,
- TREE_SITTER_LANGUAGE_VERSION, lang_version);
+ return luaL_error(L,
+ "ABI version mismatch for %s: supported between %d and %d, found %d",
+ path,
+ TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION,
+ TREE_SITTER_LANGUAGE_VERSION, lang_version);
}
- pmap_put(cstr_t)(langs, xstrdup(lang_name), lang);
+ pmap_put(cstr_t)(&langs, xstrdup(lang_name), lang);
lua_pushboolean(L, true);
return 1;
@@ -195,7 +194,7 @@ int tslua_inspect_lang(lua_State *L)
{
const char *lang_name = luaL_checkstring(L, 1);
- TSLanguage *lang = pmap_get(cstr_t)(langs, lang_name);
+ TSLanguage *lang = pmap_get(cstr_t)(&langs, lang_name);
if (!lang) {
return luaL_error(L, "no such language: %s", lang_name);
}
@@ -243,7 +242,7 @@ int tslua_push_parser(lua_State *L)
// Gather language name
const char *lang_name = luaL_checkstring(L, 1);
- TSLanguage *lang = pmap_get(cstr_t)(langs, lang_name);
+ TSLanguage *lang = pmap_get(cstr_t)(&langs, lang_name);
if (!lang) {
return luaL_error(L, "no such language: %s", lang_name);
}
@@ -261,7 +260,7 @@ int tslua_push_parser(lua_State *L)
return 1;
}
-static TSParser ** parser_check(lua_State *L, uint16_t index)
+static TSParser **parser_check(lua_State *L, uint16_t index)
{
return luaL_checkudata(L, index, TS_META_PARSER);
}
@@ -283,8 +282,8 @@ static int parser_tostring(lua_State *L)
return 1;
}
-static const char *input_cb(void *payload, uint32_t byte_index,
- TSPoint position, uint32_t *bytes_read)
+static const char *input_cb(void *payload, uint32_t byte_index, TSPoint position,
+ uint32_t *bytes_read)
{
buf_T *bp = payload;
#define BUFSIZE 256
@@ -316,9 +315,7 @@ static const char *input_cb(void *payload, uint32_t byte_index,
#undef BUFSIZE
}
-static void push_ranges(lua_State *L,
- const TSRange *ranges,
- const unsigned int length)
+static void push_ranges(lua_State *L, const TSRange *ranges, const unsigned int length)
{
lua_createtable(L, length, 0);
for (size_t i = 0; i < length; i++) {
@@ -359,40 +356,39 @@ static int parser_parse(lua_State *L)
// This switch is necessary because of the behavior of lua_isstring, that
// consider numbers as strings...
switch (lua_type(L, 3)) {
- case LUA_TSTRING:
- str = lua_tolstring(L, 3, &len);
- new_tree = ts_parser_parse_string(*p, old_tree, str, len);
- break;
+ case LUA_TSTRING:
+ str = lua_tolstring(L, 3, &len);
+ new_tree = ts_parser_parse_string(*p, old_tree, str, len);
+ break;
- case LUA_TNUMBER:
- bufnr = lua_tointeger(L, 3);
- buf = handle_get_buffer(bufnr);
+ case LUA_TNUMBER:
+ bufnr = lua_tointeger(L, 3);
+ buf = handle_get_buffer(bufnr);
- if (!buf) {
- return luaL_error(L, "invalid buffer handle: %d", bufnr);
- }
+ if (!buf) {
+ return luaL_error(L, "invalid buffer handle: %d", bufnr);
+ }
- input = (TSInput){ (void *)buf, input_cb, TSInputEncodingUTF8 };
- new_tree = ts_parser_parse(*p, old_tree, input);
+ input = (TSInput){ (void *)buf, input_cb, TSInputEncodingUTF8 };
+ new_tree = ts_parser_parse(*p, old_tree, input);
- break;
+ break;
- default:
- return luaL_error(L, "invalid argument to parser:parse()");
+ default:
+ return luaL_error(L, "invalid argument to parser:parse()");
}
// Sometimes parsing fails (timeout, or wrong parser ABI)
// In those case, just return an error.
if (!new_tree) {
- return luaL_error(L, "An error occured when parsing.");
+ return luaL_error(L, "An error occurred when parsing.");
}
// The new tree will be pushed to the stack, without copy, owwership is now to
// the lua GC.
// Old tree is still owned by the lua GC.
uint32_t n_ranges = 0;
- TSRange *changed = old_tree ? ts_tree_get_changed_ranges(
- old_tree, new_tree, &n_ranges) : NULL;
+ TSRange *changed = old_tree ? ts_tree_get_changed_ranges(old_tree, new_tree, &n_ranges) : NULL;
push_tree(L, new_tree, false); // [tree]
@@ -502,17 +498,15 @@ static void range_from_lua(lua_State *L, TSRange *range)
}
return;
error:
- luaL_error(
- L,
- "Ranges can only be made from 6 element long tables or nodes.");
+ luaL_error(L,
+ "Ranges can only be made from 6 element long tables or nodes.");
}
static int parser_set_ranges(lua_State *L)
{
if (lua_gettop(L) < 2) {
- return luaL_error(
- L,
- "not enough args to parser:set_included_ranges()");
+ return luaL_error(L,
+ "not enough args to parser:set_included_ranges()");
}
TSParser **p = parser_check(L, 1);
@@ -521,9 +515,8 @@ static int parser_set_ranges(lua_State *L)
}
if (!lua_istable(L, 2)) {
- return luaL_error(
- L,
- "argument for parser:set_included_ranges() should be a table.");
+ return luaL_error(L,
+ "argument for parser:set_included_ranges() should be a table.");
}
size_t tbl_len = lua_objlen(L, 2);
@@ -888,9 +881,9 @@ static int node_descendant_for_range(lua_State *L)
return 0;
}
TSPoint start = { (uint32_t)lua_tointeger(L, 2),
- (uint32_t)lua_tointeger(L, 3) };
+ (uint32_t)lua_tointeger(L, 3) };
TSPoint end = { (uint32_t)lua_tointeger(L, 4),
- (uint32_t)lua_tointeger(L, 5) };
+ (uint32_t)lua_tointeger(L, 5) };
TSNode child = ts_node_descendant_for_point_range(node, start, end);
push_node(L, child, 1);
@@ -904,9 +897,9 @@ static int node_named_descendant_for_range(lua_State *L)
return 0;
}
TSPoint start = { (uint32_t)lua_tointeger(L, 2),
- (uint32_t)lua_tointeger(L, 3) };
+ (uint32_t)lua_tointeger(L, 3) };
TSPoint end = { (uint32_t)lua_tointeger(L, 4),
- (uint32_t)lua_tointeger(L, 5) };
+ (uint32_t)lua_tointeger(L, 5) };
TSNode child = ts_node_named_descendant_for_point_range(node, start, end);
push_node(L, child, 1);
@@ -915,8 +908,7 @@ static int node_named_descendant_for_range(lua_State *L)
static int node_next_child(lua_State *L)
{
- TSTreeCursor *ud = luaL_checkudata(
- L, lua_upvalueindex(1), TS_META_TREECURSOR);
+ TSTreeCursor *ud = luaL_checkudata(L, lua_upvalueindex(1), TS_META_TREECURSOR);
if (!ud) {
return 0;
}
@@ -937,19 +929,18 @@ static int node_next_child(lua_State *L)
if (ts_tree_cursor_goto_next_sibling(ud)) {
push:
- push_node(
- L,
- ts_tree_cursor_current_node(ud),
- lua_upvalueindex(2)); // [node]
+ push_node(L,
+ ts_tree_cursor_current_node(ud),
+ lua_upvalueindex(2)); // [node]
- const char * field = ts_tree_cursor_current_field_name(ud);
+ const char * field = ts_tree_cursor_current_field_name(ud);
- if (field != NULL) {
- lua_pushstring(L, ts_tree_cursor_current_field_name(ud));
- } else {
- lua_pushnil(L);
- } // [node, field_name_or_nil]
- return 2;
+ if (field != NULL) {
+ lua_pushstring(L, ts_tree_cursor_current_field_name(ud));
+ } else {
+ lua_pushnil(L);
+ } // [node, field_name_or_nil]
+ return 2;
}
end:
@@ -992,6 +983,50 @@ static int node_parent(lua_State *L)
return 1;
}
+static int node_next_sibling(lua_State *L)
+{
+ TSNode node;
+ if (!node_check(L, 1, &node)) {
+ return 0;
+ }
+ TSNode sibling = ts_node_next_sibling(node);
+ push_node(L, sibling, 1);
+ return 1;
+}
+
+static int node_prev_sibling(lua_State *L)
+{
+ TSNode node;
+ if (!node_check(L, 1, &node)) {
+ return 0;
+ }
+ TSNode sibling = ts_node_prev_sibling(node);
+ push_node(L, sibling, 1);
+ return 1;
+}
+
+static int node_next_named_sibling(lua_State *L)
+{
+ TSNode node;
+ if (!node_check(L, 1, &node)) {
+ return 0;
+ }
+ TSNode sibling = ts_node_next_named_sibling(node);
+ push_node(L, sibling, 1);
+ return 1;
+}
+
+static int node_prev_named_sibling(lua_State *L)
+{
+ TSNode node;
+ if (!node_check(L, 1, &node)) {
+ return 0;
+ }
+ TSNode sibling = ts_node_prev_named_sibling(node);
+ push_node(L, sibling, 1);
+ return 1;
+}
+
/// assumes the match table being on top of the stack
static void set_match(lua_State *L, TSQueryMatch *match, int nodeidx)
{
@@ -1127,7 +1162,7 @@ int tslua_parse_query(lua_State *L)
}
const char *lang_name = lua_tostring(L, 1);
- TSLanguage *lang = pmap_get(cstr_t)(langs, lang_name);
+ TSLanguage *lang = pmap_get(cstr_t)(&langs, lang_name);
if (!lang) {
return luaL_error(L, "no such language: %s", lang_name);
}
@@ -1154,11 +1189,16 @@ int tslua_parse_query(lua_State *L)
static const char *query_err_string(TSQueryError err) {
switch (err) {
- case TSQueryErrorSyntax: return "invalid syntax";
- case TSQueryErrorNodeType: return "invalid node type";
- case TSQueryErrorField: return "invalid field";
- case TSQueryErrorCapture: return "invalid capture";
- default: return "error";
+ case TSQueryErrorSyntax:
+ return "invalid syntax";
+ case TSQueryErrorNodeType:
+ return "invalid node type";
+ case TSQueryErrorField:
+ return "invalid field";
+ case TSQueryErrorCapture:
+ return "invalid capture";
+ default:
+ return "error";
}
}
diff --git a/src/nvim/lua/vim.lua b/src/nvim/lua/vim.lua
index 8cecaa51dd..7a209f2d79 100644
--- a/src/nvim/lua/vim.lua
+++ b/src/nvim/lua/vim.lua
@@ -4,6 +4,7 @@
-- 1. runtime/lua/vim/ (the runtime): For "nice to have" features, e.g. the
-- `inspect` and `lpeg` modules.
-- 2. runtime/lua/vim/shared.lua: Code shared between Nvim and tests.
+-- (This will go away if we migrate to nvim as the test-runner.)
-- 3. src/nvim/lua/: Compiled-into Nvim itself.
--
-- Guideline: "If in doubt, put it in the runtime".
@@ -104,6 +105,12 @@ setmetatable(vim, {
elseif key == 'highlight' then
t.highlight = require('vim.highlight')
return t.highlight
+ elseif key == 'diagnostic' then
+ t.diagnostic = require('vim.diagnostic')
+ return t.diagnostic
+ elseif key == 'ui' then
+ t.ui = require('vim.ui')
+ return t.ui
end
end
})
@@ -178,8 +185,8 @@ end
--- Return a human-readable representation of the given object.
---
---@see https://github.com/kikito/inspect.lua
---@see https://github.com/mpeterv/vinspect
+---@see https://github.com/kikito/inspect.lua
+---@see https://github.com/mpeterv/vinspect
local function inspect(object, options) -- luacheck: no unused
error(object, options) -- Stub for gen_vimdoc.py
end
@@ -203,15 +210,15 @@ do
--- end)(vim.paste)
--- </pre>
---
- --@see |paste|
+ ---@see |paste|
---
- --@param lines |readfile()|-style list of lines to paste. |channel-lines|
- --@param phase -1: "non-streaming" paste: the call contains all lines.
+ ---@param lines |readfile()|-style list of lines to paste. |channel-lines|
+ ---@param phase -1: "non-streaming" paste: the call contains all lines.
--- If paste is "streamed", `phase` indicates the stream state:
--- - 1: starts the paste (exactly once)
--- - 2: continues the paste (zero or more times)
--- - 3: ends the paste (exactly once)
- --@returns false if client should cancel the paste.
+ ---@returns false if client should cancel the paste.
function vim.paste(lines, phase)
local call = vim.api.nvim_call_function
local now = vim.loop.now()
@@ -273,13 +280,13 @@ end
---@see |vim.in_fast_event()|
function vim.schedule_wrap(cb)
return (function (...)
- local args = {...}
- vim.schedule(function() cb(unpack(args)) end)
+ local args = vim.F.pack_len(...)
+ vim.schedule(function() cb(vim.F.unpack_len(args)) end)
end)
end
--- <Docs described in |vim.empty_dict()| >
---@private
+---@private
function vim.empty_dict()
return setmetatable({}, vim._empty_dict_mt)
end
@@ -338,12 +345,12 @@ end
--- Get a table of lines with start, end columns for a region marked by two points
---
---@param bufnr number of buffer
---@param pos1 (line, column) tuple marking beginning of region
---@param pos2 (line, column) tuple marking end of region
---@param regtype type of selection (:help setreg)
---@param inclusive boolean indicating whether the selection is end-inclusive
---@return region lua table of the form {linenr = {startcol,endcol}}
+---@param bufnr number of buffer
+---@param pos1 (line, column) tuple marking beginning of region
+---@param pos2 (line, column) tuple marking end of region
+---@param regtype type of selection (:help setreg)
+---@param inclusive boolean indicating whether the selection is end-inclusive
+---@return region lua table of the form {linenr = {startcol,endcol}}
function vim.region(bufnr, pos1, pos2, regtype, inclusive)
if not vim.api.nvim_buf_is_loaded(bufnr) then
vim.fn.bufload(bufnr)
@@ -390,9 +397,9 @@ end
--- Use to do a one-shot timer that calls `fn`
--- Note: The {fn} is |schedule_wrap|ped automatically, so API functions are
--- safe to call.
---@param fn Callback to call once `timeout` expires
---@param timeout Number of milliseconds to wait before calling `fn`
---@return timer luv timer object
+---@param fn Callback to call once `timeout` expires
+---@param timeout Number of milliseconds to wait before calling `fn`
+---@return timer luv timer object
function vim.defer_fn(fn, timeout)
vim.validate { fn = { fn, 'c', true}; }
local timer = vim.loop.new_timer()
@@ -408,11 +415,12 @@ end
--- Notification provider
---- without a runtime, writes to :Messages
--- see :help nvim_notify
---@param msg Content of the notification to show to the user
---@param log_level Optional log level
---@param opts Dictionary with optional options (timeout, etc)
+---
+--- Without a runtime, writes to :Messages
+---@see :help nvim_notify
+---@param msg Content of the notification to show to the user
+---@param log_level Optional log level
+---@param opts Dictionary with optional options (timeout, etc)
function vim.notify(msg, log_level, _opts)
if log_level == vim.log.levels.ERROR then
@@ -425,26 +433,35 @@ function vim.notify(msg, log_level, _opts)
end
-local on_keystroke_callbacks = {}
+function vim.register_keystroke_callback()
+ error('vim.register_keystroke_callback is deprecated, instead use: vim.on_key')
+end
+
+local on_key_cbs = {}
---- Register a lua {fn} with an {id} to be run after every keystroke.
+--- Adds Lua function {fn} with namespace id {ns_id} as a listener to every,
+--- yes every, input key.
---
---@param fn function: Function to call. It should take one argument, which is a string.
---- The string will contain the literal keys typed.
---- See |i_CTRL-V|
+--- The Nvim command-line option |-w| is related but does not support callbacks
+--- and cannot be toggled dynamically.
---
+---@param fn function: Callback function. It should take one string argument.
+--- On each key press, Nvim passes the key char to fn(). |i_CTRL-V|
--- If {fn} is nil, it removes the callback for the associated {ns_id}
---@param ns_id number? Namespace ID. If not passed or 0, will generate and return a new
---- namespace ID from |nvim_create_namesapce()|
+---@param ns_id number? Namespace ID. If nil or 0, generates and returns a new
+--- |nvim_create_namesapce()| id.
---
---@return number Namespace ID associated with {fn}
+---@return number Namespace id associated with {fn}. Or count of all callbacks
+---if on_key() is called without arguments.
---
---@note {fn} will be automatically removed if an error occurs while calling.
---- This is to prevent the annoying situation of every keystroke erroring
---- while trying to remove a broken callback.
---@note {fn} will not be cleared from |nvim_buf_clear_namespace()|
---@note {fn} will receive the keystrokes after mappings have been evaluated
-function vim.register_keystroke_callback(fn, ns_id)
+---@note {fn} will be removed if an error occurs while calling.
+---@note {fn} will not be cleared by |nvim_buf_clear_namespace()|
+---@note {fn} will receive the keys after mappings have been evaluated
+function vim.on_key(fn, ns_id)
+ if fn == nil and ns_id == nil then
+ return #on_key_cbs
+ end
+
vim.validate {
fn = { fn, 'c', true},
ns_id = { ns_id, 'n', true }
@@ -454,20 +471,19 @@ function vim.register_keystroke_callback(fn, ns_id)
ns_id = vim.api.nvim_create_namespace('')
end
- on_keystroke_callbacks[ns_id] = fn
+ on_key_cbs[ns_id] = fn
return ns_id
end
---- Function that executes the keystroke callbacks.
---@private
-function vim._log_keystroke(char)
+--- Executes the on_key callbacks.
+---@private
+function vim._on_key(char)
local failed_ns_ids = {}
local failed_messages = {}
- for k, v in pairs(on_keystroke_callbacks) do
+ for k, v in pairs(on_key_cbs) do
local ok, err_msg = pcall(v, char)
if not ok then
- vim.register_keystroke_callback(nil, k)
-
+ vim.on_key(nil, k)
table.insert(failed_ns_ids, k)
table.insert(failed_messages, err_msg)
end
@@ -475,7 +491,7 @@ function vim._log_keystroke(char)
if failed_ns_ids[1] then
error(string.format(
- "Error executing 'on_keystroke' with ns_ids of '%s'\n With messages: %s",
+ "Error executing 'on_key' with ns_ids '%s'\n Messages: %s",
table.concat(failed_ns_ids, ", "),
table.concat(failed_messages, "\n")))
end
@@ -641,6 +657,4 @@ vim._expand_pat_get_parts = function(lua_string)
return parts, search_index
end
-pcall(require, 'vim._meta')
-
return module
diff --git a/src/nvim/lua/xdiff.c b/src/nvim/lua/xdiff.c
new file mode 100644
index 0000000000..3955fbe72c
--- /dev/null
+++ b/src/nvim/lua/xdiff.c
@@ -0,0 +1,332 @@
+// 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 <errno.h>
+#include <lauxlib.h>
+#include <lua.h>
+#include <lualib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "nvim/api/private/helpers.h"
+#include "nvim/lua/converter.h"
+#include "nvim/lua/executor.h"
+#include "nvim/lua/xdiff.h"
+#include "nvim/vim.h"
+#include "xdiff/xdiff.h"
+
+typedef enum {
+ kNluaXdiffModeUnified = 0,
+ kNluaXdiffModeOnHunkCB,
+ kNluaXdiffModeLocations,
+} NluaXdiffMode;
+
+typedef struct {
+ lua_State *lstate;
+ Error *err;
+} hunkpriv_t;
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "lua/xdiff.c.generated.h"
+#endif
+
+static int write_string(void *priv, mmbuffer_t *mb, int nbuf)
+{
+ luaL_Buffer *buf = (luaL_Buffer *)priv;
+ for (int i = 0; i < nbuf; i++) {
+ const long size = mb[i].size;
+ for (long total = 0; total < size; total += LUAL_BUFFERSIZE) {
+ const int tocopy = MIN((int)(size - total), LUAL_BUFFERSIZE);
+ char *p = luaL_prepbuffer(buf);
+ if (!p) {
+ return -1;
+ }
+ memcpy(p, mb[i].ptr + total, (unsigned)tocopy);
+ luaL_addsize(buf, (unsigned)tocopy);
+ }
+ }
+ return 0;
+}
+
+// hunk_func callback used when opts.hunk_lines = true
+static int hunk_locations_cb(long start_a, long count_a, long start_b, long count_b, void *cb_data)
+{
+ // Mimic extra offsets done by xdiff, see:
+ // src/xdiff/xemit.c:284
+ // src/xdiff/xutils.c:(356,368)
+ if (count_a > 0) {
+ start_a += 1;
+ }
+ if (count_b > 0) {
+ start_b += 1;
+ }
+
+ lua_State * lstate = (lua_State *)cb_data;
+ lua_createtable(lstate, 0, 0);
+
+ lua_pushinteger(lstate, start_a);
+ lua_rawseti(lstate, -2, 1);
+ lua_pushinteger(lstate, count_a);
+ lua_rawseti(lstate, -2, 2);
+ lua_pushinteger(lstate, start_b);
+ lua_rawseti(lstate, -2, 3);
+ lua_pushinteger(lstate, count_b);
+ lua_rawseti(lstate, -2, 4);
+
+ lua_rawseti(lstate, -2, (signed)lua_objlen(lstate, -2)+1);
+
+ return 0;
+}
+
+// hunk_func callback used when opts.on_hunk is given
+static int call_on_hunk_cb(long start_a, long count_a, long start_b, long count_b, void *cb_data)
+{
+ // Mimic extra offsets done by xdiff, see:
+ // src/xdiff/xemit.c:284
+ // src/xdiff/xutils.c:(356,368)
+ if (count_a > 0) {
+ start_a += 1;
+ }
+ if (count_b > 0) {
+ start_b += 1;
+ }
+
+ hunkpriv_t *priv = (hunkpriv_t *)cb_data;
+ lua_State * lstate = priv->lstate;
+ Error *err = priv->err;
+ const int fidx = lua_gettop(lstate);
+ lua_pushvalue(lstate, fidx);
+ lua_pushinteger(lstate, start_a);
+ lua_pushinteger(lstate, count_a);
+ lua_pushinteger(lstate, start_b);
+ lua_pushinteger(lstate, count_b);
+
+ if (lua_pcall(lstate, 4, 1, 0) != 0) {
+ api_set_error(err, kErrorTypeException,
+ "error running function on_hunk: %s",
+ lua_tostring(lstate, -1));
+ return -1;
+ }
+
+ int r = 0;
+ if (lua_isnumber(lstate, -1)) {
+ r = (int)lua_tonumber(lstate, -1);
+ }
+
+ lua_pop(lstate, 1);
+ lua_settop(lstate, fidx);
+ return r;
+}
+
+static mmfile_t get_string_arg(lua_State *lstate, int idx)
+{
+ if (lua_type(lstate, idx) != LUA_TSTRING) {
+ luaL_argerror(lstate, idx, "expected string");
+ }
+ mmfile_t mf;
+ mf.ptr = (char *)lua_tolstring(lstate, idx, (size_t *)&mf.size);
+ return mf;
+}
+
+// Helper function for validating option types
+static bool check_xdiff_opt(ObjectType actType, ObjectType expType, const char *name, Error *err)
+{
+ if (actType != expType) {
+ const char * type_str =
+ expType == kObjectTypeString ? "string" :
+ expType == kObjectTypeInteger ? "integer" :
+ expType == kObjectTypeBoolean ? "boolean" :
+ expType == kObjectTypeLuaRef ? "function" :
+ "NA";
+
+ api_set_error(err, kErrorTypeValidation, "%s is not a %s", name,
+ type_str);
+ return true;
+ }
+
+ return false;
+}
+
+static NluaXdiffMode process_xdl_diff_opts(lua_State *lstate, xdemitconf_t *cfg, xpparam_t *params,
+ Error *err)
+{
+ const DictionaryOf(LuaRef) opts = nlua_pop_Dictionary(lstate, true, err);
+
+ NluaXdiffMode mode = kNluaXdiffModeUnified;
+
+ bool had_on_hunk = false;
+ bool had_result_type_indices = false;
+ for (size_t i = 0; i < opts.size; i++) {
+ String k = opts.items[i].key;
+ Object *v = &opts.items[i].value;
+ if (strequal("on_hunk", k.data)) {
+ if (check_xdiff_opt(v->type, kObjectTypeLuaRef, "on_hunk", err)) {
+ goto exit_1;
+ }
+ had_on_hunk = true;
+ nlua_pushref(lstate, v->data.luaref);
+ } else if (strequal("result_type", k.data)) {
+ if (check_xdiff_opt(v->type, kObjectTypeString, "result_type", err)) {
+ goto exit_1;
+ }
+ if (strequal("unified", v->data.string.data)) {
+ } else if (strequal("indices", v->data.string.data)) {
+ had_result_type_indices = true;
+ } else {
+ api_set_error(err, kErrorTypeValidation, "not a valid result_type");
+ goto exit_1;
+ }
+ } else if (strequal("algorithm", k.data)) {
+ if (check_xdiff_opt(v->type, kObjectTypeString, "algorithm", err)) {
+ goto exit_1;
+ }
+ if (strequal("myers", v->data.string.data)) {
+ // default
+ } else if (strequal("minimal", v->data.string.data)) {
+ cfg->flags |= XDF_NEED_MINIMAL;
+ } else if (strequal("patience", v->data.string.data)) {
+ cfg->flags |= XDF_PATIENCE_DIFF;
+ } else if (strequal("histogram", v->data.string.data)) {
+ cfg->flags |= XDF_HISTOGRAM_DIFF;
+ } else {
+ api_set_error(err, kErrorTypeValidation, "not a valid algorithm");
+ goto exit_1;
+ }
+ } else if (strequal("ctxlen", k.data)) {
+ if (check_xdiff_opt(v->type, kObjectTypeInteger, "ctxlen", err)) {
+ goto exit_1;
+ }
+ cfg->ctxlen = v->data.integer;
+ } else if (strequal("interhunkctxlen", k.data)) {
+ if (check_xdiff_opt(v->type, kObjectTypeInteger, "interhunkctxlen",
+ err)) {
+ goto exit_1;
+ }
+ cfg->interhunkctxlen = v->data.integer;
+ } else {
+ struct {
+ const char *name;
+ unsigned long value;
+ } flags[] = {
+ { "ignore_whitespace", XDF_IGNORE_WHITESPACE },
+ { "ignore_whitespace_change", XDF_IGNORE_WHITESPACE_CHANGE },
+ { "ignore_whitespace_change_at_eol", XDF_IGNORE_WHITESPACE_AT_EOL },
+ { "ignore_cr_at_eol", XDF_IGNORE_CR_AT_EOL },
+ { "ignore_blank_lines", XDF_IGNORE_BLANK_LINES },
+ { "indent_heuristic", XDF_INDENT_HEURISTIC },
+ { NULL, 0 },
+ };
+ bool key_used = false;
+ for (size_t j = 0; flags[j].name; j++) {
+ if (strequal(flags[j].name, k.data)) {
+ if (check_xdiff_opt(v->type, kObjectTypeBoolean, flags[j].name,
+ err)) {
+ goto exit_1;
+ }
+ if (v->data.boolean) {
+ params->flags |= flags[j].value;
+ }
+ key_used = true;
+ break;
+ }
+ }
+
+ if (key_used) {
+ continue;
+ }
+
+ api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data);
+ goto exit_1;
+ }
+ }
+
+ if (had_on_hunk) {
+ mode = kNluaXdiffModeOnHunkCB;
+ cfg->hunk_func = call_on_hunk_cb;
+ } else if (had_result_type_indices) {
+ mode = kNluaXdiffModeLocations;
+ cfg->hunk_func = hunk_locations_cb;
+ }
+
+exit_1:
+ api_free_dictionary(opts);
+ return mode;
+}
+
+int nlua_xdl_diff(lua_State *lstate)
+{
+ if (lua_gettop(lstate) < 2) {
+ return luaL_error(lstate, "Expected at least 2 arguments");
+ }
+ mmfile_t ma = get_string_arg(lstate, 1);
+ mmfile_t mb = get_string_arg(lstate, 2);
+
+ Error err = ERROR_INIT;
+
+ xdemitconf_t cfg;
+ xpparam_t params;
+ xdemitcb_t ecb;
+
+ memset(&cfg, 0, sizeof(cfg));
+ memset(&params, 0, sizeof(params));
+ memset(&ecb, 0, sizeof(ecb));
+
+ NluaXdiffMode mode = kNluaXdiffModeUnified;
+
+ if (lua_gettop(lstate) == 3) {
+ if (lua_type(lstate, 3) != LUA_TTABLE) {
+ return luaL_argerror(lstate, 3, "expected table");
+ }
+
+ mode = process_xdl_diff_opts(lstate, &cfg, &params, &err);
+
+ if (ERROR_SET(&err)) {
+ goto exit_0;
+ }
+ }
+
+ luaL_Buffer buf;
+ hunkpriv_t *priv = NULL;
+ switch (mode) {
+ case kNluaXdiffModeUnified:
+ luaL_buffinit(lstate, &buf);
+ ecb.priv = &buf;
+ ecb.out_line = write_string;
+ break;
+ case kNluaXdiffModeOnHunkCB:
+ priv = xmalloc(sizeof(*priv));
+ priv->lstate = lstate;
+ priv->err = &err;
+ ecb.priv = priv;
+ break;
+ case kNluaXdiffModeLocations:
+ lua_createtable(lstate, 0, 0);
+ ecb.priv = lstate;
+ break;
+ }
+
+ if (xdl_diff(&ma, &mb, &params, &cfg, &ecb) == -1) {
+ if (!ERROR_SET(&err)) {
+ api_set_error(&err, kErrorTypeException,
+ "Error while performing diff operation");
+ }
+ }
+
+ XFREE_CLEAR(priv);
+
+exit_0:
+ if (ERROR_SET(&err)) {
+ luaL_where(lstate, 1);
+ lua_pushstring(lstate, err.msg);
+ api_clear_error(&err);
+ lua_concat(lstate, 2);
+ return lua_error(lstate);
+ } else if (mode == kNluaXdiffModeUnified) {
+ luaL_pushresult(&buf);
+ return 1;
+ } else if (mode == kNluaXdiffModeLocations) {
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/nvim/lua/xdiff.h b/src/nvim/lua/xdiff.h
new file mode 100644
index 0000000000..cae7c98e81
--- /dev/null
+++ b/src/nvim/lua/xdiff.h
@@ -0,0 +1,12 @@
+#ifndef NVIM_LUA_XDIFF_H
+#define NVIM_LUA_XDIFF_H
+
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "lua/xdiff.h.generated.h"
+#endif
+
+#endif // NVIM_LUA_XDIFF_H
diff --git a/src/nvim/macros.h b/src/nvim/macros.h
index e718254fb9..e1aa1b7704 100644
--- a/src/nvim/macros.h
+++ b/src/nvim/macros.h
@@ -34,10 +34,6 @@
/// LINEEMPTY() - return TRUE if the line is empty
#define LINEEMPTY(p) (*ml_get(p) == NUL)
-/// BUFEMPTY() - return TRUE if the current buffer is empty
-#define BUFEMPTY() (curbuf->b_ml.ml_line_count == 1 && *ml_get((linenr_T)1) == \
- NUL)
-
// toupper() and tolower() that use the current locale.
// Careful: Only call TOUPPER_LOC() and TOLOWER_LOC() with a character in the
// range 0 - 255. toupper()/tolower() on some systems can't handle others.
@@ -133,6 +129,8 @@
/// error. A mechanism to detect many (though not all) of those errors at
/// compile time is implemented. It works by the second division producing
/// a division by zero in those cases (-Wdiv-by-zero in GCC).
+///
+/// -V:ARRAY_SIZE:1063
#define ARRAY_SIZE(arr) \
((sizeof(arr)/sizeof((arr)[0])) \
/ ((size_t)(!(sizeof(arr) % sizeof((arr)[0])))))
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 7d7eba2105..d977589ad7 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -3,27 +3,22 @@
#define EXTERN
#include <assert.h>
+#include <msgpack.h>
+#include <stdbool.h>
#include <stdint.h>
#include <string.h>
-#include <stdbool.h>
-
-#include <lua.h>
-#include <lauxlib.h>
-#include <msgpack.h>
#include "nvim/ascii.h"
-#include "nvim/channel.h"
-#include "nvim/vim.h"
-#include "nvim/main.h"
#include "nvim/aucmd.h"
#include "nvim/buffer.h"
+#include "nvim/channel.h"
#include "nvim/charset.h"
+#include "nvim/decoration.h"
#include "nvim/diff.h"
#include "nvim/eval.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_docmd.h"
-#include "nvim/decoration.h"
#include "nvim/fileio.h"
#include "nvim/fold.h"
#include "nvim/getchar.h"
@@ -32,29 +27,36 @@
#include "nvim/iconv.h"
#include "nvim/if_cscope.h"
#include "nvim/lua/executor.h"
+#include "nvim/main.h"
+#include "nvim/vim.h"
#ifdef HAVE_LOCALE_H
# include <locale.h>
#endif
+#include "nvim/garray.h"
+#include "nvim/log.h"
#include "nvim/mark.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
+#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
-#include "nvim/garray.h"
-#include "nvim/log.h"
-#include "nvim/memory.h"
-#include "nvim/move.h"
#include "nvim/mouse.h"
+#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/ops.h"
#include "nvim/option.h"
-#include "nvim/os_unix.h"
+#include "nvim/os/fileio.h"
+#include "nvim/os/input.h"
+#include "nvim/os/os.h"
#include "nvim/os/os_defs.h"
+#include "nvim/os/time.h"
+#include "nvim/os_unix.h"
#include "nvim/path.h"
-#include "nvim/profile.h"
#include "nvim/popupmnu.h"
+#include "nvim/profile.h"
#include "nvim/quickfix.h"
#include "nvim/screen.h"
+#include "nvim/shada.h"
#include "nvim/sign.h"
#include "nvim/state.h"
#include "nvim/strings.h"
@@ -63,25 +65,19 @@
#include "nvim/ui_compositor.h"
#include "nvim/version.h"
#include "nvim/window.h"
-#include "nvim/shada.h"
-#include "nvim/os/input.h"
-#include "nvim/os/os.h"
-#include "nvim/os/time.h"
-#include "nvim/os/fileio.h"
#ifdef WIN32
# include "nvim/os/os_win_console.h"
#endif
+#include "nvim/api/private/defs.h"
+#include "nvim/api/private/dispatch.h"
+#include "nvim/api/private/helpers.h"
+#include "nvim/api/ui.h"
#include "nvim/event/loop.h"
-#include "nvim/os/signal.h"
#include "nvim/event/process.h"
+#include "nvim/msgpack_rpc/channel.h"
#include "nvim/msgpack_rpc/helpers.h"
#include "nvim/msgpack_rpc/server.h"
-#include "nvim/msgpack_rpc/channel.h"
-#include "nvim/api/ui.h"
-#include "nvim/api/private/defs.h"
-#include "nvim/api/private/helpers.h"
-#include "nvim/api/private/handle.h"
-#include "nvim/api/private/dispatch.h"
+#include "nvim/os/signal.h"
#ifndef WIN32
# include "nvim/os/pty_process_unix.h"
#endif
@@ -128,8 +124,6 @@ void event_init(void)
signal_init();
// finish mspgack-rpc initialization
channel_init();
- remote_ui_init();
- api_vim_init();
terminal_init();
ui_init();
}
@@ -162,8 +156,6 @@ void early_init(mparm_T *paramp)
{
env_init();
fs_init();
- handle_init();
- decor_init();
eval_init(); // init global variables
init_path(argv0 ? argv0 : "nvim");
init_normal_cmds(); // Init the table of Normal mode commands.
@@ -258,6 +250,8 @@ int main(int argc, char **argv)
// Check if we have an interactive window.
check_and_set_isatty(&params);
+ nlua_init();
+
// Process the command line arguments. File names are put in the global
// argument list "global_alist".
command_line_scan(&params);
@@ -283,9 +277,9 @@ int main(int argc, char **argv)
TIME_MSG("expanding arguments");
- if (params.diff_mode && params.window_count == -1)
- params.window_count = 0; /* open up to 3 windows */
-
+ if (params.diff_mode && params.window_count == -1) {
+ params.window_count = 0; // open up to 3 windows
+ }
// Don't redraw until much later.
RedrawingDisabled++;
@@ -318,7 +312,8 @@ int main(int argc, char **argv)
debug_break_level = params.use_debug_break_level;
// Read ex-commands if invoked with "-es".
- if (!params.input_isatty && silent_mode && exmode_active == EXMODE_NORMAL) {
+ if (!params.input_isatty && !params.input_neverscript
+ && silent_mode && exmode_active) {
input_start(STDIN_FILENO);
}
@@ -338,25 +333,14 @@ int main(int argc, char **argv)
// prepare screen now, so external UIs can display messages
starting = NO_BUFFERS;
screenclear();
- TIME_MSG("initialized screen early for UI");
- }
-
-
- // open terminals when opening files that start with term://
-#define PROTO "term://"
- do_cmdline_cmd("augroup nvim_terminal");
- do_cmdline_cmd("autocmd!");
- do_cmdline_cmd("autocmd BufReadCmd " PROTO "* nested "
- ":if !exists('b:term_title')|call termopen( "
- // Capture the command string
- "matchstr(expand(\"<amatch>\"), "
- "'\\c\\m" PROTO "\\%(.\\{-}//\\%(\\d\\+:\\)\\?\\)\\?\\zs.*'), "
- // capture the working directory
- "{'cwd': expand(get(matchlist(expand(\"<amatch>\"), "
- "'\\c\\m" PROTO "\\(.\\{-}\\)//'), 1, ''))})"
- "|endif");
- do_cmdline_cmd("augroup END");
-#undef PROTO
+ TIME_MSG("init screen for UI");
+ }
+
+ init_default_mappings(); // Default mappings.
+ TIME_MSG("init default mappings");
+
+ init_default_autocmds();
+ TIME_MSG("init default autocommands");
// Reset 'loadplugins' for "-u NONE" before "--cmd" arguments.
// Allows for setting 'loadplugins' there.
@@ -474,7 +458,7 @@ int main(int argc, char **argv)
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
}
- apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
+ apply_autocmds(EVENT_BUFENTER, NULL, NULL, false, curbuf);
TIME_MSG("BufEnter autocommands");
setpcmark();
@@ -601,15 +585,16 @@ void getout(int exitval)
/* When running in Ex mode an error causes us to exit with a non-zero exit
* code. POSIX requires this, although it's not 100% clear from the
* standard. */
- if (exmode_active)
+ if (exmode_active) {
exitval += ex_exitval;
+ }
set_vim_var_nr(VV_EXITING, exitval);
// Position the cursor on the last screen line, below all the text
ui_cursor_goto(Rows - 1, 0);
- /* Optionally print hashtable efficiency. */
+ // Optionally print hashtable efficiency.
hash_debug_results();
if (v_dying <= 1) {
@@ -620,7 +605,7 @@ void getout(int exitval)
next_tp = tp->tp_next;
FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
if (wp->w_buffer == NULL) {
- /* Autocmd must have close the buffer already, skip. */
+ // Autocmd must have close the buffer already, skip.
continue;
}
@@ -641,7 +626,7 @@ void getout(int exitval)
}
}
- /* Trigger BufUnload for buffers that are loaded */
+ // Trigger BufUnload for buffers that are loaded
FOR_ALL_BUFFERS(buf) {
if (buf->b_ml.ml_mfp != NULL) {
bufref_T bufref;
@@ -689,8 +674,8 @@ void getout(int exitval)
profile_dump();
if (did_emsg
- ) {
- /* give the user a chance to read the (error) message */
+ ) {
+ // give the user a chance to read the (error) message
no_wait_return = FALSE;
wait_return(FALSE);
}
@@ -742,7 +727,7 @@ static void init_locale(void)
setlocale(LC_ALL, "");
# ifdef LC_NUMERIC
- /* Make sure strtod() uses a decimal point, not a comma. */
+ // Make sure strtod() uses a decimal point, not a comma.
setlocale(LC_NUMERIC, "C");
# endif
@@ -764,10 +749,10 @@ static void init_locale(void)
static bool edit_stdin(bool explicit, mparm_T *parmp)
{
bool implicit = !headless_mode
- && !embedded_mode
- && exmode_active != EXMODE_NORMAL // -E/-Es but not -e/-es.
- && !parmp->input_isatty
- && scriptin[0] == NULL; // `-s -` was not given.
+ && !embedded_mode
+ && (!exmode_active || parmp->input_neverscript)
+ && !parmp->input_isatty
+ && scriptin[0] == NULL; // `-s -` was not given.
return explicit || implicit;
}
@@ -799,269 +784,242 @@ static void command_line_scan(mparm_T *parmp)
parmp->commands[parmp->n_commands++] = &(argv[0][1]);
}
- // Optional argument.
+ // Optional argument.
} else if (argv[0][0] == '-' && !had_minmin) {
want_argument = false;
c = argv[0][argv_idx++];
switch (c) {
- case NUL: { // "nvim -" read from stdin
- if (exmode_active) {
- // "nvim -e -" silent mode
- silent_mode = true;
- parmp->no_swap_file = true;
- } else {
- if (parmp->edit_type != EDIT_NONE
- && parmp->edit_type != EDIT_FILE
- && parmp->edit_type != EDIT_STDIN) {
- mainerr(err_too_many_args, argv[0]);
- }
- had_stdin_file = true;
- parmp->edit_type = EDIT_STDIN;
+ case NUL: // "nvim -" read from stdin
+ if (exmode_active) {
+ // "nvim -e -" silent mode
+ silent_mode = true;
+ parmp->no_swap_file = true;
+ } else {
+ if (parmp->edit_type != EDIT_NONE
+ && parmp->edit_type != EDIT_FILE
+ && parmp->edit_type != EDIT_STDIN) {
+ mainerr(err_too_many_args, argv[0]);
}
- argv_idx = -1; // skip to next argument
- break;
+ had_stdin_file = true;
+ parmp->edit_type = EDIT_STDIN;
}
- case '-': { // "--" don't take any more option arguments
- // "--help" give help message
- // "--version" give version message
- // "--noplugin[s]" skip plugins
- // "--cmd <cmd>" execute cmd before vimrc
- if (STRICMP(argv[0] + argv_idx, "help") == 0) {
- usage();
- os_exit(0);
- } else if (STRICMP(argv[0] + argv_idx, "version") == 0) {
- version();
- os_exit(0);
- } else if (STRICMP(argv[0] + argv_idx, "api-info") == 0) {
- FileDescriptor fp;
- const int fof_ret = file_open_fd(&fp, STDOUT_FILENO,
- kFileWriteOnly);
- msgpack_packer *p = msgpack_packer_new(&fp, msgpack_file_write);
-
- if (fof_ret != 0) {
- emsgf(_("E5421: Failed to open stdin: %s"), os_strerror(fof_ret));
- }
+ argv_idx = -1; // skip to next argument
+ break;
+ case '-': // "--" don't take any more option arguments
+ // "--help" give help message
+ // "--version" give version message
+ // "--noplugin[s]" skip plugins
+ // "--cmd <cmd>" execute cmd before vimrc
+ if (STRICMP(argv[0] + argv_idx, "help") == 0) {
+ usage();
+ os_exit(0);
+ } else if (STRICMP(argv[0] + argv_idx, "version") == 0) {
+ version();
+ os_exit(0);
+ } else if (STRICMP(argv[0] + argv_idx, "api-info") == 0) {
+ FileDescriptor fp;
+ const int fof_ret = file_open_fd(&fp, STDOUT_FILENO,
+ kFileWriteOnly);
+ msgpack_packer *p = msgpack_packer_new(&fp, msgpack_file_write);
+
+ if (fof_ret != 0) {
+ emsgf(_("E5421: Failed to open stdin: %s"), os_strerror(fof_ret));
+ }
- if (p == NULL) {
- EMSG(_(e_outofmem));
- }
+ if (p == NULL) {
+ EMSG(_(e_outofmem));
+ }
- Object md = DICTIONARY_OBJ(api_metadata());
- msgpack_rpc_from_object(md, p);
+ Object md = DICTIONARY_OBJ(api_metadata());
+ msgpack_rpc_from_object(md, p);
- msgpack_packer_free(p);
- const int ff_ret = file_flush(&fp);
- if (ff_ret < 0) {
- msgpack_file_write_error(ff_ret);
- }
- os_exit(0);
- } else if (STRICMP(argv[0] + argv_idx, "headless") == 0) {
- headless_mode = true;
- } else if (STRICMP(argv[0] + argv_idx, "embed") == 0) {
- embedded_mode = true;
- } else if (STRNICMP(argv[0] + argv_idx, "listen", 6) == 0) {
- want_argument = true;
- argv_idx += 6;
- } else if (STRNICMP(argv[0] + argv_idx, "literal", 7) == 0) {
- // Do nothing: file args are always literal. #7679
- } else if (STRNICMP(argv[0] + argv_idx, "noplugin", 8) == 0) {
- p_lpl = false;
- } else if (STRNICMP(argv[0] + argv_idx, "cmd", 3) == 0) {
- want_argument = true;
- argv_idx += 3;
- } else if (STRNICMP(argv[0] + argv_idx, "startuptime", 11) == 0) {
- want_argument = true;
- argv_idx += 11;
- } else if (STRNICMP(argv[0] + argv_idx, "clean", 5) == 0) {
- parmp->use_vimrc = "NONE";
- parmp->clean = true;
- set_option_value("shadafile", 0L, "NONE", 0);
- } else {
- if (argv[0][argv_idx])
- mainerr(err_opt_unknown, argv[0]);
- had_minmin = true;
+ msgpack_packer_free(p);
+ const int ff_ret = file_flush(&fp);
+ if (ff_ret < 0) {
+ msgpack_file_write_error(ff_ret);
}
- if (!want_argument) {
- argv_idx = -1; // skip to next argument
+ os_exit(0);
+ } else if (STRICMP(argv[0] + argv_idx, "headless") == 0) {
+ headless_mode = true;
+ } else if (STRICMP(argv[0] + argv_idx, "embed") == 0) {
+ embedded_mode = true;
+ } else if (STRNICMP(argv[0] + argv_idx, "listen", 6) == 0) {
+ want_argument = true;
+ argv_idx += 6;
+ } else if (STRNICMP(argv[0] + argv_idx, "literal", 7) == 0) {
+ // Do nothing: file args are always literal. #7679
+ } else if (STRNICMP(argv[0] + argv_idx, "noplugin", 8) == 0) {
+ p_lpl = false;
+ } else if (STRNICMP(argv[0] + argv_idx, "cmd", 3) == 0) {
+ want_argument = true;
+ argv_idx += 3;
+ } else if (STRNICMP(argv[0] + argv_idx, "startuptime", 11) == 0) {
+ want_argument = true;
+ argv_idx += 11;
+ } else if (STRNICMP(argv[0] + argv_idx, "clean", 5) == 0) {
+ parmp->use_vimrc = "NONE";
+ parmp->clean = true;
+ set_option_value("shadafile", 0L, "NONE", 0);
+ } else {
+ if (argv[0][argv_idx]) {
+ mainerr(err_opt_unknown, argv[0]);
}
- break;
+ had_minmin = true;
}
- case 'A': { // "-A" start in Arabic mode.
- set_option_value("arabic", 1L, NULL, 0);
- break;
- }
- case 'b': { // "-b" binary mode.
- // Needs to be effective before expanding file names, because
- // for Win32 this makes us edit a shortcut file itself,
- // instead of the file it links to.
- set_options_bin(curbuf->b_p_bin, 1, 0);
- curbuf->b_p_bin = 1; // Binary file I/O.
- break;
+ if (!want_argument) {
+ argv_idx = -1; // skip to next argument
}
+ break;
+ case 'A': // "-A" start in Arabic mode.
+ set_option_value("arabic", 1L, NULL, 0);
+ break;
+ case 'b': // "-b" binary mode.
+ // Needs to be effective before expanding file names, because
+ // for Win32 this makes us edit a shortcut file itself,
+ // instead of the file it links to.
+ set_options_bin(curbuf->b_p_bin, 1, 0);
+ curbuf->b_p_bin = 1; // Binary file I/O.
+ break;
- case 'D': { // "-D" Debugging
- parmp->use_debug_break_level = 9999;
- break;
- }
- case 'd': { // "-d" 'diff'
- parmp->diff_mode = true;
- break;
- }
- case 'e': { // "-e" Ex mode
- exmode_active = EXMODE_NORMAL;
- break;
- }
- case 'E': { // "-E" Ex mode
- exmode_active = EXMODE_VIM;
- break;
- }
- case 'f': { // "-f" GUI: run in foreground.
- break;
- }
- case '?': // "-?" give help message (for MS-Windows)
- case 'h': { // "-h" give help message
- usage();
- os_exit(0);
- }
- case 'H': { // "-H" start in Hebrew mode: rl + hkmap set.
- p_hkmap = true;
- set_option_value("rl", 1L, NULL, 0);
- break;
- }
- case 'l': { // "-l" lisp mode, 'lisp' and 'showmatch' on.
- set_option_value("lisp", 1L, NULL, 0);
- p_sm = true;
- break;
- }
- case 'M': { // "-M" no changes or writing of files
- reset_modifiable();
- FALLTHROUGH;
- }
- case 'm': { // "-m" no writing of files
- p_write = false;
- break;
- }
+ case 'D': // "-D" Debugging
+ parmp->use_debug_break_level = 9999;
+ break;
+ case 'd': // "-d" 'diff'
+ parmp->diff_mode = true;
+ break;
+ case 'e': // "-e" Ex mode
+ exmode_active = true;
+ break;
+ case 'E': // "-E" Ex mode
+ exmode_active = true;
+ parmp->input_neverscript = true;
+ break;
+ case 'f': // "-f" GUI: run in foreground.
+ break;
+ case '?': // "-?" give help message (for MS-Windows)
+ case 'h': // "-h" give help message
+ usage();
+ os_exit(0);
+ case 'H': // "-H" start in Hebrew mode: rl + hkmap set.
+ p_hkmap = true;
+ set_option_value("rl", 1L, NULL, 0);
+ break;
+ case 'l': // "-l" lisp mode, 'lisp' and 'showmatch' on.
+ set_option_value("lisp", 1L, NULL, 0);
+ p_sm = true;
+ break;
+ case 'M': // "-M" no changes or writing of files
+ reset_modifiable();
+ FALLTHROUGH;
+ case 'm': // "-m" no writing of files
+ p_write = false;
+ break;
- case 'N': // "-N" Nocompatible
- case 'X': // "-X" Do not connect to X server
- // No-op
- break;
+ case 'N': // "-N" Nocompatible
+ case 'X': // "-X" Do not connect to X server
+ // No-op
+ break;
- case 'n': { // "-n" no swap file
- parmp->no_swap_file = true;
- break;
- }
- case 'p': { // "-p[N]" open N tab pages
- // default is 0: open window for each file
- parmp->window_count = get_number_arg(argv[0], &argv_idx, 0);
- parmp->window_layout = WIN_TABS;
- break;
- }
- case 'o': { // "-o[N]" open N horizontal split windows
- // default is 0: open window for each file
- parmp->window_count = get_number_arg(argv[0], &argv_idx, 0);
- parmp->window_layout = WIN_HOR;
- break;
- }
- case 'O': { // "-O[N]" open N vertical split windows
- // default is 0: open window for each file
- parmp->window_count = get_number_arg(argv[0], &argv_idx, 0);
- parmp->window_layout = WIN_VER;
- break;
- }
- case 'q': { // "-q" QuickFix mode
- if (parmp->edit_type != EDIT_NONE) {
- mainerr(err_too_many_args, argv[0]);
- }
- parmp->edit_type = EDIT_QF;
- if (argv[0][argv_idx]) { // "-q{errorfile}"
- parmp->use_ef = (char_u *)argv[0] + argv_idx;
- argv_idx = -1;
- } else if (argc > 1) { // "-q {errorfile}"
- want_argument = true;
- }
- break;
- }
- case 'R': { // "-R" readonly mode
- readonlymode = true;
- curbuf->b_p_ro = true;
- p_uc = 10000; // don't update very often
- break;
+ case 'n': // "-n" no swap file
+ parmp->no_swap_file = true;
+ break;
+ case 'p': // "-p[N]" open N tab pages
+ // default is 0: open window for each file
+ parmp->window_count = get_number_arg(argv[0], &argv_idx, 0);
+ parmp->window_layout = WIN_TABS;
+ break;
+ case 'o': // "-o[N]" open N horizontal split windows
+ // default is 0: open window for each file
+ parmp->window_count = get_number_arg(argv[0], &argv_idx, 0);
+ parmp->window_layout = WIN_HOR;
+ break;
+ case 'O': // "-O[N]" open N vertical split windows
+ // default is 0: open window for each file
+ parmp->window_count = get_number_arg(argv[0], &argv_idx, 0);
+ parmp->window_layout = WIN_VER;
+ break;
+ case 'q': // "-q" QuickFix mode
+ if (parmp->edit_type != EDIT_NONE) {
+ mainerr(err_too_many_args, argv[0]);
}
- case 'r': // "-r" recovery mode
- case 'L': { // "-L" recovery mode
- recoverymode = 1;
- break;
+ parmp->edit_type = EDIT_QF;
+ if (argv[0][argv_idx]) { // "-q{errorfile}"
+ parmp->use_ef = (char_u *)argv[0] + argv_idx;
+ argv_idx = -1;
+ } else if (argc > 1) { // "-q {errorfile}"
+ want_argument = true;
}
- case 's': {
- if (exmode_active) { // "-es" silent (batch) Ex-mode
- silent_mode = true;
- parmp->no_swap_file = true;
- } else { // "-s {scriptin}" read from script file
- want_argument = true;
- }
- break;
+ break;
+ case 'R': // "-R" readonly mode
+ readonlymode = true;
+ curbuf->b_p_ro = true;
+ p_uc = 10000; // don't update very often
+ break;
+ case 'r': // "-r" recovery mode
+ case 'L': // "-L" recovery mode
+ recoverymode = 1;
+ break;
+ case 's':
+ if (exmode_active) { // "-es" silent (batch) Ex-mode
+ silent_mode = true;
+ parmp->no_swap_file = true;
+ } else { // "-s {scriptin}" read from script file
+ want_argument = true;
}
- case 't': { // "-t {tag}" or "-t{tag}" jump to tag
- if (parmp->edit_type != EDIT_NONE) {
- mainerr(err_too_many_args, argv[0]);
- }
- parmp->edit_type = EDIT_TAG;
- if (argv[0][argv_idx]) { // "-t{tag}"
- parmp->tagname = (char_u *)argv[0] + argv_idx;
- argv_idx = -1;
- } else { // "-t {tag}"
- want_argument = true;
- }
- break;
+ break;
+ case 't': // "-t {tag}" or "-t{tag}" jump to tag
+ if (parmp->edit_type != EDIT_NONE) {
+ mainerr(err_too_many_args, argv[0]);
}
- case 'v': {
- version();
- os_exit(0);
+ parmp->edit_type = EDIT_TAG;
+ if (argv[0][argv_idx]) { // "-t{tag}"
+ parmp->tagname = (char_u *)argv[0] + argv_idx;
+ argv_idx = -1;
+ } else { // "-t {tag}"
+ want_argument = true;
}
- case 'V': { // "-V{N}" Verbose level
- // default is 10: a little bit verbose
- p_verbose = get_number_arg(argv[0], &argv_idx, 10);
- if (argv[0][argv_idx] != NUL) {
- set_option_value("verbosefile", 0L, argv[0] + argv_idx, 0);
- argv_idx = (int)STRLEN(argv[0]);
- }
- break;
+ break;
+ case 'v':
+ version();
+ os_exit(0);
+ case 'V': // "-V{N}" Verbose level
+ // default is 10: a little bit verbose
+ p_verbose = get_number_arg(argv[0], &argv_idx, 10);
+ if (argv[0][argv_idx] != NUL) {
+ set_option_value("verbosefile", 0L, argv[0] + argv_idx, 0);
+ argv_idx = (int)STRLEN(argv[0]);
}
- case 'w': { // "-w{number}" set window height
- // "-w {scriptout}" write to script
- if (ascii_isdigit(((char_u *)argv[0])[argv_idx])) {
- n = get_number_arg(argv[0], &argv_idx, 10);
- set_option_value("window", n, NULL, 0);
- break;
- }
- want_argument = true;
+ break;
+ case 'w': // "-w{number}" set window height
+ // "-w {scriptout}" write to script
+ if (ascii_isdigit(((char_u *)argv[0])[argv_idx])) {
+ n = get_number_arg(argv[0], &argv_idx, 10);
+ set_option_value("window", n, NULL, 0);
break;
}
+ want_argument = true;
+ break;
- case 'c': { // "-c{command}" or "-c {command}" exec command
- if (argv[0][argv_idx] != NUL) {
- if (parmp->n_commands >= MAX_ARG_CMDS) {
- mainerr(err_extra_cmd, NULL);
- }
- parmp->commands[parmp->n_commands++] = argv[0] + argv_idx;
- argv_idx = -1;
- break;
+ case 'c': // "-c{command}" or "-c {command}" exec command
+ if (argv[0][argv_idx] != NUL) {
+ if (parmp->n_commands >= MAX_ARG_CMDS) {
+ mainerr(err_extra_cmd, NULL);
}
- FALLTHROUGH;
- }
- case 'S': // "-S {file}" execute Vim script
- case 'i': // "-i {shada}" use for ShaDa file
- case 'u': // "-u {vimrc}" vim inits file
- case 'U': // "-U {gvimrc}" gvim inits file
- case 'W': { // "-W {scriptout}" overwrite
- want_argument = true;
+ parmp->commands[parmp->n_commands++] = argv[0] + argv_idx;
+ argv_idx = -1;
break;
}
+ FALLTHROUGH;
+ case 'S': // "-S {file}" execute Vim script
+ case 'i': // "-i {shada}" use for ShaDa file
+ case 'u': // "-u {vimrc}" vim inits file
+ case 'U': // "-U {gvimrc}" gvim inits file
+ case 'W': // "-W {scriptout}" overwrite
+ want_argument = true;
+ break;
- default: {
- mainerr(err_opt_unknown, argv[0]);
- }
+ default:
+ mainerr(err_opt_unknown, argv[0]);
}
// Handle option arguments with argument.
@@ -1079,130 +1037,122 @@ static void command_line_scan(mparm_T *parmp)
argv_idx = -1;
switch (c) {
- case 'c': // "-c {command}" execute command
- case 'S': { // "-S {file}" execute Vim script
- if (parmp->n_commands >= MAX_ARG_CMDS) {
- mainerr(err_extra_cmd, NULL);
- }
- if (c == 'S') {
- char *a;
-
- if (argc < 1) {
- // "-S" without argument: use default session file name.
- a = SESSION_FILE;
- } else if (argv[0][0] == '-') {
- // "-S" followed by another option: use default session file.
- a = SESSION_FILE;
- ++argc;
- --argv;
- } else {
- a = argv[0];
- }
-
- size_t s_size = STRLEN(a) + 9;
- char *s = xmalloc(s_size);
- snprintf(s, s_size, "so %s", a);
- parmp->cmds_tofree[parmp->n_commands] = true;
- parmp->commands[parmp->n_commands++] = s;
+ case 'c': // "-c {command}" execute command
+ case 'S': // "-S {file}" execute Vim script
+ if (parmp->n_commands >= MAX_ARG_CMDS) {
+ mainerr(err_extra_cmd, NULL);
+ }
+ if (c == 'S') {
+ char *a;
+
+ if (argc < 1) {
+ // "-S" without argument: use default session file name.
+ a = SESSION_FILE;
+ } else if (argv[0][0] == '-') {
+ // "-S" followed by another option: use default session file.
+ a = SESSION_FILE;
+ ++argc;
+ --argv;
} else {
- parmp->commands[parmp->n_commands++] = argv[0];
+ a = argv[0];
}
- break;
+
+ size_t s_size = STRLEN(a) + 9;
+ char *s = xmalloc(s_size);
+ snprintf(s, s_size, "so %s", a);
+ parmp->cmds_tofree[parmp->n_commands] = true;
+ parmp->commands[parmp->n_commands++] = s;
+ } else {
+ parmp->commands[parmp->n_commands++] = argv[0];
}
+ break;
- case '-': {
- if (strequal(argv[-1], "--cmd")) {
- // "--cmd {command}" execute command
- if (parmp->n_pre_commands >= MAX_ARG_CMDS) {
- mainerr(err_extra_cmd, NULL);
- }
- parmp->pre_commands[parmp->n_pre_commands++] = argv[0];
- } else if (strequal(argv[-1], "--listen")) {
- // "--listen {address}"
- parmp->listen_addr = argv[0];
+ case '-':
+ if (strequal(argv[-1], "--cmd")) {
+ // "--cmd {command}" execute command
+ if (parmp->n_pre_commands >= MAX_ARG_CMDS) {
+ mainerr(err_extra_cmd, NULL);
}
- // "--startuptime <file>" already handled
- break;
+ parmp->pre_commands[parmp->n_pre_commands++] = argv[0];
+ } else if (strequal(argv[-1], "--listen")) {
+ // "--listen {address}"
+ parmp->listen_addr = argv[0];
}
+ // "--startuptime <file>" already handled
+ break;
- case 'q': { // "-q {errorfile}" QuickFix mode
- parmp->use_ef = (char_u *)argv[0];
- break;
- }
+ case 'q': // "-q {errorfile}" QuickFix mode
+ parmp->use_ef = (char_u *)argv[0];
+ break;
- case 'i': { // "-i {shada}" use for shada
- set_option_value("shadafile", 0L, argv[0], 0);
- break;
- }
+ case 'i': // "-i {shada}" use for shada
+ set_option_value("shadafile", 0L, argv[0], 0);
+ break;
- case 's': { // "-s {scriptin}" read from script file
- if (scriptin[0] != NULL) {
+ case 's': { // "-s {scriptin}" read from script file
+ if (scriptin[0] != NULL) {
scripterror:
- vim_snprintf((char *)IObuff, IOSIZE,
- _("Attempt to open script file again: \"%s %s\"\n"),
- argv[-1], argv[0]);
- mch_errmsg((const char *)IObuff);
- os_exit(2);
- }
- int error;
- if (strequal(argv[0], "-")) {
- const int stdin_dup_fd = os_dup(STDIN_FILENO);
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("Attempt to open script file again: \"%s %s\"\n"),
+ argv[-1], argv[0]);
+ mch_errmsg((const char *)IObuff);
+ os_exit(2);
+ }
+ int error;
+ if (strequal(argv[0], "-")) {
+ const int stdin_dup_fd = os_dup(STDIN_FILENO);
#ifdef WIN32
- // Replace the original stdin with the console input handle.
- os_replace_stdin_to_conin();
+ // Replace the original stdin with the console input handle.
+ os_replace_stdin_to_conin();
#endif
- FileDescriptor *const stdin_dup = file_open_fd_new(
- &error, stdin_dup_fd, kFileReadOnly|kFileNonBlocking);
- assert(stdin_dup != NULL);
- scriptin[0] = stdin_dup;
- } else if ((scriptin[0] = file_open_new(
- &error, argv[0], kFileReadOnly|kFileNonBlocking, 0)) == NULL) {
- vim_snprintf((char *)IObuff, IOSIZE,
- _("Cannot open for reading: \"%s\": %s\n"),
- argv[0], os_strerror(error));
- mch_errmsg((const char *)IObuff);
- os_exit(2);
- }
- save_typebuf();
- break;
+ FileDescriptor *const stdin_dup = file_open_fd_new(&error, stdin_dup_fd,
+ kFileReadOnly|kFileNonBlocking);
+ assert(stdin_dup != NULL);
+ scriptin[0] = stdin_dup;
+ } else if ((scriptin[0] =
+ file_open_new(&error, argv[0], kFileReadOnly|kFileNonBlocking,
+ 0)) == NULL) {
+ vim_snprintf((char *)IObuff, IOSIZE,
+ _("Cannot open for reading: \"%s\": %s\n"),
+ argv[0], os_strerror(error));
+ mch_errmsg((const char *)IObuff);
+ os_exit(2);
}
+ save_typebuf();
+ break;
+ }
- case 't': { // "-t {tag}"
- parmp->tagname = (char_u *)argv[0];
- break;
- }
- case 'u': { // "-u {vimrc}" vim inits file
- parmp->use_vimrc = argv[0];
- break;
- }
- case 'U': { // "-U {gvimrc}" gvim inits file
+ case 't': // "-t {tag}"
+ parmp->tagname = (char_u *)argv[0];
+ break;
+ case 'u': // "-u {vimrc}" vim inits file
+ parmp->use_vimrc = argv[0];
+ break;
+ case 'U': // "-U {gvimrc}" gvim inits file
+ break;
+
+ case 'w': // "-w {nr}" 'window' value
+ // "-w {scriptout}" append to script file
+ if (ascii_isdigit(*((char_u *)argv[0]))) {
+ argv_idx = 0;
+ n = get_number_arg(argv[0], &argv_idx, 10);
+ set_option_value("window", n, NULL, 0);
+ argv_idx = -1;
break;
}
-
- case 'w': { // "-w {nr}" 'window' value
- // "-w {scriptout}" append to script file
- if (ascii_isdigit(*((char_u *)argv[0]))) {
- argv_idx = 0;
- n = get_number_arg(argv[0], &argv_idx, 10);
- set_option_value("window", n, NULL, 0);
- argv_idx = -1;
- break;
- }
- FALLTHROUGH;
+ FALLTHROUGH;
+ case 'W': // "-W {scriptout}" overwrite script file
+ if (scriptout != NULL) {
+ goto scripterror;
}
- case 'W': { // "-W {scriptout}" overwrite script file
- if (scriptout != NULL) {
- goto scripterror;
- }
- if ((scriptout = os_fopen(argv[0], c == 'w' ? APPENDBIN : WRITEBIN))
- == NULL) {
- mch_errmsg(_("Cannot open for script output: \""));
- mch_errmsg(argv[0]);
- mch_errmsg("\"\n");
- os_exit(2);
- }
- break;
+ if ((scriptout = os_fopen(argv[0], c == 'w' ? APPENDBIN : WRITEBIN))
+ == NULL) {
+ mch_errmsg(_("Cannot open for script output: \""));
+ mch_errmsg(argv[0]);
+ mch_errmsg("\"\n");
+ os_exit(2);
}
+ break;
}
}
} else { // File name argument.
@@ -1223,7 +1173,7 @@ scripterror:
if (parmp->diff_mode && os_isdir(p) && GARGCOUNT > 0
&& !os_isdir(alist_name(&GARGLIST[0]))) {
char_u *r = (char_u *)concat_fnames((char *)p,
- (char *)path_tail(alist_name(&GARGLIST[0])), true);
+ (char *)path_tail(alist_name(&GARGLIST[0])), true);
xfree(p);
p = r;
}
@@ -1348,10 +1298,11 @@ static char_u *get_fname(mparm_T *parmp, char_u *cwd)
static void set_window_layout(mparm_T *paramp)
{
if (paramp->diff_mode && paramp->window_layout == 0) {
- if (diffopt_horizontal())
- paramp->window_layout = WIN_HOR; /* use horizontal split */
- else
- paramp->window_layout = WIN_VER; /* use vertical split */
+ if (diffopt_horizontal()) {
+ paramp->window_layout = WIN_HOR; // use horizontal split
+ } else {
+ paramp->window_layout = WIN_VER; // use vertical split
+ }
}
}
@@ -1366,23 +1317,10 @@ static void load_plugins(void)
char_u *const plugin_pattern_vim = (char_u *)"plugin/**/*.vim"; // NOLINT
char_u *const plugin_pattern_lua = (char_u *)"plugin/**/*.lua"; // NOLINT
- // First add all package directories to 'runtimepath', so that their
- // autoload directories can be found. Only if not done already with a
- // :packloadall command.
- // Make a copy of 'runtimepath', so that source_runtime does not use the
- // pack directories.
- if (!did_source_packages) {
- rtp_copy = vim_strsave(p_rtp);
- add_pack_start_dirs();
- }
-
- source_in_path(rtp_copy == NULL ? p_rtp : rtp_copy,
- plugin_pattern_vim,
- DIP_ALL | DIP_NOAFTER);
- source_in_path(rtp_copy == NULL ? p_rtp : rtp_copy,
- plugin_pattern_lua,
- DIP_ALL | DIP_NOAFTER);
- TIME_MSG("loading plugins");
+ // don't use source_runtime() yet so we can check for :packloadall below
+ source_in_path(p_rtp, plugin_pattern_vim, DIP_ALL | DIP_NOAFTER);
+ source_in_path(p_rtp, plugin_pattern_lua, DIP_ALL | DIP_NOAFTER);
+ TIME_MSG("loading rtp plugins");
xfree(rtp_copy);
// Only source "start" packages if not done already with a :packloadall
@@ -1424,15 +1362,16 @@ static void handle_quickfix(mparm_T *paramp)
static void handle_tag(char_u *tagname)
{
if (tagname != NULL) {
- swap_exists_did_quit = FALSE;
+ swap_exists_did_quit = false;
vim_snprintf((char *)IObuff, IOSIZE, "ta %s", tagname);
do_cmdline_cmd((char *)IObuff);
TIME_MSG("jumping to tag");
- /* If the user doesn't want to edit the file then we quit here. */
- if (swap_exists_did_quit)
+ // If the user doesn't want to edit the file then we quit here.
+ if (swap_exists_did_quit) {
getout(1);
+ }
}
}
@@ -1442,13 +1381,11 @@ static void read_stdin(void)
// When getting the ATTENTION prompt here, use a dialog.
swap_exists_action = SEA_DIALOG;
no_wait_return = true;
- int save_msg_didany = msg_didany;
+ bool save_msg_didany = msg_didany;
set_buflisted(true);
-
// Create memfile and read from stdin.
(void)open_buffer(true, NULL, 0);
-
- if (BUFEMPTY() && curbuf->b_next != NULL) {
+ if (buf_is_empty(curbuf) && curbuf->b_next != NULL) {
// stdin was empty, go to buffer 2 (e.g. "echo file1 | xargs nvim"). #8561
do_cmdline_cmd("silent! bnext");
// Delete the empty stdin buffer.
@@ -1472,26 +1409,31 @@ static void create_windows(mparm_T *parmp)
/*
* Create the number of windows that was requested.
*/
- if (parmp->window_count == -1) /* was not set */
+ if (parmp->window_count == -1) { // was not set
parmp->window_count = 1;
- if (parmp->window_count == 0)
+ }
+ if (parmp->window_count == 0) {
parmp->window_count = GARGCOUNT;
+ }
if (parmp->window_count > 1) {
// Don't change the windows if there was a command in vimrc that
// already split some windows
- if (parmp->window_layout == 0)
+ if (parmp->window_layout == 0) {
parmp->window_layout = WIN_HOR;
+ }
if (parmp->window_layout == WIN_TABS) {
parmp->window_count = make_tabpages(parmp->window_count);
TIME_MSG("making tab pages");
} else if (firstwin->w_next == NULL) {
parmp->window_count = make_windows(parmp->window_count,
- parmp->window_layout == WIN_VER);
+ parmp->window_layout == WIN_VER);
TIME_MSG("making windows");
- } else
+ } else {
parmp->window_count = win_count();
- } else
+ }
+ } else {
parmp->window_count = 1;
+ }
if (recoverymode) { // do recover
msg_scroll = true; // scroll message up
@@ -1511,17 +1453,20 @@ static void create_windows(mparm_T *parmp)
dorewind = TRUE;
while (done++ < 1000) {
if (dorewind) {
- if (parmp->window_layout == WIN_TABS)
+ if (parmp->window_layout == WIN_TABS) {
goto_tabpage(1);
- else
+ } else {
curwin = firstwin;
+ }
} else if (parmp->window_layout == WIN_TABS) {
- if (curtab->tp_next == NULL)
+ if (curtab->tp_next == NULL) {
break;
+ }
goto_tabpage(0);
} else {
- if (curwin->w_next == NULL)
+ if (curwin->w_next == NULL) {
break;
+ }
curwin = curwin->w_next;
}
dorewind = FALSE;
@@ -1535,13 +1480,13 @@ static void create_windows(mparm_T *parmp)
swap_exists_action = SEA_DIALOG;
set_buflisted(TRUE);
- /* create memfile, read file */
+ // create memfile, read file
(void)open_buffer(FALSE, NULL, 0);
if (swap_exists_action == SEA_QUIT) {
if (got_int || only_one_window()) {
- /* abort selected or quit and only one window */
- did_emsg = FALSE; /* avoid hit-enter prompt */
+ // abort selected or quit and only one window
+ did_emsg = FALSE; // avoid hit-enter prompt
getout(1);
}
/* We can't close the window, it would disturb what
@@ -1550,20 +1495,22 @@ static void create_windows(mparm_T *parmp)
setfname(curbuf, NULL, NULL, false);
curwin->w_arg_idx = -1;
swap_exists_action = SEA_NONE;
- } else
+ } else {
handle_swap_exists(NULL);
- dorewind = TRUE; /* start again */
+ }
+ dorewind = TRUE; // start again
}
os_breakcheck();
if (got_int) {
- (void)vgetc(); /* only break the file loading, not the rest */
+ (void)vgetc(); // only break the file loading, not the rest
break;
}
}
- if (parmp->window_layout == WIN_TABS)
+ if (parmp->window_layout == WIN_TABS) {
goto_tabpage(1);
- else
+ } else {
curwin = firstwin;
+ }
curbuf = curwin->w_buffer;
--autocmd_no_enter;
--autocmd_no_leave;
@@ -1574,10 +1521,10 @@ static void create_windows(mparm_T *parmp)
/// windows. make_windows() has already opened the windows.
static void edit_buffers(mparm_T *parmp, char_u *cwd)
{
- int arg_idx; /* index in argument list */
+ int arg_idx; // index in argument list
int i;
bool advance = true;
- win_T *win;
+ win_T *win;
char *p_shm_save = NULL;
/*
@@ -1586,7 +1533,7 @@ static void edit_buffers(mparm_T *parmp, char_u *cwd)
++autocmd_no_enter;
++autocmd_no_leave;
- /* When w_arg_idx is -1 remove the window (see create_windows()). */
+ // When w_arg_idx is -1 remove the window (see create_windows()).
if (curwin->w_arg_idx == -1) {
win_close(curwin, true);
advance = false;
@@ -1607,8 +1554,9 @@ static void edit_buffers(mparm_T *parmp, char_u *cwd)
if (advance) {
if (parmp->window_layout == WIN_TABS) {
- if (curtab->tp_next == NULL) /* just checking */
+ if (curtab->tp_next == NULL) { // just checking
break;
+ }
goto_tabpage(0);
// Temporarily reset 'shm' option to not print fileinfo when
// loading the other buffers. This would overwrite the already
@@ -1621,8 +1569,9 @@ static void edit_buffers(mparm_T *parmp, char_u *cwd)
set_option_value("shm", 0L, buf, 0);
}
} else {
- if (curwin->w_next == NULL) /* just checking */
+ if (curwin->w_next == NULL) { // just checking
break;
+ }
win_enter(curwin->w_next, false);
}
}
@@ -1634,15 +1583,15 @@ static void edit_buffers(mparm_T *parmp, char_u *cwd)
curwin->w_arg_idx = arg_idx;
/* Edit file from arg list, if there is one. When "Quit" selected
* at the ATTENTION prompt close the window. */
- swap_exists_did_quit = FALSE;
+ swap_exists_did_quit = false;
(void)do_ecmd(0, arg_idx < GARGCOUNT
? alist_name(&GARGLIST[arg_idx]) : NULL,
- NULL, NULL, ECMD_LASTL, ECMD_HIDE, curwin);
+ NULL, NULL, ECMD_LASTL, ECMD_HIDE, curwin);
if (swap_exists_did_quit) {
- /* abort or quit selected */
+ // abort or quit selected
if (got_int || only_one_window()) {
- /* abort selected and only one window */
- did_emsg = FALSE; /* avoid hit-enter prompt */
+ // abort selected and only one window
+ did_emsg = FALSE; // avoid hit-enter prompt
getout(1);
}
win_close(curwin, true);
@@ -1655,7 +1604,7 @@ static void edit_buffers(mparm_T *parmp, char_u *cwd)
}
os_breakcheck();
if (got_int) {
- (void)vgetc(); /* only break the file loading, not the rest */
+ (void)vgetc(); // only break the file loading, not the rest
break;
}
}
@@ -1665,13 +1614,14 @@ static void edit_buffers(mparm_T *parmp, char_u *cwd)
xfree(p_shm_save);
}
- if (parmp->window_layout == WIN_TABS)
+ if (parmp->window_layout == WIN_TABS) {
goto_tabpage(1);
+ }
--autocmd_no_enter;
- /* make the first window the current window */
+ // make the first window the current window
win = firstwin;
- /* Avoid making a preview window the current window. */
+ // Avoid making a preview window the current window.
while (win->w_p_pvw) {
win = win->w_next;
if (win == NULL) {
@@ -1683,8 +1633,9 @@ static void edit_buffers(mparm_T *parmp, char_u *cwd)
--autocmd_no_leave;
TIME_MSG("editing files in windows");
- if (parmp->window_count > 1 && parmp->window_layout != WIN_TABS)
- win_equal(curwin, false, 'b'); /* adjust heights */
+ if (parmp->window_count > 1 && parmp->window_layout != WIN_TABS) {
+ win_equal(curwin, false, 'b'); // adjust heights
+ }
}
/*
@@ -1697,7 +1648,7 @@ static void exe_pre_commands(mparm_T *parmp)
int i;
if (cnt > 0) {
- curwin->w_cursor.lnum = 0; /* just in case.. */
+ curwin->w_cursor.lnum = 0; // just in case..
sourcing_name = (char_u *)_("pre-vimrc command line");
current_sctx.sc_sid = SID_CMDARG;
for (i = 0; i < cnt; i++) {
@@ -1722,15 +1673,17 @@ static void exe_commands(mparm_T *parmp)
* with g`" was used.
*/
msg_scroll = TRUE;
- if (parmp->tagname == NULL && curwin->w_cursor.lnum <= 1)
+ if (parmp->tagname == NULL && curwin->w_cursor.lnum <= 1) {
curwin->w_cursor.lnum = 0;
+ }
sourcing_name = (char_u *)"command line";
current_sctx.sc_sid = SID_CARG;
current_sctx.sc_seq = 0;
for (i = 0; i < parmp->n_commands; i++) {
do_cmdline_cmd(parmp->commands[i]);
- if (parmp->cmds_tofree[i])
+ if (parmp->cmds_tofree[i]) {
xfree(parmp->commands[i]);
+ }
}
sourcing_name = NULL;
current_sctx.sc_sid = 0;
@@ -1738,12 +1691,14 @@ static void exe_commands(mparm_T *parmp)
curwin->w_cursor.lnum = 1;
}
- if (!exmode_active)
+ if (!exmode_active) {
msg_scroll = FALSE;
+ }
- /* When started with "-q errorfile" jump to first error again. */
- if (parmp->edit_type == EDIT_QF)
+ // When started with "-q errorfile" jump to first error again.
+ if (parmp->edit_type == EDIT_QF) {
qf_jump(NULL, 0, 0, FALSE);
+ }
TIME_MSG("executing command arguments");
}
@@ -1773,7 +1728,7 @@ static void do_system_initialization(void)
memcpy(vimrc, dir, dir_len);
vimrc[dir_len] = PATHSEP;
memcpy(vimrc + dir_len + 1, path_tail, sizeof(path_tail));
- if (do_source((char_u *)vimrc, false, DOSO_NONE) != FAIL) {
+ if (do_source((char_u *)vimrc, false, DOSO_NONE) != FAIL) {
xfree(vimrc);
xfree(config_dirs);
return;
@@ -1810,22 +1765,23 @@ static bool do_user_initialization(void)
}
char_u *init_lua_path = (char_u *)stdpaths_user_conf_subpath("init.lua");
+ char_u *user_vimrc = (char_u *)stdpaths_user_conf_subpath("init.vim");
+
+ // init.lua
if (os_path_exists(init_lua_path)
&& do_source(init_lua_path, true, DOSO_VIMRC)) {
- os_setenv("MYVIMRC", (const char *)init_lua_path, 1);
- char_u *vimrc_path = (char_u *)stdpaths_user_conf_subpath("init.vim");
-
- if (os_path_exists(vimrc_path)) {
- EMSG3(_("Conflicting configs: \"%s\" \"%s\""), init_lua_path, vimrc_path);
+ if (os_path_exists(user_vimrc)) {
+ EMSG3(_("E5422: Conflicting configs: \"%s\" \"%s\""), init_lua_path,
+ user_vimrc);
}
- xfree(vimrc_path);
+ xfree(user_vimrc);
xfree(init_lua_path);
return false;
}
xfree(init_lua_path);
- char_u *user_vimrc = (char_u *)stdpaths_user_conf_subpath("init.vim");
+ // init.vim
if (do_source(user_vimrc, true, DOSO_VIMRC) != FAIL) {
do_exrc = p_exrc;
if (do_exrc) {
@@ -1837,6 +1793,7 @@ static bool do_user_initialization(void)
return do_exrc;
}
xfree(user_vimrc);
+
char *const config_dirs = stdpaths_get_xdg_var(kXDGConfigDirs);
if (config_dirs != NULL) {
const void *iter = NULL;
@@ -1853,7 +1810,7 @@ static bool do_user_initialization(void)
memmove(vimrc, dir, dir_len);
vimrc[dir_len] = PATHSEP;
memmove(vimrc + dir_len + 1, path_tail, sizeof(path_tail));
- if (do_source((char_u *) vimrc, true, DOSO_VIMRC) != FAIL) {
+ if (do_source((char_u *)vimrc, true, DOSO_VIMRC) != FAIL) {
do_exrc = p_exrc;
if (do_exrc) {
do_exrc = (path_full_compare((char_u *)VIMRC_FILE, (char_u *)vimrc,
@@ -1867,6 +1824,7 @@ static bool do_user_initialization(void)
} while (iter != NULL);
xfree(config_dirs);
}
+
if (execute_env("EXINIT") == OK) {
do_exrc = p_exrc;
return do_exrc;
@@ -1903,7 +1861,7 @@ static void source_startup_scripts(const mparm_T *const parmp)
// If vimrc file is not owned by user, set 'secure' mode.
if (!file_owned(VIMRC_FILE))
#endif
- secure = p_secure;
+ secure = p_secure;
if (do_source((char_u *)VIMRC_FILE, true, DOSO_VIMRC) == FAIL) {
#if defined(UNIX)
@@ -2000,10 +1958,10 @@ static void mainerr(const char *errstr, const char *str)
/// Prints version information for "nvim -v" or "nvim --version".
static void version(void)
{
- info_message = TRUE; // use mch_msg(), not mch_errmsg()
+ info_message = true; // use mch_msg(), not mch_errmsg()
list_version();
msg_putchar('\n');
- msg_didout = FALSE;
+ msg_didout = false;
}
/// Prints help message for "nvim -h" or "nvim --help".
@@ -2059,7 +2017,8 @@ static void usage(void)
*/
static void check_swap_exists_action(void)
{
- if (swap_exists_action == SEA_QUIT)
+ if (swap_exists_action == SEA_QUIT) {
getout(1);
+ }
handle_swap_exists(NULL);
}
diff --git a/src/nvim/main.h b/src/nvim/main.h
index 61252f2bce..d387e6d668 100644
--- a/src/nvim/main.h
+++ b/src/nvim/main.h
@@ -30,6 +30,7 @@ typedef struct {
bool input_isatty; // stdin is a terminal
bool output_isatty; // stdout is a terminal
bool err_isatty; // stderr is a terminal
+ bool input_neverscript; // never treat stdin as script (-E/-Es)
int no_swap_file; // "-n" argument used
int use_debug_break_level;
int window_count; // number of windows to use
diff --git a/src/nvim/map.c b/src/nvim/map.c
index 7d97b7f13d..20d5570e8c 100644
--- a/src/nvim/map.c
+++ b/src/nvim/map.c
@@ -8,20 +8,18 @@
// khash.h does not make its own copy of the key or value.
//
-#include <stdlib.h>
+#include <lauxlib.h>
+#include <lua.h>
#include <stdbool.h>
+#include <stdlib.h>
#include <string.h>
-#include <lua.h>
-#include <lauxlib.h>
-
+#include "nvim/api/private/dispatch.h"
+#include "nvim/lib/khash.h"
#include "nvim/map.h"
#include "nvim/map_defs.h"
-#include "nvim/vim.h"
#include "nvim/memory.h"
-#include "nvim/api/private/dispatch.h"
-
-#include "nvim/lib/khash.h"
+#include "nvim/vim.h"
#define cstr_t_hash kh_str_hash_func
#define cstr_t_eq kh_str_hash_equal
@@ -38,11 +36,11 @@
#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
@@ -52,58 +50,50 @@
#define MAP_IMPL(T, U, ...) \
INITIALIZER_DECLARE(T, U, __VA_ARGS__); \
- __KHASH_IMPL(T##_##U##_map,, T, U, 1, T##_hash, T##_eq) \
- \
- Map(T, U) *map_##T##_##U##_new() \
- { \
- Map(T, U) *rv = xmalloc(sizeof(Map(T, U))); \
- rv->table = kh_init(T##_##U##_map); \
- return rv; \
- } \
+ __KHASH_IMPL(T##_##U##_map, , T, U, 1, T##_hash, T##_eq) \
\
- void map_##T##_##U##_free(Map(T, U) *map) \
+ void map_##T##_##U##_destroy(Map(T, U) *map) \
{ \
- kh_destroy(T##_##U##_map, map->table); \
- xfree(map); \
+ kh_dealloc(T##_##U##_map, &map->table); \
} \
\
U map_##T##_##U##_get(Map(T, U) *map, T key) \
{ \
khiter_t k; \
\
- if ((k = kh_get(T##_##U##_map, map->table, key)) == kh_end(map->table)) { \
+ if ((k = kh_get(T##_##U##_map, &map->table, key)) == kh_end(&map->table)) { \
return INITIALIZER(T, U); \
} \
\
- return kh_val(map->table, k); \
+ return kh_val(&map->table, k); \
} \
\
bool map_##T##_##U##_has(Map(T, U) *map, T key) \
{ \
- return kh_get(T##_##U##_map, map->table, key) != kh_end(map->table); \
+ return kh_get(T##_##U##_map, &map->table, key) != kh_end(&map->table); \
} \
\
T map_##T##_##U##_key(Map(T, U) *map, T key) \
{ \
khiter_t k; \
\
- if ((k = kh_get(T##_##U##_map, map->table, key)) == kh_end(map->table)) { \
+ if ((k = kh_get(T##_##U##_map, &map->table, key)) == kh_end(&map->table)) { \
abort(); /* Caller must check map_has(). */ \
} \
\
- return kh_key(map->table, k); \
+ return kh_key(&map->table, k); \
} \
U map_##T##_##U##_put(Map(T, U) *map, T key, U value) \
{ \
int ret; \
U rv = INITIALIZER(T, U); \
- khiter_t k = kh_put(T##_##U##_map, map->table, key, &ret); \
+ khiter_t k = kh_put(T##_##U##_map, &map->table, key, &ret); \
\
if (!ret) { \
- rv = kh_val(map->table, k); \
+ rv = kh_val(&map->table, k); \
} \
\
- kh_val(map->table, k) = value; \
+ kh_val(&map->table, k) = value; \
return rv; \
} \
\
@@ -112,18 +102,18 @@
int ret; \
khiter_t k; \
if (put) { \
- k = kh_put(T##_##U##_map, map->table, key, &ret); \
+ k = kh_put(T##_##U##_map, &map->table, key, &ret); \
if (ret) { \
- kh_val(map->table, k) = INITIALIZER(T, U); \
+ kh_val(&map->table, k) = INITIALIZER(T, U); \
} \
} else { \
- k = kh_get(T##_##U##_map, map->table, key); \
- if (k == kh_end(map->table)) { \
+ k = kh_get(T##_##U##_map, &map->table, key); \
+ if (k == kh_end(&map->table)) { \
return NULL; \
} \
} \
\
- return &kh_val(map->table, k); \
+ return &kh_val(&map->table, k); \
} \
\
U map_##T##_##U##_del(Map(T, U) *map, T key) \
@@ -131,9 +121,9 @@
U rv = INITIALIZER(T, U); \
khiter_t k; \
\
- if ((k = kh_get(T##_##U##_map, map->table, key)) != kh_end(map->table)) { \
- rv = kh_val(map->table, k); \
- kh_del(T##_##U##_map, map->table, k); \
+ if ((k = kh_get(T##_##U##_map, &map->table, key)) != kh_end(&map->table)) { \
+ rv = kh_val(&map->table, k); \
+ kh_del(T##_##U##_map, &map->table, k); \
} \
\
return rv; \
@@ -141,7 +131,7 @@
\
void map_##T##_##U##_clear(Map(T, U) *map) \
{ \
- kh_clear(T##_##U##_map, map->table); \
+ kh_clear(T##_##U##_map, &map->table); \
}
static inline khint_t String_hash(String s)
@@ -194,11 +184,12 @@ static inline bool ColorKey_eq(ColorKey ae1, ColorKey ae2)
MAP_IMPL(int, int, DEFAULT_INITIALIZER)
MAP_IMPL(cstr_t, ptr_t, DEFAULT_INITIALIZER)
+MAP_IMPL(cstr_t, int, DEFAULT_INITIALIZER)
MAP_IMPL(ptr_t, ptr_t, DEFAULT_INITIALIZER)
MAP_IMPL(uint64_t, ptr_t, DEFAULT_INITIALIZER)
MAP_IMPL(uint64_t, ssize_t, SSIZE_INITIALIZER)
MAP_IMPL(uint64_t, uint64_t, DEFAULT_INITIALIZER)
-#define EXTMARK_NS_INITIALIZER { 0, 0 }
+#define EXTMARK_NS_INITIALIZER { { MAP_INIT }, 1 }
MAP_IMPL(uint64_t, ExtmarkNs, EXTMARK_NS_INITIALIZER)
#define EXTMARK_ITEM_INITIALIZER { 0, 0, NULL }
MAP_IMPL(uint64_t, ExtmarkItem, EXTMARK_ITEM_INITIALIZER)
diff --git a/src/nvim/map.h b/src/nvim/map.h
index 7bd3d31330..d6515878a2 100644
--- a/src/nvim/map.h
+++ b/src/nvim/map.h
@@ -18,11 +18,12 @@
KHASH_DECLARE(T##_##U##_map, T, U) \
\
typedef struct { \
- khash_t(T##_##U##_map) *table; \
+ khash_t(T##_##U##_map) table; \
} Map(T, U); \
\
Map(T, U) *map_##T##_##U##_new(void); \
void map_##T##_##U##_free(Map(T, U) *map); \
+ void map_##T##_##U##_destroy(Map(T, U) *map); \
U map_##T##_##U##_get(Map(T, U) *map, T key); \
bool map_##T##_##U##_has(Map(T, U) *map, T key); \
T map_##T##_##U##_key(Map(T, U) *map, T key); \
@@ -36,6 +37,7 @@
//
MAP_DECLS(int, int)
MAP_DECLS(cstr_t, ptr_t)
+MAP_DECLS(cstr_t, int)
MAP_DECLS(ptr_t, ptr_t)
MAP_DECLS(uint64_t, ptr_t)
MAP_DECLS(uint64_t, ssize_t)
@@ -44,7 +46,7 @@ MAP_DECLS(uint64_t, uint64_t)
// NB: this is the only way to define a struct both containing and contained
// in a map...
typedef struct ExtmarkNs { // For namespacing extmarks
- Map(uint64_t, uint64_t) *map; // For fast lookup
+ Map(uint64_t, uint64_t) map[1]; // For fast lookup
uint64_t free_id; // For automatically assigning id's
} ExtmarkNs;
@@ -57,8 +59,10 @@ MAP_DECLS(String, handle_T)
MAP_DECLS(ColorKey, ColorItem)
-#define map_new(T, U) map_##T##_##U##_new
-#define map_free(T, U) map_##T##_##U##_free
+#define MAP_INIT { { 0, 0, 0, 0, NULL, NULL, NULL } }
+#define map_init(k, v, map) do { *(map) = (Map(k, v))MAP_INIT; } while (false)
+
+#define map_destroy(T, U) map_##T##_##U##_destroy
#define map_get(T, U) map_##T##_##U##_get
#define map_has(T, U) map_##T##_##U##_has
#define map_key(T, U) map_##T##_##U##_key
@@ -67,10 +71,9 @@ MAP_DECLS(ColorKey, ColorItem)
#define map_del(T, U) map_##T##_##U##_del
#define map_clear(T, U) map_##T##_##U##_clear
-#define map_size(map) ((map)->table->size)
+#define map_size(map) ((map)->table.size)
-#define pmap_new(T) map_new(T, ptr_t)
-#define pmap_free(T) map_free(T, ptr_t)
+#define pmap_destroy(T) map_destroy(T, ptr_t)
#define pmap_get(T) map_get(T, ptr_t)
#define pmap_has(T) map_has(T, ptr_t)
#define pmap_key(T) map_key(T, ptr_t)
@@ -79,12 +82,13 @@ MAP_DECLS(ColorKey, ColorItem)
/// @see pmap_del2
#define pmap_del(T) map_del(T, ptr_t)
#define pmap_clear(T) map_clear(T, ptr_t)
+#define pmap_init(k, map) map_init(k, ptr_t, map)
#define map_foreach(map, key, value, block) \
- kh_foreach(map->table, key, value, block)
+ kh_foreach(&(map)->table, key, value, block)
#define map_foreach_value(map, value, block) \
- kh_foreach_value(map->table, value, block)
+ kh_foreach_value(&(map)->table, value, block)
void pmap_del2(PMap(cstr_t) *map, const char *key);
diff --git a/src/nvim/mark.c b/src/nvim/mark.c
index 73a9c1d1d7..b296bf39cf 100644
--- a/src/nvim/mark.c
+++ b/src/nvim/mark.c
@@ -7,35 +7,35 @@
#include <assert.h>
#include <inttypes.h>
-#include <string.h>
#include <limits.h>
+#include <string.h>
-#include "nvim/vim.h"
#include "nvim/ascii.h"
-#include "nvim/mark.h"
#include "nvim/buffer.h"
#include "nvim/charset.h"
#include "nvim/diff.h"
#include "nvim/eval.h"
#include "nvim/ex_cmds.h"
+#include "nvim/extmark.h"
#include "nvim/fileio.h"
#include "nvim/fold.h"
-#include "nvim/extmark.h"
+#include "nvim/mark.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/normal.h"
#include "nvim/option.h"
+#include "nvim/os/input.h"
+#include "nvim/os/os.h"
+#include "nvim/os/time.h"
#include "nvim/path.h"
#include "nvim/quickfix.h"
#include "nvim/search.h"
#include "nvim/sign.h"
#include "nvim/strings.h"
#include "nvim/ui.h"
-#include "nvim/os/os.h"
-#include "nvim/os/time.h"
-#include "nvim/os/input.h"
+#include "nvim/vim.h"
/*
* This file contains routines to maintain and manipulate marks.
@@ -94,21 +94,23 @@ int setmark_pos(int c, pos_T *pos, int fnum)
{
int i;
- /* Check for a special key (may cause islower() to crash). */
- if (c < 0)
+ // Check for a special key (may cause islower() to crash).
+ if (c < 0) {
return FAIL;
+ }
if (c == '\'' || c == '`') {
if (pos == &curwin->w_cursor) {
setpcmark();
- /* keep it even when the cursor doesn't move */
+ // keep it even when the cursor doesn't move
curwin->w_prev_pcmark = curwin->w_pcmark;
- } else
+ } else {
curwin->w_pcmark = *pos;
+ }
return OK;
}
- // Can't set a mark in a non-existant buffer.
+ // Can't set a mark in a non-existent buffer.
buf_T *buf = buflist_findnr(fnum);
if (buf == NULL) {
return FAIL;
@@ -166,11 +168,12 @@ int setmark_pos(int c, pos_T *pos, int fnum)
*/
void setpcmark(void)
{
- xfmark_T *fm;
+ xfmark_T *fm;
- /* for :global the mark is set only once */
- if (global_busy || listcmd_busy || cmdmod.keepjumps)
+ // for :global the mark is set only once
+ if (global_busy || listcmd_busy || cmdmod.keepjumps) {
return;
+ }
curwin->w_prev_pcmark = curwin->w_pcmark;
curwin->w_pcmark = curwin->w_cursor;
@@ -189,7 +192,7 @@ void setpcmark(void)
}
}
- /* If jumplist is full: remove oldest entry */
+ // If jumplist is full: remove oldest entry
if (++curwin->w_jumplistlen > JUMPLISTSIZE) {
curwin->w_jumplistlen = JUMPLISTSIZE;
free_xfmark(curwin->w_jumplist[0]);
@@ -214,7 +217,7 @@ void checkpcmark(void)
&& (equalpos(curwin->w_pcmark, curwin->w_cursor)
|| curwin->w_pcmark.lnum == 0)) {
curwin->w_pcmark = curwin->w_prev_pcmark;
- curwin->w_prev_pcmark.lnum = 0; /* Show it has been checked */
+ curwin->w_prev_pcmark.lnum = 0; // Show it has been checked
}
}
@@ -223,18 +226,20 @@ void checkpcmark(void)
*/
pos_T *movemark(int count)
{
- pos_T *pos;
- xfmark_T *jmp;
+ pos_T *pos;
+ xfmark_T *jmp;
cleanup_jumplist(curwin, true);
- if (curwin->w_jumplistlen == 0) /* nothing to jump to */
+ if (curwin->w_jumplistlen == 0) { // nothing to jump to
return (pos_T *)NULL;
+ }
for (;; ) {
if (curwin->w_jumplistidx + count < 0
- || curwin->w_jumplistidx + count >= curwin->w_jumplistlen)
+ || curwin->w_jumplistidx + count >= curwin->w_jumplistlen) {
return (pos_T *)NULL;
+ }
/*
* if first CTRL-O or CTRL-I command after a jump, add cursor position
@@ -243,30 +248,34 @@ pos_T *movemark(int count)
*/
if (curwin->w_jumplistidx == curwin->w_jumplistlen) {
setpcmark();
- --curwin->w_jumplistidx; /* skip the new entry */
- if (curwin->w_jumplistidx + count < 0)
+ --curwin->w_jumplistidx; // skip the new entry
+ if (curwin->w_jumplistidx + count < 0) {
return (pos_T *)NULL;
+ }
}
curwin->w_jumplistidx += count;
jmp = curwin->w_jumplist + curwin->w_jumplistidx;
- if (jmp->fmark.fnum == 0)
+ if (jmp->fmark.fnum == 0) {
fname2fnum(jmp);
+ }
if (jmp->fmark.fnum != curbuf->b_fnum) {
- /* jump to other file */
- if (buflist_findnr(jmp->fmark.fnum) == NULL) { /* Skip this one .. */
+ // jump to other file
+ if (buflist_findnr(jmp->fmark.fnum) == NULL) { // Skip this one ..
count += count < 0 ? -1 : 1;
continue;
}
if (buflist_getfile(jmp->fmark.fnum, jmp->fmark.mark.lnum,
- 0, FALSE) == FAIL)
+ 0, FALSE) == FAIL) {
return (pos_T *)NULL;
- /* Set lnum again, autocommands my have changed it */
+ }
+ // Set lnum again, autocommands my have changed it
curwin->w_cursor = jmp->fmark.mark;
pos = (pos_T *)-1;
- } else
+ } else {
pos = &(jmp->fmark.mark);
+ }
return pos;
}
}
@@ -278,20 +287,24 @@ pos_T *movechangelist(int count)
{
int n;
- if (curbuf->b_changelistlen == 0) /* nothing to jump to */
+ if (curbuf->b_changelistlen == 0) { // nothing to jump to
return (pos_T *)NULL;
+ }
n = curwin->w_changelistidx;
if (n + count < 0) {
- if (n == 0)
+ if (n == 0) {
return (pos_T *)NULL;
+ }
n = 0;
} else if (n + count >= curbuf->b_changelistlen) {
- if (n == curbuf->b_changelistlen - 1)
+ if (n == curbuf->b_changelistlen - 1) {
return (pos_T *)NULL;
+ }
n = curbuf->b_changelistlen - 1;
- } else
+ } else {
n += count;
+ }
curwin->w_changelistidx = n;
return &(curbuf->b_changelist[n].mark);
}
@@ -319,16 +332,17 @@ pos_T *getmark(int c, bool changefile)
pos_T *getmark_buf_fnum(buf_T *buf, int c, bool changefile, int *fnum)
{
- pos_T *posp;
- pos_T *startp, *endp;
+ pos_T *posp;
+ pos_T *startp, *endp;
static pos_T pos_copy;
posp = NULL;
/* Check for special key, can't be a mark name and might cause islower()
* to crash. */
- if (c < 0)
+ if (c < 0) {
return posp;
+ }
if (c > '~') { // check for islower()/isupper()
} else if (c == '\'' || c == '`') { // previous context mark
pos_copy = curwin->w_pcmark; // need to make a copy because
@@ -346,30 +360,30 @@ pos_T *getmark_buf_fnum(buf_T *buf, int c, bool changefile, int *fnum)
} else if (c == '{' || c == '}') { // to previous/next paragraph
pos_T pos;
oparg_T oa;
- int slcb = listcmd_busy;
+ bool slcb = listcmd_busy;
pos = curwin->w_cursor;
- listcmd_busy = TRUE; /* avoid that '' is changed */
+ listcmd_busy = true; // avoid that '' is changed
if (findpar(&oa.inclusive,
- c == '}' ? FORWARD : BACKWARD, 1L, NUL, FALSE)) {
+ c == '}' ? FORWARD : BACKWARD, 1L, NUL, FALSE)) {
pos_copy = curwin->w_cursor;
posp = &pos_copy;
}
curwin->w_cursor = pos;
listcmd_busy = slcb;
- } else if (c == '(' || c == ')') { /* to previous/next sentence */
+ } else if (c == '(' || c == ')') { // to previous/next sentence
pos_T pos;
- int slcb = listcmd_busy;
+ bool slcb = listcmd_busy;
pos = curwin->w_cursor;
- listcmd_busy = TRUE; /* avoid that '' is changed */
+ listcmd_busy = true; // avoid that '' is changed
if (findsent(c == ')' ? FORWARD : BACKWARD, 1L)) {
pos_copy = curwin->w_cursor;
posp = &pos_copy;
}
curwin->w_cursor = pos;
listcmd_busy = slcb;
- } else if (c == '<' || c == '>') { /* start/end of visual area */
+ } else if (c == '<' || c == '>') { // start/end of visual area
startp = &buf->b_visual.vi_start;
endp = &buf->b_visual.vi_end;
if (((c == '<') == lt(*startp, *endp) || endp->lnum == 0)
@@ -383,63 +397,62 @@ pos_T *getmark_buf_fnum(buf_T *buf, int c, bool changefile, int *fnum)
if (buf->b_visual.vi_mode == 'V') {
pos_copy = *posp;
posp = &pos_copy;
- if (c == '<')
+ if (c == '<') {
pos_copy.col = 0;
- else
+ } else {
pos_copy.col = MAXCOL;
+ }
pos_copy.coladd = 0;
}
- } else if (ASCII_ISLOWER(c)) { /* normal named mark */
+ } else if (ASCII_ISLOWER(c)) { // normal named mark
posp = &(buf->b_namedm[c - 'a'].mark);
- } else if (ASCII_ISUPPER(c) || ascii_isdigit(c)) { /* named file mark */
- if (ascii_isdigit(c))
+ } else if (ASCII_ISUPPER(c) || ascii_isdigit(c)) { // named file mark
+ if (ascii_isdigit(c)) {
c = c - '0' + NMARKS;
- else
+ } else {
c -= 'A';
+ }
posp = &(namedfm[c].fmark.mark);
if (namedfm[c].fmark.fnum == 0) {
fname2fnum(&namedfm[c]);
}
- if (fnum != NULL)
+ if (fnum != NULL) {
*fnum = namedfm[c].fmark.fnum;
- else if (namedfm[c].fmark.fnum != buf->b_fnum) {
- /* mark is in another file */
+ } else if (namedfm[c].fmark.fnum != buf->b_fnum) {
+ // mark is in another file
posp = &pos_copy;
if (namedfm[c].fmark.mark.lnum != 0
&& changefile && namedfm[c].fmark.fnum) {
if (buflist_getfile(namedfm[c].fmark.fnum,
- (linenr_T)1, GETF_SETMARK, FALSE) == OK) {
- /* Set the lnum now, autocommands could have changed it */
+ (linenr_T)1, GETF_SETMARK, FALSE) == OK) {
+ // Set the lnum now, autocommands could have changed it
curwin->w_cursor = namedfm[c].fmark.mark;
return (pos_T *)-1;
}
- pos_copy.lnum = -1; /* can't get file */
- } else
+ pos_copy.lnum = -1; // can't get file
+ } else {
pos_copy.lnum = 0; /* mark exists, but is not valid in
current buffer */
+ }
}
}
return posp;
}
-/*
- * Search for the next named mark in the current file.
- *
- * Returns pointer to pos_T of the next mark or NULL if no mark is found.
- */
-pos_T *
-getnextmark (
- pos_T *startpos, /* where to start */
- int dir, /* direction for search */
- int begin_line
-)
+/// Search for the next named mark in the current file.
+///
+/// @param startpos where to start
+/// @param dir direction for search
+///
+/// @return pointer to pos_T of the next mark or NULL if no mark is found.
+pos_T *getnextmark(pos_T *startpos, int dir, int begin_line)
{
int i;
- pos_T *result = NULL;
+ pos_T *result = NULL;
pos_T pos;
pos = *startpos;
@@ -448,21 +461,24 @@ getnextmark (
* position must be in a previous line.
* When searching forward and leaving the cursor on the first non-blank,
* position must be in a next line. */
- if (dir == BACKWARD && begin_line)
+ if (dir == BACKWARD && begin_line) {
pos.col = 0;
- else if (dir == FORWARD && begin_line)
+ } else if (dir == FORWARD && begin_line) {
pos.col = MAXCOL;
+ }
for (i = 0; i < NMARKS; i++) {
if (curbuf->b_namedm[i].mark.lnum > 0) {
if (dir == FORWARD) {
if ((result == NULL || lt(curbuf->b_namedm[i].mark, *result))
- && lt(pos, curbuf->b_namedm[i].mark))
+ && lt(pos, curbuf->b_namedm[i].mark)) {
result = &curbuf->b_namedm[i].mark;
+ }
} else {
if ((result == NULL || lt(*result, curbuf->b_namedm[i].mark))
- && lt(curbuf->b_namedm[i].mark, pos))
+ && lt(curbuf->b_namedm[i].mark, pos)) {
result = &curbuf->b_namedm[i].mark;
+ }
}
}
}
@@ -494,10 +510,11 @@ static void fname2fnum(xfmark_T *fm)
expand_env((char_u *)"~/", NameBuff, MAXPATHL);
len = (int)STRLEN(NameBuff);
STRLCPY(NameBuff + len, fm->fname + 2, MAXPATHL - len);
- } else
+ } else {
STRLCPY(NameBuff, fm->fname, MAXPATHL);
+ }
- /* Try to shorten the file name. */
+ // Try to shorten the file name.
os_dirname(IObuff, IOSIZE);
p = path_shorten_fname(NameBuff, IObuff);
@@ -513,14 +530,16 @@ static void fname2fnum(xfmark_T *fm)
*/
void fmarks_check_names(buf_T *buf)
{
- char_u *name = buf->b_ffname;
+ char_u *name = buf->b_ffname;
int i;
- if (buf->b_ffname == NULL)
+ if (buf->b_ffname == NULL) {
return;
+ }
- for (i = 0; i < NGLOBALMARKS; ++i)
+ for (i = 0; i < NGLOBALMARKS; ++i) {
fmarks_check_one(&namedfm[i], name, buf);
+ }
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
for (i = 0; i < wp->w_jumplistlen; ++i) {
@@ -552,8 +571,9 @@ int check_mark(pos_T *pos)
if (pos->lnum <= 0) {
/* lnum is negative if mark is in another file can can't get that
* file, error message already give then. */
- if (pos->lnum == 0)
+ if (pos->lnum == 0) {
EMSG(_(e_marknotset));
+ }
return FAIL;
}
if (pos->lnum > curbuf->b_ml.ml_line_count) {
@@ -593,8 +613,9 @@ void clrallmarks(buf_T *const buf)
*/
char_u *fm_getname(fmark_T *fmark, int lead_len)
{
- if (fmark->fnum == curbuf->b_fnum) /* current buffer */
+ if (fmark->fnum == curbuf->b_fnum) { // current buffer
return mark_line(&(fmark->mark), lead_len);
+ }
return buflist_nr2name(fmark->fnum, FALSE, TRUE);
}
@@ -604,11 +625,12 @@ char_u *fm_getname(fmark_T *fmark, int lead_len)
*/
static char_u *mark_line(pos_T *mp, int lead_len)
{
- char_u *s, *p;
+ char_u *s, *p;
int len;
- if (mp->lnum == 0 || mp->lnum > curbuf->b_ml.ml_line_count)
+ if (mp->lnum == 0 || mp->lnum > curbuf->b_ml.ml_line_count) {
return vim_strsave((char_u *)"-invalid-");
+ }
assert(Columns >= 0 && (size_t)Columns <= SIZE_MAX);
// Allow for up to 5 bytes per character.
s = vim_strnsave(skipwhite(ml_get(mp->lnum)), (size_t)Columns * 5);
@@ -617,8 +639,9 @@ static char_u *mark_line(pos_T *mp, int lead_len)
len = 0;
for (p = s; *p != NUL; MB_PTR_ADV(p)) {
len += ptr2cells(p);
- if (len >= Columns - lead_len)
+ if (len >= Columns - lead_len) {
break;
+ }
}
*p = NUL;
return s;
@@ -629,28 +652,32 @@ static char_u *mark_line(pos_T *mp, int lead_len)
*/
void ex_marks(exarg_T *eap)
{
- char_u *arg = eap->arg;
+ char_u *arg = eap->arg;
int i;
- char_u *name;
- pos_T *posp, *startp, *endp;
+ char_u *name;
+ pos_T *posp, *startp, *endp;
- if (arg != NULL && *arg == NUL)
+ if (arg != NULL && *arg == NUL) {
arg = NULL;
+ }
show_one_mark('\'', arg, &curwin->w_pcmark, NULL, true);
- for (i = 0; i < NMARKS; ++i)
+ for (i = 0; i < NMARKS; ++i) {
show_one_mark(i + 'a', arg, &curbuf->b_namedm[i].mark, NULL, true);
+ }
for (i = 0; i < NGLOBALMARKS; ++i) {
- if (namedfm[i].fmark.fnum != 0)
+ if (namedfm[i].fmark.fnum != 0) {
name = fm_getname(&namedfm[i].fmark, 15);
- else
+ } else {
name = namedfm[i].fname;
+ }
if (name != NULL) {
show_one_mark(i >= NMARKS ? i - NMARKS + '0' : i + 'A',
- arg, &namedfm[i].fmark.mark, name,
- namedfm[i].fmark.fnum == curbuf->b_fnum);
- if (namedfm[i].fmark.fnum != 0)
+ arg, &namedfm[i].fmark.mark, name,
+ namedfm[i].fmark.fnum == curbuf->b_fnum);
+ if (namedfm[i].fmark.fnum != 0) {
xfree(name);
+ }
}
}
show_one_mark('"', arg, &curbuf->b_last_cursor.mark, NULL, true);
@@ -673,14 +700,8 @@ void ex_marks(exarg_T *eap)
show_one_mark(-1, arg, NULL, NULL, false);
}
-static void
-show_one_mark(
- int c,
- char_u *arg,
- pos_T *p,
- char_u *name_arg,
- int current // in current file
-)
+/// @param current in current file
+static void show_one_mark(int c, char_u *arg, pos_T *p, char_u *name_arg, int current)
{
static bool did_title = false;
bool mustfree = false;
@@ -731,41 +752,42 @@ show_one_mark(
*/
void ex_delmarks(exarg_T *eap)
{
- char_u *p;
+ char_u *p;
int from, to;
int i;
int lower;
int digit;
int n;
- if (*eap->arg == NUL && eap->forceit)
- /* clear all marks */
+ if (*eap->arg == NUL && eap->forceit) {
+ // clear all marks
clrallmarks(curbuf);
- else if (eap->forceit)
+ } else if (eap->forceit) {
EMSG(_(e_invarg));
- else if (*eap->arg == NUL)
+ } else if (*eap->arg == NUL) {
EMSG(_(e_argreq));
- else {
- /* clear specified marks only */
+ } else {
+ // clear specified marks only
for (p = eap->arg; *p != NUL; ++p) {
lower = ASCII_ISLOWER(*p);
digit = ascii_isdigit(*p);
if (lower || digit || ASCII_ISUPPER(*p)) {
if (p[1] == '-') {
- /* clear range of marks */
+ // clear range of marks
from = *p;
to = p[2];
if (!(lower ? ASCII_ISLOWER(p[2])
- : (digit ? ascii_isdigit(p[2])
- : ASCII_ISUPPER(p[2])))
+ : (digit ? ascii_isdigit(p[2])
+ : ASCII_ISUPPER(p[2])))
|| to < from) {
EMSG2(_(e_invarg2), p);
return;
}
p += 2;
- } else
- /* clear one lower case mark */
+ } else {
+ // clear one lower case mark
from = to = *p;
+ }
for (i = from; i <= to; ++i) {
if (lower) {
@@ -781,19 +803,29 @@ void ex_delmarks(exarg_T *eap)
XFREE_CLEAR(namedfm[n].fname);
}
}
- } else
+ } else {
switch (*p) {
- case '"': CLEAR_FMARK(&curbuf->b_last_cursor); break;
- case '^': CLEAR_FMARK(&curbuf->b_last_insert); break;
- case '.': CLEAR_FMARK(&curbuf->b_last_change); break;
- case '[': curbuf->b_op_start.lnum = 0; break;
- case ']': curbuf->b_op_end.lnum = 0; break;
- case '<': curbuf->b_visual.vi_start.lnum = 0; break;
- case '>': curbuf->b_visual.vi_end.lnum = 0; break;
- case ' ': break;
- default: EMSG2(_(e_invarg2), p);
+ case '"':
+ CLEAR_FMARK(&curbuf->b_last_cursor); break;
+ case '^':
+ CLEAR_FMARK(&curbuf->b_last_insert); break;
+ case '.':
+ CLEAR_FMARK(&curbuf->b_last_change); break;
+ case '[':
+ curbuf->b_op_start.lnum = 0; break;
+ case ']':
+ curbuf->b_op_end.lnum = 0; break;
+ case '<':
+ curbuf->b_visual.vi_start.lnum = 0; break;
+ case '>':
+ curbuf->b_visual.vi_end.lnum = 0; break;
+ case ' ':
+ break;
+ default:
+ EMSG2(_(e_invarg2), p);
return;
}
+ }
}
}
}
@@ -804,7 +836,7 @@ void ex_delmarks(exarg_T *eap)
void ex_jumps(exarg_T *eap)
{
int i;
- char_u *name;
+ char_u *name;
cleanup_jumplist(curwin, true);
// Highlight title
@@ -825,11 +857,11 @@ void ex_jumps(exarg_T *eap)
break;
}
sprintf((char *)IObuff, "%c %2d %5ld %4d ",
- i == curwin->w_jumplistidx ? '>' : ' ',
- i > curwin->w_jumplistidx ? i - curwin->w_jumplistidx
- : curwin->w_jumplistidx - i,
- curwin->w_jumplist[i].fmark.mark.lnum,
- curwin->w_jumplist[i].fmark.mark.col);
+ i == curwin->w_jumplistidx ? '>' : ' ',
+ i > curwin->w_jumplistidx ? i - curwin->w_jumplistidx
+ : curwin->w_jumplistidx - i,
+ curwin->w_jumplist[i].fmark.mark.lnum,
+ curwin->w_jumplist[i].fmark.mark.col);
msg_outtrans(IObuff);
msg_outtrans_attr(name,
curwin->w_jumplist[i].fmark.fnum == curbuf->b_fnum
@@ -839,8 +871,9 @@ void ex_jumps(exarg_T *eap)
}
ui_flush();
}
- if (curwin->w_jumplistidx == curwin->w_jumplistlen)
+ if (curwin->w_jumplistidx == curwin->w_jumplistlen) {
MSG_PUTS("\n>");
+ }
}
void ex_clearjumps(exarg_T *eap)
@@ -856,7 +889,7 @@ void ex_clearjumps(exarg_T *eap)
void ex_changes(exarg_T *eap)
{
int i;
- char_u *name;
+ char_u *name;
// Highlight title
MSG_PUTS_TITLE(_("\nchange line col text"));
@@ -864,14 +897,15 @@ void ex_changes(exarg_T *eap)
for (i = 0; i < curbuf->b_changelistlen && !got_int; ++i) {
if (curbuf->b_changelist[i].mark.lnum != 0) {
msg_putchar('\n');
- if (got_int)
+ if (got_int) {
break;
+ }
sprintf((char *)IObuff, "%c %3d %5ld %4d ",
- i == curwin->w_changelistidx ? '>' : ' ',
- i > curwin->w_changelistidx ? i - curwin->w_changelistidx
- : curwin->w_changelistidx - i,
- (long)curbuf->b_changelist[i].mark.lnum,
- curbuf->b_changelist[i].mark.col);
+ i == curwin->w_changelistidx ? '>' : ' ',
+ i > curwin->w_changelistidx ? i - curwin->w_changelistidx
+ : curwin->w_changelistidx - i,
+ (long)curbuf->b_changelist[i].mark.lnum,
+ curbuf->b_changelist[i].mark.col);
msg_outtrans(IObuff);
name = mark_line(&curbuf->b_changelist[i].mark, 17);
msg_outtrans_attr(name, HL_ATTR(HLF_D));
@@ -880,8 +914,9 @@ void ex_changes(exarg_T *eap)
}
ui_flush();
}
- if (curwin->w_changelistidx == curbuf->b_changelistlen)
+ if (curwin->w_changelistidx == curbuf->b_changelistlen) {
MSG_PUTS("\n>");
+ }
}
#define one_adjust(add) \
@@ -890,27 +925,27 @@ void ex_changes(exarg_T *eap)
if (*lp >= line1 && *lp <= line2) \
{ \
if (amount == MAXLNUM) \
- *lp = 0; \
+ *lp = 0; \
else \
- *lp += amount; \
+ *lp += amount; \
} \
else if (amount_after && *lp > line2) \
- *lp += amount_after; \
+ *lp += amount_after; \
}
-/* don't delete the line, just put at first deleted line */
+// don't delete the line, just put at first deleted line
#define one_adjust_nodel(add) \
{ \
lp = add; \
if (*lp >= line1 && *lp <= line2) \
{ \
if (amount == MAXLNUM) \
- *lp = line1; \
+ *lp = line1; \
else \
- *lp += amount; \
+ *lp += amount; \
} \
else if (amount_after && *lp > line2) \
- *lp += amount_after; \
+ *lp += amount_after; \
}
/*
@@ -922,13 +957,9 @@ void ex_changes(exarg_T *eap)
* If 'amount_after' is non-zero adjust marks after line2.
* Example: Delete lines 34 and 35: mark_adjust(34, 35, MAXLNUM, -2);
* Example: Insert two lines below 55: mark_adjust(56, MAXLNUM, 2, 0);
- * or: mark_adjust(56, 55, MAXLNUM, 2);
+ * or: mark_adjust(56, 55, MAXLNUM, 2);
*/
-void mark_adjust(linenr_T line1,
- linenr_T line2,
- long amount,
- long amount_after,
- ExtmarkOp op)
+void mark_adjust(linenr_T line1, linenr_T line2, long amount, long amount_after, ExtmarkOp op)
{
mark_adjust_internal(line1, line2, amount, amount_after, true, op);
}
@@ -938,54 +969,56 @@ void mark_adjust(linenr_T line1,
// This is only useful when folds need to be moved in a way different to
// calling foldMarkAdjust() with arguments line1, line2, amount, amount_after,
// for an example of why this may be necessary, see do_move().
-void mark_adjust_nofold(linenr_T line1, linenr_T line2, long amount,
- long amount_after,
+void mark_adjust_nofold(linenr_T line1, linenr_T line2, long amount, long amount_after,
ExtmarkOp op)
{
mark_adjust_internal(line1, line2, amount, amount_after, false, op);
}
-static void mark_adjust_internal(linenr_T line1, linenr_T line2,
- long amount, long amount_after,
- bool adjust_folds,
- ExtmarkOp op)
+static void mark_adjust_internal(linenr_T line1, linenr_T line2, long amount, long amount_after,
+ bool adjust_folds, ExtmarkOp op)
{
int i;
int fnum = curbuf->b_fnum;
- linenr_T *lp;
+ linenr_T *lp;
static pos_T initpos = { 1, 0, 0 };
- if (line2 < line1 && amount_after == 0L) /* nothing to do */
+ if (line2 < line1 && amount_after == 0L) { // nothing to do
return;
+ }
if (!cmdmod.lockmarks) {
- /* named marks, lower case and upper case */
+ // named marks, lower case and upper case
for (i = 0; i < NMARKS; i++) {
one_adjust(&(curbuf->b_namedm[i].mark.lnum));
- if (namedfm[i].fmark.fnum == fnum)
+ if (namedfm[i].fmark.fnum == fnum) {
one_adjust_nodel(&(namedfm[i].fmark.mark.lnum));
+ }
}
for (i = NMARKS; i < NGLOBALMARKS; i++) {
- if (namedfm[i].fmark.fnum == fnum)
+ if (namedfm[i].fmark.fnum == fnum) {
one_adjust_nodel(&(namedfm[i].fmark.mark.lnum));
+ }
}
- /* last Insert position */
+ // last Insert position
one_adjust(&(curbuf->b_last_insert.mark.lnum));
- /* last change position */
+ // last change position
one_adjust(&(curbuf->b_last_change.mark.lnum));
- /* last cursor position, if it was set */
- if (!equalpos(curbuf->b_last_cursor.mark, initpos))
+ // last cursor position, if it was set
+ if (!equalpos(curbuf->b_last_cursor.mark, initpos)) {
one_adjust(&(curbuf->b_last_cursor.mark.lnum));
+ }
- /* list of change positions */
- for (i = 0; i < curbuf->b_changelistlen; ++i)
+ // list of change positions
+ for (i = 0; i < curbuf->b_changelistlen; ++i) {
one_adjust_nodel(&(curbuf->b_changelist[i].mark.lnum));
+ }
- /* Visual area */
+ // Visual area
one_adjust_nodel(&(curbuf->b_visual.vi_start.lnum));
one_adjust_nodel(&(curbuf->b_visual.vi_end.lnum));
@@ -1008,15 +1041,16 @@ static void mark_adjust_internal(linenr_T line1, linenr_T line2,
}
}
- /* previous context mark */
+ // previous context mark
one_adjust(&(curwin->w_pcmark.lnum));
- /* previous pcmark */
+ // previous pcmark
one_adjust(&(curwin->w_prev_pcmark.lnum));
- /* saved cursor for formatting */
- if (saved_cursor.lnum != 0)
+ // saved cursor for formatting
+ if (saved_cursor.lnum != 0) {
one_adjust_nodel(&(saved_cursor.lnum));
+ }
/*
* Adjust items in all windows related to the current buffer.
@@ -1034,7 +1068,7 @@ static void mark_adjust_internal(linenr_T line1, linenr_T line2,
if (win->w_buffer == curbuf) {
if (!cmdmod.lockmarks) {
- /* marks in the tag stack */
+ // marks in the tag stack
for (i = 0; i < win->w_tagstacklen; i++) {
if (win->w_tagstack[i].fmark.fnum == fnum) {
one_adjust_nodel(&(win->w_tagstack[i].fmark.mark.lnum));
@@ -1042,7 +1076,7 @@ static void mark_adjust_internal(linenr_T line1, linenr_T line2,
}
}
- /* the displayed Visual area */
+ // the displayed Visual area
if (win->w_old_cursor_lnum != 0) {
one_adjust_nodel(&(win->w_old_cursor_lnum));
one_adjust_nodel(&(win->w_old_visual_lnum));
@@ -1052,13 +1086,13 @@ static void mark_adjust_internal(linenr_T line1, linenr_T line2,
* other than the current window */
if (win != curwin) {
if (win->w_topline >= line1 && win->w_topline <= line2) {
- if (amount == MAXLNUM) { /* topline is deleted */
+ if (amount == MAXLNUM) { // topline is deleted
if (line1 <= 1) {
win->w_topline = 1;
} else {
win->w_topline = line1 - 1;
}
- } else { /* keep topline on the same line */
+ } else { // keep topline on the same line
win->w_topline += amount;
}
win->w_topfill = 0;
@@ -1067,14 +1101,14 @@ static void mark_adjust_internal(linenr_T line1, linenr_T line2,
win->w_topfill = 0;
}
if (win->w_cursor.lnum >= line1 && win->w_cursor.lnum <= line2) {
- if (amount == MAXLNUM) { /* line with cursor is deleted */
+ if (amount == MAXLNUM) { // line with cursor is deleted
if (line1 <= 1) {
win->w_cursor.lnum = 1;
} else {
win->w_cursor.lnum = line1 - 1;
}
win->w_cursor.col = 0;
- } else { /* keep cursor on the same line */
+ } else { // keep cursor on the same line
win->w_cursor.lnum += amount;
}
} else if (amount_after && win->w_cursor.lnum > line2) {
@@ -1088,11 +1122,11 @@ static void mark_adjust_internal(linenr_T line1, linenr_T line2,
}
}
- /* adjust diffs */
+ // adjust diffs
diff_mark_adjust(line1, line2, amount, amount_after);
}
-/* This code is used often, needs to be fast. */
+// This code is used often, needs to be fast.
#define col_adjust(pp) \
{ \
posp = pp; \
@@ -1115,56 +1149,58 @@ static void mark_adjust_internal(linenr_T line1, linenr_T line2,
// position.
// "spaces_removed" is the number of spaces that were removed, matters when the
// cursor is inside them.
-void mark_col_adjust(
- linenr_T lnum, colnr_T mincol, long lnum_amount, long col_amount,
- int spaces_removed)
+void mark_col_adjust(linenr_T lnum, colnr_T mincol, long lnum_amount, long col_amount,
+ int spaces_removed)
{
int i;
int fnum = curbuf->b_fnum;
- pos_T *posp;
+ pos_T *posp;
- if ((col_amount == 0L && lnum_amount == 0L) || cmdmod.lockmarks)
- return; /* nothing to do */
-
- /* named marks, lower case and upper case */
+ if ((col_amount == 0L && lnum_amount == 0L) || cmdmod.lockmarks) {
+ return; // nothing to do
+ }
+ // named marks, lower case and upper case
for (i = 0; i < NMARKS; i++) {
col_adjust(&(curbuf->b_namedm[i].mark));
- if (namedfm[i].fmark.fnum == fnum)
+ if (namedfm[i].fmark.fnum == fnum) {
col_adjust(&(namedfm[i].fmark.mark));
+ }
}
for (i = NMARKS; i < NGLOBALMARKS; i++) {
- if (namedfm[i].fmark.fnum == fnum)
+ if (namedfm[i].fmark.fnum == fnum) {
col_adjust(&(namedfm[i].fmark.mark));
+ }
}
- /* last Insert position */
+ // last Insert position
col_adjust(&(curbuf->b_last_insert.mark));
- /* last change position */
+ // last change position
col_adjust(&(curbuf->b_last_change.mark));
- /* list of change positions */
- for (i = 0; i < curbuf->b_changelistlen; ++i)
+ // list of change positions
+ for (i = 0; i < curbuf->b_changelistlen; ++i) {
col_adjust(&(curbuf->b_changelist[i].mark));
+ }
- /* Visual area */
+ // Visual area
col_adjust(&(curbuf->b_visual.vi_start));
col_adjust(&(curbuf->b_visual.vi_end));
- /* previous context mark */
+ // previous context mark
col_adjust(&(curwin->w_pcmark));
- /* previous pcmark */
+ // previous pcmark
col_adjust(&(curwin->w_prev_pcmark));
- /* saved cursor for formatting */
+ // saved cursor for formatting
col_adjust(&saved_cursor);
/*
* Adjust items in all windows related to the current buffer.
*/
FOR_ALL_WINDOWS_IN_TAB(win, curtab) {
- /* marks in the jumplist */
+ // marks in the jumplist
for (i = 0; i < win->w_jumplistlen; ++i) {
if (win->w_jumplist[i].fmark.fnum == fnum) {
col_adjust(&(win->w_jumplist[i].fmark.mark));
@@ -1172,14 +1208,14 @@ void mark_col_adjust(
}
if (win->w_buffer == curbuf) {
- /* marks in the tag stack */
+ // marks in the tag stack
for (i = 0; i < win->w_tagstacklen; i++) {
if (win->w_tagstack[i].fmark.fnum == fnum) {
col_adjust(&(win->w_tagstack[i].fmark.mark));
}
}
- /* cursor position for other windows with the same buffer */
+ // cursor position for other windows with the same buffer
if (win != curwin) {
col_adjust(&win->w_cursor);
}
@@ -1269,8 +1305,9 @@ void copy_jumplist(win_T *from, win_T *to)
for (i = 0; i < from->w_jumplistlen; ++i) {
to->w_jumplist[i] = from->w_jumplist[i];
- if (from->w_jumplist[i].fname != NULL)
+ if (from->w_jumplist[i].fname != NULL) {
to->w_jumplist[i].fname = vim_strsave(from->w_jumplist[i].fname);
+ }
}
to->w_jumplistlen = from->w_jumplistlen;
to->w_jumplistidx = from->w_jumplistidx;
@@ -1287,18 +1324,17 @@ void copy_jumplist(win_T *from, win_T *to)
///
/// @return Pointer that needs to be passed to next `mark_jumplist_iter` call or
/// NULL if iteration is over.
-const void *mark_jumplist_iter(const void *const iter, const win_T *const win,
- xfmark_T *const fm)
+const void *mark_jumplist_iter(const void *const iter, const win_T *const win, xfmark_T *const fm)
FUNC_ATTR_NONNULL_ARG(2, 3) FUNC_ATTR_WARN_UNUSED_RESULT
{
if (iter == NULL && win->w_jumplistlen == 0) {
- *fm = (xfmark_T) {{{0, 0, 0}, 0, 0, NULL}, NULL};
+ *fm = (xfmark_T) { { { 0, 0, 0 }, 0, 0, NULL }, NULL };
return NULL;
}
const xfmark_T *const iter_mark =
- (iter == NULL
+ (iter == NULL
? &(win->w_jumplist[0])
- : (const xfmark_T *const) iter);
+ : (const xfmark_T *const)iter);
*fm = *iter_mark;
if (iter_mark == &(win->w_jumplist[win->w_jumplistlen - 1])) {
return NULL;
@@ -1318,30 +1354,29 @@ const void *mark_jumplist_iter(const void *const iter, const win_T *const win,
///
/// @return Pointer that needs to be passed to next `mark_global_iter` call or
/// NULL if iteration is over.
-const void *mark_global_iter(const void *const iter, char *const name,
- xfmark_T *const fm)
+const void *mark_global_iter(const void *const iter, char *const name, xfmark_T *const fm)
FUNC_ATTR_NONNULL_ARG(2, 3) FUNC_ATTR_WARN_UNUSED_RESULT
{
*name = NUL;
const xfmark_T *iter_mark = (iter == NULL
? &(namedfm[0])
- : (const xfmark_T *const) iter);
- while ((size_t) (iter_mark - &(namedfm[0])) < ARRAY_SIZE(namedfm)
+ : (const xfmark_T *const)iter);
+ while ((size_t)(iter_mark - &(namedfm[0])) < ARRAY_SIZE(namedfm)
&& !iter_mark->fmark.mark.lnum) {
iter_mark++;
}
- if ((size_t) (iter_mark - &(namedfm[0])) == ARRAY_SIZE(namedfm)
+ if ((size_t)(iter_mark - &(namedfm[0])) == ARRAY_SIZE(namedfm)
|| !iter_mark->fmark.mark.lnum) {
return NULL;
}
- size_t iter_off = (size_t) (iter_mark - &(namedfm[0]));
- *name = (char) (iter_off < NMARKS
- ? 'A' + (char) iter_off
- : '0' + (char) (iter_off - NMARKS));
+ size_t iter_off = (size_t)(iter_mark - &(namedfm[0]));
+ *name = (char)(iter_off < NMARKS
+ ? 'A' + (char)iter_off
+ : '0' + (char)(iter_off - NMARKS));
*fm = *iter_mark;
- while ((size_t) (++iter_mark - &(namedfm[0])) < ARRAY_SIZE(namedfm)) {
+ while ((size_t)(++iter_mark - &(namedfm[0])) < ARRAY_SIZE(namedfm)) {
if (iter_mark->fmark.mark.lnum) {
- return (const void *) iter_mark;
+ return (const void *)iter_mark;
}
}
return NULL;
@@ -1358,34 +1393,27 @@ const void *mark_global_iter(const void *const iter, char *const name,
/// behaviour is undefined.
///
/// @return Pointer to the next mark or NULL.
-static inline const fmark_T *next_buffer_mark(const buf_T *const buf,
- char *const mark_name)
+static inline const fmark_T *next_buffer_mark(const buf_T *const buf, char *const mark_name)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
switch (*mark_name) {
- case NUL: {
- *mark_name = '"';
- return &(buf->b_last_cursor);
- }
- case '"': {
- *mark_name = '^';
- return &(buf->b_last_insert);
- }
- case '^': {
- *mark_name = '.';
- return &(buf->b_last_change);
- }
- case '.': {
- *mark_name = 'a';
- return &(buf->b_namedm[0]);
- }
- case 'z': {
- return NULL;
- }
- default: {
- (*mark_name)++;
- return &(buf->b_namedm[*mark_name - 'a']);
- }
+ case NUL:
+ *mark_name = '"';
+ return &(buf->b_last_cursor);
+ case '"':
+ *mark_name = '^';
+ return &(buf->b_last_insert);
+ case '^':
+ *mark_name = '.';
+ return &(buf->b_last_change);
+ case '.':
+ *mark_name = 'a';
+ return &(buf->b_namedm[0]);
+ case 'z':
+ return NULL;
+ default:
+ (*mark_name)++;
+ return &(buf->b_namedm[*mark_name - 'a']);
}
}
@@ -1401,12 +1429,12 @@ static inline const fmark_T *next_buffer_mark(const buf_T *const buf,
///
/// @return Pointer that needs to be passed to next `mark_buffer_iter` call or
/// NULL if iteration is over.
-const void *mark_buffer_iter(const void *const iter, const buf_T *const buf,
- char *const name, fmark_T *const fm)
+const void *mark_buffer_iter(const void *const iter, const buf_T *const buf, char *const name,
+ fmark_T *const fm)
FUNC_ATTR_NONNULL_ARG(2, 3, 4) FUNC_ATTR_WARN_UNUSED_RESULT
{
*name = NUL;
- char mark_name = (char) (iter == NULL
+ char mark_name = (char)(iter == NULL
? NUL
: (iter == &(buf->b_last_cursor)
? '"'
@@ -1414,8 +1442,8 @@ const void *mark_buffer_iter(const void *const iter, const buf_T *const buf,
? '^'
: (iter == &(buf->b_last_change)
? '.'
- : 'a' + (char) ((const fmark_T *)iter
- - &(buf->b_namedm[0]))))));
+ : 'a' + (char)((const fmark_T *)iter
+ - &(buf->b_namedm[0]))))));
const fmark_T *iter_mark = next_buffer_mark(buf, &mark_name);
while (iter_mark != NULL && iter_mark->mark.lnum == 0) {
iter_mark = next_buffer_mark(buf, &mark_name);
@@ -1423,14 +1451,14 @@ const void *mark_buffer_iter(const void *const iter, const buf_T *const buf,
if (iter_mark == NULL) {
return NULL;
}
- size_t iter_off = (size_t) (iter_mark - &(buf->b_namedm[0]));
+ size_t iter_off = (size_t)(iter_mark - &(buf->b_namedm[0]));
if (mark_name) {
*name = mark_name;
} else {
- *name = (char) ('a' + (char) iter_off);
+ *name = (char)('a' + (char)iter_off);
}
*fm = *iter_mark;
- return (const void *) iter_mark;
+ return (const void *)iter_mark;
}
/// Set global mark
@@ -1467,8 +1495,7 @@ bool mark_set_global(const char name, const xfmark_T fm, const bool update)
/// later then existing one.
///
/// @return true on success, false on failure.
-bool mark_set_local(const char name, buf_T *const buf,
- const fmark_T fm, const bool update)
+bool mark_set_local(const char name, buf_T *const buf, const fmark_T fm, const bool update)
FUNC_ATTR_NONNULL_ALL
{
fmark_T *fm_tgt = NULL;
@@ -1556,8 +1583,7 @@ 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)
+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)
{
if (pos->lnum <= 0) {
diff --git a/src/nvim/marktree.c b/src/nvim/marktree.c
index feb54eae4a..ebe4478bc8 100644
--- a/src/nvim/marktree.c
+++ b/src/nvim/marktree.c
@@ -49,9 +49,9 @@
#include <assert.h>
-#include "nvim/marktree.h"
-#include "nvim/lib/kvec.h"
#include "nvim/garray.h"
+#include "nvim/lib/kvec.h"
+#include "nvim/marktree.h"
#define T MT_BRANCH_FACTOR
#define ILEN (sizeof(mtnode_t)+(2 * T) * sizeof(void *))
@@ -137,7 +137,9 @@ static inline int marktree_getp_aux(const mtnode_t *x, mtkey_t k, int *r)
end = mid;
}
}
- if (begin == x->n) { *rr = 1; return x->n - 1; }
+ if (begin == x->n) {
+ *rr = 1; return x->n - 1;
+ }
if ((*rr = key_cmp(k, x->key[begin])) < 0) {
begin--;
}
@@ -232,9 +234,8 @@ uint64_t marktree_put(MarkTree *b, int row, int col, bool right_gravity)
return id;
}
-uint64_t marktree_put_pair(MarkTree *b,
- int start_row, int start_col, bool start_right,
- int end_row, int end_col, bool end_right)
+uint64_t marktree_put_pair(MarkTree *b, int start_row, int start_col, bool start_right, int end_row,
+ int end_col, bool end_right)
{
uint64_t id = (b->next_id+=ID_INCR)|PAIRED;
uint64_t start_id = id|(start_right?RIGHT_GRAVITY:0);
@@ -250,7 +251,6 @@ void marktree_put_key(MarkTree *b, int row, int col, uint64_t id)
if (!b->root) {
b->root = (mtnode_t *)xcalloc(1, ILEN);
- b->id2node = pmap_new(uint64_t)();
b->n_nodes++;
}
mtnode_t *r, *s;
@@ -547,9 +547,9 @@ void marktree_clear(MarkTree *b)
marktree_free_node(b->root);
b->root = NULL;
}
- if (b->id2node) {
- pmap_free(uint64_t)(b->id2node);
- b->id2node = NULL;
+ if (b->id2node->table.keys) {
+ pmap_destroy(uint64_t)(b->id2node);
+ pmap_init(uint64_t, b->id2node);
}
b->n_keys = 0;
b->n_nodes = 0;
@@ -595,8 +595,8 @@ bool marktree_itr_get(MarkTree *b, int row, int col, MarkTreeIter *itr)
itr, false, false, NULL);
}
-bool marktree_itr_get_ext(MarkTree *b, mtpos_t p, MarkTreeIter *itr,
- bool last, bool gravity, mtpos_t *oldbase)
+bool marktree_itr_get_ext(MarkTree *b, mtpos_t p, MarkTreeIter *itr, bool last, bool gravity,
+ mtpos_t *oldbase)
{
mtkey_t k = { .pos = p, .id = gravity ? RIGHT_GRAVITY : 0 };
if (last && !gravity) {
@@ -696,8 +696,7 @@ bool marktree_itr_next(MarkTree *b, MarkTreeIter *itr)
return marktree_itr_next_skip(b, itr, false, NULL);
}
-static bool marktree_itr_next_skip(MarkTree *b, MarkTreeIter *itr, bool skip,
- mtpos_t oldbase[])
+static bool marktree_itr_next_skip(MarkTree *b, MarkTreeIter *itr, bool skip, mtpos_t oldbase[])
{
if (!itr->node) {
return false;
@@ -820,8 +819,8 @@ mtmark_t marktree_itr_current(MarkTreeIter *itr)
mtpos_t pos = marktree_itr_pos(itr);
mtmark_t mark = { .row = pos.row,
.col = pos.col,
- .id = ANTIGRAVITY(keyid),
- .right_gravity = keyid & RIGHT_GRAVITY };
+ .id = ANTIGRAVITY(keyid),
+ .right_gravity = keyid & RIGHT_GRAVITY };
return mark;
}
return (mtmark_t){ -1, -1, 0, false };
@@ -834,10 +833,8 @@ static void swap_id(uint64_t *id1, uint64_t *id2)
*id2 = temp;
}
-bool marktree_splice(MarkTree *b,
- int start_line, int start_col,
- int old_extent_line, int old_extent_col,
- int new_extent_line, int new_extent_col)
+bool marktree_splice(MarkTree *b, int start_line, int start_col, int old_extent_line,
+ int old_extent_col, int new_extent_line, int new_extent_col)
{
mtpos_t start = { start_line, start_col };
mtpos_t old_extent = { (int)old_extent_line, old_extent_col };
@@ -904,7 +901,8 @@ continue_same_node:
refkey(b, itr->node, itr->i);
refkey(b, enditr->node, enditr->i);
} else {
- past_right = true; // NOLINT
+ past_right = true; // NOLINT
+ (void)past_right;
break;
}
}
@@ -994,10 +992,8 @@ past_continue_same_node:
return moved;
}
-void marktree_move_region(MarkTree *b,
- int start_row, colnr_T start_col,
- int extent_row, colnr_T extent_col,
- int new_row, colnr_T new_col)
+void marktree_move_region(MarkTree *b, int start_row, colnr_T start_col, int extent_row,
+ colnr_T extent_col, int new_row, colnr_T new_col)
{
mtpos_t start = { start_row, start_col }, size = { extent_row, extent_col };
mtpos_t end = size;
@@ -1114,8 +1110,7 @@ void marktree_check(MarkTree *b)
}
#ifndef NDEBUG
-static size_t check_node(MarkTree *b, mtnode_t *x,
- mtpos_t *last, bool *last_right)
+static size_t check_node(MarkTree *b, mtnode_t *x, mtpos_t *last, bool *last_right)
{
assert(x->n <= 2 * T - 1);
// TODO(bfredl): too strict if checking "in repair" post-delete tree.
diff --git a/src/nvim/marktree.h b/src/nvim/marktree.h
index 8a1c564a6d..7af23765c3 100644
--- a/src/nvim/marktree.h
+++ b/src/nvim/marktree.h
@@ -49,7 +49,7 @@ struct mtnode_s {
int32_t n;
int32_t level;
// TODO(bfredl): we could consider having a only-sometimes-valid
- // index into parent for faster "chached" lookup.
+ // index into parent for faster "cached" lookup.
mtnode_t *parent;
mtkey_t key[2 * MT_BRANCH_FACTOR - 1];
mtnode_t *ptr[];
@@ -63,7 +63,7 @@ typedef struct {
uint64_t next_id;
// TODO(bfredl): the pointer to node could be part of the larger
// Map(uint64_t, ExtmarkItem) essentially;
- PMap(uint64_t) *id2node;
+ PMap(uint64_t) id2node[1];
} MarkTree;
diff --git a/src/nvim/math.c b/src/nvim/math.c
index b51f335ed7..791f1f9373 100644
--- a/src/nvim/math.c
+++ b/src/nvim/math.c
@@ -3,40 +3,38 @@
#include <math.h>
+#include <stdint.h>
+#include <string.h>
+
#include "nvim/math.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "math.c.generated.h"
#endif
-#if defined(__clang__) && __clang__ == 1 && __clang_major__ >= 6
-// Workaround glibc + Clang 6+ bug. #8274
-// https://bugzilla.redhat.com/show_bug.cgi?id=1472437
-# pragma clang diagnostic push
-# pragma clang diagnostic ignored "-Wconversion"
-#endif
int xfpclassify(double d)
{
-#if defined(__MINGW32__)
- // Workaround mingw warning. #7863
- return __fpclassify(d);
-#else
- return fpclassify(d);
-#endif
+ uint64_t m;
+ int e;
+
+ memcpy(&m, &d, sizeof(m));
+ e = 0x7ff & (m >> 52);
+ m = 0xfffffffffffffULL & m;
+
+ switch (e) {
+ default:
+ return FP_NORMAL;
+ case 0x000:
+ return m ? FP_SUBNORMAL : FP_ZERO;
+ case 0x7ff:
+ return m ? FP_NAN : FP_INFINITE;
+ }
}
int xisinf(double d)
{
- return isinf(d);
+ return FP_INFINITE == xfpclassify(d);
}
int xisnan(double d)
{
-#if defined(__MINGW32__)
- // Workaround mingw warning. #7863
- return _isnan(d);
-#else
- return isnan(d);
-#endif
+ return FP_NAN == xfpclassify(d);
}
-#if defined(__clang__) && __clang__ == 1 && __clang_major__ >= 6
-# pragma clang diagnostic pop
-#endif
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index 73e3ba53a5..253ddfc253 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -31,30 +31,30 @@
#include <wchar.h>
#include <wctype.h>
-#include "nvim/vim.h"
#include "nvim/ascii.h"
+#include "nvim/vim.h"
#ifdef HAVE_LOCALE_H
# include <locale.h>
#endif
-#include "nvim/eval.h"
-#include "nvim/path.h"
-#include "nvim/iconv.h"
-#include "nvim/mbyte.h"
+#include "nvim/arabic.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
+#include "nvim/eval.h"
#include "nvim/fileio.h"
#include "nvim/func_attr.h"
+#include "nvim/iconv.h"
+#include "nvim/mark.h"
+#include "nvim/mbyte.h"
#include "nvim/memline.h"
+#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
-#include "nvim/memory.h"
#include "nvim/option.h"
+#include "nvim/os/os.h"
+#include "nvim/path.h"
#include "nvim/screen.h"
#include "nvim/spell.h"
#include "nvim/strings.h"
-#include "nvim/os/os.h"
-#include "nvim/arabic.h"
-#include "nvim/mark.h"
typedef struct {
int rangeStart;
@@ -70,12 +70,10 @@ struct interval {
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "mbyte.c.generated.h"
+
# include "unicode_tables.generated.h"
#endif
-char_u e_loadlib[] = "E370: Could not load library %s";
-char_u e_loadfunc[] = "E448: Could not load library function %s";
-
// To speed up BYTELEN(); keep a lookup table to quickly get the length in
// bytes of a UTF-8 character from the first byte of a UTF-8 string. Bytes
// which are illegal when used as the first byte have a 1. The NUL byte has
@@ -130,131 +128,131 @@ static struct
enc_canon_table[] =
{
#define IDX_LATIN_1 0
- {"latin1", ENC_8BIT + ENC_LATIN1, 1252},
+ { "latin1", ENC_8BIT + ENC_LATIN1, 1252 },
#define IDX_ISO_2 1
- {"iso-8859-2", ENC_8BIT, 0},
+ { "iso-8859-2", ENC_8BIT, 0 },
#define IDX_ISO_3 2
- {"iso-8859-3", ENC_8BIT, 0},
+ { "iso-8859-3", ENC_8BIT, 0 },
#define IDX_ISO_4 3
- {"iso-8859-4", ENC_8BIT, 0},
+ { "iso-8859-4", ENC_8BIT, 0 },
#define IDX_ISO_5 4
- {"iso-8859-5", ENC_8BIT, 0},
+ { "iso-8859-5", ENC_8BIT, 0 },
#define IDX_ISO_6 5
- {"iso-8859-6", ENC_8BIT, 0},
+ { "iso-8859-6", ENC_8BIT, 0 },
#define IDX_ISO_7 6
- {"iso-8859-7", ENC_8BIT, 0},
+ { "iso-8859-7", ENC_8BIT, 0 },
#define IDX_ISO_8 7
- {"iso-8859-8", ENC_8BIT, 0},
+ { "iso-8859-8", ENC_8BIT, 0 },
#define IDX_ISO_9 8
- {"iso-8859-9", ENC_8BIT, 0},
+ { "iso-8859-9", ENC_8BIT, 0 },
#define IDX_ISO_10 9
- {"iso-8859-10", ENC_8BIT, 0},
+ { "iso-8859-10", ENC_8BIT, 0 },
#define IDX_ISO_11 10
- {"iso-8859-11", ENC_8BIT, 0},
+ { "iso-8859-11", ENC_8BIT, 0 },
#define IDX_ISO_13 11
- {"iso-8859-13", ENC_8BIT, 0},
+ { "iso-8859-13", ENC_8BIT, 0 },
#define IDX_ISO_14 12
- {"iso-8859-14", ENC_8BIT, 0},
+ { "iso-8859-14", ENC_8BIT, 0 },
#define IDX_ISO_15 13
- {"iso-8859-15", ENC_8BIT + ENC_LATIN9, 0},
+ { "iso-8859-15", ENC_8BIT + ENC_LATIN9, 0 },
#define IDX_KOI8_R 14
- {"koi8-r", ENC_8BIT, 0},
+ { "koi8-r", ENC_8BIT, 0 },
#define IDX_KOI8_U 15
- {"koi8-u", ENC_8BIT, 0},
+ { "koi8-u", ENC_8BIT, 0 },
#define IDX_UTF8 16
- {"utf-8", ENC_UNICODE, 0},
+ { "utf-8", ENC_UNICODE, 0 },
#define IDX_UCS2 17
- {"ucs-2", ENC_UNICODE + ENC_ENDIAN_B + ENC_2BYTE, 0},
+ { "ucs-2", ENC_UNICODE + ENC_ENDIAN_B + ENC_2BYTE, 0 },
#define IDX_UCS2LE 18
- {"ucs-2le", ENC_UNICODE + ENC_ENDIAN_L + ENC_2BYTE, 0},
+ { "ucs-2le", ENC_UNICODE + ENC_ENDIAN_L + ENC_2BYTE, 0 },
#define IDX_UTF16 19
- {"utf-16", ENC_UNICODE + ENC_ENDIAN_B + ENC_2WORD, 0},
+ { "utf-16", ENC_UNICODE + ENC_ENDIAN_B + ENC_2WORD, 0 },
#define IDX_UTF16LE 20
- {"utf-16le", ENC_UNICODE + ENC_ENDIAN_L + ENC_2WORD, 0},
+ { "utf-16le", ENC_UNICODE + ENC_ENDIAN_L + ENC_2WORD, 0 },
#define IDX_UCS4 21
- {"ucs-4", ENC_UNICODE + ENC_ENDIAN_B + ENC_4BYTE, 0},
+ { "ucs-4", ENC_UNICODE + ENC_ENDIAN_B + ENC_4BYTE, 0 },
#define IDX_UCS4LE 22
- {"ucs-4le", ENC_UNICODE + ENC_ENDIAN_L + ENC_4BYTE, 0},
+ { "ucs-4le", ENC_UNICODE + ENC_ENDIAN_L + ENC_4BYTE, 0 },
- /* For debugging DBCS encoding on Unix. */
+ // For debugging DBCS encoding on Unix.
#define IDX_DEBUG 23
- {"debug", ENC_DBCS, DBCS_DEBUG},
+ { "debug", ENC_DBCS, DBCS_DEBUG },
#define IDX_EUC_JP 24
- {"euc-jp", ENC_DBCS, DBCS_JPNU},
+ { "euc-jp", ENC_DBCS, DBCS_JPNU },
#define IDX_SJIS 25
- {"sjis", ENC_DBCS, DBCS_JPN},
+ { "sjis", ENC_DBCS, DBCS_JPN },
#define IDX_EUC_KR 26
- {"euc-kr", ENC_DBCS, DBCS_KORU},
+ { "euc-kr", ENC_DBCS, DBCS_KORU },
#define IDX_EUC_CN 27
- {"euc-cn", ENC_DBCS, DBCS_CHSU},
+ { "euc-cn", ENC_DBCS, DBCS_CHSU },
#define IDX_EUC_TW 28
- {"euc-tw", ENC_DBCS, DBCS_CHTU},
+ { "euc-tw", ENC_DBCS, DBCS_CHTU },
#define IDX_BIG5 29
- {"big5", ENC_DBCS, DBCS_CHT},
+ { "big5", ENC_DBCS, DBCS_CHT },
/* MS-DOS and MS-Windows codepages are included here, so that they can be
* used on Unix too. Most of them are similar to ISO-8859 encodings, but
* not exactly the same. */
#define IDX_CP437 30
- {"cp437", ENC_8BIT, 437}, /* like iso-8859-1 */
+ { "cp437", ENC_8BIT, 437 }, // like iso-8859-1
#define IDX_CP737 31
- {"cp737", ENC_8BIT, 737}, /* like iso-8859-7 */
+ { "cp737", ENC_8BIT, 737 }, // like iso-8859-7
#define IDX_CP775 32
- {"cp775", ENC_8BIT, 775}, /* Baltic */
+ { "cp775", ENC_8BIT, 775 }, // Baltic
#define IDX_CP850 33
- {"cp850", ENC_8BIT, 850}, /* like iso-8859-4 */
+ { "cp850", ENC_8BIT, 850 }, // like iso-8859-4
#define IDX_CP852 34
- {"cp852", ENC_8BIT, 852}, /* like iso-8859-1 */
+ { "cp852", ENC_8BIT, 852 }, // like iso-8859-1
#define IDX_CP855 35
- {"cp855", ENC_8BIT, 855}, /* like iso-8859-2 */
+ { "cp855", ENC_8BIT, 855 }, // like iso-8859-2
#define IDX_CP857 36
- {"cp857", ENC_8BIT, 857}, /* like iso-8859-5 */
+ { "cp857", ENC_8BIT, 857 }, // like iso-8859-5
#define IDX_CP860 37
- {"cp860", ENC_8BIT, 860}, /* like iso-8859-9 */
+ { "cp860", ENC_8BIT, 860 }, // like iso-8859-9
#define IDX_CP861 38
- {"cp861", ENC_8BIT, 861}, /* like iso-8859-1 */
+ { "cp861", ENC_8BIT, 861 }, // like iso-8859-1
#define IDX_CP862 39
- {"cp862", ENC_8BIT, 862}, /* like iso-8859-1 */
+ { "cp862", ENC_8BIT, 862 }, // like iso-8859-1
#define IDX_CP863 40
- {"cp863", ENC_8BIT, 863}, /* like iso-8859-8 */
+ { "cp863", ENC_8BIT, 863 }, // like iso-8859-8
#define IDX_CP865 41
- {"cp865", ENC_8BIT, 865}, /* like iso-8859-1 */
+ { "cp865", ENC_8BIT, 865 }, // like iso-8859-1
#define IDX_CP866 42
- {"cp866", ENC_8BIT, 866}, /* like iso-8859-5 */
+ { "cp866", ENC_8BIT, 866 }, // like iso-8859-5
#define IDX_CP869 43
- {"cp869", ENC_8BIT, 869}, /* like iso-8859-7 */
+ { "cp869", ENC_8BIT, 869 }, // like iso-8859-7
#define IDX_CP874 44
- {"cp874", ENC_8BIT, 874}, /* Thai */
+ { "cp874", ENC_8BIT, 874 }, // Thai
#define IDX_CP932 45
- {"cp932", ENC_DBCS, DBCS_JPN},
+ { "cp932", ENC_DBCS, DBCS_JPN },
#define IDX_CP936 46
- {"cp936", ENC_DBCS, DBCS_CHS},
+ { "cp936", ENC_DBCS, DBCS_CHS },
#define IDX_CP949 47
- {"cp949", ENC_DBCS, DBCS_KOR},
+ { "cp949", ENC_DBCS, DBCS_KOR },
#define IDX_CP950 48
- {"cp950", ENC_DBCS, DBCS_CHT},
+ { "cp950", ENC_DBCS, DBCS_CHT },
#define IDX_CP1250 49
- {"cp1250", ENC_8BIT, 1250}, /* Czech, Polish, etc. */
+ { "cp1250", ENC_8BIT, 1250 }, // Czech, Polish, etc.
#define IDX_CP1251 50
- {"cp1251", ENC_8BIT, 1251}, /* Cyrillic */
- /* cp1252 is considered to be equal to latin1 */
+ { "cp1251", ENC_8BIT, 1251 }, // Cyrillic
+ // cp1252 is considered to be equal to latin1
#define IDX_CP1253 51
- {"cp1253", ENC_8BIT, 1253}, /* Greek */
+ { "cp1253", ENC_8BIT, 1253 }, // Greek
#define IDX_CP1254 52
- {"cp1254", ENC_8BIT, 1254}, /* Turkish */
+ { "cp1254", ENC_8BIT, 1254 }, // Turkish
#define IDX_CP1255 53
- {"cp1255", ENC_8BIT, 1255}, /* Hebrew */
+ { "cp1255", ENC_8BIT, 1255 }, // Hebrew
#define IDX_CP1256 54
- {"cp1256", ENC_8BIT, 1256}, /* Arabic */
+ { "cp1256", ENC_8BIT, 1256 }, // Arabic
#define IDX_CP1257 55
- {"cp1257", ENC_8BIT, 1257}, /* Baltic */
+ { "cp1257", ENC_8BIT, 1257 }, // Baltic
#define IDX_CP1258 56
- {"cp1258", ENC_8BIT, 1258}, /* Vietnamese */
+ { "cp1258", ENC_8BIT, 1258 }, // Vietnamese
#define IDX_MACROMAN 57
- {"macroman", ENC_8BIT + ENC_MACROMAN, 0}, /* Mac OS */
+ { "macroman", ENC_8BIT + ENC_MACROMAN, 0 }, // Mac OS
#define IDX_HPROMAN8 58
- {"hp-roman8", ENC_8BIT, 0}, /* HP Roman8 */
+ { "hp-roman8", ENC_8BIT, 0 }, // HP Roman8
#define IDX_COUNT 59
};
@@ -339,9 +337,11 @@ static int enc_canon_search(const char_u *name)
{
int i;
- for (i = 0; i < IDX_COUNT; ++i)
- if (STRCMP(name, enc_canon_table[i].name) == 0)
+ for (i = 0; i < IDX_COUNT; ++i) {
+ if (STRCMP(name, enc_canon_table[i].name) == 0) {
return i;
+ }
+ }
return -1;
}
@@ -356,12 +356,13 @@ int enc_canon_props(const char_u *name)
int i;
i = enc_canon_search(name);
- if (i >= 0)
+ if (i >= 0) {
return enc_canon_table[i].prop;
- if (STRNCMP(name, "2byte-", 6) == 0)
+ } else if (STRNCMP(name, "2byte-", 6) == 0) {
return ENC_DBCS;
- if (STRNCMP(name, "8bit-", 5) == 0 || STRNCMP(name, "iso-8859-", 9) == 0)
+ } else if (STRNCMP(name, "8bit-", 5) == 0 || STRNCMP(name, "iso-8859-", 9) == 0) {
return ENC_8BIT;
+ }
return 0;
}
@@ -439,21 +440,23 @@ static bool intable(const struct interval *table, size_t n_items, int c)
{
int mid, bot, top;
- /* first quick check for Latin1 etc. characters */
- if (c < table[0].first)
+ // first quick check for Latin1 etc. characters
+ if (c < table[0].first) {
return false;
+ }
- /* binary search in table */
+ // binary search in table
bot = 0;
top = (int)(n_items - 1);
while (top >= bot) {
mid = (bot + top) / 2;
- if (table[mid].last < c)
+ if (table[mid].last < c) {
bot = mid + 1;
- else if (table[mid].first > c)
+ } else if (table[mid].first > c) {
top = mid - 1;
- else
+ } else {
return true;
+ }
}
return false;
}
@@ -515,12 +518,14 @@ int utf_ptr2cells(const char_u *p)
// Need to convert to a character number.
if (*p >= 0x80) {
c = utf_ptr2char(p);
- /* An illegal byte is displayed as <xx>. */
- if (utf_ptr2len(p) == 1 || c == NUL)
+ // An illegal byte is displayed as <xx>.
+ if (utf_ptr2len(p) == 1 || c == NUL) {
return 4;
- /* If the char is ASCII it must be an overlong sequence. */
- if (c < 0x80)
+ }
+ // If the char is ASCII it must be an overlong sequence.
+ if (c < 0x80) {
return char2cells(c);
+ }
return utf_char2cells(c);
}
return 1;
@@ -532,17 +537,20 @@ int utf_ptr2cells_len(const char_u *p, int size)
{
int c;
- /* Need to convert to a wide character. */
+ // Need to convert to a wide character.
if (size > 0 && *p >= 0x80) {
- if (utf_ptr2len_len(p, size) < utf8len_tab[*p])
- return 1; /* truncated */
+ if (utf_ptr2len_len(p, size) < utf8len_tab[*p]) {
+ return 1; // truncated
+ }
c = utf_ptr2char(p);
- /* An illegal byte is displayed as <xx>. */
- if (utf_ptr2len(p) == 1 || c == NUL)
+ // An illegal byte is displayed as <xx>.
+ if (utf_ptr2len(p) == 1 || c == NUL) {
return 4;
- /* If the char is ASCII it must be an overlong sequence. */
- if (c < 0x80)
+ }
+ // If the char is ASCII it must be an overlong sequence.
+ if (c < 0x80) {
return char2cells(c);
+ }
return utf_char2cells(c);
}
return 1;
@@ -654,13 +662,14 @@ static int utf_safe_read_char_adv(const char_u **s, size_t *n)
{
int c;
- if (*n == 0) /* end of buffer */
+ if (*n == 0) { // end of buffer
return 0;
+ }
uint8_t k = utf8len_tab_zero[**s];
if (k == 1) {
- /* ASCII character or NUL */
+ // ASCII character or NUL
(*n)--;
return *(*s)++;
}
@@ -677,14 +686,14 @@ static int utf_safe_read_char_adv(const char_u **s, size_t *n)
* U+00C3 (UTF-8: 0xC3 0x83), so need to check that special case too.
* It's safe even if n=1, else we would have k=2 > n. */
if (c != (int)(**s) || (c == 0xC3 && (*s)[1] == 0x83)) {
- /* byte sequence was successfully decoded */
+ // byte sequence was successfully decoded
*s += k;
*n -= k;
return c;
}
}
- /* byte sequence is incomplete or illegal */
+ // byte sequence is incomplete or illegal
return -1;
}
@@ -724,10 +733,12 @@ bool utf_composinglike(const char_u *p1, const char_u *p2)
int c2;
c2 = utf_ptr2char(p2);
- if (utf_iscomposing(c2))
+ if (utf_iscomposing(c2)) {
return true;
- if (!arabic_maycombine(c2))
+ }
+ if (!arabic_maycombine(c2)) {
return false;
+ }
return arabic_combine(utf_ptr2char(p1), c2);
}
@@ -749,23 +760,26 @@ int utfc_ptr2char(const char_u *p, int *pcc)
c = utf_ptr2char(p);
len = utf_ptr2len(p);
- /* Only accept a composing char when the first char isn't illegal. */
+ // Only accept a composing char when the first char isn't illegal.
if ((len > 1 || *p < 0x80)
&& p[len] >= 0x80
&& UTF_COMPOSINGLIKE(p, p + len)) {
cc = utf_ptr2char(p + len);
for (;; ) {
pcc[i++] = cc;
- if (i == MAX_MCO)
+ if (i == MAX_MCO) {
break;
+ }
len += utf_ptr2len(p + len);
- if (p[len] < 0x80 || !utf_iscomposing(cc = utf_ptr2char(p + len)))
+ if (p[len] < 0x80 || !utf_iscomposing(cc = utf_ptr2char(p + len))) {
break;
+ }
}
}
- if (i < MAX_MCO) /* last composing char must be 0 */
+ if (i < MAX_MCO) { // last composing char must be 0
pcc[i] = 0;
+ }
return c;
}
@@ -858,15 +872,19 @@ int utf_ptr2len_len(const char_u *p, int size)
int m;
len = utf8len_tab[*p];
- if (len == 1)
- return 1; /* NUL, ascii or illegal lead byte */
- if (len > size)
- m = size; /* incomplete byte sequence. */
- else
+ if (len == 1) {
+ return 1; // NUL, ascii or illegal lead byte
+ }
+ if (len > size) {
+ m = size; // incomplete byte sequence.
+ } else {
m = len;
- for (i = 1; i < m; ++i)
- if ((p[i] & 0xc0) != 0x80)
+ }
+ for (i = 1; i < m; ++i) {
+ if ((p[i] & 0xc0) != 0x80) {
return 1;
+ }
+ }
return len;
}
@@ -918,17 +936,20 @@ int utfc_ptr2len_len(const char_u *p, int size)
int len;
int prevlen;
- if (size < 1 || *p == NUL)
+ if (size < 1 || *p == NUL) {
return 0;
- if (p[0] < 0x80 && (size == 1 || p[1] < 0x80)) /* be quick for ASCII */
+ }
+ if (p[0] < 0x80 && (size == 1 || p[1] < 0x80)) { // be quick for ASCII
return 1;
+ }
- /* Skip over first UTF-8 char, stopping at a NUL byte. */
+ // Skip over first UTF-8 char, stopping at a NUL byte.
len = utf_ptr2len_len(p, size);
- /* Check for illegal byte and incomplete byte sequence. */
- if ((len == 1 && p[0] >= 0x80) || len > size)
+ // Check for illegal byte and incomplete byte sequence.
+ if ((len == 1 && p[0] >= 0x80) || len > size) {
return 1;
+ }
/*
* Check for composing characters. We can handle only the first six, but
@@ -938,21 +959,24 @@ int utfc_ptr2len_len(const char_u *p, int size)
while (len < size) {
int len_next_char;
- if (p[len] < 0x80)
+ if (p[len] < 0x80) {
break;
+ }
/*
* Next character length should not go beyond size to ensure that
* UTF_COMPOSINGLIKE(...) does not read beyond size.
*/
len_next_char = utf_ptr2len_len(p + len, size - len);
- if (len_next_char > size - len)
+ if (len_next_char > size - len) {
break;
+ }
- if (!UTF_COMPOSINGLIKE(p + prevlen, p + len))
+ if (!UTF_COMPOSINGLIKE(p + prevlen, p + len)) {
break;
+ }
- /* Skip over composing char */
+ // Skip over composing char
prevlen = len;
len += len_next_char;
}
@@ -1046,9 +1070,9 @@ bool utf_printable(int c)
* 0xd800-0xdfff is reserved for UTF-16, actually illegal. */
static struct interval nonprint[] =
{
- {0x070f, 0x070f}, {0x180b, 0x180e}, {0x200b, 0x200f}, {0x202a, 0x202e},
- {0x206a, 0x206f}, {0xd800, 0xdfff}, {0xfeff, 0xfeff}, {0xfff9, 0xfffb},
- {0xfffe, 0xffff}
+ { 0x070f, 0x070f }, { 0x180b, 0x180e }, { 0x200b, 0x200f }, { 0x202a, 0x202e },
+ { 0x206a, 0x206f }, { 0xd800, 0xdfff }, { 0xfeff, 0xfeff }, { 0xfff9, 0xfffb },
+ { 0xfffe, 0xffff }
};
return !intable(nonprint, ARRAY_SIZE(nonprint), c);
@@ -1068,7 +1092,7 @@ int utf_class(const int c)
int utf_class_tab(const int c, const uint64_t *const chartab)
{
- /* sorted list of non-overlapping intervals */
+ // sorted list of non-overlapping intervals
static struct clinterval {
unsigned int first;
unsigned int last;
@@ -1150,7 +1174,7 @@ int utf_class_tab(const int c, const uint64_t *const chartab)
int top = ARRAY_SIZE(classes) - 1;
int mid;
- /* First quick check for Latin1 characters, use 'iskeyword'. */
+ // First quick check for Latin1 characters, use 'iskeyword'.
if (c < 0x100) {
if (c == ' ' || c == '\t' || c == NUL || c == 0xa0) {
return 0; // blank
@@ -1161,15 +1185,16 @@ int utf_class_tab(const int c, const uint64_t *const chartab)
return 1; // punctuation
}
- /* binary search in table */
+ // binary search in table
while (top >= bot) {
mid = (bot + top) / 2;
- if (classes[mid].last < (unsigned int)c)
+ if (classes[mid].last < (unsigned int)c) {
bot = mid + 1;
- else if (classes[mid].first > (unsigned int)c)
+ } else if (classes[mid].first > (unsigned int)c) {
top = mid - 1;
- else
+ } else {
return (int)classes[mid].class;
+ }
}
// emoji
@@ -1177,7 +1202,7 @@ int utf_class_tab(const int c, const uint64_t *const chartab)
return 3;
}
- /* most other characters are "word" characters */
+ // most other characters are "word" characters
return 2;
}
@@ -1194,25 +1219,27 @@ bool utf_ambiguous_width(int c)
*/
static int utf_convert(int a, const convertStruct *const table, size_t n_items)
{
- size_t start, mid, end; /* indices into table */
+ size_t start, mid, end; // indices into table
start = 0;
end = n_items;
while (start < end) {
- /* need to search further */
+ // need to search further
mid = (end + start) / 2;
- if (table[mid].rangeEnd < a)
+ if (table[mid].rangeEnd < a) {
start = mid + 1;
- else
+ } else {
end = mid;
+ }
}
if (start < n_items
&& table[start].rangeStart <= a
&& a <= table[start].rangeEnd
- && (a - table[start].rangeStart) % table[start].step == 0)
+ && (a - table[start].rangeStart) % table[start].step == 0) {
return a + table[start].offset;
- else
+ } else {
return a;
+ }
}
/*
@@ -1237,21 +1264,24 @@ int utf_fold(int a)
/// simple case folding.
int mb_toupper(int a)
{
- /* If 'casemap' contains "keepascii" use ASCII style toupper(). */
- if (a < 128 && (cmp_flags & CMP_KEEPASCII))
+ // If 'casemap' contains "keepascii" use ASCII style toupper().
+ if (a < 128 && (cmp_flags & CMP_KEEPASCII)) {
return TOUPPER_ASC(a);
+ }
#if defined(__STDC_ISO_10646__)
- /* If towupper() is available and handles Unicode, use it. */
- if (!(cmp_flags & CMP_INTERNAL))
+ // If towupper() is available and handles Unicode, use it.
+ if (!(cmp_flags & CMP_INTERNAL)) {
return towupper(a);
+ }
#endif
- /* For characters below 128 use locale sensitive toupper(). */
- if (a < 128)
+ // For characters below 128 use locale sensitive toupper().
+ if (a < 128) {
return TOUPPER_LOC(a);
+ }
- /* For any other characters use the above mapping table. */
+ // For any other characters use the above mapping table.
return utf_convert(a, toUpper, ARRAY_SIZE(toUpper));
}
@@ -1265,21 +1295,24 @@ bool mb_islower(int a)
/// simple case folding.
int mb_tolower(int a)
{
- /* If 'casemap' contains "keepascii" use ASCII style tolower(). */
- if (a < 128 && (cmp_flags & CMP_KEEPASCII))
+ // If 'casemap' contains "keepascii" use ASCII style tolower().
+ if (a < 128 && (cmp_flags & CMP_KEEPASCII)) {
return TOLOWER_ASC(a);
+ }
#if defined(__STDC_ISO_10646__)
- /* If towlower() is available and handles Unicode, use it. */
- if (!(cmp_flags & CMP_INTERNAL))
+ // If towlower() is available and handles Unicode, use it.
+ if (!(cmp_flags & CMP_INTERNAL)) {
return towlower(a);
+ }
#endif
- /* For characters below 128 use locale sensitive tolower(). */
- if (a < 128)
+ // For characters below 128 use locale sensitive tolower().
+ if (a < 128) {
return TOLOWER_LOC(a);
+ }
- /* For any other characters use the above mapping table. */
+ // For any other characters use the above mapping table.
return utf_convert(a, toLower, ARRAY_SIZE(toLower));
}
@@ -1288,8 +1321,7 @@ bool mb_isupper(int a)
return mb_tolower(a) != a;
}
-static int utf_strnicmp(const char_u *s1, const char_u *s2, size_t n1,
- size_t n2)
+static int utf_strnicmp(const char_u *s1, const char_u *s2, size_t n1, size_t n2)
{
int c1, c2, cdiff;
char_u buffer[6];
@@ -1298,23 +1330,27 @@ static int utf_strnicmp(const char_u *s1, const char_u *s2, size_t n1,
c1 = utf_safe_read_char_adv(&s1, &n1);
c2 = utf_safe_read_char_adv(&s2, &n2);
- if (c1 <= 0 || c2 <= 0)
+ if (c1 <= 0 || c2 <= 0) {
break;
+ }
- if (c1 == c2)
+ if (c1 == c2) {
continue;
+ }
cdiff = utf_fold(c1) - utf_fold(c2);
- if (cdiff != 0)
+ if (cdiff != 0) {
return cdiff;
+ }
}
- /* some string ended or has an incomplete/illegal character sequence */
+ // some string ended or has an incomplete/illegal character sequence
if (c1 == 0 || c2 == 0) {
- /* some string ended. shorter string is smaller */
- if (c1 == 0 && c2 == 0)
+ // some string ended. shorter string is smaller
+ if (c1 == 0 && c2 == 0) {
return 0;
+ }
return c1 == 0 ? -1 : 1;
}
@@ -1335,8 +1371,9 @@ static int utf_strnicmp(const char_u *s1, const char_u *s2, size_t n1,
while (n1 > 0 && n2 > 0 && *s1 != NUL && *s2 != NUL) {
cdiff = (int)(*s1) - (int)(*s2);
- if (cdiff != 0)
+ if (cdiff != 0) {
return cdiff;
+ }
s1++;
s2++;
@@ -1344,20 +1381,23 @@ static int utf_strnicmp(const char_u *s1, const char_u *s2, size_t n1,
n2--;
}
- if (n1 > 0 && *s1 == NUL)
+ if (n1 > 0 && *s1 == NUL) {
n1 = 0;
- if (n2 > 0 && *s2 == NUL)
+ }
+ if (n2 > 0 && *s2 == NUL) {
n2 = 0;
+ }
- if (n1 == 0 && n2 == 0)
+ if (n1 == 0 && n2 == 0) {
return 0;
+ }
return n1 == 0 ? -1 : 1;
}
#ifdef WIN32
-#ifndef CP_UTF8
-# define CP_UTF8 65001 /* magic number from winnls.h */
-#endif
+# ifndef CP_UTF8
+# define CP_UTF8 65001 // magic number from winnls.h
+# endif
/// Converts string from UTF-8 to UTF-16.
///
@@ -1456,8 +1496,7 @@ int utf16_to_utf8(const wchar_t *utf16, int utf16len, char **utf8)
/// @param len maximum length (an earlier NUL terminates)
/// @param[out] codepoints incremented with UTF-32 code point size
/// @param[out] codeunits incremented with UTF-16 code unit size
-void mb_utflen(const char_u *s, size_t len, size_t *codepoints,
- size_t *codeunits)
+void mb_utflen(const char_u *s, size_t len, size_t *codepoints, size_t *codeunits)
FUNC_ATTR_NONNULL_ALL
{
size_t count = 0, extra = 0;
@@ -1476,8 +1515,7 @@ void mb_utflen(const char_u *s, size_t len, size_t *codepoints,
*codeunits += count + extra;
}
-ssize_t mb_utf_index_to_bytes(const char_u *s, size_t len,
- size_t index, bool use_utf16_units)
+ssize_t mb_utf_index_to_bytes(const char_u *s, size_t len, size_t index, bool use_utf16_units)
FUNC_ATTR_NONNULL_ALL
{
size_t count = 0;
@@ -1540,7 +1578,7 @@ void show_utf8(void)
{
int len;
int rlen = 0;
- char_u *line;
+ char_u *line;
int clen;
int i;
@@ -1556,7 +1594,7 @@ void show_utf8(void)
clen = 0;
for (i = 0; i < len; ++i) {
if (clen == 0) {
- /* start of (composing) character, get its length */
+ // start of (composing) character, get its length
if (i > 0) {
STRCPY(IObuff + rlen, "+ ");
rlen += 2;
@@ -1564,11 +1602,12 @@ void show_utf8(void)
clen = utf_ptr2len(line + i);
}
sprintf((char *)IObuff + rlen, "%02x ",
- (line[i] == NL) ? NUL : line[i]); /* NUL is stored as NL */
+ (line[i] == NL) ? NUL : line[i]); // NUL is stored as NL
--clen;
rlen += (int)STRLEN(IObuff + rlen);
- if (rlen > IOSIZE - 20)
+ if (rlen > IOSIZE - 20) {
break;
+ }
}
msg(IObuff);
@@ -1582,42 +1621,49 @@ int utf_head_off(const char_u *base, const char_u *p)
int c;
int len;
- if (*p < 0x80) /* be quick for ASCII */
+ if (*p < 0x80) { // be quick for ASCII
return 0;
+ }
/* Skip backwards over trailing bytes: 10xx.xxxx
* Skip backwards again if on a composing char. */
const char_u *q;
for (q = p;; --q) {
- /* Move s to the last byte of this char. */
+ // Move s to the last byte of this char.
const char_u *s;
for (s = q; (s[1] & 0xc0) == 0x80; ++s) {}
- /* Move q to the first byte of this char. */
- while (q > base && (*q & 0xc0) == 0x80)
+ // Move q to the first byte of this char.
+ while (q > base && (*q & 0xc0) == 0x80) {
--q;
+ }
/* Check for illegal sequence. Do allow an illegal byte after where we
* started. */
len = utf8len_tab[*q];
- if (len != (int)(s - q + 1) && len != (int)(p - q + 1))
+ if (len != (int)(s - q + 1) && len != (int)(p - q + 1)) {
return 0;
+ }
- if (q <= base)
+ if (q <= base) {
break;
+ }
c = utf_ptr2char(q);
- if (utf_iscomposing(c))
+ if (utf_iscomposing(c)) {
continue;
+ }
if (arabic_maycombine(c)) {
- /* Advance to get a sneak-peak at the next char */
+ // Advance to get a sneak-peak at the next char
const char_u *j = q;
--j;
- /* Move j to the first byte of this char. */
- while (j > base && (*j & 0xc0) == 0x80)
+ // Move j to the first byte of this char.
+ while (j > base && (*j & 0xc0) == 0x80) {
--j;
- if (arabic_combine(utf_ptr2char(j), c))
+ }
+ if (arabic_combine(utf_ptr2char(j), c)) {
continue;
+ }
}
break;
}
@@ -1630,12 +1676,12 @@ bool utf_eat_space(int cc)
FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT
{
return (cc >= 0x2000 && cc <= 0x206F) // General punctuations
- || (cc >= 0x2e00 && cc <= 0x2e7f) // Supplemental punctuations
- || (cc >= 0x3000 && cc <= 0x303f) // CJK symbols and punctuations
- || (cc >= 0xff01 && cc <= 0xff0f) // Full width ASCII punctuations
- || (cc >= 0xff1a && cc <= 0xff20) // ..
- || (cc >= 0xff3b && cc <= 0xff40) // ..
- || (cc >= 0xff5b && cc <= 0xff65); // ..
+ || (cc >= 0x2e00 && cc <= 0x2e7f) // Supplemental punctuations
+ || (cc >= 0x3000 && cc <= 0x303f) // CJK symbols and punctuations
+ || (cc >= 0xff01 && cc <= 0xff0f) // Full width ASCII punctuations
+ || (cc >= 0xff1a && cc <= 0xff20) // ..
+ || (cc >= 0xff3b && cc <= 0xff40) // ..
+ || (cc >= 0xff5b && cc <= 0xff65); // ..
}
// Whether line break is allowed before "cc".
@@ -1817,8 +1863,9 @@ int mb_tail_off(char_u *base, char_u *p)
int i;
int j;
- if (*p == NUL)
+ if (*p == NUL) {
return 0;
+ }
// Find the last character that is 10xx.xxxx
for (i = 0; (p[i + 1] & 0xc0) == 0x80; i++) {}
@@ -1842,10 +1889,10 @@ int mb_tail_off(char_u *base, char_u *p)
void utf_find_illegal(void)
{
pos_T pos = curwin->w_cursor;
- char_u *p;
+ char_u *p;
int len;
vimconv_T vimconv;
- char_u *tofree = NULL;
+ char_u *tofree = NULL;
vimconv.vc_type = CONV_NONE;
if (enc_canon_props(curbuf->b_p_fenc) & ENC_8BIT) {
@@ -1861,8 +1908,9 @@ void utf_find_illegal(void)
if (vimconv.vc_type != CONV_NONE) {
xfree(tofree);
tofree = string_convert(&vimconv, p, NULL);
- if (tofree == NULL)
+ if (tofree == NULL) {
break;
+ }
p = tofree;
}
@@ -1871,10 +1919,10 @@ void utf_find_illegal(void)
* utf_ptr2len()) or too many of them (overlong sequence). */
len = utf_ptr2len(p);
if (*p >= 0x80 && (len == 1
- || utf_char2len(utf_ptr2char(p)) != len)) {
- if (vimconv.vc_type == CONV_NONE)
+ || utf_char2len(utf_ptr2char(p)) != len)) {
+ if (vimconv.vc_type == CONV_NONE) {
curwin->w_cursor.col += (colnr_T)(p - get_cursor_pos_ptr());
- else {
+ } else {
int l;
len = (int)(p - tofree);
@@ -1887,13 +1935,14 @@ void utf_find_illegal(void)
}
p += len;
}
- if (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
+ if (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count) {
break;
+ }
++curwin->w_cursor.lnum;
curwin->w_cursor.col = 0;
}
- /* didn't find it: don't move and beep */
+ // didn't find it: don't move and beep
curwin->w_cursor = pos;
beep_flush();
@@ -1947,13 +1996,10 @@ void mb_check_adjust_col(void *win_)
}
}
-/*
- * Return a pointer to the character before "*p", if there is one.
- */
-char_u * mb_prevptr(
- char_u *line, /* start of the string */
- char_u *p
- )
+/// @param line start of the string
+///
+/// @return a pointer to the character before "*p", if there is one.
+char_u *mb_prevptr(char_u *line, char_u *p)
{
if (p > line) {
MB_PTR_BACK(line, p);
@@ -1967,14 +2013,16 @@ char_u * mb_prevptr(
*/
int mb_charlen(char_u *str)
{
- char_u *p = str;
+ char_u *p = str;
int count;
- if (p == NULL)
+ if (p == NULL) {
return 0;
+ }
- for (count = 0; *p != NUL; count++)
+ for (count = 0; *p != NUL; count++) {
p += (*mb_ptr2len)(p);
+ }
return count;
}
@@ -1984,11 +2032,12 @@ int mb_charlen(char_u *str)
*/
int mb_charlen_len(char_u *str, int len)
{
- char_u *p = str;
+ char_u *p = str;
int count;
- for (count = 0; *p != NUL && p < str + len; count++)
+ for (count = 0; *p != NUL && p < str + len; count++) {
p += (*mb_ptr2len)(p);
+ }
return count;
}
@@ -2050,12 +2099,14 @@ const char *mb_unescape(const char **const pp)
/*
* Skip the Vim specific head of a 'encoding' name.
*/
-char_u * enc_skip(char_u *p)
+char_u *enc_skip(char_u *p)
{
- if (STRNCMP(p, "2byte-", 6) == 0)
+ if (STRNCMP(p, "2byte-", 6) == 0) {
return p + 6;
- if (STRNCMP(p, "8bit-", 5) == 0)
+ }
+ if (STRNCMP(p, "8bit-", 5) == 0) {
return p + 5;
+ }
return p;
}
@@ -2067,7 +2118,7 @@ char_u * enc_skip(char_u *p)
*/
char_u *enc_canonize(char_u *enc) FUNC_ATTR_NONNULL_RET
{
- char_u *p, *s;
+ char_u *p, *s;
int i;
if (STRCMP(enc, "default") == 0) {
@@ -2075,47 +2126,51 @@ char_u *enc_canonize(char_u *enc) FUNC_ATTR_NONNULL_RET
return vim_strsave(fenc_default);
}
- /* copy "enc" to allocated memory, with room for two '-' */
+ // copy "enc" to allocated memory, with room for two '-'
char_u *r = xmalloc(STRLEN(enc) + 3);
- /* Make it all lower case and replace '_' with '-'. */
+ // Make it all lower case and replace '_' with '-'.
p = r;
for (s = enc; *s != NUL; ++s) {
- if (*s == '_')
+ if (*s == '_') {
*p++ = '-';
- else
+ } else {
*p++ = TOLOWER_ASC(*s);
+ }
}
*p = NUL;
- /* Skip "2byte-" and "8bit-". */
+ // Skip "2byte-" and "8bit-".
p = enc_skip(r);
- /* Change "microsoft-cp" to "cp". Used in some spell files. */
- if (STRNCMP(p, "microsoft-cp", 12) == 0)
+ // Change "microsoft-cp" to "cp". Used in some spell files.
+ if (STRNCMP(p, "microsoft-cp", 12) == 0) {
STRMOVE(p, p + 10);
+ }
- /* "iso8859" -> "iso-8859" */
+ // "iso8859" -> "iso-8859"
if (STRNCMP(p, "iso8859", 7) == 0) {
STRMOVE(p + 4, p + 3);
p[3] = '-';
}
- /* "iso-8859n" -> "iso-8859-n" */
+ // "iso-8859n" -> "iso-8859-n"
if (STRNCMP(p, "iso-8859", 8) == 0 && p[8] != '-') {
STRMOVE(p + 9, p + 8);
p[8] = '-';
}
- /* "latin-N" -> "latinN" */
- if (STRNCMP(p, "latin-", 6) == 0)
+ // "latin-N" -> "latinN"
+ if (STRNCMP(p, "latin-", 6) == 0) {
STRMOVE(p + 5, p + 6);
+ }
if (enc_canon_search(p) >= 0) {
- /* canonical name can be used unmodified */
- if (p != r)
+ // canonical name can be used unmodified
+ if (p != r) {
STRMOVE(r, p);
+ }
} else if ((i = enc_alias_search(p)) >= 0) {
- /* alias recognized, get canonical name */
+ // alias recognized, get canonical name
xfree(r);
r = vim_strsave((char_u *)enc_canon_table[i].name);
}
@@ -2130,9 +2185,11 @@ static int enc_alias_search(char_u *name)
{
int i;
- for (i = 0; enc_alias_table[i].name != NULL; ++i)
- if (STRCMP(name, enc_alias_table[i].name) == 0)
+ for (i = 0; enc_alias_table[i].name != NULL; ++i) {
+ if (STRCMP(name, enc_alias_table[i].name) == 0) {
return enc_alias_table[i].canon;
+ }
+ }
return -1;
}
@@ -2145,19 +2202,19 @@ static int enc_alias_search(char_u *name)
* Get the canonicalized encoding of the current locale.
* Returns an allocated string when successful, NULL when not.
*/
-char_u * enc_locale(void)
+char_u *enc_locale(void)
{
int i;
char buf[50];
const char *s;
-# ifdef HAVE_NL_LANGINFO_CODESET
+#ifdef HAVE_NL_LANGINFO_CODESET
if (!(s = nl_langinfo(CODESET)) || *s == NUL)
-# endif
+#endif
{
-# if defined(HAVE_LOCALE_H)
+#if defined(HAVE_LOCALE_H)
if (!(s = setlocale(LC_CTYPE, NULL)) || *s == NUL)
-# endif
+#endif
{
if ((s = os_getenv("LC_ALL"))) {
if ((s = os_getenv("LC_CTYPE"))) {
@@ -2208,7 +2265,7 @@ enc_locale_copy_enc:
return enc_canonize((char_u *)buf);
}
-# if defined(HAVE_ICONV)
+#if defined(HAVE_ICONV)
/*
@@ -2217,18 +2274,18 @@ enc_locale_copy_enc:
* Returns (void *)-1 if failed.
* (should return iconv_t, but that causes problems with prototypes).
*/
-void * my_iconv_open(char_u *to, char_u *from)
+void *my_iconv_open(char_u *to, char_u *from)
{
iconv_t fd;
-#define ICONV_TESTLEN 400
+# define ICONV_TESTLEN 400
char_u tobuf[ICONV_TESTLEN];
- char *p;
+ char *p;
size_t tolen;
static WorkingStatus iconv_working = kUnknown;
- if (iconv_working == kBroken)
- return (void *)-1; /* detected a broken iconv() previously */
-
+ if (iconv_working == kBroken) {
+ return (void *)-1; // detected a broken iconv() previously
+ }
fd = iconv_open((char *)enc_skip(to), (char *)enc_skip(from));
if (fd != (iconv_t)-1 && iconv_working == kUnknown) {
@@ -2246,8 +2303,9 @@ void * my_iconv_open(char_u *to, char_u *from)
iconv_working = kBroken;
iconv_close(fd);
fd = (iconv_t)-1;
- } else
+ } else {
iconv_working = kWorking;
+ }
}
return (void *)fd;
@@ -2260,17 +2318,17 @@ void * my_iconv_open(char_u *to, char_u *from)
* Returns the converted string in allocated memory. NULL for an error.
* If resultlenp is not NULL, sets it to the result length in bytes.
*/
-static char_u *iconv_string(const vimconv_T *const vcp, char_u *str,
- size_t slen, size_t *unconvlenp, size_t *resultlenp)
+static char_u *iconv_string(const vimconv_T *const vcp, char_u *str, size_t slen,
+ size_t *unconvlenp, size_t *resultlenp)
{
- const char *from;
+ const char *from;
size_t fromlen;
- char *to;
+ char *to;
size_t tolen;
size_t len = 0;
size_t done = 0;
- char_u *result = NULL;
- char_u *p;
+ char_u *result = NULL;
+ char_u *p;
int l;
from = (char *)str;
@@ -2281,8 +2339,9 @@ static char_u *iconv_string(const vimconv_T *const vcp, char_u *str,
* increase the buffer size. */
len = len + fromlen * 2 + 40;
p = xmalloc(len);
- if (done > 0)
+ if (done > 0) {
memmove(p, result, done);
+ }
xfree(result);
result = p;
}
@@ -2330,12 +2389,13 @@ static char_u *iconv_string(const vimconv_T *const vcp, char_u *str,
done = to - (char *)result;
}
- if (resultlenp != NULL && result != NULL)
+ if (resultlenp != NULL && result != NULL) {
*resultlenp = (size_t)(to - (char *)result);
+ }
return result;
}
-# endif // HAVE_ICONV
+#endif // HAVE_ICONV
@@ -2354,12 +2414,10 @@ int convert_setup(vimconv_T *vcp, char_u *from, char_u *to)
return convert_setup_ext(vcp, from, true, to, true);
}
-/*
- * As convert_setup(), but only when from_unicode_is_utf8 is TRUE will all
- * "from" unicode charsets be considered utf-8. Same for "to".
- */
-int convert_setup_ext(vimconv_T *vcp, char_u *from, bool from_unicode_is_utf8,
- char_u *to, bool to_unicode_is_utf8)
+/// As convert_setup(), but only when from_unicode_is_utf8 is true will all
+/// "from" unicode charsets be considered utf-8. Same for "to".
+int convert_setup_ext(vimconv_T *vcp, char_u *from, bool from_unicode_is_utf8, char_u *to,
+ bool to_unicode_is_utf8)
{
int from_prop;
int to_prop;
@@ -2367,58 +2425,61 @@ int convert_setup_ext(vimconv_T *vcp, char_u *from, bool from_unicode_is_utf8,
int to_is_utf8;
// Reset to no conversion.
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
if (vcp->vc_type == CONV_ICONV && vcp->vc_fd != (iconv_t)-1) {
iconv_close(vcp->vc_fd);
}
-# endif
+#endif
*vcp = (vimconv_T)MBYTE_NONE_CONV;
- /* No conversion when one of the names is empty or they are equal. */
+ // No conversion when one of the names is empty or they are equal.
if (from == NULL || *from == NUL || to == NULL || *to == NUL
- || STRCMP(from, to) == 0)
+ || STRCMP(from, to) == 0) {
return OK;
+ }
from_prop = enc_canon_props(from);
to_prop = enc_canon_props(to);
- if (from_unicode_is_utf8)
+ if (from_unicode_is_utf8) {
from_is_utf8 = from_prop & ENC_UNICODE;
- else
+ } else {
from_is_utf8 = from_prop == ENC_UNICODE;
- if (to_unicode_is_utf8)
+ }
+ if (to_unicode_is_utf8) {
to_is_utf8 = to_prop & ENC_UNICODE;
- else
+ } else {
to_is_utf8 = to_prop == ENC_UNICODE;
+ }
if ((from_prop & ENC_LATIN1) && to_is_utf8) {
- /* Internal latin1 -> utf-8 conversion. */
+ // Internal latin1 -> utf-8 conversion.
vcp->vc_type = CONV_TO_UTF8;
- vcp->vc_factor = 2; /* up to twice as long */
+ vcp->vc_factor = 2; // up to twice as long
} else if ((from_prop & ENC_LATIN9) && to_is_utf8) {
- /* Internal latin9 -> utf-8 conversion. */
+ // Internal latin9 -> utf-8 conversion.
vcp->vc_type = CONV_9_TO_UTF8;
- vcp->vc_factor = 3; /* up to three as long (euro sign) */
+ vcp->vc_factor = 3; // up to three as long (euro sign)
} else if (from_is_utf8 && (to_prop & ENC_LATIN1)) {
- /* Internal utf-8 -> latin1 conversion. */
+ // Internal utf-8 -> latin1 conversion.
vcp->vc_type = CONV_TO_LATIN1;
} else if (from_is_utf8 && (to_prop & ENC_LATIN9)) {
- /* Internal utf-8 -> latin9 conversion. */
+ // Internal utf-8 -> latin9 conversion.
vcp->vc_type = CONV_TO_LATIN9;
}
-# ifdef HAVE_ICONV
+#ifdef HAVE_ICONV
else { // NOLINT(readability/braces)
// Use iconv() for conversion.
- vcp->vc_fd = (iconv_t)my_iconv_open(
- to_is_utf8 ? (char_u *)"utf-8" : to,
- from_is_utf8 ? (char_u *)"utf-8" : from);
+ vcp->vc_fd = (iconv_t)my_iconv_open(to_is_utf8 ? (char_u *)"utf-8" : to,
+ from_is_utf8 ? (char_u *)"utf-8" : from);
if (vcp->vc_fd != (iconv_t)-1) {
vcp->vc_type = CONV_ICONV;
- vcp->vc_factor = 4; /* could be longer too... */
+ vcp->vc_factor = 4; // could be longer too...
}
}
-# endif
- if (vcp->vc_type == CONV_NONE)
+#endif
+ if (vcp->vc_type == CONV_NONE) {
return FAIL;
+ }
return OK;
}
@@ -2440,130 +2501,154 @@ char_u *string_convert(const vimconv_T *const vcp, char_u *ptr, size_t *lenp)
* an incomplete sequence at the end it is not converted and "*unconvlenp" is
* set to the number of remaining bytes.
*/
-char_u * string_convert_ext(const vimconv_T *const vcp, char_u *ptr,
- size_t *lenp, size_t *unconvlenp)
+char_u *string_convert_ext(const vimconv_T *const vcp, char_u *ptr, size_t *lenp,
+ size_t *unconvlenp)
{
- char_u *retval = NULL;
- char_u *d;
+ char_u *retval = NULL;
+ char_u *d;
int l;
int c;
size_t len;
- if (lenp == NULL)
+ if (lenp == NULL) {
len = STRLEN(ptr);
- else
+ } else {
len = *lenp;
- if (len == 0)
+ }
+ if (len == 0) {
return vim_strsave((char_u *)"");
+ }
switch (vcp->vc_type) {
- case CONV_TO_UTF8: /* latin1 to utf-8 conversion */
- retval = xmalloc(len * 2 + 1);
- d = retval;
- for (size_t i = 0; i < len; ++i) {
- c = ptr[i];
- if (c < 0x80)
- *d++ = c;
- else {
- *d++ = 0xc0 + ((unsigned)c >> 6);
- *d++ = 0x80 + (c & 0x3f);
- }
+ case CONV_TO_UTF8: // latin1 to utf-8 conversion
+ retval = xmalloc(len * 2 + 1);
+ d = retval;
+ for (size_t i = 0; i < len; ++i) {
+ c = ptr[i];
+ if (c < 0x80) {
+ *d++ = c;
+ } else {
+ *d++ = 0xc0 + ((unsigned)c >> 6);
+ *d++ = 0x80 + (c & 0x3f);
}
- *d = NUL;
- if (lenp != NULL)
- *lenp = (size_t)(d - retval);
- break;
+ }
+ *d = NUL;
+ if (lenp != NULL) {
+ *lenp = (size_t)(d - retval);
+ }
+ break;
- case CONV_9_TO_UTF8: /* latin9 to utf-8 conversion */
- retval = xmalloc(len * 3 + 1);
- d = retval;
- for (size_t i = 0; i < len; ++i) {
- c = ptr[i];
- switch (c) {
- case 0xa4: c = 0x20ac; break; /* euro */
- case 0xa6: c = 0x0160; break; /* S hat */
- case 0xa8: c = 0x0161; break; /* S -hat */
- case 0xb4: c = 0x017d; break; /* Z hat */
- case 0xb8: c = 0x017e; break; /* Z -hat */
- case 0xbc: c = 0x0152; break; /* OE */
- case 0xbd: c = 0x0153; break; /* oe */
- case 0xbe: c = 0x0178; break; /* Y */
- }
- d += utf_char2bytes(c, d);
+ case CONV_9_TO_UTF8: // latin9 to utf-8 conversion
+ retval = xmalloc(len * 3 + 1);
+ d = retval;
+ for (size_t i = 0; i < len; ++i) {
+ c = ptr[i];
+ switch (c) {
+ case 0xa4:
+ c = 0x20ac; break; // euro
+ case 0xa6:
+ c = 0x0160; break; // S hat
+ case 0xa8:
+ c = 0x0161; break; // S -hat
+ case 0xb4:
+ c = 0x017d; break; // Z hat
+ case 0xb8:
+ c = 0x017e; break; // Z -hat
+ case 0xbc:
+ c = 0x0152; break; // OE
+ case 0xbd:
+ c = 0x0153; break; // oe
+ case 0xbe:
+ c = 0x0178; break; // Y
}
- *d = NUL;
- if (lenp != NULL)
- *lenp = (size_t)(d - retval);
- break;
+ d += utf_char2bytes(c, d);
+ }
+ *d = NUL;
+ if (lenp != NULL) {
+ *lenp = (size_t)(d - retval);
+ }
+ break;
- case CONV_TO_LATIN1: /* utf-8 to latin1 conversion */
- case CONV_TO_LATIN9: /* utf-8 to latin9 conversion */
- retval = xmalloc(len + 1);
- d = retval;
- for (size_t i = 0; i < len; ++i) {
- l = utf_ptr2len_len(ptr + i, len - i);
- if (l == 0)
- *d++ = NUL;
- else if (l == 1) {
- uint8_t l_w = utf8len_tab_zero[ptr[i]];
-
- if (l_w == 0) {
- /* Illegal utf-8 byte cannot be converted */
+ case CONV_TO_LATIN1: // utf-8 to latin1 conversion
+ case CONV_TO_LATIN9: // utf-8 to latin9 conversion
+ retval = xmalloc(len + 1);
+ d = retval;
+ for (size_t i = 0; i < len; ++i) {
+ l = utf_ptr2len_len(ptr + i, len - i);
+ if (l == 0) {
+ *d++ = NUL;
+ } else if (l == 1) {
+ uint8_t l_w = utf8len_tab_zero[ptr[i]];
+
+ if (l_w == 0) {
+ // Illegal utf-8 byte cannot be converted
+ xfree(retval);
+ return NULL;
+ }
+ if (unconvlenp != NULL && l_w > len - i) {
+ // Incomplete sequence at the end.
+ *unconvlenp = len - i;
+ break;
+ }
+ *d++ = ptr[i];
+ } else {
+ c = utf_ptr2char(ptr + i);
+ if (vcp->vc_type == CONV_TO_LATIN9) {
+ switch (c) {
+ case 0x20ac:
+ c = 0xa4; break; // euro
+ case 0x0160:
+ c = 0xa6; break; // S hat
+ case 0x0161:
+ c = 0xa8; break; // S -hat
+ case 0x017d:
+ c = 0xb4; break; // Z hat
+ case 0x017e:
+ c = 0xb8; break; // Z -hat
+ case 0x0152:
+ c = 0xbc; break; // OE
+ case 0x0153:
+ c = 0xbd; break; // oe
+ case 0x0178:
+ c = 0xbe; break; // Y
+ case 0xa4:
+ case 0xa6:
+ case 0xa8:
+ case 0xb4:
+ case 0xb8:
+ case 0xbc:
+ case 0xbd:
+ case 0xbe:
+ c = 0x100; break; // not in latin9
+ }
+ }
+ if (!utf_iscomposing(c)) { // skip composing chars
+ if (c < 0x100) {
+ *d++ = c;
+ } else if (vcp->vc_fail) {
xfree(retval);
return NULL;
- }
- if (unconvlenp != NULL && l_w > len - i) {
- /* Incomplete sequence at the end. */
- *unconvlenp = len - i;
- break;
- }
- *d++ = ptr[i];
- } else {
- c = utf_ptr2char(ptr + i);
- if (vcp->vc_type == CONV_TO_LATIN9)
- switch (c) {
- case 0x20ac: c = 0xa4; break; /* euro */
- case 0x0160: c = 0xa6; break; /* S hat */
- case 0x0161: c = 0xa8; break; /* S -hat */
- case 0x017d: c = 0xb4; break; /* Z hat */
- case 0x017e: c = 0xb8; break; /* Z -hat */
- case 0x0152: c = 0xbc; break; /* OE */
- case 0x0153: c = 0xbd; break; /* oe */
- case 0x0178: c = 0xbe; break; /* Y */
- case 0xa4:
- case 0xa6:
- case 0xa8:
- case 0xb4:
- case 0xb8:
- case 0xbc:
- case 0xbd:
- case 0xbe: c = 0x100; break; /* not in latin9 */
- }
- if (!utf_iscomposing(c)) { /* skip composing chars */
- if (c < 0x100)
- *d++ = c;
- else if (vcp->vc_fail) {
- xfree(retval);
- return NULL;
- } else {
- *d++ = 0xbf;
- if (utf_char2cells(c) > 1)
- *d++ = '?';
+ } else {
+ *d++ = 0xbf;
+ if (utf_char2cells(c) > 1) {
+ *d++ = '?';
}
}
- i += l - 1;
}
+ i += l - 1;
}
- *d = NUL;
- if (lenp != NULL)
- *lenp = (size_t)(d - retval);
- break;
+ }
+ *d = NUL;
+ if (lenp != NULL) {
+ *lenp = (size_t)(d - retval);
+ }
+ break;
-# ifdef HAVE_ICONV
- case CONV_ICONV: // conversion with vcp->vc_fd
- retval = iconv_string(vcp, ptr, len, unconvlenp, lenp);
- break;
-# endif
+#ifdef HAVE_ICONV
+ case CONV_ICONV: // conversion with vcp->vc_fd
+ retval = iconv_string(vcp, ptr, len, unconvlenp, lenp);
+ break;
+#endif
}
return retval;
diff --git a/src/nvim/memfile.c b/src/nvim/memfile.c
index 7bed644da3..438340e0c4 100644
--- a/src/nvim/memfile.c
+++ b/src/nvim/memfile.c
@@ -39,24 +39,24 @@
/// mf_fullname() make file name full path (use before first :cd)
#include <assert.h>
+#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
-#include <string.h>
#include <stdbool.h>
-#include <fcntl.h>
+#include <string.h>
-#include "nvim/vim.h"
#include "nvim/ascii.h"
-#include "nvim/memfile.h"
+#include "nvim/assert.h"
#include "nvim/fileio.h"
+#include "nvim/memfile.h"
#include "nvim/memline.h"
-#include "nvim/message.h"
#include "nvim/memory.h"
+#include "nvim/message.h"
+#include "nvim/os/input.h"
+#include "nvim/os/os.h"
#include "nvim/os_unix.h"
#include "nvim/path.h"
-#include "nvim/assert.h"
-#include "nvim/os/os.h"
-#include "nvim/os/input.h"
+#include "nvim/vim.h"
#define MEMFILE_PAGE_SIZE 4096 /// default page size
@@ -168,7 +168,7 @@ void mf_close(memfile_T *mfp, bool del_file)
return;
}
if (mfp->mf_fd >= 0 && close(mfp->mf_fd) < 0) {
- EMSG(_(e_swapclose));
+ EMSG(_(e_swapclose));
}
if (del_file && mfp->mf_fname != NULL) {
os_remove((char *)mfp->mf_fname);
@@ -282,14 +282,16 @@ bhdr_T *mf_new(memfile_T *mfp, bool negative, unsigned page_count)
bhdr_T *mf_get(memfile_T *mfp, blocknr_T nr, unsigned page_count)
{
// check block number exists
- if (nr >= mfp->mf_blocknr_max || nr <= mfp->mf_blocknr_min)
+ if (nr >= mfp->mf_blocknr_max || nr <= mfp->mf_blocknr_min) {
return NULL;
+ }
// see if it is in the cache
bhdr_T *hp = mf_find_hash(mfp, nr);
if (hp == NULL) { // not in the hash list
- if (nr < 0 || nr >= mfp->mf_infile_count) // can't be in the file
+ if (nr < 0 || nr >= mfp->mf_infile_count) { // can't be in the file
return NULL;
+ }
// could check here if the block is in the free list
@@ -331,8 +333,9 @@ void mf_put(memfile_T *mfp, bhdr_T *hp, bool dirty, bool infile)
mfp->mf_dirty = true;
}
hp->bh_flags = flags;
- if (infile)
+ if (infile) {
mf_trans_add(mfp, hp); // may translate negative in positive nr
+ }
}
/// Signal block as no longer used (may put it in the free list).
@@ -381,32 +384,38 @@ int mf_sync(memfile_T *mfp, int flags)
// fails then we give up.
int status = OK;
bhdr_T *hp;
- for (hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
+ for (hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev) {
if (((flags & MFS_ALL) || hp->bh_bnum >= 0)
&& (hp->bh_flags & BH_DIRTY)
&& (status == OK || (hp->bh_bnum >= 0
&& hp->bh_bnum < mfp->mf_infile_count))) {
- if ((flags & MFS_ZERO) && hp->bh_bnum != 0)
+ if ((flags & MFS_ZERO) && hp->bh_bnum != 0) {
continue;
+ }
if (mf_write(mfp, hp) == FAIL) {
- if (status == FAIL) // double error: quit syncing
+ if (status == FAIL) { // double error: quit syncing
break;
+ }
status = FAIL;
}
if (flags & MFS_STOP) { // Stop when char available now.
- if (os_char_avail())
+ if (os_char_avail()) {
break;
+ }
} else {
os_breakcheck();
}
- if (got_int)
+ if (got_int) {
break;
+ }
}
+ }
// If the whole list is flushed, the memfile is not dirty anymore.
// In case of an error, dirty flag is also set, to avoid trying all the time.
- if (hp == NULL || status == FAIL)
+ if (hp == NULL || status == FAIL) {
mfp->mf_dirty = false;
+ }
if (flags & MFS_FLUSH) {
if (os_fsync(mfp->mf_fd)) {
@@ -465,15 +474,17 @@ static void mf_ins_used(memfile_T *mfp, bhdr_T *hp)
/// Remove block from memfile's used list.
static void mf_rem_used(memfile_T *mfp, bhdr_T *hp)
{
- if (hp->bh_next == NULL) // last block in used list
+ if (hp->bh_next == NULL) { // last block in used list
mfp->mf_used_last = hp->bh_prev;
- else
+ } else {
hp->bh_next->bh_prev = hp->bh_prev;
+ }
- if (hp->bh_prev == NULL) // first block in used list
+ if (hp->bh_prev == NULL) { // first block in used list
mfp->mf_used_first = hp->bh_next;
- else
+ } else {
hp->bh_prev->bh_next = hp->bh_next;
+ }
}
/// Release as many blocks as possible.
@@ -554,8 +565,9 @@ static bhdr_T *mf_rem_free(memfile_T *mfp)
/// - Error reading file.
static int mf_read(memfile_T *mfp, bhdr_T *hp)
{
- if (mfp->mf_fd < 0) // there is no file, can't read
+ if (mfp->mf_fd < 0) { // there is no file, can't read
return FAIL;
+ }
unsigned page_size = mfp->mf_page_size;
// TODO(elmart): Check (page_size * hp->bh_bnum) within off_T bounds.
@@ -592,12 +604,15 @@ static int mf_write(memfile_T *mfp, bhdr_T *hp)
unsigned page_count; // number of pages written
unsigned size; // number of bytes written
- if (mfp->mf_fd < 0) // there is no file, can't write
+ if (mfp->mf_fd < 0) { // there is no file, can't write
return FAIL;
+ }
- if (hp->bh_bnum < 0) // must assign file block number
- if (mf_trans_add(mfp, hp) == FAIL)
+ if (hp->bh_bnum < 0) { // must assign file block number
+ if (mf_trans_add(mfp, hp) == FAIL) {
return FAIL;
+ }
+ }
page_size = mfp->mf_page_size;
@@ -620,10 +635,11 @@ static int mf_write(memfile_T *mfp, bhdr_T *hp)
PERROR(_("E296: Seek error in swap file write"));
return FAIL;
}
- if (hp2 == NULL) // freed block, fill with dummy data
+ if (hp2 == NULL) { // freed block, fill with dummy data
page_count = 1;
- else
+ } else {
page_count = hp2->bh_page_count;
+ }
size = page_size * page_count;
void *data = (hp2 == NULL) ? hp->bh_data : hp2->bh_data;
if ((unsigned)write_eintr(mfp->mf_fd, data, size) != size) {
@@ -631,18 +647,22 @@ static int mf_write(memfile_T *mfp, bhdr_T *hp)
/// disk is full. We give the message again only after a successful
/// write or when hitting a key. We keep on trying, in case some
/// space becomes available.
- if (!did_swapwrite_msg)
+ if (!did_swapwrite_msg) {
EMSG(_("E297: Write error in swap file"));
+ }
did_swapwrite_msg = true;
return FAIL;
}
did_swapwrite_msg = false;
- if (hp2 != NULL) // written a non-dummy block
+ if (hp2 != NULL) { // written a non-dummy block
hp2->bh_flags &= ~BH_DIRTY;
- if (nr + (blocknr_T)page_count > mfp->mf_infile_count) // appended to file
+ }
+ if (nr + (blocknr_T)page_count > mfp->mf_infile_count) { // appended to file
mfp->mf_infile_count = nr + page_count;
- if (nr == hp->bh_bnum) // written the desired block
+ }
+ if (nr == hp->bh_bnum) { // written the desired block
break;
+ }
}
return OK;
}
@@ -653,8 +673,9 @@ static int mf_write(memfile_T *mfp, bhdr_T *hp)
/// FAIL On failure.
static int mf_trans_add(memfile_T *mfp, bhdr_T *hp)
{
- if (hp->bh_bnum >= 0) // it's already positive
+ if (hp->bh_bnum >= 0) { // it's already positive
return OK;
+ }
mf_blocknr_trans_item_T *np = xmalloc(sizeof(mf_blocknr_trans_item_T));
@@ -702,8 +723,9 @@ blocknr_T mf_trans_del(memfile_T *mfp, blocknr_T old_nr)
mf_blocknr_trans_item_T *np =
(mf_blocknr_trans_item_T *)mf_hash_find(&mfp->mf_trans, old_nr);
- if (np == NULL) // not found
+ if (np == NULL) { // not found
return old_nr;
+ }
mfp->mf_neg_count--;
blocknr_T new_bnum = np->nt_new_bnum;
@@ -834,8 +856,9 @@ static void mf_hash_free_all(mf_hashtab_T *mht)
static mf_hashitem_T *mf_hash_find(mf_hashtab_T *mht, blocknr_T key)
{
mf_hashitem_T *mhi = mht->mht_buckets[(size_t)key & mht->mht_mask];
- while (mhi != NULL && mhi->mhi_key != key)
+ while (mhi != NULL && mhi->mhi_key != key) {
mhi = mhi->mhi_next;
+ }
return mhi;
}
@@ -845,8 +868,9 @@ static void mf_hash_add_item(mf_hashtab_T *mht, mf_hashitem_T *mhi)
size_t idx = (size_t)mhi->mhi_key & mht->mht_mask;
mhi->mhi_next = mht->mht_buckets[idx];
mhi->mhi_prev = NULL;
- if (mhi->mhi_next != NULL)
+ if (mhi->mhi_next != NULL) {
mhi->mhi_next->mhi_prev = mhi;
+ }
mht->mht_buckets[idx] = mhi;
mht->mht_count++;
@@ -861,14 +885,16 @@ static void mf_hash_add_item(mf_hashtab_T *mht, mf_hashitem_T *mhi)
/// Remove item from hashtable. Item must be non NULL and within hashtable.
static void mf_hash_rem_item(mf_hashtab_T *mht, mf_hashitem_T *mhi)
{
- if (mhi->mhi_prev == NULL)
+ if (mhi->mhi_prev == NULL) {
mht->mht_buckets[(size_t)mhi->mhi_key & mht->mht_mask] =
mhi->mhi_next;
- else
+ } else {
mhi->mhi_prev->mhi_next = mhi->mhi_next;
+ }
- if (mhi->mhi_next != NULL)
+ if (mhi->mhi_next != NULL) {
mhi->mhi_next->mhi_prev = mhi->mhi_prev;
+ }
mht->mht_count--;
@@ -884,8 +910,9 @@ static void mf_hash_grow(mf_hashtab_T *mht)
mf_hashitem_T **buckets = xcalloc(1, size);
int shift = 0;
- while ((mht->mht_mask >> shift) != 0)
+ while ((mht->mht_mask >> shift) != 0) {
shift++;
+ }
for (size_t i = 0; i <= mht->mht_mask; i++) {
/// Traverse the items in the i-th original bucket and move them into
@@ -914,13 +941,16 @@ static void mf_hash_grow(mf_hashtab_T *mht)
}
}
- for (size_t j = 0; j < MHT_GROWTH_FACTOR; j++)
- if (tails[j] != NULL)
+ for (size_t j = 0; j < MHT_GROWTH_FACTOR; j++) {
+ if (tails[j] != NULL) {
tails[j]->mhi_next = NULL;
+ }
+ }
}
- if (mht->mht_buckets != mht->mht_small_buckets)
+ if (mht->mht_buckets != mht->mht_small_buckets) {
xfree(mht->mht_buckets);
+ }
mht->mht_buckets = buckets;
mht->mht_mask = (mht->mht_mask + 1) * MHT_GROWTH_FACTOR - 1;
diff --git a/src/nvim/memfile_defs.h b/src/nvim/memfile_defs.h
index 2402d2147d..3eaa7d83e0 100644
--- a/src/nvim/memfile_defs.h
+++ b/src/nvim/memfile_defs.h
@@ -101,7 +101,7 @@ typedef struct memfile {
blocknr_T mf_neg_count; /// number of negative blocks numbers
blocknr_T mf_infile_count; /// number of pages in the file
unsigned mf_page_size; /// number of bytes in a page
- bool mf_dirty; /// TRUE if there are dirty blocks
+ bool mf_dirty; /// true if there are dirty blocks
} memfile_T;
#endif // NVIM_MEMFILE_DEFS_H
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index cb2437b2b3..69598bbdda 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -38,29 +38,31 @@
#include <assert.h>
#include <errno.h>
+#include <fcntl.h>
#include <inttypes.h>
-#include <string.h>
#include <stdbool.h>
-#include <fcntl.h>
+#include <string.h>
#include "nvim/ascii.h"
-#include "nvim/vim.h"
-#include "nvim/memline.h"
#include "nvim/buffer.h"
#include "nvim/change.h"
#include "nvim/cursor.h"
#include "nvim/eval.h"
-#include "nvim/getchar.h"
#include "nvim/fileio.h"
#include "nvim/func_attr.h"
+#include "nvim/getchar.h"
#include "nvim/main.h"
#include "nvim/mark.h"
#include "nvim/mbyte.h"
#include "nvim/memfile.h"
+#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
#include "nvim/option.h"
+#include "nvim/os/input.h"
+#include "nvim/os/os.h"
+#include "nvim/os/process.h"
#include "nvim/os_unix.h"
#include "nvim/path.h"
#include "nvim/screen.h"
@@ -68,44 +70,42 @@
#include "nvim/spell.h"
#include "nvim/strings.h"
#include "nvim/ui.h"
-#include "nvim/version.h"
#include "nvim/undo.h"
+#include "nvim/version.h"
+#include "nvim/vim.h"
#include "nvim/window.h"
-#include "nvim/os/os.h"
-#include "nvim/os/process.h"
-#include "nvim/os/input.h"
-#ifndef UNIX /* it's in os/unix_defs.h for Unix */
+#ifndef UNIX // it's in os/unix_defs.h for Unix
# include <time.h>
#endif
-typedef struct block0 ZERO_BL; /* contents of the first block */
-typedef struct pointer_block PTR_BL; /* contents of a pointer block */
-typedef struct data_block DATA_BL; /* contents of a data block */
-typedef struct pointer_entry PTR_EN; /* block/line-count pair */
+typedef struct block0 ZERO_BL; // contents of the first block
+typedef struct pointer_block PTR_BL; // contents of a pointer block
+typedef struct data_block DATA_BL; // contents of a data block
+typedef struct pointer_entry PTR_EN; // block/line-count pair
-#define DATA_ID (('d' << 8) + 'a') /* data block id */
-#define PTR_ID (('p' << 8) + 't') /* pointer block id */
-#define BLOCK0_ID0 'b' /* block 0 id 0 */
-#define BLOCK0_ID1 '0' /* block 0 id 1 */
+#define DATA_ID (('d' << 8) + 'a') // data block id
+#define PTR_ID (('p' << 8) + 't') // pointer block id
+#define BLOCK0_ID0 'b' // block 0 id 0
+#define BLOCK0_ID1 '0' // block 0 id 1
/*
* pointer to a block, used in a pointer block
*/
struct pointer_entry {
- blocknr_T pe_bnum; /* block number */
- linenr_T pe_line_count; /* number of lines in this branch */
- linenr_T pe_old_lnum; /* lnum for this block (for recovery) */
- int pe_page_count; /* number of pages in block pe_bnum */
+ blocknr_T pe_bnum; // block number
+ linenr_T pe_line_count; // number of lines in this branch
+ linenr_T pe_old_lnum; // lnum for this block (for recovery)
+ int pe_page_count; // number of pages in block pe_bnum
};
/*
* A pointer block contains a list of branches in the tree.
*/
struct pointer_block {
- uint16_t pb_id; /* ID for pointer block: PTR_ID */
- uint16_t pb_count; /* number of pointers in this block */
- uint16_t pb_count_max; /* maximum value for pb_count */
+ uint16_t pb_id; // ID for pointer block: PTR_ID
+ uint16_t pb_count; // number of pointers in this block
+ uint16_t pb_count_max; // maximum value for pb_count
PTR_EN pb_pointer[1]; /* list of pointers to blocks (actually longer)
* followed by empty space until end of page */
};
@@ -118,15 +118,15 @@ struct pointer_block {
* etc. Thus the order of the lines is the opposite of the line number.
*/
struct data_block {
- uint16_t db_id; /* ID for data block: DATA_ID */
- unsigned db_free; /* free space available */
- unsigned db_txt_start; /* byte where text starts */
- unsigned db_txt_end; /* byte just after data block */
- linenr_T db_line_count; /* number of lines in this block */
- unsigned db_index[1]; /* index for start of line (actually bigger)
- * followed by empty space upto db_txt_start
- * followed by the text in the lines until
- * end of page */
+ uint16_t db_id; // ID for data block: DATA_ID
+ unsigned db_free; // free space available
+ unsigned db_txt_start; // byte where text starts
+ unsigned db_txt_end; // byte just after data block
+ linenr_T db_line_count; // number of lines in this block
+ unsigned db_index[1]; // index for start of line (actually bigger)
+ // followed by empty space up to db_txt_start
+ // followed by the text in the lines until
+ // end of page
};
/*
@@ -140,12 +140,12 @@ struct data_block {
#define DB_MARKED ((unsigned)1 << ((sizeof(unsigned) * 8) - 1))
#define DB_INDEX_MASK (~DB_MARKED)
-#define INDEX_SIZE (sizeof(unsigned)) /* size of one db_index entry */
-#define HEADER_SIZE (sizeof(DATA_BL) - INDEX_SIZE) /* size of data block header */
+#define INDEX_SIZE (sizeof(unsigned)) // size of one db_index entry
+#define HEADER_SIZE (sizeof(DATA_BL) - INDEX_SIZE) // size of data block header
-#define B0_FNAME_SIZE_ORG 900 /* what it was in older versions */
-#define B0_FNAME_SIZE_NOCRYPT 898 /* 2 bytes used for other things */
-#define B0_FNAME_SIZE_CRYPT 890 /* 10 bytes used for other things */
+#define B0_FNAME_SIZE_ORG 900 // what it was in older versions
+#define B0_FNAME_SIZE_NOCRYPT 898 // 2 bytes used for other things
+#define B0_FNAME_SIZE_CRYPT 890 // 10 bytes used for other things
#define B0_UNAME_SIZE 40
#define B0_HNAME_SIZE 40
/*
@@ -172,18 +172,18 @@ struct data_block {
*/
struct block0 {
char_u b0_id[2]; ///< ID for block 0: BLOCK0_ID0 and BLOCK0_ID1.
- char_u b0_version[10]; /* Vim version string */
- char_u b0_page_size[4]; /* number of bytes per page */
- char_u b0_mtime[4]; /* last modification time of file */
- char_u b0_ino[4]; /* inode of b0_fname */
- char_u b0_pid[4]; /* process id of creator (or 0) */
- char_u b0_uname[B0_UNAME_SIZE]; /* name of user (uid if no name) */
- char_u b0_hname[B0_HNAME_SIZE]; /* host name (if it has a name) */
- char_u b0_fname[B0_FNAME_SIZE_ORG]; /* name of file being edited */
- long b0_magic_long; /* check for byte order of long */
- int b0_magic_int; /* check for byte order of int */
- short b0_magic_short; /* check for byte order of short */
- char_u b0_magic_char; /* check for last char */
+ char_u b0_version[10]; // Vim version string
+ char_u b0_page_size[4]; // number of bytes per page
+ char_u b0_mtime[4]; // last modification time of file
+ char_u b0_ino[4]; // inode of b0_fname
+ char_u b0_pid[4]; // process id of creator (or 0)
+ char_u b0_uname[B0_UNAME_SIZE]; // name of user (uid if no name)
+ char_u b0_hname[B0_HNAME_SIZE]; // host name (if it has a name)
+ char_u b0_fname[B0_FNAME_SIZE_ORG]; // name of file being edited
+ long b0_magic_long; // check for byte order of long
+ int b0_magic_int; // check for byte order of int
+ short b0_magic_short; // check for byte order of short
+ char_u b0_magic_char; // check for last char
};
/*
@@ -213,7 +213,7 @@ struct block0 {
* When empty there is only the NUL. */
#define B0_HAS_FENC 8
-#define STACK_INCR 5 /* nr of entries added to ml_stack at a time */
+#define STACK_INCR 5 // nr of entries added to ml_stack at a time
/*
* The line number where the first mark may be is remembered.
@@ -226,16 +226,16 @@ static linenr_T lowest_marked = 0;
/*
* arguments for ml_find_line()
*/
-#define ML_DELETE 0x11 /* delete line */
-#define ML_INSERT 0x12 /* insert line */
-#define ML_FIND 0x13 /* just find the line */
-#define ML_FLUSH 0x02 /* flush locked block */
-#define ML_SIMPLE(x) (x & 0x10) /* DEL, INS or FIND */
+#define ML_DELETE 0x11 // delete line
+#define ML_INSERT 0x12 // insert line
+#define ML_FIND 0x13 // just find the line
+#define ML_FLUSH 0x02 // flush locked block
+#define ML_SIMPLE(x) (x & 0x10) // DEL, INS or FIND
-/* argument for ml_upd_block0() */
+// argument for ml_upd_block0()
typedef enum {
- UB_FNAME = 0 /* update timestamp and filename */
- , UB_SAME_DIR /* update the B0_SAME_DIR flag */
+ UB_FNAME = 0 // update timestamp and filename
+ , UB_SAME_DIR // update the B0_SAME_DIR flag
} upd_block0_T;
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -249,10 +249,10 @@ typedef enum {
*/
int ml_open(buf_T *buf)
{
- bhdr_T *hp = NULL;
- ZERO_BL *b0p;
- PTR_BL *pp;
- DATA_BL *dp;
+ bhdr_T *hp = NULL;
+ ZERO_BL *b0p;
+ PTR_BL *pp;
+ DATA_BL *dp;
/*
* init fields in memline struct
@@ -264,6 +264,7 @@ int ml_open(buf_T *buf)
buf->b_ml.ml_line_lnum = 0; // no cached line
buf->b_ml.ml_line_offset = 0;
buf->b_ml.ml_chunksize = NULL;
+ buf->b_ml.ml_usedchunks = 0;
if (cmdmod.noswapfile) {
buf->b_p_swf = false;
@@ -306,7 +307,7 @@ int ml_open(buf_T *buf)
b0p->b0_magic_int = (int)B0_MAGIC_INT;
b0p->b0_magic_short = (short)B0_MAGIC_SHORT;
b0p->b0_magic_char = B0_MAGIC_CHAR;
- xstrlcpy(xstpcpy((char *) b0p->b0_version, "VIM "), Version, 6);
+ xstrlcpy(xstpcpy((char *)b0p->b0_version, "VIM "), Version, 6);
long_to_char((long)mfp->mf_page_size, b0p->b0_page_size);
if (!buf->b_spell) {
@@ -328,14 +329,16 @@ int ml_open(buf_T *buf)
* is created.
*/
mf_put(mfp, hp, true, false);
- if (!buf->b_help && !B_SPELL(buf))
+ if (!buf->b_help && !B_SPELL(buf)) {
(void)mf_sync(mfp, 0);
+ }
/*
* Fill in root pointer block and write page 1.
*/
- if ((hp = ml_new_ptr(mfp)) == NULL)
+ if ((hp = ml_new_ptr(mfp)) == NULL) {
goto error;
+ }
if (hp->bh_bnum != 1) {
IEMSG(_("E298: Didn't get block nr 1?"));
goto error;
@@ -345,7 +348,7 @@ int ml_open(buf_T *buf)
pp->pb_pointer[0].pe_bnum = 2;
pp->pb_pointer[0].pe_page_count = 1;
pp->pb_pointer[0].pe_old_lnum = 1;
- pp->pb_pointer[0].pe_line_count = 1; /* line count after insertion */
+ pp->pb_pointer[0].pe_line_count = 1; // line count after insertion
mf_put(mfp, hp, true, false);
/*
@@ -358,10 +361,10 @@ int ml_open(buf_T *buf)
}
dp = hp->bh_data;
- dp->db_index[0] = --dp->db_txt_start; /* at end of block */
+ dp->db_index[0] = --dp->db_txt_start; // at end of block
dp->db_free -= 1 + INDEX_SIZE;
dp->db_line_count = 1;
- *((char_u *)dp + dp->db_txt_start) = NUL; /* empty line */
+ *((char_u *)dp + dp->db_txt_start) = NUL; // empty line
return OK;
@@ -382,19 +385,19 @@ error:
*/
void ml_setname(buf_T *buf)
{
- int success = FALSE;
- memfile_T *mfp;
- char_u *fname;
- char_u *dirp;
+ bool success = false;
+ memfile_T *mfp;
+ char_u *fname;
+ char_u *dirp;
mfp = buf->b_ml.ml_mfp;
- if (mfp->mf_fd < 0) { /* there is no swap file yet */
+ if (mfp->mf_fd < 0) { // there is no swap file yet
/*
* When 'updatecount' is 0 and 'noswapfile' there is no swap file.
* For help files we will make a swap file now.
*/
if (p_uc != 0 && !cmdmod.noswapfile) {
- ml_open_file(buf); /* create a swap file */
+ ml_open_file(buf); // create a swap file
}
return;
}
@@ -405,50 +408,54 @@ void ml_setname(buf_T *buf)
dirp = p_dir;
bool found_existing_dir = false;
for (;; ) {
- if (*dirp == NUL) /* tried all directories, fail */
+ if (*dirp == NUL) { // tried all directories, fail
break;
+ }
fname = (char_u *)findswapname(buf, (char **)&dirp, (char *)mfp->mf_fname,
&found_existing_dir);
- /* alloc's fname */
- if (dirp == NULL) /* out of memory */
+ // alloc's fname
+ if (dirp == NULL) { // out of memory
break;
- if (fname == NULL) /* no file name found for this dir */
+ }
+ if (fname == NULL) { // no file name found for this dir
continue;
+ }
- /* if the file name is the same we don't have to do anything */
+ // if the file name is the same we don't have to do anything
if (fnamecmp(fname, mfp->mf_fname) == 0) {
xfree(fname);
- success = TRUE;
+ success = true;
break;
}
- /* need to close the swap file before renaming */
+ // need to close the swap file before renaming
if (mfp->mf_fd >= 0) {
close(mfp->mf_fd);
mfp->mf_fd = -1;
}
- /* try to rename the swap file */
+ // try to rename the swap file
if (vim_rename(mfp->mf_fname, fname) == 0) {
- success = TRUE;
+ success = true;
mf_free_fnames(mfp);
mf_set_fnames(mfp, fname);
ml_upd_block0(buf, UB_SAME_DIR);
break;
}
- xfree(fname); /* this fname didn't work, try another */
+ xfree(fname); // this fname didn't work, try another
}
- if (mfp->mf_fd == -1) { /* need to (re)open the swap file */
+ if (mfp->mf_fd == -1) { // need to (re)open the swap file
mfp->mf_fd = os_open((char *)mfp->mf_fname, O_RDWR, 0);
if (mfp->mf_fd < 0) {
- /* could not (re)open the swap file, what can we do???? */
+ // could not (re)open the swap file, what can we do????
EMSG(_("E301: Oops, lost the swap file!!!"));
return;
}
(void)os_set_cloexec(mfp->mf_fd);
}
- if (!success)
+ if (!success) {
EMSG(_("E302: Could not rename swap file"));
+ }
}
/*
@@ -472,21 +479,22 @@ void ml_open_files(void)
*/
void ml_open_file(buf_T *buf)
{
- memfile_T *mfp;
- char_u *fname;
- char_u *dirp;
+ memfile_T *mfp;
+ char_u *fname;
+ char_u *dirp;
mfp = buf->b_ml.ml_mfp;
if (mfp == NULL || mfp->mf_fd >= 0 || !buf->b_p_swf || cmdmod.noswapfile
|| buf->terminal) {
- return; /* nothing to do */
+ return; // nothing to do
}
- /* For a spell buffer use a temp file name. */
+ // For a spell buffer use a temp file name.
if (buf->b_spell) {
fname = vim_tempname();
- if (fname != NULL)
- (void)mf_open_file(mfp, fname); /* consumes fname! */
+ if (fname != NULL) {
+ (void)mf_open_file(mfp, fname); // consumes fname!
+ }
buf->b_may_swap = false;
return;
}
@@ -497,21 +505,24 @@ void ml_open_file(buf_T *buf)
dirp = p_dir;
bool found_existing_dir = false;
for (;; ) {
- if (*dirp == NUL)
+ if (*dirp == NUL) {
break;
+ }
// There is a small chance that between choosing the swap file name
// and creating it, another Vim creates the file. In that case the
// creation will fail and we will use another directory.
fname = (char_u *)findswapname(buf, (char **)&dirp, NULL,
&found_existing_dir);
- if (dirp == NULL)
- break; /* out of memory */
- if (fname == NULL)
+ if (dirp == NULL) {
+ break; // out of memory
+ }
+ if (fname == NULL) {
continue;
- if (mf_open_file(mfp, fname) == OK) { /* consumes fname! */
+ }
+ if (mf_open_file(mfp, fname) == OK) { // consumes fname!
ml_upd_block0(buf, UB_SAME_DIR);
- /* Flush block zero, so others can read it */
+ // Flush block zero, so others can read it
if (mf_sync(mfp, MFS_ZERO) == OK) {
/* Mark all blocks that should be in the swapfile as dirty.
* Needed for when the 'swapfile' option was reset, so that
@@ -519,7 +530,7 @@ void ml_open_file(buf_T *buf)
mf_set_dirty(mfp);
break;
}
- /* Writing block 0 failed: close the file and try another dir */
+ // Writing block 0 failed: close the file and try another dir
mf_close_file(buf, false);
}
}
@@ -527,13 +538,12 @@ void ml_open_file(buf_T *buf)
if (*p_dir != NUL && mfp->mf_fname == NULL) {
need_wait_return = true; // call wait_return later
no_wait_return++;
- (void)EMSG2(_(
- "E303: Unable to open swap file for \"%s\", recovery impossible"),
- buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname);
+ (void)EMSG2(_("E303: Unable to open swap file for \"%s\", recovery impossible"),
+ buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname);
--no_wait_return;
}
- /* don't try to open a swap file again */
+ // don't try to open a swap file again
buf->b_may_swap = false;
}
@@ -559,11 +569,13 @@ void check_need_swap(bool newfile)
*/
void ml_close(buf_T *buf, int del_file)
{
- if (buf->b_ml.ml_mfp == NULL) /* not open */
+ if (buf->b_ml.ml_mfp == NULL) { // not open
return;
- mf_close(buf->b_ml.ml_mfp, del_file); /* close the .swp file */
- if (buf->b_ml.ml_line_lnum != 0 && (buf->b_ml.ml_flags & ML_LINE_DIRTY))
+ }
+ mf_close(buf->b_ml.ml_mfp, del_file); // close the .swp file
+ if (buf->b_ml.ml_line_lnum != 0 && (buf->b_ml.ml_flags & ML_LINE_DIRTY)) {
xfree(buf->b_ml.ml_line_ptr);
+ }
xfree(buf->b_ml.ml_stack);
XFREE_CLEAR(buf->b_ml.ml_chunksize);
buf->b_ml.ml_mfp = NULL;
@@ -584,8 +596,8 @@ void ml_close_all(int del_file)
FOR_ALL_BUFFERS(buf) {
ml_close(buf, del_file && ((buf->b_flags & BF_PRESERVED) == 0));
}
- spell_delete_wordlist(); /* delete the internal wordlist */
- vim_deltempdir(); /* delete created temp directory */
+ spell_delete_wordlist(); // delete the internal wordlist
+ vim_deltempdir(); // delete created temp directory
}
/*
@@ -596,7 +608,7 @@ void ml_close_notmod(void)
{
FOR_ALL_BUFFERS(buf) {
if (!bufIsChanged(buf)) {
- ml_close(buf, TRUE); /* close all not-modified buffers */
+ ml_close(buf, TRUE); // close all not-modified buffers
}
}
}
@@ -632,13 +644,14 @@ static bool ml_check_b0_strings(ZERO_BL *b0p)
*/
static void ml_upd_block0(buf_T *buf, upd_block0_T what)
{
- memfile_T *mfp;
- bhdr_T *hp;
- ZERO_BL *b0p;
+ memfile_T *mfp;
+ bhdr_T *hp;
+ ZERO_BL *b0p;
mfp = buf->b_ml.ml_mfp;
- if (mfp == NULL || (hp = mf_get(mfp, 0, 1)) == NULL)
+ if (mfp == NULL || (hp = mf_get(mfp, 0, 1)) == NULL) {
return;
+ }
b0p = hp->bh_data;
if (ml_check_b0_id(b0p) == FAIL) {
IEMSG(_("E304: ml_upd_block0(): Didn't get block 0??"));
@@ -659,9 +672,9 @@ static void ml_upd_block0(buf_T *buf, upd_block0_T what)
*/
static void set_b0_fname(ZERO_BL *b0p, buf_T *buf)
{
- if (buf->b_ffname == NULL)
+ if (buf->b_ffname == NULL) {
b0p->b0_fname[0] = NUL;
- else {
+ } else {
char uname[B0_UNAME_SIZE];
/*
@@ -672,9 +685,9 @@ static void set_b0_fname(ZERO_BL *b0p, buf_T *buf)
* Then insert the user name to get "~user/".
*/
home_replace(NULL, buf->b_ffname, b0p->b0_fname,
- B0_FNAME_SIZE_CRYPT, TRUE);
+ B0_FNAME_SIZE_CRYPT, TRUE);
if (b0p->b0_fname[0] == '~') {
- /* If there is no user name or it is too long, don't use "~/" */
+ // If there is no user name or it is too long, don't use "~/"
int retval = os_get_user_name(uname, B0_UNAME_SIZE);
size_t ulen = STRLEN(uname);
size_t flen = STRLEN(b0p->b0_fname);
@@ -701,7 +714,7 @@ static void set_b0_fname(ZERO_BL *b0p, buf_T *buf)
}
}
- /* Also add the 'fileencoding' if there is room. */
+ // Also add the 'fileencoding' if there is room.
add_b0_fenc(b0p, curbuf);
}
@@ -713,10 +726,11 @@ static void set_b0_fname(ZERO_BL *b0p, buf_T *buf)
*/
static void set_b0_dir_flag(ZERO_BL *b0p, buf_T *buf)
{
- if (same_directory(buf->b_ml.ml_mfp->mf_fname, buf->b_ffname))
+ if (same_directory(buf->b_ml.ml_mfp->mf_fname, buf->b_ffname)) {
b0p->b0_flags |= B0_SAME_DIR;
- else
+ } else {
b0p->b0_flags &= ~B0_SAME_DIR;
+ }
}
/*
@@ -728,11 +742,11 @@ static void add_b0_fenc(ZERO_BL *b0p, buf_T *buf)
int size = B0_FNAME_SIZE_NOCRYPT;
n = (int)STRLEN(buf->b_p_fenc);
- if ((int)STRLEN(b0p->b0_fname) + n + 1 > size)
+ if ((int)STRLEN(b0p->b0_fname) + n + 1 > size) {
b0p->b0_flags &= ~B0_HAS_FENC;
- else {
+ } else {
memmove((char *)b0p->b0_fname + size - n,
- (char *)buf->b_p_fenc, (size_t)n);
+ (char *)buf->b_p_fenc, (size_t)n);
*(b0p->b0_fname + size - n - 1) = NUL;
b0p->b0_flags |= B0_HAS_FENC;
}
@@ -744,26 +758,26 @@ static void add_b0_fenc(ZERO_BL *b0p, buf_T *buf)
/// swap file.
void ml_recover(bool checkext)
{
- buf_T *buf = NULL;
- memfile_T *mfp = NULL;
- char_u *fname;
- char_u *fname_used = NULL;
- bhdr_T *hp = NULL;
- ZERO_BL *b0p;
+ buf_T *buf = NULL;
+ memfile_T *mfp = NULL;
+ char_u *fname;
+ char_u *fname_used = NULL;
+ bhdr_T *hp = NULL;
+ ZERO_BL *b0p;
int b0_ff;
- char_u *b0_fenc = NULL;
- PTR_BL *pp;
- DATA_BL *dp;
- infoptr_T *ip;
+ char_u *b0_fenc = NULL;
+ PTR_BL *pp;
+ DATA_BL *dp;
+ infoptr_T *ip;
blocknr_T bnum;
int page_count;
int len;
- int directly;
+ bool directly;
linenr_T lnum;
- char_u *p;
+ char_u *p;
int i;
long error;
- int cannot_open;
+ bool cannot_open;
linenr_T line_count;
bool has_error;
int idx;
@@ -771,7 +785,7 @@ void ml_recover(bool checkext)
int txt_start;
off_T size;
int called_from_main;
- int serious_error = TRUE;
+ bool serious_error = true;
long mtime;
int attr;
int orig_file_status = NOTDONE;
@@ -783,45 +797,48 @@ void ml_recover(bool checkext)
// If the file name ends in ".s[a-w][a-z]" we assume this is the swap file.
// Otherwise a search is done to find the swap file(s).
fname = curbuf->b_fname;
- if (fname == NULL) /* When there is no file name */
+ if (fname == NULL) { // When there is no file name
fname = (char_u *)"";
+ }
len = (int)STRLEN(fname);
if (checkext && len >= 4
&& STRNICMP(fname + len - 4, ".s", 2) == 0
&& vim_strchr((char_u *)"abcdefghijklmnopqrstuvw",
TOLOWER_ASC(fname[len - 2])) != NULL
&& ASCII_ISALPHA(fname[len - 1])) {
- directly = TRUE;
- fname_used = vim_strsave(fname); /* make a copy for mf_open() */
+ directly = true;
+ fname_used = vim_strsave(fname); // make a copy for mf_open()
} else {
- directly = FALSE;
+ directly = false;
- /* count the number of matching swap files */
+ // count the number of matching swap files
len = recover_names(fname, FALSE, 0, NULL);
- if (len == 0) { /* no swap files found */
+ if (len == 0) { // no swap files found
EMSG2(_("E305: No swap file found for %s"), fname);
goto theend;
}
- if (len == 1) /* one swap file found, use it */
+ if (len == 1) { // one swap file found, use it
i = 1;
- else { /* several swap files found, choose */
- /* list the names of the swap files */
+ } else { // several swap files found, choose
+ // list the names of the swap files
(void)recover_names(fname, TRUE, 0, NULL);
msg_putchar('\n');
MSG_PUTS(_("Enter number of swap file to use (0 to quit): "));
i = get_number(FALSE, NULL);
- if (i < 1 || i > len)
+ if (i < 1 || i > len) {
goto theend;
+ }
}
- /* get the swap file name that will be used */
+ // get the swap file name that will be used
(void)recover_names(fname, FALSE, i, &fname_used);
}
- if (fname_used == NULL)
+ if (fname_used == NULL) {
goto theend; // user chose invalid number.
-
- /* When called from main() still need to initialize storage structure */
- if (called_from_main && ml_open(curbuf) == FAIL)
+ }
+ // When called from main() still need to initialize storage structure
+ if (called_from_main && ml_open(curbuf) == FAIL) {
getout(1);
+ }
/*
* Allocate a buffer structure for the swap file that is used for recovery.
@@ -868,9 +885,8 @@ void ml_recover(bool checkext)
msg_start();
MSG_PUTS_ATTR(_("Unable to read block 0 from "), attr | MSG_HIST);
msg_outtrans_attr(mfp->mf_fname, attr | MSG_HIST);
- MSG_PUTS_ATTR(_(
- "\nMaybe no changes were made or Vim did not update the swap file."),
- attr | MSG_HIST);
+ MSG_PUTS_ATTR(_("\nMaybe no changes were made or Vim did not update the swap file."),
+ attr | MSG_HIST);
msg_end();
goto theend;
}
@@ -879,7 +895,7 @@ void ml_recover(bool checkext)
msg_start();
msg_outtrans_attr(mfp->mf_fname, MSG_HIST);
MSG_PUTS_ATTR(_(" cannot be used with this version of Vim.\n"),
- MSG_HIST);
+ MSG_HIST);
MSG_PUTS_ATTR(_("Use Vim version 3.0.\n"), MSG_HIST);
msg_end();
goto theend;
@@ -892,9 +908,9 @@ void ml_recover(bool checkext)
msg_start();
msg_outtrans_attr(mfp->mf_fname, attr | MSG_HIST);
MSG_PUTS_ATTR(_(" cannot be used on this computer.\n"),
- attr | MSG_HIST);
+ attr | MSG_HIST);
MSG_PUTS_ATTR(_("The file was created on "), attr | MSG_HIST);
- /* avoid going past the end of a corrupted hostname */
+ // avoid going past the end of a corrupted hostname
b0p->b0_fname[0] = NUL;
MSG_PUTS_ATTR(b0p->b0_hname, attr | MSG_HIST);
MSG_PUTS_ATTR(_(",\nor the file has been damaged."), attr | MSG_HIST);
@@ -913,9 +929,8 @@ void ml_recover(bool checkext)
if (mfp->mf_page_size < previous_page_size) {
msg_start();
msg_outtrans_attr(mfp->mf_fname, attr | MSG_HIST);
- MSG_PUTS_ATTR(_(
- " has been damaged (page size is smaller than minimum value).\n"),
- attr | MSG_HIST);
+ MSG_PUTS_ATTR(_(" has been damaged (page size is smaller than minimum value).\n"),
+ attr | MSG_HIST);
msg_end();
goto theend;
}
@@ -926,7 +941,7 @@ void ml_recover(bool checkext)
}
mfp->mf_infile_count = mfp->mf_blocknr_max;
- /* need to reallocate the memory used to store the data */
+ // need to reallocate the memory used to store the data
p = xmalloc(mfp->mf_page_size);
memmove(p, hp->bh_data, previous_page_size);
xfree(hp->bh_data);
@@ -947,10 +962,11 @@ void ml_recover(bool checkext)
home_replace(NULL, mfp->mf_fname, NameBuff, MAXPATHL, TRUE);
smsg(_("Using swap file \"%s\""), NameBuff);
- if (buf_spname(curbuf) != NULL)
+ if (buf_spname(curbuf) != NULL) {
STRLCPY(NameBuff, buf_spname(curbuf), MAXPATHL);
- else
+ } else {
home_replace(NULL, curbuf->b_ffname, NameBuff, MAXPATHL, TRUE);
+ }
smsg(_("Original file \"%s\""), NameBuff);
msg_putchar('\n');
@@ -964,13 +980,13 @@ void ml_recover(bool checkext)
&& os_fileinfo((char *)curbuf->b_ffname, &org_file_info)
&& ((os_fileinfo((char *)mfp->mf_fname, &swp_file_info)
&& org_file_info.stat.st_mtim.tv_sec
- > swp_file_info.stat.st_mtim.tv_sec)
+ > swp_file_info.stat.st_mtim.tv_sec)
|| org_file_info.stat.st_mtim.tv_sec != mtime)) {
EMSG(_("E308: Warning: Original file may have been changed"));
}
ui_flush();
- /* Get the 'fileformat' and 'fileencoding' from block zero. */
+ // Get the 'fileformat' and 'fileencoding' from block zero.
b0_ff = (b0p->b0_flags & B0_FF_MASK);
if (b0p->b0_flags & B0_HAS_FENC) {
int fnsize = B0_FNAME_SIZE_NOCRYPT;
@@ -980,7 +996,7 @@ void ml_recover(bool checkext)
b0_fenc = vim_strnsave(p, b0p->b0_fname + fnsize - p);
}
- mf_put(mfp, hp, false, false); /* release block 0 */
+ mf_put(mfp, hp, false, false); // release block 0
hp = NULL;
/*
@@ -995,39 +1011,42 @@ void ml_recover(bool checkext)
* Try reading the original file to obtain the values of 'fileformat',
* 'fileencoding', etc. Ignore errors. The text itself is not used.
*/
- if (curbuf->b_ffname != NULL)
+ if (curbuf->b_ffname != NULL) {
orig_file_status = readfile(curbuf->b_ffname, NULL, (linenr_T)0,
- (linenr_T)0, (linenr_T)MAXLNUM, NULL, READ_NEW);
+ (linenr_T)0, (linenr_T)MAXLNUM, NULL, READ_NEW);
+ }
- /* Use the 'fileformat' and 'fileencoding' as stored in the swap file. */
- if (b0_ff != 0)
+ // Use the 'fileformat' and 'fileencoding' as stored in the swap file.
+ if (b0_ff != 0) {
set_fileformat(b0_ff - 1, OPT_LOCAL);
+ }
if (b0_fenc != NULL) {
set_option_value("fenc", 0L, (char *)b0_fenc, OPT_LOCAL);
xfree(b0_fenc);
}
unchanged(curbuf, true, true);
- bnum = 1; /* start with block 1 */
- page_count = 1; /* which is 1 page */
- lnum = 0; /* append after line 0 in curbuf */
+ bnum = 1; // start with block 1
+ page_count = 1; // which is 1 page
+ lnum = 0; // append after line 0 in curbuf
line_count = 0;
- idx = 0; /* start with first index in block 1 */
+ idx = 0; // start with first index in block 1
error = 0;
buf->b_ml.ml_stack_top = 0;
buf->b_ml.ml_stack = NULL;
- buf->b_ml.ml_stack_size = 0; /* no stack yet */
+ buf->b_ml.ml_stack_size = 0; // no stack yet
- if (curbuf->b_ffname == NULL)
- cannot_open = TRUE;
- else
- cannot_open = FALSE;
+ if (curbuf->b_ffname == NULL) {
+ cannot_open = true;
+ } else {
+ cannot_open = false;
+ }
- serious_error = FALSE;
+ serious_error = false;
for (; !got_int; line_breakcheck()) {
- if (hp != NULL)
- mf_put(mfp, hp, false, false); /* release previous block */
-
+ if (hp != NULL) {
+ mf_put(mfp, hp, false, false); // release previous block
+ }
/*
* get block
*/
@@ -1041,11 +1060,12 @@ void ml_recover(bool checkext)
(colnr_T)0, true);
} else { // there is a block
pp = hp->bh_data;
- if (pp->pb_id == PTR_ID) { /* it is a pointer block */
- /* check line count when using pointer block first time */
+ if (pp->pb_id == PTR_ID) { // it is a pointer block
+ // check line count when using pointer block first time
if (idx == 0 && line_count != 0) {
- for (i = 0; i < (int)pp->pb_count; ++i)
+ for (i = 0; i < (int)pp->pb_count; ++i) {
line_count -= pp->pb_pointer[i].pe_line_count;
+ }
if (line_count != 0) {
++error;
ml_append(lnum++, (char_u *)_("???LINE COUNT WRONG"),
@@ -1079,7 +1099,7 @@ void ml_recover(bool checkext)
ml_append(lnum++, (char_u *)_("???LINES MISSING"),
(colnr_T)0, true);
}
- ++idx; /* get same block again for next index */
+ ++idx; // get same block again for next index
continue;
}
@@ -1097,12 +1117,12 @@ void ml_recover(bool checkext)
idx = 0;
continue;
}
- } else { /* not a pointer block */
+ } else { // not a pointer block
dp = hp->bh_data;
- if (dp->db_id != DATA_ID) { /* block id wrong */
+ if (dp->db_id != DATA_ID) { // block id wrong
if (bnum == 1) {
EMSG2(_("E310: Block 1 ID wrong (%s not a .swp file?)"),
- mfp->mf_fname);
+ mfp->mf_fname);
goto theend;
}
++error;
@@ -1115,17 +1135,16 @@ void ml_recover(bool checkext)
// check length of block
// if wrong, use length in pointer block
if (page_count * mfp->mf_page_size != dp->db_txt_end) {
- ml_append(
- lnum++,
- (char_u *)_("??? from here until ???END lines"
- " may be messed up"),
- (colnr_T)0, true);
+ ml_append(lnum++,
+ (char_u *)_("??? from here until ???END lines"
+ " may be messed up"),
+ (colnr_T)0, true);
error++;
has_error = true;
dp->db_txt_end = page_count * mfp->mf_page_size;
}
- /* make sure there is a NUL at the end of the block */
+ // make sure there is a NUL at the end of the block
*((char_u *)dp + dp->db_txt_end - 1) = NUL;
/*
@@ -1133,11 +1152,10 @@ void ml_recover(bool checkext)
* if wrong, use count in data block
*/
if (line_count != dp->db_line_count) {
- ml_append(
- lnum++,
- (char_u *)_("??? from here until ???END lines"
- " may have been inserted/deleted"),
- (colnr_T)0, true);
+ ml_append(lnum++,
+ (char_u *)_("??? from here until ???END lines"
+ " may have been inserted/deleted"),
+ (colnr_T)0, true);
error++;
has_error = true;
}
@@ -1148,8 +1166,9 @@ void ml_recover(bool checkext)
|| txt_start >= (int)dp->db_txt_end) {
p = (char_u *)"???";
++error;
- } else
+ } else {
p = (char_u *)dp + txt_start;
+ }
ml_append(lnum++, p, (colnr_T)0, true);
}
if (has_error) {
@@ -1159,15 +1178,16 @@ void ml_recover(bool checkext)
}
}
- if (buf->b_ml.ml_stack_top == 0) /* finished */
+ if (buf->b_ml.ml_stack_top == 0) { // finished
break;
+ }
/*
* go one block up in the tree
*/
ip = &(buf->b_ml.ml_stack[--(buf->b_ml.ml_stack_top)]);
bnum = ip->ip_bnum;
- idx = ip->ip_index + 1; /* go to next index */
+ idx = ip->ip_index + 1; // go to next index
page_count = 1;
}
@@ -1187,7 +1207,7 @@ void ml_recover(bool checkext)
}
} else {
for (idx = 1; idx <= lnum; ++idx) {
- /* Need to copy one line, fetching the other one may flush it. */
+ // Need to copy one line, fetching the other one may flush it.
p = vim_strsave(ml_get(idx));
i = STRCMP(p, ml_get(idx + lnum));
xfree(p);
@@ -1204,30 +1224,30 @@ void ml_recover(bool checkext)
* empty buffer. These will now be after the last line in the buffer.
*/
while (curbuf->b_ml.ml_line_count > lnum
- && !(curbuf->b_ml.ml_flags & ML_EMPTY))
+ && !(curbuf->b_ml.ml_flags & ML_EMPTY)) {
ml_delete(curbuf->b_ml.ml_line_count, false);
+ }
curbuf->b_flags |= BF_RECOVERED;
check_cursor();
recoverymode = FALSE;
- if (got_int)
+ if (got_int) {
EMSG(_("E311: Recovery Interrupted"));
- else if (error) {
+ } else if (error) {
++no_wait_return;
MSG(">>>>>>>>>>>>>");
- EMSG(_(
- "E312: Errors detected while recovering; look for lines starting with ???"));
+ EMSG(_( "E312: Errors detected while recovering; look for lines starting with ???"));
--no_wait_return;
MSG(_("See \":help E312\" for more information."));
MSG(">>>>>>>>>>>>>");
} else {
if (curbuf->b_changed) {
MSG(_("Recovery completed. You should check if everything is OK."));
- MSG_PUTS(_(
- "\n(You might want to write out this file under another name\n"));
+ MSG_PUTS(_("\n(You might want to write out this file under another name\n"));
MSG_PUTS(_("and run diff with the original file to check for changes)"));
- } else
+ } else {
MSG(_("Recovery completed. Buffer contents equals file contents."));
+ }
MSG_PUTS(_("\nYou may want to delete the .swp file now.\n\n"));
cmdline_row = msg_row;
}
@@ -1237,51 +1257,49 @@ theend:
xfree(fname_used);
recoverymode = FALSE;
if (mfp != NULL) {
- if (hp != NULL)
+ if (hp != NULL) {
mf_put(mfp, hp, false, false);
- mf_close(mfp, false); /* will also xfree(mfp->mf_fname) */
+ }
+ mf_close(mfp, false); // will also xfree(mfp->mf_fname)
}
if (buf != NULL) { //may be NULL if swap file not found.
xfree(buf->b_ml.ml_stack);
xfree(buf);
}
- if (serious_error && called_from_main)
+ if (serious_error && called_from_main) {
ml_close(curbuf, TRUE);
- else {
+ } else {
apply_autocmds(EVENT_BUFREADPOST, NULL, curbuf->b_fname, FALSE, curbuf);
apply_autocmds(EVENT_BUFWINENTER, NULL, curbuf->b_fname, FALSE, curbuf);
}
return;
}
-/*
- * Find the names of swap files in current directory and the directory given
- * with the 'directory' option.
- *
- * Used to:
- * - list the swap files for "vim -r"
- * - count the number of swap files when recovering
- * - list the swap files when recovering
- * - find the name of the n'th swap file when recovering
- */
-int
-recover_names (
- char_u *fname, /* base for swap file name */
- int list, /* when TRUE, list the swap file names */
- int nr, /* when non-zero, return nr'th swap file name */
- char_u **fname_out /* result when "nr" > 0 */
-)
+/// Find the names of swap files in current directory and the directory given
+/// with the 'directory' option.
+///
+/// Used to:
+/// - list the swap files for "vim -r"
+/// - count the number of swap files when recovering
+/// - list the swap files when recovering
+/// - find the name of the n'th swap file when recovering
+///
+/// @param fname base for swap file name
+/// @param list when TRUE, list the swap file names
+/// @param nr when non-zero, return nr'th swap file name
+/// @param fname_out result when "nr" > 0
+int recover_names(char_u *fname, int list, int nr, char_u **fname_out)
{
int num_names;
- char_u *(names[6]);
- char_u *tail;
- char_u *p;
+ char_u *(names[6]);
+ char_u *tail;
+ char_u *p;
int num_files;
int file_count = 0;
- char_u **files;
- char_u *dirp;
- char_u *dir_name;
- char_u *fname_res = NULL;
+ char_u **files;
+ char_u *dirp;
+ char_u *dir_name;
+ char_u *fname_res = NULL;
#ifdef HAVE_READLINK
char_u fname_buf[MAXPATHL];
#endif
@@ -1290,15 +1308,15 @@ recover_names (
#ifdef HAVE_READLINK
/* Expand symlink in the file name, because the swap file is created
* with the actual file instead of with the symlink. */
- if (resolve_symlink(fname, fname_buf) == OK)
+ if (resolve_symlink(fname, fname_buf) == OK) {
fname_res = fname_buf;
- else
+ } else
#endif
fname_res = fname;
}
if (list) {
- /* use msg() to start the scrolling properly */
+ // use msg() to start the scrolling properly
msg((char_u *)_("Swap files found:"));
msg_putchar('\n');
}
@@ -1313,7 +1331,7 @@ recover_names (
// Advance dirp to next directory name.
(void)copy_option_part(&dirp, dir_name, 31000, ",");
- if (dir_name[0] == '.' && dir_name[1] == NUL) { /* check current dir */
+ if (dir_name[0] == '.' && dir_name[1] == NUL) { // check current dir
if (fname == NULL) {
names[0] = vim_strsave((char_u *)"*.sw?");
/* For Unix names starting with a dot are special. MS-Windows
@@ -1321,9 +1339,10 @@ recover_names (
names[1] = vim_strsave((char_u *)".*.sw?");
names[2] = vim_strsave((char_u *)".sw?");
num_names = 3;
- } else
+ } else {
num_names = recov_file_names(names, fname_res, TRUE);
- } else { /* check directory dir_name */
+ }
+ } else { // check directory dir_name
if (fname == NULL) {
names[0] = (char_u *)concat_fnames((char *)dir_name, "*.sw?", TRUE);
/* For Unix names starting with a dot are special. MS-Windows
@@ -1349,11 +1368,12 @@ recover_names (
}
}
- if (num_names == 0)
+ if (num_names == 0) {
num_files = 0;
- else if (expand_wildcards(num_names, names, &num_files, &files,
- EW_KEEPALL|EW_FILE|EW_SILENT) == FAIL)
+ } else if (expand_wildcards(num_names, names, &num_files, &files,
+ EW_KEEPALL|EW_FILE|EW_SILENT) == FAIL) {
num_files = 0;
+ }
/*
* When no swap file found, wildcard expansion might have failed (e.g.
@@ -1386,27 +1406,29 @@ recover_names (
// down. When the array becomes empty free it here, since
// FreeWild() won't be called below.
xfree(files[i]);
- if (--num_files == 0)
+ if (--num_files == 0) {
xfree(files);
- else
- for (; i < num_files; ++i)
+ } else {
+ for (; i < num_files; ++i) {
files[i] = files[i + 1];
+ }
+ }
}
}
}
if (nr > 0) {
file_count += num_files;
if (nr <= file_count) {
- *fname_out = vim_strsave(
- files[nr - 1 + num_files - file_count]);
- dirp = (char_u *)""; /* stop searching */
+ *fname_out = vim_strsave(files[nr - 1 + num_files - file_count]);
+ dirp = (char_u *)""; // stop searching
}
} else if (list) {
if (dir_name[0] == '.' && dir_name[1] == NUL) {
- if (fname == NULL)
+ if (fname == NULL) {
MSG_PUTS(_(" In current directory:\n"));
- else
+ } else {
MSG_PUTS(_(" Using specified name:\n"));
+ }
} else {
MSG_PUTS(_(" In directory "));
msg_home_replace(dir_name);
@@ -1415,23 +1437,27 @@ recover_names (
if (num_files) {
for (int i = 0; i < num_files; ++i) {
- /* print the swap file name */
+ // print the swap file name
msg_outnum((long)++file_count);
msg_puts(". ");
msg_puts((const char *)path_tail(files[i]));
msg_putchar('\n');
(void)swapfile_info(files[i]);
}
- } else
+ } else {
MSG_PUTS(_(" -- none --\n"));
+ }
ui_flush();
- } else
+ } else {
file_count += num_files;
+ }
- for (int i = 0; i < num_names; ++i)
+ for (int i = 0; i < num_names; ++i) {
xfree(names[i]);
- if (num_files > 0)
+ }
+ if (num_files > 0) {
FreeWild(num_files, files);
+ }
}
xfree(dir_name);
return file_count;
@@ -1441,7 +1467,7 @@ recover_names (
* Append the full path to name with path separators made into percent
* signs, to dir. An unnamed buffer is handled as "" (<currentdir>/"")
*/
-char *make_percent_swname(const char *dir, char *name)
+char *make_percent_swname(const char *dir, const char *name)
FUNC_ATTR_NONNULL_ARG(1)
{
char *d = NULL;
@@ -1542,10 +1568,11 @@ static time_t swapfile_info(char_u *fname)
MSG_PUTS(_(" [garbled strings (not nul terminated)]"));
} else {
MSG_PUTS(_(" file name: "));
- if (b0.b0_fname[0] == NUL)
+ if (b0.b0_fname[0] == NUL) {
MSG_PUTS(_("[No Name]"));
- else
+ } else {
msg_outtrans(b0.b0_fname);
+ }
MSG_PUTS(_("\n modified: "));
MSG_PUTS(b0.b0_dirty ? _("YES") : _("no"));
@@ -1556,10 +1583,11 @@ static time_t swapfile_info(char_u *fname)
}
if (*(b0.b0_hname) != NUL) {
- if (*(b0.b0_uname) != NUL)
+ if (*(b0.b0_uname) != NUL) {
MSG_PUTS(_(" host name: "));
- else
+ } else {
MSG_PUTS(_("\n host name: "));
+ }
msg_outtrans(b0.b0_hname);
}
@@ -1576,11 +1604,13 @@ static time_t swapfile_info(char_u *fname)
MSG_PUTS(_("\n [not usable on this computer]"));
}
}
- } else
+ } else {
MSG_PUTS(_(" [cannot be read]"));
+ }
close(fd);
- } else
+ } else {
MSG_PUTS(_(" [cannot be opened]"));
+ }
msg_putchar('\n');
return x;
@@ -1648,18 +1678,20 @@ static int recov_file_names(char_u **names, char_u *path, int prepend_dot)
// Form the normal swap file name pattern by appending ".sw?".
names[num_names] = (char_u *)concat_fnames((char *)path, ".sw?", FALSE);
- if (num_names >= 1) { /* check if we have the same name twice */
+ if (num_names >= 1) { // check if we have the same name twice
char_u *p = names[num_names - 1];
int i = (int)STRLEN(names[num_names - 1]) - (int)STRLEN(names[num_names]);
- if (i > 0)
- p += i; /* file name has been expanded to full path */
-
- if (STRCMP(p, names[num_names]) != 0)
+ if (i > 0) {
+ p += i; // file name has been expanded to full path
+ }
+ if (STRCMP(p, names[num_names]) != 0) {
++num_names;
- else
+ } else {
xfree(names[num_names]);
- } else
+ }
+ } else {
++num_names;
+ }
return num_names;
}
@@ -1674,11 +1706,11 @@ static int recov_file_names(char_u **names, char_u *path, int prepend_dot)
void ml_sync_all(int check_file, int check_char, bool do_fsync)
{
FOR_ALL_BUFFERS(buf) {
- if (buf->b_ml.ml_mfp == NULL || buf->b_ml.ml_mfp->mf_fname == NULL)
- continue; /* no file */
-
- ml_flush_line(buf); /* flush buffered line */
- /* flush locked block */
+ if (buf->b_ml.ml_mfp == NULL || buf->b_ml.ml_mfp->mf_fname == NULL) {
+ continue; // no file
+ }
+ ml_flush_line(buf); // flush buffered line
+ // flush locked block
(void)ml_find_line(buf, (linenr_T)0, ML_FLUSH);
if (bufIsChanged(buf) && check_file && mf_need_trans(buf->b_ml.ml_mfp)
&& buf->b_ffname != NULL) {
@@ -1717,15 +1749,16 @@ void ml_sync_all(int check_file, int check_char, bool do_fsync)
*/
void ml_preserve(buf_T *buf, int message, bool do_fsync)
{
- bhdr_T *hp;
+ bhdr_T *hp;
linenr_T lnum;
- memfile_T *mfp = buf->b_ml.ml_mfp;
+ memfile_T *mfp = buf->b_ml.ml_mfp;
int status;
int got_int_save = got_int;
if (mfp == NULL || mfp->mf_fname == NULL) {
- if (message)
+ if (message) {
EMSG(_("E313: Cannot preserve, there is no swap file"));
+ }
return;
}
@@ -1737,7 +1770,7 @@ void ml_preserve(buf_T *buf, int message, bool do_fsync)
(void)ml_find_line(buf, (linenr_T)0, ML_FLUSH); // flush locked block
status = mf_sync(mfp, MFS_ALL | (do_fsync ? MFS_FLUSH : 0));
- /* stack is invalid after mf_sync(.., MFS_ALL) */
+ // stack is invalid after mf_sync(.., MFS_ALL)
buf->b_ml.ml_stack_top = 0;
/*
@@ -1774,10 +1807,11 @@ theend:
got_int |= got_int_save;
if (message) {
- if (status == OK)
+ if (status == OK) {
MSG(_("File preserved"));
- else
+ } else {
EMSG(_("E314: Preserve failed"));
+ }
}
}
@@ -1785,7 +1819,7 @@ theend:
* NOTE: The pointer returned by the ml_get_*() functions only remains valid
* until the next call!
* line1 = ml_get(1);
- * line2 = ml_get(2); // line1 is now invalid!
+ * line2 = ml_get(2); // line1 is now invalid!
* Make a copy of the line if necessary.
*/
/*
@@ -1796,7 +1830,7 @@ theend:
*/
char_u *ml_get(linenr_T lnum)
{
- return ml_get_buf(curbuf, lnum, FALSE);
+ return ml_get_buf(curbuf, lnum, false);
}
/*
@@ -1808,26 +1842,18 @@ char_u *ml_get_pos(const pos_T *pos)
return ml_get_buf(curbuf, pos->lnum, false) + pos->col;
}
-/*
- * Return a pointer to a line in a specific buffer
- *
- * "will_change": if TRUE mark the buffer dirty (chars in the line will be
- * changed)
- */
-char_u *
-ml_get_buf (
- buf_T *buf,
- linenr_T lnum,
- bool will_change // line will be changed
-)
+/// Return a pointer to a line in a specific buffer
+///
+/// @param will_change true mark the buffer dirty (chars in the line will be changed)
+char_u *ml_get_buf(buf_T *buf, linenr_T lnum, bool will_change)
FUNC_ATTR_NONNULL_ALL
{
- bhdr_T *hp;
- DATA_BL *dp;
- char_u *ptr;
+ bhdr_T *hp;
+ DATA_BL *dp;
+ char_u *ptr;
static int recursive = 0;
- if (lnum > buf->b_ml.ml_line_count) { /* invalid line number */
+ if (lnum > buf->b_ml.ml_line_count) { // invalid line number
if (recursive == 0) {
// Avoid giving this message for a recursive call, may happen when
// the GUI redraws part of the text.
@@ -1839,11 +1865,13 @@ errorret:
STRCPY(IObuff, "???");
return IObuff;
}
- if (lnum <= 0) /* pretend line 0 is line 1 */
+ if (lnum <= 0) { // pretend line 0 is line 1
lnum = 1;
+ }
- if (buf->b_ml.ml_mfp == NULL) /* there are no lines */
+ if (buf->b_ml.ml_mfp == NULL) { // there are no lines
return (char_u *)"";
+ }
/*
* See if it is the same line as requested last time.
@@ -1898,88 +1926,89 @@ int ml_line_alloced(void)
return curbuf->b_ml.ml_flags & ML_LINE_DIRTY;
}
-/*
- * Append a line after lnum (may be 0 to insert a line in front of the file).
- * "line" does not need to be allocated, but can't be another line in a
- * buffer, unlocking may make it invalid.
- *
- * newfile: TRUE when starting to edit a new file, meaning that pe_old_lnum
- * will be set for recovery
- * Check: The caller of this function should probably also call
- * appended_lines().
- *
- * return FAIL for failure, OK otherwise
- */
-int ml_append(
- linenr_T lnum, // append after this line (can be 0)
- char_u *line, // text of the new line
- colnr_T len, // length of new line, including NUL, or 0
- bool newfile // flag, see above
-)
+/// Append a line after lnum (may be 0 to insert a line in front of the file).
+/// "line" does not need to be allocated, but can't be another line in a
+/// buffer, unlocking may make it invalid.
+///
+/// newfile: TRUE when starting to edit a new file, meaning that pe_old_lnum
+/// will be set for recovery
+/// Check: The caller of this function should probably also call
+/// appended_lines().
+///
+/// @param lnum append after this line (can be 0)
+/// @param line text of the new line
+/// @param len length of new line, including NUL, or 0
+/// @param newfile flag, see above
+///
+/// @return FAIL for failure, OK otherwise
+int ml_append(linenr_T lnum, char_u *line, colnr_T len, bool newfile)
{
- /* When starting up, we might still need to create the memfile */
- if (curbuf->b_ml.ml_mfp == NULL && open_buffer(FALSE, NULL, 0) == FAIL)
+ // When starting up, we might still need to create the memfile
+ if (curbuf->b_ml.ml_mfp == NULL && open_buffer(FALSE, NULL, 0) == FAIL) {
return FAIL;
+ }
- if (curbuf->b_ml.ml_line_lnum != 0)
+ if (curbuf->b_ml.ml_line_lnum != 0) {
ml_flush_line(curbuf);
+ }
return ml_append_int(curbuf, lnum, line, len, newfile, FALSE);
}
-/*
- * Like ml_append() but for an arbitrary buffer. The buffer must already have
- * a memline.
- */
-int ml_append_buf(
- buf_T *buf,
- linenr_T lnum, // append after this line (can be 0)
- char_u *line, // text of the new line
- colnr_T len, // length of new line, including NUL, or 0
- bool newfile // flag, see above
-)
+/// Like ml_append() but for an arbitrary buffer. The buffer must already have
+/// a memline.
+///
+/// @param lnum append after this line (can be 0)
+/// @param line text of the new line
+/// @param len length of new line, including NUL, or 0
+/// @param newfile flag, see above
+int ml_append_buf(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, bool newfile)
FUNC_ATTR_NONNULL_ARG(1)
{
- if (buf->b_ml.ml_mfp == NULL)
+ if (buf->b_ml.ml_mfp == NULL) {
return FAIL;
+ }
- if (buf->b_ml.ml_line_lnum != 0)
+ if (buf->b_ml.ml_line_lnum != 0) {
ml_flush_line(buf);
+ }
return ml_append_int(buf, lnum, line, len, newfile, FALSE);
}
-static int ml_append_int(
- buf_T *buf,
- linenr_T lnum, // append after this line (can be 0)
- char_u *line, // text of the new line
- colnr_T len, // length of line, including NUL, or 0
- bool newfile, // flag, see above
- int mark // mark the new line
-)
+/// @param lnum append after this line (can be 0)
+/// @param line text of the new line
+/// @param len length of line, including NUL, or 0
+/// @param newfile flag, see above
+/// @param mark mark the new line
+static int ml_append_int(buf_T *buf, linenr_T lnum, char_u *line, colnr_T len, bool newfile,
+ int mark)
{
int i;
- int line_count; /* number of indexes in current block */
+ int line_count; // number of indexes in current block
int offset;
int from, to;
- int space_needed; /* space needed for new line */
+ int space_needed; // space needed for new line
int page_size;
int page_count;
- int db_idx; /* index for lnum in data block */
- bhdr_T *hp;
- memfile_T *mfp;
- DATA_BL *dp;
- PTR_BL *pp;
- infoptr_T *ip;
-
- /* lnum out of range */
- if (lnum > buf->b_ml.ml_line_count || buf->b_ml.ml_mfp == NULL)
+ int db_idx; // index for lnum in data block
+ bhdr_T *hp;
+ memfile_T *mfp;
+ DATA_BL *dp;
+ PTR_BL *pp;
+ infoptr_T *ip;
+
+ // lnum out of range
+ if (lnum > buf->b_ml.ml_line_count || buf->b_ml.ml_mfp == NULL) {
return FAIL;
+ }
- if (lowest_marked && lowest_marked > lnum)
+ if (lowest_marked && lowest_marked > lnum) {
lowest_marked = lnum + 1;
+ }
- if (len == 0)
- len = (colnr_T)STRLEN(line) + 1; /* space needed for the text */
- space_needed = len + INDEX_SIZE; /* space needed for text + index */
+ if (len == 0) {
+ len = (colnr_T)STRLEN(line) + 1; // space needed for the text
+ }
+ space_needed = len + INDEX_SIZE; // space needed for text + index
mfp = buf->b_ml.ml_mfp;
page_size = mfp->mf_page_size;
@@ -1990,16 +2019,18 @@ static int ml_append_int(
* This also releases any locked block.
*/
if ((hp = ml_find_line(buf, lnum == 0 ? (linenr_T)1 : lnum,
- ML_INSERT)) == NULL)
+ ML_INSERT)) == NULL) {
return FAIL;
+ }
buf->b_ml.ml_flags &= ~ML_EMPTY;
- if (lnum == 0) /* got line one instead, correct db_idx */
- db_idx = -1; /* careful, it is negative! */
- else
+ if (lnum == 0) { // got line one instead, correct db_idx
+ db_idx = -1; // careful, it is negative!
+ } else {
db_idx = lnum - buf->b_ml.ml_locked_low;
- /* get line count before the insertion */
+ }
+ // get line count before the insertion
line_count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low;
dp = hp->bh_data;
@@ -2020,11 +2051,12 @@ static int ml_append_int(
*/
--(buf->b_ml.ml_locked_lineadd);
--(buf->b_ml.ml_locked_high);
- if ((hp = ml_find_line(buf, lnum + 1, ML_INSERT)) == NULL)
+ if ((hp = ml_find_line(buf, lnum + 1, ML_INSERT)) == NULL) {
return FAIL;
+ }
- db_idx = -1; /* careful, it is negative! */
- /* get line count before the insertion */
+ db_idx = -1; // careful, it is negative!
+ // get line count before the insertion
line_count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low;
CHECK(buf->b_ml.ml_locked_low != lnum + 1, "locked_low != lnum + 1");
@@ -2033,7 +2065,7 @@ static int ml_append_int(
++buf->b_ml.ml_line_count;
- if ((int)dp->db_free >= space_needed) { /* enough room in data block */
+ if ((int)dp->db_free >= space_needed) { // enough room in data block
/*
* Insert new line in existing data block, or in data block allocated above.
*/
@@ -2045,38 +2077,43 @@ static int ml_append_int(
* move the text of the lines that follow to the front
* adjust the indexes of the lines that follow
*/
- if (line_count > db_idx + 1) { /* if there are following lines */
+ if (line_count > db_idx + 1) { // if there are following lines
/*
* Offset is the start of the previous line.
* This will become the character just after the new line.
*/
- if (db_idx < 0)
+ if (db_idx < 0) {
offset = dp->db_txt_end;
- else
+ } else {
offset = ((dp->db_index[db_idx]) & DB_INDEX_MASK);
+ }
memmove((char *)dp + dp->db_txt_start,
- (char *)dp + dp->db_txt_start + len,
- (size_t)(offset - (dp->db_txt_start + len)));
- for (i = line_count - 1; i > db_idx; --i)
+ (char *)dp + dp->db_txt_start + len,
+ (size_t)(offset - (dp->db_txt_start + len)));
+ for (i = line_count - 1; i > db_idx; --i) {
dp->db_index[i + 1] = dp->db_index[i] - len;
+ }
dp->db_index[db_idx + 1] = offset - len;
- } else /* add line at the end */
+ } else { // add line at the end
dp->db_index[db_idx + 1] = dp->db_txt_start;
+ }
/*
* copy the text into the block
*/
memmove((char *)dp + dp->db_index[db_idx + 1], line, (size_t)len);
- if (mark)
+ if (mark) {
dp->db_index[db_idx + 1] |= DB_MARKED;
+ }
/*
* Mark the block dirty.
*/
buf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
- if (!newfile)
+ if (!newfile) {
buf->b_ml.ml_flags |= ML_LOCKED_POS;
- } else { /* not enough space in data block */
+ }
+ } else { // not enough space in data block
/*
* If there is not enough room we have to create a new data block and copy some
* lines into it.
@@ -2088,20 +2125,20 @@ static int ml_append_int(
*/
long line_count_left, line_count_right;
int page_count_left, page_count_right;
- bhdr_T *hp_left;
- bhdr_T *hp_right;
- bhdr_T *hp_new;
+ bhdr_T *hp_left;
+ bhdr_T *hp_right;
+ bhdr_T *hp_new;
int lines_moved;
- int data_moved = 0; /* init to shut up gcc */
- int total_moved = 0; /* init to shut up gcc */
- DATA_BL *dp_right, *dp_left;
+ int data_moved = 0; // init to shut up gcc
+ int total_moved = 0; // init to shut up gcc
+ DATA_BL *dp_right, *dp_left;
int stack_idx;
- int in_left;
+ bool in_left;
int lineadd;
blocknr_T bnum_left, bnum_right;
linenr_T lnum_left, lnum_right;
int pb_idx;
- PTR_BL *pp_new;
+ PTR_BL *pp_new;
/*
* We are going to allocate a new data block. Depending on the
@@ -2111,24 +2148,24 @@ static int ml_append_int(
* also put in the right block. This method is more efficient when
* inserting a lot of lines at one place.
*/
- if (db_idx < 0) { /* left block is new, right block is existing */
+ if (db_idx < 0) { // left block is new, right block is existing
lines_moved = 0;
- in_left = TRUE;
- /* space_needed does not change */
- } else { /* left block is existing, right block is new */
+ in_left = true;
+ // space_needed does not change
+ } else { // left block is existing, right block is new
lines_moved = line_count - db_idx - 1;
- if (lines_moved == 0)
- in_left = FALSE; /* put new line in right block */
- /* space_needed does not change */
- else {
+ if (lines_moved == 0) {
+ in_left = false; // put new line in right block
+ // space_needed does not change
+ } else {
data_moved = ((dp->db_index[db_idx]) & DB_INDEX_MASK) -
dp->db_txt_start;
total_moved = data_moved + lines_moved * INDEX_SIZE;
if ((int)dp->db_free + total_moved >= space_needed) {
- in_left = TRUE; /* put new line in left block */
+ in_left = true; // put new line in left block
space_needed = total_moved;
} else {
- in_left = FALSE; /* put new line in right block */
+ in_left = false; // put new line in right block
space_needed += total_moved;
}
}
@@ -2136,12 +2173,12 @@ static int ml_append_int(
page_count = ((space_needed + HEADER_SIZE) + page_size - 1) / page_size;
hp_new = ml_new_data(mfp, newfile, page_count);
- if (db_idx < 0) { /* left block is new */
+ if (db_idx < 0) { // left block is new
hp_left = hp_new;
hp_right = hp;
line_count_left = 0;
line_count_right = line_count;
- } else { /* right block is new */
+ } else { // right block is new
hp_left = hp;
hp_right = hp_new;
line_count_left = line_count;
@@ -2161,11 +2198,12 @@ static int ml_append_int(
dp_right->db_txt_start -= len;
dp_right->db_free -= len + INDEX_SIZE;
dp_right->db_index[0] = dp_right->db_txt_start;
- if (mark)
+ if (mark) {
dp_right->db_index[0] |= DB_MARKED;
+ }
memmove((char *)dp_right + dp_right->db_txt_start,
- line, (size_t)len);
+ line, (size_t)len);
++line_count_right;
}
/*
@@ -2177,8 +2215,8 @@ static int ml_append_int(
dp_right->db_txt_start -= data_moved;
dp_right->db_free -= total_moved;
memmove((char *)dp_right + dp_right->db_txt_start,
- (char *)dp_left + dp_left->db_txt_start,
- (size_t)data_moved);
+ (char *)dp_left + dp_left->db_txt_start,
+ (size_t)data_moved);
offset = dp_right->db_txt_start - dp_left->db_txt_start;
dp_left->db_txt_start += data_moved;
dp_left->db_free += total_moved;
@@ -2187,8 +2225,9 @@ static int ml_append_int(
* update indexes in the new block
*/
for (to = line_count_right, from = db_idx + 1;
- from < line_count_left; ++from, ++to)
+ from < line_count_left; ++from, ++to) {
dp_right->db_index[to] = dp->db_index[from] + offset;
+ }
line_count_right += lines_moved;
line_count_left -= lines_moved;
}
@@ -2200,22 +2239,24 @@ static int ml_append_int(
dp_left->db_txt_start -= len;
dp_left->db_free -= len + INDEX_SIZE;
dp_left->db_index[line_count_left] = dp_left->db_txt_start;
- if (mark)
+ if (mark) {
dp_left->db_index[line_count_left] |= DB_MARKED;
+ }
memmove((char *)dp_left + dp_left->db_txt_start,
- line, (size_t)len);
+ line, (size_t)len);
++line_count_left;
}
- if (db_idx < 0) { /* left block is new */
+ if (db_idx < 0) { // left block is new
lnum_left = lnum + 1;
lnum_right = 0;
- } else { /* right block is new */
+ } else { // right block is new
lnum_left = 0;
- if (in_left)
+ if (in_left) {
lnum_right = lnum + 2;
- else
+ } else {
lnum_right = lnum + 1;
+ }
}
dp_left->db_line_count = line_count_left;
dp_right->db_line_count = line_count_right;
@@ -2226,10 +2267,12 @@ static int ml_append_int(
* The old one (hp, in ml_locked) gets a positive blocknumber if
* we changed it and we are not editing a new file.
*/
- if (lines_moved || in_left)
+ if (lines_moved || in_left) {
buf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
- if (!newfile && db_idx >= 0 && in_left)
+ }
+ if (!newfile && db_idx >= 0 && in_left) {
buf->b_ml.ml_flags |= ML_LOCKED_POS;
+ }
mf_put(mfp, hp_new, true, false);
/*
@@ -2248,9 +2291,10 @@ static int ml_append_int(
--stack_idx) {
ip = &(buf->b_ml.ml_stack[stack_idx]);
pb_idx = ip->ip_index;
- if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
+ if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL) {
return FAIL;
- pp = hp->bh_data; /* must be pointer block */
+ }
+ pp = hp->bh_data; // must be pointer block
if (pp->pb_id != PTR_ID) {
IEMSG(_("E317: pointer block id wrong 3"));
mf_put(mfp, hp, false, false);
@@ -2260,12 +2304,13 @@ static int ml_append_int(
* TODO: If the pointer block is full and we are adding at the end
* try to insert in front of the next block
*/
- /* block not full, add one entry */
+ // block not full, add one entry
if (pp->pb_count < pp->pb_count_max) {
- if (pb_idx + 1 < (int)pp->pb_count)
+ if (pb_idx + 1 < (int)pp->pb_count) {
memmove(&pp->pb_pointer[pb_idx + 2],
- &pp->pb_pointer[pb_idx + 1],
- (size_t)(pp->pb_count - pb_idx - 1) * sizeof(PTR_EN));
+ &pp->pb_pointer[pb_idx + 1],
+ (size_t)(pp->pb_count - pb_idx - 1) * sizeof(PTR_EN));
+ }
++pp->pb_count;
pp->pb_pointer[pb_idx].pe_line_count = line_count_left;
pp->pb_pointer[pb_idx].pe_bnum = bnum_left;
@@ -2274,19 +2319,21 @@ static int ml_append_int(
pp->pb_pointer[pb_idx + 1].pe_bnum = bnum_right;
pp->pb_pointer[pb_idx + 1].pe_page_count = page_count_right;
- if (lnum_left != 0)
+ if (lnum_left != 0) {
pp->pb_pointer[pb_idx].pe_old_lnum = lnum_left;
- if (lnum_right != 0)
+ }
+ if (lnum_right != 0) {
pp->pb_pointer[pb_idx + 1].pe_old_lnum = lnum_right;
+ }
mf_put(mfp, hp, true, false);
- buf->b_ml.ml_stack_top = stack_idx + 1; /* truncate stack */
+ buf->b_ml.ml_stack_top = stack_idx + 1; // truncate stack
if (lineadd) {
--(buf->b_ml.ml_stack_top);
- /* fix line count for rest of blocks in the stack */
+ // fix line count for rest of blocks in the stack
ml_lineadd(buf, lineadd);
- /* fix stack itself */
+ // fix stack itself
buf->b_ml.ml_stack[buf->b_ml.ml_stack_top].ip_high +=
lineadd;
++(buf->b_ml.ml_stack_top);
@@ -2296,21 +2343,23 @@ static int ml_append_int(
* We are finished, break the loop here.
*/
break;
- } else { /* pointer block full */
+ } else { // pointer block full
/*
* split the pointer block
* allocate a new pointer block
* move some of the pointer into the new block
* prepare for updating the parent block
*/
- for (;; ) { /* do this twice when splitting block 1 */
+ for (;; ) { // do this twice when splitting block 1
hp_new = ml_new_ptr(mfp);
- if (hp_new == NULL) /* TODO: try to fix tree */
+ if (hp_new == NULL) { // TODO: try to fix tree
return FAIL;
+ }
pp_new = hp_new->bh_data;
- if (hp->bh_bnum != 1)
+ if (hp->bh_bnum != 1) {
break;
+ }
/*
* if block 1 becomes full the tree is given an extra level
@@ -2324,12 +2373,12 @@ static int ml_append_int(
pp->pb_pointer[0].pe_line_count = buf->b_ml.ml_line_count;
pp->pb_pointer[0].pe_old_lnum = 1;
pp->pb_pointer[0].pe_page_count = 1;
- mf_put(mfp, hp, true, false); /* release block 1 */
- hp = hp_new; /* new block is to be split */
+ mf_put(mfp, hp, true, false); // release block 1
+ hp = hp_new; // new block is to be split
pp = pp_new;
CHECK(stack_idx != 0, _("stack_idx should be 0"));
ip->ip_index = 0;
- ++stack_idx; /* do block 1 again later */
+ ++stack_idx; // do block 1 again later
}
/*
* move the pointers after the current one to the new block
@@ -2338,15 +2387,16 @@ static int ml_append_int(
total_moved = pp->pb_count - pb_idx - 1;
if (total_moved) {
memmove(&pp_new->pb_pointer[0],
- &pp->pb_pointer[pb_idx + 1],
- (size_t)(total_moved) * sizeof(PTR_EN));
+ &pp->pb_pointer[pb_idx + 1],
+ (size_t)(total_moved) * sizeof(PTR_EN));
pp_new->pb_count = total_moved;
pp->pb_count -= total_moved - 1;
pp->pb_pointer[pb_idx + 1].pe_bnum = bnum_right;
pp->pb_pointer[pb_idx + 1].pe_line_count = line_count_right;
pp->pb_pointer[pb_idx + 1].pe_page_count = page_count_right;
- if (lnum_right)
+ if (lnum_right) {
pp->pb_pointer[pb_idx + 1].pe_old_lnum = lnum_right;
+ }
} else {
pp_new->pb_count = 1;
pp_new->pb_pointer[0].pe_bnum = bnum_right;
@@ -2357,8 +2407,9 @@ static int ml_append_int(
pp->pb_pointer[pb_idx].pe_bnum = bnum_left;
pp->pb_pointer[pb_idx].pe_line_count = line_count_left;
pp->pb_pointer[pb_idx].pe_page_count = page_count_left;
- if (lnum_left)
+ if (lnum_left) {
pp->pb_pointer[pb_idx].pe_old_lnum = lnum_left;
+ }
lnum_left = 0;
lnum_right = 0;
@@ -2366,11 +2417,13 @@ static int ml_append_int(
* recompute line counts
*/
line_count_right = 0;
- for (i = 0; i < (int)pp_new->pb_count; ++i)
+ for (i = 0; i < (int)pp_new->pb_count; ++i) {
line_count_right += pp_new->pb_pointer[i].pe_line_count;
+ }
line_count_left = 0;
- for (i = 0; i < (int)pp->pb_count; ++i)
+ for (i = 0; i < (int)pp->pb_count; ++i) {
line_count_left += pp->pb_pointer[i].pe_line_count;
+ }
bnum_left = hp->bh_bnum;
bnum_right = hp_new->bh_bnum;
@@ -2390,7 +2443,7 @@ static int ml_append_int(
}
}
- /* The line was inserted below 'lnum' */
+ // The line was inserted below 'lnum'
ml_updatechunk(buf, lnum + 1, (long)len, ML_CHNK_ADDLINE);
return OK;
}
@@ -2437,8 +2490,9 @@ int ml_replace(linenr_T lnum, char_u *line, bool copy)
// return FAIL for failure, OK otherwise
int ml_replace_buf(buf_T *buf, linenr_T lnum, char_u *line, bool copy)
{
- if (line == NULL) /* just checking... */
+ if (line == NULL) { // just checking...
return FAIL;
+ }
// When starting up, we might still need to create the memfile
if (buf->b_ml.ml_mfp == NULL && open_buffer(false, NULL, 0) == FAIL) {
@@ -2485,12 +2539,12 @@ int ml_delete(linenr_T lnum, bool message)
static int ml_delete_int(buf_T *buf, linenr_T lnum, bool message)
{
- bhdr_T *hp;
- memfile_T *mfp;
- DATA_BL *dp;
- PTR_BL *pp;
- infoptr_T *ip;
- int count; /* number of entries in block */
+ bhdr_T *hp;
+ memfile_T *mfp;
+ DATA_BL *dp;
+ PTR_BL *pp;
+ infoptr_T *ip;
+ int count; // number of entries in block
int idx;
int stack_idx;
int text_start;
@@ -2498,19 +2552,22 @@ static int ml_delete_int(buf_T *buf, linenr_T lnum, bool message)
long line_size;
int i;
- if (lnum < 1 || lnum > buf->b_ml.ml_line_count)
+ if (lnum < 1 || lnum > buf->b_ml.ml_line_count) {
return FAIL;
+ }
- if (lowest_marked && lowest_marked > lnum)
+ if (lowest_marked && lowest_marked > lnum) {
lowest_marked--;
+ }
/*
* If the file becomes empty the last line is replaced by an empty line.
*/
- if (buf->b_ml.ml_line_count == 1) { /* file becomes empty */
+ if (buf->b_ml.ml_line_count == 1) { // file becomes empty
if (message
- )
+ ) {
set_keep_msg((char_u *)_(no_lines_msg), 0);
+ }
i = ml_replace((linenr_T)1, (char_u *)"", true);
buf->b_ml.ml_flags |= ML_EMPTY;
@@ -2524,14 +2581,16 @@ static int ml_delete_int(buf_T *buf, linenr_T lnum, bool message)
* This also releases any locked block.
*/
mfp = buf->b_ml.ml_mfp;
- if (mfp == NULL)
+ if (mfp == NULL) {
return FAIL;
+ }
- if ((hp = ml_find_line(buf, lnum, ML_DELETE)) == NULL)
+ if ((hp = ml_find_line(buf, lnum, ML_DELETE)) == NULL) {
return FAIL;
+ }
dp = hp->bh_data;
- /* compute line count before the delete */
+ // compute line count before the delete
count = (long)(buf->b_ml.ml_locked_high)
- (long)(buf->b_ml.ml_locked_low) + 2;
idx = lnum - buf->b_ml.ml_locked_low;
@@ -2539,10 +2598,11 @@ static int ml_delete_int(buf_T *buf, linenr_T lnum, bool message)
--buf->b_ml.ml_line_count;
line_start = ((dp->db_index[idx]) & DB_INDEX_MASK);
- if (idx == 0) /* first line in block, text at the end */
+ if (idx == 0) { // first line in block, text at the end
line_size = dp->db_txt_end - line_start;
- else
+ } else {
line_size = ((dp->db_index[idx - 1]) & DB_INDEX_MASK) - line_start;
+ }
// Line should always have an NL char internally (represented as NUL),
// even if 'noeol' is set.
@@ -2558,33 +2618,35 @@ static int ml_delete_int(buf_T *buf, linenr_T lnum, bool message)
* ml_find_line().
*/
if (count == 1) {
- mf_free(mfp, hp); /* free the data block */
+ mf_free(mfp, hp); // free the data block
buf->b_ml.ml_locked = NULL;
for (stack_idx = buf->b_ml.ml_stack_top - 1; stack_idx >= 0;
--stack_idx) {
- buf->b_ml.ml_stack_top = 0; /* stack is invalid when failing */
+ buf->b_ml.ml_stack_top = 0; // stack is invalid when failing
ip = &(buf->b_ml.ml_stack[stack_idx]);
idx = ip->ip_index;
- if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
+ if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL) {
return FAIL;
- pp = hp->bh_data; /* must be pointer block */
+ }
+ pp = hp->bh_data; // must be pointer block
if (pp->pb_id != PTR_ID) {
IEMSG(_("E317: pointer block id wrong 4"));
mf_put(mfp, hp, false, false);
return FAIL;
}
count = --(pp->pb_count);
- if (count == 0) /* the pointer block becomes empty! */
+ if (count == 0) { // the pointer block becomes empty!
mf_free(mfp, hp);
- else {
- if (count != idx) /* move entries after the deleted one */
+ } else {
+ if (count != idx) { // move entries after the deleted one
memmove(&pp->pb_pointer[idx], &pp->pb_pointer[idx + 1],
- (size_t)(count - idx) * sizeof(PTR_EN));
+ (size_t)(count - idx) * sizeof(PTR_EN));
+ }
mf_put(mfp, hp, true, false);
- buf->b_ml.ml_stack_top = stack_idx; /* truncate stack */
- /* fix line count for rest of blocks in the stack */
+ buf->b_ml.ml_stack_top = stack_idx; // truncate stack
+ // fix line count for rest of blocks in the stack
if (buf->b_ml.ml_locked_lineadd != 0) {
ml_lineadd(buf, buf->b_ml.ml_locked_lineadd);
buf->b_ml.ml_stack[buf->b_ml.ml_stack_top].ip_high +=
@@ -2602,14 +2664,15 @@ static int ml_delete_int(buf_T *buf, linenr_T lnum, bool message)
*/
text_start = dp->db_txt_start;
memmove((char *)dp + text_start + line_size,
- (char *)dp + text_start, (size_t)(line_start - text_start));
+ (char *)dp + text_start, (size_t)(line_start - text_start));
/*
* delete the index by moving the next indexes backwards
* Adjust the indexes for the text movement.
*/
- for (i = idx; i < count - 1; ++i)
+ for (i = idx; i < count - 1; ++i) {
dp->db_index[i] = dp->db_index[i + 1] + line_size;
+ }
dp->db_free += line_size + INDEX_SIZE;
dp->db_txt_start += line_size;
@@ -2630,24 +2693,25 @@ static int ml_delete_int(buf_T *buf, linenr_T lnum, bool message)
*/
void ml_setmarked(linenr_T lnum)
{
- bhdr_T *hp;
+ bhdr_T *hp;
DATA_BL *dp;
- /* invalid line number */
+ // invalid line number
if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count
- || curbuf->b_ml.ml_mfp == NULL)
- return; /* give error message? */
-
- if (lowest_marked == 0 || lowest_marked > lnum)
+ || curbuf->b_ml.ml_mfp == NULL) {
+ return; // give error message?
+ }
+ if (lowest_marked == 0 || lowest_marked > lnum) {
lowest_marked = lnum;
+ }
/*
* find the data block containing the line
* This also fills the stack with the blocks from the root to the data block
* This also releases any locked block.
*/
- if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
- return; /* give error message? */
-
+ if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL) {
+ return; // give error message?
+ }
dp = hp->bh_data;
dp->db_index[lnum - curbuf->b_ml.ml_locked_low] |= DB_MARKED;
curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
@@ -2658,13 +2722,14 @@ void ml_setmarked(linenr_T lnum)
*/
linenr_T ml_firstmarked(void)
{
- bhdr_T *hp;
- DATA_BL *dp;
+ bhdr_T *hp;
+ DATA_BL *dp;
linenr_T lnum;
int i;
- if (curbuf->b_ml.ml_mfp == NULL)
- return (linenr_T) 0;
+ if (curbuf->b_ml.ml_mfp == NULL) {
+ return (linenr_T)0;
+ }
/*
* The search starts with lowest_marked line. This is the last line where
@@ -2676,22 +2741,23 @@ linenr_T ml_firstmarked(void)
* This also fills the stack with the blocks from the root to the data
* block This also releases any locked block.
*/
- if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
- return (linenr_T)0; /* give error message? */
-
+ if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL) {
+ return (linenr_T)0; // give error message?
+ }
dp = hp->bh_data;
for (i = lnum - curbuf->b_ml.ml_locked_low;
- lnum <= curbuf->b_ml.ml_locked_high; ++i, ++lnum)
+ lnum <= curbuf->b_ml.ml_locked_high; ++i, ++lnum) {
if ((dp->db_index[i]) & DB_MARKED) {
(dp->db_index[i]) &= DB_INDEX_MASK;
curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
lowest_marked = lnum + 1;
return lnum;
}
+ }
}
- return (linenr_T) 0;
+ return (linenr_T)0;
}
/*
@@ -2699,13 +2765,14 @@ linenr_T ml_firstmarked(void)
*/
void ml_clearmarked(void)
{
- bhdr_T *hp;
- DATA_BL *dp;
+ bhdr_T *hp;
+ DATA_BL *dp;
linenr_T lnum;
int i;
- if (curbuf->b_ml.ml_mfp == NULL) /* nothing to do */
+ if (curbuf->b_ml.ml_mfp == NULL) { // nothing to do
return;
+ }
/*
* The search starts with line lowest_marked.
@@ -2716,17 +2783,18 @@ void ml_clearmarked(void)
* This also fills the stack with the blocks from the root to the data
* block and releases any locked block.
*/
- if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL)
- return; /* give error message? */
-
+ if ((hp = ml_find_line(curbuf, lnum, ML_FIND)) == NULL) {
+ return; // give error message?
+ }
dp = hp->bh_data;
for (i = lnum - curbuf->b_ml.ml_locked_low;
- lnum <= curbuf->b_ml.ml_locked_high; ++i, ++lnum)
+ lnum <= curbuf->b_ml.ml_locked_high; ++i, ++lnum) {
if ((dp->db_index[i]) & DB_MARKED) {
(dp->db_index[i]) &= DB_INDEX_MASK;
curbuf->b_ml.ml_flags |= ML_LOCKED_DIRTY;
}
+ }
}
lowest_marked = 0;
@@ -2749,11 +2817,11 @@ size_t ml_flush_deleted_bytes(buf_T *buf, size_t *codepoints, size_t *codeunits)
*/
static void ml_flush_line(buf_T *buf)
{
- bhdr_T *hp;
- DATA_BL *dp;
+ bhdr_T *hp;
+ DATA_BL *dp;
linenr_T lnum;
- char_u *new_line;
- char_u *old_line;
+ char_u *new_line;
+ char_u *old_line;
colnr_T new_len;
int old_len;
int extra;
@@ -2761,16 +2829,17 @@ static void ml_flush_line(buf_T *buf)
int start;
int count;
int i;
- static int entered = FALSE;
-
- if (buf->b_ml.ml_line_lnum == 0 || buf->b_ml.ml_mfp == NULL)
- return; /* nothing to do */
+ static bool entered = false;
+ if (buf->b_ml.ml_line_lnum == 0 || buf->b_ml.ml_mfp == NULL) {
+ return; // nothing to do
+ }
if (buf->b_ml.ml_flags & ML_LINE_DIRTY) {
- /* This code doesn't work recursively. */
- if (entered)
+ // This code doesn't work recursively.
+ if (entered) {
return;
- entered = TRUE;
+ }
+ entered = true;
buf->flush_count++;
@@ -2785,39 +2854,41 @@ static void ml_flush_line(buf_T *buf)
idx = lnum - buf->b_ml.ml_locked_low;
start = ((dp->db_index[idx]) & DB_INDEX_MASK);
old_line = (char_u *)dp + start;
- if (idx == 0) /* line is last in block */
+ if (idx == 0) { // line is last in block
old_len = dp->db_txt_end - start;
- else /* text of previous line follows */
+ } else { // text of previous line follows
old_len = (dp->db_index[idx - 1] & DB_INDEX_MASK) - start;
+ }
new_len = (colnr_T)STRLEN(new_line) + 1;
- extra = new_len - old_len; /* negative if lines gets smaller */
+ extra = new_len - old_len; // negative if lines gets smaller
/*
* if new line fits in data block, replace directly
*/
if ((int)dp->db_free >= extra) {
- /* if the length changes and there are following lines */
+ // if the length changes and there are following lines
count = buf->b_ml.ml_locked_high - buf->b_ml.ml_locked_low + 1;
if (extra != 0 && idx < count - 1) {
- /* move text of following lines */
+ // move text of following lines
memmove((char *)dp + dp->db_txt_start - extra,
- (char *)dp + dp->db_txt_start,
- (size_t)(start - dp->db_txt_start));
+ (char *)dp + dp->db_txt_start,
+ (size_t)(start - dp->db_txt_start));
- /* adjust pointers of this and following lines */
- for (i = idx + 1; i < count; ++i)
+ // adjust pointers of this and following lines
+ for (i = idx + 1; i < count; ++i) {
dp->db_index[i] -= extra;
+ }
}
dp->db_index[idx] -= extra;
- /* adjust free space */
+ // adjust free space
dp->db_free -= extra;
dp->db_txt_start -= extra;
- /* copy new line into the data block */
+ // copy new line into the data block
memmove(old_line - extra, new_line, (size_t)new_len);
buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS);
- /* The else case is already covered by the insert and delete */
+ // The else case is already covered by the insert and delete
ml_updatechunk(buf, lnum, (long)extra, ML_CHNK_UPDLINE);
} else {
// Cannot do it in one data block: Delete and append.
@@ -2833,7 +2904,7 @@ static void ml_flush_line(buf_T *buf)
}
xfree(new_line);
- entered = FALSE;
+ entered = false;
}
buf->b_ml.ml_line_lnum = 0;
@@ -2874,8 +2945,8 @@ static bhdr_T *ml_new_ptr(memfile_T *mfp)
* lookup line 'lnum' in a memline
*
* action: if ML_DELETE or ML_INSERT the line count is updated while searching
- * if ML_FLUSH only flush a locked block
- * if ML_FIND just find the line
+ * if ML_FLUSH only flush a locked block
+ * if ML_FIND just find the line
*
* If the block was found it is locked and put in ml_locked.
* The stack is updated to lead to the locked block. The ip_high field in
@@ -2887,11 +2958,11 @@ static bhdr_T *ml_new_ptr(memfile_T *mfp)
*/
static bhdr_T *ml_find_line(buf_T *buf, linenr_T lnum, int action)
{
- DATA_BL *dp;
- PTR_BL *pp;
- infoptr_T *ip;
- bhdr_T *hp;
- memfile_T *mfp;
+ DATA_BL *dp;
+ PTR_BL *pp;
+ infoptr_T *ip;
+ bhdr_T *hp;
+ memfile_T *mfp;
linenr_T t;
blocknr_T bnum, bnum2;
int dirty;
@@ -2925,58 +2996,63 @@ static bhdr_T *ml_find_line(buf_T *buf, linenr_T lnum, int action)
}
mf_put(mfp, buf->b_ml.ml_locked, buf->b_ml.ml_flags & ML_LOCKED_DIRTY,
- buf->b_ml.ml_flags & ML_LOCKED_POS);
+ buf->b_ml.ml_flags & ML_LOCKED_POS);
buf->b_ml.ml_locked = NULL;
/*
* If lines have been added or deleted in the locked block, need to
* update the line count in pointer blocks.
*/
- if (buf->b_ml.ml_locked_lineadd != 0)
+ if (buf->b_ml.ml_locked_lineadd != 0) {
ml_lineadd(buf, buf->b_ml.ml_locked_lineadd);
+ }
}
- if (action == ML_FLUSH) /* nothing else to do */
+ if (action == ML_FLUSH) { // nothing else to do
return NULL;
+ }
- bnum = 1; /* start at the root of the tree */
+ bnum = 1; // start at the root of the tree
page_count = 1;
low = 1;
high = buf->b_ml.ml_line_count;
- if (action == ML_FIND) { /* first try stack entries */
+ if (action == ML_FIND) { // first try stack entries
for (top = buf->b_ml.ml_stack_top - 1; top >= 0; --top) {
ip = &(buf->b_ml.ml_stack[top]);
if (ip->ip_low <= lnum && ip->ip_high >= lnum) {
bnum = ip->ip_bnum;
low = ip->ip_low;
high = ip->ip_high;
- buf->b_ml.ml_stack_top = top; /* truncate stack at prev entry */
+ buf->b_ml.ml_stack_top = top; // truncate stack at prev entry
break;
}
}
- if (top < 0)
- buf->b_ml.ml_stack_top = 0; /* not found, start at the root */
- } else /* ML_DELETE or ML_INSERT */
- buf->b_ml.ml_stack_top = 0; /* start at the root */
-
+ if (top < 0) {
+ buf->b_ml.ml_stack_top = 0; // not found, start at the root
+ }
+ } else { // ML_DELETE or ML_INSERT
+ buf->b_ml.ml_stack_top = 0; // start at the root
+ }
/*
* search downwards in the tree until a data block is found
*/
for (;; ) {
- if ((hp = mf_get(mfp, bnum, page_count)) == NULL)
+ if ((hp = mf_get(mfp, bnum, page_count)) == NULL) {
goto error_noblock;
+ }
/*
* update high for insert/delete
*/
- if (action == ML_INSERT)
+ if (action == ML_INSERT) {
++high;
- else if (action == ML_DELETE)
+ } else if (action == ML_DELETE) {
--high;
+ }
dp = hp->bh_data;
- if (dp->db_id == DATA_ID) { /* data block */
+ if (dp->db_id == DATA_ID) { // data block
buf->b_ml.ml_locked = hp;
buf->b_ml.ml_locked_low = low;
buf->b_ml.ml_locked_high = high;
@@ -2985,7 +3061,7 @@ static bhdr_T *ml_find_line(buf_T *buf, linenr_T lnum, int action)
return hp;
}
- pp = (PTR_BL *)(dp); /* must be pointer block */
+ pp = (PTR_BL *)(dp); // must be pointer block
if (pp->pb_id != PTR_ID) {
IEMSG(_("E317: pointer block id wrong"));
goto error_block;
@@ -2996,7 +3072,7 @@ static bhdr_T *ml_find_line(buf_T *buf, linenr_T lnum, int action)
ip->ip_bnum = bnum;
ip->ip_low = low;
ip->ip_high = high;
- ip->ip_index = -1; /* index not known yet */
+ ip->ip_index = -1; // index not known yet
dirty = FALSE;
for (idx = 0; idx < (int)pp->pb_count; ++idx) {
@@ -3028,7 +3104,6 @@ static bhdr_T *ml_find_line(buf_T *buf, linenr_T lnum, int action)
if (lnum > buf->b_ml.ml_line_count) {
IEMSGN(_("E322: line number out of range: %" PRId64 " past the end"),
lnum - buf->b_ml.ml_line_count);
-
} else {
IEMSGN(_("E323: line count wrong in block %" PRId64), bnum);
}
@@ -3052,10 +3127,11 @@ error_noblock:
* the incremented/decremented line counts, because there won't be a line
* inserted/deleted after all.
*/
- if (action == ML_DELETE)
+ if (action == ML_DELETE) {
ml_lineadd(buf, 1);
- else if (action == ML_INSERT)
+ } else if (action == ML_INSERT) {
ml_lineadd(buf, -1);
+ }
buf->b_ml.ml_stack_top = 0;
return NULL;
}
@@ -3069,9 +3145,9 @@ static int ml_add_stack(buf_T *buf)
{
int top = buf->b_ml.ml_stack_top;
- /* may have to increase the stack size */
+ // may have to increase the stack size
if (top == buf->b_ml.ml_stack_size) {
- CHECK(top > 0, _("Stack size increases")); /* more than 5 levels??? */
+ CHECK(top > 0, _("Stack size increases")); // more than 5 levels???
buf->b_ml.ml_stack_size += STACK_INCR;
size_t new_size = sizeof(infoptr_T) * buf->b_ml.ml_stack_size;
@@ -3095,16 +3171,17 @@ static int ml_add_stack(buf_T *buf)
static void ml_lineadd(buf_T *buf, int count)
{
int idx;
- infoptr_T *ip;
- PTR_BL *pp;
- memfile_T *mfp = buf->b_ml.ml_mfp;
- bhdr_T *hp;
+ infoptr_T *ip;
+ PTR_BL *pp;
+ memfile_T *mfp = buf->b_ml.ml_mfp;
+ bhdr_T *hp;
for (idx = buf->b_ml.ml_stack_top - 1; idx >= 0; --idx) {
ip = &(buf->b_ml.ml_stack[idx]);
- if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL)
+ if ((hp = mf_get(mfp, ip->ip_bnum, 1)) == NULL) {
break;
- pp = hp->bh_data; /* must be pointer block */
+ }
+ pp = hp->bh_data; // must be pointer block
if (pp->pb_id != PTR_ID) {
mf_put(mfp, hp, false, false);
IEMSG(_("E317: pointer block id wrong 2"));
@@ -3130,14 +3207,15 @@ int resolve_symlink(const char_u *fname, char_u *buf)
int ret;
int depth = 0;
- if (fname == NULL)
+ if (fname == NULL) {
return FAIL;
+ }
- /* Put the result so far in tmp[], starting with the original name. */
+ // Put the result so far in tmp[], starting with the original name.
STRLCPY(tmp, fname, MAXPATHL);
for (;; ) {
- /* Limit symlink depth to 100, catch recursive loops. */
+ // Limit symlink depth to 100, catch recursive loops.
if (++depth == 100) {
EMSG2(_("E773: Symlink loop for \"%s\""), fname);
return FAIL;
@@ -3149,14 +3227,15 @@ int resolve_symlink(const char_u *fname, char_u *buf)
/* Found non-symlink or not existing file, stop here.
* When at the first level use the unmodified name, skip the
* call to vim_FullName(). */
- if (depth == 1)
+ if (depth == 1) {
return FAIL;
+ }
- /* Use the resolved name in tmp[]. */
+ // Use the resolved name in tmp[].
break;
}
- /* There must be some error reading links, use original name. */
+ // There must be some error reading links, use original name.
return FAIL;
}
buf[ret] = NUL;
@@ -3191,8 +3270,8 @@ int resolve_symlink(const char_u *fname, char_u *buf)
*/
char_u *makeswapname(char_u *fname, char_u *ffname, buf_T *buf, char_u *dir_name)
{
- char_u *r, *s;
- char_u *fname_res = fname;
+ char_u *r, *s;
+ char_u *fname_res = fname;
#ifdef HAVE_READLINK
char_u fname_buf[MAXPATHL];
@@ -3219,46 +3298,43 @@ char_u *makeswapname(char_u *fname, char_u *ffname, buf_T *buf, char_u *dir_name
// Prepend a '.' to the swap file name for the current directory.
r = (char_u *)modname((char *)fname_res, ".swp",
- dir_name[0] == '.' && dir_name[1] == NUL);
- if (r == NULL) /* out of memory */
+ dir_name[0] == '.' && dir_name[1] == NUL);
+ if (r == NULL) { // out of memory
return NULL;
+ }
s = get_file_in_dir(r, dir_name);
xfree(r);
return s;
}
-/*
- * Get file name to use for swap file or backup file.
- * Use the name of the edited file "fname" and an entry in the 'dir' or 'bdir'
- * option "dname".
- * - If "dname" is ".", return "fname" (swap file in dir of file).
- * - If "dname" starts with "./", insert "dname" in "fname" (swap file
- * relative to dir of file).
- * - Otherwise, prepend "dname" to the tail of "fname" (swap file in specific
- * dir).
- *
- * The return value is an allocated string and can be NULL.
- */
-char_u *
-get_file_in_dir (
- char_u *fname,
- char_u *dname /* don't use "dirname", it is a global for Alpha */
-)
+/// Get file name to use for swap file or backup file.
+/// Use the name of the edited file "fname" and an entry in the 'dir' or 'bdir'
+/// option "dname".
+/// - If "dname" is ".", return "fname" (swap file in dir of file).
+/// - If "dname" starts with "./", insert "dname" in "fname" (swap file
+/// relative to dir of file).
+/// - Otherwise, prepend "dname" to the tail of "fname" (swap file in specific
+/// dir).
+///
+/// The return value is an allocated string and can be NULL.
+///
+/// @param dname don't use "dirname", it is a global for Alpha
+char_u *get_file_in_dir(char_u *fname, char_u *dname)
{
- char_u *t;
- char_u *tail;
- char_u *retval;
+ char_u *t;
+ char_u *tail;
+ char_u *retval;
int save_char;
tail = path_tail(fname);
- if (dname[0] == '.' && dname[1] == NUL)
+ if (dname[0] == '.' && dname[1] == NUL) {
retval = vim_strsave(fname);
- else if (dname[0] == '.' && vim_ispathsep(dname[1])) {
- if (tail == fname) /* no path before file name */
+ } else if (dname[0] == '.' && vim_ispathsep(dname[1])) {
+ if (tail == fname) { // no path before file name
retval = (char_u *)concat_fnames((char *)dname + 2, (char *)tail, TRUE);
- else {
+ } else {
save_char = *tail;
*tail = NUL;
t = (char_u *)concat_fnames((char *)fname, (char *)dname + 2, TRUE);
@@ -3274,14 +3350,11 @@ get_file_in_dir (
}
-/*
- * Print the ATTENTION message: info about an existing swap file.
- */
-static void
-attention_message (
- buf_T *buf, /* buffer being edited */
- char_u *fname /* swap file name */
-)
+/// Print the ATTENTION message: info about an existing swap file.
+///
+/// @param buf buffer being edited
+/// @param fname swap file name
+static void attention_message(buf_T *buf, char_u *fname)
{
assert(buf->b_fname != NULL);
@@ -3337,24 +3410,30 @@ attention_message (
*/
static int do_swapexists(buf_T *buf, char_u *fname)
{
- set_vim_var_string(VV_SWAPNAME, (char *) fname, -1);
+ set_vim_var_string(VV_SWAPNAME, (char *)fname, -1);
set_vim_var_string(VV_SWAPCHOICE, NULL, -1);
- /* Trigger SwapExists autocommands with <afile> set to the file being
- * edited. Disallow changing directory here. */
- ++allbuf_lock;
- apply_autocmds(EVENT_SWAPEXISTS, buf->b_fname, NULL, FALSE, NULL);
- --allbuf_lock;
+ // Trigger SwapExists autocommands with <afile> set to the file being
+ // edited. Disallow changing directory here.
+ allbuf_lock++;
+ apply_autocmds(EVENT_SWAPEXISTS, buf->b_fname, NULL, false, NULL);
+ allbuf_lock--;
set_vim_var_string(VV_SWAPNAME, NULL, -1);
switch (*get_vim_var_str(VV_SWAPCHOICE)) {
- case 'o': return 1;
- case 'e': return 2;
- case 'r': return 3;
- case 'd': return 4;
- case 'q': return 5;
- case 'a': return 6;
+ case 'o':
+ return 1;
+ case 'e':
+ return 2;
+ case 'r':
+ return 3;
+ case 'd':
+ return 4;
+ case 'q':
+ return 5;
+ case 'a':
+ return 6;
}
return 0;
@@ -3383,14 +3462,13 @@ static int do_swapexists(buf_T *buf, char_u *fname)
/// never set to false.
///
/// @return [allocated] Name of the swap file.
-static char *findswapname(buf_T *buf, char **dirp, char *old_fname,
- bool *found_existing_dir)
+static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_existing_dir)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1, 2, 4)
{
char *fname;
size_t n;
char *dir_name;
- char *buf_fname = (char *) buf->b_fname;
+ char *buf_fname = (char *)buf->b_fname;
/*
* Isolate a directory name from *dirp and put it in dir_name.
@@ -3398,7 +3476,7 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname,
*/
const size_t dir_len = strlen(*dirp) + 1;
dir_name = xmalloc(dir_len);
- (void)copy_option_part((char_u **) dirp, (char_u *) dir_name, dir_len, ",");
+ (void)copy_option_part((char_u **)dirp, (char_u *)dir_name, dir_len, ",");
/*
* we try different names until we find one that does not exist yet
@@ -3457,7 +3535,7 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname,
// inode too.
expand_env(b0.b0_fname, NameBuff, MAXPATHL);
if (fnamecmp_ino(buf->b_ffname, NameBuff,
- char_to_long(b0.b0_ino))) {
+ char_to_long(b0.b0_ino))) {
differ = TRUE;
}
}
@@ -3466,7 +3544,7 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname,
// "~user/path/file". Expand it first.
expand_env(b0.b0_fname, NameBuff, MAXPATHL);
if (fnamecmp_ino(buf->b_ffname, NameBuff,
- char_to_long(b0.b0_ino))) {
+ char_to_long(b0.b0_ino))) {
differ = TRUE;
}
}
@@ -3530,12 +3608,10 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname,
choice = do_dialog(VIM_WARNING, (char_u *)_("VIM - ATTENTION"),
(char_u *)name,
process_still_running
- ? (char_u *)_(
- "&Open Read-Only\n&Edit anyway\n&Recover"
- "\n&Quit\n&Abort") :
- (char_u *)_(
- "&Open Read-Only\n&Edit anyway\n&Recover"
- "\n&Delete it\n&Quit\n&Abort"),
+ ? (char_u *)_("&Open Read-Only\n&Edit anyway\n&Recover"
+ "\n&Quit\n&Abort") :
+ (char_u *)_("&Open Read-Only\n&Edit anyway\n&Recover"
+ "\n&Delete it\n&Quit\n&Abort"),
1, NULL, false);
if (process_still_running && choice >= 4) {
@@ -3575,11 +3651,11 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname,
}
} else {
MSG_PUTS("\n");
- if (msg_silent == 0)
- /* call wait_return() later */
- need_wait_return = TRUE;
+ if (msg_silent == 0) {
+ // call wait_return() later
+ need_wait_return = true;
+ }
}
-
}
}
}
@@ -3590,19 +3666,19 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname,
* If that still isn't enough decrement the last but one char: ".svz"
* Can happen when editing many "No Name" buffers.
*/
- if (fname[n - 1] == 'a') { /* ".s?a" */
- if (fname[n - 2] == 'a') { /* ".saa": tried enough, give up */
+ if (fname[n - 1] == 'a') { // ".s?a"
+ if (fname[n - 2] == 'a') { // ".saa": tried enough, give up
EMSG(_("E326: Too many swap files found"));
XFREE_CLEAR(fname);
break;
}
- --fname[n - 2]; /* ".svz", ".suz", etc. */
+ --fname[n - 2]; // ".svz", ".suz", etc.
fname[n - 1] = 'z' + 1;
}
- --fname[n - 1]; /* ".swo", ".swn", etc. */
+ --fname[n - 1]; // ".swo", ".swn", etc.
}
- if (os_isdir((char_u *) dir_name)) {
+ if (os_isdir((char_u *)dir_name)) {
*found_existing_dir = true;
} else if (!*found_existing_dir && **dirp == NUL) {
int ret;
@@ -3627,66 +3703,62 @@ static int b0_magic_wrong(ZERO_BL *b0p)
|| b0p->b0_magic_char != B0_MAGIC_CHAR;
}
-/*
- * Compare current file name with file name from swap file.
- * Try to use inode numbers when possible.
- * Return non-zero when files are different.
- *
- * When comparing file names a few things have to be taken into consideration:
- * - When working over a network the full path of a file depends on the host.
- * We check the inode number if possible. It is not 100% reliable though,
- * because the device number cannot be used over a network.
- * - When a file does not exist yet (editing a new file) there is no inode
- * number.
- * - The file name in a swap file may not be valid on the current host. The
- * "~user" form is used whenever possible to avoid this.
- *
- * This is getting complicated, let's make a table:
- *
- * ino_c ino_s fname_c fname_s differ =
- *
- * both files exist -> compare inode numbers:
- * != 0 != 0 X X ino_c != ino_s
- *
- * inode number(s) unknown, file names available -> compare file names
- * == 0 X OK OK fname_c != fname_s
- * X == 0 OK OK fname_c != fname_s
- *
- * current file doesn't exist, file for swap file exist, file name(s) not
- * available -> probably different
- * == 0 != 0 FAIL X TRUE
- * == 0 != 0 X FAIL TRUE
- *
- * current file exists, inode for swap unknown, file name(s) not
- * available -> probably different
- * != 0 == 0 FAIL X TRUE
- * != 0 == 0 X FAIL TRUE
- *
- * current file doesn't exist, inode for swap unknown, one file name not
- * available -> probably different
- * == 0 == 0 FAIL OK TRUE
- * == 0 == 0 OK FAIL TRUE
- *
- * current file doesn't exist, inode for swap unknown, both file names not
- * available -> compare file names
- * == 0 == 0 FAIL FAIL fname_c != fname_s
- *
- * Only the last 32 bits of the inode will be used. This can't be changed
- * without making the block 0 incompatible with 32 bit versions.
- */
-
-static bool fnamecmp_ino(
- char_u *fname_c, // current file name
- char_u *fname_s, // file name from swap file
- long ino_block0
-)
+/// Compare current file name with file name from swap file.
+/// Try to use inode numbers when possible.
+/// Return non-zero when files are different.
+///
+/// When comparing file names a few things have to be taken into consideration:
+/// - When working over a network the full path of a file depends on the host.
+/// We check the inode number if possible. It is not 100% reliable though,
+/// because the device number cannot be used over a network.
+/// - When a file does not exist yet (editing a new file) there is no inode
+/// number.
+/// - The file name in a swap file may not be valid on the current host. The
+/// "~user" form is used whenever possible to avoid this.
+///
+/// This is getting complicated, let's make a table:
+///
+/// ino_c ino_s fname_c fname_s differ =
+///
+/// both files exist -> compare inode numbers:
+/// != 0 != 0 X X ino_c != ino_s
+///
+/// inode number(s) unknown, file names available -> compare file names
+/// == 0 X OK OK fname_c != fname_s
+/// X == 0 OK OK fname_c != fname_s
+///
+/// current file doesn't exist, file for swap file exist, file name(s) not
+/// available -> probably different
+/// == 0 != 0 FAIL X TRUE
+/// == 0 != 0 X FAIL TRUE
+///
+/// current file exists, inode for swap unknown, file name(s) not
+/// available -> probably different
+/// != 0 == 0 FAIL X TRUE
+/// != 0 == 0 X FAIL TRUE
+///
+/// current file doesn't exist, inode for swap unknown, one file name not
+/// available -> probably different
+/// == 0 == 0 FAIL OK TRUE
+/// == 0 == 0 OK FAIL TRUE
+///
+/// current file doesn't exist, inode for swap unknown, both file names not
+/// available -> compare file names
+/// == 0 == 0 FAIL FAIL fname_c != fname_s
+///
+/// Only the last 32 bits of the inode will be used. This can't be changed
+/// without making the block 0 incompatible with 32 bit versions.
+///
+/// @param fname_c current file name
+/// @param fname_s file name from swap file
+static bool fnamecmp_ino(char_u *fname_c, char_u *fname_s, long ino_block0)
{
- uint64_t ino_c = 0; /* ino of current file */
- uint64_t ino_s; /* ino of file from swap file */
- char_u buf_c[MAXPATHL]; /* full path of fname_c */
- char_u buf_s[MAXPATHL]; /* full path of fname_s */
- int retval_c; /* flag: buf_c valid */
- int retval_s; /* flag: buf_s valid */
+ uint64_t ino_c = 0; // ino of current file
+ uint64_t ino_s; // ino of file from swap file
+ char_u buf_c[MAXPATHL]; // full path of fname_c
+ char_u buf_s[MAXPATHL]; // full path of fname_s
+ int retval_c; // flag: buf_c valid
+ int retval_s; // flag: buf_s valid
FileInfo file_info;
if (os_fileinfo((char *)fname_c, &file_info)) {
@@ -3704,8 +3776,9 @@ static bool fnamecmp_ino(
ino_s = (uint64_t)ino_block0;
}
- if (ino_c && ino_s)
+ if (ino_c && ino_s) {
return ino_c != ino_s;
+ }
/*
* One of the inode numbers is unknown, try a forced vim_FullName() and
@@ -3713,8 +3786,9 @@ static bool fnamecmp_ino(
*/
retval_c = vim_FullName((char *)fname_c, (char *)buf_c, MAXPATHL, TRUE);
retval_s = vim_FullName((char *)fname_s, (char *)buf_s, MAXPATHL, TRUE);
- if (retval_c == OK && retval_s == OK)
+ if (retval_c == OK && retval_s == OK) {
return STRCMP(buf_c, buf_s) != 0;
+ }
/*
* Can't compare inodes or file names, guess that the files are different,
@@ -3765,11 +3839,12 @@ static long char_to_long(char_u *s)
*/
void ml_setflags(buf_T *buf)
{
- bhdr_T *hp;
- ZERO_BL *b0p;
+ bhdr_T *hp;
+ ZERO_BL *b0p;
- if (!buf->b_ml.ml_mfp)
+ if (!buf->b_ml.ml_mfp) {
return;
+ }
for (hp = buf->b_ml.ml_mfp->mf_used_last; hp != NULL; hp = hp->bh_prev) {
if (hp->bh_bnum == 0) {
b0p = hp->bh_data;
@@ -3784,19 +3859,19 @@ void ml_setflags(buf_T *buf)
}
}
-#define MLCS_MAXL 800 /* max no of lines in chunk */
-#define MLCS_MINL 400 /* should be half of MLCS_MAXL */
+#define MLCS_MAXL 800 // max no of lines in chunk
+#define MLCS_MINL 400 // should be half of MLCS_MAXL
/*
* Keep information for finding byte offset of a line, updtype may be one of:
* ML_CHNK_ADDLINE: Add len to parent chunk, possibly splitting it
- * Careful: ML_CHNK_ADDLINE may cause ml_find_line() to be called.
+ * Careful: ML_CHNK_ADDLINE may cause ml_find_line() to be called.
* ML_CHNK_DELLINE: Subtract len from parent chunk, possibly deleting it
* ML_CHNK_UPDLINE: Add len to parent chunk, as a signed entity.
*/
static void ml_updatechunk(buf_T *buf, linenr_T line, long len, int updtype)
{
- static buf_T *ml_upd_lastbuf = NULL;
+ static buf_T *ml_upd_lastbuf = NULL;
static linenr_T ml_upd_lastline;
static linenr_T ml_upd_lastcurline;
static int ml_upd_lastcurix;
@@ -3804,13 +3879,14 @@ static void ml_updatechunk(buf_T *buf, linenr_T line, long len, int updtype)
linenr_T curline = ml_upd_lastcurline;
int curix = ml_upd_lastcurix;
long size;
- chunksize_T *curchnk;
+ chunksize_T *curchnk;
int rest;
- bhdr_T *hp;
- DATA_BL *dp;
+ bhdr_T *hp;
+ DATA_BL *dp;
- if (buf->b_ml.ml_usedchunks == -1 || len == 0)
+ if (buf->b_ml.ml_usedchunks == -1 || len == 0) {
return;
+ }
if (buf->b_ml.ml_chunksize == NULL) {
buf->b_ml.ml_chunksize = xmalloc(sizeof(chunksize_T) * 100);
buf->b_ml.ml_numchunks = 100;
@@ -3838,8 +3914,8 @@ static void ml_updatechunk(buf_T *buf, linenr_T line, long len, int updtype)
|| updtype != ML_CHNK_ADDLINE) {
for (curline = 1, curix = 0;
curix < buf->b_ml.ml_usedchunks - 1
- && line >= curline +
- buf->b_ml.ml_chunksize[curix].mlcs_numlines;
+ && line >= curline +
+ buf->b_ml.ml_chunksize[curix].mlcs_numlines;
curix++) {
curline += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
}
@@ -3851,31 +3927,31 @@ static void ml_updatechunk(buf_T *buf, linenr_T line, long len, int updtype)
}
curchnk = buf->b_ml.ml_chunksize + curix;
- if (updtype == ML_CHNK_DELLINE)
+ if (updtype == ML_CHNK_DELLINE) {
len = -len;
+ }
curchnk->mlcs_totalsize += len;
if (updtype == ML_CHNK_ADDLINE) {
curchnk->mlcs_numlines++;
- /* May resize here so we don't have to do it in both cases below */
+ // May resize here so we don't have to do it in both cases below
if (buf->b_ml.ml_usedchunks + 1 >= buf->b_ml.ml_numchunks) {
buf->b_ml.ml_numchunks = buf->b_ml.ml_numchunks * 3 / 2;
- buf->b_ml.ml_chunksize = xrealloc(
- buf->b_ml.ml_chunksize,
- sizeof(chunksize_T) * buf->b_ml.ml_numchunks);
+ buf->b_ml.ml_chunksize = xrealloc(buf->b_ml.ml_chunksize,
+ sizeof(chunksize_T) * buf->b_ml.ml_numchunks);
}
if (buf->b_ml.ml_chunksize[curix].mlcs_numlines >= MLCS_MAXL) {
- int count; /* number of entries in block */
+ int count; // number of entries in block
int idx;
int text_end;
int linecnt;
memmove(buf->b_ml.ml_chunksize + curix + 1,
- buf->b_ml.ml_chunksize + curix,
- (buf->b_ml.ml_usedchunks - curix) *
- sizeof(chunksize_T));
- /* Compute length of first half of lines in the split chunk */
+ buf->b_ml.ml_chunksize + curix,
+ (buf->b_ml.ml_usedchunks - curix) *
+ sizeof(chunksize_T));
+ // Compute length of first half of lines in the split chunk
size = 0;
linecnt = 0;
while (curline < buf->b_ml.ml_line_count
@@ -3889,11 +3965,12 @@ static void ml_updatechunk(buf_T *buf, linenr_T line, long len, int updtype)
(long)(buf->b_ml.ml_locked_low) + 1;
idx = curline - buf->b_ml.ml_locked_low;
curline = buf->b_ml.ml_locked_high + 1;
- if (idx == 0) /* first line in block, text at the end */
+ if (idx == 0) { // first line in block, text at the end
text_end = dp->db_txt_end;
- else
+ } else {
text_end = ((dp->db_index[idx - 1]) & DB_INDEX_MASK);
- /* Compute index of last line to use in this MEMLINE */
+ }
+ // Compute index of last line to use in this MEMLINE
rest = count - idx;
if (linecnt + rest > MLCS_MINL) {
idx += MLCS_MINL - linecnt - 1;
@@ -3909,7 +3986,7 @@ static void ml_updatechunk(buf_T *buf, linenr_T line, long len, int updtype)
buf->b_ml.ml_chunksize[curix].mlcs_totalsize = size;
buf->b_ml.ml_chunksize[curix + 1].mlcs_totalsize -= size;
buf->b_ml.ml_usedchunks++;
- ml_upd_lastbuf = NULL; /* Force recalc of curix & curline */
+ ml_upd_lastbuf = NULL; // Force recalc of curix & curline
return;
} else if (buf->b_ml.ml_chunksize[curix].mlcs_numlines >= MLCS_MINL
&& curix == buf->b_ml.ml_usedchunks - 1
@@ -3934,12 +4011,13 @@ static void ml_updatechunk(buf_T *buf, linenr_T line, long len, int updtype)
return;
}
dp = hp->bh_data;
- if (dp->db_line_count == 1)
+ if (dp->db_line_count == 1) {
rest = dp->db_txt_end - dp->db_txt_start;
- else
+ } else {
rest =
((dp->db_index[dp->db_line_count - 2]) & DB_INDEX_MASK)
- dp->db_txt_start;
+ }
curchnk->mlcs_totalsize = rest;
curchnk->mlcs_numlines = 1;
curchnk[-1].mlcs_totalsize -= rest;
@@ -3948,7 +4026,7 @@ static void ml_updatechunk(buf_T *buf, linenr_T line, long len, int updtype)
}
} else if (updtype == ML_CHNK_DELLINE) {
curchnk->mlcs_numlines--;
- ml_upd_lastbuf = NULL; /* Force recalc of curix & curline */
+ ml_upd_lastbuf = NULL; // Force recalc of curix & curline
if (curix < (buf->b_ml.ml_usedchunks - 1)
&& (curchnk->mlcs_numlines + curchnk[1].mlcs_numlines)
<= MLCS_MINL) {
@@ -3957,7 +4035,7 @@ static void ml_updatechunk(buf_T *buf, linenr_T line, long len, int updtype)
} else if (curix == 0 && curchnk->mlcs_numlines <= 0) {
buf->b_ml.ml_usedchunks--;
memmove(buf->b_ml.ml_chunksize, buf->b_ml.ml_chunksize + 1,
- buf->b_ml.ml_usedchunks * sizeof(chunksize_T));
+ buf->b_ml.ml_usedchunks * sizeof(chunksize_T));
return;
} else if (curix == 0 || (curchnk->mlcs_numlines > 10
&& (curchnk->mlcs_numlines +
@@ -3966,15 +4044,15 @@ static void ml_updatechunk(buf_T *buf, linenr_T line, long len, int updtype)
return;
}
- /* Collapse chunks */
+ // Collapse chunks
curchnk[-1].mlcs_numlines += curchnk->mlcs_numlines;
curchnk[-1].mlcs_totalsize += curchnk->mlcs_totalsize;
buf->b_ml.ml_usedchunks--;
if (curix < buf->b_ml.ml_usedchunks) {
memmove(buf->b_ml.ml_chunksize + curix,
- buf->b_ml.ml_chunksize + curix + 1,
- (buf->b_ml.ml_usedchunks - curix) *
- sizeof(chunksize_T));
+ buf->b_ml.ml_chunksize + curix + 1,
+ (buf->b_ml.ml_usedchunks - curix) *
+ sizeof(chunksize_T));
}
return;
}
@@ -3999,9 +4077,9 @@ long ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp, bool no_ff)
linenr_T curline;
int curix;
long size;
- bhdr_T *hp;
- DATA_BL *dp;
- int count; /* number of entries in block */
+ bhdr_T *hp;
+ DATA_BL *dp;
+ int count; // number of entries in block
int idx;
int start_idx;
int text_end;
@@ -4029,15 +4107,18 @@ long ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp, bool no_ff)
if (buf->b_ml.ml_usedchunks == -1
|| buf->b_ml.ml_chunksize == NULL
- || lnum < 0)
+ || lnum < 0) {
return -1;
+ }
- if (offp == NULL)
+ if (offp == NULL) {
offset = 0;
- else
+ } else {
offset = *offp;
- if (lnum == 0 && offset <= 0)
- return 1; /* Not a "find offset" and offset 0 _must_ be in line 1 */
+ }
+ if (lnum == 0 && offset <= 0) {
+ return 1; // Not a "find offset" and offset 0 _must_ be in line 1
+ }
/*
* Find the last chunk before the one containing our line. Last chunk is
* special because it will never qualify
@@ -4053,36 +4134,41 @@ long ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp, bool no_ff)
+ ffdos * buf->b_ml.ml_chunksize[curix].mlcs_numlines))) {
curline += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
size += buf->b_ml.ml_chunksize[curix].mlcs_totalsize;
- if (offset && ffdos)
+ if (offset && ffdos) {
size += buf->b_ml.ml_chunksize[curix].mlcs_numlines;
+ }
curix++;
}
while ((lnum != 0 && curline < lnum) || (offset != 0 && size < offset)) {
if (curline > buf->b_ml.ml_line_count
- || (hp = ml_find_line(buf, curline, ML_FIND)) == NULL)
+ || (hp = ml_find_line(buf, curline, ML_FIND)) == NULL) {
return -1;
+ }
dp = hp->bh_data;
count = (long)(buf->b_ml.ml_locked_high) -
(long)(buf->b_ml.ml_locked_low) + 1;
start_idx = idx = curline - buf->b_ml.ml_locked_low;
- if (idx == 0) /* first line in block, text at the end */
+ if (idx == 0) { // first line in block, text at the end
text_end = dp->db_txt_end;
- else
+ } else {
text_end = ((dp->db_index[idx - 1]) & DB_INDEX_MASK);
- /* Compute index of last line to use in this MEMLINE */
+ }
+ // Compute index of last line to use in this MEMLINE
if (lnum != 0) {
- if (curline + (count - idx) >= lnum)
+ if (curline + (count - idx) >= lnum) {
idx += lnum - curline - 1;
- else
+ } else {
idx = count - 1;
+ }
} else {
extra = 0;
while (offset >= size
+ text_end - (int)((dp->db_index[idx]) & DB_INDEX_MASK)
+ ffdos) {
- if (ffdos)
+ if (ffdos) {
size++;
+ }
if (idx == count - 1) {
extra = 1;
break;
@@ -4093,25 +4179,28 @@ long ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp, bool no_ff)
len = text_end - ((dp->db_index[idx]) & DB_INDEX_MASK);
size += len;
if (offset != 0 && size >= offset) {
- if (size + ffdos == offset)
+ if (size + ffdos == offset) {
*offp = 0;
- else if (idx == start_idx)
+ } else if (idx == start_idx) {
*offp = offset - size + len;
- else
+ } else {
*offp = offset - size + len
- (text_end - ((dp->db_index[idx - 1]) & DB_INDEX_MASK));
+ }
curline += idx - start_idx + extra;
- if (curline > buf->b_ml.ml_line_count)
- return -1; /* exactly one byte beyond the end */
+ if (curline > buf->b_ml.ml_line_count) {
+ return -1; // exactly one byte beyond the end
+ }
return curline;
}
curline = buf->b_ml.ml_locked_high + 1;
}
if (lnum != 0) {
- /* Count extra CR characters. */
- if (ffdos)
+ // Count extra CR characters.
+ if (ffdos) {
size += lnum - 1;
+ }
/* Don't count the last line break if 'noeol' and ('bin' or
* 'nofixeol'). */
diff --git a/src/nvim/memory.c b/src/nvim/memory.c
index 7a8fc4da75..5e6c6a8189 100644
--- a/src/nvim/memory.c
+++ b/src/nvim/memory.c
@@ -1,26 +1,26 @@
// 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
- // Various routines dealing with allocation and deallocation of memory.
+// Various routines dealing with allocation and deallocation of memory.
#include <assert.h>
#include <inttypes.h>
-#include <string.h>
#include <stdbool.h>
+#include <string.h>
-#include "nvim/vim.h"
+#include "nvim/api/vim.h"
#include "nvim/context.h"
+#include "nvim/decoration.h"
#include "nvim/eval.h"
#include "nvim/highlight.h"
+#include "nvim/lua/executor.h"
#include "nvim/memfile.h"
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
-#include "nvim/ui.h"
#include "nvim/sign.h"
-#include "nvim/api/vim.h"
-#include "nvim/lua/executor.h"
-#include "nvim/decoration.h"
+#include "nvim/ui.h"
+#include "nvim/vim.h"
#ifdef UNIT_TESTING
# define malloc(size) mem_malloc(size)
@@ -47,8 +47,9 @@ void try_to_free_memory(void)
{
static bool trying_to_free = false;
// avoid recursive calls
- if (trying_to_free)
+ if (trying_to_free) {
return;
+ }
trying_to_free = true;
// free any scrollback text
@@ -169,6 +170,8 @@ void *xrealloc(void *ptr, size_t size)
/// xmalloc() wrapper that allocates size + 1 bytes and zeroes the last byte
///
+/// Commonly used to allocate strings, e.g. `char *s = xmallocz(len)`.
+///
/// @see {xmalloc}
/// @param size
/// @return pointer to allocated space. Never NULL
@@ -182,7 +185,7 @@ void *xmallocz(size_t size)
}
void *ret = xmalloc(total_size);
- ((char*)ret)[size] = 0;
+ ((char *)ret)[size] = 0;
return ret;
}
@@ -339,16 +342,16 @@ char *xstpcpy(char *restrict dst, const char *restrict src)
char *xstpncpy(char *restrict dst, const char *restrict src, size_t maxlen)
FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
- const char *p = memchr(src, '\0', maxlen);
- if (p) {
- size_t srclen = (size_t)(p - src);
- memcpy(dst, src, srclen);
- memset(dst + srclen, 0, maxlen - srclen);
- return dst + srclen;
- } else {
- memcpy(dst, src, maxlen);
- return dst + maxlen;
- }
+ const char *p = memchr(src, '\0', maxlen);
+ if (p) {
+ size_t srclen = (size_t)(p - src);
+ memcpy(dst, src, srclen);
+ memset(dst + srclen, 0, maxlen - srclen);
+ return dst + srclen;
+ } else {
+ memcpy(dst, src, maxlen);
+ return dst + maxlen;
+ }
}
/// xstrlcpy - Copy a NUL-terminated string into a sized buffer
@@ -447,7 +450,7 @@ void *xmemrchr(const void *src, uint8_t c, size_t len)
{
while (len--) {
if (((uint8_t *)src)[len] == c) {
- return (uint8_t *) src + len;
+ return (uint8_t *)src + len;
}
}
return NULL;
@@ -500,7 +503,7 @@ bool striequal(const char *a, const char *b)
void do_outofmem_msg(size_t size)
{
if (!did_outofmem_msg) {
- /* Don't hide this message */
+ // Don't hide this message
emsg_silent = 0;
/* Must come first to avoid coming back here when printing the error
@@ -523,35 +526,35 @@ void time_to_bytes(time_t time_, uint8_t buf[8])
#if defined(EXITFREE)
-#include "nvim/file_search.h"
-#include "nvim/buffer.h"
-#include "nvim/charset.h"
-#include "nvim/diff.h"
-#include "nvim/edit.h"
-#include "nvim/ex_cmds.h"
-#include "nvim/ex_docmd.h"
-#include "nvim/ex_getln.h"
-#include "nvim/fileio.h"
-#include "nvim/fold.h"
-#include "nvim/getchar.h"
-#include "nvim/mark.h"
-#include "nvim/mbyte.h"
-#include "nvim/memline.h"
-#include "nvim/move.h"
-#include "nvim/option.h"
-#include "nvim/ops.h"
-#include "nvim/os_unix.h"
-#include "nvim/path.h"
-#include "nvim/quickfix.h"
-#include "nvim/regexp.h"
-#include "nvim/screen.h"
-#include "nvim/search.h"
-#include "nvim/spell.h"
-#include "nvim/syntax.h"
-#include "nvim/tag.h"
-#include "nvim/window.h"
-#include "nvim/os/os.h"
-#include "nvim/eval/typval.h"
+# include "nvim/buffer.h"
+# include "nvim/charset.h"
+# include "nvim/diff.h"
+# include "nvim/edit.h"
+# include "nvim/eval/typval.h"
+# include "nvim/ex_cmds.h"
+# include "nvim/ex_docmd.h"
+# include "nvim/ex_getln.h"
+# include "nvim/file_search.h"
+# include "nvim/fileio.h"
+# include "nvim/fold.h"
+# include "nvim/getchar.h"
+# include "nvim/mark.h"
+# include "nvim/mbyte.h"
+# include "nvim/memline.h"
+# include "nvim/move.h"
+# include "nvim/ops.h"
+# include "nvim/option.h"
+# include "nvim/os/os.h"
+# include "nvim/os_unix.h"
+# include "nvim/path.h"
+# include "nvim/quickfix.h"
+# include "nvim/regexp.h"
+# include "nvim/screen.h"
+# include "nvim/search.h"
+# include "nvim/spell.h"
+# include "nvim/syntax.h"
+# include "nvim/tag.h"
+# include "nvim/window.h"
/*
* Free everything that we allocated.
@@ -562,7 +565,7 @@ void time_to_bytes(time_t time_, uint8_t buf[8])
*/
void free_all_mem(void)
{
- buf_T *buf, *nextbuf;
+ buf_T *buf, *nextbuf;
// When we cause a crash here it is caught and Vim tries to exit cleanly.
// Don't try freeing everything again.
@@ -574,10 +577,11 @@ void free_all_mem(void)
// Don't want to trigger autocommands from here on.
block_autocmds();
- /* Close all tabs and windows. Reset 'equalalways' to avoid redraws. */
+ // Close all tabs and windows. Reset 'equalalways' to avoid redraws.
p_ea = false;
- if (first_tabpage->tp_next != NULL)
+ if (first_tabpage->tp_next != NULL) {
do_cmdline_cmd("tabonly!");
+ }
if (!ONE_WINDOW) {
// to keep things simple, don't perform this
@@ -586,17 +590,17 @@ void free_all_mem(void)
do_cmdline_cmd("only!");
}
- /* Free all spell info. */
+ // Free all spell info.
spell_free_all();
- /* Clear user commands (before deleting buffers). */
+ // Clear user commands (before deleting buffers).
ex_comclear(NULL);
- /* Clear menus. */
+ // Clear menus.
do_cmdline_cmd("aunmenu *");
do_cmdline_cmd("menutranslate clear");
- /* Clear mappings, abbreviations, breakpoints. */
+ // Clear mappings, abbreviations, breakpoints.
do_cmdline_cmd("lmapclear");
do_cmdline_cmd("xmapclear");
do_cmdline_cmd("mapclear");
@@ -609,7 +613,7 @@ void free_all_mem(void)
free_titles();
free_findfile();
- /* Obviously named calls. */
+ // Obviously named calls.
free_all_autocmds();
free_all_marks();
alist_clear(&global_alist);
@@ -627,25 +631,25 @@ void free_all_mem(void)
diff_clear(curtab);
clear_sb_text(true); // free any scrollback text
- /* Free some global vars. */
+ // Free some global vars.
xfree(last_cmdline);
xfree(new_last_cmdline);
set_keep_msg(NULL, 0);
- /* Clear cmdline history. */
+ // Clear cmdline history.
p_hi = 0;
init_history();
qf_free_all(NULL);
- /* Free all location lists */
+ // Free all location lists
FOR_ALL_TAB_WINDOWS(tab, win) {
qf_free_all(win);
}
- /* Close all script inputs. */
+ // Close all script inputs.
close_all_scripts();
- /* Destroy all windows. Must come before freeing buffers. */
+ // Destroy all windows. Must come before freeing buffers.
win_free_all();
// Free all option values. Must come after closing windows.
@@ -653,13 +657,13 @@ void free_all_mem(void)
free_arshape_buf();
- /* Clear registers. */
+ // Clear registers.
clear_registers();
ResetRedobuff();
ResetRedobuff();
- /* highlight info */
+ // highlight info
free_highlight();
reset_last_sourcing();
@@ -667,10 +671,12 @@ void free_all_mem(void)
free_tabpage(first_tabpage);
first_tabpage = NULL;
- /* message history */
- for (;; )
- if (delete_first_msg() == FAIL)
+ // message history
+ for (;; ) {
+ if (delete_first_msg() == FAIL) {
break;
+ }
+ }
eval_clear();
api_vim_free_all_mem();
diff --git a/src/nvim/menu.c b/src/nvim/menu.c
index 112f51fc64..2b1a250604 100644
--- a/src/nvim/menu.c
+++ b/src/nvim/menu.c
@@ -10,27 +10,27 @@
#include <inttypes.h>
#include <string.h>
-#include "nvim/vim.h"
#include "nvim/ascii.h"
-#include "nvim/menu.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
#include "nvim/eval.h"
+#include "nvim/eval/typval.h"
#include "nvim/ex_docmd.h"
+#include "nvim/garray.h"
#include "nvim/getchar.h"
+#include "nvim/keymap.h"
#include "nvim/memory.h"
+#include "nvim/menu.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
-#include "nvim/keymap.h"
-#include "nvim/garray.h"
+#include "nvim/screen.h"
#include "nvim/state.h"
#include "nvim/strings.h"
#include "nvim/ui.h"
-#include "nvim/eval/typval.h"
-#include "nvim/screen.h"
+#include "nvim/vim.h"
#include "nvim/window.h"
-#define MENUDEPTH 10 /* maximum depth of menus */
+#define MENUDEPTH 10 // maximum depth of menus
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -43,8 +43,7 @@
/// The character for each menu mode
static char_u menu_mode_chars[] = { 'n', 'v', 's', 'o', 'i', 'c', 't' };
-static char_u e_notsubmenu[] = N_(
- "E327: Part of menu-item path is not sub-menu");
+static char_u e_notsubmenu[] = N_("E327: Part of menu-item path is not sub-menu");
static char_u e_othermode[] = N_("E328: Menu only exists in another mode");
static char_u e_nomenu[] = N_("E329: No menu \"%s\"");
@@ -63,18 +62,17 @@ static vimmenu_T **get_root_menu(const char_u *const name)
/// Do the :menu command and relatives.
/// @param eap Ex command arguments
-void
-ex_menu(exarg_T *eap)
+void ex_menu(exarg_T *eap)
{
- char_u *menu_path;
+ char_u *menu_path;
int modes;
- char_u *map_to; // command mapped to the menu entry
+ char_u *map_to; // command mapped to the menu entry
int noremap;
bool silent = false;
int unmenu;
- char_u *map_buf;
- char_u *arg;
- char_u *p;
+ char_u *map_buf;
+ char_u *arg;
+ char_u *p;
int i;
long pri_tab[MENUDEPTH + 1];
TriState enable = kNone; // kTrue for "menu enable",
@@ -109,8 +107,9 @@ ex_menu(exarg_T *eap)
if (STRNCMP(arg, "icon=", 5) == 0) {
arg += 5;
while (*arg != NUL && *arg != ' ') {
- if (*arg == '\\')
+ if (*arg == '\\') {
STRMOVE(arg, arg + 1);
+ }
MB_PTR_ADV(arg);
}
if (*arg != NUL) {
@@ -139,11 +138,13 @@ ex_menu(exarg_T *eap)
} else if (eap->addr_count && eap->line2 != 0) {
pri_tab[0] = eap->line2;
i = 1;
- } else
+ } else {
i = 0;
- while (i < MENUDEPTH)
+ }
+ while (i < MENUDEPTH) {
pri_tab[i++] = 500;
- pri_tab[MENUDEPTH] = -1; /* mark end of the table */
+ }
+ pri_tab[MENUDEPTH] = -1; // mark end of the table
/*
* Check for "disable" or "enable" argument.
@@ -195,31 +196,34 @@ ex_menu(exarg_T *eap)
}
if (menu_is_popup(menu_path)) {
- for (i = 0; i < MENU_INDEX_TIP; ++i)
+ for (i = 0; i < MENU_INDEX_TIP; ++i) {
if (modes & (1 << i)) {
p = popup_mode_name(menu_path, i);
menu_enable_recurse(*root_menu_ptr, p, MENU_ALL_MODES, enable);
xfree(p);
}
+ }
}
menu_enable_recurse(*root_menu_ptr, menu_path, modes, enable);
} else if (unmenu) {
/*
* Delete menu(s).
*/
- if (STRCMP(menu_path, "*") == 0) /* meaning: remove all menus */
+ if (STRCMP(menu_path, "*") == 0) { // meaning: remove all menus
menu_path = (char_u *)"";
+ }
/*
* For the PopUp menu, remove a menu for each mode separately.
*/
if (menu_is_popup(menu_path)) {
- for (i = 0; i < MENU_INDEX_TIP; ++i)
+ for (i = 0; i < MENU_INDEX_TIP; ++i) {
if (modes & (1 << i)) {
p = popup_mode_name(menu_path, i);
remove_menu(root_menu_ptr, p, MENU_ALL_MODES, true);
xfree(p);
}
+ }
}
// Careful: remove_menu() changes menu_path
@@ -229,7 +233,7 @@ ex_menu(exarg_T *eap)
* Add menu(s).
* Replace special key codes.
*/
- if (STRICMP(map_to, "<nop>") == 0) { /* "<Nop>" means nothing */
+ if (STRICMP(map_to, "<nop>") == 0) { // "<Nop>" means nothing
map_to = (char_u *)"";
map_buf = NULL;
} else if (modes & MENU_TIP_MODE) {
@@ -247,7 +251,7 @@ ex_menu(exarg_T *eap)
* For the PopUp menu, add a menu for each mode separately.
*/
if (menu_is_popup(menu_path)) {
- for (i = 0; i < MENU_INDEX_TIP; ++i)
+ for (i = 0; i < MENU_INDEX_TIP; ++i) {
if (modes & (1 << i)) {
p = popup_mode_name(menu_path, i);
// Include all modes, to make ":amenu" work
@@ -255,6 +259,7 @@ ex_menu(exarg_T *eap)
add_menu_path(p, &menuarg, pri_tab, map_to);
xfree(p);
}
+ }
}
xfree(map_buf);
@@ -272,33 +277,28 @@ theend:
/// @param[out] menuarg menu entry
/// @param[] pri_tab priority table
/// @param[in] call_data Right hand side command
-static int
-add_menu_path(
- const char_u *const menu_path,
- vimmenu_T *menuarg,
- const long *const pri_tab,
- const char_u *const call_data
-)
+static int add_menu_path(const char_u *const menu_path, vimmenu_T *menuarg,
+ const long *const pri_tab, const char_u *const call_data)
{
- char_u *path_name;
+ char_u *path_name;
int modes = menuarg->modes;
- vimmenu_T *menu = NULL;
- vimmenu_T *parent;
- vimmenu_T **lower_pri;
- char_u *p;
- char_u *name;
- char_u *dname;
- char_u *next_name;
+ vimmenu_T *menu = NULL;
+ vimmenu_T *parent;
+ vimmenu_T **lower_pri;
+ char_u *p;
+ char_u *name;
+ char_u *dname;
+ char_u *next_name;
char_u c;
char_u d;
int i;
int pri_idx = 0;
int old_modes = 0;
int amenu;
- char_u *en_name;
- char_u *map_to = NULL;
+ char_u *en_name;
+ char_u *map_to = NULL;
- /* Make a copy so we can stuff around with it, since it could be const */
+ // Make a copy so we can stuff around with it, since it could be const
path_name = vim_strsave(menu_path);
vimmenu_T **root_menu_ptr = get_root_menu(menu_path);
vimmenu_T **menup = root_menu_ptr;
@@ -317,12 +317,12 @@ add_menu_path(
}
dname = menu_text(name, NULL, NULL);
if (*dname == NUL) {
- /* Only a mnemonic or accelerator is not valid. */
+ // Only a mnemonic or accelerator is not valid.
EMSG(_("E792: Empty menu name"));
goto erret;
}
- /* See if it's already there */
+ // See if it's already there
lower_pri = menup;
menu = *menup;
while (menu != NULL) {
@@ -364,7 +364,7 @@ add_menu_path(
goto erret;
}
- /* Not already there, so lets add it */
+ // Not already there, so lets add it
menu = xcalloc(1, sizeof(vimmenu_T));
menu->modes = modes;
@@ -387,7 +387,6 @@ add_menu_path(
*lower_pri = menu;
old_modes = 0;
-
} else {
old_modes = menu->modes;
@@ -419,16 +418,17 @@ add_menu_path(
*/
amenu = ((modes & (MENU_NORMAL_MODE | MENU_INSERT_MODE)) ==
(MENU_NORMAL_MODE | MENU_INSERT_MODE));
- if (sys_menu)
+ if (sys_menu) {
modes &= ~old_modes;
+ }
if (menu != NULL && modes) {
p = (call_data == NULL) ? NULL : vim_strsave(call_data);
- /* loop over all modes, may add more than one */
+ // loop over all modes, may add more than one
for (i = 0; i < MENU_MODES; ++i) {
if (modes & (1 << i)) {
- /* free any old menu */
+ // free any old menu
free_menu_string(menu, i);
// For "amenu", may insert an extra character.
@@ -462,7 +462,7 @@ add_menu_path(
if (c == Ctrl_C) {
int len = (int)STRLEN(menu->strings[i]);
- /* Append CTRL-\ CTRL-G to obey 'insertmode'. */
+ // Append CTRL-\ CTRL-G to obey 'insertmode'.
menu->strings[i][len] = Ctrl_BSL;
menu->strings[i][len + 1] = Ctrl_G;
menu->strings[i][len + 2] = NUL;
@@ -504,20 +504,17 @@ erret:
* Set the (sub)menu with the given name to enabled or disabled.
* Called recursively.
*/
-static int menu_enable_recurse(vimmenu_T *menu,
- char_u *name,
- int modes,
- int enable)
+static int menu_enable_recurse(vimmenu_T *menu, char_u *name, int modes, int enable)
{
- char_u *p;
-
- if (menu == NULL)
- return OK; /* Got to bottom of hierarchy */
+ char_u *p;
- /* Get name of this element in the menu hierarchy */
+ if (menu == NULL) {
+ return OK; // Got to bottom of hierarchy
+ }
+ // Get name of this element in the menu hierarchy
p = menu_name_skip(name);
- /* Find the menu */
+ // Find the menu
while (menu != NULL) {
if (*name == NUL || *name == '*' || menu_name_equal(name, menu)) {
if (*p != NUL) {
@@ -539,8 +536,9 @@ static int menu_enable_recurse(vimmenu_T *menu,
* modes, so keep looping, otherwise we are just doing the named
* menu item (which has been found) so break here.
*/
- if (*name != NUL && *name != '*')
+ if (*name != NUL && *name != '*') {
break;
+ }
}
menu = menu->next;
}
@@ -553,42 +551,39 @@ static int menu_enable_recurse(vimmenu_T *menu,
return OK;
}
-/*
- * Remove the (sub)menu with the given name from the menu hierarchy
- * Called recursively.
- */
-static int
-remove_menu (
- vimmenu_T **menup,
- char_u *name,
- int modes,
- bool silent /* don't give error messages */
-)
+/// Remove the (sub)menu with the given name from the menu hierarchy
+/// Called recursively.
+///
+/// @param silent don't give error messages
+static int remove_menu(vimmenu_T **menup, char_u *name, int modes, bool silent)
{
- vimmenu_T *menu;
- vimmenu_T *child;
- char_u *p;
-
- if (*menup == NULL)
- return OK; /* Got to bottom of hierarchy */
+ vimmenu_T *menu;
+ vimmenu_T *child;
+ char_u *p;
- /* Get name of this element in the menu hierarchy */
+ if (*menup == NULL) {
+ return OK; // Got to bottom of hierarchy
+ }
+ // Get name of this element in the menu hierarchy
p = menu_name_skip(name);
- /* Find the menu */
+ // Find the menu
while ((menu = *menup) != NULL) {
if (*name == NUL || menu_name_equal(name, menu)) {
if (*p != NUL && menu->children == NULL) {
- if (!silent)
+ if (!silent) {
EMSG(_(e_notsubmenu));
+ }
return FAIL;
}
if ((menu->modes & modes) != 0x0) {
- if (remove_menu(&menu->children, p, modes, silent) == FAIL)
+ if (remove_menu(&menu->children, p, modes, silent) == FAIL) {
return FAIL;
+ }
} else if (*name != NUL) {
- if (!silent)
+ if (!silent) {
EMSG(_(e_othermode));
+ }
return FAIL;
}
@@ -597,39 +592,45 @@ remove_menu (
* modes, so keep looping, otherwise we are just removing the named
* menu item (which has been found) so break here.
*/
- if (*name != NUL)
+ if (*name != NUL) {
break;
+ }
/* Remove the menu item for the given mode[s]. If the menu item
* is no longer valid in ANY mode, delete it */
menu->modes &= ~modes;
- if (modes & MENU_TIP_MODE)
+ if (modes & MENU_TIP_MODE) {
free_menu_string(menu, MENU_INDEX_TIP);
- if ((menu->modes & MENU_ALL_MODES) == 0)
+ }
+ if ((menu->modes & MENU_ALL_MODES) == 0) {
free_menu(menup);
- else
+ } else {
menup = &menu->next;
- } else
+ }
+ } else {
menup = &menu->next;
+ }
}
if (*name != NUL) {
if (menu == NULL) {
- if (!silent)
+ if (!silent) {
EMSG2(_(e_nomenu), name);
+ }
return FAIL;
}
- /* Recalculate modes for menu based on the new updated children */
+ // Recalculate modes for menu based on the new updated children
menu->modes &= ~modes;
child = menu->children;
- for (; child != NULL; child = child->next)
+ for (; child != NULL; child = child->next) {
menu->modes |= child->modes;
+ }
if (modes & MENU_TIP_MODE) {
free_menu_string(menu, MENU_INDEX_TIP);
}
if ((menu->modes & MENU_ALL_MODES) == 0) {
- /* The menu item is no longer valid in ANY mode, so delete it */
+ // The menu item is no longer valid in ANY mode, so delete it
*menup = menu;
free_menu(menup);
}
@@ -644,7 +645,7 @@ remove_menu (
static void free_menu(vimmenu_T **menup)
{
int i;
- vimmenu_T *menu;
+ vimmenu_T *menu;
menu = *menup;
@@ -657,10 +658,10 @@ static void free_menu(vimmenu_T **menup)
xfree(menu->en_name);
xfree(menu->en_dname);
xfree(menu->actext);
- for (i = 0; i < MENU_MODES; i++)
+ for (i = 0; i < MENU_MODES; i++) {
free_menu_string(menu, i);
+ }
xfree(menu);
-
}
/*
@@ -671,11 +672,14 @@ static void free_menu_string(vimmenu_T *menu, int idx)
int count = 0;
int i;
- for (i = 0; i < MENU_MODES; i++)
- if (menu->strings[i] == menu->strings[idx])
+ for (i = 0; i < MENU_MODES; i++) {
+ if (menu->strings[i] == menu->strings[idx]) {
count++;
- if (count == 1)
+ }
+ }
+ if (count == 1) {
xfree(menu->strings[idx]);
+ }
menu->strings[idx] = NULL;
}
@@ -793,8 +797,8 @@ static vimmenu_T *find_menu(vimmenu_T *menu, char_u *name, int modes)
if (menu_name_equal(name, menu)) {
// Found menu
if (*p != NUL && menu->children == NULL) {
- EMSG(_(e_notsubmenu));
- return NULL;
+ EMSG(_(e_notsubmenu));
+ return NULL;
} else if ((menu->modes & modes) == 0x0) {
EMSG(_(e_othermode));
return NULL;
@@ -826,8 +830,8 @@ static int show_menus(char_u *const path_name, int modes)
return FAIL;
}
- /* Now we have found the matching menu, and we list the mappings */
- /* Highlight title */
+ // Now we have found the matching menu, and we list the mappings
+ // Highlight title
MSG_PUTS_TITLE(_("\n--- Menus ---"));
show_menus_recursive(menu->parent, modes, 0);
@@ -840,15 +844,18 @@ static void show_menus_recursive(vimmenu_T *menu, int modes, int depth)
int i;
int bit;
- if (menu != NULL && (menu->modes & modes) == 0x0)
+ if (menu != NULL && (menu->modes & modes) == 0x0) {
return;
+ }
if (menu != NULL) {
msg_putchar('\n');
- if (got_int) /* "q" hit for "--more--" */
+ if (got_int) { // "q" hit for "--more--"
return;
- for (i = 0; i < depth; i++)
+ }
+ for (i = 0; i < depth; i++) {
MSG_PUTS(" ");
+ }
if (menu->priority) {
msg_outnum((long)menu->priority);
MSG_PUTS(" ");
@@ -858,28 +865,33 @@ static void show_menus_recursive(vimmenu_T *menu, int modes, int depth)
}
if (menu != NULL && menu->children == NULL) {
- for (bit = 0; bit < MENU_MODES; bit++)
+ for (bit = 0; bit < MENU_MODES; bit++) {
if ((menu->modes & modes & (1 << bit)) != 0) {
msg_putchar('\n');
- if (got_int) /* "q" hit for "--more--" */
+ if (got_int) { // "q" hit for "--more--"
return;
- for (i = 0; i < depth + 2; i++)
+ }
+ for (i = 0; i < depth + 2; i++) {
MSG_PUTS(" ");
+ }
msg_putchar(menu_mode_chars[bit]);
- if (menu->noremap[bit] == REMAP_NONE)
+ if (menu->noremap[bit] == REMAP_NONE) {
msg_putchar('*');
- else if (menu->noremap[bit] == REMAP_SCRIPT)
+ } else if (menu->noremap[bit] == REMAP_SCRIPT) {
msg_putchar('&');
- else
+ } else {
msg_putchar(' ');
- if (menu->silent[bit])
+ }
+ if (menu->silent[bit]) {
msg_putchar('s');
- else
+ } else {
msg_putchar(' ');
- if ((menu->modes & menu->enabled & (1 << bit)) == 0)
+ }
+ if ((menu->modes & menu->enabled & (1 << bit)) == 0) {
msg_putchar('-');
- else
+ } else {
msg_putchar(' ');
+ }
MSG_PUTS(" ");
if (*menu->strings[bit] == NUL) {
msg_puts_attr("<Nop>", HL_ATTR(HLF_8));
@@ -887,17 +899,21 @@ static void show_menus_recursive(vimmenu_T *menu, int modes, int depth)
msg_outtrans_special(menu->strings[bit], false, 0);
}
}
+ }
} else {
if (menu == NULL) {
menu = root_menu;
depth--;
- } else
+ } else {
menu = menu->children;
+ }
- /* recursively show all children. Skip PopUp[nvoci]. */
- for (; menu != NULL && !got_int; menu = menu->next)
- if (!menu_is_hidden(menu->dname))
+ // recursively show all children. Skip PopUp[nvoci].
+ for (; menu != NULL && !got_int; menu = menu->next) {
+ if (!menu_is_hidden(menu->dname)) {
show_menus_recursive(menu, modes, depth + 1);
+ }
+ }
}
}
@@ -905,57 +921,61 @@ static void show_menus_recursive(vimmenu_T *menu, int modes, int depth)
/*
* Used when expanding menu names.
*/
-static vimmenu_T *expand_menu = NULL;
+static vimmenu_T *expand_menu = NULL;
static int expand_modes = 0x0;
-static int expand_emenu; /* TRUE for ":emenu" command */
+static int expand_emenu; // TRUE for ":emenu" command
/*
* Work out what to complete when doing command line completion of menu names.
*/
-char_u *set_context_in_menu_cmd(expand_T *xp, const char *cmd, char_u *arg,
- bool forceit)
+char_u *set_context_in_menu_cmd(expand_T *xp, const char *cmd, char_u *arg, bool forceit)
FUNC_ATTR_NONNULL_ALL
{
- char_u *after_dot;
- char_u *p;
- char_u *path_name = NULL;
- char_u *name;
+ char_u *after_dot;
+ char_u *p;
+ char_u *path_name = NULL;
+ char_u *name;
int unmenu;
- vimmenu_T *menu;
+ vimmenu_T *menu;
int expand_menus;
xp->xp_context = EXPAND_UNSUCCESSFUL;
- /* Check for priority numbers, enable and disable */
- for (p = arg; *p; ++p)
- if (!ascii_isdigit(*p) && *p != '.')
+ // Check for priority numbers, enable and disable
+ for (p = arg; *p; ++p) {
+ if (!ascii_isdigit(*p) && *p != '.') {
break;
+ }
+ }
if (!ascii_iswhite(*p)) {
if (STRNCMP(arg, "enable", 6) == 0
- && (arg[6] == NUL || ascii_iswhite(arg[6])))
+ && (arg[6] == NUL || ascii_iswhite(arg[6]))) {
p = arg + 6;
- else if (STRNCMP(arg, "disable", 7) == 0
- && (arg[7] == NUL || ascii_iswhite(arg[7])))
+ } else if (STRNCMP(arg, "disable", 7) == 0
+ && (arg[7] == NUL || ascii_iswhite(arg[7]))) {
p = arg + 7;
- else
+ } else {
p = arg;
+ }
}
- while (*p != NUL && ascii_iswhite(*p))
+ while (*p != NUL && ascii_iswhite(*p)) {
++p;
+ }
arg = after_dot = p;
for (; *p && !ascii_iswhite(*p); ++p) {
- if ((*p == '\\' || *p == Ctrl_V) && p[1] != NUL)
+ if ((*p == '\\' || *p == Ctrl_V) && p[1] != NUL) {
p++;
- else if (*p == '.')
+ } else if (*p == '.') {
after_dot = p + 1;
+ }
}
- // ":popup" only uses menues, not entries
+ // ":popup" only uses menus, not entries
expand_menus = !((*cmd == 't' && cmd[1] == 'e') || *cmd == 'p');
expand_emenu = (*cmd == 'e');
if (expand_menus && ascii_iswhite(*p)) {
@@ -966,12 +986,13 @@ char_u *set_context_in_menu_cmd(expand_T *xp, const char *cmd, char_u *arg,
// With :menu though you might want to add a menu with the same name as
// one in another mode, so match menus from other modes too.
expand_modes = get_menu_cmd_modes(cmd, forceit, NULL, &unmenu);
- if (!unmenu)
+ if (!unmenu) {
expand_modes = MENU_ALL_MODES;
+ }
menu = root_menu;
if (after_dot > arg) {
- size_t path_len = (size_t) (after_dot - arg);
+ size_t path_len = (size_t)(after_dot - arg);
path_name = xmalloc(path_len);
STRLCPY(path_name, arg, path_len);
}
@@ -980,7 +1001,7 @@ char_u *set_context_in_menu_cmd(expand_T *xp, const char *cmd, char_u *arg,
p = menu_name_skip(name);
while (menu != NULL) {
if (menu_name_equal(name, menu)) {
- /* Found menu */
+ // Found menu
if ((*p != NUL && menu->children == NULL)
|| ((menu->modes & expand_modes) == 0x0)) {
/*
@@ -995,7 +1016,7 @@ char_u *set_context_in_menu_cmd(expand_T *xp, const char *cmd, char_u *arg,
menu = menu->next;
}
if (menu == NULL) {
- /* No menu found with the name we were looking for */
+ // No menu found with the name we were looking for
xfree(path_name);
return NULL;
}
@@ -1019,35 +1040,38 @@ char_u *set_context_in_menu_cmd(expand_T *xp, const char *cmd, char_u *arg,
*/
char_u *get_menu_name(expand_T *xp, int idx)
{
- static vimmenu_T *menu = NULL;
- char_u *str;
+ static vimmenu_T *menu = NULL;
+ char_u *str;
static int should_advance = FALSE;
- if (idx == 0) { /* first call: start at first item */
+ if (idx == 0) { // first call: start at first item
menu = expand_menu;
should_advance = false;
}
- /* Skip PopUp[nvoci]. */
+ // Skip PopUp[nvoci].
while (menu != NULL && (menu_is_hidden(menu->dname)
|| menu_is_separator(menu->dname)
|| menu->children == NULL)) {
menu = menu->next;
}
- if (menu == NULL) /* at end of linked list */
+ if (menu == NULL) { // at end of linked list
return NULL;
+ }
- if (menu->modes & expand_modes)
- if (should_advance)
+ if (menu->modes & expand_modes) {
+ if (should_advance) {
str = menu->en_dname;
- else {
+ } else {
str = menu->dname;
- if (menu->en_dname == NULL)
+ if (menu->en_dname == NULL) {
should_advance = TRUE;
+ }
}
- else
+ } else {
str = (char_u *)"";
+ }
if (should_advance) {
// Advance to next menu entry.
@@ -1065,18 +1089,18 @@ char_u *get_menu_name(expand_T *xp, int idx)
*/
char_u *get_menu_names(expand_T *xp, int idx)
{
- static vimmenu_T *menu = NULL;
+ static vimmenu_T *menu = NULL;
#define TBUFFER_LEN 256
- static char_u tbuffer[TBUFFER_LEN]; /*hack*/
- char_u *str;
+ static char_u tbuffer[TBUFFER_LEN]; //hack
+ char_u *str;
static bool should_advance = false;
- if (idx == 0) { /* first call: start at first item */
+ if (idx == 0) { // first call: start at first item
menu = expand_menu;
should_advance = false;
}
- /* Skip Browse-style entries, popup menus and separators. */
+ // Skip Browse-style entries, popup menus and separators.
while (menu != NULL
&& (menu_is_hidden(menu->dname)
|| (expand_emenu && menu_is_separator(menu->dname))
@@ -1084,8 +1108,9 @@ char_u *get_menu_names(expand_T *xp, int idx)
menu = menu->next;
}
- if (menu == NULL) /* at end of linked list */
+ if (menu == NULL) { // at end of linked list
return NULL;
+ }
if (menu->modes & expand_modes) {
if (menu->children != NULL) {
@@ -1102,17 +1127,18 @@ char_u *get_menu_names(expand_T *xp, int idx)
STRCAT(tbuffer, "\001");
str = tbuffer;
} else {
- if (should_advance)
+ if (should_advance) {
str = menu->en_dname;
- else {
+ } else {
str = menu->dname;
if (menu->en_dname == NULL) {
should_advance = true;
}
}
}
- } else
+ } else {
str = (char_u *)"";
+ }
if (should_advance) {
// Advance to next menu entry.
@@ -1132,17 +1158,19 @@ char_u *get_menu_names(expand_T *xp, int idx)
/// @return start of the next element
char_u *menu_name_skip(char_u *const name)
{
- char_u *p;
+ char_u *p;
for (p = name; *p && *p != '.'; MB_PTR_ADV(p)) {
if (*p == '\\' || *p == Ctrl_V) {
STRMOVE(p, p + 1);
- if (*p == NUL)
+ if (*p == NUL) {
break;
+ }
}
}
- if (*p)
+ if (*p) {
*p++ = NUL;
+ }
return p;
}
@@ -1154,8 +1182,9 @@ static bool menu_name_equal(const char_u *const name, vimmenu_T *const menu)
{
if (menu->en_name != NULL
&& (menu_namecmp(name, menu->en_name)
- || menu_namecmp(name, menu->en_dname)))
+ || menu_namecmp(name, menu->en_dname))) {
return true;
+ }
return menu_namecmp(name, menu->name) || menu_namecmp(name, menu->dname);
}
@@ -1163,9 +1192,11 @@ static bool menu_namecmp(const char_u *const name, const char_u *const mname)
{
int i;
- for (i = 0; name[i] != NUL && name[i] != TAB; ++i)
- if (name[i] != mname[i])
+ for (i = 0; name[i] != NUL && name[i] != TAB; ++i) {
+ if (name[i] != mname[i]) {
break;
+ }
+ }
return (name[i] == NUL || name[i] == TAB)
&& (mname[i] == NUL || mname[i] == TAB);
}
@@ -1180,45 +1211,39 @@ static bool menu_namecmp(const char_u *const name, const char_u *const mname)
/// to whether the command is a "nore" command.
/// @param[out] unmenu If not NULL, the flag it points to is set according
/// to whether the command is an "unmenu" command.
-int
-get_menu_cmd_modes(
- const char *cmd,
- bool forceit,
- int *noremap,
- int *unmenu
-)
+int get_menu_cmd_modes(const char *cmd, bool forceit, int *noremap, int *unmenu)
{
int modes;
switch (*cmd++) {
- case 'v': /* vmenu, vunmenu, vnoremenu */
+ case 'v': // vmenu, vunmenu, vnoremenu
modes = MENU_VISUAL_MODE | MENU_SELECT_MODE;
break;
- case 'x': /* xmenu, xunmenu, xnoremenu */
+ case 'x': // xmenu, xunmenu, xnoremenu
modes = MENU_VISUAL_MODE;
break;
- case 's': /* smenu, sunmenu, snoremenu */
+ case 's': // smenu, sunmenu, snoremenu
modes = MENU_SELECT_MODE;
break;
- case 'o': /* omenu */
+ case 'o': // omenu
modes = MENU_OP_PENDING_MODE;
break;
- case 'i': /* imenu */
+ case 'i': // imenu
modes = MENU_INSERT_MODE;
break;
case 't':
- modes = MENU_TIP_MODE; /* tmenu */
+ modes = MENU_TIP_MODE; // tmenu
break;
- case 'c': /* cmenu */
+ case 'c': // cmenu
modes = MENU_CMDLINE_MODE;
break;
- case 'a': /* amenu */
+ case 'a': // amenu
modes = MENU_INSERT_MODE | MENU_CMDLINE_MODE | MENU_NORMAL_MODE
| MENU_VISUAL_MODE | MENU_SELECT_MODE
| MENU_OP_PENDING_MODE;
break;
case 'n':
- if (*cmd != 'o') { /* nmenu, not noremenu */
+ if (*cmd != 'o') { // nmenu, not noremenu
modes = MENU_NORMAL_MODE;
break;
}
@@ -1235,10 +1260,12 @@ get_menu_cmd_modes(
}
}
- if (noremap != NULL)
+ if (noremap != NULL) {
*noremap = (*cmd == 'n' ? REMAP_NONE : REMAP_YES);
- if (unmenu != NULL)
+ }
+ if (unmenu != NULL) {
*unmenu = (*cmd == 'u');
+ }
return modes;
}
@@ -1274,27 +1301,31 @@ static char_u *menu_text(const char_u *str, int *mnemonic, char_u **actext)
FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT
FUNC_ATTR_NONNULL_ARG(1)
{
- char_u *p;
- char_u *text;
+ char_u *p;
+ char_u *text;
- /* Locate accelerator text, after the first TAB */
+ // Locate accelerator text, after the first TAB
p = vim_strchr(str, TAB);
if (p != NULL) {
- if (actext != NULL)
+ if (actext != NULL) {
*actext = vim_strsave(p + 1);
+ }
assert(p >= str);
text = vim_strnsave(str, (size_t)(p - str));
- } else
+ } else {
text = vim_strsave(str);
+ }
- /* Find mnemonic characters "&a" and reduce "&&" to "&". */
+ // Find mnemonic characters "&a" and reduce "&&" to "&".
for (p = text; p != NULL; ) {
p = vim_strchr(p, '&');
if (p != NULL) {
- if (p[1] == NUL) /* trailing "&" */
+ if (p[1] == NUL) { // trailing "&"
break;
- if (mnemonic != NULL && p[1] != '&')
+ }
+ if (mnemonic != NULL && p[1] != '&') {
*mnemonic = p[1];
+ }
STRMOVE(p, p + 1);
p = p + 1;
}
@@ -1343,7 +1374,7 @@ int menu_is_separator(char_u *name)
static int menu_is_hidden(char_u *name)
{
return (name[0] == MNU_HIDDEN_CHAR)
- || (menu_is_popup(name) && name[5] != NUL);
+ || (menu_is_popup(name) && name[5] != NUL);
}
// Execute "menu". Use by ":emenu" and the window toolbar.
@@ -1359,8 +1390,8 @@ static void execute_menu(const exarg_T *eap, vimmenu_T *menu)
mode = (char_u *)"Insert";
idx = MENU_INDEX_INSERT;
} else if (State & CMDLINE) {
- mode = (char_u *)"Command";
- idx = MENU_INDEX_CMDLINE;
+ mode = (char_u *)"Command";
+ idx = MENU_INDEX_CMDLINE;
} else if (get_real_state() & VISUAL) {
/* Detect real visual mode -- if we are really in visual mode we
* don't need to do any guesswork to figure out what the selection
@@ -1379,13 +1410,13 @@ static void execute_menu(const exarg_T *eap, vimmenu_T *menu)
* select start and end. */
if ((curbuf->b_visual.vi_start.lnum == eap->line1)
&& (curbuf->b_visual.vi_end.lnum) == eap->line2) {
- /* Set it up for visual mode - equivalent to gv. */
+ // Set it up for visual mode - equivalent to gv.
VIsual_mode = curbuf->b_visual.vi_mode;
tpos = curbuf->b_visual.vi_end;
curwin->w_cursor = curbuf->b_visual.vi_start;
curwin->w_curswant = curbuf->b_visual.vi_curswant;
} else {
- /* Set it up for line-wise visual mode */
+ // Set it up for line-wise visual mode
VIsual_mode = 'V';
curwin->w_cursor.lnum = eap->line1;
curwin->w_cursor.col = 1;
@@ -1394,7 +1425,7 @@ static void execute_menu(const exarg_T *eap, vimmenu_T *menu)
tpos.coladd = 0;
}
- /* Activate visual mode */
+ // Activate visual mode
VIsual_active = TRUE;
VIsual_reselect = TRUE;
check_cursor();
@@ -1484,15 +1515,15 @@ void ex_emenu(exarg_T *eap)
*/
typedef struct {
- char_u *from; /* English name */
- char_u *from_noamp; /* same, without '&' */
- char_u *to; /* translated name */
+ char_u *from; // English name
+ char_u *from_noamp; // same, without '&'
+ char_u *to; // translated name
} menutrans_T;
static garray_T menutrans_ga = GA_EMPTY_INIT_VALUE;
#define FREE_MENUTRANS(mt) \
- menutrans_T* _mt = (mt); \
+ menutrans_T * _mt = (mt); \
xfree(_mt->from); \
xfree(_mt->from_noamp); \
xfree(_mt->to)
@@ -1504,11 +1535,12 @@ static garray_T menutrans_ga = GA_EMPTY_INIT_VALUE;
*/
void ex_menutranslate(exarg_T *eap)
{
- char_u *arg = eap->arg;
- char_u *from, *from_noamp, *to;
+ char_u *arg = eap->arg;
+ char_u *from, *from_noamp, *to;
- if (menutrans_ga.ga_itemsize == 0)
+ if (menutrans_ga.ga_itemsize == 0) {
ga_init(&menutrans_ga, (int)sizeof(menutrans_T), 5);
+ }
/*
* ":menutrans clear": clear all translations.
@@ -1516,18 +1548,18 @@ void ex_menutranslate(exarg_T *eap)
if (STRNCMP(arg, "clear", 5) == 0 && ends_excmd(*skipwhite(arg + 5))) {
GA_DEEP_CLEAR(&menutrans_ga, menutrans_T, FREE_MENUTRANS);
- /* Delete all "menutrans_" global variables. */
+ // Delete all "menutrans_" global variables.
del_menutrans_vars();
} else {
- /* ":menutrans from to": add translation */
+ // ":menutrans from to": add translation
from = arg;
arg = menu_skip_part(arg);
to = skipwhite(arg);
*arg = NUL;
arg = menu_skip_part(to);
- if (arg == to)
+ if (arg == to) {
EMSG(_(e_invarg));
- else {
+ } else {
from = vim_strsave(from);
from_noamp = menu_text(from, NULL, NULL);
assert(arg >= to);
@@ -1536,7 +1568,7 @@ void ex_menutranslate(exarg_T *eap)
menu_translate_tab_and_shift(to);
menu_unescape_name(from);
menu_unescape_name(to);
- menutrans_T* tp = GA_APPEND_VIA_PTR(menutrans_T, &menutrans_ga);
+ menutrans_T * tp = GA_APPEND_VIA_PTR(menutrans_T, &menutrans_ga);
tp->from = from;
tp->from_noamp = from_noamp;
tp->to = to;
@@ -1550,8 +1582,9 @@ void ex_menutranslate(exarg_T *eap)
static char_u *menu_skip_part(char_u *p)
{
while (*p != NUL && *p != '.' && !ascii_iswhite(*p)) {
- if ((*p == '\\' || *p == Ctrl_V) && p[1] != NUL)
+ if ((*p == '\\' || *p == Ctrl_V) && p[1] != NUL) {
++p;
+ }
++p;
}
return p;
@@ -1563,8 +1596,8 @@ static char_u *menu_skip_part(char_u *p)
*/
static char_u *menutrans_lookup(char_u *name, int len)
{
- menutrans_T *tp = (menutrans_T *)menutrans_ga.ga_data;
- char_u *dname;
+ menutrans_T *tp = (menutrans_T *)menutrans_ga.ga_data;
+ char_u *dname;
for (int i = 0; i < menutrans_ga.ga_len; i++) {
if (STRNICMP(name, tp[i].from, len) == 0 && tp[i].from[len] == NUL) {
@@ -1572,7 +1605,7 @@ static char_u *menutrans_lookup(char_u *name, int len)
}
}
- /* Now try again while ignoring '&' characters. */
+ // Now try again while ignoring '&' characters.
char_u c = name[len];
name[len] = NUL;
dname = menu_text(name, NULL, NULL);
@@ -1593,7 +1626,7 @@ static char_u *menutrans_lookup(char_u *name, int len)
*/
static void menu_unescape_name(char_u *name)
{
- char_u *p;
+ char_u *p;
for (p = name; *p && *p != '.'; MB_PTR_ADV(p)) {
if (*p == '\\') {
@@ -1608,19 +1641,20 @@ static void menu_unescape_name(char_u *name)
*/
static char_u *menu_translate_tab_and_shift(char_u *arg_start)
{
- char_u *arg = arg_start;
+ char_u *arg = arg_start;
while (*arg && !ascii_iswhite(*arg)) {
- if ((*arg == '\\' || *arg == Ctrl_V) && arg[1] != NUL)
+ if ((*arg == '\\' || *arg == Ctrl_V) && arg[1] != NUL) {
arg++;
- else if (STRNICMP(arg, "<TAB>", 5) == 0) {
+ } else if (STRNICMP(arg, "<TAB>", 5) == 0) {
*arg = TAB;
STRMOVE(arg + 1, arg + 5);
}
arg++;
}
- if (*arg != NUL)
+ if (*arg != NUL) {
*arg++ = NUL;
+ }
arg = skipwhite(arg);
return arg;
diff --git a/src/nvim/message.c b/src/nvim/message.c
index ec5dabbbc0..ed673b52d3 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -7,42 +7,42 @@
#include <assert.h>
#include <inttypes.h>
-#include <stdbool.h>
#include <stdarg.h>
+#include <stdbool.h>
#include <string.h>
-#include "nvim/vim.h"
+#include "nvim/api/private/helpers.h"
#include "nvim/ascii.h"
#include "nvim/assert.h"
-#include "nvim/message.h"
#include "nvim/charset.h"
#include "nvim/eval.h"
-#include "nvim/ex_eval.h"
#include "nvim/ex_docmd.h"
+#include "nvim/ex_eval.h"
#include "nvim/fileio.h"
#include "nvim/func_attr.h"
+#include "nvim/garray.h"
#include "nvim/getchar.h"
+#include "nvim/highlight.h"
+#include "nvim/keymap.h"
#include "nvim/main.h"
#include "nvim/mbyte.h"
#include "nvim/memory.h"
+#include "nvim/message.h"
#include "nvim/misc1.h"
-#include "nvim/keymap.h"
-#include "nvim/garray.h"
+#include "nvim/mouse.h"
+#include "nvim/normal.h"
#include "nvim/ops.h"
#include "nvim/option.h"
-#include "nvim/normal.h"
+#include "nvim/os/input.h"
+#include "nvim/os/os.h"
+#include "nvim/os/time.h"
#include "nvim/regexp.h"
#include "nvim/screen.h"
#include "nvim/strings.h"
#include "nvim/syntax.h"
-#include "nvim/highlight.h"
#include "nvim/ui.h"
#include "nvim/ui_compositor.h"
-#include "nvim/mouse.h"
-#include "nvim/os/os.h"
-#include "nvim/os/input.h"
-#include "nvim/os/time.h"
-#include "nvim/api/private/helpers.h"
+#include "nvim/vim.h"
/*
* To be able to scroll back at the "more" and "hit-enter" prompts we need to
@@ -50,24 +50,24 @@
*/
typedef struct msgchunk_S msgchunk_T;
struct msgchunk_S {
- msgchunk_T *sb_next;
- msgchunk_T *sb_prev;
- char sb_eol; /* TRUE when line ends after this text */
- int sb_msg_col; /* column in which text starts */
- int sb_attr; /* text attributes */
- char_u sb_text[1]; /* text to be displayed, actually longer */
+ msgchunk_T *sb_next;
+ msgchunk_T *sb_prev;
+ char sb_eol; // TRUE when line ends after this text
+ int sb_msg_col; // column in which text starts
+ int sb_attr; // text attributes
+ char_u sb_text[1]; // text to be displayed, actually longer
};
-/* Magic chars used in confirm dialog strings */
+// Magic chars used in confirm dialog strings
#define DLG_BUTTON_SEP '\n'
#define DLG_HOTKEY_CHAR '&'
-static int confirm_msg_used = FALSE; /* displaying confirm_msg */
+static int confirm_msg_used = FALSE; // displaying confirm_msg
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "message.c.generated.h"
#endif
-static char_u *confirm_msg = NULL; /* ":confirm" message */
-static char_u *confirm_msg_tail; /* tail of confirm_msg */
+static char_u *confirm_msg = NULL; // ":confirm" message
+static char_u *confirm_msg_tail; // tail of confirm_msg
MessageHistoryEntry *first_msg_hist = NULL;
MessageHistoryEntry *last_msg_hist = NULL;
@@ -79,37 +79,37 @@ static int verbose_did_open = FALSE;
/*
* When writing messages to the screen, there are many different situations.
* A number of variables is used to remember the current state:
- * msg_didany TRUE when messages were written since the last time the
- * user reacted to a prompt.
- * Reset: After hitting a key for the hit-return prompt,
- * hitting <CR> for the command line or input().
- * Set: When any message is written to the screen.
- * msg_didout TRUE when something was written to the current line.
- * Reset: When advancing to the next line, when the current
- * text can be overwritten.
- * Set: When any message is written to the screen.
- * msg_nowait No extra delay for the last drawn message.
- * Used in normal_cmd() before the mode message is drawn.
+ * msg_didany true when messages were written since the last time the
+ * user reacted to a prompt.
+ * Reset: After hitting a key for the hit-return prompt,
+ * hitting <CR> for the command line or input().
+ * Set: When any message is written to the screen.
+ * msg_didout true when something was written to the current line.
+ * Reset: When advancing to the next line, when the current
+ * text can be overwritten.
+ * Set: When any message is written to the screen.
+ * msg_nowait No extra delay for the last drawn message.
+ * Used in normal_cmd() before the mode message is drawn.
* emsg_on_display There was an error message recently. Indicates that there
- * should be a delay before redrawing.
- * msg_scroll The next message should not overwrite the current one.
- * msg_scrolled How many lines the screen has been scrolled (because of
- * messages). Used in update_screen() to scroll the screen
- * back. Incremented each time the screen scrolls a line.
+ * should be a delay before redrawing.
+ * msg_scroll The next message should not overwrite the current one.
+ * msg_scrolled How many lines the screen has been scrolled (because of
+ * messages). Used in update_screen() to scroll the screen
+ * back. Incremented each time the screen scrolls a line.
* msg_scrolled_ign TRUE when msg_scrolled is non-zero and msg_puts_attr()
- * writes something without scrolling should not make
- * need_wait_return to be set. This is a hack to make ":ts"
- * work without an extra prompt.
- * lines_left Number of lines available for messages before the
- * more-prompt is to be given. -1 when not set.
- * need_wait_return TRUE when the hit-return prompt is needed.
- * Reset: After giving the hit-return prompt, when the user
- * has answered some other prompt.
- * Set: When the ruler or typeahead display is overwritten,
- * scrolling the screen for some message.
- * keep_msg Message to be displayed after redrawing the screen, in
- * main_loop().
- * This is an allocated string or NULL when not used.
+ * writes something without scrolling should not make
+ * need_wait_return to be set. This is a hack to make ":ts"
+ * work without an extra prompt.
+ * lines_left Number of lines available for messages before the
+ * more-prompt is to be given. -1 when not set.
+ * need_wait_return true when the hit-return prompt is needed.
+ * Reset: After giving the hit-return prompt, when the user
+ * has answered some other prompt.
+ * Set: When the ruler or typeahead display is overwritten,
+ * scrolling the screen for some message.
+ * keep_msg Message to be displayed after redrawing the screen, in
+ * main_loop().
+ * This is an allocated string or NULL when not used.
*/
@@ -231,8 +231,7 @@ int msg_attr(const char *s, const int attr)
}
/// similar to msg_outtrans_attr, but support newlines and tabs.
-void msg_multiline_attr(const char *s, int attr,
- bool check_int, bool *need_clear)
+void msg_multiline_attr(const char *s, int attr, bool check_int, bool *need_clear)
FUNC_ATTR_NONNULL_ALL
{
const char *next_spec = s;
@@ -287,16 +286,17 @@ bool msg_attr_keep(char_u *s, int attr, bool keep, bool multiline)
}
if (attr == 0) {
- set_vim_var_string(VV_STATUSMSG, (char *) s, -1);
+ set_vim_var_string(VV_STATUSMSG, (char *)s, -1);
}
/*
* It is possible that displaying a messages causes a problem (e.g.,
- * when redrawing the window), which causes another message, etc.. To
+ * when redrawing the window), which causes another message, etc.. To
* break this loop, limit the recursiveness to 3 levels.
*/
- if (entered >= 3)
+ if (entered >= 3) {
return TRUE;
+ }
++entered;
/* Add message to history (unless it's a repeated kept message or a
@@ -309,11 +309,12 @@ bool msg_attr_keep(char_u *s, int attr, bool keep, bool multiline)
add_msg_hist((const char *)s, -1, attr, multiline);
}
- /* Truncate the message if needed. */
+ // Truncate the message if needed.
msg_start();
buf = msg_strtrunc(s, FALSE);
- if (buf != NULL)
+ if (buf != NULL) {
s = buf;
+ }
bool need_clear = true;
if (multiline) {
@@ -336,31 +337,28 @@ bool msg_attr_keep(char_u *s, int attr, bool keep, bool multiline)
return retval;
}
-/*
- * Truncate a string such that it can be printed without causing a scroll.
- * Returns an allocated string or NULL when no truncating is done.
- */
-char_u *
-msg_strtrunc (
- char_u *s,
- int force /* always truncate */
-)
+/// Truncate a string such that it can be printed without causing a scroll.
+/// Returns an allocated string or NULL when no truncating is done.
+///
+/// @param force always truncate
+char_u *msg_strtrunc(char_u *s, int force)
{
- char_u *buf = NULL;
+ char_u *buf = NULL;
int len;
int room;
- /* May truncate message to avoid a hit-return prompt */
+ // May truncate message to avoid a hit-return prompt
if ((!msg_scroll && !need_wait_return && shortmess(SHM_TRUNCALL)
&& !exmode_active && msg_silent == 0 && !ui_has(kUIMessages))
|| force) {
len = vim_strsize(s);
- if (msg_scrolled != 0)
- /* Use all the columns. */
+ if (msg_scrolled != 0) {
+ // Use all the columns.
room = (int)(Rows - msg_row) * Columns - 1;
- else
- /* Use up to 'showcmd' column. */
+ } else {
+ // Use up to 'showcmd' column.
room = (int)(Rows - msg_row - 1) * Columns + sc_col - 1;
+ }
if (len > room && room > 0) {
// may have up to 18 bytes per cell (6 per char, up to two
// composing chars)
@@ -390,10 +388,10 @@ void trunc_string(char_u *s, char_u *buf, int room_in, int buflen)
}
half = room / 2;
- /* First part: Start of the string. */
+ // First part: Start of the string.
for (e = 0; len < half && e < buflen; ++e) {
if (s[e] == NUL) {
- /* text fits without truncating! */
+ // text fits without truncating!
buf[e] = NUL;
return;
}
@@ -497,7 +495,7 @@ int smsg_attr_keep(int attr, char *s, ...)
* isn't printed each time when it didn't change.
*/
static int last_sourcing_lnum = 0;
-static char_u *last_sourcing_name = NULL;
+static char_u *last_sourcing_name = NULL;
/*
* Reset the last used sourcing name/lnum. Makes sure it is displayed again
@@ -515,8 +513,9 @@ void reset_last_sourcing(void)
static int other_sourcing_name(void)
{
if (sourcing_name != NULL) {
- if (last_sourcing_name != NULL)
+ if (last_sourcing_name != NULL) {
return STRCMP(sourcing_name, last_sourcing_name) != 0;
+ }
return TRUE;
}
return FALSE;
@@ -577,16 +576,17 @@ void msg_source(int attr)
if (p != NULL) {
msg_attr(p, HL_ATTR(HLF_N));
xfree(p);
- last_sourcing_lnum = sourcing_lnum; /* only once for each line */
+ last_sourcing_lnum = sourcing_lnum; // only once for each line
}
- /* remember the last sourcing name printed, also when it's empty */
+ // remember the last sourcing name printed, also when it's empty
if (sourcing_name == NULL || other_sourcing_name()) {
xfree(last_sourcing_name);
- if (sourcing_name == NULL)
+ if (sourcing_name == NULL) {
last_sourcing_name = NULL;
- else
+ } else {
last_sourcing_name = vim_strsave(sourcing_name);
+ }
}
--no_wait_return;
}
@@ -601,9 +601,9 @@ int emsg_not_now(void)
{
if ((emsg_off > 0 && vim_strchr(p_debug, 'm') == NULL
&& vim_strchr(p_debug, 't') == NULL)
- || emsg_skip > 0
- )
+ || emsg_skip > 0) {
return TRUE;
+ }
return FALSE;
}
@@ -762,7 +762,7 @@ bool emsgf_multiline(const char *const fmt, ...)
va_list ap;
- static char errbuf[MULTILINE_BUFSIZE];
+ static char errbuf[MULTILINE_BUFSIZE];
if (emsg_not_now()) {
return true;
}
@@ -794,9 +794,9 @@ static bool emsgfv(const char *fmt, va_list ap)
/// detected when fuzzing vim.
void iemsg(const char *s)
{
- emsg((char_u *)s);
+ emsg((char_u *)s);
#ifdef ABORT_ON_INTERNAL_ERROR
- abort();
+ abort();
#endif
}
@@ -805,19 +805,19 @@ void iemsg(const char *s)
/// detected when fuzzing vim.
void iemsgf(const char *s, ...)
{
- va_list ap;
- va_start(ap, s);
- (void)emsgfv(s, ap);
- va_end(ap);
+ va_list ap;
+ va_start(ap, s);
+ (void)emsgfv(s, ap);
+ va_end(ap);
#ifdef ABORT_ON_INTERNAL_ERROR
- abort();
+ abort();
#endif
}
/// Give an "Internal error" message.
void internal_error(char *where)
{
- IEMSG2(_(e_intern2), where);
+ IEMSG2(_(e_intern2), where);
}
static void msg_emsgf_event(void **argv)
@@ -858,8 +858,9 @@ char_u *msg_trunc_attr(char_u *s, int force, int attr)
n = msg_attr((const char *)s, attr);
msg_hist_off = false;
- if (n)
+ if (n) {
return s;
+ }
return NULL;
}
@@ -930,18 +931,21 @@ void add_hl_msg_hist(HlMessage hl_msg)
/// @param[in] len Length of s or -1.
static void add_msg_hist(const char *s, int len, int attr, bool multiline)
{
- if (msg_hist_off || msg_silent != 0)
+ if (msg_hist_off || msg_silent != 0) {
return;
+ }
- /* Don't let the message history get too big */
- while (msg_hist_len > MAX_MSG_HIST_LEN)
+ // Don't let the message history get too big
+ while (msg_hist_len > MAX_MSG_HIST_LEN) {
(void)delete_first_msg();
+ }
- /* allocate an entry and add the message at the end of the history */
+ // allocate an entry and add the message at the end of the history
struct msg_hist *p = xmalloc(sizeof(struct msg_hist));
- if (len < 0)
+ if (len < 0) {
len = (int)STRLEN(s);
- /* remove leading and trailing newlines */
+ }
+ // remove leading and trailing newlines
while (len > 0 && *s == '\n') {
++s;
--len;
@@ -972,11 +976,12 @@ int delete_first_msg(void)
{
struct msg_hist *p;
- if (msg_hist_len <= 0)
+ if (msg_hist_len <= 0) {
return FAIL;
+ }
p = first_msg_hist;
first_msg_hist = p->next;
- if (first_msg_hist == NULL) { /* history is becoming empty */
+ if (first_msg_hist == NULL) { // history is becoming empty
assert(msg_hist_len == 1);
last_msg_hist = NULL;
}
@@ -1078,7 +1083,7 @@ void wait_return(int redraw)
int oldState;
int tmpState;
int had_got_int;
- FILE *save_scriptout;
+ FILE *save_scriptout;
if (redraw == true) {
redraw_all_later(NOT_VALID);
@@ -1086,8 +1091,9 @@ void wait_return(int redraw)
/* If using ":silent cmd", don't wait for a return. Also don't set
* need_wait_return to do it later. */
- if (msg_silent != 0)
+ if (msg_silent != 0) {
return;
+ }
/*
* When inside vgetc(), we can't wait for a typed character at all.
@@ -1095,24 +1101,26 @@ void wait_return(int redraw)
* the end. Adjust cmdline_row to avoid the next message overwriting the
* last one.
*/
- if (vgetc_busy > 0)
+ if (vgetc_busy > 0) {
return;
- need_wait_return = TRUE;
+ }
+ need_wait_return = true;
if (no_wait_return) {
- if (!exmode_active)
+ if (!exmode_active) {
cmdline_row = msg_row;
+ }
return;
}
- redir_off = TRUE; /* don't redirect this message */
+ redir_off = true; // don't redirect this message
oldState = State;
if (quit_more) {
- c = CAR; /* just pretend CR was hit */
+ c = CAR; // just pretend CR was hit
quit_more = FALSE;
got_int = FALSE;
} else if (exmode_active) {
- MSG_PUTS(" "); /* make sure the cursor is on the right line */
- c = CAR; /* no need for a return in ex mode */
+ MSG_PUTS(" "); // make sure the cursor is on the right line
+ c = CAR; // no need for a return in ex mode
got_int = FALSE;
} else {
// Make sure the hit-return prompt is on screen when 'guioptions' was
@@ -1165,18 +1173,18 @@ void wait_return(int redraw)
if (p_more) {
if (c == 'b' || c == 'k' || c == 'u' || c == 'g'
|| c == K_UP || c == K_PAGEUP) {
- if (msg_scrolled > Rows)
- /* scroll back to show older messages */
+ if (msg_scrolled > Rows) {
+ // scroll back to show older messages
do_more_prompt(c);
- else {
- msg_didout = FALSE;
+ } else {
+ msg_didout = false;
c = K_IGNORE;
msg_col =
cmdmsg_rl ? Columns - 1 :
0;
}
if (quit_more) {
- c = CAR; /* just pretend CR was hit */
+ c = CAR; // just pretend CR was hit
quit_more = FALSE;
got_int = FALSE;
} else if (c != K_IGNORE) {
@@ -1185,8 +1193,9 @@ void wait_return(int redraw)
}
} else if (msg_scrolled > Rows - 2
&& (c == 'j' || c == 'd' || c == 'f'
- || c == K_DOWN || c == K_PAGEDOWN))
+ || c == K_DOWN || c == K_PAGEDOWN)) {
c = K_IGNORE;
+ }
}
} while ((had_got_int && c == Ctrl_C)
|| c == K_IGNORE
@@ -1201,9 +1210,9 @@ void wait_return(int redraw)
* Avoid that the mouse-up event causes visual mode to start.
*/
if (c == K_LEFTMOUSE || c == K_MIDDLEMOUSE || c == K_RIGHTMOUSE
- || c == K_X1MOUSE || c == K_X2MOUSE)
+ || c == K_X1MOUSE || c == K_X2MOUSE) {
(void)jump_to_mouse(MOUSE_SETPOS, NULL, 0);
- else if (vim_strchr((char_u *)"\r\n ", c) == NULL && c != Ctrl_C) {
+ } else if (vim_strchr((char_u *)"\r\n ", c) == NULL && c != Ctrl_C) {
/* Put the character back in the typeahead buffer. Don't use the
* stuff buffer, because lmaps wouldn't work. */
ins_char_typebuf(c);
@@ -1216,8 +1225,9 @@ void wait_return(int redraw)
// If the user hits ':', '?' or '/' we get a command line from the next
// line.
if (c == ':' || c == '?' || c == '/') {
- if (!exmode_active)
+ if (!exmode_active) {
cmdline_row = msg_row;
+ }
skip_redraw = true; // skip redraw once
do_redraw = false;
msg_ext_keep_after_cmdline = true;
@@ -1240,7 +1250,7 @@ void wait_return(int redraw)
XFREE_CLEAR(keep_msg); // don't redisplay message, it's too long
}
- if (tmpState == SETWSIZE) { /* got resize event while in vgetc() */
+ if (tmpState == SETWSIZE) { // got resize event while in vgetc()
ui_refresh();
} else if (!skip_redraw) {
if (redraw == true || (msg_scrolled != 0 && redraw != -1)) {
@@ -1259,9 +1269,10 @@ static void hit_return_msg(void)
{
int save_p_more = p_more;
- p_more = FALSE; /* don't want see this message when scrolling back */
- if (msg_didout) /* start on a new line */
+ p_more = FALSE; // don't want see this message when scrolling back
+ if (msg_didout) { // start on a new line
msg_putchar('\n');
+ }
msg_ext_set_kind("return_prompt");
if (got_int) {
MSG_PUTS(_("Interrupt: "));
@@ -1280,11 +1291,12 @@ static void hit_return_msg(void)
void set_keep_msg(char_u *s, int attr)
{
xfree(keep_msg);
- if (s != NULL && msg_silent == 0)
+ if (s != NULL && msg_silent == 0) {
keep_msg = vim_strsave(s);
- else
+ } else {
keep_msg = NULL;
- keep_msg_more = FALSE;
+ }
+ keep_msg_more = false;
keep_msg_attr = attr;
}
@@ -1324,12 +1336,12 @@ void msg_start(void)
0;
} else if (msg_didout) { // start message on next line
msg_putchar('\n');
- did_return = TRUE;
- if (exmode_active != EXMODE_NORMAL)
- cmdline_row = msg_row;
+ did_return = true;
+ cmdline_row = msg_row;
}
- if (!msg_didany || lines_left < 0)
+ if (!msg_didany || lines_left < 0) {
msg_starthere();
+ }
if (msg_silent == 0) {
msg_didout = false; // no output on current line yet
}
@@ -1354,7 +1366,7 @@ void msg_start(void)
void msg_starthere(void)
{
lines_left = cmdline_row;
- msg_didany = FALSE;
+ msg_didany = false;
}
void msg_putchar(int c)
@@ -1397,7 +1409,7 @@ void msg_home_replace_hl(char_u *fname)
static void msg_home_replace_attr(char_u *fname, int attr)
{
- char_u *name;
+ char_u *name;
name = home_replace_save(NULL, fname);
msg_outtrans_attr(name, attr);
@@ -1450,7 +1462,7 @@ int msg_outtrans_len_attr(const char_u *msgstr, int len, int attr)
int mb_l;
int c;
- /* if MSG_HIST flag set, add message to history */
+ // if MSG_HIST flag set, add message to history
if (attr & MSG_HIST) {
add_msg_hist(str, len, attr, false);
attr &= ~MSG_HIST;
@@ -1519,13 +1531,16 @@ void msg_make(char_u *arg)
static char_u *str = (char_u *)"eeffoc", *rs = (char_u *)"Plon#dqg#vxjduB";
arg = skipwhite(arg);
- for (i = 5; *arg && i >= 0; --i)
- if (*arg++ != str[i])
+ for (i = 5; *arg && i >= 0; --i) {
+ if (*arg++ != str[i]) {
break;
+ }
+ }
if (i < 0) {
msg_putchar('\n');
- for (i = 0; rs[i]; ++i)
+ for (i = 0; rs[i]; ++i) {
msg_putchar(rs[i] - 3);
+ }
}
}
@@ -1541,11 +1556,10 @@ void msg_make(char_u *arg)
/// Otherwise characters are not highlighted.
/// This function is used to show mappings, where we want to see how to type
/// the character/string -- webb
-int msg_outtrans_special(
- const char_u *strstart,
- bool from, ///< true for LHS of a mapping
- int maxlen ///< screen columns, 0 for unlimeted
-)
+///
+/// @param from true for LHS of a mapping
+/// @param maxlen screen columns, 0 for unlimeted
+int msg_outtrans_special(const char_u *strstart, bool from, int maxlen)
{
if (strstart == NULL) {
return 0; // Do nothing.
@@ -1586,8 +1600,7 @@ int msg_outtrans_special(
/// @param[in] replace_lt Convert `<` into `<lt>`.
///
/// @return [allocated] Converted string.
-char *str2special_save(const char *const str, const bool replace_spaces,
- const bool replace_lt)
+char *str2special_save(const char *const str, const bool replace_spaces, const bool replace_lt)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_MALLOC
FUNC_ATTR_NONNULL_RET
{
@@ -1612,8 +1625,7 @@ char *str2special_save(const char *const str, const bool replace_spaces,
/// @return Converted key code, in a static buffer. Buffer is always one and the
/// same, so save converted string somewhere before running str2special
/// for the second time.
-const char *str2special(const char **const sp, const bool replace_spaces,
- const bool replace_lt)
+const char *str2special(const char **const sp, const bool replace_spaces, const bool replace_lt)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET
{
static char buf[7];
@@ -1708,6 +1720,8 @@ void msg_prt_line(char_u *s, int list)
int n;
int attr = 0;
char_u *lead = NULL;
+ bool in_multispace = false;
+ int multispace_pos = 0;
char_u *trail = NULL;
int l;
@@ -1772,6 +1786,10 @@ void msg_prt_line(char_u *s, int list)
} else {
attr = 0;
c = *s++;
+ in_multispace = c == ' ' && ((col > 0 && s[-2] == ' ') || *s == ' ');
+ if (!in_multispace) {
+ multispace_pos = 0;
+ }
if (c == TAB && (!list || curwin->w_p_lcs_chars.tab1)) {
// tab amount depends on current column
n_extra = tabstop_padding(col,
@@ -1787,11 +1805,11 @@ void msg_prt_line(char_u *s, int list)
: curwin->w_p_lcs_chars.tab1;
c_extra = curwin->w_p_lcs_chars.tab2;
c_final = curwin->w_p_lcs_chars.tab3;
- attr = HL_ATTR(HLF_8);
+ attr = HL_ATTR(HLF_0);
}
} else if (c == 160 && list && curwin->w_p_lcs_chars.nbsp != NUL) {
c = curwin->w_p_lcs_chars.nbsp;
- attr = HL_ATTR(HLF_8);
+ attr = HL_ATTR(HLF_0);
} else if (c == NUL && list && curwin->w_p_lcs_chars.eol != NUL) {
p_extra = (char_u *)"";
c_extra = NUL;
@@ -1808,21 +1826,30 @@ void msg_prt_line(char_u *s, int list)
c = *p_extra++;
/* Use special coloring to be able to distinguish <hex> from
* the same in plain text. */
- attr = HL_ATTR(HLF_8);
- } else if (c == ' ' && lead != NULL && s <= lead) {
- c = curwin->w_p_lcs_chars.lead;
- attr = HL_ATTR(HLF_8);
- } else if (c == ' ' && trail != NULL && s > trail) {
- c = curwin->w_p_lcs_chars.trail;
- attr = HL_ATTR(HLF_8);
- } else if (c == ' ' && list && curwin->w_p_lcs_chars.space != NUL) {
- c = curwin->w_p_lcs_chars.space;
- attr = HL_ATTR(HLF_8);
+ attr = HL_ATTR(HLF_0);
+ } else if (c == ' ') {
+ if (lead != NULL && s <= lead) {
+ c = curwin->w_p_lcs_chars.lead;
+ attr = HL_ATTR(HLF_0);
+ } else if (trail != NULL && s > trail) {
+ c = curwin->w_p_lcs_chars.trail;
+ attr = HL_ATTR(HLF_0);
+ } else if (list && in_multispace && curwin->w_p_lcs_chars.multispace != NULL) {
+ c = curwin->w_p_lcs_chars.multispace[multispace_pos++];
+ if (curwin->w_p_lcs_chars.multispace[multispace_pos] == NUL) {
+ multispace_pos = 0;
+ }
+ attr = HL_ATTR(HLF_0);
+ } else if (list && curwin->w_p_lcs_chars.space != NUL) {
+ c = curwin->w_p_lcs_chars.space;
+ attr = HL_ATTR(HLF_0);
+ }
}
}
- if (c == NUL)
+ if (c == NUL) {
break;
+ }
msg_putchar_attr(c, attr);
col++;
@@ -2009,8 +2036,7 @@ static void msg_ext_emit_chunk(void)
* The display part of msg_puts_attr_len().
* May be called recursively to display scroll-back text.
*/
-static void msg_puts_display(const char_u *str, int maxlen, int attr,
- int recurse)
+static void msg_puts_display(const char_u *str, int maxlen, int attr, int recurse)
{
const char_u *s = str;
const char_u *t_s = str; // String from "t_s" to "s" is still todo.
@@ -2063,17 +2089,19 @@ static void msg_puts_display(const char_u *str, int maxlen, int attr,
t_puts(&t_col, t_s, s, attr);
}
- /* When no more prompt and no more room, truncate here */
- if (msg_no_more && lines_left == 0)
+ // When no more prompt and no more room, truncate here
+ if (msg_no_more && lines_left == 0) {
break;
+ }
// Scroll the screen up one line.
bool has_last_char = (*s >= ' ' && !cmdmsg_rl);
msg_scroll_up(!has_last_char);
msg_row = Rows - 2;
- if (msg_col >= Columns) /* can happen after screen resize */
+ if (msg_col >= Columns) { // can happen after screen resize
msg_col = Columns - 1;
+ }
// Display char in last column before showing more-prompt.
if (has_last_char) {
@@ -2114,20 +2142,24 @@ static void msg_puts_display(const char_u *str, int maxlen, int attr,
* If screen is completely filled and 'more' is set then wait
* for a character.
*/
- if (lines_left > 0)
+ if (lines_left > 0) {
--lines_left;
+ }
if (p_more && lines_left == 0 && State != HITRETURN
&& !msg_no_more && !exmode_active) {
- if (do_more_prompt(NUL))
+ if (do_more_prompt(NUL)) {
s = confirm_msg_tail;
- if (quit_more)
+ }
+ if (quit_more) {
return;
+ }
}
/* When we displayed a char in last column need to check if there
* is still more. */
- if (did_last_char)
+ if (did_last_char) {
continue;
+ }
}
wrap = *s == '\n'
@@ -2146,20 +2178,23 @@ static void msg_puts_display(const char_u *str, int maxlen, int attr,
store_sb_text((char_u **)&sb_str, (char_u *)s, attr, &sb_col, true);
}
- if (*s == '\n') { /* go to next line */
- msg_didout = FALSE; /* remember that line is empty */
- if (cmdmsg_rl)
+ if (*s == '\n') { // go to next line
+ msg_didout = false; // remember that line is empty
+ if (cmdmsg_rl) {
msg_col = Columns - 1;
- else
+ } else {
msg_col = 0;
- if (++msg_row >= Rows) /* safety check */
+ }
+ if (++msg_row >= Rows) { // safety check
msg_row = Rows - 1;
- } else if (*s == '\r') { /* go to column 0 */
+ }
+ } else if (*s == '\r') { // go to column 0
msg_col = 0;
- } else if (*s == '\b') { /* go to previous char */
- if (msg_col)
+ } else if (*s == '\b') { // go to previous char
+ if (msg_col) {
--msg_col;
- } else if (*s == TAB) { /* translate Tab into spaces */
+ }
+ } else if (*s == TAB) { // translate Tab into spaces
do {
msg_screen_putchar(' ', attr);
} while (msg_col & 7);
@@ -2183,9 +2218,10 @@ static void msg_puts_display(const char_u *str, int maxlen, int attr,
msg_screen_putchar(*s, attr);
}
} else {
- /* postpone this character until later */
- if (t_col == 0)
+ // postpone this character until later
+ if (t_col == 0) {
t_s = s;
+ }
t_col += cw;
s += l - 1;
}
@@ -2343,7 +2379,7 @@ void msg_reset_scroll(void)
static void inc_msg_scrolled(void)
{
if (*get_vim_var_str(VV_SCROLLSTART) == NUL) {
- char *p = (char *) sourcing_name;
+ char *p = (char *)sourcing_name;
char *tofree = NULL;
// v:scrollstart is empty, set it to the script/function name and line
@@ -2354,7 +2390,7 @@ static void inc_msg_scrolled(void)
size_t len = strlen(p) + 40;
tofree = xmalloc(len);
vim_snprintf(tofree, len, _("%s line %" PRId64),
- p, (int64_t) sourcing_lnum);
+ p, (int64_t)sourcing_lnum);
p = tofree;
}
set_vim_var_string(VV_SCROLLSTART, p, -1);
@@ -2379,15 +2415,13 @@ typedef enum {
static sb_clear_T do_clear_sb_text = SB_CLEAR_NONE;
/// Store part of a printed message for displaying when scrolling back.
-static void store_sb_text(
- char_u **sb_str, // start of string
- char_u *s, // just after string
- int attr,
- int *sb_col,
- int finish // line ends
-)
+///
+/// @param sb_str start of string
+/// @param s just after string
+/// @param finish line ends
+static void store_sb_text(char_u **sb_str, char_u *s, int attr, int *sb_col, int finish)
{
- msgchunk_T *mp;
+ msgchunk_T *mp;
if (do_clear_sb_text == SB_CLEAR_ALL
|| do_clear_sb_text == SB_CLEAR_CMDLINE_DONE) {
@@ -2412,8 +2446,9 @@ static void store_sb_text(
last_msgchunk = mp;
}
mp->sb_next = NULL;
- } else if (finish && last_msgchunk != NULL)
+ } else if (finish && last_msgchunk != NULL) {
last_msgchunk->sb_eol = TRUE;
+ }
*sb_str = s;
*sb_col = 0;
@@ -2445,8 +2480,8 @@ void sb_text_end_cmdline(void)
/// Called when redrawing the screen.
void clear_sb_text(int all)
{
- msgchunk_T *mp;
- msgchunk_T **lastp;
+ msgchunk_T *mp;
+ msgchunk_T **lastp;
if (all) {
lastp = &last_msgchunk;
@@ -2469,7 +2504,7 @@ void clear_sb_text(int all)
*/
void show_sb_text(void)
{
- msgchunk_T *mp;
+ msgchunk_T *mp;
/* Only show something if there is more than one line, otherwise it looks
* weird, typing a command without output results in one line. */
@@ -2489,8 +2524,9 @@ static msgchunk_T *msg_sb_start(msgchunk_T *mps)
{
msgchunk_T *mp = mps;
- while (mp != NULL && mp->sb_prev != NULL && !mp->sb_prev->sb_eol)
+ while (mp != NULL && mp->sb_prev != NULL && !mp->sb_prev->sb_eol) {
mp = mp->sb_prev;
+ }
return mp;
}
@@ -2499,8 +2535,9 @@ static msgchunk_T *msg_sb_start(msgchunk_T *mps)
*/
void msg_sb_eol(void)
{
- if (last_msgchunk != NULL)
+ if (last_msgchunk != NULL) {
last_msgchunk->sb_eol = TRUE;
+ }
}
/*
@@ -2509,18 +2546,20 @@ void msg_sb_eol(void)
*/
static msgchunk_T *disp_sb_line(int row, msgchunk_T *smp)
{
- msgchunk_T *mp = smp;
- char_u *p;
+ msgchunk_T *mp = smp;
+ char_u *p;
for (;; ) {
msg_row = row;
msg_col = mp->sb_msg_col;
p = mp->sb_text;
- if (*p == '\n') /* don't display the line break */
+ if (*p == '\n') { // don't display the line break
++p;
+ }
msg_puts_display(p, -1, mp->sb_attr, TRUE);
- if (mp->sb_eol || mp->sb_next == NULL)
+ if (mp->sb_eol || mp->sb_next == NULL) {
break;
+ }
mp = mp->sb_next;
}
@@ -2618,8 +2657,8 @@ static int do_more_prompt(int typed_char)
int retval = FALSE;
int toscroll;
bool to_redraw = false;
- msgchunk_T *mp_last = NULL;
- msgchunk_T *mp;
+ msgchunk_T *mp_last = NULL;
+ msgchunk_T *mp;
int i;
// If headless mode is enabled and no input is required, this variable
@@ -2636,23 +2675,25 @@ static int do_more_prompt(int typed_char)
entered = true;
if (typed_char == 'G') {
- /* "g<": Find first line on the last page. */
+ // "g<": Find first line on the last page.
mp_last = msg_sb_start(last_msgchunk);
for (i = 0; i < Rows - 2 && mp_last != NULL
- && mp_last->sb_prev != NULL; ++i)
+ && mp_last->sb_prev != NULL; ++i) {
mp_last = msg_sb_start(mp_last->sb_prev);
+ }
}
State = ASKMORE;
setmouse();
- if (typed_char == NUL)
+ if (typed_char == NUL) {
msg_moremsg(FALSE);
+ }
for (;; ) {
/*
* Get a typed character directly from the user.
*/
if (used_typed_char != NUL) {
- c = used_typed_char; /* was typed at hit-enter prompt */
+ c = used_typed_char; // was typed at hit-enter prompt
used_typed_char = NUL;
} else {
c = get_keystroke(resize_events);
@@ -2661,64 +2702,64 @@ static int do_more_prompt(int typed_char)
toscroll = 0;
switch (c) {
- case BS: /* scroll one line back */
+ case BS: // scroll one line back
case K_BS:
case 'k':
case K_UP:
toscroll = -1;
break;
- case CAR: /* one extra line */
+ case CAR: // one extra line
case NL:
case 'j':
case K_DOWN:
toscroll = 1;
break;
- case 'u': /* Up half a page */
+ case 'u': // Up half a page
toscroll = -(Rows / 2);
break;
- case 'd': /* Down half a page */
+ case 'd': // Down half a page
toscroll = Rows / 2;
break;
- case 'b': /* one page back */
+ case 'b': // one page back
case K_PAGEUP:
toscroll = -(Rows - 1);
break;
- case ' ': /* one extra page */
+ case ' ': // one extra page
case 'f':
case K_PAGEDOWN:
case K_LEFTMOUSE:
toscroll = Rows - 1;
break;
- case 'g': /* all the way back to the start */
+ case 'g': // all the way back to the start
toscroll = -999999;
break;
- case 'G': /* all the way to the end */
+ case 'G': // all the way to the end
toscroll = 999999;
lines_left = 999999;
break;
- case ':': /* start new command line */
+ case ':': // start new command line
if (!confirm_msg_used) {
/* Since got_int is set all typeahead will be flushed, but we
* want to keep this ':', remember that in a special way. */
typeahead_noflush(':');
- cmdline_row = Rows - 1; /* put ':' on this line */
- skip_redraw = TRUE; /* skip redraw once */
- need_wait_return = FALSE; /* don't wait in main() */
+ cmdline_row = Rows - 1; // put ':' on this line
+ skip_redraw = true; // skip redraw once
+ need_wait_return = false; // don't wait in main()
}
FALLTHROUGH;
case 'q': // quit
case Ctrl_C:
case ESC:
if (confirm_msg_used) {
- /* Jump to the choices of the dialog. */
+ // Jump to the choices of the dialog.
retval = TRUE;
} else {
got_int = TRUE;
@@ -2737,7 +2778,7 @@ static int do_more_prompt(int typed_char)
to_redraw = true;
break;
- default: /* no valid response */
+ default: // no valid response
msg_moremsg(TRUE);
continue;
}
@@ -2756,10 +2797,11 @@ static int do_more_prompt(int typed_char)
mp = NULL;
}
- /* go to start of line at top of the screen */
+ // go to start of line at top of the screen
for (i = 0; i < Rows - 2 && mp != NULL && mp->sb_prev != NULL;
- ++i)
+ ++i) {
mp = msg_sb_start(mp->sb_prev);
+ }
if (mp != NULL && (mp->sb_prev != NULL || to_redraw)) {
// Find line to be displayed at top
@@ -2768,10 +2810,11 @@ static int do_more_prompt(int typed_char)
break;
}
mp = msg_sb_start(mp->sb_prev);
- if (mp_last == NULL)
+ if (mp_last == NULL) {
mp_last = msg_sb_start(last_msgchunk);
- else
+ } else {
mp_last = msg_sb_start(mp_last->sb_prev);
+ }
}
if (toscroll == -1 && !to_redraw) {
@@ -2795,7 +2838,7 @@ static int do_more_prompt(int typed_char)
toscroll = 0;
}
} else {
- /* First display any text that we scrolled back. */
+ // First display any text that we scrolled back.
while (toscroll > 0 && mp_last != NULL) {
if (msg_do_throttle() && !msg_grid.throttled) {
// Tricky: we redraw at one line higher than usual. Therefore
@@ -2821,7 +2864,7 @@ static int do_more_prompt(int typed_char)
continue;
}
- /* display more text, return to caller */
+ // display more text, return to caller
lines_left = toscroll;
}
@@ -2902,7 +2945,7 @@ static void msg_screen_putchar(int c, int attr)
void msg_moremsg(int full)
{
int attr;
- char_u *s = (char_u *)_("-- More --");
+ char_u *s = (char_u *)_("-- More --");
attr = hl_combine_attr(HL_ATTR(HLF_MSG), HL_ATTR(HLF_M));
grid_puts(&msg_grid_adj, s, Rows - 1, 0, attr);
@@ -2920,19 +2963,19 @@ void msg_moremsg(int full)
void repeat_message(void)
{
if (State == ASKMORE) {
- msg_moremsg(TRUE); /* display --more-- message again */
+ msg_moremsg(TRUE); // display --more-- message again
msg_row = Rows - 1;
} else if (State == CONFIRM) {
- display_confirm_msg(); /* display ":confirm" message again */
+ display_confirm_msg(); // display ":confirm" message again
msg_row = Rows - 1;
} else if (State == EXTERNCMD) {
- ui_cursor_goto(msg_row, msg_col); /* put cursor back */
+ ui_cursor_goto(msg_row, msg_col); // put cursor back
} else if (State == HITRETURN || State == SETWSIZE) {
if (msg_row == Rows - 1) {
/* Avoid drawing the "hit-enter" prompt below the previous one,
* overwrite it. Esp. useful when regaining focus and a
* FocusGained autocmd exists but didn't draw anything. */
- msg_didout = FALSE;
+ msg_didout = false;
msg_col = 0;
msg_clr_eos();
}
@@ -2947,8 +2990,9 @@ void repeat_message(void)
*/
void msg_clr_eos(void)
{
- if (msg_silent == 0)
+ if (msg_silent == 0) {
msg_clr_eos_force();
+ }
}
/*
@@ -3096,8 +3140,8 @@ void msg_check(void)
return;
}
if (msg_row == Rows - 1 && msg_col >= sc_col) {
- need_wait_return = TRUE;
- redraw_cmdline = TRUE;
+ need_wait_return = true;
+ redraw_cmdline = true;
}
}
@@ -3114,16 +3158,18 @@ static void redir_write(const char *const str, const ptrdiff_t maxlen)
return;
}
- /* Don't do anything for displaying prompts and the like. */
- if (redir_off)
+ // Don't do anything for displaying prompts and the like.
+ if (redir_off) {
return;
+ }
- /* If 'verbosefile' is set prepare for writing in that file. */
- if (*p_vfile != NUL && verbose_fd == NULL)
+ // If 'verbosefile' is set prepare for writing in that file.
+ if (*p_vfile != NUL && verbose_fd == NULL) {
verbose_open();
+ }
if (redirecting()) {
- /* If the string doesn't start with CR or NL, go to msg_col */
+ // If the string doesn't start with CR or NL, go to msg_col
if (*s != '\n' && *s != '\r') {
while (cur_col < msg_col) {
if (capture_ga) {
@@ -3175,8 +3221,9 @@ static void redir_write(const char *const str, const ptrdiff_t maxlen)
s++;
}
- if (msg_silent != 0) /* should update msg_col */
+ if (msg_silent != 0) { // should update msg_col
msg_col = cur_col;
+ }
}
}
@@ -3192,8 +3239,9 @@ int redirecting(void)
*/
void verbose_enter(void)
{
- if (*p_vfile != NUL)
+ if (*p_vfile != NUL) {
++msg_silent;
+ }
}
/*
@@ -3202,9 +3250,11 @@ void verbose_enter(void)
*/
void verbose_leave(void)
{
- if (*p_vfile != NUL)
- if (--msg_silent < 0)
+ if (*p_vfile != NUL) {
+ if (--msg_silent < 0) {
msg_silent = 0;
+ }
+ }
}
/*
@@ -3212,11 +3262,12 @@ void verbose_leave(void)
*/
void verbose_enter_scroll(void)
{
- if (*p_vfile != NUL)
+ if (*p_vfile != NUL) {
++msg_silent;
- else
- /* always scroll up, don't overwrite */
+ } else {
+ // always scroll up, don't overwrite
msg_scroll = TRUE;
+ }
}
/*
@@ -3225,10 +3276,12 @@ void verbose_enter_scroll(void)
void verbose_leave_scroll(void)
{
if (*p_vfile != NUL) {
- if (--msg_silent < 0)
+ if (--msg_silent < 0) {
msg_silent = 0;
- } else
+ }
+ } else {
cmdline_row = msg_row;
+ }
}
/*
@@ -3250,7 +3303,7 @@ void verbose_stop(void)
int verbose_open(void)
{
if (verbose_fd == NULL && !verbose_did_open) {
- /* Only give the error message once. */
+ // Only give the error message once.
verbose_did_open = TRUE;
verbose_fd = os_fopen((char *)p_vfile, "a");
@@ -3309,8 +3362,8 @@ void give_warning2(char_u *const message, char_u *const a1, bool hl)
*/
void msg_advance(int col)
{
- if (msg_silent != 0) { /* nothing to advance to */
- msg_col = col; /* for redirection, may fill it up later */
+ if (msg_silent != 0) { // nothing to advance to
+ msg_col = col; // for redirection, may fill it up later
return;
}
if (ui_has(kUIMessages)) {
@@ -3321,49 +3374,44 @@ void msg_advance(int col)
}
return;
}
- if (col >= Columns) /* not enough room */
+ if (col >= Columns) { // not enough room
col = Columns - 1;
- if (cmdmsg_rl)
- while (msg_col > Columns - col)
+ }
+ if (cmdmsg_rl) {
+ while (msg_col > Columns - col) {
msg_putchar(' ');
- else
- while (msg_col < col)
+ }
+ } else {
+ while (msg_col < col) {
msg_putchar(' ');
+ }
+ }
}
-/*
- * Used for "confirm()" function, and the :confirm command prefix.
- * Versions which haven't got flexible dialogs yet, and console
- * versions, get this generic handler which uses the command line.
- *
- * type = one of:
- * VIM_QUESTION, VIM_INFO, VIM_WARNING, VIM_ERROR or VIM_GENERIC
- * title = title string (can be NULL for default)
- * (neither used in console dialogs at the moment)
- *
- * Format of the "buttons" string:
- * "Button1Name\nButton2Name\nButton3Name"
- * The first button should normally be the default/accept
- * The second button should be the 'Cancel' button
- * Other buttons- use your imagination!
- * A '&' in a button name becomes a shortcut, so each '&' should be before a
- * different letter.
- */
-int
-do_dialog (
- int type,
- char_u *title,
- char_u *message,
- char_u *buttons,
- int dfltbutton,
- char_u *textfield, /* IObuff for inputdialog(), NULL
- otherwise */
- int ex_cmd /* when TRUE pressing : accepts default and starts
- Ex command */
-)
+/// Used for "confirm()" function, and the :confirm command prefix.
+/// Versions which haven't got flexible dialogs yet, and console
+/// versions, get this generic handler which uses the command line.
+///
+/// type = one of:
+/// VIM_QUESTION, VIM_INFO, VIM_WARNING, VIM_ERROR or VIM_GENERIC
+/// title = title string (can be NULL for default)
+/// (neither used in console dialogs at the moment)
+///
+/// Format of the "buttons" string:
+/// "Button1Name\nButton2Name\nButton3Name"
+/// The first button should normally be the default/accept
+/// The second button should be the 'Cancel' button
+/// Other buttons- use your imagination!
+/// A '&' in a button name becomes a shortcut, so each '&' should be before a
+/// different letter.
+///
+/// @param textfiel IObuff for inputdialog(), NULL otherwise
+/// @param ex_cmd when TRUE pressing : accepts default and starts Ex command
+int do_dialog(int type, char_u *title, char_u *message, char_u *buttons, int dfltbutton,
+ char_u *textfield, int ex_cmd)
{
int retval = 0;
- char_u *hotkeys;
+ char_u *hotkeys;
int c;
int i;
@@ -3392,16 +3440,16 @@ do_dialog (
// Get a typed character directly from the user.
c = get_keystroke(NULL);
switch (c) {
- case CAR: /* User accepts default option */
+ case CAR: // User accepts default option
case NL:
retval = dfltbutton;
break;
- case Ctrl_C: /* User aborts/cancels */
+ case Ctrl_C: // User aborts/cancels
case ESC:
retval = 0;
break;
- default: /* Could be a hotkey? */
- if (c < 0) { /* special keys are ignored here */
+ default: // Could be a hotkey?
+ if (c < 0) { // special keys are ignored here
continue;
}
if (c == ':' && ex_cmd) {
@@ -3420,9 +3468,10 @@ do_dialog (
i += utfc_ptr2len(hotkeys + i) - 1;
retval++;
}
- if (hotkeys[i])
+ if (hotkeys[i]) {
break;
- /* No hotkey match, so keep waiting */
+ }
+ // No hotkey match, so keep waiting
continue;
}
break;
@@ -3440,15 +3489,11 @@ do_dialog (
}
-/*
- * Copy one character from "*from" to "*to", taking care of multi-byte
- * characters. Return the length of the character in bytes.
- */
-static int copy_char(
- const char_u *from,
- char_u *to,
- bool lowercase // make character lower case
-)
+/// Copy one character from "*from" to "*to", taking care of multi-byte
+/// characters. Return the length of the character in bytes.
+///
+/// @param lowercase make character lower case
+static int copy_char(const char_u *from, char_u *to, bool lowercase)
FUNC_ATTR_NONNULL_ALL
{
if (lowercase) {
@@ -3475,9 +3520,7 @@ static int copy_char(
/// corresponding button has a hotkey
///
/// @return Pointer to memory allocated for storing hotkeys
-static char_u * console_dialog_alloc(const char_u *message,
- char_u *buttons,
- bool has_hotkey[])
+static char_u *console_dialog_alloc(const char_u *message, char_u *buttons, bool has_hotkey[])
{
int lenhotkey = HOTK_LEN; // count first button
has_hotkey[0] = false;
@@ -3506,9 +3549,9 @@ static char_u * console_dialog_alloc(const char_u *message,
}
len += (int)(STRLEN(message)
- + 2 // for the NL's
- + STRLEN(buttons)
- + 3); // for the ": " and NUL
+ + 2 // for the NL's
+ + STRLEN(buttons)
+ + 3); // for the ": " and NUL
lenhotkey++; // for the NUL
// If no hotkey is specified, first char is used.
@@ -3537,7 +3580,7 @@ static char_u * console_dialog_alloc(const char_u *message,
static char_u *msg_show_console_dialog(char_u *message, char_u *buttons, int dfltbutton)
FUNC_ATTR_NONNULL_RET
{
- bool has_hotkey[HAS_HOTKEY_LEN] = {false};
+ bool has_hotkey[HAS_HOTKEY_LEN] = { false };
char_u *hotk = console_dialog_alloc(message, buttons, has_hotkey);
copy_hotkeys_and_msg(message, buttons, dfltbutton, has_hotkey, hotk);
@@ -3554,9 +3597,8 @@ static char_u *msg_show_console_dialog(char_u *message, char_u *buttons, int dfl
/// @param has_hotkey An element in this array is true if corresponding button
/// has a hotkey
/// @param[out] hotkeys_ptr Pointer to the memory location where hotkeys will be copied
-static void copy_hotkeys_and_msg(const char_u *message, char_u *buttons,
- int default_button_idx, const bool has_hotkey[],
- char_u *hotkeys_ptr)
+static void copy_hotkeys_and_msg(const char_u *message, char_u *buttons, int default_button_idx,
+ const bool has_hotkey[], char_u *hotkeys_ptr)
{
*confirm_msg = '\n';
STRCPY(confirm_msg + 1, message);
@@ -3596,7 +3638,6 @@ static void copy_hotkeys_and_msg(const char_u *message, char_u *buttons,
if (idx < HAS_HOTKEY_LEN - 1 && !has_hotkey[++idx]) {
first_hotkey = true;
}
-
} else if (*r == DLG_HOTKEY_CHAR || first_hotkey) {
if (*r == DLG_HOTKEY_CHAR) {
++r;
@@ -3645,21 +3686,24 @@ void display_confirm_msg(void)
int vim_dialog_yesno(int type, char_u *title, char_u *message, int dflt)
{
if (do_dialog(type,
- title == NULL ? (char_u *)_("Question") : title,
- message,
- (char_u *)_("&Yes\n&No"), dflt, NULL, FALSE) == 1)
+ title == NULL ? (char_u *)_("Question") : title,
+ message,
+ (char_u *)_("&Yes\n&No"), dflt, NULL, FALSE) == 1) {
return VIM_YES;
+ }
return VIM_NO;
}
int vim_dialog_yesnocancel(int type, char_u *title, char_u *message, int dflt)
{
switch (do_dialog(type,
- title == NULL ? (char_u *)_("Question") : title,
- message,
- (char_u *)_("&Yes\n&No\n&Cancel"), dflt, NULL, FALSE)) {
- case 1: return VIM_YES;
- case 2: return VIM_NO;
+ title == NULL ? (char_u *)_("Question") : title,
+ message,
+ (char_u *)_("&Yes\n&No\n&Cancel"), dflt, NULL, FALSE)) {
+ case 1:
+ return VIM_YES;
+ case 2:
+ return VIM_NO;
}
return VIM_CANCEL;
}
@@ -3667,14 +3711,18 @@ int vim_dialog_yesnocancel(int type, char_u *title, char_u *message, int dflt)
int vim_dialog_yesnoallcancel(int type, char_u *title, char_u *message, int dflt)
{
switch (do_dialog(type,
- title == NULL ? (char_u *)"Question" : title,
- message,
- (char_u *)_("&Yes\n&No\nSave &All\n&Discard All\n&Cancel"),
- dflt, NULL, FALSE)) {
- case 1: return VIM_YES;
- case 2: return VIM_NO;
- case 3: return VIM_ALL;
- case 4: return VIM_DISCARDALL;
+ title == NULL ? (char_u *)"Question" : title,
+ message,
+ (char_u *)_("&Yes\n&No\nSave &All\n&Discard All\n&Cancel"),
+ dflt, NULL, FALSE)) {
+ case 1:
+ return VIM_YES;
+ case 2:
+ return VIM_NO;
+ case 3:
+ return VIM_ALL;
+ case 4:
+ return VIM_DISCARDALL;
}
return VIM_CANCEL;
}
diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c
index 38d0a7dadf..2dfe5df325 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -7,37 +7,43 @@
#include <assert.h>
#include <inttypes.h>
+#include <limits.h>
#include <stdbool.h>
#include <string.h>
-#include <limits.h>
-#include "nvim/vim.h"
#include "nvim/ascii.h"
-#include "nvim/misc1.h"
+#include "nvim/buffer.h"
+#include "nvim/buffer_updates.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
#include "nvim/diff.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
+#include "nvim/event/stream.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
#include "nvim/fileio.h"
-#include "nvim/func_attr.h"
#include "nvim/fold.h"
+#include "nvim/func_attr.h"
+#include "nvim/garray.h"
#include "nvim/getchar.h"
#include "nvim/indent.h"
#include "nvim/indent_c.h"
-#include "nvim/buffer_updates.h"
#include "nvim/main.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/garray.h"
-#include "nvim/move.h"
+#include "nvim/misc1.h"
#include "nvim/mouse.h"
+#include "nvim/move.h"
#include "nvim/option.h"
+#include "nvim/os/input.h"
+#include "nvim/os/os.h"
+#include "nvim/os/shell.h"
+#include "nvim/os/signal.h"
+#include "nvim/os/time.h"
#include "nvim/os_unix.h"
#include "nvim/quickfix.h"
#include "nvim/regexp.h"
@@ -48,14 +54,8 @@
#include "nvim/tag.h"
#include "nvim/ui.h"
#include "nvim/undo.h"
+#include "nvim/vim.h"
#include "nvim/window.h"
-#include "nvim/os/os.h"
-#include "nvim/os/shell.h"
-#include "nvim/os/signal.h"
-#include "nvim/os/input.h"
-#include "nvim/os/time.h"
-#include "nvim/event/stream.h"
-#include "nvim/buffer.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "misc1.c.generated.h"
@@ -73,23 +73,23 @@ static garray_T ga_users = GA_EMPTY_INIT_VALUE;
* If "include_space" is set, include trailing whitespace while calculating the
* length.
*/
-int get_leader_len(char_u *line, char_u **flags,
- bool backward, bool include_space)
+int get_leader_len(char_u *line, char_u **flags, bool backward, bool include_space)
{
int i, j;
int result;
int got_com = FALSE;
int found_one;
- char_u part_buf[COM_MAX_LEN]; /* buffer for one option part */
- char_u *string; /* pointer to comment string */
- char_u *list;
+ char_u part_buf[COM_MAX_LEN]; // buffer for one option part
+ char_u *string; // pointer to comment string
+ char_u *list;
int middle_match_len = 0;
- char_u *prev_list;
- char_u *saved_flags = NULL;
+ char_u *prev_list;
+ char_u *saved_flags = NULL;
result = i = 0;
- while (ascii_iswhite(line[i])) /* leading white space is ignored */
+ while (ascii_iswhite(line[i])) { // leading white space is ignored
++i;
+ }
/*
* Repeat to match several nested comment strings.
@@ -102,51 +102,60 @@ int get_leader_len(char_u *line, char_u **flags,
for (list = curbuf->b_p_com; *list; ) {
/* Get one option part into part_buf[]. Advance "list" to next
* one. Put "string" at start of string. */
- if (!got_com && flags != NULL)
- *flags = list; /* remember where flags started */
+ if (!got_com && flags != NULL) {
+ *flags = list; // remember where flags started
+ }
prev_list = list;
(void)copy_option_part(&list, part_buf, COM_MAX_LEN, ",");
string = vim_strchr(part_buf, ':');
- if (string == NULL) /* missing ':', ignore this part */
+ if (string == NULL) { // missing ':', ignore this part
continue;
- *string++ = NUL; /* isolate flags from string */
+ }
+ *string++ = NUL; // isolate flags from string
/* If we found a middle match previously, use that match when this
* is not a middle or end. */
if (middle_match_len != 0
&& vim_strchr(part_buf, COM_MIDDLE) == NULL
- && vim_strchr(part_buf, COM_END) == NULL)
+ && vim_strchr(part_buf, COM_END) == NULL) {
break;
+ }
/* When we already found a nested comment, only accept further
* nested comments. */
- if (got_com && vim_strchr(part_buf, COM_NEST) == NULL)
+ if (got_com && vim_strchr(part_buf, COM_NEST) == NULL) {
continue;
+ }
- /* When 'O' flag present and using "O" command skip this one. */
- if (backward && vim_strchr(part_buf, COM_NOBACK) != NULL)
+ // When 'O' flag present and using "O" command skip this one.
+ if (backward && vim_strchr(part_buf, COM_NOBACK) != NULL) {
continue;
+ }
/* Line contents and string must match.
* When string starts with white space, must have some white space
* (but the amount does not need to match, there might be a mix of
* TABs and spaces). */
if (ascii_iswhite(string[0])) {
- if (i == 0 || !ascii_iswhite(line[i - 1]))
- continue; /* missing white space */
- while (ascii_iswhite(string[0]))
+ if (i == 0 || !ascii_iswhite(line[i - 1])) {
+ continue; // missing white space
+ }
+ while (ascii_iswhite(string[0])) {
++string;
+ }
}
- for (j = 0; string[j] != NUL && string[j] == line[i + j]; ++j)
+ for (j = 0; string[j] != NUL && string[j] == line[i + j]; ++j) {
;
- if (string[j] != NUL)
- continue; /* string doesn't match */
-
+ }
+ if (string[j] != NUL) {
+ continue; // string doesn't match
+ }
/* When 'b' flag used, there must be white space or an
* end-of-line after the string in the line. */
if (vim_strchr(part_buf, COM_BLANK) != NULL
- && !ascii_iswhite(line[i + j]) && line[i + j] != NUL)
+ && !ascii_iswhite(line[i + j]) && line[i + j] != NUL) {
continue;
+ }
/* We have found a match, stop searching unless this is a middle
* comment. The middle comment can be a substring of the end
@@ -160,13 +169,15 @@ int get_leader_len(char_u *line, char_u **flags,
}
continue;
}
- if (middle_match_len != 0 && j > middle_match_len)
+ if (middle_match_len != 0 && j > middle_match_len) {
/* Use this match instead of the middle match, since it's a
* longer thus better match. */
middle_match_len = 0;
+ }
- if (middle_match_len == 0)
+ if (middle_match_len == 0) {
i += j;
+ }
found_one = TRUE;
break;
}
@@ -174,29 +185,34 @@ int get_leader_len(char_u *line, char_u **flags,
if (middle_match_len != 0) {
/* Use the previously found middle match after failing to find a
* match with an end. */
- if (!got_com && flags != NULL)
+ if (!got_com && flags != NULL) {
*flags = saved_flags;
+ }
i += middle_match_len;
found_one = TRUE;
}
- /* No match found, stop scanning. */
- if (!found_one)
+ // No match found, stop scanning.
+ if (!found_one) {
break;
+ }
result = i;
- /* Include any trailing white space. */
- while (ascii_iswhite(line[i]))
+ // Include any trailing white space.
+ while (ascii_iswhite(line[i])) {
++i;
+ }
- if (include_space)
+ if (include_space) {
result = i;
+ }
- /* If this comment doesn't nest, stop here. */
+ // If this comment doesn't nest, stop here.
got_com = TRUE;
- if (vim_strchr(part_buf, COM_NEST) == NULL)
+ if (vim_strchr(part_buf, COM_NEST) == NULL) {
break;
+ }
}
return result;
}
@@ -213,12 +229,12 @@ int get_last_leader_offset(char_u *line, char_u **flags)
int result = -1;
int i, j;
int lower_check_bound = 0;
- char_u *string;
- char_u *com_leader;
- char_u *com_flags;
- char_u *list;
+ char_u *string;
+ char_u *com_leader;
+ char_u *com_flags;
+ char_u *list;
int found_one;
- char_u part_buf[COM_MAX_LEN]; /* buffer for one option part */
+ char_u part_buf[COM_MAX_LEN]; // buffer for one option part
/*
* Repeat to match several nested comment strings.
@@ -242,7 +258,7 @@ int get_last_leader_offset(char_u *line, char_u **flags)
* happen. */
continue;
}
- *string++ = NUL; /* Isolate flags from string. */
+ *string++ = NUL; // Isolate flags from string.
com_leader = string;
/*
@@ -252,16 +268,19 @@ int get_last_leader_offset(char_u *line, char_u **flags)
* TABs and spaces).
*/
if (ascii_iswhite(string[0])) {
- if (i == 0 || !ascii_iswhite(line[i - 1]))
+ if (i == 0 || !ascii_iswhite(line[i - 1])) {
continue;
+ }
while (ascii_iswhite(*string)) {
string++;
}
}
- for (j = 0; string[j] != NUL && string[j] == line[i + j]; ++j)
+ for (j = 0; string[j] != NUL && string[j] == line[i + j]; ++j) {
/* do nothing */;
- if (string[j] != NUL)
+ }
+ if (string[j] != NUL) {
continue;
+ }
/*
* When 'b' flag used, there must be white space or an
@@ -290,23 +309,25 @@ int get_last_leader_offset(char_u *line, char_u **flags)
*/
found_one = TRUE;
- if (flags)
+ if (flags) {
*flags = flags_save;
+ }
com_flags = flags_save;
break;
}
if (found_one) {
- char_u part_buf2[COM_MAX_LEN]; /* buffer for one option part */
+ char_u part_buf2[COM_MAX_LEN]; // buffer for one option part
int len1, len2, off;
result = i;
/*
* If this comment nests, continue searching.
*/
- if (vim_strchr(part_buf, COM_NEST) != NULL)
+ if (vim_strchr(part_buf, COM_NEST) != NULL) {
continue;
+ }
lower_check_bound = i;
@@ -316,31 +337,36 @@ int get_last_leader_offset(char_u *line, char_u **flags)
* the comment leader correctly.
*/
- while (ascii_iswhite(*com_leader))
+ while (ascii_iswhite(*com_leader)) {
++com_leader;
+ }
len1 = (int)STRLEN(com_leader);
for (list = curbuf->b_p_com; *list; ) {
char_u *flags_save = list;
(void)copy_option_part(&list, part_buf2, COM_MAX_LEN, ",");
- if (flags_save == com_flags)
+ if (flags_save == com_flags) {
continue;
+ }
string = vim_strchr(part_buf2, ':');
++string;
- while (ascii_iswhite(*string))
+ while (ascii_iswhite(*string)) {
++string;
+ }
len2 = (int)STRLEN(string);
- if (len2 == 0)
+ if (len2 == 0) {
continue;
+ }
/* Now we have to verify whether string ends with a substring
* beginning the com_leader. */
for (off = (len2 > i ? i : len2); off > 0 && off + len1 > len2; ) {
--off;
if (!STRNCMP(string + off, com_leader, len2 - off)) {
- if (i - off < lower_check_bound)
+ if (i - off < lower_check_bound) {
lower_check_bound = i - off;
+ }
}
}
}
@@ -349,178 +375,6 @@ int get_last_leader_offset(char_u *line, char_u **flags)
return result;
}
-/*
- * Return the number of window lines occupied by buffer line "lnum".
- */
-int plines(const linenr_T lnum)
-{
- return plines_win(curwin, lnum, true);
-}
-
-int plines_win(
- win_T *const wp,
- const linenr_T lnum,
- const bool winheight // when true limit to window height
-)
-{
- /* Check for filler lines above this buffer line. When folded the result
- * is one line anyway. */
- return plines_win_nofill(wp, lnum, winheight) + diff_check_fill(wp, lnum);
-}
-
-int plines_nofill(const linenr_T lnum)
-{
- return plines_win_nofill(curwin, lnum, true);
-}
-
-int plines_win_nofill(
- win_T *const wp,
- const linenr_T lnum,
- const bool winheight // when true limit to window height
-)
-{
- if (!wp->w_p_wrap) {
- return 1;
- }
-
- if (wp->w_width_inner == 0) {
- return 1;
- }
-
- // A folded lines is handled just like an empty line.
- if (lineFolded(wp, lnum)) {
- return 1;
- }
-
- const int lines = plines_win_nofold(wp, lnum);
- if (winheight && lines > wp->w_height_inner) {
- return wp->w_height_inner;
- }
- return lines;
-}
-
-/*
- * Return number of window lines physical line "lnum" will occupy in window
- * "wp". Does not care about folding, 'wrap' or 'diff'.
- */
-int plines_win_nofold(win_T *wp, linenr_T lnum)
-{
- char_u *s;
- unsigned int col;
- int width;
-
- s = ml_get_buf(wp->w_buffer, lnum, FALSE);
- if (*s == NUL) /* empty line */
- return 1;
- col = win_linetabsize(wp, s, MAXCOL);
-
- // If list mode is on, then the '$' at the end of the line may take up one
- // extra column.
- if (wp->w_p_list && wp->w_p_lcs_chars.eol != NUL) {
- col += 1;
- }
-
- /*
- * Add column offset for 'number', 'relativenumber' and 'foldcolumn'.
- */
- width = wp->w_width_inner - win_col_off(wp);
- if (width <= 0 || col > 32000) {
- return 32000; // bigger than the number of screen columns
- }
- if (col <= (unsigned int)width) {
- return 1;
- }
- col -= (unsigned int)width;
- width += win_col_off2(wp);
- assert(col <= INT_MAX && (int)col < INT_MAX - (width -1));
- return ((int)col + (width - 1)) / width + 1;
-}
-
-/*
- * Like plines_win(), but only reports the number of physical screen lines
- * used from the start of the line to the given column number.
- */
-int plines_win_col(win_T *wp, linenr_T lnum, long column)
-{
- // Check for filler lines above this buffer line. When folded the result
- // is one line anyway.
- int lines = diff_check_fill(wp, lnum);
-
- if (!wp->w_p_wrap)
- return lines + 1;
-
- if (wp->w_width_inner == 0) {
- return lines + 1;
- }
-
- char_u *line = ml_get_buf(wp->w_buffer, lnum, false);
- char_u *s = line;
-
- colnr_T col = 0;
- while (*s != NUL && --column >= 0) {
- col += win_lbr_chartabsize(wp, line, s, col, NULL);
- MB_PTR_ADV(s);
- }
-
- // If *s is a TAB, and the TAB is not displayed as ^I, and we're not in
- // INSERT mode, then col must be adjusted so that it represents the last
- // screen position of the TAB. This only fixes an error when the TAB wraps
- // from one screen line to the next (when 'columns' is not a multiple of
- // 'ts') -- webb.
- if (*s == TAB && (State & NORMAL)
- && (!wp->w_p_list || wp->w_p_lcs_chars.tab1)) {
- col += win_lbr_chartabsize(wp, line, s, col, NULL) - 1;
- }
-
- // Add column offset for 'number', 'relativenumber', 'foldcolumn', etc.
- int width = wp->w_width_inner - win_col_off(wp);
- if (width <= 0) {
- return 9999;
- }
-
- lines += 1;
- if (col > width)
- lines += (col - width) / (width + win_col_off2(wp)) + 1;
- return lines;
-}
-
-/// Get the number of screen lines lnum takes up. This takes care of
-/// both folds and topfill, and limits to the current window height.
-///
-/// @param[in] wp window line is in
-/// @param[in] lnum line number
-/// @param[out] nextp if not NULL, the line after a fold
-/// @param[out] foldedp if not NULL, whether lnum is on a fold
-/// @param[in] cache whether to use the window's cache for folds
-///
-/// @return the total number of screen lines
-int plines_win_full(win_T *wp, linenr_T lnum, linenr_T *const nextp,
- bool *const foldedp, const bool cache)
-{
- bool folded = hasFoldingWin(wp, lnum, NULL, nextp, cache, NULL);
- if (foldedp) {
- *foldedp = folded;
- }
- if (folded) {
- return 1;
- } else if (lnum == wp->w_topline) {
- return plines_win_nofill(wp, lnum, true) + wp->w_topfill;
- }
- return plines_win(wp, lnum, true);
-}
-
-int plines_m_win(win_T *wp, linenr_T first, linenr_T last)
-{
- int count = 0;
-
- while (first <= last) {
- linenr_T next = first;
- count += plines_win_full(wp, first, &next, NULL, false);
- first = next + 1;
- }
- return count;
-}
-
int gchar_pos(pos_T *pos)
FUNC_ATTR_NONNULL_ARG(1)
{
@@ -533,7 +387,7 @@ int gchar_pos(pos_T *pos)
/*
* check_status: called when the status bars for the buffer 'buf'
- * need to be updated
+ * need to be updated
*/
void check_status(buf_T *buf)
{
@@ -631,7 +485,7 @@ int is_mouse_key(int c)
*/
int get_keystroke(MultiQueue *events)
{
- char_u *buf = NULL;
+ char_u *buf = NULL;
int buflen = 150;
int maxlen;
int len = 0;
@@ -665,9 +519,9 @@ int get_keystroke(MultiQueue *events)
n = fix_input_buffer(buf + len, n);
len += n;
waited = 0;
- } else if (len > 0)
- ++waited; /* keep track of the waiting time */
-
+ } else if (len > 0) {
+ ++waited; // keep track of the waiting time
+ }
if (n > 0) { // found a termcode: adjust length
len = n;
}
@@ -675,19 +529,20 @@ int get_keystroke(MultiQueue *events)
continue;
}
- /* Handle modifier and/or special key code. */
+ // Handle modifier and/or special key code.
n = buf[0];
if (n == K_SPECIAL) {
n = TO_SPECIAL(buf[1], buf[2]);
if (buf[1] == KS_MODIFIER
|| n == K_IGNORE
- || (is_mouse_key(n) && n != K_LEFTMOUSE)
- ) {
- if (buf[1] == KS_MODIFIER)
+ || (is_mouse_key(n) && n != K_LEFTMOUSE)) {
+ if (buf[1] == KS_MODIFIER) {
mod_mask = buf[2];
+ }
len -= 3;
- if (len > 0)
+ if (len > 0) {
memmove(buf, buf + 3, (size_t)len);
+ }
continue;
}
break;
@@ -706,27 +561,25 @@ int get_keystroke(MultiQueue *events)
return n;
}
-/*
- * Get a number from the user.
- * When "mouse_used" is not NULL allow using the mouse.
- */
-int
-get_number (
- int colon, /* allow colon to abort */
- int *mouse_used
-)
+/// Get a number from the user.
+/// When "mouse_used" is not NULL allow using the mouse.
+///
+/// @param colon allow colon to abort
+int get_number(int colon, int *mouse_used)
{
int n = 0;
int c;
int typed = 0;
- if (mouse_used != NULL)
+ if (mouse_used != NULL) {
*mouse_used = FALSE;
+ }
/* When not printing messages, the user won't know what to type, return a
* zero (as if CR was hit). */
- if (msg_silent != 0)
+ if (msg_silent != 0) {
return 0;
+ }
no_mapping++;
for (;; ) {
@@ -748,10 +601,11 @@ get_number (
break;
} else if (n == 0 && c == ':' && colon) {
stuffcharReadbuff(':');
- if (!exmode_active)
+ if (!exmode_active) {
cmdline_row = msg_row;
- skip_redraw = TRUE; /* skip redraw once */
- do_redraw = FALSE;
+ }
+ skip_redraw = true; // skip redraw once
+ do_redraw = false;
break;
} else if (c == Ctrl_C || c == ESC || c == 'q') {
n = 0;
@@ -815,41 +669,46 @@ void msgmore(long n)
{
long pn;
- if (global_busy /* no messages now, wait until global is finished */
- || !messaging()) /* 'lazyredraw' set, don't do messages now */
+ if (global_busy // no messages now, wait until global is finished
+ || !messaging()) { // 'lazyredraw' set, don't do messages now
return;
+ }
/* We don't want to overwrite another important message, but do overwrite
* a previous "more lines" or "fewer lines" message, so that "5dd" and
* then "put" reports the last action. */
- if (keep_msg != NULL && !keep_msg_more)
+ if (keep_msg != NULL && !keep_msg_more) {
return;
+ }
- if (n > 0)
+ if (n > 0) {
pn = n;
- else
+ } else {
pn = -n;
+ }
if (pn > p_report) {
if (pn == 1) {
- if (n > 0)
+ if (n > 0) {
STRLCPY(msg_buf, _("1 more line"), MSG_BUF_LEN);
- else
+ } else {
STRLCPY(msg_buf, _("1 line less"), MSG_BUF_LEN);
+ }
} else {
- if (n > 0)
+ if (n > 0) {
vim_snprintf((char *)msg_buf, MSG_BUF_LEN,
- _("%" PRId64 " more lines"), (int64_t)pn);
- else
+ _("%" PRId64 " more lines"), (int64_t)pn);
+ } else {
vim_snprintf((char *)msg_buf, MSG_BUF_LEN,
- _("%" PRId64 " fewer lines"), (int64_t)pn);
+ _("%" PRId64 " fewer lines"), (int64_t)pn);
+ }
}
if (got_int) {
xstrlcat((char *)msg_buf, _(" (Interrupted)"), MSG_BUF_LEN);
}
if (msg(msg_buf)) {
set_keep_msg(msg_buf, 0);
- keep_msg_more = TRUE;
+ keep_msg_more = true;
}
}
}
@@ -924,7 +783,7 @@ static void init_users(void)
}
lazy_init_done = TRUE;
-
+
os_get_usernames(&ga_users);
}
@@ -934,8 +793,9 @@ static void init_users(void)
char_u *get_users(expand_T *xp, int idx)
{
init_users();
- if (idx < ga_users.ga_len)
+ if (idx < ga_users.ga_len) {
return ((char_u **)ga_users.ga_data)[idx];
+ }
return NULL;
}
@@ -952,10 +812,12 @@ int match_user(char_u *name)
init_users();
for (int i = 0; i < ga_users.ga_len; i++) {
- if (STRCMP(((char_u **)ga_users.ga_data)[i], name) == 0)
- return 2; /* full match */
- if (STRNCMP(((char_u **)ga_users.ga_data)[i], name, n) == 0)
- result = 1; /* partial match */
+ if (STRCMP(((char_u **)ga_users.ga_data)[i], name) == 0) {
+ return 2; // full match
+ }
+ if (STRNCMP(((char_u **)ga_users.ga_data)[i], name, n) == 0) {
+ result = 1; // partial match
+ }
}
return result;
}
@@ -1012,7 +874,7 @@ void preserve_exit(void)
*/
#ifndef BREAKCHECK_SKIP
-# define BREAKCHECK_SKIP 1000
+# define BREAKCHECK_SKIP 1000
#endif
static int breakcheck_count = 0;
@@ -1093,8 +955,7 @@ int call_shell(char_u *cmd, ShellOpts opts, char_u *extra_shell_arg)
/// @param ret_len length of the stdout
///
/// @return an allocated string, or NULL for error.
-char_u *get_cmd_output(char_u *cmd, char_u *infile, ShellOpts flags,
- size_t *ret_len)
+char_u *get_cmd_output(char_u *cmd, char_u *infile, ShellOpts flags, size_t *ret_len)
{
char_u *buffer = NULL;
@@ -1142,12 +1003,14 @@ char_u *get_cmd_output(char_u *cmd, char_u *infile, ShellOpts flags,
EMSG2(_(e_notread), tempname);
XFREE_CLEAR(buffer);
} else if (ret_len == NULL) {
- /* Change NUL into SOH, otherwise the string is truncated. */
- for (i = 0; i < len; ++i)
- if (buffer[i] == NUL)
+ // Change NUL into SOH, otherwise the string is truncated.
+ for (i = 0; i < len; ++i) {
+ if (buffer[i] == NUL) {
buffer[i] = 1;
+ }
+ }
- buffer[len] = NUL; /* make sure the buffer is terminated */
+ buffer[len] = NUL; // make sure the buffer is terminated
} else {
*ret_len = len;
}
@@ -1163,10 +1026,12 @@ done:
*/
void FreeWild(int count, char_u **files)
{
- if (count <= 0 || files == NULL)
+ if (count <= 0 || files == NULL) {
return;
- while (count--)
+ }
+ while (count--) {
xfree(files[count]);
+ }
xfree(files);
}
diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c
index 4c0339e5f4..cf463fd40a 100644
--- a/src/nvim/mouse.c
+++ b/src/nvim/mouse.c
@@ -3,25 +3,26 @@
#include <stdbool.h>
-#include "nvim/mouse.h"
-#include "nvim/vim.h"
#include "nvim/ascii.h"
-#include "nvim/window.h"
+#include "nvim/buffer_defs.h"
+#include "nvim/charset.h"
+#include "nvim/cursor.h"
+#include "nvim/diff.h"
+#include "nvim/fold.h"
+#include "nvim/memline.h"
+#include "nvim/misc1.h"
+#include "nvim/mouse.h"
+#include "nvim/move.h"
+#include "nvim/os_unix.h"
+#include "nvim/plines.h"
+#include "nvim/screen.h"
#include "nvim/state.h"
#include "nvim/strings.h"
-#include "nvim/screen.h"
#include "nvim/syntax.h"
#include "nvim/ui.h"
#include "nvim/ui_compositor.h"
-#include "nvim/os_unix.h"
-#include "nvim/fold.h"
-#include "nvim/diff.h"
-#include "nvim/move.h"
-#include "nvim/misc1.h"
-#include "nvim/cursor.h"
-#include "nvim/buffer_defs.h"
-#include "nvim/memline.h"
-#include "nvim/charset.h"
+#include "nvim/vim.h"
+#include "nvim/window.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "mouse.c.generated.h"
@@ -30,33 +31,34 @@
static linenr_T orig_topline = 0;
static int orig_topfill = 0;
-// Move the cursor to the specified row and column on the screen.
-// Change current window if necessary. Returns an integer with the
-// CURSOR_MOVED bit set if the cursor has moved or unset otherwise.
-//
-// The MOUSE_FOLD_CLOSE bit is set when clicked on the '-' in a fold column.
-// The MOUSE_FOLD_OPEN bit is set when clicked on the '+' in a fold column.
-//
-// If flags has MOUSE_FOCUS, then the current window will not be changed, and
-// if the mouse is outside the window then the text will scroll, or if the
-// 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.
-// 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.
-//
-// If flags has MOUSE_DID_MOVE, nothing is done if the mouse didn't move since
-// the last call.
-//
-// If flags has MOUSE_SETPOS, nothing is done, only the current position is
-// remembered.
-int jump_to_mouse(int flags,
- bool *inclusive, // used for inclusive operator, can be NULL
- int which_button) // MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE
+/// Move the cursor to the specified row and column on the screen.
+/// Change current window if necessary. Returns an integer with the
+/// CURSOR_MOVED bit set if the cursor has moved or unset otherwise.
+///
+/// The MOUSE_FOLD_CLOSE bit is set when clicked on the '-' in a fold column.
+/// The MOUSE_FOLD_OPEN bit is set when clicked on the '+' in a fold column.
+///
+/// If flags has MOUSE_FOCUS, then the current window will not be changed, and
+/// if the mouse is outside the window then the text will scroll, or if the
+/// 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.
+/// 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.
+///
+/// If flags has MOUSE_DID_MOVE, nothing is done if the mouse didn't move since
+/// the last call.
+///
+/// If flags has MOUSE_SETPOS, nothing is done, only the current position is
+/// remembered.
+///
+/// @param inclusive used for inclusive operator, can be NULL
+/// @param which_button MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE
+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
@@ -65,7 +67,7 @@ int jump_to_mouse(int flags,
static win_T *dragwin = NULL; // window being dragged
static int did_drag = false; // drag was noticed
- win_T *wp, *old_curwin;
+ win_T *wp, *old_curwin;
pos_T old_cursor;
int count;
bool first;
@@ -80,8 +82,9 @@ int jump_to_mouse(int flags,
if (flags & MOUSE_RELEASED) {
// On button release we may change window focus if positioned on a
// status line and no dragging happened.
- if (dragwin != NULL && !did_drag)
+ if (dragwin != NULL && !did_drag) {
flags &= ~(MOUSE_FOCUS | MOUSE_DID_MOVE);
+ }
dragwin = NULL;
did_drag = false;
}
@@ -108,15 +111,16 @@ retnomove:
prev_row = mouse_row;
prev_col = mouse_col;
- if (flags & MOUSE_SETPOS)
+ if (flags & MOUSE_SETPOS) {
goto retnomove; // ugly goto...
-
+ }
old_curwin = curwin;
old_cursor = curwin->w_cursor;
if (!(flags & MOUSE_FOCUS)) {
- if (row < 0 || col < 0) // check if it makes sense
+ if (row < 0 || col < 0) { // check if it makes sense
return IN_UNKNOWN;
+ }
// find the window where the row is in
wp = mouse_find_win(&grid, &row, &col);
@@ -150,10 +154,11 @@ retnomove:
// The rightmost character of the status line might be a vertical
// separator character if there is no connecting window to the right.
if (on_status_line && on_sep_line) {
- if (stl_connected(wp))
+ if (stl_connected(wp)) {
on_sep_line = 0;
- else
+ } else {
on_status_line = 0;
+ }
}
// Before jumping to another buffer, or moving the cursor for a left
@@ -180,28 +185,32 @@ retnomove:
// Only change window focus when not clicking on or dragging the
// status line. Do change focus when releasing the mouse button
// (MOUSE_FOCUS was set above if we dragged first).
- if (dragwin == NULL || (flags & MOUSE_RELEASED))
+ if (dragwin == NULL || (flags & MOUSE_RELEASED)) {
win_enter(wp, true); // can make wp invalid!
+ }
// set topline, to be able to check for double click ourselves
- if (curwin != old_curwin)
+ if (curwin != old_curwin) {
set_mouse_topline(curwin);
+ }
if (on_status_line) { // In (or below) status line
// Don't use start_arrow() if we're in the same window
- if (curwin == old_curwin)
+ if (curwin == old_curwin) {
return IN_STATUS_LINE;
- else
+ } else {
return IN_STATUS_LINE | CURSOR_MOVED;
+ }
}
if (on_sep_line) { // In (or below) status line
// Don't use start_arrow() if we're in the same window
- if (curwin == old_curwin)
+ if (curwin == old_curwin) {
return IN_SEP_LINE;
- else
+ } else {
return IN_SEP_LINE | CURSOR_MOVED;
+ }
}
curwin->w_cursor.lnum = curwin->w_topline;
- } else if (on_status_line && which_button == MOUSE_LEFT) {
+ } else if (on_status_line && which_button == MOUSE_LEFT) {
if (dragwin != NULL) {
// Drag the status line
count = row - dragwin->w_winrow - dragwin->w_height + 1
@@ -210,7 +219,7 @@ retnomove:
did_drag |= count;
}
return IN_STATUS_LINE; // Cursor didn't move
- } else if (on_sep_line && which_button == MOUSE_LEFT) {
+ } else if (on_sep_line && which_button == MOUSE_LEFT) {
if (dragwin != NULL) {
// Drag the separator column
count = col - dragwin->w_wincol - dragwin->w_width + 1
@@ -227,25 +236,23 @@ retnomove:
redraw_curbuf_later(INVERTED); // delete the inversion
}
-
- row -= curwin->w_winrow;
- col -= curwin->w_wincol;
-
// When clicking beyond the end of the window, scroll the screen.
// Scroll by however many rows outside the window we are.
if (row < 0) {
count = 0;
for (first = true; curwin->w_topline > 1; ) {
- if (curwin->w_topfill < diff_check(curwin, curwin->w_topline))
- ++count;
- else
- count += plines(curwin->w_topline - 1);
- if (!first && count > -row)
+ if (curwin->w_topfill < win_get_fill(curwin, curwin->w_topline)) {
+ count++;
+ } else {
+ count += plines_win(curwin, curwin->w_topline - 1, true);
+ }
+ if (!first && count > -row) {
break;
+ }
first = false;
(void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
- if (curwin->w_topfill < diff_check(curwin, curwin->w_topline)) {
- ++curwin->w_topfill;
+ if (curwin->w_topfill < win_get_fill(curwin, curwin->w_topline)) {
+ curwin->w_topfill++;
} else {
--curwin->w_topline;
curwin->w_topfill = 0;
@@ -256,13 +263,13 @@ retnomove:
~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
redraw_later(curwin, VALID);
row = 0;
- } else if (row >= curwin->w_height_inner) {
+ } else if (row >= curwin->w_height_inner) {
count = 0;
for (first = true; curwin->w_topline < curbuf->b_ml.ml_line_count; ) {
if (curwin->w_topfill > 0) {
++count;
} else {
- count += plines(curwin->w_topline);
+ count += plines_win(curwin, curwin->w_topline, true);
}
if (!first && count > row - curwin->w_height_inner + 1) {
@@ -276,11 +283,10 @@ retnomove:
}
if (curwin->w_topfill > 0) {
- --curwin->w_topfill;
+ curwin->w_topfill--;
} else {
- ++curwin->w_topline;
- curwin->w_topfill =
- diff_check_fill(curwin, curwin->w_topline);
+ curwin->w_topline++;
+ curwin->w_topfill = win_get_fill(curwin, curwin->w_topline);
}
}
check_topfill(curwin, false);
@@ -288,7 +294,7 @@ retnomove:
curwin->w_valid &=
~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
row = curwin->w_height_inner - 1;
- } else if (row == 0) {
+ } else if (row == 0) {
// When dragging the mouse, while the text has been scrolled up as
// far as it goes, moving the mouse in the top line should scroll
// the text down (done later when recomputing w_topline).
@@ -366,12 +372,12 @@ bool mouse_comp_pos(win_T *win, int *rowp, int *colp, linenr_T *lnump)
while (row > 0) {
// Don't include filler lines in "count"
- if (win->w_p_diff
+ if (win_may_fill(win)
&& !hasFoldingWin(win, lnum, NULL, NULL, true, NULL)) {
if (lnum == win->w_topline) {
row -= win->w_topfill;
} else {
- row -= diff_check_fill(win, lnum);
+ row -= win_get_fill(win, lnum);
}
count = plines_win_nofill(win, lnum, true);
} else {
@@ -395,8 +401,9 @@ bool mouse_comp_pos(win_T *win, int *rowp, int *colp, linenr_T *lnump)
if (!retval) {
// Compute the column without wrapping.
off = win_col_off(win) - win_col_off2(win);
- if (col < off)
+ if (col < off) {
col = off;
+ }
col += row * (win->w_width_inner - off);
// add skip column (for long wrapping line)
col += win->w_skipcol;
@@ -432,23 +439,26 @@ win_T *mouse_find_win(int *gridp, int *rowp, int *colp)
}
- frame_T *fp;
+ frame_T *fp;
fp = topframe;
*rowp -= firstwin->w_winrow;
for (;; ) {
- if (fp->fr_layout == FR_LEAF)
+ if (fp->fr_layout == FR_LEAF) {
break;
+ }
if (fp->fr_layout == FR_ROW) {
for (fp = fp->fr_child; fp->fr_next != NULL; fp = fp->fr_next) {
- if (*colp < fp->fr_width)
+ if (*colp < fp->fr_width) {
break;
+ }
*colp -= fp->fr_width;
}
} else { // fr_layout == FR_COL
for (fp = fp->fr_child; fp->fr_next != NULL; fp = fp->fr_next) {
- if (*rowp < fp->fr_height)
+ if (*rowp < fp->fr_height) {
break;
+ }
*rowp -= fp->fr_height;
}
}
@@ -522,7 +532,7 @@ static colnr_T scroll_line_len(linenr_T lnum)
char_u *line = ml_get(lnum);
if (*line != NUL) {
for (;;) {
- int numchar = chartabsize(line, col);
+ int numchar = win_chartabsize(curwin, line, col);
MB_PTR_ADV(line);
if (*line == NUL) { // don't count the last character
break;
@@ -570,27 +580,26 @@ static linenr_T find_longest_lnum(void)
return ret;
}
-///
-/// Do a horizontal scroll. Return TRUE if the cursor moved, FALSE otherwise.
-///
+/// Do a horizontal scroll.
+/// @return true if the cursor moved, false otherwise.
bool mouse_scroll_horiz(int dir)
{
if (curwin->w_p_wrap) {
- return false;
+ return false;
}
int step = 6;
if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)) {
- step = curwin->w_width_inner;
+ step = curwin->w_width_inner;
}
int leftcol = curwin->w_leftcol + (dir == MSCR_RIGHT ? -step : +step);
if (leftcol < 0) {
- leftcol = 0;
+ leftcol = 0;
}
if (curwin->w_leftcol == leftcol) {
- return false;
+ return false;
}
curwin->w_leftcol = (colnr_T)leftcol;
@@ -599,8 +608,8 @@ bool mouse_scroll_horiz(int dir)
// longest visible line.
if (!virtual_active()
&& (colnr_T)leftcol > scroll_line_len(curwin->w_cursor.lnum)) {
- curwin->w_cursor.lnum = find_longest_lnum();
- curwin->w_cursor.col = 0;
+ curwin->w_cursor.lnum = find_longest_lnum();
+ curwin->w_cursor.col = 0;
}
return leftcol_changed();
@@ -619,10 +628,10 @@ static int mouse_adjust_click(win_T *wp, int row, int col)
// scanned *up to* `col`, nudging it left or right when concealed characters
// are encountered.
//
- // chartabsize() is used to keep track of the virtual column position relative
- // to the line's bytes. For example: if col == 9 and the line starts with a
- // tab that's 8 columns wide, we would want the cursor to be highlighting the
- // second byte, not the ninth.
+ // win_chartabsize() is used to keep track of the virtual column position
+ // relative to the line's bytes. For example: if col == 9 and the line
+ // starts with a tab that's 8 columns wide, we would want the cursor to be
+ // highlighting the second byte, not the ninth.
linenr_T lnum = wp->w_cursor.lnum;
char_u *line = ml_get(lnum);
@@ -646,7 +655,7 @@ static int mouse_adjust_click(win_T *wp, int row, int col)
// checked for concealed characters.
vcol = 0;
while (vcol < offset && *ptr != NUL) {
- vcol += chartabsize(ptr, vcol);
+ vcol += win_chartabsize(curwin, ptr, vcol);
ptr += utfc_ptr2len(ptr);
}
@@ -657,7 +666,7 @@ static int mouse_adjust_click(win_T *wp, int row, int col)
vcol = offset;
ptr_end = ptr_row_offset;
while (vcol < col && *ptr_end != NUL) {
- vcol += chartabsize(ptr_end, vcol);
+ vcol += win_chartabsize(curwin, ptr_end, vcol);
ptr_end += utfc_ptr2len(ptr_end);
}
@@ -672,7 +681,7 @@ static int mouse_adjust_click(win_T *wp, int row, int col)
#define decr() nudge--; ptr_end -= utfc_ptr2len(ptr_end)
while (ptr < ptr_end && *ptr != NUL) {
- cwidth = chartabsize(ptr, vcol);
+ cwidth = win_chartabsize(curwin, ptr, vcol);
vcol += cwidth;
if (cwidth > 1 && *ptr == '\t' && nudge > 0) {
// A tab will "absorb" any previous adjustments.
@@ -721,14 +730,20 @@ int mouse_check_fold(void)
int click_row = mouse_row;
int click_col = mouse_col;
int mouse_char = ' ';
+ int max_row = Rows;
+ int max_col = Columns;
+ int multigrid = ui_has(kUIMultigrid);
win_T *wp;
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;
+ }
- if (wp && mouse_row >= 0 && mouse_row < Rows
- && mouse_col >= 0 && mouse_col <= Columns) {
- int multigrid = ui_has(kUIMultigrid);
+ if (wp && mouse_row >= 0 && mouse_row < max_row
+ && mouse_col >= 0 && mouse_col < max_col) {
ScreenGrid *gp = multigrid ? &wp->w_grid_alloc : &default_grid;
int fdc = win_fdccol_count(wp);
int row = multigrid && mouse_grid == 0 ? click_row : mouse_row;
diff --git a/src/nvim/move.c b/src/nvim/move.c
index 1210a3365a..ca3dd34204 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -17,7 +17,7 @@
#include <stdbool.h>
#include "nvim/ascii.h"
-#include "nvim/move.h"
+#include "nvim/buffer.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
#include "nvim/diff.h"
@@ -26,16 +26,18 @@
#include "nvim/mbyte.h"
#include "nvim/memline.h"
#include "nvim/misc1.h"
+#include "nvim/move.h"
#include "nvim/option.h"
+#include "nvim/plines.h"
#include "nvim/popupmnu.h"
#include "nvim/screen.h"
#include "nvim/strings.h"
#include "nvim/window.h"
typedef struct {
- linenr_T lnum; /* line number */
- int fill; /* filler lines */
- int height; /* height of added line */
+ linenr_T lnum; // line number
+ int fill; // filler lines
+ int height; // height of added line
} lineoff_T;
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -83,7 +85,7 @@ static void comp_botline(win_T *wp)
lnum = last;
}
- /* wp->w_botline is the line that is just below the window */
+ // wp->w_botline is the line that is just below the window
wp->w_botline = lnum;
wp->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
wp->w_viewport_invalid = true;
@@ -172,7 +174,7 @@ void update_topline(win_T *wp)
old_topfill = wp->w_topfill;
// If the buffer is empty, always set topline to 1.
- if (BUFEMPTY()) { // special case - file is empty
+ if (buf_is_empty(curbuf)) { // special case - file is empty
if (wp->w_topline != 1) {
redraw_later(wp, NOT_VALID);
}
@@ -195,7 +197,7 @@ void update_topline(win_T *wp)
}
}
// Check if there are more filler lines than allowed.
- if (!check_topline && wp->w_topfill > diff_check_fill(wp, wp->w_topline)) {
+ if (!check_topline && wp->w_topfill > win_get_fill(wp, wp->w_topline)) {
check_topline = true;
}
@@ -272,8 +274,7 @@ void update_topline(win_T *wp)
n += wp->w_filler_rows;
loff.height = 0;
while (loff.lnum < wp->w_botline
- && (loff.lnum + 1 < wp->w_botline || loff.fill == 0)
- ) {
+ && (loff.lnum + 1 < wp->w_botline || loff.fill == 0)) {
n += loff.height;
if (n >= *so_ptr) {
break;
@@ -285,7 +286,7 @@ void update_topline(win_T *wp)
check_botline = false;
}
} else {
- /* sufficient context, no need to scroll */
+ // sufficient context, no need to scroll
check_botline = false;
}
}
@@ -323,8 +324,7 @@ void update_topline(win_T *wp)
* Need to redraw when topline changed.
*/
if (wp->w_topline != old_topline
- || wp->w_topfill != old_topfill
- ) {
+ || wp->w_topfill != old_topfill) {
dollar_vcol = -1;
if (wp->w_skipcol != 0) {
wp->w_skipcol = 0;
@@ -344,7 +344,7 @@ void update_topline(win_T *wp)
/*
* Update win->w_topline to move the cursor onto the screen.
*/
-void update_topline_win(win_T* win)
+void update_topline_win(win_T * win)
{
win_T *save_curwin;
switch_win(&save_curwin, NULL, win, NULL, true);
@@ -372,8 +372,7 @@ static bool check_top_offset(void)
{
long so = get_scrolloff_value(curwin);
if (curwin->w_cursor.lnum < curwin->w_topline + so
- || hasAnyFolding(curwin)
- ) {
+ || hasAnyFolding(curwin)) {
lineoff_T loff;
loff.lnum = curwin->w_cursor.lnum;
loff.fill = 0;
@@ -383,8 +382,8 @@ static bool check_top_offset(void)
topline_back(curwin, &loff);
// Stop when included a line above the window.
if (loff.lnum < curwin->w_topline
- || (loff.lnum == curwin->w_topline && loff.fill > 0)
- ) {
+ || (loff.lnum == curwin->w_topline &&
+ loff.fill > 0)) {
break;
}
n += loff.height;
@@ -418,8 +417,8 @@ void check_cursor_moved(win_T *wp)
wp->w_viewport_invalid = true;
} else if (wp->w_cursor.col != wp->w_valid_cursor.col
|| wp->w_leftcol != wp->w_valid_leftcol
- || wp->w_cursor.coladd != wp->w_valid_cursor.coladd
- ) {
+ || wp->w_cursor.coladd !=
+ wp->w_valid_cursor.coladd) {
wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL);
wp->w_valid_cursor.col = wp->w_cursor.col;
wp->w_valid_leftcol = wp->w_leftcol;
@@ -451,13 +450,18 @@ void changed_window_setting_win(win_T *wp)
*/
void set_topline(win_T *wp, linenr_T lnum)
{
- /* go to first of folded lines */
+ linenr_T prev_topline = wp->w_topline;
+
+ // go to first of folded lines
(void)hasFoldingWin(wp, lnum, &lnum, NULL, true, NULL);
- /* Approximate the value of w_botline */
+ // Approximate the value of w_botline
wp->w_botline += lnum - wp->w_topline;
wp->w_topline = lnum;
wp->w_topline_was_set = true;
- wp->w_topfill = 0;
+ if (lnum != prev_topline) {
+ // Keep the filler lines when the topline didn't change.
+ wp->w_topfill = 0;
+ }
wp->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_TOPLINE);
// Don't set VALID_TOPLINE here, 'scrolloff' needs to be checked.
redraw_later(wp, VALID);
@@ -553,7 +557,7 @@ void validate_cursor(void)
*/
static void curs_rows(win_T *wp)
{
- /* Check if wp->w_lines[].wl_size is invalid */
+ // Check if wp->w_lines[].wl_size is invalid
int all_invalid = (!redrawing()
|| wp->w_lines_valid == 0
|| wp->w_lines[0].wl_lnum > wp->w_topline);
@@ -562,27 +566,28 @@ static void curs_rows(win_T *wp)
for (linenr_T lnum = wp->w_topline; lnum < wp->w_cursor.lnum; ++i) {
bool valid = false;
if (!all_invalid && i < wp->w_lines_valid) {
- if (wp->w_lines[i].wl_lnum < lnum || !wp->w_lines[i].wl_valid)
- continue; /* skip changed or deleted lines */
+ if (wp->w_lines[i].wl_lnum < lnum || !wp->w_lines[i].wl_valid) {
+ continue; // skip changed or deleted lines
+ }
if (wp->w_lines[i].wl_lnum == lnum) {
/* Check for newly inserted lines below this row, in which
* case we need to check for folded lines. */
if (!wp->w_buffer->b_mod_set
|| wp->w_lines[i].wl_lastlnum < wp->w_cursor.lnum
- || wp->w_buffer->b_mod_top
- > wp->w_lines[i].wl_lastlnum + 1)
+ || wp->w_buffer->b_mod_top
+ > wp->w_lines[i].wl_lastlnum + 1) {
valid = true;
+ }
} else if (wp->w_lines[i].wl_lnum > lnum) {
- --i; /* hold at inserted lines */
+ --i; // hold at inserted lines
}
}
- if (valid
- && (lnum != wp->w_topline || !wp->w_p_diff)
- ) {
+ if (valid && (lnum != wp->w_topline || !win_may_fill(wp))) {
lnum = wp->w_lines[i].wl_lastlnum + 1;
- /* Cursor inside folded lines, don't count this row */
- if (lnum > wp->w_cursor.lnum)
+ // Cursor inside folded lines, don't count this row
+ if (lnum > wp->w_cursor.lnum) {
break;
+ }
wp->w_cline_row += wp->w_lines[i].wl_size;
} else {
linenr_T last = lnum;
@@ -606,7 +611,7 @@ static void curs_rows(win_T *wp)
wp->w_cline_height = plines_win_full(wp, wp->w_cursor.lnum, NULL,
&wp->w_cline_folded, true);
} else if (i > wp->w_lines_valid) {
- /* a line that is too long to fit on the last screen line */
+ // a line that is too long to fit on the last screen line
wp->w_cline_height = 0;
wp->w_cline_folded = hasFoldingWin(wp, wp->w_cursor.lnum, NULL,
NULL, true, NULL);
@@ -638,9 +643,9 @@ void validate_virtcol_win(win_T *wp)
getvvcol(wp, &wp->w_cursor, NULL, &(wp->w_virtcol), NULL);
wp->w_valid |= VALID_VIRTCOL;
if (wp->w_p_cuc
- && !pum_visible()
- )
+ && !pum_visible()) {
redraw_later(wp, SOME_VALID);
+ }
}
}
@@ -711,8 +716,9 @@ int curwin_col_off(void)
*/
int win_col_off2(win_T *wp)
{
- if ((wp->w_p_nu || wp->w_p_rnu) && vim_strchr(p_cpo, CPO_NUMCOL) != NULL)
+ if ((wp->w_p_nu || wp->w_p_rnu) && vim_strchr(p_cpo, CPO_NUMCOL) != NULL) {
return number_width(wp) + 1;
+ }
return 0;
}
@@ -725,10 +731,7 @@ int curwin_col_off2(void)
// Also updates curwin->w_wrow and curwin->w_cline_row.
// Also updates curwin->w_leftcol.
// @param may_scroll when true, may scroll horizontally
-void curs_columns(
- win_T *wp,
- int may_scroll
-)
+void curs_columns(win_T *wp, int may_scroll)
{
int n;
int width = 0;
@@ -758,9 +761,10 @@ void curs_columns(
getvvcol(wp, &wp->w_cursor, &startcol, &(wp->w_virtcol), &endcol);
}
- /* remove '$' from change command when cursor moves onto it */
- if (startcol > dollar_vcol)
+ // remove '$' from change command when cursor moves onto it
+ if (startcol > dollar_vcol) {
dollar_vcol = -1;
+ }
int extra = win_col_off(wp);
wp->w_wcol = wp->w_virtcol + extra;
@@ -775,8 +779,7 @@ void curs_columns(
wp->w_wcol = wp->w_width_inner - 1;
wp->w_wrow = wp->w_height_inner - 1;
} else if (wp->w_p_wrap
- && wp->w_width_inner != 0
- ) {
+ && wp->w_width_inner != 0) {
width = textwidth + win_col_off2(wp);
// long line wrapping, adjust wp->w_wrow
@@ -786,17 +789,17 @@ void curs_columns(
wp->w_wcol -= n * width;
wp->w_wrow += n;
- /* When cursor wraps to first char of next line in Insert
- * mode, the 'showbreak' string isn't shown, backup to first
- * column */
- if (*p_sbr && *get_cursor_pos_ptr() == NUL
- && wp->w_wcol == (int)vim_strsize(p_sbr)) {
+ // When cursor wraps to first char of next line in Insert
+ // mode, the 'showbreak' string isn't shown, backup to first
+ // column
+ char_u *const sbr = get_showbreak_value(wp);
+ if (*sbr && *get_cursor_pos_ptr() == NUL
+ && wp->w_wcol == (int)vim_strsize(sbr)) {
wp->w_wcol = 0;
}
}
} else if (may_scroll
- && !wp->w_cline_folded
- ) {
+ && !wp->w_cline_folded) {
// No line wrapping: compute wp->w_leftcol if scrolling is on and line
// is not folded.
// If scrolling is off, wp->w_leftcol is assumed to be 0
@@ -808,7 +811,7 @@ void curs_columns(
assert(siso <= INT_MAX);
int off_left = startcol - wp->w_leftcol - (int)siso;
int off_right =
- endcol - wp->w_leftcol - wp->w_width_inner + (int)siso + 1;
+ endcol - wp->w_leftcol - wp->w_width_inner + (int)siso + 1;
if (off_left < 0 || off_right > 0) {
int diff = (off_left < 0) ? -off_left: off_right;
@@ -828,8 +831,9 @@ void curs_columns(
new_leftcol = wp->w_leftcol + diff;
}
}
- if (new_leftcol < 0)
+ if (new_leftcol < 0) {
new_leftcol = 0;
+ }
if (new_leftcol != (int)wp->w_leftcol) {
wp->w_leftcol = new_leftcol;
win_check_anchored_floats(wp);
@@ -849,7 +853,7 @@ void curs_columns(
if (wp->w_cursor.lnum == wp->w_topline) {
wp->w_wrow += wp->w_topfill;
} else {
- wp->w_wrow += diff_check_fill(wp, wp->w_cursor.lnum);
+ wp->w_wrow += win_get_fill(wp, wp->w_cursor.lnum);
}
prev_skipcol = wp->w_skipcol;
@@ -859,13 +863,12 @@ void curs_columns(
|| ((prev_skipcol > 0
|| wp->w_wrow + so >= wp->w_height_inner)
&& (plines =
- plines_win_nofill(wp, wp->w_cursor.lnum, false)) - 1
+ plines_win_nofill(wp, wp->w_cursor.lnum, false)) - 1
>= wp->w_height_inner))
&& wp->w_height_inner != 0
&& wp->w_cursor.lnum == wp->w_topline
&& width > 0
- && wp->w_width_inner != 0
- ) {
+ && wp->w_width_inner != 0) {
/* Cursor past end of screen. Happens with a single line that does
* not fit on screen. Find a skipcol to show the text around the
* cursor. Avoid scrolling all the time. compute value of "extra":
@@ -964,8 +967,8 @@ void curs_columns(
/// @param[out] scolp start screen column
/// @param[out] ccolp cursor screen column
/// @param[out] ecolp end screen column
-void textpos2screenpos(win_T *wp, pos_T *pos, int *rowp, int *scolp,
- int *ccolp, int *ecolp, bool local)
+void textpos2screenpos(win_T *wp, pos_T *pos, int *rowp, int *scolp, int *ccolp, int *ecolp,
+ bool local)
{
colnr_T scol = 0, ccol = 0, ecol = 0;
int row = 0;
@@ -988,7 +991,7 @@ void textpos2screenpos(win_T *wp, pos_T *pos, int *rowp, int *scolp,
if ((local && existing_row) || visible_row) {
colnr_T off;
colnr_T col;
- int width;
+ int width;
getvcol(wp, pos, &scol, &ccol, &ecol);
@@ -1033,38 +1036,42 @@ bool scrolldown(long line_count, int byfold)
{
int done = 0; // total # of physical lines done
- /* Make sure w_topline is at the first of a sequence of folded lines. */
+ // Make sure w_topline is at the first of a sequence of folded lines.
(void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
- validate_cursor(); /* w_wrow needs to be valid */
+ validate_cursor(); // w_wrow needs to be valid
while (line_count-- > 0) {
- if (curwin->w_topfill < diff_check(curwin, curwin->w_topline)
+ if (curwin->w_topfill < win_get_fill(curwin, curwin->w_topline)
&& curwin->w_topfill < curwin->w_height_inner - 1) {
curwin->w_topfill++;
done++;
} else {
- if (curwin->w_topline == 1)
+ if (curwin->w_topline == 1) {
break;
+ }
--curwin->w_topline;
curwin->w_topfill = 0;
- /* A sequence of folded lines only counts for one logical line */
+ // A sequence of folded lines only counts for one logical line
linenr_T first;
if (hasFolding(curwin->w_topline, &first, NULL)) {
++done;
- if (!byfold)
+ if (!byfold) {
line_count -= curwin->w_topline - first - 1;
+ }
curwin->w_botline -= curwin->w_topline - first;
curwin->w_topline = first;
- } else
- done += plines_nofill(curwin->w_topline);
+ } else {
+ done += plines_win_nofill(curwin, curwin->w_topline, true);
+ }
}
- --curwin->w_botline; /* approximate w_botline */
+ --curwin->w_botline; // approximate w_botline
invalidate_botline();
}
- curwin->w_wrow += done; /* keep w_wrow updated */
- curwin->w_cline_row += done; /* keep w_cline_row updated */
+ curwin->w_wrow += done; // keep w_wrow updated
+ curwin->w_cline_row += done; // keep w_cline_row updated
- if (curwin->w_cursor.lnum == curwin->w_topline)
+ if (curwin->w_cursor.lnum == curwin->w_topline) {
curwin->w_cline_row = 0;
+ }
check_topfill(curwin, true);
/*
@@ -1073,8 +1080,7 @@ bool scrolldown(long line_count, int byfold)
*/
int wrow = curwin->w_wrow;
if (curwin->w_p_wrap
- && curwin->w_width_inner != 0
- ) {
+ && curwin->w_width_inner != 0) {
validate_virtcol();
validate_cheight();
wrow += curwin->w_cline_height - 1 -
@@ -1085,18 +1091,20 @@ bool scrolldown(long line_count, int byfold)
linenr_T first;
if (hasFolding(curwin->w_cursor.lnum, &first, NULL)) {
--wrow;
- if (first == 1)
+ if (first == 1) {
curwin->w_cursor.lnum = 1;
- else
+ } else {
curwin->w_cursor.lnum = first - 1;
- } else
- wrow -= plines(curwin->w_cursor.lnum--);
+ }
+ } else {
+ wrow -= plines_win(curwin, curwin->w_cursor.lnum--, true);
+ }
curwin->w_valid &=
~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL);
moved = true;
}
if (moved) {
- /* Move cursor to first line of closed fold. */
+ // Move cursor to first line of closed fold.
foldAdjustCursor();
coladvance(curwin->w_curswant);
}
@@ -1113,39 +1121,44 @@ bool scrollup(long line_count, int byfold)
linenr_T botline = curwin->w_botline;
if ((byfold && hasAnyFolding(curwin))
- || curwin->w_p_diff) {
+ || win_may_fill(curwin)) {
// count each sequence of folded lines as one logical line
linenr_T lnum = curwin->w_topline;
while (line_count--) {
- if (curwin->w_topfill > 0)
+ if (curwin->w_topfill > 0) {
--curwin->w_topfill;
- else {
- if (byfold)
+ } else {
+ if (byfold) {
(void)hasFolding(lnum, NULL, &lnum);
- if (lnum >= curbuf->b_ml.ml_line_count)
+ }
+ if (lnum >= curbuf->b_ml.ml_line_count) {
break;
- ++lnum;
- curwin->w_topfill = diff_check_fill(curwin, lnum);
+ }
+ lnum++;
+ curwin->w_topfill = win_get_fill(curwin, lnum);
}
}
- /* approximate w_botline */
+ // approximate w_botline
curwin->w_botline += lnum - curwin->w_topline;
curwin->w_topline = lnum;
} else {
curwin->w_topline += line_count;
- curwin->w_botline += line_count; /* approximate w_botline */
+ curwin->w_botline += line_count; // approximate w_botline
}
- if (curwin->w_topline > curbuf->b_ml.ml_line_count)
+ if (curwin->w_topline > curbuf->b_ml.ml_line_count) {
curwin->w_topline = curbuf->b_ml.ml_line_count;
- if (curwin->w_botline > curbuf->b_ml.ml_line_count + 1)
+ }
+ if (curwin->w_botline > curbuf->b_ml.ml_line_count + 1) {
curwin->w_botline = curbuf->b_ml.ml_line_count + 1;
+ }
check_topfill(curwin, false);
- if (hasAnyFolding(curwin))
- /* Make sure w_topline is at the first of a sequence of folded lines. */
+ if (hasAnyFolding(curwin)) {
+ // Make sure w_topline is at the first of a sequence of folded lines.
(void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
+ }
curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
if (curwin->w_cursor.lnum < curwin->w_topline) {
@@ -1156,19 +1169,15 @@ bool scrollup(long line_count, int byfold)
}
bool moved = topline != curwin->w_topline
- || botline != curwin->w_botline;
+ || botline != curwin->w_botline;
return moved;
}
-/*
- * Don't end up with too many filler lines in the window.
- */
-void
-check_topfill (
- win_T *wp,
- bool down /* when true scroll down when not enough space */
-)
+/// Don't end up with too many filler lines in the window.
+///
+/// @param down when true scroll down when not enough space
+void check_topfill(win_T *wp, bool down)
{
if (wp->w_topfill > 0) {
int n = plines_win_nofill(wp, wp->w_topline, true);
@@ -1193,11 +1202,11 @@ check_topfill (
*/
static void max_topfill(void)
{
- int n = plines_nofill(curwin->w_topline);
+ int n = plines_win_nofill(curwin, curwin->w_topline, true);
if (n >= curwin->w_height_inner) {
curwin->w_topfill = 0;
} else {
- curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline);
+ curwin->w_topfill = win_get_fill(curwin, curwin->w_topline);
if (curwin->w_topfill + n > curwin->w_height_inner) {
curwin->w_topfill = curwin->w_height_inner - n;
}
@@ -1210,29 +1219,25 @@ static void max_topfill(void)
*/
void scrolldown_clamp(void)
{
- int can_fill = (curwin->w_topfill
- < diff_check_fill(curwin, curwin->w_topline));
+ int can_fill = (curwin->w_topfill < win_get_fill(curwin, curwin->w_topline));
if (curwin->w_topline <= 1
- && !can_fill
- )
+ && !can_fill) {
return;
+ }
- validate_cursor(); /* w_wrow needs to be valid */
+ validate_cursor(); // w_wrow needs to be valid
- /*
- * Compute the row number of the last row of the cursor line
- * and make sure it doesn't go off the screen. Make sure the cursor
- * doesn't go past 'scrolloff' lines from the screen end.
- */
+ // Compute the row number of the last row of the cursor line
+ // and make sure it doesn't go off the screen. Make sure the cursor
+ // doesn't go past 'scrolloff' lines from the screen end.
int end_row = curwin->w_wrow;
- if (can_fill)
- ++end_row;
- else
- end_row += plines_nofill(curwin->w_topline - 1);
- if (curwin->w_p_wrap
- && curwin->w_width_inner != 0
- ) {
+ if (can_fill) {
+ end_row++;
+ } else {
+ end_row += plines_win_nofill(curwin, curwin->w_topline - 1, true);
+ }
+ if (curwin->w_p_wrap && curwin->w_width_inner != 0) {
validate_cheight();
validate_virtcol();
end_row += curwin->w_cline_height - 1 -
@@ -1247,7 +1252,7 @@ void scrolldown_clamp(void)
curwin->w_topfill = 0;
}
(void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
- --curwin->w_botline; /* approximate w_botline */
+ --curwin->w_botline; // approximate w_botline
curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
}
}
@@ -1259,22 +1264,19 @@ void scrolldown_clamp(void)
void scrollup_clamp(void)
{
if (curwin->w_topline == curbuf->b_ml.ml_line_count
- && curwin->w_topfill == 0
- )
+ && curwin->w_topfill == 0) {
return;
+ }
- validate_cursor(); /* w_wrow needs to be valid */
+ validate_cursor(); // w_wrow needs to be valid
- /*
- * Compute the row number of the first row of the cursor line
- * and make sure it doesn't go off the screen. Make sure the cursor
- * doesn't go before 'scrolloff' lines from the screen start.
- */
- int start_row = curwin->w_wrow - plines_nofill(curwin->w_topline)
- - curwin->w_topfill;
- if (curwin->w_p_wrap
- && curwin->w_width_inner != 0
- ) {
+ // Compute the row number of the first row of the cursor line
+ // and make sure it doesn't go off the screen. Make sure the cursor
+ // doesn't go before 'scrolloff' lines from the screen start.
+ int start_row = (curwin->w_wrow
+ - plines_win_nofill(curwin, curwin->w_topline, true)
+ - curwin->w_topfill);
+ if (curwin->w_p_wrap && curwin->w_width_inner != 0) {
validate_virtcol();
start_row -= curwin->w_virtcol / curwin->w_width_inner;
}
@@ -1298,7 +1300,7 @@ void scrollup_clamp(void)
*/
static void topline_back(win_T *wp, lineoff_T *lp)
{
- if (lp->fill < diff_check_fill(wp, lp->lnum)) {
+ if (lp->fill < win_get_fill(wp, lp->lnum)) {
// Add a filler line
lp->fill++;
lp->height = 1;
@@ -1324,7 +1326,7 @@ static void topline_back(win_T *wp, lineoff_T *lp)
*/
static void botline_forw(win_T *wp, lineoff_T *lp)
{
- if (lp->fill < diff_check_fill(wp, lp->lnum + 1)) {
+ if (lp->fill < win_get_fill(wp, lp->lnum + 1)) {
// Add a filler line.
lp->fill++;
lp->height = 1;
@@ -1351,8 +1353,8 @@ static void botline_forw(win_T *wp, lineoff_T *lp)
static void botline_topline(lineoff_T *lp)
{
if (lp->fill > 0) {
- ++lp->lnum;
- lp->fill = diff_check_fill(curwin, lp->lnum) - lp->fill + 1;
+ lp->lnum++;
+ lp->fill = win_get_fill(curwin, lp->lnum) - lp->fill + 1;
}
}
@@ -1364,8 +1366,8 @@ static void botline_topline(lineoff_T *lp)
static void topline_botline(lineoff_T *lp)
{
if (lp->fill > 0) {
- lp->fill = diff_check_fill(curwin, lp->lnum) - lp->fill + 1;
- --lp->lnum;
+ lp->fill = win_get_fill(curwin, lp->lnum) - lp->fill + 1;
+ lp->lnum--;
}
}
@@ -1377,15 +1379,16 @@ static void topline_botline(lineoff_T *lp)
void scroll_cursor_top(int min_scroll, int always)
{
int scrolled = 0;
- linenr_T top; /* just above displayed lines */
- linenr_T bot; /* just below displayed lines */
+ linenr_T top; // just above displayed lines
+ linenr_T bot; // just below displayed lines
linenr_T old_topline = curwin->w_topline;
linenr_T old_topfill = curwin->w_topfill;
linenr_T new_topline;
int off = (int)get_scrolloff_value(curwin);
- if (mouse_dragging > 0)
+ if (mouse_dragging > 0) {
off = mouse_dragging - 1;
+ }
/*
* Decrease topline until:
@@ -1412,7 +1415,7 @@ void scroll_cursor_top(int min_scroll, int always)
// "used" already contains the number of filler lines above, don't add it
// again.
// Hide filler lines above cursor line by adding them to "extra".
- int extra = diff_check_fill(curwin, curwin->w_cursor.lnum);
+ int extra = win_get_fill(curwin, curwin->w_cursor.lnum);
/*
* Check if the lines from "top" to "bot" fit in the window. If they do,
@@ -1421,14 +1424,15 @@ void scroll_cursor_top(int min_scroll, int always)
while (top > 0) {
int i = hasFolding(top, &top, NULL)
? 1 // count one logical line for a sequence of folded lines
- : plines_nofill(top);
+ : plines_win_nofill(curwin, top, true);
used += i;
if (extra + i <= off && bot < curbuf->b_ml.ml_line_count) {
- if (hasFolding(bot, NULL, &bot))
- /* count one logical line for a sequence of folded lines */
- ++used;
- else
- used += plines(bot);
+ if (hasFolding(bot, NULL, &bot)) {
+ // count one logical line for a sequence of folded lines
+ used++;
+ } else {
+ used += plines_win(curwin, bot, true);
+ }
}
if (used > curwin->w_height_inner) {
break;
@@ -1441,8 +1445,9 @@ void scroll_cursor_top(int min_scroll, int always)
* If scrolling is needed, scroll at least 'sj' lines.
*/
if ((new_topline >= curwin->w_topline || scrolled > min_scroll)
- && extra >= off)
+ && extra >= off) {
break;
+ }
extra += i;
new_topline = top;
@@ -1462,22 +1467,25 @@ void scroll_cursor_top(int min_scroll, int always)
* If "always" is false, only adjust topline to a lower value, higher
* value may happen with wrapping lines
*/
- if (new_topline < curwin->w_topline || always)
+ if (new_topline < curwin->w_topline || always) {
curwin->w_topline = new_topline;
- if (curwin->w_topline > curwin->w_cursor.lnum)
+ }
+ if (curwin->w_topline > curwin->w_cursor.lnum) {
curwin->w_topline = curwin->w_cursor.lnum;
- curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline);
+ }
+ curwin->w_topfill = win_get_fill(curwin, curwin->w_topline);
if (curwin->w_topfill > 0 && extra > off) {
curwin->w_topfill -= extra - off;
- if (curwin->w_topfill < 0)
+ if (curwin->w_topfill < 0) {
curwin->w_topfill = 0;
+ }
}
check_topfill(curwin, false);
if (curwin->w_topline != old_topline
- || curwin->w_topfill != old_topfill
- )
+ || curwin->w_topfill != old_topfill) {
curwin->w_valid &=
~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
+ }
curwin->w_valid |= VALID_TOPLINE;
curwin->w_viewport_invalid = true;
}
@@ -1495,10 +1503,10 @@ void set_empty_rows(win_T *wp, int used)
} else {
wp->w_empty_rows = wp->w_height_inner - used;
if (wp->w_botline <= wp->w_buffer->b_ml.ml_line_count) {
- wp->w_filler_rows = diff_check_fill(wp, wp->w_botline);
- if (wp->w_empty_rows > wp->w_filler_rows)
+ wp->w_filler_rows = win_get_fill(wp, wp->w_botline);
+ if (wp->w_empty_rows > wp->w_filler_rows) {
wp->w_empty_rows -= wp->w_filler_rows;
- else {
+ } else {
wp->w_filler_rows = wp->w_empty_rows;
wp->w_empty_rows = 0;
}
@@ -1521,10 +1529,10 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
lineoff_T boff;
int fill_below_window;
linenr_T old_topline = curwin->w_topline;
- int old_topfill = curwin->w_topfill;
+ int old_topfill = curwin->w_topfill;
linenr_T old_botline = curwin->w_botline;
- int old_valid = curwin->w_valid;
- int old_empty_rows = curwin->w_empty_rows;
+ int old_valid = curwin->w_valid;
+ int old_empty_rows = curwin->w_empty_rows;
linenr_T cln = curwin->w_cursor.lnum; // Cursor Line Number
long so = get_scrolloff_value(curwin);
@@ -1547,23 +1555,24 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
set_empty_rows(curwin, used);
curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
if (curwin->w_topline != old_topline
- || curwin->w_topfill != old_topfill
- )
+ || curwin->w_topfill != old_topfill) {
curwin->w_valid &= ~(VALID_WROW|VALID_CROW);
+ }
} else {
validate_botline(curwin);
}
- /* The lines of the cursor line itself are always used. */
- used = plines_nofill(cln);
+ // The lines of the cursor line itself are always used.
+ used = plines_win_nofill(curwin, cln, true);
- /* If the cursor is below botline, we will at least scroll by the height
- * of the cursor line. Correct for empty lines, which are really part of
- * botline. */
+ // If the cursor is below botline, we will at least scroll by the height
+ // of the cursor line. Correct for empty lines, which are really part of
+ // botline.
if (cln >= curwin->w_botline) {
scrolled = used;
- if (cln == curwin->w_botline)
+ if (cln == curwin->w_botline) {
scrolled -= curwin->w_empty_rows;
+ }
}
/*
@@ -1579,7 +1588,7 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
}
loff.fill = 0;
boff.fill = 0;
- fill_below_window = diff_check_fill(curwin, curwin->w_botline)
+ fill_below_window = win_get_fill(curwin, curwin->w_botline)
- curwin->w_filler_rows;
while (loff.lnum > 1) {
@@ -1590,8 +1599,7 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
|| boff.lnum + 1 > curbuf->b_ml.ml_line_count)
&& loff.lnum <= curwin->w_botline
&& (loff.lnum < curwin->w_botline
- || loff.fill >= fill_below_window)
- ) {
+ || loff.fill >= fill_below_window)) {
break;
}
@@ -1607,9 +1615,8 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
}
if (loff.lnum >= curwin->w_botline
&& (loff.lnum > curwin->w_botline
- || loff.fill <= fill_below_window)
- ) {
- /* Count screen lines that are below the window. */
+ || loff.fill <= fill_below_window)) {
+ // Count screen lines that are below the window.
scrolled += loff.height;
if (loff.lnum == curwin->w_botline
&& loff.fill == 0) {
@@ -1629,14 +1636,13 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
extra += boff.height;
if (boff.lnum >= curwin->w_botline
|| (boff.lnum + 1 == curwin->w_botline
- && boff.fill > curwin->w_filler_rows)
- ) {
- /* Count screen lines that are below the window. */
+ && boff.fill > curwin->w_filler_rows)) {
+ // Count screen lines that are below the window.
scrolled += boff.height;
if (boff.lnum == curwin->w_botline
- && boff.fill == 0
- )
+ && boff.fill == 0) {
scrolled -= curwin->w_empty_rows;
+ }
}
}
}
@@ -1646,10 +1652,10 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
// curwin->w_empty_rows is larger, no need to scroll
if (scrolled <= 0) {
line_count = 0;
- // more than a screenfull, don't scroll but redraw
+ // more than a screenfull, don't scroll but redraw
} else if (used > curwin->w_height_inner) {
line_count = used;
- // scroll minimal number of lines
+ // scroll minimal number of lines
} else {
line_count = 0;
boff.fill = curwin->w_topfill;
@@ -1660,8 +1666,9 @@ void scroll_cursor_bot(int min_scroll, int set_topbot)
i += boff.height;
++line_count;
}
- if (i < scrolled) /* below curwin->w_botline, don't scroll */
+ if (i < scrolled) { // below curwin->w_botline, don't scroll
line_count = 9999;
+ }
}
/*
@@ -1703,12 +1710,12 @@ void scroll_cursor_halfway(int atend)
loff.lnum = boff.lnum = curwin->w_cursor.lnum;
(void)hasFolding(loff.lnum, &loff.lnum, &boff.lnum);
- int used = plines_nofill(loff.lnum);
+ int used = plines_win_nofill(curwin, loff.lnum, true);
loff.fill = 0;
boff.fill = 0;
linenr_T topline = loff.lnum;
while (topline > 1) {
- if (below <= above) { /* add a line below the cursor first */
+ if (below <= above) { // add a line below the cursor first
if (boff.lnum < curbuf->b_ml.ml_line_count) {
botline_forw(curwin, &boff);
used += boff.height;
@@ -1717,9 +1724,10 @@ void scroll_cursor_halfway(int atend)
}
below += boff.height;
} else {
- ++below; /* count a "~" line */
- if (atend)
+ ++below; // count a "~" line
+ if (atend) {
++used;
+ }
}
}
@@ -1738,8 +1746,9 @@ void scroll_cursor_halfway(int atend)
topfill = loff.fill;
}
}
- if (!hasFolding(topline, &curwin->w_topline, NULL))
+ if (!hasFolding(topline, &curwin->w_topline, NULL)) {
curwin->w_topline = topline;
+ }
curwin->w_topfill = topfill;
if (old_topline > curwin->w_topline + curwin->w_height_inner) {
curwin->w_botfill = false;
@@ -1788,12 +1797,12 @@ void cursor_correct(void)
* If there are sufficient file-lines above and below the cursor, we can
* return now.
*/
- linenr_T cln = curwin->w_cursor.lnum; /* Cursor Line Number */
+ linenr_T cln = curwin->w_cursor.lnum; // Cursor Line Number
if (cln >= curwin->w_topline + above_wanted
&& cln < curwin->w_botline - below_wanted
- && !hasAnyFolding(curwin)
- )
+ && !hasAnyFolding(curwin)) {
return;
+ }
/*
* Narrow down the area where the cursor can be put by taking lines from
@@ -1803,34 +1812,37 @@ void cursor_correct(void)
*/
linenr_T topline = curwin->w_topline;
linenr_T botline = curwin->w_botline - 1;
- /* count filler lines as context */
- int above = curwin->w_topfill; /* screen lines above topline */
- int below = curwin->w_filler_rows; /* screen lines below botline */
+ // count filler lines as context
+ int above = curwin->w_topfill; // screen lines above topline
+ int below = curwin->w_filler_rows; // screen lines below botline
while ((above < above_wanted || below < below_wanted) && topline < botline) {
if (below < below_wanted && (below <= above || above >= above_wanted)) {
- if (hasFolding(botline, &botline, NULL))
- ++below;
- else
- below += plines(botline);
- --botline;
+ if (hasFolding(botline, &botline, NULL)) {
+ below++;
+ } else {
+ below += plines_win(curwin, botline, true);
+ }
+ botline--;
}
if (above < above_wanted && (above < below || below >= below_wanted)) {
- if (hasFolding(topline, NULL, &topline))
- ++above;
- else
- above += plines_nofill(topline);
-
- /* Count filler lines below this line as context. */
- if (topline < botline)
- above += diff_check_fill(curwin, topline + 1);
+ if (hasFolding(topline, NULL, &topline)) {
+ above++;
+ } else {
+ above += plines_win_nofill(curwin, topline, true);
+ }
+
+ // Count filler lines below this line as context.
+ if (topline < botline) {
+ above += win_get_fill(curwin, topline + 1);
+ }
++topline;
}
}
- if (topline == botline || botline == 0)
+ if (topline == botline || botline == 0) {
curwin->w_cursor.lnum = topline;
- else if (topline > botline)
+ } else if (topline > botline) {
curwin->w_cursor.lnum = botline;
- else {
+ } else {
if (cln < topline && curwin->w_topline > 1) {
curwin->w_cursor.lnum = topline;
curwin->w_valid &=
@@ -1860,7 +1872,7 @@ int onepage(Direction dir, long count)
linenr_T old_topline = curwin->w_topline;
long so = get_scrolloff_value(curwin);
- if (curbuf->b_ml.ml_line_count == 1) { /* nothing to do */
+ if (curbuf->b_ml.ml_line_count == 1) { // nothing to do
beep_flush();
return FAIL;
}
@@ -1875,9 +1887,7 @@ int onepage(Direction dir, long count)
? ((curwin->w_topline >= curbuf->b_ml.ml_line_count - so)
&& curwin->w_botline > curbuf->b_ml.ml_line_count)
: (curwin->w_topline == 1
- && curwin->w_topfill ==
- diff_check_fill(curwin, curwin->w_topline)
- )) {
+ && curwin->w_topfill == win_get_fill(curwin, curwin->w_topline))) {
beep_flush();
retval = FAIL;
break;
@@ -1886,16 +1896,18 @@ int onepage(Direction dir, long count)
loff.fill = 0;
if (dir == FORWARD) {
if (ONE_WINDOW && p_window > 0 && p_window < Rows - 1) {
- /* Vi compatible scrolling */
- if (p_window <= 2)
+ // Vi compatible scrolling
+ if (p_window <= 2) {
++curwin->w_topline;
- else
+ } else {
curwin->w_topline += p_window - 2;
- if (curwin->w_topline > curbuf->b_ml.ml_line_count)
+ }
+ if (curwin->w_topline > curbuf->b_ml.ml_line_count) {
curwin->w_topline = curbuf->b_ml.ml_line_count;
+ }
curwin->w_cursor.lnum = curwin->w_topline;
} else if (curwin->w_botline > curbuf->b_ml.ml_line_count) {
- /* at end of file */
+ // at end of file
curwin->w_topline = curbuf->b_ml.ml_line_count;
curwin->w_topfill = 0;
curwin->w_valid &= ~(VALID_WROW|VALID_CROW);
@@ -1903,7 +1915,7 @@ int onepage(Direction dir, long count)
/* For the overlap, start with the line just below the window
* and go upwards. */
loff.lnum = curwin->w_botline;
- loff.fill = diff_check_fill(curwin, loff.lnum)
+ loff.fill = win_get_fill(curwin, loff.lnum)
- curwin->w_filler_rows;
get_scroll_overlap(&loff, -1);
curwin->w_topline = loff.lnum;
@@ -1913,23 +1925,26 @@ int onepage(Direction dir, long count)
curwin->w_valid &= ~(VALID_WCOL|VALID_CHEIGHT|VALID_WROW|
VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
}
- } else { /* dir == BACKWARDS */
+ } else { // dir == BACKWARDS
if (curwin->w_topline == 1) {
- /* Include max number of filler lines */
+ // Include max number of filler lines
max_topfill();
continue;
}
if (ONE_WINDOW && p_window > 0 && p_window < Rows - 1) {
- /* Vi compatible scrolling (sort of) */
- if (p_window <= 2)
+ // Vi compatible scrolling (sort of)
+ if (p_window <= 2) {
--curwin->w_topline;
- else
+ } else {
curwin->w_topline -= p_window - 2;
- if (curwin->w_topline < 1)
+ }
+ if (curwin->w_topline < 1) {
curwin->w_topline = 1;
+ }
curwin->w_cursor.lnum = curwin->w_topline + p_window - 1;
- if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
+ if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) {
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+ }
continue;
}
@@ -1937,8 +1952,7 @@ int onepage(Direction dir, long count)
* line at the bottom of the window. Make sure this results in
* the same line as before doing CTRL-F. */
loff.lnum = curwin->w_topline - 1;
- loff.fill = diff_check_fill(curwin, loff.lnum + 1)
- - curwin->w_topfill;
+ loff.fill = win_get_fill(curwin, loff.lnum + 1) - curwin->w_topfill;
get_scroll_overlap(&loff, 1);
if (loff.lnum >= curbuf->b_ml.ml_line_count) {
@@ -1960,12 +1974,12 @@ int onepage(Direction dir, long count)
n += loff.height;
}
}
- if (loff.lnum < 1) { /* at begin of file */
+ if (loff.lnum < 1) { // at begin of file
curwin->w_topline = 1;
max_topfill();
curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
} else {
- /* Go two lines forward again. */
+ // Go two lines forward again.
topline_botline(&loff);
botline_forw(curwin, &loff);
botline_forw(curwin, &loff);
@@ -1977,14 +1991,13 @@ int onepage(Direction dir, long count)
* very long lines. */
if (loff.lnum >= curwin->w_topline
&& (loff.lnum > curwin->w_topline
- || loff.fill >= curwin->w_topfill)
- ) {
+ || loff.fill >= curwin->w_topfill)) {
/* First try using the maximum number of filler lines. If
* that's not enough, backup one line. */
loff.fill = curwin->w_topfill;
- if (curwin->w_topfill < diff_check_fill(curwin,
- curwin->w_topline))
+ if (curwin->w_topfill < win_get_fill(curwin, curwin->w_topline)) {
max_topfill();
+ }
if (curwin->w_topfill == loff.fill) {
--curwin->w_topline;
curwin->w_topfill = 0;
@@ -2035,25 +2048,26 @@ int onepage(Direction dir, long count)
* This is symmetric, so that doing both keeps the same lines displayed.
* Three lines are examined:
*
- * before CTRL-F after CTRL-F / before CTRL-B
- * etc. l1
- * l1 last but one line ------------
- * l2 last text line l2 top text line
- * ------------- l3 second text line
- * l3 etc.
+ * before CTRL-F after CTRL-F / before CTRL-B
+ * etc. l1
+ * l1 last but one line ------------
+ * l2 last text line l2 top text line
+ * ------------- l3 second text line
+ * l3 etc.
*/
static void get_scroll_overlap(lineoff_T *lp, int dir)
{
int min_height = curwin->w_height_inner - 2;
- if (lp->fill > 0)
+ if (lp->fill > 0) {
lp->height = 1;
- else
- lp->height = plines_nofill(lp->lnum);
+ } else {
+ lp->height = plines_win_nofill(curwin, lp->lnum, true);
+ }
int h1 = lp->height;
- if (h1 > min_height)
- return; /* no overlap */
-
+ if (h1 > min_height) {
+ return; // no overlap
+ }
lineoff_T loff0 = *lp;
if (dir > 0) {
botline_forw(curwin, lp);
@@ -2062,7 +2076,7 @@ static void get_scroll_overlap(lineoff_T *lp, int dir)
}
int h2 = lp->height;
if (h2 == MAXCOL || h2 + h1 > min_height) {
- *lp = loff0; /* no overlap */
+ *lp = loff0; // no overlap
return;
}
@@ -2074,7 +2088,7 @@ static void get_scroll_overlap(lineoff_T *lp, int dir)
}
int h3 = lp->height;
if (h3 == MAXCOL || h3 + h2 > min_height) {
- *lp = loff0; /* no overlap */
+ *lp = loff0; // no overlap
return;
}
@@ -2085,10 +2099,11 @@ static void get_scroll_overlap(lineoff_T *lp, int dir)
topline_back(curwin, lp);
}
int h4 = lp->height;
- if (h4 == MAXCOL || h4 + h3 + h2 > min_height || h3 + h2 + h1 > min_height)
- *lp = loff1; /* 1 line overlap */
- else
- *lp = loff2; /* 2 lines overlap */
+ if (h4 == MAXCOL || h4 + h3 + h2 > min_height || h3 + h2 + h1 > min_height) {
+ *lp = loff1; // 1 line overlap
+ } else {
+ *lp = loff2; // 2 lines overlap
+ }
return;
}
@@ -2100,11 +2115,11 @@ void halfpage(bool flag, linenr_T Prenum)
if (Prenum) {
curwin->w_p_scr = (Prenum > curwin->w_height_inner) ? curwin->w_height_inner
- : Prenum;
+ : Prenum;
}
assert(curwin->w_p_scr <= INT_MAX);
int n = curwin->w_p_scr <= curwin->w_height_inner ? (int)curwin->w_p_scr
- : curwin->w_height_inner;
+ : curwin->w_height_inner;
update_topline(curwin);
validate_botline(curwin);
@@ -2119,13 +2134,14 @@ void halfpage(bool flag, linenr_T Prenum)
n--;
curwin->w_topfill--;
} else {
- i = plines_nofill(curwin->w_topline);
+ i = plines_win_nofill(curwin, curwin->w_topline, true);
n -= i;
- if (n < 0 && scrolled > 0)
+ if (n < 0 && scrolled > 0) {
break;
+ }
(void)hasFolding(curwin->w_topline, NULL, &curwin->w_topline);
- ++curwin->w_topline;
- curwin->w_topfill = diff_check_fill(curwin, curwin->w_topline);
+ curwin->w_topline++;
+ curwin->w_topfill = win_get_fill(curwin, curwin->w_topline);
if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) {
++curwin->w_cursor.lnum;
@@ -2136,21 +2152,19 @@ void halfpage(bool flag, linenr_T Prenum)
curwin->w_valid &= ~(VALID_CROW|VALID_WROW);
scrolled += i;
- /*
- * Correct w_botline for changed w_topline.
- * Won't work when there are filler lines.
- */
- if (curwin->w_p_diff)
+ // Correct w_botline for changed w_topline.
+ // Won't work when there are filler lines.
+ if (win_may_fill(curwin)) {
curwin->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP);
- else {
+ } else {
room += i;
do {
- i = plines(curwin->w_botline);
- if (i > room)
+ i = plines_win(curwin, curwin->w_botline, true);
+ if (i > room) {
break;
- (void)hasFolding(curwin->w_botline, NULL,
- &curwin->w_botline);
- ++curwin->w_botline;
+ }
+ (void)hasFolding(curwin->w_botline, NULL, &curwin->w_botline);
+ curwin->w_botline++;
room -= i;
} while (curwin->w_botline <= curbuf->b_ml.ml_line_count);
}
@@ -2162,11 +2176,12 @@ void halfpage(bool flag, linenr_T Prenum)
while (--n >= 0
&& curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) {
(void)hasFolding(curwin->w_cursor.lnum, NULL,
- &curwin->w_cursor.lnum);
+ &curwin->w_cursor.lnum);
++curwin->w_cursor.lnum;
}
- } else
+ } else {
curwin->w_cursor.lnum += n;
+ }
check_cursor_lnum();
}
} else {
@@ -2174,15 +2189,16 @@ void halfpage(bool flag, linenr_T Prenum)
* scroll the text down
*/
while (n > 0 && curwin->w_topline > 1) {
- if (curwin->w_topfill < diff_check_fill(curwin, curwin->w_topline)) {
+ if (curwin->w_topfill < win_get_fill(curwin, curwin->w_topline)) {
i = 1;
n--;
curwin->w_topfill++;
} else {
- i = plines_nofill(curwin->w_topline - 1);
+ i = plines_win_nofill(curwin, curwin->w_topline - 1, true);
n -= i;
- if (n < 0 && scrolled > 0)
+ if (n < 0 && scrolled > 0) {
break;
+ }
--curwin->w_topline;
(void)hasFolding(curwin->w_topline, &curwin->w_topline, NULL);
curwin->w_topfill = 0;
@@ -2198,19 +2214,20 @@ void halfpage(bool flag, linenr_T Prenum)
// When hit top of the file: move cursor up.
if (n > 0) {
- if (curwin->w_cursor.lnum <= (linenr_T)n)
+ if (curwin->w_cursor.lnum <= (linenr_T)n) {
curwin->w_cursor.lnum = 1;
- else if (hasAnyFolding(curwin)) {
+ } else if (hasAnyFolding(curwin)) {
while (--n >= 0 && curwin->w_cursor.lnum > 1) {
--curwin->w_cursor.lnum;
(void)hasFolding(curwin->w_cursor.lnum,
- &curwin->w_cursor.lnum, NULL);
+ &curwin->w_cursor.lnum, NULL);
}
- } else
+ } else {
curwin->w_cursor.lnum -= n;
+ }
}
}
- /* Move cursor to first line of closed fold. */
+ // Move cursor to first line of closed fold.
foldAdjustCursor();
check_topfill(curwin, !flag);
cursor_correct();
@@ -2237,7 +2254,7 @@ void do_check_cursorbind(void)
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
curwin = wp;
curbuf = curwin->w_buffer;
- /* skip original window and windows with 'noscrollbind' */
+ // skip original window and windows with 'noscrollbind'
if (curwin != old_curwin && curwin->w_p_crb) {
if (curwin->w_p_diff) {
curwin->w_cursor.lnum =
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
index a2d8859c68..a1a1f0f8c0 100644
--- a/src/nvim/msgpack_rpc/channel.c
+++ b/src/nvim/msgpack_rpc/channel.c
@@ -1,44 +1,43 @@
// 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 <inttypes.h>
+#include <msgpack.h>
#include <stdbool.h>
#include <string.h>
-#include <inttypes.h>
-
#include <uv.h>
-#include <msgpack.h>
#include "nvim/api/private/helpers.h"
-#include "nvim/api/vim.h"
#include "nvim/api/ui.h"
+#include "nvim/api/vim.h"
+#include "nvim/ascii.h"
#include "nvim/channel.h"
-#include "nvim/msgpack_rpc/channel.h"
-#include "nvim/event/loop.h"
+#include "nvim/eval.h"
#include "nvim/event/libuv_process.h"
+#include "nvim/event/loop.h"
#include "nvim/event/rstream.h"
-#include "nvim/event/wstream.h"
#include "nvim/event/socket.h"
-#include "nvim/msgpack_rpc/helpers.h"
-#include "nvim/vim.h"
+#include "nvim/event/wstream.h"
+#include "nvim/lib/kvec.h"
+#include "nvim/log.h"
#include "nvim/main.h"
-#include "nvim/ascii.h"
+#include "nvim/map.h"
#include "nvim/memory.h"
-#include "nvim/eval.h"
-#include "nvim/os_unix.h"
#include "nvim/message.h"
-#include "nvim/map.h"
-#include "nvim/log.h"
#include "nvim/misc1.h"
-#include "nvim/lib/kvec.h"
+#include "nvim/msgpack_rpc/channel.h"
+#include "nvim/msgpack_rpc/helpers.h"
#include "nvim/os/input.h"
+#include "nvim/os_unix.h"
#include "nvim/ui.h"
+#include "nvim/vim.h"
#if MIN_LOG_LEVEL > DEBUG_LOG_LEVEL
-#define log_client_msg(...)
-#define log_server_msg(...)
+# define log_client_msg(...)
+# define log_server_msg(...)
#endif
-static PMap(cstr_t) *event_strings = NULL;
+static PMap(cstr_t) event_strings = MAP_INIT;
static msgpack_sbuffer out_buffer;
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -48,7 +47,6 @@ static msgpack_sbuffer out_buffer;
void rpc_init(void)
{
ch_before_blocking_events = multiqueue_new_child(main_loop.events);
- event_strings = pmap_new(cstr_t)();
msgpack_sbuffer_init(&out_buffer);
}
@@ -60,7 +58,6 @@ void rpc_start(Channel *channel)
RpcState *rpc = &channel->rpc;
rpc->closed = false;
rpc->unpacker = msgpack_unpacker_new(MSGPACK_UNPACKER_INIT_BUFFER_SIZE);
- rpc->subscribed_events = pmap_new(cstr_t)();
rpc->next_request_id = 1;
rpc->info = (Dictionary)ARRAY_DICT_INIT;
kv_init(rpc->call_stack);
@@ -104,7 +101,7 @@ bool rpc_send_event(uint64_t id, const char *name, Array args)
if (channel) {
send_event(channel, name, args);
- } else {
+ } else {
broadcast_event(name, args);
}
@@ -118,10 +115,7 @@ bool rpc_send_event(uint64_t id, const char *name, Array args)
/// @param args Array with method arguments
/// @param[out] error True if the return value is an error
/// @return Whatever the remote method returned
-Object rpc_send_call(uint64_t id,
- const char *method_name,
- Array args,
- Error *err)
+Object rpc_send_call(uint64_t id, const char *method_name, Array args, Error *err)
{
Channel *channel = NULL;
@@ -183,11 +177,11 @@ void rpc_subscribe(uint64_t id, char *event)
abort();
}
- char *event_string = pmap_get(cstr_t)(event_strings, event);
+ char *event_string = pmap_get(cstr_t)(&event_strings, event);
if (!event_string) {
event_string = xstrdup(event);
- pmap_put(cstr_t)(event_strings, event_string, event_string);
+ pmap_put(cstr_t)(&event_strings, event_string, event_string);
}
pmap_put(cstr_t)(channel->rpc.subscribed_events, event_string, event_string);
@@ -208,8 +202,7 @@ void rpc_unsubscribe(uint64_t id, char *event)
unsubscribe(channel, event);
}
-static void receive_msgpack(Stream *stream, RBuffer *rbuf, size_t c,
- void *data, bool eof)
+static void receive_msgpack(Stream *stream, RBuffer *rbuf, size_t c, void *data, bool eof)
{
Channel *channel = data;
channel_incref(channel);
@@ -465,10 +458,7 @@ static void send_error(Channel *chan, MessageType type, uint32_t id, char *err)
api_clear_error(&e);
}
-static void send_request(Channel *channel,
- uint32_t id,
- const char *name,
- Array args)
+static void send_request(Channel *channel, uint32_t id, const char *name, Array args)
{
const String method = cstr_as_string((char *)name);
channel_write(channel, serialize_request(channel->id,
@@ -479,9 +469,7 @@ static void send_request(Channel *channel,
1));
}
-static void send_event(Channel *channel,
- const char *name,
- Array args)
+static void send_event(Channel *channel, const char *name, Array args)
{
const String method = cstr_as_string((char *)name);
channel_write(channel, serialize_request(channel->id,
@@ -497,7 +485,7 @@ static void broadcast_event(const char *name, Array args)
kvec_t(Channel *) subscribed = KV_INITIAL_VALUE;
Channel *channel;
- map_foreach_value(channels, channel, {
+ map_foreach_value(&channels, channel, {
if (channel->is_rpc
&& pmap_has(cstr_t)(channel->rpc.subscribed_events, name)) {
kv_push(subscribed, channel);
@@ -528,15 +516,15 @@ end:
static void unsubscribe(Channel *channel, char *event)
{
- char *event_string = pmap_get(cstr_t)(event_strings, event);
+ char *event_string = pmap_get(cstr_t)(&event_strings, event);
if (!event_string) {
- WLOG("RPC: ch %" PRIu64 ": tried to unsubscribe unknown event '%s'",
- channel->id, event);
- return;
+ WLOG("RPC: ch %" PRIu64 ": tried to unsubscribe unknown event '%s'",
+ channel->id, event);
+ return;
}
pmap_del(cstr_t)(channel->rpc.subscribed_events, event_string);
- map_foreach_value(channels, channel, {
+ map_foreach_value(&channels, channel, {
if (channel->is_rpc
&& pmap_has(cstr_t)(channel->rpc.subscribed_events, event_string)) {
return;
@@ -544,7 +532,7 @@ static void unsubscribe(Channel *channel, char *event)
});
// Since the string is no longer used by other channels, release it's memory
- pmap_del(cstr_t)(event_strings, event_string);
+ pmap_del(cstr_t)(&event_strings, event_string);
xfree(event_string);
}
@@ -583,7 +571,7 @@ void rpc_free(Channel *channel)
unsubscribe(channel, event_string);
});
- pmap_free(cstr_t)(channel->rpc.subscribed_events);
+ pmap_destroy(cstr_t)(channel->rpc.subscribed_events);
kv_destroy(channel->rpc.call_stack);
api_free_dictionary(channel->rpc.info);
}
@@ -591,10 +579,10 @@ void rpc_free(Channel *channel)
static bool is_rpc_response(msgpack_object *obj)
{
return obj->type == MSGPACK_OBJECT_ARRAY
- && obj->via.array.size == 4
- && obj->via.array.ptr[0].type == MSGPACK_OBJECT_POSITIVE_INTEGER
- && obj->via.array.ptr[0].via.u64 == 1
- && obj->via.array.ptr[1].type == MSGPACK_OBJECT_POSITIVE_INTEGER;
+ && obj->via.array.size == 4
+ && obj->via.array.ptr[0].type == MSGPACK_OBJECT_POSITIVE_INTEGER
+ && obj->via.array.ptr[0].via.u64 == 1
+ && obj->via.array.ptr[1].type == MSGPACK_OBJECT_POSITIVE_INTEGER;
}
static bool is_valid_rpc_response(msgpack_object *obj, Channel *channel)
@@ -636,12 +624,8 @@ static void call_set_error(Channel *channel, char *msg, int loglevel)
channel_close(channel->id, kChannelPartRpc, NULL);
}
-static WBuffer *serialize_request(uint64_t channel_id,
- uint32_t request_id,
- const String method,
- Array args,
- msgpack_sbuffer *sbuffer,
- size_t refcount)
+static WBuffer *serialize_request(uint64_t channel_id, uint32_t request_id, const String method,
+ Array args, msgpack_sbuffer *sbuffer, size_t refcount)
{
msgpack_packer pac;
msgpack_packer_init(&pac, sbuffer, msgpack_sbuffer_write);
@@ -656,12 +640,8 @@ static WBuffer *serialize_request(uint64_t channel_id,
return rv;
}
-static WBuffer *serialize_response(uint64_t channel_id,
- MessageType type,
- uint32_t response_id,
- Error *err,
- Object arg,
- msgpack_sbuffer *sbuffer)
+static WBuffer *serialize_response(uint64_t channel_id, MessageType type, uint32_t response_id,
+ Error *err, Object arg, msgpack_sbuffer *sbuffer)
{
msgpack_packer pac;
msgpack_packer_init(&pac, sbuffer, msgpack_sbuffer_write);
@@ -719,14 +699,14 @@ const char *rpc_client_name(Channel *chan)
}
#if MIN_LOG_LEVEL <= DEBUG_LOG_LEVEL
-#define REQ "[request] "
-#define RES "[response] "
-#define NOT "[notify] "
-#define ERR "[error] "
+# define REQ "[request] "
+# define RES "[response] "
+# define NOT "[notify] "
+# define ERR "[error] "
// Cannot define array with negative offsets, so this one is needed to be added
// to MSGPACK_UNPACK_\* values.
-#define MUR_OFF 2
+# define MUR_OFF 2
static const char *const msgpack_error_messages[] = {
[MSGPACK_UNPACK_EXTRA_BYTES + MUR_OFF] = "extra bytes found",
@@ -735,47 +715,43 @@ static const char *const msgpack_error_messages[] = {
[MSGPACK_UNPACK_NOMEM_ERROR + MUR_OFF] = "not enough memory",
};
-static void log_server_msg(uint64_t channel_id,
- msgpack_sbuffer *packed)
+static void log_server_msg(uint64_t channel_id, msgpack_sbuffer *packed)
{
msgpack_unpacked unpacked;
msgpack_unpacked_init(&unpacked);
DLOGN("RPC ->ch %" PRIu64 ": ", channel_id);
const msgpack_unpack_return result =
- msgpack_unpack_next(&unpacked, packed->data, packed->size, NULL);
+ msgpack_unpack_next(&unpacked, packed->data, packed->size, NULL);
switch (result) {
- case MSGPACK_UNPACK_SUCCESS: {
- uint64_t type = unpacked.data.via.array.ptr[0].via.u64;
- log_lock();
- FILE *f = open_log_file();
- fprintf(f, type ? (type == 1 ? RES : NOT) : REQ);
- log_msg_close(f, unpacked.data);
- msgpack_unpacked_destroy(&unpacked);
- break;
- }
- case MSGPACK_UNPACK_EXTRA_BYTES:
- case MSGPACK_UNPACK_CONTINUE:
- case MSGPACK_UNPACK_PARSE_ERROR:
- case MSGPACK_UNPACK_NOMEM_ERROR: {
- log_lock();
- FILE *f = open_log_file();
- fprintf(f, ERR);
- log_msg_close(f, (msgpack_object) {
- .type = MSGPACK_OBJECT_STR,
- .via.str = {
- .ptr = (char *)msgpack_error_messages[result + MUR_OFF],
- .size = (uint32_t)strlen(
- msgpack_error_messages[result + MUR_OFF]),
- },
+ case MSGPACK_UNPACK_SUCCESS: {
+ uint64_t type = unpacked.data.via.array.ptr[0].via.u64;
+ log_lock();
+ FILE *f = open_log_file();
+ fprintf(f, type ? (type == 1 ? RES : NOT) : REQ);
+ log_msg_close(f, unpacked.data);
+ msgpack_unpacked_destroy(&unpacked);
+ break;
+ }
+ case MSGPACK_UNPACK_EXTRA_BYTES:
+ case MSGPACK_UNPACK_CONTINUE:
+ case MSGPACK_UNPACK_PARSE_ERROR:
+ case MSGPACK_UNPACK_NOMEM_ERROR: {
+ log_lock();
+ FILE *f = open_log_file();
+ fprintf(f, ERR);
+ log_msg_close(f, (msgpack_object) {
+ .type = MSGPACK_OBJECT_STR,
+ .via.str = {
+ .ptr = (char *)msgpack_error_messages[result + MUR_OFF],
+ .size = (uint32_t)strlen(msgpack_error_messages[result + MUR_OFF]),
+ },
});
- break;
- }
+ break;
+ }
}
}
-static void log_client_msg(uint64_t channel_id,
- bool is_request,
- msgpack_object msg)
+static void log_client_msg(uint64_t channel_id, bool is_request, msgpack_object msg)
{
DLOGN("RPC <-ch %" PRIu64 ": ", channel_id);
log_lock();
diff --git a/src/nvim/msgpack_rpc/channel_defs.h b/src/nvim/msgpack_rpc/channel_defs.h
index 6ef8c027f0..de328af1ce 100644
--- a/src/nvim/msgpack_rpc/channel_defs.h
+++ b/src/nvim/msgpack_rpc/channel_defs.h
@@ -27,7 +27,7 @@ typedef struct {
} RequestEvent;
typedef struct {
- PMap(cstr_t) *subscribed_events;
+ PMap(cstr_t) subscribed_events[1];
bool closed;
msgpack_unpacker *unpacker;
uint32_t next_request_id;
diff --git a/src/nvim/msgpack_rpc/helpers.c b/src/nvim/msgpack_rpc/helpers.c
index a4a36e5ebf..b1b9c77953 100644
--- a/src/nvim/msgpack_rpc/helpers.c
+++ b/src/nvim/msgpack_rpc/helpers.c
@@ -1,19 +1,18 @@
// 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 <stdbool.h>
#include <inttypes.h>
-
#include <msgpack.h>
+#include <stdbool.h>
#include "nvim/api/private/dispatch.h"
#include "nvim/api/private/helpers.h"
-#include "nvim/msgpack_rpc/helpers.h"
+#include "nvim/assert.h"
#include "nvim/lib/kvec.h"
-#include "nvim/vim.h"
#include "nvim/log.h"
#include "nvim/memory.h"
-#include "nvim/assert.h"
+#include "nvim/msgpack_rpc/helpers.h"
+#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "msgpack_rpc/helpers.c.generated.h"
@@ -86,8 +85,9 @@ bool msgpack_rpc_to_object(const msgpack_object *const obj, Object *const arg)
FUNC_ATTR_NONNULL_ALL
{
bool ret = true;
- kvec_t(MPToAPIObjectStackItem) stack = KV_INITIAL_VALUE;
- kv_push(stack, ((MPToAPIObjectStackItem) {
+ kvec_withinit_t(MPToAPIObjectStackItem, 2) stack = KV_INITIAL_VALUE;
+ kvi_init(stack);
+ kvi_push(stack, ((MPToAPIObjectStackItem) {
.mobj = obj,
.aobj = arg,
.container = false,
@@ -99,178 +99,167 @@ bool msgpack_rpc_to_object(const msgpack_object *const obj, Object *const arg)
*cur.aobj = NIL;
}
switch (cur.mobj->type) {
- case MSGPACK_OBJECT_NIL: {
- break;
- }
- case MSGPACK_OBJECT_BOOLEAN: {
- *cur.aobj = BOOLEAN_OBJ(cur.mobj->via.boolean);
- break;
- }
- case MSGPACK_OBJECT_NEGATIVE_INTEGER: {
- STATIC_ASSERT(sizeof(Integer) == sizeof(cur.mobj->via.i64),
- "Msgpack integer size does not match API integer");
- *cur.aobj = INTEGER_OBJ(cur.mobj->via.i64);
- break;
- }
- case MSGPACK_OBJECT_POSITIVE_INTEGER: {
- STATIC_ASSERT(sizeof(Integer) == sizeof(cur.mobj->via.u64),
- "Msgpack integer size does not match API integer");
- if (cur.mobj->via.u64 > API_INTEGER_MAX) {
- ret = false;
- } else {
- *cur.aobj = INTEGER_OBJ((Integer)cur.mobj->via.u64);
- }
- break;
+ case MSGPACK_OBJECT_NIL:
+ break;
+ case MSGPACK_OBJECT_BOOLEAN:
+ *cur.aobj = BOOLEAN_OBJ(cur.mobj->via.boolean);
+ break;
+ case MSGPACK_OBJECT_NEGATIVE_INTEGER:
+ STATIC_ASSERT(sizeof(Integer) == sizeof(cur.mobj->via.i64),
+ "Msgpack integer size does not match API integer");
+ *cur.aobj = INTEGER_OBJ(cur.mobj->via.i64);
+ break;
+ case MSGPACK_OBJECT_POSITIVE_INTEGER:
+ STATIC_ASSERT(sizeof(Integer) == sizeof(cur.mobj->via.u64),
+ "Msgpack integer size does not match API integer");
+ if (cur.mobj->via.u64 > API_INTEGER_MAX) {
+ ret = false;
+ } else {
+ *cur.aobj = INTEGER_OBJ((Integer)cur.mobj->via.u64);
}
+ break;
#ifdef NVIM_MSGPACK_HAS_FLOAT32
- case MSGPACK_OBJECT_FLOAT32:
- case MSGPACK_OBJECT_FLOAT64:
+ case MSGPACK_OBJECT_FLOAT32:
+ case MSGPACK_OBJECT_FLOAT64:
#else
- case MSGPACK_OBJECT_FLOAT:
+ case MSGPACK_OBJECT_FLOAT:
#endif
- {
- STATIC_ASSERT(sizeof(Float) == sizeof(cur.mobj->via.f64),
- "Msgpack floating-point size does not match API integer");
- *cur.aobj = FLOAT_OBJ(cur.mobj->via.f64);
- break;
- }
+ {
+ STATIC_ASSERT(sizeof(Float) == sizeof(cur.mobj->via.f64),
+ "Msgpack floating-point size does not match API integer");
+ *cur.aobj = FLOAT_OBJ(cur.mobj->via.f64);
+ break;
+ }
#define STR_CASE(type, attr, obj, dest, conv) \
- case type: { \
- dest = conv(((String) { \
- .size = obj->via.attr.size, \
- .data = (obj->via.attr.ptr == NULL || obj->via.attr.size == 0 \
+case type: { \
+ dest = conv(((String) { \
+ .size = obj->via.attr.size, \
+ .data = (obj->via.attr.ptr == NULL || obj->via.attr.size == 0 \
? xmemdupz("", 0) \
: xmemdupz(obj->via.attr.ptr, obj->via.attr.size)), \
- })); \
- break; \
- }
+ })); \
+ break; \
+}
STR_CASE(MSGPACK_OBJECT_STR, str, cur.mobj, *cur.aobj, STRING_OBJ)
STR_CASE(MSGPACK_OBJECT_BIN, bin, cur.mobj, *cur.aobj, STRING_OBJ)
- case MSGPACK_OBJECT_ARRAY: {
- const size_t size = cur.mobj->via.array.size;
- if (cur.container) {
- if (cur.idx >= size) {
- (void)kv_pop(stack);
- } else {
- const size_t idx = cur.idx;
- cur.idx++;
- kv_last(stack) = cur;
- kv_push(stack, ((MPToAPIObjectStackItem) {
+ case MSGPACK_OBJECT_ARRAY: {
+ const size_t size = cur.mobj->via.array.size;
+ if (cur.container) {
+ if (cur.idx >= size) {
+ (void)kv_pop(stack);
+ } else {
+ const size_t idx = cur.idx;
+ cur.idx++;
+ kv_last(stack) = cur;
+ kvi_push(stack, ((MPToAPIObjectStackItem) {
.mobj = &cur.mobj->via.array.ptr[idx],
.aobj = &cur.aobj->data.array.items[idx],
.container = false,
}));
- }
- } else {
- *cur.aobj = ARRAY_OBJ(((Array) {
+ }
+ } else {
+ *cur.aobj = ARRAY_OBJ(((Array) {
.size = size,
.capacity = size,
.items = (size > 0
? xcalloc(size, sizeof(*cur.aobj->data.array.items))
: NULL),
}));
- cur.container = true;
- kv_last(stack) = cur;
- }
- break;
+ cur.container = true;
+ kv_last(stack) = cur;
}
- case MSGPACK_OBJECT_MAP: {
- const size_t size = cur.mobj->via.map.size;
- if (cur.container) {
- if (cur.idx >= size) {
- (void)kv_pop(stack);
- } else {
- const size_t idx = cur.idx;
- cur.idx++;
- kv_last(stack) = cur;
- const msgpack_object *const key = &cur.mobj->via.map.ptr[idx].key;
- switch (key->type) {
+ break;
+ }
+ case MSGPACK_OBJECT_MAP: {
+ const size_t size = cur.mobj->via.map.size;
+ if (cur.container) {
+ if (cur.idx >= size) {
+ (void)kv_pop(stack);
+ } else {
+ const size_t idx = cur.idx;
+ cur.idx++;
+ kv_last(stack) = cur;
+ const msgpack_object *const key = &cur.mobj->via.map.ptr[idx].key;
+ switch (key->type) {
#define ID(x) x
- STR_CASE(MSGPACK_OBJECT_STR, str, key,
- cur.aobj->data.dictionary.items[idx].key, ID)
- STR_CASE(MSGPACK_OBJECT_BIN, bin, key,
- cur.aobj->data.dictionary.items[idx].key, ID)
+ STR_CASE(MSGPACK_OBJECT_STR, str, key,
+ cur.aobj->data.dictionary.items[idx].key, ID)
+ STR_CASE(MSGPACK_OBJECT_BIN, bin, key,
+ cur.aobj->data.dictionary.items[idx].key, ID)
#undef ID
- case MSGPACK_OBJECT_NIL:
- case MSGPACK_OBJECT_BOOLEAN:
- case MSGPACK_OBJECT_POSITIVE_INTEGER:
- case MSGPACK_OBJECT_NEGATIVE_INTEGER:
+ case MSGPACK_OBJECT_NIL:
+ case MSGPACK_OBJECT_BOOLEAN:
+ case MSGPACK_OBJECT_POSITIVE_INTEGER:
+ case MSGPACK_OBJECT_NEGATIVE_INTEGER:
#ifdef NVIM_MSGPACK_HAS_FLOAT32
- case MSGPACK_OBJECT_FLOAT32:
- case MSGPACK_OBJECT_FLOAT64:
+ case MSGPACK_OBJECT_FLOAT32:
+ case MSGPACK_OBJECT_FLOAT64:
#else
- case MSGPACK_OBJECT_FLOAT:
+ case MSGPACK_OBJECT_FLOAT:
#endif
- case MSGPACK_OBJECT_EXT:
- case MSGPACK_OBJECT_MAP:
- case MSGPACK_OBJECT_ARRAY: {
- ret = false;
- break;
- }
- }
- if (ret) {
- kv_push(stack, ((MPToAPIObjectStackItem) {
+ case MSGPACK_OBJECT_EXT:
+ case MSGPACK_OBJECT_MAP:
+ case MSGPACK_OBJECT_ARRAY:
+ ret = false;
+ break;
+ }
+ if (ret) {
+ kvi_push(stack, ((MPToAPIObjectStackItem) {
.mobj = &cur.mobj->via.map.ptr[idx].val,
.aobj = &cur.aobj->data.dictionary.items[idx].value,
.container = false,
}));
- }
}
- } else {
- *cur.aobj = DICTIONARY_OBJ(((Dictionary) {
+ }
+ } else {
+ *cur.aobj = DICTIONARY_OBJ(((Dictionary) {
.size = size,
.capacity = size,
.items = (size > 0
? xcalloc(size, sizeof(*cur.aobj->data.dictionary.items))
: NULL),
}));
- cur.container = true;
- kv_last(stack) = cur;
- }
- break;
+ cur.container = true;
+ kv_last(stack) = cur;
}
- case MSGPACK_OBJECT_EXT: {
- switch ((ObjectType)(cur.mobj->via.ext.type + EXT_OBJECT_TYPE_SHIFT)) {
- case kObjectTypeBuffer: {
- cur.aobj->type = kObjectTypeBuffer;
- ret = msgpack_rpc_to_buffer(cur.mobj, &cur.aobj->data.integer);
- break;
- }
- case kObjectTypeWindow: {
- cur.aobj->type = kObjectTypeWindow;
- ret = msgpack_rpc_to_window(cur.mobj, &cur.aobj->data.integer);
- break;
- }
- case kObjectTypeTabpage: {
- cur.aobj->type = kObjectTypeTabpage;
- ret = msgpack_rpc_to_tabpage(cur.mobj, &cur.aobj->data.integer);
- break;
- }
- case kObjectTypeNil:
- case kObjectTypeBoolean:
- case kObjectTypeInteger:
- case kObjectTypeFloat:
- case kObjectTypeString:
- case kObjectTypeArray:
- case kObjectTypeDictionary:
- case kObjectTypeLuaRef: {
- break;
- }
- }
+ break;
+ }
+ case MSGPACK_OBJECT_EXT:
+ switch ((ObjectType)(cur.mobj->via.ext.type + EXT_OBJECT_TYPE_SHIFT)) {
+ case kObjectTypeBuffer:
+ cur.aobj->type = kObjectTypeBuffer;
+ ret = msgpack_rpc_to_buffer(cur.mobj, &cur.aobj->data.integer);
+ break;
+ case kObjectTypeWindow:
+ cur.aobj->type = kObjectTypeWindow;
+ ret = msgpack_rpc_to_window(cur.mobj, &cur.aobj->data.integer);
+ break;
+ case kObjectTypeTabpage:
+ cur.aobj->type = kObjectTypeTabpage;
+ ret = msgpack_rpc_to_tabpage(cur.mobj, &cur.aobj->data.integer);
+ break;
+ case kObjectTypeNil:
+ case kObjectTypeBoolean:
+ case kObjectTypeInteger:
+ case kObjectTypeFloat:
+ case kObjectTypeString:
+ case kObjectTypeArray:
+ case kObjectTypeDictionary:
+ case kObjectTypeLuaRef:
break;
}
+ break;
#undef STR_CASE
}
if (!cur.container) {
(void)kv_pop(stack);
}
}
- kv_destroy(stack);
+ kvi_destroy(stack);
return ret;
}
-static bool msgpack_rpc_to_string(const msgpack_object *const obj,
- String *const arg)
+static bool msgpack_rpc_to_string(const msgpack_object *const obj, String *const arg)
FUNC_ATTR_NONNULL_ALL
{
if (obj->type == MSGPACK_OBJECT_BIN || obj->type == MSGPACK_OBJECT_STR) {
@@ -302,8 +291,7 @@ bool msgpack_rpc_to_array(const msgpack_object *const obj, Array *const arg)
return true;
}
-bool msgpack_rpc_to_dictionary(const msgpack_object *const obj,
- Dictionary *const arg)
+bool msgpack_rpc_to_dictionary(const msgpack_object *const obj, Dictionary *const arg)
FUNC_ATTR_NONNULL_ALL
{
if (obj->type != MSGPACK_OBJECT_MAP) {
@@ -316,12 +304,12 @@ bool msgpack_rpc_to_dictionary(const msgpack_object *const obj,
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)) {
+ &arg->items[i].key)) {
return false;
}
if (!msgpack_rpc_to_object(&obj->via.map.ptr[i].val,
- &arg->items[i].value)) {
+ &arg->items[i].value)) {
return false;
}
}
@@ -375,100 +363,93 @@ typedef struct {
void msgpack_rpc_from_object(const Object result, msgpack_packer *const res)
FUNC_ATTR_NONNULL_ARG(2)
{
- kvec_t(APIToMPObjectStackItem) stack = KV_INITIAL_VALUE;
- kv_push(stack, ((APIToMPObjectStackItem) { &result, false, 0 }));
+ kvec_withinit_t(APIToMPObjectStackItem, 2) stack = KV_INITIAL_VALUE;
+ kvi_init(stack);
+ kvi_push(stack, ((APIToMPObjectStackItem) { &result, false, 0 }));
while (kv_size(stack)) {
APIToMPObjectStackItem cur = kv_last(stack);
STATIC_ASSERT(kObjectTypeWindow == kObjectTypeBuffer + 1
&& kObjectTypeTabpage == kObjectTypeWindow + 1,
"Buffer, window and tabpage enum items are in order");
switch (cur.aobj->type) {
- case kObjectTypeNil:
- case kObjectTypeLuaRef: {
- // TODO(bfredl): could also be an error. Though kObjectTypeLuaRef
- // should only appear when the caller has opted in to handle references,
- // see nlua_pop_Object.
- msgpack_pack_nil(res);
- break;
- }
- case kObjectTypeBoolean: {
- msgpack_rpc_from_boolean(cur.aobj->data.boolean, res);
- break;
- }
- case kObjectTypeInteger: {
- msgpack_rpc_from_integer(cur.aobj->data.integer, res);
- break;
- }
- case kObjectTypeFloat: {
- msgpack_rpc_from_float(cur.aobj->data.floating, res);
- break;
- }
- case kObjectTypeString: {
- msgpack_rpc_from_string(cur.aobj->data.string, res);
- break;
- }
- case kObjectTypeBuffer: {
- msgpack_rpc_from_buffer(cur.aobj->data.integer, res);
- break;
- }
- case kObjectTypeWindow: {
- msgpack_rpc_from_window(cur.aobj->data.integer, res);
- break;
- }
- case kObjectTypeTabpage: {
- msgpack_rpc_from_tabpage(cur.aobj->data.integer, res);
- break;
- }
- case kObjectTypeArray: {
- const size_t size = cur.aobj->data.array.size;
- if (cur.container) {
- if (cur.idx >= size) {
- (void)kv_pop(stack);
- } else {
- const size_t idx = cur.idx;
- cur.idx++;
- kv_last(stack) = cur;
- kv_push(stack, ((APIToMPObjectStackItem) {
+ case kObjectTypeNil:
+ case kObjectTypeLuaRef:
+ // TODO(bfredl): could also be an error. Though kObjectTypeLuaRef
+ // should only appear when the caller has opted in to handle references,
+ // see nlua_pop_Object.
+ msgpack_pack_nil(res);
+ break;
+ case kObjectTypeBoolean:
+ msgpack_rpc_from_boolean(cur.aobj->data.boolean, res);
+ break;
+ case kObjectTypeInteger:
+ msgpack_rpc_from_integer(cur.aobj->data.integer, res);
+ break;
+ case kObjectTypeFloat:
+ msgpack_rpc_from_float(cur.aobj->data.floating, res);
+ break;
+ case kObjectTypeString:
+ msgpack_rpc_from_string(cur.aobj->data.string, res);
+ break;
+ case kObjectTypeBuffer:
+ msgpack_rpc_from_buffer(cur.aobj->data.integer, res);
+ break;
+ case kObjectTypeWindow:
+ msgpack_rpc_from_window(cur.aobj->data.integer, res);
+ break;
+ case kObjectTypeTabpage:
+ msgpack_rpc_from_tabpage(cur.aobj->data.integer, res);
+ break;
+ case kObjectTypeArray: {
+ const size_t size = cur.aobj->data.array.size;
+ if (cur.container) {
+ if (cur.idx >= size) {
+ (void)kv_pop(stack);
+ } else {
+ const size_t idx = cur.idx;
+ cur.idx++;
+ kv_last(stack) = cur;
+ kvi_push(stack, ((APIToMPObjectStackItem) {
.aobj = &cur.aobj->data.array.items[idx],
.container = false,
}));
- }
- } else {
- msgpack_pack_array(res, size);
- cur.container = true;
- kv_last(stack) = cur;
}
- break;
+ } else {
+ msgpack_pack_array(res, size);
+ cur.container = true;
+ kv_last(stack) = cur;
}
- case kObjectTypeDictionary: {
- const size_t size = cur.aobj->data.dictionary.size;
- if (cur.container) {
- if (cur.idx >= size) {
- (void)kv_pop(stack);
- } else {
- const size_t idx = cur.idx;
- cur.idx++;
- kv_last(stack) = cur;
- msgpack_rpc_from_string(cur.aobj->data.dictionary.items[idx].key,
- res);
- kv_push(stack, ((APIToMPObjectStackItem) {
+ break;
+ }
+ case kObjectTypeDictionary: {
+ const size_t size = cur.aobj->data.dictionary.size;
+ if (cur.container) {
+ if (cur.idx >= size) {
+ (void)kv_pop(stack);
+ } else {
+ const size_t idx = cur.idx;
+ cur.idx++;
+ kv_last(stack) = cur;
+ msgpack_rpc_from_string(cur.aobj->data.dictionary.items[idx].key,
+ res);
+ kvi_push(stack, ((APIToMPObjectStackItem) {
.aobj = &cur.aobj->data.dictionary.items[idx].value,
.container = false,
}));
- }
- } else {
- msgpack_pack_map(res, size);
- cur.container = true;
- kv_last(stack) = cur;
}
- break;
+ } else {
+ msgpack_pack_map(res, size);
+ cur.container = true;
+ kv_last(stack) = cur;
}
+ break;
+ }
}
if (!cur.container) {
(void)kv_pop(stack);
}
}
- kv_destroy(stack);
+ kvi_destroy(stack);
}
void msgpack_rpc_from_array(Array result, msgpack_packer *res)
@@ -493,9 +474,7 @@ void msgpack_rpc_from_dictionary(Dictionary result, msgpack_packer *res)
}
/// Serializes a msgpack-rpc request or notification(id == 0)
-void msgpack_rpc_serialize_request(uint32_t request_id,
- const String method,
- Array args,
+void msgpack_rpc_serialize_request(uint32_t request_id, const String method, Array args,
msgpack_packer *pac)
FUNC_ATTR_NONNULL_ARG(4)
{
@@ -511,9 +490,7 @@ void msgpack_rpc_serialize_request(uint32_t request_id,
}
/// Serializes a msgpack-rpc response
-void msgpack_rpc_serialize_response(uint32_t response_id,
- Error *err,
- Object arg,
+void msgpack_rpc_serialize_response(uint32_t response_id, Error *err, Object arg,
msgpack_packer *pac)
FUNC_ATTR_NONNULL_ARG(2, 4)
{
@@ -544,15 +521,15 @@ static bool msgpack_rpc_is_notification(msgpack_object *req)
msgpack_object *msgpack_rpc_method(msgpack_object *req)
{
msgpack_object *obj = req->via.array.ptr
- + (msgpack_rpc_is_notification(req) ? 1 : 2);
+ + (msgpack_rpc_is_notification(req) ? 1 : 2);
return obj->type == MSGPACK_OBJECT_STR || obj->type == MSGPACK_OBJECT_BIN ?
- obj : NULL;
+ obj : NULL;
}
msgpack_object *msgpack_rpc_args(msgpack_object *req)
{
msgpack_object *obj = req->via.array.ptr
- + (msgpack_rpc_is_notification(req) ? 2 : 3);
+ + (msgpack_rpc_is_notification(req) ? 2 : 3);
return obj->type == MSGPACK_OBJECT_ARRAY ? obj : NULL;
}
@@ -565,8 +542,7 @@ static msgpack_object *msgpack_rpc_msg_id(msgpack_object *req)
return obj->type == MSGPACK_OBJECT_POSITIVE_INTEGER ? obj : NULL;
}
-MessageType msgpack_rpc_validate(uint32_t *response_id, msgpack_object *req,
- Error *err)
+MessageType msgpack_rpc_validate(uint32_t *response_id, msgpack_object *req, Error *err)
{
*response_id = 0;
// Validate the basic structure of the msgpack-rpc payload
diff --git a/src/nvim/msgpack_rpc/server.c b/src/nvim/msgpack_rpc/server.c
index 062ea784ca..e954e4b3a3 100644
--- a/src/nvim/msgpack_rpc/server.c
+++ b/src/nvim/msgpack_rpc/server.c
@@ -2,24 +2,24 @@
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <assert.h>
+#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
-#include <inttypes.h>
-#include "nvim/msgpack_rpc/channel.h"
-#include "nvim/msgpack_rpc/server.h"
-#include "nvim/os/os.h"
-#include "nvim/event/socket.h"
#include "nvim/ascii.h"
#include "nvim/eval.h"
+#include "nvim/event/socket.h"
+#include "nvim/fileio.h"
#include "nvim/garray.h"
-#include "nvim/vim.h"
+#include "nvim/log.h"
#include "nvim/main.h"
#include "nvim/memory.h"
-#include "nvim/log.h"
-#include "nvim/fileio.h"
+#include "nvim/msgpack_rpc/channel.h"
+#include "nvim/msgpack_rpc/server.h"
+#include "nvim/os/os.h"
#include "nvim/path.h"
#include "nvim/strings.h"
+#include "nvim/vim.h"
#define MAX_CONNECTIONS 32
#define LISTEN_ADDRESS_ENV_VAR "NVIM_LISTEN_ADDRESS"
@@ -90,7 +90,7 @@ char *server_address_new(void)
static uint32_t count = 0;
char template[ADDRESS_MAX_SIZE];
snprintf(template, ADDRESS_MAX_SIZE,
- "\\\\.\\pipe\\nvim-%" PRIu64 "-%" PRIu32, os_get_pid(), count++);
+ "\\\\.\\pipe\\nvim-%" PRIu64 "-%" PRIu32, os_get_pid(), count++);
return xstrdup(template);
#else
return (char *)vim_tempname();
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 44cdc09c0b..493c704f42 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -9,14 +9,12 @@
#include <assert.h>
#include <inttypes.h>
-#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
+#include <string.h>
-#include "nvim/log.h"
-#include "nvim/vim.h"
+#include "nvim/api/private/helpers.h"
#include "nvim/ascii.h"
-#include "nvim/normal.h"
#include "nvim/buffer.h"
#include "nvim/change.h"
#include "nvim/charset.h"
@@ -25,6 +23,7 @@
#include "nvim/digraph.h"
#include "nvim/edit.h"
#include "nvim/eval/userfunc.h"
+#include "nvim/event/loop.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_docmd.h"
@@ -34,34 +33,35 @@
#include "nvim/getchar.h"
#include "nvim/indent.h"
#include "nvim/indent_c.h"
+#include "nvim/keymap.h"
+#include "nvim/log.h"
#include "nvim/main.h"
#include "nvim/mark.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
-#include "nvim/keymap.h"
-#include "nvim/move.h"
#include "nvim/mouse.h"
+#include "nvim/move.h"
+#include "nvim/normal.h"
#include "nvim/ops.h"
#include "nvim/option.h"
+#include "nvim/os/input.h"
+#include "nvim/os/time.h"
+#include "nvim/plines.h"
#include "nvim/quickfix.h"
#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/spell.h"
#include "nvim/spellfile.h"
+#include "nvim/state.h"
#include "nvim/strings.h"
#include "nvim/syntax.h"
#include "nvim/tag.h"
#include "nvim/ui.h"
-#include "nvim/mouse.h"
#include "nvim/undo.h"
+#include "nvim/vim.h"
#include "nvim/window.h"
-#include "nvim/state.h"
-#include "nvim/event/loop.h"
-#include "nvim/os/time.h"
-#include "nvim/os/input.h"
-#include "nvim/api/private/helpers.h"
typedef struct normal_state {
VimState state;
@@ -87,12 +87,10 @@ typedef struct normal_state {
/*
* The Visual area is remembered for reselection.
*/
-static int resel_VIsual_mode = NUL; /* 'v', 'V', or Ctrl-V */
-static linenr_T resel_VIsual_line_count; /* number of lines */
-static colnr_T resel_VIsual_vcol; /* nr of cols or end col */
-static int VIsual_mode_orig = NUL; /* saved Visual mode */
-
-static int restart_VIsual_select = 0;
+static int resel_VIsual_mode = NUL; // 'v', 'V', or Ctrl-V
+static linenr_T resel_VIsual_line_count; // number of lines
+static colnr_T resel_VIsual_vcol; // nr of cols or end col
+static int VIsual_mode_orig = NUL; // saved Visual mode
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -120,18 +118,18 @@ static char *e_noident = N_("E349: No identifier under cursor");
*/
typedef void (*nv_func_T)(cmdarg_T *cap);
-/* Values for cmd_flags. */
-#define NV_NCH 0x01 /* may need to get a second char */
-#define NV_NCH_NOP (0x02|NV_NCH) /* get second char when no operator pending */
-#define NV_NCH_ALW (0x04|NV_NCH) /* always get a second char */
-#define NV_LANG 0x08 /* second char needs language adjustment */
+// Values for cmd_flags.
+#define NV_NCH 0x01 // may need to get a second char
+#define NV_NCH_NOP (0x02|NV_NCH) // get second char when no operator pending
+#define NV_NCH_ALW (0x04|NV_NCH) // always get a second char
+#define NV_LANG 0x08 // second char needs language adjustment
-#define NV_SS 0x10 /* may start selection */
-#define NV_SSS 0x20 /* may start selection with shift modifier */
-#define NV_STS 0x40 /* may stop selection without shift modif. */
-#define NV_RL 0x80 /* 'rightleft' modifies command */
-#define NV_KEEPREG 0x100 /* don't clear regname */
-#define NV_NCW 0x200 /* not allowed in command-line window */
+#define NV_SS 0x10 // may start selection
+#define NV_SSS 0x20 // may start selection with shift modifier
+#define NV_STS 0x40 // may stop selection without shift modif.
+#define NV_RL 0x80 // 'rightleft' modifies command
+#define NV_KEEPREG 0x100 // don't clear regname
+#define NV_NCW 0x200 // not allowed in command-line window
/*
* Generally speaking, every Normal mode command should either clear any
@@ -149,10 +147,10 @@ typedef void (*nv_func_T)(cmdarg_T *cap);
* It is faster when all keys from zero to '~' are present.
*/
static const struct nv_cmd {
- int cmd_char; /* (first) command character */
- nv_func_T cmd_func; /* function for this command */
- uint16_t cmd_flags; /* NV_ flags */
- short cmd_arg; /* value for ca.arg */
+ int cmd_char; // (first) command character
+ nv_func_T cmd_func; // function for this command
+ uint16_t cmd_flags; // NV_ flags
+ short cmd_arg; // value for ca.arg
} nv_cmds[] =
{
{ NUL, nv_error, 0, 0 },
@@ -345,10 +343,10 @@ static const struct nv_cmd {
{ K_COMMAND, nv_colon, 0, 0 },
};
-/* Number of commands in nv_cmds[]. */
+// Number of commands in nv_cmds[].
#define NV_CMDS_SIZE ARRAY_SIZE(nv_cmds)
-/* Sorted index of commands in nv_cmds[]. */
+// Sorted index of commands in nv_cmds[].
static short nv_cmd_idx[NV_CMDS_SIZE];
/* The highest index for which
@@ -363,13 +361,15 @@ static int nv_compare(const void *s1, const void *s2)
{
int c1, c2;
- /* The commands are sorted on absolute value. */
+ // The commands are sorted on absolute value.
c1 = nv_cmds[*(const short *)s1].cmd_char;
c2 = nv_cmds[*(const short *)s2].cmd_char;
- if (c1 < 0)
+ if (c1 < 0) {
c1 = -c1;
- if (c2 < 0)
+ }
+ if (c2 < 0) {
c2 = -c2;
+ }
return c1 - c2;
}
@@ -380,15 +380,15 @@ void init_normal_cmds(void)
{
assert(NV_CMDS_SIZE <= SHRT_MAX);
- /* Fill the index table with a one to one relation. */
+ // Fill the index table with a one to one relation.
for (short int i = 0; i < (short int)NV_CMDS_SIZE; ++i) {
nv_cmd_idx[i] = i;
}
- /* Sort the commands by the command character. */
+ // Sort the commands by the command character.
qsort(&nv_cmd_idx, NV_CMDS_SIZE, sizeof(short), nv_compare);
- /* Find the first entry that can't be indexed by the command character. */
+ // Find the first entry that can't be indexed by the command character.
short int i;
for (i = 0; i < (short int)NV_CMDS_SIZE; ++i) {
if (i != nv_cmds[nv_cmd_idx[i]].cmd_char) {
@@ -409,38 +409,43 @@ static int find_command(int cmdchar)
int top, bot;
int c;
- /* A multi-byte character is never a command. */
- if (cmdchar >= 0x100)
+ // A multi-byte character is never a command.
+ if (cmdchar >= 0x100) {
return -1;
+ }
/* We use the absolute value of the character. Special keys have a
* negative value, but are sorted on their absolute value. */
- if (cmdchar < 0)
+ if (cmdchar < 0) {
cmdchar = -cmdchar;
+ }
/* If the character is in the first part: The character is the index into
* nv_cmd_idx[]. */
assert(nv_max_linear < (int)NV_CMDS_SIZE);
- if (cmdchar <= nv_max_linear)
+ if (cmdchar <= nv_max_linear) {
return nv_cmd_idx[cmdchar];
+ }
- /* Perform a binary search. */
+ // Perform a binary search.
bot = nv_max_linear + 1;
top = NV_CMDS_SIZE - 1;
idx = -1;
while (bot <= top) {
i = (top + bot) / 2;
c = nv_cmds[nv_cmd_idx[i]].cmd_char;
- if (c < 0)
+ if (c < 0) {
c = -c;
+ }
if (cmdchar == c) {
idx = nv_cmd_idx[i];
break;
}
- if (cmdchar > c)
+ if (cmdchar > c) {
bot = i + 1;
- else
+ } else {
top = i - 1;
+ }
}
return idx;
}
@@ -545,59 +550,60 @@ static bool normal_need_additional_char(NormalState *s)
int cmdchar = s->ca.cmdchar;
// without NV_NCH we never need to check for an additional char
return flags & NV_NCH && (
- // NV_NCH_NOP is set and no operator is pending, get a second char
- ((flags & NV_NCH_NOP) == NV_NCH_NOP && !pending_op)
- // NV_NCH_ALW is set, always get a second char
- || (flags & NV_NCH_ALW) == NV_NCH_ALW
- // 'q' without a pending operator, recording or executing a register,
- // needs to be followed by a second char, examples:
- // - qc => record using register c
- // - q: => open command-line window
- || (cmdchar == 'q'
- && !pending_op
- && reg_recording == 0
- && reg_executing == 0)
- // 'a' or 'i' after an operator is a text object, examples:
- // - ciw => change inside word
- // - da( => delete parenthesis and everything inside.
- // Also, don't do anything when these keys are received in visual mode
- // so just get another char.
- //
- // TODO(tarruda): Visual state needs to be refactored into a
- // separate state that "inherits" from normal state.
- || ((cmdchar == 'a' || cmdchar == 'i') && (pending_op || VIsual_active)));
+ // NV_NCH_NOP is set and no operator is pending, get a second char
+ ((flags & NV_NCH_NOP) == NV_NCH_NOP && !pending_op)
+ // NV_NCH_ALW is set, always get a second char
+ || (flags & NV_NCH_ALW) == NV_NCH_ALW
+ // 'q' without a pending operator, recording or executing a register,
+ // needs to be followed by a second char, examples:
+ // - qc => record using register c
+ // - q: => open command-line window
+ || (cmdchar == 'q'
+ && !pending_op
+ && reg_recording == 0
+ && reg_executing == 0)
+ // 'a' or 'i' after an operator is a text object, examples:
+ // - ciw => change inside word
+ // - da( => delete parenthesis and everything inside.
+ // Also, don't do anything when these keys are received in visual mode
+ // so just get another char.
+ //
+ // TODO(tarruda): Visual state needs to be refactored into a
+ // separate state that "inherits" from normal state.
+ || ((cmdchar == 'a' || cmdchar == 'i') &&
+ (pending_op || VIsual_active)));
}
static bool normal_need_redraw_mode_message(NormalState *s)
{
return (
- // 'showmode' is set and messages can be printed
- ((p_smd && msg_silent == 0
- // must restart insert mode(ctrl+o or ctrl+l) or we just entered visual
- // mode
- && (restart_edit != 0 || (VIsual_active
- && s->old_pos.lnum == curwin->w_cursor.lnum
- && s->old_pos.col == curwin->w_cursor.col))
- // command-line must be cleared or redrawn
- && (clear_cmdline || redraw_cmdline)
- // some message was printed or scrolled
- && (msg_didout || (msg_didany && msg_scroll))
- // it is fine to remove the current message
- && !msg_nowait
- // the command was the result of direct user input and not a mapping
- && KeyTyped)
- // must restart insert mode, not in visual mode and error message is
- // being shown
- || (restart_edit != 0 && !VIsual_active && msg_scroll
- && emsg_on_display))
- // no register was used
- && s->oa.regname == 0
- && !(s->ca.retval & CA_COMMAND_BUSY)
- && stuff_empty()
- && typebuf_typed()
- && emsg_silent == 0
- && !did_wait_return
- && s->oa.op_type == OP_NOP);
+ // 'showmode' is set and messages can be printed
+ ((p_smd && msg_silent == 0
+ // must restart insert mode(ctrl+o or ctrl+l) or we just entered visual
+ // mode
+ && (restart_edit != 0 || (VIsual_active
+ && s->old_pos.lnum == curwin->w_cursor.lnum
+ && s->old_pos.col == curwin->w_cursor.col))
+ // command-line must be cleared or redrawn
+ && (clear_cmdline || redraw_cmdline)
+ // some message was printed or scrolled
+ && (msg_didout || (msg_didany && msg_scroll))
+ // it is fine to remove the current message
+ && !msg_nowait
+ // the command was the result of direct user input and not a mapping
+ && KeyTyped)
+ // must restart insert mode, not in visual mode and error message is
+ // being shown
+ || (restart_edit != 0 && !VIsual_active && msg_scroll
+ && emsg_on_display))
+ // no register was used
+ && s->oa.regname == 0
+ && !(s->ca.retval & CA_COMMAND_BUSY)
+ && stuff_empty()
+ && typebuf_typed()
+ && emsg_silent == 0
+ && !did_wait_return
+ && s->oa.op_type == OP_NOP);
}
static void normal_redraw_mode_message(NormalState *s)
@@ -612,7 +618,7 @@ static void normal_redraw_mode_message(NormalState *s)
// If need to redraw, and there is a "keep_msg", redraw before the
// delay
if (must_redraw && keep_msg != NULL && !emsg_on_display) {
- char_u *kmsg;
+ char_u *kmsg;
kmsg = keep_msg;
keep_msg = NULL;
@@ -708,7 +714,7 @@ static void normal_get_additional_char(NormalState *s)
if (!lit) {
// Typing CTRL-K gets a digraph.
if (*cp == Ctrl_K && ((nv_cmds[s->idx].cmd_flags & NV_LANG)
- || cp == &s->ca.extra_char)
+ || cp == &s->ca.extra_char)
&& vim_strchr(p_cpo, CPO_DIGRAPH) == NULL) {
s->c = get_digraph(false);
if (s->c > 0) {
@@ -736,7 +742,7 @@ static void normal_get_additional_char(NormalState *s)
s->ca.nchar = s->ca.extra_char;
s->idx = find_command(s->ca.cmdchar);
} else if ((s->ca.nchar == 'n' || s->ca.nchar == 'N')
- && s->ca.cmdchar == 'g') {
+ && s->ca.cmdchar == 'g') {
s->ca.oap->op_type = get_op_type(*cp, NUL);
} else if (*cp == Ctrl_BSL) {
long towait = (p_ttm >= 0 ? p_ttm : p_tm);
@@ -770,7 +776,7 @@ static void normal_get_additional_char(NormalState *s)
&& (s->c >= 0x100 || MB_BYTE2LEN(vpeekc()) > 1)) {
s->c = plain_vgetc();
if (!utf_iscomposing(s->c)) {
- vungetc(s->c); /* it wasn't, put it back */
+ vungetc(s->c); // it wasn't, put it back
break;
} else if (s->ca.ncharC1 == 0) {
s->ca.ncharC1 = s->c;
@@ -786,16 +792,26 @@ static void normal_get_additional_char(NormalState *s)
static void normal_invert_horizontal(NormalState *s)
{
switch (s->ca.cmdchar) {
- case 'l': s->ca.cmdchar = 'h'; break;
- case K_RIGHT: s->ca.cmdchar = K_LEFT; break;
- case K_S_RIGHT: s->ca.cmdchar = K_S_LEFT; break;
- case K_C_RIGHT: s->ca.cmdchar = K_C_LEFT; break;
- case 'h': s->ca.cmdchar = 'l'; break;
- case K_LEFT: s->ca.cmdchar = K_RIGHT; break;
- case K_S_LEFT: s->ca.cmdchar = K_S_RIGHT; break;
- case K_C_LEFT: s->ca.cmdchar = K_C_RIGHT; break;
- case '>': s->ca.cmdchar = '<'; break;
- case '<': s->ca.cmdchar = '>'; break;
+ case 'l':
+ s->ca.cmdchar = 'h'; break;
+ case K_RIGHT:
+ s->ca.cmdchar = K_LEFT; break;
+ case K_S_RIGHT:
+ s->ca.cmdchar = K_S_LEFT; break;
+ case K_C_RIGHT:
+ s->ca.cmdchar = K_C_LEFT; break;
+ case 'h':
+ s->ca.cmdchar = 'l'; break;
+ case K_LEFT:
+ s->ca.cmdchar = K_RIGHT; break;
+ case K_S_LEFT:
+ s->ca.cmdchar = K_S_RIGHT; break;
+ case K_C_LEFT:
+ s->ca.cmdchar = K_C_RIGHT; break;
+ case '>':
+ s->ca.cmdchar = '<'; break;
+ case '<':
+ s->ca.cmdchar = '>'; break;
}
s->idx = find_command(s->ca.cmdchar);
}
@@ -809,7 +825,7 @@ static bool normal_get_command_count(NormalState *s)
// Note that '0' is a command and not the start of a count, but it's
// part of a count after other digits.
while ((s->c >= '1' && s->c <= '9') || (s->ca.count0 != 0
- && (s->c == K_DEL || s->c == K_KDEL || s->c == '0'))) {
+ && (s->c == K_DEL || s->c == K_KDEL || s->c == '0'))) {
if (s->c == K_DEL || s->c == K_KDEL) {
s->ca.count0 /= 10;
del_from_showcmd(4); // delete the digit and ~@%
@@ -942,11 +958,11 @@ normal_end:
// if still inside a mapping that started in Visual mode).
// May switch from Visual to Select mode after CTRL-O command.
if (s->oa.op_type == OP_NOP
- && ((restart_edit != 0 && !VIsual_active && s->old_mapped_len == 0)
- || restart_VIsual_select == 1)
- && !(s->ca.retval & CA_COMMAND_BUSY)
- && stuff_empty()
- && s->oa.regname == 0) {
+ && ((restart_edit != 0 && !VIsual_active && s->old_mapped_len == 0)
+ || restart_VIsual_select == 1)
+ && !(s->ca.retval & CA_COMMAND_BUSY)
+ && stuff_empty()
+ && s->oa.regname == 0) {
if (restart_VIsual_select == 1) {
VIsual_select = true;
showmode();
@@ -969,7 +985,7 @@ static int normal_execute(VimState *state, int key)
{
NormalState *s = (NormalState *)state;
s->command_finished = false;
- s->ctrl_w = false; /* got CTRL-W command */
+ s->ctrl_w = false; // got CTRL-W command
s->old_col = curwin->w_curswant;
s->c = key;
@@ -981,7 +997,7 @@ static int normal_execute(VimState *state, int key)
if (restart_edit == 0) {
s->old_mapped_len = 0;
} else if (s->old_mapped_len || (VIsual_active && s->mapped_len == 0
- && typebuf_maplen() > 0)) {
+ && typebuf_maplen() > 0)) {
s->old_mapped_len = typebuf_maplen();
}
@@ -991,7 +1007,7 @@ static int normal_execute(VimState *state, int key)
// In Select mode, typed text replaces the selection.
if (VIsual_active && VIsual_select && (vim_isprintc(s->c)
- || s->c == NL || s->c == CAR || s->c == K_KENTER)) {
+ || s->c == NL || s->c == CAR || s->c == K_KENTER)) {
// Fake a "c"hange command. When "restart_edit" is set (e.g., because
// 'insertmode' is set) fake a "d"elete command, Insert mode will
// restart automatically.
@@ -1009,14 +1025,14 @@ static int normal_execute(VimState *state, int key)
s->need_flushbuf = add_to_showcmd(s->c);
- while (normal_get_command_count(s)) continue;
+ while (normal_get_command_count(s)) { continue; }
if (s->c == K_EVENT) {
// Save the count values so that ca.opcount and ca.count0 are exactly
// the same when coming back here after handling K_EVENT.
s->oa.prev_opcount = s->ca.opcount;
s->oa.prev_count0 = s->ca.count0;
- } else if (s->ca.opcount != 0) {
+ } else if (s->ca.opcount != 0) {
// If we're in the middle of an operator (including after entering a
// yank buffer with '"') AND we had a count before the operator, then
// that count overrides the current value of ca.count0.
@@ -1188,7 +1204,7 @@ static void normal_check_interrupt(NormalState *s)
&& s->previous_got_int) {
// Typed two CTRL-C in a row: go back to ex mode as if "Q" was
// used and keep "got_int" set, so that it aborts ":g".
- exmode_active = EXMODE_NORMAL;
+ exmode_active = true;
State = NORMAL;
} else if (!global_busy || !exmode_active) {
if (!quit_more) {
@@ -1277,6 +1293,15 @@ static void normal_redraw(NormalState *s)
redrawWinline(curwin, curwin->w_cursor.lnum);
}
+ // Might need to update for 'cursorline'.
+ // When 'cursorlineopt' is "screenline" need to redraw always.
+ if (curwin->w_p_cul
+ && (curwin->w_last_cursorline != curwin->w_cursor.lnum
+ || (curwin->w_p_culopt_flags & CULOPT_SCRLINE))
+ && !char_avail()) {
+ redraw_later(curwin, VALID);
+ }
+
if (VIsual_active) {
update_curbuf(INVERTED); // update inverted part
} else if (must_redraw) {
@@ -1340,7 +1365,7 @@ static int normal_check(VimState *state)
quit_more = false;
// If skip redraw is set (for ":" in wait_return()), don't redraw now.
- // If there is nothing in the stuff_buffer or do_redraw is TRUE,
+ // If there is nothing in the stuff_buffer or do_redraw is true,
// update cursor and redraw.
if (skip_redraw || exmode_active) {
skip_redraw = false;
@@ -1398,7 +1423,7 @@ static int normal_check(VimState *state)
if (s->noexmode) {
return 0;
}
- do_exmode(exmode_active == EXMODE_VIM);
+ do_exmode();
return -1;
}
@@ -1419,18 +1444,19 @@ static void set_vcount_ca(cmdarg_T *cap, bool *set_prevcount)
{
long count = cap->count0;
- /* multiply with cap->opcount the same way as above */
- if (cap->opcount != 0)
+ // multiply with cap->opcount the same way as above
+ if (cap->opcount != 0) {
count = cap->opcount * (count == 0 ? 1 : count);
+ }
set_vcount(count, count == 0 ? 1 : count, *set_prevcount);
- *set_prevcount = false; /* only set v:prevcount once */
+ *set_prevcount = false; // only set v:prevcount once
}
// Handle an operator after Visual mode or when the movement is finished.
// "gui_yank" is true when yanking text for the clipboard.
void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
{
- oparg_T *oap = cap->oap;
+ oparg_T *oap = cap->oap;
pos_T old_cursor;
bool empty_region_error;
int restart_edit_save;
@@ -1500,12 +1526,11 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
&& oap->op_type != OP_FOLDCLOSE
&& oap->op_type != OP_FOLDCLOSEREC
&& oap->op_type != OP_FOLDDEL
- && oap->op_type != OP_FOLDDELREC
- ) {
+ && oap->op_type != OP_FOLDDELREC) {
prep_redo(oap->regname, cap->count0,
- get_op_char(oap->op_type), get_extra_op_char(oap->op_type),
- oap->motion_force, cap->cmdchar, cap->nchar);
- if (cap->cmdchar == '/' || cap->cmdchar == '?') { /* was a search */
+ get_op_char(oap->op_type), get_extra_op_char(oap->op_type),
+ oap->motion_force, cap->cmdchar, cap->nchar);
+ if (cap->cmdchar == '/' || cap->cmdchar == '?') { // was a search
/*
* If 'cpoptions' does not contain 'r', insert the search
* pattern to really repeat the same command.
@@ -1533,8 +1558,9 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
* redo_VIsual_line_count and redo_VIsual_vcol. */
oap->start = curwin->w_cursor;
curwin->w_cursor.lnum += redo_VIsual_line_count - 1;
- if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
+ if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) {
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+ }
VIsual_mode = redo_VIsual_mode;
if (redo_VIsual_vcol == MAXCOL || VIsual_mode == 'v') {
if (VIsual_mode == 'v') {
@@ -1542,8 +1568,9 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
validate_virtcol();
curwin->w_curswant =
curwin->w_virtcol + redo_VIsual_vcol - 1;
- } else
+ } else {
curwin->w_curswant = redo_VIsual_vcol;
+ }
} else {
curwin->w_curswant = MAXCOL;
}
@@ -1553,7 +1580,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
cap->count1 = (cap->count0 == 0 ? 1 : cap->count0);
} else if (VIsual_active) {
if (!gui_yank) {
- /* Save the current VIsual area for '< and '> marks, and "gv" */
+ // Save the current VIsual area for '< and '> marks, and "gv"
curbuf->b_visual.vi_start = VIsual;
curbuf->b_visual.vi_end = curwin->w_cursor;
curbuf->b_visual.vi_mode = VIsual_mode;
@@ -1599,10 +1626,11 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
* to the end of the operated text. w_cursor is equal to oap->start.
*/
if (lt(oap->start, curwin->w_cursor)) {
- /* Include folded lines completely. */
+ // Include folded lines completely.
if (!VIsual_active) {
- if (hasFolding(oap->start.lnum, &oap->start.lnum, NULL))
+ if (hasFolding(oap->start.lnum, &oap->start.lnum, NULL)) {
oap->start.col = 0;
+ }
if ((curwin->w_cursor.col > 0
|| oap->inclusive
|| oap->motion_type == kMTLineWise)
@@ -1637,7 +1665,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
check_pos(curwin->w_buffer, &oap->end);
oap->line_count = oap->end.lnum - oap->start.lnum + 1;
- /* Set "virtual_op" before resetting VIsual_active. */
+ // Set "virtual_op" before resetting VIsual_active.
virtual_op = virtual_active();
if (VIsual_active || redo_VIsual_busy) {
@@ -1649,19 +1677,22 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
* size of the Visual text
*/
resel_VIsual_mode = VIsual_mode;
- if (curwin->w_curswant == MAXCOL)
+ if (curwin->w_curswant == MAXCOL) {
resel_VIsual_vcol = MAXCOL;
- else {
- if (VIsual_mode != Ctrl_V)
+ } else {
+ if (VIsual_mode != Ctrl_V) {
getvvcol(curwin, &(oap->end),
- NULL, NULL, &oap->end_vcol);
+ NULL, NULL, &oap->end_vcol);
+ }
if (VIsual_mode == Ctrl_V || oap->line_count <= 1) {
- if (VIsual_mode != Ctrl_V)
+ if (VIsual_mode != Ctrl_V) {
getvvcol(curwin, &(oap->start),
- &oap->start_vcol, NULL, NULL);
+ &oap->start_vcol, NULL, NULL);
+ }
resel_VIsual_vcol = oap->end_vcol - oap->start_vcol + 1;
- } else
+ } else {
resel_VIsual_vcol = oap->end_vcol;
+ }
}
resel_VIsual_line_count = oap->line_count;
}
@@ -1676,8 +1707,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
&& oap->op_type != OP_FOLDCLOSEREC
&& oap->op_type != OP_FOLDDEL
&& oap->op_type != OP_FOLDDELREC
- && oap->motion_force == NUL
- ) {
+ && oap->motion_force == NUL) {
/* Prepare for redoing. Only use the nchar field for "r",
* otherwise it might be the second char of the operator. */
if (cap->cmdchar == 'g' && (cap->nchar == 'n'
@@ -1717,8 +1747,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
} else if (VIsual_mode == 'v') {
oap->motion_type = kMTCharWise;
if (*ml_get_pos(&(oap->end)) == NUL
- && (include_line_break || !virtual_op)
- ) {
+ && (include_line_break || !virtual_op)) {
oap->inclusive = false;
// Try to include the newline, unless it's an operator
// that works on lines only.
@@ -1820,22 +1849,24 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
oap->inclusive = true;
}
}
- } else
+ } else {
oap->end_adjusted = false;
+ }
switch (oap->op_type) {
case OP_LSHIFT:
case OP_RSHIFT:
op_shift(oap, true,
- oap->is_VIsual ? (int)cap->count1 :
- 1);
+ oap->is_VIsual ? (int)cap->count1 :
+ 1);
auto_format(false, true);
break;
case OP_JOIN_NS:
case OP_JOIN:
- if (oap->line_count < 2)
+ if (oap->line_count < 2) {
oap->line_count = 2;
+ }
if (curwin->w_cursor.lnum + oap->line_count - 1 >
curbuf->b_ml.ml_line_count) {
beep_flush();
@@ -1847,7 +1878,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
break;
case OP_DELETE:
- VIsual_reselect = false; /* don't reselect now */
+ VIsual_reselect = false; // don't reselect now
if (empty_region_error) {
vim_beep(BO_OPER);
CancelRedo();
@@ -1877,7 +1908,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
break;
case OP_CHANGE:
- VIsual_reselect = false; /* don't reselect now */
+ VIsual_reselect = false; // don't reselect now
if (empty_region_error) {
vim_beep(BO_OPER);
CancelRedo();
@@ -1886,10 +1917,11 @@ 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 (p_im || !KeyTyped) {
restart_edit_save = restart_edit;
- else
+ } else {
restart_edit_save = 0;
+ }
restart_edit = 0;
// Restore linebreak, so that when the user edits it looks as before.
@@ -1897,10 +1929,12 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
// Reset finish_op now, don't want it set inside edit().
finish_op = false;
- if (op_change(oap)) /* will call edit() */
+ if (op_change(oap)) { // will call edit()
cap->retval |= CA_COMMAND_BUSY;
- if (restart_edit == 0)
+ }
+ if (restart_edit == 0) {
restart_edit = restart_edit_save;
+ }
}
break;
@@ -1924,8 +1958,8 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
break;
}
op_reindent(oap,
- *curbuf->b_p_inde != NUL ? get_expr_indent :
- get_c_indent);
+ *curbuf->b_p_inde != NUL ? get_expr_indent :
+ get_c_indent);
break;
}
@@ -1939,8 +1973,9 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
if (empty_region_error) {
vim_beep(BO_OPER);
CancelRedo();
- } else
+ } else {
op_tilde(oap);
+ }
check_cursor_col();
break;
@@ -1957,7 +1992,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
break;
case OP_FORMAT2:
- op_format(oap, true); /* use internal function */
+ op_format(oap, true); // use internal function
break;
case OP_FUNCTION:
@@ -1969,7 +2004,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
case OP_INSERT:
case OP_APPEND:
- VIsual_reselect = false; /* don't reselect now */
+ VIsual_reselect = false; // don't reselect now
if (empty_region_error) {
vim_beep(BO_OPER);
CancelRedo();
@@ -2001,7 +2036,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
break;
case OP_REPLACE:
- VIsual_reselect = false; /* don't reselect now */
+ VIsual_reselect = false; // don't reselect now
if (empty_region_error) {
vim_beep(BO_OPER);
CancelRedo();
@@ -2133,10 +2168,10 @@ static void op_function(const oparg_T *oap)
{
const TriState save_virtual_op = virtual_op;
- if (*p_opfunc == NUL)
+ if (*p_opfunc == NUL) {
EMSG(_("E774: 'operatorfunc' is empty"));
- else {
- /* Set '[ and '] marks to text to be operated on. */
+ } else {
+ // Set '[ and '] marks to text to be operated on.
curbuf->b_op_start = oap->start;
curbuf->b_op_end = oap->end;
if (oap->motion_type != kMTLineWise && !oap->inclusive) {
@@ -2149,10 +2184,10 @@ static void op_function(const oparg_T *oap)
argv[1].v_type = VAR_UNKNOWN;
argv[0].vval.v_string =
(char_u *)(((const char *const[]) {
- [kMTBlockWise] = "block",
- [kMTLineWise] = "line",
- [kMTCharWise] = "char",
- })[oap->motion_type]);
+ [kMTBlockWise] = "block",
+ [kMTLineWise] = "line",
+ [kMTCharWise] = "char",
+ })[oap->motion_type]);
// Reset virtual_op so that 'virtualedit' can be changed in the
// function.
@@ -2170,73 +2205,69 @@ static void move_tab_to_mouse(void)
{
int tabnr = tab_page_click_defs[mouse_col].tabnr;
if (tabnr <= 0) {
- tabpage_move(9999);
+ tabpage_move(9999);
} else if (tabnr < tabpage_index(curtab)) {
- tabpage_move(tabnr - 1);
+ tabpage_move(tabnr - 1);
} else {
- tabpage_move(tabnr);
- }
-}
-
-/*
- * Do the appropriate action for the current mouse click in the current mode.
- * Not used for Command-line mode.
- *
- * Normal Mode:
- * event modi- position visual change action
- * fier cursor window
- * left press - yes end yes
- * left press C yes end yes "^]" (2)
- * left press S yes end yes "*" (2)
- * left drag - yes start if moved no
- * left relse - yes start if moved no
- * middle press - yes if not active no put register
- * middle press - yes if active no yank and put
- * right press - yes start or extend yes
- * right press S yes no change yes "#" (2)
- * right drag - yes extend no
- * right relse - yes extend no
- *
- * Insert or Replace Mode:
- * event modi- position visual change action
- * fier cursor window
- * left press - yes (cannot be active) yes
- * left press C yes (cannot be active) yes "CTRL-O^]" (2)
- * left press S yes (cannot be active) yes "CTRL-O*" (2)
- * left drag - yes start or extend (1) no CTRL-O (1)
- * left relse - yes start or extend (1) no CTRL-O (1)
- * middle press - no (cannot be active) no put register
- * right press - yes start or extend yes CTRL-O
- * right press S yes (cannot be active) yes "CTRL-O#" (2)
- *
- * (1) only if mouse pointer moved since press
- * (2) only if click is in same buffer
- *
- * Return true if start_arrow() should be called for edit mode.
- */
-bool
-do_mouse (
- oparg_T *oap, /* operator argument, can be NULL */
- int c, /* K_LEFTMOUSE, etc */
- int dir, /* Direction to 'put' if necessary */
- long count,
- bool fixindent /* PUT_FIXINDENT if fixing indent necessary */
-)
-{
- static bool got_click = false; /* got a click some time back */
-
- int which_button; /* MOUSE_LEFT, _MIDDLE or _RIGHT */
- bool is_click; /* If false it's a drag or release event */
- bool is_drag; /* If true it's a drag event */
- int jump_flags = 0; /* flags for jump_to_mouse() */
+ tabpage_move(tabnr);
+ }
+}
+
+/// Do the appropriate action for the current mouse click in the current mode.
+/// Not used for Command-line mode.
+///
+/// Normal Mode:
+/// event modi- position visual change action
+/// fier cursor window
+/// left press - yes end yes
+/// left press C yes end yes "^]" (2)
+/// left press S yes end yes "*" (2)
+/// left drag - yes start if moved no
+/// left relse - yes start if moved no
+/// middle press - yes if not active no put register
+/// middle press - yes if active no yank and put
+/// right press - yes start or extend yes
+/// right press S yes no change yes "#" (2)
+/// right drag - yes extend no
+/// right relse - yes extend no
+///
+/// Insert or Replace Mode:
+/// event modi- position visual change action
+/// fier cursor window
+/// left press - yes (cannot be active) yes
+/// left press C yes (cannot be active) yes "CTRL-O^]" (2)
+/// left press S yes (cannot be active) yes "CTRL-O*" (2)
+/// left drag - yes start or extend (1) no CTRL-O (1)
+/// left relse - yes start or extend (1) no CTRL-O (1)
+/// middle press - no (cannot be active) no put register
+/// right press - yes start or extend yes CTRL-O
+/// right press S yes (cannot be active) yes "CTRL-O#" (2)
+///
+/// (1) only if mouse pointer moved since press
+/// (2) only if click is in same buffer
+///
+/// @param oap operator argument, can be NULL
+/// @param c K_LEFTMOUSE, etc
+/// @param dir Direction to 'put' if necessary
+/// @param fixindent PUT_FIXINDENT if fixing indent necessary
+///
+/// @return true if start_arrow() should be called for edit mode.
+bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent)
+{
+ static bool got_click = false; // got a click some time back
+
+ int which_button; // MOUSE_LEFT, _MIDDLE or _RIGHT
+ bool is_click; // If false it's a drag or release event
+ bool is_drag; // If true it's a drag event
+ int jump_flags = 0; // flags for jump_to_mouse()
pos_T start_visual;
- bool moved; /* Has cursor moved? */
- 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 */
+ bool moved; // Has cursor moved?
+ 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
int c1, c2;
pos_T save_cursor;
- win_T *old_curwin = curwin;
+ win_T *old_curwin = curwin;
static pos_T orig_cursor;
colnr_T leftcol, rightcol;
pos_T end_visual;
@@ -2261,8 +2292,9 @@ do_mouse (
/* Need to get the character, peeking doesn't get the actual
* one. */
nc = safe_vgetc();
- if (c == nc)
+ if (c == nc) {
continue;
+ }
vungetc(nc);
mouse_grid = save_mouse_grid;
mouse_row = save_mouse_row;
@@ -2280,12 +2312,13 @@ do_mouse (
/*
* Ignore drag and release events if we didn't get a click.
*/
- if (is_click)
+ if (is_click) {
got_click = true;
- else {
- if (!got_click) /* didn't get click, ignore */
+ } else {
+ if (!got_click) { // didn't get click, ignore
return false;
- if (!is_drag) { /* release, reset got_click */
+ }
+ if (!is_drag) { // release, reset got_click
got_click = false;
if (in_tab_line) {
in_tab_line = false;
@@ -2299,20 +2332,23 @@ do_mouse (
* CTRL right mouse button does CTRL-T
*/
if (is_click && (mod_mask & MOD_MASK_CTRL) && which_button == MOUSE_RIGHT) {
- if (State & INSERT)
+ if (State & INSERT) {
stuffcharReadbuff(Ctrl_O);
- if (count > 1)
+ }
+ if (count > 1) {
stuffnumReadbuff(count);
+ }
stuffcharReadbuff(Ctrl_T);
- got_click = false; /* ignore drag&release now */
+ got_click = false; // ignore drag&release now
return false;
}
/*
* CTRL only works with left mouse button
*/
- if ((mod_mask & MOD_MASK_CTRL) && which_button != MOUSE_LEFT)
+ if ((mod_mask & MOD_MASK_CTRL) && which_button != MOUSE_LEFT) {
return false;
+ }
/*
* When a modifier is down, ignore drag and release events, as well as
@@ -2329,22 +2365,24 @@ do_mouse (
&& which_button == MOUSE_LEFT)
&& !((mod_mask & MOD_MASK_ALT)
&& !mouse_model_popup()
- && which_button == MOUSE_RIGHT)
- )
+ && which_button == MOUSE_RIGHT)) {
return false;
+ }
/*
* If the button press was used as the movement command for an operator
* (eg "d<MOUSE>"), or it is the middle button that is held down, ignore
* drag/release events.
*/
- if (!is_click && which_button == MOUSE_MIDDLE)
+ if (!is_click && which_button == MOUSE_MIDDLE) {
return false;
+ }
- if (oap != NULL)
+ if (oap != NULL) {
regname = oap->regname;
- else
+ } else {
regname = 0;
+ }
/*
* Middle mouse button does a 'put' of the selected text
@@ -2378,8 +2416,9 @@ do_mouse (
/*
* The rest is below jump_to_mouse()
*/
- } else if ((State & INSERT) == 0)
+ } else if ((State & INSERT) == 0) {
return false;
+ }
/*
* Middle click in insert mode doesn't move the mouse, just insert the
@@ -2401,7 +2440,7 @@ do_mouse (
do_put(regname, NULL, BACKWARD, 1L,
(fixindent ? PUT_FIXINDENT : 0) | PUT_CURSEND);
- /* Repeat it with CTRL-R CTRL-O r or CTRL-R CTRL-P r */
+ // Repeat it with CTRL-R CTRL-O r or CTRL-R CTRL-P r
AppendCharToRedobuff(Ctrl_R);
AppendCharToRedobuff(fixindent ? Ctrl_P : Ctrl_O);
AppendCharToRedobuff(regname == 0 ? '"' : regname);
@@ -2411,9 +2450,10 @@ do_mouse (
}
}
- /* When dragging or button-up stay in the same window. */
- if (!is_click)
+ // When dragging or button-up stay in the same window.
+ if (!is_click) {
jump_flags |= MOUSE_FOCUS | MOUSE_DID_MOVE;
+ }
start_visual.lnum = 0;
@@ -2426,67 +2466,65 @@ do_mouse (
return false;
}
- /* click in a tab selects that tab page */
+ // click in a tab selects that tab page
if (is_click
&& cmdwin_type == 0
&& mouse_col < Columns) {
in_tab_line = true;
c1 = tab_page_click_defs[mouse_col].tabnr;
switch (tab_page_click_defs[mouse_col].type) {
- case kStlClickDisabled: {
- break;
- }
- case kStlClickTabClose: {
- tabpage_T *tp;
+ case kStlClickDisabled:
+ break;
+ case kStlClickTabClose: {
+ tabpage_T *tp;
- // Close the current or specified tab page.
- if (c1 == 999) {
- tp = curtab;
- } else {
- tp = find_tabpage(c1);
- }
- if (tp == curtab) {
- if (first_tabpage->tp_next != NULL) {
- tabpage_close(false);
- }
- } else if (tp != NULL) {
- tabpage_close_other(tp, false);
+ // Close the current or specified tab page.
+ if (c1 == 999) {
+ tp = curtab;
+ } else {
+ tp = find_tabpage(c1);
+ }
+ if (tp == curtab) {
+ if (first_tabpage->tp_next != NULL) {
+ tabpage_close(false);
}
- break;
+ } else if (tp != NULL) {
+ tabpage_close_other(tp, false);
}
- case kStlClickTabSwitch: {
- if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK) {
- // double click opens new page
- end_visual_mode();
- tabpage_new();
- tabpage_move(c1 == 0 ? 9999 : c1 - 1);
- } else {
- // Go to specified tab page, or next one if not clicking
- // on a label.
- goto_tabpage(c1);
+ break;
+ }
+ case kStlClickTabSwitch:
+ if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK) {
+ // double click opens new page
+ end_visual_mode();
+ tabpage_new();
+ tabpage_move(c1 == 0 ? 9999 : c1 - 1);
+ } else {
+ // Go to specified tab page, or next one if not clicking
+ // on a label.
+ goto_tabpage(c1);
- // It's like clicking on the status line of a window.
- if (curwin != old_curwin) {
- end_visual_mode();
- }
+ // It's like clicking on the status line of a window.
+ if (curwin != old_curwin) {
+ end_visual_mode();
}
- 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
- },
+ 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)
+ },
+ {
+ .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)
@@ -2495,43 +2533,43 @@ do_mouse (
== MOD_MASK_2CLICK)
? 2
: 1)
- },
},
- {
- .v_lock = VAR_FIXED,
- .v_type = VAR_STRING,
- .vval = { .v_string = (char_u *) (which_button == MOUSE_LEFT
+ },
+ {
+ .v_lock = VAR_FIXED,
+ .v_type = VAR_STRING,
+ .vval = { .v_string = (char_u *)(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_u[]) {
+ (char_u)(mod_mask & MOD_MASK_SHIFT ? 's' : ' '),
+ (char_u)(mod_mask & MOD_MASK_CTRL ? 'c' : ' '),
+ (char_u)(mod_mask & MOD_MASK_ALT ? 'a' : ' '),
+ (char_u)(mod_mask & MOD_MASK_META ? 'm' : ' '),
+ NUL
+ }
},
- {
- .v_lock = VAR_FIXED,
- .v_type = VAR_STRING,
- .vval = {
- .v_string = (char_u[]) {
- (char_u) (mod_mask & MOD_MASK_SHIFT ? 's' : ' '),
- (char_u) (mod_mask & MOD_MASK_CTRL ? 'c' : ' '),
- (char_u) (mod_mask & MOD_MASK_ALT ? 'a' : ' '),
- (char_u) (mod_mask & MOD_MASK_META ? 'm' : ' '),
- NUL
- }
- },
- }
- };
- typval_T rettv;
- int doesrange;
- (void)call_func((char_u *)tab_page_click_defs[mouse_col].func,
- -1,
- &rettv, ARRAY_SIZE(argv), argv, NULL,
- curwin->w_cursor.lnum, curwin->w_cursor.lnum,
- &doesrange, true, NULL, NULL);
- tv_clear(&rettv);
- break;
- }
+ }
+ };
+ 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((char_u *)tab_page_click_defs[mouse_col].func, -1,
+ &rettv, ARRAY_SIZE(argv), argv, &funcexe);
+ tv_clear(&rettv);
+ break;
+ }
}
}
return true;
@@ -2569,8 +2607,9 @@ do_mouse (
if (is_click) {
/* stop Visual mode for a left click in a window, but not when
* on a status line */
- if (VIsual_active)
+ if (VIsual_active) {
jump_flags |= MOUSE_MAY_STOP_VIS;
+ }
} else {
jump_flags |= MOUSE_MAY_VIS;
}
@@ -2602,9 +2641,10 @@ do_mouse (
oap->motion_type = kMTCharWise;
}
- /* When releasing the button let jump_to_mouse() know. */
- if (!is_click && !is_drag)
+ // When releasing the button let jump_to_mouse() know.
+ if (!is_click && !is_drag) {
jump_flags |= MOUSE_RELEASED;
+ }
/*
* JUMP!
@@ -2620,8 +2660,9 @@ do_mouse (
/* When jumping to another window, clear a pending operator. That's a bit
* friendlier than beeping and not jumping to that window. */
- if (curwin != old_curwin && oap != NULL && oap->op_type != OP_NOP)
+ if (curwin != old_curwin && oap != NULL && oap->op_type != OP_NOP) {
clearop(oap);
+ }
if (mod_mask == 0
&& !is_drag
@@ -2651,16 +2692,17 @@ do_mouse (
}
}
- /* When dragging the mouse above the window, scroll down. */
+ // When dragging the mouse above the window, scroll down.
if (is_drag && mouse_row < 0 && !in_status_line) {
scroll_redraw(false, 1L);
mouse_row = 0;
}
- if (start_visual.lnum) { /* right click in visual mode */
- /* When ALT is pressed make Visual mode blockwise. */
- if (mod_mask & MOD_MASK_ALT)
+ if (start_visual.lnum) { // right click in visual mode
+ // When ALT is pressed make Visual mode blockwise.
+ if (mod_mask & MOD_MASK_ALT) {
VIsual_mode = Ctrl_V;
+ }
/*
* In Visual-block mode, divide the area in four, pick up the corner
@@ -2668,55 +2710,58 @@ do_mouse (
*/
if (VIsual_mode == Ctrl_V) {
getvcols(curwin, &start_visual, &end_visual, &leftcol, &rightcol);
- if (curwin->w_curswant > (leftcol + rightcol) / 2)
+ if (curwin->w_curswant > (leftcol + rightcol) / 2) {
end_visual.col = leftcol;
- else
+ } else {
end_visual.col = rightcol;
+ }
if (curwin->w_cursor.lnum >=
(start_visual.lnum + end_visual.lnum) / 2) {
end_visual.lnum = start_visual.lnum;
}
- /* move VIsual to the right column */
- start_visual = curwin->w_cursor; /* save the cursor pos */
+ // move VIsual to the right column
+ start_visual = curwin->w_cursor; // save the cursor pos
curwin->w_cursor = end_visual;
coladvance(end_visual.col);
VIsual = curwin->w_cursor;
- curwin->w_cursor = start_visual; /* restore the cursor */
+ curwin->w_cursor = start_visual; // restore the cursor
} else {
/*
* If the click is before the start of visual, change the start.
* If the click is after the end of visual, change the end. If
* the click is inside the visual, change the closest side.
*/
- if (lt(curwin->w_cursor, start_visual))
+ if (lt(curwin->w_cursor, start_visual)) {
VIsual = end_visual;
- else if (lt(end_visual, curwin->w_cursor))
+ } else if (lt(end_visual, curwin->w_cursor)) {
VIsual = start_visual;
- else {
- /* In the same line, compare column number */
+ } else {
+ // In the same line, compare column number
if (end_visual.lnum == start_visual.lnum) {
if (curwin->w_cursor.col - start_visual.col >
- end_visual.col - curwin->w_cursor.col)
+ end_visual.col - curwin->w_cursor.col) {
VIsual = start_visual;
- else
+ } else {
VIsual = end_visual;
+ }
}
- /* In different lines, compare line number */
+ // In different lines, compare line number
else {
diff = (curwin->w_cursor.lnum - start_visual.lnum) -
(end_visual.lnum - curwin->w_cursor.lnum);
- if (diff > 0) /* closest to end */
+ if (diff > 0) { // closest to end
VIsual = start_visual;
- else if (diff < 0) /* closest to start */
+ } else if (diff < 0) { // closest to start
VIsual = end_visual;
- else { /* in the middle line */
+ } else { // in the middle line
if (curwin->w_cursor.col <
- (start_visual.col + end_visual.col) / 2)
+ (start_visual.col + end_visual.col) / 2) {
VIsual = end_visual;
- else
+ } else {
VIsual = start_visual;
+ }
}
}
}
@@ -2725,8 +2770,9 @@ do_mouse (
/*
* If Visual mode started in insert mode, execute "CTRL-O"
*/
- else if ((State & INSERT) && VIsual_active)
+ else if ((State & INSERT) && VIsual_active) {
stuffcharReadbuff(Ctrl_O);
+ }
/*
* Middle mouse click: Put text before cursor.
@@ -2736,10 +2782,12 @@ do_mouse (
regname = '*';
}
if (yank_register_mline(regname)) {
- if (mouse_past_bottom)
+ if (mouse_past_bottom) {
dir = FORWARD;
- } else if (mouse_past_eol)
+ }
+ } else if (mouse_past_eol) {
dir = FORWARD;
+ }
if (fixindent) {
c1 = (dir == BACKWARD) ? '[' : ']';
@@ -2754,8 +2802,9 @@ do_mouse (
* Remember where the paste started, so in edit() Insstart can be set
* to this position
*/
- if (restart_edit != 0)
+ if (restart_edit != 0) {
where_paste_started = curwin->w_cursor;
+ }
do_put(regname, NULL, dir, count,
(fixindent ? PUT_FIXINDENT : 0)| PUT_CURSEND);
}
@@ -2781,10 +2830,11 @@ do_mouse (
&& (mod_mask &
MOD_MASK_MULTI_CLICK) ==
MOD_MASK_2CLICK)) {
- if (State & INSERT)
+ if (State & INSERT) {
stuffcharReadbuff(Ctrl_O);
+ }
stuffcharReadbuff(Ctrl_RSB);
- got_click = false; /* ignore drag&release now */
+ got_click = false; // ignore drag&release now
}
/*
* Shift-Mouse click searches for the next occurrence of the word under
@@ -2792,15 +2842,16 @@ do_mouse (
*/
else if ((mod_mask & MOD_MASK_SHIFT)) {
if (State & INSERT
- || (VIsual_active && VIsual_select)
- )
+ || (VIsual_active && VIsual_select)) {
stuffcharReadbuff(Ctrl_O);
- if (which_button == MOUSE_LEFT)
+ }
+ if (which_button == MOUSE_LEFT) {
stuffcharReadbuff('*');
- else /* MOUSE_RIGHT */
+ } else { // MOUSE_RIGHT
stuffcharReadbuff('#');
+ }
}
- /* Handle double clicks, unless on status line */
+ // Handle double clicks, unless on status line
else if (in_status_line) {
} else if (in_sep_line) {
} else if ((mod_mask & MOD_MASK_MULTI_CLICK) && (State & (NORMAL | INSERT))) {
@@ -2812,26 +2863,28 @@ do_mouse (
orig_cursor = VIsual;
VIsual_active = true;
VIsual_reselect = true;
- /* start Select mode if 'selectmode' contains "mouse" */
+ // start Select mode if 'selectmode' contains "mouse"
may_start_select('o');
setmouse();
}
if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK) {
- /* Double click with ALT pressed makes it blockwise. */
- if (mod_mask & MOD_MASK_ALT)
+ // Double click with ALT pressed makes it blockwise.
+ if (mod_mask & MOD_MASK_ALT) {
VIsual_mode = Ctrl_V;
- else
+ } else {
VIsual_mode = 'v';
- } else if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_3CLICK)
+ }
+ } else if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_3CLICK) {
VIsual_mode = 'V';
- else if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_4CLICK)
+ } else if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_4CLICK) {
VIsual_mode = Ctrl_V;
+ }
}
/*
* A double click selects a word or a block.
*/
if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK) {
- pos_T *pos = NULL;
+ pos_T *pos = NULL;
int gc;
if (is_click) {
@@ -2839,8 +2892,9 @@ do_mouse (
* not a word character, try finding a match and select a (),
* {}, [], #if/#endif, etc. block. */
end_visual = curwin->w_cursor;
- while (gc = gchar_pos(&end_visual), ascii_iswhite(gc))
+ while (gc = gchar_pos(&end_visual), ascii_iswhite(gc)) {
inc(&end_visual);
+ }
if (oap != NULL) {
oap->motion_type = kMTCharWise;
}
@@ -2870,28 +2924,32 @@ do_mouse (
find_end_of_word(&VIsual);
} else {
find_start_of_word(&VIsual);
- if (*p_sel == 'e' && *get_cursor_pos_ptr() != NUL)
+ if (*p_sel == 'e' && *get_cursor_pos_ptr() != NUL) {
curwin->w_cursor.col +=
(*mb_ptr2len)(get_cursor_pos_ptr());
+ }
find_end_of_word(&curwin->w_cursor);
}
}
curwin->w_set_curswant = true;
}
- if (is_click)
- redraw_curbuf_later(INVERTED); /* update the inversion */
+ if (is_click) {
+ redraw_curbuf_later(INVERTED); // update the inversion
+ }
} else if (VIsual_active && !old_active) {
- if (mod_mask & MOD_MASK_ALT)
+ if (mod_mask & MOD_MASK_ALT) {
VIsual_mode = Ctrl_V;
- else
+ } else {
VIsual_mode = 'v';
+ }
}
- /* If Visual mode changed show it later. */
+ // If Visual mode changed show it later.
if ((!VIsual_active && old_active && mode_displayed)
|| (VIsual_active && p_smd && msg_silent == 0
- && (!old_active || VIsual_mode != old_mode)))
+ && (!old_active || VIsual_mode != old_mode))) {
redraw_cmdline = true;
+ }
return moved;
}
@@ -2901,7 +2959,7 @@ do_mouse (
*/
static void find_start_of_word(pos_T *pos)
{
- char_u *line;
+ char_u *line;
int cclass;
int col;
@@ -2924,7 +2982,7 @@ static void find_start_of_word(pos_T *pos)
*/
static void find_end_of_word(pos_T *pos)
{
- char_u *line;
+ char_u *line;
int cclass;
int col;
@@ -2937,8 +2995,9 @@ static void find_end_of_word(pos_T *pos)
while (line[pos->col] != NUL) {
col = pos->col + (*mb_ptr2len)(line + pos->col);
if (get_mouse_class(line + col) != cclass) {
- if (*p_sel == 'e')
+ if (*p_sel == 'e') {
pos->col = col;
+ }
break;
}
pos->col = col;
@@ -2972,8 +3031,9 @@ static int get_mouse_class(char_u *p)
* "->", "/ *", "*=", "+=", "&=", "<=", ">=", "!=" etc. Otherwise, each
* character is in its own class.
*/
- if (c != NUL && vim_strchr((char_u *)"-+*/%<>&|^!=", c) != NULL)
+ if (c != NUL && vim_strchr((char_u *)"-+*/%<>&|^!=", c) != NULL) {
return 1;
+ }
return c;
}
@@ -2984,19 +3044,19 @@ static int get_mouse_class(char_u *p)
*/
void end_visual_mode(void)
{
-
VIsual_active = false;
setmouse();
mouse_dragging = 0;
- /* Save the current VIsual area for '< and '> marks, and "gv" */
+ // Save the current VIsual area for '< and '> marks, and "gv"
curbuf->b_visual.vi_mode = VIsual_mode;
curbuf->b_visual.vi_start = VIsual;
curbuf->b_visual.vi_end = curwin->w_cursor;
curbuf->b_visual.vi_curswant = curwin->w_curswant;
curbuf->b_visual_mode_eval = VIsual_mode;
- if (!virtual_active())
+ if (!virtual_active()) {
curwin->w_cursor.coladd = 0;
+ }
may_clear_cmdline();
@@ -3010,7 +3070,7 @@ void reset_VIsual_and_resel(void)
{
if (VIsual_active) {
end_visual_mode();
- redraw_curbuf_later(INVERTED); /* delete the inversion later */
+ redraw_curbuf_later(INVERTED); // delete the inversion later
}
VIsual_reselect = false;
}
@@ -3022,7 +3082,7 @@ void reset_VIsual(void)
{
if (VIsual_active) {
end_visual_mode();
- redraw_curbuf_later(INVERTED); /* delete the inversion later */
+ redraw_curbuf_later(INVERTED); // delete the inversion later
VIsual_reselect = false;
}
}
@@ -3033,11 +3093,8 @@ void reset_VIsual(void)
// "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.
-static bool find_is_eval_item(
- const char_u *const ptr,
- int *const colp,
- int *const bnp,
- const int dir)
+static bool find_is_eval_item(const char_u *const ptr, int *const colp, int *const bnp,
+ const int dir)
{
// Accept everything inside [].
if ((*ptr == ']' && dir == BACKWARD) || (*ptr == '[' && dir == FORWARD)) {
@@ -3090,17 +3147,12 @@ size_t find_ident_under_cursor(char_u **text, int find_type)
curwin->w_cursor.col, text, NULL, find_type);
}
-/*
- * Like find_ident_under_cursor(), but for any window and any position.
- * However: Uses 'iskeyword' from the current window!.
- */
-size_t find_ident_at_pos(
- win_T *wp,
- linenr_T lnum,
- colnr_T startcol,
- char_u **text,
- int *textcol, // column where "text" starts, can be NULL
- int find_type)
+/// Like find_ident_under_cursor(), but for any window and any position.
+/// However: Uses 'iskeyword' from the current window!.
+///
+/// @param textcol column where "text" starts, can be NULL
+size_t find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol, char_u **text, int *textcol,
+ int find_type)
FUNC_ATTR_NONNULL_ARG(1, 4)
{
int col = 0; // init to shut up GCC
@@ -3206,7 +3258,7 @@ size_t find_ident_at_pos(
static void prep_redo_cmd(cmdarg_T *cap)
{
prep_redo(cap->oap->regname, cap->count0,
- NUL, cap->cmdchar, NUL, NUL, cap->nchar);
+ NUL, cap->cmdchar, NUL, NUL, cap->nchar);
}
/*
@@ -3216,23 +3268,29 @@ static void prep_redo_cmd(cmdarg_T *cap)
static void prep_redo(int regname, long num, int cmd1, int cmd2, int cmd3, int cmd4, int cmd5)
{
ResetRedobuff();
- if (regname != 0) { /* yank from specified buffer */
+ if (regname != 0) { // yank from specified buffer
AppendCharToRedobuff('"');
AppendCharToRedobuff(regname);
}
- if (num)
+ if (num) {
AppendNumberToRedobuff(num);
+ }
- if (cmd1 != NUL)
+ if (cmd1 != NUL) {
AppendCharToRedobuff(cmd1);
- if (cmd2 != NUL)
+ }
+ if (cmd2 != NUL) {
AppendCharToRedobuff(cmd2);
- if (cmd3 != NUL)
+ }
+ if (cmd3 != NUL) {
AppendCharToRedobuff(cmd3);
- if (cmd4 != NUL)
+ }
+ if (cmd4 != NUL) {
AppendCharToRedobuff(cmd4);
- if (cmd5 != NUL)
+ }
+ if (cmd5 != NUL) {
AppendCharToRedobuff(cmd5);
+ }
}
/*
@@ -3242,8 +3300,9 @@ static void prep_redo(int regname, long num, int cmd1, int cmd2, int cmd3, int c
*/
static bool checkclearop(oparg_T *oap)
{
- if (oap->op_type == OP_NOP)
+ if (oap->op_type == OP_NOP) {
return false;
+ }
clearopbeep(oap);
return true;
}
@@ -3256,9 +3315,9 @@ static bool checkclearop(oparg_T *oap)
static bool checkclearopq(oparg_T *oap)
{
if (oap->op_type == OP_NOP
- && !VIsual_active
- )
+ && !VIsual_active) {
return false;
+ }
clearopbeep(oap);
return true;
}
@@ -3269,6 +3328,7 @@ static void clearop(oparg_T *oap)
oap->regname = 0;
oap->motion_force = NUL;
oap->use_reg_one = false;
+ motion_force = NUL;
}
static void clearopbeep(oparg_T *oap)
@@ -3283,12 +3343,18 @@ static void clearopbeep(oparg_T *oap)
static void unshift_special(cmdarg_T *cap)
{
switch (cap->cmdchar) {
- case K_S_RIGHT: cap->cmdchar = K_RIGHT; break;
- case K_S_LEFT: cap->cmdchar = K_LEFT; break;
- case K_S_UP: cap->cmdchar = K_UP; break;
- case K_S_DOWN: cap->cmdchar = K_DOWN; break;
- case K_S_HOME: cap->cmdchar = K_HOME; break;
- case K_S_END: cap->cmdchar = K_END; break;
+ case K_S_RIGHT:
+ cap->cmdchar = K_RIGHT; break;
+ case K_S_LEFT:
+ cap->cmdchar = K_LEFT; break;
+ case K_S_UP:
+ cap->cmdchar = K_UP; break;
+ case K_S_DOWN:
+ cap->cmdchar = K_DOWN; break;
+ case K_S_HOME:
+ cap->cmdchar = K_HOME; break;
+ case K_S_END:
+ cap->cmdchar = K_END; break;
}
cap->cmdchar = simplify_key(cap->cmdchar, &mod_mask);
}
@@ -3306,17 +3372,18 @@ static void may_clear_cmdline(void)
}
// Routines for displaying a partly typed command
-# define SHOWCMD_BUFLEN SHOWCMD_COLS + 1 + 30
+#define SHOWCMD_BUFLEN SHOWCMD_COLS + 1 + 30
static char_u showcmd_buf[SHOWCMD_BUFLEN];
-static char_u old_showcmd_buf[SHOWCMD_BUFLEN]; /* For push_showcmd() */
+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)
+ if (!p_sc) {
return;
+ }
if (VIsual_active && !char_avail()) {
int cursor_bot = lt(VIsual, curwin->w_cursor);
@@ -3324,7 +3391,7 @@ void clear_showcmd(void)
colnr_T leftcol, rightcol;
linenr_T top, bot;
- /* Show the size of the Visual area. */
+ // Show the size of the Visual area.
if (cursor_bot) {
top = VIsual.lnum;
bot = curwin->w_cursor.lnum;
@@ -3338,18 +3405,21 @@ void clear_showcmd(void)
lines = bot - top + 1;
if (VIsual_mode == Ctrl_V) {
- char_u *saved_sbr = p_sbr;
+ char_u *const saved_sbr = p_sbr;
+ char_u *const saved_w_sbr = curwin->w_p_sbr;
- /* Make 'sbr' empty for a moment to get the correct size. */
+ // Make 'sbr' empty for a moment to get the correct size.
p_sbr = empty_option;
+ curwin->w_p_sbr = empty_option;
getvcols(curwin, &curwin->w_cursor, &VIsual, &leftcol, &rightcol);
p_sbr = saved_sbr;
+ curwin->w_p_sbr = saved_w_sbr;
snprintf((char *)showcmd_buf, SHOWCMD_BUFLEN, "%" PRId64 "x%" PRId64,
(int64_t)lines, (int64_t)rightcol - leftcol + 1);
} else if (VIsual_mode == 'V' || VIsual.lnum != curwin->w_cursor.lnum) {
snprintf((char *)showcmd_buf, SHOWCMD_BUFLEN, "%" PRId64, (int64_t)lines);
} else {
- char_u *s, *e;
+ char_u *s, *e;
int l;
int bytes = 0;
int chars = 0;
@@ -3366,16 +3436,17 @@ void clear_showcmd(void)
if (l == 0) {
++bytes;
++chars;
- break; /* end of line */
+ break; // end of line
}
bytes += l;
++chars;
s += l;
}
- if (bytes == chars)
+ if (bytes == chars) {
sprintf((char *)showcmd_buf, "%d", chars);
- else
+ } else {
sprintf((char *)showcmd_buf, "%d-%d", chars, bytes);
+ }
}
int limit = ui_has(kUIMessages) ? SHOWCMD_BUFLEN-1 : SHOWCMD_COLS;
showcmd_buf[limit] = NUL; // truncate
@@ -3384,9 +3455,10 @@ void clear_showcmd(void)
showcmd_buf[0] = NUL;
showcmd_visual = false;
- /* Don't actually display something if there is nothing to clear. */
- if (showcmd_is_clear)
+ // Don't actually display something if there is nothing to clear.
+ if (showcmd_is_clear) {
return;
+ }
}
display_showcmd();
@@ -3398,7 +3470,7 @@ void clear_showcmd(void)
*/
bool add_to_showcmd(int c)
{
- char_u *p;
+ char_u *p;
int i;
static int ignore[] =
{
@@ -3412,23 +3484,28 @@ bool add_to_showcmd(int c)
0
};
- if (!p_sc || msg_silent != 0)
+ if (!p_sc || msg_silent != 0) {
return false;
+ }
if (showcmd_visual) {
showcmd_buf[0] = NUL;
showcmd_visual = false;
}
- /* Ignore keys that are scrollbar updates and mouse clicks */
- if (IS_SPECIAL(c))
- for (i = 0; ignore[i] != 0; ++i)
- if (ignore[i] == c)
+ // Ignore keys that are scrollbar updates and mouse clicks
+ if (IS_SPECIAL(c)) {
+ for (i = 0; ignore[i] != 0; ++i) {
+ if (ignore[i] == c) {
return false;
+ }
+ }
+ }
p = transchar(c);
- if (*p == ' ')
+ if (*p == ' ') {
STRCPY(p, "<20>");
+ }
size_t old_len = STRLEN(showcmd_buf);
size_t extra_len = STRLEN(p);
size_t limit = ui_has(kUIMessages) ? SHOWCMD_BUFLEN-1 : SHOWCMD_COLS;
@@ -3438,8 +3515,9 @@ bool add_to_showcmd(int c)
}
STRCAT(showcmd_buf, p);
- if (char_avail())
+ if (char_avail()) {
return false;
+ }
display_showcmd();
@@ -3459,16 +3537,19 @@ static void del_from_showcmd(int len)
{
int old_len;
- if (!p_sc)
+ if (!p_sc) {
return;
+ }
old_len = (int)STRLEN(showcmd_buf);
- if (len > old_len)
+ if (len > old_len) {
len = old_len;
+ }
showcmd_buf[old_len - len] = NUL;
- if (!char_avail())
+ if (!char_avail()) {
display_showcmd();
+ }
}
/*
@@ -3477,14 +3558,16 @@ static void del_from_showcmd(int len)
*/
void push_showcmd(void)
{
- if (p_sc)
+ if (p_sc) {
STRCPY(old_showcmd_buf, showcmd_buf);
+ }
}
void pop_showcmd(void)
{
- if (!p_sc)
+ if (!p_sc) {
return;
+ }
STRCPY(showcmd_buf, old_showcmd_buf);
@@ -3533,18 +3616,18 @@ static void display_showcmd(void)
*/
void do_check_scrollbind(bool check)
{
- static win_T *old_curwin = NULL;
+ static win_T *old_curwin = NULL;
static linenr_T old_topline = 0;
static int old_topfill = 0;
- static buf_T *old_buf = NULL;
+ static buf_T *old_buf = NULL;
static colnr_T old_leftcol = 0;
if (check && curwin->w_p_scb) {
/* If a ":syncbind" command was just used, don't scroll, only reset
* the values. */
- if (did_syncbind)
+ if (did_syncbind) {
did_syncbind = false;
- else if (curwin == old_curwin) {
+ } else if (curwin == old_curwin) {
/*
* Synchronize other windows, as necessary according to
* 'scrollbind'. Don't do this after an ":edit" command, except
@@ -3557,9 +3640,9 @@ void do_check_scrollbind(bool check)
|| curwin->w_topfill != old_topfill
|| curwin->w_leftcol != old_leftcol)) {
check_scrollbind(curwin->w_topline - old_topline,
- (long)(curwin->w_leftcol - old_leftcol));
+ (long)(curwin->w_leftcol - old_leftcol));
}
- } else if (vim_strchr(p_sbo, 'j')) { /* jump flag set in 'scrollopt' */
+ } else if (vim_strchr(p_sbo, 'j')) { // jump flag set in 'scrollopt'
/*
* When switching between windows, make sure that the relative
* vertical offset is valid for the new window. The relative
@@ -3591,8 +3674,8 @@ void check_scrollbind(linenr_T topline_diff, long leftcol_diff)
{
bool want_ver;
bool want_hor;
- win_T *old_curwin = curwin;
- buf_T *old_curbuf = curbuf;
+ win_T *old_curwin = curwin;
+ buf_T *old_curbuf = curbuf;
int old_VIsual_select = VIsual_select;
int old_VIsual_active = VIsual_active;
colnr_T tgt_leftcol = curwin->w_leftcol;
@@ -3613,7 +3696,7 @@ void check_scrollbind(linenr_T topline_diff, long leftcol_diff)
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
curwin = wp;
curbuf = curwin->w_buffer;
- /* skip original window and windows with 'noscrollbind' */
+ // skip original window and windows with 'noscrollbind'
if (curwin == old_curwin || !curwin->w_p_scb) {
continue;
}
@@ -3626,16 +3709,19 @@ void check_scrollbind(linenr_T topline_diff, long leftcol_diff)
} else {
curwin->w_scbind_pos += topline_diff;
topline = curwin->w_scbind_pos;
- if (topline > curbuf->b_ml.ml_line_count)
+ if (topline > curbuf->b_ml.ml_line_count) {
topline = curbuf->b_ml.ml_line_count;
- if (topline < 1)
+ }
+ if (topline < 1) {
topline = 1;
+ }
y = topline - curwin->w_topline;
- if (y > 0)
+ if (y > 0) {
scrollup(y, false);
- else
+ } else {
scrolldown(-y, false);
+ }
}
redraw_later(curwin, VALID);
@@ -3668,7 +3754,7 @@ void check_scrollbind(linenr_T topline_diff, long leftcol_diff)
*/
static void nv_ignore(cmdarg_T *cap)
{
- cap->retval |= CA_COMMAND_BUSY; /* don't call edit() now */
+ cap->retval |= CA_COMMAND_BUSY; // don't call edit() now
}
/*
@@ -3692,8 +3778,9 @@ static void nv_error(cmdarg_T *cap)
*/
static void nv_help(cmdarg_T *cap)
{
- if (!checkclearopq(cap->oap))
+ if (!checkclearopq(cap->oap)) {
ex_help(NULL);
+ }
}
/*
@@ -3722,25 +3809,22 @@ static void nv_page(cmdarg_T *cap)
{
if (!checkclearop(cap->oap)) {
if (mod_mask & MOD_MASK_CTRL) {
- /* <C-PageUp>: tab page back; <C-PageDown>: tab page forward */
- if (cap->arg == BACKWARD)
+ // <C-PageUp>: tab page back; <C-PageDown>: tab page forward
+ if (cap->arg == BACKWARD) {
goto_tabpage(-(int)cap->count1);
- else
+ } else {
goto_tabpage((int)cap->count0);
- } else
+ }
+ } else {
(void)onepage(cap->arg, cap->count1);
+ }
}
}
-/*
- * Implementation of "gd" and "gD" command.
- */
-static void
-nv_gd (
- oparg_T *oap,
- int nchar,
- int thisblock /* 1 for "1gd" and "1gD" */
-)
+/// Implementation of "gd" and "gD" command.
+///
+/// @param thisblock 1 for "1gd" and "1gD"
+static void nv_gd(oparg_T *oap, int nchar, int thisblock)
{
size_t len;
char_u *ptr;
@@ -3785,23 +3869,17 @@ static bool is_ident(char_u *line, int offset)
return incomment == false && instring == 0;
}
-/*
- * Search for variable declaration of "ptr[len]".
- * When "locally" is true in the current function ("gd"), otherwise in the
- * current file ("gD").
- * When "thisblock" is true check the {} block scope.
- * Return fail when not found.
- */
-bool
-find_decl (
- char_u *ptr,
- size_t len,
- bool locally,
- bool thisblock,
- int flags_arg // flags passed to searchit()
-)
-{
- char_u *pat;
+/// Search for variable declaration of "ptr[len]".
+/// When "locally" is true in the current function ("gd"), otherwise in the
+/// current file ("gD").
+///
+/// @param thisblock when true check the {} block scope.
+/// @param flags_arg flags passed to searchit()
+///
+/// @return fail when not found.
+bool find_decl(char_u *ptr, size_t len, bool locally, bool thisblock, int flags_arg)
+{
+ char_u *pat;
pos_T old_pos;
pos_T par_pos;
pos_T found_pos;
@@ -3822,8 +3900,8 @@ find_decl (
old_pos = curwin->w_cursor;
save_p_ws = p_ws;
save_p_scs = p_scs;
- p_ws = false; /* don't wrap around end of file now */
- p_scs = false; /* don't switch ignorecase off now */
+ p_ws = false; // don't wrap around end of file now
+ p_scs = false; // don't switch ignorecase off now
/*
* With "gD" go to line 1.
@@ -3831,18 +3909,19 @@ find_decl (
* back until a blank line. If this fails go to line 1.
*/
if (!locally || !findpar(&incll, BACKWARD, 1L, '{', false)) {
- setpcmark(); /* Set in findpar() otherwise */
+ setpcmark(); // Set in findpar() otherwise
curwin->w_cursor.lnum = 1;
par_pos = curwin->w_cursor;
} else {
par_pos = curwin->w_cursor;
while (curwin->w_cursor.lnum > 1
- && *skipwhite(get_cursor_line_ptr()) != NUL)
+ && *skipwhite(get_cursor_line_ptr()) != NUL) {
--curwin->w_cursor.lnum;
+ }
}
curwin->w_cursor.col = 0;
- /* Search forward for the identifier, ignore comment lines. */
+ // Search forward for the identifier, ignore comment lines.
clearpos(&found_pos);
for (;; ) {
t = searchit(curwin, curbuf, &curwin->w_cursor, NULL, FORWARD,
@@ -3866,7 +3945,7 @@ find_decl (
}
if (t == false) {
- /* If we previously found a valid position, use it. */
+ // If we previously found a valid position, use it.
if (found_pos.lnum != 0) {
curwin->w_cursor = found_pos;
t = true;
@@ -3874,7 +3953,7 @@ find_decl (
break;
}
if (get_leader_len(get_cursor_line_ptr(), NULL, false, true) > 0) {
- /* Ignore this line, continue at start of next line. */
+ // Ignore this line, continue at start of next line.
++curwin->w_cursor.lnum;
curwin->w_cursor.col = 0;
continue;
@@ -3916,7 +3995,7 @@ find_decl (
curwin->w_cursor = old_pos;
} else {
curwin->w_set_curswant = true;
- /* "n" searches forward now */
+ // "n" searches forward now
reset_search_dir();
}
@@ -3940,10 +4019,10 @@ static bool nv_screengo(oparg_T *oap, int dir, long dist)
bool retval = true;
bool atend = false;
int n;
- int col_off1; /* margin offset for first screen line */
- int col_off2; /* margin offset for wrapped screen line */
- int width1; /* text width for first screen line */
- int width2; /* test width for wrapped screen line */
+ int col_off1; // margin offset for first screen line
+ int col_off2; // margin offset for wrapped screen line
+ int width1; // text width for first screen line
+ int width2; // test width for wrapped screen line
oap->motion_type = kMTCharWise;
oap->inclusive = (curwin->w_curswant == MAXCOL);
@@ -3963,20 +4042,22 @@ static bool nv_screengo(oparg_T *oap, int dir, long dist)
if (curwin->w_curswant == MAXCOL) {
atend = true;
validate_virtcol();
- if (width1 <= 0)
+ if (width1 <= 0) {
curwin->w_curswant = 0;
- else {
+ } else {
curwin->w_curswant = width1 - 1;
- if (curwin->w_virtcol > curwin->w_curswant)
+ if (curwin->w_virtcol > curwin->w_curswant) {
curwin->w_curswant += ((curwin->w_virtcol
- curwin->w_curswant -
1) / width2 + 1) * width2;
+ }
}
} else {
- if (linelen > width1)
+ if (linelen > width1) {
n = ((linelen - width1 - 1) / width2 + 1) * width2 + width1;
- else
+ } else {
n = width1;
+ }
if (curwin->w_curswant >= n) {
curwin->w_curswant = n - 1;
}
@@ -4012,11 +4093,12 @@ static bool nv_screengo(oparg_T *oap, int dir, long dist)
curwin->w_curswant += w;
}
}
- } else { /* dir == FORWARD */
- if (linelen > width1)
+ } else { // dir == FORWARD
+ if (linelen > width1) {
n = ((linelen - width1 - 1) / width2 + 1) * width2 + width1;
- else
+ } else {
n = width1;
+ }
if (curwin->w_curswant + width2 < (colnr_T)n
&& !hasFolding(curwin->w_cursor.lnum, NULL, NULL)) {
// move forward within line
@@ -4046,10 +4128,11 @@ static bool nv_screengo(oparg_T *oap, int dir, long dist)
}
}
- if (virtual_active() && atend)
+ if (virtual_active() && atend) {
coladvance(MAXCOL);
- else
+ } else {
coladvance(curwin->w_curswant);
+ }
if (curwin->w_cursor.col > 0 && curwin->w_p_wrap) {
/*
@@ -4059,20 +4142,22 @@ static bool nv_screengo(oparg_T *oap, int dir, long dist)
*/
validate_virtcol();
colnr_T virtcol = curwin->w_virtcol;
- if (virtcol > (colnr_T)width1 && *p_sbr != NUL)
- virtcol -= vim_strsize(p_sbr);
+ if (virtcol > (colnr_T)width1 && *get_showbreak_value(curwin) != NUL) {
+ virtcol -= vim_strsize(get_showbreak_value(curwin));
+ }
if (virtcol > curwin->w_curswant
&& (curwin->w_curswant < (colnr_T)width1
? (curwin->w_curswant > (colnr_T)width1 / 2)
: ((curwin->w_curswant - width1) % width2
- > (colnr_T)width2 / 2)))
+ > (colnr_T)width2 / 2))) {
--curwin->w_cursor.col;
+ }
}
- if (atend)
- curwin->w_curswant = MAXCOL; /* stick in the last column */
-
+ if (atend) {
+ curwin->w_curswant = MAXCOL; // stick in the last column
+ }
return retval;
}
@@ -4137,8 +4222,9 @@ static void nv_mouse(cmdarg_T *cap)
*/
static void nv_scroll_line(cmdarg_T *cap)
{
- if (!checkclearop(cap->oap))
+ if (!checkclearop(cap->oap)) {
scroll_redraw(cap->arg, cap->count1);
+ }
}
/*
@@ -4151,8 +4237,8 @@ void scroll_redraw(int up, long count)
linenr_T prev_lnum = curwin->w_cursor.lnum;
bool moved = up ?
- scrollup(count, true) :
- scrolldown(count, true);
+ scrollup(count, true) :
+ scrolldown(count, true);
if (get_scrolloff_value(curwin)) {
// Adjust the cursor position for 'scrolloff'. Mark w_topline as
@@ -4165,17 +4251,18 @@ void scroll_redraw(int up, long count)
* we get stuck at one position. Don't move the cursor up if the
* first line of the buffer is already on the screen */
while (curwin->w_topline == prev_topline
- && curwin->w_topfill == prev_topfill
- ) {
+ && curwin->w_topfill == prev_topfill) {
if (up) {
if (curwin->w_cursor.lnum > prev_lnum
- || cursor_down(1L, false) == false)
+ || cursor_down(1L, false) == false) {
break;
+ }
} else {
if (curwin->w_cursor.lnum < prev_lnum
|| prev_topline == 1L
- || cursor_up(1L, false) == false)
+ || cursor_up(1L, false) == false) {
break;
+ }
}
/* Mark w_topline as valid, otherwise the screen jumps back at the
* end of the file. */
@@ -4211,8 +4298,9 @@ static void nv_zet(cmdarg_T *cap)
/*
* "z123{nchar}": edit the count before obtaining {nchar}
*/
- if (checkclearop(cap->oap))
+ if (checkclearop(cap->oap)) {
return;
+ }
n = nchar - '0';
for (;; ) {
no_mapping++;
@@ -4220,11 +4308,11 @@ static void nv_zet(cmdarg_T *cap)
LANGMAP_ADJUST(nchar, true);
no_mapping--;
(void)add_to_showcmd(nchar);
- if (nchar == K_DEL || nchar == K_KDEL)
+ if (nchar == K_DEL || nchar == K_KDEL) {
n /= 10;
- else if (ascii_isdigit(nchar))
+ } else if (ascii_isdigit(nchar)) {
n = n * 10 + (nchar - '0');
- else if (nchar == CAR) {
+ } else if (nchar == CAR) {
win_setheight(n);
break;
} else if (nchar == 'l'
@@ -4261,15 +4349,16 @@ dozet:
&& cap->count0
&& cap->count0 != curwin->w_cursor.lnum) {
setpcmark();
- if (cap->count0 > curbuf->b_ml.ml_line_count)
+ if (cap->count0 > curbuf->b_ml.ml_line_count) {
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
- else
+ } else {
curwin->w_cursor.lnum = cap->count0;
+ }
check_cursor_col();
}
switch (nchar) {
- /* "z+", "z<CR>" and "zt": put cursor at top of screen */
+ // "z+", "z<CR>" and "zt": put cursor at top of screen
case '+':
if (cap->count0 == 0) {
// No count given: put cursor at the line below screen
@@ -4287,16 +4376,19 @@ dozet:
beginline(BL_WHITE | BL_FIX);
FALLTHROUGH;
- case 't': scroll_cursor_top(0, true);
+ case 't':
+ scroll_cursor_top(0, true);
redraw_later(curwin, VALID);
set_fraction(curwin);
break;
- /* "z." and "zz": put cursor in middle of screen */
- case '.': beginline(BL_WHITE | BL_FIX);
- FALLTHROUGH;
+ // "z." and "zz": put cursor in middle of screen
+ case '.':
+ beginline(BL_WHITE | BL_FIX);
+ FALLTHROUGH;
- case 'z': scroll_cursor_halfway(true);
+ case 'z':
+ scroll_cursor_halfway(true);
redraw_later(curwin, VALID);
set_fraction(curwin);
break;
@@ -4308,74 +4400,83 @@ dozet:
if (cap->count0 != 0) {
scroll_cursor_bot(0, true);
curwin->w_cursor.lnum = curwin->w_topline;
- } else if (curwin->w_topline == 1)
+ } else if (curwin->w_topline == 1) {
curwin->w_cursor.lnum = 1;
- else
+ } else {
curwin->w_cursor.lnum = curwin->w_topline - 1;
+ }
FALLTHROUGH;
case '-':
beginline(BL_WHITE | BL_FIX);
FALLTHROUGH;
- case 'b': scroll_cursor_bot(0, true);
+ case 'b':
+ scroll_cursor_bot(0, true);
redraw_later(curwin, VALID);
set_fraction(curwin);
break;
- /* "zH" - scroll screen right half-page */
+ // "zH" - scroll screen right half-page
case 'H':
cap->count1 *= curwin->w_width_inner / 2;
FALLTHROUGH;
- /* "zh" - scroll screen to the right */
+ // "zh" - scroll screen to the right
case 'h':
case K_LEFT:
if (!curwin->w_p_wrap) {
- if ((colnr_T)cap->count1 > curwin->w_leftcol)
+ if ((colnr_T)cap->count1 > curwin->w_leftcol) {
curwin->w_leftcol = 0;
- else
+ } else {
curwin->w_leftcol -= (colnr_T)cap->count1;
+ }
leftcol_changed();
}
break;
// "zL" - scroll screen left half-page
- case 'L': cap->count1 *= curwin->w_width_inner / 2;
+ case 'L':
+ cap->count1 *= curwin->w_width_inner / 2;
FALLTHROUGH;
- /* "zl" - scroll screen to the left */
+ // "zl" - scroll screen to the left
case 'l':
case K_RIGHT:
if (!curwin->w_p_wrap) {
- /* scroll the window left */
+ // scroll the window left
curwin->w_leftcol += (colnr_T)cap->count1;
leftcol_changed();
}
break;
- /* "zs" - scroll screen, cursor at the start */
- case 's': if (!curwin->w_p_wrap) {
- if (hasFolding(curwin->w_cursor.lnum, NULL, NULL))
- col = 0; /* like the cursor is in col 0 */
- else
+ // "zs" - scroll screen, cursor at the start
+ case 's':
+ if (!curwin->w_p_wrap) {
+ if (hasFolding(curwin->w_cursor.lnum, NULL, NULL)) {
+ col = 0; // like the cursor is in col 0
+ } else {
getvcol(curwin, &curwin->w_cursor, &col, NULL, NULL);
- if (col > l_p_siso)
+ }
+ if (col > l_p_siso) {
col -= l_p_siso;
- else
+ } else {
col = 0;
+ }
if (curwin->w_leftcol != col) {
curwin->w_leftcol = col;
redraw_later(curwin, NOT_VALID);
}
- }
+ }
break;
- /* "ze" - scroll screen, cursor at the end */
- case 'e': if (!curwin->w_p_wrap) {
- if (hasFolding(curwin->w_cursor.lnum, NULL, NULL))
- col = 0; /* like the cursor is in col 0 */
- else
+ // "ze" - scroll screen, cursor at the end
+ case 'e':
+ if (!curwin->w_p_wrap) {
+ if (hasFolding(curwin->w_cursor.lnum, NULL, NULL)) {
+ col = 0; // like the cursor is in col 0
+ } else {
getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col);
+ }
n = curwin->w_width_inner - curwin_col_off();
if (col + l_p_siso < n) {
col = 0;
@@ -4386,7 +4487,7 @@ dozet:
curwin->w_leftcol = col;
redraw_later(curwin, NOT_VALID);
}
- }
+ }
break;
// "zp", "zP" in block mode put without addind trailing spaces
@@ -4395,41 +4496,46 @@ dozet:
nv_put(cap);
break;
// "zy" Yank without trailing spaces
- case 'y': nv_operator(cap);
- break;
+ case 'y':
+ nv_operator(cap);
+ break;
- /* "zF": create fold command */
- /* "zf": create fold operator */
+ // "zF": create fold command
+ // "zf": create fold operator
case 'F':
- case 'f': if (foldManualAllowed(true)) {
+ case 'f':
+ if (foldManualAllowed(true)) {
cap->nchar = 'f';
nv_operator(cap);
curwin->w_p_fen = true;
- /* "zF" is like "zfzf" */
+ // "zF" is like "zfzf"
if (nchar == 'F' && cap->oap->op_type == OP_FOLD) {
nv_operator(cap);
finish_op = true;
}
- } else
+ } else {
clearopbeep(cap->oap);
+ }
break;
- /* "zd": delete fold at cursor */
- /* "zD": delete fold at cursor recursively */
+ // "zd": delete fold at cursor
+ // "zD": delete fold at cursor recursively
case 'd':
- case 'D': if (foldManualAllowed(false)) {
+ case 'D':
+ if (foldManualAllowed(false)) {
if (VIsual_active) {
nv_operator(cap);
} else {
deleteFold(curwin, curwin->w_cursor.lnum,
curwin->w_cursor.lnum, nchar == 'D', false);
}
- }
+ }
break;
- /* "zE": erase all folds */
- case 'E': if (foldmethodIsManual(curwin)) {
+ // "zE": erase all folds
+ case 'E':
+ if (foldmethodIsManual(curwin)) {
clearFolding(curwin);
changed_window_setting();
} else if (foldmethodIsMarker(curwin)) {
@@ -4439,20 +4545,24 @@ dozet:
}
break;
- /* "zn": fold none: reset 'foldenable' */
- case 'n': curwin->w_p_fen = false;
+ // "zn": fold none: reset 'foldenable'
+ case 'n':
+ curwin->w_p_fen = false;
break;
- /* "zN": fold Normal: set 'foldenable' */
- case 'N': curwin->w_p_fen = true;
+ // "zN": fold Normal: set 'foldenable'
+ case 'N':
+ curwin->w_p_fen = true;
break;
- /* "zi": invert folding: toggle 'foldenable' */
- case 'i': curwin->w_p_fen = !curwin->w_p_fen;
+ // "zi": invert folding: toggle 'foldenable'
+ case 'i':
+ curwin->w_p_fen = !curwin->w_p_fen;
break;
// "za": open closed fold or close open fold at cursor
- case 'a': if (hasFolding(curwin->w_cursor.lnum, NULL, NULL)) {
+ case 'a':
+ if (hasFolding(curwin->w_cursor.lnum, NULL, NULL)) {
openFold(curwin->w_cursor, cap->count1);
} else {
closeFold(curwin->w_cursor, cap->count1);
@@ -4461,7 +4571,8 @@ dozet:
break;
// "zA": open fold at cursor recursively
- case 'A': if (hasFolding(curwin->w_cursor.lnum, NULL, NULL)) {
+ case 'A':
+ if (hasFolding(curwin->w_cursor.lnum, NULL, NULL)) {
openFoldRecurse(curwin->w_cursor);
} else {
closeFoldRecurse(curwin->w_cursor);
@@ -4470,7 +4581,8 @@ dozet:
break;
// "zo": open fold at cursor or Visual area
- case 'o': if (VIsual_active) {
+ case 'o':
+ if (VIsual_active) {
nv_operator(cap);
} else {
openFold(curwin->w_cursor, cap->count1);
@@ -4478,7 +4590,8 @@ dozet:
break;
// "zO": open fold recursively
- case 'O': if (VIsual_active) {
+ case 'O':
+ if (VIsual_active) {
nv_operator(cap);
} else {
openFoldRecurse(curwin->w_cursor);
@@ -4486,16 +4599,18 @@ dozet:
break;
// "zc": close fold at cursor or Visual area
- case 'c': if (VIsual_active) {
+ case 'c':
+ if (VIsual_active) {
nv_operator(cap);
- } else {
+ } else {
closeFold(curwin->w_cursor, cap->count1);
}
curwin->w_p_fen = true;
break;
// "zC": close fold recursively
- case 'C': if (VIsual_active) {
+ case 'C':
+ if (VIsual_active) {
nv_operator(cap);
} else {
closeFoldRecurse(curwin->w_cursor);
@@ -4503,24 +4618,27 @@ dozet:
curwin->w_p_fen = true;
break;
- /* "zv": open folds at the cursor */
- case 'v': foldOpenCursor();
+ // "zv": open folds at the cursor
+ case 'v':
+ foldOpenCursor();
break;
- /* "zx": re-apply 'foldlevel' and open folds at the cursor */
- case 'x': curwin->w_p_fen = true;
- curwin->w_foldinvalid = true; /* recompute folds */
- newFoldLevel(); /* update right now */
+ // "zx": re-apply 'foldlevel' and open folds at the cursor
+ case 'x':
+ curwin->w_p_fen = true;
+ curwin->w_foldinvalid = true; // recompute folds
+ newFoldLevel(); // update right now
foldOpenCursor();
break;
- /* "zX": undo manual opens/closes, re-apply 'foldlevel' */
- case 'X': curwin->w_p_fen = true;
- curwin->w_foldinvalid = true; /* recompute folds */
- old_fdl = -1; /* force an update */
+ // "zX": undo manual opens/closes, re-apply 'foldlevel'
+ case 'X':
+ curwin->w_p_fen = true;
+ curwin->w_foldinvalid = true; // recompute folds
+ old_fdl = -1; // force an update
break;
- /* "zm": fold more */
+ // "zm": fold more
case 'm':
if (curwin->w_p_fdl > 0) {
curwin->w_p_fdl -= cap->count1;
@@ -4528,17 +4646,18 @@ dozet:
curwin->w_p_fdl = 0;
}
}
- old_fdl = -1; /* force an update */
+ old_fdl = -1; // force an update
curwin->w_p_fen = true;
break;
- /* "zM": close all folds */
- case 'M': curwin->w_p_fdl = 0;
- old_fdl = -1; /* force an update */
+ // "zM": close all folds
+ case 'M':
+ curwin->w_p_fdl = 0;
+ old_fdl = -1; // force an update
curwin->w_p_fen = true;
break;
- /* "zr": reduce folding */
+ // "zr": reduce folding
case 'r':
curwin->w_p_fdl += cap->count1;
{
@@ -4554,11 +4673,12 @@ dozet:
old_fdl = -1; // force an update
break;
- case 'j': /* "zj" move to next fold downwards */
- case 'k': /* "zk" move to next fold upwards */
+ case 'j': // "zj" move to next fold downwards
+ case 'k': // "zk" move to next fold upwards
if (foldMoveTo(true, nchar == 'j' ? FORWARD : BACKWARD,
- cap->count1) == false)
+ cap->count1) == false) {
clearopbeep(cap->oap);
+ }
break;
@@ -4575,18 +4695,20 @@ dozet:
undo = true;
FALLTHROUGH;
- case 'g': /* "zg": add good word to word list */
- case 'w': /* "zw": add wrong word to word list */
- case 'G': /* "zG": add good word to temp word list */
- case 'W': /* "zW": add wrong word to temp word list */
+ case 'g': // "zg": add good word to word list
+ case 'w': // "zw": add wrong word to word list
+ case 'G': // "zG": add good word to temp word list
+ case 'W': // "zW": add wrong word to temp word list
{
- char_u *ptr = NULL;
+ char_u *ptr = NULL;
size_t len;
- if (checkclearop(cap->oap))
+ if (checkclearop(cap->oap)) {
break;
- if (VIsual_active && !get_visual_text(cap, &ptr, &len))
+ }
+ if (VIsual_active && !get_visual_text(cap, &ptr, &len)) {
return;
+ }
if (ptr == NULL) {
pos_T pos = curwin->w_cursor;
@@ -4596,13 +4718,15 @@ dozet:
emsg_off++;
len = spell_move_to(curwin, FORWARD, true, true, NULL);
emsg_off--;
- if (len != 0 && curwin->w_cursor.col <= pos.col)
+ if (len != 0 && curwin->w_cursor.col <= pos.col) {
ptr = ml_get_pos(&curwin->w_cursor);
+ }
curwin->w_cursor = pos;
}
- if (ptr == NULL && (len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0)
+ if (ptr == NULL && (len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0) {
return;
+ }
assert(len <= INT_MAX);
spell_add_word(ptr, (int)len,
nchar == 'w' || nchar == 'W'
@@ -4612,18 +4736,20 @@ dozet:
}
break;
- case '=': /* "z=": suggestions for a badly spelled word */
- if (!checkclearop(cap->oap))
+ case '=': // "z=": suggestions for a badly spelled word
+ if (!checkclearop(cap->oap)) {
spell_suggest((int)cap->count0);
+ }
break;
- default: clearopbeep(cap->oap);
+ default:
+ clearopbeep(cap->oap);
}
- /* Redraw when 'foldenable' changed */
+ // Redraw when 'foldenable' changed
if (old_fen != curwin->w_p_fen) {
if (foldmethodIsDiff(curwin) && curwin->w_p_scb) {
- /* Adjust 'foldenable' in diff-synced windows. */
+ // Adjust 'foldenable' in diff-synced windows.
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp != curwin && foldmethodIsDiff(wp) && wp->w_p_scb) {
wp->w_p_fen = curwin->w_p_fen;
@@ -4634,9 +4760,10 @@ dozet:
changed_window_setting();
}
- /* Redraw when 'foldlevel' changed. */
- if (old_fdl != curwin->w_p_fdl)
+ // Redraw when 'foldlevel' changed.
+ if (old_fdl != curwin->w_p_fdl) {
newFoldLevel();
+ }
}
@@ -4652,7 +4779,7 @@ static void nv_exmode(cmdarg_T *cap)
if (VIsual_active) {
vim_beep(BO_EX);
} else if (!checkclearop(cap->oap)) {
- do_exmode(false);
+ do_exmode();
}
}
@@ -4679,9 +4806,10 @@ static void nv_colon(cmdarg_T *cap)
}
}
- /* When typing, don't type below an old message */
- if (KeyTyped)
+ // When typing, don't type below an old message
+ if (KeyTyped) {
compute_cmdrow();
+ }
old_p_im = p_im;
@@ -4689,26 +4817,28 @@ static void nv_colon(cmdarg_T *cap)
cmd_result = do_cmdline(NULL, is_cmdkey ? getcmdkeycmd : getexline, NULL,
cap->oap->op_type != OP_NOP ? DOCMD_KEEPLINE : 0);
- /* If 'insertmode' changed, enter or exit Insert mode */
+ // If 'insertmode' changed, enter or exit Insert mode
if (p_im != old_p_im) {
- if (p_im)
+ if (p_im) {
restart_edit = 'i';
- else
+ } else {
restart_edit = 0;
+ }
}
- if (cmd_result == false)
- /* The Ex command failed, do not execute the operator. */
+ if (cmd_result == false) {
+ // The Ex command failed, do not execute the operator.
clearop(cap->oap);
- else if (cap->oap->op_type != OP_NOP
- && (cap->oap->start.lnum > curbuf->b_ml.ml_line_count
- || cap->oap->start.col >
- (colnr_T)STRLEN(ml_get(cap->oap->start.lnum))
- || did_emsg
- ))
+ } else if (cap->oap->op_type != OP_NOP
+ && (cap->oap->start.lnum > curbuf->b_ml.ml_line_count
+ || cap->oap->start.col >
+ (colnr_T)STRLEN(ml_get(cap->oap->start.lnum))
+ || did_emsg
+ )) {
/* The start of the operator has become invalid by the Ex command.
*/
clearopbeep(cap->oap);
+ }
}
}
@@ -4717,12 +4847,13 @@ static void nv_colon(cmdarg_T *cap)
*/
static void nv_ctrlg(cmdarg_T *cap)
{
- if (VIsual_active) { /* toggle Selection/Visual mode */
+ if (VIsual_active) { // toggle Selection/Visual mode
VIsual_select = !VIsual_select;
showmode();
- } else if (!checkclearop(cap->oap))
- /* print full name if count given or :cd used */
+ } else if (!checkclearop(cap->oap)) {
+ // print full name if count given or :cd used
fileinfo((int)cap->count0, false, true);
+ }
}
/*
@@ -4731,10 +4862,11 @@ static void nv_ctrlg(cmdarg_T *cap)
static void nv_ctrlh(cmdarg_T *cap)
{
if (VIsual_active && VIsual_select) {
- cap->cmdchar = 'x'; /* BS key behaves like 'x' in Select mode */
+ cap->cmdchar = 'x'; // BS key behaves like 'x' in Select mode
v_visop(cap);
- } else
+ } else {
nv_left(cap);
+ }
}
/*
@@ -4743,7 +4875,7 @@ static void nv_ctrlh(cmdarg_T *cap)
static void nv_clear(cmdarg_T *cap)
{
if (!checkclearop(cap->oap)) {
- /* Clear all syntax states to force resyncing. */
+ // Clear all syntax states to force resyncing.
syn_stack_free_all(curwin->w_s);
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
wp->w_s->b_syn_slow = false;
@@ -4761,7 +4893,7 @@ static void nv_ctrlo(cmdarg_T *cap)
if (VIsual_active && VIsual_select) {
VIsual_select = false;
showmode();
- restart_VIsual_select = 2; /* restart Select mode later */
+ restart_VIsual_select = 2; // restart Select mode later
} else {
cap->count1 = -cap->count1;
nv_pcmark(cap);
@@ -4772,9 +4904,10 @@ static void nv_ctrlo(cmdarg_T *cap)
// not named.
static void nv_hat(cmdarg_T *cap)
{
- if (!checkclearopq(cap->oap))
+ if (!checkclearopq(cap->oap)) {
(void)buflist_getfile((int)cap->count0, (linenr_T)0,
- GETF_SETMARK|GETF_ALT, false);
+ GETF_SETMARK|GETF_ALT, false);
+ }
}
/*
@@ -4784,15 +4917,18 @@ static void nv_Zet(cmdarg_T *cap)
{
if (!checkclearopq(cap->oap)) {
switch (cap->nchar) {
- /* "ZZ": equivalent to ":x". */
- case 'Z': do_cmdline_cmd("x");
+ // "ZZ": equivalent to ":x".
+ case 'Z':
+ do_cmdline_cmd("x");
break;
- /* "ZQ": equivalent to ":q!" (Elvis compatible). */
- case 'Q': do_cmdline_cmd("q!");
+ // "ZQ": equivalent to ":q!" (Elvis compatible).
+ case 'Q':
+ do_cmdline_cmd("q!");
break;
- default: clearopbeep(cap->oap);
+ default:
+ clearopbeep(cap->oap);
}
}
}
@@ -4815,23 +4951,23 @@ void do_nv_ident(int c1, int c2)
/*
* Handle the commands that use the word under the cursor.
- * [g] CTRL-] :ta to current identifier
- * [g] 'K' run program for current identifier
- * [g] '*' / to current identifier or string
- * [g] '#' ? to current identifier or string
- * g ']' :tselect for current identifier
+ * [g] CTRL-] :ta to current identifier
+ * [g] 'K' run program for current identifier
+ * [g] '*' / to current identifier or string
+ * [g] '#' ? to current identifier or string
+ * g ']' :tselect for current identifier
*/
static void nv_ident(cmdarg_T *cap)
{
- char_u *ptr = NULL;
- char_u *p;
- size_t n = 0; /* init for GCC */
+ char_u *ptr = NULL;
+ char_u *p;
+ size_t n = 0; // init for GCC
int cmdchar;
- bool g_cmd; /* "g" command */
+ bool g_cmd; // "g" command
bool tag_cmd = false;
- char_u *aux_ptr;
+ char_u *aux_ptr;
- if (cap->cmdchar == 'g') { /* "g*", "g#", "g]" and "gCTRL-]" */
+ if (cap->cmdchar == 'g') { // "g*", "g#", "g]" and "gCTRL-]"
cmdchar = cap->nchar;
g_cmd = true;
} else {
@@ -4839,17 +4975,20 @@ static void nv_ident(cmdarg_T *cap)
g_cmd = false;
}
- if (cmdchar == POUND) /* the pound sign, '#' for English keyboards */
+ if (cmdchar == POUND) { // the pound sign, '#' for English keyboards
cmdchar = '#';
+ }
/*
* The "]", "CTRL-]" and "K" commands accept an argument in Visual mode.
*/
if (cmdchar == ']' || cmdchar == Ctrl_RSB || cmdchar == 'K') {
- if (VIsual_active && get_visual_text(cap, &ptr, &n) == false)
+ if (VIsual_active && get_visual_text(cap, &ptr, &n) == false) {
return;
- if (checkclearopq(cap->oap))
+ }
+ if (checkclearopq(cap->oap)) {
return;
+ }
}
if (ptr == NULL && (n = find_ident_under_cursor(&ptr,
@@ -4886,11 +5025,12 @@ static void nv_ident(cmdarg_T *cap)
* it was.
*/
setpcmark();
- curwin->w_cursor.col = (colnr_T) (ptr - get_cursor_line_ptr());
+ curwin->w_cursor.col = (colnr_T)(ptr - get_cursor_line_ptr());
- if (!g_cmd && vim_iswordp(ptr))
+ if (!g_cmd && vim_iswordp(ptr)) {
STRCPY(buf, "\\<");
- no_smartcase = true; /* don't use 'smartcase' now */
+ }
+ no_smartcase = true; // don't use 'smartcase' now
break;
case 'K':
@@ -4910,7 +5050,7 @@ static void nv_ident(cmdarg_T *cap)
--n;
}
if (n == 0) {
- EMSG(_(e_noident)); /* found dashes only */
+ EMSG(_(e_noident)); // found dashes only
xfree(buf);
return;
}
@@ -4923,7 +5063,8 @@ static void nv_ident(cmdarg_T *cap)
snprintf(buf, buf_size, ".,.+%" PRId64, (int64_t)(cap->count0 - 1));
}
- STRCAT(buf, "! ");
+ do_cmdline_cmd("tabnew");
+ STRCAT(buf, "terminal ");
if (cap->count0 == 0 && isman_s) {
STRCAT(buf, "man");
} else {
@@ -4932,7 +5073,7 @@ static void nv_ident(cmdarg_T *cap)
STRCAT(buf, " ");
if (cap->count0 != 0 && (isman || isman_s)) {
snprintf(buf + STRLEN(buf), buf_size - STRLEN(buf), "%" PRId64,
- (int64_t)cap->count0);
+ (int64_t)cap->count0);
STRCAT(buf, " ");
}
}
@@ -4940,21 +5081,23 @@ static void nv_ident(cmdarg_T *cap)
case ']':
tag_cmd = true;
- if (p_cst)
+ if (p_cst) {
STRCPY(buf, "cstag ");
- else
+ } else {
STRCPY(buf, "ts ");
+ }
break;
default:
tag_cmd = true;
- if (curbuf->b_help)
+ if (curbuf->b_help) {
STRCPY(buf, "he! ");
- else {
- if (g_cmd)
+ } else {
+ if (g_cmd) {
STRCPY(buf, "tj ");
- else
+ } else {
snprintf(buf, buf_size, "%" PRId64 "ta ", (int64_t)cap->count0);
+ }
}
}
@@ -4974,24 +5117,27 @@ static void nv_ident(cmdarg_T *cap)
STRCAT(buf, p);
xfree(p);
} else {
- if (cmdchar == '*')
+ if (cmdchar == '*') {
aux_ptr = (char_u *)(p_magic ? "/.*~[^$\\" : "/^$\\");
- else if (cmdchar == '#')
+ } else if (cmdchar == '#') {
aux_ptr = (char_u *)(p_magic ? "/?.*~[^$\\" : "/?^$\\");
- else if (tag_cmd) {
- if (curbuf->b_help)
- /* ":help" handles unescaped argument */
+ } else if (tag_cmd) {
+ if (curbuf->b_help) {
+ // ":help" handles unescaped argument
aux_ptr = (char_u *)"";
- else
+ } else {
aux_ptr = (char_u *)"\\|\"\n[";
- } else
+ }
+ } else {
aux_ptr = (char_u *)"\\|\"\n*?[";
+ }
p = (char_u *)buf + STRLEN(buf);
while (n-- > 0) {
- /* put a backslash before \ and some others */
- if (vim_strchr(aux_ptr, *ptr) != NULL)
+ // put a backslash before \ and some others
+ if (vim_strchr(aux_ptr, *ptr) != NULL) {
*p++ = '\\';
+ }
/* When current byte is a part of multibyte character, copy all
* bytes of that character. */
const size_t len = (size_t)(utfc_ptr2len(ptr) - 1);
@@ -5020,27 +5166,37 @@ static void nv_ident(cmdarg_T *cap)
g_tag_at_cursor = true;
do_cmdline_cmd(buf);
g_tag_at_cursor = false;
+
+ if (cmdchar == 'K' && !kp_ex && !kp_help) {
+ // Start insert mode in terminal buffer
+ restart_edit = 'i';
+
+ add_map((char_u *)"<buffer> <esc> <Cmd>call jobstop(&channel)<CR>", TERM_FOCUS, true);
+ do_cmdline_cmd("autocmd TermClose <buffer> "
+ " if !v:event.status |"
+ " exec 'bdelete! ' .. expand('<abuf>') |"
+ " endif");
+ }
}
xfree(buf);
}
-/*
- * Get visually selected text, within one line only.
- * Returns false if more than one line selected.
- */
-bool
-get_visual_text (
- cmdarg_T *cap,
- char_u **pp, /* return: start of selected text */
- size_t *lenp /* return: length of selected text */
-)
-{
- if (VIsual_mode != 'V')
+/// Get visually selected text, within one line only.
+///
+/// @param pp return: start of selected text
+/// @param lenp return: length of selected text
+///
+/// @return false if more than one line selected.
+bool get_visual_text(cmdarg_T *cap, char_u **pp, size_t *lenp)
+{
+ if (VIsual_mode != 'V') {
unadjust_for_sel();
+ }
if (VIsual.lnum != curwin->w_cursor.lnum) {
- if (cap != NULL)
+ if (cap != NULL) {
clearopbeep(cap->oap);
+ }
return false;
}
if (VIsual_mode == 'V') {
@@ -5066,8 +5222,9 @@ get_visual_text (
*/
static void nv_tagpop(cmdarg_T *cap)
{
- if (!checkclearopq(cap->oap))
+ if (!checkclearopq(cap->oap)) {
do_tag((char_u *)"", DT_POP, (int)cap->count1, false, true);
+ }
}
/*
@@ -5086,40 +5243,42 @@ static void nv_scroll(cmdarg_T *cap)
if (cap->cmdchar == 'L') {
validate_botline(curwin); // make sure curwin->w_botline is valid
curwin->w_cursor.lnum = curwin->w_botline - 1;
- if (cap->count1 - 1 >= curwin->w_cursor.lnum)
+ if (cap->count1 - 1 >= curwin->w_cursor.lnum) {
curwin->w_cursor.lnum = 1;
- else {
+ } else {
if (hasAnyFolding(curwin)) {
- /* Count a fold for one screen line. */
+ // Count a fold for one screen line.
for (n = cap->count1 - 1; n > 0
&& curwin->w_cursor.lnum > curwin->w_topline; --n) {
(void)hasFolding(curwin->w_cursor.lnum,
- &curwin->w_cursor.lnum, NULL);
+ &curwin->w_cursor.lnum, NULL);
--curwin->w_cursor.lnum;
}
- } else
+ } else {
curwin->w_cursor.lnum -= cap->count1 - 1;
+ }
}
} else {
if (cap->cmdchar == 'M') {
- /* Don't count filler lines above the window. */
- used -= diff_check_fill(curwin, curwin->w_topline)
+ // Don't count filler lines above the window.
+ used -= win_get_fill(curwin, curwin->w_topline)
- curwin->w_topfill;
validate_botline(curwin); // make sure w_empty_rows is valid
half = (curwin->w_height_inner - curwin->w_empty_rows + 1) / 2;
for (n = 0; curwin->w_topline + n < curbuf->b_ml.ml_line_count; n++) {
// Count half he number of filler lines to be "below this
// line" and half to be "above the next line".
- if (n > 0 && used + diff_check_fill(curwin, curwin->w_topline
- + n) / 2 >= half) {
- --n;
+ if (n > 0 && used + win_get_fill(curwin, curwin->w_topline + n) / 2 >= half) {
+ n--;
break;
}
- used += plines(curwin->w_topline + n);
- if (used >= half)
+ used += plines_win(curwin, curwin->w_topline + n, true);
+ if (used >= half) {
break;
- if (hasFolding(curwin->w_topline + n, NULL, &lnum))
+ }
+ if (hasFolding(curwin->w_topline + n, NULL, &lnum)) {
n = lnum - curwin->w_topline;
+ }
}
if (n > 0 && used > curwin->w_height_inner) {
n--;
@@ -5127,7 +5286,7 @@ static void nv_scroll(cmdarg_T *cap)
} else { // (cap->cmdchar == 'H')
n = cap->count1 - 1;
if (hasAnyFolding(curwin)) {
- /* Count a fold for one screen line. */
+ // Count a fold for one screen line.
lnum = curwin->w_topline;
while (n-- > 0 && lnum < curwin->w_botline - 1) {
(void)hasFolding(lnum, NULL, &lnum);
@@ -5137,8 +5296,9 @@ static void nv_scroll(cmdarg_T *cap)
}
}
curwin->w_cursor.lnum = curwin->w_topline + n;
- if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
+ if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) {
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+ }
}
// Correct for 'so', except when an operator is pending.
@@ -5157,9 +5317,10 @@ static void nv_right(cmdarg_T *cap)
int PAST_LINE;
if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)) {
- /* <C-Right> and <S-Right> move a word or WORD right */
- if (mod_mask & MOD_MASK_CTRL)
+ // <C-Right> and <S-Right> move a word or WORD right
+ if (mod_mask & MOD_MASK_CTRL) {
cap->arg = true;
+ }
nv_wordcmd(cap);
return;
}
@@ -5172,13 +5333,14 @@ static void nv_right(cmdarg_T *cap)
* In virtual mode, there's no such thing as "PAST_LINE", as lines are
* (theoretically) infinitely long.
*/
- if (virtual_active())
+ if (virtual_active()) {
PAST_LINE = 0;
+ }
for (n = cap->count1; n > 0; --n) {
if ((!PAST_LINE && oneright() == false)
- || (PAST_LINE && *get_cursor_pos_ptr() == NUL)
- ) {
+ || (PAST_LINE &&
+ *get_cursor_pos_ptr() == NUL)) {
// <Space> wraps to next line if 'whichwrap' has 's'.
// 'l' wraps to next line if 'whichwrap' has 'l'.
// CURS_RIGHT wraps to next line if 'whichwrap' has '>'.
@@ -5223,8 +5385,9 @@ static void nv_right(cmdarg_T *cap)
}
}
if (n != cap->count1 && (fdo_flags & FDO_HOR) && KeyTyped
- && cap->oap->op_type == OP_NOP)
+ && cap->oap->op_type == OP_NOP) {
foldOpenCursor();
+ }
}
/*
@@ -5237,9 +5400,10 @@ static void nv_left(cmdarg_T *cap)
long n;
if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)) {
- /* <C-Left> and <S-Left> move a word or WORD left */
- if (mod_mask & MOD_MASK_CTRL)
+ // <C-Left> and <S-Left> move a word or WORD left
+ if (mod_mask & MOD_MASK_CTRL) {
cap->arg = 1;
+ }
nv_bck_word(cap);
return;
}
@@ -5249,8 +5413,8 @@ static void nv_left(cmdarg_T *cap)
for (n = cap->count1; n > 0; --n) {
if (oneleft() == false) {
/* <BS> and <Del> wrap to previous line if 'whichwrap' has 'b'.
- * 'h' wraps to previous line if 'whichwrap' has 'h'.
- * CURS_LEFT wraps to previous line if 'whichwrap' has '<'.
+ * 'h' wraps to previous line if 'whichwrap' has 'h'.
+ * CURS_LEFT wraps to previous line if 'whichwrap' has '<'.
*/
if ((((cap->cmdchar == K_BS || cap->cmdchar == Ctrl_H)
&& vim_strchr(p_ww, 'b') != NULL)
@@ -5276,15 +5440,17 @@ static void nv_left(cmdarg_T *cap)
}
continue;
}
- /* Only beep and flush if not moved at all */
- else if (cap->oap->op_type == OP_NOP && n == cap->count1)
+ // Only beep and flush if not moved at all
+ else if (cap->oap->op_type == OP_NOP && n == cap->count1) {
beep_flush();
+ }
break;
}
}
if (n != cap->count1 && (fdo_flags & FDO_HOR) && KeyTyped
- && cap->oap->op_type == OP_NOP)
+ && cap->oap->op_type == OP_NOP) {
foldOpenCursor();
+ }
}
/*
@@ -5294,7 +5460,7 @@ static void nv_left(cmdarg_T *cap)
static void nv_up(cmdarg_T *cap)
{
if (mod_mask & MOD_MASK_SHIFT) {
- /* <S-Up> is page up */
+ // <S-Up> is page up
cap->arg = BACKWARD;
nv_page(cap);
} else {
@@ -5314,7 +5480,7 @@ static void nv_up(cmdarg_T *cap)
static void nv_down(cmdarg_T *cap)
{
if (mod_mask & MOD_MASK_SHIFT) {
- /* <S-Down> is page down */
+ // <S-Down> is page down
cap->arg = FORWARD;
nv_page(cap);
} else if (bt_quickfix(curbuf) && cap->cmdchar == CAR) {
@@ -5347,7 +5513,7 @@ static void nv_down(cmdarg_T *cap)
*/
static void nv_gotofile(cmdarg_T *cap)
{
- char_u *ptr;
+ char_u *ptr;
linenr_T lnum = -1;
if (text_locked()) {
@@ -5376,8 +5542,9 @@ static void nv_gotofile(cmdarg_T *cap)
beginline(BL_SOL | BL_FIX);
}
xfree(ptr);
- } else
+ } else {
clearop(cap->oap);
+ }
}
/*
@@ -5385,10 +5552,10 @@ static void nv_gotofile(cmdarg_T *cap)
*/
static void nv_end(cmdarg_T *cap)
{
- if (cap->arg || (mod_mask & MOD_MASK_CTRL)) { /* CTRL-END = goto last line */
+ if (cap->arg || (mod_mask & MOD_MASK_CTRL)) { // CTRL-END = goto last line
cap->arg = true;
nv_goto(cap);
- cap->count1 = 1; /* to end of current line */
+ cap->count1 = 1; // to end of current line
}
nv_dollar(cap);
}
@@ -5404,13 +5571,15 @@ static void nv_dollar(cmdarg_T *cap)
* is pending (whew!) keep the cursor where it is.
* Otherwise, send it to the end of the line. */
if (!virtual_active() || gchar_cursor() != NUL
- || cap->oap->op_type == OP_NOP)
- curwin->w_curswant = MAXCOL; /* so we stay at the end */
+ || cap->oap->op_type == OP_NOP) {
+ curwin->w_curswant = MAXCOL; // so we stay at the end
+ }
if (cursor_down(cap->count1 - 1,
- cap->oap->op_type == OP_NOP) == false)
+ cap->oap->op_type == OP_NOP) == false) {
clearopbeep(cap->oap);
- else if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP)
+ } else if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP) {
foldOpenCursor();
+ }
}
/*
@@ -5419,11 +5588,11 @@ static void nv_dollar(cmdarg_T *cap)
*/
static void nv_search(cmdarg_T *cap)
{
- oparg_T *oap = cap->oap;
+ oparg_T *oap = cap->oap;
pos_T save_cursor = curwin->w_cursor;
if (cap->cmdchar == '?' && cap->oap->op_type == OP_ROT13) {
- /* Translate "g??" to "g?g?" */
+ // Translate "g??" to "g?g?"
cap->cmdchar = 'g';
cap->nchar = '?';
nv_operator(cap);
@@ -5464,18 +5633,13 @@ static void nv_next(cmdarg_T *cap)
}
}
-/*
- * Search for "pat" in direction "dir" ('/' or '?', 0 for repeat).
- * Uses only cap->count1 and cap->oap from "cap".
- * Return 0 for failure, 1 for found, 2 for found and line offset added.
- */
-static int normal_search(
- cmdarg_T *cap,
- int dir,
- char_u *pat,
- int opt, // extra flags for do_search()
- int *wrapped
-)
+/// Search for "pat" in direction "dir" ('/' or '?', 0 for repeat).
+/// Uses only cap->count1 and cap->oap from "cap".
+///
+/// @param opt extra flags for do_search()
+///
+/// @return 0 for failure, 1 for found, 2 for found and line offset added.
+static int normal_search(cmdarg_T *cap, int dir, char_u *pat, int opt, int *wrapped)
{
int i;
searchit_arg_T sia;
@@ -5498,8 +5662,9 @@ static int normal_search(
cap->oap->motion_type = kMTLineWise;
}
curwin->w_cursor.coladd = 0;
- if (cap->oap->op_type == OP_NOP && (fdo_flags & FDO_SEARCH) && KeyTyped)
+ if (cap->oap->op_type == OP_NOP && (fdo_flags & FDO_SEARCH) && KeyTyped) {
foldOpenCursor();
+ }
}
/* "/$" will put the cursor after the end of the line, may need to
@@ -5518,28 +5683,31 @@ static void nv_csearch(cmdarg_T *cap)
{
bool t_cmd;
- if (cap->cmdchar == 't' || cap->cmdchar == 'T')
+ if (cap->cmdchar == 't' || cap->cmdchar == 'T') {
t_cmd = true;
- else
+ } else {
t_cmd = false;
+ }
cap->oap->motion_type = kMTCharWise;
if (IS_SPECIAL(cap->nchar) || searchc(cap, t_cmd) == false) {
clearopbeep(cap->oap);
} else {
curwin->w_set_curswant = true;
- /* Include a Tab for "tx" and for "dfx". */
+ // Include a Tab for "tx" and for "dfx".
if (gchar_cursor() == TAB && virtual_active() && cap->arg == FORWARD
&& (t_cmd || cap->oap->op_type != OP_NOP)) {
colnr_T scol, ecol;
getvcol(curwin, &curwin->w_cursor, &scol, NULL, &ecol);
curwin->w_cursor.coladd = ecol - scol;
- } else
+ } else {
curwin->w_cursor.coladd = 0;
+ }
adjust_for_sel(cap);
- if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP)
+ if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP) {
foldOpenCursor();
+ }
}
}
@@ -5551,8 +5719,8 @@ static void nv_brackets(cmdarg_T *cap)
{
pos_T new_pos = { 0, 0, 0 };
pos_T prev_pos;
- pos_T *pos = NULL; /* init for GCC */
- pos_T old_pos; /* cursor position before command */
+ pos_T *pos = NULL; // init for GCC
+ pos_T old_pos; // cursor position before command
int flag;
long n;
int findc;
@@ -5561,32 +5729,32 @@ static void nv_brackets(cmdarg_T *cap)
cap->oap->motion_type = kMTCharWise;
cap->oap->inclusive = false;
old_pos = curwin->w_cursor;
- curwin->w_cursor.coladd = 0; /* TODO: don't do this for an error. */
+ curwin->w_cursor.coladd = 0; // TODO: don't do this for an error.
/*
* "[f" or "]f" : Edit file under the cursor (same as "gf")
*/
- if (cap->nchar == 'f')
+ if (cap->nchar == 'f') {
nv_gotofile(cap);
- else
+ } else
/*
* Find the occurrence(s) of the identifier or define under cursor
* in current and included files or jump to the first occurrence.
*
- * search list jump
- * fwd bwd fwd bwd fwd bwd
- * identifier "]i" "[i" "]I" "[I" "]^I" "[^I"
- * define "]d" "[d" "]D" "[D" "]^D" "[^D"
+ * search list jump
+ * fwd bwd fwd bwd fwd bwd
+ * identifier "]i" "[i" "]I" "[I" "]^I" "[^I"
+ * define "]d" "[d" "]D" "[D" "]^D" "[^D"
*/
if (vim_strchr((char_u *)
- "iI\011dD\004",
- cap->nchar) != NULL) {
- char_u *ptr;
+ "iI\011dD\004",
+ cap->nchar) != NULL) {
+ char_u *ptr;
size_t len;
- if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0)
+ if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0) {
clearop(cap->oap);
- else {
+ } else {
find_pattern_in_path(ptr, 0, len, true,
cap->count0 == 0 ? !isupper(cap->nchar) : false,
(((cap->nchar & 0xf) == ('d' & 0xf))
@@ -5614,14 +5782,16 @@ static void nv_brackets(cmdarg_T *cap)
&& vim_strchr((char_u *)"{(*/#mM", cap->nchar) != NULL)
|| (cap->cmdchar == ']'
&& vim_strchr((char_u *)"})*/#mM", cap->nchar) != NULL)) {
- if (cap->nchar == '*')
+ if (cap->nchar == '*') {
cap->nchar = '/';
+ }
prev_pos.lnum = 0;
if (cap->nchar == 'm' || cap->nchar == 'M') {
- if (cap->cmdchar == '[')
+ if (cap->cmdchar == '[') {
findc = '{';
- else
+ } else {
findc = '}';
+ }
n = 9999;
} else {
findc = cap->nchar;
@@ -5629,12 +5799,14 @@ static void nv_brackets(cmdarg_T *cap)
}
for (; n > 0; --n) {
if ((pos = findmatchlimit(cap->oap, findc,
- (cap->cmdchar == '[') ? FM_BACKWARD : FM_FORWARD, 0)) == NULL) {
- if (new_pos.lnum == 0) { /* nothing found */
- if (cap->nchar != 'm' && cap->nchar != 'M')
+ (cap->cmdchar == '[') ? FM_BACKWARD : FM_FORWARD, 0)) == NULL) {
+ if (new_pos.lnum == 0) { // nothing found
+ if (cap->nchar != 'm' && cap->nchar != 'M') {
clearopbeep(cap->oap);
- } else
- pos = &new_pos; /* use last one found */
+ }
+ } else {
+ pos = &new_pos; // use last one found
+ }
break;
}
prev_pos = new_pos;
@@ -5650,24 +5822,27 @@ static void nv_brackets(cmdarg_T *cap)
* Also repeat for the given count.
*/
if (cap->nchar == 'm' || cap->nchar == 'M') {
- /* norm is true for "]M" and "[m" */
+ // norm is true for "]M" and "[m"
int norm = ((findc == '{') == (cap->nchar == 'm'));
n = cap->count1;
- /* found a match: we were inside a method */
+ // found a match: we were inside a method
if (prev_pos.lnum != 0) {
pos = &prev_pos;
curwin->w_cursor = prev_pos;
- if (norm)
+ if (norm) {
--n;
- } else
+ }
+ } else {
pos = NULL;
+ }
while (n > 0) {
for (;; ) {
if ((findc == '{' ? dec_cursor() : inc_cursor()) < 0) {
- /* if not found anything, that's an error */
- if (pos == NULL)
+ // if not found anything, that's an error
+ if (pos == NULL) {
clearopbeep(cap->oap);
+ }
n = 0;
break;
}
@@ -5686,54 +5861,59 @@ static void nv_brackets(cmdarg_T *cap)
new_pos = curwin->w_cursor;
pos = &new_pos;
}
- /* found start/end of other method: go to match */
+ // found start/end of other method: go to match
else if ((pos = findmatchlimit(cap->oap, findc,
- (cap->cmdchar == '[') ? FM_BACKWARD : FM_FORWARD,
- 0)) == NULL)
+ (cap->cmdchar == '[') ? FM_BACKWARD : FM_FORWARD,
+ 0)) == NULL) {
n = 0;
- else
+ } else {
curwin->w_cursor = *pos;
+ }
break;
}
}
--n;
}
curwin->w_cursor = old_pos;
- if (pos == NULL && new_pos.lnum != 0)
+ if (pos == NULL && new_pos.lnum != 0) {
clearopbeep(cap->oap);
+ }
}
if (pos != NULL) {
setpcmark();
curwin->w_cursor = *pos;
curwin->w_set_curswant = true;
if ((fdo_flags & FDO_BLOCK) && KeyTyped
- && cap->oap->op_type == OP_NOP)
+ && cap->oap->op_type == OP_NOP) {
foldOpenCursor();
+ }
}
}
/*
* "[[", "[]", "]]" and "][": move to start or end of function
*/
else if (cap->nchar == '[' || cap->nchar == ']') {
- if (cap->nchar == cap->cmdchar) /* "]]" or "[[" */
+ if (cap->nchar == cap->cmdchar) { // "]]" or "[["
flag = '{';
- else
- flag = '}'; /* "][" or "[]" */
-
+ } else {
+ flag = '}'; // "][" or "[]"
+ }
curwin->w_set_curswant = true;
/*
* Imitate strange Vi behaviour: When using "]]" with an operator
* we also stop at '}'.
*/
if (!findpar(&cap->oap->inclusive, cap->arg, cap->count1, flag,
- (cap->oap->op_type != OP_NOP
- && cap->arg == FORWARD && flag == '{')))
+ (cap->oap->op_type != OP_NOP
+ && cap->arg == FORWARD && flag == '{'))) {
clearopbeep(cap->oap);
- else {
- if (cap->oap->op_type == OP_NOP)
+ } else {
+ if (cap->oap->op_type == OP_NOP) {
beginline(BL_WHITE | BL_FIX);
- if ((fdo_flags & FDO_BLOCK) && KeyTyped && cap->oap->op_type == OP_NOP)
+ }
+ if ((fdo_flags & FDO_BLOCK) && KeyTyped && cap->oap->op_type == OP_NOP) {
foldOpenCursor();
+ }
}
} else if (cap->nchar == 'p' || cap->nchar == 'P') {
// "[p", "[P", "]P" and "]p": put with indent adjustment
@@ -5747,12 +5927,14 @@ static void nv_brackets(cmdarg_T *cap)
for (n = cap->count1; n > 0; --n) {
prev_pos = *pos;
pos = getnextmark(pos, cap->cmdchar == '[' ? BACKWARD : FORWARD,
- cap->nchar == '\'');
- if (pos == NULL)
+ cap->nchar == '\'');
+ if (pos == NULL) {
break;
+ }
}
- if (pos == NULL)
+ if (pos == NULL) {
pos = &prev_pos;
+ }
nv_cursormark(cap, cap->nchar == '\'', pos);
}
/*
@@ -5761,31 +5943,33 @@ static void nv_brackets(cmdarg_T *cap)
*/
else if (cap->nchar >= K_RIGHTRELEASE && cap->nchar <= K_LEFTMOUSE) {
(void)do_mouse(cap->oap, cap->nchar,
- (cap->cmdchar == ']') ? FORWARD : BACKWARD,
- cap->count1, PUT_FIXINDENT);
+ (cap->cmdchar == ']') ? FORWARD : BACKWARD,
+ cap->count1, PUT_FIXINDENT);
}
/*
* "[z" and "]z": move to start or end of open fold.
*/
else if (cap->nchar == 'z') {
if (foldMoveTo(false, cap->cmdchar == ']' ? FORWARD : BACKWARD,
- cap->count1) == false)
+ cap->count1) == false) {
clearopbeep(cap->oap);
+ }
}
/*
* "[c" and "]c": move to next or previous diff-change.
*/
else if (cap->nchar == 'c') {
if (diff_move_to(cap->cmdchar == ']' ? FORWARD : BACKWARD,
- cap->count1) == false)
+ cap->count1) == false) {
clearopbeep(cap->oap);
+ }
}
/*
* "[s", "[S", "]s" and "]S": move to next spell error.
*/
else if (cap->nchar == 's' || cap->nchar == 'S') {
setpcmark();
- for (n = 0; n < cap->count1; ++n)
+ for (n = 0; n < cap->count1; ++n) {
if (spell_move_to(curwin, cap->cmdchar == ']' ? FORWARD : BACKWARD,
cap->nchar == 's', false, NULL) == 0) {
clearopbeep(cap->oap);
@@ -5793,12 +5977,15 @@ static void nv_brackets(cmdarg_T *cap)
} else {
curwin->w_set_curswant = true;
}
- if (cap->oap->op_type == OP_NOP && (fdo_flags & FDO_SEARCH) && KeyTyped)
+ }
+ if (cap->oap->op_type == OP_NOP && (fdo_flags & FDO_SEARCH) && KeyTyped) {
foldOpenCursor();
+ }
}
- /* Not a valid cap->nchar. */
- else
+ // Not a valid cap->nchar.
+ else {
clearopbeep(cap->oap);
+ }
}
/*
@@ -5806,7 +5993,7 @@ static void nv_brackets(cmdarg_T *cap)
*/
static void nv_percent(cmdarg_T *cap)
{
- pos_T *pos;
+ pos_T *pos;
linenr_T lnum = curwin->w_cursor.lnum;
cap->oap->inclusive = true;
@@ -5838,9 +6025,9 @@ static void nv_percent(cmdarg_T *cap)
} else { // "%" : go to matching paren
cap->oap->motion_type = kMTCharWise;
cap->oap->use_reg_one = true;
- if ((pos = findmatch(cap->oap, NUL)) == NULL)
+ if ((pos = findmatch(cap->oap, NUL)) == NULL) {
clearopbeep(cap->oap);
- else {
+ } else {
setpcmark();
curwin->w_cursor = *pos;
curwin->w_set_curswant = true;
@@ -5851,8 +6038,9 @@ static void nv_percent(cmdarg_T *cap)
if (cap->oap->op_type == OP_NOP
&& lnum != curwin->w_cursor.lnum
&& (fdo_flags & FDO_PERCENT)
- && KeyTyped)
+ && KeyTyped) {
foldOpenCursor();
+ }
}
/*
@@ -5863,18 +6051,19 @@ static void nv_brace(cmdarg_T *cap)
{
cap->oap->motion_type = kMTCharWise;
cap->oap->use_reg_one = true;
- /* The motion used to be inclusive for "(", but that is not what Vi does. */
+ // The motion used to be inclusive for "(", but that is not what Vi does.
cap->oap->inclusive = false;
curwin->w_set_curswant = true;
- if (findsent(cap->arg, cap->count1) == false)
+ if (findsent(cap->arg, cap->count1) == false) {
clearopbeep(cap->oap);
- else {
- /* Don't leave the cursor on the NUL past end of line. */
+ } else {
+ // Don't leave the cursor on the NUL past end of line.
adjust_cursor(cap->oap);
curwin->w_cursor.coladd = 0;
- if ((fdo_flags & FDO_BLOCK) && KeyTyped && cap->oap->op_type == OP_NOP)
+ if ((fdo_flags & FDO_BLOCK) && KeyTyped && cap->oap->op_type == OP_NOP) {
foldOpenCursor();
+ }
}
}
@@ -5884,8 +6073,9 @@ static void nv_brace(cmdarg_T *cap)
static void nv_mark(cmdarg_T *cap)
{
if (!checkclearop(cap->oap)) {
- if (setmark(cap->nchar) == false)
+ if (setmark(cap->nchar) == false) {
clearopbeep(cap->oap);
+ }
}
}
@@ -5899,12 +6089,13 @@ static void nv_findpar(cmdarg_T *cap)
cap->oap->inclusive = false;
cap->oap->use_reg_one = true;
curwin->w_set_curswant = true;
- if (!findpar(&cap->oap->inclusive, cap->arg, cap->count1, NUL, false))
+ if (!findpar(&cap->oap->inclusive, cap->arg, cap->count1, NUL, false)) {
clearopbeep(cap->oap);
- else {
+ } else {
curwin->w_cursor.coladd = 0;
- if ((fdo_flags & FDO_BLOCK) && KeyTyped && cap->oap->op_type == OP_NOP)
+ if ((fdo_flags & FDO_BLOCK) && KeyTyped && cap->oap->op_type == OP_NOP) {
foldOpenCursor();
+ }
}
}
@@ -5914,14 +6105,14 @@ static void nv_findpar(cmdarg_T *cap)
static void nv_undo(cmdarg_T *cap)
{
if (cap->oap->op_type == OP_LOWER
- || VIsual_active
- ) {
- /* translate "<Visual>u" to "<Visual>gu" and "guu" to "gugu" */
+ || VIsual_active) {
+ // translate "<Visual>u" to "<Visual>gu" and "guu" to "gugu"
cap->cmdchar = 'g';
cap->nchar = 'u';
nv_operator(cap);
- } else
+ } else {
nv_kundo(cap);
+ }
}
/*
@@ -5944,7 +6135,7 @@ static void nv_kundo(cmdarg_T *cap)
*/
static void nv_replace(cmdarg_T *cap)
{
- char_u *ptr;
+ char_u *ptr;
int had_ctrl_v;
if (checkclearop(cap->oap)) {
@@ -5955,26 +6146,29 @@ static void nv_replace(cmdarg_T *cap)
return;
}
- /* get another character */
+ // get another character
if (cap->nchar == Ctrl_V) {
had_ctrl_v = Ctrl_V;
cap->nchar = get_literal();
- /* Don't redo a multibyte character with CTRL-V. */
- if (cap->nchar > DEL)
+ // Don't redo a multibyte character with CTRL-V.
+ if (cap->nchar > DEL) {
had_ctrl_v = NUL;
- } else
+ }
+ } else {
had_ctrl_v = NUL;
+ }
- /* Abort if the character is a special key. */
+ // Abort if the character is a special key.
if (IS_SPECIAL(cap->nchar)) {
clearopbeep(cap->oap);
return;
}
- /* Visual mode "r" */
+ // Visual mode "r"
if (VIsual_active) {
- if (got_int)
+ if (got_int) {
reset_VIsual();
+ }
if (had_ctrl_v) {
// Use a special (negative) number to make a difference between a
// literal CR or NL and a line break.
@@ -5988,24 +6182,25 @@ static void nv_replace(cmdarg_T *cap)
return;
}
- /* Break tabs, etc. */
+ // Break tabs, etc.
if (virtual_active()) {
- if (u_save_cursor() == false)
+ if (u_save_cursor() == false) {
return;
+ }
if (gchar_cursor() == NUL) {
- /* Add extra space and put the cursor on the first one. */
+ // Add extra space and put the cursor on the first one.
coladvance_force((colnr_T)(getviscol() + cap->count1));
assert(cap->count1 <= INT_MAX);
curwin->w_cursor.col -= (colnr_T)cap->count1;
- } else if (gchar_cursor() == TAB)
+ } else if (gchar_cursor() == TAB) {
coladvance_force(getviscol());
+ }
}
- /* Abort if not enough characters to replace. */
+ // Abort if not enough characters to replace.
ptr = get_cursor_pos_ptr();
if (STRLEN(ptr) < (unsigned)cap->count1
- || (mb_charlen(ptr) < cap->count1)
- ) {
+ || (mb_charlen(ptr) < cap->count1)) {
clearopbeep(cap->oap);
return;
}
@@ -6022,9 +6217,10 @@ static void nv_replace(cmdarg_T *cap)
return;
}
- /* save line for undo */
- if (u_save_cursor() == false)
+ // save line for undo
+ if (u_save_cursor() == false) {
return;
+ }
if (had_ctrl_v != Ctrl_V && (cap->nchar == '\r' || cap->nchar == '\n')) {
/*
@@ -6032,18 +6228,18 @@ static void nv_replace(cmdarg_T *cap)
* Strange vi behaviour: Only one newline is inserted.
* Delete the characters here.
* Insert the newline with an insert command, takes care of
- * autoindent. The insert command depends on being on the last
+ * autoindent. The insert command depends on being on the last
* character of a line or not.
*/
- (void)del_chars(cap->count1, false); /* delete the characters */
+ (void)del_chars(cap->count1, false); // delete the characters
stuffcharReadbuff('\r');
stuffcharReadbuff(ESC);
- /* Give 'r' to edit(), to get the redo command right. */
+ // Give 'r' to edit(), to get the redo command right.
invoke_edit(cap, true, 'r', false);
} else {
prep_redo(cap->oap->regname, cap->count1,
- NUL, 'r', NUL, had_ctrl_v, cap->nchar);
+ NUL, 'r', NUL, had_ctrl_v, cap->nchar);
curbuf->b_op_start = curwin->w_cursor;
const int old_State = State;
@@ -6080,7 +6276,7 @@ static void nv_replace(cmdarg_T *cap)
ins_char(cap->ncharC2);
}
}
- --curwin->w_cursor.col; /* cursor on the last replaced char */
+ --curwin->w_cursor.col; // cursor on the last replaced char
/* if the character on the left of the current cursor is a multi-byte
* character, move two characters left */
mb_adjust_cursor();
@@ -6112,16 +6308,18 @@ static void v_swap_corners(int cmdchar)
curwin->w_curswant = right;
/* 'selection "exclusive" and cursor at right-bottom corner: move it
* right one column */
- if (old_cursor.lnum >= VIsual.lnum && *p_sel == 'e')
+ if (old_cursor.lnum >= VIsual.lnum && *p_sel == 'e') {
++curwin->w_curswant;
+ }
coladvance(curwin->w_curswant);
if (curwin->w_cursor.col == old_cursor.col
&& (!virtual_active()
- || curwin->w_cursor.coladd == old_cursor.coladd)
- ) {
+ || curwin->w_cursor.coladd ==
+ old_cursor.coladd)) {
curwin->w_cursor.lnum = VIsual.lnum;
- if (old_cursor.lnum <= VIsual.lnum && *p_sel == 'e')
+ if (old_cursor.lnum <= VIsual.lnum && *p_sel == 'e') {
++right;
+ }
coladvance(right);
VIsual = curwin->w_cursor;
@@ -6142,18 +6340,19 @@ static void v_swap_corners(int cmdchar)
*/
static void nv_Replace(cmdarg_T *cap)
{
- if (VIsual_active) { /* "R" is replace lines */
+ if (VIsual_active) { // "R" is replace lines
cap->cmdchar = 'c';
cap->nchar = NUL;
- VIsual_mode_orig = VIsual_mode; /* remember original area for gv */
+ VIsual_mode_orig = VIsual_mode; // remember original area for gv
VIsual_mode = 'V';
nv_operator(cap);
} else if (!checkclearopq(cap->oap)) {
if (!MODIFIABLE(curbuf)) {
EMSG(_(e_modifiable));
} else {
- if (virtual_active())
+ if (virtual_active()) {
coladvance(getviscol());
+ }
invoke_edit(cap, false, cap->arg ? 'V' : 'R', false);
}
}
@@ -6167,17 +6366,19 @@ static void nv_vreplace(cmdarg_T *cap)
if (VIsual_active) {
cap->cmdchar = 'r';
cap->nchar = cap->extra_char;
- nv_replace(cap); /* Do same as "r" in Visual mode for now */
+ nv_replace(cap); // Do same as "r" in Visual mode for now
} else if (!checkclearopq(cap->oap)) {
if (!MODIFIABLE(curbuf)) {
EMSG(_(e_modifiable));
} else {
- if (cap->extra_char == Ctrl_V) /* get another character */
+ if (cap->extra_char == Ctrl_V) { // get another character
cap->extra_char = get_literal();
+ }
stuffcharReadbuff(cap->extra_char);
stuffcharReadbuff(ESC);
- if (virtual_active())
+ if (virtual_active()) {
coladvance(getviscol());
+ }
invoke_edit(cap, true, 'v', false);
}
}
@@ -6203,8 +6404,9 @@ static void n_swapchar(cmdarg_T *cap)
prep_redo_cmd(cap);
- if (u_save_cursor() == false)
+ if (u_save_cursor() == false) {
return;
+ }
startpos = curwin->w_cursor;
for (n = cap->count1; n > 0; --n) {
@@ -6216,12 +6418,14 @@ static void n_swapchar(cmdarg_T *cap)
++curwin->w_cursor.lnum;
curwin->w_cursor.col = 0;
if (n > 1) {
- if (u_savesub(curwin->w_cursor.lnum) == false)
+ if (u_savesub(curwin->w_cursor.lnum) == false) {
break;
+ }
u_clearline();
}
- } else
+ } else {
break;
+ }
}
}
@@ -6233,8 +6437,9 @@ static void n_swapchar(cmdarg_T *cap)
0L, true);
curbuf->b_op_start = startpos;
curbuf->b_op_end = curwin->w_cursor;
- if (curbuf->b_op_end.col > 0)
+ if (curbuf->b_op_end.col > 0) {
--curbuf->b_op_end.col;
+ }
}
}
@@ -6243,19 +6448,21 @@ static void n_swapchar(cmdarg_T *cap)
*/
static void nv_cursormark(cmdarg_T *cap, int flag, pos_T *pos)
{
- if (check_mark(pos) == false)
+ if (check_mark(pos) == false) {
clearop(cap->oap);
- else {
+ } else {
if (cap->cmdchar == '\''
|| cap->cmdchar == '`'
|| cap->cmdchar == '['
- || cap->cmdchar == ']')
+ || cap->cmdchar == ']') {
setpcmark();
+ }
curwin->w_cursor = *pos;
- if (flag)
+ if (flag) {
beginline(BL_WHITE | BL_FIX);
- else
+ } else {
check_cursor();
+ }
}
cap->oap->motion_type = flag ? kMTLineWise : kMTCharWise;
if (cap->cmdchar == '`') {
@@ -6278,8 +6485,9 @@ static void v_visop(cmdarg_T *cap)
if (VIsual_mode != Ctrl_V) {
VIsual_mode_orig = VIsual_mode;
VIsual_mode = 'V';
- } else if (cap->cmdchar == 'C' || cap->cmdchar == 'D')
+ } else if (cap->cmdchar == 'C' || cap->cmdchar == 'D') {
curwin->w_curswant = MAXCOL;
+ }
}
cap->cmdchar = *(vim_strchr(trans, cap->cmdchar) + 1);
nv_operator(cap);
@@ -6301,8 +6509,9 @@ static void nv_subst(cmdarg_T *cap)
}
cap->cmdchar = 'c';
nv_operator(cap);
- } else
+ } else {
nv_optrans(cap);
+ }
}
/*
@@ -6310,14 +6519,15 @@ static void nv_subst(cmdarg_T *cap)
*/
static void nv_abbrev(cmdarg_T *cap)
{
- if (cap->cmdchar == K_DEL || cap->cmdchar == K_KDEL)
- cap->cmdchar = 'x'; /* DEL key behaves like 'x' */
-
- /* in Visual mode these commands are operators */
- if (VIsual_active)
+ if (cap->cmdchar == K_DEL || cap->cmdchar == K_KDEL) {
+ cap->cmdchar = 'x'; // DEL key behaves like 'x'
+ }
+ // in Visual mode these commands are operators
+ if (VIsual_active) {
v_visop(cap);
- else
+ } else {
nv_optrans(cap);
+ }
}
/*
@@ -6344,24 +6554,27 @@ static void nv_optrans(cmdarg_T *cap)
*/
static void nv_gomark(cmdarg_T *cap)
{
- pos_T *pos;
+ pos_T *pos;
int c;
pos_T old_cursor = curwin->w_cursor;
const bool old_KeyTyped = KeyTyped; // getting file may reset it
- if (cap->cmdchar == 'g')
+ if (cap->cmdchar == 'g') {
c = cap->extra_char;
- else
+ } else {
c = cap->nchar;
+ }
pos = getmark(c, (cap->oap->op_type == OP_NOP));
- if (pos == (pos_T *)-1) { /* jumped to other file */
+ if (pos == (pos_T *)-1) { // jumped to other file
if (cap->arg) {
check_cursor_lnum();
beginline(BL_WHITE | BL_FIX);
- } else
+ } else {
check_cursor();
- } else
+ }
+ } else {
nv_cursormark(cap, cap->arg, pos);
+ }
// May need to clear the coladd that a mark includes.
if (!virtual_active()) {
@@ -6380,7 +6593,7 @@ static void nv_gomark(cmdarg_T *cap)
// Handle CTRL-O, CTRL-I, "g;", "g,", and "CTRL-Tab" commands.
static void nv_pcmark(cmdarg_T *cap)
{
- pos_T *pos;
+ pos_T *pos;
linenr_T lnum = curwin->w_cursor.lnum;
const bool old_KeyTyped = KeyTyped; // getting file may reset it
@@ -6397,22 +6610,25 @@ static void nv_pcmark(cmdarg_T *cap)
if (pos == (pos_T *)-1) { // jump to other file
curwin->w_set_curswant = true;
check_cursor();
- } else if (pos != NULL) /* can jump */
+ } else if (pos != NULL) { // can jump
nv_cursormark(cap, false, pos);
- else if (cap->cmdchar == 'g') {
- if (curbuf->b_changelistlen == 0)
+ } else if (cap->cmdchar == 'g') {
+ if (curbuf->b_changelistlen == 0) {
EMSG(_("E664: changelist is empty"));
- else if (cap->count1 < 0)
+ } else if (cap->count1 < 0) {
EMSG(_("E662: At start of changelist"));
- else
+ } else {
EMSG(_("E663: At end of changelist"));
- } else
+ }
+ } else {
clearopbeep(cap->oap);
+ }
if (cap->oap->op_type == OP_NOP
&& (pos == (pos_T *)-1 || lnum != curwin->w_cursor.lnum)
&& (fdo_flags & FDO_MARK)
- && old_KeyTyped)
+ && old_KeyTyped) {
foldOpenCursor();
+ }
}
}
@@ -6421,16 +6637,19 @@ static void nv_pcmark(cmdarg_T *cap)
*/
static void nv_regname(cmdarg_T *cap)
{
- if (checkclearop(cap->oap))
+ if (checkclearop(cap->oap)) {
return;
- if (cap->nchar == '=')
+ }
+ if (cap->nchar == '=') {
cap->nchar = get_expr_register();
+ }
if (cap->nchar != NUL && valid_yank_reg(cap->nchar, false)) {
cap->oap->regname = cap->nchar;
- cap->opcount = cap->count0; /* remember count before '"' */
+ cap->opcount = cap->count0; // remember count before '"'
set_reg_var(cap->oap->regname);
- } else
+ } else {
clearopbeep(cap->oap);
+ }
}
/*
@@ -6441,8 +6660,9 @@ static void nv_regname(cmdarg_T *cap)
*/
static void nv_visual(cmdarg_T *cap)
{
- if (cap->cmdchar == Ctrl_Q)
+ if (cap->cmdchar == Ctrl_Q) {
cap->cmdchar = Ctrl_V;
+ }
// 'v', 'V' and CTRL-V can be used while an operator is pending to make it
// charwise, linewise, or blockwise.
@@ -6453,28 +6673,30 @@ static void nv_visual(cmdarg_T *cap)
}
VIsual_select = cap->arg;
- if (VIsual_active) { /* change Visual mode */
- if (VIsual_mode == cap->cmdchar) /* stop visual mode */
+ if (VIsual_active) { // change Visual mode
+ if (VIsual_mode == cap->cmdchar) { // stop visual mode
end_visual_mode();
- else { /* toggle char/block mode */
- /* or char/line mode */
+ } else { // toggle char/block mode
+ // or char/line mode
VIsual_mode = cap->cmdchar;
showmode();
}
redraw_curbuf_later(INVERTED); // update the inversion
} else { // start Visual mode
if (cap->count0 > 0 && resel_VIsual_mode != NUL) {
- /* use previously selected part */
+ // use previously selected part
VIsual = curwin->w_cursor;
VIsual_active = true;
VIsual_reselect = true;
- if (!cap->arg)
- /* start Select mode when 'selectmode' contains "cmd" */
+ if (!cap->arg) {
+ // start Select mode when 'selectmode' contains "cmd"
may_start_select('c');
+ }
setmouse();
- if (p_smd && msg_silent == 0)
- redraw_cmdline = true; /* show visual mode later */
+ if (p_smd && msg_silent == 0) {
+ redraw_cmdline = true; // show visual mode later
+ }
/*
* For V and ^V, we multiply the number of lines even if there
* was only one -- webb
@@ -6482,8 +6704,9 @@ static void nv_visual(cmdarg_T *cap)
if (resel_VIsual_mode != 'v' || resel_VIsual_line_count > 1) {
curwin->w_cursor.lnum +=
resel_VIsual_line_count * cap->count0 - 1;
- if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
+ if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) {
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
+ }
}
VIsual_mode = resel_VIsual_mode;
if (VIsual_mode == 'v') {
@@ -6492,8 +6715,9 @@ static void nv_visual(cmdarg_T *cap)
assert(cap->count0 >= INT_MIN && cap->count0 <= INT_MAX);
curwin->w_curswant = (curwin->w_virtcol
+ resel_VIsual_vcol * (int)cap->count0 - 1);
- } else
+ } else {
curwin->w_curswant = resel_VIsual_vcol;
+ }
coladvance(curwin->w_curswant);
}
if (resel_VIsual_vcol == MAXCOL) {
@@ -6505,22 +6729,26 @@ static void nv_visual(cmdarg_T *cap)
curwin->w_curswant = (curwin->w_virtcol
+ resel_VIsual_vcol * (int)cap->count0 - 1);
coladvance(curwin->w_curswant);
- } else
+ } else {
curwin->w_set_curswant = true;
- redraw_curbuf_later(INVERTED); /* show the inversion */
+ }
+ redraw_curbuf_later(INVERTED); // show the inversion
} else {
- if (!cap->arg)
- /* start Select mode when 'selectmode' contains "cmd" */
+ if (!cap->arg) {
+ // start Select mode when 'selectmode' contains "cmd"
may_start_select('c');
+ }
n_start_visual_mode(cap->cmdchar);
- if (VIsual_mode != 'V' && *p_sel == 'e')
- ++cap->count1; /* include one more char */
+ if (VIsual_mode != 'V' && *p_sel == 'e') {
+ ++cap->count1; // include one more char
+ }
if (cap->count0 > 0 && --cap->count1 > 0) {
- /* With a count select that many characters or lines. */
- if (VIsual_mode == 'v' || VIsual_mode == Ctrl_V)
+ // With a count select that many characters or lines.
+ if (VIsual_mode == 'v' || VIsual_mode == Ctrl_V) {
nv_right(cap);
- else if (VIsual_mode == 'V')
+ } else if (VIsual_mode == 'V') {
nv_down(cap);
+ }
}
}
}
@@ -6531,7 +6759,7 @@ static void nv_visual(cmdarg_T *cap)
*/
void start_selection(void)
{
- /* if 'selectmode' contains "key", start Select mode */
+ // if 'selectmode' contains "key", start Select mode
may_start_select('k');
n_start_visual_mode('v');
}
@@ -6554,9 +6782,9 @@ static void n_start_visual_mode(int c)
VIsual_mode = c;
VIsual_active = true;
VIsual_reselect = true;
- /* Corner case: the 0 position in a tab may change when going into
- * virtualedit. Recalculate curwin->w_cursor to avoid bad hilighting.
- */
+ // Corner case: the 0 position in a tab may change when going into
+ // virtualedit. Recalculate curwin->w_cursor to avoid bad highlighting.
+ //
if (c == Ctrl_V && (ve_flags & VE_BLOCK) && gchar_cursor() == TAB) {
validate_virtcol();
coladvance(curwin->w_virtcol);
@@ -6569,9 +6797,9 @@ static void n_start_visual_mode(int c)
// Check for redraw after changing the state.
conceal_check_cursor_line();
- if (p_smd && msg_silent == 0)
- redraw_cmdline = true; /* show visual mode later */
-
+ if (p_smd && msg_silent == 0) {
+ redraw_cmdline = true; // show visual mode later
+ }
/* Only need to redraw this line, unless still need to redraw an old
* Visual area (when 'lazyredraw' is set). */
if (curwin->w_redr_type < INVERTED) {
@@ -6602,8 +6830,9 @@ static void nv_window(cmdarg_T *cap)
static void nv_suspend(cmdarg_T *cap)
{
clearop(cap->oap);
- if (VIsual_active)
- end_visual_mode(); /* stop Visual mode */
+ if (VIsual_active) {
+ end_visual_mode(); // stop Visual mode
+ }
do_cmdline_cmd("st");
}
@@ -6612,7 +6841,7 @@ static void nv_suspend(cmdarg_T *cap)
*/
static void nv_g_cmd(cmdarg_T *cap)
{
- oparg_T *oap = cap->oap;
+ oparg_T *oap = cap->oap;
pos_T tpos;
int i;
bool flag = false;
@@ -6647,18 +6876,19 @@ static void nv_g_cmd(cmdarg_T *cap)
/*
* "gv": Reselect the previous Visual area. If Visual already active,
- * exchange previous and current Visual area.
+ * exchange previous and current Visual area.
*/
case 'v':
- if (checkclearop(oap))
+ if (checkclearop(oap)) {
break;
+ }
- if ( curbuf->b_visual.vi_start.lnum == 0
- || curbuf->b_visual.vi_start.lnum > curbuf->b_ml.ml_line_count
- || curbuf->b_visual.vi_end.lnum == 0)
+ if (curbuf->b_visual.vi_start.lnum == 0
+ || curbuf->b_visual.vi_start.lnum > curbuf->b_ml.ml_line_count
+ || curbuf->b_visual.vi_end.lnum == 0) {
beep_flush();
- else {
- /* set w_cursor to the start of the Visual area, tpos to the end */
+ } else {
+ // set w_cursor to the start of the Visual area, tpos to the end
if (VIsual_active) {
i = VIsual_mode;
VIsual_mode = curbuf->b_visual.vi_mode;
@@ -6704,7 +6934,7 @@ static void nv_g_cmd(cmdarg_T *cap)
break;
/*
* "gV": Don't reselect the previous Visual area after a Select mode
- * mapping of menu.
+ * mapping of menu.
*/
case 'V':
VIsual_reselect = false;
@@ -6732,8 +6962,9 @@ static void nv_g_cmd(cmdarg_T *cap)
*/
case 'N':
case 'n':
- if (!current_search(cap->count1, cap->nchar == 'n'))
+ if (!current_search(cap->count1, cap->nchar == 'n')) {
clearopbeep(oap);
+ }
break;
/*
@@ -6746,10 +6977,12 @@ static void nv_g_cmd(cmdarg_T *cap)
if (!curwin->w_p_wrap) {
oap->motion_type = kMTLineWise;
i = cursor_down(cap->count1, oap->op_type == OP_NOP);
- } else
+ } else {
i = nv_screengo(oap, FORWARD, cap->count1);
- if (!i)
+ }
+ if (!i) {
clearopbeep(oap);
+ }
break;
case 'k':
@@ -6758,10 +6991,12 @@ static void nv_g_cmd(cmdarg_T *cap)
if (!curwin->w_p_wrap) {
oap->motion_type = kMTLineWise;
i = cursor_up(cap->count1, oap->op_type == OP_NOP);
- } else
+ } else {
i = nv_screengo(oap, BACKWARD, cap->count1);
- if (!i)
+ }
+ if (!i) {
clearopbeep(oap);
+ }
break;
/*
@@ -6786,17 +7021,18 @@ static void nv_g_cmd(cmdarg_T *cap)
oap->motion_type = kMTCharWise;
oap->inclusive = false;
if (curwin->w_p_wrap
- && curwin->w_width_inner != 0
- ) {
+ && curwin->w_width_inner != 0) {
int width1 = curwin->w_width_inner - curwin_col_off();
int width2 = width1 + curwin_col_off2();
validate_virtcol();
i = 0;
- if (curwin->w_virtcol >= (colnr_T)width1 && width2 > 0)
+ if (curwin->w_virtcol >= (colnr_T)width1 && width2 > 0) {
i = (curwin->w_virtcol - width1) / width2 * width2 + width1;
- } else
+ }
+ } else {
i = curwin->w_leftcol;
+ }
/* Go to the middle of the screen line. When 'number' or
* 'relativenumber' is on and lines are wrapping the middle can be more
* to the left. */
@@ -6815,21 +7051,20 @@ static void nv_g_cmd(cmdarg_T *cap)
curwin->w_set_curswant = true;
break;
- case 'M':
- {
- const char_u *const ptr = get_cursor_line_ptr();
+ case 'M': {
+ const char_u *const ptr = get_cursor_line_ptr();
- oap->motion_type = kMTCharWise;
- oap->inclusive = false;
- i = (int)mb_string2cells_len(ptr, STRLEN(ptr));
- if (cap->count0 > 0 && cap->count0 <= 100) {
- coladvance((colnr_T)(i * cap->count0 / 100));
- } else {
- coladvance((colnr_T)(i / 2));
- }
- curwin->w_set_curswant = true;
+ oap->motion_type = kMTCharWise;
+ oap->inclusive = false;
+ i = (int)mb_string2cells_len(ptr, STRLEN(ptr));
+ if (cap->count0 > 0 && cap->count0 <= 100) {
+ coladvance((colnr_T)(i * cap->count0 / 100));
+ } else {
+ coladvance((colnr_T)(i / 2));
}
- break;
+ curwin->w_set_curswant = true;
+ }
+ break;
case '_':
/* "g_": to the last non-blank character in the line or <count> lines
@@ -6838,19 +7073,21 @@ static void nv_g_cmd(cmdarg_T *cap)
cap->oap->inclusive = true;
curwin->w_curswant = MAXCOL;
if (cursor_down(cap->count1 - 1,
- cap->oap->op_type == OP_NOP) == false)
+ cap->oap->op_type == OP_NOP) == false) {
clearopbeep(cap->oap);
- else {
- char_u *ptr = get_cursor_line_ptr();
+ } else {
+ char_u *ptr = get_cursor_line_ptr();
- /* In Visual mode we may end up after the line. */
- if (curwin->w_cursor.col > 0 && ptr[curwin->w_cursor.col] == NUL)
+ // In Visual mode we may end up after the line.
+ if (curwin->w_cursor.col > 0 && ptr[curwin->w_cursor.col] == NUL) {
--curwin->w_cursor.col;
+ }
- /* Decrease the cursor column until it's on a non-blank. */
+ // Decrease the cursor column until it's on a non-blank.
while (curwin->w_cursor.col > 0
- && ascii_iswhite(ptr[curwin->w_cursor.col]))
+ && ascii_iswhite(ptr[curwin->w_cursor.col])) {
--curwin->w_cursor.col;
+ }
curwin->w_set_curswant = true;
adjust_for_sel(cap);
}
@@ -6858,28 +7095,27 @@ static void nv_g_cmd(cmdarg_T *cap)
case '$':
case K_END:
- case K_KEND:
- {
+ case K_KEND: {
int col_off = curwin_col_off();
oap->motion_type = kMTCharWise;
oap->inclusive = true;
if (curwin->w_p_wrap
- && curwin->w_width_inner != 0
- ) {
- curwin->w_curswant = MAXCOL; /* so we stay at the end */
+ && curwin->w_width_inner != 0) {
+ curwin->w_curswant = MAXCOL; // so we stay at the end
if (cap->count1 == 1) {
int width1 = curwin->w_width_inner - col_off;
int width2 = width1 + curwin_col_off2();
validate_virtcol();
i = width1 - 1;
- if (curwin->w_virtcol >= (colnr_T)width1)
+ if (curwin->w_virtcol >= (colnr_T)width1) {
i += ((curwin->w_virtcol - width1) / width2 + 1)
* width2;
+ }
coladvance((colnr_T)i);
- /* Make sure we stick in this column. */
+ // Make sure we stick in this column.
validate_virtcol();
curwin->w_curswant = curwin->w_virtcol;
curwin->w_set_curswant = false;
@@ -6889,11 +7125,13 @@ static void nv_g_cmd(cmdarg_T *cap)
* the end of the line. We do not want to advance to
* the next screen line.
*/
- if (curwin->w_virtcol > (colnr_T)i)
+ if (curwin->w_virtcol > (colnr_T)i) {
--curwin->w_cursor.col;
+ }
}
- } else if (nv_screengo(oap, FORWARD, cap->count1 - 1) == false)
+ } else if (nv_screengo(oap, FORWARD, cap->count1 - 1) == false) {
clearopbeep(oap);
+ }
} else {
if (cap->count1 > 1) {
// if it fails, let the cursor still move to the last char
@@ -6916,10 +7154,10 @@ static void nv_g_cmd(cmdarg_T *cap)
case '*':
case '#':
#if POUND != '#'
- case POUND: /* pound sign (sometimes equal to '#') */
+ case POUND: // pound sign (sometimes equal to '#')
#endif
- case Ctrl_RSB: /* :tag or :tselect for current identifier */
- case ']': /* :tselect for current identifier */
+ case Ctrl_RSB: // :tag or :tselect for current identifier
+ case ']': // :tselect for current identifier
nv_ident(cap);
break;
@@ -6931,8 +7169,9 @@ static void nv_g_cmd(cmdarg_T *cap)
oap->motion_type = kMTCharWise;
curwin->w_set_curswant = true;
oap->inclusive = true;
- if (bckend_word(cap->count1, cap->nchar == 'E', false) == false)
+ if (bckend_word(cap->count1, cap->nchar == 'E', false) == false) {
clearopbeep(oap);
+ }
break;
// "g CTRL-G": display info about cursor position
@@ -6947,8 +7186,9 @@ static void nv_g_cmd(cmdarg_T *cap)
check_cursor_lnum();
i = (int)STRLEN(get_cursor_line_ptr());
if (curwin->w_cursor.col > (colnr_T)i) {
- if (virtual_active())
+ if (virtual_active()) {
curwin->w_cursor.coladd += curwin->w_cursor.col - i;
+ }
curwin->w_cursor.col = i;
}
}
@@ -6961,8 +7201,9 @@ static void nv_g_cmd(cmdarg_T *cap)
*/
case 'I':
beginline(0);
- if (!checkclearopq(oap))
+ if (!checkclearopq(oap)) {
invoke_edit(cap, false, 'g', false);
+ }
break;
/*
@@ -6974,7 +7215,7 @@ static void nv_g_cmd(cmdarg_T *cap)
nv_gotofile(cap);
break;
- /* "g'm" and "g`m": jump to mark without setting pcmark */
+ // "g'm" and "g`m": jump to mark without setting pcmark
case '\'':
cap->arg = true;
FALLTHROUGH;
@@ -6991,7 +7232,7 @@ static void nv_g_cmd(cmdarg_T *cap)
/*
* "ga": Display the ascii value of the character under the
- * cursor. It is displayed in decimal, hex, and octal. -- webb
+ * cursor. It is displayed in decimal, hex, and octal. -- webb
*/
case 'a':
do_ascii(NULL);
@@ -6999,14 +7240,15 @@ static void nv_g_cmd(cmdarg_T *cap)
/*
* "g8": Display the bytes used for the UTF-8 character under the
- * cursor. It is displayed in hex.
+ * cursor. It is displayed in hex.
* "8g8" finds illegal byte sequence.
*/
case '8':
- if (cap->count0 == 8)
+ if (cap->count0 == 8) {
utf_find_illegal();
- else
+ } else {
show_utf8();
+ }
break;
// "g<": show scrollback text
case '<':
@@ -7023,14 +7265,14 @@ static void nv_g_cmd(cmdarg_T *cap)
break;
/*
- * Two-character operators:
- * "gq" Format text
- * "gw" Format text and keep cursor position
- * "g~" Toggle the case of the text.
- * "gu" Change text to lower case.
- * "gU" Change text to upper case.
- * "g?" rot13 encoding
- * "g@" call 'operatorfunc'
+ * Two-character operators:
+ * "gq" Format text
+ * "gw" Format text and keep cursor position
+ * "g~" Toggle the case of the text.
+ * "gu" Change text to lower case.
+ * "gU" Change text to upper case.
+ * "g?" rot13 encoding
+ * "g@" call 'operatorfunc'
*/
case 'q':
case 'w':
@@ -7046,7 +7288,7 @@ static void nv_g_cmd(cmdarg_T *cap)
/*
* "gd": Find first occurrence of pattern under the cursor in the
- * current function
+ * current function
* "gD": idem, but in the current file.
*/
case 'd':
@@ -7088,12 +7330,12 @@ static void nv_g_cmd(cmdarg_T *cap)
nv_put(cap);
break;
- /* "go": goto byte count from start of buffer */
+ // "go": goto byte count from start of buffer
case 'o':
goto_byte(cap->count0);
break;
- /* "gQ": improved Ex mode */
+ // "gQ": improved Ex mode
case 'Q':
if (text_locked()) {
clearopbeep(cap->oap);
@@ -7101,8 +7343,9 @@ static void nv_g_cmd(cmdarg_T *cap)
break;
}
- if (!checkclearopq(oap))
- do_exmode(true);
+ if (!checkclearopq(oap)) {
+ do_exmode();
+ }
break;
case ',':
@@ -7115,12 +7358,14 @@ static void nv_g_cmd(cmdarg_T *cap)
break;
case 't':
- if (!checkclearop(oap))
+ if (!checkclearop(oap)) {
goto_tabpage((int)cap->count0);
+ }
break;
case 'T':
- if (!checkclearop(oap))
+ if (!checkclearop(oap)) {
goto_tabpage(-(int)cap->count1);
+ }
break;
case TAB:
if (!checkclearop(oap)) {
@@ -7129,10 +7374,11 @@ static void nv_g_cmd(cmdarg_T *cap)
break;
case '+':
- case '-': /* "g+" and "g-": undo or redo along the timeline */
- if (!checkclearopq(oap))
+ case '-': // "g+" and "g-": undo or redo along the timeline
+ if (!checkclearopq(oap)) {
undo_time(cap->nchar == '-' ? -cap->count1 : cap->count1,
- false, false, false);
+ false, false, false);
+ }
break;
default:
@@ -7147,19 +7393,20 @@ static void nv_g_cmd(cmdarg_T *cap)
static void n_opencmd(cmdarg_T *cap)
{
if (!checkclearopq(cap->oap)) {
- if (cap->cmdchar == 'O')
- /* Open above the first line of a folded sequence of lines */
+ if (cap->cmdchar == 'O') {
+ // Open above the first line of a folded sequence of lines
(void)hasFolding(curwin->w_cursor.lnum,
- &curwin->w_cursor.lnum, NULL);
- else
- /* Open below the last line of a folded sequence of lines */
+ &curwin->w_cursor.lnum, NULL);
+ } else {
+ // Open below the last line of a folded sequence of lines
(void)hasFolding(curwin->w_cursor.lnum,
- NULL, &curwin->w_cursor.lnum);
+ NULL, &curwin->w_cursor.lnum);
+ }
if (u_save((linenr_T)(curwin->w_cursor.lnum -
(cap->cmdchar == 'O' ? 1 : 0)),
- (linenr_T)(curwin->w_cursor.lnum +
- (cap->cmdchar == 'o' ? 1 : 0))
- )
+ (linenr_T)(curwin->w_cursor.lnum +
+ (cap->cmdchar == 'o' ? 1 : 0))
+ )
&& open_line(cap->cmdchar == 'O' ? BACKWARD : FORWARD,
has_format_option(FO_OPEN_COMS)
? OPENLINE_DO_COM : 0,
@@ -7184,8 +7431,9 @@ static void nv_dot(cmdarg_T *cap)
* instead of the last command (inserting text). This is used for
* CTRL-O <.> in insert mode.
*/
- if (start_redo(cap->count0, restart_edit != 0 && !arrow_used) == false)
+ if (start_redo(cap->count0, restart_edit != 0 && !arrow_used) == false) {
clearopbeep(cap->oap);
+ }
}
}
@@ -7205,11 +7453,10 @@ static void nv_redo(cmdarg_T *cap)
*/
static void nv_Undo(cmdarg_T *cap)
{
- /* In Visual mode and typing "gUU" triggers an operator */
+ // In Visual mode and typing "gUU" triggers an operator
if (cap->oap->op_type == OP_UPPER
- || VIsual_active
- ) {
- /* translate "gUU" to "gUgU" */
+ || VIsual_active) {
+ // translate "gUU" to "gUgU"
cap->cmdchar = 'g';
cap->nchar = 'U';
nv_operator(cap);
@@ -7254,9 +7501,9 @@ static void nv_operator(cmdarg_T *cap)
return;
}
- if (op_type == cap->oap->op_type) /* double operator works on lines */
+ if (op_type == cap->oap->op_type) { // double operator works on lines
nv_lineop(cap);
- else if (!checkclearop(cap->oap)) {
+ } else if (!checkclearop(cap->oap)) {
cap->oap->start = curwin->w_cursor;
cap->oap->op_type = op_type;
set_op_var(op_type);
@@ -7274,11 +7521,11 @@ static void set_op_var(int optype)
char opchars[3];
int opchar0 = get_op_char(optype);
assert(opchar0 >= 0 && opchar0 <= UCHAR_MAX);
- opchars[0] = (char) opchar0;
+ opchars[0] = (char)opchar0;
int opchar1 = get_extra_op_char(optype);
assert(opchar1 >= 0 && opchar1 <= UCHAR_MAX);
- opchars[1] = (char) opchar1;
+ opchars[1] = (char)opchar1;
opchars[2] = NUL;
set_vim_var_string(VV_OP, opchars, -1);
@@ -7316,10 +7563,10 @@ static void nv_lineop(cmdarg_T *cap)
*/
static void nv_home(cmdarg_T *cap)
{
- /* CTRL-HOME is like "gg" */
- if (mod_mask & MOD_MASK_CTRL)
+ // CTRL-HOME is like "gg"
+ if (mod_mask & MOD_MASK_CTRL) {
nv_goto(cap);
- else {
+ } else {
cap->count0 = 1;
nv_pipe(cap);
}
@@ -7338,8 +7585,9 @@ static void nv_pipe(cmdarg_T *cap)
if (cap->count0 > 0) {
coladvance((colnr_T)(cap->count0 - 1));
curwin->w_curswant = (colnr_T)(cap->count0 - 1);
- } else
+ } else {
curwin->w_curswant = 0;
+ }
/* keep curswant at the column where we wanted to go, not where
* we ended; differs if line is too short */
curwin->w_set_curswant = false;
@@ -7354,10 +7602,11 @@ static void nv_bck_word(cmdarg_T *cap)
cap->oap->motion_type = kMTCharWise;
cap->oap->inclusive = false;
curwin->w_set_curswant = true;
- if (bck_word(cap->count1, cap->arg, false) == false)
+ if (bck_word(cap->count1, cap->arg, false) == false) {
clearopbeep(cap->oap);
- else if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP)
+ } else if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP) {
foldOpenCursor();
+ }
}
/*
@@ -7374,10 +7623,11 @@ static void nv_wordcmd(cmdarg_T *cap)
/*
* Set inclusive for the "E" and "e" command.
*/
- if (cap->cmdchar == 'e' || cap->cmdchar == 'E')
+ if (cap->cmdchar == 'e' || cap->cmdchar == 'E') {
word_end = true;
- else
+ } else {
word_end = false;
+ }
cap->oap->inclusive = word_end;
/*
@@ -7404,22 +7654,25 @@ static void nv_wordcmd(cmdarg_T *cap)
cap->oap->motion_type = kMTCharWise;
curwin->w_set_curswant = true;
- if (word_end)
+ if (word_end) {
n = end_word(cap->count1, cap->arg, flag, false);
- else
+ } else {
n = fwd_word(cap->count1, cap->arg, cap->oap->op_type != OP_NOP);
+ }
/* Don't leave the cursor on the NUL past the end of line. Unless we
* didn't move it forward. */
- if (lt(startpos, curwin->w_cursor))
+ if (lt(startpos, curwin->w_cursor)) {
adjust_cursor(cap->oap);
+ }
- if (n == false && cap->oap->op_type == OP_NOP)
+ if (n == false && cap->oap->op_type == OP_NOP) {
clearopbeep(cap->oap);
- else {
+ } else {
adjust_for_sel(cap);
- if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP)
+ if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP) {
foldOpenCursor();
+ }
}
}
@@ -7437,8 +7690,8 @@ static void adjust_cursor(oparg_T *oap)
*/
if (curwin->w_cursor.col > 0 && gchar_cursor() == NUL
&& (!VIsual_active || *p_sel == 'o')
- && !virtual_active() && (ve_flags & VE_ONEMORE) == 0
- ) {
+ && !virtual_active() &&
+ (ve_flags & VE_ONEMORE) == 0) {
curwin->w_cursor.col--;
// prevent cursor from moving on the trail byte
mb_adjust_cursor();
@@ -7455,8 +7708,9 @@ static void nv_beginline(cmdarg_T *cap)
cap->oap->motion_type = kMTCharWise;
cap->oap->inclusive = false;
beginline(cap->arg);
- if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP)
+ if ((fdo_flags & FDO_HOR) && KeyTyped && cap->oap->op_type == OP_NOP) {
foldOpenCursor();
+ }
ins_at_eol = false; /* Don't move cursor past eol (only necessary in a
one-character line). */
}
@@ -7480,13 +7734,14 @@ static void adjust_for_sel(cmdarg_T *cap)
*/
static bool unadjust_for_sel(void)
{
- pos_T *pp;
+ pos_T *pp;
if (*p_sel == 'e' && !equalpos(VIsual, curwin->w_cursor)) {
- if (lt(VIsual, curwin->w_cursor))
+ if (lt(VIsual, curwin->w_cursor)) {
pp = &curwin->w_cursor;
- else
+ } else {
pp = &VIsual;
+ }
if (pp->coladd > 0) {
pp->coladd--;
} else if (pp->col > 0) {
@@ -7506,10 +7761,10 @@ static bool unadjust_for_sel(void)
*/
static void nv_select(cmdarg_T *cap)
{
- if (VIsual_active)
+ if (VIsual_active) {
VIsual_select = true;
- else if (VIsual_reselect) {
- cap->nchar = 'v'; /* fake "gv" command */
+ } else if (VIsual_reselect) {
+ cap->nchar = 'v'; // fake "gv" command
cap->arg = true;
nv_g_cmd(cap);
}
@@ -7524,24 +7779,28 @@ static void nv_goto(cmdarg_T *cap)
{
linenr_T lnum;
- if (cap->arg)
+ if (cap->arg) {
lnum = curbuf->b_ml.ml_line_count;
- else
+ } else {
lnum = 1L;
+ }
cap->oap->motion_type = kMTLineWise;
setpcmark();
- /* When a count is given, use it instead of the default lnum */
- if (cap->count0 != 0)
+ // When a count is given, use it instead of the default lnum
+ if (cap->count0 != 0) {
lnum = cap->count0;
- if (lnum < 1L)
+ }
+ if (lnum < 1L) {
lnum = 1L;
- else if (lnum > curbuf->b_ml.ml_line_count)
+ } else if (lnum > curbuf->b_ml.ml_line_count) {
lnum = curbuf->b_ml.ml_line_count;
+ }
curwin->w_cursor.lnum = lnum;
beginline(BL_SOL | BL_FIX);
- if ((fdo_flags & FDO_JUMP) && KeyTyped && cap->oap->op_type == OP_NOP)
+ if ((fdo_flags & FDO_JUMP) && KeyTyped && cap->oap->op_type == OP_NOP) {
foldOpenCursor();
+ }
}
/*
@@ -7551,20 +7810,24 @@ static void nv_normal(cmdarg_T *cap)
{
if (cap->nchar == Ctrl_N || cap->nchar == Ctrl_G) {
clearop(cap->oap);
- if (restart_edit != 0 && mode_displayed)
- clear_cmdline = true; /* unshow mode later */
+ if (restart_edit != 0 && mode_displayed) {
+ clear_cmdline = true; // unshow mode later
+ }
restart_edit = 0;
- if (cmdwin_type != 0)
+ if (cmdwin_type != 0) {
cmdwin_result = Ctrl_C;
+ }
if (VIsual_active) {
- end_visual_mode(); /* stop Visual */
+ 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)
+ // CTRL-\ CTRL-G restarts Insert mode when 'insertmode' is set.
+ if (cap->nchar == Ctrl_G && p_im) {
restart_edit = 'a';
- } else
+ }
+ } else {
clearopbeep(cap->oap);
+ }
}
/*
@@ -7581,7 +7844,7 @@ static void nv_esc(cmdarg_T *cap)
&& cap->oap->regname == 0
&& !p_im);
- if (cap->arg) { /* true for CTRL-C */
+ if (cap->arg) { // true for CTRL-C
if (restart_edit == 0
&& cmdwin_type == 0
&& !VIsual_active
@@ -7596,11 +7859,12 @@ 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)
+ if (!p_im) {
restart_edit = 0;
+ }
if (cmdwin_type != 0) {
cmdwin_result = K_IGNORE;
- got_int = false; /* don't stop executing autocommands et al. */
+ got_int = false; // don't stop executing autocommands et al.
return;
}
} else if (cmdwin_type != 0 && ex_normal_busy) {
@@ -7612,8 +7876,8 @@ static void nv_esc(cmdarg_T *cap)
}
if (VIsual_active) {
- end_visual_mode(); /* stop Visual */
- check_cursor_col(); /* make sure cursor is not beyond EOL */
+ end_visual_mode(); // stop Visual
+ check_cursor_col(); // make sure cursor is not beyond EOL
curwin->w_set_curswant = true;
redraw_curbuf_later(INVERTED);
} else if (no_reason) {
@@ -7624,9 +7888,9 @@ static void nv_esc(cmdarg_T *cap)
/* 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
- )
+ && ex_normal_busy == 0) {
restart_edit = 'a';
+ }
}
// Move the cursor for the "A" command.
@@ -7657,7 +7921,7 @@ static void nv_edit(cmdarg_T *cap)
// in Visual mode "A" and "I" are an operator
if (VIsual_active && (cap->cmdchar == 'A' || cap->cmdchar == 'I')) {
v_visop(cap);
- // in Visual mode and after an operator "a" and "i" are for text objects
+ // in Visual mode and after an operator "a" and "i" are for text objects
} else if ((cap->cmdchar == 'a' || cap->cmdchar == 'i')
&& (cap->oap->op_type != OP_NOP || VIsual_active)) {
nv_object(cap);
@@ -7671,20 +7935,21 @@ static void nv_edit(cmdarg_T *cap)
set_cursor_for_append_to_line();
break;
- case 'I': /* "I"nsert before the first non-blank */
+ case 'I': // "I"nsert before the first non-blank
beginline(BL_WHITE);
break;
- case 'a': /* "a"ppend is like "i"nsert on the next character. */
+ case 'a': // "a"ppend is like "i"nsert on the next character.
/* increment coladd when in virtual space, increment the
* column otherwise, also to append after an unprintable char */
if (virtual_active()
&& (curwin->w_cursor.coladd > 0
|| *get_cursor_pos_ptr() == NUL
- || *get_cursor_pos_ptr() == TAB))
+ || *get_cursor_pos_ptr() == TAB)) {
curwin->w_cursor.coladd++;
- else if (*get_cursor_pos_ptr() != NUL)
+ } else if (*get_cursor_pos_ptr() != NUL) {
inc_cursor();
+ }
break;
}
@@ -7702,35 +7967,32 @@ static void nv_edit(cmdarg_T *cap)
}
}
-/*
- * Invoke edit() and take care of "restart_edit" and the return value.
- */
-static void
-invoke_edit (
- cmdarg_T *cap,
- int repl, /* "r" or "gr" command */
- int cmd,
- int startln
-)
+/// Invoke edit() and take care of "restart_edit" and the return value.
+///
+/// @param repl "r" or "gr" command
+static void invoke_edit(cmdarg_T *cap, int repl, int cmd, int startln)
{
int restart_edit_save = 0;
/* Complicated: When the user types "a<C-O>a" we don't want to do Insert
* mode recursively. But when doing "a<C-O>." or "a<C-O>rx" we do allow
* it. */
- if (repl || !stuff_empty())
+ if (repl || !stuff_empty()) {
restart_edit_save = restart_edit;
- else
+ } else {
restart_edit_save = 0;
+ }
- /* Always reset "restart_edit", this is not a restarted edit. */
+ // Always reset "restart_edit", this is not a restarted edit.
restart_edit = 0;
- if (edit(cmd, startln, cap->count1))
+ if (edit(cmd, startln, cap->count1)) {
cap->retval |= CA_COMMAND_BUSY;
+ }
- if (restart_edit == 0)
+ if (restart_edit == 0) {
restart_edit = restart_edit_save;
+ }
}
/*
@@ -7740,43 +8002,43 @@ static void nv_object(cmdarg_T *cap)
{
bool flag;
bool include;
- char_u *mps_save;
+ char_u *mps_save;
- if (cap->cmdchar == 'i')
- include = false; /* "ix" = inner object: exclude white space */
- else
- include = true; /* "ax" = an object: include white space */
-
- /* Make sure (), [], {} and <> are in 'matchpairs' */
+ if (cap->cmdchar == 'i') {
+ include = false; // "ix" = inner object: exclude white space
+ } else {
+ include = true; // "ax" = an object: include white space
+ }
+ // Make sure (), [], {} and <> are in 'matchpairs'
mps_save = curbuf->b_p_mps;
curbuf->b_p_mps = (char_u *)"(:),{:},[:],<:>";
switch (cap->nchar) {
- case 'w': /* "aw" = a word */
+ case 'w': // "aw" = a word
flag = current_word(cap->oap, cap->count1, include, false);
break;
- case 'W': /* "aW" = a WORD */
+ case 'W': // "aW" = a WORD
flag = current_word(cap->oap, cap->count1, include, true);
break;
- case 'b': /* "ab" = a braces block */
+ case 'b': // "ab" = a braces block
case '(':
case ')':
flag = current_block(cap->oap, cap->count1, include, '(', ')');
break;
- case 'B': /* "aB" = a Brackets block */
+ case 'B': // "aB" = a Brackets block
case '{':
case '}':
flag = current_block(cap->oap, cap->count1, include, '{', '}');
break;
- case '[': /* "a[" = a [] block */
+ case '[': // "a[" = a [] block
case ']':
flag = current_block(cap->oap, cap->count1, include, '[', ']');
break;
- case '<': /* "a<" = a <> block */
+ case '<': // "a<" = a <> block
case '>':
flag = current_block(cap->oap, cap->count1, include, '<', '>');
break;
- case 't': /* "at" = a tag block (xml and html) */
+ case 't': // "at" = a tag block (xml and html)
// Do not adjust oap->end in do_pending_operator()
// otherwise there are different results for 'dit'
// (note leading whitespace in last line):
@@ -7786,17 +8048,17 @@ static void nv_object(cmdarg_T *cap)
cap->retval |= CA_NO_ADJ_OP_END;
flag = current_tagblock(cap->oap, cap->count1, include);
break;
- case 'p': /* "ap" = a paragraph */
+ case 'p': // "ap" = a paragraph
flag = current_par(cap->oap, cap->count1, include, 'p');
break;
- case 's': /* "as" = a sentence */
+ case 's': // "as" = a sentence
flag = current_sent(cap->oap, cap->count1, include);
break;
- case '"': /* "a"" = a double quoted string */
- case '\'': /* "a'" = a single quoted string */
- case '`': /* "a`" = a backtick quoted string */
+ case '"': // "a"" = a double quoted string
+ case '\'': // "a'" = a single quoted string
+ case '`': // "a`" = a backtick quoted string
flag = current_quote(cap->oap, cap->count1, include,
- cap->nchar);
+ cap->nchar);
break;
default:
flag = false;
@@ -7804,8 +8066,9 @@ static void nv_object(cmdarg_T *cap)
}
curbuf->b_p_mps = mps_save;
- if (!flag)
+ if (!flag) {
clearopbeep(cap->oap);
+ }
adjust_cursor_col();
curwin->w_set_curswant = true;
}
@@ -7817,7 +8080,7 @@ static void nv_object(cmdarg_T *cap)
static void nv_record(cmdarg_T *cap)
{
if (cap->oap->op_type == OP_FORMAT) {
- /* "gqq" is the same as "gqgq": format line */
+ // "gqq" is the same as "gqgq": format line
cap->cmdchar = 'g';
cap->nchar = 'q';
nv_operator(cap);
@@ -7840,11 +8103,13 @@ static void nv_record(cmdarg_T *cap)
*/
static void nv_at(cmdarg_T *cap)
{
- if (checkclearop(cap->oap))
+ if (checkclearop(cap->oap)) {
return;
+ }
if (cap->nchar == '=') {
- if (get_expr_register() == NUL)
+ if (get_expr_register() == NUL) {
return;
+ }
}
while (cap->count1-- && !got_int) {
if (do_execreg(cap->nchar, false, false, false) == false) {
@@ -7862,10 +8127,11 @@ static void nv_halfpage(cmdarg_T *cap)
{
if ((cap->cmdchar == Ctrl_U && curwin->w_cursor.lnum == 1)
|| (cap->cmdchar == Ctrl_D
- && curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count))
+ && curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)) {
clearopbeep(cap->oap);
- else if (!checkclearop(cap->oap))
+ } else if (!checkclearop(cap->oap)) {
halfpage(cap->cmdchar == Ctrl_D, cap->count0);
+ }
}
/*
@@ -7915,7 +8181,7 @@ static void nv_put_opt(cmdarg_T *cap, bool fix_indent)
int flags = 0;
if (cap->oap->op_type != OP_NOP) {
- /* "dp" is ":diffput" */
+ // "dp" is ":diffput"
if (cap->oap->op_type == OP_DELETE && cap->cmdchar == 'p') {
clearop(cap->oap);
assert(cap->opcount >= 0);
@@ -7952,7 +8218,7 @@ static void nv_put_opt(cmdarg_T *cap, bool fix_indent)
regname = cap->oap->regname;
// '+' and '*' could be the same selection
bool clipoverwrite = (regname == '+' || regname == '*')
- && (cb_flags & CB_UNNAMEDMASK);
+ && (cb_flags & CB_UNNAMEDMASK);
if (regname == 0 || regname == '"' || clipoverwrite
|| ascii_isdigit(regname) || regname == '-') {
// The delete might overwrite the register we want to put, save it first
@@ -7993,11 +8259,12 @@ static void nv_put_opt(cmdarg_T *cap, bool fix_indent)
if ((VIsual_mode != 'V'
&& curwin->w_cursor.col < curbuf->b_op_start.col)
|| (VIsual_mode == 'V'
- && curwin->w_cursor.lnum < curbuf->b_op_start.lnum))
+ && curwin->w_cursor.lnum < curbuf->b_op_start.lnum)) {
/* cursor is at the end of the line or end of file, put
* forward. */
dir = FORWARD;
- /* May have been reset in do_put(). */
+ }
+ // May have been reset in do_put().
VIsual_active = true;
}
do_put(cap->oap->regname, savereg, dir, cap->count1, flags);
@@ -8041,7 +8308,7 @@ static void nv_put_opt(cmdarg_T *cap, bool fix_indent)
*/
static void nv_open(cmdarg_T *cap)
{
- /* "do" is ":diffget" */
+ // "do" is ":diffget"
if (cap->oap->op_type == OP_DELETE && cap->cmdchar == 'o') {
clearop(cap->oap);
assert(cap->opcount >= 0);
@@ -8056,12 +8323,10 @@ static void nv_open(cmdarg_T *cap)
}
}
-// Calculate start/end virtual columns for operating in block mode.
-static void get_op_vcol(
- oparg_T *oap,
- colnr_T redo_VIsual_vcol,
- bool initial // when true: adjust position for 'selectmode'
-)
+/// Calculate start/end virtual columns for operating in block mode.
+///
+/// @param initial when true: adjust position for 'selectmode'
+static void get_op_vcol(oparg_T *oap, colnr_T redo_VIsual_vcol, bool initial)
{
colnr_T start;
colnr_T end;
@@ -8136,20 +8401,18 @@ static void nv_event(cmdarg_T *cap)
// not safe to perform garbage collection because there could be unreferenced
// lists or dicts being used.
may_garbage_collect = false;
- bool may_restart = (restart_edit != 0);
+ bool may_restart = (restart_edit != 0 || restart_VIsual_select != 0);
state_handle_k_event();
finish_op = false;
if (may_restart) {
// Tricky: if restart_edit was set before the handler we are in ctrl-o mode,
// but if not, the event should be allowed to trigger :startinsert.
- cap->retval |= CA_COMMAND_BUSY; // don't call edit() now
+ cap->retval |= CA_COMMAND_BUSY; // don't call edit() or restart Select now
}
}
-/*
- * Return TRUE when 'mousemodel' is set to "popup" or "popup_setpos".
- */
-static int mouse_model_popup(void)
+/// @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/ops.c b/src/nvim/ops.c
index 855f63ba7b..1d737ee9fc 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -11,27 +11,27 @@
#include <stdbool.h>
#include <string.h>
-#include "nvim/vim.h"
#include "nvim/ascii.h"
-#include "nvim/ops.h"
+#include "nvim/assert.h"
#include "nvim/buffer.h"
#include "nvim/change.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
-#include "nvim/assert.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_getln.h"
+#include "nvim/extmark.h"
#include "nvim/fileio.h"
#include "nvim/fold.h"
#include "nvim/getchar.h"
#include "nvim/indent.h"
+#include "nvim/lib/kvec.h"
#include "nvim/log.h"
+#include "nvim/macros.h"
#include "nvim/mark.h"
-#include "nvim/extmark.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
@@ -39,8 +39,12 @@
#include "nvim/misc1.h"
#include "nvim/move.h"
#include "nvim/normal.h"
+#include "nvim/ops.h"
#include "nvim/option.h"
+#include "nvim/os/input.h"
+#include "nvim/os/time.h"
#include "nvim/path.h"
+#include "nvim/plines.h"
#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/state.h"
@@ -48,15 +52,12 @@
#include "nvim/terminal.h"
#include "nvim/ui.h"
#include "nvim/undo.h"
-#include "nvim/macros.h"
+#include "nvim/vim.h"
#include "nvim/window.h"
-#include "nvim/lib/kvec.h"
-#include "nvim/os/input.h"
-#include "nvim/os/time.h"
static yankreg_T y_regs[NUM_REGISTERS];
-static yankreg_T *y_previous = NULL; /* ptr to last written yankreg */
+static yankreg_T *y_previous = NULL; // ptr to last written yankreg
// for behavior between start_batch_changes() and end_batch_changes())
static int batch_change_count = 0; // inside a script
@@ -69,20 +70,20 @@ static bool clipboard_didwarn = false;
* also op_change, op_shift, op_insert, op_replace - AKelly
*/
struct block_def {
- int startspaces; /* 'extra' cols before first char */
- int endspaces; /* 'extra' cols after last char */
- int textlen; /* chars in block */
- char_u *textstart; /* pointer to 1st char (partially) in block */
- colnr_T textcol; /* index of chars (partially) in block */
- colnr_T start_vcol; /* start col of 1st char wholly inside block */
- colnr_T end_vcol; /* start col of 1st char wholly after block */
- int is_short; /* TRUE if line is too short to fit in block */
- int is_MAX; /* TRUE if curswant==MAXCOL when starting */
- int is_oneChar; /* TRUE if block within one character */
- int pre_whitesp; /* screen cols of ws before block */
- int pre_whitesp_c; /* chars of ws before block */
- colnr_T end_char_vcols; /* number of vcols of post-block char */
- colnr_T start_char_vcols; /* number of vcols of pre-block char */
+ int startspaces; // 'extra' cols before first char
+ int endspaces; // 'extra' cols after last char
+ int textlen; // chars in block
+ char_u *textstart; // pointer to 1st char (partially) in block
+ colnr_T textcol; // index of chars (partially) in block
+ colnr_T start_vcol; // start col of 1st char wholly inside block
+ colnr_T end_vcol; // start col of 1st char wholly after block
+ int is_short; // TRUE if line is too short to fit in block
+ int is_MAX; // TRUE if curswant==MAXCOL when starting
+ int is_oneChar; // TRUE if block within one character
+ int pre_whitesp; // screen cols of ws before block
+ int pre_whitesp_c; // chars of ws before block
+ colnr_T end_char_vcols; // number of vcols of post-block char
+ colnr_T start_char_vcols; // number of vcols of pre-block char
};
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -182,7 +183,7 @@ int op_on_lines(int op)
// Return TRUE if operator "op" changes text.
int op_is_change(int op)
{
- return opchars[op][2] & OPF_CHANGE;
+ return opchars[op][2] & OPF_CHANGE;
}
/*
@@ -209,12 +210,13 @@ void op_shift(oparg_T *oap, int curs_top, int amount)
{
long i;
int first_char;
- char_u *s;
+ char_u *s;
int block_col = 0;
if (u_save((linenr_T)(oap->start.lnum - 1),
- (linenr_T)(oap->end.lnum + 1)) == FAIL)
+ (linenr_T)(oap->end.lnum + 1)) == FAIL) {
return;
+ }
if (oap->motion_type == kMTBlockWise) {
block_col = curwin->w_cursor.col;
@@ -237,32 +239,35 @@ void op_shift(oparg_T *oap, int curs_top, int amount)
if (oap->motion_type == kMTBlockWise) {
curwin->w_cursor.lnum = oap->start.lnum;
curwin->w_cursor.col = block_col;
- } else if (curs_top) { /* put cursor on first line, for ">>" */
+ } else if (curs_top) { // put cursor on first line, for ">>"
curwin->w_cursor.lnum = oap->start.lnum;
- beginline(BL_SOL | BL_FIX); /* shift_line() may have set cursor.col */
- } else
- --curwin->w_cursor.lnum; /* put cursor on last line, for ":>" */
-
+ beginline(BL_SOL | BL_FIX); // shift_line() may have set cursor.col
+ } else {
+ --curwin->w_cursor.lnum; // put cursor on last line, for ":>"
+ }
// The cursor line is not in a closed fold
foldOpenCursor();
if (oap->line_count > p_report) {
- if (oap->op_type == OP_RSHIFT)
+ if (oap->op_type == OP_RSHIFT) {
s = (char_u *)">";
- else
+ } else {
s = (char_u *)"<";
+ }
if (oap->line_count == 1) {
- if (amount == 1)
+ if (amount == 1) {
sprintf((char *)IObuff, _("1 line %sed 1 time"), s);
- else
+ } else {
sprintf((char *)IObuff, _("1 line %sed %d times"), s, amount);
+ }
} else {
- if (amount == 1)
+ if (amount == 1) {
sprintf((char *)IObuff, _("%" PRId64 " lines %sed 1 time"),
- (int64_t)oap->line_count, s);
- else
+ (int64_t)oap->line_count, s);
+ } else {
sprintf((char *)IObuff, _("%" PRId64 " lines %sed %d times"),
- (int64_t)oap->line_count, s, amount);
+ (int64_t)oap->line_count, s, amount);
+ }
}
msg_attr_keep(IObuff, 0, true, false);
}
@@ -280,14 +285,11 @@ void op_shift(oparg_T *oap, int curs_top, int amount)
changed_lines(oap->start.lnum, 0, oap->end.lnum + 1, 0L, true);
}
-// Shift the current line one shiftwidth left (if left != 0) or right
-// leaves cursor on first blank in the line.
-void shift_line(
- int left,
- int round,
- int amount,
- int call_changed_bytes // call changed_bytes()
-)
+/// Shift the current line one shiftwidth left (if left != 0) or right
+/// leaves cursor on first blank in the line.
+///
+/// @param call_changed_bytes call changed_bytes()
+void shift_line(int left, int round, int amount, int call_changed_bytes)
{
int count;
int i, j;
@@ -303,18 +305,22 @@ void shift_line(
}
if (left) {
i -= amount;
- if (i < 0)
+ if (i < 0) {
i = 0;
- } else
+ }
+ } else {
i += amount;
+ }
count = i * p_sw;
} else { // original vi indent
if (left) {
count -= p_sw * amount;
- if (count < 0)
+ if (count < 0) {
count = 0;
- } else
+ }
+ } else {
count += p_sw * amount;
+ }
}
// Set new indent
@@ -343,7 +349,7 @@ static void shift_block(oparg_T *oap, int amount)
int i = 0, j = 0;
const int old_p_ri = p_ri;
- p_ri = 0; /* don't want revins in indent */
+ p_ri = 0; // don't want revins in indent
State = INSERT; // don't want REPLACE for State
block_prep(oap, &bd, curwin->w_cursor.lnum, true);
@@ -381,7 +387,7 @@ static void shift_block(oparg_T *oap, int amount)
}
for (; ascii_iswhite(*bd.textstart); ) {
// TODO: is passing bd.textstart for start of the line OK?
- incr = lbr_chartabsize_adv(bd.textstart, &bd.textstart, (colnr_T)(bd.start_vcol));
+ incr = lbr_chartabsize_adv(bd.textstart, &bd.textstart, (bd.start_vcol));
total += incr;
bd.start_vcol += incr;
}
@@ -407,7 +413,7 @@ static void shift_block(oparg_T *oap, int amount)
newlen = i+j;
memset(newp + bd.textcol, TAB, (size_t)i);
memset(newp + bd.textcol + i, ' ', (size_t)j);
- /* the end */
+ // the end
memmove(newp + bd.textcol + i + j, bd.textstart, (size_t)len);
} else { // left
colnr_T destination_col; // column to which text in block will
@@ -419,7 +425,7 @@ static void shift_block(oparg_T *oap, int amount)
size_t fill; // nr of spaces that replace a TAB
size_t new_line_len; // the length of the line after the
// block shift
- char_u *non_white = bd.textstart;
+ char_u *non_white = bd.textstart;
/*
* Firstly, let's find the first non-whitespace character that is
@@ -461,15 +467,17 @@ static void shift_block(oparg_T *oap, int amount)
/* If "bd.startspaces" is set, "bd.textstart" points to the character
* preceding the block. We have to subtract its width to obtain its
* column number. */
- if (bd.startspaces)
+ if (bd.startspaces) {
verbatim_copy_width -= bd.start_char_vcols;
+ }
while (verbatim_copy_width < destination_col) {
char_u *line = verbatim_copy_end;
// TODO: is passing verbatim_copy_end for start of the line OK?
incr = lbr_chartabsize(line, verbatim_copy_end, verbatim_copy_width);
- if (verbatim_copy_width + incr > destination_col)
+ if (verbatim_copy_width + incr > destination_col) {
break;
+ }
verbatim_copy_width += incr;
MB_PTR_ADV(verbatim_copy_end);
}
@@ -498,7 +506,7 @@ static void shift_block(oparg_T *oap, int amount)
}
// replace the line
ml_replace(curwin->w_cursor.lnum, newp, false);
- changed_bytes(curwin->w_cursor.lnum, (colnr_T)bd.textcol);
+ changed_bytes(curwin->w_cursor.lnum, bd.textcol);
extmark_splice_cols(curbuf, (int)curwin->w_cursor.lnum-1, startcol,
oldlen, newlen,
kExtmarkUndo);
@@ -518,7 +526,7 @@ static void block_insert(oparg_T *oap, char_u *s, int b_insert, struct block_def
int spaces = 0; // non-zero if cutting a TAB
colnr_T offset; // pointer along new line
size_t s_len = STRLEN(s);
- char_u *newp, *oldp; // new, old lines
+ char_u *newp, *oldp; // new, old lines
linenr_T lnum; // loop var
int oldstate = State;
State = INSERT; // don't want REPLACE for State
@@ -534,20 +542,23 @@ static void block_insert(oparg_T *oap, char_u *s, int b_insert, struct block_def
if (b_insert) {
p_ts = bdp->start_char_vcols;
spaces = bdp->startspaces;
- if (spaces != 0)
- count = p_ts - 1; /* we're cutting a TAB */
+ if (spaces != 0) {
+ count = p_ts - 1; // we're cutting a TAB
+ }
offset = bdp->textcol;
- } else { /* append */
+ } else { // append
p_ts = bdp->end_char_vcols;
- if (!bdp->is_short) { /* spaces = padding after block */
+ if (!bdp->is_short) { // spaces = padding after block
spaces = (bdp->endspaces ? p_ts - bdp->endspaces : 0);
- if (spaces != 0)
- count = p_ts - 1; /* we're cutting a TAB */
+ if (spaces != 0) {
+ count = p_ts - 1; // we're cutting a TAB
+ }
offset = bdp->textcol + bdp->textlen - (spaces != 0);
- } else { /* spaces = padding to block edge */
- /* if $ used, just append to EOL (ie spaces==0) */
- if (!bdp->is_MAX)
+ } else { // spaces = padding to block edge
+ // if $ used, just append to EOL (ie spaces==0)
+ if (!bdp->is_MAX) {
spaces = (oap->end_vcol - bdp->end_vcol) + 1;
+ }
count = spaces;
offset = bdp->textcol + bdp->textlen;
}
@@ -593,8 +604,9 @@ static void block_insert(oparg_T *oap, char_u *s, int b_insert, struct block_def
skipped = 1;
}
- if (spaces > 0)
+ if (spaces > 0) {
offset += count;
+ }
STRMOVE(newp + offset, oldp);
ml_replace(lnum, newp, false);
@@ -607,7 +619,7 @@ static void block_insert(oparg_T *oap, char_u *s, int b_insert, struct block_def
curbuf->b_op_end.lnum = oap->end.lnum;
curbuf->b_op_end.col = offset;
}
- } /* for all lnum */
+ } // for all lnum
changed_lines(oap->start.lnum + 1, 0, oap->end.lnum + 1, 0L, true);
@@ -620,13 +632,13 @@ static void block_insert(oparg_T *oap, char_u *s, int b_insert, struct block_def
void op_reindent(oparg_T *oap, Indenter how)
{
long i;
- char_u *l;
+ char_u *l;
int amount;
linenr_T first_changed = 0;
linenr_T last_changed = 0;
linenr_T start_lnum = curwin->w_cursor.lnum;
- /* Don't even try when 'modifiable' is off. */
+ // Don't even try when 'modifiable' is off.
if (!MODIFIABLE(curbuf)) {
EMSG(_(e_modifiable));
return;
@@ -638,8 +650,9 @@ void op_reindent(oparg_T *oap, Indenter how)
if (i > 1
&& (i % 50 == 0 || i == oap->line_count - 1)
- && oap->line_count > p_report)
+ && oap->line_count > p_report) {
smsg(_("%" PRId64 " lines to indent... "), (int64_t)i);
+ }
/*
* Be vi-compatible: For lisp indenting the first line is not
@@ -648,11 +661,11 @@ void op_reindent(oparg_T *oap, Indenter how)
if (i != oap->line_count - 1 || oap->line_count == 1
|| how != get_lisp_indent) {
l = skipwhite(get_cursor_line_ptr());
- if (*l == NUL) /* empty or blank line */
+ if (*l == NUL) { // empty or blank line
amount = 0;
- else
- amount = how(); /* get the indent for this line */
-
+ } else {
+ amount = how(); // get the indent for this line
+ }
if (amount >= 0 && set_indent(amount, SIN_UNDO)) {
// did change the indent, call changed_lines() later
if (first_changed == 0) {
@@ -662,10 +675,10 @@ void op_reindent(oparg_T *oap, Indenter how)
}
}
++curwin->w_cursor.lnum;
- curwin->w_cursor.col = 0; /* make sure it's valid */
+ curwin->w_cursor.col = 0; // make sure it's valid
}
- /* put cursor on first non-blank of indented line */
+ // put cursor on first non-blank of indented line
curwin->w_cursor.lnum = start_lnum;
beginline(BL_SOL | BL_FIX);
@@ -682,12 +695,13 @@ void op_reindent(oparg_T *oap, Indenter how)
if (oap->line_count > p_report) {
i = oap->line_count - (i + 1);
- if (i == 1)
+ if (i == 1) {
MSG(_("1 line indented "));
- else
+ } else {
smsg(_("%" PRId64 " lines indented "), (int64_t)i);
+ }
}
- /* set '[ and '] marks */
+ // set '[ and '] marks
curbuf->b_op_start = oap->start;
curbuf->b_op_end = oap->end;
}
@@ -695,7 +709,7 @@ void op_reindent(oparg_T *oap, Indenter how)
/*
* Keep the last expression line here, for repeating.
*/
-static char_u *expr_line = NULL;
+static char_u *expr_line = NULL;
/*
* Get an expression for the "\"=expr1" or "CTRL-R =expr1"
@@ -703,7 +717,7 @@ static char_u *expr_line = NULL;
*/
int get_expr_register(void)
{
- char_u *new_line;
+ char_u *new_line;
new_line = getcmdline('=', 0L, 0, true);
if (new_line == NULL) {
@@ -733,12 +747,13 @@ void set_expr_line(char_u *new_line)
*/
char_u *get_expr_line(void)
{
- char_u *expr_copy;
- char_u *rv;
+ char_u *expr_copy;
+ char_u *rv;
static int nested = 0;
- if (expr_line == NULL)
+ if (expr_line == NULL) {
return NULL;
+ }
/* Make a copy of the expression, because evaluating it may cause it to be
* changed. */
@@ -746,12 +761,13 @@ char_u *get_expr_line(void)
/* When we are invoked recursively limit the evaluation to 10 levels.
* Then return the string as-is. */
- if (nested >= 10)
+ if (nested >= 10) {
return expr_copy;
+ }
- ++nested;
- rv = eval_to_string(expr_copy, NULL, TRUE);
- --nested;
+ nested++;
+ rv = eval_to_string(expr_copy, NULL, true);
+ nested--;
xfree(expr_copy);
return rv;
}
@@ -761,8 +777,9 @@ char_u *get_expr_line(void)
*/
char_u *get_expr_line_src(void)
{
- if (expr_line == NULL)
+ if (expr_line == NULL) {
return NULL;
+ }
return vim_strsave(expr_line);
}
@@ -775,7 +792,7 @@ char_u *get_expr_line_src(void)
bool valid_yank_reg(int regname, bool writing)
{
if ((regname > 0 && ASCII_ISALNUM(regname))
- || (!writing && vim_strchr((char_u *) "/.%:=" , regname) != NULL)
+ || (!writing && vim_strchr((char_u *)"/.%:=", regname) != NULL)
|| regname == '#'
|| regname == '"'
|| regname == '-'
@@ -787,12 +804,6 @@ bool valid_yank_reg(int regname, bool writing)
return false;
}
-typedef enum {
- YREG_PASTE,
- YREG_YANK,
- YREG_PUT,
-} yreg_mode_t;
-
/// Return yankreg_T to use, according to the value of `regname`.
/// Cannot handle the '_' (black hole) register.
/// Must only be called with a valid register name!
@@ -819,8 +830,8 @@ yankreg_T *get_yank_register(int regname, int mode)
// reg is set to clipboard contents.
return reg;
} else if (mode != YREG_YANK
- && (regname == 0 || regname == '"' || regname == '*' || regname == '+')
- && y_previous != NULL) {
+ && (regname == 0 || regname == '"' || regname == '*' || regname == '+')
+ && y_previous != NULL) {
// in case clipboard not available, paste from previous used register
return y_previous;
}
@@ -893,9 +904,9 @@ bool yank_register_mline(int regname)
*/
int do_record(int c)
{
- char_u *p;
+ char_u *p;
static int regname;
- yankreg_T *old_y_previous;
+ yankreg_T *old_y_previous;
int retval;
if (reg_recording == 0) {
@@ -909,7 +920,7 @@ int do_record(int c)
regname = c;
retval = OK;
}
- } else { /* stop recording */
+ } else { // stop recording
/*
* Get the recorded key hits. K_SPECIAL and CSI will be escaped, this
* needs to be removed again to put it in a register. exec_reg then
@@ -922,10 +933,10 @@ int do_record(int c)
MSG("");
}
p = get_recorded();
- if (p == NULL)
+ if (p == NULL) {
retval = FAIL;
- else {
- /* Remove escaping for CSI and K_SPECIAL in multi-byte chars. */
+ } else {
+ // Remove escaping for CSI and K_SPECIAL in multi-byte chars.
vim_unescape_csi(p);
/*
@@ -954,18 +965,18 @@ static void set_yreg_additional_data(yankreg_T *reg, dict_T *additional_data)
/*
* Stuff string "p" into yank register "regname" as a single line (append if
- * uppercase). "p" must have been alloced.
+ * uppercase). "p" must have been allocated.
*
* return FAIL for failure, OK otherwise
*/
static int stuff_yank(int regname, char_u *p)
{
- /* check for read-only register */
+ // check for read-only register
if (regname != 0 && !valid_yank_reg(regname, true)) {
xfree(p);
return FAIL;
}
- if (regname == '_') { /* black hole: don't do anything */
+ if (regname == '_') { // black hole: don't do anything
xfree(p);
return OK;
}
@@ -995,36 +1006,35 @@ static int execreg_lastc = NUL;
/// Execute a yank register: copy it into the stuff buffer
///
-/// Return FAIL for failure, OK otherwise
-int
-do_execreg(
- int regname,
- int colon, /* insert ':' before each line */
- int addcr, /* always add '\n' to end of line */
- int silent /* set "silent" flag in typeahead buffer */
-)
+/// @param colon insert ':' before each line
+/// @param addcr always add '\n' to end of line
+/// @param silent set "silent" flag in typeahead buffer
+///
+/// @return FAIL for failure, OK otherwise
+int do_execreg(int regname, int colon, int addcr, int silent)
{
char_u *p;
int retval = OK;
- if (regname == '@') { /* repeat previous one */
+ if (regname == '@') { // repeat previous one
if (execreg_lastc == NUL) {
EMSG(_("E748: No previously used register"));
return FAIL;
}
regname = execreg_lastc;
}
- /* check for valid regname */
+ // check for valid regname
if (regname == '%' || regname == '#' || !valid_yank_reg(regname, false)) {
emsg_invreg(regname);
return FAIL;
}
execreg_lastc = regname;
- if (regname == '_') /* black hole: don't stuff anything */
+ if (regname == '_') { // black hole: don't stuff anything
return OK;
+ }
- if (regname == ':') { /* use last command line */
+ if (regname == ':') { // use last command line
if (last_cmdline == NULL) {
EMSG(_(e_nolastcmd));
return FAIL;
@@ -1032,13 +1042,12 @@ do_execreg(
// don't keep the cmdline containing @:
XFREE_CLEAR(new_last_cmdline);
// Escape all control characters with a CTRL-V
- p = vim_strsave_escaped_ext(
- last_cmdline,
- (char_u *)"\001\002\003\004\005\006\007"
- "\010\011\012\013\014\015\016\017"
- "\020\021\022\023\024\025\026\027"
- "\030\031\032\033\034\035\036\037",
- Ctrl_V, false);
+ p = vim_strsave_escaped_ext(last_cmdline,
+ (char_u *)"\001\002\003\004\005\006\007"
+ "\010\011\012\013\014\015\016\017"
+ "\020\021\022\023\024\025\026\027"
+ "\030\031\032\033\034\035\036\037",
+ Ctrl_V, false);
// When in Visual mode "'<,'>" will be prepended to the command.
// Remove it when it's already there.
if (VIsual_active && STRNCMP(p, "'<,'>", 5) == 0) {
@@ -1049,11 +1058,12 @@ do_execreg(
xfree(p);
} else if (regname == '=') {
p = get_expr_line();
- if (p == NULL)
+ if (p == NULL) {
return FAIL;
+ }
retval = put_in_typebuf(p, true, colon, silent);
xfree(p);
- } else if (regname == '.') { /* use last inserted text */
+ } else if (regname == '.') { // use last inserted text
p = get_last_insert_save();
if (p == NULL) {
EMSG(_(e_noinstext));
@@ -1063,10 +1073,11 @@ do_execreg(
xfree(p);
} else {
yankreg_T *reg = get_yank_register(regname, YREG_PASTE);
- if (reg->y_array == NULL)
+ if (reg->y_array == NULL) {
return FAIL;
+ }
- // Disallow remaping for ":@r".
+ // Disallow remapping for ":@r".
int remap = colon ? REMAP_NONE : REMAP_YES;
/*
@@ -1120,18 +1131,13 @@ static void put_reedit_in_typebuf(int silent)
}
}
-/*
- * Insert register contents "s" into the typeahead buffer, so that it will be
- * executed again.
- * When "esc" is TRUE it is to be taken literally: Escape CSI characters and
- * no remapping.
- */
-static int put_in_typebuf(
- char_u *s,
- bool esc,
- bool colon, // add ':' before the line
- int silent
-)
+/// Insert register contents "s" into the typeahead buffer, so that it will be
+/// executed again.
+///
+/// @param esc when true then it is to be taken literally: Escape CSI
+/// characters and no remapping.
+/// @param colon add ':' before the line
+static int put_in_typebuf(char_u *s, bool esc, bool colon, int silent)
{
int retval = OK;
@@ -1140,7 +1146,7 @@ static int put_in_typebuf(
retval = ins_typebuf((char_u *)"\n", REMAP_NONE, 0, true, silent);
}
if (retval == OK) {
- char_u *p;
+ char_u *p;
if (esc) {
p = vim_strsave_escape_csi(s);
@@ -1162,16 +1168,13 @@ static int put_in_typebuf(
return retval;
}
-/*
- * Insert a yank register: copy it into the Read buffer.
- * Used by CTRL-R command and middle mouse button in insert mode.
- *
- * return FAIL for failure, OK otherwise
- */
-int insert_reg(
- int regname,
- bool literally_arg // insert literally, not as if typed
-)
+/// Insert a yank register: copy it into the Read buffer.
+/// Used by CTRL-R command and middle mouse button in insert mode.
+///
+/// @param literally_arg insert literally, not as if typed
+///
+/// @return FAIL for failure, OK otherwise
+int insert_reg(int regname, bool literally_arg)
{
int retval = OK;
bool allocated;
@@ -1183,12 +1186,14 @@ int insert_reg(
* If you hit CTRL-C, the loop will be broken here.
*/
os_breakcheck();
- if (got_int)
+ if (got_int) {
return FAIL;
+ }
- /* check for valid regname */
- if (regname != NUL && !valid_yank_reg(regname, false))
+ // check for valid regname
+ if (regname != NUL && !valid_yank_reg(regname, false)) {
return FAIL;
+ }
char_u *arg;
if (regname == '.') { // Insert last inserted text.
@@ -1226,26 +1231,24 @@ int insert_reg(
return retval;
}
-/*
- * Stuff a string into the typeahead buffer, such that edit() will insert it
- * literally ("literally" TRUE) or interpret is as typed characters.
- */
-static void stuffescaped(const char *arg, int literally)
+/// Stuff a string into the typeahead buffer, such that edit() will insert it
+/// literally ("literally" true) or interpret is as typed characters.
+static void stuffescaped(const char *arg, bool literally)
{
while (*arg != NUL) {
// Stuff a sequence of normal ASCII characters, that's fast. Also
// stuff K_SPECIAL to get the effect of a special key when "literally"
- // is TRUE.
+ // is true.
const char *const start = arg;
while ((*arg >= ' ' && *arg < DEL) || ((uint8_t)(*arg) == K_SPECIAL
&& !literally)) {
arg++;
}
if (arg > start) {
- stuffReadbuffLen(start, (long)(arg - start));
+ stuffReadbuffLen(start, (arg - start));
}
- /* stuff a single special character */
+ // stuff a single special character
if (*arg != NUL) {
const int c = mb_cptr2char_adv((const char_u **)&arg);
if (literally && ((c < ' ' && c != TAB) || c == DEL)) {
@@ -1256,23 +1259,24 @@ static void stuffescaped(const char *arg, int literally)
}
}
-// If "regname" is a special register, return true and store a pointer to its
-// value in "argp".
-bool get_spec_reg(
- int regname,
- char_u **argp,
- bool *allocated, // return: true when value was allocated
- bool errmsg // give error message when failing
-)
+/// If "regname" is a special register, return true and store a pointer to its
+/// value in "argp".
+///
+/// @param allocated return: true when value was allocated
+/// @param errmsg give error message when failing
+///
+/// @return true if "regname" is a special register,
+bool get_spec_reg(int regname, char_u **argp, bool *allocated, bool errmsg)
{
size_t cnt;
*argp = NULL;
*allocated = false;
switch (regname) {
- case '%': /* file name */
- if (errmsg)
- check_fname(); /* will give emsg if not set */
+ case '%': // file name
+ if (errmsg) {
+ check_fname(); // will give emsg if not set
+ }
*argp = curbuf->b_fname;
return true;
@@ -1280,24 +1284,26 @@ bool get_spec_reg(
*argp = getaltfname(errmsg); // may give emsg if not set
return true;
- case '=': /* result of expression */
+ case '=': // result of expression
*argp = get_expr_line();
*allocated = true;
return true;
- case ':': /* last command line */
- if (last_cmdline == NULL && errmsg)
+ case ':': // last command line
+ if (last_cmdline == NULL && errmsg) {
EMSG(_(e_nolastcmd));
+ }
*argp = last_cmdline;
return true;
- case '/': /* last search-pattern */
- if (last_search_pat() == NULL && errmsg)
+ case '/': // last search-pattern
+ if (last_search_pat() == NULL && errmsg) {
EMSG(_(e_noprevre));
+ }
*argp = last_search_pat();
return true;
- case '.': /* last inserted text */
+ case '.': // last inserted text
*argp = get_last_insert_save();
*allocated = true;
if (*argp == NULL && errmsg) {
@@ -1310,9 +1316,8 @@ bool get_spec_reg(
if (!errmsg) {
return false;
}
- *argp = file_name_at_cursor(
- FNAME_MESS | FNAME_HYP | (regname == Ctrl_P ? FNAME_EXP : 0),
- 1L, NULL);
+ *argp = file_name_at_cursor(FNAME_MESS | FNAME_HYP | (regname == Ctrl_P ? FNAME_EXP : 0),
+ 1L, NULL);
*allocated = true;
return true;
@@ -1336,7 +1341,7 @@ bool get_spec_reg(
*argp = ml_get_buf(curwin->w_buffer, curwin->w_cursor.lnum, false);
return true;
- case '_': /* black hole: always empty */
+ case '_': // black hole: always empty
*argp = (char_u *)"";
return true;
}
@@ -1360,8 +1365,9 @@ bool cmdline_paste_reg(int regname, bool literally_arg, bool remcr)
const bool literally = literally_arg || is_literal_register(regname);
yankreg_T *reg = get_yank_register(regname, YREG_PASTE);
- if (reg->y_array == NULL)
+ if (reg->y_array == NULL) {
return FAIL;
+ }
for (size_t i = 0; i < reg->y_size; i++) {
cmdline_paste_str(reg->y_array[i], literally);
@@ -1374,8 +1380,9 @@ bool cmdline_paste_reg(int regname, bool literally_arg, bool remcr)
/* Check for CTRL-C, in case someone tries to paste a few thousand
* lines and gets bored. */
os_breakcheck();
- if (got_int)
+ if (got_int) {
return FAIL;
+ }
}
return OK;
}
@@ -1402,8 +1409,8 @@ int op_delete(oparg_T *oap)
{
int n;
linenr_T lnum;
- char_u *ptr;
- char_u *newp, *oldp;
+ char_u *ptr;
+ char_u *newp, *oldp;
struct block_def bd = { 0 };
linenr_T old_lcount = curbuf->b_ml.ml_line_count;
@@ -1434,8 +1441,9 @@ int op_delete(oparg_T *oap)
&& oap->motion_force == NUL
&& oap->op_type == OP_DELETE) {
ptr = ml_get(oap->end.lnum) + oap->end.col;
- if (*ptr != NUL)
+ if (*ptr != NUL) {
ptr += oap->inclusive;
+ }
ptr = skipwhite(ptr);
if (*ptr == NUL && inindent(0)) {
oap->motion_type = kMTLineWise;
@@ -1508,7 +1516,6 @@ int op_delete(oparg_T *oap)
set_clipboard(oap->regname, reg);
do_autocmd_textyankpost(oap, reg);
}
-
}
/*
@@ -1526,7 +1533,7 @@ int op_delete(oparg_T *oap)
continue;
}
- /* Adjust cursor position for tab replaced by spaces and 'lbr'. */
+ // Adjust cursor position for tab replaced by spaces and 'lbr'.
if (lnum == curwin->w_cursor.lnum) {
curwin->w_cursor.col = bd.textcol + bd.startspaces;
curwin->w_cursor.coladd = 0;
@@ -1566,12 +1573,13 @@ int op_delete(oparg_T *oap)
if (oap->line_count > 1) {
lnum = curwin->w_cursor.lnum;
- ++curwin->w_cursor.lnum;
- del_lines(oap->line_count - 1, TRUE);
+ curwin->w_cursor.lnum++;
+ del_lines(oap->line_count - 1, true);
curwin->w_cursor.lnum = lnum;
}
- if (u_save_cursor() == FAIL)
+ if (u_save_cursor() == FAIL) {
return FAIL;
+ }
if (curbuf->b_p_ai) { // don't delete indent
beginline(BL_WHITE); // cursor on first non-white
did_ai = true; // delete the indent when ESC hit
@@ -1587,25 +1595,27 @@ int op_delete(oparg_T *oap)
(int)curwin->w_cursor.lnum-1, curwin->w_cursor.col,
old_len - curwin->w_cursor.col, 0, kExtmarkUndo);
- // leave cursor past last char in line
+ // leave cursor past last char in line
if (oap->line_count > 1) {
u_clearline(); // "U" command not possible after "2cc"
}
} else {
- del_lines(oap->line_count, TRUE);
+ del_lines(oap->line_count, true);
beginline(BL_WHITE | BL_FIX);
- u_clearline(); /* "U" command not possible after "dd" */
+ u_clearline(); // "U" command not possible after "dd"
}
} else {
if (virtual_op) {
int endcol = 0;
- /* For virtualedit: break the tabs that are partly included. */
+ // For virtualedit: break the tabs that are partly included.
if (gchar_pos(&oap->start) == '\t') {
- if (u_save_cursor() == FAIL) /* save first line for undo */
+ if (u_save_cursor() == FAIL) { // save first line for undo
return FAIL;
- if (oap->line_count == 1)
+ }
+ if (oap->line_count == 1) {
endcol = getviscol2(oap->end.col, oap->end.coladd);
+ }
coladvance_force(getviscol2(oap->start.col, oap->start.coladd));
oap->start = curwin->w_cursor;
if (oap->line_count == 1) {
@@ -1616,14 +1626,15 @@ int op_delete(oparg_T *oap)
}
}
- /* Break a tab only when it's included in the area. */
+ // Break a tab only when it's included in the area.
if (gchar_pos(&oap->end) == '\t'
&& oap->end.coladd == 0
&& oap->inclusive) {
- /* save last line for undo */
+ // save last line for undo
if (u_save((linenr_T)(oap->end.lnum - 1),
- (linenr_T)(oap->end.lnum + 1)) == FAIL)
+ (linenr_T)(oap->end.lnum + 1)) == FAIL) {
return FAIL;
+ }
curwin->w_cursor = oap->end;
coladvance_force(getviscol2(oap->end.col, oap->end.coladd));
oap->end = curwin->w_cursor;
@@ -1632,17 +1643,18 @@ int op_delete(oparg_T *oap)
mb_adjust_opend(oap);
}
- if (oap->line_count == 1) { /* delete characters within one line */
- if (u_save_cursor() == FAIL) /* save line for undo */
+ if (oap->line_count == 1) { // delete characters within one line
+ if (u_save_cursor() == FAIL) { // save line for undo
return FAIL;
+ }
- /* if 'cpoptions' contains '$', display '$' at end of change */
- if ( vim_strchr(p_cpo, CPO_DOLLAR) != NULL
- && oap->op_type == OP_CHANGE
- && oap->end.lnum == curwin->w_cursor.lnum
- && !oap->is_VIsual
- )
+ // if 'cpoptions' contains '$', display '$' at end of change
+ if (vim_strchr(p_cpo, CPO_DOLLAR) != NULL
+ && oap->op_type == OP_CHANGE
+ && oap->end.lnum == curwin->w_cursor.lnum
+ && !oap->is_VIsual) {
display_dollar(oap->end.col - !oap->inclusive);
+ }
n = oap->end.col - oap->start.col + 1 - !oap->inclusive;
@@ -1650,20 +1662,23 @@ int op_delete(oparg_T *oap)
/* fix up things for virtualedit-delete:
* break the tabs which are going to get in our way
*/
- char_u *curline = get_cursor_line_ptr();
+ char_u *curline = get_cursor_line_ptr();
int len = (int)STRLEN(curline);
if (oap->end.coladd != 0
&& (int)oap->end.col >= len - 1
- && !(oap->start.coladd && (int)oap->end.col >= len - 1))
+ && !(oap->start.coladd && (int)oap->end.col >= len - 1)) {
n++;
- /* Delete at least one char (e.g, when on a control char). */
- if (n == 0 && oap->start.coladd != oap->end.coladd)
+ }
+ // Delete at least one char (e.g, when on a control char).
+ if (n == 0 && oap->start.coladd != oap->end.coladd) {
n = 1;
+ }
- /* When deleted a char in the line, reset coladd. */
- if (gchar_cursor() != NUL)
+ // When deleted a char in the line, reset coladd.
+ if (gchar_cursor() != NUL) {
curwin->w_cursor.coladd = 0;
+ }
}
(void)del_bytes((colnr_T)n, !virtual_op,
@@ -1672,16 +1687,17 @@ int op_delete(oparg_T *oap)
// delete characters between lines
pos_T curpos;
- /* save deleted and changed lines for undo */
+ // save deleted and changed lines for undo
if (u_save((linenr_T)(curwin->w_cursor.lnum - 1),
- (linenr_T)(curwin->w_cursor.lnum + oap->line_count)) == FAIL)
+ (linenr_T)(curwin->w_cursor.lnum + oap->line_count)) == FAIL) {
return FAIL;
+ }
curbuf_splice_pending++;
pos_T startpos = curwin->w_cursor; // start position for delete
- bcount_t deleted_bytes = get_region_bytecount(
- curbuf, startpos.lnum, oap->end.lnum, startpos.col,
- oap->end.col) + oap->inclusive;
+ bcount_t deleted_bytes = get_region_bytecount(curbuf, startpos.lnum, oap->end.lnum,
+ startpos.col,
+ oap->end.col) + oap->inclusive;
truncate_line(true); // delete from cursor to end of line
curpos = curwin->w_cursor; // remember curwin->w_cursor
@@ -1701,7 +1717,9 @@ int op_delete(oparg_T *oap)
(int)oap->line_count-1, n, deleted_bytes,
0, 0, 0, kExtmarkUndo);
}
- auto_format(false, true);
+ if (oap->op_type == OP_DELETE) {
+ auto_format(false, true);
+ }
}
msgmore(curbuf->b_ml.ml_line_count - old_lcount);
@@ -1724,7 +1742,7 @@ setmarks:
*/
static void mb_adjust_opend(oparg_T *oap)
{
- char_u *p;
+ char_u *p;
if (oap->inclusive) {
p = ml_get(oap->end.lnum);
@@ -1764,15 +1782,15 @@ int op_replace(oparg_T *oap, int c)
{
int n, numc;
int num_chars;
- char_u *newp, *oldp;
+ char_u *newp, *oldp;
colnr_T oldlen;
struct block_def bd;
- char_u *after_p = NULL;
+ char_u *after_p = NULL;
int had_ctrl_v_cr = false;
- if ((curbuf->b_ml.ml_flags & ML_EMPTY ) || oap->empty)
- return OK; /* nothing to do */
-
+ if ((curbuf->b_ml.ml_flags & ML_EMPTY ) || oap->empty) {
+ return OK; // nothing to do
+ }
if (c == REPLACE_CR_NCHAR) {
had_ctrl_v_cr = true;
c = CAR;
@@ -1784,8 +1802,9 @@ int op_replace(oparg_T *oap, int c)
mb_adjust_opend(oap);
if (u_save((linenr_T)(oap->start.lnum - 1),
- (linenr_T)(oap->end.lnum + 1)) == FAIL)
+ (linenr_T)(oap->end.lnum + 1)) == FAIL) {
return FAIL;
+ }
/*
* block mode replace
@@ -1812,18 +1831,20 @@ int op_replace(oparg_T *oap, int c)
getvpos(&vpos, oap->start_vcol);
bd.startspaces += vpos.coladd;
n = bd.startspaces;
- } else
- /* allow for pre spaces */
+ } else {
+ // allow for pre spaces
n = (bd.startspaces ? bd.start_char_vcols - 1 : 0);
+ }
- /* allow for post spp */
+ // allow for post spp
n += (bd.endspaces
&& !bd.is_oneChar
&& bd.end_char_vcols > 0) ? bd.end_char_vcols - 1 : 0;
- /* Figure out how many characters to replace. */
+ // Figure out how many characters to replace.
numc = oap->end_vcol - oap->start_vcol + 1;
- if (bd.is_short && (!virtual_op || bd.is_MAX))
+ if (bd.is_short && (!virtual_op || bd.is_MAX)) {
numc -= (oap->end_vcol - bd.end_vcol) + 1;
+ }
/* A double-wide character can be replaced only up to half the
* times. */
@@ -1835,7 +1856,7 @@ int op_replace(oparg_T *oap, int c)
numc = numc / 2;
}
- /* Compute bytes needed, move character count to num_chars. */
+ // Compute bytes needed, move character count to num_chars.
num_chars = numc;
numc *= (*mb_char2len)(c);
@@ -1863,19 +1884,19 @@ int op_replace(oparg_T *oap, int c)
assert(col >= 0);
int newrows = 0, newcols = 0;
if (had_ctrl_v_cr || (c != '\r' && c != '\n')) {
- // strlen(newp) at this point
- int newp_len = bd.textcol + bd.startspaces;
- while (--num_chars >= 0) {
- newp_len += utf_char2bytes(c, newp + newp_len);
- }
- if (!bd.is_short) {
- // insert post-spaces
- memset(newp + newp_len, ' ', (size_t)bd.endspaces);
- newp_len += bd.endspaces;
- // copy the part after the changed part
- memmove(newp + newp_len, oldp, (size_t)col);
- }
- newcols = newp_len - bd.textcol;
+ // strlen(newp) at this point
+ int newp_len = bd.textcol + bd.startspaces;
+ while (--num_chars >= 0) {
+ newp_len += utf_char2bytes(c, newp + newp_len);
+ }
+ if (!bd.is_short) {
+ // insert post-spaces
+ memset(newp + newp_len, ' ', (size_t)bd.endspaces);
+ newp_len += bd.endspaces;
+ // copy the part after the changed part
+ memmove(newp + newp_len, oldp, (size_t)col);
+ }
+ newcols = newp_len - bd.textcol;
} else {
// Replacing with \r or \n means splitting the line.
after_p_len = (size_t)col;
@@ -1904,10 +1925,12 @@ int op_replace(oparg_T *oap, int c)
oap->start.col = 0;
curwin->w_cursor.col = 0;
oap->end.col = (colnr_T)STRLEN(ml_get(oap->end.lnum));
- if (oap->end.col)
+ if (oap->end.col) {
--oap->end.col;
- } else if (!oap->inclusive)
+ }
+ } else if (!oap->inclusive) {
dec(&(oap->end));
+ }
// TODO(bfredl): we could batch all the splicing
// done on the same line, at least
@@ -1917,8 +1940,9 @@ int op_replace(oparg_T *oap, int c)
if ((*mb_char2len)(c) > 1 || (*mb_char2len)(n) > 1) {
/* This is slow, but it handles replacing a single-byte
* with a multi-byte and the other way around. */
- if (curwin->w_cursor.lnum == oap->end.lnum)
+ if (curwin->w_cursor.lnum == oap->end.lnum) {
oap->end.col += (*mb_char2len)(c) - (*mb_char2len)(n);
+ }
replace_character(c);
} else {
if (n == TAB) {
@@ -1928,11 +1952,12 @@ int op_replace(oparg_T *oap, int c)
/* oap->end has to be recalculated when
* the tab breaks */
end_vcol = getviscol2(oap->end.col,
- oap->end.coladd);
+ oap->end.coladd);
}
coladvance_force(getviscol());
- if (curwin->w_cursor.lnum == oap->end.lnum)
+ if (curwin->w_cursor.lnum == oap->end.lnum) {
getvpos(&oap->end, end_vcol);
+ }
}
pbyte(curwin->w_cursor, c);
}
@@ -1940,8 +1965,9 @@ int op_replace(oparg_T *oap, int c)
int virtcols = oap->end.coladd;
if (curwin->w_cursor.lnum == oap->start.lnum
- && oap->start.col == oap->end.col && oap->start.coladd)
+ && oap->start.col == oap->end.col && oap->start.coladd) {
virtcols -= oap->start.coladd;
+ }
/* oap->end has been trimmed so it's effectively inclusive;
* as a result an extra +1 must be counted so we don't
@@ -1960,9 +1986,10 @@ int op_replace(oparg_T *oap, int c)
}
}
- /* Advance to next character, stop at the end of the file. */
- if (inc_cursor() == -1)
+ // Advance to next character, stop at the end of the file.
+ if (inc_cursor() == -1) {
break;
+ }
}
}
@@ -1970,7 +1997,7 @@ int op_replace(oparg_T *oap, int c)
check_cursor();
changed_lines(oap->start.lnum, oap->start.col, oap->end.lnum + 1, 0L, true);
- /* Set "'[" and "']" marks. */
+ // Set "'[" and "']" marks.
curbuf->b_op_start = oap->start;
curbuf->b_op_end = oap->end;
@@ -1988,8 +2015,9 @@ void op_tilde(oparg_T *oap)
int did_change = FALSE;
if (u_save((linenr_T)(oap->start.lnum - 1),
- (linenr_T)(oap->end.lnum + 1)) == FAIL)
+ (linenr_T)(oap->end.lnum + 1)) == FAIL) {
return;
+ }
pos = oap->start;
if (oap->motion_type == kMTBlockWise) { // Visual block mode
@@ -2000,7 +2028,6 @@ void op_tilde(oparg_T *oap)
pos.col = bd.textcol;
one_change = swapchars(oap->op_type, &pos, bd.textlen);
did_change |= one_change;
-
}
if (did_change) {
changed_lines(oap->start.lnum, 0, oap->end.lnum + 1, 0L, true);
@@ -2010,31 +2037,36 @@ void op_tilde(oparg_T *oap)
oap->start.col = 0;
pos.col = 0;
oap->end.col = (colnr_T)STRLEN(ml_get(oap->end.lnum));
- if (oap->end.col)
+ if (oap->end.col) {
--oap->end.col;
- } else if (!oap->inclusive)
+ }
+ } else if (!oap->inclusive) {
dec(&(oap->end));
+ }
- if (pos.lnum == oap->end.lnum)
+ if (pos.lnum == oap->end.lnum) {
did_change = swapchars(oap->op_type, &pos,
- oap->end.col - pos.col + 1);
- else
+ oap->end.col - pos.col + 1);
+ } else {
for (;; ) {
did_change |= swapchars(oap->op_type, &pos,
- pos.lnum == oap->end.lnum ? oap->end.col + 1 :
- (int)STRLEN(ml_get_pos(&pos)));
- if (ltoreq(oap->end, pos) || inc(&pos) == -1)
+ pos.lnum == oap->end.lnum ? oap->end.col + 1 :
+ (int)STRLEN(ml_get_pos(&pos)));
+ if (ltoreq(oap->end, pos) || inc(&pos) == -1) {
break;
+ }
}
+ }
if (did_change) {
changed_lines(oap->start.lnum, oap->start.col, oap->end.lnum + 1,
0L, true);
}
}
- if (!did_change && oap->is_VIsual)
- /* No change: need to remove the Visual selection */
+ if (!did_change && oap->is_VIsual) {
+ // No change: need to remove the Visual selection
redraw_curbuf_later(INVERTED);
+ }
/*
* Set '[ and '] marks.
@@ -2043,10 +2075,11 @@ void op_tilde(oparg_T *oap)
curbuf->b_op_end = oap->end;
if (oap->line_count > p_report) {
- if (oap->line_count == 1)
+ if (oap->line_count == 1) {
MSG(_("1 line changed"));
- else
+ } else {
smsg(_("%" PRId64 " lines changed"), (int64_t)oap->line_count);
+ }
}
}
@@ -2070,8 +2103,9 @@ static int swapchars(int op_type, pos_T *pos, int length)
todo -= len - 1;
}
did_change |= swapchar(op_type, pos);
- if (inc(pos) == -1) /* at end of file */
+ if (inc(pos) == -1) { // at end of file
break;
+ }
}
return did_change;
}
@@ -2094,7 +2128,7 @@ bool swapchar(int op_type, pos_T *pos)
if (op_type == OP_UPPER && c == 0xdf) {
pos_T sp = curwin->w_cursor;
- /* Special handling of German sharp s: change to "SS". */
+ // Special handling of German sharp s: change to "SS".
curwin->w_cursor = *pos;
del_char(false);
ins_char('S');
@@ -2140,16 +2174,16 @@ bool swapchar(int op_type, pos_T *pos)
void op_insert(oparg_T *oap, long count1)
{
long ins_len, pre_textlen = 0;
- char_u *firstline, *ins_text;
+ char_u *firstline, *ins_text;
colnr_T ind_pre = 0;
struct block_def bd;
int i;
pos_T t1;
- /* edit() changes this - record it for OP_APPEND */
+ // edit() changes this - record it for OP_APPEND
bd.is_MAX = (curwin->w_curswant == MAXCOL);
- /* vis block is still marked. Get rid of it now. */
+ // vis block is still marked. Get rid of it now.
curwin->w_cursor.lnum = oap->start.lnum;
update_screen(INVERTED);
@@ -2162,12 +2196,14 @@ void op_insert(oparg_T *oap, long count1)
unsigned old_ve_flags = ve_flags;
ve_flags = VE_ALL;
- if (u_save_cursor() == FAIL)
+ if (u_save_cursor() == FAIL) {
return;
+ }
coladvance_force(oap->op_type == OP_APPEND
? oap->end_vcol + 1 : getviscol());
- if (oap->op_type == OP_APPEND)
+ if (oap->op_type == OP_APPEND) {
--curwin->w_cursor.col;
+ }
ve_flags = old_ve_flags;
}
// Get the info about the block before entering the text
@@ -2184,18 +2220,19 @@ void op_insert(oparg_T *oap, long count1)
if (oap->op_type == OP_APPEND) {
if (oap->motion_type == kMTBlockWise
- && curwin->w_cursor.coladd == 0
- ) {
- /* Move the cursor to the character right of the block. */
+ && curwin->w_cursor.coladd == 0) {
+ // Move the cursor to the character right of the block.
curwin->w_set_curswant = TRUE;
while (*get_cursor_pos_ptr() != NUL
- && (curwin->w_cursor.col < bd.textcol + bd.textlen))
+ && (curwin->w_cursor.col < bd.textcol + bd.textlen)) {
++curwin->w_cursor.col;
+ }
if (bd.is_short && !bd.is_MAX) {
/* First line was too short, make it longer and adjust the
* values in "bd". */
- if (u_save_cursor() == FAIL)
+ if (u_save_cursor() == FAIL) {
return;
+ }
for (i = 0; i < bd.endspaces; i++) {
ins_char(' ');
}
@@ -2227,8 +2264,9 @@ void op_insert(oparg_T *oap, long count1)
/* If user has moved off this line, we don't know what to do, so do
* nothing.
* Also don't repeat the insert when Insert mode ended with CTRL-C. */
- if (curwin->w_cursor.lnum != oap->start.lnum || got_int)
+ if (curwin->w_cursor.lnum != oap->start.lnum || got_int) {
return;
+ }
if (oap->motion_type == kMTBlockWise) {
struct block_def bd2;
@@ -2264,7 +2302,7 @@ void op_insert(oparg_T *oap, long count1)
int t = getviscol2(curbuf->b_op_start_orig.col,
curbuf->b_op_start_orig.coladd);
oap->start.col = curbuf->b_op_start_orig.col;
- /* reset pre_textlen to the value of OP_INSERT */
+ // reset pre_textlen to the value of OP_INSERT
pre_textlen += bd.textlen;
pre_textlen -= t - oap->start_vcol;
oap->start_vcol = t;
@@ -2281,8 +2319,9 @@ void op_insert(oparg_T *oap, long count1)
if (!bd.is_MAX || bd2.textlen < bd.textlen) {
if (oap->op_type == OP_APPEND) {
pre_textlen += bd2.textlen - bd.textlen;
- if (bd2.endspaces)
+ if (bd2.endspaces) {
--bd2.textlen;
+ }
}
bd.textcol = bd2.textcol;
bd.textlen = bd2.textlen;
@@ -2342,18 +2381,20 @@ int op_change(oparg_T *oap)
if (oap->motion_type == kMTLineWise) {
l = 0;
if (!p_paste && curbuf->b_p_si
- && !curbuf->b_p_cin
- )
+ && !curbuf->b_p_cin) {
can_si = true; // It's like opening a new line, do si
+ }
}
/* First delete the text in the region. In an empty buffer only need to
* save for undo */
if (curbuf->b_ml.ml_flags & ML_EMPTY) {
- if (u_save_cursor() == FAIL)
+ if (u_save_cursor() == FAIL) {
return FALSE;
- } else if (op_delete(oap) == FAIL)
+ }
+ } else if (op_delete(oap) == FAIL) {
return FALSE;
+ }
if ((l > curwin->w_cursor.col) && !LINEEMPTY(curwin->w_cursor.lnum)
&& !virtual_op) {
@@ -2439,6 +2480,7 @@ int op_change(oparg_T *oap)
xfree(ins_text);
}
}
+ auto_format(false, true);
return retval;
}
@@ -2464,9 +2506,9 @@ 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)
+/// 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)
void free_register(yankreg_T *reg)
FUNC_ATTR_NONNULL_ALL
{
@@ -2496,7 +2538,7 @@ bool op_yank(oparg_T *oap, bool message, int deleting)
return false;
}
if (oap->regname == '_') {
- return true; // black hole: nothing to do
+ return true; // black hole: nothing to do
}
yankreg_T *reg = get_yank_register(oap->regname, YREG_YANK);
@@ -2558,8 +2600,9 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
// Visual block mode
reg->y_width = oap->end_vcol - oap->start_vcol;
- if (curwin->w_curswant == MAXCOL && reg->y_width > 0)
+ if (curwin->w_curswant == MAXCOL && reg->y_width > 0) {
reg->y_width--;
+ }
}
for (; lnum <= yankendlnum; lnum++, y_idx++) {
@@ -2573,8 +2616,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
reg->y_array[y_idx] = vim_strsave(ml_get(lnum));
break;
- case kMTCharWise:
- {
+ case kMTCharWise: {
colnr_T startcol = 0, endcol = MAXCOL;
int is_oneChar = false;
colnr_T cs, ce;
@@ -2620,11 +2662,11 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
}
}
}
- if (endcol == MAXCOL)
+ if (endcol == MAXCOL) {
endcol = (colnr_T)STRLEN(p);
+ }
if (startcol > endcol
- || is_oneChar
- ) {
+ || is_oneChar) {
bd.textlen = 0;
} else {
bd.textlen = endcol - startcol + oap->inclusive;
@@ -2635,14 +2677,15 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
}
// NOTREACHED
case kMTUnknown:
- abort();
+ abort();
}
}
- if (curr != reg) { /* append the new block to the old block */
+ if (curr != reg) { // append the new block to the old block
new_ptr = xmalloc(sizeof(char_u *) * (curr->y_size + reg->y_size));
- for (j = 0; j < curr->y_size; ++j)
+ for (j = 0; j < curr->y_size; ++j) {
new_ptr[j] = curr->y_array[j];
+ }
xfree(curr->y_array);
curr->y_array = new_ptr;
@@ -2663,10 +2706,12 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
xfree(reg->y_array[0]);
curr->y_array[j++] = pnew;
y_idx = 1;
- } else
+ } else {
y_idx = 0;
- while (y_idx < reg->y_size)
+ }
+ while (y_idx < reg->y_size) {
curr->y_array[j++] = reg->y_array[y_idx++];
+ }
curr->y_size = j;
xfree(reg->y_array);
}
@@ -2719,8 +2764,8 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
// Copy a block range into a register.
// If "exclude_trailing_space" is set, do not copy trailing whitespaces.
-static void yank_copy_line(yankreg_T *reg, struct block_def *bd,
- size_t y_idx, bool exclude_trailing_space)
+static void yank_copy_line(yankreg_T *reg, struct block_def *bd, size_t y_idx,
+ bool exclude_trailing_space)
FUNC_ATTR_NONNULL_ALL
{
if (exclude_trailing_space) {
@@ -2831,24 +2876,25 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
int delcount;
int incr = 0;
struct block_def bd;
- char_u **y_array = NULL;
+ char_u **y_array = NULL;
long nr_lines = 0;
pos_T new_cursor;
int indent;
- int orig_indent = 0; /* init for gcc */
- int indent_diff = 0; /* init for gcc */
- int first_indent = TRUE;
+ int orig_indent = 0; // init for gcc
+ int indent_diff = 0; // init for gcc
+ bool first_indent = true;
int lendiff = 0;
pos_T old_pos;
- char_u *insert_string = NULL;
+ char_u *insert_string = NULL;
bool allocated = false;
long cnt;
- if (flags & PUT_FIXINDENT)
+ if (flags & PUT_FIXINDENT) {
orig_indent = get_indent();
+ }
- curbuf->b_op_start = curwin->w_cursor; /* default for '[ mark */
- curbuf->b_op_end = curwin->w_cursor; /* default for '] mark */
+ curbuf->b_op_start = curwin->w_cursor; // default for '[ mark
+ curbuf->b_op_end = curwin->w_cursor; // default for '] mark
/*
* Using inserted text works differently, because the register includes
@@ -2859,7 +2905,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
// PUT_LINE has special handling below which means we use 'i' to start.
char command_start_char = non_linewise_vis ? 'c' :
- (flags & PUT_LINE ? 'i' : (dir == FORWARD ? 'a' : 'i'));
+ (flags & PUT_LINE ? 'i' : (dir == FORWARD ? 'a' : 'i'));
// To avoid 'autoindent' on linewise puts, create a new line with `:put _`.
if (flags & PUT_LINE) {
@@ -2961,27 +3007,30 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
y_size = 0;
ptr = insert_string;
while (ptr != NULL) {
- if (y_array != NULL)
+ if (y_array != NULL) {
y_array[y_size] = ptr;
+ }
++y_size;
ptr = vim_strchr(ptr, '\n');
if (ptr != NULL) {
- if (y_array != NULL)
+ if (y_array != NULL) {
*ptr = NUL;
+ }
++ptr;
- /* A trailing '\n' makes the register linewise. */
+ // A trailing '\n' makes the register linewise.
if (*ptr == NUL) {
y_type = kMTLineWise;
break;
}
}
}
- if (y_array != NULL)
+ if (y_array != NULL) {
break;
+ }
y_array = (char_u **)xmalloc(y_size * sizeof(char_u *));
}
} else {
- y_size = 1; /* use fake one-line yank register */
+ y_size = 1; // use fake one-line yank register
y_array = &insert_string;
}
} else {
@@ -3029,12 +3078,12 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
dir = FORWARD;
}
if (flags & PUT_LINE_FORWARD) {
- /* Must be "p" for a Visual block, put lines below the block. */
+ // Must be "p" for a Visual block, put lines below the block.
curwin->w_cursor = curbuf->b_visual.vi_end;
dir = FORWARD;
}
- curbuf->b_op_start = curwin->w_cursor; /* default for '[ mark */
- curbuf->b_op_end = curwin->w_cursor; /* default for '] mark */
+ curbuf->b_op_start = curwin->w_cursor; // default for '[ mark
+ curbuf->b_op_end = curwin->w_cursor; // default for '] mark
}
if (flags & PUT_LINE) { // :put command or "p" in Visual line mode.
@@ -3043,7 +3092,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
if (y_size == 0 || y_array == NULL) {
EMSG2(_("E353: Nothing in register %s"),
- regname == 0 ? (char_u *)"\"" : transchar(regname));
+ regname == 0 ? (char_u *)"\"" : transchar(regname));
goto end;
}
@@ -3069,7 +3118,8 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
}
// In an empty buffer the empty line is going to be replaced, include
// it in the saved lines.
- if ((BUFEMPTY() ? u_save(0, 2) : u_save(lnum - 1, lnum)) == FAIL) {
+ if ((buf_is_empty(curbuf) ?
+ u_save(0, 2) : u_save(lnum - 1, lnum)) == FAIL) {
goto end;
}
if (dir == FORWARD) {
@@ -3112,10 +3162,11 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
colnr_T endcol2 = 0;
if (dir == FORWARD && c != NUL) {
- if (ve_flags == VE_ALL)
+ if (ve_flags == VE_ALL) {
getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2);
- else
+ } else {
getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col);
+ }
// move to start of next multi-byte character
curwin->w_cursor.col += utfc_ptr2len(get_cursor_pos_ptr());
@@ -3135,10 +3186,12 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
curwin->w_cursor.col++;
}
if (c == TAB) {
- if (dir == BACKWARD && curwin->w_cursor.col)
+ if (dir == BACKWARD && curwin->w_cursor.col) {
curwin->w_cursor.col--;
- if (dir == FORWARD && col - 1 == endcol2)
+ }
+ if (dir == FORWARD && col - 1 == endcol2) {
curwin->w_cursor.col++;
+ }
}
}
curwin->w_cursor.coladd = 0;
@@ -3155,7 +3208,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
vcol = 0;
delcount = 0;
- /* add a new line */
+ // add a new line
if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) {
if (ml_append(curbuf->b_ml.ml_line_count, (char_u *)"",
(colnr_T)1, false) == FAIL) {
@@ -3164,21 +3217,21 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
nr_lines++;
lines_appended = 1;
}
- /* get the old line and advance to the position to insert at */
+ // get the old line and advance to the position to insert at
oldp = get_cursor_line_ptr();
oldlen = STRLEN(oldp);
for (ptr = oldp; vcol < col && *ptr; ) {
- /* Count a tab for what it's worth (if list mode not on) */
- incr = lbr_chartabsize_adv(oldp, &ptr, (colnr_T)vcol);
+ // Count a tab for what it's worth (if list mode not on)
+ incr = lbr_chartabsize_adv(oldp, &ptr, vcol);
vcol += incr;
}
bd.textcol = (colnr_T)(ptr - oldp);
shortline = (vcol < col) || (vcol == col && !*ptr);
- if (vcol < col) /* line too short, padd with spaces */
+ if (vcol < col) { // line too short, padd with spaces
bd.startspaces = col - vcol;
- else if (vcol > col) {
+ } else if (vcol > col) {
bd.endspaces = vcol - col;
bd.startspaces = incr - bd.endspaces;
--bd.textcol;
@@ -3244,18 +3297,19 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
delcount, addcount, kExtmarkUndo);
++curwin->w_cursor.lnum;
- if (i == 0)
+ if (i == 0) {
curwin->w_cursor.col += bd.startspaces;
+ }
}
changed_lines(lnum, 0, curbuf->b_op_start.lnum + (linenr_T)y_size
- - (linenr_T)nr_lines , nr_lines, true);
+ - (linenr_T)nr_lines, nr_lines, true);
- /* Set '[ mark. */
+ // Set '[ mark.
curbuf->b_op_start = curwin->w_cursor;
curbuf->b_op_start.lnum = lnum;
- /* adjust '] mark */
+ // adjust '] mark
curbuf->b_op_end.lnum = curwin->w_cursor.lnum - 1;
curbuf->b_op_end.col = bd.textcol + (colnr_T)totlen - 1;
curbuf->b_op_end.coladd = 0;
@@ -3265,12 +3319,14 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
curwin->w_cursor = curbuf->b_op_end;
curwin->w_cursor.col++;
- /* in Insert mode we might be after the NUL, correct for that */
+ // in Insert mode we might be after the NUL, correct for that
len = (colnr_T)STRLEN(get_cursor_line_ptr());
- if (curwin->w_cursor.col > len)
+ if (curwin->w_cursor.col > len) {
curwin->w_cursor.col = len;
- } else
+ }
+ } else {
curwin->w_cursor.lnum = lnum;
+ }
} else {
// Character or Line mode
if (y_type == kMTCharWise) {
@@ -3291,8 +3347,9 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
/*
* Line mode: BACKWARD is the same as FORWARD on the previous line
*/
- else if (dir == BACKWARD)
+ else if (dir == BACKWARD) {
--lnum;
+ }
new_cursor = curwin->w_cursor;
// simple case: insert into one line at a time
@@ -3303,7 +3360,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
if (VIsual_active) {
end_lnum = curbuf->b_visual.vi_end.lnum;
if (end_lnum < curbuf->b_visual.vi_start.lnum) {
- end_lnum = curbuf->b_visual.vi_start.lnum;
+ end_lnum = curbuf->b_visual.vi_start.lnum;
}
if (end_lnum > start_lnum) {
// "col" is valid for the first line, in following lines
@@ -3360,7 +3417,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
}
} while (VIsual_active && lnum <= end_lnum);
- if (VIsual_active) { /* reset lnum to the last visual line */
+ if (VIsual_active) { // reset lnum to the last visual line
lnum--;
}
@@ -3381,7 +3438,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
lnum = new_cursor.lnum;
ptr = ml_get(lnum) + col;
totlen = STRLEN(y_array[y_size - 1]);
- newp = (char_u *) xmalloc((size_t)(STRLEN(ptr) + totlen + 1));
+ newp = (char_u *)xmalloc((size_t)(STRLEN(ptr) + totlen + 1));
STRCPY(newp, y_array[y_size - 1]);
STRCAT(newp, ptr);
// insert second line
@@ -3412,23 +3469,26 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
old_pos = curwin->w_cursor;
curwin->w_cursor.lnum = lnum;
ptr = ml_get(lnum);
- if (cnt == count && i == y_size - 1)
+ if (cnt == count && i == y_size - 1) {
lendiff = (int)STRLEN(ptr);
- if (*ptr == '#' && preprocs_left())
- indent = 0; /* Leave # lines at start */
- else if (*ptr == NUL)
- indent = 0; /* Ignore empty lines */
- else if (first_indent) {
+ }
+ if (*ptr == '#' && preprocs_left()) {
+ indent = 0; // Leave # lines at start
+ } else if (*ptr == NUL) {
+ indent = 0; // Ignore empty lines
+ } else if (first_indent) {
indent_diff = orig_indent - get_indent();
indent = orig_indent;
- first_indent = FALSE;
- } else if ((indent = get_indent() + indent_diff) < 0)
+ first_indent = false;
+ } else if ((indent = get_indent() + indent_diff) < 0) {
indent = 0;
+ }
(void)set_indent(indent, SIN_NOMARK);
curwin->w_cursor = old_pos;
- /* remember how many chars were removed */
- if (cnt == count && i == y_size - 1)
+ // remember how many chars were removed
+ if (cnt == count && i == y_size - 1) {
lendiff -= (int)STRLEN(ml_get(lnum));
+ }
}
}
@@ -3447,8 +3507,9 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
(int)y_size-1, lastsize, totsize,
kExtmarkUndo);
} else if (y_type == kMTLineWise && flags & PUT_LINE_SPLIT) {
- extmark_splice(curbuf, (int)new_cursor.lnum-1, col, 0, 0, 0,
- (int)y_size+1, 0, totsize+1, kExtmarkUndo);
+ // Account for last pasted NL + last NL
+ extmark_splice(curbuf, (int)new_cursor.lnum-1, col + 1, 0, 0, 0,
+ (int)y_size+1, 0, totsize+2, kExtmarkUndo);
}
}
@@ -3456,8 +3517,9 @@ error:
// Adjust marks.
if (y_type == kMTLineWise) {
curbuf->b_op_start.col = 0;
- if (dir == FORWARD)
+ if (dir == FORWARD) {
curbuf->b_op_start.lnum++;
+ }
}
ExtmarkOp kind = (y_type == kMTLineWise && !(flags & PUT_LINE_SPLIT))
@@ -3474,17 +3536,18 @@ error:
curbuf->b_op_start.lnum, nr_lines, true);
}
- /* put '] mark at last inserted character */
+ // put '] mark at last inserted character
curbuf->b_op_end.lnum = lnum;
- /* correct length for change in indent */
+ // correct length for change in indent
col = (colnr_T)STRLEN(y_array[y_size - 1]) - lendiff;
- if (col > 1)
+ if (col > 1) {
curbuf->b_op_end.col = col - 1;
- else
+ } else {
curbuf->b_op_end.col = 0;
+ }
if (flags & PUT_CURSLINE) {
- /* ":put": put cursor on last inserted line */
+ // ":put": put cursor on last inserted line
curwin->w_cursor.lnum = lnum;
beginline(BL_WHITE | BL_FIX);
} else if (flags & PUT_CURSEND) {
@@ -3503,11 +3566,13 @@ error:
} else if (y_type == kMTLineWise) {
// put cursor on first non-blank in first inserted line
curwin->w_cursor.col = 0;
- if (dir == FORWARD)
+ if (dir == FORWARD) {
++curwin->w_cursor.lnum;
+ }
beginline(BL_WHITE | BL_FIX);
- } else /* put cursor on first inserted character */
+ } else { // put cursor on first inserted character
curwin->w_cursor = new_cursor;
+ }
}
}
@@ -3515,14 +3580,16 @@ error:
curwin->w_set_curswant = TRUE;
end:
- if (allocated)
+ if (allocated) {
xfree(insert_string);
- if (regname == '=')
+ }
+ if (regname == '=') {
xfree(y_array);
+ }
VIsual_active = FALSE;
- /* If the cursor is past the end of the line put it at the end. */
+ // If the cursor is past the end of the line put it at the end.
adjust_cursor_eol();
} // NOLINT(readability/fn_size)
@@ -3536,13 +3603,13 @@ void adjust_cursor_eol(void)
&& gchar_cursor() == NUL
&& (ve_flags & VE_ONEMORE) == 0
&& !(restart_edit || (State & INSERT))) {
- /* Put the cursor on the last character in the line. */
+ // Put the cursor on the last character in the line.
dec_cursor();
if (ve_flags == VE_ALL) {
colnr_T scol, ecol;
- /* Coladd is set to the width of the last character. */
+ // Coladd is set to the width of the last character.
getvcol(curwin, &curwin->w_cursor, &scol, NULL, &ecol);
curwin->w_cursor.coladd = ecol - scol + 1;
}
@@ -3559,24 +3626,30 @@ int preprocs_left(void)
&& curbuf->b_ind_hash_comment == 0));
}
-/* Return the character name of the register with the given number */
+// Return the character name of the register with the given number
int get_register_name(int num)
{
- if (num == -1)
+ if (num == -1) {
return '"';
- else if (num < 10)
+ } else if (num < 10) {
return num + '0';
- else if (num == DELETION_REGISTER)
+ } else if (num == DELETION_REGISTER) {
return '-';
- else if (num == STAR_REGISTER)
+ } else if (num == STAR_REGISTER) {
return '*';
- else if (num == PLUS_REGISTER)
+ } else if (num == PLUS_REGISTER) {
return '+';
- else {
+ } else {
return num + 'a' - 10;
}
}
+/// @return the index of the register "" points to.
+int get_unname_register(void)
+{
+ return y_previous == NULL ? -1 : (int)(y_previous - &y_regs[0]);
+}
+
/*
* ":dis" and ":registers": Display the contents of the yank registers.
*/
@@ -3589,8 +3662,9 @@ void ex_display(exarg_T *eap)
int clen;
char_u type[2];
- if (arg != NULL && *arg == NUL)
+ if (arg != NULL && *arg == NUL) {
arg = NULL;
+ }
int attr = HL_ATTR(HLF_8);
// Highlight title
@@ -3598,23 +3672,28 @@ void ex_display(exarg_T *eap)
for (int i = -1; i < NUM_REGISTERS && !got_int; i++) {
name = get_register_name(i);
switch (get_reg_type(name, NULL)) {
- case kMTLineWise: type[0] = 'l'; break;
- case kMTCharWise: type[0] = 'c'; break;
- default: type[0] = 'b'; break;
+ case kMTLineWise:
+ type[0] = 'l'; break;
+ case kMTCharWise:
+ type[0] = 'c'; break;
+ default:
+ type[0] = 'b'; break;
}
if (arg != NULL && vim_strchr(arg, name) == NULL) {
- continue; /* did not ask for this register */
+ continue; // did not ask for this register
}
if (i == -1) {
- if (y_previous != NULL)
+ if (y_previous != NULL) {
yb = y_previous;
- else
+ } else {
yb = &(y_regs[0]);
- } else
+ }
+ } else {
yb = &(y_regs[i]);
+ }
get_clipboard(name, &yb, true);
@@ -3684,7 +3763,7 @@ void ex_display(exarg_T *eap)
* display alternate file name
*/
if ((arg == NULL || vim_strchr(arg, '%') != NULL) && !got_int) {
- char_u *fname;
+ char_u *fname;
linenr_T dummy;
if (buflist_name_nr(0, &fname, &dummy) != FAIL) {
@@ -3712,15 +3791,11 @@ void ex_display(exarg_T *eap)
}
}
-/*
- * display a string for do_dis()
- * truncate at end of screen line
- */
-static void
-dis_msg(
- const char_u *p,
- bool skip_esc // if true, ignore trailing ESC
-)
+/// display a string for do_dis()
+/// truncate at end of screen line
+///
+/// @param skip_esc if true, ignore trailing ESC
+static void dis_msg(const char_u *p, bool skip_esc)
FUNC_ATTR_NONNULL_ALL
{
int n;
@@ -3733,8 +3808,9 @@ dis_msg(
if ((l = utfc_ptr2len(p)) > 1) {
msg_outtrans_len(p, l);
p += l;
- } else
+ } else {
msg_outtrans_len(p++, 1);
+ }
}
os_breakcheck();
}
@@ -3750,9 +3826,7 @@ dis_msg(
/// @param include_space - whether to skip space following the comment leader
/// @param[out] is_comment - whether the current line ends with an unclosed
/// comment.
-char_u *skip_comment(
- char_u *line, bool process, bool include_space, bool *is_comment
-)
+char_u *skip_comment(char_u *line, bool process, bool include_space, bool *is_comment)
{
char_u *comment_flags = NULL;
int lead_len;
@@ -3781,8 +3855,9 @@ char_u *skip_comment(
lead_len = get_leader_len(line, &comment_flags, false, include_space);
- if (lead_len == 0)
+ if (lead_len == 0) {
return line;
+ }
/* Find:
* - COM_END,
@@ -3816,25 +3891,21 @@ char_u *skip_comment(
// to set those marks.
//
// return FAIL for failure, OK otherwise
-int do_join(size_t count,
- int insert_space,
- int save_undo,
- int use_formatoptions,
- bool setmark)
+int do_join(size_t count, int insert_space, int save_undo, int use_formatoptions, bool setmark)
{
- char_u *curr = NULL;
- char_u *curr_start = NULL;
- char_u *cend;
- char_u *newp;
- char_u *spaces; /* number of spaces inserted before a line */
+ char_u *curr = NULL;
+ char_u *curr_start = NULL;
+ char_u *cend;
+ char_u *newp;
+ char_u *spaces; // number of spaces inserted before a line
int endcurr1 = NUL;
int endcurr2 = NUL;
- int currsize = 0; /* size of the current line */
- int sumsize = 0; /* size of the long new line */
+ int currsize = 0; // size of the current line
+ int sumsize = 0; // size of the long new line
linenr_T t;
colnr_T col = 0;
int ret = OK;
- int *comments = NULL;
+ int *comments = NULL;
int remove_comments = (use_formatoptions == TRUE)
&& has_format_option(FO_REMOVE_COMS);
bool prev_was_comment = false;
@@ -3884,13 +3955,14 @@ int do_join(size_t count,
|| (utf_ptr2char(curr) < 0x100 && endcurr1 < 0x100))
&& (!has_format_option(FO_MBYTE_JOIN2)
|| (utf_ptr2char(curr) < 0x100 && !utf_eat_space(endcurr1))
- || (endcurr1 < 0x100 && !utf_eat_space(utf_ptr2char(curr))))
- ) {
- /* don't add a space if the line is ending in a space */
- if (endcurr1 == ' ')
+ || (endcurr1 < 0x100 &&
+ !utf_eat_space(utf_ptr2char(curr))))) {
+ // don't add a space if the line is ending in a space
+ if (endcurr1 == ' ') {
endcurr1 = endcurr2;
- else
+ } else {
++spaces[t];
+ }
// Extra space when 'joinspaces' set and line ends in '.', '?', or '!'.
if (p_js && (endcurr1 == '.' || endcurr1 == '?' || endcurr1 == '!')) {
++spaces[t];
@@ -3955,8 +4027,8 @@ int do_join(size_t count,
const int spaces_removed = (int)((curr - curr_start) - spaces[t]);
linenr_T lnum = curwin->w_cursor.lnum + t;
colnr_T mincol = (colnr_T)0;
- long lnum_amount = (linenr_T)-t;
- long col_amount = (long)(cend - newp - spaces_removed);
+ long lnum_amount = -t;
+ long col_amount = (cend - newp - spaces_removed);
mark_col_adjust(lnum, mincol, lnum_amount, col_amount, spaces_removed);
@@ -3965,10 +4037,12 @@ int do_join(size_t count,
}
curr = curr_start = ml_get((linenr_T)(curwin->w_cursor.lnum + t - 1));
- if (remove_comments)
+ if (remove_comments) {
curr += comments[t - 1];
- if (insert_space && t > 1)
+ }
+ if (insert_space && t > 1) {
curr = skipwhite(curr);
+ }
currsize = (int)STRLEN(curr);
}
@@ -4000,7 +4074,7 @@ int do_join(size_t count,
/*
* Set the cursor column:
* Vi compatible: use the column of the first join
- * vim: use the column of the last join
+ * vim: use the column of the last join
*/
curwin->w_cursor.col =
(vim_strchr(p_cpo, CPO_JOINCOL) != NULL ? currsize : col);
@@ -4011,8 +4085,9 @@ int do_join(size_t count,
theend:
xfree(spaces);
- if (remove_comments)
+ if (remove_comments) {
xfree(comments);
+ }
return ret;
}
@@ -4021,15 +4096,17 @@ theend:
* the first line. White-space is ignored. Note that the whole of
* 'leader1' must match 'leader2_len' characters from 'leader2' -- webb
*/
-static int same_leader(linenr_T lnum, int leader1_len, char_u *leader1_flags, int leader2_len, char_u *leader2_flags)
+static int same_leader(linenr_T lnum, int leader1_len, char_u *leader1_flags, int leader2_len,
+ char_u *leader2_flags)
{
int idx1 = 0, idx2 = 0;
- char_u *p;
- char_u *line1;
- char_u *line2;
+ char_u *p;
+ char_u *line1;
+ char_u *line2;
- if (leader1_len == 0)
+ if (leader1_len == 0) {
return leader2_len == 0;
+ }
/*
* If first leader has 'f' flag, the lines can be joined only if the
@@ -4040,18 +4117,24 @@ static int same_leader(linenr_T lnum, int leader1_len, char_u *leader1_flags, in
*/
if (leader1_flags != NULL) {
for (p = leader1_flags; *p && *p != ':'; ++p) {
- if (*p == COM_FIRST)
+ if (*p == COM_FIRST) {
return leader2_len == 0;
- if (*p == COM_END)
+ }
+ if (*p == COM_END) {
return FALSE;
+ }
if (*p == COM_START) {
- if (*(ml_get(lnum) + leader1_len) == NUL)
+ if (*(ml_get(lnum) + leader1_len) == NUL) {
return FALSE;
- if (leader2_flags == NULL || leader2_len == 0)
+ }
+ if (leader2_flags == NULL || leader2_len == 0) {
return FALSE;
- for (p = leader2_flags; *p && *p != ':'; ++p)
- if (*p == COM_MIDDLE)
+ }
+ for (p = leader2_flags; *p && *p != ':'; ++p) {
+ if (*p == COM_MIDDLE) {
return TRUE;
+ }
+ }
return FALSE;
}
}
@@ -4062,30 +4145,30 @@ static int same_leader(linenr_T lnum, int leader1_len, char_u *leader1_flags, in
* The first line has to be saved, only one line can be locked at a time.
*/
line1 = vim_strsave(ml_get(lnum));
- for (idx1 = 0; ascii_iswhite(line1[idx1]); ++idx1)
+ for (idx1 = 0; ascii_iswhite(line1[idx1]); ++idx1) {
;
+ }
line2 = ml_get(lnum + 1);
for (idx2 = 0; idx2 < leader2_len; ++idx2) {
if (!ascii_iswhite(line2[idx2])) {
- if (line1[idx1++] != line2[idx2])
+ if (line1[idx1++] != line2[idx2]) {
break;
- } else
- while (ascii_iswhite(line1[idx1]))
+ }
+ } else {
+ while (ascii_iswhite(line1[idx1])) {
++idx1;
+ }
+ }
}
xfree(line1);
return idx2 == leader2_len && idx1 == leader1_len;
}
-/*
- * Implementation of the format operator 'gq'.
- */
-void
-op_format(
- oparg_T *oap,
- int keep_cursor /* keep cursor on same text char */
-)
+/// Implementation of the format operator 'gq'.
+///
+/// @param keep_cursor keep cursor on same text char
+void op_format(oparg_T *oap, int keep_cursor)
{
long old_line_count = curbuf->b_ml.ml_line_count;
@@ -4094,21 +4177,24 @@ op_format(
curwin->w_cursor = oap->cursor_start;
if (u_save((linenr_T)(oap->start.lnum - 1),
- (linenr_T)(oap->end.lnum + 1)) == FAIL)
+ (linenr_T)(oap->end.lnum + 1)) == FAIL) {
return;
+ }
curwin->w_cursor = oap->start;
- if (oap->is_VIsual)
- /* When there is no change: need to remove the Visual selection */
+ if (oap->is_VIsual) {
+ // When there is no change: need to remove the Visual selection
redraw_curbuf_later(INVERTED);
+ }
- /* Set '[ mark at the start of the formatted area */
+ // Set '[ mark at the start of the formatted area
curbuf->b_op_start = oap->start;
/* For "gw" remember the cursor position and put it back below (adjusted
* for joined and split lines). */
- if (keep_cursor)
+ if (keep_cursor) {
saved_cursor = oap->cursor_start;
+ }
format_lines(oap->line_count, keep_cursor);
@@ -4117,13 +4203,14 @@ op_format(
* If the cursor was moved one line back (e.g. with "Q}") go to the next
* line, so "." will do the next lines.
*/
- if (oap->end_adjusted && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
+ if (oap->end_adjusted && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) {
++curwin->w_cursor.lnum;
+ }
beginline(BL_WHITE | BL_FIX);
old_line_count = curbuf->b_ml.ml_line_count - old_line_count;
msgmore(old_line_count);
- /* put '] mark on the end of the formatted area */
+ // put '] mark on the end of the formatted area
curbuf->b_op_end = curwin->w_cursor;
if (keep_cursor) {
@@ -4151,25 +4238,22 @@ op_format(
*/
void op_formatexpr(oparg_T *oap)
{
- if (oap->is_VIsual)
- /* When there is no change: need to remove the Visual selection */
+ if (oap->is_VIsual) {
+ // When there is no change: need to remove the Visual selection
redraw_curbuf_later(INVERTED);
+ }
- if (fex_format(oap->start.lnum, oap->line_count, NUL) != 0)
+ if (fex_format(oap->start.lnum, oap->line_count, NUL) != 0) {
/* As documented: when 'formatexpr' returns non-zero fall back to
* internal formatting. */
op_format(oap, FALSE);
+ }
}
-int
-fex_format(
- linenr_T lnum,
- long count,
- int c /* character to be inserted */
-)
+/// @param c character to be inserted
+int fex_format(linenr_T lnum, long count, int c)
{
- int use_sandbox = was_set_insecurely(
- curwin, (char_u *)"formatexpr", OPT_LOCAL);
+ int use_sandbox = was_set_insecurely(curwin, (char_u *)"formatexpr", OPT_LOCAL);
int r;
char_u *fex;
@@ -4198,17 +4282,13 @@ fex_format(
return r;
}
-/*
- * Format "line_count" lines, starting at the cursor position.
- * When "line_count" is negative, format until the end of the paragraph.
- * Lines after the cursor line are saved for undo, caller must have saved the
- * first line.
- */
-void
-format_lines(
- linenr_T line_count,
- int avoid_fex /* don't use 'formatexpr' */
-)
+/// Format "line_count" lines, starting at the cursor position.
+/// When "line_count" is negative, format until the end of the paragraph.
+/// Lines after the cursor line are saved for undo, caller must have saved the
+/// first line.
+///
+/// @param avoid_fex don't use 'formatexpr'
+void format_lines(linenr_T line_count, int avoid_fex)
{
bool is_not_par; // current line not part of parag.
bool next_is_not_par; // next line not part of paragraph
@@ -4246,11 +4326,12 @@ format_lines(
is_not_par = true;
}
next_is_not_par = fmt_check_par(curwin->w_cursor.lnum
- , &next_leader_len, &next_leader_flags, do_comments
- );
+ , &next_leader_len, &next_leader_flags, do_comments
+ );
is_end_par = (is_not_par || next_is_not_par);
- if (!is_end_par && do_trail_white)
+ if (!is_end_par && do_trail_white) {
is_end_par = !ends_in_white(curwin->w_cursor.lnum - 1);
+ }
curwin->w_cursor.lnum--;
for (count = line_count; count != 0 && !got_int; --count) {
@@ -4274,23 +4355,26 @@ format_lines(
next_leader_flags = NULL;
} else {
next_is_not_par = fmt_check_par(curwin->w_cursor.lnum + 1
- , &next_leader_len, &next_leader_flags, do_comments
- );
- if (do_number_indent)
+ , &next_leader_len, &next_leader_flags, do_comments
+ );
+ if (do_number_indent) {
next_is_start_par =
(get_number_indent(curwin->w_cursor.lnum + 1) > 0);
+ }
}
advance = true;
is_end_par = (is_not_par || next_is_not_par || next_is_start_par);
- if (!is_end_par && do_trail_white)
+ if (!is_end_par && do_trail_white) {
is_end_par = !ends_in_white(curwin->w_cursor.lnum);
+ }
/*
* Skip lines that are not in a paragraph.
*/
if (is_not_par) {
- if (line_count < 0)
+ if (line_count < 0) {
break;
+ }
} else {
/*
* For the first line of a paragraph, check indent of second line.
@@ -4302,7 +4386,7 @@ format_lines(
&& curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) {
if (do_second_indent && !LINEEMPTY(curwin->w_cursor.lnum + 1)) {
if (leader_len == 0 && next_leader_len == 0) {
- /* no comment found */
+ // no comment found
second_indent =
get_indent_lnum(curwin->w_cursor.lnum + 1);
} else {
@@ -4311,11 +4395,11 @@ format_lines(
}
} else if (do_number_indent) {
if (leader_len == 0 && next_leader_len == 0) {
- /* no comment found */
+ // no comment found
second_indent =
get_number_indent(curwin->w_cursor.lnum);
} else {
- /* get_number_indent() is now "comment aware"... */
+ // get_number_indent() is now "comment aware"...
second_indent =
get_number_indent(curwin->w_cursor.lnum);
do_comments_list = 1;
@@ -4328,20 +4412,22 @@ format_lines(
*/
if (curwin->w_cursor.lnum >= curbuf->b_ml.ml_line_count
|| !same_leader(curwin->w_cursor.lnum,
- leader_len, leader_flags,
- next_leader_len, next_leader_flags)
- )
+ leader_len, leader_flags,
+ next_leader_len,
+ next_leader_flags)) {
is_end_par = true;
+ }
/*
* If we have got to the end of a paragraph, or the line is
* getting long, format it.
*/
if (is_end_par || force_format) {
- if (need_set_indent)
+ if (need_set_indent) {
/* replace indent in first line with minimal number of
* tabs and spaces, according to current options */
(void)set_indent(get_indent(), SIN_CHANGED);
+ }
// put cursor on last non-space
State = NORMAL; // don't go past end-of-line
@@ -4350,25 +4436,26 @@ format_lines(
dec_cursor();
}
- /* do the formatting, without 'showmode' */
- State = INSERT; /* for open_line() */
+ // do the formatting, without 'showmode'
+ State = INSERT; // for open_line()
smd_save = p_smd;
p_smd = FALSE;
insertchar(NUL, INSCHAR_FORMAT
- + (do_comments ? INSCHAR_DO_COM : 0)
- + (do_comments && do_comments_list
+ + (do_comments ? INSCHAR_DO_COM : 0)
+ + (do_comments && do_comments_list
? INSCHAR_COM_LIST : 0)
- + (avoid_fex ? INSCHAR_NO_FEX : 0), second_indent);
+ + (avoid_fex ? INSCHAR_NO_FEX : 0), second_indent);
State = old_State;
p_smd = smd_save;
second_indent = -1;
- /* at end of par.: need to set indent of next par. */
+ // at end of par.: need to set indent of next par.
need_set_indent = is_end_par;
if (is_end_par) {
/* When called with a negative line count, break at the
* end of the paragraph. */
- if (line_count < 0)
+ if (line_count < 0) {
break;
+ }
first_par_line = true;
}
force_format = false;
@@ -4382,8 +4469,9 @@ format_lines(
advance = false;
curwin->w_cursor.lnum++;
curwin->w_cursor.col = 0;
- if (line_count < 0 && u_save_cursor() == FAIL)
+ if (line_count < 0 && u_save_cursor() == FAIL) {
break;
+ }
if (next_leader_len > 0) {
(void)del_bytes(next_leader_len, false, false);
mark_col_adjust(curwin->w_cursor.lnum, (colnr_T)0, 0L,
@@ -4420,11 +4508,12 @@ format_lines(
*/
static int ends_in_white(linenr_T lnum)
{
- char_u *s = ml_get(lnum);
+ char_u *s = ml_get(lnum);
size_t l;
- if (*s == NUL)
+ if (*s == NUL) {
return FALSE;
+ }
l = STRLEN(s) - 1;
return ascii_iswhite(s[l]);
}
@@ -4439,22 +4528,24 @@ static int ends_in_white(linenr_T lnum)
*/
static int fmt_check_par(linenr_T lnum, int *leader_len, char_u **leader_flags, int do_comments)
{
- char_u *flags = NULL; /* init for GCC */
- char_u *ptr;
+ char_u *flags = NULL; // init for GCC
+ char_u *ptr;
ptr = ml_get(lnum);
- if (do_comments)
- *leader_len = get_leader_len(ptr, leader_flags, FALSE, TRUE);
- else
+ if (do_comments) {
+ *leader_len = get_leader_len(ptr, leader_flags, false, true);
+ } else {
*leader_len = 0;
+ }
if (*leader_len > 0) {
/*
* Search for 'e' flag in comment leader flags.
*/
flags = *leader_flags;
- while (*flags && *flags != ':' && *flags != COM_END)
+ while (*flags && *flags != ':' && *flags != COM_END) {
++flags;
+ }
}
return *skipwhite(ptr + *leader_len) == NUL
@@ -4474,13 +4565,13 @@ int paragraph_start(linenr_T lnum)
int next_leader_len = 0; // leader len of next line
char_u *next_leader_flags = NULL; // flags for leader of next line
- if (lnum <= 1)
- return TRUE; /* start of the file */
-
+ if (lnum <= 1) {
+ return TRUE; // start of the file
+ }
p = ml_get(lnum - 1);
- if (*p == NUL)
- return TRUE; /* after empty line */
-
+ if (*p == NUL) {
+ return TRUE; // after empty line
+ }
const bool do_comments = has_format_option(FO_Q_COMS); // format comments
if (fmt_check_par(lnum - 1, &leader_len, &leader_flags, do_comments)) {
return true; // after non-paragraph line
@@ -4490,16 +4581,16 @@ int paragraph_start(linenr_T lnum)
return true; // "lnum" is not a paragraph line
}
- if (has_format_option(FO_WHITE_PAR) && !ends_in_white(lnum - 1))
- return TRUE; /* missing trailing space in previous line. */
-
- if (has_format_option(FO_Q_NUMBER) && (get_number_indent(lnum) > 0))
- return TRUE; /* numbered item starts in "lnum". */
-
+ if (has_format_option(FO_WHITE_PAR) && !ends_in_white(lnum - 1)) {
+ return TRUE; // missing trailing space in previous line.
+ }
+ if (has_format_option(FO_Q_NUMBER) && (get_number_indent(lnum) > 0)) {
+ return TRUE; // numbered item starts in "lnum".
+ }
if (!same_leader(lnum - 1, leader_len, leader_flags,
- next_leader_len, next_leader_flags))
- return TRUE; /* change of comment leader. */
-
+ next_leader_len, next_leader_flags)) {
+ return TRUE; // change of comment leader.
+ }
return FALSE;
}
@@ -4516,15 +4607,14 @@ int paragraph_start(linenr_T lnum)
* - start/endspaces is the number of columns of the first/last yanked char
* that are to be yanked.
*/
-static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum,
- bool is_del)
+static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, bool is_del)
{
int incr = 0;
- char_u *pend;
- char_u *pstart;
- char_u *line;
- char_u *prev_pstart;
- char_u *prev_pend;
+ char_u *pend;
+ char_u *pstart;
+ char_u *line;
+ char_u *prev_pstart;
+ char_u *prev_pend;
const int lbr_saved = curwin->w_p_lbr;
// Avoid a problem with unwanted linebreaks in block mode.
@@ -4545,8 +4635,8 @@ static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum,
pstart = line;
prev_pstart = line;
while (bdp->start_vcol < oap->start_vcol && *pstart) {
- /* Count a tab for what it's worth (if list mode not on) */
- incr = lbr_chartabsize(line, pstart, (colnr_T)bdp->start_vcol);
+ // Count a tab for what it's worth (if list mode not on)
+ incr = lbr_chartabsize(line, pstart, bdp->start_vcol);
bdp->start_vcol += incr;
if (ascii_iswhite(*pstart)) {
bdp->pre_whitesp += incr;
@@ -4559,7 +4649,7 @@ static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum,
MB_PTR_ADV(pstart);
}
bdp->start_char_vcols = incr;
- if (bdp->start_vcol < oap->start_vcol) { /* line too short */
+ if (bdp->start_vcol < oap->start_vcol) { // line too short
bdp->end_vcol = bdp->start_vcol;
bdp->is_short = true;
if (!is_del || oap->op_type == OP_APPEND) {
@@ -4569,8 +4659,9 @@ static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum,
/* notice: this converts partly selected Multibyte characters to
* spaces, too. */
bdp->startspaces = bdp->start_vcol - oap->start_vcol;
- if (is_del && bdp->startspaces)
+ if (is_del && bdp->startspaces) {
bdp->startspaces = bdp->start_char_vcols - bdp->startspaces;
+ }
pend = pstart;
bdp->end_vcol = bdp->start_vcol;
if (bdp->end_vcol > oap->end_vcol) { // it's all in one character
@@ -4594,9 +4685,9 @@ static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum,
} else {
prev_pend = pend;
while (bdp->end_vcol <= oap->end_vcol && *pend != NUL) {
- /* Count a tab for what it's worth (if list mode not on) */
+ // Count a tab for what it's worth (if list mode not on)
prev_pend = pend;
- incr = lbr_chartabsize_adv(line, &pend, (colnr_T)bdp->end_vcol);
+ incr = lbr_chartabsize_adv(line, &pend, bdp->end_vcol);
bdp->end_vcol += incr;
}
if (bdp->end_vcol <= oap->end_vcol
@@ -4616,17 +4707,19 @@ static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum,
bdp->endspaces = bdp->end_vcol - oap->end_vcol - 1;
if (!is_del && bdp->endspaces) {
bdp->endspaces = incr - bdp->endspaces;
- if (pend != pstart)
+ if (pend != pstart) {
pend = prev_pend;
+ }
}
}
}
bdp->end_char_vcols = incr;
- if (is_del && bdp->startspaces)
+ if (is_del && bdp->startspaces) {
pstart = prev_pstart;
+ }
bdp->textlen = (int)(pend - pstart);
}
- bdp->textcol = (colnr_T) (pstart - line);
+ bdp->textcol = (colnr_T)(pstart - line);
bdp->textstart = pstart;
curwin->w_p_lbr = lbr_saved;
}
@@ -4741,13 +4834,13 @@ void op_addsub(oparg_T *oap, linenr_T Prenum1, bool g_cmd)
int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
{
int col;
- char_u *buf1 = NULL;
+ char_u *buf1 = NULL;
char_u buf2[NUMBUFLEN];
int pre; // 'X' or 'x': hex; '0': octal; 'B' or 'b': bin
static bool hexupper = false; // 0xABC
uvarnumber_T n;
uvarnumber_T oldn;
- char_u *ptr;
+ char_u *ptr;
int c;
int todel;
int firstdigit;
@@ -4803,14 +4896,14 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
&& ptr[col - 1] == '0'
&& !utf_head_off(ptr, ptr + col - 1)
&& ascii_isxdigit(ptr[col + 1])))) {
- // In case of binary/hexadecimal pattern overlap match, rescan
+ // In case of binary/hexadecimal pattern overlap match, rescan
- col = curwin->w_cursor.col;
+ col = curwin->w_cursor.col;
- while (col > 0 && ascii_isdigit(ptr[col])) {
- col--;
- col -= utf_head_off(ptr, ptr + col);
- }
+ while (col > 0 && ascii_isdigit(ptr[col])) {
+ col--;
+ col -= utf_head_off(ptr, ptr + col);
+ }
}
if ((do_hex
@@ -4826,8 +4919,8 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
&& !utf_head_off(ptr, ptr + col - 1)
&& ascii_isbdigit(ptr[col + 1]))) {
// Found hexadecimal or binary number, move to its start.
- col--;
- col -= utf_head_off(ptr, ptr + col);
+ col--;
+ col -= utf_head_off(ptr, ptr + col);
} else {
// Search forward and then backward to find the start of number.
col = pos->col;
@@ -4925,7 +5018,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
0 + (do_bin ? STR2NR_BIN : 0)
+ (do_oct ? STR2NR_OCT : 0)
+ (do_hex ? STR2NR_HEX : 0),
- NULL, &n, maxlen);
+ NULL, &n, maxlen, false);
// ignore leading '-' for hex, octal and bin numbers
if (pre && negative) {
@@ -5033,17 +5126,16 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
// leading zeros
for (bits = 8 * sizeof(n); bits > 0; bits--) {
- if ((n >> (bits - 1)) & 0x1) {
- break;
- }
+ if ((n >> (bits - 1)) & 0x1) {
+ break;
+ }
}
while (bits > 0) {
- buf2[i++] = ((n >> --bits) & 0x1) ? '1' : '0';
+ buf2[i++] = ((n >> --bits) & 0x1) ? '1' : '0';
}
buf2[i] = '\0';
-
} else if (pre == 0) {
vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIu64, (uint64_t)n);
} else if (pre == '0') {
@@ -5101,18 +5193,18 @@ theend:
MotionType get_reg_type(int regname, colnr_T *reg_width)
{
switch (regname) {
- case '%': // file name
- case '#': // alternate file name
- case '=': // expression
- case ':': // last command line
- case '/': // last search-pattern
- case '.': // last inserted text
- case Ctrl_F: // Filename under cursor
- case Ctrl_P: // Path under cursor, expand via "path"
- case Ctrl_W: // word under cursor
- case Ctrl_A: // WORD (mnemonic All) under cursor
- case '_': // black hole: always empty
- return kMTCharWise;
+ case '%': // file name
+ case '#': // alternate file name
+ case '=': // expression
+ case ':': // last command line
+ case '/': // last search-pattern
+ case '.': // last inserted text
+ case Ctrl_F: // Filename under cursor
+ case Ctrl_P: // Path under cursor, expand via "path"
+ case Ctrl_W: // word under cursor
+ case Ctrl_A: // WORD (mnemonic All) under cursor
+ case '_': // black hole: always empty
+ return kMTCharWise;
}
if (regname != NUL && !valid_yank_reg(regname, false)) {
@@ -5137,26 +5229,25 @@ MotionType get_reg_type(int regname, colnr_T *reg_width)
/// @param[out] buf Buffer to store formatted string. The allocated size should
/// be at least NUMBUFLEN+2 to always fit the value.
/// @param buf_len The allocated size of the buffer.
-void format_reg_type(MotionType reg_type, colnr_T reg_width,
- char *buf, size_t buf_len)
+void format_reg_type(MotionType reg_type, colnr_T reg_width, char *buf, size_t buf_len)
FUNC_ATTR_NONNULL_ALL
{
assert(buf_len > 1);
switch (reg_type) {
- case kMTLineWise:
- buf[0] = 'V';
- buf[1] = NUL;
- break;
- case kMTCharWise:
- buf[0] = 'v';
- buf[1] = NUL;
- break;
- case kMTBlockWise:
- snprintf(buf, buf_len, CTRL_V_STR "%" PRIdCOLNR, reg_width + 1);
- break;
- case kMTUnknown:
- buf[0] = NUL;
- break;
+ case kMTLineWise:
+ buf[0] = 'V';
+ buf[1] = NUL;
+ break;
+ case kMTCharWise:
+ buf[0] = 'v';
+ buf[1] = NUL;
+ break;
+ case kMTBlockWise:
+ snprintf(buf, buf_len, CTRL_V_STR "%" PRIdCOLNR, reg_width + 1);
+ break;
+ case kMTUnknown:
+ buf[0] = NUL;
+ break;
}
}
@@ -5197,12 +5288,14 @@ void *get_reg_contents(int regname, int flags)
return get_reg_wrap_one_line(get_expr_line(), flags);
}
- if (regname == '@') /* "@@" is used for unnamed register */
+ if (regname == '@') { // "@@" is used for unnamed register
regname = '"';
+ }
- /* check for valid regname */
- if (regname != NUL && !valid_yank_reg(regname, false))
+ // check for valid regname
+ if (regname != NUL && !valid_yank_reg(regname, false)) {
return NULL;
+ }
char_u *retval;
bool allocated;
@@ -5217,8 +5310,9 @@ void *get_reg_contents(int regname, int flags)
}
yankreg_T *reg = get_yank_register(regname, YREG_PASTE);
- if (reg->y_array == NULL)
+ if (reg->y_array == NULL) {
return NULL;
+ }
if (flags & kGRegList) {
list_T *const list = tv_list_alloc((ptrdiff_t)reg->y_size);
@@ -5279,7 +5373,7 @@ static yankreg_T *init_write_reg(int name, yankreg_T **old_y_previous, bool must
yankreg_T *reg = get_yank_register(name, YREG_YANK);
if (!is_append_register(name) && !must_append) {
- free_register(reg);
+ free_register(reg);
}
return reg;
}
@@ -5298,18 +5392,16 @@ static void finish_write_reg(int name, yankreg_T *reg, yankreg_T *old_y_previous
/// write_reg_contents - store `str` in register `name`
///
/// @see write_reg_contents_ex
-void write_reg_contents(int name, const char_u *str, ssize_t len,
- int must_append)
+void write_reg_contents(int name, const char_u *str, ssize_t len, int must_append)
{
write_reg_contents_ex(name, str, len, must_append, kMTUnknown, 0L);
}
-void write_reg_contents_lst(int name, char_u **strings,
- bool must_append, MotionType yank_type,
+void write_reg_contents_lst(int name, char_u **strings, bool must_append, MotionType yank_type,
colnr_T block_len)
{
if (name == '/' || name == '=') {
- char_u *s = strings[0];
+ char_u *s = strings[0];
if (strings[0] == NULL) {
s = (char_u *)"";
} else if (strings[1] != NULL) {
@@ -5326,7 +5418,7 @@ void write_reg_contents_lst(int name, char_u **strings,
return;
}
- yankreg_T *old_y_previous, *reg;
+ yankreg_T *old_y_previous, *reg;
if (!(reg = init_write_reg(name, &old_y_previous, must_append))) {
return;
}
@@ -5354,18 +5446,14 @@ void write_reg_contents_lst(int name, char_u **strings,
/// is an uppercase letter.
/// @param yank_type The motion type (kMTUnknown to auto detect)
/// @param block_len width of visual block
-void write_reg_contents_ex(int name,
- const char_u *str,
- ssize_t len,
- bool must_append,
- MotionType yank_type,
- colnr_T block_len)
+void write_reg_contents_ex(int name, const char_u *str, ssize_t len, bool must_append,
+ MotionType yank_type, colnr_T block_len)
{
if (len < 0) {
- len = (ssize_t) STRLEN(str);
+ len = (ssize_t)STRLEN(str);
}
- /* Special case: '/' search pattern */
+ // Special case: '/' search pattern
if (name == '/') {
set_last_search_pat(str, RE_SEARCH, TRUE, TRUE);
return;
@@ -5394,7 +5482,7 @@ void write_reg_contents_ex(int name,
if (name == '=') {
size_t offset = 0;
- size_t totlen = (size_t) len;
+ size_t totlen = (size_t)len;
if (must_append && expr_line) {
// append has been specified and expr_line already exists, so we'll
@@ -5419,7 +5507,7 @@ void write_reg_contents_ex(int name,
return;
}
- yankreg_T *old_y_previous, *reg;
+ yankreg_T *old_y_previous, *reg;
if (!(reg = init_write_reg(name, &old_y_previous, must_append))) {
return;
}
@@ -5437,9 +5525,8 @@ void write_reg_contents_ex(int name,
/// @param len length of the string (Ignored when str_list=true.)
/// @param blocklen width of visual block, or -1 for "I don't know."
/// @param str_list True if str is `char_u **`.
-static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type,
- const char_u *str, size_t len, colnr_T blocklen,
- bool str_list)
+static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type, const char_u *str, size_t len,
+ colnr_T blocklen, bool str_list)
FUNC_ATTR_NONNULL_ALL
{
if (y_ptr->y_array == NULL) { // NULL means empty register
@@ -5458,7 +5545,7 @@ static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type,
// Count the number of lines within the string
if (str_list) {
- for (char_u **ss = (char_u **) str; *ss != NULL; ++ss) {
+ for (char_u **ss = (char_u **)str; *ss != NULL; ++ss) {
newlines++;
}
} else {
@@ -5473,6 +5560,11 @@ static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type,
}
}
+ // Without any lines make the register empty.
+ if (y_ptr->y_size + newlines == 0) {
+ XFREE_CLEAR(y_ptr->y_array);
+ return;
+ }
// Grow the register array to hold the pointers to the new lines.
char_u **pp = xrealloc(y_ptr->y_array,
@@ -5486,7 +5578,7 @@ static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type,
// Find the end of each line and save it into the array.
if (str_list) {
- for (char_u **ss = (char_u **) str; *ss != NULL; ++ss, ++lnum) {
+ for (char_u **ss = (char_u **)str; *ss != NULL; ++ss, ++lnum) {
size_t ss_len = STRLEN(*ss);
pp[lnum] = xmemdupz(*ss, ss_len);
if (ss_len > maxlen) {
@@ -5527,7 +5619,7 @@ static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type,
set_yreg_additional_data(y_ptr, NULL);
y_ptr->timestamp = os_time();
if (yank_type == kMTBlockWise) {
- y_ptr->y_width = (blocklen == -1 ? (colnr_T) maxlen - 1 : blocklen);
+ y_ptr->y_width = (blocklen == -1 ? (colnr_T)maxlen - 1 : blocklen);
} else {
y_ptr->y_width = 0;
}
@@ -5553,9 +5645,8 @@ void clear_oparg(oparg_T *oap)
* case, eol_size will be added to the character count to account for
* the size of the EOL character.
*/
-static varnumber_T line_count_info(char_u *line, varnumber_T *wc,
- varnumber_T *cc, varnumber_T limit,
- int eol_size)
+static varnumber_T line_count_info(char_u *line, varnumber_T *wc, varnumber_T *cc,
+ varnumber_T limit, int eol_size)
{
varnumber_T i;
varnumber_T words = 0;
@@ -5568,17 +5659,19 @@ static varnumber_T line_count_info(char_u *line, varnumber_T *wc,
words++;
is_word = 0;
}
- } else if (!ascii_isspace(line[i]))
+ } else if (!ascii_isspace(line[i])) {
is_word = 1;
+ }
++chars;
i += (*mb_ptr2len)(line + i);
}
- if (is_word)
+ if (is_word) {
words++;
+ }
*wc += words;
- /* Add eol_size if the end of line was reached before hitting limit. */
+ // Add eol_size if the end of line was reached before hitting limit.
if (i < limit && line[i] == NUL) {
i += eol_size;
chars += eol_size;
@@ -5593,7 +5686,7 @@ static varnumber_T line_count_info(char_u *line, varnumber_T *wc,
/// When "dict" is not NULL store the info there instead of showing it.
void cursor_pos_info(dict_T *dict)
{
- char_u *p;
+ char_u *p;
char_u buf1[50];
char_u buf2[40];
linenr_T lnum;
@@ -5620,10 +5713,11 @@ void cursor_pos_info(dict_T *dict)
return;
}
} else {
- if (get_fileformat(curbuf) == EOL_DOS)
+ if (get_fileformat(curbuf) == EOL_DOS) {
eol_size = 2;
- else
+ } else {
eol_size = 1;
+ }
if (l_VIsual_active) {
if (lt(VIsual, curwin->w_cursor)) {
@@ -5633,23 +5727,28 @@ void cursor_pos_info(dict_T *dict)
min_pos = curwin->w_cursor;
max_pos = VIsual;
}
- if (*p_sel == 'e' && max_pos.col > 0)
+ if (*p_sel == 'e' && max_pos.col > 0) {
--max_pos.col;
+ }
if (l_VIsual_mode == Ctrl_V) {
- char_u * saved_sbr = p_sbr;
+ char_u *const saved_sbr = p_sbr;
+ char_u *const saved_w_sbr = curwin->w_p_sbr;
- /* Make 'sbr' empty for a moment to get the correct size. */
+ // Make 'sbr' empty for a moment to get the correct size.
p_sbr = empty_option;
+ curwin->w_p_sbr = empty_option;
oparg.is_VIsual = true;
oparg.motion_type = kMTBlockWise;
oparg.op_type = OP_NOP;
getvcols(curwin, &min_pos, &max_pos,
- &oparg.start_vcol, &oparg.end_vcol);
+ &oparg.start_vcol, &oparg.end_vcol);
p_sbr = saved_sbr;
- if (curwin->w_curswant == MAXCOL)
+ curwin->w_p_sbr = saved_w_sbr;
+ if (curwin->w_curswant == MAXCOL) {
oparg.end_vcol = MAXCOL;
- /* Swap the start, end vcol if needed */
+ }
+ // Swap the start, end vcol if needed
if (oparg.end_vcol < oparg.start_vcol) {
oparg.end_vcol += oparg.start_vcol;
oparg.start_vcol = oparg.end_vcol - oparg.start_vcol;
@@ -5660,18 +5759,19 @@ void cursor_pos_info(dict_T *dict)
}
for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum) {
- /* Check for a CTRL-C every 100000 characters. */
+ // Check for a CTRL-C every 100000 characters.
if (byte_count > last_check) {
os_breakcheck();
- if (got_int)
+ if (got_int) {
return;
+ }
last_check = byte_count + 100000L;
}
- /* Do extra processing for VIsual mode. */
+ // Do extra processing for VIsual mode.
if (l_VIsual_active
&& lnum >= min_pos.lnum && lnum <= max_pos.lnum) {
- char_u *s = NULL;
+ char_u *s = NULL;
long len = 0L;
switch (l_VIsual_mode) {
@@ -5686,8 +5786,7 @@ void cursor_pos_info(dict_T *dict)
s = ml_get(lnum);
len = MAXCOL;
break;
- case 'v':
- {
+ case 'v': {
colnr_T start_col = (lnum == min_pos.lnum)
? min_pos.col : 0;
colnr_T end_col = (lnum == max_pos.lnum)
@@ -5700,23 +5799,24 @@ void cursor_pos_info(dict_T *dict)
}
if (s != NULL) {
byte_count_cursor += line_count_info(s, &word_count_cursor,
- &char_count_cursor, len, eol_size);
+ &char_count_cursor, len, eol_size);
if (lnum == curbuf->b_ml.ml_line_count
&& !curbuf->b_p_eol
&& (curbuf->b_p_bin || !curbuf->b_p_fixeol)
- && (long)STRLEN(s) < len)
+ && (long)STRLEN(s) < len) {
byte_count_cursor -= eol_size;
+ }
}
} else {
- /* In non-visual mode, check for the line the cursor is on */
+ // In non-visual mode, check for the line the cursor is on
if (lnum == curwin->w_cursor.lnum) {
word_count_cursor += word_count;
char_count_cursor += char_count;
byte_count_cursor = byte_count
- + line_count_info(ml_get(lnum), &word_count_cursor,
- &char_count_cursor,
- (varnumber_T)curwin->w_cursor.col + 1,
- eol_size);
+ + line_count_info(ml_get(lnum), &word_count_cursor,
+ &char_count_cursor,
+ (varnumber_T)curwin->w_cursor.col + 1,
+ eol_size);
}
}
// Add to the running totals
@@ -5814,18 +5914,18 @@ void cursor_pos_info(dict_T *dict)
if (dict != NULL) {
// Don't shorten this message, the user asked for it.
- tv_dict_add_nr(dict, S_LEN("words"), (varnumber_T)word_count);
- tv_dict_add_nr(dict, S_LEN("chars"), (varnumber_T)char_count);
+ tv_dict_add_nr(dict, S_LEN("words"), word_count);
+ tv_dict_add_nr(dict, S_LEN("chars"), char_count);
tv_dict_add_nr(dict, S_LEN("bytes"), (varnumber_T)(byte_count + bom_count));
STATIC_ASSERT(sizeof("visual") == sizeof("cursor"),
"key_len argument in tv_dict_add_nr is wrong");
tv_dict_add_nr(dict, l_VIsual_active ? "visual_bytes" : "cursor_bytes",
- sizeof("visual_bytes") - 1, (varnumber_T)byte_count_cursor);
+ sizeof("visual_bytes") - 1, byte_count_cursor);
tv_dict_add_nr(dict, l_VIsual_active ? "visual_chars" : "cursor_chars",
- sizeof("visual_chars") - 1, (varnumber_T)char_count_cursor);
+ sizeof("visual_chars") - 1, char_count_cursor);
tv_dict_add_nr(dict, l_VIsual_active ? "visual_words" : "cursor_words",
- sizeof("visual_words") - 1, (varnumber_T)word_count_cursor);
+ sizeof("visual_words") - 1, word_count_cursor);
}
}
@@ -5914,13 +6014,16 @@ bool prepare_yankreg_from_object(yankreg_T *reg, String regtype, size_t lines)
case 0:
reg->y_type = kMTUnknown;
break;
- case 'v': case 'c':
+ case 'v':
+ case 'c':
reg->y_type = kMTCharWise;
break;
- case 'V': case 'l':
+ case 'V':
+ case 'l':
reg->y_type = kMTLineWise;
break;
- case 'b': case Ctrl_V:
+ case 'b':
+ case Ctrl_V:
reg->y_type = kMTBlockWise;
break;
default:
@@ -6025,13 +6128,16 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet)
case 0:
reg->y_type = kMTUnknown;
break;
- case 'v': case 'c':
+ case 'v':
+ case 'c':
reg->y_type = kMTCharWise;
break;
- case 'V': case 'l':
+ case 'V':
+ case 'l':
reg->y_type = kMTLineWise;
break;
- case 'b': case Ctrl_V:
+ case 'b':
+ case Ctrl_V:
reg->y_type = kMTBlockWise;
break;
default:
@@ -6055,11 +6161,10 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet)
if (TV_LIST_ITEM_TV(li)->v_type != VAR_STRING) {
goto err;
}
- reg->y_array[tv_idx++] = (char_u *)xstrdupnul(
- (const char *)TV_LIST_ITEM_TV(li)->vval.v_string);
+ reg->y_array[tv_idx++] = (char_u *)xstrdupnul((const char *)TV_LIST_ITEM_TV(li)->vval.v_string);
});
- if (reg->y_size > 0 && strlen((char*)reg->y_array[reg->y_size-1]) == 0) {
+ if (reg->y_size > 0 && strlen((char *)reg->y_array[reg->y_size-1]) == 0) {
// a known-to-be charwise yank might have a final linebreak
// but otherwise there is no line after the final newline
if (reg->y_type != kMTCharWise) {
@@ -6114,8 +6219,7 @@ static void set_clipboard(int name, yankreg_T *reg)
return;
}
- list_T *const lines = tv_list_alloc(
- (ptrdiff_t)reg->y_size + (reg->y_type != kMTCharWise));
+ list_T *const lines = tv_list_alloc((ptrdiff_t)reg->y_size + (reg->y_type != kMTCharWise));
for (size_t i = 0; i < reg->y_size; i++) {
tv_list_append_string(lines, (const char *)reg->y_array[i], -1);
@@ -6123,23 +6227,19 @@ static void set_clipboard(int name, yankreg_T *reg)
char regtype;
switch (reg->y_type) {
- case kMTLineWise: {
- regtype = 'V';
- tv_list_append_string(lines, NULL, 0);
- break;
- }
- case kMTCharWise: {
- regtype = 'v';
- break;
- }
- case kMTBlockWise: {
- regtype = 'b';
- tv_list_append_string(lines, NULL, 0);
- break;
- }
- case kMTUnknown: {
- abort();
- }
+ case kMTLineWise:
+ regtype = 'V';
+ tv_list_append_string(lines, NULL, 0);
+ break;
+ case kMTCharWise:
+ regtype = 'v';
+ break;
+ case kMTBlockWise:
+ regtype = 'b';
+ tv_list_append_string(lines, NULL, 0);
+ break;
+ case kMTUnknown:
+ abort();
}
list_T *args = tv_list_alloc(3);
@@ -6213,8 +6313,8 @@ static inline bool reg_empty(const yankreg_T *const reg)
/// Iterate over global registers.
///
/// @see op_register_iter
-const void *op_global_reg_iter(const void *const iter, char *const name,
- yankreg_T *const reg, bool *is_unnamed)
+const void *op_global_reg_iter(const void *const iter, char *const name, yankreg_T *const reg,
+ bool *is_unnamed)
FUNC_ATTR_NONNULL_ARG(2, 3, 4) FUNC_ATTR_WARN_UNUSED_RESULT
{
return op_reg_iter(iter, y_regs, name, reg, is_unnamed);
@@ -6229,9 +6329,8 @@ const void *op_global_reg_iter(const void *const iter, char *const name,
///
/// @return Pointer that must be passed to next `op_register_iter` call or
/// NULL if iteration is over.
-const void *op_reg_iter(const void *const iter, const yankreg_T *const regs,
- char *const name, yankreg_T *const reg,
- bool *is_unnamed)
+const void *op_reg_iter(const void *const iter, const yankreg_T *const regs, char *const name,
+ yankreg_T *const reg, bool *is_unnamed)
FUNC_ATTR_NONNULL_ARG(3, 4, 5) FUNC_ATTR_WARN_UNUSED_RESULT
{
*name = NUL;
@@ -6250,7 +6349,7 @@ const void *op_reg_iter(const void *const iter, const yankreg_T *const regs,
*is_unnamed = (iter_reg == y_previous);
while (++iter_reg - &(regs[0]) < NUM_SAVED_REGISTERS) {
if (!reg_empty(iter_reg)) {
- return (void *) iter_reg;
+ return (void *)iter_reg;
}
}
return NULL;
@@ -6325,8 +6424,7 @@ bool op_reg_set_previous(const char name)
/// Get the byte count of buffer region. End-exclusive.
///
/// @return number of bytes
-bcount_t get_region_bytecount(buf_T *buf, linenr_T start_lnum,
- linenr_T end_lnum, colnr_T start_col,
+bcount_t get_region_bytecount(buf_T *buf, linenr_T start_lnum, linenr_T end_lnum, colnr_T start_col,
colnr_T end_col)
{
linenr_T max_lnum = buf->b_ml.ml_line_count;
@@ -6343,8 +6441,7 @@ bcount_t get_region_bytecount(buf_T *buf, linenr_T start_lnum,
if (start_lnum + i > max_lnum) {
return deleted_bytes;
}
- deleted_bytes += (bcount_t)STRLEN(
- ml_get_buf(buf, start_lnum + i, false)) + 1;
+ deleted_bytes += (bcount_t)STRLEN(ml_get_buf(buf, start_lnum + i, false)) + 1;
}
if (end_lnum > max_lnum) {
return deleted_bytes;
diff --git a/src/nvim/ops.h b/src/nvim/ops.h
index 112ffbeaba..5b87746921 100644
--- a/src/nvim/ops.h
+++ b/src/nvim/ops.h
@@ -90,6 +90,13 @@ typedef struct yankreg {
dict_T *additional_data; ///< Additional data from ShaDa file.
} yankreg_T;
+/// Modes for get_yank_register()
+typedef enum {
+ YREG_PASTE,
+ YREG_YANK,
+ YREG_PUT,
+} yreg_mode_t;
+
/// Convert register name into register index
///
/// @param[in] regname Register name.
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 388bedc043..5646a62cd4 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -16,58 +16,56 @@
// - If it's a numeric option, add any necessary bounds checks to
// set_num_option().
// - If it's a list of flags, add some code in do_set(), search for WW_ALL.
-// - When adding an option with expansion (P_EXPAND), but with a different
-// default for Vi and Vim (no P_VI_DEF), add some code at VIMEXP.
// - Add documentation! doc/options.txt, and any other related places.
// - Add an entry in runtime/optwin.vim.
#define IN_OPTION_C
#include <assert.h>
#include <inttypes.h>
+#include <limits.h>
#include <stdbool.h>
-#include <string.h>
#include <stdlib.h>
-#include <limits.h>
+#include <string.h>
-#include "nvim/vim.h"
-#include "nvim/macros.h"
#include "nvim/ascii.h"
-#include "nvim/edit.h"
-#include "nvim/option.h"
#include "nvim/buffer.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
+#include "nvim/cursor_shape.h"
#include "nvim/diff.h"
#include "nvim/digraph.h"
+#include "nvim/edit.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
+#include "nvim/ex_session.h"
#include "nvim/fileio.h"
#include "nvim/fold.h"
+#include "nvim/garray.h"
#include "nvim/getchar.h"
#include "nvim/hardcopy.h"
#include "nvim/highlight.h"
#include "nvim/indent_c.h"
+#include "nvim/keymap.h"
+#include "nvim/macros.h"
#include "nvim/mbyte.h"
#include "nvim/memfile.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
-#include "nvim/runtime.h"
-#include "nvim/keymap.h"
-#include "nvim/garray.h"
-#include "nvim/cursor_shape.h"
-#include "nvim/move.h"
#include "nvim/mouse.h"
+#include "nvim/move.h"
#include "nvim/normal.h"
+#include "nvim/option.h"
+#include "nvim/os/os.h"
#include "nvim/os_unix.h"
#include "nvim/path.h"
#include "nvim/popupmnu.h"
#include "nvim/regexp.h"
-#include "nvim/ex_session.h"
+#include "nvim/runtime.h"
#include "nvim/screen.h"
#include "nvim/spell.h"
#include "nvim/spellfile.h"
@@ -76,13 +74,13 @@
#include "nvim/ui.h"
#include "nvim/ui_compositor.h"
#include "nvim/undo.h"
+#include "nvim/vim.h"
#include "nvim/window.h"
-#include "nvim/os/os.h"
#ifdef WIN32
# include "nvim/os/pty_conpty_win.h"
#endif
-#include "nvim/lua/executor.h"
#include "nvim/api/private/helpers.h"
+#include "nvim/lua/executor.h"
#include "nvim/os/input.h"
#include "nvim/os/lang.h"
#include "nvim/quickfix.h"
@@ -126,64 +124,64 @@ static char *p_ttytype = NULL;
static int p_ai;
static int p_bin;
static int p_bomb;
-static char_u *p_bh;
-static char_u *p_bt;
+static char_u *p_bh;
+static char_u *p_bt;
static int p_bl;
static long p_channel;
static int p_ci;
static int p_cin;
-static char_u *p_cink;
-static char_u *p_cino;
-static char_u *p_cinw;
-static char_u *p_com;
-static char_u *p_cms;
-static char_u *p_cpt;
-static char_u *p_cfu;
-static char_u *p_ofu;
-static char_u *p_tfu;
+static char_u *p_cink;
+static char_u *p_cino;
+static char_u *p_cinw;
+static char_u *p_com;
+static char_u *p_cms;
+static char_u *p_cpt;
+static char_u *p_cfu;
+static char_u *p_ofu;
+static char_u *p_tfu;
static int p_eol;
static int p_fixeol;
static int p_et;
-static char_u *p_fenc;
-static char_u *p_ff;
-static char_u *p_fo;
-static char_u *p_flp;
-static char_u *p_ft;
+static char_u *p_fenc;
+static char_u *p_ff;
+static char_u *p_fo;
+static char_u *p_flp;
+static char_u *p_ft;
static long p_iminsert;
static long p_imsearch;
-static char_u *p_inex;
-static char_u *p_inde;
-static char_u *p_indk;
-static char_u *p_fex;
+static char_u *p_inex;
+static char_u *p_inde;
+static char_u *p_indk;
+static char_u *p_fex;
static int p_inf;
-static char_u *p_isk;
+static char_u *p_isk;
static int p_lisp;
static int p_ml;
static int p_ma;
static int p_mod;
-static char_u *p_mps;
-static char_u *p_nf;
+static char_u *p_mps;
+static char_u *p_nf;
static int p_pi;
-static char_u *p_qe;
+static char_u *p_qe;
static int p_ro;
static int p_si;
static long p_sts;
-static char_u *p_sua;
+static char_u *p_sua;
static long p_sw;
static int p_swf;
static long p_smc;
-static char_u *p_syn;
-static char_u *p_spc;
-static char_u *p_spf;
-static char_u *p_spl;
-static char_u *p_spo;
+static char_u *p_syn;
+static char_u *p_spc;
+static char_u *p_spf;
+static char_u *p_spl;
+static char_u *p_spo;
static long p_ts;
static long p_tw;
static int p_udf;
static long p_wm;
static char_u *p_vsts;
static char_u *p_vts;
-static char_u *p_keymap;
+static char_u *p_keymap;
// Saved values for when 'bin' is set.
static int p_et_nobin;
@@ -200,20 +198,18 @@ static long p_wm_nopaste;
static char_u *p_vsts_nopaste;
typedef struct vimoption {
- char *fullname; // full option name
- char *shortname; // permissible abbreviation
+ char *fullname; // full option name
+ char *shortname; // permissible abbreviation
uint32_t flags; // see below
- char_u *var; // global option: pointer to variable;
- // window-local option: VAR_WIN;
- // buffer-local option: global value
+ char_u *var; // global option: pointer to variable;
+ // window-local option: VAR_WIN;
+ // buffer-local option: global value
idopt_T indir; // global option: PV_NONE;
// local option: indirect option index
- char_u *def_val[2]; // default values for variable (vi and vim)
+ char_u *def_val; // default values for variable (neovim!!)
LastSet last_set; // script in which the option was last set
} vimoption_T;
-#define VI_DEFAULT 0 // def_val[VI_DEFAULT] is Vi default value
-#define VIM_DEFAULT 1 // def_val[VIM_DEFAULT] is Vim default value
/*
* Flags
@@ -232,8 +228,6 @@ typedef struct vimoption {
// use free() when assigning new value
#define P_WAS_SET 0x100U // option has been set/reset
#define P_NO_MKRC 0x200U // don't include in :mkvimrc output
-#define P_VI_DEF 0x400U // Use Vi default for Vim
-#define P_VIM 0x800U // Vim option
// when option changed, what to display:
#define P_RSTAT 0x1000U ///< redraw status lines
@@ -266,15 +260,13 @@ typedef struct vimoption {
#define P_MLE 0x80000000U ///< under control of 'modelineexpr'
#define HIGHLIGHT_INIT \
- "8:SpecialKey,~:EndOfBuffer,z:TermCursor,Z:TermCursorNC,@:NonText," \
- "d:Directory,e:ErrorMsg,i:IncSearch,l:Search,m:MoreMsg,M:ModeMsg,n:LineNr," \
- "N:CursorLineNr,r:Question,s:StatusLine,S:StatusLineNC,c:VertSplit,t:Title," \
- "v:Visual,V:VisualNOS,w:WarningMsg,W:WildMenu,f:Folded,F:FoldColumn," \
- "A:DiffAdd,C:DiffChange,D:DiffDelete,T:DiffText,>:SignColumn,-:Conceal," \
- "B:SpellBad,P:SpellCap,R:SpellRare,L:SpellLocal,+:Pmenu,=:PmenuSel," \
- "x:PmenuSbar,X:PmenuThumb,*:TabLine,#:TabLineSel,_:TabLineFill," \
- "!:CursorColumn,.:CursorLine,o:ColorColumn,q:QuickFixLine," \
- "0:Whitespace,I:NormalNC"
+ "8:SpecialKey,~:EndOfBuffer,z:TermCursor,Z:TermCursorNC,@:NonText,d:Directory,e:ErrorMsg," \
+ "i:IncSearch,l:Search,m:MoreMsg,M:ModeMsg,n:LineNr,a:LineNrAbove,b:LineNrBelow,N:CursorLineNr," \
+ "r:Question,s:StatusLine,S:StatusLineNC,c:VertSplit,t:Title,v:Visual,V:VisualNOS,w:WarningMsg," \
+ "W:WildMenu,f:Folded,F:FoldColumn,A:DiffAdd,C:DiffChange,D:DiffDelete,T:DiffText,>:SignColumn," \
+ "-:Conceal,B:SpellBad,P:SpellCap,R:SpellRare,L:SpellLocal,+:Pmenu,=:PmenuSel,x:PmenuSbar," \
+ "X:PmenuThumb,*:TabLine,#:TabLineSel,_:TabLineFill,!:CursorColumn,.:CursorLine,o:ColorColumn," \
+ "q:QuickFixLine,0:Whitespace,I:NormalNC"
/*
* options[] is initialized here.
@@ -322,12 +314,15 @@ static char *(p_csl_values[]) = { "slash", "backslash", NULL };
#endif
static char *(p_icm_values[]) = { "nosplit", "split", NULL };
static char *(p_scl_values[]) = { "yes", "no", "auto", "auto:1", "auto:2",
- "auto:3", "auto:4", "auto:5", "auto:6", "auto:7", "auto:8", "auto:9",
- "yes:1", "yes:2", "yes:3", "yes:4", "yes:5", "yes:6", "yes:7", "yes:8",
- "yes:9", "number", NULL };
+ "auto:3", "auto:4", "auto:5", "auto:6", "auto:7", "auto:8",
+ "auto:9",
+ "yes:1", "yes:2", "yes:3", "yes:4", "yes:5", "yes:6",
+ "yes:7", "yes:8",
+ "yes:9", "number", NULL };
static char *(p_fdc_values[]) = { "auto", "auto:1", "auto:2",
- "auto:3", "auto:4", "auto:5", "auto:6", "auto:7", "auto:8", "auto:9",
- "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL };
+ "auto:3", "auto:4", "auto:5", "auto:6", "auto:7", "auto:8",
+ "auto:9",
+ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL };
/// All possible flags for 'shm'.
static char_u SHM_ALL[] = {
@@ -379,11 +374,11 @@ void set_init_1(bool clean_arg)
* temp files.
*/
{
-# ifdef UNIX
- static char *(names[4]) = {"", "TMPDIR", "TEMP", "TMP"};
-# else
- static char *(names[3]) = {"TMPDIR", "TEMP", "TMP"};
-# endif
+#ifdef UNIX
+ static char *(names[4]) = { "", "TMPDIR", "TEMP", "TMP" };
+#else
+ static char *(names[3]) = { "TMPDIR", "TEMP", "TMP" };
+#endif
garray_T ga;
opt_idx = findoption("backupskip");
@@ -391,16 +386,16 @@ void set_init_1(bool clean_arg)
for (size_t n = 0; n < ARRAY_SIZE(names); n++) {
bool mustfree = true;
char *p;
-# ifdef UNIX
+#ifdef UNIX
if (*names[n] == NUL) {
-# ifdef __APPLE__
+# ifdef __APPLE__
p = "/private/tmp";
-# else
+# else
p = "/tmp";
-# endif
+# endif
mustfree = false;
} else
-# endif
+#endif
{
p = vim_getenv(names[n]);
}
@@ -434,8 +429,8 @@ void set_init_1(bool clean_arg)
}
{
- char_u *cdpath;
- char_u *buf;
+ char_u *cdpath;
+ char_u *buf;
int i;
int j;
@@ -459,7 +454,7 @@ void set_init_1(bool clean_arg)
buf[j] = NUL;
opt_idx = findoption("cdpath");
if (opt_idx >= 0) {
- options[opt_idx].def_val[VI_DEFAULT] = buf;
+ options[opt_idx].def_val = buf;
options[opt_idx].flags |= P_DEF_ALLOCED;
} else {
xfree(buf); // cannot happen
@@ -478,30 +473,30 @@ void set_init_1(bool clean_arg)
set_string_default("printexpr",
#ifdef UNIX
"system(['lpr'] "
- "+ (empty(&printdevice)?[]:['-P', &printdevice]) "
- "+ [v:fname_in])"
+ "+ (empty(&printdevice)?[]:['-P', &printdevice]) "
+ "+ [v:fname_in])"
". delete(v:fname_in)"
"+ v:shell_error",
#elif defined(MSWIN)
"system(['copy', v:fname_in, "
- "empty(&printdevice)?'LPT1':&printdevice])"
+ "empty(&printdevice)?'LPT1':&printdevice])"
". delete(v:fname_in)",
#else
"",
#endif
false);
- char *backupdir = stdpaths_user_data_subpath("backup", 0, true);
+ char *backupdir = stdpaths_user_data_subpath("backup", 2, true);
const size_t backupdir_len = strlen(backupdir);
backupdir = xrealloc(backupdir, backupdir_len + 3);
memmove(backupdir + 2, backupdir, backupdir_len + 1);
memmove(backupdir, ".,", 2);
- set_string_default("viewdir", stdpaths_user_data_subpath("view", 0, true),
- true);
set_string_default("backupdir", backupdir, true);
+ set_string_default("viewdir", stdpaths_user_data_subpath("view", 2, true),
+ true);
set_string_default("directory", stdpaths_user_data_subpath("swap", 2, true),
true);
- set_string_default("undodir", stdpaths_user_data_subpath("undo", 0, true),
+ set_string_default("undodir", stdpaths_user_data_subpath("undo", 2, true),
true);
// Set default for &runtimepath. All necessary expansions are performed in
// this function.
@@ -527,7 +522,7 @@ void set_init_1(bool clean_arg)
check_win_options(curwin);
check_options();
- // Set all options to their Vim default
+ // Set all options to their default value
set_options_default(OPT_FREE);
// set 'laststatus'
@@ -558,20 +553,15 @@ void set_init_1(bool clean_arg)
&& options[opt_idx].var != NULL) {
p = _(*(char **)options[opt_idx].var);
} else {
- p = (char *) option_expand(opt_idx, NULL);
+ p = (char *)option_expand(opt_idx, NULL);
}
if (p != NULL) {
p = xstrdup(p);
*(char **)options[opt_idx].var = p;
- /* VIMEXP
- * Defaults for all expanded options are currently the same for Vi
- * and Vim. When this changes, add some code here! Also need to
- * split P_DEF_ALLOCED in two.
- */
if (options[opt_idx].flags & P_DEF_ALLOCED) {
- xfree(options[opt_idx].def_val[VI_DEFAULT]);
+ xfree(options[opt_idx].def_val);
}
- options[opt_idx].def_val[VI_DEFAULT] = (char_u *)p;
+ options[opt_idx].def_val = (char_u *)p;
options[opt_idx].flags |= P_DEF_ALLOCED;
}
}
@@ -597,8 +587,8 @@ void set_init_1(bool clean_arg)
// in 'fileencodings'
char_u *p = enc_locale();
if (p == NULL) {
- // use utf-8 as 'default' if locale encoding can't be detected.
- p = (char_u *)xmemdupz(S_LEN("utf-8"));
+ // use utf-8 as 'default' if locale encoding can't be detected.
+ p = (char_u *)xmemdupz(S_LEN("utf-8"));
}
fenc_default = p;
@@ -614,39 +604,34 @@ void set_init_1(bool clean_arg)
/// Set an option to its default value.
/// This does not take care of side effects!
-static void
-set_option_default(
- int opt_idx,
- int opt_flags, // OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL
- int compatible // use Vi default value
-)
-{
- char_u *varp; // pointer to variable for current option
- int dvi; // index in def_val[]
+///
+/// @param opt_flags OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL
+static void set_option_default(int opt_idx, int opt_flags)
+{
+ char_u *varp; // pointer to variable for current option
int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
varp = get_varp_scope(&(options[opt_idx]), both ? OPT_LOCAL : opt_flags);
uint32_t flags = options[opt_idx].flags;
if (varp != NULL) { // skip hidden option, nothing to do for it
- dvi = ((flags & P_VI_DEF) || compatible) ? VI_DEFAULT : VIM_DEFAULT;
if (flags & P_STRING) {
/* Use set_string_option_direct() for local options to handle
* freeing and allocating the value. */
if (options[opt_idx].indir != PV_NONE) {
set_string_option_direct(NULL, opt_idx,
- options[opt_idx].def_val[dvi], opt_flags, 0);
+ options[opt_idx].def_val, opt_flags, 0);
} else {
if ((opt_flags & OPT_FREE) && (flags & P_ALLOCED)) {
free_string_option(*(char_u **)(varp));
}
- *(char_u **)varp = options[opt_idx].def_val[dvi];
+ *(char_u **)varp = options[opt_idx].def_val;
options[opt_idx].flags &= ~P_ALLOCED;
}
- } else if (flags & P_NUM) {
+ } else if (flags & P_NUM) {
if (options[opt_idx].indir == PV_SCROLL) {
win_comp_scroll(curwin);
} else {
- long def_val = (long)options[opt_idx].def_val[dvi];
+ long def_val = (long)options[opt_idx].def_val;
if ((long *)varp == &curwin->w_p_so
|| (long *)varp == &curwin->w_p_siso) {
// 'scrolloff' and 'sidescrolloff' local values have a
@@ -662,7 +647,7 @@ set_option_default(
}
}
} else { // P_BOOL
- *(int *)varp = (int)(intptr_t)options[opt_idx].def_val[dvi];
+ *(int *)varp = (int)(intptr_t)options[opt_idx].def_val;
#ifdef UNIX
// 'modeline' defaults to off for root
if (options[opt_idx].indir == PV_ML && getuid() == ROOT_UID) {
@@ -685,14 +670,13 @@ set_option_default(
}
/// Set all options (except terminal options) to their default value.
-static void
-set_options_default(
- int opt_flags // OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL
-)
+///
+/// @param opt_flags OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL
+static void set_options_default(int opt_flags)
{
for (int i = 0; options[i].fullname; i++) {
if (!(options[i].flags & P_NODEFAULT)) {
- set_option_default(i, opt_flags, false);
+ set_option_default(i, opt_flags);
}
}
@@ -716,10 +700,10 @@ static void set_string_default(const char *name, char *val, bool allocated)
int opt_idx = findoption(name);
if (opt_idx >= 0) {
if (options[opt_idx].flags & P_DEF_ALLOCED) {
- xfree(options[opt_idx].def_val[VI_DEFAULT]);
+ xfree(options[opt_idx].def_val);
}
- options[opt_idx].def_val[VI_DEFAULT] = allocated
+ options[opt_idx].def_val = allocated
? (char_u *)val
: (char_u *)xstrdup(val);
options[opt_idx].flags |= P_DEF_ALLOCED;
@@ -728,8 +712,7 @@ static void set_string_default(const char *name, char *val, bool allocated)
// For an option value that contains comma separated items, find "newval" in
// "origval". Return NULL if not found.
-static char_u *find_dup_item(char_u *origval, const char_u *newval,
- uint32_t flags)
+static char_u *find_dup_item(char_u *origval, const char_u *newval, uint32_t flags)
FUNC_ATTR_NONNULL_ARG(2)
{
int bs = 0;
@@ -766,7 +749,7 @@ void set_number_default(char *name, long val)
opt_idx = findoption(name);
if (opt_idx >= 0) {
- options[opt_idx].def_val[VI_DEFAULT] = (char_u *)(intptr_t)val;
+ options[opt_idx].def_val = (char_u *)(intptr_t)val;
}
}
@@ -781,11 +764,11 @@ void free_all_options(void)
free_string_option(*(char_u **)options[i].var);
}
if (options[i].flags & P_DEF_ALLOCED) {
- free_string_option(options[i].def_val[VI_DEFAULT]);
+ free_string_option(options[i].def_val);
}
} else if (options[i].var != VAR_WIN && (options[i].flags & P_STRING)) {
// buffer-local option: free global value
- free_string_option(*(char_u **)options[i].var);
+ clear_string_option((char_u **)options[i].var);
}
}
}
@@ -804,7 +787,7 @@ void set_init_2(bool headless)
// which results in the actual value computed from the window height.
idx = findoption("scroll");
if (idx >= 0 && !(options[idx].flags & P_WAS_SET)) {
- set_option_default(idx, OPT_LOCAL, false);
+ set_option_default(idx, OPT_LOCAL);
}
comp_col();
@@ -845,16 +828,15 @@ void set_init_3(void)
// Default for p_sp is "| tee", for p_srr is ">".
// For known shells it is changed here to include stderr.
//
- if ( fnamecmp(p, "csh") == 0
- || fnamecmp(p, "tcsh") == 0
- ) {
+ if (fnamecmp(p, "csh") == 0
+ || fnamecmp(p, "tcsh") == 0) {
if (do_sp) {
p_sp = (char_u *)"|& tee";
- options[idx_sp].def_val[VI_DEFAULT] = p_sp;
+ options[idx_sp].def_val = p_sp;
}
if (do_srr) {
p_srr = (char_u *)">&";
- options[idx_srr].def_val[VI_DEFAULT] = p_srr;
+ options[idx_srr].def_val = p_srr;
}
} else if (fnamecmp(p, "sh") == 0
|| fnamecmp(p, "ksh") == 0
@@ -865,22 +847,21 @@ void set_init_3(void)
|| fnamecmp(p, "bash") == 0
|| fnamecmp(p, "fish") == 0
|| fnamecmp(p, "ash") == 0
- || fnamecmp(p, "dash") == 0
- ) {
+ || fnamecmp(p, "dash") == 0) {
// Always use POSIX shell style redirection if we reach this
if (do_sp) {
p_sp = (char_u *)"2>&1| tee";
- options[idx_sp].def_val[VI_DEFAULT] = p_sp;
+ options[idx_sp].def_val = p_sp;
}
if (do_srr) {
p_srr = (char_u *)">%s 2>&1";
- options[idx_srr].def_val[VI_DEFAULT] = p_srr;
+ options[idx_srr].def_val = p_srr;
}
}
xfree(p);
}
- if (BUFEMPTY()) {
+ if (buf_is_empty(curbuf)) {
int idx_ffs = findoption_len(S_LEN("ffs"));
// Apply the first entry of 'fileformats' to the initial buffer.
@@ -941,38 +922,37 @@ void set_title_defaults(void)
*/
idx1 = findoption("title");
if (idx1 >= 0 && !(options[idx1].flags & P_WAS_SET)) {
- options[idx1].def_val[VI_DEFAULT] = (char_u *)(intptr_t)0;
+ options[idx1].def_val = (char_u *)(intptr_t)0;
p_title = 0;
}
idx1 = findoption("icon");
if (idx1 >= 0 && !(options[idx1].flags & P_WAS_SET)) {
- options[idx1].def_val[VI_DEFAULT] = (char_u *)(intptr_t)0;
+ options[idx1].def_val = (char_u *)(intptr_t)0;
p_icon = 0;
}
}
-// Parse 'arg' for option settings.
-//
-// 'arg' may be IObuff, but only when no errors can be present and option
-// does not need to be expanded with option_expand().
-// "opt_flags":
-// 0 for ":set"
-// OPT_GLOBAL for ":setglobal"
-// OPT_LOCAL for ":setlocal" and a modeline
-// OPT_MODELINE for a modeline
-// OPT_WINONLY to only set window-local options
-// OPT_NOWIN to skip setting window-local options
-//
-// returns FAIL if an error is detected, OK otherwise
-int do_set(
- char_u *arg, // option string (may be written to!)
- int opt_flags
-)
+/// Parse 'arg' for option settings.
+///
+/// 'arg' may be IObuff, but only when no errors can be present and option
+/// does not need to be expanded with option_expand().
+/// "opt_flags":
+/// 0 for ":set"
+/// OPT_GLOBAL for ":setglobal"
+/// OPT_LOCAL for ":setlocal" and a modeline
+/// OPT_MODELINE for a modeline
+/// OPT_WINONLY to only set window-local options
+/// OPT_NOWIN to skip setting window-local options
+///
+/// @param arg option string (may be written to!)
+///
+/// @return FAIL if an error is detected, OK otherwise
+int do_set(char_u *arg, int opt_flags)
{
int opt_idx;
- char_u *errmsg;
+ char_u *errmsg;
char_u errbuf[80];
- char_u *startarg;
+ char_u *startarg;
int prefix; // 1: nothing, 0: "no", 2: "inv" in front of name
char_u nextchar; // next non-white char after option name
int afterchar; // character just after option name
@@ -981,12 +961,11 @@ int do_set(
varnumber_T value;
int key;
uint32_t flags; // flags for current option
- char_u *varp = NULL; // pointer to variable for current option
+ char_u *varp = NULL; // pointer to variable for current option
int did_show = false; // already showed one value
int adding; // "opt+=arg"
int prepending; // "opt^=arg"
int removing; // "opt-=arg"
- int cp_val = 0;
if (*arg == NUL) {
showoptions(0, opt_flags);
@@ -1118,8 +1097,9 @@ int do_set(
/* Skip all options that are not window-local (used when showing
* an already loaded buffer in a window). */
if ((opt_flags & OPT_WINONLY)
- && (opt_idx < 0 || options[opt_idx].var != VAR_WIN))
+ && (opt_idx < 0 || options[opt_idx].var != VAR_WIN)) {
goto skip;
+ }
// Skip all options that are window-local (used for :vimgrep).
if ((opt_flags & OPT_NOWIN) && opt_idx >= 0
@@ -1134,8 +1114,7 @@ int do_set(
goto skip;
}
if ((flags & P_MLE) && !p_mle) {
- errmsg = (char_u *)N_(
- "E992: Not allowed in a modeline when 'modelineexpr' is off");
+ errmsg = (char_u *)N_("E992: Not allowed in a modeline when 'modelineexpr' is off");
goto skip;
}
// In diff mode some options are overruled. This avoids that
@@ -1157,13 +1136,10 @@ int do_set(
if (vim_strchr((char_u *)"?=:!&<", nextchar) != NULL) {
arg += len;
- cp_val = false;
if (nextchar == '&' && arg[1] == 'v' && arg[2] == 'i') {
- if (arg[3] == 'm') { // "opt&vim": set to Vim default
- cp_val = false;
+ if (arg[3] == 'm') { // "opt&vim": set to Vim default
arg += 3;
- } else { // "opt&vi": set to Vi default
- cp_val = true;
+ } else { // "opt&vi": set to Vi default
arg += 2;
}
}
@@ -1174,10 +1150,10 @@ int do_set(
}
}
- /*
- * allow '=' and ':' as MSDOS command.com allows only one
- * '=' character per "set" command line. grrr. (jw)
- */
+ //
+ // allow '=' and ':' as MS-DOS command.com allows only one
+ // '=' character per "set" command line. grrr. (jw)
+ //
if (nextchar == '?'
|| (prefix == 1
&& vim_strchr((char_u *)"=:&<", nextchar) == NULL
@@ -1199,10 +1175,10 @@ int do_set(
option_last_set_msg(options[opt_idx].last_set);
} else if ((int)options[opt_idx].indir & PV_WIN) {
option_last_set_msg(curwin->w_p_script_ctx[
- (int)options[opt_idx].indir & PV_MASK]);
+ (int)options[opt_idx].indir & PV_MASK]);
} else if ((int)options[opt_idx].indir & PV_BUF) {
option_last_set_msg(curbuf->b_p_script_ctx[
- (int)options[opt_idx].indir & PV_MASK]);
+ (int)options[opt_idx].indir & PV_MASK]);
}
}
} else {
@@ -1210,8 +1186,9 @@ int do_set(
goto skip;
}
if (nextchar != '?'
- && nextchar != NUL && !ascii_iswhite(afterchar))
+ && nextchar != NUL && !ascii_iswhite(afterchar)) {
errmsg = e_trailing;
+ }
} else {
int value_is_replaced = !prepending && !adding && !removing;
int value_checked = false;
@@ -1230,9 +1207,7 @@ int do_set(
if (nextchar == '!') {
value = *(int *)(varp) ^ 1;
} else if (nextchar == '&') {
- value = (int)(intptr_t)options[opt_idx].def_val[
- ((flags & P_VI_DEF) || cp_val)
- ? VI_DEFAULT : VIM_DEFAULT];
+ value = (int)(intptr_t)options[opt_idx].def_val;
} else if (nextchar == '<') {
// For 'autoread' -1 means to use global value.
if ((int *)varp == &curbuf->b_p_ar
@@ -1277,16 +1252,14 @@ int do_set(
// other error
arg++;
if (nextchar == '&') {
- value = (long)(intptr_t)options[opt_idx].def_val[
- ((flags & P_VI_DEF) || cp_val) ? VI_DEFAULT : VIM_DEFAULT];
+ value = (long)(intptr_t)options[opt_idx].def_val;
} else if (nextchar == '<') {
// For 'undolevels' NO_LOCAL_UNDOLEVEL means to
// use the global value.
if ((long *)varp == &curbuf->b_p_ul && opt_flags == OPT_LOCAL) {
value = NO_LOCAL_UNDOLEVEL;
} else {
- value = *(long *)get_varp_scope(
- &(options[opt_idx]), OPT_GLOBAL);
+ value = *(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL);
}
} else if (((long *)varp == &p_wc
|| (long *)varp == &p_wcm)
@@ -1301,9 +1274,9 @@ int do_set(
}
} else if (*arg == '-' || ascii_isdigit(*arg)) {
// Allow negative, octal and hex numbers.
- vim_str2nr(arg, NULL, &i, STR2NR_ALL, &value, NULL, 0);
- if (arg[i] != NUL && !ascii_iswhite(arg[i])) {
- errmsg = e_invarg;
+ vim_str2nr(arg, NULL, &i, STR2NR_ALL, &value, NULL, 0, true);
+ if (i == 0 || (arg[i] != NUL && !ascii_iswhite(arg[i]))) {
+ errmsg = (char_u *)N_("E521: Number required after =");
goto skip;
}
} else {
@@ -1324,11 +1297,11 @@ int do_set(
errbuf, sizeof(errbuf),
opt_flags);
} else if (opt_idx >= 0) { // String.
- char_u *save_arg = NULL;
- char_u *s = NULL;
- char_u *oldval = NULL; // previous value if *varp
- char_u *newval;
- char_u *origval = NULL;
+ char_u *save_arg = NULL;
+ char_u *s = NULL;
+ char_u *oldval = NULL; // previous value if *varp
+ char_u *newval;
+ char_u *origval = NULL;
char *saved_origval = NULL;
char *saved_newval = NULL;
unsigned newlen;
@@ -1339,8 +1312,9 @@ int do_set(
* with a local value the local value will be
* reset, use the global value here. */
if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0
- && ((int)options[opt_idx].indir & PV_BOTH))
+ && ((int)options[opt_idx].indir & PV_BOTH)) {
varp = options[opt_idx].var;
+ }
/* The old value is kept until we are sure that the
* new value is valid. */
@@ -1355,14 +1329,12 @@ int do_set(
origval = oldval;
}
- if (nextchar == '&') { // set to default val
- newval = options[opt_idx].def_val[
- ((flags & P_VI_DEF) || cp_val)
- ? VI_DEFAULT : VIM_DEFAULT];
- /* expand environment variables and ~ (since the
- * default value was already expanded, only
- * required when an environment variable was set
- * later */
+ if (nextchar == '&') { // set to default val
+ newval = options[opt_idx].def_val;
+ // expand environment variables and ~ (since the
+ // default value was already expanded, only
+ // required when an environment variable was set
+ // later
new_value_alloced = true;
if (newval == NULL) {
newval = empty_option;
@@ -1376,8 +1348,7 @@ int do_set(
newval = (char_u *)xstrdup((char *)newval);
}
} else if (nextchar == '<') { // set to global val
- newval = vim_strsave(*(char_u **)get_varp_scope(
- &(options[opt_idx]), OPT_GLOBAL));
+ newval = vim_strsave(*(char_u **)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL));
new_value_alloced = true;
} else {
arg++; // jump to after the '=' or ':'
@@ -1405,16 +1376,13 @@ int do_set(
*(char_u **)varp = empty_option;
break;
case 1:
- *(char_u **)varp = vim_strsave(
- (char_u *)"indent,eol");
+ *(char_u **)varp = vim_strsave((char_u *)"indent,eol");
break;
case 2:
- *(char_u **)varp = vim_strsave(
- (char_u *)"indent,eol,start");
+ *(char_u **)varp = vim_strsave((char_u *)"indent,eol,start");
break;
case 3:
- *(char_u **)varp = vim_strsave(
- (char_u *)"indent,eol,nostop");
+ *(char_u **)varp = vim_strsave((char_u *)"indent,eol,nostop");
break;
}
xfree(oldval);
@@ -1433,22 +1401,19 @@ int do_set(
*errbuf = NUL;
i = getdigits_int(&arg, true, 0);
if (i & 1) {
- STRCAT(errbuf, "b,");
+ STRLCAT(errbuf, "b,", sizeof(errbuf));
}
if (i & 2) {
- STRCAT(errbuf, "s,");
+ STRLCAT(errbuf, "s,", sizeof(errbuf));
}
if (i & 4) {
- STRCAT(errbuf, "h,l,");
+ STRLCAT(errbuf, "h,l,", sizeof(errbuf));
}
if (i & 8) {
- STRCAT(errbuf, "<,>,");
+ STRLCAT(errbuf, "<,>,", sizeof(errbuf));
}
if (i & 16) {
- STRCAT(errbuf, "[,],");
- }
- if (*errbuf != NUL) { // remove trailing ,
- errbuf[STRLEN(errbuf) - 1] = NUL;
+ STRLCAT(errbuf, "[,],", sizeof(errbuf));
}
save_arg = arg;
arg = errbuf;
@@ -1457,9 +1422,9 @@ int do_set(
* Remove '>' before 'dir' and 'bdir', for
* backwards compatibility with version 3.0
*/
- else if ( *arg == '>'
- && (varp == (char_u *)&p_dir
- || varp == (char_u *)&p_bdir)) {
+ else if (*arg == '>'
+ && (varp == (char_u *)&p_dir
+ || varp == (char_u *)&p_bdir)) {
arg++;
}
@@ -1494,8 +1459,9 @@ int do_set(
|| (s == newval
&& arg[2] != '\\')))
#endif
- )
+ ) {
arg++; // remove backslash
+ }
i = utfc_ptr2len(arg);
if (i > 1) {
// copy multibyte char
@@ -1563,7 +1529,7 @@ int do_set(
i--;
}
memmove(newval + i + comma, newval,
- STRLEN(newval) + 1);
+ STRLEN(newval) + 1);
memmove(newval, origval, (size_t)i);
} else {
i = (int)STRLEN(newval);
@@ -1680,7 +1646,6 @@ int do_set(
if (errmsg != NULL) {
goto skip;
}
-
} else {
// key code option(FIXME(tarruda): Show a warning or something
// similar)
@@ -1749,15 +1714,13 @@ theend:
return OK;
}
-// Call this when an option has been given a new value through a user command.
-// Sets the P_WAS_SET flag and takes care of the P_INSECURE flag.
-static void did_set_option(
- int opt_idx,
- int opt_flags, // possibly with OPT_MODELINE
- int new_value, // value was replaced completely
- int value_checked // value was checked to be safe, no need to
- // set P_INSECURE
-)
+/// Call this when an option has been given a new value through a user command.
+/// Sets the P_WAS_SET flag and takes care of the P_INSECURE flag.
+///
+/// @param opt_flags possibly with OPT_MODELINE
+/// @param new_value value was replaced completely
+/// @param value_checked value was checked to be safe, no need to set P_INSECURE
+static void did_set_option(int opt_idx, int opt_flags, int new_value, int value_checked)
{
options[opt_idx].flags |= P_WAS_SET;
@@ -1826,12 +1789,10 @@ static void did_set_title(void)
}
}
-// set_options_bin - called when 'bin' changes value.
-void set_options_bin(
- int oldval,
- int newval,
- int opt_flags // OPT_LOCAL and/or OPT_GLOBAL
-)
+/// set_options_bin - called when 'bin' changes value.
+///
+/// @param opt_flags OPT_LOCAL and/or OPT_GLOBAL
+void set_options_bin(int oldval, int newval, int opt_flags)
{
/*
* The option values that are changed when 'bin' changes are
@@ -1889,7 +1850,7 @@ void set_options_bin(
/// number, return -1.
int get_shada_parameter(int type)
{
- char_u *p;
+ char_u *p;
p = find_shada_parameter(type);
if (p != NULL && ascii_isdigit(*p)) {
@@ -1903,7 +1864,7 @@ int get_shada_parameter(int type)
/// Return NULL if the parameter is not specified in the string.
char_u *find_shada_parameter(int type)
{
- char_u *p;
+ char_u *p;
for (p = p_shada; *p; p++) {
if (*p == type) {
@@ -1987,6 +1948,7 @@ static void didset_options(void)
briopt_check(curwin);
// initialize the table for 'breakat'.
fill_breakat_flags();
+ fill_culopt_flags(NULL, curwin);
}
// More side effects of setting options.
@@ -2131,12 +2093,18 @@ static uint32_t *insecure_flag(win_T *const wp, int opt_idx, int opt_flags)
if (opt_flags & OPT_LOCAL) {
assert(wp != NULL);
switch ((int)options[opt_idx].indir) {
- case PV_STL: return &wp->w_p_stl_flags;
- case PV_FDE: return &wp->w_p_fde_flags;
- case PV_FDT: return &wp->w_p_fdt_flags;
- case PV_INDE: return &wp->w_buffer->b_p_inde_flags;
- case PV_FEX: return &wp->w_buffer->b_p_fex_flags;
- case PV_INEX: return &wp->w_buffer->b_p_inex_flags;
+ case PV_STL:
+ return &wp->w_p_stl_flags;
+ case PV_FDE:
+ return &wp->w_p_fde_flags;
+ case PV_FDT:
+ return &wp->w_p_fdt_flags;
+ case PV_INDE:
+ return &wp->w_buffer->b_p_inde_flags;
+ case PV_FEX:
+ return &wp->w_buffer->b_p_fex_flags;
+ case PV_INEX:
+ return &wp->w_buffer->b_p_inex_flags;
}
}
@@ -2154,23 +2122,19 @@ static void redraw_titles(void)
static int shada_idx = -1;
-// Set a string option to a new value (without checking the effect).
-// The string is copied into allocated memory.
-// if ("opt_idx" == -1) "name" is used, otherwise "opt_idx" is used.
-// When "set_sid" is zero set the scriptID to current_sctx.sc_sid. When
-// "set_sid" is SID_NONE don't set the scriptID. Otherwise set the scriptID to
-// "set_sid".
-void
-set_string_option_direct(
- const char *name,
- int opt_idx,
- const char_u *val,
- int opt_flags, // OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL
- int set_sid
-)
-{
- char_u *s;
- char_u **varp;
+/// Set a string option to a new value (without checking the effect).
+/// The string is copied into allocated memory.
+/// if ("opt_idx" == -1) "name" is used, otherwise "opt_idx" is used.
+/// When "set_sid" is zero set the scriptID to current_sctx.sc_sid. When
+/// "set_sid" is SID_NONE don't set the scriptID. Otherwise set the scriptID to
+/// "set_sid".
+///
+/// @param opt_flags OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL
+void set_string_option_direct(const char *name, int opt_idx, const char_u *val, int opt_flags,
+ int set_sid)
+{
+ char_u *s;
+ char_u **varp;
int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
int idx = opt_idx;
@@ -2187,7 +2151,7 @@ set_string_option_direct(
return;
}
- assert((void *) options[idx].var != (void *) &p_shada);
+ assert((void *)options[idx].var != (void *)&p_shada);
s = vim_strsave(val);
{
@@ -2227,13 +2191,12 @@ set_string_option_direct(
}
/// Set global value for string option when it's a local option.
-static void
-set_string_option_global(
- int opt_idx, // option index
- char_u **varp // pointer to option variable
-)
+///
+/// @param opt_idx option index
+/// @param varp pointer to option variable
+static void set_string_option_global(int opt_idx, char_u **varp)
{
- char_u **p, *s;
+ char_u **p, *s;
// the global value is always allocated
if (options[opt_idx].var == VAR_WIN) {
@@ -2256,8 +2219,7 @@ set_string_option_global(
/// #OPT_GLOBAL.
///
/// @return NULL on success, error message on error.
-static char *set_string_option(const int opt_idx, const char *const value,
- const int opt_flags)
+static char *set_string_option(const int opt_idx, const char *const value, const int opt_flags)
FUNC_ATTR_NONNULL_ARG(2) FUNC_ATTR_WARN_UNUSED_RESULT
{
if (options[opt_idx].var == NULL) { // don't set hidden option
@@ -2265,12 +2227,11 @@ static char *set_string_option(const int opt_idx, const char *const value,
}
char *const s = xstrdup(value);
- char **const varp = (char **)get_varp_scope(
- &(options[opt_idx]),
- ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0
+ char **const varp = (char **)get_varp_scope(&(options[opt_idx]),
+ ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0
? (((int)options[opt_idx].indir & PV_BOTH)
? OPT_GLOBAL : OPT_LOCAL)
- : opt_flags));
+ : opt_flags));
char *const oldval = *varp;
*varp = s;
@@ -2278,9 +2239,9 @@ static char *set_string_option(const int opt_idx, const char *const value,
char *const saved_newval = xstrdup(s);
int value_checked = false;
- char *const r = (char *)did_set_string_option(
- opt_idx, (char_u **)varp, (int)true, (char_u *)oldval,
- NULL, 0, opt_flags, &value_checked);
+ char *const r = (char *)did_set_string_option(opt_idx, (char_u **)varp, (int)true,
+ (char_u *)oldval,
+ NULL, 0, opt_flags, &value_checked);
if (r == NULL) {
did_set_option(opt_idx, opt_flags, true, value_checked);
}
@@ -2344,23 +2305,23 @@ static bool valid_spellfile(const char_u *val)
/// Handle string options that need some action to perform when changed.
/// Returns NULL for success, or an error message for an error.
-static char_u *
-did_set_string_option(
- int opt_idx, // index in options[] table
- char_u **varp, // pointer to the option variable
- bool new_value_alloced, // new value was allocated
- char_u *oldval, // previous value of the option
- char_u *errbuf, // buffer for errors, or NULL
- size_t errbuflen, // length of errors buffer
- int opt_flags, // OPT_LOCAL and/or OPT_GLOBAL
- int *value_checked // value was checked to be safe, no
- // need to set P_INSECURE
-)
-{
- char_u *errmsg = NULL;
- char_u *s, *p;
+///
+/// @param opt_idx index in options[] table
+/// @param varp pointer to the option variable
+/// @param new_value_alloced new value was allocated
+/// @param oldval previous value of the option
+/// @param errbuf buffer for errors, or NULL
+/// @param errbuflen length of errors buffer
+/// @param opt_flags OPT_LOCAL and/or OPT_GLOBAL
+/// @param value_checked value was checked to be safe, no need to set P_INSECURE
+static char_u *did_set_string_option(int opt_idx, char_u **varp, bool new_value_alloced,
+ char_u *oldval, char_u *errbuf, size_t errbuflen,
+ int opt_flags, int *value_checked)
+{
+ char_u *errmsg = NULL;
+ char_u *s, *p;
int did_chartab = false;
- char_u **gvarp;
+ char_u **gvarp;
bool free_oldval = (options[opt_idx].flags & P_ALLOCED);
bool value_changed = false;
@@ -2374,7 +2335,7 @@ did_set_string_option(
errmsg = e_secure;
} else if (((options[opt_idx].flags & P_NFNAME)
&& vim_strpbrk(*varp, (char_u *)(secure ? "/\\*?[|;&<>\r\n"
- : "/\\*?[<>\r\n")) != NULL)
+ : "/\\*?[<>\r\n")) != NULL)
|| ((options[opt_idx].flags & P_NDNAME)
&& vim_strpbrk(*varp, (char_u *)"*?[|;&<>\r\n") != NULL)) {
// Check for a "normal" directory or file name in some options. Disallow a
@@ -2382,7 +2343,7 @@ did_set_string_option(
// are often illegal in a file name. Be more permissive if "secure" is off.
errmsg = e_invarg;
} else if (gvarp == &p_bkc) { // 'backupcopy'
- char_u *bkc = p_bkc;
+ char_u *bkc = p_bkc;
unsigned int *flags = &bkc_flags;
if (opt_flags & OPT_LOCAL) {
@@ -2436,6 +2397,13 @@ did_set_string_option(
os_setenv("VIMRUNTIME", "", 1);
didset_vimruntime = false;
}
+ } else if (varp == &p_rtp || varp == &p_pp) { // 'runtimepath' 'packpath'
+ runtime_search_path_invalidate();
+ } else if (varp == &curwin->w_p_culopt
+ || gvarp == &curwin->w_allbuf_opt.wo_culopt) { // 'cursorlineopt'
+ if (**varp == NUL || fill_culopt_flags(*varp, curwin) != OK) {
+ errmsg = e_invarg;
+ }
} else if (varp == &curwin->w_p_cc) { // 'colorcolumn'
errmsg = check_colorcolumn(curwin);
} else if (varp == &p_hlg) { // 'helplang'
@@ -2517,13 +2485,14 @@ ambw_end:
check_string_option(&p_bg);
init_highlight(false, false);
}
- } else
+ } else {
errmsg = e_invarg;
+ }
} else if (varp == &p_wim) { // 'wildmode'
if (check_opt_wim() == FAIL) {
errmsg = e_invarg;
}
- // 'wildoptions'
+ // 'wildoptions'
} else if (varp == &p_wop) {
if (opt_strings_flags(p_wop, p_wop_values, &wop_flags, true) != OK) {
errmsg = e_invarg;
@@ -2537,7 +2506,7 @@ ambw_end:
if (check_ei() == FAIL) {
errmsg = e_invarg;
}
- // 'encoding', 'fileencoding' and 'makeencoding'
+ // 'encoding', 'fileencoding' and 'makeencoding'
} else if (varp == &p_enc || gvarp == &p_fenc || gvarp == &p_menc) {
if (gvarp == &p_fenc) {
if (!MODIFIABLE(curbuf) && opt_flags != OPT_GLOBAL) {
@@ -2708,7 +2677,7 @@ ambw_end:
if (*p_vfile != NUL && verbose_open() == FAIL) {
errmsg = e_invarg;
}
- // 'shada'
+ // 'shada'
} else if (varp == &p_shada) {
// TODO(ZyX-I): Remove this code in the future, alongside with &viminfo
// option.
@@ -2716,10 +2685,10 @@ ambw_end:
? (shada_idx == -1
? ((shada_idx = findoption("shada")))
: shada_idx)
- : opt_idx);
+ : opt_idx);
// Update free_oldval now that we have the opt_idx for 'shada', otherwise
// there would be a disconnect between the check for P_ALLOCED at the start
- // of the function and the set of P_ALLOCED at the end of the fuction.
+ // of the function and the set of P_ALLOCED at the end of the function.
free_oldval = (options[opt_idx].flags & P_ALLOCED);
for (s = p_shada; *s; ) {
// Check it's a valid character
@@ -2745,8 +2714,9 @@ ambw_end:
_("E526: Missing number after <%s>"),
transchar_byte(*(s - 1)));
errmsg = errbuf;
- } else
+ } else {
errmsg = (char_u *)"";
+ }
break;
}
}
@@ -2764,10 +2734,10 @@ ambw_end:
if (*p_shada && errmsg == NULL && get_shada_parameter('\'') < 0) {
errmsg = (char_u *)N_("E528: Must specify a ' value");
}
- } else if (varp == &p_sbr) { // 'showbreak'
- for (s = p_sbr; *s; ) {
+ } else if (gvarp == &p_sbr) { // 'showbreak'
+ for (s = *varp; *s; ) {
if (ptr2cells(s) != 1) {
- errmsg = (char_u *)N_("E595: contains unprintable or wide character");
+ errmsg = (char_u *)N_("E595: 'showbreak' contains unprintable or wide character");
}
MB_PTR_ADV(s);
}
@@ -2792,7 +2762,6 @@ ambw_end:
stl_syntax &= ~flagval;
}
did_set_title();
-
} else if (varp == &p_sel) { // 'selection'
if (*p_sel == NUL
|| check_opt_strings(p_sel, p_sel_values, false) != OK) {
@@ -2911,8 +2880,9 @@ ambw_end:
} else if (gvarp == &p_cpt) {
// check if it is a valid value for 'complete' -- Acevedo
for (s = *varp; *s; ) {
- while (*s == ',' || *s == ' ')
+ while (*s == ',' || *s == ' ') {
s++;
+ }
if (!*s) {
break;
}
@@ -2935,8 +2905,9 @@ ambw_end:
_("E535: Illegal character after <%c>"),
*--s);
errmsg = errbuf;
- } else
+ } else {
errmsg = (char_u *)"";
+ }
break;
}
}
@@ -3047,8 +3018,7 @@ ambw_end:
}
} else if (gvarp == &p_cms) { // 'commentstring'
if (**varp != NUL && strstr((char *)(*varp), "%s") == NULL) {
- errmsg = (char_u *)N_(
- "E537: 'commentstring' must be empty or contain %s");
+ errmsg = (char_u *)N_("E537: 'commentstring' must be empty or contain %s");
}
} else if (varp == &p_fdo) { // 'foldopen'
if (opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, true) != OK) {
@@ -3091,11 +3061,11 @@ ambw_end:
} else if (gvarp == &p_cino) { // 'cinoptions'
// TODO(vim): recognize errors
parse_cino(curbuf);
- // inccommand
+ // inccommand
} else if (varp == &p_icm) {
- if (check_opt_strings(p_icm, p_icm_values, false) != OK) {
- errmsg = e_invarg;
- }
+ if (check_opt_strings(p_icm, p_icm_values, false) != OK) {
+ errmsg = e_invarg;
+ }
} else if (gvarp == &p_ft) {
if (!valid_filetype(*varp)) {
errmsg = e_invarg;
@@ -3297,7 +3267,7 @@ ambw_end:
}
if (varp == &(curwin->w_s->b_p_spl)) {
char_u fname[200];
- char_u *q = curwin->w_s->b_p_spl;
+ char_u *q = curwin->w_s->b_p_spl;
// Skip the first name if it is "cjk".
if (STRNCMP(q, "cjk,", 4) == 0) {
@@ -3328,8 +3298,9 @@ ambw_end:
}
if (curwin->w_curswant != MAXCOL
- && (options[opt_idx].flags & (P_CURSWANT | P_RALL)) != 0)
+ && (options[opt_idx].flags & (P_CURSWANT | P_RALL)) != 0) {
curwin->w_set_curswant = true;
+ }
check_redraw(options[opt_idx].flags);
@@ -3357,8 +3328,7 @@ int check_signcolumn(char_u *val)
&& !STRNCMP(val, "auto:", 5)
&& ascii_isdigit(val[5])
&& val[6] == '-'
- && ascii_isdigit(val[7])
- ) {
+ && ascii_isdigit(val[7])) {
int min = val[5] - '0';
int max = val[7] - '0';
if (min < 1 || max < 2 || min > 8 || max > 9 || min >= max) {
@@ -3375,7 +3345,7 @@ int check_signcolumn(char_u *val)
/// @return error message, NULL if it's OK.
char_u *check_colorcolumn(win_T *wp)
{
- char_u *s;
+ char_u *s;
int col;
unsigned int count = 0;
int color_cols[256];
@@ -3465,11 +3435,13 @@ static char_u *set_chars_option(win_T *wp, char_u **varp, bool set)
int c1;
int c2 = 0;
int c3 = 0;
+ char_u *last_multispace = NULL; // Last occurrence of "multispace:"
+ int multispace_len = 0; // Length of lcs-multispace string
struct chars_tab {
- int *cp; ///< char value
- char *name; ///< char id
- int def; ///< default value
+ int *cp; ///< char value
+ char *name; ///< char id
+ int def; ///< default value
};
struct chars_tab *tab;
@@ -3534,6 +3506,15 @@ static char_u *set_chars_option(win_T *wp, char_u **varp, bool set)
if (varp == &p_lcs || varp == &wp->w_p_lcs) {
wp->w_p_lcs_chars.tab1 = NUL;
wp->w_p_lcs_chars.tab3 = NUL;
+ if (wp->w_p_lcs_chars.multispace != NULL) {
+ xfree(wp->w_p_lcs_chars.multispace);
+ }
+ if (multispace_len > 0) {
+ wp->w_p_lcs_chars.multispace = xmalloc((size_t)(multispace_len + 1) * sizeof(int));
+ wp->w_p_lcs_chars.multispace[multispace_len] = NUL;
+ } else {
+ wp->w_p_lcs_chars.multispace = NULL;
+ }
}
}
p = *varp;
@@ -3550,27 +3531,27 @@ static char_u *set_chars_option(win_T *wp, char_u **varp, bool set)
int c1len = utf_ptr2len(s);
c1 = mb_cptr2char_adv((const char_u **)&s);
if (mb_char2cells(c1) > 1 || (c1len == 1 && c1 > 127)) {
- continue;
+ return e_invarg;
}
if (tab[i].cp == &wp->w_p_lcs_chars.tab2) {
if (*s == NUL) {
- continue;
+ return e_invarg;
}
int c2len = utf_ptr2len(s);
c2 = mb_cptr2char_adv((const char_u **)&s);
if (mb_char2cells(c2) > 1 || (c2len == 1 && c2 > 127)) {
- continue;
+ return e_invarg;
}
if (!(*s == ',' || *s == NUL)) {
int c3len = utf_ptr2len(s);
c3 = mb_cptr2char_adv((const char_u **)&s);
if (mb_char2cells(c3) > 1 || (c3len == 1 && c3 > 127)) {
- continue;
+ return e_invarg;
}
}
}
if (*s == ',' || *s == NUL) {
- if (round) {
+ if (round > 0) {
if (tab[i].cp == &wp->w_p_lcs_chars.tab2) {
wp->w_p_lcs_chars.tab1 = c1;
wp->w_p_lcs_chars.tab2 = c2;
@@ -3586,7 +3567,42 @@ static char_u *set_chars_option(win_T *wp, char_u **varp, bool set)
}
if (i == entries) {
- return e_invarg;
+ len = (int)STRLEN("multispace");
+ if ((varp == &p_lcs || varp == &wp->w_p_lcs)
+ && STRNCMP(p, "multispace", len) == 0
+ && p[len] == ':'
+ && p[len + 1] != NUL) {
+ s = p + len + 1;
+ if (round == 0) {
+ // Get length of lcs-multispace string in the first round
+ last_multispace = p;
+ multispace_len = 0;
+ while (*s != NUL && *s != ',') {
+ int c1len = utf_ptr2len(s);
+ c1 = mb_cptr2char_adv((const char_u **)&s);
+ if (mb_char2cells(c1) > 1 || (c1len == 1 && c1 > 127)) {
+ return e_invarg;
+ }
+ multispace_len++;
+ }
+ if (multispace_len == 0) {
+ // lcs-multispace cannot be an empty string
+ return e_invarg;
+ }
+ p = s;
+ } else {
+ int multispace_pos = 0;
+ while (*s != NUL && *s != ',') {
+ c1 = mb_cptr2char_adv((const char_u **)&s);
+ if (p == last_multispace) {
+ wp->w_p_lcs_chars.multispace[multispace_pos++] = c1;
+ }
+ }
+ p = s;
+ }
+ } else {
+ return e_invarg;
+ }
}
if (*p == ',') {
p++;
@@ -3635,8 +3651,9 @@ char_u *check_stl_option(char_u *s)
}
if (*s == '.') {
s++;
- while (*s && ascii_isdigit(*s))
+ while (*s && ascii_isdigit(*s)) {
s++;
+ }
}
if (*s == '(') {
groupdepth++;
@@ -3664,7 +3681,7 @@ char_u *check_stl_option(char_u *s)
static char_u *did_set_spell_option(bool is_spellfile)
{
- char_u *errmsg = NULL;
+ char_u *errmsg = NULL;
if (is_spellfile) {
int l = (int)STRLEN(curwin->w_s->b_p_spf);
@@ -3691,8 +3708,8 @@ static char_u *did_set_spell_option(bool is_spellfile)
static char_u *compile_cap_prog(synblock_T *synblock)
FUNC_ATTR_NONNULL_ALL
{
- regprog_T *rp = synblock->b_cap_prog;
- char_u *re;
+ regprog_T *rp = synblock->b_cap_prog;
+ char_u *re;
if (synblock->b_p_spc == NULL || *synblock->b_p_spc == NUL) {
synblock->b_cap_prog = NULL;
@@ -3791,8 +3808,7 @@ static void set_option_sctx_idx(int opt_idx, int opt_flags, sctx_T script_ctx)
/// @param[in] opt_flags OPT_LOCAL and/or OPT_GLOBAL.
///
/// @return NULL on success, error message on error.
-static char *set_bool_option(const int opt_idx, char_u *const varp,
- const int value,
+static char *set_bool_option(const int opt_idx, char_u *const varp, const int value,
const int opt_flags)
{
int old_value = *(int *)varp;
@@ -3817,7 +3833,7 @@ static char *set_bool_option(const int opt_idx, char_u *const varp,
if ((int *)varp == &p_force_on && p_force_on == false) {
p_force_on = true;
return (char *)e_unsupportedoption;
- // Ensure that options set to p_force_off cannot be enabled.
+ // Ensure that options set to p_force_off cannot be enabled.
} else if ((int *)varp == &p_force_off && p_force_off == true) {
p_force_off = false;
return (char *)e_unsupportedoption;
@@ -3830,29 +3846,26 @@ static char *set_bool_option(const int opt_idx, char_u *const varp,
} else if ((int *)varp == &curwin->w_p_cul && !value && old_value) {
// 'cursorline'
reset_cursorline();
- // 'undofile'
+ // 'undofile'
} else if ((int *)varp == &curbuf->b_p_udf || (int *)varp == &p_udf) {
// Only take action when the option was set. When reset we do not
// delete the undo file, the option may be set again without making
// any changes in between.
if (curbuf->b_p_udf || p_udf) {
char_u hash[UNDO_HASH_SIZE];
- buf_T *save_curbuf = curbuf;
FOR_ALL_BUFFERS(bp) {
- curbuf = bp;
// When 'undofile' is set globally: for every buffer, otherwise
// only for the current buffer: Try to read in the undofile,
// if one exists, the buffer wasn't changed and the buffer was
// loaded
- if ((curbuf == save_curbuf
+ if ((curbuf == bp
|| (opt_flags & OPT_GLOBAL) || opt_flags == 0)
- && !curbufIsChanged() && curbuf->b_ml.ml_mfp != NULL) {
- u_compute_hash(hash);
- u_read_undo(NULL, hash, curbuf->b_fname);
+ && !bufIsChanged(bp) && bp->b_ml.ml_mfp != NULL) {
+ u_compute_hash(bp, hash);
+ u_read_undo(NULL, hash, bp->b_fname);
}
}
- curbuf = save_curbuf;
}
} else if ((int *)varp == &curbuf->b_p_ro) {
// when 'readonly' is reset globally, also reset readonlymode
@@ -3897,7 +3910,7 @@ static char *set_bool_option(const int opt_idx, char_u *const varp,
}
} else if ((int *)varp == &p_terse) {
// when 'terse' is set change 'shortmess'
- char_u *p;
+ char_u *p;
p = vim_strchr(p_shm, SHM_SEARCH);
@@ -3934,8 +3947,8 @@ static char *set_bool_option(const int opt_idx, char_u *const varp,
// when 'hlsearch' is set or reset: reset no_hlsearch
set_no_hlsearch(false);
} else if ((int *)varp == &curwin->w_p_scb) {
- // when 'scrollbind' is set: snapshot the current position to avoid a jump
- // at the end of normal_cmd()
+ // when 'scrollbind' is set: snapshot the current position to avoid a jump
+ // at the end of normal_cmd()
if (curwin->w_p_scb) {
do_check_scrollbind(false);
curwin->w_scbind_pos = curwin->w_topline;
@@ -4005,7 +4018,7 @@ static char *set_bool_option(const int opt_idx, char_u *const varp,
}
} else if ((int *)varp == &curwin->w_p_spell) { // 'spell'
if (curwin->w_p_spell) {
- char_u *errmsg = did_set_spelllang(curwin);
+ char_u *errmsg = did_set_spelllang(curwin);
if (errmsg != NULL) {
EMSG(_(errmsg));
}
@@ -4034,8 +4047,7 @@ static char *set_bool_option(const int opt_idx, char_u *const varp,
/* Arabic requires a utf-8 encoding, inform the user if its not
* set. */
if (STRCMP(p_enc, "utf-8") != 0) {
- static char *w_arabic = N_(
- "W17: Arabic requires UTF-8, do ':set encoding=utf-8'");
+ static char *w_arabic = N_("W17: Arabic requires UTF-8, do ':set encoding=utf-8'");
msg_source(HL_ATTR(HLF_W));
msg_attr(_(w_arabic), HL_ATTR(HLF_W));
@@ -4095,7 +4107,7 @@ static char *set_bool_option(const int opt_idx, char_u *const varp,
set_vim_var_string(VV_OPTION_OLD, buf_old, -1);
set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
apply_autocmds(EVENT_OPTIONSET,
- (char_u *) options[opt_idx].fullname,
+ (char_u *)options[opt_idx].fullname,
NULL, false, NULL);
reset_v_option_vars();
}
@@ -4125,13 +4137,13 @@ static char *set_bool_option(const int opt_idx, char_u *const varp,
/// @param[in] opt_flags OPT_LOCAL, OPT_GLOBAL or OPT_MODELINE.
///
/// @return NULL on success, error message on error.
-static char *set_num_option(int opt_idx, char_u *varp, long value,
- char_u *errbuf, size_t errbuflen, int opt_flags)
+static char *set_num_option(int opt_idx, char_u *varp, long value, char_u *errbuf, size_t errbuflen,
+ int opt_flags)
{
- char_u *errmsg = NULL;
+ char_u *errmsg = NULL;
long old_value = *(long *)varp;
long old_Rows = Rows; // remember old Rows
- long *pp = (long *)varp;
+ long *pp = (long *)varp;
// Disallow changing some options from secure mode.
if ((secure || sandbox != 0)
@@ -4141,7 +4153,7 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
// Many number options assume their value is in the signed int range.
if (value < INT_MIN || value > INT_MAX) {
- return (char *)e_invarg;
+ return (char *)e_invarg;
}
// Options that need some validation.
@@ -4405,7 +4417,7 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
if (p_lines < min_rows() && full_screen) {
if (errbuf != NULL) {
vim_snprintf((char *)errbuf, errbuflen,
- _("E593: Need at least %d lines"), min_rows());
+ _("E593: Need at least %d lines"), min_rows());
errmsg = errbuf;
}
p_lines = min_rows();
@@ -4413,7 +4425,7 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
if (p_columns < MIN_COLUMNS && full_screen) {
if (errbuf != NULL) {
vim_snprintf((char *)errbuf, errbuflen,
- _("E594: Need at least %d columns"), MIN_COLUMNS);
+ _("E594: Need at least %d columns"), MIN_COLUMNS);
errmsg = errbuf;
}
p_columns = MIN_COLUMNS;
@@ -4458,7 +4470,7 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
}
win_comp_scroll(curwin);
} else if (curwin->w_p_scr <= 0) {
- // If 'scroll' became invalid because of a side effect silently adjust it.
+ // If 'scroll' became invalid because of a side effect silently adjust it.
curwin->w_p_scr = 1;
} else { // curwin->w_p_scr > curwin->w_height
curwin->w_p_scr = curwin->w_height;
@@ -4494,7 +4506,7 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
set_vim_var_string(VV_OPTION_OLD, buf_old, -1);
set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
apply_autocmds(EVENT_OPTIONSET,
- (char_u *) options[opt_idx].fullname,
+ (char_u *)options[opt_idx].fullname,
NULL, false, NULL);
reset_v_option_vars();
}
@@ -4514,8 +4526,7 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
return (char *)errmsg;
}
-static void trigger_optionsset_string(int opt_idx, int opt_flags,
- char *oldval, char *newval)
+static void trigger_optionsset_string(int opt_idx, int opt_flags, char *oldval, char *newval)
{
// Don't do this recursively.
if (oldval != NULL
@@ -4638,8 +4649,8 @@ bool is_tty_option(const char *name)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
return (name[0] == 't' && name[1] == '_')
- || strequal(name, "term")
- || strequal(name, "ttytype");
+ || strequal(name, "term")
+ || strequal(name, "ttytype");
}
#define TCO_BUFFER_SIZE 8
@@ -4718,18 +4729,15 @@ static int findoption(const char *const arg)
/// Gets the value for an option.
///
+/// @param stringval NULL when only checking existence
+///
/// @returns:
/// Number or Toggle option: 1, *numval gets value.
/// String option: 0, *stringval gets allocated string.
/// Hidden Number or Toggle option: -1.
/// hidden String option: -2.
/// unknown option: -3.
-int get_option_value(
- const char *name,
- long *numval,
- char_u **stringval, ///< NULL when only checking existence
- int opt_flags
-)
+int get_option_value(const char *name, long *numval, char_u **stringval, int opt_flags)
{
if (get_tty_option(name, (char **)stringval)) {
return 0;
@@ -4763,7 +4771,7 @@ int get_option_value(
if ((int *)varp == &curbuf->b_changed) {
*numval = curbufIsChanged();
} else {
- *numval = (long) *(int *)varp; // NOLINT(whitespace/cast)
+ *numval = (long)*(int *)varp; // NOLINT(whitespace/cast)
}
}
return 1;
@@ -4785,11 +4793,7 @@ int get_option_value(
// see SOPT_* in option_defs.h for other flags
//
// Possible opt_type values: see SREQ_* in option_defs.h
-int get_option_value_strict(char *name,
- int64_t *numval,
- char **stringval,
- int opt_type,
- void *from)
+int get_option_value_strict(char *name, int64_t *numval, char **stringval, int opt_type, void *from)
{
if (get_tty_option(name, stringval)) {
return SOPT_STRING | SOPT_GLOBAL;
@@ -4905,8 +4909,8 @@ int get_option_value_strict(char *name,
/// @param[in] opt_flags Flags: OPT_LOCAL, OPT_GLOBAL, or 0 (both).
///
/// @return NULL on success, error message on error.
-char *set_option_value(const char *const name, const long number,
- const char *const string, const int opt_flags)
+char *set_option_value(const char *const name, const long number, const char *const string,
+ const int opt_flags)
FUNC_ATTR_NONNULL_ARG(1)
{
if (is_tty_option(name)) {
@@ -4914,7 +4918,7 @@ char *set_option_value(const char *const name, const long number,
}
int opt_idx;
- char_u *varp;
+ char_u *varp;
opt_idx = findoption(name);
if (opt_idx < 0) {
@@ -4974,7 +4978,7 @@ int find_key_option_len(const char_u *arg_arg, size_t len, bool has_lt)
// add_termcap_entry().
if (len >= 4 && arg[0] == 't' && arg[1] == '_') {
key = TERMCAP2KEY(arg[2], arg[3]);
- } else if (has_lt) {
+ } else if (has_lt) {
arg--; // put arg at the '<'
modifiers = 0;
key = find_special_key(&arg, len + 1, &modifiers, true, true, false);
@@ -4992,15 +4996,13 @@ static int find_key_option(const char_u *arg, bool has_lt)
/// if 'all' == 0: show changed options
/// if 'all' == 1: show all normal options
-static void
-showoptions(
- int all,
- int opt_flags // OPT_LOCAL and/or OPT_GLOBAL
-)
+///
+/// @param opt_flags OPT_LOCAL and/or OPT_GLOBAL
+static void showoptions(int all, int opt_flags)
{
- vimoption_T *p;
+ vimoption_T *p;
int col;
- char_u *varp;
+ char_u *varp;
int item_count;
int run;
int row, rows;
@@ -5094,20 +5096,17 @@ showoptions(
/// Return true if option "p" has its default value.
static int optval_default(vimoption_T *p, char_u *varp)
{
- int dvi;
-
if (varp == NULL) {
return true; // hidden option is always at default
}
- dvi = (p->flags & P_VI_DEF) ? VI_DEFAULT : VIM_DEFAULT;
if (p->flags & P_NUM) {
- return *(long *)varp == (long)(intptr_t)p->def_val[dvi];
+ return *(long *)varp == (long)(intptr_t)p->def_val;
}
if (p->flags & P_BOOL) {
- return *(int *)varp == (int)(intptr_t)p->def_val[dvi];
+ return *(int *)varp == (int)(intptr_t)p->def_val;
}
// P_STRING
- return STRCMP(*(char_u **)varp, p->def_val[dvi]) == 0;
+ return STRCMP(*(char_u **)varp, p->def_val) == 0;
}
/// Send update to UIs with values of UI relevant options
@@ -5138,13 +5137,11 @@ void ui_refresh_options(void)
/// showoneopt: show the value of one option
/// must not be called with a hidden option!
-static void
-showoneopt(
- vimoption_T *p,
- int opt_flags // OPT_LOCAL or OPT_GLOBAL
-)
+///
+/// @param opt_flags OPT_LOCAL or OPT_GLOBAL
+static void showoneopt(vimoption_T *p, int opt_flags)
{
- char_u *varp;
+ char_u *varp;
int save_silent = silent_mode;
silent_mode = false;
@@ -5195,11 +5192,11 @@ showoneopt(
/// Return FAIL on error, OK otherwise.
int makeset(FILE *fd, int opt_flags, int local_only)
{
- vimoption_T *p;
- char_u *varp; // currently used value
- char_u *varp_fresh; // local value
- char_u *varp_local = NULL; // fresh value
- char *cmd;
+ vimoption_T *p;
+ char_u *varp; // currently used value
+ char_u *varp_fresh; // local value
+ char_u *varp_local = NULL; // fresh value
+ char *cmd;
int round;
int pri;
@@ -5323,21 +5320,20 @@ int makefoldset(FILE *fd)
|| put_setnum(fd, "setlocal", "fdl", &curwin->w_p_fdl) == FAIL
|| put_setnum(fd, "setlocal", "fml", &curwin->w_p_fml) == FAIL
|| put_setnum(fd, "setlocal", "fdn", &curwin->w_p_fdn) == FAIL
- || put_setbool(fd, "setlocal", "fen", curwin->w_p_fen) == FAIL
- ) {
+ || put_setbool(fd, "setlocal", "fen",
+ curwin->w_p_fen) == FAIL) {
return FAIL;
}
return OK;
}
-static int put_setstring(FILE *fd, char *cmd, char *name,
- char_u **valuep, uint64_t flags)
+static int put_setstring(FILE *fd, char *cmd, char *name, char_u **valuep, uint64_t flags)
{
- char_u *s;
- char_u *buf = NULL;
- char_u *part = NULL;
- char_u *p;
+ char_u *s;
+ char_u *buf = NULL;
+ char_u *part = NULL;
+ char_u *p;
if (fprintf(fd, "%s %s=", cmd, name) < 0) {
return FAIL;
@@ -5363,7 +5359,7 @@ static int put_setstring(FILE *fd, char *cmd, char *name,
home_replace(NULL, *valuep, buf, size, false);
// If the option value is longer than MAXPATHL, we need to append
- // earch comma separated part of the option sperately, so that it
+ // search comma separated part of the option separately, so that it
// can be expanded when read back.
if (size >= MAXPATHL && (flags & P_COMMA) != 0
&& vim_strchr(*valuep, ',') != NULL) {
@@ -5375,15 +5371,15 @@ static int put_setstring(FILE *fd, char *cmd, char *name,
}
p = buf;
while (*p != NUL) {
- // for each comma separated option part, append value to
- // the option, :set rtp+=value
- if (fprintf(fd, "%s %s+=", cmd, name) < 0) {
- goto fail;
- }
- (void)copy_option_part(&p, part, size, ",");
- if (put_escstr(fd, part, 2) == FAIL || put_eol(fd) == FAIL) {
- goto fail;
- }
+ // for each comma separated option part, append value to
+ // the option, :set rtp+=value
+ if (fprintf(fd, "%s %s+=", cmd, name) < 0) {
+ goto fail;
+ }
+ (void)copy_option_part(&p, part, size, ",");
+ if (put_escstr(fd, part, 2) == FAIL || put_eol(fd) == FAIL) {
+ goto fail;
+ }
}
xfree(buf);
xfree(part);
@@ -5499,120 +5495,149 @@ void unset_global_local_option(char *name, void *from)
switch ((int)p->indir)
{
- // global option with local value: use local value if it's been set
+ // global option with local value: use local value if it's been set
+ case PV_EP:
+ clear_string_option(&buf->b_p_ep);
+ break;
+ case PV_KP:
+ clear_string_option(&buf->b_p_kp);
+ break;
+ case PV_PATH:
+ clear_string_option(&buf->b_p_path);
+ break;
+ case PV_AR:
+ buf->b_p_ar = -1;
+ break;
+ case PV_BKC:
+ clear_string_option(&buf->b_p_bkc);
+ buf->b_bkc_flags = 0;
+ break;
+ case PV_TAGS:
+ clear_string_option(&buf->b_p_tags);
+ break;
+ case PV_TC:
+ clear_string_option(&buf->b_p_tc);
+ buf->b_tc_flags = 0;
+ break;
+ case PV_SISO:
+ curwin->w_p_siso = -1;
+ break;
+ case PV_SO:
+ curwin->w_p_so = -1;
+ break;
+ case PV_DEF:
+ clear_string_option(&buf->b_p_def);
+ break;
+ case PV_INC:
+ clear_string_option(&buf->b_p_inc);
+ break;
+ case PV_DICT:
+ clear_string_option(&buf->b_p_dict);
+ break;
+ case PV_TSR:
+ clear_string_option(&buf->b_p_tsr);
+ break;
+ case PV_FP:
+ clear_string_option(&buf->b_p_fp);
+ break;
+ case PV_EFM:
+ clear_string_option(&buf->b_p_efm);
+ break;
+ case PV_GP:
+ clear_string_option(&buf->b_p_gp);
+ break;
+ case PV_MP:
+ clear_string_option(&buf->b_p_mp);
+ break;
+ case PV_SBR:
+ clear_string_option(&((win_T *)from)->w_p_sbr);
+ break;
+ case PV_STL:
+ clear_string_option(&((win_T *)from)->w_p_stl);
+ break;
+ case PV_UL:
+ buf->b_p_ul = NO_LOCAL_UNDOLEVEL;
+ break;
+ case PV_LW:
+ clear_string_option(&buf->b_p_lw);
+ break;
+ case PV_MENC:
+ clear_string_option(&buf->b_p_menc);
+ break;
+ case PV_LCS:
+ clear_string_option(&((win_T *)from)->w_p_lcs);
+ set_chars_option((win_T *)from, &((win_T *)from)->w_p_lcs, true);
+ redraw_later((win_T *)from, NOT_VALID);
+ break;
+ case PV_FCS:
+ clear_string_option(&((win_T *)from)->w_p_fcs);
+ set_chars_option((win_T *)from, &((win_T *)from)->w_p_fcs, true);
+ redraw_later((win_T *)from, NOT_VALID);
+ break;
+ }
+}
+
+/// Get pointer to option variable, depending on local or global scope.
+static char_u *get_varp_scope(vimoption_T *p, int opt_flags)
+{
+ if ((opt_flags & OPT_GLOBAL) && p->indir != PV_NONE) {
+ if (p->var == VAR_WIN) {
+ return (char_u *)GLOBAL_WO(get_varp(p));
+ }
+ return p->var;
+ }
+ if ((opt_flags & OPT_LOCAL) && ((int)p->indir & PV_BOTH)) {
+ switch ((int)p->indir) {
+ case PV_FP:
+ return (char_u *)&(curbuf->b_p_fp);
+ case PV_EFM:
+ return (char_u *)&(curbuf->b_p_efm);
+ case PV_GP:
+ return (char_u *)&(curbuf->b_p_gp);
+ case PV_MP:
+ return (char_u *)&(curbuf->b_p_mp);
case PV_EP:
- clear_string_option(&buf->b_p_ep);
- break;
+ return (char_u *)&(curbuf->b_p_ep);
case PV_KP:
- clear_string_option(&buf->b_p_kp);
- break;
+ return (char_u *)&(curbuf->b_p_kp);
case PV_PATH:
- clear_string_option(&buf->b_p_path);
- break;
+ return (char_u *)&(curbuf->b_p_path);
case PV_AR:
- buf->b_p_ar = -1;
- break;
- case PV_BKC:
- clear_string_option(&buf->b_p_bkc);
- buf->b_bkc_flags = 0;
- break;
+ return (char_u *)&(curbuf->b_p_ar);
case PV_TAGS:
- clear_string_option(&buf->b_p_tags);
- break;
+ return (char_u *)&(curbuf->b_p_tags);
case PV_TC:
- clear_string_option(&buf->b_p_tc);
- buf->b_tc_flags = 0;
- break;
+ return (char_u *)&(curbuf->b_p_tc);
case PV_SISO:
- curwin->w_p_siso = -1;
- break;
+ return (char_u *)&(curwin->w_p_siso);
case PV_SO:
- curwin->w_p_so = -1;
- break;
+ return (char_u *)&(curwin->w_p_so);
case PV_DEF:
- clear_string_option(&buf->b_p_def);
- break;
+ return (char_u *)&(curbuf->b_p_def);
case PV_INC:
- clear_string_option(&buf->b_p_inc);
- break;
+ return (char_u *)&(curbuf->b_p_inc);
case PV_DICT:
- clear_string_option(&buf->b_p_dict);
- break;
+ return (char_u *)&(curbuf->b_p_dict);
case PV_TSR:
- clear_string_option(&buf->b_p_tsr);
- break;
- case PV_FP:
- clear_string_option(&buf->b_p_fp);
- break;
- case PV_EFM:
- clear_string_option(&buf->b_p_efm);
- break;
- case PV_GP:
- clear_string_option(&buf->b_p_gp);
- break;
- case PV_MP:
- clear_string_option(&buf->b_p_mp);
- break;
+ return (char_u *)&(curbuf->b_p_tsr);
+ case PV_TFU:
+ return (char_u *)&(curbuf->b_p_tfu);
+ case PV_SBR:
+ return (char_u *)&(curwin->w_p_sbr);
case PV_STL:
- clear_string_option(&((win_T *)from)->w_p_stl);
- break;
+ return (char_u *)&(curwin->w_p_stl);
case PV_UL:
- buf->b_p_ul = NO_LOCAL_UNDOLEVEL;
- break;
+ return (char_u *)&(curbuf->b_p_ul);
case PV_LW:
- clear_string_option(&buf->b_p_lw);
- break;
+ return (char_u *)&(curbuf->b_p_lw);
+ case PV_BKC:
+ return (char_u *)&(curbuf->b_p_bkc);
case PV_MENC:
- clear_string_option(&buf->b_p_menc);
- break;
- case PV_LCS:
- clear_string_option(&((win_T *)from)->w_p_lcs);
- set_chars_option((win_T *)from, &((win_T *)from)->w_p_lcs, true);
- redraw_later((win_T *)from, NOT_VALID);
- break;
+ return (char_u *)&(curbuf->b_p_menc);
case PV_FCS:
- clear_string_option(&((win_T *)from)->w_p_fcs);
- set_chars_option((win_T *)from, &((win_T *)from)->w_p_fcs, true);
- redraw_later((win_T *)from, NOT_VALID);
- break;
- }
-}
-
-/// Get pointer to option variable, depending on local or global scope.
-static char_u *get_varp_scope(vimoption_T *p, int opt_flags)
-{
- if ((opt_flags & OPT_GLOBAL) && p->indir != PV_NONE) {
- if (p->var == VAR_WIN) {
- return (char_u *)GLOBAL_WO(get_varp(p));
- }
- return p->var;
- }
- if ((opt_flags & OPT_LOCAL) && ((int)p->indir & PV_BOTH)) {
- switch ((int)p->indir) {
- case PV_FP: return (char_u *)&(curbuf->b_p_fp);
- case PV_EFM: return (char_u *)&(curbuf->b_p_efm);
- case PV_GP: return (char_u *)&(curbuf->b_p_gp);
- case PV_MP: return (char_u *)&(curbuf->b_p_mp);
- case PV_EP: return (char_u *)&(curbuf->b_p_ep);
- case PV_KP: return (char_u *)&(curbuf->b_p_kp);
- case PV_PATH: return (char_u *)&(curbuf->b_p_path);
- case PV_AR: return (char_u *)&(curbuf->b_p_ar);
- case PV_TAGS: return (char_u *)&(curbuf->b_p_tags);
- case PV_TC: return (char_u *)&(curbuf->b_p_tc);
- case PV_SISO: return (char_u *)&(curwin->w_p_siso);
- case PV_SO: return (char_u *)&(curwin->w_p_so);
- case PV_DEF: return (char_u *)&(curbuf->b_p_def);
- case PV_INC: return (char_u *)&(curbuf->b_p_inc);
- case PV_DICT: return (char_u *)&(curbuf->b_p_dict);
- case PV_TSR: return (char_u *)&(curbuf->b_p_tsr);
- case PV_TFU: return (char_u *)&(curbuf->b_p_tfu);
- case PV_STL: return (char_u *)&(curwin->w_p_stl);
- case PV_UL: return (char_u *)&(curbuf->b_p_ul);
- case PV_LW: return (char_u *)&(curbuf->b_p_lw);
- case PV_BKC: return (char_u *)&(curbuf->b_p_bkc);
- case PV_MENC: return (char_u *)&(curbuf->b_p_menc);
- case PV_FCS: return (char_u *)&(curwin->w_p_fcs);
- case PV_LCS: return (char_u *)&(curwin->w_p_lcs);
+ return (char_u *)&(curwin->w_p_fcs);
+ case PV_LCS:
+ return (char_u *)&(curwin->w_p_lcs);
}
return NULL; // "cannot happen"
}
@@ -5628,160 +5653,290 @@ static char_u *get_varp(vimoption_T *p)
}
switch ((int)p->indir) {
- case PV_NONE: return p->var;
+ case PV_NONE:
+ return p->var;
// global option with local value: use local value if it's been set
- case PV_EP: return *curbuf->b_p_ep != NUL
+ case PV_EP:
+ return *curbuf->b_p_ep != NUL
? (char_u *)&curbuf->b_p_ep : p->var;
- case PV_KP: return *curbuf->b_p_kp != NUL
+ case PV_KP:
+ return *curbuf->b_p_kp != NUL
? (char_u *)&curbuf->b_p_kp : p->var;
- case PV_PATH: return *curbuf->b_p_path != NUL
+ case PV_PATH:
+ return *curbuf->b_p_path != NUL
? (char_u *)&(curbuf->b_p_path) : p->var;
- case PV_AR: return curbuf->b_p_ar >= 0
+ case PV_AR:
+ return curbuf->b_p_ar >= 0
? (char_u *)&(curbuf->b_p_ar) : p->var;
- case PV_TAGS: return *curbuf->b_p_tags != NUL
+ case PV_TAGS:
+ return *curbuf->b_p_tags != NUL
? (char_u *)&(curbuf->b_p_tags) : p->var;
- case PV_TC: return *curbuf->b_p_tc != NUL
+ case PV_TC:
+ return *curbuf->b_p_tc != NUL
? (char_u *)&(curbuf->b_p_tc) : p->var;
- case PV_SISO: return curwin->w_p_siso >= 0
+ case PV_SISO:
+ return curwin->w_p_siso >= 0
? (char_u *)&(curwin->w_p_siso) : p->var;
- case PV_SO: return curwin->w_p_so >= 0
+ case PV_SO:
+ return curwin->w_p_so >= 0
? (char_u *)&(curwin->w_p_so) : p->var;
- case PV_BKC: return *curbuf->b_p_bkc != NUL
+ case PV_BKC:
+ return *curbuf->b_p_bkc != NUL
? (char_u *)&(curbuf->b_p_bkc) : p->var;
- case PV_DEF: return *curbuf->b_p_def != NUL
+ case PV_DEF:
+ return *curbuf->b_p_def != NUL
? (char_u *)&(curbuf->b_p_def) : p->var;
- case PV_INC: return *curbuf->b_p_inc != NUL
+ case PV_INC:
+ return *curbuf->b_p_inc != NUL
? (char_u *)&(curbuf->b_p_inc) : p->var;
- case PV_DICT: return *curbuf->b_p_dict != NUL
+ case PV_DICT:
+ return *curbuf->b_p_dict != NUL
? (char_u *)&(curbuf->b_p_dict) : p->var;
- case PV_TSR: return *curbuf->b_p_tsr != NUL
+ case PV_TSR:
+ return *curbuf->b_p_tsr != NUL
? (char_u *)&(curbuf->b_p_tsr) : p->var;
- case PV_FP: return *curbuf->b_p_fp != NUL
+ case PV_FP:
+ return *curbuf->b_p_fp != NUL
? (char_u *)&(curbuf->b_p_fp) : p->var;
- case PV_EFM: return *curbuf->b_p_efm != NUL
+ case PV_EFM:
+ return *curbuf->b_p_efm != NUL
? (char_u *)&(curbuf->b_p_efm) : p->var;
- case PV_GP: return *curbuf->b_p_gp != NUL
+ case PV_GP:
+ return *curbuf->b_p_gp != NUL
? (char_u *)&(curbuf->b_p_gp) : p->var;
- case PV_MP: return *curbuf->b_p_mp != NUL
+ case PV_MP:
+ return *curbuf->b_p_mp != NUL
? (char_u *)&(curbuf->b_p_mp) : p->var;
- case PV_STL: return *curwin->w_p_stl != NUL
+ case PV_SBR:
+ return *curwin->w_p_sbr != NUL
+ ? (char_u *)&(curwin->w_p_sbr) : p->var;
+ case PV_STL:
+ return *curwin->w_p_stl != NUL
? (char_u *)&(curwin->w_p_stl) : p->var;
- case PV_UL: return curbuf->b_p_ul != NO_LOCAL_UNDOLEVEL
+ case PV_UL:
+ return curbuf->b_p_ul != NO_LOCAL_UNDOLEVEL
? (char_u *)&(curbuf->b_p_ul) : p->var;
- case PV_LW: return *curbuf->b_p_lw != NUL
+ case PV_LW:
+ return *curbuf->b_p_lw != NUL
? (char_u *)&(curbuf->b_p_lw) : p->var;
- case PV_MENC: return *curbuf->b_p_menc != NUL
+ case PV_MENC:
+ return *curbuf->b_p_menc != NUL
? (char_u *)&(curbuf->b_p_menc) : p->var;
- case PV_FCS: return *curwin->w_p_fcs != NUL
+ case PV_FCS:
+ return *curwin->w_p_fcs != NUL
? (char_u *)&(curwin->w_p_fcs) : p->var;
- case PV_LCS: return *curwin->w_p_lcs != NUL
+ case PV_LCS:
+ return *curwin->w_p_lcs != NUL
? (char_u *)&(curwin->w_p_lcs) : p->var;
- case PV_ARAB: return (char_u *)&(curwin->w_p_arab);
- case PV_LIST: return (char_u *)&(curwin->w_p_list);
- case PV_SPELL: return (char_u *)&(curwin->w_p_spell);
- case PV_CUC: return (char_u *)&(curwin->w_p_cuc);
- case PV_CUL: return (char_u *)&(curwin->w_p_cul);
- case PV_CC: return (char_u *)&(curwin->w_p_cc);
- case PV_DIFF: return (char_u *)&(curwin->w_p_diff);
- case PV_FDC: return (char_u *)&(curwin->w_p_fdc);
- case PV_FEN: return (char_u *)&(curwin->w_p_fen);
- case PV_FDI: return (char_u *)&(curwin->w_p_fdi);
- case PV_FDL: return (char_u *)&(curwin->w_p_fdl);
- case PV_FDM: return (char_u *)&(curwin->w_p_fdm);
- case PV_FML: return (char_u *)&(curwin->w_p_fml);
- case PV_FDN: return (char_u *)&(curwin->w_p_fdn);
- case PV_FDE: return (char_u *)&(curwin->w_p_fde);
- case PV_FDT: return (char_u *)&(curwin->w_p_fdt);
- case PV_FMR: return (char_u *)&(curwin->w_p_fmr);
- case PV_NU: return (char_u *)&(curwin->w_p_nu);
- case PV_RNU: return (char_u *)&(curwin->w_p_rnu);
- case PV_NUW: return (char_u *)&(curwin->w_p_nuw);
- case PV_WFH: return (char_u *)&(curwin->w_p_wfh);
- case PV_WFW: return (char_u *)&(curwin->w_p_wfw);
- case PV_PVW: return (char_u *)&(curwin->w_p_pvw);
- case PV_RL: return (char_u *)&(curwin->w_p_rl);
- case PV_RLC: return (char_u *)&(curwin->w_p_rlc);
- case PV_SCROLL: return (char_u *)&(curwin->w_p_scr);
- case PV_WRAP: return (char_u *)&(curwin->w_p_wrap);
- case PV_LBR: return (char_u *)&(curwin->w_p_lbr);
- case PV_BRI: return (char_u *)&(curwin->w_p_bri);
- case PV_BRIOPT: return (char_u *)&(curwin->w_p_briopt);
- case PV_SCBIND: return (char_u *)&(curwin->w_p_scb);
- case PV_CRBIND: return (char_u *)&(curwin->w_p_crb);
- case PV_COCU: return (char_u *)&(curwin->w_p_cocu);
- case PV_COLE: return (char_u *)&(curwin->w_p_cole);
-
- case PV_AI: return (char_u *)&(curbuf->b_p_ai);
- case PV_BIN: return (char_u *)&(curbuf->b_p_bin);
- case PV_BOMB: return (char_u *)&(curbuf->b_p_bomb);
- case PV_BH: return (char_u *)&(curbuf->b_p_bh);
- case PV_BT: return (char_u *)&(curbuf->b_p_bt);
- case PV_BL: return (char_u *)&(curbuf->b_p_bl);
- case PV_CHANNEL:return (char_u *)&(curbuf->b_p_channel);
- case PV_CI: return (char_u *)&(curbuf->b_p_ci);
- case PV_CIN: return (char_u *)&(curbuf->b_p_cin);
- case PV_CINK: return (char_u *)&(curbuf->b_p_cink);
- case PV_CINO: return (char_u *)&(curbuf->b_p_cino);
- case PV_CINW: return (char_u *)&(curbuf->b_p_cinw);
- case PV_COM: return (char_u *)&(curbuf->b_p_com);
- case PV_CMS: return (char_u *)&(curbuf->b_p_cms);
- case PV_CPT: return (char_u *)&(curbuf->b_p_cpt);
-# ifdef BACKSLASH_IN_FILENAME
- case PV_CSL: return (char_u *)&(curbuf->b_p_csl);
-# endif
- case PV_CFU: return (char_u *)&(curbuf->b_p_cfu);
- case PV_OFU: return (char_u *)&(curbuf->b_p_ofu);
- case PV_EOL: return (char_u *)&(curbuf->b_p_eol);
- case PV_FIXEOL: return (char_u *)&(curbuf->b_p_fixeol);
- case PV_ET: return (char_u *)&(curbuf->b_p_et);
- case PV_FENC: return (char_u *)&(curbuf->b_p_fenc);
- case PV_FF: return (char_u *)&(curbuf->b_p_ff);
- case PV_FT: return (char_u *)&(curbuf->b_p_ft);
- case PV_FO: return (char_u *)&(curbuf->b_p_fo);
- case PV_FLP: return (char_u *)&(curbuf->b_p_flp);
- case PV_IMI: return (char_u *)&(curbuf->b_p_iminsert);
- case PV_IMS: return (char_u *)&(curbuf->b_p_imsearch);
- case PV_INF: return (char_u *)&(curbuf->b_p_inf);
- case PV_ISK: return (char_u *)&(curbuf->b_p_isk);
- case PV_INEX: return (char_u *)&(curbuf->b_p_inex);
- case PV_INDE: return (char_u *)&(curbuf->b_p_inde);
- case PV_INDK: return (char_u *)&(curbuf->b_p_indk);
- case PV_FEX: return (char_u *)&(curbuf->b_p_fex);
- case PV_LISP: return (char_u *)&(curbuf->b_p_lisp);
- case PV_ML: return (char_u *)&(curbuf->b_p_ml);
- case PV_MPS: return (char_u *)&(curbuf->b_p_mps);
- case PV_MA: return (char_u *)&(curbuf->b_p_ma);
- case PV_MOD: return (char_u *)&(curbuf->b_changed);
- case PV_NF: return (char_u *)&(curbuf->b_p_nf);
- case PV_PI: return (char_u *)&(curbuf->b_p_pi);
- case PV_QE: return (char_u *)&(curbuf->b_p_qe);
- case PV_RO: return (char_u *)&(curbuf->b_p_ro);
- case PV_SCBK: return (char_u *)&(curbuf->b_p_scbk);
- case PV_SI: return (char_u *)&(curbuf->b_p_si);
- case PV_STS: return (char_u *)&(curbuf->b_p_sts);
- case PV_SUA: return (char_u *)&(curbuf->b_p_sua);
- case PV_SWF: return (char_u *)&(curbuf->b_p_swf);
- case PV_SMC: return (char_u *)&(curbuf->b_p_smc);
- case PV_SYN: return (char_u *)&(curbuf->b_p_syn);
- case PV_SPC: return (char_u *)&(curwin->w_s->b_p_spc);
- case PV_SPF: return (char_u *)&(curwin->w_s->b_p_spf);
- case PV_SPL: return (char_u *)&(curwin->w_s->b_p_spl);
- case PV_SPO: return (char_u *)&(curwin->w_s->b_p_spo);
- case PV_SW: return (char_u *)&(curbuf->b_p_sw);
- case PV_TFU: return (char_u *)&(curbuf->b_p_tfu);
- case PV_TS: return (char_u *)&(curbuf->b_p_ts);
- case PV_TW: return (char_u *)&(curbuf->b_p_tw);
- case PV_UDF: return (char_u *)&(curbuf->b_p_udf);
- case PV_WM: return (char_u *)&(curbuf->b_p_wm);
- case PV_VSTS: return (char_u *)&(curbuf->b_p_vsts);
- case PV_VTS: return (char_u *)&(curbuf->b_p_vts);
- case PV_KMAP: return (char_u *)&(curbuf->b_p_keymap);
- case PV_SCL: return (char_u *)&(curwin->w_p_scl);
- case PV_WINHL: return (char_u *)&(curwin->w_p_winhl);
- case PV_WINBL: return (char_u *)&(curwin->w_p_winbl);
- default: IEMSG(_("E356: get_varp ERROR"));
+ case PV_ARAB:
+ return (char_u *)&(curwin->w_p_arab);
+ case PV_LIST:
+ return (char_u *)&(curwin->w_p_list);
+ case PV_SPELL:
+ return (char_u *)&(curwin->w_p_spell);
+ case PV_CUC:
+ return (char_u *)&(curwin->w_p_cuc);
+ case PV_CUL:
+ return (char_u *)&(curwin->w_p_cul);
+ case PV_CULOPT:
+ return (char_u *)&(curwin->w_p_culopt);
+ case PV_CC:
+ return (char_u *)&(curwin->w_p_cc);
+ case PV_DIFF:
+ return (char_u *)&(curwin->w_p_diff);
+ case PV_FDC:
+ return (char_u *)&(curwin->w_p_fdc);
+ case PV_FEN:
+ return (char_u *)&(curwin->w_p_fen);
+ case PV_FDI:
+ return (char_u *)&(curwin->w_p_fdi);
+ case PV_FDL:
+ return (char_u *)&(curwin->w_p_fdl);
+ case PV_FDM:
+ return (char_u *)&(curwin->w_p_fdm);
+ case PV_FML:
+ return (char_u *)&(curwin->w_p_fml);
+ case PV_FDN:
+ return (char_u *)&(curwin->w_p_fdn);
+ case PV_FDE:
+ return (char_u *)&(curwin->w_p_fde);
+ case PV_FDT:
+ return (char_u *)&(curwin->w_p_fdt);
+ case PV_FMR:
+ return (char_u *)&(curwin->w_p_fmr);
+ case PV_NU:
+ return (char_u *)&(curwin->w_p_nu);
+ case PV_RNU:
+ return (char_u *)&(curwin->w_p_rnu);
+ case PV_NUW:
+ return (char_u *)&(curwin->w_p_nuw);
+ case PV_WFH:
+ return (char_u *)&(curwin->w_p_wfh);
+ case PV_WFW:
+ return (char_u *)&(curwin->w_p_wfw);
+ case PV_PVW:
+ return (char_u *)&(curwin->w_p_pvw);
+ case PV_RL:
+ return (char_u *)&(curwin->w_p_rl);
+ case PV_RLC:
+ return (char_u *)&(curwin->w_p_rlc);
+ case PV_SCROLL:
+ return (char_u *)&(curwin->w_p_scr);
+ case PV_WRAP:
+ return (char_u *)&(curwin->w_p_wrap);
+ case PV_LBR:
+ return (char_u *)&(curwin->w_p_lbr);
+ case PV_BRI:
+ return (char_u *)&(curwin->w_p_bri);
+ case PV_BRIOPT:
+ return (char_u *)&(curwin->w_p_briopt);
+ case PV_SCBIND:
+ return (char_u *)&(curwin->w_p_scb);
+ case PV_CRBIND:
+ return (char_u *)&(curwin->w_p_crb);
+ case PV_COCU:
+ return (char_u *)&(curwin->w_p_cocu);
+ case PV_COLE:
+ return (char_u *)&(curwin->w_p_cole);
+
+ case PV_AI:
+ return (char_u *)&(curbuf->b_p_ai);
+ case PV_BIN:
+ return (char_u *)&(curbuf->b_p_bin);
+ case PV_BOMB:
+ return (char_u *)&(curbuf->b_p_bomb);
+ case PV_BH:
+ return (char_u *)&(curbuf->b_p_bh);
+ case PV_BT:
+ return (char_u *)&(curbuf->b_p_bt);
+ case PV_BL:
+ return (char_u *)&(curbuf->b_p_bl);
+ case PV_CHANNEL:
+ return (char_u *)&(curbuf->b_p_channel);
+ case PV_CI:
+ return (char_u *)&(curbuf->b_p_ci);
+ case PV_CIN:
+ return (char_u *)&(curbuf->b_p_cin);
+ case PV_CINK:
+ return (char_u *)&(curbuf->b_p_cink);
+ case PV_CINO:
+ return (char_u *)&(curbuf->b_p_cino);
+ case PV_CINW:
+ return (char_u *)&(curbuf->b_p_cinw);
+ case PV_COM:
+ return (char_u *)&(curbuf->b_p_com);
+ case PV_CMS:
+ return (char_u *)&(curbuf->b_p_cms);
+ case PV_CPT:
+ return (char_u *)&(curbuf->b_p_cpt);
+#ifdef BACKSLASH_IN_FILENAME
+ case PV_CSL:
+ return (char_u *)&(curbuf->b_p_csl);
+#endif
+ case PV_CFU:
+ return (char_u *)&(curbuf->b_p_cfu);
+ case PV_OFU:
+ return (char_u *)&(curbuf->b_p_ofu);
+ case PV_EOL:
+ return (char_u *)&(curbuf->b_p_eol);
+ case PV_FIXEOL:
+ return (char_u *)&(curbuf->b_p_fixeol);
+ case PV_ET:
+ return (char_u *)&(curbuf->b_p_et);
+ case PV_FENC:
+ return (char_u *)&(curbuf->b_p_fenc);
+ case PV_FF:
+ return (char_u *)&(curbuf->b_p_ff);
+ case PV_FT:
+ return (char_u *)&(curbuf->b_p_ft);
+ case PV_FO:
+ return (char_u *)&(curbuf->b_p_fo);
+ case PV_FLP:
+ return (char_u *)&(curbuf->b_p_flp);
+ case PV_IMI:
+ return (char_u *)&(curbuf->b_p_iminsert);
+ case PV_IMS:
+ return (char_u *)&(curbuf->b_p_imsearch);
+ case PV_INF:
+ return (char_u *)&(curbuf->b_p_inf);
+ case PV_ISK:
+ return (char_u *)&(curbuf->b_p_isk);
+ case PV_INEX:
+ return (char_u *)&(curbuf->b_p_inex);
+ case PV_INDE:
+ return (char_u *)&(curbuf->b_p_inde);
+ case PV_INDK:
+ return (char_u *)&(curbuf->b_p_indk);
+ case PV_FEX:
+ return (char_u *)&(curbuf->b_p_fex);
+ case PV_LISP:
+ return (char_u *)&(curbuf->b_p_lisp);
+ case PV_ML:
+ return (char_u *)&(curbuf->b_p_ml);
+ case PV_MPS:
+ return (char_u *)&(curbuf->b_p_mps);
+ case PV_MA:
+ return (char_u *)&(curbuf->b_p_ma);
+ case PV_MOD:
+ return (char_u *)&(curbuf->b_changed);
+ case PV_NF:
+ return (char_u *)&(curbuf->b_p_nf);
+ case PV_PI:
+ return (char_u *)&(curbuf->b_p_pi);
+ case PV_QE:
+ return (char_u *)&(curbuf->b_p_qe);
+ case PV_RO:
+ return (char_u *)&(curbuf->b_p_ro);
+ case PV_SCBK:
+ return (char_u *)&(curbuf->b_p_scbk);
+ case PV_SI:
+ return (char_u *)&(curbuf->b_p_si);
+ case PV_STS:
+ return (char_u *)&(curbuf->b_p_sts);
+ case PV_SUA:
+ return (char_u *)&(curbuf->b_p_sua);
+ case PV_SWF:
+ return (char_u *)&(curbuf->b_p_swf);
+ case PV_SMC:
+ return (char_u *)&(curbuf->b_p_smc);
+ case PV_SYN:
+ return (char_u *)&(curbuf->b_p_syn);
+ case PV_SPC:
+ return (char_u *)&(curwin->w_s->b_p_spc);
+ case PV_SPF:
+ return (char_u *)&(curwin->w_s->b_p_spf);
+ case PV_SPL:
+ return (char_u *)&(curwin->w_s->b_p_spl);
+ case PV_SPO:
+ return (char_u *)&(curwin->w_s->b_p_spo);
+ case PV_SW:
+ return (char_u *)&(curbuf->b_p_sw);
+ case PV_TFU:
+ return (char_u *)&(curbuf->b_p_tfu);
+ case PV_TS:
+ return (char_u *)&(curbuf->b_p_ts);
+ case PV_TW:
+ return (char_u *)&(curbuf->b_p_tw);
+ case PV_UDF:
+ return (char_u *)&(curbuf->b_p_udf);
+ case PV_WM:
+ return (char_u *)&(curbuf->b_p_wm);
+ case PV_VSTS:
+ return (char_u *)&(curbuf->b_p_vsts);
+ case PV_VTS:
+ return (char_u *)&(curbuf->b_p_vts);
+ case PV_KMAP:
+ return (char_u *)&(curbuf->b_p_keymap);
+ case PV_SCL:
+ return (char_u *)&(curwin->w_p_scl);
+ case PV_WINHL:
+ return (char_u *)&(curwin->w_p_winhl);
+ case PV_WINBL:
+ return (char_u *)&(curwin->w_p_winbl);
+ default:
+ IEMSG(_("E356: get_varp ERROR"));
}
// always return a valid pointer to avoid a crash!
return (char_u *)&(curbuf->b_p_wm);
@@ -5817,6 +5972,7 @@ void copy_winopt(winopt_T *from, winopt_T *to)
to->wo_nuw = from->wo_nuw;
to->wo_rl = from->wo_rl;
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_wrap = from->wo_wrap;
to->wo_wrap_save = from->wo_wrap_save;
@@ -5830,6 +5986,7 @@ void copy_winopt(winopt_T *from, winopt_T *to)
to->wo_spell = from->wo_spell;
to->wo_cuc = from->wo_cuc;
to->wo_cul = from->wo_cul;
+ to->wo_culopt = vim_strsave(from->wo_culopt);
to->wo_cc = vim_strsave(from->wo_cc);
to->wo_diff = from->wo_diff;
to->wo_diff_saved = from->wo_diff_saved;
@@ -5879,7 +6036,9 @@ static void check_winopt(winopt_T *wop)
check_string_option(&wop->wo_fmr);
check_string_option(&wop->wo_scl);
check_string_option(&wop->wo_rlc);
+ check_string_option(&wop->wo_sbr);
check_string_option(&wop->wo_stl);
+ check_string_option(&wop->wo_culopt);
check_string_option(&wop->wo_cc);
check_string_option(&wop->wo_cocu);
check_string_option(&wop->wo_briopt);
@@ -5901,7 +6060,9 @@ void clear_winopt(winopt_T *wop)
clear_string_option(&wop->wo_fmr);
clear_string_option(&wop->wo_scl);
clear_string_option(&wop->wo_rlc);
+ clear_string_option(&wop->wo_sbr);
clear_string_option(&wop->wo_stl);
+ clear_string_option(&wop->wo_culopt);
clear_string_option(&wop->wo_cc);
clear_string_option(&wop->wo_cocu);
clear_string_option(&wop->wo_briopt);
@@ -5914,6 +6075,7 @@ void didset_window_options(win_T *wp)
{
check_colorcolumn(wp);
briopt_check(wp);
+ fill_culopt_flags(NULL, wp);
set_chars_option(wp, &wp->w_p_fcs, true);
set_chars_option(wp, &wp->w_p_lcs, true);
parse_winhl_opt(wp); // sets w_hl_needs_update also for w_p_winbl
@@ -5932,7 +6094,7 @@ void didset_window_options(win_T *wp)
void buf_copy_options(buf_T *buf, int flags)
{
int should_copy = true;
- char_u *save_p_isk = NULL; // init for GCC
+ char_u *save_p_isk = NULL; // init for GCC
int dont_do_help;
int did_isk = false;
@@ -5977,22 +6139,18 @@ void buf_copy_options(buf_T *buf, int flags)
buf->b_p_ro = false; // don't copy readonly
buf->b_p_fenc = vim_strsave(p_fenc);
switch (*p_ffs) {
- case 'm': {
- buf->b_p_ff = vim_strsave((char_u *)FF_MAC);
- break;
- }
- case 'd': {
- buf->b_p_ff = vim_strsave((char_u *)FF_DOS);
- break;
- }
- case 'u': {
- buf->b_p_ff = vim_strsave((char_u *)FF_UNIX);
- break;
- }
- default: {
- buf->b_p_ff = vim_strsave(p_ff);
- break;
- }
+ case 'm':
+ buf->b_p_ff = vim_strsave((char_u *)FF_MAC);
+ break;
+ case 'd':
+ buf->b_p_ff = vim_strsave((char_u *)FF_DOS);
+ break;
+ case 'u':
+ buf->b_p_ff = vim_strsave((char_u *)FF_UNIX);
+ break;
+ default:
+ buf->b_p_ff = vim_strsave(p_ff);
+ break;
}
buf->b_p_bh = empty_option;
buf->b_p_bt = empty_option;
@@ -6021,9 +6179,9 @@ void buf_copy_options(buf_T *buf, int flags)
buf->b_p_inf = p_inf;
buf->b_p_swf = cmdmod.noswapfile ? false : p_swf;
buf->b_p_cpt = vim_strsave(p_cpt);
-# ifdef BACKSLASH_IN_FILENAME
+#ifdef BACKSLASH_IN_FILENAME
buf->b_p_csl = vim_strsave(p_csl);
-# endif
+#endif
buf->b_p_cfu = vim_strsave(p_cfu);
buf->b_p_ofu = vim_strsave(p_ofu);
buf->b_p_tfu = vim_strsave(p_tfu);
@@ -6156,7 +6314,7 @@ void reset_modifiable(void)
p_ma = false;
opt_idx = findoption("ma");
if (opt_idx >= 0) {
- options[opt_idx].def_val[VI_DEFAULT] = false;
+ options[opt_idx].def_val = false;
}
}
@@ -6173,21 +6331,17 @@ void set_imsearch_global(void)
}
static int expand_option_idx = -1;
-static char_u expand_option_name[5] = {'t', '_', NUL, NUL, NUL};
+static char_u expand_option_name[5] = { 't', '_', NUL, NUL, NUL };
static int expand_option_flags = 0;
-void
-set_context_in_set_cmd(
- expand_T *xp,
- char_u *arg,
- int opt_flags // OPT_GLOBAL and/or OPT_LOCAL
-)
+/// @param opt_flags OPT_GLOBAL and/or OPT_LOCAL
+void set_context_in_set_cmd(expand_T *xp, char_u *arg, int opt_flags)
{
char_u nextchar;
uint32_t flags = 0; // init for GCC
int opt_idx = 0; // init for GCC
- char_u *p;
- char_u *s;
+ char_u *p;
+ char_u *s;
int is_term_option = false;
int key;
@@ -6311,15 +6465,14 @@ set_context_in_set_cmd(
|| p == (char_u *)&p_pp
|| p == (char_u *)&p_rtp
|| p == (char_u *)&p_cdpath
- || p == (char_u *)&p_vdir
- ) {
+ || p == (char_u *)&p_vdir) {
xp->xp_context = EXPAND_DIRECTORIES;
if (p == (char_u *)&p_path
- || p == (char_u *)&p_cdpath
- )
+ || p == (char_u *)&p_cdpath) {
xp->xp_backslash = XP_BS_THREE;
- else
+ } else {
xp->xp_backslash = XP_BS_ONE;
+ }
} else if (p == (char_u *)&p_ft) {
xp->xp_context = EXPAND_FILETYPE;
} else {
@@ -6365,7 +6518,7 @@ int ExpandSettings(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***
int num_normal = 0; // Nr of matching non-term-code settings
int match;
int count = 0;
- char_u *str;
+ char_u *str;
int loop;
static char *(names[]) = { "all" };
int ic = regmatch->rm_ic; // remember the ignore-case flag
@@ -6409,8 +6562,9 @@ int ExpandSettings(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***
if (match) {
if (loop == 0) {
num_normal++;
- } else
+ } else {
(*file)[count++] = vim_strsave(str);
+ }
}
}
@@ -6472,13 +6626,11 @@ void ExpandOldSetting(int *num_file, char_u ***file)
/// Get the value for the numeric or string option///opp in a nice format into
/// NameBuff[]. Must not be called with a hidden option!
-static void
-option_value2string(
- vimoption_T *opp,
- int opt_flags // OPT_GLOBAL and/or OPT_LOCAL
-)
+///
+/// @param opt_flags OPT_GLOBAL and/or OPT_LOCAL
+static void option_value2string(vimoption_T *opp, int opt_flags)
{
- char_u *varp;
+ char_u *varp;
varp = get_varp_scope(opp, opt_flags);
@@ -6501,7 +6653,7 @@ option_value2string(
NameBuff[0] = NUL;
} else if (opp->flags & P_EXPAND) {
home_replace(NULL, varp, NameBuff, MAXPATHL, false);
- // Translate 'pastetoggle' into special key names.
+ // Translate 'pastetoggle' into special key names.
} else if ((char_u **)opp->var == &p_pt) {
str2specialbuf((const char *)p_pt, (char *)NameBuff, MAXPATHL);
} else {
@@ -6614,8 +6766,8 @@ static void langmap_init(void)
/// changed at any time!
static void langmap_set(void)
{
- char_u *p;
- char_u *p2;
+ char_u *p;
+ char_u *p2;
int from, to;
ga_clear(&langmap_mapga); // clear the previous map first
@@ -6661,7 +6813,7 @@ static void langmap_set(void)
}
if (to == NUL) {
EMSG2(_("E357: 'langmap': Matching character missing for %s"),
- transchar(from));
+ transchar(from));
return;
}
@@ -6680,9 +6832,8 @@ static void langmap_set(void)
p = p2;
if (p[0] != NUL) {
if (p[0] != ',') {
- EMSG2(_(
- "E358: 'langmap': Extra characters after semicolon: %s"),
- p);
+ EMSG2(_("E358: 'langmap': Extra characters after semicolon: %s"),
+ p);
return;
}
p++;
@@ -6855,17 +7006,17 @@ static void paste_option_changed(void)
/// vimrc_found() - Called when a vimrc or "VIMINIT" has been found.
///
-/// Set the values for options that didn't get set yet to the Vim defaults.
+/// Set the values for options that didn't get set yet to the defaults.
/// When "fname" is not NULL, use it to set $"envname" when it wasn't set yet.
-void vimrc_found(char_u *fname, char_u *envname)
+void vimrc_found(char *fname, char *envname)
{
if (fname != NULL && envname != NULL) {
- char *p = vim_getenv((char *)envname);
+ char *p = vim_getenv(envname);
if (p == NULL) {
// Set $MYVIMRC to the first vimrc file found.
- p = FullName_save((char *)fname, false);
+ p = FullName_save(fname, false);
if (p != NULL) {
- os_setenv((char *)envname, p, 1);
+ os_setenv(envname, p, 1);
xfree(p);
}
} else {
@@ -6907,7 +7058,7 @@ void reset_option_was_set(const char *name)
/// fill_breakat_flags() -- called when 'breakat' changes value.
static void fill_breakat_flags(void)
{
- char_u *p;
+ char_u *p;
int i;
for (i = 0; i < 256; i++) {
@@ -6921,15 +7072,55 @@ static void fill_breakat_flags(void)
}
}
+/// fill_culopt_flags() -- called when 'culopt' changes value
+static int fill_culopt_flags(char_u *val, win_T *wp)
+{
+ char_u *p;
+ char_u culopt_flags_new = 0;
+
+ if (val == NULL) {
+ p = wp->w_p_culopt;
+ } else {
+ p = val;
+ }
+ while (*p != NUL) {
+ if (STRNCMP(p, "line", 4) == 0) {
+ p += 4;
+ culopt_flags_new |= CULOPT_LINE;
+ } else if (STRNCMP(p, "both", 4) == 0) {
+ p += 4;
+ culopt_flags_new |= CULOPT_LINE | CULOPT_NBR;
+ } else if (STRNCMP(p, "number", 6) == 0) {
+ p += 6;
+ culopt_flags_new |= CULOPT_NBR;
+ } else if (STRNCMP(p, "screenline", 10) == 0) {
+ p += 10;
+ culopt_flags_new |= CULOPT_SCRLINE;
+ }
+
+ if (*p != ',' && *p != NUL) {
+ return FAIL;
+ }
+ if (*p == ',') {
+ p++;
+ }
+ }
+
+ // Can't have both "line" and "screenline".
+ if ((culopt_flags_new & CULOPT_LINE) && (culopt_flags_new & CULOPT_SCRLINE)) {
+ return FAIL;
+ }
+ wp->w_p_culopt_flags = culopt_flags_new;
+
+ return OK;
+}
+
/// Check an option that can be a range of string values.
///
-/// Return OK for correct value, FAIL otherwise.
-/// Empty is always OK.
-static int check_opt_strings(
- char_u *val,
- char **values,
- int list // when true: accept a list of values
-)
+/// @param list when true: accept a list of values
+///
+/// @return OK for correct value, FAIL otherwise. Empty is always OK.
+static int check_opt_strings(char_u *val, char **values, int list)
{
return opt_strings_flags(val, values, NULL, list);
}
@@ -6937,14 +7128,12 @@ static int check_opt_strings(
/// Handle an option that can be a range of string values.
/// Set a flag in "*flagp" for each string present.
///
-/// Return OK for correct value, FAIL otherwise.
-/// Empty is always OK.
-static int opt_strings_flags(
- char_u *val, // new value
- char **values, // array of valid string values
- unsigned *flagp,
- bool list // when true: accept a list of values
-)
+/// @param val new value
+/// @param values array of valid string values
+/// @param list when true: accept a list of values
+///
+/// @return OK for correct value, FAIL otherwise. Empty is always OK.
+static int opt_strings_flags(char_u *val, char **values, unsigned *flagp, bool list)
{
unsigned int new_flags = 0;
@@ -6975,7 +7164,7 @@ static int opt_strings_flags(
static int check_opt_wim(void)
{
char_u new_wim_flags[4];
- char_u *p;
+ char_u *p;
int i;
int idx = 0;
@@ -7032,10 +7221,14 @@ bool can_bs(int what)
return false;
}
switch (*p_bs) {
- case '3': return true;
- case '2': return what != BS_NOSTOP;
- case '1': return what != BS_START;
- case '0': return false;
+ case '3':
+ return true;
+ case '2':
+ return what != BS_NOSTOP;
+ case '1':
+ return what != BS_START;
+ case '0':
+ return false;
}
return vim_strchr(p_bs, what) != NULL;
}
@@ -7232,11 +7425,7 @@ colnr_T tabstop_start(colnr_T col, long ts, long *vts)
// Find the number of tabs and spaces necessary to get from one column
// to another.
-void tabstop_fromto(colnr_T start_col,
- colnr_T end_col,
- long ts_arg,
- long *vts,
- int *ntabs,
+void tabstop_fromto(colnr_T start_col, colnr_T end_col, long ts_arg, long *vts, int *ntabs,
int *nspcs)
{
int spaces = end_col - start_col;
@@ -7406,25 +7595,24 @@ static bool briopt_check(win_T *wp)
int bri_shift = 0;
int bri_min = 20;
bool bri_sbr = false;
+ int bri_list = 0;
char_u *p = wp->w_p_briopt;
while (*p != NUL)
{
if (STRNCMP(p, "shift:", 6) == 0
- && ((p[6] == '-' && ascii_isdigit(p[7])) || ascii_isdigit(p[6])))
- {
+ && ((p[6] == '-' && ascii_isdigit(p[7])) || ascii_isdigit(p[6]))) {
p += 6;
bri_shift = getdigits_int(&p, true, 0);
- }
- else if (STRNCMP(p, "min:", 4) == 0 && ascii_isdigit(p[4]))
- {
+ } else if (STRNCMP(p, "min:", 4) == 0 && ascii_isdigit(p[4])) {
p += 4;
bri_min = getdigits_int(&p, true, 0);
- }
- else if (STRNCMP(p, "sbr", 3) == 0)
- {
+ } else if (STRNCMP(p, "sbr", 3) == 0) {
p += 3;
bri_sbr = true;
+ } else if (STRNCMP(p, "list:", 5) == 0) {
+ p += 5;
+ bri_list = (int)getdigits(&p, false, 0);
}
if (*p != ',' && *p != NUL) {
return false;
@@ -7437,6 +7625,7 @@ static bool briopt_check(win_T *wp)
wp->w_briopt_shift = bri_shift;
wp->w_briopt_min = bri_min;
wp->w_briopt_sbr = bri_sbr;
+ wp->w_briopt_list = bri_list;
return true;
}
@@ -7449,6 +7638,22 @@ unsigned int get_bkc_value(buf_T *buf)
return buf->b_bkc_flags ? buf->b_bkc_flags : bkc_flags;
}
+/// Get the local or global value of 'showbreak'.
+///
+/// @param win If not NULL, the window to get the local option from; global
+/// otherwise.
+char_u *get_showbreak_value(win_T *const win)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ if (win->w_p_sbr == NULL || *win->w_p_sbr == NUL) {
+ return p_sbr;
+ }
+ if (STRCMP(win->w_p_sbr, "NONE") == 0) {
+ return empty_option;
+ }
+ return win->w_p_sbr;
+}
+
/// Return the current end-of-line type: EOL_DOS, EOL_UNIX or EOL_MAC.
int get_fileformat(const buf_T *buf)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
@@ -7495,8 +7700,10 @@ int get_fileformat_force(const buf_T *buf, const exarg_T *eap)
int default_fileformat(void)
{
switch (*p_ffs) {
- case 'm': return EOL_MAC;
- case 'd': return EOL_DOS;
+ case 'm':
+ return EOL_MAC;
+ case 'd':
+ return EOL_DOS;
}
return EOL_UNIX;
}
@@ -7512,15 +7719,15 @@ void set_fileformat(int eol_style, int opt_flags)
char *p = NULL;
switch (eol_style) {
- case EOL_UNIX:
- p = FF_UNIX;
- break;
- case EOL_MAC:
- p = FF_MAC;
- break;
- case EOL_DOS:
- p = FF_DOS;
- break;
+ case EOL_UNIX:
+ p = FF_UNIX;
+ break;
+ case EOL_MAC:
+ p = FF_MAC;
+ break;
+ case EOL_DOS:
+ p = FF_DOS;
+ break;
}
// p is NULL if "eol_style" is EOL_UNKNOWN.
@@ -7558,11 +7765,10 @@ char_u *skip_to_option_part(const char_u *p)
/// @param[in] sep_chars chars that separate the option parts
///
/// @return length of `*option`
-size_t copy_option_part(char_u **option, char_u *buf, size_t maxlen,
- char *sep_chars)
+size_t copy_option_part(char_u **option, char_u *buf, size_t maxlen, char *sep_chars)
{
size_t len = 0;
- char_u *p = *option;
+ char_u *p = *option;
// skip '.' at start of option part, for 'suffixes'
if (*p == '.') {
@@ -7595,6 +7801,12 @@ int csh_like_shell(void)
return strstr((char *)path_tail(p_sh), "csh") != NULL;
}
+/// Return true when 'shell' has "fish" in the tail.
+bool fish_like_shell(void)
+{
+ return strstr((char *)path_tail(p_sh), "fish") != NULL;
+}
+
/// Return the number of requested sign columns, based on current
/// buffer signs and on user configuration.
int win_signcol_count(win_T *wp)
@@ -7719,53 +7931,52 @@ Dictionary get_all_vimoptions(void)
static Dictionary vimoption2dict(vimoption_T *opt)
{
- Dictionary dict = ARRAY_DICT_INIT;
+ Dictionary dict = ARRAY_DICT_INIT;
- PUT(dict, "name", CSTR_TO_OBJ(opt->fullname));
- PUT(dict, "shortname", CSTR_TO_OBJ(opt->shortname));
+ PUT(dict, "name", CSTR_TO_OBJ(opt->fullname));
+ PUT(dict, "shortname", CSTR_TO_OBJ(opt->shortname));
- const char *scope;
- if (opt->indir & PV_BUF) {
- scope = "buf";
- } else if (opt->indir & PV_WIN) {
- scope = "win";
- } else {
- scope = "global";
- }
-
- PUT(dict, "scope", CSTR_TO_OBJ(scope));
-
- // welcome to the jungle
- PUT(dict, "global_local", BOOL(opt->indir & PV_BOTH));
- PUT(dict, "commalist", BOOL(opt->flags & P_COMMA));
- PUT(dict, "flaglist", BOOL(opt->flags & P_FLAGLIST));
-
- PUT(dict, "was_set", BOOL(opt->flags & P_WAS_SET));
-
- PUT(dict, "last_set_sid", INTEGER_OBJ(opt->last_set.script_ctx.sc_sid));
- PUT(dict, "last_set_linenr", INTEGER_OBJ(opt->last_set.script_ctx.sc_lnum));
- PUT(dict, "last_set_chan", INTEGER_OBJ((int64_t)opt->last_set.channel_id));
-
- const char *type;
- Object def;
- // TODO(bfredl): do you even nocp?
- char_u *def_val = opt->def_val[(opt->flags & P_VI_DEF)
- ? VI_DEFAULT : VIM_DEFAULT];
- if (opt->flags & P_STRING) {
- type = "string";
- def = CSTR_TO_OBJ(def_val ? (char *)def_val : "");
- } else if (opt->flags & P_NUM) {
- type = "number";
- def = INTEGER_OBJ((Integer)(intptr_t)def_val);
- } else if (opt->flags & P_BOOL) {
- type = "boolean";
- def = BOOL((intptr_t)def_val);
- } else {
- type = ""; def = NIL;
- }
- PUT(dict, "type", CSTR_TO_OBJ(type));
- PUT(dict, "default", def);
- PUT(dict, "allows_duplicates", BOOL(!(opt->flags & P_NODUP)));
+ const char *scope;
+ if (opt->indir & PV_BUF) {
+ scope = "buf";
+ } else if (opt->indir & PV_WIN) {
+ scope = "win";
+ } else {
+ scope = "global";
+ }
+
+ PUT(dict, "scope", CSTR_TO_OBJ(scope));
+
+ // welcome to the jungle
+ PUT(dict, "global_local", BOOL(opt->indir & PV_BOTH));
+ PUT(dict, "commalist", BOOL(opt->flags & P_COMMA));
+ PUT(dict, "flaglist", BOOL(opt->flags & P_FLAGLIST));
+
+ PUT(dict, "was_set", BOOL(opt->flags & P_WAS_SET));
+
+ PUT(dict, "last_set_sid", INTEGER_OBJ(opt->last_set.script_ctx.sc_sid));
+ PUT(dict, "last_set_linenr", INTEGER_OBJ(opt->last_set.script_ctx.sc_lnum));
+ PUT(dict, "last_set_chan", INTEGER_OBJ((int64_t)opt->last_set.channel_id));
+
+ const char *type;
+ Object def;
+ // TODO(bfredl): do you even nocp?
+ char_u *def_val = opt->def_val;
+ if (opt->flags & P_STRING) {
+ type = "string";
+ def = CSTR_TO_OBJ(def_val ? (char *)def_val : "");
+ } else if (opt->flags & P_NUM) {
+ type = "number";
+ def = INTEGER_OBJ((Integer)(intptr_t)def_val);
+ } else if (opt->flags & P_BOOL) {
+ type = "boolean";
+ def = BOOL((intptr_t)def_val);
+ } else {
+ type = ""; def = NIL;
+ }
+ PUT(dict, "type", CSTR_TO_OBJ(type));
+ PUT(dict, "default", def);
+ PUT(dict, "allows_duplicates", BOOL(!(opt->flags & P_NODUP)));
- return dict;
+ return dict;
}
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index beb62a6a0b..e588d3f373 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -276,10 +276,10 @@ enum {
})
// flags used for parsed 'wildmode'
-#define WIM_FULL 1
-#define WIM_LONGEST 2
-#define WIM_LIST 4
-#define WIM_BUFLASTUSED 8
+#define WIM_FULL 0x01
+#define WIM_LONGEST 0x02
+#define WIM_LIST 0x04
+#define WIM_BUFLASTUSED 0x08
// arguments for can_bs()
// each defined char should be unique over all values
@@ -291,6 +291,11 @@ enum {
#define BS_START 's' // "Start"
#define BS_NOSTOP 'p' // "nostoP
+// flags for the 'culopt' option
+#define CULOPT_LINE 0x01 // Highlight complete line
+#define CULOPT_SCRLINE 0x02 // Highlight screen line
+#define CULOPT_NBR 0x04 // Highlight Number column
+
#define LISPWORD_VALUE \
"defun,define,defmacro,set!,lambda,if,case,let,flet,let*,letrec,do,do*,define-syntax,let-syntax,letrec-syntax,destructuring-bind,defpackage,defparameter,defstruct,deftype,defvar,do-all-symbols,do-external-symbols,do-symbols,dolist,dotimes,ecase,etypecase,eval-when,labels,macrolet,multiple-value-bind,multiple-value-call,multiple-value-prog1,multiple-value-setq,prog1,progv,typecase,unless,unwind-protect,when,with-input-from-string,with-open-file,with-open-stream,with-output-to-string,with-package-iterator,define-condition,handler-bind,handler-case,restart-bind,restart-case,with-simple-restart,store-value,use-value,muffle-warning,abort,continue,with-slots,with-slots*,with-accessors,with-accessors*,defclass,defmethod,print-unreadable-object"
@@ -459,7 +464,6 @@ EXTERN char_u *p_pmcs; // 'printmbcharset'
EXTERN char_u *p_pfn; // 'printfont'
EXTERN char_u *p_popt; // 'printoptions'
EXTERN char_u *p_header; // 'printheader'
-EXTERN int p_prompt; // 'prompt'
EXTERN char_u *p_guicursor; // 'guicursor'
EXTERN char_u *p_guifont; // 'guifont'
EXTERN char_u *p_guifontwide; // 'guifontwide'
@@ -740,11 +744,11 @@ EXTERN long p_wd; // 'writedelay'
EXTERN int p_force_on; ///< options that cannot be turned off.
EXTERN int p_force_off; ///< options that cannot be turned on.
-/*
- * "indir" values for buffer-local opions.
- * These need to be defined globally, so that the BV_COUNT can be used with
- * b_p_scriptID[].
- */
+//
+// "indir" values for buffer-local options.
+// These need to be defined globally, so that the BV_COUNT can be used with
+// b_p_scriptID[].
+//
enum {
BV_AI = 0
, BV_AR
@@ -871,7 +875,9 @@ enum {
, WV_SPELL
, WV_CUC
, WV_CUL
+ , WV_CULOPT
, WV_CC
+ , WV_SBR
, WV_STL
, WV_WFH
, WV_WFW
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 0b09686675..8b9cdefd57 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -6,11 +6,11 @@
-- type='number', list=nil, scope={'global'},
-- deny_duplicates=nil,
-- enable_if=nil,
--- defaults={condition=nil, if_true={vi=224, vim=0}, if_false=nil},
+-- defaults={condition=nil, if_true=224, if_false=nil},
-- secure=nil, gettext=nil, noglob=nil, normal_fname_chars=nil,
-- pri_mkrc=nil, deny_in_modelines=nil, normal_dname_chars=nil,
-- modelineexpr=nil,
--- expand=nil, nodefault=nil, no_mkrc=nil, vi_def=true, vim=true,
+-- expand=nil, nodefault=nil, no_mkrc=nil,
-- alloced=nil,
-- save_pv_indir=nil,
-- redraw={'curswant'},
@@ -21,7 +21,6 @@
-- scopes: global, buffer, window
-- redraw options: statuslines, current_window, curent_window_only,
-- current_buffer, all_windows, everything, curswant
--- default: {vi=…[, vim=…]}
-- defaults: {condition=#if condition, if_true=default, if_false=default}
-- #if condition:
-- string: #ifdef string
@@ -55,125 +54,109 @@ return {
full_name='aleph', abbreviation='al',
short_desc=N_("ASCII code of the letter Aleph (Hebrew)"),
type='number', scope={'global'},
- vi_def=true,
redraw={'curswant'},
varname='p_aleph',
- defaults={if_true={vi=224}}
+ defaults={if_true=224}
},
{
full_name='arabic', abbreviation='arab',
short_desc=N_("Arabic as a default second language"),
type='bool', scope={'window'},
- vi_def=true,
- vim=true,
redraw={'curswant'},
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='arabicshape', abbreviation='arshape',
short_desc=N_("do shaping for Arabic characters"),
type='bool', scope={'global'},
- vi_def=true,
- vim=true,
redraw={'all_windows', 'ui_option'},
varname='p_arshape',
- defaults={if_true={vi=true}}
+ defaults={if_true=true}
},
{
full_name='allowrevins', abbreviation='ari',
short_desc=N_("allow CTRL-_ in Insert and Command-line mode"),
type='bool', scope={'global'},
- vi_def=true,
- vim=true,
varname='p_ari',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='ambiwidth', abbreviation='ambw',
short_desc=N_("what to do with Unicode chars of ambiguous width"),
type='string', scope={'global'},
- vi_def=true,
redraw={'all_windows', 'ui_option'},
varname='p_ambw',
- defaults={if_true={vi="single"}}
+ defaults={if_true="single"}
},
{
full_name='autochdir', abbreviation='acd',
short_desc=N_("change directory to the file in the current window"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_acd',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='autoindent', abbreviation='ai',
short_desc=N_("take indent for new line from previous line"),
type='bool', scope={'buffer'},
varname='p_ai',
- defaults={if_true={vi=false, vim=true}}
+ defaults={if_true=true}
},
{
full_name='autoread', abbreviation='ar',
short_desc=N_("autom. read file when changed outside of Vim"),
type='bool', scope={'global', 'buffer'},
varname='p_ar',
- defaults={if_true={vi=false, vim=true}}
+ defaults={if_true=true}
},
{
full_name='autowrite', abbreviation='aw',
short_desc=N_("automatically write file if changed"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_aw',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='autowriteall', abbreviation='awa',
short_desc=N_("as 'autowrite', but works with more commands"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_awa',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='background', abbreviation='bg',
short_desc=N_("\"dark\" or \"light\", used for highlight colors"),
type='string', scope={'global'},
- vim=true,
redraw={'all_windows'},
varname='p_bg',
- defaults={if_true={vi="light",vim="dark"}}
+ defaults={if_true="dark"}
},
{
full_name='backspace', abbreviation='bs',
short_desc=N_("how backspace works at start of line"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vim=true,
varname='p_bs',
- defaults={if_true={vi="", vim="indent,eol,start"}}
+ defaults={if_true="indent,eol,start"}
},
{
full_name='backup', abbreviation='bk',
short_desc=N_("keep backup file after overwriting a file"),
type='bool', scope={'global'},
- vi_def=true,
- vim=true,
varname='p_bk',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='backupcopy', abbreviation='bkc',
short_desc=N_("make backup as a copy, don't rename the file"),
type='string', list='onecomma', scope={'global', 'buffer'},
deny_duplicates=true,
- vim=true,
varname='p_bkc',
defaults={
condition='UNIX',
- if_true={vi="yes", vim="auto"},
- if_false={vi="auto", vim="auto"}
+ if_true="auto",
+ if_false="auto"
},
},
{
@@ -182,90 +165,79 @@ return {
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
secure=true,
- vi_def=true,
expand='nodefault',
varname='p_bdir',
- defaults={if_true={vi=''}}
+ defaults={if_true=''}
},
{
full_name='backupext', abbreviation='bex',
short_desc=N_("extension used for the backup file"),
type='string', scope={'global'},
normal_fname_chars=true,
- vi_def=true,
varname='p_bex',
- defaults={if_true={vi="~"}}
+ defaults={if_true="~"}
},
{
full_name='backupskip', abbreviation='bsk',
short_desc=N_("no backup for files that match these patterns"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
varname='p_bsk',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='belloff', abbreviation='bo',
short_desc=N_("do not ring the bell for these reasons"),
type='string', list='comma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
varname='p_bo',
- defaults={if_true={vi="all"}}
+ defaults={if_true="all"}
},
{
full_name='binary', abbreviation='bin',
short_desc=N_("read/write/edit file in binary mode"),
type='bool', scope={'buffer'},
- vi_def=true,
redraw={'statuslines'},
varname='p_bin',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='bomb',
short_desc=N_("a Byte Order Mark to the file"),
type='bool', scope={'buffer'},
no_mkrc=true,
- vi_def=true,
redraw={'statuslines'},
varname='p_bomb',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='breakat', abbreviation='brk',
short_desc=N_("characters that may cause a line break"),
type='string', list='flags', scope={'global'},
- vi_def=true,
redraw={'all_windows'},
varname='p_breakat',
- defaults={if_true={vi=" \t!@*-+;:,./?"}}
+ defaults={if_true=" \t!@*-+;:,./?"}
},
{
full_name='breakindent', abbreviation='bri',
short_desc=N_("wrapped line repeats indent"),
type='bool', scope={'window'},
- vi_def=true,
- vim=true,
redraw={'current_window'},
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='breakindentopt', abbreviation='briopt',
short_desc=N_("settings for 'breakindent'"),
type='string', list='onecomma', scope={'window'},
deny_duplicates=true,
- vi_def=true,
alloced=true,
redraw={'current_buffer'},
- defaults={if_true={vi=""}},
+ defaults={if_true=""},
},
{
full_name='browsedir', abbreviation='bsdir',
short_desc=N_("which directory to start browsing in"),
type='string', scope={'global'},
- vi_def=true,
enable_if=false,
},
{
@@ -273,56 +245,51 @@ return {
short_desc=N_("what to do when buffer is no longer in window"),
type='string', scope={'buffer'},
noglob=true,
- vi_def=true,
alloced=true,
varname='p_bh',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='buflisted', abbreviation='bl',
short_desc=N_("whether the buffer shows up in the buffer list"),
type='bool', scope={'buffer'},
noglob=true,
- vi_def=true,
varname='p_bl',
- defaults={if_true={vi=1}}
+ defaults={if_true=1}
},
{
full_name='buftype', abbreviation='bt',
short_desc=N_("special type of buffer"),
type='string', scope={'buffer'},
noglob=true,
- vi_def=true,
alloced=true,
varname='p_bt',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='casemap', abbreviation='cmp',
short_desc=N_("specifies how case of letters is changed"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
varname='p_cmp',
- defaults={if_true={vi="internal,keepascii"}}
+ defaults={if_true="internal,keepascii"}
},
{
full_name='cdpath', abbreviation='cd',
short_desc=N_("list of directories searched with \":cd\""),
type='string', list='comma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
expand=true,
secure=true,
varname='p_cdpath',
- defaults={if_true={vi=",,"}}
+ defaults={if_true=",,"}
},
{
full_name='cedit',
short_desc=N_("used to open the command-line window"),
type='string', scope={'global'},
varname='p_cedit',
- defaults={if_true={vi="", vim=macros('CTRL_F_STR')}}
+ defaults={if_true=macros('CTRL_F_STR')}
},
{
full_name='channel',
@@ -331,121 +298,108 @@ return {
no_mkrc=true,
nodefault=true,
varname='p_channel',
- defaults={if_true={vi=0}}
+ defaults={if_true=0}
},
{
full_name='charconvert', abbreviation='ccv',
short_desc=N_("expression for character encoding conversion"),
type='string', scope={'global'},
secure=true,
- vi_def=true,
varname='p_ccv',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='cindent', abbreviation='cin',
short_desc=N_("do C program indenting"),
type='bool', scope={'buffer'},
- vi_def=true,
- vim=true,
varname='p_cin',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='cinkeys', abbreviation='cink',
short_desc=N_("keys that trigger indent when 'cindent' is set"),
type='string', list='onecomma', scope={'buffer'},
deny_duplicates=true,
- vi_def=true,
alloced=true,
varname='p_cink',
- defaults={if_true={vi=indentkeys_default}}
+ defaults={if_true=indentkeys_default}
},
{
full_name='cinoptions', abbreviation='cino',
short_desc=N_("how to do indenting when 'cindent' is set"),
type='string', list='onecomma', scope={'buffer'},
deny_duplicates=true,
- vi_def=true,
alloced=true,
varname='p_cino',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='cinwords', abbreviation='cinw',
short_desc=N_("words where 'si' and 'cin' add an indent"),
type='string', list='onecomma', scope={'buffer'},
deny_duplicates=true,
- vi_def=true,
alloced=true,
varname='p_cinw',
- defaults={if_true={vi="if,else,while,do,for,switch"}}
+ defaults={if_true="if,else,while,do,for,switch"}
},
{
full_name='clipboard', abbreviation='cb',
short_desc=N_("use the clipboard as the unnamed register"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
varname='p_cb',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='cmdheight', abbreviation='ch',
short_desc=N_("number of lines to use for the command-line"),
type='number', scope={'global'},
- vi_def=true,
redraw={'all_windows'},
varname='p_ch',
- defaults={if_true={vi=1}}
+ defaults={if_true=1}
},
{
full_name='cmdwinheight', abbreviation='cwh',
short_desc=N_("height of the command-line window"),
type='number', scope={'global'},
- vi_def=true,
varname='p_cwh',
- defaults={if_true={vi=7}}
+ defaults={if_true=7}
},
{
full_name='colorcolumn', abbreviation='cc',
short_desc=N_("columns to highlight"),
type='string', list='onecomma', scope={'window'},
deny_duplicates=true,
- vi_def=true,
redraw={'current_window'},
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='columns', abbreviation='co',
short_desc=N_("number of columns in the display"),
type='number', scope={'global'},
no_mkrc=true,
- vi_def=true,
redraw={'everything'},
varname='p_columns',
- defaults={if_true={vi=macros('DFLT_COLS')}}
+ defaults={if_true=macros('DFLT_COLS')}
},
{
full_name='comments', abbreviation='com',
short_desc=N_("patterns that can start a comment line"),
type='string', list='onecomma', scope={'buffer'},
deny_duplicates=true,
- vi_def=true,
alloced=true,
redraw={'curswant'},
varname='p_com',
- defaults={if_true={vi="s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:-"}}
+ defaults={if_true="s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:-"}
},
{
full_name='commentstring', abbreviation='cms',
short_desc=N_("template for comments; used for fold marker"),
type='string', scope={'buffer'},
- vi_def=true,
alloced=true,
redraw={'curswant'},
varname='p_cms',
- defaults={if_true={vi="/*%s*/"}}
+ defaults={if_true="/*%s*/"}
},
{
full_name='compatible', abbreviation='cp',
@@ -455,7 +409,7 @@ return {
varname='p_force_off',
-- pri_mkrc isn't needed here, optval_default()
-- always returns TRUE for 'compatible'
- defaults={if_true={vi=true, vim=false}}
+ defaults={if_true=false}
},
{
full_name='complete', abbreviation='cpt',
@@ -464,193 +418,172 @@ return {
deny_duplicates=true,
alloced=true,
varname='p_cpt',
- defaults={if_true={vi=".,w,b,u,t,i", vim=".,w,b,u,t"}}
+ defaults={if_true=".,w,b,u,t"}
},
{
full_name='concealcursor', abbreviation='cocu',
short_desc=N_("whether concealable text is hidden in cursor line"),
type='string', scope={'window'},
- vi_def=true,
alloced=true,
redraw={'current_window'},
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='conceallevel', abbreviation='cole',
short_desc=N_("whether concealable text is shown or hidden"),
type='number', scope={'window'},
- vi_def=true,
redraw={'current_window'},
- defaults={if_true={vi=0}}
+ defaults={if_true=0}
},
{
full_name='completefunc', abbreviation='cfu',
short_desc=N_("function to be used for Insert mode completion"),
type='string', scope={'buffer'},
secure=true,
- vi_def=true,
alloced=true,
varname='p_cfu',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='completeopt', abbreviation='cot',
short_desc=N_("options for Insert mode completion"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
varname='p_cot',
- defaults={if_true={vi="menu,preview"}}
+ defaults={if_true="menu,preview"}
},
{
full_name='completeslash', abbreviation='csl',
type='string', scope={'buffer'},
- vi_def=true,
- vim=true,
varname='p_csl',
enable_if='BACKSLASH_IN_FILENAME',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='confirm', abbreviation='cf',
short_desc=N_("ask what to do about unsaved/read-only files"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_confirm',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='copyindent', abbreviation='ci',
short_desc=N_("make 'autoindent' use existing indent structure"),
type='bool', scope={'buffer'},
- vi_def=true,
- vim=true,
varname='p_ci',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='cpoptions', abbreviation='cpo',
short_desc=N_("flags for Vi-compatible behavior"),
type='string', list='flags', scope={'global'},
- vim=true,
redraw={'all_windows'},
varname='p_cpo',
- defaults={if_true={vi=macros('CPO_VI'), vim=macros('CPO_VIM')}}
+ defaults={if_true=macros('CPO_VIM')}
},
{
full_name='cscopepathcomp', abbreviation='cspc',
short_desc=N_("how many components of the path to show"),
type='number', scope={'global'},
- vi_def=true,
- vim=true,
varname='p_cspc',
- defaults={if_true={vi=0}}
+ defaults={if_true=0}
},
{
full_name='cscopeprg', abbreviation='csprg',
short_desc=N_("command to execute cscope"),
type='string', scope={'global'},
secure=true,
- vi_def=true,
expand=true,
varname='p_csprg',
- defaults={if_true={vi="cscope"}}
+ defaults={if_true="cscope"}
},
{
full_name='cscopequickfix', abbreviation='csqf',
short_desc=N_("use quickfix window for cscope results"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
varname='p_csqf',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='cscoperelative', abbreviation='csre',
short_desc=N_("Use cscope.out path basename as prefix"),
type='bool', scope={'global'},
- vi_def=true,
- vim=true,
varname='p_csre',
- defaults={if_true={vi=0}}
+ defaults={if_true=0}
},
{
full_name='cscopetag', abbreviation='cst',
short_desc=N_("use cscope for tag commands"),
type='bool', scope={'global'},
- vi_def=true,
- vim=true,
varname='p_cst',
- defaults={if_true={vi=0}}
+ defaults={if_true=0}
},
{
full_name='cscopetagorder', abbreviation='csto',
short_desc=N_("determines \":cstag\" search order"),
type='number', scope={'global'},
- vi_def=true,
- vim=true,
varname='p_csto',
- defaults={if_true={vi=0}}
+ defaults={if_true=0}
},
{
full_name='cscopeverbose', abbreviation='csverb',
short_desc=N_("give messages when adding a cscope database"),
type='bool', scope={'global'},
- vi_def=true,
- vim=true,
varname='p_csverbose',
- defaults={if_true={vi=1}}
+ defaults={if_true=1}
},
{
full_name='cursorbind', abbreviation='crb',
short_desc=N_("move cursor in window as it moves in other windows"),
type='bool', scope={'window'},
- vi_def=true,
pv_name='p_crbind',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='cursorcolumn', abbreviation='cuc',
short_desc=N_("highlight the screen column of the cursor"),
type='bool', scope={'window'},
- vi_def=true,
redraw={'current_window_only'},
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='cursorline', abbreviation='cul',
short_desc=N_("highlight the screen line of the cursor"),
type='bool', scope={'window'},
- vi_def=true,
redraw={'current_window_only'},
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
+ },
+ {
+ full_name='cursorlineopt', abbreviation='culopt',
+ short_desc=N_("settings for 'cursorline'"),
+ type='string', list='onecomma', scope={'window'},
+ deny_duplicates=true,
+ redraw={'current_window_only'},
+ defaults={if_true="both"}
},
{
full_name='debug',
short_desc=N_("to \"msg\" to see all error messages"),
type='string', scope={'global'},
- vi_def=true,
varname='p_debug',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='define', abbreviation='def',
short_desc=N_("pattern to be used to find a macro definition"),
type='string', scope={'global', 'buffer'},
- vi_def=true,
alloced=true,
redraw={'curswant'},
varname='p_def',
- defaults={if_true={vi="^\\s*#\\s*define"}}
+ defaults={if_true="^\\s*#\\s*define"}
},
{
full_name='delcombine', abbreviation='deco',
short_desc=N_("delete combining characters on their own"),
type='bool', scope={'global'},
- vi_def=true,
- vim=true,
varname='p_deco',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='dictionary', abbreviation='dict',
@@ -658,49 +591,43 @@ return {
type='string', list='onecomma', scope={'global', 'buffer'},
deny_duplicates=true,
normal_dname_chars=true,
- vi_def=true,
expand=true,
varname='p_dict',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='diff',
short_desc=N_("diff mode for the current window"),
type='bool', scope={'window'},
noglob=true,
- vi_def=true,
redraw={'current_window'},
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='diffexpr', abbreviation='dex',
short_desc=N_("expression used to obtain a diff file"),
type='string', scope={'global'},
secure=true,
- vi_def=true,
redraw={'curswant'},
varname='p_dex',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='diffopt', abbreviation='dip',
short_desc=N_("options for using diff mode"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
alloced=true,
redraw={'current_window'},
varname='p_dip',
- defaults={if_true={vi="internal,filler,closeoff"}}
+ defaults={if_true="internal,filler,closeoff"}
},
{
full_name='digraph', abbreviation='dg',
short_desc=N_("enable the entering of digraphs in Insert mode"),
type='bool', scope={'global'},
- vi_def=true,
- vim=true,
varname='p_dg',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='directory', abbreviation='dir',
@@ -708,188 +635,167 @@ return {
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
secure=true,
- vi_def=true,
expand='nodefault',
varname='p_dir',
- defaults={if_true={vi=''}}
+ defaults={if_true=''}
},
{
full_name='display', abbreviation='dy',
short_desc=N_("list of flags for how to display text"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vim=true,
redraw={'all_windows'},
varname='p_dy',
- defaults={if_true={vi="", vim="lastline,msgsep"}}
+ defaults={if_true="lastline,msgsep"}
},
{
full_name='eadirection', abbreviation='ead',
short_desc=N_("in which direction 'equalalways' works"),
type='string', scope={'global'},
- vi_def=true,
varname='p_ead',
- defaults={if_true={vi="both"}}
+ defaults={if_true="both"}
},
{
full_name='edcompatible', abbreviation='ed',
short_desc=N_("No description"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_force_off',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='emoji', abbreviation='emo',
short_desc=N_("No description"),
type='bool', scope={'global'},
- vi_def=true,
redraw={'all_windows', 'ui_option'},
varname='p_emoji',
- defaults={if_true={vi=true}}
+ defaults={if_true=true}
},
{
full_name='encoding', abbreviation='enc',
short_desc=N_("encoding used internally"),
type='string', scope={'global'},
deny_in_modelines=true,
- vi_def=true,
varname='p_enc',
- defaults={if_true={vi=macros('ENC_DFLT')}}
+ defaults={if_true=macros('ENC_DFLT')}
},
{
full_name='endofline', abbreviation='eol',
short_desc=N_("write <EOL> for last line in file"),
type='bool', scope={'buffer'},
no_mkrc=true,
- vi_def=true,
redraw={'statuslines'},
varname='p_eol',
- defaults={if_true={vi=true}}
+ defaults={if_true=true}
},
{
full_name='equalalways', abbreviation='ea',
short_desc=N_("windows are automatically made the same size"),
type='bool', scope={'global'},
- vi_def=true,
redraw={'all_windows'},
varname='p_ea',
- defaults={if_true={vi=true}}
+ defaults={if_true=true}
},
{
full_name='equalprg', abbreviation='ep',
short_desc=N_("external program to use for \"=\" command"),
type='string', scope={'global', 'buffer'},
secure=true,
- vi_def=true,
expand=true,
varname='p_ep',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='errorbells', abbreviation='eb',
short_desc=N_("ring the bell for error messages"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_eb',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='errorfile', abbreviation='ef',
short_desc=N_("name of the errorfile for the QuickFix mode"),
type='string', scope={'global'},
secure=true,
- vi_def=true,
expand=true,
varname='p_ef',
- defaults={if_true={vi=macros('DFLT_ERRORFILE')}}
+ defaults={if_true=macros('DFLT_ERRORFILE')}
},
{
full_name='errorformat', abbreviation='efm',
short_desc=N_("description of the lines in the error file"),
type='string', list='onecomma', scope={'global', 'buffer'},
deny_duplicates=true,
- vi_def=true,
varname='p_efm',
- defaults={if_true={vi=macros('DFLT_EFM')}}
+ defaults={if_true=macros('DFLT_EFM')}
},
{
full_name='eventignore', abbreviation='ei',
short_desc=N_("autocommand events that are ignored"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
varname='p_ei',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='expandtab', abbreviation='et',
short_desc=N_("use spaces when <Tab> is inserted"),
type='bool', scope={'buffer'},
- vi_def=true,
- vim=true,
varname='p_et',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='exrc', abbreviation='ex',
short_desc=N_("read .nvimrc and .exrc in the current directory"),
type='bool', scope={'global'},
secure=true,
- vi_def=true,
varname='p_exrc',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='fileencoding', abbreviation='fenc',
short_desc=N_("file encoding for multi-byte text"),
type='string', scope={'buffer'},
no_mkrc=true,
- vi_def=true,
alloced=true,
redraw={'statuslines', 'current_buffer'},
varname='p_fenc',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='fileencodings', abbreviation='fencs',
short_desc=N_("automatically detected character encodings"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
varname='p_fencs',
- defaults={if_true={vi="ucs-bom,utf-8,default,latin1"}}
+ defaults={if_true="ucs-bom,utf-8,default,latin1"}
},
{
full_name='fileformat', abbreviation='ff',
short_desc=N_("file format used for file I/O"),
type='string', scope={'buffer'},
no_mkrc=true,
- vi_def=true,
alloced=true,
redraw={'curswant', 'statuslines'},
varname='p_ff',
- defaults={if_true={vi=macros('DFLT_FF')}}
+ defaults={if_true=macros('DFLT_FF')}
},
{
full_name='fileformats', abbreviation='ffs',
short_desc=N_("automatically detected values for 'fileformat'"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vim=true,
varname='p_ffs',
- defaults={if_true={vi=macros('DFLT_FFS_VI'), vim=macros('DFLT_FFS_VIM')}}
+ defaults={if_true=macros('DFLT_FFS_VIM')}
},
{
full_name='fileignorecase', abbreviation='fic',
short_desc=N_("ignore case when using file names"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_fic',
defaults={
condition='CASE_INSENSITIVE_FILENAME',
- if_true={vi=true},
- if_false={vi=false},
+ if_true=true,
+ if_false=false,
}
},
{
@@ -898,235 +804,204 @@ return {
type='string', scope={'buffer'},
noglob=true,
normal_fname_chars=true,
- vi_def=true,
alloced=true,
expand=true,
varname='p_ft',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='fillchars', abbreviation='fcs',
short_desc=N_("characters to use for displaying special items"),
type='string', list='onecomma', scope={'global', 'window'},
deny_duplicates=true,
- vi_def=true,
alloced=true,
redraw={'current_window'},
varname='p_fcs',
- defaults={if_true={vi=''}}
+ defaults={if_true=''}
},
{
full_name='fixendofline', abbreviation='fixeol',
short_desc=N_("make sure last line in file has <EOL>"),
type='bool', scope={'buffer'},
- vi_def=true,
redraw={'statuslines'},
varname='p_fixeol',
- defaults={if_true={vi=true}}
+ defaults={if_true=true}
},
{
full_name='foldclose', abbreviation='fcl',
short_desc=N_("close a fold when the cursor leaves it"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
redraw={'current_window'},
varname='p_fcl',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='foldcolumn', abbreviation='fdc',
short_desc=N_("width of the column used to indicate folds"),
type='string', scope={'window'},
- vi_def=true,
alloced=true,
redraw={'current_window'},
- defaults={if_true={vi="0"}}
+ defaults={if_true="0"}
},
{
full_name='foldenable', abbreviation='fen',
short_desc=N_("set to display all folds open"),
type='bool', scope={'window'},
- vi_def=true,
redraw={'current_window'},
- defaults={if_true={vi=true}}
+ defaults={if_true=true}
},
{
full_name='foldexpr', abbreviation='fde',
short_desc=N_("expression used when 'foldmethod' is \"expr\""),
type='string', scope={'window'},
- vi_def=true,
- vim=true,
modelineexpr=true,
alloced=true,
redraw={'current_window'},
- defaults={if_true={vi="0"}}
+ defaults={if_true="0"}
},
{
full_name='foldignore', abbreviation='fdi',
short_desc=N_("ignore lines when 'foldmethod' is \"indent\""),
type='string', scope={'window'},
- vi_def=true,
- vim=true,
alloced=true,
redraw={'current_window'},
- defaults={if_true={vi="#"}}
+ defaults={if_true="#"}
},
{
full_name='foldlevel', abbreviation='fdl',
short_desc=N_("close folds with a level higher than this"),
type='number', scope={'window'},
- vi_def=true,
redraw={'current_window'},
- defaults={if_true={vi=0}}
+ defaults={if_true=0}
},
{
full_name='foldlevelstart', abbreviation='fdls',
short_desc=N_("'foldlevel' when starting to edit a file"),
type='number', scope={'global'},
- vi_def=true,
redraw={'curswant'},
varname='p_fdls',
- defaults={if_true={vi=-1}}
+ defaults={if_true=-1}
},
{
full_name='foldmarker', abbreviation='fmr',
short_desc=N_("markers used when 'foldmethod' is \"marker\""),
type='string', list='onecomma', scope={'window'},
deny_duplicates=true,
- vi_def=true,
- vim=true,
alloced=true,
redraw={'current_window'},
- defaults={if_true={vi="{{{,}}}"}}
+ defaults={if_true="{{{,}}}"}
},
{
full_name='foldmethod', abbreviation='fdm',
short_desc=N_("folding type"),
type='string', scope={'window'},
- vi_def=true,
- vim=true,
alloced=true,
redraw={'current_window'},
- defaults={if_true={vi="manual"}}
+ defaults={if_true="manual"}
},
{
full_name='foldminlines', abbreviation='fml',
short_desc=N_("minimum number of lines for a fold to be closed"),
type='number', scope={'window'},
- vi_def=true,
redraw={'current_window'},
- defaults={if_true={vi=1}}
+ defaults={if_true=1}
},
{
full_name='foldnestmax', abbreviation='fdn',
short_desc=N_("maximum fold depth"),
type='number', scope={'window'},
- vi_def=true,
redraw={'current_window'},
- defaults={if_true={vi=20}}
+ defaults={if_true=20}
},
{
full_name='foldopen', abbreviation='fdo',
short_desc=N_("for which commands a fold will be opened"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
redraw={'curswant'},
varname='p_fdo',
- defaults={if_true={vi="block,hor,mark,percent,quickfix,search,tag,undo"}}
+ defaults={if_true="block,hor,mark,percent,quickfix,search,tag,undo"}
},
{
full_name='foldtext', abbreviation='fdt',
short_desc=N_("expression used to display for a closed fold"),
type='string', scope={'window'},
- vi_def=true,
- vim=true,
modelineexpr=true,
alloced=true,
redraw={'current_window'},
- defaults={if_true={vi="foldtext()"}}
+ defaults={if_true="foldtext()"}
},
{
full_name='formatexpr', abbreviation='fex',
short_desc=N_("expression used with \"gq\" command"),
type='string', scope={'buffer'},
- vi_def=true,
- vim=true,
modelineexpr=true,
alloced=true,
varname='p_fex',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='formatoptions', abbreviation='fo',
short_desc=N_("how automatic formatting is to be done"),
type='string', list='flags', scope={'buffer'},
- vim=true,
alloced=true,
varname='p_fo',
- defaults={if_true={vi=macros('DFLT_FO_VI'), vim=macros('DFLT_FO_VIM')}}
+ defaults={if_true=macros('DFLT_FO_VIM')}
},
{
full_name='formatlistpat', abbreviation='flp',
short_desc=N_("pattern used to recognize a list header"),
type='string', scope={'buffer'},
- vi_def=true,
alloced=true,
varname='p_flp',
- defaults={if_true={vi="^\\s*\\d\\+[\\]:.)}\\t ]\\s*"}}
+ defaults={if_true="^\\s*\\d\\+[\\]:.)}\\t ]\\s*"}
},
{
full_name='formatprg', abbreviation='fp',
short_desc=N_("name of external program used with \"gq\" command"),
type='string', scope={'global', 'buffer'},
secure=true,
- vi_def=true,
expand=true,
varname='p_fp',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='fsync', abbreviation='fs',
short_desc=N_("whether to invoke fsync() after file write"),
type='bool', scope={'global'},
secure=true,
- vi_def=true,
varname='p_fs',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='gdefault', abbreviation='gd',
short_desc=N_("the \":substitute\" flag 'g' is default on"),
type='bool', scope={'global'},
- vi_def=true,
- vim=true,
varname='p_gd',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='grepformat', abbreviation='gfm',
short_desc=N_("format of 'grepprg' output"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
varname='p_gefm',
- defaults={if_true={vi=macros('DFLT_GREPFORMAT')}}
+ defaults={if_true=macros('DFLT_GREPFORMAT')}
},
{
full_name='grepprg', abbreviation='gp',
short_desc=N_("program to use for \":grep\""),
type='string', scope={'global', 'buffer'},
secure=true,
- vi_def=true,
expand=true,
varname='p_gp',
defaults={
condition='WIN32',
-- Add an extra file name so that grep will always
-- insert a file name in the match line. */
- if_true={vi="findstr /n $* nul"},
- if_false={vi="grep -n $* /dev/null"}
+ if_true="findstr /n $* nul",
+ if_false="grep -n $* /dev/null"
}
},
{
@@ -1134,35 +1009,31 @@ return {
short_desc=N_("GUI: settings for cursor shape and blinking"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
varname='p_guicursor',
- defaults={if_true={vi="n-v-c-sm:block,i-ci-ve:ver25,r-cr-o:hor20"}}
+ defaults={if_true="n-v-c-sm:block,i-ci-ve:ver25,r-cr-o:hor20"}
},
{
full_name='guifont', abbreviation='gfn',
short_desc=N_("GUI: Name(s) of font(s) to be used"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
varname='p_guifont',
redraw={'ui_option'},
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='guifontwide', abbreviation='gfw',
short_desc=N_("list of font names for double-wide characters"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
redraw={'ui_option'},
varname='p_guifontwide',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='guioptions', abbreviation='go',
short_desc=N_("GUI: Which components and options are used"),
type='string', list='flags', scope={'global'},
- vi_def=true,
redraw={'all_windows'},
enable_if=false,
},
@@ -1170,7 +1041,6 @@ return {
full_name='guitablabel', abbreviation='gtl',
short_desc=N_("GUI: custom label for a tab page"),
type='string', scope={'global'},
- vi_def=true,
modelineexpr=true,
redraw={'current_window'},
enable_if=false,
@@ -1179,7 +1049,6 @@ return {
full_name='guitabtooltip', abbreviation='gtt',
short_desc=N_("GUI: custom tooltip for a tab page"),
type='string', scope={'global'},
- vi_def=true,
redraw={'current_window'},
enable_if=false,
},
@@ -1188,228 +1057,199 @@ return {
short_desc=N_("full path name of the main help file"),
type='string', scope={'global'},
secure=true,
- vi_def=true,
expand=true,
varname='p_hf',
- defaults={if_true={vi=macros('DFLT_HELPFILE')}}
+ defaults={if_true=macros('DFLT_HELPFILE')}
},
{
full_name='helpheight', abbreviation='hh',
short_desc=N_("minimum height of a new help window"),
type='number', scope={'global'},
- vi_def=true,
varname='p_hh',
- defaults={if_true={vi=20}}
+ defaults={if_true=20}
},
{
full_name='helplang', abbreviation='hlg',
short_desc=N_("preferred help languages"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
varname='p_hlg',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='hidden', abbreviation='hid',
short_desc=N_("don't unload buffer when it is |abandon|ed"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_hid',
- defaults={if_true={vi=false}}
+ defaults={if_true=true}
},
{
full_name='highlight', abbreviation='hl',
short_desc=N_("sets highlighting mode for various occasions"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
varname='p_hl',
- defaults={if_true={vi=macros('HIGHLIGHT_INIT')}}
+ defaults={if_true=macros('HIGHLIGHT_INIT')}
},
{
full_name='history', abbreviation='hi',
short_desc=N_("number of command-lines that are remembered"),
type='number', scope={'global'},
- vim=true,
varname='p_hi',
- defaults={if_true={vi=0, vim=10000}}
+ defaults={if_true=10000}
},
{
full_name='hkmap', abbreviation='hk',
short_desc=N_("Hebrew keyboard mapping"),
type='bool', scope={'global'},
- vi_def=true,
- vim=true,
varname='p_hkmap',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='hkmapp', abbreviation='hkp',
short_desc=N_("phonetic Hebrew keyboard mapping"),
type='bool', scope={'global'},
- vi_def=true,
- vim=true,
varname='p_hkmapp',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='hlsearch', abbreviation='hls',
short_desc=N_("highlight matches with last search pattern"),
type='bool', scope={'global'},
- vim=true,
redraw={'all_windows'},
varname='p_hls',
- defaults={if_true={vi=false, vim=true}}
+ defaults={if_true=true}
},
{
full_name='icon',
short_desc=N_("Vim set the text of the window icon"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_icon',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='iconstring',
short_desc=N_("to use for the Vim icon text"),
type='string', scope={'global'},
- vi_def=true,
modelineexpr=true,
varname='p_iconstring',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='ignorecase', abbreviation='ic',
short_desc=N_("ignore case in search patterns"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_ic',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='imcmdline', abbreviation='imc',
short_desc=N_("use IM when starting to edit a command line"),
type='bool', scope={'global'},
- vi_def=true,
enable_if=false,
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='imdisable', abbreviation='imd',
short_desc=N_("do not use the IM in any mode"),
type='bool', scope={'global'},
- vi_def=true,
enable_if=false,
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='iminsert', abbreviation='imi',
short_desc=N_("use :lmap or IM in Insert mode"),
type='number', scope={'buffer'},
- vi_def=true,
varname='p_iminsert', pv_name='p_imi',
defaults={
- if_true={vi=macros('B_IMODE_NONE')},
+ if_true=macros('B_IMODE_NONE'),
}
},
{
full_name='imsearch', abbreviation='ims',
short_desc=N_("use :lmap or IM when typing a search pattern"),
type='number', scope={'buffer'},
- vi_def=true,
varname='p_imsearch', pv_name='p_ims',
defaults={
- if_true={vi=macros('B_IMODE_USE_INSERT')},
+ if_true=macros('B_IMODE_USE_INSERT'),
}
},
{
full_name='inccommand', abbreviation='icm',
short_desc=N_("Live preview of substitution"),
type='string', scope={'global'},
- vi_def=true,
redraw={'all_windows'},
varname='p_icm',
- defaults={if_true={vi=""}}
+ defaults={if_true="nosplit"}
},
{
full_name='include', abbreviation='inc',
short_desc=N_("pattern to be used to find an include file"),
type='string', scope={'global', 'buffer'},
- vi_def=true,
alloced=true,
varname='p_inc',
- defaults={if_true={vi="^\\s*#\\s*include"}}
+ defaults={if_true="^\\s*#\\s*include"}
},
{
full_name='includeexpr', abbreviation='inex',
short_desc=N_("expression used to process an include line"),
type='string', scope={'buffer'},
- vi_def=true,
modelineexpr=true,
alloced=true,
varname='p_inex',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='incsearch', abbreviation='is',
short_desc=N_("highlight match while typing search pattern"),
type='bool', scope={'global'},
- vim=true,
varname='p_is',
- defaults={if_true={vi=false, vim=true}}
+ defaults={if_true=true}
},
{
full_name='indentexpr', abbreviation='inde',
short_desc=N_("expression used to obtain the indent of a line"),
type='string', scope={'buffer'},
- vi_def=true,
- vim=true,
modelineexpr=true,
alloced=true,
varname='p_inde',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='indentkeys', abbreviation='indk',
short_desc=N_("keys that trigger indenting with 'indentexpr'"),
type='string', list='onecomma', scope={'buffer'},
deny_duplicates=true,
- vi_def=true,
alloced=true,
varname='p_indk',
- defaults={if_true={vi=indentkeys_default}}
+ defaults={if_true=indentkeys_default}
},
{
full_name='infercase', abbreviation='inf',
short_desc=N_("adjust case of match for keyword completion"),
type='bool', scope={'buffer'},
- vi_def=true,
varname='p_inf',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='insertmode', abbreviation='im',
short_desc=N_("start the edit of a file in Insert mode"),
type='bool', scope={'global'},
- vi_def=true,
- vim=true,
varname='p_im',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='isfname', abbreviation='isf',
short_desc=N_("characters included in file names and pathnames"),
type='string', list='comma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
varname='p_isf',
defaults={
condition='BACKSLASH_IN_FILENAME',
-- Excluded are: & and ^ are special in cmd.exe
-- ( and ) are used in text separating fnames */
- if_true={vi="@,48-57,/,\\,.,-,_,+,,,#,$,%,{,},[,],:,@-@,!,~,="},
- if_false={vi="@,48-57,/,.,-,_,+,,,#,$,%,~,="}
+ if_true="@,48-57,/,\\,.,-,_,+,,,#,$,%,{,},[,],:,@-@,!,~,=",
+ if_false="@,48-57,/,.,-,_,+,,,#,$,%,~,="
}
},
{
@@ -1417,12 +1257,11 @@ return {
short_desc=N_("characters included in identifiers"),
type='string', list='comma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
varname='p_isi',
defaults={
condition='WIN32',
- if_true={vi="@,48-57,_,128-167,224-235"},
- if_false={vi="@,48-57,_,192-255"}
+ if_true="@,48-57,_,128-167,224-235",
+ if_false="@,48-57,_,192-255"
}
},
{
@@ -1430,30 +1269,26 @@ return {
short_desc=N_("characters included in keywords"),
type='string', list='comma', scope={'buffer'},
deny_duplicates=true,
- vim=true,
alloced=true,
varname='p_isk',
- defaults={if_true={vi="@,48-57,_", vim="@,48-57,_,192-255"}}
+ defaults={if_true="@,48-57,_,192-255"}
},
{
full_name='isprint', abbreviation='isp',
short_desc=N_("printable characters"),
type='string', list='comma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
redraw={'all_windows'},
varname='p_isp',
- defaults={if_true={vi="@,161-255"}
+ defaults={if_true="@,161-255"
}
},
{
full_name='joinspaces', abbreviation='js',
short_desc=N_("two spaces after a period with a join command"),
type='bool', scope={'global'},
- vi_def=true,
- vim=true,
varname='p_js',
- defaults={if_true={vi=true}}
+ defaults={if_true=false}
},
{
full_name='jumpoptions', abbreviation='jop',
@@ -1461,8 +1296,7 @@ return {
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
varname='p_jop',
- vim=true,
- defaults={if_true={vim=''}}
+ defaults={if_true=''}
},
{
full_name='keymap', abbreviation='kmp',
@@ -1470,31 +1304,28 @@ return {
type='string', scope={'buffer'},
normal_fname_chars=true,
pri_mkrc=true,
- vi_def=true,
alloced=true,
redraw={'statuslines', 'current_buffer'},
varname='p_keymap', pv_name='p_kmap',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='keymodel', abbreviation='km',
short_desc=N_("enable starting/stopping selection with keys"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
varname='p_km',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='keywordprg', abbreviation='kp',
short_desc=N_("program to use for the \"K\" command"),
type='string', scope={'global', 'buffer'},
secure=true,
- vi_def=true,
expand=true,
varname='p_kp',
defaults={
- if_true={vi=":Man"},
+ if_true=":Man",
}
},
{
@@ -1503,324 +1334,289 @@ return {
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
secure=true,
- vi_def=true,
varname='p_langmap',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='langmenu', abbreviation='lm',
short_desc=N_("language to be used for the menus"),
type='string', scope={'global'},
normal_fname_chars=true,
- vi_def=true,
varname='p_lm',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='langnoremap', abbreviation='lnr',
short_desc=N_("do not apply 'langmap' to mapped characters"),
type='bool', scope={'global'},
varname='p_lnr',
- defaults={if_true={vi=false, vim=true}}
+ defaults={if_true=true}
},
{
full_name='langremap', abbreviation='lrm',
short_desc=N_('No description'),
type='bool', scope={'global'},
varname='p_lrm',
- defaults={if_true={vi=true, vim=false}}
+ defaults={if_true=false}
},
{
full_name='laststatus', abbreviation='ls',
short_desc=N_("tells when last window has status lines"),
type='number', scope={'global'},
- vim=true,
redraw={'all_windows'},
varname='p_ls',
- defaults={if_true={vi=1,vim=2}}
+ defaults={if_true=2}
},
{
full_name='lazyredraw', abbreviation='lz',
short_desc=N_("don't redraw while executing macros"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_lz',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='linebreak', abbreviation='lbr',
short_desc=N_("wrap long lines at a blank"),
type='bool', scope={'window'},
- vi_def=true,
redraw={'current_window'},
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='lines',
short_desc=N_("of lines in the display"),
type='number', scope={'global'},
no_mkrc=true,
- vi_def=true,
redraw={'everything'},
varname='p_lines',
- defaults={if_true={vi=macros('DFLT_ROWS')}}
+ defaults={if_true=macros('DFLT_ROWS')}
},
{
full_name='linespace', abbreviation='lsp',
short_desc=N_("number of pixel lines to use between characters"),
type='number', scope={'global'},
- vi_def=true,
redraw={'ui_option'},
varname='p_linespace',
- defaults={if_true={vi=0}}
+ defaults={if_true=0}
},
{
full_name='lisp',
short_desc=N_("indenting for Lisp"),
type='bool', scope={'buffer'},
- vi_def=true,
varname='p_lisp',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='lispwords', abbreviation='lw',
short_desc=N_("words that change how lisp indenting works"),
type='string', list='onecomma', scope={'global', 'buffer'},
deny_duplicates=true,
- vi_def=true,
varname='p_lispwords', pv_name='p_lw',
- defaults={if_true={vi=macros('LISPWORD_VALUE')}}
+ defaults={if_true=macros('LISPWORD_VALUE')}
},
{
full_name='list',
short_desc=N_("<Tab> and <EOL>"),
type='bool', scope={'window'},
- vi_def=true,
redraw={'current_window'},
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='listchars', abbreviation='lcs',
short_desc=N_("characters for displaying in list mode"),
type='string', list='onecomma', scope={'global', 'window'},
deny_duplicates=true,
- vim=true,
alloced=true,
redraw={'current_window'},
varname='p_lcs',
- defaults={if_true={vi="eol:$", vim="tab:> ,trail:-,nbsp:+"}}
+ defaults={if_true="tab:> ,trail:-,nbsp:+"}
},
{
full_name='loadplugins', abbreviation='lpl',
short_desc=N_("load plugin scripts when starting up"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_lpl',
- defaults={if_true={vi=true}}
+ defaults={if_true=true}
},
{
full_name='magic',
short_desc=N_("special characters in search patterns"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_magic',
- defaults={if_true={vi=true}}
+ defaults={if_true=true}
},
{
full_name='makeef', abbreviation='mef',
short_desc=N_("name of the errorfile for \":make\""),
type='string', scope={'global'},
secure=true,
- vi_def=true,
expand=true,
varname='p_mef',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='makeencoding', abbreviation='menc',
short_desc=N_("Converts the output of external commands"),
type='string', scope={'global', 'buffer'},
- vi_def=true,
varname='p_menc',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='makeprg', abbreviation='mp',
short_desc=N_("program to use for the \":make\" command"),
type='string', scope={'global', 'buffer'},
secure=true,
- vi_def=true,
expand=true,
varname='p_mp',
- defaults={if_true={vi="make"}}
+ defaults={if_true="make"}
},
{
full_name='matchpairs', abbreviation='mps',
short_desc=N_("pairs of characters that \"%\" can match"),
type='string', list='onecomma', scope={'buffer'},
deny_duplicates=true,
- vi_def=true,
alloced=true,
varname='p_mps',
- defaults={if_true={vi="(:),{:},[:]"}}
+ defaults={if_true="(:),{:},[:]"}
},
{
full_name='matchtime', abbreviation='mat',
short_desc=N_("tenths of a second to show matching paren"),
type='number', scope={'global'},
- vi_def=true,
varname='p_mat',
- defaults={if_true={vi=5}}
+ defaults={if_true=5}
},
{
full_name='maxcombine', abbreviation='mco',
short_desc=N_("maximum nr of combining characters displayed"),
type='number', scope={'global'},
- vi_def=true,
varname='p_mco',
- defaults={if_true={vi=6}}
+ defaults={if_true=6}
},
{
full_name='maxfuncdepth', abbreviation='mfd',
short_desc=N_("maximum recursive depth for user functions"),
type='number', scope={'global'},
- vi_def=true,
varname='p_mfd',
- defaults={if_true={vi=100}}
+ defaults={if_true=100}
},
{
full_name='maxmapdepth', abbreviation='mmd',
short_desc=N_("maximum recursive depth for mapping"),
type='number', scope={'global'},
- vi_def=true,
varname='p_mmd',
- defaults={if_true={vi=1000}}
+ defaults={if_true=1000}
},
{
full_name='maxmempattern', abbreviation='mmp',
short_desc=N_("maximum memory (in Kbyte) used for pattern search"),
type='number', scope={'global'},
- vi_def=true,
varname='p_mmp',
- defaults={if_true={vi=1000}}
+ defaults={if_true=1000}
},
{
full_name='menuitems', abbreviation='mis',
short_desc=N_("maximum number of items in a menu"),
type='number', scope={'global'},
- vi_def=true,
varname='p_mis',
- defaults={if_true={vi=25}}
+ defaults={if_true=25}
},
{
full_name='mkspellmem', abbreviation='msm',
short_desc=N_("memory used before |:mkspell| compresses the tree"),
type='string', scope={'global'},
secure=true,
- vi_def=true,
expand=true,
varname='p_msm',
- defaults={if_true={vi="460000,2000,500"}}
+ defaults={if_true="460000,2000,500"}
},
{
full_name='modeline', abbreviation='ml',
short_desc=N_("recognize modelines at start or end of file"),
type='bool', scope={'buffer'},
- vim=true,
varname='p_ml',
- defaults={if_true={vi=false, vim=true}}
+ defaults={if_true=true}
},
{
full_name='modelineexpr', abbreviation='mle',
short_desc=N_("allow some options to be set in modeline"),
type='bool', scope={'global'},
- vi_def=true,
secure=true,
varname='p_mle',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='modelines', abbreviation='mls',
short_desc=N_("number of lines checked for modelines"),
type='number', scope={'global'},
- vi_def=true,
varname='p_mls',
- defaults={if_true={vi=5}}
+ defaults={if_true=5}
},
{
full_name='modifiable', abbreviation='ma',
short_desc=N_("changes to the text are not possible"),
type='bool', scope={'buffer'},
noglob=true,
- vi_def=true,
varname='p_ma',
- defaults={if_true={vi=true}}
+ defaults={if_true=true}
},
{
full_name='modified', abbreviation='mod',
short_desc=N_("buffer has been modified"),
type='bool', scope={'buffer'},
no_mkrc=true,
- vi_def=true,
redraw={'statuslines'},
varname='p_mod',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='more',
short_desc=N_("listings when the whole screen is filled"),
type='bool', scope={'global'},
- vim=true,
varname='p_more',
- defaults={if_true={vi=false, vim=true}}
+ defaults={if_true=true}
},
{
full_name='mouse',
short_desc=N_("the use of mouse clicks"),
type='string', list='flags', scope={'global'},
varname='p_mouse',
- defaults={if_true={vi="", vim=""}}
+ defaults={if_true=""}
},
{
full_name='mousefocus', abbreviation='mousef',
short_desc=N_("keyboard focus follows the mouse"),
type='bool', scope={'global'},
- vi_def=true,
redraw={'ui_option'},
varname='p_mousef',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='mousehide', abbreviation='mh',
short_desc=N_("hide mouse pointer while typing"),
type='bool', scope={'global'},
- vi_def=true,
enable_if=false,
- defaults={if_true={vi=true}}
+ defaults={if_true=true}
},
{
full_name='mousemodel', abbreviation='mousem',
short_desc=N_("changes meaning of mouse buttons"),
type='string', scope={'global'},
- vi_def=true,
varname='p_mousem',
- defaults={if_true={vi="extend"}}
+ defaults={if_true="extend"}
},
{
full_name='mouseshape', abbreviation='mouses',
short_desc=N_("shape of the mouse pointer in different modes"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
enable_if=false,
},
{
full_name='mousetime', abbreviation='mouset',
short_desc=N_("max time between mouse double-click"),
type='number', scope={'global'},
- vi_def=true,
varname='p_mouset',
- defaults={if_true={vi=500}}
+ defaults={if_true=500}
},
{
full_name='nrformats', abbreviation='nf',
@@ -1829,50 +1625,45 @@ return {
deny_duplicates=true,
alloced=true,
varname='p_nf',
- defaults={if_true={vi="bin,octal,hex", vim="bin,hex"}}
+ defaults={if_true="bin,hex"}
},
{
full_name='number', abbreviation='nu',
short_desc=N_("print the line number in front of each line"),
type='bool', scope={'window'},
- vi_def=true,
redraw={'current_window'},
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='numberwidth', abbreviation='nuw',
short_desc=N_("number of columns used for the line number"),
type='number', scope={'window'},
- vim=true,
redraw={'current_window'},
- defaults={if_true={vi=8, vim=4}}
+ defaults={if_true=4}
},
{
full_name='omnifunc', abbreviation='ofu',
short_desc=N_("function for filetype-specific completion"),
type='string', scope={'buffer'},
secure=true,
- vi_def=true,
alloced=true,
varname='p_ofu',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='opendevice', abbreviation='odev',
short_desc=N_("allow reading/writing devices on MS-Windows"),
type='bool', scope={'global'},
- vi_def=true,
enable_if=false,
- defaults={if_true={vi=false, vim=false}}
+ defaults={if_true=false}
},
{
full_name='operatorfunc', abbreviation='opfunc',
short_desc=N_("function to be called for |g@| operator"),
type='string', scope={'global'},
secure=true,
- vi_def=true,
varname='p_opfunc',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='packpath', abbreviation='pp',
@@ -1880,320 +1671,280 @@ return {
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
secure=true,
- vi_def=true,
expand=true,
varname='p_pp',
- defaults={if_true={vi=''}}
+ defaults={if_true=''}
},
{
full_name='paragraphs', abbreviation='para',
short_desc=N_("nroff macros that separate paragraphs"),
type='string', scope={'global'},
- vi_def=true,
varname='p_para',
- defaults={if_true={vi="IPLPPPQPP TPHPLIPpLpItpplpipbp"}}
+ defaults={if_true="IPLPPPQPP TPHPLIPpLpItpplpipbp"}
},
{
full_name='paste',
short_desc=N_("pasting text"),
type='bool', scope={'global'},
pri_mkrc=true,
- vi_def=true,
varname='p_paste',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='pastetoggle', abbreviation='pt',
short_desc=N_("key code that causes 'paste' to toggle"),
type='string', scope={'global'},
- vi_def=true,
varname='p_pt',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='patchexpr', abbreviation='pex',
short_desc=N_("expression used to patch a file"),
type='string', scope={'global'},
secure=true,
- vi_def=true,
varname='p_pex',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='patchmode', abbreviation='pm',
short_desc=N_("keep the oldest version of a file"),
type='string', scope={'global'},
normal_fname_chars=true,
- vi_def=true,
varname='p_pm',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='path', abbreviation='pa',
short_desc=N_("list of directories searched with \"gf\" et.al."),
type='string', list='comma', scope={'global', 'buffer'},
deny_duplicates=true,
- vi_def=true,
expand=true,
varname='p_path',
- defaults={if_true={vi=".,/usr/include,,"}}
+ defaults={if_true=".,/usr/include,,"}
},
{
full_name='preserveindent', abbreviation='pi',
short_desc=N_("preserve the indent structure when reindenting"),
type='bool', scope={'buffer'},
- vi_def=true,
- vim=true,
varname='p_pi',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='previewheight', abbreviation='pvh',
short_desc=N_("height of the preview window"),
type='number', scope={'global'},
- vi_def=true,
varname='p_pvh',
- defaults={if_true={vi=12}}
+ defaults={if_true=12}
},
{
full_name='previewwindow', abbreviation='pvw',
short_desc=N_("identifies the preview window"),
type='bool', scope={'window'},
noglob=true,
- vi_def=true,
redraw={'statuslines'},
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='printdevice', abbreviation='pdev',
short_desc=N_("name of the printer to be used for :hardcopy"),
type='string', scope={'global'},
secure=true,
- vi_def=true,
varname='p_pdev',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='printencoding', abbreviation='penc',
short_desc=N_("encoding to be used for printing"),
type='string', scope={'global'},
- vi_def=true,
varname='p_penc',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='printexpr', abbreviation='pexpr',
short_desc=N_("expression used to print PostScript for :hardcopy"),
type='string', scope={'global'},
secure=true,
- vi_def=true,
varname='p_pexpr',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='printfont', abbreviation='pfn',
short_desc=N_("name of the font to be used for :hardcopy"),
type='string', scope={'global'},
- vi_def=true,
varname='p_pfn',
- defaults={if_true={vi="courier"}}
+ defaults={if_true="courier"}
},
{
full_name='printheader', abbreviation='pheader',
short_desc=N_("format of the header used for :hardcopy"),
type='string', scope={'global'},
- vi_def=true,
varname='p_header',
- defaults={if_true={vi="%<%f%h%m%=Page %N"}}
+ defaults={if_true="%<%f%h%m%=Page %N"}
},
{
full_name='printmbcharset', abbreviation='pmbcs',
short_desc=N_("CJK character set to be used for :hardcopy"),
type='string', scope={'global'},
- vi_def=true,
varname='p_pmcs',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='printmbfont', abbreviation='pmbfn',
short_desc=N_("font names to be used for CJK output of :hardcopy"),
type='string', scope={'global'},
- vi_def=true,
varname='p_pmfn',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='printoptions', abbreviation='popt',
short_desc=N_("controls the format of :hardcopy output"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
varname='p_popt',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='prompt',
short_desc=N_("enable prompt in Ex mode"),
type='bool', scope={'global'},
- vi_def=true,
- varname='p_prompt',
- defaults={if_true={vi=true}}
+ varname='p_force_on',
+ defaults={if_true=true}
},
{
full_name='pumblend', abbreviation='pb',
short_desc=N_("Controls transparency level of popup menu"),
type='number', scope={'global'},
- vi_def=true,
redraw={'ui_option'},
varname='p_pb',
- defaults={if_true={vi=0}}
+ defaults={if_true=0}
},
{
full_name='pumheight', abbreviation='ph',
short_desc=N_("maximum height of the popup menu"),
type='number', scope={'global'},
- vi_def=true,
varname='p_ph',
- defaults={if_true={vi=0}}
+ defaults={if_true=0}
},
{
full_name='pumwidth', abbreviation='pw',
short_desc=N_("minimum width of the popup menu"),
type='number', scope={'global'},
- vi_def=true,
varname='p_pw',
- defaults={if_true={vi=15}}
+ defaults={if_true=15}
},
{
full_name='pyxversion', abbreviation='pyx',
short_desc=N_("selects default python version to use"),
type='number', scope={'global'},
secure=true,
- vi_def=true,
varname='p_pyx',
- defaults={if_true={vi=0}}
+ defaults={if_true=0}
},
{
full_name='quickfixtextfunc', abbreviation='qftf',
short_desc=N_("customize the quickfix window"),
type='string', scope={'global'},
- vi_def=true,
varname='p_qftf',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='quoteescape', abbreviation='qe',
short_desc=N_("escape characters used in a string"),
type='string', scope={'buffer'},
- vi_def=true,
alloced=true,
varname='p_qe',
- defaults={if_true={vi="\\"}}
+ defaults={if_true="\\"}
},
{
full_name='readonly', abbreviation='ro',
short_desc=N_("disallow writing the buffer"),
type='bool', scope={'buffer'},
noglob=true,
- vi_def=true,
redraw={'statuslines'},
varname='p_ro',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='redrawdebug', abbreviation='rdb',
short_desc=N_("Changes the way redrawing works (debug)"),
type='string', list='onecomma', scope={'global'},
- vi_def=true,
varname='p_rdb',
- defaults={if_true={vi=''}}
+ defaults={if_true=''}
},
{
full_name='redrawtime', abbreviation='rdt',
short_desc=N_("timeout for 'hlsearch' and |:match| highlighting"),
type='number', scope={'global'},
- vi_def=true,
varname='p_rdt',
- defaults={if_true={vi=2000}}
+ defaults={if_true=2000}
},
{
full_name='regexpengine', abbreviation='re',
short_desc=N_("default regexp engine to use"),
type='number', scope={'global'},
- vi_def=true,
varname='p_re',
- defaults={if_true={vi=0}}
+ defaults={if_true=0}
},
{
full_name='relativenumber', abbreviation='rnu',
short_desc=N_("show relative line number in front of each line"),
type='bool', scope={'window'},
- vi_def=true,
redraw={'current_window'},
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='remap',
short_desc=N_("mappings to work recursively"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_remap',
- defaults={if_true={vi=true}}
+ defaults={if_true=true}
},
{
full_name='report',
short_desc=N_("for reporting nr. of lines changed"),
type='number', scope={'global'},
- vi_def=true,
varname='p_report',
- defaults={if_true={vi=2}}
+ defaults={if_true=2}
},
{
full_name='revins', abbreviation='ri',
short_desc=N_("inserting characters will work backwards"),
type='bool', scope={'global'},
- vi_def=true,
- vim=true,
varname='p_ri',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='rightleft', abbreviation='rl',
short_desc=N_("window is right-to-left oriented"),
type='bool', scope={'window'},
- vi_def=true,
redraw={'current_window'},
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='rightleftcmd', abbreviation='rlc',
short_desc=N_("commands for which editing works right-to-left"),
type='string', scope={'window'},
- vi_def=true,
alloced=true,
redraw={'current_window'},
- defaults={if_true={vi="search"}}
+ defaults={if_true="search"}
},
{
full_name='ruler', abbreviation='ru',
short_desc=N_("show cursor line and column in the status line"),
type='bool', scope={'global'},
- vi_def=true,
- vim=true,
redraw={'statuslines'},
varname='p_ru',
- defaults={if_true={vi=true}}
+ defaults={if_true=true}
},
{
full_name='rulerformat', abbreviation='ruf',
short_desc=N_("custom format for the ruler"),
type='string', scope={'global'},
- vi_def=true,
alloced=true,
modelineexpr=true,
redraw={'statuslines'},
varname='p_ruf',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='runtimepath', abbreviation='rtp',
@@ -2201,110 +1952,93 @@ return {
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
secure=true,
- vi_def=true,
expand='nodefault',
varname='p_rtp',
- defaults={if_true={vi=''}}
+ defaults={if_true=''}
},
{
full_name='scroll', abbreviation='scr',
short_desc=N_("lines to scroll with CTRL-U and CTRL-D"),
type='number', scope={'window'},
no_mkrc=true,
- vi_def=true,
pv_name='p_scroll',
- defaults={if_true={vi=0}}
+ defaults={if_true=0}
},
{
full_name='scrollback', abbreviation='scbk',
short_desc=N_("lines to scroll with CTRL-U and CTRL-D"),
type='number', scope={'buffer'},
- vi_def=true,
varname='p_scbk',
redraw={'current_buffer'},
- defaults={if_true={vi=-1}}
+ defaults={if_true=-1}
},
{
full_name='scrollbind', abbreviation='scb',
short_desc=N_("scroll in window as other windows scroll"),
type='bool', scope={'window'},
- vi_def=true,
pv_name='p_scbind',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='scrolljump', abbreviation='sj',
short_desc=N_("minimum number of lines to scroll"),
type='number', scope={'global'},
- vi_def=true,
- vim=true,
varname='p_sj',
- defaults={if_true={vi=1}}
+ defaults={if_true=1}
},
{
full_name='scrolloff', abbreviation='so',
short_desc=N_("minimum nr. of lines above and below cursor"),
type='number', scope={'global', 'window'},
- vi_def=true,
- vim=true,
redraw={'all_windows'},
varname='p_so',
- defaults={if_true={vi=0}}
+ defaults={if_true=0}
},
{
full_name='scrollopt', abbreviation='sbo',
short_desc=N_("how 'scrollbind' should behave"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
varname='p_sbo',
- defaults={if_true={vi="ver,jump"}}
+ defaults={if_true="ver,jump"}
},
{
full_name='sections', abbreviation='sect',
short_desc=N_("nroff macros that separate sections"),
type='string', scope={'global'},
- vi_def=true,
varname='p_sections',
- defaults={if_true={vi="SHNHH HUnhsh"}}
+ defaults={if_true="SHNHH HUnhsh"}
},
{
full_name='secure',
short_desc=N_("mode for reading .vimrc in current dir"),
type='bool', scope={'global'},
secure=true,
- vi_def=true,
varname='p_secure',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='selection', abbreviation='sel',
short_desc=N_("what type of selection to use"),
type='string', scope={'global'},
- vi_def=true,
varname='p_sel',
- defaults={if_true={vi="inclusive"}}
+ defaults={if_true="inclusive"}
},
{
full_name='selectmode', abbreviation='slm',
short_desc=N_("when to use Select mode instead of Visual mode"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
varname='p_slm',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='sessionoptions', abbreviation='ssop',
short_desc=N_("options for |:mksession|"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vim=true,
varname='p_ssop',
- defaults={if_true={
- vi="blank,buffers,curdir,folds,help,options,tabpages,winsize",
- vim="blank,buffers,curdir,folds,help,tabpages,winsize"
- }}
+ defaults={if_true="blank,buffers,curdir,folds,help,tabpages,winsize"}
},
{
full_name='shada', abbreviation='sd',
@@ -2313,31 +2047,29 @@ return {
deny_duplicates=true,
secure=true,
varname='p_shada',
- defaults={if_true={vi="", vim="!,'100,<50,s10,h"}}
+ defaults={if_true="!,'100,<50,s10,h"}
},
{
full_name='shadafile', abbreviation='sdf',
short_desc=N_("overrides the filename used for shada"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
secure=true,
expand=true,
varname='p_shadafile',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='shell', abbreviation='sh',
short_desc=N_("name of shell to use for external commands"),
type='string', scope={'global'},
secure=true,
- vi_def=true,
expand=true,
varname='p_sh',
defaults={
condition='WIN32',
- if_true={vi="cmd.exe"},
- if_false={vi="sh"}
+ if_true="cmd.exe",
+ if_false="sh"
}
},
{
@@ -2345,12 +2077,11 @@ return {
short_desc=N_("flag to shell to execute one command"),
type='string', scope={'global'},
secure=true,
- vi_def=true,
varname='p_shcf',
defaults={
condition='WIN32',
- if_true={vi="/s /c"},
- if_false={vi="-c"}
+ if_true="/s /c",
+ if_false="-c"
}
},
{
@@ -2358,12 +2089,11 @@ return {
short_desc=N_("string to put output of \":make\" in error file"),
type='string', scope={'global'},
secure=true,
- vi_def=true,
varname='p_sp',
defaults={
condition='WIN32',
- if_true={vi=">%s 2>&1"},
- if_false={vi="| tee"},
+ if_true=">%s 2>&1",
+ if_false="| tee",
}
},
{
@@ -2371,50 +2101,46 @@ return {
short_desc=N_("quote character(s) for around shell command"),
type='string', scope={'global'},
secure=true,
- vi_def=true,
varname='p_shq',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='shellredir', abbreviation='srr',
short_desc=N_("string to put output of filter in a temp file"),
type='string', scope={'global'},
secure=true,
- vi_def=true,
varname='p_srr',
defaults={
condition='WIN32',
- if_true={vi=">%s 2>&1"},
- if_false={vi=">"}
+ if_true=">%s 2>&1",
+ if_false=">"
}
},
{
full_name='shellslash', abbreviation='ssl',
short_desc=N_("use forward slash for shell file names"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_ssl',
enable_if='BACKSLASH_IN_FILENAME',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='shelltemp', abbreviation='stmp',
short_desc=N_("whether to use a temp file for shell commands"),
type='bool', scope={'global'},
varname='p_stmp',
- defaults={if_true={vi=false, vim=true}}
+ defaults={if_true=true}
},
{
full_name='shellxquote', abbreviation='sxq',
short_desc=N_("like 'shellquote', but include redirection"),
type='string', scope={'global'},
secure=true,
- vi_def=true,
varname='p_sxq',
defaults={
condition='WIN32',
- if_true={vi="\""},
- if_false={vi=""},
+ if_true="\"",
+ if_false="",
}
},
{
@@ -2422,164 +2148,140 @@ return {
short_desc=N_("characters to escape when 'shellxquote' is ("),
type='string', scope={'global'},
secure=true,
- vi_def=true,
varname='p_sxe',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='shiftround', abbreviation='sr',
short_desc=N_("round indent to multiple of shiftwidth"),
type='bool', scope={'global'},
- vi_def=true,
- vim=true,
varname='p_sr',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='shiftwidth', abbreviation='sw',
short_desc=N_("number of spaces to use for (auto)indent step"),
type='number', scope={'buffer'},
- vi_def=true,
varname='p_sw',
- defaults={if_true={vi=8}}
+ defaults={if_true=8}
},
{
full_name='shortmess', abbreviation='shm',
short_desc=N_("list of flags, reduce length of messages"),
type='string', list='flags', scope={'global'},
- vim=true,
varname='p_shm',
- defaults={if_true={vi="S", vim="filnxtToOF"}}
+ defaults={if_true="filnxtToOF"}
},
{
full_name='showbreak', abbreviation='sbr',
short_desc=N_("string to use at the start of wrapped lines"),
- type='string', scope={'global'},
- vi_def=true,
+ type='string', scope={'global', 'window'},
redraw={'all_windows'},
varname='p_sbr',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='showcmd', abbreviation='sc',
short_desc=N_("show (partial) command in status line"),
type='bool', scope={'global'},
- vim=true,
varname='p_sc',
- defaults={if_true={vi=false, vim=true}}
+ defaults={if_true=true}
},
{
full_name='showfulltag', abbreviation='sft',
short_desc=N_("show full tag pattern when completing tag"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_sft',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='showmatch', abbreviation='sm',
short_desc=N_("briefly jump to matching bracket if insert one"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_sm',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='showmode', abbreviation='smd',
short_desc=N_("message on status line to show current mode"),
type='bool', scope={'global'},
- vim=true,
varname='p_smd',
- defaults={if_true={vi=false, vim=true}}
+ defaults={if_true=true}
},
{
full_name='showtabline', abbreviation='stal',
short_desc=N_("tells when the tab pages line is displayed"),
type='number', scope={'global'},
- vi_def=true,
redraw={'all_windows', 'ui_option'},
varname='p_stal',
- defaults={if_true={vi=1}}
+ defaults={if_true=1}
},
{
full_name='sidescroll', abbreviation='ss',
short_desc=N_("minimum number of columns to scroll horizontal"),
type='number', scope={'global'},
- vi_def=true,
varname='p_ss',
- defaults={if_true={vi=1}}
+ defaults={if_true=1}
},
{
full_name='sidescrolloff', abbreviation='siso',
short_desc=N_("min. nr. of columns to left and right of cursor"),
type='number', scope={'global', 'window'},
- vi_def=true,
- vim=true,
redraw={'all_windows'},
varname='p_siso',
- defaults={if_true={vi=0}}
+ defaults={if_true=0}
},
{
full_name='signcolumn', abbreviation='scl',
short_desc=N_("when to display the sign column"),
type='string', scope={'window'},
- vi_def=true,
alloced=true,
redraw={'current_window'},
- defaults={if_true={vi="auto"}}
+ defaults={if_true="auto"}
},
{
full_name='smartcase', abbreviation='scs',
short_desc=N_("no ignore case when pattern has uppercase"),
type='bool', scope={'global'},
- vi_def=true,
- vim=true,
varname='p_scs',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='smartindent', abbreviation='si',
short_desc=N_("smart autoindenting for C programs"),
type='bool', scope={'buffer'},
- vi_def=true,
- vim=true,
varname='p_si',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='smarttab', abbreviation='sta',
short_desc=N_("use 'shiftwidth' when inserting <Tab>"),
type='bool', scope={'global'},
- vim=true,
varname='p_sta',
- defaults={if_true={vi=false, vim=true}}
+ defaults={if_true=true}
},
{
full_name='softtabstop', abbreviation='sts',
short_desc=N_("number of spaces that <Tab> uses while editing"),
type='number', scope={'buffer'},
- vi_def=true,
- vim=true,
varname='p_sts',
- defaults={if_true={vi=0}}
+ defaults={if_true=0}
},
{
full_name='spell',
short_desc=N_("spell checking"),
type='bool', scope={'window'},
- vi_def=true,
redraw={'current_window'},
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='spellcapcheck', abbreviation='spc',
short_desc=N_("pattern to locate end of a sentence"),
type='string', scope={'buffer'},
- vi_def=true,
alloced=true,
redraw={'current_buffer'},
varname='p_spc',
- defaults={if_true={vi="[.?!]\\_[\\])'\" ]\\+"}}
+ defaults={if_true="[.?!]\\_[\\])'\" ]\\+"}
},
{
full_name='spellfile', abbreviation='spf',
@@ -2587,23 +2289,21 @@ return {
type='string', list='onecomma', scope={'buffer'},
deny_duplicates=true,
secure=true,
- vi_def=true,
alloced=true,
expand=true,
varname='p_spf',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='spelllang', abbreviation='spl',
short_desc=N_("language(s) to do spell checking for"),
type='string', list='onecomma', scope={'buffer'},
deny_duplicates=true,
- vi_def=true,
alloced=true,
expand=true,
redraw={'current_buffer'},
varname='p_spl',
- defaults={if_true={vi="en"}}
+ defaults={if_true="en"}
},
{
full_name='spellsuggest', abbreviation='sps',
@@ -2611,102 +2311,91 @@ return {
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
secure=true,
- vi_def=true,
expand=true,
varname='p_sps',
- defaults={if_true={vi="best"}}
+ defaults={if_true="best"}
},
{
full_name='spelloptions', abbreviation='spo',
type='string', list='onecomma', scope={'buffer'},
deny_duplicates=true,
secure=true,
- vi_def=true,
expand=true,
varname='p_spo',
- defaults={if_true={vi="", vim=""}}
+ defaults={if_true=""}
},
{
full_name='splitbelow', abbreviation='sb',
short_desc=N_("new window from split is below the current one"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_sb',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='splitright', abbreviation='spr',
short_desc=N_("new window is put right of the current one"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_spr',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='startofline', abbreviation='sol',
short_desc=N_("commands move cursor to first non-blank in line"),
type='bool', scope={'global'},
- vi_def=true,
vim=false,
varname='p_sol',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='statusline', abbreviation='stl',
short_desc=N_("custom format for the status line"),
type='string', scope={'global', 'window'},
- vi_def=true,
alloced=true,
modelineexpr=true,
redraw={'statuslines'},
varname='p_stl',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='suffixes', abbreviation='su',
short_desc=N_("suffixes that are ignored with multiple match"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
varname='p_su',
- defaults={if_true={vi=".bak,~,.o,.h,.info,.swp,.obj"}}
+ defaults={if_true=".bak,~,.o,.h,.info,.swp,.obj"}
},
{
full_name='suffixesadd', abbreviation='sua',
short_desc=N_("suffixes added when searching for a file"),
type='string', list='onecomma', scope={'buffer'},
deny_duplicates=true,
- vi_def=true,
alloced=true,
varname='p_sua',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='swapfile', abbreviation='swf',
short_desc=N_("whether to use a swapfile for a buffer"),
type='bool', scope={'buffer'},
- vi_def=true,
redraw={'statuslines'},
varname='p_swf',
- defaults={if_true={vi=true}}
+ defaults={if_true=true}
},
{
full_name='switchbuf', abbreviation='swb',
short_desc=N_("sets behavior when switching to another buffer"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
varname='p_swb',
- defaults={if_true={vi=""}}
+ defaults={if_true="uselast"}
},
{
full_name='synmaxcol', abbreviation='smc',
short_desc=N_("maximum column to find syntax items"),
type='number', scope={'buffer'},
- vi_def=true,
redraw={'current_buffer'},
varname='p_smc',
- defaults={if_true={vi=3000}}
+ defaults={if_true=3000}
},
{
full_name='syntax', abbreviation='syn',
@@ -2714,146 +2403,127 @@ return {
type='string', scope={'buffer'},
noglob=true,
normal_fname_chars=true,
- vi_def=true,
alloced=true,
varname='p_syn',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='tagfunc', abbreviation='tfu',
short_desc=N_("function used to perform tag searches"),
type='string', scope={'buffer'},
- vim=true,
- vi_def=true,
varname='p_tfu',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='tabline', abbreviation='tal',
short_desc=N_("custom format for the console tab pages line"),
type='string', scope={'global'},
- vi_def=true,
modelineexpr=true,
redraw={'all_windows'},
varname='p_tal',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='tabpagemax', abbreviation='tpm',
short_desc=N_("maximum number of tab pages for |-p| and \"tab all\""),
type='number', scope={'global'},
- vim=true,
varname='p_tpm',
- defaults={if_true={vi=10, vim=50}}
+ defaults={if_true=50}
},
{
full_name='tabstop', abbreviation='ts',
short_desc=N_("number of spaces that <Tab> in file uses"),
type='number', scope={'buffer'},
- vi_def=true,
redraw={'current_buffer'},
varname='p_ts',
- defaults={if_true={vi=8}}
+ defaults={if_true=8}
},
{
full_name='tagbsearch', abbreviation='tbs',
short_desc=N_("use binary searching in tags files"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_tbs',
- defaults={if_true={vi=true}}
+ defaults={if_true=true}
},
{
full_name='tagcase', abbreviation='tc',
short_desc=N_("how to handle case when searching in tags files"),
type='string', scope={'global', 'buffer'},
- vim=true,
varname='p_tc',
- defaults={if_true={vi="followic", vim="followic"}}
+ defaults={if_true="followic"}
},
{
full_name='taglength', abbreviation='tl',
short_desc=N_("number of significant characters for a tag"),
type='number', scope={'global'},
- vi_def=true,
varname='p_tl',
- defaults={if_true={vi=0}}
+ defaults={if_true=0}
},
{
full_name='tagrelative', abbreviation='tr',
short_desc=N_("file names in tag file are relative"),
type='bool', scope={'global'},
- vim=true,
varname='p_tr',
- defaults={if_true={vi=false, vim=true}}
+ defaults={if_true=true}
},
{
full_name='tags', abbreviation='tag',
short_desc=N_("list of file names used by the tag command"),
type='string', list='onecomma', scope={'global', 'buffer'},
deny_duplicates=true,
- vi_def=true,
expand=true,
varname='p_tags',
- defaults={if_true={vi="./tags;,tags"}}
+ defaults={if_true="./tags;,tags"}
},
{
full_name='tagstack', abbreviation='tgst',
short_desc=N_("push tags onto the tag stack"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_tgst',
- defaults={if_true={vi=true}}
+ defaults={if_true=true}
},
{
full_name='termbidi', abbreviation='tbidi',
short_desc=N_("terminal takes care of bi-directionality"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_tbidi',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='termencoding', abbreviation='tenc',
short_desc=N_("Terminal encodig"),
type='string', scope={'global'},
- vi_def=true,
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='termguicolors', abbreviation='tgc',
short_desc=N_("Terminal true color support"),
type='bool', scope={'global'},
- vi_def=false,
redraw={'ui_option'},
varname='p_tgc',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='termpastefilter', abbreviation='tpf',
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vim=true,
varname='p_tpf',
- defaults={if_true={vi="", vim="BS,HT,ESC,DEL"}}
+ defaults={if_true="BS,HT,ESC,DEL"}
},
{
full_name='terse',
short_desc=N_("hides notification of search wrap"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_terse',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='textwidth', abbreviation='tw',
short_desc=N_("maximum width of text that is being inserted"),
type='number', scope={'buffer'},
- vi_def=true,
- vim=true,
redraw={'current_buffer'},
varname='p_tw',
- defaults={if_true={vi=0}}
+ defaults={if_true=0}
},
{
full_name='thesaurus', abbreviation='tsr',
@@ -2861,51 +2531,44 @@ return {
type='string', list='onecomma', scope={'global', 'buffer'},
deny_duplicates=true,
normal_dname_chars=true,
- vi_def=true,
expand=true,
varname='p_tsr',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='tildeop', abbreviation='top',
short_desc=N_("tilde command \"~\" behaves like an operator"),
type='bool', scope={'global'},
- vi_def=true,
- vim=true,
varname='p_to',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='timeout', abbreviation='to',
short_desc=N_("time out on mappings and key codes"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_timeout',
- defaults={if_true={vi=true}}
+ defaults={if_true=true}
},
{
full_name='timeoutlen', abbreviation='tm',
short_desc=N_("time out time in milliseconds"),
type='number', scope={'global'},
- vi_def=true,
varname='p_tm',
- defaults={if_true={vi=1000}}
+ defaults={if_true=1000}
},
{
full_name='title',
short_desc=N_("Vim set the title of the window"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_title',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='titlelen',
short_desc=N_("of 'columns' used for window title"),
type='number', scope={'global'},
- vi_def=true,
varname='p_titlelen',
- defaults={if_true={vi=85}}
+ defaults={if_true=85}
},
{
full_name='titleold',
@@ -2913,46 +2576,40 @@ return {
type='string', scope={'global'},
secure=true,
no_mkrc=true,
- vi_def=true,
varname='p_titleold',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='titlestring',
short_desc=N_("to use for the Vim window title"),
type='string', scope={'global'},
- vi_def=true,
modelineexpr=true,
varname='p_titlestring',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='ttimeout',
short_desc=N_("out on mappings"),
type='bool', scope={'global'},
- vi_def=true,
- vim=true,
redraw={'ui_option'},
varname='p_ttimeout',
- defaults={if_true={vi=true}}
+ defaults={if_true=true}
},
{
full_name='ttimeoutlen', abbreviation='ttm',
short_desc=N_("time out time for key codes in milliseconds"),
type='number', scope={'global'},
- vi_def=true,
redraw={'ui_option'},
varname='p_ttm',
- defaults={if_true={vi=50}}
+ defaults={if_true=50}
},
{
full_name='ttyfast', abbreviation='tf',
short_desc=N_("No description"),
type='bool', scope={'global'},
no_mkrc=true,
- vi_def=true,
varname='p_force_on',
- defaults={if_true={vi=true}}
+ defaults={if_true=true}
},
{
full_name='undodir', abbreviation='udir',
@@ -2960,105 +2617,92 @@ return {
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
secure=true,
- vi_def=true,
expand='nodefault',
varname='p_udir',
- defaults={if_true={vi=''}}
+ defaults={if_true=''}
},
{
full_name='undofile', abbreviation='udf',
short_desc=N_("save undo information in a file"),
type='bool', scope={'buffer'},
- vi_def=true,
- vim=true,
varname='p_udf',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='undolevels', abbreviation='ul',
short_desc=N_("maximum number of changes that can be undone"),
type='number', scope={'global', 'buffer'},
- vi_def=true,
varname='p_ul',
- defaults={if_true={vi=1000}}
+ defaults={if_true=1000}
},
{
full_name='undoreload', abbreviation='ur',
short_desc=N_("max nr of lines to save for undo on a buffer reload"),
type='number', scope={'global'},
- vi_def=true,
varname='p_ur',
- defaults={if_true={vi=10000}}
+ defaults={if_true=10000}
},
{
full_name='updatecount', abbreviation='uc',
short_desc=N_("after this many characters flush swap file"),
type='number', scope={'global'},
- vi_def=true,
varname='p_uc',
- defaults={if_true={vi=200}}
+ defaults={if_true=200}
},
{
full_name='updatetime', abbreviation='ut',
short_desc=N_("after this many milliseconds flush swap file"),
type='number', scope={'global'},
- vi_def=true,
varname='p_ut',
- defaults={if_true={vi=4000}}
+ defaults={if_true=4000}
},
{
full_name='varsofttabstop', abbreviation='vsts',
short_desc=N_("list of numbers of spaces that <Tab> uses while editing"),
type='string', list='comma', scope={'buffer'},
- vi_def=true,
varname='p_vsts',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='vartabstop', abbreviation='vts',
short_desc=N_("list of numbers of spaces that <Tab> in file uses"),
type='string', list='comma', scope={'buffer'},
- vi_def=true,
varname='p_vts',
redraw={'current_buffer'},
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='verbose', abbreviation='vbs',
short_desc=N_("give informative messages"),
type='number', scope={'global'},
- vi_def=true,
varname='p_verbose',
- defaults={if_true={vi=0}}
+ defaults={if_true=0}
},
{
full_name='verbosefile', abbreviation='vfile',
short_desc=N_("file to write messages in"),
type='string', scope={'global'},
secure=true,
- vi_def=true,
expand=true,
varname='p_vfile',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='viewdir', abbreviation='vdir',
short_desc=N_("directory where to store files with :mkview"),
type='string', scope={'global'},
secure=true,
- vi_def=true,
expand='nodefault',
varname='p_vdir',
- defaults={if_true={vi=''}}
+ defaults={if_true=''}
},
{
full_name='viewoptions', abbreviation='vop',
short_desc=N_("specifies what to save for :mkview"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
varname='p_vop',
- defaults={if_true={vi="folds,options,cursor,curdir"}}
+ defaults={if_true="folds,cursor,curdir"}
},
{
-- Alias for "shada".
@@ -3077,232 +2721,202 @@ return {
short_desc=N_("when to use virtual editing"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
- vim=true,
redraw={'curswant'},
varname='p_ve',
- defaults={if_true={vi="", vim=""}}
+ defaults={if_true=""}
},
{
full_name='visualbell', abbreviation='vb',
short_desc=N_("use visual bell instead of beeping"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_vb',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='warn',
short_desc=N_("for shell command when buffer was changed"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_warn',
- defaults={if_true={vi=true}}
+ defaults={if_true=true}
},
{
full_name='whichwrap', abbreviation='ww',
short_desc=N_("allow specified keys to cross line boundaries"),
type='string', list='flagscomma', scope={'global'},
- vim=true,
varname='p_ww',
- defaults={if_true={vi="", vim="b,s"}}
+ defaults={if_true="b,s"}
},
{
full_name='wildchar', abbreviation='wc',
short_desc=N_("command-line character for wildcard expansion"),
type='number', scope={'global'},
- vim=true,
varname='p_wc',
- defaults={if_true={vi=imacros('Ctrl_E'), vim=imacros('TAB')}}
+ defaults={if_true=imacros('TAB')}
},
{
full_name='wildcharm', abbreviation='wcm',
short_desc=N_("like 'wildchar' but also works when mapped"),
type='number', scope={'global'},
- vi_def=true,
varname='p_wcm',
- defaults={if_true={vi=0}}
+ defaults={if_true=0}
},
{
full_name='wildignore', abbreviation='wig',
short_desc=N_("files matching these patterns are not completed"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
varname='p_wig',
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='wildignorecase', abbreviation='wic',
short_desc=N_("ignore case when completing file names"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_wic',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='wildmenu', abbreviation='wmnu',
short_desc=N_("use menu for command line completion"),
type='bool', scope={'global'},
- vim=true,
varname='p_wmnu',
- defaults={if_true={vi=false, vim=true}}
+ defaults={if_true=true}
},
{
full_name='wildmode', abbreviation='wim',
short_desc=N_("mode for 'wildchar' command-line expansion"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=false,
- vim=true,
varname='p_wim',
- defaults={if_true={vi="", vim="full"}}
+ defaults={if_true="full"}
},
{
full_name='wildoptions', abbreviation='wop',
short_desc=N_("specifies how command line completion is done"),
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vim=true,
varname='p_wop',
- defaults={if_true={vi='', vim='pum,tagfile'}}
+ defaults={if_true='pum,tagfile'}
},
{
full_name='winaltkeys', abbreviation='wak',
short_desc=N_("when the windows system handles ALT keys"),
type='string', scope={'global'},
- vi_def=true,
varname='p_wak',
- defaults={if_true={vi="menu"}}
+ defaults={if_true="menu"}
},
{
full_name='winblend', abbreviation='winbl',
short_desc=N_("Controls transparency level for floating windows"),
type='number', scope={'window'},
- vi_def=true,
redraw={'current_window'},
- defaults={if_true={vi=0}}
+ defaults={if_true=0}
},
{
full_name='winhighlight', abbreviation='winhl',
short_desc=N_("Setup window-local highlights");
type='string', scope={'window'},
- vi_def=true,
alloced=true,
redraw={'current_window'},
- defaults={if_true={vi=""}}
+ defaults={if_true=""}
},
{
full_name='window', abbreviation='wi',
short_desc=N_("nr of lines to scroll for CTRL-F and CTRL-B"),
type='number', scope={'global'},
- vi_def=true,
varname='p_window',
- defaults={if_true={vi=0}}
+ defaults={if_true=0}
},
{
full_name='winheight', abbreviation='wh',
short_desc=N_("minimum number of lines for the current window"),
type='number', scope={'global'},
- vi_def=true,
varname='p_wh',
- defaults={if_true={vi=1}}
+ defaults={if_true=1}
},
{
full_name='winfixheight', abbreviation='wfh',
short_desc=N_("keep window height when opening/closing windows"),
type='bool', scope={'window'},
- vi_def=true,
redraw={'statuslines'},
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='winfixwidth', abbreviation='wfw',
short_desc=N_("keep window width when opening/closing windows"),
type='bool', scope={'window'},
- vi_def=true,
redraw={'statuslines'},
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='winminheight', abbreviation='wmh',
short_desc=N_("minimum number of lines for any window"),
type='number', scope={'global'},
- vi_def=true,
varname='p_wmh',
- defaults={if_true={vi=1}}
+ defaults={if_true=1}
},
{
full_name='winminwidth', abbreviation='wmw',
short_desc=N_("minimal number of columns for any window"),
type='number', scope={'global'},
- vi_def=true,
varname='p_wmw',
- defaults={if_true={vi=1}}
+ defaults={if_true=1}
},
{
full_name='winwidth', abbreviation='wiw',
short_desc=N_("minimal number of columns for current window"),
type='number', scope={'global'},
- vi_def=true,
varname='p_wiw',
- defaults={if_true={vi=20}}
+ defaults={if_true=20}
},
{
full_name='wrap',
short_desc=N_("lines wrap and continue on the next line"),
type='bool', scope={'window'},
- vi_def=true,
redraw={'current_window'},
- defaults={if_true={vi=true}}
+ defaults={if_true=true}
},
{
full_name='wrapmargin', abbreviation='wm',
short_desc=N_("chars from the right where wrapping starts"),
type='number', scope={'buffer'},
- vi_def=true,
varname='p_wm',
- defaults={if_true={vi=0}}
+ defaults={if_true=0}
},
{
full_name='wrapscan', abbreviation='ws',
short_desc=N_("searches wrap around the end of the file"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_ws',
- defaults={if_true={vi=true}}
+ defaults={if_true=true}
},
{
full_name='write',
short_desc=N_("to a file is allowed"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_write',
- defaults={if_true={vi=true}}
+ defaults={if_true=true}
},
{
full_name='writeany', abbreviation='wa',
short_desc=N_("write to file with no need for \"!\" override"),
type='bool', scope={'global'},
- vi_def=true,
varname='p_wa',
- defaults={if_true={vi=false}}
+ defaults={if_true=false}
},
{
full_name='writebackup', abbreviation='wb',
short_desc=N_("make a backup before overwriting a file"),
type='bool', scope={'global'},
- vi_def=true,
- vim=true,
varname='p_wb',
- defaults={if_true={vi=true}}
+ defaults={if_true=true}
},
{
full_name='writedelay', abbreviation='wd',
short_desc=N_("delay this many msec for each char (for debug)"),
type='number', scope={'global'},
- vi_def=true,
varname='p_wd',
- defaults={if_true={vi=0}}
+ defaults={if_true=0}
},
}
}
diff --git a/src/nvim/os/dl.c b/src/nvim/os/dl.c
index 8483d316f3..b2e3994d10 100644
--- a/src/nvim/os/dl.c
+++ b/src/nvim/os/dl.c
@@ -7,10 +7,10 @@
#include <stdint.h>
#include <uv.h>
-#include "nvim/os/dl.h"
-#include "nvim/os/os.h"
#include "nvim/memory.h"
#include "nvim/message.h"
+#include "nvim/os/dl.h"
+#include "nvim/os/os.h"
/// possible function prototypes that can be called by os_libcall()
/// int -> int
@@ -38,12 +38,8 @@ typedef int (*int_int_fn)(int i);
/// not NULL. NULL when using `int_out`.
/// @param[out] int_out the output integer param
/// @return true on success, false on failure
-bool os_libcall(const char *libname,
- const char *funcname,
- const char *argv,
- int argi,
- char **str_out,
- int *int_out)
+bool os_libcall(const char *libname, const char *funcname, const char *argv, int argi,
+ char **str_out, int *int_out)
{
if (!libname || !funcname) {
return false;
@@ -53,17 +49,17 @@ bool os_libcall(const char *libname,
// open the dynamic loadable library
if (uv_dlopen(libname, &lib)) {
- EMSG2(_("dlerror = \"%s\""), uv_dlerror(&lib));
- uv_dlclose(&lib);
- return false;
+ EMSG2(_("dlerror = \"%s\""), uv_dlerror(&lib));
+ uv_dlclose(&lib);
+ return false;
}
// find and load the requested function in the library
gen_fn fn;
- if (uv_dlsym(&lib, funcname, (void **) &fn)) {
- EMSG2(_("dlerror = \"%s\""), uv_dlerror(&lib));
- uv_dlclose(&lib);
- return false;
+ if (uv_dlsym(&lib, funcname, (void **)&fn)) {
+ EMSG2(_("dlerror = \"%s\""), uv_dlerror(&lib));
+ uv_dlclose(&lib);
+ return false;
}
// call the library and save the result
@@ -71,17 +67,17 @@ bool os_libcall(const char *libname,
// exceptions. jmp's on Unix seem to interact trickily with signals as
// well. So for now we only support those libraries that are well-behaved.
if (str_out) {
- str_str_fn sfn = (str_str_fn) fn;
- int_str_fn ifn = (int_str_fn) fn;
+ str_str_fn sfn = (str_str_fn)fn;
+ int_str_fn ifn = (int_str_fn)fn;
const char *res = argv ? sfn(argv) : ifn(argi);
// assume that ptr values of NULL, 1 or -1 are illegal
- *str_out = (res && (intptr_t) res != 1 && (intptr_t) res != -1)
+ *str_out = (res && (intptr_t)res != 1 && (intptr_t)res != -1)
? xstrdup(res) : NULL;
} else {
- str_int_fn sfn = (str_int_fn) fn;
- int_int_fn ifn = (int_int_fn) fn;
+ str_int_fn sfn = (str_int_fn)fn;
+ int_int_fn ifn = (int_int_fn)fn;
*int_out = argv ? sfn(argv) : ifn(argi);
}
diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c
index 008f5ef63b..0f363ecfc3 100644
--- a/src/nvim/os/env.c
+++ b/src/nvim/os/env.c
@@ -6,41 +6,40 @@
#include <assert.h>
#include <uv.h>
-#include "nvim/vim.h"
#include "nvim/ascii.h"
#include "nvim/charset.h"
+#include "nvim/eval.h"
+#include "nvim/ex_getln.h"
#include "nvim/fileio.h"
-#include "nvim/os/os.h"
+#include "nvim/macros.h"
+#include "nvim/map.h"
#include "nvim/memory.h"
#include "nvim/message.h"
+#include "nvim/os/os.h"
#include "nvim/path.h"
-#include "nvim/macros.h"
#include "nvim/strings.h"
-#include "nvim/eval.h"
-#include "nvim/ex_getln.h"
#include "nvim/version.h"
-#include "nvim/map.h"
+#include "nvim/vim.h"
#ifdef WIN32
-#include "nvim/mbyte.h" // for utf8_to_utf16, utf16_to_utf8
+# include "nvim/mbyte.h" // for utf8_to_utf16, utf16_to_utf8
#endif
#ifdef HAVE__NSGETENVIRON
-#include <crt_externs.h>
+# include <crt_externs.h>
#endif
#ifdef HAVE_SYS_UTSNAME_H
-#include <sys/utsname.h>
+# include <sys/utsname.h>
#endif
// Because `uv_os_getenv` requires allocating, we must manage a map to maintain
// the behavior of `os_getenv`.
-static PMap(cstr_t) *envmap;
+static PMap(cstr_t) envmap = MAP_INIT;
static uv_mutex_t mutex;
void env_init(void)
{
- envmap = pmap_new(cstr_t)();
uv_mutex_init(&mutex);
}
@@ -66,8 +65,8 @@ const char *os_getenv(const char *name)
}
uv_mutex_lock(&mutex);
int r = 0;
- if (pmap_has(cstr_t)(envmap, name)
- && !!(e = (char *)pmap_get(cstr_t)(envmap, name))) {
+ if (pmap_has(cstr_t)(&envmap, name)
+ && !!(e = (char *)pmap_get(cstr_t)(&envmap, name))) {
if (e[0] != '\0') {
// Found non-empty cached env var.
// NOTE: This risks incoherence if an in-process library changes the
@@ -75,7 +74,7 @@ const char *os_getenv(const char *name)
// that turns out to be a problem, we can just remove this codepath.
goto end;
}
- pmap_del2(envmap, name);
+ pmap_del2(&envmap, name);
}
e = xmalloc(size);
r = uv_os_getenv(name, e, &size);
@@ -88,7 +87,7 @@ const char *os_getenv(const char *name)
e = NULL;
goto end;
}
- pmap_put(cstr_t)(envmap, xstrdup(name), e);
+ pmap_put(cstr_t)(&envmap, xstrdup(name), e);
end:
// Must do this before ELOG, log.c may call os_setenv.
uv_mutex_unlock(&mutex);
@@ -157,7 +156,7 @@ int os_setenv(const char *name, const char *value, int overwrite)
assert(r != UV_EINVAL);
// Destroy the old map item. Do this AFTER uv_os_setenv(), because `value`
// could be a previous os_getenv() result.
- pmap_del2(envmap, name);
+ pmap_del2(&envmap, name);
// Must do this before ELOG, log.c may call os_setenv.
uv_mutex_unlock(&mutex);
if (r != 0) {
@@ -174,7 +173,7 @@ int os_unsetenv(const char *name)
return -1;
}
uv_mutex_lock(&mutex);
- pmap_del2(envmap, name);
+ pmap_del2(&envmap, name);
int r = uv_os_unsetenv(name);
// Must do this before ELOG, log.c may call os_setenv.
uv_mutex_unlock(&mutex);
@@ -207,7 +206,7 @@ size_t os_get_fullenv_size(void)
# if defined(HAVE__NSGETENVIRON)
char **environ = *_NSGetEnviron();
# else
- extern char **environ;
+ extern char **environ;
# endif
while (environ[len] != NULL) {
@@ -220,7 +219,9 @@ size_t os_get_fullenv_size(void)
void os_free_fullenv(char **env)
{
- if (!env) { return; }
+ if (!env) {
+ return;
+ }
for (char **it = env; *it; it++) {
XFREE_CLEAR(*it);
}
@@ -263,7 +264,7 @@ void os_copy_fullenv(char **env, size_t env_size)
# if defined(HAVE__NSGETENVIRON)
char **environ = *_NSGetEnviron();
# else
- extern char **environ;
+ extern char **environ;
# endif
for (size_t i = 0; i < env_size && environ[i] != NULL; i++) {
@@ -323,7 +324,7 @@ char *os_getenvname_at_index(size_t index)
# if defined(HAVE__NSGETENVIRON)
char **environ = *_NSGetEnviron();
# else
- extern char **environ;
+ extern char **environ;
# endif
// check if index is inside the environ array
@@ -567,16 +568,12 @@ void expand_env(char_u *src, char_u *dst, int dstlen)
/// @param esc Escape spaces in expanded variables
/// @param one `srcp` is a single filename
/// @param prefix Start again after this (can be NULL)
-void expand_env_esc(char_u *restrict srcp,
- char_u *restrict dst,
- int dstlen,
- bool esc,
- bool one,
+void expand_env_esc(char_u *restrict srcp, char_u *restrict dst, int dstlen, bool esc, bool one,
char_u *prefix)
FUNC_ATTR_NONNULL_ARG(1, 2)
{
- char_u *tail;
- char_u *var;
+ char_u *tail;
+ char_u *var;
bool copy_char;
bool mustfree; // var was allocated, need to free it later
bool at_start = true; // at start of a name
@@ -622,7 +619,7 @@ void expand_env_esc(char_u *restrict srcp,
while (c-- > 0 && *tail != NUL && *tail != '}') {
*var++ = *tail++;
}
- } else // NOLINT
+ } else // NOLINT
#endif
{
while (c-- > 0 && *tail != NUL && vim_isIDc(*tail)) {
@@ -643,7 +640,7 @@ void expand_env_esc(char_u *restrict srcp,
var = (char_u *)vim_getenv((char *)dst);
mustfree = true;
#if defined(UNIX)
- }
+ }
#endif
} else if (src[1] == NUL // home directory
|| vim_ispathsep(src[1])
@@ -674,7 +671,7 @@ void expand_env_esc(char_u *restrict srcp,
ExpandInit(&xpc);
xpc.xp_context = EXPAND_FILES;
var = ExpandOne(&xpc, dst, NULL,
- WILD_ADD_SLASH|WILD_SILENT, WILD_EXPAND_FREE);
+ WILD_ADD_SLASH|WILD_SILENT, WILD_EXPAND_FREE);
mustfree = true;
}
#else
@@ -688,7 +685,7 @@ void expand_env_esc(char_u *restrict srcp,
// If 'shellslash' is set change backslashes to forward slashes.
// Can't use slash_adjust(), p_ssl may be set temporarily.
if (p_ssl && var != NULL && vim_strchr(var, '\\') != NULL) {
- char_u *p = vim_strsave(var);
+ char_u *p = vim_strsave(var);
if (mustfree) {
xfree(var);
@@ -702,7 +699,7 @@ void expand_env_esc(char_u *restrict srcp,
// If "var" contains white space, escape it with a backslash.
// Required for ":e ~/tt" when $HOME includes a space.
if (esc && var != NULL && vim_strpbrk(var, (char_u *)" \t") != NULL) {
- char_u *p = vim_strsave_escaped(var, (char_u *)" \t");
+ char_u *p = vim_strsave_escaped(var, (char_u *)" \t");
if (mustfree) {
xfree(var);
@@ -722,8 +719,9 @@ void expand_env_esc(char_u *restrict srcp,
#if defined(BACKSLASH_IN_FILENAME)
&& dst[-1] != ':'
#endif
- && vim_ispathsep(*tail))
+ && vim_ispathsep(*tail)) {
++tail;
+ }
dst += c;
src = tail;
copy_char = false;
@@ -827,14 +825,11 @@ static char *remove_tail(char *path, char *pend, char *dirname)
/// @param[out] len Location where current directory length should be saved.
///
/// @return Next iter argument value or NULL when iteration should stop.
-const void *vim_env_iter(const char delim,
- const char *const val,
- const void *const iter,
- const char **const dir,
- size_t *const len)
+const void *vim_env_iter(const char delim, const char *const val, const void *const iter,
+ const char **const dir, size_t *const len)
FUNC_ATTR_NONNULL_ARG(2, 4, 5) FUNC_ATTR_WARN_UNUSED_RESULT
{
- const char *varval = (const char *) iter;
+ const char *varval = (const char *)iter;
if (varval == NULL) {
varval = val;
}
@@ -844,7 +839,7 @@ const void *vim_env_iter(const char delim,
*len = strlen(varval);
return NULL;
} else {
- *len = (size_t) (dirend - varval);
+ *len = (size_t)(dirend - varval);
return dirend + 1;
}
}
@@ -862,14 +857,11 @@ const void *vim_env_iter(const char delim,
/// @param[out] len Location where current directory length should be saved.
///
/// @return Next iter argument value or NULL when iteration should stop.
-const void *vim_env_iter_rev(const char delim,
- const char *const val,
- const void *const iter,
- const char **const dir,
- size_t *const len)
+const void *vim_env_iter_rev(const char delim, const char *const val, const void *const iter,
+ const char **const dir, size_t *const len)
FUNC_ATTR_NONNULL_ARG(2, 4, 5) FUNC_ATTR_WARN_UNUSED_RESULT
{
- const char *varend = (const char *) iter;
+ const char *varend = (const char *)iter;
if (varend == NULL) {
varend = val + strlen(val) - 1;
}
@@ -881,7 +873,7 @@ const void *vim_env_iter_rev(const char delim,
return NULL;
} else {
*dir = colon + 1;
- *len = (size_t) (varend - colon);
+ *len = (size_t)(varend - colon);
return colon - 1;
}
}
@@ -956,10 +948,9 @@ char *vim_getenv(const char *name)
// Find runtime path relative to the nvim binary: ../share/nvim/runtime
if (vim_path == NULL) {
vim_get_prefix_from_exepath(exe_name);
- if (append_path(
- exe_name,
- "share" _PATHSEPSTR "nvim" _PATHSEPSTR "runtime" _PATHSEPSTR,
- MAXPATHL) == OK) {
+ if (append_path(exe_name,
+ "share" _PATHSEPSTR "nvim" _PATHSEPSTR "runtime" _PATHSEPSTR,
+ MAXPATHL) == OK) {
vim_path = exe_name; // -V507
}
}
@@ -1044,8 +1035,8 @@ char *vim_getenv(const char *name)
/// a list of them.
///
/// @return length of the string put into dst, does not include NUL byte.
-size_t home_replace(const buf_T *const buf, const char_u *src,
- char_u *const dst, size_t dstlen, const bool one)
+size_t home_replace(const buf_T *const buf, const char_u *src, char_u *const dst, size_t dstlen,
+ const bool one)
FUNC_ATTR_NONNULL_ARG(3)
{
size_t dirlen = 0;
@@ -1155,7 +1146,7 @@ size_t home_replace(const buf_T *const buf, const char_u *src,
/// Like home_replace, store the replaced string in allocated memory.
/// @param buf When not NULL, check for help files
/// @param src Input file name
-char_u * home_replace_save(buf_T *buf, char_u *src) FUNC_ATTR_NONNULL_RET
+char_u *home_replace_save(buf_T *buf, char_u *src) FUNC_ATTR_NONNULL_RET
{
size_t len = 3; // space for "~/" and trailing NUL
if (src != NULL) { // just in case
@@ -1170,7 +1161,7 @@ char_u * home_replace_save(buf_T *buf, char_u *src) FUNC_ATTR_NONNULL_RET
/// Function given to ExpandGeneric() to obtain an environment variable name.
char_u *get_env_name(expand_T *xp, int idx)
{
-# define ENVNAMELEN 100
+#define ENVNAMELEN 100
// this static buffer is needed to avoid a memory leak in ExpandGeneric
static char_u name[ENVNAMELEN];
assert(idx >= 0);
diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c
index bb68326a03..1ae6ca4244 100644
--- a/src/nvim/os/fileio.c
+++ b/src/nvim/os/fileio.c
@@ -4,13 +4,13 @@
/// @file fileio.c
///
/// Buffered reading/writing to a file. Unlike fileio.c this is not dealing with
-/// Nvim stuctures for buffer, with autocommands, etc: just fopen/fread/fwrite
+/// Nvim structures for buffer, with autocommands, etc: just fopen/fread/fwrite
/// replacement.
#include <assert.h>
-#include <stddef.h>
-#include <stdbool.h>
#include <fcntl.h>
+#include <stdbool.h>
+#include <stddef.h>
#include "auto/config.h"
@@ -20,13 +20,13 @@
#include <uv.h>
-#include "nvim/os/fileio.h"
-#include "nvim/memory.h"
-#include "nvim/os/os.h"
#include "nvim/globals.h"
-#include "nvim/rbuffer.h"
#include "nvim/macros.h"
+#include "nvim/memory.h"
#include "nvim/message.h"
+#include "nvim/os/fileio.h"
+#include "nvim/os/os.h"
+#include "nvim/rbuffer.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/fileio.c.generated.h"
@@ -44,8 +44,8 @@
/// does not have kFileCreate\*).
///
/// @return Error code, or 0 on success. @see os_strerror()
-int file_open(FileDescriptor *const ret_fp, const char *const fname,
- const int flags, const int mode)
+int file_open(FileDescriptor *const ret_fp, const char *const fname, const int flags,
+ const int mode)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
int os_open_flags = 0;
@@ -99,8 +99,7 @@ int file_open(FileDescriptor *const ret_fp, const char *const fname,
/// FILE_WRITE_ONLY or FILE_READ_ONLY is required.
///
/// @return Error code (@see os_strerror()) or 0. Currently always returns 0.
-int file_open_fd(FileDescriptor *const ret_fp, const int fd,
- const int flags)
+int file_open_fd(FileDescriptor *const ret_fp, const int fd, const int flags)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
ret_fp->wr = !!(flags & (kFileCreate
@@ -131,8 +130,8 @@ int file_open_fd(FileDescriptor *const ret_fp, const int fd,
/// does not have kFileCreate\*).
///
/// @return [allocated] Opened file or NULL in case of error.
-FileDescriptor *file_open_new(int *const error, const char *const fname,
- const int flags, const int mode)
+FileDescriptor *file_open_new(int *const error, const char *const fname, const int flags,
+ const int mode)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
FileDescriptor *const fp = xmalloc(sizeof(*fp));
@@ -152,8 +151,7 @@ FileDescriptor *file_open_new(int *const error, const char *const fname,
/// does not have FILE_CREATE\*).
///
/// @return [allocated] Opened file or NULL in case of error.
-FileDescriptor *file_open_fd_new(int *const error, const int fd,
- const int flags)
+FileDescriptor *file_open_fd_new(int *const error, const int fd, const int flags)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT
{
FileDescriptor *const fp = xmalloc(sizeof(*fp));
@@ -277,8 +275,7 @@ static void file_rb_write_full_cb(RBuffer *const rv, FileDescriptor *const fp)
/// bytes.
///
/// @return error_code (< 0) or number of bytes read.
-ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf,
- const size_t size)
+ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf, const size_t size)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
assert(!fp->wr);
@@ -362,8 +359,7 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf,
/// @param[in] size Amount of bytes to write.
///
/// @return Number of bytes written or libuv error code (< 0).
-ptrdiff_t file_write(FileDescriptor *const fp, const char *const buf,
- const size_t size)
+ptrdiff_t file_write(FileDescriptor *const fp, const char *const buf, const size_t size)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1)
{
assert(fp->wr);
@@ -392,8 +388,8 @@ ptrdiff_t file_skip(FileDescriptor *const fp, const size_t size)
assert(!fp->wr);
size_t read_bytes = 0;
do {
- const ptrdiff_t new_read_bytes = file_read(
- fp, skipbuf, MIN(size - read_bytes, sizeof(skipbuf)));
+ const ptrdiff_t new_read_bytes =
+ file_read(fp, skipbuf, MIN(size - read_bytes, sizeof(skipbuf)));
if (new_read_bytes < 0) {
return new_read_bytes;
} else if (new_read_bytes == 0) {
diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c
index d0fa74a77f..bbf70a4830 100644
--- a/src/nvim/os/fs.c
+++ b/src/nvim/os/fs.c
@@ -2,12 +2,12 @@
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
// fs.c -- filesystem access
-#include <stdbool.h>
-#include <stddef.h>
#include <assert.h>
-#include <limits.h>
-#include <fcntl.h>
#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stddef.h>
#include "auto/config.h"
@@ -17,19 +17,19 @@
#include <uv.h>
-#include "nvim/os/os.h"
-#include "nvim/os/os_defs.h"
#include "nvim/ascii.h"
+#include "nvim/assert.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/assert.h"
#include "nvim/misc1.h"
#include "nvim/option.h"
+#include "nvim/os/os.h"
+#include "nvim/os/os_defs.h"
#include "nvim/path.h"
#include "nvim/strings.h"
#ifdef WIN32
-#include "nvim/mbyte.h" // for utf8_to_utf16, utf16_to_utf8
+# include "nvim/mbyte.h" // for utf8_to_utf16, utf16_to_utf8
#endif
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -37,18 +37,18 @@
#endif
#define RUN_UV_FS_FUNC(ret, func, ...) \
- do { \
- bool did_try_to_free = false; \
+ do { \
+ bool did_try_to_free = false; \
uv_call_start: {} \
- uv_fs_t req; \
- ret = func(&fs_loop, &req, __VA_ARGS__); \
- uv_fs_req_cleanup(&req); \
- if (ret == UV_ENOMEM && !did_try_to_free) { \
- try_to_free_memory(); \
- did_try_to_free = true; \
- goto uv_call_start; \
- } \
- } while (0)
+ uv_fs_t req; \
+ ret = func(&fs_loop, &req, __VA_ARGS__); \
+ uv_fs_req_cleanup(&req); \
+ if (ret == UV_ENOMEM && !did_try_to_free) { \
+ try_to_free_memory(); \
+ did_try_to_free = true; \
+ goto uv_call_start; \
+ } \
+ } while (0)
// Many fs functions from libuv return that value on success.
static const int kLibuvSuccess = 0;
@@ -199,16 +199,16 @@ int os_nodetype(const char *name)
}
switch (guess) {
- case UV_TTY: // FILE_TYPE_CHAR
- return NODE_WRITABLE;
- case UV_FILE: // FILE_TYPE_DISK
- return NODE_NORMAL;
- case UV_NAMED_PIPE: // not handled explicitly in Vim os_win32.c
- case UV_UDP: // unix only
- case UV_TCP: // unix only
- case UV_UNKNOWN_HANDLE:
- default:
- return NODE_OTHER; // Vim os_win32.c default
+ case UV_TTY: // FILE_TYPE_CHAR
+ return NODE_WRITABLE;
+ case UV_FILE: // FILE_TYPE_DISK
+ return NODE_NORMAL;
+ case UV_NAMED_PIPE: // not handled explicitly in Vim os_win32.c
+ case UV_UDP: // unix only
+ case UV_TCP: // unix only
+ case UV_UNKNOWN_HANDLE:
+ default:
+ return NODE_OTHER; // Vim os_win32.c default
}
#endif
}
@@ -326,7 +326,7 @@ static bool is_executable_ext(const char *name, char **abspath)
sizeof(os_buf) - (size_t)(buf_end - os_buf), ENV_SEPSTR);
if (ext_len != 0) {
bool in_pathext = nameext_len == ext_len
- && 0 == mb_strnicmp((char_u *)nameext, (char_u *)ext, ext_len);
+ && 0 == mb_strnicmp((char_u *)nameext, (char_u *)ext, ext_len);
if (((in_pathext || is_unix_shell) && is_executable(name, abspath))
|| is_executable(os_buf, abspath)) {
@@ -436,17 +436,17 @@ FILE *os_fopen(const char *path, const char *flags)
// Per table in fopen(3) manpage.
if (flags[1] == '\0' || flags[1] == 'b') {
switch (flags[0]) {
- case 'r':
- iflags = O_RDONLY;
- break;
- case 'w':
- iflags = O_WRONLY | O_CREAT | O_TRUNC;
- break;
- case 'a':
- iflags = O_WRONLY | O_CREAT | O_APPEND;
- break;
- default:
- abort();
+ case 'r':
+ iflags = O_RDONLY;
+ break;
+ case 'w':
+ iflags = O_WRONLY | O_CREAT | O_TRUNC;
+ break;
+ case 'a':
+ iflags = O_WRONLY | O_CREAT | O_APPEND;
+ break;
+ default:
+ abort();
}
#ifdef WIN32
if (flags[1] == 'b') {
@@ -458,17 +458,17 @@ FILE *os_fopen(const char *path, const char *flags)
// char 1 is always '+' ('b' is handled above).
assert(flags[1] == '+');
switch (flags[0]) {
- case 'r':
- iflags = O_RDWR;
- break;
- case 'w':
- iflags = O_RDWR | O_CREAT | O_TRUNC;
- break;
- case 'a':
- iflags = O_RDWR | O_CREAT | O_APPEND;
- break;
- default:
- abort();
+ case 'r':
+ iflags = O_RDWR;
+ break;
+ case 'w':
+ iflags = O_RDWR | O_CREAT | O_TRUNC;
+ break;
+ case 'a':
+ iflags = O_RDWR | O_CREAT | O_APPEND;
+ break;
+ default:
+ abort();
}
}
// Per fopen(3) manpage: default to 0666, it will be umask-adjusted.
@@ -553,8 +553,8 @@ os_dup_dup:
/// @param[in] non_blocking Do not restart syscall if EAGAIN was encountered.
///
/// @return Number of bytes read or libuv error code (< 0).
-ptrdiff_t os_read(const int fd, bool *const ret_eof, char *const ret_buf,
- const size_t size, const bool non_blocking)
+ptrdiff_t os_read(const int fd, bool *const ret_eof, char *const ret_buf, const size_t size,
+ const bool non_blocking)
FUNC_ATTR_WARN_UNUSED_RESULT
{
*ret_eof = false;
@@ -609,8 +609,8 @@ ptrdiff_t os_read(const int fd, bool *const ret_eof, char *const ret_buf,
/// @param[in] non_blocking Do not restart syscall if EAGAIN was encountered.
///
/// @return Number of bytes read or libuv error code (< 0).
-ptrdiff_t os_readv(const int fd, bool *const ret_eof, struct iovec *iov,
- size_t iov_size, const bool non_blocking)
+ptrdiff_t os_readv(const int fd, bool *const ret_eof, struct iovec *iov, size_t iov_size,
+ const bool non_blocking)
FUNC_ATTR_NONNULL_ALL
{
*ret_eof = false;
@@ -668,8 +668,7 @@ ptrdiff_t os_readv(const int fd, bool *const ret_eof, struct iovec *iov,
/// @param[in] non_blocking Do not restart syscall if EAGAIN was encountered.
///
/// @return Number of bytes written or libuv error code (< 0).
-ptrdiff_t os_write(const int fd, const char *const buf, const size_t size,
- const bool non_blocking)
+ptrdiff_t os_write(const int fd, const char *const buf, const size_t size, const bool non_blocking)
FUNC_ATTR_WARN_UNUSED_RESULT
{
if (buf == NULL) {
@@ -884,8 +883,7 @@ int os_mkdir(const char *path, int32_t mode)
/// of the higher level directories.
///
/// @return `0` for success, libuv error code for failure.
-int os_mkdir_recurse(const char *const dir, int32_t mode,
- char **const failed_dir)
+int os_mkdir_recurse(const char *const dir, int32_t mode, char **const failed_dir)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
// Get end of directory name in "dir".
@@ -1058,8 +1056,7 @@ bool os_fileinfo_fd(int file_descriptor, FileInfo *file_info)
/// Compare the inodes of two FileInfos
///
/// @return `true` if the two FileInfos represent the same file.
-bool os_fileinfo_id_equal(const FileInfo *file_info_1,
- const FileInfo *file_info_2)
+bool os_fileinfo_id_equal(const FileInfo *file_info_1, const FileInfo *file_info_2)
FUNC_ATTR_NONNULL_ALL
{
return file_info_1->stat.st_ino == file_info_2->stat.st_ino
@@ -1119,7 +1116,7 @@ uint64_t os_fileinfo_blocksize(const FileInfo *file_info)
///
/// @param path Path to the file.
/// @param[out] file_info Pointer to a `FileID` to fill in.
-/// @return `true` on sucess, `false` for failure.
+/// @return `true` on success, `false` for failure.
bool os_fileid(const char *path, FileID *file_id)
FUNC_ATTR_NONNULL_ALL
{
@@ -1149,8 +1146,7 @@ bool os_fileid_equal(const FileID *file_id_1, const FileID *file_id_2)
/// @param file_id Pointer to a `FileID`
/// @param file_info Pointer to a `FileInfo`
/// @return `true` if the `FileID` and the `FileInfo` represent te same file.
-bool os_fileid_equal_fileinfo(const FileID *file_id,
- const FileInfo *file_info)
+bool os_fileid_equal_fileinfo(const FileID *file_id, const FileInfo *file_info)
FUNC_ATTR_NONNULL_ALL
{
return file_id->inode == file_info->stat.st_ino
@@ -1219,8 +1215,7 @@ char *os_resolve_shortcut(const char *fname)
EMSG2("utf8_to_utf16 failed: %d", r);
} else if (p != NULL) {
// Get a pointer to the IPersistFile interface.
- hr = pslw->lpVtbl->QueryInterface(
- pslw, &IID_IPersistFile, (void **)&ppf);
+ hr = pslw->lpVtbl->QueryInterface(pslw, &IID_IPersistFile, (void **)&ppf);
if (hr != S_OK) {
goto shortcut_errorw;
}
@@ -1231,12 +1226,12 @@ char *os_resolve_shortcut(const char *fname)
goto shortcut_errorw;
}
-# if 0 // This makes Vim wait a long time if the target does not exist.
+# if 0 // This makes Vim wait a long time if the target does not exist.
hr = pslw->lpVtbl->Resolve(pslw, NULL, SLR_NO_UI);
if (hr != S_OK) {
goto shortcut_errorw;
}
-# endif
+# endif
// Get the path to the link target.
ZeroMemory(wsz, MAX_PATH * sizeof(wchar_t));
@@ -1267,7 +1262,7 @@ shortcut_end:
return rfname;
}
-#define is_path_sep(c) ((c) == L'\\' || (c) == L'/')
+# define is_path_sep(c) ((c) == L'\\' || (c) == L'/')
/// Returns true if the path contains a reparse point (junction or symbolic
/// link). Otherwise false in returned.
bool os_is_reparse_point_include(const char *path)
diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c
index eca245650a..4c6e9ee4d3 100644
--- a/src/nvim/os/input.c
+++ b/src/nvim/os/input.c
@@ -2,28 +2,27 @@
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <assert.h>
-#include <string.h>
#include <stdbool.h>
-
+#include <string.h>
#include <uv.h>
#include "nvim/api/private/defs.h"
-#include "nvim/os/input.h"
+#include "nvim/ascii.h"
#include "nvim/event/loop.h"
#include "nvim/event/rstream.h"
-#include "nvim/ascii.h"
-#include "nvim/vim.h"
-#include "nvim/ui.h"
-#include "nvim/memory.h"
-#include "nvim/keymap.h"
-#include "nvim/mbyte.h"
-#include "nvim/fileio.h"
#include "nvim/ex_cmds2.h"
+#include "nvim/fileio.h"
#include "nvim/getchar.h"
+#include "nvim/keymap.h"
#include "nvim/main.h"
+#include "nvim/mbyte.h"
+#include "nvim/memory.h"
#include "nvim/misc1.h"
-#include "nvim/state.h"
#include "nvim/msgpack_rpc/channel.h"
+#include "nvim/os/input.h"
+#include "nvim/state.h"
+#include "nvim/ui.h"
+#include "nvim/vim.h"
#define READ_BUFFER_SIZE 0xfff
#define INPUT_BUFFER_SIZE (READ_BUFFER_SIZE * 4)
@@ -102,8 +101,7 @@ static void create_cursorhold_event(bool events_enabled)
///
/// wait until either the input buffer is non-empty or , if `events` is not NULL
/// until `events` is non-empty.
-int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt,
- MultiQueue *events)
+int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *events)
{
if (maxlen && rbuffer_size(input_buffer)) {
return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen);
@@ -192,7 +190,7 @@ void os_breakcheck(void)
/// @return `true` if file descriptor refers to a terminal.
bool os_isatty(int fd)
{
- return uv_guess_handle(fd) == UV_TTY;
+ return uv_guess_handle(fd) == UV_TTY;
}
size_t input_enqueue(String keys)
@@ -208,8 +206,8 @@ size_t input_enqueue(String keys)
// K_SPECIAL(0x80) or CSI(0x9B).
uint8_t buf[19] = { 0 };
unsigned int new_size
- = trans_special((const uint8_t **)&ptr, (size_t)(end - ptr), buf, true,
- false);
+ = trans_special((const uint8_t **)&ptr, (size_t)(end - ptr), buf, true,
+ false);
if (new_size) {
new_size = handle_mouse_event(&ptr, buf, new_size);
@@ -234,13 +232,13 @@ size_t input_enqueue(String keys)
// copy the character, escaping CSI and K_SPECIAL
if ((uint8_t)*ptr == CSI) {
- rbuffer_write(input_buffer, (char *)&(uint8_t){K_SPECIAL}, 1);
- rbuffer_write(input_buffer, (char *)&(uint8_t){KS_EXTRA}, 1);
- rbuffer_write(input_buffer, (char *)&(uint8_t){KE_CSI}, 1);
+ rbuffer_write(input_buffer, (char *)&(uint8_t){ K_SPECIAL }, 1);
+ rbuffer_write(input_buffer, (char *)&(uint8_t){ KS_EXTRA }, 1);
+ rbuffer_write(input_buffer, (char *)&(uint8_t){ KE_CSI }, 1);
} else if ((uint8_t)*ptr == K_SPECIAL) {
- rbuffer_write(input_buffer, (char *)&(uint8_t){K_SPECIAL}, 1);
- rbuffer_write(input_buffer, (char *)&(uint8_t){KS_SPECIAL}, 1);
- rbuffer_write(input_buffer, (char *)&(uint8_t){KE_FILLER}, 1);
+ rbuffer_write(input_buffer, (char *)&(uint8_t){ K_SPECIAL }, 1);
+ rbuffer_write(input_buffer, (char *)&(uint8_t){ KS_SPECIAL }, 1);
+ rbuffer_write(input_buffer, (char *)&(uint8_t){ KE_FILLER }, 1);
} else {
rbuffer_write(input_buffer, ptr, 1);
}
@@ -301,8 +299,7 @@ static uint8_t check_multiclick(int code, int grid, int row, int col)
// 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)
+static unsigned int handle_mouse_event(char **ptr, uint8_t *buf, unsigned int bufsize)
{
int mouse_code = 0;
int type = 0;
@@ -318,7 +315,7 @@ static unsigned int handle_mouse_event(char **ptr, uint8_t *buf,
if (type != KS_EXTRA
|| !((mouse_code >= KE_LEFTMOUSE && mouse_code <= KE_RIGHTRELEASE)
- || (mouse_code >= KE_MOUSEDOWN && mouse_code <= KE_MOUSERIGHT))) {
+ || (mouse_code >= KE_MOUSEDOWN && mouse_code <= KE_MOUSERIGHT))) {
return bufsize;
}
@@ -364,8 +361,7 @@ static unsigned int handle_mouse_event(char **ptr, uint8_t *buf,
return bufsize;
}
-size_t input_enqueue_mouse(int code, uint8_t modifier,
- int grid, int row, int col)
+size_t input_enqueue_mouse(int code, uint8_t modifier, int grid, int row, int col)
{
modifier |= check_multiclick(code, grid, row, col);
uint8_t buf[7], *p = buf;
@@ -437,8 +433,7 @@ bool input_available(void)
return rbuffer_size(input_buffer) != 0;
}
-static void input_read_cb(Stream *stream, RBuffer *buf, size_t c, void *data,
- bool at_eof)
+static void input_read_cb(Stream *stream, RBuffer *buf, size_t c, void *data, bool at_eof)
{
if (at_eof) {
input_done();
diff --git a/src/nvim/os/os_win_console.c b/src/nvim/os/os_win_console.c
index 18dcfeafa0..2c9cb699fc 100644
--- a/src/nvim/os/os_win_console.c
+++ b/src/nvim/os/os_win_console.c
@@ -1,9 +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
-#include "nvim/vim.h"
#include "nvim/os/input.h"
#include "nvim/os/os_win_console.h"
+#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/os_win_console.c.generated.h"
diff --git a/src/nvim/os/process.c b/src/nvim/os/process.c
index c7b473a012..e70bc71961 100644
--- a/src/nvim/os/process.c
+++ b/src/nvim/os/process.c
@@ -23,16 +23,16 @@
#endif
#if defined(__APPLE__) || defined(BSD)
-# include <sys/sysctl.h>
# include <pwd.h>
+# include <sys/sysctl.h>
#endif
+#include "nvim/api/private/helpers.h"
#include "nvim/globals.h"
#include "nvim/log.h"
-#include "nvim/os/process.h"
#include "nvim/os/os.h"
#include "nvim/os/os_defs.h"
-#include "nvim/api/private/helpers.h"
+#include "nvim/os/process.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/process.c.generated.h"
diff --git a/src/nvim/os/pty_conpty_win.c b/src/nvim/os/pty_conpty_win.c
index 5bcadd6490..0625d6994e 100644
--- a/src/nvim/os/pty_conpty_win.c
+++ b/src/nvim/os/pty_conpty_win.c
@@ -3,9 +3,9 @@
#include <uv.h>
-#include "nvim/vim.h"
#include "nvim/os/os.h"
#include "nvim/os/pty_conpty_win.h"
+#include "nvim/vim.h"
#ifndef EXTENDED_STARTUPINFO_PRESENT
# define EXTENDED_STARTUPINFO_PRESENT 0x00080000
@@ -54,8 +54,7 @@ TriState os_dyn_conpty_init(void)
return kTrue;
}
-conpty_t *os_conpty_init(char **in_name, char **out_name,
- uint16_t width, uint16_t height)
+conpty_t *os_conpty_init(char **in_name, char **out_name, uint16_t width, uint16_t height)
{
static int count = 0;
conpty_t *conpty_object = xcalloc(1, sizeof(*conpty_object));
@@ -65,36 +64,34 @@ conpty_t *os_conpty_init(char **in_name, char **out_name,
char buf[MAXPATHL];
SECURITY_ATTRIBUTES sa = { 0 };
const DWORD mode = PIPE_ACCESS_INBOUND
- | PIPE_ACCESS_OUTBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE;
+ | PIPE_ACCESS_OUTBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE;
sa.nLength = sizeof(sa);
snprintf(buf, sizeof(buf), "\\\\.\\pipe\\nvim-term-in-%d-%d",
os_get_pid(), count);
*in_name = xstrdup(buf);
- if ((in_read = CreateNamedPipeA(
- *in_name,
- mode,
- PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
- 1,
- 0,
- 0,
- 30000,
- &sa)) == INVALID_HANDLE_VALUE) {
+ if ((in_read = CreateNamedPipeA(*in_name,
+ mode,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+ 1,
+ 0,
+ 0,
+ 30000,
+ &sa)) == INVALID_HANDLE_VALUE) {
emsg = "create input pipe failed";
goto failed;
}
snprintf(buf, sizeof(buf), "\\\\.\\pipe\\nvim-term-out-%d-%d",
os_get_pid(), count);
*out_name = xstrdup(buf);
- if ((out_write = CreateNamedPipeA(
- *out_name,
- mode,
- PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
- 1,
- 0,
- 0,
- 30000,
- &sa)) == INVALID_HANDLE_VALUE) {
+ if ((out_write = CreateNamedPipeA(*out_name,
+ mode,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+ 1,
+ 0,
+ 0,
+ 30000,
+ &sa)) == INVALID_HANDLE_VALUE) {
emsg = "create output pipe failed";
goto failed;
}
@@ -104,7 +101,7 @@ conpty_t *os_conpty_init(char **in_name, char **out_name,
HRESULT hr;
hr = pCreatePseudoConsole(size, in_read, out_write, 0, &conpty_object->pty);
if (FAILED(hr)) {
- emsg = "create psudo console failed";
+ emsg = "create pseudo console failed";
goto failed;
}
@@ -113,22 +110,20 @@ conpty_t *os_conpty_init(char **in_name, char **out_name,
InitializeProcThreadAttributeList(NULL, 1, 0, & bytes_required);
conpty_object->si_ex.lpAttributeList =
(PPROC_THREAD_ATTRIBUTE_LIST)xmalloc(bytes_required);
- if (!InitializeProcThreadAttributeList(
- conpty_object->si_ex.lpAttributeList,
- 1,
- 0,
- &bytes_required)) {
+ if (!InitializeProcThreadAttributeList(conpty_object->si_ex.lpAttributeList,
+ 1,
+ 0,
+ &bytes_required)) {
emsg = "InitializeProcThreadAttributeList failed";
goto failed;
}
- if (!UpdateProcThreadAttribute(
- conpty_object->si_ex.lpAttributeList,
- 0,
- PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
- conpty_object->pty,
- sizeof(conpty_object->pty),
- NULL,
- NULL)) {
+ if (!UpdateProcThreadAttribute(conpty_object->si_ex.lpAttributeList,
+ 0,
+ PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
+ conpty_object->pty,
+ sizeof(conpty_object->pty),
+ NULL,
+ NULL)) {
emsg = "UpdateProcThreadAttribute failed";
goto failed;
}
@@ -150,38 +145,35 @@ finished:
return conpty_object;
}
-bool os_conpty_spawn(conpty_t *conpty_object, HANDLE *process_handle,
- wchar_t *name, wchar_t *cmd_line, wchar_t *cwd,
- wchar_t *env)
+bool os_conpty_spawn(conpty_t *conpty_object, HANDLE *process_handle, wchar_t *name,
+ wchar_t *cmd_line, wchar_t *cwd, wchar_t *env)
{
PROCESS_INFORMATION pi = { 0 };
- if (!CreateProcessW(
- name,
- cmd_line,
- NULL,
- NULL,
- false,
- EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT,
- env,
- cwd,
- &conpty_object->si_ex.StartupInfo,
- &pi)) {
+ if (!CreateProcessW(name,
+ cmd_line,
+ NULL,
+ NULL,
+ false,
+ EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT,
+ env,
+ cwd,
+ &conpty_object->si_ex.StartupInfo,
+ &pi)) {
return false;
}
*process_handle = pi.hProcess;
return true;
}
-void os_conpty_set_size(conpty_t *conpty_object,
- uint16_t width, uint16_t height)
+void os_conpty_set_size(conpty_t *conpty_object, uint16_t width, uint16_t height)
{
- assert(width <= SHRT_MAX);
- assert(height <= SHRT_MAX);
- COORD size = { (int16_t)width, (int16_t)height };
- if (pResizePseudoConsole(conpty_object->pty, size) != S_OK) {
- ELOG("ResizePseudoConsoel failed: error code: %d",
- os_translate_sys_error((int)GetLastError()));
- }
+ assert(width <= SHRT_MAX);
+ assert(height <= SHRT_MAX);
+ COORD size = { (int16_t)width, (int16_t)height };
+ if (pResizePseudoConsole(conpty_object->pty, size) != S_OK) {
+ ELOG("ResizePseudoConsoel failed: error code: %d",
+ os_translate_sys_error((int)GetLastError()));
+ }
}
void os_conpty_free(conpty_t *conpty_object)
diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c
index 36d6dbe2db..24ecf5c24f 100644
--- a/src/nvim/os/pty_process_unix.c
+++ b/src/nvim/os/pty_process_unix.c
@@ -5,11 +5,10 @@
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
-
-#include <termios.h>
+#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/wait.h>
-#include <sys/ioctl.h>
+#include <termios.h>
// forkpty is not in POSIX, so headers are platform-specific
#if defined(__FreeBSD__) || defined(__DragonFly__)
@@ -26,15 +25,14 @@
#include <uv.h>
-#include "nvim/lib/klist.h"
-
#include "nvim/event/loop.h"
+#include "nvim/event/process.h"
#include "nvim/event/rstream.h"
#include "nvim/event/wstream.h"
-#include "nvim/event/process.h"
-#include "nvim/os/pty_process_unix.h"
+#include "nvim/lib/klist.h"
#include "nvim/log.h"
#include "nvim/os/os.h"
+#include "nvim/os/pty_process_unix.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/pty_process_unix.c.generated.h"
@@ -159,7 +157,7 @@ static void init_child(PtyProcess *ptyproc)
FUNC_ATTR_NONNULL_ALL
{
#if defined(HAVE__NSGETENVIRON)
-#define environ (*_NSGetEnviron())
+# define environ (*_NSGetEnviron())
#else
extern char **environ;
#endif
diff --git a/src/nvim/os/pty_process_win.c b/src/nvim/os/pty_process_win.c
index 2bf73d08e6..f78f3e66f5 100644
--- a/src/nvim/os/pty_process_win.c
+++ b/src/nvim/os/pty_process_win.c
@@ -4,15 +4,14 @@
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
-
#include <winpty_constants.h>
-#include "nvim/os/os.h"
#include "nvim/ascii.h"
-#include "nvim/memory.h"
#include "nvim/mbyte.h" // for utf8_to_utf16, utf16_to_utf8
-#include "nvim/os/pty_process_win.h"
+#include "nvim/memory.h"
+#include "nvim/os/os.h"
#include "nvim/os/pty_conpty_win.h"
+#include "nvim/os/pty_process_win.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/pty_process_win.c.generated.h"
@@ -59,8 +58,8 @@ int pty_process_spawn(PtyProcess *ptyproc)
if (os_has_conpty_working()) {
if ((conpty_object =
- os_conpty_init(&in_name, &out_name,
- ptyproc->width, ptyproc->height)) != NULL) {
+ os_conpty_init(&in_name, &out_name,
+ ptyproc->width, ptyproc->height)) != NULL) {
ptyproc->type = kConpty;
}
}
@@ -94,20 +93,18 @@ int pty_process_spawn(PtyProcess *ptyproc)
if (!proc->in.closed) {
in_req = xmalloc(sizeof(uv_connect_t));
- uv_pipe_connect(
- in_req,
- &proc->in.uv.pipe,
- in_name,
- pty_process_connect_cb);
+ uv_pipe_connect(in_req,
+ &proc->in.uv.pipe,
+ in_name,
+ pty_process_connect_cb);
}
if (!proc->out.closed) {
out_req = xmalloc(sizeof(uv_connect_t));
- uv_pipe_connect(
- out_req,
- &proc->out.uv.pipe,
- out_name,
- pty_process_connect_cb);
+ uv_pipe_connect(out_req,
+ &proc->out.uv.pipe,
+ out_name,
+ pty_process_connect_cb);
}
if (proc->cwd != NULL) {
@@ -146,13 +143,12 @@ int pty_process_spawn(PtyProcess *ptyproc)
goto cleanup;
}
} else {
- spawncfg = winpty_spawn_config_new(
- WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN,
- NULL, // Optional application name
- cmd_line,
- cwd,
- env,
- &err);
+ spawncfg = winpty_spawn_config_new(WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN,
+ NULL, // Optional application name
+ cmd_line,
+ cwd,
+ env,
+ &err);
if (spawncfg == NULL) {
emsg = "winpty_spawn_config_new failed";
goto cleanup;
@@ -176,13 +172,12 @@ int pty_process_spawn(PtyProcess *ptyproc)
}
proc->pid = (int)GetProcessId(process_handle);
- if (!RegisterWaitForSingleObject(
- &ptyproc->finish_wait,
- process_handle,
- pty_process_finish1,
- ptyproc,
- INFINITE,
- WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE)) {
+ if (!RegisterWaitForSingleObject(&ptyproc->finish_wait,
+ process_handle,
+ pty_process_finish1,
+ ptyproc,
+ INFINITE,
+ WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE)) {
abort();
}
@@ -193,8 +188,8 @@ int pty_process_spawn(PtyProcess *ptyproc)
}
(ptyproc->type == kConpty) ?
- (void *)(ptyproc->object.conpty = conpty_object) :
- (void *)(ptyproc->object.winpty = winpty_object);
+ (void *)(ptyproc->object.conpty = conpty_object) :
+ (void *)(ptyproc->object.winpty = winpty_object);
ptyproc->process_handle = process_handle;
winpty_object = NULL;
conpty_object = NULL;
@@ -235,8 +230,7 @@ const char *pty_process_tty_name(PtyProcess *ptyproc)
return "?";
}
-void pty_process_resize(PtyProcess *ptyproc, uint16_t width,
- uint16_t height)
+void pty_process_resize(PtyProcess *ptyproc, uint16_t width, uint16_t height)
FUNC_ATTR_NONNULL_ALL
{
if (ptyproc->type == kConpty
@@ -454,15 +448,24 @@ int translate_winpty_error(int winpty_errno)
}
switch (winpty_errno) {
- case WINPTY_ERROR_OUT_OF_MEMORY: return UV_ENOMEM;
- case WINPTY_ERROR_SPAWN_CREATE_PROCESS_FAILED: return UV_EAI_FAIL;
- case WINPTY_ERROR_LOST_CONNECTION: return UV_ENOTCONN;
- case WINPTY_ERROR_AGENT_EXE_MISSING: return UV_ENOENT;
- case WINPTY_ERROR_UNSPECIFIED: return UV_UNKNOWN;
- case WINPTY_ERROR_AGENT_DIED: return UV_ESRCH;
- case WINPTY_ERROR_AGENT_TIMEOUT: return UV_ETIMEDOUT;
- case WINPTY_ERROR_AGENT_CREATION_FAILED: return UV_EAI_FAIL;
- default: return UV_UNKNOWN;
+ case WINPTY_ERROR_OUT_OF_MEMORY:
+ return UV_ENOMEM;
+ case WINPTY_ERROR_SPAWN_CREATE_PROCESS_FAILED:
+ return UV_EAI_FAIL;
+ case WINPTY_ERROR_LOST_CONNECTION:
+ return UV_ENOTCONN;
+ case WINPTY_ERROR_AGENT_EXE_MISSING:
+ return UV_ENOENT;
+ case WINPTY_ERROR_UNSPECIFIED:
+ return UV_UNKNOWN;
+ case WINPTY_ERROR_AGENT_DIED:
+ return UV_ESRCH;
+ case WINPTY_ERROR_AGENT_TIMEOUT:
+ return UV_ETIMEDOUT;
+ case WINPTY_ERROR_AGENT_CREATION_FAILED:
+ return UV_EAI_FAIL;
+ default:
+ return UV_UNKNOWN;
}
}
diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c
index 2974245857..2bff65b241 100644
--- a/src/nvim/os/shell.c
+++ b/src/nvim/os/shell.c
@@ -1,36 +1,35 @@
// 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 <string.h>
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
-
+#include <string.h>
#include <uv.h>
#include "nvim/ascii.h"
-#include "nvim/fileio.h"
-#include "nvim/lib/kvec.h"
-#include "nvim/log.h"
-#include "nvim/event/loop.h"
+#include "nvim/charset.h"
#include "nvim/event/libuv_process.h"
+#include "nvim/event/loop.h"
#include "nvim/event/rstream.h"
#include "nvim/ex_cmds.h"
+#include "nvim/fileio.h"
+#include "nvim/lib/kvec.h"
+#include "nvim/log.h"
+#include "nvim/main.h"
+#include "nvim/memline.h"
+#include "nvim/memory.h"
+#include "nvim/message.h"
#include "nvim/misc1.h"
+#include "nvim/option_defs.h"
#include "nvim/os/shell.h"
#include "nvim/os/signal.h"
#include "nvim/path.h"
-#include "nvim/types.h"
-#include "nvim/main.h"
-#include "nvim/vim.h"
-#include "nvim/message.h"
-#include "nvim/memory.h"
-#include "nvim/ui.h"
#include "nvim/screen.h"
-#include "nvim/memline.h"
-#include "nvim/option_defs.h"
-#include "nvim/charset.h"
#include "nvim/strings.h"
+#include "nvim/types.h"
+#include "nvim/ui.h"
+#include "nvim/vim.h"
#define DYNAMIC_BUFFER_INIT { NULL, 0, 0 }
#define NS_1_SECOND 1000000000U // 1 second, in nanoseconds
@@ -47,8 +46,7 @@ typedef struct {
# include "os/shell.c.generated.h"
#endif
-static void save_patterns(int num_pat, char_u **pat, int *num_file,
- char_u ***file)
+static void save_patterns(int num_pat, char_u **pat, int *num_file, char_u ***file)
{
*file = xmalloc((size_t)num_pat * sizeof(char_u *));
for (int i = 0; i < num_pat; i++) {
@@ -99,22 +97,21 @@ static bool have_dollars(int num, char_u **file)
/// copied into *file.
///
/// @returns OK for success or FAIL for error.
-int os_expand_wildcards(int num_pat, char_u **pat, int *num_file,
- char_u ***file, int flags)
+int os_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file, int flags)
FUNC_ATTR_NONNULL_ARG(3)
FUNC_ATTR_NONNULL_ARG(4)
{
int i;
size_t len;
- char_u *p;
+ char_u *p;
bool dir;
char_u *extra_shell_arg = NULL;
ShellOpts shellopts = kShellOptExpand | kShellOptSilent;
int j;
- char_u *tempname;
- char_u *command;
- FILE *fd;
- char_u *buffer;
+ char_u *tempname;
+ char_u *command;
+ FILE *fd;
+ char_u *buffer;
#define STYLE_ECHO 0 // use "echo", the default
#define STYLE_GLOB 1 // use "glob", for csh
#define STYLE_VIMGLOB 2 // use "vimglob", for Posix sh
@@ -215,7 +212,7 @@ int os_expand_wildcards(int num_pat, char_u **pat, int *num_file,
}
if (is_fish_shell) {
- len += sizeof("egin;"" end") - 1;
+ len += sizeof("egin;" " end") - 1;
}
command = xmalloc(len);
@@ -319,9 +316,9 @@ int os_expand_wildcards(int num_pat, char_u **pat, int *num_file,
if (shell_style == STYLE_PRINT) {
extra_shell_arg = (char_u *)"-G"; // Use zsh NULL_GLOB option
- // If we use -f then shell variables set in .cshrc won't get expanded.
- // vi can do it, so we will too, but it is only necessary if there is a "$"
- // in one of the patterns, otherwise we can still use the fast option.
+ // If we use -f then shell variables set in .cshrc won't get expanded.
+ // vi can do it, so we will too, but it is only necessary if there is a "$"
+ // in one of the patterns, otherwise we can still use the fast option.
} else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat)) {
extra_shell_arg = (char_u *)"-f"; // Use csh fast option
}
@@ -409,7 +406,7 @@ int os_expand_wildcards(int num_pat, char_u **pat, int *num_file,
}
p = skipwhite(p); // skip to next entry
}
- // file names are separated with NL
+ // file names are separated with NL
} else if (shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB) {
buffer[len] = NUL; // make sure the buffer ends in NUL
p = buffer;
@@ -422,7 +419,7 @@ int os_expand_wildcards(int num_pat, char_u **pat, int *num_file,
}
p = skipwhite(p); // skip leading white space
}
- // file names are separated with NUL
+ // file names are separated with NUL
} else {
// Some versions of zsh use spaces instead of NULs to separate
// results. Only do this when there is no NUL before the end of the
@@ -705,22 +702,14 @@ int os_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_args)
/// returned buffer is not NULL)
/// @return the return code of the process, -1 if the process couldn't be
/// started properly
-int os_system(char **argv,
- const char *input,
- size_t len,
- char **output,
+int os_system(char **argv, const char *input, size_t len, char **output,
size_t *nread) FUNC_ATTR_NONNULL_ARG(1)
{
return do_os_system(argv, input, len, output, nread, true, false);
}
-static int do_os_system(char **argv,
- const char *input,
- size_t len,
- char **output,
- size_t *nread,
- bool silent,
- bool forward_output)
+static int do_os_system(char **argv, const char *input, size_t len, char **output, size_t *nread,
+ bool silent, bool forward_output)
{
out_data_decide_throttle(0); // Initialize throttle decider.
out_data_ring(NULL, 0); // Initialize output ring-buffer.
@@ -851,8 +840,7 @@ static void dynamic_buffer_ensure(DynamicBuffer *buf, size_t desired)
buf->data = xrealloc(buf->data, buf->cap);
}
-static void system_data_cb(Stream *stream, RBuffer *buf, size_t count,
- void *data, bool eof)
+static void system_data_cb(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof)
{
DynamicBuffer *dbuf = data;
@@ -885,10 +873,10 @@ static void system_data_cb(Stream *stream, RBuffer *buf, size_t count,
/// Returns the previous decision if size=0.
static bool out_data_decide_throttle(size_t size)
{
- static uint64_t started = 0; // Start time of the current throttle.
- static size_t received = 0; // Bytes observed since last throttle.
- static size_t visit = 0; // "Pulse" count of the current throttle.
- static char pulse_msg[] = { ' ', ' ', ' ', '\0' };
+ static uint64_t started = 0; // Start time of the current throttle.
+ static size_t received = 0; // Bytes observed since last throttle.
+ static size_t visit = 0; // "Pulse" count of the current throttle.
+ static char pulse_msg[] = { ' ', ' ', ' ', '\0' };
if (!size) {
bool previous_decision = (visit > 0);
@@ -945,8 +933,8 @@ static bool out_data_decide_throttle(size_t size)
static void out_data_ring(char *output, size_t size)
{
#define MAX_CHUNK_SIZE (OUT_DATA_THRESHOLD / 2)
- static char last_skipped[MAX_CHUNK_SIZE]; // Saved output.
- static size_t last_skipped_len = 0;
+ static char last_skipped[MAX_CHUNK_SIZE]; // Saved output.
+ static size_t last_skipped_len = 0;
assert(output != NULL || (size == 0 || size == SIZE_MAX));
@@ -1015,8 +1003,7 @@ end:
ui_flush();
}
-static void out_data_cb(Stream *stream, RBuffer *buf, size_t count, void *data,
- bool eof)
+static void out_data_cb(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof)
{
size_t cnt;
char *ptr = rbuffer_read_ptr(buf, &cnt);
@@ -1049,10 +1036,10 @@ static size_t tokenize(const char_u *const str, char **const argv)
FUNC_ATTR_NONNULL_ARG(1)
{
size_t argc = 0;
- const char *p = (const char *) str;
+ const char *p = (const char *)str;
while (*p != NUL) {
- const size_t len = word_length((const char_u *) p);
+ const size_t len = word_length((const char_u *)p);
if (argv != NULL) {
// Fill the slot
@@ -1060,7 +1047,7 @@ static size_t tokenize(const char_u *const str, char **const argv)
}
argc++;
- p = (const char *) skipwhite((char_u *) (p + len));
+ p = (const char *)skipwhite((char_u *)(p + len));
}
return argc;
@@ -1115,7 +1102,7 @@ static void read_input(DynamicBuffer *buf)
dynamic_buffer_ensure(buf, buf->len + len);
buf->data[buf->len++] = NUL;
} else {
- char_u *s = vim_strchr(lp + written, NL);
+ char_u *s = vim_strchr(lp + written, NL);
len = s == NULL ? l : (size_t)(s - (lp + written));
dynamic_buffer_ensure(buf, buf->len + len);
memcpy(buf->data + buf->len, lp + written, len);
diff --git a/src/nvim/os/signal.c b/src/nvim/os/signal.c
index bc774b8ebc..0d125ec964 100644
--- a/src/nvim/os/signal.c
+++ b/src/nvim/os/signal.c
@@ -3,25 +3,24 @@
#include <assert.h>
#include <stdbool.h>
-
#include <uv.h>
#ifndef WIN32
# include <signal.h> // for sigset_t
#endif
#include "nvim/ascii.h"
-#include "nvim/log.h"
-#include "nvim/vim.h"
-#include "nvim/globals.h"
-#include "nvim/memline.h"
#include "nvim/eval.h"
+#include "nvim/event/loop.h"
+#include "nvim/event/signal.h"
#include "nvim/fileio.h"
+#include "nvim/globals.h"
+#include "nvim/log.h"
#include "nvim/main.h"
+#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/misc1.h"
-#include "nvim/event/signal.h"
#include "nvim/os/signal.h"
-#include "nvim/event/loop.h"
+#include "nvim/vim.h"
static SignalWatcher spipe, shup, squit, sterm, susr1;
#ifdef SIGPWR
@@ -120,31 +119,31 @@ void signal_accept_deadly(void)
rejecting_deadly = false;
}
-static char * signal_name(int signum)
+static char *signal_name(int signum)
{
switch (signum) {
#ifdef SIGPWR
- case SIGPWR:
- return "SIGPWR";
+ case SIGPWR:
+ return "SIGPWR";
#endif
#ifdef SIGPIPE
- case SIGPIPE:
- return "SIGPIPE";
+ case SIGPIPE:
+ return "SIGPIPE";
#endif
- case SIGTERM:
- return "SIGTERM";
+ case SIGTERM:
+ return "SIGTERM";
#ifdef SIGQUIT
- case SIGQUIT:
- return "SIGQUIT";
+ case SIGQUIT:
+ return "SIGQUIT";
#endif
- case SIGHUP:
- return "SIGHUP";
+ case SIGHUP:
+ return "SIGHUP";
#ifdef SIGUSR1
- case SIGUSR1:
- return "SIGUSR1";
+ case SIGUSR1:
+ return "SIGUSR1";
#endif
- default:
- return "Unknown";
+ default:
+ return "Unknown";
}
}
@@ -173,34 +172,34 @@ static void on_signal(SignalWatcher *handle, int signum, void *data)
assert(signum >= 0);
switch (signum) {
#ifdef SIGPWR
- case SIGPWR:
- // Signal of a power failure(eg batteries low), flush the swap files to
- // be safe
- ml_sync_all(false, false, true);
- break;
+ case SIGPWR:
+ // Signal of a power failure(eg batteries low), flush the swap files to
+ // be safe
+ ml_sync_all(false, false, true);
+ break;
#endif
#ifdef SIGPIPE
- case SIGPIPE:
- // Ignore
- break;
+ case SIGPIPE:
+ // Ignore
+ break;
#endif
- case SIGTERM:
+ case SIGTERM:
#ifdef SIGQUIT
- case SIGQUIT:
+ case SIGQUIT:
#endif
- case SIGHUP:
- if (!rejecting_deadly) {
- deadly_signal(signum);
- }
- break;
+ case SIGHUP:
+ if (!rejecting_deadly) {
+ deadly_signal(signum);
+ }
+ break;
#ifdef SIGUSR1
- case SIGUSR1:
- apply_autocmds(EVENT_SIGNAL, (char_u *)"SIGUSR1", curbuf->b_fname, true,
- curbuf);
- break;
-#endif
- default:
- ELOG("invalid signal: %d", signum);
- break;
+ case SIGUSR1:
+ apply_autocmds(EVENT_SIGNAL, (char_u *)"SIGUSR1", curbuf->b_fname, true,
+ curbuf);
+ break;
+#endif
+ default:
+ ELOG("invalid signal: %d", signum);
+ break;
}
}
diff --git a/src/nvim/os/stdpaths.c b/src/nvim/os/stdpaths.c
index 93b8d5ca12..10b0d391bf 100644
--- a/src/nvim/os/stdpaths.c
+++ b/src/nvim/os/stdpaths.c
@@ -3,11 +3,11 @@
#include <stdbool.h>
-#include "nvim/os/stdpaths_defs.h"
+#include "nvim/ascii.h"
+#include "nvim/memory.h"
#include "nvim/os/os.h"
+#include "nvim/os/stdpaths_defs.h"
#include "nvim/path.h"
-#include "nvim/memory.h"
-#include "nvim/ascii.h"
/// Names of the environment variables, mapped to XDGVarType values
static const char *xdg_env_vars[] = {
@@ -137,8 +137,7 @@ char *stdpaths_user_conf_subpath(const char *fname)
/// @param[in] escape_commas If true, all commas will be escaped.
///
/// @return [allocated] `$XDG_DATA_HOME/nvim/{fname}`.
-char *stdpaths_user_data_subpath(const char *fname,
- const size_t trailing_pathseps,
+char *stdpaths_user_data_subpath(const char *fname, const size_t trailing_pathseps,
const bool escape_commas)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
{
diff --git a/src/nvim/os/time.c b/src/nvim/os/time.c
index 9ea74716aa..d9f4fe9e37 100644
--- a/src/nvim/os/time.c
+++ b/src/nvim/os/time.c
@@ -3,15 +3,14 @@
#include <assert.h>
#include <limits.h>
-
#include <uv.h>
#include "nvim/assert.h"
-#include "nvim/os/time.h"
-#include "nvim/os/input.h"
#include "nvim/event/loop.h"
-#include "nvim/os/os.h"
#include "nvim/main.h"
+#include "nvim/os/input.h"
+#include "nvim/os/os.h"
+#include "nvim/os/time.h"
static uv_mutex_t delay_mutex;
static uv_cond_t delay_cond;
@@ -169,8 +168,7 @@ struct tm *os_localtime(struct tm *result) FUNC_ATTR_NONNULL_ALL
/// @param result[out] Pointer to a 'char' where the result should be placed
/// @param result_len length of result buffer
/// @return human-readable string of current local time
-char *os_ctime_r(const time_t *restrict clock, char *restrict result,
- size_t result_len)
+char *os_ctime_r(const time_t *restrict clock, char *restrict result, size_t result_len)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
{
struct tm clock_local;
@@ -219,5 +217,5 @@ char *os_strptime(const char *str, const char *format, struct tm *tm)
Timestamp os_time(void)
FUNC_ATTR_WARN_UNUSED_RESULT
{
- return (Timestamp) time(NULL);
+ return (Timestamp)time(NULL);
}
diff --git a/src/nvim/os/tty.c b/src/nvim/os/tty.c
index c80ef99084..126b1b0044 100644
--- a/src/nvim/os/tty.c
+++ b/src/nvim/os/tty.c
@@ -23,15 +23,6 @@
/// @param out_fd stdout file descriptor
void os_tty_guess_term(const char **term, int out_fd)
{
- bool winpty = (os_getenv("NVIM") != NULL);
-
- if (winpty) {
- // Force TERM=win32con when running in winpty.
- *term = "win32con";
- uv_tty_set_vterm_state(UV_TTY_UNSUPPORTED);
- return;
- }
-
bool conemu_ansi = strequal(os_getenv("ConEmuANSI"), "ON");
bool vtp = false;
diff --git a/src/nvim/os/users.c b/src/nvim/os/users.c
index 16e17a9c60..fd7ead68da 100644
--- a/src/nvim/os/users.c
+++ b/src/nvim/os/users.c
@@ -6,11 +6,10 @@
#include <uv.h>
#include "auto/config.h"
-
#include "nvim/ascii.h"
-#include "nvim/os/os.h"
#include "nvim/garray.h"
#include "nvim/memory.h"
+#include "nvim/os/os.h"
#include "nvim/strings.h"
#ifdef HAVE_PWD_H
# include <pwd.h>
@@ -44,7 +43,7 @@ int os_get_usernames(garray_T *users)
}
ga_init(users, sizeof(char *), 20);
-# if defined(HAVE_GETPWENT) && defined(HAVE_PWD_H)
+#if defined(HAVE_GETPWENT) && defined(HAVE_PWD_H)
{
struct passwd *pw;
@@ -54,7 +53,7 @@ int os_get_usernames(garray_T *users)
}
endpwent();
}
-# elif defined(WIN32)
+#elif defined(WIN32)
{
DWORD nusers = 0, ntotal = 0, i;
PUSER_INFO_0 uinfo;
@@ -74,8 +73,8 @@ int os_get_usernames(garray_T *users)
NetApiBufferFree(uinfo);
}
}
-# endif
-# if defined(HAVE_GETPWNAM)
+#endif
+#if defined(HAVE_GETPWNAM)
{
const char *user_env = os_getenv("USER");
@@ -105,7 +104,7 @@ int os_get_usernames(garray_T *users)
}
}
}
-# endif
+#endif
return OK;
}
diff --git a/src/nvim/os_unix.c b/src/nvim/os_unix.c
index be4bd9709b..9396a5896a 100644
--- a/src/nvim/os_unix.c
+++ b/src/nvim/os_unix.c
@@ -7,15 +7,13 @@
#include <stdbool.h>
#include <string.h>
-#include "nvim/api/private/handle.h"
-#include "nvim/vim.h"
#include "nvim/ascii.h"
-#include "nvim/os_unix.h"
#include "nvim/buffer.h"
#include "nvim/charset.h"
#include "nvim/eval.h"
#include "nvim/ex_cmds.h"
#include "nvim/fileio.h"
+#include "nvim/garray.h"
#include "nvim/getchar.h"
#include "nvim/main.h"
#include "nvim/mbyte.h"
@@ -24,19 +22,20 @@
#include "nvim/message.h"
#include "nvim/misc1.h"
#include "nvim/mouse.h"
-#include "nvim/garray.h"
+#include "nvim/msgpack_rpc/helpers.h"
+#include "nvim/os/input.h"
+#include "nvim/os/os.h"
+#include "nvim/os/shell.h"
+#include "nvim/os/signal.h"
+#include "nvim/os/time.h"
+#include "nvim/os_unix.h"
#include "nvim/path.h"
#include "nvim/screen.h"
#include "nvim/strings.h"
#include "nvim/syntax.h"
-#include "nvim/ui.h"
#include "nvim/types.h"
-#include "nvim/os/os.h"
-#include "nvim/os/time.h"
-#include "nvim/os/input.h"
-#include "nvim/os/shell.h"
-#include "nvim/os/signal.h"
-#include "nvim/msgpack_rpc/helpers.h"
+#include "nvim/ui.h"
+#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os_unix.c.generated.h"
@@ -62,13 +61,15 @@ vim_acl_T mch_get_acl(const char_u *fname)
// Set the ACL of file "fname" to "acl" (unless it's NULL).
void mch_set_acl(const char_u *fname, vim_acl_T aclent)
{
- if (aclent == NULL)
+ if (aclent == NULL) {
return;
+ }
}
void mch_free_acl(vim_acl_T aclent)
{
- if (aclent == NULL)
+ if (aclent == NULL) {
return;
+ }
}
#endif
diff --git a/src/nvim/path.c b/src/nvim/path.c
index 6ac24182cc..60c7ea7fa4 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -6,15 +6,13 @@
#include <stdbool.h>
#include <stdlib.h>
-#include "nvim/vim.h"
#include "nvim/ascii.h"
-#include "nvim/path.h"
#include "nvim/charset.h"
#include "nvim/eval.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
-#include "nvim/fileio.h"
#include "nvim/file_search.h"
+#include "nvim/fileio.h"
#include "nvim/garray.h"
#include "nvim/memfile.h"
#include "nvim/memline.h"
@@ -22,20 +20,22 @@
#include "nvim/message.h"
#include "nvim/misc1.h"
#include "nvim/option.h"
+#include "nvim/os/input.h"
#include "nvim/os/os.h"
#include "nvim/os/shell.h"
#include "nvim/os_unix.h"
+#include "nvim/path.h"
#include "nvim/quickfix.h"
#include "nvim/regexp.h"
#include "nvim/screen.h"
#include "nvim/strings.h"
#include "nvim/tag.h"
#include "nvim/types.h"
-#include "nvim/os/input.h"
+#include "nvim/vim.h"
#include "nvim/window.h"
-#define URL_SLASH 1 /* path_is_url() has found "://" */
-#define URL_BACKSLASH 2 /* path_is_url() has found ":\\" */
+#define URL_SLASH 1 // path_is_url() has found "://"
+#define URL_BACKSLASH 2 // path_is_url() has found ":\\"
#ifdef gen_expand_wildcards
# undef gen_expand_wildcards
@@ -53,8 +53,8 @@
/// @param checkname When both files don't exist, only compare their names.
/// @param expandenv Whether to expand environment variables in file names.
/// @return Enum of type FileComparison. @see FileComparison.
-FileComparison path_full_compare(char_u *const s1, char_u *const s2,
- const bool checkname, const bool expandenv)
+FileComparison path_full_compare(char_u *const s1, char_u *const s2, const bool checkname,
+ const bool expandenv)
{
assert(s1 && s2);
char_u exp1[MAXPATHL];
@@ -63,9 +63,9 @@ FileComparison path_full_compare(char_u *const s1, char_u *const s2,
FileID file_id_1, file_id_2;
if (expandenv) {
- expand_env(s1, exp1, MAXPATHL);
+ expand_env(s1, exp1, MAXPATHL);
} else {
- xstrlcpy((char *)exp1, (const char *)s1, MAXPATHL);
+ xstrlcpy((char *)exp1, (const char *)s1, MAXPATHL);
}
bool id_ok_1 = os_fileid((char *)exp1, &file_id_1);
bool id_ok_2 = os_fileid((char *)s2, &file_id_2);
@@ -146,7 +146,7 @@ char_u *path_tail_with_sep(char_u *fname)
const char_u *invocation_path_tail(const char_u *invocation, size_t *len)
FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ARG(1)
{
- const char_u *tail = get_past_head((char_u *) invocation);
+ const char_u *tail = get_past_head((char_u *)invocation);
const char_u *p = tail;
while (*p != NUL && *p != ' ') {
bool was_sep = vim_ispathsep_nocolon(*p);
@@ -266,7 +266,7 @@ int vim_ispathlistsep(int c)
#ifdef UNIX
return c == ':';
#else
- return c == ';'; /* might not be right for every system... */
+ return c == ';'; // might not be right for every system...
#endif
}
@@ -280,11 +280,12 @@ char_u *shorten_dir(char_u *str)
char_u *d = str;
bool skip = false;
for (char_u *s = str;; ++s) {
- if (s >= tail) { /* copy the whole tail */
+ if (s >= tail) { // copy the whole tail
*d++ = *s;
- if (*s == NUL)
+ if (*s == NUL) {
break;
- } else if (vim_ispathsep(*s)) { /* copy '/' and next char */
+ }
+ } else if (vim_ispathsep(*s)) { // copy '/' and next char
*d++ = *s;
skip = false;
} else if (!skip) {
@@ -348,8 +349,7 @@ int path_fnamecmp(const char *fname1, const char *fname2)
/// @param[in] len Compare at most len bytes.
///
/// @return 0 if they are equal, non-zero otherwise.
-int path_fnamencmp(const char *const fname1, const char *const fname2,
- size_t len)
+int path_fnamencmp(const char *const fname1, const char *const fname2, size_t len)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
#ifdef BACKSLASH_IN_FILENAME
@@ -383,15 +383,14 @@ int path_fnamencmp(const char *const fname1, const char *const fname2,
///
/// @param[in] fname1 First fname to append to.
/// @param[in] len1 Length of fname1.
-/// @param[in] fname2 Secord part of the file name.
+/// @param[in] fname2 Second part of the file name.
/// @param[in] len2 Length of fname2.
/// @param[in] sep If true and fname1 does not end with a path separator,
/// add a path separator before fname2.
///
/// @return fname1
-static inline char *do_concat_fnames(char *fname1, const size_t len1,
- const char *fname2, const size_t len2,
- const bool sep)
+static inline char *do_concat_fnames(char *fname1, const size_t len1, const char *fname2,
+ const size_t len2, const bool sep)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
{
if (sep && *fname1 && !after_pathsep(fname1, fname1 + len1)) {
@@ -548,7 +547,7 @@ bool path_has_exp_wildcard(const char_u *p)
#else
const char *wildcards = "*?["; // Windows.
#endif
- if (vim_strchr((char_u *) wildcards, *p) != NULL) {
+ if (vim_strchr((char_u *)wildcards, *p) != NULL) {
return true;
}
}
@@ -590,8 +589,8 @@ static const char *scandir_next_with_dots(Directory *dir)
/// Implementation of path_expand().
///
/// Chars before `path + wildoff` do not get expanded.
-static size_t do_path_expand(garray_T *gap, const char_u *path,
- size_t wildoff, int flags, bool didstar)
+static size_t do_path_expand(garray_T *gap, const char_u *path, size_t wildoff, int flags,
+ bool didstar)
FUNC_ATTR_NONNULL_ALL
{
int start_len = gap->ga_len;
@@ -599,11 +598,12 @@ static size_t do_path_expand(garray_T *gap, const char_u *path,
bool starstar = false;
static int stardepth = 0; // depth for "**" expansion
- /* Expanding "**" may take a long time, check for CTRL-C. */
+ // Expanding "**" may take a long time, check for CTRL-C.
if (stardepth > 0) {
os_breakcheck();
- if (got_int)
+ if (got_int) {
return 0;
+ }
}
// Make room for file name. When doing encoding conversion the actual
@@ -633,7 +633,7 @@ static size_t do_path_expand(garray_T *gap, const char_u *path,
|| (!p_fic && (flags & EW_ICASE)
&& isalpha(PTR2CHAR(path_end)))
#endif
- )) {
+ )) {
e = p;
}
len = (size_t)(utfc_ptr2len(path_end));
@@ -644,20 +644,23 @@ static size_t do_path_expand(garray_T *gap, const char_u *path,
e = p;
*e = NUL;
- /* Now we have one wildcard component between "s" and "e". */
+ // Now we have one wildcard component between "s" and "e".
/* Remove backslashes between "wildoff" and the start of the wildcard
* component. */
- for (p = buf + wildoff; p < s; ++p)
+ for (p = buf + wildoff; p < s; ++p) {
if (rem_backslash(p)) {
STRMOVE(p, p + 1);
--e;
--s;
}
+ }
- /* Check for "**" between "s" and "e". */
- for (p = s; p < e; ++p)
- if (p[0] == '*' && p[1] == '*')
+ // Check for "**" between "s" and "e".
+ for (p = s; p < e; ++p) {
+ if (p[0] == '*' && p[1] == '*') {
starstar = true;
+ }
+ }
// convert the file pattern to a regexp pattern
int starts_with_dot = *s == '.';
@@ -675,11 +678,13 @@ static size_t do_path_expand(garray_T *gap, const char_u *path,
#else
regmatch.rm_ic = true; // Always ignore case on Windows.
#endif
- if (flags & (EW_NOERROR | EW_NOTWILD))
+ if (flags & (EW_NOERROR | EW_NOTWILD)) {
++emsg_silent;
+ }
regmatch.regprog = vim_regcomp(pat, RE_MAGIC);
- if (flags & (EW_NOERROR | EW_NOTWILD))
+ if (flags & (EW_NOERROR | EW_NOTWILD)) {
--emsg_silent;
+ }
xfree(pat);
if (regmatch.regprog == NULL && (flags & EW_NOTWILD) == 0) {
@@ -727,9 +732,9 @@ static size_t do_path_expand(garray_T *gap, const char_u *path,
}
STRCPY(buf + len, path_end);
- if (path_has_exp_wildcard(path_end)) { /* handle more wildcards */
- /* need to expand another component of the path */
- /* remove backslashes for the remaining components only */
+ if (path_has_exp_wildcard(path_end)) { // handle more wildcards
+ // need to expand another component of the path
+ // remove backslashes for the remaining components only
(void)do_path_expand(gap, buf, len + 1, flags, false);
} else {
FileInfo file_info;
@@ -741,7 +746,7 @@ static size_t do_path_expand(garray_T *gap, const char_u *path,
}
// add existing file or symbolic link
if ((flags & EW_ALLLINKS) ? os_fileinfo_link((char *)buf, &file_info)
- : os_path_exists(buf)) {
+ : os_path_exists(buf)) {
addfile(gap, buf, flags);
}
}
@@ -767,14 +772,16 @@ static size_t do_path_expand(garray_T *gap, const char_u *path,
*/
static int find_previous_pathsep(char_u *path, char_u **psep)
{
- /* skip the current separator */
- if (*psep > path && vim_ispathsep(**psep))
+ // skip the current separator
+ if (*psep > path && vim_ispathsep(**psep)) {
--*psep;
+ }
- /* find the previous separator */
+ // find the previous separator
while (*psep > path) {
- if (vim_ispathsep(**psep))
+ if (vim_ispathsep(**psep)) {
return OK;
+ }
MB_PTR_BACK(path, *psep);
}
@@ -828,8 +835,9 @@ static void expand_path_option(char_u *curdir, garray_T *gap)
/* Relative to current buffer:
* "/path/file" + "." -> "/path/"
* "/path/file" + "./subdir" -> "/path/subdir" */
- if (curbuf->b_ffname == NULL)
+ if (curbuf->b_ffname == NULL) {
continue;
+ }
char_u *p = path_tail(curbuf->b_ffname);
size_t len = (size_t)(p - curbuf->b_ffname);
if (len + STRLEN(buf) >= MAXPATHL) {
@@ -870,13 +878,13 @@ static void expand_path_option(char_u *curdir, garray_T *gap)
*
* path: /foo/bar/baz
* fname: /foo/bar/baz/quux.txt
- * returns: ^this
+ * returns: ^this
*/
static char_u *get_path_cutoff(char_u *fname, garray_T *gap)
{
int maxlen = 0;
- char_u **path_part = (char_u **)gap->ga_data;
- char_u *cutoff = NULL;
+ char_u **path_part = (char_u **)gap->ga_data;
+ char_u *cutoff = NULL;
for (int i = 0; i < gap->ga_len; i++) {
int j = 0;
@@ -932,14 +940,16 @@ static void uniquefy_paths(garray_T *gap, char_u *pattern)
STRCAT(file_pattern, pattern);
char_u *pat = file_pat_to_reg_pat(file_pattern, NULL, NULL, true);
xfree(file_pattern);
- if (pat == NULL)
+ if (pat == NULL) {
return;
+ }
- regmatch.rm_ic = TRUE; /* always ignore case */
+ regmatch.rm_ic = TRUE; // always ignore case
regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
xfree(pat);
- if (regmatch.regprog == NULL)
+ if (regmatch.regprog == NULL) {
return;
+ }
char_u *curdir = xmalloc(MAXPATHL);
os_dirname(curdir, MAXPATHL);
@@ -951,16 +961,17 @@ static void uniquefy_paths(garray_T *gap, char_u *pattern)
char_u *path = fnames[i];
int is_in_curdir;
char_u *dir_end = (char_u *)gettail_dir((const char *)path);
- char_u *pathsep_p;
- char_u *path_cutoff;
+ char_u *pathsep_p;
+ char_u *path_cutoff;
len = STRLEN(path);
is_in_curdir = fnamencmp(curdir, path, dir_end - path) == 0
&& curdir[dir_end - path] == NUL;
- if (is_in_curdir)
+ if (is_in_curdir) {
in_curdir[i] = vim_strsave(path);
+ }
- /* Shorten the filename while maintaining its uniqueness */
+ // Shorten the filename while maintaining its uniqueness
path_cutoff = get_path_cutoff(path, &path_ga);
// Don't assume all files can be reached without path when search
@@ -1010,19 +1021,21 @@ static void uniquefy_paths(garray_T *gap, char_u *pattern)
os_breakcheck();
}
- /* Shorten filenames in /in/current/directory/{filename} */
+ // Shorten filenames in /in/current/directory/{filename}
for (int i = 0; i < gap->ga_len && !got_int; i++) {
char_u *rel_path;
char_u *path = in_curdir[i];
- if (path == NULL)
+ if (path == NULL) {
continue;
+ }
/* If the {filename} is not unique, change it to ./{filename}.
* Else reduce it to {filename} */
short_name = path_shorten_fname(path, curdir);
- if (short_name == NULL)
+ if (short_name == NULL) {
short_name = path;
+ }
if (is_unique(short_name, gap, i)) {
STRCPY(fnames[i], short_name);
continue;
@@ -1040,14 +1053,16 @@ static void uniquefy_paths(garray_T *gap, char_u *pattern)
}
xfree(curdir);
- for (int i = 0; i < gap->ga_len; i++)
+ for (int i = 0; i < gap->ga_len; i++) {
xfree(in_curdir[i]);
+ }
xfree(in_curdir);
ga_clear_strings(&path_ga);
vim_regfree(regmatch.regprog);
- if (sort_again)
+ if (sort_again) {
ga_remove_duplicate_strings(gap);
+ }
}
/// Find end of the directory name
@@ -1072,8 +1087,9 @@ const char *gettail_dir(const char *const fname)
look_for_sep = false;
}
} else {
- if (!look_for_sep)
+ if (!look_for_sep) {
dir_end = next_dir_end;
+ }
look_for_sep = true;
}
MB_PTR_ADV(p);
@@ -1082,16 +1098,12 @@ const char *gettail_dir(const char *const fname)
}
-/*
- * Calls globpath() with 'path' values for the given pattern and stores the
- * result in "gap".
- * Returns the total number of matches.
- */
-static int expand_in_path(
- garray_T *const gap,
- char_u *const pattern,
- const int flags // EW_* flags
-)
+/// Calls globpath() with 'path' values for the given pattern and stores the
+/// result in "gap".
+/// Returns the total number of matches.
+///
+/// @param flags EW_* flags
+static int expand_in_path(garray_T *const gap, char_u *const pattern, const int flags)
{
garray_T path_ga;
@@ -1131,7 +1143,7 @@ static bool has_env_var(char_u *p)
for (; *p; MB_PTR_ADV(p)) {
if (*p == '\\' && p[1] != NUL) {
p++;
- } else if (vim_strchr((char_u *) "$" , *p) != NULL) {
+ } else if (vim_strchr((char_u *)"$", *p) != NULL) {
return true;
}
}
@@ -1186,8 +1198,7 @@ static bool has_special_wildchar(char_u *p)
/// If FAIL is returned, *num_file and *file are either
/// unchanged or *num_file is set to 0 and *file is set
/// to NULL or points to "".
-int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file,
- char_u ***file, int flags)
+int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***file, int flags)
{
garray_T ga;
char_u *p;
@@ -1203,9 +1214,9 @@ int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file,
*/
if (recursive)
#ifdef SPECIAL_WILDCHAR
- return os_expand_wildcards(num_pat, pat, num_file, file, flags);
+ { return os_expand_wildcards(num_pat, pat, num_file, file, flags); }
#else
- return FAIL;
+ { return FAIL; }
#endif
#ifdef SPECIAL_WILDCHAR
@@ -1247,8 +1258,9 @@ int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file,
// First expand environment variables, "~/" and "~user/".
if ((has_env_var(p) && !(flags & EW_NOTENV)) || *p == '~') {
p = expand_env_save_opt(p, true);
- if (p == NULL)
+ if (p == NULL) {
p = pat[i];
+ }
#ifdef UNIX
/*
* On Unix, if expand_env() can't expand an environment
@@ -1278,8 +1290,8 @@ int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file,
&& !path_is_absolute(p)
&& !(p[0] == '.'
&& (vim_ispathsep(p[1])
- || (p[1] == '.' && vim_ispathsep(p[2]))))
- ) {
+ || (p[1] == '.' &&
+ vim_ispathsep(p[2]))))) {
/* :find completion where 'path' is used.
* Recursiveness is OK here. */
recursive = false;
@@ -1295,7 +1307,7 @@ int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file,
}
if (add_pat == -1 || (add_pat == 0 && (flags & EW_NOTFOUND))) {
- char_u *t = backslash_halve_save(p);
+ char_u *t = backslash_halve_save(p);
/* When EW_NOTFOUND is used, always add files and dirs. Makes
* "vim c:/" work. */
@@ -1310,10 +1322,12 @@ int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file,
}
}
- if (did_expand_in_path && !GA_EMPTY(&ga) && (flags & EW_PATH))
+ if (did_expand_in_path && !GA_EMPTY(&ga) && (flags & EW_PATH)) {
uniquefy_paths(&ga, p);
- if (p != pat[i])
+ }
+ if (p != pat[i]) {
xfree(p);
+ }
}
*num_file = ga.ga_len;
@@ -1333,14 +1347,12 @@ static int vim_backtick(char_u *p)
return *p == '`' && *(p + 1) != NUL && *(p + STRLEN(p) - 1) == '`';
}
-// Expand an item in `backticks` by executing it as a command.
-// Currently only works when pat[] starts and ends with a `.
-// Returns number of file names found, -1 if an error is encountered.
-static int expand_backtick(
- garray_T *gap,
- char_u *pat,
- int flags /* EW_* flags */
-)
+/// Expand an item in `backticks` by executing it as a command.
+/// Currently only works when pat[] starts and ends with a `.
+/// Returns number of file names found, -1 if an error is encountered.
+///
+/// @param flags EW_* flags
+static int expand_backtick(garray_T *gap, char_u *pat, int flags)
{
char_u *p;
char_u *buffer;
@@ -1349,11 +1361,11 @@ static int expand_backtick(
// Create the command: lop off the backticks.
char_u *cmd = vim_strnsave(pat + 1, STRLEN(pat) - 2);
- if (*cmd == '=') /* `={expr}`: Expand expression */
- buffer = eval_to_string(cmd + 1, &p, TRUE);
- else
- buffer = get_cmd_output(cmd, NULL,
- (flags & EW_SILENT) ? kShellOptSilent : 0, NULL);
+ if (*cmd == '=') { // `={expr}`: Expand expression
+ buffer = eval_to_string(cmd + 1, &p, true);
+ } else {
+ buffer = get_cmd_output(cmd, NULL, (flags & EW_SILENT) ? kShellOptSilent : 0, NULL);
+ }
xfree(cmd);
if (buffer == NULL) {
return -1;
@@ -1361,11 +1373,12 @@ static int expand_backtick(
cmd = buffer;
while (*cmd != NUL) {
- cmd = skipwhite(cmd); /* skip over white space */
+ cmd = skipwhite(cmd); // skip over white space
p = cmd;
- while (*p != NUL && *p != '\r' && *p != '\n') /* skip over entry */
+ while (*p != NUL && *p != '\r' && *p != '\n') { // skip over entry
++p;
- /* add an entry if it is not empty */
+ }
+ // add an entry if it is not empty
if (p > cmd) {
char_u i = *p;
*p = NUL;
@@ -1374,8 +1387,9 @@ static int expand_backtick(
++cnt;
}
cmd = p;
- while (*cmd != NUL && (*cmd == '\r' || *cmd == '\n'))
+ while (*cmd != NUL && (*cmd == '\r' || *cmd == '\n')) {
++cmd;
+ }
}
xfree(buffer);
@@ -1414,18 +1428,16 @@ void slash_adjust(char_u *p)
}
#endif
-// Add a file to a file list. Accepted flags:
-// EW_DIR add directories
-// EW_FILE add files
-// EW_EXEC add executable files
-// EW_NOTFOUND add even when it doesn't exist
-// EW_ADDSLASH add slash after directory name
-// EW_ALLLINKS add symlink also when the referred file does not exist
-void addfile(
- garray_T *gap,
- char_u *f, /* filename */
- int flags
-)
+/// Add a file to a file list. Accepted flags:
+/// EW_DIR add directories
+/// EW_FILE add files
+/// EW_EXEC add executable files
+/// EW_NOTFOUND add even when it doesn't exist
+/// EW_ADDSLASH add slash after directory name
+/// EW_ALLLINKS add symlink also when the referred file does not exist
+///
+/// @param f filename
+void addfile(garray_T *gap, char_u *f, int flags)
{
bool isdir;
FileInfo file_info;
@@ -1439,14 +1451,16 @@ void addfile(
}
#ifdef FNAME_ILLEGAL
- /* if the file/dir contains illegal characters, don't add it */
- if (vim_strpbrk(f, (char_u *)FNAME_ILLEGAL) != NULL)
+ // if the file/dir contains illegal characters, don't add it
+ if (vim_strpbrk(f, (char_u *)FNAME_ILLEGAL) != NULL) {
return;
+ }
#endif
isdir = os_isdir(f);
- if ((isdir && !(flags & EW_DIR)) || (!isdir && !(flags & EW_FILE)))
+ if ((isdir && !(flags & EW_DIR)) || (!isdir && !(flags & EW_FILE))) {
return;
+ }
// If the file isn't executable, may not add it. Do accept directories.
// When invoked from expand_shellcmd() do not use $PATH.
@@ -1464,8 +1478,9 @@ void addfile(
/*
* Append a slash or backslash after directory names if none is present.
*/
- if (isdir && (flags & EW_ADDSLASH))
+ if (isdir && (flags & EW_ADDSLASH)) {
add_pathsep((char *)p);
+ }
GA_APPEND(char_u *, gap, p);
}
@@ -1478,14 +1493,15 @@ void addfile(
void simplify_filename(char_u *filename)
{
int components = 0;
- char_u *p, *tail, *start;
+ char_u *p, *tail, *start;
bool stripping_disabled = false;
bool relative = true;
p = filename;
#ifdef BACKSLASH_IN_FILENAME
- if (p[1] == ':') /* skip "x:" */
+ if (p[1] == ':') { // skip "x:"
p += 2;
+ }
#endif
if (vim_ispathsep(*p)) {
@@ -1494,17 +1510,18 @@ void simplify_filename(char_u *filename)
++p;
while (vim_ispathsep(*p));
}
- start = p; /* remember start after "c:/" or "/" or "///" */
+ start = p; // remember start after "c:/" or "/" or "///"
do {
/* At this point "p" is pointing to the char following a single "/"
* or "p" is at the "start" of the (absolute or relative) path name. */
- if (vim_ispathsep(*p))
- STRMOVE(p, p + 1); /* remove duplicate "/" */
- else if (p[0] == '.' && (vim_ispathsep(p[1]) || p[1] == NUL)) {
- if (p == start && relative)
- p += 1 + (p[1] != NUL); /* keep single "." or leading "./" */
- else {
+ if (vim_ispathsep(*p)) {
+ STRMOVE(p, p + 1); // remove duplicate "/"
+ } else if (p[0] == '.' &&
+ (vim_ispathsep(p[1]) || p[1] == NUL)) {
+ if (p == start && relative) {
+ p += 1 + (p[1] != NUL); // keep single "." or leading "./"
+ } else {
/* Strip "./" or ".///". If we are at the end of the file name
* and there is no trailing path separator, either strip "/." if
* we are after "start", or strip "." if we are at the beginning
@@ -1527,11 +1544,11 @@ void simplify_filename(char_u *filename)
MB_PTR_ADV(tail);
}
- if (components > 0) { /* strip one preceding component */
+ if (components > 0) { // strip one preceding component
bool do_strip = false;
char_u saved_char;
- /* Don't strip for an erroneous file name. */
+ // Don't strip for an erroneous file name.
if (!stripping_disabled) {
/* If the preceding component does not exist in the file
* system, we strip it. On Unix, we don't accept a symbolic
@@ -1613,21 +1630,22 @@ void simplify_filename(char_u *filename)
*p++ = '.';
*p = NUL;
} else {
- if (p > start && tail[-1] == '.')
+ if (p > start && tail[-1] == '.') {
--p;
- STRMOVE(p, tail); /* strip previous component */
+ }
+ STRMOVE(p, tail); // strip previous component
}
--components;
}
- } else if (p == start && !relative) /* leading "/.." or "/../" */
- STRMOVE(p, tail); /* strip ".." or "../" */
- else {
- if (p == start + 2 && p[-2] == '.') { /* leading "./../" */
- STRMOVE(p - 2, p); /* strip leading "./" */
+ } else if (p == start && !relative) { // leading "/.." or "/../"
+ STRMOVE(p, tail); // strip ".." or "../"
+ } else {
+ if (p == start + 2 && p[-2] == '.') { // leading "./../"
+ STRMOVE(p - 2, p); // strip leading "./"
tail -= 2;
}
- p = tail; /* skip to char after ".." or "../" */
+ p = tail; // skip to char after ".." or "../"
}
} else {
components++; // Simple path component.
@@ -1639,31 +1657,24 @@ void simplify_filename(char_u *filename)
static char *eval_includeexpr(const char *const ptr, const size_t len)
{
set_vim_var_string(VV_FNAME, ptr, (ptrdiff_t)len);
- char *res = (char *)eval_to_string_safe(
- curbuf->b_p_inex, NULL,
- was_set_insecurely(curwin, (char_u *)"includeexpr", OPT_LOCAL));
+ char *res = (char *)eval_to_string_safe(curbuf->b_p_inex, NULL,
+ was_set_insecurely(curwin, (char_u *)"includeexpr",
+ OPT_LOCAL));
set_vim_var_string(VV_FNAME, NULL, 0);
return res;
}
-/*
- * Return the name of the file ptr[len] in 'path'.
- * Otherwise like file_name_at_cursor().
- */
-char_u *
-find_file_name_in_path (
- char_u *ptr,
- size_t len,
- int options,
- long count,
- char_u *rel_fname /* file we are searching relative to */
-)
+/// Return the name of the file ptr[len] in 'path'.
+/// Otherwise like file_name_at_cursor().
+///
+/// @param rel_fname file we are searching relative to
+char_u *find_file_name_in_path(char_u *ptr, size_t len, int options, long count, char_u *rel_fname)
{
char_u *file_name;
char_u *tofree = NULL;
if ((options & FNAME_INCL) && *curbuf->b_p_inex != NUL) {
- tofree = (char_u *) eval_includeexpr((char *) ptr, len);
+ tofree = (char_u *)eval_includeexpr((char *)ptr, len);
if (tofree != NULL) {
ptr = tofree;
len = STRLEN(ptr);
@@ -1680,7 +1691,7 @@ find_file_name_in_path (
*/
if (file_name == NULL
&& !(options & FNAME_INCL) && *curbuf->b_p_inex != NUL) {
- tofree = (char_u *) eval_includeexpr((char *) ptr, len);
+ tofree = (char_u *)eval_includeexpr((char *)ptr, len);
if (tofree != NULL) {
ptr = tofree;
len = STRLEN(ptr);
@@ -1701,8 +1712,9 @@ find_file_name_in_path (
xfree(file_name);
file_name = find_file_in_path(ptr, len, options, FALSE, rel_fname);
}
- } else
+ } else {
file_name = vim_strnsave(ptr, len);
+ }
xfree(tofree);
@@ -1714,10 +1726,11 @@ find_file_name_in_path (
// URL_BACKSLASH.
int path_is_url(const char *p)
{
- if (strncmp(p, "://", 3) == 0)
+ if (strncmp(p, "://", 3) == 0) {
return URL_SLASH;
- else if (strncmp(p, ":\\\\", 3) == 0)
+ } else if (strncmp(p, ":\\\\", 3) == 0) {
return URL_BACKSLASH;
+ }
return 0;
}
@@ -1735,7 +1748,9 @@ int path_with_url(const char *fname)
bool path_with_extension(const char *path, const char *extension)
{
const char *last_dot = strrchr(path, '.');
- if (!last_dot) { return false; }
+ if (!last_dot) {
+ return false;
+ }
return strcmp(last_dot + 1, extension) == 0;
}
@@ -1809,8 +1824,9 @@ char *fix_fname(const char *fname)
# ifdef BACKSLASH_IN_FILENAME
|| strstr(fname, "\\\\") != NULL
# endif
- )
+ ) {
return FullName_save(fname, false);
+ }
fname = xstrdup(fname);
@@ -1845,7 +1861,7 @@ void path_fix_case(char_u *name)
tail = name;
} else {
*slash = NUL;
- ok = os_scandir(&dir, (char *) name);
+ ok = os_scandir(&dir, (char *)name);
*slash = '/';
tail = slash + 1;
}
@@ -1855,7 +1871,7 @@ void path_fix_case(char_u *name)
}
char_u *entry;
- while ((entry = (char_u *) os_scandir_next(&dir))) {
+ while ((entry = (char_u *)os_scandir_next(&dir))) {
// Only accept names that differ in case and are the same byte
// length. TODO: accept different length name.
if (STRICMP(tail, entry) == 0 && STRLEN(tail) == STRLEN(entry)) {
@@ -1895,12 +1911,13 @@ int after_pathsep(const char *b, const char *p)
bool same_directory(char_u *f1, char_u *f2)
{
char_u ffname[MAXPATHL];
- char_u *t1;
- char_u *t2;
+ char_u *t1;
+ char_u *t2;
- /* safety check */
- if (f1 == NULL || f2 == NULL)
+ // safety check
+ if (f1 == NULL || f2 == NULL) {
return false;
+ }
(void)vim_FullName((char *)f1, (char *)ffname, MAXPATHL, FALSE);
t1 = path_tail_with_sep(ffname);
@@ -1918,22 +1935,23 @@ int pathcmp(const char *p, const char *q, int maxlen)
{
int i, j;
int c1, c2;
- const char *s = NULL;
+ const char *s = NULL;
for (i = 0, j = 0; maxlen < 0 || (i < maxlen && j < maxlen);) {
c1 = PTR2CHAR((char_u *)p + i);
c2 = PTR2CHAR((char_u *)q + j);
- /* End of "p": check if "q" also ends or just has a slash. */
+ // End of "p": check if "q" also ends or just has a slash.
if (c1 == NUL) {
- if (c2 == NUL) /* full match */
+ if (c2 == NUL) { // full match
return 0;
+ }
s = q;
i = j;
break;
}
- /* End of "q": check if "p" just has a slash. */
+ // End of "q": check if "p" just has a slash.
if (c2 == NUL) {
s = p;
break;
@@ -1941,15 +1959,17 @@ int pathcmp(const char *p, const char *q, int maxlen)
if ((p_fic ? mb_toupper(c1) != mb_toupper(c2) : c1 != c2)
#ifdef BACKSLASH_IN_FILENAME
- /* consider '/' and '\\' to be equal */
+ // consider '/' and '\\' to be equal
&& !((c1 == '/' && c2 == '\\')
|| (c1 == '\\' && c2 == '/'))
#endif
) {
- if (vim_ispathsep(c1))
+ if (vim_ispathsep(c1)) {
return -1;
- if (vim_ispathsep(c2))
+ }
+ if (vim_ispathsep(c2)) {
return 1;
+ }
return p_fic ? mb_toupper(c1) - mb_toupper(c2)
: c1 - c2; // no match
}
@@ -2057,26 +2077,27 @@ char_u *path_shorten_fname(char_u *full_path, char_u *dir_name)
/// If FAIL is returned, *num_file and *file are either
/// unchanged or *num_file is set to 0 and *file is set
/// to NULL or points to "".
-int expand_wildcards_eval(char_u **pat, int *num_file, char_u ***file,
- int flags)
+int expand_wildcards_eval(char_u **pat, int *num_file, char_u ***file, int flags)
{
int ret = FAIL;
- char_u *eval_pat = NULL;
- char_u *exp_pat = *pat;
- char_u *ignored_msg;
+ char_u *eval_pat = NULL;
+ char_u *exp_pat = *pat;
+ char_u *ignored_msg;
size_t usedlen;
if (*exp_pat == '%' || *exp_pat == '#' || *exp_pat == '<') {
++emsg_off;
eval_pat = eval_vars(exp_pat, exp_pat, &usedlen,
- NULL, &ignored_msg, NULL);
+ NULL, &ignored_msg, NULL);
--emsg_off;
- if (eval_pat != NULL)
+ if (eval_pat != NULL) {
exp_pat = concat_str(eval_pat, exp_pat + usedlen);
+ }
}
- if (exp_pat != NULL)
+ if (exp_pat != NULL) {
ret = expand_wildcards(1, &exp_pat, num_file, file, flags);
+ }
if (eval_pat != NULL) {
xfree(exp_pat);
@@ -2100,25 +2121,25 @@ int expand_wildcards_eval(char_u **pat, int *num_file, char_u ***file,
/// If FAIL is returned, *num_file and *file are either
/// unchanged or *num_file is set to 0 and *file is set to
/// NULL or points to "".
-int expand_wildcards(int num_pat, char_u **pat, int *num_files, char_u ***files,
- int flags)
+int expand_wildcards(int num_pat, char_u **pat, int *num_files, char_u ***files, int flags)
{
int retval;
int i, j;
- char_u *p;
- int non_suf_match; /* number without matching suffix */
+ char_u *p;
+ int non_suf_match; // number without matching suffix
retval = gen_expand_wildcards(num_pat, pat, num_files, files, flags);
- /* When keeping all matches, return here */
- if ((flags & EW_KEEPALL) || retval == FAIL)
+ // When keeping all matches, return here
+ if ((flags & EW_KEEPALL) || retval == FAIL) {
return retval;
+ }
/*
* Remove names that match 'wildignore'.
*/
if (*p_wig) {
- char_u *ffname;
+ char_u *ffname;
// check all files in (*files)[]
assert(*num_files == 0 || *files != NULL);
@@ -2183,7 +2204,7 @@ int match_suffix(char_u *fname)
if (setsuflen == 0) {
char_u *tail = path_tail(fname);
- /* empty entry: match name without a '.' */
+ // empty entry: match name without a '.'
if (vim_strchr(tail, '.') == NULL) {
setsuflen = 1;
break;
@@ -2209,13 +2230,13 @@ int path_full_dir_name(char *directory, char *buffer, size_t len)
int retval = OK;
if (STRLEN(directory) == 0) {
- return os_dirname((char_u *) buffer, len);
+ return os_dirname((char_u *)buffer, len);
}
char old_dir[MAXPATHL];
// Get current directory name.
- if (os_dirname((char_u *) old_dir, MAXPATHL) == FAIL) {
+ if (os_dirname((char_u *)old_dir, MAXPATHL) == FAIL) {
return FAIL;
}
@@ -2229,7 +2250,7 @@ int path_full_dir_name(char *directory, char *buffer, size_t len)
retval = FAIL;
}
- if (retval == FAIL || os_dirname((char_u *) buffer, len) == FAIL) {
+ if (retval == FAIL || os_dirname((char_u *)buffer, len) == FAIL) {
// Do not return immediately since we are in the wrong directory.
retval = FAIL;
}
@@ -2283,14 +2304,13 @@ int append_path(char *path, const char *to_append, size_t max_len)
/// @param force also expand when "fname" is already absolute.
///
/// @return FAIL for failure, OK for success.
-static int path_to_absolute(const char_u *fname, char_u *buf, size_t len,
- int force)
+static int path_to_absolute(const char_u *fname, char_u *buf, size_t len, int force)
{
char_u *p;
*buf = NUL;
char *relative_directory = xmalloc(len);
- char *end_of_path = (char *) fname;
+ char *end_of_path = (char *)fname;
// expand it if forced or not an absolute path
if (force || !path_is_absolute(fname)) {
@@ -2311,13 +2331,13 @@ static int path_to_absolute(const char_u *fname, char_u *buf, size_t len,
memcpy(relative_directory, fname, (size_t)(p - fname));
relative_directory[p-fname] = NUL;
}
- end_of_path = (char *) (p + 1);
+ end_of_path = (char *)(p + 1);
} else {
relative_directory[0] = NUL;
- end_of_path = (char *) fname;
+ end_of_path = (char *)fname;
}
- if (FAIL == path_full_dir_name(relative_directory, (char *) buf, len)) {
+ if (FAIL == path_full_dir_name(relative_directory, (char *)buf, len)) {
xfree(relative_directory);
return FAIL;
}
diff --git a/src/nvim/plines.c b/src/nvim/plines.c
new file mode 100644
index 0000000000..5b0418ed92
--- /dev/null
+++ b/src/nvim/plines.c
@@ -0,0 +1,510 @@
+// 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
+
+// plines.c: calculate the vertical and horizontal size of text in a window
+
+#include <assert.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include "nvim/ascii.h"
+#include "nvim/buffer.h"
+#include "nvim/charset.h"
+#include "nvim/cursor.h"
+#include "nvim/decoration.h"
+#include "nvim/diff.h"
+#include "nvim/fold.h"
+#include "nvim/func_attr.h"
+#include "nvim/indent.h"
+#include "nvim/main.h"
+#include "nvim/mbyte.h"
+#include "nvim/memline.h"
+#include "nvim/memory.h"
+#include "nvim/move.h"
+#include "nvim/option.h"
+#include "nvim/plines.h"
+#include "nvim/screen.h"
+#include "nvim/strings.h"
+#include "nvim/vim.h"
+#include "nvim/window.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "plines.c.generated.h"
+#endif
+
+/// Functions calculating vertical size of text when displayed inside a window.
+/// Calls horizontal size functions defined below.
+
+/// @param winheight when true limit to window height
+int plines_win(win_T *wp, linenr_T lnum, bool winheight)
+{
+ // Check for filler lines above this buffer line. When folded the result
+ // is one line anyway.
+ return plines_win_nofill(wp, lnum, winheight) + win_get_fill(wp, lnum);
+}
+
+
+/// Return the number of filler lines above "lnum".
+///
+/// @param wp
+/// @param lnum
+///
+/// @return Number of filler lines above lnum
+int win_get_fill(win_T *wp, linenr_T lnum)
+{
+ int virt_lines = decor_virtual_lines(wp, lnum);
+
+ // be quick when there are no filler lines
+ if (diffopt_filler()) {
+ int n = diff_check(wp, lnum);
+
+ if (n > 0) {
+ return virt_lines+n;
+ }
+ }
+ return virt_lines;
+}
+
+bool win_may_fill(win_T *wp)
+{
+ return (wp->w_p_diff && diffopt_filler()) || wp->w_buffer->b_virt_line_mark;
+}
+
+/// @param winheight when true limit to window height
+int plines_win_nofill(win_T *wp, linenr_T lnum, bool winheight)
+{
+ if (!wp->w_p_wrap) {
+ return 1;
+ }
+
+ if (wp->w_width_inner == 0) {
+ return 1;
+ }
+
+ // A folded lines is handled just like an empty line.
+ if (lineFolded(wp, lnum)) {
+ return 1;
+ }
+
+ const int lines = plines_win_nofold(wp, lnum);
+ if (winheight && lines > wp->w_height_inner) {
+ return wp->w_height_inner;
+ }
+ return lines;
+}
+
+/// @Return number of window lines physical line "lnum" will occupy in window
+/// "wp". Does not care about folding, 'wrap' or 'diff'.
+int plines_win_nofold(win_T *wp, linenr_T lnum)
+{
+ char_u *s;
+ unsigned int col;
+ int width;
+
+ s = ml_get_buf(wp->w_buffer, lnum, false);
+ if (*s == NUL) { // empty line
+ return 1;
+ }
+ col = win_linetabsize(wp, s, MAXCOL);
+
+ // If list mode is on, then the '$' at the end of the line may take up one
+ // extra column.
+ if (wp->w_p_list && wp->w_p_lcs_chars.eol != NUL) {
+ col += 1;
+ }
+
+ // Add column offset for 'number', 'relativenumber' and 'foldcolumn'.
+ width = wp->w_width_inner - win_col_off(wp);
+ if (width <= 0 || col > 32000) {
+ return 32000; // bigger than the number of screen columns
+ }
+ if (col <= (unsigned int)width) {
+ return 1;
+ }
+ col -= (unsigned int)width;
+ width += win_col_off2(wp);
+ assert(col <= INT_MAX && (int)col < INT_MAX - (width -1));
+ return ((int)col + (width - 1)) / width + 1;
+}
+
+/// Like plines_win(), but only reports the number of physical screen lines
+/// used from the start of the line to the given column number.
+int plines_win_col(win_T *wp, linenr_T lnum, long column)
+{
+ // Check for filler lines above this buffer line. When folded the result
+ // is one line anyway.
+ int lines = win_get_fill(wp, lnum);
+
+ if (!wp->w_p_wrap) {
+ return lines + 1;
+ }
+
+ if (wp->w_width_inner == 0) {
+ return lines + 1;
+ }
+
+ char_u *line = ml_get_buf(wp->w_buffer, lnum, false);
+ char_u *s = line;
+
+ colnr_T col = 0;
+ while (*s != NUL && --column >= 0) {
+ col += win_lbr_chartabsize(wp, line, s, col, NULL);
+ MB_PTR_ADV(s);
+ }
+
+ // If *s is a TAB, and the TAB is not displayed as ^I, and we're not in
+ // INSERT mode, then col must be adjusted so that it represents the last
+ // screen position of the TAB. This only fixes an error when the TAB wraps
+ // from one screen line to the next (when 'columns' is not a multiple of
+ // 'ts') -- webb.
+ if (*s == TAB && (State & NORMAL)
+ && (!wp->w_p_list || wp->w_p_lcs_chars.tab1)) {
+ col += win_lbr_chartabsize(wp, line, s, col, NULL) - 1;
+ }
+
+ // Add column offset for 'number', 'relativenumber', 'foldcolumn', etc.
+ int width = wp->w_width_inner - win_col_off(wp);
+ if (width <= 0) {
+ return 9999;
+ }
+
+ lines += 1;
+ if (col > width) {
+ lines += (col - width) / (width + win_col_off2(wp)) + 1;
+ }
+ return lines;
+}
+
+/// Get the number of screen lines lnum takes up. This takes care of
+/// both folds and topfill, and limits to the current window height.
+///
+/// @param[in] wp window line is in
+/// @param[in] lnum line number
+/// @param[out] nextp if not NULL, the line after a fold
+/// @param[out] foldedp if not NULL, whether lnum is on a fold
+/// @param[in] cache whether to use the window's cache for folds
+///
+/// @return the total number of screen lines
+int plines_win_full(win_T *wp, linenr_T lnum, linenr_T *const nextp, bool *const foldedp,
+ const bool cache)
+{
+ bool folded = hasFoldingWin(wp, lnum, NULL, nextp, cache, NULL);
+ if (foldedp) {
+ *foldedp = folded;
+ }
+ if (folded) {
+ return 1;
+ } else if (lnum == wp->w_topline) {
+ return plines_win_nofill(wp, lnum, true) + wp->w_topfill;
+ }
+ return plines_win(wp, lnum, true);
+}
+
+int plines_m_win(win_T *wp, linenr_T first, linenr_T last)
+{
+ int count = 0;
+
+ while (first <= last) {
+ linenr_T next = first;
+ count += plines_win_full(wp, first, &next, NULL, false);
+ first = next + 1;
+ }
+ return count;
+}
+
+/// Functions calculating horizontal size of text, when displayed in a window.
+
+/// Return the number of characters 'c' will take on the screen, taking
+/// into account the size of a tab.
+/// Also see getvcol()
+///
+/// @param p
+/// @param col
+///
+/// @return Number of characters.
+int win_chartabsize(win_T *wp, char_u *p, colnr_T col)
+{
+ buf_T *buf = wp->w_buffer;
+ if (*p == TAB && (!wp->w_p_list || wp->w_p_lcs_chars.tab1)) {
+ return tabstop_padding(col, buf->b_p_ts, buf->b_p_vts_array);
+ } else {
+ return ptr2cells(p);
+ }
+}
+
+/// Return the number of characters the string 's' will take on the screen,
+/// taking into account the size of a tab.
+///
+/// @param s
+///
+/// @return Number of characters the string will take on the screen.
+int linetabsize(char_u *s)
+{
+ return linetabsize_col(0, s);
+}
+
+/// Like linetabsize(), but starting at column "startcol".
+///
+/// @param startcol
+/// @param s
+///
+/// @return Number of characters the string will take on the screen.
+int linetabsize_col(int startcol, char_u *s)
+{
+ colnr_T col = startcol;
+ char_u *line = s; // pointer to start of line, for breakindent
+
+ while (*s != NUL) {
+ col += lbr_chartabsize_adv(line, &s, col);
+ }
+ return (int)col;
+}
+
+/// Like linetabsize(), but for a given window instead of the current one.
+///
+/// @param wp
+/// @param line
+/// @param len
+///
+/// @return Number of characters the string will take on the screen.
+unsigned int win_linetabsize(win_T *wp, char_u *line, colnr_T len)
+{
+ colnr_T col = 0;
+
+ for (char_u *s = line;
+ *s != NUL && (len == MAXCOL || s < line + len);
+ MB_PTR_ADV(s)) {
+ col += win_lbr_chartabsize(wp, line, s, col, NULL);
+ }
+
+ return (unsigned int)col;
+}
+
+/// like win_chartabsize(), but also check for line breaks on the screen
+///
+/// @param line
+/// @param s
+/// @param col
+///
+/// @return The number of characters taken up on the screen.
+int lbr_chartabsize(char_u *line, unsigned char *s, colnr_T col)
+{
+ if (!curwin->w_p_lbr && *get_showbreak_value(curwin) == NUL
+ && !curwin->w_p_bri) {
+ if (curwin->w_p_wrap) {
+ return win_nolbr_chartabsize(curwin, s, col, NULL);
+ }
+ return win_chartabsize(curwin, s, col);
+ }
+ return win_lbr_chartabsize(curwin, line == NULL ? s: line, s, col, NULL);
+}
+
+/// Call lbr_chartabsize() and advance the pointer.
+///
+/// @param line
+/// @param s
+/// @param col
+///
+/// @return The number of characters take up on the screen.
+int lbr_chartabsize_adv(char_u *line, char_u **s, colnr_T col)
+{
+ int retval;
+
+ retval = lbr_chartabsize(line, *s, col);
+ MB_PTR_ADV(*s);
+ return retval;
+}
+
+/// This function is used very often, keep it fast!!!!
+///
+/// If "headp" not NULL, set *headp to the size of what we for 'showbreak'
+/// string at start of line. Warning: *headp is only set if it's a non-zero
+/// value, init to 0 before calling.
+///
+/// @param wp
+/// @param line
+/// @param s
+/// @param col
+/// @param headp
+///
+/// @return The number of characters taken up on the screen.
+int win_lbr_chartabsize(win_T *wp, char_u *line, char_u *s, colnr_T col, int *headp)
+{
+ colnr_T col2;
+ colnr_T col_adj = 0; // col + screen size of tab
+ colnr_T colmax;
+ int added;
+ int mb_added = 0;
+ int numberextra;
+ char_u *ps;
+ int n;
+
+ // No 'linebreak', 'showbreak' and 'breakindent': return quickly.
+ if (!wp->w_p_lbr && !wp->w_p_bri && *get_showbreak_value(wp) == NUL) {
+ if (wp->w_p_wrap) {
+ return win_nolbr_chartabsize(wp, s, col, headp);
+ }
+ return win_chartabsize(wp, s, col);
+ }
+
+ // First get normal size, without 'linebreak'
+ int size = win_chartabsize(wp, s, col);
+ int c = *s;
+ if (*s == TAB) {
+ col_adj = size - 1;
+ }
+
+ // If 'linebreak' set check at a blank before a non-blank if the line
+ // needs a break here
+ if (wp->w_p_lbr
+ && vim_isbreak(c)
+ && !vim_isbreak((int)s[1])
+ && wp->w_p_wrap
+ && (wp->w_width_inner != 0)) {
+ // Count all characters from first non-blank after a blank up to next
+ // non-blank after a blank.
+ numberextra = win_col_off(wp);
+ col2 = col;
+ colmax = (colnr_T)(wp->w_width_inner - numberextra - col_adj);
+
+ if (col >= colmax) {
+ colmax += col_adj;
+ n = colmax + win_col_off2(wp);
+
+ if (n > 0) {
+ colmax += (((col - colmax) / n) + 1) * n - col_adj;
+ }
+ }
+
+ for (;;) {
+ ps = s;
+ MB_PTR_ADV(s);
+ c = *s;
+
+ if (!(c != NUL
+ && (vim_isbreak(c) || col2 == col || !vim_isbreak((int)(*ps))))) {
+ break;
+ }
+
+ col2 += win_chartabsize(wp, s, col2);
+
+ if (col2 >= colmax) { // doesn't fit
+ size = colmax - col + col_adj;
+ break;
+ }
+ }
+ } else if ((size == 2)
+ && (MB_BYTE2LEN(*s) > 1)
+ && wp->w_p_wrap
+ && in_win_border(wp, col)) {
+ // Count the ">" in the last column.
+ size++;
+ mb_added = 1;
+ }
+
+ // May have to add something for 'breakindent' and/or 'showbreak'
+ // string at start of line.
+ // Set *headp to the size of what we add.
+ added = 0;
+
+ char_u *const sbr = get_showbreak_value(wp);
+ if ((*sbr != NUL || wp->w_p_bri) && wp->w_p_wrap && col != 0) {
+ colnr_T sbrlen = 0;
+ int numberwidth = win_col_off(wp);
+
+ numberextra = numberwidth;
+ col += numberextra + mb_added;
+
+ if (col >= (colnr_T)wp->w_width_inner) {
+ col -= wp->w_width_inner;
+ numberextra = wp->w_width_inner - (numberextra - win_col_off2(wp));
+ if (col >= numberextra && numberextra > 0) {
+ col %= numberextra;
+ }
+ if (*sbr != NUL) {
+ sbrlen = (colnr_T)MB_CHARLEN(sbr);
+ if (col >= sbrlen) {
+ col -= sbrlen;
+ }
+ }
+ if (col >= numberextra && numberextra > 0) {
+ col %= numberextra;
+ } else if (col > 0 && numberextra > 0) {
+ col += numberwidth - win_col_off2(wp);
+ }
+
+ numberwidth -= win_col_off2(wp);
+ }
+
+ if (col == 0 || (col + size + sbrlen > (colnr_T)wp->w_width_inner)) {
+ if (*sbr != NUL) {
+ if (size + sbrlen + numberwidth > (colnr_T)wp->w_width_inner) {
+ // Calculate effective window width.
+ int width = (colnr_T)wp->w_width_inner - sbrlen - numberwidth;
+ int prev_width = col ? ((colnr_T)wp->w_width_inner - (sbrlen + col))
+ : 0;
+
+ if (width <= 0) {
+ width = 1;
+ }
+ added += ((size - prev_width) / width) * vim_strsize(sbr);
+ if ((size - prev_width) % width) {
+ // Wrapped, add another length of 'sbr'.
+ added += vim_strsize(sbr);
+ }
+ } else {
+ added += vim_strsize(sbr);
+ }
+ }
+
+ if (wp->w_p_bri) {
+ added += get_breakindent_win(wp, line);
+ }
+
+ size += added;
+ if (col != 0) {
+ added = 0;
+ }
+ }
+ }
+
+ if (headp != NULL) {
+ *headp = added + mb_added;
+ }
+ return size;
+}
+
+/// Like win_lbr_chartabsize(), except that we know 'linebreak' is off and
+/// 'wrap' is on. This means we need to check for a double-byte character that
+/// doesn't fit at the end of the screen line.
+///
+/// @param wp
+/// @param s
+/// @param col
+/// @param headp
+///
+/// @return The number of characters take up on the screen.
+static int win_nolbr_chartabsize(win_T *wp, char_u *s, colnr_T col, int *headp)
+{
+ int n;
+
+ if ((*s == TAB) && (!wp->w_p_list || wp->w_p_lcs_chars.tab1)) {
+ return tabstop_padding(col,
+ wp->w_buffer->b_p_ts,
+ wp->w_buffer->b_p_vts_array);
+ }
+ n = ptr2cells(s);
+
+ // Add one cell for a double-width character in the last column of the
+ // window, displayed with a ">".
+ if ((n == 2) && (MB_BYTE2LEN(*s) > 1) && in_win_border(wp, col)) {
+ if (headp != NULL) {
+ *headp = 1;
+ }
+ return 3;
+ }
+ return n;
+}
+
diff --git a/src/nvim/plines.h b/src/nvim/plines.h
new file mode 100644
index 0000000000..32778b69f1
--- /dev/null
+++ b/src/nvim/plines.h
@@ -0,0 +1,9 @@
+#ifndef NVIM_PLINES_H
+#define NVIM_PLINES_H
+
+#include "nvim/vim.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "plines.h.generated.h"
+#endif
+#endif // NVIM_PLINES_H
diff --git a/src/nvim/po/sr.po b/src/nvim/po/sr.po
index 1450ab5164..d34c1c3100 100644
--- a/src/nvim/po/sr.po
+++ b/src/nvim/po/sr.po
@@ -2,7 +2,7 @@
#
# Do ":help uganda" in Vim to read copying and usage conditions.
# Do ":help credits" in Vim to see a list of people who contributed.
-# Copyright (C) 2017
+# Copyright (C) 2021
# This file is distributed under the same license as the Vim package.
# FIRST AUTHOR Ivan Pešić <ivan.pesic@gmail.com>, 2017.
#
@@ -10,8 +10,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Vim(Serbian)\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2021-02-14 01:49+0400\n"
-"PO-Revision-Date: 2021-02-14 01:54+0400\n"
+"POT-Creation-Date: 2021-06-13 13:16+0400\n"
+"PO-Revision-Date: 2021-06-13 13:50+0400\n"
"Last-Translator: Ivan Pešić <ivan.pesic@gmail.com>\n"
"Language-Team: Serbian\n"
"Language: sr\n"
@@ -97,6 +97,9 @@ msgstr "Извршавање %s"
msgid "autocommand %s"
msgstr "аутокоманда %s"
+msgid "E972: Blob value does not have the right number of bytes"
+msgstr "E972: Блоб вредност нема одговарајући број бајтова"
+
msgid "E831: bf_key_init() called with empty password"
msgstr "E831: bf_key_init() је позвана са празном лозинком"
@@ -866,7 +869,7 @@ msgid "E976: using Blob as a String"
msgstr "E976: коришћење Blob као String"
msgid "E908: using an invalid value as a String"
-msgstr "E908: користи се недозвољена вредност као String"
+msgstr "E908: Користи се неважећа вредност као Стринг: %s"
msgid "E698: variable nested too deep for making a copy"
msgstr "E698: променљива је предубоко угњеждена да би се направила копија"
@@ -913,7 +916,7 @@ msgid "E928: String required"
msgstr "E928: Захтева се String"
msgid "E808: Number or Float required"
-msgstr "E808: Захтева се Number или Float"
+msgstr "E808: Захтева се Број или Покретни"
msgid "add() argument"
msgstr "add() аргумент"
@@ -1130,6 +1133,9 @@ msgstr ""
"\n"
"# Преградне линије, копиране дословно:\n"
+msgid "E503: \"%s\" is not a file or writable device"
+msgstr "E503: „%s” није фајл или уређај на који може да се уписује"
+
msgid "Save As"
msgstr "Сачувај као"
@@ -4635,12 +4641,12 @@ msgstr "E531: Користите \":gui\" да покренете GUI"
msgid "E589: 'backupext' and 'patchmode' are equal"
msgstr "E589: 'backupext' и 'patchmode' су истоветни"
-msgid "E834: Conflicts with value of 'listchars'"
-msgstr "E834: У конфликту са вредношћу 'listchars'"
-
msgid "E835: Conflicts with value of 'fillchars'"
msgstr "E835: У конфликту са вредношћу 'fillchars'"
+msgid "E834: Conflicts with value of 'listchars'"
+msgstr "E834: У конфликту са вредношћу 'listchars'"
+
msgid "E617: Cannot be changed in the GTK+ 2 GUI"
msgstr "E617: Не може да се промени у GTK+ 2 GUI"
@@ -5064,7 +5070,7 @@ msgstr "E554: Синтаксна грешка у %s{...}"
#, c-format
msgid "E888: (NFA regexp) cannot repeat %s"
-msgstr "E888: (NFA regexp) не може да се понови %s"
+msgstr "E888: (НКА регуларни израз) не може да се понови %s"
msgid ""
"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be "
@@ -5130,15 +5136,15 @@ msgid "External submatches:\n"
msgstr "Спољна подпоклапања:\n"
msgid "E865: (NFA) Regexp end encountered prematurely"
-msgstr "E865: Крај (NFA) Regexp израза је достигнут прерано"
+msgstr "E865: (НКА) прерано је достигнут крај регуларног израза"
#, c-format
msgid "E866: (NFA regexp) Misplaced %c"
-msgstr "E866: (NFA regexp) %c је на погрешном месту"
+msgstr "E866: (НКА регуларни израз) %c је на погрешном месту"
#, c-format
msgid "E877: (NFA regexp) Invalid character class: %d"
-msgstr "E877: (NFA regexp) Неважећа карактер класа: %d"
+msgstr "E877: (НКА регуларни израз) Неважећа карактер класа: %d"
#, c-format
msgid "E867: (NFA) Unknown operator '\\z%c'"
@@ -6422,6 +6428,13 @@ msgstr "E853: Име аргумента је дуплирано: %s"
msgid "E989: Non-default argument follows default argument"
msgstr "E989: Неподразумевани аргумент следи иза подразумеваног аргумента"
+msgid "E126: Missing :endfunction"
+msgstr "E126: Недостаје :endfunction"
+
+#, c-format
+msgid "W22: Text found after :endfunction: %s"
+msgstr "W22: Пронађен текст након :endfunction: %s"
+
#, c-format
msgid "E451: Expected }: %s"
msgstr "E451: Очекује се }: %s"
@@ -6497,17 +6510,6 @@ msgstr "E862: Овде не може да се користи g:"
msgid "E932: Closure function should not be at top level: %s"
msgstr "E932: Затварајућа функција не би требало да буде на највишем нивоу: %s"
-msgid "E126: Missing :endfunction"
-msgstr "E126: Недостаје :endfunction"
-
-#, c-format
-msgid "W1001: Text found after :enddef: %s"
-msgstr "W1001: Пронађен је текст након :enddef: %s"
-
-#, c-format
-msgid "W22: Text found after :endfunction: %s"
-msgstr "W22: Пронађен текст након :endfunction: %s"
-
#, c-format
msgid "E707: Function name conflicts with variable: %s"
msgstr "E707: Име функције је у конфликту са променљивом: %s"
@@ -6983,8 +6985,8 @@ msgid "E475: Invalid value for argument %s: %s"
msgstr "E475: Неважећа вредност за аргумент %s: %s"
#, c-format
-msgid "E15: Invalid expression: %s"
-msgstr "E15: Неважећи израз: %s"
+msgid "E15: Invalid expression: \"%s\""
+msgstr "E15: Неважећи израз: „%s”"
msgid "E16: Invalid range"
msgstr "E16: Неважећи опсег"
diff --git a/src/nvim/po/tr.po b/src/nvim/po/tr.po
index 3db3cbfef0..e1fef00863 100644
--- a/src/nvim/po/tr.po
+++ b/src/nvim/po/tr.po
@@ -1,16 +1,16 @@
# Turkish translations for Vim
# Vim Türkçe çevirileri
-# Copyright (C) 2020 Emir SARI <bitigchi@me.com>
+# Copyright (C) 2021 Emir SARI <emir_sari@msn.com>
# This file is distributed under the same license as the Vim package.
-# Emir SARI <bitigchi@me.com>, 2019-2020
+# Emir SARI <emir_sari@msn.com>, 2019-2021
#
msgid ""
msgstr ""
"Project-Id-Version: Vim Turkish Localization Project\n"
-"Report-Msgid-Bugs-To: Emir SARI <bitigchi@me.com>\n"
-"POT-Creation-Date: 2020-11-29 00:20+0300\n"
-"PO-Revision-Date: 2020-11-29 20:00+0300\n"
-"Last-Translator: Emir SARI <bitigchi@me.com>\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2021-07-16 17:56+0300\n"
+"PO-Revision-Date: 2021-07-16 20:00+0300\n"
+"Last-Translator: Emir SARI <emir_sari@msn.com>\n"
"Language-Team: Turkish <https://github.com/bitigchi/vim>\n"
"Language: tr\n"
"MIME-Version: 1.0\n"
@@ -28,7 +28,7 @@ msgid "E165: Cannot go beyond last file"
msgstr "E165: Son dosyadan öteye gidilemez"
msgid "E610: No argument to delete"
-msgstr "E610: Silinecek bir değişken yok"
+msgstr "E610: Silinecek bir argüman yok"
msgid "E249: window layout changed unexpectedly"
msgstr "E249: Pencere yerleşimi beklenmedik bir biçimde değişti"
@@ -94,6 +94,9 @@ msgstr "%s çalıştırılıyor"
msgid "autocommand %s"
msgstr "%s otokomutu"
+msgid "E972: Blob value does not have the right number of bytes"
+msgstr "E972: İkili geniş nesne değeri doğru bayt sayısına sahip değil"
+
msgid "E831: bf_key_init() called with empty password"
msgstr "E831: bf_key_init() boş bir şifre ile çağrıldı"
@@ -131,6 +134,27 @@ msgstr "E931: Arabellek kaydedilemedi"
msgid "E937: Attempt to delete a buffer that is in use: %s"
msgstr "E937: Kullanımda olan bir arabellek silinmeye çalışılıyor: %s"
+msgid "E90: Cannot unload last buffer"
+msgstr "E90: Son arabellek bellekten kaldırılamıyor"
+
+msgid "E84: No modified buffer found"
+msgstr "E84: Değiştirilmiş bir arabellek bulunamadı"
+
+msgid "E85: There is no listed buffer"
+msgstr "E85: Listelenmiş bir arabellek yok"
+
+msgid "E87: Cannot go beyond last buffer"
+msgstr "E87: Son arabellekten öteye gidilemez"
+
+msgid "E88: Cannot go before first buffer"
+msgstr "E88: İlk arabellekten öncesine gidilemez"
+
+#, c-format
+msgid "E89: No write since last change for buffer %d (add ! to override)"
+msgstr ""
+"E89: %d numaralı arabellek son değişiklikten sonra yazılmadı (geçersiz "
+"kılmak için ! ekleyin)"
+
msgid "E515: No buffers were unloaded"
msgstr "E515: Hiçbir arabellek bellekten kaldırılmadı"
@@ -158,27 +182,6 @@ msgid_plural "%d buffers wiped out"
msgstr[0] "%d arabellek yok edildi"
msgstr[1] "%d arabellek yok edildi"
-msgid "E90: Cannot unload last buffer"
-msgstr "E90: Son arabellek bellekten kaldırılamıyor"
-
-msgid "E84: No modified buffer found"
-msgstr "E84: Değiştirilmiş bir arabellek bulunamadı"
-
-msgid "E85: There is no listed buffer"
-msgstr "E85: Listelenmiş bir arabellek yok"
-
-msgid "E87: Cannot go beyond last buffer"
-msgstr "E87: Son arabellekten öteye gidilemez"
-
-msgid "E88: Cannot go before first buffer"
-msgstr "E88: İlk arabellekten öncesine gidilemez"
-
-#, c-format
-msgid "E89: No write since last change for buffer %d (add ! to override)"
-msgstr ""
-"E89: %d numaralı arabellek son değişiklikten sonra yazılmadı (geçersiz "
-"kılmak için ! ekleyin)"
-
msgid "E948: Job still running (add ! to end the job)"
msgstr "E948: İş hâlâ sürüyor (bitirmek için ! ekleyin)"
@@ -424,13 +427,13 @@ msgid "E901: gethostbyname() in channel_open()"
msgstr "E901: channel_open() içinde gethostbyname()"
msgid "E903: received command with non-string argument"
-msgstr "E903: Dizi olmayan değişken içeren komut alındı"
+msgstr "E903: Dizi olmayan argüman içeren komut alındı"
msgid "E904: last argument for expr/call must be a number"
-msgstr "E904: İfadenin/çağrının son değişkeni bir sayı olmalıdır"
+msgstr "E904: İfadenin/çağrının son argüman bir sayı olmalıdır"
msgid "E904: third argument for call must be a list"
-msgstr "E904: Çağrının üçüncü değişkeni bir liste olmalıdır"
+msgstr "E904: Çağrının üçüncü argümanı bir liste olmalıdır"
#, c-format
msgid "E905: received unknown command: %s"
@@ -449,7 +452,7 @@ msgstr "E631: %s(): Yazma başarısız"
#, c-format
msgid "E917: Cannot use a callback with %s()"
-msgstr "E917: %s() ile geri çağırma kullanılamaz"
+msgstr "E917: %s() ile geri çağırma kullanılamıyor"
msgid "E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel"
msgstr "E912: ch_evalexpr()/ch_sendexpr() raw/nl kanalları ile kullanılamaz"
@@ -511,6 +514,11 @@ msgid "Warning: Using a weak encryption method; see :help 'cm'"
msgstr ""
"Uyarı: Zayıf bir şifreleme yöntemi kullanılıyor; bilgi için: :help 'cm'"
+msgid ""
+"Note: Encryption of swapfile not supported, disabling swap- and undofile"
+msgstr "Takas dosyası şifrelemesi desteklenmiyor, takas ve geri al dosyası "
+"devre dışı bırakılıyor"
+
msgid "Enter encryption key: "
msgstr "Şifreleme anahtarı girin: "
@@ -570,7 +578,7 @@ msgid "%3d expr %s"
msgstr "%3d ifade %s"
msgid "extend() argument"
-msgstr "extend() değişkeni"
+msgstr "extend() argümanı"
#, c-format
msgid "E737: Key already exists: %s"
@@ -728,9 +736,6 @@ msgstr "E708: [:] en son gelmelidir"
msgid "E709: [:] requires a List or Blob value"
msgstr "E709: [:] bir liste veya ikili geniş nesne değeri gerektirir"
-msgid "E972: Blob value does not have the right number of bytes"
-msgstr "E972: İkili geniş nesne değeri doğru bayt sayısına sahip değil"
-
msgid "E996: Cannot lock a range"
msgstr "E996: Erim kilitlenemiyor"
@@ -741,7 +746,7 @@ msgid "E260: Missing name after ->"
msgstr "E260: -> sonrası ad eksik"
msgid "E695: Cannot index a Funcref"
-msgstr "E695: Bir Funcref dizinlenemez"
+msgstr "E695: Bir Funcref dizinlenemiyor"
msgid "Not enough memory to set references, garbage collection aborted!"
msgstr "Referansları ayarlamak için yetersiz bellek, atık toplama durduruldu"
@@ -759,9 +764,6 @@ msgstr ""
"\n"
"\tEn son şuradan ayarlandı: "
-msgid "E808: Number or Float required"
-msgstr "E808: Sayı veya kayan noktalı değer gerekiyor"
-
#, c-format
msgid "E158: Invalid buffer name: %s"
msgstr "E158: Geçersiz arabellek adı: %s"
@@ -780,7 +782,7 @@ msgid "E922: expected a dict"
msgstr "E922: Bir sözlük bekleniyordu"
msgid "E923: Second argument of function() must be a list or a dict"
-msgstr "E923: function() ikinci değişkeni bir liste veya sözlük olmalıdır"
+msgstr "E923: function() ikinci argümanı bir liste veya sözlük olmalıdır"
msgid ""
"&OK\n"
@@ -882,7 +884,7 @@ msgid "E742: Cannot change value of %s"
msgstr "E742: %s değeri değiştirilemiyor"
msgid "E921: Invalid callback argument"
-msgstr "E921: Geçersiz geri çağırma değişkeni"
+msgstr "E921: Geçersiz geri çağırma argümanı"
#, c-format
msgid "<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s"
@@ -927,6 +929,10 @@ msgstr "E135: *Süzgeç* otokomutları şu anki arabelleği değiştirmemelidir"
msgid "[No write since last change]\n"
msgstr "[Son değişiklikten sonra yazılmadı]\n"
+#, c-format
+msgid "E503: \"%s\" is not a file or writable device"
+msgstr "E503: \"%s\", bir dosya veya yazılabilir aygıt değil"
+
msgid "Save As"
msgstr "Farklı Kaydet"
@@ -985,7 +991,7 @@ msgid "E143: Autocommands unexpectedly deleted new buffer %s"
msgstr "E143: yeni %s arabelleğini otokomutlar beklenmedik bir biçimde sildi"
msgid "E144: non-numeric argument to :z"
-msgstr "E144: :z için sayısal olmayan değişken"
+msgstr "E144: :z için sayısal olmayan argüman"
msgid "E145: Shell commands and some functionality not allowed in rvim"
msgstr "E145: rvim içinde kabuk komutları ve bazı işlevselliğe izin verilmez"
@@ -1091,9 +1097,6 @@ msgstr "Kaynak alınan dosyanın sonu"
msgid "End of function"
msgstr "İşlevin sonu"
-msgid "E464: Ambiguous use of user-defined command"
-msgstr "E464: Kullanıcı tanımlı komutun belirsiz kullanımı"
-
msgid "E492: Not an editor command"
msgstr "E492: Bir düzenleyici komutu değil"
@@ -1178,7 +1181,7 @@ msgid "E187: Unknown"
msgstr "E187: Bilinmeyen"
msgid "E465: :winsize requires two number arguments"
-msgstr "E465: :winsize iki adet sayı değişken gerektirir"
+msgstr "E465: :winsize iki adet sayı argüman gerektirir"
#, c-format
msgid "Window position: X %d, Y %d"
@@ -1188,7 +1191,7 @@ msgid "E188: Obtaining window position not implemented for this platform"
msgstr "E188: Pencere konumunu alma özelliği bu platformda mevcut değil"
msgid "E466: :winpos requires two number arguments"
-msgstr "E466: :winpos iki adet sayı değişken gerektirir"
+msgstr "E466: :winpos iki adet sayı argüman gerektirir"
msgid "E930: Cannot use :redir inside execute()"
msgstr "E930: :redir, execute() içinde kullanılamaz"
@@ -1340,6 +1343,9 @@ msgstr "E788: Şu anda başka bir arabellek düzenlenemez"
msgid "E811: Not allowed to change buffer information now"
msgstr "E811: Şu anda arabellek bilgisi değiştirilemez"
+msgid "[Command Line]"
+msgstr "[Komut Satırı]"
+
msgid "E199: Active window or buffer deleted"
msgstr "E199: Etkin pencere veya arabellek silinmiş"
@@ -1530,7 +1536,7 @@ msgid "E655: Too many symbolic links (cycle?)"
msgstr "E655: Çok fazla sembolik bağlantı (çevrim?)"
msgid "writefile() first argument must be a List or a Blob"
-msgstr "writefile() ilk değişkeni bir liste veya ikili geniş nesne olmalıdır"
+msgstr "writefile() ilk argümanı bir liste veya ikili geniş nesne olmalıdır"
msgid "Select Directory dialog"
msgstr "Dizin Seç iletişim kutusu"
@@ -1581,6 +1587,9 @@ msgstr "E446: İmleç altında bir dosya adı yok"
msgid "E447: Can't find file \"%s\" in path"
msgstr "E447: \"%s\" dosyası yol içinde bulunamadı"
+msgid "E808: Number or Float required"
+msgstr "E808: Sayı veya kayan noktalı değer gerekiyor"
+
msgid "E490: No fold found"
msgstr "E490: Kıvırma bulunamadı"
@@ -1805,7 +1814,7 @@ msgstr "E671: Pencere başlığı \"%s\" bulunamıyor"
#, c-format
msgid "E243: Argument not supported: \"-%s\"; Use the OLE version."
-msgstr "E243: \"-%s\" değişkeni desteklenmiyor; OLE sürümünü kullanın."
+msgstr "E243: \"-%s\" argümanı desteklenmiyor; OLE sürümünü kullanın."
msgid "E988: GUI cannot be used. Cannot execute gvim.exe."
msgstr "E988: Grafik arabirim kullanılamaz. gvim.exe çalıştırılamadı."
@@ -2042,11 +2051,11 @@ msgstr "E411: Vurgulama grubu bulunamadı: %s"
#, c-format
msgid "E412: Not enough arguments: \":highlight link %s\""
-msgstr "E412: Yetersiz sayıda değişken: \":highlight link %s\""
+msgstr "E412: Yetersiz sayıda argüman: \":highlight link %s\""
#, c-format
msgid "E413: Too many arguments: \":highlight link %s\""
-msgstr "E413: Çok fazla değişken: \":highlight link %s\""
+msgstr "E413: Çok fazla argüman: \":highlight link %s\""
msgid "E414: group has settings, highlight link ignored"
msgstr "E414: Grup ayarları mevcut, vurgulama bağlantısı yok sayıldı"
@@ -2061,7 +2070,7 @@ msgstr "E416: Eksik eşittir imi: %s"
#, c-format
msgid "E417: missing argument: %s"
-msgstr "E417: Eksik değişkenler: %s"
+msgstr "E417: Argüman eksik: %s"
#, c-format
msgid "E418: Illegal value: %s"
@@ -2086,7 +2095,7 @@ msgstr "E422: Uçbirim kodu çok uzun: %s"
#, c-format
msgid "E423: Illegal argument: %s"
-msgstr "E423: İzin verilmeyen değişken: %s"
+msgstr "E423: İzin verilmeyen argüman: %s"
msgid "E424: Too many different highlighting attributes in use"
msgstr "E424: Çok fazla değişik vurgulama kuralları kullanılıyor"
@@ -2295,7 +2304,7 @@ msgid "unknown option"
msgstr "bilinmeyen seçenek"
msgid "window index is out of range"
-msgstr "pencere dizini erimin dışında"
+msgstr "pencere sırası erimin dışında"
msgid "couldn't open buffer"
msgstr "arabellek açılamadı"
@@ -2513,9 +2522,6 @@ msgstr " Dahili anahtar sözcük tamamlaması (^N^P)"
msgid "Hit end of paragraph"
msgstr "Paragrafın sonuna varıldı"
-msgid "E839: Completion function changed window"
-msgstr "E839: Tamamlama işlevi pencereyi değiştirdi"
-
msgid "E840: Completion function deleted text"
msgstr "E840: Tamamlama işlevi metni sildi"
@@ -2594,23 +2600,23 @@ msgstr "E938: JSON'da yinelenmiş anahtar: \"%s\""
#, c-format
msgid "E899: Argument of %s must be a List or Blob"
-msgstr "E899: %s değişkeni bir liste veya ikili geniş nesne olmalıdır"
+msgstr "E899: %s argümanı bir liste veya ikili geniş nesne olmalıdır"
msgid "E900: maxdepth must be non-negative number"
msgstr "E900: maxdepth negatif olmayan bir sayı olmalı"
msgid "flatten() argument"
-msgstr "flatten() değişkeni"
+msgstr "flatten() argümanı"
#, c-format
msgid "E696: Missing comma in List: %s"
msgstr "E696: Listede virgül eksik: %s"
msgid "sort() argument"
-msgstr "sort() değişkeni"
+msgstr "sort() argümanı"
msgid "uniq() argument"
-msgstr "uniq() değişkeni"
+msgstr "uniq() argümanı"
msgid "E702: Sort compare function failed"
msgstr "E702: Sıralayıp karşılaştırma işlevi başarısız oldu"
@@ -2619,25 +2625,28 @@ msgid "E882: Uniq compare function failed"
msgstr "E882: Benzersizlik karşılaştırma işlevi başarısız oldu"
msgid "map() argument"
-msgstr "map() değişkeni"
+msgstr "map() argümanı"
msgid "mapnew() argument"
-msgstr "mapnew() değişkeni"
+msgstr "mapnew() argümanı"
msgid "filter() argument"
-msgstr "filter() değişkeni"
+msgstr "filter() argümanı"
msgid "add() argument"
-msgstr "add() değişkeni"
+msgstr "add() argümanı"
+
+msgid "extendnew() argument"
+msgstr "extendnew() argümanı"
msgid "insert() argument"
-msgstr "insert() değişkeni"
+msgstr "insert() argümanı"
msgid "remove() argument"
-msgstr "remove() değişkeni"
+msgstr "remove() argümanı"
msgid "reverse() argument"
-msgstr "reverse() değişkeni"
+msgstr "reverse() argümanı"
#, c-format
msgid "Current %slanguage: \"%s\""
@@ -2648,22 +2657,22 @@ msgid "E197: Cannot set language to \"%s\""
msgstr "E197: \"%s\" diline ayarlanamıyor"
msgid "Unknown option argument"
-msgstr "Bilinmeyen seçenek değişkeni"
+msgstr "Bilinmeyen seçenek argümanı"
msgid "Too many edit arguments"
-msgstr "Çok fazla düzenleme değişkeni"
+msgstr "Çok fazla düzenleme argümanı"
msgid "Argument missing after"
-msgstr "Şundan sonra değişken eksik:"
+msgstr "Şundan sonra argüman eksik:"
msgid "Garbage after option argument"
-msgstr "Seçenek değişkeninden sonra anlamsız veri"
+msgstr "Seçenek argümanından sonra anlamsız veri"
msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"
-msgstr "Çok fazla \"+komut\", \"-c komut\" veya \"--cmd komut\" değişkeni"
+msgstr "Çok fazla \"+komut\", \"-c komut\" veya \"--cmd komut\" argümanı"
msgid "Invalid argument for"
-msgstr "Şunun için geçersiz değişken:"
+msgstr "Şunun için geçersiz argüman:"
#, c-format
msgid "%d files to edit\n"
@@ -2735,7 +2744,7 @@ msgstr ""
"Kullanım:"
msgid " vim [arguments] "
-msgstr " vim [değişkenler] "
+msgstr " vim [argümanlar] "
msgid ""
"\n"
@@ -2967,21 +2976,21 @@ msgid ""
"Arguments recognised by gvim (Motif version):\n"
msgstr ""
"\n"
-"gvim tarafından tanınan değişkenler (Motif sürümü):\n"
+"gvim tarafından tanınan argümanlar (Motif sürümü):\n"
msgid ""
"\n"
"Arguments recognised by gvim (neXtaw version):\n"
msgstr ""
"\n"
-"gvim tarafından tanınan değişkenler (neXtaw sürümü):\n"
+"gvim tarafından tanınan argümanlar (neXtaw sürümü):\n"
msgid ""
"\n"
"Arguments recognised by gvim (Athena version):\n"
msgstr ""
"\n"
-"gvim tarafından tanınan değişkenler (Athena sürümü):\n"
+"gvim tarafından tanınan argümanlar (Athena sürümü):\n"
msgid "-display <display>\tRun Vim on <display>"
msgstr "-display <ekran>\tVim'i <ekran>'da çalıştır"
@@ -3032,7 +3041,7 @@ msgid ""
"Arguments recognised by gvim (GTK+ version):\n"
msgstr ""
"\n"
-"gvim tarafından tanınan değişkenler (GTK+ sürümü):\n"
+"gvim tarafından tanınan argümanlar (GTK+ sürümü):\n"
msgid "-display <display>\tRun Vim on <display> (also: --display)"
msgstr "-display <ekran>\tVim'i <ekran>'da çalıştır (veya: --display)"
@@ -3078,7 +3087,7 @@ msgid "E228: makemap: Illegal mode"
msgstr "E228: makemap: İzin verilmeyen kip"
msgid "E460: entries missing in mapset() dict argument"
-msgstr "E460: mapset() sözlük değişkeninde eksik girdiler"
+msgstr "E460: mapset() sözlük argümanında eksik girdiler"
#, c-format
msgid "E357: 'langmap': Matching character missing for %s"
@@ -3716,13 +3725,13 @@ msgstr ""
"İ&ptal"
msgid "E766: Insufficient arguments for printf()"
-msgstr "E766: printf() için yetersiz değişkenler"
+msgstr "E766: printf() için yetersiz argüman"
msgid "E807: Expected Float argument for printf()"
-msgstr "E807: printf() için kayan noktalı değer türünde değişken bekleniyordu"
+msgstr "E807: printf() için kayan noktalı değer türünde argüman bekleniyordu"
msgid "E767: Too many arguments to printf()"
-msgstr "E767: printf() için çok fazla değişken"
+msgstr "E767: printf() için çok fazla argüman"
msgid "Type number and <Enter> or click with the mouse (q or empty cancels): "
msgstr ""
@@ -4014,12 +4023,12 @@ msgstr "E531: Grafik arabirimi başlatmak için \":gui\" yazın"
msgid "E589: 'backupext' and 'patchmode' are equal"
msgstr "E589: 'backupext' ve 'patchmode' birbirine eşit"
-msgid "E834: Conflicts with value of 'listchars'"
-msgstr "E834: 'listchars' değeriyle çakışmalar var"
-
msgid "E835: Conflicts with value of 'fillchars'"
msgstr "E835: 'fillchars' değeriyle çakışmalar var"
+msgid "E834: Conflicts with value of 'listchars'"
+msgstr "E834: 'listchars' değeriyle çakışmalar var"
+
msgid "E617: Cannot be changed in the GTK+ 2 GUI"
msgstr "E617: GTK+ 2 grafik arabiriminde değiştirilemez"
@@ -4392,7 +4401,7 @@ msgid "Cannot open file \"%s\""
msgstr "\"%s\" dosyası açılamıyor"
msgid "cannot have both a list and a \"what\" argument"
-msgstr "ya birinci ya da son değişken belirtilmelidir"
+msgstr "ya birinci ya da son argüman belirtilmelidir"
msgid "E681: Buffer is not loaded"
msgstr "E681: Arabellek yüklenemedi"
@@ -4725,10 +4734,10 @@ msgid "modeline"
msgstr "kip satırı"
msgid "--cmd argument"
-msgstr "--cmd değişkeni"
+msgstr "--cmd argümanı"
msgid "-c argument"
-msgstr "-c değişkeni"
+msgstr "-c argümanı"
msgid "environment variable"
msgstr "ortam değişkeni"
@@ -4736,6 +4745,9 @@ msgstr "ortam değişkeni"
msgid "error handler"
msgstr "hata işleyicisi"
+msgid "changed window size"
+msgstr "değiştirilen pencere boyutu"
+
msgid "W15: Warning: Wrong line separator, ^M may be missing"
msgstr "W15: Uyarı: Yanlış satır ayırıcısı, ^M eksik olabilir"
@@ -5215,6 +5227,9 @@ msgstr "E765: 'spellfile' içinde %d adet girdi yok"
msgid "Word '%.*s' removed from %s"
msgstr "'%.*s' sözcüğü %s içinden çıkartıldı"
+msgid "Seek error in spellfile"
+msgstr "Yazım dosyasında arama hatası"
+
#, c-format
msgid "Word '%.*s' added to %s"
msgstr "'%.*s' sözcüğü %s dosyasına eklendi"
@@ -5242,7 +5257,7 @@ msgstr " < \"%.*s\""
#, c-format
msgid "E390: Illegal argument: %s"
-msgstr "E390: İzin verilmeyen değişken: %s"
+msgstr "E390: İzin verilmeyen argüman: %s"
msgid "No Syntax items defined for this buffer"
msgstr "Bu arabellek için sözdizim ögeleri tanımlanmamış"
@@ -5343,7 +5358,7 @@ msgid " line breaks"
msgstr " satır sonu"
msgid "E395: contains argument not accepted here"
-msgstr "E395: Burada kabul edilmeyen bir değişken içeriyor"
+msgstr "E395: Burada kabul edilmeyen bir argüman içeriyor"
msgid "E844: invalid cchar value"
msgstr "E844: Geçersiz cchar değeri"
@@ -5375,7 +5390,7 @@ msgstr "E398: '=' eksik: %s"
#, c-format
msgid "E399: Not enough arguments: syntax region %s"
-msgstr "E399: Yetersiz değişken: %s sözdizim bölgesi"
+msgstr "E399: Yetersiz sayıda argüman: %s sözdizim bölgesi"
msgid "E848: Too many syntax clusters"
msgstr "E848: Çok fazla sözdizim kümesi"
@@ -5396,7 +5411,7 @@ msgstr "E403: Sözdizim eşitlemesi: Satır devamları dizgisi iki kez tanımlan
#, c-format
msgid "E404: Illegal arguments: %s"
-msgstr "E404: İzin verilmeyen değişkenler: %s"
+msgstr "E404: İzin verilmeyen argümanlar: %s"
#, c-format
msgid "E405: Missing equal sign: %s"
@@ -5404,7 +5419,7 @@ msgstr "E405: Eşittir imi eksik: %s"
#, c-format
msgid "E406: Empty argument: %s"
-msgstr "E406: Boş değişken: %s"
+msgstr "E406: Boş argüman: %s"
#, c-format
msgid "E407: %s not allowed here"
@@ -5539,7 +5554,7 @@ msgid "E436: No \"%s\" entry in termcap"
msgstr "E436: termcap içinde \"%s\" girdisi yok"
msgid "E437: terminal capability \"cm\" required"
-msgstr "E437: \"cm\" uçbirim kabiliyeti gerekiyor"
+msgstr "E437: \"cm\" uçbirim yeteneği gerekiyor"
msgid ""
"\n"
@@ -5688,16 +5703,16 @@ msgstr "E914: Bir Kanal, Kayan Noktalı Değer yerine kullanılıyor"
msgid "E975: Using a Blob as a Float"
msgstr "E975: Bir İkili Geniş Nesne, Kayan Noktalı Değer yerine kullanılıyor"
-msgid "E729: using Funcref as a String"
+msgid "E729: Using a Funcref as a String"
msgstr "E729: Funcref bir Dizi yerine kullanılıyor"
-msgid "E730: using List as a String"
+msgid "E730: Using a List as a String"
msgstr "E730: Liste bir Dizi yerine kullanılıyor"
-msgid "E731: using Dictionary as a String"
+msgid "E731: Using a Dictionary as a String"
msgstr "E731: Sözlük bir Dizi yerine kullanılıyor"
-msgid "E976: using Blob as a String"
+msgid "E976: Using a Blob as a String"
msgstr "E976: İkili Geniş Nesne bir Dizi yerine kullanılıyor"
msgid "E977: Can only compare Blob with Blob"
@@ -5892,16 +5907,16 @@ msgid "E180: Invalid complete value: %s"
msgstr "E180: Geçersiz tam değer: %s"
msgid "E468: Completion argument only allowed for custom completion"
-msgstr "E468: Tamamlama değişkenine yalnızca özel tamamlamalarda izin verilir"
+msgstr "E468: Tamamlama argümanına yalnızca özel tamamlamalarda izin verilir"
msgid "E467: Custom completion requires a function argument"
-msgstr "E467: Özel tamamlama bir işlev değişkeni gerektirir"
+msgstr "E467: Özel tamamlama bir işlev argümanı gerektirir"
msgid "E175: No attribute specified"
msgstr "E175: Bir öznitelik belirtilmemiş"
msgid "E176: Invalid number of arguments"
-msgstr "E176: Geçersiz değişken sayısı"
+msgstr "E176: Geçersiz argüman sayısı"
msgid "E177: Count cannot be specified twice"
msgstr "E177: Sayım iki defa belirtilemez"
@@ -5910,10 +5925,10 @@ msgid "E178: Invalid default value for count"
msgstr "E178: Sayım için geçersiz öntanımlı değer"
msgid "E179: argument required for -complete"
-msgstr "E179: -complete için değişken gerekiyor"
+msgstr "E179: -complete için argüman gerekiyor"
msgid "E179: argument required for -addr"
-msgstr "E179: -addr için değişken gerekiyor"
+msgstr "E179: -addr için argüman gerekiyor"
#, c-format
msgid "E174: Command already exists: add ! to replace it: %s"
@@ -5948,14 +5963,21 @@ msgstr "E130: Bilinmeyen işlev: %s"
#, c-format
msgid "E125: Illegal argument: %s"
-msgstr "E125: İzin verilmeyen değişken: %s"
+msgstr "E125: İzin verilmeyen argüman: %s"
#, c-format
msgid "E853: Duplicate argument name: %s"
-msgstr "E853: Yinelenen değişken adı: %s"
+msgstr "E853: Yinelenen argüman adı: %s"
msgid "E989: Non-default argument follows default argument"
-msgstr "E989: Öntanımlı olmayan değişken öntanımlı değişkenden sonra"
+msgstr "E989: Öntanımlı olmayan argüman öntanımlı argümandan sonra"
+
+msgid "E126: Missing :endfunction"
+msgstr "E126: :endfunction eksik"
+
+#, c-format
+msgid "W22: Text found after :endfunction: %s"
+msgstr "W22: :endfunction sonrası metin bulundu: %s"
#, c-format
msgid "E451: Expected }: %s"
@@ -5963,11 +5985,11 @@ msgstr "E451: } bekleniyordu: %s"
#, c-format
msgid "E740: Too many arguments for function %s"
-msgstr "E740: %s işlevi için çok fazla değişken"
+msgstr "E740: %s işlevi için çok fazla argüman"
#, c-format
msgid "E116: Invalid arguments for function %s"
-msgstr "E116: %s işlevi için geçersiz değişkenler"
+msgstr "E116: %s işlevi için geçersiz argümanlar"
msgid "E132: Function call depth is higher than 'maxfuncdepth'"
msgstr "E132: İşlevin çağırdığı derinlik 'maxfuncdepth'ten daha yüksek"
@@ -5989,7 +6011,7 @@ msgid "%s returning %s"
msgstr "%s, %s döndürüyor"
msgid "E699: Too many arguments"
-msgstr "E699: Çok fazla değişken"
+msgstr "E699: Çok fazla argüman"
#, c-format
msgid "E276: Cannot use function as a method: %s"
@@ -6032,17 +6054,6 @@ msgstr "E862: g: burada kullanılamaz"
msgid "E932: Closure function should not be at top level: %s"
msgstr "E932: Kapatma işlevi en üst düzeyde olmamalıdır: %s"
-msgid "E126: Missing :endfunction"
-msgstr "E126: :endfunction eksik"
-
-#, c-format
-msgid "W1001: Text found after :enddef: %s"
-msgstr "W1001: :enddef sonrası metin bulundu: %s"
-
-#, c-format
-msgid "W22: Text found after :endfunction: %s"
-msgstr "W22: :endfunction sonrası metin bulundu: %s"
-
#, c-format
msgid "E707: Function name conflicts with variable: %s"
msgstr "E707: İşlev adı şu değişken ile çakışıyor: %s"
@@ -6605,6 +6616,55 @@ msgstr "gvimext.dll hatası"
msgid "Path length too long!"
msgstr "Yol çok uzun!"
+msgid "E10: \\ should be followed by /, ? or &"
+msgstr "E10: \\ sonrasında /, ? veya & gelmeli"
+
+msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
+msgstr "E11: Komut satırı penceresinde geçersiz; <CR> çalıştırır, CTRL-C çıkar"
+
+msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
+msgstr ""
+"E12: Geçerli dizin veya etiket aramasında exrc veya vimrc'den komutlara izin "
+"verilmiyor"
+
+msgid "E13: File exists (add ! to override)"
+msgstr "E13: Dosya mevcut (geçersiz kılmak için ! ekleyin)"
+
+#, c-format
+msgid "E15: Invalid expression: \"%s\""
+msgstr "E15: Geçersiz ifade: \"%s\""
+
+msgid "E16: Invalid range"
+msgstr "E16: Geçersiz erim"
+
+#, c-format
+msgid "E17: \"%s\" is a directory"
+msgstr "E17: \"%s\" bir dizin"
+
+msgid "E18: Unexpected characters in :let"
+msgstr "E18: :let içinde beklenmeyen karakter"
+
+msgid "E18: Unexpected characters in assignment"
+msgstr "E18: Atama içerisinde beklenmedik karakterler"
+
+msgid "E19: Mark has invalid line number"
+msgstr "E19: İm satır numarası geçersiz"
+
+msgid "E20: Mark not set"
+msgstr "E20: İm ayarlanmamış"
+
+msgid "E21: Cannot make changes, 'modifiable' is off"
+msgstr "E21: Değişiklik yapılamıyor, 'modifiable' kapalı"
+
+msgid "E22: Scripts nested too deep"
+msgstr "E22: Betikler çok iç içe geçmiş"
+
+msgid "E23: No alternate file"
+msgstr "E23: Başka bir dosya yok"
+
+msgid "E24: No such abbreviation"
+msgstr "E24: Böyle bir kısaltma yok"
+
#, c-format
msgid "E121: Undefined variable: %s"
msgstr "E121: Tanımlanmamış değişken: %s"
@@ -6613,6 +6673,9 @@ msgstr "E121: Tanımlanmamış değişken: %s"
msgid "E121: Undefined variable: %c:%s"
msgstr "E121: Tanımlanmamış değişken: %c:%s"
+msgid "E464: Ambiguous use of user-defined command"
+msgstr "E464: Kullanıcı tanımlı komutun belirsiz kullanımı"
+
msgid "E476: Invalid command"
msgstr "E476: Geçersiz komut"
@@ -6633,15 +6696,19 @@ msgid ""
"E856: \"assert_fails()\" second argument must be a string or a list with one "
"or two strings"
msgstr ""
-"E856: \"assert_fails()\" ikinci değişkeni bir dizi veya bir veya iki dizili "
+"E856: \"assert_fails()\" ikinci argüman bir dizi veya bir veya iki dizili "
"bir liste olmalıdır"
+#, c-format
+msgid "E908: using an invalid value as a String: %s"
+msgstr "E908: Geçersiz bir değer bir Dizi yerine kullanılıyor: %s"
+
msgid "E909: Cannot index a special variable"
msgstr "E909: Özel bir değişken dizinlenemiyor"
#, c-format
-msgid "E1100: Missing :var: %s"
-msgstr "E1100: :var eksik: %s"
+msgid "E1100: Command not supported in Vim9 script (missing :var?): %s"
+msgstr "E1100: Komut Vim9 betiğinde desteklenmiyor (:var? eksik): %s"
#, c-format
msgid "E1001: Variable not found: %s"
@@ -6655,18 +6722,18 @@ msgid "E1003: Missing return value"
msgstr "E1003: Dönüş değeri eksik"
#, c-format
-msgid "E1004: White space required before and after '%s'"
-msgstr "E1004: '%s' öncesinde ve sonrasında boşluk gerekiyor"
+msgid "E1004: White space required before and after '%s' at \"%s\""
+msgstr "E1004: Şu konumda '%s' öncesinde ve sonrasında boşluk gerekiyor: \"%s\""
msgid "E1005: Too many argument types"
-msgstr "E1005: Çok fazla değişken türü"
+msgstr "E1005: Çok fazla argüman türü"
#, c-format
msgid "E1006: %s is used as an argument"
-msgstr "E1006: %s bir değişken olarak kullanılıyor"
+msgstr "E1006: %s bir argüman olarak kullanılıyor"
msgid "E1007: Mandatory argument after optional argument"
-msgstr "E1007: İsteğe bağlı değişken sonrasında zorunlu değişken"
+msgstr "E1007: İsteğe bağlı argüman sonrasında zorunlu argüman"
msgid "E1008: Missing <type>"
msgstr "E1008: <tür> eksik"
@@ -6688,7 +6755,7 @@ msgstr "E1012: Tür uyumsuzluğu, %s bekleniyordu, ancak %s alındı"
#, c-format
msgid "E1013: Argument %d: type mismatch, expected %s but got %s"
-msgstr "E1013: %d değişkeni: Tür uyumsuzluğu, %s bekleniyordu, ancak %s alındı"
+msgstr "E1013: %d argümanı: Tür uyumsuzluğu, %s bekleniyordu, ancak %s alındı"
#, c-format
msgid "E1014: Invalid key: %s"
@@ -6728,8 +6795,8 @@ msgid "E1022: Type or initialization required"
msgstr "E1022: Tür veya ilklendirme gerekiyor"
#, c-format
-msgid "E1023: Using a Number as a Bool: %d"
-msgstr "E1023: Bir Sayı, bir Bool yerine kullanılıyor: %d"
+msgid "E1023: Using a Number as a Bool: %lld"
+msgstr "E1023: Bir Sayı, bir Boole yerine kullanılıyor: %lld"
msgid "E1024: Using a Number as a String"
msgstr "E1024: Bir Sayı, bir Dizi yerine kullanılıyor"
@@ -6768,11 +6835,11 @@ msgid "E1034: Cannot use reserved name %s"
msgstr "E1034: Ayrılmış ad %s kullanılamaz"
msgid "E1035: % requires number arguments"
-msgstr "E1035: %, sayı değişkenler gerektirir"
+msgstr "E1035: %, sayı argümanları gerektirir"
#, c-format
msgid "E1036: %c requires number or float arguments"
-msgstr "E1036: %c, sayı veya kayan noktalı değer değişkenler gerektirir"
+msgstr "E1036: %c, sayı veya kayan noktalı değer argümanları gerektirir"
#, c-format
msgid "E1037: Cannot use \"%s\" with %s"
@@ -6798,7 +6865,7 @@ msgid "E1043: Invalid command after :export"
msgstr "E1043: :export sonrası geçersiz komut"
msgid "E1044: Export with invalid argument"
-msgstr "E1044: Geçersiz değişkenle dışa aktarım"
+msgstr "E1044: Geçersiz argümanla dışa aktarım"
msgid "E1045: Missing \"as\" after *"
msgstr "E1045: * sonrası \"as\" eksik"
@@ -6817,11 +6884,12 @@ msgstr "E1048: Betikte öge bulunamadı: %s"
msgid "E1049: Item not exported in script: %s"
msgstr "E1049: Betikte öge dışa aktarılmadı: %s"
-msgid "E1050: Colon required before a range"
-msgstr "E1050: Bir erim öncesi iki nokta gerekiyor"
+#, c-format
+msgid "E1050: Colon required before a range: %s"
+msgstr "E1050: Bir erim öncesi iki nokta gerekiyor: %s"
msgid "E1051: Wrong argument type for +"
-msgstr "E1051: + için hatalı değişken türü"
+msgstr "E1051: + için hatalı argüman türü"
#, c-format
msgid "E1052: Cannot declare an option: %s"
@@ -6875,12 +6943,12 @@ msgid "E1067: Separator mismatch: %s"
msgstr "E1067: Ayırıcı uyumsuzluğu: %s"
#, c-format
-msgid "E1068: No white space allowed before '%s'"
-msgstr "E1068: '%s' önce boşluğa izin verilmiyor"
+msgid "E1068: No white space allowed before '%s': %s"
+msgstr "E1068: '%s' önce boşluğa izin verilmiyor: %s"
#, c-format
-msgid "E1069: White space required after '%s'"
-msgstr "E1069: '%s' sonrası boşluk gerekiyor"
+msgid "E1069: White space required after '%s': %s"
+msgstr "E1069: '%s' sonrası boşluk gerekiyor: %s"
msgid "E1070: Missing \"from\""
msgstr "E1070: \"from\" eksik"
@@ -6908,7 +6976,7 @@ msgstr "E1076: Bu Vim kayan noktalı değer desteği ile derlenmemiş"
#, c-format
msgid "E1077: Missing argument type for %s"
-msgstr "E1077: %s için değişken türü eksik"
+msgstr "E1077: %s için argüman türü eksik"
#, c-format
msgid "E1081: Cannot unlet %s"
@@ -6933,7 +7001,7 @@ msgid "E1086: Cannot use :function inside :def"
msgstr "E1086: :def içinde :function kullanılamaz"
msgid "E1087: Cannot use an index when declaring a variable"
-msgstr "E1087: Bir değişken tanımlarken indeks kullanılamaz"
+msgstr "E1087: Bir değişken tanımlarken dizinleme kullanılamaz"
#, c-format
msgid "E1089: Unknown variable: %s"
@@ -6941,7 +7009,7 @@ msgstr "E1089: Bilinmeyen değişken: %s"
#, c-format
msgid "E1090: Cannot assign to argument %s"
-msgstr "E1090: %s değişkenine atanamıyor"
+msgstr "E1090: %s argümanına atanamıyor"
#, c-format
msgid "E1091: Function is not compiled: %s"
@@ -6989,11 +7057,11 @@ msgid "E1105: Cannot convert %s to string"
msgstr "E1105: %s bir diziye dönüştürülemiyor"
msgid "E1106: One argument too many"
-msgstr "E1106: Bir değişken fazladan"
+msgstr "E1106: Bir argüman fazladan"
#, c-format
msgid "E1106: %d arguments too many"
-msgstr "E1106: %d değişken fazladan"
+msgstr "E1106: %d argüman fazladan"
msgid "E1107: String, List, Dict or Blob required"
msgstr "E1107: Dizi, Liste, Sözlük veya İkili Nesne gerekiyor"
@@ -7026,10 +7094,10 @@ msgid "E1114: Only values of 0x100 and higher supported"
msgstr "E1114: Yalnızca 0x100 ve daha yüksek değerler destekleniyor"
msgid "E1115: \"assert_fails()\" fourth argument must be a number"
-msgstr "E1115: \"assert_fails()\" dördüncü değişkeni bir sayı olmalıdır"
+msgstr "E1115: \"assert_fails()\" dördüncü argüman bir sayı olmalıdır"
msgid "E1116: \"assert_fails()\" fifth argument must be a string"
-msgstr "E1116: \"assert_fails()\" beşinci değişkeni bir dizi olmalıdır"
+msgstr "E1116: \"assert_fails()\" beşinci argüman bir dizi olmalıdır"
msgid "E1117: Cannot use ! with nested :def"
msgstr "E1117: !, iç içe geçmiş :def ile kullanılamaz"
@@ -7080,7 +7148,7 @@ msgid "E1131: Cannot add to null blob"
msgstr "E1131: Null ikili geniş nesnesine ekleme yapılamaz"
msgid "E1132: Missing function argument"
-msgstr "E1132: İşlev değişkeni eksik"
+msgstr "E1132: İşlev argümanı eksik"
msgid "E1133: Cannot extend a null dict"
msgstr "E1133: Bir null sözlük genişletilemez"
@@ -7108,12 +7176,259 @@ msgstr "E1138: Bir Boole, Sayı yerine kullanılıyor"
msgid "E1139: Missing matching bracket after dict key"
msgstr "E1139: Sözlük anahtarı sonrası eşleşen ayraç eksik"
-msgid "E1140: For argument must be a sequence of lists"
-msgstr "E1140: For değişkeni listelerin bir sıralaması olmalıdır"
+msgid "E1140: :for argument must be a sequence of lists"
+msgstr "E1140: :for argümanı listelerin bir sıralaması olmalıdır"
msgid "E1141: Indexable type required"
msgstr "E1141: İndekslenebilir tür gerekiyor"
+msgid "E1142: Non-empty string required"
+msgstr "E1142: Boş olmayan dizi gerekiyor"
+
+#, c-format
+msgid "E1143: Empty expression: \"%s\""
+msgstr "E1143: Boş ifade: \"%s\""
+
+#, c-format
+msgid "E1144: Command \"%s\" is not followed by white space: %s"
+msgstr "E1144: \"%s\" komutu sonrasında boşluk gelmiyor: %s"
+
+#, c-format
+msgid "E1145: Missing heredoc end marker: %s"
+msgstr "E1145: Son imleyicisi eksik: %s"
+
+#, c-format
+msgid "E1146: Command not recognized: %s"
+msgstr "E1146: Komut tanınamadı: %s"
+
+msgid "E1147: List not set"
+msgstr "E1147: Liste ayarlanmamış"
+
+#, c-format
+msgid "E1148: Cannot index a %s"
+msgstr "E1148: Bir %s dizinlenemiyor"
+
+#, c-format
+msgid "E1149: Script variable is invalid after reload in function %s"
+msgstr "E1149: %s işlevindeki yeniden yüklemeden sonra betik değişkeni geçersiz"
+
+msgid "E1150: Script variable type changed"
+msgstr "E1150: Betik değişkeni türü değiştirildi"
+
+msgid "E1151: Mismatched endfunction"
+msgstr "E1151: Eşleşmeyen endfunction"
+
+msgid "E1152: Mismatched enddef"
+msgstr "E1152: Eşleşmeyen enddef"
+
+msgid "E1153: Invalid operation for bool"
+msgstr "E1153: Boole için geçersiz işlem"
+
+msgid "E1154: Divide by zero"
+msgstr "E1154: Sıfır ile bölüm"
+
+msgid "E1155: Cannot define autocommands for ALL events"
+msgstr "E1155: Otokomutlar TÜM olaylar için tanımlanamıyor"
+
+msgid "E1156: Cannot change the argument list recursively"
+msgstr "E1156: Değişken listesi özyineli olarak değiştirilemiyor"
+
+msgid "E1157: Missing return type"
+msgstr "E1157: Dönüş türü eksik"
+
+msgid "E1158: Cannot use flatten() in Vim9 script"
+msgstr "E1158: flatten(), Vim9 betiğinde kullanılamaz"
+
+msgid "E1159: Cannot split a window when closing the buffer"
+msgstr "E1159: Arabellek kapatılırken bir pencere bölünemez"
+
+msgid "E1160: Cannot use a default for variable arguments"
+msgstr "E1160: Değişken argümanları için bir öntanımlı kullanılamaz"
+
+#, c-format
+msgid "E1161: Cannot json encode a %s"
+msgstr "E1161: Bir %s JSON olarak kodlanamıyor"
+
+#, c-format
+msgid "E1162: Register name must be one character: %s"
+msgstr "E1162: Yazmaç adı tek bir karakter olmalıdır: %s"
+
+#, c-format
+msgid "E1163: Variable %d: type mismatch, expected %s but got %s"
+msgstr "E1163: %d değişkeni: Tür uyumsuzluğu, %s bekleniyordu, ancak %s alındı"
+
+msgid "E1164: vim9cmd must be followed by a command"
+msgstr "E1164: vim9cmd sonrasında bir komut gelmelidir"
+
+#, c-format
+msgid "E1165: Cannot use a range with an assignment: %s"
+msgstr "E1165: Bir atama ile bir erim kullanılamıyor: %s"
+
+msgid "E1166: Cannot use a range with a dictionary"
+msgstr "E1166: Bir sözlük ile bir erim kullanılamıyor"
+
+#, c-format
+msgid "E1167: Argument name shadows existing variable: %s"
+msgstr "E1167: Argüman adı var olan değişkeni gölgeliyor: %s"
+
+#, c-format
+msgid "E1168: Argument already declared in the script: %s"
+msgstr "E1168: Betikte argüman halihazırda tanımlanmış: %s"
+
+msgid "E1169: 'import * as {name}' not supported here"
+msgstr "E1169: 'import * as {name} burada desteklenmiyor"
+
+msgid "E1170: Cannot use #{ to start a comment"
+msgstr "E1170: Bir yorum başlatmak için #{ kullanılamaz"
+
+msgid "E1171: Missing } after inline function"
+msgstr "E1171: Satıriçi işlevden sonra } eksik"
+
+msgid "E1172: Cannot use default values in a lambda"
+msgstr "E1172: Bir lambda içerisinde öntanımlı değerler kullanılamıyor"
+
+#, c-format
+msgid "E1173: Text found after enddef: %s"
+msgstr "E1173: :enddef sonrası metin bulundu: %s"
+
+#, c-format
+msgid "E1174: String required for argument %d"
+msgstr "E1174: %d argümanı için dizi gerekiyor"
+
+#, c-format
+msgid "E1175: Non-empty string required for argument %d"
+msgstr "E1175: %d argümanı için boş olmayan dizi gerekiyor"
+
+msgid "E1176: Misplaced command modifier"
+msgstr "E1176: Yanlış yere konulmuş komut değiştiricisi"
+
+#, c-format
+msgid "E1177: For loop on %s not supported"
+msgstr "E1177: %s üzerinde for döngüsü desteklenmiyor"
+
+msgid "E1178: Cannot lock or unlock a local variable"
+msgstr "E1178: Bir yerel değişken kilitlenemiyor/kilidi açılamıyor"
+
+#, c-format
+msgid ""
+"E1179: Failed to extract PWD from %s, check your shell's config related to "
+"OSC 7"
+msgstr ""
+"E1179: %s içinden PWD çıkarılamadı, kabuğunuzun OSC 7 ile ilgili "
+"yapılandırmasını denetleyin"
+
+#, c-format
+msgid "E1180: Variable arguments type must be a list: %s"
+msgstr "E1180: Değişken argümanları türü bir liste olmalıdır: %s"
+
+msgid "E1181: Cannot use an underscore here"
+msgstr "E1181: Alt çizgi burada kullanılamaz"
+
+msgid "E1182: Blob required"
+msgstr "E1182: İkili geniş nesne gerekiyor"
+
+#, c-format
+msgid "E1183: Cannot use a range with an assignment operator: %s"
+msgstr "E1183: Bir atama işleci ile bir erim kullanılamıyor: %s"
+
+msgid "E1184: Blob not set"
+msgstr "E1184: İkili geniş nesne ayarlanmamış"
+
+msgid "E1185: Cannot nest :redir"
+msgstr "E1185: :redir içe geçirilemiyor"
+
+msgid "E1185: Missing :redir END"
+msgstr "E1185: :redir END eksik"
+
+#, c-format
+msgid "E1186: Expression does not result in a value: %s"
+msgstr "E1186: İfade bir değer sonucu vermiyor: %s"
+
+msgid "E1187: Failed to source defaults.vim"
+msgstr "E1187: defaults.vim kaynaklanamadı"
+
+msgid "E1188: Cannot open a terminal from the command line window"
+msgstr "E1188: Komut satırı penceresinden bir uçbirim açılamıyor"
+
+#, c-format
+msgid "E1189: Cannot use :legacy with this command: %s"
+msgstr "E1189: :legacy, bu komut ile kullanılamıyor: %s"
+
+msgid "E1190: One argument too few"
+msgstr "E1190: Bir argüman daha gerekiyor"
+
+#, c-format
+msgid "E1190: %d arguments too few"
+msgstr "E1190: %d argüman daha gerekiyor"
+
+#, c-format
+msgid "E1191: Call to function that failed to compile: %s"
+msgstr "E1191: Derlenemeyen işlev çağrısı: %s"
+
+msgid "E1192: Empty function name"
+msgstr "E1192: Boş işlev adı"
+
+msgid "E1193: cryptmethod xchacha20 not built into this Vim"
+msgstr "E1193: cryptmethod xchacha20 bu Vim ile kullanılamıyor"
+
+msgid "E1194: Cannot encrypt header, not enough space"
+msgstr "E1194: Üstbilgi şifrelenemiyor, yetersiz alan"
+
+msgid "E1195: Cannot encrypt buffer, not enough space"
+msgstr "E1195: Arabellek şifrelenemiyor, yetersiz alan"
+
+msgid "E1196: Cannot decrypt header, not enough space"
+msgstr "E1196: Üstbilgi şifresi çözülemiyor, yetersiz alan"
+
+msgid "E1197: Cannot allocate_buffer for encryption"
+msgstr "E1197: Şifreleme için allocate_buffer yapılamıyor"
+
+msgid "E1198: Decryption failed: Header incomplete!"
+msgstr "E1198: Şifre çözümü başarısız: Üstbilgi tam değil!"
+
+msgid "E1199: Cannot decrypt buffer, not enough space"
+msgstr "E1199: Arabellek şifresi çözülemiyor, yetersiz alan"
+
+msgid "E1200: Decryption failed!"
+msgstr "E1200: Şifre çözümü başarısız!"
+
+msgid "E1201: Decryption failed: pre-mature end of file!"
+msgstr "E1201: Şifre çözümü başarısız: Beklenmedik dosya sonu!"
+
+#, c-format
+msgid "E1202: No white space allowed after '%s': %s"
+msgstr "E1202: '%s' sonrası boşluğa izin verilmiyor: %s"
+
+#, c-format
+msgid "E1203: Dot can only be used on a dictionary: %s"
+msgstr "E1203: Nokta yalnızca bir sözlükte kullanılabilir: %s"
+
+#, c-format
+msgid "E1204: No Number allowed after .: '\\%%%c'"
+msgstr "E1204: . sonrası Sayıya izin verilmiyor: '\\%%%c'"
+
+msgid "E1205: No white space allowed between option and"
+msgstr "E1205: and seçeneği arasında boşluğa izin verilmiyor"
+
+#, c-format
+msgid "E1206: Dictionary required for argument %d"
+msgstr "E1206: %d argümanı için sözlük gerekiyor"
+
+#, c-format
+msgid "E1207: Expression without an effect: %s"
+msgstr "E1207: Bir efekt olmadan ifade: %s"
+
+msgid "E1208: -complete used without -nargs"
+msgstr "E1208: -complete, -nargs olmadan kullanıldı"
+
+#, c-format
+msgid "E1209: Invalid value for a line number: \"%s\""
+msgstr "E1209: Satır numarası için geçersiz değer: \"%s\""
+
+#, c-format
+msgid "E1210: Number required for argument %d"
+msgstr "E1210: %d argümanı için sayı gerekiyor"
+
msgid "--No lines in buffer--"
msgstr "--Arabellek içinde satır yok--"
@@ -7123,17 +7438,6 @@ msgstr "E470: Komut durduruldu"
msgid "E471: Argument required"
msgstr "E471: Değişken gerekiyor"
-msgid "E10: \\ should be followed by /, ? or &"
-msgstr "E10: \\ sonrasında /, ? veya & gelmeli"
-
-msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits"
-msgstr "E11: Komut satırı penceresinde geçersiz; <CR> çalıştırır, CTRL-C çıkar"
-
-msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search"
-msgstr ""
-"E12: Geçerli dizin veya etiket aramasında exrc veya vimrc'den komutlara izin "
-"verilmiyor"
-
msgid "E171: Missing :endif"
msgstr "E171: :endif eksik"
@@ -7164,9 +7468,6 @@ msgstr "E588: :while olmadan :endwhile"
msgid "E588: :endfor without :for"
msgstr "E588: :for olmadan :endfor"
-msgid "E13: File exists (add ! to override)"
-msgstr "E13: Dosya mevcut (geçersiz kılmak için ! ekleyin)"
-
msgid "E472: Command failed"
msgstr "E472: Komut başarısız oldu"
@@ -7193,34 +7494,23 @@ msgid "Interrupted"
msgstr "Yarıda kesildi"
msgid "E474: Invalid argument"
-msgstr "E474: Geçersiz değişken"
+msgstr "E474: Geçersiz argüman"
#, c-format
msgid "E475: Invalid argument: %s"
-msgstr "E475: Geçersiz değişken: %s"
+msgstr "E475: Geçersiz argüman: %s"
#, c-format
msgid "E983: Duplicate argument: %s"
-msgstr "E983: Yinelenen değişken: %s"
+msgstr "E983: Yinelenen argüman: %s"
#, c-format
msgid "E475: Invalid value for argument %s"
-msgstr "E475: %s değişkeni için geçersiz değer"
+msgstr "E475: %s argümanı için geçersiz değer"
#, c-format
msgid "E475: Invalid value for argument %s: %s"
-msgstr "E475: %s değişkeni için geçersiz değer: %s"
-
-#, c-format
-msgid "E15: Invalid expression: %s"
-msgstr "E15: Geçersiz ifade: %s"
-
-msgid "E16: Invalid range"
-msgstr "E16: Geçersiz erim"
-
-#, c-format
-msgid "E17: \"%s\" is a directory"
-msgstr "E17: \"%s\" bir dizin"
+msgstr "E475: %s argümanı için geçersiz değer: %s"
msgid "E756: Spell checking is not possible"
msgstr "E756: Yazım denetimi olanaklı değil"
@@ -7236,24 +7526,6 @@ msgstr "E667: Fsync başarısız oldu"
msgid "E448: Could not load library function %s"
msgstr "E448: %s kitaplık işlevi yüklenemedi"
-msgid "E19: Mark has invalid line number"
-msgstr "E19: İm satır numarası geçersiz"
-
-msgid "E20: Mark not set"
-msgstr "E20: İm ayarlanmamış"
-
-msgid "E21: Cannot make changes, 'modifiable' is off"
-msgstr "E21: Değişiklik yapılamıyor, 'modifiable' kapalı"
-
-msgid "E22: Scripts nested too deep"
-msgstr "E22: Betikler çok iç içe geçmiş"
-
-msgid "E23: No alternate file"
-msgstr "E23: Başka bir dosya yok"
-
-msgid "E24: No such abbreviation"
-msgstr "E24: Böyle bir kısaltma yok"
-
msgid "E477: No ! allowed"
msgstr "E477: ! imine izin verilmiyor"
@@ -7327,7 +7599,7 @@ msgid "E485: Can't read file %s"
msgstr "E485: %s dosyası okunamıyor"
msgid "E38: Null argument"
-msgstr "E38: Anlamsız değişken"
+msgstr "E38: Anlamsız argüman"
msgid "E39: Number expected"
msgstr "E39: Sayı bekleniyordu"
@@ -7392,6 +7664,9 @@ msgstr "E794: Değişken kum havuzunda ayarlanamıyor: \"%s\""
msgid "E928: String required"
msgstr "E928: Dizi gerekiyor"
+msgid "E889: Number required"
+msgstr "E889: Sayı gerekiyor"
+
msgid "E713: Cannot use empty key for Dictionary"
msgstr "E713: Sözlük için boş anahtar kullanılamaz"
@@ -7411,11 +7686,11 @@ msgstr "E978: İkili geniş nesne için geçersiz işlem"
#, c-format
msgid "E118: Too many arguments for function: %s"
-msgstr "E118: İşlev için çok fazla değişken: %s"
+msgstr "E118: İşlev için çok fazla argüman: %s"
#, c-format
msgid "E119: Not enough arguments for function: %s"
-msgstr "E119: Şu işlev için yetersiz sayıda değişken: %s"
+msgstr "E119: Şu işlev için yetersiz sayıda argüman: %s"
#, c-format
msgid "E933: Function was deleted: %s"
@@ -7437,18 +7712,15 @@ msgstr "E697: Liste sonunda ']' eksik: %s"
#, c-format
msgid "E712: Argument of %s must be a List or Dictionary"
-msgstr "E712: %s ögesinin değişkeni bir liste veya sözlük olmalıdır"
+msgstr "E712: %s ögesinin argümanı bir liste veya sözlük olmalıdır"
#, c-format
msgid "E896: Argument of %s must be a List, Dictionary or Blob"
-msgstr "E896: %s değişkeni bir liste, sözlük veya ikili geniş nesne olmalıdır"
+msgstr "E896: %s argümanı bir liste, sözlük veya ikili geniş nesne olmalıdır"
msgid "E804: Cannot use '%' with Float"
msgstr "E804: Bir kayan noktalı değer ile '%' kullanılamaz"
-msgid "E908: using an invalid value as a String"
-msgstr "E908: Geçersiz bir değer bir Dizi yerine kullanılıyor"
-
msgid "E996: Cannot lock an option"
msgstr "E996: Seçenek kilitlenemiyor"
@@ -7456,9 +7728,6 @@ msgstr "E996: Seçenek kilitlenemiyor"
msgid "E113: Unknown option: %s"
msgstr "E113: Bilinmeyen seçenek: %s"
-msgid "E18: Unexpected characters in :let"
-msgstr "E18: :let içinde beklenmeyen karakter"
-
#, c-format
msgid "E998: Reduce of an empty %s with no initial value"
msgstr "E998: Başlangıç değeri olmayan boş bir %s için reduce() yapılamıyor"
@@ -7616,7 +7885,7 @@ msgstr "E957: Geçersiz pencere numarası"
#, c-format
msgid "E686: Argument of %s must be a List"
-msgstr "E686: %s değişkeni bir liste olmalı"
+msgstr "E686: %s argümanı bir liste olmalı"
msgid "E109: Missing ':' after '?'"
msgstr "E109: '?' sonrası ':' eksik"
@@ -7685,7 +7954,7 @@ msgstr "'%s' anahtarı sözlüğe eklenemedi"
#, c-format
msgid "index must be int or slice, not %s"
-msgstr "dizin bir tamsayı veya dilim olmalıdır, %s olamaz"
+msgstr "sıra bir tamsayı veya dilim olmalıdır, %s olamaz"
#, c-format
msgid "expected str() or unicode() instance, but got %s"
@@ -7762,10 +8031,10 @@ msgid "expected sequence element of size 2, but got sequence of size %d"
msgstr "2 boyut bir sıralama bekleniyordu, ancak %d boyut bir sıralama geldi"
msgid "list constructor does not accept keyword arguments"
-msgstr "liste yapıcısı anahtar sözcük değişkenleri kabul etmez"
+msgstr "liste yapıcısı anahtar sözcük argümanları kabul etmez"
msgid "list index out of range"
-msgstr "liste dizini erimin dışında"
+msgstr "liste sırası erimin dışında"
#, c-format
msgid "internal error: failed to get Vim list item %d"
@@ -8013,8 +8282,7 @@ msgstr ""
"düzenleyebilirsiniz."
msgid "\" Hit <Enter> on a help line to open a help window on this option."
-msgstr ""
-"\" Yardım penceresini açmak için seçenek adı üzerinde <Enter>'a basın."
+msgstr "\" Yardım penceresini açmak için seçenek adı üzerinde <Enter>'a basın."
msgid "\" Hit <Enter> on an index line to jump there."
msgstr ""
@@ -8056,7 +8324,8 @@ msgid "moving around, searching and patterns"
msgstr "dolaşma, arama ve dizgeler"
msgid "list of flags specifying which commands wrap to another line"
-msgstr "hangi komutların diğer satıra kaydırıldığını belirleyen bayraklar\n"
+msgstr ""
+"hangi komutların diğer satıra kaydırıldığını belirleyen bayraklar\n"
"listesi"
msgid ""
@@ -8081,6 +8350,9 @@ msgstr ":cd için kullanılan dizin adları listesi"
msgid "change to directory of file in buffer"
msgstr "arabellekteki dosyanın olduğu dizine değiştir"
+msgid "change to pwd of shell in terminal buffer"
+msgstr "uçbirim arabelleğindeki kabuğun pwd'sine geç"
+
msgid "search commands wrap around the end of the buffer"
msgstr "arama komutları, arabelleğin sonunda kaydırılır"
@@ -8320,7 +8592,8 @@ msgid "multiple windows"
msgstr "çoklu pencereler"
msgid "0, 1 or 2; when to use a status line for the last window"
-msgstr "0, 1 veya 2; son pencere için ne zaman bir durum satırı\n"
+msgstr ""
+"0, 1 veya 2; son pencere için ne zaman bir durum satırı\n"
"kullanılacağı"
msgid "alternate format to be used for a status line"
@@ -8382,7 +8655,8 @@ msgid "this window scrolls together with other bound windows"
msgstr "bu pencere, bağlı diğer pencerelerle birlikte kayar"
msgid "\"ver\", \"hor\" and/or \"jump\"; list of options for 'scrollbind'"
-msgstr "\"ver\", \"hor\" ve/veya \"jump\"; 'scrollbind' için seçenekler listesi"
+msgstr ""
+"\"ver\", \"hor\" ve/veya \"jump\"; 'scrollbind' için seçenekler listesi"
msgid "this window's cursor moves together with other bound windows"
msgstr "bu pencerenin imleci bağlı diğer pencerelerle birlikte kayar"
@@ -8394,7 +8668,8 @@ msgid "key that precedes Vim commands in a terminal window"
msgstr "bir uçbirim penceresinde Vim komutlarından önce gelen düğme"
msgid "max number of lines to keep for scrollback in a terminal window"
-msgstr "bir uçbirim penceresinde geri kaydırma için kullanılacak\n"
+msgstr ""
+"bir uçbirim penceresinde geri kaydırma için kullanılacak\n"
"en çok satır sayısı"
msgid "type of pty to use for a terminal window"
@@ -8522,8 +8797,7 @@ msgid "list of flags that specify how the GUI works"
msgstr "grafik arabirimin nice çalıştığını belirleyen bayraklar listesi"
msgid "\"icons\", \"text\" and/or \"tooltips\"; how to show the toolbar"
-msgstr ""
-"\"icons\", \"text\" ve/veya \"tooltips\"; araç çubuğu kipleri "
+msgstr "\"icons\", \"text\" ve/veya \"tooltips\"; araç çubuğu kipleri "
msgid "size of toolbar icons"
msgstr "araç çubuğu simgelerinin boyutu"
@@ -8679,7 +8953,8 @@ msgid "list of directories for undo files"
msgstr "geri al dosyaları için dizinler listesi"
msgid "maximum number lines to save for undo on a buffer reload"
-msgstr "arabellek yeniden yüklemesinde geri al için kaydedilecek\n"
+msgstr ""
+"arabellek yeniden yüklemesinde geri al için kaydedilecek\n"
"en çok satır sayısı"
msgid "changes have been made and not written to a file"
@@ -8704,7 +8979,8 @@ msgid "definition of what comment lines look like"
msgstr "yorum satırlarının nice görüneceğinin tanımı"
msgid "list of flags that tell how automatic formatting works"
-msgstr "kendiliğinden biçimlendirmenin nice çalıştığını anlatan\n"
+msgstr ""
+"kendiliğinden biçimlendirmenin nice çalıştığını anlatan\n"
"bayraklar listesi"
msgid "pattern to recognize a numbered list"
@@ -8714,7 +8990,8 @@ msgid "expression used for \"gq\" to format lines"
msgstr "satırları biçimlendirmek için \"gq\" için kullanılan ifade"
msgid "specifies how Insert mode completion works for CTRL-N and CTRL-P"
-msgstr "Ekleme kipi tamamlamasının CTRL-N ve CTRL-P için nice çalıştığını\n"
+msgstr ""
+"Ekleme kipi tamamlamasının CTRL-N ve CTRL-P için nice çalıştığını\n"
"belirler"
msgid "whether to use a popup menu for Insert mode completion"
@@ -8739,7 +9016,8 @@ msgid "list of dictionary files for keyword completion"
msgstr "anahtar sözcük tamamlaması için sözlük dosyaları listesi"
msgid "list of thesaurus files for keyword completion"
-msgstr "anahtar sözcük tamamlaması için eşanlamlılar sözlüğü dosyaları\n"
+msgstr ""
+"anahtar sözcük tamamlaması için eşanlamlılar sözlüğü dosyaları\n"
"listesi"
msgid "adjust case of a keyword completion match"
@@ -8883,7 +9161,8 @@ msgid "markers used when 'foldmethod' is \"marker\""
msgstr "'foldmethod' \"marker\" olduğunda kullanılan imleyiciler"
msgid "maximum fold depth for when 'foldmethod' is \"indent\" or \"syntax\""
-msgstr "'foldmethod' \"indent\" veya \"syntax\" olduğunda kullanılan en çok\n"
+msgstr ""
+"'foldmethod' \"indent\" veya \"syntax\" olduğunda kullanılan en çok\n"
"kıvırma derinliği"
msgid "diff mode"
@@ -9013,7 +9292,8 @@ msgid "use a swap file for this buffer"
msgstr "bu arabellek için bir takas dosyası kullan"
msgid "\"sync\", \"fsync\" or empty; how to flush a swap file to disk"
-msgstr "\"sync\", \"fsync\", veya boş; bir takas dosyasının diske\n"
+msgstr ""
+"\"sync\", \"fsync\", veya boş; bir takas dosyasının diske\n"
"nice floşlanacağı"
msgid "number of characters typed to cause a swap file update"
@@ -9089,13 +9369,14 @@ msgid "characters to escape when 'shellxquote' is ("
msgstr "'shellxquote' ( iken kaçırılacak karakterler"
msgid "argument for 'shell' to execute a command"
-msgstr "bir komut çalıştırmak için 'shell' için değişken"
+msgstr "bir komut çalıştırmak için 'shell' için argüman"
msgid "used to redirect command output to a file"
msgstr "komut çıktısını bir dosyaya yeniden yönlendirmek için kullanılır"
msgid "use a temp file for shell commands instead of using a pipe"
-msgstr "bir veri yolu kullanımı yerine kabuk komutları için geçici\n"
+msgstr ""
+"bir veri yolu kullanımı yerine kabuk komutları için geçici\n"
"bir dosya kullan"
msgid "program used for \"=\" command"
@@ -9108,7 +9389,8 @@ msgid "program used for the \"K\" command"
msgstr "\"K\" komutu için kullanılan program"
msgid "warn when using a shell command and a buffer has changes"
-msgstr "bir kabuk komutu kullanılıyorsa ve arabellekte değişiklikler\n"
+msgstr ""
+"bir kabuk komutu kullanılıyorsa ve arabellekte değişiklikler\n"
"varsa uyar"
msgid "running make and jumping to errors (quickfix)"
@@ -9124,7 +9406,8 @@ msgid "program used for the \":make\" command"
msgstr "\":make\" komutu için kullanılan program"
msgid "string used to put the output of \":make\" in the error file"
-msgstr "\":make\" komutunun çıktısını hata dosyasına koymak için\n"
+msgstr ""
+"\":make\" komutunun çıktısını hata dosyasına koymak için\n"
"kullanılan dizi"
msgid "name of the errorfile for the 'makeprg' command"
@@ -9179,7 +9462,8 @@ msgid "insert characters backwards"
msgstr "karakterleri geriye doğru ekle"
msgid "allow CTRL-_ in Insert and Command-line mode to toggle 'revins'"
-msgstr "'revins' açıp kapatmak için Ekleme ve Komut Satırı kipinde\n"
+msgstr ""
+"'revins' açıp kapatmak için Ekleme ve Komut Satırı kipinde\n"
"CTRL-_ izin ver"
msgid "the ASCII code for the first letter of the Hebrew alphabet"
@@ -9210,8 +9494,9 @@ msgid "apply 'langmap' to mapped characters"
msgstr "eşlemlenen karakterlere 'langmap' uygula"
msgid "when set never use IM; overrules following IM options"
-msgstr "ayarlandığında hiçbir zaman IM kullanma; aşağıdaki IM seçeneklerini "
-"geçersiz kılar"
+msgstr ""
+"ayarlandığında hiçbir zaman IM kullanma; aşağıdaki IM seçeneklerini geçersiz "
+"kılar"
msgid "in Insert mode: 1: use :lmap; 2: use IM; 0: neither"
msgstr "Ekleme kipinde: 1: :lmap kullan; 2; IM kullan; 0: hiçbiri"
diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c
index f620517aff..606c03f838 100644
--- a/src/nvim/popupmnu.c
+++ b/src/nvim/popupmnu.c
@@ -9,26 +9,27 @@
#include <inttypes.h>
#include <stdbool.h>
-#include "nvim/vim.h"
#include "nvim/api/private/helpers.h"
#include "nvim/ascii.h"
-#include "nvim/eval/typval.h"
-#include "nvim/popupmnu.h"
+#include "nvim/buffer.h"
#include "nvim/charset.h"
+#include "nvim/edit.h"
+#include "nvim/eval/typval.h"
#include "nvim/ex_cmds.h"
#include "nvim/memline.h"
+#include "nvim/memory.h"
#include "nvim/move.h"
#include "nvim/option.h"
+#include "nvim/popupmnu.h"
#include "nvim/screen.h"
-#include "nvim/ui_compositor.h"
#include "nvim/search.h"
#include "nvim/strings.h"
-#include "nvim/memory.h"
-#include "nvim/window.h"
-#include "nvim/edit.h"
#include "nvim/ui.h"
+#include "nvim/ui_compositor.h"
+#include "nvim/vim.h"
+#include "nvim/window.h"
-static pumitem_T *pum_array = NULL; // items of displayed pum
+static pumitem_T *pum_array = NULL; // items of displayed pum
static int pum_size; // nr of items in "pum_array"
static int pum_selected; // index of selected item or -1
static int pum_first = 0; // index of top item
@@ -97,8 +98,7 @@ static void pum_compute_size(void)
/// if false, a new item is selected, but the array
/// is the same
/// @param cmd_startcol only for cmdline mode: column of completed match
-void pum_display(pumitem_T *array, int size, int selected, bool array_changed,
- int cmd_startcol)
+void pum_display(pumitem_T *array, int size, int selected, bool array_changed, int cmd_startcol)
{
int context_lines;
int above_row;
@@ -233,7 +233,7 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed,
context_lines = 3;
} else {
context_lines = curwin->w_cline_row
- + curwin->w_cline_height - curwin->w_wrow;
+ + curwin->w_cline_height - curwin->w_wrow;
}
pum_row = pum_win_row + context_lines;
@@ -487,17 +487,17 @@ void pum_redraw(void)
s = NULL;
switch (round) {
- case 1:
- p = pum_array[idx].pum_text;
- break;
+ case 1:
+ p = pum_array[idx].pum_text;
+ break;
- case 2:
- p = pum_array[idx].pum_kind;
- break;
+ case 2:
+ p = pum_array[idx].pum_kind;
+ break;
- case 3:
- p = pum_array[idx].pum_extra;
- break;
+ case 3:
+ p = pum_array[idx].pum_extra;
+ break;
}
if (p != NULL) {
@@ -514,7 +514,7 @@ void pum_redraw(void)
char_u saved = *p;
*p = NUL;
- st = (char_u *)transstr((const char *)s);
+ st = (char_u *)transstr((const char *)s, true);
*p = saved;
if (pum_rl) {
@@ -735,7 +735,7 @@ static int pum_set_selected(int n, int repeat)
&& (curbuf->b_p_bt[2] == 'f')
&& (curbuf->b_p_bh[0] == 'w')) {
// Already a "wipeout" buffer, make it empty.
- while (!BUFEMPTY()) {
+ while (!buf_is_empty(curbuf)) {
ml_delete((linenr_T)1, false);
}
} else {
diff --git a/src/nvim/profile.c b/src/nvim/profile.c
index 0a5030edae..fe7bd2e912 100644
--- a/src/nvim/profile.c
+++ b/src/nvim/profile.c
@@ -1,17 +1,16 @@
// 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 <stdio.h>
-#include <math.h>
#include <assert.h>
+#include <math.h>
+#include <stdio.h>
#include "nvim/assert.h"
-#include "nvim/profile.h"
-#include "nvim/os/time.h"
#include "nvim/func_attr.h"
-#include "nvim/os/os_defs.h"
-
#include "nvim/globals.h" // for the global `time_fd` (startuptime)
+#include "nvim/os/os_defs.h"
+#include "nvim/os/time.h"
+#include "nvim/profile.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "profile.c.generated.h"
@@ -97,7 +96,7 @@ proftime_T profile_divide(proftime_T tm, int count) FUNC_ATTR_CONST
return profile_zero();
}
- return (proftime_T) round((double) tm / (double) count);
+ return (proftime_T)round((double)tm / (double)count);
}
/// Adds time `tm2` to `tm1`.
@@ -250,7 +249,7 @@ void time_start(const char *message)
return;
}
- // intialize the global variables
+ // initialize the global variables
g_prev_time = g_start_time = profile_start();
fprintf(time_fd, "\n\ntimes in msec\n");
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 71624baaf4..eb0ba874f4 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -8,9 +8,8 @@
#include <stdbool.h>
#include <string.h>
-#include "nvim/vim.h"
+#include "nvim/api/private/helpers.h"
#include "nvim/ascii.h"
-#include "nvim/quickfix.h"
#include "nvim/buffer.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
@@ -26,48 +25,52 @@
#include "nvim/mark.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
+#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
-#include "nvim/memory.h"
#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/option.h"
+#include "nvim/os/input.h"
+#include "nvim/os/os.h"
#include "nvim/os_unix.h"
#include "nvim/path.h"
+#include "nvim/quickfix.h"
#include "nvim/regexp.h"
#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/strings.h"
#include "nvim/syntax.h"
#include "nvim/ui.h"
+#include "nvim/vim.h"
#include "nvim/window.h"
-#include "nvim/os/os.h"
-#include "nvim/os/input.h"
-#include "nvim/api/private/helpers.h"
struct dir_stack_T {
- struct dir_stack_T *next;
- char_u *dirname;
+ struct dir_stack_T *next;
+ char_u *dirname;
};
// For each error the next struct is allocated and linked in a list.
typedef struct qfline_S qfline_T;
struct qfline_S {
- qfline_T *qf_next; ///< pointer to next error in the list
- qfline_T *qf_prev; ///< pointer to previous error in the list
- linenr_T qf_lnum; ///< line number where the error occurred
- int qf_fnum; ///< file number for the line
- int qf_col; ///< column where the error occurred
- int qf_nr; ///< error number
- char_u *qf_module; ///< module name for this error
- char_u *qf_pattern; ///< search pattern for the error
- char_u *qf_text; ///< description of the error
- char_u qf_viscol; ///< set to TRUE if qf_col is screen column
- char_u qf_cleared; ///< set to TRUE if line has been deleted
- char_u qf_type; ///< type of the error (mostly 'E'); 1 for
- // :helpgrep
- char_u qf_valid; ///< valid error message detected
+ qfline_T *qf_next; ///< pointer to next error in the list
+ qfline_T *qf_prev; ///< pointer to previous error in the list
+ linenr_T qf_lnum; ///< line number where the error occurred
+ linenr_T qf_end_lnum; ///< line number when the error has range or zero
+
+ int qf_fnum; ///< file number for the line
+ int qf_col; ///< column where the error occurred
+ int qf_end_col; ///< column when the error has range or zero
+ int qf_nr; ///< error number
+ char_u *qf_module; ///< module name for this error
+ char_u *qf_pattern; ///< search pattern for the error
+ char_u *qf_text; ///< description of the error
+ char_u qf_viscol; ///< set to TRUE if qf_col and qf_end_col is
+ // screen column
+ char_u qf_cleared; ///< set to TRUE if line has been deleted
+ char_u qf_type; ///< type of the error (mostly 'E'); 1 for :helpgrep
+ char_u qf_valid; ///< valid error message detected
};
// There is a stack of error lists.
@@ -80,7 +83,7 @@ typedef enum
QFLT_QUICKFIX, ///< Quickfix list - global list
QFLT_LOCATION, ///< Location list - per window list
QFLT_INTERNAL ///< Internal - Temporary list used by
- // getqflist()/getloclist()
+ // getqflist()/getloclist()
} qfltype_T;
/// Quickfix/Location list definition
@@ -90,17 +93,17 @@ typedef enum
/// information and entries can be added later using setqflist()/setloclist().
typedef struct qf_list_S {
unsigned qf_id; ///< Unique identifier for this list
- qfltype_T qfl_type;
- qfline_T *qf_start; ///< pointer to the first error
- qfline_T *qf_last; ///< pointer to the last error
- qfline_T *qf_ptr; ///< pointer to the current error
+ qfltype_T qfl_type;
+ qfline_T *qf_start; ///< pointer to the first error
+ qfline_T *qf_last; ///< pointer to the last error
+ qfline_T *qf_ptr; ///< pointer to the current error
int qf_count; ///< number of errors (0 means empty list)
int qf_index; ///< current index in the error list
int qf_nonevalid; ///< TRUE if not a single valid entry found
- char_u *qf_title; ///< title derived from the command that created
- ///< the error list or set by setqflist
- typval_T *qf_ctx; ///< context set by setqflist/setloclist
- Callback qftf_cb; ///< 'quickfixtextfunc' callback function
+ char_u *qf_title; ///< title derived from the command that created
+ ///< the error list or set by setqflist
+ typval_T *qf_ctx; ///< context set by setqflist/setloclist
+ Callback qftf_cb; ///< 'quickfixtextfunc' callback function
struct dir_stack_T *qf_dir_stack;
char_u *qf_directory;
@@ -134,8 +137,8 @@ static unsigned last_qf_id = 0; // Last Used quickfix list id
// Structure used to hold the info of one part of 'errorformat'
typedef struct efm_S efm_T;
struct efm_S {
- regprog_T *prog; // pre-formatted part of 'errorformat'
- efm_T *next; // pointer to next (NULL if last)
+ regprog_T *prog; // pre-formatted part of 'errorformat'
+ efm_T *next; // pointer to next (NULL if last)
char_u addr[FMT_PATTERNS]; // indices of used % patterns
char_u prefix; // prefix of this format line:
// 'D' enter directory
@@ -180,12 +183,12 @@ typedef struct {
size_t linelen;
char_u *growbuf;
size_t growbufsiz;
- FILE *fd;
- typval_T *tv;
- char_u *p_str;
- list_T *p_list;
+ FILE *fd;
+ typval_T *tv;
+ char_u *p_str;
+ list_T *p_list;
listitem_T *p_li;
- buf_T *buf;
+ buf_T *buf;
linenr_T buflnum;
linenr_T lnumlast;
vimconv_T vc;
@@ -197,12 +200,14 @@ typedef struct {
char_u *errmsg;
size_t errmsglen;
long lnum;
- int col;
+ long end_lnum;
+ int col;
+ int end_col;
bool use_viscol;
char_u *pattern;
- int enr;
+ int enr;
char_u type;
- bool valid;
+ bool valid;
} qffields_T;
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -231,7 +236,7 @@ static char_u *e_no_more_items = (char_u *)N_("E553: No more items");
// Macro to loop through all the items in a quickfix list
// Quickfix item index starts from 1, so i below starts at 1
#define FOR_ALL_QFL_ITEMS(qfl, qfp, i) \
- for (i = 1, qfp = qfl->qf_start; /* NOLINT(readability/braces) */ \
+ for (i = 1, qfp = qfl->qf_start; /* NOLINT(readability/braces) */ \
!got_int && i <= qfl->qf_count && qfp != NULL; \
i++, qfp = qfp->qf_next)
@@ -239,7 +244,7 @@ static char_u *e_no_more_items = (char_u *)N_("E553: No more items");
// 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_u *qf_last_bufname = NULL;
-static bufref_T qf_last_bufref = { NULL, 0, 0 };
+static bufref_T qf_last_bufref = { NULL, 0, 0 };
static char *e_current_quickfix_list_was_changed =
N_("E925: Current quickfix list was changed");
@@ -253,9 +258,7 @@ static qf_delq_T *qf_delq_head = NULL;
/// Process the next line from a file/buffer/list/string and add it
/// to the quickfix list 'qfl'.
-static int qf_init_process_nextline(qf_list_T *qfl,
- efm_T *fmt_first,
- qfstate_T *state,
+static int qf_init_process_nextline(qf_list_T *qfl, efm_T *fmt_first, qfstate_T *state,
qffields_T *fields)
{
int status;
@@ -282,7 +285,9 @@ static int qf_init_process_nextline(qf_list_T *qfl,
0,
fields->errmsg,
fields->lnum,
+ fields->end_lnum,
fields->col,
+ fields->end_col,
fields->use_viscol,
fields->pattern,
fields->enr,
@@ -301,11 +306,10 @@ static int qf_init_process_nextline(qf_list_T *qfl,
/// @params enc If non-NULL, encoding used to parse errors
///
/// @returns -1 for error, number of errors for success.
-int qf_init(win_T *wp, const char_u *restrict efile,
- char_u *restrict errorformat, int newlist,
+int qf_init(win_T *wp, const char_u *restrict efile, char_u *restrict errorformat, int newlist,
const char_u *restrict qf_title, char_u *restrict enc)
{
- qf_info_T *qi = &ql_info;
+ qf_info_T *qi = &ql_info;
if (wp != NULL) {
qi = ll_get_or_alloc_list(wp);
@@ -331,7 +335,7 @@ static struct fmtpattern
{ 't', "." },
{ 'm', ".\\+" },
{ 'r', ".*" },
- { 'p', "[- .]*" }, // NOLINT(whitespace/tab)
+ { 'p', "[- .]*"}, // NOLINT(whitespace/tab)
{ 'v', "\\d\\+" },
{ 's', ".\\+" },
{ 'o', ".\\+" }
@@ -341,14 +345,8 @@ static struct fmtpattern
/// See fmt_pat definition above for the list of supported patterns. The
/// pattern specifier is supplied in "efmpat". The converted pattern is stored
/// in "regpat". Returns a pointer to the location after the pattern.
-static char_u * efmpat_to_regpat(
- const char_u *efmpat,
- char_u *regpat,
- efm_T *efminfo,
- int idx,
- int round,
- char_u *errmsg,
- size_t errmsglen)
+static char_u *efmpat_to_regpat(const char_u *efmpat, char_u *regpat, efm_T *efminfo, int idx,
+ int round, char_u *errmsg, size_t errmsglen)
FUNC_ATTR_NONNULL_ALL
{
if (efminfo->addr[idx]) {
@@ -367,7 +365,7 @@ static char_u * efmpat_to_regpat(
EMSG(errmsg);
return NULL;
}
- efminfo->addr[idx] = (char_u)++round;
+ efminfo->addr[idx] = (char_u)++ round;
*regpat++ = '\\';
*regpat++ = '(';
#ifdef BACKSLASH_IN_FILENAME
@@ -408,13 +406,8 @@ static char_u * efmpat_to_regpat(
/// Convert a scanf like format in 'errorformat' to a regular expression.
/// Returns a pointer to the location after the pattern.
-static char_u * scanf_fmt_to_regpat(
- const char_u **pefmp,
- const char_u *efm,
- int len,
- char_u *regpat,
- char_u *errmsg,
- size_t errmsglen)
+static char_u *scanf_fmt_to_regpat(const char_u **pefmp, const char_u *efm, int len, char_u *regpat,
+ char_u *errmsg, size_t errmsglen)
FUNC_ATTR_NONNULL_ALL
{
const char_u *efmp = *pefmp;
@@ -452,8 +445,8 @@ static char_u * scanf_fmt_to_regpat(
}
/// Analyze/parse an errorformat prefix.
-static const char_u *efm_analyze_prefix(const char_u *efmp, efm_T *efminfo,
- char_u *errmsg, size_t errmsglen)
+static const char_u *efm_analyze_prefix(const char_u *efmp, efm_T *efminfo, char_u *errmsg,
+ size_t errmsglen)
FUNC_ATTR_NONNULL_ALL
{
if (vim_strchr((char_u *)"+-", *efmp) != NULL) {
@@ -473,8 +466,8 @@ static const char_u *efm_analyze_prefix(const char_u *efmp, efm_T *efminfo,
// Converts a 'errorformat' string to regular expression pattern
-static int efm_to_regpat(const char_u *efm, int len, efm_T *fmt_ptr,
- char_u *regpat, char_u *errmsg, size_t errmsglen)
+static int efm_to_regpat(const char_u *efm, int len, efm_T *fmt_ptr, char_u *regpat, char_u *errmsg,
+ size_t errmsglen)
FUNC_ATTR_NONNULL_ALL
{
// Build regexp pattern from current 'errorformat' option
@@ -591,7 +584,7 @@ static int efm_option_part_len(char_u *efm)
/// Parse the 'errorformat' option. Multiple parts in the 'errorformat' option
/// are parsed and converted to regular expressions. Returns information about
/// the parsed 'errorformat' option.
-static efm_T * parse_efm_option(char_u *efm)
+static efm_T *parse_efm_option(char_u *efm)
{
efm_T *fmt_ptr = NULL;
efm_T *fmt_first = NULL;
@@ -762,7 +755,7 @@ retry:
errno = 0;
if (fgets((char *)IObuff, IOSIZE, state->fd) == NULL) {
if (errno == EINTR) {
- goto retry;
+ goto retry;
}
return QF_END_OF_INPUT;
}
@@ -908,7 +901,7 @@ static bool qf_list_has_valid_entries(qf_list_T *qfl)
}
/// Return a pointer to a list in the specified quickfix stack
-static qf_list_T * qf_get_list(qf_info_T *qi, int idx)
+static qf_list_T *qf_get_list(qf_info_T *qi, int idx)
FUNC_ATTR_NONNULL_ALL
{
return &qi->qf_lists[idx];
@@ -916,11 +909,11 @@ static qf_list_T * qf_get_list(qf_info_T *qi, int idx)
/// Parse a line and get the quickfix fields.
/// Return the QF_ status.
-static int qf_parse_line(qf_list_T *qfl, char_u *linebuf,
- size_t linelen, efm_T *fmt_first, qffields_T *fields)
+static int qf_parse_line(qf_list_T *qfl, char_u *linebuf, size_t linelen, efm_T *fmt_first,
+ qffields_T *fields)
{
efm_T *fmt_ptr;
- int idx = 0;
+ int idx = 0;
char_u *tail = NULL;
int status;
@@ -1023,14 +1016,8 @@ static void qf_free_fields(qffields_T *pfields)
// Setup the state information used for parsing lines and populating a
// quickfix list.
-static int qf_setup_state(
- qfstate_T *pstate,
- char_u *restrict enc,
- const char_u *restrict efile,
- typval_T *tv,
- buf_T *buf,
- linenr_T lnumfirst,
- linenr_T lnumlast)
+static int qf_setup_state(qfstate_T *pstate, char_u *restrict enc, const char_u *restrict efile,
+ typval_T *tv, buf_T *buf, linenr_T lnumfirst, linenr_T lnumlast)
FUNC_ATTR_NONNULL_ARG(1)
{
pstate->vc.vc_type = CONV_NONE;
@@ -1073,38 +1060,32 @@ static void qf_cleanup_state(qfstate_T *pstate)
}
}
-// Read the errorfile "efile" into memory, line by line, building the error
-// list.
-// Alternative: when "efile" is NULL read errors from buffer "buf".
-// Alternative: when "tv" is not NULL get errors from the string or list.
-// Always use 'errorformat' from "buf" if there is a local value.
-// Then "lnumfirst" and "lnumlast" specify the range of lines to use.
-// Set the title of the list to "qf_title".
-// Return -1 for error, number of errors for success.
-static int
-qf_init_ext(
- qf_info_T *qi,
- int qf_idx,
- const char_u *restrict efile,
- buf_T *buf,
- typval_T *tv,
- char_u *restrict errorformat,
- bool newlist, // true: start a new error list
- linenr_T lnumfirst, // first line number to use
- linenr_T lnumlast, // last line number to use
- const char_u *restrict qf_title,
- char_u *restrict enc
-)
+/// Read the errorfile "efile" into memory, line by line, building the error
+/// list.
+/// Alternative: when "efile" is NULL read errors from buffer "buf".
+/// Alternative: when "tv" is not NULL get errors from the string or list.
+/// Always use 'errorformat' from "buf" if there is a local value.
+/// Then "lnumfirst" and "lnumlast" specify the range of lines to use.
+/// Set the title of the list to "qf_title".
+///
+/// @param newlist true: start a new error list
+/// @param lnumfirst first line number to use
+/// @param lnumlast last line number to use
+///
+/// @return -1 for error, number of errors for success.
+static int qf_init_ext(qf_info_T *qi, int qf_idx, const char_u *restrict efile, buf_T *buf,
+ typval_T *tv, char_u *restrict errorformat, bool newlist, linenr_T lnumfirst,
+ linenr_T lnumlast, const char_u *restrict qf_title, char_u *restrict enc)
FUNC_ATTR_NONNULL_ARG(1)
{
qf_list_T *qfl;
qfstate_T state = { 0 };
qffields_T fields = { 0 };
- qfline_T *old_last = NULL;
+ qfline_T *old_last = NULL;
bool adding = false;
- static efm_T *fmt_first = NULL;
- char_u *efm;
- static char_u *last_efm = NULL;
+ static efm_T *fmt_first = NULL;
+ char_u *efm;
+ static char_u *last_efm = NULL;
int retval = -1; // default: return error flag
int status;
@@ -1230,7 +1211,7 @@ static void qf_store_title(qf_list_T *qfl, const char_u *title)
/// that created the quickfix list with the ":" prefix.
/// Create a quickfix list title string by prepending ":" to a user command.
/// Returns a pointer to a static buffer with the title.
-static char_u * qf_cmdtitle(char_u *cmd)
+static char_u *qf_cmdtitle(char_u *cmd)
{
static char_u qftitle_str[IOSIZE];
@@ -1240,7 +1221,7 @@ static char_u * qf_cmdtitle(char_u *cmd)
}
/// Return a pointer to the current list in the specified quickfix stack
-static qf_list_T * qf_get_curlist(qf_info_T *qi)
+static qf_list_T *qf_get_curlist(qf_info_T *qi)
FUNC_ATTR_NONNULL_ALL
{
return qf_get_list(qi, qi->qf_curlist);
@@ -1269,8 +1250,9 @@ static void qf_new_list(qf_info_T *qi, const char_u *qf_title)
qi->qf_lists[i - 1] = qi->qf_lists[i];
}
qi->qf_curlist = LISTCOUNT - 1;
- } else
+ } else {
qi->qf_curlist = qi->qf_listcount++;
+ }
qfl = qf_get_curlist(qi);
memset(qfl, 0, sizeof(qf_list_T));
qf_store_title(qfl, qf_title);
@@ -1280,10 +1262,7 @@ static void qf_new_list(qf_info_T *qi, const char_u *qf_title)
/// Parse the match for filename ('%f') pattern in regmatch.
/// Return the matched value in "fields->namebuf".
-static int qf_parse_fmt_f(regmatch_T *rmp,
- int midx,
- qffields_T *fields,
- int prefix)
+static int qf_parse_fmt_f(regmatch_T *rmp, int midx, qffields_T *fields, int prefix)
{
char_u c;
@@ -1353,9 +1332,7 @@ static int qf_parse_fmt_t(regmatch_T *rmp, int midx, qffields_T *fields)
/// Parse the match for '%+' format pattern. The whole matching line is included
/// in the error string. Return the matched line in "fields->errmsg".
-static void qf_parse_fmt_plus(const char_u *linebuf,
- size_t linelen,
- qffields_T *fields)
+static void qf_parse_fmt_plus(const char_u *linebuf, size_t linelen, qffields_T *fields)
FUNC_ATTR_NONNULL_ALL
{
if (linelen >= fields->errmsglen) {
@@ -1492,9 +1469,8 @@ static int (*qf_parse_fmt[FMT_PATTERNS])(regmatch_T *, int, qffields_T *) = {
/// fmt_ptr contains the 'efm' format specifiers/prefixes that have a match.
/// Returns QF_OK if all the matches are successfully parsed. On failure,
/// returns QF_FAIL or QF_NOMEM.
-static int qf_parse_match(char_u *linebuf, size_t linelen, efm_T *fmt_ptr,
- regmatch_T *regmatch, qffields_T *fields,
- int qf_multiline, int qf_multiscan, char_u **tail)
+static int qf_parse_match(char_u *linebuf, size_t linelen, efm_T *fmt_ptr, regmatch_T *regmatch,
+ qffields_T *fields, int qf_multiline, int qf_multiscan, char_u **tail)
{
char_u idx = fmt_ptr->prefix;
int i;
@@ -1542,9 +1518,8 @@ static int qf_parse_match(char_u *linebuf, size_t linelen, efm_T *fmt_ptr,
/// 'fmt_ptr->prog' and return the matching values in 'fields'.
/// Returns QF_OK if the efm format matches completely and the fields are
/// successfully copied. Otherwise returns QF_FAIL or QF_NOMEM.
-static int qf_parse_get_fields(char_u *linebuf, size_t linelen, efm_T *fmt_ptr,
- qffields_T *fields, int qf_multiline,
- int qf_multiscan, char_u **tail)
+static int qf_parse_get_fields(char_u *linebuf, size_t linelen, efm_T *fmt_ptr, qffields_T *fields,
+ int qf_multiline, int qf_multiscan, char_u **tail)
{
regmatch_T regmatch;
int status = QF_FAIL;
@@ -1561,7 +1536,9 @@ static int qf_parse_get_fields(char_u *linebuf, size_t linelen, efm_T *fmt_ptr,
fields->errmsg[0] = NUL;
}
fields->lnum = 0;
+ fields->end_lnum = 0;
fields->col = 0;
+ fields->end_col = 0;
fields->use_viscol = false;
fields->enr = -1;
fields->type = 0;
@@ -1602,8 +1579,7 @@ static int qf_parse_dir_pfx(int idx, qffields_T *fields, qf_list_T *qfl)
}
/// Parse global file name error format prefixes (%O, %P and %Q).
-static int qf_parse_file_pfx(int idx, qffields_T *fields, qf_list_T *qfl,
- char_u *tail)
+static int qf_parse_file_pfx(int idx, qffields_T *fields, qf_list_T *qfl, char_u *tail)
{
fields->valid = false;
if (*fields->namebuf == NUL || os_path_exists(fields->namebuf)) {
@@ -1626,8 +1602,7 @@ static int qf_parse_file_pfx(int idx, qffields_T *fields, qf_list_T *qfl,
/// Parse a non-error line (a line which doesn't match any of the error
/// format in 'efm').
-static int qf_parse_line_nomatch(char_u *linebuf, size_t linelen,
- qffields_T *fields)
+static int qf_parse_line_nomatch(char_u *linebuf, size_t linelen, qffields_T *fields)
{
fields->namebuf[0] = NUL; // no match found, remove file name
fields->lnum = 0; // don't jump to this line
@@ -1705,11 +1680,12 @@ static void locstack_queue_delreq(qf_info_T *qi)
static void ll_free_all(qf_info_T **pqi)
{
int i;
- qf_info_T *qi;
+ qf_info_T *qi;
qi = *pqi;
- if (qi == NULL)
+ if (qi == NULL) {
return;
+ }
*pqi = NULL; // Remove reference to this list
qi->qf_refcount--;
@@ -1732,7 +1708,7 @@ static void ll_free_all(qf_info_T **pqi)
void qf_free_all(win_T *wp)
{
int i;
- qf_info_T *qi = &ql_info;
+ qf_info_T *qi = &ql_info;
if (wp != NULL) {
// location list
@@ -1752,7 +1728,7 @@ void qf_free_all(win_T *wp)
/// Must always call decr_quickfix_busy() exactly once after this.
static void incr_quickfix_busy(void)
{
- quickfix_busy++;
+ quickfix_busy++;
}
/// Safe to free location list stacks. Process any delayed delete requests.
@@ -1799,7 +1775,9 @@ void check_quickfix_busy(void)
/// @param bufnum buffer number or zero
/// @param mesg message
/// @param lnum line number
+/// @param end_lnum line number for end
/// @param col column
+/// @param end_col column for end
/// @param vis_col using visual column
/// @param pattern search pattern
/// @param nr error number
@@ -1807,10 +1785,9 @@ void check_quickfix_busy(void)
/// @param valid valid entry
///
/// @returns QF_OK or QF_FAIL.
-static int qf_add_entry(qf_list_T *qfl, char_u *dir, char_u *fname,
- char_u *module, int bufnum, char_u *mesg, long lnum,
- int col, char_u vis_col, char_u *pattern, int nr,
- char_u type, char_u valid)
+static int qf_add_entry(qf_list_T *qfl, char_u *dir, char_u *fname, char_u *module, int bufnum,
+ char_u *mesg, long lnum, long end_lnum, int col, int end_col,
+ char_u vis_col, char_u *pattern, int nr, char_u type, char_u valid)
{
qfline_T *qfp = xmalloc(sizeof(qfline_T));
qfline_T **lastp; // pointer to qf_last or NULL
@@ -1828,7 +1805,9 @@ static int qf_add_entry(qf_list_T *qfl, char_u *dir, char_u *fname,
}
qfp->qf_text = vim_strsave(mesg);
qfp->qf_lnum = lnum;
+ qfp->qf_end_lnum = end_lnum;
qfp->qf_col = col;
+ qfp->qf_end_col = end_col;
qfp->qf_viscol = vis_col;
if (pattern == NULL || *pattern == NUL) {
qfp->qf_pattern = NULL;
@@ -1907,7 +1886,7 @@ static qf_info_T *ll_get_or_alloc_list(win_T *wp)
/// For a location list command, returns the stack for the current window. If
/// the location list is not found, then returns NULL and prints an error
/// message if 'print_emsg' is TRUE.
-static qf_info_T * qf_cmd_get_stack(exarg_T *eap, int print_emsg)
+static qf_info_T *qf_cmd_get_stack(exarg_T *eap, int print_emsg)
{
qf_info_T *qi = &ql_info;
@@ -1957,7 +1936,9 @@ static int copy_loclist_entries(const qf_list_T *from_qfl, qf_list_T *to_qfl)
0,
from_qfp->qf_text,
from_qfp->qf_lnum,
+ from_qfp->qf_end_lnum,
from_qfp->qf_col,
+ from_qfp->qf_end_col,
from_qfp->qf_viscol,
from_qfp->qf_pattern,
from_qfp->qf_nr,
@@ -2124,10 +2105,9 @@ static int qf_get_fnum(qf_list_T *qfl, char_u *directory, char_u *fname )
// Push dirbuf onto the directory stack and return pointer to actual dir or
// NULL on error.
-static char_u *qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr,
- bool is_file_stack)
+static char_u *qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr, bool is_file_stack)
{
- struct dir_stack_T *ds_ptr;
+ struct dir_stack_T *ds_ptr;
// allocate new stack element and hook it in
struct dir_stack_T *ds_new = xmalloc(sizeof(struct dir_stack_T));
@@ -2149,9 +2129,10 @@ static char_u *qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr,
while (ds_new) {
xfree((*stackptr)->dirname);
(*stackptr)->dirname = (char_u *)concat_fnames((char *)ds_new->dirname,
- (char *)dirbuf, TRUE);
- if (os_isdir((*stackptr)->dirname))
+ (char *)dirbuf, TRUE);
+ if (os_isdir((*stackptr)->dirname)) {
break;
+ }
ds_new = ds_new->next;
}
@@ -2171,9 +2152,9 @@ static char_u *qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr,
}
}
- if ((*stackptr)->dirname != NULL)
+ if ((*stackptr)->dirname != NULL) {
return (*stackptr)->dirname;
- else {
+ } else {
ds_ptr = *stackptr;
*stackptr = (*stackptr)->next;
xfree(ds_ptr);
@@ -2186,7 +2167,7 @@ static char_u *qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr,
// stack is empty
static char_u *qf_pop_dir(struct dir_stack_T **stackptr)
{
- struct dir_stack_T *ds_ptr;
+ struct dir_stack_T *ds_ptr;
// TODO(vim): Should we check if dirbuf is the directory on top of the stack?
// What to do if it isn't?
@@ -2206,7 +2187,7 @@ static char_u *qf_pop_dir(struct dir_stack_T **stackptr)
// clean up directory stack
static void qf_clean_dir_stack(struct dir_stack_T **stackptr)
{
- struct dir_stack_T *ds_ptr;
+ struct dir_stack_T *ds_ptr;
while ((ds_ptr = *stackptr) != NULL) {
*stackptr = (*stackptr)->next;
@@ -2235,9 +2216,9 @@ static void qf_clean_dir_stack(struct dir_stack_T **stackptr)
/// qf_guess_filepath will return NULL.
static char_u *qf_guess_filepath(qf_list_T *qfl, char_u *filename)
{
- struct dir_stack_T *ds_ptr;
- struct dir_stack_T *ds_tmp;
- char_u *fullname;
+ struct dir_stack_T *ds_ptr;
+ struct dir_stack_T *ds_tmp;
+ char_u *fullname;
// no dirs on the stack - there's nothing we can do
if (qfl->qf_dir_stack == NULL) {
@@ -2316,8 +2297,7 @@ static bool is_qf_entry_present(qf_list_T *qfl, qfline_T *qf_ptr)
/// Get the next valid entry in the current quickfix/location list. The search
/// starts from the current entry. Returns NULL on failure.
-static qfline_T *get_next_valid_entry(qf_list_T *qfl, qfline_T *qf_ptr,
- int *qf_index, int dir)
+static qfline_T *get_next_valid_entry(qf_list_T *qfl, qfline_T *qf_ptr, int *qf_index, int dir)
{
int idx = *qf_index;
int old_qf_fnum = qf_ptr->qf_fnum;
@@ -2337,8 +2317,7 @@ static qfline_T *get_next_valid_entry(qf_list_T *qfl, qfline_T *qf_ptr,
/// Get the previous valid entry in the current quickfix/location list. The
/// search starts from the current entry. Returns NULL on failure.
-static qfline_T *get_prev_valid_entry(qf_list_T *qfl, qfline_T *qf_ptr,
- int *qf_index, int dir)
+static qfline_T *get_prev_valid_entry(qf_list_T *qfl, qfline_T *qf_ptr, int *qf_index, int dir)
{
int idx = *qf_index;
int old_qf_fnum = qf_ptr->qf_fnum;
@@ -2360,8 +2339,7 @@ static qfline_T *get_prev_valid_entry(qf_list_T *qfl, qfline_T *qf_ptr,
/// the quickfix list.
/// dir == FORWARD or FORWARD_FILE: next valid entry
/// dir == BACKWARD or BACKWARD_FILE: previous valid entry
-static qfline_T *get_nth_valid_entry(qf_list_T *qfl, int errornr,
- int dir, int *new_qfidx)
+static qfline_T *get_nth_valid_entry(qf_list_T *qfl, int errornr, int dir, int *new_qfidx)
{
qfline_T *qf_ptr = qfl->qf_ptr;
int qf_idx = qfl->qf_index;
@@ -2421,25 +2399,24 @@ static qfline_T *get_nth_entry(qf_list_T *qfl, int errornr, int *new_qfidx)
return qf_ptr;
}
-/// Get a entry specied by 'errornr' and 'dir' from the current
+/// Get a entry specified by 'errornr' and 'dir' from the current
/// quickfix/location list. 'errornr' specifies the index of the entry and 'dir'
/// specifies the direction (FORWARD/BACKWARD/FORWARD_FILE/BACKWARD_FILE).
/// Returns a pointer to the entry and the index of the new entry is stored in
/// 'new_qfidx'.
-static qfline_T * qf_get_entry(qf_list_T *qfl, int errornr,
- int dir, int *new_qfidx)
+static qfline_T *qf_get_entry(qf_list_T *qfl, int errornr, int dir, int *new_qfidx)
{
- qfline_T *qf_ptr = qfl->qf_ptr;
- int qfidx = qfl->qf_index;
+ qfline_T *qf_ptr = qfl->qf_ptr;
+ int qfidx = qfl->qf_index;
- if (dir != 0) { // next/prev valid entry
- qf_ptr = get_nth_valid_entry(qfl, errornr, dir, &qfidx);
- } else if (errornr != 0) { // go to specified number
- qf_ptr = get_nth_entry(qfl, errornr, &qfidx);
- }
+ if (dir != 0) { // next/prev valid entry
+ qf_ptr = get_nth_valid_entry(qfl, errornr, dir, &qfidx);
+ } else if (errornr != 0) { // go to specified number
+ qf_ptr = get_nth_entry(qfl, errornr, &qfidx);
+ }
- *new_qfidx = qfidx;
- return qf_ptr;
+ *new_qfidx = qfidx;
+ return qf_ptr;
}
// Find a window displaying a Vim help file.
@@ -2580,8 +2557,7 @@ static int qf_open_new_file_win(qf_info_T *ll_ref)
// to the window just above the location list window. This is used for opening
// a file from a location window and not from a quickfix window. If some usable
// window is previously found, then it is supplied in 'use_win'.
-static void qf_goto_win_with_ll_file(win_T *use_win, int qf_fnum,
- qf_info_T *ll_ref)
+static void qf_goto_win_with_ll_file(win_T *use_win, int qf_fnum, qf_info_T *ll_ref)
{
win_T *win = use_win;
@@ -2668,8 +2644,7 @@ static void qf_goto_win_with_qfl_file(int qf_fnum)
// window, jump to it. Otherwise open a new window to display the file. If
// 'newwin' is true, then always open a new window. This is called from either
// a quickfix or a location list window.
-static int qf_jump_to_usable_window(int qf_fnum, bool newwin,
- int *opened_window)
+static int qf_jump_to_usable_window(int qf_fnum, bool newwin, int *opened_window)
{
win_T *usable_wp = NULL;
bool usable_win = false;
@@ -2719,8 +2694,8 @@ static int qf_jump_to_usable_window(int qf_fnum, bool newwin,
}
/// Edit the selected file or help file.
-static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit,
- win_T *oldwin, int *opened_window)
+static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit, win_T *oldwin,
+ int *opened_window)
{
qf_list_T *qfl = qf_get_curlist(qi);
long old_changetick = qfl->qf_changedtick;
@@ -2773,8 +2748,7 @@ static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit,
/// Go to the error line in the current file using either line/column number or
/// a search pattern.
-static void qf_jump_goto_line(linenr_T qf_lnum, int qf_col, char_u qf_viscol,
- char_u *qf_pattern)
+static void qf_jump_goto_line(linenr_T qf_lnum, int qf_col, char_u qf_viscol, char_u *qf_pattern)
{
linenr_T i;
@@ -2810,8 +2784,8 @@ static void qf_jump_goto_line(linenr_T qf_lnum, int qf_col, char_u qf_viscol,
}
/// Display quickfix list index and size message
-static void qf_jump_print_msg(qf_info_T *qi, int qf_index, qfline_T *qf_ptr,
- buf_T *old_curbuf, linenr_T old_lnum)
+static void qf_jump_print_msg(qf_info_T *qi, int qf_index, qfline_T *qf_ptr, buf_T *old_curbuf,
+ linenr_T old_lnum)
{
// Update the screen before showing the message, unless the screen
// scrolled up.
@@ -2846,15 +2820,14 @@ static void qf_jump_print_msg(qf_info_T *qi, int qf_index, qfline_T *qf_ptr,
/// Returns OK if successfully jumped or opened a window. Returns FAIL if not
/// able to jump/open a window. Returns NOTDONE if a file is not associated
/// with the entry.
-static int qf_jump_open_window(qf_info_T *qi, qfline_T *qf_ptr, bool newwin,
- int *opened_window)
+static int qf_jump_open_window(qf_info_T *qi, qfline_T *qf_ptr, bool newwin, int *opened_window)
{
qf_list_T *qfl = qf_get_curlist(qi);
long old_changetick = qfl->qf_changedtick;
int old_qf_curlist = qi->qf_curlist;
qfltype_T qfl_type = qfl->qfl_type;
- // For ":helpgrep" find a help window or open one.
+ // For ":helpgrep" find a help window or open one.
if (qf_ptr->qf_type == 1 && (!bt_help(curwin->w_buffer) || cmdmod.tab != 0)) {
if (jump_to_help_window(qi, newwin, opened_window) == FAIL) {
return FAIL;
@@ -2905,9 +2878,8 @@ static int qf_jump_open_window(qf_info_T *qi, qfline_T *qf_ptr, bool newwin,
/// Returns OK on success and FAIL on failing to open the file/buffer. Returns
/// NOTDONE if the quickfix/location list is freed by an autocmd when opening
/// the file.
-static int qf_jump_to_buffer(qf_info_T *qi, int qf_index, qfline_T *qf_ptr,
- int forceit, win_T *oldwin, int *opened_window,
- int openfold, int print_message)
+static int qf_jump_to_buffer(qf_info_T *qi, int qf_index, qfline_T *qf_ptr, int forceit,
+ win_T *oldwin, int *opened_window, int openfold, int print_message)
{
buf_T *old_curbuf;
linenr_T old_lnum;
@@ -2959,8 +2931,7 @@ void qf_jump(qf_info_T *qi, int dir, int errornr, int forceit)
// else if "errornr" is zero, redisplay the same line
// If 'forceit' is true, then can discard changes to the current buffer.
// If 'newwin' is true, then open the file in a new window.
-static void qf_jump_newwin(qf_info_T *qi, int dir, int errornr, int forceit,
- bool newwin)
+static void qf_jump_newwin(qf_info_T *qi, int dir, int errornr, int forceit, bool newwin)
{
qf_list_T *qfl;
qfline_T *qf_ptr;
@@ -2975,8 +2946,9 @@ static void qf_jump_newwin(qf_info_T *qi, int dir, int errornr, int forceit,
const bool old_KeyTyped = KeyTyped; // getting file may reset it
int retval = OK;
- if (qi == NULL)
+ if (qi == NULL) {
qi = &ql_info;
+ }
if (qf_stack_empty(qi) || qf_list_empty(qf_get_curlist(qi))) {
EMSG(_(e_quickfix));
@@ -2998,6 +2970,7 @@ static void qf_jump_newwin(qf_info_T *qi, int dir, int errornr, int forceit,
}
qfl->qf_index = qf_index;
+ qfl->qf_ptr = qf_ptr;
if (qf_win_pos_update(qi, old_qf_index)) {
// No need to print the error message if it's visible in the error
// window
@@ -3025,8 +2998,8 @@ static void qf_jump_newwin(qf_info_T *qi, int dir, int errornr, int forceit,
win_close(curwin, true); // Close opened window
}
if (qf_ptr != NULL && qf_ptr->qf_fnum != 0) {
- // Couldn't open file, so put index back where it was. This could
- // happen if the file was readonly and we changed something.
+ // Couldn't open file, so put index back where it was. This could
+ // happen if the file was readonly and we changed something.
failed:
qf_ptr = old_qf_ptr;
qf_index = old_qf_index;
@@ -3108,11 +3081,8 @@ static void qf_list_entry(qfline_T *qfp, int qf_idx, bool cursel)
}
if (qfp->qf_lnum == 0) {
IObuff[0] = NUL;
- } else if (qfp->qf_col == 0) {
- vim_snprintf((char *)IObuff, IOSIZE, "%" PRIdLINENR, qfp->qf_lnum);
} else {
- vim_snprintf((char *)IObuff, IOSIZE, "%" PRIdLINENR " col %d",
- qfp->qf_lnum, qfp->qf_col);
+ qf_range_text(qfp, IObuff, IOSIZE);
}
vim_snprintf((char *)IObuff + STRLEN(IObuff), IOSIZE, "%s",
(char *)qf_types(qfp->qf_type, qfp->qf_nr));
@@ -3144,9 +3114,9 @@ void qf_list(exarg_T *eap)
int i;
int idx1 = 1;
int idx2 = -1;
- char_u *arg = eap->arg;
- int all = eap->forceit; // if not :cl!, only show
- // recognised errors
+ char_u *arg = eap->arg;
+ int all = eap->forceit; // if not :cl!, only show
+ // recognised errors
qf_info_T *qi;
if ((qi = qf_cmd_get_stack(eap, true)) == NULL) {
@@ -3189,15 +3159,15 @@ void qf_list(exarg_T *eap)
// that this depends on syntax items defined in the qf.vim syntax file
qfFileAttr = syn_name2attr((char_u *)"qfFileName");
if (qfFileAttr == 0) {
- qfFileAttr = HL_ATTR(HLF_D);
+ qfFileAttr = HL_ATTR(HLF_D);
}
qfSepAttr = syn_name2attr((char_u *)"qfSeparator");
if (qfSepAttr == 0) {
- qfSepAttr = HL_ATTR(HLF_D);
+ qfSepAttr = HL_ATTR(HLF_D);
}
qfLineAttr = syn_name2attr((char_u *)"qfLineNr");
if (qfLineAttr == 0) {
- qfLineAttr = HL_ATTR(HLF_N);
+ qfLineAttr = HL_ATTR(HLF_N);
}
if (qfl->qf_nonevalid) {
@@ -3213,8 +3183,7 @@ void qf_list(exarg_T *eap)
// Remove newlines and leading whitespace from an error message.
// Put the result in "buf[bufsize]".
-static void qf_fmt_text(const char_u *restrict text, char_u *restrict buf,
- int bufsize)
+static void qf_fmt_text(const char_u *restrict text, char_u *restrict buf, int bufsize)
FUNC_ATTR_NONNULL_ALL
{
int i;
@@ -3223,15 +3192,44 @@ static void qf_fmt_text(const char_u *restrict text, char_u *restrict buf,
for (i = 0; *p != NUL && i < bufsize - 1; ++i) {
if (*p == '\n') {
buf[i] = ' ';
- while (*++p != NUL)
- if (!ascii_iswhite(*p) && *p != '\n')
+ while (*++p != NUL) {
+ if (!ascii_iswhite(*p) && *p != '\n') {
break;
- } else
+ }
+ }
+ } else {
buf[i] = *p++;
+ }
}
buf[i] = NUL;
}
+// Range information from lnum, col, end_lnum, and end_col.
+// Put the result in "buf[bufsize]".
+static void qf_range_text(const qfline_T *qfp, char_u *buf, int bufsize)
+{
+ vim_snprintf((char *)buf, (size_t)bufsize, "%" PRIdLINENR, qfp->qf_lnum);
+ int len = (int)STRLEN(buf);
+
+ if (qfp->qf_end_lnum > 0 && qfp->qf_lnum != qfp->qf_end_lnum) {
+ vim_snprintf((char *)buf + len, (size_t)(bufsize - len),
+ "-%" PRIdLINENR, qfp->qf_end_lnum);
+ len += (int)STRLEN(buf + len);
+ }
+ if (qfp->qf_col > 0) {
+ vim_snprintf((char *)buf + len, (size_t)(bufsize - len),
+ " col %d", qfp->qf_col);
+ len += (int)STRLEN(buf + len);
+ if (qfp->qf_end_col > 0 && qfp->qf_col != qfp->qf_end_col) {
+ vim_snprintf((char *)buf + len, (size_t)(bufsize - len),
+ "-%d", qfp->qf_end_col);
+ len += (int)STRLEN(buf + len);
+ }
+ }
+ 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)
@@ -3250,8 +3248,8 @@ static void qf_msg(qf_info_T *qi, int which, char *lead)
size_t len = STRLEN(buf);
if (len < 34) {
- memset(buf + len, ' ', 34 - len);
- buf[34] = NUL;
+ memset(buf + len, ' ', 34 - len);
+ buf[34] = NUL;
}
xstrlcat((char *)buf, title, IOSIZE);
}
@@ -3334,8 +3332,8 @@ void qf_history(exarg_T *eap)
/// associated with the list like context and title are not freed.
static void qf_free_items(qf_list_T *qfl)
{
- qfline_T *qfp;
- qfline_T *qfpnext;
+ qfline_T *qfp;
+ qfline_T *qfpnext;
bool stop = false;
while (qfl->qf_count && qfl->qf_start != NULL) {
@@ -3390,13 +3388,12 @@ static void qf_free(qf_list_T *qfl)
}
// qf_mark_adjust: adjust marks
-bool qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, long amount,
- long amount_after)
+bool qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, long amount, long amount_after)
{
int i;
- qfline_T *qfp;
+ qfline_T *qfp;
int idx;
- qf_info_T *qi = &ql_info;
+ qf_info_T *qi = &ql_info;
bool found_one = false;
int buf_has_flag = wp == NULL ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY;
@@ -3417,12 +3414,14 @@ bool qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, long amount,
if (qfp->qf_fnum == curbuf->b_fnum) {
found_one = true;
if (qfp->qf_lnum >= line1 && qfp->qf_lnum <= line2) {
- if (amount == MAXLNUM)
+ if (amount == MAXLNUM) {
qfp->qf_cleared = TRUE;
- else
+ } else {
qfp->qf_lnum += amount;
- } else if (amount_after && qfp->qf_lnum > line2)
+ }
+ } else if (amount_after && qfp->qf_lnum > line2) {
qfp->qf_lnum += amount_after;
+ }
}
}
}
@@ -3450,7 +3449,7 @@ static char_u *qf_types(int c, int nr)
{
static char_u buf[20];
static char_u cc[3];
- char_u *p;
+ char_u *p;
if (c == 'W' || c == 'w') {
p = (char_u *)" warning";
@@ -3469,8 +3468,9 @@ static char_u *qf_types(int c, int nr)
p = cc;
}
- if (nr <= 0)
+ if (nr <= 0) {
return p;
+ }
sprintf((char *)buf, "%s %3d", (char *)p, nr);
return buf;
@@ -3480,7 +3480,7 @@ static char_u *qf_types(int c, int nr)
// When "split" is true: Open the entry/result under the cursor in a new window.
void qf_view_result(bool split)
{
- qf_info_T *qi = &ql_info;
+ qf_info_T *qi = &ql_info;
if (!bt_quickfix(curbuf)) {
return;
@@ -3509,9 +3509,9 @@ void qf_view_result(bool split)
// close it if not.
void ex_cwindow(exarg_T *eap)
{
- qf_info_T *qi;
- qf_list_T *qfl;
- win_T *win;
+ qf_info_T *qi;
+ qf_list_T *qfl;
+ win_T *win;
if ((qi = qf_cmd_get_stack(eap, true)) == NULL) {
return;
@@ -3556,8 +3556,7 @@ void ex_cclose(exarg_T *eap)
// Goto a quickfix or location list window (if present).
// Returns OK if the window is found, FAIL otherwise.
-static int qf_goto_cwindow(const qf_info_T *qi, bool resize, int sz,
- bool vertsplit)
+static int qf_goto_cwindow(const qf_info_T *qi, bool resize, int sz, bool vertsplit)
{
win_T *const win = qf_find_win(qi);
if (win == NULL) {
@@ -3685,8 +3684,8 @@ static void qf_set_title_var(qf_list_T *qfl)
/// ":lopen": open a window that shows the location list.
void ex_copen(exarg_T *eap)
{
- qf_info_T *qi;
- qf_list_T *qfl;
+ qf_info_T *qi;
+ qf_list_T *qfl;
int height;
int status = FAIL;
int lnum;
@@ -3772,7 +3771,7 @@ void ex_cbottom(exarg_T *eap)
// window).
linenr_T qf_current_entry(win_T *wp)
{
- qf_info_T *qi = &ql_info;
+ qf_info_T *qi = &ql_info;
if (IS_LL_WINDOW(wp)) {
// In the location list window, use the referenced location list
@@ -3782,14 +3781,13 @@ linenr_T qf_current_entry(win_T *wp)
return qf_get_curlist(qi)->qf_index;
}
-// Update the cursor position in the quickfix window to the current error.
-// Return TRUE if there is a quickfix window.
-static int qf_win_pos_update(
- qf_info_T *qi,
- int old_qf_index // previous qf_index or zero
-)
+/// Update the cursor position in the quickfix window to the current error.
+/// Return TRUE if there is a quickfix window.
+///
+/// @param old_qf_index previous qf_index or zero
+static int qf_win_pos_update(qf_info_T *qi, int old_qf_index)
{
- win_T *win;
+ win_T *win;
int qf_index = qf_get_curlist(qi)->qf_index;
// Put the cursor on the current error in the quickfix window, so that
@@ -3914,8 +3912,8 @@ static void qf_update_win_titlevar(qf_info_T *qi)
// Find the quickfix buffer. If it exists, update the contents.
static void qf_update_buffer(qf_info_T *qi, qfline_T *old_last)
{
- buf_T *buf;
- win_T *win;
+ buf_T *buf;
+ win_T *win;
aco_save_T aco;
// Check if a buffer for the quickfix list exists. Update it.
@@ -3962,9 +3960,8 @@ static void qf_update_buffer(qf_info_T *qi, qfline_T *old_last)
}
// Add an error line to the quickfix buffer.
-static int qf_buf_add_line(qf_list_T *qfl, buf_T *buf, linenr_T lnum,
- const qfline_T *qfp, char_u *dirname,
- char_u *qftf_str, bool first_bufline)
+static int qf_buf_add_line(qf_list_T *qfl, buf_T *buf, linenr_T lnum, const qfline_T *qfp,
+ char_u *dirname, char_u *qftf_str, bool first_bufline)
FUNC_ATTR_NONNULL_ARG(1, 2, 4, 5)
{
int len;
@@ -4005,16 +4002,9 @@ static int qf_buf_add_line(qf_list_T *qfl, buf_T *buf, linenr_T lnum,
IObuff[len++] = '|';
}
if (qfp->qf_lnum > 0) {
- snprintf((char *)IObuff + len, (size_t)(IOSIZE - len), "%" PRId64,
- (int64_t)qfp->qf_lnum);
+ qf_range_text(qfp, IObuff + len, IOSIZE - len);
len += (int)STRLEN(IObuff + len);
- if (qfp->qf_col > 0) {
- snprintf((char *)IObuff + len, (size_t)(IOSIZE - len), " col %d",
- qfp->qf_col);
- len += (int)STRLEN(IObuff + len);
- }
-
snprintf((char *)IObuff + len, (size_t)(IOSIZE - len), "%s",
(char *)qf_types(qfp->qf_type, qfp->qf_nr));
len += (int)STRLEN(IObuff + len);
@@ -4043,10 +4033,7 @@ static int qf_buf_add_line(qf_list_T *qfl, buf_T *buf, linenr_T lnum,
// Call the 'quickfixtextfunc' function to get the list of lines to display in
// the quickfix window for the entries 'start_idx' to 'end_idx'.
-static list_T *call_qftf_func(qf_list_T *qfl,
- int qf_winid,
- long start_idx,
- long end_idx)
+static list_T *call_qftf_func(qf_list_T *qfl, int qf_winid, long start_idx, long end_idx)
{
Callback *cb = &qftf_cb;
list_T *qftf_list = NULL;
@@ -4093,12 +4080,11 @@ static list_T *call_qftf_func(qf_list_T *qfl,
/// If "old_last" is not NULL append the items after this one.
/// When "old_last" is NULL then "buf" must equal "curbuf"! Because ml_delete()
/// is used and autocommands will be triggered.
-static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last,
- int qf_winid)
+static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int qf_winid)
FUNC_ATTR_NONNULL_ARG(2)
{
linenr_T lnum;
- qfline_T *qfp;
+ qfline_T *qfp;
const bool old_KeyTyped = KeyTyped;
list_T *qftf_list = NULL;
listitem_T *qftf_li = NULL;
@@ -4117,11 +4103,11 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last,
// Check if there is anything to display
if (qfl != NULL) {
- char_u dirname[MAXPATHL];
- int prev_bufnr = -1;
- bool invalid_val = false;
+ char_u dirname[MAXPATHL];
+ int prev_bufnr = -1;
+ bool invalid_val = false;
- *dirname = NUL;
+ *dirname = NUL;
// Add one line for each error
if (old_last == NULL) {
@@ -4180,7 +4166,7 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last,
// Set the 'filetype' to "qf" each time after filling the buffer. This
// resembles reading a file into a buffer, it's more logical when using
// autocommands.
- curbuf_lock++;
+ curbuf->b_ro_locked++;
set_option_value("ft", 0L, "qf", OPT_LOCAL);
curbuf->b_p_ma = false;
@@ -4190,7 +4176,7 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last,
apply_autocmds(EVENT_BUFWINENTER, (char_u *)"quickfix", NULL,
false, curbuf);
keep_filetype = false;
- curbuf_lock--;
+ curbuf->b_ro_locked--;
// make sure it will be redrawn
redraw_curbuf_later(NOT_VALID);
@@ -4202,7 +4188,7 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last,
static void qf_list_changed(qf_list_T *qfl)
{
- qfl->qf_changedtick++;
+ qfl->qf_changedtick++;
}
/// Return the quickfix/location list number with the given identifier.
@@ -4258,7 +4244,7 @@ int grep_internal(cmdidx_T cmdidx)
|| cmdidx == CMD_grepadd
|| cmdidx == CMD_lgrepadd)
&& STRCMP("internal",
- *curbuf->b_p_gp == NUL ? p_gp : curbuf->b_p_gp) == 0;
+ *curbuf->b_p_gp == NUL ? p_gp : curbuf->b_p_gp) == 0;
}
// Return the make/grep autocmd name.
@@ -4266,20 +4252,20 @@ static char_u *make_get_auname(cmdidx_T cmdidx)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
switch (cmdidx) {
- case CMD_make:
- return (char_u *)"make";
- case CMD_lmake:
- return (char_u *)"lmake";
- case CMD_grep:
- return (char_u *)"grep";
- case CMD_lgrep:
- return (char_u *)"lgrep";
- case CMD_grepadd:
- return (char_u *)"grepadd";
- case CMD_lgrepadd:
- return (char_u *)"lgrepadd";
- default:
- return NULL;
+ case CMD_make:
+ return (char_u *)"make";
+ case CMD_lmake:
+ return (char_u *)"lmake";
+ case CMD_grep:
+ return (char_u *)"grep";
+ case CMD_lgrep:
+ return (char_u *)"lgrep";
+ case CMD_grepadd:
+ return (char_u *)"grepadd";
+ case CMD_lgrepadd:
+ return (char_u *)"lgrepadd";
+ default:
+ return NULL;
}
}
@@ -4316,9 +4302,9 @@ static char *make_get_fullcmd(const char_u *makecmd, const char_u *fname)
// Used for ":make", ":lmake", ":grep", ":lgrep", ":grepadd", and ":lgrepadd"
void ex_make(exarg_T *eap)
{
- char_u *fname;
- win_T *wp = NULL;
- qf_info_T *qi = &ql_info;
+ char_u *fname;
+ win_T *wp = NULL;
+ qf_info_T *qi = &ql_info;
int res;
char_u *enc = (*curbuf->b_p_menc != NUL) ? curbuf->b_p_menc : p_menc;
@@ -4342,8 +4328,9 @@ void ex_make(exarg_T *eap)
autowrite_all();
fname = get_mef_name();
- if (fname == NULL)
+ if (fname == NULL) {
return;
+ }
os_remove((char *)fname); // in case it's not unique
char *const cmd = make_get_fullcmd(eap->arg, fname);
@@ -4389,24 +4376,28 @@ cleanup:
// Returns NULL for error.
static char_u *get_mef_name(void)
{
- char_u *p;
- char_u *name;
+ char_u *p;
+ char_u *name;
static int start = -1;
static int off = 0;
if (*p_mef == NUL) {
name = vim_tempname();
- if (name == NULL)
+ if (name == NULL) {
EMSG(_(e_notmp));
+ }
return name;
}
- for (p = p_mef; *p; ++p)
- if (p[0] == '#' && p[1] == '#')
+ for (p = p_mef; *p; ++p) {
+ if (p[0] == '#' && p[1] == '#') {
break;
+ }
+ }
- if (*p == NUL)
+ if (*p == NUL) {
return vim_strsave(p_mef);
+ }
// Keep trying until the name doesn't exist yet.
for (;; ) {
@@ -4580,7 +4571,7 @@ static size_t qf_get_nth_valid_entry(qf_list_T *qfl, size_t n, int fdo)
/// ":cdo", ":ldo", ":cfdo" and ":lfdo".
void ex_cc(exarg_T *eap)
{
- qf_info_T *qi;
+ qf_info_T *qi;
if ((qi = qf_cmd_get_stack(eap, true)) == NULL) {
return;
@@ -4591,19 +4582,19 @@ void ex_cc(exarg_T *eap)
errornr = (int)eap->line2;
} else {
switch (eap->cmdidx) {
- case CMD_cc:
- case CMD_ll:
- errornr = 0;
- break;
- case CMD_crewind:
- case CMD_lrewind:
- case CMD_cfirst:
- case CMD_lfirst:
- errornr = 1;
- break;
- default:
- errornr = 32767;
- break;
+ case CMD_cc:
+ case CMD_ll:
+ errornr = 0;
+ break;
+ case CMD_crewind:
+ case CMD_lrewind:
+ case CMD_cfirst:
+ case CMD_lfirst:
+ errornr = 1;
+ break;
+ default:
+ errornr = 32767;
+ break;
}
}
@@ -4618,9 +4609,8 @@ void ex_cc(exarg_T *eap)
} else {
n = 1;
}
- size_t valid_entry = qf_get_nth_valid_entry(
- qf_get_curlist(qi), n,
- eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo);
+ size_t valid_entry = qf_get_nth_valid_entry(qf_get_curlist(qi), n,
+ eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo);
assert(valid_entry <= INT_MAX);
errornr = (int)valid_entry;
}
@@ -4633,7 +4623,7 @@ void ex_cc(exarg_T *eap)
/// ":cdo", ":ldo", ":cfdo" and ":lfdo".
void ex_cnext(exarg_T *eap)
{
- qf_info_T *qi;
+ qf_info_T *qi;
if ((qi = qf_cmd_get_stack(eap, true)) == NULL) {
return;
@@ -4651,31 +4641,31 @@ void ex_cnext(exarg_T *eap)
// Depending on the command jump to either next or previous entry/file.
Direction dir;
switch (eap->cmdidx) {
- case CMD_cprevious:
- case CMD_lprevious:
- case CMD_cNext:
- case CMD_lNext:
- dir = BACKWARD;
- break;
- case CMD_cnfile:
- case CMD_lnfile:
- case CMD_cfdo:
- case CMD_lfdo:
- dir = FORWARD_FILE;
- break;
- case CMD_cpfile:
- case CMD_lpfile:
- case CMD_cNfile:
- case CMD_lNfile:
- dir = BACKWARD_FILE;
- break;
- case CMD_cnext:
- case CMD_lnext:
- case CMD_cdo:
- case CMD_ldo:
- default:
- dir = FORWARD;
- break;
+ case CMD_cprevious:
+ case CMD_lprevious:
+ case CMD_cNext:
+ case CMD_lNext:
+ dir = BACKWARD;
+ break;
+ case CMD_cnfile:
+ case CMD_lnfile:
+ case CMD_cfdo:
+ case CMD_lfdo:
+ dir = FORWARD_FILE;
+ break;
+ case CMD_cpfile:
+ case CMD_lpfile:
+ case CMD_cNfile:
+ case CMD_lNfile:
+ dir = BACKWARD_FILE;
+ break;
+ case CMD_cnext:
+ case CMD_lnext:
+ case CMD_cdo:
+ case CMD_ldo:
+ default:
+ dir = FORWARD;
+ break;
}
qf_jump(qi, dir, errornr, eap->forceit);
@@ -4684,9 +4674,7 @@ void ex_cnext(exarg_T *eap)
/// Find the first entry in the quickfix list 'qfl' from buffer 'bnr'.
/// The index of the entry is stored in 'errornr'.
/// Returns NULL if an entry is not found.
-static qfline_T *qf_find_first_entry_in_buf(qf_list_T *qfl,
- int bnr,
- int *errornr)
+static qfline_T *qf_find_first_entry_in_buf(qf_list_T *qfl, int bnr, int *errornr)
{
qfline_T *qfp = NULL;
int idx = 0;
@@ -4705,7 +4693,7 @@ static qfline_T *qf_find_first_entry_in_buf(qf_list_T *qfl,
/// Find the first quickfix entry on the same line as 'entry'. Updates 'errornr'
/// with the error number for the first entry. Assumes the entries are sorted in
/// the quickfix list by line number.
-static qfline_T * qf_find_first_entry_on_line(qfline_T *entry, int *errornr)
+static qfline_T *qf_find_first_entry_on_line(qfline_T *entry, int *errornr)
{
while (!got_int
&& entry->qf_prev != NULL
@@ -4721,7 +4709,7 @@ static qfline_T * qf_find_first_entry_on_line(qfline_T *entry, int *errornr)
/// Find the last quickfix entry on the same line as 'entry'. Updates 'errornr'
/// with the error number for the last entry. Assumes the entries are sorted in
/// the quickfix list by line number.
-static qfline_T * qf_find_last_entry_on_line(qfline_T *entry, int *errornr)
+static qfline_T *qf_find_last_entry_on_line(qfline_T *entry, int *errornr)
{
while (!got_int
&& entry->qf_next != NULL
@@ -4737,57 +4725,53 @@ static qfline_T * qf_find_last_entry_on_line(qfline_T *entry, int *errornr)
// Returns true if the specified quickfix entry is
// after the given line (linewise is true)
// or after the line and column.
-static bool qf_entry_after_pos(const qfline_T *qfp, const pos_T *pos,
- bool linewise)
+static bool qf_entry_after_pos(const qfline_T *qfp, const pos_T *pos, bool linewise)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
if (linewise) {
return qfp->qf_lnum > pos->lnum;
}
return qfp->qf_lnum > pos->lnum
- || (qfp->qf_lnum == pos->lnum && qfp->qf_col > pos->col);
+ || (qfp->qf_lnum == pos->lnum && qfp->qf_col > pos->col);
}
// Returns true if the specified quickfix entry is
// before the given line (linewise is true)
// or before the line and column.
-static bool qf_entry_before_pos(const qfline_T *qfp, const pos_T *pos,
- bool linewise)
+static bool qf_entry_before_pos(const qfline_T *qfp, const pos_T *pos, bool linewise)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
if (linewise) {
return qfp->qf_lnum < pos->lnum;
}
return qfp->qf_lnum < pos->lnum
- || (qfp->qf_lnum == pos->lnum && qfp->qf_col < pos->col);
+ || (qfp->qf_lnum == pos->lnum && qfp->qf_col < pos->col);
}
// Returns true if the specified quickfix entry is
// on or after the given line (linewise is true)
// or on or after the line and column.
-static bool qf_entry_on_or_after_pos(const qfline_T *qfp, const pos_T *pos,
- bool linewise)
+static bool qf_entry_on_or_after_pos(const qfline_T *qfp, const pos_T *pos, bool linewise)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
if (linewise) {
return qfp->qf_lnum >= pos->lnum;
}
return qfp->qf_lnum > pos->lnum
- || (qfp->qf_lnum == pos->lnum && qfp->qf_col >= pos->col);
+ || (qfp->qf_lnum == pos->lnum && qfp->qf_col >= pos->col);
}
// Returns true if the specified quickfix entry is
// on or before the given line (linewise is true)
// or on or before the line and column.
-static bool qf_entry_on_or_before_pos(const qfline_T *qfp, const pos_T *pos,
- bool linewise)
+static bool qf_entry_on_or_before_pos(const qfline_T *qfp, const pos_T *pos, bool linewise)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
if (linewise) {
return qfp->qf_lnum <= pos->lnum;
}
return qfp->qf_lnum < pos->lnum
- || (qfp->qf_lnum == pos->lnum && qfp->qf_col <= pos->col);
+ || (qfp->qf_lnum == pos->lnum && qfp->qf_col <= pos->col);
}
/// Find the first quickfix entry after position 'pos' in buffer 'bnr'.
@@ -4797,17 +4781,12 @@ static bool qf_entry_on_or_before_pos(const qfline_T *qfp, const pos_T *pos,
/// 'qfp' points to the very first entry in the buffer and 'errornr' is the
/// index of the very first entry in the quickfix list.
/// Returns NULL if an entry is not found after 'pos'.
-static qfline_T *qf_find_entry_after_pos(
- int bnr,
- const pos_T *pos,
- bool linewise,
- qfline_T *qfp,
- int *errornr
-)
+static qfline_T *qf_find_entry_after_pos(int bnr, const pos_T *pos, bool linewise, qfline_T *qfp,
+ int *errornr)
FUNC_ATTR_NONNULL_ALL
{
if (qf_entry_after_pos(qfp, pos, linewise)) {
- // First entry is after postion 'pos'
+ // First entry is after position 'pos'
return qfp;
}
@@ -4838,13 +4817,8 @@ static qfline_T *qf_find_entry_after_pos(
/// 'qfp' points to the very first entry in the buffer and 'errornr' is the
/// index of the very first entry in the quickfix list.
/// Returns NULL if an entry is not found before 'pos'.
-static qfline_T *qf_find_entry_before_pos(
- int bnr,
- const pos_T *pos,
- bool linewise,
- qfline_T *qfp,
- int *errornr
-)
+static qfline_T *qf_find_entry_before_pos(int bnr, const pos_T *pos, bool linewise, qfline_T *qfp,
+ int *errornr)
FUNC_ATTR_NONNULL_ALL
{
// Find the entry just before the position 'pos'
@@ -4869,14 +4843,8 @@ static qfline_T *qf_find_entry_before_pos(
/// Find a quickfix entry in 'qfl' closest to position 'pos' in buffer 'bnr' in
/// the direction 'dir'.
-static qfline_T *qf_find_closest_entry(
- qf_list_T *qfl,
- int bnr,
- const pos_T *pos,
- Direction dir,
- bool linewise,
- int *errornr
-)
+static qfline_T *qf_find_closest_entry(qf_list_T *qfl, int bnr, const pos_T *pos, Direction dir,
+ bool linewise, int *errornr)
FUNC_ATTR_NONNULL_ALL
{
qfline_T *qfp;
@@ -4901,8 +4869,7 @@ static qfline_T *qf_find_closest_entry(
/// Get the nth quickfix entry below the specified entry. Searches forward in
/// the list. If linewise is true, then treat multiple entries on a single line
/// as one.
-static void qf_get_nth_below_entry(qfline_T *entry, linenr_T n,
- bool linewise, int *errornr)
+static void qf_get_nth_below_entry(qfline_T *entry, linenr_T n, bool linewise, int *errornr)
FUNC_ATTR_NONNULL_ALL
{
while (n-- > 0 && !got_int) {
@@ -4933,8 +4900,7 @@ static void qf_get_nth_below_entry(qfline_T *entry, linenr_T n,
/// Get the nth quickfix entry above the specified entry. Searches backwards in
/// the list. If linewise is TRUE, then treat multiple entries on a single line
/// as one.
-static void qf_get_nth_above_entry(qfline_T *entry, linenr_T n,
- bool linewise, int *errornr)
+static void qf_get_nth_above_entry(qfline_T *entry, linenr_T n, bool linewise, int *errornr)
FUNC_ATTR_NONNULL_ALL
{
while (n-- > 0 && !got_int) {
@@ -4955,14 +4921,8 @@ static void qf_get_nth_above_entry(qfline_T *entry, linenr_T n,
/// Find the n'th quickfix entry adjacent to position 'pos' in buffer 'bnr' in
/// the specified direction. Returns the error number in the quickfix list or 0
/// if an entry is not found.
-static int qf_find_nth_adj_entry(
- qf_list_T *qfl,
- int bnr,
- pos_T *pos,
- linenr_T n,
- Direction dir,
- bool linewise
-)
+static int qf_find_nth_adj_entry(qf_list_T *qfl, int bnr, pos_T *pos, linenr_T n, Direction dir,
+ bool linewise)
FUNC_ATTR_NONNULL_ALL
{
int errornr;
@@ -5039,16 +4999,15 @@ void ex_cbelow(exarg_T *eap)
// A quickfix entry column number is 1 based whereas cursor column
// number is 0 based. Adjust the column number.
pos.col++;
- const int errornr = qf_find_nth_adj_entry(
- qfl,
- curbuf->b_fnum,
- &pos,
- eap->addr_count > 0 ? eap->line2 : 0,
- dir,
- eap->cmdidx == CMD_cbelow
- || eap->cmdidx == CMD_lbelow
- || eap->cmdidx == CMD_cabove
- || eap->cmdidx == CMD_labove);
+ const int errornr = qf_find_nth_adj_entry(qfl,
+ curbuf->b_fnum,
+ &pos,
+ eap->addr_count > 0 ? eap->line2 : 0,
+ dir,
+ eap->cmdidx == CMD_cbelow
+ || eap->cmdidx == CMD_lbelow
+ || eap->cmdidx == CMD_cabove
+ || eap->cmdidx == CMD_labove);
if (errornr > 0) {
qf_jump(qi, 0, errornr, false);
@@ -5059,16 +5018,23 @@ void ex_cbelow(exarg_T *eap)
/// Return the autocmd name for the :cfile Ex commands
-static char_u * cfile_get_auname(cmdidx_T cmdidx)
+static char_u *cfile_get_auname(cmdidx_T cmdidx)
{
switch (cmdidx) {
- case CMD_cfile: return (char_u *)"cfile";
- case CMD_cgetfile: return (char_u *)"cgetfile";
- case CMD_caddfile: return (char_u *)"caddfile";
- case CMD_lfile: return (char_u *)"lfile";
- case CMD_lgetfile: return (char_u *)"lgetfile";
- case CMD_laddfile: return (char_u *)"laddfile";
- default: return NULL;
+ case CMD_cfile:
+ return (char_u *)"cfile";
+ case CMD_cgetfile:
+ return (char_u *)"cgetfile";
+ case CMD_caddfile:
+ return (char_u *)"caddfile";
+ case CMD_lfile:
+ return (char_u *)"lfile";
+ case CMD_lgetfile:
+ return (char_u *)"lgetfile";
+ case CMD_laddfile:
+ return (char_u *)"laddfile";
+ default:
+ return NULL;
}
}
@@ -5077,9 +5043,9 @@ static char_u * cfile_get_auname(cmdidx_T cmdidx)
// ":lfile"/":lgetfile"/":laddfile" commands.
void ex_cfile(exarg_T *eap)
{
- win_T *wp = NULL;
- qf_info_T *qi = &ql_info;
- char_u *au_name = NULL;
+ win_T *wp = NULL;
+ qf_info_T *qi = &ql_info;
+ char_u *au_name = NULL;
au_name = cfile_get_auname(eap->cmdidx);
if (au_name != NULL
@@ -5140,15 +5106,24 @@ void ex_cfile(exarg_T *eap)
static char_u *vgr_get_auname(cmdidx_T cmdidx)
{
switch (cmdidx) {
- case CMD_vimgrep: return (char_u *)"vimgrep";
- case CMD_lvimgrep: return (char_u *)"lvimgrep";
- case CMD_vimgrepadd: return (char_u *)"vimgrepadd";
- case CMD_lvimgrepadd: return (char_u *)"lvimgrepadd";
- case CMD_grep: return (char_u *)"grep";
- case CMD_lgrep: return (char_u *)"lgrep";
- case CMD_grepadd: return (char_u *)"grepadd";
- case CMD_lgrepadd: return (char_u *)"lgrepadd";
- default: return NULL;
+ case CMD_vimgrep:
+ return (char_u *)"vimgrep";
+ case CMD_lvimgrep:
+ return (char_u *)"lvimgrep";
+ case CMD_vimgrepadd:
+ return (char_u *)"vimgrepadd";
+ case CMD_lvimgrepadd:
+ return (char_u *)"lvimgrepadd";
+ case CMD_grep:
+ return (char_u *)"grep";
+ case CMD_lgrep:
+ return (char_u *)"lgrep";
+ case CMD_grepadd:
+ return (char_u *)"grepadd";
+ case CMD_lgrepadd:
+ return (char_u *)"lgrepadd";
+ default:
+ return NULL;
}
}
@@ -5193,8 +5168,7 @@ static void vgr_display_fname(char_u *fname)
}
/// Load a dummy buffer to search for a pattern using vimgrep.
-static buf_T *vgr_load_dummy_buf(char_u *fname, char_u *dirname_start,
- char_u *dirname_now)
+static buf_T *vgr_load_dummy_buf(char_u *fname, char_u *dirname_start, char_u *dirname_now)
{
// Don't do Filetype autocommands to avoid loading syntax and
// indent scripts, a great speed improvement.
@@ -5216,8 +5190,7 @@ static buf_T *vgr_load_dummy_buf(char_u *fname, char_u *dirname_start,
/// Check whether a quickfix/location list is valid. Autocmds may remove or
/// change a quickfix list when vimgrep is running. If the list is not found,
/// create a new list.
-static bool vgr_qflist_valid(win_T *wp, qf_info_T *qi, unsigned qfid,
- char_u *title)
+static bool vgr_qflist_valid(win_T *wp, qf_info_T *qi, unsigned qfid, char_u *title)
{
// Verify that the quickfix/location list was not freed by an autocmd
if (!qflist_valid(wp, qfid)) {
@@ -5241,9 +5214,8 @@ static bool vgr_qflist_valid(win_T *wp, qf_info_T *qi, unsigned qfid,
/// 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_u *fname, buf_T *buf,
- regmmatch_T *regmatch, long *tomatch,
- int duplicate_name, int flags)
+static bool vgr_match_buflines(qf_list_T *qfl, char_u *fname, buf_T *buf, regmmatch_T *regmatch,
+ long *tomatch, int duplicate_name, int flags)
FUNC_ATTR_NONNULL_ARG(1, 3, 4, 5)
{
bool found_match = false;
@@ -5263,7 +5235,9 @@ static bool vgr_match_buflines(qf_list_T *qfl, char_u *fname, buf_T *buf,
ml_get_buf(buf, regmatch->startpos[0].lnum + lnum,
false),
regmatch->startpos[0].lnum + lnum,
+ regmatch->endpos[0].lnum + lnum,
regmatch->startpos[0].col + 1,
+ regmatch->endpos[0].col + 1,
false, // vis_col
NULL, // search pattern
0, // nr
@@ -5338,27 +5312,27 @@ void ex_vimgrep(exarg_T *eap)
{
regmmatch_T regmatch;
int fcount;
- char_u **fnames;
- char_u *fname;
- char_u *s;
- char_u *p;
+ char_u **fnames;
+ char_u *fname;
+ char_u *s;
+ char_u *p;
int fi;
- qf_list_T *qfl;
+ qf_list_T *qfl;
win_T *wp = NULL;
- buf_T *buf;
+ buf_T *buf;
int duplicate_name = FALSE;
int using_dummy;
int redraw_for_dummy = FALSE;
int found_match;
- buf_T *first_match_buf = NULL;
+ buf_T *first_match_buf = NULL;
time_t seconds = 0;
aco_save_T aco;
int flags = 0;
long tomatch;
- char_u *dirname_start = NULL;
- char_u *dirname_now = NULL;
- char_u *target_dir = NULL;
- char_u *au_name = NULL;
+ char_u *dirname_start = NULL;
+ char_u *dirname_now = NULL;
+ char_u *target_dir = NULL;
+ char_u *au_name = NULL;
au_name = vgr_get_auname(eap->cmdidx);
if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
@@ -5370,10 +5344,11 @@ void ex_vimgrep(exarg_T *eap)
qf_info_T *qi = qf_cmd_get_or_alloc_stack(eap, &wp);
- if (eap->addr_count > 0)
+ if (eap->addr_count > 0) {
tomatch = eap->line2;
- else
+ } else {
tomatch = MAXLNUM;
+ }
// Get the search pattern: either white-separated or enclosed in //
regmatch.regprog = NULL;
@@ -5457,8 +5432,9 @@ void ex_vimgrep(exarg_T *eap)
save_qfid = qf_get_curlist(qi)->qf_id;
if (buf == NULL) {
- if (!got_int)
+ if (!got_int) {
smsg(_("Cannot open file \"%s\""), fname);
+ }
} else {
// Try for a match in all lines of the buffer.
// For ":1vimgrep" look for first match only.
@@ -5467,8 +5443,9 @@ void ex_vimgrep(exarg_T *eap)
duplicate_name, flags);
if (using_dummy) {
- if (found_match && first_match_buf == NULL)
+ if (found_match && first_match_buf == NULL) {
first_match_buf = buf;
+ }
if (duplicate_name) {
// Never keep a dummy buffer if there is another buffer
// with the same name.
@@ -5514,8 +5491,7 @@ void ex_vimgrep(exarg_T *eap)
// need to be done (again). But not the window-local
// options!
aucmd_prepbuf(&aco, buf);
- apply_autocmds(EVENT_FILETYPE, buf->b_p_ft,
- buf->b_fname, TRUE, buf);
+ apply_autocmds(EVENT_FILETYPE, buf->b_p_ft, buf->b_fname, true, buf);
do_modelines(OPT_NOWIN);
aucmd_restbuf(&aco);
}
@@ -5533,9 +5509,9 @@ void ex_vimgrep(exarg_T *eap)
qf_update_buffer(qi, NULL);
- if (au_name != NULL)
- apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name,
- curbuf->b_fname, TRUE, curbuf);
+ if (au_name != NULL) {
+ apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, curbuf->b_fname, true, curbuf);
+ }
// The QuickFixCmdPost autocmd may free the quickfix list. Check the list
// is still valid.
@@ -5551,8 +5527,9 @@ void ex_vimgrep(exarg_T *eap)
vgr_jump_to_match(qi, eap->forceit, &redraw_for_dummy, first_match_buf,
target_dir);
}
- } else
+ } else {
EMSG2(_(e_nomatch2), s);
+ }
decr_quickfix_busy();
@@ -5590,24 +5567,22 @@ static void restore_start_dir(char_u *dirname_start)
xfree(dirname_now);
}
-// Load file "fname" into a dummy buffer and return the buffer pointer,
-// placing the directory resulting from the buffer load into the
-// "resulting_dir" pointer. "resulting_dir" must be allocated by the caller
-// prior to calling this function. Restores directory to "dirname_start" prior
-// to returning, if autocmds or the 'autochdir' option have changed it.
-//
-// If creating the dummy buffer does not fail, must call unload_dummy_buffer()
-// or wipe_dummy_buffer() later!
-//
-// Returns NULL if it fails.
-static buf_T *
-load_dummy_buffer (
- char_u *fname,
- char_u *dirname_start, // in: old directory
- char_u *resulting_dir // out: new directory
-)
-{
- buf_T *newbuf;
+/// Load file "fname" into a dummy buffer and return the buffer pointer,
+/// placing the directory resulting from the buffer load into the
+/// "resulting_dir" pointer. "resulting_dir" must be allocated by the caller
+/// prior to calling this function. Restores directory to "dirname_start" prior
+/// to returning, if autocmds or the 'autochdir' option have changed it.
+///
+/// If creating the dummy buffer does not fail, must call unload_dummy_buffer()
+/// or wipe_dummy_buffer() later!
+///
+/// @param dirname_start in: old directory
+/// @param resulting_dir out: new directory
+///
+/// @return NULL if it fails.
+static buf_T *load_dummy_buffer(char_u *fname, char_u *dirname_start, char_u *resulting_dir)
+{
+ buf_T *newbuf;
bufref_T newbufref;
bufref_T newbuf_to_wipe;
int failed = true;
@@ -5744,7 +5719,7 @@ static void unload_dummy_buffer(buf_T *buf, char_u *dirname_start)
}
}
-/// Copy the specified quickfix entry items into a new dict and appened the dict
+/// Copy the specified quickfix entry items into a new dict and append the dict
/// to 'list'. Returns OK on success.
static int get_qfline_items(qfline_T *qfp, list_T *list)
{
@@ -5765,21 +5740,22 @@ static int get_qfline_items(qfline_T *qfp, list_T *list)
if (tv_dict_add_nr(dict, S_LEN("bufnr"), (varnumber_T)bufnum) == FAIL
|| (tv_dict_add_nr(dict, S_LEN("lnum"), (varnumber_T)qfp->qf_lnum)
== FAIL)
+ || (tv_dict_add_nr(dict, S_LEN("end_lnum"), (varnumber_T)qfp->qf_end_lnum)
+ == FAIL)
|| (tv_dict_add_nr(dict, S_LEN("col"), (varnumber_T)qfp->qf_col) == FAIL)
+ || (tv_dict_add_nr(dict, S_LEN("end_col"), (varnumber_T)qfp->qf_end_col)
+ == FAIL)
|| (tv_dict_add_nr(dict, S_LEN("vcol"), (varnumber_T)qfp->qf_viscol)
== FAIL)
|| (tv_dict_add_nr(dict, S_LEN("nr"), (varnumber_T)qfp->qf_nr) == FAIL)
- || (tv_dict_add_str(
- dict, S_LEN("module"),
- (qfp->qf_module == NULL ? "" : (const char *)qfp->qf_module))
+ || (tv_dict_add_str(dict, S_LEN("module"),
+ (qfp->qf_module == NULL ? "" : (const char *)qfp->qf_module))
== FAIL)
- || (tv_dict_add_str(
- dict, S_LEN("pattern"),
- (qfp->qf_pattern == NULL ? "" : (const char *)qfp->qf_pattern))
+ || (tv_dict_add_str(dict, S_LEN("pattern"),
+ (qfp->qf_pattern == NULL ? "" : (const char *)qfp->qf_pattern))
== FAIL)
- || (tv_dict_add_str(
- dict, S_LEN("text"),
- (qfp->qf_text == NULL ? "" : (const char *)qfp->qf_text))
+ || (tv_dict_add_str(dict, S_LEN("text"),
+ (qfp->qf_text == NULL ? "" : (const char *)qfp->qf_text))
== FAIL)
|| (tv_dict_add_str(dict, S_LEN("type"), (const char *)buf) == FAIL)
|| (tv_dict_add_nr(dict, S_LEN("valid"), (varnumber_T)qfp->qf_valid)
@@ -5796,12 +5772,11 @@ static int get_qfline_items(qfline_T *qfp, list_T *list)
/// If qf_idx is -1, use the current list. Otherwise, use the specified list.
/// If eidx is not 0, then return only the specified entry. Otherwise return
/// all the entries.
-int get_errorlist(qf_info_T *qi_arg, win_T *wp, int qf_idx, int eidx,
- list_T *list)
+int get_errorlist(qf_info_T *qi_arg, win_T *wp, int qf_idx, int eidx, list_T *list)
{
qf_info_T *qi = qi_arg;
qf_list_T *qfl;
- qfline_T *qfp;
+ qfline_T *qfp;
int i;
if (qi == NULL) {
@@ -5837,7 +5812,7 @@ int get_errorlist(qf_info_T *qi_arg, win_T *wp, int qf_idx, int eidx,
return get_qfline_items(qfp, list);
}
} else if (get_qfline_items(qfp, list) == FAIL) {
- return FAIL;
+ return FAIL;
}
}
@@ -6000,7 +5975,7 @@ static int qf_getprop_qfidx(qf_info_T *qi, dict_T *what)
if ((di = tv_dict_find(what, S_LEN("id"))) != NULL) {
// Look for a list with the specified id
if (di->di_tv.v_type == VAR_NUMBER) {
- // For zero, use the current list or the list specifed by 'nr'
+ // For zero, use the current list or the list specified by 'nr'
if (di->di_tv.vval.v_number != 0) {
qf_idx = qf_id2nr(qi, (unsigned)di->di_tv.vval.v_number);
}
@@ -6013,10 +5988,7 @@ static int qf_getprop_qfidx(qf_info_T *qi, dict_T *what)
}
/// Return default values for quickfix list properties in retdict.
-static int qf_getprop_defaults(qf_info_T *qi,
- int flags,
- int locstack,
- dict_T *retdict)
+static int qf_getprop_defaults(qf_info_T *qi, int flags, int locstack, dict_T *retdict)
{
int status = OK;
@@ -6061,15 +6033,14 @@ static int qf_getprop_defaults(qf_info_T *qi,
/// Return the quickfix list title as 'title' in retdict
static int qf_getprop_title(qf_list_T *qfl, dict_T *retdict)
{
- return tv_dict_add_str(retdict, S_LEN("title"),
- (const char *)qfl->qf_title);
+ return tv_dict_add_str(retdict, S_LEN("title"),
+ (const char *)qfl->qf_title);
}
// Returns the identifier of the window used to display files from a location
// list. If there is no associated window, then returns 0. Useful only when
// called from a location list window.
-static int qf_getprop_filewinid(const win_T *wp, const qf_info_T *qi,
- dict_T *retdict)
+static int qf_getprop_filewinid(const win_T *wp, const qf_info_T *qi, dict_T *retdict)
FUNC_ATTR_NONNULL_ARG(3)
{
handle_T winid = 0;
@@ -6086,8 +6057,7 @@ static int qf_getprop_filewinid(const win_T *wp, const qf_info_T *qi,
/// Return the quickfix list items/entries as 'items' in retdict.
/// If eidx is not 0, then return the item at the specified index.
-static int qf_getprop_items(qf_info_T *qi, int qf_idx, int eidx,
- dict_T *retdict)
+static int qf_getprop_items(qf_info_T *qi, int qf_idx, int eidx, dict_T *retdict)
{
list_T *l = tv_list_alloc(kListLenMayKnow);
get_errorlist(qi, NULL, qf_idx, eidx, l);
@@ -6246,11 +6216,8 @@ static int qf_setprop_qftf(qf_list_T *qfl, dictitem_T *di)
/// Add a new quickfix entry to list at 'qf_idx' in the stack 'qi' from the
/// items in the dict 'd'. If it is a valid error entry, then set 'valid_entry'
/// to true.
-static int qf_add_entry_from_dict(
- qf_list_T *qfl,
- const dict_T *d,
- bool first_entry,
- bool *valid_entry)
+static int qf_add_entry_from_dict(qf_list_T *qfl, const dict_T *d, bool first_entry,
+ bool *valid_entry)
FUNC_ATTR_NONNULL_ALL
{
static bool did_bufnr_emsg;
@@ -6263,7 +6230,9 @@ static int qf_add_entry_from_dict(
char *const module = tv_dict_get_string(d, "module", true);
int bufnum = (int)tv_dict_get_number(d, "bufnr");
const long lnum = (long)tv_dict_get_number(d, "lnum");
+ const long end_lnum = (long)tv_dict_get_number(d, "end_lnum");
const int col = (int)tv_dict_get_number(d, "col");
+ const int end_col = (int)tv_dict_get_number(d, "end_col");
const char_u vcol = (char_u)tv_dict_get_number(d, "vcol");
const int nr = (int)tv_dict_get_number(d, "nr");
const char *const type = tv_dict_get_string(d, "type", false);
@@ -6301,7 +6270,9 @@ static int qf_add_entry_from_dict(
bufnum,
(char_u *)text,
lnum,
+ end_lnum,
col,
+ end_col,
vcol, // vis_col
(char_u *)pattern, // search pattern
nr,
@@ -6322,8 +6293,7 @@ static int qf_add_entry_from_dict(
/// Add list of entries to quickfix/location list. Each list entry is
/// a dictionary with item information.
-static int qf_add_entries(qf_info_T *qi, int qf_idx, list_T *list,
- char_u *title, int action)
+static int qf_add_entries(qf_info_T *qi, int qf_idx, list_T *list, char_u *title, int action)
{
qf_list_T *qfl = qf_get_list(qi, qf_idx);
qfline_T *old_last = NULL;
@@ -6386,11 +6356,7 @@ static int qf_add_entries(qf_info_T *qi, int qf_idx, list_T *list,
}
/// Get the quickfix list index from 'nr' or 'id'
-static int qf_setprop_get_qfidx(
- const qf_info_T *qi,
- const dict_T *what,
- int action,
- bool *newlist)
+static int qf_setprop_get_qfidx(const qf_info_T *qi, const dict_T *what, int action, bool *newlist)
FUNC_ATTR_NONNULL_ALL
{
dictitem_T *di;
@@ -6441,8 +6407,7 @@ static int qf_setprop_get_qfidx(
}
// Set the quickfix list title.
-static int qf_setprop_title(qf_info_T *qi, int qf_idx, const dict_T *what,
- const dictitem_T *di)
+static int qf_setprop_title(qf_info_T *qi, int qf_idx, const dict_T *what, const dictitem_T *di)
FUNC_ATTR_NONNULL_ALL
{
qf_list_T *qfl = qf_get_list(qi, qf_idx);
@@ -6460,8 +6425,7 @@ static int qf_setprop_title(qf_info_T *qi, int qf_idx, const dict_T *what,
}
// Set quickfix list items/entries.
-static int qf_setprop_items(qf_info_T *qi, int qf_idx, dictitem_T *di,
- int action)
+static int qf_setprop_items(qf_info_T *qi, int qf_idx, dictitem_T *di, int action)
FUNC_ATTR_NONNULL_ALL
{
if (di->di_tv.v_type != VAR_LIST) {
@@ -6478,17 +6442,13 @@ static int qf_setprop_items(qf_info_T *qi, int qf_idx, dictitem_T *di,
}
// Set quickfix list items/entries from a list of lines.
-static int qf_setprop_items_from_lines(
- qf_info_T *qi,
- int qf_idx,
- const dict_T *what,
- dictitem_T *di,
- int action)
+static int qf_setprop_items_from_lines(qf_info_T *qi, int qf_idx, const dict_T *what,
+ dictitem_T *di, int action)
FUNC_ATTR_NONNULL_ALL
{
char_u *errorformat = p_efm;
dictitem_T *efm_di;
- int retval = FAIL;
+ int retval = FAIL;
// Use the user supplied errorformat settings (if present)
if ((efm_di = tv_dict_find(what, S_LEN("efm"))) != NULL) {
@@ -6528,11 +6488,10 @@ static int qf_setprop_context(qf_list_T *qfl, dictitem_T *di)
}
// Set the current index in the specified quickfix list
-static int qf_setprop_curidx(qf_info_T *qi, qf_list_T *qfl,
- const dictitem_T *di)
+static int qf_setprop_curidx(qf_info_T *qi, qf_list_T *qfl, const dictitem_T *di)
FUNC_ATTR_NONNULL_ALL
{
- int newidx;
+ int newidx;
// If the specified index is '$', then use the last entry
if (di->di_tv.v_type == VAR_STRING
@@ -6573,13 +6532,12 @@ static int qf_setprop_curidx(qf_info_T *qi, qf_list_T *qfl,
/// Set quickfix/location list properties (title, items, context).
/// Also used to add items from parsing a list of lines.
/// Used by the setqflist() and setloclist() Vim script functions.
-static int qf_set_properties(qf_info_T *qi, const dict_T *what, int action,
- char_u *title)
+static int qf_set_properties(qf_info_T *qi, const dict_T *what, int action, char_u *title)
FUNC_ATTR_NONNULL_ALL
{
qf_list_T *qfl;
dictitem_T *di;
- int retval = FAIL;
+ int retval = FAIL;
bool newlist = action == ' ' || qf_stack_empty(qi);
int qf_idx = qf_setprop_get_qfidx(qi, what, action, &newlist);
if (qf_idx == INVALID_QFIDX) { // List not found
@@ -6685,8 +6643,7 @@ static void qf_free_stack(win_T *wp, qf_info_T *qi)
// of dictionaries. "title" will be copied to w:quickfix_title
// "action" is 'a' for add, 'r' for replace. Otherwise create a new list.
// When "what" is not NULL then only set some properties.
-int set_errorlist(win_T *wp, list_T *list, int action, char_u *title,
- dict_T *what)
+int set_errorlist(win_T *wp, list_T *list, int action, char_u *title, dict_T *what)
{
qf_info_T *qi = &ql_info;
int retval = OK;
@@ -6771,32 +6728,37 @@ bool set_ref_in_quickfix(int copyID)
}
/// Return the autocmd name for the :cbuffer Ex commands
-static char_u * cbuffer_get_auname(cmdidx_T cmdidx)
+static char_u *cbuffer_get_auname(cmdidx_T cmdidx)
{
switch (cmdidx) {
- case CMD_cbuffer: return (char_u *)"cbuffer";
- case CMD_cgetbuffer: return (char_u *)"cgetbuffer";
- case CMD_caddbuffer: return (char_u *)"caddbuffer";
- case CMD_lbuffer: return (char_u *)"lbuffer";
- case CMD_lgetbuffer: return (char_u *)"lgetbuffer";
- case CMD_laddbuffer: return (char_u *)"laddbuffer";
- default: return NULL;
+ case CMD_cbuffer:
+ return (char_u *)"cbuffer";
+ case CMD_cgetbuffer:
+ return (char_u *)"cgetbuffer";
+ case CMD_caddbuffer:
+ return (char_u *)"caddbuffer";
+ case CMD_lbuffer:
+ return (char_u *)"lbuffer";
+ case CMD_lgetbuffer:
+ return (char_u *)"lgetbuffer";
+ case CMD_laddbuffer:
+ return (char_u *)"laddbuffer";
+ default:
+ return NULL;
}
}
/// Process and validate the arguments passed to the :cbuffer, :caddbuffer,
/// :cgetbuffer, :lbuffer, :laddbuffer, :lgetbuffer Ex commands.
-static int cbuffer_process_args(exarg_T *eap,
- buf_T **bufp,
- linenr_T *line1,
- linenr_T *line2)
+static int cbuffer_process_args(exarg_T *eap, buf_T **bufp, linenr_T *line1, linenr_T *line2)
{
buf_T *buf = NULL;
- if (*eap->arg == NUL)
+ if (*eap->arg == NUL) {
buf = curbuf;
- else if (*skipwhite(skipdigits(eap->arg)) == NUL)
+ } else if (*skipwhite(skipdigits(eap->arg)) == NUL) {
buf = buflist_findnr(atoi((char *)eap->arg));
+ }
if (buf == NULL) {
EMSG(_(e_invarg));
@@ -6902,16 +6864,23 @@ void ex_cbuffer(exarg_T *eap)
}
/// Return the autocmd name for the :cexpr Ex commands.
-static char_u * cexpr_get_auname(cmdidx_T cmdidx)
+static char_u *cexpr_get_auname(cmdidx_T cmdidx)
{
switch (cmdidx) {
- case CMD_cexpr: return (char_u *)"cexpr";
- case CMD_cgetexpr: return (char_u *)"cgetexpr";
- case CMD_caddexpr: return (char_u *)"caddexpr";
- case CMD_lexpr: return (char_u *)"lexpr";
- case CMD_lgetexpr: return (char_u *)"lgetexpr";
- case CMD_laddexpr: return (char_u *)"laddexpr";
- default: return NULL;
+ case CMD_cexpr:
+ return (char_u *)"cexpr";
+ case CMD_cgetexpr:
+ return (char_u *)"cgetexpr";
+ case CMD_caddexpr:
+ return (char_u *)"caddexpr";
+ case CMD_lexpr:
+ return (char_u *)"lexpr";
+ case CMD_lgetexpr:
+ return (char_u *)"lgetexpr";
+ case CMD_laddexpr:
+ return (char_u *)"laddexpr";
+ default:
+ return NULL;
}
}
@@ -7005,10 +6974,7 @@ static qf_info_T *hgr_get_ll(bool *new_ll)
}
// Search for a pattern in a help file.
-static void hgr_search_file(
- qf_list_T *qfl,
- char_u *fname,
- regmatch_T *p_regmatch)
+static void hgr_search_file(qf_list_T *qfl, char_u *fname, regmatch_T *p_regmatch)
FUNC_ATTR_NONNULL_ARG(1, 3)
{
FILE *const fd = os_fopen((char *)fname, "r");
@@ -7035,7 +7001,10 @@ static void hgr_search_file(
0,
line,
lnum,
+ 0,
(int)(p_regmatch->startp[0] - line) + 1, // col
+ (int)(p_regmatch->endp[0] - line)
+ + 1, // end_col
false, // vis_col
NULL, // search pattern
0, // nr
@@ -7060,11 +7029,8 @@ static void hgr_search_file(
// Search for a pattern in all the help files in the doc directory under
// the given directory.
-static void hgr_search_files_in_dir(
- qf_list_T *qfl,
- char_u *dirname,
- regmatch_T *p_regmatch,
- const char_u *lang)
+static void hgr_search_files_in_dir(qf_list_T *qfl, char_u *dirname, regmatch_T *p_regmatch,
+ const char_u *lang)
FUNC_ATTR_NONNULL_ARG(1, 2, 3)
{
int fcount;
@@ -7096,8 +7062,7 @@ static void hgr_search_files_in_dir(
// and add the matches to a quickfix list.
// 'lang' is the language specifier. If supplied, then only matches in the
// specified language are found.
-static void hgr_search_in_rtp(qf_list_T *qfl, regmatch_T *p_regmatch,
- const char_u *lang)
+static void hgr_search_in_rtp(qf_list_T *qfl, regmatch_T *p_regmatch, const char_u *lang)
FUNC_ATTR_NONNULL_ARG(1, 2)
{
// Go through all directories in 'runtimepath'
@@ -7117,9 +7082,12 @@ void ex_helpgrep(exarg_T *eap)
char_u *au_name = NULL;
switch (eap->cmdidx) {
- case CMD_helpgrep: au_name = (char_u *)"helpgrep"; break;
- case CMD_lhelpgrep: au_name = (char_u *)"lhelpgrep"; break;
- default: break;
+ case CMD_helpgrep:
+ au_name = (char_u *)"helpgrep"; break;
+ case CMD_lhelpgrep:
+ au_name = (char_u *)"lhelpgrep"; break;
+ default:
+ break;
}
if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
curbuf->b_fname, true, curbuf)) {
diff --git a/src/nvim/rbuffer.c b/src/nvim/rbuffer.c
index df9394fbb2..4ac50095b3 100644
--- a/src/nvim/rbuffer.c
+++ b/src/nvim/rbuffer.c
@@ -6,8 +6,8 @@
#include <string.h>
#include "nvim/memory.h"
-#include "nvim/vim.h"
#include "nvim/rbuffer.h"
+#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "rbuffer.c.generated.h"
@@ -144,7 +144,7 @@ void rbuffer_consumed(RBuffer *buf, size_t count)
buf->read_ptr += count;
if (buf->read_ptr >= buf->end_ptr) {
- buf->read_ptr -= rbuffer_capacity(buf);
+ buf->read_ptr -= rbuffer_capacity(buf);
}
bool was_full = buf->size == rbuffer_capacity(buf);
diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c
index c2ef217638..98a46cf781 100644
--- a/src/nvim/regexp.c
+++ b/src/nvim/regexp.c
@@ -63,6 +63,7 @@
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
+#include "nvim/plines.h"
#include "nvim/garray.h"
#include "nvim/strings.h"
@@ -6725,26 +6726,24 @@ static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest,
if (expr != NULL) {
typval_T argv[2];
- int dummy;
typval_T rettv;
staticList10_T matchList = TV_LIST_STATIC10_INIT;
-
rettv.v_type = VAR_STRING;
rettv.vval.v_string = NULL;
argv[0].v_type = VAR_LIST;
argv[0].vval.v_list = &matchList.sl_list;
+ funcexe_T funcexe = FUNCEXE_INIT;
+ funcexe.argv_func = fill_submatch_list;
+ funcexe.evaluate = true;
if (expr->v_type == VAR_FUNC) {
s = expr->vval.v_string;
- call_func(s, -1, &rettv, 1, argv,
- fill_submatch_list, 0L, 0L, &dummy,
- true, NULL, NULL);
+ call_func(s, -1, &rettv, 1, argv, &funcexe);
} else if (expr->v_type == VAR_PARTIAL) {
partial_T *partial = expr->vval.v_partial;
s = partial_name(partial);
- call_func(s, -1, &rettv, 1, argv,
- fill_submatch_list, 0L, 0L, &dummy,
- true, partial, NULL);
+ funcexe.partial = partial;
+ call_func(s, -1, &rettv, 1, argv, &funcexe);
}
if (tv_list_len(&matchList.sl_list) > 0) {
// fill_submatch_list() was called.
diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c
index 35c3285cda..039f9b4675 100644
--- a/src/nvim/regexp_nfa.c
+++ b/src/nvim/regexp_nfa.c
@@ -1161,8 +1161,6 @@ static int nfa_regatom(void)
int emit_range;
int negated;
int startc = -1;
- int endc = -1;
- int oldstartc = -1;
int save_prev_at_start = prev_at_start;
c = getchr();
@@ -1572,7 +1570,7 @@ collection:
* Failed to recognize a character class. Use the simple
* version that turns [abc] into 'a' OR 'b' OR 'c'
*/
- startc = endc = oldstartc = -1;
+ startc = -1;
negated = false;
if (*regparse == '^') { // negated range
negated = true;
@@ -1589,7 +1587,7 @@ collection:
// Emit the OR branches for each character in the []
emit_range = false;
while (regparse < endp) {
- oldstartc = startc;
+ int oldstartc = startc;
startc = -1;
got_coll_char = false;
if (*regparse == '[') {
@@ -1729,7 +1727,7 @@ collection:
/* Previous char was '-', so this char is end of range. */
if (emit_range) {
- endc = startc;
+ int endc = startc;
startc = oldstartc;
if (startc > endc) {
EMSG_RET_FAIL(_(e_reverse_range));
diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c
index c3cd210538..7b72efce23 100644
--- a/src/nvim/runtime.c
+++ b/src/nvim/runtime.c
@@ -5,21 +5,25 @@
///
/// Management of runtime files (including packages)
-#include "nvim/vim.h"
#include "nvim/ascii.h"
+#include "nvim/api/private/helpers.h"
#include "nvim/charset.h"
#include "nvim/eval.h"
-#include "nvim/option.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds2.h"
#include "nvim/misc1.h"
+#include "nvim/option.h"
#include "nvim/os/os.h"
#include "nvim/runtime.h"
+#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "runtime.c.generated.h"
#endif
+static bool runtime_search_path_valid = false;
+static int *runtime_search_path_ref = NULL;
+static RuntimeSearchPath runtime_search_path;
/// ":runtime [what] {name}"
void ex_runtime(exarg_T *eap)
@@ -60,12 +64,11 @@ static void source_callback(char_u *fname, void *cookie)
/// When "flags" has DIP_ERR: give an error message if there is no match.
///
/// return FAIL when no file could be sourced, OK otherwise.
-int do_in_path(char_u *path, char_u *name, int flags,
- DoInRuntimepathCB callback, void *cookie)
+int do_in_path(char_u *path, char_u *name, int flags, DoInRuntimepathCB callback, void *cookie)
{
- char_u *tail;
+ char_u *tail;
int num_files;
- char_u **files;
+ char_u **files;
int i;
bool did_one = false;
@@ -90,8 +93,7 @@ int do_in_path(char_u *path, char_u *name, int flags,
// Skip after or non-after directories.
if (flags & (DIP_NOAFTER | DIP_AFTER)) {
- bool is_after = buflen >= 5
- && STRCMP(buf + buflen - 5, "after") == 0;
+ bool is_after = path_is_after(buf, buflen);
if ((is_after && (flags & DIP_NOAFTER))
|| (!is_after && (flags & DIP_AFTER))) {
@@ -100,10 +102,8 @@ int do_in_path(char_u *path, char_u *name, int flags,
}
if (name == NULL) {
- (*callback)(buf, (void *)&cookie);
- if (!did_one) {
- did_one = (cookie == NULL);
- }
+ (*callback)(buf, cookie);
+ did_one = true;
} else if (buflen + STRLEN(name) + 2 < MAXPATHL) {
add_pathsep((char *)buf);
tail = buf + STRLEN(buf);
@@ -122,10 +122,11 @@ int do_in_path(char_u *path, char_u *name, int flags,
verbose_leave();
}
+ int ew_flags = ((flags & DIP_DIR) ? EW_DIR : EW_FILE)
+ | (flags & DIP_DIRFILE) ? (EW_DIR|EW_FILE) : 0;
+
// Expand wildcards, invoke the callback for each match.
- if (gen_expand_wildcards(1, &buf, &num_files, &files,
- (flags & DIP_DIR) ? EW_DIR : EW_FILE)
- == OK) {
+ if (gen_expand_wildcards(1, &buf, &num_files, &files, ew_flags) == OK) {
for (i = 0; i < num_files; i++) {
(*callback)(files[i], cookie);
did_one = true;
@@ -157,6 +158,115 @@ int do_in_path(char_u *path, char_u *name, int flags,
return did_one ? OK : FAIL;
}
+/// Find the file "name" in all directories in "path" and invoke
+/// "callback(fname, cookie)".
+/// "name" can contain wildcards.
+/// When "flags" has DIP_ALL: source all files, otherwise only the first one.
+/// When "flags" has DIP_DIR: find directories instead of files.
+/// When "flags" has DIP_ERR: give an error message if there is no match.
+///
+/// return FAIL when no file could be sourced, OK otherwise.
+int do_in_cached_path(char_u *name, int flags, DoInRuntimepathCB callback, void *cookie)
+{
+ runtime_search_path_validate();
+ char_u *tail;
+ int num_files;
+ char_u **files;
+ int i;
+ bool did_one = false;
+
+ char_u buf[MAXPATHL];
+
+ if (p_verbose > 10 && name != NULL) {
+ verbose_enter();
+ smsg(_("Searching for \"%s\" in runtime path"), (char *)name);
+ verbose_leave();
+ }
+
+ RuntimeSearchPath path = runtime_search_path;
+ int ref = 0;
+ if (runtime_search_path_ref == NULL) {
+ // cached path was unreferenced. keep a ref to
+ // prevent runtime_search_path() to freeing it too early
+ ref++;
+ runtime_search_path_ref = &ref;
+ }
+
+ // Loop over all entries in cached path
+ for (size_t j = 0; j < kv_size(path); j++) {
+ SearchPathItem item = kv_A(path, j);
+ size_t buflen = strlen(item.path);
+
+ // Skip after or non-after directories.
+ if (flags & (DIP_NOAFTER | DIP_AFTER)) {
+ if ((item.after && (flags & DIP_NOAFTER))
+ || (!item.after && (flags & DIP_AFTER))) {
+ continue;
+ }
+ }
+
+ if (name == NULL) {
+ (*callback)((char_u *)item.path, cookie);
+ did_one = true;
+ } else if (buflen + STRLEN(name) + 2 < MAXPATHL) {
+ STRCPY(buf, item.path);
+ add_pathsep((char *)buf);
+ tail = buf + STRLEN(buf);
+
+ // Loop over all patterns in "name"
+ char_u *np = name;
+ while (*np != NUL && ((flags & DIP_ALL) || !did_one)) {
+ // Append the pattern from "name" to buf[].
+ assert(MAXPATHL >= (tail - buf));
+ copy_option_part(&np, tail, (size_t)(MAXPATHL - (tail - buf)),
+ "\t ");
+
+ if (p_verbose > 10) {
+ verbose_enter();
+ smsg(_("Searching for \"%s\""), buf);
+ verbose_leave();
+ }
+
+ int ew_flags = ((flags & DIP_DIR) ? EW_DIR : EW_FILE)
+ | (flags & DIP_DIRFILE) ? (EW_DIR|EW_FILE) : 0;
+
+ // Expand wildcards, invoke the callback for each match.
+ char_u *(pat[]) = { buf };
+ if (gen_expand_wildcards(1, pat, &num_files, &files, ew_flags) == OK) {
+ for (i = 0; i < num_files; i++) {
+ (*callback)(files[i], cookie);
+ did_one = true;
+ if (!(flags & DIP_ALL)) {
+ break;
+ }
+ }
+ FreeWild(num_files, files);
+ }
+ }
+ }
+ }
+
+ if (!did_one && name != NULL) {
+ if (flags & DIP_ERR) {
+ EMSG3(_(e_dirnotf), "runtime path", name);
+ } else if (p_verbose > 0) {
+ verbose_enter();
+ smsg(_("not found in runtime path: \"%s\""), name);
+ verbose_leave();
+ }
+ }
+
+ if (ref) {
+ if (runtime_search_path_ref == &ref) {
+ runtime_search_path_ref = NULL;
+ } else {
+ runtime_search_path_free(path);
+ }
+ }
+
+
+ return did_one ? OK : FAIL;
+}
/// Find "name" in "path". When found, invoke the callback function for
/// it: callback(fname, "cookie")
/// When "flags" has DIP_ALL repeat for all matches, otherwise only the first
@@ -165,32 +275,33 @@ int do_in_path(char_u *path, char_u *name, int flags,
/// If "name" is NULL calls callback for each entry in "path". Cookie is
/// passed by reference in this case, setting it to NULL indicates that callback
/// has done its job.
-int do_in_path_and_pp(char_u *path, char_u *name, int flags,
- DoInRuntimepathCB callback, void *cookie)
+int do_in_path_and_pp(char_u *path, char_u *name, int flags, DoInRuntimepathCB callback,
+ void *cookie)
{
int done = FAIL;
if ((flags & DIP_NORTP) == 0) {
- done = do_in_path(path, name, flags, callback, cookie);
+ done |= do_in_path(path, (name && !*name) ? NULL : name, flags, callback, cookie);
}
if ((done == FAIL || (flags & DIP_ALL)) && (flags & DIP_START)) {
- char *start_dir = "pack/*/start/*/%s"; // NOLINT
- size_t len = STRLEN(start_dir) + STRLEN(name);
- char_u *s = xmallocz(len);
+ char *start_dir = "pack/*/start/*/%s%s"; // NOLINT
+ size_t len = STRLEN(start_dir) + STRLEN(name) + 6;
+ char_u *s = xmallocz(len); // TODO(bfredl): get rid of random allocations
+ char *suffix = (flags & DIP_AFTER) ? "after/" : "";
- vim_snprintf((char *)s, len, start_dir, name);
- done = do_in_path(p_pp, s, flags, callback, cookie);
+ vim_snprintf((char *)s, len, start_dir, suffix, name);
+ done |= do_in_path(p_pp, s, flags & ~DIP_AFTER, callback, cookie);
xfree(s);
- if (done == FAIL|| (flags & DIP_ALL)) {
- start_dir = "start/*/%s"; // NOLINT
- len = STRLEN(start_dir) + STRLEN(name);
+ if (done == FAIL || (flags & DIP_ALL)) {
+ start_dir = "start/*/%s%s"; // NOLINT
+ len = STRLEN(start_dir) + STRLEN(name) + 6;
s = xmallocz(len);
- vim_snprintf((char *)s, len, start_dir, name);
- done = do_in_path(p_pp, s, flags, callback, cookie);
+ vim_snprintf((char *)s, len, start_dir, suffix, name);
+ done |= do_in_path(p_pp, s, flags & ~DIP_AFTER, callback, cookie);
xfree(s);
}
@@ -202,7 +313,7 @@ int do_in_path_and_pp(char_u *path, char_u *name, int flags,
char_u *s = xmallocz(len);
vim_snprintf((char *)s, len, opt_dir, name);
- done = do_in_path(p_pp, s, flags, callback, cookie);
+ done |= do_in_path(p_pp, s, flags, callback, cookie);
xfree(s);
@@ -212,7 +323,7 @@ int do_in_path_and_pp(char_u *path, char_u *name, int flags,
s = xmallocz(len);
vim_snprintf((char *)s, len, opt_dir, name);
- done = do_in_path(p_pp, s, flags, callback, cookie);
+ done |= do_in_path(p_pp, s, flags, callback, cookie);
xfree(s);
}
@@ -221,11 +332,161 @@ int do_in_path_and_pp(char_u *path, char_u *name, int flags,
return done;
}
+static void push_path(RuntimeSearchPath *search_path, char *entry, bool after)
+{
+ kv_push(*search_path, ((SearchPathItem){ entry, after }));
+}
+
+static void expand_pack_entry(RuntimeSearchPath *search_path, CharVec *after_path,
+ char_u *pack_entry)
+{
+ static char_u buf[MAXPATHL], buf2[MAXPATHL];
+ char *start_dir = "/pack/*/start/*"; // NOLINT
+ if (STRLEN(pack_entry) + STRLEN(start_dir) + 1 < MAXPATHL) {
+ xstrlcpy((char *)buf, (char *)pack_entry, MAXPATHL);
+ xstrlcpy((char *)buf2, (char *)pack_entry, MAXPATHL);
+ xstrlcat((char *)buf, start_dir, sizeof buf);
+ xstrlcat((char *)buf2, "/start/*", sizeof buf); // NOLINT
+ int num_files;
+ char_u **files;
+
+ char_u *(pat[]) = { buf, buf2 };
+ if (gen_expand_wildcards(2, pat, &num_files, &files, EW_DIR) == OK) {
+ for (int i = 0; i < num_files; i++) {
+ push_path(search_path, xstrdup((char *)files[i]), false);
+ size_t after_size = STRLEN(files[i])+7;
+ char *after = xmallocz(after_size);
+ xstrlcpy(after, (char *)files[i], after_size);
+ xstrlcat(after, "/after", after_size);
+ if (os_isdir((char_u *)after)) {
+ kv_push(*after_path, after);
+ } else {
+ xfree(after);
+ }
+ }
+ FreeWild(num_files, files);
+ }
+ }
+}
+
+static bool path_is_after(char_u *buf, size_t buflen)
+{
+ // NOTE: we only consider dirs exactly matching "after" to be an AFTER dir.
+ // vim8 considers all dirs like "foo/bar_after", "Xafter" etc, as an
+ // "after" dir in SOME codepaths not not in ALL codepaths.
+ return buflen >= 5
+ && (!(buflen >= 6) || vim_ispathsep(buf[buflen-6]))
+ && STRCMP(buf + buflen - 5, "after") == 0;
+}
+
+RuntimeSearchPath runtime_search_path_build(void)
+{
+ kvec_t(String) pack_entries = KV_INITIAL_VALUE;
+ Map(String, handle_T) pack_used = MAP_INIT;
+ // TODO(bfredl): add a set of existing rtp entries to not duplicate those
+ RuntimeSearchPath search_path = KV_INITIAL_VALUE;
+ CharVec after_path = KV_INITIAL_VALUE;
+
+ static char_u buf[MAXPATHL];
+ for (char *entry = (char *)p_pp; *entry != NUL; ) {
+ char *cur_entry = entry;
+ copy_option_part((char_u **)&entry, buf, MAXPATHL, ",");
+
+ String the_entry = { .data = cur_entry, .size = STRLEN(buf) };
+
+ kv_push(pack_entries, the_entry);
+ 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;
+ copy_option_part((char_u **)&rtp_entry, buf, MAXPATHL, ",");
+ size_t buflen = STRLEN(buf);
+
+ if (path_is_after(buf, buflen)) {
+ rtp_entry = cur_entry;
+ break;
+ }
+
+ push_path(&search_path, xstrdup((char *)buf), false);
+
+ handle_T *h = map_ref(String, handle_T)(&pack_used, cstr_as_string((char *)buf), false);
+ if (h) {
+ (*h)++;
+ expand_pack_entry(&search_path, &after_path, buf);
+ }
+ }
+
+ for (size_t i = 0; i < kv_size(pack_entries); i++) {
+ handle_T h = map_get(String, handle_T)(&pack_used, kv_A(pack_entries, i));
+ if (h == 0) {
+ expand_pack_entry(&search_path, &after_path, (char_u *)kv_A(pack_entries, i).data);
+ }
+ }
+
+ // "after" packages
+ for (size_t i = 0; i < kv_size(after_path); i++) {
+ push_path(&search_path, kv_A(after_path, i), true);
+ }
+
+ // "after" dirs in rtp
+ for (; *rtp_entry != NUL;) {
+ copy_option_part((char_u **)&rtp_entry, buf, MAXPATHL, ",");
+ push_path(&search_path, xstrdup((char *)buf), path_is_after(buf, STRLEN(buf)));
+ }
+
+ // strings are not owned
+ kv_destroy(pack_entries);
+ kv_destroy(after_path);
+ map_destroy(String, handle_T)(&pack_used);
+
+ return search_path;
+}
+
+void runtime_search_path_invalidate(void)
+{
+ runtime_search_path_valid = false;
+}
+
+void runtime_search_path_free(RuntimeSearchPath path)
+{
+ for (size_t j = 0; j < kv_size(path); j++) {
+ SearchPathItem item = kv_A(path, j);
+ xfree(item.path);
+ }
+ kv_destroy(path);
+}
+
+void runtime_search_path_validate(void)
+{
+ if (!runtime_search_path_valid) {
+ if (!runtime_search_path_ref) {
+ runtime_search_path_free(runtime_search_path);
+ }
+ runtime_search_path = runtime_search_path_build();
+ runtime_search_path_valid = true;
+ runtime_search_path_ref = NULL; // initially unowned
+ }
+}
+
+
+
/// Just like do_in_path_and_pp(), using 'runtimepath' for "path".
-int do_in_runtimepath(char_u *name, int flags, DoInRuntimepathCB callback,
- void *cookie)
+int do_in_runtimepath(char_u *name, int flags, DoInRuntimepathCB callback, void *cookie)
{
- return do_in_path_and_pp(p_rtp, name, flags, callback, cookie);
+ int success = FAIL;
+ if (!(flags & DIP_NORTP)) {
+ success |= do_in_cached_path((name && !*name) ? NULL : name, flags, callback, cookie);
+ flags = (flags & ~DIP_START) | DIP_NORTP;
+ }
+ // TODO(bfredl): we could integrate disabled OPT dirs into the cached path
+ // which would effectivize ":packadd myoptpack" as well
+ if ((flags & (DIP_START|DIP_OPT)) && (success == FAIL || (flags & DIP_ALL))) {
+ success |= do_in_path_and_pp(p_rtp, name, flags, callback, cookie);
+ }
+ return success;
}
/// Source the file "name" from all directories in 'runtimepath'.
@@ -235,8 +496,7 @@ int do_in_runtimepath(char_u *name, int flags, DoInRuntimepathCB callback,
/// return FAIL when no file could be sourced, OK otherwise.
int source_runtime(char_u *name, int flags)
{
- flags |= (flags & DIP_NORTP) ? 0 : DIP_START;
- return source_in_path(p_rtp, name, flags);
+ return do_in_runtimepath(name, flags, source_callback, NULL);
}
/// Just like source_runtime(), but use "path" instead of 'runtimepath'.
@@ -403,8 +663,10 @@ theend:
return retval;
}
-/// Load scripts in "plugin" and "ftdetect" directories of the package.
-static int load_pack_plugin(char_u *fname)
+/// Load scripts in "plugin" directory of the package.
+/// For opt packages, also load scripts in "ftdetect" (start packages already
+/// load these from filetype.vim)
+static int load_pack_plugin(bool opt, char_u *fname)
{
static const char *ftpat = "%s/ftdetect/*.vim"; // NOLINT
@@ -421,7 +683,7 @@ static int load_pack_plugin(char_u *fname)
// If runtime/filetype.vim wasn't loaded yet, the scripts will be
// found when it loads.
- if (eval_to_number(cmd) > 0) {
+ if (opt && eval_to_number(cmd) > 0) {
do_cmdline_cmd("augroup filetypedetect");
vim_snprintf((char *)pat, len, ftpat, ffname);
source_all_matches(pat);
@@ -441,7 +703,7 @@ static int APP_ADD_DIR;
static int APP_LOAD;
static int APP_BOTH;
-static void add_pack_plugin(char_u *fname, void *cookie)
+static void add_pack_plugin(bool opt, char_u *fname, void *cookie)
{
if (cookie != &APP_LOAD) {
char *buf = xmalloc(MAXPATHL);
@@ -465,17 +727,18 @@ static void add_pack_plugin(char_u *fname, void *cookie)
}
if (cookie != &APP_ADD_DIR) {
- load_pack_plugin(fname);
+ load_pack_plugin(opt, fname);
}
}
-/// Add all packages in the "start" directory to 'runtimepath'.
-void add_pack_start_dirs(void)
+static void add_start_pack_plugin(char_u *fname, void *cookie)
{
- do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR, // NOLINT
- add_pack_plugin, &APP_ADD_DIR);
- do_in_path(p_pp, (char_u *)"start/*", DIP_ALL + DIP_DIR, // NOLINT
- add_pack_plugin, &APP_ADD_DIR);
+ add_pack_plugin(false, fname, cookie);
+}
+
+static void add_opt_pack_plugin(char_u *fname, void *cookie)
+{
+ add_pack_plugin(true, fname, cookie);
}
/// Load plugins from all packages in the "start" directory.
@@ -483,9 +746,9 @@ void load_start_packages(void)
{
did_source_packages = true;
do_in_path(p_pp, (char_u *)"pack/*/start/*", DIP_ALL + DIP_DIR, // NOLINT
- add_pack_plugin, &APP_LOAD);
+ add_start_pack_plugin, &APP_LOAD);
do_in_path(p_pp, (char_u *)"start/*", DIP_ALL + DIP_DIR, // NOLINT
- add_pack_plugin, &APP_LOAD);
+ add_start_pack_plugin, &APP_LOAD);
}
// ":packloadall"
@@ -496,7 +759,6 @@ void ex_packloadall(exarg_T *eap)
// First do a round to add all directories to 'runtimepath', then load
// the plugins. This allows for plugins to use an autoload directory
// of another plugin.
- add_pack_start_dirs();
load_start_packages();
}
}
@@ -522,7 +784,8 @@ void ex_packadd(exarg_T *eap)
res = do_in_path(p_pp, (char_u *)pat,
DIP_ALL + DIP_DIR
+ (round == 2 && res == FAIL ? DIP_ERR : 0),
- add_pack_plugin, eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
+ round == 1 ? add_start_pack_plugin : add_opt_pack_plugin,
+ eap->forceit ? &APP_ADD_DIR : &APP_BOTH);
xfree(pat);
}
}
@@ -555,8 +818,7 @@ static char *strcpy_comma_escaped(char *dest, const char *src, const size_t len)
/// (common_suf is present after each new item, single_suf is present
/// after half of the new items) and with commas after each item, commas
/// inside the values are escaped.
-static inline size_t compute_double_env_sep_len(const char *const val,
- const size_t common_suf_len,
+static inline size_t compute_double_env_sep_len(const char *const val, const size_t common_suf_len,
const size_t single_suf_len)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
{
@@ -599,9 +861,8 @@ static inline size_t compute_double_env_sep_len(const char *const val,
/// Otherwise in reverse.
///
/// @return (dest + appended_characters_length)
-static inline char *add_env_sep_dirs(char *dest, const char *const val,
- const char *const suf1, const size_t len1,
- const char *const suf2, const size_t len2,
+static inline char *add_env_sep_dirs(char *dest, const char *const val, const char *const suf1,
+ const size_t len1, const char *const suf2, const size_t len2,
const bool forward)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ARG(1)
{
@@ -660,9 +921,8 @@ static inline char *add_env_sep_dirs(char *dest, const char *const val,
/// Otherwise in reverse.
///
/// @return (dest + appended_characters_length)
-static inline char *add_dir(char *dest, const char *const dir,
- const size_t dir_len, const XDGVarType type,
- const char *const suf1, const size_t len1,
+static inline char *add_dir(char *dest, const char *const dir, const size_t dir_len,
+ const XDGVarType type, const char *const suf1, const size_t len1,
const char *const suf2, const size_t len2)
FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_WARN_UNUSED_RESULT
{
diff --git a/src/nvim/runtime.h b/src/nvim/runtime.h
index b40c2b670e..db31ae4e1e 100644
--- a/src/nvim/runtime.h
+++ b/src/nvim/runtime.h
@@ -7,10 +7,30 @@
typedef void (*DoInRuntimepathCB)(char_u *, void *);
+typedef struct {
+ char *path;
+ bool after;
+} SearchPathItem;
+
+typedef kvec_t(SearchPathItem) RuntimeSearchPath;
+typedef kvec_t(char *) CharVec;
+
// last argument for do_source()
#define DOSO_NONE 0
#define DOSO_VIMRC 1 // loading vimrc file
+// Used for flags in do_in_path()
+#define DIP_ALL 0x01 // all matches, not just the first one
+#define DIP_DIR 0x02 // find directories instead of files
+#define DIP_ERR 0x04 // give an error message when none found
+#define DIP_START 0x08 // also use "start" directory in 'packpath'
+#define DIP_OPT 0x10 // also use "opt" directory in 'packpath'
+#define DIP_NORTP 0x20 // do not use 'runtimepath'
+#define DIP_NOAFTER 0x40 // skip "after" directories
+#define DIP_AFTER 0x80 // only use "after" directories
+#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"
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 3446a944cd..98d8722ec8 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -65,45 +65,50 @@
#include <stdbool.h>
#include <string.h>
-#include "nvim/log.h"
-#include "nvim/vim.h"
-#include "nvim/ascii.h"
+#include "nvim/api/private/helpers.h"
+#include "nvim/api/vim.h"
#include "nvim/arabic.h"
-#include "nvim/screen.h"
+#include "nvim/ascii.h"
#include "nvim/buffer.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
#include "nvim/cursor_shape.h"
+#include "nvim/decoration.h"
#include "nvim/diff.h"
+#include "nvim/edit.h"
#include "nvim/eval.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_cmds2.h"
#include "nvim/ex_getln.h"
-#include "nvim/edit.h"
+#include "nvim/extmark.h"
#include "nvim/fileio.h"
#include "nvim/fold.h"
-#include "nvim/indent.h"
+#include "nvim/garray.h"
#include "nvim/getchar.h"
#include "nvim/highlight.h"
+#include "nvim/indent.h"
+#include "nvim/lib/kvec.h"
+#include "nvim/log.h"
+#include "nvim/lua/executor.h"
#include "nvim/main.h"
#include "nvim/mark.h"
-#include "nvim/extmark.h"
-#include "nvim/decoration.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/menu.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
-#include "nvim/garray.h"
#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/option.h"
+#include "nvim/os/time.h"
#include "nvim/os_unix.h"
#include "nvim/path.h"
+#include "nvim/plines.h"
#include "nvim/popupmnu.h"
#include "nvim/quickfix.h"
#include "nvim/regexp.h"
+#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/sign.h"
#include "nvim/spell.h"
@@ -115,12 +120,8 @@
#include "nvim/ui_compositor.h"
#include "nvim/undo.h"
#include "nvim/version.h"
+#include "nvim/vim.h"
#include "nvim/window.h"
-#include "nvim/os/time.h"
-#include "nvim/api/private/helpers.h"
-#include "nvim/api/vim.h"
-#include "nvim/lua/executor.h"
-#include "nvim/lib/kvec.h"
#define MB_FILLER_CHAR '<' /* character used when a double-width character
* doesn't fit. */
@@ -134,7 +135,7 @@ static size_t linebuf_size = 0;
static schar_T *linebuf_char = NULL;
static sattr_T *linebuf_attr = NULL;
-static match_T search_hl; /* used for 'hlsearch' highlight matching */
+static match_T search_hl; // used for 'hlsearch' highlight matching
StlClickDefinition *tab_page_click_defs = NULL;
@@ -165,10 +166,9 @@ static bool resizing = false;
#endif
#define SEARCH_HL_PRIORITY 0
-static char * provider_first_error = NULL;
+static char * provider_err = NULL;
-static bool provider_invoke(NS ns_id, const char *name, LuaRef ref,
- Array args, bool default_true)
+static bool provider_invoke(NS ns_id, const char *name, LuaRef ref, Array args, bool default_true)
{
Error err = ERROR_INIT;
@@ -187,10 +187,10 @@ static bool provider_invoke(NS ns_id, const char *name, LuaRef ref,
const char *ns_name = describe_ns(ns_id);
ELOG("error in provider %s:%s: %s", ns_name, name, err.msg);
bool verbose_errs = true; // TODO(bfredl):
- if (verbose_errs && provider_first_error == NULL) {
+ if (verbose_errs && provider_err == NULL) {
static char errbuf[IOSIZE];
snprintf(errbuf, sizeof errbuf, "%s: %s", ns_name, err.msg);
- provider_first_error = xstrdup(errbuf);
+ provider_err = xstrdup(errbuf);
}
}
@@ -207,10 +207,12 @@ void redraw_later(win_T *wp, int type)
{
if (!exiting && wp->w_redr_type < type) {
wp->w_redr_type = type;
- if (type >= NOT_VALID)
+ if (type >= NOT_VALID) {
wp->w_lines_valid = 0;
- if (must_redraw < type) /* must_redraw is the maximum of all windows */
+ }
+ if (must_redraw < type) { // must_redraw is the maximum of all windows
must_redraw = type;
+ }
}
}
@@ -269,10 +271,10 @@ void redraw_buf_range_later(buf_T *buf, linenr_T firstline, linenr_T lastline)
if (wp->w_buffer == buf
&& lastline >= wp->w_topline && firstline < wp->w_botline) {
if (wp->w_redraw_top == 0 || wp->w_redraw_top > firstline) {
- wp->w_redraw_top = firstline;
+ wp->w_redraw_top = firstline;
}
if (wp->w_redraw_bot == 0 || wp->w_redraw_bot < lastline) {
- wp->w_redraw_bot = lastline;
+ wp->w_redraw_bot = lastline;
}
redraw_later(wp, VALID);
}
@@ -287,20 +289,16 @@ void redraw_buf_range_later(buf_T *buf, linenr_T firstline, linenr_T lastline)
* Note that when also inserting/deleting lines w_redraw_top and w_redraw_bot
* may become invalid and the whole window will have to be redrawn.
*/
-void
-redrawWinline(
- win_T *wp,
- linenr_T lnum
-)
+void redrawWinline(win_T *wp, linenr_T lnum)
FUNC_ATTR_NONNULL_ALL
{
if (lnum >= wp->w_topline
&& lnum < wp->w_botline) {
if (wp->w_redraw_top == 0 || wp->w_redraw_top > lnum) {
- wp->w_redraw_top = lnum;
+ wp->w_redraw_top = lnum;
}
if (wp->w_redraw_bot == 0 || wp->w_redraw_bot < lnum) {
- wp->w_redraw_bot = lnum;
+ wp->w_redraw_bot = lnum;
}
redraw_later(wp, VALID);
}
@@ -323,8 +321,7 @@ void update_curbuf(int type)
/// @param type set to a NOT_VALID to force redraw of entire screen
int update_screen(int type)
{
- static int did_intro = FALSE;
- int did_one;
+ static bool did_intro = false;
// Don't do anything if the screen structures are (not yet) valid.
// A VimResized autocmd can invoke redrawing in the middle of a resize,
@@ -339,8 +336,9 @@ int update_screen(int type)
}
if (must_redraw) {
- if (type < must_redraw) /* use maximal type */
+ if (type < must_redraw) { // use maximal type
type = must_redraw;
+ }
/* must_redraw is reset here, so that when we run into some weird
* reason to redraw while busy redrawing (e.g., asynchronous
@@ -349,9 +347,10 @@ int update_screen(int type)
must_redraw = 0;
}
- /* Need to update w_lines[]. */
- if (curwin->w_lines_valid == 0 && type < NOT_VALID)
+ // Need to update w_lines[].
+ if (curwin->w_lines_valid == 0 && type < NOT_VALID) {
type = NOT_VALID;
+ }
/* Postpone the redrawing when it's not needed and when being called
* recursively. */
@@ -386,7 +385,7 @@ int update_screen(int type)
// non-displayed part of msg_grid is considered invalid.
for (int i = 0; i < MIN(msg_scrollsize(), msg_grid.Rows); i++) {
grid_clear_line(&msg_grid, msg_grid.line_offset[i],
- (int)msg_grid.Columns, false);
+ msg_grid.Columns, false);
}
}
if (msg_use_msgsep()) {
@@ -437,8 +436,8 @@ int update_screen(int type)
}
}
}
- redraw_cmdline = TRUE;
- redraw_tabline = TRUE;
+ redraw_cmdline = true;
+ redraw_tabline = true;
}
msg_scrolled = 0;
msg_scrolled_at_flush = 0;
@@ -448,12 +447,13 @@ int update_screen(int type)
win_ui_flush();
msg_ext_check_clear();
- /* reset cmdline_row now (may have been changed temporarily) */
+ // reset cmdline_row now (may have been changed temporarily)
compute_cmdrow();
- /* Check for changed highlighting */
- if (need_highlight_changed)
+ // Check for changed highlighting
+ if (need_highlight_changed) {
highlight_changed();
+ }
if (type == CLEAR) { // first clear screen
screenclear(); // will reset clear_cmdline
@@ -503,21 +503,24 @@ int update_screen(int type)
redraw_tabline = true;
}
- if (clear_cmdline) /* going to clear cmdline (done below) */
- check_for_delay(FALSE);
+ if (clear_cmdline) { // going to clear cmdline (done below)
+ check_for_delay(false);
+ }
/* Force redraw when width of 'number' or 'relativenumber' column
* changes. */
if (curwin->w_redr_type < NOT_VALID
&& curwin->w_nrwidth != ((curwin->w_p_nu || curwin->w_p_rnu)
- ? number_width(curwin) : 0))
+ ? number_width(curwin) : 0)) {
curwin->w_redr_type = NOT_VALID;
+ }
/*
* Only start redrawing if there is really something to do.
*/
- if (type == INVERTED)
+ if (type == INVERTED) {
update_curswant();
+ }
if (curwin->w_redr_type < type
&& !((type == VALID
&& curwin->w_lines[0].wl_valid
@@ -530,8 +533,9 @@ int update_screen(int type)
&& curwin->w_old_visual_mode == VIsual_mode
&& (curwin->w_valid & VALID_VIRTCOL)
&& curwin->w_old_curswant == curwin->w_curswant)
- ))
+ )) {
curwin->w_redr_type = type;
+ }
// Redraw the tab pages line if needed.
if (redraw_tabline || type >= NOT_VALID) {
@@ -577,7 +581,7 @@ int update_screen(int type)
* Go from top to bottom through the windows, redrawing the ones that need
* it.
*/
- did_one = FALSE;
+ bool did_one = false;
search_hl.rm.regprog = NULL;
@@ -596,13 +600,13 @@ int update_screen(int type)
if (wp->w_redr_type != 0) {
if (!did_one) {
- did_one = TRUE;
+ did_one = true;
start_search_hl();
}
win_update(wp, &providers);
}
- /* redraw status line after the window to minimize cursor movement */
+ // redraw status line after the window to minimize cursor movement
if (wp->w_redr_status) {
win_redr_status(wp);
}
@@ -631,10 +635,11 @@ int update_screen(int type)
showmode();
}
- /* May put up an introductory message when not editing a file */
- if (!did_intro)
+ // May put up an introductory message when not editing a file
+ if (!did_intro) {
maybe_intro_message();
- did_intro = TRUE;
+ }
+ did_intro = true;
for (size_t i = 0; i < kv_size(providers); i++) {
DecorProvider *p = kv_A(providers, i);
@@ -704,7 +709,7 @@ bool win_cursorline_standout(const win_T *wp)
FUNC_ATTR_NONNULL_ALL
{
return wp->w_p_cul
- || (wp->w_p_cole > 0 && (VIsual_active || !conceal_cursor_line(wp)));
+ || (wp->w_p_cole > 0 && (VIsual_active || !conceal_cursor_line(wp)));
}
/*
@@ -715,28 +720,28 @@ bool win_cursorline_standout(const win_T *wp)
*
* How the window is redrawn depends on wp->w_redr_type. Each type also
* implies the one below it.
- * NOT_VALID redraw the whole window
- * SOME_VALID redraw the whole window but do scroll when possible
- * REDRAW_TOP redraw the top w_upd_rows window lines, otherwise like VALID
- * INVERTED redraw the changed part of the Visual area
- * INVERTED_ALL redraw the whole Visual area
- * VALID 1. scroll up/down to adjust for a changed w_topline
- * 2. update lines at the top when scrolled down
- * 3. redraw changed text:
- * - if wp->w_buffer->b_mod_set set, update lines between
- * b_mod_top and b_mod_bot.
- * - if wp->w_redraw_top non-zero, redraw lines between
- * wp->w_redraw_top and wp->w_redr_bot.
- * - continue redrawing when syntax status is invalid.
- * 4. if scrolled up, update lines at the bottom.
+ * NOT_VALID redraw the whole window
+ * SOME_VALID redraw the whole window but do scroll when possible
+ * REDRAW_TOP redraw the top w_upd_rows window lines, otherwise like VALID
+ * INVERTED redraw the changed part of the Visual area
+ * INVERTED_ALL redraw the whole Visual area
+ * VALID 1. scroll up/down to adjust for a changed w_topline
+ * 2. update lines at the top when scrolled down
+ * 3. redraw changed text:
+ * - if wp->w_buffer->b_mod_set set, update lines between
+ * b_mod_top and b_mod_bot.
+ * - if wp->w_redraw_top non-zero, redraw lines between
+ * wp->w_redraw_top and wp->w_redr_bot.
+ * - continue redrawing when syntax status is invalid.
+ * 4. if scrolled up, update lines at the bottom.
* This results in three areas that may need updating:
- * top: from first row to top_end (when scrolled down)
+ * top: from first row to top_end (when scrolled down)
* mid: from mid_start to mid_end (update inversion or changed text)
* bot: from bot_start to last row (when scrolled up)
*/
static void win_update(win_T *wp, Providers *providers)
{
- buf_T *buf = wp->w_buffer;
+ buf_T *buf = wp->w_buffer;
int type;
int top_end = 0; /* Below last row of the top area that needs
updating. 0 when no top area updating. */
@@ -746,29 +751,26 @@ static void win_update(win_T *wp, Providers *providers)
updating. 0 when no mid area updating. */
int bot_start = 999; /* first row of the bot area that needs
updating. 999 when no bot area updating */
- int scrolled_down = FALSE; /* TRUE when scrolled down when
- w_topline got smaller a bit */
+ bool scrolled_down = false; // true when scrolled down when w_topline got smaller a bit
bool top_to_mod = false; // redraw above mod_top
- int row; /* current window row to display */
- linenr_T lnum; /* current buffer lnum to display */
- int idx; /* current index in w_lines[] */
- int srow; /* starting row of the current line */
+ int row; // current window row to display
+ linenr_T lnum; // current buffer lnum to display
+ int idx; // current index in w_lines[]
+ int srow; // starting row of the current line
- int eof = FALSE; /* if TRUE, we hit the end of the file */
- int didline = FALSE; /* if TRUE, we finished the last line */
+ bool eof = false; // if true, we hit the end of the file
+ bool didline = false; // if true, we finished the last line
int i;
long j;
static bool recursive = false; // being called recursively
const linenr_T old_botline = wp->w_botline;
- const int old_wrow = wp->w_wrow;
- const int old_wcol = wp->w_wcol;
// Remember what happened to the previous line.
#define DID_NONE 1 // didn't update a line
#define DID_LINE 2 // updated a normal line
#define DID_FOLD 3 // updated a folded line
int did_update = DID_NONE;
- linenr_T syntax_last_parsed = 0; /* last parsed text line */
+ linenr_T syntax_last_parsed = 0; // last parsed text line
linenr_T mod_top = 0;
linenr_T mod_bot = 0;
int save_got_int;
@@ -825,10 +827,11 @@ static void win_update(win_T *wp, Providers *providers)
* changes. Set mod_bot to the first line after the changes.
*/
mod_top = wp->w_redraw_top;
- if (wp->w_redraw_bot != 0)
+ if (wp->w_redraw_bot != 0) {
mod_bot = wp->w_redraw_bot + 1;
- else
+ } else {
mod_bot = 0;
+ }
if (buf->b_mod_set) {
if (mod_top == 0 || mod_top > buf->b_mod_top) {
mod_top = buf->b_mod_top;
@@ -836,12 +839,14 @@ static void win_update(win_T *wp, Providers *providers)
* in a pattern match. */
if (syntax_present(wp)) {
mod_top -= buf->b_s.b_syn_sync_linebreaks;
- if (mod_top < 1)
+ if (mod_top < 1) {
mod_top = 1;
+ }
}
}
- if (mod_bot == 0 || mod_bot < buf->b_mod_bot)
+ if (mod_bot == 0 || mod_bot < buf->b_mod_bot) {
mod_bot = buf->b_mod_bot;
+ }
// When 'hlsearch' is on and using a multi-line search pattern, a
// change in one line may make the Search highlighting in a
@@ -880,10 +885,11 @@ static void win_update(win_T *wp, Providers *providers)
* to this line. If there is no valid entry, use MAXLNUM. */
lnumt = wp->w_topline;
lnumb = MAXLNUM;
- for (i = 0; i < wp->w_lines_valid; ++i)
+ for (i = 0; i < wp->w_lines_valid; ++i) {
if (wp->w_lines[i].wl_valid) {
- if (wp->w_lines[i].wl_lastlnum < mod_top)
+ if (wp->w_lines[i].wl_lastlnum < mod_top) {
lnumt = wp->w_lines[i].wl_lastlnum + 1;
+ }
if (lnumb == MAXLNUM && wp->w_lines[i].wl_lnum >= mod_bot) {
lnumb = wp->w_lines[i].wl_lnum;
// When there is a fold column it might need updating
@@ -893,6 +899,7 @@ static void win_update(win_T *wp, Providers *providers)
}
}
}
+ }
(void)hasFoldingWin(wp, mod_top, &mod_top, NULL, true, NULL);
if (mod_top > lnumt) {
@@ -913,16 +920,18 @@ static void win_update(win_T *wp, Providers *providers)
* If the end of the change is above w_topline: do like no change was
* made, but redraw the first line to find changes in syntax. */
if (mod_top != 0 && mod_top < wp->w_topline) {
- if (mod_bot > wp->w_topline)
+ if (mod_bot > wp->w_topline) {
mod_top = wp->w_topline;
- else if (syntax_present(wp))
+ } else if (syntax_present(wp)) {
top_end = 1;
+ }
}
/* When line numbers are displayed need to redraw all lines below
* inserted/deleted lines. */
- if (mod_top != 0 && buf->b_mod_xlines != 0 && wp->w_p_nu)
+ if (mod_top != 0 && buf->b_mod_xlines != 0 && wp->w_p_nu) {
mod_bot = MAXLNUM;
+ }
}
wp->w_redraw_top = 0; // reset for next time
wp->w_redraw_bot = 0;
@@ -940,12 +949,13 @@ static void win_update(win_T *wp, Providers *providers)
break;
}
}
- if (top_end == 0)
- /* not found (cannot happen?): redraw everything */
+ if (top_end == 0) {
+ // not found (cannot happen?): redraw everything
type = NOT_VALID;
- else
- /* top area defined, the rest is VALID */
+ } else {
+ // top area defined, the rest is VALID
type = VALID;
+ }
}
/*
@@ -958,8 +968,7 @@ static void win_update(win_T *wp, Providers *providers)
*/
if ((type == VALID || type == SOME_VALID
|| type == INVERTED || type == INVERTED_ALL)
- && !wp->w_botfill && !wp->w_old_botfill
- ) {
+ && !wp->w_botfill && !wp->w_old_botfill) {
if (mod_top != 0
&& wp->w_topline == mod_top
&& (!wp->w_lines[0].wl_valid
@@ -987,14 +996,15 @@ static void win_update(win_T *wp, Providers *providers)
}
(void)hasFoldingWin(wp, ln, NULL, &ln, true, NULL);
}
- } else
+ } else {
j = wp->w_lines[0].wl_lnum - wp->w_topline;
+ }
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 += diff_check_fill(wp, wp->w_lines[0].wl_lnum)
- - wp->w_old_topfill;
+ // 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
// Try to insert the correct number of lines.
// If not the last window, delete the lines at the bottom.
@@ -1031,7 +1041,7 @@ static void win_update(win_T *wp, Providers *providers)
* needs updating.
*/
- /* try to find wp->w_topline in wp->w_lines[].wl_lnum */
+ // try to find wp->w_topline in wp->w_lines[].wl_lnum
j = -1;
row = 0;
for (i = 0; i < wp->w_lines_valid; i++) {
@@ -1053,11 +1063,12 @@ static void win_update(win_T *wp, Providers *providers)
*/
/* If the topline didn't change, delete old filler lines,
* otherwise delete filler lines of the new topline... */
- if (wp->w_lines[0].wl_lnum == wp->w_topline)
+ if (wp->w_lines[0].wl_lnum == wp->w_topline) {
row += wp->w_old_topfill;
- else
- row += diff_check_fill(wp, wp->w_topline);
- /* ... but don't delete new filler lines. */
+ } else {
+ row += win_get_fill(wp, wp->w_topline);
+ }
+ // ... but don't delete new filler lines.
row -= wp->w_topfill;
if (row > 0) {
win_scroll_lines(wp, 0, -row);
@@ -1066,7 +1077,7 @@ static void win_update(win_T *wp, Providers *providers)
if ((row == 0 || bot_start < 999) && wp->w_lines_valid != 0) {
/*
* Skip the lines (below the deleted lines) that are still
- * valid and don't need redrawing. Copy their info
+ * valid and don't need redrawing. Copy their info
* upwards, to compensate for the deleted lines. Set
* bot_start to the first row that needs redrawing.
*/
@@ -1083,18 +1094,19 @@ static void win_update(win_T *wp, Providers *providers)
}
bot_start += wp->w_lines[idx++].wl_size;
- /* stop at the last valid entry in w_lines[].wl_size */
+ // stop at the last valid entry in w_lines[].wl_size
if (++j >= wp->w_lines_valid) {
wp->w_lines_valid = idx;
break;
}
}
- /* Correct the first entry for filler lines at the top
- * when it won't get updated below. */
- if (wp->w_p_diff && bot_start > 0)
- wp->w_lines[0].wl_size =
- plines_win_nofill(wp, wp->w_topline, true)
- + wp->w_topfill;
+
+ // Correct the first entry for filler lines at the top
+ // when it won't get updated below.
+ if (win_may_fill(wp) && bot_start > 0) {
+ wp->w_lines[0].wl_size = (plines_win_nofill(wp, wp->w_topline, true)
+ + wp->w_topfill);
+ }
}
}
}
@@ -1104,19 +1116,19 @@ static void win_update(win_T *wp, Providers *providers)
mid_end = wp->w_grid.Rows;
}
} else {
- /* Not VALID or INVERTED: redraw all lines. */
+ // Not VALID or INVERTED: redraw all lines.
mid_start = 0;
mid_end = wp->w_grid.Rows;
}
if (type == SOME_VALID) {
- /* SOME_VALID: redraw all lines. */
+ // SOME_VALID: redraw all lines.
mid_start = 0;
mid_end = wp->w_grid.Rows;
type = NOT_VALID;
}
- /* check if we are updating or removing the inverted part */
+ // check if we are updating or removing the inverted part
if ((VIsual_active && buf == curwin->w_buffer)
|| (wp->w_old_cursor_lnum != 0 && type != NOT_VALID)) {
linenr_T from, to;
@@ -1133,15 +1145,19 @@ static void win_update(win_T *wp, Providers *providers)
from = VIsual.lnum;
to = curwin->w_cursor.lnum;
}
- /* redraw more when the cursor moved as well */
- if (wp->w_old_cursor_lnum < from)
+ // redraw more when the cursor moved as well
+ if (wp->w_old_cursor_lnum < from) {
from = wp->w_old_cursor_lnum;
- if (wp->w_old_cursor_lnum > to)
+ }
+ if (wp->w_old_cursor_lnum > to) {
to = wp->w_old_cursor_lnum;
- if (wp->w_old_visual_lnum < from)
+ }
+ if (wp->w_old_visual_lnum < from) {
from = wp->w_old_visual_lnum;
- if (wp->w_old_visual_lnum > to)
+ }
+ if (wp->w_old_visual_lnum > to) {
to = wp->w_old_visual_lnum;
+ }
} else {
/*
* Find the line numbers that need to be updated: The lines
@@ -1154,21 +1170,26 @@ static void win_update(win_T *wp, Providers *providers)
} else {
from = wp->w_old_cursor_lnum;
to = curwin->w_cursor.lnum;
- if (from == 0) /* Visual mode just started */
+ if (from == 0) { // Visual mode just started
from = to;
+ }
}
if (VIsual.lnum != wp->w_old_visual_lnum
|| VIsual.col != wp->w_old_visual_col) {
if (wp->w_old_visual_lnum < from
- && wp->w_old_visual_lnum != 0)
+ && wp->w_old_visual_lnum != 0) {
from = wp->w_old_visual_lnum;
- if (wp->w_old_visual_lnum > to)
+ }
+ if (wp->w_old_visual_lnum > to) {
to = wp->w_old_visual_lnum;
- if (VIsual.lnum < from)
+ }
+ if (VIsual.lnum < from) {
from = VIsual.lnum;
- if (VIsual.lnum > to)
+ }
+ if (VIsual.lnum > to) {
to = VIsual.lnum;
+ }
}
}
@@ -1181,27 +1202,33 @@ static void win_update(win_T *wp, Providers *providers)
colnr_T fromc, toc;
int save_ve_flags = ve_flags;
- if (curwin->w_p_lbr)
+ if (curwin->w_p_lbr) {
ve_flags = VE_ALL;
+ }
getvcols(wp, &VIsual, &curwin->w_cursor, &fromc, &toc);
ve_flags = save_ve_flags;
- ++toc;
- if (curwin->w_curswant == MAXCOL)
+ toc++;
+ // Highlight to the end of the line, unless 'virtualedit' has
+ // "block".
+ if (curwin->w_curswant == MAXCOL && !(ve_flags & VE_BLOCK)) {
toc = MAXCOL;
+ }
if (fromc != wp->w_old_cursor_fcol
|| toc != wp->w_old_cursor_lcol) {
- if (from > VIsual.lnum)
+ if (from > VIsual.lnum) {
from = VIsual.lnum;
- if (to < VIsual.lnum)
+ }
+ if (to < VIsual.lnum) {
to = VIsual.lnum;
+ }
}
wp->w_old_cursor_fcol = fromc;
wp->w_old_cursor_lcol = toc;
}
} else {
- /* Use the line numbers of the old Visual area. */
+ // Use the line numbers of the old Visual area.
if (wp->w_old_cursor_lnum < wp->w_old_visual_lnum) {
from = wp->w_old_cursor_lnum;
to = wp->w_old_visual_lnum;
@@ -1214,18 +1241,21 @@ static void win_update(win_T *wp, Providers *providers)
/*
* There is no need to update lines above the top of the window.
*/
- if (from < wp->w_topline)
+ if (from < wp->w_topline) {
from = wp->w_topline;
+ }
/*
* If we know the value of w_botline, use it to restrict the update to
* the lines that are visible in the window.
*/
if (wp->w_valid & VALID_BOTLINE) {
- if (from >= wp->w_botline)
+ if (from >= wp->w_botline) {
from = wp->w_botline - 1;
- if (to >= wp->w_botline)
+ }
+ if (to >= wp->w_botline) {
to = wp->w_botline - 1;
+ }
}
/*
@@ -1241,27 +1271,30 @@ static void win_update(win_T *wp, Providers *providers)
lnum = wp->w_topline;
idx = 0;
srow = 0;
- if (scrolled_down)
+ if (scrolled_down) {
mid_start = top_end;
- else
+ } else {
mid_start = 0;
- while (lnum < from && idx < wp->w_lines_valid) { /* find start */
- if (wp->w_lines[idx].wl_valid)
+ }
+ while (lnum < from && idx < wp->w_lines_valid) { // find start
+ if (wp->w_lines[idx].wl_valid) {
mid_start += wp->w_lines[idx].wl_size;
- else if (!scrolled_down)
+ } else if (!scrolled_down) {
srow += wp->w_lines[idx].wl_size;
+ }
++idx;
- if (idx < wp->w_lines_valid && wp->w_lines[idx].wl_valid)
+ if (idx < wp->w_lines_valid && wp->w_lines[idx].wl_valid) {
lnum = wp->w_lines[idx].wl_lnum;
- else
+ } else {
++lnum;
+ }
}
srow += mid_start;
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) {
- /* Only update until first row of this line */
+ // Only update until first row of this line
mid_end = srow;
break;
}
@@ -1283,7 +1316,7 @@ static void win_update(win_T *wp, Providers *providers)
wp->w_old_visual_col = 0;
}
- /* reset got_int, otherwise regexp won't work */
+ // reset got_int, otherwise regexp won't work
save_got_int = got_int;
got_int = 0;
// Set the time limit to 'redrawtime'.
@@ -1293,7 +1326,7 @@ static void win_update(win_T *wp, Providers *providers)
/*
* Update all the window rows.
*/
- idx = 0; /* first entry in w_lines[].wl_size */
+ idx = 0; // first entry in w_lines[].wl_size
row = 0;
srow = 0;
lnum = wp->w_topline; // first line shown in window
@@ -1333,9 +1366,9 @@ static void win_update(win_T *wp, Providers *providers)
break;
}
- /* stop updating when hit the end of the file */
+ // stop updating when hit the end of the file
if (lnum > buf->b_ml.ml_line_count) {
- eof = TRUE;
+ eof = true;
break;
}
@@ -1368,7 +1401,9 @@ static void win_update(win_T *wp, Providers *providers)
// match in fixed position might need redraw
// if lines were inserted or deleted
|| (wp->w_match_head != NULL
- && buf->b_mod_xlines != 0)))))) {
+ && buf->b_mod_xlines != 0)))))
+ || (wp->w_p_cul && (lnum == wp->w_cursor.lnum
+ || lnum == wp->w_last_cursorline))) {
if (lnum == mod_top) {
top_to_mod = false;
}
@@ -1378,10 +1413,12 @@ static void win_update(win_T *wp, Providers *providers)
* up or down to minimize redrawing.
* Don't do this when the change continues until the end.
* Don't scroll when dollar_vcol >= 0, keep the "$".
+ * Don't scroll when redrawing the top, scrolled already above.
*/
if (lnum == mod_top
&& mod_bot != MAXLNUM
- && !(dollar_vcol >= 0 && mod_bot == mod_top + 1)) {
+ && !(dollar_vcol >= 0 && mod_bot == mod_top + 1)
+ && row >= top_end) {
int old_rows = 0;
int new_rows = 0;
int xtra_rows;
@@ -1394,8 +1431,9 @@ static void win_update(win_T *wp, Providers *providers)
/* Only valid lines have a meaningful wl_lnum. Invalid
* lines are part of the changed area. */
if (wp->w_lines[i].wl_valid
- && wp->w_lines[i].wl_lnum == mod_bot)
+ && wp->w_lines[i].wl_lnum == mod_bot) {
break;
+ }
old_rows += wp->w_lines[i].wl_size;
if (wp->w_lines[i].wl_valid
&& wp->w_lines[i].wl_lastlnum + 1 == mod_bot) {
@@ -1403,8 +1441,9 @@ static void win_update(win_T *wp, Providers *providers)
* Add following invalid entries. */
++i;
while (i < wp->w_lines_valid
- && !wp->w_lines[i].wl_valid)
+ && !wp->w_lines[i].wl_valid) {
old_rows += wp->w_lines[i++].wl_size;
+ }
break;
}
}
@@ -1467,15 +1506,15 @@ static void win_update(win_T *wp, Providers *providers)
if (j < i) {
int x = row + new_rows;
- /* move entries in w_lines[] upwards */
+ // move entries in w_lines[] upwards
for (;; ) {
- /* stop at last valid entry in w_lines[] */
+ // stop at last valid entry in w_lines[]
if (i >= wp->w_lines_valid) {
wp->w_lines_valid = j;
break;
}
wp->w_lines[j] = wp->w_lines[i];
- /* stop at a line that won't fit */
+ // stop at a line that won't fit
if (x + (int)wp->w_lines[j].wl_size
> wp->w_grid.Rows) {
wp->w_lines_valid = j + 1;
@@ -1484,10 +1523,11 @@ static void win_update(win_T *wp, Providers *providers)
x += wp->w_lines[j++].wl_size;
++i;
}
- if (bot_start > x)
+ if (bot_start > x) {
bot_start = x;
- } else { /* j > i */
- /* move entries in w_lines[] downwards */
+ }
+ } else { // j > i
+ // move entries in w_lines[] downwards
j -= i;
wp->w_lines_valid += j;
if (wp->w_lines_valid > wp->w_grid.Rows) {
@@ -1523,17 +1563,17 @@ static void win_update(win_T *wp, Providers *providers)
&& lnum > wp->w_topline
&& !(dy_flags & (DY_LASTLINE | DY_TRUNCATE))
&& srow + wp->w_lines[idx].wl_size > wp->w_grid.Rows
- && diff_check_fill(wp, lnum) == 0
- ) {
+ && 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;
} else {
prepare_search_hl(wp, lnum);
- /* Let the syntax stuff know we skipped a few lines. */
+ // Let the syntax stuff know we skipped a few lines.
if (syntax_last_parsed != 0 && syntax_last_parsed + 1 < lnum
- && syntax_present(wp))
+ && syntax_present(wp)) {
syntax_end_parsing(syntax_last_parsed + 1);
+ }
// Display one line
row = win_line(wp, lnum, srow,
@@ -1588,7 +1628,7 @@ static void win_update(win_T *wp, Providers *providers)
}
if (lnum > buf->b_ml.ml_line_count) {
- eof = TRUE;
+ eof = true;
break;
}
}
@@ -1597,14 +1637,16 @@ static void win_update(win_T *wp, Providers *providers)
*/
- if (idx > wp->w_lines_valid)
+ if (idx > wp->w_lines_valid) {
wp->w_lines_valid = idx;
+ }
/*
* Let the syntax stuff know we stop parsing here.
*/
- if (syntax_last_parsed != 0 && syntax_present(wp))
+ if (syntax_last_parsed != 0 && syntax_present(wp)) {
syntax_end_parsing(syntax_last_parsed + 1);
+ }
/*
* If we didn't hit the end of the file, and we didn't finish the last
@@ -1621,7 +1663,7 @@ static void win_update(win_T *wp, Providers *providers)
* Don't overwrite it, it can be edited.
*/
wp->w_botline = lnum + 1;
- } else if (diff_check_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;
@@ -1648,22 +1690,17 @@ static void win_update(win_T *wp, Providers *providers)
} else {
if (eof) { // we hit the end of the file
wp->w_botline = buf->b_ml.ml_line_count + 1;
- j = diff_check_fill(wp, wp->w_botline);
+ j = win_get_fill(wp, wp->w_botline);
if (j > 0 && !wp->w_botfill) {
- // display filler lines at the end of the file
- if (char2cells(wp->w_p_fcs_chars.diff) > 1) {
- i = '-';
- } else {
- i = wp->w_p_fcs_chars.diff;
- }
- if (row + j > wp->w_grid.Rows) {
- j = wp->w_grid.Rows - row;
- }
- win_draw_end(wp, i, i, true, row, row + (int)j, HLF_DED);
- row += j;
+ // 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,
+ false, false, info, &line_providers);
}
- } else if (dollar_vcol == -1)
+ } else if (dollar_vcol == -1) {
wp->w_botline = lnum;
+ }
// make sure the rest of the screen is blank
// write the 'eob' character to rows that aren't part of the file.
@@ -1678,7 +1715,7 @@ static void win_update(win_T *wp, Providers *providers)
}
syn_set_timeout(NULL);
- /* Reset the type of redrawing required, the window has been updated. */
+ // Reset the type of redrawing required, the window has been updated.
wp->w_redr_type = 0;
wp->w_old_topfill = wp->w_topfill;
wp->w_old_botfill = wp->w_botfill;
@@ -1687,7 +1724,7 @@ static void win_update(win_T *wp, Providers *providers)
/*
* There is a trick with w_botline. If we invalidate it on each
* change that might modify it, this will cause a lot of expensive
- * calls to plines() in update_topline() each time. Therefore the
+ * calls to plines_win() in update_topline() each time. Therefore the
* value of w_botline is often approximated, and this value is used to
* compute the value of w_topline. If the value of w_botline was
* wrong, check that the value of w_topline is correct (cursor is on
@@ -1699,58 +1736,26 @@ static void win_update(win_T *wp, Providers *providers)
wp->w_valid |= VALID_BOTLINE;
wp->w_viewport_invalid = true;
if (wp == curwin && wp->w_botline != old_botline && !recursive) {
- const linenr_T old_topline = wp->w_topline;
- const int new_wcol = wp->w_wcol;
recursive = true;
curwin->w_valid &= ~VALID_TOPLINE;
update_topline(curwin); // may invalidate w_botline again
-
- if (old_wcol != new_wcol
- && (wp->w_valid & (VALID_WCOL|VALID_WROW))
- != (VALID_WCOL|VALID_WROW)) {
- // A win_line() call applied a fix to screen cursor column to
- // accommodate concealment of cursor line, but in this call to
- // update_topline() the cursor's row or column got invalidated.
- // If they are left invalid, setcursor() will recompute them
- // but there won't be any further win_line() call to re-fix the
- // column and the cursor will end up misplaced. So we call
- // cursor validation now and reapply the fix again (or call
- // win_line() to do it for us).
- validate_cursor();
- if (wp->w_wcol == old_wcol
- && wp->w_wrow == old_wrow
- && old_topline == wp->w_topline) {
- wp->w_wcol = new_wcol;
- } else {
- redrawWinline(wp, wp->w_cursor.lnum);
- }
- }
- // New redraw either due to updated topline or due to wcol fix.
- if (wp->w_redr_type != 0) {
+ if (must_redraw != 0) {
// Don't update for changes in buffer again.
i = curbuf->b_mod_set;
curbuf->b_mod_set = false;
- j = curbuf->b_mod_xlines;
- curbuf->b_mod_xlines = 0;
win_update(curwin, providers);
+ must_redraw = 0;
curbuf->b_mod_set = i;
- curbuf->b_mod_xlines = j;
- }
- // Other windows might have w_redr_type raised in update_topline().
- must_redraw = 0;
- FOR_ALL_WINDOWS_IN_TAB(wwp, curtab) {
- if (wwp->w_redr_type > must_redraw) {
- must_redraw = wwp->w_redr_type;
- }
}
recursive = false;
}
}
- /* restore got_int, unless CTRL-C was hit while redrawing */
- if (!got_int)
+ // restore got_int, unless CTRL-C was hit while redrawing
+ if (!got_int) {
got_int = save_got_int;
+ }
} // NOLINT(readability/fn_size)
/// Returns width of the signcolumn that should be used for the whole window
@@ -1770,8 +1775,8 @@ int win_signcol_width(win_T *wp)
/// Call grid_fill() with columns adjusted for 'rightleft' if needed.
/// Return the new offset.
-static int win_fill_end(win_T *wp, int c1, int c2, int off, int width, int row,
- int endrow, int attr)
+static int win_fill_end(win_T *wp, int c1, int c2, int off, int width, int row, int endrow,
+ int attr)
{
int nn = off + width;
@@ -1792,8 +1797,7 @@ static int win_fill_end(win_T *wp, int c1, int c2, int off, int width, int row,
/// Clear lines near the end of the window and mark the unused lines with "c1".
/// Use "c2" as filler character.
/// When "draw_margin" is true, then draw the sign/fold/number columns.
-static void win_draw_end(win_T *wp, int c1, int c2, bool draw_margin, int row,
- int endrow, hlf_T hl)
+static void win_draw_end(win_T *wp, int c1, int c2, bool draw_margin, int row, int endrow, hlf_T hl)
{
assert(hl >= 0 && hl < HLF_COUNT);
int n = 0;
@@ -1833,13 +1837,14 @@ static void win_draw_end(win_T *wp, int c1, int c2, bool draw_margin, int row,
}
-/*
- * Advance **color_cols and return TRUE when there are columns to draw.
- */
-static int advance_color_col(int vcol, int **color_cols)
+/// Advance **color_cols
+///
+/// @return true when there are columns to draw.
+static bool advance_color_col(int vcol, int **color_cols)
{
- while (**color_cols >= 0 && vcol > **color_cols)
+ while (**color_cols >= 0 && vcol > **color_cols) {
++*color_cols;
+ }
return **color_cols >= 0;
}
@@ -1860,7 +1865,7 @@ static int compute_foldcolumn(win_T *wp, int col)
/// Put a single char from an UTF-8 buffer into a line buffer.
///
/// Handles composing chars and arabic shaping state.
-static int line_putchar(LineState *s, schar_T *dest, int maxcells, bool rl)
+static int line_putchar(buf_T *buf, LineState *s, schar_T *dest, int maxcells, bool rl, int vcol)
{
const char_u *p = (char_u *)s->p;
int cells = utf_ptr2cells(p);
@@ -1870,7 +1875,13 @@ static int line_putchar(LineState *s, schar_T *dest, int maxcells, bool rl)
return -1;
}
u8c = utfc_ptr2char(p, u8cc);
- if (*p < 0x80 && u8cc[0] == 0) {
+ if (*p == TAB) {
+ cells = MIN(tabstop_padding(vcol, buf->b_p_ts, buf->b_p_vts_array), maxcells);
+ for (int c = 0; c < cells; c++) {
+ schar_from_ascii(dest[c], ' ');
+ }
+ goto done;
+ } else if (*p < 0x80 && u8cc[0] == 0) {
schar_from_ascii(dest[0], *p);
s->prev_c = u8c;
} else {
@@ -1903,6 +1914,7 @@ static int line_putchar(LineState *s, schar_T *dest, int maxcells, bool rl)
if (cells > 1) {
dest[1][0] = 0;
}
+done:
s->p += c_len;
return cells;
}
@@ -1917,13 +1929,7 @@ static int line_putchar(LineState *s, schar_T *dest, int maxcells, bool rl)
///
/// Assume monocell characters
/// @return number of chars added to \param p
-static size_t
-fill_foldcolumn(
- char_u *p,
- win_T *wp,
- foldinfo_T foldinfo,
- linenr_T lnum
-)
+static size_t fill_foldcolumn(char_u *p, win_T *wp, foldinfo_T foldinfo, linenr_T lnum)
{
int i = 0;
int level;
@@ -1992,24 +1998,23 @@ fill_foldcolumn(
/// or explicitly return `false`.
///
/// @return the number of last row the line occupies.
-static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
- bool nochange, bool number_only, foldinfo_T foldinfo,
- Providers *providers)
+static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
+ bool number_only, foldinfo_T foldinfo, Providers *providers)
{
int c = 0; // init for GCC
long vcol = 0; // virtual column (for tabs)
long vcol_sbr = -1; // virtual column after showbreak
long vcol_prev = -1; // "vcol" of previous character
- char_u *line; // current line
- char_u *ptr; // current position in "line"
+ char_u *line; // current line
+ char_u *ptr; // current position in "line"
int row; // row in the window, excl w_winrow
- ScreenGrid *grid = &wp->w_grid; // grid specfic to the window
+ ScreenGrid *grid = &wp->w_grid; // grid specific to the window
char_u extra[57]; // sign, line number and 'fdc' must
// fit in here
int n_extra = 0; // number of extra chars
- char_u *p_extra = NULL; // string of extra chars, plus NUL
- char_u *p_extra_free = NULL; // p_extra needs to be freed
+ char_u *p_extra = NULL; // string of extra chars, plus NUL
+ char_u *p_extra_free = NULL; // p_extra needs to be freed
int c_extra = NUL; // extra chars, all the same
int c_final = NUL; // final char, mandatory if set
int extra_attr = 0; // attributes when n_extra != 0
@@ -2022,49 +2027,48 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
// saved "extra" items for when draw_state becomes WL_LINE (again)
int saved_n_extra = 0;
- char_u *saved_p_extra = NULL;
+ char_u *saved_p_extra = NULL;
int saved_c_extra = 0;
int saved_c_final = 0;
int saved_char_attr = 0;
- int n_attr = 0; /* chars with special attr */
- int saved_attr2 = 0; /* char_attr saved for n_attr */
- int n_attr3 = 0; /* chars with overruling special attr */
- int saved_attr3 = 0; /* char_attr saved for n_attr3 */
+ int n_attr = 0; // chars with special attr
+ int saved_attr2 = 0; // char_attr saved for n_attr
+ int n_attr3 = 0; // chars with overruling special attr
+ int saved_attr3 = 0; // char_attr saved for n_attr3
- int n_skip = 0; /* nr of chars to skip for 'nowrap' */
+ int n_skip = 0; // nr of chars to skip for 'nowrap'
int fromcol = -10; // start of inverting
int tocol = MAXCOL; // end of inverting
int fromcol_prev = -2; // start of inverting after cursor
bool noinvcur = false; // don't invert the cursor
- int lnum_in_visual_area = false;
+ bool lnum_in_visual_area = false;
pos_T pos;
long v;
- int char_attr = 0; /* attributes for next character */
- int attr_pri = FALSE; /* char_attr has priority */
- int area_highlighting = FALSE; /* Visual or incsearch highlighting
- in this line */
- int attr = 0; /* attributes for area highlighting */
- int area_attr = 0; /* attributes desired by highlighting */
- int search_attr = 0; /* attributes desired by 'hlsearch' */
- int vcol_save_attr = 0; /* saved attr for 'cursorcolumn' */
- int syntax_attr = 0; /* attributes desired by syntax */
- int has_syntax = FALSE; /* this buffer has syntax highl. */
+ int char_attr = 0; // attributes for next character
+ bool attr_pri = false; // char_attr has priority
+ bool area_highlighting = false; // Visual or incsearch highlighting in this line
+ int attr = 0; // attributes for area highlighting
+ int area_attr = 0; // attributes desired by highlighting
+ int search_attr = 0; // attributes desired by 'hlsearch'
+ int vcol_save_attr = 0; // saved attr for 'cursorcolumn'
+ int syntax_attr = 0; // attributes desired by syntax
+ int has_syntax = FALSE; // this buffer has syntax highl.
int save_did_emsg;
int eol_hl_off = 0; // 1 if highlighted char after EOL
- int draw_color_col = false; // highlight colorcolumn
+ bool draw_color_col = false; // highlight colorcolumn
int *color_cols = NULL; // pointer to according columns array
bool has_spell = false; // this buffer has spell checking
-# define SPWORDLEN 150
- char_u nextline[SPWORDLEN * 2]; /* text with start of the next line */
- int nextlinecol = 0; /* column where nextline[] starts */
+#define SPWORDLEN 150
+ char_u nextline[SPWORDLEN * 2]; // text with start of the next line
+ int nextlinecol = 0; // column where nextline[] starts
int nextline_idx = 0; /* index in nextline[] where next line
starts */
- int spell_attr = 0; /* attributes desired by spelling */
- int word_end = 0; /* last byte with same spell_attr */
- static linenr_T checked_lnum = 0; /* line number for "checked_col" */
+ int spell_attr = 0; // attributes desired by spelling
+ int word_end = 0; // last byte with same spell_attr
+ static linenr_T checked_lnum = 0; // line number for "checked_col"
static int checked_col = 0; /* column in "checked_lnum" up to which
* there are no spell errors */
static int cap_col = -1; // column to check for Cap word
@@ -2083,13 +2087,17 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
int change_end = -1; // last col of changed area
colnr_T trailcol = MAXCOL; // start of trailing spaces
colnr_T leadcol = 0; // start of leading spaces
+ bool in_multispace = false; // in multiple consecutive spaces
+ int multispace_pos = 0; // position in lcs-multispace string
bool need_showbreak = false; // overlong line, skip first x chars
sign_attrs_T sattrs[SIGN_SHOW_MAX]; // attributes for signs
int num_signs; // number of signs for line
int line_attr = 0; // attribute for the whole line
+ int line_attr_save;
int line_attr_lowprio = 0; // low-priority attribute for the line
+ int line_attr_lowprio_save;
matchitem_T *cur; // points to the match list
- match_T *shl; // points to search_hl or a match
+ match_T *shl; // points to search_hl or a match
bool shl_flag; // flag to indicate whether search_hl
// has been processed or not
bool prevcol_hl_flag; // flag to indicate whether prevcol
@@ -2100,37 +2108,44 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
bool search_attr_from_match = false; // if search_attr is from :match
bool has_decor = false; // this buffer has decoration
- bool do_virttext = false; // draw virtual text for this line
int win_col_offset = 0; // offset for window columns
char_u buf_fold[FOLD_TEXT_LEN + 1]; // Hold value returned by get_foldtext
bool area_active = false;
- /* draw_state: items that are drawn in sequence: */
-#define WL_START 0 /* nothing done yet */
-# define WL_CMDLINE WL_START + 1 /* cmdline window column */
-# define WL_FOLD WL_CMDLINE + 1 /* 'foldcolumn' */
-# define WL_SIGN WL_FOLD + 1 /* column for signs */
-#define WL_NR WL_SIGN + 1 /* line number */
-# define WL_BRI WL_NR + 1 /* 'breakindent' */
-# define WL_SBR WL_BRI + 1 /* 'showbreak' or 'diff' */
-#define WL_LINE WL_SBR + 1 /* text in the line */
- int draw_state = WL_START; /* what to draw next */
+ int cul_attr = 0; // set when 'cursorline' active
+ // 'cursorlineopt' has "screenline" and cursor is in this line
+ bool cul_screenline = false;
+ // margin columns for the screen line, needed for when 'cursorlineopt'
+ // contains "screenline"
+ int left_curline_col = 0;
+ int right_curline_col = 0;
+
+ // draw_state: items that are drawn in sequence:
+#define WL_START 0 // nothing done yet
+#define WL_CMDLINE WL_START + 1 // cmdline window column
+#define WL_FOLD WL_CMDLINE + 1 // 'foldcolumn'
+#define WL_SIGN WL_FOLD + 1 // column for signs
+#define WL_NR WL_SIGN + 1 // line number
+#define WL_BRI WL_NR + 1 // 'breakindent'
+#define WL_SBR WL_BRI + 1 // 'showbreak' or 'diff'
+#define WL_LINE WL_SBR + 1 // text in the line
+ int draw_state = WL_START; // what to draw next
int syntax_flags = 0;
int syntax_seqnr = 0;
int prev_syntax_id = 0;
int conceal_attr = win_hl_attr(wp, HLF_CONCEAL);
- int is_concealing = false;
+ bool is_concealing = false;
int boguscols = 0; ///< nonexistent columns added to
///< force wrapping
int vcol_off = 0; ///< offset for concealed characters
int did_wcol = false;
int match_conc = 0; ///< cchar for match functions
int old_boguscols = 0;
-# define VCOL_HLC (vcol - vcol_off)
-# define FIX_FOR_BOGUSCOLS \
+#define VCOL_HLC (vcol - vcol_off)
+#define FIX_FOR_BOGUSCOLS \
{ \
n_extra += vcol_off; \
vcol -= vcol_off; \
@@ -2140,14 +2155,14 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
boguscols = 0; \
}
- if (startrow > endrow) /* past the end already! */
+ if (startrow > endrow) { // past the end already!
return startrow;
+ }
row = startrow;
- char *err_text = NULL;
-
buf_T *buf = wp->w_buffer;
+ bool end_fill = (lnum == buf->b_ml.ml_line_count+1);
if (!number_only) {
// To speed up the loop below, set extra_check when there is linebreak,
@@ -2191,14 +2206,20 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
}
}
- if (has_decor) {
- extra_check = true;
+ if (provider_err) {
+ Decoration err_decor = DECORATION_INIT;
+ int hl_err = syn_check_group((char_u *)S_LEN("ErrorMsg"));
+ kv_push(err_decor.virt_text,
+ ((VirtTextChunk){ .text = provider_err,
+ .hl_id = hl_err }));
+ err_decor.virt_text_width = mb_string2cells((char_u *)provider_err);
+ decor_add_ephemeral(lnum-1, 0, lnum-1, 0, &err_decor);
+ provider_err = NULL;
+ has_decor = true;
}
- if (provider_first_error) {
- err_text = provider_first_error;
- provider_first_error = NULL;
- do_virttext = true;
+ if (has_decor) {
+ extra_check = true;
}
// Check for columns to display for 'colorcolumn'.
@@ -2209,6 +2230,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
if (wp->w_p_spell
&& !has_fold
+ && !end_fill
&& *wp->w_s->b_p_spl != NUL
&& !GA_EMPTY(&wp->w_s->b_langp)
&& *(char **)(wp->w_s->b_langp.ga_data) != NULL) {
@@ -2308,7 +2330,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
area_highlighting = true;
attr = win_hl_attr(wp, HLF_V);
}
- // handle 'incsearch' and ":s///c" highlighting
+ // handle 'incsearch' and ":s///c" highlighting
} else if (highlight_match
&& wp == curwin
&& !has_fold
@@ -2337,42 +2359,55 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
filler_lines = diff_check(wp, lnum);
if (filler_lines < 0) {
if (filler_lines == -1) {
- if (diff_find_change(wp, lnum, &change_start, &change_end))
- diff_hlf = HLF_ADD; /* added line */
- else if (change_start == 0)
- diff_hlf = HLF_TXD; /* changed text */
- else
- diff_hlf = HLF_CHD; /* changed line */
- } else
- diff_hlf = HLF_ADD; /* added line */
+ if (diff_find_change(wp, lnum, &change_start, &change_end)) {
+ diff_hlf = HLF_ADD; // added line
+ } else if (change_start == 0) {
+ diff_hlf = HLF_TXD; // changed text
+ } else {
+ diff_hlf = HLF_CHD; // changed line
+ }
+ } else {
+ diff_hlf = HLF_ADD; // added line
+ }
filler_lines = 0;
- area_highlighting = TRUE;
+ area_highlighting = true;
}
- if (lnum == wp->w_topline)
+ int virtual_lines = decor_virtual_lines(wp, lnum);
+ filler_lines += virtual_lines;
+ if (lnum == wp->w_topline) {
filler_lines = wp->w_topfill;
+ virtual_lines = MIN(virtual_lines, filler_lines);
+ }
filler_todo = filler_lines;
// Cursor line highlighting for 'cursorline' in the current window.
if (lnum == wp->w_cursor.lnum) {
- // Do not show the cursor line when Visual mode is active, because it's
- // not clear what is selected then.
- if (wp->w_p_cul && !(wp == curwin && VIsual_active)) {
- int cul_attr = win_hl_attr(wp, HLF_CUL);
- HlAttrs ae = syn_attr2entry(cul_attr);
-
- // We make a compromise here (#7383):
- // * low-priority CursorLine if fg is not set
- // * high-priority ("same as Vim" priority) CursorLine if fg is set
- if (ae.rgb_fg_color == -1 && ae.cterm_fg_color == 0) {
- line_attr_lowprio = cul_attr;
- } else {
- if (!(State & INSERT) && bt_quickfix(wp->w_buffer)
- && qf_current_entry(wp) == lnum) {
- line_attr = hl_combine_attr(cul_attr, line_attr);
+ // Do not show the cursor line in the text when Visual mode is active,
+ // because it's not clear what is selected then.
+ if (wp->w_p_cul && !(wp == curwin && VIsual_active)
+ && wp->w_p_culopt_flags != CULOPT_NBR) {
+ cul_screenline = (wp->w_p_wrap
+ && (wp->w_p_culopt_flags & CULOPT_SCRLINE));
+ if (!cul_screenline) {
+ cul_attr = win_hl_attr(wp, HLF_CUL);
+ HlAttrs ae = syn_attr2entry(cul_attr);
+ // We make a compromise here (#7383):
+ // * low-priority CursorLine if fg is not set
+ // * high-priority ("same as Vim" priority) CursorLine if fg is set
+ if (ae.rgb_fg_color == -1 && ae.cterm_fg_color == 0) {
+ line_attr_lowprio = cul_attr;
} else {
- line_attr = cul_attr;
+ if (!(State & INSERT) && bt_quickfix(wp->w_buffer)
+ && qf_current_entry(wp) == lnum) {
+ line_attr = hl_combine_attr(cul_attr, line_attr);
+ } else {
+ line_attr = cul_attr;
+ }
}
+ } else {
+ margin_columns_win(wp, &left_curline_col, &right_curline_col);
}
+ area_highlighting = true;
}
// Update w_last_cursorline even if Visual mode is active.
wp->w_last_cursorline = wp->w_cursor.lnum;
@@ -2397,7 +2432,12 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
area_highlighting = true;
}
- line = ml_get_buf(wp->w_buffer, lnum, FALSE);
+ if (cul_screenline) {
+ line_attr_save = line_attr;
+ line_attr_lowprio_save = line_attr_lowprio;
+ }
+
+ line = end_fill ? (char_u *)"" : ml_get_buf(wp->w_buffer, lnum, false);
ptr = line;
if (has_spell && !number_only) {
@@ -2410,7 +2450,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
* current line into nextline[]. Above the start of the next line was
* copied to nextline[SPWORDLEN]. */
if (nextline[SPWORDLEN] == NUL) {
- /* No next line or it is empty. */
+ // No next line or it is empty.
nextlinecol = MAXCOL;
nextline_idx = 0;
} else {
@@ -2423,7 +2463,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
STRMOVE(nextline + v, nextline + SPWORDLEN);
nextline_idx = v + 1;
} else {
- /* Long line, use only the last SPWORDLEN bytes. */
+ // Long line, use only the last SPWORDLEN bytes.
nextlinecol = v - SPWORDLEN;
memmove(nextline, line + nextlinecol, SPWORDLEN); // -V512
nextline_idx = SPWORDLEN + 1;
@@ -2431,8 +2471,9 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
}
}
- if (wp->w_p_list && !has_fold) {
+ if (wp->w_p_list && !has_fold && !end_fill) {
if (wp->w_p_lcs_chars.space
+ || wp->w_p_lcs_chars.multispace != NULL
|| wp->w_p_lcs_chars.trail
|| wp->w_p_lcs_chars.lead
|| wp->w_p_lcs_chars.nbsp) {
@@ -2444,7 +2485,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
while (trailcol > (colnr_T)0 && ascii_iswhite(ptr[trailcol - 1])) {
trailcol--;
}
- trailcol += (colnr_T) (ptr - line);
+ trailcol += (colnr_T)(ptr - line);
}
// find end of leading whitespace
if (wp->w_p_lcs_chars.lead) {
@@ -2466,12 +2507,13 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
* 'nowrap' or 'wrap' and a single line that doesn't fit: Advance to the
* first character to be displayed.
*/
- if (wp->w_p_wrap)
+ if (wp->w_p_wrap) {
v = wp->w_skipcol;
- else
+ } else {
v = wp->w_leftcol;
+ }
if (v > 0 && !number_only) {
- char_u *prev_ptr = ptr;
+ char_u *prev_ptr = ptr;
while (vcol < v && *ptr != NUL) {
c = win_lbr_chartabsize(wp, line, ptr, (colnr_T)vcol, NULL);
vcol += c;
@@ -2508,10 +2550,11 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
* Adjust for when the inverted text is before the screen,
* and when the start of the inverted text is before the screen.
*/
- if (tocol <= vcol)
+ if (tocol <= vcol) {
fromcol = 0;
- else if (fromcol >= 0 && fromcol < vcol)
+ } else if (fromcol >= 0 && fromcol < vcol) {
fromcol = vcol;
+ }
// When w_skipcol is non-zero, first line needs 'showbreak'
if (wp->w_p_wrap) {
@@ -2527,10 +2570,10 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
pos = wp->w_cursor;
wp->w_cursor.lnum = lnum;
wp->w_cursor.col = linecol;
- len = spell_move_to(wp, FORWARD, TRUE, TRUE, &spell_hlf);
+ len = spell_move_to(wp, FORWARD, true, true, &spell_hlf);
- /* spell_move_to() may call ml_get() and make "line" invalid */
- line = ml_get_buf(wp->w_buffer, lnum, FALSE);
+ // spell_move_to() may call ml_get() and make "line" invalid
+ line = ml_get_buf(wp->w_buffer, lnum, false);
ptr = line + linecol;
if (len == 0 || (int)wp->w_cursor.col > ptr - line) {
@@ -2539,13 +2582,14 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
spell_hlf = HLF_COUNT;
word_end = (int)(spell_to_word_end(ptr, wp) - line + 1);
} else {
- /* bad word found, use attributes until end of word */
+ // bad word found, use attributes until end of word
assert(len <= INT_MAX);
word_end = wp->w_cursor.col + (int)len + 1;
- /* Turn index into actual attributes. */
- if (spell_hlf != HLF_COUNT)
+ // Turn index into actual attributes.
+ if (spell_hlf != HLF_COUNT) {
spell_attr = highlight_attr[spell_hlf];
+ }
}
wp->w_cursor = pos;
@@ -2567,12 +2611,14 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
* cursor */
fromcol_prev = fromcol;
fromcol = -1;
- } else if ((colnr_T)fromcol < wp->w_virtcol)
- /* restart highlighting after the cursor */
+ } else if ((colnr_T)fromcol < wp->w_virtcol) {
+ // restart highlighting after the cursor
fromcol_prev = wp->w_virtcol;
+ }
}
- if (fromcol >= tocol)
+ if (fromcol >= tocol) {
fromcol = -1;
+ }
}
/*
@@ -2582,8 +2628,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
cur = wp->w_match_head;
shl_flag = false;
while ((cur != NULL || !shl_flag) && !number_only
- && !has_fold
- ) {
+ && !has_fold && !end_fill) {
if (!shl_flag) {
shl = &search_hl;
shl_flag = true;
@@ -2594,7 +2639,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
shl->endcol = MAXCOL;
shl->attr_cur = 0;
shl->is_addpos = false;
- v = (long)(ptr - line);
+ v = (ptr - line);
if (cur != NULL) {
cur->pos.cur = 0;
}
@@ -2616,18 +2661,18 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
shl->startcol = 0;
}
if (lnum == shl->lnum + shl->rm.endpos[0].lnum
- - shl->rm.startpos[0].lnum) {
- shl->endcol = shl->rm.endpos[0].col;
+ - shl->rm.startpos[0].lnum) {
+ shl->endcol = shl->rm.endpos[0].col;
} else {
- shl->endcol = MAXCOL;
+ shl->endcol = MAXCOL;
}
// Highlight one character for an empty match.
if (shl->startcol == shl->endcol) {
- if (line[shl->endcol] != NUL) {
- shl->endcol += (*mb_ptr2len)(line + shl->endcol);
- } else {
- ++shl->endcol;
- }
+ if (line[shl->endcol] != NUL) {
+ shl->endcol += (*mb_ptr2len)(line + shl->endcol);
+ } else {
+ ++shl->endcol;
+ }
}
if ((long)shl->startcol < v) { // match at leftcol
shl->attr_cur = shl->attr;
@@ -2636,8 +2681,9 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
}
area_highlighting = true;
}
- if (shl != &search_hl && cur != NULL)
+ if (shl != &search_hl && cur != NULL) {
cur = cur->next;
+ }
}
unsigned off = 0; // Offset relative start of line
@@ -2650,7 +2696,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
off += col;
}
- // wont highlight after TERM_ATTRS_MAX columns
+ // won't highlight after TERM_ATTRS_MAX columns
int term_attrs[TERM_ATTRS_MAX] = { 0 };
if (wp->w_buffer->terminal) {
terminal_get_line_attributes(wp->w_buffer->terminal, wp, lnum, term_attrs);
@@ -2665,10 +2711,16 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
// Skip this quickly when working on the text.
if (draw_state != WL_LINE) {
+ if (cul_screenline) {
+ cul_attr = 0;
+ line_attr = line_attr_save;
+ line_attr_lowprio = line_attr_lowprio_save;
+ }
+
if (draw_state == WL_CMDLINE - 1 && n_extra == 0) {
draw_state = WL_CMDLINE;
if (cmdwin_type != 0 && wp == curwin) {
- /* Draw the cmdline character. */
+ // Draw the cmdline character.
n_extra = 1;
c_extra = cmdwin_type;
c_final = NUL;
@@ -2696,18 +2748,17 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
// sign column, this is hit until sign_idx reaches count
if (draw_state == WL_SIGN - 1 && n_extra == 0) {
- draw_state = WL_SIGN;
- /* Show the sign column when there are any signs in this
- * buffer or when using Netbeans. */
- int count = win_signcol_count(wp);
- if (count > 0) {
- get_sign_display_info(
- false, wp, sattrs, row,
- startrow, filler_lines, filler_todo, count,
- &c_extra, &c_final, extra, sizeof(extra),
- &p_extra, &n_extra,
- &char_attr, &draw_state, &sign_idx);
- }
+ draw_state = WL_SIGN;
+ /* Show the sign column when there are any signs in this
+ * buffer or when using Netbeans. */
+ int count = win_signcol_count(wp);
+ if (count > 0) {
+ get_sign_display_info(false, wp, sattrs, row,
+ startrow, filler_lines, filler_todo, count,
+ &c_extra, &c_final, extra, sizeof(extra),
+ &p_extra, &n_extra,
+ &char_attr, &draw_state, &sign_idx);
+ }
}
if (draw_state == WL_NR - 1 && n_extra == 0) {
@@ -2723,12 +2774,11 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
if (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u'
&& num_signs > 0) {
int count = win_signcol_count(wp);
- get_sign_display_info(
- true, wp, sattrs, row,
- startrow, filler_lines, filler_todo, count,
- &c_extra, &c_final, extra, sizeof(extra),
- &p_extra, &n_extra,
- &char_attr, &draw_state, &sign_idx);
+ get_sign_display_info(true, wp, sattrs, row,
+ startrow, filler_lines, filler_todo, count,
+ &c_extra, &c_final, extra, sizeof(extra),
+ &p_extra, &n_extra,
+ &char_attr, &draw_state, &sign_idx);
} else {
if (row == startrow + filler_lines) {
// Draw the line number (empty space after wrapping). */
@@ -2775,15 +2825,29 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
n_extra = number_width(wp) + 1;
char_attr = win_hl_attr(wp, HLF_N);
+ if (wp->w_p_rnu && lnum < wp->w_cursor.lnum) {
+ // Use LineNrAbove
+ char_attr = win_hl_attr(wp, HLF_LNA);
+ }
+ if (wp->w_p_rnu && lnum > wp->w_cursor.lnum) {
+ // Use LineNrBelow
+ char_attr = win_hl_attr(wp, HLF_LNB);
+ }
+
sign_attrs_T *num_sattr = sign_get_attr(SIGN_NUMHL, sattrs, 0, 1);
if (num_sattr != NULL) {
// :sign defined with "numhl" highlight.
char_attr = num_sattr->sat_numhl;
- } else if ((wp->w_p_cul || wp->w_p_rnu)
+ } else if (wp->w_p_cul
&& lnum == wp->w_cursor.lnum
+ && (wp->w_p_culopt_flags & CULOPT_NBR)
+ && (row == startrow
+ || wp->w_p_culopt_flags & CULOPT_LINE)
&& filler_todo == 0) {
// When 'cursorline' is set highlight the line number of
// the current line differently.
+ // When 'cursorlineopt' has "screenline" only highlight
+ // the line number itself.
// TODO(vim): Can we use CursorLine instead of CursorLineNr
// when CursorLineNr isn't set?
char_attr = win_hl_attr(wp, HLF_CLN);
@@ -2797,7 +2861,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
}
if (wp->w_briopt_sbr && draw_state == WL_BRI - 1
- && n_extra == 0 && *p_sbr != NUL) {
+ && n_extra == 0 && *get_showbreak_value(wp) != NUL) {
// draw indent after showbreak value
draw_state = WL_BRI;
} else if (wp->w_briopt_sbr && draw_state == WL_SBR && n_extra == 0) {
@@ -2815,9 +2879,6 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
if (diff_hlf != (hlf_T)0) {
char_attr = win_hl_attr(wp, diff_hlf);
- if (wp->w_p_cul && lnum == wp->w_cursor.lnum) {
- char_attr = hl_combine_attr(char_attr, win_hl_attr(wp, HLF_CUL));
- }
}
p_extra = NULL;
c_extra = ' ';
@@ -2843,7 +2904,18 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
if (draw_state == WL_SBR - 1 && n_extra == 0) {
draw_state = WL_SBR;
- if (filler_todo > 0) {
+ if (filler_todo > filler_lines - virtual_lines) {
+ // TODO(bfredl): check this doesn't inhibit TUI-style
+ // clear-to-end-of-line.
+ c_extra = ' ';
+ c_final = NUL;
+ if (wp->w_p_rl) {
+ n_extra = col + 1;
+ } else {
+ n_extra = grid->Columns - col;
+ }
+ char_attr = 0;
+ } else if (filler_todo > 0) {
// draw "deleted" diff line(s)
if (char2cells(wp->w_p_fcs_chars.diff) > 1) {
c_extra = '-';
@@ -2859,24 +2931,26 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
}
char_attr = win_hl_attr(wp, HLF_DED);
}
- if (*p_sbr != NUL && need_showbreak) {
- /* Draw 'showbreak' at the start of each broken line. */
- p_extra = p_sbr;
+ char_u *const sbr = get_showbreak_value(wp);
+ if (*sbr != NUL && need_showbreak) {
+ // Draw 'showbreak' at the start of each broken line.
+ p_extra = sbr;
c_extra = NUL;
c_final = NUL;
- n_extra = (int)STRLEN(p_sbr);
+ n_extra = (int)STRLEN(sbr);
char_attr = win_hl_attr(wp, HLF_AT);
if (wp->w_skipcol == 0 || !wp->w_p_wrap) {
need_showbreak = false;
}
- vcol_sbr = vcol + MB_CHARLEN(p_sbr);
- /* Correct end of highlighted area for 'showbreak',
- * required when 'linebreak' is also set. */
- if (tocol == vcol)
+ vcol_sbr = vcol + MB_CHARLEN(sbr);
+ // Correct end of highlighted area for 'showbreak',
+ // required when 'linebreak' is also set.
+ if (tocol == vcol) {
tocol += n_extra;
+ }
// Combine 'showbreak' with 'cursorline', prioritizing 'showbreak'.
- if (wp->w_p_cul && lnum == wp->w_cursor.lnum) {
- char_attr = hl_combine_attr(win_hl_attr(wp, HLF_CUL), char_attr);
+ if (cul_attr) {
+ char_attr = hl_combine_attr(cul_attr, char_attr);
}
}
}
@@ -2891,7 +2965,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
}
if (saved_n_extra) {
- /* Continue item from end of wrapped line. */
+ // Continue item from end of wrapped line.
n_extra = saved_n_extra;
c_extra = saved_c_extra;
c_final = saved_c_final;
@@ -2903,6 +2977,23 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
}
}
+ if (cul_screenline && draw_state == WL_LINE
+ && vcol >= left_curline_col
+ && vcol < right_curline_col) {
+ cul_attr = win_hl_attr(wp, HLF_CUL);
+ HlAttrs ae = syn_attr2entry(cul_attr);
+ if (ae.rgb_fg_color == -1 && ae.cterm_fg_color == 0) {
+ line_attr_lowprio = cul_attr;
+ } else {
+ if (!(State & INSERT) && bt_quickfix(wp->w_buffer)
+ && qf_current_entry(wp) == lnum) {
+ line_attr = hl_combine_attr(cul_attr, line_attr);
+ } else {
+ line_attr = cul_attr;
+ }
+ }
+ }
+
// When still displaying '$' of change command, stop at cursor
if (((dollar_vcol >= 0
&& wp == curwin
@@ -2928,20 +3019,20 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
&& vcol == 0
&& n_extra == 0
&& row == startrow) {
- char_attr = win_hl_attr(wp, HLF_FL);
+ char_attr = win_hl_attr(wp, HLF_FL);
- linenr_T lnume = lnum + foldinfo.fi_lines - 1;
- memset(buf_fold, ' ', FOLD_TEXT_LEN);
- p_extra = get_foldtext(wp, lnum, lnume, foldinfo, buf_fold);
- n_extra = STRLEN(p_extra);
+ linenr_T lnume = lnum + foldinfo.fi_lines - 1;
+ memset(buf_fold, ' ', FOLD_TEXT_LEN);
+ p_extra = get_foldtext(wp, lnum, lnume, foldinfo, buf_fold);
+ n_extra = STRLEN(p_extra);
- if (p_extra != buf_fold) {
- xfree(p_extra_free);
- p_extra_free = p_extra;
- }
- c_extra = NUL;
- c_final = NUL;
- p_extra[n_extra] = NUL;
+ if (p_extra != buf_fold) {
+ xfree(p_extra_free);
+ p_extra_free = p_extra;
+ }
+ c_extra = NUL;
+ c_final = NUL;
+ p_extra[n_extra] = NUL;
}
if (draw_state == WL_LINE
@@ -2982,7 +3073,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
&& (colnr_T)vcol == wp->w_virtcol))) {
area_attr = 0; // stop highlighting
area_active = false;
- }
+ }
if (!n_extra) {
/*
@@ -2993,7 +3084,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
* Do this for 'search_hl' and the match list (ordered by
* priority).
*/
- v = (long)(ptr - line);
+ v = (ptr - line);
cur = wp->w_match_head;
shl_flag = false;
while (cur != NULL || !shl_flag) {
@@ -3007,10 +3098,10 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
if (cur != NULL) {
cur->pos.cur = 0;
}
- bool pos_inprogress = true; // mark that a position match search is
- // in progress
+ bool pos_inprogress = true; // mark that a position match search is
+ // in progress
while (shl->rm.regprog != NULL
- || (cur != NULL && pos_inprogress)) {
+ || (cur != NULL && pos_inprogress)) {
if (shl->startcol != MAXCOL
&& v >= (long)shl->startcol
&& v < (long)shl->endcol) {
@@ -3037,17 +3128,18 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
shl == &search_hl ? NULL : cur);
pos_inprogress = !(cur == NULL || cur->pos.cur == 0);
- /* Need to get the line again, a multi-line regexp
- * may have made it invalid. */
- line = ml_get_buf(wp->w_buffer, lnum, FALSE);
+ // Need to get the line again, a multi-line regexp
+ // may have made it invalid.
+ line = ml_get_buf(wp->w_buffer, lnum, false);
ptr = line + v;
if (shl->lnum == lnum) {
shl->startcol = shl->rm.startpos[0].col;
- if (shl->rm.endpos[0].lnum == 0)
+ if (shl->rm.endpos[0].lnum == 0) {
shl->endcol = shl->rm.endpos[0].col;
- else
+ } else {
shl->endcol = MAXCOL;
+ }
if (shl->startcol == shl->endcol) {
// highlight empty match, try again after it
@@ -3061,8 +3153,9 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
}
break;
}
- if (shl != &search_hl && cur != NULL)
+ if (shl != &search_hl && cur != NULL) {
cur = cur->next;
+ }
}
/* Use attributes from match with highest priority among
@@ -3083,8 +3176,9 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
search_attr = shl->attr_cur;
search_attr_from_match = shl != &search_hl;
}
- if (shl != &search_hl && cur != NULL)
+ if (shl != &search_hl && cur != NULL) {
cur = cur->next;
+ }
}
// Only highlight one character after the last column.
if (*ptr == NUL
@@ -3110,12 +3204,11 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
}
line_attr = win_hl_attr(wp, diff_hlf);
// Overlay CursorLine onto diff-mode highlight.
- if (wp->w_p_cul && lnum == wp->w_cursor.lnum) {
+ if (cul_attr) {
line_attr = 0 != line_attr_lowprio // Low-priority CursorLine
- ? hl_combine_attr(hl_combine_attr(win_hl_attr(wp, HLF_CUL),
- line_attr),
+ ? hl_combine_attr(hl_combine_attr(cul_attr, line_attr),
hl_get_underline())
- : hl_combine_attr(line_attr, win_hl_attr(wp, HLF_CUL));
+ : hl_combine_attr(line_attr, cul_attr);
}
}
@@ -3191,6 +3284,12 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
(void)mb_l;
multi_attr = win_hl_attr(wp, HLF_AT);
+ if (cul_attr) {
+ multi_attr = 0 != line_attr_lowprio
+ ? hl_combine_attr(cul_attr, multi_attr)
+ : hl_combine_attr(multi_attr, cul_attr);
+ }
+
// put the pointer back to output the double-width
// character at the start of the next line.
n_extra++;
@@ -3329,7 +3428,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
/* Get syntax attribute, unless still at the start of the line
* (double-wide char that doesn't fit). */
- v = (long)(ptr - line);
+ v = (ptr - line);
if (has_syntax && v > 0) {
/* Get the syntax attribute for the character. If there
* is an error, disable syntax highlighting. */
@@ -3342,16 +3441,23 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
if (did_emsg) {
wp->w_s->b_syn_error = TRUE;
has_syntax = FALSE;
- } else
+ } else {
did_emsg = save_did_emsg;
+ }
- /* Need to get the line again, a multi-line regexp may
- * have made it invalid. */
- line = ml_get_buf(wp->w_buffer, lnum, FALSE);
+ // Need to get the line again, a multi-line regexp may
+ // have made it invalid.
+ line = ml_get_buf(wp->w_buffer, lnum, false);
ptr = line + v;
if (!attr_pri) {
- char_attr = syntax_attr;
+ if (cul_attr) {
+ char_attr = 0 != line_attr_lowprio
+ ? hl_combine_attr(cul_attr, syntax_attr)
+ : hl_combine_attr(syntax_attr, cul_attr);
+ } else {
+ char_attr = syntax_attr;
+ }
} else {
char_attr = hl_combine_attr(syntax_attr, char_attr);
}
@@ -3370,7 +3476,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
* Only do this when there is no syntax highlighting, the
* @Spell cluster is not used or the current syntax item
* contains the @Spell cluster. */
- v = (long)(ptr - line);
+ v = (ptr - line);
if (has_spell && v >= word_end && v > cur_checked_col) {
spell_attr = 0;
if (!attr_pri) {
@@ -3417,9 +3523,10 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
checked_col = (int)((p - nextline) + len - nextline_idx);
}
- /* Turn index into actual attributes. */
- if (spell_hlf != HLF_COUNT)
+ // Turn index into actual attributes.
+ if (spell_hlf != HLF_COUNT) {
spell_attr = highlight_attr[spell_hlf];
+ }
if (cap_col > 0) {
if (p != prev_ptr
@@ -3429,17 +3536,19 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
capcol_lnum = lnum + 1;
cap_col = (int)((p - nextline) + cap_col
- nextline_idx);
- } else
- /* Compute the actual column. */
+ } else {
+ // Compute the actual column.
cap_col += (int)(prev_ptr - line);
+ }
}
}
}
if (spell_attr != 0) {
- if (!attr_pri)
+ if (!attr_pri) {
char_attr = hl_combine_attr(char_attr, spell_attr);
- else
+ } else {
char_attr = hl_combine_attr(spell_attr, char_attr);
+ }
}
if (wp->w_buffer->terminal) {
@@ -3467,6 +3576,16 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
char_u *p = ptr - (mb_off + 1);
// TODO: is passing p for start of the line OK?
n_extra = win_lbr_chartabsize(wp, line, p, (colnr_T)vcol, NULL) - 1;
+
+ // We have just drawn the showbreak value, no need to add
+ // space for it again.
+ if (vcol == vcol_sbr) {
+ n_extra -= MB_CHARLEN(get_showbreak_value(wp));
+ if (n_extra < 0) {
+ n_extra = 0;
+ }
+ }
+
if (c == TAB && n_extra + col > grid->Columns) {
n_extra = tabstop_padding(vcol, wp->w_buffer->b_p_ts,
wp->w_buffer->b_p_vts_array) - 1;
@@ -3474,24 +3593,44 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
c_extra = mb_off > 0 ? MB_FILLER_CHAR : ' ';
c_final = NUL;
if (ascii_iswhite(c)) {
- if (c == TAB)
- /* See "Tab alignment" below. */
+ if (c == TAB) {
+ // See "Tab alignment" below.
FIX_FOR_BOGUSCOLS;
+ }
if (!wp->w_p_list) {
c = ' ';
}
}
}
- // 'list': change char 160 to 'nbsp' and space to 'space'.
+ in_multispace = c == ' ' && ((ptr > line + 1 && ptr[-2] == ' ') || *ptr == ' ');
+ if (!in_multispace) {
+ multispace_pos = 0;
+ }
+
+ // 'list': Change char 160 to 'nbsp' and space to 'space'.
+ // But not when the character is followed by a composing
+ // character (use mb_l to check that).
if (wp->w_p_list
- && (((c == 160
- || (mb_utf8 && (mb_c == 160 || mb_c == 0x202f)))
- && curwin->w_p_lcs_chars.nbsp)
- || (c == ' ' && curwin->w_p_lcs_chars.space
+ && ((((c == 160 && mb_l == 1)
+ || (mb_utf8
+ && ((mb_c == 160 && mb_l == 2)
+ || (mb_c == 0x202f && mb_l == 3))))
+ && wp->w_p_lcs_chars.nbsp)
+ || (c == ' '
+ && mb_l == 1
+ && (wp->w_p_lcs_chars.space
+ || (in_multispace && wp->w_p_lcs_chars.multispace != NULL))
&& ptr - line >= leadcol
&& ptr - line <= trailcol))) {
- c = (c == ' ') ? wp->w_p_lcs_chars.space : wp->w_p_lcs_chars.nbsp;
+ if (in_multispace && wp->w_p_lcs_chars.multispace != NULL) {
+ c = wp->w_p_lcs_chars.multispace[multispace_pos++];
+ if (wp->w_p_lcs_chars.multispace[multispace_pos] == NUL) {
+ multispace_pos = 0;
+ }
+ } else {
+ c = (c == ' ') ? wp->w_p_lcs_chars.space : wp->w_p_lcs_chars.nbsp;
+ }
n_attr = 1;
extra_attr = win_hl_attr(wp, HLF_0);
saved_attr2 = char_attr; // save current attr
@@ -3532,10 +3671,12 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
if (c == TAB && (!wp->w_p_list || wp->w_p_lcs_chars.tab1)) {
int tab_len = 0;
long vcol_adjusted = vcol; // removed showbreak length
+ char_u *const sbr = get_showbreak_value(wp);
+
// Only adjust the tab_len, when at the first column after the
// showbreak value was drawn.
- if (*p_sbr != NUL && vcol == vcol_sbr && wp->w_p_wrap) {
- vcol_adjusted = vcol - MB_CHARLEN(p_sbr);
+ if (*sbr != NUL && vcol == vcol_sbr && wp->w_p_wrap) {
+ vcol_adjusted = vcol - MB_CHARLEN(sbr);
}
// tab amount depends on current column
tab_len = tabstop_padding(vcol_adjusted,
@@ -3546,8 +3687,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
n_extra = tab_len;
} else {
char_u *p;
- int i;
- int saved_nextra = n_extra;
+ int i;
+ int saved_nextra = n_extra;
if (vcol_off > 0) {
// there are characters to conceal
@@ -3623,7 +3764,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
? wp->w_p_lcs_chars.tab3
: wp->w_p_lcs_chars.tab1;
if (wp->w_p_lbr) {
- c_extra = NUL; /* using p_extra from above */
+ c_extra = NUL; // using p_extra from above
} else {
c_extra = wp->w_p_lcs_chars.tab2;
}
@@ -3689,10 +3830,11 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
} else if (c != NUL) {
p_extra = transchar_buf(wp->w_buffer, c);
if (n_extra == 0) {
- n_extra = byte2cells(c) - 1;
+ n_extra = byte2cells(c) - 1;
+ }
+ if ((dy_flags & DY_UHEX) && wp->w_p_rl) {
+ rl_mirror(p_extra); // reverse "<12>"
}
- if ((dy_flags & DY_UHEX) && wp->w_p_rl)
- rl_mirror(p_extra); /* reverse "<12>" */
c_extra = NUL;
c_final = NUL;
if (wp->w_p_lbr) {
@@ -3750,8 +3892,9 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
prev_syntax_id = syntax_seqnr;
- if (n_extra > 0)
+ if (n_extra > 0) {
vcol_off += n_extra;
+ }
vcol += n_extra;
if (wp->w_p_wrap && n_extra > 0) {
if (wp->w_p_rl) {
@@ -3765,7 +3908,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
n_extra = 0;
n_attr = 0;
} else if (n_skip == 0) {
- is_concealing = TRUE;
+ is_concealing = true;
n_skip = 1;
}
mb_c = c;
@@ -3778,7 +3921,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
}
} else {
prev_syntax_id = 0;
- is_concealing = FALSE;
+ is_concealing = false;
}
if (n_skip > 0 && did_decrement_ptr) {
@@ -3843,7 +3986,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
// At end of the text line or just after the last character.
if (c == NUL && eol_hl_off == 0) {
- long prevcol = (long)(ptr - line) - 1;
+ long prevcol = (ptr - line) - 1;
// we're not really at that column when skipping some text
if ((long)(wp->w_p_wrap ? wp->w_skipcol : wp->w_leftcol) > prevcol) {
@@ -3877,8 +4020,9 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
int n = 0;
if (wp->w_p_rl) {
- if (col < 0)
+ if (col < 0) {
n = 1;
+ }
} else {
if (col >= grid->Columns) {
n = -1;
@@ -3918,8 +4062,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
}
int eol_attr = char_attr;
- if (wp->w_p_cul && lnum == wp->w_cursor.lnum) {
- eol_attr = hl_combine_attr(win_hl_attr(wp, HLF_CUL), eol_attr);
+ if (cul_attr) {
+ eol_attr = hl_combine_attr(cul_attr, eol_attr);
}
linebuf_attr[off] = eol_attr;
if (wp->w_p_rl) {
@@ -3939,30 +4083,28 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
v = wp->w_leftcol;
}
- /* check if line ends before left margin */
- if (vcol < v + col - win_col_off(wp))
+ // check if line ends before left margin
+ if (vcol < v + col - win_col_off(wp)) {
vcol = v + col - win_col_off(wp);
+ }
// Get rid of the boguscols now, we want to draw until the right
// edge for 'cursorcolumn'.
col -= boguscols;
// boguscols = 0; // Disabled because value never read after this
- if (draw_color_col)
+ if (draw_color_col) {
draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
+ }
- VirtText virt_text = KV_INITIAL_VALUE;
- bool has_aligned = false;
- if (err_text) {
- int hl_err = syn_check_group((char_u *)S_LEN("ErrorMsg"));
- kv_push(virt_text, ((VirtTextChunk){ .text = err_text,
- .hl_id = hl_err }));
- do_virttext = true;
- } else if (has_decor) {
- virt_text = decor_redraw_eol(wp->w_buffer, &decor_state, &line_attr,
- &has_aligned);
- if (kv_size(virt_text)) {
- do_virttext = true;
- }
+ bool has_virttext = false;
+ // Make sure alignment is the same regardless
+ // if listchars=eol:X is used or not.
+ int eol_skip = (wp->w_p_lcs_chars.eol == lcs_eol_one && eol_hl_off == 0
+ ? 1 : 0);
+
+ if (has_decor) {
+ has_virttext = decor_redraw_eol(wp->w_buffer, &decor_state, &line_attr,
+ col + eol_skip);
}
if (((wp->w_p_cuc
@@ -3971,20 +4113,10 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
grid->Columns * (row - startrow + 1) + v
&& lnum != wp->w_cursor.lnum)
|| draw_color_col || line_attr_lowprio || line_attr
- || diff_hlf != (hlf_T)0 || do_virttext
- || has_aligned)) {
+ || diff_hlf != (hlf_T)0 || has_virttext)) {
int rightmost_vcol = 0;
int i;
- size_t virt_pos = 0;
- LineState s = LINE_STATE("");
- int virt_attr = 0;
-
- // Make sure alignment is the same regardless
- // if listchars=eol:X is used or not.
- bool delay_virttext = wp->w_p_lcs_chars.eol == lcs_eol_one
- && eol_hl_off == 0;
-
if (wp->w_p_cuc) {
rightmost_vcol = wp->w_virtcol;
}
@@ -4010,37 +4142,15 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
}
int base_attr = hl_combine_attr(line_attr_lowprio, diff_attr);
- if (base_attr || line_attr || has_aligned) {
+ if (base_attr || line_attr || has_virttext) {
rightmost_vcol = INT_MAX;
}
int col_stride = wp->w_p_rl ? -1 : 1;
while (wp->w_p_rl ? col >= 0 : col < grid->Columns) {
- int cells = -1;
- if (do_virttext && !delay_virttext) {
- if (*s.p == NUL) {
- if (virt_pos < virt_text.size) {
- s.p = kv_A(virt_text, virt_pos).text;
- int hl_id = kv_A(virt_text, virt_pos).hl_id;
- virt_attr = hl_id > 0 ? syn_id2attr(hl_id) : 0;
- virt_pos++;
- } else {
- do_virttext = false;
- }
- }
- if (*s.p != NUL) {
- cells = line_putchar(&s, &linebuf_char[off], grid->Columns - col,
- false);
- }
- }
- delay_virttext = false;
-
- if (cells == -1) {
- schar_from_ascii(linebuf_char[off], ' ');
- cells = 1;
- }
- col += cells * col_stride;
+ schar_from_ascii(linebuf_char[off], ' ');
+ col += col_stride;
if (draw_color_col) {
draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
}
@@ -4053,24 +4163,16 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
col_attr = mc_attr;
}
- if (do_virttext) {
- col_attr = hl_combine_attr(col_attr, virt_attr);
- }
-
col_attr = hl_combine_attr(col_attr, line_attr);
linebuf_attr[off] = col_attr;
- if (cells == 2) {
- linebuf_attr[off+1] = col_attr;
- }
- off += cells * col_stride;
+ off += col_stride;
- if (VCOL_HLC >= rightmost_vcol && *s.p == NUL
- && virt_pos >= virt_text.size) {
+ if (VCOL_HLC >= rightmost_vcol) {
break;
}
- vcol += cells;
+ vcol += 1;
}
}
@@ -4095,7 +4197,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
/*
* Update w_cline_height and w_cline_folded if the cursor line was
- * updated (saves a call to plines() later).
+ * updated (saves a call to plines_win() later).
*/
if (wp == curwin && lnum == curwin->w_cursor.lnum) {
curwin->w_cline_row = startrow;
@@ -4203,7 +4305,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
tocol++;
}
if (wp->w_p_rl) {
- /* now it's time to backup one cell */
+ // now it's time to backup one cell
--off;
--col;
}
@@ -4218,8 +4320,9 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
} else if (wp->w_p_cole > 0 && is_concealing) {
--n_skip;
++vcol_off;
- if (n_extra > 0)
+ if (n_extra > 0) {
vcol_off += n_extra;
+ }
if (wp->w_p_wrap) {
/*
* Special voodoo required if 'wrap' is on.
@@ -4273,27 +4376,30 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
n_attr = 0;
}
}
-
- } else
+ } else {
--n_skip;
+ }
/* Only advance the "vcol" when after the 'number' or 'relativenumber'
* column. */
if (draw_state > WL_NR
- && filler_todo <= 0
- )
+ && filler_todo <= 0) {
++vcol;
+ }
- if (vcol_save_attr >= 0)
+ if (vcol_save_attr >= 0) {
char_attr = vcol_save_attr;
+ }
- /* restore attributes after "predeces" in 'listchars' */
- if (draw_state > WL_NR && n_attr3 > 0 && --n_attr3 == 0)
+ // restore attributes after "predeces" in 'listchars'
+ if (draw_state > WL_NR && n_attr3 > 0 && --n_attr3 == 0) {
char_attr = saved_attr3;
+ }
- /* restore attributes after last 'listchars' or 'number' char */
- if (n_attr > 0 && draw_state == WL_LINE && --n_attr == 0)
+ // restore attributes after last 'listchars' or 'number' char
+ if (n_attr > 0 && draw_state == WL_LINE && --n_attr == 0) {
char_attr = saved_attr2;
+ }
/*
* At end of screen line and there is more to come: Display the line
@@ -4305,18 +4411,30 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
|| filler_todo > 0
|| (wp->w_p_list && wp->w_p_lcs_chars.eol != NUL
&& p_extra != at_end_str)
- || (n_extra != 0 && (c_extra != NUL || *p_extra != NUL)))
- ) {
+ || (n_extra != 0 &&
+ (c_extra != NUL || *p_extra != NUL)))) {
bool wrap = wp->w_p_wrap // Wrapping enabled.
- && 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,
- || ui_has(kUIMultigrid)) // or has dedicated grid.
- && !wp->w_p_rl; // Not right-to-left.
+ && 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,
+ || ui_has(kUIMultigrid)) // or has dedicated grid.
+ && !wp->w_p_rl; // Not right-to-left.
int draw_col = col - boguscols;
- draw_virt_text(buf, win_col_offset, &draw_col, grid->Columns);
+ if (filler_todo > 0) {
+ int index = filler_todo - (filler_lines - virtual_lines);
+ if (index > 0) {
+ int fpos = kv_size(buf->b_virt_lines) - index;
+ assert(fpos >= 0);
+ int offset = buf->b_virt_line_leftcol ? 0 : win_col_offset;
+ draw_virt_text_item(buf, offset, kv_A(buf->b_virt_lines, fpos),
+ kHlModeReplace, grid->Columns, offset);
+ }
+ } else {
+ draw_virt_text(buf, win_col_offset, &draw_col, grid->Columns);
+ }
+
grid_put_linebuf(grid, row, 0, draw_col, grid->Columns, wp->w_p_rl,
wp, wp->w_hl_attr_normal, wrap);
if (wrap) {
@@ -4338,8 +4456,9 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
* '$' and highlighting until last column, break here. */
if ((!wp->w_p_wrap
&& filler_todo <= 0
- ) || lcs_eol_one == -1)
+ ) || lcs_eol_one == -1) {
break;
+ }
// When the window is too narrow draw all "@" lines.
if (draw_state != WL_LINE && filler_todo <= 0) {
@@ -4347,7 +4466,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
row = endrow;
}
- /* When line got too long for screen break here. */
+ // When line got too long for screen break here.
if (row == endrow) {
++row;
break;
@@ -4360,7 +4479,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
off += col;
}
- /* reset the drawing state for the start of a wrapped line */
+ // reset the drawing state for the start of a wrapped line
draw_state = WL_START;
saved_n_extra = n_extra;
saved_p_extra = p_extra;
@@ -4375,21 +4494,19 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
filler_todo--;
// When the filler lines are actually below the last line of the
// file, don't draw the line itself, break here.
- if (filler_todo == 0 && wp->w_botfill) {
+ if (filler_todo == 0 && (wp->w_botfill || end_fill)) {
break;
}
}
+ } // for every character in the line
- } /* for every character in the line */
-
- /* After an empty line check first word for capital. */
+ // After an empty line check first word for capital.
if (*skipwhite(line) == NUL) {
capcol_lnum = lnum + 1;
cap_col = 0;
}
xfree(p_extra_free);
- xfree(err_text);
return row;
}
@@ -4397,60 +4514,83 @@ void draw_virt_text(buf_T *buf, int col_off, int *end_col, int max_col)
{
DecorState *state = &decor_state;
int right_pos = max_col;
+ bool do_eol = state->eol_col > -1;
for (size_t i = 0; i < kv_size(state->active); i++) {
DecorRange *item = &kv_A(state->active, i);
- if (item->start_row == state->row && kv_size(item->decor.virt_text)) {
- if (item->win_col == -1) {
- if (item->decor.virt_text_pos == kVTRightAlign) {
- right_pos -= item->decor.col;
- item->win_col = right_pos;
- } else if (item->decor.virt_text_pos == kVTWinCol) {
- item->win_col = MAX(item->decor.col+col_off, 0);
- }
- }
- if (item->win_col < 0) {
- continue;
- }
- VirtText vt = item->decor.virt_text;
- HlMode hl_mode = item->decor.hl_mode;
- LineState s = LINE_STATE("");
- int virt_attr = 0;
- int col = item->win_col;
- size_t virt_pos = 0;
- item->win_col = -2; // deactivate
-
- while (col < max_col) {
- if (!*s.p) {
- if (virt_pos == kv_size(vt)) {
- break;
- }
- s.p = kv_A(vt, virt_pos).text;
- int hl_id = kv_A(vt, virt_pos).hl_id;
- virt_attr = hl_id > 0 ? syn_id2attr(hl_id) : 0;
- virt_pos++;
- continue;
- }
- int attr;
- bool through = false;
- if (hl_mode == kHlModeCombine) {
- attr = hl_combine_attr(linebuf_attr[col], virt_attr);
- } else if (hl_mode == kHlModeBlend) {
- through = (*s.p == ' ');
- attr = hl_blend_attrs(linebuf_attr[col], virt_attr, &through);
- } else {
- attr = virt_attr;
- }
- schar_T dummy[2];
- int cells = line_putchar(&s, through ? dummy : &linebuf_char[col],
- max_col-col, false);
- linebuf_attr[col++] = attr;
- if (cells > 1) {
- linebuf_attr[col++] = attr;
- }
+ if (!(item->start_row == state->row && kv_size(item->decor.virt_text))) {
+ continue;
+ }
+ if (item->win_col == -1) {
+ if (item->decor.virt_text_pos == kVTRightAlign) {
+ right_pos -= item->decor.virt_text_width;
+ item->win_col = right_pos;
+ } else if (item->decor.virt_text_pos == kVTEndOfLine && do_eol) {
+ item->win_col = state->eol_col;
+ } else if (item->decor.virt_text_pos == kVTWinCol) {
+ item->win_col = MAX(item->decor.col+col_off, 0);
+ }
+ }
+ if (item->win_col < 0) {
+ continue;
+ }
+
+ int col = draw_virt_text_item(buf, item->win_col, item->decor.virt_text,
+ item->decor.hl_mode, max_col, item->win_col-col_off);
+ item->win_col = -2; // deactivate
+ if (item->decor.virt_text_pos == kVTEndOfLine && do_eol) {
+ state->eol_col = col+1;
+ }
+
+ *end_col = MAX(*end_col, col);
+ }
+}
+
+static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode,
+ int max_col, int vcol)
+{
+ LineState s = LINE_STATE("");
+ int virt_attr = 0;
+ size_t virt_pos = 0;
+
+ while (col < max_col) {
+ if (!*s.p) {
+ if (virt_pos >= kv_size(vt)) {
+ break;
}
- *end_col = MAX(*end_col, col);
+ virt_attr = 0;
+ do {
+ s.p = kv_A(vt, virt_pos).text;
+ int hl_id = kv_A(vt, virt_pos).hl_id;
+ virt_attr = hl_combine_attr(virt_attr,
+ hl_id > 0 ? syn_id2attr(hl_id) : 0);
+ virt_pos++;
+ } while (!s.p && virt_pos < kv_size(vt));
+ if (!s.p) {
+ break;
+ }
+ }
+ int attr;
+ bool through = false;
+ if (hl_mode == kHlModeCombine) {
+ attr = hl_combine_attr(linebuf_attr[col], virt_attr);
+ } else if (hl_mode == kHlModeBlend) {
+ through = (*s.p == ' ');
+ attr = hl_blend_attrs(linebuf_attr[col], virt_attr, &through);
+ } else {
+ attr = virt_attr;
}
+ schar_T dummy[2];
+ int cells = line_putchar(buf, &s, through ? dummy : &linebuf_char[col],
+ max_col-col, false, vcol);
+ // if we failed to emit a char, we still need to advance
+ cells = MAX(cells, 1);
+
+ for (int c = 0; c < cells; c++) {
+ linebuf_attr[col++] = attr;
+ }
+ vcol += cells;
}
+ return col;
}
/// Determine if dedicated window grid should be used or the default_grid
@@ -4479,25 +4619,11 @@ void screen_adjust_grid(ScreenGrid **grid, int *row_off, int *col_off)
// @param count max number of signs
// @param[out] n_extrap number of characters from pp_extra to display
// @param[in, out] sign_idxp Index of the displayed sign
-static void get_sign_display_info(
- bool nrcol,
- win_T *wp,
- sign_attrs_T sattrs[],
- int row,
- int startrow,
- int filler_lines,
- int filler_todo,
- int count,
- int *c_extrap,
- int *c_finalp,
- char_u *extra,
- size_t extra_size,
- char_u **pp_extra,
- int *n_extrap,
- int *char_attrp,
- int *draw_statep,
- int *sign_idxp
-)
+static void get_sign_display_info(bool nrcol, win_T *wp, sign_attrs_T sattrs[], int row,
+ int startrow, int filler_lines, int filler_todo, int count,
+ int *c_extrap, int *c_finalp, char_u *extra, size_t extra_size,
+ char_u **pp_extra, int *n_extrap, int *char_attrp,
+ int *draw_statep, int *sign_idxp)
{
// Draw cells with the sign value or blank.
*c_extrap = ' ';
@@ -4535,7 +4661,7 @@ static void get_sign_display_info(
assert((size_t)win_signcol_width(wp) >= mb_string2cells(*pp_extra));
// symbol(s) bytes + (filling spaces) (one byte each)
*n_extrap = symbol_blen +
- (win_signcol_width(wp) - mb_string2cells(*pp_extra));
+ (win_signcol_width(wp) - mb_string2cells(*pp_extra));
assert(extra_size > (size_t)symbol_blen);
memset(extra, ' ', extra_size);
@@ -4565,8 +4691,7 @@ static void get_sign_display_info(
* - the character is multi-byte and the next byte is different
* - the character is two cells wide and the second cell differs.
*/
-static int grid_char_needs_redraw(ScreenGrid *grid, int off_from, int off_to,
- int cols)
+static int grid_char_needs_redraw(ScreenGrid *grid, int off_from, int off_to, int cols)
{
return (cols > 0
&& ((schar_cmp(linebuf_char[off_from], grid->chars[off_to])
@@ -4588,9 +4713,8 @@ static int grid_char_needs_redraw(ScreenGrid *grid, int off_from, int off_to,
/// When FALSE and "clear_width" > 0, clear columns "endcol" to "clear_width"
/// If "wrap" is true, then hint to the UI that "row" contains a line
/// which has wrapped into the next row.
-static void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol,
- int clear_width, int rlflag, win_T *wp,
- int bg_attr, bool wrap)
+static void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol, int clear_width,
+ int rlflag, win_T *wp, int bg_attr, bool wrap)
{
unsigned off_from;
unsigned off_to;
@@ -4627,12 +4751,11 @@ static void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol,
max_off_to = grid->line_offset[row] + grid->Columns;
if (rlflag) {
- /* Clear rest first, because it's left of the text. */
+ // Clear rest first, because it's left of the text.
if (clear_width > 0) {
while (col <= endcol && grid->chars[off_to][0] == ' '
&& grid->chars[off_to][1] == NUL
- && grid->attrs[off_to] == bg_attr
- ) {
+ && grid->attrs[off_to] == bg_attr) {
++off_to;
++col;
}
@@ -4758,7 +4881,7 @@ static void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol,
*/
void rl_mirror(char_u *str)
{
- char_u *p1, *p2;
+ char_u *p1, *p2;
int t;
for (p1 = str, p2 = str + STRLEN(str) - 1; p1 < p2; ++p1, --p2) {
@@ -4773,7 +4896,6 @@ void rl_mirror(char_u *str)
*/
void status_redraw_all(void)
{
-
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->w_status_height) {
wp->w_redr_status = true;
@@ -4809,8 +4931,9 @@ void redraw_statuslines(void)
win_redr_status(wp);
}
}
- if (redraw_tabline)
+ if (redraw_tabline) {
draw_tabline();
+ }
}
/*
@@ -4862,9 +4985,10 @@ static int status_match_len(expand_T *xp, char_u *s)
int emenu = (xp->xp_context == EXPAND_MENUS
|| xp->xp_context == EXPAND_MENUNAMES);
- /* Check for menu separators - replace with '|'. */
- if (emenu && menu_is_separator(s))
+ // Check for menu separators - replace with '|'.
+ if (emenu && menu_is_separator(s)) {
return 1;
+ }
while (*s != NUL) {
s += skip_status_match_char(xp, s);
@@ -4884,78 +5008,76 @@ static int skip_status_match_char(expand_T *xp, char_u *s)
if ((rem_backslash(s) && xp->xp_context != EXPAND_HELP)
|| ((xp->xp_context == EXPAND_MENUS
|| xp->xp_context == EXPAND_MENUNAMES)
- && (s[0] == '\t' || (s[0] == '\\' && s[1] != NUL)))
- ) {
+ && (s[0] == '\t' ||
+ (s[0] == '\\' && s[1] != NUL)))) {
#ifndef BACKSLASH_IN_FILENAME
- if (xp->xp_shell && csh_like_shell() && s[1] == '\\' && s[2] == '!')
+ if (xp->xp_shell && csh_like_shell() && s[1] == '\\' && s[2] == '!') {
return 2;
+ }
#endif
return 1;
}
return 0;
}
-/*
- * Show wildchar matches in the status line.
- * Show at least the "match" item.
- * We start at item 'first_match' in the list and show all matches that fit.
- *
- * If inversion is possible we use it. Else '=' characters are used.
- */
-void
-win_redr_status_matches (
- expand_T *xp,
- int num_matches,
- char_u **matches, /* list of matches */
- int match,
- int showtail
-)
+/// Show wildchar matches in the status line.
+/// Show at least the "match" item.
+/// We start at item 'first_match' in the list and show all matches that fit.
+///
+/// If inversion is possible we use it. Else '=' characters are used.
+///
+/// @param matches list of matches
+void win_redr_status_matches(expand_T *xp, int num_matches, char_u **matches, int match,
+ int showtail)
{
#define L_MATCH(m) (showtail ? sm_gettail(matches[m], false) : matches[m])
int row;
- char_u *buf;
+ char_u *buf;
int len;
- int clen; /* length in screen cells */
+ int clen; // length in screen cells
int fillchar;
int attr;
int i;
- int highlight = TRUE;
- char_u *selstart = NULL;
+ bool highlight = true;
+ char_u *selstart = NULL;
int selstart_col = 0;
- char_u *selend = NULL;
+ char_u *selend = NULL;
static int first_match = 0;
- int add_left = FALSE;
- char_u *s;
+ bool add_left = false;
+ char_u *s;
int emenu;
int l;
- if (matches == NULL) /* interrupted completion? */
+ if (matches == NULL) { // interrupted completion?
return;
+ }
buf = xmalloc(Columns * MB_MAXBYTES + 1);
- if (match == -1) { /* don't show match but original text */
+ if (match == -1) { // don't show match but original text
match = 0;
- highlight = FALSE;
+ highlight = false;
}
- /* count 1 for the ending ">" */
+ // count 1 for the ending ">"
clen = status_match_len(xp, L_MATCH(match)) + 3;
- if (match == 0)
+ if (match == 0) {
first_match = 0;
- else if (match < first_match) {
- /* jumping left, as far as we can go */
+ } else if (match < first_match) {
+ // jumping left, as far as we can go
first_match = match;
- add_left = TRUE;
+ add_left = true;
} else {
- /* check if match fits on the screen */
- for (i = first_match; i < match; ++i)
+ // check if match fits on the screen
+ for (i = first_match; i < match; ++i) {
clen += status_match_len(xp, L_MATCH(i)) + 2;
- if (first_match > 0)
+ }
+ if (first_match > 0) {
clen += 2;
+ }
// jumping right, put match at the left
if ((long)clen > Columns) {
first_match = match;
- /* if showing the last match, we can add some on the left */
+ // if showing the last match, we can add some on the left
clen = 2;
for (i = match; i < num_matches; ++i) {
clen += status_match_len(xp, L_MATCH(i)) + 2;
@@ -4963,11 +5085,12 @@ win_redr_status_matches (
break;
}
}
- if (i == num_matches)
- add_left = TRUE;
+ if (i == num_matches) {
+ add_left = true;
+ }
}
}
- if (add_left)
+ if (add_left) {
while (first_match > 0) {
clen += status_match_len(xp, L_MATCH(first_match - 1)) + 2;
if ((long)clen >= Columns) {
@@ -4975,6 +5098,7 @@ win_redr_status_matches (
}
first_match--;
}
+ }
fillchar = fillchar_status(&attr, curwin);
@@ -4995,7 +5119,7 @@ win_redr_status_matches (
}
s = L_MATCH(i);
- /* Check for menu separators - replace with '|' */
+ // Check for menu separators - replace with '|'
emenu = (xp->xp_context == EXPAND_MENUS
|| xp->xp_context == EXPAND_MENUNAMES);
if (emenu && menu_is_separator(s)) {
@@ -5003,7 +5127,7 @@ win_redr_status_matches (
l = (int)STRLEN(buf + len);
len += l;
clen += l;
- } else
+ } else {
for (; *s != NUL; ++s) {
s += skip_status_match_char(xp, s);
clen += ptr2cells(s);
@@ -5016,14 +5140,17 @@ win_redr_status_matches (
len += (int)STRLEN(buf + len);
}
}
- if (i == match)
+ }
+ if (i == match) {
selend = buf + len;
+ }
*(buf + len++) = ' ';
*(buf + len++) = ' ';
clen += 2;
- if (++i == num_matches)
+ if (++i == num_matches) {
break;
+ }
}
if (i != num_matches) {
@@ -5056,7 +5183,7 @@ win_redr_status_matches (
save_p_wmh = p_wmh;
p_ls = 2;
p_wmh = 0;
- last_status(FALSE);
+ last_status(false);
}
wild_menu_showing = WM_SHOWN;
}
@@ -5087,7 +5214,7 @@ win_redr_status_matches (
static void win_redr_status(win_T *wp)
{
int row;
- char_u *p;
+ char_u *p;
int len;
int fillchar;
int attr;
@@ -5112,7 +5239,7 @@ static void win_redr_status(win_T *wp)
// popup menu is visible and may be drawn over it
wp->w_redr_status = true;
} else if (*p_stl != NUL || *wp->w_p_stl != NUL) {
- /* redraw custom status line */
+ // redraw custom status line
redraw_custom_statusline(wp);
} else {
fillchar = fillchar_status(&attr, wp);
@@ -5177,11 +5304,12 @@ static void win_redr_status(win_T *wp)
this_ru_col + wp->w_wincol, fillchar, fillchar, attr);
if (get_keymap_str(wp, (char_u *)"<%s>", NameBuff, MAXPATHL)
- && this_ru_col - len > (int)(STRLEN(NameBuff) + 1))
+ && this_ru_col - len > (int)(STRLEN(NameBuff) + 1)) {
grid_puts(&default_grid, NameBuff, row,
(int)(this_ru_col - STRLEN(NameBuff) - 1), attr);
+ }
- win_redr_ruler(wp, TRUE);
+ win_redr_ruler(wp, true);
}
/*
@@ -5204,14 +5332,15 @@ static void win_redr_status(win_T *wp)
*/
static void redraw_custom_statusline(win_T *wp)
{
- static int entered = false;
+ static bool entered = false;
int saved_did_emsg = did_emsg;
/* When called recursively return. This can happen when the statusline
* contains an expression that triggers a redraw. */
- if (entered)
+ if (entered) {
return;
- entered = TRUE;
+ }
+ entered = true;
did_emsg = false;
win_redr_custom(wp, false);
@@ -5227,57 +5356,55 @@ static void redraw_custom_statusline(win_T *wp)
entered = false;
}
-/*
- * Return TRUE if the status line of window "wp" is connected to the status
- * line of the window right of it. If not, then it's a vertical separator.
- * Only call if (wp->w_vsep_width != 0).
- */
-int stl_connected(win_T *wp)
+/// Only call if (wp->w_vsep_width != 0).
+///
+/// @return true if the status line of window "wp" is connected to the status
+/// line of the window right of it. If not, then it's a vertical separator.
+bool stl_connected(win_T *wp)
{
- frame_T *fr;
+ frame_T *fr;
fr = wp->w_frame;
while (fr->fr_parent != NULL) {
if (fr->fr_parent->fr_layout == FR_COL) {
- if (fr->fr_next != NULL)
+ if (fr->fr_next != NULL) {
break;
+ }
} else {
- if (fr->fr_next != NULL)
- return TRUE;
+ if (fr->fr_next != NULL) {
+ return true;
+ }
}
fr = fr->fr_parent;
}
- return FALSE;
+ return false;
}
-/*
- * Get the value to show for the language mappings, active 'keymap'.
- */
-int
-get_keymap_str (
- win_T *wp,
- char_u *fmt, // format string containing one %s item
- char_u *buf, // buffer for the result
- int len // length of buffer
-)
+/// Get the value to show for the language mappings, active 'keymap'.
+///
+/// @param fmt format string containing one %s item
+/// @param buf buffer for the result
+/// @param len length of buffer
+bool get_keymap_str(win_T *wp, char_u *fmt, char_u *buf, int len)
{
- char_u *p;
+ char_u *p;
- if (wp->w_buffer->b_p_iminsert != B_IMODE_LMAP)
- return FALSE;
+ if (wp->w_buffer->b_p_iminsert != B_IMODE_LMAP) {
+ return false;
+ }
{
- buf_T *old_curbuf = curbuf;
- win_T *old_curwin = curwin;
- char_u *s;
+ buf_T *old_curbuf = curbuf;
+ win_T *old_curwin = curwin;
+ char_u *s;
curbuf = wp->w_buffer;
curwin = wp;
- STRCPY(buf, "b:keymap_name"); /* must be writable */
- ++emsg_skip;
- s = p = eval_to_string(buf, NULL, FALSE);
- --emsg_skip;
+ STRCPY(buf, "b:keymap_name"); // must be writable
+ emsg_skip++;
+ s = p = eval_to_string(buf, NULL, false);
+ emsg_skip--;
curbuf = old_curbuf;
curwin = old_curwin;
if (p == NULL || *p == NUL) {
@@ -5299,13 +5426,9 @@ get_keymap_str (
* 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
-)
+static void win_redr_custom(win_T *wp, bool draw_ruler)
{
- static int entered = FALSE;
+ static bool entered = false;
int attr;
int curattr;
int row;
@@ -5316,12 +5439,12 @@ win_redr_custom (
int len;
int fillchar;
char_u buf[MAXPATHL];
- char_u *stl;
- char_u *p;
+ char_u *stl;
+ char_u *p;
stl_hlrec_t *hltab;
StlClickRecord *tabtab;
int use_sandbox = false;
- win_T *ewp;
+ win_T *ewp;
int p_crb_save;
ScreenGrid *grid = &default_grid;
@@ -5329,13 +5452,14 @@ win_redr_custom (
/* There is a tiny chance that this gets called recursively: When
* redrawing a status line triggers redrawing the ruler or tabline.
* Avoid trouble by not allowing recursion. */
- if (entered)
+ if (entered) {
return;
- entered = TRUE;
+ }
+ entered = true;
- /* setup environment for the task at hand */
+ // setup environment for the task at hand
if (wp == NULL) {
- /* Use 'tabline'. Always at the first line of the screen. */
+ // Use 'tabline'. Always at the first line of the screen.
stl = p_tal;
row = 0;
fillchar = ' ';
@@ -5349,15 +5473,19 @@ win_redr_custom (
if (draw_ruler) {
stl = p_ruf;
- /* advance past any leading group spec - implicit in ru_col */
+ // advance past any leading group spec - implicit in ru_col
if (*stl == '%') {
- if (*++stl == '-')
+ if (*++stl == '-') {
stl++;
- if (atoi((char *)stl))
- while (ascii_isdigit(*stl))
+ }
+ if (atoi((char *)stl)) {
+ while (ascii_isdigit(*stl)) {
stl++;
- if (*stl++ != '(')
+ }
+ }
+ if (*stl++ != '(') {
stl = p_ruf;
+ }
}
col = ru_col - (Columns - wp->w_width);
if (col < (wp->w_width + 1) / 2) {
@@ -5374,19 +5502,21 @@ win_redr_custom (
use_sandbox = was_set_insecurely(wp, (char_u *)"rulerformat", 0);
} else {
- if (*wp->w_p_stl != NUL)
+ if (*wp->w_p_stl != NUL) {
stl = wp->w_p_stl;
- else
+ } else {
stl = p_stl;
- use_sandbox = was_set_insecurely(
- wp, (char_u *)"statusline", *wp->w_p_stl == NUL ? 0 : OPT_LOCAL);
+ }
+ use_sandbox = was_set_insecurely(wp, (char_u *)"statusline",
+ *wp->w_p_stl == NUL ? 0 : OPT_LOCAL);
}
col += wp->w_wincol;
}
- if (maxwidth <= 0)
+ if (maxwidth <= 0) {
goto theend;
+ }
/* Temporarily reset 'cursorbind', we don't want a side effect from moving
* the cursor away and back. */
@@ -5404,12 +5534,12 @@ win_redr_custom (
ewp->w_p_crb = p_crb_save;
// Make all characters printable.
- p = (char_u *)transstr((const char *)buf);
+ p = (char_u *)transstr((const char *)buf, true);
len = STRLCPY(buf, p, sizeof(buf));
len = (size_t)len < sizeof(buf) ? len : (int)sizeof(buf) - 1;
xfree(p);
- /* fill up with "fillchar" */
+ // fill up with "fillchar"
while (width < maxwidth && len < (int)sizeof(buf) - 1) {
len += utf_char2bytes(fillchar, buf + len);
width++;
@@ -5429,14 +5559,15 @@ win_redr_custom (
col += vim_strnsize(p, textlen);
p = hltab[n].start;
- if (hltab[n].userhl == 0)
+ if (hltab[n].userhl == 0) {
curattr = attr;
- else if (hltab[n].userhl < 0)
+ } else if (hltab[n].userhl < 0) {
curattr = syn_id2attr(-hltab[n].userhl);
- else if (wp != NULL && wp != curwin && wp->w_status_height != 0)
+ } else if (wp != NULL && wp != curwin && wp->w_status_height != 0) {
curattr = highlight_stlnc[hltab[n].userhl - 1];
- else
+ } else {
curattr = highlight_user[hltab[n].userhl - 1];
+ }
}
// Make sure to use an empty string instead of p, if p is beyond buf + len.
grid_puts(grid, p >= buf + len ? (char_u *)"" : p, row, col,
@@ -5453,11 +5584,11 @@ win_redr_custom (
.type = kStlClickDisabled,
};
for (n = 0; tabtab[n].start != NULL; n++) {
- len += vim_strnsize(p, (int)(tabtab[n].start - (char *) p));
+ 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;
+ p = (char_u *)tabtab[n].start;
cur_click_def = tabtab[n].def;
}
while (col < Columns) {
@@ -5466,7 +5597,7 @@ win_redr_custom (
}
theend:
- entered = FALSE;
+ entered = false;
}
static void win_redr_border(win_T *wp)
@@ -5527,7 +5658,7 @@ static void win_redr_border(win_T *wp)
}
}
-// Low-level functions to manipulate invidual character cells on the
+// Low-level functions to manipulate individual character cells on the
// screen grid.
/// Put a ASCII character in a screen cell.
@@ -5621,8 +5752,7 @@ void grid_putchar(ScreenGrid *grid, int c, int row, int col, int attr)
/// get a single character directly from grid.chars into "bytes[]".
/// Also return its attribute in *attrp;
-void grid_getbytes(ScreenGrid *grid, int row, int col, char_u *bytes,
- int *attrp)
+void grid_getbytes(ScreenGrid *grid, int row, int col, char_u *bytes, int *attrp)
{
unsigned off;
@@ -5669,22 +5799,21 @@ void grid_put_schar(ScreenGrid *grid, int row, int col, char_u *schar, int attr)
assert(put_dirty_row == row);
unsigned int off = grid->line_offset[row] + col;
if (grid->attrs[off] != attr || schar_cmp(grid->chars[off], schar)) {
- schar_copy(grid->chars[off], schar);
- grid->attrs[off] = attr;
+ schar_copy(grid->chars[off], schar);
+ grid->attrs[off] = attr;
- put_dirty_first = MIN(put_dirty_first, col);
- // TODO(bfredl): Y U NO DOUBLEWIDTH?
- put_dirty_last = MAX(put_dirty_last, col+1);
+ put_dirty_first = MIN(put_dirty_first, col);
+ // TODO(bfredl): Y U NO DOUBLEWIDTH?
+ put_dirty_last = MAX(put_dirty_last, col+1);
}
}
/// like grid_puts(), but output "text[len]". When "len" is -1 output up to
/// a NUL.
-void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row,
- int col, int attr)
+void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row, int col, int attr)
{
unsigned off;
- char_u *ptr = text;
+ char_u *ptr = text;
int len = textlen;
int c;
unsigned max_off;
@@ -5693,7 +5822,7 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row,
int u8c = 0;
int u8cc[MAX_MCO];
int clear_next_cell = FALSE;
- int prev_c = 0; /* previous Arabic character */
+ int prev_c = 0; // previous Arabic character
int pc, nc, nc1;
int pcc[MAX_MCO];
int need_redraw;
@@ -5786,7 +5915,7 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row,
if (clear_next_cell) {
clear_next_cell = false;
} else if ((len < 0 ? ptr[mbyte_blen] == NUL
- : ptr + mbyte_blen >= text + len)
+ : ptr + mbyte_blen >= text + len)
&& ((mbyte_cells == 1
&& grid_off2cells(grid, off, max_off) > 1)
|| (mbyte_cells == 2
@@ -5885,10 +6014,11 @@ static void init_search_hl(win_T *wp)
matchitem_T *cur = wp->w_match_head;
while (cur != NULL) {
cur->hl.rm = cur->match;
- if (cur->hlg_id == 0)
+ if (cur->hlg_id == 0) {
cur->hl.attr = 0;
- else
+ } else {
cur->hl.attr = syn_id2attr(cur->hlg_id);
+ }
cur->hl.buf = wp->w_buffer;
cur->hl.lnum = 0;
cur->hl.first_lnum = 0;
@@ -5911,7 +6041,7 @@ static void prepare_search_hl(win_T *wp, linenr_T lnum)
FUNC_ATTR_NONNULL_ALL
{
matchitem_T *cur; // points to the match list
- match_T *shl; // points to search_hl or a match
+ match_T *shl; // points to search_hl or a match
bool shl_flag; // flag to indicate whether search_hl
// has been processed or not
@@ -5942,8 +6072,8 @@ static void prepare_search_hl(win_T *wp, linenr_T lnum)
if (cur != NULL) {
cur->pos.cur = 0;
}
- bool pos_inprogress = true; // mark that a position match search is
- // in progress
+ bool pos_inprogress = true; // mark that a position match search is
+ // in progress
int n = 0;
while (shl->first_lnum < lnum && (shl->rm.regprog != NULL
|| (cur != NULL && pos_inprogress))) {
@@ -5961,27 +6091,24 @@ static void prepare_search_hl(win_T *wp, linenr_T lnum)
}
}
}
- if (shl != &search_hl && cur != NULL)
+ if (shl != &search_hl && cur != NULL) {
cur = cur->next;
+ }
}
}
-/*
- * Search for a next 'hlsearch' or match.
- * Uses shl->buf.
- * Sets shl->lnum and shl->rm contents.
- * Note: Assumes a previous match is always before "lnum", unless
- * shl->lnum is zero.
- * Careful: Any pointers for buffer lines will become invalid.
- */
-static void
-next_search_hl (
- win_T *win,
- match_T *shl, /* points to search_hl or a match */
- linenr_T lnum,
- colnr_T mincol, /* minimal column for a match */
- matchitem_T *cur /* to retrieve match positions if any */
-)
+/// Search for a next 'hlsearch' or match.
+/// Uses shl->buf.
+/// Sets shl->lnum and shl->rm contents.
+/// Note: Assumes a previous match is always before "lnum", unless
+/// shl->lnum is zero.
+/// Careful: Any pointers for buffer lines will become invalid.
+///
+/// @param shl points to search_hl or a match
+/// @param mincol minimal column for a match
+/// @param cur to retrieve match positions if any
+static void next_search_hl(win_T *win, match_T *shl, linenr_T lnum, colnr_T mincol,
+ matchitem_T *cur)
FUNC_ATTR_NONNULL_ARG(2)
{
linenr_T l;
@@ -6001,10 +6128,11 @@ next_search_hl (
// 2. If the previous match includes "mincol", use it.
// 3. Continue after the previous match.
l = shl->lnum + shl->rm.endpos[0].lnum - shl->rm.startpos[0].lnum;
- if (lnum > l)
+ if (lnum > l) {
shl->lnum = 0;
- else if (lnum < l || shl->rm.endpos[0].col > mincol)
+ } else if (lnum < l || shl->rm.endpos[0].col > mincol) {
return;
+ }
}
/*
@@ -6015,7 +6143,7 @@ next_search_hl (
for (;; ) {
// Stop searching after passing the time limit.
if (profile_passed_limit(shl->tm)) {
- shl->lnum = 0; /* no match found in time */
+ shl->lnum = 0; // no match found in time
break;
}
// Three situations:
@@ -6028,10 +6156,10 @@ next_search_hl (
} else if (vim_strchr(p_cpo, CPO_SEARCH) == NULL
|| (shl->rm.endpos[0].lnum == 0
&& shl->rm.endpos[0].col <= shl->rm.startpos[0].col)) {
- char_u *ml;
+ char_u *ml;
matchcol = shl->rm.startpos[0].col;
- ml = ml_get_buf(shl->buf, lnum, FALSE) + matchcol;
+ ml = ml_get_buf(shl->buf, lnum, false) + matchcol;
if (*ml == NUL) {
++matchcol;
shl->lnum = 0;
@@ -6067,7 +6195,7 @@ next_search_hl (
}
shl->rm.regprog = NULL;
shl->lnum = 0;
- got_int = FALSE; // avoid the "Type :quit to exit Vim" message
+ got_int = FALSE; // avoid the "Type :quit to exit Vim" message
break;
}
} else if (cur != NULL) {
@@ -6090,15 +6218,12 @@ next_search_hl (
}
}
-/// If there is a match fill "shl" and return one.
-/// Return zero otherwise.
-static int
-next_search_hl_pos(
- match_T *shl, // points to a match
- linenr_T lnum,
- posmatch_T *posmatch, // match positions
- colnr_T mincol // minimal column for a match
-)
+/// @param shl points to a match. Fill on match.
+/// @param posmatch match positions
+/// @param mincol minimal column for a match
+///
+/// @return one on match, otherwise return zero.
+static int next_search_hl_pos(match_T *shl, linenr_T lnum, posmatch_T *posmatch, colnr_T mincol)
FUNC_ATTR_NONNULL_ALL
{
int i;
@@ -6152,8 +6277,8 @@ next_search_hl_pos(
/// Fill the grid from 'start_row' to 'end_row', from 'start_col' to 'end_col'
/// with character 'c1' in first column followed by 'c2' in the other columns.
/// Use attributes 'attr'.
-void grid_fill(ScreenGrid *grid, int start_row, int end_row, int start_col,
- int end_col, int c1, int c2, int attr)
+void grid_fill(ScreenGrid *grid, int start_row, int end_row, int start_col, int end_col, int c1,
+ int c2, int attr)
{
schar_T sc;
@@ -6243,11 +6368,9 @@ void grid_fill(ScreenGrid *grid, int start_row, int end_row, int start_col,
}
}
-/*
- * Check if there should be a delay. Used before clearing or redrawing the
- * screen or the command line.
- */
-void check_for_delay(int check_msg_scroll)
+/// 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)
{
if ((emsg_on_display || (check_msg_scroll && msg_scroll))
&& !did_wait_return
@@ -6391,9 +6514,9 @@ retry:
msg_grid_invalid = true;
}
- win_new_shellsize(); /* fit the windows in the new sized shell */
+ win_new_shellsize(); // fit the windows in the new sized shell
- comp_col(); /* recompute columns for shown command and ruler */
+ comp_col(); // recompute columns for shown command and ruler
// We're changing the size of the screen.
// - Allocate new arrays for default_grid
@@ -6406,8 +6529,8 @@ retry:
// size is wrong.
grid_alloc(&default_grid, Rows, Columns, true, true);
- StlClickDefinition *new_tab_page_click_defs = xcalloc(
- (size_t)Columns, sizeof(*new_tab_page_click_defs));
+ 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);
xfree(tab_page_click_defs);
@@ -6431,9 +6554,9 @@ retry:
* in case applying autocommands always changes Rows or Columns.
*/
if (starting == 0 && ++retry_count <= 3) {
- apply_autocmds(EVENT_VIMRESIZED, NULL, NULL, FALSE, curbuf);
- /* In rare cases, autocommands may have altered Rows or Columns,
- * jump back to check if we need to allocate the screen again. */
+ apply_autocmds(EVENT_VIMRESIZED, NULL, NULL, false, curbuf);
+ // In rare cases, autocommands may have altered Rows or Columns,
+ // jump back to check if we need to allocate the screen again.
goto retry;
}
@@ -6515,8 +6638,7 @@ void screen_free_all_mem(void)
///
/// @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 clear_tab_page_click_defs(StlClickDefinition *const tpcd, const long tpcd_size)
{
if (tpcd != NULL) {
for (long i = 0; i < tpcd_size; i++) {
@@ -6524,7 +6646,7 @@ void clear_tab_page_click_defs(StlClickDefinition *const tpcd,
xfree(tpcd[i].func);
}
}
- memset(tpcd, 0, (size_t) tpcd_size * sizeof(tpcd[0]));
+ memset(tpcd, 0, (size_t)tpcd_size * sizeof(tpcd[0]));
}
}
@@ -6542,7 +6664,7 @@ void screenclear(void)
// blank out the default grid
for (i = 0; i < default_grid.Rows; i++) {
grid_clear_line(&default_grid, default_grid.line_offset[i],
- (int)default_grid.Columns, true);
+ default_grid.Columns, true);
default_grid.line_wraps[i] = false;
}
@@ -6629,8 +6751,8 @@ void setcursor(void)
// With 'rightleft' set and the cursor on a double-wide character,
// position it on the leftmost column.
col = curwin->w_width_inner - curwin->w_wcol
- - ((utf_ptr2cells(get_cursor_pos_ptr()) == 2
- && vim_isprintc(gchar_cursor())) ? 2 : 1);
+ - ((utf_ptr2cells(get_cursor_pos_ptr()) == 2
+ && vim_isprintc(gchar_cursor())) ? 2 : 1);
}
screen_adjust_grid(&grid, &row, &col);
@@ -6679,8 +6801,7 @@ void win_scroll_lines(win_T *wp, int row, int line_count)
/// 'col' is the column from with we start inserting.
//
/// 'row', 'col' and 'end' are relative to the start of the region.
-void grid_ins_lines(ScreenGrid *grid, int row, int line_count, int end, int col,
- int width)
+void grid_ins_lines(ScreenGrid *grid, int row, int line_count, int end, int col, int width)
{
int i;
int j;
@@ -6716,7 +6837,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, (int)grid->Columns, false);
+ grid_clear_line(grid, temp, grid->Columns, false);
}
}
@@ -6731,8 +6852,7 @@ void grid_ins_lines(ScreenGrid *grid, int row, int line_count, int end, int col,
/// 'end' is the line after the scrolled part. Normally it is Rows.
/// When scrolling region used 'off' is the offset from the top for the region.
/// 'row' and 'end' are relative to the start of the region.
-void grid_del_lines(ScreenGrid *grid, int row, int line_count, int end, int col,
- int width)
+void grid_del_lines(ScreenGrid *grid, int row, int line_count, int end, int col, int width)
{
int j;
int i;
@@ -6769,7 +6889,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, (int)grid->Columns, false);
+ grid_clear_line(grid, temp, grid->Columns, false);
}
}
@@ -6783,8 +6903,8 @@ 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.
-// If clear_cmdline is FALSE there may be a message there that needs to be
+// If clear_cmdline is true, clear the rest of the cmdline.
+// If clear_cmdline is false there may be a message there that needs to be
// cleared only if a mode is shown.
// Return the length of the message (0 if no message).
int showmode(void)
@@ -6793,7 +6913,6 @@ int showmode(void)
int length = 0;
int do_mode;
int attr;
- int nwr_save;
int sub_attr;
if (ui_has(kUIMessages) && clear_cmdline) {
@@ -6815,26 +6934,26 @@ int showmode(void)
// Call char_avail() only when we are going to show something, because
// it takes a bit of time.
if (!redrawing() || (char_avail() && !KeyTyped) || msg_silent != 0) {
- redraw_cmdline = TRUE; /* show mode later */
+ redraw_cmdline = true; // show mode later
return 0;
}
- nwr_save = need_wait_return;
+ bool nwr_save = need_wait_return;
- /* wait a bit before overwriting an important message */
- check_for_delay(FALSE);
+ // wait a bit before overwriting an important message
+ check_for_delay(false);
- /* if the cmdline is more than one line high, erase top lines */
+ // if the cmdline is more than one line high, erase top lines
need_clear = clear_cmdline;
if (clear_cmdline && cmdline_row < Rows - 1) {
msg_clr_cmdline(); // will reset clear_cmdline
}
- /* Position on the last line in the window, column 0 */
+ // Position on the last line in the window, column 0
msg_pos_mode();
attr = HL_ATTR(HLF_CM); // Highlight mode
- // When the screen is too narrow to show the entire mode messsage,
+ // When the screen is too narrow to show the entire mode message,
// avoid scrolling and truncate instead.
msg_no_more = true;
int save_lines_left = lines_left;
@@ -6856,8 +6975,9 @@ int showmode(void)
length -= vim_strsize(edit_submode_extra);
}
if (length > 0) {
- if (edit_submode_pre != NULL)
+ if (edit_submode_pre != NULL) {
length -= vim_strsize(edit_submode_pre);
+ }
if (length - vim_strsize(edit_submode) > 0) {
if (edit_submode_pre != NULL) {
msg_puts_attr((const char *)edit_submode_pre, attr);
@@ -6866,7 +6986,7 @@ int showmode(void)
}
if (edit_submode_extra != NULL) {
MSG_PUTS_ATTR(" ", attr); // Add a space in between.
- if ((int)edit_submode_highl < (int)HLF_COUNT) {
+ if ((int)edit_submode_highl < HLF_COUNT) {
sub_attr = win_hl_attr(curwin, edit_submode_highl);
} else {
sub_attr = attr;
@@ -6877,13 +6997,14 @@ int showmode(void)
} else {
if (State & TERM_FOCUS) {
MSG_PUTS_ATTR(_(" TERMINAL"), attr);
- } else if (State & VREPLACE_FLAG)
+ } else if (State & VREPLACE_FLAG) {
MSG_PUTS_ATTR(_(" VREPLACE"), attr);
- else if (State & REPLACE_FLAG)
+ } else if (State & REPLACE_FLAG) {
MSG_PUTS_ATTR(_(" REPLACE"), attr);
- else if (State & INSERT) {
- if (p_ri)
+ } else if (State & INSERT) {
+ if (p_ri) {
MSG_PUTS_ATTR(_(" REVERSE"), attr);
+ }
MSG_PUTS_ATTR(_(" INSERT"), attr);
} else if (restart_edit == 'I' || restart_edit == 'i'
|| restart_edit == 'a') {
@@ -6904,8 +7025,9 @@ int showmode(void)
MSG_PUTS_ATTR(NameBuff, attr);
}
}
- if ((State & INSERT) && p_paste)
+ if ((State & INSERT) && p_paste) {
MSG_PUTS_ATTR(_(" (paste)"), attr);
+ }
if (VIsual_active) {
char *p;
@@ -6915,12 +7037,18 @@ int showmode(void)
switch ((VIsual_select ? 4 : 0)
+ (VIsual_mode == Ctrl_V) * 2
+ (VIsual_mode == 'V')) {
- case 0: p = N_(" VISUAL"); break;
- case 1: p = N_(" VISUAL LINE"); break;
- case 2: p = N_(" VISUAL BLOCK"); break;
- case 4: p = N_(" SELECT"); break;
- case 5: p = N_(" SELECT LINE"); break;
- default: p = N_(" SELECT BLOCK"); break;
+ case 0:
+ p = N_(" VISUAL"); break;
+ case 1:
+ p = N_(" VISUAL LINE"); break;
+ case 2:
+ p = N_(" VISUAL BLOCK"); break;
+ case 4:
+ p = N_(" SELECT"); break;
+ case 5:
+ p = N_(" SELECT LINE"); break;
+ default:
+ p = N_(" SELECT BLOCK"); break;
}
MSG_PUTS_ATTR(_(p), attr);
}
@@ -6936,10 +7064,11 @@ int showmode(void)
need_clear = true;
}
- mode_displayed = TRUE;
- if (need_clear || clear_cmdline)
+ mode_displayed = true;
+ if (need_clear || clear_cmdline) {
msg_clr_eos();
- msg_didout = FALSE; /* overwrite this message */
+ }
+ msg_didout = false; // overwrite this message
length = msg_col;
msg_col = 0;
msg_no_more = false;
@@ -6950,12 +7079,13 @@ int showmode(void)
msg_clr_cmdline();
}
- // NB: also handles clearing the showmode if it was emtpy or disabled
+ // NB: also handles clearing the showmode if it was empty or disabled
msg_ext_flush_showmode();
- /* In Visual mode the size of the selected area must be redrawn. */
- if (VIsual_active)
+ // In Visual mode the size of the selected area must be redrawn.
+ if (VIsual_active) {
clear_showcmd();
+ }
// If the last window has no status line, the ruler is after the mode
// message and must be redrawn
@@ -7029,15 +7159,15 @@ void draw_tabline(void)
int col = 0;
int scol = 0;
int attr;
- win_T *wp;
- win_T *cwp;
+ win_T *wp;
+ win_T *cwp;
int wincount;
int modified;
int c;
int len;
int attr_nosel = HL_ATTR(HLF_TP);
int attr_fill = HL_ATTR(HLF_TPF);
- char_u *p;
+ char_u *p;
int room;
int use_sep_chars = (t_colors < 8
);
@@ -7052,15 +7182,16 @@ void draw_tabline(void)
return;
}
- if (tabline_height() < 1)
+ if (tabline_height() < 1) {
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);
- /* Use the 'tabline' option if it's set. */
+ // Use the 'tabline' option if it's set.
if (*p_tal != NUL) {
int saved_did_emsg = did_emsg;
@@ -7146,7 +7277,7 @@ void draw_tabline(void)
room = scol - col + tabwidth - 1;
if (room > 0) {
- /* Get buffer name in NameBuff[] */
+ // Get buffer name in NameBuff[]
get_trans_bufname(cwp->w_buffer);
(void)shorten_dir(NameBuff);
len = vim_strsize(NameBuff);
@@ -7176,13 +7307,14 @@ void draw_tabline(void)
}
}
- if (use_sep_chars)
+ if (use_sep_chars) {
c = '_';
- else
+ } else {
c = ' ';
+ }
grid_fill(&default_grid, 0, 1, col, Columns, c, c, attr_fill);
- /* Put an "X" for closing the current tab if there are several. */
+ // Put an "X" for closing the current tab if there are several.
if (first_tabpage->tp_next != NULL) {
grid_putchar(&default_grid, 'X', 0, Columns - 1, attr_nosel);
tab_page_click_defs[Columns - 1] = (StlClickDefinition) {
@@ -7195,7 +7327,7 @@ void draw_tabline(void)
/* Reset the flag here again, in case evaluating 'tabline' causes it to be
* set. */
- redraw_tabline = FALSE;
+ redraw_tabline = false;
}
void ui_ext_tabline_update(void)
@@ -7237,10 +7369,11 @@ void ui_ext_tabline_update(void)
*/
void get_trans_bufname(buf_T *buf)
{
- if (buf_spname(buf) != NULL)
+ if (buf_spname(buf) != NULL) {
STRLCPY(NameBuff, buf_spname(buf), MAXPATHL);
- else
+ } else {
home_replace(buf, buf->b_fname, NameBuff, MAXPATHL, TRUE);
+ }
trans_characters(NameBuff, MAXPATHL);
}
@@ -7299,14 +7432,14 @@ int messaging(void)
return !(p_lz && char_avail() && !KeyTyped);
}
-/*
- * Show current status info in ruler and various other places
- * If always is FALSE, only show ruler if position has changed.
- */
-void showruler(int always)
+/// Show current status info in ruler and various other places
+///
+/// @param always if false, only show ruler if position has changed.
+void showruler(bool always)
{
- if (!always && !redrawing())
+ if (!always && !redrawing()) {
return;
+ }
if ((*p_stl != NUL || *curwin->w_p_stl != NUL) && curwin->w_status_height) {
redraw_custom_statusline(curwin);
} else {
@@ -7315,15 +7448,16 @@ void showruler(int always)
if (need_maketitle
|| (p_icon && (stl_syntax & STL_IN_ICON))
- || (p_title && (stl_syntax & STL_IN_TITLE))
- )
+ || (p_title && (stl_syntax & STL_IN_TITLE))) {
maketitle();
- /* Redraw the tab pages line if needed. */
- if (redraw_tabline)
+ }
+ // Redraw the tab pages line if needed.
+ if (redraw_tabline) {
draw_tabline();
+ }
}
-static void win_redr_ruler(win_T *wp, int always)
+static void win_redr_ruler(win_T *wp, bool always)
{
static bool did_show_ext_ruler = false;
@@ -7336,8 +7470,9 @@ static void win_redr_ruler(win_T *wp, int always)
* Check if cursor.lnum is valid, since win_redr_ruler() may be called
* after deleting lines, before cursor.lnum is corrected.
*/
- if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
+ if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count) {
return;
+ }
// Don't draw the ruler while doing insert-completion, it might overwrite
// the (long) mode message.
@@ -7365,24 +7500,24 @@ static void win_redr_ruler(win_T *wp, int always)
*/
int empty_line = FALSE;
if (!(State & INSERT)
- && *ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE) == NUL)
+ && *ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE) == NUL) {
empty_line = TRUE;
+ }
/*
* Only draw the ruler when something changed.
*/
validate_virtcol_win(wp);
- if ( redraw_cmdline
- || always
- || wp->w_cursor.lnum != wp->w_ru_cursor.lnum
- || wp->w_cursor.col != wp->w_ru_cursor.col
- || wp->w_virtcol != wp->w_ru_virtcol
- || wp->w_cursor.coladd != wp->w_ru_cursor.coladd
- || wp->w_topline != wp->w_ru_topline
- || wp->w_buffer->b_ml.ml_line_count != wp->w_ru_line_count
- || wp->w_topfill != wp->w_ru_topfill
- || empty_line != wp->w_ru_empty) {
-
+ if (redraw_cmdline
+ || always
+ || wp->w_cursor.lnum != wp->w_ru_cursor.lnum
+ || wp->w_cursor.col != wp->w_ru_cursor.col
+ || wp->w_virtcol != wp->w_ru_virtcol
+ || wp->w_cursor.coladd != wp->w_ru_cursor.coladd
+ || wp->w_topline != wp->w_ru_topline
+ || wp->w_buffer->b_ml.ml_line_count != wp->w_ru_line_count
+ || wp->w_topfill != wp->w_ru_topfill
+ || empty_line != wp->w_ru_empty) {
int width;
int row;
int fillchar;
@@ -7420,12 +7555,12 @@ static void win_redr_ruler(win_T *wp, int always)
* To avoid portability problems we use strlen() here.
*/
vim_snprintf((char *)buffer, RULER_BUF_LEN, "%" PRId64 ",",
- (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) ? (int64_t)0L
- : (int64_t)wp->w_cursor.lnum);
+ (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) ? (int64_t)0L
+ : (int64_t)wp->w_cursor.lnum);
size_t len = STRLEN(buffer);
col_print(buffer + len, RULER_BUF_LEN - len,
- empty_line ? 0 : (int)wp->w_cursor.col + 1,
- (int)virtcol + 1);
+ empty_line ? 0 : (int)wp->w_cursor.col + 1,
+ (int)virtcol + 1);
/*
* Add a "50%" if there is room for it.
@@ -7513,8 +7648,9 @@ int number_width(win_T *wp)
lnum = wp->w_buffer->b_ml.ml_line_count;
}
- if (lnum == wp->w_nrwidth_line_count)
+ if (lnum == wp->w_nrwidth_line_count) {
return wp->w_nrwidth_width;
+ }
wp->w_nrwidth_line_count = lnum;
n = 0;
@@ -7539,22 +7675,66 @@ int number_width(win_T *wp)
return n;
}
+/// Used when 'cursorlineopt' contains "screenline": compute the margins between
+/// which the highlighting is used.
+static void margin_columns_win(win_T *wp, int *left_col, int *right_col)
+{
+ // cache previous calculations depending on w_virtcol
+ static int saved_w_virtcol;
+ static win_T *prev_wp;
+ static int prev_left_col;
+ static int prev_right_col;
+ static int prev_col_off;
+
+ int cur_col_off = win_col_off(wp);
+ int width1;
+ int width2;
+
+ if (saved_w_virtcol == wp->w_virtcol && prev_wp == wp
+ && prev_col_off == cur_col_off) {
+ *right_col = prev_right_col;
+ *left_col = prev_left_col;
+ return;
+ }
+
+ width1 = wp->w_width - cur_col_off;
+ width2 = width1 + win_col_off2(wp);
+
+ *left_col = 0;
+ *right_col = width1;
+
+ if (wp->w_virtcol >= (colnr_T)width1) {
+ *right_col = width1 + ((wp->w_virtcol - width1) / width2 + 1) * width2;
+ }
+ if (wp->w_virtcol >= (colnr_T)width1 && width2 > 0) {
+ *left_col = (wp->w_virtcol - width1) / width2 * width2 + width1;
+ }
+
+ // cache values
+ prev_left_col = *left_col;
+ prev_right_col = *right_col;
+ prev_wp = wp;
+ saved_w_virtcol = wp->w_virtcol;
+ prev_col_off = cur_col_off;
+}
+
/// Set dimensions of the Nvim application "shell".
void screen_resize(int width, int height)
{
- static int busy = FALSE;
+ static bool recursive = false;
// Avoid recursiveness, can happen when setting the window size causes
// another window-changed signal.
- if (updating_screen || busy) {
+ if (updating_screen || recursive) {
return;
}
- if (width < 0 || height < 0) /* just checking... */
+ if (width < 0 || height < 0) { // just checking...
return;
+ }
if (State == HITRETURN || State == SETWSIZE) {
- /* postpone the resizing */
+ // postpone the resizing
State = SETWSIZE;
return;
}
@@ -7563,10 +7743,11 @@ void screen_resize(int width, int height)
* buffer has already been closed and removing a scrollbar causes a resize
* event. Don't resize then, it will happen after entering another buffer.
*/
- if (curwin->w_buffer == NULL)
+ if (curwin->w_buffer == NULL) {
return;
+ }
- ++busy;
+ recursive = true;
Rows = height;
Columns = width;
@@ -7585,7 +7766,7 @@ void screen_resize(int width, int height)
/* The window layout used to be adjusted here, but it now happens in
* screenalloc() (also invoked from screenclear()). That is because the
- * "busy" check above may skip this, but not screenalloc(). */
+ * "recursive" check above may skip this, but not screenalloc(). */
if (State != ASKMORE && State != EXTERNCMD && State != CONFIRM) {
screenclear();
@@ -7617,8 +7798,9 @@ void screen_resize(int width, int height)
ui_comp_set_screen_valid(true);
repeat_message();
} else {
- if (curwin->w_p_scb)
- do_check_scrollbind(TRUE);
+ if (curwin->w_p_scb) {
+ do_check_scrollbind(true);
+ }
if (State & CMDLINE) {
redraw_popupmenu = false;
update_screen(NOT_VALID);
@@ -7643,7 +7825,7 @@ void screen_resize(int width, int height)
}
ui_flush();
}
- busy--;
+ recursive = false;
}
/// Check if the new Nvim application "shell" dimensions are valid.
@@ -7701,4 +7883,3 @@ win_T *get_win_by_grid_handle(handle_T handle)
return NULL;
}
-
diff --git a/src/nvim/search.c b/src/nvim/search.c
index 82fc0f9d8e..3d30932d69 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -7,13 +7,11 @@
#include <assert.h>
#include <inttypes.h>
+#include <limits.h> // for INT_MAX on MSVC
#include <stdbool.h>
#include <string.h>
-#include <limits.h> /* for INT_MAX on MSVC */
#include "nvim/ascii.h"
-#include "nvim/vim.h"
-#include "nvim/search.h"
#include "nvim/buffer.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
@@ -34,17 +32,19 @@
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
-#include "nvim/move.h"
#include "nvim/mouse.h"
+#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/option.h"
+#include "nvim/os/time.h"
#include "nvim/path.h"
#include "nvim/regexp.h"
#include "nvim/screen.h"
+#include "nvim/search.h"
#include "nvim/strings.h"
#include "nvim/ui.h"
+#include "nvim/vim.h"
#include "nvim/window.h"
-#include "nvim/os/time.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "search.c.generated.h"
@@ -79,12 +79,12 @@
static struct spat spats[2] =
{
// Last used search pattern
- [0] = {NULL, true, false, 0, {'/', false, false, 0L}, NULL},
+ [0] = { NULL, true, false, 0, { '/', false, false, 0L }, NULL },
// Last used substitute pattern
- [1] = {NULL, true, false, 0, {'/', false, false, 0L}, NULL}
+ [1] = { NULL, true, false, 0, { '/', false, false, 0L }, NULL }
};
-static int last_idx = 0; /* index in spats[] for RE_LAST */
+static int last_idx = 0; // index in spats[] for RE_LAST
static char_u lastc[2] = { NUL, NUL }; // last character searched for
static Direction lastcdir = FORWARD; // last direction of character search
@@ -97,100 +97,100 @@ static struct spat saved_spats[2];
static int saved_spats_last_idx = 0;
static bool saved_spats_no_hlsearch = false;
-static char_u *mr_pattern = NULL; // pattern used by search_regcomp()
-static int mr_pattern_alloced = false; // mr_pattern was allocated
+static char_u *mr_pattern = NULL; // pattern used by search_regcomp()
+static bool mr_pattern_alloced = false; // mr_pattern was allocated
/*
* Type used by find_pattern_in_path() to remember which included files have
* been searched already.
*/
typedef struct SearchedFile {
- FILE *fp; /* File pointer */
- char_u *name; /* Full name of file */
- linenr_T lnum; /* Line we were up to in file */
- int matched; /* Found a match in this file */
+ FILE *fp; // File pointer
+ char_u *name; // Full name of file
+ linenr_T lnum; // Line we were up to in file
+ int matched; // Found a match in this file
} SearchedFile;
-/*
- * translate search pattern for vim_regcomp()
- *
- * pat_save == RE_SEARCH: save pat in spats[RE_SEARCH].pat (normal search cmd)
- * pat_save == RE_SUBST: save pat in spats[RE_SUBST].pat (:substitute command)
- * pat_save == RE_BOTH: save pat in both patterns (:global command)
- * pat_use == RE_SEARCH: use previous search pattern if "pat" is NULL
- * pat_use == RE_SUBST: use previous substitute pattern if "pat" is NULL
- * pat_use == RE_LAST: use last used pattern if "pat" is NULL
- * options & SEARCH_HIS: put search string in history
- * options & SEARCH_KEEP: keep previous search pattern
- *
- * returns FAIL if failed, OK otherwise.
- */
-int
-search_regcomp(
- char_u *pat,
- int pat_save,
- int pat_use,
- int options,
- regmmatch_T *regmatch /* return: pattern and ignore-case flag */
-)
+/// translate search pattern for vim_regcomp()
+///
+/// pat_save == RE_SEARCH: save pat in spats[RE_SEARCH].pat (normal search cmd)
+/// pat_save == RE_SUBST: save pat in spats[RE_SUBST].pat (:substitute command)
+/// pat_save == RE_BOTH: save pat in both patterns (:global command)
+/// pat_use == RE_SEARCH: use previous search pattern if "pat" is NULL
+/// pat_use == RE_SUBST: use previous substitute pattern if "pat" is NULL
+/// pat_use == RE_LAST: use last used pattern if "pat" is NULL
+/// options & SEARCH_HIS: put search string in history
+/// options & SEARCH_KEEP: keep previous search pattern
+///
+/// @param regmatch return: pattern and ignore-case flag
+///
+/// @return FAIL if failed, OK otherwise.
+int search_regcomp(char_u *pat, int pat_save, int pat_use, int options, regmmatch_T *regmatch)
{
int magic;
int i;
- rc_did_emsg = FALSE;
+ rc_did_emsg = false;
magic = p_magic;
/*
* If no pattern given, use a previously defined pattern.
*/
if (pat == NULL || *pat == NUL) {
- if (pat_use == RE_LAST)
+ if (pat_use == RE_LAST) {
i = last_idx;
- else
+ } else {
i = pat_use;
- if (spats[i].pat == NULL) { /* pattern was never defined */
- if (pat_use == RE_SUBST)
+ }
+ if (spats[i].pat == NULL) { // pattern was never defined
+ if (pat_use == RE_SUBST) {
EMSG(_(e_nopresub));
- else
+ } else {
EMSG(_(e_noprevre));
- rc_did_emsg = TRUE;
+ }
+ rc_did_emsg = true;
return FAIL;
}
pat = spats[i].pat;
magic = spats[i].magic;
no_smartcase = spats[i].no_scs;
- } else if (options & SEARCH_HIS) /* put new pattern in history */
- add_to_history(HIST_SEARCH, pat, TRUE, NUL);
+ } else if (options & SEARCH_HIS) { // put new pattern in history
+ add_to_history(HIST_SEARCH, pat, true, NUL);
+ }
if (mr_pattern_alloced) {
xfree(mr_pattern);
- mr_pattern_alloced = FALSE;
+ mr_pattern_alloced = false;
}
if (curwin->w_p_rl && *curwin->w_p_rlc == 's') {
mr_pattern = reverse_text(pat);
- mr_pattern_alloced = TRUE;
- } else
+ mr_pattern_alloced = true;
+ } else {
mr_pattern = pat;
+ }
/*
* Save the currently used pattern in the appropriate place,
* unless the pattern should not be remembered.
*/
if (!(options & SEARCH_KEEP) && !cmdmod.keeppatterns) {
- /* search or global command */
- if (pat_save == RE_SEARCH || pat_save == RE_BOTH)
+ // search or global command
+ if (pat_save == RE_SEARCH || pat_save == RE_BOTH) {
save_re_pat(RE_SEARCH, pat, magic);
- /* substitute or global command */
- if (pat_save == RE_SUBST || pat_save == RE_BOTH)
+ }
+ // substitute or global command
+ if (pat_save == RE_SUBST || pat_save == RE_BOTH) {
save_re_pat(RE_SUBST, pat, magic);
+ }
}
regmatch->rmm_ic = ignorecase(pat);
regmatch->rmm_maxcol = 0;
regmatch->regprog = vim_regcomp(pat, magic ? RE_MAGIC : 0);
- if (regmatch->regprog == NULL)
+ if (regmatch->regprog == NULL) {
return FAIL;
+ }
return OK;
}
@@ -237,9 +237,10 @@ void save_re_pat(int idx, char_u *pat, int magic)
spats[idx].timestamp = os_time();
spats[idx].additional_data = NULL;
last_idx = idx;
- /* If 'hlsearch' set and search pat changed: need redraw. */
- if (p_hls)
+ // If 'hlsearch' set and search pat changed: need redraw.
+ if (p_hls) {
redraw_all_later(SOME_VALID);
+ }
set_no_hlsearch(false);
}
}
@@ -254,11 +255,13 @@ void save_search_patterns(void)
{
if (save_level++ == 0) {
saved_spats[0] = spats[0];
- if (spats[0].pat != NULL)
+ if (spats[0].pat != NULL) {
saved_spats[0].pat = vim_strsave(spats[0].pat);
+ }
saved_spats[1] = spats[1];
- if (spats[1].pat != NULL)
+ if (spats[1].pat != NULL) {
saved_spats[1].pat = vim_strsave(spats[1].pat);
+ }
saved_spats_last_idx = last_idx;
saved_spats_no_hlsearch = no_hlsearch;
}
@@ -293,7 +296,7 @@ void free_search_patterns(void)
if (mr_pattern_alloced) {
xfree(mr_pattern);
- mr_pattern_alloced = FALSE;
+ mr_pattern_alloced = false;
mr_pattern = NULL;
}
}
@@ -367,8 +370,8 @@ int ignorecase_opt(char_u *pat, int ic_in, int scs)
{
int ic = ic_in;
if (ic && !no_smartcase && scs
- && !(ctrl_x_mode_not_default() && curbuf->b_p_inf)
- ) {
+ && !(ctrl_x_mode_not_default() &&
+ curbuf->b_p_inf)) {
ic = !pat_has_uppercase(pat);
}
no_smartcase = false;
@@ -429,10 +432,11 @@ void set_last_csearch(int c, char_u *s, int len)
{
*lastc = c;
lastc_bytelen = len;
- if (len)
+ if (len) {
memcpy(lastc_bytes, s, len);
- else
+ } else {
memset(lastc_bytes, 0, sizeof(lastc_bytes));
+ }
}
void set_csearch_direction(Direction cdir)
@@ -466,34 +470,38 @@ void reset_search_dir(void)
void set_last_search_pat(const char_u *s, int idx, int magic, int setlast)
{
free_spat(&spats[idx]);
- /* An empty string means that nothing should be matched. */
- if (*s == NUL)
+ // An empty string means that nothing should be matched.
+ if (*s == NUL) {
spats[idx].pat = NULL;
- else
- spats[idx].pat = (char_u *) xstrdup((char *) s);
+ } else {
+ spats[idx].pat = (char_u *)xstrdup((char *)s);
+ }
spats[idx].timestamp = os_time();
spats[idx].additional_data = NULL;
spats[idx].magic = magic;
- spats[idx].no_scs = FALSE;
+ spats[idx].no_scs = false;
spats[idx].off.dir = '/';
set_vv_searchforward();
spats[idx].off.line = FALSE;
spats[idx].off.end = FALSE;
spats[idx].off.off = 0;
- if (setlast)
+ if (setlast) {
last_idx = idx;
+ }
if (save_level) {
free_spat(&saved_spats[idx]);
saved_spats[idx] = spats[0];
- if (spats[idx].pat == NULL)
+ if (spats[idx].pat == NULL) {
saved_spats[idx].pat = NULL;
- else
+ } else {
saved_spats[idx].pat = vim_strsave(spats[idx].pat);
+ }
saved_spats_last_idx = last_idx;
}
- /* If 'hlsearch' set and search pat changed: need redraw. */
- if (p_hls && idx == last_idx && !no_hlsearch)
+ // If 'hlsearch' set and search pat changed: need redraw.
+ if (p_hls && idx == last_idx && !no_hlsearch) {
redraw_all_later(SOME_VALID);
+ }
}
/*
@@ -507,7 +515,7 @@ void last_pat_prog(regmmatch_T *regmatch)
regmatch->regprog = NULL;
return;
}
- ++emsg_off; /* So it doesn't beep if bad expr */
+ ++emsg_off; // So it doesn't beep if bad expr
(void)search_regcomp((char_u *)"", 0, last_idx, SEARCH_KEEP, regmatch);
--emsg_off;
}
@@ -527,27 +535,21 @@ void last_pat_prog(regmmatch_T *regmatch)
/// if (options & SEARCH_PEEK) check for typed char, cancel search
/// if (options & SEARCH_COL) start at pos->col instead of zero
///
-/// @returns FAIL (zero) for failure, non-zero for success.
-/// the index of the first matching
-/// subpattern plus one; one if there was none.
-int searchit(
- win_T *win, // window to search in; can be NULL for a
- // buffer without a window!
- buf_T *buf,
- pos_T *pos,
- pos_T *end_pos, // set to end of the match, unless NULL
- Direction dir,
- char_u *pat,
- long count,
- int options,
- int pat_use, // which pattern to use when "pat" is empty
- searchit_arg_T *extra_arg // optional extra arguments, can be NULL
-)
+/// @param win window to search in; can be NULL for a buffer without a window!
+/// @param end_pos set to end of the match, unless NULL
+/// @param pat_use which pattern to use when "pat" is empty
+/// @param extra_arg optional extra arguments, can be NULL
+///
+/// @returns FAIL (zero) for failure, non-zero for success.
+/// the index of the first matching
+/// subpattern plus one; one if there was none.
+int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, char_u *pat,
+ long count, int options, int pat_use, searchit_arg_T *extra_arg)
{
int found;
- linenr_T lnum; /* no init to shut up Apollo cc */
+ linenr_T lnum; // no init to shut up Apollo cc
regmmatch_T regmatch;
- char_u *ptr;
+ char_u *ptr;
colnr_T matchcol;
lpos_T endpos;
lpos_T matchpos;
@@ -556,26 +558,27 @@ int searchit(
int at_first_line;
int extra_col;
int start_char_len;
- int match_ok;
+ bool match_ok;
long nmatched;
int submatch = 0;
bool first_match = true;
int save_called_emsg = called_emsg;
- int break_loop = false;
+ bool break_loop = false;
linenr_T stop_lnum = 0; // stop after this line number when != 0
proftime_T *tm = NULL; // timeout limit or NULL
int *timed_out = NULL; // set when timed out or NULL
if (extra_arg != NULL) {
- stop_lnum = extra_arg->sa_stop_lnum;
- tm = extra_arg->sa_tm;
- timed_out = &extra_arg->sa_timed_out;
+ stop_lnum = extra_arg->sa_stop_lnum;
+ tm = extra_arg->sa_tm;
+ timed_out = &extra_arg->sa_timed_out;
}
if (search_regcomp(pat, RE_SEARCH, pat_use,
- (options & (SEARCH_HIS + SEARCH_KEEP)), &regmatch) == FAIL) {
- if ((options & SEARCH_MSG) && !rc_did_emsg)
+ (options & (SEARCH_HIS + SEARCH_KEEP)), &regmatch) == FAIL) {
+ if ((options & SEARCH_MSG) && !rc_did_emsg) {
EMSG2(_("E383: Invalid search string: %s"), mr_pattern);
+ }
return FAIL;
}
@@ -583,7 +586,7 @@ int searchit(
* find the string
*/
called_emsg = FALSE;
- do { /* loop for count */
+ do { // loop for count
// When not accepting a match at the start position set "extra_col" to a
// non-zero value. Don't do that when starting at MAXCOL, since MAXCOL + 1
// is zero.
@@ -608,13 +611,13 @@ int searchit(
extra_col = (options & SEARCH_START) ? start_char_len : 0;
}
- start_pos = *pos; /* remember start pos for detecting no match */
- found = 0; /* default: not found */
- at_first_line = TRUE; /* default: start in first line */
- if (pos->lnum == 0) { /* correct lnum for when starting in line 0 */
+ start_pos = *pos; // remember start pos for detecting no match
+ found = 0; // default: not found
+ at_first_line = TRUE; // default: start in first line
+ if (pos->lnum == 0) { // correct lnum for when starting in line 0
pos->lnum = 1;
pos->col = 0;
- at_first_line = FALSE; /* not in first line now */
+ at_first_line = FALSE; // not in first line now
}
/*
@@ -628,19 +631,22 @@ int searchit(
&& (options & SEARCH_START) == 0) {
lnum = pos->lnum - 1;
at_first_line = FALSE;
- } else
+ } else {
lnum = pos->lnum;
+ }
- for (loop = 0; loop <= 1; ++loop) { /* loop twice if 'wrapscan' set */
+ for (loop = 0; loop <= 1; ++loop) { // loop twice if 'wrapscan' set
for (; lnum > 0 && lnum <= buf->b_ml.ml_line_count;
lnum += dir, at_first_line = FALSE) {
- /* Stop after checking "stop_lnum", if it's set. */
+ // Stop after checking "stop_lnum", if it's set.
if (stop_lnum != 0 && (dir == FORWARD
- ? lnum > stop_lnum : lnum < stop_lnum))
+ ? lnum > stop_lnum : lnum < stop_lnum)) {
break;
- /* Stop after passing the "tm" time limit. */
- if (tm != NULL && profile_passed_limit(*tm))
+ }
+ // Stop after passing the "tm" time limit.
+ if (tm != NULL && profile_passed_limit(*tm)) {
break;
+ }
// Look for a match somewhere in line "lnum".
colnr_T col = at_first_line && (options & SEARCH_COL) ? pos->col : 0;
@@ -655,15 +661,16 @@ int searchit(
break;
}
if (nmatched > 0) {
- /* match may actually be in another line when using \zs */
+ // match may actually be in another line when using \zs
matchpos = regmatch.startpos[0];
endpos = regmatch.endpos[0];
submatch = first_submatch(&regmatch);
- /* "lnum" may be past end of buffer for "\n\zs". */
- if (lnum + matchpos.lnum > buf->b_ml.ml_line_count)
+ // "lnum" may be past end of buffer for "\n\zs".
+ if (lnum + matchpos.lnum > buf->b_ml.ml_line_count) {
ptr = (char_u *)"";
- else
- ptr = ml_get_buf(buf, lnum + matchpos.lnum, FALSE);
+ } else {
+ ptr = ml_get_buf(buf, lnum + matchpos.lnum, false);
+ }
/*
* Forward search in the first line: match should be after
@@ -671,14 +678,12 @@ int searchit(
* match (this is vi compatible) or on the next char.
*/
if (dir == FORWARD && at_first_line) {
- match_ok = TRUE;
- /*
- * When the match starts in a next line it's certainly
- * past the start position.
- * When match lands on a NUL the cursor will be put
- * one back afterwards, compare with that position,
- * otherwise "/$" will get stuck on end of line.
- */
+ match_ok = true;
+ // When the match starts in a next line it's certainly
+ // past the start position.
+ // When match lands on a NUL the cursor will be put
+ // one back afterwards, compare with that position,
+ // otherwise "/$" will get stuck on end of line.
while (matchpos.lnum == 0
&& (((options & SEARCH_END) && first_match)
? (nmatched == 1
@@ -696,7 +701,7 @@ int searchit(
if (nmatched > 1) {
/* end is in next line, thus no match in
* this line */
- match_ok = FALSE;
+ match_ok = false;
break;
}
matchcol = endpos.col;
@@ -739,8 +744,9 @@ int searchit(
// have made it invalid.
ptr = ml_get_buf(buf, lnum, false);
}
- if (!match_ok)
+ if (!match_ok) {
continue;
+ }
}
if (dir == BACKWARD) {
/*
@@ -750,7 +756,7 @@ int searchit(
* When putting the new cursor at the end, compare
* relative to the end of the match.
*/
- match_ok = FALSE;
+ match_ok = false;
for (;; ) {
/* Remember a position that is before the start
* position, we use it if it's the last match in
@@ -774,8 +780,9 @@ int searchit(
matchpos = regmatch.startpos[0];
endpos = regmatch.endpos[0];
submatch = first_submatch(&regmatch);
- } else
+ } else {
break;
+ }
// We found a valid match, now check if there is
// another one after it.
@@ -803,16 +810,16 @@ int searchit(
}
}
if (ptr[matchcol] == NUL
- || (nmatched = vim_regexec_multi(
- &regmatch, win, buf, lnum + matchpos.lnum, matchcol,
- tm, timed_out)) == 0) {
- // If the search timed out, we did find a match
- // but it might be the wrong one, so that's not
- // OK.
- if (tm != NULL && profile_passed_limit(*tm)) {
- match_ok = false;
- }
- break;
+ || (nmatched =
+ vim_regexec_multi(&regmatch, win, buf, lnum + matchpos.lnum, matchcol,
+ tm, timed_out)) == 0) {
+ // If the search timed out, we did find a match
+ // but it might be the wrong one, so that's not
+ // OK.
+ if (tm != NULL && profile_passed_limit(*tm)) {
+ match_ok = false;
+ }
+ break;
}
// vim_regexec_multi() may clear "regprog"
if (regmatch.regprog == NULL) {
@@ -827,8 +834,9 @@ int searchit(
* If there is only a match after the cursor, skip
* this match.
*/
- if (!match_ok)
+ if (!match_ok) {
continue;
+ }
}
/* With the SEARCH_END option move to the last character
@@ -842,10 +850,9 @@ int searchit(
pos->lnum = lnum + endpos.lnum;
pos->col = endpos.col;
if (endpos.col == 0) {
- if (pos->lnum > 1) { /* just in case */
- --pos->lnum;
- pos->col = (colnr_T)STRLEN(ml_get_buf(buf,
- pos->lnum, FALSE));
+ if (pos->lnum > 1) { // just in case
+ pos->lnum--;
+ pos->col = (colnr_T)STRLEN(ml_get_buf(buf, pos->lnum, false));
}
} else {
pos->col--;
@@ -873,14 +880,15 @@ int searchit(
found = 1;
first_match = false;
- /* Set variables used for 'incsearch' highlighting. */
+ // Set variables used for 'incsearch' highlighting.
search_match_lines = endpos.lnum - matchpos.lnum;
search_match_endcol = endpos.col;
break;
}
- line_breakcheck(); /* stop if ctrl-C typed */
- if (got_int)
+ line_breakcheck(); // stop if ctrl-C typed
+ if (got_int) {
break;
+ }
/* Cancel searching if a character was typed. Used for
* 'incsearch'. Don't check too often, that would slowdown
@@ -888,12 +896,13 @@ int searchit(
if ((options & SEARCH_PEEK)
&& ((lnum - pos->lnum) & 0x3f) == 0
&& char_avail()) {
- break_loop = TRUE;
+ break_loop = true;
break;
}
- if (loop && lnum == start_pos.lnum)
- break; /* if second loop, stop where started */
+ if (loop && lnum == start_pos.lnum) {
+ break; // if second loop, stop where started
+ }
}
at_first_line = FALSE;
@@ -933,8 +942,7 @@ int searchit(
}
if (got_int || called_emsg
|| (timed_out != NULL && *timed_out)
- || break_loop
- ) {
+ || break_loop) {
break;
}
} while (--count > 0 && found); // stop after count matches or no match
@@ -943,28 +951,30 @@ int searchit(
called_emsg |= save_called_emsg;
- if (!found) { /* did not find it */
- if (got_int)
+ if (!found) { // did not find it
+ if (got_int) {
EMSG(_(e_interr));
- else if ((options & SEARCH_MSG) == SEARCH_MSG) {
- if (p_ws)
+ } else if ((options & SEARCH_MSG) == SEARCH_MSG) {
+ if (p_ws) {
EMSG2(_(e_patnotf2), mr_pattern);
- else if (lnum == 0)
+ } else if (lnum == 0) {
EMSG2(_("E384: search hit TOP without match for: %s"),
- mr_pattern);
- else
+ mr_pattern);
+ } else {
EMSG2(_("E385: search hit BOTTOM without match for: %s"),
- mr_pattern);
+ mr_pattern);
+ }
}
return FAIL;
}
- /* A pattern like "\n\zs" may go past the last line. */
+ // A pattern like "\n\zs" may go past the last line.
if (pos->lnum > buf->b_ml.ml_line_count) {
pos->lnum = buf->b_ml.ml_line_count;
- pos->col = (int)STRLEN(ml_get_buf(buf, pos->lnum, FALSE));
- if (pos->col > 0)
- --pos->col;
+ pos->col = (int)STRLEN(ml_get_buf(buf, pos->lnum, false));
+ if (pos->col > 0) {
+ pos->col--;
+ }
}
return submatch + 1;
@@ -987,8 +997,9 @@ static int first_submatch(regmmatch_T *rp)
int submatch;
for (submatch = 1;; ++submatch) {
- if (rp->startpos[submatch].lnum >= 0)
+ if (rp->startpos[submatch].lnum >= 0) {
break;
+ }
if (submatch == 9) {
submatch = 0;
break;
@@ -997,49 +1008,46 @@ static int first_submatch(regmmatch_T *rp)
return submatch;
}
-/*
- * Highest level string search function.
- * Search for the 'count'th occurrence of pattern 'pat' in direction 'dirc'
- * If 'dirc' is 0: use previous dir.
- * If 'pat' is NULL or empty : use previous string.
- * If 'options & SEARCH_REV' : go in reverse of previous dir.
- * If 'options & SEARCH_ECHO': echo the search command and handle options
- * If 'options & SEARCH_MSG' : may give error message
- * If 'options & SEARCH_OPT' : interpret optional flags
- * If 'options & SEARCH_HIS' : put search pattern in history
- * If 'options & SEARCH_NOOF': don't add offset to position
- * If 'options & SEARCH_MARK': set previous context mark
- * If 'options & SEARCH_KEEP': keep previous search pattern
- * If 'options & SEARCH_START': accept match at curpos itself
- * If 'options & SEARCH_PEEK': check for typed char, cancel search
- *
- * Careful: If spats[0].off.line == TRUE and spats[0].off.off == 0 this
- * makes the movement linewise without moving the match position.
- *
- * Return 0 for failure, 1 for found, 2 for found and line offset added.
- */
-int do_search(
- oparg_T *oap, // can be NULL
- int dirc, // '/' or '?'
- int search_delim, // delimiter for search, e.g. '%' in s%regex%replacement
- char_u *pat,
- long count,
- int options,
- searchit_arg_T *sia // optional arguments or NULL
-)
+/// Highest level string search function.
+/// Search for the 'count'th occurrence of pattern 'pat' in direction 'dirc'
+///
+/// Careful: If spats[0].off.line == TRUE and spats[0].off.off == 0 this
+/// makes the movement linewise without moving the match position.
+///
+/// @param dirc if 0: use previous dir.
+/// @param pat NULL or empty : use previous string.
+/// @param options if TRUE and
+/// SEARCH_REV == TRUE : go in reverse of previous dir.
+/// SEARCH_ECHO == TRUE : echo the search command and handle options
+/// SEARCH_MSG == TRUE : may give error message
+/// SEARCH_OPT == TRUE : interpret optional flags
+/// SEARCH_HIS == TRUE : put search pattern in history
+/// SEARCH_NOOF == TRUE : don't add offset to position
+/// SEARCH_MARK == TRUE : set previous context mark
+/// SEARCH_KEEP == TRUE : keep previous search pattern
+/// SEARCH_START == TRUE : accept match at curpos itself
+/// SEARCH_PEEK == TRUE : check for typed char, cancel search
+/// @param oap can be NULL
+/// @param dirc '/' or '?'
+/// @param search_delim delimiter for search, e.g. '%' in s%regex%replacement
+/// @param sia optional arguments or NULL
+///
+/// @return 0 for failure, 1 for found, 2 for found and line offset added.
+int do_search(oparg_T *oap, int dirc, int search_delim, char_u *pat, long count, int options,
+ searchit_arg_T *sia)
{
- pos_T pos; /* position of the last match */
- char_u *searchstr;
+ pos_T pos; // position of the last match
+ char_u *searchstr;
struct soffset old_off;
- int retval; /* Return value */
- char_u *p;
+ int retval; // Return value
+ char_u *p;
long c;
- char_u *dircp;
- char_u *strcopy = NULL;
- char_u *ps;
- char_u *msgbuf = NULL;
- size_t len;
- bool has_offset = false;
+ char_u *dircp;
+ char_u *strcopy = NULL;
+ char_u *ps;
+ char_u *msgbuf = NULL;
+ size_t len;
+ bool has_offset = false;
/*
* A line offset is not remembered, this is vi compatible.
@@ -1055,32 +1063,35 @@ int do_search(
*/
old_off = spats[0].off;
- pos = curwin->w_cursor; /* start searching at the cursor position */
+ pos = curwin->w_cursor; // start searching at the cursor position
/*
* Find out the direction of the search.
*/
- if (dirc == 0)
+ if (dirc == 0) {
dirc = spats[0].off.dir;
- else {
+ } else {
spats[0].off.dir = dirc;
set_vv_searchforward();
}
if (options & SEARCH_REV) {
- if (dirc == '/')
+ if (dirc == '/') {
dirc = '?';
- else
+ } else {
dirc = '/';
+ }
}
/* If the cursor is in a closed fold, don't find another match in the same
* fold. */
if (dirc == '/') {
- if (hasFolding(pos.lnum, NULL, &pos.lnum))
- pos.col = MAXCOL - 2; /* avoid overflow when adding 1 */
+ if (hasFolding(pos.lnum, NULL, &pos.lnum)) {
+ pos.col = MAXCOL - 2; // avoid overflow when adding 1
+ }
} else {
- if (hasFolding(pos.lnum, &pos.lnum, NULL))
+ if (hasFolding(pos.lnum, &pos.lnum, NULL)) {
pos.col = 0;
+ }
}
/*
@@ -1109,12 +1120,12 @@ int do_search(
goto end_do_search;
}
} else {
- /* make search_regcomp() use spats[RE_SEARCH].pat */
+ // make search_regcomp() use spats[RE_SEARCH].pat
searchstr = (char_u *)"";
}
}
- if (pat != NULL && *pat != NUL) { /* look for (new) offset */
+ if (pat != NULL && *pat != NUL) { // look for (new) offset
/*
* Find end of regular expression.
* If there is a matching '/' or '?', toss it.
@@ -1122,7 +1133,7 @@ int do_search(
ps = strcopy;
p = skip_regexp(pat, search_delim, p_magic, &strcopy);
if (strcopy != ps) {
- /* made a copy of "pat" to change "\?" to "?" */
+ // made a copy of "pat" to change "\?" to "?"
searchcmdlen += (int)(STRLEN(pat) - STRLEN(strcopy));
pat = strcopy;
searchstr = strcopy;
@@ -1147,30 +1158,32 @@ int do_search(
}
p++;
}
- if (ascii_isdigit(*p) || *p == '+' || *p == '-') { /* got an offset */
- /* 'nr' or '+nr' or '-nr' */
- if (ascii_isdigit(*p) || ascii_isdigit(*(p + 1)))
+ if (ascii_isdigit(*p) || *p == '+' || *p == '-') { // got an offset
+ // 'nr' or '+nr' or '-nr'
+ if (ascii_isdigit(*p) || ascii_isdigit(*(p + 1))) {
spats[0].off.off = atol((char *)p);
- else if (*p == '-') /* single '-' */
+ } else if (*p == '-') { // single '-'
spats[0].off.off = -1;
- else /* single '+' */
+ } else { // single '+'
spats[0].off.off = 1;
+ }
++p;
- while (ascii_isdigit(*p)) /* skip number */
+ while (ascii_isdigit(*p)) { // skip number
++p;
+ }
}
- /* compute length of search command for get_address() */
+ // compute length of search command for get_address()
searchcmdlen += (int)(p - pat);
- pat = p; /* put pat after search command */
+ pat = p; // put pat after search command
}
if ((options & SEARCH_ECHO) && messaging() && !msg_silent
&& (!cmd_silent || !shortmess(SHM_SEARCHCOUNT))) {
- char_u *trunc;
- char_u off_buf[40];
- size_t off_len = 0;
+ char_u *trunc;
+ char_u off_buf[40];
+ size_t off_len = 0;
// Compute msg_row early.
msg_start();
@@ -1290,18 +1303,22 @@ int do_search(
*/
if (!spats[0].off.line && spats[0].off.off && pos.col < MAXCOL - 2) {
if (spats[0].off.off > 0) {
- for (c = spats[0].off.off; c; --c)
- if (decl(&pos) == -1)
+ for (c = spats[0].off.off; c; --c) {
+ if (decl(&pos) == -1) {
break;
- if (c) { /* at start of buffer */
- pos.lnum = 0; /* allow lnum == 0 here */
+ }
+ }
+ if (c) { // at start of buffer
+ pos.lnum = 0; // allow lnum == 0 here
pos.col = MAXCOL;
}
} else {
- for (c = spats[0].off.off; c; ++c)
- if (incl(&pos) == -1)
+ for (c = spats[0].off.off; c; ++c) {
+ if (incl(&pos) == -1) {
break;
- if (c) { /* at end of buffer */
+ }
+ }
+ if (c) { // at end of buffer
pos.lnum = curbuf->b_ml.ml_line_count + 1;
pos.col = 0;
}
@@ -1331,10 +1348,10 @@ int do_search(
retval = 0;
goto end_do_search;
}
- if (spats[0].off.end && oap != NULL)
- oap->inclusive = true; /* 'e' includes last character */
-
- retval = 1; /* pattern found */
+ if (spats[0].off.end && oap != NULL) {
+ oap->inclusive = true; // 'e' includes last character
+ }
+ retval = 1; // pattern found
/*
* Add character and/or line offset
@@ -1344,28 +1361,33 @@ int do_search(
if (spats[0].off.line) { // Add the offset to the line number.
c = pos.lnum + spats[0].off.off;
- if (c < 1)
+ if (c < 1) {
pos.lnum = 1;
- else if (c > curbuf->b_ml.ml_line_count)
+ } else if (c > curbuf->b_ml.ml_line_count) {
pos.lnum = curbuf->b_ml.ml_line_count;
- else
+ } else {
pos.lnum = c;
+ }
pos.col = 0;
- retval = 2; /* pattern found, line offset added */
- } else if (pos.col < MAXCOL - 2) { /* just in case */
- /* to the right, check for end of file */
+ retval = 2; // pattern found, line offset added
+ } else if (pos.col < MAXCOL - 2) { // just in case
+ // to the right, check for end of file
c = spats[0].off.off;
if (c > 0) {
- while (c-- > 0)
- if (incl(&pos) == -1)
+ while (c-- > 0) {
+ if (incl(&pos) == -1) {
break;
+ }
+ }
}
- /* to the left, check for start of file */
+ // to the left, check for start of file
else {
- while (c++ < 0)
- if (decl(&pos) == -1)
+ while (c++ < 0) {
+ if (decl(&pos) == -1) {
break;
+ }
+ }
}
}
if (!equalpos(pos, org_pos)) {
@@ -1410,14 +1432,16 @@ int do_search(
++pat;
}
- if (options & SEARCH_MARK)
+ if (options & SEARCH_MARK) {
setpcmark();
+ }
curwin->w_cursor = pos;
curwin->w_set_curswant = TRUE;
end_do_search:
- if ((options & SEARCH_KEEP) || cmdmod.keeppatterns)
+ if ((options & SEARCH_KEEP) || cmdmod.keeppatterns) {
spats[0].off = old_off;
+ }
xfree(msgbuf);
return retval;
@@ -1435,18 +1459,20 @@ end_do_search:
int search_for_exact_line(buf_T *buf, pos_T *pos, Direction dir, char_u *pat)
{
linenr_T start = 0;
- char_u *ptr;
- char_u *p;
+ char_u *ptr;
+ char_u *p;
- if (buf->b_ml.ml_line_count == 0)
+ if (buf->b_ml.ml_line_count == 0) {
return FAIL;
+ }
for (;; ) {
pos->lnum += dir;
if (pos->lnum < 1) {
if (p_ws) {
pos->lnum = buf->b_ml.ml_line_count;
- if (!shortmess(SHM_SEARCH))
+ if (!shortmess(SHM_SEARCH)) {
give_warning((char_u *)_(top_bot_msg), true);
+ }
} else {
pos->lnum = 1;
break;
@@ -1454,20 +1480,23 @@ int search_for_exact_line(buf_T *buf, pos_T *pos, Direction dir, char_u *pat)
} else if (pos->lnum > buf->b_ml.ml_line_count) {
if (p_ws) {
pos->lnum = 1;
- if (!shortmess(SHM_SEARCH))
+ if (!shortmess(SHM_SEARCH)) {
give_warning((char_u *)_(bot_top_msg), true);
+ }
} else {
pos->lnum = 1;
break;
}
}
- if (pos->lnum == start)
+ if (pos->lnum == start) {
break;
- if (start == 0)
+ }
+ if (start == 0) {
start = pos->lnum;
- ptr = ml_get_buf(buf, pos->lnum, FALSE);
+ }
+ ptr = ml_get_buf(buf, pos->lnum, false);
p = skipwhite(ptr);
- pos->col = (colnr_T) (p - ptr);
+ pos->col = (colnr_T)(p - ptr);
/* when adding lines the matching line may be empty but it is not
* ignored because we are interested in the next line -- Acevedo */
@@ -1480,8 +1509,9 @@ int search_for_exact_line(buf_T *buf, pos_T *pos, Direction dir, char_u *pat)
// Expanding lines or words.
assert(compl_length >= 0);
if ((p_ic ? mb_strnicmp(p, pat, (size_t)compl_length)
- : STRNCMP(p, pat, compl_length)) == 0)
+ : STRNCMP(p, pat, compl_length)) == 0) {
return OK;
+ }
}
}
return FAIL;
@@ -1501,15 +1531,15 @@ int searchc(cmdarg_T *cap, int t_cmd)
FUNC_ATTR_NONNULL_ALL
{
int c = cap->nchar; // char to search for
- Direction dir = cap->arg; // TRUE for searching forward
+ int dir = cap->arg; // true for searching forward
long count = cap->count1; // repeat count
int col;
- char_u *p;
+ char_u *p;
int len;
- int stop = TRUE;
+ bool stop = true;
- if (c != NUL) { /* normal search: remember args for repeat */
- if (!KeyStuffed) { /* don't remember when redoing */
+ if (c != NUL) { // normal search: remember args for repeat
+ if (!KeyStuffed) { // don't remember when redoing
*lastc = c;
set_csearch_direction(dir);
set_csearch_until(t_cmd);
@@ -1534,19 +1564,21 @@ int searchc(cmdarg_T *cap, int t_cmd)
}
t_cmd = last_t_cmd;
c = *lastc;
- /* For multi-byte re-use last lastc_bytes[] and lastc_bytelen. */
+ // For multi-byte re-use last lastc_bytes[] and lastc_bytelen.
/* Force a move of at least one char, so ";" and "," will move the
* cursor, even if the cursor is right in front of char we are looking
* at. */
- if (vim_strchr(p_cpo, CPO_SCOLON) == NULL && count == 1 && t_cmd)
- stop = FALSE;
+ if (vim_strchr(p_cpo, CPO_SCOLON) == NULL && count == 1 && t_cmd) {
+ stop = false;
+ }
}
- if (dir == BACKWARD)
+ if (dir == BACKWARD) {
cap->oap->inclusive = false;
- else
+ } else {
cap->oap->inclusive = true;
+ }
p = get_cursor_line_ptr();
col = curwin->w_cursor.col;
@@ -1620,7 +1652,7 @@ static bool check_prevcol(char_u *linep, int col, int ch, int *prevcol)
if (prevcol) {
*prevcol = col;
}
- return (col >= 0 && linep[col] == ch) ? true : false;
+ return col >= 0 && linep[col] == ch;
}
/*
@@ -1665,8 +1697,7 @@ static bool find_rawstring_end(char_u *linep, pos_T *startpos, pos_T *endpos)
/// If there is a match set "*initc" to the matching character and "*findc" to
/// the opposite character. Set "*backwards" to the direction.
/// When "switchit" is true swap the direction.
-static void find_mps_values(int *initc, int *findc, bool *backwards,
- bool switchit)
+static void find_mps_values(int *initc, int *findc, bool *backwards, bool switchit)
FUNC_ATTR_NONNULL_ALL
{
char_u *ptr = curbuf->b_p_mps;
@@ -1732,7 +1763,7 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
bool backwards = false; // init for gcc
bool raw_string = false; // search for raw string
bool inquote = false; // true when inside quotes
- char_u *ptr;
+ char_u *ptr;
int hash_dir = 0; // Direction searched for # things
int comment_dir = 0; // Direction searched for comments
int traveled = 0; // how far we've searched so far
@@ -1752,13 +1783,14 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
// don't recognize backslashes
bool cpo_bsl = (vim_strchr(p_cpo, CPO_MATCHBSL) != NULL);
- /* Direction to search when initc is '/', '*' or '#' */
- if (flags & FM_BACKWARD)
+ // Direction to search when initc is '/', '*' or '#'
+ if (flags & FM_BACKWARD) {
dir = BACKWARD;
- else if (flags & FM_FORWARD)
+ } else if (flags & FM_FORWARD) {
dir = FORWARD;
- else
+ } else {
dir = 0;
+ }
/*
* if initc given, look in the table for the matching character
@@ -1768,8 +1800,9 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
*/
if (initc == '/' || initc == '*' || initc == 'R') {
comment_dir = dir;
- if (initc == '/')
+ if (initc == '/') {
ignore_cend = true;
+ }
backwards = (dir == FORWARD) ? false : true;
raw_string = (initc == 'R');
initc = NUL;
@@ -1792,16 +1825,17 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
* Only check for special things when 'cpo' doesn't have '%'.
*/
if (!cpo_match) {
- /* Are we before or at #if, #else etc.? */
+ // Are we before or at #if, #else etc.?
ptr = skipwhite(linep);
if (*ptr == '#' && pos.col <= (colnr_T)(ptr - linep)) {
ptr = skipwhite(ptr + 1);
- if ( STRNCMP(ptr, "if", 2) == 0
- || STRNCMP(ptr, "endif", 5) == 0
- || STRNCMP(ptr, "el", 2) == 0)
+ if (STRNCMP(ptr, "if", 2) == 0
+ || STRNCMP(ptr, "endif", 5) == 0
+ || STRNCMP(ptr, "el", 2) == 0) {
hash_dir = 1;
+ }
}
- /* Are we on a comment? */
+ // Are we on a comment?
else if (linep[pos.col] == '/') {
if (linep[pos.col + 1] == '*') {
comment_dir = FORWARD;
@@ -1833,12 +1867,14 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
* If beyond the end of the line, use the last character in
* the line.
*/
- if (linep[pos.col] == NUL && pos.col)
+ if (linep[pos.col] == NUL && pos.col) {
--pos.col;
+ }
for (;; ) {
initc = PTR2CHAR(linep + pos.col);
- if (initc == NUL)
+ if (initc == NUL) {
break;
+ }
find_mps_values(&initc, &findc, &backwards, false);
if (findc) {
@@ -1847,18 +1883,20 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
pos.col += utfc_ptr2len(linep + pos.col);
}
if (!findc) {
- /* no brace in the line, maybe use " #if" then */
- if (!cpo_match && *skipwhite(linep) == '#')
+ // no brace in the line, maybe use " #if" then
+ if (!cpo_match && *skipwhite(linep) == '#') {
hash_dir = 1;
- else
+ } else {
return NULL;
+ }
} else if (!cpo_bsl) {
int col, bslcnt = 0;
/* Set "match_escaped" if there are an odd number of
* backslashes. */
- for (col = pos.col; check_prevcol(linep, col, '\\', &col); )
+ for (col = pos.col; check_prevcol(linep, col, '\\', &col); ) {
bslcnt++;
+ }
match_escaped = (bslcnt & 1);
}
}
@@ -1872,49 +1910,58 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
}
if (initc != '#') {
ptr = skipwhite(skipwhite(linep) + 1);
- if (STRNCMP(ptr, "if", 2) == 0 || STRNCMP(ptr, "el", 2) == 0)
+ if (STRNCMP(ptr, "if", 2) == 0 || STRNCMP(ptr, "el", 2) == 0) {
hash_dir = 1;
- else if (STRNCMP(ptr, "endif", 5) == 0)
+ } else if (STRNCMP(ptr, "endif", 5) == 0) {
hash_dir = -1;
- else
+ } else {
return NULL;
+ }
}
pos.col = 0;
while (!got_int) {
if (hash_dir > 0) {
- if (pos.lnum == curbuf->b_ml.ml_line_count)
+ if (pos.lnum == curbuf->b_ml.ml_line_count) {
break;
- } else if (pos.lnum == 1)
+ }
+ } else if (pos.lnum == 1) {
break;
+ }
pos.lnum += hash_dir;
linep = ml_get(pos.lnum);
- line_breakcheck(); /* check for CTRL-C typed */
+ line_breakcheck(); // check for CTRL-C typed
ptr = skipwhite(linep);
- if (*ptr != '#')
+ if (*ptr != '#') {
continue;
- pos.col = (colnr_T) (ptr - linep);
+ }
+ pos.col = (colnr_T)(ptr - linep);
ptr = skipwhite(ptr + 1);
if (hash_dir > 0) {
- if (STRNCMP(ptr, "if", 2) == 0)
+ if (STRNCMP(ptr, "if", 2) == 0) {
count++;
- else if (STRNCMP(ptr, "el", 2) == 0) {
- if (count == 0)
+ } else if (STRNCMP(ptr, "el", 2) == 0) {
+ if (count == 0) {
return &pos;
+ }
} else if (STRNCMP(ptr, "endif", 5) == 0) {
- if (count == 0)
+ if (count == 0) {
return &pos;
+ }
count--;
}
} else {
if (STRNCMP(ptr, "if", 2) == 0) {
- if (count == 0)
+ if (count == 0) {
return &pos;
+ }
count--;
} else if (initc == '#' && STRNCMP(ptr, "el", 2) == 0) {
- if (count == 0)
+ if (count == 0) {
return &pos;
- } else if (STRNCMP(ptr, "endif", 5) == 0)
+ }
+ } else if (STRNCMP(ptr, "endif", 5) == 0) {
count++;
+ }
}
}
return NULL;
@@ -1933,11 +1980,11 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
pos_T match_pos; // Where last slash-star was found
clearpos(&match_pos);
- /* backward search: Check if this line contains a single-line comment */
+ // backward search: Check if this line contains a single-line comment
if ((backwards && comment_dir)
- || lisp
- )
+ || lisp) {
comment_col = check_linecomment(linep);
+ }
if (lisp && comment_col != MAXCOL && pos.col > (colnr_T)comment_col) {
lispcomm = true; // find match inside this comment
}
@@ -1947,58 +1994,63 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
* inc() and dec() here, but that is much slower
*/
if (backwards) {
- /* char to match is inside of comment, don't search outside */
- if (lispcomm && pos.col < (colnr_T)comment_col)
+ // char to match is inside of comment, don't search outside
+ if (lispcomm && pos.col < (colnr_T)comment_col) {
break;
- if (pos.col == 0) { /* at start of line, go to prev. one */
- if (pos.lnum == 1) /* start of file */
+ }
+ if (pos.col == 0) { // at start of line, go to prev. one
+ if (pos.lnum == 1) { // start of file
break;
+ }
--pos.lnum;
- if (maxtravel > 0 && ++traveled > maxtravel)
+ if (maxtravel > 0 && ++traveled > maxtravel) {
break;
+ }
linep = ml_get(pos.lnum);
- pos.col = (colnr_T)STRLEN(linep); /* pos.col on trailing NUL */
+ pos.col = (colnr_T)STRLEN(linep); // pos.col on trailing NUL
do_quotes = -1;
line_breakcheck();
- /* Check if this line contains a single-line comment */
+ // Check if this line contains a single-line comment
if (comment_dir
- || lisp
- )
+ || lisp) {
comment_col = check_linecomment(linep);
- /* skip comment */
- if (lisp && comment_col != MAXCOL)
+ }
+ // skip comment
+ if (lisp && comment_col != MAXCOL) {
pos.col = comment_col;
+ }
} else {
pos.col--;
pos.col -= utf_head_off(linep, linep + pos.col);
}
- } else { /* forward search */
+ } else { // forward search
if (linep[pos.col] == NUL
- /* at end of line, go to next one */
- /* don't search for match in comment */
+ // at end of line, go to next one
+ // 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 */
+ && pos.col == (colnr_T)comment_col)) {
+ if (pos.lnum == curbuf->b_ml.ml_line_count // end of file
/* line is exhausted and comment with it,
* don't search for match in code */
- || lispcomm
- )
+ || lispcomm) {
break;
+ }
++pos.lnum;
- if (maxtravel && traveled++ > maxtravel)
+ if (maxtravel && traveled++ > maxtravel) {
break;
+ }
linep = ml_get(pos.lnum);
pos.col = 0;
do_quotes = -1;
line_breakcheck();
- if (lisp) /* find comment pos in new line */
+ if (lisp) { // find comment pos in new line
comment_col = check_linecomment(linep);
+ }
} else {
pos.col += utfc_ptr2len(linep + pos.col);
}
@@ -2014,40 +2066,37 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
}
if (comment_dir) {
- /* Note: comments do not nest, and we ignore quotes in them */
- /* TODO: ignore comment brackets inside strings */
+ // Note: comments do not nest, and we ignore quotes in them
+ // TODO: ignore comment brackets inside strings
if (comment_dir == FORWARD) {
if (linep[pos.col] == '*' && linep[pos.col + 1] == '/') {
pos.col++;
return &pos;
}
- } else { /* Searching backwards */
+ } else { // Searching backwards
/*
* A comment may contain / * or / /, it may also start or end
* with / * /. Ignore a / * after / / and after *.
*/
- if (pos.col == 0)
+ if (pos.col == 0) {
continue;
- else if (raw_string)
- {
+ } else if (raw_string) {
if (linep[pos.col - 1] == 'R'
&& linep[pos.col] == '"'
- && vim_strchr(linep + pos.col + 1, '(') != NULL)
- {
+ && vim_strchr(linep + pos.col + 1, '(') != NULL) {
/* Possible start of raw string. Now that we have the
* delimiter we can check if it ends before where we
* started searching, or before the previously found
* raw string start. */
if (!find_rawstring_end(linep, &pos,
- count > 0 ? &match_pos : &curwin->w_cursor))
- {
+ count > 0 ? &match_pos : &curwin->w_cursor)) {
count++;
match_pos = pos;
match_pos.col--;
}
- linep = ml_get(pos.lnum); /* may have been released */
+ linep = ml_get(pos.lnum); // may have been released
}
- } else if ( linep[pos.col - 1] == '/'
+ } else if (linep[pos.col - 1] == '/'
&& linep[pos.col] == '*'
&& (pos.col == 1 || linep[pos.col - 2] != '*')
&& (int)pos.col < comment_col) {
@@ -2055,15 +2104,16 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
match_pos = pos;
match_pos.col--;
} else if (linep[pos.col - 1] == '*' && linep[pos.col] == '/') {
- if (count > 0)
+ if (count > 0) {
pos = match_pos;
- else if (pos.col > 1 && linep[pos.col - 2] == '/'
- && (int)pos.col <= comment_col)
+ } else if (pos.col > 1 && linep[pos.col - 2] == '/'
+ && (int)pos.col <= comment_col) {
pos.col -= 2;
- else if (ignore_cend)
+ } else if (ignore_cend) {
continue;
- else
+ } else {
return NULL;
+ }
return &pos;
}
}
@@ -2075,24 +2125,27 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
* of quotes are ignored, but only if there is an even number of
* quotes in the line.
*/
- if (cpo_match)
+ if (cpo_match) {
do_quotes = 0;
- else if (do_quotes == -1) {
+ } else if (do_quotes == -1) {
/*
* Count the number of quotes in the line, skipping \" and '"'.
* Watch out for "\\".
*/
at_start = do_quotes;
for (ptr = linep; *ptr; ++ptr) {
- if (ptr == linep + pos.col + backwards)
+ if (ptr == linep + pos.col + backwards) {
at_start = (do_quotes & 1);
+ }
if (*ptr == '"'
- && (ptr == linep || ptr[-1] != '\'' || ptr[1] != '\''))
+ && (ptr == linep || ptr[-1] != '\'' || ptr[1] != '\'')) {
++do_quotes;
- if (*ptr == '\\' && ptr[1] != NUL)
+ }
+ if (*ptr == '\\' && ptr[1] != NUL) {
++ptr;
+ }
}
- do_quotes &= 1; /* result is 1 with even number of quotes */
+ do_quotes &= 1; // result is 1 with even number of quotes
/*
* If we find an uneven count, check current line and previous
@@ -2124,7 +2177,7 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
}
}
- /* ml_get() only keeps one line, need to get linep again */
+ // ml_get() only keeps one line, need to get linep again
linep = ml_get(pos.lnum);
}
}
@@ -2147,7 +2200,7 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
const int c = PTR2CHAR(linep + pos.col);
switch (c) {
case NUL:
- /* at end of line without trailing backslash, reset inquote */
+ // at end of line without trailing backslash, reset inquote
if (pos.col == 0 || linep[pos.col - 1] != '\\') {
inquote = false;
start_in_quotes = kFalse;
@@ -2160,9 +2213,11 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
if (do_quotes) {
int col;
- for (col = pos.col - 1; col >= 0; --col)
- if (linep[col] != '\\')
+ for (col = pos.col - 1; col >= 0; --col) {
+ if (linep[col] != '\\') {
break;
+ }
+ }
if ((((int)pos.col - 1 - col) & 1) == 0) {
inquote = !inquote;
start_in_quotes = kFalse;
@@ -2212,8 +2267,9 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
&& vim_strchr((char_u *)"(){}[]", c) != NULL
&& pos.col > 1
&& check_prevcol(linep, pos.col, '\\', NULL)
- && check_prevcol(linep, pos.col - 1, '#', NULL))
+ && check_prevcol(linep, pos.col - 1, '#', NULL)) {
break;
+ }
/* Check for match outside of quotes, and inside of
* quotes when the start is also inside of quotes. */
@@ -2222,17 +2278,19 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
int col, bslcnt = 0;
if (!cpo_bsl) {
- for (col = pos.col; check_prevcol(linep, col, '\\', &col); )
+ for (col = pos.col; check_prevcol(linep, col, '\\', &col); ) {
bslcnt++;
+ }
}
/* Only accept a match when 'M' is in 'cpo' or when escaping
* is what we expect. */
if (cpo_bsl || (bslcnt & 1) == match_escaped) {
- if (c == initc)
+ if (c == initc) {
count++;
- else {
- if (count == 0)
+ } else {
+ if (count == 0) {
return &pos;
+ }
count--;
}
}
@@ -2244,7 +2302,7 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
pos = match_pos;
return &pos;
}
- return (pos_T *)NULL; /* never found it */
+ return (pos_T *)NULL; // never found it
}
/*
@@ -2257,51 +2315,55 @@ static int check_linecomment(const char_u *line)
const char_u *p = line; // scan from start
// skip Lispish one-line comments
if (curbuf->b_p_lisp) {
- if (vim_strchr(p, ';') != NULL) { /* there may be comments */
- int in_str = FALSE; /* inside of string */
+ if (vim_strchr(p, ';') != NULL) { // there may be comments
+ bool in_str = false; // inside of string
while ((p = vim_strpbrk(p, (char_u *)"\";")) != NULL) {
if (*p == '"') {
if (in_str) {
- if (*(p - 1) != '\\') /* skip escaped quote */
- in_str = FALSE;
+ if (*(p - 1) != '\\') { // skip escaped quote
+ in_str = false;
+ }
} else if (p == line || ((p - line) >= 2
- /* skip #\" form */
- && *(p - 1) != '\\' && *(p - 2) != '#'))
- in_str = TRUE;
+ // skip #\" form
+ && *(p - 1) != '\\' && *(p - 2) != '#')) {
+ in_str = true;
+ }
} else if (!in_str && ((p - line) < 2
- || (*(p - 1) != '\\' && *(p - 2) != '#')))
- break; /* found! */
- ++p;
+ || (*(p - 1) != '\\' && *(p - 2) != '#'))) {
+ break; // found!
+ }
+ p++;
}
- } else
+ } else {
p = NULL;
- } else
+ }
+ } else {
while ((p = vim_strchr(p, '/')) != NULL) {
/* accept a double /, unless it's preceded with * and followed by *,
* because * / / * is an end and start of a C comment */
- if (p[1] == '/' && (p == line || p[-1] != '*' || p[2] != '*'))
+ if (p[1] == '/' && (p == line || p[-1] != '*' || p[2] != '*')) {
break;
+ }
++p;
}
+ }
- if (p == NULL)
+ if (p == NULL) {
return MAXCOL;
+ }
return (int)(p - line);
}
-/*
- * Move cursor briefly to character matching the one under the cursor.
- * Used for Insert mode and "r" command.
- * Show the match only if it is visible on the screen.
- * If there isn't a match, then beep.
- */
-void
-showmatch(
- int c // char to show match for
-)
+/// Move cursor briefly to character matching the one under the cursor.
+/// Used for Insert mode and "r" command.
+/// Show the match only if it is visible on the screen.
+/// If there isn't a match, then beep.
+///
+/// @param c char to show match for
+void showmatch(int c)
{
- pos_T *lpos, save_cursor;
+ pos_T *lpos, save_cursor;
pos_T mpos;
colnr_T vcol;
long *so = curwin->w_p_so >= 0 ? &curwin->w_p_so : &p_so;
@@ -2310,15 +2372,16 @@ showmatch(
long save_siso;
int save_state;
colnr_T save_dollar_vcol;
- char_u *p;
+ char_u *p;
/*
* Only show match for chars in the 'matchpairs' option.
*/
- /* 'matchpairs' is "x:y,x:y" */
+ // 'matchpairs' is "x:y,x:y"
for (p = curbuf->b_p_mps; *p != NUL; ++p) {
- if (PTR2CHAR(p) == c && (curwin->w_p_rl ^ p_ri))
+ if (PTR2CHAR(p) == c && (curwin->w_p_rl ^ p_ri)) {
break;
+ }
p += utfc_ptr2len(p) + 1;
if (PTR2CHAR(p) == c && !(curwin->w_p_rl ^ p_ri)) {
break;
@@ -2335,7 +2398,7 @@ showmatch(
if ((lpos = findmatch(NULL, NUL)) == NULL) { // no match, so beep
vim_beep(BO_MATCH);
} else if (lpos->lnum >= curwin->w_topline
- && lpos->lnum < curwin->w_botline) {
+ && lpos->lnum < curwin->w_botline) {
if (!curwin->w_p_wrap) {
getvcol(curwin, lpos, NULL, &vcol, NULL);
}
@@ -2396,14 +2459,15 @@ int findsent(Direction dir, long count)
{
pos_T pos, tpos;
int c;
- int (*func)(pos_T *);
+ int (*func)(pos_T *);
bool noskip = false; // do not skip blanks
pos = curwin->w_cursor;
- if (dir == FORWARD)
+ if (dir == FORWARD) {
func = incl;
- else
+ } else {
func = decl;
+ }
while (count--) {
const pos_T prev_pos = pos;
@@ -2418,8 +2482,8 @@ int findsent(Direction dir, long count)
if (dir == FORWARD) {
goto found;
}
- // if on the start of a paragraph or a section and searching forward,
- // go to the next line
+ // if on the start of a paragraph or a section and searching forward,
+ // go to the next line
} else if (dir == FORWARD && pos.col == 0
&& startPS(pos.lnum, NUL, false)) {
if (pos.lnum == curbuf->b_ml.ml_line_count) {
@@ -2442,11 +2506,11 @@ int findsent(Direction dir, long count)
if (found_dot) {
break;
}
- if (vim_strchr((char_u *) ".!?", c) != NULL) {
+ if (vim_strchr((char_u *)".!?", c) != NULL) {
found_dot = true;
}
- if (vim_strchr((char_u *) ")]\"'", c) != NULL
- && vim_strchr((char_u *) ".!?)]\"'", gchar_pos(&tpos)) == NULL) {
+ if (vim_strchr((char_u *)")]\"'", c) != NULL
+ && vim_strchr((char_u *)".!?)]\"'", gchar_pos(&tpos)) == NULL) {
break;
}
decl(&pos);
@@ -2456,41 +2520,47 @@ int findsent(Direction dir, long count)
const int startlnum = pos.lnum;
const bool cpo_J = vim_strchr(p_cpo, CPO_ENDOFSENT) != NULL;
- for (;; ) { /* find end of sentence */
+ for (;; ) { // find end of sentence
c = gchar_pos(&pos);
if (c == NUL || (pos.col == 0 && startPS(pos.lnum, NUL, FALSE))) {
- if (dir == BACKWARD && pos.lnum != startlnum)
+ if (dir == BACKWARD && pos.lnum != startlnum) {
++pos.lnum;
+ }
break;
}
if (c == '.' || c == '!' || c == '?') {
tpos = pos;
do
- if ((c = inc(&tpos)) == -1)
+ if ((c = inc(&tpos)) == -1) {
break;
+ }
while (vim_strchr((char_u *)")]\"'", c = gchar_pos(&tpos))
!= NULL);
if (c == -1 || (!cpo_J && (c == ' ' || c == '\t')) || c == NUL
|| (cpo_J && (c == ' ' && inc(&tpos) >= 0
&& gchar_pos(&tpos) == ' '))) {
pos = tpos;
- if (gchar_pos(&pos) == NUL) /* skip NUL at EOL */
+ if (gchar_pos(&pos) == NUL) { // skip NUL at EOL
inc(&pos);
+ }
break;
}
}
if ((*func)(&pos) == -1) {
- if (count)
+ if (count) {
return FAIL;
+ }
noskip = true;
break;
}
}
found:
- /* skip white space */
- while (!noskip && ((c = gchar_pos(&pos)) == ' ' || c == '\t'))
- if (incl(&pos) == -1)
+ // skip white space
+ while (!noskip && ((c = gchar_pos(&pos)) == ' ' || c == '\t')) {
+ if (incl(&pos) == -1) {
break;
+ }
+ }
if (equalpos(prev_pos, pos)) {
// didn't actually move, advance one character and try again
@@ -2509,28 +2579,22 @@ found:
return OK;
}
-/*
- * Find the next paragraph or section in direction 'dir'.
- * Paragraphs are currently supposed to be separated by empty lines.
- * If 'what' is NUL we go to the next paragraph.
- * If 'what' is '{' or '}' we go to the next section.
- * If 'both' is TRUE also stop at '}'.
- * Return TRUE if the next paragraph or section was found.
- */
-bool
-findpar (
- bool *pincl, /* Return: true if last char is to be included */
- int dir,
- long count,
- int what,
- int both
-)
+/// Find the next paragraph or section in direction 'dir'.
+/// Paragraphs are currently supposed to be separated by empty lines.
+/// If 'what' is NUL we go to the next paragraph.
+/// If 'what' is '{' or '}' we go to the next section.
+/// If 'both' is TRUE also stop at '}'.
+///
+/// @param pincl Return: true if last char is to be included
+///
+/// @return TRUE if the next paragraph or section was found.
+bool findpar(bool *pincl, int dir, long count, int what, int both)
{
linenr_T curr;
- bool did_skip; /* true after separating lines have been skipped */
- bool first; /* true on first line */
- linenr_T fold_first; /* first line of a closed fold */
- linenr_T fold_last; /* last line of a closed fold */
+ bool did_skip; // true after separating lines have been skipped
+ bool first; // true on first line
+ linenr_T fold_first; // first line of a closed fold
+ linenr_T fold_last; // last line of a closed fold
bool fold_skipped; /* true if a closed fold was skipped this
iteration */
@@ -2539,32 +2603,37 @@ findpar (
while (count--) {
did_skip = false;
for (first = true;; first = false) {
- if (*ml_get(curr) != NUL)
+ if (*ml_get(curr) != NUL) {
did_skip = true;
+ }
- /* skip folded lines */
+ // skip folded lines
fold_skipped = false;
if (first && hasFolding(curr, &fold_first, &fold_last)) {
curr = ((dir > 0) ? fold_last : fold_first) + dir;
fold_skipped = true;
}
- if (!first && did_skip && startPS(curr, what, both))
+ if (!first && did_skip && startPS(curr, what, both)) {
break;
+ }
- if (fold_skipped)
+ if (fold_skipped) {
curr -= dir;
+ }
if ((curr += dir) < 1 || curr > curbuf->b_ml.ml_line_count) {
- if (count)
+ if (count) {
return false;
+ }
curr -= dir;
break;
}
}
}
setpcmark();
- if (both && *ml_get(curr) == '}') /* include line with '}' */
+ if (both && *ml_get(curr) == '}') { // include line with '}'
++curr;
+ }
curwin->w_cursor.lnum = curr;
if (curr == curbuf->b_ml.ml_line_count && what != '}') {
char_u *line = ml_get(curr);
@@ -2576,8 +2645,9 @@ findpar (
curwin->w_cursor.col -= utf_head_off(line, line + curwin->w_cursor.col);
*pincl = true;
}
- } else
+ } else {
curwin->w_cursor.col = 0;
+ }
return true;
}
@@ -2586,7 +2656,7 @@ findpar (
*/
static int inmacro(char_u *opt, char_u *s)
{
- char_u *macro;
+ char_u *macro;
for (macro = opt; macro[0]; ++macro) {
/* Accept two characters in the option being equal to two characters
@@ -2597,11 +2667,13 @@ static int inmacro(char_u *opt, char_u *s)
&& (s[0] == NUL || s[0] == ' ')))
&& (macro[1] == s[1]
|| ((macro[1] == NUL || macro[1] == ' ')
- && (s[0] == NUL || s[1] == NUL || s[1] == ' '))))
+ && (s[0] == NUL || s[1] == NUL || s[1] == ' ')))) {
break;
+ }
++macro;
- if (macro[0] == NUL)
+ if (macro[0] == NUL) {
break;
+ }
}
return macro[0] != NUL;
}
@@ -2613,7 +2685,7 @@ static int inmacro(char_u *opt, char_u *s)
*/
int startPS(linenr_T lnum, int para, int both)
{
- char_u *s;
+ char_u *s;
s = ml_get(lnum);
if (*s == para || *s == '\f' || (both && *s == '}')) {
@@ -2642,7 +2714,7 @@ int startPS(linenr_T lnum, int para, int both)
* 2 or higher - keyword characters (letters, digits and underscore)
*/
-static int cls_bigword; /* TRUE for "W", "B" or "E" */
+static int cls_bigword; // TRUE for "W", "B" or "E"
/*
* cls() - returns the class of character at curwin->w_cursor
@@ -2669,20 +2741,15 @@ static int cls(void)
return c;
}
-/*
- * fwd_word(count, type, eol) - move forward one word
- *
- * Returns FAIL if the cursor was already at the end of the file.
- * If eol is TRUE, last word stops at end of line (for operators).
- */
-int
-fwd_word(
- long count,
- int bigword, /* "W", "E" or "B" */
- int eol
-)
+/// fwd_word(count, type, eol) - move forward one word
+///
+/// @return FAIL if the cursor was already at the end of the file.
+/// If eol is TRUE, last word stops at end of line (for operators).
+///
+/// @param bigword "W", "E" or "B"
+int fwd_word(long count, int bigword, int eol)
{
- int sclass; /* starting class */
+ int sclass; // starting class
int i;
int last_line;
@@ -2702,20 +2769,24 @@ fwd_word(
*/
last_line = (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count);
i = inc_cursor();
- if (i == -1 || (i >= 1 && last_line)) /* started at last char in file */
+ if (i == -1 || (i >= 1 && last_line)) { // started at last char in file
return FAIL;
- if (i >= 1 && eol && count == 0) /* started at last char in line */
+ }
+ if (i >= 1 && eol && count == 0) { // started at last char in line
return OK;
+ }
/*
* Go one char past end of current word (if any)
*/
- if (sclass != 0)
+ if (sclass != 0) {
while (cls() == sclass) {
i = inc_cursor();
- if (i == -1 || (i >= 1 && eol && count == 0))
+ if (i == -1 || (i >= 1 && eol && count == 0)) {
return OK;
+ }
}
+ }
/*
* go to next non-white
@@ -2724,12 +2795,14 @@ fwd_word(
/*
* We'll stop if we land on a blank line
*/
- if (curwin->w_cursor.col == 0 && *get_cursor_line_ptr() == NUL)
+ if (curwin->w_cursor.col == 0 && *get_cursor_line_ptr() == NUL) {
break;
+ }
i = inc_cursor();
- if (i == -1 || (i >= 1 && eol && count == 0))
+ if (i == -1 || (i >= 1 && eol && count == 0)) {
return OK;
+ }
}
}
return OK;
@@ -2744,18 +2817,20 @@ fwd_word(
*/
int bck_word(long count, int bigword, int stop)
{
- int sclass; /* starting class */
+ int sclass; // starting class
curwin->w_cursor.coladd = 0;
cls_bigword = bigword;
while (--count >= 0) {
/* When inside a range of folded lines, move to the first char of the
* first line. */
- if (hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL))
+ if (hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL)) {
curwin->w_cursor.col = 0;
+ }
sclass = cls();
- if (dec_cursor() == -1) /* started at start of file */
+ if (dec_cursor() == -1) { // started at start of file
return FAIL;
+ }
if (!stop || sclass == cls() || sclass == 0) {
/*
@@ -2775,11 +2850,12 @@ int bck_word(long count, int bigword, int stop)
/*
* Move backward to start of this word.
*/
- if (skip_chars(cls(), BACKWARD))
+ if (skip_chars(cls(), BACKWARD)) {
return OK;
+ }
}
- inc_cursor(); /* overshot - forward one */
+ inc_cursor(); // overshot - forward one
finished:
stop = FALSE;
}
@@ -2803,7 +2879,7 @@ finished:
*/
int end_word(long count, int bigword, int stop, int empty)
{
- int sclass; /* starting class */
+ int sclass; // starting class
curwin->w_cursor.coladd = 0;
cls_bigword = bigword;
@@ -2814,8 +2890,9 @@ int end_word(long count, int bigword, int stop, int empty)
coladvance(MAXCOL);
}
sclass = cls();
- if (inc_cursor() == -1)
+ if (inc_cursor() == -1) {
return FAIL;
+ }
/*
* If we're in the middle of a word, we just have to move to the end
@@ -2825,8 +2902,9 @@ int end_word(long count, int bigword, int stop, int empty)
/*
* Move forward to end of the current word
*/
- if (skip_chars(sclass, FORWARD))
+ if (skip_chars(sclass, FORWARD)) {
return FAIL;
+ }
} else if (!stop || sclass == 0) {
/*
* We were at the end of a word. Go to the end of the next word.
@@ -2845,47 +2923,48 @@ int end_word(long count, int bigword, int stop, int empty)
/*
* Move forward to the end of this word.
*/
- if (skip_chars(cls(), FORWARD))
+ if (skip_chars(cls(), FORWARD)) {
return FAIL;
+ }
}
- dec_cursor(); /* overshot - one char backward */
+ dec_cursor(); // overshot - one char backward
finished:
- stop = FALSE; /* we move only one word less */
+ stop = FALSE; // we move only one word less
}
return OK;
}
-/*
- * Move back to the end of the word.
- *
- * Returns FAIL if start of the file was reached.
- */
-int
-bckend_word(
- long count,
- int bigword, /* TRUE for "B" */
- int eol /* TRUE: stop at end of line. */
-)
+/// Move back to the end of the word.
+///
+/// @param bigword TRUE for "B"
+/// @param eol if true, then stop at end of line.
+///
+/// @return FAIL if start of the file was reached.
+int bckend_word(long count, int bigword, bool eol)
{
- int sclass; /* starting class */
+ int sclass; // starting class
int i;
curwin->w_cursor.coladd = 0;
cls_bigword = bigword;
while (--count >= 0) {
sclass = cls();
- if ((i = dec_cursor()) == -1)
+ if ((i = dec_cursor()) == -1) {
return FAIL;
- if (eol && i == 1)
+ }
+ if (eol && i == 1) {
return OK;
+ }
/*
* Move backward to before the start of this word.
*/
if (sclass != 0) {
- while (cls() == sclass)
- if ((i = dec_cursor()) == -1 || (eol && i == 1))
+ while (cls() == sclass) {
+ if ((i = dec_cursor()) == -1 || (eol && i == 1)) {
return OK;
+ }
+ }
}
/*
@@ -2903,16 +2982,17 @@ bckend_word(
return OK;
}
-/*
- * Skip a row of characters of the same class.
- * Return TRUE when end-of-file reached, FALSE otherwise.
- */
-static int skip_chars(int cclass, int dir)
+/// Skip a row of characters of the same class.
+///
+/// @return true when end-of-file reached, false otherwise.
+static bool skip_chars(int cclass, int dir)
{
- while (cls() == cclass)
- if ((dir == FORWARD ? inc_cursor() : dec_cursor()) == -1)
- return TRUE;
- return FALSE;
+ while (cls() == cclass) {
+ if ((dir == FORWARD ? inc_cursor() : dec_cursor()) == -1) {
+ return true;
+ }
+ }
+ return false;
}
/*
@@ -2920,14 +3000,15 @@ static int skip_chars(int cclass, int dir)
*/
static void back_in_line(void)
{
- int sclass; /* starting class */
+ int sclass; // starting class
sclass = cls();
for (;; ) {
- if (curwin->w_cursor.col == 0) /* stop at start of line */
+ if (curwin->w_cursor.col == 0) { // stop at start of line
break;
+ }
dec_cursor();
- if (cls() != sclass) { /* stop at start of word */
+ if (cls() != sclass) { // stop at start of word
inc_cursor();
break;
}
@@ -2947,36 +3028,29 @@ static void find_first_blank(pos_T *posp)
}
}
-/*
- * Skip count/2 sentences and count/2 separating white spaces.
- */
-static void
-findsent_forward(
- long count,
- int at_start_sent /* cursor is at start of sentence */
-)
+/// Skip count/2 sentences and count/2 separating white spaces.
+///
+/// @param at_start_sent cursor is at start of sentence
+static void findsent_forward(long count, bool at_start_sent)
{
while (count--) {
findsent(FORWARD, 1L);
- if (at_start_sent)
+ if (at_start_sent) {
find_first_blank(&curwin->w_cursor);
- if (count == 0 || at_start_sent)
+ }
+ if (count == 0 || at_start_sent) {
decl(&curwin->w_cursor);
+ }
at_start_sent = !at_start_sent;
}
}
-/*
- * Find word under cursor, cursor at end.
- * Used while an operator is pending, and in Visual mode.
- */
-int
-current_word(
- oparg_T *oap,
- long count,
- int include, /* TRUE: include word and white space */
- int bigword /* FALSE == word, TRUE == WORD */
-)
+/// Find word under cursor, cursor at end.
+/// Used while an operator is pending, and in Visual mode.
+///
+/// @param include TRUE: include word and white space
+/// @param bigword FALSE == word, TRUE == WORD
+int current_word(oparg_T *oap, long count, int include, int bigword)
{
pos_T start_pos;
pos_T pos;
@@ -2986,9 +3060,10 @@ current_word(
cls_bigword = bigword;
clearpos(&start_pos);
- /* Correct cursor when 'selection' is exclusive */
- if (VIsual_active && *p_sel == 'e' && lt(VIsual, curwin->w_cursor))
+ // Correct cursor when 'selection' is exclusive
+ if (VIsual_active && *p_sel == 'e' && lt(VIsual, curwin->w_cursor)) {
dec_cursor();
+ }
/*
* When Visual mode is not active, or when the VIsual area is only one
@@ -3007,8 +3082,9 @@ current_word(
* not be included ("word"), find end of word.
*/
if ((cls() == 0) == include) {
- if (end_word(1L, bigword, TRUE, TRUE) == FAIL)
+ if (end_word(1L, bigword, TRUE, TRUE) == FAIL) {
return FAIL;
+ }
} else {
/*
* If the start is not on white space, and white space should be
@@ -3018,19 +3094,21 @@ current_word(
* word) back up to end of the line.
*/
fwd_word(1L, bigword, TRUE);
- if (curwin->w_cursor.col == 0)
+ if (curwin->w_cursor.col == 0) {
decl(&curwin->w_cursor);
- else
+ } else {
oneleft();
+ }
- if (include)
+ if (include) {
include_white = TRUE;
+ }
}
if (VIsual_active) {
- /* should do something when inclusive == false ! */
+ // should do something when inclusive == false !
VIsual = start_pos;
- redraw_curbuf_later(INVERTED); /* update the inversion */
+ redraw_curbuf_later(INVERTED); // update the inversion
} else {
oap->start = start_pos;
oap->motion_type = kMTCharWise;
@@ -3047,35 +3125,42 @@ current_word(
/*
* In Visual mode, with cursor at start: move cursor back.
*/
- if (decl(&curwin->w_cursor) == -1)
+ if (decl(&curwin->w_cursor) == -1) {
return FAIL;
+ }
if (include != (cls() != 0)) {
- if (bck_word(1L, bigword, TRUE) == FAIL)
+ if (bck_word(1L, bigword, TRUE) == FAIL) {
return FAIL;
+ }
} else {
- if (bckend_word(1L, bigword, TRUE) == FAIL)
+ if (bckend_word(1L, bigword, true) == FAIL) {
return FAIL;
+ }
(void)incl(&curwin->w_cursor);
}
} else {
/*
* Move cursor forward one word and/or white area.
*/
- if (incl(&curwin->w_cursor) == -1)
+ if (incl(&curwin->w_cursor) == -1) {
return FAIL;
+ }
if (include != (cls() == 0)) {
- if (fwd_word(1L, bigword, TRUE) == FAIL && count > 1)
+ if (fwd_word(1L, bigword, TRUE) == FAIL && count > 1) {
return FAIL;
+ }
/*
* If end is just past a new-line, we don't want to include
* the first character on the line.
* Put cursor on last char of white.
*/
- if (oneleft() == FAIL)
+ if (oneleft() == FAIL) {
inclusive = false;
+ }
} else {
- if (end_word(1L, bigword, TRUE, TRUE) == FAIL)
+ if (end_word(1L, bigword, TRUE, TRUE) == FAIL) {
return FAIL;
+ }
}
}
--count;
@@ -3091,29 +3176,32 @@ current_word(
* (cursor is at start of next line).
* But don't delete white space at start of line (indent).
*/
- pos = curwin->w_cursor; /* save cursor position */
+ pos = curwin->w_cursor; // save cursor position
curwin->w_cursor = start_pos;
if (oneleft() == OK) {
back_in_line();
if (cls() == 0 && curwin->w_cursor.col > 0) {
- if (VIsual_active)
+ if (VIsual_active) {
VIsual = curwin->w_cursor;
- else
+ } else {
oap->start = curwin->w_cursor;
+ }
}
}
- curwin->w_cursor = pos; /* put cursor back at end */
+ curwin->w_cursor = pos; // put cursor back at end
}
if (VIsual_active) {
- if (*p_sel == 'e' && inclusive && ltoreq(VIsual, curwin->w_cursor))
+ if (*p_sel == 'e' && inclusive && ltoreq(VIsual, curwin->w_cursor)) {
inc_cursor();
+ }
if (VIsual_mode == 'V') {
VIsual_mode = 'v';
- redraw_cmdline = TRUE; /* show mode later */
+ redraw_cmdline = true; // show mode later
}
- } else
+ } else {
oap->inclusive = inclusive;
+ }
return OK;
}
@@ -3126,14 +3214,14 @@ int current_sent(oparg_T *oap, long count, int include)
{
pos_T start_pos;
pos_T pos;
- int start_blank;
+ bool start_blank;
int c;
- int at_start_sent;
+ bool at_start_sent;
long ncount;
start_pos = curwin->w_cursor;
pos = start_pos;
- findsent(FORWARD, 1L); /* Find start of next sentence. */
+ findsent(FORWARD, 1L); // Find start of next sentence.
/*
* When the Visual area is bigger than one character: Extend it.
@@ -3148,32 +3236,36 @@ extend:
* - in a sentence or just after it
* - at the start of a sentence
*/
- at_start_sent = TRUE;
+ at_start_sent = true;
decl(&pos);
while (lt(pos, curwin->w_cursor)) {
c = gchar_pos(&pos);
if (!ascii_iswhite(c)) {
- at_start_sent = FALSE;
+ at_start_sent = false;
break;
}
incl(&pos);
}
if (!at_start_sent) {
findsent(BACKWARD, 1L);
- if (equalpos(curwin->w_cursor, start_pos))
- at_start_sent = TRUE; /* exactly at start of sentence */
- else
- /* inside a sentence, go to its end (start of next) */
+ if (equalpos(curwin->w_cursor, start_pos)) {
+ at_start_sent = true; // exactly at start of sentence
+ } else {
+ // inside a sentence, go to its end (start of next)
findsent(FORWARD, 1L);
+ }
}
- if (include) /* "as" gets twice as much as "is" */
+ if (include) { // "as" gets twice as much as "is"
count *= 2;
+ }
while (count--) {
- if (at_start_sent)
+ if (at_start_sent) {
find_first_blank(&curwin->w_cursor);
+ }
c = gchar_cursor();
- if (!at_start_sent || (!include && !ascii_iswhite(c)))
+ if (!at_start_sent || (!include && !ascii_iswhite(c))) {
findsent(BACKWARD, 1L);
+ }
at_start_sent = !at_start_sent;
}
} else {
@@ -3185,28 +3277,31 @@ extend:
* - in a sentence
*/
incl(&pos);
- at_start_sent = TRUE;
- if (!equalpos(pos, curwin->w_cursor)) { /* not just before a sentence */
- at_start_sent = FALSE;
+ at_start_sent = true;
+ if (!equalpos(pos, curwin->w_cursor)) { // not just before a sentence
+ at_start_sent = false;
while (lt(pos, curwin->w_cursor)) {
c = gchar_pos(&pos);
if (!ascii_iswhite(c)) {
- at_start_sent = TRUE;
+ at_start_sent = true;
break;
}
incl(&pos);
}
- if (at_start_sent) /* in the sentence */
+ if (at_start_sent) { // in the sentence
findsent(BACKWARD, 1L);
- else /* in/before white before a sentence */
+ } else { // in/before white before a sentence
curwin->w_cursor = start_pos;
+ }
}
- if (include) /* "as" gets twice as much as "is" */
+ if (include) { // "as" gets twice as much as "is"
count *= 2;
+ }
findsent_forward(count, at_start_sent);
- if (*p_sel == 'e')
+ if (*p_sel == 'e') {
++curwin->w_cursor.col;
+ }
}
return OK;
}
@@ -3215,27 +3310,30 @@ extend:
* If the cursor started on a blank, check if it is just before the start
* of the next sentence.
*/
- while (c = gchar_pos(&pos), ascii_iswhite(c))
+ while (c = gchar_pos(&pos), ascii_iswhite(c)) {
incl(&pos);
+ }
if (equalpos(pos, curwin->w_cursor)) {
- start_blank = TRUE;
- find_first_blank(&start_pos); /* go back to first blank */
+ start_blank = true;
+ find_first_blank(&start_pos); // go back to first blank
} else {
- start_blank = FALSE;
+ start_blank = false;
findsent(BACKWARD, 1L);
start_pos = curwin->w_cursor;
}
- if (include)
+ if (include) {
ncount = count * 2;
- else {
+ } else {
ncount = count;
- if (start_blank)
+ if (start_blank) {
--ncount;
+ }
}
- if (ncount > 0)
- findsent_forward(ncount, TRUE);
- else
+ if (ncount > 0) {
+ findsent_forward(ncount, true);
+ } else {
decl(&curwin->w_cursor);
+ }
if (include) {
/*
@@ -3246,57 +3344,57 @@ extend:
if (start_blank) {
find_first_blank(&curwin->w_cursor);
c = gchar_pos(&curwin->w_cursor);
- if (ascii_iswhite(c))
+ if (ascii_iswhite(c)) {
decl(&curwin->w_cursor);
- } else if (c = gchar_cursor(), !ascii_iswhite(c))
+ }
+ } else if (c = gchar_cursor(), !ascii_iswhite(c)) {
find_first_blank(&start_pos);
+ }
}
if (VIsual_active) {
- /* Avoid getting stuck with "is" on a single space before a sentence. */
- if (equalpos(start_pos, curwin->w_cursor))
+ // Avoid getting stuck with "is" on a single space before a sentence.
+ if (equalpos(start_pos, curwin->w_cursor)) {
goto extend;
- if (*p_sel == 'e')
+ }
+ if (*p_sel == 'e') {
++curwin->w_cursor.col;
+ }
VIsual = start_pos;
VIsual_mode = 'v';
redraw_cmdline = true; // show mode later
redraw_curbuf_later(INVERTED); // update the inversion
} else {
- /* include a newline after the sentence, if there is one */
- if (incl(&curwin->w_cursor) == -1)
+ // include a newline after the sentence, if there is one
+ if (incl(&curwin->w_cursor) == -1) {
oap->inclusive = true;
- else
+ } else {
oap->inclusive = false;
+ }
oap->start = start_pos;
oap->motion_type = kMTCharWise;
}
return OK;
}
-/*
- * Find block under the cursor, cursor at end.
- * "what" and "other" are two matching parenthesis/brace/etc.
- */
-int
-current_block(
- oparg_T *oap,
- long count,
- int include, /* TRUE == include white space */
- int what, /* '(', '{', etc. */
- int other /* ')', '}', etc. */
-)
+/// Find block under the cursor, cursor at end.
+/// "what" and "other" are two matching parenthesis/brace/etc.
+///
+/// @param include TRUE == include white space
+/// @param what '(', '{', etc.
+/// @param other ')', '}', etc.
+int current_block(oparg_T *oap, long count, int include, int what, int other)
{
pos_T old_pos;
- pos_T *pos = NULL;
+ pos_T *pos = NULL;
pos_T start_pos;
- pos_T *end_pos;
+ pos_T *end_pos;
pos_T old_start, old_end;
- char_u *save_cpo;
- int sol = FALSE; /* '{' at start of line */
+ char_u *save_cpo;
+ bool sol = false; // '{' at start of line
old_pos = curwin->w_cursor;
- old_end = curwin->w_cursor; /* remember where we started */
+ old_end = curwin->w_cursor; // remember where we started
old_start = old_end;
/*
@@ -3304,18 +3402,23 @@ current_block(
*/
if (!VIsual_active || equalpos(VIsual, curwin->w_cursor)) {
setpcmark();
- if (what == '{') /* ignore indent */
- while (inindent(1))
- if (inc_cursor() != 0)
+ if (what == '{') { // ignore indent
+ while (inindent(1)) {
+ if (inc_cursor() != 0) {
break;
- if (gchar_cursor() == what)
- /* cursor on '(' or '{', move cursor just after it */
+ }
+ }
+ }
+ if (gchar_cursor() == what) {
+ // cursor on '(' or '{', move cursor just after it
++curwin->w_cursor.col;
+ }
} else if (lt(VIsual, curwin->w_cursor)) {
old_start = VIsual;
- curwin->w_cursor = VIsual; /* cursor at low end of Visual */
- } else
+ curwin->w_cursor = VIsual; // cursor at low end of Visual
+ } else {
old_end = VIsual;
+ }
// Search backwards for unclosed '(', '{', etc..
// Put this position in start_pos.
@@ -3351,7 +3454,7 @@ current_block(
sol = (curwin->w_cursor.col == 0);
decl(&curwin->w_cursor);
while (inindent(1)) {
- sol = TRUE;
+ sol = true;
if (decl(&curwin->w_cursor) != 0) {
break;
}
@@ -3376,8 +3479,9 @@ current_block(
return FAIL;
}
curwin->w_cursor = *end_pos;
- } else
+ } else {
break;
+ }
}
if (VIsual_active) {
@@ -3389,35 +3493,35 @@ current_block(
}
VIsual = start_pos;
VIsual_mode = 'v';
- redraw_curbuf_later(INVERTED); /* update the inversion */
+ redraw_curbuf_later(INVERTED); // update the inversion
showmode();
} else {
oap->start = start_pos;
oap->motion_type = kMTCharWise;
oap->inclusive = false;
- if (sol)
+ if (sol) {
incl(&curwin->w_cursor);
- else if (ltoreq(start_pos, curwin->w_cursor))
- /* Include the character under the cursor. */
+ } else if (ltoreq(start_pos, curwin->w_cursor)) {
+ // Include the character under the cursor.
oap->inclusive = true;
- else
+ } else {
/* End is before the start (no text in between <>, [], etc.): don't
* operate on any text. */
curwin->w_cursor = start_pos;
+ }
}
return OK;
}
-/*
- * Return TRUE if the cursor is on a "<aaa>" tag. Ignore "<aaa/>".
- * When "end_tag" is TRUE return TRUE if the cursor is on "</aaa>".
- */
-static int in_html_tag(int end_tag)
+/// @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/>".
+static bool in_html_tag(bool end_tag)
{
- char_u *line = get_cursor_line_ptr();
- char_u *p;
+ char_u *line = get_cursor_line_ptr();
+ char_u *p;
int c;
int lc = NUL;
pos_T pos;
@@ -3444,39 +3548,37 @@ static int in_html_tag(int end_tag)
return *p == '/';
}
- /* check that there is no '/' after the '<' */
- if (*p == '/')
- return FALSE;
+ // check that there is no '/' after the '<'
+ if (*p == '/') {
+ return false;
+ }
- /* check that the matching '>' is not preceded by '/' */
+ // check that the matching '>' is not preceded by '/'
for (;; ) {
- if (inc(&pos) < 0)
- return FALSE;
+ if (inc(&pos) < 0) {
+ return false;
+ }
c = *ml_get_pos(&pos);
- if (c == '>')
+ if (c == '>') {
break;
+ }
lc = c;
}
return lc != '/';
}
-/*
- * Find tag block under the cursor, cursor at end.
- */
-int
-current_tagblock(
- oparg_T *oap,
- long count_arg,
- bool include // true == include white space
-)
+/// Find tag block under the cursor, cursor at end.
+///
+/// @param include true == include white space
+int current_tagblock(oparg_T *oap, long count_arg, bool include)
{
long count = count_arg;
pos_T old_pos;
pos_T start_pos;
pos_T end_pos;
pos_T old_start, old_end;
- char_u *p;
- char_u *cp;
+ char_u *p;
+ char_u *cp;
int len;
bool do_include = include;
bool save_p_ws = p_ws;
@@ -3486,40 +3588,47 @@ current_tagblock(
p_ws = false;
old_pos = curwin->w_cursor;
- old_end = curwin->w_cursor; /* remember where we started */
+ old_end = curwin->w_cursor; // remember where we started
old_start = old_end;
- if (!VIsual_active || *p_sel == 'e')
- decl(&old_end); /* old_end is inclusive */
-
+ if (!VIsual_active || *p_sel == 'e') {
+ decl(&old_end); // old_end is inclusive
+ }
/*
* If we start on "<aaa>" select that block.
*/
if (!VIsual_active || equalpos(VIsual, curwin->w_cursor)) {
setpcmark();
- /* ignore indent */
- while (inindent(1))
- if (inc_cursor() != 0)
+ // ignore indent
+ while (inindent(1)) {
+ if (inc_cursor() != 0) {
break;
+ }
+ }
- if (in_html_tag(FALSE)) {
- /* cursor on start tag, move to its '>' */
- while (*get_cursor_pos_ptr() != '>')
- if (inc_cursor() < 0)
+ if (in_html_tag(false)) {
+ // cursor on start tag, move to its '>'
+ while (*get_cursor_pos_ptr() != '>') {
+ if (inc_cursor() < 0) {
break;
- } else if (in_html_tag(TRUE)) {
- /* cursor on end tag, move to just before it */
- while (*get_cursor_pos_ptr() != '<')
- if (dec_cursor() < 0)
+ }
+ }
+ } else if (in_html_tag(true)) {
+ // cursor on end tag, move to just before it
+ while (*get_cursor_pos_ptr() != '<') {
+ if (dec_cursor() < 0) {
break;
+ }
+ }
dec_cursor();
old_end = curwin->w_cursor;
}
} else if (lt(VIsual, curwin->w_cursor)) {
old_start = VIsual;
- curwin->w_cursor = VIsual; /* cursor at low end of Visual */
- } else
+ curwin->w_cursor = VIsual; // cursor at low end of Visual
+ } else {
old_end = VIsual;
+ }
again:
/*
@@ -3527,11 +3636,10 @@ again:
* Put this position in start_pos.
*/
for (long n = 0; n < count; n++) {
- if (do_searchpair(
- "<[^ \t>/!]\\+\\%(\\_s\\_[^>]\\{-}[^/]>\\|$\\|\\_s\\=>\\)",
- "",
- "</[^>]*>", BACKWARD, NULL, 0,
- NULL, (linenr_T)0, 0L) <= 0) {
+ if (do_searchpair("<[^ \t>/!]\\+\\%(\\_s\\_[^>]\\{-}[^/]>\\|$\\|\\_s\\=>\\)",
+ "",
+ "</[^>]*>", BACKWARD, NULL, 0,
+ NULL, (linenr_T)0, 0L) <= 0) {
curwin->w_cursor = old_pos;
goto theend;
}
@@ -3597,14 +3705,15 @@ again:
end_pos = curwin->w_cursor;
if (!do_include) {
- /* Exclude the start tag. */
+ // Exclude the start tag.
curwin->w_cursor = start_pos;
- while (inc_cursor() >= 0)
+ while (inc_cursor() >= 0) {
if (*get_cursor_pos_ptr() == '>') {
inc_cursor();
start_pos = curwin->w_cursor;
break;
}
+ }
curwin->w_cursor = end_pos;
// If we are in Visual mode and now have the same text as before set
@@ -3629,7 +3738,7 @@ again:
}
VIsual = start_pos;
VIsual_mode = 'v';
- redraw_curbuf_later(INVERTED); /* update the inversion */
+ redraw_curbuf_later(INVERTED); // update the inversion
showmode();
} else {
oap->start = start_pos;
@@ -3650,13 +3759,9 @@ theend:
return retval;
}
-int
-current_par(
- oparg_T *oap,
- long count,
- int include, /* TRUE == include white space */
- int type /* 'p' for paragraph, 'S' for section */
-)
+/// @param include TRUE == include white space
+/// @param type 'p' for paragraph, 'S' for section
+int current_par(oparg_T *oap, long count, int include, int type)
{
linenr_T start_lnum;
linenr_T end_lnum;
@@ -3669,8 +3774,9 @@ current_par(
int t;
int i;
- if (type == 'S') /* not implemented yet */
+ if (type == 'S') { // not implemented yet
return FAIL;
+ }
start_lnum = curwin->w_cursor.lnum;
@@ -3679,10 +3785,11 @@ current_par(
*/
if (VIsual_active && start_lnum != VIsual.lnum) {
extend:
- if (start_lnum < VIsual.lnum)
+ if (start_lnum < VIsual.lnum) {
dir = BACKWARD;
- else
+ } else {
dir = FORWARD;
+ }
for (i = count; --i >= 0; ) {
if (start_lnum ==
(dir == BACKWARD ? 1 : curbuf->b_ml.ml_line_count)) {
@@ -3700,20 +3807,24 @@ extend:
}
for (;; ) {
if (start_lnum == (dir == BACKWARD
- ? 1 : curbuf->b_ml.ml_line_count))
+ ? 1 : curbuf->b_ml.ml_line_count)) {
break;
+ }
if (start_is_white != linewhite(start_lnum + dir)
|| (!start_is_white
&& startPS(start_lnum + (dir > 0
- ? 1 : 0), 0, 0)))
+ ? 1 : 0), 0, 0))) {
break;
+ }
start_lnum += dir;
}
- if (!include)
+ if (!include) {
break;
+ }
if (start_lnum == (dir == BACKWARD
- ? 1 : curbuf->b_ml.ml_line_count))
+ ? 1 : curbuf->b_ml.ml_line_count)) {
break;
+ }
prev_start_is_white = start_is_white;
}
}
@@ -3727,12 +3838,14 @@ extend:
*/
white_in_front = linewhite(start_lnum);
while (start_lnum > 1) {
- if (white_in_front) { /* stop at first white line */
- if (!linewhite(start_lnum - 1))
+ if (white_in_front) { // stop at first white line
+ if (!linewhite(start_lnum - 1)) {
break;
- } else { /* stop at first non-white line of start of paragraph */
- if (linewhite(start_lnum - 1) || startPS(start_lnum, 0, 0))
+ }
+ } else { // stop at first non-white line of start of paragraph
+ if (linewhite(start_lnum - 1) || startPS(start_lnum, 0, 0)) {
break;
+ }
}
--start_lnum;
}
@@ -3741,19 +3854,23 @@ extend:
* Move past the end of any white lines.
*/
end_lnum = start_lnum;
- while (end_lnum <= curbuf->b_ml.ml_line_count && linewhite(end_lnum))
+ while (end_lnum <= curbuf->b_ml.ml_line_count && linewhite(end_lnum)) {
++end_lnum;
+ }
--end_lnum;
i = count;
- if (!include && white_in_front)
+ if (!include && white_in_front) {
--i;
+ }
while (i--) {
- if (end_lnum == curbuf->b_ml.ml_line_count)
+ if (end_lnum == curbuf->b_ml.ml_line_count) {
return FAIL;
+ }
- if (!include)
+ if (!include) {
do_white = linewhite(end_lnum + 1);
+ }
if (include || !do_white) {
++end_lnum;
@@ -3762,29 +3879,35 @@ extend:
*/
while (end_lnum < curbuf->b_ml.ml_line_count
&& !linewhite(end_lnum + 1)
- && !startPS(end_lnum + 1, 0, 0))
+ && !startPS(end_lnum + 1, 0, 0)) {
++end_lnum;
+ }
}
- if (i == 0 && white_in_front && include)
+ if (i == 0 && white_in_front && include) {
break;
+ }
/*
* skip to end of white lines after paragraph
*/
- if (include || do_white)
+ if (include || do_white) {
while (end_lnum < curbuf->b_ml.ml_line_count
- && linewhite(end_lnum + 1))
+ && linewhite(end_lnum + 1)) {
++end_lnum;
+ }
+ }
}
/*
* If there are no empty lines at the end, try to find some empty lines at
* the start (unless that has been done already).
*/
- if (!white_in_front && !linewhite(end_lnum) && include)
- while (start_lnum > 1 && linewhite(start_lnum - 1))
+ if (!white_in_front && !linewhite(end_lnum) && include) {
+ while (start_lnum > 1 && linewhite(start_lnum - 1)) {
--start_lnum;
+ }
+ }
if (VIsual_active) {
// Problem: when doing "Vipipip" nothing happens in a single white
@@ -3793,11 +3916,11 @@ extend:
goto extend;
}
if (VIsual.lnum != start_lnum) {
- VIsual.lnum = start_lnum;
- VIsual.col = 0;
+ VIsual.lnum = start_lnum;
+ VIsual.col = 0;
}
VIsual_mode = 'V';
- redraw_curbuf_later(INVERTED); /* update the inversion */
+ redraw_curbuf_later(INVERTED); // update the inversion
showmode();
} else {
oap->start.lnum = start_lnum;
@@ -3811,19 +3934,14 @@ extend:
}
-/*
- * Search quote char from string line[col].
- * Quote character escaped by one of the characters in "escape" is not counted
- * as a quote.
- * Returns column number of "quotechar" or -1 when not found.
- */
-static int
-find_next_quote(
- char_u *line,
- int col,
- int quotechar,
- char_u *escape /* escape characters, can be NULL */
-)
+/// Search quote char from string line[col].
+/// Quote character escaped by one of the characters in "escape" is not counted
+/// as a quote.
+///
+/// @param escape escape characters, can be NULL
+///
+/// @return column number of "quotechar" or -1 when not found.
+static int find_next_quote(char_u *line, int col, int quotechar, char_u *escape)
{
int c;
@@ -3841,19 +3959,14 @@ find_next_quote(
return col;
}
-/*
- * Search backwards in "line" from column "col_start" to find "quotechar".
- * Quote character escaped by one of the characters in "escape" is not counted
- * as a quote.
- * Return the found column or zero.
- */
-static int
-find_prev_quote(
- char_u *line,
- int col_start,
- int quotechar,
- char_u *escape /* escape characters, can be NULL */
-)
+/// Search backwards in "line" from column "col_start" to find "quotechar".
+/// Quote character escaped by one of the characters in "escape" is not counted
+/// as a quote.
+///
+/// @param escape escape characters, can be NULL
+///
+/// @return the found column or zero.
+static int find_prev_quote(char_u *line, int col_start, int quotechar, char_u *escape)
{
int n;
@@ -3861,29 +3974,32 @@ find_prev_quote(
col_start--;
col_start -= utf_head_off(line, line + col_start);
n = 0;
- if (escape != NULL)
+ if (escape != NULL) {
while (col_start - n > 0 && vim_strchr(escape,
- line[col_start - n - 1]) != NULL)
+ line[col_start - n - 1]) != NULL) {
++n;
- if (n & 1)
- col_start -= n; /* uneven number of escape chars, skip it */
- else if (line[col_start] == quotechar)
+ }
+ }
+ if (n & 1) {
+ col_start -= n; // uneven number of escape chars, skip it
+ } else if (line[col_start] ==
+ quotechar) {
break;
+ }
}
return col_start;
}
-// Find quote under the cursor, cursor at end.
-// Returns true if found, else false.
-bool current_quote(
- oparg_T *oap,
- long count,
- bool include, // true == include quote char
- int quotechar // Quote character
-)
+/// Find quote under the cursor, cursor at end.
+///
+/// @param include true == include quote char
+/// @param quotechar Quote character
+///
+/// @return true if found, else false.
+bool current_quote(oparg_T *oap, long count, bool include, int quotechar)
FUNC_ATTR_NONNULL_ALL
{
- char_u *line = get_cursor_line_ptr();
+ char_u *line = get_cursor_line_ptr();
int col_end;
int col_start = curwin->w_cursor.col;
bool inclusive = false;
@@ -3901,7 +4017,7 @@ bool current_quote(
if (VIsual_active) {
// this only works within one line
if (VIsual.lnum != curwin->w_cursor.lnum) {
- return false;
+ return false;
}
vis_bef_curs = lt(VIsual, curwin->w_cursor);
@@ -3946,12 +4062,13 @@ bool current_quote(
col_end = VIsual.col;
}
- /* Find out if we have a quote in the selection. */
- while (i <= col_end)
+ // Find out if we have a quote in the selection.
+ while (i <= col_end) {
if (line[i++] == quotechar) {
selected_quote = true;
break;
}
+ }
}
if (!vis_empty && line[col_start] == quotechar) {
@@ -3965,9 +4082,9 @@ bool current_quote(
goto abort_search;
}
col_end = find_next_quote(line, col_start + 1, quotechar,
- curbuf->b_p_qe);
+ curbuf->b_p_qe);
if (col_end < 0) {
- /* We were on a starting quote perhaps? */
+ // We were on a starting quote perhaps?
col_end = col_start;
col_start = curwin->w_cursor.col;
}
@@ -3977,23 +4094,23 @@ bool current_quote(
goto abort_search;
}
col_start = find_prev_quote(line, col_end, quotechar,
- curbuf->b_p_qe);
+ curbuf->b_p_qe);
if (line[col_start] != quotechar) {
- /* We were on an ending quote perhaps? */
+ // We were on an ending quote perhaps?
col_start = col_end;
col_end = curwin->w_cursor.col;
}
}
} else if (line[col_start] == quotechar
- || !vis_empty
- ) {
+ || !vis_empty) {
int first_col = col_start;
if (!vis_empty) {
- if (vis_bef_curs)
+ if (vis_bef_curs) {
first_col = find_next_quote(line, col_start, quotechar, NULL);
- else
+ } else {
first_col = find_prev_quote(line, col_start, quotechar, NULL);
+ }
}
/* The cursor is on a quote, we don't know if it's the opening or
* closing quote. Search from the start of the line to find out.
@@ -4001,14 +4118,14 @@ bool current_quote(
* in between two strings. */
col_start = 0;
for (;; ) {
- /* Find open quote character. */
+ // Find open quote character.
col_start = find_next_quote(line, col_start, quotechar, NULL);
if (col_start < 0 || col_start > first_col) {
goto abort_search;
}
// Find close quote character.
col_end = find_next_quote(line, col_start + 1, quotechar,
- curbuf->b_p_qe);
+ curbuf->b_p_qe);
if (col_end < 0) {
goto abort_search;
}
@@ -4020,17 +4137,17 @@ bool current_quote(
col_start = col_end + 1;
}
} else {
- /* Search backward for a starting quote. */
+ // Search backward for a starting quote.
col_start = find_prev_quote(line, col_start, quotechar, curbuf->b_p_qe);
if (line[col_start] != quotechar) {
- /* No quote before the cursor, look after the cursor. */
+ // No quote before the cursor, look after the cursor.
col_start = find_next_quote(line, col_start, quotechar, NULL);
if (col_start < 0) {
goto abort_search;
}
}
- /* Find close quote character. */
+ // Find close quote character.
col_end = find_next_quote(line, col_start + 1, quotechar,
curbuf->b_p_qe);
if (col_end < 0) {
@@ -4041,20 +4158,23 @@ bool current_quote(
// When "include" is true, include spaces after closing quote or before
// the starting quote.
if (include) {
- if (ascii_iswhite(line[col_end + 1]))
- while (ascii_iswhite(line[col_end + 1]))
+ if (ascii_iswhite(line[col_end + 1])) {
+ while (ascii_iswhite(line[col_end + 1])) {
++col_end;
- else
- while (col_start > 0 && ascii_iswhite(line[col_start - 1]))
+ }
+ } else {
+ while (col_start > 0 && ascii_iswhite(line[col_start - 1])) {
--col_start;
+ }
+ }
}
/* Set start position. After vi" another i" must include the ".
* For v2i" include the quotes. */
if (!include && count < 2
- && (vis_empty || !inside_quotes)
- )
+ && (vis_empty || !inside_quotes)) {
++col_start;
+ }
curwin->w_cursor.col = col_start;
if (VIsual_active) {
/* Set the start of the Visual area when the Visual area was empty, we
@@ -4076,13 +4196,14 @@ bool current_quote(
oap->motion_type = kMTCharWise;
}
- /* Set end position. */
+ // Set end position.
curwin->w_cursor.col = col_end;
if ((include || count > 1
- /* After vi" another i" must include the ". */
+ // After vi" another i" must include the ".
|| (!vis_empty && inside_quotes)
- ) && inc_cursor() == 2)
+ ) && inc_cursor() == 2) {
inclusive = true;
+ }
if (VIsual_active) {
if (vis_empty || vis_bef_curs) {
// decrement cursor when 'selection' is not exclusive
@@ -4105,10 +4226,10 @@ bool current_quote(
}
if (VIsual_mode == 'V') {
VIsual_mode = 'v';
- redraw_cmdline = TRUE; /* show mode later */
+ redraw_cmdline = true; // show mode later
}
} else {
- /* Set inclusive and other oap's flags. */
+ // Set inclusive and other oap's flags.
oap->inclusive = inclusive;
}
@@ -4120,10 +4241,10 @@ abort_search:
inc_cursor();
}
if (restore_vis_bef) {
- pos_T t = curwin->w_cursor;
+ pos_T t = curwin->w_cursor;
- curwin->w_cursor = VIsual;
- VIsual = t;
+ curwin->w_cursor = VIsual;
+ VIsual = t;
}
}
return false;
@@ -4131,22 +4252,19 @@ abort_search:
-/*
- * Find next search match under cursor, cursor at end.
- * Used while an operator is pending, and in Visual mode.
- */
-int
-current_search(
- long count,
- bool forward // true for forward, false for backward
-)
+/// Find next search match under cursor, cursor at end.
+/// Used while an operator is pending, and in Visual mode.
+///
+/// @param forward true for forward, false for backward
+int current_search(long count, bool forward)
{
bool old_p_ws = p_ws;
pos_T save_VIsual = VIsual;
- /* Correct cursor when 'selection' is exclusive */
- if (VIsual_active && *p_sel == 'e' && lt(VIsual, curwin->w_cursor))
+ // Correct cursor when 'selection' is exclusive
+ if (VIsual_active && *p_sel == 'e' && lt(VIsual, curwin->w_cursor)) {
dec_cursor();
+ }
pos_T end_pos; // end position of the pattern match
pos_T orig_pos; // position of the cursor at beginning
@@ -4156,7 +4274,7 @@ current_search(
// When searching forward and the cursor is at the start of the Visual
// area, skip the first search backward, otherwise it doesn't move.
const bool skip_first_backward = forward && VIsual_active
- && lt(curwin->w_cursor, VIsual);
+ && lt(curwin->w_cursor, VIsual);
orig_pos = pos = curwin->w_cursor;
if (VIsual_active) {
@@ -4214,8 +4332,9 @@ current_search(
// selection works.
if (i == 1 && !result) { // not found, abort */
curwin->w_cursor = orig_pos;
- if (VIsual_active)
+ if (VIsual_active) {
VIsual = save_VIsual;
+ }
return FAIL;
} else if (i == 0 && !result) {
if (forward) { // try again from start of buffer
@@ -4223,8 +4342,7 @@ current_search(
} else { // try again from end of buffer
// searching backwards, so set pos to last line and col
pos.lnum = curwin->w_buffer->b_ml.ml_line_count;
- pos.col = (colnr_T)STRLEN(
- ml_get(curwin->w_buffer->b_ml.ml_line_count));
+ pos.col = (colnr_T)STRLEN(ml_get(curwin->w_buffer->b_ml.ml_line_count));
}
}
}
@@ -4277,8 +4395,7 @@ current_search(
/// else from position "cur".
/// "direction" is FORWARD or BACKWARD.
/// Returns TRUE, FALSE or -1 for failure.
-static int
-is_zero_width(char_u *pattern, int move, pos_T *cur, Direction direction)
+static int is_zero_width(char_u *pattern, int move, pos_T *cur, Direction direction)
{
regmmatch_T regmatch;
int nmatched = 0;
@@ -4292,8 +4409,9 @@ is_zero_width(char_u *pattern, int move, pos_T *cur, Direction direction)
}
if (search_regcomp(pattern, RE_SEARCH, RE_SEARCH,
- SEARCH_KEEP, &regmatch) == FAIL)
+ SEARCH_KEEP, &regmatch) == FAIL) {
return -1;
+ }
// init startcol correctly
regmatch.startpos[0].col = -1;
@@ -4340,7 +4458,7 @@ is_zero_width(char_u *pattern, int move, pos_T *cur, Direction direction)
*/
int linewhite(linenr_T lnum)
{
- char_u *p;
+ char_u *p;
p = skipwhite(ml_get(lnum));
return *p == NUL;
@@ -4348,64 +4466,63 @@ int linewhite(linenr_T lnum)
// Add the search count "[3/19]" to "msgbuf".
// See update_search_stat() for other arguments.
-static void cmdline_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos,
- bool show_top_bot_msg, char_u *msgbuf,
- bool recompute, int maxcount, long timeout)
+static void cmdline_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, bool show_top_bot_msg,
+ char_u *msgbuf, bool recompute, int maxcount, long timeout)
{
- searchstat_T stat;
-
- update_search_stat(dirc, pos, cursor_pos, &stat, recompute, maxcount,
- timeout);
- if (stat.cur > 0) {
- char t[SEARCH_STAT_BUF_LEN];
-
- if (curwin->w_p_rl && *curwin->w_p_rlc == 's') {
- if (stat.incomplete == 1) {
- vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]");
- } else if (stat.cnt > maxcount && stat.cur > maxcount) {
- vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>%d/>%d]",
- maxcount, maxcount);
- } else if (stat.cnt > maxcount) {
- vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>%d/%d]",
- maxcount, stat.cur);
- } else {
- vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]",
- stat.cnt, stat.cur);
- }
+ searchstat_T stat;
+
+ update_search_stat(dirc, pos, cursor_pos, &stat, recompute, maxcount,
+ timeout);
+ if (stat.cur > 0) {
+ char t[SEARCH_STAT_BUF_LEN];
+
+ if (curwin->w_p_rl && *curwin->w_p_rlc == 's') {
+ if (stat.incomplete == 1) {
+ vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]");
+ } else if (stat.cnt > maxcount && stat.cur > maxcount) {
+ vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>%d/>%d]",
+ maxcount, maxcount);
+ } else if (stat.cnt > maxcount) {
+ vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>%d/%d]",
+ maxcount, stat.cur);
} else {
- if (stat.incomplete == 1) {
- vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]");
- } else if (stat.cnt > maxcount && stat.cur > maxcount) {
- vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>%d/>%d]",
- maxcount, maxcount);
- } else if (stat.cnt > maxcount) {
- vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/>%d]",
- stat.cur, maxcount);
- } else {
- vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]",
- stat.cur, stat.cnt);
- }
+ vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]",
+ stat.cnt, stat.cur);
}
-
- size_t len = strlen(t);
- if (show_top_bot_msg && len + 2 < SEARCH_STAT_BUF_LEN) {
- memmove(t + 2, t, len);
- t[0] = 'W';
- t[1] = ' ';
- len += 2;
+ } else {
+ if (stat.incomplete == 1) {
+ vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]");
+ } else if (stat.cnt > maxcount && stat.cur > maxcount) {
+ vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>%d/>%d]",
+ maxcount, maxcount);
+ } else if (stat.cnt > maxcount) {
+ vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/>%d]",
+ stat.cur, maxcount);
+ } else {
+ vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]",
+ stat.cur, stat.cnt);
}
+ }
- memmove(msgbuf + STRLEN(msgbuf) - len, t, len);
- if (dirc == '?' && stat.cur == maxcount + 1) {
- stat.cur = -1;
- }
+ size_t len = strlen(t);
+ if (show_top_bot_msg && len + 2 < SEARCH_STAT_BUF_LEN) {
+ memmove(t + 2, t, len);
+ t[0] = 'W';
+ t[1] = ' ';
+ len += 2;
+ }
- // keep the message even after redraw, but don't put in history
- msg_hist_off = true;
- msg_ext_set_kind("search_count");
- give_warning(msgbuf, false);
- msg_hist_off = false;
+ memmove(msgbuf + STRLEN(msgbuf) - len, t, len);
+ if (dirc == '?' && stat.cur == maxcount + 1) {
+ stat.cur = -1;
}
+
+ // keep the message even after redraw, but don't put in history
+ msg_hist_off = true;
+ msg_ext_set_kind("search_count");
+ give_warning(msgbuf, false);
+ msg_hist_off = false;
+ }
}
// Add the search count information to "stat".
@@ -4414,260 +4531,255 @@ static void cmdline_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos,
// dirc == 0: don't find the next/previous match (only set the result to "stat")
// dirc == '/': find the next match
// dirc == '?': find the previous match
-static void update_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos,
- searchstat_T *stat, bool recompute, int maxcount,
- long timeout)
+static void update_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, searchstat_T *stat,
+ bool recompute, int maxcount, long timeout)
{
- int save_ws = p_ws;
- bool wraparound = false;
- pos_T p = (*pos);
- static pos_T lastpos = { 0, 0, 0 };
- static int cur = 0;
- static int cnt = 0;
- static bool exact_match = false;
- static int incomplete = 0;
- static int last_maxcount = SEARCH_STAT_DEF_MAX_COUNT;
- static int chgtick = 0;
- static char_u *lastpat = NULL;
- static buf_T *lbuf = NULL;
- proftime_T start;
-
- memset(stat, 0, sizeof(searchstat_T));
-
- if (dirc == 0 && !recompute && !EMPTY_POS(lastpos)) {
- stat->cur = cur;
- stat->cnt = cnt;
- stat->exact_match = exact_match;
- stat->incomplete = incomplete;
- stat->last_maxcount = last_maxcount;
- return;
- }
- last_maxcount = maxcount;
- wraparound = ((dirc == '?' && lt(lastpos, p))
- || (dirc == '/' && lt(p, lastpos)));
-
- // If anything relevant changed the count has to be recomputed.
- // STRNICMP ignores case, but we should not ignore case.
- // Unfortunately, there is no STRNICMP function.
- // XXX: above comment should be "no MB_STRCMP function" ?
- if (!(chgtick == buf_get_changedtick(curbuf)
- && lastpat != NULL // supress clang/NULL passed as nonnull parameter
- && STRNICMP(lastpat, spats[last_idx].pat, STRLEN(lastpat)) == 0
- && STRLEN(lastpat) == STRLEN(spats[last_idx].pat)
- && equalpos(lastpos, *cursor_pos)
- && lbuf == curbuf)
- || wraparound || cur < 0 || (maxcount > 0 && cur > maxcount)
- || recompute) {
- cur = 0;
- cnt = 0;
- exact_match = false;
- incomplete = 0;
- clearpos(&lastpos);
- lbuf = curbuf;
- }
-
- if (equalpos(lastpos, *cursor_pos) && !wraparound
- && (dirc == 0 || dirc == '/' ? cur < cnt : cur > 0)) {
- cur += dirc == 0 ? 0 : dirc == '/' ? 1 : -1;
- } else {
- bool done_search = false;
- pos_T endpos = { 0, 0, 0 };
- p_ws = false;
- if (timeout > 0) {
- start = profile_setlimit(timeout);
- }
- while (!got_int && searchit(curwin, curbuf, &lastpos, &endpos,
- FORWARD, NULL, 1, SEARCH_KEEP, RE_LAST,
- NULL) != FAIL) {
- done_search = true;
- // Stop after passing the time limit.
- if (timeout > 0 && profile_passed_limit(start)) {
- incomplete = 1;
- break;
- }
- cnt++;
- if (ltoreq(lastpos, p)) {
- cur = cnt;
- if (lt(p, endpos)) {
- exact_match = true;
- }
- }
- fast_breakcheck();
- if (maxcount > 0 && cnt > maxcount) {
- incomplete = 2; // max count exceeded
- break;
- }
- }
- if (got_int) {
- cur = -1; // abort
- }
- if (done_search) {
- xfree(lastpat);
- lastpat = vim_strsave(spats[last_idx].pat);
- chgtick = buf_get_changedtick(curbuf);
- lbuf = curbuf;
- lastpos = p;
- }
- }
+ int save_ws = p_ws;
+ bool wraparound = false;
+ pos_T p = (*pos);
+ static pos_T lastpos = { 0, 0, 0 };
+ static int cur = 0;
+ static int cnt = 0;
+ static bool exact_match = false;
+ static int incomplete = 0;
+ static int last_maxcount = SEARCH_STAT_DEF_MAX_COUNT;
+ static int chgtick = 0;
+ static char_u *lastpat = NULL;
+ static buf_T *lbuf = NULL;
+ proftime_T start;
+
+ memset(stat, 0, sizeof(searchstat_T));
+
+ if (dirc == 0 && !recompute && !EMPTY_POS(lastpos)) {
stat->cur = cur;
stat->cnt = cnt;
stat->exact_match = exact_match;
stat->incomplete = incomplete;
stat->last_maxcount = last_maxcount;
- p_ws = save_ws;
+ return;
+ }
+ last_maxcount = maxcount;
+ wraparound = ((dirc == '?' && lt(lastpos, p))
+ || (dirc == '/' && lt(p, lastpos)));
+
+ // If anything relevant changed the count has to be recomputed.
+ // STRNICMP ignores case, but we should not ignore case.
+ // Unfortunately, there is no STRNICMP function.
+ // XXX: above comment should be "no MB_STRCMP function" ?
+ if (!(chgtick == buf_get_changedtick(curbuf)
+ && lastpat != NULL // suppress clang/NULL passed as nonnull parameter
+ && STRNICMP(lastpat, spats[last_idx].pat, STRLEN(lastpat)) == 0
+ && STRLEN(lastpat) == STRLEN(spats[last_idx].pat)
+ && equalpos(lastpos, *cursor_pos)
+ && lbuf == curbuf)
+ || wraparound || cur < 0 || (maxcount > 0 && cur > maxcount)
+ || recompute) {
+ cur = 0;
+ cnt = 0;
+ exact_match = false;
+ incomplete = 0;
+ clearpos(&lastpos);
+ lbuf = curbuf;
+ }
+
+ if (equalpos(lastpos, *cursor_pos) && !wraparound
+ && (dirc == 0 || dirc == '/' ? cur < cnt : cur > 0)) {
+ cur += dirc == 0 ? 0 : dirc == '/' ? 1 : -1;
+ } else {
+ bool done_search = false;
+ pos_T endpos = { 0, 0, 0 };
+ p_ws = false;
+ if (timeout > 0) {
+ start = profile_setlimit(timeout);
+ }
+ while (!got_int && searchit(curwin, curbuf, &lastpos, &endpos,
+ FORWARD, NULL, 1, SEARCH_KEEP, RE_LAST,
+ NULL) != FAIL) {
+ done_search = true;
+ // Stop after passing the time limit.
+ if (timeout > 0 && profile_passed_limit(start)) {
+ incomplete = 1;
+ break;
+ }
+ cnt++;
+ if (ltoreq(lastpos, p)) {
+ cur = cnt;
+ if (lt(p, endpos)) {
+ exact_match = true;
+ }
+ }
+ fast_breakcheck();
+ if (maxcount > 0 && cnt > maxcount) {
+ incomplete = 2; // max count exceeded
+ break;
+ }
+ }
+ if (got_int) {
+ cur = -1; // abort
+ }
+ if (done_search) {
+ xfree(lastpat);
+ lastpat = vim_strsave(spats[last_idx].pat);
+ chgtick = buf_get_changedtick(curbuf);
+ lbuf = curbuf;
+ lastpos = p;
+ }
+ }
+ stat->cur = cur;
+ stat->cnt = cnt;
+ stat->exact_match = exact_match;
+ stat->incomplete = incomplete;
+ stat->last_maxcount = last_maxcount;
+ p_ws = save_ws;
}
// "searchcount()" function
void f_searchcount(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- pos_T pos = curwin->w_cursor;
- char_u *pattern = NULL;
- int maxcount = SEARCH_STAT_DEF_MAX_COUNT;
- long timeout = SEARCH_STAT_DEF_TIMEOUT;
- bool recompute = true;
- searchstat_T stat;
+ pos_T pos = curwin->w_cursor;
+ char_u *pattern = NULL;
+ int maxcount = SEARCH_STAT_DEF_MAX_COUNT;
+ long timeout = SEARCH_STAT_DEF_TIMEOUT;
+ bool recompute = true;
+ searchstat_T stat;
- tv_dict_alloc_ret(rettv);
+ tv_dict_alloc_ret(rettv);
- if (shortmess(SHM_SEARCHCOUNT)) { // 'shortmess' contains 'S' flag
- recompute = true;
- }
+ if (shortmess(SHM_SEARCHCOUNT)) { // 'shortmess' contains 'S' flag
+ recompute = true;
+ }
- if (argvars[0].v_type != VAR_UNKNOWN) {
- dict_T *dict;
- dictitem_T *di;
- listitem_T *li;
- bool error = false;
+ if (argvars[0].v_type != VAR_UNKNOWN) {
+ dict_T *dict;
+ dictitem_T *di;
+ listitem_T *li;
+ bool error = false;
- if (argvars[0].v_type != VAR_DICT || argvars[0].vval.v_dict == NULL) {
- EMSG(_(e_dictreq));
+ if (argvars[0].v_type != VAR_DICT || argvars[0].vval.v_dict == NULL) {
+ EMSG(_(e_dictreq));
+ return;
+ }
+ dict = argvars[0].vval.v_dict;
+ di = tv_dict_find(dict, (const char *)"timeout", -1);
+ if (di != NULL) {
+ timeout = (long)tv_get_number_chk(&di->di_tv, &error);
+ if (error) {
return;
}
- dict = argvars[0].vval.v_dict;
- di = tv_dict_find(dict, (const char *)"timeout", -1);
- if (di != NULL) {
- timeout = (long)tv_get_number_chk(&di->di_tv, &error);
- if (error) {
- return;
- }
+ }
+ di = tv_dict_find(dict, (const char *)"maxcount", -1);
+ if (di != NULL) {
+ maxcount = (int)tv_get_number_chk(&di->di_tv, &error);
+ if (error) {
+ return;
}
- di = tv_dict_find(dict, (const char *)"maxcount", -1);
- if (di != NULL) {
- maxcount = (int)tv_get_number_chk(&di->di_tv, &error);
- if (error) {
- return;
- }
+ }
+ di = tv_dict_find(dict, (const char *)"recompute", -1);
+ if (di != NULL) {
+ recompute = tv_get_number_chk(&di->di_tv, &error);
+ if (error) {
+ return;
+ }
+ }
+ di = tv_dict_find(dict, (const char *)"pattern", -1);
+ if (di != NULL) {
+ pattern = (char_u *)tv_get_string_chk(&di->di_tv);
+ if (pattern == NULL) {
+ return;
}
- di = tv_dict_find(dict, (const char *)"recompute", -1);
- if (di != NULL) {
- recompute = tv_get_number_chk(&di->di_tv, &error);
+ }
+ di = tv_dict_find(dict, (const char *)"pos", -1);
+ if (di != NULL) {
+ if (di->di_tv.v_type != VAR_LIST) {
+ EMSG2(_(e_invarg2), "pos");
+ return;
+ }
+ if (tv_list_len(di->di_tv.vval.v_list) != 3) {
+ EMSG2(_(e_invarg2), "List format should be [lnum, col, off]");
+ return;
+ }
+ li = tv_list_find(di->di_tv.vval.v_list, 0L);
+ if (li != NULL) {
+ pos.lnum = tv_get_number_chk(TV_LIST_ITEM_TV(li), &error);
if (error) {
return;
}
}
- di = tv_dict_find(dict, (const char *)"pattern", -1);
- if (di != NULL) {
- pattern = (char_u *)tv_get_string_chk(&di->di_tv);
- if (pattern == NULL) {
+ li = tv_list_find(di->di_tv.vval.v_list, 1L);
+ if (li != NULL) {
+ pos.col = tv_get_number_chk(TV_LIST_ITEM_TV(li), &error) - 1;
+ if (error) {
return;
}
}
- di = tv_dict_find(dict, (const char *)"pos", -1);
- if (di != NULL) {
- if (di->di_tv.v_type != VAR_LIST) {
- EMSG2(_(e_invarg2), "pos");
- return;
- }
- if (tv_list_len(di->di_tv.vval.v_list) != 3) {
- EMSG2(_(e_invarg2), "List format should be [lnum, col, off]");
+ li = tv_list_find(di->di_tv.vval.v_list, 2L);
+ if (li != NULL) {
+ pos.coladd = tv_get_number_chk(TV_LIST_ITEM_TV(li), &error);
+ if (error) {
return;
}
- li = tv_list_find(di->di_tv.vval.v_list, 0L);
- if (li != NULL) {
- pos.lnum = tv_get_number_chk(TV_LIST_ITEM_TV(li), &error);
- if (error) {
- return;
- }
- }
- li = tv_list_find(di->di_tv.vval.v_list, 1L);
- if (li != NULL) {
- pos.col = tv_get_number_chk(TV_LIST_ITEM_TV(li), &error) - 1;
- if (error) {
- return;
- }
- }
- li = tv_list_find(di->di_tv.vval.v_list, 2L);
- if (li != NULL) {
- pos.coladd = tv_get_number_chk(TV_LIST_ITEM_TV(li), &error);
- if (error) {
- return;
- }
- }
}
}
+ }
- save_last_search_pattern();
- if (pattern != NULL) {
- if (*pattern == NUL) {
- goto the_end;
- }
- xfree(spats[last_idx].pat);
- spats[last_idx].pat = vim_strsave(pattern);
- }
- if (spats[last_idx].pat == NULL || *spats[last_idx].pat == NUL) {
- goto the_end; // the previous pattern was never defined
+ save_last_search_pattern();
+ if (pattern != NULL) {
+ if (*pattern == NUL) {
+ goto the_end;
}
+ xfree(spats[last_idx].pat);
+ spats[last_idx].pat = vim_strsave(pattern);
+ }
+ if (spats[last_idx].pat == NULL || *spats[last_idx].pat == NUL) {
+ goto the_end; // the previous pattern was never defined
+ }
- update_search_stat(0, &pos, &pos, &stat, recompute, maxcount, timeout);
+ update_search_stat(0, &pos, &pos, &stat, recompute, maxcount, timeout);
- tv_dict_add_nr(rettv->vval.v_dict, S_LEN("current"), stat.cur);
- tv_dict_add_nr(rettv->vval.v_dict, S_LEN("total"), stat.cnt);
- tv_dict_add_nr(rettv->vval.v_dict, S_LEN("exact_match"), stat.exact_match);
- tv_dict_add_nr(rettv->vval.v_dict, S_LEN("incomplete"), stat.incomplete);
- tv_dict_add_nr(rettv->vval.v_dict, S_LEN("maxcount"), stat.last_maxcount);
+ tv_dict_add_nr(rettv->vval.v_dict, S_LEN("current"), stat.cur);
+ tv_dict_add_nr(rettv->vval.v_dict, S_LEN("total"), stat.cnt);
+ tv_dict_add_nr(rettv->vval.v_dict, S_LEN("exact_match"), stat.exact_match);
+ tv_dict_add_nr(rettv->vval.v_dict, S_LEN("incomplete"), stat.incomplete);
+ tv_dict_add_nr(rettv->vval.v_dict, S_LEN("maxcount"), stat.last_maxcount);
the_end:
- restore_last_search_pattern();
+ restore_last_search_pattern();
}
-/*
- * Find identifiers or defines in included files.
- * If p_ic && (compl_cont_status & CONT_SOL) then ptr must be in lowercase.
- */
-void
-find_pattern_in_path(
- char_u *ptr, // pointer to search pattern
- Direction dir, // direction of expansion
- size_t len, // length of search pattern
- bool whole, // match whole words only
- bool skip_comments, // don't match inside comments
- int type, // Type of search; are we looking for a type?
- // a macro?
- long count,
- int action, // What to do when we find it
- linenr_T start_lnum, // first line to start searching
- linenr_T end_lnum // last line for searching
-)
+/// Find identifiers or defines in included files.
+/// If p_ic && (compl_cont_status & CONT_SOL) then ptr must be in lowercase.
+///
+/// @param ptr pointer to search pattern
+/// @param dir direction of expansion
+/// @param len length of search pattern
+/// @param whole match whole words only
+/// @param skip_comments don't match inside comments
+/// @param type Type of search; are we looking for a type? a macro?
+/// @param action What to do when we find it
+/// @param start_lnum first line to start searching
+/// @param end_lnum last line for searching
+void find_pattern_in_path(char_u *ptr, Direction dir, size_t len, bool whole, bool skip_comments,
+ int type, long count, int action, linenr_T start_lnum, linenr_T end_lnum)
{
- SearchedFile *files; /* Stack of included files */
- SearchedFile *bigger; /* When we need more space */
+ SearchedFile *files; // Stack of included files
+ SearchedFile *bigger; // When we need more space
int max_path_depth = 50;
long match_count = 1;
- char_u *pat;
- char_u *new_fname;
- char_u *curr_fname = curbuf->b_fname;
- char_u *prev_fname = NULL;
+ char_u *pat;
+ char_u *new_fname;
+ char_u *curr_fname = curbuf->b_fname;
+ char_u *prev_fname = NULL;
linenr_T lnum;
int depth;
- int depth_displayed; /* For type==CHECK_PATH */
+ int depth_displayed; // For type==CHECK_PATH
int old_files;
int already_searched;
- char_u *file_line;
- char_u *line;
- char_u *p;
+ char_u *file_line;
+ char_u *line;
+ char_u *p;
char_u save_char;
- int define_matched;
+ bool define_matched;
regmatch_T regmatch;
regmatch_T incl_regmatch;
regmatch_T def_regmatch;
@@ -4675,10 +4787,10 @@ find_pattern_in_path(
bool did_show = false;
bool found = false;
int i;
- char_u *already = NULL;
- char_u *startp = NULL;
- char_u *inc_opt = NULL;
- win_T *curwin_save = NULL;
+ char_u *already = NULL;
+ char_u *startp = NULL;
+ char_u *inc_opt = NULL;
+ win_T *curwin_save = NULL;
const int l_g_do_tagpreview = g_do_tagpreview;
regmatch.regprog = NULL;
@@ -4690,41 +4802,45 @@ find_pattern_in_path(
if (type != CHECK_PATH && type != FIND_DEFINE
/* when CONT_SOL is set compare "ptr" with the beginning of the line
* is faster than quote_meta/regcomp/regexec "ptr" -- Acevedo */
- && !(compl_cont_status & CONT_SOL)
- ) {
+ && !(compl_cont_status & CONT_SOL)) {
pat = xmalloc(len + 5);
assert(len <= INT_MAX);
sprintf((char *)pat, whole ? "\\<%.*s\\>" : "%.*s", (int)len, ptr);
- /* ignore case according to p_ic, p_scs and pat */
+ // ignore case according to p_ic, p_scs and pat
regmatch.rm_ic = ignorecase(pat);
regmatch.regprog = vim_regcomp(pat, p_magic ? RE_MAGIC : 0);
xfree(pat);
- if (regmatch.regprog == NULL)
+ if (regmatch.regprog == NULL) {
goto fpip_end;
+ }
}
inc_opt = (*curbuf->b_p_inc == NUL) ? p_inc : curbuf->b_p_inc;
if (*inc_opt != NUL) {
incl_regmatch.regprog = vim_regcomp(inc_opt, p_magic ? RE_MAGIC : 0);
- if (incl_regmatch.regprog == NULL)
+ if (incl_regmatch.regprog == NULL) {
goto fpip_end;
- incl_regmatch.rm_ic = FALSE; /* don't ignore case in incl. pat. */
+ }
+ incl_regmatch.rm_ic = FALSE; // don't ignore case in incl. pat.
}
if (type == FIND_DEFINE && (*curbuf->b_p_def != NUL || *p_def != NUL)) {
def_regmatch.regprog = vim_regcomp(*curbuf->b_p_def == NUL
? p_def : curbuf->b_p_def, p_magic ? RE_MAGIC : 0);
- if (def_regmatch.regprog == NULL)
+ if (def_regmatch.regprog == NULL) {
goto fpip_end;
- def_regmatch.rm_ic = FALSE; /* don't ignore case in define pat. */
+ }
+ def_regmatch.rm_ic = FALSE; // don't ignore case in define pat.
}
files = xcalloc(max_path_depth, sizeof(SearchedFile));
old_files = max_path_depth;
depth = depth_displayed = -1;
lnum = start_lnum;
- if (end_lnum > curbuf->b_ml.ml_line_count)
+ if (end_lnum > curbuf->b_ml.ml_line_count) {
end_lnum = curbuf->b_ml.ml_line_count;
- if (lnum > end_lnum) /* do at least one line */
+ }
+ if (lnum > end_lnum) { // do at least one line
lnum = end_lnum;
+ }
line = ml_get(lnum);
for (;; ) {
@@ -4733,17 +4849,18 @@ find_pattern_in_path(
char_u *p_fname = (curr_fname == curbuf->b_fname)
? curbuf->b_ffname : curr_fname;
- if (inc_opt != NULL && strstr((char *)inc_opt, "\\zs") != NULL)
- /* Use text from '\zs' to '\ze' (or end) of 'include'. */
+ if (inc_opt != NULL && strstr((char *)inc_opt, "\\zs") != NULL) {
+ // Use text from '\zs' to '\ze' (or end) of 'include'.
new_fname = find_file_name_in_path(incl_regmatch.startp[0],
(size_t)(incl_regmatch.endp[0]
- incl_regmatch.startp[0]),
FNAME_EXP|FNAME_INCL|FNAME_REL,
1L, p_fname);
- else
- /* Use text after match with 'include'. */
+ } else {
+ // Use text after match with 'include'.
new_fname = file_name_in_line(incl_regmatch.endp[0], 0,
- FNAME_EXP|FNAME_INCL|FNAME_REL, 1L, p_fname, NULL);
+ FNAME_EXP|FNAME_INCL|FNAME_REL, 1L, p_fname, NULL);
+ }
already_searched = FALSE;
if (new_fname != NULL) {
// Check whether we have already searched in this file
@@ -4788,15 +4905,17 @@ find_pattern_in_path(
did_show = true;
while (depth_displayed < depth && !got_int) {
++depth_displayed;
- for (i = 0; i < depth_displayed; i++)
+ for (i = 0; i < depth_displayed; i++) {
MSG_PUTS(" ");
+ }
msg_home_replace(files[depth_displayed].name);
MSG_PUTS(" -->\n");
}
if (!got_int) { /* don't display if 'q' typed
for "--more--" message */
- for (i = 0; i <= depth_displayed; i++)
+ for (i = 0; i <= depth_displayed; i++) {
MSG_PUTS(" ");
+ }
if (new_fname != NULL) {
/* using "new_fname" is more reliable, e.g., when
* 'includeexpr' is set. */
@@ -4808,21 +4927,23 @@ find_pattern_in_path(
*/
if (inc_opt != NULL
&& strstr((char *)inc_opt, "\\zs") != NULL) {
- /* pattern contains \zs, use the match */
+ // pattern contains \zs, use the match
p = incl_regmatch.startp[0];
i = (int)(incl_regmatch.endp[0]
- incl_regmatch.startp[0]);
} else {
- /* find the file name after the end of the match */
+ // find the file name after the end of the match
for (p = incl_regmatch.endp[0];
- *p && !vim_isfilec(*p); p++)
+ *p && !vim_isfilec(*p); p++) {
;
- for (i = 0; vim_isfilec(p[i]); i++)
+ }
+ for (i = 0; vim_isfilec(p[i]); i++) {
;
+ }
}
if (i == 0) {
- /* Nothing found, use the rest of the line. */
+ // Nothing found, use the rest of the line.
p = incl_regmatch.endp[0];
i = (int)STRLEN(p);
}
@@ -4833,8 +4954,9 @@ find_pattern_in_path(
--p;
++i;
}
- if (p[i] == '"' || p[i] == '>')
+ if (p[i] == '"' || p[i] == '>') {
++i;
+ }
}
save_char = p[i];
p[i] = NUL;
@@ -4843,29 +4965,32 @@ find_pattern_in_path(
}
if (new_fname == NULL && action == ACTION_SHOW_ALL) {
- if (already_searched)
+ if (already_searched) {
MSG_PUTS(_(" (Already listed)"));
- else
+ } else {
MSG_PUTS(_(" NOT FOUND"));
+ }
}
}
- ui_flush(); /* output each line directly */
+ ui_flush(); // output each line directly
}
if (new_fname != NULL) {
- /* Push the new file onto the file stack */
+ // Push the new file onto the file stack
if (depth + 1 == old_files) {
bigger = xmalloc(max_path_depth * 2 * sizeof(SearchedFile));
- for (i = 0; i <= depth; i++)
+ for (i = 0; i <= depth; i++) {
bigger[i] = files[i];
+ }
for (i = depth + 1; i < old_files + max_path_depth; i++) {
bigger[i].fp = NULL;
bigger[i].name = NULL;
bigger[i].lnum = 0;
bigger[i].matched = FALSE;
}
- for (i = old_files; i < max_path_depth; i++)
+ for (i = old_files; i < max_path_depth; i++) {
bigger[i + max_path_depth] = files[i];
+ }
old_files += max_path_depth;
max_path_depth *= 2;
xfree(files);
@@ -4892,10 +5017,9 @@ find_pattern_in_path(
} else if (p_verbose >= 5) {
verbose_enter();
smsg(_("Searching included file %s"),
- (char *)new_fname);
+ (char *)new_fname);
verbose_leave();
}
-
}
}
} else {
@@ -4904,7 +5028,7 @@ find_pattern_in_path(
*/
p = line;
search_line:
- define_matched = FALSE;
+ define_matched = false;
if (def_regmatch.regprog != NULL
&& vim_regexec(&def_regmatch, line, (colnr_T)0)) {
/*
@@ -4913,9 +5037,10 @@ search_line:
* don't let it match beyond the end of this identifier.
*/
p = def_regmatch.endp[0];
- while (*p && !vim_iswordc(*p))
+ while (*p && !vim_iswordc(*p)) {
p++;
- define_matched = TRUE;
+ }
+ define_matched = true;
}
/*
@@ -4924,18 +5049,18 @@ search_line:
*/
if (def_regmatch.regprog == NULL || define_matched) {
if (define_matched
- || (compl_cont_status & CONT_SOL)
- ) {
- /* compare the first "len" chars from "ptr" */
+ || (compl_cont_status & CONT_SOL)) {
+ // compare the first "len" chars from "ptr"
startp = skipwhite(p);
if (p_ic) {
matched = !mb_strnicmp(startp, ptr, len);
- }
- else
+ } else {
matched = !STRNCMP(startp, ptr, len);
+ }
if (matched && define_matched && whole
- && vim_iswordc(startp[len]))
+ && vim_iswordc(startp[len])) {
matched = false;
+ }
} else if (regmatch.regprog != NULL
&& vim_regexec(&regmatch, line, (colnr_T)(p - line))) {
matched = true;
@@ -4958,7 +5083,7 @@ search_line:
*/
p = skipwhite(line);
if (matched
- || (p[0] == '/' && p[1] == '*') || p[0] == '*')
+ || (p[0] == '/' && p[1] == '*') || p[0] == '*') {
for (p = line; *p && p < startp; ++p) {
if (matched
&& p[0] == '/'
@@ -4975,6 +5100,7 @@ search_line:
p++;
}
}
+ }
}
}
}
@@ -4982,35 +5108,39 @@ search_line:
if (matched) {
if (action == ACTION_EXPAND) {
bool cont_s_ipos = false;
- char_u *aux;
+ char_u *aux;
- if (depth == -1 && lnum == curwin->w_cursor.lnum)
+ if (depth == -1 && lnum == curwin->w_cursor.lnum) {
break;
+ }
found = true;
aux = p = startp;
if (compl_cont_status & CONT_ADDING) {
p += compl_length;
- if (vim_iswordp(p))
+ if (vim_iswordp(p)) {
goto exit_matched;
+ }
p = find_word_start(p);
}
p = find_word_end(p);
i = (int)(p - aux);
if ((compl_cont_status & CONT_ADDING) && i == compl_length) {
- /* IOSIZE > compl_length, so the STRNCPY works */
+ // IOSIZE > compl_length, so the STRNCPY works
STRNCPY(IObuff, aux, i);
/* Get the next line: when "depth" < 0 from the current
* buffer, otherwise from the included file. Jump to
* exit_matched when past the last line. */
if (depth < 0) {
- if (lnum >= end_lnum)
+ if (lnum >= end_lnum) {
goto exit_matched;
+ }
line = ml_get(++lnum);
} else if (vim_fgets(line = file_line,
- LSIZE, files[depth].fp))
+ LSIZE, files[depth].fp)) {
goto exit_matched;
+ }
/* we read a line, set "already" to check this "line" later
* if depth >= 0 we'll increase files[depth].lnum far
@@ -5020,9 +5150,10 @@ search_line:
p = find_word_end(p);
if (p > aux) {
if (*aux != ')' && IObuff[i-1] != TAB) {
- if (IObuff[i-1] != ' ')
+ if (IObuff[i-1] != ' ') {
IObuff[i++] = ' ';
- /* IObuf =~ "\(\k\|\i\).* ", thus i >= 2*/
+ }
+ // IObuf =~ "\(\k\|\i\).* ", thus i >= 2
if (p_js
&& (IObuff[i-2] == '.'
|| IObuff[i-2] == '?'
@@ -5030,9 +5161,10 @@ search_line:
IObuff[i++] = ' ';
}
}
- /* copy as much as possible of the new word */
- if (p - aux >= IOSIZE - i)
+ // copy as much as possible of the new word
+ if (p - aux >= IOSIZE - i) {
p = aux + IOSIZE - i - 1;
+ }
STRNCPY(IObuff + i, aux, p - aux);
i += (int)(p - aux);
cont_s_ipos = true;
@@ -5040,13 +5172,14 @@ search_line:
IObuff[i] = NUL;
aux = IObuff;
- if (i == compl_length)
+ if (i == compl_length) {
goto exit_matched;
+ }
}
- const int add_r = ins_compl_add_infercase(
- aux, i, p_ic, curr_fname == curbuf->b_fname ? NULL : curr_fname,
- dir, cont_s_ipos);
+ const int add_r = ins_compl_add_infercase(aux, i, p_ic,
+ curr_fname == curbuf->b_fname ? NULL : curr_fname,
+ dir, cont_s_ipos);
if (add_r == OK) {
// if dir was BACKWARD then honor it just once
dir = FORWARD;
@@ -5059,11 +5192,13 @@ search_line:
gotocmdline(true); // cursor at status line
}
if (curr_fname != prev_fname) {
- if (did_show)
- msg_putchar('\n'); /* cursor below last one */
- if (!got_int) /* don't display if 'q' typed
+ if (did_show) {
+ msg_putchar('\n'); // cursor below last one
+ }
+ if (!got_int) { /* don't display if 'q' typed
at "--more--" message */
msg_home_replace_hl(curr_fname);
+ }
prev_fname = curr_fname;
}
did_show = true;
@@ -5076,8 +5211,9 @@ search_line:
/* Set matched flag for this file and all the ones that
* include it */
- for (i = 0; i <= depth; ++i)
+ for (i = 0; i <= depth; ++i) {
files[i].matched = TRUE;
+ }
} else if (--count <= 0) {
found = true;
if (depth == -1 && lnum == curwin->w_cursor.lnum
@@ -5089,14 +5225,15 @@ search_line:
(depth == -1) ? &lnum : &files[depth].lnum, 1L);
did_show = true;
} else {
- /* ":psearch" uses the preview window */
+ // ":psearch" uses the preview window
if (l_g_do_tagpreview != 0) {
curwin_save = curwin;
prepare_tagpreview(true);
}
if (action == ACTION_SPLIT) {
- if (win_split(0, 0) == FAIL)
+ if (win_split(0, 0) == FAIL) {
break;
+ }
RESET_BINDING(curwin);
}
if (depth == -1) {
@@ -5128,7 +5265,7 @@ search_line:
if (l_g_do_tagpreview != 0
&& curwin != curwin_save && win_valid(curwin_save)) {
- /* Return cursor to where we were */
+ // Return cursor to where we were
validate_cursor();
redraw_later(curwin, VALID);
win_enter(curwin_save, true);
@@ -5148,10 +5285,12 @@ exit_matched:
}
}
line_breakcheck();
- if (action == ACTION_EXPAND)
+ if (action == ACTION_EXPAND) {
ins_compl_check_keys(30, false);
- if (got_int || compl_interrupted)
+ }
+ if (got_int || compl_interrupted) {
break;
+ }
/*
* Read the next line. When reading an included file and encountering
@@ -5166,55 +5305,62 @@ exit_matched:
files[old_files].matched = files[depth].matched;
--depth;
curr_fname = (depth == -1) ? curbuf->b_fname
- : files[depth].name;
- if (depth < depth_displayed)
+ : files[depth].name;
+ if (depth < depth_displayed) {
depth_displayed = depth;
+ }
}
- if (depth >= 0) { /* we could read the line */
+ if (depth >= 0) { // we could read the line
files[depth].lnum++;
- /* Remove any CR and LF from the line. */
+ // Remove any CR and LF from the line.
i = (int)STRLEN(line);
- if (i > 0 && line[i - 1] == '\n')
+ if (i > 0 && line[i - 1] == '\n') {
line[--i] = NUL;
- if (i > 0 && line[i - 1] == '\r')
+ }
+ if (i > 0 && line[i - 1] == '\r') {
line[--i] = NUL;
+ }
} else if (!already) {
- if (++lnum > end_lnum)
+ if (++lnum > end_lnum) {
break;
+ }
line = ml_get(lnum);
}
already = NULL;
}
- /* End of big for (;;) loop. */
+ // End of big for (;;) loop.
- /* Close any files that are still open. */
+ // Close any files that are still open.
for (i = 0; i <= depth; i++) {
fclose(files[i].fp);
xfree(files[i].name);
}
- for (i = old_files; i < max_path_depth; i++)
+ for (i = old_files; i < max_path_depth; i++) {
xfree(files[i].name);
+ }
xfree(files);
if (type == CHECK_PATH) {
if (!did_show) {
- if (action != ACTION_SHOW_ALL)
+ if (action != ACTION_SHOW_ALL) {
MSG(_("All included files were found"));
- else
+ } else {
MSG(_("No included files"));
+ }
}
} else if (!found
- && action != ACTION_EXPAND
- ) {
- if (got_int || compl_interrupted)
+ && action != ACTION_EXPAND) {
+ if (got_int || compl_interrupted) {
EMSG(_(e_interr));
- else if (type == FIND_DEFINE)
+ } else if (type == FIND_DEFINE) {
EMSG(_("E388: Couldn't find definition"));
- else
+ } else {
EMSG(_("E389: Couldn't find pattern"));
+ }
}
- if (action == ACTION_SHOW || action == ACTION_SHOW_ALL)
+ if (action == ACTION_SHOW || action == ACTION_SHOW_ALL) {
msg_end();
+ }
fpip_end:
xfree(file_line);
@@ -5223,11 +5369,11 @@ fpip_end:
vim_regfree(def_regmatch.regprog);
}
-static void show_pat_in_path(char_u *line, int type, bool did_show, int action,
- FILE *fp, linenr_T *lnum, long count)
+static void show_pat_in_path(char_u *line, int type, bool did_show, int action, FILE *fp,
+ linenr_T *lnum, long count)
FUNC_ATTR_NONNULL_ARG(1, 6)
{
- char_u *p;
+ char_u *p;
if (did_show) {
msg_putchar('\n'); // cursor below last one
@@ -5240,11 +5386,13 @@ static void show_pat_in_path(char_u *line, int type, bool did_show, int action,
for (;; ) {
p = line + STRLEN(line) - 1;
if (fp != NULL) {
- /* We used fgets(), so get rid of newline at end */
- if (p >= line && *p == '\n')
+ // We used fgets(), so get rid of newline at end
+ if (p >= line && *p == '\n') {
--p;
- if (p >= line && *p == '\r')
+ }
+ if (p >= line && *p == '\r') {
--p;
+ }
*(p + 1) = NUL;
}
if (action == ACTION_SHOW_ALL) {
@@ -5256,19 +5404,22 @@ static void show_pat_in_path(char_u *line, int type, bool did_show, int action,
msg_puts(" ");
}
msg_prt_line(line, FALSE);
- ui_flush(); /* show one line at a time */
+ ui_flush(); // show one line at a time
- /* Definition continues until line that doesn't end with '\' */
- if (got_int || type != FIND_DEFINE || p < line || *p != '\\')
+ // Definition continues until line that doesn't end with '\'
+ if (got_int || type != FIND_DEFINE || p < line || *p != '\\') {
break;
+ }
if (fp != NULL) {
- if (vim_fgets(line, LSIZE, fp)) /* end of file */
+ if (vim_fgets(line, LSIZE, fp)) { // end of file
break;
+ }
++*lnum;
} else {
- if (++*lnum > curbuf->b_ml.ml_line_count)
+ if (++*lnum > curbuf->b_ml.ml_line_count) {
break;
+ }
line = ml_get(*lnum);
}
msg_putchar('\n');
diff --git a/src/nvim/search.h b/src/nvim/search.h
index 98ddaa5eeb..0dbaf79c37 100644
--- a/src/nvim/search.h
+++ b/src/nvim/search.h
@@ -88,7 +88,7 @@ typedef struct searchstat
{
int cur; // current position of found words
int cnt; // total count of found words
- int exact_match; // TRUE if matched exactly on specified position
+ bool exact_match; // true if matched exactly on specified position
int incomplete; // 0: search was fully completed
// 1: recomputing was timed out
// 2: max count exceeded
diff --git a/src/nvim/sha256.c b/src/nvim/sha256.c
index a2378cc202..9d6a2f2c41 100644
--- a/src/nvim/sha256.c
+++ b/src/nvim/sha256.c
@@ -51,8 +51,7 @@ void sha256_start(context_sha256_T *ctx)
ctx->state[7] = 0x5BE0CD19;
}
-static void sha256_process(context_sha256_T *ctx,
- const char_u data[SHA256_BUFFER_SIZE])
+static void sha256_process(context_sha256_T *ctx, const char_u data[SHA256_BUFFER_SIZE])
{
uint32_t temp1, temp2, W[SHA256_BUFFER_SIZE];
uint32_t A, B, C, D, E, F, G, H;
@@ -88,7 +87,7 @@ static void sha256_process(context_sha256_T *ctx,
#define R(t) \
(W[t] = S1(W[t - 2]) + W[t - 7] + \
- S0(W[t - 15]) + W[t - 16])
+ S0(W[t - 15]) + W[t - 16])
#define P(a, b, c, d, e, f, g, h, x, K) { \
temp1 = h + S3(e) + F1(e, f, g) + K + x; \
@@ -188,7 +187,7 @@ void sha256_update(context_sha256_T *ctx, const char_u *input, size_t length)
uint32_t left = ctx->total[0] & (SHA256_BUFFER_SIZE-1); // left < buf size
- ctx->total[0] += (uint32_t) length;
+ ctx->total[0] += (uint32_t)length;
ctx->total[0] &= 0xFFFFFFFF;
if (ctx->total[0] < length) {
@@ -262,8 +261,8 @@ void sha256_finish(context_sha256_T *ctx, char_u digest[SHA256_SUM_SIZE])
///
/// @returns hex digest of "buf[buf_len]" in a static array.
/// if "salt" is not NULL also do "salt[salt_len]".
-const char *sha256_bytes(const uint8_t *restrict buf, size_t buf_len,
- const uint8_t *restrict salt, size_t salt_len)
+const char *sha256_bytes(const uint8_t *restrict buf, size_t buf_len, const uint8_t *restrict salt,
+ size_t salt_len)
{
char_u sha256sum[SHA256_SUM_SIZE];
static char hexit[SHA256_BUFFER_SIZE + 1]; // buf size + NULL
diff --git a/src/nvim/shada.c b/src/nvim/shada.c
index c0e787380f..bf245bec51 100644
--- a/src/nvim/shada.c
+++ b/src/nvim/shada.c
@@ -1,51 +1,50 @@
// 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 <stdlib.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include <string.h>
-#include <inttypes.h>
-#include <errno.h>
#include <assert.h>
-
+#include <errno.h>
+#include <inttypes.h>
#include <msgpack.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
#include <uv.h>
-#include "nvim/os/os.h"
-#include "nvim/os/time.h"
-#include "nvim/vim.h"
-#include "nvim/pos.h"
-#include "nvim/ascii.h"
-#include "nvim/shada.h"
-#include "nvim/message.h"
-#include "nvim/globals.h"
-#include "nvim/memory.h"
-#include "nvim/mark.h"
-#include "nvim/macros.h"
-#include "nvim/ops.h"
-#include "nvim/garray.h"
-#include "nvim/option.h"
-#include "nvim/msgpack_rpc/helpers.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
+#include "nvim/ascii.h"
#include "nvim/buffer.h"
#include "nvim/buffer_defs.h"
+#include "nvim/eval/decode.h"
+#include "nvim/eval/encode.h"
+#include "nvim/eval/typval.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
-#include "nvim/search.h"
-#include "nvim/regexp.h"
-#include "nvim/eval/typval.h"
-#include "nvim/version.h"
-#include "nvim/path.h"
#include "nvim/fileio.h"
-#include "nvim/os/fileio.h"
-#include "nvim/strings.h"
-#include "nvim/quickfix.h"
-#include "nvim/eval/encode.h"
-#include "nvim/eval/decode.h"
+#include "nvim/garray.h"
+#include "nvim/globals.h"
#include "nvim/lib/khash.h"
#include "nvim/lib/kvec.h"
+#include "nvim/macros.h"
+#include "nvim/mark.h"
+#include "nvim/memory.h"
+#include "nvim/message.h"
+#include "nvim/msgpack_rpc/helpers.h"
+#include "nvim/ops.h"
+#include "nvim/option.h"
+#include "nvim/os/fileio.h"
+#include "nvim/os/os.h"
+#include "nvim/os/time.h"
+#include "nvim/path.h"
+#include "nvim/pos.h"
+#include "nvim/quickfix.h"
+#include "nvim/regexp.h"
+#include "nvim/search.h"
+#include "nvim/shada.h"
+#include "nvim/strings.h"
+#include "nvim/version.h"
+#include "nvim/vim.h"
#ifdef HAVE_BE64TOH
# define _BSD_SOURCE 1
@@ -67,24 +66,24 @@ KHASH_MAP_INIT_STR(fnamebufs, buf_T *)
KHASH_SET_INIT_STR(strset)
#define copy_option_part(src, dest, ...) \
- ((char *) copy_option_part((char_u **) src, (char_u *) dest, __VA_ARGS__))
+ ((char *)copy_option_part((char_u **)src, (char_u *)dest, __VA_ARGS__))
#define find_shada_parameter(...) \
- ((const char *) find_shada_parameter(__VA_ARGS__))
+ ((const char *)find_shada_parameter(__VA_ARGS__))
#define home_replace_save(a, b) \
- ((char *)home_replace_save(a, (char_u *)b))
+ ((char *)home_replace_save(a, (char_u *)b))
#define home_replace(a, b, c, d, e) \
- home_replace(a, (char_u *)b, (char_u *)c, d, e)
+ home_replace(a, (char_u *)b, (char_u *)c, d, e)
#define vim_rename(a, b) \
- (vim_rename((char_u *)a, (char_u *)b))
+ (vim_rename((char_u *)a, (char_u *)b))
#define mb_strnicmp(a, b, c) \
- (mb_strnicmp((char_u *)a, (char_u *)b, c))
+ (mb_strnicmp((char_u *)a, (char_u *)b, c))
#define path_try_shorten_fname(b) \
- ((char *)path_try_shorten_fname((char_u *)b))
+ ((char *)path_try_shorten_fname((char_u *)b))
#define buflist_new(ffname, sfname, ...) \
- (buflist_new((char_u *)ffname, (char_u *)sfname, __VA_ARGS__))
-#define os_isdir(f) (os_isdir((char_u *) f))
-#define regtilde(s, m) ((char *) regtilde((char_u *) s, m))
-#define path_tail_with_sep(f) ((char *) path_tail_with_sep((char_u *)f))
+ (buflist_new((char_u *)ffname, (char_u *)sfname, __VA_ARGS__))
+#define os_isdir(f) (os_isdir((char_u *)f))
+#define regtilde(s, m) ((char *)regtilde((char_u *)s, m))
+#define path_tail_with_sep(f) ((char *)path_tail_with_sep((char_u *)f))
#define SEARCH_KEY_MAGIC "sm"
#define SEARCH_KEY_SMARTCASE "sc"
@@ -172,7 +171,7 @@ typedef enum {
kSDItemBufferList = 9, ///< Buffer list.
kSDItemLocalMark = 10, ///< Buffer-local mark.
kSDItemChange = 11, ///< Item from buffer change list.
-#define SHADA_LAST_ENTRY ((uint64_t) kSDItemChange)
+#define SHADA_LAST_ENTRY ((uint64_t)kSDItemChange)
} ShadaEntryType;
/// Possible results when reading ShaDa file
@@ -202,11 +201,11 @@ enum SRNIFlags {
kSDReadHeader = (1 << kSDItemHeader), ///< Determines whether header should
///< be read (it is usually ignored).
kSDReadUndisableableData = (
- (1 << kSDItemSearchPattern)
- | (1 << kSDItemSubString)
- | (1 << kSDItemJump)), ///< Data reading which cannot be disabled by
- ///< &shada or other options except for disabling
- ///< reading ShaDa as a whole.
+ (1 << kSDItemSearchPattern)
+ | (1 << kSDItemSubString)
+ | (1 << kSDItemJump)), ///< Data reading which cannot be disabled by
+ ///< &shada or other options except for disabling
+ ///< reading ShaDa as a whole.
kSDReadRegisters = (1 << kSDItemRegister), ///< Determines whether registers
///< should be read (may only be
///< disabled when writing, but
@@ -434,13 +433,13 @@ typedef struct sd_write_def {
#endif
#define DEF_SDE(name, attr, ...) \
- [kSDItem##name] = { \
- .timestamp = 0, \
- .type = kSDItem##name, \
- .data = { \
- .attr = { __VA_ARGS__ } \
- } \
- }
+ [kSDItem##name] = { \
+ .timestamp = 0, \
+ .type = kSDItem##name, \
+ .data = { \
+ .attr = { __VA_ARGS__ } \
+ } \
+ }
#define DEFAULT_POS { 1, 0, 0 }
static const pos_T default_pos = DEFAULT_POS;
static const ShadaEntry sd_default_values[] = {
@@ -475,9 +474,9 @@ static const ShadaEntry sd_default_values[] = {
DEF_SDE(Variable, global_var,
.name = NULL,
.value = {
- .v_type = VAR_UNKNOWN,
- .vval = { .v_string = NULL }
- },
+ .v_type = VAR_UNKNOWN,
+ .vval = { .v_string = NULL }
+ },
.additional_elements = NULL),
DEF_SDE(GlobalMark, filemark,
.name = '"',
@@ -533,17 +532,16 @@ 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) { \
- code \
- } \
+ for (HMLListEntry *cur_entry = (hmll)->first; cur_entry != NULL; \
+ cur_entry = cur_entry->next) { \
+ code \
+ } \
/// Remove entry from the linked list
///
/// @param hmll List to remove from.
/// @param hmll_entry Entry to remove.
-static inline void hmll_remove(HMLList *const hmll,
- HMLListEntry *const hmll_entry)
+static inline void hmll_remove(HMLList *const hmll, HMLListEntry *const hmll_entry)
FUNC_ATTR_NONNULL_ALL
{
if (hmll_entry == hmll->last_free_entry - 1) {
@@ -580,9 +578,7 @@ static inline void hmll_remove(HMLList *const hmll,
/// to insert at the first entry.
/// @param[in] data Data to insert.
/// @param[in] can_free_entry True if data can be freed.
-static inline void hmll_insert(HMLList *const hmll,
- HMLListEntry *hmll_entry,
- const ShadaEntry data,
+static inline void hmll_insert(HMLList *const hmll, HMLListEntry *hmll_entry, const ShadaEntry data,
const bool can_free_entry)
FUNC_ATTR_NONNULL_ARG(1)
{
@@ -595,11 +591,11 @@ static inline void hmll_insert(HMLList *const hmll,
}
HMLListEntry *target_entry;
if (hmll->free_entry == NULL) {
- assert((size_t) (hmll->last_free_entry - hmll->entries)
+ assert((size_t)(hmll->last_free_entry - hmll->entries)
== hmll->num_entries);
target_entry = hmll->last_free_entry++;
} else {
- assert((size_t) (hmll->last_free_entry - hmll->entries) - 1
+ assert((size_t)(hmll->last_free_entry - hmll->entries) - 1
== hmll->num_entries);
target_entry = hmll->free_entry;
hmll->free_entry = NULL;
@@ -637,10 +633,10 @@ static inline void hmll_insert(HMLList *const hmll,
///
/// @return `for` cycle header (use `HMLL_FORALL(hmll, cur_entry) {body}`).
#define HMLL_ITER_BACK(hmll, cur_entry, code) \
- for (cur_entry = (hmll)->last; cur_entry != NULL; \
- cur_entry = cur_entry->prev) { \
- code \
- }
+ for (cur_entry = (hmll)->last; cur_entry != NULL; \
+ cur_entry = cur_entry->prev) { \
+ code \
+ }
/// Free linked list
///
@@ -655,8 +651,7 @@ static inline void hmll_dealloc(HMLList *const hmll)
/// Wrapper for reading from file descriptors
///
/// @return -1 or number of bytes read.
-static ptrdiff_t read_file(ShaDaReadDef *const sd_reader, void *const dest,
- const size_t size)
+static ptrdiff_t read_file(ShaDaReadDef *const sd_reader, void *const dest, const size_t size)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
const ptrdiff_t ret = file_read(sd_reader->cookie, dest, size);
@@ -678,14 +673,13 @@ static int read_char(ShaDaReadDef *const sd_reader)
if (read_bytes != 1) {
return EOF;
}
- return (int) ret;
+ return (int)ret;
}
/// Wrapper for writing to file descriptors
///
/// @return -1 or number of bytes written.
-static ptrdiff_t write_file(ShaDaWriteDef *const sd_writer,
- const void *const dest,
+static ptrdiff_t write_file(ShaDaWriteDef *const sd_writer, const void *const dest,
const size_t size)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
@@ -720,8 +714,7 @@ static void close_sd_writer(ShaDaWriteDef *const sd_writer)
///
/// @return FAIL in case of failure, OK in case of success. May set
/// sd_reader->eof or sd_reader->error.
-static int sd_reader_skip_read(ShaDaReadDef *const sd_reader,
- const size_t offset)
+static int sd_reader_skip_read(ShaDaReadDef *const sd_reader, const size_t offset)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
const ptrdiff_t skip_bytes = file_skip(sd_reader->cookie, offset);
@@ -749,8 +742,7 @@ static int sd_reader_skip_read(ShaDaReadDef *const sd_reader,
///
/// @return kSDReadStatusReadError, kSDReadStatusNotShaDa or
/// kSDReadStatusSuccess.
-static ShaDaReadResult sd_reader_skip(ShaDaReadDef *const sd_reader,
- const size_t offset)
+static ShaDaReadResult sd_reader_skip(ShaDaReadDef *const sd_reader, const size_t offset)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
if (sd_reader->skip(sd_reader, offset) != OK) {
@@ -762,7 +754,7 @@ static ShaDaReadResult sd_reader_skip(ShaDaReadDef *const sd_reader,
emsgf(_(RCERR "Error while reading ShaDa file: "
"last entry specified that it occupies %" PRIu64 " bytes, "
"but file ended earlier"),
- (uint64_t) offset);
+ (uint64_t)offset);
return kSDReadStatusNotShaDa;
}
abort();
@@ -776,8 +768,7 @@ static ShaDaReadResult sd_reader_skip(ShaDaReadDef *const sd_reader,
/// @param[out] sd_reader Location where reader structure will be saved.
///
/// @return libuv error in case of error, 0 otherwise.
-static int open_shada_file_for_reading(const char *const fname,
- ShaDaReadDef *sd_reader)
+static int open_shada_file_for_reading(const char *const fname, ShaDaReadDef *sd_reader)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
int error;
@@ -819,7 +810,7 @@ static void close_file(void *cookie)
static inline bool in_bufset(const khash_t(bufset) *const set, const buf_T *buf)
FUNC_ATTR_PURE
{
- return kh_get(bufset, set, (uintptr_t) buf) != kh_end(set);
+ return kh_get(bufset, set, (uintptr_t)buf) != kh_end(set);
}
/// Check whether string is in the given set
@@ -837,7 +828,7 @@ static inline bool in_strset(const khash_t(strset) *const set, char *str)
/// Msgpack callback for writing to ShaDaWriteDef*
static int msgpack_sd_writer_write(void *data, const char *buf, size_t len)
{
- ShaDaWriteDef *const sd_writer = (ShaDaWriteDef *) data;
+ ShaDaWriteDef *const sd_writer = (ShaDaWriteDef *)data;
ptrdiff_t written_bytes = sd_writer->write(sd_writer, buf, len);
if (written_bytes == -1) {
emsgf(_(SERR "System error while writing ShaDa file: %s"),
@@ -910,10 +901,8 @@ static int shada_read_file(const char *const file, const int flags)
/// @param[out] hist Location where iteration results should be saved.
///
/// @return Next iteration state.
-static const void *shada_hist_iter(const void *const iter,
- const uint8_t history_type,
- const bool zero,
- ShadaEntry *const hist)
+static const void *shada_hist_iter(const void *const iter, const uint8_t history_type,
+ const bool zero, ShadaEntry *const hist)
FUNC_ATTR_NONNULL_ARG(4) FUNC_ATTR_WARN_UNUSED_RESULT
{
histentry_T hist_he;
@@ -927,9 +916,9 @@ static const void *shada_hist_iter(const void *const iter,
.data = {
.history_item = {
.histtype = history_type,
- .string = (char *) hist_he.hisstr,
- .sep = (char) (history_type == HIST_SEARCH
- ? (char) hist_he.hisstr[STRLEN(hist_he.hisstr) + 1]
+ .string = (char *)hist_he.hisstr,
+ .sep = (char)(history_type == HIST_SEARCH
+ ? (char)hist_he.hisstr[STRLEN(hist_he.hisstr) + 1]
: 0),
.additional_elements = hist_he.additional_elements,
}
@@ -954,8 +943,8 @@ static const void *shada_hist_iter(const void *const iter,
/// be used. Must be true only if inserting
/// entry from current Neovim history.
/// @param[in] can_free_entry True if entry can be freed.
-static void hms_insert(HistoryMergerState *const hms_p, const ShadaEntry entry,
- const bool do_iter, const bool can_free_entry)
+static void hms_insert(HistoryMergerState *const hms_p, const ShadaEntry entry, const bool do_iter,
+ const bool can_free_entry)
FUNC_ATTR_NONNULL_ALL
{
if (do_iter) {
@@ -1008,11 +997,8 @@ static void hms_insert(HistoryMergerState *const hms_p, const ShadaEntry entry,
/// @param[in] do_merge Prepare structure for merging elements.
/// @param[in] reading If true, then merger is reading history for use
/// in Neovim.
-static inline void hms_init(HistoryMergerState *const hms_p,
- const uint8_t history_type,
- const size_t num_elements,
- const bool do_merge,
- const bool reading)
+static inline void hms_init(HistoryMergerState *const hms_p, const uint8_t history_type,
+ const size_t num_elements, const bool do_merge, const bool reading)
FUNC_ATTR_NONNULL_ALL
{
hmll_init(&hms_p->hmll, num_elements);
@@ -1027,8 +1013,7 @@ static inline void hms_init(HistoryMergerState *const hms_p,
///
/// @param[in,out] hms_p Merger structure into which history should be
/// inserted.
-static inline void hms_insert_whole_neovim_history(
- HistoryMergerState *const hms_p)
+static inline void hms_insert_whole_neovim_history(HistoryMergerState *const hms_p)
FUNC_ATTR_NONNULL_ALL
{
while (hms_p->last_hist_entry.type != kSDItemMissing) {
@@ -1048,21 +1033,20 @@ static inline void hms_insert_whole_neovim_history(
/// @param[out] new_hisidx New last history entry index.
/// @param[out] new_hisnum Amount of history items in merger structure.
static inline void hms_to_he_array(const HistoryMergerState *const hms_p,
- histentry_T *const hist_array,
- int *const new_hisidx,
+ histentry_T *const hist_array, int *const new_hisidx,
int *const new_hisnum)
FUNC_ATTR_NONNULL_ALL
{
histentry_T *hist = hist_array;
HMLL_FORALL(&hms_p->hmll, cur_entry, {
hist->timestamp = cur_entry->data.timestamp;
- hist->hisnum = (int) (hist - hist_array) + 1;
- hist->hisstr = (char_u *) cur_entry->data.data.history_item.string;
+ hist->hisnum = (int)(hist - hist_array) + 1;
+ hist->hisstr = (char_u *)cur_entry->data.data.history_item.string;
hist->additional_elements =
- cur_entry->data.data.history_item.additional_elements;
+ cur_entry->data.data.history_item.additional_elements;
hist++;
})
- *new_hisnum = (int) (hist - hist_array);
+ *new_hisnum = (int)(hist - hist_array);
*new_hisidx = *new_hisnum - 1;
}
@@ -1083,7 +1067,7 @@ static inline void hms_dealloc(HistoryMergerState *const hms_p)
///
/// @return for cycle header. Use `HMS_ITER(hms_p, cur_entry) {body}`.
#define HMS_ITER(hms_p, cur_entry, code) \
- HMLL_FORALL(&((hms_p)->hmll), cur_entry, code)
+ HMLL_FORALL(&((hms_p)->hmll), cur_entry, code)
/// Find buffer for given buffer name (cached)
///
@@ -1091,8 +1075,7 @@ static inline void hms_dealloc(HistoryMergerState *const hms_p)
/// @param[in] fname File name to find.
///
/// @return Pointer to the buffer or NULL.
-static buf_T *find_buffer(khash_t(fnamebufs) *const fname_bufs,
- const char *const fname)
+static buf_T *find_buffer(khash_t(fnamebufs) *const fname_bufs, const char *const fname)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
int kh_ret;
@@ -1123,7 +1106,7 @@ 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]; \
@@ -1140,17 +1123,17 @@ static inline bool marks_equal(const pos_T a, const pos_T b)
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)); \
+ 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) { \
@@ -1177,8 +1160,8 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
const bool get_old_files = (flags & (kShaDaGetOldfiles | kShaDaForceit)
&& (force || tv_list_len(oldfiles_list) == 0));
const bool want_marks = flags & kShaDaWantMarks;
- const unsigned srni_flags = (unsigned) (
- (flags & kShaDaWantInfo
+ const unsigned srni_flags = (unsigned)(
+ (flags & kShaDaWantInfo
? (kSDReadUndisableableData
| kSDReadRegisters
| kSDReadGlobalMarks
@@ -1190,11 +1173,11 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
&& ARGCOUNT == 0
? kSDReadBufferList
: 0))
- : 0)
- | (want_marks && get_shada_parameter('\'') > 0
+ : 0)
+ | (want_marks && get_shada_parameter('\'') > 0
? kSDReadLocalMarks | kSDReadChanges
: 0)
- | (get_old_files
+ | (get_old_files
? kSDReadLocalMarks
: 0));
if (srni_flags == 0) {
@@ -1204,7 +1187,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
HistoryMergerState hms[HIST_COUNT];
if (srni_flags & kSDReadHistory) {
for (uint8_t i = 0; i < HIST_COUNT; i++) {
- hms_init(&hms[i], i, (size_t) p_hi, true, true);
+ hms_init(&hms[i], i, (size_t)p_hi, true, true);
}
}
ShadaEntry cur_entry;
@@ -1219,253 +1202,237 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
while ((srni_ret = shada_read_next_item(sd_reader, &cur_entry, srni_flags, 0))
!= kSDReadStatusFinished) {
switch (srni_ret) {
- case kSDReadStatusSuccess: {
- break;
- }
- case kSDReadStatusFinished: {
- // Should be handled by the while condition.
- abort();
- }
- case kSDReadStatusNotShaDa:
- case kSDReadStatusReadError: {
- goto shada_read_main_cycle_end;
- }
- case kSDReadStatusMalformed: {
- continue;
- }
+ case kSDReadStatusSuccess:
+ break;
+ case kSDReadStatusFinished:
+ // Should be handled by the while condition.
+ abort();
+ case kSDReadStatusNotShaDa:
+ case kSDReadStatusReadError:
+ goto shada_read_main_cycle_end;
+ case kSDReadStatusMalformed:
+ continue;
}
switch (cur_entry.type) {
- case kSDItemMissing: {
- abort();
- }
- case kSDItemUnknown: {
- break;
- }
- case kSDItemHeader: {
- shada_free_shada_entry(&cur_entry);
- break;
- }
- case kSDItemSearchPattern: {
- if (!force) {
- SearchPattern pat;
- (cur_entry.data.search_pattern.is_substitute_pattern
+ case kSDItemMissing:
+ abort();
+ case kSDItemUnknown:
+ break;
+ case kSDItemHeader:
+ shada_free_shada_entry(&cur_entry);
+ break;
+ case kSDItemSearchPattern:
+ if (!force) {
+ SearchPattern pat;
+ (cur_entry.data.search_pattern.is_substitute_pattern
? &get_substitute_pattern
: &get_search_pattern)(&pat);
- if (pat.pat != NULL && pat.timestamp >= cur_entry.timestamp) {
- shada_free_shada_entry(&cur_entry);
- break;
- }
+ if (pat.pat != NULL && pat.timestamp >= cur_entry.timestamp) {
+ shada_free_shada_entry(&cur_entry);
+ break;
}
- (cur_entry.data.search_pattern.is_substitute_pattern
+ }
+ (cur_entry.data.search_pattern.is_substitute_pattern
? &set_substitute_pattern
: &set_search_pattern)((SearchPattern) {
- .magic = cur_entry.data.search_pattern.magic,
- .no_scs = !cur_entry.data.search_pattern.smartcase,
- .off = {
- .dir = cur_entry.data.search_pattern.search_backward ? '?' : '/',
- .line = cur_entry.data.search_pattern.has_line_offset,
- .end = cur_entry.data.search_pattern.place_cursor_at_end,
- .off = cur_entry.data.search_pattern.offset,
- },
- .pat = (char_u *) cur_entry.data.search_pattern.pat,
- .additional_data = cur_entry.data.search_pattern.additional_data,
- .timestamp = cur_entry.timestamp,
- });
- if (cur_entry.data.search_pattern.is_last_used) {
- set_last_used_pattern(
- cur_entry.data.search_pattern.is_substitute_pattern);
- set_no_hlsearch(!cur_entry.data.search_pattern.highlighted);
- }
- // Do not free shada entry: its allocated memory was saved above.
- break;
- }
- case kSDItemSubString: {
- if (!force) {
- SubReplacementString sub;
- sub_get_replacement(&sub);
- if (sub.sub != NULL && sub.timestamp >= cur_entry.timestamp) {
- shada_free_shada_entry(&cur_entry);
- break;
- }
- }
- sub_set_replacement((SubReplacementString) {
- .sub = cur_entry.data.sub_string.sub,
- .timestamp = cur_entry.timestamp,
- .additional_elements = cur_entry.data.sub_string.additional_elements,
- });
- // Without using regtilde and without / &cpo flag previous substitute
- // string is close to useless: you can only use it with :& or :~ and
- // that’s all because s//~ is not available until the first call to
- // regtilde. Vim was not calling this for some reason.
- (void) regtilde(cur_entry.data.sub_string.sub, p_magic);
- // Do not free shada entry: its allocated memory was saved above.
- break;
+ .magic = cur_entry.data.search_pattern.magic,
+ .no_scs = !cur_entry.data.search_pattern.smartcase,
+ .off = {
+ .dir = cur_entry.data.search_pattern.search_backward ? '?' : '/',
+ .line = cur_entry.data.search_pattern.has_line_offset,
+ .end = cur_entry.data.search_pattern.place_cursor_at_end,
+ .off = cur_entry.data.search_pattern.offset,
+ },
+ .pat = (char_u *)cur_entry.data.search_pattern.pat,
+ .additional_data = cur_entry.data.search_pattern.additional_data,
+ .timestamp = cur_entry.timestamp,
+ });
+ if (cur_entry.data.search_pattern.is_last_used) {
+ set_last_used_pattern(cur_entry.data.search_pattern.is_substitute_pattern);
+ set_no_hlsearch(!cur_entry.data.search_pattern.highlighted);
}
- case kSDItemHistoryEntry: {
- if (cur_entry.data.history_item.histtype >= HIST_COUNT) {
+ // Do not free shada entry: its allocated memory was saved above.
+ break;
+ case kSDItemSubString:
+ if (!force) {
+ SubReplacementString sub;
+ sub_get_replacement(&sub);
+ if (sub.sub != NULL && sub.timestamp >= cur_entry.timestamp) {
shada_free_shada_entry(&cur_entry);
break;
}
- hms_insert(hms + cur_entry.data.history_item.histtype, cur_entry, true,
- true);
- // Do not free shada entry: its allocated memory was saved above.
+ }
+ sub_set_replacement((SubReplacementString) {
+ .sub = cur_entry.data.sub_string.sub,
+ .timestamp = cur_entry.timestamp,
+ .additional_elements = cur_entry.data.sub_string.additional_elements,
+ });
+ // Without using regtilde and without / &cpo flag previous substitute
+ // string is close to useless: you can only use it with :& or :~ and
+ // that’s all because s//~ is not available until the first call to
+ // regtilde. Vim was not calling this for some reason.
+ (void)regtilde(cur_entry.data.sub_string.sub, p_magic);
+ // Do not free shada entry: its allocated memory was saved above.
+ break;
+ case kSDItemHistoryEntry:
+ if (cur_entry.data.history_item.histtype >= HIST_COUNT) {
+ shada_free_shada_entry(&cur_entry);
+ break;
+ }
+ hms_insert(hms + cur_entry.data.history_item.histtype, cur_entry, true,
+ true);
+ // Do not free shada entry: its allocated memory was saved above.
+ break;
+ case kSDItemRegister:
+ if (cur_entry.data.reg.type != kMTCharWise
+ && cur_entry.data.reg.type != kMTLineWise
+ && cur_entry.data.reg.type != kMTBlockWise) {
+ shada_free_shada_entry(&cur_entry);
break;
}
- case kSDItemRegister: {
- if (cur_entry.data.reg.type != kMTCharWise
- && cur_entry.data.reg.type != kMTLineWise
- && cur_entry.data.reg.type != kMTBlockWise) {
+ if (!force) {
+ const yankreg_T *const reg = op_reg_get(cur_entry.data.reg.name);
+ if (reg == NULL || reg->timestamp >= cur_entry.timestamp) {
shada_free_shada_entry(&cur_entry);
break;
}
- if (!force) {
- const yankreg_T *const reg = op_reg_get(cur_entry.data.reg.name);
- if (reg == NULL || reg->timestamp >= cur_entry.timestamp) {
- shada_free_shada_entry(&cur_entry);
- break;
- }
- }
- if (!op_reg_set(cur_entry.data.reg.name, (yankreg_T) {
- .y_array = (char_u **)cur_entry.data.reg.contents,
- .y_size = cur_entry.data.reg.contents_size,
- .y_type = cur_entry.data.reg.type,
- .y_width = (colnr_T) cur_entry.data.reg.width,
- .timestamp = cur_entry.timestamp,
- .additional_data = cur_entry.data.reg.additional_data,
- }, cur_entry.data.reg.is_unnamed)) {
- shada_free_shada_entry(&cur_entry);
- }
- // Do not free shada entry: its allocated memory was saved above.
- break;
}
- case kSDItemVariable: {
- var_set_global(cur_entry.data.global_var.name,
- cur_entry.data.global_var.value);
- cur_entry.data.global_var.value.v_type = VAR_UNKNOWN;
+ if (!op_reg_set(cur_entry.data.reg.name, (yankreg_T) {
+ .y_array = (char_u **)cur_entry.data.reg.contents,
+ .y_size = cur_entry.data.reg.contents_size,
+ .y_type = cur_entry.data.reg.type,
+ .y_width = (colnr_T)cur_entry.data.reg.width,
+ .timestamp = cur_entry.timestamp,
+ .additional_data = cur_entry.data.reg.additional_data,
+ }, cur_entry.data.reg.is_unnamed)) {
shada_free_shada_entry(&cur_entry);
- break;
}
- case kSDItemJump:
- case kSDItemGlobalMark: {
- buf_T *buf = find_buffer(&fname_bufs, cur_entry.data.filemark.fname);
- if (buf != NULL) {
- XFREE_CLEAR(cur_entry.data.filemark.fname);
- }
- xfmark_T fm = (xfmark_T) {
- .fname = (char_u *) (buf == NULL
+ // Do not free shada entry: its allocated memory was saved above.
+ break;
+ case kSDItemVariable:
+ var_set_global(cur_entry.data.global_var.name,
+ cur_entry.data.global_var.value);
+ cur_entry.data.global_var.value.v_type = VAR_UNKNOWN;
+ shada_free_shada_entry(&cur_entry);
+ break;
+ case kSDItemJump:
+ case kSDItemGlobalMark: {
+ buf_T *buf = find_buffer(&fname_bufs, cur_entry.data.filemark.fname);
+ if (buf != NULL) {
+ XFREE_CLEAR(cur_entry.data.filemark.fname);
+ }
+ xfmark_T fm = (xfmark_T) {
+ .fname = (char_u *)(buf == NULL
? cur_entry.data.filemark.fname
: NULL),
- .fmark = {
- .mark = cur_entry.data.filemark.mark,
- .fnum = (buf == NULL ? 0 : buf->b_fnum),
- .timestamp = cur_entry.timestamp,
- .additional_data = cur_entry.data.filemark.additional_data,
- },
- };
- if (cur_entry.type == kSDItemGlobalMark) {
- if (!mark_set_global(cur_entry.data.filemark.name, fm, !force)) {
- shada_free_shada_entry(&cur_entry);
- break;
- }
- } else {
+ .fmark = {
+ .mark = cur_entry.data.filemark.mark,
+ .fnum = (buf == NULL ? 0 : buf->b_fnum),
+ .timestamp = cur_entry.timestamp,
+ .additional_data = cur_entry.data.filemark.additional_data,
+ },
+ };
+ if (cur_entry.type == kSDItemGlobalMark) {
+ if (!mark_set_global(cur_entry.data.filemark.name, fm, !force)) {
+ shada_free_shada_entry(&cur_entry);
+ break;
+ }
+ } else {
#define SDE_TO_XFMARK(entry) fm
#define ADJUST_IDX(i) \
- if (curwin->w_jumplistidx >= i \
- && curwin->w_jumplistidx + 1 <= curwin->w_jumplistlen) { \
- curwin->w_jumplistidx++; \
- }
+ if (curwin->w_jumplistidx >= i \
+ && curwin->w_jumplistidx + 1 <= curwin->w_jumplistlen) { \
+ curwin->w_jumplistidx++; \
+ }
#define DUMMY_AFTERFREE(entry)
- MERGE_JUMPS(curwin->w_jumplistlen, curwin->w_jumplist, xfmark_T,
- fmark.timestamp, fmark.mark, cur_entry,
- (buf == NULL
+ MERGE_JUMPS(curwin->w_jumplistlen, curwin->w_jumplist, xfmark_T,
+ fmark.timestamp, fmark.mark, cur_entry,
+ (buf == NULL
? (jl_entry.fname != NULL
&& STRCMP(fm.fname, jl_entry.fname) == 0)
: fm.fmark.fnum == jl_entry.fmark.fnum),
- free_xfmark, SDE_TO_XFMARK, ADJUST_IDX, DUMMY_AFTERFREE);
+ free_xfmark, SDE_TO_XFMARK, ADJUST_IDX, DUMMY_AFTERFREE);
#undef SDE_TO_XFMARK
#undef ADJUST_IDX
#undef DUMMY_AFTERFREE
- }
- // Do not free shada entry: its allocated memory was saved above.
- break;
}
- case kSDItemBufferList: {
- for (size_t i = 0; i < cur_entry.data.buffer_list.size; i++) {
- char *const sfname = path_try_shorten_fname(
- cur_entry.data.buffer_list.buffers[i].fname);
- buf_T *const buf = buflist_new(
- cur_entry.data.buffer_list.buffers[i].fname, sfname, 0,
- BLN_LISTED);
- if (buf != NULL) {
- RESET_FMARK(&buf->b_last_cursor,
- cur_entry.data.buffer_list.buffers[i].pos, 0);
- buflist_setfpos(buf, curwin, buf->b_last_cursor.mark.lnum,
- buf->b_last_cursor.mark.col, false);
- buf->additional_data =
- cur_entry.data.buffer_list.buffers[i].additional_data;
- cur_entry.data.buffer_list.buffers[i].additional_data = NULL;
- }
+ // Do not free shada entry: its allocated memory was saved above.
+ break;
+ }
+ case kSDItemBufferList:
+ for (size_t i = 0; i < cur_entry.data.buffer_list.size; i++) {
+ char *const sfname = path_try_shorten_fname(cur_entry.data.buffer_list.buffers[i].fname);
+ buf_T *const buf = buflist_new(cur_entry.data.buffer_list.buffers[i].fname, sfname, 0,
+ BLN_LISTED);
+ if (buf != NULL) {
+ RESET_FMARK(&buf->b_last_cursor,
+ cur_entry.data.buffer_list.buffers[i].pos, 0);
+ buflist_setfpos(buf, curwin, buf->b_last_cursor.mark.lnum,
+ buf->b_last_cursor.mark.col, false);
+ buf->additional_data =
+ cur_entry.data.buffer_list.buffers[i].additional_data;
+ cur_entry.data.buffer_list.buffers[i].additional_data = NULL;
}
- shada_free_shada_entry(&cur_entry);
- break;
}
- case kSDItemChange:
- case kSDItemLocalMark: {
- if (get_old_files && !in_strset(&oldfiles_set,
- cur_entry.data.filemark.fname)) {
- char *fname = cur_entry.data.filemark.fname;
- if (want_marks) {
- // Do not bother with allocating memory for the string if already
- // allocated string from cur_entry can be used. It cannot be used if
- // want_marks is set because this way it may be used for a mark.
- fname = xstrdup(fname);
- }
- int kh_ret;
- (void)kh_put(strset, &oldfiles_set, fname, &kh_ret);
- tv_list_append_allocated_string(oldfiles_list, fname);
- if (!want_marks) {
- // Avoid free because this string was already used.
- cur_entry.data.filemark.fname = NULL;
- }
+ shada_free_shada_entry(&cur_entry);
+ break;
+ case kSDItemChange:
+ case kSDItemLocalMark: {
+ if (get_old_files && !in_strset(&oldfiles_set,
+ cur_entry.data.filemark.fname)) {
+ char *fname = cur_entry.data.filemark.fname;
+ if (want_marks) {
+ // Do not bother with allocating memory for the string if already
+ // allocated string from cur_entry can be used. It cannot be used if
+ // want_marks is set because this way it may be used for a mark.
+ fname = xstrdup(fname);
}
+ int kh_ret;
+ (void)kh_put(strset, &oldfiles_set, fname, &kh_ret);
+ tv_list_append_allocated_string(oldfiles_list, fname);
if (!want_marks) {
- shada_free_shada_entry(&cur_entry);
- break;
+ // Avoid free because this string was already used.
+ cur_entry.data.filemark.fname = NULL;
}
- buf_T *buf = find_buffer(&fname_bufs, cur_entry.data.filemark.fname);
- if (buf == NULL) {
+ }
+ if (!want_marks) {
+ shada_free_shada_entry(&cur_entry);
+ break;
+ }
+ buf_T *buf = find_buffer(&fname_bufs, cur_entry.data.filemark.fname);
+ if (buf == NULL) {
+ shada_free_shada_entry(&cur_entry);
+ break;
+ }
+ const fmark_T fm = (fmark_T) {
+ .mark = cur_entry.data.filemark.mark,
+ .fnum = 0,
+ .timestamp = cur_entry.timestamp,
+ .additional_data = cur_entry.data.filemark.additional_data,
+ };
+ if (cur_entry.type == kSDItemLocalMark) {
+ if (!mark_set_local(cur_entry.data.filemark.name, buf, fm, !force)) {
shada_free_shada_entry(&cur_entry);
break;
}
- const fmark_T fm = (fmark_T) {
- .mark = cur_entry.data.filemark.mark,
- .fnum = 0,
- .timestamp = cur_entry.timestamp,
- .additional_data = cur_entry.data.filemark.additional_data,
- };
- if (cur_entry.type == kSDItemLocalMark) {
- if (!mark_set_local(cur_entry.data.filemark.name, buf, fm, !force)) {
- shada_free_shada_entry(&cur_entry);
- break;
- }
- } else {
- int kh_ret;
- (void) kh_put(bufset, &cl_bufs, (uintptr_t) buf, &kh_ret);
+ } else {
+ int kh_ret;
+ (void)kh_put(bufset, &cl_bufs, (uintptr_t)buf, &kh_ret);
#define SDE_TO_FMARK(entry) fm
#define AFTERFREE(entry) (entry).data.filemark.fname = NULL
#define DUMMY_IDX_ADJ(i)
- MERGE_JUMPS(buf->b_changelistlen, buf->b_changelist, fmark_T,
- timestamp, mark, cur_entry, true,
- free_fmark, SDE_TO_FMARK, DUMMY_IDX_ADJ, AFTERFREE);
+ MERGE_JUMPS(buf->b_changelistlen, buf->b_changelist, fmark_T,
+ timestamp, mark, cur_entry, true,
+ free_fmark, SDE_TO_FMARK, DUMMY_IDX_ADJ, AFTERFREE);
#undef SDE_TO_FMARK
#undef AFTERFREE
#undef DUMMY_IDX_ADJ
- }
- // Do not free shada entry: except for fname, its allocated memory (i.e.
- // additional_data attribute contents if non-NULL) was saved above.
- xfree(cur_entry.data.filemark.fname);
- break;
}
+ // Do not free shada entry: except for fname, its allocated memory (i.e.
+ // additional_data attribute contents if non-NULL) was saved above.
+ xfree(cur_entry.data.filemark.fname);
+ break;
+ }
}
}
shada_read_main_cycle_end:
@@ -1490,7 +1457,7 @@ shada_read_main_cycle_end:
}
if (cl_bufs.n_occupied) {
FOR_ALL_TAB_WINDOWS(tp, wp) {
- (void) tp;
+ (void)tp;
if (in_bufset(&cl_bufs, wp->w_buffer)) {
wp->w_changelistidx = wp->w_buffer->b_changelistlen;
}
@@ -1499,7 +1466,7 @@ shada_read_main_cycle_end:
kh_dealloc(bufset, &cl_bufs);
const char *key;
kh_foreach_key(&fname_bufs, key, {
- xfree((void *) key);
+ xfree((void *)key);
})
kh_dealloc(fnamebufs, &fname_bufs);
kh_dealloc(strset, &oldfiles_set);
@@ -1544,33 +1511,33 @@ static char *shada_filename(const char *file)
// If shell is not performing them then they should be done in main.c
// where arguments are parsed, *not here*.
expand_env((char_u *)file, &(NameBuff[0]), MAXPATHL);
- file = (const char *) &(NameBuff[0]);
+ file = (const char *)&(NameBuff[0]);
}
}
return xstrdup(file);
}
#define PACK_STATIC_STR(s) \
- do { \
- msgpack_pack_str(spacker, sizeof(s) - 1); \
- msgpack_pack_str_body(spacker, s, sizeof(s) - 1); \
- } while (0)
+ do { \
+ msgpack_pack_str(spacker, sizeof(s) - 1); \
+ msgpack_pack_str_body(spacker, s, sizeof(s) - 1); \
+ } while (0)
#define PACK_STRING(s) \
- do { \
- const String s_ = (s); \
- msgpack_pack_str(spacker, s_.size); \
- if (s_.size) { \
- msgpack_pack_str_body(spacker, s_.data, s_.size); \
- } \
- } while (0)
+ do { \
+ const String s_ = (s); \
+ msgpack_pack_str(spacker, s_.size); \
+ if (s_.size) { \
+ msgpack_pack_str_body(spacker, s_.data, s_.size); \
+ } \
+ } while (0)
#define PACK_BIN(s) \
- do { \
- const String s_ = (s); \
- msgpack_pack_bin(spacker, s_.size); \
- if (s_.size > 0) { \
- msgpack_pack_bin_body(spacker, s_.data, s_.size); \
- } \
- } while (0)
+ do { \
+ const String s_ = (s); \
+ msgpack_pack_bin(spacker, s_.size); \
+ if (s_.size > 0) { \
+ msgpack_pack_bin_body(spacker, s_.data, s_.size); \
+ } \
+ } while (0)
/// Write single ShaDa entry
///
@@ -1580,8 +1547,7 @@ static char *shada_filename(const char *file)
/// restrictions.
///
/// @return kSDWriteSuccessfull, kSDWriteFailed or kSDWriteIgnError.
-static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
- ShadaEntry entry,
+static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer, ShadaEntry entry,
const size_t max_kbyte)
FUNC_ATTR_NONNULL_ALL
{
@@ -1625,237 +1591,239 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
#define CHECK_DEFAULT(entry, attr) \
(sd_default_values[entry.type].data.attr == entry.data.attr)
#define ONE_IF_NOT_DEFAULT(entry, attr) \
- ((size_t) (!CHECK_DEFAULT(entry, attr)))
+ ((size_t)(!CHECK_DEFAULT(entry, attr)))
switch (entry.type) {
- case kSDItemMissing: {
- abort();
- }
- case kSDItemUnknown: {
- if (spacker->callback(spacker->data, entry.data.unknown_item.contents,
- (unsigned) entry.data.unknown_item.size) == -1) {
- goto shada_pack_entry_error;
- }
- break;
+ case kSDItemMissing:
+ abort();
+ case kSDItemUnknown:
+ if (spacker->callback(spacker->data, entry.data.unknown_item.contents,
+ (unsigned)entry.data.unknown_item.size) == -1) {
+ goto shada_pack_entry_error;
}
- case kSDItemHistoryEntry: {
- const bool is_hist_search =
- entry.data.history_item.histtype == HIST_SEARCH;
- const size_t arr_size = 2 + (size_t)is_hist_search + (size_t)(
- tv_list_len(entry.data.history_item.additional_elements));
- msgpack_pack_array(spacker, arr_size);
- msgpack_pack_uint8(spacker, entry.data.history_item.histtype);
- PACK_BIN(cstr_as_string(entry.data.history_item.string));
- if (is_hist_search) {
- msgpack_pack_uint8(spacker, (uint8_t)entry.data.history_item.sep);
- }
- DUMP_ADDITIONAL_ELEMENTS(entry.data.history_item.additional_elements,
- "history entry item");
- break;
+ break;
+ case kSDItemHistoryEntry: {
+ const bool is_hist_search =
+ entry.data.history_item.histtype == HIST_SEARCH;
+ const size_t arr_size = 2 + (size_t)is_hist_search + (size_t)(
+ tv_list_len(entry.data.
+ history_item.
+ additional_elements));
+ msgpack_pack_array(spacker, arr_size);
+ msgpack_pack_uint8(spacker, entry.data.history_item.histtype);
+ PACK_BIN(cstr_as_string(entry.data.history_item.string));
+ if (is_hist_search) {
+ msgpack_pack_uint8(spacker, (uint8_t)entry.data.history_item.sep);
}
- case kSDItemVariable: {
- const size_t arr_size = 2 + (size_t)(
- tv_list_len(entry.data.global_var.additional_elements));
- msgpack_pack_array(spacker, arr_size);
- const String varname = cstr_as_string(entry.data.global_var.name);
- PACK_BIN(varname);
- char vardesc[256] = "variable g:";
- memcpy(&vardesc[sizeof("variable g:") - 1], varname.data,
- varname.size + 1);
- if (encode_vim_to_msgpack(spacker, &entry.data.global_var.value, vardesc)
- == FAIL) {
- ret = kSDWriteIgnError;
- EMSG2(_(WERR "Failed to write variable %s"),
- entry.data.global_var.name);
- goto shada_pack_entry_error;
- }
- DUMP_ADDITIONAL_ELEMENTS(entry.data.global_var.additional_elements,
- "variable item");
- break;
+ DUMP_ADDITIONAL_ELEMENTS(entry.data.history_item.additional_elements,
+ "history entry item");
+ break;
+ }
+ case kSDItemVariable: {
+ if (entry.data.global_var.value.v_type == VAR_TYPE_BLOB) {
+ // Strings and Blobs both pack as msgpack BINs; differentiate them by
+ // storing an additional VAR_TYPE_BLOB element alongside Blobs
+ list_T *const list = tv_list_alloc(1);
+ tv_list_append_number(list, VAR_TYPE_BLOB);
+ entry.data.global_var.additional_elements = list;
}
- case kSDItemSubString: {
- const size_t arr_size = 1 + (size_t)(
- tv_list_len(entry.data.sub_string.additional_elements));
- msgpack_pack_array(spacker, arr_size);
- PACK_BIN(cstr_as_string(entry.data.sub_string.sub));
- DUMP_ADDITIONAL_ELEMENTS(entry.data.sub_string.additional_elements,
- "sub string item");
- break;
+ const size_t arr_size = 2 + (size_t)(
+ tv_list_len(entry.data.global_var.additional_elements));
+ msgpack_pack_array(spacker, arr_size);
+ const String varname = cstr_as_string(entry.data.global_var.name);
+ PACK_BIN(varname);
+ char vardesc[256] = "variable g:";
+ memcpy(&vardesc[sizeof("variable g:") - 1], varname.data,
+ varname.size + 1);
+ if (encode_vim_to_msgpack(spacker, &entry.data.global_var.value, vardesc)
+ == FAIL) {
+ ret = kSDWriteIgnError;
+ EMSG2(_(WERR "Failed to write variable %s"),
+ entry.data.global_var.name);
+ goto shada_pack_entry_error;
}
- case kSDItemSearchPattern: {
- const size_t map_size = (size_t) (
- 1 // Search pattern is always present
- + ONE_IF_NOT_DEFAULT(entry, search_pattern.magic)
- + ONE_IF_NOT_DEFAULT(entry, search_pattern.is_last_used)
- + ONE_IF_NOT_DEFAULT(entry, search_pattern.smartcase)
- + ONE_IF_NOT_DEFAULT(entry, search_pattern.has_line_offset)
- + ONE_IF_NOT_DEFAULT(entry, search_pattern.place_cursor_at_end)
- + ONE_IF_NOT_DEFAULT(entry, search_pattern.is_substitute_pattern)
- + ONE_IF_NOT_DEFAULT(entry, search_pattern.highlighted)
- + ONE_IF_NOT_DEFAULT(entry, search_pattern.offset)
- + ONE_IF_NOT_DEFAULT(entry, search_pattern.search_backward)
- // finally, additional data:
- + (size_t) (
- entry.data.search_pattern.additional_data
+ DUMP_ADDITIONAL_ELEMENTS(entry.data.global_var.additional_elements,
+ "variable item");
+ break;
+ }
+ case kSDItemSubString: {
+ const size_t arr_size = 1 + (size_t)(
+ tv_list_len(entry.data.sub_string.additional_elements));
+ msgpack_pack_array(spacker, arr_size);
+ PACK_BIN(cstr_as_string(entry.data.sub_string.sub));
+ DUMP_ADDITIONAL_ELEMENTS(entry.data.sub_string.additional_elements,
+ "sub string item");
+ break;
+ }
+ case kSDItemSearchPattern: {
+ const size_t map_size = (size_t)(
+ 1 // Search pattern is always present
+ + ONE_IF_NOT_DEFAULT(entry, search_pattern.magic)
+ + ONE_IF_NOT_DEFAULT(entry, search_pattern.is_last_used)
+ + ONE_IF_NOT_DEFAULT(entry, search_pattern.smartcase)
+ + ONE_IF_NOT_DEFAULT(entry, search_pattern.has_line_offset)
+ + ONE_IF_NOT_DEFAULT(entry, search_pattern.place_cursor_at_end)
+ + ONE_IF_NOT_DEFAULT(entry,
+ search_pattern.is_substitute_pattern)
+ + ONE_IF_NOT_DEFAULT(entry, search_pattern.highlighted)
+ + ONE_IF_NOT_DEFAULT(entry, search_pattern.offset)
+ + ONE_IF_NOT_DEFAULT(entry, search_pattern.search_backward)
+ // finally, additional data:
+ + (size_t)(
+ entry.data.search_pattern.additional_data
? entry.data.search_pattern.additional_data->dv_hashtab.ht_used
: 0));
- msgpack_pack_map(spacker, map_size);
- PACK_STATIC_STR(SEARCH_KEY_PAT);
- PACK_BIN(cstr_as_string(entry.data.search_pattern.pat));
+ msgpack_pack_map(spacker, map_size);
+ PACK_STATIC_STR(SEARCH_KEY_PAT);
+ PACK_BIN(cstr_as_string(entry.data.search_pattern.pat));
#define PACK_BOOL(entry, name, attr) \
- do { \
- if (!CHECK_DEFAULT(entry, search_pattern.attr)) { \
- PACK_STATIC_STR(name); \
- if (sd_default_values[entry.type].data.search_pattern.attr) { \
- msgpack_pack_false(spacker); \
- } else { \
- msgpack_pack_true(spacker); \
- } \
- } \
- } while (0)
- PACK_BOOL(entry, SEARCH_KEY_MAGIC, magic);
- PACK_BOOL(entry, SEARCH_KEY_IS_LAST_USED, is_last_used);
- PACK_BOOL(entry, SEARCH_KEY_SMARTCASE, smartcase);
- PACK_BOOL(entry, SEARCH_KEY_HAS_LINE_OFFSET, has_line_offset);
- PACK_BOOL(entry, SEARCH_KEY_PLACE_CURSOR_AT_END, place_cursor_at_end);
- PACK_BOOL(entry, SEARCH_KEY_IS_SUBSTITUTE_PATTERN, is_substitute_pattern);
- PACK_BOOL(entry, SEARCH_KEY_HIGHLIGHTED, highlighted);
- PACK_BOOL(entry, SEARCH_KEY_BACKWARD, search_backward);
- if (!CHECK_DEFAULT(entry, search_pattern.offset)) {
- PACK_STATIC_STR(SEARCH_KEY_OFFSET);
- msgpack_pack_int64(spacker, entry.data.search_pattern.offset);
- }
-#undef PACK_BOOL
- DUMP_ADDITIONAL_DATA(entry.data.search_pattern.additional_data,
- "search pattern item");
- break;
+ do { \
+ if (!CHECK_DEFAULT(entry, search_pattern.attr)) { \
+ PACK_STATIC_STR(name); \
+ if (sd_default_values[entry.type].data.search_pattern.attr) { \
+ msgpack_pack_false(spacker); \
+ } else { \
+ msgpack_pack_true(spacker); \
+ } \
+ } \
+ } while (0)
+ PACK_BOOL(entry, SEARCH_KEY_MAGIC, magic);
+ PACK_BOOL(entry, SEARCH_KEY_IS_LAST_USED, is_last_used);
+ PACK_BOOL(entry, SEARCH_KEY_SMARTCASE, smartcase);
+ PACK_BOOL(entry, SEARCH_KEY_HAS_LINE_OFFSET, has_line_offset);
+ PACK_BOOL(entry, SEARCH_KEY_PLACE_CURSOR_AT_END, place_cursor_at_end);
+ PACK_BOOL(entry, SEARCH_KEY_IS_SUBSTITUTE_PATTERN, is_substitute_pattern);
+ PACK_BOOL(entry, SEARCH_KEY_HIGHLIGHTED, highlighted);
+ PACK_BOOL(entry, SEARCH_KEY_BACKWARD, search_backward);
+ if (!CHECK_DEFAULT(entry, search_pattern.offset)) {
+ PACK_STATIC_STR(SEARCH_KEY_OFFSET);
+ msgpack_pack_int64(spacker, entry.data.search_pattern.offset);
}
- case kSDItemChange:
- case kSDItemGlobalMark:
- case kSDItemLocalMark:
- case kSDItemJump: {
- const size_t map_size = (size_t) (
- 1 // File name
- + ONE_IF_NOT_DEFAULT(entry, filemark.mark.lnum)
- + ONE_IF_NOT_DEFAULT(entry, filemark.mark.col)
- + ONE_IF_NOT_DEFAULT(entry, filemark.name)
- // Additional entries, if any:
- + (size_t) (
- entry.data.filemark.additional_data == NULL
+#undef PACK_BOOL
+ DUMP_ADDITIONAL_DATA(entry.data.search_pattern.additional_data,
+ "search pattern item");
+ break;
+ }
+ case kSDItemChange:
+ case kSDItemGlobalMark:
+ case kSDItemLocalMark:
+ case kSDItemJump: {
+ const size_t map_size = (size_t)(
+ 1 // File name
+ + ONE_IF_NOT_DEFAULT(entry, filemark.mark.lnum)
+ + ONE_IF_NOT_DEFAULT(entry, filemark.mark.col)
+ + ONE_IF_NOT_DEFAULT(entry, filemark.name)
+ // Additional entries, if any:
+ + (size_t)(
+ entry.data.filemark.additional_data == NULL
? 0
: entry.data.filemark.additional_data->dv_hashtab.ht_used));
- msgpack_pack_map(spacker, map_size);
- PACK_STATIC_STR(KEY_FILE);
- PACK_BIN(cstr_as_string(entry.data.filemark.fname));
- if (!CHECK_DEFAULT(entry, filemark.mark.lnum)) {
- PACK_STATIC_STR(KEY_LNUM);
- msgpack_pack_long(spacker, entry.data.filemark.mark.lnum);
- }
- if (!CHECK_DEFAULT(entry, filemark.mark.col)) {
- PACK_STATIC_STR(KEY_COL);
- msgpack_pack_long(spacker, entry.data.filemark.mark.col);
- }
- assert(entry.type == kSDItemJump || entry.type == kSDItemChange
+ msgpack_pack_map(spacker, map_size);
+ PACK_STATIC_STR(KEY_FILE);
+ PACK_BIN(cstr_as_string(entry.data.filemark.fname));
+ if (!CHECK_DEFAULT(entry, filemark.mark.lnum)) {
+ PACK_STATIC_STR(KEY_LNUM);
+ msgpack_pack_long(spacker, entry.data.filemark.mark.lnum);
+ }
+ if (!CHECK_DEFAULT(entry, filemark.mark.col)) {
+ PACK_STATIC_STR(KEY_COL);
+ msgpack_pack_long(spacker, entry.data.filemark.mark.col);
+ }
+ assert(entry.type == kSDItemJump || entry.type == kSDItemChange
? CHECK_DEFAULT(entry, filemark.name)
: true);
- if (!CHECK_DEFAULT(entry, filemark.name)) {
- PACK_STATIC_STR(KEY_NAME_CHAR);
- msgpack_pack_uint8(spacker, (uint8_t) entry.data.filemark.name);
- }
- DUMP_ADDITIONAL_DATA(entry.data.filemark.additional_data,
- "mark (change, jump, global or local) item");
- break;
+ if (!CHECK_DEFAULT(entry, filemark.name)) {
+ PACK_STATIC_STR(KEY_NAME_CHAR);
+ msgpack_pack_uint8(spacker, (uint8_t)entry.data.filemark.name);
}
- case kSDItemRegister: {
- const size_t map_size = (size_t) (
- 2 // Register contents and name
- + ONE_IF_NOT_DEFAULT(entry, reg.type)
- + ONE_IF_NOT_DEFAULT(entry, reg.width)
- + ONE_IF_NOT_DEFAULT(entry, reg.is_unnamed)
- // Additional entries, if any:
- + (size_t) (entry.data.reg.additional_data == NULL
+ DUMP_ADDITIONAL_DATA(entry.data.filemark.additional_data,
+ "mark (change, jump, global or local) item");
+ break;
+ }
+ case kSDItemRegister: {
+ const size_t map_size = (size_t)(
+ 2 // Register contents and name
+ + ONE_IF_NOT_DEFAULT(entry, reg.type)
+ + ONE_IF_NOT_DEFAULT(entry, reg.width)
+ + ONE_IF_NOT_DEFAULT(entry, reg.is_unnamed)
+ // Additional entries, if any:
+ + (size_t)(entry.data.reg.additional_data == NULL
? 0
: entry.data.reg.additional_data->dv_hashtab.ht_used));
- msgpack_pack_map(spacker, map_size);
- PACK_STATIC_STR(REG_KEY_CONTENTS);
- msgpack_pack_array(spacker, entry.data.reg.contents_size);
- for (size_t i = 0; i < entry.data.reg.contents_size; i++) {
- PACK_BIN(cstr_as_string(entry.data.reg.contents[i]));
- }
- PACK_STATIC_STR(KEY_NAME_CHAR);
- msgpack_pack_char(spacker, entry.data.reg.name);
- if (!CHECK_DEFAULT(entry, reg.type)) {
- PACK_STATIC_STR(REG_KEY_TYPE);
- msgpack_pack_uint8(spacker, (uint8_t)entry.data.reg.type);
- }
- if (!CHECK_DEFAULT(entry, reg.width)) {
- PACK_STATIC_STR(REG_KEY_WIDTH);
- msgpack_pack_uint64(spacker, (uint64_t) entry.data.reg.width);
- }
- if (!CHECK_DEFAULT(entry, reg.is_unnamed)) {
- PACK_STATIC_STR(REG_KEY_UNNAMED);
- if (entry.data.reg.is_unnamed) {
- msgpack_pack_true(spacker);
- } else {
- msgpack_pack_false(spacker);
- }
+ msgpack_pack_map(spacker, map_size);
+ PACK_STATIC_STR(REG_KEY_CONTENTS);
+ msgpack_pack_array(spacker, entry.data.reg.contents_size);
+ for (size_t i = 0; i < entry.data.reg.contents_size; i++) {
+ PACK_BIN(cstr_as_string(entry.data.reg.contents[i]));
+ }
+ PACK_STATIC_STR(KEY_NAME_CHAR);
+ msgpack_pack_char(spacker, entry.data.reg.name);
+ if (!CHECK_DEFAULT(entry, reg.type)) {
+ PACK_STATIC_STR(REG_KEY_TYPE);
+ msgpack_pack_uint8(spacker, (uint8_t)entry.data.reg.type);
+ }
+ if (!CHECK_DEFAULT(entry, reg.width)) {
+ PACK_STATIC_STR(REG_KEY_WIDTH);
+ msgpack_pack_uint64(spacker, (uint64_t)entry.data.reg.width);
+ }
+ if (!CHECK_DEFAULT(entry, reg.is_unnamed)) {
+ PACK_STATIC_STR(REG_KEY_UNNAMED);
+ if (entry.data.reg.is_unnamed) {
+ msgpack_pack_true(spacker);
+ } else {
+ msgpack_pack_false(spacker);
}
- DUMP_ADDITIONAL_DATA(entry.data.reg.additional_data, "register item");
- break;
}
- case kSDItemBufferList: {
- msgpack_pack_array(spacker, entry.data.buffer_list.size);
- for (size_t i = 0; i < entry.data.buffer_list.size; i++) {
- const size_t map_size = (size_t) (
- 1 // Buffer name
- + (size_t) (entry.data.buffer_list.buffers[i].pos.lnum
- != default_pos.lnum)
- + (size_t) (entry.data.buffer_list.buffers[i].pos.col
- != default_pos.col)
- // Additional entries, if any:
- + (size_t) (
- entry.data.buffer_list.buffers[i].additional_data == NULL
+ DUMP_ADDITIONAL_DATA(entry.data.reg.additional_data, "register item");
+ break;
+ }
+ case kSDItemBufferList:
+ msgpack_pack_array(spacker, entry.data.buffer_list.size);
+ for (size_t i = 0; i < entry.data.buffer_list.size; i++) {
+ const size_t map_size = (size_t)(
+ 1 // Buffer name
+ + (size_t)(entry.data.buffer_list.buffers[i].pos.lnum
+ != default_pos.lnum)
+ + (size_t)(entry.data.buffer_list.buffers[i].pos.col
+ != default_pos.col)
+ // Additional entries, if any:
+ + (size_t)(
+ entry.data.buffer_list.buffers[i].additional_data
+ == NULL
? 0
: (entry.data.buffer_list.buffers[i].additional_data
->dv_hashtab.ht_used)));
- msgpack_pack_map(spacker, map_size);
- PACK_STATIC_STR(KEY_FILE);
- PACK_BIN(cstr_as_string(entry.data.buffer_list.buffers[i].fname));
- if (entry.data.buffer_list.buffers[i].pos.lnum != 1) {
- PACK_STATIC_STR(KEY_LNUM);
- msgpack_pack_uint64(
- spacker, (uint64_t) entry.data.buffer_list.buffers[i].pos.lnum);
- }
- if (entry.data.buffer_list.buffers[i].pos.col != 0) {
- PACK_STATIC_STR(KEY_COL);
- msgpack_pack_uint64(
- spacker, (uint64_t) entry.data.buffer_list.buffers[i].pos.col);
- }
- DUMP_ADDITIONAL_DATA(entry.data.buffer_list.buffers[i].additional_data,
- "buffer list subitem");
+ msgpack_pack_map(spacker, map_size);
+ PACK_STATIC_STR(KEY_FILE);
+ PACK_BIN(cstr_as_string(entry.data.buffer_list.buffers[i].fname));
+ if (entry.data.buffer_list.buffers[i].pos.lnum != 1) {
+ PACK_STATIC_STR(KEY_LNUM);
+ msgpack_pack_uint64(spacker, (uint64_t)entry.data.buffer_list.buffers[i].pos.lnum);
}
- break;
+ if (entry.data.buffer_list.buffers[i].pos.col != 0) {
+ PACK_STATIC_STR(KEY_COL);
+ msgpack_pack_uint64(spacker, (uint64_t)entry.data.buffer_list.buffers[i].pos.col);
+ }
+ DUMP_ADDITIONAL_DATA(entry.data.buffer_list.buffers[i].additional_data,
+ "buffer list subitem");
}
- case kSDItemHeader: {
- msgpack_pack_map(spacker, entry.data.header.size);
- for (size_t i = 0; i < entry.data.header.size; i++) {
- PACK_STRING(entry.data.header.items[i].key);
- const Object obj = entry.data.header.items[i].value;
- switch (obj.type) {
- case kObjectTypeString: {
- PACK_BIN(obj.data.string);
- break;
- }
- case kObjectTypeInteger: {
- msgpack_pack_int64(spacker, (int64_t) obj.data.integer);
- break;
- }
- default: {
- abort();
- }
- }
+ break;
+ case kSDItemHeader:
+ msgpack_pack_map(spacker, entry.data.header.size);
+ for (size_t i = 0; i < entry.data.header.size; i++) {
+ PACK_STRING(entry.data.header.items[i].key);
+ const Object obj = entry.data.header.items[i].value;
+ switch (obj.type) {
+ case kObjectTypeString:
+ PACK_BIN(obj.data.string);
+ break;
+ case kObjectTypeInteger:
+ msgpack_pack_int64(spacker, (int64_t)obj.data.integer);
+ break;
+ default:
+ abort();
}
- break;
}
+ break;
}
#undef CHECK_DEFAULT
#undef ONE_IF_NOT_DEFAULT
@@ -1865,17 +1833,17 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer,
goto shada_pack_entry_error;
}
} else {
- if (msgpack_pack_uint64(packer, (uint64_t) entry.type) == -1) {
+ if (msgpack_pack_uint64(packer, (uint64_t)entry.type) == -1) {
goto shada_pack_entry_error;
}
}
- if (msgpack_pack_uint64(packer, (uint64_t) entry.timestamp) == -1) {
+ if (msgpack_pack_uint64(packer, (uint64_t)entry.timestamp) == -1) {
goto shada_pack_entry_error;
}
if (sbuf.size > 0) {
- if ((msgpack_pack_uint64(packer, (uint64_t) sbuf.size) == -1)
+ if ((msgpack_pack_uint64(packer, (uint64_t)sbuf.size) == -1)
|| (packer->callback(packer->data, sbuf.data,
- (unsigned) sbuf.size) == -1)) {
+ (unsigned)sbuf.size) == -1)) {
goto shada_pack_entry_error;
}
}
@@ -1898,9 +1866,9 @@ shada_pack_entry_error:
/// @param[in] entry Entry written.
/// @param[in] max_kbyte Maximum size of an item in KiB. Zero means no
/// restrictions.
-static inline ShaDaWriteResult shada_pack_pfreed_entry(
- msgpack_packer *const packer, PossiblyFreedShadaEntry entry,
- const size_t max_kbyte)
+static inline ShaDaWriteResult shada_pack_pfreed_entry(msgpack_packer *const packer,
+ PossiblyFreedShadaEntry entry,
+ const size_t max_kbyte)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_ALWAYS_INLINE
{
ShaDaWriteResult ret = kSDWriteSuccessfull;
@@ -1938,9 +1906,10 @@ static int compare_file_marks(const void *a, const void *b)
///
/// @return kSDReadStatusNotShaDa, kSDReadStatusReadError or
/// kSDReadStatusSuccess.
-static inline ShaDaReadResult shada_parse_msgpack(
- ShaDaReadDef *const sd_reader, const size_t length,
- msgpack_unpacked *ret_unpacked, char **const ret_buf)
+static inline ShaDaReadResult shada_parse_msgpack(ShaDaReadDef *const sd_reader,
+ const size_t length,
+ msgpack_unpacked *ret_unpacked,
+ char **const ret_buf)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1)
{
const uintmax_t initial_fpos = sd_reader->fpos;
@@ -1957,47 +1926,42 @@ shada_parse_msgpack_read_next: {}
msgpack_unpacked unpacked;
msgpack_unpacked_init(&unpacked);
const msgpack_unpack_return result =
- msgpack_unpack_next(&unpacked, buf, length, &off);
+ msgpack_unpack_next(&unpacked, buf, length, &off);
ShaDaReadResult ret = kSDReadStatusSuccess;
switch (result) {
- case MSGPACK_UNPACK_SUCCESS: {
- if (off < length) {
- goto shada_parse_msgpack_extra_bytes;
- }
- break;
+ case MSGPACK_UNPACK_SUCCESS:
+ if (off < length) {
+ goto shada_parse_msgpack_extra_bytes;
}
- case MSGPACK_UNPACK_PARSE_ERROR: {
- emsgf(_(RCERR "Failed to parse ShaDa file due to a msgpack parser error "
- "at position %" PRIu64),
- (uint64_t) initial_fpos);
- ret = kSDReadStatusNotShaDa;
- break;
+ break;
+ case MSGPACK_UNPACK_PARSE_ERROR:
+ emsgf(_(RCERR "Failed to parse ShaDa file due to a msgpack parser error "
+ "at position %" PRIu64),
+ (uint64_t)initial_fpos);
+ ret = kSDReadStatusNotShaDa;
+ break;
+ case MSGPACK_UNPACK_NOMEM_ERROR:
+ if (!did_try_to_free) {
+ did_try_to_free = true;
+ try_to_free_memory();
+ goto shada_parse_msgpack_read_next;
}
- case MSGPACK_UNPACK_NOMEM_ERROR: {
- if (!did_try_to_free) {
- did_try_to_free = true;
- try_to_free_memory();
- goto shada_parse_msgpack_read_next;
- }
- EMSG(_(e_outofmem));
- ret = kSDReadStatusReadError;
- break;
- }
- case MSGPACK_UNPACK_CONTINUE: {
- emsgf(_(RCERR "Failed to parse ShaDa file: incomplete msgpack string "
- "at position %" PRIu64),
- (uint64_t) initial_fpos);
- ret = kSDReadStatusNotShaDa;
- break;
- }
- case MSGPACK_UNPACK_EXTRA_BYTES: {
+ EMSG(_(e_outofmem));
+ ret = kSDReadStatusReadError;
+ break;
+ case MSGPACK_UNPACK_CONTINUE:
+ emsgf(_(RCERR "Failed to parse ShaDa file: incomplete msgpack string "
+ "at position %" PRIu64),
+ (uint64_t)initial_fpos);
+ ret = kSDReadStatusNotShaDa;
+ break;
+ case MSGPACK_UNPACK_EXTRA_BYTES:
shada_parse_msgpack_extra_bytes:
- emsgf(_(RCERR "Failed to parse ShaDa file: extra bytes in msgpack string "
- "at position %" PRIu64),
- (uint64_t) initial_fpos);
- ret = kSDReadStatusNotShaDa;
- break;
- }
+ emsgf(_(RCERR "Failed to parse ShaDa file: extra bytes in msgpack string "
+ "at position %" PRIu64),
+ (uint64_t)initial_fpos);
+ ret = kSDReadStatusNotShaDa;
+ break;
}
if (ret_buf != NULL && ret == kSDReadStatusSuccess) {
if (ret_unpacked == NULL) {
@@ -2027,81 +1991,67 @@ static const char *shada_format_entry(const ShadaEntry entry)
vim_snprintf(S_LEN(ret), "%s", "[ ] ts=%" PRIu64 " ");
// ^ Space for `can_free_entry`
switch (entry.type) {
- case kSDItemMissing: {
- vim_snprintf_add(S_LEN(ret), "Missing");
- break;
- }
- case kSDItemHeader: {
- vim_snprintf_add(S_LEN(ret), "Header { TODO }");
- break;
- }
- case kSDItemBufferList: {
- vim_snprintf_add(S_LEN(ret), "BufferList { TODO }");
- break;
- }
- case kSDItemUnknown: {
- vim_snprintf_add(S_LEN(ret), "Unknown { TODO }");
- break;
- }
- case kSDItemSearchPattern: {
- vim_snprintf_add(S_LEN(ret), "SearchPattern { TODO }");
- break;
- }
- case kSDItemSubString: {
- vim_snprintf_add(S_LEN(ret), "SubString { TODO }");
- break;
- }
- case kSDItemHistoryEntry: {
- vim_snprintf_add(S_LEN(ret), "HistoryEntry { TODO }");
- break;
- }
- case kSDItemRegister: {
- vim_snprintf_add(S_LEN(ret), "Register { TODO }");
- break;
- }
- case kSDItemVariable: {
- vim_snprintf_add(S_LEN(ret), "Variable { TODO }");
- break;
- }
+ case kSDItemMissing:
+ vim_snprintf_add(S_LEN(ret), "Missing");
+ break;
+ case kSDItemHeader:
+ vim_snprintf_add(S_LEN(ret), "Header { TODO }");
+ break;
+ case kSDItemBufferList:
+ vim_snprintf_add(S_LEN(ret), "BufferList { TODO }");
+ break;
+ case kSDItemUnknown:
+ vim_snprintf_add(S_LEN(ret), "Unknown { TODO }");
+ break;
+ case kSDItemSearchPattern:
+ vim_snprintf_add(S_LEN(ret), "SearchPattern { TODO }");
+ break;
+ case kSDItemSubString:
+ vim_snprintf_add(S_LEN(ret), "SubString { TODO }");
+ break;
+ case kSDItemHistoryEntry:
+ vim_snprintf_add(S_LEN(ret), "HistoryEntry { TODO }");
+ break;
+ case kSDItemRegister:
+ vim_snprintf_add(S_LEN(ret), "Register { TODO }");
+ break;
+ case kSDItemVariable:
+ vim_snprintf_add(S_LEN(ret), "Variable { TODO }");
+ break;
#define FORMAT_MARK_ENTRY(entry_name, name_fmt, name_fmt_arg) \
- do { \
- typval_T ad_tv = { \
- .v_type = VAR_DICT, \
- .vval.v_dict = entry.data.filemark.additional_data \
- }; \
- size_t ad_len; \
- char *const ad = encode_tv2string(&ad_tv, &ad_len); \
- vim_snprintf_add( \
- S_LEN(ret), \
- entry_name " {" name_fmt " file=[%zu]\"%.512s\", " \
- "pos={l=%" PRIdLINENR ",c=%" PRIdCOLNR ",a=%" PRIdCOLNR "}, " \
- "ad={%p:[%zu]%.64s} }", \
- name_fmt_arg, \
- strlen(entry.data.filemark.fname), \
- entry.data.filemark.fname, \
- entry.data.filemark.mark.lnum, \
- entry.data.filemark.mark.col, \
- entry.data.filemark.mark.coladd, \
- (void *)entry.data.filemark.additional_data, \
- ad_len, \
- ad); \
- } while (0)
- case kSDItemGlobalMark: {
- FORMAT_MARK_ENTRY("GlobalMark", " name='%c',", entry.data.filemark.name);
- break;
- }
- case kSDItemChange: {
- FORMAT_MARK_ENTRY("Change", "%s", "");
- break;
- }
- case kSDItemLocalMark: {
- FORMAT_MARK_ENTRY("LocalMark", " name='%c',", entry.data.filemark.name);
- break;
- }
- case kSDItemJump: {
- FORMAT_MARK_ENTRY("Jump", "%s", "");
- break;
- }
+ do { \
+ typval_T ad_tv = { \
+ .v_type = VAR_DICT, \
+ .vval.v_dict = entry.data.filemark.additional_data \
+ }; \
+ size_t ad_len; \
+ char *const ad = encode_tv2string(&ad_tv, &ad_len); \
+ vim_snprintf_add(S_LEN(ret), \
+ entry_name " {" name_fmt " file=[%zu]\"%.512s\", " \
+ "pos={l=%" PRIdLINENR ",c=%" PRIdCOLNR ",a=%" PRIdCOLNR "}, " \
+ "ad={%p:[%zu]%.64s} }", \
+ name_fmt_arg, \
+ strlen(entry.data.filemark.fname), \
+ entry.data.filemark.fname, \
+ entry.data.filemark.mark.lnum, \
+ entry.data.filemark.mark.col, \
+ entry.data.filemark.mark.coladd, \
+ (void *)entry.data.filemark.additional_data, \
+ ad_len, \
+ ad); \
+ } while (0)
+ case kSDItemGlobalMark:
+ FORMAT_MARK_ENTRY("GlobalMark", " name='%c',", entry.data.filemark.name);
+ break;
+ case kSDItemChange:
+ FORMAT_MARK_ENTRY("Change", "%s", "");
+ break;
+ case kSDItemLocalMark:
+ FORMAT_MARK_ENTRY("LocalMark", " name='%c',", entry.data.filemark.name);
+ break;
+ case kSDItemJump:
+ FORMAT_MARK_ENTRY("Jump", "%s", "");
+ break;
#undef FORMAT_MARK_ENTRY
}
return ret;
@@ -2112,8 +2062,7 @@ static const char *shada_format_entry(const ShadaEntry entry)
/// @param[in] entry ShaDa entry to format.
///
/// @return string representing ShaDa entry in a static buffer.
-static const char *shada_format_pfreed_entry(
- const PossiblyFreedShadaEntry pfs_entry)
+static const char *shada_format_pfreed_entry(const PossiblyFreedShadaEntry pfs_entry)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_UNUSED FUNC_ATTR_NONNULL_RET
{
char *ret = (char *)shada_format_entry(pfs_entry.data);
@@ -2129,10 +2078,11 @@ static const char *shada_format_pfreed_entry(
/// @param[in,out] ret_wms Location where results are saved.
/// @param[out] packer MessagePack packer for entries which are not
/// merged.
-static inline ShaDaWriteResult shada_read_when_writing(
- ShaDaReadDef *const sd_reader, const unsigned srni_flags,
- const size_t max_kbyte, WriteMergerState *const wms,
- msgpack_packer *const packer)
+static inline ShaDaWriteResult shada_read_when_writing(ShaDaReadDef *const sd_reader,
+ const unsigned srni_flags,
+ const size_t max_kbyte,
+ WriteMergerState *const wms,
+ msgpack_packer *const packer)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
ShaDaWriteResult ret = kSDWriteSuccessfull;
@@ -2142,217 +2092,202 @@ static inline ShaDaWriteResult shada_read_when_writing(
max_kbyte))
!= kSDReadStatusFinished) {
switch (srni_ret) {
- case kSDReadStatusSuccess: {
- break;
- }
- case kSDReadStatusFinished: {
- // Should be handled by the while condition.
- abort();
- }
- case kSDReadStatusNotShaDa: {
- ret = kSDWriteReadNotShada;
- FALLTHROUGH;
- }
- case kSDReadStatusReadError: {
- return ret;
- }
- case kSDReadStatusMalformed: {
- continue;
- }
+ case kSDReadStatusSuccess:
+ break;
+ case kSDReadStatusFinished:
+ // Should be handled by the while condition.
+ abort();
+ case kSDReadStatusNotShaDa:
+ ret = kSDWriteReadNotShada;
+ FALLTHROUGH;
+ case kSDReadStatusReadError:
+ return ret;
+ case kSDReadStatusMalformed:
+ continue;
}
#define COMPARE_WITH_ENTRY(wms_entry_, entry) \
- do { \
- PossiblyFreedShadaEntry *const wms_entry = (wms_entry_); \
- if (wms_entry->data.type != kSDItemMissing) { \
- if (wms_entry->data.timestamp >= (entry).timestamp) { \
- shada_free_shada_entry(&(entry)); \
- break; \
- } \
- if (wms_entry->can_free_entry) { \
- shada_free_shada_entry(&wms_entry->data); \
- } \
+ do { \
+ PossiblyFreedShadaEntry *const wms_entry = (wms_entry_); \
+ if (wms_entry->data.type != kSDItemMissing) { \
+ if (wms_entry->data.timestamp >= (entry).timestamp) { \
+ shada_free_shada_entry(&(entry)); \
+ break; \
} \
- *wms_entry = pfs_entry; \
- } while (0)
+ if (wms_entry->can_free_entry) { \
+ shada_free_shada_entry(&wms_entry->data); \
+ } \
+ } \
+ *wms_entry = pfs_entry; \
+ } while (0)
const PossiblyFreedShadaEntry pfs_entry = {
.can_free_entry = true,
.data = entry,
};
switch (entry.type) {
- case kSDItemMissing: {
+ case kSDItemMissing:
+ break;
+ case kSDItemHeader:
+ case kSDItemBufferList:
+ abort();
+ case kSDItemUnknown:
+ ret = shada_pack_entry(packer, entry, 0);
+ shada_free_shada_entry(&entry);
+ break;
+ case kSDItemSearchPattern:
+ COMPARE_WITH_ENTRY((entry.data.search_pattern.is_substitute_pattern
+ ? &wms->sub_search_pattern
+ : &wms->search_pattern), entry);
+ break;
+ case kSDItemSubString:
+ COMPARE_WITH_ENTRY(&wms->replacement, entry);
+ break;
+ case kSDItemHistoryEntry:
+ if (entry.data.history_item.histtype >= HIST_COUNT) {
+ ret = shada_pack_entry(packer, entry, 0);
+ shada_free_shada_entry(&entry);
break;
}
- case kSDItemHeader:
- case kSDItemBufferList: {
- abort();
+ if (wms->hms[entry.data.history_item.histtype].hmll.size != 0) {
+ hms_insert(&wms->hms[entry.data.history_item.histtype], entry, true,
+ true);
+ } else {
+ shada_free_shada_entry(&entry);
}
- case kSDItemUnknown: {
+ break;
+ case kSDItemRegister: {
+ const int idx = op_reg_index(entry.data.reg.name);
+ if (idx < 0) {
ret = shada_pack_entry(packer, entry, 0);
shada_free_shada_entry(&entry);
break;
}
- case kSDItemSearchPattern: {
- COMPARE_WITH_ENTRY((entry.data.search_pattern.is_substitute_pattern
- ? &wms->sub_search_pattern
- : &wms->search_pattern), entry);
- break;
- }
- case kSDItemSubString: {
- COMPARE_WITH_ENTRY(&wms->replacement, entry);
- break;
+ COMPARE_WITH_ENTRY(&wms->registers[idx], entry);
+ break;
+ }
+ case kSDItemVariable:
+ if (!in_strset(&wms->dumped_variables, entry.data.global_var.name)) {
+ ret = shada_pack_entry(packer, entry, 0);
}
- case kSDItemHistoryEntry: {
- if (entry.data.history_item.histtype >= HIST_COUNT) {
- ret = shada_pack_entry(packer, entry, 0);
- shada_free_shada_entry(&entry);
- break;
+ shada_free_shada_entry(&entry);
+ break;
+ case kSDItemGlobalMark:
+ if (ascii_isdigit(entry.data.filemark.name)) {
+ bool processed_mark = false;
+ // Completely ignore numbered mark names, make a list sorted by
+ // timestamp.
+ for (size_t i = ARRAY_SIZE(wms->numbered_marks); i > 0; i--) {
+ ShadaEntry wms_entry = wms->numbered_marks[i - 1].data;
+ if (wms_entry.type != kSDItemGlobalMark) {
+ continue;
+ }
+ // Ignore duplicates.
+ if (wms_entry.timestamp == entry.timestamp
+ && (wms_entry.data.filemark.additional_data == NULL
+ && entry.data.filemark.additional_data == NULL)
+ && marks_equal(wms_entry.data.filemark.mark,
+ entry.data.filemark.mark)
+ && strcmp(wms_entry.data.filemark.fname,
+ entry.data.filemark.fname) == 0) {
+ shada_free_shada_entry(&entry);
+ processed_mark = true;
+ break;
+ }
+ if (wms_entry.timestamp >= entry.timestamp) {
+ processed_mark = true;
+ if (i < ARRAY_SIZE(wms->numbered_marks)) {
+ replace_numbered_mark(wms, i, pfs_entry);
+ } else {
+ shada_free_shada_entry(&entry);
+ }
+ break;
+ }
}
- if (wms->hms[entry.data.history_item.histtype].hmll.size != 0) {
- hms_insert(&wms->hms[entry.data.history_item.histtype], entry, true,
- true);
- } else {
- shada_free_shada_entry(&entry);
+ if (!processed_mark) {
+ replace_numbered_mark(wms, 0, pfs_entry);
}
- break;
- }
- case kSDItemRegister: {
- const int idx = op_reg_index(entry.data.reg.name);
+ } else {
+ const int idx = mark_global_index(entry.data.filemark.name);
if (idx < 0) {
ret = shada_pack_entry(packer, entry, 0);
shada_free_shada_entry(&entry);
break;
}
- COMPARE_WITH_ENTRY(&wms->registers[idx], entry);
- break;
+ COMPARE_WITH_ENTRY(&wms->global_marks[idx], entry);
}
- case kSDItemVariable: {
- if (!in_strset(&wms->dumped_variables, entry.data.global_var.name)) {
- ret = shada_pack_entry(packer, entry, 0);
- }
+ break;
+ case kSDItemChange:
+ case kSDItemLocalMark: {
+ if (shada_removable(entry.data.filemark.fname)) {
shada_free_shada_entry(&entry);
break;
}
- case kSDItemGlobalMark: {
- if (ascii_isdigit(entry.data.filemark.name)) {
- bool processed_mark = false;
- // Completely ignore numbered mark names, make a list sorted by
- // timestamp.
- for (size_t i = ARRAY_SIZE(wms->numbered_marks); i > 0; i--) {
- ShadaEntry wms_entry = wms->numbered_marks[i - 1].data;
- if (wms_entry.type != kSDItemGlobalMark) {
- continue;
- }
- // Ignore duplicates.
- if (wms_entry.timestamp == entry.timestamp
- && (wms_entry.data.filemark.additional_data == NULL
- && entry.data.filemark.additional_data == NULL)
- && marks_equal(wms_entry.data.filemark.mark,
- entry.data.filemark.mark)
- && strcmp(wms_entry.data.filemark.fname,
- entry.data.filemark.fname) == 0) {
+ const char *const fname = (const char *)entry.data.filemark.fname;
+ khiter_t k;
+ int kh_ret;
+ k = kh_put(file_marks, &wms->file_marks, fname, &kh_ret);
+ FileMarks *const filemarks = &kh_val(&wms->file_marks, k);
+ if (kh_ret > 0) {
+ memset(filemarks, 0, sizeof(*filemarks));
+ }
+ if (entry.timestamp > filemarks->greatest_timestamp) {
+ filemarks->greatest_timestamp = entry.timestamp;
+ }
+ if (entry.type == kSDItemLocalMark) {
+ const int idx = mark_local_index(entry.data.filemark.name);
+ if (idx < 0) {
+ filemarks->additional_marks = xrealloc(filemarks->additional_marks,
+ (++filemarks->additional_marks_size
+ * sizeof(filemarks->additional_marks[0])));
+ filemarks->additional_marks[filemarks->additional_marks_size - 1] =
+ entry;
+ } else {
+ PossiblyFreedShadaEntry *const wms_entry = &filemarks->marks[idx];
+ if (wms_entry->data.type != kSDItemMissing) {
+ if (wms_entry->data.timestamp >= entry.timestamp) {
shada_free_shada_entry(&entry);
- processed_mark = true;
break;
}
- if (wms_entry.timestamp >= entry.timestamp) {
- processed_mark = true;
- if (i < ARRAY_SIZE(wms->numbered_marks)) {
- replace_numbered_mark(wms, i, pfs_entry);
- } else {
- shada_free_shada_entry(&entry);
+ if (wms_entry->can_free_entry) {
+ if (kh_key(&wms->file_marks, k)
+ == wms_entry->data.data.filemark.fname) {
+ kh_key(&wms->file_marks, k) = entry.data.filemark.fname;
}
- break;
+ shada_free_shada_entry(&wms_entry->data);
}
}
- if (!processed_mark) {
- replace_numbered_mark(wms, 0, pfs_entry);
- }
- } else {
- const int idx = mark_global_index(entry.data.filemark.name);
- if (idx < 0) {
- ret = shada_pack_entry(packer, entry, 0);
- shada_free_shada_entry(&entry);
- break;
- }
- COMPARE_WITH_ENTRY(&wms->global_marks[idx], entry);
- }
- break;
- }
- case kSDItemChange:
- case kSDItemLocalMark: {
- if (shada_removable(entry.data.filemark.fname)) {
- shada_free_shada_entry(&entry);
- break;
+ *wms_entry = pfs_entry;
}
- const char *const fname = (const char *) entry.data.filemark.fname;
- khiter_t k;
- int kh_ret;
- k = kh_put(file_marks, &wms->file_marks, fname, &kh_ret);
- FileMarks *const filemarks = &kh_val(&wms->file_marks, k);
- if (kh_ret > 0) {
- memset(filemarks, 0, sizeof(*filemarks));
- }
- if (entry.timestamp > filemarks->greatest_timestamp) {
- filemarks->greatest_timestamp = entry.timestamp;
- }
- if (entry.type == kSDItemLocalMark) {
- const int idx = mark_local_index(entry.data.filemark.name);
- if (idx < 0) {
- filemarks->additional_marks = xrealloc(
- filemarks->additional_marks,
- (++filemarks->additional_marks_size
- * sizeof(filemarks->additional_marks[0])));
- filemarks->additional_marks[filemarks->additional_marks_size - 1] =
- entry;
- } else {
- PossiblyFreedShadaEntry *const wms_entry = &filemarks->marks[idx];
- if (wms_entry->data.type != kSDItemMissing) {
- if (wms_entry->data.timestamp >= entry.timestamp) {
- shada_free_shada_entry(&entry);
- break;
- }
- if (wms_entry->can_free_entry) {
- if (kh_key(&wms->file_marks, k)
- == wms_entry->data.data.filemark.fname) {
- kh_key(&wms->file_marks, k) = entry.data.filemark.fname;
- }
- shada_free_shada_entry(&wms_entry->data);
- }
- }
- *wms_entry = pfs_entry;
- }
- } else {
+ } else {
#define FREE_POSSIBLY_FREED_SHADA_ENTRY(entry) \
- do { \
- if (entry.can_free_entry) { \
- shada_free_shada_entry(&entry.data); \
- } \
- } while (0)
+ do { \
+ 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,
- PossiblyFreedShadaEntry, data.timestamp,
- data.data.filemark.mark, entry, true,
- FREE_POSSIBLY_FREED_SHADA_ENTRY, SDE_TO_PFSDE,
- DUMMY_IDX_ADJ, AFTERFREE_DUMMY);
- }
- break;
- }
- case kSDItemJump: {
- MERGE_JUMPS(wms->jumps_size, wms->jumps, PossiblyFreedShadaEntry,
- data.timestamp, data.data.filemark.mark, entry,
- strcmp(jl_entry.data.data.filemark.fname,
- entry.data.filemark.fname) == 0,
+ MERGE_JUMPS(filemarks->changes_size, filemarks->changes,
+ PossiblyFreedShadaEntry, data.timestamp,
+ data.data.filemark.mark, entry, true,
FREE_POSSIBLY_FREED_SHADA_ENTRY, SDE_TO_PFSDE,
DUMMY_IDX_ADJ, AFTERFREE_DUMMY);
+ }
+ break;
+ }
+ case kSDItemJump:
+ MERGE_JUMPS(wms->jumps_size, wms->jumps, PossiblyFreedShadaEntry,
+ data.timestamp, data.data.filemark.mark, entry,
+ strcmp(jl_entry.data.data.filemark.fname,
+ entry.data.filemark.fname) == 0,
+ FREE_POSSIBLY_FREED_SHADA_ENTRY, SDE_TO_PFSDE,
+ DUMMY_IDX_ADJ, AFTERFREE_DUMMY);
#undef FREE_POSSIBLY_FREED_SHADA_ENTRY
#undef SDE_TO_PFSDE
#undef DUMMY_IDX_ADJ
#undef AFTERFREE_DUMMY
- break;
- }
+ break;
}
}
#undef COMPARE_WITH_ENTRY
@@ -2365,8 +2300,7 @@ static inline ShaDaWriteResult shada_read_when_writing(
/// @param[in] removable_bufs Cache of buffers ignored due to their location.
///
/// @return true or false.
-static inline bool ignore_buf(const buf_T *const buf,
- khash_t(bufset) *const removable_bufs)
+static inline bool ignore_buf(const buf_T *const buf, khash_t(bufset) *const removable_bufs)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE
{
return (buf->b_ffname == NULL || !buf->b_p_bl || bt_quickfix(buf) \
@@ -2378,8 +2312,7 @@ static inline bool ignore_buf(const buf_T *const buf,
/// @param[in] removable_bufs Buffers which are ignored
///
/// @return ShadaEntry List of buffers to save, kSDItemBufferList entry.
-static inline ShadaEntry shada_get_buflist(
- khash_t(bufset) *const removable_bufs)
+static inline ShadaEntry shada_get_buflist(khash_t(bufset) *const removable_bufs)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE
{
int max_bufs = get_shada_parameter('%');
@@ -2393,14 +2326,14 @@ static inline ShadaEntry shada_get_buflist(
ShadaEntry buflist_entry = (ShadaEntry) {
.type = kSDItemBufferList,
- .timestamp = os_time(),
- .data = {
- .buffer_list = {
- .size = buf_count,
- .buffers = xmalloc(buf_count
- * sizeof(*buflist_entry.data.buffer_list.buffers)),
- },
+ .timestamp = os_time(),
+ .data = {
+ .buffer_list = {
+ .size = buf_count,
+ .buffers = xmalloc(buf_count
+ * sizeof(*buflist_entry.data.buffer_list.buffers)),
},
+ },
};
size_t i = 0;
FOR_ALL_BUFFERS(buf) {
@@ -2412,8 +2345,8 @@ static inline ShadaEntry shada_get_buflist(
}
buflist_entry.data.buffer_list.buffers[i] = (struct buffer_list_buffer) {
.pos = buf->b_last_cursor.mark,
- .fname = (char *)buf->b_ffname,
- .additional_data = buf->additional_data,
+ .fname = (char *)buf->b_ffname,
+ .additional_data = buf->additional_data,
};
i++;
}
@@ -2435,8 +2368,7 @@ static inline ShadaEntry shada_get_buflist(
/// saved.
static inline void add_search_pattern(PossiblyFreedShadaEntry *const ret_pse,
const SearchPatternGetter get_pattern,
- const bool is_substitute_pattern,
- const bool search_last_used,
+ const bool is_substitute_pattern, const bool search_last_used,
const bool search_highlighted)
FUNC_ATTR_ALWAYS_INLINE
{
@@ -2457,7 +2389,7 @@ static inline void add_search_pattern(PossiblyFreedShadaEntry *const ret_pse,
? defaults.data.search_pattern.has_line_offset
: pat.off.line),
.place_cursor_at_end = (
- is_substitute_pattern
+ is_substitute_pattern
? defaults.data.search_pattern.place_cursor_at_end
: pat.off.end),
.offset = (is_substitute_pattern
@@ -2481,8 +2413,7 @@ static inline void add_search_pattern(PossiblyFreedShadaEntry *const ret_pse,
///
/// @param[in] wms The WriteMergerState used when writing.
/// @param[in] max_reg_lines The maximum number of register lines.
-static inline void shada_initialize_registers(WriteMergerState *const wms,
- int max_reg_lines)
+static inline void shada_initialize_registers(WriteMergerState *const wms, int max_reg_lines)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_ALWAYS_INLINE
{
const void *reg_iter = NULL;
@@ -2527,8 +2458,7 @@ static inline void shada_initialize_registers(WriteMergerState *const wms,
/// @param[out] wms Merger state to adjust.
/// @param[in] idx Index at which new mark should be placed.
/// @param[in] entry New mark.
-static inline void replace_numbered_mark(WriteMergerState *const wms,
- const size_t idx,
+static inline void replace_numbered_mark(WriteMergerState *const wms, const size_t idx,
const PossiblyFreedShadaEntry entry)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_ALWAYS_INLINE
{
@@ -2566,8 +2496,7 @@ static inline void find_removable_bufs(khash_t(bufset) *removable_bufs)
/// @param[in] sd_reader Structure containing file reader definition. If it is
/// not NULL then contents of this file will be merged
/// with current Neovim runtime.
-static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
- ShaDaReadDef *const sd_reader)
+static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, ShaDaReadDef *const sd_reader)
FUNC_ATTR_NONNULL_ARG(1)
{
ShaDaWriteResult ret = kSDWriteSuccessfull;
@@ -2588,8 +2517,8 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
}
const bool dump_registers = (max_reg_lines != 0);
khash_t(bufset) removable_bufs = KHASH_EMPTY_TABLE(bufset);
- const size_t max_kbyte = (size_t) max_kbyte_i;
- const size_t num_marked_files = (size_t) get_shada_parameter('\'');
+ const size_t max_kbyte = (size_t)max_kbyte_i;
+ const size_t num_marked_files = (size_t)get_shada_parameter('\'');
const bool dump_global_marks = get_shada_parameter('f') != 0;
bool dump_history = false;
@@ -2602,20 +2531,21 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
if (num_saved > 0) {
dump_history = true;
dump_one_history[i] = true;
- hms_init(&wms->hms[i], i, (size_t) num_saved, sd_reader != NULL, false);
+ hms_init(&wms->hms[i], i, (size_t)num_saved, sd_reader != NULL, false);
} else {
dump_one_history[i] = false;
}
}
- const unsigned srni_flags = (unsigned) (
- kSDReadUndisableableData
- | kSDReadUnknown
- | (dump_history ? kSDReadHistory : 0)
- | (dump_registers ? kSDReadRegisters : 0)
- | (dump_global_vars ? kSDReadVariables : 0)
- | (dump_global_marks ? kSDReadGlobalMarks : 0)
- | (num_marked_files ? kSDReadLocalMarks | kSDReadChanges : 0));
+ const unsigned srni_flags = (unsigned)(
+ kSDReadUndisableableData
+ | kSDReadUnknown
+ | (dump_history ? kSDReadHistory : 0)
+ | (dump_registers ? kSDReadRegisters : 0)
+ | (dump_global_vars ? kSDReadVariables : 0)
+ | (dump_global_marks ? kSDReadGlobalMarks : 0)
+ | (num_marked_files ? kSDReadLocalMarks |
+ kSDReadChanges : 0));
msgpack_packer *const packer = msgpack_packer_new(sd_writer,
&msgpack_sd_writer_write);
@@ -2645,11 +2575,11 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
{ STATIC_CSTR_AS_STRING("version"),
STRING_OBJ(cstr_as_string(longVersion)) },
{ STATIC_CSTR_AS_STRING("max_kbyte"),
- INTEGER_OBJ((Integer) max_kbyte) },
+ INTEGER_OBJ((Integer)max_kbyte) },
{ STATIC_CSTR_AS_STRING("pid"),
- INTEGER_OBJ((Integer) os_get_pid()) },
+ INTEGER_OBJ((Integer)os_get_pid()) },
{ STATIC_CSTR_AS_STRING("encoding"),
- STRING_OBJ(cstr_as_string((char *) p_enc)) },
+ STRING_OBJ(cstr_as_string((char *)p_enc)) },
}),
}
}
@@ -2681,34 +2611,32 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
break;
}
switch (vartv.v_type) {
- case VAR_FUNC:
- case VAR_PARTIAL:
+ case VAR_FUNC:
+ case VAR_PARTIAL:
+ tv_clear(&vartv);
+ continue;
+ case VAR_DICT: {
+ dict_T *di = vartv.vval.v_dict;
+ int copyID = get_copyID();
+ if (!set_ref_in_ht(&di->dv_hashtab, copyID, NULL)
+ && copyID == di->dv_copyID) {
tv_clear(&vartv);
continue;
- case VAR_DICT:
- {
- dict_T *di = vartv.vval.v_dict;
- int copyID = get_copyID();
- if (!set_ref_in_ht(&di->dv_hashtab, copyID, NULL)
- && copyID == di->dv_copyID) {
- tv_clear(&vartv);
- continue;
- }
- break;
- }
- case VAR_LIST:
- {
- list_T *l = vartv.vval.v_list;
- int copyID = get_copyID();
- if (!set_ref_in_list(l, copyID, NULL)
- && copyID == l->lv_copyID) {
- tv_clear(&vartv);
- continue;
- }
- break;
- }
- default:
- break;
+ }
+ break;
+ }
+ case VAR_LIST: {
+ list_T *l = vartv.vval.v_list;
+ int copyID = get_copyID();
+ if (!set_ref_in_list(l, copyID, NULL)
+ && copyID == l->lv_copyID) {
+ tv_clear(&vartv);
+ continue;
+ }
+ break;
+ }
+ default:
+ break;
}
typval_T tgttv;
tv_copy(&vartv, &tgttv);
@@ -2718,7 +2646,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
.timestamp = cur_timestamp,
.data = {
.global_var = {
- .name = (char *) name,
+ .name = (char *)name,
.value = tgttv,
.additional_elements = NULL,
}
@@ -2733,7 +2661,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
tv_clear(&tgttv);
if (spe_ret == kSDWriteSuccessfull) {
int kh_ret;
- (void) kh_put(strset, &wms->dumped_variables, name, &kh_ret);
+ (void)kh_put(strset, &wms->dumped_variables, name, &kh_ret);
}
} while (var_iter != NULL);
}
@@ -2766,7 +2694,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
.timestamp = sub.timestamp,
.data = {
.sub_string = {
- .sub = (char *) sub.sub,
+ .sub = (char *)sub.sub,
.additional_elements = sub.additional_elements,
}
}
@@ -2788,17 +2716,17 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
const char *fname;
if (fm.fmark.fnum == 0) {
assert(fm.fname != NULL);
- if (shada_removable((const char *) fm.fname)) {
+ if (shada_removable((const char *)fm.fname)) {
continue;
}
- fname = (const char *) fm.fname;
+ fname = (const char *)fm.fname;
} else {
const buf_T *const buf = buflist_findnr(fm.fmark.fnum);
if (buf == NULL || buf->b_ffname == NULL
|| in_bufset(&removable_bufs, buf)) {
continue;
}
- fname = (const char *) buf->b_ffname;
+ fname = (const char *)buf->b_ffname;
}
const PossiblyFreedShadaEntry pf_entry = {
.can_free_entry = false,
@@ -2835,7 +2763,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
continue;
}
const void *local_marks_iter = NULL;
- const char *const fname = (const char *) buf->b_ffname;
+ const char *const fname = (const char *)buf->b_ffname;
khiter_t k;
int kh_ret;
k = kh_put(file_marks, &wms->file_marks, fname, &kh_ret);
@@ -2859,7 +2787,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
.filemark = {
.mark = fm.mark,
.name = name,
- .fname = (char *) fname,
+ .fname = (char *)fname,
.additional_data = fm.additional_data,
}
}
@@ -2879,7 +2807,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
.data = {
.filemark = {
.mark = fm.mark,
- .fname = (char *) fname,
+ .fname = (char *)fname,
.additional_data = fm.additional_data,
}
}
@@ -2889,13 +2817,13 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
filemarks->greatest_timestamp = fm.timestamp;
}
}
- filemarks->changes_size = (size_t) buf->b_changelistlen;
+ filemarks->changes_size = (size_t)buf->b_changelistlen;
}
}
if (sd_reader != NULL) {
- const ShaDaWriteResult srww_ret = shada_read_when_writing(
- sd_reader, srni_flags, max_kbyte, wms, packer);
+ const ShaDaWriteResult srww_ret = shada_read_when_writing(sd_reader, srni_flags, max_kbyte, wms,
+ packer);
if (srww_ret != kSDWriteSuccessfull) {
ret = srww_ret;
}
@@ -2961,7 +2889,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
const size_t file_markss_size = kh_size(&wms->file_marks);
FileMarks **const all_file_markss =
- xmalloc(file_markss_size * sizeof(*all_file_markss));
+ xmalloc(file_markss_size * sizeof(*all_file_markss));
FileMarks **cur_file_marks = all_file_markss;
for (khint_t i = kh_begin(&wms->file_marks); i != kh_end(&wms->file_marks);
i++) {
@@ -2969,7 +2897,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
*cur_file_marks++ = &kh_val(&wms->file_marks, i);
}
}
- qsort((void *) all_file_markss, file_markss_size, sizeof(*all_file_markss),
+ qsort((void *)all_file_markss, file_markss_size, sizeof(*all_file_markss),
&compare_file_marks);
const size_t file_markss_to_dump = MIN(num_marked_files, file_markss_size);
for (size_t i = 0; i < file_markss_to_dump; i++) {
@@ -3000,11 +2928,10 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
if (dump_one_history[i]) {
hms_insert_whole_neovim_history(&wms->hms[i]);
HMS_ITER(&wms->hms[i], cur_entry, {
- if (shada_pack_pfreed_entry(
- packer, (PossiblyFreedShadaEntry) {
- .data = cur_entry->data,
- .can_free_entry = cur_entry->can_free_entry,
- }, max_kbyte) == kSDWriteFailed) {
+ if (shada_pack_pfreed_entry(packer, (PossiblyFreedShadaEntry) {
+ .data = cur_entry->data,
+ .can_free_entry = cur_entry->can_free_entry,
+ }, max_kbyte) == kSDWriteFailed) {
ret = kSDWriteFailed;
break;
}
@@ -3075,7 +3002,7 @@ int shada_write_file(const char *const file, bool nomerge)
}
// Save permissions from the original file, with modifications:
- int perm = (int) os_getperm(fname);
+ int perm = (int)os_getperm(fname);
perm = (perm >= 0) ? ((perm & 0777) | 0600) : 0600;
// ^3 ^1 ^2 ^2,3
// 1: Strip SUID bit if any.
@@ -3083,8 +3010,7 @@ int shada_write_file(const char *const file, bool nomerge)
// 3: If somebody happened to delete the file after it was opened for
// reading use u=rw permissions.
shada_write_file_open: {}
- sd_writer.cookie = file_open_new(
- &error, tempname, kFileCreateOnly|kFileNoSymlink, perm);
+ sd_writer.cookie = file_open_new(&error, tempname, kFileCreateOnly|kFileNoSymlink, perm);
if (sd_writer.cookie == NULL) {
if (error == UV_EEXIST || error == UV_ELOOP) {
// File already exists, try another name
@@ -3237,8 +3163,7 @@ int shada_read_marks(void)
/// @param[in] missing_ok If true, do not error out when file is missing.
///
/// @return OK in case of success, FAIL otherwise.
-int shada_read_everything(const char *const fname, const bool forceit,
- const bool missing_ok)
+int shada_read_everything(const char *const fname, const bool forceit, const bool missing_ok)
{
return shada_read_file(fname,
kShaDaWantInfo|kShaDaWantMarks|kShaDaGetOldfiles
@@ -3252,81 +3177,71 @@ static void shada_free_shada_entry(ShadaEntry *const entry)
return;
}
switch (entry->type) {
- case kSDItemMissing: {
- break;
- }
- case kSDItemUnknown: {
- xfree(entry->data.unknown_item.contents);
- break;
- }
- case kSDItemHeader: {
- api_free_dictionary(entry->data.header);
- break;
- }
- case kSDItemChange:
- case kSDItemJump:
- case kSDItemGlobalMark:
- case kSDItemLocalMark: {
- tv_dict_unref(entry->data.filemark.additional_data);
- xfree(entry->data.filemark.fname);
- break;
- }
- case kSDItemSearchPattern: {
- tv_dict_unref(entry->data.search_pattern.additional_data);
- xfree(entry->data.search_pattern.pat);
- break;
- }
- case kSDItemRegister: {
- tv_dict_unref(entry->data.reg.additional_data);
- for (size_t i = 0; i < entry->data.reg.contents_size; i++) {
- xfree(entry->data.reg.contents[i]);
- }
- xfree(entry->data.reg.contents);
- break;
+ case kSDItemMissing:
+ break;
+ case kSDItemUnknown:
+ xfree(entry->data.unknown_item.contents);
+ break;
+ case kSDItemHeader:
+ api_free_dictionary(entry->data.header);
+ break;
+ case kSDItemChange:
+ case kSDItemJump:
+ case kSDItemGlobalMark:
+ case kSDItemLocalMark:
+ tv_dict_unref(entry->data.filemark.additional_data);
+ xfree(entry->data.filemark.fname);
+ break;
+ case kSDItemSearchPattern:
+ tv_dict_unref(entry->data.search_pattern.additional_data);
+ xfree(entry->data.search_pattern.pat);
+ break;
+ case kSDItemRegister:
+ tv_dict_unref(entry->data.reg.additional_data);
+ for (size_t i = 0; i < entry->data.reg.contents_size; i++) {
+ xfree(entry->data.reg.contents[i]);
}
- case kSDItemHistoryEntry: {
- tv_list_unref(entry->data.history_item.additional_elements);
- xfree(entry->data.history_item.string);
- break;
- }
- case kSDItemVariable: {
- tv_list_unref(entry->data.global_var.additional_elements);
- xfree(entry->data.global_var.name);
- tv_clear(&entry->data.global_var.value);
- break;
- }
- case kSDItemSubString: {
- tv_list_unref(entry->data.sub_string.additional_elements);
- xfree(entry->data.sub_string.sub);
- break;
- }
- case kSDItemBufferList: {
- for (size_t i = 0; i < entry->data.buffer_list.size; i++) {
- xfree(entry->data.buffer_list.buffers[i].fname);
- tv_dict_unref(entry->data.buffer_list.buffers[i].additional_data);
- }
- xfree(entry->data.buffer_list.buffers);
- break;
+ xfree(entry->data.reg.contents);
+ break;
+ case kSDItemHistoryEntry:
+ tv_list_unref(entry->data.history_item.additional_elements);
+ xfree(entry->data.history_item.string);
+ break;
+ case kSDItemVariable:
+ tv_list_unref(entry->data.global_var.additional_elements);
+ xfree(entry->data.global_var.name);
+ tv_clear(&entry->data.global_var.value);
+ break;
+ case kSDItemSubString:
+ tv_list_unref(entry->data.sub_string.additional_elements);
+ xfree(entry->data.sub_string.sub);
+ break;
+ case kSDItemBufferList:
+ for (size_t i = 0; i < entry->data.buffer_list.size; i++) {
+ xfree(entry->data.buffer_list.buffers[i].fname);
+ tv_dict_unref(entry->data.buffer_list.buffers[i].additional_data);
}
+ xfree(entry->data.buffer_list.buffers);
+ break;
}
}
#ifndef HAVE_BE64TOH
static inline uint64_t be64toh(uint64_t big_endian_64_bits)
{
-#ifdef ORDER_BIG_ENDIAN
+# ifdef ORDER_BIG_ENDIAN
return big_endian_64_bits;
-#else
+# else
// It may appear that when !defined(ORDER_BIG_ENDIAN) actual order is big
// endian. This variant is suboptimal, but it works regardless of actual
// order.
- uint8_t *buf = (uint8_t *) &big_endian_64_bits;
+ uint8_t *buf = (uint8_t *)&big_endian_64_bits;
uint64_t ret = 0;
for (size_t i = 8; i; i--) {
- ret |= ((uint64_t) buf[i - 1]) << ((8 - i) * 8);
+ ret |= ((uint64_t)buf[i - 1]) << ((8 - i) * 8);
}
return ret;
-#endif
+# endif
}
#endif
@@ -3339,8 +3254,7 @@ static inline uint64_t be64toh(uint64_t big_endian_64_bits)
/// @return kSDReadStatusSuccess if everything was OK, kSDReadStatusNotShaDa if
/// there were not enough bytes to read or kSDReadStatusReadError if
/// there was some error while reading.
-static ShaDaReadResult fread_len(ShaDaReadDef *const sd_reader,
- char *const buffer,
+static ShaDaReadResult fread_len(ShaDaReadDef *const sd_reader, char *const buffer,
const size_t length)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
@@ -3378,8 +3292,7 @@ static ShaDaReadResult fread_len(ShaDaReadDef *const sd_reader,
/// @return kSDReadStatusSuccess if reading was successful,
/// kSDReadStatusNotShaDa if there were not enough bytes to read or
/// kSDReadStatusReadError if reading failed for whatever reason.
-static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader,
- const int first_char,
+static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader, const int first_char,
uint64_t *const result)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
@@ -3394,42 +3307,37 @@ static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader,
emsgf(_(RCERR "Error while reading ShaDa file: "
"expected positive integer at position %" PRIu64
", but got nothing"),
- (uint64_t) fpos);
+ (uint64_t)fpos);
return kSDReadStatusNotShaDa;
}
}
if (~first_char & 0x80) {
// Positive fixnum
- *result = (uint64_t) ((uint8_t) first_char);
+ *result = (uint64_t)((uint8_t)first_char);
} else {
size_t length = 0;
switch (first_char) {
- case 0xCC: { // uint8
- length = 1;
- break;
- }
- case 0xCD: { // uint16
- length = 2;
- break;
- }
- case 0xCE: { // uint32
- length = 4;
- break;
- }
- case 0xCF: { // uint64
- length = 8;
- break;
- }
- default: {
- emsgf(_(RCERR "Error while reading ShaDa file: "
- "expected positive integer at position %" PRIu64),
- (uint64_t) fpos);
- return kSDReadStatusNotShaDa;
- }
+ case 0xCC: // uint8
+ length = 1;
+ break;
+ case 0xCD: // uint16
+ length = 2;
+ break;
+ case 0xCE: // uint32
+ length = 4;
+ break;
+ case 0xCF: // uint64
+ length = 8;
+ break;
+ default:
+ emsgf(_(RCERR "Error while reading ShaDa file: "
+ "expected positive integer at position %" PRIu64),
+ (uint64_t)fpos);
+ return kSDReadStatusNotShaDa;
}
uint64_t buf = 0;
- char *buf_u8 = (char *) &buf;
+ char *buf_u8 = (char *)&buf;
ShaDaReadResult fl_ret;
if ((fl_ret = fread_len(sd_reader, &(buf_u8[sizeof(buf)-length]), length))
!= kSDReadStatusSuccess) {
@@ -3441,24 +3349,24 @@ static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader,
}
#define READERR(entry_name, error_desc) \
- RERR "Error while reading ShaDa file: " \
- entry_name " entry at position %" PRIu64 " " \
- error_desc
+ 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)
+ 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); \
- goto shada_read_next_item_error; \
- } while (0)
+ do { \
+ ga_clear(&ga); \
+ goto shada_read_next_item_error; \
+ } while (0)
#define ID(s) s
#define BINDUP(b) xmemdupz(b.ptr, b.size)
-#define TOINT(s) ((int) (s))
-#define TOLONG(s) ((long) (s))
-#define TOCHAR(s) ((char) (s))
-#define TOU8(s) ((uint8_t) (s))
-#define TOSIZE(s) ((size_t) (s))
+#define TOINT(s) ((int)(s))
+#define TOLONG(s) ((long)(s))
+#define TOCHAR(s) ((char)(s))
+#define TOU8(s) ((uint8_t)(s))
+#define TOSIZE(s) ((size_t)(s))
#define CHECKED_ENTRY(condition, error_desc, entry_name, obj, tgt, attr, \
proc) \
do { \
@@ -3479,18 +3387,16 @@ static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader,
}
#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); \
+ 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 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, \
- 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, \
+ attr, proc)
#define BOOLEAN_KEY(un, entry_name, name, tgt) \
TYPED_KEY(un, entry_name, name, "a boolean", tgt, BOOLEAN, boolean, ID)
#define STRING_KEY(un, entry_name, name, tgt) \
@@ -3499,19 +3405,18 @@ static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader,
TYPED_KEY(un, entry_name, name, "a binary", tgt, BIN, bin, \
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 \
- == MSGPACK_OBJECT_POSITIVE_INTEGER) \
- || (un.data.via.map.ptr[i].val.type \
- == MSGPACK_OBJECT_NEGATIVE_INTEGER)), \
- i64, proc)
+ CHECKED_KEY(un, entry_name, name, "which is not an integer", tgt, \
+ ((un.data.via.map.ptr[i].val.type \
+ == MSGPACK_OBJECT_POSITIVE_INTEGER) \
+ || (un.data.via.map.ptr[i].val.type \
+ == MSGPACK_OBJECT_NEGATIVE_INTEGER)), \
+ i64, proc)
#define INTEGER_KEY(un, entry_name, name, tgt) \
INT_KEY(un, entry_name, name, tgt, TOINT)
#define LONG_KEY(un, entry_name, name, tgt) \
INT_KEY(un, entry_name, name, tgt, TOLONG)
#define ADDITIONAL_KEY(un) \
- else { /* NOLINT(readability/braces) */ \
+ 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)), \
@@ -3522,54 +3427,54 @@ static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader,
#define CONVERTED(str, len) (xmemdupz((str), (len)))
#define BIN_CONVERTED(b) CONVERTED(b.ptr, b.size)
#define SET_ADDITIONAL_DATA(tgt, name) \
- do { \
- if (ad_ga.ga_len) { \
- msgpack_object obj = { \
- .type = MSGPACK_OBJECT_MAP, \
- .via = { \
- .map = { \
- .size = (uint32_t) ad_ga.ga_len, \
- .ptr = ad_ga.ga_data, \
- } \
- } \
- }; \
- typval_T adtv; \
- if (msgpack_to_vim(obj, &adtv) == FAIL \
- || adtv.v_type != VAR_DICT) { \
- emsgf(_(READERR(name, \
- "cannot be converted to a VimL dictionary")), \
- initial_fpos); \
- ga_clear(&ad_ga); \
- tv_clear(&adtv); \
- goto shada_read_next_item_error; \
+ do { \
+ if (ad_ga.ga_len) { \
+ msgpack_object obj = { \
+ .type = MSGPACK_OBJECT_MAP, \
+ .via = { \
+ .map = { \
+ .size = (uint32_t)ad_ga.ga_len, \
+ .ptr = ad_ga.ga_data, \
} \
- tgt = adtv.vval.v_dict; \
} \
+ }; \
+ typval_T adtv; \
+ if (msgpack_to_vim(obj, &adtv) == FAIL \
+ || adtv.v_type != VAR_DICT) { \
+ emsgf(_(READERR(name, \
+ "cannot be converted to a VimL dictionary")), \
+ initial_fpos); \
ga_clear(&ad_ga); \
- } while (0)
+ tv_clear(&adtv); \
+ goto shada_read_next_item_error; \
+ } \
+ tgt = adtv.vval.v_dict; \
+ } \
+ ga_clear(&ad_ga); \
+ } while (0)
#define SET_ADDITIONAL_ELEMENTS(src, src_maxsize, tgt, name) \
- do { \
- if ((src).size > (size_t) (src_maxsize)) { \
- msgpack_object obj = { \
- .type = MSGPACK_OBJECT_ARRAY, \
- .via = { \
- .array = { \
- .size = ((src).size - (uint32_t) (src_maxsize)), \
- .ptr = (src).ptr + (src_maxsize), \
- } \
- } \
- }; \
- typval_T aetv; \
- if (msgpack_to_vim(obj, &aetv) == FAIL) { \
- emsgf(_(READERR(name, "cannot be converted to a VimL list")), \
- initial_fpos); \
- tv_clear(&aetv); \
- goto shada_read_next_item_error; \
+ do { \
+ if ((src).size > (size_t)(src_maxsize)) { \
+ msgpack_object obj = { \
+ .type = MSGPACK_OBJECT_ARRAY, \
+ .via = { \
+ .array = { \
+ .size = ((src).size - (uint32_t)(src_maxsize)), \
+ .ptr = (src).ptr + (src_maxsize), \
} \
- assert(aetv.v_type == VAR_LIST); \
- (tgt) = aetv.vval.v_list; \
} \
- } while (0)
+ }; \
+ typval_T aetv; \
+ if (msgpack_to_vim(obj, &aetv) == FAIL) { \
+ emsgf(_(READERR(name, "cannot be converted to a VimL list")), \
+ initial_fpos); \
+ tv_clear(&aetv); \
+ goto shada_read_next_item_error; \
+ } \
+ assert(aetv.v_type == VAR_LIST); \
+ (tgt) = aetv.vval.v_list; \
+ } \
+ } while (0)
/// Iterate over shada file contents
///
@@ -3581,10 +3486,8 @@ static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader,
/// greater then given.
///
/// @return Any value from ShaDaReadResult enum.
-static ShaDaReadResult shada_read_next_item(ShaDaReadDef *const sd_reader,
- ShadaEntry *const entry,
- const unsigned flags,
- const size_t max_kbyte)
+static ShaDaReadResult shada_read_next_item(ShaDaReadDef *const sd_reader, ShadaEntry *const entry,
+ const unsigned flags, const size_t max_kbyte)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
ShaDaReadResult ret = kSDReadStatusMalformed;
@@ -3600,11 +3503,11 @@ shada_read_next_item_start:
// First: manually unpack type, timestamp and length.
// This is needed to avoid both seeking and having to maintain a buffer.
- uint64_t type_u64 = (uint64_t) kSDItemMissing;
+ uint64_t type_u64 = (uint64_t)kSDItemMissing;
uint64_t timestamp_u64;
uint64_t length_u64;
- const uint64_t initial_fpos = (uint64_t) sd_reader->fpos;
+ const uint64_t initial_fpos = (uint64_t)sd_reader->fpos;
const int first_char = read_char(sd_reader);
if (first_char == EOF && sd_reader->eof) {
return kSDReadStatusFinished;
@@ -3647,7 +3550,7 @@ shada_read_next_item_start:
if ((type_u64 > SHADA_LAST_ENTRY
? !(flags & kSDReadUnknown)
- : !((unsigned) (1 << type_u64) & flags))
+ : !((unsigned)(1 << type_u64) & flags))
|| (max_kbyte && length > max_kbyte * 1024)) {
// First entry is unknown or equal to "\n" (10)? Most likely this means that
// current file is not a ShaDa file because first item should normally be
@@ -3675,16 +3578,16 @@ shada_read_next_item_start:
entry->data.unknown_item.size = length;
entry->data.unknown_item.type = type_u64;
if (initial_fpos == 0) {
- const ShaDaReadResult spm_ret = shada_parse_msgpack(
- sd_reader, length, NULL, &entry->data.unknown_item.contents);
+ const ShaDaReadResult spm_ret = shada_parse_msgpack(sd_reader, length, NULL,
+ &entry->data.unknown_item.contents);
if (spm_ret != kSDReadStatusSuccess) {
entry->type = kSDItemMissing;
}
return spm_ret;
} else {
entry->data.unknown_item.contents = xmalloc(length);
- const ShaDaReadResult fl_ret = fread_len(
- sd_reader, entry->data.unknown_item.contents, length);
+ const ShaDaReadResult fl_ret =
+ fread_len(sd_reader, entry->data.unknown_item.contents, length);
if (fl_ret != kSDReadStatusSuccess) {
shada_free_shada_entry(entry);
entry->type = kSDItemMissing;
@@ -3704,350 +3607,367 @@ shada_read_next_item_start:
}
ret = kSDReadStatusMalformed;
entry->data = sd_default_values[type_u64].data;
- switch ((ShadaEntryType) type_u64) {
- case kSDItemHeader: {
- if (!msgpack_rpc_to_dictionary(&(unpacked.data), &(entry->data.header))) {
- emsgf(_(READERR("header", "is not a dictionary")), initial_fpos);
- goto shada_read_next_item_error;
- }
- break;
+ switch ((ShadaEntryType)type_u64) {
+ case kSDItemHeader:
+ if (!msgpack_rpc_to_dictionary(&(unpacked.data), &(entry->data.header))) {
+ emsgf(_(READERR("header", "is not a dictionary")), initial_fpos);
+ goto shada_read_next_item_error;
}
- case kSDItemSearchPattern: {
- if (unpacked.data.type != MSGPACK_OBJECT_MAP) {
- emsgf(_(READERR("search pattern", "is not a dictionary")),
- initial_fpos);
- goto shada_read_next_item_error;
- }
- garray_T ad_ga;
- ga_init(&ad_ga, sizeof(*(unpacked.data.via.map.ptr)), 1);
- for (size_t i = 0; i < unpacked.data.via.map.size; i++) {
- CHECK_KEY_IS_STR(unpacked, "search pattern")
- BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_MAGIC,
- entry->data.search_pattern.magic)
- BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_SMARTCASE,
- entry->data.search_pattern.smartcase)
- BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_HAS_LINE_OFFSET,
- entry->data.search_pattern.has_line_offset)
- BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_PLACE_CURSOR_AT_END,
- entry->data.search_pattern.place_cursor_at_end)
- BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_IS_LAST_USED,
- entry->data.search_pattern.is_last_used)
- BOOLEAN_KEY(unpacked, "search pattern",
- SEARCH_KEY_IS_SUBSTITUTE_PATTERN,
- entry->data.search_pattern.is_substitute_pattern)
- BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_HIGHLIGHTED,
- entry->data.search_pattern.highlighted)
- BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_BACKWARD,
- entry->data.search_pattern.search_backward)
- INTEGER_KEY(unpacked, "search pattern", SEARCH_KEY_OFFSET,
- entry->data.search_pattern.offset)
- CONVERTED_STRING_KEY(unpacked, "search pattern", SEARCH_KEY_PAT,
- entry->data.search_pattern.pat)
- ADDITIONAL_KEY(unpacked)
- }
- if (entry->data.search_pattern.pat == NULL) {
- emsgf(_(READERR("search pattern", "has no pattern")), initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
- }
- SET_ADDITIONAL_DATA(entry->data.search_pattern.additional_data,
- "search pattern");
- break;
+ break;
+ case kSDItemSearchPattern: {
+ if (unpacked.data.type != MSGPACK_OBJECT_MAP) {
+ emsgf(_(READERR("search pattern", "is not a dictionary")),
+ initial_fpos);
+ goto shada_read_next_item_error;
}
- case kSDItemChange:
- case kSDItemJump:
- case kSDItemGlobalMark:
- case kSDItemLocalMark: {
- if (unpacked.data.type != MSGPACK_OBJECT_MAP) {
- emsgf(_(READERR("mark", "is not a dictionary")), initial_fpos);
- goto shada_read_next_item_error;
- }
- garray_T ad_ga;
- ga_init(&ad_ga, sizeof(*(unpacked.data.via.map.ptr)), 1);
- for (size_t i = 0; i < unpacked.data.via.map.size; i++) {
- CHECK_KEY_IS_STR(unpacked, "mark")
- if (CHECK_KEY(unpacked.data.via.map.ptr[i].key, KEY_NAME_CHAR)) {
- if (type_u64 == kSDItemJump || type_u64 == kSDItemChange) {
- emsgf(_(READERR("mark", "has n key which is only valid for "
- "local and global mark entries")), initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
- }
- CHECKED_ENTRY(
- (unpacked.data.via.map.ptr[i].val.type
- == MSGPACK_OBJECT_POSITIVE_INTEGER),
- "has n key value which is not an unsigned integer",
- "mark", unpacked.data.via.map.ptr[i].val,
- entry->data.filemark.name, u64, TOCHAR);
+ garray_T ad_ga;
+ ga_init(&ad_ga, sizeof(*(unpacked.data.via.map.ptr)), 1);
+ for (size_t i = 0; i < unpacked.data.via.map.size; i++) {
+ CHECK_KEY_IS_STR(unpacked, "search pattern")
+ BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_MAGIC,
+ entry->data.search_pattern.magic)
+ BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_SMARTCASE,
+ entry->data.search_pattern.smartcase)
+ BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_HAS_LINE_OFFSET,
+ entry->data.search_pattern.has_line_offset)
+ BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_PLACE_CURSOR_AT_END,
+ entry->data.search_pattern.place_cursor_at_end)
+ BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_IS_LAST_USED,
+ entry->data.search_pattern.is_last_used)
+ BOOLEAN_KEY(unpacked, "search pattern",
+ SEARCH_KEY_IS_SUBSTITUTE_PATTERN,
+ entry->data.search_pattern.is_substitute_pattern)
+ BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_HIGHLIGHTED,
+ entry->data.search_pattern.highlighted)
+ BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_BACKWARD,
+ entry->data.search_pattern.search_backward)
+ INTEGER_KEY(unpacked, "search pattern", SEARCH_KEY_OFFSET,
+ entry->data.search_pattern.offset)
+ CONVERTED_STRING_KEY(unpacked, "search pattern", SEARCH_KEY_PAT,
+ entry->data.search_pattern.pat)
+ ADDITIONAL_KEY(unpacked)
+ }
+ if (entry->data.search_pattern.pat == NULL) {
+ emsgf(_(READERR("search pattern", "has no pattern")), initial_fpos);
+ CLEAR_GA_AND_ERROR_OUT(ad_ga);
+ }
+ SET_ADDITIONAL_DATA(entry->data.search_pattern.additional_data,
+ "search pattern");
+ break;
+ }
+ case kSDItemChange:
+ case kSDItemJump:
+ case kSDItemGlobalMark:
+ case kSDItemLocalMark: {
+ if (unpacked.data.type != MSGPACK_OBJECT_MAP) {
+ emsgf(_(READERR("mark", "is not a dictionary")), initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ garray_T ad_ga;
+ ga_init(&ad_ga, sizeof(*(unpacked.data.via.map.ptr)), 1);
+ for (size_t i = 0; i < unpacked.data.via.map.size; i++) {
+ CHECK_KEY_IS_STR(unpacked, "mark")
+ if (CHECK_KEY(unpacked.data.via.map.ptr[i].key, KEY_NAME_CHAR)) {
+ if (type_u64 == kSDItemJump || type_u64 == kSDItemChange) {
+ emsgf(_(READERR("mark", "has n key which is only valid for "
+ "local and global mark entries")), initial_fpos);
+ CLEAR_GA_AND_ERROR_OUT(ad_ga);
}
- LONG_KEY(unpacked, "mark", KEY_LNUM, entry->data.filemark.mark.lnum)
- INTEGER_KEY(unpacked, "mark", KEY_COL, entry->data.filemark.mark.col)
- STRING_KEY(unpacked, "mark", KEY_FILE, entry->data.filemark.fname)
- ADDITIONAL_KEY(unpacked)
- }
- if (entry->data.filemark.fname == NULL) {
- emsgf(_(READERR("mark", "is missing file name")), initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
- }
- if (entry->data.filemark.mark.lnum <= 0) {
- emsgf(_(READERR("mark", "has invalid line number")), initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
+ CHECKED_ENTRY((unpacked.data.via.map.ptr[i].val.type
+ == MSGPACK_OBJECT_POSITIVE_INTEGER),
+ "has n key value which is not an unsigned integer",
+ "mark", unpacked.data.via.map.ptr[i].val,
+ entry->data.filemark.name, u64, TOCHAR);
}
- if (entry->data.filemark.mark.col < 0) {
- emsgf(_(READERR("mark", "has invalid column number")), initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
- }
- SET_ADDITIONAL_DATA(entry->data.filemark.additional_data, "mark");
- break;
+ LONG_KEY(unpacked, "mark", KEY_LNUM, entry->data.filemark.mark.lnum)
+ INTEGER_KEY(unpacked, "mark", KEY_COL, entry->data.filemark.mark.col)
+ STRING_KEY(unpacked, "mark", KEY_FILE, entry->data.filemark.fname)
+ ADDITIONAL_KEY(unpacked)
}
- case kSDItemRegister: {
- if (unpacked.data.type != MSGPACK_OBJECT_MAP) {
- emsgf(_(READERR("register", "is not a dictionary")), initial_fpos);
- goto shada_read_next_item_error;
- }
- garray_T ad_ga;
- ga_init(&ad_ga, sizeof(*(unpacked.data.via.map.ptr)), 1);
- for (size_t i = 0; i < unpacked.data.via.map.size; i++) {
- CHECK_KEY_IS_STR(unpacked, "register")
- if (CHECK_KEY(unpacked.data.via.map.ptr[i].key,
- REG_KEY_CONTENTS)) {
- if (unpacked.data.via.map.ptr[i].val.type != MSGPACK_OBJECT_ARRAY) {
- emsgf(_(READERR("register",
- "has " REG_KEY_CONTENTS
- " key with non-array value")),
- initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
- }
- if (unpacked.data.via.map.ptr[i].val.via.array.size == 0) {
- emsgf(_(READERR("register",
- "has " REG_KEY_CONTENTS " key with empty array")),
- initial_fpos);
+ if (entry->data.filemark.fname == NULL) {
+ emsgf(_(READERR("mark", "is missing file name")), initial_fpos);
+ CLEAR_GA_AND_ERROR_OUT(ad_ga);
+ }
+ if (entry->data.filemark.mark.lnum <= 0) {
+ emsgf(_(READERR("mark", "has invalid line number")), initial_fpos);
+ CLEAR_GA_AND_ERROR_OUT(ad_ga);
+ }
+ if (entry->data.filemark.mark.col < 0) {
+ emsgf(_(READERR("mark", "has invalid column number")), initial_fpos);
+ CLEAR_GA_AND_ERROR_OUT(ad_ga);
+ }
+ SET_ADDITIONAL_DATA(entry->data.filemark.additional_data, "mark");
+ break;
+ }
+ case kSDItemRegister: {
+ if (unpacked.data.type != MSGPACK_OBJECT_MAP) {
+ emsgf(_(READERR("register", "is not a dictionary")), initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ garray_T ad_ga;
+ ga_init(&ad_ga, sizeof(*(unpacked.data.via.map.ptr)), 1);
+ for (size_t i = 0; i < unpacked.data.via.map.size; i++) {
+ CHECK_KEY_IS_STR(unpacked, "register")
+ if (CHECK_KEY(unpacked.data.via.map.ptr[i].key,
+ REG_KEY_CONTENTS)) {
+ if (unpacked.data.via.map.ptr[i].val.type != MSGPACK_OBJECT_ARRAY) {
+ emsgf(_(READERR("register",
+ "has " REG_KEY_CONTENTS
+ " key with non-array value")),
+ initial_fpos);
+ CLEAR_GA_AND_ERROR_OUT(ad_ga);
+ }
+ if (unpacked.data.via.map.ptr[i].val.via.array.size == 0) {
+ emsgf(_(READERR("register",
+ "has " REG_KEY_CONTENTS " key with empty array")),
+ initial_fpos);
+ CLEAR_GA_AND_ERROR_OUT(ad_ga);
+ }
+ const msgpack_object_array arr =
+ unpacked.data.via.map.ptr[i].val.via.array;
+ for (size_t j = 0; j < arr.size; j++) {
+ if (arr.ptr[j].type != MSGPACK_OBJECT_BIN) {
+ emsgf(_(READERR("register", "has " REG_KEY_CONTENTS " array "
+ "with non-binary value")), initial_fpos);
CLEAR_GA_AND_ERROR_OUT(ad_ga);
}
- const msgpack_object_array arr =
- unpacked.data.via.map.ptr[i].val.via.array;
- for (size_t j = 0; j < arr.size; j++) {
- if (arr.ptr[j].type != MSGPACK_OBJECT_BIN) {
- emsgf(_(READERR("register", "has " REG_KEY_CONTENTS " array "
- "with non-binary value")), initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
- }
- }
- entry->data.reg.contents_size = arr.size;
- entry->data.reg.contents = xmalloc(arr.size * sizeof(char *));
- for (size_t j = 0; j < arr.size; j++) {
- entry->data.reg.contents[j] = BIN_CONVERTED(arr.ptr[j].via.bin);
- }
}
- BOOLEAN_KEY(unpacked, "register", REG_KEY_UNNAMED,
- entry->data.reg.is_unnamed)
- TYPED_KEY(unpacked, "register", REG_KEY_TYPE, "an unsigned integer",
- entry->data.reg.type, POSITIVE_INTEGER, u64, TOU8)
- TYPED_KEY(unpacked, "register", KEY_NAME_CHAR, "an unsigned integer",
- entry->data.reg.name, POSITIVE_INTEGER, u64, TOCHAR)
- TYPED_KEY(unpacked, "register", REG_KEY_WIDTH, "an unsigned integer",
- entry->data.reg.width, POSITIVE_INTEGER, u64, TOSIZE)
- ADDITIONAL_KEY(unpacked)
- }
- if (entry->data.reg.contents == NULL) {
- emsgf(_(READERR("register", "has missing " REG_KEY_CONTENTS " array")),
- initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
+ entry->data.reg.contents_size = arr.size;
+ entry->data.reg.contents = xmalloc(arr.size * sizeof(char *));
+ for (size_t j = 0; j < arr.size; j++) {
+ entry->data.reg.contents[j] = BIN_CONVERTED(arr.ptr[j].via.bin);
+ }
}
- SET_ADDITIONAL_DATA(entry->data.reg.additional_data, "register");
- break;
+ BOOLEAN_KEY(unpacked, "register", REG_KEY_UNNAMED,
+ entry->data.reg.is_unnamed)
+ TYPED_KEY(unpacked, "register", REG_KEY_TYPE, "an unsigned integer",
+ entry->data.reg.type, POSITIVE_INTEGER, u64, TOU8)
+ TYPED_KEY(unpacked, "register", KEY_NAME_CHAR, "an unsigned integer",
+ entry->data.reg.name, POSITIVE_INTEGER, u64, TOCHAR)
+ TYPED_KEY(unpacked, "register", REG_KEY_WIDTH, "an unsigned integer",
+ entry->data.reg.width, POSITIVE_INTEGER, u64, TOSIZE)
+ ADDITIONAL_KEY(unpacked)
}
- case kSDItemHistoryEntry: {
- if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
- emsgf(_(READERR("history", "is not an array")), initial_fpos);
- goto shada_read_next_item_error;
- }
- if (unpacked.data.via.array.size < 2) {
- emsgf(_(READERR("history", "does not have enough elements")),
- initial_fpos);
+ if (entry->data.reg.contents == NULL) {
+ emsgf(_(READERR("register", "has missing " REG_KEY_CONTENTS " array")),
+ initial_fpos);
+ CLEAR_GA_AND_ERROR_OUT(ad_ga);
+ }
+ SET_ADDITIONAL_DATA(entry->data.reg.additional_data, "register");
+ break;
+ }
+ case kSDItemHistoryEntry: {
+ if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
+ emsgf(_(READERR("history", "is not an array")), initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ if (unpacked.data.via.array.size < 2) {
+ emsgf(_(READERR("history", "does not have enough elements")),
+ initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ if (unpacked.data.via.array.ptr[0].type
+ != MSGPACK_OBJECT_POSITIVE_INTEGER) {
+ emsgf(_(READERR("history", "has wrong history type type")),
+ initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ if (unpacked.data.via.array.ptr[1].type
+ != MSGPACK_OBJECT_BIN) {
+ emsgf(_(READERR("history", "has wrong history string type")),
+ initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ if (memchr(unpacked.data.via.array.ptr[1].via.bin.ptr, 0,
+ unpacked.data.via.array.ptr[1].via.bin.size) != NULL) {
+ emsgf(_(READERR("history", "contains string with zero byte inside")),
+ initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ entry->data.history_item.histtype =
+ (uint8_t)unpacked.data.via.array.ptr[0].via.u64;
+ const bool is_hist_search =
+ entry->data.history_item.histtype == HIST_SEARCH;
+ if (is_hist_search) {
+ if (unpacked.data.via.array.size < 3) {
+ emsgf(_(READERR("search history",
+ "does not have separator character")), initial_fpos);
goto shada_read_next_item_error;
}
- if (unpacked.data.via.array.ptr[0].type
+ if (unpacked.data.via.array.ptr[2].type
!= MSGPACK_OBJECT_POSITIVE_INTEGER) {
- emsgf(_(READERR("history", "has wrong history type type")),
- initial_fpos);
- goto shada_read_next_item_error;
- }
- if (unpacked.data.via.array.ptr[1].type
- != MSGPACK_OBJECT_BIN) {
- emsgf(_(READERR("history", "has wrong history string type")),
- initial_fpos);
- goto shada_read_next_item_error;
- }
- if (memchr(unpacked.data.via.array.ptr[1].via.bin.ptr, 0,
- unpacked.data.via.array.ptr[1].via.bin.size) != NULL) {
- emsgf(_(READERR("history", "contains string with zero byte inside")),
- initial_fpos);
+ emsgf(_(READERR("search history",
+ "has wrong history separator type")), initial_fpos);
goto shada_read_next_item_error;
}
- entry->data.history_item.histtype =
- (uint8_t) unpacked.data.via.array.ptr[0].via.u64;
- const bool is_hist_search =
- entry->data.history_item.histtype == HIST_SEARCH;
- if (is_hist_search) {
- if (unpacked.data.via.array.size < 3) {
- emsgf(_(READERR("search history",
- "does not have separator character")), initial_fpos);
- goto shada_read_next_item_error;
- }
- if (unpacked.data.via.array.ptr[2].type
- != MSGPACK_OBJECT_POSITIVE_INTEGER) {
- emsgf(_(READERR("search history",
- "has wrong history separator type")), initial_fpos);
+ entry->data.history_item.sep =
+ (char)unpacked.data.via.array.ptr[2].via.u64;
+ }
+ size_t strsize;
+ strsize = (
+ unpacked.data.via.array.ptr[1].via.bin.size
+ + 1 // Zero byte
+ + 1); // Separator character
+ entry->data.history_item.string = xmalloc(strsize);
+ memcpy(entry->data.history_item.string,
+ unpacked.data.via.array.ptr[1].via.bin.ptr,
+ unpacked.data.via.array.ptr[1].via.bin.size);
+ entry->data.history_item.string[strsize - 2] = 0;
+ entry->data.history_item.string[strsize - 1] =
+ entry->data.history_item.sep;
+ SET_ADDITIONAL_ELEMENTS(unpacked.data.via.array, (2 + is_hist_search),
+ entry->data.history_item.additional_elements,
+ "history");
+ break;
+ }
+ case kSDItemVariable: {
+ if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
+ emsgf(_(READERR("variable", "is not an array")), initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ if (unpacked.data.via.array.size < 2) {
+ emsgf(_(READERR("variable", "does not have enough elements")),
+ initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ if (unpacked.data.via.array.ptr[0].type != MSGPACK_OBJECT_BIN) {
+ emsgf(_(READERR("variable", "has wrong variable name type")),
+ initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ entry->data.global_var.name =
+ xmemdupz(unpacked.data.via.array.ptr[0].via.bin.ptr,
+ unpacked.data.via.array.ptr[0].via.bin.size);
+ SET_ADDITIONAL_ELEMENTS(unpacked.data.via.array, 2,
+ entry->data.global_var.additional_elements,
+ "variable");
+ bool is_blob = false;
+ // A msgpack BIN could be a String or Blob; an additional VAR_TYPE_BLOB
+ // element is stored with Blobs which can be used to differentiate them
+ if (unpacked.data.via.array.ptr[1].type == MSGPACK_OBJECT_BIN) {
+ const listitem_T *type_item
+ = tv_list_first(entry->data.global_var.additional_elements);
+ if (type_item != NULL) {
+ const typval_T *type_tv = TV_LIST_ITEM_TV(type_item);
+ if (type_tv->v_type != VAR_NUMBER
+ || type_tv->vval.v_number != VAR_TYPE_BLOB) {
+ emsgf(_(READERR("variable", "has wrong variable type")),
+ initial_fpos);
goto shada_read_next_item_error;
}
- entry->data.history_item.sep =
- (char) unpacked.data.via.array.ptr[2].via.u64;
+ is_blob = true;
}
- size_t strsize;
- strsize = (
- unpacked.data.via.array.ptr[1].via.bin.size
- + 1 // Zero byte
- + 1); // Separator character
- entry->data.history_item.string = xmalloc(strsize);
- memcpy(entry->data.history_item.string,
- unpacked.data.via.array.ptr[1].via.bin.ptr,
- unpacked.data.via.array.ptr[1].via.bin.size);
- entry->data.history_item.string[strsize - 2] = 0;
- entry->data.history_item.string[strsize - 1] =
- entry->data.history_item.sep;
- SET_ADDITIONAL_ELEMENTS(unpacked.data.via.array, (2 + is_hist_search),
- entry->data.history_item.additional_elements,
- "history");
- break;
}
- case kSDItemVariable: {
- if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
- emsgf(_(READERR("variable", "is not an array")), initial_fpos);
- goto shada_read_next_item_error;
- }
- if (unpacked.data.via.array.size < 2) {
- emsgf(_(READERR("variable", "does not have enough elements")),
- initial_fpos);
- goto shada_read_next_item_error;
- }
- if (unpacked.data.via.array.ptr[0].type != MSGPACK_OBJECT_BIN) {
- emsgf(_(READERR("variable", "has wrong variable name type")),
- initial_fpos);
- goto shada_read_next_item_error;
- }
- entry->data.global_var.name =
- xmemdupz(unpacked.data.via.array.ptr[0].via.bin.ptr,
- unpacked.data.via.array.ptr[0].via.bin.size);
- if (msgpack_to_vim(unpacked.data.via.array.ptr[1],
- &(entry->data.global_var.value)) == FAIL) {
- emsgf(_(READERR("variable", "has value that cannot "
- "be converted to the VimL value")), initial_fpos);
- goto shada_read_next_item_error;
- }
- SET_ADDITIONAL_ELEMENTS(unpacked.data.via.array, 2,
- entry->data.global_var.additional_elements,
- "variable");
- break;
+ if (is_blob) {
+ const msgpack_object_bin *const bin
+ = &unpacked.data.via.array.ptr[1].via.bin;
+ blob_T *const blob = tv_blob_alloc();
+ ga_concat_len(&blob->bv_ga, bin->ptr, (size_t)bin->size);
+ tv_blob_set_ret(&entry->data.global_var.value, blob);
+ } else if (msgpack_to_vim(unpacked.data.via.array.ptr[1],
+ &(entry->data.global_var.value)) == FAIL) {
+ emsgf(_(READERR("variable", "has value that cannot "
+ "be converted to the VimL value")), initial_fpos);
+ goto shada_read_next_item_error;
}
- case kSDItemSubString: {
- if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
- emsgf(_(READERR("sub string", "is not an array")), initial_fpos);
- goto shada_read_next_item_error;
- }
- if (unpacked.data.via.array.size < 1) {
- emsgf(_(READERR("sub string", "does not have enough elements")),
- initial_fpos);
- goto shada_read_next_item_error;
- }
- if (unpacked.data.via.array.ptr[0].type != MSGPACK_OBJECT_BIN) {
- emsgf(_(READERR("sub string", "has wrong sub string type")),
- initial_fpos);
- goto shada_read_next_item_error;
- }
- entry->data.sub_string.sub =
- BIN_CONVERTED(unpacked.data.via.array.ptr[0].via.bin);
- SET_ADDITIONAL_ELEMENTS(unpacked.data.via.array, 1,
- entry->data.sub_string.additional_elements,
- "sub string");
+ break;
+ }
+ case kSDItemSubString:
+ if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
+ emsgf(_(READERR("sub string", "is not an array")), initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ if (unpacked.data.via.array.size < 1) {
+ emsgf(_(READERR("sub string", "does not have enough elements")),
+ initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ if (unpacked.data.via.array.ptr[0].type != MSGPACK_OBJECT_BIN) {
+ emsgf(_(READERR("sub string", "has wrong sub string type")),
+ initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ entry->data.sub_string.sub =
+ BIN_CONVERTED(unpacked.data.via.array.ptr[0].via.bin);
+ SET_ADDITIONAL_ELEMENTS(unpacked.data.via.array, 1,
+ entry->data.sub_string.additional_elements,
+ "sub string");
+ break;
+ case kSDItemBufferList:
+ if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
+ emsgf(_(READERR("buffer list", "is not an array")), initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ if (unpacked.data.via.array.size == 0) {
break;
}
- case kSDItemBufferList: {
- if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
- emsgf(_(READERR("buffer list", "is not an array")), initial_fpos);
- goto shada_read_next_item_error;
- }
- if (unpacked.data.via.array.size == 0) {
- break;
- }
- entry->data.buffer_list.buffers =
- xcalloc(unpacked.data.via.array.size,
- sizeof(*entry->data.buffer_list.buffers));
- for (size_t i = 0; i < unpacked.data.via.array.size; i++) {
- entry->data.buffer_list.size++;
- msgpack_unpacked unpacked_2 = (msgpack_unpacked) {
- .data = unpacked.data.via.array.ptr[i],
- };
+ entry->data.buffer_list.buffers =
+ xcalloc(unpacked.data.via.array.size,
+ sizeof(*entry->data.buffer_list.buffers));
+ for (size_t i = 0; i < unpacked.data.via.array.size; i++) {
+ entry->data.buffer_list.size++;
+ msgpack_unpacked unpacked_2 = (msgpack_unpacked) {
+ .data = unpacked.data.via.array.ptr[i],
+ };
+ {
+ if (unpacked_2.data.type != MSGPACK_OBJECT_MAP) {
+ emsgf(_(RERR "Error while reading ShaDa file: "
+ "buffer list at position %" PRIu64 " "
+ "contains entry that is not a dictionary"),
+ initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ entry->data.buffer_list.buffers[i].pos = default_pos;
+ garray_T ad_ga;
+ ga_init(&ad_ga, sizeof(*(unpacked_2.data.via.map.ptr)), 1);
{
- if (unpacked_2.data.type != MSGPACK_OBJECT_MAP) {
- emsgf(_(RERR "Error while reading ShaDa file: "
- "buffer list at position %" PRIu64 " "
- "contains entry that is not a dictionary"),
- initial_fpos);
- goto shada_read_next_item_error;
- }
- entry->data.buffer_list.buffers[i].pos = default_pos;
- garray_T ad_ga;
- ga_init(&ad_ga, sizeof(*(unpacked_2.data.via.map.ptr)), 1);
+ // XXX: Temporarily reassign `i` because the macros depend on it.
+ const size_t j = i;
{
- // XXX: Temporarily reassign `i` because the macros depend on it.
- const size_t j = i;
- {
- for (i = 0; i < unpacked_2.data.via.map.size; i++) { // -V535
- CHECK_KEY_IS_STR(unpacked_2, "buffer list entry")
- LONG_KEY(unpacked_2, "buffer list entry", KEY_LNUM,
- entry->data.buffer_list.buffers[j].pos.lnum)
- INTEGER_KEY(unpacked_2, "buffer list entry", KEY_COL,
- entry->data.buffer_list.buffers[j].pos.col)
- STRING_KEY(unpacked_2, "buffer list entry", KEY_FILE,
- entry->data.buffer_list.buffers[j].fname)
- ADDITIONAL_KEY(unpacked_2)
- }
+ for (i = 0; i < unpacked_2.data.via.map.size; i++) { // -V535
+ CHECK_KEY_IS_STR(unpacked_2, "buffer list entry")
+ LONG_KEY(unpacked_2, "buffer list entry", KEY_LNUM,
+ entry->data.buffer_list.buffers[j].pos.lnum)
+ INTEGER_KEY(unpacked_2, "buffer list entry", KEY_COL,
+ entry->data.buffer_list.buffers[j].pos.col)
+ STRING_KEY(unpacked_2, "buffer list entry", KEY_FILE,
+ entry->data.buffer_list.buffers[j].fname)
+ ADDITIONAL_KEY(unpacked_2)
}
- i = j; // XXX: Restore `i`.
}
- if (entry->data.buffer_list.buffers[i].pos.lnum <= 0) {
- emsgf(_(RERR "Error while reading ShaDa file: "
- "buffer list at position %" PRIu64 " "
- "contains entry with invalid line number"),
- initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
- }
- if (entry->data.buffer_list.buffers[i].pos.col < 0) {
- emsgf(_(RERR "Error while reading ShaDa file: "
- "buffer list at position %" PRIu64 " "
- "contains entry with invalid column number"),
- initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
- }
- if (entry->data.buffer_list.buffers[i].fname == NULL) {
- emsgf(_(RERR "Error while reading ShaDa file: "
- "buffer list at position %" PRIu64 " "
- "contains entry that does not have a file name"),
- initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
- }
- SET_ADDITIONAL_DATA(
- entry->data.buffer_list.buffers[i].additional_data,
- "buffer list entry");
+ i = j; // XXX: Restore `i`.
+ }
+ if (entry->data.buffer_list.buffers[i].pos.lnum <= 0) {
+ emsgf(_(RERR "Error while reading ShaDa file: "
+ "buffer list at position %" PRIu64 " "
+ "contains entry with invalid line number"),
+ initial_fpos);
+ CLEAR_GA_AND_ERROR_OUT(ad_ga);
+ }
+ if (entry->data.buffer_list.buffers[i].pos.col < 0) {
+ emsgf(_(RERR "Error while reading ShaDa file: "
+ "buffer list at position %" PRIu64 " "
+ "contains entry with invalid column number"),
+ initial_fpos);
+ CLEAR_GA_AND_ERROR_OUT(ad_ga);
}
+ if (entry->data.buffer_list.buffers[i].fname == NULL) {
+ emsgf(_(RERR "Error while reading ShaDa file: "
+ "buffer list at position %" PRIu64 " "
+ "contains entry that does not have a file name"),
+ initial_fpos);
+ CLEAR_GA_AND_ERROR_OUT(ad_ga);
+ }
+ SET_ADDITIONAL_DATA(entry->data.buffer_list.buffers[i].additional_data,
+ "buffer list entry");
}
- break;
- }
- case kSDItemMissing:
- case kSDItemUnknown: {
- abort();
}
+ break;
+ case kSDItemMissing:
+ case kSDItemUnknown:
+ abort();
}
- entry->type = (ShadaEntryType) type_u64;
+ entry->type = (ShadaEntryType)type_u64;
ret = kSDReadStatusSuccess;
shada_read_next_item_end:
if (buf != NULL) {
@@ -4056,7 +3976,7 @@ shada_read_next_item_end:
}
return ret;
shada_read_next_item_error:
- entry->type = (ShadaEntryType) type_u64;
+ entry->type = (ShadaEntryType)type_u64;
shada_free_shada_entry(entry);
entry->type = kSDItemMissing;
goto shada_read_next_item_end;
@@ -4091,13 +4011,13 @@ shada_read_next_item_error:
static bool shada_removable(const char *name)
FUNC_ATTR_WARN_UNUSED_RESULT
{
- char *p;
+ char *p;
char part[MAXPATHL + 1];
bool retval = false;
char *new_name = home_replace_save(NULL, name);
- for (p = (char *) p_shada; *p; ) {
- (void) copy_option_part(&p, part, ARRAY_SIZE(part), ", ");
+ for (p = (char *)p_shada; *p; ) {
+ (void)copy_option_part(&p, part, ARRAY_SIZE(part), ", ");
if (part[0] == 'r') {
home_replace(NULL, part + 1, NameBuff, MAXPATHL, true);
size_t n = STRLEN(NameBuff);
@@ -4118,8 +4038,8 @@ static bool shada_removable(const char *name)
/// location.
///
/// @return number of jumplist entries
-static inline size_t shada_init_jumps(
- PossiblyFreedShadaEntry *jumps, khash_t(bufset) *const removable_bufs)
+static inline size_t shada_init_jumps(PossiblyFreedShadaEntry *jumps,
+ khash_t(bufset) *const removable_bufs)
{
if (!curwin->w_jumplistlen) {
return 0;
@@ -4146,9 +4066,9 @@ static inline size_t shada_init_jumps(
: fm.fmark.fnum != 0) {
continue;
}
- const char *const fname = (char *) (fm.fmark.fnum == 0
+ const char *const fname = (char *)(fm.fmark.fnum == 0
? (fm.fname == NULL ? NULL : fm.fname)
- : buf ? buf->b_ffname : NULL);
+ : buf ? buf->b_ffname : NULL);
if (fname == NULL) {
continue;
}
@@ -4161,7 +4081,7 @@ static inline size_t shada_init_jumps(
.filemark = {
.name = NUL,
.mark = fm.fmark.mark,
- .fname = (char *) fname,
+ .fname = (char *)fname,
.additional_data = fm.fmark.additional_data,
}
}
@@ -4242,9 +4162,8 @@ void shada_encode_gvars(msgpack_sbuffer *const sbuf)
do {
typval_T vartv;
const char *name = NULL;
- var_iter = var_shada_iter(
- var_iter, &name, &vartv,
- VAR_FLAVOUR_DEFAULT | VAR_FLAVOUR_SESSION | VAR_FLAVOUR_SHADA);
+ var_iter = var_shada_iter(var_iter, &name, &vartv,
+ VAR_FLAVOUR_DEFAULT | VAR_FLAVOUR_SESSION | VAR_FLAVOUR_SHADA);
if (name == NULL) {
break;
}
@@ -4274,8 +4193,7 @@ void shada_encode_gvars(msgpack_sbuffer *const sbuf)
/// Wrapper for reading from msgpack_sbuffer.
///
/// @return number of bytes read.
-static ptrdiff_t read_sbuf(ShaDaReadDef *const sd_reader, void *const dest,
- const size_t size)
+static ptrdiff_t read_sbuf(ShaDaReadDef *const sd_reader, void *const dest, const size_t size)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
msgpack_sbuffer *sbuf = (msgpack_sbuffer *)sd_reader->cookie;
@@ -4297,8 +4215,7 @@ static ptrdiff_t read_sbuf(ShaDaReadDef *const sd_reader, void *const dest,
///
/// @return FAIL in case of failure, OK in case of success. May set
/// sd_reader->eof.
-static int sd_sbuf_reader_skip_read(ShaDaReadDef *const sd_reader,
- const size_t offset)
+static int sd_sbuf_reader_skip_read(ShaDaReadDef *const sd_reader, const size_t offset)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
msgpack_sbuffer *sbuf = (msgpack_sbuffer *)sd_reader->cookie;
@@ -4316,8 +4233,7 @@ static int sd_sbuf_reader_skip_read(ShaDaReadDef *const sd_reader,
///
/// @param[in] sbuf msgpack_sbuffer to read from.
/// @param[out] sd_reader Location where reader structure will be saved.
-static void open_shada_sbuf_for_reading(const msgpack_sbuffer *const sbuf,
- ShaDaReadDef *sd_reader)
+static void open_shada_sbuf_for_reading(const msgpack_sbuffer *const sbuf, ShaDaReadDef *sd_reader)
FUNC_ATTR_NONNULL_ALL
{
*sd_reader = (ShaDaReadDef) {
diff --git a/src/nvim/sign.c b/src/nvim/sign.c
index 15fd25e096..25427de6bf 100644
--- a/src/nvim/sign.c
+++ b/src/nvim/sign.c
@@ -6,33 +6,33 @@
//
-#include "nvim/vim.h"
-#include "nvim/sign.h"
#include "nvim/ascii.h"
#include "nvim/buffer.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
-#include "nvim/ex_docmd.h"
#include "nvim/edit.h"
+#include "nvim/ex_docmd.h"
#include "nvim/fold.h"
#include "nvim/move.h"
+#include "nvim/option.h"
#include "nvim/screen.h"
+#include "nvim/sign.h"
#include "nvim/syntax.h"
-#include "nvim/option.h"
+#include "nvim/vim.h"
/// Struct to hold the sign properties.
typedef struct sign sign_T;
struct sign
{
- sign_T *sn_next; // next sign in list
- int sn_typenr; // type number of sign
- char_u *sn_name; // name of sign
- char_u *sn_icon; // name of pixmap
- char_u *sn_text; // text used instead of pixmap
- int sn_line_hl; // highlight ID for line
- int sn_text_hl; // highlight ID for text
- int sn_num_hl; // highlight ID for line number
+ sign_T *sn_next; // next sign in list
+ int sn_typenr; // type number of sign
+ char_u *sn_name; // name of sign
+ char_u *sn_icon; // name of pixmap
+ char_u *sn_text; // text used instead of pixmap
+ int sn_line_hl; // highlight ID for line
+ int sn_text_hl; // highlight ID for text
+ int sn_num_hl; // highlight ID for line number
};
static sign_T *first_sign = NULL;
@@ -42,19 +42,19 @@ static void sign_list_defined(sign_T *sp);
static void sign_undefine(sign_T *sp, sign_T *sp_prev);
static char *cmds[] = {
- "define",
+ "define",
#define SIGNCMD_DEFINE 0
- "undefine",
+ "undefine",
#define SIGNCMD_UNDEFINE 1
- "list",
+ "list",
#define SIGNCMD_LIST 2
- "place",
+ "place",
#define SIGNCMD_PLACE 3
- "unplace",
+ "unplace",
#define SIGNCMD_UNPLACE 4
- "jump",
+ "jump",
#define SIGNCMD_JUMP 5
- NULL
+ NULL
#define SIGNCMD_LAST 6
};
@@ -65,17 +65,17 @@ static int next_sign_id = 1; // next sign id in the global group
/// Initialize data needed for managing signs
void init_signs(void)
{
- hash_init(&sg_table); // sign group hash table
+ hash_init(&sg_table); // sign group hash table
}
/// A new sign in group 'groupname' is added. If the group is not present,
/// create it. Otherwise reference the group.
///
-static signgroup_T * sign_group_ref(const char_u *groupname)
+static signgroup_T *sign_group_ref(const char_u *groupname)
{
- hash_T hash;
- hashitem_T *hi;
- signgroup_T *group;
+ hash_T hash;
+ hashitem_T *hi;
+ signgroup_T *group;
hash = hash_hash(groupname);
hi = hash_lookup(&sg_table, (char *)groupname, STRLEN(groupname), hash);
@@ -100,7 +100,7 @@ static signgroup_T * sign_group_ref(const char_u *groupname)
/// removed, then remove the group.
static void sign_group_unref(char_u *groupname)
{
- hashitem_T *hi;
+ hashitem_T *hi;
signgroup_T *group;
hi = hash_find(&sg_table, groupname);
@@ -115,15 +115,15 @@ static void sign_group_unref(char_u *groupname)
}
}
-/// Returns TRUE if 'sign' is in 'group'.
+/// @return true if 'sign' is in 'group'.
/// A sign can either be in the global group (sign->group == NULL)
/// or in a named group. If 'group' is '*', then the sign is part of the group.
-int sign_in_group(sign_entry_T *sign, const char_u *group)
+bool sign_in_group(sign_entry_T *sign, const char_u *group)
{
- return ((group != NULL && STRCMP(group, "*") == 0)
- || (group == NULL && sign->se_group == NULL)
- || (group != NULL && sign->se_group != NULL
- && STRCMP(group, sign->se_group->sg_name) == 0));
+ return ((group != NULL && STRCMP(group, "*") == 0)
+ || (group == NULL && sign->se_group == NULL)
+ || (group != NULL && sign->se_group != NULL
+ && STRCMP(group, sign->se_group->sg_name) == 0));
}
/// Get the next free sign identifier in the specified group
@@ -143,7 +143,7 @@ int sign_group_get_next_signid(buf_T *buf, const char_u *groupname)
group = HI2SG(hi);
}
- // Search for the next usuable sign identifier
+ // Search for the next usable sign identifier
while (!found) {
if (group == NULL) {
id = next_sign_id++; // global group
@@ -166,17 +166,19 @@ int sign_group_get_next_signid(buf_T *buf, const char_u *groupname)
/// Insert a new sign into the signlist for buffer 'buf' between the 'prev' and
/// 'next' signs.
-static void insert_sign(
- buf_T *buf, // buffer to store sign in
- sign_entry_T *prev, // previous sign entry
- sign_entry_T *next, // next sign entry
- int id, // sign ID
- const char_u *group, // sign group; NULL for global group
- int prio, // sign priority
- linenr_T lnum, // line number which gets the mark
- int typenr, // typenr of sign we are adding
- bool has_text_or_icon // sign has text or icon
-)
+///
+/// @param buf buffer to store sign in
+/// @param prev previous sign entry
+/// @param next next sign entry
+/// @param id sign ID
+/// @param group sign group; NULL for global group
+/// @param prio sign priority
+/// @param lnum line number which gets the mark
+/// @param typenr typenr of sign we are adding
+/// @param has_text_or_icon sign has text or icon
+static void insert_sign(buf_T *buf, sign_entry_T *prev, sign_entry_T *next, int id,
+ const char_u *group, int prio, linenr_T lnum, int typenr,
+ bool has_text_or_icon)
{
sign_entry_T *newsign = xmalloc(sizeof(sign_entry_T));
newsign->se_id = id;
@@ -194,7 +196,7 @@ static void insert_sign(
if (next != NULL) {
next->se_prev = newsign;
}
- buf->b_signcols_max = -1;
+ buf->b_signcols_valid = false;
if (prev == NULL) {
// When adding first sign need to redraw the windows to create the
@@ -212,18 +214,19 @@ static void insert_sign(
}
/// Insert a new sign sorted by line number and sign priority.
-static void insert_sign_by_lnum_prio(
- buf_T *buf, // buffer to store sign in
- sign_entry_T *prev, // previous sign entry
- int id, // sign ID
- const char_u *group, // sign group; NULL for global group
- int prio, // sign priority
- linenr_T lnum, // line number which gets the mark
- int typenr, // typenr of sign we are adding
- bool has_text_or_icon // sign has text or icon
-)
+///
+/// @param buf buffer to store sign in
+/// @param prev previous sign entry
+/// @param id sign ID
+/// @param group sign group; NULL for global group
+/// @param prio sign priority
+/// @param lnum line number which gets the mark
+/// @param typenr typenr of sign we are adding
+/// @param has_text_or_icon sign has text or icon
+static void insert_sign_by_lnum_prio(buf_T *buf, sign_entry_T *prev, int id, const char_u *group,
+ int prio, linenr_T lnum, int typenr, bool has_text_or_icon)
{
- sign_entry_T *sign;
+ sign_entry_T *sign;
// keep signs sorted by lnum, priority and id: insert new sign at
// the proper position in the list for this lnum.
@@ -242,9 +245,9 @@ static void insert_sign_by_lnum_prio(
}
/// Get the name of a sign by its typenr.
-char_u * sign_typenr2name(int typenr)
+char_u *sign_typenr2name(int typenr)
{
- sign_T *sp;
+ sign_T *sp;
for (sp = first_sign; sp != NULL; sp = sp->sn_next) {
if (sp->sn_typenr == typenr) {
@@ -255,9 +258,9 @@ char_u * sign_typenr2name(int typenr)
}
/// Return information about a sign in a Dict
-dict_T * sign_get_info(sign_entry_T *sign)
+dict_T *sign_get_info(sign_entry_T *sign)
{
- dict_T *d = tv_dict_alloc();
+ dict_T *d = tv_dict_alloc();
tv_dict_add_nr(d, S_LEN("id"), sign->se_id);
tv_dict_add_str(d, S_LEN("group"), ((sign->se_group == NULL)
? (char *)""
@@ -345,15 +348,16 @@ 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.
-void buf_addsign(
- buf_T *buf, // buffer to store sign in
- int id, // sign ID
- const char_u *groupname, // sign group
- int prio, // sign priority
- linenr_T lnum, // line number which gets the mark
- int typenr, // typenr of sign we are adding
- bool has_text_or_icon // sign has text or icon
-)
+///
+/// @param buf buffer to store sign in
+/// @param id sign ID
+/// @param groupname sign group
+/// @param prio sign priority
+/// @param lnum line number which gets the mark
+/// @param typenr typenr of sign we are adding
+/// @param has_text_or_icon sign has text or icon
+void buf_addsign(buf_T *buf, int id, const char_u *groupname, int prio, linenr_T lnum, int typenr,
+ bool has_text_or_icon)
{
sign_entry_T *sign; // a sign in the signlist
sign_entry_T *prev; // the previous sign
@@ -368,53 +372,51 @@ void buf_addsign(
sign_sort_by_prio_on_line(buf, sign);
return;
} else if (lnum < sign->se_lnum) {
- insert_sign_by_lnum_prio(
- buf,
- prev,
- id,
- groupname,
- prio,
- lnum,
- typenr,
- has_text_or_icon);
+ insert_sign_by_lnum_prio(buf,
+ prev,
+ id,
+ groupname,
+ prio,
+ lnum,
+ typenr,
+ has_text_or_icon);
return;
}
prev = sign;
}
- insert_sign_by_lnum_prio(
- buf,
- prev,
- id,
- groupname,
- prio,
- lnum,
- typenr,
- has_text_or_icon);
+ insert_sign_by_lnum_prio(buf,
+ prev,
+ id,
+ groupname,
+ prio,
+ lnum,
+ typenr,
+ has_text_or_icon);
}
-// For an existing, placed sign "markId" change the type to "typenr".
-// Returns the line number of the sign, or zero if the sign is not found.
-linenr_T buf_change_sign_type(
- buf_T *buf, // buffer to store sign in
- int markId, // sign ID
- const char_u *group, // sign group
- int typenr, // typenr of sign we are adding
- int prio // sign priority
-)
+/// For an existing, placed sign "markId" change the type to "typenr".
+/// Returns the line number of the sign, or zero if the sign is not found.
+///
+/// @param buf buffer to store sign in
+/// @param markId sign ID
+/// @param group sign group
+/// @param typenr typenr of sign we are adding
+/// @param prio sign priority
+linenr_T buf_change_sign_type(buf_T *buf, int markId, const char_u *group, int typenr, int prio)
{
- sign_entry_T *sign; // a sign in the signlist
+ sign_entry_T *sign; // a sign in the signlist
- FOR_ALL_SIGNS_IN_BUF(buf, sign) {
- if (sign->se_id == markId && sign_in_group(sign, group)) {
- sign->se_typenr = typenr;
- sign->se_priority = prio;
- sign_sort_by_prio_on_line(buf, sign);
- return sign->se_lnum;
- }
+ FOR_ALL_SIGNS_IN_BUF(buf, sign) {
+ if (sign->se_id == markId && sign_in_group(sign, group)) {
+ sign->se_typenr = typenr;
+ sign->se_priority = prio;
+ sign_sort_by_prio_on_line(buf, sign);
+ return sign->se_lnum;
}
+ }
- return (linenr_T)0;
+ return (linenr_T)0;
}
/// Return the sign attrs which has the attribute specified by 'type'. Returns
@@ -426,44 +428,43 @@ linenr_T buf_change_sign_type(
/// @param max_signs the number of signs, with priority for the ones
/// with the highest Ids.
/// @return Attrs of the matching sign, or NULL
-sign_attrs_T * sign_get_attr(SignType type, sign_attrs_T sattrs[],
- int idx, int max_signs)
+sign_attrs_T *sign_get_attr(SignType type, sign_attrs_T sattrs[], int idx, int max_signs)
{
- sign_attrs_T *matches[SIGN_SHOW_MAX];
- int nr_matches = 0;
-
- for (int i = 0; i < SIGN_SHOW_MAX; i++) {
- if ( (type == SIGN_TEXT && sattrs[i].sat_text != NULL)
- || (type == SIGN_LINEHL && sattrs[i].sat_linehl != 0)
- || (type == SIGN_NUMHL && sattrs[i].sat_numhl != 0)) {
- matches[nr_matches] = &sattrs[i];
- nr_matches++;
- // attr list is sorted with most important (priority, id), thus we
- // may stop as soon as we have max_signs matches
- if (nr_matches >= max_signs) {
- break;
- }
- }
+ sign_attrs_T *matches[SIGN_SHOW_MAX];
+ int nr_matches = 0;
+
+ for (int i = 0; i < SIGN_SHOW_MAX; i++) {
+ if ( (type == SIGN_TEXT && sattrs[i].sat_text != NULL)
+ || (type == SIGN_LINEHL && sattrs[i].sat_linehl != 0)
+ || (type == SIGN_NUMHL && sattrs[i].sat_numhl != 0)) {
+ matches[nr_matches] = &sattrs[i];
+ nr_matches++;
+ // attr list is sorted with most important (priority, id), thus we
+ // may stop as soon as we have max_signs matches
+ if (nr_matches >= max_signs) {
+ break;
+ }
}
+ }
- if (nr_matches > idx) {
- return matches[nr_matches - idx - 1];
- }
+ if (nr_matches > idx) {
+ return matches[nr_matches - idx - 1];
+ }
- return NULL;
+ return NULL;
}
/// Lookup a sign by typenr. Returns NULL if sign is not found.
-static sign_T * find_sign_by_typenr(int typenr)
+static sign_T *find_sign_by_typenr(int typenr)
{
- sign_T *sp;
+ sign_T *sp;
- for (sp = first_sign; sp != NULL; sp = sp->sn_next) {
- if (sp->sn_typenr == typenr) {
- return sp;
- }
+ for (sp = first_sign; sp != NULL; sp = sp->sn_next) {
+ if (sp->sn_typenr == typenr) {
+ return sp;
}
- return NULL;
+ }
+ return NULL;
}
/// Return the attributes of all the signs placed on line 'lnum' in buffer
@@ -474,44 +475,44 @@ static sign_T * find_sign_by_typenr(int typenr)
/// @return Number of signs of which attrs were found
int buf_get_signattrs(buf_T *buf, linenr_T lnum, sign_attrs_T sattrs[])
{
- sign_entry_T *sign;
- sign_T *sp;
+ sign_entry_T *sign;
+ sign_T *sp;
- int nr_matches = 0;
+ int nr_matches = 0;
- FOR_ALL_SIGNS_IN_BUF(buf, sign) {
- if (sign->se_lnum > lnum) {
- // Signs are sorted by line number in the buffer. No need to check
- // for signs after the specified line number 'lnum'.
- break;
- }
+ FOR_ALL_SIGNS_IN_BUF(buf, sign) {
+ if (sign->se_lnum > lnum) {
+ // Signs are sorted by line number in the buffer. No need to check
+ // for signs after the specified line number 'lnum'.
+ break;
+ }
- if (sign->se_lnum == lnum) {
- sign_attrs_T sattr;
- memset(&sattr, 0, sizeof(sattr));
- sattr.sat_typenr = sign->se_typenr;
- sp = find_sign_by_typenr(sign->se_typenr);
- if (sp != NULL) {
- sattr.sat_text = sp->sn_text;
- if (sattr.sat_text != NULL && sp->sn_text_hl != 0) {
- sattr.sat_texthl = syn_id2attr(sp->sn_text_hl);
- }
- if (sp->sn_line_hl != 0) {
- sattr.sat_linehl = syn_id2attr(sp->sn_line_hl);
- }
- if (sp->sn_num_hl != 0) {
- sattr.sat_numhl = syn_id2attr(sp->sn_num_hl);
- }
- }
-
- sattrs[nr_matches] = sattr;
- nr_matches++;
- if (nr_matches == SIGN_SHOW_MAX) {
- break;
- }
+ if (sign->se_lnum == lnum) {
+ sign_attrs_T sattr;
+ memset(&sattr, 0, sizeof(sattr));
+ sattr.sat_typenr = sign->se_typenr;
+ sp = find_sign_by_typenr(sign->se_typenr);
+ if (sp != NULL) {
+ sattr.sat_text = sp->sn_text;
+ if (sattr.sat_text != NULL && sp->sn_text_hl != 0) {
+ sattr.sat_texthl = syn_id2attr(sp->sn_text_hl);
+ }
+ if (sp->sn_line_hl != 0) {
+ sattr.sat_linehl = syn_id2attr(sp->sn_line_hl);
+ }
+ if (sp->sn_num_hl != 0) {
+ sattr.sat_numhl = syn_id2attr(sp->sn_num_hl);
}
+ }
+
+ sattrs[nr_matches] = sattr;
+ nr_matches++;
+ if (nr_matches == SIGN_SHOW_MAX) {
+ break;
+ }
}
- return nr_matches;
+ }
+ return nr_matches;
}
/// Delete sign 'id' in group 'group' from buffer 'buf'.
@@ -520,21 +521,22 @@ int buf_get_signattrs(buf_T *buf, linenr_T lnum, sign_attrs_T sattrs[])
/// If 'group' is '*', then delete the sign in all the groups. If 'group' is
/// NULL, then delete the sign in the global group. Otherwise delete the sign in
/// the specified group.
-/// Returns the line number of the deleted sign. If multiple signs are deleted,
+///
+/// @param buf buffer sign is stored in
+/// @param atlnum sign at this line, 0 - at any line
+/// @param id sign id
+/// @param group sign group
+///
+/// @return the line number of the deleted sign. If multiple signs are deleted,
/// then returns the line number of the last sign deleted.
-linenr_T buf_delsign(
- buf_T *buf, // buffer sign is stored in
- linenr_T atlnum, // sign at this line, 0 - at any line
- int id, // sign id
- char_u *group // sign group
-)
+linenr_T buf_delsign(buf_T *buf, linenr_T atlnum, int id, char_u *group)
{
sign_entry_T **lastp; // pointer to pointer to current sign
sign_entry_T *sign; // a sign in a b_signlist
sign_entry_T *next; // the next sign in a b_signlist
linenr_T lnum; // line number whose sign was deleted
- buf->b_signcols_max = -1;
+ buf->b_signcols_valid = false;
lastp = &buf->b_signlist;
lnum = 0;
for (sign = buf->b_signlist; sign != NULL; sign = next) {
@@ -580,30 +582,30 @@ linenr_T buf_delsign(
/// 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.
-int buf_findsign(
- buf_T *buf, // buffer to store sign in
- int id, // sign ID
- char_u *group // sign group
-)
+///
+/// @param buf buffer to store sign in
+/// @param id sign ID
+/// @param group sign group
+int buf_findsign(buf_T *buf, int id, char_u *group)
{
- sign_entry_T *sign; // a sign in the signlist
+ sign_entry_T *sign; // a sign in the signlist
- FOR_ALL_SIGNS_IN_BUF(buf, sign) {
- if (sign->se_id == id && sign_in_group(sign, group)) {
- return (int)sign->se_lnum;
- }
+ FOR_ALL_SIGNS_IN_BUF(buf, sign) {
+ if (sign->se_id == id && sign_in_group(sign, group)) {
+ return (int)sign->se_lnum;
}
+ }
- return 0;
+ return 0;
}
/// Return the sign at line 'lnum' in buffer 'buf'. Returns NULL if a sign is
/// not found at the line. If 'groupname' is NULL, searches in the global group.
-static sign_entry_T * buf_getsign_at_line(
- buf_T *buf, // buffer whose sign we are searching for
- linenr_T lnum, // line number of sign
- char_u *groupname // sign group name
-)
+///
+/// @param buf buffer whose sign we are searching for
+/// @param lnum line number of sign
+/// @param groupname sign group name
+static sign_entry_T *buf_getsign_at_line(buf_T *buf, linenr_T lnum, char_u *groupname)
{
sign_entry_T *sign; // a sign in the signlist
@@ -623,61 +625,61 @@ static sign_entry_T * buf_getsign_at_line(
}
/// Return the identifier of the sign at line number 'lnum' in buffer 'buf'.
-int buf_findsign_id(
- buf_T *buf, // buffer whose sign we are searching for
- linenr_T lnum, // line number of sign
- char_u *groupname // sign group name
-)
+///
+/// @param buf buffer whose sign we are searching for
+/// @param lnum line number of sign
+/// @param groupname sign group name
+int buf_findsign_id(buf_T *buf, linenr_T lnum, char_u *groupname)
{
- sign_entry_T *sign; // a sign in the signlist
+ sign_entry_T *sign; // a sign in the signlist
- sign = buf_getsign_at_line(buf, lnum, groupname);
- if (sign != NULL) {
- return sign->se_id;
- }
+ sign = buf_getsign_at_line(buf, lnum, groupname);
+ if (sign != NULL) {
+ return sign->se_id;
+ }
- return 0;
+ return 0;
}
/// Delete signs in buffer "buf".
void buf_delete_signs(buf_T *buf, char_u *group)
{
- sign_entry_T *sign;
- sign_entry_T **lastp; // pointer to pointer to current sign
- sign_entry_T *next;
+ sign_entry_T *sign;
+ sign_entry_T **lastp; // pointer to pointer to current sign
+ sign_entry_T *next;
- // When deleting the last sign need to redraw the windows to remove the
- // sign column. Not when curwin is NULL (this means we're exiting).
- if (buf->b_signlist != NULL && curwin != NULL) {
- changed_line_abv_curs();
- }
+ // When deleting the last sign need to redraw the windows to remove the
+ // sign column. Not when curwin is NULL (this means we're exiting).
+ if (buf->b_signlist != NULL && curwin != NULL) {
+ changed_line_abv_curs();
+ }
- lastp = &buf->b_signlist;
- for (sign = buf->b_signlist; sign != NULL; sign = next) {
- next = sign->se_next;
- if (sign_in_group(sign, group)) {
- *lastp = next;
- if (next != NULL) {
- next->se_prev = sign->se_prev;
- }
- if (sign->se_group != NULL) {
- sign_group_unref(sign->se_group->sg_name);
- }
- xfree(sign);
- } else {
- lastp = &sign->se_next;
+ lastp = &buf->b_signlist;
+ for (sign = buf->b_signlist; sign != NULL; sign = next) {
+ next = sign->se_next;
+ if (sign_in_group(sign, group)) {
+ *lastp = next;
+ if (next != NULL) {
+ next->se_prev = sign->se_prev;
+ }
+ if (sign->se_group != NULL) {
+ sign_group_unref(sign->se_group->sg_name);
}
+ xfree(sign);
+ } else {
+ lastp = &sign->se_next;
}
- buf->b_signcols_max = -1;
+ }
+ buf->b_signcols_valid = false;
}
/// List placed signs for "rbuf". If "rbuf" is NULL do it for all buffers.
void sign_list_placed(buf_T *rbuf, char_u *sign_group)
{
buf_T *buf;
- sign_entry_T *sign;
- char lbuf[MSG_BUF_LEN];
- char group[MSG_BUF_LEN];
+ sign_entry_T *sign;
+ char lbuf[MSG_BUF_LEN];
+ char group[MSG_BUF_LEN];
MSG_PUTS_TITLE(_("\n--- Signs ---"));
msg_putchar('\n');
@@ -720,12 +722,7 @@ void sign_list_placed(buf_T *rbuf, char_u *sign_group)
}
/// Adjust a placed sign for inserted/deleted lines.
-void sign_mark_adjust(
- linenr_T line1,
- linenr_T line2,
- long amount,
- long amount_after
-)
+void sign_mark_adjust(linenr_T line1, linenr_T line2, long amount, long amount_after)
{
sign_entry_T *sign; // a sign in a b_signlist
sign_entry_T *next; // the next sign in a b_signlist
@@ -735,7 +732,7 @@ void sign_mark_adjust(
int is_fixed = 0;
int signcol = win_signcol_configured(curwin, &is_fixed);
- curbuf->b_signcols_max = -1;
+ curbuf->b_signcols_valid = false;
lastp = &curbuf->b_signlist;
for (sign = curbuf->b_signlist; sign != NULL; sign = next) {
@@ -769,26 +766,26 @@ void sign_mark_adjust(
/// Find index of a ":sign" subcmd from its name.
/// "*end_cmd" must be writable.
-static int sign_cmd_idx(
- char_u *begin_cmd, // begin of sign subcmd
- char_u *end_cmd // just after sign subcmd
-)
+///
+/// @param begin_cmd begin of sign subcmd
+/// @param end_cmd just after sign subcmd
+static int sign_cmd_idx(char_u *begin_cmd, char_u *end_cmd)
{
- int idx;
- char_u save = *end_cmd;
+ int idx;
+ char_u save = *end_cmd;
- *end_cmd = (char_u)NUL;
- for (idx = 0; ; idx++) {
- if (cmds[idx] == NULL || STRCMP(begin_cmd, cmds[idx]) == 0) {
- break;
- }
+ *end_cmd = (char_u)NUL;
+ for (idx = 0; ; idx++) {
+ if (cmds[idx] == NULL || STRCMP(begin_cmd, cmds[idx]) == 0) {
+ break;
}
- *end_cmd = save;
- return idx;
+ }
+ *end_cmd = save;
+ return idx;
}
/// Find a sign by name. Also returns pointer to the previous sign.
-static sign_T * sign_find(const char_u *name, sign_T **sp_prev)
+static sign_T *sign_find(const char_u *name, sign_T **sp_prev)
{
sign_T *sp;
@@ -808,10 +805,10 @@ static sign_T * sign_find(const char_u *name, sign_T **sp_prev)
}
/// Allocate a new sign
-static sign_T * alloc_new_sign(char_u *name)
+static sign_T *alloc_new_sign(char_u *name)
{
- sign_T *sp;
- sign_T *lp;
+ sign_T *sp;
+ sign_T *lp;
int start = next_sign_typenr;
// Allocate a new sign.
@@ -858,8 +855,8 @@ static void sign_define_init_icon(sign_T *sp, char_u *icon)
/// Initialize the text for a new sign
static int sign_define_init_text(sign_T *sp, char_u *text)
{
- char_u *s;
- char_u *endp;
+ char_u *s;
+ char_u *endp;
int cells;
size_t len;
@@ -904,17 +901,11 @@ static int sign_define_init_text(sign_T *sp, char_u *text)
}
/// Define a new sign or update an existing sign
-int sign_define_by_name(
- char_u *name,
- char_u *icon,
- char_u *linehl,
- char_u *text,
- char_u *texthl,
- char_u *numhl
-)
+int sign_define_by_name(char_u *name, char_u *icon, char_u *linehl, char_u *text, char_u *texthl,
+ char_u *numhl)
{
- sign_T *sp_prev;
- sign_T *sp;
+ sign_T *sp_prev;
+ sign_T *sp;
sp = sign_find(name, &sp_prev);
if (sp == NULL) {
@@ -966,8 +957,8 @@ int sign_define_by_name(
/// Free the sign specified by 'name'.
int sign_undefine_by_name(const char_u *name)
{
- sign_T *sp_prev;
- sign_T *sp;
+ sign_T *sp_prev;
+ sign_T *sp;
sp = sign_find(name, &sp_prev);
if (sp == NULL) {
@@ -982,18 +973,18 @@ int sign_undefine_by_name(const char_u *name)
static void may_force_numberwidth_recompute(buf_T *buf, int unplace)
{
FOR_ALL_TAB_WINDOWS(tp, wp)
- if (wp->w_buffer == buf
- && (wp->w_p_nu || wp->w_p_rnu)
- && (unplace || wp->w_nrwidth_width < 2)
- && (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u')) {
- wp->w_nrwidth_line_count = 0;
- }
+ if (wp->w_buffer == buf
+ && (wp->w_p_nu || wp->w_p_rnu)
+ && (unplace || wp->w_nrwidth_width < 2)
+ && (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u')) {
+ wp->w_nrwidth_line_count = 0;
+ }
}
/// List the signs matching 'name'
static void sign_list_by_name(char_u *name)
{
- sign_T *sp;
+ sign_T *sp;
sp = sign_find(name, NULL);
if (sp != NULL) {
@@ -1005,14 +996,8 @@ static void sign_list_by_name(char_u *name)
/// Place a sign at the specified file location or update a sign.
-int sign_place(
- int *sign_id,
- const char_u *sign_group,
- const char_u *sign_name,
- buf_T *buf,
- linenr_T lnum,
- int prio
-)
+int sign_place(int *sign_id, const char_u *sign_group, const char_u *sign_name, buf_T *buf,
+ linenr_T lnum, int prio)
{
sign_T *sp;
@@ -1038,14 +1023,13 @@ int sign_place(
// ":sign place {id} line={lnum} name={name} file={fname}":
// place a sign
bool has_text_or_icon = sp->sn_text != NULL || sp->sn_icon != NULL;
- buf_addsign(
- buf,
- *sign_id,
- sign_group,
- prio,
- lnum,
- sp->sn_typenr,
- has_text_or_icon);
+ buf_addsign(buf,
+ *sign_id,
+ sign_group,
+ prio,
+ lnum,
+ sp->sn_typenr,
+ has_text_or_icon);
} else {
// ":sign place {id} file={fname}": change sign type and/or priority
lnum = buf_change_sign_type(buf, *sign_id, sign_group, sp->sn_typenr, prio);
@@ -1075,7 +1059,7 @@ int sign_unplace(int sign_id, char_u *sign_group, buf_T *buf, linenr_T atlnum)
redraw_buf_later(buf, NOT_VALID);
buf_delete_signs(buf, sign_group);
} else {
- linenr_T lnum;
+ linenr_T lnum;
// Delete only the specified signs
lnum = buf_delsign(buf, atlnum, sign_id, sign_group);
@@ -1098,7 +1082,7 @@ int sign_unplace(int sign_id, char_u *sign_group, buf_T *buf, linenr_T atlnum)
/// Unplace the sign at the current cursor line.
static void sign_unplace_at_cursor(char_u *groupname)
{
- int id = -1;
+ int id = -1;
id = buf_findsign_id(curwin->w_buffer, curwin->w_cursor.lnum, groupname);
if (id > 0) {
@@ -1144,13 +1128,13 @@ linenr_T sign_jump(int sign_id, char_u *sign_group, buf_T *buf)
/// ":sign define {name} ..." command
static void sign_define_cmd(char_u *sign_name, char_u *cmdline)
{
- char_u *arg;
- char_u *p = cmdline;
- char_u *icon = NULL;
- char_u *text = NULL;
- char_u *linehl = NULL;
- char_u *texthl = NULL;
- char_u *numhl = NULL;
+ char_u *arg;
+ char_u *p = cmdline;
+ char_u *icon = NULL;
+ char_u *text = NULL;
+ char_u *linehl = NULL;
+ char_u *texthl = NULL;
+ char_u *numhl = NULL;
int failed = false;
// set values for a defined sign.
@@ -1194,14 +1178,8 @@ static void sign_define_cmd(char_u *sign_name, char_u *cmdline)
}
/// ":sign place" command
-static void sign_place_cmd(
- buf_T *buf,
- linenr_T lnum,
- char_u *sign_name,
- int id,
- char_u *group,
- int prio
-)
+static void sign_place_cmd(buf_T *buf, linenr_T lnum, char_u *sign_name, int id, char_u *group,
+ int prio)
{
if (id <= 0) {
// List signs placed in a file/buffer
@@ -1233,62 +1211,56 @@ static void sign_place_cmd(
}
/// ":sign unplace" command
-static void sign_unplace_cmd(
- buf_T *buf,
- linenr_T lnum,
- char_u *sign_name,
- int id,
- char_u *group
-)
+static void sign_unplace_cmd(buf_T *buf, linenr_T lnum, char_u *sign_name, int id, char_u *group)
{
- if (lnum >= 0 || sign_name != NULL || (group != NULL && *group == '\0')) {
- EMSG(_(e_invarg));
- return;
- }
+ if (lnum >= 0 || sign_name != NULL || (group != NULL && *group == '\0')) {
+ EMSG(_(e_invarg));
+ return;
+ }
- if (id == -2) {
- if (buf != NULL) {
- // :sign unplace * file={fname}
- // :sign unplace * group={group} file={fname}
- // :sign unplace * group=* file={fname}
- // :sign unplace * buffer={nr}
- // :sign unplace * group={group} buffer={nr}
- // :sign unplace * group=* buffer={nr}
- sign_unplace(0, group, buf, 0);
- } else {
- // :sign unplace *
- // :sign unplace * group={group}
- // :sign unplace * group=*
- FOR_ALL_BUFFERS(cbuf) {
- if (cbuf->b_signlist != NULL) {
- buf_delete_signs(cbuf, group);
- }
+ if (id == -2) {
+ if (buf != NULL) {
+ // :sign unplace * file={fname}
+ // :sign unplace * group={group} file={fname}
+ // :sign unplace * group=* file={fname}
+ // :sign unplace * buffer={nr}
+ // :sign unplace * group={group} buffer={nr}
+ // :sign unplace * group=* buffer={nr}
+ sign_unplace(0, group, buf, 0);
+ } else {
+ // :sign unplace *
+ // :sign unplace * group={group}
+ // :sign unplace * group=*
+ FOR_ALL_BUFFERS(cbuf) {
+ if (cbuf->b_signlist != NULL) {
+ buf_delete_signs(cbuf, group);
}
}
+ }
+ } else {
+ if (buf != NULL) {
+ // :sign unplace {id} file={fname}
+ // :sign unplace {id} group={group} file={fname}
+ // :sign unplace {id} group=* file={fname}
+ // :sign unplace {id} buffer={nr}
+ // :sign unplace {id} group={group} buffer={nr}
+ // :sign unplace {id} group=* buffer={nr}
+ sign_unplace(id, group, buf, 0);
} else {
- if (buf != NULL) {
- // :sign unplace {id} file={fname}
- // :sign unplace {id} group={group} file={fname}
- // :sign unplace {id} group=* file={fname}
- // :sign unplace {id} buffer={nr}
- // :sign unplace {id} group={group} buffer={nr}
- // :sign unplace {id} group=* buffer={nr}
- sign_unplace(id, group, buf, 0);
+ if (id == -1) {
+ // :sign unplace group={group}
+ // :sign unplace group=*
+ sign_unplace_at_cursor(group);
} else {
- if (id == -1) {
- // :sign unplace group={group}
- // :sign unplace group=*
- sign_unplace_at_cursor(group);
- } else {
- // :sign unplace {id}
- // :sign unplace {id} group={group}
- // :sign unplace {id} group=*
- FOR_ALL_BUFFERS(cbuf) {
- sign_unplace(id, group, cbuf, 0);
- }
+ // :sign unplace {id}
+ // :sign unplace {id} group={group}
+ // :sign unplace {id} group=*
+ FOR_ALL_BUFFERS(cbuf) {
+ sign_unplace(id, group, cbuf, 0);
}
}
}
+ }
}
/// Jump to a placed sign commands:
@@ -1296,13 +1268,7 @@ static void sign_unplace_cmd(
/// :sign jump {id} buffer={nr}
/// :sign jump {id} group={group} file={fname}
/// :sign jump {id} group={group} buffer={nr}
-static void sign_jump_cmd(
- buf_T *buf,
- linenr_T lnum,
- char_u *sign_name,
- int id,
- char_u *group
-)
+static void sign_jump_cmd(buf_T *buf, linenr_T lnum, char_u *sign_name, int id, char_u *group)
{
if (sign_name == NULL && group == NULL && id == -1) {
EMSG(_(e_argreq));
@@ -1324,21 +1290,13 @@ static void sign_jump_cmd(
/// ":sign jump" commands.
/// The supported arguments are: line={lnum} name={name} group={group}
/// priority={prio} and file={fname} or buffer={nr}.
-static int parse_sign_cmd_args(
- int cmd,
- char_u *arg,
- char_u **sign_name,
- int *signid,
- char_u **group,
- int *prio,
- buf_T **buf,
- linenr_T *lnum
-)
+static int parse_sign_cmd_args(int cmd, char_u *arg, char_u **sign_name, int *signid,
+ char_u **group, int *prio, buf_T **buf, linenr_T *lnum)
{
- char_u *arg1;
- char_u *name;
- char_u *filename = NULL;
- int lnum_arg = false;
+ char_u *arg1;
+ char_u *name;
+ char_u *filename = NULL;
+ int lnum_arg = false;
// first arg could be placed sign id
arg1 = arg;
@@ -1448,7 +1406,7 @@ void ex_sign(exarg_T *eap)
} else if (*arg == NUL) {
EMSG(_("E156: Missing sign name"));
} else {
- char_u *name;
+ char_u *name;
// Isolate the sign name. If it's a number skip leading zeroes,
// so that "099" and "99" are the same sign. But keep "0".
@@ -1574,12 +1532,8 @@ list_T *get_buffer_signs(buf_T *buf)
}
/// Return information about all the signs placed in a buffer
-static void sign_get_placed_in_buf(
- buf_T *buf,
- linenr_T lnum,
- int sign_id,
- const char_u *sign_group,
- list_T *retlist)
+static void sign_get_placed_in_buf(buf_T *buf, linenr_T lnum, int sign_id, const char_u *sign_group,
+ list_T *retlist)
{
dict_T *d;
list_T *l;
@@ -1609,13 +1563,8 @@ static void sign_get_placed_in_buf(
/// Get a list of signs placed in buffer 'buf'. If 'num' is non-zero, return the
/// sign placed at the line number. If 'lnum' is zero, return all the signs
/// placed in 'buf'. If 'buf' is NULL, return signs placed in all the buffers.
-void sign_get_placed(
- buf_T *buf,
- linenr_T lnum,
- int sign_id,
- const char_u *sign_group,
- list_T *retlist
-)
+void sign_get_placed(buf_T *buf, linenr_T lnum, int sign_id, const char_u *sign_group,
+ list_T *retlist)
{
if (buf != NULL) {
sign_get_placed_in_buf(buf, lnum, sign_id, sign_group, retlist);
@@ -1697,13 +1646,13 @@ void free_signs(void)
static enum
{
- EXP_SUBCMD, // expand :sign sub-commands
- EXP_DEFINE, // expand :sign define {name} args
- EXP_PLACE, // expand :sign place {id} args
- EXP_LIST, // expand :sign place args
- EXP_UNPLACE, // expand :sign unplace"
- EXP_SIGN_NAMES, // expand with name of placed signs
- EXP_SIGN_GROUPS, // expand with name of placed sign groups
+ EXP_SUBCMD, // expand :sign sub-commands
+ EXP_DEFINE, // expand :sign define {name} args
+ EXP_PLACE, // expand :sign place {id} args
+ EXP_LIST, // expand :sign place args
+ EXP_UNPLACE, // expand :sign unplace"
+ EXP_SIGN_NAMES, // expand with name of placed signs
+ EXP_SIGN_GROUPS, // expand with name of placed sign groups
} expand_what;
// Return the n'th sign name (used for command line completion)
@@ -1740,45 +1689,45 @@ static char_u *get_nth_sign_group_name(int idx)
/// Function given to ExpandGeneric() to obtain the sign command
/// expansion.
-char_u * get_sign_name(expand_T *xp, int idx)
+char_u *get_sign_name(expand_T *xp, int idx)
{
switch (expand_what) {
- case EXP_SUBCMD:
- return (char_u *)cmds[idx];
- case EXP_DEFINE: {
- char *define_arg[] = { "icon=", "linehl=", "text=", "texthl=", "numhl=",
- NULL };
- return (char_u *)define_arg[idx];
- }
- case EXP_PLACE: {
- char *place_arg[] = { "line=", "name=", "group=", "priority=", "file=",
- "buffer=", NULL };
- return (char_u *)place_arg[idx];
- }
- case EXP_LIST: {
- char *list_arg[] = { "group=", "file=", "buffer=", NULL };
- return (char_u *)list_arg[idx];
- }
- case EXP_UNPLACE: {
- char *unplace_arg[] = { "group=", "file=", "buffer=", NULL };
- return (char_u *)unplace_arg[idx];
- }
- case EXP_SIGN_NAMES:
- return get_nth_sign_name(idx);
- case EXP_SIGN_GROUPS:
- return get_nth_sign_group_name(idx);
- default:
- return NULL;
+ case EXP_SUBCMD:
+ return (char_u *)cmds[idx];
+ case EXP_DEFINE: {
+ char *define_arg[] = { "icon=", "linehl=", "text=", "texthl=", "numhl=",
+ NULL };
+ return (char_u *)define_arg[idx];
+ }
+ case EXP_PLACE: {
+ char *place_arg[] = { "line=", "name=", "group=", "priority=", "file=",
+ "buffer=", NULL };
+ return (char_u *)place_arg[idx];
+ }
+ case EXP_LIST: {
+ char *list_arg[] = { "group=", "file=", "buffer=", NULL };
+ return (char_u *)list_arg[idx];
+ }
+ case EXP_UNPLACE: {
+ char *unplace_arg[] = { "group=", "file=", "buffer=", NULL };
+ return (char_u *)unplace_arg[idx];
+ }
+ case EXP_SIGN_NAMES:
+ return get_nth_sign_name(idx);
+ case EXP_SIGN_GROUPS:
+ return get_nth_sign_group_name(idx);
+ default:
+ return NULL;
}
}
/// Handle command line completion for :sign command.
void set_context_in_sign_cmd(expand_T *xp, char_u *arg)
{
- char_u *end_subcmd;
- char_u *last;
- int cmd_idx;
- char_u *begin_subcmd_args;
+ char_u *end_subcmd;
+ char_u *last;
+ int cmd_idx;
+ char_u *begin_subcmd_args;
// Default: expand subcommands.
xp->xp_context = EXPAND_SIGN;
@@ -1822,70 +1771,70 @@ void set_context_in_sign_cmd(expand_T *xp, char_u *arg)
// Expand last argument name (before equal sign).
xp->xp_pattern = last;
switch (cmd_idx) {
- case SIGNCMD_DEFINE:
- expand_what = EXP_DEFINE;
- break;
- case SIGNCMD_PLACE:
- // List placed signs
- if (ascii_isdigit(*begin_subcmd_args)) {
- // :sign place {id} {args}...
- expand_what = EXP_PLACE;
- } else {
- // :sign place {args}...
- expand_what = EXP_LIST;
- }
- break;
- case SIGNCMD_LIST:
- case SIGNCMD_UNDEFINE:
- // :sign list <CTRL-D>
- // :sign undefine <CTRL-D>
- expand_what = EXP_SIGN_NAMES;
- break;
- case SIGNCMD_JUMP:
- case SIGNCMD_UNPLACE:
- expand_what = EXP_UNPLACE;
- break;
- default:
- xp->xp_context = EXPAND_NOTHING;
+ case SIGNCMD_DEFINE:
+ expand_what = EXP_DEFINE;
+ break;
+ case SIGNCMD_PLACE:
+ // List placed signs
+ if (ascii_isdigit(*begin_subcmd_args)) {
+ // :sign place {id} {args}...
+ expand_what = EXP_PLACE;
+ } else {
+ // :sign place {args}...
+ expand_what = EXP_LIST;
+ }
+ break;
+ case SIGNCMD_LIST:
+ case SIGNCMD_UNDEFINE:
+ // :sign list <CTRL-D>
+ // :sign undefine <CTRL-D>
+ expand_what = EXP_SIGN_NAMES;
+ break;
+ case SIGNCMD_JUMP:
+ case SIGNCMD_UNPLACE:
+ expand_what = EXP_UNPLACE;
+ break;
+ default:
+ xp->xp_context = EXPAND_NOTHING;
}
} else {
- // Expand last argument value (after equal sign).
+ // Expand last argument value (after equal sign).
xp->xp_pattern = p + 1;
switch (cmd_idx) {
- case SIGNCMD_DEFINE:
- if (STRNCMP(last, "texthl", 6) == 0
- || STRNCMP(last, "linehl", 6) == 0
- || STRNCMP(last, "numhl", 5) == 0) {
- xp->xp_context = EXPAND_HIGHLIGHT;
- } else if (STRNCMP(last, "icon", 4) == 0) {
- xp->xp_context = EXPAND_FILES;
- } else {
- xp->xp_context = EXPAND_NOTHING;
- }
- break;
- case SIGNCMD_PLACE:
- if (STRNCMP(last, "name", 4) == 0) {
- expand_what = EXP_SIGN_NAMES;
- } else if (STRNCMP(last, "group", 5) == 0) {
- expand_what = EXP_SIGN_GROUPS;
- } else if (STRNCMP(last, "file", 4) == 0) {
- xp->xp_context = EXPAND_BUFFERS;
- } else {
- xp->xp_context = EXPAND_NOTHING;
- }
- break;
- case SIGNCMD_UNPLACE:
- case SIGNCMD_JUMP:
- if (STRNCMP(last, "group", 5) == 0) {
- expand_what = EXP_SIGN_GROUPS;
- } else if (STRNCMP(last, "file", 4) == 0) {
- xp->xp_context = EXPAND_BUFFERS;
- } else {
- xp->xp_context = EXPAND_NOTHING;
- }
- break;
- default:
+ case SIGNCMD_DEFINE:
+ if (STRNCMP(last, "texthl", 6) == 0
+ || STRNCMP(last, "linehl", 6) == 0
+ || STRNCMP(last, "numhl", 5) == 0) {
+ xp->xp_context = EXPAND_HIGHLIGHT;
+ } else if (STRNCMP(last, "icon", 4) == 0) {
+ xp->xp_context = EXPAND_FILES;
+ } else {
xp->xp_context = EXPAND_NOTHING;
+ }
+ break;
+ case SIGNCMD_PLACE:
+ if (STRNCMP(last, "name", 4) == 0) {
+ expand_what = EXP_SIGN_NAMES;
+ } else if (STRNCMP(last, "group", 5) == 0) {
+ expand_what = EXP_SIGN_GROUPS;
+ } else if (STRNCMP(last, "file", 4) == 0) {
+ xp->xp_context = EXPAND_BUFFERS;
+ } else {
+ xp->xp_context = EXPAND_NOTHING;
+ }
+ break;
+ case SIGNCMD_UNPLACE:
+ case SIGNCMD_JUMP:
+ if (STRNCMP(last, "group", 5) == 0) {
+ expand_what = EXP_SIGN_GROUPS;
+ } else if (STRNCMP(last, "file", 4) == 0) {
+ xp->xp_context = EXPAND_BUFFERS;
+ } else {
+ xp->xp_context = EXPAND_NOTHING;
+ }
+ break;
+ default:
+ xp->xp_context = EXPAND_NOTHING;
}
}
}
@@ -1914,11 +1863,11 @@ int sign_define_from_dict(const char *name_arg, dict_T *dict)
goto cleanup;
}
if (dict != NULL) {
- icon = tv_dict_get_string(dict, "icon" , true);
+ icon = tv_dict_get_string(dict, "icon", true);
linehl = tv_dict_get_string(dict, "linehl", true);
- text = tv_dict_get_string(dict, "text" , true);
+ text = tv_dict_get_string(dict, "text", true);
texthl = tv_dict_get_string(dict, "texthl", true);
- numhl = tv_dict_get_string(dict, "numhl" , true);
+ numhl = tv_dict_get_string(dict, "numhl", true);
}
if (sign_define_by_name((char_u *)name, (char_u *)icon, (char_u *)linehl,
@@ -1942,27 +1891,23 @@ cleanup:
/// values in 'retlist'.
void sign_define_multiple(list_T *l, list_T *retlist)
{
- int retval;
+ int retval;
- TV_LIST_ITER_CONST(l, li, {
- retval = -1;
- if (TV_LIST_ITEM_TV(li)->v_type == VAR_DICT) {
- retval = sign_define_from_dict(NULL, TV_LIST_ITEM_TV(li)->vval.v_dict);
- } else {
- EMSG(_(e_dictreq));
- }
- tv_list_append_number(retlist, retval);
- });
+ TV_LIST_ITER_CONST(l, li, {
+ retval = -1;
+ if (TV_LIST_ITEM_TV(li)->v_type == VAR_DICT) {
+ retval = sign_define_from_dict(NULL, TV_LIST_ITEM_TV(li)->vval.v_dict);
+ } else {
+ EMSG(_(e_dictreq));
+ }
+ tv_list_append_number(retlist, retval);
+ });
}
/// Place a new sign using the values specified in dict 'dict'. Returns the sign
/// identifier if successfully placed, otherwise returns 0.
-int sign_place_from_dict(
- typval_T *id_tv,
- typval_T *group_tv,
- typval_T *name_tv,
- typval_T *buf_tv,
- dict_T *dict)
+int sign_place_from_dict(typval_T *id_tv, typval_T *group_tv, typval_T *name_tv, typval_T *buf_tv,
+ dict_T *dict)
{
int sign_id = 0;
char_u *group = NULL;
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 771c2106db..3e56ad561b 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -72,15 +72,14 @@
#include <inttypes.h>
#include <limits.h>
#include <stdbool.h>
-#include <string.h>
#include <stdlib.h>
+#include <string.h>
#include <wctype.h>
-/* for offsetof() */
+// for offsetof()
#include <stddef.h>
#include "nvim/ascii.h"
-#include "nvim/spell.h"
#include "nvim/buffer.h"
#include "nvim/change.h"
#include "nvim/charset.h"
@@ -92,6 +91,7 @@
#include "nvim/ex_docmd.h"
#include "nvim/fileio.h"
#include "nvim/func_attr.h"
+#include "nvim/garray.h"
#include "nvim/getchar.h"
#include "nvim/hashtab.h"
#include "nvim/mark.h"
@@ -100,21 +100,21 @@
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
-#include "nvim/garray.h"
#include "nvim/normal.h"
#include "nvim/option.h"
+#include "nvim/os/input.h"
+#include "nvim/os/os.h"
#include "nvim/os_unix.h"
#include "nvim/path.h"
#include "nvim/regexp.h"
#include "nvim/screen.h"
#include "nvim/search.h"
+#include "nvim/spell.h"
#include "nvim/spellfile.h"
#include "nvim/strings.h"
#include "nvim/syntax.h"
-#include "nvim/undo.h"
#include "nvim/ui.h"
-#include "nvim/os/os.h"
-#include "nvim/os/input.h"
+#include "nvim/undo.h"
// only used for su_badflags
#define WF_MIXCAP 0x20 // mix of upper and lower case: macaRONI
@@ -151,26 +151,26 @@ typedef struct suginfo_S {
int su_maxscore; // maximum score for adding to su_ga
int su_sfmaxscore; // idem, for when doing soundfold words
garray_T su_sga; // like su_ga, sound-folded scoring
- char_u *su_badptr; // start of bad word in line
+ char_u *su_badptr; // start of bad word in line
int su_badlen; // length of detected bad word in line
int su_badflags; // caps flags for bad word
char_u su_badword[MAXWLEN]; // bad word truncated at su_badlen
char_u su_fbadword[MAXWLEN]; // su_badword case-folded
char_u su_sal_badword[MAXWLEN]; // su_badword soundfolded
hashtab_T su_banned; // table with banned words
- slang_T *su_sallang; // default language for sound folding
+ slang_T *su_sallang; // default language for sound folding
} suginfo_T;
// One word suggestion. Used in "si_ga".
typedef struct {
- char_u *st_word; // suggested word, allocated string
+ char_u *st_word; // suggested word, allocated string
int st_wordlen; // STRLEN(st_word)
int st_orglen; // length of replaced text
int st_score; // lower is better
int st_altscore; // used when st_score compares equal
bool st_salscore; // st_score is for soundalike
bool st_had_bonus; // bonus already included in score
- slang_T *st_slang; // language used for sound folding
+ slang_T *st_slang; // language used for sound folding
} suggest_T;
#define SUG(ga, i) (((suggest_T *)(ga).ga_data)[i])
@@ -235,14 +235,14 @@ typedef struct {
// Structure to store info for word matching.
typedef struct matchinf_S {
- langp_T *mi_lp; // info for language and region
+ langp_T *mi_lp; // info for language and region
// pointers to original text to be checked
- char_u *mi_word; // start of word being checked
- char_u *mi_end; // end of matching word so far
- char_u *mi_fend; // next char to be added to mi_fword
- char_u *mi_cend; // char after what was used for
- // mi_capflags
+ char_u *mi_word; // start of word being checked
+ char_u *mi_end; // end of matching word so far
+ char_u *mi_fend; // next char to be added to mi_fword
+ char_u *mi_cend; // char after what was used for
+ // mi_capflags
// case-folded text
char_u mi_fword[MAXWLEN + 1]; // mi_word case-folded
@@ -265,11 +265,11 @@ typedef struct matchinf_S {
// others
int mi_result; // result so far: SP_BAD, SP_OK, etc.
int mi_capflags; // WF_ONECAP WF_ALLCAP WF_KEEPCAP
- win_T *mi_win; // buffer being checked
+ win_T *mi_win; // buffer being checked
// for NOBREAK
int mi_result2; // "mi_resul" without following word
- char_u *mi_end2; // "mi_end" without following word
+ char_u *mi_end2; // "mi_end" without following word
} matchinf_T;
// Structure used for the cookie argument of do_in_runtimepath().
@@ -334,26 +334,24 @@ char *e_format = N_("E759: Format error in spell file");
static char_u *repl_from = NULL;
static char_u *repl_to = NULL;
-// Main spell-checking function.
-// "ptr" points to a character that could be the start of a word.
-// "*attrp" is set to the highlight index for a badly spelled word. For a
-// non-word or when it's OK it remains unchanged.
-// This must only be called when 'spelllang' is not empty.
-//
-// "capcol" is used to check for a Capitalised word after the end of a
-// sentence. If it's zero then perform the check. Return the column where to
-// check next, or -1 when no sentence end was found. If it's NULL then don't
-// worry.
-//
-// Returns the length of the word in bytes, also when it's OK, so that the
-// caller can skip over the word.
-size_t spell_check(
- win_T *wp, // current window
- char_u *ptr,
- hlf_T *attrp,
- int *capcol, // column to check for Capital
- bool docount // count good words
-)
+/// Main spell-checking function.
+/// "ptr" points to a character that could be the start of a word.
+/// "*attrp" is set to the highlight index for a badly spelled word. For a
+/// non-word or when it's OK it remains unchanged.
+/// This must only be called when 'spelllang' is not empty.
+///
+/// "capcol" is used to check for a Capitalised word after the end of a
+/// sentence. If it's zero then perform the check. Return the column where to
+/// check next, or -1 when no sentence end was found. If it's NULL then don't
+/// worry.
+///
+/// @param wp current window
+/// @param capcol column to check for Capital
+/// @param docount count good words
+///
+/// @return the length of the word in bytes, also when it's OK, so that the
+/// caller can skip over the word.
+size_t spell_check(win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, bool docount)
{
matchinf_T mi; // Most things are put in "mi" so that it can
// be passed to functions quickly.
@@ -383,7 +381,7 @@ size_t spell_check(
// julifeest".
if (*ptr >= '0' && *ptr <= '9') {
if (*ptr == '0' && (ptr[1] == 'b' || ptr[1] == 'B')) {
- mi.mi_end = (char_u*) skipbin((char*) ptr + 2);
+ mi.mi_end = (char_u *)skipbin((char *)ptr + 2);
} else if (*ptr == '0' && (ptr[1] == 'x' || ptr[1] == 'X')) {
mi.mi_end = skiphex(ptr + 2);
} else {
@@ -486,7 +484,7 @@ size_t spell_check(
// Count the word in the first language where it's found to be OK.
if (count_word && mi.mi_result == SP_OK) {
count_common_word(mi.mi_lp->lp_slang, ptr,
- (int)(mi.mi_end - ptr), 1);
+ (int)(mi.mi_end - ptr), 1);
count_word = false;
}
}
@@ -499,8 +497,8 @@ size_t spell_check(
return nrlen;
}
} else if (!spell_iswordp_nmw(ptr, wp)) {
- // When we are at a non-word character there is no error, just
- // skip over the character (try looking for a word after it).
+ // When we are at a non-word character there is no error, just
+ // skip over the character (try looking for a word after it).
if (capcol != NULL && wp->w_s->b_cap_prog != NULL) {
regmatch_T regmatch;
@@ -521,7 +519,7 @@ size_t spell_check(
MB_PTR_ADV(mi.mi_end);
} else if (mi.mi_result == SP_BAD
&& LANGP_ENTRY(wp->w_s->b_langp, 0)->lp_slang->sl_nobreak) {
- char_u *p, *fp;
+ char_u *p, *fp;
int save_result = mi.mi_result;
// First language in 'spelllang' is NOBREAK. Find first position
@@ -576,10 +574,10 @@ static void find_word(matchinf_T *mip, int mode)
{
int wlen = 0;
int flen;
- char_u *ptr;
- slang_T *slang = mip->mi_lp->lp_slang;
- char_u *byts;
- idx_T *idxs;
+ char_u *ptr;
+ slang_T *slang = mip->mi_lp->lp_slang;
+ char_u *byts;
+ idx_T *idxs;
if (mode == FIND_KEEPWORD || mode == FIND_KEEPCOMPOUND) {
// Check for word with matching case in keep-case tree.
@@ -588,9 +586,10 @@ static void find_word(matchinf_T *mip, int mode)
byts = slang->sl_kbyts;
idxs = slang->sl_kidxs;
- if (mode == FIND_KEEPCOMPOUND)
+ if (mode == FIND_KEEPCOMPOUND) {
// Skip over the previously found word(s).
wlen += mip->mi_compoff;
+ }
} else {
// Check for case-folded in case-folded tree.
ptr = mip->mi_fword;
@@ -607,12 +606,11 @@ static void find_word(matchinf_T *mip, int mode)
wlen = mip->mi_compoff;
flen -= mip->mi_compoff;
}
-
}
- if (byts == NULL)
+ if (byts == NULL) {
return; // array is empty
-
+ }
idx_T arridx = 0;
int endlen[MAXWLEN]; // length at possible word endings
idx_T endidx[MAXWLEN]; // possible word endings
@@ -625,8 +623,9 @@ static void find_word(matchinf_T *mip, int mode)
// - we reach the end of the tree,
// - or we reach the end of the line.
for (;; ) {
- if (flen <= 0 && *mip->mi_fend != NUL)
+ if (flen <= 0 && *mip->mi_fend != NUL) {
flen = fold_more(mip);
+ }
len = byts[arridx++];
@@ -648,35 +647,39 @@ static void find_word(matchinf_T *mip, int mode)
++arridx;
--len;
}
- if (len == 0)
+ if (len == 0) {
break; // no children, word must end here
+ }
}
// Stop looking at end of the line.
- if (ptr[wlen] == NUL)
+ if (ptr[wlen] == NUL) {
break;
+ }
// Perform a binary search in the list of accepted bytes.
c = ptr[wlen];
- if (c == TAB) // <Tab> is handled like <Space>
+ if (c == TAB) { // <Tab> is handled like <Space>
c = ' ';
+ }
idx_T lo = arridx;
idx_T hi = arridx + len - 1;
while (lo < hi) {
idx_T m = (lo + hi) / 2;
- if (byts[m] > c)
+ if (byts[m] > c) {
hi = m - 1;
- else if (byts[m] < c)
+ } else if (byts[m] < c) {
lo = m + 1;
- else {
+ } else {
lo = hi = m;
break;
}
}
// Stop if there is no matching byte.
- if (hi < lo || byts[lo] != c)
+ if (hi < lo || byts[lo] != c) {
break;
+ }
// Continue at the child (if there is one).
arridx = idxs[lo];
@@ -687,10 +690,12 @@ static void find_word(matchinf_T *mip, int mode)
// checked word.
if (c == ' ') {
for (;; ) {
- if (flen <= 0 && *mip->mi_fend != NUL)
+ if (flen <= 0 && *mip->mi_fend != NUL) {
flen = fold_more(mip);
- if (ptr[wlen] != ' ' && ptr[wlen] != TAB)
+ }
+ if (ptr[wlen] != ' ' && ptr[wlen] != TAB) {
break;
+ }
++wlen;
--flen;
}
@@ -711,11 +716,13 @@ static void find_word(matchinf_T *mip, int mode)
continue; // not at first byte of character
}
if (spell_iswordp(ptr + wlen, mip->mi_win)) {
- if (slang->sl_compprog == NULL && !slang->sl_nobreak)
+ if (slang->sl_compprog == NULL && !slang->sl_nobreak) {
continue; // next char is a word character
+ }
word_ends = false;
- } else
+ } else {
word_ends = true;
+ }
// The prefix flag is before compound flags. Once a valid prefix flag
// has been found we try compound flags.
bool prefix_found = false;
@@ -754,23 +761,26 @@ static void find_word(matchinf_T *mip, int mode)
}
if (mip->mi_capflags == WF_KEEPCAP
- || !spell_valid_case(mip->mi_capflags, flags))
+ || !spell_valid_case(mip->mi_capflags, flags)) {
continue;
+ }
}
// When mode is FIND_PREFIX the word must support the prefix:
// check the prefix ID and the condition. Do that for the list at
// mip->mi_prefarridx that find_prefix() filled.
else if (mode == FIND_PREFIX && !prefix_found) {
c = valid_word_prefix(mip->mi_prefcnt, mip->mi_prefarridx,
- flags,
- mip->mi_word + mip->mi_cprefixlen, slang,
- false);
- if (c == 0)
+ flags,
+ mip->mi_word + mip->mi_cprefixlen, slang,
+ false);
+ if (c == 0) {
continue;
+ }
// Use the WF_RARE flag for a rare prefix.
- if (c & WF_RAREPFX)
+ if (c & WF_RAREPFX) {
flags |= WF_RARE;
+ }
prefix_found = true;
}
@@ -790,8 +800,9 @@ static void find_word(matchinf_T *mip, int mode)
// that's too short... Myspell compatibility requires this
// anyway.
if (((unsigned)flags >> 24) == 0
- || wlen - mip->mi_compoff < slang->sl_compminlen)
+ || wlen - mip->mi_compoff < slang->sl_compminlen) {
continue;
+ }
// For multi-byte chars check character length against
// COMPOUNDMIN.
if (slang->sl_compminlen > 0
@@ -804,27 +815,32 @@ static void find_word(matchinf_T *mip, int mode)
// maximum for syllables is specified.
if (!word_ends && mip->mi_complen + mip->mi_compextra + 2
> slang->sl_compmax
- && slang->sl_compsylmax == MAXWLEN)
+ && slang->sl_compsylmax == MAXWLEN) {
continue;
+ }
// Don't allow compounding on a side where an affix was added,
// unless COMPOUNDPERMITFLAG was used.
- if (mip->mi_complen > 0 && (flags & WF_NOCOMPBEF))
+ if (mip->mi_complen > 0 && (flags & WF_NOCOMPBEF)) {
continue;
- if (!word_ends && (flags & WF_NOCOMPAFT))
+ }
+ if (!word_ends && (flags & WF_NOCOMPAFT)) {
continue;
+ }
// Quickly check if compounding is possible with this flag.
if (!byte_in_str(mip->mi_complen == 0
? slang->sl_compstartflags
: slang->sl_compallflags,
- ((unsigned)flags >> 24)))
+ ((unsigned)flags >> 24))) {
continue;
+ }
// If there is a match with a CHECKCOMPOUNDPATTERN rule
// discard the compound word.
- if (match_checkcompoundpattern(ptr, wlen, &slang->sl_comppat))
+ if (match_checkcompoundpattern(ptr, wlen, &slang->sl_comppat)) {
continue;
+ }
if (mode == FIND_COMPOUND) {
int capflags;
@@ -842,8 +858,9 @@ static void find_word(matchinf_T *mip, int mode)
}
capflags = captype(p, mip->mi_word + wlen);
if (capflags == WF_KEEPCAP || (capflags == WF_ALLCAP
- && (flags & WF_FIXCAP) != 0))
+ && (flags & WF_FIXCAP) != 0)) {
continue;
+ }
if (capflags != WF_ALLCAP) {
// When the character before the word is a word
@@ -876,23 +893,26 @@ static void find_word(matchinf_T *mip, int mode)
STRLCPY(fword, ptr, endlen[endidxcnt] + 1);
}
}
- if (!can_compound(slang, fword, mip->mi_compflags))
+ if (!can_compound(slang, fword, mip->mi_compflags)) {
continue;
+ }
} else if (slang->sl_comprules != NULL
- && !match_compoundrule(slang, mip->mi_compflags))
+ && !match_compoundrule(slang, mip->mi_compflags)) {
// The compound flags collected so far do not match any
// COMPOUNDRULE, discard the compounded word.
continue;
+ }
}
// Check NEEDCOMPOUND: can't use word without compounding.
- else if (flags & WF_NEEDCOMP)
+ else if (flags & WF_NEEDCOMP) {
continue;
+ }
int nobreak_result = SP_OK;
if (!word_ends) {
int save_result = mip->mi_result;
- char_u *save_end = mip->mi_end;
+ char_u *save_end = mip->mi_end;
langp_T *save_lp = mip->mi_lp;
// Check that a valid word follows. If there is one and we
@@ -900,8 +920,9 @@ static void find_word(matchinf_T *mip, int mode)
// always finished here. For NOBREAK we only check that a
// valid word follows.
// Recursive!
- if (slang->sl_nobreak)
+ if (slang->sl_nobreak) {
mip->mi_result = SP_BAD;
+ }
// Find following word in case-folded tree.
mip->mi_compoff = endlen[endidxcnt];
@@ -922,8 +943,9 @@ static void find_word(matchinf_T *mip, int mode)
c = mip->mi_compoff;
#endif
++mip->mi_complen;
- if (flags & WF_COMPROOT)
+ if (flags & WF_COMPROOT) {
++mip->mi_compextra;
+ }
// For NOBREAK we need to try all NOBREAK languages, at least
// to find the ".add" file(s).
@@ -931,8 +953,9 @@ static void find_word(matchinf_T *mip, int mode)
if (slang->sl_nobreak) {
mip->mi_lp = LANGP_ENTRY(mip->mi_win->w_s->b_langp, lpi);
if (mip->mi_lp->lp_slang->sl_fidxs == NULL
- || !mip->mi_lp->lp_slang->sl_nobreak)
+ || !mip->mi_lp->lp_slang->sl_nobreak) {
continue;
+ }
}
find_word(mip, FIND_COMPOUND);
@@ -956,12 +979,14 @@ static void find_word(matchinf_T *mip, int mode)
#endif
}
- if (!slang->sl_nobreak)
+ if (!slang->sl_nobreak) {
break;
+ }
}
--mip->mi_complen;
- if (flags & WF_COMPROOT)
+ if (flags & WF_COMPROOT) {
--mip->mi_compextra;
+ }
mip->mi_lp = save_lp;
if (slang->sl_nobreak) {
@@ -969,25 +994,28 @@ static void find_word(matchinf_T *mip, int mode)
mip->mi_result = save_result;
mip->mi_end = save_end;
} else {
- if (mip->mi_result == SP_OK)
+ if (mip->mi_result == SP_OK) {
break;
+ }
continue;
}
}
int res = SP_BAD;
- if (flags & WF_BANNED)
+ if (flags & WF_BANNED) {
res = SP_BANNED;
- else if (flags & WF_REGION) {
+ } else if (flags & WF_REGION) {
// Check region.
- if ((mip->mi_lp->lp_region & (flags >> 16)) != 0)
+ if ((mip->mi_lp->lp_region & (flags >> 16)) != 0) {
res = SP_OK;
- else
+ } else {
res = SP_LOCAL;
- } else if (flags & WF_RARE)
+ }
+ } else if (flags & WF_RARE) {
res = SP_RARE;
- else
+ } else {
res = SP_OK;
+ }
// Always use the longest match and the best result. For NOBREAK
// we separately keep the longest match without a following good
@@ -997,36 +1025,37 @@ static void find_word(matchinf_T *mip, int mode)
mip->mi_result2 = res;
mip->mi_end2 = mip->mi_word + wlen;
} else if (mip->mi_result2 == res
- && mip->mi_end2 < mip->mi_word + wlen)
+ && mip->mi_end2 < mip->mi_word + wlen) {
mip->mi_end2 = mip->mi_word + wlen;
+ }
} else if (mip->mi_result > res) {
mip->mi_result = res;
mip->mi_end = mip->mi_word + wlen;
- } else if (mip->mi_result == res && mip->mi_end < mip->mi_word + wlen)
+ } else if (mip->mi_result == res && mip->mi_end < mip->mi_word + wlen) {
mip->mi_end = mip->mi_word + wlen;
+ }
- if (mip->mi_result == SP_OK)
+ if (mip->mi_result == SP_OK) {
break;
+ }
}
- if (mip->mi_result == SP_OK)
+ if (mip->mi_result == SP_OK) {
break;
+ }
}
}
-// Returns true if there is a match between the word ptr[wlen] and
-// CHECKCOMPOUNDPATTERN rules, assuming that we will concatenate with another
-// word.
-// A match means that the first part of CHECKCOMPOUNDPATTERN matches at the
-// end of ptr[wlen] and the second part matches after it.
-static bool
-match_checkcompoundpattern (
- char_u *ptr,
- int wlen,
- garray_T *gap // &sl_comppat
-)
+/// Returns true if there is a match between the word ptr[wlen] and
+/// CHECKCOMPOUNDPATTERN rules, assuming that we will concatenate with another
+/// word.
+/// A match means that the first part of CHECKCOMPOUNDPATTERN matches at the
+/// end of ptr[wlen] and the second part matches after it.
+///
+/// @param gap &sl_comppat
+static bool match_checkcompoundpattern(char_u *ptr, int wlen, garray_T *gap)
{
- char_u *p;
+ char_u *p;
int len;
for (int i = 0; i + 1 < gap->ga_len; i += 2) {
@@ -1036,8 +1065,9 @@ match_checkcompoundpattern (
// check if first part matches at end of previous word.
p = ((char_u **)gap->ga_data)[i];
len = (int)STRLEN(p);
- if (len <= wlen && STRNCMP(ptr + wlen - len, p, len) == 0)
+ if (len <= wlen && STRNCMP(ptr + wlen - len, p, len) == 0) {
return true;
+ }
}
}
return false;
@@ -1045,8 +1075,7 @@ match_checkcompoundpattern (
// Returns true if "flags" is a valid sequence of compound flags and "word"
// does not have too many syllables.
-static bool can_compound(slang_T *slang, const char_u *word,
- const char_u *flags)
+static bool can_compound(slang_T *slang, const char_u *word, const char_u *flags)
FUNC_ATTR_NONNULL_ALL
{
char_u uflags[MAXWLEN * 2] = { 0 };
@@ -1069,8 +1098,9 @@ static bool can_compound(slang_T *slang, const char_u *word,
// are too many syllables AND the number of compound words is above
// COMPOUNDWORDMAX then compounding is not allowed.
if (slang->sl_compsylmax < MAXWLEN
- && count_syllables(slang, word) > slang->sl_compsylmax)
+ && count_syllables(slang, word) > slang->sl_compsylmax) {
return (int)STRLEN(flags) < slang->sl_compmax;
+ }
return true;
}
@@ -1082,8 +1112,9 @@ static bool can_be_compound(trystate_T *sp, slang_T *slang, char_u *compflags, i
// If the flag doesn't appear in sl_compstartflags or sl_compallflags
// then it can't possibly compound.
if (!byte_in_str(sp->ts_complen == sp->ts_compsplit
- ? slang->sl_compstartflags : slang->sl_compallflags, flag))
+ ? slang->sl_compstartflags : slang->sl_compallflags, flag)) {
return false;
+ }
// If there are no wildcards, we can check if the flags collected so far
// possibly can form a match with COMPOUNDRULE patterns. This only
@@ -1105,7 +1136,7 @@ static bool can_be_compound(trystate_T *sp, slang_T *slang, char_u *compflags, i
// Caller must check that slang->sl_comprules is not NULL.
static bool match_compoundrule(slang_T *slang, char_u *compflags)
{
- char_u *p;
+ char_u *p;
int i;
int c;
@@ -1115,30 +1146,37 @@ static bool match_compoundrule(slang_T *slang, char_u *compflags)
// them against the current rule entry
for (i = 0;; ++i) {
c = compflags[i];
- if (c == NUL)
+ if (c == NUL) {
// found a rule that matches for the flags we have so far
return true;
- if (*p == '/' || *p == NUL)
+ }
+ if (*p == '/' || *p == NUL) {
break; // end of rule, it's too short
+ }
if (*p == '[') {
bool match = false;
// compare against all the flags in []
++p;
- while (*p != ']' && *p != NUL)
- if (*p++ == c)
+ while (*p != ']' && *p != NUL) {
+ if (*p++ == c) {
match = true;
- if (!match)
+ }
+ }
+ if (!match) {
break; // none matches
- } else if (*p != c)
+ }
+ } else if (*p != c) {
break; // flag of word doesn't match flag in pattern
+ }
++p;
}
// Skip to the next "/", where the next pattern starts.
p = vim_strchr(p, '/');
- if (p == NULL)
+ if (p == NULL) {
break;
+ }
}
// Checked all the rules and none of them match the flags, so there
@@ -1146,18 +1184,15 @@ static bool match_compoundrule(slang_T *slang, char_u *compflags)
return false;
}
-// Return non-zero if the prefix indicated by "arridx" matches with the prefix
-// ID in "flags" for the word "word".
-// The WF_RAREPFX flag is included in the return value for a rare prefix.
-static int
-valid_word_prefix (
- int totprefcnt, // nr of prefix IDs
- int arridx, // idx in sl_pidxs[]
- int flags,
- char_u *word,
- slang_T *slang,
- bool cond_req // only use prefixes with a condition
-)
+/// Return non-zero if the prefix indicated by "arridx" matches with the prefix
+/// ID in "flags" for the word "word".
+/// The WF_RAREPFX flag is included in the return value for a rare prefix.
+///
+/// @param totprefcnt nr of prefix IDs
+/// @param arridx idx in sl_pidxs[]
+/// @param cond_req only use prefixes with a condition
+static int valid_word_prefix(int totprefcnt, int arridx, int flags, char_u *word, slang_T *slang,
+ bool cond_req)
{
int prefcnt;
int pidx;
@@ -1168,13 +1203,15 @@ valid_word_prefix (
pidx = slang->sl_pidxs[arridx + prefcnt];
// Check the prefix ID.
- if (prefid != (pidx & 0xff))
+ if (prefid != (pidx & 0xff)) {
continue;
+ }
// Check if the prefix doesn't combine and the word already has a
// suffix.
- if ((flags & WF_HAS_AFF) && (pidx & WF_PFX_NC))
+ if ((flags & WF_HAS_AFF) && (pidx & WF_PFX_NC)) {
continue;
+ }
// Check the condition, if there is one. The condition index is
// stored in the two bytes above the prefix ID byte.
@@ -1183,8 +1220,9 @@ valid_word_prefix (
if (!vim_regexec_prog(rp, false, word, 0)) {
continue;
}
- } else if (cond_req)
+ } else if (cond_req) {
continue;
+ }
// It's a match! Return the WF_ flags.
return pidx;
@@ -1206,16 +1244,16 @@ static void find_prefix(matchinf_T *mip, int mode)
int wlen = 0;
int flen;
int c;
- char_u *ptr;
+ char_u *ptr;
idx_T lo, hi, m;
- slang_T *slang = mip->mi_lp->lp_slang;
- char_u *byts;
- idx_T *idxs;
+ slang_T *slang = mip->mi_lp->lp_slang;
+ char_u *byts;
+ idx_T *idxs;
byts = slang->sl_pbyts;
- if (byts == NULL)
+ if (byts == NULL) {
return; // array is empty
-
+ }
// We use the case-folded word here, since prefixes are always
// case-folded.
ptr = mip->mi_fword;
@@ -1232,8 +1270,9 @@ static void find_prefix(matchinf_T *mip, int mode)
// - we reach the end of the tree,
// - or we reach the end of the line.
for (;; ) {
- if (flen == 0 && *mip->mi_fend != NUL)
+ if (flen == 0 && *mip->mi_fend != NUL) {
flen = fold_more(mip);
+ }
len = byts[arridx++];
@@ -1254,9 +1293,10 @@ static void find_prefix(matchinf_T *mip, int mode)
// Find the word that comes after the prefix.
mip->mi_prefixlen = wlen;
- if (mode == FIND_COMPOUND)
+ if (mode == FIND_COMPOUND) {
// Skip over the previously found word(s).
mip->mi_prefixlen += mip->mi_compoff;
+ }
// Case-folded length may differ from original length.
mip->mi_cprefixlen = nofold_len(mip->mi_fword, mip->mi_prefixlen,
@@ -1264,13 +1304,15 @@ static void find_prefix(matchinf_T *mip, int mode)
find_word(mip, FIND_PREFIX);
- if (len == 0)
+ if (len == 0) {
break; // no children, word must end here
+ }
}
// Stop looking at end of the line.
- if (ptr[wlen] == NUL)
+ if (ptr[wlen] == NUL) {
break;
+ }
// Perform a binary search in the list of accepted bytes.
c = ptr[wlen];
@@ -1278,19 +1320,20 @@ static void find_prefix(matchinf_T *mip, int mode)
hi = arridx + len - 1;
while (lo < hi) {
m = (lo + hi) / 2;
- if (byts[m] > c)
+ if (byts[m] > c) {
hi = m - 1;
- else if (byts[m] < c)
+ } else if (byts[m] < c) {
lo = m + 1;
- else {
+ } else {
lo = hi = m;
break;
}
}
// Stop if there is no matching byte.
- if (hi < lo || byts[lo] != c)
+ if (hi < lo || byts[lo] != c) {
break;
+ }
// Continue at the child (if there is one).
arridx = idxs[lo];
@@ -1305,7 +1348,7 @@ static void find_prefix(matchinf_T *mip, int mode)
static int fold_more(matchinf_T *mip)
{
int flen;
- char_u *p;
+ char_u *p;
p = mip->mi_fend;
do {
@@ -1349,42 +1392,40 @@ static bool no_spell_checking(win_T *wp)
return false;
}
-// Moves to the next spell error.
-// "curline" is false for "[s", "]s", "[S" and "]S".
-// "curline" is true to find word under/after cursor in the same line.
-// For Insert mode completion "dir" is BACKWARD and "curline" is true: move
-// to after badly spelled word before the cursor.
-// Return 0 if not found, length of the badly spelled word otherwise.
-size_t
-spell_move_to (
- win_T *wp,
- int dir, // FORWARD or BACKWARD
- bool allwords, // true for "[s"/"]s", false for "[S"/"]S"
- bool curline,
- hlf_T *attrp // return: attributes of bad word or NULL
- // (only when "dir" is FORWARD)
-)
+/// Moves to the next spell error.
+/// "curline" is false for "[s", "]s", "[S" and "]S".
+/// "curline" is true to find word under/after cursor in the same line.
+/// For Insert mode completion "dir" is BACKWARD and "curline" is true: move
+/// to after badly spelled word before the cursor.
+///
+/// @param dir FORWARD or BACKWARD
+/// @param allwords true for "[s"/"]s", false for "[S"/"]S"
+/// @param attrp return: attributes of bad word or NULL (only when "dir" is FORWARD)
+///
+/// @return 0 if not found, length of the badly spelled word otherwise.
+size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *attrp)
{
linenr_T lnum;
pos_T found_pos;
size_t found_len = 0;
- char_u *line;
- char_u *p;
- char_u *endp;
+ char_u *line;
+ char_u *p;
+ char_u *endp;
hlf_T attr = HLF_COUNT;
size_t len;
int has_syntax = syntax_present(wp);
int col;
bool can_spell;
- char_u *buf = NULL;
+ char_u *buf = NULL;
size_t buflen = 0;
int skip = 0;
int capcol = -1;
bool found_one = false;
bool wrapped = false;
- if (no_spell_checking(wp))
+ if (no_spell_checking(wp)) {
return 0;
+ }
// Start looking for bad word at the start of the line, because we can't
// start halfway through a word, we don't know where it starts or ends.
@@ -1399,7 +1440,7 @@ spell_move_to (
clearpos(&found_pos);
while (!got_int) {
- line = ml_get_buf(wp->w_buffer, lnum, FALSE);
+ line = ml_get_buf(wp->w_buffer, lnum, false);
len = STRLEN(line);
if (buflen < len + MAXWLEN + 2) {
@@ -1410,8 +1451,9 @@ spell_move_to (
assert(buf && buflen >= len + MAXWLEN + 2);
// In first line check first word for Capital.
- if (lnum == 1)
+ if (lnum == 1) {
capcol = 0;
+ }
// For checking first word with a capital skip white space.
if (capcol == 0) {
@@ -1425,16 +1467,17 @@ spell_move_to (
// Need to get the line again, may have looked at the previous
// one.
- line = ml_get_buf(wp->w_buffer, lnum, FALSE);
+ line = ml_get_buf(wp->w_buffer, lnum, false);
}
// Copy the line into "buf" and append the start of the next line if
// possible.
STRCPY(buf, line);
- if (lnum < wp->w_buffer->b_ml.ml_line_count)
+ if (lnum < wp->w_buffer->b_ml.ml_line_count) {
spell_cat_line(buf + STRLEN(buf),
- ml_get_buf(wp->w_buffer, lnum + 1, FALSE),
+ ml_get_buf(wp->w_buffer, lnum + 1, false),
MAXWLEN);
+ }
p = buf + skip;
endp = buf + len;
while (p < endp) {
@@ -1443,8 +1486,9 @@ spell_move_to (
if (dir == BACKWARD
&& lnum == wp->w_cursor.lnum
&& !wrapped
- && (colnr_T)(p - buf) >= wp->w_cursor.col)
+ && (colnr_T)(p - buf) >= wp->w_cursor.col) {
break;
+ }
// start of word
attr = HLF_COUNT;
@@ -1464,11 +1508,13 @@ spell_move_to (
if (has_syntax) {
col = (int)(p - buf);
(void)syn_get_id(wp, lnum, (colnr_T)col,
- FALSE, &can_spell, FALSE);
- if (!can_spell)
+ FALSE, &can_spell, FALSE);
+ if (!can_spell) {
attr = HLF_COUNT;
- } else
+ }
+ } else {
can_spell = true;
+ }
if (can_spell) {
found_one = true;
@@ -1479,8 +1525,9 @@ spell_move_to (
// No need to search further.
wp->w_cursor = found_pos;
xfree(buf);
- if (attrp != NULL)
+ if (attrp != NULL) {
*attrp = attr;
+ }
return len;
} else if (curline) {
// Insert mode completion: put cursor after
@@ -1490,8 +1537,9 @@ spell_move_to (
}
found_len = len;
}
- } else
+ } else {
found_one = true;
+ }
}
}
@@ -1529,22 +1577,24 @@ spell_move_to (
// starting line again and accept the last match.
lnum = wp->w_buffer->b_ml.ml_line_count;
wrapped = true;
- if (!shortmess(SHM_SEARCH))
+ if (!shortmess(SHM_SEARCH)) {
give_warning((char_u *)_(top_bot_msg), true);
+ }
}
capcol = -1;
} else {
- if (lnum < wp->w_buffer->b_ml.ml_line_count)
+ if (lnum < wp->w_buffer->b_ml.ml_line_count) {
++lnum;
- else if (!p_ws)
+ } else if (!p_ws) {
break; // at first line and 'nowrapscan'
- else {
+ } else {
// Wrap around to the start of the buffer. May search the
// starting line again and accept the first match.
lnum = 1;
wrapped = true;
- if (!shortmess(SHM_SEARCH))
+ if (!shortmess(SHM_SEARCH)) {
give_warning((char_u *)_(bot_top_msg), true);
+ }
}
// If we are back at the starting line and there is no match then
@@ -1555,17 +1605,19 @@ spell_move_to (
// Skip the characters at the start of the next line that were
// included in a match crossing line boundaries.
- if (attr == HLF_COUNT)
+ if (attr == HLF_COUNT) {
skip = (int)(p - endp);
- else
+ } else {
skip = 0;
+ }
// Capcol skips over the inserted space.
--capcol;
// But after empty line check first word in next line
- if (*skipwhite(line) == NUL)
+ if (*skipwhite(line) == NUL) {
capcol = 0;
+ }
}
line_breakcheck();
@@ -1581,12 +1633,13 @@ spell_move_to (
// to skip those bytes if the word was OK.
void spell_cat_line(char_u *buf, char_u *line, int maxlen)
{
- char_u *p;
+ char_u *p;
int n;
p = skipwhite(line);
- while (vim_strchr((char_u *)"*#/\"\t", *p) != NULL)
+ while (vim_strchr((char_u *)"*#/\"\t", *p) != NULL) {
p = skipwhite(p + 1);
+ }
if (*p != NUL) {
// Only worth concatenating if there is something else than spaces to
@@ -1630,8 +1683,9 @@ static void spell_load_lang(char_u *lang)
if (r == FAIL && *sl.sl_lang != NUL && round == 1
&& apply_autocmds(EVENT_SPELLFILEMISSING, lang,
- curbuf->b_fname, FALSE, curbuf))
+ curbuf->b_fname, FALSE, curbuf)) {
continue;
+ }
break;
}
break;
@@ -1647,9 +1701,8 @@ static void spell_load_lang(char_u *lang)
lang);
do_cmdline_cmd(autocmd_buf);
} else {
- smsg(
- _("Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""),
- lang, spell_enc(), lang);
+ smsg(_("Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\""),
+ lang, spell_enc(), lang);
}
} else if (sl.sl_slang != NULL) {
// At least one file was loaded, now load ALL the additions.
@@ -1662,9 +1715,9 @@ static void spell_load_lang(char_u *lang)
// use "latin1" for "latin9". And limit to 60 characters (just in case).
char_u *spell_enc(void)
{
-
- if (STRLEN(p_enc) < 60 && STRCMP(p_enc, "iso-8859-15") != 0)
+ if (STRLEN(p_enc) < 60 && STRCMP(p_enc, "iso-8859-15") != 0) {
return p_enc;
+ }
return (char_u *)"latin1";
}
@@ -1673,7 +1726,7 @@ char_u *spell_enc(void)
static void int_wordlist_spl(char_u *fname)
{
vim_snprintf((char *)fname, MAXPATHL, SPL_FNAME_TMPL,
- int_wordlist, spell_enc());
+ int_wordlist, spell_enc());
}
// Allocate a new slang_T for language "lang". "lang" can be NULL.
@@ -1683,8 +1736,9 @@ slang_T *slang_alloc(char_u *lang)
{
slang_T *lp = xcalloc(1, sizeof(slang_T));
- if (lang != NULL)
+ if (lang != NULL) {
lp->sl_name = vim_strsave(lang);
+ }
ga_init(&lp->sl_rep, sizeof(fromto_T), 10);
ga_init(&lp->sl_repsal, sizeof(fromto_T), 10);
lp->sl_compmax = MAXWLEN;
@@ -1722,7 +1776,7 @@ static void free_fromto(fromto_T *ftp) {
// Clear an slang_T so that the file can be reloaded.
void slang_clear(slang_T *lp)
{
- garray_T *gap;
+ garray_T *gap;
XFREE_CLEAR(lp->sl_fbyts);
XFREE_CLEAR(lp->sl_kbyts);
@@ -1792,17 +1846,18 @@ void slang_clear_sug(slang_T *lp)
// Invoked through do_in_runtimepath().
static void spell_load_cb(char_u *fname, void *cookie)
{
- spelload_T *slp = (spelload_T *)cookie;
- slang_T *slang;
+ spelload_T *slp = (spelload_T *)cookie;
+ slang_T *slang;
slang = spell_load_file(fname, slp->sl_lang, NULL, false);
if (slang != NULL) {
// When a previously loaded file has NOBREAK also use it for the
// ".add" files.
- if (slp->sl_nobreak && slang->sl_add)
+ if (slp->sl_nobreak && slang->sl_add) {
slang->sl_nobreak = true;
- else if (slang->sl_nobreak)
+ } else if (slang->sl_nobreak) {
slp->sl_nobreak = true;
+ }
slp->sl_slang = slang;
}
@@ -1818,10 +1873,10 @@ static void spell_load_cb(char_u *fname, void *cookie)
void count_common_word(slang_T *lp, char_u *word, int len, int count)
{
hash_T hash;
- hashitem_T *hi;
+ hashitem_T *hi;
wordcount_T *wc;
char_u buf[MAXWLEN];
- char_u *p;
+ char_u *p;
if (len == -1) {
p = word;
@@ -1842,21 +1897,18 @@ void count_common_word(slang_T *lp, char_u *word, int len, int count)
hash_add_item(&lp->sl_wordcount, hi, wc->wc_word, hash);
} else {
wc = HI2WC(hi);
- if ((wc->wc_count += count) < (unsigned)count) // check for overflow
+ if ((wc->wc_count += count) < (unsigned)count) { // check for overflow
wc->wc_count = MAXWORDCOUNT;
+ }
}
}
-// Adjust the score of common words.
-static int
-score_wordcount_adj (
- slang_T *slang,
- int score,
- char_u *word,
- bool split // word was split, less bonus
-)
+/// Adjust the score of common words.
+///
+/// @param split word was split, less bonus
+static int score_wordcount_adj(slang_T *slang, int score, char_u *word, bool split)
{
- hashitem_T *hi;
+ hashitem_T *hi;
wordcount_T *wc;
int bonus;
int newscore;
@@ -1864,18 +1916,21 @@ score_wordcount_adj (
hi = hash_find(&slang->sl_wordcount, word);
if (!HASHITEM_EMPTY(hi)) {
wc = HI2WC(hi);
- if (wc->wc_count < SCORE_THRES2)
+ if (wc->wc_count < SCORE_THRES2) {
bonus = SCORE_COMMON1;
- else if (wc->wc_count < SCORE_THRES3)
+ } else if (wc->wc_count < SCORE_THRES3) {
bonus = SCORE_COMMON2;
- else
+ } else {
bonus = SCORE_COMMON3;
- if (split)
+ }
+ if (split) {
newscore = score - bonus / 2;
- else
+ } else {
newscore = score - bonus;
- if (newscore < 0)
+ }
+ if (newscore < 0) {
return 0;
+ }
return newscore;
}
return score;
@@ -1885,11 +1940,13 @@ score_wordcount_adj (
// Like strchr() but independent of locale.
bool byte_in_str(char_u *str, int n)
{
- char_u *p;
+ char_u *p;
- for (p = str; *p != NUL; ++p)
- if (*p == n)
+ for (p = str; *p != NUL; ++p) {
+ if (*p == n) {
return true;
+ }
+ }
return false;
}
@@ -1897,24 +1954,27 @@ bool byte_in_str(char_u *str, int n)
// in "slang->sl_syl_items".
int init_syl_tab(slang_T *slang)
{
- char_u *p;
- char_u *s;
+ char_u *p;
+ char_u *s;
int l;
ga_init(&slang->sl_syl_items, sizeof(syl_item_T), 4);
p = vim_strchr(slang->sl_syllable, '/');
while (p != NULL) {
*p++ = NUL;
- if (*p == NUL) // trailing slash
+ if (*p == NUL) { // trailing slash
break;
+ }
s = p;
p = vim_strchr(p, '/');
- if (p == NULL)
+ if (p == NULL) {
l = (int)STRLEN(s);
- else
+ } else {
l = (int)(p - s);
- if (l >= SY_MAXLEN)
+ }
+ if (l >= SY_MAXLEN) {
return SP_FORMERROR;
+ }
syl_item_T *syl = GA_APPEND_VIA_PTR(syl_item_T, &slang->sl_syl_items);
STRLCPY(syl->sy_chars, s, l + 1);
@@ -1932,11 +1992,12 @@ static int count_syllables(slang_T *slang, const char_u *word)
int cnt = 0;
bool skip = false;
int len;
- syl_item_T *syl;
+ syl_item_T *syl;
int c;
- if (slang->sl_syllable == NULL)
+ if (slang->sl_syllable == NULL) {
return 0;
+ }
for (const char_u *p = word; *p != NUL; p += len) {
// When running into a space reset counter.
@@ -1951,8 +2012,9 @@ static int count_syllables(slang_T *slang, const char_u *word)
for (int i = 0; i < slang->sl_syl_items.ga_len; ++i) {
syl = ((syl_item_T *)slang->sl_syl_items.ga_data) + i;
if (syl->sy_len > len
- && STRNCMP(p, syl->sy_chars, syl->sy_len) == 0)
+ && STRNCMP(p, syl->sy_chars, syl->sy_len) == 0) {
len = syl->sy_len;
+ }
}
if (len != 0) { // found a match, count syllable
++cnt;
@@ -1961,9 +2023,9 @@ static int count_syllables(slang_T *slang, const char_u *word)
// No recognized syllable item, at least a syllable char then?
c = utf_ptr2char(p);
len = (*mb_ptr2len)(p);
- if (vim_strchr(slang->sl_syllable, c) == NULL)
+ if (vim_strchr(slang->sl_syllable, c) == NULL) {
skip = false; // No, search for next syllable
- else if (!skip) {
+ } else if (!skip) {
++cnt; // Yes, count it
skip = true; // don't count following syllable chars
}
@@ -1977,26 +2039,26 @@ static int count_syllables(slang_T *slang, const char_u *word)
char_u *did_set_spelllang(win_T *wp)
{
garray_T ga;
- char_u *splp;
- char_u *region;
+ char_u *splp;
+ char_u *region;
char_u region_cp[3];
bool filename;
int region_mask;
- slang_T *slang;
+ slang_T *slang;
int c;
char_u lang[MAXWLEN + 1];
char_u spf_name[MAXPATHL];
int len;
- char_u *p;
+ char_u *p;
int round;
- char_u *spf;
- char_u *use_region = NULL;
+ char_u *spf;
+ char_u *use_region = NULL;
bool dont_use_region = false;
bool nobreak = false;
- langp_T *lp, *lp2;
+ langp_T *lp, *lp2;
static bool recursive = false;
- char_u *ret_msg = NULL;
- char_u *spl_copy;
+ char_u *ret_msg = NULL;
+ char_u *spl_copy;
bufref_T bufref;
set_bufref(&bufref, wp->w_buffer);
@@ -2004,8 +2066,9 @@ char_u *did_set_spelllang(win_T *wp)
// We don't want to do this recursively. May happen when a language is
// not available and the SpellFileMissing autocommand opens a new buffer
// in which 'spell' is set.
- if (recursive)
+ if (recursive) {
return NULL;
+ }
recursive = true;
ga_init(&ga, sizeof(langp_T), 2);
@@ -2046,8 +2109,9 @@ char_u *did_set_spelllang(win_T *wp)
STRLCPY(region_cp, p + 1, 3);
memmove(p, p + 3, len - (p - lang) - 2);
region = region_cp;
- } else
+ } else {
dont_use_region = true;
+ }
// Check if we loaded this language before.
for (slang = first_lang; slang != NULL; slang = slang->sl_next) {
@@ -2061,28 +2125,32 @@ char_u *did_set_spelllang(win_T *wp)
if (len > 3 && lang[len - 3] == '_') {
region = lang + len - 2;
lang[len - 3] = NUL;
- } else
+ } else {
dont_use_region = true;
+ }
// Check if we loaded this language before.
- for (slang = first_lang; slang != NULL; slang = slang->sl_next)
- if (STRICMP(lang, slang->sl_name) == 0)
+ for (slang = first_lang; slang != NULL; slang = slang->sl_next) {
+ if (STRICMP(lang, slang->sl_name) == 0) {
break;
+ }
+ }
}
if (region != NULL) {
// If the region differs from what was used before then don't
// use it for 'spellfile'.
- if (use_region != NULL && STRCMP(region, use_region) != 0)
+ if (use_region != NULL && STRCMP(region, use_region) != 0) {
dont_use_region = true;
+ }
use_region = region;
}
// If not found try loading the language now.
if (slang == NULL) {
- if (filename)
+ if (filename) {
(void)spell_load_file(lang, lang, NULL, false);
- else {
+ } else {
spell_load_lang(lang);
// SpellFileMissing autocommands may do anything, including
// destroying the buffer we are using...
@@ -2105,16 +2173,19 @@ char_u *did_set_spelllang(win_T *wp)
c = find_region(slang->sl_regions, region);
if (c == REGION_ALL) {
if (slang->sl_add) {
- if (*slang->sl_regions != NUL)
+ if (*slang->sl_regions != NUL) {
// This addition file is for other regions.
region_mask = 0;
- } else
+ }
+ } else {
// This is probably an error. Give a warning and
// accept the words anyway.
smsg(_("Warning: region %s not supported"),
region);
- } else
+ }
+ } else {
region_mask = 1 << c;
+ }
}
if (region_mask != 0) {
@@ -2123,8 +2194,9 @@ char_u *did_set_spelllang(win_T *wp)
p_->lp_region = region_mask;
use_midword(slang, wp);
- if (slang->sl_nobreak)
+ if (slang->sl_nobreak) {
nobreak = true;
+ }
}
}
}
@@ -2138,8 +2210,9 @@ char_u *did_set_spelllang(win_T *wp)
for (round = 0; round == 0 || *spf != NUL; ++round) {
if (round == 0) {
// Internal wordlist, if there is one.
- if (int_wordlist == NULL)
+ if (int_wordlist == NULL) {
continue;
+ }
int_wordlist_spl(spf_name);
} else {
// One entry in 'spellfile'.
@@ -2154,8 +2227,9 @@ char_u *did_set_spelllang(win_T *wp)
break;
}
}
- if (c < ga.ga_len)
+ if (c < ga.ga_len) {
continue;
+ }
}
// Check if it was loaded already.
@@ -2169,31 +2243,34 @@ char_u *did_set_spelllang(win_T *wp)
// Not loaded, try loading it now. The language name includes the
// region name, the region is ignored otherwise. for int_wordlist
// use an arbitrary name.
- if (round == 0)
+ if (round == 0) {
STRCPY(lang, "internal wordlist");
- else {
+ } else {
STRLCPY(lang, path_tail(spf_name), MAXWLEN + 1);
p = vim_strchr(lang, '.');
- if (p != NULL)
+ if (p != NULL) {
*p = NUL; // truncate at ".encoding.add"
+ }
}
slang = spell_load_file(spf_name, lang, NULL, true);
// If one of the languages has NOBREAK we assume the addition
// files also have this.
- if (slang != NULL && nobreak)
+ if (slang != NULL && nobreak) {
slang->sl_nobreak = true;
+ }
}
if (slang != NULL) {
region_mask = REGION_ALL;
if (use_region != NULL && !dont_use_region) {
// find region in sl_regions
c = find_region(slang->sl_regions, use_region);
- if (c != REGION_ALL)
+ if (c != REGION_ALL) {
region_mask = 1 << c;
- else if (*slang->sl_regions != NUL)
+ } else if (*slang->sl_regions != NUL) {
// This spell file is for other regions.
region_mask = 0;
+ }
}
if (region_mask != 0) {
@@ -2219,36 +2296,38 @@ char_u *did_set_spelllang(win_T *wp)
lp = LANGP_ENTRY(ga, i);
// sound folding
- if (!GA_EMPTY(&lp->lp_slang->sl_sal))
+ if (!GA_EMPTY(&lp->lp_slang->sl_sal)) {
// language does sound folding itself
lp->lp_sallang = lp->lp_slang;
- else
+ } else {
// find first similar language that does sound folding
for (int j = 0; j < ga.ga_len; ++j) {
lp2 = LANGP_ENTRY(ga, j);
if (!GA_EMPTY(&lp2->lp_slang->sl_sal)
&& STRNCMP(lp->lp_slang->sl_name,
- lp2->lp_slang->sl_name, 2) == 0) {
+ lp2->lp_slang->sl_name, 2) == 0) {
lp->lp_sallang = lp2->lp_slang;
break;
}
}
+ }
// REP items
- if (!GA_EMPTY(&lp->lp_slang->sl_rep))
+ if (!GA_EMPTY(&lp->lp_slang->sl_rep)) {
// language has REP items itself
lp->lp_replang = lp->lp_slang;
- else
+ } else {
// find first similar language that has REP items
for (int j = 0; j < ga.ga_len; ++j) {
lp2 = LANGP_ENTRY(ga, j);
if (!GA_EMPTY(&lp2->lp_slang->sl_rep)
&& STRNCMP(lp->lp_slang->sl_name,
- lp2->lp_slang->sl_name, 2) == 0) {
+ lp2->lp_slang->sl_name, 2) == 0) {
lp->lp_replang = lp2->lp_slang;
break;
}
}
+ }
}
theend:
@@ -2302,10 +2381,12 @@ static int find_region(char_u *rp, char_u *region)
int i;
for (i = 0;; i += 2) {
- if (rp[i] == NUL)
+ if (rp[i] == NUL) {
return REGION_ALL;
- if (rp[i] == region[0] && rp[i + 1] == region[1])
+ }
+ if (rp[i] == region[0] && rp[i + 1] == region[1]) {
break;
+ }
}
return i / 2;
}
@@ -2323,7 +2404,7 @@ static int find_region(char_u *rp, char_u *region)
int captype(char_u *word, char_u *end)
FUNC_ATTR_NONNULL_ARG(1)
{
- char_u *p;
+ char_u *p;
int firstcap;
bool allcap;
bool past_second = false; // past second word char
@@ -2356,10 +2437,12 @@ int captype(char_u *word, char_u *end)
}
}
- if (allcap)
+ if (allcap) {
return WF_ALLCAP;
- if (firstcap)
+ }
+ if (firstcap) {
return WF_ONECAP;
+ }
return 0;
}
@@ -2373,7 +2456,7 @@ static int badword_captype(char_u *word, char_u *end)
int c;
int l, u;
bool first;
- char_u *p;
+ char_u *p;
if (flags & WF_KEEPCAP) {
// Count the number of UPPER and lower case letters.
@@ -2383,23 +2466,27 @@ static int badword_captype(char_u *word, char_u *end)
c = PTR2CHAR(p);
if (SPELL_ISUPPER(c)) {
++u;
- if (p == word)
+ if (p == word) {
first = true;
- } else
+ }
+ } else {
++l;
+ }
}
// If there are more UPPER than lower case letters suggest an
// ALLCAP word. Otherwise, if the first letter is UPPER then
// suggest ONECAP. Exception: "ALl" most likely should be "All",
// require three upper case letters.
- if (u > l && u > 2)
+ if (u > l && u > 2) {
flags |= WF_ALLCAP;
- else if (first)
+ } else if (first) {
flags |= WF_ONECAP;
+ }
- if (u >= 2 && l >= 2) // maCARONI maCAroni
+ if (u >= 2 && l >= 2) { // maCARONI maCAroni
flags |= WF_MIXCAP;
+ }
}
return flags;
}
@@ -2407,7 +2494,7 @@ static int badword_captype(char_u *word, char_u *end)
// Delete the internal wordlist and its .spl file.
void spell_delete_wordlist(void)
{
- char_u fname[MAXPATHL] = {0};
+ char_u fname[MAXPATHL] = { 0 };
if (int_wordlist != NULL) {
os_remove((char *)int_wordlist);
@@ -2420,7 +2507,7 @@ void spell_delete_wordlist(void)
// Free all languages.
void spell_free_all(void)
{
- slang_T *slang;
+ slang_T *slang;
// Go through all buffers and handle 'spelllang'. <VN>
FOR_ALL_BUFFERS(buf) {
@@ -2475,10 +2562,10 @@ static int bytes2offset(char_u **pp)
c = *p++;
if ((c & 0x80) == 0x00) { // 1 byte
nr = c - 1;
- } else if ((c & 0xc0) == 0x80) { // 2 bytes
+ } else if ((c & 0xc0) == 0x80) { // 2 bytes
nr = (c & 0x3f) - 1;
nr = nr * 255 + (*p++ - 1);
- } else if ((c & 0xe0) == 0xc0) { // 3 bytes
+ } else if ((c & 0xe0) == 0xc0) { // 3 bytes
nr = (c & 0x1f) - 1;
nr = nr * 255 + (*p++ - 1);
nr = nr * 255 + (*p++ - 1);
@@ -2537,8 +2624,9 @@ void clear_spell_chartab(spelltab_T *sp)
// We include digits. A word shouldn't start with a digit, but handling
// that is done separately.
- for (i = '0'; i <= '9'; ++i)
+ for (i = '0'; i <= '9'; ++i) {
sp->st_isw[i] = true;
+ }
for (i = 'A'; i <= 'Z'; ++i) {
sp->st_isw[i] = true;
sp->st_isu[i] = true;
@@ -2627,9 +2715,10 @@ bool spell_iswordp_nmw(const char_u *p, win_T *wp)
static bool spell_mb_isword_class(int cl, const win_T *wp)
FUNC_ATTR_PURE FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
- if (wp->w_s->b_cjk)
+ if (wp->w_s->b_cjk) {
// East Asian characters are not considered word characters.
return cl == 2 || cl == 0x2800;
+ }
return cl >= 2 && cl != 0x2070 && cl != 0x2080 && cl != 3;
}
@@ -2641,11 +2730,12 @@ static bool spell_iswordp_w(const int *p, const win_T *wp)
const int *s;
if (*p < 256 ? wp->w_s->b_spell_ismw[*p]
- : (wp->w_s->b_spell_ismw_mb != NULL
- && vim_strchr(wp->w_s->b_spell_ismw_mb, *p) != NULL))
+ : (wp->w_s->b_spell_ismw_mb != NULL
+ && vim_strchr(wp->w_s->b_spell_ismw_mb, *p) != NULL)) {
s = p + 1;
- else
+ } else {
s = p;
+ }
if (*s > 255) {
return spell_mb_isword_class(utf_class(*s), wp);
@@ -2657,8 +2747,7 @@ static bool spell_iswordp_w(const int *p, const win_T *wp)
// Uses the character definitions from the .spl file.
// When using a multi-byte 'encoding' the length may change!
// Returns FAIL when something wrong.
-int spell_casefold(const win_T *wp, char_u *str, int len, char_u *buf,
- int buflen)
+int spell_casefold(const win_T *wp, char_u *str, int len, char_u *buf, int buflen)
FUNC_ATTR_NONNULL_ALL
{
if (len >= buflen) {
@@ -2708,8 +2797,8 @@ static int sps_limit = 9999; // max nr of suggestions given
// Sets "sps_flags" and "sps_limit".
int spell_check_sps(void)
{
- char_u *p;
- char_u *s;
+ char_u *p;
+ char_u *s;
char_u buf[MAXPATHL];
int f;
@@ -2742,12 +2831,14 @@ int spell_check_sps(void)
sps_limit = 9999;
return FAIL;
}
- if (f != 0)
+ if (f != 0) {
sps_flags = f;
+ }
}
- if (sps_flags == 0)
+ if (sps_flags == 0) {
sps_flags = SPS_BEST;
+ }
return OK;
}
@@ -2758,13 +2849,13 @@ int spell_check_sps(void)
// When "count" is non-zero use that suggestion.
void spell_suggest(int count)
{
- char_u *line;
+ char_u *line;
pos_T prev_cursor = curwin->w_cursor;
char_u wcopy[MAXWLEN + 2];
- char_u *p;
+ char_u *p;
int c;
suginfo_T sug;
- suggest_T *stp;
+ suggest_T *stp;
int mouse_used;
int need_cap;
int limit;
@@ -2833,36 +2924,39 @@ void spell_suggest(int count)
// Get the list of suggestions. Limit to 'lines' - 2 or the number in
// 'spellsuggest', whatever is smaller.
- if (sps_limit > (int)Rows - 2)
+ if (sps_limit > (int)Rows - 2) {
limit = (int)Rows - 2;
- else
+ } else {
limit = sps_limit;
+ }
spell_find_suggest(line + curwin->w_cursor.col, badlen, &sug, limit,
- true, need_cap, true);
+ true, need_cap, true);
- if (GA_EMPTY(&sug.su_ga))
+ if (GA_EMPTY(&sug.su_ga)) {
MSG(_("Sorry, no suggestions"));
- else if (count > 0) {
- if (count > sug.su_ga.ga_len)
+ } else if (count > 0) {
+ if (count > sug.su_ga.ga_len) {
smsg(_("Sorry, only %" PRId64 " suggestions"),
(int64_t)sug.su_ga.ga_len);
+ }
} else {
// When 'rightleft' is set the list is drawn right-left.
cmdmsg_rl = curwin->w_p_rl;
- if (cmdmsg_rl)
+ if (cmdmsg_rl) {
msg_col = Columns - 1;
+ }
// List the suggestions.
msg_start();
msg_row = Rows - 1; // for when 'cmdheight' > 1
lines_left = Rows; // avoid more prompt
vim_snprintf((char *)IObuff, IOSIZE, _("Change \"%.*s\" to:"),
- sug.su_badlen, sug.su_badptr);
+ sug.su_badlen, sug.su_badptr);
if (cmdmsg_rl && STRNCMP(IObuff, "Change", 6) == 0) {
// And now the rabbit from the high hat: Avoid showing the
// untranslated message rightleft.
vim_snprintf((char *)IObuff, IOSIZE, ":ot \"%.*s\" egnahC",
- sug.su_badlen, sug.su_badptr);
+ sug.su_badlen, sug.su_badptr);
}
msg_puts((const char *)IObuff);
msg_clr_eos();
@@ -2875,10 +2969,11 @@ void spell_suggest(int count)
// The suggested word may replace only part of the bad word, add
// the not replaced part.
STRLCPY(wcopy, stp->st_word, MAXWLEN + 1);
- if (sug.su_badlen > stp->st_orglen)
+ if (sug.su_badlen > stp->st_orglen) {
STRLCPY(wcopy + stp->st_wordlen,
- sug.su_badptr + stp->st_orglen,
- sug.su_badlen - stp->st_orglen + 1);
+ sug.su_badptr + stp->st_orglen,
+ sug.su_badlen - stp->st_orglen + 1);
+ }
vim_snprintf((char *)IObuff, IOSIZE, "%2d", i + 1);
if (cmdmsg_rl) {
rl_mirror(IObuff);
@@ -2897,16 +2992,18 @@ void spell_suggest(int count)
if (p_verbose > 0) {
// Add the score.
- if (sps_flags & (SPS_DOUBLE | SPS_BEST))
+ if (sps_flags & (SPS_DOUBLE | SPS_BEST)) {
vim_snprintf((char *)IObuff, IOSIZE, " (%s%d - %d)",
- stp->st_salscore ? "s " : "",
- stp->st_score, stp->st_altscore);
- else
+ stp->st_salscore ? "s " : "",
+ stp->st_score, stp->st_altscore);
+ } else {
vim_snprintf((char *)IObuff, IOSIZE, " (%d)",
- stp->st_score);
- if (cmdmsg_rl)
+ stp->st_score);
+ }
+ if (cmdmsg_rl) {
// Mirror the numbers, but keep the leading space.
rl_mirror(IObuff + 1);
+ }
msg_advance(30);
msg_puts((const char *)IObuff);
}
@@ -2941,8 +3038,8 @@ void spell_suggest(int count)
// repl_to.
repl_from = vim_strnsave(sug.su_badptr, sug.su_badlen);
vim_snprintf((char *)IObuff, IOSIZE, "%s%.*s", stp->st_word,
- sug.su_badlen - stp->st_orglen,
- sug.su_badptr + stp->st_orglen);
+ sug.su_badlen - stp->st_orglen,
+ sug.su_badptr + stp->st_orglen);
repl_to = vim_strsave(IObuff);
} else {
// Replacing su_badlen or more, use the whole word.
@@ -2961,7 +3058,7 @@ void spell_suggest(int count)
ResetRedobuff();
AppendToRedobuff("ciw");
AppendToRedobuffLit(p + c,
- stp->st_wordlen + sug.su_badlen - stp->st_orglen);
+ stp->st_wordlen + sug.su_badlen - stp->st_orglen);
AppendCharToRedobuff(ESC);
// "p" may be freed here
@@ -2969,8 +3066,9 @@ void spell_suggest(int count)
curwin->w_cursor.col = c;
changed_bytes(curwin->w_cursor.lnum, c);
- } else
+ } else {
curwin->w_cursor = prev_cursor;
+ }
spell_find_cleanup(&sug);
xfree(line);
@@ -2982,27 +3080,28 @@ void spell_suggest(int count)
static bool check_need_cap(linenr_T lnum, colnr_T col)
{
bool need_cap = false;
- char_u *line;
- char_u *line_copy = NULL;
- char_u *p;
+ char_u *line;
+ char_u *line_copy = NULL;
+ char_u *p;
colnr_T endcol;
regmatch_T regmatch;
- if (curwin->w_s->b_cap_prog == NULL)
+ if (curwin->w_s->b_cap_prog == NULL) {
return false;
+ }
line = get_cursor_line_ptr();
endcol = 0;
if (getwhitecols(line) >= (int)col) {
// At start of line, check if previous line is empty or sentence
// ends there.
- if (lnum == 1)
+ if (lnum == 1) {
need_cap = true;
- else {
+ } else {
line = ml_get(lnum - 1);
- if (*skipwhite(line) == NUL)
+ if (*skipwhite(line) == NUL) {
need_cap = true;
- else {
+ } else {
// Append a space in place of the line break.
line_copy = concat_str(line, (char_u *)" ");
line = line_copy;
@@ -3042,10 +3141,10 @@ static bool check_need_cap(linenr_T lnum, colnr_T col)
void ex_spellrepall(exarg_T *eap)
{
pos_T pos = curwin->w_cursor;
- char_u *frompat;
+ char_u *frompat;
int addlen;
- char_u *line;
- char_u *p;
+ char_u *line;
+ char_u *p;
bool save_ws = p_ws;
linenr_T prev_lnum = 0;
@@ -3072,7 +3171,7 @@ void ex_spellrepall(exarg_T *eap)
// when changing "etc" to "etc.".
line = get_cursor_line_ptr();
if (addlen <= 0 || STRNCMP(line + curwin->w_cursor.col,
- repl_to, STRLEN(repl_to)) != 0) {
+ repl_to, STRLEN(repl_to)) != 0) {
p = xmalloc(STRLEN(line) + addlen + 1);
memmove(p, line, curwin->w_cursor.col);
STRCPY(p + curwin->w_cursor.col, repl_to);
@@ -3093,26 +3192,23 @@ void ex_spellrepall(exarg_T *eap)
curwin->w_cursor = pos;
xfree(frompat);
- if (sub_nsubs == 0)
+ if (sub_nsubs == 0) {
EMSG2(_("E753: Not found: %s"), repl_from);
- else
+ } else {
do_sub_msg(false);
+ }
}
-// Find spell suggestions for "word". Return them in the growarray "*gap" as
-// a list of allocated strings.
-void
-spell_suggest_list (
- garray_T *gap,
- char_u *word,
- int maxcount, // maximum nr of suggestions
- bool need_cap, // 'spellcapcheck' matched
- bool interactive
-)
+/// Find spell suggestions for "word". Return them in the growarray "*gap" as
+/// a list of allocated strings.
+///
+/// @param maxcount maximum nr of suggestions
+/// @param need_cap 'spellcapcheck' matched
+void spell_suggest_list(garray_T *gap, char_u *word, int maxcount, bool need_cap, bool interactive)
{
suginfo_T sug;
- suggest_T *stp;
- char_u *wcopy;
+ suggest_T *stp;
+ char_u *wcopy;
spell_find_suggest(word, 0, &sug, maxcount, false, need_cap, interactive);
@@ -3134,44 +3230,41 @@ spell_suggest_list (
spell_find_cleanup(&sug);
}
-// Find spell suggestions for the word at the start of "badptr".
-// Return the suggestions in "su->su_ga".
-// The maximum number of suggestions is "maxcount".
-// Note: does use info for the current window.
-// This is based on the mechanisms of Aspell, but completely reimplemented.
-static void
-spell_find_suggest (
- char_u *badptr,
- int badlen, // length of bad word or 0 if unknown
- suginfo_T *su,
- int maxcount,
- bool banbadword, // don't include badword in suggestions
- bool need_cap, // word should start with capital
- bool interactive
-)
+/// Find spell suggestions for the word at the start of "badptr".
+/// Return the suggestions in "su->su_ga".
+/// The maximum number of suggestions is "maxcount".
+/// Note: does use info for the current window.
+/// This is based on the mechanisms of Aspell, but completely reimplemented.
+///
+/// @param badlen length of bad word or 0 if unknown
+/// @param banbadword don't include badword in suggestions
+/// @param need_cap word should start with capital
+static void spell_find_suggest(char_u *badptr, int badlen, suginfo_T *su, int maxcount,
+ bool banbadword, bool need_cap, bool interactive)
{
hlf_T attr = HLF_COUNT;
char_u buf[MAXPATHL];
- char_u *p;
+ char_u *p;
bool do_combine = false;
- char_u *sps_copy;
+ char_u *sps_copy;
static bool expr_busy = false;
int c;
- langp_T *lp;
+ langp_T *lp;
bool did_intern = false;
// Set the info in "*su".
memset(su, 0, sizeof(suginfo_T));
ga_init(&su->su_ga, (int)sizeof(suggest_T), 10);
ga_init(&su->su_sga, (int)sizeof(suggest_T), 10);
- if (*badptr == NUL)
+ if (*badptr == NUL) {
return;
+ }
hash_init(&su->su_banned);
su->su_badptr = badptr;
- if (badlen != 0)
+ if (badlen != 0) {
su->su_badlen = badlen;
- else {
+ } else {
size_t tmplen = spell_check(curwin, su->su_badptr, &attr, NULL, false);
assert(tmplen <= INT_MAX);
su->su_badlen = (int)tmplen;
@@ -3179,8 +3272,9 @@ spell_find_suggest (
su->su_maxcount = maxcount;
su->su_maxscore = SCORE_MAXINIT;
- if (su->su_badlen >= MAXWLEN)
+ if (su->su_badlen >= MAXWLEN) {
su->su_badlen = MAXWLEN - 1; // just in case
+ }
STRLCPY(su->su_badword, su->su_badptr, su->su_badlen + 1);
(void)spell_casefold(curwin, su->su_badptr, su->su_badlen, su->su_fbadword,
MAXWLEN);
@@ -3192,9 +3286,10 @@ spell_find_suggest (
// get caps flags for bad word
su->su_badflags = badword_captype(su->su_badptr,
- su->su_badptr + su->su_badlen);
- if (need_cap)
+ su->su_badptr + su->su_badlen);
+ if (need_cap) {
su->su_badflags |= WF_ONECAP;
+ }
// Find the default language for sound folding. We simply use the first
// one in 'spelllang' that supports sound folding. That's good for when
@@ -3210,9 +3305,10 @@ spell_find_suggest (
// Soundfold the bad word with the default sound folding, so that we don't
// have to do this many times.
- if (su->su_sallang != NULL)
+ if (su->su_sallang != NULL) {
spell_soundfold(su->su_sallang, su->su_fbadword, true,
- su->su_sal_badword);
+ su->su_sal_badword);
+ }
// If the word is not capitalised and spell_check() doesn't consider the
// word to be bad then it might need to be capitalised. Add a suggestion
@@ -3221,12 +3317,13 @@ spell_find_suggest (
if (!SPELL_ISUPPER(c) && attr == HLF_COUNT) {
make_case_word(su->su_badword, buf, WF_ONECAP);
add_suggestion(su, &su->su_ga, buf, su->su_badlen, SCORE_ICASE,
- 0, true, su->su_sallang, false);
+ 0, true, su->su_sallang, false);
}
// Ban the bad word itself. It may appear in another region.
- if (banbadword)
+ if (banbadword) {
add_banned(su, su->su_badword);
+ }
// Make a copy of 'spellsuggest', because the expression may change it.
sps_copy = vim_strsave(p_sps);
@@ -3258,10 +3355,11 @@ spell_find_suggest (
xfree(sps_copy);
- if (do_combine)
+ if (do_combine) {
// Combine the two list of suggestions. This must be done last,
// because sorting changes the order again.
score_combine(su);
+ }
}
// Find suggestions by evaluating expression "expr".
@@ -3297,9 +3395,9 @@ static void spell_suggest_expr(suginfo_T *su, char_u *expr)
// Find suggestions in file "fname". Used for "file:" in 'spellsuggest'.
static void spell_suggest_file(suginfo_T *su, char_u *fname)
{
- FILE *fd;
+ FILE *fd;
char_u line[MAXWLEN * 2];
- char_u *p;
+ char_u *p;
int len;
char_u cword[MAXWLEN];
@@ -3315,13 +3413,15 @@ static void spell_suggest_file(suginfo_T *su, char_u *fname)
line_breakcheck();
p = vim_strchr(line, '/');
- if (p == NULL)
+ if (p == NULL) {
continue; // No Tab found, just skip the line.
+ }
*p++ = NUL;
if (STRICMP(su->su_badword, line) == 0) {
// Match! Isolate the good word, until CR or NL.
- for (len = 0; p[len] >= ' '; ++len)
+ for (len = 0; p[len] >= ' '; ++len) {
;
+ }
p[len] = NUL;
// If the suggestion doesn't have specific case duplicate the case
@@ -3332,7 +3432,7 @@ static void spell_suggest_file(suginfo_T *su, char_u *fname)
}
add_suggestion(su, &su->su_ga, p, su->su_badlen,
- SCORE_FILE, 0, true, su->su_sallang, false);
+ SCORE_FILE, 0, true, su->su_sallang, false);
}
}
@@ -3360,15 +3460,17 @@ static void spell_suggest_intern(suginfo_T *su, bool interactive)
suggest_try_change(su);
// For the resulting top-scorers compute the sound-a-like score.
- if (sps_flags & SPS_DOUBLE)
+ if (sps_flags & SPS_DOUBLE) {
score_comp_sal(su);
+ }
// 3. Try finding sound-a-like words.
if ((sps_flags & SPS_FAST) == 0) {
- if (sps_flags & SPS_BEST)
+ if (sps_flags & SPS_BEST) {
// Adjust the word score for the suggestions found so far for how
// they sounds like.
rescore_suggestions(su);
+ }
// While going through the soundfold tree "su_maxscore" is the score
// for the soundfold word, limits the changes that are being tried,
@@ -3407,9 +3509,10 @@ static void spell_suggest_intern(suginfo_T *su, bool interactive)
}
if ((sps_flags & SPS_DOUBLE) == 0 && su->su_ga.ga_len != 0) {
- if (sps_flags & SPS_BEST)
+ if (sps_flags & SPS_BEST) {
// Adjust the word score for how it sounds like.
rescore_suggestions(su);
+ }
// Remove bogus suggestions, sort and truncate at "maxcount".
check_suggestions(su, &su->su_ga);
@@ -3420,7 +3523,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);
@@ -3459,11 +3562,13 @@ static void allcap_copy(char_u *word, char_u *wcopy)
if (c == 0xdf) {
c = 'S';
- if (d - wcopy >= MAXWLEN - 1)
+ if (d - wcopy >= MAXWLEN - 1) {
break;
+ }
*d++ = c;
- } else
+ } else {
c = SPELL_TOUPPER(c);
+ }
if (d - wcopy >= MAXWLEN - MB_MAXBYTES) {
break;
@@ -3476,7 +3581,7 @@ static void allcap_copy(char_u *word, char_u *wcopy)
// Try finding suggestions by recognizing specific situations.
static void suggest_try_special(suginfo_T *su)
{
- char_u *p;
+ char_u *p;
size_t len;
int c;
char_u word[MAXWLEN];
@@ -3496,7 +3601,7 @@ static void suggest_try_special(suginfo_T *su)
// Give a soundalike score of 0, compute the score as if deleting one
// character.
add_suggestion(su, &su->su_ga, word, su->su_badlen,
- RESCORE(SCORE_REP, 0), 0, true, su->su_sallang, false);
+ RESCORE(SCORE_REP, 0), 0, true, su->su_sallang, false);
}
}
@@ -3509,8 +3614,7 @@ proftime_T total;
proftime_T times[STATE_FINAL + 1];
long counts[STATE_FINAL + 1];
- static void
-prof_init(void)
+static void prof_init(void)
{
for (int i = 0; i <= STATE_FINAL; i++) {
profile_zero(&times[i]);
@@ -3521,8 +3625,7 @@ prof_init(void)
}
// call before changing state
- static void
-prof_store(state_T state)
+static void prof_store(state_T state)
{
profile_end(&current);
profile_add(&times[state], &current);
@@ -3531,8 +3634,7 @@ prof_store(state_T state)
}
# define PROF_STORE(state) prof_store(state);
- static void
-prof_report(char *name)
+static void prof_report(char *name)
{
FILE *fd = fopen("suggestprof", "a");
@@ -3554,8 +3656,8 @@ static void suggest_try_change(suginfo_T *su)
{
char_u fword[MAXWLEN]; // copy of the bad word, case-folded
int n;
- char_u *p;
- langp_T *lp;
+ char_u *p;
+ langp_T *lp;
// We make a copy of the case-folded bad word, so that we can modify it
// to find matches (esp. REP items). Append some more text, changing
@@ -3570,8 +3672,9 @@ static void suggest_try_change(suginfo_T *su)
// If reloading a spell file fails it's still in the list but
// everything has been cleared.
- if (lp->lp_slang->sl_fbyts == NULL)
+ if (lp->lp_slang->sl_fbyts == NULL) {
continue;
+ }
// Try it for this language. Will add possible suggestions.
//
@@ -3623,28 +3726,28 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
char_u tword[MAXWLEN]; // good word collected so far
trystate_T stack[MAXWLEN];
char_u preword[MAXWLEN * 3] = { 0 }; // word found with proper case;
- // concatenation of prefix compound
- // words and split word. NUL terminated
- // when going deeper but not when coming
- // back.
+ // concatenation of prefix compound
+ // words and split word. NUL terminated
+ // when going deeper but not when coming
+ // back.
char_u compflags[MAXWLEN]; // compound flags, one for each word
- trystate_T *sp;
+ trystate_T *sp;
int newscore;
int score;
- char_u *byts, *fbyts, *pbyts;
- idx_T *idxs, *fidxs, *pidxs;
+ char_u *byts, *fbyts, *pbyts;
+ idx_T *idxs, *fidxs, *pidxs;
int depth;
int c, c2, c3;
int n = 0;
int flags;
- garray_T *gap;
+ garray_T *gap;
idx_T arridx;
int len;
- char_u *p;
- fromto_T *ftp;
+ char_u *p;
+ fromto_T *ftp;
int fl = 0, tl;
int repextra = 0; // extra bytes in fword[] from REP item
- slang_T *slang = lp->lp_slang;
+ slang_T *slang = lp->lp_slang;
int fword_ends;
bool goodword_ends;
#ifdef DEBUG_TRIEWALK
@@ -3709,8 +3812,9 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
if (sp->ts_prefixdepth == PFD_PREFIXTREE) {
// Skip over the NUL bytes, we use them later.
- for (n = 0; n < len && byts[arridx + n] == 0; ++n)
+ for (n = 0; n < len && byts[arridx + n] == 0; ++n) {
;
+ }
sp->ts_curi += n;
// Always past NUL bytes now.
@@ -3727,7 +3831,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
n = nofold_len(fword, sp->ts_fidx, su->su_badptr);
flags = badword_captype(su->su_badptr, su->su_badptr + n);
su->su_badflags = badword_captype(su->su_badptr + n,
- su->su_badptr + su->su_badlen);
+ su->su_badptr + su->su_badlen);
#ifdef DEBUG_TRIEWALK
sprintf(changename[depth], "prefix");
#endif
@@ -3743,7 +3847,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// and make find_keepcap_word() works.
tword[sp->ts_twordlen] = NUL;
make_case_word(tword + sp->ts_splitoff,
- preword + sp->ts_prewordlen, flags);
+ preword + sp->ts_prewordlen, flags);
sp->ts_prewordlen = (char_u)STRLEN(preword);
sp->ts_splitoff = sp->ts_twordlen;
}
@@ -3764,8 +3868,9 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
flags = (int)idxs[arridx];
// Skip words with the NOSUGGEST flag.
- if (flags & WF_NOSUGGEST)
+ if (flags & WF_NOSUGGEST) {
break;
+ }
fword_ends = (fword[sp->ts_fidx] == NUL
|| (soundfold
@@ -3782,17 +3887,20 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// none this must be the first try without a prefix.
n = stack[sp->ts_prefixdepth].ts_arridx;
len = pbyts[n++];
- for (c = 0; c < len && pbyts[n + c] == 0; ++c)
+ for (c = 0; c < len && pbyts[n + c] == 0; ++c) {
;
+ }
if (c > 0) {
c = valid_word_prefix(c, n, flags,
- tword + sp->ts_splitoff, slang, false);
- if (c == 0)
+ tword + sp->ts_splitoff, slang, false);
+ if (c == 0) {
break;
+ }
// Use the WF_RARE flag for a rare prefix.
- if (c & WF_RAREPFX)
+ if (c & WF_RAREPFX) {
flags |= WF_RARE;
+ }
// Tricky: when checking for both prefix and compounding
// we run into the prefix flag first.
@@ -3805,10 +3913,11 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// Check NEEDCOMPOUND: can't use word without compounding. Do try
// appending another compound word below.
if (sp->ts_complen == sp->ts_compsplit && fword_ends
- && (flags & WF_NEEDCOMP))
+ && (flags & WF_NEEDCOMP)) {
goodword_ends = false;
- else
+ } else {
goodword_ends = true;
+ }
p = NULL;
compound_ok = true;
@@ -3821,18 +3930,19 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
if (sp->ts_fidx - sp->ts_splitfidx
== sp->ts_twordlen - sp->ts_splitoff
&& STRNCMP(fword + sp->ts_splitfidx,
- tword + sp->ts_splitoff,
- sp->ts_fidx - sp->ts_splitfidx) == 0) {
+ tword + sp->ts_splitoff,
+ sp->ts_fidx - sp->ts_splitfidx) == 0) {
preword[sp->ts_prewordlen] = NUL;
newscore = score_wordcount_adj(slang, sp->ts_score,
- preword + sp->ts_prewordlen,
- sp->ts_prewordlen > 0);
+ preword + sp->ts_prewordlen,
+ sp->ts_prewordlen > 0);
// Add the suggestion if the score isn't too bad.
- if (newscore <= su->su_maxscore)
+ if (newscore <= su->su_maxscore) {
add_suggestion(su, &su->su_ga, preword,
- sp->ts_splitfidx - repextra,
- newscore, 0, false,
- lp->lp_sallang, false);
+ sp->ts_splitfidx - repextra,
+ newscore, 0, false,
+ lp->lp_sallang, false);
+ }
break;
}
} else {
@@ -3856,23 +3966,26 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
compflags[sp->ts_complen] = ((unsigned)flags >> 24);
compflags[sp->ts_complen + 1] = NUL;
STRLCPY(preword + sp->ts_prewordlen,
- tword + sp->ts_splitoff,
- sp->ts_twordlen - sp->ts_splitoff + 1);
+ tword + sp->ts_splitoff,
+ sp->ts_twordlen - sp->ts_splitoff + 1);
// Verify CHECKCOMPOUNDPATTERN rules.
if (match_checkcompoundpattern(preword, sp->ts_prewordlen,
- &slang->sl_comppat))
+ &slang->sl_comppat)) {
compound_ok = false;
+ }
if (compound_ok) {
p = preword;
- while (*skiptowhite(p) != NUL)
+ while (*skiptowhite(p) != NUL) {
p = skipwhite(skiptowhite(p));
+ }
if (fword_ends && !can_compound(slang, p,
- compflags + sp->ts_compsplit))
+ compflags + sp->ts_compsplit)) {
// Compound is not allowed. But it may still be
// possible if we add another (short) word.
compound_ok = false;
+ }
}
// Get pointer to last char of previous word.
@@ -3884,29 +3997,31 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// Form the word with proper case in preword.
// If there is a word from a previous split, append.
// For the soundfold tree don't change the case, simply append.
- if (soundfold)
+ if (soundfold) {
STRCPY(preword + sp->ts_prewordlen, tword + sp->ts_splitoff);
- else if (flags & WF_KEEPCAP)
+ } else if (flags & WF_KEEPCAP) {
// Must find the word in the keep-case tree.
find_keepcap_word(slang, tword + sp->ts_splitoff,
- preword + sp->ts_prewordlen);
- else {
+ preword + sp->ts_prewordlen);
+ } else {
// Include badflags: If the badword is onecap or allcap
// use that for the goodword too. But if the badword is
// allcap and it's only one char long use onecap.
c = su->su_badflags;
if ((c & WF_ALLCAP)
- && su->su_badlen == (*mb_ptr2len)(su->su_badptr)
- )
+ && su->su_badlen ==
+ (*mb_ptr2len)(su->su_badptr)) {
c = WF_ONECAP;
+ }
c |= flags;
// When appending a compound word after a word character don't
// use Onecap.
- if (p != NULL && spell_iswordp_nmw(p, curwin))
+ if (p != NULL && spell_iswordp_nmw(p, curwin)) {
c &= ~WF_ONECAP;
+ }
make_case_word(tword + sp->ts_splitoff,
- preword + sp->ts_prewordlen, c);
+ preword + sp->ts_prewordlen, c);
}
if (!soundfold) {
@@ -3919,8 +4034,9 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
if ((sp->ts_complen == sp->ts_compsplit
&& WAS_BANNED(su, preword + sp->ts_prewordlen))
|| WAS_BANNED(su, preword)) {
- if (slang->sl_compprog == NULL)
+ if (slang->sl_compprog == NULL) {
break;
+ }
// the word so far was banned but we may try compounding
goodword_ends = false;
}
@@ -3929,14 +4045,17 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
newscore = 0;
if (!soundfold) { // soundfold words don't have flags
if ((flags & WF_REGION)
- && (((unsigned)flags >> 16) & lp->lp_region) == 0)
+ && (((unsigned)flags >> 16) & lp->lp_region) == 0) {
newscore += SCORE_REGION;
- if (flags & WF_RARE)
+ }
+ if (flags & WF_RARE) {
newscore += SCORE_RARE;
+ }
if (!spell_valid_case(su->su_badflags,
- captype(preword + sp->ts_prewordlen, NULL)))
+ captype(preword + sp->ts_prewordlen, NULL))) {
newscore += SCORE_ICASE;
+ }
}
// TODO: how about splitting in the soundfold tree?
@@ -3951,15 +4070,16 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// print the stack of changes that brought us here
smsg("------ %s -------", fword);
- for (j = 0; j < depth; ++j)
+ for (j = 0; j < depth; ++j) {
smsg("%s", changename[j]);
+ }
}
#endif
if (soundfold) {
// For soundfolded words we need to find the original
// words, the edit distance and then add them.
add_sound_suggest(su, preword, sp->ts_score, lp);
- } else if (sp->ts_fidx > 0) {
+ } else if (sp->ts_fidx > 0) {
// Give a penalty when changing non-word char to word
// char, e.g., "thes," -> "these".
p = fword + sp->ts_fidx;
@@ -3974,15 +4094,15 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// Give a bonus to words seen before.
score = score_wordcount_adj(slang,
- sp->ts_score + newscore,
- preword + sp->ts_prewordlen,
- sp->ts_prewordlen > 0);
+ sp->ts_score + newscore,
+ preword + sp->ts_prewordlen,
+ sp->ts_prewordlen > 0);
// Add the suggestion if the score isn't too bad.
if (score <= su->su_maxscore) {
add_suggestion(su, &su->su_ga, preword,
- sp->ts_fidx - repextra,
- score, 0, false, lp->lp_sallang, false);
+ sp->ts_fidx - repextra,
+ score, 0, false, lp->lp_sallang, false);
if (su->su_badflags & WF_MIXCAP) {
// We really don't know if the word should be
@@ -3990,13 +4110,13 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
c = captype(preword, NULL);
if (c == 0 || c == WF_ALLCAP) {
make_case_word(tword + sp->ts_splitoff,
- preword + sp->ts_prewordlen,
- c == 0 ? WF_ALLCAP : 0);
+ preword + sp->ts_prewordlen,
+ c == 0 ? WF_ALLCAP : 0);
add_suggestion(su, &su->su_ga, preword,
- sp->ts_fidx - repextra,
- score + SCORE_ICASE, 0, false,
- lp->lp_sallang, false);
+ sp->ts_fidx - repextra,
+ score + SCORE_ICASE, 0, false,
+ lp->lp_sallang, false);
}
}
}
@@ -4006,8 +4126,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// Try word split and/or compounding.
if ((sp->ts_fidx >= sp->ts_fidxtry || fword_ends)
// Don't split in the middle of a character
- && (sp->ts_tcharlen == 0)
- ) {
+ && (sp->ts_tcharlen == 0)) {
bool try_compound;
int try_split;
@@ -4045,7 +4164,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
|| sp->ts_complen + 1 - sp->ts_compsplit
< slang->sl_compmax)
&& (can_be_compound(sp, slang,
- compflags, ((unsigned)flags >> 24)))) {
+ compflags, ((unsigned)flags >> 24)))) {
try_compound = true;
compflags[sp->ts_complen] = ((unsigned)flags >> 24);
compflags[sp->ts_complen + 1] = NUL;
@@ -4076,35 +4195,40 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// is only one word it must not have the NEEDCOMPOUND
// flag.
if (sp->ts_complen == sp->ts_compsplit
- && (flags & WF_NEEDCOMP))
+ && (flags & WF_NEEDCOMP)) {
break;
+ }
p = preword;
- while (*skiptowhite(p) != NUL)
+ while (*skiptowhite(p) != NUL) {
p = skipwhite(skiptowhite(p));
+ }
if (sp->ts_complen > sp->ts_compsplit
&& !can_compound(slang, p,
- compflags + sp->ts_compsplit))
+ compflags + sp->ts_compsplit)) {
break;
+ }
- if (slang->sl_nosplitsugs)
+ if (slang->sl_nosplitsugs) {
newscore += SCORE_SPLIT_NO;
- else
+ } else {
newscore += SCORE_SPLIT;
+ }
// Give a bonus to words seen before.
newscore = score_wordcount_adj(slang, newscore,
- preword + sp->ts_prewordlen, true);
+ preword + sp->ts_prewordlen, true);
}
if (TRY_DEEPER(su, stack, depth, newscore)) {
go_deeper(stack, depth, newscore);
#ifdef DEBUG_TRIEWALK
- if (!try_compound && !fword_ends)
+ if (!try_compound && !fword_ends) {
sprintf(changename[depth], "%.*s-%s: split",
- sp->ts_twordlen, tword, fword + sp->ts_fidx);
- else
+ sp->ts_twordlen, tword, fword + sp->ts_fidx);
+ } else {
sprintf(changename[depth], "%.*s-%s: compound",
- sp->ts_twordlen, tword, fword + sp->ts_fidx);
+ sp->ts_twordlen, tword, fword + sp->ts_fidx);
+ }
#endif
// Save things to be restored at STATE_SPLITUNDO.
sp->ts_save_badflags = su->su_badflags;
@@ -4115,8 +4239,9 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
sp = &stack[depth];
// Append a space to preword when splitting.
- if (!try_compound && !fword_ends)
+ if (!try_compound && !fword_ends) {
STRCAT(preword, " ");
+ }
sp->ts_prewordlen = (char_u)STRLEN(preword);
sp->ts_splitoff = sp->ts_twordlen;
sp->ts_splitfidx = sp->ts_fidx;
@@ -4127,8 +4252,8 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// character when the word ends. But only when the
// good word can end.
if (((!try_compound && !spell_iswordp_nmw(fword
- + sp->ts_fidx,
- curwin))
+ + sp->ts_fidx,
+ curwin))
|| fword_ends)
&& fword[sp->ts_fidx] != NUL
&& goodword_ends) {
@@ -4138,28 +4263,30 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
if (fword_ends) {
// Copy the skipped character to preword.
memmove(preword + sp->ts_prewordlen,
- fword + sp->ts_fidx, l);
+ fword + sp->ts_fidx, l);
sp->ts_prewordlen += l;
preword[sp->ts_prewordlen] = NUL;
- } else
+ } else {
sp->ts_score -= SCORE_SPLIT - SCORE_SUBST;
+ }
sp->ts_fidx += l;
}
// When compounding include compound flag in
// compflags[] (already set above). When splitting we
// may start compounding over again.
- if (try_compound)
+ if (try_compound) {
++sp->ts_complen;
- else
+ } else {
sp->ts_compsplit = sp->ts_complen;
+ }
sp->ts_prefixdepth = PFD_NOPREFIX;
// set su->su_badflags to the caps type at this
// position
n = nofold_len(fword, sp->ts_fidx, su->su_badptr);
su->su_badflags = badword_captype(su->su_badptr + n,
- su->su_badptr + su->su_badlen);
+ su->su_badptr + su->su_badlen);
// Restart at top of the tree.
sp->ts_arridx = 0;
@@ -4194,8 +4321,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// Past the NUL bytes in the node.
su->su_badflags = sp->ts_save_badflags;
if (fword[sp->ts_fidx] == NUL
- && sp->ts_tcharlen == 0
- ) {
+ && sp->ts_tcharlen == 0) {
// The badword ends, can't use STATE_PLAIN.
PROF_STORE(sp->ts_state)
sp->ts_state = STATE_DEL;
@@ -4228,11 +4354,12 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// just deleted this byte, accepting it is always cheaper than
// delete + substitute.
if (c == fword[sp->ts_fidx]
- || (sp->ts_tcharlen > 0 && sp->ts_isdiff != DIFF_NONE)
- )
+ || (sp->ts_tcharlen > 0 &&
+ sp->ts_isdiff != DIFF_NONE)) {
newscore = 0;
- else
+ } else {
newscore = SCORE_SUBST;
+ }
if ((newscore == 0
|| (sp->ts_fidx >= sp->ts_fidxtry
&& ((sp->ts_flags & TSF_DIDDEL) == 0
@@ -4240,14 +4367,15 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
&& TRY_DEEPER(su, stack, depth, newscore)) {
go_deeper(stack, depth, newscore);
#ifdef DEBUG_TRIEWALK
- if (newscore > 0)
+ if (newscore > 0) {
sprintf(changename[depth], "%.*s-%s: subst %c to %c",
- sp->ts_twordlen, tword, fword + sp->ts_fidx,
- fword[sp->ts_fidx], c);
- else
+ sp->ts_twordlen, tword, fword + sp->ts_fidx,
+ fword[sp->ts_fidx], c);
+ } else {
sprintf(changename[depth], "%.*s-%s: accept %c",
- sp->ts_twordlen, tword, fword + sp->ts_fidx,
- fword[sp->ts_fidx]);
+ sp->ts_twordlen, tword, fword + sp->ts_fidx,
+ fword[sp->ts_fidx]);
+ }
#endif
++depth;
sp = &stack[depth];
@@ -4289,12 +4417,11 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
+ sp->ts_fcharstart))) {
sp->ts_score -= SCORE_SUBST - SCORE_SUBCOMP;
} else if (
- !soundfold
- && slang->sl_has_map
- && similar_chars(
- slang,
- utf_ptr2char(tword + sp->ts_twordlen - sp->ts_tcharlen),
- utf_ptr2char(fword + sp->ts_fcharstart))) {
+ !soundfold
+ && slang->sl_has_map
+ && similar_chars(slang,
+ utf_ptr2char(tword + sp->ts_twordlen - sp->ts_tcharlen),
+ utf_ptr2char(fword + sp->ts_fcharstart))) {
// For a similar character adjust score from
// SCORE_SUBST to SCORE_SIMILAR.
sp->ts_score -= SCORE_SUBST - SCORE_SIMILAR;
@@ -4339,19 +4466,20 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
PROF_STORE(sp->ts_state)
sp->ts_state = STATE_INS_PREP;
sp->ts_curi = 1;
- if (soundfold && sp->ts_fidx == 0 && fword[sp->ts_fidx] == '*')
+ if (soundfold && sp->ts_fidx == 0 && fword[sp->ts_fidx] == '*') {
// Deleting a vowel at the start of a word counts less, see
// soundalike_score().
newscore = 2 * SCORE_DEL / 3;
- else
+ } else {
newscore = SCORE_DEL;
+ }
if (fword[sp->ts_fidx] != NUL
&& TRY_DEEPER(su, stack, depth, newscore)) {
go_deeper(stack, depth, newscore);
#ifdef DEBUG_TRIEWALK
sprintf(changename[depth], "%.*s-%s: delete %c",
- sp->ts_twordlen, tword, fword + sp->ts_fidx,
- fword[sp->ts_fidx]);
+ sp->ts_twordlen, tword, fword + sp->ts_fidx,
+ fword[sp->ts_fidx]);
#endif
++depth;
@@ -4421,19 +4549,20 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// accepting that byte is always better.
n += sp->ts_curi++;
c = byts[n];
- if (soundfold && sp->ts_twordlen == 0 && c == '*')
+ if (soundfold && sp->ts_twordlen == 0 && c == '*') {
// Inserting a vowel at the start of a word counts less,
// see soundalike_score().
newscore = 2 * SCORE_INS / 3;
- else
+ } else {
newscore = SCORE_INS;
+ }
if (c != fword[sp->ts_fidx]
&& TRY_DEEPER(su, stack, depth, newscore)) {
go_deeper(stack, depth, newscore);
#ifdef DEBUG_TRIEWALK
sprintf(changename[depth], "%.*s-%s: insert %c",
- sp->ts_twordlen, tword, fword + sp->ts_fidx,
- c);
+ sp->ts_twordlen, tword, fword + sp->ts_fidx,
+ c);
#endif
++depth;
sp = &stack[depth];
@@ -4454,8 +4583,9 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// soundfold words (illogical but does give a better
// score).
if (sp->ts_twordlen >= 2
- && tword[sp->ts_twordlen - 2] == c)
+ && tword[sp->ts_twordlen - 2] == c) {
sp->ts_score -= SCORE_INS - SCORE_INSDUP;
+ }
}
}
break;
@@ -4566,8 +4696,8 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
go_deeper(stack, depth, SCORE_SWAP3);
#ifdef DEBUG_TRIEWALK
sprintf(changename[depth], "%.*s-%s: swap3 %c and %c",
- sp->ts_twordlen, tword, fword + sp->ts_fidx,
- c, c3);
+ sp->ts_twordlen, tword, fword + sp->ts_fidx,
+ c, c3);
#endif
PROF_STORE(sp->ts_state)
sp->ts_state = STATE_UNSWAP3;
@@ -4611,8 +4741,8 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
#ifdef DEBUG_TRIEWALK
p = fword + sp->ts_fidx;
sprintf(changename[depth], "%.*s-%s: rotate left %c%c%c",
- sp->ts_twordlen, tword, fword + sp->ts_fidx,
- p[0], p[1], p[2]);
+ sp->ts_twordlen, tword, fword + sp->ts_fidx,
+ p[0], p[1], p[2]);
#endif
PROF_STORE(sp->ts_state)
sp->ts_state = STATE_UNROT3L;
@@ -4648,8 +4778,8 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
#ifdef DEBUG_TRIEWALK
p = fword + sp->ts_fidx;
sprintf(changename[depth], "%.*s-%s: rotate right %c%c%c",
- sp->ts_twordlen, tword, fword + sp->ts_fidx,
- p[0], p[1], p[2]);
+ sp->ts_twordlen, tword, fword + sp->ts_fidx,
+ p[0], p[1], p[2]);
#endif
PROF_STORE(sp->ts_state)
sp->ts_state = STATE_UNROT3R;
@@ -4696,10 +4826,11 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// Use the first byte to quickly find the first entry that may
// match. If the index is -1 there is none.
- if (soundfold)
+ if (soundfold) {
sp->ts_curi = slang->sl_repsal_first[fword[sp->ts_fidx]];
- else
+ } else {
sp->ts_curi = lp->lp_replang->sl_rep_first[fword[sp->ts_fidx]];
+ }
if (sp->ts_curi < 0) {
PROF_STORE(sp->ts_state)
@@ -4717,10 +4848,11 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// valid.
p = fword + sp->ts_fidx;
- if (soundfold)
+ if (soundfold) {
gap = &slang->sl_repsal;
- else
+ } else {
gap = &lp->lp_replang->sl_rep;
+ }
while (sp->ts_curi < gap->ga_len) {
ftp = (fromto_T *)gap->ga_data + sp->ts_curi++;
if (*ftp->ft_from != *p) {
@@ -4733,8 +4865,8 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
go_deeper(stack, depth, SCORE_REP);
#ifdef DEBUG_TRIEWALK
sprintf(changename[depth], "%.*s-%s: replace %s with %s",
- sp->ts_twordlen, tword, fword + sp->ts_fidx,
- ftp->ft_from, ftp->ft_to);
+ sp->ts_twordlen, tword, fword + sp->ts_fidx,
+ ftp->ft_from, ftp->ft_to);
#endif
// Need to undo this afterwards.
PROF_STORE(sp->ts_state)
@@ -4755,19 +4887,21 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
}
}
- if (sp->ts_curi >= gap->ga_len && sp->ts_state == STATE_REP)
+ if (sp->ts_curi >= gap->ga_len && sp->ts_state == STATE_REP) {
// No (more) matches.
PROF_STORE(sp->ts_state)
sp->ts_state = STATE_FINAL;
+ }
break;
case STATE_REP_UNDO:
// Undo a REP replacement and continue with the next one.
- if (soundfold)
+ if (soundfold) {
gap = &slang->sl_repsal;
- else
+ } else {
gap = &lp->lp_replang->sl_rep;
+ }
ftp = (fromto_T *)gap->ga_data + sp->ts_curi - 1;
fl = (int)STRLEN(ftp->ft_from);
tl = (int)STRLEN(ftp->ft_to);
@@ -4815,7 +4949,7 @@ static void go_deeper(trystate_T *stack, int depth, int score_add)
// fword[flen] and return the byte length of that many chars in "word".
static int nofold_len(char_u *fword, int flen, char_u *word)
{
- char_u *p;
+ char_u *p;
int i = 0;
for (p = fword; p < fword + flen; MB_PTR_ADV(p)) {
@@ -4849,9 +4983,9 @@ static void find_keepcap_word(slang_T *slang, char_u *fword, char_u *kword)
int len;
int c;
idx_T lo, hi, m;
- char_u *p;
- char_u *byts = slang->sl_kbyts; // array with bytes of the words
- idx_T *idxs = slang->sl_kidxs; // array with indexes
+ char_u *p;
+ char_u *byts = slang->sl_kbyts; // array with bytes of the words
+ idx_T *idxs = slang->sl_kidxs; // array with indexes
if (byts == NULL) {
// array is empty: "cannot happen"
@@ -4882,7 +5016,7 @@ static void find_keepcap_word(slang_T *slang, char_u *fword, char_u *kword)
// kword is getting too long, continue one level up
--depth;
- } else if (++round[depth] > 2) {
+ } else if (++round[depth] > 2) {
// tried both fold-case and upper-case character, continue one
// level up
--depth;
@@ -4907,19 +5041,20 @@ static void find_keepcap_word(slang_T *slang, char_u *fword, char_u *kword)
hi = tryidx + len - 1;
while (lo < hi) {
m = (lo + hi) / 2;
- if (byts[m] > c)
+ if (byts[m] > c) {
hi = m - 1;
- else if (byts[m] < c)
+ } else if (byts[m] < c) {
lo = m + 1;
- else {
+ } else {
lo = hi = m;
break;
}
}
// Stop if there is no matching byte.
- if (hi < lo || byts[lo] != c)
+ if (hi < lo || byts[lo] != c) {
break;
+ }
// Continue at the child (if there is one).
tryidx = idxs[lo];
@@ -4930,11 +5065,11 @@ static void find_keepcap_word(slang_T *slang, char_u *fword, char_u *kword)
// level deeper.
if (round[depth] == 1) {
STRNCPY(kword + kwordlen[depth], fword + fwordidx[depth],
- flen);
+ flen);
kwordlen[depth + 1] = kwordlen[depth] + flen;
} else {
STRNCPY(kword + kwordlen[depth], uword + uwordidx[depth],
- ulen);
+ ulen);
kwordlen[depth + 1] = kwordlen[depth] + ulen;
}
fwordidx[depth + 1] = fwordidx[depth] + flen;
@@ -4955,11 +5090,11 @@ static void find_keepcap_word(slang_T *slang, char_u *fword, char_u *kword)
// su->su_sga.
static void score_comp_sal(suginfo_T *su)
{
- langp_T *lp;
+ langp_T *lp;
char_u badsound[MAXWLEN];
int i;
- suggest_T *stp;
- suggest_T *sstp;
+ suggest_T *stp;
+ suggest_T *sstp;
int score;
ga_grow(&su->su_sga, su->su_ga.ga_len);
@@ -4998,13 +5133,13 @@ static void score_comp_sal(suginfo_T *su)
static void score_combine(suginfo_T *su)
{
garray_T ga;
- garray_T *gap;
- langp_T *lp;
- suggest_T *stp;
- char_u *p;
+ garray_T *gap;
+ langp_T *lp;
+ suggest_T *stp;
+ char_u *p;
char_u badsound[MAXWLEN];
int round;
- slang_T *slang = NULL;
+ slang_T *slang = NULL;
// Add the alternate score to su_ga.
for (int lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi) {
@@ -5017,11 +5152,12 @@ static void score_combine(suginfo_T *su)
for (int i = 0; i < su->su_ga.ga_len; ++i) {
stp = &SUG(su->su_ga, i);
stp->st_altscore = stp_sal_score(stp, su, slang, badsound);
- if (stp->st_altscore == SCORE_MAXMAX)
+ if (stp->st_altscore == SCORE_MAXMAX) {
stp->st_score = (stp->st_score * 3 + SCORE_BIG) / 4;
- else
+ } else {
stp->st_score = (stp->st_score * 3
+ stp->st_altscore) / 4;
+ }
stp->st_salscore = false;
}
break;
@@ -5030,7 +5166,7 @@ static void score_combine(suginfo_T *su)
if (slang == NULL) { // Using "double" without sound folding.
(void)cleanup_suggestions(&su->su_ga, su->su_maxscore,
- su->su_maxcount);
+ su->su_maxcount);
return;
}
@@ -5038,11 +5174,12 @@ static void score_combine(suginfo_T *su)
for (int i = 0; i < su->su_sga.ga_len; ++i) {
stp = &SUG(su->su_sga, i);
stp->st_altscore = spell_edit_score(slang,
- su->su_badword, stp->st_word);
- if (stp->st_score == SCORE_MAXMAX)
+ su->su_badword, stp->st_word);
+ if (stp->st_score == SCORE_MAXMAX) {
stp->st_score = (SCORE_BIG * 7 + stp->st_altscore) / 8;
- else
+ } else {
stp->st_score = (stp->st_score * 7 + stp->st_altscore) / 8;
+ }
stp->st_salscore = true;
}
@@ -5066,13 +5203,16 @@ static void score_combine(suginfo_T *su)
// Don't add a word if it's already there.
p = SUG(*gap, i).st_word;
int j;
- for (j = 0; j < ga.ga_len; ++j)
- if (STRCMP(stp[j].st_word, p) == 0)
+ for (j = 0; j < ga.ga_len; ++j) {
+ if (STRCMP(stp[j].st_word, p) == 0) {
break;
- if (j == ga.ga_len)
+ }
+ }
+ if (j == ga.ga_len) {
stp[ga.ga_len++] = SUG(*gap, i);
- else
+ } else {
xfree(p);
+ }
}
}
}
@@ -5091,19 +5231,15 @@ static void score_combine(suginfo_T *su)
su->su_ga = ga;
}
-// For the goodword in "stp" compute the soundalike score compared to the
-// badword.
-static int
-stp_sal_score (
- suggest_T *stp,
- suginfo_T *su,
- slang_T *slang,
- char_u *badsound // sound-folded badword
-)
+/// For the goodword in "stp" compute the soundalike score compared to the
+/// badword.
+///
+/// @param badsound sound-folded badword
+static int stp_sal_score(suggest_T *stp, suginfo_T *su, slang_T *slang, char_u *badsound)
{
- char_u *p;
- char_u *pbad;
- char_u *pgood;
+ char_u *p;
+ char_u *pbad;
+ char_u *pgood;
char_u badsound2[MAXWLEN];
char_u fword[MAXWLEN];
char_u goodsound[MAXWLEN];
@@ -5111,9 +5247,9 @@ stp_sal_score (
int lendiff;
lendiff = su->su_badlen - stp->st_orglen;
- if (lendiff >= 0)
+ if (lendiff >= 0) {
pbad = badsound;
- else {
+ } else {
// soundfold the bad word with more characters following
(void)spell_casefold(curwin, su->su_badptr, stp->st_orglen, fword, MAXWLEN);
@@ -5122,9 +5258,11 @@ stp_sal_score (
// removing the space. Don't do it when the good word also contains a
// space.
if (ascii_iswhite(su->su_badptr[su->su_badlen])
- && *skiptowhite(stp->st_word) == NUL)
- for (p = fword; *(p = skiptowhite(p)) != NUL; )
+ && *skiptowhite(stp->st_word) == NUL) {
+ for (p = fword; *(p = skiptowhite(p)) != NUL; ) {
STRMOVE(p, p + 1);
+ }
+ }
spell_soundfold(slang, fword, true, badsound2);
pbad = badsound2;
@@ -5135,10 +5273,11 @@ stp_sal_score (
// what replaces the bad word.
STRCPY(goodword, stp->st_word);
STRLCPY(goodword + stp->st_wordlen,
- su->su_badptr + su->su_badlen - lendiff, lendiff + 1);
+ su->su_badptr + su->su_badlen - lendiff, lendiff + 1);
pgood = goodword;
- } else
+ } else {
pgood = stp->st_word;
+ }
// Sound-fold the word and compute the score for the difference.
spell_soundfold(slang, pgood, false, goodsound);
@@ -5153,17 +5292,18 @@ static sftword_T dumsft;
// Prepare for calling suggest_try_soundalike().
static void suggest_try_soundalike_prep(void)
{
- langp_T *lp;
- slang_T *slang;
+ langp_T *lp;
+ slang_T *slang;
// Do this for all languages that support sound folding and for which a
// .sug file has been loaded.
for (int lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi) {
lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
slang = lp->lp_slang;
- if (!GA_EMPTY(&slang->sl_sal) && slang->sl_sbyts != NULL)
+ if (!GA_EMPTY(&slang->sl_sal) && slang->sl_sbyts != NULL) {
// prepare the hashtable used by add_sound_suggest()
hash_init(&slang->sl_sounddone);
+ }
}
}
@@ -5172,8 +5312,8 @@ static void suggest_try_soundalike_prep(void)
static void suggest_try_soundalike(suginfo_T *su)
{
char_u salword[MAXWLEN];
- langp_T *lp;
- slang_T *slang;
+ langp_T *lp;
+ slang_T *slang;
// Do this for all languages that support sound folding and for which a
// .sug file has been loaded.
@@ -5201,10 +5341,10 @@ static void suggest_try_soundalike(suginfo_T *su)
// Finish up after calling suggest_try_soundalike().
static void suggest_try_soundalike_finish(void)
{
- langp_T *lp;
- slang_T *slang;
+ langp_T *lp;
+ slang_T *slang;
int todo;
- hashitem_T *hi;
+ hashitem_T *hi;
// Do this for all languages that support sound folding and for which a
// .sug file has been loaded.
@@ -5214,11 +5354,12 @@ static void suggest_try_soundalike_finish(void)
if (!GA_EMPTY(&slang->sl_sal) && slang->sl_sbyts != NULL) {
// Free the info about handled words.
todo = (int)slang->sl_sounddone.ht_used;
- for (hi = slang->sl_sounddone.ht_array; todo > 0; ++hi)
+ for (hi = slang->sl_sounddone.ht_array; todo > 0; ++hi) {
if (!HASHITEM_EMPTY(hi)) {
xfree(HI2SFT(hi));
--todo;
}
+ }
// Clear the hashtable, it may also be used by another region.
hash_clear(&slang->sl_sounddone);
@@ -5227,32 +5368,28 @@ static void suggest_try_soundalike_finish(void)
}
}
-// A match with a soundfolded word is found. Add the good word(s) that
-// produce this soundfolded word.
-static void
-add_sound_suggest (
- suginfo_T *su,
- char_u *goodword,
- int score, // soundfold score
- langp_T *lp
-)
+/// A match with a soundfolded word is found. Add the good word(s) that
+/// produce this soundfolded word.
+///
+/// @param score soundfold score
+static void add_sound_suggest(suginfo_T *su, char_u *goodword, int score, langp_T *lp)
{
- slang_T *slang = lp->lp_slang; // language for sound folding
+ slang_T *slang = lp->lp_slang; // language for sound folding
int sfwordnr;
- char_u *nrline;
+ char_u *nrline;
int orgnr;
char_u theword[MAXWLEN];
int i;
int wlen;
- char_u *byts;
- idx_T *idxs;
+ char_u *byts;
+ idx_T *idxs;
int n;
int wordcount;
int wc;
int goodscore;
hash_T hash;
- hashitem_T *hi;
- sftword_T *sft;
+ hashitem_T *hi;
+ sftword_T *sft;
int bc, gc;
int limit;
@@ -5271,8 +5408,9 @@ add_sound_suggest (
hash_add_item(&slang->sl_sounddone, hi, sft->sft_word, hash);
} else {
sft = HI2SFT(hi);
- if (score >= sft->sft_score)
+ if (score >= sft->sft_score) {
return;
+ }
sft->sft_score = score;
}
@@ -5299,25 +5437,28 @@ add_sound_suggest (
wordcount = 0;
for (wlen = 0; wlen < MAXWLEN - 3; ++wlen) {
i = 1;
- if (wordcount == orgnr && byts[n + 1] == NUL)
+ if (wordcount == orgnr && byts[n + 1] == NUL) {
break; // found end of word
-
- if (byts[n + 1] == NUL)
+ }
+ if (byts[n + 1] == NUL) {
++wordcount;
+ }
// skip over the NUL bytes
- for (; byts[n + i] == NUL; ++i)
+ for (; byts[n + i] == NUL; ++i) {
if (i > byts[n]) { // safety check
STRCPY(theword + wlen, "BAD");
wlen += 3;
goto badword;
}
+ }
// One of the siblings must have the word.
for (; i < byts[n]; ++i) {
wc = idxs[idxs[n + i]]; // nr of words under this byte
- if (wordcount + wc > orgnr)
+ if (wordcount + wc > orgnr) {
break;
+ }
wordcount += wc;
}
@@ -5330,12 +5471,13 @@ badword:
// Go over the possible flags and regions.
for (; i <= byts[n] && byts[n + i] == NUL; ++i) {
char_u cword[MAXWLEN];
- char_u *p;
+ char_u *p;
int flags = (int)idxs[n + i];
// Skip words with the NOSUGGEST flag
- if (flags & WF_NOSUGGEST)
+ if (flags & WF_NOSUGGEST) {
continue;
+ }
if (flags & WF_KEEPCAP) {
// Must find the word in the keep-case tree.
@@ -5347,23 +5489,26 @@ badword:
// Need to fix case according to "flags".
make_case_word(theword, cword, flags);
p = cword;
- } else
+ } else {
p = theword;
+ }
}
// Add the suggestion.
if (sps_flags & SPS_DOUBLE) {
// Add the suggestion if the score isn't too bad.
- if (score <= su->su_maxscore)
+ if (score <= su->su_maxscore) {
add_suggestion(su, &su->su_sga, p, su->su_badlen,
- score, 0, false, slang, false);
+ score, 0, false, slang, false);
+ }
} else {
// Add a penalty for words in another region.
if ((flags & WF_REGION)
- && (((unsigned)flags >> 16) & lp->lp_region) == 0)
+ && (((unsigned)flags >> 16) & lp->lp_region) == 0) {
goodscore = SCORE_REGION;
- else
+ } else {
goodscore = 0;
+ }
// Add a small penalty for changing the first letter from
// lower to upper case. Helps for "tath" -> "Kath", which is
@@ -5373,8 +5518,9 @@ badword:
if (SPELL_ISUPPER(gc)) {
bc = PTR2CHAR(su->su_badword);
if (!SPELL_ISUPPER(bc)
- && SPELL_TOFOLD(bc) != SPELL_TOFOLD(gc))
+ && SPELL_TOFOLD(bc) != SPELL_TOFOLD(gc)) {
goodscore += SCORE_ICASE / 2;
+ }
}
// Compute the score for the good word. This only does letter
@@ -5385,11 +5531,12 @@ badword:
// If the limit is very high then the iterative method is
// inefficient, using an array is quicker.
limit = MAXSCORE(su->su_sfmaxscore - goodscore, score);
- if (limit > SCORE_LIMITMAX)
+ if (limit > SCORE_LIMITMAX) {
goodscore += spell_edit_score(slang, su->su_badword, p);
- else
+ } else {
goodscore += spell_edit_score_limit(slang, su->su_badword,
- p, limit);
+ p, limit);
+ }
// When going over the limit don't bother to do the rest.
if (goodscore < SCORE_MAXMAX) {
@@ -5398,9 +5545,10 @@ badword:
// Add the suggestion if the score isn't too bad.
goodscore = RESCORE(goodscore, score);
- if (goodscore <= su->su_sfmaxscore)
+ if (goodscore <= su->su_sfmaxscore) {
add_suggestion(su, &su->su_ga, p, su->su_badlen,
- goodscore, score, true, slang, true);
+ goodscore, score, true, slang, true);
+ }
}
}
}
@@ -5414,9 +5562,9 @@ static int soundfold_find(slang_T *slang, char_u *word)
int len;
int wlen = 0;
int c;
- char_u *ptr = word;
- char_u *byts;
- idx_T *idxs;
+ char_u *ptr = word;
+ char_u *byts;
+ idx_T *idxs;
int wordnr = 0;
byts = slang->sl_sbyts;
@@ -5430,35 +5578,41 @@ static int soundfold_find(slang_T *slang, char_u *word)
// If the word ends we found the word. If not skip the NUL bytes.
c = ptr[wlen];
if (byts[arridx] == NUL) {
- if (c == NUL)
+ if (c == NUL) {
break;
+ }
// Skip over the zeros, there can be several.
while (len > 0 && byts[arridx] == NUL) {
++arridx;
--len;
}
- if (len == 0)
+ if (len == 0) {
return -1; // no children, word should have ended here
+ }
++wordnr;
}
// If the word ends we didn't find it.
- if (c == NUL)
+ if (c == NUL) {
return -1;
+ }
// Perform a binary search in the list of accepted bytes.
- if (c == TAB) // <Tab> is handled like <Space>
+ if (c == TAB) { // <Tab> is handled like <Space>
c = ' ';
+ }
while (byts[arridx] < c) {
// The word count is in the first idxs[] entry of the child.
wordnr += idxs[idxs[arridx]];
++arridx;
- if (--len == 0) // end of the bytes, didn't find it
+ if (--len == 0) { // end of the bytes, didn't find it
return -1;
+ }
}
- if (byts[arridx] != c) // didn't find the byte
+ if (byts[arridx] != c) { // didn't find the byte
return -1;
+ }
// Continue at the child (if there is one).
arridx = idxs[arridx];
@@ -5466,9 +5620,11 @@ static int soundfold_find(slang_T *slang, char_u *word)
// One space in the good word may stand for several spaces in the
// checked word.
- if (c == ' ')
- while (ptr[wlen] == ' ' || ptr[wlen] == TAB)
+ if (c == ' ') {
+ while (ptr[wlen] == ' ' || ptr[wlen] == TAB) {
++wlen;
+ }
+ }
}
return wordnr;
@@ -5477,15 +5633,16 @@ static int soundfold_find(slang_T *slang, char_u *word)
// Copy "fword" to "cword", fixing case according to "flags".
static void make_case_word(char_u *fword, char_u *cword, int flags)
{
- if (flags & WF_ALLCAP)
+ if (flags & WF_ALLCAP) {
// Make it all upper-case
allcap_copy(fword, cword);
- else if (flags & WF_ONECAP)
+ } else if (flags & WF_ONECAP) {
// Make the first letter upper-case
onecap_copy(fword, cword, true);
- else
+ } else {
// Use goodword as-is.
STRCPY(cword, fword);
+ }
}
// Returns true if "c1" and "c2" are similar characters according to the MAP
@@ -5494,7 +5651,7 @@ static bool similar_chars(slang_T *slang, int c1, int c2)
{
int m1, m2;
char_u buf[MB_MAXBYTES + 1];
- hashitem_T *hi;
+ hashitem_T *hi;
if (c1 >= 256) {
buf[utf_char2bytes(c1, buf)] = 0;
@@ -5526,25 +5683,20 @@ static bool similar_chars(slang_T *slang, int c1, int c2)
return m1 == m2;
}
-// Adds a suggestion to the list of suggestions.
-// For a suggestion that is already in the list the lowest score is remembered.
-static void
-add_suggestion (
- suginfo_T *su,
- garray_T *gap, // either su_ga or su_sga
- const char_u *goodword,
- int badlenarg, // len of bad word replaced with "goodword"
- int score,
- int altscore,
- bool had_bonus, // value for st_had_bonus
- slang_T *slang, // language for sound folding
- bool maxsf // su_maxscore applies to soundfold score,
- // su_sfmaxscore to the total score.
-)
+/// Adds a suggestion to the list of suggestions.
+/// For a suggestion that is already in the list the lowest score is remembered.
+///
+/// @param gap either su_ga or su_sga
+/// @param badlenarg len of bad word replaced with "goodword"
+/// @param had_bonus value for st_had_bonus
+/// @param slang language for sound folding
+/// @param maxsf su_maxscore applies to soundfold score, su_sfmaxscore to the total score.
+static void add_suggestion(suginfo_T *su, garray_T *gap, const char_u *goodword, int badlenarg,
+ int score, int altscore, bool had_bonus, slang_T *slang, bool maxsf)
{
int goodlen; // len of goodword changed
int badlen; // len of bad word changed
- suggest_T *stp;
+ suggest_T *stp;
suggest_T new_sug;
// Minimize "badlen" for consistency. Avoids that changing "the the" to
@@ -5554,8 +5706,9 @@ add_suggestion (
for (;; ) {
goodlen = (int)(pgood - goodword);
badlen = (int)(pbad - su->su_badptr);
- if (goodlen <= 0 || badlen <= 0)
+ if (goodlen <= 0 || badlen <= 0) {
break;
+ }
MB_PTR_BACK(goodword, pgood);
MB_PTR_BACK(su->su_badptr, pbad);
if (utf_ptr2char(pgood) != utf_ptr2char(pbad)) {
@@ -5563,10 +5716,11 @@ add_suggestion (
}
}
- if (badlen == 0 && goodlen == 0)
+ if (badlen == 0 && goodlen == 0) {
// goodword doesn't change anything; may happen for "the the" changing
// the first "the" to itself.
return;
+ }
int i;
if (GA_EMPTY(gap)) {
@@ -5581,8 +5735,9 @@ add_suggestion (
&& stp->st_orglen == badlen
&& STRNCMP(stp->st_word, goodword, goodlen) == 0) {
// Found it. Remember the word with the lowest score.
- if (stp->st_slang == NULL)
+ if (stp->st_slang == NULL) {
stp->st_slang = slang;
+ }
new_sug.st_score = score;
new_sug.st_altscore = altscore;
@@ -5595,9 +5750,9 @@ add_suggestion (
// suggest_try_change() doesn't compute the soundalike
// word to keep it fast, while some special methods set
// the soundalike score to zero.
- if (had_bonus)
+ if (had_bonus) {
rescore_one(su, stp);
- else {
+ } else {
new_sug.st_word = stp->st_word;
new_sug.st_wordlen = stp->st_wordlen;
new_sug.st_slang = stp->st_slang;
@@ -5630,25 +5785,24 @@ add_suggestion (
// If we have too many suggestions now, sort the list and keep
// the best suggestions.
if (gap->ga_len > SUG_MAX_COUNT(su)) {
- if (maxsf)
+ if (maxsf) {
su->su_sfmaxscore = cleanup_suggestions(gap,
- su->su_sfmaxscore, SUG_CLEAN_COUNT(su));
- else
+ su->su_sfmaxscore, SUG_CLEAN_COUNT(su));
+ } else {
su->su_maxscore = cleanup_suggestions(gap,
- su->su_maxscore, SUG_CLEAN_COUNT(su));
+ su->su_maxscore, SUG_CLEAN_COUNT(su));
+ }
}
}
}
-// Suggestions may in fact be flagged as errors. Esp. for banned words and
-// for split words, such as "the the". Remove these from the list here.
-static void
-check_suggestions (
- suginfo_T *su,
- garray_T *gap // either su_ga or su_sga
-)
+/// Suggestions may in fact be flagged as errors. Esp. for banned words and
+/// for split words, such as "the the". Remove these from the list here.
+///
+/// @param gap either su_ga or su_sga
+static void check_suggestions(suginfo_T *su, garray_T *gap)
{
- suggest_T *stp;
+ suggest_T *stp;
char_u longword[MAXWLEN + 1];
int len;
hlf_T attr;
@@ -5662,16 +5816,17 @@ check_suggestions (
STRLCPY(longword, stp[i].st_word, MAXWLEN + 1);
len = stp[i].st_wordlen;
STRLCPY(longword + len, su->su_badptr + stp[i].st_orglen,
- MAXWLEN - len + 1);
+ MAXWLEN - len + 1);
attr = HLF_COUNT;
(void)spell_check(curwin, longword, &attr, NULL, false);
if (attr != HLF_COUNT) {
// Remove this entry.
xfree(stp[i].st_word);
--gap->ga_len;
- if (i < gap->ga_len)
+ if (i < gap->ga_len) {
memmove(stp + i, stp + i + 1,
- sizeof(suggest_T) * (gap->ga_len - i));
+ sizeof(suggest_T) * (gap->ga_len - i));
+ }
}
}
}
@@ -5680,9 +5835,9 @@ check_suggestions (
// Add a word to be banned.
static void add_banned(suginfo_T *su, char_u *word)
{
- char_u *s;
+ char_u *s;
hash_T hash;
- hashitem_T *hi;
+ hashitem_T *hi;
hash = hash_hash(word);
const size_t word_len = STRLEN(word);
@@ -5707,23 +5862,24 @@ static void rescore_suggestions(suginfo_T *su)
// Recompute the score for one suggestion if sound-folding is possible.
static void rescore_one(suginfo_T *su, suggest_T *stp)
{
- slang_T *slang = stp->st_slang;
+ slang_T *slang = stp->st_slang;
char_u sal_badword[MAXWLEN];
- char_u *p;
+ char_u *p;
// Only rescore suggestions that have no sal score yet and do have a
// language.
if (slang != NULL && !GA_EMPTY(&slang->sl_sal) && !stp->st_had_bonus) {
- if (slang == su->su_sallang)
+ if (slang == su->su_sallang) {
p = su->su_sal_badword;
- else {
+ } else {
spell_soundfold(slang, su->su_fbadword, true, sal_badword);
p = sal_badword;
}
stp->st_altscore = stp_sal_score(stp, su, slang, p);
- if (stp->st_altscore == SCORE_MAXMAX)
+ if (stp->st_altscore == SCORE_MAXMAX) {
stp->st_altscore = SCORE_BIG;
+ }
stp->st_score = RESCORE(stp->st_score, stp->st_altscore);
stp->st_had_bonus = true;
}
@@ -5734,28 +5890,27 @@ static void rescore_one(suginfo_T *su, suggest_T *stp)
// First on "st_score", then "st_altscore" then alphabetically.
static int sug_compare(const void *s1, const void *s2)
{
- suggest_T *p1 = (suggest_T *)s1;
- suggest_T *p2 = (suggest_T *)s2;
+ suggest_T *p1 = (suggest_T *)s1;
+ suggest_T *p2 = (suggest_T *)s2;
int n = p1->st_score - p2->st_score;
if (n == 0) {
n = p1->st_altscore - p2->st_altscore;
- if (n == 0)
+ if (n == 0) {
n = STRICMP(p1->st_word, p2->st_word);
+ }
}
return n;
}
-// Cleanup the suggestions:
-// - Sort on score.
-// - Remove words that won't be displayed.
-// Returns the maximum score in the list or "maxscore" unmodified.
-static int
-cleanup_suggestions (
- garray_T *gap,
- int maxscore,
- int keep // nr of suggestions to keep
-)
+/// Cleanup the suggestions:
+/// - Sort on score.
+/// - Remove words that won't be displayed.
+///
+/// @param keep nr of suggestions to keep
+///
+/// @return the maximum score in the list or "maxscore" unmodified.
+static int cleanup_suggestions(garray_T *gap, int maxscore, int keep)
FUNC_ATTR_NONNULL_ALL
{
if (gap->ga_len > 0) {
@@ -5823,12 +5978,12 @@ char *eval_soundfold(const char *const word)
void spell_soundfold(slang_T *slang, char_u *inword, bool folded, char_u *res)
{
char_u fword[MAXWLEN];
- char_u *word;
+ char_u *word;
- if (slang->sl_sofo)
+ if (slang->sl_sofo) {
// SOFOFROM and SOFOTO used
spell_soundfold_sofo(slang, inword, res);
- else {
+ } else {
// SAL items used. Requires the word to be case-folded.
if (folded) {
word = inword;
@@ -5892,12 +6047,12 @@ static void spell_soundfold_sofo(slang_T *slang, char_u *inword, char_u *res)
// Multi-byte version of spell_soundfold().
static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
{
- salitem_T *smp = (salitem_T *)slang->sl_sal.ga_data;
+ salitem_T *smp = (salitem_T *)slang->sl_sal.ga_data;
int word[MAXWLEN] = { 0 };
int wres[MAXWLEN] = { 0 };
int l;
- int *ws;
- int *pf;
+ int *ws;
+ int *pf;
int i, j, z;
int reslen;
int n, k = 0;
@@ -5954,27 +6109,34 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
&& ws[0] != NUL; ++n) {
// Quickly skip entries that don't match the word. Most
// entries are less then three chars, optimize for that.
- if (c != ws[0])
+ if (c != ws[0]) {
continue;
+ }
k = smp[n].sm_leadlen;
if (k > 1) {
- if (word[i + 1] != ws[1])
+ if (word[i + 1] != ws[1]) {
continue;
+ }
if (k > 2) {
- for (j = 2; j < k; ++j)
- if (word[i + j] != ws[j])
+ for (j = 2; j < k; ++j) {
+ if (word[i + j] != ws[j]) {
break;
- if (j < k)
+ }
+ }
+ if (j < k) {
continue;
+ }
}
}
if ((pf = smp[n].sm_oneof_w) != NULL) {
// Check for match with one of the chars in "sm_oneof".
- while (*pf != NUL && *pf != word[i + k])
+ while (*pf != NUL && *pf != word[i + k]) {
++pf;
- if (*pf == NUL)
+ }
+ if (*pf == NUL) {
continue;
+ }
++k;
}
char_u *s = smp[n].sm_rules;
@@ -5986,15 +6148,17 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
k--;
s++;
}
- if (*s == '<')
+ if (*s == '<') {
s++;
+ }
if (ascii_isdigit(*s)) {
// determine priority
pri = *s - '0';
s++;
}
- if (*s == '^' && *(s + 1) == '^')
+ if (*s == '^' && *(s + 1) == '^') {
s++;
+ }
if (*s == NUL
|| (*s == '^'
@@ -6017,19 +6181,24 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
for (; ((ws = smp[n0].sm_lead_w)[0] & 0xff)
== (c0 & 0xff); ++n0) {
// Quickly skip entries that don't match the word.
- if (c0 != ws[0])
+ if (c0 != ws[0]) {
continue;
+ }
k0 = smp[n0].sm_leadlen;
if (k0 > 1) {
- if (word[i + k] != ws[1])
+ if (word[i + k] != ws[1]) {
continue;
+ }
if (k0 > 2) {
pf = word + i + k + 1;
- for (j = 2; j < k0; ++j)
- if (*pf++ != ws[j])
+ for (j = 2; j < k0; ++j) {
+ if (*pf++ != ws[j]) {
break;
- if (j < k0)
+ }
+ }
+ if (j < k0) {
continue;
+ }
}
}
k0 += k - 1;
@@ -6037,10 +6206,12 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
if ((pf = smp[n0].sm_oneof_w) != NULL) {
// Check for match with one of the chars in
// "sm_oneof".
- while (*pf != NUL && *pf != word[i + k0])
+ while (*pf != NUL && *pf != word[i + k0]) {
++pf;
- if (*pf == NUL)
+ }
+ if (*pf == NUL) {
continue;
+ }
++k0;
}
@@ -6051,8 +6222,9 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
// "if (k0 == k)"
s++;
}
- if (*s == '<')
+ if (*s == '<') {
s++;
+ }
if (ascii_isdigit(*s)) {
p0 = *s - '0';
s++;
@@ -6062,22 +6234,25 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
// *s == '^' cuts
|| (*s == '$'
&& !spell_iswordp_w(word + i + k0,
- curwin))) {
- if (k0 == k)
+ curwin))) {
+ if (k0 == k) {
// this is just a piece of the string
continue;
+ }
- if (p0 < pri)
+ if (p0 < pri) {
// priority too low
continue;
+ }
// rule fits; stop search
break;
}
}
if (p0 >= pri && (smp[n0].sm_lead_w[0] & 0xff)
- == (c0 & 0xff))
+ == (c0 & 0xff)) {
continue;
+ }
}
// replace string
@@ -6088,20 +6263,23 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
// rule with '<' is used
if (reslen > 0 && ws != NULL && *ws != NUL
&& (wres[reslen - 1] == c
- || wres[reslen - 1] == *ws))
+ || wres[reslen - 1] == *ws)) {
reslen--;
+ }
z0 = 1;
z = 1;
k0 = 0;
- if (ws != NULL)
+ if (ws != NULL) {
while (*ws != NUL && word[i + k0] != NUL) {
word[i + k0] = *ws;
k0++;
ws++;
}
- if (k > k0)
+ }
+ if (k > k0) {
memmove(word + i + k0, word + i + k,
- sizeof(int) * (wordlen - (i + k) + 1));
+ sizeof(int) * (wordlen - (i + k) + 1));
+ }
// new "actual letter"
c = word[i];
@@ -6109,23 +6287,27 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
// no '<' rule used
i += k - 1;
z = 0;
- if (ws != NULL)
+ if (ws != NULL) {
while (*ws != NUL && ws[1] != NUL
&& reslen < MAXWLEN) {
- if (reslen == 0 || wres[reslen - 1] != *ws)
+ if (reslen == 0 || wres[reslen - 1] != *ws) {
wres[reslen++] = *ws;
+ }
ws++;
}
+ }
// new "actual letter"
- if (ws == NULL)
+ if (ws == NULL) {
c = NUL;
- else
+ } else {
c = *ws;
+ }
if (strstr((char *)s, "^^") != NULL) {
- if (c != NUL)
+ if (c != NUL) {
wres[reslen++] = c;
+ }
memmove(word, word + i + 1,
- sizeof(int) * (wordlen - (i + 1) + 1));
+ sizeof(int) * (wordlen - (i + 1) + 1));
i = 0;
z0 = 1;
}
@@ -6133,7 +6315,7 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
break;
}
}
- } else if (ascii_iswhite(c)) {
+ } else if (ascii_iswhite(c)) {
c = ' ';
k = 1;
}
@@ -6141,9 +6323,10 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
if (z0 == 0) {
if (k && !p0 && reslen < MAXWLEN && c != NUL
&& (!slang->sl_collapse || reslen == 0
- || wres[reslen - 1] != c))
+ || wres[reslen - 1] != c)) {
// condense only double letters
wres[reslen++] = c;
+ }
i++;
z = 0;
@@ -6162,35 +6345,36 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res)
res[l] = NUL;
}
-// Compute a score for two sound-a-like words.
-// This permits up to two inserts/deletes/swaps/etc. to keep things fast.
-// Instead of a generic loop we write out the code. That keeps it fast by
-// avoiding checks that will not be possible.
-static int
-soundalike_score (
- char_u *goodstart, // sound-folded good word
- char_u *badstart // sound-folded bad word
-)
+/// Compute a score for two sound-a-like words.
+/// This permits up to two inserts/deletes/swaps/etc. to keep things fast.
+/// Instead of a generic loop we write out the code. That keeps it fast by
+/// avoiding checks that will not be possible.
+///
+/// @param goodstart sound-folded good word
+/// @param badstart sound-folded bad word
+static int soundalike_score(char_u *goodstart, char_u *badstart)
{
- char_u *goodsound = goodstart;
- char_u *badsound = badstart;
+ char_u *goodsound = goodstart;
+ char_u *badsound = badstart;
int goodlen;
int badlen;
int n;
- char_u *pl, *ps;
- char_u *pl2, *ps2;
+ char_u *pl, *ps;
+ char_u *pl2, *ps2;
int score = 0;
// Adding/inserting "*" at the start (word starts with vowel) shouldn't be
// counted so much, vowels in the middle of the word aren't counted at all.
if ((*badsound == '*' || *goodsound == '*') && *badsound != *goodsound) {
if ((badsound[0] == NUL && goodsound[1] == NUL)
- || (goodsound[0] == NUL && badsound[1] == NUL))
+ || (goodsound[0] == NUL && badsound[1] == NUL)) {
// changing word with vowel to word without a sound
return SCORE_DEL;
- if (badsound[0] == NUL || goodsound[0] == NUL)
+ }
+ if (badsound[0] == NUL || goodsound[0] == NUL) {
// more than two changes
return SCORE_MAXMAX;
+ }
if (badsound[1] == goodsound[1]
|| (badsound[1] != NUL
@@ -6199,10 +6383,11 @@ soundalike_score (
// handle like a substitute
} else {
score = 2 * SCORE_DEL / 3;
- if (*badsound == '*')
+ if (*badsound == '*') {
++badsound;
- else
+ } else {
++goodsound;
+ }
}
}
@@ -6212,8 +6397,9 @@ soundalike_score (
// Return quickly if the lengths are too different to be fixed by two
// changes.
n = goodlen - badlen;
- if (n < -2 || n > 2)
+ if (n < -2 || n > 2) {
return SCORE_MAXMAX;
+ }
if (n > 0) {
pl = goodsound; // goodsound is longest
@@ -6239,8 +6425,9 @@ soundalike_score (
++ps;
}
// strings must be equal after second delete
- if (STRCMP(pl + 1, ps) == 0)
+ if (STRCMP(pl + 1, ps) == 0) {
return score + SCORE_DEL * 2;
+ }
// Failed to compare.
break;
@@ -6253,20 +6440,23 @@ soundalike_score (
pl2 = pl + 1;
ps2 = ps;
while (*pl2 == *ps2) {
- if (*pl2 == NUL) // reached the end
+ if (*pl2 == NUL) { // reached the end
return score + SCORE_DEL;
+ }
++pl2;
++ps2;
}
// 2: delete then swap, then rest must be equal
if (pl2[0] == ps2[1] && pl2[1] == ps2[0]
- && STRCMP(pl2 + 2, ps2 + 2) == 0)
+ && STRCMP(pl2 + 2, ps2 + 2) == 0) {
return score + SCORE_DEL + SCORE_SWAP;
+ }
// 3: delete then substitute, then the rest must be equal
- if (STRCMP(pl2 + 1, ps2 + 1) == 0)
+ if (STRCMP(pl2 + 1, ps2 + 1) == 0) {
return score + SCORE_DEL + SCORE_SUBST;
+ }
// 4: first swap then delete
if (pl[0] == ps[1] && pl[1] == ps[0]) {
@@ -6277,8 +6467,9 @@ soundalike_score (
++ps2;
}
// delete a char and then strings must be equal
- if (STRCMP(pl2 + 1, ps2) == 0)
+ if (STRCMP(pl2 + 1, ps2) == 0) {
return score + SCORE_SWAP + SCORE_DEL;
+ }
}
// 5: first substitute then delete
@@ -6289,8 +6480,9 @@ soundalike_score (
++ps2;
}
// delete a char and then strings must be equal
- if (STRCMP(pl2 + 1, ps2) == 0)
+ if (STRCMP(pl2 + 1, ps2) == 0) {
return score + SCORE_SUBST + SCORE_DEL;
+ }
// Failed to compare.
break;
@@ -6299,47 +6491,54 @@ soundalike_score (
// Lengths are equal, thus changes must result in same length: An
// insert is only possible in combination with a delete.
// 1: check if for identical strings
- if (*pl == NUL)
+ if (*pl == NUL) {
return score;
+ }
// 2: swap
if (pl[0] == ps[1] && pl[1] == ps[0]) {
pl2 = pl + 2; // swap, skip two chars
ps2 = ps + 2;
while (*pl2 == *ps2) {
- if (*pl2 == NUL) // reached the end
+ if (*pl2 == NUL) { // reached the end
return score + SCORE_SWAP;
+ }
++pl2;
++ps2;
}
// 3: swap and swap again
if (pl2[0] == ps2[1] && pl2[1] == ps2[0]
- && STRCMP(pl2 + 2, ps2 + 2) == 0)
+ && STRCMP(pl2 + 2, ps2 + 2) == 0) {
return score + SCORE_SWAP + SCORE_SWAP;
+ }
// 4: swap and substitute
- if (STRCMP(pl2 + 1, ps2 + 1) == 0)
+ if (STRCMP(pl2 + 1, ps2 + 1) == 0) {
return score + SCORE_SWAP + SCORE_SUBST;
+ }
}
// 5: substitute
pl2 = pl + 1;
ps2 = ps + 1;
while (*pl2 == *ps2) {
- if (*pl2 == NUL) // reached the end
+ if (*pl2 == NUL) { // reached the end
return score + SCORE_SUBST;
+ }
++pl2;
++ps2;
}
// 6: substitute and swap
if (pl2[0] == ps2[1] && pl2[1] == ps2[0]
- && STRCMP(pl2 + 2, ps2 + 2) == 0)
+ && STRCMP(pl2 + 2, ps2 + 2) == 0) {
return score + SCORE_SUBST + SCORE_SWAP;
+ }
// 7: substitute and substitute
- if (STRCMP(pl2 + 1, ps2 + 1) == 0)
+ if (STRCMP(pl2 + 1, ps2 + 1) == 0) {
return score + SCORE_SUBST + SCORE_SUBST;
+ }
// 8: insert then delete
pl2 = pl;
@@ -6348,8 +6547,9 @@ soundalike_score (
++pl2;
++ps2;
}
- if (STRCMP(pl2 + 1, ps2) == 0)
+ if (STRCMP(pl2 + 1, ps2) == 0) {
return score + SCORE_INS + SCORE_DEL;
+ }
// 9: delete then insert
pl2 = pl + 1;
@@ -6358,8 +6558,9 @@ soundalike_score (
++pl2;
++ps2;
}
- if (STRCMP(pl2, ps2 + 1) == 0)
+ if (STRCMP(pl2, ps2 + 1) == 0) {
return score + SCORE_INS + SCORE_DEL;
+ }
// Failed to compare.
break;
@@ -6408,8 +6609,9 @@ static int spell_edit_score(slang_T *slang, char_u *badword, char_u *goodword)
cnt = xmalloc(sizeof(int) * (badlen + 1) * (goodlen + 1));
CNT(0, 0) = 0;
- for (j = 1; j <= goodlen; ++j)
+ for (j = 1; j <= goodlen; ++j) {
CNT(0, j) = CNT(0, j - 1) + SCORE_INS;
+ }
for (i = 1; i <= badlen; ++i) {
CNT(i, 0) = CNT(i - 1, 0) + SCORE_DEL;
@@ -6420,16 +6622,17 @@ static int spell_edit_score(slang_T *slang, char_u *badword, char_u *goodword)
CNT(i, j) = CNT(i - 1, j - 1);
} else {
// Use a better score when there is only a case difference.
- if (SPELL_TOFOLD(bc) == SPELL_TOFOLD(gc))
+ if (SPELL_TOFOLD(bc) == SPELL_TOFOLD(gc)) {
CNT(i, j) = SCORE_ICASE + CNT(i - 1, j - 1);
- else {
+ } else {
// For a similar character use SCORE_SIMILAR.
if (slang != NULL
&& slang->sl_has_map
- && similar_chars(slang, gc, bc))
+ && similar_chars(slang, gc, bc)) {
CNT(i, j) = SCORE_SIMILAR + CNT(i - 1, j - 1);
- else
+ } else {
CNT(i, j) = SCORE_SUBST + CNT(i - 1, j - 1);
+ }
}
if (i > 1 && j > 1) {
@@ -6437,16 +6640,19 @@ static int spell_edit_score(slang_T *slang, char_u *badword, char_u *goodword)
pgc = wgoodword[j - 2];
if (bc == pgc && pbc == gc) {
t = SCORE_SWAP + CNT(i - 2, j - 2);
- if (t < CNT(i, j))
+ if (t < CNT(i, j)) {
CNT(i, j) = t;
+ }
}
}
t = SCORE_DEL + CNT(i - 1, j);
- if (t < CNT(i, j))
+ if (t < CNT(i, j)) {
CNT(i, j) = t;
+ }
t = SCORE_INS + CNT(i, j - 1);
- if (t < CNT(i, j))
+ if (t < CNT(i, j)) {
CNT(i, j) = t;
+ }
}
}
}
@@ -6515,11 +6721,13 @@ static int spell_edit_score_limit_w(slang_T *slang, char_u *badword, char_u *goo
bc = wbadword[bi];
gc = wgoodword[gi];
- if (bc != gc) // stop at a char that's different
+ if (bc != gc) { // stop at a char that's different
break;
+ }
if (bc == NUL) { // both words end
- if (score < minscore)
+ if (score < minscore) {
minscore = score;
+ }
goto pop; // do next alternative
}
++bi;
@@ -6528,14 +6736,16 @@ static int spell_edit_score_limit_w(slang_T *slang, char_u *badword, char_u *goo
if (gc == NUL) { // goodword ends, delete badword chars
do {
- if ((score += SCORE_DEL) >= minscore)
+ if ((score += SCORE_DEL) >= minscore) {
goto pop; // do next alternative
+ }
} while (wbadword[++bi] != NUL);
minscore = score;
- } else if (bc == NUL) { // badword ends, insert badword chars
+ } else if (bc == NUL) { // badword ends, insert badword chars
do {
- if ((score += SCORE_INS) >= minscore)
+ if ((score += SCORE_INS) >= minscore) {
goto pop; // do next alternative
+ }
} while (wgoodword[++gi] != NUL);
minscore = score;
} else { // both words continue
@@ -6586,16 +6796,17 @@ static int spell_edit_score_limit_w(slang_T *slang, char_u *badword, char_u *goo
// Substitute one character for another which is the same
// thing as deleting a character from both goodword and badword.
// Use a better score when there is only a case difference.
- if (SPELL_TOFOLD(bc) == SPELL_TOFOLD(gc))
+ if (SPELL_TOFOLD(bc) == SPELL_TOFOLD(gc)) {
score += SCORE_ICASE;
- else {
+ } else {
// For a similar character use SCORE_SIMILAR.
if (slang != NULL
&& slang->sl_has_map
- && similar_chars(slang, gc, bc))
+ && similar_chars(slang, gc, bc)) {
score += SCORE_SIMILAR;
- else
+ } else {
score += SCORE_SUBST;
+ }
}
if (score < minscore) {
@@ -6607,8 +6818,9 @@ static int spell_edit_score_limit_w(slang_T *slang, char_u *badword, char_u *goo
}
pop:
// Get here to try the next alternative, pop it from the stack.
- if (stackidx == 0) // stack is empty, finished
+ if (stackidx == 0) { // stack is empty, finished
break;
+ }
// pop an item from the stack
--stackidx;
@@ -6620,8 +6832,9 @@ pop:
// When the score goes over "limit" it may actually be much higher.
// Return a very large number to avoid going below the limit when giving a
// bonus.
- if (minscore > limit)
+ if (minscore > limit) {
return SCORE_MAXMAX;
+ }
return minscore;
}
@@ -6656,7 +6869,7 @@ void ex_spellinfo(exarg_T *eap)
// ":spelldump"
void ex_spelldump(exarg_T *eap)
{
- char_u *spl;
+ char_u *spl;
long dummy;
if (no_spell_checking(curwin)) {
@@ -6672,7 +6885,7 @@ void ex_spelldump(exarg_T *eap)
set_option_value("spl", dummy, (char *)spl, OPT_LOCAL);
xfree(spl);
- if (!BUFEMPTY()) {
+ if (!buf_is_empty(curbuf)) {
return;
}
@@ -6685,50 +6898,49 @@ void ex_spelldump(exarg_T *eap)
redraw_later(curwin, NOT_VALID);
}
-// Go through all possible words and:
-// 1. When "pat" is NULL: dump a list of all words in the current buffer.
-// "ic" and "dir" are not used.
-// 2. When "pat" is not NULL: add matching words to insert mode completion.
-void
-spell_dump_compl (
- char_u *pat, // leading part of the word
- int ic, // ignore case
- Direction *dir, // direction for adding matches
- int dumpflags_arg // DUMPFLAG_*
-)
+/// Go through all possible words and:
+/// 1. When "pat" is NULL: dump a list of all words in the current buffer.
+/// "ic" and "dir" are not used.
+/// 2. When "pat" is not NULL: add matching words to insert mode completion.
+///
+/// @param pat leading part of the word
+/// @param ic ignore case
+/// @param dir direction for adding matches
+/// @param dumpflags_arg DUMPFLAG_*
+void spell_dump_compl(char_u *pat, int ic, Direction *dir, int dumpflags_arg)
{
- langp_T *lp;
- slang_T *slang;
+ langp_T *lp;
+ slang_T *slang;
idx_T arridx[MAXWLEN];
int curi[MAXWLEN];
char_u word[MAXWLEN];
int c;
- char_u *byts;
- idx_T *idxs;
+ char_u *byts;
+ idx_T *idxs;
linenr_T lnum = 0;
int round;
int depth;
int n;
int flags;
- char_u *region_names = NULL; // region names being used
+ char_u *region_names = NULL; // region names being used
bool do_region = true; // dump region names and numbers
- char_u *p;
+ char_u *p;
int dumpflags = dumpflags_arg;
int patlen;
// When ignoring case or when the pattern starts with capital pass this on
// to dump_word().
if (pat != NULL) {
- if (ic)
+ if (ic) {
dumpflags |= DUMPFLAG_ICASE;
- else {
+ } else {
n = captype(pat, NULL);
- if (n == WF_ONECAP)
+ if (n == WF_ONECAP) {
dumpflags |= DUMPFLAG_ONECAP;
- else if (n == WF_ALLCAP
- && (int)STRLEN(pat) > mb_ptr2len(pat)
- )
+ } else if (n == WF_ALLCAP
+ && (int)STRLEN(pat) > mb_ptr2len(pat)) {
dumpflags |= DUMPFLAG_ALLCAP;
+ }
}
}
@@ -6738,9 +6950,9 @@ spell_dump_compl (
lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
p = lp->lp_slang->sl_regions;
if (p[0] != 0) {
- if (region_names == NULL) // first language with regions
+ if (region_names == NULL) { // first language with regions
region_names = p;
- else if (STRCMP(region_names, p) != 0) {
+ } else if (STRCMP(region_names, p) != 0) {
do_region = false; // region names are different
break;
}
@@ -6752,15 +6964,17 @@ spell_dump_compl (
vim_snprintf((char *)IObuff, IOSIZE, "/regions=%s", region_names);
ml_append(lnum++, IObuff, (colnr_T)0, false);
}
- } else
+ } else {
do_region = false;
+ }
// Loop over all files loaded for the entries in 'spelllang'.
for (int lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi) {
lp = LANGP_ENTRY(curwin->w_s->b_langp, lpi);
slang = lp->lp_slang;
- if (slang->sl_fbyts == NULL) // reloading failed
+ if (slang->sl_fbyts == NULL) { // reloading failed
continue;
+ }
if (pat == NULL) {
vim_snprintf((char *)IObuff, IOSIZE, "# file: %s", slang->sl_fname);
@@ -6769,10 +6983,11 @@ spell_dump_compl (
// When matching with a pattern and there are no prefixes only use
// parts of the tree that match "pat".
- if (pat != NULL && slang->sl_pbyts == NULL)
+ if (pat != NULL && slang->sl_pbyts == NULL) {
patlen = (int)STRLEN(pat);
- else
+ } else {
patlen = -1;
+ }
// round 1: case-folded tree
// round 2: keep-case tree
@@ -6786,9 +7001,9 @@ spell_dump_compl (
byts = slang->sl_kbyts;
idxs = slang->sl_kidxs;
}
- if (byts == NULL)
+ if (byts == NULL) {
continue; // array is empty
-
+ }
depth = 0;
arridx[0] = 0;
curi[0] = 1;
@@ -6817,23 +7032,26 @@ spell_dump_compl (
|| (((unsigned)flags >> 16)
& lp->lp_region) != 0)) {
word[depth] = NUL;
- if (!do_region)
+ if (!do_region) {
flags &= ~WF_REGION;
+ }
// Dump the basic word if there is no prefix or
// when it's the first one.
c = (unsigned)flags >> 24;
if (c == 0 || curi[depth] == 2) {
dump_word(slang, word, pat, dir,
- dumpflags, flags, lnum);
- if (pat == NULL)
+ dumpflags, flags, lnum);
+ if (pat == NULL) {
++lnum;
+ }
}
// Apply the prefix, if there is one.
- if (c != 0)
+ if (c != 0) {
lnum = dump_prefixes(slang, word, pat, dir,
- dumpflags, flags, lnum);
+ dumpflags, flags, lnum);
+ }
}
} else {
// Normal char, go one level deeper.
@@ -6849,8 +7067,9 @@ spell_dump_compl (
// ignore case...
assert(depth >= 0);
if (depth <= patlen
- && mb_strnicmp(word, pat, (size_t)depth) != 0)
+ && mb_strnicmp(word, pat, (size_t)depth) != 0) {
--depth;
+ }
}
}
}
@@ -6860,22 +7079,23 @@ spell_dump_compl (
// Dumps one word: apply case modifications and append a line to the buffer.
// When "lnum" is zero add insert mode completion.
-static void dump_word(slang_T *slang, char_u *word, char_u *pat,
- Direction *dir, int dumpflags, int wordflags,
- linenr_T lnum)
+static void dump_word(slang_T *slang, char_u *word, char_u *pat, Direction *dir, int dumpflags,
+ int wordflags, linenr_T lnum)
{
bool keepcap = false;
- char_u *p;
- char_u *tw;
+ char_u *p;
+ char_u *tw;
char_u cword[MAXWLEN];
char_u badword[MAXWLEN + 10];
int i;
int flags = wordflags;
- if (dumpflags & DUMPFLAG_ONECAP)
+ if (dumpflags & DUMPFLAG_ONECAP) {
flags |= WF_ONECAP;
- if (dumpflags & DUMPFLAG_ALLCAP)
+ }
+ if (dumpflags & DUMPFLAG_ALLCAP) {
flags |= WF_ALLCAP;
+ }
if ((dumpflags & DUMPFLAG_KEEPCASE) == 0 && (flags & WF_CAPMASK) != 0) {
// Need to fix case according to "flags".
@@ -6885,8 +7105,9 @@ static void dump_word(slang_T *slang, char_u *word, char_u *pat,
p = word;
if ((dumpflags & DUMPFLAG_KEEPCASE)
&& ((captype(word, NULL) & WF_KEEPCAP) == 0
- || (flags & WF_FIXCAP) != 0))
+ || (flags & WF_FIXCAP) != 0)) {
keepcap = true;
+ }
}
tw = p;
@@ -6917,13 +7138,13 @@ static void dump_word(slang_T *slang, char_u *word, char_u *pat,
}
if (dumpflags & DUMPFLAG_COUNT) {
- hashitem_T *hi;
+ hashitem_T *hi;
// Include the word count for ":spelldump!".
hi = hash_find(&slang->sl_wordcount, tw);
if (!HASHITEM_EMPTY(hi)) {
vim_snprintf((char *)IObuff, IOSIZE, "%s\t%d",
- tw, HI2WC(hi)->wc_count);
+ tw, HI2WC(hi)->wc_count);
p = IObuff;
}
}
@@ -6939,20 +7160,16 @@ static void dump_word(slang_T *slang, char_u *word, char_u *pat,
}
}
-// For ":spelldump": Find matching prefixes for "word". Prepend each to
-// "word" and append a line to the buffer.
-// When "lnum" is zero add insert mode completion.
-// Return the updated line number.
-static linenr_T
-dump_prefixes (
- slang_T *slang,
- char_u *word, // case-folded word
- char_u *pat,
- Direction *dir,
- int dumpflags,
- int flags, // flags with prefix ID
- linenr_T startlnum
-)
+/// For ":spelldump": Find matching prefixes for "word". Prepend each to
+/// "word" and append a line to the buffer.
+/// When "lnum" is zero add insert mode completion.
+///
+/// @param word case-folded word
+/// @param flags flags with prefix ID
+///
+/// @return the updated line number.
+static linenr_T dump_prefixes(slang_T *slang, char_u *word, char_u *pat, Direction *dir,
+ int dumpflags, int flags, linenr_T startlnum)
{
idx_T arridx[MAXWLEN];
int curi[MAXWLEN];
@@ -6960,8 +7177,8 @@ dump_prefixes (
char_u word_up[MAXWLEN];
bool has_word_up = false;
int c;
- char_u *byts;
- idx_T *idxs;
+ char_u *byts;
+ idx_T *idxs;
linenr_T lnum = startlnum;
int depth;
int n;
@@ -6998,19 +7215,22 @@ dump_prefixes (
c = byts[n];
if (c == 0) {
// End of prefix, find out how many IDs there are.
- for (i = 1; i < len; ++i)
- if (byts[n + i] != 0)
+ for (i = 1; i < len; ++i) {
+ if (byts[n + i] != 0) {
break;
+ }
+ }
curi[depth] += i - 1;
c = valid_word_prefix(i, n, flags, word, slang, false);
if (c != 0) {
STRLCPY(prefix + depth, word, MAXWLEN - depth);
dump_word(slang, prefix, pat, dir, dumpflags,
- (c & WF_RAREPFX) ? (flags | WF_RARE)
- : flags, lnum);
- if (lnum != 0)
+ (c & WF_RAREPFX) ? (flags | WF_RARE)
+ : flags, lnum);
+ if (lnum != 0) {
++lnum;
+ }
}
// Check for prefix that matches the word when the
@@ -7018,14 +7238,15 @@ dump_prefixes (
// a condition.
if (has_word_up) {
c = valid_word_prefix(i, n, flags, word_up, slang,
- true);
+ true);
if (c != 0) {
STRLCPY(prefix + depth, word_up, MAXWLEN - depth);
dump_word(slang, prefix, pat, dir, dumpflags,
- (c & WF_RAREPFX) ? (flags | WF_RARE)
- : flags, lnum);
- if (lnum != 0)
+ (c & WF_RAREPFX) ? (flags | WF_RARE)
+ : flags, lnum);
+ if (lnum != 0) {
++lnum;
+ }
}
}
} else {
@@ -7045,7 +7266,7 @@ dump_prefixes (
// Uses the spell-checking word characters.
char_u *spell_to_word_end(char_u *start, win_T *win)
{
- char_u *p = start;
+ char_u *p = start;
while (*p != NUL && spell_iswordp(p, win)) {
MB_PTR_ADV(p);
@@ -7060,8 +7281,8 @@ char_u *spell_to_word_end(char_u *start, win_T *win)
// Returns the column number of the word.
int spell_word_start(int startcol)
{
- char_u *line;
- char_u *p;
+ char_u *line;
+ char_u *p;
int col = 0;
if (no_spell_checking(curwin)) {
diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c
index 0597f392e7..772275df84 100644
--- a/src/nvim/spellfile.c
+++ b/src/nvim/spellfile.c
@@ -226,19 +226,17 @@
// stored as an offset to the previous number in as
// few bytes as possible, see offset2bytes())
-#include <stdio.h>
#include <stdint.h>
+#include <stdio.h>
#include <wctype.h>
-#include "nvim/vim.h"
-#include "nvim/spell_defs.h"
#include "nvim/ascii.h"
#include "nvim/buffer.h"
#include "nvim/charset.h"
#include "nvim/ex_cmds2.h"
#include "nvim/fileio.h"
-#include "nvim/memory.h"
#include "nvim/memline.h"
+#include "nvim/memory.h"
#include "nvim/misc1.h"
#include "nvim/option.h"
#include "nvim/os/os.h"
@@ -246,9 +244,11 @@
#include "nvim/regexp.h"
#include "nvim/screen.h"
#include "nvim/spell.h"
+#include "nvim/spell_defs.h"
#include "nvim/spellfile.h"
#include "nvim/ui.h"
#include "nvim/undo.h"
+#include "nvim/vim.h"
#ifndef UNIX // it's in os/unix_defs.h for Unix
# include <time.h> // for time_t
@@ -310,7 +310,7 @@ static char *msg_compressing = N_("Compressing word tree...");
// and .dic file.
// Main structure to store the contents of a ".aff" file.
typedef struct afffile_S {
- char_u *af_enc; // "SET", normalized, alloc'ed string or NULL
+ char_u *af_enc; // "SET", normalized, alloc'ed string or NULL
int af_flagtype; // AFT_CHAR, AFT_LONG, AFT_NUM or AFT_CAPLONG
unsigned af_rare; // RARE ID for rare word
unsigned af_keepcase; // KEEPCASE ID for keep-case word
@@ -338,17 +338,17 @@ typedef struct afffile_S {
typedef struct affentry_S affentry_T;
// Affix entry from ".aff" file. Used for prefixes and suffixes.
struct affentry_S {
- affentry_T *ae_next; // next affix with same name/number
- char_u *ae_chop; // text to chop off basic word (can be NULL)
- char_u *ae_add; // text to add to basic word (can be NULL)
- char_u *ae_flags; // flags on the affix (can be NULL)
- char_u *ae_cond; // condition (NULL for ".")
- regprog_T *ae_prog; // regexp program for ae_cond or NULL
+ affentry_T *ae_next; // next affix with same name/number
+ char_u *ae_chop; // text to chop off basic word (can be NULL)
+ char_u *ae_add; // text to add to basic word (can be NULL)
+ char_u *ae_flags; // flags on the affix (can be NULL)
+ char_u *ae_cond; // condition (NULL for ".")
+ regprog_T *ae_prog; // regexp program for ae_cond or NULL
char ae_compforbid; // COMPOUNDFORBIDFLAG found
char ae_comppermit; // COMPOUNDPERMITFLAG found
};
-# define AH_KEY_LEN 17 // 2 x 8 bytes + NUL
+#define AH_KEY_LEN 17 // 2 x 8 bytes + NUL
// Affix header from ".aff" file. Used for af_pref and af_suff.
typedef struct affheader_S {
@@ -357,7 +357,7 @@ typedef struct affheader_S {
int ah_newID; // prefix ID after renumbering; 0 if not used
int ah_combine; // suffix may combine with prefix
int ah_follows; // another affix block should be following
- affentry_T *ah_first; // first affix entry
+ affentry_T *ah_first; // first affix entry
} affheader_T;
#define HI2AH(hi) ((affheader_T *)(hi)->hi_key)
@@ -381,7 +381,7 @@ typedef struct compitem_S {
typedef struct sblock_S sblock_T;
struct sblock_S {
int sb_used; // nr of bytes already in use
- sblock_T *sb_next; // next block in list
+ sblock_T *sb_next; // next block in list
char_u sb_data[1]; // data, actually longer
};
@@ -397,9 +397,9 @@ struct wordnode_S {
wordnode_T *next; // next node with same hash key
wordnode_T *wnode; // parent node that will write this node
} wn_u2;
- wordnode_T *wn_child; // child (next byte in word)
- wordnode_T *wn_sibling; // next sibling (alternate byte in word,
- // always sorted)
+ wordnode_T *wn_child; // child (next byte in word)
+ wordnode_T *wn_sibling; // next sibling (alternate byte in word,
+ // always sorted)
int wn_refs; // Nr. of references to this node. Only
// relevant for first node in a list of
// siblings, in following siblings it is
@@ -425,29 +425,29 @@ struct wordnode_S {
// Info used while reading the spell files.
typedef struct spellinfo_S {
- wordnode_T *si_foldroot; // tree with case-folded words
+ wordnode_T *si_foldroot; // tree with case-folded words
long si_foldwcount; // nr of words in si_foldroot
- wordnode_T *si_keeproot; // tree with keep-case words
+ wordnode_T *si_keeproot; // tree with keep-case words
long si_keepwcount; // nr of words in si_keeproot
- wordnode_T *si_prefroot; // tree with postponed prefixes
+ wordnode_T *si_prefroot; // tree with postponed prefixes
long si_sugtree; // creating the soundfolding trie
- sblock_T *si_blocks; // memory blocks used
+ sblock_T *si_blocks; // memory blocks used
long si_blocks_cnt; // memory blocks allocated
int si_did_emsg; // TRUE when ran out of memory
long si_compress_cnt; // words to add before lowering
// compression limit
- wordnode_T *si_first_free; // List of nodes that have been freed during
- // compression, linked by "wn_child" field.
+ wordnode_T *si_first_free; // List of nodes that have been freed during
+ // compression, linked by "wn_child" field.
long si_free_count; // number of nodes in si_first_free
#ifdef SPELL_PRINTTREE
int si_wordnode_nr; // sequence nr for nodes
#endif
- buf_T *si_spellbuf; // buffer used to store soundfold word table
+ buf_T *si_spellbuf; // buffer used to store soundfold word table
int si_ascii; // handling only ASCII words
int si_add; // addition file
@@ -457,18 +457,18 @@ typedef struct spellinfo_S {
int si_memtot; // runtime memory used
int si_verbose; // verbose messages
int si_msg_count; // number of words added since last message
- char_u *si_info; // info text chars or NULL
+ char_u *si_info; // info text chars or NULL
int si_region_count; // number of regions supported (1 when there
// are no regions)
char_u si_region_name[MAXREGIONS * 2 + 1];
- // region names; used only if
- // si_region_count > 1)
+ // region names; used only if
+ // si_region_count > 1)
garray_T si_rep; // list of fromto_T entries from REP lines
garray_T si_repsal; // list of fromto_T entries from REPSAL lines
garray_T si_sal; // list of fromto_T entries from SAL lines
- char_u *si_sofofr; // SOFOFROM text
- char_u *si_sofoto; // SOFOTO text
+ char_u *si_sofofr; // SOFOFROM text
+ char_u *si_sofoto; // SOFOTO text
int si_nosugfile; // NOSUGFILE item found
int si_nosplitsugs; // NOSPLITSUGS item found
int si_nocompoundsugs; // NOCOMPOUNDSUGS item found
@@ -478,16 +478,16 @@ typedef struct spellinfo_S {
time_t si_sugtime; // timestamp for .sug file
int si_rem_accents; // soundsalike: remove accents
garray_T si_map; // MAP info concatenated
- char_u *si_midword; // MIDWORD chars or NULL
+ char_u *si_midword; // MIDWORD chars or NULL
int si_compmax; // max nr of words for compounding
int si_compminlen; // minimal length for compounding
int si_compsylmax; // max nr of syllables for compounding
int si_compoptions; // COMP_ flags
garray_T si_comppat; // CHECKCOMPOUNDPATTERN items, each stored as
// a string
- char_u *si_compflags; // flags used for compounding
+ char_u *si_compflags; // flags used for compounding
char_u si_nobreak; // NOBREAK
- char_u *si_syllable; // syllable string
+ char_u *si_syllable; // syllable string
garray_T si_prefcond; // table with conditions for postponed
// prefixes, each stored as a string
int si_newprefID; // current value for ah_newID
@@ -508,16 +508,16 @@ typedef struct spellinfo_S {
/// @return Allows to proceed if everything is OK, returns SP_TRUNCERROR if
/// there are not enough bytes, returns SP_OTHERERROR if reading failed.
#define SPELL_READ_BYTES(buf, n, fd, exit_code) \
- do { \
- const size_t n__SPRB = (n); \
- FILE *const fd__SPRB = (fd); \
- char *const buf__SPRB = (buf); \
- const size_t read_bytes__SPRB = fread(buf__SPRB, 1, n__SPRB, fd__SPRB); \
- if (read_bytes__SPRB != n__SPRB) { \
- exit_code; \
- return feof(fd__SPRB) ? SP_TRUNCERROR : SP_OTHERERROR; \
- } \
- } while (0)
+ do { \
+ const size_t n__SPRB = (n); \
+ FILE *const fd__SPRB = (fd); \
+ char *const buf__SPRB = (buf); \
+ const size_t read_bytes__SPRB = fread(buf__SPRB, 1, n__SPRB, fd__SPRB); \
+ if (read_bytes__SPRB != n__SPRB) { \
+ exit_code; \
+ return feof(fd__SPRB) ? SP_TRUNCERROR : SP_OTHERERROR; \
+ } \
+ } while (0)
/// Like #SPELL_READ_BYTES, but also error out if NUL byte was read
///
@@ -525,16 +525,16 @@ typedef struct spellinfo_S {
/// there are not enough bytes, returns SP_OTHERERROR if reading failed,
/// returns SP_FORMERROR if read out a NUL byte.
#define SPELL_READ_NONNUL_BYTES(buf, n, fd, exit_code) \
- do { \
- const size_t n__SPRNB = (n); \
- FILE *const fd__SPRNB = (fd); \
- char *const buf__SPRNB = (buf); \
- SPELL_READ_BYTES(buf__SPRNB, n__SPRNB, fd__SPRNB, exit_code); \
- if (memchr(buf__SPRNB, NUL, (size_t)n__SPRNB)) { \
- exit_code; \
- return SP_FORMERROR; \
- } \
- } while (0)
+ do { \
+ const size_t n__SPRNB = (n); \
+ FILE *const fd__SPRNB = (fd); \
+ char *const buf__SPRNB = (buf); \
+ SPELL_READ_BYTES(buf__SPRNB, n__SPRNB, fd__SPRNB, exit_code); \
+ if (memchr(buf__SPRNB, NUL, (size_t)n__SPRNB)) { \
+ exit_code; \
+ return SP_FORMERROR; \
+ } \
+ } while (0)
/// Check that spell file starts with a magic string
///
@@ -556,40 +556,36 @@ static inline int spell_check_magic_string(FILE *const fd)
return 0;
}
-// Load one spell file and store the info into a slang_T.
-//
-// This is invoked in three ways:
-// - From spell_load_cb() to load a spell file for the first time. "lang" is
-// the language name, "old_lp" is NULL. Will allocate an slang_T.
-// - To reload a spell file that was changed. "lang" is NULL and "old_lp"
-// points to the existing slang_T.
-// - Just after writing a .spl file; it's read back to produce the .sug file.
-// "old_lp" is NULL and "lang" is NULL. Will allocate an slang_T.
-//
-// Returns the slang_T the spell file was loaded into. NULL for error.
-slang_T *
-spell_load_file (
- char_u *fname,
- char_u *lang,
- slang_T *old_lp,
- bool silent // no error if file doesn't exist
-)
+/// Load one spell file and store the info into a slang_T.
+///
+/// This is invoked in three ways:
+/// - From spell_load_cb() to load a spell file for the first time. "lang" is
+/// the language name, "old_lp" is NULL. Will allocate an slang_T.
+/// - To reload a spell file that was changed. "lang" is NULL and "old_lp"
+/// points to the existing slang_T.
+/// - Just after writing a .spl file; it's read back to produce the .sug file.
+/// "old_lp" is NULL and "lang" is NULL. Will allocate an slang_T.
+///
+/// @param silent no error if file doesn't exist
+///
+/// @return the slang_T the spell file was loaded into. NULL for error.
+slang_T *spell_load_file(char_u *fname, char_u *lang, slang_T *old_lp, bool silent)
{
- FILE *fd;
- char_u *p;
+ FILE *fd;
+ char_u *p;
int n;
int len;
- char_u *save_sourcing_name = sourcing_name;
+ char_u *save_sourcing_name = sourcing_name;
linenr_T save_sourcing_lnum = sourcing_lnum;
- slang_T *lp = NULL;
+ slang_T *lp = NULL;
int c = 0;
int res;
fd = os_fopen((char *)fname, "r");
if (fd == NULL) {
- if (!silent)
+ if (!silent) {
EMSG2(_(e_notopen), fname);
- else if (p_verbose > 2) {
+ } else if (p_verbose > 2) {
verbose_enter();
smsg((char *)e_notopen, fname);
verbose_leave();
@@ -610,8 +606,9 @@ spell_load_file (
// Check for .add.spl.
lp->sl_add = strstr((char *)path_tail(fname), SPL_FNAME_ADD) != NULL;
- } else
+ } else {
lp = old_lp;
+ }
// Set sourcing_name, so that error messages mention the file name.
sourcing_name = fname;
@@ -620,19 +617,16 @@ spell_load_file (
// <HEADER>: <fileID>
const int scms_ret = spell_check_magic_string(fd);
switch (scms_ret) {
- case SP_FORMERROR:
- case SP_TRUNCERROR: {
- emsgf("%s", _("E757: This does not look like a spell file"));
- goto endFAIL;
- }
- case SP_OTHERERROR: {
- emsgf(_("E5042: Failed to read spell file %s: %s"),
- fname, strerror(ferror(fd)));
- goto endFAIL;
- }
- case 0: {
- break;
- }
+ case SP_FORMERROR:
+ case SP_TRUNCERROR:
+ emsgf("%s", _("E757: This does not look like a spell file"));
+ goto endFAIL;
+ case SP_OTHERERROR:
+ emsgf(_("E5042: Failed to read spell file %s: %s"),
+ fname, strerror(ferror(fd)));
+ goto endFAIL;
+ case 0:
+ break;
}
c = getc(fd); // <versionnr>
if (c < VIMSPELLVERSION) {
@@ -648,19 +642,22 @@ spell_load_file (
// <section>: <sectionID> <sectionflags> <sectionlen> (section contents)
for (;; ) {
n = getc(fd); // <sectionID> or <sectionend>
- if (n == SN_END)
+ if (n == SN_END) {
break;
+ }
c = getc(fd); // <sectionflags>
len = get4c(fd); // <sectionlen>
- if (len < 0)
+ if (len < 0) {
goto truncerr;
+ }
res = 0;
switch (n) {
case SN_INFO:
lp->sl_info = READ_STRING(fd, len); // <infotext>
- if (lp->sl_info == NULL)
+ if (lp->sl_info == NULL) {
goto endFAIL;
+ }
break;
case SN_REGION:
@@ -673,8 +670,9 @@ spell_load_file (
case SN_MIDWORD:
lp->sl_midword = READ_STRING(fd, len); // <midword>
- if (lp->sl_midword == NULL)
+ if (lp->sl_midword == NULL) {
goto endFAIL;
+ }
break;
case SN_PREFCOND:
@@ -699,8 +697,9 @@ spell_load_file (
case SN_MAP:
p = READ_STRING(fd, len); // <mapstr>
- if (p == NULL)
+ if (p == NULL) {
goto endFAIL;
+ }
set_map_str(lp, p);
xfree(p);
break;
@@ -731,10 +730,12 @@ spell_load_file (
case SN_SYLLABLE:
lp->sl_syllable = READ_STRING(fd, len); // <syllable>
- if (lp->sl_syllable == NULL)
+ if (lp->sl_syllable == NULL) {
goto endFAIL;
- if (init_syl_tab(lp) == FAIL)
+ }
+ if (init_syl_tab(lp) == FAIL) {
goto endFAIL;
+ }
break;
default:
@@ -744,9 +745,11 @@ spell_load_file (
EMSG(_("E770: Unsupported section in spell file"));
goto endFAIL;
}
- while (--len >= 0)
- if (getc(fd) < 0)
+ while (--len >= 0) {
+ if (getc(fd) < 0) {
goto truncerr;
+ }
+ }
break;
}
someerror:
@@ -759,8 +762,9 @@ truncerr:
EMSG(_(e_spell_trunc));
goto endFAIL;
}
- if (res == SP_OTHERERROR)
+ if (res == SP_OTHERERROR) {
goto endFAIL;
+ }
}
// <LWORDTREE>
@@ -792,16 +796,19 @@ truncerr:
goto endOK;
endFAIL:
- if (lang != NULL)
+ if (lang != NULL) {
// truncating the name signals the error to spell_load_lang()
*lang = NUL;
- if (lp != NULL && old_lp == NULL)
+ }
+ if (lp != NULL && old_lp == NULL) {
slang_free(lp);
+ }
lp = NULL;
endOK:
- if (fd != NULL)
+ if (fd != NULL) {
fclose(fd);
+ }
sourcing_name = save_sourcing_name;
sourcing_lnum = save_sourcing_lnum;
@@ -827,8 +834,9 @@ static void tree_count_words(char_u *byts, idx_T *idxs)
if (curi[depth] > byts[arridx[depth]]) {
// Done all bytes at this node, go up one level.
idxs[arridx[depth]] = wordcount[depth];
- if (depth > 0)
+ if (depth > 0) {
wordcount[depth - 1] += wordcount[depth];
+ }
--depth;
fast_breakcheck();
@@ -862,10 +870,10 @@ static void tree_count_words(char_u *byts, idx_T *idxs)
// Load the .sug files for languages that have one and weren't loaded yet.
void suggest_load_files(void)
{
- langp_T *lp;
- slang_T *slang;
- char_u *dotp;
- FILE *fd;
+ langp_T *lp;
+ slang_T *slang;
+ char_u *dotp;
+ FILE *fd;
char_u buf[MAXWLEN];
int i;
time_t timestamp;
@@ -895,21 +903,22 @@ void suggest_load_files(void)
}
// <SUGHEADER>: <fileID> <versionnr> <timestamp>
- for (i = 0; i < VIMSUGMAGICL; ++i)
+ for (i = 0; i < VIMSUGMAGICL; ++i) {
buf[i] = getc(fd); // <fileID>
+ }
if (STRNCMP(buf, VIMSUGMAGIC, VIMSUGMAGICL) != 0) {
EMSG2(_("E778: This does not look like a .sug file: %s"),
- slang->sl_fname);
+ slang->sl_fname);
goto nextone;
}
c = getc(fd); // <versionnr>
if (c < VIMSUGVERSION) {
EMSG2(_("E779: Old .sug file, needs to be updated: %s"),
- slang->sl_fname);
+ slang->sl_fname);
goto nextone;
- } else if (c > VIMSUGVERSION) {
+ } else if (c > VIMSUGVERSION) {
EMSG2(_("E780: .sug file is for newer version of Vim: %s"),
- slang->sl_fname);
+ slang->sl_fname);
goto nextone;
}
@@ -918,7 +927,7 @@ void suggest_load_files(void)
timestamp = get8ctime(fd); // <timestamp>
if (timestamp != slang->sl_sugtime) {
EMSG2(_("E781: .sug file doesn't match .spl file: %s"),
- slang->sl_fname);
+ slang->sl_fname);
goto nextone;
}
@@ -928,7 +937,7 @@ void suggest_load_files(void)
false, 0) != 0) {
someerror:
EMSG2(_("E782: error while reading .sug file: %s"),
- slang->sl_fname);
+ slang->sl_fname);
slang_clear_sug(slang);
goto nextone;
}
@@ -942,8 +951,9 @@ someerror:
// <sugwcount>
wcount = get4c(fd);
- if (wcount < 0)
+ if (wcount < 0) {
goto someerror;
+ }
// Read all the wordnr lists into the buffer, one NUL terminated
// list per line.
@@ -956,8 +966,9 @@ someerror:
goto someerror;
}
GA_APPEND(char_u, &ga, c);
- if (c == NUL)
+ if (c == NUL) {
break;
+ }
}
if (ml_append_buf(slang->sl_sugbuf, (linenr_T)wordnr,
ga.ga_data, ga.ga_len, true) == FAIL) {
@@ -972,8 +983,9 @@ someerror:
tree_count_words(slang->sl_sbyts, slang->sl_sidxs);
nextone:
- if (fd != NULL)
+ if (fd != NULL) {
fclose(fd);
+ }
STRCPY(dotp, ".spl");
}
}
@@ -988,7 +1000,7 @@ nextone:
static char_u *read_cnt_string(FILE *fd, int cnt_bytes, int *cntp)
{
int cnt = 0;
- char_u *str;
+ char_u *str;
// read the length bytes, MSB first
for (int i = 0; i < cnt_bytes; i++) {
@@ -1001,12 +1013,13 @@ static char_u *read_cnt_string(FILE *fd, int cnt_bytes, int *cntp)
cnt = (cnt << 8) + (unsigned)c;
}
*cntp = cnt;
- if (cnt == 0)
+ if (cnt == 0) {
return NULL; // nothing to read, return NULL
-
+ }
str = READ_STRING(fd, cnt);
- if (str == NULL)
+ if (str == NULL) {
*cntp = SP_OTHERERROR;
+ }
return str;
}
@@ -1027,14 +1040,15 @@ static int read_region_section(FILE *fd, slang_T *lp, int len)
// Return SP_*ERROR flags.
static int read_charflags_section(FILE *fd)
{
- char_u *flags;
- char_u *fol;
+ char_u *flags;
+ char_u *fol;
int flagslen, follen;
// <charflagslen> <charflags>
flags = read_cnt_string(fd, 1, &flagslen);
- if (flagslen < 0)
+ if (flagslen < 0) {
return flagslen;
+ }
// <folcharslen> <folchars>
fol = read_cnt_string(fd, 2, &follen);
@@ -1044,15 +1058,17 @@ static int read_charflags_section(FILE *fd)
}
// Set the word-char flags and fill SPELL_ISUPPER() table.
- if (flags != NULL && fol != NULL)
+ if (flags != NULL && fol != NULL) {
set_spell_charflags(flags, flagslen, fol);
+ }
xfree(flags);
xfree(fol);
// When <charflagslen> is zero then <fcharlen> must also be zero.
- if ((flags == NULL) != (fol == NULL))
+ if ((flags == NULL) != (fol == NULL)) {
return SP_FORMERROR;
+ }
return 0;
}
@@ -1094,11 +1110,12 @@ static int read_prefcond_section(FILE *fd, slang_T *lp)
static int read_rep_section(FILE *fd, garray_T *gap, int16_t *first)
{
int cnt;
- fromto_T *ftp;
+ fromto_T *ftp;
cnt = get2c(fd); // <repcount>
- if (cnt < 0)
+ if (cnt < 0) {
return SP_TRUNCERROR;
+ }
ga_grow(gap, cnt);
@@ -1107,15 +1124,18 @@ static int read_rep_section(FILE *fd, garray_T *gap, int16_t *first)
int c;
ftp = &((fromto_T *)gap->ga_data)[gap->ga_len];
ftp->ft_from = read_cnt_string(fd, 1, &c);
- if (c < 0)
+ if (c < 0) {
return c;
- if (c == 0)
+ }
+ if (c == 0) {
return SP_FORMERROR;
+ }
ftp->ft_to = read_cnt_string(fd, 1, &c);
if (c <= 0) {
xfree(ftp->ft_from);
- if (c < 0)
+ if (c < 0) {
return c;
+ }
return SP_FORMERROR;
}
}
@@ -1126,8 +1146,9 @@ static int read_rep_section(FILE *fd, garray_T *gap, int16_t *first)
}
for (int i = 0; i < gap->ga_len; ++i) {
ftp = &((fromto_T *)gap->ga_data)[i];
- if (first[*ftp->ft_from] == -1)
+ if (first[*ftp->ft_from] == -1) {
first[*ftp->ft_from] = i;
+ }
}
return 0;
}
@@ -1137,10 +1158,10 @@ static int read_rep_section(FILE *fd, garray_T *gap, int16_t *first)
static int read_sal_section(FILE *fd, slang_T *slang)
{
int cnt;
- garray_T *gap;
- salitem_T *smp;
+ garray_T *gap;
+ salitem_T *smp;
int ccnt;
- char_u *p;
+ char_u *p;
slang->sl_sofo = false;
@@ -1156,8 +1177,9 @@ static int read_sal_section(FILE *fd, slang_T *slang)
}
cnt = get2c(fd); // <salcount>
- if (cnt < 0)
+ if (cnt < 0) {
return SP_TRUNCERROR;
+ }
gap = &slang->sl_sal;
ga_init(gap, sizeof(salitem_T), 10);
@@ -1169,8 +1191,9 @@ static int read_sal_section(FILE *fd, slang_T *slang)
smp = &((salitem_T *)gap->ga_data)[gap->ga_len];
ccnt = getc(fd); // <salfromlen>
- if (ccnt < 0)
+ if (ccnt < 0) {
return SP_TRUNCERROR;
+ }
p = xmalloc(ccnt + 2);
smp->sm_lead = p;
@@ -1178,8 +1201,9 @@ static int read_sal_section(FILE *fd, slang_T *slang)
int i = 0;
for (; i < ccnt; ++i) {
c = getc(fd); // <salfrom>
- if (vim_strchr((char_u *)"0123456789(-<^$", c) != NULL)
+ if (vim_strchr((char_u *)"0123456789(-<^$", c) != NULL) {
break;
+ }
*p++ = c;
}
smp->sm_leadlen = (int)(p - smp->sm_lead);
@@ -1190,15 +1214,18 @@ static int read_sal_section(FILE *fd, slang_T *slang)
smp->sm_oneof = p;
for (++i; i < ccnt; ++i) {
c = getc(fd); // <salfrom>
- if (c == ')')
+ if (c == ')') {
break;
+ }
*p++ = c;
}
*p++ = NUL;
- if (++i < ccnt)
+ if (++i < ccnt) {
c = getc(fd);
- } else
+ }
+ } else {
smp->sm_oneof = NULL;
+ }
// Any following chars go in sm_rules.
smp->sm_rules = p;
@@ -1209,7 +1236,8 @@ static int read_sal_section(FILE *fd, slang_T *slang)
i++;
if (i < ccnt) {
SPELL_READ_NONNUL_BYTES( // <salfrom>
- (char *)p, (size_t)(ccnt - i), fd, xfree(smp->sm_lead));
+ (char *)p, (size_t)(ccnt - i), fd,
+ xfree(smp->sm_lead));
p += (ccnt - i);
}
*p++ = NUL;
@@ -1272,13 +1300,16 @@ static int read_words_section(FILE *fd, slang_T *lp, int len)
// Read one word at a time.
for (i = 0;; ++i) {
c = getc(fd);
- if (c == EOF)
+ if (c == EOF) {
return SP_TRUNCERROR;
+ }
word[i] = c;
- if (word[i] == NUL)
+ if (word[i] == NUL) {
break;
- if (i == MAXWLEN - 1)
+ }
+ if (i == MAXWLEN - 1) {
return SP_FORMERROR;
+ }
}
// Init the count to 10.
@@ -1293,15 +1324,16 @@ static int read_words_section(FILE *fd, slang_T *lp, int len)
static int read_sofo_section(FILE *fd, slang_T *slang)
{
int cnt;
- char_u *from, *to;
+ char_u *from, *to;
int res;
slang->sl_sofo = true;
// <sofofromlen> <sofofrom>
from = read_cnt_string(fd, 2, &cnt);
- if (cnt < 0)
+ if (cnt < 0) {
return cnt;
+ }
// <sofotolen> <sofoto>
to = read_cnt_string(fd, 2, &cnt);
@@ -1311,12 +1343,13 @@ static int read_sofo_section(FILE *fd, slang_T *slang)
}
// Store the info in slang->sl_sal and/or slang->sl_sal_first.
- if (from != NULL && to != NULL)
+ if (from != NULL && to != NULL) {
res = set_sofo(slang, from, to);
- else if (from != NULL || to != NULL)
+ } else if (from != NULL || to != NULL) {
res = SP_FORMERROR; // only one of two strings is an error
- else
+ } else {
res = 0;
+ }
xfree(from);
xfree(to);
@@ -1331,39 +1364,42 @@ static int read_compound(FILE *fd, slang_T *slang, int len)
int todo = len;
int c;
int atstart;
- char_u *pat;
- char_u *pp;
- char_u *cp;
- char_u *ap;
- char_u *crp;
+ char_u *pat;
+ char_u *pp;
+ char_u *cp;
+ char_u *ap;
+ char_u *crp;
int cnt;
- garray_T *gap;
+ garray_T *gap;
- if (todo < 2)
+ if (todo < 2) {
return SP_FORMERROR; // need at least two bytes
-
+ }
--todo;
c = getc(fd); // <compmax>
- if (c < 2)
+ if (c < 2) {
c = MAXWLEN;
+ }
slang->sl_compmax = c;
--todo;
c = getc(fd); // <compminlen>
- if (c < 1)
+ if (c < 1) {
c = 0;
+ }
slang->sl_compminlen = c;
--todo;
c = getc(fd); // <compsylmax>
- if (c < 1)
+ if (c < 1) {
c = MAXWLEN;
+ }
slang->sl_compsylmax = c;
c = getc(fd); // <compoptions>
- if (c != 0)
+ if (c != 0) {
ungetc(c, fd); // be backwards compatible with Vim 7.0b
- else {
+ } else {
--todo;
c = getc(fd); // only use the lower byte for now
--todo;
@@ -1371,6 +1407,9 @@ static int read_compound(FILE *fd, slang_T *slang, int len)
gap = &slang->sl_comppat;
c = get2c(fd); // <comppatcount>
+ if (c < 0) {
+ return SP_TRUNCERROR;
+ }
todo -= 2;
ga_init(gap, sizeof(char_u *), c);
ga_grow(gap, c);
@@ -1378,13 +1417,15 @@ static int read_compound(FILE *fd, slang_T *slang, int len)
((char_u **)(gap->ga_data))[gap->ga_len++] =
read_cnt_string(fd, 1, &cnt);
// <comppatlen> <comppattext>
- if (cnt < 0)
+ if (cnt < 0) {
return cnt;
+ }
todo -= cnt + 1;
}
}
- if (todo < 0)
+ if (todo < 0) {
return SP_FORMERROR;
+ }
// Turn the COMPOUNDRULE items into a regexp pattern:
// "a[bc]/a*b+" -> "^\(a[bc]\|a*b\+\)$".
@@ -1433,17 +1474,18 @@ static int read_compound(FILE *fd, slang_T *slang, int len)
if (atstart != 0) {
// At start of item: copy flags to "sl_compstartflags". For a
// [abc] item set "atstart" to 2 and copy up to the ']'.
- if (c == '[')
+ if (c == '[') {
atstart = 2;
- else if (c == ']')
+ } else if (c == ']') {
atstart = 0;
- else {
+ } else {
if (!byte_in_str(slang->sl_compstartflags, c)) {
*cp++ = c;
*cp = NUL;
}
- if (atstart == 1)
+ if (atstart == 1) {
atstart = 0;
+ }
}
}
@@ -1452,8 +1494,9 @@ static int read_compound(FILE *fd, slang_T *slang, int len)
if (c == '?' || c == '+' || c == '*') {
XFREE_CLEAR(slang->sl_comprules);
crp = NULL;
- } else
+ } else {
*crp++ = c;
+ }
}
if (c == '/') { // slash separates two items
@@ -1473,13 +1516,15 @@ static int read_compound(FILE *fd, slang_T *slang, int len)
*pp++ = '$';
*pp = NUL;
- if (crp != NULL)
+ if (crp != NULL) {
*crp = NUL;
+ }
slang->sl_compprog = vim_regcomp(pat, RE_MAGIC + RE_STRING + RE_STRICT);
xfree(pat);
- if (slang->sl_compprog == NULL)
+ if (slang->sl_compprog == NULL) {
return SP_FORMERROR;
+ }
return 0;
}
@@ -1488,8 +1533,8 @@ static int read_compound(FILE *fd, slang_T *slang, int len)
// Returns SP_*ERROR flags when there is something wrong.
static int set_sofo(slang_T *lp, char_u *from, char_u *to)
{
- char_u *s;
- char_u *p;
+ char_u *s;
+ char_u *p;
// Use "sl_sal" as an array with 256 pointers to a list of wide
// characters. The index is the low byte of the character.
@@ -1551,10 +1596,10 @@ static int set_sofo(slang_T *lp, char_u *from, char_u *to)
// Fill the first-index table for "lp".
static void set_sal_first(slang_T *lp)
{
- salfirst_T *sfirst;
- salitem_T *smp;
+ salfirst_T *sfirst;
+ salitem_T *smp;
int c;
- garray_T *gap = &lp->sl_sal;
+ garray_T *gap = &lp->sl_sal;
sfirst = lp->sl_sal_first;
for (int i = 0; i < 256; ++i) {
@@ -1610,24 +1655,21 @@ static int *mb_str2wide(char_u *s)
return res;
}
-// Reads a tree from the .spl or .sug file.
-// Allocates the memory and stores pointers in "bytsp" and "idxsp".
-// This is skipped when the tree has zero length.
-// Returns zero when OK, SP_ value for an error.
-static int
-spell_read_tree (
- FILE *fd,
- char_u **bytsp,
- long *bytsp_len,
- idx_T **idxsp,
- bool prefixtree, // true for the prefix tree
- int prefixcnt // when "prefixtree" is true: prefix count
-)
+/// Reads a tree from the .spl or .sug file.
+/// Allocates the memory and stores pointers in "bytsp" and "idxsp".
+/// This is skipped when the tree has zero length.
+///
+/// @param prefixtree true for the prefix tree
+/// @param prefixcnt when "prefixtree" is true: prefix count
+///
+/// @return zero when OK, SP_ value for an error.
+static int spell_read_tree(FILE *fd, char_u **bytsp, long *bytsp_len, idx_T **idxsp,
+ bool prefixtree, int prefixcnt)
FUNC_ATTR_NONNULL_ARG(1, 2, 4)
{
int idx;
- char_u *bp;
- idx_T *ip;
+ char_u *bp;
+ idx_T *ip;
// The tree size was computed when writing the file, so that we can
// allocate it as one long block. <nodecount>
@@ -1653,30 +1695,28 @@ spell_read_tree (
// Recursively read the tree and store it in the array.
idx = read_tree_node(fd, bp, ip, len, 0, prefixtree, prefixcnt);
- if (idx < 0)
+ if (idx < 0) {
return idx;
+ }
}
return 0;
}
-// Read one row of siblings from the spell file and store it in the byte array
-// "byts" and index array "idxs". Recursively read the children.
-//
-// NOTE: The code here must match put_node()!
-//
-// Returns the index (>= 0) following the siblings.
-// Returns SP_TRUNCERROR if the file is shorter than expected.
-// Returns SP_FORMERROR if there is a format error.
-static idx_T
-read_tree_node (
- FILE *fd,
- char_u *byts,
- idx_T *idxs,
- int maxidx, // size of arrays
- idx_T startidx, // current index in "byts" and "idxs"
- bool prefixtree, // true for reading PREFIXTREE
- int maxprefcondnr // maximum for <prefcondnr>
-)
+/// Read one row of siblings from the spell file and store it in the byte array
+/// "byts" and index array "idxs". Recursively read the children.
+///
+/// NOTE: The code here must match put_node()!
+///
+/// Returns the index (>= 0) following the siblings.
+/// Returns SP_TRUNCERROR if the file is shorter than expected.
+/// Returns SP_FORMERROR if there is a format error.
+///
+/// @param maxidx size of arrays
+/// @param startidx current index in "byts" and "idxs"
+/// @param prefixtree true for reading PREFIXTREE
+/// @param maxprefcondnr maximum for <prefcondnr>
+static idx_T read_tree_node(FILE *fd, char_u *byts, idx_T *idxs, int maxidx, idx_T startidx,
+ bool prefixtree, int maxprefcondnr)
{
int len;
int i;
@@ -1687,18 +1727,21 @@ read_tree_node (
#define SHARED_MASK 0x8000000
len = getc(fd); // <siblingcount>
- if (len <= 0)
+ if (len <= 0) {
return SP_TRUNCERROR;
+ }
- if (startidx + len >= maxidx)
+ if (startidx + len >= maxidx) {
return SP_FORMERROR;
+ }
byts[idx++] = len;
// Read the byte values, flag/region bytes and shared indexes.
for (i = 1; i <= len; ++i) {
c = getc(fd); // <byte>
- if (c < 0)
+ if (c < 0) {
return SP_TRUNCERROR;
+ }
if (c <= BY_SPECIAL) {
if (c == BY_NOFLAGS && !prefixtree) {
// No flags, all regions.
@@ -1709,16 +1752,18 @@ read_tree_node (
// condition nr. In idxs[] store the prefix ID in the low
// byte, the condition index shifted up 8 bits, the flags
// shifted up 24 bits.
- if (c == BY_FLAGS)
+ if (c == BY_FLAGS) {
c = getc(fd) << 24; // <pflags>
- else
+ } else {
c = 0;
+ }
c |= getc(fd); // <affixID>
n = get2c(fd); // <prefcondnr>
- if (n >= maxprefcondnr)
+ if (n >= maxprefcondnr) {
return SP_FORMERROR;
+ }
c |= (n << 8);
} else { // c must be BY_FLAGS or BY_FLAGS2
// Read flags and optional region and prefix ID. In
@@ -1726,21 +1771,25 @@ read_tree_node (
// that and prefix ID above the region.
c2 = c;
c = getc(fd); // <flags>
- if (c2 == BY_FLAGS2)
+ if (c2 == BY_FLAGS2) {
c = (getc(fd) << 8) + c; // <flags2>
- if (c & WF_REGION)
+ }
+ if (c & WF_REGION) {
c = (getc(fd) << 16) + c; // <region>
- if (c & WF_AFX)
+ }
+ if (c & WF_AFX) {
c = (getc(fd) << 24) + c; // <affixID>
+ }
}
idxs[idx] = c;
c = 0;
- } else { // c == BY_INDEX
+ } else { // c == BY_INDEX
// <nodeidx>
n = get3c(fd);
- if (n < 0 || n >= maxidx)
+ if (n < 0 || n >= maxidx) {
return SP_FORMERROR;
+ }
idxs[idx] = n + SHARED_MASK;
c = getc(fd); // <xbyte>
}
@@ -1751,38 +1800,39 @@ read_tree_node (
// Recursively read the children for non-shared siblings.
// Skip the end-of-word ones (zero byte value) and the shared ones (and
// remove SHARED_MASK)
- for (i = 1; i <= len; ++i)
+ for (i = 1; i <= len; ++i) {
if (byts[startidx + i] != 0) {
- if (idxs[startidx + i] & SHARED_MASK)
+ if (idxs[startidx + i] & SHARED_MASK) {
idxs[startidx + i] &= ~SHARED_MASK;
- else {
+ } else {
idxs[startidx + i] = idx;
idx = read_tree_node(fd, byts, idxs, maxidx, idx,
- prefixtree, maxprefcondnr);
- if (idx < 0)
+ prefixtree, maxprefcondnr);
+ if (idx < 0) {
break;
+ }
}
}
+ }
return idx;
}
-// Reload the spell file "fname" if it's loaded.
-static void
-spell_reload_one (
- char_u *fname,
- bool added_word // invoked through "zg"
-)
+/// Reload the spell file "fname" if it's loaded.
+///
+/// @param added_word invoked through "zg"
+static void spell_reload_one(char_u *fname, bool added_word)
{
- slang_T *slang;
+ slang_T *slang;
bool didit = false;
for (slang = first_lang; slang != NULL; slang = slang->sl_next) {
if (path_full_compare(fname, slang->sl_fname, false, true) == kEqualFiles) {
slang_clear(slang);
- if (spell_load_file(fname, NULL, slang, false) == NULL)
+ if (spell_load_file(fname, NULL, slang, false) == NULL) {
// reloading failed, clear the language
slang_clear(slang);
+ }
redraw_all_later(SOME_VALID);
didit = true;
}
@@ -1790,8 +1840,9 @@ spell_reload_one (
// When "zg" was used and the file wasn't loaded yet, should redo
// 'spelllang' to load it now.
- if (added_word && !didit)
+ if (added_word && !didit) {
did_set_spelllang(curwin);
+ }
}
// Functions for ":mkspell".
@@ -1817,13 +1868,14 @@ static long compress_added = 500000; // word count
// Sets "sps_flags".
int spell_check_msm(void)
{
- char_u *p = p_msm;
+ char_u *p = p_msm;
long start = 0;
long incr = 0;
long added = 0;
- if (!ascii_isdigit(*p))
+ if (!ascii_isdigit(*p)) {
return FAIL;
+ }
// block count = (value * 1024) / SBLOCKSIZE (but avoid overflow)
start = (getdigits_long(&p, true, 0) * 10) / (SBLOCKSIZE / 102);
if (*p != ',') {
@@ -1861,11 +1913,12 @@ int spell_check_msm(void)
// readable format, so that we can see what happens when adding a word and/or
// compressing the tree.
// Based on code from Olaf Seibert.
-#define PRINTLINESIZE 1000
-#define PRINTWIDTH 6
+# define PRINTLINESIZE 1000
+# define PRINTWIDTH 6
-#define PRINTSOME(l, depth, fmt, a1, a2) vim_snprintf(l + depth * PRINTWIDTH, \
- PRINTLINESIZE - PRINTWIDTH * depth, fmt, a1, a2)
+# define PRINTSOME(l, depth, fmt, a1, a2) vim_snprintf(l + depth * PRINTWIDTH, \
+ PRINTLINESIZE - PRINTWIDTH * depth, fmt, a1, \
+ a2)
static char line1[PRINTLINESIZE];
static char line2[PRINTLINESIZE];
@@ -1873,7 +1926,7 @@ static char line3[PRINTLINESIZE];
static void spell_clear_flags(wordnode_T *node)
{
- wordnode_T *np;
+ wordnode_T *np;
for (np = node; np != NULL; np = np->wn_sibling) {
np->wn_u1.index = FALSE;
@@ -1895,20 +1948,23 @@ static void spell_print_node(wordnode_T *node, int depth)
node->wn_u1.index = TRUE;
if (node->wn_byte != NUL) {
- if (node->wn_child != NULL)
+ if (node->wn_child != NULL) {
PRINTSOME(line1, depth, " %c -> ", node->wn_byte, 0);
- else
+ } else {
// Cannot happen?
PRINTSOME(line1, depth, " %c ???", node->wn_byte, 0);
- } else
+ }
+ } else {
PRINTSOME(line1, depth, " $ ", 0, 0);
+ }
PRINTSOME(line2, depth, "%d/%d ", node->wn_nr, node->wn_refs);
- if (node->wn_sibling != NULL)
+ if (node->wn_sibling != NULL) {
PRINTSOME(line3, depth, " | ", 0, 0);
- else
+ } else {
PRINTSOME(line3, depth, " ", 0, 0);
+ }
if (node->wn_byte == NUL) {
msg((char_u *)line1);
@@ -1917,8 +1973,9 @@ static void spell_print_node(wordnode_T *node, int depth)
}
// do the children
- if (node->wn_byte != NUL && node->wn_child != NULL)
+ if (node->wn_byte != NUL && node->wn_child != NULL) {
spell_print_node(node->wn_child, depth + 1);
+ }
// do the siblings
if (node->wn_sibling != NULL) {
@@ -1948,39 +2005,39 @@ static void spell_print_tree(wordnode_T *root)
// Returns an afffile_T, NULL for complete failure.
static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
{
- FILE *fd;
+ FILE *fd;
char_u rline[MAXLINELEN];
- char_u *line;
- char_u *pc = NULL;
+ char_u *line;
+ char_u *pc = NULL;
#define MAXITEMCNT 30
- char_u *(items[MAXITEMCNT]);
+ char_u *(items[MAXITEMCNT]);
int itemcnt;
- char_u *p;
+ char_u *p;
int lnum = 0;
affheader_T *cur_aff = NULL;
bool did_postpone_prefix = false;
int aff_todo = 0;
- hashtab_T *tp;
- char_u *low = NULL;
- char_u *fol = NULL;
- char_u *upp = NULL;
+ hashtab_T *tp;
+ char_u *low = NULL;
+ char_u *fol = NULL;
+ char_u *upp = NULL;
int do_rep;
int do_repsal;
int do_sal;
int do_mapline;
bool found_map = false;
- hashitem_T *hi;
+ hashitem_T *hi;
int l;
int compminlen = 0; // COMPOUNDMIN value
int compsylmax = 0; // COMPOUNDSYLMAX value
int compoptions = 0; // COMP_ flags
int compmax = 0; // COMPOUNDWORDMAX value
- char_u *compflags = NULL; // COMPOUNDFLAG and COMPOUNDRULE
- // concatenated
- char_u *midword = NULL; // MIDWORD value
- char_u *syllable = NULL; // SYLLABLE value
- char_u *sofofrom = NULL; // SOFOFROM value
- char_u *sofoto = NULL; // SOFOTO value
+ char_u *compflags = NULL; // COMPOUNDFLAG and COMPOUNDRULE
+ // concatenated
+ char_u *midword = NULL; // MIDWORD value
+ char_u *syllable = NULL; // SYLLABLE value
+ char_u *sofofrom = NULL; // SOFOFROM value
+ char_u *sofoto = NULL; // SOFOTO value
// Open the file.
fd = os_fopen((char *)fname, "r");
@@ -2016,8 +2073,9 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
++lnum;
// Skip comment lines.
- if (*rline == '#')
+ if (*rline == '#') {
continue;
+ }
// Convert from "SET" to 'encoding' when needed.
xfree(pc);
@@ -2038,22 +2096,29 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
// item.
itemcnt = 0;
for (p = line;; ) {
- while (*p != NUL && *p <= ' ') // skip white space and CR/NL
+ while (*p != NUL && *p <= ' ') { // skip white space and CR/NL
++p;
- if (*p == NUL)
+ }
+ if (*p == NUL) {
break;
- if (itemcnt == MAXITEMCNT) // too many items
+ }
+ if (itemcnt == MAXITEMCNT) { // too many items
break;
+ }
items[itemcnt++] = p;
// A few items have arbitrary text argument, don't split them.
- if (itemcnt == 2 && spell_info_item(items[0]))
- while (*p >= ' ' || *p == TAB) // skip until CR/NL
+ if (itemcnt == 2 && spell_info_item(items[0])) {
+ while (*p >= ' ' || *p == TAB) { // skip until CR/NL
++p;
- else
- while (*p > ' ') // skip until white space or CR/NL
+ }
+ } else {
+ while (*p > ' ') { // skip until white space or CR/NL
++p;
- if (*p == NUL)
+ }
+ }
+ if (*p == NUL) {
break;
+ }
*p++ = NUL;
}
@@ -2064,21 +2129,23 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
aff->af_enc = enc_canonize(items[1]);
if (!spin->si_ascii
&& convert_setup(&spin->si_conv, aff->af_enc,
- p_enc) == FAIL)
+ p_enc) == FAIL) {
smsg(_("Conversion in %s not supported: from %s to %s"),
fname, aff->af_enc, p_enc);
+ }
spin->si_conv.vc_fail = true;
} else if (is_aff_rule(items, itemcnt, "FLAG", 2)
&& aff->af_flagtype == AFT_CHAR) {
- if (STRCMP(items[1], "long") == 0)
+ if (STRCMP(items[1], "long") == 0) {
aff->af_flagtype = AFT_LONG;
- else if (STRCMP(items[1], "num") == 0)
+ } else if (STRCMP(items[1], "num") == 0) {
aff->af_flagtype = AFT_NUM;
- else if (STRCMP(items[1], "caplong") == 0)
+ } else if (STRCMP(items[1], "caplong") == 0) {
aff->af_flagtype = AFT_CAPLONG;
- else
+ } else {
smsg(_("Invalid value for FLAG in %s line %d: %s"),
fname, lnum, items[1]);
+ }
if (aff->af_rare != 0
|| aff->af_keepcase != 0
|| aff->af_bad != 0
@@ -2089,10 +2156,11 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
|| aff->af_nosuggest != 0
|| compflags != NULL
|| aff->af_suff.ht_used > 0
- || aff->af_pref.ht_used > 0)
+ || aff->af_pref.ht_used > 0) {
smsg(_("FLAG after using flags in %s line %d: %s"),
fname, lnum, items[1]);
- } else if (spell_info_item(items[0]) && itemcnt > 1) {
+ }
+ } else if (spell_info_item(items[0]) && itemcnt > 1) {
p = getroom(spin,
(spin->si_info == NULL ? 0 : STRLEN(spin->si_info))
+ STRLEN(items[0])
@@ -2108,7 +2176,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
} else if (is_aff_rule(items, itemcnt, "MIDWORD", 2)
&& midword == NULL) {
midword = getroom_save(spin, items[1]);
- } else if (is_aff_rule(items, itemcnt, "TRY", 2)) {
+ } else if (is_aff_rule(items, itemcnt, "TRY", 2)) {
// ignored, we look in the tree for what chars may appear
}
// TODO: remove "RAR" later
@@ -2116,54 +2184,56 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
|| is_aff_rule(items, itemcnt, "RARE", 2))
&& aff->af_rare == 0) {
aff->af_rare = affitem2flag(aff->af_flagtype, items[1],
- fname, lnum);
+ fname, lnum);
}
// TODO: remove "KEP" later
else if ((is_aff_rule(items, itemcnt, "KEP", 2)
|| is_aff_rule(items, itemcnt, "KEEPCASE", 2))
&& aff->af_keepcase == 0) {
aff->af_keepcase = affitem2flag(aff->af_flagtype, items[1],
- fname, lnum);
+ fname, lnum);
} else if ((is_aff_rule(items, itemcnt, "BAD", 2)
|| is_aff_rule(items, itemcnt, "FORBIDDENWORD", 2))
&& aff->af_bad == 0) {
aff->af_bad = affitem2flag(aff->af_flagtype, items[1],
- fname, lnum);
+ fname, lnum);
} else if (is_aff_rule(items, itemcnt, "NEEDAFFIX", 2)
&& aff->af_needaffix == 0) {
aff->af_needaffix = affitem2flag(aff->af_flagtype, items[1],
- fname, lnum);
+ fname, lnum);
} else if (is_aff_rule(items, itemcnt, "CIRCUMFIX", 2)
&& aff->af_circumfix == 0) {
aff->af_circumfix = affitem2flag(aff->af_flagtype, items[1],
- fname, lnum);
+ fname, lnum);
} else if (is_aff_rule(items, itemcnt, "NOSUGGEST", 2)
&& aff->af_nosuggest == 0) {
aff->af_nosuggest = affitem2flag(aff->af_flagtype, items[1],
- fname, lnum);
+ fname, lnum);
} else if ((is_aff_rule(items, itemcnt, "NEEDCOMPOUND", 2)
|| is_aff_rule(items, itemcnt, "ONLYINCOMPOUND", 2))
&& aff->af_needcomp == 0) {
aff->af_needcomp = affitem2flag(aff->af_flagtype, items[1],
- fname, lnum);
+ fname, lnum);
} else if (is_aff_rule(items, itemcnt, "COMPOUNDROOT", 2)
&& aff->af_comproot == 0) {
aff->af_comproot = affitem2flag(aff->af_flagtype, items[1],
- fname, lnum);
+ fname, lnum);
} else if (is_aff_rule(items, itemcnt, "COMPOUNDFORBIDFLAG", 2)
&& aff->af_compforbid == 0) {
aff->af_compforbid = affitem2flag(aff->af_flagtype, items[1],
- fname, lnum);
- if (aff->af_pref.ht_used > 0)
+ fname, lnum);
+ if (aff->af_pref.ht_used > 0) {
smsg(_("Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line %d"),
fname, lnum);
+ }
} else if (is_aff_rule(items, itemcnt, "COMPOUNDPERMITFLAG", 2)
&& aff->af_comppermit == 0) {
aff->af_comppermit = affitem2flag(aff->af_flagtype, items[1],
- fname, lnum);
- if (aff->af_pref.ht_used > 0)
+ fname, lnum);
+ if (aff->af_pref.ht_used > 0) {
smsg(_("Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line %d"),
fname, lnum);
+ }
} else if (is_aff_rule(items, itemcnt, "COMPOUNDFLAG", 2)
&& compflags == NULL) {
// Turn flag "c" into COMPOUNDRULE compatible string "c+",
@@ -2172,20 +2242,22 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
STRCPY(p, items[1]);
STRCAT(p, "+");
compflags = p;
- } else if (is_aff_rule(items, itemcnt, "COMPOUNDRULES", 2)) {
+ } else if (is_aff_rule(items, itemcnt, "COMPOUNDRULES", 2)) {
// We don't use the count, but do check that it's a number and
// not COMPOUNDRULE mistyped.
- if (atoi((char *)items[1]) == 0)
+ if (atoi((char *)items[1]) == 0) {
smsg(_("Wrong COMPOUNDRULES value in %s line %d: %s"),
fname, lnum, items[1]);
- } else if (is_aff_rule(items, itemcnt, "COMPOUNDRULE", 2)) {
+ }
+ } else if (is_aff_rule(items, itemcnt, "COMPOUNDRULE", 2)) {
// Don't use the first rule if it is a number.
if (compflags != NULL || *skipdigits(items[1]) != NUL) {
// Concatenate this string to previously defined ones,
// using a slash to separate them.
l = (int)STRLEN(items[1]) + 1;
- if (compflags != NULL)
+ if (compflags != NULL) {
l += (int)STRLEN(compflags) + 1;
+ }
p = getroom(spin, l, false);
if (compflags != NULL) {
STRCPY(p, compflags);
@@ -2197,43 +2269,49 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
} else if (is_aff_rule(items, itemcnt, "COMPOUNDWORDMAX", 2)
&& compmax == 0) {
compmax = atoi((char *)items[1]);
- if (compmax == 0)
+ if (compmax == 0) {
smsg(_("Wrong COMPOUNDWORDMAX value in %s line %d: %s"),
fname, lnum, items[1]);
+ }
} else if (is_aff_rule(items, itemcnt, "COMPOUNDMIN", 2)
&& compminlen == 0) {
compminlen = atoi((char *)items[1]);
- if (compminlen == 0)
+ if (compminlen == 0) {
smsg(_("Wrong COMPOUNDMIN value in %s line %d: %s"),
fname, lnum, items[1]);
+ }
} else if (is_aff_rule(items, itemcnt, "COMPOUNDSYLMAX", 2)
&& compsylmax == 0) {
compsylmax = atoi((char *)items[1]);
- if (compsylmax == 0)
+ if (compsylmax == 0) {
smsg(_("Wrong COMPOUNDSYLMAX value in %s line %d: %s"),
fname, lnum, items[1]);
- } else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDDUP", 1)) {
+ }
+ } else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDDUP", 1)) {
compoptions |= COMP_CHECKDUP;
- } else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDREP", 1)) {
+ } else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDREP", 1)) {
compoptions |= COMP_CHECKREP;
- } else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDCASE", 1)) {
+ } else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDCASE", 1)) {
compoptions |= COMP_CHECKCASE;
- } else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDTRIPLE", 1)) {
+ } else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDTRIPLE", 1)) {
compoptions |= COMP_CHECKTRIPLE;
- } else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDPATTERN", 2)) {
- if (atoi((char *)items[1]) == 0)
+ } else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDPATTERN", 2)) {
+ if (atoi((char *)items[1]) == 0) {
smsg(_("Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s"),
fname, lnum, items[1]);
- } else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDPATTERN", 3)) {
- garray_T *gap = &spin->si_comppat;
+ }
+ } else if (is_aff_rule(items, itemcnt, "CHECKCOMPOUNDPATTERN", 3)) {
+ garray_T *gap = &spin->si_comppat;
int i;
// Only add the couple if it isn't already there.
- for (i = 0; i < gap->ga_len - 1; i += 2)
+ for (i = 0; i < gap->ga_len - 1; i += 2) {
if (STRCMP(((char_u **)(gap->ga_data))[i], items[1]) == 0
&& STRCMP(((char_u **)(gap->ga_data))[i + 1],
- items[2]) == 0)
+ items[2]) == 0) {
break;
+ }
+ }
if (i >= gap->ga_len) {
ga_grow(gap, 2);
((char_u **)(gap->ga_data))[gap->ga_len++]
@@ -2244,15 +2322,15 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
} else if (is_aff_rule(items, itemcnt, "SYLLABLE", 2)
&& syllable == NULL) {
syllable = getroom_save(spin, items[1]);
- } else if (is_aff_rule(items, itemcnt, "NOBREAK", 1)) {
+ } else if (is_aff_rule(items, itemcnt, "NOBREAK", 1)) {
spin->si_nobreak = true;
- } else if (is_aff_rule(items, itemcnt, "NOSPLITSUGS", 1)) {
+ } else if (is_aff_rule(items, itemcnt, "NOSPLITSUGS", 1)) {
spin->si_nosplitsugs = true;
} else if (is_aff_rule(items, itemcnt, "NOCOMPOUNDSUGS", 1)) {
spin->si_nocompoundsugs = true;
- } else if (is_aff_rule(items, itemcnt, "NOSUGFILE", 1)) {
+ } else if (is_aff_rule(items, itemcnt, "NOSUGFILE", 1)) {
spin->si_nosugfile = true;
- } else if (is_aff_rule(items, itemcnt, "PFXPOSTPONE", 1)) {
+ } else if (is_aff_rule(items, itemcnt, "PFXPOSTPONE", 1)) {
aff->af_pfxpostpone = true;
} else if (is_aff_rule(items, itemcnt, "IGNOREEXTRA", 1)) {
aff->af_ignoreextra = true;
@@ -2263,10 +2341,11 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
int lasti = 4;
char_u key[AH_KEY_LEN];
- if (*items[0] == 'P')
+ if (*items[0] == 'P') {
tp = &aff->af_pref;
- else
+ } else {
tp = &aff->af_suff;
+ }
// Myspell allows the same affix name to be used multiple
// times. The affix files that do this have an undocumented
@@ -2276,12 +2355,14 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
hi = hash_find(tp, key);
if (!HASHITEM_EMPTY(hi)) {
cur_aff = HI2AH(hi);
- if (cur_aff->ah_combine != (*items[2] == 'Y'))
+ if (cur_aff->ah_combine != (*items[2] == 'Y')) {
smsg(_("Different combining flag in continued affix block in %s line %d: %s"),
fname, lnum, items[1]);
- if (!cur_aff->ah_follows)
+ }
+ if (!cur_aff->ah_follows) {
smsg(_("Duplicate affix in %s line %d: %s"),
fname, lnum, items[1]);
+ }
} else {
// New affix letter.
cur_aff = getroom(spin, sizeof(*cur_aff), true);
@@ -2314,20 +2395,23 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
if (itemcnt > lasti && STRCMP(items[lasti], "S") == 0) {
++lasti;
cur_aff->ah_follows = true;
- } else
+ } else {
cur_aff->ah_follows = false;
+ }
// Myspell allows extra text after the item, but that might
// mean mistakes go unnoticed. Require a comment-starter,
// unless IGNOREEXTRA is used. Hunspell uses a "-" item.
if (itemcnt > lasti
&& !aff->af_ignoreextra
- && *items[lasti] != '#')
+ && *items[lasti] != '#') {
smsg(_(e_afftrailing), fname, lnum, items[lasti]);
+ }
- if (STRCMP(items[2], "Y") != 0 && STRCMP(items[2], "N") != 0)
+ if (STRCMP(items[2], "Y") != 0 && STRCMP(items[2], "N") != 0) {
smsg(_("Expected Y or N in %s line %d: %s"),
- fname, lnum, items[2]);
+ fname, lnum, items[2]);
+ }
if (*items[0] == 'P' && aff->af_pfxpostpone) {
if (cur_aff->ah_newID == 0) {
@@ -2340,9 +2424,10 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
// postponed. We know that only after handling all
// the items.
did_postpone_prefix = false;
- } else
+ } else {
// Did use the ID in a previous block.
did_postpone_prefix = true;
+ }
}
aff_todo = atoi((char *)items[3]);
@@ -2351,7 +2436,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
&& aff_todo > 0
&& STRCMP(cur_aff->ah_key, items[1]) == 0
&& itemcnt >= 5) {
- affentry_T *aff_entry;
+ affentry_T *aff_entry;
bool upper = false;
int lasti = 5;
@@ -2360,15 +2445,17 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
// Hunspell uses a "-" item.
if (itemcnt > lasti && *items[lasti] != '#'
&& (STRCMP(items[lasti], "-") != 0
- || itemcnt != lasti + 1))
+ || itemcnt != lasti + 1)) {
smsg(_(e_afftrailing), fname, lnum, items[lasti]);
+ }
// New item for an affix letter.
aff_todo--;
aff_entry = getroom(spin, sizeof(*aff_entry), true);
- if (STRCMP(items[2], "0") != 0)
+ if (STRCMP(items[2], "0") != 0) {
aff_entry->ae_chop = getroom_save(spin, items[2]);
+ }
if (STRCMP(items[3], "0") != 0) {
aff_entry->ae_add = getroom_save(spin, items[3]);
@@ -2391,15 +2478,17 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
char_u buf[MAXLINELEN];
aff_entry->ae_cond = getroom_save(spin, items[4]);
- if (*items[0] == 'P')
+ if (*items[0] == 'P') {
sprintf((char *)buf, "^%s", items[4]);
- else
+ } else {
sprintf((char *)buf, "%s$", items[4]);
+ }
aff_entry->ae_prog = vim_regcomp(buf,
- RE_MAGIC + RE_STRING + RE_STRICT);
- if (aff_entry->ae_prog == NULL)
+ RE_MAGIC + RE_STRING + RE_STRICT);
+ if (aff_entry->ae_prog == NULL) {
smsg(_("Broken condition in %s line %d: %s"),
fname, lnum, items[4]);
+ }
}
// For postponed prefixes we need an entry in si_prefcond
@@ -2415,9 +2504,8 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
// be empty or start with the same letter.
if (aff_entry->ae_chop != NULL
&& aff_entry->ae_add != NULL
- && aff_entry->ae_chop[(*mb_ptr2len)(
- aff_entry->ae_chop)] == NUL
- ) {
+ && aff_entry->ae_chop[(*mb_ptr2len)(aff_entry->ae_chop)] ==
+ NUL) {
int c, c_up;
c = PTR2CHAR(aff_entry->ae_chop);
@@ -2442,10 +2530,9 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
aff_entry->ae_cond = getroom_save(spin, buf);
if (aff_entry->ae_cond != NULL) {
sprintf((char *)buf, "^%s",
- aff_entry->ae_cond);
+ aff_entry->ae_cond);
vim_regfree(aff_entry->ae_prog);
- aff_entry->ae_prog = vim_regcomp(
- buf, RE_MAGIC + RE_STRING);
+ aff_entry->ae_prog = vim_regcomp(buf, RE_MAGIC + RE_STRING);
}
}
}
@@ -2454,43 +2541,49 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
if (aff_entry->ae_chop == NULL) {
int idx;
- char_u **pp;
+ char_u **pp;
int n;
// Find a previously used condition.
for (idx = spin->si_prefcond.ga_len - 1; idx >= 0;
--idx) {
p = ((char_u **)spin->si_prefcond.ga_data)[idx];
- if (str_equal(p, aff_entry->ae_cond))
+ if (str_equal(p, aff_entry->ae_cond)) {
break;
+ }
}
if (idx < 0) {
// Not found, add a new condition.
idx = spin->si_prefcond.ga_len;
pp = GA_APPEND_VIA_PTR(char_u *, &spin->si_prefcond);
*pp = (aff_entry->ae_cond == NULL) ?
- NULL : getroom_save(spin, aff_entry->ae_cond);
+ NULL : getroom_save(spin, aff_entry->ae_cond);
}
// Add the prefix to the prefix tree.
- if (aff_entry->ae_add == NULL)
+ if (aff_entry->ae_add == NULL) {
p = (char_u *)"";
- else
+ } else {
p = aff_entry->ae_add;
+ }
// PFX_FLAGS is a negative number, so that
// tree_add_word() knows this is the prefix tree.
n = PFX_FLAGS;
- if (!cur_aff->ah_combine)
+ if (!cur_aff->ah_combine) {
n |= WFP_NC;
- if (upper)
+ }
+ if (upper) {
n |= WFP_UP;
- if (aff_entry->ae_comppermit)
+ }
+ if (aff_entry->ae_comppermit) {
n |= WFP_COMPPERMIT;
- if (aff_entry->ae_compforbid)
+ }
+ if (aff_entry->ae_compforbid) {
n |= WFP_COMPFORBID;
+ }
tree_add_word(spin, p, spin->si_prefroot, n,
- idx, cur_aff->ah_newID);
+ idx, cur_aff->ah_newID);
did_postpone_prefix = true;
}
@@ -2501,26 +2594,28 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
}
}
}
- } else if (is_aff_rule(items, itemcnt, "FOL", 2) && fol == NULL) {
+ } else if (is_aff_rule(items, itemcnt, "FOL", 2) && fol == NULL) {
fol = vim_strsave(items[1]);
- } else if (is_aff_rule(items, itemcnt, "LOW", 2) && low == NULL) {
+ } else if (is_aff_rule(items, itemcnt, "LOW", 2) && low == NULL) {
low = vim_strsave(items[1]);
- } else if (is_aff_rule(items, itemcnt, "UPP", 2) && upp == NULL) {
+ } else if (is_aff_rule(items, itemcnt, "UPP", 2) && upp == NULL) {
upp = vim_strsave(items[1]);
} else if (is_aff_rule(items, itemcnt, "REP", 2)
|| is_aff_rule(items, itemcnt, "REPSAL", 2)) {
/* Ignore REP/REPSAL count */;
- if (!isdigit(*items[1]))
+ if (!isdigit(*items[1])) {
smsg(_("Expected REP(SAL) count in %s line %d"),
fname, lnum);
+ }
} else if ((STRCMP(items[0], "REP") == 0
|| STRCMP(items[0], "REPSAL") == 0)
&& itemcnt >= 3) {
// REP/REPSAL item
// Myspell ignores extra arguments, we require it starts with
// # to detect mistakes.
- if (itemcnt > 3 && items[3][0] != '#')
+ if (itemcnt > 3 && items[3][0] != '#') {
smsg(_(e_afftrailing), fname, lnum, items[3]);
+ }
if (items[0][3] == 'S' ? do_repsal : do_rep) {
// Replace underscore with space (can't include a space
// directly).
@@ -2538,15 +2633,16 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
? &spin->si_repsal
: &spin->si_rep, items[1], items[2]);
}
- } else if (is_aff_rule(items, itemcnt, "MAP", 2)) {
+ } else if (is_aff_rule(items, itemcnt, "MAP", 2)) {
// MAP item or count
if (!found_map) {
// First line contains the count.
found_map = true;
- if (!isdigit(*items[1]))
+ if (!isdigit(*items[1])) {
smsg(_("Expected MAP count in %s line %d"),
fname, lnum);
- } else if (do_mapline) {
+ }
+ } else if (do_mapline) {
int c;
// Check that every character appears only once.
@@ -2572,17 +2668,18 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
if (do_sal) {
// SAL item (sounds-a-like)
// Either one of the known keys or a from-to pair.
- if (STRCMP(items[1], "followup") == 0)
+ if (STRCMP(items[1], "followup") == 0) {
spin->si_followup = sal_to_bool(items[2]);
- else if (STRCMP(items[1], "collapse_result") == 0)
+ } else if (STRCMP(items[1], "collapse_result") == 0) {
spin->si_collapse = sal_to_bool(items[2]);
- else if (STRCMP(items[1], "remove_accents") == 0)
+ } else if (STRCMP(items[1], "remove_accents") == 0) {
spin->si_rem_accents = sal_to_bool(items[2]);
- else
+ } else {
// when "to" is "_" it means empty
add_fromto(spin, &spin->si_sal, items[1],
- STRCMP(items[2], "_") == 0 ? (char_u *)""
- : items[2]);
+ STRCMP(items[2], "_") == 0 ? (char_u *)""
+ : items[2]);
+ }
}
} else if (is_aff_rule(items, itemcnt, "SOFOFROM", 2)
&& sofofrom == NULL) {
@@ -2590,19 +2687,20 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
} else if (is_aff_rule(items, itemcnt, "SOFOTO", 2)
&& sofoto == NULL) {
sofoto = getroom_save(spin, items[1]);
- } else if (STRCMP(items[0], "COMMON") == 0) {
+ } else if (STRCMP(items[0], "COMMON") == 0) {
int i;
for (i = 1; i < itemcnt; ++i) {
if (HASHITEM_EMPTY(hash_find(&spin->si_commonwords,
- items[i]))) {
+ items[i]))) {
p = vim_strsave(items[i]);
hash_add(&spin->si_commonwords, p);
}
}
- } else
+ } else {
smsg(_("Unrecognized or duplicate item in %s line %d: %s"),
fname, lnum, items[0]);
+ }
}
}
@@ -2643,17 +2741,19 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
spin->si_compoptions |= compoptions;
}
- if (compflags != NULL)
+ if (compflags != NULL) {
process_compflags(spin, aff, compflags);
+ }
// Check that we didn't use too many renumbered flags.
if (spin->si_newcompID < spin->si_newprefID) {
- if (spin->si_newcompID == 127 || spin->si_newcompID == 255)
+ if (spin->si_newcompID == 127 || spin->si_newcompID == 255) {
MSG(_("Too many postponed prefixes"));
- else if (spin->si_newprefID == 0 || spin->si_newprefID == 127)
+ } else if (spin->si_newprefID == 0 || spin->si_newprefID == 127) {
MSG(_("Too many compound flags"));
- else
+ } else {
MSG(_("Too many postponed prefixes and/or compound flags"));
+ }
}
if (syllable != NULL) {
@@ -2662,12 +2762,12 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
}
if (sofofrom != NULL || sofoto != NULL) {
- if (sofofrom == NULL || sofoto == NULL)
+ if (sofofrom == NULL || sofoto == NULL) {
smsg(_("Missing SOFO%s line in %s"),
sofofrom == NULL ? "FROM" : "TO", fname);
- else if (!GA_EMPTY(&spin->si_sal))
+ } else if (!GA_EMPTY(&spin->si_sal)) {
smsg(_("Both SAL and SOFO lines in %s"), fname);
- else {
+ } else {
aff_check_string(spin->si_sofofr, sofofrom, "SOFOFROM");
aff_check_string(spin->si_sofoto, sofoto, "SOFOTO");
spin->si_sofofr = sofofrom;
@@ -2698,8 +2798,8 @@ static bool is_aff_rule(char_u **items, int itemcnt, char *rulename, int mincoun
// ae_flags to ae_comppermit and ae_compforbid.
static void aff_process_flags(afffile_T *affile, affentry_T *entry)
{
- char_u *p;
- char_u *prevp;
+ char_u *p;
+ char_u *prevp;
unsigned flag;
if (entry->ae_flags != NULL
@@ -2710,16 +2810,19 @@ static void aff_process_flags(afffile_T *affile, affentry_T *entry)
if (flag == affile->af_comppermit || flag == affile->af_compforbid) {
STRMOVE(prevp, p);
p = prevp;
- if (flag == affile->af_comppermit)
+ if (flag == affile->af_comppermit) {
entry->ae_comppermit = true;
- else
+ } else {
entry->ae_compforbid = true;
+ }
}
- if (affile->af_flagtype == AFT_NUM && *p == ',')
+ if (affile->af_flagtype == AFT_NUM && *p == ',') {
++p;
+ }
}
- if (*entry->ae_flags == NUL)
+ if (*entry->ae_flags == NUL) {
entry->ae_flags = NULL; // nothing left
+ }
}
}
@@ -2739,16 +2842,17 @@ static bool spell_info_item(char_u *s)
static unsigned affitem2flag(int flagtype, char_u *item, char_u *fname, int lnum)
{
unsigned res;
- char_u *p = item;
+ char_u *p = item;
res = get_affitem(flagtype, &p);
if (res == 0) {
- if (flagtype == AFT_NUM)
+ if (flagtype == AFT_NUM) {
smsg(_("Flag is not a number in %s line %d: %s"),
fname, lnum, item);
- else
+ } else {
smsg(_("Illegal flag in %s line %d: %s"),
fname, lnum, item);
+ }
}
if (*p != NUL) {
smsg(_(e_affname), fname, lnum, item);
@@ -2778,8 +2882,9 @@ static unsigned get_affitem(int flagtype, char_u **pp)
res = mb_ptr2char_adv((const char_u **)pp);
if (flagtype == AFT_LONG || (flagtype == AFT_CAPLONG
&& res >= 'A' && res <= 'Z')) {
- if (**pp == NUL)
+ if (**pp == NUL) {
return 0;
+ }
res = mb_ptr2char_adv((const char_u **)pp) + (res << 16);
}
}
@@ -2792,22 +2897,23 @@ static unsigned get_affitem(int flagtype, char_u **pp)
// they fit in one byte.
static void process_compflags(spellinfo_T *spin, afffile_T *aff, char_u *compflags)
{
- char_u *p;
- char_u *prevp;
+ char_u *p;
+ char_u *prevp;
unsigned flag;
- compitem_T *ci;
+ compitem_T *ci;
int id;
int len;
- char_u *tp;
+ char_u *tp;
char_u key[AH_KEY_LEN];
- hashitem_T *hi;
+ hashitem_T *hi;
// Make room for the old and the new compflags, concatenated with a / in
// between. Processing it makes it shorter, but we don't know by how
// much, thus allocate the maximum.
len = (int)STRLEN(compflags) + 1;
- if (spin->si_compflags != NULL)
+ if (spin->si_compflags != NULL) {
len += (int)STRLEN(spin->si_compflags) + 1;
+ }
p = getroom(spin, len, false);
if (spin->si_compflags != NULL) {
STRCPY(p, spin->si_compflags);
@@ -2817,10 +2923,10 @@ static void process_compflags(spellinfo_T *spin, afffile_T *aff, char_u *compfla
tp = p + STRLEN(p);
for (p = compflags; *p != NUL; ) {
- if (vim_strchr((char_u *)"/?*+[]", *p) != NULL)
+ if (vim_strchr((char_u *)"/?*+[]", *p) != NULL) {
// Copy non-flag characters directly.
*tp++ = *p++;
- else {
+ } else {
// First get the flag number, also checks validity.
prevp = p;
flag = get_affitem(aff->af_flagtype, &p);
@@ -2846,8 +2952,9 @@ static void process_compflags(spellinfo_T *spin, afffile_T *aff, char_u *compfla
}
*tp++ = id;
}
- if (aff->af_flagtype == AFT_NUM && *p == ',')
+ if (aff->af_flagtype == AFT_NUM && *p == ',') {
++p;
+ }
}
}
@@ -2869,7 +2976,7 @@ static void check_renumber(spellinfo_T *spin)
// Returns true if flag "flag" appears in affix list "afflist".
static bool flag_in_afflist(int flagtype, char_u *afflist, unsigned flag)
{
- char_u *p;
+ char_u *p;
unsigned n;
switch (flagtype) {
@@ -2913,25 +3020,28 @@ static bool flag_in_afflist(int flagtype, char_u *afflist, unsigned flag)
// Give a warning when "spinval" and "affval" numbers are set and not the same.
static void aff_check_number(int spinval, int affval, char *name)
{
- if (spinval != 0 && spinval != affval)
+ if (spinval != 0 && spinval != affval) {
smsg(_("%s value differs from what is used in another .aff file"),
name);
+ }
}
// Give a warning when "spinval" and "affval" strings are set and not the same.
static void aff_check_string(char_u *spinval, char_u *affval, char *name)
{
- if (spinval != NULL && STRCMP(spinval, affval) != 0)
+ if (spinval != NULL && STRCMP(spinval, affval) != 0) {
smsg(_("%s value differs from what is used in another .aff file"),
name);
+ }
}
// Returns true if strings "s1" and "s2" are equal. Also consider both being
// NULL as equal.
static bool str_equal(char_u *s1, char_u *s2)
{
- if (s1 == NULL || s2 == NULL)
+ if (s1 == NULL || s2 == NULL) {
return s1 == s2;
+ }
return STRCMP(s1, s2) == 0;
}
@@ -2957,11 +3067,11 @@ static bool sal_to_bool(char_u *s)
// Free the structure filled by spell_read_aff().
static void spell_free_aff(afffile_T *aff)
{
- hashtab_T *ht;
- hashitem_T *hi;
+ hashtab_T *ht;
+ hashitem_T *hi;
int todo;
affheader_T *ah;
- affentry_T *ae;
+ affentry_T *ae;
xfree(aff->af_enc);
@@ -2972,12 +3082,14 @@ static void spell_free_aff(afffile_T *aff)
if (!HASHITEM_EMPTY(hi)) {
--todo;
ah = HI2AH(hi);
- for (ae = ah->ah_first; ae != NULL; ae = ae->ae_next)
+ for (ae = ah->ah_first; ae != NULL; ae = ae->ae_next) {
vim_regfree(ae->ae_prog);
+ }
}
}
- if (ht == &aff->af_suff)
+ if (ht == &aff->af_suff) {
break;
+ }
}
hash_clear(&aff->af_pref);
@@ -2991,18 +3103,18 @@ static int spell_read_dic(spellinfo_T *spin, char_u *fname, afffile_T *affile)
{
hashtab_T ht;
char_u line[MAXLINELEN];
- char_u *p;
- char_u *afflist;
+ char_u *p;
+ char_u *afflist;
char_u store_afflist[MAXWLEN];
int pfxlen;
bool need_affix;
- char_u *dw;
- char_u *pc;
- char_u *w;
+ char_u *dw;
+ char_u *pc;
+ char_u *w;
int l;
hash_T hash;
- hashitem_T *hi;
- FILE *fd;
+ hashitem_T *hi;
+ FILE *fd;
int lnum = 1;
int non_ascii = 0;
int retval = OK;
@@ -3039,16 +3151,18 @@ static int spell_read_dic(spellinfo_T *spin, char_u *fname, afffile_T *affile)
while (!vim_fgets(line, MAXLINELEN, fd) && !got_int) {
line_breakcheck();
++lnum;
- if (line[0] == '#' || line[0] == '/')
+ if (line[0] == '#' || line[0] == '/') {
continue; // comment line
-
+ }
// Remove CR, LF and white space from the end. White space halfway through
// the word is kept to allow multi-word terms like "et al.".
l = (int)STRLEN(line);
- while (l > 0 && line[l - 1] <= ' ')
+ while (l > 0 && line[l - 1] <= ' ') {
--l;
- if (l == 0)
+ }
+ if (l == 0) {
continue; // empty line
+ }
line[l] = NUL;
// Convert from "SET" to 'encoding' when needed.
@@ -3114,15 +3228,17 @@ static int spell_read_dic(spellinfo_T *spin, char_u *fname, afffile_T *affile)
hash = hash_hash(dw);
hi = hash_lookup(&ht, (const char *)dw, STRLEN(dw), hash);
if (!HASHITEM_EMPTY(hi)) {
- if (p_verbose > 0)
+ if (p_verbose > 0) {
smsg(_("Duplicate word in %s line %d: %s"),
fname, lnum, dw);
- else if (duplicate == 0)
+ } else if (duplicate == 0) {
smsg(_("First duplicate word in %s line %d: %s"),
fname, lnum, dw);
+ }
++duplicate;
- } else
+ } else {
hash_add_item(&ht, hi, dw, hash);
+ }
flags = 0;
store_afflist[0] = NUL;
@@ -3132,48 +3248,57 @@ static int spell_read_dic(spellinfo_T *spin, char_u *fname, afffile_T *affile)
// Extract flags from the affix list.
flags |= get_affix_flags(affile, afflist);
- if (affile->af_needaffix != 0 && flag_in_afflist(
- affile->af_flagtype, afflist, affile->af_needaffix))
+ if (affile->af_needaffix != 0 &&
+ flag_in_afflist(affile->af_flagtype, afflist,
+ affile->af_needaffix)) {
need_affix = true;
+ }
- if (affile->af_pfxpostpone)
+ if (affile->af_pfxpostpone) {
// Need to store the list of prefix IDs with the word.
pfxlen = get_pfxlist(affile, afflist, store_afflist);
+ }
- if (spin->si_compflags != NULL)
+ if (spin->si_compflags != NULL) {
// Need to store the list of compound flags with the word.
// Concatenate them to the list of prefix IDs.
get_compflags(affile, afflist, store_afflist + pfxlen);
+ }
}
// Add the word to the word tree(s).
if (store_word(spin, dw, flags, spin->si_region,
- store_afflist, need_affix) == FAIL)
+ store_afflist, need_affix) == FAIL) {
retval = FAIL;
+ }
if (afflist != NULL) {
// Find all matching suffixes and add the resulting words.
// Additionally do matching prefixes that combine.
if (store_aff_word(spin, dw, afflist, affile,
- &affile->af_suff, &affile->af_pref,
- CONDIT_SUF, flags, store_afflist, pfxlen) == FAIL)
+ &affile->af_suff, &affile->af_pref,
+ CONDIT_SUF, flags, store_afflist, pfxlen) == FAIL) {
retval = FAIL;
+ }
// Find all matching prefixes and add the resulting words.
if (store_aff_word(spin, dw, afflist, affile,
- &affile->af_pref, NULL,
- CONDIT_SUF, flags, store_afflist, pfxlen) == FAIL)
+ &affile->af_pref, NULL,
+ CONDIT_SUF, flags, store_afflist, pfxlen) == FAIL) {
retval = FAIL;
+ }
}
xfree(pc);
}
- if (duplicate > 0)
+ if (duplicate > 0) {
smsg(_("%d duplicate word(s) in %s"), duplicate, fname);
- if (spin->si_ascii && non_ascii > 0)
+ }
+ if (spin->si_ascii && non_ascii > 0) {
smsg(_("Ignored %d word(s) with non-ASCII characters in %s"),
non_ascii, fname);
+ }
hash_clear(&ht);
fclose(fd);
@@ -3186,24 +3311,34 @@ static int get_affix_flags(afffile_T *affile, char_u *afflist)
{
int flags = 0;
- if (affile->af_keepcase != 0 && flag_in_afflist(
- affile->af_flagtype, afflist, affile->af_keepcase))
+ if (affile->af_keepcase != 0 &&
+ flag_in_afflist(affile->af_flagtype, afflist,
+ affile->af_keepcase)) {
flags |= WF_KEEPCAP | WF_FIXCAP;
- if (affile->af_rare != 0 && flag_in_afflist(
- affile->af_flagtype, afflist, affile->af_rare))
+ }
+ if (affile->af_rare != 0 &&
+ flag_in_afflist(affile->af_flagtype, afflist, affile->af_rare)) {
flags |= WF_RARE;
- if (affile->af_bad != 0 && flag_in_afflist(
- affile->af_flagtype, afflist, affile->af_bad))
+ }
+ if (affile->af_bad != 0 &&
+ flag_in_afflist(affile->af_flagtype, afflist, affile->af_bad)) {
flags |= WF_BANNED;
- if (affile->af_needcomp != 0 && flag_in_afflist(
- affile->af_flagtype, afflist, affile->af_needcomp))
+ }
+ if (affile->af_needcomp != 0 &&
+ flag_in_afflist(affile->af_flagtype, afflist,
+ affile->af_needcomp)) {
flags |= WF_NEEDCOMP;
- if (affile->af_comproot != 0 && flag_in_afflist(
- affile->af_flagtype, afflist, affile->af_comproot))
+ }
+ if (affile->af_comproot != 0 &&
+ flag_in_afflist(affile->af_flagtype, afflist,
+ affile->af_comproot)) {
flags |= WF_COMPROOT;
- if (affile->af_nosuggest != 0 && flag_in_afflist(
- affile->af_flagtype, afflist, affile->af_nosuggest))
+ }
+ if (affile->af_nosuggest != 0 &&
+ flag_in_afflist(affile->af_flagtype, afflist,
+ affile->af_nosuggest)) {
flags |= WF_NOSUGGEST;
+ }
return flags;
}
@@ -3213,12 +3348,12 @@ static int get_affix_flags(afffile_T *affile, char_u *afflist)
// and return the number of affixes.
static int get_pfxlist(afffile_T *affile, char_u *afflist, char_u *store_afflist)
{
- char_u *p;
- char_u *prevp;
+ char_u *p;
+ char_u *prevp;
int cnt = 0;
int id;
char_u key[AH_KEY_LEN];
- hashitem_T *hi;
+ hashitem_T *hi;
for (p = afflist; *p != NUL; ) {
prevp = p;
@@ -3229,12 +3364,14 @@ static int get_pfxlist(afffile_T *affile, char_u *afflist, char_u *store_afflist
hi = hash_find(&affile->af_pref, key);
if (!HASHITEM_EMPTY(hi)) {
id = HI2AH(hi)->ah_newID;
- if (id != 0)
+ if (id != 0) {
store_afflist[cnt++] = id;
+ }
}
}
- if (affile->af_flagtype == AFT_NUM && *p == ',')
+ if (affile->af_flagtype == AFT_NUM && *p == ',') {
++p;
+ }
}
store_afflist[cnt] = NUL;
@@ -3246,11 +3383,11 @@ static int get_pfxlist(afffile_T *affile, char_u *afflist, char_u *store_afflist
// Puts the flags in "store_afflist[]".
static void get_compflags(afffile_T *affile, char_u *afflist, char_u *store_afflist)
{
- char_u *p;
- char_u *prevp;
+ char_u *p;
+ char_u *prevp;
int cnt = 0;
char_u key[AH_KEY_LEN];
- hashitem_T *hi;
+ hashitem_T *hi;
for (p = afflist; *p != NUL; ) {
prevp = p;
@@ -3258,48 +3395,47 @@ static void get_compflags(afffile_T *affile, char_u *afflist, char_u *store_affl
// A flag is a compound flag if it appears in "af_comp".
STRLCPY(key, prevp, p - prevp + 1);
hi = hash_find(&affile->af_comp, key);
- if (!HASHITEM_EMPTY(hi))
+ if (!HASHITEM_EMPTY(hi)) {
store_afflist[cnt++] = HI2CI(hi)->ci_newID;
+ }
}
- if (affile->af_flagtype == AFT_NUM && *p == ',')
+ if (affile->af_flagtype == AFT_NUM && *p == ',') {
++p;
+ }
}
store_afflist[cnt] = NUL;
}
-// Apply affixes to a word and store the resulting words.
-// "ht" is the hashtable with affentry_T that need to be applied, either
-// prefixes or suffixes.
-// "xht", when not NULL, is the prefix hashtable, to be used additionally on
-// the resulting words for combining affixes.
-//
-// Returns FAIL when out of memory.
-static int
-store_aff_word (
- spellinfo_T *spin, // spell info
- char_u *word, // basic word start
- char_u *afflist, // list of names of supported affixes
- afffile_T *affile,
- hashtab_T *ht,
- hashtab_T *xht,
- int condit, // CONDIT_SUF et al.
- int flags, // flags for the word
- char_u *pfxlist, // list of prefix IDs
- int pfxlen // nr of flags in "pfxlist" for prefixes, rest
- // is compound flags
-)
+/// Apply affixes to a word and store the resulting words.
+/// "ht" is the hashtable with affentry_T that need to be applied, either
+/// prefixes or suffixes.
+/// "xht", when not NULL, is the prefix hashtable, to be used additionally on
+/// the resulting words for combining affixes.
+///
+/// @param spin spell info
+/// @param word basic word start
+/// @param afflist list of names of supported affixes
+/// @param condit CONDIT_SUF et al.
+/// @param flags flags for the word
+/// @param pfxlist list of prefix IDs
+/// @param pfxlen nr of flags in "pfxlist" for prefixes, rest is compound flags
+///
+/// @return FAIL when out of memory.
+static int store_aff_word(spellinfo_T *spin, char_u *word, char_u *afflist, afffile_T *affile,
+ hashtab_T *ht, hashtab_T *xht, int condit, int flags, char_u *pfxlist,
+ int pfxlen)
{
int todo;
- hashitem_T *hi;
+ hashitem_T *hi;
affheader_T *ah;
- affentry_T *ae;
+ affentry_T *ae;
char_u newword[MAXWLEN];
int retval = OK;
int i, j;
- char_u *p;
+ char_u *p;
int use_flags;
- char_u *use_pfxlist;
+ char_u *use_pfxlist;
int use_pfxlen;
bool need_affix;
char_u store_afflist[MAXWLEN];
@@ -3317,7 +3453,7 @@ store_aff_word (
// supports this affix.
if (((condit & CONDIT_COMB) == 0 || ah->ah_combine)
&& flag_in_afflist(affile->af_flagtype, afflist,
- ah->ah_flag)) {
+ ah->ah_flag)) {
// Loop over all affix entries with this name.
for (ae = ah->ah_first; ae != NULL; ae = ae->ae_next) {
// Check the condition. It's not logical to match case
@@ -3341,7 +3477,7 @@ store_aff_word (
== ((condit & CONDIT_AFF) == 0
|| ae->ae_flags == NULL
|| !flag_in_afflist(affile->af_flagtype,
- ae->ae_flags, affile->af_circumfix)))) {
+ ae->ae_flags, affile->af_circumfix)))) {
// Match. Remove the chop and add the affix.
if (xht == NULL) {
// prefix: chop/add at the start of the word
@@ -3371,8 +3507,9 @@ store_aff_word (
}
*p = NUL;
}
- if (ae->ae_add != NULL)
+ if (ae->ae_add != NULL) {
STRCAT(newword, ae->ae_add);
+ }
}
use_flags = flags;
@@ -3384,57 +3521,64 @@ store_aff_word (
// Extract flags from the affix list.
use_flags |= get_affix_flags(affile, ae->ae_flags);
- if (affile->af_needaffix != 0 && flag_in_afflist(
- affile->af_flagtype, ae->ae_flags,
- affile->af_needaffix))
+ if (affile->af_needaffix != 0 && flag_in_afflist(affile->af_flagtype, ae->ae_flags,
+ affile->af_needaffix)) {
need_affix = true;
+ }
// When there is a CIRCUMFIX flag the other affix
// must also have it and we don't add the word
// with one affix.
- if (affile->af_circumfix != 0 && flag_in_afflist(
- affile->af_flagtype, ae->ae_flags,
- affile->af_circumfix)) {
+ if (affile->af_circumfix != 0 && flag_in_afflist(affile->af_flagtype, ae->ae_flags,
+ affile->af_circumfix)) {
use_condit |= CONDIT_CFIX;
- if ((condit & CONDIT_CFIX) == 0)
+ if ((condit & CONDIT_CFIX) == 0) {
need_affix = true;
+ }
}
if (affile->af_pfxpostpone
|| spin->si_compflags != NULL) {
- if (affile->af_pfxpostpone)
+ if (affile->af_pfxpostpone) {
// Get prefix IDS from the affix list.
use_pfxlen = get_pfxlist(affile,
- ae->ae_flags, store_afflist);
- else
+ ae->ae_flags, store_afflist);
+ } else {
use_pfxlen = 0;
+ }
use_pfxlist = store_afflist;
// Combine the prefix IDs. Avoid adding the
// same ID twice.
for (i = 0; i < pfxlen; ++i) {
- for (j = 0; j < use_pfxlen; ++j)
- if (pfxlist[i] == use_pfxlist[j])
+ for (j = 0; j < use_pfxlen; ++j) {
+ if (pfxlist[i] == use_pfxlist[j]) {
break;
- if (j == use_pfxlen)
+ }
+ }
+ if (j == use_pfxlen) {
use_pfxlist[use_pfxlen++] = pfxlist[i];
+ }
}
- if (spin->si_compflags != NULL)
+ if (spin->si_compflags != NULL) {
// Get compound IDS from the affix list.
get_compflags(affile, ae->ae_flags,
- use_pfxlist + use_pfxlen);
- else
+ use_pfxlist + use_pfxlen);
+ } else {
use_pfxlist[use_pfxlen] = NUL;
+ }
// Combine the list of compound flags.
// Concatenate them to the prefix IDs list.
// Avoid adding the same ID twice.
for (i = pfxlen; pfxlist[i] != NUL; ++i) {
for (j = use_pfxlen;
- use_pfxlist[j] != NUL; ++j)
- if (pfxlist[i] == use_pfxlist[j])
+ use_pfxlist[j] != NUL; ++j) {
+ if (pfxlist[i] == use_pfxlist[j]) {
break;
+ }
+ }
if (use_pfxlist[j] == NUL) {
use_pfxlist[j++] = pfxlist[i];
use_pfxlist[j] = NUL;
@@ -3459,52 +3603,58 @@ store_aff_word (
// ... don't use a prefix list if combining
// affixes is not allowed. But do use the
// compound flags after them.
- if (!ah->ah_combine && use_pfxlist != NULL)
+ if (!ah->ah_combine && use_pfxlist != NULL) {
use_pfxlist += use_pfxlen;
+ }
}
// When compounding is supported and there is no
// "COMPOUNDPERMITFLAG" then forbid compounding on the
// side where the affix is applied.
if (spin->si_compflags != NULL && !ae->ae_comppermit) {
- if (xht != NULL)
+ if (xht != NULL) {
use_flags |= WF_NOCOMPAFT;
- else
+ } else {
use_flags |= WF_NOCOMPBEF;
+ }
}
// Store the modified word.
if (store_word(spin, newword, use_flags,
- spin->si_region, use_pfxlist,
- need_affix) == FAIL)
+ spin->si_region, use_pfxlist,
+ need_affix) == FAIL) {
retval = FAIL;
+ }
// When added a prefix or a first suffix and the affix
// has flags may add a(nother) suffix. RECURSIVE!
- if ((condit & CONDIT_SUF) && ae->ae_flags != NULL)
+ if ((condit & CONDIT_SUF) && ae->ae_flags != NULL) {
if (store_aff_word(spin, newword, ae->ae_flags,
- affile, &affile->af_suff, xht,
- use_condit & (xht == NULL
+ affile, &affile->af_suff, xht,
+ use_condit & (xht == NULL
? ~0 : ~CONDIT_SUF),
- use_flags, use_pfxlist, pfxlen) == FAIL)
+ use_flags, use_pfxlist, pfxlen) == FAIL) {
retval = FAIL;
+ }
+ }
// When added a suffix and combining is allowed also
// try adding a prefix additionally. Both for the
// word flags and for the affix flags. RECURSIVE!
if (xht != NULL && ah->ah_combine) {
if (store_aff_word(spin, newword,
- afflist, affile,
- xht, NULL, use_condit,
- use_flags, use_pfxlist,
- pfxlen) == FAIL
+ afflist, affile,
+ xht, NULL, use_condit,
+ use_flags, use_pfxlist,
+ pfxlen) == FAIL
|| (ae->ae_flags != NULL
&& store_aff_word(spin, newword,
- ae->ae_flags, affile,
- xht, NULL, use_condit,
- use_flags, use_pfxlist,
- pfxlen) == FAIL))
+ ae->ae_flags, affile,
+ xht, NULL, use_condit,
+ use_flags, use_pfxlist,
+ pfxlen) == FAIL)) {
retval = FAIL;
+ }
}
}
}
@@ -3518,12 +3668,12 @@ store_aff_word (
// Read a file with a list of words.
static int spell_read_wordfile(spellinfo_T *spin, char_u *fname)
{
- FILE *fd;
+ FILE *fd;
long lnum = 0;
char_u rline[MAXLINELEN];
- char_u *line;
- char_u *pc = NULL;
- char_u *p;
+ char_u *line;
+ char_u *pc = NULL;
+ char_u *p;
int l;
int retval = OK;
bool did_word = false;
@@ -3547,15 +3697,18 @@ static int spell_read_wordfile(spellinfo_T *spin, char_u *fname)
++lnum;
// Skip comment lines.
- if (*rline == '#')
+ if (*rline == '#') {
continue;
+ }
// Remove CR, LF and white space from the end.
l = (int)STRLEN(rline);
- while (l > 0 && rline[l - 1] <= ' ')
+ while (l > 0 && rline[l - 1] <= ' ') {
--l;
- if (l == 0)
+ }
+ if (l == 0) {
continue; // empty or blank line
+ }
rline[l] = NUL;
// Convert from "/encoding={encoding}" to 'encoding' when needed.
@@ -3583,16 +3736,17 @@ static int spell_read_wordfile(spellinfo_T *spin, char_u *fname)
smsg(_("/encoding= line after word ignored in %s line %ld: %s"),
fname, lnum, line - 1);
} else {
- char_u *enc;
+ char_u *enc;
// Setup for conversion to 'encoding'.
line += 9;
enc = enc_canonize(line);
if (!spin->si_ascii
&& convert_setup(&spin->si_conv, enc,
- p_enc) == FAIL)
+ p_enc) == FAIL) {
smsg(_("Conversion in %s not supported: from %s to %s"),
fname, line, p_enc);
+ }
xfree(enc);
spin->si_conv.vc_fail = true;
}
@@ -3632,15 +3786,16 @@ static int spell_read_wordfile(spellinfo_T *spin, char_u *fname)
if (p != NULL) {
*p++ = NUL;
while (*p != NUL) {
- if (*p == '=') // keep-case word
+ if (*p == '=') { // keep-case word
flags |= WF_KEEPCAP | WF_FIXCAP;
- else if (*p == '!') // Bad, bad, wicked word.
+ } else if (*p == '!') { // Bad, bad, wicked word.
flags |= WF_BANNED;
- else if (*p == '?') // Rare word.
+ } else if (*p == '?') { // Rare word.
flags |= WF_RARE;
- else if (ascii_isdigit(*p)) { // region number(s)
- if ((flags & WF_REGION) == 0) // first one
+ } else if (ascii_isdigit(*p)) { // region number(s)
+ if ((flags & WF_REGION) == 0) { // first one
regionmask = 0;
+ }
flags |= WF_REGION;
l = *p - '0';
@@ -3678,7 +3833,7 @@ static int spell_read_wordfile(spellinfo_T *spin, char_u *fname)
if (spin->si_ascii && non_ascii > 0) {
vim_snprintf((char *)IObuff, IOSIZE,
- _("Ignored %d words with non-ASCII characters"), non_ascii);
+ _("Ignored %d words with non-ASCII characters"), non_ascii);
spell_message(spin, IObuff);
}
@@ -3696,16 +3851,17 @@ static int spell_read_wordfile(spellinfo_T *spin, char_u *fname)
static void *getroom(spellinfo_T *spin, size_t len, bool align)
FUNC_ATTR_NONNULL_RET
{
- char_u *p;
- sblock_T *bl = spin->si_blocks;
+ char_u *p;
+ sblock_T *bl = spin->si_blocks;
assert(len <= SBLOCKSIZE);
-
- if (align && bl != NULL)
+
+ if (align && bl != NULL) {
// Round size up for alignment. On some systems structures need to be
// aligned to the size of a pointer (e.g., SPARC).
bl->sb_used = (bl->sb_used + sizeof(char *) - 1)
& ~(sizeof(char *) - 1);
+ }
if (bl == NULL || bl->sb_used + len > SBLOCKSIZE) {
// Allocate a block of memory. It is not freed until much later.
@@ -3734,7 +3890,7 @@ static char_u *getroom_save(spellinfo_T *spin, char_u *s)
// Free the list of allocated sblock_T.
static void free_blocks(sblock_T *bl)
{
- sblock_T *next;
+ sblock_T *next;
while (bl != NULL) {
next = bl->sb_next;
@@ -3751,22 +3907,20 @@ static wordnode_T *wordtree_alloc(spellinfo_T *spin)
return (wordnode_T *)getroom(spin, sizeof(wordnode_T), true);
}
-// Store a word in the tree(s).
-// Always store it in the case-folded tree. For a keep-case word this is
-// useful when the word can also be used with all caps (no WF_FIXCAP flag) and
-// used to find suggestions.
-// For a keep-case word also store it in the keep-case tree.
-// When "pfxlist" is not NULL store the word for each postponed prefix ID and
-// compound flag.
-static int
-store_word (
- spellinfo_T *spin,
- char_u *word,
- int flags, // extra flags, WF_BANNED
- int region, // supported region(s)
- const char_u *pfxlist, // list of prefix IDs or NULL
- bool need_affix // only store word with affix ID
-)
+/// Store a word in the tree(s).
+/// Always store it in the case-folded tree. For a keep-case word this is
+/// useful when the word can also be used with all caps (no WF_FIXCAP flag) and
+/// used to find suggestions.
+/// For a keep-case word also store it in the keep-case tree.
+/// When "pfxlist" is not NULL store the word for each postponed prefix ID and
+/// compound flag.
+///
+/// @param flags extra flags, wf_banned
+/// @param region supported region(s)
+/// @param pfxlist list of prefix ids or null
+/// @param need_affix only store word with affix id
+static int store_word(spellinfo_T *spin, char_u *word, int flags, int region, const char_u *pfxlist,
+ bool need_affix)
{
int len = (int)STRLEN(word);
int ct = captype(word, word + len);
@@ -3804,12 +3958,13 @@ store_word (
// When "flags" < 0 we are adding to the prefix tree where "flags" is used for
// "rare" and "region" is the condition nr.
// Returns FAIL when out of memory.
-static int tree_add_word(spellinfo_T *spin, char_u *word, wordnode_T *root, int flags, int region, int affixID)
+static int tree_add_word(spellinfo_T *spin, char_u *word, wordnode_T *root, int flags, int region,
+ int affixID)
{
- wordnode_T *node = root;
- wordnode_T *np;
- wordnode_T *copyp, **copyprev;
- wordnode_T **prev = NULL;
+ wordnode_T *node = root;
+ wordnode_T *np;
+ wordnode_T *copyp, **copyprev;
+ wordnode_T **prev = NULL;
int i;
// Add each byte of the word to the tree, including the NUL at the end.
@@ -3823,11 +3978,13 @@ static int tree_add_word(spellinfo_T *spin, char_u *word, wordnode_T *root, int
for (copyp = node; copyp != NULL; copyp = copyp->wn_sibling) {
// Allocate a new node and copy the info.
np = get_wordnode(spin);
- if (np == NULL)
+ if (np == NULL) {
return FAIL;
+ }
np->wn_child = copyp->wn_child;
- if (np->wn_child != NULL)
+ if (np->wn_child != NULL) {
++np->wn_child->wn_refs; // child gets extra ref
+ }
np->wn_byte = copyp->wn_byte;
if (np->wn_byte == NUL) {
np->wn_flags = copyp->wn_flags;
@@ -3837,13 +3994,15 @@ static int tree_add_word(spellinfo_T *spin, char_u *word, wordnode_T *root, int
// Link the new node in the list, there will be one ref.
np->wn_refs = 1;
- if (copyprev != NULL)
+ if (copyprev != NULL) {
*copyprev = np;
+ }
copyprev = &np->wn_sibling;
// Let "node" point to the head of the copied list.
- if (copyp == node)
+ if (copyp == node) {
node = np;
+ }
}
}
@@ -3874,22 +4033,24 @@ static int tree_add_word(spellinfo_T *spin, char_u *word, wordnode_T *root, int
|| node->wn_affixID != affixID))) {
// Allocate a new node.
np = get_wordnode(spin);
- if (np == NULL)
+ if (np == NULL) {
return FAIL;
+ }
np->wn_byte = word[i];
// If "node" is NULL this is a new child or the end of the sibling
// list: ref count is one. Otherwise use ref count of sibling and
// make ref count of sibling one (matters when inserting in front
// of the list of siblings).
- if (node == NULL)
+ if (node == NULL) {
np->wn_refs = 1;
- else {
+ } else {
np->wn_refs = node->wn_refs;
node->wn_refs = 1;
}
- if (prev != NULL)
+ if (prev != NULL) {
*prev = np;
+ }
np->wn_sibling = node;
node = np;
}
@@ -3931,7 +4092,7 @@ static int tree_add_word(spellinfo_T *spin, char_u *word, wordnode_T *root, int
#ifndef SPELL_COMPRESS_ALLWAYS
if (spin->si_compress_cnt == 1 // NOLINT(readability/braces)
? spin->si_free_count < MAXWLEN
- : spin->si_blocks_cnt >= compress_start)
+ : spin->si_blocks_cnt >= compress_start)
#endif
{
// Decrement the block counter. The effect is that we compress again
@@ -3945,7 +4106,7 @@ static int tree_add_word(spellinfo_T *spin, char_u *word, wordnode_T *root, int
msg_start();
msg_puts(_(msg_compressing));
msg_clr_eos();
- msg_didout = FALSE;
+ msg_didout = false;
msg_col = 0;
ui_flush();
}
@@ -3970,17 +4131,18 @@ static wordnode_T *get_wordnode(spellinfo_T *spin)
{
wordnode_T *n;
- if (spin->si_first_free == NULL)
+ if (spin->si_first_free == NULL) {
n = (wordnode_T *)getroom(spin, sizeof(wordnode_T), true);
- else {
+ } else {
n = spin->si_first_free;
spin->si_first_free = n->wn_child;
memset(n, 0, sizeof(wordnode_T));
--spin->si_free_count;
}
#ifdef SPELL_PRINTTREE
- if (n != NULL)
+ if (n != NULL) {
n->wn_nr = ++spin->si_wordnode_nr;
+ }
#endif
return n;
}
@@ -3992,13 +4154,14 @@ static wordnode_T *get_wordnode(spellinfo_T *spin)
static int deref_wordnode(spellinfo_T *spin, wordnode_T *node)
FUNC_ATTR_NONNULL_ALL
{
- wordnode_T *np;
+ wordnode_T *np;
int cnt = 0;
if (--node->wn_refs == 0) {
for (np = node; np != NULL; np = np->wn_sibling) {
- if (np->wn_child != NULL)
+ if (np->wn_child != NULL) {
cnt += deref_wordnode(spin, np->wn_child);
+ }
free_wordnode(spin, np);
++cnt;
}
@@ -4018,8 +4181,7 @@ static void free_wordnode(spellinfo_T *spin, wordnode_T *n)
}
// Compress a tree: find tails that are identical and can be shared.
-static void wordtree_compress(spellinfo_T *spin, wordnode_T *root,
- const char *name)
+static void wordtree_compress(spellinfo_T *spin, wordnode_T *root, const char *name)
FUNC_ATTR_NONNULL_ALL
{
hashtab_T ht;
@@ -4036,12 +4198,13 @@ static void wordtree_compress(spellinfo_T *spin, wordnode_T *root,
if (spin->si_verbose || p_verbose > 2)
#endif
{
- if (tot > 1000000)
+ if (tot > 1000000) {
perc = (tot - n) / (tot / 100);
- else if (tot == 0)
+ } else if (tot == 0) {
perc = 0;
- else
+ } else {
perc = (tot - n) * 100 / tot;
+ }
vim_snprintf((char *)IObuff, IOSIZE,
_("Compressed %s of %ld nodes; %ld (%ld%%) remaining"),
name, tot, tot - n, perc);
@@ -4054,22 +4217,18 @@ static void wordtree_compress(spellinfo_T *spin, wordnode_T *root,
}
}
-// Compress a node, its siblings and its children, depth first.
-// Returns the number of compressed nodes.
-static long node_compress(
- spellinfo_T *spin,
- wordnode_T *node,
- hashtab_T *ht,
- long *tot // total count of nodes before compressing,
- // incremented while going through the tree
-)
+/// Compress a node, its siblings and its children, depth first.
+/// Returns the number of compressed nodes.
+///
+/// @param tot total count of nodes before compressing, incremented while going through the tree
+static long node_compress(spellinfo_T *spin, wordnode_T *node, hashtab_T *ht, long *tot)
FUNC_ATTR_NONNULL_ALL
{
- wordnode_T *np;
- wordnode_T *tp;
- wordnode_T *child;
+ wordnode_T *np;
+ wordnode_T *tp;
+ wordnode_T *child;
hash_T hash;
- hashitem_T *hi;
+ hashitem_T *hi;
long len = 0;
unsigned nr, n;
long compressed = 0;
@@ -4092,7 +4251,7 @@ static long node_compress(
// There are children we encountered before with a hash value
// identical to the current child. Now check if there is one
// that is really identical.
- for (tp = HI2WN(hi); tp != NULL; tp = tp->wn_u2.next)
+ for (tp = HI2WN(hi); tp != NULL; tp = tp->wn_u2.next) {
if (node_equal(child, tp)) {
// Found one! Now use that child in place of the
// current one. This means the current child and all
@@ -4102,6 +4261,7 @@ static long node_compress(
np->wn_child = tp;
break;
}
+ }
if (tp == NULL) {
// No other child with this hash value equals the child of
// the node, add it to the linked list after the first
@@ -4110,10 +4270,11 @@ static long node_compress(
child->wn_u2.next = tp->wn_u2.next;
tp->wn_u2.next = child;
}
- } else
+ } else {
// No other child has this hash value, add it to the
// hashtable.
hash_add_item(ht, hi, child->wn_u1.hashkey, hash);
+ }
}
}
*tot += len + 1; // add one for the node that stores the length
@@ -4124,12 +4285,13 @@ static long node_compress(
node->wn_u1.hashkey[0] = len;
nr = 0;
for (np = node; np != NULL; np = np->wn_sibling) {
- if (np->wn_byte == NUL)
+ if (np->wn_byte == NUL) {
// end node: use wn_flags, wn_region and wn_affixID
n = np->wn_flags + (np->wn_region << 8) + (np->wn_affixID << 16);
- else
+ } else {
// byte node: use the byte value and the child pointer
n = (unsigned)(np->wn_byte + ((uintptr_t)np->wn_child << 8));
+ }
nr = nr * 101 + n;
}
@@ -4153,18 +4315,20 @@ static long node_compress(
// Returns true when two nodes have identical siblings and children.
static bool node_equal(wordnode_T *n1, wordnode_T *n2)
{
- wordnode_T *p1;
- wordnode_T *p2;
+ wordnode_T *p1;
+ wordnode_T *p2;
for (p1 = n1, p2 = n2; p1 != NULL && p2 != NULL;
- p1 = p1->wn_sibling, p2 = p2->wn_sibling)
+ p1 = p1->wn_sibling, p2 = p2->wn_sibling) {
if (p1->wn_byte != p2->wn_byte
|| (p1->wn_byte == NUL
? (p1->wn_flags != p2->wn_flags
|| p1->wn_region != p2->wn_region
|| p1->wn_affixID != p2->wn_affixID)
- : (p1->wn_child != p2->wn_child)))
+ : (p1->wn_child != p2->wn_child))) {
break;
+ }
+ }
return p1 == NULL && p2 == NULL;
}
@@ -4173,8 +4337,8 @@ static bool node_equal(wordnode_T *n1, wordnode_T *n2)
// Function given to qsort() to sort the REP items on "from" string.
static int rep_compare(const void *s1, const void *s2)
{
- fromto_T *p1 = (fromto_T *)s1;
- fromto_T *p2 = (fromto_T *)s2;
+ fromto_T *p1 = (fromto_T *)s1;
+ fromto_T *p2 = (fromto_T *)s2;
return STRCMP(p1->ft_from, p2->ft_from);
}
@@ -4195,9 +4359,10 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname)
// <HEADER>: <fileID> <versionnr>
// <fileID>
size_t fwv = fwrite(VIMSPELLMAGIC, VIMSPELLMAGICL, 1, fd);
- if (fwv != (size_t)1)
+ if (fwv != (size_t)1) {
// Catch first write error, don't try writing more.
goto theend;
+ }
putc(VIMSPELLVERSION, fd); // <versionnr>
@@ -4222,8 +4387,9 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname)
fwv &= fwrite(spin->si_region_name, l, 1, fd);
// <regionname> ...
regionmask = (1 << spin->si_region_count) - 1;
- } else
+ } else {
regionmask = 0;
+ }
// SN_CHARFLAGS: <charflagslen> <charflags> <folcharslen> <folchars>
//
@@ -4251,10 +4417,12 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname)
fputc(128, fd); // <charflagslen>
for (size_t i = 128; i < 256; ++i) {
flags = 0;
- if (spelltab.st_isw[i])
+ if (spelltab.st_isw[i]) {
flags |= CF_WORD;
- if (spelltab.st_isu[i])
+ }
+ if (spelltab.st_isu[i]) {
flags |= CF_UPPER;
+ }
fputc(flags, fd); // <charflags>
}
@@ -4293,24 +4461,28 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname)
// round 3: SN_REPSAL section
for (unsigned int round = 1; round <= 3; ++round) {
garray_T *gap;
- if (round == 1)
+ if (round == 1) {
gap = &spin->si_rep;
- else if (round == 2) {
+ } else if (round == 2) {
// Don't write SN_SAL when using a SN_SOFO section
- if (spin->si_sofofr != NULL && spin->si_sofoto != NULL)
+ if (spin->si_sofofr != NULL && spin->si_sofoto != NULL) {
continue;
+ }
gap = &spin->si_sal;
- } else
+ } else {
gap = &spin->si_repsal;
+ }
// Don't write the section if there are no items.
- if (GA_EMPTY(gap))
+ if (GA_EMPTY(gap)) {
continue;
+ }
// Sort the REP/REPSAL items.
- if (round != 2)
+ if (round != 2) {
qsort(gap->ga_data, (size_t)gap->ga_len,
- sizeof(fromto_T), rep_compare);
+ sizeof(fromto_T), rep_compare);
+ }
int sect_id = round == 1 ? SN_REP : (round == 2 ? SN_SAL : SN_REPSAL);
putc(sect_id, fd); // <sectionID>
@@ -4326,18 +4498,22 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname)
l += 1 + STRLEN(ftp->ft_from); // count <*fromlen> and <*from>
l += 1 + STRLEN(ftp->ft_to); // count <*tolen> and <*to>
}
- if (round == 2)
+ if (round == 2) {
++l; // count <salflags>
+ }
put_bytes(fd, l, 4); // <sectionlen>
if (round == 2) {
int i = 0;
- if (spin->si_followup)
+ if (spin->si_followup) {
i |= SAL_F0LLOWUP;
- if (spin->si_collapse)
+ }
+ if (spin->si_collapse) {
i |= SAL_COLLAPSE;
- if (spin->si_rem_accents)
+ }
+ if (spin->si_rem_accents) {
i |= SAL_REM_ACCENTS;
+ }
putc(i, fd); // <salflags>
}
@@ -4351,11 +4527,11 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname)
l = STRLEN(p);
assert(l < INT_MAX);
putc((int)l, fd);
- if (l > 0)
+ if (l > 0) {
fwv &= fwrite(p, l, 1, fd);
+ }
}
}
-
}
// SN_SOFO: <sofofromlen> <sofofrom> <sofotolen> <sofoto>
@@ -4386,19 +4562,22 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname)
for (unsigned int round = 1; round <= 2; ++round) {
size_t todo;
size_t len = 0;
- hashitem_T *hi;
+ hashitem_T *hi;
todo = spin->si_commonwords.ht_used;
- for (hi = spin->si_commonwords.ht_array; todo > 0; ++hi)
+ for (hi = spin->si_commonwords.ht_array; todo > 0; ++hi) {
if (!HASHITEM_EMPTY(hi)) {
size_t l = STRLEN(hi->hi_key) + 1;
len += l;
- if (round == 2) // <word>
+ if (round == 2) { // <word>
fwv &= fwrite(hi->hi_key, l, 1, fd);
+ }
--todo;
}
- if (round == 1)
+ }
+ if (round == 1) {
put_bytes(fd, len, 4); // <sectionlen>
+ }
}
}
@@ -4506,12 +4685,13 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname)
spin->si_memtot = 0;
for (unsigned int round = 1; round <= 3; ++round) {
wordnode_T *tree;
- if (round == 1)
+ if (round == 1) {
tree = spin->si_foldroot->wn_sibling;
- else if (round == 2)
+ } else if (round == 2) {
tree = spin->si_keeproot->wn_sibling;
- else
+ } else {
tree = spin->si_prefroot->wn_sibling;
+ }
// Clear the index and wnode fields in the tree.
clear_node(tree);
@@ -4531,16 +4711,20 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname)
}
// Write another byte to check for errors (file system full).
- if (putc(0, fd) == EOF)
+ if (putc(0, fd) == EOF) {
retval = FAIL;
+ }
theend:
- if (fclose(fd) == EOF)
+ if (fclose(fd) == EOF) {
retval = FAIL;
+ }
- if (fwv != (size_t)1)
+ if (fwv != (size_t)1) {
retval = FAIL;
- if (retval == FAIL)
+ }
+ if (retval == FAIL) {
EMSG(_(e_write));
+ }
return retval;
}
@@ -4550,54 +4734,54 @@ theend:
// space.
static void clear_node(wordnode_T *node)
{
- wordnode_T *np;
+ wordnode_T *np;
- if (node != NULL)
+ if (node != NULL) {
for (np = node; np != NULL; np = np->wn_sibling) {
np->wn_u1.index = 0;
np->wn_u2.wnode = NULL;
- if (np->wn_byte != NUL)
+ if (np->wn_byte != NUL) {
clear_node(np->wn_child);
+ }
}
+ }
}
-// Dump a word tree at node "node".
-//
-// This first writes the list of possible bytes (siblings). Then for each
-// byte recursively write the children.
-//
-// NOTE: The code here must match the code in read_tree_node(), since
-// assumptions are made about the indexes (so that we don't have to write them
-// in the file).
-//
-// Returns the number of nodes used.
-static int
-put_node (
- FILE *fd, // NULL when only counting
- wordnode_T *node,
- int idx,
- int regionmask,
- bool prefixtree // true for PREFIXTREE
-)
+/// Dump a word tree at node "node".
+///
+/// This first writes the list of possible bytes (siblings). Then for each
+/// byte recursively write the children.
+///
+/// NOTE: The code here must match the code in read_tree_node(), since
+/// assumptions are made about the indexes (so that we don't have to write them
+/// in the file).
+///
+/// @param fd NULL when only counting
+/// @param prefixtree true for PREFIXTREE
+///
+/// @return the number of nodes used.
+static int put_node(FILE *fd, wordnode_T *node, int idx, int regionmask, bool prefixtree)
{
// If "node" is zero the tree is empty.
- if (node == NULL)
+ if (node == NULL) {
return 0;
+ }
// Store the index where this node is written.
node->wn_u1.index = idx;
// Count the number of siblings.
int siblingcount = 0;
- for (wordnode_T *np = node; np != NULL; np = np->wn_sibling)
+ for (wordnode_T *np = node; np != NULL; np = np->wn_sibling) {
++siblingcount;
+ }
// Write the sibling count.
- if (fd != NULL)
+ if (fd != NULL) {
putc(siblingcount, fd); // <siblingcount>
-
+ }
// Write each sibling byte and optionally extra info.
for (wordnode_T *np = node; np != NULL; np = np->wn_sibling) {
if (np->wn_byte == 0) {
@@ -4608,9 +4792,9 @@ put_node (
// associated condition nr (stored in wn_region). The
// byte value is misused to store the "rare" and "not
// combining" flags
- if (np->wn_flags == (uint16_t)PFX_FLAGS)
+ if (np->wn_flags == (uint16_t)PFX_FLAGS) {
putc(BY_NOFLAGS, fd); // <byte>
- else {
+ } else {
putc(BY_FLAGS, fd); // <byte>
putc(np->wn_flags, fd); // <pflags>
}
@@ -4619,10 +4803,12 @@ put_node (
} else {
// For word trees we write the flag/region items.
int flags = np->wn_flags;
- if (regionmask != 0 && np->wn_region != regionmask)
+ if (regionmask != 0 && np->wn_region != regionmask) {
flags |= WF_REGION;
- if (np->wn_affixID != 0)
+ }
+ if (np->wn_affixID != 0) {
flags |= WF_AFX;
+ }
if (flags == 0) {
// word without flags or region
putc(BY_NOFLAGS, fd); // <byte>
@@ -4635,10 +4821,12 @@ put_node (
putc(BY_FLAGS, fd); // <byte>
putc(flags, fd); // <flags>
}
- if (flags & WF_REGION)
+ if (flags & WF_REGION) {
putc(np->wn_region, fd); // <region>
- if (flags & WF_AFX)
+ }
+ if (flags & WF_AFX) {
putc(np->wn_affixID, fd); // <affixID>
+ }
}
}
}
@@ -4650,15 +4838,17 @@ put_node (
putc(BY_INDEX, fd); // <byte>
put_bytes(fd, (uintmax_t)np->wn_child->wn_u1.index, 3); // <nodeidx>
}
- } else if (np->wn_child->wn_u2.wnode == NULL)
+ } else if (np->wn_child->wn_u2.wnode == NULL) {
// We will write the child below and give it an index.
np->wn_child->wn_u2.wnode = node;
+ }
- if (fd != NULL)
+ if (fd != NULL) {
if (putc(np->wn_byte, fd) == EOF) { // <byte> or <xbyte>
EMSG(_(e_write));
return 0;
}
+ }
}
}
@@ -4667,10 +4857,12 @@ put_node (
int newindex = idx + siblingcount + 1;
// Recursively dump the children of each sibling.
- for (wordnode_T *np = node; np != NULL; np = np->wn_sibling)
- if (np->wn_byte != 0 && np->wn_child->wn_u2.wnode == node)
+ for (wordnode_T *np = node; np != NULL; np = np->wn_sibling) {
+ if (np->wn_byte != 0 && np->wn_child->wn_u2.wnode == node) {
newindex = put_node(fd, np->wn_child, newindex, regionmask,
- prefixtree);
+ prefixtree);
+ }
+ }
return newindex;
}
@@ -4681,8 +4873,8 @@ put_node (
void ex_mkspell(exarg_T *eap)
{
int fcount;
- char_u **fnames;
- char_u *arg = eap->arg;
+ char_u **fnames;
+ char_u *arg = eap->arg;
bool ascii = false;
if (STRNCMP(arg, "-ascii", 6) == 0) {
@@ -4702,9 +4894,9 @@ void ex_mkspell(exarg_T *eap)
// Writes the file with the name "wfname", with ".spl" changed to ".sug".
static void spell_make_sugfile(spellinfo_T *spin, char_u *wfname)
{
- char_u *fname = NULL;
+ char_u *fname = NULL;
int len;
- slang_T *slang;
+ slang_T *slang;
bool free_slang = false;
// Read back the .spl file that was written. This fills the required
@@ -4721,8 +4913,9 @@ static void spell_make_sugfile(spellinfo_T *spin, char_u *wfname)
if (slang == NULL) {
spell_message(spin, (char_u *)_("Reading back spell file..."));
slang = spell_load_file(wfname, NULL, NULL, false);
- if (slang == NULL)
+ if (slang == NULL) {
return;
+ }
free_slang = true;
}
@@ -4737,15 +4930,17 @@ static void spell_make_sugfile(spellinfo_T *spin, char_u *wfname)
// Go through the trie of good words, soundfold each word and add it to
// the soundfold trie.
spell_message(spin, (char_u *)_("Performing soundfolding..."));
- if (sug_filltree(spin, slang) == FAIL)
+ if (sug_filltree(spin, slang) == FAIL) {
goto theend;
+ }
// Create the table which links each soundfold word with a list of the
// good words it may come from. Creates buffer "spin->si_spellbuf".
// This also removes the wordnr from the NUL byte entries to make
// compression possible.
- if (sug_maketable(spin) == FAIL)
+ if (sug_maketable(spin) == FAIL) {
goto theend;
+ }
smsg(_("Number of words after soundfolding: %" PRId64),
(int64_t)spin->si_spellbuf->b_ml.ml_line_count);
@@ -4765,8 +4960,9 @@ static void spell_make_sugfile(spellinfo_T *spin, char_u *wfname)
theend:
xfree(fname);
- if (free_slang)
+ if (free_slang) {
slang_free(slang);
+ }
free_blocks(spin->si_blocks);
close_spellbuf(spin->si_spellbuf);
}
@@ -4774,8 +4970,8 @@ theend:
// Build the soundfold trie for language "slang".
static int sug_filltree(spellinfo_T *spin, slang_T *slang)
{
- char_u *byts;
- idx_T *idxs;
+ char_u *byts;
+ idx_T *idxs;
int depth;
idx_T arridx[MAXWLEN];
int curi[MAXWLEN];
@@ -4806,13 +5002,13 @@ static int sug_filltree(spellinfo_T *spin, slang_T *slang)
if (curi[depth] > byts[arridx[depth]]) {
// Done all bytes at this node, go up one level.
idxs[arridx[depth]] = wordcount[depth];
- if (depth > 0)
+ if (depth > 0) {
wordcount[depth - 1] += wordcount[depth];
+ }
--depth;
line_breakcheck();
} else {
-
// Do one more byte at this node.
n = arridx[depth] + curi[depth];
++curi[depth];
@@ -4826,9 +5022,10 @@ static int sug_filltree(spellinfo_T *spin, slang_T *slang)
// We use the "flags" field for the MSB of the wordnr,
// "region" for the LSB of the wordnr.
if (tree_add_word(spin, tsalword, spin->si_foldroot,
- words_done >> 16, words_done & 0xffff,
- 0) == FAIL)
+ words_done >> 16, words_done & 0xffff,
+ 0) == FAIL) {
return FAIL;
+ }
++words_done;
++wordcount[depth];
@@ -4877,25 +5074,22 @@ static int sug_maketable(spellinfo_T *spin)
ga_init(&ga, 1, 100);
// recursively go through the tree
- if (sug_filltable(spin, spin->si_foldroot->wn_sibling, 0, &ga) == -1)
+ if (sug_filltable(spin, spin->si_foldroot->wn_sibling, 0, &ga) == -1) {
res = FAIL;
+ }
ga_clear(&ga);
return res;
}
-// Fill the table for one node and its children.
-// Returns the wordnr at the start of the node.
-// Returns -1 when out of memory.
-static int
-sug_filltable (
- spellinfo_T *spin,
- wordnode_T *node,
- int startwordnr,
- garray_T *gap // place to store line of numbers
-)
+/// Fill the table for one node and its children.
+/// Returns the wordnr at the start of the node.
+/// Returns -1 when out of memory.
+///
+/// @param gap place to store line of numbers
+static int sug_filltable(spellinfo_T *spin, wordnode_T *node, int startwordnr, garray_T *gap)
{
- wordnode_T *p, *np;
+ wordnode_T *p, *np;
int wordnr = startwordnr;
int nr;
int prev_nr;
@@ -4915,7 +5109,7 @@ sug_filltable (
nr -= prev_nr;
prev_nr += nr;
gap->ga_len += offset2bytes(nr,
- (char_u *)gap->ga_data + gap->ga_len);
+ (char_u *)gap->ga_data + gap->ga_len);
}
// add the NUL byte
@@ -4929,8 +5123,9 @@ sug_filltable (
// Remove extra NUL entries, we no longer need them. We don't
// bother freeing the nodes, the won't be reused anyway.
- while (p->wn_sibling != NULL && p->wn_sibling->wn_byte == NUL)
+ while (p->wn_sibling != NULL && p->wn_sibling->wn_byte == NUL) {
p->wn_sibling = p->wn_sibling->wn_sibling;
+ }
// Clear the flags on the remaining NUL node, so that compression
// works a lot better.
@@ -4938,8 +5133,9 @@ sug_filltable (
p->wn_region = 0;
} else {
wordnr = sug_filltable(spin, p->wn_child, wordnr, gap);
- if (wordnr == -1)
+ if (wordnr == -1) {
return -1;
+ }
}
}
return wordnr;
@@ -4999,7 +5195,7 @@ static void sug_write(spellinfo_T *spin, char_u *fname)
spell_message(spin, IObuff);
// <SUGHEADER>: <fileID> <versionnr> <timestamp>
- if (fwrite(VIMSUGMAGIC, VIMSUGMAGICL, (size_t)1, fd) != 1) { // <fileID>
+ if (fwrite(VIMSUGMAGIC, VIMSUGMAGICL, (size_t)1, fd) != 1) { // <fileID>
EMSG(_(e_write));
goto theend;
}
@@ -5035,7 +5231,7 @@ static void sug_write(spellinfo_T *spin, char_u *fname)
for (linenr_T lnum = 1; lnum <= wcount; ++lnum) {
// <sugline>: <sugnr> ... NUL
- char_u *line = ml_get_buf(spin->si_spellbuf, lnum, FALSE);
+ char_u *line = ml_get_buf(spin->si_spellbuf, lnum, false);
size_t len = STRLEN(line) + 1;
if (fwrite(line, len, 1, fd) == 0) {
EMSG(_(e_write));
@@ -5046,11 +5242,12 @@ static void sug_write(spellinfo_T *spin, char_u *fname)
}
// Write another byte to check for errors.
- if (putc(0, fd) == EOF)
+ if (putc(0, fd) == EOF) {
EMSG(_(e_write));
+ }
vim_snprintf((char *)IObuff, IOSIZE,
- _("Estimated runtime memory use: %d bytes"), spin->si_memtot);
+ _("Estimated runtime memory use: %d bytes"), spin->si_memtot);
spell_message(spin, IObuff);
theend:
@@ -5059,23 +5256,20 @@ theend:
}
-// 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.
-// Exception: when "fnames[0]" ends in ".add" it's used as the input file name
-// and ".spl" is appended to make the output file name.
-static void
-mkspell (
- int fcount,
- char_u **fnames,
- bool ascii, // -ascii argument given
- bool over_write, // overwrite existing output file
- bool added_word // invoked through "zg"
-)
+/// 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.
+/// Exception: when "fnames[0]" ends in ".add" it's used as the input file name
+/// and ".spl" is appended to make the output file name.
+///
+/// @param ascii -ascii argument given
+/// @param over_write overwrite existing output file
+/// @param added_word invoked through "zg"
+static void mkspell(int fcount, char_u **fnames, bool ascii, bool over_write, bool added_word)
{
- char_u *fname = NULL;
- char_u *wfname;
- char_u **innames;
+ char_u *fname = NULL;
+ char_u *wfname;
+ char_u **innames;
int incount;
afffile_T *(afile[MAXREGIONS]);
int i;
@@ -5111,26 +5305,29 @@ mkspell (
// "path/en.latin1.add.spl".
incount = 1;
vim_snprintf((char *)wfname, MAXPATHL, "%s.spl", fnames[0]);
- } else if (fcount == 1) {
+ } else if (fcount == 1) {
// For ":mkspell path/vim" output file is "path/vim.latin1.spl".
incount = 1;
vim_snprintf((char *)wfname, MAXPATHL, SPL_FNAME_TMPL,
- fnames[0], spin.si_ascii ? (char_u *)"ascii" : spell_enc());
- } else if (len > 4 && STRCMP(fnames[0] + len - 4, ".spl") == 0) {
+ fnames[0], spin.si_ascii ? (char_u *)"ascii" : spell_enc());
+ } else if (len > 4 && STRCMP(fnames[0] + len - 4, ".spl") == 0) {
// Name ends in ".spl", use as the file name.
STRLCPY(wfname, fnames[0], MAXPATHL);
- } else
+ } else {
// Name should be language, make the file name from it.
vim_snprintf((char *)wfname, MAXPATHL, SPL_FNAME_TMPL,
- fnames[0], spin.si_ascii ? (char_u *)"ascii" : spell_enc());
+ fnames[0], spin.si_ascii ? (char_u *)"ascii" : spell_enc());
+ }
// Check for .ascii.spl.
- if (strstr((char *)path_tail(wfname), SPL_FNAME_ASCII) != NULL)
+ if (strstr((char *)path_tail(wfname), SPL_FNAME_ASCII) != NULL) {
spin.si_ascii = true;
+ }
// Check for .add.spl.
- if (strstr((char *)path_tail(wfname), SPL_FNAME_ADD) != NULL)
+ if (strstr((char *)path_tail(wfname), SPL_FNAME_ADD) != NULL) {
spin.si_add = true;
+ }
}
if (incount <= 0) {
@@ -5181,8 +5378,9 @@ mkspell (
// one in the .spl file if the .aff file doesn't define one. That's
// better than guessing the contents, the table will match a
// previously loaded spell file.
- if (!spin.si_add)
+ if (!spin.si_add) {
spin.si_clear_chartab = true;
+ }
// Read all the .aff and .dic files.
// Text is converted to 'encoding'.
@@ -5196,28 +5394,31 @@ mkspell (
// Read the .aff file. Will init "spin->si_conv" based on the
// "SET" line.
afile[i] = spell_read_aff(&spin, fname);
- if (afile[i] == NULL)
+ if (afile[i] == NULL) {
error = true;
- else {
+ } else {
// Read the .dic file and store the words in the trees.
vim_snprintf((char *)fname, MAXPATHL, "%s.dic",
- innames[i]);
- if (spell_read_dic(&spin, fname, afile[i]) == FAIL)
+ innames[i]);
+ if (spell_read_dic(&spin, fname, afile[i]) == FAIL) {
error = true;
+ }
}
} else {
// No .aff file, try reading the file as a word list. Store
// the words in the trees.
- if (spell_read_wordfile(&spin, innames[i]) == FAIL)
+ if (spell_read_wordfile(&spin, innames[i]) == FAIL) {
error = true;
+ }
}
// Free any conversion stuff.
convert_setup(&spin.si_conv, NULL, NULL);
}
- if (spin.si_compflags != NULL && spin.si_nobreak)
+ if (spin.si_compflags != NULL && spin.si_nobreak) {
MSG(_("Warning: both compounding and NOBREAK specified"));
+ }
if (!error && !got_int) {
// Combine tails in the tree.
@@ -5237,12 +5438,13 @@ mkspell (
spell_message(&spin, (char_u *)_("Done!"));
vim_snprintf((char *)IObuff, IOSIZE,
- _("Estimated runtime memory use: %d bytes"), spin.si_memtot);
+ _("Estimated runtime memory use: %d bytes"), spin.si_memtot);
spell_message(&spin, IObuff);
// If the file is loaded need to reload it.
- if (!error)
+ if (!error) {
spell_reload_one(wfname, added_word);
+ }
}
// Free the allocated memory.
@@ -5255,18 +5457,20 @@ mkspell (
hash_clear_all(&spin.si_commonwords, 0);
// Free the .aff file structures.
- for (i = 0; i < incount; ++i)
- if (afile[i] != NULL)
+ for (i = 0; i < incount; ++i) {
+ if (afile[i] != NULL) {
spell_free_aff(afile[i]);
+ }
+ }
// Free all the bits and pieces at once.
free_blocks(spin.si_blocks);
// If there is soundfolding info and no NOSUGFILE item create the
// .sug file with the soundfolded word trie.
- if (spin.si_sugtime != 0 && !error && !got_int)
+ if (spin.si_sugtime != 0 && !error && !got_int) {
spell_make_sugfile(&spin, wfname);
-
+ }
}
theend:
@@ -5280,12 +5484,14 @@ static void spell_message(const spellinfo_T *spin, char_u *str)
FUNC_ATTR_NONNULL_ALL
{
if (spin->si_verbose || p_verbose > 2) {
- if (!spin->si_verbose)
+ if (!spin->si_verbose) {
verbose_enter();
+ }
MSG(str);
ui_flush();
- if (!spin->si_verbose)
+ if (!spin->si_verbose) {
verbose_leave();
+ }
}
}
@@ -5302,32 +5508,29 @@ void ex_spell(exarg_T *eap)
eap->cmdidx == CMD_spellundo);
}
-// Add "word[len]" to 'spellfile' as a good or bad word.
-void
-spell_add_word (
- char_u *word,
- int len,
- SpellAddType what, // SPELL_ADD_ values
- int idx, // "zG" and "zW": zero, otherwise index in
- // 'spellfile'
- bool undo // true for "zug", "zuG", "zuw" and "zuW"
-)
+/// Add "word[len]" to 'spellfile' as a good or bad word.
+///
+/// @param what SPELL_ADD_ values
+/// @param idx "zG" and "zW": zero, otherwise index in 'spellfile'
+/// @param bool // true for "zug", "zuG", "zuw" and "zuW"
+void spell_add_word(char_u *word, int len, SpellAddType what, int idx, bool undo)
{
- FILE *fd = NULL;
- buf_T *buf = NULL;
+ FILE *fd = NULL;
+ buf_T *buf = NULL;
bool new_spf = false;
- char_u *fname;
- char_u *fnamebuf = NULL;
+ char_u *fname;
+ char_u *fnamebuf = NULL;
char_u line[MAXWLEN * 2];
long fpos, fpos_next = 0;
int i;
- char_u *spf;
+ char_u *spf;
if (idx == 0) { // use internal wordlist
if (int_wordlist == NULL) {
int_wordlist = vim_tempname();
- if (int_wordlist == NULL)
+ if (int_wordlist == NULL) {
return;
+ }
}
fname = int_wordlist;
} else {
@@ -5345,8 +5548,9 @@ spell_add_word (
for (spf = curwin->w_s->b_p_spf, i = 1; *spf != NUL; ++i) {
copy_option_part(&spf, fnamebuf, MAXPATHL, ",");
- if (i == idx)
+ if (i == idx) {
break;
+ }
if (*spf == NUL) {
EMSGN(_("E765: 'spellfile' does not have %" PRId64 " entries"), idx);
xfree(fnamebuf);
@@ -5356,8 +5560,9 @@ spell_add_word (
// Check that the user isn't editing the .add file somewhere.
buf = buflist_findname_exp(fnamebuf);
- if (buf != NULL && buf->b_ml.ml_mfp == NULL)
+ if (buf != NULL && buf->b_ml.ml_mfp == NULL) {
buf = NULL;
+ }
if (buf != NULL && bufIsChanged(buf)) {
EMSG(_(e_bufloaded));
xfree(fnamebuf);
@@ -5399,8 +5604,9 @@ spell_add_word (
}
}
}
- if (fd != NULL)
+ if (fd != NULL) {
fclose(fd);
+ }
}
}
@@ -5447,8 +5653,9 @@ spell_add_word (
mkspell(1, &fname, false, true, true);
// If the .add file is edited somewhere, reload it.
- if (buf != NULL)
+ if (buf != NULL) {
buf_reload(buf, buf->b_orig_mode);
+ }
redraw_all_later(SOME_VALID);
}
@@ -5458,13 +5665,13 @@ spell_add_word (
// Initialize 'spellfile' for the current buffer.
static void init_spellfile(void)
{
- char_u *buf;
+ char_u *buf;
int l;
- char_u *fname;
- char_u *rtp;
- char_u *lend;
+ char_u *fname;
+ char_u *rtp;
+ char_u *lend;
bool aspath = false;
- char_u *lstart = curbuf->b_s.b_p_spl;
+ char_u *lstart = curbuf->b_s.b_p_spl;
if (*curwin->w_s->b_p_spl != NUL && !GA_EMPTY(&curwin->w_s->b_langp)) {
buf = xmalloc(MAXPATHL);
@@ -5472,31 +5679,33 @@ static void init_spellfile(void)
// Find the end of the language name. Exclude the region. If there
// is a path separator remember the start of the tail.
for (lend = curwin->w_s->b_p_spl; *lend != NUL
- && vim_strchr((char_u *)",._", *lend) == NULL; ++lend)
+ && vim_strchr((char_u *)",._", *lend) == NULL; ++lend) {
if (vim_ispathsep(*lend)) {
aspath = true;
lstart = lend + 1;
}
+ }
// Loop over all entries in 'runtimepath'. Use the first one where we
// are allowed to write.
rtp = p_rtp;
while (*rtp != NUL) {
- if (aspath)
+ if (aspath) {
// Use directory of an entry with path, e.g., for
// "/dir/lg.utf-8.spl" use "/dir".
STRLCPY(buf, curbuf->b_s.b_p_spl,
- lstart - curbuf->b_s.b_p_spl);
- else
+ lstart - curbuf->b_s.b_p_spl);
+ } else {
// Copy the path from 'runtimepath' to buf[].
copy_option_part(&rtp, buf, MAXPATHL, ",");
+ }
if (os_file_is_writable((char *)buf) == 2) {
// Use the first language name from 'spelllang' and the
// encoding used in the first loaded .spl file.
- if (aspath)
+ if (aspath) {
STRLCPY(buf, curbuf->b_s.b_p_spl,
- lend - curbuf->b_s.b_p_spl + 1);
- else {
+ lend - curbuf->b_s.b_p_spl + 1);
+ } else {
// Create the "spell" directory if it doesn't exist yet.
l = (int)STRLEN(buf);
vim_snprintf((char *)buf + l, MAXPATHL - l, "/spell");
@@ -5506,7 +5715,7 @@ static void init_spellfile(void)
l = (int)STRLEN(buf);
vim_snprintf((char *)buf + l, MAXPATHL - l,
- "/%.*s", (int)(lend - lstart), lstart);
+ "/%.*s", (int)(lend - lstart), lstart);
}
l = (int)STRLEN(buf);
fname = LANGP_ENTRY(curwin->w_s->b_langp, 0)
@@ -5526,19 +5735,16 @@ static void init_spellfile(void)
}
}
-// Set the spell character tables from strings in the .spl file.
-static void
-set_spell_charflags (
- char_u *flags,
- int cnt, // length of "flags"
- char_u *fol
-)
+/// Set the spell character tables from strings in the .spl file.
+///
+/// @param cnt length of "flags"
+static void set_spell_charflags(char_u *flags, int cnt, char_u *fol)
{
// We build the new tables here first, so that we can compare with the
// previous one.
spelltab_T new_st;
int i;
- char_u *p = fol;
+ char_u *p = fol;
int c;
clear_spell_chartab(&new_st);
@@ -5552,8 +5758,9 @@ set_spell_charflags (
if (*p != NUL) {
c = mb_ptr2char_adv((const char_u **)&p);
new_st.st_fold[i + 128] = c;
- if (i + 128 != c && new_st.st_isu[i + 128] && c < 256)
+ if (i + 128 != c && new_st.st_isu[i + 128] && c < 256) {
new_st.st_upper[c] = i + 128;
+ }
}
}
@@ -5590,9 +5797,9 @@ static int write_spell_prefcond(FILE *fd, garray_T *gap)
{
assert(gap->ga_len >= 0);
- if (fd != NULL)
+ if (fd != NULL) {
put_bytes(fd, (uintmax_t)gap->ga_len, 2); // <prefcondcnt>
-
+ }
size_t totlen = 2 + (size_t)gap->ga_len; // <prefcondcnt> and <condlen> bytes
size_t x = 1; // collect return value of fwrite()
for (int i = 0; i < gap->ga_len; ++i) {
@@ -5606,8 +5813,9 @@ static int write_spell_prefcond(FILE *fd, garray_T *gap)
x &= fwrite(p, len, 1, fd);
}
totlen += len;
- } else if (fd != NULL)
+ } else if (fd != NULL) {
fputc(0, fd);
+ }
}
assert(totlen <= INT_MAX);
@@ -5617,7 +5825,7 @@ static int write_spell_prefcond(FILE *fd, garray_T *gap)
// Use map string "map" for languages "lp".
static void set_map_str(slang_T *lp, char_u *map)
{
- char_u *p;
+ char_u *p;
int headc = 0;
int c;
int i;
@@ -5629,8 +5837,9 @@ static void set_map_str(slang_T *lp, char_u *map)
lp->sl_has_map = true;
// Init the array and hash tables empty.
- for (i = 0; i < 256; ++i)
+ for (i = 0; i < 256; ++i) {
lp->sl_map_array[i] = 0;
+ }
hash_init(&lp->sl_map_hash);
// The similar characters are stored separated with slashes:
@@ -5651,9 +5860,9 @@ static void set_map_str(slang_T *lp, char_u *map)
if (c >= 256) {
int cl = mb_char2len(c);
int headcl = mb_char2len(headc);
- char_u *b;
+ char_u *b;
hash_T hash;
- hashitem_T *hi;
+ hashitem_T *hi;
b = xmalloc(cl + headcl + 2);
utf_char2bytes(c, b);
@@ -5670,8 +5879,9 @@ static void set_map_str(slang_T *lp, char_u *map)
EMSG(_("E783: duplicate char in MAP entry"));
xfree(b);
}
- } else
+ } else {
lp->sl_map_array[c] = headc;
+ }
}
}
}
diff --git a/src/nvim/state.c b/src/nvim/state.c
index a3c74789d1..a9f3d67849 100644
--- a/src/nvim/state.c
+++ b/src/nvim/state.c
@@ -3,19 +3,18 @@
#include <assert.h>
-#include "nvim/lib/kvec.h"
-
#include "nvim/ascii.h"
+#include "nvim/edit.h"
+#include "nvim/ex_docmd.h"
+#include "nvim/getchar.h"
+#include "nvim/lib/kvec.h"
#include "nvim/log.h"
-#include "nvim/state.h"
-#include "nvim/vim.h"
#include "nvim/main.h"
-#include "nvim/getchar.h"
#include "nvim/option_defs.h"
-#include "nvim/ui.h"
#include "nvim/os/input.h"
-#include "nvim/ex_docmd.h"
-#include "nvim/edit.h"
+#include "nvim/state.h"
+#include "nvim/ui.h"
+#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "state.c.generated.h"
@@ -144,6 +143,9 @@ char *get_mode(void)
buf[0] = (char)(VIsual_mode + 's' - 'v');
} else {
buf[0] = (char)VIsual_mode;
+ if (restart_VIsual_select) {
+ buf[1] = 's';
+ }
}
} else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
|| State == CONFIRM) {
@@ -171,12 +173,10 @@ char *get_mode(void)
buf[1] = 'x';
}
}
- } else if ((State & CMDLINE) || exmode_active) {
+ } else if (State & CMDLINE) {
buf[0] = 'c';
- if (exmode_active == EXMODE_VIM) {
+ if (exmode_active) {
buf[1] = 'v';
- } else if (exmode_active == EXMODE_NORMAL) {
- buf[1] = 'e';
}
} else if (State & TERM_FOCUS) {
buf[0] = 't';
diff --git a/src/nvim/strings.c b/src/nvim/strings.c
index cb66f7682d..79a3db4843 100644
--- a/src/nvim/strings.c
+++ b/src/nvim/strings.c
@@ -190,6 +190,7 @@ char_u *vim_strsave_shellescape(const char_u *string,
char_u *escaped_string;
size_t l;
int csh_like;
+ bool fish_like;
/* Only csh and similar shells expand '!' within single quotes. For sh and
* the like we must not put a backslash before it, it will be taken
@@ -197,6 +198,10 @@ char_u *vim_strsave_shellescape(const char_u *string,
* Csh also needs to have "\n" escaped twice when do_special is set. */
csh_like = csh_like_shell();
+ // Fish shell uses '\' as an escape character within single quotes, so '\'
+ // itself must be escaped to get a literal '\'.
+ fish_like = fish_like_shell();
+
/* First count the number of extra bytes required. */
size_t length = STRLEN(string) + 3; // two quotes and a trailing NUL
for (const char_u *p = string; *p != NUL; MB_PTR_ADV(p)) {
@@ -220,6 +225,9 @@ char_u *vim_strsave_shellescape(const char_u *string,
++length; /* insert backslash */
p += l - 1;
}
+ if (*p == '\\' && fish_like) {
+ length++; // insert backslash
+ }
}
/* Allocate memory for the result and fill it. */
@@ -267,6 +275,11 @@ char_u *vim_strsave_shellescape(const char_u *string,
*d++ = *p++;
continue;
}
+ if (*p == '\\' && fish_like) {
+ *d++ = '\\';
+ *d++ = *p++;
+ continue;
+ }
MB_COPY_CHAR(p, d);
}
@@ -964,7 +977,7 @@ int vim_vsnprintf_typval(
break;
}
}
- str_arg_l = precision = (size_t)(p1 - (char_u *)str_arg);
+ str_arg_l = (size_t)(p1 - (char_u *)str_arg);
}
}
break;
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index ce81f26d38..d2c94d9fe8 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -9,13 +9,12 @@
#include <ctype.h>
#include <inttypes.h>
#include <stdbool.h>
-#include <string.h>
#include <stdlib.h>
+#include <string.h>
-#include "nvim/vim.h"
-#include "nvim/ascii.h"
#include "nvim/api/private/helpers.h"
-#include "nvim/syntax.h"
+#include "nvim/ascii.h"
+#include "nvim/buffer.h"
#include "nvim/charset.h"
#include "nvim/cursor_shape.h"
#include "nvim/eval.h"
@@ -23,39 +22,40 @@
#include "nvim/ex_docmd.h"
#include "nvim/fileio.h"
#include "nvim/fold.h"
+#include "nvim/garray.h"
#include "nvim/hashtab.h"
#include "nvim/highlight.h"
#include "nvim/indent_c.h"
+#include "nvim/keymap.h"
+#include "nvim/macros.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
-#include "nvim/keymap.h"
-#include "nvim/garray.h"
#include "nvim/option.h"
+#include "nvim/os/os.h"
+#include "nvim/os/time.h"
#include "nvim/os_unix.h"
#include "nvim/path.h"
-#include "nvim/macros.h"
#include "nvim/regexp.h"
#include "nvim/screen.h"
#include "nvim/sign.h"
#include "nvim/strings.h"
+#include "nvim/syntax.h"
#include "nvim/syntax_defs.h"
#include "nvim/terminal.h"
#include "nvim/ui.h"
-#include "nvim/os/os.h"
-#include "nvim/os/time.h"
-#include "nvim/buffer.h"
+#include "nvim/vim.h"
static bool did_syntax_onoff = false;
/// Structure that stores information about a highlight group.
/// The ID of a highlight group is also called group ID. It is the index in
/// the highlight_ga array PLUS ONE.
-struct hl_group {
- char_u *sg_name; ///< highlight group name
- char_u *sg_name_u; ///< uppercase of sg_name
+typedef struct hl_group {
+ char_u *sg_name; ///< highlight group name
+ char *sg_name_u; ///< uppercase of sg_name
bool sg_cleared; ///< "hi clear" was used
int sg_attr; ///< Screen attr @see ATTR_ENTRY
int sg_link; ///< link to this highlight group ID
@@ -80,7 +80,7 @@ struct hl_group {
char *sg_rgb_sp_name; ///< RGB special color name
int sg_blend; ///< blend level (0-100 inclusive), -1 if unset
-};
+} HlGroup;
/// \addtogroup SG_SET
/// @{
@@ -91,28 +91,29 @@ struct hl_group {
// builtin |highlight-groups|
static garray_T highlight_ga = GA_EMPTY_INIT_VALUE;
+Map(cstr_t, int) highlight_unames = MAP_INIT;
-static inline struct hl_group * HL_TABLE(void)
+static inline struct hl_group *HL_TABLE(void)
{
return ((struct hl_group *)((highlight_ga.ga_data)));
}
-#define MAX_HL_ID 20000 /* maximum value for a highlight ID. */
+#define MAX_HL_ID 20000 // maximum value for a highlight ID.
-/* different types of offsets that are possible */
-#define SPO_MS_OFF 0 /* match start offset */
-#define SPO_ME_OFF 1 /* match end offset */
-#define SPO_HS_OFF 2 /* highl. start offset */
-#define SPO_HE_OFF 3 /* highl. end offset */
-#define SPO_RS_OFF 4 /* region start offset */
-#define SPO_RE_OFF 5 /* region end offset */
-#define SPO_LC_OFF 6 /* leading context offset */
+// different types of offsets that are possible
+#define SPO_MS_OFF 0 // match start offset
+#define SPO_ME_OFF 1 // match end offset
+#define SPO_HS_OFF 2 // highl. start offset
+#define SPO_HE_OFF 3 // highl. end offset
+#define SPO_RS_OFF 4 // region start offset
+#define SPO_RE_OFF 5 // region end offset
+#define SPO_LC_OFF 6 // leading context offset
#define SPO_COUNT 7
-/* Flags to indicate an additional string for highlight name completion. */
-static int include_none = 0; /* when 1 include "nvim/None" */
-static int include_default = 0; /* when 1 include "nvim/default" */
-static int include_link = 0; /* when 2 include "nvim/link" and "clear" */
+// Flags to indicate an additional string for highlight name completion.
+static int include_none = 0; // when 1 include "nvim/None"
+static int include_default = 0; // when 1 include "nvim/default"
+static int include_link = 0; // when 2 include "nvim/link" and "clear"
/// The "term", "cterm" and "gui" arguments can be any combination of the
/// following names, separated by commas (but no spaces!).
@@ -214,12 +215,12 @@ typedef struct {
proftime_T slowest;
proftime_T average;
int id;
- char_u *pattern;
+ char_u *pattern;
} time_entry_T;
struct name_list {
int flag;
- char *name;
+ char *name;
};
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -227,40 +228,40 @@ struct name_list {
#endif
static char *(spo_name_tab[SPO_COUNT]) =
-{"ms=", "me=", "hs=", "he=", "rs=", "re=", "lc="};
+{ "ms=", "me=", "hs=", "he=", "rs=", "re=", "lc=" };
/* The sp_off_flags are computed like this:
* offset from the start of the matched text: (1 << SPO_XX_OFF)
- * offset from the end of the matched text: (1 << (SPO_XX_OFF + SPO_COUNT))
+ * offset from the end of the matched text: (1 << (SPO_XX_OFF + SPO_COUNT))
* When both are present, only one is used.
*/
-#define SPTYPE_MATCH 1 /* match keyword with this group ID */
-#define SPTYPE_START 2 /* match a regexp, start of item */
-#define SPTYPE_END 3 /* match a regexp, end of item */
-#define SPTYPE_SKIP 4 /* match a regexp, skip within item */
+#define SPTYPE_MATCH 1 // match keyword with this group ID
+#define SPTYPE_START 2 // match a regexp, start of item
+#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" */
+#define NONE_IDX -2 // value of sp_sync_idx for "NONE"
/*
* Flags for b_syn_sync_flags:
*/
-#define SF_CCOMMENT 0x01 /* sync on a C-style comment */
-#define SF_MATCH 0x02 /* sync by matching a pattern */
+#define SF_CCOMMENT 0x01 // sync on a C-style comment
+#define SF_MATCH 0x02 // sync by matching a pattern
#define SYN_STATE_P(ssp) ((bufstate_T *)((ssp)->ga_data))
-#define MAXKEYWLEN 80 /* maximum length of a keyword */
+#define MAXKEYWLEN 80 // maximum length of a keyword
/*
* The attributes of the syntax item that has been recognized.
*/
-static int current_attr = 0; /* attr of current syntax word */
-static int current_id = 0; /* ID of current char for syn_get_id() */
-static int current_trans_id = 0; /* idem, transparency removed */
+static int current_attr = 0; // attr of current syntax word
+static int current_id = 0; // ID of current char for syn_get_id()
+static int current_trans_id = 0; // idem, transparency removed
static int current_flags = 0;
static int current_seqnr = 0;
static int current_sub_char = 0;
@@ -268,9 +269,9 @@ static int current_sub_char = 0;
/*
* Methods of combining two clusters
*/
-#define CLUSTER_REPLACE 1 /* replace first list with second */
-#define CLUSTER_ADD 2 /* add second list to first */
-#define CLUSTER_SUBTRACT 3 /* subtract second list from first */
+#define CLUSTER_REPLACE 1 // replace first list with second
+#define CLUSTER_ADD 2 // add second list to first
+#define CLUSTER_SUBTRACT 3 // subtract second list from first
#define SYN_CLSTR(buf) ((syn_cluster_T *)((buf)->b_syn_clusters.ga_data))
@@ -282,12 +283,12 @@ static int current_sub_char = 0;
* 22000 - 22999 CONTAINED indicator (current_syn_inc_tag added)
* 23000 - 32767 cluster IDs (subtract SYNID_CLUSTER for the cluster ID)
*/
-#define SYNID_ALLBUT MAX_HL_ID /* syntax group ID for contains=ALLBUT */
-#define SYNID_TOP 21000 /* syntax group ID for contains=TOP */
-#define SYNID_CONTAINED 22000 /* syntax group ID for contains=CONTAINED */
-#define SYNID_CLUSTER 23000 /* first syntax group ID for clusters */
+#define SYNID_ALLBUT MAX_HL_ID // syntax group ID for contains=ALLBUT
+#define SYNID_TOP 21000 // syntax group ID for contains=TOP
+#define SYNID_CONTAINED 22000 // syntax group ID for contains=CONTAINED
+#define SYNID_CLUSTER 23000 // first syntax group ID for clusters
-#define MAX_SYN_INC_TAG 999 /* maximum before the above overflow */
+#define MAX_SYN_INC_TAG 999 // maximum before the above overflow
#define MAX_CLUSTER_ID (32767 - SYNID_CLUSTER)
/*
@@ -333,7 +334,7 @@ static char msg_no_items[] = N_("No Syntax items defined for this buffer");
// valid of si_cont_list for containing all but contained groups
#define ID_LIST_ALL (int16_t *)-1
-static int next_seqnr = 1; /* value to use for si_seqnr */
+static int next_seqnr = 1; // value to use for si_seqnr
/*
* The next possible match in the current line for any pattern is remembered,
@@ -342,15 +343,15 @@ static int next_seqnr = 1; /* value to use for si_seqnr */
* If next_match_col == MAXCOL, no match found in this line.
* (All end positions have the column of the char after the end)
*/
-static int next_match_col; /* column for start of next match */
-static lpos_T next_match_m_endpos; /* position for end of next match */
-static lpos_T next_match_h_startpos; /* pos. for highl. start of next match */
-static lpos_T next_match_h_endpos; /* pos. for highl. end of next match */
-static int next_match_idx; /* index of matched item */
-static long next_match_flags; /* flags for next match */
-static lpos_T next_match_eos_pos; /* end of start pattn (start region) */
-static lpos_T next_match_eoe_pos; /* pos. for end of end pattern */
-static int next_match_end_idx; /* ID of group for end pattn or zero */
+static int next_match_col; // column for start of next match
+static lpos_T next_match_m_endpos; // position for end of next match
+static lpos_T next_match_h_startpos; // pos. for highl. start of next match
+static lpos_T next_match_h_endpos; // pos. for highl. end of next match
+static int next_match_idx; // index of matched item
+static long next_match_flags; // flags for next match
+static lpos_T next_match_eos_pos; // end of start pattn (start region)
+static lpos_T next_match_eoe_pos; // pos. for end of end pattern
+static int next_match_end_idx; // ID of group for end pattn or zero
static reg_extmatch_T *next_match_extmatch = NULL;
/*
@@ -364,25 +365,25 @@ static reg_extmatch_T *next_match_extmatch = NULL;
* The current state (within the line) of the recognition engine.
* When current_state.ga_itemsize is 0 the current state is invalid.
*/
-static win_T *syn_win; // current window for highlighting
-static buf_T *syn_buf; // current buffer for highlighting
-static synblock_T *syn_block; // current buffer for highlighting
-static proftime_T *syn_tm; // timeout limit
-static linenr_T current_lnum = 0; // lnum of current state
-static colnr_T current_col = 0; // column of current state
-static int current_state_stored = 0; // TRUE if stored current state
- // after setting current_finished
-static int current_finished = 0; // current line has been finished
-static garray_T current_state // current stack of state_items
+static win_T *syn_win; // current window for highlighting
+static buf_T *syn_buf; // current buffer for highlighting
+static synblock_T *syn_block; // current buffer for highlighting
+static proftime_T *syn_tm; // timeout limit
+static linenr_T current_lnum = 0; // lnum of current state
+static colnr_T current_col = 0; // column of current state
+static bool current_state_stored = false; // true if stored current state
+ // after setting current_finished
+static bool current_finished = false; // current line has been finished
+static garray_T current_state // current stack of state_items
= GA_EMPTY_INIT_VALUE;
-static int16_t *current_next_list = NULL; // when non-zero, nextgroup list
-static int current_next_flags = 0; // flags for current_next_list
-static int current_line_id = 0; // unique number for current line
+static int16_t *current_next_list = NULL; // when non-zero, nextgroup list
+static int current_next_flags = 0; // flags for current_next_list
+static int current_line_id = 0; // unique number for current line
#define CUR_STATE(idx) ((stateitem_T *)(current_state.ga_data))[idx]
-static int syn_time_on = FALSE;
-# define IF_SYN_TIME(p) (p)
+static bool syn_time_on = false;
+#define IF_SYN_TIME(p) (p)
// Set the timeout used for syntax highlighting.
// Use NULL to reset, no timeout.
@@ -395,19 +396,19 @@ void syn_set_timeout(proftime_T *tm)
* Start the syntax recognition for a line. This function is normally called
* from the screen updating, once for each displayed line.
* The buffer is remembered in syn_buf, because get_syntax_attr() doesn't get
- * it. Careful: curbuf and curwin are likely to point to another buffer and
+ * it. Careful: curbuf and curwin are likely to point to another buffer and
* window.
*/
void syntax_start(win_T *wp, linenr_T lnum)
{
- synstate_T *p;
- synstate_T *last_valid = NULL;
- synstate_T *last_min_valid = NULL;
- synstate_T *sp, *prev = NULL;
+ synstate_T *p;
+ synstate_T *last_valid = NULL;
+ synstate_T *last_min_valid = NULL;
+ synstate_T *sp, *prev = NULL;
linenr_T parsed_lnum;
linenr_T first_stored;
int dist;
- static int changedtick = 0; /* remember the last change ID */
+ static int changedtick = 0; // remember the last change ID
current_sub_char = NUL;
@@ -430,8 +431,9 @@ void syntax_start(win_T *wp, linenr_T lnum)
* Allocate syntax stack when needed.
*/
syn_stack_alloc();
- if (syn_block->b_sst_array == NULL)
- return; /* out of memory */
+ if (syn_block->b_sst_array == NULL) {
+ return; // out of memory
+ }
syn_block->b_sst_lasttick = display_tick;
/*
@@ -451,29 +453,33 @@ void syntax_start(win_T *wp, linenr_T lnum)
* state (this happens very often!). Otherwise invalidate
* current_state and figure it out below.
*/
- if (current_lnum != lnum)
+ if (current_lnum != lnum) {
invalidate_current_state();
- } else
+ }
+ } else {
invalidate_current_state();
+ }
/*
* Try to synchronize from a saved state in b_sst_array[].
* Only do this if lnum is not before and not to far beyond a saved state.
*/
if (INVALID_STATE(&current_state) && syn_block->b_sst_array != NULL) {
- /* Find last valid saved state before start_lnum. */
+ // Find last valid saved state before start_lnum.
for (p = syn_block->b_sst_first; p != NULL; p = p->sst_next) {
if (p->sst_lnum > lnum) {
break;
}
if (p->sst_change_lnum == 0) {
last_valid = p;
- if (p->sst_lnum >= lnum - syn_block->b_syn_sync_minlines)
+ if (p->sst_lnum >= lnum - syn_block->b_syn_sync_minlines) {
last_min_valid = p;
+ }
}
}
- if (last_min_valid != NULL)
+ if (last_min_valid != NULL) {
load_current_state(last_min_valid);
+ }
}
/*
@@ -482,24 +488,27 @@ void syntax_start(win_T *wp, linenr_T lnum)
*/
if (INVALID_STATE(&current_state)) {
syn_sync(wp, lnum, last_valid);
- if (current_lnum == 1)
- /* First line is always valid, no matter "minlines". */
+ if (current_lnum == 1) {
+ // First line is always valid, no matter "minlines".
first_stored = 1;
- else
+ } else {
/* Need to parse "minlines" lines before state can be considered
* valid to store. */
first_stored = current_lnum + syn_block->b_syn_sync_minlines;
- } else
+ }
+ } else {
first_stored = current_lnum;
+ }
/*
* Advance from the sync point or saved state until the current line.
* Save some entries for syncing with later on.
*/
- if (syn_block->b_sst_len <= Rows)
+ if (syn_block->b_sst_len <= Rows) {
dist = 999999;
- else
+ } else {
dist = syn_buf->b_ml.ml_line_count / (syn_block->b_sst_len - Rows) + 1;
+ }
while (current_lnum < lnum) {
syn_start_line();
(void)syn_finish_line(false);
@@ -511,26 +520,30 @@ void syntax_start(win_T *wp, linenr_T lnum)
/* Check if the saved state entry is for the current line and is
* equal to the current state. If so, then validate all saved
* states that depended on a change before the parsed line. */
- if (prev == NULL)
+ if (prev == NULL) {
prev = syn_stack_find_entry(current_lnum - 1);
- if (prev == NULL)
+ }
+ if (prev == NULL) {
sp = syn_block->b_sst_first;
- else
+ } else {
sp = prev;
- while (sp != NULL && sp->sst_lnum < current_lnum)
+ }
+ while (sp != NULL && sp->sst_lnum < current_lnum) {
sp = sp->sst_next;
+ }
if (sp != NULL
&& sp->sst_lnum == current_lnum
&& syn_stack_equal(sp)) {
parsed_lnum = current_lnum;
prev = sp;
while (sp != NULL && sp->sst_change_lnum <= parsed_lnum) {
- if (sp->sst_lnum <= lnum)
- /* valid state before desired line, use this one */
+ if (sp->sst_lnum <= lnum) {
+ // valid state before desired line, use this one
prev = sp;
- else if (sp->sst_change_lnum == 0)
- /* past saved states depending on change, break here. */
+ } else if (sp->sst_change_lnum == 0) {
+ // past saved states depending on change, break here.
break;
+ }
sp->sst_change_lnum = 0;
sp = sp->sst_next;
}
@@ -541,8 +554,9 @@ void syntax_start(win_T *wp, linenr_T lnum)
* saved state. But only when parsed at least 'minlines'. */
else if (prev == NULL
|| current_lnum == lnum
- || current_lnum >= prev->sst_lnum + dist)
+ || current_lnum >= prev->sst_lnum + dist) {
prev = store_current_state();
+ }
}
/* This can take a long time: break when CTRL-C pressed. The current
@@ -564,7 +578,7 @@ void syntax_start(win_T *wp, linenr_T lnum)
static void clear_syn_state(synstate_T *p)
{
if (p->sst_stacksize > SST_FIX_STATES) {
-# define UNREF_BUFSTATE_EXTMATCH(bs) unref_extmatch((bs)->bs_extmatch)
+#define UNREF_BUFSTATE_EXTMATCH(bs) unref_extmatch((bs)->bs_extmatch)
GA_DEEP_CLEAR(&(p->sst_union.sst_ga), bufstate_T, UNREF_BUFSTATE_EXTMATCH);
} else {
for (int i = 0; i < p->sst_stacksize; i++) {
@@ -578,7 +592,7 @@ static void clear_syn_state(synstate_T *p)
*/
static void clear_current_state(void)
{
-# define UNREF_STATEITEM_EXTMATCH(si) unref_extmatch((si)->si_extmatch)
+#define UNREF_STATEITEM_EXTMATCH(si) unref_extmatch((si)->si_extmatch)
GA_DEEP_CLEAR(&current_state, stateitem_T, UNREF_STATEITEM_EXTMATCH);
}
@@ -593,8 +607,8 @@ static void clear_current_state(void)
*/
static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid)
{
- buf_T *curbuf_save;
- win_T *curwin_save;
+ buf_T *curbuf_save;
+ win_T *curwin_save;
pos_T cursor_save;
int idx;
linenr_T lnum;
@@ -602,8 +616,8 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid)
linenr_T break_lnum;
bool had_sync_point;
stateitem_T *cur_si;
- synpat_T *spp;
- char_u *line;
+ synpat_T *spp;
+ char_u *line;
int found_flags = 0;
int found_match_idx = 0;
linenr_T found_current_lnum = 0;
@@ -624,22 +638,25 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid)
* where N is minlines * 1.5, or minlines * 2 if minlines is small.
* Watch out for overflow when minlines is MAXLNUM.
*/
- if (syn_block->b_syn_sync_minlines > start_lnum)
+ if (syn_block->b_syn_sync_minlines > start_lnum) {
start_lnum = 1;
- else {
- if (syn_block->b_syn_sync_minlines == 1)
+ } else {
+ if (syn_block->b_syn_sync_minlines == 1) {
lnum = 1;
- else if (syn_block->b_syn_sync_minlines < 10)
+ } else if (syn_block->b_syn_sync_minlines < 10) {
lnum = syn_block->b_syn_sync_minlines * 2;
- else
+ } else {
lnum = syn_block->b_syn_sync_minlines * 3 / 2;
+ }
if (syn_block->b_syn_sync_maxlines != 0
- && lnum > syn_block->b_syn_sync_maxlines)
+ && lnum > syn_block->b_syn_sync_maxlines) {
lnum = syn_block->b_syn_sync_maxlines;
- if (lnum >= start_lnum)
+ }
+ if (lnum >= start_lnum) {
start_lnum = 1;
- else
+ } else {
start_lnum -= lnum;
+ }
}
current_lnum = start_lnum;
@@ -659,12 +676,13 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid)
*/
for (; start_lnum > 1; --start_lnum) {
line = ml_get(start_lnum - 1);
- if (*line == NUL || *(line + STRLEN(line) - 1) != '\\')
+ if (*line == NUL || *(line + STRLEN(line) - 1) != '\\') {
break;
+ }
}
current_lnum = start_lnum;
- /* set cursor to start of search */
+ // set cursor to start of search
cursor_save = wp->w_cursor;
wp->w_cursor.lnum = start_lnum;
wp->w_cursor.col = 0;
@@ -675,7 +693,7 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid)
* Restrict the search for the end of a comment to b_syn_sync_maxlines.
*/
if (find_start_comment((int)syn_block->b_syn_sync_maxlines) != NULL) {
- for (idx = syn_block->b_syn_patterns.ga_len; --idx >= 0; )
+ for (idx = syn_block->b_syn_patterns.ga_len; --idx >= 0; ) {
if (SYN_ITEMS(syn_block)[idx].sp_syn.id
== syn_block->b_syn_sync_id
&& SYN_ITEMS(syn_block)[idx].sp_type == SPTYPE_START) {
@@ -684,9 +702,10 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid)
update_si_attr(current_state.ga_len - 1);
break;
}
+ }
}
- /* restore cursor and buffer */
+ // restore cursor and buffer
wp->w_cursor = cursor_save;
curwin = curwin_save;
curbuf = curbuf_save;
@@ -696,17 +715,18 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid)
*/
else if (syn_block->b_syn_sync_flags & SF_MATCH) {
if (syn_block->b_syn_sync_maxlines != 0
- && start_lnum > syn_block->b_syn_sync_maxlines)
+ && start_lnum > syn_block->b_syn_sync_maxlines) {
break_lnum = start_lnum - syn_block->b_syn_sync_maxlines;
- else
+ } else {
break_lnum = 0;
+ }
found_m_endpos.lnum = 0;
found_m_endpos.col = 0;
end_lnum = start_lnum;
lnum = start_lnum;
while (--lnum > break_lnum) {
- /* This can take a long time: break when CTRL-C pressed. */
+ // This can take a long time: break when CTRL-C pressed.
line_breakcheck();
if (got_int) {
invalidate_current_state();
@@ -714,7 +734,7 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid)
break;
}
- /* Check if we have run into a valid saved state stack now. */
+ // Check if we have run into a valid saved state stack now.
if (last_valid != NULL && lnum == last_valid->sst_lnum) {
load_current_state(last_valid);
break;
@@ -723,8 +743,9 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid)
/*
* Check if the previous line has the line-continuation pattern.
*/
- if (lnum > 1 && syn_match_linecont(lnum - 1))
+ if (lnum > 1 && syn_match_linecont(lnum - 1)) {
continue;
+ }
/*
* Start with nothing on the state stack
@@ -740,12 +761,12 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid)
if (had_sync_point && current_state.ga_len) {
cur_si = &CUR_STATE(current_state.ga_len - 1);
if (cur_si->si_m_endpos.lnum > start_lnum) {
- /* ignore match that goes to after where started */
+ // ignore match that goes to after where started
current_lnum = end_lnum;
break;
}
if (cur_si->si_idx < 0) {
- /* Cannot happen? */
+ // Cannot happen?
found_flags = 0;
found_match_idx = KEYWORD_IDX;
} else {
@@ -763,23 +784,27 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid)
if (found_m_endpos.lnum > current_lnum) {
current_lnum = found_m_endpos.lnum;
current_col = found_m_endpos.col;
- if (current_lnum >= end_lnum)
+ if (current_lnum >= end_lnum) {
break;
- } else if (found_m_endpos.col > current_col)
+ }
+ } else if (found_m_endpos.col > current_col) {
current_col = found_m_endpos.col;
- else
+ } else {
++current_col;
+ }
/* syn_current_attr() will have skipped the check for
* an item that ends here, need to do that now. Be
* careful not to go past the NUL. */
prev_current_col = current_col;
- if (syn_getcurline()[current_col] != NUL)
+ if (syn_getcurline()[current_col] != NUL) {
++current_col;
+ }
check_state_ends();
current_col = prev_current_col;
- } else
+ } else {
break;
+ }
}
}
@@ -809,7 +834,7 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid)
cur_si = &CUR_STATE(current_state.ga_len - 1);
cur_si->si_h_startpos.lnum = found_current_lnum;
cur_si->si_h_startpos.col = found_current_col;
- update_si_end(cur_si, (int)current_col, TRUE);
+ update_si_end(cur_si, (int)current_col, true);
check_keepend();
}
current_col = found_m_endpos.col;
@@ -827,7 +852,7 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid)
invalidate_current_state();
}
- /* Ran into start of the file or exceeded maximum number of lines */
+ // Ran into start of the file or exceeded maximum number of lines
if (lnum <= break_lnum) {
invalidate_current_state();
current_lnum = break_lnum + 1;
@@ -880,7 +905,7 @@ static int syn_match_linecont(linenr_T lnum)
*/
static void syn_start_line(void)
{
- current_finished = FALSE;
+ current_finished = false;
current_col = 0;
/*
@@ -888,7 +913,7 @@ static void syn_start_line(void)
* previous line and regions that have "keepend".
*/
if (!GA_EMPTY(&current_state)) {
- syn_update_ends(TRUE);
+ syn_update_ends(true);
check_state_ends();
}
@@ -897,15 +922,13 @@ static void syn_start_line(void)
next_seqnr = 1;
}
-/*
- * Check for items in the stack that need their end updated.
- * When "startofline" is TRUE the last item is always updated.
- * When "startofline" is FALSE the item with "keepend" is forcefully updated.
- */
-static void syn_update_ends(int startofline)
+/// Check for items in the stack that need their end updated.
+///
+/// @param startofline if true the last item is always updated.
+/// if false the item with "keepend" is forcefully updated.
+static void syn_update_ends(bool startofline)
{
stateitem_T *cur_si;
- int seen_keepend;
if (startofline) {
/* Check for a match carried over from a previous line with a
@@ -935,25 +958,30 @@ static void syn_update_ends(int startofline)
* Then check for items ending in column 0.
*/
int i = current_state.ga_len - 1;
- if (keepend_level >= 0)
- for (; i > keepend_level; --i)
- if (CUR_STATE(i).si_flags & HL_EXTEND)
+ if (keepend_level >= 0) {
+ for (; i > keepend_level; --i) {
+ if (CUR_STATE(i).si_flags & HL_EXTEND) {
break;
+ }
+ }
+ }
- seen_keepend = FALSE;
- for (; i < current_state.ga_len; ++i) {
+ bool seen_keepend = false;
+ for (; i < current_state.ga_len; i++) {
cur_si = &CUR_STATE(i);
if ((cur_si->si_flags & HL_KEEPEND)
|| (seen_keepend && !startofline)
|| (i == current_state.ga_len - 1 && startofline)) {
- cur_si->si_h_startpos.col = 0; /* start highl. in col 0 */
+ cur_si->si_h_startpos.col = 0; // start highl. in col 0
cur_si->si_h_startpos.lnum = current_lnum;
- if (!(cur_si->si_flags & HL_MATCHCONT))
+ if (!(cur_si->si_flags & HL_MATCHCONT)) {
update_si_end(cur_si, (int)current_col, !startofline);
+ }
- if (!startofline && (cur_si->si_flags & HL_KEEPEND))
- seen_keepend = TRUE;
+ if (!startofline && (cur_si->si_flags & HL_KEEPEND)) {
+ seen_keepend = true;
+ }
}
}
check_keepend();
@@ -997,7 +1025,7 @@ static void syn_update_ends(int startofline)
static void syn_stack_free_block(synblock_T *block)
{
- synstate_T *p;
+ synstate_T *p;
if (block->b_sst_array != NULL) {
for (p = block->b_sst_first; p != NULL; p = p->sst_next) {
@@ -1016,7 +1044,7 @@ void syn_stack_free_all(synblock_T *block)
{
syn_stack_free_block(block);
- /* When using "syntax" fold method, must update all folds. */
+ // When using "syntax" fold method, must update all folds.
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->w_s == block && foldmethodIsSyntax(wp)) {
foldUpdateAll(wp);
@@ -1033,31 +1061,35 @@ void syn_stack_free_all(synblock_T *block)
static void syn_stack_alloc(void)
{
long len;
- synstate_T *to, *from;
- synstate_T *sstp;
+ synstate_T *to, *from;
+ synstate_T *sstp;
len = syn_buf->b_ml.ml_line_count / SST_DIST + Rows * 2;
- if (len < SST_MIN_ENTRIES)
+ if (len < SST_MIN_ENTRIES) {
len = SST_MIN_ENTRIES;
- else if (len > SST_MAX_ENTRIES)
+ } else if (len > SST_MAX_ENTRIES) {
len = SST_MAX_ENTRIES;
+ }
if (syn_block->b_sst_len > len * 2 || syn_block->b_sst_len < len) {
- /* Allocate 50% too much, to avoid reallocating too often. */
+ // Allocate 50% too much, to avoid reallocating too often.
len = syn_buf->b_ml.ml_line_count;
len = (len + len / 2) / SST_DIST + Rows * 2;
- if (len < SST_MIN_ENTRIES)
+ if (len < SST_MIN_ENTRIES) {
len = SST_MIN_ENTRIES;
- else if (len > SST_MAX_ENTRIES)
+ } else if (len > SST_MAX_ENTRIES) {
len = SST_MAX_ENTRIES;
+ }
if (syn_block->b_sst_array != NULL) {
/* When shrinking the array, cleanup the existing stack.
* Make sure that all valid entries fit in the new array. */
while (syn_block->b_sst_len - syn_block->b_sst_freecount + 2 > len
- && syn_stack_cleanup())
+ && syn_stack_cleanup()) {
;
- if (len < syn_block->b_sst_len - syn_block->b_sst_freecount + 2)
+ }
+ if (len < syn_block->b_sst_len - syn_block->b_sst_freecount + 2) {
len = syn_block->b_sst_len - syn_block->b_sst_freecount + 2;
+ }
}
assert(len >= 0);
@@ -1065,7 +1097,7 @@ static void syn_stack_alloc(void)
to = sstp - 1;
if (syn_block->b_sst_array != NULL) {
- /* Move the states from the old array to the new one. */
+ // Move the states from the old array to the new one.
for (from = syn_block->b_sst_first; from != NULL;
from = from->sst_next) {
++to;
@@ -1082,10 +1114,11 @@ static void syn_stack_alloc(void)
syn_block->b_sst_freecount = len;
}
- /* Create the list of free entries. */
+ // Create the list of free entries.
syn_block->b_sst_firstfree = to + 1;
- while (++to < sstp + len)
+ while (++to < sstp + len) {
to->sst_next = to + 1;
+ }
(sstp + len - 1)->sst_next = NULL;
xfree(syn_block->b_sst_array);
@@ -1113,7 +1146,7 @@ void syn_stack_apply_changes(buf_T *buf)
static void syn_stack_apply_changes_block(synblock_T *block, buf_T *buf)
{
- synstate_T *p, *prev, *np;
+ synstate_T *p, *prev, *np;
linenr_T n;
prev = NULL;
@@ -1121,12 +1154,13 @@ static void syn_stack_apply_changes_block(synblock_T *block, buf_T *buf)
if (p->sst_lnum + block->b_syn_sync_linebreaks > buf->b_mod_top) {
n = p->sst_lnum + buf->b_mod_xlines;
if (n <= buf->b_mod_bot) {
- /* this state is inside the changed area, remove it */
+ // this state is inside the changed area, remove it
np = p->sst_next;
- if (prev == NULL)
+ if (prev == NULL) {
block->b_sst_first = np;
- else
+ } else {
prev->sst_next = np;
+ }
syn_stack_free_entry(block, p);
p = np;
continue;
@@ -1135,14 +1169,16 @@ static void syn_stack_apply_changes_block(synblock_T *block, buf_T *buf)
* that needs to be parsed before this entry can be made valid
* again. */
if (p->sst_change_lnum != 0 && p->sst_change_lnum > buf->b_mod_top) {
- if (p->sst_change_lnum + buf->b_mod_xlines > buf->b_mod_top)
+ if (p->sst_change_lnum + buf->b_mod_xlines > buf->b_mod_top) {
p->sst_change_lnum += buf->b_mod_xlines;
- else
+ } else {
p->sst_change_lnum = buf->b_mod_top;
+ }
}
if (p->sst_change_lnum == 0
- || p->sst_change_lnum < buf->b_mod_bot)
+ || p->sst_change_lnum < buf->b_mod_bot) {
p->sst_change_lnum = buf->b_mod_bot;
+ }
p->sst_lnum = n;
}
@@ -1151,27 +1187,26 @@ static void syn_stack_apply_changes_block(synblock_T *block, buf_T *buf)
}
}
-/*
- * Reduce the number of entries in the state stack for syn_buf.
- * Returns TRUE if at least one entry was freed.
- */
-static int syn_stack_cleanup(void)
+/// Reduce the number of entries in the state stack for syn_buf.
+///
+/// @return true if at least one entry was freed.
+static bool syn_stack_cleanup(void)
{
- synstate_T *p, *prev;
+ synstate_T *p, *prev;
disptick_T tick;
- int above;
int dist;
- int retval = FALSE;
+ bool retval = false;
if (syn_block->b_sst_first == NULL) {
return retval;
}
- /* Compute normal distance between non-displayed entries. */
- if (syn_block->b_sst_len <= Rows)
+ // Compute normal distance between non-displayed entries.
+ if (syn_block->b_sst_len <= Rows) {
dist = 999999;
- else
+ } else {
dist = syn_buf->b_ml.ml_line_count / (syn_block->b_sst_len - Rows) + 1;
+ }
/*
* Go through the list to find the "tick" for the oldest entry that can
@@ -1179,16 +1214,18 @@ static int syn_stack_cleanup(void)
* "b_sst_lasttick" (the display tick wraps around).
*/
tick = syn_block->b_sst_lasttick;
- above = FALSE;
+ bool above = false;
prev = syn_block->b_sst_first;
for (p = prev->sst_next; p != NULL; prev = p, p = p->sst_next) {
if (prev->sst_lnum + dist > p->sst_lnum) {
if (p->sst_tick > syn_block->b_sst_lasttick) {
- if (!above || p->sst_tick < tick)
+ if (!above || p->sst_tick < tick) {
tick = p->sst_tick;
- above = TRUE;
- } else if (!above && p->sst_tick < tick)
+ }
+ above = true;
+ } else if (!above && p->sst_tick < tick) {
tick = p->sst_tick;
+ }
}
}
@@ -1199,11 +1236,11 @@ static int syn_stack_cleanup(void)
prev = syn_block->b_sst_first;
for (p = prev->sst_next; p != NULL; prev = p, p = p->sst_next) {
if (p->sst_tick == tick && prev->sst_lnum + dist > p->sst_lnum) {
- /* Move this entry from used list to free list */
+ // Move this entry from used list to free list
prev->sst_next = p->sst_next;
syn_stack_free_entry(syn_block, p);
p = prev;
- retval = TRUE;
+ retval = true;
}
}
return retval;
@@ -1227,14 +1264,16 @@ static void syn_stack_free_entry(synblock_T *block, synstate_T *p)
*/
static synstate_T *syn_stack_find_entry(linenr_T lnum)
{
- synstate_T *p, *prev;
+ synstate_T *p, *prev;
prev = NULL;
for (p = syn_block->b_sst_first; p != NULL; prev = p, p = p->sst_next) {
- if (p->sst_lnum == lnum)
+ if (p->sst_lnum == lnum) {
return p;
- if (p->sst_lnum > lnum)
+ }
+ if (p->sst_lnum > lnum) {
break;
+ }
}
return prev;
}
@@ -1246,10 +1285,10 @@ static synstate_T *syn_stack_find_entry(linenr_T lnum)
static synstate_T *store_current_state(void)
{
int i;
- synstate_T *p;
- bufstate_T *bp;
+ synstate_T *p;
+ bufstate_T *bp;
stateitem_T *cur_si;
- synstate_T *sp = syn_stack_find_entry(current_lnum);
+ synstate_T *sp = syn_stack_find_entry(current_lnum);
/*
* If the current state contains a start or end pattern that continues
@@ -1261,51 +1300,55 @@ static synstate_T *store_current_state(void)
|| cur_si->si_m_endpos.lnum >= current_lnum
|| cur_si->si_h_endpos.lnum >= current_lnum
|| (cur_si->si_end_idx
- && cur_si->si_eoe_pos.lnum >= current_lnum))
+ && cur_si->si_eoe_pos.lnum >= current_lnum)) {
break;
+ }
}
if (i >= 0) {
if (sp != NULL) {
- /* find "sp" in the list and remove it */
- if (syn_block->b_sst_first == sp)
- /* it's the first entry */
+ // find "sp" in the list and remove it
+ if (syn_block->b_sst_first == sp) {
+ // it's the first entry
syn_block->b_sst_first = sp->sst_next;
- else {
- /* find the entry just before this one to adjust sst_next */
- for (p = syn_block->b_sst_first; p != NULL; p = p->sst_next)
- if (p->sst_next == sp)
+ } else {
+ // find the entry just before this one to adjust sst_next
+ for (p = syn_block->b_sst_first; p != NULL; p = p->sst_next) {
+ if (p->sst_next == sp) {
break;
- if (p != NULL) /* just in case */
+ }
+ }
+ if (p != NULL) { // just in case
p->sst_next = sp->sst_next;
+ }
}
syn_stack_free_entry(syn_block, sp);
sp = NULL;
}
- } else if (sp == NULL || sp->sst_lnum != current_lnum) {
+ } else if (sp == NULL || sp->sst_lnum != current_lnum) {
/*
* Add a new entry
*/
- /* If no free items, cleanup the array first. */
+ // If no free items, cleanup the array first.
if (syn_block->b_sst_freecount == 0) {
(void)syn_stack_cleanup();
- /* "sp" may have been moved to the freelist now */
+ // "sp" may have been moved to the freelist now
sp = syn_stack_find_entry(current_lnum);
}
- /* Still no free items? Must be a strange problem... */
- if (syn_block->b_sst_freecount == 0)
+ // Still no free items? Must be a strange problem...
+ if (syn_block->b_sst_freecount == 0) {
sp = NULL;
- else {
+ } else {
/* Take the first item from the free list and put it in the used
* list, after *sp */
p = syn_block->b_sst_firstfree;
syn_block->b_sst_firstfree = p->sst_next;
--syn_block->b_sst_freecount;
if (sp == NULL) {
- /* Insert in front of the list */
+ // Insert in front of the list
p->sst_next = syn_block->b_sst_first;
syn_block->b_sst_first = p;
} else {
- /* insert in list after *sp */
+ // insert in list after *sp
p->sst_next = sp->sst_next;
sp->sst_next = p;
}
@@ -1315,7 +1358,7 @@ static synstate_T *store_current_state(void)
}
}
if (sp != NULL) {
- /* When overwriting an existing state stack, clear it first */
+ // When overwriting an existing state stack, clear it first
clear_syn_state(sp);
sp->sst_stacksize = current_state.ga_len;
if (current_state.ga_len > SST_FIX_STATES) {
@@ -1325,8 +1368,9 @@ static synstate_T *store_current_state(void)
ga_grow(&sp->sst_union.sst_ga, current_state.ga_len);
sp->sst_union.sst_ga.ga_len = current_state.ga_len;
bp = SYN_STATE_P(&(sp->sst_union.sst_ga));
- } else
+ } else {
bp = sp->sst_union.sst_stack;
+ }
for (i = 0; i < sp->sst_stacksize; ++i) {
bp[i].bs_idx = CUR_STATE(i).si_idx;
bp[i].bs_flags = CUR_STATE(i).si_flags;
@@ -1339,7 +1383,7 @@ static synstate_T *store_current_state(void)
sp->sst_tick = display_tick;
sp->sst_change_lnum = 0;
}
- current_state_stored = TRUE;
+ current_state_stored = true;
return sp;
}
@@ -1349,32 +1393,35 @@ static synstate_T *store_current_state(void)
static void load_current_state(synstate_T *from)
{
int i;
- bufstate_T *bp;
+ bufstate_T *bp;
clear_current_state();
validate_current_state();
keepend_level = -1;
if (from->sst_stacksize) {
ga_grow(&current_state, from->sst_stacksize);
- if (from->sst_stacksize > SST_FIX_STATES)
+ if (from->sst_stacksize > SST_FIX_STATES) {
bp = SYN_STATE_P(&(from->sst_union.sst_ga));
- else
+ } else {
bp = from->sst_union.sst_stack;
+ }
for (i = 0; i < from->sst_stacksize; ++i) {
CUR_STATE(i).si_idx = bp[i].bs_idx;
CUR_STATE(i).si_flags = bp[i].bs_flags;
CUR_STATE(i).si_seqnr = bp[i].bs_seqnr;
CUR_STATE(i).si_cchar = bp[i].bs_cchar;
CUR_STATE(i).si_extmatch = ref_extmatch(bp[i].bs_extmatch);
- if (keepend_level < 0 && (CUR_STATE(i).si_flags & HL_KEEPEND))
+ if (keepend_level < 0 && (CUR_STATE(i).si_flags & HL_KEEPEND)) {
keepend_level = i;
+ }
CUR_STATE(i).si_ends = FALSE;
CUR_STATE(i).si_m_lnum = 0;
- if (CUR_STATE(i).si_idx >= 0)
+ if (CUR_STATE(i).si_idx >= 0) {
CUR_STATE(i).si_next_list =
(SYN_ITEMS(syn_block)[CUR_STATE(i).si_idx]).sp_next_list;
- else
+ } else {
CUR_STATE(i).si_next_list = NULL;
+ }
update_si_attr(i);
}
current_state.ga_len = from->sst_stacksize;
@@ -1384,32 +1431,33 @@ static void load_current_state(synstate_T *from)
current_lnum = from->sst_lnum;
}
-/*
- * Compare saved state stack "*sp" with the current state.
- * Return TRUE when they are equal.
- */
-static int syn_stack_equal(synstate_T *sp)
+/// Compare saved state stack "*sp" with the current state.
+///
+/// @return true when they are equal.
+static bool syn_stack_equal(synstate_T *sp)
{
- bufstate_T *bp;
- reg_extmatch_T *six, *bsx;
+ bufstate_T *bp;
+ reg_extmatch_T *six, *bsx;
- /* First a quick check if the stacks have the same size end nextlist. */
+ // First a quick check if the stacks have the same size end nextlist.
if (sp->sst_stacksize != current_state.ga_len
|| sp->sst_next_list != current_next_list) {
- return FALSE;
+ return false;
}
- /* Need to compare all states on both stacks. */
- if (sp->sst_stacksize > SST_FIX_STATES)
+ // Need to compare all states on both stacks.
+ if (sp->sst_stacksize > SST_FIX_STATES) {
bp = SYN_STATE_P(&(sp->sst_union.sst_ga));
- else
+ } else {
bp = sp->sst_union.sst_stack;
+ }
int i;
for (i = current_state.ga_len; --i >= 0; ) {
- /* If the item has another index the state is different. */
- if (bp[i].bs_idx != CUR_STATE(i).si_idx)
+ // If the item has another index the state is different.
+ if (bp[i].bs_idx != CUR_STATE(i).si_idx) {
break;
+ }
if (bp[i].bs_extmatch == CUR_STATE(i).si_extmatch) {
continue;
}
@@ -1420,8 +1468,9 @@ static int syn_stack_equal(synstate_T *sp)
six = CUR_STATE(i).si_extmatch;
/* If one of the extmatch pointers is NULL the states are
* different. */
- if (bsx == NULL || six == NULL)
+ if (bsx == NULL || six == NULL) {
break;
+ }
int j;
for (j = 0; j < NSUBEXP; ++j) {
/* Check each referenced match string. They must all be
@@ -1440,13 +1489,15 @@ static int syn_stack_equal(synstate_T *sp)
}
}
}
- if (j != NSUBEXP)
+ if (j != NSUBEXP) {
break;
+ }
+ }
+ if (i < 0) {
+ return true;
}
- if (i < 0)
- return TRUE;
- return FALSE;
+ return false;
}
/*
@@ -1454,21 +1505,23 @@ static int syn_stack_equal(synstate_T *sp)
* this line depended on a change before it, it now depends on the line below
* the last parsed line.
* The window looks like this:
- * line which changed
- * displayed line
- * displayed line
+ * line which changed
+ * displayed line
+ * displayed line
* lnum -> line below window
*/
void syntax_end_parsing(linenr_T lnum)
{
- synstate_T *sp;
+ synstate_T *sp;
sp = syn_stack_find_entry(lnum);
- if (sp != NULL && sp->sst_lnum < lnum)
+ if (sp != NULL && sp->sst_lnum < lnum) {
sp = sp->sst_next;
+ }
- if (sp != NULL && sp->sst_change_lnum != 0)
+ if (sp != NULL && sp->sst_change_lnum != 0) {
sp->sst_change_lnum = lnum;
+ }
}
/*
@@ -1478,7 +1531,7 @@ void syntax_end_parsing(linenr_T lnum)
static void invalidate_current_state(void)
{
clear_current_state();
- current_state.ga_itemsize = 0; /* mark current_state invalid */
+ current_state.ga_itemsize = 0; // mark current_state invalid
current_next_list = NULL;
keepend_level = -1;
}
@@ -1489,15 +1542,14 @@ static void validate_current_state(void)
ga_set_growsize(&current_state, 3);
}
-/*
- * Return TRUE if the syntax at start of lnum changed since last time.
- * This will only be called just after get_syntax_attr() for the previous
- * line, to check if the next line needs to be redrawn too.
- */
-int syntax_check_changed(linenr_T lnum)
+/// This will only be called just after get_syntax_attr() for the previous
+/// line, to check if the next line needs to be redrawn too.
+///
+/// @return true if the syntax at start of lnum changed since last time.
+bool syntax_check_changed(linenr_T lnum)
{
- int retval = TRUE;
- synstate_T *sp;
+ bool retval = true;
+ synstate_T *sp;
/*
* Check the state stack when:
@@ -1519,8 +1571,9 @@ int syntax_check_changed(linenr_T lnum)
* Compare the current state with the previously saved state of
* the line.
*/
- if (syn_stack_equal(sp))
- retval = FALSE;
+ if (syn_stack_equal(sp)) {
+ retval = false;
+ }
/*
* Store the current state in b_sst_array[] for later use.
@@ -1533,16 +1586,13 @@ int syntax_check_changed(linenr_T lnum)
return retval;
}
-/*
- * Finish the current line.
- * This doesn't return any attributes, it only gets the state at the end of
- * the line. It can start anywhere in the line, as long as the current state
- * is valid.
- */
-static bool
-syn_finish_line(
- const bool syncing // called for syncing
-)
+/// Finish the current line.
+/// This doesn't return any attributes, it only gets the state at the end of
+/// the line. It can start anywhere in the line, as long as the current state
+/// is valid.
+///
+/// @param syncing called for syncing
+static bool syn_finish_line(const bool syncing)
{
while (!current_finished) {
(void)syn_current_attr(syncing, false, NULL, false);
@@ -1572,36 +1622,35 @@ syn_finish_line(
return false;
}
-/*
- * Return highlight attributes for next character.
- * Must first call syntax_start() once for the line.
- * "col" is normally 0 for the first use in a line, and increments by one each
- * time. It's allowed to skip characters and to stop before the end of the
- * line. But only a "col" after a previously used column is allowed.
- * When "can_spell" is not NULL set it to TRUE when spell-checking should be
- * done.
- */
-int
-get_syntax_attr(
- const colnr_T col,
- bool *const can_spell,
- const bool keep_state // keep state of char at "col"
-)
+/// Gets highlight attributes for next character.
+/// Must first call syntax_start() once for the line.
+/// "col" is normally 0 for the first use in a line, and increments by one each
+/// time. It's allowed to skip characters and to stop before the end of the
+/// line. But only a "col" after a previously used column is allowed.
+/// When "can_spell" is not NULL set it to TRUE when spell-checking should be
+/// done.
+///
+/// @param keep_state keep state of char at "col"
+///
+/// @return highlight attributes for next character.
+int get_syntax_attr(const colnr_T col, bool *const can_spell, const bool keep_state)
{
int attr = 0;
- if (can_spell != NULL)
+ if (can_spell != NULL) {
/* Default: Only do spelling when there is no @Spell cluster or when
* ":syn spell toplevel" was used. */
*can_spell = syn_block->b_syn_spell == SYNSPL_DEFAULT
? (syn_block->b_spell_cluster_id == 0)
: (syn_block->b_syn_spell == SYNSPL_TOP);
+ }
- /* check for out of memory situation */
- if (syn_block->b_sst_array == NULL)
+ // check for out of memory situation
+ if (syn_block->b_sst_array == NULL) {
return 0;
+ }
- /* After 'synmaxcol' the attribute is always zero. */
+ // After 'synmaxcol' the attribute is always zero.
if (syn_buf->b_p_smc > 0 && col >= (colnr_T)syn_buf->b_p_smc) {
clear_current_state();
current_id = 0;
@@ -1611,9 +1660,10 @@ get_syntax_attr(
return 0;
}
- /* Make sure current_state is valid */
- if (INVALID_STATE(&current_state))
+ // Make sure current_state is valid
+ if (INVALID_STATE(&current_state)) {
validate_current_state();
+ }
/*
* Skip from the current column to "col", get the attributes for "col".
@@ -1627,15 +1677,14 @@ get_syntax_attr(
return attr;
}
-/*
- * Get syntax attributes for current_lnum, current_col.
- */
-static int syn_current_attr(
- const bool syncing, // When true: called for syncing
- const bool displaying, // result will be displayed
- bool *const can_spell, // return: do spell checking
- const bool keep_state // keep syntax stack afterwards
-)
+/// Get syntax attributes for current_lnum, current_col.
+///
+/// @param syncing When true: called for syncing
+/// @param displaying result will be displayed
+/// @param can_spell return: do spell checking
+/// @param keep_state keep syntax stack afterwards
+static int syn_current_attr(const bool syncing, const bool displaying, bool *const can_spell,
+ const bool keep_state)
{
lpos_T endpos; // was: char_u *endp;
lpos_T hl_startpos; // was: int hl_startcol;
@@ -1654,9 +1703,9 @@ static int syn_current_attr(
regmmatch_T regmatch;
lpos_T pos;
reg_extmatch_T *cur_extmatch = NULL;
- char_u buf_chartab[32]; // chartab array for syn iskeyword
- char_u *line; // current line. NOTE: becomes invalid after
- // looking for a pattern match!
+ char_u buf_chartab[32]; // chartab array for syn iskeyword
+ char_u *line; // current line. NOTE: becomes invalid after
+ // looking for a pattern match!
// variables for zero-width matches that have a "nextgroup" argument
bool keep_next_list;
@@ -1677,15 +1726,15 @@ static int syn_current_attr(
(void)push_next_match();
}
- current_finished = TRUE;
- current_state_stored = FALSE;
+ current_finished = true;
+ current_state_stored = false;
return 0;
}
- /* if the current or next character is NUL, we will finish the line now */
+ // if the current or next character is NUL, we will finish the line now
if (line[current_col] == NUL || line[current_col + 1] == NUL) {
- current_finished = TRUE;
- current_state_stored = FALSE;
+ current_finished = true;
+ current_state_stored = false;
}
/*
@@ -1700,8 +1749,8 @@ static int syn_current_attr(
// Only check for keywords when not syncing and there are some.
const bool do_keywords = !syncing
- && (syn_block->b_keywtab.ht_used > 0
- || syn_block->b_keywtab_ic.ht_used > 0);
+ && (syn_block->b_keywtab.ht_used > 0
+ || syn_block->b_keywtab_ic.ht_used > 0);
/* Init the list of zero-width matches with a nextlist. This is used to
* avoid matching the same item in the same position twice. */
@@ -1727,23 +1776,25 @@ static int syn_current_attr(
* Always need to check for contained items if some item has the
* "containedin" argument (takes extra time!).
*/
- if (current_state.ga_len)
+ if (current_state.ga_len) {
cur_si = &CUR_STATE(current_state.ga_len - 1);
- else
+ } else {
cur_si = NULL;
+ }
if (syn_block->b_syn_containedin || cur_si == NULL
|| cur_si->si_cont_list != NULL) {
/*
* 2. Check for keywords, if on a keyword char after a non-keyword
- * char. Don't do this when syncing.
+ * char. Don't do this when syncing.
*/
if (do_keywords) {
line = syn_getcurline();
const char_u *cur_pos = line + current_col;
if (vim_iswordp_buf(cur_pos, syn_buf)
- && (current_col == 0 || !vim_iswordp_buf(
- cur_pos - 1 - utf_head_off(line, cur_pos - 1), syn_buf))) {
+ && (current_col == 0 ||
+ !vim_iswordp_buf(cur_pos - 1 - utf_head_off(line, cur_pos - 1),
+ syn_buf))) {
syn_id = check_keyword_id(line, (int)current_col, &endcol, &flags,
&next_list, cur_si, &cchar);
if (syn_id != 0) {
@@ -1752,7 +1803,7 @@ static int syn_current_attr(
cur_si = &CUR_STATE(current_state.ga_len - 1);
cur_si->si_m_startcol = current_col;
cur_si->si_h_startpos.lnum = current_lnum;
- cur_si->si_h_startpos.col = 0; /* starts right away */
+ cur_si->si_h_startpos.col = 0; // starts right away
cur_si->si_m_endpos.lnum = current_lnum;
cur_si->si_m_endpos.col = endcol;
cur_si->si_h_endpos.lnum = current_lnum;
@@ -1762,10 +1813,11 @@ static int syn_current_attr(
cur_si->si_flags = flags;
cur_si->si_seqnr = next_seqnr++;
cur_si->si_cchar = cchar;
- if (current_state.ga_len > 1)
+ if (current_state.ga_len > 1) {
cur_si->si_flags |=
CUR_STATE(current_state.ga_len - 2).si_flags
& HL_CONCEAL;
+ }
cur_si->si_id = syn_id;
cur_si->si_trans_id = syn_id;
if (flags & HL_TRANSP) {
@@ -1773,10 +1825,8 @@ static int syn_current_attr(
cur_si->si_attr = 0;
cur_si->si_trans_id = 0;
} else {
- cur_si->si_attr = CUR_STATE(
- current_state.ga_len - 2).si_attr;
- cur_si->si_trans_id = CUR_STATE(
- current_state.ga_len - 2).si_trans_id;
+ cur_si->si_attr = CUR_STATE(current_state.ga_len - 2).si_attr;
+ cur_si->si_trans_id = CUR_STATE(current_state.ga_len - 2).si_trans_id;
}
} else {
cur_si->si_attr = syn_id2attr(syn_id);
@@ -1804,28 +1854,29 @@ static int syn_current_attr(
* pattern takes quite a bit of time, thus we want to
* avoid doing it when it's not needed.
*/
- next_match_idx = 0; /* no match in this line yet */
+ next_match_idx = 0; // no match in this line yet
next_match_col = MAXCOL;
for (int idx = syn_block->b_syn_patterns.ga_len; --idx >= 0; ) {
synpat_T *const spp = &(SYN_ITEMS(syn_block)[idx]);
- if ( spp->sp_syncing == syncing
- && (displaying || !(spp->sp_flags & HL_DISPLAY))
- && (spp->sp_type == SPTYPE_MATCH
- || spp->sp_type == SPTYPE_START)
- && (current_next_list != NULL
+ if (spp->sp_syncing == syncing
+ && (displaying || !(spp->sp_flags & HL_DISPLAY))
+ && (spp->sp_type == SPTYPE_MATCH
+ || spp->sp_type == SPTYPE_START)
+ && (current_next_list != NULL
? in_id_list(NULL, current_next_list,
- &spp->sp_syn, 0)
+ &spp->sp_syn, 0)
: (cur_si == NULL
? !(spp->sp_flags & HL_CONTAINED)
: in_id_list(cur_si,
- cur_si->si_cont_list, &spp->sp_syn,
- spp->sp_flags & HL_CONTAINED)))) {
+ cur_si->si_cont_list, &spp->sp_syn,
+ spp->sp_flags & HL_CONTAINED)))) {
/* If we already tried matching in this line, and
* there isn't a match before next_match_col, skip
* this item. */
if (spp->sp_line_id == current_line_id
- && spp->sp_startcol >= next_match_col)
+ && spp->sp_startcol >= next_match_col) {
continue;
+ }
spp->sp_line_id = current_line_id;
colnr_T lc_col = current_col - spp->sp_offsets[SPO_LC_OFF];
@@ -1839,7 +1890,7 @@ static int syn_current_attr(
IF_SYN_TIME(&spp->sp_time));
spp->sp_prog = regmatch.regprog;
if (!r) {
- /* no match in this line, try another one */
+ // no match in this line, try another one
spp->sp_startcol = MAXCOL;
continue;
}
@@ -1848,7 +1899,7 @@ static int syn_current_attr(
* Compute the first column of the match.
*/
syn_add_start_off(&pos, &regmatch,
- spp, SPO_MS_OFF, -1);
+ spp, SPO_MS_OFF, -1);
if (pos.lnum > current_lnum) {
/* must have used end of match in a next line,
* we can't handle that */
@@ -1865,8 +1916,9 @@ static int syn_current_attr(
* If a previously found match starts at a lower
* column number, don't use this one.
*/
- if (startcol >= next_match_col)
+ if (startcol >= next_match_col) {
continue;
+ }
/*
* If we matched this pattern at this position
@@ -1881,14 +1933,14 @@ static int syn_current_attr(
endpos.lnum = regmatch.endpos[0].lnum;
endpos.col = regmatch.endpos[0].col;
- /* Compute the highlight start. */
+ // Compute the highlight start.
syn_add_start_off(&hl_startpos, &regmatch,
- spp, SPO_HS_OFF, -1);
+ spp, SPO_HS_OFF, -1);
- /* Compute the region start. */
- /* Default is to use the end of the match. */
+ // Compute the region start.
+ // Default is to use the end of the match.
syn_add_end_off(&eos_pos, &regmatch,
- spp, SPO_RS_OFF, 0);
+ spp, SPO_RS_OFF, 0);
/*
* Grab the external submatches before they get
@@ -1899,7 +1951,7 @@ static int syn_current_attr(
re_extmatch_out = NULL;
flags = 0;
- eoe_pos.lnum = 0; /* avoid warning */
+ eoe_pos.lnum = 0; // avoid warning
eoe_pos.col = 0;
end_idx = 0;
hl_endpos.lnum = 0;
@@ -1916,9 +1968,10 @@ static int syn_current_attr(
startpos = endpos;
find_endpos(idx, &startpos, &endpos, &hl_endpos,
- &flags, &eoe_pos, &end_idx, cur_extmatch);
- if (endpos.lnum == 0)
- continue; /* not found */
+ &flags, &eoe_pos, &end_idx, cur_extmatch);
+ if (endpos.lnum == 0) {
+ continue; // not found
+ }
}
/*
* For a "match" the size must be > 0 after the
@@ -1927,9 +1980,9 @@ static int syn_current_attr(
*/
else if (spp->sp_type == SPTYPE_MATCH) {
syn_add_end_off(&hl_endpos, &regmatch, spp,
- SPO_HE_OFF, 0);
+ SPO_HE_OFF, 0);
syn_add_end_off(&endpos, &regmatch, spp,
- SPO_ME_OFF, 0);
+ SPO_ME_OFF, 0);
if (endpos.lnum == current_lnum
&& (int)endpos.col + syncing < startcol) {
/*
@@ -1949,8 +2002,9 @@ static int syn_current_attr(
/* Highlighting must start after startpos and end
* before endpos. */
if (hl_startpos.lnum == current_lnum
- && (int)hl_startpos.col < startcol)
+ && (int)hl_startpos.col < startcol) {
hl_startpos.col = startcol;
+ }
limit_pos_zero(&hl_endpos, &endpos);
next_match_idx = idx;
@@ -1973,7 +2027,7 @@ static int syn_current_attr(
* If we found a match at the current column, use it.
*/
if (next_match_idx >= 0 && next_match_col == (int)current_col) {
- synpat_T *lspp;
+ synpat_T *lspp;
/* When a zero-width item matched which has a nextgroup,
* don't push the item but set nextgroup. */
@@ -2013,8 +2067,9 @@ static int syn_current_attr(
if (((current_next_flags & HL_SKIPWHITE)
&& ascii_iswhite(line[current_col]))
|| ((current_next_flags & HL_SKIPEMPTY)
- && *line == NUL))
+ && *line == NUL)) {
break;
+ }
}
/*
@@ -2031,7 +2086,6 @@ static int syn_current_attr(
found_match = true;
}
}
-
} while (found_match);
restore_chartab(buf_chartab);
@@ -2076,9 +2130,9 @@ static int syn_current_attr(
/* There is no @Spell cluster: Do spelling for items without
* @NoSpell cluster. */
if (syn_block->b_nospell_cluster_id == 0
- || current_trans_id == 0)
+ || current_trans_id == 0) {
*can_spell = (syn_block->b_syn_spell != SYNSPL_NOTOP);
- else {
+ } else {
sps.inc_tag = 0;
sps.id = syn_block->b_nospell_cluster_id;
sps.cont_in_list = NULL;
@@ -2089,9 +2143,9 @@ static int syn_current_attr(
* the @Spell cluster. But not when @NoSpell is also there.
* At the toplevel only spell check when ":syn spell toplevel"
* was used. */
- if (current_trans_id == 0)
+ if (current_trans_id == 0) {
*can_spell = (syn_block->b_syn_spell == SYNSPL_TOP);
- else {
+ } else {
sps.inc_tag = 0;
sps.id = syn_block->b_spell_cluster_id;
sps.cont_in_list = NULL;
@@ -2099,8 +2153,9 @@ static int syn_current_attr(
if (syn_block->b_nospell_cluster_id != 0) {
sps.id = syn_block->b_nospell_cluster_id;
- if (in_id_list(sip, sip->si_cont_list, &sps, 0))
+ if (in_id_list(sip, sip->si_cont_list, &sps, 0)) {
*can_spell = false;
+ }
}
}
}
@@ -2124,14 +2179,15 @@ static int syn_current_attr(
--current_col;
}
}
- } else if (can_spell != NULL)
+ } else if (can_spell != NULL) {
/* Default: Only do spelling when there is no @Spell cluster or when
* ":syn spell toplevel" was used. */
*can_spell = syn_block->b_syn_spell == SYNSPL_DEFAULT
? (syn_block->b_spell_cluster_id == 0)
: (syn_block->b_syn_spell == SYNSPL_TOP);
+ }
- /* nextgroup ends at end of line, unless "skipnl" or "skipempty" present */
+ // nextgroup ends at end of line, unless "skipnl" or "skipempty" present
if (current_next_list != NULL
&& (line = syn_getcurline())[current_col] != NUL
&& line[current_col + 1] == NUL
@@ -2139,10 +2195,11 @@ static int syn_current_attr(
current_next_list = NULL;
}
- if (!GA_EMPTY(&zero_width_next_ga))
+ if (!GA_EMPTY(&zero_width_next_ga)) {
ga_clear(&zero_width_next_ga);
+ }
- /* No longer need external matches. But keep next_match_extmatch. */
+ // No longer need external matches. But keep next_match_extmatch.
unref_extmatch(re_extmatch_out);
re_extmatch_out = NULL;
unref_extmatch(cur_extmatch);
@@ -2151,16 +2208,14 @@ static int syn_current_attr(
}
-/*
- * Check if we already matched pattern "idx" at the current column.
- */
-static int did_match_already(int idx, garray_T *gap)
+/// @return true if we already matched pattern "idx" at the current column.
+static bool did_match_already(int idx, garray_T *gap)
{
for (int i = current_state.ga_len; --i >= 0; ) {
if (CUR_STATE(i).si_m_startcol == (int)current_col
&& CUR_STATE(i).si_m_lnum == (int)current_lnum
&& CUR_STATE(i).si_idx == idx) {
- return TRUE;
+ return true;
}
}
@@ -2168,11 +2223,11 @@ static int did_match_already(int idx, garray_T *gap)
* stack, and can only be matched once anyway. */
for (int i = gap->ga_len; --i >= 0; ) {
if (((int *)(gap->ga_data))[i] == idx) {
- return TRUE;
+ return true;
}
}
- return FALSE;
+ return false;
}
/*
@@ -2202,14 +2257,15 @@ static stateitem_T *push_next_match(void)
cur_si->si_flags = spp->sp_flags;
cur_si->si_seqnr = next_seqnr++;
cur_si->si_cchar = spp->sp_cchar;
- if (current_state.ga_len > 1)
+ if (current_state.ga_len > 1) {
cur_si->si_flags |=
CUR_STATE(current_state.ga_len - 2).si_flags & HL_CONCEAL;
+ }
cur_si->si_next_list = spp->sp_next_list;
cur_si->si_extmatch = ref_extmatch(next_match_extmatch);
if (spp->sp_type == SPTYPE_START && !(spp->sp_flags & HL_ONELINE)) {
- /* Try to find the end pattern in the current line */
- update_si_end(cur_si, (int)(next_match_m_endpos.col), TRUE);
+ // Try to find the end pattern in the current line
+ update_si_end(cur_si, (int)(next_match_m_endpos.col), true);
check_keepend();
} else {
cur_si->si_m_endpos = next_match_m_endpos;
@@ -2219,8 +2275,9 @@ static stateitem_T *push_next_match(void)
cur_si->si_eoe_pos = next_match_eoe_pos;
cur_si->si_end_idx = next_match_end_idx;
}
- if (keepend_level < 0 && (cur_si->si_flags & HL_KEEPEND))
+ if (keepend_level < 0 && (cur_si->si_flags & HL_KEEPEND)) {
keepend_level = current_state.ga_len - 1;
+ }
check_keepend();
update_si_attr(current_state.ga_len - 1);
@@ -2242,15 +2299,16 @@ static stateitem_T *push_next_match(void)
cur_si->si_flags = HL_MATCH;
cur_si->si_seqnr = next_seqnr++;
cur_si->si_flags |= save_flags;
- if (cur_si->si_flags & HL_CONCEALENDS)
+ if (cur_si->si_flags & HL_CONCEALENDS) {
cur_si->si_flags |= HL_CONCEAL;
+ }
cur_si->si_next_list = NULL;
check_keepend();
update_si_attr(current_state.ga_len - 1);
}
}
- next_match_idx = -1; /* try other match next time */
+ next_match_idx = -1; // try other match next time
return cur_si;
}
@@ -2285,14 +2343,15 @@ static void check_state_ends(void)
cur_si->si_h_endpos = cur_si->si_eoe_pos;
cur_si->si_flags |= HL_MATCH;
cur_si->si_seqnr = next_seqnr++;
- if (cur_si->si_flags & HL_CONCEALENDS)
+ if (cur_si->si_flags & HL_CONCEALENDS) {
cur_si->si_flags |= HL_CONCEAL;
+ }
update_si_attr(current_state.ga_len - 1);
- /* nextgroup= should not match in the end pattern */
+ // nextgroup= should not match in the end pattern
current_next_list = NULL;
- /* what matches next may be different now, clear it */
+ // what matches next may be different now, clear it
next_match_idx = 0;
next_match_col = MAXCOL;
break;
@@ -2302,8 +2361,9 @@ static void check_state_ends(void)
current_next_list = cur_si->si_next_list;
current_next_flags = cur_si->si_flags;
if (!(current_next_flags & (HL_SKIPNL | HL_SKIPEMPTY))
- && syn_getcurline()[current_col] == NUL)
+ && syn_getcurline()[current_col] == NUL) {
current_next_list = NULL;
+ }
/* When the ended item has "extend", another item with
* "keepend" now needs to check for its end. */
@@ -2311,13 +2371,15 @@ static void check_state_ends(void)
pop_current_state();
- if (GA_EMPTY(&current_state))
+ if (GA_EMPTY(&current_state)) {
break;
+ }
if (had_extend && keepend_level >= 0) {
- syn_update_ends(FALSE);
- if (GA_EMPTY(&current_state))
+ syn_update_ends(false);
+ if (GA_EMPTY(&current_state)) {
break;
+ }
}
cur_si = &CUR_STATE(current_state.ga_len - 1);
@@ -2335,16 +2397,18 @@ static void check_state_ends(void)
&& SYN_ITEMS(syn_block)[cur_si->si_idx].sp_type
== SPTYPE_START
&& !(cur_si->si_flags & (HL_MATCH | HL_KEEPEND))) {
- update_si_end(cur_si, (int)current_col, TRUE);
+ update_si_end(cur_si, (int)current_col, true);
check_keepend();
if ((current_next_flags & HL_HAS_EOL)
&& keepend_level < 0
- && syn_getcurline()[current_col] == NUL)
+ && syn_getcurline()[current_col] == NUL) {
break;
+ }
}
}
- } else
+ } else {
break;
+ }
}
}
@@ -2355,23 +2419,26 @@ static void check_state_ends(void)
static void update_si_attr(int idx)
{
stateitem_T *sip = &CUR_STATE(idx);
- synpat_T *spp;
+ synpat_T *spp;
- /* This should not happen... */
- if (sip->si_idx < 0)
+ // This should not happen...
+ if (sip->si_idx < 0) {
return;
+ }
spp = &(SYN_ITEMS(syn_block)[sip->si_idx]);
- if (sip->si_flags & HL_MATCH)
+ if (sip->si_flags & HL_MATCH) {
sip->si_id = spp->sp_syn_match_id;
- else
+ } else {
sip->si_id = spp->sp_syn.id;
+ }
sip->si_attr = syn_id2attr(sip->si_id);
sip->si_trans_id = sip->si_id;
- if (sip->si_flags & HL_MATCH)
+ if (sip->si_flags & HL_MATCH) {
sip->si_cont_list = NULL;
- else
+ } else {
sip->si_cont_list = spp->sp_cont_list;
+ }
/*
* For transparent items, take attr from outer item.
@@ -2382,8 +2449,9 @@ static void update_si_attr(int idx)
if (idx == 0) {
sip->si_attr = 0;
sip->si_trans_id = 0;
- if (sip->si_cont_list == NULL)
+ if (sip->si_cont_list == NULL) {
sip->si_cont_list = ID_LIST_ALL;
+ }
} else {
sip->si_attr = CUR_STATE(idx - 1).si_attr;
sip->si_trans_id = CUR_STATE(idx - 1).si_trans_id;
@@ -2412,17 +2480,20 @@ static void check_keepend(void)
* This check can consume a lot of time; only do it from the level where
* there really is a keepend.
*/
- if (keepend_level < 0)
+ if (keepend_level < 0) {
return;
+ }
/*
* Find the last index of an "extend" item. "keepend" items before that
* won't do anything. If there is no "extend" item "i" will be
* "keepend_level" and all "keepend" items will work normally.
*/
- for (i = current_state.ga_len - 1; i > keepend_level; --i)
- if (CUR_STATE(i).si_flags & HL_EXTEND)
+ for (i = current_state.ga_len - 1; i > keepend_level; --i) {
+ if (CUR_STATE(i).si_flags & HL_EXTEND) {
break;
+ }
+ }
maxpos.lnum = 0;
maxpos.col = 0;
@@ -2440,42 +2511,42 @@ static void check_keepend(void)
if (maxpos.lnum == 0
|| maxpos.lnum > sip->si_m_endpos.lnum
|| (maxpos.lnum == sip->si_m_endpos.lnum
- && maxpos.col > sip->si_m_endpos.col))
+ && maxpos.col > sip->si_m_endpos.col)) {
maxpos = sip->si_m_endpos;
+ }
if (maxpos_h.lnum == 0
|| maxpos_h.lnum > sip->si_h_endpos.lnum
|| (maxpos_h.lnum == sip->si_h_endpos.lnum
- && maxpos_h.col > sip->si_h_endpos.col))
+ && maxpos_h.col > sip->si_h_endpos.col)) {
maxpos_h = sip->si_h_endpos;
+ }
}
}
}
-/*
- * Update an entry in the current_state stack for a start-skip-end pattern.
- * This finds the end of the current item, if it's in the current line.
- *
- * Return the flags for the matched END.
- */
-static void
-update_si_end(
- stateitem_T *sip,
- int startcol, /* where to start searching for the end */
- int force /* when TRUE overrule a previous end */
-)
+/// Update an entry in the current_state stack for a start-skip-end pattern.
+/// This finds the end of the current item, if it's in the current line.
+///
+/// @param startcol where to start searching for the end
+/// @param force when true overrule a previous end
+///
+/// @return the flags for the matched END.
+static void update_si_end(stateitem_T *sip, int startcol, bool force)
{
lpos_T hl_endpos;
lpos_T end_endpos;
- /* return quickly for a keyword */
- if (sip->si_idx < 0)
+ // return quickly for a keyword
+ if (sip->si_idx < 0) {
return;
+ }
/* Don't update when it's already done. Can be a match of an end pattern
* that started in a previous line. Watch out: can also be a "keepend"
* from a containing item. */
- if (!force && sip->si_m_endpos.lnum >= current_lnum)
+ if (!force && sip->si_m_endpos.lnum >= current_lnum) {
return;
+ }
/*
* We need to find the end of the region. It may continue in the next
@@ -2488,23 +2559,23 @@ update_si_end(
};
lpos_T endpos = { 0 };
find_endpos(sip->si_idx, &startpos, &endpos, &hl_endpos,
- &(sip->si_flags), &end_endpos, &end_idx, sip->si_extmatch);
+ &(sip->si_flags), &end_endpos, &end_idx, sip->si_extmatch);
if (endpos.lnum == 0) {
- /* No end pattern matched. */
+ // No end pattern matched.
if (SYN_ITEMS(syn_block)[sip->si_idx].sp_flags & HL_ONELINE) {
- /* a "oneline" never continues in the next line */
+ // a "oneline" never continues in the next line
sip->si_ends = TRUE;
sip->si_m_endpos.lnum = current_lnum;
sip->si_m_endpos.col = (colnr_T)STRLEN(syn_getcurline());
} else {
- /* continues in the next line */
+ // continues in the next line
sip->si_ends = FALSE;
sip->si_m_endpos.lnum = 0;
}
sip->si_h_endpos = sip->si_m_endpos;
} else {
- /* match within this line */
+ // match within this line
sip->si_m_endpos = endpos;
sip->si_h_endpos = hl_endpos;
sip->si_eoe_pos = end_endpos;
@@ -2533,49 +2604,49 @@ static void pop_current_state(void)
unref_extmatch(CUR_STATE(current_state.ga_len - 1).si_extmatch);
--current_state.ga_len;
}
- /* after the end of a pattern, try matching a keyword or pattern */
+ // after the end of a pattern, try matching a keyword or pattern
next_match_idx = -1;
- /* if first state with "keepend" is popped, reset keepend_level */
- if (keepend_level >= current_state.ga_len)
+ // if first state with "keepend" is popped, reset keepend_level
+ if (keepend_level >= current_state.ga_len) {
keepend_level = -1;
+ }
}
-/*
- * Find the end of a start/skip/end syntax region after "startpos".
- * Only checks one line.
- * Also handles a match item that continued from a previous line.
- * If not found, the syntax item continues in the next line. m_endpos->lnum
- * will be 0.
- * If found, the end of the region and the end of the highlighting is
- * computed.
- */
-static void
-find_endpos(
- int idx, // index of the pattern
- lpos_T *startpos, // where to start looking for an END match
- lpos_T *m_endpos, // return: end of match
- lpos_T *hl_endpos, // return: end of highlighting
- long *flagsp, // return: flags of matching END
- lpos_T *end_endpos, // return: end of end pattern match
- int *end_idx, // return: group ID for end pat. match, or 0
- reg_extmatch_T *start_ext // submatches from the start pattern
-)
+/// Find the end of a start/skip/end syntax region after "startpos".
+/// Only checks one line.
+/// Also handles a match item that continued from a previous line.
+/// If not found, the syntax item continues in the next line. m_endpos->lnum
+/// will be 0.
+/// If found, the end of the region and the end of the highlighting is
+/// computed.
+///
+/// @param idx index of the pattern
+/// @param startpos where to start looking for an END match
+/// @param m_endpos return: end of match
+/// @param hl_endpos return: end of highlighting
+/// @param flagsp return: flags of matching END
+/// @param end_endpos return: end of end pattern match
+/// @param end_idx return: group ID for end pat. match, or 0
+/// @param start_ext submatches from the start pattern
+static void find_endpos(int idx, lpos_T *startpos, lpos_T *m_endpos, lpos_T *hl_endpos,
+ long *flagsp, lpos_T *end_endpos, int *end_idx, reg_extmatch_T *start_ext)
{
colnr_T matchcol;
- synpat_T *spp, *spp_skip;
+ synpat_T *spp, *spp_skip;
int start_idx;
int best_idx;
regmmatch_T regmatch;
- regmmatch_T best_regmatch; /* startpos/endpos of best match */
+ regmmatch_T best_regmatch; // startpos/endpos of best match
lpos_T pos;
- char_u *line;
- int had_match = false;
+ char_u *line;
+ bool had_match = false;
char_u buf_chartab[32]; // chartab array for syn option iskeyword
- /* just in case we are invoked for a keyword */
- if (idx < 0)
+ // just in case we are invoked for a keyword
+ if (idx < 0) {
return;
+ }
/*
* Check for being called with a START pattern.
@@ -2593,21 +2664,23 @@ find_endpos(
*/
for (;; ) {
spp = &(SYN_ITEMS(syn_block)[idx]);
- if (spp->sp_type != SPTYPE_START)
+ if (spp->sp_type != SPTYPE_START) {
break;
+ }
++idx;
}
/*
- * Lookup the SKIP pattern (if present)
+ * Lookup the SKIP pattern (if present)
*/
if (spp->sp_type == SPTYPE_SKIP) {
spp_skip = spp;
++idx;
- } else
+ } else {
spp_skip = NULL;
+ }
- /* Setup external matches for syn_regexec(). */
+ // Setup external matches for syn_regexec().
unref_extmatch(re_extmatch_in);
re_extmatch_in = ref_extmatch(start_ext);
@@ -2627,11 +2700,13 @@ find_endpos(
int lc_col = matchcol;
spp = &(SYN_ITEMS(syn_block)[idx]);
- if (spp->sp_type != SPTYPE_END) /* past last END pattern */
+ if (spp->sp_type != SPTYPE_END) { // past last END pattern
break;
+ }
lc_col -= spp->sp_offsets[SPO_LC_OFF];
- if (lc_col < 0)
+ if (lc_col < 0) {
lc_col = 0;
+ }
regmatch.rmm_ic = spp->sp_ic;
regmatch.regprog = spp->sp_prog;
@@ -2652,8 +2727,9 @@ find_endpos(
* If all end patterns have been tried, and there is no match, the
* item continues until end-of-line.
*/
- if (best_idx == -1)
+ if (best_idx == -1) {
break;
+ }
/*
* If the skip pattern matches before the end pattern,
@@ -2662,8 +2738,9 @@ find_endpos(
if (spp_skip != NULL) {
int lc_col = matchcol - spp_skip->sp_offsets[SPO_LC_OFF];
- if (lc_col < 0)
+ if (lc_col < 0) {
lc_col = 0;
+ }
regmatch.rmm_ic = spp_skip->sp_ic;
regmatch.regprog = spp_skip->sp_prog;
int r = syn_regexec(&regmatch, startpos->lnum, lc_col,
@@ -2710,16 +2787,18 @@ find_endpos(
*/
spp = &(SYN_ITEMS(syn_block)[best_idx]);
syn_add_end_off(m_endpos, &best_regmatch, spp, SPO_ME_OFF, 1);
- /* can't end before the start */
- if (m_endpos->lnum == startpos->lnum && m_endpos->col < startpos->col)
+ // can't end before the start
+ if (m_endpos->lnum == startpos->lnum && m_endpos->col < startpos->col) {
m_endpos->col = startpos->col;
+ }
syn_add_end_off(end_endpos, &best_regmatch, spp, SPO_HE_OFF, 1);
- /* can't end before the start */
+ // can't end before the start
if (end_endpos->lnum == startpos->lnum
- && end_endpos->col < startpos->col)
+ && end_endpos->col < startpos->col) {
end_endpos->col = startpos->col;
- /* can't end after the match */
+ }
+ // can't end after the match
limit_pos(end_endpos, m_endpos);
/*
@@ -2736,10 +2815,11 @@ find_endpos(
}
hl_endpos->col += spp->sp_offsets[SPO_RE_OFF];
- /* can't end before the start */
+ // can't end before the start
if (hl_endpos->lnum == startpos->lnum
- && hl_endpos->col < startpos->col)
+ && hl_endpos->col < startpos->col) {
hl_endpos->col = startpos->col;
+ }
limit_pos(hl_endpos, m_endpos);
/* now the match ends where the highlighting ends, it is turned
@@ -2752,17 +2832,18 @@ find_endpos(
*flagsp = spp->sp_flags;
- had_match = TRUE;
+ had_match = true;
break;
}
- /* no match for an END pattern in this line */
- if (!had_match)
+ // no match for an END pattern in this line
+ if (!had_match) {
m_endpos->lnum = 0;
+ }
restore_chartab(buf_chartab);
- /* Remove external matches. */
+ // Remove external matches.
unref_extmatch(re_extmatch_in);
re_extmatch_in = NULL;
}
@@ -2772,10 +2853,11 @@ find_endpos(
*/
static void limit_pos(lpos_T *pos, lpos_T *limit)
{
- if (pos->lnum > limit->lnum)
+ if (pos->lnum > limit->lnum) {
*pos = *limit;
- else if (pos->lnum == limit->lnum && pos->col > limit->col)
+ } else if (pos->lnum == limit->lnum && pos->col > limit->col) {
pos->col = limit->col;
+ }
}
/*
@@ -2783,28 +2865,27 @@ static void limit_pos(lpos_T *pos, lpos_T *limit)
*/
static void limit_pos_zero(lpos_T *pos, lpos_T *limit)
{
- if (pos->lnum == 0)
+ if (pos->lnum == 0) {
*pos = *limit;
- else
+ } else {
limit_pos(pos, limit);
+ }
}
-/*
- * Add offset to matched text for end of match or highlight.
- */
-static void
-syn_add_end_off(
- lpos_T *result, // returned position
- regmmatch_T *regmatch, // start/end of match
- synpat_T *spp, // matched pattern
- int idx, // index of offset
- int extra // extra chars for offset to start
-)
+/// Add offset to matched text for end of match or highlight.
+///
+/// @param result returned position
+/// @param regmatch start/end of match
+/// @param spp matched pattern
+/// @param idx index of offset
+/// @param extra extra chars for offset to start
+static void syn_add_end_off(lpos_T *result, regmmatch_T *regmatch, synpat_T *spp, int idx,
+ int extra)
{
int col;
int off;
- char_u *base;
- char_u *p;
+ char_u *base;
+ char_u *p;
if (spp->sp_off_flags & (1 << idx)) {
result->lnum = regmatch->startpos[0].lnum;
@@ -2815,12 +2896,12 @@ syn_add_end_off(
col = regmatch->endpos[0].col;
off = spp->sp_offsets[idx];
}
- /* Don't go past the end of the line. Matters for "rs=e+2" when there
- * is a matchgroup. Watch out for match with last NL in the buffer. */
- if (result->lnum > syn_buf->b_ml.ml_line_count)
+ // Don't go past the end of the line. Matters for "rs=e+2" when there
+ // is a matchgroup. Watch out for match with last NL in the buffer.
+ if (result->lnum > syn_buf->b_ml.ml_line_count) {
col = 0;
- else if (off != 0) {
- base = ml_get_buf(syn_buf, result->lnum, FALSE);
+ } else if (off != 0) {
+ base = ml_get_buf(syn_buf, result->lnum, false);
p = base + col;
if (off > 0) {
while (off-- > 0 && *p != NUL) {
@@ -2836,23 +2917,19 @@ syn_add_end_off(
result->col = col;
}
-/*
- * Add offset to matched text for start of match or highlight.
- * Avoid resulting column to become negative.
- */
-static void
-syn_add_start_off(
- lpos_T *result, // returned position
- regmmatch_T *regmatch, // start/end of match
- synpat_T *spp,
- int idx,
- int extra // extra chars for offset to end
-)
+/// Add offset to matched text for start of match or highlight.
+/// Avoid resulting column to become negative.
+///
+/// @param result returned position
+/// @param regmatch start/end of match
+/// @param extra extra chars for offset to end
+static void syn_add_start_off(lpos_T *result, regmmatch_T *regmatch, synpat_T *spp, int idx,
+ int extra)
{
int col;
int off;
- char_u *base;
- char_u *p;
+ char_u *base;
+ char_u *p;
if (spp->sp_off_flags & (1 << (idx + SPO_COUNT))) {
result->lnum = regmatch->endpos[0].lnum;
@@ -2864,12 +2941,12 @@ syn_add_start_off(
off = spp->sp_offsets[idx];
}
if (result->lnum > syn_buf->b_ml.ml_line_count) {
- /* a "\n" at the end of the pattern may take us below the last line */
+ // a "\n" at the end of the pattern may take us below the last line
result->lnum = syn_buf->b_ml.ml_line_count;
- col = (int)STRLEN(ml_get_buf(syn_buf, result->lnum, FALSE));
+ col = (int)STRLEN(ml_get_buf(syn_buf, result->lnum, false));
}
if (off != 0) {
- base = ml_get_buf(syn_buf, result->lnum, FALSE);
+ base = ml_get_buf(syn_buf, result->lnum, false);
p = base + col;
if (off > 0) {
while (off-- && *p != NUL) {
@@ -2890,7 +2967,7 @@ syn_add_start_off(
*/
static char_u *syn_getcurline(void)
{
- return ml_get_buf(syn_buf, current_lnum, FALSE);
+ return ml_get_buf(syn_buf, current_lnum, false);
}
/*
@@ -2902,7 +2979,7 @@ static int syn_regexec(regmmatch_T *rmp, linenr_T lnum, colnr_T col, syn_time_T
int r;
int timed_out = 0;
proftime_T pt;
- const int l_syn_time_on = syn_time_on;
+ const bool l_syn_time_on = syn_time_on;
if (l_syn_time_on) {
pt = profile_start();
@@ -2926,8 +3003,9 @@ static int syn_regexec(regmmatch_T *rmp, linenr_T lnum, colnr_T col, syn_time_T
st->slowest = pt;
}
++st->count;
- if (r > 0)
+ if (r > 0) {
++st->match;
+ }
}
if (timed_out && !syn_win->w_s->b_syn_slow) {
syn_win->w_s->b_syn_slow = true;
@@ -2942,20 +3020,19 @@ static int syn_regexec(regmmatch_T *rmp, linenr_T lnum, colnr_T col, syn_time_T
return FALSE;
}
-/*
- * Check one position in a line for a matching keyword.
- * The caller must check if a keyword can start at startcol.
- * Return its ID if found, 0 otherwise.
- */
-static int check_keyword_id(
- char_u *const line,
- const int startcol, // position in line to check for keyword
- int *const endcolp, // return: character after found keyword
- long *const flagsp, // return: flags of matching keyword
- int16_t **const next_listp, // return: next_list of matching keyword
- stateitem_T *const cur_si, // item at the top of the stack
- int *const ccharp // conceal substitution char
-)
+/// Check one position in a line for a matching keyword.
+/// The caller must check if a keyword can start at startcol.
+/// Return its ID if found, 0 otherwise.
+///
+/// @param startcol position in line to check for keyword
+/// @param endcolp return: character after found keyword
+/// @param flagsp return: flags of matching keyword
+/// @param next_listp return: next_list of matching keyword
+/// @param cur_si item at the top of the stack
+/// @param ccharp conceal substitution char
+static int check_keyword_id(char_u *const line, const int startcol, int *const endcolp,
+ long *const flagsp, int16_t **const next_listp,
+ stateitem_T *const cur_si, int *const ccharp)
{
// Find first character after the keyword. First character was already
// checked.
@@ -3003,11 +3080,10 @@ static int check_keyword_id(
/// When current_next_list is non-zero accept only that group, otherwise:
/// Accept a not-contained keyword at toplevel.
/// Accept a keyword at other levels only if it is in the contains list.
-static keyentry_T *match_keyword(char_u *keyword, hashtab_T *ht,
- stateitem_T *cur_si)
+static keyentry_T *match_keyword(char_u *keyword, hashtab_T *ht, stateitem_T *cur_si)
{
hashitem_T *hi = hash_find(ht, keyword);
- if (!HASHITEM_EMPTY(hi))
+ if (!HASHITEM_EMPTY(hi)) {
for (keyentry_T *kp = HI2KE(hi); kp != NULL; kp = kp->ke_next) {
if (current_next_list != 0
? in_id_list(NULL, current_next_list, &kp->k_syn, 0)
@@ -3018,6 +3094,7 @@ static keyentry_T *match_keyword(char_u *keyword, hashtab_T *ht,
return kp;
}
}
+ }
return NULL;
}
@@ -3026,12 +3103,13 @@ static keyentry_T *match_keyword(char_u *keyword, hashtab_T *ht,
*/
static void syn_cmd_conceal(exarg_T *eap, int syncing)
{
- char_u *arg = eap->arg;
- char_u *next;
+ char_u *arg = eap->arg;
+ char_u *next;
eap->nextcmd = find_nextcmd(arg);
- if (eap->skip)
+ if (eap->skip) {
return;
+ }
next = skiptowhite(arg);
if (*arg == NUL) {
@@ -3054,12 +3132,13 @@ static void syn_cmd_conceal(exarg_T *eap, int syncing)
*/
static void syn_cmd_case(exarg_T *eap, int syncing)
{
- char_u *arg = eap->arg;
- char_u *next;
+ char_u *arg = eap->arg;
+ char_u *next;
eap->nextcmd = find_nextcmd(arg);
- if (eap->skip)
+ if (eap->skip) {
return;
+ }
next = skiptowhite(arg);
if (*arg == NUL) {
@@ -3084,14 +3163,18 @@ static void syn_cmd_foldlevel(exarg_T *eap, int syncing)
char_u *arg_end;
eap->nextcmd = find_nextcmd(arg);
- if (eap->skip)
+ if (eap->skip) {
return;
+ }
if (*arg == NUL) {
switch (curwin->w_s->b_syn_foldlevel) {
- case SYNFLD_START: MSG(_("syntax foldlevel start")); break;
- case SYNFLD_MINIMUM: MSG(_("syntax foldlevel minimum")); break;
- default: break;
+ case SYNFLD_START:
+ MSG(_("syntax foldlevel start")); break;
+ case SYNFLD_MINIMUM:
+ MSG(_("syntax foldlevel minimum")); break;
+ default:
+ break;
}
return;
}
@@ -3117,12 +3200,13 @@ static void syn_cmd_foldlevel(exarg_T *eap, int syncing)
*/
static void syn_cmd_spell(exarg_T *eap, int syncing)
{
- char_u *arg = eap->arg;
- char_u *next;
+ char_u *arg = eap->arg;
+ char_u *next;
eap->nextcmd = find_nextcmd(arg);
- if (eap->skip)
+ if (eap->skip) {
return;
+ }
next = skiptowhite(arg);
if (*arg == NUL) {
@@ -3201,17 +3285,17 @@ void syntax_clear(synblock_T *block)
block->b_syn_containedin = false;
block->b_syn_conceal = false;
- /* free the keywords */
+ // free the keywords
clear_keywtab(&block->b_keywtab);
clear_keywtab(&block->b_keywtab_ic);
- /* free the syntax patterns */
+ // free the syntax patterns
for (int i = block->b_syn_patterns.ga_len; --i >= 0; ) {
syn_clear_pattern(block, i);
}
ga_clear(&block->b_syn_patterns);
- /* free the syntax clusters */
+ // free the syntax clusters
for (int i = block->b_syn_clusters.ga_len; --i >= 0; ) {
syn_clear_cluster(block, i);
}
@@ -3230,11 +3314,11 @@ void syntax_clear(synblock_T *block)
block->b_syn_folditems = 0;
clear_string_option(&block->b_syn_isk);
- /* free the stored states */
+ // free the stored states
syn_stack_free_all(block);
invalidate_current_state();
- /* Reset the counter for ":syn include" */
+ // Reset the counter for ":syn include"
running_syn_inc_tag = 0;
}
@@ -3255,7 +3339,7 @@ void reset_synblock(win_T *wp)
*/
static void syntax_sync_clear(void)
{
- /* free the syntax patterns */
+ // free the syntax patterns
for (int i = curwin->w_s->b_syn_patterns.ga_len; --i >= 0; ) {
if (SYN_ITEMS(curwin->w_s)[i].sp_syncing) {
syn_remove_pattern(curwin->w_s, i);
@@ -3272,7 +3356,7 @@ static void syntax_sync_clear(void)
XFREE_CLEAR(curwin->w_s->b_syn_linecont_pat);
clear_string_option(&curwin->w_s->b_syn_isk);
- syn_stack_free_all(curwin->w_s); /* Need to recompute all syntax. */
+ syn_stack_free_all(curwin->w_s); // Need to recompute all syntax.
}
/*
@@ -3280,14 +3364,15 @@ static void syntax_sync_clear(void)
*/
static void syn_remove_pattern(synblock_T *block, int idx)
{
- synpat_T *spp;
+ synpat_T *spp;
spp = &(SYN_ITEMS(block)[idx]);
- if (spp->sp_flags & HL_FOLD)
+ if (spp->sp_flags & HL_FOLD) {
--block->b_syn_folditems;
+ }
syn_clear_pattern(block, idx);
memmove(spp, spp + 1,
- sizeof(synpat_T) * (block->b_syn_patterns.ga_len - idx - 1));
+ sizeof(synpat_T) * (block->b_syn_patterns.ga_len - idx - 1));
--block->b_syn_patterns.ga_len;
}
@@ -3299,7 +3384,7 @@ static void syn_clear_pattern(synblock_T *block, int i)
{
xfree(SYN_ITEMS(block)[i].sp_pattern);
vim_regfree(SYN_ITEMS(block)[i].sp_prog);
- /* Only free sp_cont_list and sp_next_list of first start pattern */
+ // Only free sp_cont_list and sp_next_list of first start pattern
if (i == 0 || SYN_ITEMS(block)[i - 1].sp_type != SPTYPE_START) {
xfree(SYN_ITEMS(block)[i].sp_cont_list);
xfree(SYN_ITEMS(block)[i].sp_next_list);
@@ -3322,13 +3407,14 @@ static void syn_clear_cluster(synblock_T *block, int i)
*/
static void syn_cmd_clear(exarg_T *eap, int syncing)
{
- char_u *arg = eap->arg;
- char_u *arg_end;
+ char_u *arg = eap->arg;
+ char_u *arg_end;
int id;
eap->nextcmd = find_nextcmd(arg);
- if (eap->skip)
+ if (eap->skip) {
return;
+ }
/*
* We have to disable this within ":syn include @group filename",
@@ -3336,16 +3422,17 @@ static void syn_cmd_clear(exarg_T *eap, int syncing)
* Only required for Vim 5.x syntax files, 6.0 ones don't contain ":syn
* clear".
*/
- if (curwin->w_s->b_syn_topgrp != 0)
+ if (curwin->w_s->b_syn_topgrp != 0) {
return;
+ }
if (ends_excmd(*arg)) {
/*
* No argument: Clear all syntax items.
*/
- if (syncing)
+ if (syncing) {
syntax_sync_clear();
- else {
+ } else {
syntax_clear(curwin->w_s);
if (curwin->w_s == &curwin->w_buffer->b_s) {
do_unlet(S_LEN("b:current_syntax"), true);
@@ -3372,18 +3459,19 @@ static void syn_cmd_clear(exarg_T *eap, int syncing)
XFREE_CLEAR(SYN_CLSTR(curwin->w_s)[scl_id].scl_list);
}
} else {
- id = syn_namen2id(arg, (int)(arg_end - arg));
+ id = syn_name2id_len(arg, (int)(arg_end - arg));
if (id == 0) {
EMSG2(_(e_nogroup), arg);
break;
- } else
+ } else {
syn_clear_one(id, syncing);
+ }
}
arg = skipwhite(arg_end);
}
}
redraw_curbuf_later(SOME_VALID);
- syn_stack_free_all(curwin->w_s); /* Need to recompute all syntax. */
+ syn_stack_free_all(curwin->w_s); // Need to recompute all syntax.
}
/*
@@ -3391,19 +3479,20 @@ static void syn_cmd_clear(exarg_T *eap, int syncing)
*/
static void syn_clear_one(const int id, const bool syncing)
{
- synpat_T *spp;
+ synpat_T *spp;
- /* Clear keywords only when not ":syn sync clear group-name" */
+ // Clear keywords only when not ":syn sync clear group-name"
if (!syncing) {
syn_clear_keyword(id, &curwin->w_s->b_keywtab);
syn_clear_keyword(id, &curwin->w_s->b_keywtab_ic);
}
- /* clear the patterns for "id" */
+ // clear the patterns for "id"
for (int idx = curwin->w_s->b_syn_patterns.ga_len; --idx >= 0; ) {
spp = &(SYN_ITEMS(curwin->w_s)[idx]);
- if (spp->sp_syn.id != id || spp->sp_syncing != syncing)
+ if (spp->sp_syn.id != id || spp->sp_syncing != syncing) {
continue;
+ }
syn_remove_pattern(curwin->w_s, idx);
}
}
@@ -3417,16 +3506,6 @@ static void syn_cmd_on(exarg_T *eap, int syncing)
}
/*
- * Handle ":syntax enable" command.
- */
-static void syn_cmd_enable(exarg_T *eap, int syncing)
-{
- set_internal_string_var("syntax_cmd", (char_u *)"enable");
- syn_cmd_onoff(eap, "syntax");
- do_unlet(S_LEN("g:syntax_cmd"), true);
-}
-
-/*
* Handle ":syntax reset" command.
* It actually resets highlighting, not syntax.
*/
@@ -3434,9 +3513,7 @@ static void syn_cmd_reset(exarg_T *eap, int syncing)
{
eap->nextcmd = check_nextcmd(eap->arg);
if (!eap->skip) {
- set_internal_string_var("syntax_cmd", (char_u *)"reset");
- do_cmdline_cmd("runtime! syntax/syncolor.vim");
- do_unlet(S_LEN("g:syntax_cmd"), true);
+ init_highlight(true, true);
}
}
@@ -3475,25 +3552,22 @@ void syn_maybe_enable(void)
exarg_T ea;
ea.arg = (char_u *)"";
ea.skip = false;
- syn_cmd_enable(&ea, false);
+ syn_cmd_on(&ea, false);
}
}
-/*
- * Handle ":syntax [list]" command: list current syntax words.
- */
-static void
-syn_cmd_list(
- exarg_T *eap,
- int syncing /* when TRUE: list syncing items */
-)
+/// Handle ":syntax [list]" command: list current syntax words.
+///
+/// @param syncing when TRUE: list syncing items
+static void syn_cmd_list(exarg_T *eap, int syncing)
{
- char_u *arg = eap->arg;
- char_u *arg_end;
+ char_u *arg = eap->arg;
+ char_u *arg_end;
eap->nextcmd = find_nextcmd(arg);
- if (eap->skip)
+ if (eap->skip) {
return;
+ }
if (!syntax_present(curwin)) {
MSG(_(msg_no_items));
@@ -3506,7 +3580,7 @@ syn_cmd_list(
syn_lines_msg();
syn_match_msg();
return;
- } else if (!(curwin->w_s->b_syn_sync_flags & SF_MATCH)) {
+ } else if (!(curwin->w_s->b_syn_sync_flags & SF_MATCH)) {
if (curwin->w_s->b_syn_sync_minlines == 0) {
MSG_PUTS(_("no syncing"));
} else {
@@ -3529,8 +3603,9 @@ syn_cmd_list(
syn_lines_msg();
syn_match_msg();
}
- } else
+ } else {
MSG_PUTS_TITLE(_("\n--- Syntax items ---"));
+ }
if (ends_excmd(*arg)) {
/*
* No argument: List all group IDs and all syntax clusters.
@@ -3549,12 +3624,13 @@ syn_cmd_list(
arg_end = skiptowhite(arg);
if (*arg == '@') {
int id = syn_scl_namen2id(arg + 1, (int)(arg_end - arg - 1));
- if (id == 0)
+ if (id == 0) {
EMSG2(_("E392: No such syntax cluster: %s"), arg);
- else
+ } else {
syn_list_cluster(id - SYNID_CLUSTER);
+ }
} else {
- int id = syn_namen2id(arg, (int)(arg_end - arg));
+ int id = syn_name2id_len(arg, (int)(arg_end - arg));
if (id == 0) {
EMSG2(_(e_nogroup), arg);
} else {
@@ -3603,37 +3679,33 @@ static void syn_match_msg(void)
static int last_matchgroup;
-/*
- * List one syntax item, for ":syntax" or "syntax list syntax_name".
- */
-static void
-syn_list_one(
- const int id,
- const bool syncing, // when true: list syncing items
- const bool link_only // when true; list link-only too
-)
+/// List one syntax item, for ":syntax" or "syntax list syntax_name".
+///
+/// @param syncing when true: list syncing items
+/// @param link_only when true; list link-only too
+static void syn_list_one(const int id, const bool syncing, const bool link_only)
{
bool did_header = false;
static struct name_list namelist1[] =
{
- {HL_DISPLAY, "display"},
- {HL_CONTAINED, "contained"},
- {HL_ONELINE, "oneline"},
- {HL_KEEPEND, "keepend"},
- {HL_EXTEND, "extend"},
- {HL_EXCLUDENL, "excludenl"},
- {HL_TRANSP, "transparent"},
- {HL_FOLD, "fold"},
- {HL_CONCEAL, "conceal"},
- {HL_CONCEALENDS, "concealends"},
- {0, NULL}
+ { HL_DISPLAY, "display" },
+ { HL_CONTAINED, "contained" },
+ { HL_ONELINE, "oneline" },
+ { HL_KEEPEND, "keepend" },
+ { HL_EXTEND, "extend" },
+ { HL_EXCLUDENL, "excludenl" },
+ { HL_TRANSP, "transparent" },
+ { HL_FOLD, "fold" },
+ { HL_CONCEAL, "conceal" },
+ { HL_CONCEALENDS, "concealends" },
+ { 0, NULL }
};
static struct name_list namelist2[] =
{
- {HL_SKIPWHITE, "skipwhite"},
- {HL_SKIPNL, "skipnl"},
- {HL_SKIPEMPTY, "skipempty"},
- {0, NULL}
+ { HL_SKIPWHITE, "skipwhite" },
+ { HL_SKIPNL, "skipnl" },
+ { HL_SKIPEMPTY, "skipempty" },
+ { 0, NULL }
};
const int attr = HL_ATTR(HLF_D); // highlight like directories
@@ -3660,14 +3732,17 @@ syn_list_one(
if (spp->sp_type == SPTYPE_MATCH) {
put_pattern("match", ' ', spp, attr);
msg_putchar(' ');
- } else if (spp->sp_type == SPTYPE_START) {
- while (SYN_ITEMS(curwin->w_s)[idx].sp_type == SPTYPE_START)
+ } else if (spp->sp_type == SPTYPE_START) {
+ while (SYN_ITEMS(curwin->w_s)[idx].sp_type == SPTYPE_START) {
put_pattern("start", '=', &SYN_ITEMS(curwin->w_s)[idx++], attr);
- if (SYN_ITEMS(curwin->w_s)[idx].sp_type == SPTYPE_SKIP)
+ }
+ if (SYN_ITEMS(curwin->w_s)[idx].sp_type == SPTYPE_SKIP) {
put_pattern("skip", '=', &SYN_ITEMS(curwin->w_s)[idx++], attr);
+ }
while (idx < curwin->w_s->b_syn_patterns.ga_len
- && SYN_ITEMS(curwin->w_s)[idx].sp_type == SPTYPE_END)
+ && SYN_ITEMS(curwin->w_s)[idx].sp_type == SPTYPE_END) {
put_pattern("end", '=', &SYN_ITEMS(curwin->w_s)[idx++], attr);
+ }
--idx;
msg_putchar(' ');
}
@@ -3692,16 +3767,17 @@ syn_list_one(
msg_puts_attr("groupthere", attr);
}
msg_putchar(' ');
- if (spp->sp_sync_idx >= 0)
+ if (spp->sp_sync_idx >= 0) {
msg_outtrans(HL_TABLE()[SYN_ITEMS(curwin->w_s)
[spp->sp_sync_idx].sp_syn.id - 1].sg_name);
- else
+ } else {
MSG_PUTS("NONE");
+ }
msg_putchar(' ');
}
}
- /* list the link, if there is one */
+ // list the link, if there is one
if (HL_TABLE()[id - 1].sg_link && (did_header || link_only) && !got_int) {
(void)syn_list_header(did_header, 0, id, true);
msg_puts_attr("links to", attr);
@@ -3714,11 +3790,12 @@ static void syn_list_flags(struct name_list *nlist, int flags, int attr)
{
int i;
- for (i = 0; nlist[i].flag != 0; ++i)
+ for (i = 0; nlist[i].flag != 0; ++i) {
if (flags & nlist[i].flag) {
msg_puts_attr(nlist[i].name, attr);
msg_putchar(' ');
}
+ }
}
/*
@@ -3728,14 +3805,16 @@ static void syn_list_cluster(int id)
{
int endcol = 15;
- /* slight hack: roughly duplicate the guts of syn_list_header() */
+ // slight hack: roughly duplicate the guts of syn_list_header()
msg_putchar('\n');
msg_outtrans(SYN_CLSTR(curwin->w_s)[id].scl_name);
- if (msg_col >= endcol) /* output at least one space */
+ if (msg_col >= endcol) { // output at least one space
endcol = msg_col + 1;
- if (Columns <= endcol) /* avoid hang for tiny window */
+ }
+ if (Columns <= endcol) { // avoid hang for tiny window
endcol = Columns - 1;
+ }
msg_advance(endcol);
if (SYN_CLSTR(curwin->w_s)[id].scl_list != NULL) {
@@ -3746,9 +3825,7 @@ static void syn_list_cluster(int id)
}
}
-static void put_id_list(const char *const name,
- const int16_t *const list,
- const int attr)
+static void put_id_list(const char *const name, const int16_t *const list, const int attr)
{
msg_puts_attr(name, attr);
msg_putchar('=');
@@ -3759,38 +3836,40 @@ static void put_id_list(const char *const name,
} else {
msg_puts("ALL");
}
- } else if (*p >= SYNID_TOP && *p < SYNID_CONTAINED) {
+ } else if (*p >= SYNID_TOP && *p < SYNID_CONTAINED) {
msg_puts("TOP");
- } else if (*p >= SYNID_CONTAINED && *p < SYNID_CLUSTER) {
+ } else if (*p >= SYNID_CONTAINED && *p < SYNID_CLUSTER) {
msg_puts("CONTAINED");
- } else if (*p >= SYNID_CLUSTER) {
+ } else if (*p >= SYNID_CLUSTER) {
int scl_id = *p - SYNID_CLUSTER;
msg_putchar('@');
msg_outtrans(SYN_CLSTR(curwin->w_s)[scl_id].scl_name);
- } else
+ } else {
msg_outtrans(HL_TABLE()[*p - 1].sg_name);
- if (p[1])
+ }
+ if (p[1]) {
msg_putchar(',');
+ }
}
msg_putchar(' ');
}
-static void put_pattern(const char *const s, const int c,
- const synpat_T *const spp, const int attr)
+static void put_pattern(const char *const s, const int c, const synpat_T *const spp, const int attr)
{
static const char *const sepchars = "/+=-#@\"|'^&";
int i;
- /* May have to write "matchgroup=group" */
+ // May have to write "matchgroup=group"
if (last_matchgroup != spp->sp_syn_match_id) {
last_matchgroup = spp->sp_syn_match_id;
msg_puts_attr("matchgroup", attr);
msg_putchar('=');
- if (last_matchgroup == 0)
+ if (last_matchgroup == 0) {
msg_outtrans((char_u *)"NONE");
- else
+ } else {
msg_outtrans(HL_TABLE()[last_matchgroup - 1].sg_name);
+ }
msg_putchar(' ');
}
@@ -3798,12 +3877,13 @@ static void put_pattern(const char *const s, const int c,
msg_puts_attr(s, attr);
msg_putchar(c);
- /* output the pattern, in between a char that is not in the pattern */
- for (i = 0; vim_strchr(spp->sp_pattern, sepchars[i]) != NULL; )
+ // output the pattern, in between a char that is not in the pattern
+ for (i = 0; vim_strchr(spp->sp_pattern, sepchars[i]) != NULL; ) {
if (sepchars[++i] == NUL) {
- i = 0; /* no good char found, just use the first one */
+ i = 0; // no good char found, just use the first one
break;
}
+ }
msg_putchar(sepchars[i]);
msg_outtrans(spp->sp_pattern);
msg_putchar(sepchars[i]);
@@ -3821,12 +3901,14 @@ static void put_pattern(const char *const s, const int c,
msg_puts(spo_name_tab[i]);
const long n = spp->sp_offsets[i];
if (i != SPO_LC_OFF) {
- if (spp->sp_off_flags & mask)
+ if (spp->sp_off_flags & mask) {
msg_putchar('s');
- else
+ } else {
msg_putchar('e');
- if (n > 0)
+ }
+ if (n > 0) {
msg_putchar('+');
+ }
}
if (n || i == SPO_LC_OFF) {
msg_outnum(n);
@@ -3836,14 +3918,13 @@ static void put_pattern(const char *const s, const int c,
msg_putchar(' ');
}
-// List or clear the keywords for one syntax group.
-// Return true if the header has been printed.
-static bool syn_list_keywords(
- const int id,
- const hashtab_T *const ht,
- bool did_header, // header has already been printed
- const int attr
-)
+/// List or clear the keywords for one syntax group.
+///
+/// @param did_header header has already been printed
+///
+/// @return true if the header has been printed.
+static bool syn_list_keywords(const int id, const hashtab_T *const ht, bool did_header,
+ const int attr)
{
int prev_contained = 0;
const int16_t *prev_next_list = NULL;
@@ -3870,7 +3951,7 @@ static bool syn_list_keywords(
|| prev_skipempty != (kp->flags & HL_SKIPEMPTY)
|| prev_cont_in_list != kp->k_syn.cont_in_list
|| prev_next_list != kp->next_list) {
- force_newline = true;
+ force_newline = true;
} else {
outlen = (int)STRLEN(kp->keyword);
}
@@ -3924,10 +4005,10 @@ static bool syn_list_keywords(
static void syn_clear_keyword(int id, hashtab_T *ht)
{
- hashitem_T *hi;
- keyentry_T *kp;
- keyentry_T *kp_prev;
- keyentry_T *kp_next;
+ hashitem_T *hi;
+ keyentry_T *kp;
+ keyentry_T *kp_prev;
+ keyentry_T *kp_next;
int todo;
hash_lock(ht);
@@ -3942,12 +4023,14 @@ static void syn_clear_keyword(int id, hashtab_T *ht)
if (kp->k_syn.id == id) {
kp_next = kp->ke_next;
if (kp_prev == NULL) {
- if (kp_next == NULL)
+ if (kp_next == NULL) {
hash_remove(ht, hi);
- else
+ } else {
hi->hi_key = KE2HIKEY(kp_next);
- } else
+ }
+ } else {
kp_prev->ke_next = kp_next;
+ }
xfree(kp->next_list);
xfree(kp->k_syn.cont_in_list);
xfree(kp);
@@ -3966,10 +4049,10 @@ static void syn_clear_keyword(int id, hashtab_T *ht)
*/
static void clear_keywtab(hashtab_T *ht)
{
- hashitem_T *hi;
+ hashitem_T *hi;
int todo;
- keyentry_T *kp;
- keyentry_T *kp_next;
+ keyentry_T *kp;
+ keyentry_T *kp_next;
todo = (int)ht->ht_used;
for (hi = ht->ht_array; todo > 0; ++hi) {
@@ -3994,11 +4077,8 @@ static void clear_keywtab(hashtab_T *ht)
/// @param flags flags for this keyword
/// @param cont_in_list containedin for this keyword
/// @param next_list nextgroup for this keyword
-static void add_keyword(char_u *const name,
- const int id,
- const int flags,
- int16_t *const cont_in_list,
- int16_t *const next_list,
+static void add_keyword(char_u *const name, const int id, const int flags,
+ int16_t *const cont_in_list, int16_t *const next_list,
const int conceal_char)
{
char_u name_folded[MAXKEYWLEN + 1];
@@ -4040,18 +4120,16 @@ static void add_keyword(char_u *const name,
}
}
-/*
- * Get the start and end of the group name argument.
- * Return a pointer to the first argument.
- * Return NULL if the end of the command was found instead of further args.
- */
-static char_u *
-get_group_name (
- char_u *arg, /* start of the argument */
- char_u **name_end /* pointer to end of the name */
-)
+/// Get the start and end of the group name argument.
+///
+/// @param arg start of the argument
+/// @param name_end pointer to end of the name
+///
+/// @return a pointer to the first argument.
+/// Return NULL if the end of the command was found instead of further args.
+static char_u *get_group_name(char_u *arg, char_u **name_end)
{
- char_u *rest;
+ char_u *rest;
*name_end = skiptowhite(arg);
rest = skipwhite(*name_end);
@@ -4060,62 +4138,62 @@ get_group_name (
* Check if there are enough arguments. The first argument may be a
* pattern, where '|' is allowed, so only check for NUL.
*/
- if (ends_excmd(*arg) || *rest == NUL)
+ if (ends_excmd(*arg) || *rest == NUL) {
return NULL;
+ }
return rest;
}
-/*
- * Check for syntax command option arguments.
- * This can be called at any place in the list of arguments, and just picks
- * out the arguments that are known. Can be called several times in a row to
- * collect all options in between other arguments.
- * Return a pointer to the next argument (which isn't an option).
- * Return NULL for any error;
- */
-static char_u *
-get_syn_options(
- char_u *arg, // next argument to be checked
- syn_opt_arg_T *opt, // various things
- int *conceal_char,
- int skip // TRUE if skipping over command
-)
-{
- char_u *gname_start, *gname;
+/// Check for syntax command option arguments.
+/// This can be called at any place in the list of arguments, and just picks
+/// out the arguments that are known. Can be called several times in a row to
+/// collect all options in between other arguments.
+///
+/// @param arg next argument to be checked
+/// @param opt various things
+/// @param skip TRUE if skipping over command
+///
+/// @return a pointer to the next argument (which isn't an option).
+/// Return NULL for any error;
+static char_u *get_syn_options(char_u *arg, syn_opt_arg_T *opt, int *conceal_char, int skip)
+{
+ char_u *gname_start, *gname;
int syn_id;
int len = 0;
- char *p;
+ char *p;
int fidx;
static const struct flag {
- char *name;
+ char *name;
int argtype;
int flags;
- } flagtab[] = { {"cCoOnNtTaAiInNeEdD", 0, HL_CONTAINED},
- {"oOnNeElLiInNeE", 0, HL_ONELINE},
- {"kKeEeEpPeEnNdD", 0, HL_KEEPEND},
- {"eExXtTeEnNdD", 0, HL_EXTEND},
- {"eExXcClLuUdDeEnNlL", 0, HL_EXCLUDENL},
- {"tTrRaAnNsSpPaArReEnNtT", 0, HL_TRANSP},
- {"sSkKiIpPnNlL", 0, HL_SKIPNL},
- {"sSkKiIpPwWhHiItTeE", 0, HL_SKIPWHITE},
- {"sSkKiIpPeEmMpPtTyY", 0, HL_SKIPEMPTY},
- {"gGrRoOuUpPhHeErReE", 0, HL_SYNC_HERE},
- {"gGrRoOuUpPtThHeErReE", 0, HL_SYNC_THERE},
- {"dDiIsSpPlLaAyY", 0, HL_DISPLAY},
- {"fFoOlLdD", 0, HL_FOLD},
- {"cCoOnNcCeEaAlL", 0, HL_CONCEAL},
- {"cCoOnNcCeEaAlLeEnNdDsS", 0, HL_CONCEALENDS},
- {"cCcChHaArR", 11, 0},
- {"cCoOnNtTaAiInNsS", 1, 0},
- {"cCoOnNtTaAiInNeEdDiInN", 2, 0},
- {"nNeExXtTgGrRoOuUpP", 3, 0},};
+ } flagtab[] = { { "cCoOnNtTaAiInNeEdD", 0, HL_CONTAINED },
+ { "oOnNeElLiInNeE", 0, HL_ONELINE },
+ { "kKeEeEpPeEnNdD", 0, HL_KEEPEND },
+ { "eExXtTeEnNdD", 0, HL_EXTEND },
+ { "eExXcClLuUdDeEnNlL", 0, HL_EXCLUDENL },
+ { "tTrRaAnNsSpPaArReEnNtT", 0, HL_TRANSP },
+ { "sSkKiIpPnNlL", 0, HL_SKIPNL },
+ { "sSkKiIpPwWhHiItTeE", 0, HL_SKIPWHITE },
+ { "sSkKiIpPeEmMpPtTyY", 0, HL_SKIPEMPTY },
+ { "gGrRoOuUpPhHeErReE", 0, HL_SYNC_HERE },
+ { "gGrRoOuUpPtThHeErReE", 0, HL_SYNC_THERE },
+ { "dDiIsSpPlLaAyY", 0, HL_DISPLAY },
+ { "fFoOlLdD", 0, HL_FOLD },
+ { "cCoOnNcCeEaAlL", 0, HL_CONCEAL },
+ { "cCoOnNcCeEaAlLeEnNdDsS", 0, HL_CONCEALENDS },
+ { "cCcChHaArR", 11, 0 },
+ { "cCoOnNtTaAiInNsS", 1, 0 },
+ { "cCoOnNtTaAiInNeEdDiInN", 2, 0 },
+ { "nNeExXtTgGrRoOuUpP", 3, 0 }, };
static const char *const first_letters = "cCoOkKeEtTsSgGdDfFnN";
- if (arg == NULL) /* already detected error */
+ if (arg == NULL) { // already detected error
return NULL;
+ }
- if (curwin->w_s->b_syn_conceal)
+ if (curwin->w_s->b_syn_conceal) {
opt->flags |= HL_CONCEAL;
+ }
for (;; ) {
/*
@@ -4123,15 +4201,17 @@ get_syn_options(
* Need to skip quickly when no option name is found.
* Also avoid tolower(), it's slow.
*/
- if (strchr(first_letters, *arg) == NULL)
+ if (strchr(first_letters, *arg) == NULL) {
break;
+ }
for (fidx = ARRAY_SIZE(flagtab); --fidx >= 0; ) {
p = flagtab[fidx].name;
int i;
for (i = 0, len = 0; p[i] != NUL; i += 2, ++len) {
- if (arg[len] != p[i] && arg[len] != p[i + 1])
+ if (arg[len] != p[i] && arg[len] != p[i + 1]) {
break;
+ }
}
if (p[i] == NUL && (ascii_iswhite(arg[len])
|| (flagtab[fidx].argtype > 0
@@ -4140,14 +4220,16 @@ get_syn_options(
if (opt->keyword
&& (flagtab[fidx].flags == HL_DISPLAY
|| flagtab[fidx].flags == HL_FOLD
- || flagtab[fidx].flags == HL_EXTEND))
- /* treat "display", "fold" and "extend" as a keyword */
+ || flagtab[fidx].flags == HL_EXTEND)) {
+ // treat "display", "fold" and "extend" as a keyword
fidx = -1;
+ }
break;
}
}
- if (fidx < 0) /* no match found */
+ if (fidx < 0) { // no match found
break;
+ }
if (flagtab[fidx].argtype == 1) {
if (!opt->has_cont_list) {
@@ -4157,15 +4239,15 @@ get_syn_options(
if (get_id_list(&arg, 8, &opt->cont_list, skip) == FAIL) {
return NULL;
}
- } else if (flagtab[fidx].argtype == 2) {
+ } else if (flagtab[fidx].argtype == 2) {
if (get_id_list(&arg, 11, &opt->cont_in_list, skip) == FAIL) {
return NULL;
}
- } else if (flagtab[fidx].argtype == 3) {
+ } else if (flagtab[fidx].argtype == 3) {
if (get_id_list(&arg, 9, &opt->next_list, skip) == FAIL) {
return NULL;
}
- } else if (flagtab[fidx].argtype == 11 && arg[5] == '=') {
+ } else if (flagtab[fidx].argtype == 11 && arg[5] == '=') {
// cchar=?
*conceal_char = utf_ptr2char(arg + 6);
arg += mb_ptr2len(arg + 6) - 1;
@@ -4186,20 +4268,22 @@ get_syn_options(
}
gname_start = arg;
arg = skiptowhite(arg);
- if (gname_start == arg)
+ if (gname_start == arg) {
return NULL;
+ }
gname = vim_strnsave(gname_start, arg - gname_start);
if (STRCMP(gname, "NONE") == 0) {
*opt->sync_idx = NONE_IDX;
} else {
syn_id = syn_name2id(gname);
int i;
- for (i = curwin->w_s->b_syn_patterns.ga_len; --i >= 0; )
+ for (i = curwin->w_s->b_syn_patterns.ga_len; --i >= 0; ) {
if (SYN_ITEMS(curwin->w_s)[i].sp_syn.id == syn_id
&& SYN_ITEMS(curwin->w_s)[i].sp_type == SPTYPE_START) {
*opt->sync_idx = i;
break;
}
+ }
if (i < 0) {
EMSG2(_("E394: Didn't find region item for %s"), gname);
xfree(gname);
@@ -4210,9 +4294,10 @@ get_syn_options(
xfree(gname);
arg = skipwhite(arg);
} else if (flagtab[fidx].flags == HL_FOLD
- && foldmethodIsSyntax(curwin))
- /* Need to update folds later. */
+ && foldmethodIsSyntax(curwin)) {
+ // Need to update folds later.
foldUpdateAll(curwin);
+ }
}
}
@@ -4226,8 +4311,9 @@ get_syn_options(
*/
static void syn_incl_toplevel(int id, int *flagsp)
{
- if ((*flagsp & HL_CONTAINED) || curwin->w_s->b_syn_topgrp == 0)
+ if ((*flagsp & HL_CONTAINED) || curwin->w_s->b_syn_topgrp == 0) {
return;
+ }
*flagsp |= HL_CONTAINED;
if (curwin->w_s->b_syn_topgrp >= SYNID_CLUSTER) {
// We have to alloc this, because syn_combine_list() will free it.
@@ -4237,7 +4323,7 @@ static void syn_incl_toplevel(int id, int *flagsp)
grp_list[0] = id;
grp_list[1] = 0;
syn_combine_list(&SYN_CLSTR(curwin->w_s)[tlg_id].scl_list, &grp_list,
- CLUSTER_ADD);
+ CLUSTER_ADD);
}
}
@@ -4246,18 +4332,19 @@ static void syn_incl_toplevel(int id, int *flagsp)
*/
static void syn_cmd_include(exarg_T *eap, int syncing)
{
- char_u *arg = eap->arg;
+ char_u *arg = eap->arg;
int sgl_id = 1;
- char_u *group_name_end;
- char_u *rest;
- char_u *errormsg = NULL;
+ char_u *group_name_end;
+ char_u *rest;
+ char_u *errormsg = NULL;
int prev_toplvl_grp;
int prev_syn_inc_tag;
- int source = FALSE;
+ bool source = false;
eap->nextcmd = find_nextcmd(arg);
- if (eap->skip)
+ if (eap->skip) {
return;
+ }
if (arg[0] == '@') {
++arg;
@@ -4267,9 +4354,10 @@ static void syn_cmd_include(exarg_T *eap, int syncing)
return;
}
sgl_id = syn_check_cluster(arg, (int)(group_name_end - arg));
- if (sgl_id == 0)
+ if (sgl_id == 0) {
return;
- /* separate_nextcmd() and expand_filename() depend on this */
+ }
+ // separate_nextcmd() and expand_filename() depend on this
eap->arg = rest;
}
@@ -4285,8 +4373,9 @@ static void syn_cmd_include(exarg_T *eap, int syncing)
// ":runtime!" is used.
source = true;
if (expand_filename(eap, syn_cmdlinep, &errormsg) == FAIL) {
- if (errormsg != NULL)
+ if (errormsg != NULL) {
EMSG(errormsg);
+ }
return;
}
}
@@ -4305,7 +4394,7 @@ static void syn_cmd_include(exarg_T *eap, int syncing)
curwin->w_s->b_syn_topgrp = sgl_id;
if (source
? do_source(eap->arg, false, DOSO_NONE) == FAIL
- : source_in_path(p_rtp, eap->arg, DIP_ALL) == FAIL) {
+ : source_runtime(eap->arg, DIP_ALL) == FAIL) {
EMSG2(_(e_notopen), eap->arg);
}
curwin->w_s->b_syn_topgrp = prev_toplvl_grp;
@@ -4317,13 +4406,13 @@ static void syn_cmd_include(exarg_T *eap, int syncing)
*/
static void syn_cmd_keyword(exarg_T *eap, int syncing)
{
- char_u *arg = eap->arg;
- char_u *group_name_end;
+ char_u *arg = eap->arg;
+ char_u *group_name_end;
int syn_id;
- char_u *rest;
- char_u *keyword_copy = NULL;
- char_u *p;
- char_u *kw;
+ char_u *rest;
+ char_u *keyword_copy = NULL;
+ char_u *p;
+ char_u *kw;
syn_opt_arg_T syn_opt_arg;
int cnt;
int conceal_char = NUL;
@@ -4413,39 +4502,36 @@ error:
}
}
- if (rest != NULL)
+ if (rest != NULL) {
eap->nextcmd = check_nextcmd(rest);
- else
+ } else {
EMSG2(_(e_invarg2), arg);
+ }
redraw_curbuf_later(SOME_VALID);
- syn_stack_free_all(curwin->w_s); /* Need to recompute all syntax. */
+ syn_stack_free_all(curwin->w_s); // Need to recompute all syntax.
}
-/*
- * Handle ":syntax match {name} [{options}] {pattern} [{options}]".
- *
- * Also ":syntax sync match {name} [[grouphere | groupthere] {group-name}] .."
- */
-static void
-syn_cmd_match(
- exarg_T *eap,
- int syncing /* TRUE for ":syntax sync match .. " */
-)
-{
- char_u *arg = eap->arg;
- char_u *group_name_end;
- char_u *rest;
- synpat_T item; /* the item found in the line */
+/// Handle ":syntax match {name} [{options}] {pattern} [{options}]".
+///
+/// Also ":syntax sync match {name} [[grouphere | groupthere] {group-name}] .."
+///
+/// @param syncing TRUE for ":syntax sync match .. "
+static void syn_cmd_match(exarg_T *eap, int syncing)
+{
+ char_u *arg = eap->arg;
+ char_u *group_name_end;
+ char_u *rest;
+ synpat_T item; // the item found in the line
int syn_id;
syn_opt_arg_T syn_opt_arg;
int sync_idx = 0;
int conceal_char = NUL;
- /* Isolate the group name, check for validity */
+ // Isolate the group name, check for validity
rest = get_group_name(arg, &group_name_end);
- /* Get options before the pattern */
+ // Get options before the pattern
syn_opt_arg.flags = 0;
syn_opt_arg.keyword = false;
syn_opt_arg.sync_idx = syncing ? &sync_idx : NULL;
@@ -4455,7 +4541,7 @@ syn_cmd_match(
syn_opt_arg.next_list = NULL;
rest = get_syn_options(rest, &syn_opt_arg, &conceal_char, eap->skip);
- /* get the pattern. */
+ // get the pattern.
init_syn_patterns();
memset(&item, 0, sizeof(item));
rest = get_syn_pattern(rest, &item);
@@ -4466,14 +4552,14 @@ syn_cmd_match(
// Get options after the pattern
rest = get_syn_options(rest, &syn_opt_arg, &conceal_char, eap->skip);
- if (rest != NULL) { /* all arguments are valid */
+ if (rest != NULL) { // all arguments are valid
/*
* Check for trailing command and illegal trailing arguments.
*/
eap->nextcmd = check_nextcmd(rest);
- if (!ends_excmd(*rest) || eap->skip)
+ if (!ends_excmd(*rest) || eap->skip) {
rest = NULL;
- else {
+ } else {
if ((syn_id = syn_check_group(arg, (int)(group_name_end - arg))) != 0) {
syn_incl_toplevel(syn_id, &syn_opt_arg.flags);
/*
@@ -4491,19 +4577,22 @@ syn_cmd_match(
spp->sp_cont_list = syn_opt_arg.cont_list;
spp->sp_syn.cont_in_list = syn_opt_arg.cont_in_list;
spp->sp_cchar = conceal_char;
- if (syn_opt_arg.cont_in_list != NULL)
+ if (syn_opt_arg.cont_in_list != NULL) {
curwin->w_s->b_syn_containedin = TRUE;
+ }
spp->sp_next_list = syn_opt_arg.next_list;
- /* remember that we found a match for syncing on */
- if (syn_opt_arg.flags & (HL_SYNC_HERE|HL_SYNC_THERE))
+ // remember that we found a match for syncing on
+ if (syn_opt_arg.flags & (HL_SYNC_HERE|HL_SYNC_THERE)) {
curwin->w_s->b_syn_sync_flags |= SF_MATCH;
- if (syn_opt_arg.flags & HL_FOLD)
+ }
+ if (syn_opt_arg.flags & HL_FOLD) {
++curwin->w_s->b_syn_folditems;
+ }
redraw_curbuf_later(SOME_VALID);
- syn_stack_free_all(curwin->w_s); /* Need to recompute all syntax. */
- return; /* don't free the progs and patterns now */
+ syn_stack_free_all(curwin->w_s); // Need to recompute all syntax.
+ return; // don't free the progs and patterns now
}
}
}
@@ -4517,49 +4606,46 @@ syn_cmd_match(
xfree(syn_opt_arg.cont_in_list);
xfree(syn_opt_arg.next_list);
- if (rest == NULL)
+ if (rest == NULL) {
EMSG2(_(e_invarg2), arg);
+ }
}
-/*
- * Handle ":syntax region {group-name} [matchgroup={group-name}]
- * start {start} .. [skip {skip}] end {end} .. [{options}]".
- */
-static void
-syn_cmd_region(
- exarg_T *eap,
- int syncing /* TRUE for ":syntax sync region .." */
-)
-{
- char_u *arg = eap->arg;
- char_u *group_name_end;
- char_u *rest; /* next arg, NULL on error */
- char_u *key_end;
- char_u *key = NULL;
- char_u *p;
+/// Handle ":syntax region {group-name} [matchgroup={group-name}]
+/// start {start} .. [skip {skip}] end {end} .. [{options}]".
+///
+/// @param syncing TRUE for ":syntax sync region .."
+static void syn_cmd_region(exarg_T *eap, int syncing)
+{
+ char_u *arg = eap->arg;
+ char_u *group_name_end;
+ char_u *rest; // next arg, NULL on error
+ char_u *key_end;
+ char_u *key = NULL;
+ char_u *p;
int item;
#define ITEM_START 0
#define ITEM_SKIP 1
#define ITEM_END 2
#define ITEM_MATCHGROUP 3
struct pat_ptr {
- synpat_T *pp_synp; /* pointer to syn_pattern */
- int pp_matchgroup_id; /* matchgroup ID */
- struct pat_ptr *pp_next; /* pointer to next pat_ptr */
+ synpat_T *pp_synp; // pointer to syn_pattern
+ int pp_matchgroup_id; // matchgroup ID
+ struct pat_ptr *pp_next; // pointer to next pat_ptr
} *(pat_ptrs[3]);
- /* patterns found in the line */
- struct pat_ptr *ppp;
- struct pat_ptr *ppp_next;
- int pat_count = 0; /* nr of syn_patterns found */
+ // patterns found in the line
+ struct pat_ptr *ppp;
+ struct pat_ptr *ppp_next;
+ int pat_count = 0; // nr of syn_patterns found
int syn_id;
int matchgroup_id = 0;
- int not_enough = FALSE; /* not enough arguments */
- int illegal = FALSE; /* illegal arguments */
- int success = FALSE;
+ bool not_enough = false; // not enough arguments
+ bool illegal = false; // illegal arguments
+ bool success = false;
syn_opt_arg_T syn_opt_arg;
int conceal_char = NUL;
- /* Isolate the group name, check for validity */
+ // Isolate the group name, check for validity
rest = get_group_name(arg, &group_name_end);
pat_ptrs[0] = NULL;
@@ -4584,10 +4670,11 @@ syn_cmd_region(
break;
}
- /* must be a pattern or matchgroup then */
+ // must be a pattern or matchgroup then
key_end = rest;
- while (*key_end && !ascii_iswhite(*key_end) && *key_end != '=')
+ while (*key_end && !ascii_iswhite(*key_end) && *key_end != '=') {
++key_end;
+ }
xfree(key);
key = vim_strnsave_up(rest, key_end - rest);
if (STRCMP(key, "MATCHGROUP") == 0) {
@@ -4613,18 +4700,18 @@ syn_cmd_region(
}
rest = skipwhite(rest + 1);
if (*rest == NUL) {
- not_enough = TRUE;
+ not_enough = true;
break;
}
if (item == ITEM_MATCHGROUP) {
p = skiptowhite(rest);
- if ((p - rest == 4 && STRNCMP(rest, "NONE", 4) == 0) || eap->skip)
+ if ((p - rest == 4 && STRNCMP(rest, "NONE", 4) == 0) || eap->skip) {
matchgroup_id = 0;
- else {
+ } else {
matchgroup_id = syn_check_group(rest, (int)(p - rest));
if (matchgroup_id == 0) {
- illegal = TRUE;
+ illegal = true;
break;
}
}
@@ -4660,8 +4747,9 @@ syn_cmd_region(
}
}
xfree(key);
- if (illegal || not_enough)
+ if (illegal || not_enough) {
rest = NULL;
+ }
// Must have a "start" and "end" pattern.
if (rest != NULL && (pat_ptrs[ITEM_START] == NULL
@@ -4676,9 +4764,9 @@ syn_cmd_region(
* If OK, add the item.
*/
eap->nextcmd = check_nextcmd(rest);
- if (!ends_excmd(*rest) || eap->skip)
+ if (!ends_excmd(*rest) || eap->skip) {
rest = NULL;
- else {
+ } else {
ga_grow(&(curwin->w_s->b_syn_patterns), pat_count);
if ((syn_id = syn_check_group(arg, (int)(group_name_end - arg))) != 0) {
syn_incl_toplevel(syn_id, &syn_opt_arg.flags);
@@ -4705,21 +4793,23 @@ syn_cmd_region(
syn_opt_arg.cont_list;
SYN_ITEMS(curwin->w_s)[idx].sp_syn.cont_in_list =
syn_opt_arg.cont_in_list;
- if (syn_opt_arg.cont_in_list != NULL)
+ if (syn_opt_arg.cont_in_list != NULL) {
curwin->w_s->b_syn_containedin = TRUE;
+ }
SYN_ITEMS(curwin->w_s)[idx].sp_next_list =
syn_opt_arg.next_list;
}
++curwin->w_s->b_syn_patterns.ga_len;
++idx;
- if (syn_opt_arg.flags & HL_FOLD)
+ if (syn_opt_arg.flags & HL_FOLD) {
++curwin->w_s->b_syn_folditems;
+ }
}
}
redraw_curbuf_later(SOME_VALID);
- syn_stack_free_all(curwin->w_s); /* Need to recompute all syntax. */
- success = TRUE; /* don't free the progs and patterns now */
+ syn_stack_free_all(curwin->w_s); // Need to recompute all syntax.
+ success = true; // don't free the progs and patterns now
}
}
}
@@ -4727,7 +4817,7 @@ syn_cmd_region(
/*
* Free the allocated memory.
*/
- for (item = ITEM_START; item <= ITEM_END; ++item)
+ for (item = ITEM_START; item <= ITEM_END; ++item) {
for (ppp = pat_ptrs[item]; ppp != NULL; ppp = ppp_next) {
if (!success && ppp->pp_synp != NULL) {
vim_regfree(ppp->pp_synp->sp_prog);
@@ -4737,15 +4827,17 @@ syn_cmd_region(
ppp_next = ppp->pp_next;
xfree(ppp);
}
+ }
if (!success) {
xfree(syn_opt_arg.cont_list);
xfree(syn_opt_arg.cont_in_list);
xfree(syn_opt_arg.next_list);
- if (not_enough)
+ if (not_enough) {
EMSG2(_("E399: Not enough arguments: syntax region %s"), arg);
- else if (illegal || rest == NULL)
+ } else if (illegal || rest == NULL) {
EMSG2(_(e_invarg2), arg);
+ }
}
}
@@ -4760,8 +4852,7 @@ static int syn_compare_stub(const void *const v1, const void *const v2)
// Combines lists of syntax clusters.
// *clstr1 and *clstr2 must both be allocated memory; they will be consumed.
-static void syn_combine_list(int16_t **const clstr1, int16_t **const clstr2,
- const int list_op)
+static void syn_combine_list(int16_t **const clstr1, int16_t **const clstr2, const int list_op)
{
size_t count1 = 0;
size_t count2 = 0;
@@ -4772,15 +4863,18 @@ static void syn_combine_list(int16_t **const clstr1, int16_t **const clstr2,
/*
* Handle degenerate cases.
*/
- if (*clstr2 == NULL)
+ if (*clstr2 == NULL) {
return;
+ }
if (*clstr1 == NULL || list_op == CLUSTER_REPLACE) {
- if (list_op == CLUSTER_REPLACE)
+ if (list_op == CLUSTER_REPLACE) {
xfree(*clstr1);
- if (list_op == CLUSTER_REPLACE || list_op == CLUSTER_ADD)
+ }
+ if (list_op == CLUSTER_REPLACE || list_op == CLUSTER_ADD) {
*clstr1 = *clstr2;
- else
+ } else {
xfree(*clstr2);
+ }
return;
}
@@ -4812,8 +4906,9 @@ static void syn_combine_list(int16_t **const clstr1, int16_t **const clstr2,
* We always want to add from the first list.
*/
if (*g1 < *g2) {
- if (round == 2)
+ if (round == 2) {
clstr[count] = *g1;
+ }
count++;
g1++;
continue;
@@ -4823,12 +4918,14 @@ static void syn_combine_list(int16_t **const clstr1, int16_t **const clstr2,
* lists.
*/
if (list_op == CLUSTER_ADD) {
- if (round == 2)
+ if (round == 2) {
clstr[count] = *g2;
+ }
count++;
}
- if (*g1 == *g2)
+ if (*g1 == *g2) {
g1++;
+ }
g2++;
}
@@ -4837,13 +4934,18 @@ static void syn_combine_list(int16_t **const clstr1, int16_t **const clstr2,
* first. As before, we only want to add from the second list if
* we're adding the lists.
*/
- for (; *g1; g1++, count++)
- if (round == 2)
+ for (; *g1; g1++, count++) {
+ if (round == 2) {
clstr[count] = *g1;
- if (list_op == CLUSTER_ADD)
- for (; *g2; g2++, count++)
- if (round == 2)
+ }
+ }
+ if (list_op == CLUSTER_ADD) {
+ for (; *g2; g2++, count++) {
+ if (round == 2) {
clstr[count] = *g2;
+ }
+ }
+ }
if (round == 1) {
/*
@@ -4903,15 +5005,16 @@ static int syn_scl_namen2id(char_u *linep, int len)
static int syn_check_cluster(char_u *pp, int len)
{
int id;
- char_u *name;
+ char_u *name;
name = vim_strnsave(pp, len);
id = syn_scl_name2id(name);
- if (id == 0) /* doesn't exist yet */
+ if (id == 0) { // doesn't exist yet
id = syn_add_cluster(name);
- else
+ } else {
xfree(name);
+ }
return id;
}
@@ -4942,30 +5045,33 @@ static int syn_add_cluster(char_u *name)
scp->scl_name_u = vim_strsave_up(name);
scp->scl_list = NULL;
- if (STRICMP(name, "Spell") == 0)
+ if (STRICMP(name, "Spell") == 0) {
curwin->w_s->b_spell_cluster_id = len + SYNID_CLUSTER;
- if (STRICMP(name, "NoSpell") == 0)
+ }
+ if (STRICMP(name, "NoSpell") == 0) {
curwin->w_s->b_nospell_cluster_id = len + SYNID_CLUSTER;
+ }
return len + SYNID_CLUSTER;
}
/*
* Handle ":syntax cluster {cluster-name} [contains={groupname},..]
- * [add={groupname},..] [remove={groupname},..]".
+ * [add={groupname},..] [remove={groupname},..]".
*/
static void syn_cmd_cluster(exarg_T *eap, int syncing)
{
- char_u *arg = eap->arg;
- char_u *group_name_end;
- char_u *rest;
+ char_u *arg = eap->arg;
+ char_u *group_name_end;
+ char_u *rest;
bool got_clstr = false;
int opt_len;
int list_op;
eap->nextcmd = find_nextcmd(arg);
- if (eap->skip)
+ if (eap->skip) {
return;
+ }
rest = get_group_name(arg, &group_name_end);
@@ -4989,8 +5095,9 @@ static void syn_cmd_cluster(exarg_T *eap, int syncing)
&& (ascii_iswhite(rest[8]) || rest[8] == '=')) {
opt_len = 8;
list_op = CLUSTER_REPLACE;
- } else
+ } else {
break;
+ }
int16_t *clstr_list = NULL;
if (get_id_list(&rest, opt_len, &clstr_list, eap->skip) == FAIL) {
@@ -5008,14 +5115,16 @@ static void syn_cmd_cluster(exarg_T *eap, int syncing)
if (got_clstr) {
redraw_curbuf_later(SOME_VALID);
- syn_stack_free_all(curwin->w_s); /* Need to recompute all. */
+ syn_stack_free_all(curwin->w_s); // Need to recompute all.
}
}
- if (!got_clstr)
+ if (!got_clstr) {
EMSG(_("E400: No cluster specified"));
- if (rest == NULL || !ends_excmd(*rest))
+ }
+ if (rest == NULL || !ends_excmd(*rest)) {
EMSG2(_(e_invarg2), arg);
+ }
}
/*
@@ -5034,10 +5143,10 @@ static void init_syn_patterns(void)
*/
static char_u *get_syn_pattern(char_u *arg, synpat_T *ci)
{
- char_u *end;
- int *p;
+ char_u *end;
+ int *p;
int idx;
- char_u *cpo_save;
+ char_u *cpo_save;
// need at least three chars
if (arg == NULL || arg[0] == NUL || arg[1] == NUL || arg[2] == NUL) {
@@ -5045,21 +5154,22 @@ static char_u *get_syn_pattern(char_u *arg, synpat_T *ci)
}
end = skip_regexp(arg + 1, *arg, TRUE, NULL);
- if (*end != *arg) { /* end delimiter not found */
+ if (*end != *arg) { // end delimiter not found
EMSG2(_("E401: Pattern delimiter not found: %s"), arg);
return NULL;
}
// store the pattern and compiled regexp program
ci->sp_pattern = vim_strnsave(arg + 1, end - arg - 1);
- /* Make 'cpoptions' empty, to avoid the 'l' flag */
+ // Make 'cpoptions' empty, to avoid the 'l' flag
cpo_save = p_cpo;
p_cpo = (char_u *)"";
ci->sp_prog = vim_regcomp(ci->sp_pattern, RE_MAGIC);
p_cpo = cpo_save;
- if (ci->sp_prog == NULL)
+ if (ci->sp_prog == NULL) {
return NULL;
+ }
ci->sp_ic = curwin->w_s->b_syn_ic;
syn_clear_time(&ci->sp_time);
@@ -5068,41 +5178,49 @@ static char_u *get_syn_pattern(char_u *arg, synpat_T *ci)
*/
++end;
do {
- for (idx = SPO_COUNT; --idx >= 0; )
- if (STRNCMP(end, spo_name_tab[idx], 3) == 0)
+ for (idx = SPO_COUNT; --idx >= 0; ) {
+ if (STRNCMP(end, spo_name_tab[idx], 3) == 0) {
break;
+ }
+ }
if (idx >= 0) {
p = &(ci->sp_offsets[idx]);
- if (idx != SPO_LC_OFF)
+ if (idx != SPO_LC_OFF) {
switch (end[3]) {
- case 's': break;
- case 'b': break;
- case 'e': idx += SPO_COUNT; break;
- default: idx = -1; break;
+ case 's':
+ break;
+ case 'b':
+ break;
+ case 'e':
+ idx += SPO_COUNT; break;
+ default:
+ idx = -1; break;
}
+ }
if (idx >= 0) {
ci->sp_off_flags |= (1 << idx);
- if (idx == SPO_LC_OFF) { /* lc=99 */
+ if (idx == SPO_LC_OFF) { // lc=99
end += 3;
*p = getdigits_int(&end, true, 0);
- /* "lc=" offset automatically sets "ms=" offset */
+ // "lc=" offset automatically sets "ms=" offset
if (!(ci->sp_off_flags & (1 << SPO_MS_OFF))) {
ci->sp_off_flags |= (1 << SPO_MS_OFF);
ci->sp_offsets[SPO_MS_OFF] = *p;
}
- } else { /* yy=x+99 */
+ } else { // yy=x+99
end += 4;
if (*end == '+') {
end++;
*p = getdigits_int(&end, true, 0); // positive offset
- } else if (*end == '-') {
+ } else if (*end == '-') {
end++;
*p = -getdigits_int(&end, true, 0); // negative offset
}
}
- if (*end != ',')
+ if (*end != ',') {
break;
+ }
++end;
}
}
@@ -5120,14 +5238,14 @@ static char_u *get_syn_pattern(char_u *arg, synpat_T *ci)
*/
static void syn_cmd_sync(exarg_T *eap, int syncing)
{
- char_u *arg_start = eap->arg;
- char_u *arg_end;
- char_u *key = NULL;
- char_u *next_arg;
+ char_u *arg_start = eap->arg;
+ char_u *arg_end;
+ char_u *key = NULL;
+ char_u *next_arg;
int illegal = FALSE;
int finished = FALSE;
long n;
- char_u *cpo_save;
+ char_u *cpo_save;
if (ends_excmd(*arg_start)) {
syn_cmd_list(eap, TRUE);
@@ -5140,45 +5258,50 @@ static void syn_cmd_sync(exarg_T *eap, int syncing)
xfree(key);
key = vim_strnsave_up(arg_start, arg_end - arg_start);
if (STRCMP(key, "CCOMMENT") == 0) {
- if (!eap->skip)
+ if (!eap->skip) {
curwin->w_s->b_syn_sync_flags |= SF_CCOMMENT;
+ }
if (!ends_excmd(*next_arg)) {
arg_end = skiptowhite(next_arg);
- if (!eap->skip)
+ if (!eap->skip) {
curwin->w_s->b_syn_sync_id = syn_check_group(next_arg,
- (int)(arg_end - next_arg));
+ (int)(arg_end - next_arg));
+ }
next_arg = skipwhite(arg_end);
- } else if (!eap->skip)
+ } else if (!eap->skip) {
curwin->w_s->b_syn_sync_id = syn_name2id((char_u *)"Comment");
- } else if ( STRNCMP(key, "LINES", 5) == 0
- || STRNCMP(key, "MINLINES", 8) == 0
- || STRNCMP(key, "MAXLINES", 8) == 0
- || STRNCMP(key, "LINEBREAKS", 10) == 0) {
- if (key[4] == 'S')
+ }
+ } else if (STRNCMP(key, "LINES", 5) == 0
+ || STRNCMP(key, "MINLINES", 8) == 0
+ || STRNCMP(key, "MAXLINES", 8) == 0
+ || STRNCMP(key, "LINEBREAKS", 10) == 0) {
+ if (key[4] == 'S') {
arg_end = key + 6;
- else if (key[0] == 'L')
+ } else if (key[0] == 'L') {
arg_end = key + 11;
- else
+ } else {
arg_end = key + 9;
+ }
if (arg_end[-1] != '=' || !ascii_isdigit(*arg_end)) {
illegal = TRUE;
break;
}
n = getdigits_long(&arg_end, false, 0);
if (!eap->skip) {
- if (key[4] == 'B')
+ if (key[4] == 'B') {
curwin->w_s->b_syn_sync_linebreaks = n;
- else if (key[1] == 'A')
+ } else if (key[1] == 'A') {
curwin->w_s->b_syn_sync_maxlines = n;
- else
+ } else {
curwin->w_s->b_syn_sync_minlines = n;
+ }
}
- } else if (STRCMP(key, "FROMSTART") == 0) {
+ } else if (STRCMP(key, "FROMSTART") == 0) {
if (!eap->skip) {
curwin->w_s->b_syn_sync_minlines = MAXLNUM;
curwin->w_s->b_syn_sync_maxlines = 0;
}
- } else if (STRCMP(key, "LINECONT") == 0) {
+ } else if (STRCMP(key, "LINECONT") == 0) {
if (*next_arg == NUL) { // missing pattern
illegal = true;
break;
@@ -5189,18 +5312,18 @@ static void syn_cmd_sync(exarg_T *eap, int syncing)
break;
}
arg_end = skip_regexp(next_arg + 1, *next_arg, TRUE, NULL);
- if (*arg_end != *next_arg) { /* end delimiter not found */
+ if (*arg_end != *next_arg) { // end delimiter not found
illegal = TRUE;
break;
}
if (!eap->skip) {
- /* store the pattern and compiled regexp program */
+ // store the pattern and compiled regexp program
curwin->w_s->b_syn_linecont_pat =
vim_strnsave(next_arg + 1, arg_end - next_arg - 1);
curwin->w_s->b_syn_linecont_ic = curwin->w_s->b_syn_ic;
- /* Make 'cpoptions' empty, to avoid the 'l' flag */
+ // Make 'cpoptions' empty, to avoid the 'l' flag
cpo_save = p_cpo;
p_cpo = (char_u *)"";
curwin->w_s->b_syn_linecont_prog =
@@ -5217,47 +5340,43 @@ static void syn_cmd_sync(exarg_T *eap, int syncing)
next_arg = skipwhite(arg_end + 1);
} else {
eap->arg = next_arg;
- if (STRCMP(key, "MATCH") == 0)
+ if (STRCMP(key, "MATCH") == 0) {
syn_cmd_match(eap, TRUE);
- else if (STRCMP(key, "REGION") == 0)
+ } else if (STRCMP(key, "REGION") == 0) {
syn_cmd_region(eap, TRUE);
- else if (STRCMP(key, "CLEAR") == 0)
+ } else if (STRCMP(key, "CLEAR") == 0) {
syn_cmd_clear(eap, TRUE);
- else
+ } else {
illegal = TRUE;
+ }
finished = TRUE;
break;
}
arg_start = next_arg;
}
xfree(key);
- if (illegal)
+ if (illegal) {
EMSG2(_("E404: Illegal arguments: %s"), arg_start);
- else if (!finished) {
+ } else if (!finished) {
eap->nextcmd = check_nextcmd(arg_start);
redraw_curbuf_later(SOME_VALID);
- syn_stack_free_all(curwin->w_s); /* Need to recompute all syntax. */
+ syn_stack_free_all(curwin->w_s); // Need to recompute all syntax.
}
}
-/*
- * Convert a line of highlight group names into a list of group ID numbers.
- * "arg" should point to the "contains" or "nextgroup" keyword.
- * "arg" is advanced to after the last group name.
- * Careful: the argument is modified (NULs added).
- * returns FAIL for some error, OK for success.
- */
-static int
-get_id_list(
- char_u **const arg,
- const int keylen, // length of keyword
- int16_t **const list, // where to store the resulting list, if not
- // NULL, the list is silently skipped!
- const bool skip
-)
-{
- char_u *p = NULL;
- char_u *end;
+/// Convert a line of highlight group names into a list of group ID numbers.
+/// "arg" should point to the "contains" or "nextgroup" keyword.
+/// "arg" is advanced to after the last group name.
+/// Careful: the argument is modified (NULs added).
+///
+/// @param keylen length of keyword
+/// @param list where to store the resulting list, if not NULL, the list is silently skipped!
+///
+/// @return FAIL for some error, OK for success.
+static int get_id_list(char_u **const arg, const int keylen, int16_t **const list, const bool skip)
+{
+ char_u *p = NULL;
+ char_u *end;
int total_count = 0;
int16_t *retval = NULL;
regmatch_T regmatch;
@@ -5289,10 +5408,10 @@ get_id_list(
}
char_u *const name = xmalloc((int)(end - p + 3)); // leave room for "^$"
STRLCPY(name + 1, p, end - p + 1);
- if ( STRCMP(name + 1, "ALLBUT") == 0
- || STRCMP(name + 1, "ALL") == 0
- || STRCMP(name + 1, "TOP") == 0
- || STRCMP(name + 1, "CONTAINED") == 0) {
+ if (STRCMP(name + 1, "ALLBUT") == 0
+ || STRCMP(name + 1, "ALL") == 0
+ || STRCMP(name + 1, "TOP") == 0
+ || STRCMP(name + 1, "CONTAINED") == 0) {
if (TOUPPER_ASC(**arg) != 'C') {
EMSG2(_("E407: %s not allowed here"), name + 1);
failed = true;
@@ -5317,7 +5436,7 @@ get_id_list(
} else {
id = SYNID_CONTAINED + current_syn_inc_tag;
}
- } else if (name[1] == '@') {
+ } else if (name[1] == '@') {
if (skip) {
id = -1;
} else {
@@ -5382,12 +5501,14 @@ get_id_list(
++count;
}
p = skipwhite(end);
- if (*p != ',')
+ if (*p != ',') {
break;
- p = skipwhite(p + 1); /* skip comma in between arguments */
+ }
+ p = skipwhite(p + 1); // skip comma in between arguments
} while (!ends_excmd(*p));
- if (failed)
+ if (failed) {
break;
+ }
if (round == 1) {
retval = xmalloc((count + 1) * sizeof(*retval));
retval[count] = 0; // zero means end of the list
@@ -5401,11 +5522,11 @@ get_id_list(
return FAIL;
}
- if (*list == NULL)
+ if (*list == NULL) {
*list = retval;
- else
- xfree(retval); /* list already found, don't overwrite it */
-
+ } else {
+ xfree(retval); // list already found, don't overwrite it
+ }
return OK;
}
@@ -5428,20 +5549,17 @@ static int16_t *copy_id_list(const int16_t *const list)
return retval;
}
-/*
- * Check if syntax group "ssp" is in the ID list "list" of "cur_si".
- * "cur_si" can be NULL if not checking the "containedin" list.
- * Used to check if a syntax item is in the "contains" or "nextgroup" list of
- * the current item.
- * This function is called very often, keep it fast!!
- */
-static int
-in_id_list(
- stateitem_T *cur_si, // current item or NULL
- int16_t *list, // id list
- struct sp_syn *ssp, // group id and ":syn include" tag of group
- int contained // group id is contained
-)
+/// Check if syntax group "ssp" is in the ID list "list" of "cur_si".
+/// "cur_si" can be NULL if not checking the "containedin" list.
+/// Used to check if a syntax item is in the "contains" or "nextgroup" list of
+/// the current item.
+/// This function is called very often, keep it fast!!
+///
+/// @param cur_si current item or NULL
+/// @param list id list
+/// @param ssp group id and ":syn include" tag of group
+/// @param contained group id is contained
+static int in_id_list(stateitem_T *cur_si, int16_t *list, struct sp_syn *ssp, int contained)
{
int retval;
int16_t *scl_list;
@@ -5450,30 +5568,35 @@ in_id_list(
static int depth = 0;
int r;
- /* If ssp has a "containedin" list and "cur_si" is in it, return TRUE. */
+ // If ssp has a "containedin" list and "cur_si" is in it, return TRUE.
if (cur_si != NULL && ssp->cont_in_list != NULL
&& !(cur_si->si_flags & HL_MATCH)) {
/* Ignore transparent items without a contains argument. Double check
* that we don't go back past the first one. */
while ((cur_si->si_flags & HL_TRANS_CONT)
- && cur_si > (stateitem_T *)(current_state.ga_data))
+ && cur_si > (stateitem_T *)(current_state.ga_data)) {
--cur_si;
- /* cur_si->si_idx is -1 for keywords, these never contain anything. */
+ }
+ // cur_si->si_idx is -1 for keywords, these never contain anything.
if (cur_si->si_idx >= 0 && in_id_list(NULL, ssp->cont_in_list,
- &(SYN_ITEMS(syn_block)[cur_si->si_idx].sp_syn),
- SYN_ITEMS(syn_block)[cur_si->si_idx].sp_flags & HL_CONTAINED))
+ &(SYN_ITEMS(syn_block)[cur_si->si_idx].sp_syn),
+ SYN_ITEMS(syn_block)[cur_si->si_idx].sp_flags &
+ HL_CONTAINED)) {
return TRUE;
+ }
}
- if (list == NULL)
+ if (list == NULL) {
return FALSE;
+ }
/*
* If list is ID_LIST_ALL, we are in a transparent item that isn't
* inside anything. Only allow not-contained groups.
*/
- if (list == ID_LIST_ALL)
+ if (list == ID_LIST_ALL) {
return !contained;
+ }
/*
* If the first item is "ALLBUT", return TRUE if "id" is NOT in the
@@ -5483,29 +5606,34 @@ in_id_list(
item = *list;
if (item >= SYNID_ALLBUT && item < SYNID_CLUSTER) {
if (item < SYNID_TOP) {
- /* ALL or ALLBUT: accept all groups in the same file */
- if (item - SYNID_ALLBUT != ssp->inc_tag)
+ // ALL or ALLBUT: accept all groups in the same file
+ if (item - SYNID_ALLBUT != ssp->inc_tag) {
return FALSE;
- } else if (item < SYNID_CONTAINED) {
- /* TOP: accept all not-contained groups in the same file */
- if (item - SYNID_TOP != ssp->inc_tag || contained)
+ }
+ } else if (item < SYNID_CONTAINED) {
+ // TOP: accept all not-contained groups in the same file
+ if (item - SYNID_TOP != ssp->inc_tag || contained) {
return FALSE;
+ }
} else {
- /* CONTAINED: accept all contained groups in the same file */
- if (item - SYNID_CONTAINED != ssp->inc_tag || !contained)
+ // CONTAINED: accept all contained groups in the same file
+ if (item - SYNID_CONTAINED != ssp->inc_tag || !contained) {
return FALSE;
+ }
}
item = *++list;
retval = FALSE;
- } else
+ } else {
retval = TRUE;
+ }
/*
* Return "retval" if id is in the contains list.
*/
while (item != 0) {
- if (item == id)
+ if (item == id) {
return retval;
+ }
if (item >= SYNID_CLUSTER) {
scl_list = SYN_CLSTR(syn_block)[item - SYNID_CLUSTER].scl_list;
/* restrict recursiveness to 30 to avoid an endless loop for a
@@ -5514,8 +5642,9 @@ in_id_list(
++depth;
r = in_id_list(NULL, scl_list, ssp, contained);
--depth;
- if (r)
+ if (r) {
return retval;
+ }
}
}
item = *++list;
@@ -5524,8 +5653,8 @@ in_id_list(
}
struct subcommand {
- char *name; /* subcommand name */
- void (*func)(exarg_T *, int); /* function to call */
+ char *name; // subcommand name
+ void (*func)(exarg_T *, int); // function to call
};
static struct subcommand subcommands[] =
@@ -5534,7 +5663,7 @@ static struct subcommand subcommands[] =
{ "clear", syn_cmd_clear },
{ "cluster", syn_cmd_cluster },
{ "conceal", syn_cmd_conceal },
- { "enable", syn_cmd_enable },
+ { "enable", syn_cmd_on },
{ "foldlevel", syn_cmd_foldlevel },
{ "include", syn_cmd_include },
{ "iskeyword", syn_cmd_iskeyword },
@@ -5559,8 +5688,8 @@ static struct subcommand subcommands[] =
*/
void ex_syntax(exarg_T *eap)
{
- char_u *arg = eap->arg;
- char_u *subcmd_end;
+ char_u *arg = eap->arg;
+ char_u *subcmd_end;
syn_cmdlinep = eap->cmdlinep;
@@ -5583,14 +5712,15 @@ void ex_syntax(exarg_T *eap)
}
}
xfree(subcmd_name);
- if (eap->skip)
+ if (eap->skip) {
--emsg_skip;
+ }
}
void ex_ownsyntax(exarg_T *eap)
{
- char_u *old_value;
- char_u *new_value;
+ char_u *old_value;
+ char_u *new_value;
if (curwin->w_s == &curwin->w_buffer->b_s) {
curwin->w_s = xmalloc(sizeof(synblock_T));
@@ -5613,9 +5743,8 @@ void ex_ownsyntax(exarg_T *eap)
old_value = vim_strsave(old_value);
}
- /* Apply the "syntax" autocommand event, this finds and loads the syntax
- * file. */
- apply_autocmds(EVENT_SYNTAX, eap->arg, curbuf->b_fname, TRUE, curbuf);
+ // Apply the "syntax" autocommand event, this finds and loads the syntax file.
+ apply_autocmds(EVENT_SYNTAX, eap->arg, curbuf->b_fname, true, curbuf);
// Move value of b:current_syntax to w:current_syntax.
new_value = get_var_value("b:current_syntax");
@@ -5680,7 +5809,7 @@ void set_context_in_syntax_cmd(expand_T *xp, const char *arg)
include_link = 0;
include_default = 0;
- /* (part of) subcommand already typed */
+ // (part of) subcommand already typed
if (*arg != NUL) {
const char *p = (const char *)skiptowhite((const char_u *)arg);
if (*p != NUL) { // Past first word.
@@ -5712,47 +5841,44 @@ void set_context_in_syntax_cmd(expand_T *xp, const char *arg)
char_u *get_syntax_name(expand_T *xp, int idx)
{
switch (expand_what) {
- case EXP_SUBCMD:
- return (char_u *)subcommands[idx].name;
- case EXP_CASE: {
- static char *case_args[] = { "match", "ignore", NULL };
- return (char_u *)case_args[idx];
- }
- case EXP_SPELL: {
- static char *spell_args[] =
- { "toplevel", "notoplevel", "default", NULL };
- return (char_u *)spell_args[idx];
- }
- case EXP_SYNC: {
- static char *sync_args[] =
- { "ccomment", "clear", "fromstart",
- "linebreaks=", "linecont", "lines=", "match",
- "maxlines=", "minlines=", "region", NULL };
- return (char_u *)sync_args[idx];
- }
+ case EXP_SUBCMD:
+ return (char_u *)subcommands[idx].name;
+ case EXP_CASE: {
+ static char *case_args[] = { "match", "ignore", NULL };
+ return (char_u *)case_args[idx];
+ }
+ case EXP_SPELL: {
+ static char *spell_args[] =
+ { "toplevel", "notoplevel", "default", NULL };
+ return (char_u *)spell_args[idx];
+ }
+ case EXP_SYNC: {
+ static char *sync_args[] =
+ { "ccomment", "clear", "fromstart",
+ "linebreaks=", "linecont", "lines=", "match",
+ "maxlines=", "minlines=", "region", NULL };
+ return (char_u *)sync_args[idx];
+ }
}
return NULL;
}
-// Function called for expression evaluation: get syntax ID at file position.
-int syn_get_id(
- win_T *wp,
- long lnum,
- colnr_T col,
- int trans, // remove transparency
- bool *spellp, // return: can do spell checking
- int keep_state // keep state of char at "col"
-)
+/// Function called for expression evaluation: get syntax ID at file position.
+///
+/// @param trans remove transparency
+/// @param spellp return: can do spell checking
+/// @param keep_state keep state of char at "col"
+int syn_get_id(win_T *wp, long lnum, colnr_T col, int trans, bool *spellp, int keep_state)
{
// When the position is not after the current position and in the same
// line of the same buffer, need to restart parsing.
if (wp->w_buffer != syn_buf || lnum != current_lnum || col < current_col) {
syntax_start(wp, lnum);
} else if (col > current_col) {
- // next_match may not be correct when moving around, e.g. with the
- // "skip" expression in searchpair()
- next_match_idx = -1;
+ // next_match may not be correct when moving around, e.g. with the
+ // "skip" expression in searchpair()
+ next_match_idx = -1;
}
(void)get_syntax_attr(col, spellp, keep_state);
@@ -5860,8 +5986,9 @@ int syn_get_foldlevel(win_T *wp, long lnum)
}
if (level > wp->w_p_fdn) {
level = wp->w_p_fdn;
- if (level < 0)
+ if (level < 0) {
level = 0;
+ }
}
return level;
}
@@ -5871,16 +5998,17 @@ int syn_get_foldlevel(win_T *wp, long lnum)
*/
void ex_syntime(exarg_T *eap)
{
- if (STRCMP(eap->arg, "on") == 0)
- syn_time_on = TRUE;
- else if (STRCMP(eap->arg, "off") == 0)
- syn_time_on = FALSE;
- else if (STRCMP(eap->arg, "clear") == 0)
+ if (STRCMP(eap->arg, "on") == 0) {
+ syn_time_on = true;
+ } else if (STRCMP(eap->arg, "off") == 0) {
+ syn_time_on = false;
+ } else if (STRCMP(eap->arg, "clear") == 0) {
syntime_clear();
- else if (STRCMP(eap->arg, "report") == 0)
+ } else if (STRCMP(eap->arg, "report") == 0) {
syntime_report();
- else
+ } else {
EMSG2(_(e_invarg2), eap->arg);
+ }
}
static void syn_clear_time(syn_time_T *st)
@@ -5896,7 +6024,7 @@ static void syn_clear_time(syn_time_T *st)
*/
static void syntime_clear(void)
{
- synpat_T *spp;
+ synpat_T *spp;
if (!syntax_present(curwin)) {
MSG(_(msg_no_items));
@@ -5915,18 +6043,22 @@ static void syntime_clear(void)
char_u *get_syntime_arg(expand_T *xp, int idx)
{
switch (idx) {
- case 0: return (char_u *)"on";
- case 1: return (char_u *)"off";
- case 2: return (char_u *)"clear";
- case 3: return (char_u *)"report";
+ case 0:
+ return (char_u *)"on";
+ case 1:
+ return (char_u *)"off";
+ case 2:
+ return (char_u *)"clear";
+ case 3:
+ return (char_u *)"report";
}
return NULL;
}
static int syn_compare_syntime(const void *v1, const void *v2)
{
- const time_entry_T *s1 = v1;
- const time_entry_T *s2 = v2;
+ const time_entry_T *s1 = v1;
+ const time_entry_T *s2 = v2;
return profile_cmp(s1->total, s2->total);
}
@@ -5971,14 +6103,13 @@ static void syntime_report(void)
syn_compare_syntime);
}
- MSG_PUTS_TITLE(_(
- " TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"));
+ MSG_PUTS_TITLE(_(" TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN"));
MSG_PUTS("\n");
for (int idx = 0; idx < ga.ga_len && !got_int; ++idx) {
p = ((time_entry_T *)ga.ga_data) + idx;
MSG_PUTS(profile_msg(p->total));
- MSG_PUTS(" "); /* make sure there is always a separating space */
+ MSG_PUTS(" "); // make sure there is always a separating space
msg_advance(13);
msg_outnum(p->count);
MSG_PUTS(" ");
@@ -5997,12 +6128,14 @@ static void syntime_report(void)
msg_advance(69);
int len;
- if (Columns < 80)
- len = 20; /* will wrap anyway */
- else
+ if (Columns < 80) {
+ len = 20; // will wrap anyway
+ } else {
len = Columns - 70;
- if (len > (int)STRLEN(p->pattern))
+ }
+ if (len > (int)STRLEN(p->pattern)) {
len = (int)STRLEN(p->pattern);
+ }
msg_outtrans_len(p->pattern, len);
MSG_PUTS("\n");
}
@@ -6017,7 +6150,7 @@ static void syntime_report(void)
}
/**************************************
-* Highlighting stuff *
+* Highlighting stuff *
**************************************/
// The default highlight groups. These are compiled-in for fast startup and
@@ -6026,8 +6159,7 @@ static void syntime_report(void)
// When making changes here, also change runtime/colors/default.vim!
static const char *highlight_init_both[] = {
- "Conceal "
- "ctermbg=DarkGrey ctermfg=LightGrey guibg=DarkGrey guifg=LightGrey",
+ "Conceal ctermbg=DarkGrey ctermfg=LightGrey guibg=DarkGrey guifg=LightGrey",
"Cursor guibg=fg guifg=bg",
"lCursor guibg=fg guifg=bg",
"DiffText cterm=bold ctermbg=Red gui=bold guibg=Red",
@@ -6045,6 +6177,8 @@ static const char *highlight_init_both[] = {
"VertSplit cterm=reverse gui=reverse",
"WildMenu ctermbg=Yellow ctermfg=Black guibg=Yellow guifg=Black",
"default link EndOfBuffer NonText",
+ "default link LineNrAbove LineNr",
+ "default link LineNrBelow LineNr",
"default link QuickFixLine Search",
"default link Substitute Search",
"default link Whitespace NonText",
@@ -6057,6 +6191,32 @@ static const char *highlight_init_both[] = {
"RedrawDebugClear ctermbg=Yellow guibg=Yellow",
"RedrawDebugComposed ctermbg=Green guibg=Green",
"RedrawDebugRecompose ctermbg=Red guibg=Red",
+ "Error term=reverse cterm=NONE ctermfg=White ctermbg=Red gui=NONE guifg=White guibg=Red",
+ "Todo term=standout cterm=NONE ctermfg=Black ctermbg=Yellow gui=NONE guifg=Blue guibg=Yellow",
+ "default link String Constant",
+ "default link Character Constant",
+ "default link Number Constant",
+ "default link Boolean Constant",
+ "default link Float Number",
+ "default link Function Identifier",
+ "default link Conditional Statement",
+ "default link Repeat Statement",
+ "default link Label Statement",
+ "default link Operator Statement",
+ "default link Keyword Statement",
+ "default link Exception Statement",
+ "default link Include PreProc",
+ "default link Define PreProc",
+ "default link Macro PreProc",
+ "default link PreCondit PreProc",
+ "default link StorageClass Type",
+ "default link Structure Type",
+ "default link Typedef Type",
+ "default link Tag Special",
+ "default link SpecialChar Special",
+ "default link Delimiter Special",
+ "default link SpecialComment Special",
+ "default link Debug Special",
NULL
};
@@ -6065,7 +6225,7 @@ static const char *highlight_init_light[] = {
"ColorColumn ctermbg=LightRed guibg=LightRed",
"CursorColumn ctermbg=LightGrey guibg=Grey90",
"CursorLine cterm=underline guibg=Grey90",
- "CursorLineNr ctermfg=Brown gui=bold guifg=Brown",
+ "CursorLineNr cterm=underline ctermfg=Brown gui=bold guifg=Brown",
"DiffAdd ctermbg=LightBlue guibg=LightBlue",
"DiffChange ctermbg=LightMagenta guibg=LightMagenta",
"DiffDelete ctermfg=Blue ctermbg=LightCyan gui=bold guifg=Blue guibg=LightCyan",
@@ -6090,6 +6250,15 @@ static const char *highlight_init_light[] = {
"Title ctermfg=DarkMagenta gui=bold guifg=Magenta",
"Visual guibg=LightGrey",
"WarningMsg ctermfg=DarkRed guifg=Red",
+ "Comment term=bold cterm=NONE ctermfg=DarkBlue ctermbg=NONE gui=NONE guifg=Blue guibg=NONE",
+ "Constant term=underline cterm=NONE ctermfg=DarkRed ctermbg=NONE gui=NONE guifg=Magenta guibg=NONE",
+ "Special term=bold cterm=NONE ctermfg=DarkMagenta ctermbg=NONE gui=NONE guifg=#6a5acd guibg=NONE",
+ "Identifier term=underline cterm=NONE ctermfg=DarkCyan ctermbg=NONE gui=NONE guifg=DarkCyan guibg=NONE",
+ "Statement term=bold cterm=NONE ctermfg=Brown ctermbg=NONE gui=bold guifg=Brown guibg=NONE",
+ "PreProc term=underline cterm=NONE ctermfg=DarkMagenta ctermbg=NONE gui=NONE guifg=#6a0dad guibg=NONE",
+ "Type term=underline cterm=NONE ctermfg=DarkGreen ctermbg=NONE gui=bold guifg=SeaGreen guibg=NONE",
+ "Underlined term=underline cterm=underline ctermfg=DarkMagenta gui=underline guifg=SlateBlue",
+ "Ignore term=NONE cterm=NONE ctermfg=white ctermbg=NONE gui=NONE guifg=bg guibg=NONE",
NULL
};
@@ -6098,7 +6267,7 @@ static const char *highlight_init_dark[] = {
"ColorColumn ctermbg=DarkRed guibg=DarkRed",
"CursorColumn ctermbg=DarkGrey guibg=Grey40",
"CursorLine cterm=underline guibg=Grey40",
- "CursorLineNr ctermfg=Yellow gui=bold guifg=Yellow",
+ "CursorLineNr cterm=underline ctermfg=Yellow gui=bold guifg=Yellow",
"DiffAdd ctermbg=DarkBlue guibg=DarkBlue",
"DiffChange ctermbg=DarkMagenta guibg=DarkMagenta",
"DiffDelete ctermfg=Blue ctermbg=DarkCyan gui=bold guifg=Blue guibg=DarkCyan",
@@ -6123,11 +6292,20 @@ static const char *highlight_init_dark[] = {
"Title ctermfg=LightMagenta gui=bold guifg=Magenta",
"Visual guibg=DarkGrey",
"WarningMsg ctermfg=LightRed guifg=Red",
+ "Comment term=bold cterm=NONE ctermfg=Cyan ctermbg=NONE gui=NONE guifg=#80a0ff guibg=NONE",
+ "Constant term=underline cterm=NONE ctermfg=Magenta ctermbg=NONE gui=NONE guifg=#ffa0a0 guibg=NONE",
+ "Special term=bold cterm=NONE ctermfg=LightRed ctermbg=NONE gui=NONE guifg=Orange guibg=NONE",
+ "Identifier term=underline cterm=bold ctermfg=Cyan ctermbg=NONE gui=NONE guifg=#40ffff guibg=NONE",
+ "Statement term=bold cterm=NONE ctermfg=Yellow ctermbg=NONE gui=bold guifg=#ffff60 guibg=NONE",
+ "PreProc term=underline cterm=NONE ctermfg=LightBlue ctermbg=NONE gui=NONE guifg=#ff80ff guibg=NONE",
+ "Type term=underline cterm=NONE ctermfg=LightGreen ctermbg=NONE gui=bold guifg=#60ff60 guibg=NONE",
+ "Underlined term=underline cterm=underline ctermfg=LightBlue gui=underline guifg=#80a0ff",
+ "Ignore term=NONE cterm=NONE ctermfg=black ctermbg=NONE gui=NONE guifg=bg guibg=NONE",
NULL
};
const char *const highlight_init_cmdline[] = {
- // XXX When modifying a list modify it in both valid and invalid halfs.
+ // XXX When modifying a list modify it in both valid and invalid halves.
// TODO(ZyX-I): merge valid and invalid groups via a macros.
// NvimInternalError should appear only when highlighter has a bug.
@@ -6229,12 +6407,9 @@ const char *const highlight_init_cmdline[] = {
"default link NvimInvalidAssignment NvimInvalid",
"default link NvimInvalidPlainAssignment NvimInvalidAssignment",
"default link NvimInvalidAugmentedAssignment NvimInvalidAssignment",
- "default link NvimInvalidAssignmentWithAddition "
- "NvimInvalidAugmentedAssignment",
- "default link NvimInvalidAssignmentWithSubtraction "
- "NvimInvalidAugmentedAssignment",
- "default link NvimInvalidAssignmentWithConcatenation "
- "NvimInvalidAugmentedAssignment",
+ "default link NvimInvalidAssignmentWithAddition NvimInvalidAugmentedAssignment",
+ "default link NvimInvalidAssignmentWithSubtraction NvimInvalidAugmentedAssignment",
+ "default link NvimInvalidAssignmentWithConcatenation NvimInvalidAugmentedAssignment",
"default link NvimInvalidOperator NvimInvalid",
@@ -6296,7 +6471,7 @@ const char *const highlight_init_cmdline[] = {
"default link NvimInvalidOptionName NvimInvalidIdentifier",
"default link NvimInvalidOptionScope NvimInvalidIdentifierScope",
"default link NvimInvalidOptionScopeDelimiter "
- "NvimInvalidIdentifierScopeDelimiter",
+ "NvimInvalidIdentifierScopeDelimiter",
"default link NvimInvalidEnvironmentSigil NvimInvalidOptionSigil",
"default link NvimInvalidEnvironmentName NvimInvalidIdentifier",
@@ -6354,7 +6529,7 @@ void init_highlight(bool both, bool reset)
bool okay = load_colors(copy_p);
xfree(copy_p);
if (okay) {
- return;
+ return;
}
}
@@ -6368,7 +6543,7 @@ void init_highlight(bool both, bool reset)
do_highlight(pp[i], reset, true);
}
} else if (!had_both) {
- // Don't do anything before the call with both == TRUE from main().
+ // Don't do anything before the call with both == true from main().
// Not everything has been setup then, and that call will overrule
// everything anyway.
return;
@@ -6387,8 +6562,7 @@ void init_highlight(bool both, bool reset)
* to avoid Statement highlighted text disappears.
* Clear the attributes, needed when changing the t_Co value. */
if (t_colors > 8) {
- do_highlight(
- (*p_bg == 'l'
+ do_highlight((*p_bg == 'l'
? "Visual cterm=NONE ctermbg=LightGrey"
: "Visual cterm=NONE ctermbg=DarkGrey"), false, true);
} else {
@@ -6398,20 +6572,6 @@ void init_highlight(bool both, bool reset)
}
}
- /*
- * If syntax highlighting is enabled load the highlighting for it.
- */
- if (get_var_value("g:syntax_on") != NULL) {
- static int recursive = 0;
-
- if (recursive >= 5) {
- EMSG(_("E679: recursive loop loading syncolor.vim"));
- } else {
- recursive++;
- (void)source_runtime((char_u *)"syntax/syncolor.vim", DIP_ALL);
- recursive--;
- }
- }
syn_init_cmdline_highlight(false, false);
}
@@ -6421,9 +6581,9 @@ void init_highlight(bool both, bool reset)
*/
int load_colors(char_u *name)
{
- char_u *buf;
+ char_u *buf;
int retval = FAIL;
- static int recursive = false;
+ static bool recursive = false;
// When being called recursively, this is probably because setting
// 'background' caused the highlighting to be reloaded. This means it is
@@ -6443,7 +6603,7 @@ int load_colors(char_u *name)
retval = source_runtime(buf, DIP_START + DIP_OPT);
}
xfree(buf);
- apply_autocmds(EVENT_COLORSCHEME, name, curbuf->b_fname, FALSE, curbuf);
+ apply_autocmds(EVENT_COLORSCHEME, name, curbuf->b_fname, false, curbuf);
recursive = false;
@@ -6457,46 +6617,47 @@ static char *(color_names[28]) = {
"DarkGray", "DarkGrey",
"Blue", "LightBlue", "Green", "LightGreen",
"Cyan", "LightCyan", "Red", "LightRed", "Magenta",
- "LightMagenta", "Yellow", "LightYellow", "White", "NONE" };
- // indices:
- // 0, 1, 2, 3,
- // 4, 5, 6, 7,
- // 8, 9, 10, 11,
- // 12, 13,
- // 14, 15, 16, 17,
- // 18, 19, 20, 21, 22,
- // 23, 24, 25, 26, 27
+ "LightMagenta", "Yellow", "LightYellow", "White", "NONE"
+};
+// indices:
+// 0, 1, 2, 3,
+// 4, 5, 6, 7,
+// 8, 9, 10, 11,
+// 12, 13,
+// 14, 15, 16, 17,
+// 18, 19, 20, 21, 22,
+// 23, 24, 25, 26, 27
static int color_numbers_16[28] = { 0, 1, 2, 3,
- 4, 5, 6, 6,
- 7, 7, 7, 7,
- 8, 8,
- 9, 9, 10, 10,
- 11, 11, 12, 12, 13,
- 13, 14, 14, 15, -1 };
+ 4, 5, 6, 6,
+ 7, 7, 7, 7,
+ 8, 8,
+ 9, 9, 10, 10,
+ 11, 11, 12, 12, 13,
+ 13, 14, 14, 15, -1 };
// for xterm with 88 colors...
static int color_numbers_88[28] = { 0, 4, 2, 6,
- 1, 5, 32, 72,
- 84, 84, 7, 7,
- 82, 82,
- 12, 43, 10, 61,
- 14, 63, 9, 74, 13,
- 75, 11, 78, 15, -1 };
+ 1, 5, 32, 72,
+ 84, 84, 7, 7,
+ 82, 82,
+ 12, 43, 10, 61,
+ 14, 63, 9, 74, 13,
+ 75, 11, 78, 15, -1 };
// for xterm with 256 colors...
static int color_numbers_256[28] = { 0, 4, 2, 6,
- 1, 5, 130, 3,
- 248, 248, 7, 7,
- 242, 242,
- 12, 81, 10, 121,
- 14, 159, 9, 224, 13,
- 225, 11, 229, 15, -1 };
+ 1, 5, 130, 3,
+ 248, 248, 7, 7,
+ 242, 242,
+ 12, 81, 10, 121,
+ 14, 159, 9, 224, 13,
+ 225, 11, 229, 15, -1 };
// for terminals with less than 16 colors...
static int color_numbers_8[28] = { 0, 4, 2, 6,
- 1, 5, 3, 3,
- 7, 7, 7, 7,
- 0+8, 0+8,
- 4+8, 4+8, 2+8, 2+8,
- 6+8, 6+8, 1+8, 1+8, 5+8,
- 5+8, 3+8, 3+8, 7+8, -1 };
+ 1, 5, 3, 3,
+ 7, 7, 7, 7,
+ 0+8, 0+8,
+ 4+8, 4+8, 2+8, 2+8,
+ 6+8, 6+8, 1+8, 1+8, 5+8,
+ 5+8, 3+8, 3+8, 7+8, -1 };
// Lookup the "cterm" value to be used for color with index "idx" in
// color_names[].
@@ -6597,7 +6758,7 @@ void do_highlight(const char *line, const bool forceit, const bool init)
// ":highlight {group-name}": list highlighting for one group.
if (!doclear && !dolink && ends_excmd((uint8_t)(*linep))) {
- id = syn_namen2id((const char_u *)line, (int)(name_end - line));
+ id = syn_name2id_len((const char_u *)line, (int)(name_end - line));
if (id == 0) {
emsgf(_("E411: highlight group not found: %s"), line);
} else {
@@ -6814,7 +6975,7 @@ void do_highlight(const char *line, const bool forceit, const bool init)
if (error) {
break;
}
- if (*key == 'C') {
+ if (*key == 'C') {
if (!init || !(HL_TABLE()[idx].sg_set & SG_CTERM)) {
if (!init) {
HL_TABLE()[idx].sg_set |= SG_CTERM;
@@ -6830,7 +6991,7 @@ void do_highlight(const char *line, const bool forceit, const bool init)
HL_TABLE()[idx].sg_gui = attr;
}
}
- } else if (STRCMP(key, "FONT") == 0) {
+ } else if (STRCMP(key, "FONT") == 0) {
// in non-GUI fonts are simply ignored
} else if (STRCMP(key, "CTERMFG") == 0 || STRCMP(key, "CTERMBG") == 0) {
if (!init || !(HL_TABLE()[idx].sg_set & SG_CTERM)) {
@@ -6846,7 +7007,7 @@ void do_highlight(const char *line, const bool forceit, const bool init)
}
if (ascii_isdigit(*arg)) {
- color = atoi((char *)arg);
+ color = atoi(arg);
} else if (STRICMP(arg, "fg") == 0) {
if (cterm_normal_fg_color) {
color = cterm_normal_fg_color - 1;
@@ -6855,10 +7016,10 @@ void do_highlight(const char *line, const bool forceit, const bool init)
error = true;
break;
}
- } else if (STRICMP(arg, "bg") == 0) {
- if (cterm_normal_bg_color > 0)
+ } else if (STRICMP(arg, "bg") == 0) {
+ if (cterm_normal_bg_color > 0) {
color = cterm_normal_bg_color - 1;
- else {
+ } else {
EMSG(_("E420: BG color unknown"));
error = true;
break;
@@ -6925,7 +7086,7 @@ void do_highlight(const char *line, const bool forceit, const bool init)
}
}
}
- } else if (strcmp(key, "GUIFG") == 0) {
+ } else if (strcmp(key, "GUIFG") == 0) {
char **namep = &HL_TABLE()[idx].sg_rgb_fg_name;
if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) {
@@ -6949,7 +7110,7 @@ void do_highlight(const char *line, const bool forceit, const bool init)
if (is_normal_group) {
normal_fg = HL_TABLE()[idx].sg_rgb_fg;
}
- } else if (STRCMP(key, "GUIBG") == 0) {
+ } else if (STRCMP(key, "GUIBG") == 0) {
char **const namep = &HL_TABLE()[idx].sg_rgb_bg_name;
if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) {
@@ -6973,7 +7134,7 @@ void do_highlight(const char *line, const bool forceit, const bool init)
if (is_normal_group) {
normal_bg = HL_TABLE()[idx].sg_rgb_bg;
}
- } else if (strcmp(key, "GUISP") == 0) {
+ } else if (strcmp(key, "GUISP") == 0) {
char **const namep = &HL_TABLE()[idx].sg_rgb_sp_name;
if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) {
@@ -6997,9 +7158,9 @@ void do_highlight(const char *line, const bool forceit, const bool init)
if (is_normal_group) {
normal_sp = HL_TABLE()[idx].sg_rgb_sp;
}
- } else if (strcmp(key, "START") == 0 || strcmp(key, "STOP") == 0) {
+ } else if (strcmp(key, "START") == 0 || strcmp(key, "STOP") == 0) {
// Ignored for now
- } else if (strcmp(key, "BLEND") == 0) {
+ } else if (strcmp(key, "BLEND") == 0) {
if (strcmp(arg, "NONE") != 0) {
HL_TABLE()[idx].sg_blend = strtol(arg, NULL, 10);
} else {
@@ -7075,6 +7236,7 @@ void free_highlight(void)
xfree(HL_TABLE()[i].sg_name_u);
}
ga_clear(&highlight_ga);
+ map_destroy(cstr_t, int)(&highlight_unames);
}
#endif
@@ -7092,20 +7254,19 @@ void restore_cterm_colors(void)
cterm_normal_bg_color = 0;
}
-/*
- * Return TRUE if highlight group "idx" has any settings.
- * When "check_link" is TRUE also check for an existing link.
- */
-static int hl_has_settings(int idx, int check_link)
+/// @param check_link if true also check for an existing link.
+///
+/// @return TRUE if highlight group "idx" has any settings.
+static int hl_has_settings(int idx, bool check_link)
{
return HL_TABLE()[idx].sg_cleared == 0
- && (HL_TABLE()[idx].sg_attr != 0
- || HL_TABLE()[idx].sg_cterm_fg != 0
- || HL_TABLE()[idx].sg_cterm_bg != 0
- || HL_TABLE()[idx].sg_rgb_fg_name != NULL
- || HL_TABLE()[idx].sg_rgb_bg_name != NULL
- || HL_TABLE()[idx].sg_rgb_sp_name != NULL
- || (check_link && (HL_TABLE()[idx].sg_set & SG_LINK)));
+ && (HL_TABLE()[idx].sg_attr != 0
+ || HL_TABLE()[idx].sg_cterm_fg != 0
+ || HL_TABLE()[idx].sg_cterm_bg != 0
+ || HL_TABLE()[idx].sg_rgb_fg_name != NULL
+ || HL_TABLE()[idx].sg_rgb_bg_name != NULL
+ || HL_TABLE()[idx].sg_rgb_sp_name != NULL
+ || (check_link && (HL_TABLE()[idx].sg_set & SG_LINK)));
}
/*
@@ -7153,18 +7314,18 @@ static void highlight_list_one(const int id)
}
didh = highlight_list_arg(id, didh, LIST_ATTR,
- sgp->sg_cterm, NULL, "cterm");
+ sgp->sg_cterm, NULL, "cterm");
didh = highlight_list_arg(id, didh, LIST_INT,
- sgp->sg_cterm_fg, NULL, "ctermfg");
+ sgp->sg_cterm_fg, NULL, "ctermfg");
didh = highlight_list_arg(id, didh, LIST_INT,
- sgp->sg_cterm_bg, NULL, "ctermbg");
+ sgp->sg_cterm_bg, NULL, "ctermbg");
didh = highlight_list_arg(id, didh, LIST_ATTR,
- sgp->sg_gui, NULL, "gui");
+ sgp->sg_gui, NULL, "gui");
didh = highlight_list_arg(id, didh, LIST_STRING,
- 0, sgp->sg_rgb_fg_name, "guifg");
+ 0, sgp->sg_rgb_fg_name, "guifg");
didh = highlight_list_arg(id, didh, LIST_STRING,
- 0, sgp->sg_rgb_bg_name, "guibg");
+ 0, sgp->sg_rgb_bg_name, "guibg");
didh = highlight_list_arg(id, didh, LIST_STRING,
0, sgp->sg_rgb_sp_name, "guisp");
@@ -7210,9 +7371,8 @@ Dictionary get_global_hl_defs(void)
/// @param type one of \ref LIST_XXX
/// @param iarg integer argument used if \p type == LIST_INT
/// @param sarg string used if \p type == LIST_STRING
-static bool highlight_list_arg(
- const int id, bool didh, const int type, int iarg,
- char *const sarg, const char *const name)
+static bool highlight_list_arg(const int id, bool didh, const int type, int iarg, char *const sarg,
+ const char *const name)
{
char buf[100];
@@ -7229,10 +7389,11 @@ static bool highlight_list_arg(
buf[0] = NUL;
for (int i = 0; hl_attr_table[i] != 0; i++) {
if (iarg & hl_attr_table[i]) {
- if (buf[0] != NUL)
+ if (buf[0] != NUL) {
xstrlcat((char *)buf, ",", 100);
+ }
xstrlcat((char *)buf, hl_name_table[i], 100);
- iarg &= ~hl_attr_table[i]; /* don't want "inverse" */
+ iarg &= ~hl_attr_table[i]; // don't want "inverse"
}
}
}
@@ -7285,8 +7446,7 @@ const char *highlight_has_attr(const int id, const int flag, const int modec)
///
/// @return color name, possibly in a static buffer. Buffer will be overwritten
/// on next highlight_color() call. May return NULL.
-const char *highlight_color(const int id, const char *const what,
- const int modec)
+const char *highlight_color(const int id, const char *const what, const int modec)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
static char name[20];
@@ -7312,11 +7472,11 @@ const char *highlight_color(const int id, const char *const what,
if (modec == 'g') {
if (what[2] == '#' && ui_rgb_attached()) {
if (fg) {
- n = HL_TABLE()[id - 1].sg_rgb_fg;
+ n = HL_TABLE()[id - 1].sg_rgb_fg;
} else if (sp) {
- n = HL_TABLE()[id - 1].sg_rgb_sp;
+ n = HL_TABLE()[id - 1].sg_rgb_sp;
} else {
- n = HL_TABLE()[id - 1].sg_rgb_bg;
+ n = HL_TABLE()[id - 1].sg_rgb_bg;
}
if (n < 0 || n > 0xffffff) {
return NULL;
@@ -7358,8 +7518,8 @@ const char *highlight_color(const int id, const char *const what,
/// @param id highlight group id
/// @param force_newline always start a new line
/// @return true when started a new line.
-static bool syn_list_header(const bool did_header, const int outlen,
- const int id, bool force_newline)
+static bool syn_list_header(const bool did_header, const int outlen, const int id,
+ bool force_newline)
{
int endcol = 19;
bool newline = true;
@@ -7375,7 +7535,7 @@ static bool syn_list_header(const bool did_header, const int outlen,
} else if ((ui_has(kUIMessages) || msg_silent) && !force_newline) {
msg_putchar(' ');
adjust = false;
- } else if (msg_col + outlen + 1 >= Columns || force_newline) {
+ } else if (msg_col + outlen + 1 >= Columns || force_newline) {
msg_putchar('\n');
if (got_int) {
return true;
@@ -7395,7 +7555,7 @@ static bool syn_list_header(const bool did_header, const int outlen,
msg_advance(endcol);
}
- /* Show "xxx" with the attributes. */
+ // Show "xxx" with the attributes.
if (!did_header) {
msg_puts_attr("xxx", syn_id2attr(id));
msg_putchar(' ');
@@ -7410,7 +7570,7 @@ static bool syn_list_header(const bool did_header, const int outlen,
static void set_hl_attr(int idx)
{
HlAttrs at_en = HLATTRS_INIT;
- struct hl_group *sgp = HL_TABLE() + idx;
+ struct hl_group *sgp = HL_TABLE() + idx;
at_en.cterm_ae_attr = sgp->sg_cterm;
at_en.cterm_fg_color = sgp->sg_cterm_fg;
@@ -7432,26 +7592,35 @@ static void set_hl_attr(int idx)
}
}
+int syn_name2id(const char_u *name)
+ FUNC_ATTR_NONNULL_ALL
+{
+ return syn_name2id_len(name, STRLEN(name));
+}
+
/// Lookup a highlight group name and return its ID.
///
/// @param highlight name e.g. 'Cursor', 'Normal'
/// @return the highlight id, else 0 if \p name does not exist
-int syn_name2id(const char_u *name)
+int syn_name2id_len(const char_u *name, size_t len)
FUNC_ATTR_NONNULL_ALL
{
- int i;
- char_u name_u[200];
-
- /* Avoid using stricmp() too much, it's slow on some systems */
- /* Avoid alloc()/free(), these are slow too. ID names over 200 chars
- * don't deserve to be found! */
- STRLCPY(name_u, name, 200);
- vim_strup(name_u);
- for (i = highlight_ga.ga_len; --i >= 0; )
- if (HL_TABLE()[i].sg_name_u != NULL
- && STRCMP(name_u, HL_TABLE()[i].sg_name_u) == 0)
- break;
- return i + 1;
+ char name_u[201];
+
+ if (len == 0 || len > 200) {
+ // ID names over 200 chars don't deserve to be found!
+ return 0;
+ }
+
+ // Avoid using stricmp() too much, it's slow on some systems */
+ // Avoid alloc()/free(), these are slow too.
+ memcpy(name_u, name, len);
+ name_u[len] = '\0';
+ vim_strup((char_u *)name_u);
+
+ // map_get(..., int) returns 0 when no key is present, which is
+ // the expected value for missing highlight group.
+ return map_get(cstr_t, int)(&highlight_unames, name_u);
}
/// Lookup a highlight group name and return its attributes.
@@ -7481,22 +7650,12 @@ int highlight_exists(const char_u *name)
*/
char_u *syn_id2name(int id)
{
- if (id <= 0 || id > highlight_ga.ga_len)
+ if (id <= 0 || id > highlight_ga.ga_len) {
return (char_u *)"";
+ }
return HL_TABLE()[id - 1].sg_name;
}
-/*
- * Like syn_name2id(), but take a pointer + length argument.
- */
-int syn_namen2id(const char_u *linep, int len)
-{
- char_u *name = vim_strnsave(linep, len);
- int id = syn_name2id(name);
- xfree(name);
-
- return id;
-}
/// Find highlight group name in the table and return its ID.
/// If it doesn't exist yet, a new entry is created.
@@ -7505,14 +7664,11 @@ int syn_namen2id(const char_u *linep, int len)
/// @param len length of \p pp
///
/// @return 0 for failure else the id of the group
-int syn_check_group(const char_u *pp, int len)
+int syn_check_group(const char_u *name, int len)
{
- char_u *name = vim_strnsave(pp, len);
- int id = syn_name2id(name);
+ int id = syn_name2id_len(name, len);
if (id == 0) { // doesn't exist yet
- id = syn_add_group(name);
- } else {
- xfree(name);
+ return syn_add_group(vim_strnsave(name, len));
}
return id;
}
@@ -7524,15 +7680,15 @@ int syn_check_group(const char_u *pp, int len)
/// @see syn_check_group syn_unadd_group
static int syn_add_group(char_u *name)
{
- char_u *p;
+ char_u *p;
- /* Check that the name is ASCII letters, digits and underscore. */
+ // Check that the name is ASCII letters, digits and underscore.
for (p = name; *p != NUL; ++p) {
if (!vim_isprintc(*p)) {
EMSG(_("E669: Unprintable character in group name"));
xfree(name);
return 0;
- } else if (!ASCII_ISALNUM(*p) && *p != '_') {
+ } else if (!ASCII_ISALNUM(*p) && *p != '_') {
/* This is an error, but since there previously was no check only
* give a warning. */
msg_source(HL_ATTR(HLF_W));
@@ -7555,10 +7711,10 @@ static int syn_add_group(char_u *name)
return 0;
}
- char_u *const name_up = vim_strsave_up(name);
+ char *const name_up = (char *)vim_strsave_up(name);
// Append another syntax_highlight entry.
- struct hl_group* hlgp = GA_APPEND_VIA_PTR(struct hl_group, &highlight_ga);
+ struct hl_group * hlgp = GA_APPEND_VIA_PTR(struct hl_group, &highlight_ga);
memset(hlgp, 0, sizeof(*hlgp));
hlgp->sg_name = name;
hlgp->sg_rgb_bg = -1;
@@ -7567,7 +7723,11 @@ static int syn_add_group(char_u *name)
hlgp->sg_blend = -1;
hlgp->sg_name_u = name_up;
- return highlight_ga.ga_len; /* ID is index plus one */
+ int id = highlight_ga.ga_len; // ID is index plus one
+
+ map_put(cstr_t, int)(&highlight_unames, name_up, id);
+
+ return id;
}
/// When, just after calling syn_add_group(), an error is discovered, this
@@ -7575,8 +7735,10 @@ static int syn_add_group(char_u *name)
static void syn_unadd_group(void)
{
highlight_ga.ga_len--;
- xfree(HL_TABLE()[highlight_ga.ga_len].sg_name);
- xfree(HL_TABLE()[highlight_ga.ga_len].sg_name_u);
+ HlGroup *item = &HL_TABLE()[highlight_ga.ga_len];
+ map_del(cstr_t, int)(&highlight_unames, item->sg_name_u);
+ xfree(item->sg_name);
+ xfree(item->sg_name_u);
}
@@ -7604,9 +7766,9 @@ int syn_get_final_id(int hl_id)
{
int count;
- if (hl_id > highlight_ga.ga_len || hl_id < 1)
- return 0; /* Can be called from eval!! */
-
+ if (hl_id > highlight_ga.ga_len || hl_id < 1) {
+ return 0; // Can be called from eval!!
+ }
/*
* Follow links until there is no more.
* Look out for loops! Break after 100 links.
@@ -7654,8 +7816,7 @@ void highlight_attr_set_all(void)
}
// Apply difference between User[1-9] and HLF_S to HLF_SNC.
-static void combine_stl_hlt(int id, int id_S, int id_alt, int hlcnt, int i,
- int hlf, int *table)
+static void combine_stl_hlt(int id, int id_S, int id_alt, int hlcnt, int i, int hlf, int *table)
FUNC_ATTR_NONNULL_ALL
{
struct hl_group *const hlt = HL_TABLE();
@@ -7703,23 +7864,23 @@ void highlight_changed(void)
int id_SNC = 0;
int hlcnt;
- need_highlight_changed = FALSE;
+ need_highlight_changed = false;
/// Translate builtin highlight groups into attributes for quick lookup.
- for (int hlf = 0; hlf < (int)HLF_COUNT; hlf++) {
+ for (int hlf = 0; hlf < HLF_COUNT; hlf++) {
id = syn_check_group((char_u *)hlf_names[hlf], STRLEN(hlf_names[hlf]));
if (id == 0) {
abort();
}
int final_id = syn_get_final_id(id);
- if (hlf == (int)HLF_SNC) {
+ if (hlf == HLF_SNC) {
id_SNC = final_id;
- } else if (hlf == (int)HLF_S) {
+ } else if (hlf == HLF_S) {
id_S = final_id;
}
highlight_attr[hlf] = hl_get_ui_attr(hlf, final_id,
- hlf == (int)HLF_INACTIVE);
+ hlf == HLF_INACTIVE);
if (highlight_attr[hlf] != highlight_attr_last[hlf]) {
if (hlf == HLF_MSG) {
@@ -7772,7 +7933,7 @@ void set_context_in_highlight_cmd(expand_T *xp, const char *arg)
include_link = 2;
include_default = 1;
- /* (part of) subcommand already typed */
+ // (part of) subcommand already typed
if (*arg != NUL) {
const char *p = (const char *)skiptowhite((const char_u *)arg);
if (*p != NUL) { // Past "default" or group name.
@@ -7782,7 +7943,7 @@ void set_context_in_highlight_cmd(expand_T *xp, const char *arg)
xp->xp_pattern = (char_u *)arg;
p = (const char *)skiptowhite((const char_u *)arg);
}
- if (*p != NUL) { /* past group name */
+ if (*p != NUL) { // past group name
include_link = 0;
if (arg[1] == 'i' && arg[0] == 'N') {
highlight_list();
@@ -7837,8 +7998,9 @@ const char *get_highlight_name(expand_T *const xp, int idx)
/// Obtain a highlight group name.
-/// When "skip_cleared" is TRUE don't return a cleared entry.
-const char *get_highlight_name_ext(expand_T *xp, int idx, int skip_cleared)
+///
+/// @param skip_cleared if true don't return a cleared entry.
+const char *get_highlight_name_ext(expand_T *xp, int idx, bool skip_cleared)
FUNC_ATTR_WARN_UNUSED_RESULT
{
if (idx < 0) {
@@ -8560,7 +8722,6 @@ color_name_table_T color_name_table[] = {
/// return the hex value or -1 if could not find a correct value
RgbValue name_to_color(const char *name)
{
-
if (name[0] == '#' && isxdigit(name[1]) && isxdigit(name[2])
&& isxdigit(name[3]) && isxdigit(name[4]) && isxdigit(name[5])
&& isxdigit(name[6]) && name[7] == NUL) {
@@ -8583,5 +8744,5 @@ RgbValue name_to_color(const char *name)
/**************************************
-* End of Highlighting stuff *
+* End of Highlighting stuff *
**************************************/
diff --git a/src/nvim/tag.c b/src/nvim/tag.c
index ab35c936ca..c63cdad098 100644
--- a/src/nvim/tag.c
+++ b/src/nvim/tag.c
@@ -1371,12 +1371,12 @@ find_tags(
tagname_T tn; /* info for get_tagfname() */
int first_file; /* trying first tag file */
tagptrs_T tagp;
- int did_open = FALSE; /* did open a tag file */
- int stop_searching = FALSE; /* stop when match found or error */
- int retval = FAIL; /* return value */
- int is_static; /* current tag line is static */
- int is_current; /* file name matches */
- int eof = FALSE; /* found end-of-file */
+ bool did_open = false; // did open a tag file
+ bool stop_searching = false; // stop when match found or error
+ int retval = FAIL; // return value
+ int is_static; // current tag line is static
+ int is_current; // file name matches
+ bool eof = false; // found end-of-file
char_u *p;
char_u *s;
int i;
@@ -1429,12 +1429,12 @@ find_tags(
vimconv_T vimconv;
int findall = (mincount == MAXCOL || mincount == TAG_MANY);
- /* find all matching tags */
- int sort_error = FALSE; /* tags file not sorted */
- int linear; /* do a linear search */
- int sortic = FALSE; /* tag file sorted in nocase */
- int line_error = FALSE; /* syntax error */
- int has_re = (flags & TAG_REGEXP); /* regexp used */
+ // find all matching tags
+ bool sort_error = false; // tags file not sorted
+ int linear; // do a linear search
+ bool sortic = false; // tag file sorted in nocase
+ bool line_error = false; // syntax error
+ int has_re = (flags & TAG_REGEXP); // regexp used
int help_only = (flags & TAG_HELP);
int name_only = (flags & TAG_NAMES);
int noic = (flags & TAG_NOIC);
@@ -1467,6 +1467,7 @@ find_tags(
help_save = curbuf->b_help;
orgpat.pat = pat;
+ orgpat.regmatch.regprog = NULL;
vimconv.vc_type = CONV_NONE;
/*
@@ -1621,7 +1622,7 @@ find_tags(
verbose_leave();
}
}
- did_open = TRUE; /* remember that we found at least one file */
+ did_open = true; // remember that we found at least one file
state = TS_START; /* we're at the start of the file */
@@ -1638,13 +1639,13 @@ find_tags(
if ((flags & TAG_INS_COMP)) /* Double brackets for gcc */
ins_compl_check_keys(30, false);
if (got_int || compl_interrupted) {
- stop_searching = TRUE;
+ stop_searching = true;
break;
}
/* When mincount is TAG_MANY, stop when enough matches have been
* found (for completion). */
if (mincount == TAG_MANY && match_count >= TAG_MANY) {
- stop_searching = TRUE;
+ stop_searching = true;
retval = OK;
break;
}
@@ -1795,7 +1796,7 @@ line_read_in:
state = TS_BINARY;
else if (tag_file_sorted == '2') {
state = TS_BINARY;
- sortic = TRUE;
+ sortic = true;
orgpat.regmatch.rm_ic = (p_ic || !noic);
} else
state = TS_LINEAR;
@@ -1878,8 +1879,9 @@ parse_line:
i = (int)tagp.tagname[0];
if (sortic)
i = TOUPPER_ASC(tagp.tagname[0]);
- if (i < search_info.low_char || i > search_info.high_char)
- sort_error = TRUE;
+ if (i < search_info.low_char || i > search_info.high_char) {
+ sort_error = true;
+ }
/*
* Compare the current tag with the searched tag.
@@ -1970,7 +1972,7 @@ parse_line:
i = parse_tag_line(lbuf,
&tagp);
if (i == FAIL) {
- line_error = TRUE;
+ line_error = true;
break;
}
@@ -2175,7 +2177,7 @@ parse_line:
tag_file_sorted = NUL;
if (sort_error) {
EMSG2(_("E432: Tags file not sorted: %s"), tag_fname);
- sort_error = FALSE;
+ sort_error = false;
}
/*
@@ -2183,7 +2185,7 @@ parse_line:
*/
if (match_count >= mincount) {
retval = OK;
- stop_searching = TRUE;
+ stop_searching = true;
}
if (stop_searching || use_cscope)
@@ -2611,7 +2613,6 @@ static int jumpto_tag(
int keep_help // keep help flag (FALSE for cscope)
)
{
- int save_secure;
int save_magic;
bool save_p_ws;
int save_p_scs, save_p_ic;
@@ -2766,9 +2767,6 @@ static int jumpto_tag(
curwin->w_set_curswant = true;
postponed_split = 0;
- save_secure = secure;
- secure = 1;
- ++sandbox;
save_magic = p_magic;
p_magic = false; // always execute with 'nomagic'
// Save value of no_hlsearch, jumping to a tag is not a real search
@@ -2866,21 +2864,26 @@ static int jumpto_tag(
* of the line. May need to correct that here. */
check_cursor();
} else {
- curwin->w_cursor.lnum = 1; /* start command in line 1 */
+ const int save_secure = secure;
+
+ // Setup the sandbox for executing the command from the tags file.
+ secure = 1;
+ sandbox++;
+ curwin->w_cursor.lnum = 1; // start command in line 1
do_cmdline_cmd((char *)pbuf);
retval = OK;
+
+ // When the command has done something that is not allowed make sure
+ // the error message can be seen.
+ if (secure == 2) {
+ wait_return(true);
+ }
+ secure = save_secure;
+ sandbox--;
}
- /*
- * When the command has done something that is not allowed make sure
- * the error message can be seen.
- */
- if (secure == 2)
- wait_return(TRUE);
- secure = save_secure;
p_magic = save_magic;
- --sandbox;
- /* restore no_hlsearch when keeping the old search pattern */
+ // restore no_hlsearch when keeping the old search pattern
if (search_options) {
set_no_hlsearch(save_no_hlsearch);
}
@@ -3059,24 +3062,26 @@ expand_tags (
)
{
int i;
- int c;
- int tagnmflag;
- char_u tagnm[100];
+ int extra_flag;
+ char_u *name_buf;
+ size_t name_buf_size = 100;
tagptrs_T t_p;
int ret;
- if (tagnames)
- tagnmflag = TAG_NAMES;
- else
- tagnmflag = 0;
+ name_buf = xmalloc(name_buf_size);
+
+ if (tagnames) {
+ extra_flag = TAG_NAMES;
+ } else {
+ extra_flag = 0;
+ }
if (pat[0] == '/') {
ret = find_tags(pat + 1, num_file, file,
- TAG_REGEXP | tagnmflag | TAG_VERBOSE | TAG_NO_TAGFUNC,
+ TAG_REGEXP | extra_flag | TAG_VERBOSE | TAG_NO_TAGFUNC,
TAG_MANY, curbuf->b_ffname);
} else {
ret = find_tags(pat, num_file, file,
- TAG_REGEXP | tagnmflag | TAG_VERBOSE
- | TAG_NO_TAGFUNC | TAG_NOIC,
+ TAG_REGEXP | extra_flag | TAG_VERBOSE | TAG_NO_TAGFUNC | TAG_NOIC,
TAG_MANY, curbuf->b_ffname);
}
if (ret == OK && !tagnames) {
@@ -3084,18 +3089,29 @@ expand_tags (
* "<tagname>\0<kind>\0<filename>\0"
*/
for (i = 0; i < *num_file; i++) {
+ size_t len;
+
parse_match((*file)[i], &t_p);
- c = (int)(t_p.tagname_end - t_p.tagname);
- memmove(tagnm, t_p.tagname, (size_t)c);
- tagnm[c++] = 0;
- tagnm[c++] = (t_p.tagkind != NULL && *t_p.tagkind)
- ? *t_p.tagkind : 'f';
- tagnm[c++] = 0;
- memmove((*file)[i] + c, t_p.fname, t_p.fname_end - t_p.fname);
- (*file)[i][c + (t_p.fname_end - t_p.fname)] = 0;
- memmove((*file)[i], tagnm, (size_t)c);
+ len = t_p.tagname_end - t_p.tagname;
+ if (len > name_buf_size - 3) {
+ char_u *buf;
+
+ name_buf_size = len + 3;
+ buf = xrealloc(name_buf, name_buf_size);
+ name_buf = buf;
+ }
+
+ memmove(name_buf, t_p.tagname, len);
+ name_buf[len++] = 0;
+ name_buf[len++] = (t_p.tagkind != NULL && *t_p.tagkind)
+ ? *t_p.tagkind : 'f';
+ name_buf[len++] = 0;
+ memmove((*file)[i] + len, t_p.fname, t_p.fname_end - t_p.fname);
+ (*file)[i][len + (t_p.fname_end - t_p.fname)] = 0;
+ memmove((*file)[i], name_buf, len);
}
}
+ xfree(name_buf);
return ret;
}
@@ -3291,7 +3307,7 @@ static void tagstack_clear(win_T *wp)
}
// Remove the oldest entry from the tag stack and shift the rest of
-// the entires to free up the top of the stack.
+// the entries to free up the top of the stack.
static void tagstack_shift(win_T *wp)
{
taggy_T *tagstack = wp->w_tagstack;
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index c07a956dde..3335fa500a 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -76,7 +76,6 @@
#include "nvim/event/time.h"
#include "nvim/os/input.h"
#include "nvim/api/private/helpers.h"
-#include "nvim/api/private/handle.h"
typedef struct terminal_state {
VimState state;
@@ -153,11 +152,10 @@ static VTermScreenCallbacks vterm_screen_callbacks = {
.sb_popline = term_sb_pop,
};
-static PMap(ptr_t) *invalidated_terminals;
+static PMap(ptr_t) invalidated_terminals = MAP_INIT;
void terminal_init(void)
{
- invalidated_terminals = pmap_new(ptr_t)();
time_watcher_init(&main_loop, &refresh_timer, NULL);
// refresh_timer_cb will redraw the screen which can call vimscript
refresh_timer.events = multiqueue_new_child(main_loop.events);
@@ -168,8 +166,10 @@ void terminal_teardown(void)
time_watcher_stop(&refresh_timer);
multiqueue_free(refresh_timer.events);
time_watcher_close(&refresh_timer, NULL);
- pmap_free(ptr_t)(invalidated_terminals);
- invalidated_terminals = NULL;
+ pmap_destroy(ptr_t)(&invalidated_terminals);
+ // terminal_destroy might be called after terminal_teardown is invoked
+ // make sure it is in an empty, valid state
+ pmap_init(ptr_t, &invalidated_terminals);
}
// public API {{{
@@ -260,7 +260,7 @@ Terminal *terminal_open(buf_T *buf, TerminalOptions opts)
return rv;
}
-void terminal_close(Terminal *term, char *msg)
+void terminal_close(Terminal *term, int status)
{
if (term->closed) {
return;
@@ -278,8 +278,8 @@ void terminal_close(Terminal *term, char *msg)
buf_T *buf = handle_get_buffer(term->buf_handle);
term->closed = true;
- if (!msg || exiting) {
- // If no msg was given, this was called by close_buffer(buffer.c). Or if
+ if (status == -1 || exiting) {
+ // If status is -1, this was called by close_buffer(buffer.c). Or if
// exiting, we must inform the buffer the terminal no longer exists so that
// close_buffer() doesn't call this again.
term->buf_handle = 0;
@@ -291,11 +291,16 @@ void terminal_close(Terminal *term, char *msg)
term->opts.close_cb(term->opts.data);
}
} else {
+ char msg[sizeof("\r\n[Process exited ]") + NUMBUFLEN];
+ snprintf(msg, sizeof msg, "\r\n[Process exited %d]", status);
terminal_receive(term, msg, strlen(msg));
}
- if (buf) {
+ if (buf && !is_autocmd_blocked()) {
+ dict_T *dict = get_vim_var_dict(VV_EVENT);
+ tv_dict_add_nr(dict, S_LEN("status"), status);
apply_autocmds(EVENT_TERMCLOSE, NULL, NULL, false, buf);
+ tv_dict_clear(dict);
}
}
@@ -521,14 +526,12 @@ void terminal_destroy(Terminal *term)
}
if (!term->refcount) {
- // might be destroyed after terminal_teardown is invoked
- if (invalidated_terminals
- && pmap_has(ptr_t)(invalidated_terminals, term)) {
+ if (pmap_has(ptr_t)(&invalidated_terminals, term)) {
// flush any pending changes to the buffer
block_autocmds();
refresh_terminal(term);
unblock_autocmds();
- pmap_del(ptr_t)(invalidated_terminals, term);
+ pmap_del(ptr_t)(&invalidated_terminals, term);
}
for (size_t i = 0; i < term->sb_current; i++) {
xfree(term->sb_buffer[i]);
@@ -865,7 +868,7 @@ static int term_sb_push(int cols, const VTermScreenCell *cells, void *data)
}
memcpy(sbrow->cells, cells, sizeof(cells[0]) * c);
- pmap_put(ptr_t)(invalidated_terminals, term, NULL);
+ pmap_put(ptr_t)(&invalidated_terminals, term, NULL);
return 1;
}
@@ -906,7 +909,7 @@ static int term_sb_pop(int cols, VTermScreenCell *cells, void *data)
}
xfree(sbrow);
- pmap_put(ptr_t)(invalidated_terminals, term, NULL);
+ pmap_put(ptr_t)(&invalidated_terminals, term, NULL);
return 1;
}
@@ -1208,7 +1211,7 @@ static void invalidate_terminal(Terminal *term, int start_row, int end_row)
term->invalid_end = MAX(term->invalid_end, end_row);
}
- pmap_put(ptr_t)(invalidated_terminals, term, NULL);
+ pmap_put(ptr_t)(&invalidated_terminals, term, NULL);
if (!refresh_pending) {
time_watcher_start(&refresh_timer, refresh_timer_cb, REFRESH_DELAY, 0);
refresh_pending = true;
@@ -1250,10 +1253,10 @@ static void refresh_timer_cb(TimeWatcher *watcher, void *data)
void *stub; (void)(stub);
// don't process autocommands while updating terminal buffers
block_autocmds();
- map_foreach(invalidated_terminals, term, stub, {
+ map_foreach(&invalidated_terminals, term, stub, {
refresh_terminal(term);
});
- pmap_clear(ptr_t)(invalidated_terminals);
+ pmap_clear(ptr_t)(&invalidated_terminals);
unblock_autocmds();
}
diff --git a/src/nvim/testdir/check.vim b/src/nvim/testdir/check.vim
index 7b06e53dd5..14bab33a2f 100644
--- a/src/nvim/testdir/check.vim
+++ b/src/nvim/testdir/check.vim
@@ -9,6 +9,17 @@ func CheckFeature(name)
endif
endfunc
+" Command to check for the absence of a feature.
+command -nargs=1 CheckNotFeature call CheckNotFeature(<f-args>)
+func CheckNotFeature(name)
+ if !has(a:name, 1)
+ throw 'Checking for non-existent feature ' .. a:name
+ endif
+ if has(a:name)
+ throw 'Skipped: ' .. a:name .. ' feature present'
+ endif
+endfunc
+
" Command to check for the presence of a working option.
command -nargs=1 CheckOption call CheckOption(<f-args>)
func CheckOption(name)
diff --git a/src/nvim/testdir/samples/memfile_test.c b/src/nvim/testdir/samples/memfile_test.c
index c71a5c8f40..7023064637 100644
--- a/src/nvim/testdir/samples/memfile_test.c
+++ b/src/nvim/testdir/samples/memfile_test.c
@@ -37,8 +37,8 @@ test_mf_hash(void)
mf_hashtab_T ht;
mf_hashitem_T *item;
blocknr_T key;
- long_u i;
- long_u num_buckets;
+ size_t i;
+ size_t num_buckets;
mf_hash_init(&ht);
diff --git a/src/nvim/testdir/sautest/autoload/foo.vim b/src/nvim/testdir/sautest/autoload/foo.vim
index d7dcd5ce3d..298e7275d8 100644
--- a/src/nvim/testdir/sautest/autoload/foo.vim
+++ b/src/nvim/testdir/sautest/autoload/foo.vim
@@ -5,3 +5,7 @@ let foo#bar = {}
func foo#bar.echo()
let g:called_foo_bar_echo += 1
endfunc
+
+func foo#addFoo(head)
+ return a:head .. 'foo'
+endfunc
diff --git a/src/nvim/testdir/setup.vim b/src/nvim/testdir/setup.vim
index fd9cfb54be..b3df8c63e6 100644
--- a/src/nvim/testdir/setup.vim
+++ b/src/nvim/testdir/setup.vim
@@ -12,6 +12,7 @@ set directory^=.
set fillchars=vert:\|,fold:-
set laststatus=1
set listchars=eol:$
+set joinspaces
set nohidden smarttab noautoindent noautoread complete-=i noruler noshowcmd
set nrformats+=octal
set shortmess-=F
@@ -20,7 +21,15 @@ set tags=./tags,tags
set undodir^=.
set wildoptions=
set startofline
-set sessionoptions&vi
+set sessionoptions+=options
+set viewoptions+=options
+set switchbuf=
+
+" Unmap Nvim default mappings.
+unmap Y
+unmap <C-L>
+iunmap <C-U>
+iunmap <C-W>
" Prevent Nvim log from writing to stderr.
let $NVIM_LOG_FILE = exists($NVIM_LOG_FILE) ? $NVIM_LOG_FILE : 'Xnvim.log'
diff --git a/src/nvim/testdir/test42.in b/src/nvim/testdir/test42.in
index d9057e72fb..456f9ddb07 100644
--- a/src/nvim/testdir/test42.in
+++ b/src/nvim/testdir/test42.in
Binary files differ
diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim
index b5c50b5894..cc767a9bcf 100644
--- a/src/nvim/testdir/test_alot.vim
+++ b/src/nvim/testdir/test_alot.vim
@@ -7,6 +7,7 @@ source test_cd.vim
source test_changedtick.vim
source test_compiler.vim
source test_cursor_func.vim
+source test_cursorline.vim
source test_ex_equal.vim
source test_ex_undo.vim
source test_ex_z.vim
diff --git a/src/nvim/testdir/test_arglist.vim b/src/nvim/testdir/test_arglist.vim
index a1ef8325ec..01d8f32893 100644
--- a/src/nvim/testdir/test_arglist.vim
+++ b/src/nvim/testdir/test_arglist.vim
@@ -90,8 +90,8 @@ func Test_argadd_empty_curbuf()
call assert_equal('', bufname('%'))
call assert_equal(1, line('$'))
rew
- call assert_notequal(curbuf, bufnr('%'))
- call assert_equal('Xargadd', bufname('%'))
+ call assert_notequal(curbuf, '%'->bufnr())
+ call assert_equal('Xargadd', '%'->bufname())
call assert_equal(2, line('$'))
%argd
diff --git a/src/nvim/testdir/test_assert.vim b/src/nvim/testdir/test_assert.vim
index 1d114221dc..52f243aaea 100644
--- a/src/nvim/testdir/test_assert.vim
+++ b/src/nvim/testdir/test_assert.vim
@@ -7,7 +7,7 @@ func Test_assert_equalfile()
let goodtext = ["one", "two", "three"]
call writefile(goodtext, 'Xone')
- call assert_equal(1, assert_equalfile('Xone', 'xyzxyz'))
+ call assert_equal(1, 'Xone'->assert_equalfile('xyzxyz'))
call assert_match("E485: Can't read file xyzxyz", v:errors[0])
call remove(v:errors, 0)
diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim
index ad28118f16..015979e1be 100644
--- a/src/nvim/testdir/test_autocmd.vim
+++ b/src/nvim/testdir/test_autocmd.vim
@@ -998,6 +998,7 @@ func Test_bufunload_all()
endfunc
au BufUnload * call UnloadAllBufs()
au VimLeave * call writefile(['Test Finished'], 'Xout')
+ set nohidden
edit Xxx1
split Xxx2
q
@@ -1955,7 +1956,7 @@ func Test_autocmd_sigusr1()
let g:sigusr1_passed = 0
au Signal SIGUSR1 let g:sigusr1_passed = 1
- call system('/bin/kill -s usr1 ' . getpid())
+ call system('kill -s usr1 ' . getpid())
call WaitForAssert({-> assert_true(g:sigusr1_passed)})
au! Signal
diff --git a/src/nvim/testdir/test_autoload.vim b/src/nvim/testdir/test_autoload.vim
index 7396c227c9..b8c4fa251f 100644
--- a/src/nvim/testdir/test_autoload.vim
+++ b/src/nvim/testdir/test_autoload.vim
@@ -8,6 +8,8 @@ func Test_autoload_dict_func()
call g:foo#bar.echo()
call assert_equal(1, g:loaded_foo_vim)
call assert_equal(1, g:called_foo_bar_echo)
+
+ eval 'bar'->g:foo#addFoo()->assert_equal('barfoo')
endfunc
func Test_source_autoload()
diff --git a/src/nvim/testdir/test_blob.vim b/src/nvim/testdir/test_blob.vim
new file mode 100644
index 0000000000..20758b0c0a
--- /dev/null
+++ b/src/nvim/testdir/test_blob.vim
@@ -0,0 +1,349 @@
+" Tests for the Blob types
+
+func TearDown()
+ " Run garbage collection after every test
+ call test_garbagecollect_now()
+endfunc
+
+" Tests for Blob type
+
+" Blob creation from constant
+func Test_blob_create()
+ let b = 0zDEADBEEF
+ call assert_equal(v:t_blob, type(b))
+ call assert_equal(4, len(b))
+ call assert_equal(0xDE, b[0])
+ call assert_equal(0xAD, b[1])
+ call assert_equal(0xBE, b[2])
+ call assert_equal(0xEF, b[3])
+ call assert_fails('let x = b[4]')
+
+ call assert_equal(0xDE, get(b, 0))
+ call assert_equal(0xEF, get(b, 3))
+
+ call assert_fails('let b = 0z1', 'E973:')
+ call assert_fails('let b = 0z1x', 'E973:')
+ call assert_fails('let b = 0z12345', 'E973:')
+
+ call assert_equal(0z, v:_null_blob)
+
+ let b = 0z001122.33445566.778899.aabbcc.dd
+ call assert_equal(0z00112233445566778899aabbccdd, b)
+ call assert_fails('let b = 0z1.1')
+ call assert_fails('let b = 0z.')
+ call assert_fails('let b = 0z001122.')
+ call assert_fails('call get("", 1)', 'E896:')
+ call assert_equal(0, len(v:_null_blob))
+endfunc
+
+" assignment to a blob
+func Test_blob_assign()
+ let b = 0zDEADBEEF
+ let b2 = b[1:2]
+ call assert_equal(0zADBE, b2)
+
+ let bcopy = b[:]
+ call assert_equal(b, bcopy)
+ call assert_false(b is bcopy)
+
+ let b = 0zDEADBEEF
+ let b2 = b
+ call assert_true(b is b2)
+ let b[:] = 0z11223344
+ call assert_equal(0z11223344, b)
+ call assert_equal(0z11223344, b2)
+ call assert_true(b is b2)
+
+ let b = 0zDEADBEEF
+ let b[3:] = 0z66
+ call assert_equal(0zDEADBE66, b)
+ let b[:1] = 0z8899
+ call assert_equal(0z8899BE66, b)
+
+ call assert_fails('let b[2:3] = 0z112233', 'E972:')
+ call assert_fails('let b[2:3] = 0z11', 'E972:')
+ call assert_fails('let b[3:2] = 0z', 'E979:')
+
+ let b = 0zDEADBEEF
+ let b += 0z99
+ call assert_equal(0zDEADBEEF99, b)
+
+ call assert_fails('let b .= 0z33', 'E734:')
+ call assert_fails('let b .= "xx"', 'E734:')
+ call assert_fails('let b += "xx"', 'E734:')
+ call assert_fails('let b[1:1] .= 0z55', 'E734:')
+
+ let l = [0z12]
+ let m = deepcopy(l)
+ let m[0] = 0z34 " E742 or E741 should not occur.
+endfunc
+
+func Test_blob_get_range()
+ let b = 0z0011223344
+ call assert_equal(0z2233, b[2:3])
+ call assert_equal(0z223344, b[2:-1])
+ call assert_equal(0z00, b[0:-5])
+ call assert_equal(0z, b[0:-11])
+ call assert_equal(0z44, b[-1:])
+ call assert_equal(0z0011223344, b[:])
+ call assert_equal(0z0011223344, b[:-1])
+ call assert_equal(0z, b[5:6])
+endfunc
+
+func Test_blob_get()
+ let b = 0z0011223344
+ call assert_equal(0x00, get(b, 0))
+ call assert_equal(0x22, get(b, 2, 999))
+ call assert_equal(0x44, get(b, 4))
+ call assert_equal(0x44, get(b, -1))
+ call assert_equal(-1, get(b, 5))
+ call assert_equal(999, get(b, 5, 999))
+ call assert_equal(-1, get(b, -8))
+ call assert_equal(999, get(b, -8, 999))
+ call assert_equal(10, get(v:_null_blob, 2, 10))
+
+ call assert_equal(0x00, b[0])
+ call assert_equal(0x22, b[2])
+ call assert_equal(0x44, b[4])
+ call assert_equal(0x44, b[-1])
+ call assert_fails('echo b[5]', 'E979:')
+ call assert_fails('echo b[-8]', 'E979:')
+endfunc
+
+func Test_blob_to_string()
+ let b = 0z00112233445566778899aabbccdd
+ call assert_equal('0z00112233.44556677.8899AABB.CCDD', string(b))
+ call assert_equal(b, eval(string(b)))
+ call remove(b, 4, -1)
+ call assert_equal('0z00112233', string(b))
+ call remove(b, 0, 3)
+ call assert_equal('0z', string(b))
+endfunc
+
+func Test_blob_compare()
+ let b1 = 0z0011
+ let b2 = 0z1100
+ let b3 = 0z001122
+ call assert_true(b1 == b1)
+ call assert_false(b1 == b2)
+ call assert_false(b1 == b3)
+ call assert_true(b1 != b2)
+ call assert_true(b1 != b3)
+ call assert_true(b1 == 0z0011)
+ call assert_fails('echo b1 == 9', 'E977:')
+ call assert_fails('echo b1 != 9', 'E977:')
+
+ call assert_false(b1 is b2)
+ let b2 = b1
+ call assert_true(b1 == b2)
+ call assert_true(b1 is b2)
+ let b2 = copy(b1)
+ call assert_true(b1 == b2)
+ call assert_false(b1 is b2)
+ let b2 = b1[:]
+ call assert_true(b1 == b2)
+ call assert_false(b1 is b2)
+
+ call assert_fails('let x = b1 > b2')
+ call assert_fails('let x = b1 < b2')
+ call assert_fails('let x = b1 - b2')
+ call assert_fails('let x = b1 / b2')
+ call assert_fails('let x = b1 * b2')
+endfunc
+
+" test for range assign
+func Test_blob_range_assign()
+ let b = 0z00
+ let b[1] = 0x11
+ let b[2] = 0x22
+ call assert_equal(0z001122, b)
+ call assert_fails('let b[4] = 0x33', 'E979:')
+endfunc
+
+func Test_blob_for_loop()
+ let blob = 0z00010203
+ let i = 0
+ for byte in blob
+ call assert_equal(i, byte)
+ let i += 1
+ endfor
+ call assert_equal(4, i)
+
+ let blob = 0z00
+ call remove(blob, 0)
+ call assert_equal(0, len(blob))
+ for byte in blob
+ call assert_error('loop over empty blob')
+ endfor
+
+ let blob = 0z0001020304
+ let i = 0
+ for byte in blob
+ call assert_equal(i, byte)
+ if i == 1
+ call remove(blob, 0)
+ elseif i == 3
+ call remove(blob, 3)
+ endif
+ let i += 1
+ endfor
+ call assert_equal(5, i)
+endfunc
+
+func Test_blob_concatenate()
+ let b = 0z0011
+ let b += 0z2233
+ call assert_equal(0z00112233, b)
+
+ call assert_fails('let b += "a"')
+ call assert_fails('let b += 88')
+
+ let b = 0zDEAD + 0zBEEF
+ call assert_equal(0zDEADBEEF, b)
+endfunc
+
+func Test_blob_add()
+ let b = 0z0011
+ call add(b, 0x22)
+ call assert_equal(0z001122, b)
+ call add(b, '51')
+ call assert_equal(0z00112233, b)
+
+ call assert_fails('call add(b, [9])', 'E745:')
+ call assert_fails('call add("", 0x01)', 'E897:')
+endfunc
+
+func Test_blob_empty()
+ call assert_false(empty(0z001122))
+ call assert_true(empty(0z))
+ call assert_true(empty(v:_null_blob))
+endfunc
+
+" Test removing items in blob
+func Test_blob_func_remove()
+ " Test removing 1 element
+ let b = 0zDEADBEEF
+ call assert_equal(0xDE, remove(b, 0))
+ call assert_equal(0zADBEEF, b)
+
+ let b = 0zDEADBEEF
+ call assert_equal(0xEF, remove(b, -1))
+ call assert_equal(0zDEADBE, b)
+
+ let b = 0zDEADBEEF
+ call assert_equal(0xAD, remove(b, 1))
+ call assert_equal(0zDEBEEF, b)
+
+ " Test removing range of element(s)
+ let b = 0zDEADBEEF
+ call assert_equal(0zBE, remove(b, 2, 2))
+ call assert_equal(0zDEADEF, b)
+
+ let b = 0zDEADBEEF
+ call assert_equal(0zADBE, remove(b, 1, 2))
+ call assert_equal(0zDEEF, b)
+
+ " Test invalid cases
+ let b = 0zDEADBEEF
+ call assert_fails("call remove(b, 5)", 'E979:')
+ call assert_fails("call remove(b, 1, 5)", 'E979:')
+ call assert_fails("call remove(b, 3, 2)", 'E979:')
+ call assert_fails("call remove(1, 0)", 'E896:')
+ call assert_fails("call remove(b, b)", 'E974:')
+ call assert_fails("call remove(v:_null_blob, 1, 2)", 'E979:')
+
+ " Translated from v8.2.3284
+ let b = 0zDEADBEEF
+ lockvar b
+ call assert_fails('call remove(b, 0)', 'E741:')
+ unlockvar b
+endfunc
+
+func Test_blob_read_write()
+ let b = 0zDEADBEEF
+ call writefile(b, 'Xblob')
+ let br = readfile('Xblob', 'B')
+ call assert_equal(b, br)
+ call delete('Xblob')
+
+ " This was crashing when calling readfile() with a directory.
+ call assert_fails("call readfile('.', 'B')", 'E17: "." is a directory')
+endfunc
+
+" filter() item in blob
+func Test_blob_filter()
+ call assert_equal(0z, filter(0zDEADBEEF, '0'))
+ call assert_equal(0zADBEEF, filter(0zDEADBEEF, 'v:val != 0xDE'))
+ call assert_equal(0zDEADEF, filter(0zDEADBEEF, 'v:val != 0xBE'))
+ call assert_equal(0zDEADBE, filter(0zDEADBEEF, 'v:val != 0xEF'))
+ call assert_equal(0zDEADBEEF, filter(0zDEADBEEF, '1'))
+ call assert_equal(0z01030103, filter(0z010203010203, 'v:val != 0x02'))
+ call assert_equal(0zADEF, filter(0zDEADBEEF, 'v:key % 2'))
+endfunc
+
+" map() item in blob
+func Test_blob_map()
+ call assert_equal(0zDFAEBFF0, map(0zDEADBEEF, 'v:val + 1'))
+ call assert_equal(0z00010203, map(0zDEADBEEF, 'v:key'))
+ call assert_equal(0zDEAEC0F2, map(0zDEADBEEF, 'v:key + v:val'))
+
+ call assert_fails("call map(0z00, '[9]')", 'E978:')
+endfunc
+
+func Test_blob_index()
+ call assert_equal(2, index(0zDEADBEEF, 0xBE))
+ call assert_equal(-1, index(0zDEADBEEF, 0))
+ call assert_equal(2, index(0z11111111, 0x11, 2))
+ call assert_equal(3, index(0z11110111, 0x11, 2))
+ call assert_equal(2, index(0z11111111, 0x11, -2))
+ call assert_equal(3, index(0z11110111, 0x11, -2))
+
+ call assert_fails('call index("asdf", 0)', 'E897:')
+endfunc
+
+func Test_blob_insert()
+ let b = 0zDEADBEEF
+ call insert(b, 0x33)
+ call assert_equal(0z33DEADBEEF, b)
+
+ let b = 0zDEADBEEF
+ call insert(b, 0x33, 2)
+ call assert_equal(0zDEAD33BEEF, b)
+
+ call assert_fails('call insert(b, -1)', 'E475:')
+ call assert_fails('call insert(b, 257)', 'E475:')
+ call assert_fails('call insert(b, 0, [9])', 'E745:')
+ call assert_equal(0, insert(v:_null_blob, 0x33))
+
+ " Translated from v8.2.3284
+ let b = 0zDEADBEEF
+ lockvar b
+ call assert_fails('call insert(b, 3)', 'E741:')
+ unlockvar b
+endfunc
+
+func Test_blob_reverse()
+ call assert_equal(0zEFBEADDE, reverse(0zDEADBEEF))
+ call assert_equal(0zBEADDE, reverse(0zDEADBE))
+ call assert_equal(0zADDE, reverse(0zDEAD))
+ call assert_equal(0zDE, reverse(0zDE))
+ call assert_equal(0z, reverse(v:_null_blob))
+endfunc
+
+func Test_blob_lock()
+ let b = 0z112233
+ lockvar b
+ call assert_fails('let b = 0z44', 'E741:')
+ unlockvar b
+ let b = 0z44
+endfunc
+
+func Test_blob_sort()
+ if has('float')
+ call assert_fails('call sort([1.0, 0z11], "f")', 'E975:')
+ else
+ call assert_fails('call sort(["abc", 0z11], "f")', 'E702:')
+ endif
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_breakindent.vim b/src/nvim/testdir/test_breakindent.vim
index ff5029b889..97b570e64f 100644
--- a/src/nvim/testdir/test_breakindent.vim
+++ b/src/nvim/testdir/test_breakindent.vim
@@ -16,6 +16,10 @@ func s:screen_lines(lnum, width) abort
return ScreenLines([a:lnum, a:lnum + 2], a:width)
endfunc
+func s:screen_lines2(lnums, lnume, width) abort
+ return ScreenLines([a:lnums, a:lnume], a:width)
+endfunc
+
func! s:compare_lines(expect, actual)
call assert_equal(join(a:expect, "\n"), join(a:actual, "\n"))
endfunc
@@ -63,7 +67,8 @@ endfunc
func Test_breakindent02()
" simple breakindent test with showbreak set
- call s:test_windows('setl briopt=min:0 sbr=>>')
+ set sbr=>>
+ call s:test_windows('setl briopt=min:0 sbr=')
let lines = s:screen_lines(line('.'),8)
let expect = [
\ " abcd",
@@ -123,7 +128,8 @@ endfunc
func Test_breakindent04()
" breakindent set with min width 18
- call s:test_windows('setl sbr= briopt=min:18')
+ set sbr=<<<
+ call s:test_windows('setl sbr=NONE briopt=min:18')
let lines = s:screen_lines(line('.'),8)
let expect = [
\ " abcd",
@@ -133,6 +139,7 @@ func Test_breakindent04()
call s:compare_lines(expect, lines)
" clean up
call s:close_windows('set sbr=')
+ set sbr=
endfunc
func Test_breakindent04_vartabs()
@@ -745,4 +752,141 @@ func Test_breakindent20_cpo_n_nextpage()
call s:close_windows('set breakindent& briopt& cpo& number&')
endfunc
+func Test_breakindent20_list()
+ call s:test_windows('setl breakindent breakindentopt= linebreak')
+ " default:
+ call setline(1, [' 1. Congress shall make no law',
+ \ ' 2.) Congress shall make no law',
+ \ ' 3.] Congress shall make no law'])
+ norm! 1gg
+ redraw!
+ let lines = s:screen_lines2(1, 6, 20)
+ let expect = [
+ \ " 1. Congress ",
+ \ "shall make no law ",
+ \ " 2.) Congress ",
+ \ "shall make no law ",
+ \ " 3.] Congress ",
+ \ "shall make no law ",
+ \ ]
+ call s:compare_lines(expect, lines)
+ " set mininum indent
+ setl briopt=min:5
+ redraw!
+ let lines = s:screen_lines2(1, 6, 20)
+ let expect = [
+ \ " 1. Congress ",
+ \ " shall make no law ",
+ \ " 2.) Congress ",
+ \ " shall make no law ",
+ \ " 3.] Congress ",
+ \ " shall make no law ",
+ \ ]
+ call s:compare_lines(expect, lines)
+ " set additional handing indent
+ setl briopt+=list:4
+ redraw!
+ let expect = [
+ \ " 1. Congress ",
+ \ " shall make no ",
+ \ " law ",
+ \ " 2.) Congress ",
+ \ " shall make no ",
+ \ " law ",
+ \ " 3.] Congress ",
+ \ " shall make no ",
+ \ " law ",
+ \ ]
+ let lines = s:screen_lines2(1, 9, 20)
+ call s:compare_lines(expect, lines)
+
+ " reset linebreak option
+ " Note: it indents by one additional
+ " space, because of the leading space.
+ setl linebreak&vim list listchars=eol:$,space:_
+ redraw!
+ let expect = [
+ \ "__1.__Congress_shall",
+ \ " _make_no_law$ ",
+ \ "__2.)_Congress_shall",
+ \ " _make_no_law$ ",
+ \ "__3.]_Congress_shall",
+ \ " _make_no_law$ ",
+ \ ]
+ let lines = s:screen_lines2(1, 6, 20)
+ call s:compare_lines(expect, lines)
+
+ " check formatlistpat indent
+ setl briopt=min:5,list:-1
+ setl linebreak list&vim listchars&vim
+ let &l:flp = '^\s*\d\+\.\?[\]:)}\t ]\s*'
+ redraw!
+ let expect = [
+ \ " 1. Congress ",
+ \ " shall make no ",
+ \ " law ",
+ \ " 2.) Congress ",
+ \ " shall make no ",
+ \ " law ",
+ \ " 3.] Congress ",
+ \ " shall make no ",
+ \ " law ",
+ \ ]
+ let lines = s:screen_lines2(1, 9, 20)
+ call s:compare_lines(expect, lines)
+ " check formatlistpat indent with different list levels
+ let &l:flp = '^\s*\*\+\s\+'
+ redraw!
+ %delete _
+ call setline(1, ['* Congress shall make no law',
+ \ '*** Congress shall make no law',
+ \ '**** Congress shall make no law'])
+ norm! 1gg
+ let expect = [
+ \ "* Congress shall ",
+ \ " make no law ",
+ \ "*** Congress shall ",
+ \ " make no law ",
+ \ "**** Congress shall ",
+ \ " make no law ",
+ \ ]
+ let lines = s:screen_lines2(1, 6, 20)
+ call s:compare_lines(expect, lines)
+
+ " check formatlistpat indent with different list level
+ " showbreak and sbr
+ setl briopt=min:5,sbr,list:-1,shift:2
+ setl showbreak=>
+ redraw!
+ let expect = [
+ \ "* Congress shall ",
+ \ "> make no law ",
+ \ "*** Congress shall ",
+ \ "> make no law ",
+ \ "**** Congress shall ",
+ \ "> make no law ",
+ \ ]
+ let lines = s:screen_lines2(1, 6, 20)
+ call s:compare_lines(expect, lines)
+ call s:close_windows('set breakindent& briopt& linebreak& list& listchars& showbreak&')
+endfunc
+
+" The following used to crash Vim. This is fixed by 8.2.3391.
+" This is a regression introduced by 8.2.2903.
+func Test_window_resize_with_linebreak()
+ new
+ 53vnew
+ set linebreak
+ set showbreak=>>
+ set breakindent
+ set breakindentopt=shift:4
+ call setline(1, "\naaaaaaaaa\n\na\naaaaa\n¯aaaaaaaaaa\naaaaaaaaaaaa\naaa\n\"a:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - aaaaaaaa\"\naaaaaaaa\n\"a")
+ redraw!
+ call assert_equal([" >>aa^@\"a: "], ScreenLines(2, 14))
+ vertical resize 52
+ redraw!
+ call assert_equal([" >>aaa^@\"a:"], ScreenLines(2, 14))
+ %bw!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_bufline.vim b/src/nvim/testdir/test_bufline.vim
index e038bce08e..b4e8a0bc71 100644
--- a/src/nvim/testdir/test_bufline.vim
+++ b/src/nvim/testdir/test_bufline.vim
@@ -102,7 +102,7 @@ func Test_deletebufline()
call assert_equal(0, deletebufline(b, 2, 8))
call assert_equal(['aaa'], getbufline(b, 1, 2))
exe "bd!" b
- call assert_equal(1, deletebufline(b, 1))
+ call assert_equal(1, b->deletebufline(1))
split Xtest
call setline(1, ['a', 'b', 'c'])
@@ -131,11 +131,11 @@ func Test_appendbufline_redraw()
endif
let lines =<< trim END
new foo
- let winnr=bufwinnr('foo')
- let buf=bufnr('foo')
+ let winnr = 'foo'->bufwinnr()
+ let buf = bufnr('foo')
wincmd p
call appendbufline(buf, '$', range(1,200))
- exe winnr. 'wincmd w'
+ exe winnr .. 'wincmd w'
norm! G
wincmd p
call deletebufline(buf, 1, '$')
diff --git a/src/nvim/testdir/test_bufwintabinfo.vim b/src/nvim/testdir/test_bufwintabinfo.vim
index cb7ab44798..4b5b55e6bf 100644
--- a/src/nvim/testdir/test_bufwintabinfo.vim
+++ b/src/nvim/testdir/test_bufwintabinfo.vim
@@ -18,7 +18,7 @@ function Test_getbufwintabinfo()
let l = getbufinfo('%')
call assert_equal(bufnr('%'), l[0].bufnr)
call assert_equal('vim', l[0].variables.editor)
- call assert_notequal(-1, index(l[0].windows, bufwinid('%')))
+ call assert_notequal(-1, index(l[0].windows, '%'->bufwinid()))
" Test for getbufinfo() with 'bufmodified'
call assert_equal(0, len(getbufinfo({'bufmodified' : 1})))
diff --git a/src/nvim/testdir/test_cd.vim b/src/nvim/testdir/test_cd.vim
index 770ed55b8d..02a23bf82f 100644
--- a/src/nvim/testdir/test_cd.vim
+++ b/src/nvim/testdir/test_cd.vim
@@ -1,4 +1,7 @@
-" Test for :cd
+" Test for :cd and chdir()
+
+source shared.vim
+source check.vim
func Test_cd_large_path()
" This used to crash with a heap write overflow.
@@ -65,3 +68,18 @@ func Test_cd_with_cpo_chdir()
set cpo&
bw!
endfunc
+
+func Test_cd_from_non_existing_dir()
+ CheckNotMSWindows
+
+ let saveddir = getcwd()
+ call mkdir('Xdeleted_dir')
+ cd Xdeleted_dir
+ call delete(saveddir .. '/Xdeleted_dir', 'd')
+
+ " Expect E187 as the current directory was deleted.
+ call assert_fails('pwd', 'E187:')
+ call assert_equal('', getcwd())
+ cd -
+ call assert_equal(saveddir, getcwd())
+endfunc
diff --git a/src/nvim/testdir/test_cindent.vim b/src/nvim/testdir/test_cindent.vim
index b6c2d1467e..562867f548 100644
--- a/src/nvim/testdir/test_cindent.vim
+++ b/src/nvim/testdir/test_cindent.vim
@@ -118,6 +118,16 @@ b = something();
bw!
endfunc
+func Test_cindent_func()
+ new
+ setlocal cindent
+ call setline(1, ['int main(void)', '{', 'return 0;', '}'])
+ call assert_equal(-1, cindent(0))
+ call assert_equal(&sw, 3->cindent())
+ call assert_equal(-1, cindent(line('$')+1))
+ bwipe!
+endfunc
+
" this was going beyond the end of the line.
func Test_cindent_case()
new
diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim
index 34126b49fa..5a6824b5c1 100644
--- a/src/nvim/testdir/test_cmdline.vim
+++ b/src/nvim/testdir/test_cmdline.vim
@@ -7,6 +7,10 @@ func Test_complete_tab()
call writefile(['testfile'], 'Xtestfile')
call feedkeys(":e Xtestf\t\r", "tx")
call assert_equal('testfile', getline(1))
+
+ " Pressing <Tab> after '%' completes the current file, also on MS-Windows
+ call feedkeys(":e %\t\r", "tx")
+ call assert_equal('e Xtestfile', @:)
call delete('Xtestfile')
endfunc
@@ -595,13 +599,26 @@ endfunc
func Test_cmdline_complete_user_func()
call feedkeys(":func Test_cmdline_complete_user\<Tab>\<Home>\"\<cr>", 'tx')
- call assert_match('"func Test_cmdline_complete_user', @:)
+ call assert_match('"func Test_cmdline_complete_user_', @:)
call feedkeys(":func s:ScriptL\<Tab>\<Home>\"\<cr>", 'tx')
call assert_match('"func <SNR>\d\+_ScriptLocalFunction', @:)
" g: prefix also works
call feedkeys(":echo g:Test_cmdline_complete_user_f\<Tab>\<Home>\"\<cr>", 'tx')
call assert_match('"echo g:Test_cmdline_complete_user_func', @:)
+
+ " using g: prefix does not result in just "g:" matches from a lambda
+ let Fx = { a -> a }
+ call feedkeys(":echo g:\<Tab>\<Home>\"\<cr>", 'tx')
+ call assert_match('"echo g:[A-Z]', @:)
+
+ " existence of script-local dict function does not break user function name
+ " completion
+ function s:a_dict_func() dict
+ endfunction
+ call feedkeys(":call Test_cmdline_complete_user\<Tab>\<Home>\"\<cr>", 'tx')
+ call assert_match('"call Test_cmdline_complete_user_', @:)
+ delfunction s:a_dict_func
endfunc
func Test_cmdline_complete_user_names()
diff --git a/src/nvim/testdir/test_command_count.vim b/src/nvim/testdir/test_command_count.vim
index 55b230373f..c7dddf4164 100644
--- a/src/nvim/testdir/test_command_count.vim
+++ b/src/nvim/testdir/test_command_count.vim
@@ -33,7 +33,7 @@ func Test_command_count_0()
delcommand RangeBuffers
delcommand RangeBuffersAll
- set hidden&
+ set nohidden
set swapfile&
endfunc
diff --git a/src/nvim/testdir/test_const.vim b/src/nvim/testdir/test_const.vim
index ea69c8cba4..0d064617a5 100644
--- a/src/nvim/testdir/test_const.vim
+++ b/src/nvim/testdir/test_const.vim
@@ -244,18 +244,33 @@ func Test_const_with_eval_name()
call assert_fails('const {s2} = "bar"', 'E995:')
endfunc
-func Test_lock_depth_is_1()
- const l = [1, 2, 3]
- const d = {'foo': 10}
-
- " Modify list - setting item is OK, adding/removing items not
- let l[0] = 42
+func Test_lock_depth_is_2()
+ " Modify list - error when changing item or adding/removing items
+ const l = [1, 2, [3, 4]]
+ call assert_fails('let l[0] = 42', 'E741:')
+ call assert_fails('let l[2][0] = 42', 'E741:')
call assert_fails('call add(l, 4)', 'E741:')
call assert_fails('unlet l[1]', 'E741:')
- " Modify dict - changing item is OK, adding/removing items not
- let d['foo'] = 'hello'
- let d.foo = 44
+ " Modify blob - error when changing
+ const b = 0z001122
+ call assert_fails('let b[0] = 42', 'E741:')
+
+ " Modify dict - error when changing item or adding/removing items
+ const d = {'foo': 10}
+ call assert_fails("let d['foo'] = 'hello'", 'E741:')
+ call assert_fails("let d.foo = 'hello'", 'E741:')
call assert_fails("let d['bar'] = 'hello'", 'E741:')
call assert_fails("unlet d['foo']", 'E741:')
+
+ " Modifying list or dict item contents is OK.
+ let lvar = ['a', 'b']
+ let bvar = 0z1122
+ const l2 = [0, lvar, bvar]
+ let l2[1][0] = 'c'
+ let l2[2][1] = 0x33
+ call assert_equal([0, ['c', 'b'], 0z1133], l2)
+
+ const d2 = #{a: 0, b: lvar, c: 4}
+ let d2.b[1] = 'd'
endfunc
diff --git a/src/nvim/testdir/test_cursorline.vim b/src/nvim/testdir/test_cursorline.vim
new file mode 100644
index 0000000000..39d8b901ed
--- /dev/null
+++ b/src/nvim/testdir/test_cursorline.vim
@@ -0,0 +1,271 @@
+" Test for cursorline and cursorlineopt
+
+source check.vim
+source screendump.vim
+
+function! s:screen_attr(lnum) abort
+ return map(range(1, 8), 'screenattr(a:lnum, v:val)')
+endfunction
+
+function! s:test_windows(h, w) abort
+ call NewWindow(a:h, a:w)
+endfunction
+
+function! s:close_windows() abort
+ call CloseWindow()
+endfunction
+
+function! s:new_hi() abort
+ redir => save_hi
+ silent! hi CursorLineNr
+ redir END
+ let save_hi = join(split(substitute(save_hi, '\s*xxx\s*', ' ', ''), "\n"), '')
+ exe 'hi' save_hi 'ctermbg=0 guibg=Black'
+ return save_hi
+endfunction
+
+func Test_cursorline_highlight1()
+ let save_hi = s:new_hi()
+ try
+ call s:test_windows(10, 20)
+ call setline(1, repeat(['aaaa'], 10))
+ redraw
+ let attr01 = s:screen_attr(1)
+ call assert_equal(repeat([attr01[0]], 8), attr01)
+
+ setl number numberwidth=4
+ redraw
+ let attr11 = s:screen_attr(1)
+ call assert_equal(repeat([attr11[0]], 4), attr11[0:3])
+ call assert_equal(repeat([attr11[4]], 4), attr11[4:7])
+ call assert_notequal(attr11[0], attr11[4])
+
+ setl cursorline
+ redraw
+ let attr21 = s:screen_attr(1)
+ let attr22 = s:screen_attr(2)
+ call assert_equal(repeat([attr21[0]], 4), attr21[0:3])
+ call assert_equal(repeat([attr21[4]], 4), attr21[4:7])
+ call assert_equal(attr11, attr22)
+ call assert_notequal(attr22, attr21)
+
+ setl nocursorline relativenumber
+ redraw
+ let attr31 = s:screen_attr(1)
+ call assert_equal(attr22[0:3], attr31[0:3])
+ call assert_equal(attr11[4:7], attr31[4:7])
+
+ call s:close_windows()
+ finally
+ exe 'hi' save_hi
+ endtry
+endfunc
+
+func Test_cursorline_highlight2()
+ CheckOption cursorlineopt
+
+ let save_hi = s:new_hi()
+ try
+ call s:test_windows(10, 20)
+ call setline(1, repeat(['aaaa'], 10))
+ redraw
+ let attr0 = s:screen_attr(1)
+ call assert_equal(repeat([attr0[0]], 8), attr0)
+
+ setl number
+ redraw
+ let attr1 = s:screen_attr(1)
+ call assert_notequal(attr0[0:3], attr1[0:3])
+ call assert_equal(attr0[0:3], attr1[4:7])
+
+ setl cursorline cursorlineopt=both
+ redraw
+ let attr2 = s:screen_attr(1)
+ call assert_notequal(attr1[0:3], attr2[0:3])
+ call assert_notequal(attr1[4:7], attr2[4:7])
+
+ setl cursorlineopt=line
+ redraw
+ let attr3 = s:screen_attr(1)
+ call assert_equal(attr1[0:3], attr3[0:3])
+ call assert_equal(attr2[4:7], attr3[4:7])
+
+ setl cursorlineopt=number
+ redraw
+ let attr4 = s:screen_attr(1)
+ call assert_equal(attr2[0:3], attr4[0:3])
+ call assert_equal(attr1[4:7], attr4[4:7])
+
+ setl nonumber
+ redraw
+ let attr5 = s:screen_attr(1)
+ call assert_equal(attr0, attr5)
+
+ call s:close_windows()
+ finally
+ exe 'hi' save_hi
+ endtry
+endfunc
+
+func Test_cursorline_screenline()
+ CheckScreendump
+ CheckOption cursorlineopt
+
+ let filename='Xcursorline'
+ let lines = []
+
+ let file_content =<< trim END
+ 1 foooooooo ar eins‍zwei drei vier fünf sechs sieben acht un zehn elf zwöfl dreizehn v ierzehn fünfzehn
+ 2 foooooooo bar eins zwei drei vier fünf sechs sieben
+ 3 foooooooo bar eins zwei drei vier fünf sechs sieben
+ 4 foooooooo bar eins zwei drei vier fünf sechs sieben
+ END
+ let lines1 =<< trim END1
+ set nocp
+ set display=lastline
+ set cursorlineopt=screenline cursorline nu wrap sbr=>
+ hi CursorLineNr ctermfg=blue
+ 25vsp
+ END1
+ let lines2 =<< trim END2
+ call cursor(1,1)
+ END2
+ call extend(lines, lines1)
+ call extend(lines, ["call append(0, ".. string(file_content).. ')'])
+ call extend(lines, lines2)
+ call writefile(lines, filename)
+ " basic test
+ let buf = RunVimInTerminal('-S '. filename, #{rows: 20})
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_'. filename. '_1', {})
+ call term_sendkeys(buf, "fagj")
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_'. filename. '_2', {})
+ call term_sendkeys(buf, "gj")
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_'. filename. '_3', {})
+ call term_sendkeys(buf, "gj")
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_'. filename. '_4', {})
+ call term_sendkeys(buf, "gj")
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_'. filename. '_5', {})
+ call term_sendkeys(buf, "gj")
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_'. filename. '_6', {})
+ " test with set list and cursorlineopt containing number
+ call term_sendkeys(buf, "gg0")
+ call term_sendkeys(buf, ":set list cursorlineopt+=number listchars=space:-\<cr>")
+ call VerifyScreenDump(buf, 'Test_'. filename. '_7', {})
+ call term_sendkeys(buf, "fagj")
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_'. filename. '_8', {})
+ call term_sendkeys(buf, "gj")
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_'. filename. '_9', {})
+ call term_sendkeys(buf, "gj")
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_'. filename. '_10', {})
+ call term_sendkeys(buf, "gj")
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_'. filename. '_11', {})
+ call term_sendkeys(buf, "gj")
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_'. filename. '_12', {})
+ if exists("+foldcolumn") && exists("+signcolumn") && exists("+breakindent")
+ " test with set foldcolumn signcoloumn and breakindent
+ call term_sendkeys(buf, "gg0")
+ call term_sendkeys(buf, ":set breakindent foldcolumn=2 signcolumn=yes\<cr>")
+ call VerifyScreenDump(buf, 'Test_'. filename. '_13', {})
+ call term_sendkeys(buf, "fagj")
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_'. filename. '_14', {})
+ call term_sendkeys(buf, "gj")
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_'. filename. '_15', {})
+ call term_sendkeys(buf, "gj")
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_'. filename. '_16', {})
+ call term_sendkeys(buf, "gj")
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_'. filename. '_17', {})
+ call term_sendkeys(buf, "gj")
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_'. filename. '_18', {})
+ call term_sendkeys(buf, ":set breakindent& foldcolumn& signcolumn&\<cr>")
+ endif
+ " showbreak should not be highlighted with CursorLine when 'number' is off
+ call term_sendkeys(buf, "gg0")
+ call term_sendkeys(buf, ":set list cursorlineopt=screenline listchars=space:-\<cr>")
+ call term_sendkeys(buf, ":set nonumber\<cr>")
+ call VerifyScreenDump(buf, 'Test_'. filename. '_19', {})
+ call term_sendkeys(buf, "fagj")
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_'. filename. '_20', {})
+ call term_sendkeys(buf, "gj")
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_'. filename. '_21', {})
+ call term_sendkeys(buf, "gj")
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_'. filename. '_22', {})
+ call term_sendkeys(buf, "gj")
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_'. filename. '_23', {})
+ call term_sendkeys(buf, "gj")
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_'. filename. '_24', {})
+ call term_sendkeys(buf, ":set list& cursorlineopt& listchars&\<cr>")
+
+ call StopVimInTerminal(buf)
+ call delete(filename)
+endfunc
+
+func Test_cursorline_redraw()
+ CheckScreendump
+ CheckOption cursorlineopt
+
+ let textlines =<< END
+ When the option is a list of flags, {value} must be
+ exactly as they appear in the option. Remove flags
+ one by one to avoid problems.
+ Also see |:set-args| above.
+
+The {option} arguments to ":set" may be repeated. For example: >
+ :set ai nosi sw=3 ts=3
+If you make an error in one of the arguments, an error message will be given
+and the following arguments will be ignored.
+
+ *:set-verbose*
+When 'verbose' is non-zero, displaying an option value will also tell where it
+was last set. Example: >
+ :verbose set shiftwidth cindent?
+< shiftwidth=4 ~
+ Last set from modeline line 1 ~
+ cindent ~
+ Last set from /usr/local/share/vim/vim60/ftplugin/c.vim line 30 ~
+This is only done when specific option values are requested, not for ":verbose
+set all" or ":verbose set" without an argument.
+When the option was set by hand there is no "Last set" message.
+When the option was set while executing a function, user command or
+END
+ call writefile(textlines, 'Xtextfile')
+
+ let script =<< trim END
+ set cursorline scrolloff=2
+ normal 12G
+ END
+ call writefile(script, 'Xscript')
+
+ let buf = RunVimInTerminal('-S Xscript Xtextfile', #{rows: 20, cols: 40})
+ call VerifyScreenDump(buf, 'Test_cursorline_redraw_1', {})
+ call term_sendkeys(buf, "zt")
+ call TermWait(buf)
+ call term_sendkeys(buf, "\<C-U>")
+ call VerifyScreenDump(buf, 'Test_cursorline_redraw_2', {})
+
+ call StopVimInTerminal(buf)
+ call delete('Xscript')
+ call delete('Xtextfile')
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_debugger.vim b/src/nvim/testdir/test_debugger.vim
index d1464e9d3b..a396efc09e 100644
--- a/src/nvim/testdir/test_debugger.vim
+++ b/src/nvim/testdir/test_debugger.vim
@@ -267,9 +267,7 @@ func Test_Debugger()
call RunDbgCmd(buf, 'breakd func a()', ['E475: Invalid argument: func a()'])
call RunDbgCmd(buf, 'breakd func a', ['E161: Breakpoint not found: func a'])
call RunDbgCmd(buf, 'breakd expr', ['E475: Invalid argument: expr'])
- call RunDbgCmd(buf, 'breakd expr x', [
- \ 'E121: Undefined variable: x',
- \ 'E161: Breakpoint not found: expr x'])
+ call RunDbgCmd(buf, 'breakd expr x', ['E161: Breakpoint not found: expr x'])
" finish the current function
call RunDbgCmd(buf, 'finish', [
@@ -314,9 +312,12 @@ func Test_Debugger()
call RunDbgCmd(buf, 'enew! | only!')
call StopVimInTerminal(buf)
+endfunc
+func Test_Debugger_breakadd()
" Tests for :breakadd file and :breakadd here
" Breakpoints should be set before sourcing the file
+ CheckRunVimInTerminal
let lines =<< trim END
let var1 = 10
@@ -337,6 +338,10 @@ func Test_Debugger()
call StopVimInTerminal(buf)
call delete('Xtest.vim')
+ %bw!
+
+ call assert_fails('breakadd here', 'E32:')
+ call assert_fails('breakadd file Xtest.vim /\)/', 'E55:')
endfunc
func Test_Backtrace_Through_Source()
diff --git a/src/nvim/testdir/test_diffmode.vim b/src/nvim/testdir/test_diffmode.vim
index 8592f48af7..32cee7ca56 100644
--- a/src/nvim/testdir/test_diffmode.vim
+++ b/src/nvim/testdir/test_diffmode.vim
@@ -540,7 +540,7 @@ func Test_diffopt_hiddenoff()
bwipe!
bwipe!
- set hidden& diffopt&
+ set nohidden diffopt&
endfunc
func Test_diffoff_hidden()
@@ -577,7 +577,7 @@ func Test_diffoff_hidden()
bwipe!
bwipe!
- set hidden& diffopt&
+ set nohidden diffopt&
endfunc
func Test_setting_cursor()
@@ -725,7 +725,7 @@ func Test_diff_filler()
diffthis
redraw
- call assert_equal([0, 0, 0, 0, 0, 0, 0, 1, 0], map(range(-1, 7), 'diff_filler(v:val)'))
+ call assert_equal([0, 0, 0, 0, 0, 0, 0, 1, 0], map(range(-1, 7), 'v:val->diff_filler()'))
wincmd w
call assert_equal([0, 0, 0, 0, 2, 0, 0, 0], map(range(-1, 6), 'diff_filler(v:val)'))
@@ -741,16 +741,16 @@ func Test_diff_hlID()
diffthis
redraw
- call assert_equal(synIDattr(diff_hlID(-1, 1), "name"), "")
+ call diff_hlID(-1, 1)->synIDattr("name")->assert_equal("")
call assert_equal(diff_hlID(1, 1), hlID("DiffChange"))
- call assert_equal(synIDattr(diff_hlID(1, 1), "name"), "DiffChange")
+ call diff_hlID(1, 1)->synIDattr("name")->assert_equal("DiffChange")
call assert_equal(diff_hlID(1, 2), hlID("DiffText"))
- call assert_equal(synIDattr(diff_hlID(1, 2), "name"), "DiffText")
- call assert_equal(synIDattr(diff_hlID(2, 1), "name"), "")
+ call diff_hlID(1, 2)->synIDattr("name")->assert_equal("DiffText")
+ call diff_hlID(2, 1)->synIDattr("name")->assert_equal("")
call assert_equal(diff_hlID(3, 1), hlID("DiffAdd"))
- call assert_equal(synIDattr(diff_hlID(3, 1), "name"), "DiffAdd")
- call assert_equal(synIDattr(diff_hlID(4, 1), "name"), "")
+ call diff_hlID(3, 1)->synIDattr("name")->assert_equal("DiffAdd")
+ call diff_hlID(4, 1)->synIDattr("name")->assert_equal("")
wincmd w
call assert_equal(diff_hlID(1, 1), hlID("DiffChange"))
@@ -965,6 +965,30 @@ func Test_diff_screen()
call delete('XdiffSetup')
endfunc
+func Test_diff_with_scroll_and_change()
+ CheckScreendump
+
+ let lines =<< trim END
+ call setline(1, range(1, 15))
+ vnew
+ call setline(1, range(9, 15))
+ windo diffthis
+ wincmd h
+ exe "normal Gl5\<C-E>"
+ END
+ call writefile(lines, 'Xtest_scroll_change')
+ let buf = RunVimInTerminal('-S Xtest_scroll_change', {})
+
+ call VerifyScreenDump(buf, 'Test_diff_scroll_change_01', {})
+
+ call term_sendkeys(buf, "ax\<Esc>")
+ call VerifyScreenDump(buf, 'Test_diff_scroll_change_02', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xtest_scroll_change')
+endfunc
+
func Test_diff_with_cursorline()
CheckScreendump
@@ -990,6 +1014,37 @@ func Test_diff_with_cursorline()
call delete('Xtest_diff_cursorline')
endfunc
+func Test_diff_with_cursorline_breakindent()
+ CheckScreendump
+
+ call writefile([
+ \ 'hi CursorLine ctermbg=red ctermfg=white',
+ \ 'set noequalalways wrap diffopt=followwrap cursorline breakindent',
+ \ '50vnew',
+ \ 'call setline(1, [" "," "," "," "])',
+ \ 'exe "norm 20Afoo\<Esc>j20Afoo\<Esc>j20Afoo\<Esc>j20Abar\<Esc>"',
+ \ 'vnew',
+ \ 'call setline(1, [" "," "," "," "])',
+ \ 'exe "norm 20Abee\<Esc>j20Afoo\<Esc>j20Afoo\<Esc>j20Abaz\<Esc>"',
+ \ 'windo diffthis',
+ \ '2wincmd w',
+ \ ], 'Xtest_diff_cursorline_breakindent')
+ let buf = RunVimInTerminal('-S Xtest_diff_cursorline_breakindent', {})
+
+ call term_sendkeys(buf, "gg0")
+ call VerifyScreenDump(buf, 'Test_diff_with_cul_bri_01', {})
+ call term_sendkeys(buf, "j")
+ call VerifyScreenDump(buf, 'Test_diff_with_cul_bri_02', {})
+ call term_sendkeys(buf, "j")
+ call VerifyScreenDump(buf, 'Test_diff_with_cul_bri_03', {})
+ call term_sendkeys(buf, "j")
+ call VerifyScreenDump(buf, 'Test_diff_with_cul_bri_04', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xtest_diff_cursorline_breakindent')
+endfunc
+
func Test_diff_with_syntax()
CheckScreendump
diff --git a/src/nvim/testdir/test_display.vim b/src/nvim/testdir/test_display.vim
index c702b44b88..12327f34d6 100644
--- a/src/nvim/testdir/test_display.vim
+++ b/src/nvim/testdir/test_display.vim
@@ -262,3 +262,21 @@ func Test_display_scroll_at_topline()
call StopVimInTerminal(buf)
endfunc
+
+func Test_display_linebreak_breakat()
+ new
+ vert resize 25
+ let _breakat = &breakat
+ setl signcolumn=yes linebreak breakat=) showbreak=+\
+ call setline(1, repeat('x', winwidth(0) - 2) .. ')abc')
+ let lines = ScreenLines([1, 2], 25)
+ let expected = [
+ \ ' xxxxxxxxxxxxxxxxxxxxxxx',
+ \ ' + )abc '
+ \ ]
+ call assert_equal(expected, lines)
+ %bw!
+ let &breakat=_breakat
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_eval_stuff.vim b/src/nvim/testdir/test_eval_stuff.vim
index 4870b9a60a..883ba5de3d 100644
--- a/src/nvim/testdir/test_eval_stuff.vim
+++ b/src/nvim/testdir/test_eval_stuff.vim
@@ -12,25 +12,18 @@ func Test_catch_return_with_error()
call assert_equal(1, s:foo())
endfunc
-func Test_E963()
- " These commands used to cause an internal error prior to vim 8.1.0563
- let v_e = v:errors
- let v_o = v:oldfiles
- call assert_fails("let v:errors=''", 'E963:')
- call assert_equal(v_e, v:errors)
- call assert_fails("let v:oldfiles=''", 'E963:')
- call assert_equal(v_o, v:oldfiles)
-endfunc
-
-func Test_for_invalid()
- call assert_fails("for x in 99", 'E714:')
- call assert_fails("for x in function('winnr')", 'E714:')
- call assert_fails("for x in {'a': 9}", 'E714:')
-
- if 0
- /1/5/2/s/\n
- endif
- redraw
+func Test_nocatch_restore_silent_emsg()
+ silent! try
+ throw 1
+ catch
+ endtry
+ echoerr 'wrong'
+ let c1 = nr2char(screenchar(&lines, 1))
+ let c2 = nr2char(screenchar(&lines, 2))
+ let c3 = nr2char(screenchar(&lines, 3))
+ let c4 = nr2char(screenchar(&lines, 4))
+ let c5 = nr2char(screenchar(&lines, 5))
+ call assert_equal('wrong', c1 . c2 . c3 . c4 . c5)
endfunc
func Test_mkdir_p()
@@ -61,6 +54,54 @@ func Test_line_continuation()
call assert_equal([5, 6], array)
endfunc
+func Test_E963()
+ " These commands used to cause an internal error prior to vim 8.1.0563
+ let v_e = v:errors
+ let v_o = v:oldfiles
+ call assert_fails("let v:errors=''", 'E963:')
+ call assert_equal(v_e, v:errors)
+ call assert_fails("let v:oldfiles=''", 'E963:')
+ call assert_equal(v_o, v:oldfiles)
+endfunc
+
+func Test_for_invalid()
+ " Vim gives incorrect emsg here until v8.2.3284, but the exact emsg from that
+ " patch cannot be used until v8.2.2658 is ported (for loop over Strings)
+ call assert_fails("for x in 99", 'E897:')
+ call assert_fails("for x in function('winnr')", 'E897:')
+ call assert_fails("for x in {'a': 9}", 'E897:')
+
+ if 0
+ /1/5/2/s/\n
+ endif
+ redraw
+endfunc
+
+func Test_readfile_binary()
+ new
+ call setline(1, ['one', 'two', 'three'])
+ setlocal ff=dos
+ silent write XReadfile
+ let lines = readfile('XReadfile')
+ call assert_equal(['one', 'two', 'three'], lines)
+ let lines = readfile('XReadfile', '', 2)
+ call assert_equal(['one', 'two'], lines)
+ let lines = readfile('XReadfile', 'b')
+ call assert_equal(["one\r", "two\r", "three\r", ""], lines)
+ let lines = readfile('XReadfile', 'b', 2)
+ call assert_equal(["one\r", "two\r"], lines)
+
+ bwipe!
+ call delete('XReadfile')
+endfunc
+
+func Test_let_errmsg()
+ call assert_fails('let v:errmsg = []', 'E730:')
+ let v:errmsg = ''
+ call assert_fails('let v:errmsg = []', 'E730:')
+ let v:errmsg = ''
+endfunc
+
func Test_string_concatenation()
call assert_equal('ab', 'a'.'b')
call assert_equal('ab', 'a' .'b')
@@ -90,27 +131,6 @@ func Test_string_concatenation()
call assert_equal('ab', a)
endfunc
-func Test_nocatch_restore_silent_emsg()
- silent! try
- throw 1
- catch
- endtry
- echoerr 'wrong'
- let c1 = nr2char(screenchar(&lines, 1))
- let c2 = nr2char(screenchar(&lines, 2))
- let c3 = nr2char(screenchar(&lines, 3))
- let c4 = nr2char(screenchar(&lines, 4))
- let c5 = nr2char(screenchar(&lines, 5))
- call assert_equal('wrong', c1 . c2 . c3 . c4 . c5)
-endfunc
-
-func Test_let_errmsg()
- call assert_fails('let v:errmsg = []', 'E730:')
- let v:errmsg = ''
- call assert_fails('let v:errmsg = []', 'E730:')
- let v:errmsg = ''
-endfunc
-
" Test fix for issue #4507
func Test_skip_after_throw()
try
@@ -120,6 +140,31 @@ func Test_skip_after_throw()
endtry
endfunc
+" scriptversion 1
+func Test_string_concat_scriptversion1()
+ call assert_true(has('vimscript-1'))
+ let a = 'a'
+ let b = 'b'
+
+ echo a . b
+ let a .= b
+ let vers = 1.2.3
+ call assert_equal('123', vers)
+
+ if has('float')
+ call assert_fails('let f = .5', 'E15:')
+ endif
+endfunc
+
+" scriptversion 1
+func Test_vvar_scriptversion1()
+ call assert_equal(15, 017)
+ call assert_equal(15, 0o17)
+ call assert_equal(15, 0O17)
+ call assert_equal(18, 018)
+ call assert_equal(511, 0o777)
+endfunc
+
func Test_number_max_min_size()
" This will fail on systems without 64 bit number support or when not
" configured correctly.
@@ -129,6 +174,132 @@ func Test_number_max_min_size()
call assert_true(v:numbermax > 9999999)
endfunc
+func Assert_reg(name, type, value, valuestr, expr, exprstr)
+ call assert_equal(a:type, getregtype(a:name))
+ call assert_equal(a:value, getreg(a:name))
+ call assert_equal(a:valuestr, string(getreg(a:name, 0, 1)))
+ call assert_equal(a:expr, getreg(a:name, 1))
+ call assert_equal(a:exprstr, string(getreg(a:name, 1, 1)))
+endfunc
+
+func Test_let_register()
+ let @" = 'abc'
+ call Assert_reg('"', 'v', "abc", "['abc']", "abc", "['abc']")
+ let @" = "abc\n"
+ call Assert_reg('"', 'V', "abc\n", "['abc']", "abc\n", "['abc']")
+ let @" = "abc\<C-m>"
+ call Assert_reg('"', 'V', "abc\r\n", "['abc\r']", "abc\r\n", "['abc\r']")
+ let @= = '"abc"'
+ call Assert_reg('=', 'v', "abc", "['abc']", '"abc"', "['\"abc\"']")
+endfunc
+
+func Assert_regput(name, result)
+ new
+ execute "silent normal! o==\n==\e\"" . a:name . "P"
+ call assert_equal(a:result, getline(2, line('$')))
+ bwipe!
+endfunc
+
+func Test_setreg_basic()
+ call setreg('a', 'abcA', 'c')
+ call Assert_reg('a', 'v', "abcA", "['abcA']", "abcA", "['abcA']")
+ call Assert_regput('a', ['==', '=abcA='])
+
+ call setreg('A', 'abcAc', 'c')
+ call Assert_reg('A', 'v', "abcAabcAc", "['abcAabcAc']", "abcAabcAc", "['abcAabcAc']")
+ call Assert_regput('a', ['==', '=abcAabcAc='])
+
+ call setreg('A', 'abcAl', 'l')
+ call Assert_reg('A', 'V', "abcAabcAcabcAl\n", "['abcAabcAcabcAl']", "abcAabcAcabcAl\n", "['abcAabcAcabcAl']")
+ call Assert_regput('a', ['==', 'abcAabcAcabcAl', '=='])
+
+ call setreg('A', 'abcAc2','c')
+ call Assert_reg('A', 'v', "abcAabcAcabcAl\nabcAc2", "['abcAabcAcabcAl', 'abcAc2']", "abcAabcAcabcAl\nabcAc2", "['abcAabcAcabcAl', 'abcAc2']")
+ call Assert_regput('a', ['==', '=abcAabcAcabcAl', 'abcAc2='])
+
+ call setreg('b', 'abcB', 'v')
+ call Assert_reg('b', 'v', "abcB", "['abcB']", "abcB", "['abcB']")
+ call Assert_regput('b', ['==', '=abcB='])
+
+ call setreg('b', 'abcBc', 'ca')
+ call Assert_reg('b', 'v', "abcBabcBc", "['abcBabcBc']", "abcBabcBc", "['abcBabcBc']")
+ call Assert_regput('b', ['==', '=abcBabcBc='])
+
+ call setreg('b', 'abcBb', 'ba')
+ call Assert_reg('b', "\<C-V>5", "abcBabcBcabcBb", "['abcBabcBcabcBb']", "abcBabcBcabcBb", "['abcBabcBcabcBb']")
+ call Assert_regput('b', ['==', '=abcBabcBcabcBb='])
+
+ call setreg('b', 'abcBc2','ca')
+ call Assert_reg('b', "v", "abcBabcBcabcBb\nabcBc2", "['abcBabcBcabcBb', 'abcBc2']", "abcBabcBcabcBb\nabcBc2", "['abcBabcBcabcBb', 'abcBc2']")
+ call Assert_regput('b', ['==', '=abcBabcBcabcBb', 'abcBc2='])
+
+ call setreg('b', 'abcBb2','b50a')
+ call Assert_reg('b', "\<C-V>50", "abcBabcBcabcBb\nabcBc2abcBb2", "['abcBabcBcabcBb', 'abcBc2abcBb2']", "abcBabcBcabcBb\nabcBc2abcBb2", "['abcBabcBcabcBb', 'abcBc2abcBb2']")
+ call Assert_regput('b', ['==', '=abcBabcBcabcBb =', ' abcBc2abcBb2'])
+
+ call setreg('c', 'abcC', 'l')
+ call Assert_reg('c', 'V', "abcC\n", "['abcC']", "abcC\n", "['abcC']")
+ call Assert_regput('c', ['==', 'abcC', '=='])
+
+ call setreg('C', 'abcCl', 'l')
+ call Assert_reg('C', 'V', "abcC\nabcCl\n", "['abcC', 'abcCl']", "abcC\nabcCl\n", "['abcC', 'abcCl']")
+ call Assert_regput('c', ['==', 'abcC', 'abcCl', '=='])
+
+ call setreg('C', 'abcCc', 'c')
+ call Assert_reg('C', 'v', "abcC\nabcCl\nabcCc", "['abcC', 'abcCl', 'abcCc']", "abcC\nabcCl\nabcCc", "['abcC', 'abcCl', 'abcCc']")
+ call Assert_regput('c', ['==', '=abcC', 'abcCl', 'abcCc='])
+
+ call setreg('d', 'abcD', 'V')
+ call Assert_reg('d', 'V', "abcD\n", "['abcD']", "abcD\n", "['abcD']")
+ call Assert_regput('d', ['==', 'abcD', '=='])
+
+ call setreg('D', 'abcDb', 'b')
+ call Assert_reg('d', "\<C-V>5", "abcD\nabcDb", "['abcD', 'abcDb']", "abcD\nabcDb", "['abcD', 'abcDb']")
+ call Assert_regput('d', ['==', '=abcD =', ' abcDb'])
+
+ call setreg('e', 'abcE', 'b')
+ call Assert_reg('e', "\<C-V>4", "abcE", "['abcE']", "abcE", "['abcE']")
+ call Assert_regput('e', ['==', '=abcE='])
+
+ call setreg('E', 'abcEb', 'b')
+ call Assert_reg('E', "\<C-V>5", "abcE\nabcEb", "['abcE', 'abcEb']", "abcE\nabcEb", "['abcE', 'abcEb']")
+ call Assert_regput('e', ['==', '=abcE =', ' abcEb'])
+
+ call setreg('E', 'abcEl', 'l')
+ call Assert_reg('E', "V", "abcE\nabcEb\nabcEl\n", "['abcE', 'abcEb', 'abcEl']", "abcE\nabcEb\nabcEl\n", "['abcE', 'abcEb', 'abcEl']")
+ call Assert_regput('e', ['==', 'abcE', 'abcEb', 'abcEl', '=='])
+
+ call setreg('f', 'abcF', "\<C-v>")
+ call Assert_reg('f', "\<C-V>4", "abcF", "['abcF']", "abcF", "['abcF']")
+ call Assert_regput('f', ['==', '=abcF='])
+
+ call setreg('F', 'abcFc', 'c')
+ call Assert_reg('F', "v", "abcF\nabcFc", "['abcF', 'abcFc']", "abcF\nabcFc", "['abcF', 'abcFc']")
+ call Assert_regput('f', ['==', '=abcF', 'abcFc='])
+
+ call setreg('g', 'abcG', 'b10')
+ call Assert_reg('g', "\<C-V>10", "abcG", "['abcG']", "abcG", "['abcG']")
+ call Assert_regput('g', ['==', '=abcG ='])
+
+ call setreg('h', 'abcH', "\<C-v>10")
+ call Assert_reg('h', "\<C-V>10", "abcH", "['abcH']", "abcH", "['abcH']")
+ call Assert_regput('h', ['==', '=abcH ='])
+
+ call setreg('I', 'abcI')
+ call Assert_reg('I', "v", "abcI", "['abcI']", "abcI", "['abcI']")
+ call Assert_regput('I', ['==', '=abcI='])
+
+ " Error cases
+ call assert_fails('call setreg()', 'E119:')
+ call assert_fails('call setreg(1)', 'E119:')
+ call assert_fails('call setreg(1, 2, 3, 4)', 'E118:')
+ call assert_fails('call setreg([], 2)', 'E730:')
+ call assert_fails('call setreg(1, 2, [])', 'E730:')
+ call assert_fails('call setreg("/", ["1", "2"])', 'E883:')
+ call assert_fails('call setreg("=", ["1", "2"])', 'E883:')
+ call assert_fails('call setreg(1, ["", "", [], ""])', 'E730:')
+endfunc
+
func Test_curly_assignment()
let s:svar = 'svar'
let g:gvar = 'gvar'
diff --git a/src/nvim/testdir/test_ex_z.vim b/src/nvim/testdir/test_ex_z.vim
index 608a36c490..481747ce84 100644
--- a/src/nvim/testdir/test_ex_z.vim
+++ b/src/nvim/testdir/test_ex_z.vim
@@ -16,8 +16,9 @@ func Test_z()
call assert_equal(23, line('.'))
let a = execute('20z+3')
- " FIXME: I would expect the same result as '20z3' but it
- " gives "\n21\n22\n23" instead. Bug in Vim or in ":help :z"?
+ " FIXME: I would expect the same result as '20z3' since 'help z'
+ " says: Specifying no mark at all is the same as "+".
+ " However it " gives "\n21\n22\n23" instead. Bug in Vim or in ":help :z"?
"call assert_equal("\n20\n21\n22", a)
"call assert_equal(22, line('.'))
@@ -55,19 +56,48 @@ func Test_z()
call assert_equal(100, line('.'))
let a = execute('20z-1000')
- call assert_match("^\n1\n2\n.*\n19\n20$", a)
call assert_equal(20, line('.'))
let a = execute('20z=1000')
call assert_match("^\n1\n.*\n-\\+\n20\n-\\\+\n.*\n100$", a)
call assert_equal(20, line('.'))
+ " Tests with multiple windows.
+ 5split
+ call setline(1, range(1, 100))
+ " Without a count, the number line is window height - 3.
+ let a = execute('20z')
+ call assert_equal("\n20\n21", a)
+ call assert_equal(21, line('.'))
+ " If window height - 3 is less than 1, it should be clamped to 1.
+ resize 2
+ let a = execute('20z')
+ call assert_equal("\n20", a)
+ call assert_equal(20, line('.'))
+
call assert_fails('20z=a', 'E144:')
set window& scroll&
bw!
endfunc
+" :z! is the same as :z but count uses the Vim window height when not specified.
+func Test_z_bang()
+ 4split
+ call setline(1, range(1, 20))
+
+ let a = execute('10z!')
+ call assert_equal("\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20", a)
+
+ let a = execute('10z!#')
+ call assert_equal("\n 10 10\n 11 11\n 12 12\n 13 13\n 14 14\n 15 15\n 16 16\n 17 17\n 18 18\n 19 19\n 20 20", a)
+
+ let a = execute('10z!3')
+ call assert_equal("\n10\n11\n12", a)
+
+ %bwipe!
+endfunc
+
func Test_z_bug()
" This used to access invalid memory as a result of an integer overflow
" and freeze vim.
diff --git a/src/nvim/testdir/test_excmd.vim b/src/nvim/testdir/test_excmd.vim
index ed2bb2c06b..2d01cbba83 100644
--- a/src/nvim/testdir/test_excmd.vim
+++ b/src/nvim/testdir/test_excmd.vim
@@ -313,6 +313,42 @@ func Test_confirm_write_ro()
call delete('Xconfirm_write_ro')
endfunc
+func Test_confirm_write_partial_file()
+ CheckNotGui
+ CheckRunVimInTerminal
+
+ call writefile(['a', 'b', 'c', 'd'], 'Xwrite_partial')
+ call writefile(['set nobackup ff=unix cmdheight=2',
+ \ 'edit Xwrite_partial'], 'Xscript')
+ let buf = RunVimInTerminal('-S Xscript', {'rows': 20})
+
+ call term_sendkeys(buf, ":confirm 2,3w\n")
+ call WaitForAssert({-> assert_match('^Write partial file? *$',
+ \ term_getline(buf, 19))}, 1000)
+ call WaitForAssert({-> assert_match('^(Y)es, \[N\]o: *$',
+ \ term_getline(buf, 20))}, 1000)
+ call term_sendkeys(buf, 'N')
+ call WaitForAssert({-> assert_match('.* All$', term_getline(buf, 20))}, 1000)
+ call assert_equal(['a', 'b', 'c', 'd'], readfile('Xwrite_partial'))
+ call delete('Xwrite_partial')
+
+ call term_sendkeys(buf, ":confirm 2,3w\n")
+ call WaitForAssert({-> assert_match('^Write partial file? *$',
+ \ term_getline(buf, 19))}, 1000)
+ call WaitForAssert({-> assert_match('^(Y)es, \[N\]o: *$',
+ \ term_getline(buf, 20))}, 1000)
+ call term_sendkeys(buf, 'Y')
+ call WaitForAssert({-> assert_match('^"Xwrite_partial" \[New\] 2L, 4B written *$',
+ \ term_getline(buf, 19))}, 1000)
+ call WaitForAssert({-> assert_match('^Press ENTER or type command to continue *$',
+ \ term_getline(buf, 20))}, 1000)
+ call assert_equal(['b', 'c'], readfile('Xwrite_partial'))
+
+ call StopVimInTerminal(buf)
+ call delete('Xwrite_partial')
+ call delete('Xscript')
+endfunc
+
" Test for the :winsize command
func Test_winsize_cmd()
call assert_fails('winsize 1', 'E465:')
diff --git a/src/nvim/testdir/test_expr.vim b/src/nvim/testdir/test_expr.vim
index 0b41a1127a..c49285621a 100644
--- a/src/nvim/testdir/test_expr.vim
+++ b/src/nvim/testdir/test_expr.vim
@@ -502,6 +502,17 @@ func Test_empty_concatenate()
call assert_equal('b', 'b' . 'a'[4:0])
endfunc
+func Test_broken_number()
+ let X = 'bad'
+ call assert_fails('echo 1X', 'E15:')
+ call assert_fails('echo 0b1X', 'E15:')
+ call assert_fails('echo 0b12', 'E15:')
+ call assert_fails('echo 0x1X', 'E15:')
+ call assert_fails('echo 011X', 'E15:')
+ call assert_equal(2, str2nr('2a'))
+ call assert_fails('inoremap <Char-0b1z> b', 'E474:')
+endfunc
+
func Test_eval_after_if()
let s:val = ''
func SetVal(x)
diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim
index eb6151fbe1..cc789cb6bd 100644
--- a/src/nvim/testdir/test_filetype.vim
+++ b/src/nvim/testdir/test_filetype.vim
@@ -151,7 +151,6 @@ let s:filename_checks = {
\ 'dosini': ['.editorconfig', '/etc/pacman.conf', '/etc/yum.conf', 'file.ini', 'npmrc', '.npmrc', 'php.ini', 'php.ini-5', 'php.ini-file', '/etc/yum.repos.d/file', 'any/etc/pacman.conf', 'any/etc/yum.conf', 'any/etc/yum.repos.d/file', 'file.wrap'],
\ 'dot': ['file.dot', 'file.gv'],
\ 'dracula': ['file.drac', 'file.drc', 'filelvs', 'filelpe', 'drac.file', 'lpe', 'lvs', 'some-lpe', 'some-lvs'],
- \ 'dsl': ['file.dsl'],
\ 'dtd': ['file.dtd'],
\ 'dts': ['file.dts', 'file.dtsi'],
\ 'dune': ['jbuild', 'dune', 'dune-project', 'dune-workspace'],
@@ -192,6 +191,7 @@ let s:filename_checks = {
\ 'gdb': ['.gdbinit'],
\ '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'],
\ 'gitcommit': ['COMMIT_EDITMSG', 'MERGE_MSG', 'TAG_EDITMSG'],
\ 'gitconfig': ['file.git/config', '.gitconfig', '.gitmodules', 'file.git/modules//config', '/.config/git/config', '/etc/gitconfig', '/etc/gitconfig.d/file', '/.gitconfig.d/file', 'any/.config/git/config', 'any/.gitconfig.d/file', 'some.git/config', 'some.git/modules/any/config'],
@@ -260,7 +260,9 @@ let s:filename_checks = {
\ 'jovial': ['file.jov', 'file.j73', 'file.jovial'],
\ 'jproperties': ['file.properties', 'file.properties_xx', 'file.properties_xx_xx', 'some.properties_xx_xx_file'],
\ 'json': ['file.json', 'file.jsonp', 'file.json-patch', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb'],
+ \ 'jsonc': ['file.jsonc'],
\ 'jsp': ['file.jsp'],
+ \ 'julia': ['file.jl'],
\ 'kconfig': ['Kconfig', 'Kconfig.debug', 'Kconfig.file'],
\ 'kivy': ['file.kv'],
\ 'kix': ['file.kix'],
@@ -293,6 +295,7 @@ let s:filename_checks = {
\ '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'],
@@ -348,6 +351,7 @@ let s:filename_checks = {
\ 'obj': ['file.obj'],
\ 'ocaml': ['file.ml', 'file.mli', 'file.mll', 'file.mly', '.ocamlinit', 'file.mlt', 'file.mlp', 'file.mlip', 'file.mli.cppo', 'file.ml.cppo'],
\ 'occam': ['file.occ'],
+ \ 'octave': ['octaverc', '.octaverc', 'octave.conf'],
\ 'omnimark': ['file.xom', 'file.xin'],
\ 'opam': ['opam', 'file.opam', 'file.opam.template'],
\ 'openroad': ['file.or'],
@@ -394,6 +398,7 @@ let s:filename_checks = {
\ 'psf': ['file.psf'],
\ 'psl': ['file.psl'],
\ 'puppet': ['file.pp'],
+ \ 'pyret': ['file.arr'],
\ 'pyrex': ['file.pyx', 'file.pxd'],
\ 'python': ['file.py', 'file.pyw', '.pythonstartup', '.pythonrc', 'file.ptl', 'file.pyi', 'SConstruct'],
\ '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'],
@@ -425,10 +430,11 @@ let s:filename_checks = {
\ 'sather': ['file.sa'],
\ 'sbt': ['file.sbt'],
\ 'scala': ['file.scala', 'file.sc'],
- \ 'scheme': ['file.scm', 'file.ss', 'file.rkt'],
+ \ 'scheme': ['file.scm', 'file.ss', 'file.rkt', 'file.rktd', 'file.rktl'],
\ 'scilab': ['file.sci', 'file.sce'],
\ 'screen': ['.screenrc', 'screenrc'],
\ 'sexplib': ['file.sexp'],
+ \ 'scdoc': ['file.scd'],
\ 'scss': ['file.scss'],
\ 'sd': ['file.sd'],
\ 'sdc': ['file.sdc'],
@@ -751,6 +757,7 @@ func Test_pp_file()
split Xfile.pp
call assert_equal('pascal', &filetype)
bwipe!
+ unlet g:filetype_pp
" Test dist#ft#FTpp()
call writefile(['{ pascal comment'], 'Xfile.pp')
@@ -804,4 +811,110 @@ func Test_ex_file()
filetype off
endfunc
+func Test_dsl_file()
+ filetype on
+
+ call writefile([' <!doctype dsssl-spec ['], 'dslfile.dsl')
+ split dslfile.dsl
+ call assert_equal('dsl', &filetype)
+ bwipe!
+
+ call writefile(['workspace {'], 'dslfile.dsl')
+ split dslfile.dsl
+ call assert_equal('structurizr', &filetype)
+ bwipe!
+
+ call delete('dslfile.dsl')
+ filetype off
+endfunc
+
+func Test_m_file()
+ filetype on
+
+ call writefile(['looks like Matlab'], 'Xfile.m')
+ split Xfile.m
+ call assert_equal('matlab', &filetype)
+ bwipe!
+
+ let g:filetype_m = 'octave'
+ split Xfile.m
+ call assert_equal('octave', &filetype)
+ bwipe!
+ unlet g:filetype_m
+
+ " Test dist#ft#FTm()
+
+ " Objective-C
+
+ call writefile(['// Objective-C line comment'], 'Xfile.m')
+ split Xfile.m
+ call assert_equal('objc', &filetype)
+ bwipe!
+
+ call writefile(['/* Objective-C block comment */'], 'Xfile.m')
+ split Xfile.m
+ call assert_equal('objc', &filetype)
+ bwipe!
+
+ call writefile(['#import "test.m"'], 'Xfile.m')
+ split Xfile.m
+ call assert_equal('objc', &filetype)
+ bwipe!
+
+ " Octave
+
+ call writefile(['# Octave line comment'], 'Xfile.m')
+ split Xfile.m
+ call assert_equal('octave', &filetype)
+ bwipe!
+
+ call writefile(['%!test "Octave test"'], 'Xfile.m')
+ split Xfile.m
+ call assert_equal('octave', &filetype)
+ bwipe!
+
+ call writefile(['unwind_protect'], 'Xfile.m')
+ split Xfile.m
+ call assert_equal('octave', &filetype)
+ bwipe!
+
+ call writefile(['try; 42; end_try_catch'], 'Xfile.m')
+ split Xfile.m
+ call assert_equal('octave', &filetype)
+ bwipe!
+
+ " Mathematica
+
+ call writefile(['(* Mathematica comment'], 'Xfile.m')
+ split Xfile.m
+ call assert_equal('mma', &filetype)
+ bwipe!
+
+ " MATLAB
+
+ call writefile(['% MATLAB line comment'], 'Xfile.m')
+ split Xfile.m
+ call assert_equal('matlab', &filetype)
+ bwipe!
+
+ " Murphi
+
+ call writefile(['-- Murphi comment'], 'Xfile.m')
+ split Xfile.m
+ call assert_equal('murphi', &filetype)
+ bwipe!
+
+ call writefile(['/* Murphi block comment */', 'Type'], 'Xfile.m')
+ split Xfile.m
+ call assert_equal('murphi', &filetype)
+ bwipe!
+
+ call writefile(['Type'], 'Xfile.m')
+ split Xfile.m
+ call assert_equal('murphi', &filetype)
+ bwipe!
+
+ call delete('Xfile.m')
+ filetype off
+endfunc
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_filter_map.vim b/src/nvim/testdir/test_filter_map.vim
index a15567bcf2..a52a66ac2f 100644
--- a/src/nvim/testdir/test_filter_map.vim
+++ b/src/nvim/testdir/test_filter_map.vim
@@ -81,7 +81,11 @@ func Test_filter_map_dict_expr_funcref()
call assert_equal({"foo": "f", "bar": "b", "baz": "b"}, map(copy(dict), function('s:filter4')))
endfunc
-func Test_map_fails()
+func Test_map_filter_fails()
call assert_fails('call map([1], "42 +")', 'E15:')
call assert_fails('call filter([1], "42 +")', 'E15:')
+ call assert_fails("let l = map('abc', '\"> \" . v:val')", 'E896:')
+ call assert_fails("let l = filter('abc', '\"> \" . v:val')", 'E896:')
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_float_func.vim b/src/nvim/testdir/test_float_func.vim
index 154ef570e0..78675d7016 100644
--- a/src/nvim/testdir/test_float_func.vim
+++ b/src/nvim/testdir/test_float_func.vim
@@ -7,6 +7,8 @@ end
func Test_abs()
call assert_equal('1.23', string(abs(1.23)))
call assert_equal('1.23', string(abs(-1.23)))
+ eval -1.23->abs()->string()->assert_equal('1.23')
+
call assert_equal('0.0', string(abs(0.0)))
call assert_equal('0.0', string(abs(1.0/(1.0/0.0))))
call assert_equal('0.0', string(abs(-1.0/(1.0/0.0))))
@@ -22,6 +24,7 @@ endfunc
func Test_sqrt()
call assert_equal('0.0', string(sqrt(0.0)))
call assert_equal('1.414214', string(sqrt(2.0)))
+ eval 2.0->sqrt()->string()->assert_equal('1.414214')
call assert_equal("str2float('inf')", string(sqrt(1.0/0.0)))
call assert_equal("str2float('nan')", string(sqrt(-1.0)))
call assert_equal("str2float('nan')", string(sqrt(0.0/0.0)))
@@ -31,6 +34,7 @@ endfunc
func Test_log()
call assert_equal('0.0', string(log(1.0)))
call assert_equal('-0.693147', string(log(0.5)))
+ eval 0.5->log()->string()->assert_equal('-0.693147')
call assert_equal("-str2float('inf')", string(log(0.0)))
call assert_equal("str2float('nan')", string(log(-1.0)))
call assert_equal("str2float('inf')", string(log(1.0/0.0)))
@@ -42,6 +46,7 @@ func Test_log10()
call assert_equal('0.0', string(log10(1.0)))
call assert_equal('2.0', string(log10(100.0)))
call assert_equal('2.079181', string(log10(120.0)))
+ eval 120.0->log10()->string()->assert_equal('2.079181')
call assert_equal("-str2float('inf')", string(log10(0.0)))
call assert_equal("str2float('nan')", string(log10(-1.0)))
call assert_equal("str2float('inf')", string(log10(1.0/0.0)))
@@ -53,6 +58,7 @@ func Test_exp()
call assert_equal('1.0', string(exp(0.0)))
call assert_equal('7.389056', string(exp(2.0)))
call assert_equal('0.367879', string(exp(-1.0)))
+ eval -1.0->exp()->string()->assert_equal('0.367879')
call assert_equal("str2float('inf')", string(exp(1.0/0.0)))
call assert_equal('0.0', string(exp(-1.0/0.0)))
call assert_equal("str2float('nan')", string(exp(0.0/0.0)))
@@ -63,6 +69,7 @@ func Test_sin()
call assert_equal('0.0', string(sin(0.0)))
call assert_equal('0.841471', string(sin(1.0)))
call assert_equal('-0.479426', string(sin(-0.5)))
+ eval -0.5->sin()->string()->assert_equal('-0.479426')
call assert_equal("str2float('nan')", string(sin(0.0/0.0)))
call assert_equal("str2float('nan')", string(sin(1.0/0.0)))
call assert_equal('0.0', string(sin(1.0/(1.0/0.0))))
@@ -73,6 +80,8 @@ endfunc
func Test_asin()
call assert_equal('0.0', string(asin(0.0)))
call assert_equal('1.570796', string(asin(1.0)))
+ eval 1.0->asin()->string()->assert_equal('1.570796')
+
call assert_equal('-0.523599', string(asin(-0.5)))
call assert_equal("str2float('nan')", string(asin(1.1)))
call assert_equal("str2float('nan')", string(asin(1.0/0.0)))
@@ -84,6 +93,7 @@ func Test_sinh()
call assert_equal('0.0', string(sinh(0.0)))
call assert_equal('0.521095', string(sinh(0.5)))
call assert_equal('-1.026517', string(sinh(-0.9)))
+ eval -0.9->sinh()->string()->assert_equal('-1.026517')
call assert_equal("str2float('inf')", string(sinh(1.0/0.0)))
call assert_equal("-str2float('inf')", string(sinh(-1.0/0.0)))
call assert_equal("str2float('nan')", string(sinh(0.0/0.0)))
@@ -94,6 +104,7 @@ func Test_cos()
call assert_equal('1.0', string(cos(0.0)))
call assert_equal('0.540302', string(cos(1.0)))
call assert_equal('0.877583', string(cos(-0.5)))
+ eval -0.5->cos()->string()->assert_equal('0.877583')
call assert_equal("str2float('nan')", string(cos(0.0/0.0)))
call assert_equal("str2float('nan')", string(cos(1.0/0.0)))
call assert_fails('call cos("")', 'E808:')
@@ -103,6 +114,7 @@ func Test_acos()
call assert_equal('1.570796', string(acos(0.0)))
call assert_equal('0.0', string(acos(1.0)))
call assert_equal('3.141593', string(acos(-1.0)))
+ eval -1.0->acos()->string()->assert_equal('3.141593')
call assert_equal('2.094395', string(acos(-0.5)))
call assert_equal("str2float('nan')", string(acos(1.1)))
call assert_equal("str2float('nan')", string(acos(1.0/0.0)))
@@ -113,6 +125,7 @@ endfunc
func Test_cosh()
call assert_equal('1.0', string(cosh(0.0)))
call assert_equal('1.127626', string(cosh(0.5)))
+ eval 0.5->cosh()->string()->assert_equal('1.127626')
call assert_equal("str2float('inf')", string(cosh(1.0/0.0)))
call assert_equal("str2float('inf')", string(cosh(-1.0/0.0)))
call assert_equal("str2float('nan')", string(cosh(0.0/0.0)))
@@ -123,6 +136,7 @@ func Test_tan()
call assert_equal('0.0', string(tan(0.0)))
call assert_equal('0.546302', string(tan(0.5)))
call assert_equal('-0.546302', string(tan(-0.5)))
+ eval -0.5->tan()->string()->assert_equal('-0.546302')
call assert_equal("str2float('nan')", string(tan(1.0/0.0)))
call assert_equal("str2float('nan')", string(cos(0.0/0.0)))
call assert_equal('0.0', string(tan(1.0/(1.0/0.0))))
@@ -134,6 +148,7 @@ func Test_atan()
call assert_equal('0.0', string(atan(0.0)))
call assert_equal('0.463648', string(atan(0.5)))
call assert_equal('-0.785398', string(atan(-1.0)))
+ eval -1.0->atan()->string()->assert_equal('-0.785398')
call assert_equal('1.570796', string(atan(1.0/0.0)))
call assert_equal('-1.570796', string(atan(-1.0/0.0)))
call assert_equal("str2float('nan')", string(atan(0.0/0.0)))
@@ -144,6 +159,7 @@ func Test_atan2()
call assert_equal('-2.356194', string(atan2(-1, -1)))
call assert_equal('2.356194', string(atan2(1, -1)))
call assert_equal('0.0', string(atan2(1.0, 1.0/0.0)))
+ eval 1.0->atan2(1.0/0.0)->string()->assert_equal('0.0')
call assert_equal('1.570796', string(atan2(1.0/0.0, 1.0)))
call assert_equal("str2float('nan')", string(atan2(0.0/0.0, 1.0)))
call assert_fails('call atan2("", -1)', 'E808:')
@@ -154,6 +170,7 @@ func Test_tanh()
call assert_equal('0.0', string(tanh(0.0)))
call assert_equal('0.462117', string(tanh(0.5)))
call assert_equal('-0.761594', string(tanh(-1.0)))
+ eval -1.0->tanh()->string()->assert_equal('-0.761594')
call assert_equal('1.0', string(tanh(1.0/0.0)))
call assert_equal('-1.0', string(tanh(-1.0/0.0)))
call assert_equal("str2float('nan')", string(tanh(0.0/0.0)))
@@ -164,6 +181,7 @@ func Test_fmod()
call assert_equal('0.13', string(fmod(12.33, 1.22)))
call assert_equal('-0.13', string(fmod(-12.33, 1.22)))
call assert_equal("str2float('nan')", string(fmod(1.0/0.0, 1.0)))
+ eval (1.0/0.0)->fmod(1.0)->string()->assert_equal("str2float('nan')")
" On Windows we get "nan" instead of 1.0, accept both.
let res = string(fmod(1.0, 1.0/0.0))
if res != "str2float('nan')"
@@ -177,6 +195,7 @@ endfunc
func Test_pow()
call assert_equal('1.0', string(pow(0.0, 0.0)))
call assert_equal('8.0', string(pow(2.0, 3.0)))
+ eval 2.0->pow(3.0)->string()->assert_equal('8.0')
call assert_equal("str2float('nan')", string(pow(2.0, 0.0/0.0)))
call assert_equal("str2float('nan')", string(pow(0.0/0.0, 3.0)))
call assert_equal("str2float('nan')", string(pow(0.0/0.0, 3.0)))
@@ -192,6 +211,7 @@ func Test_str2float()
call assert_equal('1.0', string(str2float(' 1.0 ')))
call assert_equal('1.23', string(str2float('1.23')))
call assert_equal('1.23', string(str2float('1.23abc')))
+ eval '1.23abc'->str2float()->string()->assert_equal('1.23')
call assert_equal('1.0e40', string(str2float('1e40')))
call assert_equal('-1.23', string(str2float('-1.23')))
call assert_equal('1.23', string(str2float(' + 1.23 ')))
@@ -228,6 +248,7 @@ func Test_float2nr()
call assert_equal(1, float2nr(1.234))
call assert_equal(123, float2nr(1.234e2))
call assert_equal(12, float2nr(123.4e-1))
+ eval 123.4e-1->float2nr()->assert_equal(12)
let max_number = 1/0
let min_number = -max_number
call assert_equal(max_number/2+1, float2nr(pow(2, 62)))
@@ -242,6 +263,7 @@ func Test_floor()
call assert_equal('2.0', string(floor(2.0)))
call assert_equal('2.0', string(floor(2.11)))
call assert_equal('2.0', string(floor(2.99)))
+ eval 2.99->floor()->string()->assert_equal('2.0')
call assert_equal('-3.0', string(floor(-2.11)))
call assert_equal('-3.0', string(floor(-2.99)))
call assert_equal("str2float('nan')", string(floor(0.0/0.0)))
@@ -255,6 +277,7 @@ func Test_ceil()
call assert_equal('3.0', string(ceil(2.11)))
call assert_equal('3.0', string(ceil(2.99)))
call assert_equal('-2.0', string(ceil(-2.11)))
+ eval -2.11->ceil()->string()->assert_equal('-2.0')
call assert_equal('-2.0', string(ceil(-2.99)))
call assert_equal("str2float('nan')", string(ceil(0.0/0.0)))
call assert_equal("str2float('inf')", string(ceil(1.0/0.0)))
@@ -266,6 +289,7 @@ func Test_round()
call assert_equal('2.0', string(round(2.1)))
call assert_equal('3.0', string(round(2.5)))
call assert_equal('3.0', string(round(2.9)))
+ eval 2.9->round()->string()->assert_equal('3.0')
call assert_equal('-2.0', string(round(-2.1)))
call assert_equal('-3.0', string(round(-2.5)))
call assert_equal('-3.0', string(round(-2.9)))
@@ -279,6 +303,7 @@ func Test_trunc()
call assert_equal('2.0', string(trunc(2.1)))
call assert_equal('2.0', string(trunc(2.5)))
call assert_equal('2.0', string(trunc(2.9)))
+ eval 2.9->trunc()->string()->assert_equal('2.0')
call assert_equal('-2.0', string(trunc(-2.1)))
call assert_equal('-2.0', string(trunc(-2.5)))
call assert_equal('-2.0', string(trunc(-2.9)))
@@ -291,6 +316,7 @@ endfunc
func Test_isinf()
call assert_equal(1, isinf(1.0/0.0))
call assert_equal(-1, isinf(-1.0/0.0))
+ eval (-1.0/0.0)->isinf()->assert_equal(-1)
call assert_false(isinf(1.0))
call assert_false(isinf(0.0/0.0))
call assert_false(isinf('a'))
@@ -302,6 +328,7 @@ func Test_isnan()
call assert_true(isnan(0.0/0.0))
call assert_false(isnan(1.0))
call assert_false(isnan(1.0/0.0))
+ eval (1.0/0.0)->isnan()->assert_false()
call assert_false(isnan(-1.0/0.0))
call assert_false(isnan('a'))
call assert_false(isnan([]))
diff --git a/src/nvim/testdir/test_fnamemodify.vim b/src/nvim/testdir/test_fnamemodify.vim
index 116d23ba88..fe1df8fd4a 100644
--- a/src/nvim/testdir/test_fnamemodify.vim
+++ b/src/nvim/testdir/test_fnamemodify.vim
@@ -72,4 +72,8 @@ func Test_fnamemodify_er()
" :e never includes the whole filename, so "a.b":e:e:e --> "b"
call assert_equal('b.c', fnamemodify('a.b.c.d.e', ':r:r:e:e:e'))
call assert_equal('b.c', fnamemodify('a.b.c.d.e', ':r:r:e:e:e:e'))
+
+ call assert_equal('', fnamemodify(v:_null_string, v:_null_string))
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim
index 224ca257ab..e82fefc7fc 100644
--- a/src/nvim/testdir/test_functions.vim
+++ b/src/nvim/testdir/test_functions.vim
@@ -152,6 +152,10 @@ func Test_str2nr()
call assert_equal(65, str2nr('0101', 8))
call assert_equal(-65, str2nr('-101', 8))
call assert_equal(-65, str2nr('-0101', 8))
+ call assert_equal(65, str2nr('0o101', 8))
+ call assert_equal(65, str2nr('0O0101', 8))
+ call assert_equal(-65, str2nr('-0O101', 8))
+ call assert_equal(-65, str2nr('-0o0101', 8))
call assert_equal(11259375, str2nr('abcdef', 16))
call assert_equal(11259375, str2nr('ABCDEF', 16))
@@ -161,8 +165,16 @@ func Test_str2nr()
call assert_equal(11259375, str2nr('0XABCDEF', 16))
call assert_equal(-11259375, str2nr('-0xABCDEF', 16))
+ call assert_equal(1, str2nr("1'000'000", 10, 0))
+ call assert_equal(256, str2nr("1'0000'0000", 2, 1))
+ call assert_equal(262144, str2nr("1'000'000", 8, 1))
+ call assert_equal(1000000, str2nr("1'000'000", 10, 1))
+ call assert_equal(1000, str2nr("1'000''000", 10, 1))
+ call assert_equal(65536, str2nr("1'00'00", 16, 1))
+
call assert_equal(0, str2nr('0x10'))
call assert_equal(0, str2nr('0b10'))
+ call assert_equal(0, str2nr('0o10'))
call assert_equal(1, str2nr('12', 2))
call assert_equal(1, str2nr('18', 8))
call assert_equal(1, str2nr('1g', 16))
@@ -534,6 +546,7 @@ func Test_mode()
set complete=.
inoremap <F2> <C-R>=Save_mode()<CR>
+ xnoremap <F2> <Cmd>call Save_mode()<CR>
normal! 3G
exe "normal i\<F2>\<Esc>"
@@ -645,6 +658,14 @@ func Test_mode()
call assert_equal("\<C-S>", mode(1))
call feedkeys("\<Esc>", 'xt')
+ " v_CTRL-O
+ exe "normal gh\<C-O>\<F2>\<Esc>"
+ call assert_equal("v-vs", g:current_modes)
+ exe "normal gH\<C-O>\<F2>\<Esc>"
+ call assert_equal("V-Vs", g:current_modes)
+ exe "normal g\<C-H>\<C-O>\<F2>\<Esc>"
+ call assert_equal("\<C-V>-\<C-V>s", g:current_modes)
+
call feedkeys(":echo \<C-R>=Save_mode()\<C-U>\<CR>", 'xt')
call assert_equal('c-c', g:current_modes)
call feedkeys("gQecho \<C-R>=Save_mode()\<CR>\<CR>vi\<CR>", 'xt')
@@ -653,6 +674,7 @@ func Test_mode()
bwipe!
iunmap <F2>
+ xunmap <F2>
set complete&
endfunc
@@ -842,7 +864,7 @@ func Test_byte2line_line2byte()
set fileformat=mac
call assert_equal([-1, -1, 1, 1, 2, 2, 2, 3, 3, -1],
- \ map(range(-1, 8), 'byte2line(v:val)'))
+ \ map(range(-1, 8), 'v:val->byte2line()'))
call assert_equal([-1, -1, 1, 3, 6, 8, -1],
\ map(range(-1, 5), 'line2byte(v:val)'))
@@ -865,6 +887,34 @@ func Test_byte2line_line2byte()
bw!
endfunc
+func Test_byteidx()
+ let a = '.é.' " one char of two bytes
+ call assert_equal(0, byteidx(a, 0))
+ call assert_equal(0, byteidxcomp(a, 0))
+ call assert_equal(1, byteidx(a, 1))
+ call assert_equal(1, byteidxcomp(a, 1))
+ call assert_equal(3, byteidx(a, 2))
+ call assert_equal(3, byteidxcomp(a, 2))
+ call assert_equal(4, byteidx(a, 3))
+ call assert_equal(4, byteidxcomp(a, 3))
+ call assert_equal(-1, byteidx(a, 4))
+ call assert_equal(-1, byteidxcomp(a, 4))
+
+ let b = '.é.' " normal e with composing char
+ call assert_equal(0, b->byteidx(0))
+ call assert_equal(1, b->byteidx(1))
+ call assert_equal(4, b->byteidx(2))
+ call assert_equal(5, b->byteidx(3))
+ call assert_equal(-1, b->byteidx(4))
+
+ call assert_equal(0, b->byteidxcomp(0))
+ call assert_equal(1, b->byteidxcomp(1))
+ call assert_equal(2, b->byteidxcomp(2))
+ call assert_equal(4, b->byteidxcomp(3))
+ call assert_equal(5, b->byteidxcomp(4))
+ call assert_equal(-1, b->byteidxcomp(5))
+endfunc
+
" Test for charidx()
func Test_charidx()
let a = 'xáb́y'
@@ -996,6 +1046,9 @@ func Test_Executable()
if catcmd =~ '\<sbin\>' && result =~ '\<bin\>'
call assert_equal('/' .. substitute(catcmd, '\<sbin\>', 'bin', ''), result)
else
+ " /bin/cat and /usr/bin/cat may be hard linked, we could get either
+ let result = substitute(result, '/usr/bin/cat', '/bin/cat', '')
+ let catcmd = substitute(catcmd, 'usr/bin/cat', 'bin/cat', '')
call assert_equal('/' .. catcmd, result)
endif
bwipe
@@ -1052,7 +1105,7 @@ func Test_col()
call assert_equal(7, col('$'))
call assert_equal(4, col("'x"))
call assert_equal(6, col("'Y"))
- call assert_equal(2, col([1, 2]))
+ call assert_equal(2, [1, 2]->col())
call assert_equal(7, col([1, '$']))
call assert_equal(0, col(''))
@@ -1119,6 +1172,29 @@ func Test_shellescape()
call assert_equal("'te\\\nxt'", shellescape("te\nxt"))
call assert_equal("'te\\\\\nxt'", shellescape("te\nxt", 1))
+ set shell=fish
+ call assert_equal("'text'", shellescape('text'))
+ call assert_equal("'te\"xt'", shellescape('te"xt'))
+ call assert_equal("'te'\\''xt'", shellescape("te'xt"))
+
+ call assert_equal("'te%xt'", shellescape("te%xt"))
+ call assert_equal("'te\\%xt'", shellescape("te%xt", 1))
+ call assert_equal("'te#xt'", shellescape("te#xt"))
+ call assert_equal("'te\\#xt'", shellescape("te#xt", 1))
+ call assert_equal("'te!xt'", shellescape("te!xt"))
+ call assert_equal("'te\\!xt'", shellescape("te!xt", 1))
+
+ call assert_equal("'te\\\\xt'", shellescape("te\\xt"))
+ call assert_equal("'te\\\\xt'", shellescape("te\\xt", 1))
+ call assert_equal("'te\\\\'\\''xt'", shellescape("te\\'xt"))
+ call assert_equal("'te\\\\'\\''xt'", shellescape("te\\'xt", 1))
+ call assert_equal("'te\\\\!xt'", shellescape("te\\!xt"))
+ call assert_equal("'te\\\\\\!xt'", shellescape("te\\!xt", 1))
+ call assert_equal("'te\\\\%xt'", shellescape("te\\%xt"))
+ call assert_equal("'te\\\\\\%xt'", shellescape("te\\%xt", 1))
+ call assert_equal("'te\\\\#xt'", shellescape("te\\#xt"))
+ call assert_equal("'te\\\\\\#xt'", shellescape("te\\#xt", 1))
+
let &shell = save_shell
endfunc
@@ -1315,7 +1391,15 @@ endfunc
func Test_getchar()
call feedkeys('a', '')
call assert_equal(char2nr('a'), getchar())
+ call assert_equal(0, getchar(0))
+ call assert_equal(0, getchar(1))
+
+ call feedkeys('a', '')
+ call assert_equal('a', getcharstr())
+ call assert_equal('', getcharstr(0))
+ call assert_equal('', getcharstr(1))
+ call setline(1, 'xxxx')
" call test_setmouse(1, 3)
" let v:mouse_win = 9
" let v:mouse_winid = 9
@@ -1328,6 +1412,7 @@ func Test_getchar()
call assert_equal(win_getid(1), v:mouse_winid)
call assert_equal(1, v:mouse_lnum)
call assert_equal(3, v:mouse_col)
+ enew!
endfunc
func Test_libcall_libcallnr()
@@ -1391,13 +1476,13 @@ func Test_bufadd_bufload()
call assert_equal([''], getbufline(buf, 1, '$'))
let curbuf = bufnr('')
- call writefile(['some', 'text'], 'otherName')
- let buf = bufadd('otherName')
+ call writefile(['some', 'text'], 'XotherName')
+ let buf = 'XotherName'->bufadd()
call assert_notequal(0, buf)
- call assert_equal(1, bufexists('otherName'))
+ eval 'XotherName'->bufexists()->assert_equal(1)
call assert_equal(0, getbufvar(buf, '&buflisted'))
call assert_equal(0, bufloaded(buf))
- call bufload(buf)
+ eval buf->bufload()
call assert_equal(1, bufloaded(buf))
call assert_equal(['some', 'text'], getbufline(buf, 1, '$'))
call assert_equal(curbuf, bufnr(''))
@@ -1417,8 +1502,9 @@ func Test_bufadd_bufload()
call assert_equal(0, bufexists(buf2))
bwipe someName
- bwipe otherName
+ bwipe XotherName
call assert_equal(0, bufexists('someName'))
+ call delete('XotherName')
endfunc
func Test_readdir()
@@ -1451,6 +1537,20 @@ func Test_readdir()
call delete('Xdir', 'rf')
endfunc
+func Test_call()
+ call assert_equal(3, call('len', [123]))
+ call assert_equal(3, 'len'->call([123]))
+ call assert_fails("call call('len', 123)", 'E714:')
+ call assert_equal(0, call('', []))
+
+ function Mylen() dict
+ return len(self.data)
+ endfunction
+ let mydict = {'data': [0, 1, 2, 3], 'len': function("Mylen")}
+ eval mydict.len->call([], mydict)->assert_equal(4)
+ call assert_fails("call call('Mylen', [], 0)", 'E715:')
+endfunc
+
" Test for the eval() function
func Test_eval()
call assert_fails("call eval('5 a')", 'E488:')
diff --git a/src/nvim/testdir/test_gf.vim b/src/nvim/testdir/test_gf.vim
index ee548037ba..43efd6248e 100644
--- a/src/nvim/testdir/test_gf.vim
+++ b/src/nvim/testdir/test_gf.vim
@@ -145,7 +145,7 @@ func Test_gf_visual()
bwipe!
call delete('Xtest_gf_visual')
- set hidden&
+ set nohidden
endfunc
func Test_gf_error()
diff --git a/src/nvim/testdir/test_hide.vim b/src/nvim/testdir/test_hide.vim
index 128b8ff945..41b1a4ad7c 100644
--- a/src/nvim/testdir/test_hide.vim
+++ b/src/nvim/testdir/test_hide.vim
@@ -37,7 +37,7 @@ function Test_hide()
" :hide as a command
hide
call assert_equal([orig_bname, orig_winnr], [bufname(''), winnr('$')])
- call assert_equal([1, 1], [buflisted('Xf1'), bufloaded('Xf1')])
+ call assert_equal([1, 1], ['Xf1'->buflisted(), 'Xf1'->bufloaded()])
bwipeout! Xf1
new Xf1
diff --git a/src/nvim/testdir/test_highlight.vim b/src/nvim/testdir/test_highlight.vim
index 24c9c3580e..6fd9477ce9 100644
--- a/src/nvim/testdir/test_highlight.vim
+++ b/src/nvim/testdir/test_highlight.vim
@@ -426,6 +426,7 @@ func Test_highlight_eol_with_cursorline_breakindent()
let [hiCursorLine, hi_ul, hi_bg] = HiCursorLine()
call NewWindow('topleft 5', 10)
+ set showbreak=xxx
setlocal breakindent breakindentopt=min:0,shift:1 showbreak=>
call setline(1, ' ' . repeat('a', 9) . 'bcd')
call matchadd('Search', '\n')
@@ -483,6 +484,7 @@ func Test_highlight_eol_with_cursorline_breakindent()
call CloseWindow()
set showbreak=
+ setlocal showbreak=
exe hiCursorLine
endfunc
diff --git a/src/nvim/testdir/test_ins_complete.vim b/src/nvim/testdir/test_ins_complete.vim
index 3da3648fec..ce75799551 100644
--- a/src/nvim/testdir/test_ins_complete.vim
+++ b/src/nvim/testdir/test_ins_complete.vim
@@ -95,7 +95,7 @@ func Test_ins_complete()
call delete('Xtest11.one')
call delete('Xtest11.two')
call delete('Xtestdata')
- set cpt& cot& def& tags& tagbsearch& hidden&
+ set cpt& cot& def& tags& tagbsearch& nohidden
cd ..
call delete('Xdir', 'rf')
endfunc
@@ -497,6 +497,133 @@ func Test_ins_compl_tag_sft()
%bwipe!
endfunc
+" Test for completing special characters
+func Test_complete_special_chars()
+ new
+ call setline(1, 'int .*[-\^$ func float')
+ call feedkeys("oin\<C-X>\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>", 'xt')
+ call assert_equal('int .*[-\^$ func float', getline(2))
+ close!
+endfunc
+
+" Test for completion when text is wrapped across lines.
+func Test_complete_across_line()
+ new
+ call setline(1, ['red green blue', 'one two three'])
+ setlocal textwidth=20
+ exe "normal 2G$a re\<C-X>\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>"
+ call assert_equal(['one two three red', 'green blue one'], getline(2, '$'))
+ close!
+endfunc
+
+" Test for using CTRL-L to add one character when completing matching
+func Test_complete_add_onechar()
+ new
+ call setline(1, ['wool', 'woodwork'])
+ call feedkeys("Gowoo\<C-P>\<C-P>\<C-P>\<C-L>f", 'xt')
+ call assert_equal('woof', getline(3))
+
+ " use 'ignorecase' and backspace to erase characters from the prefix string
+ " and then add letters using CTRL-L
+ %d
+ set ignorecase backspace=2
+ setlocal complete=.
+ call setline(1, ['workhorse', 'workload'])
+ normal Go
+ exe "normal aWOR\<C-P>\<bs>\<bs>\<bs>\<bs>\<bs>\<bs>\<C-L>r\<C-L>\<C-L>"
+ call assert_equal('workh', getline(3))
+ set ignorecase& backspace&
+ close!
+endfunc
+
+" Test insert completion with 'cindent' (adjust the indent)
+func Test_complete_with_cindent()
+ new
+ setlocal cindent
+ call setline(1, ['if (i == 1)', " j = 2;"])
+ exe "normal Go{\<CR>i\<C-X>\<C-L>\<C-X>\<C-L>\<CR>}"
+ call assert_equal(['{', "\tif (i == 1)", "\t\tj = 2;", '}'], getline(3, '$'))
+
+ %d
+ call setline(1, ['when while', '{', ''])
+ setlocal cinkeys+==while
+ exe "normal Giwh\<C-P> "
+ call assert_equal("\twhile ", getline('$'))
+ close!
+endfunc
+
+" Test for <CTRL-X> <CTRL-V> completion. Complete commands and functions
+func Test_complete_cmdline()
+ new
+ exe "normal icaddb\<C-X>\<C-V>"
+ call assert_equal('caddbuffer', getline(1))
+ exe "normal ocall getqf\<C-X>\<C-V>"
+ call assert_equal('call getqflist(', getline(2))
+ exe "normal oabcxyz(\<C-X>\<C-V>"
+ call assert_equal('abcxyz(', getline(3))
+ com! -buffer TestCommand1 echo 'TestCommand1'
+ com! -buffer TestCommand2 echo 'TestCommand2'
+ write TestCommand1Test
+ write TestCommand2Test
+ " Test repeating <CTRL-X> <CTRL-V> and switching to another CTRL-X mode
+ exe "normal oT\<C-X>\<C-V>\<C-X>\<C-V>\<C-X>\<C-F>\<Esc>"
+ call assert_equal('TestCommand2Test', getline(4))
+ call delete('TestCommand1Test')
+ call delete('TestCommand2Test')
+ delcom TestCommand1
+ delcom TestCommand2
+ close!
+endfunc
+
+" Test for <CTRL-X> <CTRL-Z> stopping completion without changing the match
+func Test_complete_stop()
+ new
+ func Save_mode1()
+ let g:mode1 = mode(1)
+ return ''
+ endfunc
+ func Save_mode2()
+ let g:mode2 = mode(1)
+ return ''
+ endfunc
+ inoremap <F1> <C-R>=Save_mode1()<CR>
+ inoremap <F2> <C-R>=Save_mode2()<CR>
+ call setline(1, ['aaa bbb ccc '])
+ exe "normal A\<C-N>\<C-P>\<F1>\<C-X>\<C-Z>\<F2>\<Esc>"
+ call assert_equal('ic', g:mode1)
+ call assert_equal('i', g:mode2)
+ call assert_equal('aaa bbb ccc ', getline(1))
+ exe "normal A\<C-N>\<Down>\<F1>\<C-X>\<C-Z>\<F2>\<Esc>"
+ call assert_equal('ic', g:mode1)
+ call assert_equal('i', g:mode2)
+ call assert_equal('aaa bbb ccc aaa', getline(1))
+ set completeopt+=noselect
+ exe "normal A \<C-N>\<Down>\<Down>\<C-L>\<C-L>\<F1>\<C-X>\<C-Z>\<F2>\<Esc>"
+ call assert_equal('ic', g:mode1)
+ call assert_equal('i', g:mode2)
+ call assert_equal('aaa bbb ccc aaa bb', getline(1))
+ set completeopt&
+ exe "normal A d\<C-N>\<F1>\<C-X>\<C-Z>\<F2>\<Esc>"
+ call assert_equal('ic', g:mode1)
+ call assert_equal('i', g:mode2)
+ call assert_equal('aaa bbb ccc aaa bb d', getline(1))
+ com! -buffer TestCommand1 echo 'TestCommand1'
+ com! -buffer TestCommand2 echo 'TestCommand2'
+ exe "normal oT\<C-X>\<C-V>\<C-X>\<C-V>\<F1>\<C-X>\<C-Z>\<F2>\<Esc>"
+ call assert_equal('ic', g:mode1)
+ call assert_equal('i', g:mode2)
+ call assert_equal('TestCommand2', getline(2))
+ delcom TestCommand1
+ delcom TestCommand2
+ unlet g:mode1
+ unlet g:mode2
+ iunmap <F1>
+ iunmap <F2>
+ delfunc Save_mode1
+ delfunc Save_mode2
+ close!
+endfunc
+
" Test to ensure 'Scanning...' messages are not recorded in messages history
func Test_z1_complete_no_history()
new
diff --git a/src/nvim/testdir/test_ins_complete_no_halt.vim b/src/nvim/testdir/test_ins_complete_no_halt.vim
new file mode 100644
index 0000000000..e12925daa9
--- /dev/null
+++ b/src/nvim/testdir/test_ins_complete_no_halt.vim
@@ -0,0 +1,51 @@
+" Test insert mode completion does not get stuck when looping around.
+" In a separate file to avoid the settings to leak to other test cases.
+
+set complete+=kspell
+set completeopt+=menu
+set completeopt+=menuone
+set completeopt+=noselect
+set completeopt+=noinsert
+let g:autocompletion = v:true
+
+func Test_ins_complete_no_halt()
+ function! OpenCompletion()
+ if pumvisible() && (g:autocompletion == v:true)
+ call feedkeys("\<C-e>\<C-n>", "i")
+ return
+ endif
+ if ((v:char >= 'a' && v:char <= 'z') || (v:char >= 'A' && v:char <= 'Z')) && (g:autocompletion == v:true)
+ call feedkeys("\<C-n>", "i")
+ redraw
+ endif
+ endfunction
+
+ autocmd InsertCharPre * noautocmd call OpenCompletion()
+
+ setlocal spell! spelllang=en_us
+
+ call feedkeys("iauto-complete-halt-test test test test test test test test test test test test test test test test test test test\<C-c>", "tx!")
+ call assert_equal(["auto-complete-halt-test test test test test test test test test test test test test test test test test test test"], getline(1, "$"))
+endfunc
+
+func Test_auto_complete_backwards_no_halt()
+ function! OpenCompletion()
+ if pumvisible() && (g:autocompletion == v:true)
+ call feedkeys("\<C-e>\<C-p>", "i")
+ return
+ endif
+ if ((v:char >= 'a' && v:char <= 'z') || (v:char >= 'A' && v:char <= 'Z')) && (g:autocompletion == v:true)
+ call feedkeys("\<C-p>", "i")
+ redraw
+ endif
+ endfunction
+
+ autocmd InsertCharPre * noautocmd call OpenCompletion()
+
+ setlocal spell! spelllang=en_us
+
+ call feedkeys("iauto-complete-halt-test test test test test test test test test test test test test test test test test test test\<C-c>", "tx!")
+ call assert_equal(["auto-complete-halt-test test test test test test test test test test test test test test test test test test test"], getline(1, "$"))
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_join.vim b/src/nvim/testdir/test_join.vim
index ac6ef8f29f..ecb969d10a 100644
--- a/src/nvim/testdir/test_join.vim
+++ b/src/nvim/testdir/test_join.vim
@@ -51,7 +51,7 @@ func Test_join_marks()
/^This line/;'}-join
call assert_equal([0, 4, 11, 0], getpos("'["))
- call assert_equal([0, 4, 67, 0], getpos("']"))
+ call assert_equal([0, 4, 66, 0], getpos("']"))
enew!
endfunc
diff --git a/src/nvim/testdir/test_lambda.vim b/src/nvim/testdir/test_lambda.vim
index f026c8a55f..63bb4ae1ef 100644
--- a/src/nvim/testdir/test_lambda.vim
+++ b/src/nvim/testdir/test_lambda.vim
@@ -61,7 +61,7 @@ endfunction
function Test_lambda_fails()
call assert_equal(3, {a, b -> a + b}(1, 2))
- call assert_fails('echo {a, a -> a + a}(1, 2)', 'E15:')
+ call assert_fails('echo {a, a -> a + a}(1, 2)', 'E853:')
call assert_fails('echo {a, b -> a + b)}(1, 2)', 'E15:')
endfunc
diff --git a/src/nvim/testdir/test_listchars.vim b/src/nvim/testdir/test_listchars.vim
index 4cb609aaf0..8a1393a45d 100644
--- a/src/nvim/testdir/test_listchars.vim
+++ b/src/nvim/testdir/test_listchars.vim
@@ -140,13 +140,100 @@ func Test_listchars()
call assert_equal(expected, split(execute("%list"), "\n"))
+ " Test multispace
+ normal ggdG
+ set listchars=eol:$
+ set listchars+=multispace:yYzZ
+ set list
+
+ call append(0, [
+ \ ' ffff ',
+ \ ' i i gg',
+ \ ' h ',
+ \ ' j ',
+ \ ' 0 0 ',
+ \ ])
+
+ let expected = [
+ \ 'yYzZffffyYzZ$',
+ \ 'yYi iyYzZygg$',
+ \ ' hyYzZyYzZyY$',
+ \ 'yYzZyYzZyYj $',
+ \ 'yYzZ0yY0yYzZ$',
+ \ '$'
+ \ ]
+ redraw!
+ for i in range(1, 5)
+ call cursor(i, 1)
+ call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
+ endfor
+
+ call assert_equal(expected, split(execute("%list"), "\n"))
+
+ " the last occurrence of 'multispace:' is used
+ set listchars+=space:x,multispace:XyY
+
+ let expected = [
+ \ 'XyYXffffXyYX$',
+ \ 'XyixiXyYXygg$',
+ \ 'xhXyYXyYXyYX$',
+ \ 'XyYXyYXyYXjx$',
+ \ 'XyYX0Xy0XyYX$',
+ \ '$'
+ \ ]
+ redraw!
+ for i in range(1, 5)
+ call cursor(i, 1)
+ call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
+ endfor
+
+ call assert_equal(expected, split(execute("%list"), "\n"))
+
+ set listchars+=lead:>,trail:<
+
+ let expected = [
+ \ '>>>>ffff<<<<$',
+ \ '>>ixiXyYXygg$',
+ \ '>h<<<<<<<<<<$',
+ \ '>>>>>>>>>>j<$',
+ \ '>>>>0Xy0<<<<$',
+ \ '$'
+ \ ]
+ redraw!
+ for i in range(1, 5)
+ call cursor(i, 1)
+ call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
+ endfor
+
+ call assert_equal(expected, split(execute("%list"), "\n"))
+
+ " removing 'multispace:'
+ set listchars-=multispace:XyY
+ set listchars-=multispace:yYzZ
+
+ let expected = [
+ \ '>>>>ffff<<<<$',
+ \ '>>ixixxxxxgg$',
+ \ '>h<<<<<<<<<<$',
+ \ '>>>>>>>>>>j<$',
+ \ '>>>>0xx0<<<<$',
+ \ '$'
+ \ ]
+ redraw!
+ for i in range(1, 5)
+ call cursor(i, 1)
+ call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
+ endfor
+
+ call assert_equal(expected, split(execute("%list"), "\n"))
+
" test nbsp
normal ggdG
set listchars=nbsp:X,trail:Y
set list
" Non-breaking space
let nbsp = nr2char(0xa0)
- call append(0, [ ">".nbsp."<" ])
+ call append(0, [ ">" .. nbsp .. "<" ])
let expected = '>X< '
@@ -181,3 +268,100 @@ func Test_listchars()
enew!
set listchars& ff&
endfunc
+
+" Test that unicode listchars characters get properly inserted
+func Test_listchars_unicode()
+ enew!
+ let oldencoding=&encoding
+ set encoding=utf-8
+ set ff=unix
+
+ set listchars=eol:⇔,space:␣,multispace:≡≢≣,nbsp:≠,tab:←↔→
+ set list
+
+ let nbsp = nr2char(0xa0)
+ call append(0, [" a\tb c" .. nbsp .. "d "])
+ let expected = ['≡≢≣≡≢≣≡≢a←↔↔↔↔↔→b␣c≠d≡≢⇔']
+ redraw!
+ call cursor(1, 1)
+ call assert_equal(expected, ScreenLines(1, virtcol('$')))
+
+ set listchars+=lead:⇨,trail:⇦
+ let expected = ['⇨⇨⇨⇨⇨⇨⇨⇨a←↔↔↔↔↔→b␣c≠d⇦⇦⇔']
+ redraw!
+ call cursor(1, 1)
+ call assert_equal(expected, ScreenLines(1, virtcol('$')))
+
+ let &encoding=oldencoding
+ enew!
+ set listchars& ff&
+endfunction
+
+func Test_listchars_invalid()
+ enew!
+ set ff=unix
+
+ set listchars=eol:$
+ set list
+ set ambiwidth=double
+
+ " No colon
+ call assert_fails('set listchars=x', 'E474:')
+ call assert_fails('set listchars=x', 'E474:')
+ call assert_fails('set listchars=multispace', 'E474:')
+
+ " Too short
+ call assert_fails('set listchars=space:', 'E474:')
+ call assert_fails('set listchars=tab:x', 'E474:')
+ call assert_fails('set listchars=multispace:', 'E474:')
+
+ " One occurrence too short
+ call assert_fails('set listchars=space:,space:x', 'E474:')
+ call assert_fails('set listchars=space:x,space:', 'E474:')
+ call assert_fails('set listchars=tab:x,tab:xx', 'E474:')
+ call assert_fails('set listchars=tab:xx,tab:x', 'E474:')
+ call assert_fails('set listchars=multispace:,multispace:x', 'E474:')
+ call assert_fails('set listchars=multispace:x,multispace:', 'E474:')
+
+ " Too long
+ call assert_fails('set listchars=space:xx', 'E474:')
+ call assert_fails('set listchars=tab:xxxx', 'E474:')
+
+ " Has non-single width character
+ call assert_fails('set listchars=space:·', 'E474:')
+ call assert_fails('set listchars=tab:·x', 'E474:')
+ call assert_fails('set listchars=tab:x·', 'E474:')
+ call assert_fails('set listchars=tab:xx·', 'E474:')
+ call assert_fails('set listchars=multispace:·', 'E474:')
+ call assert_fails('set listchars=multispace:xxx·', 'E474:')
+
+ enew!
+ set ambiwidth& listchars& ff&
+endfunction
+
+" Tests that space characters following composing character won't get replaced
+" by listchars.
+func Test_listchars_composing()
+ enew!
+ let oldencoding=&encoding
+ set encoding=utf-8
+ set ff=unix
+ set list
+
+ set listchars=eol:$,space:_,nbsp:=
+
+ let nbsp1 = nr2char(0xa0)
+ let nbsp2 = nr2char(0x202f)
+ call append(0, [
+ \ " \u3099\t \u309A" .. nbsp1 .. nbsp1 .. "\u0302" .. nbsp2 .. nbsp2 .. "\u0302",
+ \ ])
+ let expected = [
+ \ "_ \u3099^I \u309A=" .. nbsp1 .. "\u0302=" .. nbsp2 .. "\u0302$"
+ \ ]
+ redraw!
+ call cursor(1, 1)
+ call assert_equal(expected, ScreenLines(1, virtcol('$')))
+ let &encoding=oldencoding
+ enew!
+ set listchars& ff&
+endfunction
diff --git a/src/nvim/testdir/test_listdict.vim b/src/nvim/testdir/test_listdict.vim
index 5152af8f58..ae035fa519 100644
--- a/src/nvim/testdir/test_listdict.vim
+++ b/src/nvim/testdir/test_listdict.vim
@@ -139,7 +139,7 @@ func Test_list_func_remove()
call assert_fails("call remove(l, 5)", 'E684:')
call assert_fails("call remove(l, 1, 5)", 'E684:')
call assert_fails("call remove(l, 3, 2)", 'E16:')
- call assert_fails("call remove(1, 0)", 'E712:')
+ call assert_fails("call remove(1, 0)", 'E896:')
call assert_fails("call remove(l, l)", 'E745:')
endfunc
@@ -616,6 +616,8 @@ func Test_reverse_sort_uniq()
call assert_equal(['bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l), 1))
call assert_equal(['bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l), 'i'))
call assert_equal(['BAR', 'Bar', 'FOO', 'FOOBAR', 'Foo', 'bar', 'foo', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l)))
+
+ call assert_fails('call reverse("")', 'E899:')
endfunc
" splitting a string to a List
diff --git a/src/nvim/testdir/test_match.vim b/src/nvim/testdir/test_match.vim
index 09448ca71b..505a052a19 100644
--- a/src/nvim/testdir/test_match.vim
+++ b/src/nvim/testdir/test_match.vim
@@ -157,7 +157,10 @@ func Test_match_error()
endfunc
func Test_matchadd_error()
- call assert_fails("call matchadd('GroupDoesNotExist', 'X')", 'E28:')
+ call clearmatches()
+ " Nvim: not an error anymore:
+ call matchadd('GroupDoesNotExist', 'X')
+ call assert_equal([{'group': 'GroupDoesNotExist', 'pattern': 'X', 'priority': 10, 'id': 13}], getmatches())
call assert_fails("call matchadd('Search', '\\(')", 'E475:')
call assert_fails("call matchadd('Search', 'XXX', 1, 123, 1)", 'E715:')
call assert_fails("call matchadd('Error', 'XXX', 1, 3)", 'E798:')
@@ -239,7 +242,7 @@ func Test_matchaddpos_otherwin()
\]
call assert_equal(expect, savematches)
- call clearmatches(winid)
+ eval winid->clearmatches()
call assert_equal([], getmatches(winid))
call setmatches(savematches, winid)
diff --git a/src/nvim/testdir/test_method.vim b/src/nvim/testdir/test_method.vim
new file mode 100644
index 0000000000..d34448e09e
--- /dev/null
+++ b/src/nvim/testdir/test_method.vim
@@ -0,0 +1,154 @@
+" Tests for ->method()
+
+func Test_list_method()
+ let l = [1, 2, 3]
+ call assert_equal([1, 2, 3, 4], [1, 2, 3]->add(4))
+ eval l->assert_equal(l)
+ eval l->assert_equal(l, 'wrong')
+ eval l->assert_notequal([3, 2, 1])
+ eval l->assert_notequal([3, 2, 1], 'wrong')
+ call assert_equal(l, l->copy())
+ call assert_equal(l, l->deepcopy())
+ call assert_equal(1, l->count(2))
+ call assert_false(l->empty())
+ call assert_true([]->empty())
+ call assert_equal(579, ['123', '+', '456']->join()->eval())
+ call assert_equal([1, 2, 3, 4, 5], [1, 2, 3]->extend([4, 5]))
+ call assert_equal([1, 3], [1, 2, 3]->filter('v:val != 2'))
+ call assert_equal(2, l->get(1))
+ call assert_equal(1, l->index(2))
+ call assert_equal([0, 1, 2, 3], [1, 2, 3]->insert(0))
+ call assert_fails('eval l->items()', 'E715:')
+ call assert_equal('1 2 3', l->join())
+ call assert_fails('eval l->keys()', 'E715:')
+ call assert_equal(3, l->len())
+ call assert_equal([2, 3, 4], [1, 2, 3]->map('v:val + 1'))
+ call assert_equal(3, l->max())
+ call assert_equal(1, l->min())
+ call assert_equal(2, [1, 2, 3]->remove(1))
+ call assert_equal([1, 2, 3, 1, 2, 3], l->repeat(2))
+ call assert_equal([3, 2, 1], [1, 2, 3]->reverse())
+ call assert_equal([1, 2, 3, 4], [4, 2, 3, 1]->sort())
+ call assert_equal('[1, 2, 3]', l->string())
+ call assert_equal(v:t_list, l->type())
+ call assert_equal([1, 2, 3], [1, 1, 2, 3, 3]->uniq())
+ call assert_fails('eval l->values()', 'E715:')
+endfunc
+
+func Test_dict_method()
+ let d = #{one: 1, two: 2, three: 3}
+
+ call assert_equal(d, d->copy())
+ call assert_equal(d, d->deepcopy())
+ call assert_equal(1, d->count(2))
+ call assert_false(d->empty())
+ call assert_true({}->empty())
+ call assert_equal(#{one: 1, two: 2, three: 3, four: 4}, d->extend(#{four: 4}))
+ call assert_equal(#{one: 1, two: 2, three: 3}, d->filter('v:val != 4'))
+ call assert_equal(2, d->get('two'))
+ call assert_fails("let x = d->index(2)", 'E897:')
+ call assert_fails("let x = d->insert(0)", 'E899:')
+ call assert_true(d->has_key('two'))
+ call assert_equal([['one', 1], ['two', 2], ['three', 3]], d->items())
+ call assert_fails("let x = d->join()", 'E714:')
+ call assert_equal(['one', 'two', 'three'], d->keys())
+ call assert_equal(3, d->len())
+ call assert_equal(#{one: 2, two: 3, three: 4}, d->map('v:val + 1'))
+ call assert_equal(#{one: 1, two: 2, three: 3}, d->map('v:val - 1'))
+ call assert_equal(3, d->max())
+ call assert_equal(1, d->min())
+ call assert_equal(2, d->remove("two"))
+ let d.two = 2
+ call assert_fails('let x = d->repeat(2)', 'E731:')
+ call assert_fails('let x = d->reverse()', 'E899:')
+ call assert_fails('let x = d->sort()', 'E686:')
+ call assert_equal("{'one': 1, 'two': 2, 'three': 3}", d->string())
+ call assert_equal(v:t_dict, d->type())
+ call assert_fails('let x = d->uniq()', 'E686:')
+ call assert_equal([1, 2, 3], d->values())
+endfunc
+
+func Test_string_method()
+ eval '1 2 3'->split()->assert_equal(['1', '2', '3'])
+ eval '1 2 3'->split()->map({i, v -> str2nr(v)})->assert_equal([1, 2, 3])
+ eval 'ABC'->str2list()->assert_equal([65, 66, 67])
+ eval 'ABC'->strlen()->assert_equal(3)
+ eval "a\rb\ec"->strtrans()->assert_equal('a^Mb^[c')
+ eval "aあb"->strwidth()->assert_equal(4)
+ eval 'abc'->substitute('b', 'x', '')->assert_equal('axc')
+
+ eval 'abc'->printf('the %s arg')->assert_equal('the abc arg')
+endfunc
+
+func Test_method_append()
+ new
+ eval ['one', 'two', 'three']->append(1)
+ call assert_equal(['', 'one', 'two', 'three'], getline(1, '$'))
+
+ %del
+ let bnr = bufnr('')
+ wincmd w
+ eval ['one', 'two', 'three']->appendbufline(bnr, 1)
+ call assert_equal(['', 'one', 'two', 'three'], getbufline(bnr, 1, '$'))
+
+ exe 'bwipe! ' .. bnr
+endfunc
+
+func Test_method_funcref()
+ func Concat(one, two, three)
+ return a:one .. a:two .. a:three
+ endfunc
+ let FuncRef = function('Concat')
+ eval 'foo'->FuncRef('bar', 'tail')->assert_equal('foobartail')
+
+ " not enough arguments
+ call assert_fails("eval 'foo'->FuncRef('bar')", 'E119:')
+ " too many arguments
+ call assert_fails("eval 'foo'->FuncRef('bar', 'tail', 'four')", 'E118:')
+
+ let Partial = function('Concat', ['two'])
+ eval 'one'->Partial('three')->assert_equal('onetwothree')
+
+ " not enough arguments
+ call assert_fails("eval 'one'->Partial()", 'E119:')
+ " too many arguments
+ call assert_fails("eval 'one'->Partial('three', 'four')", 'E118:')
+
+ delfunc Concat
+endfunc
+
+func Test_method_float()
+ eval 1.234->string()->assert_equal('1.234')
+ eval -1.234->string()->assert_equal('-1.234')
+endfunc
+
+func Test_method_syntax()
+ eval [1, 2, 3] ->sort( )
+ eval [1, 2, 3]
+ \ ->sort(
+ \ )
+ call assert_fails('eval [1, 2, 3]-> sort()', 'E260:')
+ call assert_fails('eval [1, 2, 3]->sort ()', 'E274:')
+ call assert_fails('eval [1, 2, 3]-> sort ()', 'E260:')
+endfunc
+
+func Test_method_lambda()
+ eval "text"->{x -> x .. " extended"}()->assert_equal('text extended')
+ eval "text"->{x, y -> x .. " extended " .. y}('more')->assert_equal('text extended more')
+
+ call assert_fails('eval "text"->{x -> x .. " extended"} ()', 'E274:')
+
+ " todo: lambda accepts more arguments than it consumes
+ " call assert_fails('eval "text"->{x -> x .. " extended"}("more")', 'E99:')
+
+ " Nvim doesn't include test_refcount().
+ " let l = [1, 2, 3]
+ " eval l->{x -> x}()
+ " call assert_equal(1, test_refcount(l))
+endfunc
+
+func Test_method_not_supported()
+ call assert_fails('eval 123->changenr()', 'E276:')
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_mksession.vim b/src/nvim/testdir/test_mksession.vim
index 4e46dbac16..c96c6a9678 100644
--- a/src/nvim/testdir/test_mksession.vim
+++ b/src/nvim/testdir/test_mksession.vim
@@ -170,7 +170,7 @@ func Test_mksession_rtp()
return
endif
new
- set sessionoptions&vi
+ set sessionoptions+=options
let _rtp=&rtp
" Make a real long (invalid) runtimepath value,
" that should exceed PATH_MAX (hopefully)
@@ -287,10 +287,33 @@ func Test_mksession_blank_windows()
call delete('Xtest_mks.out')
endfunc
+func Test_mksession_buffer_count()
+ set hidden
+
+ " Edit exactly three files in the current session.
+ %bwipe!
+ e Xfoo | tabe Xbar | tabe Xbaz
+ tabdo write
+ mksession! Xtest_mks.out
+
+ " Verify that loading the session does not create additional buffers.
+ %bwipe!
+ source Xtest_mks.out
+ call assert_equal(3, len(getbufinfo()))
+
+ " Clean up.
+ call delete('Xfoo')
+ call delete('Xbar')
+ call delete('Xbaz')
+ call delete('Xtest_mks.out')
+ %bwipe!
+ set nohidden
+endfunc
+
if has('extra_search')
func Test_mksession_hlsearch()
- set sessionoptions&vi
+ set sessionoptions+=options
set hlsearch
mksession! Xtest_mks.out
nohlsearch
@@ -630,7 +653,7 @@ endfunc
" Test for mksession with a named scratch buffer
func Test_mksession_scratch()
- set sessionoptions&vi
+ set sessionoptions+=options
enew | only
file Xscratch
set buftype=nofile
diff --git a/src/nvim/testdir/test_modeline.vim b/src/nvim/testdir/test_modeline.vim
index 9bdada616c..b3fe79f545 100644
--- a/src/nvim/testdir/test_modeline.vim
+++ b/src/nvim/testdir/test_modeline.vim
@@ -280,3 +280,13 @@ func Test_modeline_fails_modelineexpr()
call s:modeline_fails('tabline', 'tabline=Something()', 'E992:')
call s:modeline_fails('titlestring', 'titlestring=Something()', 'E992:')
endfunc
+
+func Test_modeline_disable()
+ set modeline
+ call writefile(['vim: sw=2', 'vim: nomodeline', 'vim: sw=3'], 'Xmodeline_disable')
+ edit Xmodeline_disable
+ call assert_equal(2, &sw)
+ call delete('Xmodeline_disable')
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_normal.vim b/src/nvim/testdir/test_normal.vim
index 5c413d1e16..aff22f5d01 100644
--- a/src/nvim/testdir/test_normal.vim
+++ b/src/nvim/testdir/test_normal.vim
@@ -1227,7 +1227,7 @@ func Test_normal23_K()
set iskeyword-=\|
" Only expect "man" to work on Unix
- if !has("unix")
+ if !has("unix") || has('nvim') " Nvim K uses :terminal. #15398
let &keywordprg = k
bw!
return
diff --git a/src/nvim/testdir/test_number.vim b/src/nvim/testdir/test_number.vim
index eaabe3f67e..d737ebe9f0 100644
--- a/src/nvim/testdir/test_number.vim
+++ b/src/nvim/testdir/test_number.vim
@@ -3,6 +3,8 @@
source check.vim
source view_util.vim
+source screendump.vim
+
func s:screen_lines(start, end) abort
return ScreenLines([a:start, a:end], 8)
endfunc
@@ -265,6 +267,37 @@ func Test_relativenumber_uninitialised()
bwipe!
endfunc
+func Test_relativenumber_colors()
+ CheckScreendump
+
+ let lines =<< trim [CODE]
+ call setline(1, range(200))
+ 111
+ set number relativenumber
+ hi LineNr ctermfg=red
+ [CODE]
+ call writefile(lines, 'XTest_relnr')
+
+ " Check that the balloon shows up after a mouse move
+ let buf = RunVimInTerminal('-S XTest_relnr', {'rows': 10, 'cols': 50})
+ call term_wait(buf, 100)
+ " Default colors
+ call VerifyScreenDump(buf, 'Test_relnr_colors_1', {})
+
+ call term_sendkeys(buf, ":hi LineNrAbove ctermfg=blue\<CR>")
+ call VerifyScreenDump(buf, 'Test_relnr_colors_2', {})
+
+ call term_sendkeys(buf, ":hi LineNrBelow ctermfg=green\<CR>")
+ call VerifyScreenDump(buf, 'Test_relnr_colors_3', {})
+
+ call term_sendkeys(buf, ":hi clear LineNrAbove\<CR>")
+ call VerifyScreenDump(buf, 'Test_relnr_colors_4', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('XTest_relnr')
+endfunc
+
" Test for displaying line numbers with 'rightleft'
func Test_number_rightleft()
CheckFeature rightleft
@@ -287,4 +320,15 @@ func Test_number_rightleft()
bw!
endfunc
+" This used to cause a divide by zero
+func Test_number_no_text_virtual_edit()
+ vnew
+ call setline(1, ['line one', 'line two'])
+ set number virtualedit=all
+ normal w
+ 4wincmd |
+ normal j
+ bwipe!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim
index 8796af7a20..72c151142d 100644
--- a/src/nvim/testdir/test_options.vim
+++ b/src/nvim/testdir/test_options.vim
@@ -539,7 +539,7 @@ func Test_copy_winopt()
call assert_equal(4,&numberwidth)
bw!
- set hidden&
+ set nohidden
endfunc
func Test_shortmess_F()
diff --git a/src/nvim/testdir/test_popup.vim b/src/nvim/testdir/test_popup.vim
index 06bdb1236a..710450293c 100644
--- a/src/nvim/testdir/test_popup.vim
+++ b/src/nvim/testdir/test_popup.vim
@@ -250,7 +250,7 @@ endfunc
func Test_noinsert_complete()
func! s:complTest1() abort
- call complete(1, ['source', 'soundfold'])
+ eval ['source', 'soundfold']->complete(1)
return ''
endfunc
@@ -403,7 +403,7 @@ func DummyCompleteFour(findstart, base)
return 0
else
call complete_add('four1')
- call complete_add('four2')
+ eval 'four2'->complete_add()
call complete_check()
call complete_add('four3')
call complete_add('four4')
@@ -989,7 +989,7 @@ func GetCompleteInfo()
if empty(g:compl_what)
let g:compl_info = complete_info()
else
- let g:compl_info = complete_info(g:compl_what)
+ let g:compl_info = g:compl_what->complete_info()
endif
return ''
endfunc
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index 6bd64caa6c..18587b9b2c 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -134,6 +134,21 @@ func XlistTests(cchar)
call assert_equal([' 2 Xtestfile1:1 col 3: Line1',
\ ' 3: non-error 2', ' 4 Xtestfile2:2 col 2: Line2'], l)
+ " Ranged entries
+ call g:Xsetlist([{'lnum':10,'text':'Line1'},
+ \ {'lnum':20,'col':10,'text':'Line2'},
+ \ {'lnum':30,'col':15,'end_col':20,'text':'Line3'},
+ \ {'lnum':40,'end_lnum':45,'text':'Line4'},
+ \ {'lnum':50,'end_lnum':55,'col':15,'text':'Line5'},
+ \ {'lnum':60,'end_lnum':65,'col':25,'end_col':35,'text':'Line6'}])
+ let l = split(execute('Xlist', ""), "\n")
+ call assert_equal([' 1:10: Line1',
+ \ ' 2:20 col 10: Line2',
+ \ ' 3:30 col 15-20: Line3',
+ \ ' 4:40-45: Line4',
+ \ ' 5:50-55 col 15: Line5',
+ \ ' 6:60-65 col 25-35: Line6'], l)
+
" Different types of errors
call g:Xsetlist([{'lnum':10,'col':5,'type':'W', 'text':'Warning','nr':11},
\ {'lnum':20,'col':10,'type':'e','text':'Error','nr':22},
@@ -599,6 +614,7 @@ func s:test_xhelpgrep(cchar)
call assert_true(&buftype == 'help')
call assert_true(winnr() == 1)
call assert_true(winnr('$') == 2)
+ call assert_match('|\d\+ col \d\+-\d\+|', getbufline(winbufnr(2), 1)[0])
" This wipes out the buffer, make sure that doesn't cause trouble.
Xclose
@@ -1437,10 +1453,13 @@ func SetXlistTests(cchar, bnum)
call s:setup_commands(a:cchar)
call g:Xsetlist([{'bufnr': a:bnum, 'lnum': 1},
- \ {'bufnr': a:bnum, 'lnum': 2}])
+ \ {'bufnr': a:bnum, 'lnum': 2, 'end_lnum': 3, 'col': 4, 'end_col': 5}])
let l = g:Xgetlist()
call assert_equal(2, len(l))
call assert_equal(2, l[1].lnum)
+ call assert_equal(3, l[1].end_lnum)
+ call assert_equal(4, l[1].col)
+ call assert_equal(5, l[1].end_col)
Xnext
call g:Xsetlist([{'bufnr': a:bnum, 'lnum': 3}], 'a')
@@ -1892,7 +1911,7 @@ func Test_switchbuf()
enew | only
set switchbuf=useopen
cexpr "Xqftestfile1:1:10"
- call assert_equal('', &switchbuf)
+ call assert_equal('uselast', &switchbuf)
call delete('Xqftestfile1')
call delete('Xqftestfile2')
@@ -2202,6 +2221,10 @@ func Xproperty_tests(cchar)
call g:Xsetlist([], 'a', {'context':246})
let d = g:Xgetlist({'context':1})
call assert_equal(246, d.context)
+ " set other Vim data types as context
+ call g:Xsetlist([], 'a', {'context' : v:_null_blob})
+ call g:Xsetlist([], 'a', {'context' : ''})
+ call test_garbagecollect_now()
if a:cchar == 'l'
" Test for copying context across two different location lists
new | only
@@ -2743,7 +2766,9 @@ func XvimgrepTests(cchar)
let l = g:Xgetlist()
call assert_equal(2, len(l))
call assert_equal(8, l[0].col)
+ call assert_equal(11, l[0].end_col)
call assert_equal(12, l[1].col)
+ call assert_equal(15, l[1].end_col)
1Xvimgrep ?Editor? Xtestfile*
let l = g:Xgetlist()
@@ -2965,7 +2990,7 @@ func Test_cclose_in_autocmd()
" call test_override('starting', 0)
endfunc
-" Check that ":file" without an argument is possible even when "curbuf_lock"
+" Check that ":file" without an argument is possible even when curbuf is locked
" is set.
func Test_file_from_copen()
" Works without argument.
@@ -4850,7 +4875,42 @@ func Test_add_invalid_entry_with_qf_window()
call setqflist(['bb'], 'a')
call assert_equal(1, line('$'))
call assert_equal(['Xfile1|10| aa'], getline(1, '$'))
- call assert_equal([{'lnum': 10, 'bufnr': bufnr('Xfile1'), 'col': 0, 'pattern': '', 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'module': '', 'text': 'aa'}], getqflist())
+ call assert_equal([{'lnum': 10 , 'end_lnum': 0 , 'bufnr': bufnr('Xfile1') , 'col': 0 , 'end_col': 0 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , getqflist())
+
+ call setqflist([{'lnum': 10 , 'bufnr': bufnr('Xfile1') , 'col': 0 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , 'r')
+ call assert_equal(1 , line('$'))
+ call assert_equal(['Xfile1|10| aa'] , getline(1 , '$'))
+ call assert_equal([{'lnum': 10 , 'end_lnum': 0 , 'bufnr': bufnr('Xfile1') , 'col': 0 , 'end_col': 0 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , getqflist())
+
+ call setqflist([{'lnum': 10 , 'end_lnum': 0 , 'bufnr': bufnr('Xfile1') , 'col': 0 , 'end_col': 0 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , 'r')
+ call assert_equal(1 , line('$'))
+ call assert_equal(['Xfile1|10| aa'] , getline(1 , '$'))
+ call assert_equal([{'lnum': 10 , 'end_lnum': 0 , 'bufnr': bufnr('Xfile1') , 'col': 0 , 'end_col': 0 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , getqflist())
+
+ call setqflist([{'lnum': 10 , 'end_lnum': -123 , 'bufnr': bufnr('Xfile1') , 'col': 0 , 'end_col': -456 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , 'r')
+ call assert_equal(1 , line('$'))
+ call assert_equal(['Xfile1|10| aa'] , getline(1 , '$'))
+ call assert_equal([{'lnum': 10 , 'end_lnum': -123 , 'bufnr': bufnr('Xfile1') , 'col': 0 , 'end_col': -456 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , getqflist())
+
+ call setqflist([{'lnum': 10 , 'end_lnum': -123 , 'bufnr': bufnr('Xfile1') , 'col': 666 , 'end_col': 0 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , 'r')
+ call assert_equal(1 , line('$'))
+ call assert_equal(['Xfile1|10 col 666| aa'] , getline(1 , '$'))
+ call assert_equal([{'lnum': 10 , 'end_lnum': -123 , 'bufnr': bufnr('Xfile1') , 'col': 666 , 'end_col': 0 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , getqflist())
+
+ call setqflist([{'lnum': 10 , 'end_lnum': -123 , 'bufnr': bufnr('Xfile1') , 'col': 666 , 'end_col': -456 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , 'r')
+ call assert_equal(1 , line('$'))
+ call assert_equal(['Xfile1|10 col 666| aa'] , getline(1 , '$'))
+ call assert_equal([{'lnum': 10 , 'end_lnum': -123 , 'bufnr': bufnr('Xfile1') , 'col': 666 , 'end_col': -456 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , getqflist())
+
+ call setqflist([{'lnum': 10 , 'end_lnum': -123 , 'bufnr': bufnr('Xfile1') , 'col': 666 , 'end_col': 222 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , 'r')
+ call assert_equal(1 , line('$'))
+ call assert_equal(['Xfile1|10 col 666-222| aa'] , getline(1 , '$'))
+ call assert_equal([{'lnum': 10 , 'end_lnum': -123 , 'bufnr': bufnr('Xfile1') , 'col': 666 , 'end_col': 222 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , getqflist())
+
+ call setqflist([{'lnum': 10 , 'end_lnum': 6 , 'bufnr': bufnr('Xfile1') , 'col': 666 , 'end_col': 222 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , 'r')
+ call assert_equal(1 , line('$'))
+ call assert_equal(['Xfile1|10-6 col 666-222| aa'] , getline(1 , '$'))
+ call assert_equal([{'lnum': 10 , 'end_lnum': 6 , 'bufnr': bufnr('Xfile1') , 'col': 666 , 'end_col': 222 , 'pattern': '' , 'valid': 1 , 'vcol': 0 , 'nr': -1 , 'type': '' , 'module': '' , 'text': 'aa'}] , getqflist())
cclose
endfunc
@@ -5001,15 +5061,21 @@ func Xtest_qftextfunc(cchar)
call assert_equal('Tqfexpr', &quickfixtextfunc)
call assert_equal('',
\ g:Xgetlist({'quickfixtextfunc' : 1}).quickfixtextfunc)
- Xexpr ['F1:10:2:green', 'F1:20:4:blue']
+ call g:Xsetlist([
+ \ { 'filename': 'F1', 'lnum': 10, 'col': 2,
+ \ 'end_col': 7, 'text': 'green'},
+ \ { 'filename': 'F1', 'lnum': 20, 'end_lnum': 25, 'col': 4,
+ \ 'end_col': 8, 'text': 'blue'},
+ \ ])
+
Xwindow
call assert_equal('F1-L10C2-green', getline(1))
call assert_equal('F1-L20C4-blue', getline(2))
Xclose
set quickfixtextfunc&vim
Xwindow
- call assert_equal('F1|10 col 2| green', getline(1))
- call assert_equal('F1|20 col 4| blue', getline(2))
+ call assert_equal('F1|10 col 2-7| green', getline(1))
+ call assert_equal('F1|20-25 col 4-8| blue', getline(2))
Xclose
set efm&
set quickfixtextfunc&
@@ -5196,4 +5262,54 @@ func Test_qftextfunc_other_loclist()
%bw!
endfunc
+func Test_locationlist_open_in_newtab()
+ call s:create_test_file('Xqftestfile1')
+ call s:create_test_file('Xqftestfile2')
+ call s:create_test_file('Xqftestfile3')
+
+ %bwipe!
+
+ lgetexpr ['Xqftestfile1:5:Line5',
+ \ 'Xqftestfile2:10:Line10',
+ \ 'Xqftestfile3:16:Line16']
+
+ silent! llast
+ call assert_equal(1, tabpagenr('$'))
+ call assert_equal('Xqftestfile3', bufname())
+
+ set switchbuf=newtab
+
+ silent! lfirst
+ call assert_equal(2, tabpagenr('$'))
+ call assert_equal('Xqftestfile1', bufname())
+
+ silent! lnext
+ call assert_equal(3, tabpagenr('$'))
+ call assert_equal('Xqftestfile2', bufname())
+
+ call delete('Xqftestfile1')
+ call delete('Xqftestfile2')
+ call delete('Xqftestfile3')
+ set switchbuf&vim
+
+ %bwipe!
+endfunc
+
+" Test for win_gettype() in quickfix and location list windows
+func Test_win_gettype()
+ copen
+ call assert_equal("quickfix", win_gettype())
+ let wid = win_getid()
+ wincmd p
+ call assert_equal("quickfix", win_gettype(wid))
+ cclose
+ lexpr ''
+ lopen
+ call assert_equal("loclist", win_gettype())
+ let wid = win_getid()
+ wincmd p
+ call assert_equal("loclist", win_gettype(wid))
+ lclose
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_registers.vim b/src/nvim/testdir/test_registers.vim
index 53069b3d31..fd8653a2eb 100644
--- a/src/nvim/testdir/test_registers.vim
+++ b/src/nvim/testdir/test_registers.vim
@@ -283,4 +283,84 @@ func Test_insert_small_delete()
bwipe!
endfunc
+" Test for getting register info
+func Test_get_reginfo()
+ enew
+ call setline(1, ['foo', 'bar'])
+
+ exe 'norm! "zyy'
+ let info = getreginfo('"')
+ call assert_equal('z', info.points_to)
+ call setreg('y', 'baz')
+ call assert_equal('z', getreginfo('').points_to)
+ call setreg('y', { 'isunnamed': v:true })
+ call assert_equal('y', getreginfo('"').points_to)
+
+ exe '$put'
+ call assert_equal(getreg('y'), getline(3))
+ call setreg('', 'qux')
+ call assert_equal('0', getreginfo('').points_to)
+ call setreg('x', 'quux')
+ call assert_equal('0', getreginfo('').points_to)
+
+ let info = getreginfo('')
+ call assert_equal(getreg('', 1, 1), info.regcontents)
+ call assert_equal(getregtype(''), info.regtype)
+
+ exe "norm! 0\<c-v>e" .. '"zy'
+ let info = getreginfo('z')
+ call assert_equal(getreg('z', 1, 1), info.regcontents)
+ call assert_equal(getregtype('z'), info.regtype)
+ call assert_equal(1, +info.isunnamed)
+
+ let info = getreginfo('"')
+ call assert_equal('z', info.points_to)
+
+ bwipe!
+endfunc
+
+" Test for restoring register with dict from getreginfo
+func Test_set_register_dict()
+ enew!
+
+ call setreg('"', #{ regcontents: ['one', 'two'],
+ \ regtype: 'V', points_to: 'z' })
+ call assert_equal(['one', 'two'], getreg('"', 1, 1))
+ let info = getreginfo('"')
+ call assert_equal('z', info.points_to)
+ call assert_equal('V', info.regtype)
+ call assert_equal(1, +getreginfo('z').isunnamed)
+
+ call setreg('x', #{ regcontents: ['three', 'four'],
+ \ regtype: 'v', isunnamed: v:true })
+ call assert_equal(['three', 'four'], getreg('"', 1, 1))
+ let info = getreginfo('"')
+ call assert_equal('x', info.points_to)
+ call assert_equal('v', info.regtype)
+ call assert_equal(1, +getreginfo('x').isunnamed)
+
+ call setreg('y', #{ regcontents: 'five',
+ \ regtype: "\<c-v>", isunnamed: v:false })
+ call assert_equal("\<c-v>4", getreginfo('y').regtype)
+ call assert_equal(0, +getreginfo('y').isunnamed)
+ call assert_equal(['three', 'four'], getreg('"', 1, 1))
+ call assert_equal('x', getreginfo('"').points_to)
+
+ call setreg('"', #{ regcontents: 'six' })
+ call assert_equal('0', getreginfo('"').points_to)
+ call assert_equal(1, +getreginfo('0').isunnamed)
+ call assert_equal(['six'], getreginfo('0').regcontents)
+ call assert_equal(['six'], getreginfo('"').regcontents)
+
+ let @x = 'one'
+ call setreg('x', {})
+ call assert_equal(1, len(split(execute('reg x'), '\n')))
+
+ call assert_fails("call setreg('0', #{regtype: 'V'}, 'v')", 'E118:')
+ call assert_fails("call setreg('0', #{regtype: 'X'})", 'E475:')
+ call assert_fails("call setreg('0', #{regtype: 'vy'})", 'E475:')
+
+ bwipe!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_rename.vim b/src/nvim/testdir/test_rename.vim
index e4228188bd..2311caf790 100644
--- a/src/nvim/testdir/test_rename.vim
+++ b/src/nvim/testdir/test_rename.vim
@@ -95,7 +95,6 @@ func Test_rename_copy()
endfunc
func Test_rename_fails()
- throw 'skipped: TODO: '
call writefile(['foo'], 'Xrenamefile')
" Can't rename into a non-existing directory.
diff --git a/src/nvim/testdir/test_spellfile.vim b/src/nvim/testdir/test_spellfile.vim
index 729467b556..0f48ab8f6f 100644
--- a/src/nvim/testdir/test_spellfile.vim
+++ b/src/nvim/testdir/test_spellfile.vim
@@ -210,6 +210,52 @@ func Test_spellfile_CHECKCOMPOUNDPATTERN()
call delete('XtestCHECKCOMPOUNDPATTERN-utf8.spl')
endfunc
+" Test NOCOMPOUNDSUGS (see :help spell-NOCOMPOUNDSUGS)
+func Test_spellfile_NOCOMPOUNDSUGS()
+ call writefile(['3',
+ \ 'one/c',
+ \ 'two/c',
+ \ 'three/c'], 'XtestNOCOMPOUNDSUGS.dic')
+
+ " pass 0 tests without NOCOMPOUNDSUGS, pass 1 tests with NOCOMPOUNDSUGS
+ for pass in [0, 1]
+ if pass == 0
+ call writefile(['COMPOUNDFLAG c'], 'XtestNOCOMPOUNDSUGS.aff')
+ else
+ call writefile(['NOCOMPOUNDSUGS',
+ \ 'COMPOUNDFLAG c'], 'XtestNOCOMPOUNDSUGS.aff')
+ endif
+
+ mkspell! XtestNOCOMPOUNDSUGS-utf8.spl XtestNOCOMPOUNDSUGS
+ set spell spelllang=XtestNOCOMPOUNDSUGS-utf8.spl
+
+ for goodword in ['one', 'two', 'three',
+ \ 'oneone', 'onetwo', 'onethree',
+ \ 'twoone', 'twotwo', 'twothree',
+ \ 'threeone', 'threetwo', 'threethree',
+ \ 'onetwothree', 'onethreetwo', 'twothreeone', 'oneoneone']
+ call assert_equal(['', ''], spellbadword(goodword), goodword)
+ endfor
+
+ for badword in ['four', 'onetwox', 'onexone']
+ call assert_equal([badword, 'bad'], spellbadword(badword))
+ endfor
+
+ if pass == 0
+ call assert_equal(['one', 'oneone'], spellsuggest('onne', 2))
+ call assert_equal(['onethree', 'one three'], spellsuggest('onethre', 2))
+ else
+ call assert_equal(['one', 'one one'], spellsuggest('onne', 2))
+ call assert_equal(['one three'], spellsuggest('onethre', 2))
+ endif
+ endfor
+
+ set spell& spelllang&
+ call delete('XtestNOCOMPOUNDSUGS.dic')
+ call delete('XtestNOCOMPOUNDSUGS.aff')
+ call delete('XtestNOCOMPOUNDSUGS-utf8.spl')
+endfunc
+
" Test COMMON (better suggestions with common words, see :help spell-COMMON)
func Test_spellfile_COMMON()
call writefile(['7',
diff --git a/src/nvim/testdir/test_startup.vim b/src/nvim/testdir/test_startup.vim
index e0dc0e0075..b140077111 100644
--- a/src/nvim/testdir/test_startup.vim
+++ b/src/nvim/testdir/test_startup.vim
@@ -27,8 +27,8 @@ func Test_after_comes_later()
set guioptions+=M
let $HOME = "/does/not/exist"
set loadplugins
- set rtp=Xhere,Xafter,Xanother
- set packpath=Xhere,Xafter
+ set rtp=Xhere,Xdir/after,Xanother
+ set packpath=Xhere,Xdir/after
set nomore
let g:sequence = ""
[CODE]
@@ -50,8 +50,8 @@ func Test_after_comes_later()
call mkdir('Xhere/pack/foo/start/foobar/plugin', 'p')
call writefile(['let g:sequence .= "pack "'], 'Xhere/pack/foo/start/foobar/plugin/foo.vim')
- call mkdir('Xafter/plugin', 'p')
- call writefile(['let g:sequence .= "after "'], 'Xafter/plugin/later.vim')
+ call mkdir('Xdir/after/plugin', 'p')
+ call writefile(['let g:sequence .= "after "'], 'Xdir/after/plugin/later.vim')
if RunVim(before, after, '')
@@ -74,7 +74,7 @@ func Test_after_comes_later()
call delete('Xsequence')
call delete('Xhere', 'rf')
call delete('Xanother', 'rf')
- call delete('Xafter', 'rf')
+ call delete('Xdir', 'rf')
endfunc
func Test_pack_in_rtp_when_plugins_run()
@@ -102,7 +102,7 @@ func Test_pack_in_rtp_when_plugins_run()
if RunVim(before, after, '')
let lines = filter(readfile('Xtestout'), '!empty(v:val)')
- call assert_match('Xhere[/\\]pack[/\\]foo[/\\]start[/\\]foobar', get(lines, 0))
+ call assert_match('runtimepath=Xhere', get(lines, 0))
call assert_match('autoloaded foo', get(lines, 1))
endif
diff --git a/src/nvim/testdir/test_swap.vim b/src/nvim/testdir/test_swap.vim
index f27920d20f..e3101d4e44 100644
--- a/src/nvim/testdir/test_swap.vim
+++ b/src/nvim/testdir/test_swap.vim
@@ -168,7 +168,6 @@ func Test_swapname()
endfunc
func Test_swapfile_delete()
- throw 'skipped: need the "blob" feature for this test'
autocmd! SwapExists
function s:swap_exists()
let v:swapchoice = s:swap_choice
@@ -319,6 +318,7 @@ func Test_swap_prompt_splitwin()
let buf = RunVimInTerminal('', {'rows': 20})
call term_sendkeys(buf, ":set nomore\n")
call term_sendkeys(buf, ":set noruler\n")
+
call term_sendkeys(buf, ":split Xfile1\n")
call term_wait(buf)
call WaitForAssert({-> assert_match('^\[O\]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort: $', term_getline(buf, 20))})
@@ -330,8 +330,19 @@ func Test_swap_prompt_splitwin()
call term_wait(buf)
call WaitForAssert({-> assert_match('^1$', term_getline(buf, 20))})
call StopVimInTerminal(buf)
+
+ " This caused Vim to crash when typing "q".
+ " TODO: it does not actually reproduce the crash.
+ call writefile(['au BufAdd * set virtualedit=all'], 'Xvimrc')
+
+ let buf = RunVimInTerminal('-u Xvimrc Xfile1', {'rows': 20, 'wait_for_ruler': 0})
+ call TermWait(buf)
+ call WaitForAssert({-> assert_match('^\[O\]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort:', term_getline(buf, 20))})
+ call term_sendkeys(buf, "q")
+
%bwipe!
call delete('Xfile1')
+ call delete('Xvimrc')
endfunc
func Test_swap_symlink()
@@ -364,4 +375,8 @@ func Test_swap_symlink()
call delete('Xswapdir', 'rf')
endfunc
+func Test_no_swap_file()
+ call assert_equal("\nNo swap file", execute('swapname'))
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_syntax.vim b/src/nvim/testdir/test_syntax.vim
index 875e23894f..914d9c2782 100644
--- a/src/nvim/testdir/test_syntax.vim
+++ b/src/nvim/testdir/test_syntax.vim
@@ -116,7 +116,7 @@ func Test_syntime()
let a = execute('syntime report')
call assert_equal("\nNo Syntax items defined for this buffer", a)
- view ../memfile_test.c
+ view samples/memfile_test.c
setfiletype cpp
redraw
let a = execute('syntime report')
@@ -546,8 +546,8 @@ func Test_synstack_synIDtrans()
call assert_equal([], synstack(1, 1))
norm f/
- call assert_equal(['cComment', 'cCommentStart'], map(synstack(line("."), col(".")), 'synIDattr(v:val, "name")'))
- call assert_equal(['Comment', 'Comment'], map(synstack(line("."), col(".")), 'synIDattr(synIDtrans(v:val), "name")'))
+ eval synstack(line("."), col("."))->map('synIDattr(v:val, "name")')->assert_equal(['cComment', 'cCommentStart'])
+ eval synstack(line("."), col("."))->map('synIDattr(synIDtrans(v:val), "name")')->assert_equal(['Comment', 'Comment'])
norm fA
call assert_equal(['cComment'], map(synstack(line("."), col(".")), 'synIDattr(v:val, "name")'))
diff --git a/src/nvim/testdir/test_system.vim b/src/nvim/testdir/test_system.vim
index 6bbe714d19..7b8ee778cc 100644
--- a/src/nvim/testdir/test_system.vim
+++ b/src/nvim/testdir/test_system.vim
@@ -7,10 +7,10 @@ func Test_System()
if !executable('echo') || !executable('cat') || !executable('wc')
return
endif
- let out = system('echo 123')
+ let out = 'echo 123'->system()
call assert_equal("123\n", out)
- let out = systemlist('echo 123')
+ let out = 'echo 123'->systemlist()
if &shell =~# 'cmd.exe$'
call assert_equal(["123\r"], out)
else
diff --git a/src/nvim/testdir/test_tagjump.vim b/src/nvim/testdir/test_tagjump.vim
index 9f02af7d8e..0fa7f85f0d 100644
--- a/src/nvim/testdir/test_tagjump.vim
+++ b/src/nvim/testdir/test_tagjump.vim
@@ -170,7 +170,7 @@ func Test_tag_symbolic()
call assert_equal('Xtest.c', expand('%:t'))
call assert_equal(2, col('.'))
- set hidden&
+ set nohidden
set tags&
enew!
call delete('Xtags')
@@ -548,6 +548,16 @@ func Test_tag_line_toolong()
call assert_equal('Xsomewhere', expand('%'))
call assert_equal(3, getcurpos()[1])
+ " expansion on command line works with long lines when &wildoptions contains
+ " 'tagfile'
+ set wildoptions=tagfile
+ call writefile([
+ \ 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa file /^pattern$/;" f'
+ \ ], 'Xtags')
+ call feedkeys(":tag \<Tab>", 'tx')
+ " Should not crash
+ call assert_true(v:true)
+
call delete('Xtags')
call delete('Xsomewhere')
set tags&
@@ -771,15 +781,16 @@ func Test_ltag()
ltag third
call assert_equal('Xfoo', bufname(''))
call assert_equal(3, line('.'))
- call assert_equal([{'lnum': 3, 'bufnr': bufnr('Xfoo'), 'col': 0,
- \ 'pattern': '', 'valid': 1, 'vcol': 0, 'nr': 0, 'type': '',
- \ 'module': '', 'text': 'third'}], getloclist(0))
+ call assert_equal([{'lnum': 3, 'end_lnum': 0, 'bufnr': bufnr('Xfoo'),
+ \ 'col': 0, 'end_col': 0, 'pattern': '', 'valid': 1, 'vcol': 0,
+ \ 'nr': 0, 'type': '', 'module': '', 'text': 'third'}], getloclist(0))
ltag second
call assert_equal(2, line('.'))
- call assert_equal([{'lnum': 0, 'bufnr': bufnr('Xfoo'), 'col': 0,
- \ 'pattern': '^\Vint second() {}\$', 'valid': 1, 'vcol': 0, 'nr': 0,
- \ 'type': '', 'module': '', 'text': 'second'}], getloclist(0))
+ call assert_equal([{'lnum': 0, 'end_lnum': 0, 'bufnr': bufnr('Xfoo'),
+ \ 'col': 0, 'end_col': 0, 'pattern': '^\Vint second() {}\$',
+ \ 'valid': 1, 'vcol': 0, 'nr': 0, 'type': '', 'module': '',
+ \ 'text': 'second'}], getloclist(0))
call delete('Xtags')
call delete('Xfoo')
diff --git a/src/nvim/testdir/test_textformat.vim b/src/nvim/testdir/test_textformat.vim
index 29f0433954..bf0706a0c2 100644
--- a/src/nvim/testdir/test_textformat.vim
+++ b/src/nvim/testdir/test_textformat.vim
@@ -975,6 +975,13 @@ func Test_fo_a_w()
exe "normal f4xx"
call assert_equal(['1 2 5 6 7 ', '8 9'], getline(1, 2))
+ " using "cw" leaves cursor in right spot
+ call setline(1, ['Now we g whether that nation, or',
+ \ 'any nation so conceived and,'])
+ set fo=tcqa tw=35
+ exe "normal 2G0cwx\<Esc>"
+ call assert_equal(['Now we g whether that nation, or x', 'nation so conceived and,'], getline(1, 2))
+
set tw=0
set fo&
%bw!
diff --git a/src/nvim/testdir/test_textobjects.vim b/src/nvim/testdir/test_textobjects.vim
index 9b800d0fa9..c259453b5e 100644
--- a/src/nvim/testdir/test_textobjects.vim
+++ b/src/nvim/testdir/test_textobjects.vim
@@ -89,101 +89,109 @@ endfunc
" Tests for string and html text objects
func Test_string_html_objects()
- enew!
- let t = '"wo\"rd\\" foo'
- put =t
- normal! da"
- call assert_equal('foo', getline('.'))
-
- let t = "'foo' 'bar' 'piep'"
- put =t
- normal! 0va'a'rx
- call assert_equal("xxxxxxxxxxxx'piep'", getline('.'))
-
- let t = "bla bla `quote` blah"
- put =t
- normal! 02f`da`
- call assert_equal("bla bla blah", getline('.'))
-
- let t = 'out " in "noXno"'
- put =t
- normal! 0fXdi"
- call assert_equal('out " in ""', getline('.'))
-
- let t = "\"'\" 'blah' rep 'buh'"
- put =t
- normal! 03f'vi'ry
- call assert_equal("\"'\" 'blah'yyyyy'buh'", getline('.'))
-
- set quoteescape=+*-
- let t = "bla `s*`d-`+++`l**` b`la"
- put =t
- normal! di`
- call assert_equal("bla `` b`la", getline('.'))
-
- let t = 'voo "nah" sdf " asdf" sdf " sdf" sd'
- put =t
- normal! $F"va"oha"i"rz
- call assert_equal('voo "zzzzzzzzzzzzzzzzzzzzzzzzzzzzsd', getline('.'))
-
- let t = "-<b>asdf<i>Xasdf</i>asdf</b>-"
- put =t
- normal! fXdit
- call assert_equal('-<b>asdf<i></i>asdf</b>-', getline('.'))
-
- let t = "-<b>asdX<i>a<i />sdf</i>asdf</b>-"
- put =t
- normal! 0fXdit
- call assert_equal('-<b></b>-', getline('.'))
-
- let t = "-<b>asdf<i>Xasdf</i>asdf</b>-"
- put =t
- normal! fXdat
- call assert_equal('-<b>asdfasdf</b>-', getline('.'))
-
- let t = "-<b>asdX<i>as<b />df</i>asdf</b>-"
- put =t
- normal! 0fXdat
- call assert_equal('--', getline('.'))
-
- let t = "-<b>\ninnertext object\n</b>"
- put =t
- normal! dit
- call assert_equal('-<b></b>', getline('.'))
-
- " copy the tag block from leading indentation before the start tag
- let t = " <b>\ntext\n</b>"
- $put =t
- normal! 2kvaty
- call assert_equal("<b>\ntext\n</b>", @")
-
- " copy the tag block from the end tag
- let t = "<title>\nwelcome\n</title>"
- $put =t
- normal! $vaty
- call assert_equal("<title>\nwelcome\n</title>", @")
-
- " copy the outer tag block from a tag without an end tag
- let t = "<html>\n<title>welcome\n</html>"
- $put =t
- normal! k$vaty
- call assert_equal("<html>\n<title>welcome\n</html>", @")
-
- " nested tag that has < in a different line from >
- let t = "<div><div\n></div></div>"
- $put =t
- normal! k0vaty
- call assert_equal("<div><div\n></div></div>", @")
-
- " nested tag with attribute that has < in a different line from >
- let t = "<div><div\nattr=\"attr\"\n></div></div>"
- $put =t
- normal! 2k0vaty
- call assert_equal("<div><div\nattr=\"attr\"\n></div></div>", @")
-
- set quoteescape&
- enew!
+ " Nvim only supports set encoding=utf-8
+ " for e in ['utf-8', 'latin1', 'cp932']
+ for e in ['utf-8']
+ enew!
+ exe 'set enc=' .. e
+
+ let t = '"wo\"rd\\" foo'
+ put =t
+ normal! da"
+ call assert_equal('foo', getline('.'), e)
+
+ let t = "'foo' 'bar' 'piep'"
+ put =t
+ normal! 0va'a'rx
+ call assert_equal("xxxxxxxxxxxx'piep'", getline('.'), e)
+
+ let t = "bla bla `quote` blah"
+ put =t
+ normal! 02f`da`
+ call assert_equal("bla bla blah", getline('.'), e)
+
+ let t = 'out " in "noXno"'
+ put =t
+ normal! 0fXdi"
+ call assert_equal('out " in ""', getline('.'), e)
+
+ let t = "\"'\" 'blah' rep 'buh'"
+ put =t
+ normal! 03f'vi'ry
+ call assert_equal("\"'\" 'blah'yyyyy'buh'", getline('.'), e)
+
+ set quoteescape=+*-
+ let t = "bla `s*`d-`+++`l**` b`la"
+ put =t
+ normal! di`
+ call assert_equal("bla `` b`la", getline('.'), e)
+
+ let t = 'voo "nah" sdf " asdf" sdf " sdf" sd'
+ put =t
+ normal! $F"va"oha"i"rz
+ call assert_equal('voo "zzzzzzzzzzzzzzzzzzzzzzzzzzzzsd', getline('.'), e)
+
+ let t = "-<b>asdf<i>Xasdf</i>asdf</b>-"
+ put =t
+ normal! fXdit
+ call assert_equal('-<b>asdf<i></i>asdf</b>-', getline('.'), e)
+
+ let t = "-<b>asdX<i>a<i />sdf</i>asdf</b>-"
+ put =t
+ normal! 0fXdit
+ call assert_equal('-<b></b>-', getline('.'), e)
+
+ let t = "-<b>asdf<i>Xasdf</i>asdf</b>-"
+ put =t
+ normal! fXdat
+ call assert_equal('-<b>asdfasdf</b>-', getline('.'), e)
+
+ let t = "-<b>asdX<i>as<b />df</i>asdf</b>-"
+ put =t
+ normal! 0fXdat
+ call assert_equal('--', getline('.'), e)
+
+ let t = "-<b>\ninnertext object\n</b>"
+ put =t
+ normal! dit
+ call assert_equal('-<b></b>', getline('.'), e)
+
+ " copy the tag block from leading indentation before the start tag
+ let t = " <b>\ntext\n</b>"
+ $put =t
+ normal! 2kvaty
+ call assert_equal("<b>\ntext\n</b>", @", e)
+
+ " copy the tag block from the end tag
+ let t = "<title>\nwelcome\n</title>"
+ $put =t
+ normal! $vaty
+ call assert_equal("<title>\nwelcome\n</title>", @", e)
+
+ " copy the outer tag block from a tag without an end tag
+ let t = "<html>\n<title>welcome\n</html>"
+ $put =t
+ normal! k$vaty
+ call assert_equal("<html>\n<title>welcome\n</html>", @", e)
+
+ " nested tag that has < in a different line from >
+ let t = "<div><div\n></div></div>"
+ $put =t
+ normal! k0vaty
+ call assert_equal("<div><div\n></div></div>", @", e)
+
+ " nested tag with attribute that has < in a different line from >
+ let t = "<div><div\nattr=\"attr\"\n></div></div>"
+ $put =t
+ normal! 2k0vaty
+ call assert_equal("<div><div\nattr=\"attr\"\n></div></div>", @", e)
+
+ set quoteescape&
+ endfor
+
+ set enc=utf-8
+ bwipe!
endfunc
func Test_empty_html_tag()
@@ -333,3 +341,84 @@ func Test_sentence_with_cursor_on_delimiter()
%delete _
endfunc
+
+" Test for quote (', " and `) textobjects
+func Test_textobj_quote()
+ new
+
+ " Test for i" when cursor is in front of a quoted object
+ call append(0, 'foo "bar"')
+ norm! 1gg0di"
+ call assert_equal(['foo ""', ''], getline(1,'$'))
+
+ " Test for visually selecting an inner quote
+ %d
+ " extend visual selection from one quote to the next
+ call setline(1, 'color "red" color "blue"')
+ call cursor(1, 7)
+ normal v4li"y
+ call assert_equal('"red" color "blue', @")
+
+ " try to extend visual selection from one quote to a non-existing quote
+ call setline(1, 'color "red" color blue')
+ call cursor(1, 7)
+ call feedkeys('v4li"y', 'xt')
+ call assert_equal('"red"', @")
+
+ " try to extend visual selection from one quote to a next partial quote
+ call setline(1, 'color "red" color "blue')
+ call cursor(1, 7)
+ normal v4li"y
+ call assert_equal('"red" color ', @")
+
+ " select a quote backwards in visual mode
+ call cursor(1, 12)
+ normal vhi"y
+ call assert_equal('red" ', @")
+ call assert_equal(8, col('.'))
+
+ " select a quote backwards in visual mode from outside the quote
+ call cursor(1, 17)
+ normal v2hi"y
+ call assert_equal('red', @")
+ call assert_equal(8, col('.'))
+
+ " visually selecting a quote with 'selection' set to 'exclusive'
+ call setline(1, 'He said "How are you?"')
+ set selection=exclusive
+ normal 012lv2li"y
+ call assert_equal('How are you?', @")
+ set selection&
+
+ " try copy a quote object with a single quote in the line
+ call setline(1, "Smith's car")
+ call cursor(1, 6)
+ call assert_beeps("normal yi'")
+ call assert_beeps("normal 2lyi'")
+
+ " selecting space before and after a quoted string
+ call setline(1, "some 'special' string")
+ normal 0ya'
+ call assert_equal("'special' ", @")
+ call setline(1, "some 'special'string")
+ normal 0ya'
+ call assert_equal(" 'special'", @")
+
+ " quoted string with odd or even number of backslashes.
+ call setline(1, 'char *s = "foo\"bar"')
+ normal $hhyi"
+ call assert_equal('foo\"bar', @")
+ call setline(1, 'char *s = "foo\\"bar"')
+ normal $hhyi"
+ call assert_equal('bar', @")
+ call setline(1, 'char *s = "foo\\\"bar"')
+ normal $hhyi"
+ call assert_equal('foo\\\"bar', @")
+ call setline(1, 'char *s = "foo\\\\"bar"')
+ normal $hhyi"
+ call assert_equal('bar', @")
+
+ close!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_undo.vim b/src/nvim/testdir/test_undo.vim
index 54caed3983..c7dcaa0f36 100644
--- a/src/nvim/testdir/test_undo.vim
+++ b/src/nvim/testdir/test_undo.vim
@@ -368,7 +368,6 @@ endfunc
" Check that reading a truncted undo file doesn't hang.
func Test_undofile_truncated()
- throw 'skipped: TODO: '
new
call setline(1, 'hello')
set ul=100
diff --git a/src/nvim/testdir/test_user_func.vim b/src/nvim/testdir/test_user_func.vim
index 7dcd92a54b..5231ef7b4f 100644
--- a/src/nvim/testdir/test_user_func.vim
+++ b/src/nvim/testdir/test_user_func.vim
@@ -47,7 +47,7 @@ func FuncWithRef(a)
endfunc
func Test_user_func()
- let g:FuncRef=function("FuncWithRef")
+ let g:FuncRef = function("FuncWithRef")
let g:counter = 0
inoremap <expr> ( ListItem()
inoremap <expr> [ ListReset()
@@ -62,6 +62,14 @@ func Test_user_func()
call assert_equal(9, g:retval)
call assert_equal(333, g:FuncRef(333))
+ let g:retval = "nop"
+ call assert_equal('xxx4asdf', "xxx"->Table(4, "asdf"))
+ call assert_equal('fail', 45->Compute(0, "retval"))
+ call assert_equal('nop', g:retval)
+ call assert_equal('ok', 45->Compute(5, "retval"))
+ call assert_equal(9, g:retval)
+ " call assert_equal(333, 333->g:FuncRef())
+
enew
normal oXX+-XX
@@ -150,6 +158,14 @@ func Test_default_arg()
\ execute('func Args2'))
endfunc
+func s:addFoo(lead)
+ return a:lead .. 'foo'
+endfunc
+
+func Test_user_method()
+ eval 'bar'->s:addFoo()->assert_equal('barfoo')
+endfunc
+
func Test_failed_call_in_try()
try | call UnknownFunc() | catch | endtry
endfunc
diff --git a/src/nvim/testdir/test_usercommands.vim b/src/nvim/testdir/test_usercommands.vim
index 4621207d19..29e578ac6d 100644
--- a/src/nvim/testdir/test_usercommands.vim
+++ b/src/nvim/testdir/test_usercommands.vim
@@ -238,6 +238,8 @@ func Test_CmdErrors()
call assert_fails('com! -complete=custom DoCmd :', 'E467:')
call assert_fails('com! -complete=customlist DoCmd :', 'E467:')
call assert_fails('com! -complete=behave,CustomComplete DoCmd :', 'E468:')
+ call assert_fails('com! -complete=file DoCmd :', 'E1208:')
+ call assert_fails('com! -nargs=0 -complete=file DoCmd :', 'E1208:')
call assert_fails('com! -nargs=x DoCmd :', 'E176:')
call assert_fails('com! -count=1 -count=2 DoCmd :', 'E177:')
call assert_fails('com! -count=x DoCmd :', 'E178:')
@@ -306,27 +308,33 @@ func Test_CmdCompletion()
call feedkeys(":com DoC\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"com DoC', @:)
- com! -complete=behave DoCmd :
+ com! -nargs=1 -complete=behave DoCmd :
call feedkeys(":DoCmd \<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"DoCmd mswin xterm', @:)
- " This does not work. Why?
- "call feedkeys(":DoCmd x\<C-A>\<C-B>\"\<CR>", 'tx')
- "call assert_equal('"DoCmd xterm', @:)
-
- com! -complete=custom,CustomComplete DoCmd :
+ com! -nargs=* -complete=custom,CustomComplete DoCmd :
call feedkeys(":DoCmd \<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"DoCmd January February Mars', @:)
- com! -complete=customlist,CustomCompleteList DoCmd :
+ com! -nargs=? -complete=customlist,CustomCompleteList DoCmd :
call feedkeys(":DoCmd \<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"DoCmd Monday Tuesday Wednesday', @:)
- com! -complete=custom,CustomCompleteList DoCmd :
+ com! -nargs=+ -complete=custom,CustomCompleteList DoCmd :
call assert_fails("call feedkeys(':DoCmd \<C-D>', 'tx')", 'E730:')
- com! -complete=customlist,CustomComp DoCmd :
+ com! -nargs=+ -complete=customlist,CustomComp DoCmd :
call assert_fails("call feedkeys(':DoCmd \<C-D>', 'tx')", 'E117:')
+
+ " custom completion without a function
+ com! -nargs=? -complete=custom, DoCmd
+ call assert_beeps("call feedkeys(':DoCmd \t', 'tx')")
+
+ " custom completion failure with the wrong function
+ com! -nargs=? -complete=custom,min DoCmd
+ call assert_fails("call feedkeys(':DoCmd \t', 'tx')", 'E118:')
+
+ delcom DoCmd
endfunc
func CallExecute(A, L, P)
@@ -459,21 +467,21 @@ func Test_command_list()
\ execute('command DoCmd'))
" Test with various -complete= argument values (non-exhaustive list)
- command! -complete=arglist DoCmd :
+ command! -nargs=1 -complete=arglist DoCmd :
call assert_equal("\n Name Args Address Complete Definition"
- \ .. "\n DoCmd 0 arglist :",
+ \ .. "\n DoCmd 1 arglist :",
\ execute('command DoCmd'))
- command! -complete=augroup DoCmd :
+ command! -nargs=* -complete=augroup DoCmd :
call assert_equal("\n Name Args Address Complete Definition"
- \ .. "\n DoCmd 0 augroup :",
+ \ .. "\n DoCmd * augroup :",
\ execute('command DoCmd'))
- command! -complete=custom,CustomComplete DoCmd :
+ command! -nargs=? -complete=custom,CustomComplete DoCmd :
call assert_equal("\n Name Args Address Complete Definition"
- \ .. "\n DoCmd 0 custom :",
+ \ .. "\n DoCmd ? custom :",
\ execute('command DoCmd'))
- command! -complete=customlist,CustomComplete DoCmd :
+ command! -nargs=+ -complete=customlist,CustomComplete DoCmd :
call assert_equal("\n Name Args Address Complete Definition"
- \ .. "\n DoCmd 0 customlist :",
+ \ .. "\n DoCmd + customlist :",
\ execute('command DoCmd'))
" Test with various -narg= argument values.
diff --git a/src/nvim/testdir/test_utf8.vim b/src/nvim/testdir/test_utf8.vim
index c51fb3a759..735efac36d 100644
--- a/src/nvim/testdir/test_utf8.vim
+++ b/src/nvim/testdir/test_utf8.vim
@@ -1,5 +1,6 @@
" Tests for Unicode manipulations
+source view_util.vim
" Visual block Insert adjusts for multi-byte char
func Test_visual_block_insert()
@@ -61,6 +62,40 @@ func Test_getvcol()
call assert_equal(2, virtcol("']"))
endfunc
+func Test_screenchar_utf8()
+ new
+
+ " 1-cell, with composing characters
+ call setline(1, ["ABC\u0308"])
+ redraw
+ call assert_equal([0x0041], screenchars(1, 1))
+ call assert_equal([0x0042], screenchars(1, 2))
+ call assert_equal([0x0043, 0x0308], screenchars(1, 3))
+ call assert_equal("A", screenstring(1, 1))
+ call assert_equal("B", screenstring(1, 2))
+ call assert_equal("C\u0308", screenstring(1, 3))
+
+ " 2-cells, with composing characters
+ let text = "\u3042\u3044\u3046\u3099"
+ call setline(1, text)
+ redraw
+ call assert_equal([0x3042], screenchars(1, 1))
+ call assert_equal([0], screenchars(1, 2))
+ call assert_equal([0x3044], screenchars(1, 3))
+ call assert_equal([0], screenchars(1, 4))
+ call assert_equal([0x3046, 0x3099], screenchars(1, 5))
+
+ call assert_equal("\u3042", screenstring(1, 1))
+ call assert_equal("", screenstring(1, 2))
+ call assert_equal("\u3044", screenstring(1, 3))
+ call assert_equal("", screenstring(1, 4))
+ call assert_equal("\u3046\u3099", screenstring(1, 5))
+
+ call assert_equal([text . ' '], ScreenLines(1, 8))
+
+ bwipe!
+endfunc
+
func Test_list2str_str2list_utf8()
" One Unicode codepoint
let s = "\u3042\u3044"
diff --git a/src/nvim/testdir/test_vimscript.vim b/src/nvim/testdir/test_vimscript.vim
index 5922660ef9..b18ce563d3 100644
--- a/src/nvim/testdir/test_vimscript.vim
+++ b/src/nvim/testdir/test_vimscript.vim
@@ -1152,6 +1152,10 @@ func Test_type()
call assert_equal(v:t_float, type(0.0))
call assert_equal(v:t_bool, type(v:false))
call assert_equal(v:t_bool, type(v:true))
+ call assert_equal(v:t_string, type(v:_null_string))
+ call assert_equal(v:t_list, type(v:_null_list))
+ call assert_equal(v:t_dict, type(v:_null_dict))
+ call assert_equal(v:t_blob, type(v:_null_blob))
endfunc
"-------------------------------------------------------------------------------
@@ -1372,6 +1376,7 @@ func Test_bitwise_functions()
" and
call assert_equal(127, and(127, 127))
call assert_equal(16, and(127, 16))
+ eval 127->and(16)->assert_equal(16)
call assert_equal(0, and(127, 128))
call assert_fails("call and(1.0, 1)", 'E805:')
call assert_fails("call and([], 1)", 'E745:')
@@ -1382,6 +1387,7 @@ func Test_bitwise_functions()
" or
call assert_equal(23, or(16, 7))
call assert_equal(15, or(8, 7))
+ eval 8->or(7)->assert_equal(15)
call assert_equal(123, or(0, 123))
call assert_fails("call or(1.0, 1)", 'E805:')
call assert_fails("call or([], 1)", 'E745:')
@@ -1392,6 +1398,7 @@ func Test_bitwise_functions()
" xor
call assert_equal(0, xor(127, 127))
call assert_equal(111, xor(127, 16))
+ eval 127->xor(16)->assert_equal(111)
call assert_equal(255, xor(127, 128))
call assert_fails("call xor(1.0, 1)", 'E805:')
call assert_fails("call xor([], 1)", 'E745:')
@@ -1401,6 +1408,7 @@ func Test_bitwise_functions()
call assert_fails("call xor(1, {})", 'E728:')
" invert
call assert_equal(65408, and(invert(127), 65535))
+ eval 127->invert()->and(65535)->assert_equal(65408)
call assert_equal(65519, and(invert(16), 65535))
call assert_equal(65407, and(invert(128), 65535))
call assert_fails("call invert(1.0)", 'E805:')
diff --git a/src/nvim/testdir/test_visual.vim b/src/nvim/testdir/test_visual.vim
index b7c5717bd2..dbabdcf427 100644
--- a/src/nvim/testdir/test_visual.vim
+++ b/src/nvim/testdir/test_visual.vim
@@ -2,6 +2,7 @@
source shared.vim
source check.vim
+source screendump.vim
func Test_block_shift_multibyte()
" Uses double-wide character.
@@ -860,6 +861,15 @@ func Test_visual_block_mode()
set tabstop& shiftwidth&
endfunc
+func Test_visual_force_motion_feedkeys()
+ onoremap <expr> i- execute('let g:mode = mode(1)')
+ call feedkeys('dvi-', 'x')
+ call assert_equal('nov', g:mode)
+ call feedkeys('di-', 'x')
+ call assert_equal('no', g:mode)
+ ounmap i-
+endfunc
+
" Test block-insert using cursor keys for movement
func Test_visual_block_insert_cursor_keys()
new
@@ -1082,5 +1092,25 @@ func Test_visual_put_blockedit_zy_and_zp()
bw!
endfunc
+func Test_visual_block_with_virtualedit()
+ CheckScreendump
+
+ let lines =<< trim END
+ call setline(1, ['aaaaaa', 'bbbb', 'cc'])
+ set virtualedit=block
+ normal G
+ END
+ call writefile(lines, 'XTest_block')
+
+ let buf = RunVimInTerminal('-S XTest_block', {'rows': 8, 'cols': 50})
+ call term_sendkeys(buf, "\<C-V>gg$")
+ call VerifyScreenDump(buf, 'Test_visual_block_with_virtualedit', {})
+
+ " clean up
+ call term_sendkeys(buf, "\<Esc>")
+ call StopVimInTerminal(buf)
+ call delete('XTest_beval')
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_window_cmd.vim b/src/nvim/testdir/test_window_cmd.vim
index a522705238..039de0c623 100644
--- a/src/nvim/testdir/test_window_cmd.vim
+++ b/src/nvim/testdir/test_window_cmd.vim
@@ -608,7 +608,7 @@ func Test_window_prevwin()
" reset
q
call delete('tmp.txt')
- set hidden&vim autoread&vim
+ set nohidden autoread&vim
delfunc Fun_RenewFile
endfunc
diff --git a/src/nvim/testdir/test_writefile.vim b/src/nvim/testdir/test_writefile.vim
index 6922e2185d..aa7882d129 100644
--- a/src/nvim/testdir/test_writefile.vim
+++ b/src/nvim/testdir/test_writefile.vim
@@ -17,6 +17,8 @@ func Test_writefile()
call assert_equal("morning", l[3])
call assert_equal("vimmers", l[4])
call delete(f)
+
+ call assert_fails('call writefile("text", "Xfile")', 'E475: Invalid argument: writefile() first argument must be a List or a Blob')
endfunc
func Test_writefile_ignore_regexp_error()
@@ -189,6 +191,14 @@ func Test_saveas()
close!
enew | only
call delete('Xfile')
+
+ " :saveas should detect and set the file type.
+ syntax on
+ saveas! Xsaveas.pl
+ call assert_equal('perl', &filetype)
+ syntax off
+ %bw!
+ call delete('Xsaveas.pl')
endfunc
func Test_write_errors()
diff --git a/src/nvim/testdir/view_util.vim b/src/nvim/testdir/view_util.vim
index 1def201a05..1cdce21602 100644
--- a/src/nvim/testdir/view_util.vim
+++ b/src/nvim/testdir/view_util.vim
@@ -16,6 +16,7 @@ func Screenline(lnum)
return matchstr(line, '^.\{-}\ze\s*$')
endfunc
+" Get text on the screen, including composing characters.
" ScreenLines(lnum, width) or
" ScreenLines([start, end], width)
function! ScreenLines(lnum, width) abort
@@ -29,7 +30,7 @@ function! ScreenLines(lnum, width) abort
endif
let lines = []
for l in range(start, end)
- let lines += [join(map(range(1, a:width), 'nr2char(screenchar(l, v:val))'), '')]
+ let lines += [join(map(range(1, a:width), 'screenstring(l, v:val)'), '')]
endfor
return lines
endfunction
diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c
index 6705ab98c2..ec277f7a4e 100644
--- a/src/nvim/tui/input.c
+++ b/src/nvim/tui/input.c
@@ -2,19 +2,19 @@
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
-#include "nvim/tui/input.h"
-#include "nvim/vim.h"
-#include "nvim/api/vim.h"
#include "nvim/api/private/helpers.h"
+#include "nvim/api/vim.h"
#include "nvim/ascii.h"
-#include "nvim/charset.h"
-#include "nvim/main.h"
-#include "nvim/macros.h"
#include "nvim/aucmd.h"
+#include "nvim/charset.h"
#include "nvim/ex_docmd.h"
+#include "nvim/macros.h"
+#include "nvim/main.h"
#include "nvim/option.h"
-#include "nvim/os/os.h"
#include "nvim/os/input.h"
+#include "nvim/os/os.h"
+#include "nvim/tui/input.h"
+#include "nvim/vim.h"
#ifdef WIN32
# include "nvim/os/os_win_console.h"
#endif
@@ -53,7 +53,7 @@ void tinput_init(TermInput *input, Loop *loop)
// ls *.md | xargs nvim
#ifdef WIN32
if (!os_isatty(input->in_fd)) {
- input->in_fd = os_get_conin_fd();
+ input->in_fd = os_get_conin_fd();
}
#else
if (!os_isatty(input->in_fd) && os_isatty(STDERR_FILENO)) {
@@ -279,25 +279,25 @@ static void forward_mouse_event(TermInput *input, TermKeyKey *key)
}
switch (ev) {
- case TERMKEY_MOUSE_PRESS:
- if (button == 4) {
- len += (size_t)snprintf(buf + len, sizeof(buf) - len, "ScrollWheelUp");
- } else if (button == 5) {
- len += (size_t)snprintf(buf + len, sizeof(buf) - len,
- "ScrollWheelDown");
- } else {
- len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Mouse");
- last_pressed_button = button;
- }
- break;
- case TERMKEY_MOUSE_DRAG:
- len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Drag");
- break;
- case TERMKEY_MOUSE_RELEASE:
- len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Release");
- break;
- case TERMKEY_MOUSE_UNKNOWN:
- abort();
+ case TERMKEY_MOUSE_PRESS:
+ if (button == 4) {
+ len += (size_t)snprintf(buf + len, sizeof(buf) - len, "ScrollWheelUp");
+ } else if (button == 5) {
+ len += (size_t)snprintf(buf + len, sizeof(buf) - len,
+ "ScrollWheelDown");
+ } else {
+ len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Mouse");
+ last_pressed_button = button;
+ }
+ break;
+ case TERMKEY_MOUSE_DRAG:
+ len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Drag");
+ break;
+ case TERMKEY_MOUSE_RELEASE:
+ len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Release");
+ break;
+ case TERMKEY_MOUSE_UNKNOWN:
+ abort();
}
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "><%d,%d>", col, row);
@@ -428,7 +428,7 @@ static bool handle_forced_escape(TermInput *input)
// skip the ESC and NUL and push one <esc> to the input buffer
size_t rcnt;
termkey_push_bytes(input->tk, rbuffer_read_ptr(input->read_stream.buffer,
- &rcnt), 1);
+ &rcnt), 1);
rbuffer_consumed(input->read_stream.buffer, 2);
tk_getkeys(input, true);
return true;
@@ -618,8 +618,7 @@ static void handle_raw_buffer(TermInput *input, bool force)
} while (rbuffer_size(input->read_stream.buffer));
}
-static void tinput_read_cb(Stream *stream, RBuffer *buf, size_t count_,
- void *data, bool eof)
+static void tinput_read_cb(Stream *stream, RBuffer *buf, size_t count_, void *data, bool eof)
{
TermInput *input = data;
@@ -637,7 +636,7 @@ static void tinput_read_cb(Stream *stream, RBuffer *buf, size_t count_,
// If 'ttimeout' is not set, start the timer with a timeout of 0 to process
// the next input.
long ms = input->ttimeout ?
- (input->ttimeoutlen >= 0 ? input->ttimeoutlen : 0) : 0;
+ (input->ttimeoutlen >= 0 ? input->ttimeoutlen : 0) : 0;
// Stop the current timer if already running
time_watcher_stop(&input->timer_handle);
time_watcher_start(&input->timer_handle, tinput_timer_cb, (uint32_t)ms, 0);
diff --git a/src/nvim/tui/terminfo.c b/src/nvim/tui/terminfo.c
index ff2a357752..ce48059b94 100644
--- a/src/nvim/tui/terminfo.c
+++ b/src/nvim/tui/terminfo.c
@@ -5,11 +5,10 @@
#include <stdbool.h>
#include <string.h>
-
#include <unibilium.h>
-#include "nvim/log.h"
#include "nvim/globals.h"
+#include "nvim/log.h"
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/option.h"
@@ -29,12 +28,12 @@ bool terminfo_is_term_family(const char *term, const char *family)
size_t tlen = strlen(term);
size_t flen = strlen(family);
return tlen >= flen
- && 0 == memcmp(term, family, flen)
- // Per commentary in terminfo, minus is the only valid suffix separator.
- // The screen terminfo may have a terminal name like screen.xterm. By making
- // the dot(.) a valid separator, such terminal names will also be the
- // terminal family of the screen.
- && ('\0' == term[flen] || '-' == term[flen] || '.' == term[flen]);
+ && 0 == memcmp(term, family, flen)
+ // Per commentary in terminfo, minus is the only valid suffix separator.
+ // The screen terminfo may have a terminal name like screen.xterm. By making
+ // the dot(.) a valid separator, such terminal names will also be the
+ // terminal family of the screen.
+ && ('\0' == term[flen] || '-' == term[flen] || '.' == term[flen]);
}
bool terminfo_is_bsd_console(const char *term)
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index 6e885279a9..803ff23cea 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -4,47 +4,45 @@
// Terminal UI functions. Invoked (by ui_bridge.c) on the TUI thread.
#include <assert.h>
+#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
-#include <limits.h>
-
-#include <uv.h>
#include <unibilium.h>
+#include <uv.h>
#if defined(HAVE_TERMIOS_H)
# include <termios.h>
#endif
-#include "nvim/lib/kvec.h"
-
+#include "nvim/api/private/helpers.h"
+#include "nvim/api/vim.h"
#include "nvim/ascii.h"
-#include "nvim/vim.h"
-#include "nvim/log.h"
-#include "nvim/ui.h"
+#include "nvim/event/loop.h"
+#include "nvim/event/signal.h"
#include "nvim/highlight.h"
-#include "nvim/map.h"
+#include "nvim/lib/kvec.h"
+#include "nvim/log.h"
#include "nvim/main.h"
+#include "nvim/map.h"
#include "nvim/memory.h"
#include "nvim/option.h"
-#include "nvim/api/vim.h"
-#include "nvim/api/private/helpers.h"
-#include "nvim/event/loop.h"
-#include "nvim/event/signal.h"
#include "nvim/os/input.h"
#include "nvim/os/os.h"
#include "nvim/os/signal.h"
#include "nvim/os/tty.h"
+#include "nvim/ui.h"
+#include "nvim/vim.h"
#ifdef WIN32
# include "nvim/os/os_win_console.h"
#endif
+#include "nvim/cursor_shape.h"
+#include "nvim/macros.h"
#include "nvim/strings.h"
#include "nvim/syntax.h"
-#include "nvim/ui_bridge.h"
-#include "nvim/ugrid.h"
#include "nvim/tui/input.h"
-#include "nvim/tui/tui.h"
#include "nvim/tui/terminfo.h"
-#include "nvim/cursor_shape.h"
-#include "nvim/macros.h"
+#include "nvim/tui/tui.h"
+#include "nvim/ugrid.h"
+#include "nvim/ui_bridge.h"
// Space reserved in two output buffers to make the cursor normal or invisible
// when flushing. No existing terminal will require 32 bytes to do that.
@@ -53,20 +51,20 @@
#define TOO_MANY_EVENTS 1000000
#define STARTS_WITH(str, prefix) \
- (strlen(str) >= (sizeof(prefix) - 1) \
- && 0 == memcmp((str), (prefix), sizeof(prefix) - 1))
+ (strlen(str) >= (sizeof(prefix) - 1) \
+ && 0 == memcmp((str), (prefix), sizeof(prefix) - 1))
#define TMUX_WRAP(is_tmux, seq) \
- ((is_tmux) ? "\x1bPtmux;\x1b" seq "\x1b\\" : seq)
+ ((is_tmux) ? "\x1bPtmux;\x1b" seq "\x1b\\" : seq)
#define LINUXSET0C "\x1b[?0c"
#define LINUXSET1C "\x1b[?1c"
#ifdef NVIM_UNIBI_HAS_VAR_FROM
-#define UNIBI_SET_NUM_VAR(var, num) \
+# define UNIBI_SET_NUM_VAR(var, num) \
do { \
- (var) = unibi_var_from_num((num)); \
+ (var) = unibi_var_from_num((num)); \
} while (0)
#else
-#define UNIBI_SET_NUM_VAR(var, num) (var).i = (num);
+# define UNIBI_SET_NUM_VAR(var, num) (var).i = (num);
#endif
typedef struct {
@@ -180,8 +178,7 @@ UI *tui_start(void)
return ui_bridge_attach(ui, tui_main, tui_scheduler);
}
-static size_t unibi_pre_fmt_str(TUIData *data, unsigned int unibi_index,
- char * buf, size_t len)
+static size_t unibi_pre_fmt_str(TUIData *data, unsigned int unibi_index, char * buf, size_t len)
{
const char *str = unibi_get_str(data->ut, unibi_index);
if (!str) {
@@ -263,10 +260,10 @@ static void terminfo_start(UI *ui)
long vtev = vte_version_env ? strtol(vte_version_env, NULL, 10) : 0;
bool iterm_env = termprg && strstr(termprg, "iTerm.app");
bool nsterm = (termprg && strstr(termprg, "Apple_Terminal"))
- || terminfo_is_term_family(term, "nsterm");
+ || terminfo_is_term_family(term, "nsterm");
bool konsole = terminfo_is_term_family(term, "konsole")
- || os_getenv("KONSOLE_PROFILE_NAME")
- || os_getenv("KONSOLE_DBUS_SESSION");
+ || os_getenv("KONSOLE_PROFILE_NAME")
+ || os_getenv("KONSOLE_DBUS_SESSION");
const char *konsolev_env = os_getenv("KONSOLE_VERSION");
long konsolev = konsolev_env ? strtol(konsolev_env, NULL, 10)
: (konsole ? 1 : 0);
@@ -508,15 +505,15 @@ static bool attrs_differ(UI *ui, int id1, int id2, bool rgb)
if (rgb) {
return a1.rgb_fg_color != a2.rgb_fg_color
- || a1.rgb_bg_color != a2.rgb_bg_color
- || a1.rgb_ae_attr != a2.rgb_ae_attr
- || a1.rgb_sp_color != a2.rgb_sp_color;
+ || a1.rgb_bg_color != a2.rgb_bg_color
+ || a1.rgb_ae_attr != a2.rgb_ae_attr
+ || a1.rgb_sp_color != a2.rgb_sp_color;
} else {
return a1.cterm_fg_color != a2.cterm_fg_color
- || a1.cterm_bg_color != a2.cterm_bg_color
- || a1.cterm_ae_attr != a2.cterm_ae_attr
- || (a1.cterm_ae_attr & (HL_UNDERLINE|HL_UNDERCURL)
- && a1.rgb_sp_color != a2.rgb_sp_color);
+ || a1.cterm_bg_color != a2.cterm_bg_color
+ || a1.cterm_ae_attr != a2.cterm_ae_attr
+ || (a1.cterm_ae_attr & (HL_UNDERLINE|HL_UNDERCURL)
+ && a1.rgb_sp_color != a2.rgb_sp_color);
}
}
@@ -593,10 +590,10 @@ static void update_attrs(UI *ui, int attr_id)
if ((undercurl || underline) && data->unibi_ext.set_underline_color != -1) {
int color = attrs.rgb_sp_color;
if (color != -1) {
- UNIBI_SET_NUM_VAR(data->params[0], (color >> 16) & 0xff); // red
- UNIBI_SET_NUM_VAR(data->params[1], (color >> 8) & 0xff); // green
- UNIBI_SET_NUM_VAR(data->params[2], color & 0xff); // blue
- unibi_out_ext(ui, data->unibi_ext.set_underline_color);
+ UNIBI_SET_NUM_VAR(data->params[0], (color >> 16) & 0xff); // red
+ UNIBI_SET_NUM_VAR(data->params[1], (color >> 8) & 0xff); // green
+ UNIBI_SET_NUM_VAR(data->params[2], color & 0xff); // blue
+ unibi_out_ext(ui, data->unibi_ext.set_underline_color);
}
}
@@ -639,14 +636,14 @@ static void update_attrs(UI *ui, int attr_id)
data->default_attr = fg == -1 && bg == -1
- && !bold && !italic && !underline && !undercurl && !reverse && !standout
- && !strikethrough;
+ && !bold && !italic && !underline && !undercurl && !reverse && !standout
+ && !strikethrough;
// Non-BCE terminals can't clear with non-default background color. Some BCE
// terminals don't support attributes either, so don't rely on it. But assume
// italic and bold has no effect if there is no text.
data->can_clear_attr = !reverse && !standout && !underline && !undercurl
- && !strikethrough && (data->bce || bg == -1);
+ && !strikethrough && (data->bce || bg == -1);
}
static void final_column_wrap(UI *ui)
@@ -802,8 +799,7 @@ safe_move:
ugrid_goto(grid, row, col);
}
-static void clear_region(UI *ui, int top, int bot, int left, int right,
- int attr_id)
+static void clear_region(UI *ui, int top, int bot, int left, int right, int attr_id)
{
TUIData *data = ui->data;
UGrid *grid = &data->grid;
@@ -1006,7 +1002,7 @@ static void tui_mode_info_set(UI *ui, bool guicursor_enabled, Array args)
static void tui_update_menu(UI *ui)
{
- // Do nothing; menus are for GUI only
+ // Do nothing; menus are for GUI only
}
static void tui_busy_start(UI *ui)
@@ -1025,7 +1021,7 @@ static void tui_mouse_on(UI *ui)
if (!data->mouse_enabled) {
#ifdef WIN32
// Windows versions with vtp(ENABLE_VIRTUAL_TERMINAL_PROCESSING) and
- // no vti(ENABLE_VIRTUAL_TERMINAL_INPUT) will need to use mouse traking of
+ // no vti(ENABLE_VIRTUAL_TERMINAL_INPUT) will need to use mouse tracking of
// libuv. For this reason, vtp (vterm) state of libuv is temporarily
// disabled because the control sequence needs to be processed by libuv
// instead of Windows vtp.
@@ -1048,7 +1044,7 @@ static void tui_mouse_off(UI *ui)
if (data->mouse_enabled) {
#ifdef WIN32
// Windows versions with vtp(ENABLE_VIRTUAL_TERMINAL_PROCESSING) and
- // no vti(ENABLE_VIRTUAL_TERMINAL_INPUT) will need to use mouse traking of
+ // no vti(ENABLE_VIRTUAL_TERMINAL_INPUT) will need to use mouse tracking of
// libuv. For this reason, vtp (vterm) state of libuv is temporarily
// disabled because the control sequence needs to be processed by libuv
// instead of Windows vtp.
@@ -1096,10 +1092,14 @@ static void tui_set_mode(UI *ui, ModeShape mode)
int shape;
switch (c.shape) {
- default: abort(); break;
- case SHAPE_BLOCK: shape = 1; break;
- case SHAPE_HOR: shape = 3; break;
- case SHAPE_VER: shape = 5; break;
+ default:
+ abort(); break;
+ case SHAPE_BLOCK:
+ shape = 1; break;
+ case SHAPE_HOR:
+ shape = 3; break;
+ case SHAPE_VER:
+ shape = 5; break;
}
UNIBI_SET_NUM_VAR(data->params[0], shape + (int)(c.blinkon == 0));
unibi_out_ext(ui, data->unibi_ext.set_cursor_style);
@@ -1123,9 +1123,9 @@ static void tui_mode_change(UI *ui, String mode, Integer mode_idx)
data->showing_mode = (ModeShape)mode_idx;
}
-static void tui_grid_scroll(UI *ui, Integer g, Integer startrow, Integer endrow,
- Integer startcol, Integer endcol,
- Integer rows, Integer cols FUNC_ATTR_UNUSED)
+static void tui_grid_scroll(UI *ui, Integer g, Integer startrow, // -V751
+ Integer endrow, Integer startcol, Integer endcol, Integer rows,
+ Integer cols FUNC_ATTR_UNUSED)
{
TUIData *data = ui->data;
UGrid *grid = &data->grid;
@@ -1134,16 +1134,16 @@ static void tui_grid_scroll(UI *ui, Integer g, Integer startrow, Integer endrow,
bool fullwidth = left == 0 && right == ui->width-1;
data->scroll_region_is_full_screen = fullwidth
- && top == 0 && bot == ui->height-1;
+ && top == 0 && bot == ui->height-1;
ugrid_scroll(grid, top, bot, left, right, (int)rows);
bool can_scroll = data->can_scroll
- && (data->scroll_region_is_full_screen
- || (data->can_change_scroll_region
- && ((left == 0 && right == ui->width - 1)
- || data->can_set_lr_margin
- || data->can_set_left_right_margin)));
+ && (data->scroll_region_is_full_screen
+ || (data->can_change_scroll_region
+ && ((left == 0 && right == ui->width - 1)
+ || data->can_set_lr_margin
+ || data->can_set_left_right_margin)));
if (can_scroll) {
// Change terminal scroll region and move cursor to the top
@@ -1184,8 +1184,7 @@ static void tui_grid_scroll(UI *ui, Integer g, Integer startrow, Integer endrow,
}
}
-static void tui_hl_attr_define(UI *ui, Integer id, HlAttrs attrs,
- HlAttrs cterm_attrs, Array info)
+static void tui_hl_attr_define(UI *ui, Integer id, HlAttrs attrs, HlAttrs cterm_attrs, Array info)
{
TUIData *data = ui->data;
kv_a(data->attrs, (size_t)id) = attrs;
@@ -1201,8 +1200,7 @@ static void tui_visual_bell(UI *ui)
unibi_out(ui, unibi_flash_screen);
}
-static void tui_default_colors_set(UI *ui, Integer rgb_fg, Integer rgb_bg,
- Integer rgb_sp,
+static void tui_default_colors_set(UI *ui, Integer rgb_fg, Integer rgb_bg, Integer rgb_sp,
Integer cterm_fg, Integer cterm_bg)
{
TUIData *data = ui->data;
@@ -1379,9 +1377,8 @@ static void tui_option_set(UI *ui, String name, Object value)
}
}
-static void tui_raw_line(UI *ui, Integer g, Integer linerow, Integer startcol,
- Integer endcol, Integer clearcol, Integer clearattr,
- LineFlags flags, const schar_T *chunk,
+static void tui_raw_line(UI *ui, Integer g, Integer linerow, Integer startcol, Integer endcol,
+ Integer clearcol, Integer clearattr, LineFlags flags, const schar_T *chunk,
const sattr_T *attrs)
{
TUIData *data = ui->data;
@@ -1461,8 +1458,8 @@ static void tui_guess_size(UI *ui)
did_user_set_dimensions = true;
assert(Columns >= INT_MIN && Columns <= INT_MAX);
assert(Rows >= INT_MIN && Rows <= INT_MAX);
- width = (int)Columns;
- height = (int)Rows;
+ width = Columns;
+ height = Rows;
goto end;
}
@@ -1486,7 +1483,7 @@ static void tui_guess_size(UI *ui)
height = unibi_get_num(data->ut, unibi_lines);
width = unibi_get_num(data->ut, unibi_columns);
-end:
+ end:
if (width <= 0 || height <= 0) {
// use the defaults
width = DFLT_COLS;
@@ -1561,8 +1558,7 @@ static void out(void *ctx, const char *str, size_t len)
data->bufpos += len;
}
-static void unibi_set_if_empty(unibi_term *ut, enum unibi_string str,
- const char *val)
+static void unibi_set_if_empty(unibi_term *ut, enum unibi_string str, const char *val)
{
if (!unibi_get_str(ut, str)) {
unibi_set_str(ut, str, val);
@@ -1596,9 +1592,8 @@ static int unibi_find_ext_bool(unibi_term *ut, const char *name)
/// Patches the terminfo records after loading from system or built-in db.
/// Several entries in terminfo are known to be deficient or outright wrong;
/// and several terminal emulators falsely announce incorrect terminal types.
-static void patch_terminfo_bugs(TUIData *data, const char *term,
- const char *colorterm, long vte_version,
- long konsolev, bool iterm_env, bool nsterm)
+static void patch_terminfo_bugs(TUIData *data, const char *term, const char *colorterm,
+ long vte_version, long konsolev, bool iterm_env, bool nsterm)
{
unibi_term *ut = data->ut;
const char *xterm_version = os_getenv("XTERM_VERSION");
@@ -1606,8 +1601,8 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
bool roxterm = !!os_getenv("ROXTERM_ID");
#endif
bool xterm = terminfo_is_term_family(term, "xterm")
- // Treat Terminal.app as generic xterm-like, for now.
- || nsterm;
+ // Treat Terminal.app as generic xterm-like, for now.
+ || nsterm;
bool kitty = terminfo_is_term_family(term, "xterm-kitty");
bool linuxvt = terminfo_is_term_family(term, "linux");
bool bsdvt = terminfo_is_bsd_console(term);
@@ -1618,18 +1613,18 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
bool tmux = terminfo_is_term_family(term, "tmux") || !!os_getenv("TMUX");
bool st = terminfo_is_term_family(term, "st");
bool gnome = terminfo_is_term_family(term, "gnome")
- || terminfo_is_term_family(term, "vte");
+ || terminfo_is_term_family(term, "vte");
bool iterm = terminfo_is_term_family(term, "iterm")
- || terminfo_is_term_family(term, "iterm2")
- || terminfo_is_term_family(term, "iTerm.app")
- || terminfo_is_term_family(term, "iTerm2.app");
+ || terminfo_is_term_family(term, "iterm2")
+ || terminfo_is_term_family(term, "iTerm.app")
+ || terminfo_is_term_family(term, "iTerm2.app");
bool alacritty = terminfo_is_term_family(term, "alacritty");
// None of the following work over SSH; see :help TERM .
bool iterm_pretending_xterm = xterm && iterm_env;
bool gnome_pretending_xterm = xterm && colorterm
- && strstr(colorterm, "gnome-terminal");
+ && strstr(colorterm, "gnome-terminal");
bool mate_pretending_xterm = xterm && colorterm
- && strstr(colorterm, "mate-terminal");
+ && strstr(colorterm, "mate-terminal");
bool true_xterm = xterm && !!xterm_version && !bsdvt;
bool cygwin = terminfo_is_term_family(term, "cygwin");
@@ -1839,8 +1834,8 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
data->unibi_ext.set_cursor_style =
(int)unibi_add_ext_str(ut, "Ss", "\x1b[%p1%d q");
if (-1 == data->unibi_ext.reset_cursor_style) {
- data->unibi_ext.reset_cursor_style = (int)unibi_add_ext_str(ut, "Se",
- "");
+ data->unibi_ext.reset_cursor_style = (int)unibi_add_ext_str(ut, "Se",
+ "");
}
unibi_set_ext_str(ut, (size_t)data->unibi_ext.reset_cursor_style,
"\x1b[ q");
@@ -1849,25 +1844,25 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
// does not support DECSCUSR.
// See http://linuxgazette.net/137/anonymous.html for more info
data->unibi_ext.set_cursor_style = (int)unibi_add_ext_str(ut, "Ss",
- "\x1b[?"
- "%?"
- // The parameter passed to Ss is the DECSCUSR parameter, so the
- // terminal capability has to translate into the Linux idiosyncratic
- // parameter.
- //
- // linuxvt only supports block and underline. It is also only
- // possible to have a steady block (no steady underline)
- "%p1%{2}%<" "%t%{8}" // blink block
- "%e%p1%{2}%=" "%t%{112}" // steady block
- "%e%p1%{3}%=" "%t%{4}" // blink underline (set to half block)
- "%e%p1%{4}%=" "%t%{4}" // steady underline
- "%e%p1%{5}%=" "%t%{2}" // blink bar (set to underline)
- "%e%p1%{6}%=" "%t%{2}" // steady bar
- "%e%{0}" // anything else
- "%;" "%dc");
+ "\x1b[?"
+ "%?"
+ // The parameter passed to Ss is the DECSCUSR parameter, so the
+ // terminal capability has to translate into the Linux idiosyncratic
+ // parameter.
+ //
+ // linuxvt only supports block and underline. It is also only
+ // possible to have a steady block (no steady underline)
+ "%p1%{2}%<" "%t%{8}" // blink block
+ "%e%p1%{2}%=" "%t%{112}" // steady block
+ "%e%p1%{3}%=" "%t%{4}" // blink underline (set to half block)
+ "%e%p1%{4}%=" "%t%{4}" // steady underline
+ "%e%p1%{5}%=" "%t%{2}" // blink bar (set to underline)
+ "%e%p1%{6}%=" "%t%{2}" // steady bar
+ "%e%{0}" // anything else
+ "%;" "%dc");
if (-1 == data->unibi_ext.reset_cursor_style) {
- data->unibi_ext.reset_cursor_style = (int)unibi_add_ext_str(ut, "Se",
- "");
+ data->unibi_ext.reset_cursor_style = (int)unibi_add_ext_str(ut, "Se",
+ "");
}
unibi_set_ext_str(ut, (size_t)data->unibi_ext.reset_cursor_style,
"\x1b[?c");
@@ -1875,34 +1870,34 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
// Konsole before version 18.07.70: set up a nonce profile. This has
// side-effects on temporary font resizing. #6798
data->unibi_ext.set_cursor_style = (int)unibi_add_ext_str(ut, "Ss",
- TMUX_WRAP(tmux, "\x1b]50;CursorShape=%?"
- "%p1%{3}%<" "%t%{0}" // block
- "%e%p1%{5}%<" "%t%{2}" // underline
- "%e%{1}" // everything else is bar
- "%;%d;BlinkingCursorEnabled=%?"
- "%p1%{1}%<" "%t%{1}" // Fortunately if we exclude zero as special,
- "%e%p1%{1}%&" // in all other cases we can treat bit #0 as a flag.
- "%;%d\x07"));
+ TMUX_WRAP(tmux,
+ "\x1b]50;CursorShape=%?"
+ "%p1%{3}%<" "%t%{0}" // block
+ "%e%p1%{5}%<" "%t%{2}" // underline
+ "%e%{1}" // everything else is bar
+ "%;%d;BlinkingCursorEnabled=%?"
+ "%p1%{1}%<" "%t%{1}" // Fortunately if we exclude zero as special,
+ "%e%p1%{1}%&" // in all other cases we can treat bit #0 as a flag.
+ "%;%d\x07"));
if (-1 == data->unibi_ext.reset_cursor_style) {
- data->unibi_ext.reset_cursor_style = (int)unibi_add_ext_str(ut, "Se",
- "");
+ data->unibi_ext.reset_cursor_style = (int)unibi_add_ext_str(ut, "Se",
+ "");
}
unibi_set_ext_str(ut, (size_t)data->unibi_ext.reset_cursor_style,
- "\x1b]50;\x07");
+ "\x1b]50;\x07");
}
}
}
/// This adds stuff that is not in standard terminfo as extended unibilium
/// capabilities.
-static void augment_terminfo(TUIData *data, const char *term,
- long vte_version,
- long konsolev, bool iterm_env, bool nsterm)
+static void augment_terminfo(TUIData *data, const char *term, long vte_version, long konsolev,
+ bool iterm_env, bool nsterm)
{
unibi_term *ut = data->ut;
bool xterm = terminfo_is_term_family(term, "xterm")
- // Treat Terminal.app as generic xterm-like, for now.
- || nsterm;
+ // Treat Terminal.app as generic xterm-like, for now.
+ || nsterm;
bool bsdvt = terminfo_is_bsd_console(term);
bool dtterm = terminfo_is_term_family(term, "dtterm");
bool rxvt = terminfo_is_term_family(term, "rxvt");
@@ -1911,9 +1906,9 @@ static void augment_terminfo(TUIData *data, const char *term,
bool screen = terminfo_is_term_family(term, "screen");
bool tmux = terminfo_is_term_family(term, "tmux") || !!os_getenv("TMUX");
bool iterm = terminfo_is_term_family(term, "iterm")
- || terminfo_is_term_family(term, "iterm2")
- || terminfo_is_term_family(term, "iTerm.app")
- || terminfo_is_term_family(term, "iTerm2.app");
+ || terminfo_is_term_family(term, "iterm2")
+ || terminfo_is_term_family(term, "iTerm.app")
+ || terminfo_is_term_family(term, "iTerm2.app");
bool alacritty = terminfo_is_term_family(term, "alacritty");
// None of the following work over SSH; see :help TERM .
bool iterm_pretending_xterm = xterm && iterm_env;
@@ -1928,19 +1923,18 @@ static void augment_terminfo(TUIData *data, const char *term,
|| teraterm // per TeraTerm "Supported Control Functions" doco
|| rxvt) { // per command.C
data->unibi_ext.resize_screen = (int)unibi_add_ext_str(ut,
- "ext.resize_screen",
- "\x1b[8;%p1%d;%p2%dt");
+ "ext.resize_screen",
+ "\x1b[8;%p1%d;%p2%dt");
}
if (putty || xterm || rxvt) {
data->unibi_ext.reset_scroll_region = (int)unibi_add_ext_str(ut,
- "ext.reset_scroll_region",
- "\x1b[r");
+ "ext.reset_scroll_region",
+ "\x1b[r");
}
// terminfo describes strikethrough modes as rmxx/smxx with respect
// to the ECMA-48 strikeout/crossed-out attributes.
- data->unibi_ext.enter_strikethrough_mode = (int)unibi_find_ext_str(
- ut, "smxx");
+ data->unibi_ext.enter_strikethrough_mode = unibi_find_ext_str(ut, "smxx");
// Dickey ncurses terminfo does not include the setrgbf and setrgbb
// capabilities, proposed by Rüdiger Sonderfeld on 2013-10-15. Adding
@@ -1955,29 +1949,29 @@ static void augment_terminfo(TUIData *data, const char *term,
// can use colons like ISO 8613-6:1994/ITU T.416:1993 says.
bool has_colon_rgb = !tmux && !screen
- && !vte_version // VTE colon-support has a big memory leak. #7573
- && (iterm || iterm_pretending_xterm // per VT100Terminal.m
- // per http://invisible-island.net/xterm/xterm.log.html#xterm_282
- || true_xterm);
+ && !vte_version // VTE colon-support has a big memory leak. #7573
+ && (iterm || iterm_pretending_xterm // per VT100Terminal.m
+ // per http://invisible-island.net/xterm/xterm.log.html#xterm_282
+ || true_xterm);
data->unibi_ext.set_rgb_foreground = unibi_find_ext_str(ut, "setrgbf");
if (-1 == data->unibi_ext.set_rgb_foreground) {
if (has_colon_rgb) {
data->unibi_ext.set_rgb_foreground = (int)unibi_add_ext_str(ut, "setrgbf",
- "\x1b[38:2:%p1%d:%p2%d:%p3%dm");
+ "\x1b[38:2:%p1%d:%p2%d:%p3%dm");
} else {
data->unibi_ext.set_rgb_foreground = (int)unibi_add_ext_str(ut, "setrgbf",
- "\x1b[38;2;%p1%d;%p2%d;%p3%dm");
+ "\x1b[38;2;%p1%d;%p2%d;%p3%dm");
}
}
data->unibi_ext.set_rgb_background = unibi_find_ext_str(ut, "setrgbb");
if (-1 == data->unibi_ext.set_rgb_background) {
if (has_colon_rgb) {
data->unibi_ext.set_rgb_background = (int)unibi_add_ext_str(ut, "setrgbb",
- "\x1b[48:2:%p1%d:%p2%d:%p3%dm");
+ "\x1b[48:2:%p1%d:%p2%d:%p3%dm");
} else {
data->unibi_ext.set_rgb_background = (int)unibi_add_ext_str(ut, "setrgbb",
- "\x1b[48;2;%p1%d;%p2%d;%p3%dm");
+ "\x1b[48;2;%p1%d;%p2%d;%p3%dm");
}
}
@@ -1985,63 +1979,59 @@ static void augment_terminfo(TUIData *data, const char *term,
// FIXME: Bypassing tmux like this affects the cursor colour globally, in
// all panes, which is not particularly desirable. A better approach
// would use a tmux control sequence and an extra if(screen) test.
- data->unibi_ext.set_cursor_color = (int)unibi_add_ext_str(
- ut, NULL, TMUX_WRAP(tmux, "\033]Pl%p1%06x\033\\"));
+ data->unibi_ext.set_cursor_color =
+ (int)unibi_add_ext_str(ut, NULL, TMUX_WRAP(tmux, "\033]Pl%p1%06x\033\\"));
} else if ((xterm || rxvt || tmux || alacritty)
&& (vte_version == 0 || vte_version >= 3900)) {
// Supported in urxvt, newer VTE.
- data->unibi_ext.set_cursor_color = (int)unibi_add_ext_str(
- ut, "ext.set_cursor_color", "\033]12;#%p1%06x\007");
+ data->unibi_ext.set_cursor_color = (int)unibi_add_ext_str(ut, "ext.set_cursor_color",
+ "\033]12;#%p1%06x\007");
}
if (-1 != data->unibi_ext.set_cursor_color) {
- data->unibi_ext.reset_cursor_color = (int)unibi_add_ext_str(
- ut, "ext.reset_cursor_color", "\x1b]112\x07");
+ data->unibi_ext.reset_cursor_color = (int)unibi_add_ext_str(ut, "ext.reset_cursor_color",
+ "\x1b]112\x07");
}
- data->unibi_ext.save_title = (int)unibi_add_ext_str(
- ut, "ext.save_title", "\x1b[22;0t");
- data->unibi_ext.restore_title = (int)unibi_add_ext_str(
- ut, "ext.restore_title", "\x1b[23;0t");
+ data->unibi_ext.save_title = (int)unibi_add_ext_str(ut, "ext.save_title", "\x1b[22;0t");
+ data->unibi_ext.restore_title = (int)unibi_add_ext_str(ut, "ext.restore_title", "\x1b[23;0t");
/// Terminals usually ignore unrecognized private modes, and there is no
/// known ambiguity with these. So we just set them unconditionally.
- data->unibi_ext.enable_lr_margin = (int)unibi_add_ext_str(
- ut, "ext.enable_lr_margin", "\x1b[?69h");
- data->unibi_ext.disable_lr_margin = (int)unibi_add_ext_str(
- ut, "ext.disable_lr_margin", "\x1b[?69l");
- data->unibi_ext.enable_bracketed_paste = (int)unibi_add_ext_str(
- ut, "ext.enable_bpaste", "\x1b[?2004h");
- data->unibi_ext.disable_bracketed_paste = (int)unibi_add_ext_str(
- ut, "ext.disable_bpaste", "\x1b[?2004l");
+ data->unibi_ext.enable_lr_margin =
+ (int)unibi_add_ext_str(ut, "ext.enable_lr_margin", "\x1b[?69h");
+ data->unibi_ext.disable_lr_margin = (int)unibi_add_ext_str(ut, "ext.disable_lr_margin",
+ "\x1b[?69l");
+ data->unibi_ext.enable_bracketed_paste = (int)unibi_add_ext_str(ut, "ext.enable_bpaste",
+ "\x1b[?2004h");
+ data->unibi_ext.disable_bracketed_paste = (int)unibi_add_ext_str(ut, "ext.disable_bpaste",
+ "\x1b[?2004l");
// For urxvt send BOTH xterm and old urxvt sequences. #8695
- data->unibi_ext.enable_focus_reporting = (int)unibi_add_ext_str(
- ut, "ext.enable_focus",
- rxvt ? "\x1b[?1004h\x1b]777;focus;on\x7" : "\x1b[?1004h");
- data->unibi_ext.disable_focus_reporting = (int)unibi_add_ext_str(
- ut, "ext.disable_focus",
- rxvt ? "\x1b[?1004l\x1b]777;focus;off\x7" : "\x1b[?1004l");
- data->unibi_ext.enable_mouse = (int)unibi_add_ext_str(
- ut, "ext.enable_mouse", "\x1b[?1002h\x1b[?1006h");
- data->unibi_ext.disable_mouse = (int)unibi_add_ext_str(
- ut, "ext.disable_mouse", "\x1b[?1002l\x1b[?1006l");
+ data->unibi_ext.enable_focus_reporting = (int)unibi_add_ext_str(ut, "ext.enable_focus",
+ rxvt ? "\x1b[?1004h\x1b]777;focus;on\x7" : "\x1b[?1004h");
+ data->unibi_ext.disable_focus_reporting = (int)unibi_add_ext_str(ut, "ext.disable_focus",
+ rxvt ? "\x1b[?1004l\x1b]777;focus;off\x7" : "\x1b[?1004l");
+ data->unibi_ext.enable_mouse = (int)unibi_add_ext_str(ut, "ext.enable_mouse",
+ "\x1b[?1002h\x1b[?1006h");
+ data->unibi_ext.disable_mouse = (int)unibi_add_ext_str(ut, "ext.disable_mouse",
+ "\x1b[?1002l\x1b[?1006l");
// Extended underline.
// terminfo will have Smulx for this (but no support for colors yet).
data->unibi_ext.set_underline_style = unibi_find_ext_str(ut, "Smulx");
if (data->unibi_ext.set_underline_style == -1) {
- int ext_bool_Su = unibi_find_ext_bool(ut, "Su"); // used by kitty
- if (vte_version >= 5102
- || (ext_bool_Su != -1
- && unibi_get_ext_bool(ut, (size_t)ext_bool_Su))) {
- data->unibi_ext.set_underline_style = (int)unibi_add_ext_str(
- ut, "ext.set_underline_style", "\x1b[4:%p1%dm");
- }
+ int ext_bool_Su = unibi_find_ext_bool(ut, "Su"); // used by kitty
+ if (vte_version >= 5102
+ || (ext_bool_Su != -1
+ && unibi_get_ext_bool(ut, (size_t)ext_bool_Su))) {
+ data->unibi_ext.set_underline_style = (int)unibi_add_ext_str(ut, "ext.set_underline_style",
+ "\x1b[4:%p1%dm");
+ }
}
if (data->unibi_ext.set_underline_style != -1) {
- // Only support colon syntax. #9270
- data->unibi_ext.set_underline_color = (int)unibi_add_ext_str(
- ut, "ext.set_underline_color", "\x1b[58:2::%p1%d:%p2%d:%p3%dm");
+ // Only support colon syntax. #9270
+ data->unibi_ext.set_underline_color = (int)unibi_add_ext_str(ut, "ext.set_underline_color",
+ "\x1b[58:2::%p1%d:%p2%d:%p3%dm");
}
}
@@ -2121,21 +2111,20 @@ static void flush_buf(UI *ui)
static const char *tui_get_stty_erase(void)
{
static char stty_erase[2] = { 0 };
-#if defined(HAVE_TERMIOS_H)
+# if defined(HAVE_TERMIOS_H)
struct termios t;
if (tcgetattr(input_global_fd(), &t) != -1) {
stty_erase[0] = (char)t.c_cc[VERASE];
stty_erase[1] = '\0';
DLOG("stty/termios:erase=%s", stty_erase);
}
-#endif
+# endif
return stty_erase;
}
/// libtermkey hook to override terminfo entries.
/// @see TermInput.tk_ti_hook_fn
-static const char *tui_tk_ti_getstr(const char *name, const char *value,
- void *data)
+static const char *tui_tk_ti_getstr(const char *name, const char *value, void *data)
{
static const char *stty_erase = NULL;
if (stty_erase == NULL) {
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index 94b6e9e39d..09709d0f43 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -69,9 +69,16 @@ static int pending_has_mouse = -1;
#else
static size_t uilog_seen = 0;
static char uilog_last_event[1024] = { 0 };
+
+#ifndef EXITFREE
+#define entered_free_all_mem false
+#endif
+
# define UI_LOG(funname) \
do { \
- if (strequal(uilog_last_event, STR(funname))) { \
+ if (entered_free_all_mem) { \
+ /* do nothing, we cannot log now */ \
+ } else if (strequal(uilog_last_event, STR(funname))) { \
uilog_seen++; \
} else { \
if (uilog_seen > 0) { \
@@ -107,6 +114,10 @@ static char uilog_last_event[1024] = { 0 };
# include "ui_events_call.generated.h"
#endif
+#ifndef EXITFREE
+#undef entered_free_all_mem
+#endif
+
void ui_init(void)
{
default_grid.handle = 1;
diff --git a/src/nvim/ui_bridge.c b/src/nvim/ui_bridge.c
index 25f45b8fe6..bc64414ecf 100644
--- a/src/nvim/ui_bridge.c
+++ b/src/nvim/ui_bridge.c
@@ -41,6 +41,8 @@ UI *ui_bridge_attach(UI *ui, ui_main_fn ui_main, event_scheduler scheduler)
UIBridgeData *rv = xcalloc(1, sizeof(UIBridgeData));
rv->ui = ui;
rv->bridge.rgb = ui->rgb;
+ rv->bridge.width = ui->width;
+ rv->bridge.height = ui->height;
rv->bridge.stop = ui_bridge_stop;
rv->bridge.grid_resize = ui_bridge_grid_resize;
rv->bridge.grid_clear = ui_bridge_grid_clear;
diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c
index 1ec5189795..9c9aec1cf5 100644
--- a/src/nvim/ui_compositor.c
+++ b/src/nvim/ui_compositor.c
@@ -214,7 +214,7 @@ void ui_comp_remove_grid(ScreenGrid *grid)
grid->comp_index = 0;
// recompose the area under the grid
- // inefficent when being overlapped: only draw up to grid->comp_index
+ // inefficient when being overlapped: only draw up to grid->comp_index
ui_comp_compose_grid(grid);
}
@@ -594,7 +594,7 @@ static void ui_comp_msg_set_pos(UI *ui, Integer grid, Integer row,
int first_row = MAX((int)row-(scrolled?1:0), 0);
compose_area(first_row, Rows-delta, 0, Columns);
} else {
- // scroll separator togheter with message text
+ // scroll separator together with message text
int first_row = MAX((int)row-(msg_was_scrolled?1:0), 0);
ui_composed_call_grid_scroll(1, first_row, Rows, 0, Columns, delta, 0);
if (scrolled && !msg_was_scrolled && row > 0) {
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index ffd613cec2..fb96d7e6ff 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -234,7 +234,7 @@ int u_save(linenr_T top, linenr_T bot)
if (top + 2 == bot)
u_saveline((linenr_T)(top + 1));
- return u_savecommon(top, bot, (linenr_T)0, FALSE);
+ return u_savecommon(curbuf, top, bot, (linenr_T)0, false);
}
/*
@@ -245,7 +245,7 @@ int u_save(linenr_T top, linenr_T bot)
*/
int u_savesub(linenr_T lnum)
{
- return u_savecommon(lnum - 1, lnum + 1, lnum + 1, false);
+ return u_savecommon(curbuf, lnum - 1, lnum + 1, lnum + 1, false);
}
/*
@@ -256,7 +256,7 @@ int u_savesub(linenr_T lnum)
*/
int u_inssub(linenr_T lnum)
{
- return u_savecommon(lnum - 1, lnum, lnum + 1, false);
+ return u_savecommon(curbuf, lnum - 1, lnum, lnum + 1, false);
}
/*
@@ -268,18 +268,19 @@ int u_inssub(linenr_T lnum)
*/
int u_savedel(linenr_T lnum, long nlines)
{
- return u_savecommon(lnum - 1, lnum + nlines,
- nlines == curbuf->b_ml.ml_line_count ? 2 : lnum, FALSE);
+ return u_savecommon(
+ curbuf, lnum - 1, lnum + nlines,
+ nlines == curbuf->b_ml.ml_line_count ? 2 : lnum, false);
}
/// Return true when undo is allowed. Otherwise print an error message and
/// return false.
///
/// @return true if undo is allowed.
-bool undo_allowed(void)
+bool undo_allowed(buf_T *buf)
{
- /* Don't allow changes when 'modifiable' is off. */
- if (!MODIFIABLE(curbuf)) {
+ // Don't allow changes when 'modifiable' is off.
+ if (!MODIFIABLE(buf)) {
EMSG(_(e_modifiable));
return false;
}
@@ -301,12 +302,12 @@ bool undo_allowed(void)
}
/// Get the 'undolevels' value for the current buffer.
-static long get_undolevel(void)
+static long get_undolevel(buf_T *buf)
{
- if (curbuf->b_p_ul == NO_LOCAL_UNDOLEVEL) {
+ if (buf->b_p_ul == NO_LOCAL_UNDOLEVEL) {
return p_ul;
}
- return curbuf->b_p_ul;
+ return buf->b_p_ul;
}
static inline void zero_fmark_additional_data(fmark_T *fmarks)
@@ -326,7 +327,9 @@ static inline void zero_fmark_additional_data(fmark_T *fmarks)
* Careful: may trigger autocommands that reload the buffer.
* Returns FAIL when lines could not be saved, OK otherwise.
*/
-int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload)
+int u_savecommon(buf_T *buf,
+ linenr_T top, linenr_T bot,
+ linenr_T newbot, int reload)
{
linenr_T lnum;
long i;
@@ -337,22 +340,23 @@ int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload)
long size;
if (!reload) {
- /* When making changes is not allowed return FAIL. It's a crude way
- * to make all change commands fail. */
- if (!undo_allowed())
+ // When making changes is not allowed return FAIL. It's a crude way
+ // to make all change commands fail.
+ if (!undo_allowed(buf)) {
return FAIL;
+ }
+ // Saving text for undo means we are going to make a change. Give a
+ // warning for a read-only file before making the change, so that the
+ // FileChangedRO event can replace the buffer with a read-write version
+ // (e.g., obtained from a source control system).
+ if (buf == curbuf) {
+ change_warning(buf, 0);
+ }
- /*
- * Saving text for undo means we are going to make a change. Give a
- * warning for a read-only file before making the change, so that the
- * FileChangedRO event can replace the buffer with a read-write version
- * (e.g., obtained from a source control system).
- */
- change_warning(0);
- if (bot > curbuf->b_ml.ml_line_count + 1) {
- /* This happens when the FileChangedRO autocommand changes the
- * file in a way it becomes shorter. */
+ if (bot > buf->b_ml.ml_line_count + 1) {
+ // This happens when the FileChangedRO autocommand changes the
+ // file in a way it becomes shorter.
EMSG(_("E881: Line count changed unexpectedly"));
return FAIL;
}
@@ -364,18 +368,14 @@ int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload)
size = bot - top - 1;
- /*
- * If curbuf->b_u_synced == true make a new header.
- */
- if (curbuf->b_u_synced) {
- /* Need to create new entry in b_changelist. */
- curbuf->b_new_change = true;
-
- if (get_undolevel() >= 0) {
- /*
- * Make a new header entry. Do this first so that we don't mess
- * up the undo info when out of memory.
- */
+ // If curbuf->b_u_synced == true make a new header.
+ if (buf->b_u_synced) {
+ // Need to create new entry in b_changelist.
+ buf->b_new_change = true;
+
+ if (get_undolevel(buf) >= 0) {
+ // Make a new header entry. Do this first so that we don't mess
+ // up the undo info when out of memory.
uhp = xmalloc(sizeof(u_header_T));
kv_init(uhp->uh_extmark);
#ifdef U_DEBUG
@@ -388,63 +388,73 @@ int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload)
* If we undid more than we redid, move the entry lists before and
* including curbuf->b_u_curhead to an alternate branch.
*/
- old_curhead = curbuf->b_u_curhead;
+ old_curhead = buf->b_u_curhead;
if (old_curhead != NULL) {
- curbuf->b_u_newhead = old_curhead->uh_next.ptr;
- curbuf->b_u_curhead = NULL;
+ buf->b_u_newhead = old_curhead->uh_next.ptr;
+ buf->b_u_curhead = NULL;
}
/*
* free headers to keep the size right
*/
- while (curbuf->b_u_numhead > get_undolevel()
- && curbuf->b_u_oldhead != NULL) {
- u_header_T *uhfree = curbuf->b_u_oldhead;
-
- if (uhfree == old_curhead)
- /* Can't reconnect the branch, delete all of it. */
- u_freebranch(curbuf, uhfree, &old_curhead);
- else if (uhfree->uh_alt_next.ptr == NULL)
- /* There is no branch, only free one header. */
- u_freeheader(curbuf, uhfree, &old_curhead);
- else {
- /* Free the oldest alternate branch as a whole. */
- while (uhfree->uh_alt_next.ptr != NULL)
+ while (buf->b_u_numhead > get_undolevel(buf)
+ && buf->b_u_oldhead != NULL) {
+ u_header_T *uhfree = buf->b_u_oldhead;
+
+ if (uhfree == old_curhead) {
+ // Can't reconnect the branch, delete all of it.
+ u_freebranch(buf, uhfree, &old_curhead);
+ } else if (uhfree->uh_alt_next.ptr == NULL) {
+ // There is no branch, only free one header.
+ u_freeheader(buf, uhfree, &old_curhead);
+ } else {
+ // Free the oldest alternate branch as a whole.
+ while (uhfree->uh_alt_next.ptr != NULL) {
uhfree = uhfree->uh_alt_next.ptr;
- u_freebranch(curbuf, uhfree, &old_curhead);
+ }
+ u_freebranch(buf, uhfree, &old_curhead);
}
#ifdef U_DEBUG
u_check(TRUE);
#endif
}
- if (uhp == NULL) { /* no undo at all */
- if (old_curhead != NULL)
- u_freebranch(curbuf, old_curhead, NULL);
- curbuf->b_u_synced = false;
+ if (uhp == NULL) { // no undo at all
+ if (old_curhead != NULL) {
+ u_freebranch(buf, old_curhead, NULL);
+ }
+ buf->b_u_synced = false;
return OK;
}
uhp->uh_prev.ptr = NULL;
- uhp->uh_next.ptr = curbuf->b_u_newhead;
+ uhp->uh_next.ptr = buf->b_u_newhead;
uhp->uh_alt_next.ptr = old_curhead;
if (old_curhead != NULL) {
uhp->uh_alt_prev.ptr = old_curhead->uh_alt_prev.ptr;
- if (uhp->uh_alt_prev.ptr != NULL)
+
+ if (uhp->uh_alt_prev.ptr != NULL) {
uhp->uh_alt_prev.ptr->uh_alt_next.ptr = uhp;
+ }
+
old_curhead->uh_alt_prev.ptr = uhp;
- if (curbuf->b_u_oldhead == old_curhead)
- curbuf->b_u_oldhead = uhp;
- } else
+
+ if (buf->b_u_oldhead == old_curhead) {
+ buf->b_u_oldhead = uhp;
+ }
+ } else {
uhp->uh_alt_prev.ptr = NULL;
- if (curbuf->b_u_newhead != NULL)
- curbuf->b_u_newhead->uh_prev.ptr = uhp;
+ }
+
+ if (buf->b_u_newhead != NULL) {
+ buf->b_u_newhead->uh_prev.ptr = uhp;
+ }
- uhp->uh_seq = ++curbuf->b_u_seq_last;
- curbuf->b_u_seq_cur = uhp->uh_seq;
+ uhp->uh_seq = ++buf->b_u_seq_last;
+ buf->b_u_seq_cur = uhp->uh_seq;
uhp->uh_time = time(NULL);
uhp->uh_save_nr = 0;
- curbuf->b_u_time_cur = uhp->uh_time + 1;
+ buf->b_u_time_cur = uhp->uh_time + 1;
uhp->uh_walk = 0;
uhp->uh_entry = NULL;
@@ -455,23 +465,26 @@ int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload)
else
uhp->uh_cursor_vcol = -1;
- /* save changed and buffer empty flag for undo */
- uhp->uh_flags = (curbuf->b_changed ? UH_CHANGED : 0) +
- ((curbuf->b_ml.ml_flags & ML_EMPTY) ? UH_EMPTYBUF : 0);
+ // save changed and buffer empty flag for undo
+ uhp->uh_flags = (buf->b_changed ? UH_CHANGED : 0) +
+ ((buf->b_ml.ml_flags & ML_EMPTY) ? UH_EMPTYBUF : 0);
- /* save named marks and Visual marks for undo */
- zero_fmark_additional_data(curbuf->b_namedm);
- memmove(uhp->uh_namedm, curbuf->b_namedm,
- sizeof(curbuf->b_namedm[0]) * NMARKS);
- uhp->uh_visual = curbuf->b_visual;
+ // save named marks and Visual marks for undo
+ zero_fmark_additional_data(buf->b_namedm);
+ memmove(uhp->uh_namedm, buf->b_namedm,
+ sizeof(buf->b_namedm[0]) * NMARKS);
+ uhp->uh_visual = buf->b_visual;
- curbuf->b_u_newhead = uhp;
- if (curbuf->b_u_oldhead == NULL)
- curbuf->b_u_oldhead = uhp;
- ++curbuf->b_u_numhead;
+ buf->b_u_newhead = uhp;
+
+ if (buf->b_u_oldhead == NULL) {
+ buf->b_u_oldhead = uhp;
+ }
+ buf->b_u_numhead++;
} else {
- if (get_undolevel() < 0) /* no undo at all */
+ if (get_undolevel(buf) < 0) { // no undo at all
return OK;
+ }
/*
* When saving a single line, and it has been saved just before, it
@@ -483,7 +496,7 @@ int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload)
* long.
*/
if (size == 1) {
- uep = u_get_headentry();
+ uep = u_get_headentry(buf);
prev_uep = NULL;
for (i = 0; i < 10; ++i) {
if (uep == NULL)
@@ -491,16 +504,17 @@ int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload)
/* If lines have been inserted/deleted we give up.
* Also when the line was included in a multi-line save. */
- if ((curbuf->b_u_newhead->uh_getbot_entry != uep
+ if ((buf->b_u_newhead->uh_getbot_entry != uep
? (uep->ue_top + uep->ue_size + 1
!= (uep->ue_bot == 0
- ? curbuf->b_ml.ml_line_count + 1
+ ? buf->b_ml.ml_line_count + 1
: uep->ue_bot))
- : uep->ue_lcount != curbuf->b_ml.ml_line_count)
+ : uep->ue_lcount != buf->b_ml.ml_line_count)
|| (uep->ue_size > 1
&& top >= uep->ue_top
- && top + 2 <= uep->ue_top + uep->ue_size + 1))
+ && top + 2 <= uep->ue_top + uep->ue_size + 1)) {
break;
+ }
/* If it's the same line we can skip saving it again. */
if (uep->ue_size == 1 && uep->ue_top == top) {
@@ -508,8 +522,8 @@ int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload)
/* It's not the last entry: get ue_bot for the last
* entry now. Following deleted/inserted lines go to
* the re-used entry. */
- u_getbot();
- curbuf->b_u_synced = false;
+ u_getbot(buf);
+ buf->b_u_synced = false;
/* Move the found entry to become the last entry. The
* order of undo/redo doesn't matter for the entries
@@ -518,18 +532,18 @@ int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload)
* for the found entry if the line count is changed by
* the executed command. */
prev_uep->ue_next = uep->ue_next;
- uep->ue_next = curbuf->b_u_newhead->uh_entry;
- curbuf->b_u_newhead->uh_entry = uep;
+ uep->ue_next = buf->b_u_newhead->uh_entry;
+ buf->b_u_newhead->uh_entry = uep;
}
- /* The executed command may change the line count. */
- if (newbot != 0)
+ // The executed command may change the line count.
+ if (newbot != 0) {
uep->ue_bot = newbot;
- else if (bot > curbuf->b_ml.ml_line_count)
+ } else if (bot > buf->b_ml.ml_line_count) {
uep->ue_bot = 0;
- else {
- uep->ue_lcount = curbuf->b_ml.ml_line_count;
- curbuf->b_u_newhead->uh_getbot_entry = uep;
+ } else {
+ uep->ue_lcount = buf->b_ml.ml_line_count;
+ buf->b_u_newhead->uh_getbot_entry = uep;
}
return OK;
}
@@ -538,8 +552,8 @@ int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload)
}
}
- /* find line number for ue_bot for previous u_save() */
- u_getbot();
+ // find line number for ue_bot for previous u_save()
+ u_getbot(buf);
}
/*
@@ -553,17 +567,15 @@ int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload)
uep->ue_size = size;
uep->ue_top = top;
- if (newbot != 0)
+ if (newbot != 0) {
uep->ue_bot = newbot;
- /*
- * Use 0 for ue_bot if bot is below last line.
- * Otherwise we have to compute ue_bot later.
- */
- else if (bot > curbuf->b_ml.ml_line_count)
+ // Use 0 for ue_bot if bot is below last line.
+ // Otherwise we have to compute ue_bot later.
+ } else if (bot > buf->b_ml.ml_line_count) {
uep->ue_bot = 0;
- else {
- uep->ue_lcount = curbuf->b_ml.ml_line_count;
- curbuf->b_u_newhead->uh_getbot_entry = uep;
+ } else {
+ uep->ue_lcount = buf->b_ml.ml_line_count;
+ buf->b_u_newhead->uh_getbot_entry = uep;
}
if (size > 0) {
@@ -574,17 +586,19 @@ int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload)
u_freeentry(uep, i);
return FAIL;
}
- uep->ue_array[i] = u_save_line(lnum++);
+ uep->ue_array[i] = u_save_line_buf(buf, lnum++);
}
- } else
+ } else {
uep->ue_array = NULL;
- uep->ue_next = curbuf->b_u_newhead->uh_entry;
- curbuf->b_u_newhead->uh_entry = uep;
+ }
+
+ uep->ue_next = buf->b_u_newhead->uh_entry;
+ buf->b_u_newhead->uh_entry = uep;
if (reload) {
// buffer was reloaded, notify text change subscribers
curbuf->b_u_newhead->uh_flags |= UH_RELOAD;
}
- curbuf->b_u_synced = false;
+ buf->b_u_synced = false;
undo_undoes = false;
#ifdef U_DEBUG
@@ -617,18 +631,20 @@ int u_savecommon(linenr_T top, linenr_T bot, linenr_T newbot, int reload)
static char_u e_not_open[] = N_("E828: Cannot open undo file for writing: %s");
-/*
- * Compute the hash for the current buffer text into hash[UNDO_HASH_SIZE].
- */
-void u_compute_hash(char_u *hash)
+/// Compute the hash for a buffer text into hash[UNDO_HASH_SIZE].
+///
+/// @param[in] buf The buffer used to compute the hash
+/// @param[in] hash Array of size UNDO_HASH_SIZE in which to store the value of
+/// the hash
+void u_compute_hash(buf_T *buf, char_u *hash)
{
context_sha256_T ctx;
linenr_T lnum;
char_u *p;
sha256_start(&ctx);
- for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum) {
- p = ml_get(lnum);
+ for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) {
+ p = ml_get_buf(buf, lnum, false);
sha256_update(&ctx, p, (uint32_t)(STRLEN(p) + 1));
}
sha256_finish(&ctx, hash);
@@ -656,6 +672,7 @@ char *u_get_undo_file_name(const char *const buf_ffname, const bool reading)
#ifdef HAVE_READLINK
char fname_buf[MAXPATHL];
#endif
+ char *p;
if (ffname == NULL) {
return NULL;
@@ -688,6 +705,13 @@ char *u_get_undo_file_name(const char *const buf_ffname, const bool reading)
memmove(tail + tail_len + 1, ".un~", sizeof(".un~"));
} else {
dir_name[dir_len] = NUL;
+
+ // Remove trailing pathseps from directory name
+ p = &dir_name[dir_len - 1];
+ while (vim_ispathsep(*p)) {
+ *p-- = NUL;
+ }
+
bool has_directory = os_isdir((char_u *)dir_name);
if (!has_directory && *dirp == NUL && !reading) {
// Last directory in the list does not exist, create it.
@@ -704,7 +728,7 @@ char *u_get_undo_file_name(const char *const buf_ffname, const bool reading)
if (has_directory) {
if (munged_name == NULL) {
munged_name = xstrdup(ffname);
- for (char *p = munged_name; *p != NUL; MB_PTR_ADV(p)) {
+ for (p = munged_name; *p != NUL; MB_PTR_ADV(p)) {
if (vim_ispathsep(*p)) {
*p = '%';
}
@@ -1002,14 +1026,14 @@ static ExtmarkUndoObject *unserialize_extmark(bufinfo_T *bi, bool *error,
extup->type = type;
if (type == kExtmarkSplice) {
n_elems = (size_t)sizeof(ExtmarkSplice) / sizeof(uint8_t);
- buf = xcalloc(sizeof(uint8_t), n_elems);
+ buf = xcalloc(n_elems, sizeof(uint8_t));
if (!undo_read(bi, buf, n_elems)) {
goto error;
}
extup->data.splice = *(ExtmarkSplice *)buf;
} else if (type == kExtmarkMove) {
n_elems = (size_t)sizeof(ExtmarkMove) / sizeof(uint8_t);
- buf = xcalloc(sizeof(uint8_t), n_elems);
+ buf = xcalloc(n_elems, sizeof(uint8_t));
if (!undo_read(bi, buf, n_elems)) {
goto error;
}
@@ -1281,8 +1305,8 @@ void u_write_undo(const char *const name, const bool forceit, buf_T *const buf,
goto theend;
}
- /* Undo must be synced. */
- u_sync(TRUE);
+ // Undo must be synced.
+ u_sync(true);
/*
* Write the header.
@@ -1767,7 +1791,7 @@ void u_undo(int count)
* be compatible.
*/
if (curbuf->b_u_synced == false) {
- u_sync(TRUE);
+ u_sync(true);
count = 1;
}
@@ -1846,8 +1870,9 @@ static void u_doit(int startcount, bool quiet, bool do_buf_event)
{
int count = startcount;
- if (!undo_allowed())
+ if (!undo_allowed(curbuf)) {
return;
+ }
u_newcount = 0;
u_oldcount = 0;
@@ -1858,15 +1883,16 @@ static void u_doit(int startcount, bool quiet, bool do_buf_event)
* needed. This may cause the file to be reloaded, that must happen
* before we do anything, because it may change curbuf->b_u_curhead
* and more. */
- change_warning(0);
+ change_warning(curbuf, 0);
if (undo_undoes) {
- if (curbuf->b_u_curhead == NULL) /* first undo */
+ if (curbuf->b_u_curhead == NULL) { // first undo
curbuf->b_u_curhead = curbuf->b_u_newhead;
- else if (get_undolevel() > 0) /* multi level undo */
- /* get next undo */
+ } else if (get_undolevel(curbuf) > 0) { // multi level undo
+ // get next undo
curbuf->b_u_curhead = curbuf->b_u_curhead->uh_next.ptr;
- /* nothing to undo */
+ }
+ // nothing to undo
if (curbuf->b_u_numhead == 0 || curbuf->b_u_curhead == NULL) {
/* stick curbuf->b_u_curhead at end */
curbuf->b_u_curhead = curbuf->b_u_oldhead;
@@ -1880,8 +1906,8 @@ static void u_doit(int startcount, bool quiet, bool do_buf_event)
u_undoredo(true, do_buf_event);
} else {
- if (curbuf->b_u_curhead == NULL || get_undolevel() <= 0) {
- beep_flush(); /* nothing to redo */
+ if (curbuf->b_u_curhead == NULL || get_undolevel(curbuf) <= 0) {
+ beep_flush(); // nothing to redo
if (count == startcount - 1) {
MSG(_("Already at newest change"));
return;
@@ -1925,9 +1951,10 @@ void undo_time(long step, bool sec, bool file, bool absolute)
bool above = false;
bool did_undo = true;
- /* First make sure the current undoable change is synced. */
- if (curbuf->b_u_synced == false)
- u_sync(TRUE);
+ // First make sure the current undoable change is synced.
+ if (curbuf->b_u_synced == false) {
+ u_sync(true);
+ }
u_newcount = 0;
u_oldcount = 0;
@@ -2122,8 +2149,8 @@ target_zero:
if (uhp != NULL || target == 0) {
// First go up the tree as much as needed.
while (!got_int) {
- /* Do the change warning now, for the same reason as above. */
- change_warning(0);
+ // Do the change warning now, for the same reason as above.
+ change_warning(curbuf, 0);
uhp = curbuf->b_u_curhead;
if (uhp == NULL)
@@ -2147,7 +2174,7 @@ target_zero:
// And now go down the tree (redo), branching off where needed.
while (!got_int) {
// Do the change warning now, for the same reason as above.
- change_warning(0);
+ change_warning(curbuf, 0);
uhp = curbuf->b_u_curhead;
if (uhp == NULL) {
@@ -2414,7 +2441,7 @@ static void u_undoredo(int undo, bool do_buf_event)
curhead->uh_entry = newlist;
curhead->uh_flags = new_flags;
- if ((old_flags & UH_EMPTYBUF) && BUFEMPTY()) {
+ if ((old_flags & UH_EMPTYBUF) && buf_is_empty(curbuf)) {
curbuf->b_ml.ml_flags |= ML_EMPTY;
}
if (old_flags & UH_CHANGED) {
@@ -2583,21 +2610,20 @@ static void u_undo_end(
msgbuf);
}
-/*
- * u_sync: stop adding to the current entry list
- */
-void
-u_sync(
- int force // Also sync when no_u_sync is set.
-)
+/// u_sync: stop adding to the current entry list
+///
+/// @param force if true, also sync when no_u_sync is set.
+void u_sync(bool force)
{
- /* Skip it when already synced or syncing is disabled. */
- if (curbuf->b_u_synced || (!force && no_u_sync > 0))
+ // Skip it when already synced or syncing is disabled.
+ if (curbuf->b_u_synced || (!force && no_u_sync > 0)) {
return;
- if (get_undolevel() < 0)
- curbuf->b_u_synced = true; /* no entries, nothing to do */
- else {
- u_getbot(); /* compute ue_bot of previous u_save */
+ }
+
+ if (get_undolevel(curbuf) < 0) {
+ curbuf->b_u_synced = true; // no entries, nothing to do
+ } else {
+ u_getbot(curbuf); // compute ue_bot of previous u_save
curbuf->b_u_curhead = NULL;
}
}
@@ -2708,7 +2734,7 @@ void ex_undojoin(exarg_T *eap)
if (!curbuf->b_u_synced) {
return; // already unsynced
}
- if (get_undolevel() < 0) {
+ if (get_undolevel(curbuf) < 0) {
return; // no entries, nothing to do
} else {
curbuf->b_u_synced = false; // Append next change to last entry
@@ -2744,13 +2770,13 @@ void u_find_first_changed(void)
return;
for (lnum = 1; lnum < curbuf->b_ml.ml_line_count
- && lnum <= uep->ue_size; ++lnum)
- if (STRCMP(ml_get_buf(curbuf, lnum, FALSE),
- uep->ue_array[lnum - 1]) != 0) {
+ && lnum <= uep->ue_size; lnum++) {
+ if (STRCMP(ml_get_buf(curbuf, lnum, false), uep->ue_array[lnum - 1]) != 0) {
clearpos(&(uhp->uh_cursor));
uhp->uh_cursor.lnum = lnum;
return;
}
+ }
if (curbuf->b_ml.ml_line_count != uep->ue_size) {
/* lines added or deleted at the end, put the cursor there */
clearpos(&(uhp->uh_cursor));
@@ -2792,38 +2818,39 @@ static void u_unch_branch(u_header_T *uhp)
* Get pointer to last added entry.
* If it's not valid, give an error message and return NULL.
*/
-static u_entry_T *u_get_headentry(void)
+static u_entry_T *u_get_headentry(buf_T *buf)
{
- if (curbuf->b_u_newhead == NULL || curbuf->b_u_newhead->uh_entry == NULL) {
+ if (buf->b_u_newhead == NULL || buf->b_u_newhead->uh_entry == NULL) {
IEMSG(_("E439: undo list corrupt"));
return NULL;
}
- return curbuf->b_u_newhead->uh_entry;
+ return buf->b_u_newhead->uh_entry;
}
/*
* u_getbot(): compute the line number of the previous u_save
* It is called only when b_u_synced is false.
*/
-static void u_getbot(void)
+static void u_getbot(buf_T *buf)
{
u_entry_T *uep;
linenr_T extra;
- uep = u_get_headentry(); /* check for corrupt undo list */
- if (uep == NULL)
+ uep = u_get_headentry(buf); // check for corrupt undo list
+ if (uep == NULL) {
return;
+ }
- uep = curbuf->b_u_newhead->uh_getbot_entry;
+ uep = buf->b_u_newhead->uh_getbot_entry;
if (uep != NULL) {
/*
* the new ue_bot is computed from the number of lines that has been
* inserted (0 - deleted) since calling u_save. This is equal to the
* old line count subtracted from the current line count.
*/
- extra = curbuf->b_ml.ml_line_count - uep->ue_lcount;
+ extra = buf->b_ml.ml_line_count - uep->ue_lcount;
uep->ue_bot = uep->ue_top + uep->ue_size + 1 + extra;
- if (uep->ue_bot < 1 || uep->ue_bot > curbuf->b_ml.ml_line_count) {
+ if (uep->ue_bot < 1 || uep->ue_bot > buf->b_ml.ml_line_count) {
IEMSG(_("E440: undo line missing"));
uep->ue_bot = uep->ue_top + 1; // assume all lines deleted, will
// get all the old lines back
@@ -2831,10 +2858,10 @@ static void u_getbot(void)
// ones
}
- curbuf->b_u_newhead->uh_getbot_entry = NULL;
+ buf->b_u_newhead->uh_getbot_entry = NULL;
}
- curbuf->b_u_synced = true;
+ buf->b_u_synced = true;
}
/*
@@ -3014,10 +3041,12 @@ void u_undoline(void)
return;
}
- /* first save the line for the 'u' command */
- if (u_savecommon(curbuf->b_u_line_lnum - 1,
- curbuf->b_u_line_lnum + 1, (linenr_T)0, FALSE) == FAIL)
+ // first save the line for the 'u' command
+ if (u_savecommon(curbuf, curbuf->b_u_line_lnum - 1,
+ curbuf->b_u_line_lnum + 1, (linenr_T)0, false) == FAIL) {
return;
+ }
+
oldp = u_save_line(curbuf->b_u_line_lnum);
ml_replace(curbuf->b_u_line_lnum, curbuf->b_u_line_ptr, true);
changed_bytes(curbuf->b_u_line_lnum, 0);
@@ -3048,12 +3077,21 @@ void u_blockfree(buf_T *buf)
xfree(buf->b_u_line_ptr);
}
-/*
- * u_save_line(): allocate memory and copy line 'lnum' into it.
- */
+/// Allocate memory and copy curbuf line into it.
+///
+/// @param lnum the line to copy
static char_u *u_save_line(linenr_T lnum)
{
- return vim_strsave(ml_get(lnum));
+ return u_save_line_buf(curbuf, lnum);
+}
+
+/// Allocate memory and copy line into it
+///
+/// @param lnum line to copy
+/// @param buf buffer to copy from
+static char_u *u_save_line_buf(buf_T *buf, linenr_T lnum)
+{
+ return vim_strsave(ml_get_buf(buf, lnum, false));
}
/// Check if the 'modified' flag is set, or 'ff' has changed (only need to
@@ -3143,18 +3181,16 @@ u_header_T *u_force_get_undo_header(buf_T *buf)
if (!uhp) {
// Undo is normally invoked in change code, which already has swapped
// curbuf.
- buf_T *save_curbuf = curbuf;
- curbuf = buf;
// Args are tricky: this means replace empty range by empty range..
- u_savecommon(0, 1, 1, true);
+ u_savecommon(curbuf, 0, 1, 1, true);
+
uhp = buf->b_u_curhead;
if (!uhp) {
uhp = buf->b_u_newhead;
- if (get_undolevel() > 0 && !uhp) {
+ if (get_undolevel(curbuf) > 0 && !uhp) {
abort();
}
}
- curbuf = save_curbuf;
}
return uhp;
}
diff --git a/src/nvim/version.c b/src/nvim/version.c
index f3a30630f8..7c197f1b7f 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -13,6 +13,7 @@
#include "nvim/api/private/helpers.h"
#include "nvim/vim.h"
#include "nvim/ascii.h"
+#include "nvim/buffer.h"
#include "nvim/iconv.h"
#include "nvim/version.h"
#include "nvim/charset.h"
@@ -38,7 +39,10 @@ NVIM_VERSION_PRERELEASE
char *Version = VIM_VERSION_SHORT;
char *longVersion = NVIM_VERSION_LONG;
char *version_buildtype = "Build type: " NVIM_VERSION_BUILD_TYPE;
+// Reproducible builds: omit compile info in Release builds. #15424
+#ifndef NDEBUG
char *version_cflags = "Compilation: " NVIM_VERSION_CFLAGS;
+#endif
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "version.c.generated.h"
@@ -2142,7 +2146,9 @@ void list_version(void)
MSG(longVersion);
MSG(version_buildtype);
list_lua_version();
+#ifndef NDEBUG
MSG(version_cflags);
+#endif
#ifdef HAVE_PATHDEF
@@ -2190,7 +2196,7 @@ void list_version(void)
/// Show the intro message when not editing a file.
void maybe_intro_message(void)
{
- if (BUFEMPTY()
+ if (buf_is_empty(curbuf)
&& (curbuf->b_fname == NULL)
&& (firstwin->w_next == NULL)
&& (vim_strchr(p_shm, SHM_INTRO) == NULL)) {
diff --git a/src/nvim/vim.h b/src/nvim/vim.h
index df4ab04eb6..62536a0600 100644
--- a/src/nvim/vim.h
+++ b/src/nvim/vim.h
@@ -102,6 +102,7 @@ typedef enum {
#define VAR_TYPE_FLOAT 5
#define VAR_TYPE_BOOL 6
#define VAR_TYPE_SPECIAL 7
+#define VAR_TYPE_BLOB 10
// values for xp_context when doing command line completion
@@ -270,7 +271,7 @@ enum { FOLD_TEXT_LEN = 51 }; //!< buffer size for get_foldtext()
/// On some systems case in a file name does not matter, on others it does.
///
/// @note Does not account for maximum name lengths and things like "../dir",
-/// thus it is not 100% accurate. OS may also use different algorythm for
+/// thus it is not 100% accurate. OS may also use different algorithm for
/// case-insensitive comparison.
///
/// @param[in] x First file name to compare.
@@ -304,17 +305,6 @@ enum { FOLD_TEXT_LEN = 51 }; //!< buffer size for get_foldtext()
#include "nvim/buffer_defs.h" // buffer and windows
#include "nvim/ex_cmds_defs.h" // Ex command defines
-// Used for flags in do_in_path()
-#define DIP_ALL 0x01 // all matches, not just the first one
-#define DIP_DIR 0x02 // find directories instead of files
-#define DIP_ERR 0x04 // give an error message when none found
-#define DIP_START 0x08 // also use "start" directory in 'packpath'
-#define DIP_OPT 0x10 // also use "opt" directory in 'packpath'
-#define DIP_NORTP 0x20 // do not use 'runtimepath'
-#define DIP_NOAFTER 0x40 // skip "after" directories
-#define DIP_AFTER 0x80 // only use "after" directories
-#define DIP_LUA 0x100 // also use ".lua" files
-
// Lowest number used for window ID. Cannot have this many windows per tab.
#define LOWEST_WIN_ID 1000
diff --git a/src/nvim/viml/parser/expressions.c b/src/nvim/viml/parser/expressions.c
index e9d82ca87d..39687a8e8d 100644
--- a/src/nvim/viml/parser/expressions.c
+++ b/src/nvim/viml/parser/expressions.c
@@ -50,20 +50,19 @@
// 7. 'isident' no longer applies to environment variables, they always include
// ASCII alphanumeric characters and underscore and nothing except this.
+#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
-#include <assert.h>
#include <string.h>
-#include "nvim/vim.h"
-#include "nvim/memory.h"
-#include "nvim/types.h"
-#include "nvim/charset.h"
#include "nvim/ascii.h"
#include "nvim/assert.h"
-#include "nvim/lib/kvec.h"
+#include "nvim/charset.h"
#include "nvim/eval/typval.h"
-
+#include "nvim/lib/kvec.h"
+#include "nvim/memory.h"
+#include "nvim/types.h"
+#include "nvim/vim.h"
#include "nvim/viml/parser/expressions.h"
#include "nvim/viml/parser/parser.h"
@@ -143,10 +142,8 @@ typedef enum {
/// numbers are not supported.
/// @param[in] exponent Exponent to scale by.
/// @param[in] exponent_negative True if exponent is negative.
-static inline float_T scale_number(const float_T num,
- const uint8_t base,
- const uvarnumber_T exponent,
- const bool exponent_negative)
+static inline float_T scale_number(const float_T num, const uint8_t base,
+ const uvarnumber_T exponent, const bool exponent_negative)
FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_CONST
{
if (num == 0 || exponent == 0) {
@@ -200,7 +197,7 @@ LexExprToken viml_pexpr_next_token(ParserState *const pstate, const int flags)
if (ret.len < pline.size \
&& strchr("?#", pline.data[ret.len]) != NULL) { \
ret.data.cmp.ccs = \
- (ExprCaseCompareStrategy)pline.data[ret.len]; \
+ (ExprCaseCompareStrategy)pline.data[ret.len]; \
ret.len++; \
} else { \
ret.data.cmp.ccs = kCCStrategyUseOption; \
@@ -209,12 +206,12 @@ LexExprToken viml_pexpr_next_token(ParserState *const pstate, const int flags)
switch (schar) {
// Paired brackets.
#define BRACKET(typ, opning, clsing) \
- case opning: \
- case clsing: { \
- ret.type = typ; \
- ret.data.brc.closing = (schar == clsing); \
- break; \
- }
+case opning: \
+case clsing: { \
+ ret.type = typ; \
+ ret.data.brc.closing = (schar == clsing); \
+ break; \
+}
BRACKET(kExprLexParenthesis, '(', ')')
BRACKET(kExprLexBracket, '[', ']')
BRACKET(kExprLexFigureBrace, '{', '}')
@@ -222,10 +219,10 @@ LexExprToken viml_pexpr_next_token(ParserState *const pstate, const int flags)
// Single character tokens without data.
#define CHAR(typ, ch) \
- case ch: { \
- ret.type = typ; \
- break; \
- }
+case ch: { \
+ ret.type = typ; \
+ break; \
+}
CHAR(kExprLexQuestion, '?')
CHAR(kExprLexColon, ':')
CHAR(kExprLexComma, ',')
@@ -233,198 +230,265 @@ LexExprToken viml_pexpr_next_token(ParserState *const pstate, const int flags)
// Multiplication/division/modulo.
#define MUL(mul_type, ch) \
- case ch: { \
- ret.type = kExprLexMultiplication; \
- ret.data.mul.type = mul_type; \
- break; \
- }
+case ch: { \
+ ret.type = kExprLexMultiplication; \
+ ret.data.mul.type = mul_type; \
+ break; \
+}
MUL(kExprLexMulMul, '*')
MUL(kExprLexMulDiv, '/')
MUL(kExprLexMulMod, '%')
#undef MUL
#define CHARREG(typ, cond) \
- do { \
- ret.type = typ; \
- for (; (ret.len < pline.size \
- && cond(pline.data[ret.len])) \
- ; ret.len++) { \
- } \
- } while (0)
-
- // Whitespace.
- case ' ':
- case TAB: {
- CHARREG(kExprLexSpacing, ascii_iswhite);
- break;
- }
-
- // Control character, except for NUL, NL and TAB.
- case Ctrl_A: case Ctrl_B: case Ctrl_C: case Ctrl_D: case Ctrl_E:
- case Ctrl_F: case Ctrl_G: case Ctrl_H:
+ do { \
+ ret.type = typ; \
+ for (; (ret.len < pline.size \
+ && cond(pline.data[ret.len])) \
+ ; ret.len++) { \
+ } \
+ } while (0)
- case Ctrl_K: case Ctrl_L: case Ctrl_M: case Ctrl_N: case Ctrl_O:
- case Ctrl_P: case Ctrl_Q: case Ctrl_R: case Ctrl_S: case Ctrl_T:
- case Ctrl_U: case Ctrl_V: case Ctrl_W: case Ctrl_X: case Ctrl_Y:
- case Ctrl_Z: {
+ // Whitespace.
+ case ' ':
+ case TAB:
+ CHARREG(kExprLexSpacing, ascii_iswhite);
+ break;
+
+ // Control character, except for NUL, NL and TAB.
+ case Ctrl_A:
+ case Ctrl_B:
+ case Ctrl_C:
+ case Ctrl_D:
+ case Ctrl_E:
+ case Ctrl_F:
+ case Ctrl_G:
+ case Ctrl_H:
+
+ case Ctrl_K:
+ case Ctrl_L:
+ case Ctrl_M:
+ case Ctrl_N:
+ case Ctrl_O:
+ case Ctrl_P:
+ case Ctrl_Q:
+ case Ctrl_R:
+ case Ctrl_S:
+ case Ctrl_T:
+ case Ctrl_U:
+ case Ctrl_V:
+ case Ctrl_W:
+ case Ctrl_X:
+ case Ctrl_Y:
+ case Ctrl_Z:
#define ISCTRL(schar) (schar < ' ')
- CHARREG(kExprLexInvalid, ISCTRL);
- ret.data.err.type = kExprLexSpacing;
- ret.data.err.msg =
- _("E15: Invalid control character present in input: %.*s");
- break;
+ CHARREG(kExprLexInvalid, ISCTRL);
+ ret.data.err.type = kExprLexSpacing;
+ ret.data.err.msg =
+ _("E15: Invalid control character present in input: %.*s");
+ break;
#undef ISCTRL
- }
- // Number.
- case '0': case '1': case '2': case '3': case '4': case '5': case '6':
- case '7': case '8': case '9': {
- ret.data.num.is_float = false;
- ret.data.num.base = 10;
- size_t frac_start = 0;
- size_t exp_start = 0;
- size_t frac_end = 0;
- bool exp_negative = false;
- CHARREG(kExprLexNumber, ascii_isdigit);
- if (flags & kELFlagAllowFloat) {
- const LexExprToken non_float_ret = ret;
+ // Number.
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': {
+ ret.data.num.is_float = false;
+ ret.data.num.base = 10;
+ size_t frac_start = 0;
+ size_t exp_start = 0;
+ size_t frac_end = 0;
+ bool exp_negative = false;
+ CHARREG(kExprLexNumber, ascii_isdigit);
+ if (flags & kELFlagAllowFloat) {
+ const LexExprToken non_float_ret = ret;
+ if (pline.size > ret.len + 1
+ && pline.data[ret.len] == '.'
+ && ascii_isdigit(pline.data[ret.len + 1])) {
+ ret.len++;
+ frac_start = ret.len;
+ frac_end = ret.len;
+ ret.data.num.is_float = true;
+ for (; ret.len < pline.size && ascii_isdigit(pline.data[ret.len])
+ ; ret.len++) {
+ // A small optimization: trailing zeroes in fractional part do not
+ // add anything to significand, so it is useless to include them in
+ // frac_end.
+ if (pline.data[ret.len] != '0') {
+ frac_end = ret.len + 1;
+ }
+ }
if (pline.size > ret.len + 1
- && pline.data[ret.len] == '.'
- && ascii_isdigit(pline.data[ret.len + 1])) {
+ && (pline.data[ret.len] == 'e'
+ || pline.data[ret.len] == 'E')
+ && ((pline.size > ret.len + 2
+ && (pline.data[ret.len + 1] == '+'
+ || pline.data[ret.len + 1] == '-')
+ && ascii_isdigit(pline.data[ret.len + 2]))
+ || ascii_isdigit(pline.data[ret.len + 1]))) {
ret.len++;
- frac_start = ret.len;
- frac_end = ret.len;
- ret.data.num.is_float = true;
- for (; ret.len < pline.size && ascii_isdigit(pline.data[ret.len])
- ; ret.len++) {
- // A small optimization: trailing zeroes in fractional part do not
- // add anything to significand, so it is useless to include them in
- // frac_end.
- if (pline.data[ret.len] != '0') {
- frac_end = ret.len + 1;
- }
- }
- if (pline.size > ret.len + 1
- && (pline.data[ret.len] == 'e'
- || pline.data[ret.len] == 'E')
- && ((pline.size > ret.len + 2
- && (pline.data[ret.len + 1] == '+'
- || pline.data[ret.len + 1] == '-')
- && ascii_isdigit(pline.data[ret.len + 2]))
- || ascii_isdigit(pline.data[ret.len + 1]))) {
+ if (pline.data[ret.len] == '+'
+ || (exp_negative = (pline.data[ret.len] == '-'))) {
ret.len++;
- if (pline.data[ret.len] == '+'
- || (exp_negative = (pline.data[ret.len] == '-'))) {
- ret.len++;
- }
- exp_start = ret.len;
- CHARREG(kExprLexNumber, ascii_isdigit);
}
- }
- if (pline.size > ret.len
- && (pline.data[ret.len] == '.'
- || ASCII_ISALPHA(pline.data[ret.len]))) {
- ret = non_float_ret;
+ exp_start = ret.len;
+ CHARREG(kExprLexNumber, ascii_isdigit);
}
}
- // TODO(ZyX-I): detect overflows
- if (ret.data.num.is_float) {
- // Vim used to use string2float here which in turn uses strtod(). There
- // are two problems with this approach:
- // 1. strtod() is locale-dependent. Not sure how it is worked around so
- // that I do not see relevant bugs, but it still does not look like
- // a good idea.
- // 2. strtod() does not accept length argument.
- //
- // The below variant of parsing floats was recognized as acceptable
- // because it is basically how uClibc does the thing: it generates
- // a number ignoring decimal point (but recording its position), then
- // uses recorded position to scale number down when processing exponent.
- float_T significand_part = 0;
- uvarnumber_T exp_part = 0;
- const size_t frac_size = (size_t)(frac_end - frac_start);
- for (size_t i = 0; i < frac_end; i++) {
- if (i == frac_start - 1) {
- continue;
- }
- significand_part = significand_part * 10 + (pline.data[i] - '0');
- }
- if (exp_start) {
- vim_str2nr(pline.data + exp_start, NULL, NULL, 0, NULL, &exp_part,
- (int)(ret.len - exp_start));
+ if (pline.size > ret.len
+ && (pline.data[ret.len] == '.'
+ || ASCII_ISALPHA(pline.data[ret.len]))) {
+ ret = non_float_ret;
+ }
+ }
+ // TODO(ZyX-I): detect overflows
+ if (ret.data.num.is_float) {
+ // Vim used to use string2float here which in turn uses strtod(). There
+ // are two problems with this approach:
+ // 1. strtod() is locale-dependent. Not sure how it is worked around so
+ // that I do not see relevant bugs, but it still does not look like
+ // a good idea.
+ // 2. strtod() does not accept length argument.
+ //
+ // The below variant of parsing floats was recognized as acceptable
+ // because it is basically how uClibc does the thing: it generates
+ // a number ignoring decimal point (but recording its position), then
+ // uses recorded position to scale number down when processing exponent.
+ float_T significand_part = 0;
+ uvarnumber_T exp_part = 0;
+ const size_t frac_size = (size_t)(frac_end - frac_start);
+ for (size_t i = 0; i < frac_end; i++) {
+ if (i == frac_start - 1) {
+ continue;
}
- if (exp_negative) {
- exp_part += frac_size;
+ significand_part = significand_part * 10 + (pline.data[i] - '0');
+ }
+ if (exp_start) {
+ vim_str2nr(pline.data + exp_start, NULL, NULL, 0, NULL, &exp_part,
+ (int)(ret.len - exp_start), false);
+ }
+ if (exp_negative) {
+ exp_part += frac_size;
+ } else {
+ if (exp_part < frac_size) {
+ exp_negative = true;
+ exp_part = frac_size - exp_part;
} else {
- if (exp_part < frac_size) {
- exp_negative = true;
- exp_part = frac_size - exp_part;
- } else {
- exp_part -= frac_size;
- }
+ exp_part -= frac_size;
}
- ret.data.num.val.floating = scale_number(significand_part, 10, exp_part,
- exp_negative);
- } else {
- int len;
- int prep;
- vim_str2nr(pline.data, &prep, &len, STR2NR_ALL, NULL,
- &ret.data.num.val.integer, (int)pline.size);
- ret.len = (size_t)len;
- const uint8_t bases[] = {
- [0] = 10,
- ['0'] = 8,
- ['x'] = 16, ['X'] = 16,
- ['b'] = 2, ['B'] = 2,
- };
- ret.data.num.base = bases[prep];
}
- break;
+ ret.data.num.val.floating = scale_number(significand_part, 10, exp_part,
+ exp_negative);
+ } else {
+ int len;
+ int prep;
+ vim_str2nr(pline.data, &prep, &len, STR2NR_ALL, NULL,
+ &ret.data.num.val.integer, (int)pline.size, false);
+ ret.len = (size_t)len;
+ const uint8_t bases[] = {
+ [0] = 10,
+ ['0'] = 8,
+ ['x'] = 16, ['X'] = 16,
+ ['b'] = 2, ['B'] = 2,
+ };
+ ret.data.num.base = bases[prep];
}
+ break;
+ }
#define ISWORD_OR_AUTOLOAD(x) \
- (ascii_isident(x) || (x) == AUTOLOAD_CHAR)
-
- // Environment variable.
- case '$': {
- CHARREG(kExprLexEnv, ascii_isident);
- break;
- }
-
- // Normal variable/function name.
- case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
- case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
- case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
- case 'v': case 'w': case 'x': case 'y': case 'z':
- case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
- case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
- case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
- case 'V': case 'W': case 'X': case 'Y': case 'Z':
- case '_': {
- ret.data.var.scope = 0;
- ret.data.var.autoload = false;
- CHARREG(kExprLexPlainIdentifier, ascii_isident);
- // "is" and "isnot" operators.
- if (!(flags & kELFlagIsNotCmp)
- && ((ret.len == 2 && memcmp(pline.data, "is", 2) == 0)
- || (ret.len == 5 && memcmp(pline.data, "isnot", 5) == 0))) {
- ret.type = kExprLexComparison;
- ret.data.cmp.type = kExprCmpIdentical;
- ret.data.cmp.inv = (ret.len == 5);
- GET_CCS(ret, pline);
+ (ascii_isident(x) || (x) == AUTOLOAD_CHAR)
+
+ // Environment variable.
+ case '$':
+ CHARREG(kExprLexEnv, ascii_isident);
+ break;
+
+ // Normal variable/function name.
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ case 'g':
+ case 'h':
+ case 'i':
+ case 'j':
+ case 'k':
+ case 'l':
+ case 'm':
+ case 'n':
+ case 'o':
+ case 'p':
+ case 'q':
+ case 'r':
+ case 's':
+ case 't':
+ case 'u':
+ case 'v':
+ case 'w':
+ case 'x':
+ case 'y':
+ case 'z':
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ case 'G':
+ case 'H':
+ case 'I':
+ case 'J':
+ case 'K':
+ case 'L':
+ case 'M':
+ case 'N':
+ case 'O':
+ case 'P':
+ case 'Q':
+ case 'R':
+ case 'S':
+ case 'T':
+ case 'U':
+ case 'V':
+ case 'W':
+ case 'X':
+ case 'Y':
+ case 'Z':
+ case '_':
+ ret.data.var.scope = 0;
+ ret.data.var.autoload = false;
+ CHARREG(kExprLexPlainIdentifier, ascii_isident);
+ // "is" and "isnot" operators.
+ if (!(flags & kELFlagIsNotCmp)
+ && ((ret.len == 2 && memcmp(pline.data, "is", 2) == 0)
+ || (ret.len == 5 && memcmp(pline.data, "isnot", 5) == 0))) {
+ ret.type = kExprLexComparison;
+ ret.data.cmp.type = kExprCmpIdentical;
+ ret.data.cmp.inv = (ret.len == 5);
+ GET_CCS(ret, pline);
// Scope: `s:`, etc.
- } else if (ret.len == 1
- && pline.size > 1
- && memchr(EXPR_VAR_SCOPE_LIST, schar,
- sizeof(EXPR_VAR_SCOPE_LIST)) != NULL
- && pline.data[ret.len] == ':'
- && !(flags & kELFlagForbidScope)) {
- ret.len++;
- ret.data.var.scope = (ExprVarScope)schar;
- CHARREG(kExprLexPlainIdentifier, ISWORD_OR_AUTOLOAD);
- ret.data.var.autoload = (
- memchr(pline.data + 2, AUTOLOAD_CHAR, ret.len - 2)
- != NULL);
+ } else if (ret.len == 1
+ && pline.size > 1
+ && memchr(EXPR_VAR_SCOPE_LIST, schar,
+ sizeof(EXPR_VAR_SCOPE_LIST)) != NULL
+ && pline.data[ret.len] == ':'
+ && !(flags & kELFlagForbidScope)) {
+ ret.len++;
+ ret.data.var.scope = (ExprVarScope)schar;
+ CHARREG(kExprLexPlainIdentifier, ISWORD_OR_AUTOLOAD);
+ ret.data.var.autoload = (
+ memchr(pline.data + 2, AUTOLOAD_CHAR, ret.len - 2)
+ != NULL);
// Previous CHARREG stopped at autoload character in order to make it
// possible to detect `is#`. Continue now with autoload characters
// included.
@@ -432,221 +496,213 @@ LexExprToken viml_pexpr_next_token(ParserState *const pstate, const int flags)
// Warning: there is ambiguity for the lexer: `is#Foo(1)` is a call of
// function `is#Foo()`, `1is#Foo(1)` is a comparison `1 is# Foo(1)`. This
// needs to be resolved on the higher level where context is available.
- } else if (pline.size > ret.len
- && pline.data[ret.len] == AUTOLOAD_CHAR) {
- ret.data.var.autoload = true;
- CHARREG(kExprLexPlainIdentifier, ISWORD_OR_AUTOLOAD);
- }
- break;
+ } else if (pline.size > ret.len
+ && pline.data[ret.len] == AUTOLOAD_CHAR) {
+ ret.data.var.autoload = true;
+ CHARREG(kExprLexPlainIdentifier, ISWORD_OR_AUTOLOAD);
}
+ break;
#undef ISWORD_OR_AUTOLOAD
#undef CHARREG
- // Option.
- case '&': {
+ // Option.
+ case '&': {
#define OPTNAMEMISS(ret) \
- do { \
- ret.type = kExprLexInvalid; \
- ret.data.err.type = kExprLexOption; \
- ret.data.err.msg = _("E112: Option name missing: %.*s"); \
- } while (0)
- if (pline.size > 1 && pline.data[1] == '&') {
- ret.type = kExprLexAnd;
- ret.len++;
- break;
+ do { \
+ ret.type = kExprLexInvalid; \
+ ret.data.err.type = kExprLexOption; \
+ ret.data.err.msg = _("E112: Option name missing: %.*s"); \
+ } while (0)
+ if (pline.size > 1 && pline.data[1] == '&') {
+ ret.type = kExprLexAnd;
+ ret.len++;
+ break;
+ }
+ if (pline.size == 1 || !ASCII_ISALPHA(pline.data[1])) {
+ OPTNAMEMISS(ret);
+ break;
+ }
+ ret.type = kExprLexOption;
+ if (pline.size > 2
+ && pline.data[2] == ':'
+ && memchr(EXPR_OPT_SCOPE_LIST, pline.data[1],
+ sizeof(EXPR_OPT_SCOPE_LIST)) != NULL) {
+ ret.len += 2;
+ ret.data.opt.scope = (ExprOptScope)pline.data[1];
+ ret.data.opt.name = pline.data + 3;
+ } else {
+ ret.data.opt.scope = kExprOptScopeUnspecified;
+ ret.data.opt.name = pline.data + 1;
+ }
+ const char *p = ret.data.opt.name;
+ const char *const e = pline.data + pline.size;
+ if (e - p >= 4 && p[0] == 't' && p[1] == '_') {
+ ret.data.opt.len = 4;
+ ret.len += 4;
+ } else {
+ for (; p < e && ASCII_ISALPHA(*p); p++) {
}
- if (pline.size == 1 || !ASCII_ISALPHA(pline.data[1])) {
+ ret.data.opt.len = (size_t)(p - ret.data.opt.name);
+ if (ret.data.opt.len == 0) {
OPTNAMEMISS(ret);
- break;
- }
- ret.type = kExprLexOption;
- if (pline.size > 2
- && pline.data[2] == ':'
- && memchr(EXPR_OPT_SCOPE_LIST, pline.data[1],
- sizeof(EXPR_OPT_SCOPE_LIST)) != NULL) {
- ret.len += 2;
- ret.data.opt.scope = (ExprOptScope)pline.data[1];
- ret.data.opt.name = pline.data + 3;
} else {
- ret.data.opt.scope = kExprOptScopeUnspecified;
- ret.data.opt.name = pline.data + 1;
- }
- const char *p = ret.data.opt.name;
- const char *const e = pline.data + pline.size;
- if (e - p >= 4 && p[0] == 't' && p[1] == '_') {
- ret.data.opt.len = 4;
- ret.len += 4;
- } else {
- for (; p < e && ASCII_ISALPHA(*p); p++) {
- }
- ret.data.opt.len = (size_t)(p - ret.data.opt.name);
- if (ret.data.opt.len == 0) {
- OPTNAMEMISS(ret);
- } else {
- ret.len += ret.data.opt.len;
- }
+ ret.len += ret.data.opt.len;
}
- break;
-#undef OPTNAMEMISS
}
+ break;
+#undef OPTNAMEMISS
+ }
- // Register.
- case '@': {
- ret.type = kExprLexRegister;
- if (pline.size > 1) {
- ret.len++;
- ret.data.reg.name = (uint8_t)pline.data[1];
- } else {
- ret.data.reg.name = -1;
- }
- break;
+ // Register.
+ case '@':
+ ret.type = kExprLexRegister;
+ if (pline.size > 1) {
+ ret.len++;
+ ret.data.reg.name = (uint8_t)pline.data[1];
+ } else {
+ ret.data.reg.name = -1;
}
-
- // Single quoted string.
- case '\'': {
- ret.type = kExprLexSingleQuotedString;
- ret.data.str.closed = false;
- for (; ret.len < pline.size && !ret.data.str.closed; ret.len++) {
- if (pline.data[ret.len] == '\'') {
- if (ret.len + 1 < pline.size && pline.data[ret.len + 1] == '\'') {
- ret.len++;
- } else {
- ret.data.str.closed = true;
- }
+ break;
+
+ // Single quoted string.
+ case '\'':
+ ret.type = kExprLexSingleQuotedString;
+ ret.data.str.closed = false;
+ for (; ret.len < pline.size && !ret.data.str.closed; ret.len++) {
+ if (pline.data[ret.len] == '\'') {
+ if (ret.len + 1 < pline.size && pline.data[ret.len + 1] == '\'') {
+ ret.len++;
+ } else {
+ ret.data.str.closed = true;
}
}
- break;
}
-
- // Double quoted string.
- case '"': {
- ret.type = kExprLexDoubleQuotedString;
- ret.data.str.closed = false;
- for (; ret.len < pline.size && !ret.data.str.closed; ret.len++) {
- if (pline.data[ret.len] == '\\') {
- if (ret.len + 1 < pline.size) {
- ret.len++;
- }
- } else if (pline.data[ret.len] == '"') {
- ret.data.str.closed = true;
+ break;
+
+ // Double quoted string.
+ case '"':
+ ret.type = kExprLexDoubleQuotedString;
+ ret.data.str.closed = false;
+ for (; ret.len < pline.size && !ret.data.str.closed; ret.len++) {
+ if (pline.data[ret.len] == '\\') {
+ if (ret.len + 1 < pline.size) {
+ ret.len++;
}
+ } else if (pline.data[ret.len] == '"') {
+ ret.data.str.closed = true;
}
- break;
}
-
- // Unary not, (un)equality and regex (not) match comparison operators.
- case '!':
- case '=': {
- if (pline.size == 1) {
- ret.type = (schar == '!' ? kExprLexNot : kExprLexAssignment);
- ret.data.ass.type = kExprAsgnPlain;
- break;
- }
- ret.type = kExprLexComparison;
- ret.data.cmp.inv = (schar == '!');
- if (pline.data[1] == '=') {
- ret.data.cmp.type = kExprCmpEqual;
- ret.len++;
- } else if (pline.data[1] == '~') {
- ret.data.cmp.type = kExprCmpMatches;
- ret.len++;
- } else if (schar == '!') {
- ret.type = kExprLexNot;
- } else {
- ret.type = kExprLexAssignment;
- ret.data.ass.type = kExprAsgnPlain;
- }
- GET_CCS(ret, pline);
+ break;
+
+ // Unary not, (un)equality and regex (not) match comparison operators.
+ case '!':
+ case '=':
+ if (pline.size == 1) {
+ ret.type = (schar == '!' ? kExprLexNot : kExprLexAssignment);
+ ret.data.ass.type = kExprAsgnPlain;
break;
}
-
- // Less/greater [or equal to] comparison operators.
- case '>':
- case '<': {
- ret.type = kExprLexComparison;
- const bool haseqsign = (pline.size > 1 && pline.data[1] == '=');
- if (haseqsign) {
- ret.len++;
- }
- GET_CCS(ret, pline);
- ret.data.cmp.inv = (schar == '<');
- ret.data.cmp.type = ((ret.data.cmp.inv ^ haseqsign)
+ ret.type = kExprLexComparison;
+ ret.data.cmp.inv = (schar == '!');
+ if (pline.data[1] == '=') {
+ ret.data.cmp.type = kExprCmpEqual;
+ ret.len++;
+ } else if (pline.data[1] == '~') {
+ ret.data.cmp.type = kExprCmpMatches;
+ ret.len++;
+ } else if (schar == '!') {
+ ret.type = kExprLexNot;
+ } else {
+ ret.type = kExprLexAssignment;
+ ret.data.ass.type = kExprAsgnPlain;
+ }
+ GET_CCS(ret, pline);
+ break;
+
+ // Less/greater [or equal to] comparison operators.
+ case '>':
+ case '<': {
+ ret.type = kExprLexComparison;
+ const bool haseqsign = (pline.size > 1 && pline.data[1] == '=');
+ if (haseqsign) {
+ ret.len++;
+ }
+ GET_CCS(ret, pline);
+ ret.data.cmp.inv = (schar == '<');
+ ret.data.cmp.type = ((ret.data.cmp.inv ^ haseqsign)
? kExprCmpGreaterOrEqual
: kExprCmpGreater);
- break;
- }
+ break;
+ }
- // Minus sign, arrow from lambdas or augmented assignment.
- case '-': {
- if (pline.size > 1 && pline.data[1] == '>') {
- ret.len++;
- ret.type = kExprLexArrow;
- } else if (pline.size > 1 && pline.data[1] == '=') {
- ret.len++;
- ret.type = kExprLexAssignment;
- ret.data.ass.type = kExprAsgnSubtract;
- } else {
- ret.type = kExprLexMinus;
- }
- break;
+ // Minus sign, arrow from lambdas or augmented assignment.
+ case '-': {
+ if (pline.size > 1 && pline.data[1] == '>') {
+ ret.len++;
+ ret.type = kExprLexArrow;
+ } else if (pline.size > 1 && pline.data[1] == '=') {
+ ret.len++;
+ ret.type = kExprLexAssignment;
+ ret.data.ass.type = kExprAsgnSubtract;
+ } else {
+ ret.type = kExprLexMinus;
}
+ break;
+ }
// Sign or augmented assignment.
#define CHAR_OR_ASSIGN(ch, ch_type, ass_type) \
- case ch: { \
- if (pline.size > 1 && pline.data[1] == '=') { \
- ret.len++; \
- ret.type = kExprLexAssignment; \
- ret.data.ass.type = ass_type; \
- } else { \
- ret.type = ch_type; \
- } \
- break; \
- }
+case ch: { \
+ if (pline.size > 1 && pline.data[1] == '=') { \
+ ret.len++; \
+ ret.type = kExprLexAssignment; \
+ ret.data.ass.type = ass_type; \
+ } else { \
+ ret.type = ch_type; \
+ } \
+ break; \
+}
CHAR_OR_ASSIGN('+', kExprLexPlus, kExprAsgnAdd)
CHAR_OR_ASSIGN('.', kExprLexDot, kExprAsgnConcat)
#undef CHAR_OR_ASSIGN
- // Expression end because Ex command ended.
- case NUL:
- case NL: {
- if (flags & kELFlagForbidEOC) {
- ret.type = kExprLexInvalid;
- ret.data.err.msg = _("E15: Unexpected EOC character: %.*s");
- ret.data.err.type = kExprLexSpacing;
- } else {
- ret.type = kExprLexEOC;
- }
- break;
- }
-
- case '|': {
- if (pline.size >= 2 && pline.data[ret.len] == '|') {
- // "||" is or.
- ret.len++;
- ret.type = kExprLexOr;
- } else if (flags & kELFlagForbidEOC) {
- // Note: `<C-r>=1 | 2<CR>` actually yields 1 in Vim without any
- // errors. This will be changed here.
- ret.type = kExprLexInvalid;
- ret.data.err.msg = _("E15: Unexpected EOC character: %.*s");
- ret.data.err.type = kExprLexOr;
- } else {
- ret.type = kExprLexEOC;
- }
- break;
+ // Expression end because Ex command ended.
+ case NUL:
+ case NL:
+ if (flags & kELFlagForbidEOC) {
+ ret.type = kExprLexInvalid;
+ ret.data.err.msg = _("E15: Unexpected EOC character: %.*s");
+ ret.data.err.type = kExprLexSpacing;
+ } else {
+ ret.type = kExprLexEOC;
}
-
- // Everything else is not valid.
- default: {
- ret.len = (size_t)utfc_ptr2len_len((const char_u *)pline.data,
- (int)pline.size);
+ break;
+
+ case '|':
+ if (pline.size >= 2 && pline.data[ret.len] == '|') {
+ // "||" is or.
+ ret.len++;
+ ret.type = kExprLexOr;
+ } else if (flags & kELFlagForbidEOC) {
+ // Note: `<C-r>=1 | 2<CR>` actually yields 1 in Vim without any
+ // errors. This will be changed here.
ret.type = kExprLexInvalid;
- ret.data.err.type = kExprLexPlainIdentifier;
- ret.data.err.msg = _("E15: Unidentified character: %.*s");
- break;
+ ret.data.err.msg = _("E15: Unexpected EOC character: %.*s");
+ ret.data.err.type = kExprLexOr;
+ } else {
+ ret.type = kExprLexEOC;
}
+ break;
+
+ // Everything else is not valid.
+ default:
+ ret.len = (size_t)utfc_ptr2len_len((const char_u *)pline.data,
+ (int)pline.size);
+ ret.type = kExprLexInvalid;
+ ret.data.err.type = kExprLexPlainIdentifier;
+ ret.data.err.msg = _("E15: Unidentified character: %.*s");
+ break;
}
#undef GET_CCS
viml_pexpr_next_token_adv_return:
@@ -737,8 +793,7 @@ static const char *const eltkn_opt_scope_tab[] = {
///
/// @return Token represented in a string form, in a static buffer (overwritten
/// on each call).
-const char *viml_pexpr_repr_token(const ParserState *const pstate,
- const LexExprToken token,
+const char *viml_pexpr_repr_token(const ParserState *const pstate, const LexExprToken token,
size_t *const ret_size)
FUNC_ATTR_WARN_UNUSED_RESULT
{
@@ -756,10 +811,10 @@ const char *viml_pexpr_repr_token(const ParserState *const pstate,
eltkn_type_tab[token.type]);
switch (token.type) {
#define TKNARGS(tkn_type, ...) \
- case tkn_type: { \
- ADDSTR(__VA_ARGS__); \
- break; \
- }
+case tkn_type: { \
+ ADDSTR(__VA_ARGS__); \
+ break; \
+}
TKNARGS(kExprLexComparison, "(type=%s,ccs=%s,inv=%i)",
eltkn_cmp_type_tab[token.data.cmp.type],
ccs_tab[token.data.cmp.ccs],
@@ -769,7 +824,7 @@ const char *viml_pexpr_repr_token(const ParserState *const pstate,
TKNARGS(kExprLexAssignment, "(type=%s)",
expr_asgn_type_tab[token.data.ass.type])
TKNARGS(kExprLexRegister, "(name=%s)", intchar2str(token.data.reg.name))
- case kExprLexDoubleQuotedString:
+ case kExprLexDoubleQuotedString:
TKNARGS(kExprLexSingleQuotedString, "(closed=%i)",
(int)token.data.str.closed)
TKNARGS(kExprLexOption, "(scope=%s,name=%.*s)",
@@ -785,19 +840,17 @@ const char *viml_pexpr_repr_token(const ParserState *const pstate,
? (double)token.data.num.val.floating
: (double)token.data.num.val.integer))
TKNARGS(kExprLexInvalid, "(msg=%s)", token.data.err.msg)
- default: {
- // No additional arguments.
- break;
- }
+ default:
+ // No additional arguments.
+ break;
#undef TKNARGS
}
if (pstate == NULL) {
ADDSTR("::%zu", token.len);
} else {
*p++ = ':';
- memmove(
- p, &pstate->reader.lines.items[token.start.line].data[token.start.col],
- token.len);
+ memmove(p, &pstate->reader.lines.items[token.start.line].data[token.start.col],
+ token.len);
p += token.len;
*p = NUL;
}
@@ -860,7 +913,7 @@ const char *const east_node_type_tab[] = {
///
/// @param[in] ch Character to convert.
///
-/// @return Converted string, stored in a static buffer (overriden after each
+/// @return Converted string, stored in a static buffer (overridden after each
/// call).
static const char *intchar2str(const int ch)
FUNC_ATTR_WARN_UNUSED_RESULT
@@ -883,12 +936,11 @@ static const char *intchar2str(const int ch)
}
#ifdef UNIT_TESTING
-#include <stdio.h>
+# include <stdio.h>
REAL_FATTR_UNUSED
-static inline void viml_pexpr_debug_print_ast_node(
- const ExprASTNode *const *const eastnode_p,
- const char *const prefix)
+static inline void viml_pexpr_debug_print_ast_node(const ExprASTNode *const *const eastnode_p,
+ const char *const prefix)
{
if (*eastnode_p == NULL) {
fprintf(stderr, "%s %p : NULL\n", prefix, (void *)eastnode_p);
@@ -901,35 +953,33 @@ static inline void viml_pexpr_debug_print_ast_node(
}
REAL_FATTR_UNUSED
-static inline void viml_pexpr_debug_print_ast_stack(
- const ExprASTStack *const ast_stack,
- const char *const msg)
+static inline void viml_pexpr_debug_print_ast_stack(const ExprASTStack *const ast_stack,
+ const char *const msg)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_ALWAYS_INLINE
{
fprintf(stderr, "\n%sstack: %zu:\n", msg, kv_size(*ast_stack));
for (size_t i = 0; i < kv_size(*ast_stack); i++) {
- viml_pexpr_debug_print_ast_node(
- (const ExprASTNode *const *)kv_A(*ast_stack, i),
- "-");
+ viml_pexpr_debug_print_ast_node((const ExprASTNode *const *)kv_A(*ast_stack, i),
+ "-");
}
}
REAL_FATTR_UNUSED
-static inline void viml_pexpr_debug_print_token(
- const ParserState *const pstate, const LexExprToken token)
+static inline void viml_pexpr_debug_print_token(const ParserState *const pstate,
+ const LexExprToken token)
FUNC_ATTR_ALWAYS_INLINE
{
fprintf(stderr, "\ntkn: %s\n", viml_pexpr_repr_token(pstate, token, NULL));
}
-#define PSTACK(msg) \
- viml_pexpr_debug_print_ast_stack(&ast_stack, #msg)
-#define PSTACK_P(msg) \
- viml_pexpr_debug_print_ast_stack(ast_stack, #msg)
-#define PNODE_P(eastnode_p, msg) \
- viml_pexpr_debug_print_ast_node((const ExprASTNode *const *)eastnode_p, \
- (#msg))
-#define PTOKEN(tkn) \
- viml_pexpr_debug_print_token(pstate, tkn)
+# define PSTACK(msg) \
+ viml_pexpr_debug_print_ast_stack(&ast_stack, #msg)
+# define PSTACK_P(msg) \
+ viml_pexpr_debug_print_ast_stack(ast_stack, #msg)
+# define PNODE_P(eastnode_p, msg) \
+ viml_pexpr_debug_print_ast_node((const ExprASTNode *const *)eastnode_p, \
+ (#msg))
+# define PTOKEN(tkn) \
+ viml_pexpr_debug_print_token(pstate, tkn)
#endif
const uint8_t node_maxchildren[] = {
@@ -1009,50 +1059,48 @@ void viml_pexpr_free_ast(ExprAST ast)
} else if (*cur_node != NULL) {
kv_drop(ast_stack, 1);
switch ((*cur_node)->type) {
- case kExprNodeDoubleQuotedString:
- case kExprNodeSingleQuotedString: {
- xfree((*cur_node)->data.str.value);
- break;
- }
- case kExprNodeMissing:
- case kExprNodeOpMissing:
- case kExprNodeTernary:
- case kExprNodeTernaryValue:
- case kExprNodeRegister:
- case kExprNodeSubscript:
- case kExprNodeListLiteral:
- case kExprNodeUnaryPlus:
- case kExprNodeBinaryPlus:
- case kExprNodeNested:
- case kExprNodeCall:
- case kExprNodePlainIdentifier:
- case kExprNodePlainKey:
- case kExprNodeComplexIdentifier:
- case kExprNodeUnknownFigure:
- case kExprNodeLambda:
- case kExprNodeDictLiteral:
- case kExprNodeCurlyBracesIdentifier:
- case kExprNodeAssignment:
- case kExprNodeComma:
- case kExprNodeColon:
- case kExprNodeArrow:
- case kExprNodeComparison:
- case kExprNodeConcat:
- case kExprNodeConcatOrSubscript:
- case kExprNodeInteger:
- case kExprNodeFloat:
- case kExprNodeOr:
- case kExprNodeAnd:
- case kExprNodeUnaryMinus:
- case kExprNodeBinaryMinus:
- case kExprNodeNot:
- case kExprNodeMultiplication:
- case kExprNodeDivision:
- case kExprNodeMod:
- case kExprNodeOption:
- case kExprNodeEnvironment: {
- break;
- }
+ case kExprNodeDoubleQuotedString:
+ case kExprNodeSingleQuotedString:
+ xfree((*cur_node)->data.str.value);
+ break;
+ case kExprNodeMissing:
+ case kExprNodeOpMissing:
+ case kExprNodeTernary:
+ case kExprNodeTernaryValue:
+ case kExprNodeRegister:
+ case kExprNodeSubscript:
+ case kExprNodeListLiteral:
+ case kExprNodeUnaryPlus:
+ case kExprNodeBinaryPlus:
+ case kExprNodeNested:
+ case kExprNodeCall:
+ case kExprNodePlainIdentifier:
+ case kExprNodePlainKey:
+ case kExprNodeComplexIdentifier:
+ case kExprNodeUnknownFigure:
+ case kExprNodeLambda:
+ case kExprNodeDictLiteral:
+ case kExprNodeCurlyBracesIdentifier:
+ case kExprNodeAssignment:
+ case kExprNodeComma:
+ case kExprNodeColon:
+ case kExprNodeArrow:
+ case kExprNodeComparison:
+ case kExprNodeConcat:
+ case kExprNodeConcatOrSubscript:
+ case kExprNodeInteger:
+ case kExprNodeFloat:
+ case kExprNodeOr:
+ case kExprNodeAnd:
+ case kExprNodeUnaryMinus:
+ case kExprNodeBinaryMinus:
+ case kExprNodeNot:
+ case kExprNodeMultiplication:
+ case kExprNodeDivision:
+ case kExprNodeMod:
+ case kExprNodeOption:
+ case kExprNodeEnvironment:
+ break;
}
xfree(*cur_node);
*cur_node = NULL;
@@ -1204,10 +1252,8 @@ static inline ExprOpAssociativity node_ass(const ExprASTNode node)
/// @param[out] ast_err Location where error is saved, if any.
///
/// @return True if no errors occurred, false otherwise.
-static bool viml_pexpr_handle_bop(const ParserState *const pstate,
- ExprASTStack *const ast_stack,
- ExprASTNode *const bop_node,
- ExprASTWantedNode *const want_node_p,
+static bool viml_pexpr_handle_bop(const ParserState *const pstate, ExprASTStack *const ast_stack,
+ ExprASTNode *const bop_node, ExprASTWantedNode *const want_node_p,
ExprASTError *const ast_err)
FUNC_ATTR_NONNULL_ALL
{
@@ -1223,8 +1269,8 @@ static bool viml_pexpr_handle_bop(const ParserState *const pstate,
: node_lvl(*bop_node));
#ifndef NDEBUG
const ExprOpAssociativity bop_node_ass = (
- (bop_node->type == kExprNodeCall
- || bop_node->type == kExprNodeSubscript)
+ (bop_node->type == kExprNodeCall
+ || bop_node->type == kExprNodeSubscript)
? kEOpAssLeft
: node_ass(*bop_node));
#endif
@@ -1301,8 +1347,7 @@ static bool viml_pexpr_handle_bop(const ParserState *const pstate,
/// @param[in] shift Number of bytes to shift.
///
/// @return Shifted position.
-static inline ParserPosition shifted_pos(const ParserPosition pos,
- const size_t shift)
+static inline ParserPosition shifted_pos(const ParserPosition pos, const size_t shift)
FUNC_ATTR_CONST FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_WARN_UNUSED_RESULT
{
return (ParserPosition) { .line = pos.line, .col = pos.col + shift };
@@ -1316,8 +1361,7 @@ static inline ParserPosition shifted_pos(const ParserPosition pos,
/// @param[in] new_col New column.
///
/// @return Shifted position.
-static inline ParserPosition recol_pos(const ParserPosition pos,
- const size_t new_col)
+static inline ParserPosition recol_pos(const ParserPosition pos, const size_t new_col)
FUNC_ATTR_CONST FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_WARN_UNUSED_RESULT
{
return (ParserPosition) { .line = pos.line, .col = new_col };
@@ -1328,22 +1372,22 @@ static inline ParserPosition recol_pos(const ParserPosition pos,
/// Highlight current token with the given group
#define HL_CUR_TOKEN(g) \
- viml_parser_highlight(pstate, cur_token.start, cur_token.len, \
- HL(g))
+ viml_parser_highlight(pstate, cur_token.start, cur_token.len, \
+ HL(g))
/// Allocate new node, saving some values
#define NEW_NODE(type) \
- viml_pexpr_new_node(type)
+ viml_pexpr_new_node(type)
/// Set position of the given node to position from the given token
///
/// @param cur_node Node to modify.
/// @param cur_token Token to set position from.
#define POS_FROM_TOKEN(cur_node, cur_token) \
- do { \
- (cur_node)->start = cur_token.start; \
- (cur_node)->len = cur_token.len; \
- } while (0)
+ do { \
+ (cur_node)->start = cur_token.start; \
+ (cur_node)->len = cur_token.len; \
+ } while (0)
/// Allocate new node and set its position from the current token
///
@@ -1352,27 +1396,27 @@ static inline ParserPosition recol_pos(const ParserPosition pos,
/// @param cur_node Variable to save allocated node to.
/// @param typ Node type.
#define NEW_NODE_WITH_CUR_POS(cur_node, typ) \
- do { \
- (cur_node) = NEW_NODE(typ); \
- POS_FROM_TOKEN((cur_node), cur_token); \
- if (prev_token.type == kExprLexSpacing) { \
- (cur_node)->start = prev_token.start; \
- (cur_node)->len += prev_token.len; \
- } \
- } while (0)
+ do { \
+ (cur_node) = NEW_NODE(typ); \
+ POS_FROM_TOKEN((cur_node), cur_token); \
+ if (prev_token.type == kExprLexSpacing) { \
+ (cur_node)->start = prev_token.start; \
+ (cur_node)->len += prev_token.len; \
+ } \
+ } while (0)
/// Check whether it is possible to have next expression after current
///
/// For :echo: `:echo @a @a` is a valid expression. `:echo (@a @a)` is not.
#define MAY_HAVE_NEXT_EXPR \
- (kv_size(ast_stack) == 1)
+ (kv_size(ast_stack) == 1)
/// Add operator node
///
/// @param[in] cur_node Node to add.
#define ADD_OP_NODE(cur_node) \
- is_invalid |= !viml_pexpr_handle_bop(pstate, &ast_stack, cur_node, \
- &want_node, &ast.err)
+ is_invalid |= !viml_pexpr_handle_bop(pstate, &ast_stack, cur_node, \
+ &want_node, &ast.err)
/// Record missing operator: for things like
///
@@ -1384,33 +1428,33 @@ static inline ParserPosition recol_pos(const ParserPosition pos,
///
/// (parsed as OpMissing(@a, @a)).
#define OP_MISSING \
- do { \
- if (flags & kExprFlagsMulti && MAY_HAVE_NEXT_EXPR) { \
- /* Multiple expressions allowed, return without calling */ \
- /* viml_parser_advance(). */ \
- goto viml_pexpr_parse_end; \
- } else { \
- assert(*top_node_p != NULL); \
- ERROR_FROM_TOKEN_AND_MSG(cur_token, _("E15: Missing operator: %.*s")); \
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeOpMissing); \
- cur_node->len = 0; \
- ADD_OP_NODE(cur_node); \
- goto viml_pexpr_parse_process_token; \
- } \
- } while (0)
+ do { \
+ if (flags & kExprFlagsMulti && MAY_HAVE_NEXT_EXPR) { \
+ /* Multiple expressions allowed, return without calling */ \
+ /* viml_parser_advance(). */ \
+ goto viml_pexpr_parse_end; \
+ } else { \
+ assert(*top_node_p != NULL); \
+ ERROR_FROM_TOKEN_AND_MSG(cur_token, _("E15: Missing operator: %.*s")); \
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeOpMissing); \
+ cur_node->len = 0; \
+ ADD_OP_NODE(cur_node); \
+ goto viml_pexpr_parse_process_token; \
+ } \
+ } while (0)
/// Record missing value: for things like "* 5"
///
/// @param[in] msg Error message.
#define ADD_VALUE_IF_MISSING(msg) \
- do { \
- if (want_node == kENodeValue) { \
- ERROR_FROM_TOKEN_AND_MSG(cur_token, (msg)); \
- NEW_NODE_WITH_CUR_POS((*top_node_p), kExprNodeMissing); \
- (*top_node_p)->len = 0; \
- want_node = kENodeOperator; \
- } \
- } while (0)
+ do { \
+ if (want_node == kENodeValue) { \
+ ERROR_FROM_TOKEN_AND_MSG(cur_token, (msg)); \
+ NEW_NODE_WITH_CUR_POS((*top_node_p), kExprNodeMissing); \
+ (*top_node_p)->len = 0; \
+ want_node = kENodeOperator; \
+ } \
+ } while (0)
/// Set AST error, unless AST already is not correct
///
@@ -1419,10 +1463,8 @@ static inline ParserPosition recol_pos(const ParserPosition pos,
/// @param[in] msg Error message, assumed to be already translated and
/// containing a single %token "%.*s".
/// @param[in] start Position at which error occurred.
-static inline void east_set_error(const ParserState *const pstate,
- ExprASTError *const ret_ast_err,
- const char *const msg,
- const ParserPosition start)
+static inline void east_set_error(const ParserState *const pstate, ExprASTError *const ret_ast_err,
+ const char *const msg, const ParserPosition start)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_ALWAYS_INLINE
{
if (ret_ast_err->msg != NULL) {
@@ -1436,21 +1478,21 @@ static inline void east_set_error(const ParserState *const pstate,
/// Set error from the given token and given message
#define ERROR_FROM_TOKEN_AND_MSG(cur_token, msg) \
- do { \
- is_invalid = true; \
- east_set_error(pstate, &ast.err, msg, cur_token.start); \
- } while (0)
+ do { \
+ is_invalid = true; \
+ east_set_error(pstate, &ast.err, msg, cur_token.start); \
+ } while (0)
/// Like #ERROR_FROM_TOKEN_AND_MSG, but gets position from a node
#define ERROR_FROM_NODE_AND_MSG(node, msg) \
- do { \
- is_invalid = true; \
- east_set_error(pstate, &ast.err, msg, node->start); \
- } while (0)
+ do { \
+ is_invalid = true; \
+ east_set_error(pstate, &ast.err, msg, node->start); \
+ } while (0)
/// Set error from the given kExprLexInvalid token
#define ERROR_FROM_TOKEN(cur_token) \
- ERROR_FROM_TOKEN_AND_MSG(cur_token, cur_token.data.err.msg)
+ ERROR_FROM_TOKEN_AND_MSG(cur_token, cur_token.data.err.msg)
/// Select figure brace type, altering highlighting as well if needed
///
@@ -1459,16 +1501,16 @@ static inline void east_set_error(const ParserState *const pstate,
/// kExprNode prefix.
/// @param[in] hl Corresponding highlighting, passed as an argument to #HL.
#define SELECT_FIGURE_BRACE_TYPE(node, new_type, hl) \
- do { \
- ExprASTNode *const node_ = (node); \
- assert(node_->type == kExprNodeUnknownFigure \
- || node_->type == kExprNode##new_type); \
- node_->type = kExprNode##new_type; \
- if (pstate->colors) { \
- kv_A(*pstate->colors, node_->data.fig.opening_hl_idx).group = \
- HL(hl); \
- } \
- } while (0)
+ do { \
+ ExprASTNode *const node_ = (node); \
+ assert(node_->type == kExprNodeUnknownFigure \
+ || node_->type == kExprNode##new_type); \
+ node_->type = kExprNode##new_type; \
+ if (pstate->colors) { \
+ kv_A(*pstate->colors, node_->data.fig.opening_hl_idx).group = \
+ HL(hl); \
+ } \
+ } while (0)
/// Add identifier which should constitute complex identifier node
///
@@ -1479,45 +1521,45 @@ static inline void east_set_error(const ParserState *const pstate,
/// a trailing semicolon.
/// @param hl Highlighting name to use, passed as an argument to #HL.
#define ADD_IDENT(new_ident_node_code, hl) \
- do { \
- assert(want_node == kENodeOperator); \
- /* Operator: may only be curly braces name, but only under certain */ \
- /* conditions. */ \
+ do { \
+ assert(want_node == kENodeOperator); \
+ /* Operator: may only be curly braces name, but only under certain */ \
+ /* conditions. */ \
\
- /* First condition is that there is no space before a part of complex */ \
- /* identifier. */ \
- if (prev_token.type == kExprLexSpacing) { \
- OP_MISSING; \
- } \
- switch ((*top_node_p)->type) { \
- /* Second is that previous node is one of the identifiers: */ \
- /* complex, plain, curly braces. */ \
+ /* First condition is that there is no space before a part of complex */ \
+ /* identifier. */ \
+ if (prev_token.type == kExprLexSpacing) { \
+ OP_MISSING; \
+ } \
+ switch ((*top_node_p)->type) { \
+ /* Second is that previous node is one of the identifiers: */ \
+ /* complex, plain, curly braces. */ \
\
- /* TODO(ZyX-I): Extend syntax to allow ${expr}. This is needed to */ \
- /* handle environment variables like those bash uses for */ \
- /* `export -f`: their names consist not only of alphanumeric */ \
- /* characetrs. */ \
- case kExprNodeComplexIdentifier: \
- case kExprNodePlainIdentifier: \
- case kExprNodeCurlyBracesIdentifier: { \
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeComplexIdentifier); \
- cur_node->len = 0; \
- cur_node->children = *top_node_p; \
- *top_node_p = cur_node; \
- kvi_push(ast_stack, &cur_node->children->next); \
- ExprASTNode **const new_top_node_p = kv_last(ast_stack); \
- assert(*new_top_node_p == NULL); \
- new_ident_node_code; \
- *new_top_node_p = cur_node; \
- HL_CUR_TOKEN(hl); \
- break; \
- } \
- default: { \
- OP_MISSING; \
- break; \
- } \
- } \
- } while (0)
+ /* TODO(ZyX-I): Extend syntax to allow ${expr}. This is needed to */ \
+ /* handle environment variables like those bash uses for */ \
+ /* `export -f`: their names consist not only of alphanumeric */ \
+ /* characetrs. */ \
+ case kExprNodeComplexIdentifier: \
+ case kExprNodePlainIdentifier: \
+ case kExprNodeCurlyBracesIdentifier: { \
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeComplexIdentifier); \
+ cur_node->len = 0; \
+ cur_node->children = *top_node_p; \
+ *top_node_p = cur_node; \
+ kvi_push(ast_stack, &cur_node->children->next); \
+ ExprASTNode **const new_top_node_p = kv_last(ast_stack); \
+ assert(*new_top_node_p == NULL); \
+ new_ident_node_code; \
+ *new_top_node_p = cur_node; \
+ HL_CUR_TOKEN(hl); \
+ break; \
+ } \
+ default: { \
+ OP_MISSING; \
+ break; \
+ } \
+ } \
+ } while (0)
/// Determine whether given parse type is an assignment
///
@@ -1551,10 +1593,8 @@ typedef struct {
/// @param[in] ast_stack Parser AST stack, used to detect whether current
/// string is a regex.
/// @param[in] is_invalid Whether currently processed token is not valid.
-static void parse_quoted_string(ParserState *const pstate,
- ExprASTNode *const node,
- const LexExprToken token,
- const ExprASTStack ast_stack,
+static void parse_quoted_string(ParserState *const pstate, ExprASTNode *const node,
+ const LexExprToken token, const ExprASTStack ast_stack,
const bool is_invalid)
FUNC_ATTR_NONNULL_ALL
{
@@ -1577,10 +1617,10 @@ static void parse_quoted_string(ParserState *const pstate,
p = chunk_e + 2;
if (pstate->colors) {
kvi_push(shifts, ((StringShift) {
- .start = token.start.col + (size_t)(chunk_e - s),
- .orig_len = 2,
- .act_len = 1,
- .escape_not_known = false,
+ .start = token.start.col + (size_t)(chunk_e - s),
+ .orig_len = 2,
+ .act_len = 1,
+ .escape_not_known = false,
}));
}
}
@@ -1613,70 +1653,74 @@ static void parse_quoted_string(ParserState *const pstate,
break;
}
switch (*p) {
- // A "\<x>" form occupies at least 4 characters, and produces up to
- // 6 characters: reserve space for 2 extra, but do not compute actual
- // length just now, it would be costy.
- case '<': {
- size += 2;
- break;
- }
- // Hexadecimal, always single byte, but at least three bytes each.
- case 'x': case 'X': {
+ // A "\<x>" form occupies at least 4 characters, and produces up to
+ // 6 characters: reserve space for 2 extra, but do not compute actual
+ // length just now, it would be costy.
+ case '<':
+ size += 2;
+ break;
+ // Hexadecimal, always single byte, but at least three bytes each.
+ case 'x':
+ case 'X':
+ size--;
+ if (ascii_isxdigit(p[1])) {
size--;
- if (ascii_isxdigit(p[1])) {
+ if (p + 2 < e && ascii_isxdigit(p[2])) {
size--;
- if (p + 2 < e && ascii_isxdigit(p[2])) {
- size--;
- }
}
- break;
}
- // Unicode
- //
- // \uF takes 1 byte which is 2 bytes less then escape sequence.
- // \uFF: 2 bytes, 2 bytes less.
- // \uFFF: 3 bytes, 2 bytes less.
- // \uFFFF: 3 bytes, 3 bytes less.
- // \UFFFFF: 4 bytes, 3 bytes less.
- // \UFFFFFF: 5 bytes, 3 bytes less.
- // \UFFFFFFF: 6 bytes, 3 bytes less.
- // \U7FFFFFFF: 6 bytes, 4 bytes less.
- case 'u': case 'U': {
- const char *const esc_start = p;
- size_t n = (*p == 'u' ? 4 : 8);
- int nr = 0;
+ break;
+ // Unicode
+ //
+ // \uF takes 1 byte which is 2 bytes less then escape sequence.
+ // \uFF: 2 bytes, 2 bytes less.
+ // \uFFF: 3 bytes, 2 bytes less.
+ // \uFFFF: 3 bytes, 3 bytes less.
+ // \UFFFFF: 4 bytes, 3 bytes less.
+ // \UFFFFFF: 5 bytes, 3 bytes less.
+ // \UFFFFFFF: 6 bytes, 3 bytes less.
+ // \U7FFFFFFF: 6 bytes, 4 bytes less.
+ case 'u':
+ case 'U': {
+ const char *const esc_start = p;
+ size_t n = (*p == 'u' ? 4 : 8);
+ int nr = 0;
+ p++;
+ while (p + 1 < e && n-- && ascii_isxdigit(p[1])) {
p++;
- while (p + 1 < e && n-- && ascii_isxdigit(p[1])) {
- p++;
- nr = (nr << 4) + hex2nr(*p);
- }
- // Escape length: (esc_start - 1) points to "\\", esc_start to "u"
- // or "U", p to the byte after last byte. So escape sequence
- // occupies p - (esc_start - 1), but it stands for a utf_char2len
- // bytes.
- size -= (size_t)((p - (esc_start - 1)) - utf_char2len(nr));
- p--;
- break;
+ nr = (nr << 4) + hex2nr(*p);
}
- // Octal, always single byte, but at least two bytes each.
- case '0': case '1': case '2': case '3': case '4': case '5': case '6':
- case '7': {
+ // Escape length: (esc_start - 1) points to "\\", esc_start to "u"
+ // or "U", p to the byte after last byte. So escape sequence
+ // occupies p - (esc_start - 1), but it stands for a utf_char2len
+ // bytes.
+ size -= (size_t)((p - (esc_start - 1)) - utf_char2len(nr));
+ p--;
+ break;
+ }
+ // Octal, always single byte, but at least two bytes each.
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ size--;
+ p++;
+ if (*p >= '0' && *p <= '7') {
size--;
p++;
- if (*p >= '0' && *p <= '7') {
+ if (p < e && *p >= '0' && *p <= '7') {
size--;
p++;
- if (p < e && *p >= '0' && *p <= '7') {
- size--;
- p++;
- }
}
- break;
- }
- default: {
- size--;
- break;
}
+ break;
+ default:
+ size--;
+ break;
}
}
}
@@ -1705,11 +1749,11 @@ static void parse_quoted_string(ParserState *const pstate,
const char *const v_p_start = v_p;
switch (*p) {
#define SINGLE_CHAR_ESC(ch, real_ch) \
- case ch: { \
- *v_p++ = real_ch; \
- p++; \
- break; \
- }
+case ch: { \
+ *v_p++ = real_ch; \
+ p++; \
+ break; \
+}
SINGLE_CHAR_ESC('b', BS)
SINGLE_CHAR_ESC('e', ESC)
SINGLE_CHAR_ESC('f', FF)
@@ -1720,76 +1764,83 @@ static void parse_quoted_string(ParserState *const pstate,
SINGLE_CHAR_ESC('\\', '\\')
#undef SINGLE_CHAR_ESC
- // Hexadecimal or unicode.
- case 'X': case 'x': case 'u': case 'U': {
- if (p + 1 < e && ascii_isxdigit(p[1])) {
- size_t n;
- int nr;
- bool is_hex = (*p == 'x' || *p == 'X');
-
- if (is_hex) {
- n = 2;
- } else if (*p == 'u') {
- n = 4;
- } else {
- n = 8;
- }
- nr = 0;
- while (p + 1 < e && n-- && ascii_isxdigit(p[1])) {
- p++;
- nr = (nr << 4) + hex2nr(*p);
- }
- p++;
- if (is_hex) {
- *v_p++ = (char)nr;
- } else {
- v_p += utf_char2bytes(nr, (char_u *)v_p);
- }
+ // Hexadecimal or unicode.
+ case 'X':
+ case 'x':
+ case 'u':
+ case 'U':
+ if (p + 1 < e && ascii_isxdigit(p[1])) {
+ size_t n;
+ int nr;
+ bool is_hex = (*p == 'x' || *p == 'X');
+
+ if (is_hex) {
+ n = 2;
+ } else if (*p == 'u') {
+ n = 4;
} else {
- is_unknown = true;
- *v_p++ = *p;
+ n = 8;
+ }
+ nr = 0;
+ while (p + 1 < e && n-- && ascii_isxdigit(p[1])) {
p++;
+ nr = (nr << 4) + hex2nr(*p);
+ }
+ p++;
+ if (is_hex) {
+ *v_p++ = (char)nr;
+ } else {
+ v_p += utf_char2bytes(nr, (char_u *)v_p);
}
- break;
+ } else {
+ is_unknown = true;
+ *v_p++ = *p;
+ p++;
}
- // Octal: "\1", "\12", "\123".
- case '0': case '1': case '2': case '3': case '4': case '5': case '6':
- case '7': {
- uint8_t ch = (uint8_t)(*p++ - '0');
+ break;
+ // Octal: "\1", "\12", "\123".
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7': {
+ uint8_t ch = (uint8_t)(*p++ - '0');
+ if (p < e && *p >= '0' && *p <= '7') {
+ ch = (uint8_t)((ch << 3) + *p++ - '0');
if (p < e && *p >= '0' && *p <= '7') {
ch = (uint8_t)((ch << 3) + *p++ - '0');
- if (p < e && *p >= '0' && *p <= '7') {
- ch = (uint8_t)((ch << 3) + *p++ - '0');
- }
}
- *v_p++ = (char)ch;
- break;
}
- // Special key, e.g.: "\<C-W>"
- case '<': {
- const size_t special_len = (
- trans_special((const char_u **)&p, (size_t)(e - p),
- (char_u *)v_p, true, true));
- if (special_len != 0) {
- v_p += special_len;
- } else {
- is_unknown = true;
- mb_copy_char((const char_u **)&p, (char_u **)&v_p);
- }
- break;
- }
- default: {
+ *v_p++ = (char)ch;
+ break;
+ }
+ // Special key, e.g.: "\<C-W>"
+ case '<': {
+ const size_t special_len = (
+ trans_special((const char_u **)&p, (size_t)(e - p),
+ (char_u *)v_p, true, true));
+ if (special_len != 0) {
+ v_p += special_len;
+ } else {
is_unknown = true;
mb_copy_char((const char_u **)&p, (char_u **)&v_p);
- break;
}
+ break;
+ }
+ default:
+ is_unknown = true;
+ mb_copy_char((const char_u **)&p, (char_u **)&v_p);
+ break;
}
if (pstate->colors) {
kvi_push(shifts, ((StringShift) {
- .start = token.start.col + (size_t)(chunk_e - s),
- .orig_len = (size_t)(p - chunk_e),
- .act_len = (size_t)(v_p - (char *)v_p_start),
- .escape_not_known = is_unknown,
+ .start = token.start.col + (size_t)(chunk_e - s),
+ .orig_len = (size_t)(p - chunk_e),
+ .act_len = (size_t)(v_p - (char *)v_p_start),
+ .escape_not_known = is_unknown,
}));
}
}
@@ -1901,21 +1952,23 @@ ExprAST viml_pexpr_parse(ParserState *const pstate, const int flags)
size_t asgn_level = 0;
do {
const bool is_concat_or_subscript = (
- want_node == kENodeValue
- && kv_size(ast_stack) > 1
- && (*kv_Z(ast_stack, 1))->type == kExprNodeConcatOrSubscript);
+ want_node == kENodeValue
+ && kv_size(ast_stack) > 1
+ && (*kv_Z(ast_stack,
+ 1))->type == kExprNodeConcatOrSubscript);
const int lexer_additional_flags = (
- kELFlagPeek
- | ((flags & kExprFlagsDisallowEOC) ? kELFlagForbidEOC : 0)
- | ((want_node == kENodeValue
- && (kv_size(ast_stack) == 1
- || ((*kv_Z(ast_stack, 1))->type != kExprNodeConcat
- && ((*kv_Z(ast_stack, 1))->type
- != kExprNodeConcatOrSubscript))))
+ kELFlagPeek
+ | ((flags & kExprFlagsDisallowEOC) ? kELFlagForbidEOC : 0)
+ | ((want_node == kENodeValue
+ && (kv_size(ast_stack) == 1
+ || ((*kv_Z(ast_stack, 1))->type != kExprNodeConcat
+ && ((*kv_Z(ast_stack, 1))->type
+ != kExprNodeConcatOrSubscript))))
? kELFlagAllowFloat
: 0));
- LexExprToken cur_token = viml_pexpr_next_token(
- pstate, want_node_to_lexer_flags[want_node] | lexer_additional_flags);
+ LexExprToken cur_token = viml_pexpr_next_token(pstate,
+ want_node_to_lexer_flags[want_node] |
+ lexer_additional_flags);
if (cur_token.type == kExprLexEOC) {
break;
}
@@ -1924,8 +1977,8 @@ ExprAST viml_pexpr_parse(ParserState *const pstate, const int flags)
bool is_invalid = token_invalid;
viml_pexpr_parse_process_token:
// May use different flags this time.
- cur_token = viml_pexpr_next_token(
- pstate, want_node_to_lexer_flags[want_node] | lexer_additional_flags);
+ cur_token = viml_pexpr_next_token(pstate,
+ want_node_to_lexer_flags[want_node] | lexer_additional_flags);
if (tok_type == kExprLexSpacing) {
if (is_invalid) {
HL_CUR_TOKEN(Spacing);
@@ -1977,12 +2030,12 @@ viml_pexpr_parse_process_token:
// for ternary and because concatenating dictionary with anything is not
// valid. There are more cases when this will make a difference though.
const bool node_is_key = (
- is_concat_or_subscript
- && (cur_token.type == kExprLexPlainIdentifier
+ is_concat_or_subscript
+ && (cur_token.type == kExprLexPlainIdentifier
? (!cur_token.data.var.autoload
&& cur_token.data.var.scope == kExprVarScopeMissing)
: (cur_token.type == kExprLexNumber))
- && prev_token.type != kExprLexSpacing);
+ && prev_token.type != kExprLexSpacing);
if (is_concat_or_subscript && !node_is_key) {
// Note: in Vim "d. a" (this is the reason behind `prev_token.type !=
// kExprLexSpacing` part of the condition) as well as any other "d.{expr}"
@@ -1997,951 +2050,896 @@ viml_pexpr_parse_process_token:
// Pop some stack pt_stack items in case of misplaced nodes.
const bool is_single_assignment = kv_last(pt_stack) == kEPTSingleAssignment;
switch (kv_last(pt_stack)) {
- case kEPTExpr: {
- break;
- }
- case kEPTLambdaArguments: {
- if ((want_node == kENodeOperator
- && tok_type != kExprLexComma
- && tok_type != kExprLexArrow)
- || (want_node == kENodeValue
- && !(cur_token.type == kExprLexPlainIdentifier
- && cur_token.data.var.scope == kExprVarScopeMissing
- && !cur_token.data.var.autoload)
- && tok_type != kExprLexArrow)) {
- lambda_node->data.fig.type_guesses.allow_lambda = false;
- if (lambda_node->children != NULL
- && lambda_node->children->type == kExprNodeComma) {
- // If lambda has comma child this means that parser has already seen
- // at least "{arg1,", so node cannot possibly be anything, but
- // lambda.
-
- // Vim may give E121 or E720 in this case, but it does not look
- // right to have either because both are results of reevaluation
- // possibly-lambda node as a dictionary and here this is not going
- // to happen.
- ERROR_FROM_TOKEN_AND_MSG(
- cur_token,
- _("E15: Expected lambda arguments list or arrow: %.*s"));
- } else {
- // Else it may appear that possibly-lambda node is actually
- // a dictionary or curly-braces-name identifier.
- lambda_node = NULL;
- kv_drop(pt_stack, 1);
- }
+ case kEPTExpr:
+ break;
+ case kEPTLambdaArguments:
+ if ((want_node == kENodeOperator
+ && tok_type != kExprLexComma
+ && tok_type != kExprLexArrow)
+ || (want_node == kENodeValue
+ && !(cur_token.type == kExprLexPlainIdentifier
+ && cur_token.data.var.scope == kExprVarScopeMissing
+ && !cur_token.data.var.autoload)
+ && tok_type != kExprLexArrow)) {
+ lambda_node->data.fig.type_guesses.allow_lambda = false;
+ if (lambda_node->children != NULL
+ && lambda_node->children->type == kExprNodeComma) {
+ // If lambda has comma child this means that parser has already seen
+ // at least "{arg1,", so node cannot possibly be anything, but
+ // lambda.
+
+ // Vim may give E121 or E720 in this case, but it does not look
+ // right to have either because both are results of reevaluation
+ // possibly-lambda node as a dictionary and here this is not going
+ // to happen.
+ ERROR_FROM_TOKEN_AND_MSG(cur_token,
+ _("E15: Expected lambda arguments list or arrow: %.*s"));
+ } else {
+ // Else it may appear that possibly-lambda node is actually
+ // a dictionary or curly-braces-name identifier.
+ lambda_node = NULL;
+ kv_drop(pt_stack, 1);
}
- break;
}
- case kEPTSingleAssignment:
- case kEPTAssignment: {
- if (want_node == kENodeValue
- && tok_type != kExprLexBracket
- && tok_type != kExprLexPlainIdentifier
- && (tok_type != kExprLexFigureBrace || cur_token.data.brc.closing)
- && !(node_is_key && tok_type == kExprLexNumber)
- && tok_type != kExprLexEnv
- && tok_type != kExprLexOption
- && tok_type != kExprLexRegister) {
- ERROR_FROM_TOKEN_AND_MSG(
- cur_token,
- _("E15: Expected value part of assignment lvalue: %.*s"));
- kv_drop(pt_stack, 1);
- } else if (want_node == kENodeOperator
- && tok_type != kExprLexBracket
- && (tok_type != kExprLexFigureBrace
- || cur_token.data.brc.closing)
- && tok_type != kExprLexDot
- && (tok_type != kExprLexComma || !is_single_assignment)
- && tok_type != kExprLexAssignment
- // Curly brace identifiers: will contain plain identifier or
- // another curly brace in position where operator is wanted.
- && !((tok_type == kExprLexPlainIdentifier
- || (tok_type == kExprLexFigureBrace
- && !cur_token.data.brc.closing))
- && prev_token.type != kExprLexSpacing)) {
- if (flags & kExprFlagsMulti && MAY_HAVE_NEXT_EXPR) {
- goto viml_pexpr_parse_end;
- }
- ERROR_FROM_TOKEN_AND_MSG(
- cur_token,
- _("E15: Expected assignment operator or subscript: %.*s"));
- kv_drop(pt_stack, 1);
+ break;
+ case kEPTSingleAssignment:
+ case kEPTAssignment:
+ if (want_node == kENodeValue
+ && tok_type != kExprLexBracket
+ && tok_type != kExprLexPlainIdentifier
+ && (tok_type != kExprLexFigureBrace || cur_token.data.brc.closing)
+ && !(node_is_key && tok_type == kExprLexNumber)
+ && tok_type != kExprLexEnv
+ && tok_type != kExprLexOption
+ && tok_type != kExprLexRegister) {
+ ERROR_FROM_TOKEN_AND_MSG(cur_token,
+ _("E15: Expected value part of assignment lvalue: %.*s"));
+ kv_drop(pt_stack, 1);
+ } else if (want_node == kENodeOperator
+ && tok_type != kExprLexBracket
+ && (tok_type != kExprLexFigureBrace
+ || cur_token.data.brc.closing)
+ && tok_type != kExprLexDot
+ && (tok_type != kExprLexComma || !is_single_assignment)
+ && tok_type != kExprLexAssignment
+ // Curly brace identifiers: will contain plain identifier or
+ // another curly brace in position where operator is wanted.
+ && !((tok_type == kExprLexPlainIdentifier
+ || (tok_type == kExprLexFigureBrace
+ && !cur_token.data.brc.closing))
+ && prev_token.type != kExprLexSpacing)) {
+ if (flags & kExprFlagsMulti && MAY_HAVE_NEXT_EXPR) {
+ goto viml_pexpr_parse_end;
}
- assert(kv_size(pt_stack));
- break;
+ ERROR_FROM_TOKEN_AND_MSG(cur_token,
+ _("E15: Expected assignment operator or subscript: %.*s"));
+ kv_drop(pt_stack, 1);
}
+ assert(kv_size(pt_stack));
+ break;
}
assert(kv_size(pt_stack));
const ExprASTParseType cur_pt = kv_last(pt_stack);
assert(lambda_node == NULL || cur_pt == kEPTLambdaArguments);
switch (tok_type) {
- case kExprLexMissing:
- case kExprLexSpacing:
- case kExprLexEOC: {
- abort();
- }
- case kExprLexInvalid: {
- ERROR_FROM_TOKEN(cur_token);
- tok_type = cur_token.data.err.type;
- goto viml_pexpr_parse_process_token;
- }
- case kExprLexRegister: {
- if (want_node == kENodeOperator) {
- // Register in operator position: e.g. @a @a
- OP_MISSING;
- }
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeRegister);
- cur_node->data.reg.name = cur_token.data.reg.name;
- *top_node_p = cur_node;
- want_node = kENodeOperator;
- HL_CUR_TOKEN(Register);
- break;
+ case kExprLexMissing:
+ case kExprLexSpacing:
+ case kExprLexEOC:
+ abort();
+ case kExprLexInvalid:
+ ERROR_FROM_TOKEN(cur_token);
+ tok_type = cur_token.data.err.type;
+ goto viml_pexpr_parse_process_token;
+ case kExprLexRegister: {
+ if (want_node == kENodeOperator) {
+ // Register in operator position: e.g. @a @a
+ OP_MISSING;
}
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeRegister);
+ cur_node->data.reg.name = cur_token.data.reg.name;
+ *top_node_p = cur_node;
+ want_node = kENodeOperator;
+ HL_CUR_TOKEN(Register);
+ break;
+ }
#define SIMPLE_UB_OP(op) \
- case kExprLex##op: { \
- if (want_node == kENodeValue) { \
- /* Value level: assume unary operator. */ \
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeUnary##op); \
- *top_node_p = cur_node; \
- kvi_push(ast_stack, &cur_node->children); \
- HL_CUR_TOKEN(Unary##op); \
- } else { \
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeBinary##op); \
- ADD_OP_NODE(cur_node); \
- HL_CUR_TOKEN(Binary##op); \
- } \
- want_node = kENodeValue; \
- break; \
- }
+case kExprLex##op: { \
+ if (want_node == kENodeValue) { \
+ /* Value level: assume unary operator. */ \
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeUnary##op); \
+ *top_node_p = cur_node; \
+ kvi_push(ast_stack, &cur_node->children); \
+ HL_CUR_TOKEN(Unary##op); \
+ } else { \
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeBinary##op); \
+ ADD_OP_NODE(cur_node); \
+ HL_CUR_TOKEN(Binary##op); \
+ } \
+ want_node = kENodeValue; \
+ break; \
+}
SIMPLE_UB_OP(Plus)
SIMPLE_UB_OP(Minus)
#undef SIMPLE_UB_OP
#define SIMPLE_B_OP(op, msg) \
- case kExprLex##op: { \
- ADD_VALUE_IF_MISSING(_("E15: Unexpected " msg ": %.*s")); \
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNode##op); \
- HL_CUR_TOKEN(op); \
- ADD_OP_NODE(cur_node); \
- break; \
- }
+case kExprLex##op: { \
+ ADD_VALUE_IF_MISSING(_("E15: Unexpected " msg ": %.*s")); \
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNode##op); \
+ HL_CUR_TOKEN(op); \
+ ADD_OP_NODE(cur_node); \
+ break; \
+}
SIMPLE_B_OP(Or, "or operator")
SIMPLE_B_OP(And, "and operator")
#undef SIMPLE_B_OP
- case kExprLexMultiplication: {
- ADD_VALUE_IF_MISSING(
- _("E15: Unexpected multiplication-like operator: %.*s"));
- switch (cur_token.data.mul.type) {
+ case kExprLexMultiplication:
+ ADD_VALUE_IF_MISSING(_("E15: Unexpected multiplication-like operator: %.*s"));
+ switch (cur_token.data.mul.type) {
#define MUL_OP(lex_op_tail, node_op_tail) \
- case kExprLexMul##lex_op_tail: { \
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNode##node_op_tail); \
- HL_CUR_TOKEN(node_op_tail); \
- break; \
- }
- MUL_OP(Mul, Multiplication)
- MUL_OP(Div, Division)
- MUL_OP(Mod, Mod)
+case kExprLexMul##lex_op_tail: { \
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNode##node_op_tail); \
+ HL_CUR_TOKEN(node_op_tail); \
+ break; \
+}
+ MUL_OP(Mul, Multiplication)
+ MUL_OP(Div, Division)
+ MUL_OP(Mod, Mod)
#undef MUL_OP
- }
- ADD_OP_NODE(cur_node);
- break;
}
- case kExprLexOption: {
- if (want_node == kENodeOperator) {
- OP_MISSING;
- }
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeOption);
- if (cur_token.type == kExprLexInvalid) {
- assert(cur_token.len == 1
- || (cur_token.len == 3
- && pline.data[cur_token.start.col + 2] == ':'));
- cur_node->data.opt.ident = (
- pline.data + cur_token.start.col + cur_token.len);
- cur_node->data.opt.ident_len = 0;
- cur_node->data.opt.scope = (
- cur_token.len == 3
+ ADD_OP_NODE(cur_node);
+ break;
+ case kExprLexOption: {
+ if (want_node == kENodeOperator) {
+ OP_MISSING;
+ }
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeOption);
+ if (cur_token.type == kExprLexInvalid) {
+ assert(cur_token.len == 1
+ || (cur_token.len == 3
+ && pline.data[cur_token.start.col + 2] == ':'));
+ cur_node->data.opt.ident = (
+ pline.data + cur_token.start.col + cur_token.len);
+ cur_node->data.opt.ident_len = 0;
+ cur_node->data.opt.scope = (
+ cur_token.len == 3
? (ExprOptScope)pline.data[cur_token.start.col + 1]
: kExprOptScopeUnspecified);
- } else {
- cur_node->data.opt.ident = cur_token.data.opt.name;
- cur_node->data.opt.ident_len = cur_token.data.opt.len;
- cur_node->data.opt.scope = cur_token.data.opt.scope;
- }
+ } else {
+ cur_node->data.opt.ident = cur_token.data.opt.name;
+ cur_node->data.opt.ident_len = cur_token.data.opt.len;
+ cur_node->data.opt.scope = cur_token.data.opt.scope;
+ }
+ *top_node_p = cur_node;
+ want_node = kENodeOperator;
+ viml_parser_highlight(pstate, cur_token.start, 1, HL(OptionSigil));
+ const size_t scope_shift = (
+ cur_token.data.opt.scope == kExprOptScopeUnspecified ? 0 : 2);
+ if (scope_shift) {
+ viml_parser_highlight(pstate, shifted_pos(cur_token.start, 1), 1,
+ HL(OptionScope));
+ viml_parser_highlight(pstate, shifted_pos(cur_token.start, 2), 1,
+ HL(OptionScopeDelimiter));
+ }
+ viml_parser_highlight(pstate, shifted_pos(cur_token.start, scope_shift + 1),
+ cur_token.len - (scope_shift + 1), HL(OptionName));
+ break;
+ }
+ case kExprLexEnv:
+ if (want_node == kENodeOperator) {
+ OP_MISSING;
+ }
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeEnvironment);
+ cur_node->data.env.ident = pline.data + cur_token.start.col + 1;
+ cur_node->data.env.ident_len = cur_token.len - 1;
+ if (cur_node->data.env.ident_len == 0) {
+ ERROR_FROM_TOKEN_AND_MSG(cur_token,
+ _("E15: Environment variable name missing"));
+ }
+ *top_node_p = cur_node;
+ want_node = kENodeOperator;
+ viml_parser_highlight(pstate, cur_token.start, 1, HL(EnvironmentSigil));
+ viml_parser_highlight(pstate, shifted_pos(cur_token.start, 1),
+ cur_token.len - 1, HL(EnvironmentName));
+ break;
+ case kExprLexNot:
+ if (want_node == kENodeOperator) {
+ OP_MISSING;
+ }
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeNot);
+ *top_node_p = cur_node;
+ kvi_push(ast_stack, &cur_node->children);
+ HL_CUR_TOKEN(Not);
+ break;
+ case kExprLexComparison:
+ ADD_VALUE_IF_MISSING(_("E15: Expected value, got comparison operator: %.*s"));
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeComparison);
+ if (cur_token.type == kExprLexInvalid) {
+ cur_node->data.cmp.ccs = kCCStrategyUseOption;
+ cur_node->data.cmp.type = kExprCmpEqual;
+ cur_node->data.cmp.inv = false;
+ } else {
+ cur_node->data.cmp.ccs = cur_token.data.cmp.ccs;
+ cur_node->data.cmp.type = cur_token.data.cmp.type;
+ cur_node->data.cmp.inv = cur_token.data.cmp.inv;
+ }
+ ADD_OP_NODE(cur_node);
+ if (cur_token.data.cmp.ccs != kCCStrategyUseOption) {
+ viml_parser_highlight(pstate, cur_token.start, cur_token.len - 1,
+ HL(Comparison));
+ viml_parser_highlight(pstate, shifted_pos(cur_token.start, cur_token.len - 1), 1,
+ HL(ComparisonModifier));
+ } else {
+ HL_CUR_TOKEN(Comparison);
+ }
+ want_node = kENodeValue;
+ break;
+ case kExprLexComma:
+ assert(!(want_node == kENodeValue && cur_pt == kEPTLambdaArguments));
+ if (want_node == kENodeValue) {
+ // Value level: comma appearing here is not valid.
+ // Note: in Vim string(,x) will give E116, this is not the case here.
+ ERROR_FROM_TOKEN_AND_MSG(cur_token, _("E15: Expected value, got comma: %.*s"));
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeMissing);
+ cur_node->len = 0;
*top_node_p = cur_node;
want_node = kENodeOperator;
- viml_parser_highlight(pstate, cur_token.start, 1, HL(OptionSigil));
- const size_t scope_shift = (
- cur_token.data.opt.scope == kExprOptScopeUnspecified ? 0 : 2);
- if (scope_shift) {
- viml_parser_highlight(pstate, shifted_pos(cur_token.start, 1), 1,
- HL(OptionScope));
- viml_parser_highlight(pstate, shifted_pos(cur_token.start, 2), 1,
- HL(OptionScopeDelimiter));
- }
- viml_parser_highlight(
- pstate, shifted_pos(cur_token.start, scope_shift + 1),
- cur_token.len - (scope_shift + 1), HL(OptionName));
- break;
}
- case kExprLexEnv: {
- if (want_node == kENodeOperator) {
- OP_MISSING;
- }
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeEnvironment);
- cur_node->data.env.ident = pline.data + cur_token.start.col + 1;
- cur_node->data.env.ident_len = cur_token.len - 1;
- if (cur_node->data.env.ident_len == 0) {
+ if (cur_pt == kEPTLambdaArguments) {
+ assert(lambda_node != NULL);
+ assert(lambda_node->data.fig.type_guesses.allow_lambda);
+ SELECT_FIGURE_BRACE_TYPE(lambda_node, Lambda, Lambda);
+ }
+ if (kv_size(ast_stack) < 2) {
+ goto viml_pexpr_parse_invalid_comma;
+ }
+ for (size_t i = 1; i < kv_size(ast_stack); i++) {
+ ExprASTNode *const *const eastnode_p =
+ (ExprASTNode *const *)kv_Z(ast_stack, i);
+ const ExprASTNodeType eastnode_type = (*eastnode_p)->type;
+ const ExprOpLvl eastnode_lvl = node_lvl(**eastnode_p);
+ if (eastnode_type == kExprNodeLambda) {
+ assert(cur_pt == kEPTLambdaArguments
+ && want_node == kENodeOperator);
+ break;
+ } else if (eastnode_type == kExprNodeDictLiteral
+ || eastnode_type == kExprNodeListLiteral
+ || eastnode_type == kExprNodeCall) {
+ break;
+ } else if (eastnode_type == kExprNodeComma
+ || eastnode_type == kExprNodeColon
+ || eastnode_lvl > kEOpLvlComma) {
+ // Do nothing
+ } else {
+viml_pexpr_parse_invalid_comma:
ERROR_FROM_TOKEN_AND_MSG(cur_token,
- _("E15: Environment variable name missing"));
+ _("E15: Comma outside of call, lambda or literal: %.*s"));
+ break;
+ }
+ if (i == kv_size(ast_stack) - 1) {
+ goto viml_pexpr_parse_invalid_comma;
}
- *top_node_p = cur_node;
- want_node = kENodeOperator;
- viml_parser_highlight(pstate, cur_token.start, 1, HL(EnvironmentSigil));
- viml_parser_highlight(pstate, shifted_pos(cur_token.start, 1),
- cur_token.len - 1, HL(EnvironmentName));
- break;
}
- case kExprLexNot: {
- if (want_node == kENodeOperator) {
- OP_MISSING;
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeComma);
+ ADD_OP_NODE(cur_node);
+ HL_CUR_TOKEN(Comma);
+ break;
+#define EXP_VAL_COLON "E15: Expected value, got colon: %.*s"
+ case kExprLexColon: {
+ bool is_ternary = false;
+ if (kv_size(ast_stack) < 2) {
+ goto viml_pexpr_parse_invalid_colon;
+ }
+ bool can_be_ternary = true;
+ bool is_subscript = false;
+ for (size_t i = 1; i < kv_size(ast_stack); i++) {
+ ExprASTNode *const *const eastnode_p =
+ (ExprASTNode *const *)kv_Z(ast_stack, i);
+ const ExprASTNodeType eastnode_type = (*eastnode_p)->type;
+ const ExprOpLvl eastnode_lvl = node_lvl(**eastnode_p);
+ STATIC_ASSERT(kEOpLvlTernary > kEOpLvlComma,
+ "Unexpected operator priorities");
+ if (can_be_ternary && eastnode_type == kExprNodeTernaryValue
+ && !(*eastnode_p)->data.ter.got_colon) {
+ kv_drop(ast_stack, i);
+ (*eastnode_p)->start = cur_token.start;
+ (*eastnode_p)->len = cur_token.len;
+ if (prev_token.type == kExprLexSpacing) {
+ (*eastnode_p)->start = prev_token.start;
+ (*eastnode_p)->len += prev_token.len;
+ }
+ is_ternary = true;
+ (*eastnode_p)->data.ter.got_colon = true;
+ ADD_VALUE_IF_MISSING(_(EXP_VAL_COLON));
+ assert((*eastnode_p)->children != NULL);
+ assert((*eastnode_p)->children->next == NULL);
+ kvi_push(ast_stack, &(*eastnode_p)->children->next);
+ break;
+ } else if (eastnode_type == kExprNodeUnknownFigure) {
+ SELECT_FIGURE_BRACE_TYPE(*eastnode_p, DictLiteral, Dict);
+ break;
+ } else if (eastnode_type == kExprNodeDictLiteral) {
+ break;
+ } else if (eastnode_type == kExprNodeSubscript) {
+ is_subscript = true;
+ // can_be_ternary = false;
+ assert(!is_ternary);
+ break;
+ } else if (eastnode_type == kExprNodeColon) {
+ goto viml_pexpr_parse_invalid_colon;
+ } else if (eastnode_lvl >= kEOpLvlTernaryValue) {
+ // Do nothing
+ } else if (eastnode_lvl >= kEOpLvlComma) {
+ can_be_ternary = false;
+ } else {
+ goto viml_pexpr_parse_invalid_colon;
+ }
+ if (i == kv_size(ast_stack) - 1) {
+ goto viml_pexpr_parse_invalid_colon;
}
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeNot);
- *top_node_p = cur_node;
- kvi_push(ast_stack, &cur_node->children);
- HL_CUR_TOKEN(Not);
- break;
}
- case kExprLexComparison: {
- ADD_VALUE_IF_MISSING(
- _("E15: Expected value, got comparison operator: %.*s"));
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeComparison);
- if (cur_token.type == kExprLexInvalid) {
- cur_node->data.cmp.ccs = kCCStrategyUseOption;
- cur_node->data.cmp.type = kExprCmpEqual;
- cur_node->data.cmp.inv = false;
+ if (is_subscript) {
+ assert(kv_size(ast_stack) > 1);
+ // Colon immediately following subscript start: it is empty subscript
+ // part like a[:2].
+ if (want_node == kENodeValue
+ && (*kv_Z(ast_stack, 1))->type == kExprNodeSubscript) {
+ NEW_NODE_WITH_CUR_POS(*top_node_p, kExprNodeMissing);
+ (*top_node_p)->len = 0;
+ want_node = kENodeOperator;
} else {
- cur_node->data.cmp.ccs = cur_token.data.cmp.ccs;
- cur_node->data.cmp.type = cur_token.data.cmp.type;
- cur_node->data.cmp.inv = cur_token.data.cmp.inv;
+ ADD_VALUE_IF_MISSING(_(EXP_VAL_COLON));
}
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeColon);
ADD_OP_NODE(cur_node);
- if (cur_token.data.cmp.ccs != kCCStrategyUseOption) {
- viml_parser_highlight(pstate, cur_token.start, cur_token.len - 1,
- HL(Comparison));
- viml_parser_highlight(
- pstate, shifted_pos(cur_token.start, cur_token.len - 1), 1,
- HL(ComparisonModifier));
+ HL_CUR_TOKEN(SubscriptColon);
+ } else {
+ goto viml_pexpr_parse_valid_colon;
+viml_pexpr_parse_invalid_colon:
+ ERROR_FROM_TOKEN_AND_MSG(cur_token,
+ _("E15: Colon outside of dictionary or ternary operator: %.*s"));
+viml_pexpr_parse_valid_colon:
+ ADD_VALUE_IF_MISSING(_(EXP_VAL_COLON));
+ if (is_ternary) {
+ HL_CUR_TOKEN(TernaryColon);
} else {
- HL_CUR_TOKEN(Comparison);
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeColon);
+ ADD_OP_NODE(cur_node);
+ HL_CUR_TOKEN(Colon);
}
- want_node = kENodeValue;
- break;
}
- case kExprLexComma: {
- assert(!(want_node == kENodeValue && cur_pt == kEPTLambdaArguments));
- if (want_node == kENodeValue) {
- // Value level: comma appearing here is not valid.
- // Note: in Vim string(,x) will give E116, this is not the case here.
- ERROR_FROM_TOKEN_AND_MSG(
- cur_token, _("E15: Expected value, got comma: %.*s"));
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeMissing);
+ want_node = kENodeValue;
+ break;
+ }
+#undef EXP_VAL_COLON
+ case kExprLexBracket:
+ if (cur_token.data.brc.closing) {
+ ExprASTNode **new_top_node_p = NULL;
+ // Always drop the topmost value:
+ //
+ // 1. When want_node != kENodeValue topmost item on stack is
+ // a *finished* left operand, which may as well be "{@a}" which
+ // needs not be finished again.
+ // 2. Otherwise it is pointing to NULL what nobody wants.
+ kv_drop(ast_stack, 1);
+ if (!kv_size(ast_stack)) {
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeListLiteral);
cur_node->len = 0;
+ if (want_node != kENodeValue) {
+ cur_node->children = *top_node_p;
+ }
*top_node_p = cur_node;
- want_node = kENodeOperator;
- }
- if (cur_pt == kEPTLambdaArguments) {
- assert(lambda_node != NULL);
- assert(lambda_node->data.fig.type_guesses.allow_lambda);
- SELECT_FIGURE_BRACE_TYPE(lambda_node, Lambda, Lambda);
+ goto viml_pexpr_parse_bracket_closing_error;
}
- if (kv_size(ast_stack) < 2) {
- goto viml_pexpr_parse_invalid_comma;
+ if (want_node == kENodeValue) {
+ // It is OK to want value if
+ //
+ // 1. It is empty list literal, in which case top node will be
+ // ListLiteral.
+ // 2. It is list literal with trailing comma, in which case top node
+ // will be that comma.
+ // 3. It is subscript with colon, but without one of the values:
+ // e.g. "a[:]", "a[1:]", top node will be colon in this case.
+ if ((*kv_last(ast_stack))->type != kExprNodeListLiteral
+ && (*kv_last(ast_stack))->type != kExprNodeComma
+ && (*kv_last(ast_stack))->type != kExprNodeColon) {
+ ERROR_FROM_TOKEN_AND_MSG(cur_token,
+ _("E15: Expected value, got closing bracket: %.*s"));
+ }
}
- for (size_t i = 1; i < kv_size(ast_stack); i++) {
- ExprASTNode *const *const eastnode_p =
- (ExprASTNode *const *)kv_Z(ast_stack, i);
- const ExprASTNodeType eastnode_type = (*eastnode_p)->type;
- const ExprOpLvl eastnode_lvl = node_lvl(**eastnode_p);
- if (eastnode_type == kExprNodeLambda) {
- assert(cur_pt == kEPTLambdaArguments
- && want_node == kENodeOperator);
- break;
- } else if (eastnode_type == kExprNodeDictLiteral
- || eastnode_type == kExprNodeListLiteral
- || eastnode_type == kExprNodeCall) {
- break;
- } else if (eastnode_type == kExprNodeComma
- || eastnode_type == kExprNodeColon
- || eastnode_lvl > kEOpLvlComma) {
- // Do nothing
- } else {
-viml_pexpr_parse_invalid_comma:
- ERROR_FROM_TOKEN_AND_MSG(
- cur_token,
- _("E15: Comma outside of call, lambda or literal: %.*s"));
- break;
+ do {
+ new_top_node_p = kv_pop(ast_stack);
+ } while (kv_size(ast_stack)
+ && (new_top_node_p == NULL
+ || ((*new_top_node_p)->type != kExprNodeListLiteral
+ && (*new_top_node_p)->type != kExprNodeSubscript)));
+ ExprASTNode *new_top_node = *new_top_node_p;
+ switch (new_top_node->type) {
+ case kExprNodeListLiteral:
+ if (pt_is_assignment(cur_pt) && new_top_node->children == NULL) {
+ ERROR_FROM_TOKEN_AND_MSG(cur_token, _("E475: Unable to assign to empty list: %.*s"));
}
- if (i == kv_size(ast_stack) - 1) {
- goto viml_pexpr_parse_invalid_comma;
+ HL_CUR_TOKEN(List);
+ break;
+ case kExprNodeSubscript:
+ HL_CUR_TOKEN(SubscriptBracket);
+ break;
+ default:
+viml_pexpr_parse_bracket_closing_error:
+ assert(!kv_size(ast_stack));
+ ERROR_FROM_TOKEN_AND_MSG(cur_token, _("E15: Unexpected closing figure brace: %.*s"));
+ HL_CUR_TOKEN(List);
+ break;
+ }
+ kvi_push(ast_stack, new_top_node_p);
+ want_node = kENodeOperator;
+ if (kv_size(ast_stack) <= asgn_level) {
+ assert(kv_size(ast_stack) == asgn_level);
+ asgn_level = 0;
+ if (cur_pt == kEPTAssignment) {
+ assert(ast.err.msg);
+ } else if (cur_pt == kEPTExpr
+ && kv_size(pt_stack) > 1
+ && pt_is_assignment(kv_Z(pt_stack, 1))) {
+ kv_drop(pt_stack, 1);
}
}
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeComma);
- ADD_OP_NODE(cur_node);
- HL_CUR_TOKEN(Comma);
- break;
- }
-#define EXP_VAL_COLON "E15: Expected value, got colon: %.*s"
- case kExprLexColon: {
- bool is_ternary = false;
- if (kv_size(ast_stack) < 2) {
- goto viml_pexpr_parse_invalid_colon;
+ if (cur_pt == kEPTSingleAssignment && kv_size(ast_stack) == 1) {
+ kv_drop(pt_stack, 1);
}
- bool can_be_ternary = true;
- bool is_subscript = false;
- for (size_t i = 1; i < kv_size(ast_stack); i++) {
- ExprASTNode *const *const eastnode_p =
- (ExprASTNode *const *)kv_Z(ast_stack, i);
- const ExprASTNodeType eastnode_type = (*eastnode_p)->type;
- const ExprOpLvl eastnode_lvl = node_lvl(**eastnode_p);
- STATIC_ASSERT(kEOpLvlTernary > kEOpLvlComma,
- "Unexpected operator priorities");
- if (can_be_ternary && eastnode_type == kExprNodeTernaryValue
- && !(*eastnode_p)->data.ter.got_colon) {
- kv_drop(ast_stack, i);
- (*eastnode_p)->start = cur_token.start;
- (*eastnode_p)->len = cur_token.len;
- if (prev_token.type == kExprLexSpacing) {
- (*eastnode_p)->start = prev_token.start;
- (*eastnode_p)->len += prev_token.len;
- }
- is_ternary = true;
- (*eastnode_p)->data.ter.got_colon = true;
- ADD_VALUE_IF_MISSING(_(EXP_VAL_COLON));
- assert((*eastnode_p)->children != NULL);
- assert((*eastnode_p)->children->next == NULL);
- kvi_push(ast_stack, &(*eastnode_p)->children->next);
- break;
- } else if (eastnode_type == kExprNodeUnknownFigure) {
- SELECT_FIGURE_BRACE_TYPE(*eastnode_p, DictLiteral, Dict);
- break;
- } else if (eastnode_type == kExprNodeDictLiteral) {
- break;
- } else if (eastnode_type == kExprNodeSubscript) {
- is_subscript = true;
- // can_be_ternary = false;
- assert(!is_ternary);
- break;
- } else if (eastnode_type == kExprNodeColon) {
- goto viml_pexpr_parse_invalid_colon;
- } else if (eastnode_lvl >= kEOpLvlTernaryValue) {
- // Do nothing
- } else if (eastnode_lvl >= kEOpLvlComma) {
- can_be_ternary = false;
- } else {
- goto viml_pexpr_parse_invalid_colon;
- }
- if (i == kv_size(ast_stack) - 1) {
- goto viml_pexpr_parse_invalid_colon;
+ } else {
+ if (want_node == kENodeValue) {
+ // Value means list literal or list assignment.
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeListLiteral);
+ *top_node_p = cur_node;
+ kvi_push(ast_stack, &cur_node->children);
+ want_node = kENodeValue;
+ if (cur_pt == kEPTAssignment) {
+ // Additional assignment parse type allows to easily forbid nested
+ // lists.
+ kvi_push(pt_stack, kEPTSingleAssignment);
+ } else if (cur_pt == kEPTSingleAssignment) {
+ ERROR_FROM_TOKEN_AND_MSG(cur_token,
+ _("E475: Nested lists not allowed when assigning: %.*s"));
}
- }
- if (is_subscript) {
- assert(kv_size(ast_stack) > 1);
- // Colon immediately following subscript start: it is empty subscript
- // part like a[:2].
- if (want_node == kENodeValue
- && (*kv_Z(ast_stack, 1))->type == kExprNodeSubscript) {
- NEW_NODE_WITH_CUR_POS(*top_node_p, kExprNodeMissing);
- (*top_node_p)->len = 0;
- want_node = kENodeOperator;
- } else {
- ADD_VALUE_IF_MISSING(_(EXP_VAL_COLON));
+ HL_CUR_TOKEN(List);
+ } else {
+ // Operator means subscript, also in assignment. But in assignment
+ // subscript may be pretty much any expression, so need to push
+ // kEPTExpr.
+ if (prev_token.type == kExprLexSpacing) {
+ OP_MISSING;
}
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeColon);
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeSubscript);
ADD_OP_NODE(cur_node);
- HL_CUR_TOKEN(SubscriptColon);
- } else {
- goto viml_pexpr_parse_valid_colon;
-viml_pexpr_parse_invalid_colon:
- ERROR_FROM_TOKEN_AND_MSG(
- cur_token,
- _("E15: Colon outside of dictionary or ternary operator: %.*s"));
-viml_pexpr_parse_valid_colon:
- ADD_VALUE_IF_MISSING(_(EXP_VAL_COLON));
- if (is_ternary) {
- HL_CUR_TOKEN(TernaryColon);
- } else {
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeColon);
- ADD_OP_NODE(cur_node);
- HL_CUR_TOKEN(Colon);
+ HL_CUR_TOKEN(SubscriptBracket);
+ if (pt_is_assignment(cur_pt)) {
+ assert(want_node == kENodeValue); // Subtract 1 for NULL at top.
+ asgn_level = kv_size(ast_stack) - 1;
+ kvi_push(pt_stack, kEPTExpr);
}
}
- want_node = kENodeValue;
- break;
}
-#undef EXP_VAL_COLON
- case kExprLexBracket: {
- if (cur_token.data.brc.closing) {
- ExprASTNode **new_top_node_p = NULL;
- // Always drop the topmost value:
- //
- // 1. When want_node != kENodeValue topmost item on stack is
- // a *finished* left operand, which may as well be "{@a}" which
- // needs not be finished again.
- // 2. Otherwise it is pointing to NULL what nobody wants.
- kv_drop(ast_stack, 1);
- if (!kv_size(ast_stack)) {
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeListLiteral);
- cur_node->len = 0;
- if (want_node != kENodeValue) {
- cur_node->children = *top_node_p;
- }
- *top_node_p = cur_node;
- goto viml_pexpr_parse_bracket_closing_error;
- }
- if (want_node == kENodeValue) {
- // It is OK to want value if
- //
- // 1. It is empty list literal, in which case top node will be
- // ListLiteral.
- // 2. It is list literal with trailing comma, in which case top node
- // will be that comma.
- // 3. It is subscript with colon, but without one of the values:
- // e.g. "a[:]", "a[1:]", top node will be colon in this case.
- if ((*kv_last(ast_stack))->type != kExprNodeListLiteral
- && (*kv_last(ast_stack))->type != kExprNodeComma
- && (*kv_last(ast_stack))->type != kExprNodeColon) {
- ERROR_FROM_TOKEN_AND_MSG(
- cur_token,
- _("E15: Expected value, got closing bracket: %.*s"));
- }
+ break;
+ case kExprLexFigureBrace:
+ if (cur_token.data.brc.closing) {
+ ExprASTNode **new_top_node_p = NULL;
+ // Always drop the topmost value:
+ //
+ // 1. When want_node != kENodeValue topmost item on stack is
+ // a *finished* left operand, which may as well be "{@a}" which
+ // needs not be finished again.
+ // 2. Otherwise it is pointing to NULL what nobody wants.
+ kv_drop(ast_stack, 1);
+ if (!kv_size(ast_stack)) {
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeUnknownFigure);
+ cur_node->data.fig.type_guesses.allow_lambda = false;
+ cur_node->data.fig.type_guesses.allow_dict = false;
+ cur_node->data.fig.type_guesses.allow_ident = false;
+ cur_node->len = 0;
+ if (want_node != kENodeValue) {
+ cur_node->children = *top_node_p;
}
- do {
- new_top_node_p = kv_pop(ast_stack);
- } while (kv_size(ast_stack)
- && (new_top_node_p == NULL
- || ((*new_top_node_p)->type != kExprNodeListLiteral
- && (*new_top_node_p)->type != kExprNodeSubscript)));
- ExprASTNode *new_top_node = *new_top_node_p;
- switch (new_top_node->type) {
- case kExprNodeListLiteral: {
- if (pt_is_assignment(cur_pt) && new_top_node->children == NULL) {
- ERROR_FROM_TOKEN_AND_MSG(
- cur_token, _("E475: Unable to assign to empty list: %.*s"));
- }
- HL_CUR_TOKEN(List);
- break;
- }
- case kExprNodeSubscript: {
- HL_CUR_TOKEN(SubscriptBracket);
- break;
- }
- default: {
-viml_pexpr_parse_bracket_closing_error:
- assert(!kv_size(ast_stack));
- ERROR_FROM_TOKEN_AND_MSG(
- cur_token, _("E15: Unexpected closing figure brace: %.*s"));
- HL_CUR_TOKEN(List);
- break;
- }
+ *top_node_p = cur_node;
+ new_top_node_p = top_node_p;
+ goto viml_pexpr_parse_figure_brace_closing_error;
+ }
+ if (want_node == kENodeValue) {
+ if ((*kv_last(ast_stack))->type != kExprNodeUnknownFigure
+ && (*kv_last(ast_stack))->type != kExprNodeComma) {
+ // kv_last being UnknownFigure may occur for empty dictionary
+ // literal, while Comma is expected in case of non-empty one.
+ ERROR_FROM_TOKEN_AND_MSG(cur_token,
+ _("E15: Expected value, got closing figure brace: %.*s"));
}
- kvi_push(ast_stack, new_top_node_p);
- want_node = kENodeOperator;
- if (kv_size(ast_stack) <= asgn_level) {
- assert(kv_size(ast_stack) == asgn_level);
- asgn_level = 0;
- if (cur_pt == kEPTAssignment) {
- assert(ast.err.msg);
- } else if (cur_pt == kEPTExpr
- && kv_size(pt_stack) > 1
- && pt_is_assignment(kv_Z(pt_stack, 1))) {
- kv_drop(pt_stack, 1);
+ }
+ do {
+ new_top_node_p = kv_pop(ast_stack);
+ } while (kv_size(ast_stack)
+ && (new_top_node_p == NULL
+ || ((*new_top_node_p)->type != kExprNodeUnknownFigure
+ && (*new_top_node_p)->type != kExprNodeDictLiteral
+ && ((*new_top_node_p)->type
+ != kExprNodeCurlyBracesIdentifier)
+ && (*new_top_node_p)->type != kExprNodeLambda)));
+ ExprASTNode *new_top_node = *new_top_node_p;
+ switch (new_top_node->type) {
+ case kExprNodeUnknownFigure:
+ if (new_top_node->children == NULL) {
+ // No children of curly braces node indicates empty dictionary.
+ assert(want_node == kENodeValue);
+ assert(new_top_node->data.fig.type_guesses.allow_dict);
+ SELECT_FIGURE_BRACE_TYPE(new_top_node, DictLiteral, Dict);
+ HL_CUR_TOKEN(Dict);
+ } else if (new_top_node->data.fig.type_guesses.allow_ident) {
+ SELECT_FIGURE_BRACE_TYPE(new_top_node, CurlyBracesIdentifier,
+ Curly);
+ HL_CUR_TOKEN(Curly);
+ } else {
+ // If by this time type of the node has not already been
+ // guessed, but it definitely is not a curly braces name then
+ // it is invalid for sure.
+ ERROR_FROM_NODE_AND_MSG(new_top_node,
+ _("E15: Don't know what figure brace means: %.*s"));
+ if (pstate->colors) {
+ // Will reset to NvimInvalidFigureBrace.
+ kv_A(*pstate->colors,
+ new_top_node->data.fig.opening_hl_idx).group = (
+ HL(FigureBrace));
}
+ HL_CUR_TOKEN(FigureBrace);
}
- if (cur_pt == kEPTSingleAssignment && kv_size(ast_stack) == 1) {
+ break;
+ case kExprNodeDictLiteral:
+ HL_CUR_TOKEN(Dict);
+ break;
+ case kExprNodeCurlyBracesIdentifier:
+ HL_CUR_TOKEN(Curly);
+ break;
+ case kExprNodeLambda:
+ HL_CUR_TOKEN(Lambda);
+ break;
+ default:
+viml_pexpr_parse_figure_brace_closing_error:
+ assert(!kv_size(ast_stack));
+ ERROR_FROM_TOKEN_AND_MSG(cur_token, _("E15: Unexpected closing figure brace: %.*s"));
+ HL_CUR_TOKEN(FigureBrace);
+ break;
+ }
+ kvi_push(ast_stack, new_top_node_p);
+ want_node = kENodeOperator;
+ if (kv_size(ast_stack) <= asgn_level) {
+ assert(kv_size(ast_stack) == asgn_level);
+ if (cur_pt == kEPTExpr
+ && kv_size(pt_stack) > 1
+ && pt_is_assignment(kv_Z(pt_stack, 1))) {
kv_drop(pt_stack, 1);
- }
- } else {
- if (want_node == kENodeValue) {
- // Value means list literal or list assignment.
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeListLiteral);
- *top_node_p = cur_node;
- kvi_push(ast_stack, &cur_node->children);
- want_node = kENodeValue;
- if (cur_pt == kEPTAssignment) {
- // Additional assignment parse type allows to easily forbid nested
- // lists.
- kvi_push(pt_stack, kEPTSingleAssignment);
- } else if (cur_pt == kEPTSingleAssignment) {
- ERROR_FROM_TOKEN_AND_MSG(
- cur_token,
- _("E475: Nested lists not allowed when assigning: %.*s"));
- }
- HL_CUR_TOKEN(List);
- } else {
- // Operator means subscript, also in assignment. But in assignment
- // subscript may be pretty much any expression, so need to push
- // kEPTExpr.
- if (prev_token.type == kExprLexSpacing) {
- OP_MISSING;
- }
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeSubscript);
- ADD_OP_NODE(cur_node);
- HL_CUR_TOKEN(SubscriptBracket);
- if (pt_is_assignment(cur_pt)) {
- assert(want_node == kENodeValue); // Subtract 1 for NULL at top.
- asgn_level = kv_size(ast_stack) - 1;
- kvi_push(pt_stack, kEPTExpr);
- }
+ asgn_level = 0;
}
}
- break;
- }
- case kExprLexFigureBrace: {
- if (cur_token.data.brc.closing) {
- ExprASTNode **new_top_node_p = NULL;
- // Always drop the topmost value:
- //
- // 1. When want_node != kENodeValue topmost item on stack is
- // a *finished* left operand, which may as well be "{@a}" which
- // needs not be finished again.
- // 2. Otherwise it is pointing to NULL what nobody wants.
- kv_drop(ast_stack, 1);
- if (!kv_size(ast_stack)) {
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeUnknownFigure);
+ } else {
+ if (want_node == kENodeValue) {
+ HL_CUR_TOKEN(FigureBrace);
+ // Value: may be any of lambda, dictionary literal and curly braces
+ // name.
+
+ // Though if we are in an assignment this may only be a curly braces
+ // name.
+ if (pt_is_assignment(cur_pt)) {
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeCurlyBracesIdentifier);
cur_node->data.fig.type_guesses.allow_lambda = false;
cur_node->data.fig.type_guesses.allow_dict = false;
- cur_node->data.fig.type_guesses.allow_ident = false;
- cur_node->len = 0;
- if (want_node != kENodeValue) {
- cur_node->children = *top_node_p;
- }
- *top_node_p = cur_node;
- new_top_node_p = top_node_p;
- goto viml_pexpr_parse_figure_brace_closing_error;
- }
- if (want_node == kENodeValue) {
- if ((*kv_last(ast_stack))->type != kExprNodeUnknownFigure
- && (*kv_last(ast_stack))->type != kExprNodeComma) {
- // kv_last being UnknownFigure may occur for empty dictionary
- // literal, while Comma is expected in case of non-empty one.
- ERROR_FROM_TOKEN_AND_MSG(
- cur_token,
- _("E15: Expected value, got closing figure brace: %.*s"));
- }
- }
- do {
- new_top_node_p = kv_pop(ast_stack);
- } while (kv_size(ast_stack)
- && (new_top_node_p == NULL
- || ((*new_top_node_p)->type != kExprNodeUnknownFigure
- && (*new_top_node_p)->type != kExprNodeDictLiteral
- && ((*new_top_node_p)->type
- != kExprNodeCurlyBracesIdentifier)
- && (*new_top_node_p)->type != kExprNodeLambda)));
- ExprASTNode *new_top_node = *new_top_node_p;
- switch (new_top_node->type) {
- case kExprNodeUnknownFigure: {
- if (new_top_node->children == NULL) {
- // No children of curly braces node indicates empty dictionary.
- assert(want_node == kENodeValue);
- assert(new_top_node->data.fig.type_guesses.allow_dict);
- SELECT_FIGURE_BRACE_TYPE(new_top_node, DictLiteral, Dict);
- HL_CUR_TOKEN(Dict);
- } else if (new_top_node->data.fig.type_guesses.allow_ident) {
- SELECT_FIGURE_BRACE_TYPE(new_top_node, CurlyBracesIdentifier,
- Curly);
- HL_CUR_TOKEN(Curly);
- } else {
- // If by this time type of the node has not already been
- // guessed, but it definitely is not a curly braces name then
- // it is invalid for sure.
- ERROR_FROM_NODE_AND_MSG(
- new_top_node,
- _("E15: Don't know what figure brace means: %.*s"));
- if (pstate->colors) {
- // Will reset to NvimInvalidFigureBrace.
- kv_A(*pstate->colors,
- new_top_node->data.fig.opening_hl_idx).group = (
- HL(FigureBrace));
- }
- HL_CUR_TOKEN(FigureBrace);
- }
- break;
- }
- case kExprNodeDictLiteral: {
- HL_CUR_TOKEN(Dict);
- break;
- }
- case kExprNodeCurlyBracesIdentifier: {
- HL_CUR_TOKEN(Curly);
- break;
- }
- case kExprNodeLambda: {
- HL_CUR_TOKEN(Lambda);
- break;
- }
- default: {
-viml_pexpr_parse_figure_brace_closing_error:
- assert(!kv_size(ast_stack));
- ERROR_FROM_TOKEN_AND_MSG(
- cur_token, _("E15: Unexpected closing figure brace: %.*s"));
- HL_CUR_TOKEN(FigureBrace);
- break;
- }
+ cur_node->data.fig.type_guesses.allow_ident = true;
+ kvi_push(pt_stack, kEPTExpr);
+ } else {
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeUnknownFigure);
+ cur_node->data.fig.type_guesses.allow_lambda = true;
+ cur_node->data.fig.type_guesses.allow_dict = true;
+ cur_node->data.fig.type_guesses.allow_ident = true;
}
- kvi_push(ast_stack, new_top_node_p);
- want_node = kENodeOperator;
- if (kv_size(ast_stack) <= asgn_level) {
- assert(kv_size(ast_stack) == asgn_level);
- if (cur_pt == kEPTExpr
- && kv_size(pt_stack) > 1
- && pt_is_assignment(kv_Z(pt_stack, 1))) {
- kv_drop(pt_stack, 1);
- asgn_level = 0;
- }
+ if (pstate->colors) {
+ cur_node->data.fig.opening_hl_idx = kv_size(*pstate->colors) - 1;
}
+ *top_node_p = cur_node;
+ kvi_push(ast_stack, &cur_node->children);
+ kvi_push(pt_stack, kEPTLambdaArguments);
+ lambda_node = cur_node;
} else {
- if (want_node == kENodeValue) {
- HL_CUR_TOKEN(FigureBrace);
- // Value: may be any of lambda, dictionary literal and curly braces
- // name.
-
- // Though if we are in an assignment this may only be a curly braces
- // name.
+ ADD_IDENT(do {
+ NEW_NODE_WITH_CUR_POS(cur_node,
+ kExprNodeCurlyBracesIdentifier);
+ cur_node->data.fig.opening_hl_idx = kv_size(*pstate->colors);
+ cur_node->data.fig.type_guesses.allow_lambda = false;
+ cur_node->data.fig.type_guesses.allow_dict = false;
+ cur_node->data.fig.type_guesses.allow_ident = true;
+ kvi_push(ast_stack, &cur_node->children);
if (pt_is_assignment(cur_pt)) {
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeCurlyBracesIdentifier);
- cur_node->data.fig.type_guesses.allow_lambda = false;
- cur_node->data.fig.type_guesses.allow_dict = false;
- cur_node->data.fig.type_guesses.allow_ident = true;
kvi_push(pt_stack, kEPTExpr);
- } else {
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeUnknownFigure);
- cur_node->data.fig.type_guesses.allow_lambda = true;
- cur_node->data.fig.type_guesses.allow_dict = true;
- cur_node->data.fig.type_guesses.allow_ident = true;
- }
- if (pstate->colors) {
- cur_node->data.fig.opening_hl_idx = kv_size(*pstate->colors) - 1;
}
- *top_node_p = cur_node;
- kvi_push(ast_stack, &cur_node->children);
- kvi_push(pt_stack, kEPTLambdaArguments);
- lambda_node = cur_node;
- } else {
- ADD_IDENT(
- do {
- NEW_NODE_WITH_CUR_POS(cur_node,
- kExprNodeCurlyBracesIdentifier);
- cur_node->data.fig.opening_hl_idx = kv_size(*pstate->colors);
- cur_node->data.fig.type_guesses.allow_lambda = false;
- cur_node->data.fig.type_guesses.allow_dict = false;
- cur_node->data.fig.type_guesses.allow_ident = true;
- kvi_push(ast_stack, &cur_node->children);
- if (pt_is_assignment(cur_pt)) {
- kvi_push(pt_stack, kEPTExpr);
- }
- want_node = kENodeValue;
- } while (0),
- Curly);
- }
- if (pt_is_assignment(cur_pt)
- && !pt_is_assignment(kv_last(pt_stack))) {
- assert(want_node == kENodeValue); // Subtract 1 for NULL at top.
- asgn_level = kv_size(ast_stack) - 1;
- }
+ want_node = kENodeValue;
+ } while (0),
+ Curly);
+ }
+ if (pt_is_assignment(cur_pt)
+ && !pt_is_assignment(kv_last(pt_stack))) {
+ assert(want_node == kENodeValue); // Subtract 1 for NULL at top.
+ asgn_level = kv_size(ast_stack) - 1;
}
- break;
}
- case kExprLexArrow: {
- if (cur_pt == kEPTLambdaArguments) {
- kv_drop(pt_stack, 1);
- assert(kv_size(pt_stack));
- if (want_node == kENodeValue) {
- // Wanting value means trailing comma and NULL at the top of the
- // stack.
- kv_drop(ast_stack, 1);
- }
- assert(kv_size(ast_stack) >= 1);
- while ((*kv_last(ast_stack))->type != kExprNodeLambda
- && (*kv_last(ast_stack))->type != kExprNodeUnknownFigure) {
- kv_drop(ast_stack, 1);
- }
- assert((*kv_last(ast_stack)) == lambda_node);
- SELECT_FIGURE_BRACE_TYPE(lambda_node, Lambda, Lambda);
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeArrow);
- if (lambda_node->children == NULL) {
- assert(want_node == kENodeValue);
- lambda_node->children = cur_node;
- kvi_push(ast_stack, &lambda_node->children);
- } else {
- assert(lambda_node->children->next == NULL);
- lambda_node->children->next = cur_node;
- kvi_push(ast_stack, &lambda_node->children->next);
- }
- kvi_push(ast_stack, &cur_node->children);
- lambda_node = NULL;
+ break;
+ case kExprLexArrow:
+ if (cur_pt == kEPTLambdaArguments) {
+ kv_drop(pt_stack, 1);
+ assert(kv_size(pt_stack));
+ if (want_node == kENodeValue) {
+ // Wanting value means trailing comma and NULL at the top of the
+ // stack.
+ kv_drop(ast_stack, 1);
+ }
+ assert(kv_size(ast_stack) >= 1);
+ while ((*kv_last(ast_stack))->type != kExprNodeLambda
+ && (*kv_last(ast_stack))->type != kExprNodeUnknownFigure) {
+ kv_drop(ast_stack, 1);
+ }
+ assert((*kv_last(ast_stack)) == lambda_node);
+ SELECT_FIGURE_BRACE_TYPE(lambda_node, Lambda, Lambda);
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeArrow);
+ if (lambda_node->children == NULL) {
+ assert(want_node == kENodeValue);
+ lambda_node->children = cur_node;
+ kvi_push(ast_stack, &lambda_node->children);
} else {
- // Only first branch is valid.
- ADD_VALUE_IF_MISSING(_("E15: Unexpected arrow: %.*s"));
- ERROR_FROM_TOKEN_AND_MSG(
- cur_token, _("E15: Arrow outside of lambda: %.*s"));
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeArrow);
- ADD_OP_NODE(cur_node);
+ assert(lambda_node->children->next == NULL);
+ lambda_node->children->next = cur_node;
+ kvi_push(ast_stack, &lambda_node->children->next);
}
- want_node = kENodeValue;
- HL_CUR_TOKEN(Arrow);
- break;
+ kvi_push(ast_stack, &cur_node->children);
+ lambda_node = NULL;
+ } else {
+ // Only first branch is valid.
+ ADD_VALUE_IF_MISSING(_("E15: Unexpected arrow: %.*s"));
+ ERROR_FROM_TOKEN_AND_MSG(cur_token, _("E15: Arrow outside of lambda: %.*s"));
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeArrow);
+ ADD_OP_NODE(cur_node);
}
- case kExprLexPlainIdentifier: {
- const ExprVarScope scope = (cur_token.type == kExprLexInvalid
+ want_node = kENodeValue;
+ HL_CUR_TOKEN(Arrow);
+ break;
+ case kExprLexPlainIdentifier: {
+ const ExprVarScope scope = (cur_token.type == kExprLexInvalid
? kExprVarScopeMissing
: cur_token.data.var.scope);
- if (want_node == kENodeValue) {
- want_node = kENodeOperator;
- NEW_NODE_WITH_CUR_POS(cur_node,
- (node_is_key
+ if (want_node == kENodeValue) {
+ want_node = kENodeOperator;
+ NEW_NODE_WITH_CUR_POS(cur_node,
+ (node_is_key
? kExprNodePlainKey
: kExprNodePlainIdentifier));
- cur_node->data.var.scope = scope;
- const size_t scope_shift = (scope == kExprVarScopeMissing ? 0 : 2);
- cur_node->data.var.ident = (pline.data + cur_token.start.col
- + scope_shift);
- cur_node->data.var.ident_len = cur_token.len - scope_shift;
- *top_node_p = cur_node;
- if (scope_shift) {
- assert(!node_is_key);
- viml_parser_highlight(pstate, cur_token.start, 1,
- HL(IdentifierScope));
- viml_parser_highlight(pstate, shifted_pos(cur_token.start, 1), 1,
- HL(IdentifierScopeDelimiter));
- }
- viml_parser_highlight(pstate, shifted_pos(cur_token.start,
- scope_shift),
- cur_token.len - scope_shift,
- (node_is_key
+ cur_node->data.var.scope = scope;
+ const size_t scope_shift = (scope == kExprVarScopeMissing ? 0 : 2);
+ cur_node->data.var.ident = (pline.data + cur_token.start.col
+ + scope_shift);
+ cur_node->data.var.ident_len = cur_token.len - scope_shift;
+ *top_node_p = cur_node;
+ if (scope_shift) {
+ assert(!node_is_key);
+ viml_parser_highlight(pstate, cur_token.start, 1,
+ HL(IdentifierScope));
+ viml_parser_highlight(pstate, shifted_pos(cur_token.start, 1), 1,
+ HL(IdentifierScopeDelimiter));
+ }
+ viml_parser_highlight(pstate, shifted_pos(cur_token.start,
+ scope_shift),
+ cur_token.len - scope_shift,
+ (node_is_key
? HL(IdentifierKey)
: HL(IdentifierName)));
+ } else {
+ if (scope == kExprVarScopeMissing) {
+ ADD_IDENT(do {
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodePlainIdentifier);
+ cur_node->data.var.scope = scope;
+ cur_node->data.var.ident = pline.data + cur_token.start.col;
+ cur_node->data.var.ident_len = cur_token.len;
+ want_node = kENodeOperator;
+ } while (0),
+ IdentifierName);
} else {
- if (scope == kExprVarScopeMissing) {
- ADD_IDENT(
- do {
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodePlainIdentifier);
- cur_node->data.var.scope = scope;
- cur_node->data.var.ident = pline.data + cur_token.start.col;
- cur_node->data.var.ident_len = cur_token.len;
- want_node = kENodeOperator;
- } while (0),
- IdentifierName);
- } else {
- OP_MISSING;
- }
- }
- break;
- }
- case kExprLexNumber: {
- if (want_node != kENodeValue) {
OP_MISSING;
}
- if (node_is_key) {
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodePlainKey);
- cur_node->data.var.ident = pline.data + cur_token.start.col;
- cur_node->data.var.ident_len = cur_token.len;
- HL_CUR_TOKEN(IdentifierKey);
- } else if (cur_token.data.num.is_float) {
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeFloat);
- cur_node->data.flt.value = cur_token.data.num.val.floating;
- HL_CUR_TOKEN(Float);
- } else {
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeInteger);
- cur_node->data.num.value = cur_token.data.num.val.integer;
- const uint8_t prefix_length = base_to_prefix_length[
- cur_token.data.num.base];
- viml_parser_highlight(pstate, cur_token.start, prefix_length,
- HL(NumberPrefix));
- viml_parser_highlight(
- pstate, shifted_pos(cur_token.start, prefix_length),
- cur_token.len - prefix_length, HL(Number));
- }
- want_node = kENodeOperator;
- *top_node_p = cur_node;
- break;
}
- case kExprLexDot: {
- ADD_VALUE_IF_MISSING(_("E15: Unexpected dot: %.*s"));
- if (prev_token.type == kExprLexSpacing) {
- if (cur_pt == kEPTAssignment) {
- ERROR_FROM_TOKEN_AND_MSG(
- cur_token, _("E15: Cannot concatenate in assignments: %.*s"));
- }
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeConcat);
- HL_CUR_TOKEN(Concat);
- } else {
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeConcatOrSubscript);
- HL_CUR_TOKEN(ConcatOrSubscript);
+ break;
+ }
+ case kExprLexNumber:
+ if (want_node != kENodeValue) {
+ OP_MISSING;
+ }
+ if (node_is_key) {
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodePlainKey);
+ cur_node->data.var.ident = pline.data + cur_token.start.col;
+ cur_node->data.var.ident_len = cur_token.len;
+ HL_CUR_TOKEN(IdentifierKey);
+ } else if (cur_token.data.num.is_float) {
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeFloat);
+ cur_node->data.flt.value = cur_token.data.num.val.floating;
+ HL_CUR_TOKEN(Float);
+ } else {
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeInteger);
+ cur_node->data.num.value = cur_token.data.num.val.integer;
+ const uint8_t prefix_length = base_to_prefix_length[
+ cur_token.data.num.base];
+ viml_parser_highlight(pstate, cur_token.start, prefix_length,
+ HL(NumberPrefix));
+ viml_parser_highlight(pstate, shifted_pos(cur_token.start, prefix_length),
+ cur_token.len - prefix_length, HL(Number));
+ }
+ want_node = kENodeOperator;
+ *top_node_p = cur_node;
+ break;
+ case kExprLexDot:
+ ADD_VALUE_IF_MISSING(_("E15: Unexpected dot: %.*s"));
+ if (prev_token.type == kExprLexSpacing) {
+ if (cur_pt == kEPTAssignment) {
+ ERROR_FROM_TOKEN_AND_MSG(cur_token, _("E15: Cannot concatenate in assignments: %.*s"));
}
- ADD_OP_NODE(cur_node);
- break;
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeConcat);
+ HL_CUR_TOKEN(Concat);
+ } else {
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeConcatOrSubscript);
+ HL_CUR_TOKEN(ConcatOrSubscript);
}
- case kExprLexParenthesis: {
- if (cur_token.data.brc.closing) {
- if (want_node == kENodeValue) {
- if (kv_size(ast_stack) > 1) {
- const ExprASTNode *const prev_top_node = *kv_Z(ast_stack, 1);
- if (prev_top_node->type == kExprNodeCall) {
- // Function call without arguments, this is not an error.
- // But further code does not expect NULL nodes.
- kv_drop(ast_stack, 1);
- goto viml_pexpr_parse_no_paren_closing_error;
- }
+ ADD_OP_NODE(cur_node);
+ break;
+ case kExprLexParenthesis:
+ if (cur_token.data.brc.closing) {
+ if (want_node == kENodeValue) {
+ if (kv_size(ast_stack) > 1) {
+ const ExprASTNode *const prev_top_node = *kv_Z(ast_stack, 1);
+ if (prev_top_node->type == kExprNodeCall) {
+ // Function call without arguments, this is not an error.
+ // But further code does not expect NULL nodes.
+ kv_drop(ast_stack, 1);
+ goto viml_pexpr_parse_no_paren_closing_error;
}
- ERROR_FROM_TOKEN_AND_MSG(
- cur_token, _("E15: Expected value, got parenthesis: %.*s"));
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeMissing);
- cur_node->len = 0;
- *top_node_p = cur_node;
- } else {
- // Always drop the topmost value: when want_node != kENodeValue
- // topmost item on stack is a *finished* left operand, which may as
- // well be "(@a)" which needs not be finished again.
- kv_drop(ast_stack, 1);
}
+ ERROR_FROM_TOKEN_AND_MSG(cur_token, _("E15: Expected value, got parenthesis: %.*s"));
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeMissing);
+ cur_node->len = 0;
+ *top_node_p = cur_node;
+ } else {
+ // Always drop the topmost value: when want_node != kENodeValue
+ // topmost item on stack is a *finished* left operand, which may as
+ // well be "(@a)" which needs not be finished again.
+ kv_drop(ast_stack, 1);
+ }
viml_pexpr_parse_no_paren_closing_error: {}
- ExprASTNode **new_top_node_p = NULL;
- while (kv_size(ast_stack)
- && (new_top_node_p == NULL
- || ((*new_top_node_p)->type != kExprNodeNested
- && (*new_top_node_p)->type != kExprNodeCall))) {
- new_top_node_p = kv_pop(ast_stack);
- }
- if (new_top_node_p != NULL
- && ((*new_top_node_p)->type == kExprNodeNested
- || (*new_top_node_p)->type == kExprNodeCall)) {
- if ((*new_top_node_p)->type == kExprNodeNested) {
- HL_CUR_TOKEN(NestingParenthesis);
- } else {
- HL_CUR_TOKEN(CallingParenthesis);
- }
- } else {
- // “Always drop the topmost value” branch has got rid of the single
- // value stack had, so there is nothing known to enclose. Correct
- // this.
- if (new_top_node_p == NULL) {
- new_top_node_p = top_node_p;
- }
- ERROR_FROM_TOKEN_AND_MSG(
- cur_token, _("E15: Unexpected closing parenthesis: %.*s"));
+ ExprASTNode **new_top_node_p = NULL;
+ while (kv_size(ast_stack)
+ && (new_top_node_p == NULL
+ || ((*new_top_node_p)->type != kExprNodeNested
+ && (*new_top_node_p)->type != kExprNodeCall))) {
+ new_top_node_p = kv_pop(ast_stack);
+ }
+ if (new_top_node_p != NULL
+ && ((*new_top_node_p)->type == kExprNodeNested
+ || (*new_top_node_p)->type == kExprNodeCall)) {
+ if ((*new_top_node_p)->type == kExprNodeNested) {
HL_CUR_TOKEN(NestingParenthesis);
- cur_node = NEW_NODE(kExprNodeNested);
- cur_node->start = cur_token.start;
- cur_node->len = 0;
- // Unexpected closing parenthesis, assume that it was wanted to
- // enclose everything in ().
- cur_node->children = *new_top_node_p;
- *new_top_node_p = cur_node;
- assert(cur_node->next == NULL);
+ } else {
+ HL_CUR_TOKEN(CallingParenthesis);
}
- kvi_push(ast_stack, new_top_node_p);
- want_node = kENodeOperator;
} else {
- switch (want_node) {
- case kENodeValue: {
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeNested);
- *top_node_p = cur_node;
- kvi_push(ast_stack, &cur_node->children);
- HL_CUR_TOKEN(NestingParenthesis);
- break;
- }
- case kENodeOperator: {
- if (prev_token.type == kExprLexSpacing) {
- // For some reason "function (args)" is a function call, but
- // "(funcref) (args)" is not. AFAIR this somehow involves
- // compatibility and Bram was commenting that this is
- // intentionally inconsistent and he is not very happy with the
- // situation himself.
- if ((*top_node_p)->type != kExprNodePlainIdentifier
- && (*top_node_p)->type != kExprNodeComplexIdentifier
- && (*top_node_p)->type != kExprNodeCurlyBracesIdentifier) {
- OP_MISSING;
- }
- }
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeCall);
- ADD_OP_NODE(cur_node);
- HL_CUR_TOKEN(CallingParenthesis);
- break;
+ // “Always drop the topmost value” branch has got rid of the single
+ // value stack had, so there is nothing known to enclose. Correct
+ // this.
+ if (new_top_node_p == NULL) {
+ new_top_node_p = top_node_p;
+ }
+ ERROR_FROM_TOKEN_AND_MSG(cur_token, _("E15: Unexpected closing parenthesis: %.*s"));
+ HL_CUR_TOKEN(NestingParenthesis);
+ cur_node = NEW_NODE(kExprNodeNested);
+ cur_node->start = cur_token.start;
+ cur_node->len = 0;
+ // Unexpected closing parenthesis, assume that it was wanted to
+ // enclose everything in ().
+ cur_node->children = *new_top_node_p;
+ *new_top_node_p = cur_node;
+ assert(cur_node->next == NULL);
+ }
+ kvi_push(ast_stack, new_top_node_p);
+ want_node = kENodeOperator;
+ } else {
+ switch (want_node) {
+ case kENodeValue:
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeNested);
+ *top_node_p = cur_node;
+ kvi_push(ast_stack, &cur_node->children);
+ HL_CUR_TOKEN(NestingParenthesis);
+ break;
+ case kENodeOperator:
+ if (prev_token.type == kExprLexSpacing) {
+ // For some reason "function (args)" is a function call, but
+ // "(funcref) (args)" is not. AFAIR this somehow involves
+ // compatibility and Bram was commenting that this is
+ // intentionally inconsistent and he is not very happy with the
+ // situation himself.
+ if ((*top_node_p)->type != kExprNodePlainIdentifier
+ && (*top_node_p)->type != kExprNodeComplexIdentifier
+ && (*top_node_p)->type != kExprNodeCurlyBracesIdentifier) {
+ OP_MISSING;
}
}
- want_node = kENodeValue;
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeCall);
+ ADD_OP_NODE(cur_node);
+ HL_CUR_TOKEN(CallingParenthesis);
+ break;
}
- break;
- }
- case kExprLexQuestion: {
- ADD_VALUE_IF_MISSING(_("E15: Expected value, got question mark: %.*s"));
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeTernary);
- ADD_OP_NODE(cur_node);
- HL_CUR_TOKEN(Ternary);
- ExprASTNode *ter_val_node;
- NEW_NODE_WITH_CUR_POS(ter_val_node, kExprNodeTernaryValue);
- ter_val_node->data.ter.got_colon = false;
- assert(cur_node->children != NULL);
- assert(cur_node->children->next == NULL);
- assert(kv_last(ast_stack) == &cur_node->children->next);
- *kv_last(ast_stack) = ter_val_node;
- kvi_push(ast_stack, &ter_val_node->children);
- break;
+ want_node = kENodeValue;
}
- case kExprLexDoubleQuotedString:
- case kExprLexSingleQuotedString: {
- const bool is_double = (tok_type == kExprLexDoubleQuotedString);
- if (!cur_token.data.str.closed) {
- // It is weird, but Vim has two identical errors messages with
- // different error numbers: "E114: Missing quote" and
- // "E115: Missing quote".
- ERROR_FROM_TOKEN_AND_MSG(
- cur_token, (is_double
+ break;
+ case kExprLexQuestion: {
+ ADD_VALUE_IF_MISSING(_("E15: Expected value, got question mark: %.*s"));
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeTernary);
+ ADD_OP_NODE(cur_node);
+ HL_CUR_TOKEN(Ternary);
+ ExprASTNode *ter_val_node;
+ NEW_NODE_WITH_CUR_POS(ter_val_node, kExprNodeTernaryValue);
+ ter_val_node->data.ter.got_colon = false;
+ assert(cur_node->children != NULL);
+ assert(cur_node->children->next == NULL);
+ assert(kv_last(ast_stack) == &cur_node->children->next);
+ *kv_last(ast_stack) = ter_val_node;
+ kvi_push(ast_stack, &ter_val_node->children);
+ break;
+ }
+ case kExprLexDoubleQuotedString:
+ case kExprLexSingleQuotedString: {
+ const bool is_double = (tok_type == kExprLexDoubleQuotedString);
+ if (!cur_token.data.str.closed) {
+ // It is weird, but Vim has two identical errors messages with
+ // different error numbers: "E114: Missing quote" and
+ // "E115: Missing quote".
+ ERROR_FROM_TOKEN_AND_MSG(cur_token, (is_double
? _("E114: Missing double quote: %.*s")
: _("E115: Missing single quote: %.*s")));
- }
- if (want_node == kENodeOperator) {
- OP_MISSING;
- }
- NEW_NODE_WITH_CUR_POS(
- cur_node, (is_double
+ }
+ if (want_node == kENodeOperator) {
+ OP_MISSING;
+ }
+ NEW_NODE_WITH_CUR_POS(cur_node, (is_double
? kExprNodeDoubleQuotedString
: kExprNodeSingleQuotedString));
- *top_node_p = cur_node;
- parse_quoted_string(pstate, cur_node, cur_token, ast_stack, is_invalid);
- want_node = kENodeOperator;
- break;
+ *top_node_p = cur_node;
+ parse_quoted_string(pstate, cur_node, cur_token, ast_stack, is_invalid);
+ want_node = kENodeOperator;
+ break;
+ }
+ case kExprLexAssignment:
+ if (cur_pt == kEPTAssignment) {
+ kv_drop(pt_stack, 1);
+ } else if (cur_pt == kEPTSingleAssignment) {
+ kv_drop(pt_stack, 2);
+ ERROR_FROM_TOKEN_AND_MSG(cur_token,
+ _("E475: Expected closing bracket to end list assignment "
+ "lvalue: %.*s"));
+ } else {
+ ERROR_FROM_TOKEN_AND_MSG(cur_token, _("E15: Misplaced assignment: %.*s"));
}
- case kExprLexAssignment: {
- if (cur_pt == kEPTAssignment) {
- kv_drop(pt_stack, 1);
- } else if (cur_pt == kEPTSingleAssignment) {
- kv_drop(pt_stack, 2);
- ERROR_FROM_TOKEN_AND_MSG(
- cur_token,
- _("E475: Expected closing bracket to end list assignment "
- "lvalue: %.*s"));
- } else {
- ERROR_FROM_TOKEN_AND_MSG(
- cur_token, _("E15: Misplaced assignment: %.*s"));
- }
- assert(kv_size(pt_stack));
- assert(kv_last(pt_stack) == kEPTExpr);
- ADD_VALUE_IF_MISSING(_("E15: Unexpected assignment: %.*s"));
- NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeAssignment);
- cur_node->data.ass.type = cur_token.data.ass.type;
- switch (cur_token.data.ass.type) {
+ assert(kv_size(pt_stack));
+ assert(kv_last(pt_stack) == kEPTExpr);
+ ADD_VALUE_IF_MISSING(_("E15: Unexpected assignment: %.*s"));
+ NEW_NODE_WITH_CUR_POS(cur_node, kExprNodeAssignment);
+ cur_node->data.ass.type = cur_token.data.ass.type;
+ switch (cur_token.data.ass.type) {
#define HL_ASGN(asgn, hl) \
- case kExprAsgn##asgn: { HL_CUR_TOKEN(hl); break; }
- HL_ASGN(Plain, PlainAssignment)
- HL_ASGN(Add, AssignmentWithAddition)
- HL_ASGN(Subtract, AssignmentWithSubtraction)
- HL_ASGN(Concat, AssignmentWithConcatenation)
+case kExprAsgn##asgn: { HL_CUR_TOKEN(hl); break; }
+ HL_ASGN(Plain, PlainAssignment)
+ HL_ASGN(Add, AssignmentWithAddition)
+ HL_ASGN(Subtract, AssignmentWithSubtraction)
+ HL_ASGN(Concat, AssignmentWithConcatenation)
#undef HL_ASGN
- }
- ADD_OP_NODE(cur_node);
- break;
}
+ ADD_OP_NODE(cur_node);
+ break;
}
viml_pexpr_parse_cycle_end:
prev_token = cur_token;
@@ -2972,115 +2970,96 @@ viml_pexpr_parse_end:
assert(cur_node != NULL);
// TODO(ZyX-I): Rehighlight as invalid?
switch (cur_node->type) {
- case kExprNodeOpMissing:
- case kExprNodeMissing: {
- // Error should’ve been already reported.
- break;
- }
- case kExprNodeCall: {
- east_set_error(
- pstate, &ast.err,
- _("E116: Missing closing parenthesis for function call: %.*s"),
- cur_node->start);
- break;
- }
- case kExprNodeNested: {
- east_set_error(
- pstate, &ast.err,
- _("E110: Missing closing parenthesis for nested expression"
- ": %.*s"),
- cur_node->start);
- break;
- }
- case kExprNodeListLiteral: {
- // For whatever reason "[1" yields "E696: Missing comma in list" error
- // in Vim while "[1," yields E697.
- east_set_error(
- pstate, &ast.err,
- _("E697: Missing end of List ']': %.*s"),
- cur_node->start);
- break;
- }
- case kExprNodeDictLiteral: {
- // Same problem like with list literal with E722 (missing comma) vs
- // E723, but additionally just "{" yields only E15.
- east_set_error(
- pstate, &ast.err,
- _("E723: Missing end of Dictionary '}': %.*s"),
- cur_node->start);
- break;
- }
- case kExprNodeUnknownFigure: {
- east_set_error(
- pstate, &ast.err,
- _("E15: Missing closing figure brace: %.*s"),
- cur_node->start);
- break;
- }
- case kExprNodeLambda: {
- east_set_error(
- pstate, &ast.err,
- _("E15: Missing closing figure brace for lambda: %.*s"),
- cur_node->start);
- break;
- }
- case kExprNodeCurlyBracesIdentifier: {
- // Until trailing "}" it is impossible to distinguish curly braces
- // identifier and dictionary, so it must not appear in the stack like
- // this.
- abort();
- }
- case kExprNodeInteger:
- case kExprNodeFloat:
- case kExprNodeSingleQuotedString:
- case kExprNodeDoubleQuotedString:
- case kExprNodeOption:
- case kExprNodeEnvironment:
- case kExprNodeRegister:
- case kExprNodePlainIdentifier:
- case kExprNodePlainKey: {
- // These are plain values and not containers, for them it should only
- // be possible to show up in the topmost stack element, but it was
- // unconditionally popped at the start.
- abort();
- }
- case kExprNodeComma:
- case kExprNodeColon:
- case kExprNodeArrow: {
- // It is actually only valid inside something else, but everything
- // where one of the above is valid requires to be closed and thus is
- // to be caught later.
- break;
- }
- case kExprNodeSubscript:
- case kExprNodeConcatOrSubscript:
- case kExprNodeComplexIdentifier:
- case kExprNodeAssignment:
- case kExprNodeMod:
- case kExprNodeDivision:
- case kExprNodeMultiplication:
- case kExprNodeNot:
- case kExprNodeAnd:
- case kExprNodeOr:
- case kExprNodeConcat:
- case kExprNodeComparison:
- case kExprNodeUnaryMinus:
- case kExprNodeUnaryPlus:
- case kExprNodeBinaryMinus:
- case kExprNodeTernary:
- case kExprNodeBinaryPlus: {
- // It is OK to see these in the stack.
- break;
- }
- case kExprNodeTernaryValue: {
- if (!cur_node->data.ter.got_colon) {
- // Actually Vim throws E109 in more cases.
- east_set_error(
- pstate, &ast.err, _("E109: Missing ':' after '?': %.*s"),
- cur_node->start);
- }
- break;
+ case kExprNodeOpMissing:
+ case kExprNodeMissing:
+ // Error should’ve been already reported.
+ break;
+ case kExprNodeCall:
+ east_set_error(pstate, &ast.err,
+ _("E116: Missing closing parenthesis for function call: %.*s"),
+ cur_node->start);
+ break;
+ case kExprNodeNested:
+ east_set_error(pstate, &ast.err,
+ _("E110: Missing closing parenthesis for nested expression"
+ ": %.*s"),
+ cur_node->start);
+ break;
+ case kExprNodeListLiteral:
+ // For whatever reason "[1" yields "E696: Missing comma in list" error
+ // in Vim while "[1," yields E697.
+ east_set_error(pstate, &ast.err,
+ _("E697: Missing end of List ']': %.*s"),
+ cur_node->start);
+ break;
+ case kExprNodeDictLiteral:
+ // Same problem like with list literal with E722 (missing comma) vs
+ // E723, but additionally just "{" yields only E15.
+ east_set_error(pstate, &ast.err,
+ _("E723: Missing end of Dictionary '}': %.*s"),
+ cur_node->start);
+ break;
+ case kExprNodeUnknownFigure:
+ east_set_error(pstate, &ast.err,
+ _("E15: Missing closing figure brace: %.*s"),
+ cur_node->start);
+ break;
+ case kExprNodeLambda:
+ east_set_error(pstate, &ast.err,
+ _("E15: Missing closing figure brace for lambda: %.*s"),
+ cur_node->start);
+ break;
+ case kExprNodeCurlyBracesIdentifier:
+ // Until trailing "}" it is impossible to distinguish curly braces
+ // identifier and dictionary, so it must not appear in the stack like
+ // this.
+ abort();
+ case kExprNodeInteger:
+ case kExprNodeFloat:
+ case kExprNodeSingleQuotedString:
+ case kExprNodeDoubleQuotedString:
+ case kExprNodeOption:
+ case kExprNodeEnvironment:
+ case kExprNodeRegister:
+ case kExprNodePlainIdentifier:
+ case kExprNodePlainKey:
+ // These are plain values and not containers, for them it should only
+ // be possible to show up in the topmost stack element, but it was
+ // unconditionally popped at the start.
+ abort();
+ case kExprNodeComma:
+ case kExprNodeColon:
+ case kExprNodeArrow:
+ // It is actually only valid inside something else, but everything
+ // where one of the above is valid requires to be closed and thus is
+ // to be caught later.
+ break;
+ case kExprNodeSubscript:
+ case kExprNodeConcatOrSubscript:
+ case kExprNodeComplexIdentifier:
+ case kExprNodeAssignment:
+ case kExprNodeMod:
+ case kExprNodeDivision:
+ case kExprNodeMultiplication:
+ case kExprNodeNot:
+ case kExprNodeAnd:
+ case kExprNodeOr:
+ case kExprNodeConcat:
+ case kExprNodeComparison:
+ case kExprNodeUnaryMinus:
+ case kExprNodeUnaryPlus:
+ case kExprNodeBinaryMinus:
+ case kExprNodeTernary:
+ case kExprNodeBinaryPlus:
+ // It is OK to see these in the stack.
+ break;
+ case kExprNodeTernaryValue:
+ if (!cur_node->data.ter.got_colon) {
+ // Actually Vim throws E109 in more cases.
+ east_set_error(pstate, &ast.err, _("E109: Missing ':' after '?': %.*s"),
+ cur_node->start);
}
+ break;
}
}
}
diff --git a/src/nvim/window.c b/src/nvim/window.c
index d051e8e467..c0f537aab3 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -5,11 +5,8 @@
#include <inttypes.h>
#include <stdbool.h>
-#include "nvim/api/private/handle.h"
#include "nvim/api/private/helpers.h"
-#include "nvim/vim.h"
#include "nvim/ascii.h"
-#include "nvim/window.h"
#include "nvim/buffer.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
@@ -21,8 +18,10 @@
#include "nvim/ex_docmd.h"
#include "nvim/ex_eval.h"
#include "nvim/ex_getln.h"
+#include "nvim/file_search.h"
#include "nvim/fileio.h"
#include "nvim/fold.h"
+#include "nvim/garray.h"
#include "nvim/getchar.h"
#include "nvim/hashtab.h"
#include "nvim/main.h"
@@ -31,14 +30,14 @@
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/misc1.h"
-#include "nvim/file_search.h"
-#include "nvim/garray.h"
-#include "nvim/move.h"
#include "nvim/mouse.h"
+#include "nvim/move.h"
#include "nvim/normal.h"
#include "nvim/option.h"
+#include "nvim/os/os.h"
#include "nvim/os_unix.h"
#include "nvim/path.h"
+#include "nvim/plines.h"
#include "nvim/quickfix.h"
#include "nvim/regexp.h"
#include "nvim/screen.h"
@@ -47,10 +46,11 @@
#include "nvim/strings.h"
#include "nvim/syntax.h"
#include "nvim/terminal.h"
-#include "nvim/undo.h"
#include "nvim/ui.h"
#include "nvim/ui_compositor.h"
-#include "nvim/os/os.h"
+#include "nvim/undo.h"
+#include "nvim/vim.h"
+#include "nvim/window.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -60,26 +60,29 @@
-#define NOWIN (win_T *)-1 /* non-existing window */
+#define NOWIN (win_T *)-1 // non-existing window
-# define ROWS_AVAIL (Rows - p_ch - tabline_height())
+#define ROWS_AVAIL (Rows - p_ch - tabline_height())
+/// flags for win_enter_ext()
+typedef enum {
+ WEE_UNDO_SYNC = 0x01,
+ WEE_CURWIN_INVALID = 0x02,
+ WEE_TRIGGER_NEW_AUTOCMDS = 0x04,
+ WEE_TRIGGER_ENTER_AUTOCMDS = 0x08,
+ WEE_TRIGGER_LEAVE_AUTOCMDS = 0x10,
+} wee_flags_T;
static char *m_onlyone = N_("Already only one window");
-/*
- * all CTRL-W window commands are handled here, called from normal_cmd().
- */
-void
-do_window(
- int nchar,
- long Prenum,
- int xchar /* extra char from ":wincmd gx" or NUL */
-)
+/// all CTRL-W window commands are handled here, called from normal_cmd().
+///
+/// @param xchar extra char from ":wincmd gx" or NUL
+void do_window(int nchar, long Prenum, int xchar)
{
long Prenum1;
- win_T *wp;
- char_u *ptr;
+ win_T *wp;
+ char_u *ptr;
linenr_T lnum = -1;
int type = FIND_DEFINE;
size_t len;
@@ -87,7 +90,7 @@ do_window(
Prenum1 = Prenum == 0 ? 1 : Prenum;
-# define CHECK_CMDWIN \
+#define CHECK_CMDWIN \
do { \
if (cmdwin_type != 0) { \
EMSG(_(e_cmdwin)); \
@@ -96,7 +99,7 @@ do_window(
} while (0)
switch (nchar) {
- /* split current window in two parts, horizontally */
+ // split current window in two parts, horizontally
case 'S':
case Ctrl_S:
case 's':
@@ -110,7 +113,7 @@ do_window(
(void)win_split((int)Prenum, 0);
break;
- /* split current window in two parts, vertically */
+ // split current window in two parts, vertically
case Ctrl_V:
case 'v':
CHECK_CMDWIN;
@@ -123,7 +126,7 @@ do_window(
(void)win_split((int)Prenum, WSP_VERT);
break;
- /* split current window and edit alternate file */
+ // split current window and edit alternate file
case Ctrl_HAT:
case '^':
CHECK_CMDWIN;
@@ -144,17 +147,18 @@ do_window(
}
break;
- /* open new window */
+ // open new window
case Ctrl_N:
case 'n':
CHECK_CMDWIN;
reset_VIsual_and_resel(); // stop Visual mode
newwindow:
- if (Prenum)
- /* window height */
+ if (Prenum) {
+ // window height
vim_snprintf(cbuf, sizeof(cbuf) - 5, "%" PRId64, (int64_t)Prenum);
- else
+ } else {
cbuf[0] = NUL;
+ }
if (nchar == 'v' || nchar == Ctrl_V) {
xstrlcat(cbuf, "v", sizeof(cbuf));
}
@@ -162,23 +166,23 @@ newwindow:
do_cmdline_cmd(cbuf);
break;
- /* quit current window */
+ // quit current window
case Ctrl_Q:
case 'q':
- reset_VIsual_and_resel(); /* stop Visual mode */
+ reset_VIsual_and_resel(); // stop Visual mode
cmd_with_count("quit", (char_u *)cbuf, sizeof(cbuf), Prenum);
do_cmdline_cmd(cbuf);
break;
- /* close current window */
+ // close current window
case Ctrl_C:
case 'c':
- reset_VIsual_and_resel(); /* stop Visual mode */
+ reset_VIsual_and_resel(); // stop Visual mode
cmd_with_count("close", (char_u *)cbuf, sizeof(cbuf), Prenum);
do_cmdline_cmd(cbuf);
break;
- /* close preview window */
+ // close preview window
case Ctrl_Z:
case 'z':
CHECK_CMDWIN;
@@ -186,7 +190,7 @@ newwindow:
do_cmdline_cmd("pclose");
break;
- /* cursor to preview window */
+ // cursor to preview window
case 'P':
wp = NULL;
FOR_ALL_WINDOWS_IN_TAB(wp2, curtab) {
@@ -202,7 +206,7 @@ newwindow:
}
break;
- /* close all but current window */
+ // close all but current window
case Ctrl_O:
case 'o':
CHECK_CMDWIN;
@@ -211,10 +215,10 @@ newwindow:
do_cmdline_cmd(cbuf);
break;
- /* cursor to next window with wrap around */
+ // cursor to next window with wrap around
case Ctrl_W:
case 'w':
- /* cursor to previous window with wrap around */
+ // cursor to previous window with wrap around
case 'W':
CHECK_CMDWIN;
if (ONE_WINDOW && Prenum != 1) { // just one window
@@ -222,10 +226,11 @@ newwindow:
} else {
if (Prenum) { // go to specified window
for (wp = firstwin; --Prenum > 0; ) {
- if (wp->w_next == NULL)
+ if (wp->w_next == NULL) {
break;
- else
+ } else {
wp = wp->w_next;
+ }
}
} else {
if (nchar == 'W') { // go to previous window
@@ -252,7 +257,7 @@ newwindow:
}
break;
- /* cursor to window below */
+ // cursor to window below
case 'j':
case K_DOWN:
case Ctrl_J:
@@ -260,7 +265,7 @@ newwindow:
win_goto_ver(false, Prenum1);
break;
- /* cursor to window above */
+ // cursor to window above
case 'k':
case K_UP:
case Ctrl_K:
@@ -268,7 +273,7 @@ newwindow:
win_goto_ver(true, Prenum1);
break;
- /* cursor to left window */
+ // cursor to left window
case 'h':
case K_LEFT:
case Ctrl_H:
@@ -277,7 +282,7 @@ newwindow:
win_goto_hor(true, Prenum1);
break;
- /* cursor to right window */
+ // cursor to right window
case 'l':
case K_RIGHT:
case Ctrl_L:
@@ -285,13 +290,13 @@ newwindow:
win_goto_hor(false, Prenum1);
break;
- /* move window to new tab page */
+ // move window to new tab page
case 'T':
- if (one_window())
+ if (one_window()) {
MSG(_(m_onlyone));
- else {
- tabpage_T *oldtab = curtab;
- tabpage_T *newtab;
+ } else {
+ tabpage_T *oldtab = curtab;
+ tabpage_T *newtab;
/* First create a new tab with the window, then go back to
* the old tab and close the window there. */
@@ -311,19 +316,19 @@ newwindow:
}
break;
- /* cursor to top-left window */
+ // cursor to top-left window
case 't':
case Ctrl_T:
win_goto(firstwin);
break;
- /* cursor to bottom-right window */
+ // cursor to bottom-right window
case 'b':
case Ctrl_B:
win_goto(lastwin_nofloating());
break;
- /* cursor to last accessed (previous) window */
+ // cursor to last accessed (previous) window
case 'p':
case Ctrl_P:
if (!win_valid(prevwin)) {
@@ -333,14 +338,14 @@ newwindow:
}
break;
- /* exchange current and next window */
+ // exchange current and next window
case 'x':
case Ctrl_X:
CHECK_CMDWIN;
win_exchange(Prenum);
break;
- /* rotate windows downwards */
+ // rotate windows downwards
case Ctrl_R:
case 'r':
CHECK_CMDWIN;
@@ -348,14 +353,14 @@ newwindow:
win_rotate(false, (int)Prenum1); // downwards
break;
- /* rotate windows upwards */
+ // rotate windows upwards
case 'R':
CHECK_CMDWIN;
reset_VIsual_and_resel(); // stop Visual mode
win_rotate(true, (int)Prenum1); // upwards
break;
- /* move window to the very top/bottom/left/right */
+ // move window to the very top/bottom/left/right
case 'K':
case 'J':
case 'H':
@@ -366,43 +371,43 @@ newwindow:
| ((nchar == 'H' || nchar == 'K') ? WSP_TOP : WSP_BOT));
break;
- /* make all windows the same height */
+ // make all windows the same height
case '=':
win_equal(NULL, false, 'b');
break;
- /* increase current window height */
+ // increase current window height
case '+':
win_setheight(curwin->w_height + (int)Prenum1);
break;
- /* decrease current window height */
+ // decrease current window height
case '-':
win_setheight(curwin->w_height - (int)Prenum1);
break;
- /* set current window height */
+ // set current window height
case Ctrl__:
case '_':
win_setheight(Prenum ? (int)Prenum : Rows-1);
break;
- /* increase current window width */
+ // increase current window width
case '>':
win_setwidth(curwin->w_width + (int)Prenum1);
break;
- /* decrease current window width */
+ // decrease current window width
case '<':
win_setwidth(curwin->w_width - (int)Prenum1);
break;
- /* set current window width */
+ // set current window width
case '|':
win_setwidth(Prenum != 0 ? (int)Prenum : Columns);
break;
- /* jump to tag and split window if tag exists (in preview window) */
+ // jump to tag and split window if tag exists (in preview window)
case '}':
CHECK_CMDWIN;
if (Prenum) {
@@ -415,10 +420,11 @@ newwindow:
case Ctrl_RSB:
CHECK_CMDWIN;
// Keep visual mode, can select words to use as a tag.
- if (Prenum)
+ if (Prenum) {
postponed_split = Prenum;
- else
+ } else {
postponed_split = -1;
+ }
if (nchar != '}') {
g_do_tagpreview = 0;
@@ -429,7 +435,7 @@ newwindow:
do_nv_ident(Ctrl_RSB, NUL);
break;
- /* edit file name under cursor in a new window */
+ // edit file name under cursor in a new window
case 'f':
case 'F':
case Ctrl_F:
@@ -460,7 +466,7 @@ wingotofile:
/* Go to the first occurrence of the identifier under cursor along path in a
* new window -- webb
*/
- case 'i': /* Go to any match */
+ case 'i': // Go to any match
case Ctrl_I:
type = FIND_ANY;
FALLTHROUGH;
@@ -484,7 +490,7 @@ wingotofile:
break;
- /* CTRL-W g extended commands */
+ // CTRL-W g extended commands
case 'g':
case Ctrl_G:
CHECK_CMDWIN;
@@ -498,18 +504,20 @@ wingotofile:
switch (xchar) {
case '}':
xchar = Ctrl_RSB;
- if (Prenum)
+ if (Prenum) {
g_do_tagpreview = Prenum;
- else
+ } else {
g_do_tagpreview = p_pvh;
+ }
FALLTHROUGH;
case ']':
case Ctrl_RSB:
// Keep visual mode, can select words to use as a tag.
- if (Prenum)
+ if (Prenum) {
postponed_split = Prenum;
- else
+ } else {
postponed_split = -1;
+ }
/* Execute the command right here, required when
* "wincmd g}" was used in a function. */
@@ -520,8 +528,8 @@ wingotofile:
goto_tabpage_lastused();
break;
- case 'f': /* CTRL-W gf: "gf" in a new tab page */
- case 'F': /* CTRL-W gF: "gF" in a new tab page */
+ case 'f': // CTRL-W gf: "gf" in a new tab page
+ case 'F': // CTRL-W gF: "gF" in a new tab page
cmdmod.tab = tabpage_index(curtab) + 1;
nchar = xchar;
goto wingotofile;
@@ -555,13 +563,13 @@ wingotofile:
}
break;
- default: beep_flush();
+ default:
+ beep_flush();
break;
}
}
-static void cmd_with_count(char *cmd, char_u *bufp, size_t bufsize,
- int64_t Prenum)
+static void cmd_with_count(char *cmd, char_u *bufp, size_t bufsize, int64_t Prenum)
{
size_t len = xstrlcpy((char *)bufp, cmd, bufsize);
@@ -676,7 +684,7 @@ void win_set_minimal_style(win_T *wp)
}
// signcolumn: use 'auto'
- if (wp->w_p_scl[0] != 'a') {
+ if (wp->w_p_scl[0] != 'a' || STRLEN(wp->w_p_scl) >= 8) {
xfree(wp->w_p_scl);
wp->w_p_scl = (char_u *)xstrdup("auto");
}
@@ -737,6 +745,37 @@ void win_config_float(win_T *wp, FloatConfig fconfig)
redraw_later(wp, NOT_VALID);
}
+ // compute initial position
+ if (wp->w_float_config.relative == kFloatRelativeWindow) {
+ int row = wp->w_float_config.row;
+ int col = wp->w_float_config.col;
+ Error dummy = ERROR_INIT;
+ win_T *parent = find_window_by_handle(wp->w_float_config.window, &dummy);
+ if (parent) {
+ row += parent->w_winrow;
+ col += parent->w_wincol;
+ ScreenGrid *grid = &parent->w_grid;
+ int row_off = 0, col_off = 0;
+ screen_adjust_grid(&grid, &row_off, &col_off);
+ row += row_off;
+ col += col_off;
+ }
+ api_clear_error(&dummy);
+ if (wp->w_float_config.bufpos.lnum >= 0) {
+ pos_T pos = { wp->w_float_config.bufpos.lnum + 1,
+ wp->w_float_config.bufpos.col, 0 };
+ int trow, tcol, tcolc, tcole;
+ textpos2screenpos(wp, &pos, &trow, &tcol, &tcolc, &tcole, true);
+ row += trow - 1;
+ col += tcol - 1;
+ }
+ wp->w_winrow = row;
+ wp->w_wincol = col;
+ } else {
+ wp->w_winrow = fconfig.row;
+ wp->w_wincol = fconfig.col;
+ }
+
// changing border style while keeping border only requires redrawing border
if (fconfig.border) {
wp->w_redr_border = true;
@@ -770,7 +809,6 @@ int win_fdccol_count(win_T *wp)
}
}
-
void ui_ext_win_position(win_T *wp)
{
if (!wp->w_floating) {
@@ -817,6 +855,8 @@ void ui_ext_win_position(win_T *wp)
int comp_row = (int)row - (south ? wp->w_height : 0);
int comp_col = (int)col - (east ? wp->w_width : 0);
+ comp_row += grid->comp_row;
+ comp_col += grid->comp_col;
comp_row = MAX(MIN(comp_row, Rows-wp->w_height_outer-1), 0);
comp_col = MAX(MIN(comp_col, Columns-wp->w_width_outer), 0);
wp->w_winrow = comp_row;
@@ -834,21 +874,21 @@ void ui_ext_win_position(win_T *wp)
} else {
ui_call_win_external_pos(wp->w_grid_alloc.handle, wp->handle);
}
-
}
void ui_ext_win_viewport(win_T *wp)
{
if ((wp == curwin || ui_has(kUIMultigrid)) && wp->w_viewport_invalid) {
int botline = wp->w_botline;
- if (botline == wp->w_buffer->b_ml.ml_line_count+1
- && wp->w_empty_rows == 0) {
+ int line_count = wp->w_buffer->b_ml.ml_line_count;
+ if (botline == line_count+1 && wp->w_empty_rows == 0) {
// TODO(bfredl): The might be more cases to consider, like how does this
// interact with incomplete final line? Diff filler lines?
botline = wp->w_buffer->b_ml.ml_line_count;
}
ui_call_win_viewport(wp->w_grid_alloc.handle, wp->handle, wp->w_topline-1,
- botline, wp->w_cursor.lnum-1, wp->w_cursor.col);
+ botline, wp->w_cursor.lnum-1, wp->w_cursor.col,
+ line_count);
wp->w_viewport_invalid = false;
}
}
@@ -870,11 +910,12 @@ void ui_ext_win_viewport(win_T *wp)
*/
int win_split(int size, int flags)
{
- /* When the ":tab" modifier was used open a new tab page instead. */
- if (may_open_tabpage() == OK)
+ // When the ":tab" modifier was used open a new tab page instead.
+ if (may_open_tabpage() == OK) {
return OK;
+ }
- /* Add flags from ":vertical", ":topleft" and ":botright". */
+ // Add flags from ":vertical", ":topleft" and ":botright".
flags |= cmdmod.split;
if ((flags & WSP_TOP) && (flags & WSP_BOT)) {
EMSG(_("E442: Can't split topleft and botright at the same time"));
@@ -883,10 +924,11 @@ int win_split(int size, int flags)
/* When creating the help window make a snapshot of the window layout.
* Otherwise clear the snapshot, it's now invalid. */
- if (flags & WSP_HELP)
+ if (flags & WSP_HELP) {
make_snapshot(SNAP_HELP_IDX);
- else
+ } else {
clear_snapshot(curtab, SNAP_HELP_IDX);
+ }
return win_split_ins(size, flags, NULL, 0);
}
@@ -899,17 +941,17 @@ int win_split(int size, int flags)
*/
int win_split_ins(int size, int flags, win_T *new_wp, int dir)
{
- win_T *wp = new_wp;
- win_T *oldwin;
+ win_T *wp = new_wp;
+ win_T *oldwin;
int new_size = size;
int i;
int need_status = 0;
- int do_equal = FALSE;
+ bool do_equal = false;
int needed;
int available;
int oldwin_height = 0;
int layout;
- frame_T *frp, *curfrp, *frp2, *prevfrp;
+ frame_T *frp, *curfrp, *frp2, *prevfrp;
int before;
int minheight;
int wmh1;
@@ -981,8 +1023,9 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
EMSG(_(e_noroom));
return FAIL;
}
- if (new_size == 0)
+ if (new_size == 0) {
new_size = oldwin->w_width / 2;
+ }
if (new_size > available - minwidth - 1) {
new_size = available - minwidth - 1;
}
@@ -990,9 +1033,10 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
new_size = wmw1;
}
- /* if it doesn't fit in the current window, need win_equal() */
- if (oldwin->w_width - new_size - 1 < p_wmw)
- do_equal = TRUE;
+ // if it doesn't fit in the current window, need win_equal()
+ if (oldwin->w_width - new_size - 1 < p_wmw) {
+ do_equal = true;
+ }
// We don't like to take lines for the new window from a
// 'winfixwidth' window. Take them from a window to the left or right
@@ -1009,9 +1053,9 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
while (frp != NULL) {
if (frp->fr_win != oldwin && frp->fr_win != NULL
&& (frp->fr_win->w_width > new_size
- || frp->fr_win->w_width > oldwin->w_width
- - new_size - 1)) {
- do_equal = TRUE;
+ || frp->fr_win->w_width > (oldwin->w_width
+ - new_size - 1))) {
+ do_equal = true;
break;
}
frp = frp->fr_next;
@@ -1064,8 +1108,9 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
oldwin->w_status_height = STATUS_HEIGHT;
oldwin_height -= STATUS_HEIGHT;
}
- if (new_size == 0)
+ if (new_size == 0) {
new_size = oldwin_height / 2;
+ }
if (new_size > available - minheight - STATUS_HEIGHT) {
new_size = available - minheight - STATUS_HEIGHT;
@@ -1074,9 +1119,10 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
new_size = wmh1;
}
- /* if it doesn't fit in the current window, need win_equal() */
- if (oldwin_height - new_size - STATUS_HEIGHT < p_wmh)
- do_equal = TRUE;
+ // if it doesn't fit in the current window, need win_equal()
+ if (oldwin_height - new_size - STATUS_HEIGHT < p_wmh) {
+ do_equal = true;
+ }
/* We don't like to take lines for the new window from a
* 'winfixheight' window. Take them from a window above or below
@@ -1088,10 +1134,11 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
did_set_fraction = true;
win_setheight_win(oldwin->w_height + new_size + STATUS_HEIGHT,
- oldwin);
+ oldwin);
oldwin_height = oldwin->w_height;
- if (need_status)
+ if (need_status) {
oldwin_height -= STATUS_HEIGHT;
+ }
}
/* Only make all windows the same height if one of them (except oldwin)
@@ -1105,7 +1152,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
&& (frp->fr_win->w_height > new_size
|| frp->fr_win->w_height > oldwin_height - new_size
- STATUS_HEIGHT)) {
- do_equal = TRUE;
+ do_equal = true;
break;
}
frp = frp->fr_next;
@@ -1120,28 +1167,29 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
&& ((flags & WSP_BOT)
|| (flags & WSP_BELOW)
|| (!(flags & WSP_ABOVE)
- && (
- (flags & WSP_VERT) ? p_spr :
- p_sb)))) {
- /* new window below/right of current one */
- if (new_wp == NULL)
- wp = win_alloc(oldwin, FALSE);
- else
+ && ((flags & WSP_VERT) ? p_spr : p_sb)))) {
+ // new window below/right of current one
+ if (new_wp == NULL) {
+ wp = win_alloc(oldwin, false);
+ } else {
win_append(oldwin, wp);
+ }
} else {
- if (new_wp == NULL)
- wp = win_alloc(oldwin->w_prev, FALSE);
- else
+ if (new_wp == NULL) {
+ wp = win_alloc(oldwin->w_prev, false);
+ } else {
win_append(oldwin->w_prev, wp);
+ }
}
if (new_wp == NULL) {
- if (wp == NULL)
+ if (wp == NULL) {
return FAIL;
+ }
new_frame(wp);
- /* make the contents of the new window the same as the current one */
+ // make the contents of the new window the same as the current one
win_init(wp, curwin, flags);
} else if (wp->w_floating) {
new_frame(wp);
@@ -1157,25 +1205,29 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
if ((topframe->fr_layout == FR_COL && (flags & WSP_VERT) == 0)
|| (topframe->fr_layout == FR_ROW && (flags & WSP_VERT) != 0)) {
curfrp = topframe->fr_child;
- if (flags & WSP_BOT)
- while (curfrp->fr_next != NULL)
+ if (flags & WSP_BOT) {
+ while (curfrp->fr_next != NULL) {
curfrp = curfrp->fr_next;
- } else
+ }
+ }
+ } else {
curfrp = topframe;
+ }
before = (flags & WSP_TOP);
} else {
curfrp = oldwin->w_frame;
- if (flags & WSP_BELOW)
+ if (flags & WSP_BELOW) {
before = FALSE;
- else if (flags & WSP_ABOVE)
+ } else if (flags & WSP_ABOVE) {
before = TRUE;
- else if (flags & WSP_VERT)
+ } else if (flags & WSP_VERT) {
before = !p_spr;
- else
+ } else {
before = !p_sb;
+ }
}
if (curfrp->fr_parent == NULL || curfrp->fr_parent->fr_layout != layout) {
- /* Need to create a new frame in the tree to make a branch. */
+ // Need to create a new frame in the tree to make a branch.
frp = xcalloc(1, sizeof(frame_T));
*frp = *curfrp;
curfrp->fr_layout = layout;
@@ -1194,17 +1246,19 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
}
}
- if (new_wp == NULL)
+ if (new_wp == NULL) {
frp = wp->w_frame;
- else
+ } else {
frp = new_wp->w_frame;
+ }
frp->fr_parent = curfrp->fr_parent;
- /* Insert the new frame at the right place in the frame list. */
- if (before)
+ // Insert the new frame at the right place in the frame list.
+ if (before) {
frame_insert(curfrp, frp);
- else
+ } else {
frame_append(curfrp, frp);
+ }
/* Set w_fraction now so that the cursor keeps the same relative
* vertical position. */
@@ -1221,12 +1275,12 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
oldwin->w_status_height = need_status;
}
if (flags & (WSP_TOP | WSP_BOT)) {
- /* set height and row of new window to full height */
+ // set height and row of new window to full height
wp->w_winrow = tabline_height();
win_new_height(wp, curfrp->fr_height - (p_ls > 0));
wp->w_status_height = (p_ls > 0);
} else {
- /* height and row of new window is same as current window */
+ // height and row of new window is same as current window
wp->w_winrow = oldwin->w_winrow;
win_new_height(wp, oldwin->w_height);
wp->w_status_height = oldwin->w_status_height;
@@ -1236,30 +1290,33 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
/* "new_size" of the current window goes to the new window, use
* one column for the vertical separator */
win_new_width(wp, new_size);
- if (before)
+ if (before) {
wp->w_vsep_width = 1;
- else {
+ } else {
wp->w_vsep_width = oldwin->w_vsep_width;
oldwin->w_vsep_width = 1;
}
if (flags & (WSP_TOP | WSP_BOT)) {
- if (flags & WSP_BOT)
+ if (flags & WSP_BOT) {
frame_add_vsep(curfrp);
- /* Set width of neighbor frame */
+ }
+ // Set width of neighbor frame
frame_new_width(curfrp, curfrp->fr_width
- - (new_size + ((flags & WSP_TOP) != 0)), flags & WSP_TOP,
- FALSE);
- } else
+ - (new_size + ((flags & WSP_TOP) != 0)), flags & WSP_TOP,
+ false);
+ } else {
win_new_width(oldwin, oldwin->w_width - (new_size + 1));
- if (before) { /* new window left of current one */
+ }
+ if (before) { // new window left of current one
wp->w_wincol = oldwin->w_wincol;
oldwin->w_wincol += new_size + 1;
- } else /* new window right of current one */
+ } else { // new window right of current one
wp->w_wincol = oldwin->w_wincol + oldwin->w_width + 1;
+ }
frame_fix_width(oldwin);
frame_fix_width(wp);
} else {
- /* width and column of new window is same as current window */
+ // width and column of new window is same as current window
if (flags & (WSP_TOP | WSP_BOT)) {
wp->w_wincol = 0;
win_new_width(wp, Columns);
@@ -1295,14 +1352,16 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
oldwin->w_status_height = STATUS_HEIGHT;
}
}
- if (flags & WSP_BOT)
+ if (flags & WSP_BOT) {
frame_add_statusline(curfrp);
+ }
frame_fix_height(wp);
frame_fix_height(oldwin);
}
- if (flags & (WSP_TOP | WSP_BOT))
+ if (flags & (WSP_TOP | WSP_BOT)) {
(void)win_comp_pos();
+ }
// Both windows need redrawing. Update all status lines, in case they
// show something related to the window count or position.
@@ -1313,41 +1372,42 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
if (need_status) {
msg_row = Rows - 1;
msg_col = sc_col;
- msg_clr_eos_force(); /* Old command/ruler may still be there */
+ msg_clr_eos_force(); // Old command/ruler may still be there
comp_col();
msg_row = Rows - 1;
- msg_col = 0; /* put position back at start of line */
+ msg_col = 0; // put position back at start of line
}
/*
* equalize the window sizes.
*/
- if (do_equal || dir != 0)
+ if (do_equal || dir != 0) {
win_equal(wp, true,
- (flags & WSP_VERT) ? (dir == 'v' ? 'b' : 'h')
- : dir == 'h' ? 'b' :
- 'v');
+ (flags & WSP_VERT) ? (dir == 'v' ? 'b' : 'h')
+ : dir == 'h' ? 'b' :
+ 'v');
+ }
/* Don't change the window height/width to 'winheight' / 'winwidth' if a
* size was given. */
if (flags & WSP_VERT) {
i = p_wiw;
- if (size != 0)
+ if (size != 0) {
p_wiw = size;
-
+ }
} else {
i = p_wh;
- if (size != 0)
+ if (size != 0) {
p_wh = size;
+ }
}
// Keep same changelist position in new window.
wp->w_changelistidx = oldwin->w_changelistidx;
- /*
- * make the new window the current window
- */
- win_enter_ext(wp, false, false, true, true, true);
+ // make the new window the current window
+ win_enter_ext(wp, WEE_TRIGGER_NEW_AUTOCMDS | WEE_TRIGGER_ENTER_AUTOCMDS
+ | WEE_TRIGGER_LEAVE_AUTOCMDS);
if (flags & WSP_VERT) {
p_wiw = i;
} else {
@@ -1394,7 +1454,7 @@ static void win_init(win_T *newp, win_T *oldp, int flags)
newp->w_prev_fraction_row = oldp->w_prev_fraction_row;
copy_jumplist(oldp, newp);
if (flags & WSP_NEWLOC) {
- /* Don't copy the location list. */
+ // Don't copy the location list.
newp->w_llist = NULL;
newp->w_llist_ref = NULL;
} else {
@@ -1403,7 +1463,7 @@ static void win_init(win_T *newp, win_T *oldp, int flags)
newp->w_localdir = (oldp->w_localdir == NULL)
? NULL : vim_strsave(oldp->w_localdir);
- /* copy tagstack and folds */
+ // copy tagstack and folds
for (i = 0; i < oldp->w_tagstacklen; i++) {
taggy_T *tag = &newp->w_tagstack[i];
*tag = oldp->w_tagstack[i];
@@ -1429,16 +1489,16 @@ static void win_init(win_T *newp, win_T *oldp, int flags)
*/
static void win_init_some(win_T *newp, win_T *oldp)
{
- /* Use the same argument list. */
+ // Use the same argument list.
newp->w_alist = oldp->w_alist;
++newp->w_alist->al_refcount;
newp->w_arg_idx = oldp->w_arg_idx;
- /* copy options from existing window */
+ // copy options from existing window
win_copy_options(oldp, newp);
}
-/// Return TRUE if "win" is floating window in the current tab page.
+/// Return true if "win" is floating window in the current tab page.
///
/// @param win window to check
bool win_valid_floating(const win_T *win)
@@ -1516,17 +1576,14 @@ int win_count(void)
return count;
}
-/*
- * Make "count" windows on the screen.
- * Return actual number of windows on the screen.
- * Must be called when there is just one window, filling the whole screen
- * (excluding the command line).
- */
-int
-make_windows (
- int count,
- int vertical /* split windows vertically if TRUE */
-)
+/// Make "count" windows on the 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
+///
+/// @return actual number of windows on the screen.
+int make_windows(int count, bool vertical)
{
int maxcount;
int todo;
@@ -1543,16 +1600,19 @@ make_windows (
- (p_wh - p_wmh)) / (p_wmh + STATUS_HEIGHT);
}
- if (maxcount < 2)
+ if (maxcount < 2) {
maxcount = 2;
- if (count > maxcount)
+ }
+ if (count > maxcount) {
count = maxcount;
+ }
/*
* add status line now, otherwise first window will be too big
*/
- if (count > 1)
- last_status(TRUE);
+ if (count > 1) {
+ last_status(true);
+ }
/*
* Don't execute autocommands while creating the windows. Must do that
@@ -1560,22 +1620,25 @@ make_windows (
*/
block_autocmds();
- /* todo is number of windows left to create */
- for (todo = count - 1; todo > 0; --todo)
+ // todo is number of windows left to create
+ for (todo = count - 1; todo > 0; --todo) {
if (vertical) {
if (win_split(curwin->w_width - (curwin->w_width - todo)
- / (todo + 1) - 1, WSP_VERT | WSP_ABOVE) == FAIL)
+ / (todo + 1) - 1, WSP_VERT | WSP_ABOVE) == FAIL) {
break;
+ }
} else {
if (win_split(curwin->w_height - (curwin->w_height - todo
* STATUS_HEIGHT) / (todo + 1)
- - STATUS_HEIGHT, WSP_ABOVE) == FAIL)
+ - STATUS_HEIGHT, WSP_ABOVE) == FAIL) {
break;
+ }
}
+ }
unblock_autocmds();
- /* return actual number of windows */
+ // return actual number of windows
return count - todo;
}
@@ -1584,10 +1647,10 @@ make_windows (
*/
static void win_exchange(long Prenum)
{
- frame_T *frp;
- frame_T *frp2;
- win_T *wp;
- win_T *wp2;
+ frame_T *frp;
+ frame_T *frp2;
+ win_T *wp;
+ win_T *wp2;
int temp;
if (curwin->w_floating) {
@@ -1607,17 +1670,20 @@ static void win_exchange(long Prenum)
*/
if (Prenum) {
frp = curwin->w_frame->fr_parent->fr_child;
- while (frp != NULL && --Prenum > 0)
+ while (frp != NULL && --Prenum > 0) {
frp = frp->fr_next;
- } else if (curwin->w_frame->fr_next != NULL) /* Swap with next */
+ }
+ } else if (curwin->w_frame->fr_next != NULL) { // Swap with next
frp = curwin->w_frame->fr_next;
- else /* Swap last window in row/col with previous */
+ } else { // Swap last window in row/col with previous
frp = curwin->w_frame->fr_prev;
+ }
/* We can only exchange a window with another window, not with a frame
* containing windows. */
- if (frp == NULL || frp->fr_win == NULL || frp->fr_win == curwin)
+ if (frp == NULL || frp->fr_win == NULL || frp->fr_win == curwin) {
return;
+ }
wp = frp->fr_win;
/*
@@ -1640,10 +1706,11 @@ static void win_exchange(long Prenum)
win_remove(wp, NULL);
frame_remove(wp->w_frame);
win_append(wp2, wp);
- if (frp2 == NULL)
+ if (frp2 == NULL) {
frame_insert(wp->w_frame->fr_parent->fr_child, wp->w_frame);
- else
+ } else {
frame_append(frp2, wp->w_frame);
+ }
}
temp = curwin->w_status_height;
curwin->w_status_height = wp->w_status_height;
@@ -1652,23 +1719,12 @@ static void win_exchange(long Prenum)
curwin->w_vsep_width = wp->w_vsep_width;
wp->w_vsep_width = temp;
- /* If the windows are not in the same frame, exchange the sizes to avoid
- * messing up the window layout. Otherwise fix the frame sizes. */
- if (curwin->w_frame->fr_parent != wp->w_frame->fr_parent) {
- temp = curwin->w_height;
- curwin->w_height = wp->w_height;
- wp->w_height = temp;
- temp = curwin->w_width;
- curwin->w_width = wp->w_width;
- wp->w_width = temp;
- } else {
- frame_fix_height(curwin);
- frame_fix_height(wp);
- frame_fix_width(curwin);
- frame_fix_width(wp);
- }
+ frame_fix_height(curwin);
+ frame_fix_height(wp);
+ frame_fix_width(curwin);
+ frame_fix_width(wp);
- (void)win_comp_pos(); /* recompute window positions */
+ (void)win_comp_pos(); // recompute window positions
win_enter(wp, true);
redraw_later(curwin, NOT_VALID);
@@ -1679,9 +1735,9 @@ static void win_exchange(long Prenum)
// if upwards false the first window becomes the second one
static void win_rotate(bool upwards, int count)
{
- win_T *wp1;
- win_T *wp2;
- frame_T *frp;
+ win_T *wp1;
+ win_T *wp2;
+ frame_T *frp;
int n;
if (curwin->w_floating) {
@@ -1704,8 +1760,8 @@ static void win_rotate(bool upwards, int count)
}
while (count--) {
- if (upwards) { /* first window becomes last window */
- /* remove first window/frame from the list */
+ if (upwards) { // first window becomes last window
+ // remove first window/frame from the list
frp = curwin->w_frame->fr_parent->fr_child;
assert(frp != NULL);
wp1 = frp->fr_win;
@@ -1713,30 +1769,32 @@ static void win_rotate(bool upwards, int count)
frame_remove(frp);
assert(frp->fr_parent->fr_child);
- /* find last frame and append removed window/frame after it */
- for (; frp->fr_next != NULL; frp = frp->fr_next)
+ // find last frame and append removed window/frame after it
+ for (; frp->fr_next != NULL; frp = frp->fr_next) {
;
+ }
win_append(frp->fr_win, wp1);
frame_append(frp, wp1->w_frame);
- wp2 = frp->fr_win; /* previously last window */
- } else { /* last window becomes first window */
- /* find last window/frame in the list and remove it */
+ wp2 = frp->fr_win; // previously last window
+ } else { // last window becomes first window
+ // find last window/frame in the list and remove it
for (frp = curwin->w_frame; frp->fr_next != NULL;
- frp = frp->fr_next)
+ frp = frp->fr_next) {
;
+ }
wp1 = frp->fr_win;
- wp2 = wp1->w_prev; /* will become last window */
+ wp2 = wp1->w_prev; // will become last window
win_remove(wp1, NULL);
frame_remove(frp);
assert(frp->fr_parent->fr_child);
- /* append the removed window/frame before the first in the list */
+ // append the removed window/frame before the first in the list
win_append(frp->fr_parent->fr_child->fr_win->w_prev, wp1);
frame_insert(frp->fr_parent->fr_child, frp);
}
- /* exchange status height and vsep width of old and new last window */
+ // exchange status 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;
@@ -1748,7 +1806,7 @@ static void win_rotate(bool upwards, int count)
frame_fix_width(wp1);
frame_fix_width(wp2);
- /* recompute w_winrow and w_wincol for all windows */
+ // recompute w_winrow and w_wincol for all windows
(void)win_comp_pos();
}
@@ -1785,17 +1843,17 @@ static void win_totop(int size, int flags)
(void)winframe_remove(curwin, &dir, NULL);
}
win_remove(curwin, NULL);
- last_status(FALSE); /* may need to remove last status line */
- (void)win_comp_pos(); /* recompute window positions */
+ last_status(false); // may need to remove last status line
+ (void)win_comp_pos(); // recompute window positions
- /* Split a window on the desired side and put the window there. */
+ // Split a window on the desired side and put the window there.
(void)win_split_ins(size, flags, curwin, dir);
if (!(flags & WSP_VERT)) {
win_setheight(height);
- if (p_ea)
+ if (p_ea) {
win_equal(curwin, true, 'v');
+ }
}
-
}
/*
@@ -1806,11 +1864,12 @@ void win_move_after(win_T *win1, win_T *win2)
{
int height;
- /* check if the arguments are reasonable */
- if (win1 == win2)
+ // check if the arguments are reasonable
+ if (win1 == win2) {
return;
+ }
- /* check if there is something to do */
+ // check if there is something to do
if (win2->w_next != win1) {
/* may need move the status line/vertical separator of the last window
* */
@@ -1853,58 +1912,54 @@ void win_move_after(win_T *win1, win_T *win2)
win2->w_pos_changed = true;
}
-/*
- * Make all windows the same height.
- * 'next_curwin' will soon be the current window, make sure it has enough
- * rows.
- */
-void win_equal(
- win_T *next_curwin, // pointer to current window to be or NULL
- bool current, // do only frame with current window
- int dir // 'v' for vertically, 'h' for horizontally,
- // 'b' for both, 0 for using p_ead
-)
-{
- if (dir == 0)
+/// Make all windows the same height.
+///'next_curwin' will soon be the current window, make sure it has enough rows.
+///
+/// @param next_curwin pointer to current window to be or NULL
+/// @param current do only frame with current window
+/// @param dir 'v' for vertically, 'h' for horizontally, 'b' for both, 0 for using p_ead
+void win_equal(win_T *next_curwin, bool current, int dir)
+{
+ if (dir == 0) {
dir = *p_ead;
+ }
win_equal_rec(next_curwin == NULL ? curwin : next_curwin, current,
topframe, dir, 0, tabline_height(),
Columns, topframe->fr_height);
}
-/*
- * Set a frame to a new position and height, spreading the available room
- * equally over contained frames.
- * The window "next_curwin" (if not NULL) should at least get the size from
- * 'winheight' and 'winwidth' if possible.
- */
-static void win_equal_rec(
- win_T *next_curwin, /* pointer to current window to be or NULL */
- bool current, /* do only frame with current window */
- frame_T *topfr, /* frame to set size off */
- int dir, /* 'v', 'h' or 'b', see win_equal() */
- int col, /* horizontal position for frame */
- int row, /* vertical position for frame */
- int width, /* new width of frame */
- int height /* new height of frame */
-)
+/// Set a frame to a new position and height, spreading the available room
+/// equally over contained frames.
+/// The window "next_curwin" (if not NULL) should at least get the size from
+/// 'winheight' and 'winwidth' if possible.
+///
+/// @param next_curwin pointer to current window to be or NULL
+/// @param current do only frame with current window
+/// @param topfr frame to set size off
+/// @param dir 'v', 'h' or 'b', see win_equal()
+/// @param col horizontal position for frame
+/// @param row vertical position for frame
+/// @param width new width of frame
+/// @param height new height of frame
+static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int dir, int col,
+ int row, int width, int height)
{
int n, m;
int extra_sep = 0;
int wincount, totwincount = 0;
- frame_T *fr;
+ frame_T *fr;
int next_curwin_size = 0;
int room = 0;
int new_size;
int has_next_curwin = 0;
- int hnc;
+ bool hnc;
if (topfr->fr_layout == FR_LEAF) {
/* Set the width/height of this frame.
* Redraw when size or position changes */
if (topfr->fr_height != height || topfr->fr_win->w_winrow != row
- || topfr->fr_width != width || topfr->fr_win->w_wincol != col
- ) {
+ || topfr->fr_width != width ||
+ topfr->fr_win->w_wincol != col) {
topfr->fr_win->w_winrow = row;
frame_new_height(topfr, height, false, false);
topfr->fr_win->w_wincol = col;
@@ -1915,15 +1970,16 @@ static void win_equal_rec(
topfr->fr_width = width;
topfr->fr_height = height;
- if (dir != 'v') { /* equalize frame widths */
+ if (dir != 'v') { // equalize frame widths
/* Compute the maximum number of windows horizontally in this
* frame. */
n = frame_minwidth(topfr, NOWIN);
- /* add one for the rightmost window, it doesn't have a separator */
- if (col + width == Columns)
+ // add one for the rightmost window, it doesn't have a separator
+ if (col + width == Columns) {
extra_sep = 1;
- else
+ } else {
extra_sep = 0;
+ }
totwincount = (n + extra_sep) / (p_wmw + 1);
has_next_curwin = frame_has_win(topfr, next_curwin);
@@ -1951,12 +2007,14 @@ static void win_equal_rec(
if (frame_has_win(fr, next_curwin)) {
room += p_wiw - p_wmw;
next_curwin_size = 0;
- if (new_size < p_wiw)
+ if (new_size < p_wiw) {
new_size = p_wiw;
- } else
- /* These windows don't use up room. */
+ }
+ } else {
+ // These windows don't use up room.
totwincount -= (n + (fr->fr_next == NULL
? extra_sep : 0)) / (p_wmw + 1);
+ }
room -= new_size - n;
if (room < 0) {
new_size += room;
@@ -1965,58 +2023,64 @@ static void win_equal_rec(
fr->fr_newwidth = new_size;
}
if (next_curwin_size == -1) {
- if (!has_next_curwin)
+ if (!has_next_curwin) {
next_curwin_size = 0;
- else if (totwincount > 1
- && (room + (totwincount - 2))
- / (totwincount - 1) > p_wiw) {
+ } else if (totwincount > 1
+ && (room + (totwincount - 2))
+ / (totwincount - 1) > p_wiw) {
/* Can make all windows wider than 'winwidth', spread
* the room equally. */
next_curwin_size = (room + p_wiw
+ (totwincount - 1) * p_wmw
+ (totwincount - 1)) / totwincount;
room -= next_curwin_size - p_wiw;
- } else
+ } else {
next_curwin_size = p_wiw;
+ }
}
}
- if (has_next_curwin)
- --totwincount; /* don't count curwin */
+ if (has_next_curwin) {
+ --totwincount; // don't count curwin
+ }
}
FOR_ALL_FRAMES(fr, topfr->fr_child) {
wincount = 1;
- if (fr->fr_next == NULL)
- /* last frame gets all that remains (avoid roundoff error) */
+ if (fr->fr_next == NULL) {
+ // last frame gets all that remains (avoid roundoff error)
new_size = width;
- else if (dir == 'v')
+ } else if (dir == 'v') {
new_size = fr->fr_width;
- else if (frame_fixed_width(fr)) {
+ } else if (frame_fixed_width(fr)) {
new_size = fr->fr_newwidth;
- wincount = 0; /* doesn't count as a sizeable window */
+ wincount = 0; // doesn't count as a sizeable window
} else {
- /* Compute the maximum number of windows horiz. in "fr". */
+ // Compute the maximum number of windows horiz. in "fr".
n = frame_minwidth(fr, NOWIN);
wincount = (n + (fr->fr_next == NULL ? extra_sep : 0))
/ (p_wmw + 1);
m = frame_minwidth(fr, next_curwin);
- if (has_next_curwin)
+ if (has_next_curwin) {
hnc = frame_has_win(fr, next_curwin);
- else
- hnc = FALSE;
- if (hnc) /* don't count next_curwin */
- --wincount;
- if (totwincount == 0)
+ } else {
+ hnc = false;
+ }
+ if (hnc) { // don't count next_curwin
+ wincount--;
+ }
+ if (totwincount == 0) {
new_size = room;
- else
+ } else {
new_size = (wincount * room + (totwincount / 2)) / totwincount;
- if (hnc) { /* add next_curwin size */
+ }
+ if (hnc) { // add next_curwin size
next_curwin_size -= p_wiw - (m - n);
new_size += next_curwin_size;
room -= new_size - next_curwin_size;
- } else
+ } else {
room -= new_size;
+ }
new_size += n;
}
@@ -2024,25 +2088,27 @@ static void win_equal_rec(
* window, unless equalizing all frames. */
if (!current || dir != 'v' || topfr->fr_parent != NULL
|| (new_size != fr->fr_width)
- || frame_has_win(fr, next_curwin))
+ || frame_has_win(fr, next_curwin)) {
win_equal_rec(next_curwin, current, fr, dir, col, row,
- new_size, height);
+ new_size, height);
+ }
col += new_size;
width -= new_size;
totwincount -= wincount;
}
- } else { /* topfr->fr_layout == FR_COL */
+ } else { // topfr->fr_layout == FR_COL
topfr->fr_width = width;
topfr->fr_height = height;
- if (dir != 'h') { /* equalize frame heights */
- /* Compute maximum number of windows vertically in this frame. */
+ if (dir != 'h') { // equalize frame heights
+ // Compute maximum number of windows vertically in this frame.
n = frame_minheight(topfr, NOWIN);
- /* add one for the bottom window if it doesn't have a statusline */
- if (row + height == cmdline_row && p_ls == 0)
+ // add one for the bottom window if it doesn't have a statusline
+ if (row + height == cmdline_row && p_ls == 0) {
extra_sep = 1;
- else
+ } else {
extra_sep = 0;
+ }
totwincount = (n + extra_sep) / (p_wmh + 1);
has_next_curwin = frame_has_win(topfr, next_curwin);
@@ -2072,12 +2138,14 @@ static void win_equal_rec(
if (frame_has_win(fr, next_curwin)) {
room += p_wh - p_wmh;
next_curwin_size = 0;
- if (new_size < p_wh)
+ if (new_size < p_wh) {
new_size = p_wh;
- } else
- /* These windows don't use up room. */
+ }
+ } else {
+ // These windows don't use up room.
totwincount -= (n + (fr->fr_next == NULL
? extra_sep : 0)) / (p_wmh + 1);
+ }
room -= new_size - n;
if (room < 0) {
new_size += room;
@@ -2086,67 +2154,74 @@ static void win_equal_rec(
fr->fr_newheight = new_size;
}
if (next_curwin_size == -1) {
- if (!has_next_curwin)
+ if (!has_next_curwin) {
next_curwin_size = 0;
- else if (totwincount > 1
- && (room + (totwincount - 2))
- / (totwincount - 1) > p_wh) {
+ } else if (totwincount > 1
+ && (room + (totwincount - 2))
+ / (totwincount - 1) > p_wh) {
/* can make all windows higher than 'winheight',
* spread the room equally. */
next_curwin_size = (room + p_wh
+ (totwincount - 1) * p_wmh
+ (totwincount - 1)) / totwincount;
room -= next_curwin_size - p_wh;
- } else
+ } else {
next_curwin_size = p_wh;
+ }
}
}
- if (has_next_curwin)
- --totwincount; /* don't count curwin */
+ if (has_next_curwin) {
+ --totwincount; // don't count curwin
+ }
}
FOR_ALL_FRAMES(fr, topfr->fr_child) {
wincount = 1;
- if (fr->fr_next == NULL)
- /* last frame gets all that remains (avoid roundoff error) */
+ if (fr->fr_next == NULL) {
+ // last frame gets all that remains (avoid roundoff error)
new_size = height;
- else if (dir == 'h')
+ } else if (dir == 'h') {
new_size = fr->fr_height;
- else if (frame_fixed_height(fr)) {
+ } else if (frame_fixed_height(fr)) {
new_size = fr->fr_newheight;
- wincount = 0; /* doesn't count as a sizeable window */
+ wincount = 0; // doesn't count as a sizeable window
} else {
- /* Compute the maximum number of windows vert. in "fr". */
+ // 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 + 1);
m = frame_minheight(fr, next_curwin);
- if (has_next_curwin)
+ if (has_next_curwin) {
hnc = frame_has_win(fr, next_curwin);
- else
- hnc = FALSE;
- if (hnc) /* don't count next_curwin */
- --wincount;
- if (totwincount == 0)
+ } else {
+ hnc = false;
+ }
+ if (hnc) { // don't count next_curwin
+ wincount--;
+ }
+ if (totwincount == 0) {
new_size = room;
- else
+ } else {
new_size = (wincount * room + (totwincount / 2)) / totwincount;
- if (hnc) { /* add next_curwin size */
+ }
+ if (hnc) { // add next_curwin size
next_curwin_size -= p_wh - (m - n);
new_size += next_curwin_size;
room -= new_size - next_curwin_size;
- } else
+ } else {
room -= new_size;
+ }
new_size += n;
}
/* Skip frame that is full width when splitting or closing a
* window, unless equalizing all frames. */
if (!current || dir != 'h' || topfr->fr_parent != NULL
|| (new_size != fr->fr_height)
- || frame_has_win(fr, next_curwin))
+ || frame_has_win(fr, next_curwin)) {
win_equal_rec(next_curwin, current, fr, dir, col, row,
- width, new_size);
+ width, new_size);
+ }
row += new_size;
height -= new_size;
totwincount -= wincount;
@@ -2159,7 +2234,7 @@ static void win_equal_rec(
/// @param keep_curwin don't close `curwin`
void close_windows(buf_T *buf, int keep_curwin)
{
- tabpage_T *tp, *nexttp;
+ tabpage_T *tp, *nexttp;
int h = tabline_height();
++RedrawingDisabled;
@@ -2172,13 +2247,14 @@ void close_windows(buf_T *buf, int keep_curwin)
break;
}
- /* Start all over, autocommands may change the window layout. */
+ // Start all over, autocommands may change the window layout.
wp = firstwin;
- } else
+ } else {
wp = wp->w_next;
+ }
}
- /* Also check windows in other tab pages. */
+ // Also check windows in other tab pages.
for (tp = first_tabpage; tp != NULL; tp = nexttp) {
nexttp = tp->tp_next;
if (tp != curtab) {
@@ -2252,14 +2328,13 @@ bool last_nonfloat(win_T *wp) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
/// last window in the tabpage
///
/// @return true when the window was closed already.
-static bool close_last_window_tabpage(win_T *win, bool free_buf,
- tabpage_T *prev_curtab)
+static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev_curtab)
FUNC_ATTR_NONNULL_ARG(1)
{
if (!ONE_WINDOW) {
return false;
}
- buf_T *old_curbuf = curbuf;
+ buf_T *old_curbuf = curbuf;
Terminal *term = win->w_buffer ? win->w_buffer->terminal : NULL;
if (term) {
@@ -2275,8 +2350,8 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf,
* Don't trigger autocommands yet, they may use wrong values, so do
* that below.
*/
- goto_tabpage_tp(alt_tabpage(), FALSE, TRUE);
- redraw_tabline = TRUE;
+ goto_tabpage_tp(alt_tabpage(), false, true);
+ redraw_tabline = true;
// save index for tabclosed event
char_u prev_idx[NUMBUFLEN];
@@ -2288,8 +2363,9 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf,
int h = tabline_height();
win_close_othertab(win, free_buf, prev_curtab);
- if (h != tabline_height())
+ if (h != tabline_height()) {
shell_new_rows();
+ }
}
// Since goto_tabpage_tp above did not trigger *Enter autocommands, do
@@ -2309,12 +2385,12 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf,
// Returns FAIL when the window was not closed.
int win_close(win_T *win, bool free_buf)
{
- win_T *wp;
- int other_buffer = FALSE;
- int close_curwin = FALSE;
+ win_T *wp;
+ bool other_buffer = false;
+ bool close_curwin = false;
int dir;
bool help_window = false;
- tabpage_T *prev_curtab = curtab;
+ tabpage_T *prev_curtab = curtab;
frame_T *win_frame = win->w_floating ? NULL : win->w_frame->fr_parent;
const bool had_diffmode = win->w_p_diff;
@@ -2345,8 +2421,9 @@ int win_close(win_T *win, bool free_buf)
/* When closing the last window in a tab page first go to another tab page
* and then close the window and the tab page to avoid that curwin and
* curtab are invalid while we are freeing memory. */
- if (close_last_window_tabpage(win, free_buf, prev_curtab))
+ if (close_last_window_tabpage(win, free_buf, prev_curtab)) {
return FAIL;
+ }
/* When closing the help window, try restoring a snapshot after closing
* the window. Otherwise clear the snapshot, it's now invalid. */
@@ -2376,14 +2453,16 @@ int win_close(win_T *win, bool free_buf)
* to be the last one left, return now.
*/
if (wp->w_buffer != curbuf) {
- other_buffer = TRUE;
+ other_buffer = true;
win->w_closing = true;
- apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
- if (!win_valid(win))
+ apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, false, curbuf);
+ if (!win_valid(win)) {
return FAIL;
+ }
win->w_closing = false;
- if (last_window())
+ if (last_window()) {
return FAIL;
+ }
}
win->w_closing = true;
apply_autocmds(EVENT_WINLEAVE, NULL, NULL, false, curbuf);
@@ -2391,11 +2470,13 @@ int win_close(win_T *win, bool free_buf)
return FAIL;
}
win->w_closing = false;
- if (last_window())
+ if (last_window()) {
return FAIL;
- /* autocmds may abort script processing */
- if (aborting())
+ }
+ // autocmds may abort script processing
+ if (aborting()) {
return FAIL;
+ }
}
bool was_floating = win->w_floating;
@@ -2502,12 +2583,14 @@ int win_close(win_T *win, bool free_buf)
* finding another window to go to.
*/
for (;; ) {
- if (wp->w_next == NULL)
+ if (wp->w_next == NULL) {
wp = firstwin;
- else
+ } else {
wp = wp->w_next;
- if (wp == curwin)
+ }
+ if (wp == curwin) {
break;
+ }
if (!wp->w_p_pvw && !bt_quickfix(wp->w_buffer)) {
curwin = wp;
break;
@@ -2515,7 +2598,7 @@ int win_close(win_T *win, bool free_buf)
}
}
curbuf = curwin->w_buffer;
- close_curwin = TRUE;
+ close_curwin = true;
// The cursor position may be invalid if the buffer changed after last
// using the window.
@@ -2533,7 +2616,8 @@ int win_close(win_T *win, bool free_buf)
}
if (close_curwin) {
- win_enter_ext(wp, false, true, false, true, true);
+ win_enter_ext(wp, WEE_CURWIN_INVALID | WEE_TRIGGER_ENTER_AUTOCMDS
+ | WEE_TRIGGER_LEAVE_AUTOCMDS);
if (other_buffer) {
// careful: after this wp and win may be invalid!
apply_autocmds(EVENT_BUFENTER, NULL, NULL, false, curbuf);
@@ -2544,12 +2628,13 @@ int win_close(win_T *win, bool free_buf)
* If last window has a status line now and we don't want one,
* remove the status line.
*/
- last_status(FALSE);
+ last_status(false);
/* After closing the help window, try restoring the window layout from
* before it was opened. */
- if (help_window)
+ if (help_window) {
restore_snapshot(SNAP_HELP_IDX, close_curwin);
+ }
// If the window had 'diff' set and now there is only one window left in
// the tab page with 'diff' set, and "closeoff" is in 'diffopt', then
@@ -2596,8 +2681,8 @@ static void do_autocmd_winclosed(win_T *win)
void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp)
{
int dir;
- tabpage_T *ptp = NULL;
- int free_tp = FALSE;
+ tabpage_T *ptp = NULL;
+ bool free_tp = false;
// Get here with win->w_buffer == NULL when win_close() detects the tab page
// changed.
@@ -2620,26 +2705,28 @@ void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp)
/* Careful: Autocommands may have closed the tab page or made it the
* current tab page. */
- for (ptp = first_tabpage; ptp != NULL && ptp != tp; ptp = ptp->tp_next)
+ for (ptp = first_tabpage; ptp != NULL && ptp != tp; ptp = ptp->tp_next) {
;
- if (ptp == NULL || tp == curtab)
+ }
+ if (ptp == NULL || tp == curtab) {
return;
+ }
- /* Autocommands may have closed the window already. */
+ // Autocommands may have closed the window already.
{
bool found_window = false;
FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
if (wp == win) {
- found_window = true;
- break;
+ found_window = true;
+ break;
}
}
if (!found_window) {
- return;
+ return;
}
}
- /* When closing the last window in a tab page remove the tab page. */
+ // When closing the last window in a tab page remove the tab page.
if (tp->tp_firstwin == tp->tp_lastwin) {
char_u prev_idx[NUMBUFLEN];
if (has_event(EVENT_TABCLOSED)) {
@@ -2666,23 +2753,24 @@ void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp)
}
}
- /* Free the memory used for the window. */
+ // Free the memory used for the window.
win_free_mem(win, &dir, tp);
- if (free_tp)
+ if (free_tp) {
free_tabpage(tp);
+ }
}
-// Free the memory used for a window.
-// Returns a pointer to the window that got the freed up space.
-static win_T *win_free_mem(
- win_T *win,
- int *dirp, // set to 'v' or 'h' for direction if 'ea'
- tabpage_T *tp // tab page "win" is in, NULL for current
-)
+/// Free the memory used for a window.
+///
+/// @param dirp set to 'v' or 'h' for direction if 'ea'
+/// @param tp tab page "win" is in, NULL for current
+///
+/// @return a pointer to the window that got the freed up space.
+static win_T *win_free_mem(win_T *win, int *dirp, tabpage_T *tp)
{
- frame_T *frp;
- win_T *wp;
+ frame_T *frp;
+ win_T *wp;
if (!win->w_floating) {
// Remove the window and its frame from the tree of frames.
@@ -2702,7 +2790,11 @@ static win_T *win_free_mem(
// When deleting the current window of another tab page select a new
// current window.
if (tp != NULL && win == tp->tp_curwin) {
- tp->tp_curwin = wp;
+ if (win_valid(tp->tp_prevwin) && tp->tp_prevwin != win) {
+ tp->tp_curwin = tp->tp_prevwin;
+ } else {
+ tp->tp_curwin = tp->tp_firstwin;
+ }
}
return wp;
@@ -2713,8 +2805,9 @@ void win_free_all(void)
{
int dummy;
- while (first_tabpage->tp_next != NULL)
+ while (first_tabpage->tp_next != NULL) {
tabpage_close(TRUE);
+ }
while (lastwin != NULL && lastwin->w_floating) {
win_T *wp = lastwin;
@@ -2730,8 +2823,9 @@ void win_free_all(void)
aucmd_win = NULL;
}
- while (firstwin != NULL)
+ while (firstwin != NULL) {
(void)win_free_mem(firstwin, &dummy, NULL);
+ }
// No window should be used after this. Set curwin to NULL to crash
// instead of using freed memory.
@@ -2740,26 +2834,24 @@ void win_free_all(void)
#endif
-/*
- * Remove a window and its frame from the tree of frames.
- * Returns a pointer to the window that got the freed up space.
- */
-win_T *
-winframe_remove (
- win_T *win,
- int *dirp, /* set to 'v' or 'h' for direction if 'ea' */
- tabpage_T *tp /* tab page "win" is in, NULL for current */
-)
+/// Remove a window and its frame from the tree of frames.
+///
+/// @param dirp set to 'v' or 'h' for direction if 'ea'
+/// @param tp tab page "win" is in, NULL for current
+///
+/// @return a pointer to the window that got the freed up space.
+win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp)
{
- frame_T *frp, *frp2, *frp3;
- frame_T *frp_close = win->w_frame;
- win_T *wp;
+ frame_T *frp, *frp2, *frp3;
+ frame_T *frp_close = win->w_frame;
+ win_T *wp;
/*
* If there is only one window there is nothing to remove.
*/
- if (tp == NULL ? ONE_WINDOW : tp->tp_firstwin == tp->tp_lastwin)
+ if (tp == NULL ? ONE_WINDOW : tp->tp_firstwin == tp->tp_lastwin) {
return NULL;
+ }
/*
* Remove the window from its frame.
@@ -2767,7 +2859,7 @@ winframe_remove (
frp2 = win_altframe(win, tp);
wp = frame2win(frp2);
- /* Remove this frame from the list of frames. */
+ // Remove this frame from the list of frames.
frame_remove(frp_close);
if (frp_close->fr_parent->fr_layout == FR_COL) {
@@ -2797,7 +2889,7 @@ winframe_remove (
}
}
frame_new_height(frp2, frp2->fr_height + frp_close->fr_height,
- frp2 == frp_close->fr_next ? TRUE : FALSE, FALSE);
+ frp2 == frp_close->fr_next, false);
*dirp = 'v';
} else {
/* When 'winfixwidth' is set, try to find another frame in the column
@@ -2826,7 +2918,7 @@ winframe_remove (
}
}
frame_new_width(frp2, frp2->fr_width + frp_close->fr_width,
- frp2 == frp_close->fr_next ? TRUE : FALSE, FALSE);
+ frp2 == frp_close->fr_next, false);
*dirp = 'h';
}
@@ -2848,8 +2940,9 @@ winframe_remove (
frp->fr_parent = frp2->fr_parent;
}
frp2->fr_parent->fr_win = frp2->fr_win;
- if (frp2->fr_win != NULL)
+ if (frp2->fr_win != NULL) {
frp2->fr_win->w_frame = frp2->fr_parent;
+ }
frp = frp2->fr_parent;
if (topframe->fr_child == frp2) {
topframe->fr_child = frp;
@@ -2860,18 +2953,21 @@ winframe_remove (
if (frp2 != NULL && frp2->fr_layout == frp->fr_layout) {
/* The frame above the parent has the same layout, have to merge
* the frames into this list. */
- if (frp2->fr_child == frp)
+ if (frp2->fr_child == frp) {
frp2->fr_child = frp->fr_child;
+ }
assert(frp->fr_child);
frp->fr_child->fr_prev = frp->fr_prev;
- if (frp->fr_prev != NULL)
+ if (frp->fr_prev != NULL) {
frp->fr_prev->fr_next = frp->fr_child;
+ }
for (frp3 = frp->fr_child;; frp3 = frp3->fr_next) {
frp3->fr_parent = frp2;
if (frp3->fr_next == NULL) {
frp3->fr_next = frp->fr_next;
- if (frp->fr_next != NULL)
+ if (frp->fr_next != NULL) {
frp->fr_next->fr_prev = frp3;
+ }
break;
}
}
@@ -2885,21 +2981,19 @@ winframe_remove (
return wp;
}
-// Return a pointer to the frame that will receive the empty screen space that
-// is left over after "win" is closed.
-//
-// If 'splitbelow' or 'splitright' is set, the space goes above or to the left
-// by default. Otherwise, the free space goes below or to the right. The
-// result is that opening a window and then immediately closing it will
-// preserve the initial window layout. The 'wfh' and 'wfw' settings are
-// respected when possible.
-static frame_T *
-win_altframe (
- win_T *win,
- tabpage_T *tp /* tab page "win" is in, NULL for current */
-)
-{
- frame_T *frp;
+/// If 'splitbelow' or 'splitright' is set, the space goes above or to the left
+/// by default. Otherwise, the free space goes below or to the right. The
+/// result is that opening a window and then immediately closing it will
+/// preserve the initial window layout. The 'wfh' and 'wfw' settings are
+/// respected when possible.
+///
+/// @param tp tab page "win" is in, NULL for current
+///
+/// @return a pointer to the frame that will receive the empty screen space that
+/// is left over after "win" is closed.
+static frame_T *win_altframe(win_T *win, tabpage_T *tp)
+{
+ frame_T *frp;
if (tp == NULL ? ONE_WINDOW : tp->tp_firstwin == tp->tp_lastwin) {
return alt_tabpage()->tp_curwin->w_frame;
@@ -2941,15 +3035,17 @@ win_altframe (
*/
static tabpage_T *alt_tabpage(void)
{
- tabpage_T *tp;
+ tabpage_T *tp;
- /* Use the next tab page if possible. */
- if (curtab->tp_next != NULL)
+ // Use the next tab page if possible.
+ if (curtab->tp_next != NULL) {
return curtab->tp_next;
+ }
- /* Find the last but one tab page. */
- for (tp = first_tabpage; tp->tp_next != curtab; tp = tp->tp_next)
+ // Find the last but one tab page.
+ for (tp = first_tabpage; tp->tp_next != curtab; tp = tp->tp_next) {
;
+ }
return tp;
}
@@ -2958,8 +3054,9 @@ static tabpage_T *alt_tabpage(void)
*/
static win_T *frame2win(frame_T *frp)
{
- while (frp->fr_win == NULL)
+ while (frp->fr_win == NULL) {
frp = frp->fr_child;
+ }
return frp->fr_win;
}
@@ -2982,21 +3079,16 @@ static bool frame_has_win(const frame_T *frp, const win_T *wp)
return false;
}
-/*
- * Set a new height for a frame. Recursively sets the height for contained
- * frames and windows. Caller must take care of positions.
- */
-static void
-frame_new_height (
- frame_T *topfrp,
- int height,
- int topfirst, /* resize topmost contained frame first */
- int wfh /* obey 'winfixheight' when there is a choice;
- may cause the height not to be set */
-)
+/// Set a new height for a frame. Recursively sets the height for contained
+/// frames and windows. Caller must take care of positions.
+///
+/// @param topfirst resize topmost contained frame first.
+/// @param wfh obey 'winfixheight' when there is a choice;
+/// may cause the height not to be set.
+static void frame_new_height(frame_T *topfrp, int height, bool topfirst, bool wfh)
FUNC_ATTR_NONNULL_ALL
{
- frame_T *frp;
+ frame_T *frp;
int extra_lines;
int h;
@@ -3010,37 +3102,42 @@ frame_new_height (
FOR_ALL_FRAMES(frp, topfrp->fr_child) {
frame_new_height(frp, height, topfirst, wfh);
if (frp->fr_height > height) {
- /* Could not fit the windows, make the whole row higher. */
+ // Could not fit the windows, make the whole row higher.
height = frp->fr_height;
break;
}
}
} while (frp != NULL);
- } else { /* fr_layout == FR_COL */
+ } else { // fr_layout == FR_COL
/* Complicated case: Resize a column of frames. Resize the bottom
* frame first, frames above that when needed. */
frp = topfrp->fr_child;
- if (wfh)
- /* Advance past frames with one window with 'wfh' set. */
+ if (wfh) {
+ // Advance past frames with one window with 'wfh' set.
while (frame_fixed_height(frp)) {
frp = frp->fr_next;
- if (frp == NULL)
- return; /* no frame without 'wfh', give up */
+ if (frp == NULL) {
+ return; // no frame without 'wfh', give up
+ }
}
+ }
if (!topfirst) {
- /* Find the bottom frame of this column */
- while (frp->fr_next != NULL)
+ // Find the bottom frame of this column
+ while (frp->fr_next != NULL) {
frp = frp->fr_next;
- if (wfh)
- /* Advance back for frames with one window with 'wfh' set. */
- while (frame_fixed_height(frp))
+ }
+ if (wfh) {
+ // Advance back for frames with one window with 'wfh' set.
+ while (frame_fixed_height(frp)) {
frp = frp->fr_prev;
+ }
+ }
}
extra_lines = height - topfrp->fr_height;
if (extra_lines < 0) {
- /* reduce height of contained frames, bottom or top frame first */
+ // reduce height of contained frames, bottom or top frame first
while (frp != NULL) {
h = frame_minheight(frp, NULL);
if (frp->fr_height + extra_lines < h) {
@@ -3048,7 +3145,7 @@ frame_new_height (
frame_new_height(frp, h, topfirst, wfh);
} else {
frame_new_height(frp, frp->fr_height + extra_lines,
- topfirst, wfh);
+ topfirst, wfh);
break;
}
if (topfirst) {
@@ -3060,12 +3157,13 @@ frame_new_height (
frp = frp->fr_prev;
while (wfh && frp != NULL && frame_fixed_height(frp));
}
- /* Increase "height" if we could not reduce enough frames. */
- if (frp == NULL)
+ // Increase "height" if we could not reduce enough frames.
+ if (frp == NULL) {
height -= extra_lines;
+ }
}
} else if (extra_lines > 0) {
- /* increase height of bottom or top frame */
+ // increase height of bottom or top frame
frame_new_height(frp, frp->fr_height + extra_lines, topfirst, wfh);
}
}
@@ -3146,13 +3244,14 @@ static bool frame_fixed_width(frame_T *frp)
*/
static void frame_add_statusline(frame_T *frp)
{
- win_T *wp;
+ win_T *wp;
if (frp->fr_layout == FR_LEAF) {
wp = frp->fr_win;
if (wp->w_status_height == 0) {
- if (wp->w_height > 0) /* don't make it negative */
+ if (wp->w_height > 0) { // don't make it negative
--wp->w_height;
+ }
wp->w_status_height = STATUS_HEIGHT;
}
} else if (frp->fr_layout == FR_ROW) {
@@ -3169,33 +3268,31 @@ static void frame_add_statusline(frame_T *frp)
}
}
-/*
- * Set width of a frame. Handles recursively going through contained frames.
- * May remove separator line for windows at the right side (for win_close()).
- */
-static void
-frame_new_width (
- frame_T *topfrp,
- int width,
- int leftfirst, /* resize leftmost contained frame first */
- int wfw /* obey 'winfixwidth' when there is a choice;
- may cause the width not to be set */
-)
-{
- frame_T *frp;
+/// Set width of a frame. Handles recursively going through contained frames.
+/// May remove separator line for windows at the right side (for win_close()).
+///
+/// @param leftfirst resize leftmost contained frame first.
+/// @param wfw obey 'winfixwidth' when there is a choice;
+/// may cause the width not to be set.
+static void frame_new_width(frame_T *topfrp, int width, bool leftfirst, bool wfw)
+{
+ frame_T *frp;
int extra_cols;
int w;
- win_T *wp;
+ win_T *wp;
if (topfrp->fr_layout == FR_LEAF) {
- /* Simple case: just one window. */
+ // Simple case: just one window.
wp = topfrp->fr_win;
- /* Find out if there are any windows right of this one. */
- for (frp = topfrp; frp->fr_parent != NULL; frp = frp->fr_parent)
- if (frp->fr_parent->fr_layout == FR_ROW && frp->fr_next != NULL)
+ // Find out if there are any windows right of this one.
+ for (frp = topfrp; frp->fr_parent != NULL; frp = frp->fr_parent) {
+ if (frp->fr_parent->fr_layout == FR_ROW && frp->fr_next != NULL) {
break;
- if (frp->fr_parent == NULL)
+ }
+ }
+ if (frp->fr_parent == NULL) {
wp->w_vsep_width = 0;
+ }
win_new_width(wp, width - wp->w_vsep_width);
} else if (topfrp->fr_layout == FR_COL) {
do {
@@ -3203,37 +3300,42 @@ frame_new_width (
FOR_ALL_FRAMES(frp, topfrp->fr_child) {
frame_new_width(frp, width, leftfirst, wfw);
if (frp->fr_width > width) {
- /* Could not fit the windows, make whole column wider. */
+ // Could not fit the windows, make whole column wider.
width = frp->fr_width;
break;
}
}
} while (frp != NULL);
- } else { /* fr_layout == FR_ROW */
+ } else { // fr_layout == FR_ROW
/* Complicated case: Resize a row of frames. Resize the rightmost
* frame first, frames left of it when needed. */
frp = topfrp->fr_child;
- if (wfw)
- /* Advance past frames with one window with 'wfw' set. */
+ if (wfw) {
+ // Advance past frames with one window with 'wfw' set.
while (frame_fixed_width(frp)) {
frp = frp->fr_next;
- if (frp == NULL)
- return; /* no frame without 'wfw', give up */
+ if (frp == NULL) {
+ return; // no frame without 'wfw', give up
+ }
}
+ }
if (!leftfirst) {
- /* Find the rightmost frame of this row */
- while (frp->fr_next != NULL)
+ // Find the rightmost frame of this row
+ while (frp->fr_next != NULL) {
frp = frp->fr_next;
- if (wfw)
- /* Advance back for frames with one window with 'wfw' set. */
- while (frame_fixed_width(frp))
+ }
+ if (wfw) {
+ // Advance back for frames with one window with 'wfw' set.
+ while (frame_fixed_width(frp)) {
frp = frp->fr_prev;
+ }
+ }
}
extra_cols = width - topfrp->fr_width;
if (extra_cols < 0) {
- /* reduce frame width, rightmost frame first */
+ // reduce frame width, rightmost frame first
while (frp != NULL) {
w = frame_minwidth(frp, NULL);
if (frp->fr_width + extra_cols < w) {
@@ -3241,7 +3343,7 @@ frame_new_width (
frame_new_width(frp, w, leftfirst, wfw);
} else {
frame_new_width(frp, frp->fr_width + extra_cols,
- leftfirst, wfw);
+ leftfirst, wfw);
break;
}
if (leftfirst) {
@@ -3253,12 +3355,13 @@ frame_new_width (
frp = frp->fr_prev;
while (wfw && frp != NULL && frame_fixed_width(frp));
}
- /* Increase "width" if we could not reduce enough frames. */
- if (frp == NULL)
+ // Increase "width" if we could not reduce enough frames.
+ if (frp == NULL) {
width -= extra_cols;
+ }
}
} else if (extra_cols > 0) {
- /* increase width of rightmost frame */
+ // increase width of rightmost frame
frame_new_width(frp, frp->fr_width + extra_cols, leftfirst, wfw);
}
}
@@ -3272,13 +3375,14 @@ frame_new_width (
static void frame_add_vsep(const frame_T *frp)
FUNC_ATTR_NONNULL_ARG(1)
{
- win_T *wp;
+ win_T *wp;
if (frp->fr_layout == FR_LEAF) {
wp = frp->fr_win;
if (wp->w_vsep_width == 0) {
- if (wp->w_width > 0) /* don't make it negative */
+ if (wp->w_width > 0) { // don't make it negative
--wp->w_width;
+ }
wp->w_vsep_width = 1;
}
} else if (frp->fr_layout == FR_COL) {
@@ -3290,8 +3394,9 @@ static void frame_add_vsep(const frame_T *frp)
assert(frp->fr_layout == FR_ROW);
// Only need to handle the last frame in the row.
frp = frp->fr_child;
- while (frp->fr_next != NULL)
+ while (frp->fr_next != NULL) {
frp = frp->fr_next;
+ }
frame_add_vsep(frp);
}
}
@@ -3322,7 +3427,7 @@ static void frame_fix_height(win_T *wp)
*/
static int frame_minheight(frame_T *topfrp, win_T *next_curwin)
{
- frame_T *frp;
+ frame_T *frp;
int m;
int n;
@@ -3340,15 +3445,16 @@ static int frame_minheight(frame_T *topfrp, win_T *next_curwin)
}
}
} else if (topfrp->fr_layout == FR_ROW) {
- /* get the minimal height from each frame in this row */
+ // get the minimal height from each frame in this row
m = 0;
FOR_ALL_FRAMES(frp, topfrp->fr_child) {
n = frame_minheight(frp, next_curwin);
- if (n > m)
+ if (n > m) {
m = n;
+ }
}
} else {
- /* Add up the minimal heights for all frames in this column. */
+ // Add up the minimal heights for all frames in this column.
m = 0;
FOR_ALL_FRAMES(frp, topfrp->fr_child) {
m += frame_minheight(frp, next_curwin);
@@ -3358,41 +3464,39 @@ static int frame_minheight(frame_T *topfrp, win_T *next_curwin)
return m;
}
-/*
- * Compute the minimal width for frame "topfrp".
- * When "next_curwin" isn't NULL, use p_wiw for this window.
- * When "next_curwin" is NOWIN, don't use at least one column for the current
- * window.
- */
-static int
-frame_minwidth (
- frame_T *topfrp,
- win_T *next_curwin /* use p_wh and p_wiw for next_curwin */
-)
+/// Compute the minimal width for frame "topfrp".
+/// When "next_curwin" isn't NULL, use p_wiw for this window.
+/// When "next_curwin" is NOWIN, don't use at least one column for the current
+/// window.
+///
+/// @param next_curwin use p_wh and p_wiw for next_curwin
+static int frame_minwidth(frame_T *topfrp, win_T *next_curwin)
{
- frame_T *frp;
+ frame_T *frp;
int m, n;
if (topfrp->fr_win != NULL) {
- if (topfrp->fr_win == next_curwin)
+ if (topfrp->fr_win == next_curwin) {
m = p_wiw + topfrp->fr_win->w_vsep_width;
- else {
- /* window: minimal width of the window plus separator column */
+ } else {
+ // window: minimal width of the window plus separator column
m = p_wmw + topfrp->fr_win->w_vsep_width;
- /* Current window is minimal one column wide */
- if (p_wmw == 0 && topfrp->fr_win == curwin && next_curwin == NULL)
+ // Current window is minimal one column wide
+ if (p_wmw == 0 && topfrp->fr_win == curwin && next_curwin == NULL) {
++m;
+ }
}
} else if (topfrp->fr_layout == FR_COL) {
- /* get the minimal width from each frame in this column */
+ // get the minimal width from each frame in this column
m = 0;
FOR_ALL_FRAMES(frp, topfrp->fr_child) {
n = frame_minwidth(frp, next_curwin);
- if (n > m)
+ if (n > m) {
m = n;
+ }
}
} else {
- /* Add up the minimal widths for all frames in this row. */
+ // Add up the minimal widths for all frames in this row.
m = 0;
FOR_ALL_FRAMES(frp, topfrp->fr_child) {
m += frame_minwidth(frp, next_curwin);
@@ -3403,21 +3507,17 @@ frame_minwidth (
}
-/*
- * 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.
- *
- * Used by ":bdel" and ":only".
- */
-void
-close_others (
- int message,
- int forceit /* always hide all other windows */
-)
-{
- win_T *wp;
- win_T *nextwp;
+/// 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.
+///
+/// Used by ":bdel" and ":only".
+///
+/// @param forceit always hide all other windows
+void close_others(int message, int forceit)
+{
+ win_T *wp;
+ win_T *nextwp;
int r;
if (curwin->w_floating) {
@@ -3429,23 +3529,22 @@ close_others (
if (one_window() && !lastwin->w_floating) {
if (message
- && !autocmd_busy
- ) {
+ && !autocmd_busy) {
MSG(_(m_onlyone));
}
return;
}
- /* Be very careful here: autocommands may change the window layout. */
+ // Be very careful here: autocommands may change the window layout.
for (wp = firstwin; win_valid(wp); wp = nextwp) {
nextwp = wp->w_next;
- if (wp == curwin) { /* don't close current window */
+ if (wp == curwin) { // don't close current window
continue;
}
- /* Check if it's allowed to abandon this window */
+ // Check if it's allowed to abandon this window
r = can_abandon(wp->w_buffer, forceit);
- if (!win_valid(wp)) { /* autocommands messed wp up */
+ if (!win_valid(wp)) { // autocommands messed wp up
nextwp = firstwin;
continue;
}
@@ -3457,14 +3556,16 @@ close_others (
continue;
}
}
- if (bufIsChanged(wp->w_buffer))
+ if (bufIsChanged(wp->w_buffer)) {
continue;
+ }
}
win_close(wp, !buf_hide(wp->w_buffer) && !bufIsChanged(wp->w_buffer));
}
- if (message && !ONE_WINDOW)
+ if (message && !ONE_WINDOW) {
EMSG(_("E445: Other window contains changes"));
+ }
}
@@ -3484,7 +3585,7 @@ void win_init_empty(win_T *wp)
wp->w_cursor.lnum = 1;
wp->w_curswant = wp->w_cursor.col = 0;
wp->w_cursor.coladd = 0;
- wp->w_pcmark.lnum = 1; /* pcmark not cleared but set to line 1 */
+ wp->w_pcmark.lnum = 1; // pcmark not cleared but set to line 1
wp->w_pcmark.col = 0;
wp->w_prev_pcmark.lnum = 0;
wp->w_prev_pcmark.col = 0;
@@ -3502,8 +3603,9 @@ void win_init_empty(win_T *wp)
*/
int win_alloc_first(void)
{
- if (win_alloc_firstwin(NULL) == FAIL)
+ if (win_alloc_firstwin(NULL) == FAIL) {
return FAIL;
+ }
first_tabpage = alloc_tabpage();
first_tabpage->tp_topframe = topframe;
@@ -3537,7 +3639,7 @@ void win_alloc_aucmd_win(void)
*/
static int win_alloc_firstwin(win_T *oldwin)
{
- curwin = win_alloc(NULL, FALSE);
+ curwin = win_alloc(NULL, false);
if (oldwin == NULL) {
/* Very first window, need to create an empty buffer for it and
* initialize from scratch. */
@@ -3547,14 +3649,14 @@ static int win_alloc_firstwin(win_T *oldwin)
}
curwin->w_buffer = curbuf;
curwin->w_s = &(curbuf->b_s);
- curbuf->b_nwindows = 1; /* there is one window */
+ curbuf->b_nwindows = 1; // there is one window
curwin->w_alist = &global_alist;
- curwin_init(); /* init current window */
+ curwin_init(); // init current window
} else {
- /* First window in new tab page, initialize it from "oldwin". */
+ // First window in new tab page, initialize it from "oldwin".
win_init(curwin, oldwin, 0);
- /* We don't want cursor- and scroll-binding in the first window. */
+ // We don't want cursor- and scroll-binding in the first window.
RESET_BINDING(curwin);
}
@@ -3601,7 +3703,7 @@ static tabpage_T *alloc_tabpage(void)
static int last_tp_handle = 0;
tabpage_T *tp = xcalloc(1, sizeof(tabpage_T));
tp->handle = ++last_tp_handle;
- handle_register_tabpage(tp);
+ pmap_put(handle_T)(&tabpage_handles, tp->handle, tp);
// Init t: variables.
tp->tp_vars = tv_dict_alloc();
@@ -3616,11 +3718,12 @@ void free_tabpage(tabpage_T *tp)
{
int idx;
- handle_unregister_tabpage(tp);
+ pmap_del(handle_T)(&tabpage_handles, tp->handle);
diff_clear(tp);
- for (idx = 0; idx < SNAP_COUNT; ++idx)
+ for (idx = 0; idx < SNAP_COUNT; ++idx) {
clear_snapshot(tp, idx);
- vars_clear(&tp->tp_vars->dv_hashtab); /* free all t: variables */
+ }
+ vars_clear(&tp->tp_vars->dv_hashtab); // free all t: variables
hash_init(&tp->tp_vars->dv_hashtab);
unref_var_dict(tp->tp_vars);
@@ -3642,8 +3745,8 @@ void free_tabpage(tabpage_T *tp)
/// @return Was the new tabpage created successfully? FAIL or OK.
int win_new_tabpage(int after, char_u *filename)
{
- tabpage_T *old_curtab = curtab;
- tabpage_T *newtp;
+ tabpage_T *old_curtab = curtab;
+ tabpage_T *newtp;
int n;
newtp = alloc_tabpage();
@@ -3667,14 +3770,15 @@ int win_new_tabpage(int after, char_u *filename)
newtp->tp_next = first_tabpage;
first_tabpage = newtp;
} else {
- tabpage_T *tp = old_curtab;
+ tabpage_T *tp = old_curtab;
if (after > 0) {
// Put new tab page before tab page "after".
n = 2;
for (tp = first_tabpage; tp->tp_next != NULL
- && n < after; tp = tp->tp_next)
+ && n < after; tp = tp->tp_next) {
++n;
+ }
}
newtp->tp_next = tp->tp_next;
tp->tp_next = newtp;
@@ -3717,7 +3821,7 @@ int may_open_tabpage(void)
int n = (cmdmod.tab == 0) ? postponed_split_tab : cmdmod.tab;
if (n != 0) {
- cmdmod.tab = 0; /* reset it to avoid doing it twice */
+ cmdmod.tab = 0; // reset it to avoid doing it twice
postponed_split_tab = 0;
return win_new_tabpage(n, NULL);
}
@@ -3733,9 +3837,10 @@ int make_tabpages(int maxcount)
int count = maxcount;
int todo;
- /* Limit to 'tabpagemax' tabs. */
- if (count > p_tpm)
+ // Limit to 'tabpagemax' tabs.
+ if (count > p_tpm) {
count = p_tpm;
+ }
/*
* Don't execute autocommands while creating the tab pages. Must do that
@@ -3751,7 +3856,7 @@ int make_tabpages(int maxcount)
unblock_autocmds();
- /* return actual number of tab pages */
+ // return actual number of tab pages
return count - todo;
}
@@ -3812,11 +3917,12 @@ void close_tabpage(tabpage_T *tab)
*/
tabpage_T *find_tabpage(int n)
{
- tabpage_T *tp;
+ tabpage_T *tp;
int i = 1;
- for (tp = first_tabpage; tp != NULL && i != n; tp = tp->tp_next)
+ for (tp = first_tabpage; tp != NULL && i != n; tp = tp->tp_next) {
++i;
+ }
return tp;
}
@@ -3827,41 +3933,42 @@ tabpage_T *find_tabpage(int n)
int tabpage_index(tabpage_T *ftp)
{
int i = 1;
- tabpage_T *tp;
+ tabpage_T *tp;
- for (tp = first_tabpage; tp != NULL && tp != ftp; tp = tp->tp_next)
+ for (tp = first_tabpage; tp != NULL && tp != ftp; tp = tp->tp_next) {
++i;
+ }
return i;
}
-/*
- * Prepare for leaving the current tab page.
- * When autocommands change "curtab" we don't leave the tab page and return
- * FAIL.
- * Careful: When OK is returned need to get a new tab page very very soon!
- */
-static int
-leave_tabpage (
- buf_T *new_curbuf, /* what is going to be the new curbuf,
- NULL if unknown */
- int trigger_leave_autocmds
-)
+/// Prepare for leaving the current tab page.
+/// When autocommands change "curtab" we don't leave the tab page and return
+/// FAIL.
+/// Careful: When OK is returned need to get a new tab page very very soon!
+///
+/// @param new_curbuf what is going to be the new curbuf,
+/// NULL if unknown.
+/// @param trigger_leave_autocmds when true trigger *Leave autocommands.
+static int leave_tabpage(buf_T *new_curbuf, bool trigger_leave_autocmds)
{
- tabpage_T *tp = curtab;
+ tabpage_T *tp = curtab;
- reset_VIsual_and_resel(); /* stop Visual mode */
+ reset_VIsual_and_resel(); // stop Visual mode
if (trigger_leave_autocmds) {
if (new_curbuf != curbuf) {
- apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
- if (curtab != tp)
+ apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, false, curbuf);
+ if (curtab != tp) {
return FAIL;
+ }
}
- apply_autocmds(EVENT_WINLEAVE, NULL, NULL, FALSE, curbuf);
- if (curtab != tp)
+ apply_autocmds(EVENT_WINLEAVE, NULL, NULL, false, curbuf);
+ if (curtab != tp) {
return FAIL;
- apply_autocmds(EVENT_TABLEAVE, NULL, NULL, FALSE, curbuf);
- if (curtab != tp)
+ }
+ apply_autocmds(EVENT_TABLEAVE, NULL, NULL, false, curbuf);
+ if (curtab != tp) {
return FAIL;
+ }
}
tp->tp_curwin = curwin;
tp->tp_prevwin = prevwin;
@@ -3874,16 +3981,16 @@ leave_tabpage (
return OK;
}
-/*
- * Start using tab page "tp".
- * Only to be used after leave_tabpage() or freeing the current tab page.
- * Only trigger *Enter autocommands when trigger_enter_autocmds is TRUE.
- * Only trigger *Leave autocommands when trigger_leave_autocmds is TRUE.
- */
-static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, int trigger_enter_autocmds, int trigger_leave_autocmds)
+/// Start using tab page "tp".
+/// Only to be used after leave_tabpage() or freeing the current tab page.
+///
+/// @param trigger_enter_autocmds when true trigger *Enter autocommands.
+/// @param trigger_leave_autocmds when true trigger *Leave autocommands.
+static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, bool trigger_enter_autocmds,
+ bool trigger_leave_autocmds)
{
int old_off = tp->tp_firstwin->w_winrow;
- win_T *next_prevwin = tp->tp_prevwin;
+ win_T *next_prevwin = tp->tp_prevwin;
tabpage_T *old_curtab = curtab;
curtab = tp;
@@ -3892,14 +3999,15 @@ static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, int trigger_enter_au
topframe = tp->tp_topframe;
if (old_curtab != curtab) {
- tabpage_check_windows(old_curtab);
+ tabpage_check_windows(old_curtab);
}
- /* We would like doing the TabEnter event first, but we don't have a
- * valid current window yet, which may break some commands.
- * This triggers autocommands, thus may make "tp" invalid. */
- win_enter_ext(tp->tp_curwin, false, true, false,
- trigger_enter_autocmds, trigger_leave_autocmds);
+ // We would like doing the TabEnter event first, but we don't have a
+ // valid current window yet, which may break some commands.
+ // This triggers autocommands, thus may make "tp" invalid.
+ win_enter_ext(tp->tp_curwin, WEE_CURWIN_INVALID
+ | (trigger_enter_autocmds ? WEE_TRIGGER_ENTER_AUTOCMDS : 0)
+ | (trigger_leave_autocmds ? WEE_TRIGGER_LEAVE_AUTOCMDS : 0));
prevwin = next_prevwin;
last_status(false); // status line may appear or disappear
@@ -3934,9 +4042,10 @@ static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, int trigger_enter_au
/* Apply autocommands after updating the display, when 'rows' and
* 'columns' have been set correctly. */
if (trigger_enter_autocmds) {
- apply_autocmds(EVENT_TABENTER, NULL, NULL, FALSE, curbuf);
- if (old_curbuf != curbuf)
- apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
+ apply_autocmds(EVENT_TABENTER, NULL, NULL, false, curbuf);
+ if (old_curbuf != curbuf) {
+ apply_autocmds(EVENT_BUFENTER, NULL, NULL, false, curbuf);
+ }
}
redraw_all_later(NOT_VALID);
@@ -3977,8 +4086,8 @@ static void tabpage_check_windows(tabpage_T *old_curtab)
*/
void goto_tabpage(int n)
{
- tabpage_T *tp = NULL; // shut up compiler
- tabpage_T *ttp;
+ tabpage_T *tp = NULL; // shut up compiler
+ tabpage_T *ttp;
int i;
if (text_locked()) {
@@ -3987,35 +4096,39 @@ void goto_tabpage(int n)
return;
}
- /* If there is only one it can't work. */
+ // If there is only one it can't work.
if (first_tabpage->tp_next == NULL) {
- if (n > 1)
+ if (n > 1) {
beep_flush();
+ }
return;
}
if (n == 0) {
- /* No count, go to next tab page, wrap around end. */
- if (curtab->tp_next == NULL)
+ // No count, go to next tab page, wrap around end.
+ if (curtab->tp_next == NULL) {
tp = first_tabpage;
- else
+ } else {
tp = curtab->tp_next;
+ }
} else if (n < 0) {
/* "gT": go to previous tab page, wrap around end. "N gT" repeats
* this N times. */
ttp = curtab;
for (i = n; i < 0; ++i) {
for (tp = first_tabpage; tp->tp_next != ttp && tp->tp_next != NULL;
- tp = tp->tp_next)
+ tp = tp->tp_next) {
;
+ }
ttp = tp;
}
} else if (n == 9999) {
- /* Go to last tab page. */
- for (tp = first_tabpage; tp->tp_next != NULL; tp = tp->tp_next)
+ // Go to last tab page.
+ for (tp = first_tabpage; tp->tp_next != NULL; tp = tp->tp_next) {
;
+ }
} else {
- /* Go to tab page "n". */
+ // Go to tab page "n".
tp = find_tabpage(n);
if (tp == NULL) {
beep_flush();
@@ -4023,29 +4136,28 @@ void goto_tabpage(int n)
}
}
- goto_tabpage_tp(tp, TRUE, TRUE);
-
+ goto_tabpage_tp(tp, true, true);
}
-/*
- * Go to tabpage "tp".
- * Only trigger *Enter autocommands when trigger_enter_autocmds is TRUE.
- * Only trigger *Leave autocommands when trigger_leave_autocmds is TRUE.
- * Note: doesn't update the GUI tab.
- */
-void goto_tabpage_tp(tabpage_T *tp, int trigger_enter_autocmds, int trigger_leave_autocmds)
+/// Go to tabpage "tp".
+/// Note: doesn't update the GUI tab.
+///
+/// @param trigger_enter_autocmds when true trigger *Enter autocommands.
+/// @param trigger_leave_autocmds when true trigger *Leave autocommands.
+void goto_tabpage_tp(tabpage_T *tp, bool trigger_enter_autocmds, bool trigger_leave_autocmds)
{
- /* Don't repeat a message in another tab page. */
+ // Don't repeat a message in another tab page.
set_keep_msg(NULL, 0);
if (tp != curtab && leave_tabpage(tp->tp_curwin->w_buffer,
- trigger_leave_autocmds) == OK) {
- if (valid_tabpage(tp))
+ trigger_leave_autocmds) == OK) {
+ if (valid_tabpage(tp)) {
enter_tabpage(tp, curbuf, trigger_enter_autocmds,
- trigger_leave_autocmds);
- else
+ trigger_leave_autocmds);
+ } else {
enter_tabpage(curtab, curbuf, trigger_enter_autocmds,
- trigger_leave_autocmds);
+ trigger_leave_autocmds);
+ }
}
}
@@ -4064,7 +4176,7 @@ void goto_tabpage_lastused(void)
*/
void goto_tabpage_win(tabpage_T *tp, win_T *wp)
{
- goto_tabpage_tp(tp, TRUE, TRUE);
+ goto_tabpage_tp(tp, true, true);
if (curtab == tp && win_valid(wp)) {
win_enter(wp, true);
}
@@ -4120,8 +4232,8 @@ void tabpage_move(int nr)
tp_dst->tp_next = curtab;
}
- /* Need to redraw the tabline. Tab page contents doesn't change. */
- redraw_tabline = TRUE;
+ // Need to redraw the tabline. Tab page contents doesn't change.
+ redraw_tabline = true;
}
@@ -4134,20 +4246,22 @@ void tabpage_move(int nr)
*/
void win_goto(win_T *wp)
{
- win_T *owp = curwin;
+ win_T *owp = curwin;
if (text_locked()) {
beep_flush();
text_locked_msg();
return;
}
- if (curbuf_locked())
+ if (curbuf_locked()) {
return;
+ }
- if (wp->w_buffer != curbuf)
+ if (wp->w_buffer != curbuf) {
reset_VIsual_and_resel();
- else if (VIsual_active)
+ } else if (VIsual_active) {
wp->w_cursor = curwin->w_cursor;
+ }
win_enter(wp, true);
@@ -4185,9 +4299,9 @@ tabpage_T *win_find_tabpage(win_T *win)
/// @return found window
win_T *win_vert_neighbor(tabpage_T *tp, win_T *wp, bool up, long count)
{
- frame_T *fr;
- frame_T *nfr;
- frame_T *foundfr;
+ frame_T *fr;
+ frame_T *nfr;
+ frame_T *foundfr;
foundfr = wp->w_frame;
@@ -4233,9 +4347,11 @@ win_T *win_vert_neighbor(tabpage_T *tp, win_T *wp, bool up, long count)
fr = fr->fr_next;
}
}
- if (nfr->fr_layout == FR_COL && up)
- while (fr->fr_next != NULL)
+ if (nfr->fr_layout == FR_COL && up) {
+ while (fr->fr_next != NULL) {
fr = fr->fr_next;
+ }
+ }
nfr = fr;
}
}
@@ -4266,9 +4382,9 @@ static void win_goto_ver(bool up, long count)
/// @return found window
win_T *win_horz_neighbor(tabpage_T *tp, win_T *wp, bool left, long count)
{
- frame_T *fr;
- frame_T *nfr;
- frame_T *foundfr;
+ frame_T *fr;
+ frame_T *nfr;
+ frame_T *foundfr;
foundfr = wp->w_frame;
@@ -4307,15 +4423,18 @@ win_T *win_horz_neighbor(tabpage_T *tp, win_T *wp, bool left, long count)
}
fr = nfr->fr_child;
if (nfr->fr_layout == FR_COL) {
- /* Find the frame at the cursor row. */
+ // Find the frame at the cursor row.
while (fr->fr_next != NULL
&& frame2win(fr)->w_winrow + fr->fr_height
- <= wp->w_winrow + wp->w_wrow)
+ <= wp->w_winrow + wp->w_wrow) {
fr = fr->fr_next;
+ }
}
- if (nfr->fr_layout == FR_ROW && left)
- while (fr->fr_next != NULL)
+ if (nfr->fr_layout == FR_ROW && left) {
+ while (fr->fr_next != NULL) {
fr = fr->fr_next;
+ }
+ }
nfr = fr;
}
}
@@ -4341,44 +4460,45 @@ static void win_goto_hor(bool left, long count)
/// win_valid(wp).
void win_enter(win_T *wp, bool undo_sync)
{
- win_enter_ext(wp, undo_sync, false, false, true, true);
+ win_enter_ext(wp, (undo_sync ? WEE_UNDO_SYNC : 0)
+ | WEE_TRIGGER_ENTER_AUTOCMDS | WEE_TRIGGER_LEAVE_AUTOCMDS);
}
-/*
- * Make window wp the current window.
- * Can be called with "curwin_invalid" TRUE, which means that curwin has just
- * been closed and isn't valid.
- */
-static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid,
- int trigger_new_autocmds, int trigger_enter_autocmds,
- int trigger_leave_autocmds)
+/// Make window "wp" the current window.
+///
+/// @param flags if contains WEE_CURWIN_INVALID, it means curwin has just been
+/// closed and isn't valid.
+static void win_enter_ext(win_T *const wp, const int flags)
{
- int other_buffer = FALSE;
+ bool other_buffer = false;
+ const bool curwin_invalid = (flags & WEE_CURWIN_INVALID);
- if (wp == curwin && !curwin_invalid) /* nothing to do */
+ if (wp == curwin && !curwin_invalid) { // nothing to do
return;
+ }
- if (!curwin_invalid && trigger_leave_autocmds) {
- /*
- * Be careful: If autocommands delete the window, return now.
- */
+ if (!curwin_invalid && (flags & WEE_TRIGGER_LEAVE_AUTOCMDS)) {
+ // Be careful: If autocommands delete the window, return now.
if (wp->w_buffer != curbuf) {
- apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf);
- other_buffer = TRUE;
- if (!win_valid(wp))
+ apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, false, curbuf);
+ other_buffer = true;
+ if (!win_valid(wp)) {
return;
+ }
}
- apply_autocmds(EVENT_WINLEAVE, NULL, NULL, FALSE, curbuf);
- if (!win_valid(wp))
+ apply_autocmds(EVENT_WINLEAVE, NULL, NULL, false, curbuf);
+ if (!win_valid(wp)) {
return;
- /* autocmds may abort script processing */
- if (aborting())
+ }
+ // autocmds may abort script processing
+ if (aborting()) {
return;
+ }
}
// sync undo before leaving the current buffer
- if (undo_sync && curbuf != wp->w_buffer) {
- u_sync(FALSE);
+ if ((flags & WEE_UNDO_SYNC) && curbuf != wp->w_buffer) {
+ u_sync(false);
}
// Might need to scroll the old window before switching, e.g., when the
@@ -4390,16 +4510,17 @@ static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid,
buf_copy_options(wp->w_buffer, BCO_ENTER | BCO_NOHELP);
}
if (!curwin_invalid) {
- prevwin = curwin; /* remember for CTRL-W p */
+ prevwin = curwin; // remember for CTRL-W p
curwin->w_redr_status = TRUE;
}
curwin = wp;
curbuf = wp->w_buffer;
check_cursor();
- if (!virtual_active())
+ if (!virtual_active()) {
curwin->w_cursor.coladd = 0;
- changed_line_abv_curs(); /* assume cursor position needs updating */
+ }
+ changed_line_abv_curs(); // assume cursor position needs updating
// New directory is either the local directory of the window, tab or NULL.
char *new_dir = (char *)(curwin->w_localdir
@@ -4437,10 +4558,10 @@ static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid,
shorten_fnames(true);
}
- if (trigger_new_autocmds) {
+ if (flags & WEE_TRIGGER_NEW_AUTOCMDS) {
apply_autocmds(EVENT_WINNEW, NULL, NULL, false, curbuf);
}
- if (trigger_enter_autocmds) {
+ if (flags & WEE_TRIGGER_ENTER_AUTOCMDS) {
apply_autocmds(EVENT_WINENTER, NULL, NULL, false, curbuf);
if (other_buffer) {
apply_autocmds(EVENT_BUFENTER, NULL, NULL, false, curbuf);
@@ -4474,9 +4595,9 @@ static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid,
win_setwidth((int)p_wiw);
}
- setmouse(); /* in case jumped to/from help buffer */
+ setmouse(); // in case jumped to/from help buffer
- /* Change directories when the 'acd' option is set. */
+ // Change directories when the 'acd' option is set.
do_autochdir();
}
@@ -4505,12 +4626,12 @@ win_T *buf_jump_open_win(buf_T *buf)
/// @return the found window, or NULL.
win_T *buf_jump_open_tab(buf_T *buf)
{
-
// First try the current tab page.
{
win_T *wp = buf_jump_open_win(buf);
- if (wp != NULL)
+ if (wp != NULL) {
return wp;
+ }
}
FOR_ALL_TABS(tp) {
@@ -4538,11 +4659,9 @@ win_T *buf_jump_open_tab(buf_T *buf)
return NULL;
}
-/*
- * Allocate a window structure and link it in the window list when "hidden" is
- * FALSE.
- */
-static win_T *win_alloc(win_T *after, int hidden)
+/// @param hidden allocate a window structure and link it in the window if
+// false.
+static win_T *win_alloc(win_T *after, bool hidden)
{
static int last_win_id = LOWEST_WIN_ID - 1;
@@ -4550,7 +4669,7 @@ static win_T *win_alloc(win_T *after, int hidden)
win_T *new_wp = xcalloc(1, sizeof(win_T));
new_wp->handle = ++last_win_id;
- handle_register_window(new_wp);
+ pmap_put(handle_T)(&window_handles, new_wp->handle, new_wp);
grid_assign_handle(&new_wp->w_grid_alloc);
@@ -4565,13 +4684,14 @@ static win_T *win_alloc(win_T *after, int hidden)
/*
* link the window in the window list
*/
- if (!hidden)
+ if (!hidden) {
win_append(after, new_wp);
+ }
new_wp->w_wincol = 0;
new_wp->w_width = Columns;
- /* position the display and the cursor at the top of the file. */
+ // position the display and the cursor at the top of the file.
new_wp->w_topline = 1;
new_wp->w_topfill = 0;
new_wp->w_botline = 2;
@@ -4585,7 +4705,7 @@ static win_T *win_alloc(win_T *after, int hidden)
new_wp->w_p_so = -1;
new_wp->w_p_siso = -1;
- /* We won't calculate w_fraction until resizing the window */
+ // We won't calculate w_fraction until resizing the window
new_wp->w_fraction = 0;
new_wp->w_prev_fraction_row = -1;
@@ -4598,8 +4718,7 @@ static win_T *win_alloc(win_T *after, int hidden)
// Free one wininfo_T.
-void
-free_wininfo(wininfo_T *wip, buf_T *bp)
+void free_wininfo(wininfo_T *wip, buf_T *bp)
{
if (wip->wi_optset) {
clear_winopt(&wip->wi_opt);
@@ -4609,22 +4728,18 @@ free_wininfo(wininfo_T *wip, buf_T *bp)
}
-/*
- * Remove window 'wp' from the window list and free the structure.
- */
-static void
-win_free (
- win_T *wp,
- tabpage_T *tp /* tab page "win" is in, NULL for current */
-)
+/// Remove window 'wp' from the window list and free the structure.
+///
+/// @param tp tab page "win" is in, NULL for current
+static void win_free(win_T *wp, tabpage_T *tp)
{
int i;
- wininfo_T *wip;
+ wininfo_T *wip;
- handle_unregister_window(wp);
+ pmap_del(handle_T)(&window_handles, wp->handle);
clearFolding(wp);
- /* reduce the reference count to the argument list. */
+ // reduce the reference count to the argument list.
alist_unlink(wp->w_alist);
/* Don't execute autocommands while the window is halfway being deleted.
@@ -4634,7 +4749,7 @@ win_free (
clear_winopt(&wp->w_onebuf_opt);
clear_winopt(&wp->w_allbuf_opt);
- vars_clear(&wp->w_vars->dv_hashtab); /* free all w: variables */
+ vars_clear(&wp->w_vars->dv_hashtab); // free all w: variables
hash_init(&wp->w_vars->dv_hashtab);
unref_var_dict(wp->w_vars);
@@ -4665,8 +4780,10 @@ win_free (
// If there already is an entry with "wi_win" set to NULL it
// must be removed, it would never be used.
+ // Skip "wip" itself, otherwise Coverity complains.
for (wip2 = buf->b_wininfo; wip2 != NULL; wip2 = wip2->wi_next) {
- if (wip2->wi_win == NULL) {
+ // `wip2 != wip` to satisfy Coverity. #14884
+ if (wip2 != wip && wip2->wi_win == NULL) {
if (wip2->wi_next != NULL) {
wip2->wi_next->wi_prev = wip2->wi_prev;
}
@@ -4695,8 +4812,9 @@ win_free (
win_free_grid(wp, false);
- if (wp != aucmd_win)
+ if (wp != aucmd_win) {
win_remove(wp, tp);
+ }
if (autocmd_busy) {
wp->w_next = au_pending_free_win;
au_pending_free_win = wp;
@@ -4725,33 +4843,32 @@ void win_free_grid(win_T *wp, bool reinit)
*/
void win_append(win_T *after, win_T *wp)
{
- win_T *before;
+ win_T *before;
- if (after == NULL) /* after NULL is in front of the first */
+ if (after == NULL) { // after NULL is in front of the first
before = firstwin;
- else
+ } else {
before = after->w_next;
+ }
wp->w_next = before;
wp->w_prev = after;
- if (after == NULL)
+ if (after == NULL) {
firstwin = wp;
- else
+ } else {
after->w_next = wp;
- if (before == NULL)
+ }
+ if (before == NULL) {
lastwin = wp;
- else
+ } else {
before->w_prev = wp;
+ }
}
-/*
- * Remove a window from the window list.
- */
-void
-win_remove (
- win_T *wp,
- tabpage_T *tp /* tab page "win" is in, NULL for current */
-)
+/// Remove a window from the window list.
+///
+/// @param tp tab page "win" is in, NULL for current
+void win_remove(win_T *wp, tabpage_T *tp)
{
if (wp->w_prev != NULL) {
wp->w_prev->w_next = wp->w_next;
@@ -4776,8 +4893,9 @@ static void frame_append(frame_T *after, frame_T *frp)
{
frp->fr_next = after->fr_next;
after->fr_next = frp;
- if (frp->fr_next != NULL)
+ if (frp->fr_next != NULL) {
frp->fr_next->fr_prev = frp;
+ }
frp->fr_prev = after;
}
@@ -4789,10 +4907,11 @@ static void frame_insert(frame_T *before, frame_T *frp)
frp->fr_next = before;
frp->fr_prev = before->fr_prev;
before->fr_prev = frp;
- if (frp->fr_prev != NULL)
+ if (frp->fr_prev != NULL) {
frp->fr_prev->fr_next = frp;
- else
+ } else {
frp->fr_parent->fr_child = frp;
+ }
}
/*
@@ -4804,10 +4923,6 @@ static void frame_remove(frame_T *frp)
frp->fr_prev->fr_next = frp->fr_next;
} else {
frp->fr_parent->fr_child = frp->fr_next;
- // special case: topframe->fr_child == frp
- if (topframe->fr_child == frp) {
- topframe->fr_child = frp->fr_next;
- }
}
if (frp->fr_next != NULL) {
frp->fr_next->fr_prev = frp->fr_prev;
@@ -4823,22 +4938,24 @@ void shell_new_rows(void)
{
int h = (int)ROWS_AVAIL;
- if (firstwin == NULL) /* not initialized yet */
+ if (firstwin == NULL) { // not initialized yet
return;
- if (h < frame_minheight(topframe, NULL))
+ }
+ if (h < frame_minheight(topframe, NULL)) {
h = frame_minheight(topframe, NULL);
+ }
/* First try setting the heights of windows with 'winfixheight'. If
* that doesn't result in the right height, forget about that option. */
- frame_new_height(topframe, h, FALSE, TRUE);
- if (!frame_check_height(topframe, h))
- frame_new_height(topframe, h, FALSE, FALSE);
+ frame_new_height(topframe, h, false, true);
+ if (!frame_check_height(topframe, h)) {
+ frame_new_height(topframe, h, false, false);
+ }
(void)win_comp_pos(); // recompute w_winrow and w_wincol
win_reconfig_floats(); // The size of floats might change
compute_cmdrow();
curtab->tp_ch_used = p_ch;
-
}
/*
@@ -4846,8 +4963,9 @@ void shell_new_rows(void)
*/
void shell_new_columns(void)
{
- if (firstwin == NULL) /* not initialized yet */
+ if (firstwin == NULL) { // not initialized yet
return;
+ }
/* First try setting the widths of windows with 'winfixwidth'. If that
* doesn't result in the right width, forget about that option. */
@@ -4920,7 +5038,7 @@ void win_size_restore(garray_T *gap)
}
}
}
- /* recompute the window positions */
+ // recompute the window positions
(void)win_comp_pos();
}
}
@@ -4962,17 +5080,16 @@ void win_reconfig_floats(void)
*/
static void frame_comp_pos(frame_T *topfrp, int *row, int *col)
{
- win_T *wp;
- frame_T *frp;
+ win_T *wp;
+ frame_T *frp;
int startcol;
int startrow;
wp = topfrp->fr_win;
if (wp != NULL) {
if (wp->w_winrow != *row
- || wp->w_wincol != *col
- ) {
- /* position changed, redraw */
+ || wp->w_wincol != *col) {
+ // position changed, redraw
wp->w_winrow = *row;
wp->w_wincol = *col;
redraw_later(wp, NOT_VALID);
@@ -5043,7 +5160,6 @@ void win_setheight_win(int height, win_T *win)
msg_col = 0;
redraw_all_later(NOT_VALID);
}
-
}
@@ -5062,30 +5178,34 @@ void win_setheight_win(int height, win_T *win)
*/
static void frame_setheight(frame_T *curfrp, int height)
{
- int room; /* total number of lines available */
- int take; /* number of lines taken from other windows */
- int room_cmdline; /* lines available from cmdline */
+ int room; // total number of lines available
+ int take; // number of lines taken from other windows
+ int room_cmdline; // lines available from cmdline
int run;
- frame_T *frp;
+ frame_T *frp;
int h;
int room_reserved;
- /* If the height already is the desired value, nothing to do. */
- if (curfrp->fr_height == height)
+ // If the height already is the desired value, nothing to do.
+ if (curfrp->fr_height == height) {
return;
+ }
if (curfrp->fr_parent == NULL) {
- /* topframe: can only change the command line */
- if (height > ROWS_AVAIL)
+ // topframe: can only change the command line
+ if (height > ROWS_AVAIL) {
height = ROWS_AVAIL;
- if (height > 0)
- frame_new_height(curfrp, height, FALSE, FALSE);
+ }
+ if (height > 0) {
+ frame_new_height(curfrp, height, false, false);
+ }
} else if (curfrp->fr_parent->fr_layout == FR_ROW) {
/* Row of frames: Also need to resize frames left and right of this
* one. First check for the minimal height of these. */
h = frame_minheight(curfrp->fr_parent, NULL);
- if (height < h)
+ if (height < h) {
height = h;
+ }
frame_setheight(curfrp->fr_parent, height);
} else {
/*
@@ -5117,7 +5237,7 @@ static void frame_setheight(frame_T *curfrp, int height)
} else {
win_T *wp = lastwin_nofloating();
room_cmdline = Rows - p_ch
- - (wp->w_winrow + wp->w_height + wp->w_status_height);
+ - (wp->w_winrow + wp->w_height + wp->w_status_height);
if (room_cmdline < 0) {
room_cmdline = 0;
}
@@ -5131,8 +5251,8 @@ static void frame_setheight(frame_T *curfrp, int height)
break;
}
frame_setheight(curfrp->fr_parent, height
- + frame_minheight(curfrp->fr_parent, NOWIN) - (int)p_wmh - 1);
- /*NOTREACHED*/
+ + frame_minheight(curfrp->fr_parent, NOWIN) - (int)p_wmh - 1);
+ //NOTREACHED
}
/*
@@ -5143,17 +5263,20 @@ static void frame_setheight(frame_T *curfrp, int height)
/* If there is not enough room, also reduce the height of a window
* with 'winfixheight' set. */
- if (height > room + room_cmdline - room_reserved)
+ if (height > room + room_cmdline - room_reserved) {
room_reserved = room + room_cmdline - height;
+ }
/* If there is only a 'winfixheight' window and making the
* window smaller, need to make the other window taller. */
- if (take < 0 && room - curfrp->fr_height < room_reserved)
+ if (take < 0 && room - curfrp->fr_height < room_reserved) {
room_reserved = 0;
+ }
if (take > 0 && room_cmdline > 0) {
- /* use lines from cmdline first */
- if (take < room_cmdline)
+ // use lines from cmdline first
+ if (take < room_cmdline) {
room_cmdline = take;
+ }
take -= room_cmdline;
topframe->fr_height += room_cmdline;
}
@@ -5161,7 +5284,7 @@ static void frame_setheight(frame_T *curfrp, int height)
/*
* set the current frame to the new height
*/
- frame_new_height(curfrp, height, FALSE, FALSE);
+ frame_new_height(curfrp, height, false, false);
/*
* First take lines from the frames after the current frame. If
@@ -5169,38 +5292,40 @@ static void frame_setheight(frame_T *curfrp, int height)
* frame.
*/
for (run = 0; run < 2; ++run) {
- if (run == 0)
- frp = curfrp->fr_next; /* 1st run: start with next window */
- else
- frp = curfrp->fr_prev; /* 2nd run: start with prev window */
+ if (run == 0) {
+ frp = curfrp->fr_next; // 1st run: start with next window
+ } else {
+ frp = curfrp->fr_prev; // 2nd run: start with prev window
+ }
while (frp != NULL && take != 0) {
h = frame_minheight(frp, NULL);
if (room_reserved > 0
&& frp->fr_win != NULL
&& frp->fr_win->w_p_wfh) {
- if (room_reserved >= frp->fr_height)
+ if (room_reserved >= frp->fr_height) {
room_reserved -= frp->fr_height;
- else {
- if (frp->fr_height - room_reserved > take)
+ } else {
+ if (frp->fr_height - room_reserved > take) {
room_reserved = frp->fr_height - take;
+ }
take -= frp->fr_height - room_reserved;
- frame_new_height(frp, room_reserved, FALSE, FALSE);
+ frame_new_height(frp, room_reserved, false, false);
room_reserved = 0;
}
} else {
if (frp->fr_height - take < h) {
take -= frp->fr_height - h;
- frame_new_height(frp, h, FALSE, FALSE);
+ frame_new_height(frp, h, false, false);
} else {
- frame_new_height(frp, frp->fr_height - take,
- FALSE, FALSE);
+ frame_new_height(frp, frp->fr_height - take, false, false);
take = 0;
}
}
- if (run == 0)
+ if (run == 0) {
frp = frp->fr_next;
- else
+ } else {
frp = frp->fr_prev;
+ }
}
}
}
@@ -5220,10 +5345,12 @@ void win_setwidth_win(int width, win_T *wp)
/* Always keep current window at least one column wide, even when
* 'winminwidth' is zero. */
if (wp == curwin) {
- if (width < p_wmw)
+ if (width < p_wmw) {
width = p_wmw;
- if (width == 0)
+ }
+ if (width == 0) {
width = 1;
+ }
} else if (width < 0) {
width = 0;
}
@@ -5238,7 +5365,6 @@ void win_setwidth_win(int width, win_T *wp)
(void)win_comp_pos();
redraw_all_later(NOT_VALID);
}
-
}
/*
@@ -5250,27 +5376,30 @@ void win_setwidth_win(int width, win_T *wp)
*/
static void frame_setwidth(frame_T *curfrp, int width)
{
- int room; /* total number of lines available */
- int take; /* number of lines taken from other windows */
+ int room; // total number of lines available
+ int take; // number of lines taken from other windows
int run;
- frame_T *frp;
+ frame_T *frp;
int w;
int room_reserved;
- /* If the width already is the desired value, nothing to do. */
- if (curfrp->fr_width == width)
+ // If the width already is the desired value, nothing to do.
+ if (curfrp->fr_width == width) {
return;
+ }
- if (curfrp->fr_parent == NULL)
- /* topframe: can't change width */
+ if (curfrp->fr_parent == NULL) {
+ // topframe: can't change width
return;
+ }
if (curfrp->fr_parent->fr_layout == FR_COL) {
/* Column of frames: Also need to resize frames above and below of
* this one. First check for the minimal width of these. */
w = frame_minwidth(curfrp->fr_parent, NULL);
- if (width < w)
+ if (width < w) {
width = w;
+ }
frame_setwidth(curfrp->fr_parent, width);
} else {
/*
@@ -5296,14 +5425,15 @@ static void frame_setwidth(frame_T *curfrp, int width)
}
}
- if (width <= room)
+ if (width <= room) {
break;
+ }
if (run == 2 || curfrp->fr_height >= ROWS_AVAIL) {
width = room;
break;
}
frame_setwidth(curfrp->fr_parent, width
- + frame_minwidth(curfrp->fr_parent, NOWIN) - (int)p_wmw - 1);
+ + frame_minwidth(curfrp->fr_parent, NOWIN) - (int)p_wmw - 1);
}
/*
@@ -5314,17 +5444,19 @@ static void frame_setwidth(frame_T *curfrp, int width)
/* If there is not enough room, also reduce the width of a window
* with 'winfixwidth' set. */
- if (width > room - room_reserved)
+ if (width > room - room_reserved) {
room_reserved = room - width;
+ }
/* If there is only a 'winfixwidth' window and making the
* window smaller, need to make the other window narrower. */
- if (take < 0 && room - curfrp->fr_width < room_reserved)
+ if (take < 0 && room - curfrp->fr_width < room_reserved) {
room_reserved = 0;
+ }
/*
* set the current frame to the new width
*/
- frame_new_width(curfrp, width, FALSE, FALSE);
+ frame_new_width(curfrp, width, false, false);
/*
* First take lines from the frames right of the current frame. If
@@ -5332,38 +5464,40 @@ static void frame_setwidth(frame_T *curfrp, int width)
* frame.
*/
for (run = 0; run < 2; ++run) {
- if (run == 0)
- frp = curfrp->fr_next; /* 1st run: start with next window */
- else
- frp = curfrp->fr_prev; /* 2nd run: start with prev window */
+ if (run == 0) {
+ frp = curfrp->fr_next; // 1st run: start with next window
+ } else {
+ frp = curfrp->fr_prev; // 2nd run: start with prev window
+ }
while (frp != NULL && take != 0) {
w = frame_minwidth(frp, NULL);
if (room_reserved > 0
&& frp->fr_win != NULL
&& frp->fr_win->w_p_wfw) {
- if (room_reserved >= frp->fr_width)
+ if (room_reserved >= frp->fr_width) {
room_reserved -= frp->fr_width;
- else {
- if (frp->fr_width - room_reserved > take)
+ } else {
+ if (frp->fr_width - room_reserved > take) {
room_reserved = frp->fr_width - take;
+ }
take -= frp->fr_width - room_reserved;
- frame_new_width(frp, room_reserved, FALSE, FALSE);
+ frame_new_width(frp, room_reserved, false, false);
room_reserved = 0;
}
} else {
if (frp->fr_width - take < w) {
take -= frp->fr_width - w;
- frame_new_width(frp, w, FALSE, FALSE);
+ frame_new_width(frp, w, false, false);
} else {
- frame_new_width(frp, frp->fr_width - take,
- FALSE, FALSE);
+ frame_new_width(frp, frp->fr_width - take, false, false);
take = 0;
}
}
- if (run == 0)
+ if (run == 0) {
frp = frp->fr_next;
- else
+ } else {
frp = frp->fr_prev;
+ }
}
}
}
@@ -5409,69 +5543,71 @@ void win_setminwidth(void)
}
}
-/*
- * Status line of dragwin is dragged "offset" lines down (negative is up).
- */
+/// Status line of dragwin is dragged "offset" lines down (negative is up).
void win_drag_status_line(win_T *dragwin, int offset)
{
- frame_T *curfr;
- frame_T *fr;
+ frame_T *curfr;
+ frame_T *fr;
int room;
int row;
- int up; /* if TRUE, drag status line up, otherwise down */
+ bool up; // if true, drag status line up, otherwise down
int n;
fr = dragwin->w_frame;
curfr = fr;
- if (fr != topframe) { /* more than one window */
+ if (fr != topframe) { // more than one window
fr = fr->fr_parent;
/* When the parent frame is not a column of frames, its parent should
* be. */
if (fr->fr_layout != FR_COL) {
curfr = fr;
- if (fr != topframe) /* only a row of windows, may drag statusline */
+ if (fr != topframe) { // only a row of windows, may drag statusline
fr = fr->fr_parent;
+ }
}
}
/* If this is the last frame in a column, may want to resize the parent
* frame instead (go two up to skip a row of frames). */
while (curfr != topframe && curfr->fr_next == NULL) {
- if (fr != topframe)
+ if (fr != topframe) {
fr = fr->fr_parent;
+ }
curfr = fr;
- if (fr != topframe)
+ if (fr != topframe) {
fr = fr->fr_parent;
+ }
}
- if (offset < 0) { /* drag up */
- up = TRUE;
+ if (offset < 0) { // drag up
+ up = true;
offset = -offset;
- /* sum up the room of the current frame and above it */
+ // sum up the room of the current frame and above it
if (fr == curfr) {
- /* only one window */
+ // only one window
room = fr->fr_height - frame_minheight(fr, NULL);
} else {
room = 0;
for (fr = fr->fr_child;; fr = fr->fr_next) {
room += fr->fr_height - frame_minheight(fr, NULL);
- if (fr == curfr)
+ if (fr == curfr) {
break;
+ }
}
}
- fr = curfr->fr_next; /* put fr at frame that grows */
- } else { /* drag down */
- up = FALSE;
- /*
- * Only dragging the last status line can reduce p_ch.
- */
+ fr = curfr->fr_next; // put fr at frame that grows
+ } else { // drag down
+ up = false;
+ // Only dragging the last status line can reduce p_ch.
room = Rows - cmdline_row;
- if (curfr->fr_next == NULL)
+ if (curfr->fr_next == NULL) {
room -= 1;
- else
+ } else {
room -= p_ch;
- if (room < 0)
+ }
+ if (room < 0) {
room = 0;
+ }
// sum up the room of frames below of the current one
FOR_ALL_FRAMES(fr, curfr->fr_next) {
room += fr->fr_height - frame_minheight(fr, NULL);
@@ -5479,23 +5615,26 @@ void win_drag_status_line(win_T *dragwin, int offset)
fr = curfr; // put fr at window that grows
}
- if (room < offset) /* Not enough room */
- offset = room; /* Move as far as we can */
- if (offset <= 0)
+ if (room < offset) { // Not enough room
+ offset = room; // Move as far as we can
+ }
+ if (offset <= 0) {
return;
+ }
/*
* Grow frame fr by "offset" lines.
* Doesn't happen when dragging the last status line up.
*/
- if (fr != NULL)
- frame_new_height(fr, fr->fr_height + offset, up, FALSE);
-
- if (up)
- fr = curfr; /* current frame gets smaller */
- else
- fr = curfr->fr_next; /* next frame gets smaller */
+ if (fr != NULL) {
+ frame_new_height(fr, fr->fr_height + offset, up, false);
+ }
+ if (up) {
+ fr = curfr; // current frame gets smaller
+ } else {
+ fr = curfr->fr_next; // next frame gets smaller
+ }
/*
* Now make the other frames smaller.
*/
@@ -5503,15 +5642,16 @@ void win_drag_status_line(win_T *dragwin, int offset)
n = frame_minheight(fr, NULL);
if (fr->fr_height - offset <= n) {
offset -= fr->fr_height - n;
- frame_new_height(fr, n, !up, FALSE);
+ frame_new_height(fr, n, !up, false);
} else {
- frame_new_height(fr, fr->fr_height - offset, !up, FALSE);
+ frame_new_height(fr, fr->fr_height - offset, !up, false);
break;
}
- if (up)
+ if (up) {
fr = fr->fr_prev;
- else
+ } else {
fr = fr->fr_next;
+ }
}
row = win_comp_pos();
grid_fill(&default_grid, row, cmdline_row, 0, Columns, ' ', ' ', 0);
@@ -5520,8 +5660,9 @@ void win_drag_status_line(win_T *dragwin, int offset)
}
cmdline_row = row;
p_ch = Rows - cmdline_row;
- if (p_ch < 1)
+ if (p_ch < 1) {
p_ch = 1;
+ }
curtab->tp_ch_used = p_ch;
redraw_all_later(SOME_VALID);
showmode();
@@ -5532,21 +5673,23 @@ void win_drag_status_line(win_T *dragwin, int offset)
*/
void win_drag_vsep_line(win_T *dragwin, int offset)
{
- frame_T *curfr;
- frame_T *fr;
+ frame_T *curfr;
+ frame_T *fr;
int room;
- int left; /* if TRUE, drag separator line left, otherwise right */
+ bool left; // if true, drag separator line left, otherwise right
int n;
fr = dragwin->w_frame;
- if (fr == topframe) /* only one window (cannot happen?) */
+ if (fr == topframe) { // only one window (cannot happen?)
return;
+ }
curfr = fr;
fr = fr->fr_parent;
- /* When the parent frame is not a row of frames, its parent should be. */
+ // When the parent frame is not a row of frames, its parent should be.
if (fr->fr_layout != FR_ROW) {
- if (fr == topframe) /* only a column of windows (cannot happen?) */
+ if (fr == topframe) { // only a column of windows (cannot happen?)
return;
+ }
curfr = fr;
fr = fr->fr_parent;
}
@@ -5554,8 +5697,9 @@ void win_drag_vsep_line(win_T *dragwin, int offset)
/* If this is the last frame in a row, may want to resize a parent
* frame instead. */
while (curfr->fr_next == NULL) {
- if (fr == topframe)
+ if (fr == topframe) {
break;
+ }
curfr = fr;
fr = fr->fr_parent;
if (fr != topframe) {
@@ -5564,20 +5708,21 @@ void win_drag_vsep_line(win_T *dragwin, int offset)
}
}
- if (offset < 0) { /* drag left */
- left = TRUE;
+ if (offset < 0) { // drag left
+ left = true;
offset = -offset;
- /* sum up the room of the current frame and left of it */
+ // sum up the room of the current frame and left of it
room = 0;
for (fr = fr->fr_child;; fr = fr->fr_next) {
room += fr->fr_width - frame_minwidth(fr, NULL);
- if (fr == curfr)
+ if (fr == curfr) {
break;
+ }
}
- fr = curfr->fr_next; /* put fr at frame that grows */
- } else { /* drag right */
- left = FALSE;
- /* sum up the room of frames right of the current one */
+ fr = curfr->fr_next; // put fr at frame that grows
+ } else { // drag right
+ left = false;
+ // sum up the room of frames right of the current one
room = 0;
FOR_ALL_FRAMES(fr, curfr->fr_next) {
room += fr->fr_width - frame_minwidth(fr, NULL);
@@ -5600,28 +5745,29 @@ void win_drag_vsep_line(win_T *dragwin, int offset)
return; // Safety check, should not happen.
}
- /* grow frame fr by offset lines */
- frame_new_width(fr, fr->fr_width + offset, left, FALSE);
-
- /* shrink other frames: current and at the left or at the right */
- if (left)
- fr = curfr; /* current frame gets smaller */
- else
- fr = curfr->fr_next; /* next frame gets smaller */
+ // grow frame fr by offset lines
+ frame_new_width(fr, fr->fr_width + offset, left, false);
+ // shrink other frames: current and at the left or at the right
+ if (left) {
+ fr = curfr; // current frame gets smaller
+ } else {
+ fr = curfr->fr_next; // next frame gets smaller
+ }
while (fr != NULL && offset > 0) {
n = frame_minwidth(fr, NULL);
if (fr->fr_width - offset <= n) {
offset -= fr->fr_width - n;
- frame_new_width(fr, n, !left, FALSE);
+ frame_new_width(fr, n, !left, false);
} else {
- frame_new_width(fr, fr->fr_width - offset, !left, FALSE);
+ frame_new_width(fr, fr->fr_width - offset, !left, false);
break;
}
- if (left)
+ if (left) {
fr = fr->fr_prev;
- else
+ } else {
fr = fr->fr_next;
+ }
}
(void)win_comp_pos();
redraw_all_later(NOT_VALID);
@@ -5639,7 +5785,7 @@ void set_fraction(win_T *wp)
// it's halfway that line. Thus with two lines it is 25%, with three
// lines 17%, etc. Similarly for the last line: 75%, 83%, etc.
wp->w_fraction = ((long)wp->w_wrow * FRACTION_MULT + FRACTION_MULT / 2)
- / (long)wp->w_height_inner;
+ / (long)wp->w_height_inner;
}
}
@@ -5665,9 +5811,9 @@ void win_new_height(win_T *wp, int height)
void scroll_to_fraction(win_T *wp, int prev_height)
{
- linenr_T lnum;
- int sline, line_size;
- int height = wp->w_height_inner;
+ linenr_T lnum;
+ int sline, line_size;
+ int height = wp->w_height_inner;
// Don't change w_topline in any of these cases:
// - window height is 0
@@ -5676,15 +5822,16 @@ void scroll_to_fraction(win_T *wp, int prev_height)
// is visible.
if (height > 0
&& (!wp->w_p_scb || wp == curwin)
- && (height < wp->w_buffer->b_ml.ml_line_count || wp->w_topline > 1)
- ) {
+ && (height < wp->w_buffer->b_ml.ml_line_count ||
+ wp->w_topline > 1)) {
/*
* Find a value for w_topline that shows the cursor at the same
* relative position in the window as before (more or less).
*/
lnum = wp->w_cursor.lnum;
- if (lnum < 1) /* can happen when starting up */
+ if (lnum < 1) { // can happen when starting up
lnum = 1;
+ }
wp->w_wrow = ((long)wp->w_fraction * (long)height - 1L) / FRACTION_MULT;
line_size = plines_win_col(wp, lnum, (long)(wp->w_cursor.col)) - 1;
sline = wp->w_wrow - line_size;
@@ -5720,7 +5867,7 @@ void scroll_to_fraction(win_T *wp, int prev_height)
while (sline > 0 && lnum > 1) {
(void)hasFoldingWin(wp, lnum, &lnum, NULL, true, NULL);
if (lnum == 1) {
- /* first line in buffer is folded */
+ // first line in buffer is folded
line_size = 1;
--sline;
break;
@@ -5859,7 +6006,7 @@ void win_comp_scroll(win_T *wp)
void command_height(void)
{
int h;
- frame_T *frp;
+ frame_T *frp;
int old_p_ch = curtab->tp_ch_used;
/* Use the value of p_ch that we remembered. This is needed for when the
@@ -5873,15 +6020,16 @@ void command_height(void)
frp = frp->fr_parent;
}
- /* Avoid changing the height of a window with 'winfixheight' set. */
+ // Avoid changing the height of a window with 'winfixheight' set.
while (frp->fr_prev != NULL && frp->fr_layout == FR_LEAF
- && frp->fr_win->w_p_wfh)
+ && frp->fr_win->w_p_wfh) {
frp = frp->fr_prev;
+ }
if (starting != NO_SCREEN) {
cmdline_row = Rows - p_ch;
- if (p_ch > old_p_ch) { /* p_ch got bigger */
+ if (p_ch > old_p_ch) { // p_ch got bigger
while (p_ch > old_p_ch) {
if (frp == NULL) {
EMSG(_(e_noroom));
@@ -5891,14 +6039,15 @@ void command_height(void)
break;
}
h = frp->fr_height - frame_minheight(frp, NULL);
- if (h > p_ch - old_p_ch)
+ if (h > p_ch - old_p_ch) {
h = p_ch - old_p_ch;
+ }
old_p_ch += h;
frame_add_height(frp, -h);
frp = frp->fr_prev;
}
- /* Recompute window positions. */
+ // Recompute window positions.
(void)win_comp_pos();
// clear the lines added to cmdline
@@ -5906,19 +6055,21 @@ void command_height(void)
grid_fill(&default_grid, cmdline_row, Rows, 0, Columns, ' ', ' ', 0);
}
msg_row = cmdline_row;
- redraw_cmdline = TRUE;
+ redraw_cmdline = true;
return;
}
- if (msg_row < cmdline_row)
+ if (msg_row < cmdline_row) {
msg_row = cmdline_row;
- redraw_cmdline = TRUE;
+ }
+ redraw_cmdline = true;
}
frame_add_height(frp, (int)(old_p_ch - p_ch));
- /* Recompute window positions. */
- if (frp != lastwin->w_frame)
+ // Recompute window positions.
+ if (frp != lastwin->w_frame) {
(void)win_comp_pos();
+ }
}
/*
@@ -5927,11 +6078,12 @@ void command_height(void)
*/
static void frame_add_height(frame_T *frp, int n)
{
- frame_new_height(frp, frp->fr_height + n, FALSE, FALSE);
+ frame_new_height(frp, frp->fr_height + n, false, false);
for (;; ) {
frp = frp->fr_parent;
- if (frp == NULL)
+ if (frp == NULL) {
break;
+ }
frp->fr_height += n;
}
}
@@ -5946,9 +6098,10 @@ char_u *grab_file_name(long count, linenr_T *file_lnum)
int options = FNAME_MESS | FNAME_EXP | FNAME_REL | FNAME_UNESC;
if (VIsual_active) {
size_t len;
- char_u *ptr;
- if (get_visual_text(NULL, &ptr, &len) == FAIL)
+ char_u *ptr;
+ if (get_visual_text(NULL, &ptr, &len) == FAIL) {
return NULL;
+ }
// Only recognize ":123" here
if (file_lnum != NULL && ptr[len] == ':' && isdigit(ptr[len + 1])) {
char_u *p = ptr + len + 1;
@@ -5968,33 +6121,26 @@ char_u *grab_file_name(long count, linenr_T *file_lnum)
* NULL is returned if the file name or file is not found.
*
* options:
- * FNAME_MESS give error messages
- * FNAME_EXP expand to path
- * FNAME_HYP check for hypertext link
- * FNAME_INCL apply "includeexpr"
+ * FNAME_MESS give error messages
+ * FNAME_EXP expand to path
+ * FNAME_HYP check for hypertext link
+ * FNAME_INCL apply "includeexpr"
*/
char_u *file_name_at_cursor(int options, long count, linenr_T *file_lnum)
{
return file_name_in_line(get_cursor_line_ptr(),
- curwin->w_cursor.col, options, count, curbuf->b_ffname,
- file_lnum);
+ curwin->w_cursor.col, options, count, curbuf->b_ffname,
+ file_lnum);
}
-/*
- * Return the name of the file under or after ptr[col].
- * Otherwise like file_name_at_cursor().
- */
-char_u *
-file_name_in_line (
- char_u *line,
- int col,
- int options,
- long count,
- char_u *rel_fname, /* file we are searching relative to */
- linenr_T *file_lnum /* line number after the file name */
-)
-{
- char_u *ptr;
+/// @param rel_fname file we are searching relative to
+/// @param file_lnum line number after the file name
+///
+/// @return the name of the file under or after ptr[col]. Otherwise like file_name_at_cursor().
+char_u *file_name_in_line(char_u *line, int col, int options, long count, char_u *rel_fname,
+ linenr_T *file_lnum)
+{
+ char_u *ptr;
size_t len;
bool in_type = true;
bool is_url = false;
@@ -6059,8 +6205,9 @@ file_name_in_line (
* But don't remove "..", could be a directory name.
*/
if (len > 2 && vim_strchr((char_u *)".,:;!", ptr[len - 1]) != NULL
- && ptr[len - 2] != '.')
+ && ptr[len - 2] != '.') {
--len;
+ }
if (file_lnum != NULL) {
char_u *p;
@@ -6092,34 +6239,31 @@ file_name_in_line (
return find_file_name_in_path(ptr, len, options, count, rel_fname);
}
-/*
- * Add or remove a status line for the bottom window(s), according to the
- * value of 'laststatus'.
- */
-void
-last_status (
- int morewin /* pretend there are two or more windows */
-)
+/// Add or remove a status line for the bottom window(s), according to the
+/// value of 'laststatus'.
+///
+/// @param morewin pretend there are two or more windows if true.
+void last_status(bool morewin)
{
- /* Don't make a difference between horizontal or vertical split. */
+ // Don't make a difference between horizontal or vertical split.
last_status_rec(topframe, (p_ls == 2
|| (p_ls == 1 && (morewin || !one_window()))));
}
-static void last_status_rec(frame_T *fr, int statusline)
+static void last_status_rec(frame_T *fr, bool statusline)
{
- frame_T *fp;
- win_T *wp;
+ frame_T *fp;
+ win_T *wp;
if (fr->fr_layout == FR_LEAF) {
wp = fr->fr_win;
if (wp->w_status_height != 0 && !statusline) {
- /* remove status line */
+ // remove status line
win_new_height(wp, wp->w_height + 1);
wp->w_status_height = 0;
comp_col();
} else if (wp->w_status_height == 0 && statusline) {
- /* Find a frame to take a line from. */
+ // Find a frame to take a line from.
fp = fr;
while (fp->fr_height <= frame_minheight(fp, NULL)) {
if (fp == topframe) {
@@ -6128,18 +6272,20 @@ static void last_status_rec(frame_T *fr, int statusline)
}
/* In a column of frames: go to frame above. If already at
* the top or in a row of frames: go to parent. */
- if (fp->fr_parent->fr_layout == FR_COL && fp->fr_prev != NULL)
+ if (fp->fr_parent->fr_layout == FR_COL && fp->fr_prev != NULL) {
fp = fp->fr_prev;
- else
+ } else {
fp = fp->fr_parent;
+ }
}
wp->w_status_height = 1;
if (fp != fr) {
- frame_new_height(fp, fp->fr_height - 1, FALSE, FALSE);
+ frame_new_height(fp, fp->fr_height - 1, false, false);
frame_fix_height(wp);
(void)win_comp_pos();
- } else
+ } else {
win_new_height(wp, wp->w_height - 1);
+ }
comp_col();
redraw_all_later(SOME_VALID);
}
@@ -6149,9 +6295,10 @@ static void last_status_rec(frame_T *fr, int statusline)
last_status_rec(fp, statusline);
}
} else {
- /* horizontally split window, set status line for last one */
- for (fp = fr->fr_child; fp->fr_next != NULL; fp = fp->fr_next)
+ // horizontally split window, set status line for last one
+ for (fp = fr->fr_child; fp->fr_next != NULL; fp = fp->fr_next) {
;
+ }
last_status_rec(fp, statusline);
}
}
@@ -6166,8 +6313,10 @@ int tabline_height(void)
}
assert(first_tabpage);
switch (p_stal) {
- case 0: return 0;
- case 1: return (first_tabpage->tp_next == NULL) ? 0 : 1;
+ case 0:
+ return 0;
+ case 1:
+ return (first_tabpage->tp_next == NULL) ? 0 : 1;
}
return 1;
}
@@ -6178,8 +6327,9 @@ int tabline_height(void)
*/
int min_rows(void)
{
- if (firstwin == NULL) /* not initialized yet */
+ if (firstwin == NULL) { // not initialized yet
return MIN_LINES;
+ }
int total = 0;
FOR_ALL_TABS(tp) {
@@ -6189,7 +6339,7 @@ int min_rows(void)
}
}
total += tabline_height();
- total += 1; /* count the room for the command line */
+ total += 1; // count the room for the command line
return total;
}
@@ -6214,12 +6364,11 @@ bool only_one_window(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
return count <= 1;
}
-/*
- * Correct the cursor line number in other windows. Used after changing the
- * current buffer, and before applying autocommands.
- * When "do_curwin" is TRUE, also check current window.
- */
-void check_lnums(int do_curwin)
+/// Correct the cursor line number in other windows. Used after changing the
+/// current buffer, and before applying autocommands.
+///
+/// @param do_curwin when true, also check current window.
+void check_lnums(bool do_curwin)
{
FOR_ALL_TAB_WINDOWS(tp, wp) {
if ((do_curwin || wp != curwin) && wp->w_buffer == curbuf) {
@@ -6285,12 +6434,15 @@ static void make_snapshot_rec(frame_T *fr, frame_T **frp)
(*frp)->fr_layout = fr->fr_layout;
(*frp)->fr_width = fr->fr_width;
(*frp)->fr_height = fr->fr_height;
- if (fr->fr_next != NULL)
+ if (fr->fr_next != NULL) {
make_snapshot_rec(fr->fr_next, &((*frp)->fr_next));
- if (fr->fr_child != NULL)
+ }
+ if (fr->fr_child != NULL) {
make_snapshot_rec(fr->fr_child, &((*frp)->fr_child));
- if (fr->fr_layout == FR_LEAF && fr->fr_win == curwin)
+ }
+ if (fr->fr_layout == FR_LEAF && fr->fr_win == curwin) {
(*frp)->fr_win = curwin;
+ }
}
/*
@@ -6311,18 +6463,14 @@ static void clear_snapshot_rec(frame_T *fr)
}
}
-/*
- * Restore a previously created snapshot, if there is any.
- * This is only done if the screen size didn't change and the window layout is
- * still the same.
- */
-void
-restore_snapshot (
- int idx,
- int close_curwin /* closing current window */
-)
+/// Restore a previously created snapshot, if there is any.
+/// This is only done if the screen size didn't change and the window layout is
+/// still the same.
+///
+/// @param close_curwin closing current window
+void restore_snapshot(int idx, int close_curwin)
{
- win_T *wp;
+ win_T *wp;
if (curtab->tp_snapshot[idx] != NULL
&& curtab->tp_snapshot[idx]->fr_width == topframe->fr_width
@@ -6349,8 +6497,9 @@ static int check_snapshot_rec(frame_T *sn, frame_T *fr)
&& check_snapshot_rec(sn->fr_next, fr->fr_next) == FAIL)
|| (sn->fr_child != NULL
&& check_snapshot_rec(sn->fr_child, fr->fr_child) == FAIL)
- || (sn->fr_win != NULL && !win_valid(sn->fr_win)))
+ || (sn->fr_win != NULL && !win_valid(sn->fr_win))) {
return FAIL;
+ }
return OK;
}
@@ -6361,25 +6510,27 @@ static int check_snapshot_rec(frame_T *sn, frame_T *fr)
*/
static win_T *restore_snapshot_rec(frame_T *sn, frame_T *fr)
{
- win_T *wp = NULL;
- win_T *wp2;
+ win_T *wp = NULL;
+ win_T *wp2;
fr->fr_height = sn->fr_height;
fr->fr_width = sn->fr_width;
if (fr->fr_layout == FR_LEAF) {
- frame_new_height(fr, fr->fr_height, FALSE, FALSE);
- frame_new_width(fr, fr->fr_width, FALSE, FALSE);
+ frame_new_height(fr, fr->fr_height, false, false);
+ frame_new_width(fr, fr->fr_width, false, false);
wp = sn->fr_win;
}
if (sn->fr_next != NULL) {
wp2 = restore_snapshot_rec(sn->fr_next, fr->fr_next);
- if (wp2 != NULL)
+ if (wp2 != NULL) {
wp = wp2;
+ }
}
if (sn->fr_child != NULL) {
wp2 = restore_snapshot_rec(sn->fr_child, fr->fr_child);
- if (wp2 != NULL)
+ if (wp2 != NULL) {
wp = wp2;
+ }
}
return wp;
}
@@ -6406,23 +6557,24 @@ static win_T *get_snapshot_focus(int idx)
return win_valid(sn->fr_win) ? sn->fr_win : NULL;
}
-/*
- * Set "win" to be the curwin and "tp" to be the current tab page.
- * restore_win() MUST be called to undo, also when FAIL is returned.
- * No autocommands will be executed until restore_win() is called.
- * When "no_display" is TRUE the display won't be affected, no redraw is
- * triggered, another tabpage access is limited.
- * Returns FAIL if switching to "win" failed.
- */
-int switch_win(win_T **save_curwin, tabpage_T **save_curtab, win_T *win, tabpage_T *tp, int no_display)
+/// Set "win" to be the curwin and "tp" to be the current tab page.
+/// restore_win() MUST be called to undo, also when FAIL is returned.
+/// No autocommands will be executed until restore_win() is called.
+///
+/// @param no_display if true the display won't be affected, no redraw is
+/// triggered, another tabpage access is limited.
+///
+/// @return FAIL if switching to "win" failed.
+int switch_win(win_T **save_curwin, tabpage_T **save_curtab, win_T *win, tabpage_T *tp,
+ bool no_display)
{
block_autocmds();
return switch_win_noblock(save_curwin, save_curtab, win, tp, no_display);
}
// As switch_win() but without blocking autocommands.
-int switch_win_noblock(win_T **save_curwin, tabpage_T **save_curtab,
- win_T *win, tabpage_T *tp, int no_display)
+int switch_win_noblock(win_T **save_curwin, tabpage_T **save_curtab, win_T *win, tabpage_T *tp,
+ bool no_display)
{
*save_curwin = curwin;
if (tp != NULL) {
@@ -6433,8 +6585,9 @@ int switch_win_noblock(win_T **save_curwin, tabpage_T **save_curtab,
curtab = tp;
firstwin = curtab->tp_firstwin;
lastwin = curtab->tp_lastwin;
- } else
- goto_tabpage_tp(tp, FALSE, FALSE);
+ } else {
+ goto_tabpage_tp(tp, false, false);
+ }
}
if (!win_valid(win)) {
return FAIL;
@@ -6454,8 +6607,7 @@ void restore_win(win_T *save_curwin, tabpage_T *save_curtab, bool no_display)
}
// As restore_win() but without unblocking autocommands.
-void restore_win_noblock(win_T *save_curwin, tabpage_T *save_curtab,
- bool no_display)
+void restore_win_noblock(win_T *save_curwin, tabpage_T *save_curtab, bool no_display)
{
if (save_curtab != NULL && valid_tabpage(save_curtab)) {
if (no_display) {
@@ -6464,8 +6616,9 @@ void restore_win_noblock(win_T *save_curwin, tabpage_T *save_curtab,
curtab = save_curtab;
firstwin = curtab->tp_firstwin;
lastwin = curtab->tp_lastwin;
- } else
- goto_tabpage_tp(save_curtab, FALSE, FALSE);
+ } else {
+ goto_tabpage_tp(save_curtab, false, false);
+ }
}
if (win_valid(save_curwin)) {
curwin = save_curwin;
@@ -6510,16 +6663,15 @@ void restore_buffer(bufref_T *save_curbuf)
/// particular ID is desired
/// @param[in] conceal_char pointer to conceal replacement char
/// @return ID of added match, -1 on failure.
-int match_add(win_T *wp, const char *const grp, const char *const pat,
- int prio, int id, list_T *pos_list,
- const char *const conceal_char)
+int match_add(win_T *wp, const char *const grp, const char *const pat, int prio, int id,
+ list_T *pos_list, const char *const conceal_char)
FUNC_ATTR_NONNULL_ARG(1, 2)
{
matchitem_T *cur;
matchitem_T *prev;
matchitem_T *m;
int hlg_id;
- regprog_T *regprog = NULL;
+ regprog_T *regprog = NULL;
int rtype = SOME_VALID;
if (*grp == NUL || (pat != NULL && *pat == NUL)) {
@@ -6541,8 +6693,7 @@ int match_add(win_T *wp, const char *const grp, const char *const pat,
cur = cur->next;
}
}
- if ((hlg_id = syn_name2id((const char_u *)grp)) == 0) {
- EMSG2(_(e_nogroup), grp);
+ if ((hlg_id = syn_check_group((const char_u *)grp, strlen(grp))) == 0) {
return -1;
}
if (pat != NULL && (regprog = vim_regcomp((char_u *)pat, RE_MAGIC)) == NULL) {
@@ -6553,10 +6704,12 @@ int match_add(win_T *wp, const char *const grp, const char *const pat,
// Find available match ID.
while (id == -1) {
cur = wp->w_match_head;
- while (cur != NULL && cur->id != wp->w_next_match_id)
+ while (cur != NULL && cur->id != wp->w_next_match_id) {
cur = cur->next;
- if (cur == NULL)
+ }
+ if (cur == NULL) {
id = wp->w_next_match_id;
+ }
wp->w_next_match_id++;
}
@@ -6648,8 +6801,8 @@ int match_add(win_T *wp, const char *const grp, const char *const pat,
}
});
- // Calculate top and bottom lines for redrawing area
- if (toplnum != 0){
+ // Calculate top and bottom lines for redrawing area
+ if (toplnum != 0) {
if (wp->w_buffer->b_mod_set) {
if (wp->w_buffer->b_mod_top > toplnum) {
wp->w_buffer->b_mod_top = toplnum;
@@ -6677,10 +6830,11 @@ int match_add(win_T *wp, const char *const grp, const char *const pat,
prev = cur;
cur = cur->next;
}
- if (cur == prev)
+ if (cur == prev) {
wp->w_match_head = m;
- else
+ } else {
prev->next = m;
+ }
m->next = cur;
redraw_later(wp, rtype);
@@ -6693,8 +6847,9 @@ fail:
/// Delete match with ID 'id' in the match list of window 'wp'.
-/// Print error messages if 'perr' is TRUE.
-int match_delete(win_T *wp, int id, int perr)
+///
+/// @param perr print error messages if true.
+int match_delete(win_T *wp, int id, bool perr)
{
matchitem_T *cur = wp->w_match_head;
matchitem_T *prev = cur;
@@ -6718,10 +6873,11 @@ int match_delete(win_T *wp, int id, int perr)
}
return -1;
}
- if (cur == prev)
+ if (cur == prev) {
wp->w_match_head = cur->next;
- else
+ } else {
prev->next = cur->next;
+ }
vim_regfree(cur->match.regprog);
xfree(cur->pattern);
if (cur->pos.toplnum != 0) {
@@ -6770,8 +6926,9 @@ matchitem_T *get_match(win_T *wp, int id)
{
matchitem_T *cur = wp->w_match_head;
- while (cur != NULL && cur->id != id)
+ while (cur != NULL && cur->id != id) {
cur = cur->next;
+ }
return cur;
}
@@ -6901,13 +7058,13 @@ void win_id2tabwin(typval_T *const argvars, typval_T *const rettv)
tv_list_append_number(list, winnr);
}
-win_T * win_id2wp(typval_T *argvars)
+win_T *win_id2wp(typval_T *argvars)
{
return win_id2wp_tp(argvars, NULL);
}
// Return the window and tab pointer of window "id".
-win_T * win_id2wp_tp(typval_T *argvars, tabpage_T **tpp)
+win_T *win_id2wp_tp(typval_T *argvars, tabpage_T **tpp)
{
int id = tv_get_number(&argvars[0]);
diff --git a/src/uncrustify.cfg b/src/uncrustify.cfg
new file mode 100644
index 0000000000..5d73e70ed0
--- /dev/null
+++ b/src/uncrustify.cfg
@@ -0,0 +1,3295 @@
+# Uncrustify-0.73.0-186-03faf73c
+
+#
+# General options
+#
+
+# The type of line endings.
+#
+# Default: auto
+newlines = auto # lf/crlf/cr/auto
+
+# The original size of tabs in the input.
+#
+# Default: 8
+input_tab_size = 8 # unsigned number
+
+# The size of tabs in the output (only used if align_with_tabs=true).
+#
+# Default: 8
+output_tab_size = 8 # unsigned number
+
+# The ASCII value of the string escape char, usually 92 (\) or (Pawn) 94 (^).
+#
+# Default: 92
+string_escape_char = 92 # unsigned number
+
+# Alternate string escape char (usually only used for Pawn).
+# Only works right before the quote char.
+string_escape_char2 = 0 # unsigned number
+
+# Replace tab characters found in string literals with the escape sequence \t
+# instead.
+string_replace_tab_chars = false # true/false
+
+# Allow interpreting '>=' and '>>=' as part of a template in code like
+# 'void f(list<list<B>>=val);'. If true, 'assert(x<0 && y>=3)' will be broken.
+# Improvements to template detection may make this option obsolete.
+tok_split_gte = false # true/false
+
+# Disable formatting of NL_CONT ('\\n') ended lines (e.g. multi-line macros).
+disable_processing_nl_cont = false # true/false
+
+# Specify the marker used in comments to disable processing of part of the
+# file.
+#
+# Default: *INDENT-OFF*
+disable_processing_cmt = "uncrustify:indent-off" # string
+
+# Specify the marker used in comments to (re)enable processing in a file.
+#
+# Default: *INDENT-ON*
+enable_processing_cmt = "uncrustify:indent-on" # string
+
+# Enable parsing of digraphs.
+enable_digraphs = false # true/false
+
+# Option to allow both disable_processing_cmt and enable_processing_cmt
+# strings, if specified, to be interpreted as ECMAScript regular expressions.
+# If true, a regex search will be performed within comments according to the
+# specified patterns in order to disable/enable processing.
+processing_cmt_as_regex = false # true/false
+
+# Add or remove the UTF-8 BOM (recommend 'remove').
+utf8_bom = remove # ignore/add/remove/force/not_defined
+
+# If the file contains bytes with values between 128 and 255, but is not
+# UTF-8, then output as UTF-8.
+utf8_byte = false # true/false
+
+# Force the output encoding to UTF-8.
+utf8_force = false # true/false
+
+#
+# Spacing options
+#
+
+# Add or remove space around non-assignment symbolic operators ('+', '/', '%',
+# '<<', and so forth).
+sp_arith = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space around arithmetic operators '+' and '-'.
+#
+# Overrides sp_arith.
+sp_arith_additive = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space around assignment operator '=', '+=', etc.
+sp_assign = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space around '=' in C++11 lambda capture specifications.
+#
+# Overrides sp_assign.
+sp_cpp_lambda_assign = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after the capture specification of a C++11 lambda when
+# an argument list is present, as in '[] <here> (int x){ ... }'.
+sp_cpp_lambda_square_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after the capture specification of a C++11 lambda with
+# no argument list is present, as in '[] <here> { ... }'.
+sp_cpp_lambda_square_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after the opening parenthesis and before the closing
+# parenthesis of a argument list of a C++11 lambda, as in
+# '[]( <here> int x <here> ){ ... }'.
+sp_cpp_lambda_argument_list = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after the argument list of a C++11 lambda, as in
+# '[](int x) <here> { ... }'.
+sp_cpp_lambda_paren_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between a lambda body and its call operator of an
+# immediately invoked lambda, as in '[]( ... ){ ... } <here> ( ... )'.
+sp_cpp_lambda_fparen = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space around assignment operator '=' in a prototype.
+#
+# If set to ignore, use sp_assign.
+sp_assign_default = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before assignment operator '=', '+=', etc.
+#
+# Overrides sp_assign.
+sp_before_assign = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after assignment operator '=', '+=', etc.
+#
+# Overrides sp_assign.
+sp_after_assign = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space in 'NS_ENUM ('.
+sp_enum_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space around assignment '=' in enum.
+sp_enum_assign = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before assignment '=' in enum.
+#
+# Overrides sp_enum_assign.
+sp_enum_before_assign = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after assignment '=' in enum.
+#
+# Overrides sp_enum_assign.
+sp_enum_after_assign = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space around assignment ':' in enum.
+sp_enum_colon = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space around preprocessor '##' concatenation operator.
+#
+# Default: add
+sp_pp_concat = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after preprocessor '#' stringify operator.
+# Also affects the '#@' charizing operator.
+sp_pp_stringify = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before preprocessor '#' stringify operator
+# as in '#define x(y) L#y'.
+sp_before_pp_stringify = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space around boolean operators '&&' and '||'.
+sp_bool = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space around compare operator '<', '>', '==', etc.
+sp_compare = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space inside '(' and ')'.
+sp_inside_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between nested parentheses, i.e. '((' vs. ') )'.
+sp_paren_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between back-to-back parentheses, i.e. ')(' vs. ') ('.
+sp_cparen_oparen = ignore # ignore/add/remove/force/not_defined
+
+# Whether to balance spaces inside nested parentheses.
+sp_balance_nested_parens = false # true/false
+
+# Add or remove space between ')' and '{'.
+sp_paren_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between nested braces, i.e. '{{' vs. '{ {'.
+sp_brace_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before pointer star '*'.
+sp_before_ptr_star = force # ignore/add/remove/force/not_defined
+
+# Add or remove space before pointer star '*' that isn't followed by a
+# variable name. If set to ignore, sp_before_ptr_star is used instead.
+sp_before_unnamed_ptr_star = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between pointer stars '*', as in 'int ***a;'.
+sp_between_ptr_star = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after pointer star '*', if followed by a word.
+#
+# Overrides sp_type_func.
+sp_after_ptr_star = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after pointer caret '^', if followed by a word.
+sp_after_ptr_block_caret = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after pointer star '*', if followed by a qualifier.
+sp_after_ptr_star_qualifier = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after a pointer star '*', if followed by a function
+# prototype or function definition.
+#
+# Overrides sp_after_ptr_star and sp_type_func.
+sp_after_ptr_star_func = remove # ignore/add/remove/force/not_defined
+
+# Add or remove space after a pointer star '*' in the trailing return of a
+# function prototype or function definition.
+sp_after_ptr_star_trailing = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after a pointer star '*', if followed by an open
+# parenthesis, as in 'void* (*)()'.
+sp_ptr_star_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before a pointer star '*', if followed by a function
+# prototype or function definition.
+sp_before_ptr_star_func = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before a pointer star '*' in the trailing return of a
+# function prototype or function definition.
+sp_before_ptr_star_trailing = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before a reference sign '&'.
+sp_before_byref = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before a reference sign '&' that isn't followed by a
+# variable name. If set to ignore, sp_before_byref is used instead.
+sp_before_unnamed_byref = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after reference sign '&', if followed by a word.
+#
+# Overrides sp_type_func.
+sp_after_byref = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after a reference sign '&', if followed by a function
+# prototype or function definition.
+#
+# Overrides sp_after_byref and sp_type_func.
+sp_after_byref_func = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before a reference sign '&', if followed by a function
+# prototype or function definition.
+sp_before_byref_func = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between type and word. In cases where total removal of
+# whitespace would be a syntax error, a value of 'remove' is treated the same
+# as 'force'.
+#
+# This also affects some other instances of space following a type that are
+# not covered by other options; for example, between the return type and
+# parenthesis of a function type template argument, between the type and
+# parenthesis of an array parameter, or between 'decltype(...)' and the
+# following word.
+#
+# Default: force
+sp_after_type = force # ignore/add/remove/force/not_defined
+
+# Add or remove space between 'decltype(...)' and word,
+# brace or function call.
+sp_after_decltype = ignore # ignore/add/remove/force/not_defined
+
+# (D) Add or remove space before the parenthesis in the D constructs
+# 'template Foo(' and 'class Foo('.
+sp_before_template_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between 'template' and '<'.
+# If set to ignore, sp_before_angle is used.
+sp_template_angle = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before '<'.
+sp_before_angle = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space inside '<' and '>'.
+sp_inside_angle = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space inside '<>'.
+sp_inside_angle_empty = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between '>' and ':'.
+sp_angle_colon = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after '>'.
+sp_after_angle = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between '>' and '(' as found in 'new List<byte>(foo);'.
+sp_angle_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between '>' and '()' as found in 'new List<byte>();'.
+sp_angle_paren_empty = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between '>' and a word as in 'List<byte> m;' or
+# 'template <typename T> static ...'.
+sp_angle_word = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between '>' and '>' in '>>' (template stuff).
+#
+# Default: add
+sp_angle_shift = ignore # ignore/add/remove/force/not_defined
+
+# (C++11) Permit removal of the space between '>>' in 'foo<bar<int> >'. Note
+# that sp_angle_shift cannot remove the space without this option.
+sp_permit_cpp11_shift = false # true/false
+
+# Add or remove space before '(' of control statements ('if', 'for', 'switch',
+# 'while', etc.).
+sp_before_sparen = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space inside '(' and ')' of control statements.
+sp_inside_sparen = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after '(' of control statements.
+#
+# Overrides sp_inside_sparen.
+sp_inside_sparen_open = remove # ignore/add/remove/force/not_defined
+
+# Add or remove space before ')' of control statements.
+#
+# Overrides sp_inside_sparen.
+sp_inside_sparen_close = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between '((' or '))' of control statements.
+sp_sparen_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after ')' of control statements.
+sp_after_sparen = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between ')' and '{' of control statements.
+sp_sparen_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between 'do' and '{'.
+sp_do_brace_open = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between '}' and 'while'.
+sp_brace_close_while = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between 'while' and '('. Overrides sp_before_sparen.
+sp_while_paren_open = ignore # ignore/add/remove/force/not_defined
+
+# (D) Add or remove space between 'invariant' and '('.
+sp_invariant_paren = ignore # ignore/add/remove/force/not_defined
+
+# (D) Add or remove space after the ')' in 'invariant (C) c'.
+sp_after_invariant_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before empty statement ';' on 'if', 'for' and 'while'.
+sp_special_semi = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before ';'.
+#
+# Default: remove
+sp_before_semi = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before ';' in non-empty 'for' statements.
+sp_before_semi_for = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before a semicolon of an empty left part of a for
+# statement, as in 'for ( <here> ; ; )'.
+sp_before_semi_for_empty = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between the semicolons of an empty middle part of a for
+# statement, as in 'for ( ; <here> ; )'.
+sp_between_semi_for_empty = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after ';', except when followed by a comment.
+#
+# Default: add
+sp_after_semi = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after ';' in non-empty 'for' statements.
+#
+# Default: force
+sp_after_semi_for = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after the final semicolon of an empty part of a for
+# statement, as in 'for ( ; ; <here> )'.
+sp_after_semi_for_empty = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before '[' (except '[]').
+sp_before_square = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before '[' for a variable definition.
+#
+# Default: remove
+sp_before_vardef_square = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before '[' for asm block.
+sp_before_square_asm_block = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before '[]'.
+sp_before_squares = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before C++17 structured bindings.
+sp_cpp_before_struct_binding = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space inside a non-empty '[' and ']'.
+sp_inside_square = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space inside '[]'.
+sp_inside_square_empty = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove space inside a non-empty Objective-C boxed array '@[' and
+# ']'. If set to ignore, sp_inside_square is used.
+sp_inside_square_oc_array = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after ',', i.e. 'a,b' vs. 'a, b'.
+sp_after_comma = add # ignore/add/remove/force/not_defined
+
+# Add or remove space before ',', i.e. 'a,b' vs. 'a ,b'.
+#
+# Default: remove
+sp_before_comma = remove # ignore/add/remove/force/not_defined
+
+# (C#) Add or remove space between ',' and ']' in multidimensional array type
+# like 'int[,,]'.
+sp_after_mdatype_commas = ignore # ignore/add/remove/force/not_defined
+
+# (C#) Add or remove space between '[' and ',' in multidimensional array type
+# like 'int[,,]'.
+sp_before_mdatype_commas = ignore # ignore/add/remove/force/not_defined
+
+# (C#) Add or remove space between ',' in multidimensional array type
+# like 'int[,,]'.
+sp_between_mdatype_commas = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between an open parenthesis and comma,
+# i.e. '(,' vs. '( ,'.
+#
+# Default: force
+sp_paren_comma = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after the variadic '...' when preceded by a
+# non-punctuator.
+# The value REMOVE will be overriden with FORCE
+sp_after_ellipsis = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before the variadic '...' when preceded by a
+# non-punctuator.
+# The value REMOVE will be overriden with FORCE
+sp_before_ellipsis = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between a type and '...'.
+sp_type_ellipsis = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between a '*' and '...'.
+sp_ptr_type_ellipsis = ignore # ignore/add/remove/force/not_defined
+
+# (D) Add or remove space between a type and '?'.
+sp_type_question = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between ')' and '...'.
+sp_paren_ellipsis = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between '&&' and '...'.
+sp_byref_ellipsis = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between ')' and a qualifier such as 'const'.
+sp_paren_qualifier = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between ')' and 'noexcept'.
+sp_paren_noexcept = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after class ':'.
+sp_after_class_colon = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before class ':'.
+sp_before_class_colon = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after class constructor ':'.
+sp_after_constr_colon = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before class constructor ':'.
+sp_before_constr_colon = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before case ':'.
+#
+# Default: remove
+sp_before_case_colon = remove # ignore/add/remove/force/not_defined
+
+# Add or remove space between 'operator' and operator sign.
+sp_after_operator = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between the operator symbol and the open parenthesis, as
+# in 'operator ++('.
+sp_after_operator_sym = ignore # ignore/add/remove/force/not_defined
+
+# Overrides sp_after_operator_sym when the operator has no arguments, as in
+# 'operator *()'.
+sp_after_operator_sym_empty = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after C/D cast, i.e. 'cast(int)a' vs. 'cast(int) a' or
+# '(int)a' vs. '(int) a'.
+sp_after_cast = remove # ignore/add/remove/force/not_defined
+
+# Add or remove spaces inside cast parentheses.
+sp_inside_paren_cast = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between the type and open parenthesis in a C++ cast,
+# i.e. 'int(exp)' vs. 'int (exp)'.
+sp_cpp_cast_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between 'sizeof' and '('.
+sp_sizeof_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between 'sizeof' and '...'.
+sp_sizeof_ellipsis = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between 'sizeof...' and '('.
+sp_sizeof_ellipsis_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between '...' and a parameter pack.
+sp_ellipsis_parameter_pack = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between a parameter pack and '...'.
+sp_parameter_pack_ellipsis = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between 'decltype' and '('.
+sp_decltype_paren = ignore # ignore/add/remove/force/not_defined
+
+# (Pawn) Add or remove space after the tag keyword.
+sp_after_tag = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space inside enum '{' and '}'.
+sp_inside_braces_enum = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space inside struct/union '{' and '}'.
+sp_inside_braces_struct = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove space inside Objective-C boxed dictionary '{' and '}'
+sp_inside_braces_oc_dict = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after open brace in an unnamed temporary
+# direct-list-initialization.
+sp_after_type_brace_init_lst_open = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before close brace in an unnamed temporary
+# direct-list-initialization.
+sp_before_type_brace_init_lst_close = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space inside an unnamed temporary direct-list-initialization.
+sp_inside_type_brace_init_lst = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space inside '{' and '}'.
+sp_inside_braces = add # ignore/add/remove/force/not_defined
+
+# Add or remove space inside '{}'.
+sp_inside_braces_empty = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space around trailing return operator '->'.
+sp_trailing_return = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between return type and function name. A minimum of 1
+# is forced except for pointer return types.
+sp_type_func = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between type and open brace of an unnamed temporary
+# direct-list-initialization.
+sp_type_brace_init_lst = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between function name and '(' on function declaration.
+sp_func_proto_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between function name and '()' on function declaration
+# without parameters.
+sp_func_proto_paren_empty = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between function name and '(' with a typedef specifier.
+sp_func_type_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between alias name and '(' of a non-pointer function type typedef.
+sp_func_def_paren = remove # ignore/add/remove/force/not_defined
+
+# Add or remove space between function name and '()' on function definition
+# without parameters.
+sp_func_def_paren_empty = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space inside empty function '()'.
+# Overrides sp_after_angle unless use_sp_after_angle_always is set to true.
+sp_inside_fparens = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space inside function '(' and ')'.
+sp_inside_fparen = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space inside the first parentheses in a function type, as in
+# 'void (*x)(...)'.
+sp_inside_tparen = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between the ')' and '(' in a function type, as in
+# 'void (*x)(...)'.
+sp_after_tparen_close = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between ']' and '(' when part of a function call.
+sp_square_fparen = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between ')' and '{' of function.
+sp_fparen_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between ')' and '{' of a function call in object
+# initialization.
+#
+# Overrides sp_fparen_brace.
+sp_fparen_brace_initializer = ignore # ignore/add/remove/force/not_defined
+
+# (Java) Add or remove space between ')' and '{{' of double brace initializer.
+sp_fparen_dbrace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between function name and '(' on function calls.
+sp_func_call_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between function name and '()' on function calls without
+# parameters. If set to ignore (the default), sp_func_call_paren is used.
+sp_func_call_paren_empty = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between the user function name and '(' on function
+# calls. You need to set a keyword to be a user function in the config file,
+# like:
+# set func_call_user tr _ i18n
+sp_func_call_user_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space inside user function '(' and ')'.
+sp_func_call_user_inside_fparen = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between nested parentheses with user functions,
+# i.e. '((' vs. '( ('.
+sp_func_call_user_paren_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between a constructor/destructor and the open
+# parenthesis.
+sp_func_class_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between a constructor without parameters or destructor
+# and '()'.
+sp_func_class_paren_empty = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between 'return' and '('.
+sp_return_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between 'return' and '{'.
+sp_return_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between '__attribute__' and '('.
+sp_attribute_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between 'defined' and '(' in '#if defined (FOO)'.
+sp_defined_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between 'throw' and '(' in 'throw (something)'.
+sp_throw_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between 'throw' and anything other than '(' as in
+# '@throw [...];'.
+sp_after_throw = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between 'catch' and '(' in 'catch (something) { }'.
+# If set to ignore, sp_before_sparen is used.
+sp_catch_paren = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove space between '@catch' and '('
+# in '@catch (something) { }'. If set to ignore, sp_catch_paren is used.
+sp_oc_catch_paren = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove space before Objective-C protocol list
+# as in '@protocol Protocol<here><Protocol_A>' or '@interface MyClass : NSObject<here><MyProtocol>'.
+sp_before_oc_proto_list = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove space between class name and '('
+# in '@interface className(categoryName)<ProtocolName>:BaseClass'
+sp_oc_classname_paren = ignore # ignore/add/remove/force/not_defined
+
+# (D) Add or remove space between 'version' and '('
+# in 'version (something) { }'. If set to ignore, sp_before_sparen is used.
+sp_version_paren = ignore # ignore/add/remove/force/not_defined
+
+# (D) Add or remove space between 'scope' and '('
+# in 'scope (something) { }'. If set to ignore, sp_before_sparen is used.
+sp_scope_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between 'super' and '(' in 'super (something)'.
+#
+# Default: remove
+sp_super_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between 'this' and '(' in 'this (something)'.
+#
+# Default: remove
+sp_this_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between a macro name and its definition.
+sp_macro = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between a macro function ')' and its definition.
+sp_macro_func = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between 'else' and '{' if on the same line.
+sp_else_brace = add # ignore/add/remove/force/not_defined
+
+# Add or remove space between '}' and 'else' if on the same line.
+sp_brace_else = add # ignore/add/remove/force/not_defined
+
+# Add or remove space between '}' and the name of a typedef on the same line.
+sp_brace_typedef = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before the '{' of a 'catch' statement, if the '{' and
+# 'catch' are on the same line, as in 'catch (decl) <here> {'.
+sp_catch_brace = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove space before the '{' of a '@catch' statement, if the '{'
+# and '@catch' are on the same line, as in '@catch (decl) <here> {'.
+# If set to ignore, sp_catch_brace is used.
+sp_oc_catch_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between '}' and 'catch' if on the same line.
+sp_brace_catch = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove space between '}' and '@catch' if on the same line.
+# If set to ignore, sp_brace_catch is used.
+sp_oc_brace_catch = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between 'finally' and '{' if on the same line.
+sp_finally_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between '}' and 'finally' if on the same line.
+sp_brace_finally = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between 'try' and '{' if on the same line.
+sp_try_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between get/set and '{' if on the same line.
+sp_getset_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between a variable and '{' for C++ uniform
+# initialization.
+sp_word_brace_init_lst = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between a variable and '{' for a namespace.
+#
+# Default: add
+sp_word_brace_ns = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before the '::' operator.
+sp_before_dc = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after the '::' operator.
+sp_after_dc = ignore # ignore/add/remove/force/not_defined
+
+# (D) Add or remove around the D named array initializer ':' operator.
+sp_d_array_colon = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after the '!' (not) unary operator.
+#
+# Default: remove
+sp_not = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after the '~' (invert) unary operator.
+#
+# Default: remove
+sp_inv = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after the '&' (address-of) unary operator. This does not
+# affect the spacing after a '&' that is part of a type.
+#
+# Default: remove
+sp_addr = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space around the '.' or '->' operators.
+#
+# Default: remove
+sp_member = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after the '*' (dereference) unary operator. This does
+# not affect the spacing after a '*' that is part of a type.
+#
+# Default: remove
+sp_deref = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after '+' or '-', as in 'x = -5' or 'y = +7'.
+#
+# Default: remove
+sp_sign = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between '++' and '--' the word to which it is being
+# applied, as in '(--x)' or 'y++;'.
+#
+# Default: remove
+sp_incdec = remove # ignore/add/remove/force/not_defined
+
+# Add or remove space before a backslash-newline at the end of a line.
+#
+# Default: add
+sp_before_nl_cont = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove space after the scope '+' or '-', as in '-(void) foo;'
+# or '+(int) bar;'.
+sp_after_oc_scope = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove space after the colon in message specs,
+# i.e. '-(int) f:(int) x;' vs. '-(int) f: (int) x;'.
+sp_after_oc_colon = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove space before the colon in message specs,
+# i.e. '-(int) f: (int) x;' vs. '-(int) f : (int) x;'.
+sp_before_oc_colon = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove space after the colon in immutable dictionary expression
+# 'NSDictionary *test = @{@"foo" :@"bar"};'.
+sp_after_oc_dict_colon = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove space before the colon in immutable dictionary expression
+# 'NSDictionary *test = @{@"foo" :@"bar"};'.
+sp_before_oc_dict_colon = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove space after the colon in message specs,
+# i.e. '[object setValue:1];' vs. '[object setValue: 1];'.
+sp_after_send_oc_colon = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove space before the colon in message specs,
+# i.e. '[object setValue:1];' vs. '[object setValue :1];'.
+sp_before_send_oc_colon = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove space after the (type) in message specs,
+# i.e. '-(int)f: (int) x;' vs. '-(int)f: (int)x;'.
+sp_after_oc_type = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove space after the first (type) in message specs,
+# i.e. '-(int) f:(int)x;' vs. '-(int)f:(int)x;'.
+sp_after_oc_return_type = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove space between '@selector' and '(',
+# i.e. '@selector(msgName)' vs. '@selector (msgName)'.
+# Also applies to '@protocol()' constructs.
+sp_after_oc_at_sel = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove space between '@selector(x)' and the following word,
+# i.e. '@selector(foo) a:' vs. '@selector(foo)a:'.
+sp_after_oc_at_sel_parens = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove space inside '@selector' parentheses,
+# i.e. '@selector(foo)' vs. '@selector( foo )'.
+# Also applies to '@protocol()' constructs.
+sp_inside_oc_at_sel_parens = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove space before a block pointer caret,
+# i.e. '^int (int arg){...}' vs. ' ^int (int arg){...}'.
+sp_before_oc_block_caret = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove space after a block pointer caret,
+# i.e. '^int (int arg){...}' vs. '^ int (int arg){...}'.
+sp_after_oc_block_caret = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove space between the receiver and selector in a message,
+# as in '[receiver selector ...]'.
+sp_after_oc_msg_receiver = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove space after '@property'.
+sp_after_oc_property = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove space between '@synchronized' and the open parenthesis,
+# i.e. '@synchronized(foo)' vs. '@synchronized (foo)'.
+sp_after_oc_synchronized = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space around the ':' in 'b ? t : f'.
+sp_cond_colon = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before the ':' in 'b ? t : f'.
+#
+# Overrides sp_cond_colon.
+sp_cond_colon_before = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after the ':' in 'b ? t : f'.
+#
+# Overrides sp_cond_colon.
+sp_cond_colon_after = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space around the '?' in 'b ? t : f'.
+sp_cond_question = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before the '?' in 'b ? t : f'.
+#
+# Overrides sp_cond_question.
+sp_cond_question_before = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after the '?' in 'b ? t : f'.
+#
+# Overrides sp_cond_question.
+sp_cond_question_after = ignore # ignore/add/remove/force/not_defined
+
+# In the abbreviated ternary form '(a ?: b)', add or remove space between '?'
+# and ':'.
+#
+# Overrides all other sp_cond_* options.
+sp_cond_ternary_short = ignore # ignore/add/remove/force/not_defined
+
+# Fix the spacing between 'case' and the label. Only 'ignore' and 'force' make
+# sense here.
+sp_case_label = ignore # ignore/add/remove/force/not_defined
+
+# (D) Add or remove space around the D '..' operator.
+sp_range = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after ':' in a Java/C++11 range-based 'for',
+# as in 'for (Type var : <here> expr)'.
+sp_after_for_colon = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before ':' in a Java/C++11 range-based 'for',
+# as in 'for (Type var <here> : expr)'.
+sp_before_for_colon = ignore # ignore/add/remove/force/not_defined
+
+# (D) Add or remove space between 'extern' and '(' as in 'extern <here> (C)'.
+sp_extern_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after the opening of a C++ comment, as in '// <here> A'.
+sp_cmt_cpp_start = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space in a C++ region marker comment, as in '// <here> BEGIN'.
+# A region marker is defined as a comment which is not preceded by other text
+# (i.e. the comment is the first non-whitespace on the line), and which starts
+# with either 'BEGIN' or 'END'.
+#
+# Overrides sp_cmt_cpp_start.
+sp_cmt_cpp_region = ignore # ignore/add/remove/force/not_defined
+
+# If true, space added with sp_cmt_cpp_start will be added after Doxygen
+# sequences like '///', '///<', '//!' and '//!<'.
+sp_cmt_cpp_doxygen = false # true/false
+
+# If true, space added with sp_cmt_cpp_start will be added after Qt translator
+# or meta-data comments like '//:', '//=', and '//~'.
+sp_cmt_cpp_qttr = false # true/false
+
+# Add or remove space between #else or #endif and a trailing comment.
+sp_endif_cmt = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after 'new', 'delete' and 'delete[]'.
+sp_after_new = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between 'new' and '(' in 'new()'.
+sp_between_new_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space between ')' and type in 'new(foo) BAR'.
+sp_after_newop_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space inside parenthesis of the new operator
+# as in 'new(foo) BAR'.
+sp_inside_newop_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after the open parenthesis of the new operator,
+# as in 'new(foo) BAR'.
+#
+# Overrides sp_inside_newop_paren.
+sp_inside_newop_paren_open = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before the close parenthesis of the new operator,
+# as in 'new(foo) BAR'.
+#
+# Overrides sp_inside_newop_paren.
+sp_inside_newop_paren_close = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space before a trailing or embedded comment.
+sp_before_tr_emb_cmt = add # ignore/add/remove/force/not_defined
+
+# Number of spaces before a trailing or embedded comment.
+sp_num_before_tr_emb_cmt = 2 # unsigned number
+
+# (Java) Add or remove space between an annotation and the open parenthesis.
+sp_annotation_paren = ignore # ignore/add/remove/force/not_defined
+
+# If true, vbrace tokens are dropped to the previous token and skipped.
+sp_skip_vbrace_tokens = false # true/false
+
+# Add or remove space after 'noexcept'.
+sp_after_noexcept = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove space after '_'.
+sp_vala_after_translation = ignore # ignore/add/remove/force/not_defined
+
+# If true, a <TAB> is inserted after #define.
+force_tab_after_define = false # true/false
+
+#
+# Indenting options
+#
+
+# The number of columns to indent per level. Usually 2, 3, 4, or 8.
+#
+# Default: 8
+indent_columns = 2 # unsigned number
+
+# The continuation indent. If non-zero, this overrides the indent of '(', '['
+# and '=' continuation indents. Negative values are OK; negative value is
+# absolute and not increased for each '(' or '[' level.
+#
+# For FreeBSD, this is set to 4.
+indent_continue = 0 # number
+
+# The continuation indent, only for class header line(s). If non-zero, this
+# overrides the indent of 'class' continuation indents.
+indent_continue_class_head = 0 # unsigned number
+
+# Whether to indent empty lines (i.e. lines which contain only spaces before
+# the newline character).
+indent_single_newlines = false # true/false
+
+# The continuation indent for func_*_param if they are true. If non-zero, this
+# overrides the indent.
+indent_param = 0 # unsigned number
+
+# How to use tabs when indenting code.
+#
+# 0: Spaces only
+# 1: Indent with tabs to brace level, align with spaces (default)
+# 2: Indent and align with tabs, using spaces when not on a tabstop
+#
+# Default: 1
+indent_with_tabs = 0 # unsigned number
+
+# Whether to indent comments that are not at a brace level with tabs on a
+# tabstop. Requires indent_with_tabs=2. If false, will use spaces.
+indent_cmt_with_tabs = false # true/false
+
+# Whether to indent strings broken by '\' so that they line up.
+indent_align_string = false # true/false
+
+# The number of spaces to indent multi-line XML strings.
+# Requires indent_align_string=true.
+indent_xml_string = 0 # unsigned number
+
+# Spaces to indent '{' from level.
+indent_brace = 0 # unsigned number
+
+# Whether braces are indented to the body level.
+indent_braces = false # true/false
+
+# Whether to disable indenting function braces if indent_braces=true.
+indent_braces_no_func = false # true/false
+
+# Whether to disable indenting class braces if indent_braces=true.
+indent_braces_no_class = false # true/false
+
+# Whether to disable indenting struct braces if indent_braces=true.
+indent_braces_no_struct = false # true/false
+
+# Whether to indent based on the size of the brace parent,
+# i.e. 'if' => 3 spaces, 'for' => 4 spaces, etc.
+indent_brace_parent = false # true/false
+
+# Whether to indent based on the open parenthesis instead of the open brace
+# in '({\n'.
+indent_paren_open_brace = false # true/false
+
+# (C#) Whether to indent the brace of a C# delegate by another level.
+indent_cs_delegate_brace = false # true/false
+
+# (C#) Whether to indent a C# delegate (to handle delegates with no brace) by
+# another level.
+indent_cs_delegate_body = false # true/false
+
+# Whether to indent the body of a 'namespace'.
+indent_namespace = false # true/false
+
+# Whether to indent only the first namespace, and not any nested namespaces.
+# Requires indent_namespace=true.
+indent_namespace_single_indent = false # true/false
+
+# The number of spaces to indent a namespace block.
+# If set to zero, use the value indent_columns
+indent_namespace_level = 0 # unsigned number
+
+# If the body of the namespace is longer than this number, it won't be
+# indented. Requires indent_namespace=true. 0 means no limit.
+indent_namespace_limit = 0 # unsigned number
+
+# Whether the 'extern "C"' body is indented.
+indent_extern = false # true/false
+
+# Whether the 'class' body is indented.
+indent_class = false # true/false
+
+# Additional indent before the leading base class colon.
+# Negative values decrease indent down to the first column.
+# Requires a newline break before colon (see pos_class_colon
+# and nl_class_colon)
+indent_before_class_colon = 0 # number
+
+# Whether to indent the stuff after a leading base class colon.
+indent_class_colon = false # true/false
+
+# Whether to indent based on a class colon instead of the stuff after the
+# colon. Requires indent_class_colon=true.
+indent_class_on_colon = false # true/false
+
+# Whether to indent the stuff after a leading class initializer colon.
+indent_constr_colon = false # true/false
+
+# Virtual indent from the ':' for member initializers.
+#
+# Default: 2
+indent_ctor_init_leading = 2 # unsigned number
+
+# Additional indent for constructor initializer list.
+# Negative values decrease indent down to the first column.
+indent_ctor_init = 0 # number
+
+# Whether to indent 'if' following 'else' as a new block under the 'else'.
+# If false, 'else\nif' is treated as 'else if' for indenting purposes.
+indent_else_if = false # true/false
+
+# Amount to indent variable declarations after a open brace.
+#
+# <0: Relative
+# >=0: Absolute
+indent_var_def_blk = 0 # number
+
+# Whether to indent continued variable declarations instead of aligning.
+indent_var_def_cont = false # true/false
+
+# Whether to indent continued shift expressions ('<<' and '>>') instead of
+# aligning. Set align_left_shift=false when enabling this.
+indent_shift = false # true/false
+
+# Whether to force indentation of function definitions to start in column 1.
+indent_func_def_force_col1 = false # true/false
+
+# Whether to indent continued function call parameters one indent level,
+# rather than aligning parameters under the open parenthesis.
+indent_func_call_param = false # true/false
+
+# Whether to indent continued function definition parameters one indent level,
+# rather than aligning parameters under the open parenthesis.
+indent_func_def_param = false # true/false
+
+# for function definitions, only if indent_func_def_param is false
+# Allows to align params when appropriate and indent them when not
+# behave as if it was true if paren position is more than this value
+# if paren position is more than the option value
+indent_func_def_param_paren_pos_threshold = 0 # unsigned number
+
+# Whether to indent continued function call prototype one indent level,
+# rather than aligning parameters under the open parenthesis.
+indent_func_proto_param = false # true/false
+
+# Whether to indent continued function call declaration one indent level,
+# rather than aligning parameters under the open parenthesis.
+indent_func_class_param = false # true/false
+
+# Whether to indent continued class variable constructors one indent level,
+# rather than aligning parameters under the open parenthesis.
+indent_func_ctor_var_param = false # true/false
+
+# Whether to indent continued template parameter list one indent level,
+# rather than aligning parameters under the open parenthesis.
+indent_template_param = false # true/false
+
+# Double the indent for indent_func_xxx_param options.
+# Use both values of the options indent_columns and indent_param.
+indent_func_param_double = false # true/false
+
+# Indentation column for standalone 'const' qualifier on a function
+# prototype.
+indent_func_const = 0 # unsigned number
+
+# Indentation column for standalone 'throw' qualifier on a function
+# prototype.
+indent_func_throw = 0 # unsigned number
+
+# How to indent within a macro followed by a brace on the same line
+# This allows reducing the indent in macros that have (for example)
+# `do { ... } while (0)` blocks bracketing them.
+#
+# true: add an indent for the brace on the same line as the macro
+# false: do not add an indent for the brace on the same line as the macro
+#
+# Default: true
+indent_macro_brace = false # true/false
+
+# The number of spaces to indent a continued '->' or '.'.
+# Usually set to 0, 1, or indent_columns.
+indent_member = 0 # unsigned number
+
+# Whether lines broken at '.' or '->' should be indented by a single indent.
+# The indent_member option will not be effective if this is set to true.
+indent_member_single = false # true/false
+
+# Spaces to indent single line ('//') comments on lines before code.
+indent_single_line_comments_before = 0 # unsigned number
+
+# Spaces to indent single line ('//') comments on lines after code.
+indent_single_line_comments_after = 0 # unsigned number
+
+# When opening a paren for a control statement (if, for, while, etc), increase
+# the indent level by this value. Negative values decrease the indent level.
+indent_sparen_extra = 0 # number
+
+# Whether to indent trailing single line ('//') comments relative to the code
+# instead of trying to keep the same absolute column.
+indent_relative_single_line_comments = true # true/false
+
+# Spaces to indent 'case' from 'switch'. Usually 0 or indent_columns.
+# It might wise to choose the same value for the option indent_case_brace.
+indent_switch_case = 0 # unsigned number
+
+# Spaces to indent '{' from 'case'. By default, the brace will appear under
+# the 'c' in case. Usually set to 0 or indent_columns. Negative values are OK.
+# It might wise to choose the same value for the option indent_switch_case.
+indent_case_brace = 0 # number
+
+# indent 'break' with 'case' from 'switch'.
+indent_switch_break_with_case = false # true/false
+
+# Whether to indent preprocessor statements inside of switch statements.
+#
+# Default: true
+indent_switch_pp = true # true/false
+
+# Spaces to shift the 'case' line, without affecting any other lines.
+# Usually 0.
+indent_case_shift = 0 # unsigned number
+
+# Whether to indent comments found in first column.
+indent_col1_comment = false # true/false
+
+# Whether to indent multi string literal in first column.
+indent_col1_multi_string_literal = false # true/false
+
+# How to indent goto labels.
+#
+# >0: Absolute column where 1 is the leftmost column
+# <=0: Subtract from brace indent
+#
+# Default: 1
+indent_label = 1 # number
+
+# How to indent access specifiers that are followed by a
+# colon.
+#
+# >0: Absolute column where 1 is the leftmost column
+# <=0: Subtract from brace indent
+#
+# Default: 1
+indent_access_spec = 1 # number
+
+# Whether to indent the code after an access specifier by one level.
+# If true, this option forces 'indent_access_spec=0'.
+indent_access_spec_body = false # true/false
+
+# If an open parenthesis is followed by a newline, whether to indent the next
+# line so that it lines up after the open parenthesis (not recommended).
+indent_paren_nl = false # true/false
+
+# How to indent a close parenthesis after a newline.
+#
+# 0: Indent to body level (default)
+# 1: Align under the open parenthesis
+# 2: Indent to the brace level
+indent_paren_close = 0 # unsigned number
+
+# Whether to indent the open parenthesis of a function definition,
+# if the parenthesis is on its own line.
+indent_paren_after_func_def = false # true/false
+
+# Whether to indent the open parenthesis of a function declaration,
+# if the parenthesis is on its own line.
+indent_paren_after_func_decl = false # true/false
+
+# Whether to indent the open parenthesis of a function call,
+# if the parenthesis is on its own line.
+indent_paren_after_func_call = true # true/false
+
+# Whether to indent a comma when inside a brace.
+# If true, aligns under the open brace.
+indent_comma_brace = false # true/false
+
+# Whether to indent a comma when inside a parenthesis.
+# If true, aligns under the open parenthesis.
+indent_comma_paren = false # true/false
+
+# Whether to indent a Boolean operator when inside a parenthesis.
+# If true, aligns under the open parenthesis.
+indent_bool_paren = false # true/false
+
+# Whether to indent a semicolon when inside a for parenthesis.
+# If true, aligns under the open for parenthesis.
+indent_semicolon_for_paren = false # true/false
+
+# Whether to align the first expression to following ones
+# if indent_bool_paren=true.
+indent_first_bool_expr = false # true/false
+
+# Whether to align the first expression to following ones
+# if indent_semicolon_for_paren=true.
+indent_first_for_expr = false # true/false
+
+# If an open square is followed by a newline, whether to indent the next line
+# so that it lines up after the open square (not recommended).
+indent_square_nl = false # true/false
+
+# (ESQL/C) Whether to preserve the relative indent of 'EXEC SQL' bodies.
+indent_preserve_sql = false # true/false
+
+# Whether to align continued statements at the '='. If false or if the '=' is
+# followed by a newline, the next line is indent one tab.
+#
+# Default: true
+indent_align_assign = true # true/false
+
+# If true, the indentation of the chunks after a '=' sequence will be set at
+# LHS token indentation column before '='.
+indent_off_after_assign = false # true/false
+
+# Whether to align continued statements at the '('. If false or the '(' is
+# followed by a newline, the next line indent is one tab.
+#
+# Default: true
+indent_align_paren = true # true/false
+
+# (OC) Whether to indent Objective-C code inside message selectors.
+indent_oc_inside_msg_sel = false # true/false
+
+# (OC) Whether to indent Objective-C blocks at brace level instead of usual
+# rules.
+indent_oc_block = false # true/false
+
+# (OC) Indent for Objective-C blocks in a message relative to the parameter
+# name.
+#
+# =0: Use indent_oc_block rules
+# >0: Use specified number of spaces to indent
+indent_oc_block_msg = 0 # unsigned number
+
+# (OC) Minimum indent for subsequent parameters
+indent_oc_msg_colon = 0 # unsigned number
+
+# (OC) Whether to prioritize aligning with initial colon (and stripping spaces
+# from lines, if necessary).
+#
+# Default: true
+indent_oc_msg_prioritize_first_colon = true # true/false
+
+# (OC) Whether to indent blocks the way that Xcode does by default
+# (from the keyword if the parameter is on its own line; otherwise, from the
+# previous indentation level). Requires indent_oc_block_msg=true.
+indent_oc_block_msg_xcode_style = false # true/false
+
+# (OC) Whether to indent blocks from where the brace is, relative to a
+# message keyword. Requires indent_oc_block_msg=true.
+indent_oc_block_msg_from_keyword = false # true/false
+
+# (OC) Whether to indent blocks from where the brace is, relative to a message
+# colon. Requires indent_oc_block_msg=true.
+indent_oc_block_msg_from_colon = false # true/false
+
+# (OC) Whether to indent blocks from where the block caret is.
+# Requires indent_oc_block_msg=true.
+indent_oc_block_msg_from_caret = false # true/false
+
+# (OC) Whether to indent blocks from where the brace caret is.
+# Requires indent_oc_block_msg=true.
+indent_oc_block_msg_from_brace = false # true/false
+
+# When indenting after virtual brace open and newline add further spaces to
+# reach this minimum indent.
+indent_min_vbrace_open = 0 # unsigned number
+
+# Whether to add further spaces after regular indent to reach next tabstop
+# when indenting after virtual brace open and newline.
+indent_vbrace_open_on_tabstop = false # true/false
+
+# How to indent after a brace followed by another token (not a newline).
+# true: indent all contained lines to match the token
+# false: indent all contained lines to match the brace
+#
+# Default: true
+indent_token_after_brace = true # true/false
+
+# Whether to indent the body of a C++11 lambda.
+indent_cpp_lambda_body = false # true/false
+
+# How to indent compound literals that are being returned.
+# true: add both the indent from return & the compound literal open brace
+# (i.e. 2 indent levels)
+# false: only indent 1 level, don't add the indent for the open brace, only
+# add the indent for the return.
+#
+# Default: true
+indent_compound_literal_return = false # true/false
+
+# (C#) Whether to indent a 'using' block if no braces are used.
+#
+# Default: true
+indent_using_block = true # true/false
+
+# How to indent the continuation of ternary operator.
+#
+# 0: Off (default)
+# 1: When the `if_false` is a continuation, indent it under `if_false`
+# 2: When the `:` is a continuation, indent it under `?`
+indent_ternary_operator = 2 # unsigned number
+
+# Whether to indent the statements inside ternary operator.
+indent_inside_ternary_operator = false # true/false
+
+# If true, the indentation of the chunks after a `return` sequence will be set at return indentation column.
+indent_off_after_return = false # true/false
+
+# If true, the indentation of the chunks after a `return new` sequence will be set at return indentation column.
+indent_off_after_return_new = false # true/false
+
+# If true, the tokens after return are indented with regular single indentation. By default (false) the indentation is after the return token.
+indent_single_after_return = false # true/false
+
+# Whether to ignore indent and alignment for 'asm' blocks (i.e. assume they
+# have their own indentation).
+indent_ignore_asm_block = false # true/false
+
+# Don't indent the close parenthesis of a function definition,
+# if the parenthesis is on its own line.
+donot_indent_func_def_close_paren = false # true/false
+
+#
+# Newline adding and removing options
+#
+
+# Whether to collapse empty blocks between '{' and '}'.
+# If true, overrides nl_inside_empty_func
+nl_collapse_empty_body = false # true/false
+
+# Don't split one-line braced assignments, as in 'foo_t f = { 1, 2 };'.
+nl_assign_leave_one_liners = false # true/false
+
+# Don't split one-line braced statements inside a 'class xx { }' body.
+nl_class_leave_one_liners = false # true/false
+
+# Don't split one-line enums, as in 'enum foo { BAR = 15 };'
+nl_enum_leave_one_liners = false # true/false
+
+# Don't split one-line get or set functions.
+nl_getset_leave_one_liners = false # true/false
+
+# (C#) Don't split one-line property get or set functions.
+nl_cs_property_leave_one_liners = false # true/false
+
+# Don't split one-line function definitions, as in 'int foo() { return 0; }'.
+# might modify nl_func_type_name
+nl_func_leave_one_liners = false # true/false
+
+# Don't split one-line C++11 lambdas, as in '[]() { return 0; }'.
+nl_cpp_lambda_leave_one_liners = false # true/false
+
+# Don't split one-line if/else statements, as in 'if(...) b++;'.
+nl_if_leave_one_liners = false # true/false
+
+# Don't split one-line while statements, as in 'while(...) b++;'.
+nl_while_leave_one_liners = false # true/false
+
+# Don't split one-line do statements, as in 'do { b++; } while(...);'.
+nl_do_leave_one_liners = false # true/false
+
+# Don't split one-line for statements, as in 'for(...) b++;'.
+nl_for_leave_one_liners = false # true/false
+
+# (OC) Don't split one-line Objective-C messages.
+nl_oc_msg_leave_one_liner = false # true/false
+
+# (OC) Add or remove newline between method declaration and '{'.
+nl_oc_mdef_brace = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove newline between Objective-C block signature and '{'.
+nl_oc_block_brace = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove blank line before '@interface' statement.
+nl_oc_before_interface = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove blank line before '@implementation' statement.
+nl_oc_before_implementation = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove blank line before '@end' statement.
+nl_oc_before_end = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove newline between '@interface' and '{'.
+nl_oc_interface_brace = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove newline between '@implementation' and '{'.
+nl_oc_implementation_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newlines at the start of the file.
+nl_start_of_file = ignore # ignore/add/remove/force/not_defined
+
+# The minimum number of newlines at the start of the file (only used if
+# nl_start_of_file is 'add' or 'force').
+nl_start_of_file_min = 0 # unsigned number
+
+# Add or remove newline at the end of the file.
+nl_end_of_file = ignore # ignore/add/remove/force/not_defined
+
+# The minimum number of newlines at the end of the file (only used if
+# nl_end_of_file is 'add' or 'force').
+nl_end_of_file_min = 0 # unsigned number
+
+# Add or remove newline between '=' and '{'.
+nl_assign_brace = ignore # ignore/add/remove/force/not_defined
+
+# (D) Add or remove newline between '=' and '['.
+nl_assign_square = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between '[]' and '{'.
+nl_tsquare_brace = ignore # ignore/add/remove/force/not_defined
+
+# (D) Add or remove newline after '= ['. Will also affect the newline before
+# the ']'.
+nl_after_square_assign = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between a function call's ')' and '{', as in
+# 'list_for_each(item, &list) { }'.
+nl_fcall_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between 'enum' and '{'.
+nl_enum_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between 'enum' and 'class'.
+nl_enum_class = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between 'enum class' and the identifier.
+nl_enum_class_identifier = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between 'enum class' type and ':'.
+nl_enum_identifier_colon = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between 'enum class identifier :' and type.
+nl_enum_colon_type = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between 'struct and '{'.
+nl_struct_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between 'union' and '{'.
+nl_union_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between 'if' and '{'.
+nl_if_brace = remove # ignore/add/remove/force/not_defined
+
+# Add or remove newline between '}' and 'else'.
+nl_brace_else = remove # ignore/add/remove/force/not_defined
+
+# Add or remove newline between 'else if' and '{'. If set to ignore,
+# nl_if_brace is used instead.
+nl_elseif_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between 'else' and '{'.
+nl_else_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between 'else' and 'if'.
+nl_else_if = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline before '{' opening brace
+nl_before_opening_brace_func_class_def = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline before 'if'/'else if' closing parenthesis.
+nl_before_if_closing_paren = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between '}' and 'finally'.
+nl_brace_finally = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between 'finally' and '{'.
+nl_finally_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between 'try' and '{'.
+nl_try_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between get/set and '{'.
+nl_getset_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between 'for' and '{'.
+nl_for_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline before the '{' of a 'catch' statement, as in
+# 'catch (decl) <here> {'.
+nl_catch_brace = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove newline before the '{' of a '@catch' statement, as in
+# '@catch (decl) <here> {'. If set to ignore, nl_catch_brace is used.
+nl_oc_catch_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between '}' and 'catch'.
+nl_brace_catch = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Add or remove newline between '}' and '@catch'. If set to ignore,
+# nl_brace_catch is used.
+nl_oc_brace_catch = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between '}' and ']'.
+nl_brace_square = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between '}' and ')' in a function invocation.
+nl_brace_fparen = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between 'while' and '{'.
+nl_while_brace = ignore # ignore/add/remove/force/not_defined
+
+# (D) Add or remove newline between 'scope (x)' and '{'.
+nl_scope_brace = ignore # ignore/add/remove/force/not_defined
+
+# (D) Add or remove newline between 'unittest' and '{'.
+nl_unittest_brace = ignore # ignore/add/remove/force/not_defined
+
+# (D) Add or remove newline between 'version (x)' and '{'.
+nl_version_brace = ignore # ignore/add/remove/force/not_defined
+
+# (C#) Add or remove newline between 'using' and '{'.
+nl_using_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between two open or close braces. Due to general
+# newline/brace handling, REMOVE may not work.
+nl_brace_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between 'do' and '{'.
+nl_do_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between '}' and 'while' of 'do' statement.
+nl_brace_while = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between 'switch' and '{'.
+nl_switch_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between 'synchronized' and '{'.
+nl_synchronized_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add a newline between ')' and '{' if the ')' is on a different line than the
+# if/for/etc.
+#
+# Overrides nl_for_brace, nl_if_brace, nl_switch_brace, nl_while_switch and
+# nl_catch_brace.
+nl_multi_line_cond = false # true/false
+
+# Add a newline after '(' if an if/for/while/switch condition spans multiple
+# lines
+nl_multi_line_sparen_open = ignore # ignore/add/remove/force/not_defined
+
+# Add a newline before ')' if an if/for/while/switch condition spans multiple
+# lines. Overrides nl_before_if_closing_paren if both are specified.
+nl_multi_line_sparen_close = remove # ignore/add/remove/force/not_defined
+
+# Force a newline in a define after the macro name for multi-line defines.
+nl_multi_line_define = false # true/false
+
+# Whether to add a newline before 'case', and a blank line before a 'case'
+# statement that follows a ';' or '}'.
+nl_before_case = false # true/false
+
+# Whether to add a newline after a 'case' statement.
+nl_after_case = true # true/false
+
+# Add or remove newline between a case ':' and '{'.
+#
+# Overrides nl_after_case.
+nl_case_colon_brace = remove # ignore/add/remove/force/not_defined
+
+# Add or remove newline between ')' and 'throw'.
+nl_before_throw = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between 'namespace' and '{'.
+nl_namespace_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline after 'template<...>' of a template class.
+nl_template_class = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline after 'template<...>' of a template class declaration.
+#
+# Overrides nl_template_class.
+nl_template_class_decl = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline after 'template<>' of a specialized class declaration.
+#
+# Overrides nl_template_class_decl.
+nl_template_class_decl_special = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline after 'template<...>' of a template class definition.
+#
+# Overrides nl_template_class.
+nl_template_class_def = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline after 'template<>' of a specialized class definition.
+#
+# Overrides nl_template_class_def.
+nl_template_class_def_special = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline after 'template<...>' of a template function.
+nl_template_func = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline after 'template<...>' of a template function
+# declaration.
+#
+# Overrides nl_template_func.
+nl_template_func_decl = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline after 'template<>' of a specialized function
+# declaration.
+#
+# Overrides nl_template_func_decl.
+nl_template_func_decl_special = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline after 'template<...>' of a template function
+# definition.
+#
+# Overrides nl_template_func.
+nl_template_func_def = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline after 'template<>' of a specialized function
+# definition.
+#
+# Overrides nl_template_func_def.
+nl_template_func_def_special = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline after 'template<...>' of a template variable.
+nl_template_var = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between 'template<...>' and 'using' of a templated
+# type alias.
+nl_template_using = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between 'class' and '{'.
+nl_class_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline before or after (depending on pos_class_comma,
+# may not be IGNORE) each',' in the base class list.
+nl_class_init_args = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline after each ',' in the constructor member
+# initialization. Related to nl_constr_colon, pos_constr_colon and
+# pos_constr_comma.
+nl_constr_init_args = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline before first element, after comma, and after last
+# element, in 'enum'.
+nl_enum_own_lines = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between return type and function name in a function
+# definition.
+# might be modified by nl_func_leave_one_liners
+nl_func_type_name = remove # ignore/add/remove/force/not_defined
+
+# Add or remove newline between return type and function name inside a class
+# definition. If set to ignore, nl_func_type_name or nl_func_proto_type_name
+# is used instead.
+nl_func_type_name_class = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between class specification and '::'
+# in 'void A::f() { }'. Only appears in separate member implementation (does
+# not appear with in-line implementation).
+nl_func_class_scope = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between function scope and name, as in
+# 'void A :: <here> f() { }'.
+nl_func_scope_name = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between return type and function name in a prototype.
+nl_func_proto_type_name = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between a function name and the opening '(' in the
+# declaration.
+nl_func_paren = ignore # ignore/add/remove/force/not_defined
+
+# Overrides nl_func_paren for functions with no parameters.
+nl_func_paren_empty = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between a function name and the opening '(' in the
+# definition.
+nl_func_def_paren = ignore # ignore/add/remove/force/not_defined
+
+# Overrides nl_func_def_paren for functions with no parameters.
+nl_func_def_paren_empty = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between a function name and the opening '(' in the
+# call.
+nl_func_call_paren = ignore # ignore/add/remove/force/not_defined
+
+# Overrides nl_func_call_paren for functions with no parameters.
+nl_func_call_paren_empty = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline after '(' in a function declaration.
+nl_func_decl_start = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline after '(' in a function definition.
+nl_func_def_start = remove # ignore/add/remove/force/not_defined
+
+# Overrides nl_func_decl_start when there is only one parameter.
+nl_func_decl_start_single = ignore # ignore/add/remove/force/not_defined
+
+# Overrides nl_func_def_start when there is only one parameter.
+nl_func_def_start_single = ignore # ignore/add/remove/force/not_defined
+
+# Whether to add a newline after '(' in a function declaration if '(' and ')'
+# are in different lines. If false, nl_func_decl_start is used instead.
+nl_func_decl_start_multi_line = false # true/false
+
+# Whether to add a newline after '(' in a function definition if '(' and ')'
+# are in different lines. If false, nl_func_def_start is used instead.
+nl_func_def_start_multi_line = false # true/false
+
+# Add or remove newline after each ',' in a function declaration.
+nl_func_decl_args = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline after each ',' in a function definition.
+nl_func_def_args = remove # ignore/add/remove/force/not_defined
+
+# Add or remove newline after each ',' in a function call.
+nl_func_call_args = ignore # ignore/add/remove/force/not_defined
+
+# Whether to add a newline after each ',' in a function declaration if '('
+# and ')' are in different lines. If false, nl_func_decl_args is used instead.
+nl_func_decl_args_multi_line = false # true/false
+
+# Whether to add a newline after each ',' in a function definition if '('
+# and ')' are in different lines. If false, nl_func_def_args is used instead.
+nl_func_def_args_multi_line = false # true/false
+
+# Add or remove newline before the ')' in a function declaration.
+nl_func_decl_end = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline before the ')' in a function definition.
+nl_func_def_end = remove # ignore/add/remove/force/not_defined
+
+# Overrides nl_func_decl_end when there is only one parameter.
+nl_func_decl_end_single = ignore # ignore/add/remove/force/not_defined
+
+# Overrides nl_func_def_end when there is only one parameter.
+nl_func_def_end_single = ignore # ignore/add/remove/force/not_defined
+
+# Whether to add a newline before ')' in a function declaration if '(' and ')'
+# are in different lines. If false, nl_func_decl_end is used instead.
+nl_func_decl_end_multi_line = false # true/false
+
+# Whether to add a newline before ')' in a function definition if '(' and ')'
+# are in different lines. If false, nl_func_def_end is used instead.
+nl_func_def_end_multi_line = false # true/false
+
+# Add or remove newline between '()' in a function declaration.
+nl_func_decl_empty = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between '()' in a function definition.
+nl_func_def_empty = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between '()' in a function call.
+nl_func_call_empty = ignore # ignore/add/remove/force/not_defined
+
+# Whether to add a newline after '(' in a function call,
+# has preference over nl_func_call_start_multi_line.
+nl_func_call_start = remove # ignore/add/remove/force/not_defined
+
+# Whether to add a newline before ')' in a function call.
+nl_func_call_end = ignore # ignore/add/remove/force/not_defined
+
+# Whether to add a newline after '(' in a function call if '(' and ')' are in
+# different lines.
+nl_func_call_start_multi_line = false # true/false
+
+# Whether to add a newline after each ',' in a function call if '(' and ')'
+# are in different lines.
+nl_func_call_args_multi_line = false # true/false
+
+# Whether to add a newline before ')' in a function call if '(' and ')' are in
+# different lines.
+nl_func_call_end_multi_line = false # true/false
+
+# Whether to respect nl_func_call_XXX option in case of closure args.
+nl_func_call_args_multi_line_ignore_closures = false # true/false
+
+# Whether to add a newline after '<' of a template parameter list.
+nl_template_start = false # true/false
+
+# Whether to add a newline after each ',' in a template parameter list.
+nl_template_args = false # true/false
+
+# Whether to add a newline before '>' of a template parameter list.
+nl_template_end = false # true/false
+
+# (OC) Whether to put each Objective-C message parameter on a separate line.
+# See nl_oc_msg_leave_one_liner.
+nl_oc_msg_args = false # true/false
+
+# Add or remove newline between function signature and '{'.
+nl_fdef_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between function signature and '{',
+# if signature ends with ')'. Overrides nl_fdef_brace.
+nl_fdef_brace_cond = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between C++11 lambda signature and '{'.
+nl_cpp_ldef_brace = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline between 'return' and the return expression.
+nl_return_expr = ignore # ignore/add/remove/force/not_defined
+
+# Whether to add a newline after semicolons, except in 'for' statements.
+nl_after_semicolon = false # true/false
+
+# (Java) Add or remove newline between the ')' and '{{' of the double brace
+# initializer.
+nl_paren_dbrace_open = ignore # ignore/add/remove/force/not_defined
+
+# Whether to add a newline after the type in an unnamed temporary
+# direct-list-initialization.
+nl_type_brace_init_lst = ignore # ignore/add/remove/force/not_defined
+
+# Whether to add a newline after the open brace in an unnamed temporary
+# direct-list-initialization.
+nl_type_brace_init_lst_open = ignore # ignore/add/remove/force/not_defined
+
+# Whether to add a newline before the close brace in an unnamed temporary
+# direct-list-initialization.
+nl_type_brace_init_lst_close = ignore # ignore/add/remove/force/not_defined
+
+# Whether to add a newline before '{'.
+nl_before_brace_open = false # true/false
+
+# Whether to add a newline after '{'.
+nl_after_brace_open = false # true/false
+
+# Whether to add a newline between the open brace and a trailing single-line
+# comment. Requires nl_after_brace_open=true.
+nl_after_brace_open_cmt = false # true/false
+
+# Whether to add a newline after a virtual brace open with a non-empty body.
+# These occur in un-braced if/while/do/for statement bodies.
+nl_after_vbrace_open = false # true/false
+
+# Whether to add a newline after a virtual brace open with an empty body.
+# These occur in un-braced if/while/do/for statement bodies.
+nl_after_vbrace_open_empty = false # true/false
+
+# Whether to add a newline after '}'. Does not apply if followed by a
+# necessary ';'.
+nl_after_brace_close = false # true/false
+
+# Whether to add a newline after a virtual brace close,
+# as in 'if (foo) a++; <here> return;'.
+nl_after_vbrace_close = false # true/false
+
+# Add or remove newline between the close brace and identifier,
+# as in 'struct { int a; } <here> b;'. Affects enumerations, unions and
+# structures. If set to ignore, uses nl_after_brace_close.
+nl_brace_struct_var = ignore # ignore/add/remove/force/not_defined
+
+# Whether to alter newlines in '#define' macros.
+nl_define_macro = false # true/false
+
+# Whether to alter newlines between consecutive parenthesis closes. The number
+# of closing parentheses in a line will depend on respective open parenthesis
+# lines.
+nl_squeeze_paren_close = false # true/false
+
+# Whether to remove blanks after '#ifxx' and '#elxx', or before '#elxx' and
+# '#endif'. Does not affect top-level #ifdefs.
+nl_squeeze_ifdef = false # true/false
+
+# Makes the nl_squeeze_ifdef option affect the top-level #ifdefs as well.
+nl_squeeze_ifdef_top_level = false # true/false
+
+# Add or remove blank line before 'if'.
+nl_before_if = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove blank line after 'if' statement. Add/Force work only if the
+# next token is not a closing brace.
+nl_after_if = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove blank line before 'for'.
+nl_before_for = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove blank line after 'for' statement.
+nl_after_for = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove blank line before 'while'.
+nl_before_while = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove blank line after 'while' statement.
+nl_after_while = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove blank line before 'switch'.
+nl_before_switch = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove blank line after 'switch' statement.
+nl_after_switch = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove blank line before 'synchronized'.
+nl_before_synchronized = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove blank line after 'synchronized' statement.
+nl_after_synchronized = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove blank line before 'do'.
+nl_before_do = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove blank line after 'do/while' statement.
+nl_after_do = ignore # ignore/add/remove/force/not_defined
+
+# Ignore nl_before_{if,for,switch,do,synchronized} if the control
+# statement is immediately after a case statement.
+# if nl_before_{if,for,switch,do} is set to remove, this option
+# does nothing.
+nl_before_ignore_after_case = false # true/false
+
+# Whether to put a blank line before 'return' statements, unless after an open
+# brace.
+nl_before_return = false # true/false
+
+# Whether to put a blank line after 'return' statements, unless followed by a
+# close brace.
+nl_after_return = false # true/false
+
+# Whether to put a blank line before a member '.' or '->' operators.
+nl_before_member = ignore # ignore/add/remove/force/not_defined
+
+# (Java) Whether to put a blank line after a member '.' or '->' operators.
+nl_after_member = ignore # ignore/add/remove/force/not_defined
+
+# Whether to double-space commented-entries in 'struct'/'union'/'enum'.
+nl_ds_struct_enum_cmt = false # true/false
+
+# Whether to force a newline before '}' of a 'struct'/'union'/'enum'.
+# (Lower priority than eat_blanks_before_close_brace.)
+nl_ds_struct_enum_close_brace = false # true/false
+
+# Add or remove newline before or after (depending on pos_class_colon) a class
+# colon, as in 'class Foo <here> : <or here> public Bar'.
+nl_class_colon = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove newline around a class constructor colon. The exact position
+# depends on nl_constr_init_args, pos_constr_colon and pos_constr_comma.
+nl_constr_colon = ignore # ignore/add/remove/force/not_defined
+
+# Whether to collapse a two-line namespace, like 'namespace foo\n{ decl; }'
+# into a single line. If true, prevents other brace newline rules from turning
+# such code into four lines. If true, it also preserves one-liner namespaces.
+nl_namespace_two_to_one_liner = false # true/false
+
+# Whether to remove a newline in simple unbraced if statements, turning them
+# into one-liners, as in 'if(b)\n i++;' => 'if(b) i++;'.
+nl_create_if_one_liner = false # true/false
+
+# Whether to remove a newline in simple unbraced for statements, turning them
+# into one-liners, as in 'for (...)\n stmt;' => 'for (...) stmt;'.
+nl_create_for_one_liner = false # true/false
+
+# Whether to remove a newline in simple unbraced while statements, turning
+# them into one-liners, as in 'while (expr)\n stmt;' => 'while (expr) stmt;'.
+nl_create_while_one_liner = false # true/false
+
+# Whether to collapse a function definition whose body (not counting braces)
+# is only one line so that the entire definition (prototype, braces, body) is
+# a single line.
+nl_create_func_def_one_liner = false # true/false
+
+# Whether to split one-line simple list definitions into three lines by
+# adding newlines, as in 'int a[12] = { <here> 0 <here> };'.
+nl_create_list_one_liner = false # true/false
+
+# Whether to split one-line simple unbraced if statements into two lines by
+# adding a newline, as in 'if(b) <here> i++;'.
+nl_split_if_one_liner = false # true/false
+
+# Whether to split one-line simple unbraced for statements into two lines by
+# adding a newline, as in 'for (...) <here> stmt;'.
+nl_split_for_one_liner = false # true/false
+
+# Whether to split one-line simple unbraced while statements into two lines by
+# adding a newline, as in 'while (expr) <here> stmt;'.
+nl_split_while_one_liner = false # true/false
+
+# Don't add a newline before a cpp-comment in a parameter list of a function
+# call.
+donot_add_nl_before_cpp_comment = false # true/false
+
+#
+# Blank line options
+#
+
+# The maximum number of consecutive newlines (3 = 2 blank lines).
+nl_max = 0 # unsigned number
+
+# The maximum number of consecutive newlines in a function.
+nl_max_blank_in_func = 0 # unsigned number
+
+# The number of newlines inside an empty function body.
+# This option overrides eat_blanks_after_open_brace and
+# eat_blanks_before_close_brace, but is ignored when
+# nl_collapse_empty_body=true
+nl_inside_empty_func = 0 # unsigned number
+
+# The number of newlines before a function prototype.
+nl_before_func_body_proto = 0 # unsigned number
+
+# The number of newlines before a multi-line function definition. Where
+# applicable, this option is overridden with eat_blanks_after_open_brace=true
+nl_before_func_body_def = 0 # unsigned number
+
+# The number of newlines before a class constructor/destructor prototype.
+nl_before_func_class_proto = 0 # unsigned number
+
+# The number of newlines before a class constructor/destructor definition.
+nl_before_func_class_def = 0 # unsigned number
+
+# The number of newlines after a function prototype.
+nl_after_func_proto = 0 # unsigned number
+
+# The number of newlines after a function prototype, if not followed by
+# another function prototype.
+nl_after_func_proto_group = 0 # unsigned number
+
+# The number of newlines after a class constructor/destructor prototype.
+nl_after_func_class_proto = 0 # unsigned number
+
+# The number of newlines after a class constructor/destructor prototype,
+# if not followed by another constructor/destructor prototype.
+nl_after_func_class_proto_group = 0 # unsigned number
+
+# Whether one-line method definitions inside a class body should be treated
+# as if they were prototypes for the purposes of adding newlines.
+#
+# Requires nl_class_leave_one_liners=true. Overrides nl_before_func_body_def
+# and nl_before_func_class_def for one-liners.
+nl_class_leave_one_liner_groups = false # true/false
+
+# The number of newlines after '}' of a multi-line function body.
+nl_after_func_body = 0 # unsigned number
+
+# The number of newlines after '}' of a multi-line function body in a class
+# declaration. Also affects class constructors/destructors.
+#
+# Overrides nl_after_func_body.
+nl_after_func_body_class = 0 # unsigned number
+
+# The number of newlines after '}' of a single line function body. Also
+# affects class constructors/destructors.
+#
+# Overrides nl_after_func_body and nl_after_func_body_class.
+nl_after_func_body_one_liner = 0 # unsigned number
+
+# The number of blank lines after a block of variable definitions at the top
+# of a function body.
+#
+# 0: No change (default).
+nl_func_var_def_blk = 0 # unsigned number
+
+# The number of newlines before a block of typedefs. If nl_after_access_spec
+# is non-zero, that option takes precedence.
+#
+# 0: No change (default).
+nl_typedef_blk_start = 0 # unsigned number
+
+# The number of newlines after a block of typedefs.
+#
+# 0: No change (default).
+nl_typedef_blk_end = 0 # unsigned number
+
+# The maximum number of consecutive newlines within a block of typedefs.
+#
+# 0: No change (default).
+nl_typedef_blk_in = 0 # unsigned number
+
+# The number of newlines before a block of variable definitions not at the top
+# of a function body. If nl_after_access_spec is non-zero, that option takes
+# precedence.
+#
+# 0: No change (default).
+nl_var_def_blk_start = 0 # unsigned number
+
+# The number of newlines after a block of variable definitions not at the top
+# of a function body.
+#
+# 0: No change (default).
+nl_var_def_blk_end = 0 # unsigned number
+
+# The maximum number of consecutive newlines within a block of variable
+# definitions.
+#
+# 0: No change (default).
+nl_var_def_blk_in = 0 # unsigned number
+
+# The minimum number of newlines before a multi-line comment.
+# Doesn't apply if after a brace open or another multi-line comment.
+nl_before_block_comment = 0 # unsigned number
+
+# The minimum number of newlines before a single-line C comment.
+# Doesn't apply if after a brace open or other single-line C comments.
+nl_before_c_comment = 0 # unsigned number
+
+# The minimum number of newlines before a CPP comment.
+# Doesn't apply if after a brace open or other CPP comments.
+nl_before_cpp_comment = 0 # unsigned number
+
+# Whether to force a newline after a multi-line comment.
+nl_after_multiline_comment = false # true/false
+
+# Whether to force a newline after a label's colon.
+nl_after_label_colon = false # true/false
+
+# The number of newlines before a struct definition.
+nl_before_struct = 0 # unsigned number
+
+# The number of newlines after '}' or ';' of a struct/enum/union definition.
+nl_after_struct = 0 # unsigned number
+
+# The number of newlines before a class definition.
+nl_before_class = 0 # unsigned number
+
+# The number of newlines after '}' or ';' of a class definition.
+nl_after_class = 0 # unsigned number
+
+# The number of newlines before a namespace.
+nl_before_namespace = 0 # unsigned number
+
+# The number of newlines after '{' of a namespace. This also adds newlines
+# before the matching '}'.
+#
+# 0: Apply eat_blanks_after_open_brace or eat_blanks_before_close_brace if
+# applicable, otherwise no change.
+#
+# Overrides eat_blanks_after_open_brace and eat_blanks_before_close_brace.
+nl_inside_namespace = 0 # unsigned number
+
+# The number of newlines after '}' of a namespace.
+nl_after_namespace = 0 # unsigned number
+
+# The number of newlines before an access specifier label. This also includes
+# the Qt-specific 'signals:' and 'slots:'. Will not change the newline count
+# if after a brace open.
+#
+# 0: No change (default).
+nl_before_access_spec = 0 # unsigned number
+
+# The number of newlines after an access specifier label. This also includes
+# the Qt-specific 'signals:' and 'slots:'. Will not change the newline count
+# if after a brace open.
+#
+# 0: No change (default).
+#
+# Overrides nl_typedef_blk_start and nl_var_def_blk_start.
+nl_after_access_spec = 0 # unsigned number
+
+# The number of newlines between a function definition and the function
+# comment, as in '// comment\n <here> void foo() {...}'.
+#
+# 0: No change (default).
+nl_comment_func_def = 0 # unsigned number
+
+# The number of newlines after a try-catch-finally block that isn't followed
+# by a brace close.
+#
+# 0: No change (default).
+nl_after_try_catch_finally = 0 # unsigned number
+
+# (C#) The number of newlines before and after a property, indexer or event
+# declaration.
+#
+# 0: No change (default).
+nl_around_cs_property = 0 # unsigned number
+
+# (C#) The number of newlines between the get/set/add/remove handlers.
+#
+# 0: No change (default).
+nl_between_get_set = 0 # unsigned number
+
+# (C#) Add or remove newline between property and the '{'.
+nl_property_brace = ignore # ignore/add/remove/force/not_defined
+
+# Whether to remove blank lines after '{'.
+eat_blanks_after_open_brace = true # true/false
+
+# Whether to remove blank lines before '}'.
+eat_blanks_before_close_brace = true # true/false
+
+# How aggressively to remove extra newlines not in preprocessor.
+#
+# 0: No change (default)
+# 1: Remove most newlines not handled by other config
+# 2: Remove all newlines and reformat completely by config
+nl_remove_extra_newlines = 0 # unsigned number
+
+# (Java) Add or remove newline after an annotation statement. Only affects
+# annotations that are after a newline.
+nl_after_annotation = ignore # ignore/add/remove/force/not_defined
+
+# (Java) Add or remove newline between two annotations.
+nl_between_annotation = ignore # ignore/add/remove/force/not_defined
+
+# The number of newlines before a whole-file #ifdef.
+#
+# 0: No change (default).
+nl_before_whole_file_ifdef = 0 # unsigned number
+
+# The number of newlines after a whole-file #ifdef.
+#
+# 0: No change (default).
+nl_after_whole_file_ifdef = 0 # unsigned number
+
+# The number of newlines before a whole-file #endif.
+#
+# 0: No change (default).
+nl_before_whole_file_endif = 0 # unsigned number
+
+# The number of newlines after a whole-file #endif.
+#
+# 0: No change (default).
+nl_after_whole_file_endif = 0 # unsigned number
+
+#
+# Positioning options
+#
+
+# The position of arithmetic operators in wrapped expressions.
+pos_arith = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force
+
+# The position of assignment in wrapped expressions. Do not affect '='
+# followed by '{'.
+pos_assign = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force
+
+# The position of Boolean operators in wrapped expressions.
+pos_bool = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force
+
+# The position of comparison operators in wrapped expressions.
+pos_compare = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force
+
+# The position of conditional operators, as in the '?' and ':' of
+# 'expr ? stmt : stmt', in wrapped expressions.
+pos_conditional = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force
+
+# The position of the comma in wrapped expressions.
+pos_comma = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force
+
+# The position of the comma in enum entries.
+pos_enum_comma = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force
+
+# The position of the comma in the base class list if there is more than one
+# line. Affects nl_class_init_args.
+pos_class_comma = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force
+
+# The position of the comma in the constructor initialization list.
+# Related to nl_constr_colon, nl_constr_init_args and pos_constr_colon.
+pos_constr_comma = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force
+
+# The position of trailing/leading class colon, between class and base class
+# list. Affects nl_class_colon.
+pos_class_colon = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force
+
+# The position of colons between constructor and member initialization.
+# Related to nl_constr_colon, nl_constr_init_args and pos_constr_comma.
+pos_constr_colon = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force
+
+# The position of shift operators in wrapped expressions.
+pos_shift = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force
+
+#
+# Line splitting options
+#
+
+# Try to limit code width to N columns.
+code_width = 100 # unsigned number
+
+# Whether to fully split long 'for' statements at semi-colons.
+ls_for_split_full = false # true/false
+
+# Whether to fully split long function prototypes/calls at commas.
+# The option ls_code_width has priority over the option ls_func_split_full.
+ls_func_split_full = false # true/false
+
+# Whether to split lines as close to code_width as possible and ignore some
+# groupings.
+# The option ls_code_width has priority over the option ls_func_split_full.
+ls_code_width = false # true/false
+
+#
+# Code alignment options (not left column spaces/tabs)
+#
+
+# Whether to keep non-indenting tabs.
+align_keep_tabs = false # true/false
+
+# Whether to use tabs for aligning.
+align_with_tabs = false # true/false
+
+# Whether to bump out to the next tab when aligning.
+align_on_tabstop = false # true/false
+
+# Whether to right-align numbers.
+align_number_right = false # true/false
+
+# Whether to keep whitespace not required for alignment.
+align_keep_extra_space = false # true/false
+
+# Whether to align variable definitions in prototypes and functions.
+align_func_params = false # true/false
+
+# The span for aligning parameter definitions in function on parameter name.
+#
+# 0: Don't align (default).
+align_func_params_span = 0 # unsigned number
+
+# The threshold for aligning function parameter definitions.
+# Use a negative number for absolute thresholds.
+#
+# 0: No limit (default).
+align_func_params_thresh = 0 # number
+
+# The gap for aligning function parameter definitions.
+align_func_params_gap = 0 # unsigned number
+
+# The span for aligning constructor value.
+#
+# 0: Don't align (default).
+align_constr_value_span = 0 # unsigned number
+
+# The threshold for aligning constructor value.
+# Use a negative number for absolute thresholds.
+#
+# 0: No limit (default).
+align_constr_value_thresh = 0 # number
+
+# The gap for aligning constructor value.
+align_constr_value_gap = 0 # unsigned number
+
+# Whether to align parameters in single-line functions that have the same
+# name. The function names must already be aligned with each other.
+align_same_func_call_params = false # true/false
+
+# The span for aligning function-call parameters for single line functions.
+#
+# 0: Don't align (default).
+align_same_func_call_params_span = 0 # unsigned number
+
+# The threshold for aligning function-call parameters for single line
+# functions.
+# Use a negative number for absolute thresholds.
+#
+# 0: No limit (default).
+align_same_func_call_params_thresh = 0 # number
+
+# The span for aligning variable definitions.
+#
+# 0: Don't align (default).
+align_var_def_span = 0 # unsigned number
+
+# How to consider (or treat) the '*' in the alignment of variable definitions.
+#
+# 0: Part of the type 'void * foo;' (default)
+# 1: Part of the variable 'void *foo;'
+# 2: Dangling 'void *foo;'
+# Dangling: the '*' will not be taken into account when aligning.
+align_var_def_star_style = 0 # unsigned number
+
+# How to consider (or treat) the '&' in the alignment of variable definitions.
+#
+# 0: Part of the type 'long & foo;' (default)
+# 1: Part of the variable 'long &foo;'
+# 2: Dangling 'long &foo;'
+# Dangling: the '&' will not be taken into account when aligning.
+align_var_def_amp_style = 0 # unsigned number
+
+# The threshold for aligning variable definitions.
+# Use a negative number for absolute thresholds.
+#
+# 0: No limit (default).
+align_var_def_thresh = 0 # number
+
+# The gap for aligning variable definitions.
+align_var_def_gap = 0 # unsigned number
+
+# Whether to align the colon in struct bit fields.
+align_var_def_colon = false # true/false
+
+# The gap for aligning the colon in struct bit fields.
+align_var_def_colon_gap = 0 # unsigned number
+
+# Whether to align any attribute after the variable name.
+align_var_def_attribute = false # true/false
+
+# Whether to align inline struct/enum/union variable definitions.
+align_var_def_inline = false # true/false
+
+# The span for aligning on '=' in assignments.
+#
+# 0: Don't align (default).
+align_assign_span = 0 # unsigned number
+
+# The span for aligning on '=' in function prototype modifier.
+#
+# 0: Don't align (default).
+align_assign_func_proto_span = 0 # unsigned number
+
+# The threshold for aligning on '=' in assignments.
+# Use a negative number for absolute thresholds.
+#
+# 0: No limit (default).
+align_assign_thresh = 0 # number
+
+# How to apply align_assign_span to function declaration "assignments", i.e.
+# 'virtual void foo() = 0' or '~foo() = {default|delete}'.
+#
+# 0: Align with other assignments (default)
+# 1: Align with each other, ignoring regular assignments
+# 2: Don't align
+align_assign_decl_func = 0 # unsigned number
+
+# The span for aligning on '=' in enums.
+#
+# 0: Don't align (default).
+align_enum_equ_span = 0 # unsigned number
+
+# The threshold for aligning on '=' in enums.
+# Use a negative number for absolute thresholds.
+#
+# 0: no limit (default).
+align_enum_equ_thresh = 0 # number
+
+# The span for aligning class member definitions.
+#
+# 0: Don't align (default).
+align_var_class_span = 0 # unsigned number
+
+# The threshold for aligning class member definitions.
+# Use a negative number for absolute thresholds.
+#
+# 0: No limit (default).
+align_var_class_thresh = 0 # number
+
+# The gap for aligning class member definitions.
+align_var_class_gap = 0 # unsigned number
+
+# The span for aligning struct/union member definitions.
+#
+# 0: Don't align (default).
+align_var_struct_span = 0 # unsigned number
+
+# The threshold for aligning struct/union member definitions.
+# Use a negative number for absolute thresholds.
+#
+# 0: No limit (default).
+align_var_struct_thresh = 0 # number
+
+# The gap for aligning struct/union member definitions.
+align_var_struct_gap = 0 # unsigned number
+
+# The span for aligning struct initializer values.
+#
+# 0: Don't align (default).
+align_struct_init_span = 0 # unsigned number
+
+# The span for aligning single-line typedefs.
+#
+# 0: Don't align (default).
+align_typedef_span = 0 # unsigned number
+
+# The minimum space between the type and the synonym of a typedef.
+align_typedef_gap = 0 # unsigned number
+
+# How to align typedef'd functions with other typedefs.
+#
+# 0: Don't mix them at all (default)
+# 1: Align the open parenthesis with the types
+# 2: Align the function type name with the other type names
+align_typedef_func = 0 # unsigned number
+
+# How to consider (or treat) the '*' in the alignment of typedefs.
+#
+# 0: Part of the typedef type, 'typedef int * pint;' (default)
+# 1: Part of type name: 'typedef int *pint;'
+# 2: Dangling: 'typedef int *pint;'
+# Dangling: the '*' will not be taken into account when aligning.
+align_typedef_star_style = 0 # unsigned number
+
+# How to consider (or treat) the '&' in the alignment of typedefs.
+#
+# 0: Part of the typedef type, 'typedef int & intref;' (default)
+# 1: Part of type name: 'typedef int &intref;'
+# 2: Dangling: 'typedef int &intref;'
+# Dangling: the '&' will not be taken into account when aligning.
+align_typedef_amp_style = 0 # unsigned number
+
+# The span for aligning comments that end lines.
+#
+# 0: Don't align (default).
+align_right_cmt_span = 0 # unsigned number
+
+# Minimum number of columns between preceding text and a trailing comment in
+# order for the comment to qualify for being aligned. Must be non-zero to have
+# an effect.
+align_right_cmt_gap = 0 # unsigned number
+
+# If aligning comments, whether to mix with comments after '}' and #endif with
+# less than three spaces before the comment.
+align_right_cmt_mix = false # true/false
+
+# Whether to only align trailing comments that are at the same brace level.
+align_right_cmt_same_level = false # true/false
+
+# Minimum column at which to align trailing comments. Comments which are
+# aligned beyond this column, but which can be aligned in a lesser column,
+# may be "pulled in".
+#
+# 0: Ignore (default).
+align_right_cmt_at_col = 0 # unsigned number
+
+# The span for aligning function prototypes.
+#
+# 0: Don't align (default).
+align_func_proto_span = 0 # unsigned number
+
+# The threshold for aligning function prototypes.
+# Use a negative number for absolute thresholds.
+#
+# 0: No limit (default).
+align_func_proto_thresh = 0 # number
+
+# Minimum gap between the return type and the function name.
+align_func_proto_gap = 0 # unsigned number
+
+# Whether to align function prototypes on the 'operator' keyword instead of
+# what follows.
+align_on_operator = false # true/false
+
+# Whether to mix aligning prototype and variable declarations. If true,
+# align_var_def_XXX options are used instead of align_func_proto_XXX options.
+align_mix_var_proto = false # true/false
+
+# Whether to align single-line functions with function prototypes.
+# Uses align_func_proto_span.
+align_single_line_func = false # true/false
+
+# Whether to align the open brace of single-line functions.
+# Requires align_single_line_func=true. Uses align_func_proto_span.
+align_single_line_brace = false # true/false
+
+# Gap for align_single_line_brace.
+align_single_line_brace_gap = 0 # unsigned number
+
+# (OC) The span for aligning Objective-C message specifications.
+#
+# 0: Don't align (default).
+align_oc_msg_spec_span = 0 # unsigned number
+
+# Whether to align macros wrapped with a backslash and a newline. This will
+# not work right if the macro contains a multi-line comment.
+align_nl_cont = false # true/false
+
+# Whether to align macro functions and variables together.
+align_pp_define_together = false # true/false
+
+# The span for aligning on '#define' bodies.
+#
+# =0: Don't align (default)
+# >0: Number of lines (including comments) between blocks
+align_pp_define_span = 0 # unsigned number
+
+# The minimum space between label and value of a preprocessor define.
+align_pp_define_gap = 0 # unsigned number
+
+# Whether to align lines that start with '<<' with previous '<<'.
+#
+# Default: true
+align_left_shift = true # true/false
+
+# Whether to align comma-separated statements following '<<' (as used to
+# initialize Eigen matrices).
+align_eigen_comma_init = false # true/false
+
+# Whether to align text after 'asm volatile ()' colons.
+align_asm_colon = false # true/false
+
+# (OC) Span for aligning parameters in an Objective-C message call
+# on the ':'.
+#
+# 0: Don't align.
+align_oc_msg_colon_span = 0 # unsigned number
+
+# (OC) Whether to always align with the first parameter, even if it is too
+# short.
+align_oc_msg_colon_first = false # true/false
+
+# (OC) Whether to align parameters in an Objective-C '+' or '-' declaration
+# on the ':'.
+align_oc_decl_colon = false # true/false
+
+# (OC) Whether to not align parameters in an Objectve-C message call if first
+# colon is not on next line of the message call (the same way Xcode does
+# aligment)
+align_oc_msg_colon_xcode_like = false # true/false
+
+#
+# Comment modification options
+#
+
+# Try to wrap comments at N columns.
+cmt_width = 0 # unsigned number
+
+# How to reflow comments.
+#
+# 0: No reflowing (apart from the line wrapping due to cmt_width) (default)
+# 1: No touching at all
+# 2: Full reflow (enable cmt_indent_multi for indent with line wrapping due to cmt_width)
+cmt_reflow_mode = 0 # unsigned number
+
+# Path to a file that contains regular expressions describing patterns for
+# which the end of one line and the beginning of the next will be folded into
+# the same sentence or paragraph during full comment reflow. The regular
+# expressions are described using ECMAScript syntax. The syntax for this
+# specification is as follows, where "..." indicates the custom regular
+# expression and "n" indicates the nth end_of_prev_line_regex and
+# beg_of_next_line_regex regular expression pair:
+#
+# end_of_prev_line_regex[1] = "...$"
+# beg_of_next_line_regex[1] = "^..."
+# end_of_prev_line_regex[2] = "...$"
+# beg_of_next_line_regex[2] = "^..."
+# .
+# .
+# .
+# end_of_prev_line_regex[n] = "...$"
+# beg_of_next_line_regex[n] = "^..."
+#
+# Note that use of this option overrides the default reflow fold regular
+# expressions, which are internally defined as follows:
+#
+# end_of_prev_line_regex[1] = "[\w,\]\)]$"
+# beg_of_next_line_regex[1] = "^[\w,\[\(]"
+# end_of_prev_line_regex[2] = "\.$"
+# beg_of_next_line_regex[2] = "^[A-Z]"
+cmt_reflow_fold_regex_file = "" # string
+
+# Whether to indent wrapped lines to the start of the encompassing paragraph
+# during full comment reflow (cmt_reflow_mode = 2). Overrides the value
+# specified by cmt_sp_after_star_cont.
+#
+# Note that cmt_align_doxygen_javadoc_tags overrides this option for
+# paragraphs associated with javadoc tags
+cmt_reflow_indent_to_paragraph_start = false # true/false
+
+# Whether to convert all tabs to spaces in comments. If false, tabs in
+# comments are left alone, unless used for indenting.
+cmt_convert_tab_to_spaces = true # true/false
+
+# Whether to apply changes to multi-line comments, including cmt_width,
+# keyword substitution and leading chars.
+#
+# Default: true
+cmt_indent_multi = true # true/false
+
+# Whether to align doxygen javadoc-style tags ('@param', '@return', etc.)
+# and corresponding fields such that groups of consecutive block tags,
+# parameter names, and descriptions align with one another. Overrides that
+# which is specified by the cmt_sp_after_star_cont. If cmt_width > 0, it may
+# be necessary to enable cmt_indent_multi and set cmt_reflow_mode = 2
+# in order to achieve the desired alignment for line-wrapping.
+cmt_align_doxygen_javadoc_tags = false # true/false
+
+# The number of spaces to insert after the star and before doxygen
+# javadoc-style tags (@param, @return, etc). Requires enabling
+# cmt_align_doxygen_javadoc_tags. Overrides that which is specified by the
+# cmt_sp_after_star_cont.
+#
+# Default: 1
+cmt_sp_before_doxygen_javadoc_tags = 1 # unsigned number
+
+# Whether to change trailing, single-line c-comments into cpp-comments.
+cmt_trailing_single_line_c_to_cpp = true # true/false
+
+# Whether to group c-comments that look like they are in a block.
+cmt_c_group = false # true/false
+
+# Whether to put an empty '/*' on the first line of the combined c-comment.
+cmt_c_nl_start = false # true/false
+
+# Whether to add a newline before the closing '*/' of the combined c-comment.
+cmt_c_nl_end = false # true/false
+
+# Whether to change cpp-comments into c-comments.
+cmt_cpp_to_c = false # true/false
+
+# Whether to group cpp-comments that look like they are in a block. Only
+# meaningful if cmt_cpp_to_c=true.
+cmt_cpp_group = false # true/false
+
+# Whether to put an empty '/*' on the first line of the combined cpp-comment
+# when converting to a c-comment.
+#
+# Requires cmt_cpp_to_c=true and cmt_cpp_group=true.
+cmt_cpp_nl_start = false # true/false
+
+# Whether to add a newline before the closing '*/' of the combined cpp-comment
+# when converting to a c-comment.
+#
+# Requires cmt_cpp_to_c=true and cmt_cpp_group=true.
+cmt_cpp_nl_end = false # true/false
+
+# Whether to put a star on subsequent comment lines.
+cmt_star_cont = false # true/false
+
+# The number of spaces to insert at the start of subsequent comment lines.
+cmt_sp_before_star_cont = 0 # unsigned number
+
+# The number of spaces to insert after the star on subsequent comment lines.
+cmt_sp_after_star_cont = 0 # unsigned number
+
+# For multi-line comments with a '*' lead, remove leading spaces if the first
+# and last lines of the comment are the same length.
+#
+# Default: true
+cmt_multi_check_last = true # true/false
+
+# For multi-line comments with a '*' lead, remove leading spaces if the first
+# and last lines of the comment are the same length AND if the length is
+# bigger as the first_len minimum.
+#
+# Default: 4
+cmt_multi_first_len_minimum = 4 # unsigned number
+
+# Path to a file that contains text to insert at the beginning of a file if
+# the file doesn't start with a C/C++ comment. If the inserted text contains
+# '$(filename)', that will be replaced with the current file's name.
+cmt_insert_file_header = "" # string
+
+# Path to a file that contains text to insert at the end of a file if the
+# file doesn't end with a C/C++ comment. If the inserted text contains
+# '$(filename)', that will be replaced with the current file's name.
+cmt_insert_file_footer = "" # string
+
+# Path to a file that contains text to insert before a function definition if
+# the function isn't preceded by a C/C++ comment. If the inserted text
+# contains '$(function)', '$(javaparam)' or '$(fclass)', these will be
+# replaced with, respectively, the name of the function, the javadoc '@param'
+# and '@return' stuff, or the name of the class to which the member function
+# belongs.
+cmt_insert_func_header = "" # string
+
+# Path to a file that contains text to insert before a class if the class
+# isn't preceded by a C/C++ comment. If the inserted text contains '$(class)',
+# that will be replaced with the class name.
+cmt_insert_class_header = "" # string
+
+# Path to a file that contains text to insert before an Objective-C message
+# specification, if the method isn't preceded by a C/C++ comment. If the
+# inserted text contains '$(message)' or '$(javaparam)', these will be
+# replaced with, respectively, the name of the function, or the javadoc
+# '@param' and '@return' stuff.
+cmt_insert_oc_msg_header = "" # string
+
+# Whether a comment should be inserted if a preprocessor is encountered when
+# stepping backwards from a function name.
+#
+# Applies to cmt_insert_oc_msg_header, cmt_insert_func_header and
+# cmt_insert_class_header.
+cmt_insert_before_preproc = false # true/false
+
+# Whether a comment should be inserted if a function is declared inline to a
+# class definition.
+#
+# Applies to cmt_insert_func_header.
+#
+# Default: true
+cmt_insert_before_inlines = true # true/false
+
+# Whether a comment should be inserted if the function is a class constructor
+# or destructor.
+#
+# Applies to cmt_insert_func_header.
+cmt_insert_before_ctor_dtor = false # true/false
+
+#
+# Code modifying options (non-whitespace)
+#
+
+# Add or remove braces on a single-line 'do' statement.
+mod_full_brace_do = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove braces on a single-line 'for' statement.
+mod_full_brace_for = add # ignore/add/remove/force/not_defined
+
+# (Pawn) Add or remove braces on a single-line function definition.
+mod_full_brace_function = ignore # ignore/add/remove/force/not_defined
+
+# Add or remove braces on a single-line 'if' statement. Braces will not be
+# removed if the braced statement contains an 'else'.
+mod_full_brace_if = add # ignore/add/remove/force/not_defined
+
+# Whether to enforce that all blocks of an 'if'/'else if'/'else' chain either
+# have, or do not have, braces. If true, braces will be added if any block
+# needs braces, and will only be removed if they can be removed from all
+# blocks.
+#
+# Overrides mod_full_brace_if.
+mod_full_brace_if_chain = false # true/false
+
+# Whether to add braces to all blocks of an 'if'/'else if'/'else' chain.
+# If true, mod_full_brace_if_chain will only remove braces from an 'if' that
+# does not have an 'else if' or 'else'.
+mod_full_brace_if_chain_only = false # true/false
+
+# Add or remove braces on single-line 'while' statement.
+mod_full_brace_while = add # ignore/add/remove/force/not_defined
+
+# Add or remove braces on single-line 'using ()' statement.
+mod_full_brace_using = ignore # ignore/add/remove/force/not_defined
+
+# Don't remove braces around statements that span N newlines
+mod_full_brace_nl = 0 # unsigned number
+
+# Whether to prevent removal of braces from 'if'/'for'/'while'/etc. blocks
+# which span multiple lines.
+#
+# Affects:
+# mod_full_brace_for
+# mod_full_brace_if
+# mod_full_brace_if_chain
+# mod_full_brace_if_chain_only
+# mod_full_brace_while
+# mod_full_brace_using
+#
+# Does not affect:
+# mod_full_brace_do
+# mod_full_brace_function
+mod_full_brace_nl_block_rem_mlcond = false # true/false
+
+# Add or remove unnecessary parenthesis on 'return' statement.
+mod_paren_on_return = ignore # ignore/add/remove/force/not_defined
+
+# (Pawn) Whether to change optional semicolons to real semicolons.
+mod_pawn_semicolon = false # true/false
+
+# Whether to fully parenthesize Boolean expressions in 'while' and 'if'
+# statement, as in 'if (a && b > c)' => 'if (a && (b > c))'.
+mod_full_paren_if_bool = false # true/false
+
+# Whether to remove superfluous semicolons.
+mod_remove_extra_semicolon = false # true/false
+
+# Whether to remove duplicate include.
+mod_remove_duplicate_include = false # true/false
+
+# If a function body exceeds the specified number of newlines and doesn't have
+# a comment after the close brace, a comment will be added.
+mod_add_long_function_closebrace_comment = 0 # unsigned number
+
+# If a namespace body exceeds the specified number of newlines and doesn't
+# have a comment after the close brace, a comment will be added.
+mod_add_long_namespace_closebrace_comment = 0 # unsigned number
+
+# If a class body exceeds the specified number of newlines and doesn't have a
+# comment after the close brace, a comment will be added.
+mod_add_long_class_closebrace_comment = 0 # unsigned number
+
+# If a switch body exceeds the specified number of newlines and doesn't have a
+# comment after the close brace, a comment will be added.
+mod_add_long_switch_closebrace_comment = 0 # unsigned number
+
+# If an #ifdef body exceeds the specified number of newlines and doesn't have
+# a comment after the #endif, a comment will be added.
+mod_add_long_ifdef_endif_comment = 0 # unsigned number
+
+# If an #ifdef or #else body exceeds the specified number of newlines and
+# doesn't have a comment after the #else, a comment will be added.
+mod_add_long_ifdef_else_comment = 0 # unsigned number
+
+# Whether to take care of the case by the mod_sort_xx options.
+mod_sort_case_sensitive = false # true/false
+
+# Whether to sort consecutive single-line 'import' statements.
+mod_sort_import = false # true/false
+
+# (C#) Whether to sort consecutive single-line 'using' statements.
+mod_sort_using = false # true/false
+
+# Whether to sort consecutive single-line '#include' statements (C/C++) and
+# '#import' statements (Objective-C). Be aware that this has the potential to
+# break your code if your includes/imports have ordering dependencies.
+mod_sort_include = true # true/false
+
+# Whether to prioritize '#include' and '#import' statements that contain
+# filename without extension when sorting is enabled.
+mod_sort_incl_import_prioritize_filename = false # true/false
+
+# Whether to prioritize '#include' and '#import' statements that does not
+# contain extensions when sorting is enabled.
+mod_sort_incl_import_prioritize_extensionless = false # true/false
+
+# Whether to prioritize '#include' and '#import' statements that contain
+# angle over quotes when sorting is enabled.
+mod_sort_incl_import_prioritize_angle_over_quotes = true # true/false
+
+# Whether to ignore file extension in '#include' and '#import' statements
+# for sorting comparison.
+mod_sort_incl_import_ignore_extension = false # true/false
+
+# Whether to group '#include' and '#import' statements when sorting is enabled.
+mod_sort_incl_import_grouping_enabled = true # true/false
+
+# Whether to move a 'break' that appears after a fully braced 'case' before
+# the close brace, as in 'case X: { ... } break;' => 'case X: { ... break; }'.
+mod_move_case_break = false # true/false
+
+# Add or remove braces around a fully braced case statement. Will only remove
+# braces if there are no variable declarations in the block.
+mod_case_brace = remove # ignore/add/remove/force/not_defined
+
+# Whether to remove a void 'return;' that appears as the last statement in a
+# function.
+mod_remove_empty_return = false # true/false
+
+# Add or remove the comma after the last value of an enumeration.
+mod_enum_last_comma = ignore # ignore/add/remove/force/not_defined
+
+# (OC) Whether to organize the properties. If true, properties will be
+# rearranged according to the mod_sort_oc_property_*_weight factors.
+mod_sort_oc_properties = false # true/false
+
+# (OC) Weight of a class property modifier.
+mod_sort_oc_property_class_weight = 0 # number
+
+# (OC) Weight of 'atomic' and 'nonatomic'.
+mod_sort_oc_property_thread_safe_weight = 0 # number
+
+# (OC) Weight of 'readwrite' when organizing properties.
+mod_sort_oc_property_readwrite_weight = 0 # number
+
+# (OC) Weight of a reference type specifier ('retain', 'copy', 'assign',
+# 'weak', 'strong') when organizing properties.
+mod_sort_oc_property_reference_weight = 0 # number
+
+# (OC) Weight of getter type ('getter=') when organizing properties.
+mod_sort_oc_property_getter_weight = 0 # number
+
+# (OC) Weight of setter type ('setter=') when organizing properties.
+mod_sort_oc_property_setter_weight = 0 # number
+
+# (OC) Weight of nullability type ('nullable', 'nonnull', 'null_unspecified',
+# 'null_resettable') when organizing properties.
+mod_sort_oc_property_nullability_weight = 0 # number
+
+#
+# Preprocessor options
+#
+
+# Add or remove indentation of preprocessor directives inside #if blocks
+# at brace level 0 (file-level).
+pp_indent = remove # ignore/add/remove/force/not_defined
+
+# Whether to indent #if/#else/#endif at the brace level. If false, these are
+# indented from column 1.
+pp_indent_at_level = false # true/false
+
+# Specifies the number of columns to indent preprocessors per level
+# at brace level 0 (file-level). If pp_indent_at_level=false, also specifies
+# the number of columns to indent preprocessors per level
+# at brace level > 0 (function-level).
+#
+# Default: 1
+pp_indent_count = 1 # unsigned number
+
+# Add or remove space after # based on pp_level of #if blocks.
+pp_space = force # ignore/add/remove/force/not_defined
+
+# Sets the number of spaces per level added with pp_space.
+pp_space_count = 0 # unsigned number
+
+# The indent for '#region' and '#endregion' in C# and '#pragma region' in
+# C/C++. Negative values decrease indent down to the first column.
+pp_indent_region = 0 # number
+
+# Whether to indent the code between #region and #endregion.
+pp_region_indent_code = false # true/false
+
+# If pp_indent_at_level=true, sets the indent for #if, #else and #endif when
+# not at file-level. Negative values decrease indent down to the first column.
+#
+# =0: Indent preprocessors using output_tab_size
+# >0: Column at which all preprocessors will be indented
+pp_indent_if = 0 # number
+
+# Whether to indent the code between #if, #else and #endif.
+pp_if_indent_code = false # true/false
+
+# Whether to indent the body of an #if that encompasses all the code in the file.
+pp_indent_in_guard = false # true/false
+
+# Whether to indent '#define' at the brace level. If false, these are
+# indented from column 1.
+pp_define_at_level = false # true/false
+
+# Whether to ignore the '#define' body while formatting.
+pp_ignore_define_body = false # true/false
+
+# Whether to indent case statements between #if, #else, and #endif.
+# Only applies to the indent of the preprocesser that the case statements
+# directly inside of.
+#
+# Default: true
+pp_indent_case = true # true/false
+
+# Whether to indent whole function definitions between #if, #else, and #endif.
+# Only applies to the indent of the preprocesser that the function definition
+# is directly inside of.
+#
+# Default: true
+pp_indent_func_def = true # true/false
+
+# Whether to indent extern C blocks between #if, #else, and #endif.
+# Only applies to the indent of the preprocesser that the extern block is
+# directly inside of.
+#
+# Default: true
+pp_indent_extern = true # true/false
+
+# Whether to indent braces directly inside #if, #else, and #endif.
+# Only applies to the indent of the preprocesser that the braces are directly
+# inside of.
+#
+# Default: true
+pp_indent_brace = true # true/false
+
+#
+# Sort includes options
+#
+
+# The regex for include category with priority 0.
+include_category_0 = "" # string
+
+# The regex for include category with priority 1.
+include_category_1 = "" # string
+
+# The regex for include category with priority 2.
+include_category_2 = "" # string
+
+#
+# Use or Do not Use options
+#
+
+# true: indent_func_call_param will be used (default)
+# false: indent_func_call_param will NOT be used
+#
+# Default: true
+use_indent_func_call_param = true # true/false
+
+# The value of the indentation for a continuation line is calculated
+# differently if the statement is:
+# - a declaration: your case with QString fileName ...
+# - an assignment: your case with pSettings = new QSettings( ...
+#
+# At the second case the indentation value might be used twice:
+# - at the assignment
+# - at the function call (if present)
+#
+# To prevent the double use of the indentation value, use this option with the
+# value 'true'.
+#
+# true: indent_continue will be used only once
+# false: indent_continue will be used every time (default)
+use_indent_continue_only_once = false # true/false
+
+# The value might be used twice:
+# - at the assignment
+# - at the opening brace
+#
+# To prevent the double use of the indentation value, use this option with the
+# value 'true'.
+#
+# true: indentation will be used only once
+# false: indentation will be used every time (default)
+indent_cpp_lambda_only_once = false # true/false
+
+# Whether sp_after_angle takes precedence over sp_inside_fparen. This was the
+# historic behavior, but is probably not the desired behavior, so this is off
+# by default.
+use_sp_after_angle_always = false # true/false
+
+# Whether to apply special formatting for Qt SIGNAL/SLOT macros. Essentially,
+# this tries to format these so that they match Qt's normalized form (i.e. the
+# result of QMetaObject::normalizedSignature), which can slightly improve the
+# performance of the QObject::connect call, rather than how they would
+# otherwise be formatted.
+#
+# See options_for_QT.cpp for details.
+#
+# Default: true
+use_options_overriding_for_qt_macros = true # true/false
+
+# If true: the form feed character is removed from the list of whitespace
+# characters. See https://en.cppreference.com/w/cpp/string/byte/isspace.
+use_form_feed_no_more_as_whitespace_character = false # true/false
+
+#
+# Warn levels - 1: error, 2: warning (default), 3: note
+#
+
+# (C#) Warning is given if doing tab-to-\t replacement and we have found one
+# in a C# verbatim string literal.
+#
+# Default: 2
+warn_level_tabs_found_in_verbatim_string_literals = 2 # unsigned number
+
+# Limit the number of loops.
+# Used by uncrustify.cpp to exit from infinite loop.
+# 0: no limit.
+debug_max_number_of_loops = 0 # number
+
+# Set the number of the line to protocol;
+# Used in the function prot_the_line if the 2. parameter is zero.
+# 0: nothing protocol.
+debug_line_number_to_protocol = 0 # number
+
+# Set the number of second(s) before terminating formatting the current file,
+# 0: no timeout.
+# only for linux
+debug_timeout = 0 # number
+
+# Set the number of characters to be printed if the text is too long,
+# 0: do not truncate.
+debug_truncate = 0 # unsigned number
+
+# Meaning of the settings:
+# Ignore - do not do any changes
+# Add - makes sure there is 1 or more space/brace/newline/etc
+# Force - makes sure there is exactly 1 space/brace/newline/etc,
+# behaves like Add in some contexts
+# Remove - removes space/brace/newline/etc
+#
+#
+# - Token(s) can be treated as specific type(s) with the 'set' option:
+# `set tokenType tokenString [tokenString...]`
+#
+# Example:
+# `set BOOL __AND__ __OR__`
+#
+# tokenTypes are defined in src/token_enum.h, use them without the
+# 'CT_' prefix: 'CT_BOOL' => 'BOOL'
+#
+#
+# - Token(s) can be treated as type(s) with the 'type' option.
+# `type tokenString [tokenString...]`
+#
+# Example:
+# `type int c_uint_8 Rectangle`
+#
+# This can also be achieved with `set TYPE int c_uint_8 Rectangle`
+#
+#
+# To embed whitespace in tokenStrings use the '\' escape character, or quote
+# the tokenStrings. These quotes are supported: "'`
+#
+#
+# - Support for the auto detection of languages through the file ending can be
+# added using the 'file_ext' command.
+# `file_ext langType langString [langString..]`
+#
+# Example:
+# `file_ext CPP .ch .cxx .cpp.in`
+#
+# langTypes are defined in uncrusify_types.h in the lang_flag_e enum, use
+# them without the 'LANG_' prefix: 'LANG_CPP' => 'CPP'
+#
+#
+# - Custom macro-based indentation can be set up using 'macro-open',
+# 'macro-else' and 'macro-close'.
+# `(macro-open | macro-else | macro-close) tokenString`
+#
+# Example:
+# `macro-open BEGIN_TEMPLATE_MESSAGE_MAP`
+# `macro-open BEGIN_MESSAGE_MAP`
+# `macro-close END_MESSAGE_MAP`
+#
+#
+set QUESTION FUNC_API_CHECK_TEXTLOCK
+set QUESTION FUNC_API_DEPRECATED_SINCE
+set QUESTION FUNC_API_FAST
+set QUESTION FUNC_API_LUA_ONLY
+set QUESTION FUNC_API_NOEXPORT
+set QUESTION FUNC_API_REMOTE_ONLY
+set QUESTION FUNC_API_SINCE
+set QUESTION FUNC_ATTR_ALWAYS_INLINE
+set QUESTION FUNC_ATTR_CONST
+set QUESTION FUNC_ATTR_MALLOC
+set QUESTION FUNC_ATTR_NONNULL_ALL
+set QUESTION FUNC_ATTR_NONNULL_ARG
+set QUESTION FUNC_ATTR_NONNULL_RET
+set QUESTION FUNC_ATTR_NORETURN
+set QUESTION FUNC_ATTR_NO_SANITIZE_UNDEFINED
+set QUESTION FUNC_ATTR_PRINTF
+set QUESTION FUNC_ATTR_PURE
+set QUESTION FUNC_ATTR_UNUSED
+set QUESTION FUNC_ATTR_WARN_UNUSED_RESULT
+set QUESTION REAL_FATTR_ALWAYS_INLINE
+set QUESTION REAL_FATTR_CONST
+set QUESTION REAL_FATTR_NONNULL_ALL
+set QUESTION REAL_FATTR_PURE
+set QUESTION REAL_FATTR_WARN_UNUSED_RESULT
+# option(s) with 'not default' value: 62
+#
diff --git a/src/nvim/xdiff/COPYING b/src/xdiff/COPYING
index f3f1b3b65e..f3f1b3b65e 100644
--- a/src/nvim/xdiff/COPYING
+++ b/src/xdiff/COPYING
diff --git a/src/nvim/xdiff/README.txt b/src/xdiff/README.txt
index 1afe74095b..95b2242b87 100644
--- a/src/nvim/xdiff/README.txt
+++ b/src/xdiff/README.txt
@@ -1,6 +1,6 @@
The files in this directory come from the xdiff implementation in git.
You can find it here: https://github.com/git/git/tree/master/xdiff
-The files were last updated 2018 September 10.
+The files were last updated August 31, 2021 from git release v.2.33.0
This is originally based on libxdiff, which can be found here:
http://www.xmailserver.org/xdiff-lib.html
diff --git a/src/nvim/xdiff/xdiff.h b/src/xdiff/xdiff.h
index 8ff4a05bfb..49985a0e9a 100644
--- a/src/nvim/xdiff/xdiff.h
+++ b/src/xdiff/xdiff.h
@@ -25,9 +25,9 @@
#ifdef __cplusplus
extern "C" {
-#endif // #ifdef __cplusplus
+#endif /* #ifdef __cplusplus */
-// xpparm_t.flags
+/* xpparm_t.flags */
#define XDF_NEED_MINIMAL (1 << 0)
#define XDF_IGNORE_WHITESPACE (1 << 1)
@@ -48,22 +48,23 @@ extern "C" {
#define XDF_INDENT_HEURISTIC (1 << 23)
-// xdemitconf_t.flags
+/* xdemitconf_t.flags */
#define XDL_EMIT_FUNCNAMES (1 << 0)
+#define XDL_EMIT_NO_HUNK_HDR (1 << 1)
#define XDL_EMIT_FUNCCONTEXT (1 << 2)
-// merge simplification levels
+/* merge simplification levels */
#define XDL_MERGE_MINIMAL 0
#define XDL_MERGE_EAGER 1
#define XDL_MERGE_ZEALOUS 2
#define XDL_MERGE_ZEALOUS_ALNUM 3
-// merge favor modes
+/* merge favor modes */
#define XDL_MERGE_FAVOR_OURS 1
#define XDL_MERGE_FAVOR_THEIRS 2
#define XDL_MERGE_FAVOR_UNION 3
-// merge output styles
+/* merge output styles */
#define XDL_MERGE_DIFF3 1
typedef struct s_mmfile {
@@ -79,14 +80,24 @@ typedef struct s_mmbuffer {
typedef struct s_xpparam {
unsigned long flags;
- // See Documentation/diff-options.txt.
+ /* -I<regex> */
+ #if 0 // unused by Vim
+ regex_t **ignore_regex;
+ size_t ignore_regex_nr;
+#endif
+
+ /* See Documentation/diff-options.txt. */
char **anchors;
size_t anchors_nr;
} xpparam_t;
typedef struct s_xdemitcb {
void *priv;
- int (*outf)(void *, mmbuffer_t *, int);
+ int (*out_hunk)(void *,
+ long old_begin, long old_nr,
+ long new_begin, long new_nr,
+ const char *func, long funclen);
+ int (*out_line)(void *, mmbuffer_t *, int);
} xdemitcb_t;
typedef long (*find_func_t)(const char *line, long line_len, char *buffer, long buffer_size, void *priv);
@@ -108,7 +119,7 @@ typedef struct s_bdiffparam {
long bsize;
} bdiffparam_t;
-#include "../memory.h"
+#include "../nvim/memory.h"
#define xdl_malloc(x) xmalloc((x))
#define xdl_free(ptr) xfree(ptr)
@@ -126,9 +137,9 @@ typedef struct s_xmparam {
int level;
int favor;
int style;
- const char *ancestor; // label for orig
- const char *file1; // label for mf1
- const char *file2; // label for mf2
+ const char *ancestor; /* label for orig */
+ const char *file1; /* label for mf1 */
+ const char *file2; /* label for mf2 */
} xmparam_t;
#define DEFAULT_CONFLICT_MARKER_SIZE 7
@@ -138,6 +149,6 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, mmfile_t *mf2,
#ifdef __cplusplus
}
-#endif // #ifdef __cplusplus
+#endif /* #ifdef __cplusplus */
-#endif // #if !defined(XDIFF_H)
+#endif /* #if !defined(XDIFF_H) */
diff --git a/src/nvim/xdiff/xdiffi.c b/src/xdiff/xdiffi.c
index 3806903986..cfcbb5d982 100644
--- a/src/nvim/xdiff/xdiffi.c
+++ b/src/xdiff/xdiffi.c
@@ -38,9 +38,9 @@ typedef struct s_xdpsplit {
* Basically considers a "box" (off1, off2, lim1, lim2) and scan from both
* the forward diagonal starting from (off1, off2) and the backward diagonal
* starting from (lim1, lim2). If the K values on the same diagonal crosses
- * returns the furthest point of reach. We might end up having to expensive
- * cases using this algorithm is full, so a little bit of heuristic is needed
- * to cut the search and to return a suboptimal point.
+ * returns the furthest point of reach. We might encounter expensive edge cases
+ * using this algorithm, so a little bit of heuristic is needed to cut the
+ * search and to return a suboptimal point.
*/
static long xdl_split(unsigned long const *ha1, long off1, long lim1,
unsigned long const *ha2, long off2, long lim2,
@@ -63,11 +63,13 @@ static long xdl_split(unsigned long const *ha1, long off1, long lim1,
int got_snake = 0;
/*
- * We need to extent the diagonal "domain" by one. If the next
+ * We need to extend the diagonal "domain" by one. If the next
* values exits the box boundaries we need to change it in the
- * opposite direction because (max - min) must be a power of two.
+ * opposite direction because (max - min) must be a power of
+ * two.
+ *
* Also we initialize the external K value to -1 so that we can
- * avoid extra conditions check inside the core loop.
+ * avoid extra conditions in the check inside the core loop.
*/
if (fmin > dmin)
kvdf[--fmin - 1] = -1;
@@ -98,11 +100,13 @@ static long xdl_split(unsigned long const *ha1, long off1, long lim1,
}
/*
- * We need to extent the diagonal "domain" by one. If the next
+ * We need to extend the diagonal "domain" by one. If the next
* values exits the box boundaries we need to change it in the
- * opposite direction because (max - min) must be a power of two.
+ * opposite direction because (max - min) must be a power of
+ * two.
+ *
* Also we initialize the external K value to -1 so that we can
- * avoid extra conditions check inside the core loop.
+ * avoid extra conditions in the check inside the core loop.
*/
if (bmin > dmin)
kvdb[--bmin - 1] = XDL_LINE_MAX;
@@ -138,7 +142,7 @@ static long xdl_split(unsigned long const *ha1, long off1, long lim1,
/*
* If the edit cost is above the heuristic trigger and if
* we got a good snake, we sample current diagonals to see
- * if some of the, have reached an "interesting" path. Our
+ * if some of them have reached an "interesting" path. Our
* measure is a function of the distance from the diagonal
* corner (i1 + i2) penalized with the distance from the
* mid diagonal itself. If this value is above the current
@@ -196,8 +200,9 @@ static long xdl_split(unsigned long const *ha1, long off1, long lim1,
}
/*
- * Enough is enough. We spent too much time here and now we collect
- * the furthest reaching path using the (i1 + i2) measure.
+ * Enough is enough. We spent too much time here and now we
+ * collect the furthest reaching path using the (i1 + i2)
+ * measure.
*/
if (ec >= xenv->mxcost) {
long fbest, fbest1, bbest, bbest1;
@@ -244,9 +249,9 @@ static long xdl_split(unsigned long const *ha1, long off1, long lim1,
/*
- * Rule: "Divide et Impera". Recursively split the box in sub-boxes by calling
- * the box splitting function. Note that the real job (marking changed lines)
- * is done in the two boundary reaching checks.
+ * Rule: "Divide et Impera" (divide & conquer). Recursively split the box in
+ * sub-boxes by calling the box splitting function. Note that the real job
+ * (marking changed lines) is done in the two boundary reaching checks.
*/
int xdl_recs_cmp(diffdata_t *dd1, long off1, long lim1,
diffdata_t *dd2, long off2, long lim2,
@@ -323,7 +328,9 @@ int xdl_do_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
}
/*
- * Allocate and setup K vectors to be used by the differential algorithm.
+ * Allocate and setup K vectors to be used by the differential
+ * algorithm.
+ *
* One is to store the forward path and one to store the backward path.
*/
ndiags = xe->xdf1.nreff + xe->xdf2.nreff + 3;
@@ -418,13 +425,13 @@ static int xget_indent(xrecord_t *rec)
ret += 1;
else if (c == '\t')
ret += 8 - ret % 8;
- // ignore other whitespace characters
+ /* ignore other whitespace characters */
if (ret >= MAX_INDENT)
return MAX_INDENT;
}
- // The line contains only whitespace.
+ /* The line contains only whitespace. */
return -1;
}
@@ -435,7 +442,7 @@ static int xget_indent(xrecord_t *rec)
*/
#define MAX_BLANKS 20
-// Characteristics measured about a hypothetical split position.
+/* Characteristics measured about a hypothetical split position. */
struct split_measurement {
/*
* Is the split at the end of the file (aside from any blank lines)?
@@ -443,8 +450,8 @@ struct split_measurement {
int end_of_file;
/*
- * How much is the line immediately following the split indented (or -1 if
- * the line is blank):
+ * How much is the line immediately following the split indented (or -1
+ * if the line is blank):
*/
int indent;
@@ -454,8 +461,8 @@ struct split_measurement {
int pre_blank;
/*
- * How much is the nearest non-blank line above the split indented (or -1
- * if there is no such line)?
+ * How much is the nearest non-blank line above the split indented (or
+ * -1 if there is no such line)?
*/
int pre_indent;
@@ -472,10 +479,10 @@ struct split_measurement {
};
struct split_score {
- // The effective indent of this split (smaller is preferred).
+ /* The effective indent of this split (smaller is preferred). */
int effective_indent;
- // Penalty for this split (smaller is preferred).
+ /* Penalty for this split (smaller is preferred). */
int penalty;
};
@@ -534,16 +541,16 @@ static void measure_split(const xdfile_t *xdf, long split,
* integer math.
*/
-// Penalty if there are no non-blank lines before the split
+/* Penalty if there are no non-blank lines before the split */
#define START_OF_FILE_PENALTY 1
-// Penalty if there are no non-blank lines after the split
+/* Penalty if there are no non-blank lines after the split */
#define END_OF_FILE_PENALTY 21
-// Multiplier for the number of blank lines around the split
+/* Multiplier for the number of blank lines around the split */
#define TOTAL_BLANK_WEIGHT (-30)
-// Multiplier for the number of blank lines after the split
+/* Multiplier for the number of blank lines after the split */
#define POST_BLANK_WEIGHT 6
/*
@@ -581,13 +588,13 @@ static void measure_split(const xdfile_t *xdf, long split,
/*
* Compute a badness score for the hypothetical split whose measurements are
- * stored in m. The weight factors were determined empirically using the tools and
- * corpus described in
+ * stored in m. The weight factors were determined empirically using the tools
+ * and corpus described in
*
* https://github.com/mhagger/diff-slider-tools
*
- * Also see that project if you want to improve the weights based on, for example,
- * a larger or more diverse corpus.
+ * Also see that project if you want to improve the weights based on, for
+ * example, a larger or more diverse corpus.
*/
static void score_add_split(const struct split_measurement *m, struct split_score *s)
{
@@ -610,7 +617,7 @@ static void score_add_split(const struct split_measurement *m, struct split_scor
post_blank = (m->indent == -1) ? 1 + m->post_blank : 0;
total_blank = m->pre_blank + post_blank;
- // Penalties based on nearby blank lines:
+ /* Penalties based on nearby blank lines: */
s->penalty += TOTAL_BLANK_WEIGHT * total_blank;
s->penalty += POST_BLANK_WEIGHT * post_blank;
@@ -621,13 +628,13 @@ static void score_add_split(const struct split_measurement *m, struct split_scor
any_blanks = (total_blank != 0);
- // Note that the effective indent is -1 at the end of the file:
+ /* Note that the effective indent is -1 at the end of the file: */
s->effective_indent += indent;
if (indent == -1) {
- // No additional adjustments needed.
+ /* No additional adjustments needed. */
} else if (m->pre_indent == -1) {
- // No additional adjustments needed.
+ /* No additional adjustments needed. */
} else if (indent > m->pre_indent) {
/*
* The line is indented more than its predecessor.
@@ -669,7 +676,7 @@ static void score_add_split(const struct split_measurement *m, struct split_scor
static int score_cmp(struct split_score *s1, struct split_score *s2)
{
- // -1 if s1.effective_indent < s2->effective_indent, etc.
+ /* -1 if s1.effective_indent < s2->effective_indent, etc. */
int cmp_indents = ((s1->effective_indent > s2->effective_indent) -
(s1->effective_indent < s2->effective_indent));
@@ -809,13 +816,16 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
group_init(xdfo, &go);
while (1) {
- // If the group is empty in the to-be-compacted file, skip it:
+ /*
+ * If the group is empty in the to-be-compacted file, skip it:
+ */
if (g.end == g.start)
goto next;
/*
* Now shift the change up and then down as far as possible in
- * each direction. If it bumps into any other changes, merge them.
+ * each direction. If it bumps into any other changes, merge
+ * them.
*/
do {
groupsize = g.end - g.start;
@@ -828,7 +838,7 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
*/
end_matching_other = -1;
- // Shift the group backward as much as possible:
+ /* Shift the group backward as much as possible: */
while (!group_slide_up(xdf, &g, flags))
if (group_previous(xdfo, &go))
xdl_bug("group sync broken sliding up");
@@ -842,7 +852,7 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
if (go.end > go.start)
end_matching_other = g.end;
- // Now shift the group forward as far as possible:
+ /* Now shift the group forward as far as possible: */
while (1) {
if (group_slide_down(xdf, &g, flags))
break;
@@ -858,17 +868,17 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
* If the group can be shifted, then we can possibly use this
* freedom to produce a more intuitive diff.
*
- * The group is currently shifted as far down as possible, so the
- * heuristics below only have to handle upwards shifts.
+ * The group is currently shifted as far down as possible, so
+ * the heuristics below only have to handle upwards shifts.
*/
if (g.end == earliest_end) {
- // no shifting was possible
+ /* no shifting was possible */
} else if (end_matching_other != -1) {
/*
- * Move the possibly merged group of changes back to line
- * up with the last group of changes from the other file
- * that it can align with.
+ * Move the possibly merged group of changes back to
+ * line up with the last group of changes from the
+ * other file that it can align with.
*/
while (go.end == go.start) {
if (group_slide_up(xdf, &g, flags))
@@ -879,14 +889,15 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
} else if (flags & XDF_INDENT_HEURISTIC) {
/*
* Indent heuristic: a group of pure add/delete lines
- * implies two splits, one between the end of the "before"
- * context and the start of the group, and another between
- * the end of the group and the beginning of the "after"
- * context. Some splits are aesthetically better and some
- * are worse. We compute a badness "score" for each split,
- * and add the scores for the two splits to define a
- * "score" for each position that the group can be shifted
- * to. Then we pick the shift with the lowest score.
+ * implies two splits, one between the end of the
+ * "before" context and the start of the group, and
+ * another between the end of the group and the
+ * beginning of the "after" context. Some splits are
+ * aesthetically better and some are worse. We compute
+ * a badness "score" for each split, and add the scores
+ * for the two splits to define a "score" for each
+ * position that the group can be shifted to. Then we
+ * pick the shift with the lowest score.
*/
long shift, best_shift = -1;
struct split_score best_score;
@@ -921,7 +932,7 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
}
next:
- // Move past the just-processed group:
+ /* Move past the just-processed group: */
if (group_next(xdf, &g))
break;
if (group_next(xdfo, &go))
@@ -987,7 +998,7 @@ static int xdl_call_hunk_func(xdfenv_t *xe UNUSED, xdchange_t *xscr, xdemitcb_t
return 0;
}
-static void xdl_mark_ignorable(xdchange_t *xscr, xdfenv_t *xe, long flags)
+static void xdl_mark_ignorable_lines(xdchange_t *xscr, xdfenv_t *xe, long flags)
{
xdchange_t *xch;
@@ -1008,6 +1019,48 @@ static void xdl_mark_ignorable(xdchange_t *xscr, xdfenv_t *xe, long flags)
}
}
+#if 0 // unused by Vim
+static int record_matches_regex(xrecord_t *rec, xpparam_t const *xpp) {
+ regmatch_t regmatch;
+ int i;
+
+ for (i = 0; i < xpp->ignore_regex_nr; i++)
+ if (!regexec_buf(xpp->ignore_regex[i], rec->ptr, rec->size, 1,
+ &regmatch, 0))
+ return 1;
+
+ return 0;
+}
+
+static void xdl_mark_ignorable_regex(xdchange_t *xscr, const xdfenv_t *xe,
+ xpparam_t const *xpp)
+{
+ xdchange_t *xch;
+
+ for (xch = xscr; xch; xch = xch->next) {
+ xrecord_t **rec;
+ int ignore = 1;
+ long i;
+
+ /*
+ * Do not override --ignore-blank-lines.
+ */
+ if (xch->ignore)
+ continue;
+
+ rec = &xe->xdf1.recs[xch->i1];
+ for (i = 0; i < xch->chg1 && ignore; i++)
+ ignore = record_matches_regex(rec[i], xpp);
+
+ rec = &xe->xdf2.recs[xch->i2];
+ for (i = 0; i < xch->chg2 && ignore; i++)
+ ignore = record_matches_regex(rec[i], xpp);
+
+ xch->ignore = ignore;
+ }
+}
+#endif
+
int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
xdemitconf_t const *xecfg, xdemitcb_t *ecb) {
xdchange_t *xscr;
@@ -1027,7 +1080,12 @@ int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
}
if (xscr) {
if (xpp->flags & XDF_IGNORE_BLANK_LINES)
- xdl_mark_ignorable(xscr, &xe, xpp->flags);
+ xdl_mark_ignorable_lines(xscr, &xe, xpp->flags);
+
+#if 0
+ if (xpp->ignore_regex)
+ xdl_mark_ignorable_regex(xscr, &xe, xpp);
+#endif
if (ef(&xe, xscr, ecb, xecfg) < 0) {
diff --git a/src/nvim/xdiff/xdiffi.h b/src/xdiff/xdiffi.h
index 467a1e85cd..8f1c7c8b04 100644
--- a/src/nvim/xdiff/xdiffi.h
+++ b/src/xdiff/xdiffi.h
@@ -61,4 +61,4 @@ int xdl_do_patience_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
int xdl_do_histogram_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
xdfenv_t *env);
-#endif // #if !defined(XDIFFI_H)
+#endif /* #if !defined(XDIFFI_H) */
diff --git a/src/nvim/xdiff/xemit.c b/src/xdiff/xemit.c
index f1a45139cc..b578e7a9d5 100644
--- a/src/nvim/xdiff/xemit.c
+++ b/src/xdiff/xemit.c
@@ -54,9 +54,9 @@ xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg)
xdchange_t *xch, *xchp, *lxch;
long max_common = 2 * xecfg->ctxlen + xecfg->interhunkctxlen;
long max_ignorable = xecfg->ctxlen;
- unsigned long ignored = 0; // number of ignored blank lines
+ unsigned long ignored = 0; /* number of ignored blank lines */
- // remove ignorable changes that are too far before other changes
+ /* remove ignorable changes that are too far before other changes */
for (xchp = *xscr; xchp && xchp->ignore; xchp = xchp->next) {
xch = xchp->next;
@@ -99,9 +99,9 @@ xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg)
static long def_ff(const char *rec, long len, char *buf, long sz, void *priv UNUSED)
{
if (len > 0 &&
- (isalpha((unsigned char)*rec) || // identifier?
- *rec == '_' || // also identifier?
- *rec == '$')) { // identifiers from VMS and other esoterico
+ (isalpha((unsigned char)*rec) || /* identifier? */
+ *rec == '_' || /* also identifier? */
+ *rec == '$')) { /* identifiers from VMS and other esoterico */
if (len > sz)
len = sz;
while (0 < len && isspace((unsigned char)rec[len - 1]))
@@ -197,7 +197,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
if (xecfg->flags & XDL_EMIT_FUNCCONTEXT) {
long fs1, i1 = xch->i1;
- // Appended chunk?
+ /* Appended chunk? */
if (i1 >= xe->xdf1.nrec) {
long i2 = xch->i2;
@@ -225,8 +225,23 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
if (fs1 < 0)
fs1 = 0;
if (fs1 < s1) {
- s2 -= s1 - fs1;
+ s2 = XDL_MAX(s2 - (s1 - fs1), 0);
s1 = fs1;
+
+ /*
+ * Did we extend context upwards into an
+ * ignored change?
+ */
+ while (xchp != xch &&
+ xchp->i1 + xchp->chg1 <= s1 &&
+ xchp->i2 + xchp->chg2 <= s2)
+ xchp = xchp->next;
+
+ /* If so, show it after all. */
+ if (xchp != xch) {
+ xch = xchp;
+ goto pre_context_calculation;
+ }
}
}
@@ -249,7 +264,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
if (fe1 < 0)
fe1 = xe->xdf1.nrec;
if (fe1 > e1) {
- e2 += fe1 - e1;
+ e2 = XDL_MIN(e2 + (fe1 - e1), xe->xdf2.nrec);
e1 = fe1;
}
@@ -281,7 +296,8 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
funclineprev = s1 - 1;
}
#endif
- if (xdl_emit_hunk_hdr(s1 + 1, e1 - s1, s2 + 1, e2 - s2,
+ if (!(xecfg->flags & XDL_EMIT_NO_HUNK_HDR) &&
+ xdl_emit_hunk_hdr(s1 + 1, e1 - s1, s2 + 1, e2 - s2,
func_line.buf, func_line.len, ecb) < 0)
return -1;
diff --git a/src/nvim/xdiff/xemit.h b/src/xdiff/xemit.h
index 3ce7e3dd50..1b9887e670 100644
--- a/src/nvim/xdiff/xemit.h
+++ b/src/xdiff/xemit.h
@@ -33,4 +33,4 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
-#endif // #if !defined(XEMIT_H)
+#endif /* #if !defined(XEMIT_H) */
diff --git a/src/nvim/xdiff/xhistogram.c b/src/xdiff/xhistogram.c
index 28cf8258e5..8598a8550d 100644
--- a/src/nvim/xdiff/xhistogram.c
+++ b/src/xdiff/xhistogram.c
@@ -42,8 +42,6 @@
*/
#include "xinclude.h"
-#include "xtypes.h"
-#include "xdiff.h"
#define MAX_PTR INT_MAX
#define MAX_CNT INT_MAX
@@ -55,8 +53,8 @@ struct histindex {
struct record {
unsigned int ptr, cnt;
struct record *next;
- } **records, // an occurrence
- **line_map; // map of line to record chain
+ } **records, /* an occurrence */
+ **line_map; /* map of line to record chain */
chastore_t rcha;
unsigned int *next_ptrs;
unsigned int table_bits,
@@ -128,7 +126,7 @@ static int scanA(struct histindex *index, int line1, int count1)
*/
NEXT_PTR(index, ptr) = rec->ptr;
rec->ptr = ptr;
- // cap rec->cnt at MAX_CNT
+ /* cap rec->cnt at MAX_CNT */
rec->cnt = XDL_MIN(MAX_CNT, rec->cnt + 1);
LINE_MAP(index, ptr) = rec;
goto continue_scan;
@@ -154,7 +152,7 @@ static int scanA(struct histindex *index, int line1, int count1)
LINE_MAP(index, ptr) = rec;
continue_scan:
- ; // no op
+ ; /* no op */
}
return 0;
@@ -237,6 +235,8 @@ static int fall_back_to_classic_diff(xpparam_t const *xpp, xdfenv_t *env,
int line1, int count1, int line2, int count2)
{
xpparam_t xpparam;
+
+ memset(&xpparam, 0, sizeof(xpparam));
xpparam.flags = xpp->flags & ~XDF_DIFF_ALGORITHM_MASK;
return xdl_fall_back_diff(env, &xpparam,
@@ -266,7 +266,7 @@ static int find_lcs(xpparam_t const *xpp, xdfenv_t *env,
index.records = NULL;
index.line_map = NULL;
- // in case of early xdl_cha_free()
+ /* in case of early xdl_cha_free() */
index.rcha.head = NULL;
index.table_bits = xdl_hashbits(count1);
@@ -288,7 +288,7 @@ static int find_lcs(xpparam_t const *xpp, xdfenv_t *env,
goto cleanup;
memset(index.next_ptrs, 0, sz);
- // lines / 4 + 1 comes from xprepare.c:xdl_prepare_ctx()
+ /* lines / 4 + 1 comes from xprepare.c:xdl_prepare_ctx() */
if (xdl_cha_init(&index.rcha, sizeof(struct record), count1 / 4 + 1) < 0)
goto cleanup;
diff --git a/src/nvim/xdiff/xinclude.h b/src/xdiff/xinclude.h
index 5a359d1431..a412404bfe 100644
--- a/src/nvim/xdiff/xinclude.h
+++ b/src/xdiff/xinclude.h
@@ -40,6 +40,7 @@
#if !defined(XINCLUDE_H)
#define XINCLUDE_H
+// This effectively re-verts b46054b3746271d23feab0 from git
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
@@ -48,7 +49,10 @@
#endif
#include <string.h>
#include <limits.h>
-
+// This include comes from git, so uncomment it
+#if 0
+#include "git-compat-util.h"
+#endif
#include "xmacros.h"
#include "xdiff.h"
#include "xtypes.h"
@@ -58,4 +62,4 @@
#include "xemit.h"
-#endif // #if !defined(XINCLUDE_H)
+#endif /* #if !defined(XINCLUDE_H) */
diff --git a/src/nvim/xdiff/xmacros.h b/src/xdiff/xmacros.h
index 1167ebbb05..2809a28ca9 100644
--- a/src/nvim/xdiff/xmacros.h
+++ b/src/xdiff/xmacros.h
@@ -51,4 +51,4 @@ do { \
} while (0)
-#endif // #if !defined(XMACROS_H)
+#endif /* #if !defined(XMACROS_H) */
diff --git a/src/nvim/xdiff/xpatience.c b/src/xdiff/xpatience.c
index f6c84c67d8..f78c897ad8 100644
--- a/src/nvim/xdiff/xpatience.c
+++ b/src/xdiff/xpatience.c
@@ -20,8 +20,6 @@
*
*/
#include "xinclude.h"
-#include "xtypes.h"
-#include "xdiff.h"
/*
* The basic idea of patience diff is to find lines that are unique in
@@ -69,7 +67,7 @@ struct hashmap {
*/
unsigned anchor : 1;
} *entries, *first, *last;
- // were common records found?
+ /* were common records found? */
unsigned long has_matches;
mmfile_t *file1, *file2;
xdfenv_t *env;
@@ -78,21 +76,21 @@ struct hashmap {
static int is_anchor(xpparam_t const *xpp, const char *line)
{
- size_t i;
- for (i = 0; i < xpp->anchors_nr; i++) {
+ int i;
+ for (i = 0; i < (int)xpp->anchors_nr; i++) {
if (!strncmp(line, xpp->anchors[i], strlen(xpp->anchors[i])))
return 1;
}
return 0;
}
-// The argument "pass" is 1 for the first file, 2 for the second.
+/* The argument "pass" is 1 for the first file, 2 for the second. */
static void insert_record(xpparam_t const *xpp, int line, struct hashmap *map,
int pass)
{
xrecord_t **records = pass == 1 ?
map->env->xdf1.recs : map->env->xdf2.recs;
- xrecord_t *record = records[line - 1], *other;
+ xrecord_t *record = records[line - 1];
/*
* After xdl_prepare_env() (or more precisely, due to
* xdl_classify_record()), the "ha" member of the records (AKA lines)
@@ -106,11 +104,7 @@ static void insert_record(xpparam_t const *xpp, int line, struct hashmap *map,
int index = (int)((record->ha << 1) % map->alloc);
while (map->entries[index].line1) {
- other = map->env->xdf1.recs[map->entries[index].line1 - 1];
- if (map->entries[index].hash != record->ha ||
- !xdl_recmatch(record->ptr, record->size,
- other->ptr, other->size,
- map->xpp->flags)) {
+ if (map->entries[index].hash != record->ha) {
if (++index >= map->alloc)
index = 0;
continue;
@@ -155,7 +149,7 @@ static int fill_hashmap(mmfile_t *file1, mmfile_t *file2,
result->xpp = xpp;
result->env = env;
- // We know exactly how large we want the hash map
+ /* We know exactly how large we want the hash map */
result->alloc = count1 * 2;
result->entries = (struct entry *)
xdl_malloc(result->alloc * sizeof(struct entry));
@@ -163,11 +157,11 @@ static int fill_hashmap(mmfile_t *file1, mmfile_t *file2,
return -1;
memset(result->entries, 0, result->alloc * sizeof(struct entry));
- // First, fill with entries from the first file
+ /* First, fill with entries from the first file */
while (count1--)
insert_record(xpp, line1++, result, 1);
- // Then search for matches in the second file
+ /* Then search for matches in the second file */
while (count2--)
insert_record(xpp, line2++, result, 2);
@@ -185,13 +179,13 @@ static int binary_search(struct entry **sequence, int longest,
while (left + 1 < right) {
int middle = left + (right - left) / 2;
- // by construction, no two entries can be equal
+ /* by construction, no two entries can be equal */
if (sequence[middle]->line2 > entry->line2)
right = middle;
else
left = middle;
}
- // return the index in "sequence", _not_ the sequence length
+ /* return the index in "sequence", _not_ the sequence length */
return left;
}
@@ -206,9 +200,10 @@ static int binary_search(struct entry **sequence, int longest,
*/
static struct entry *find_longest_common_sequence(struct hashmap *map)
{
- struct entry **sequence = (struct entry **)xdl_malloc(map->nr * sizeof(struct entry *));
+ struct entry **sequence = xdl_malloc(map->nr * sizeof(struct entry *));
int longest = 0, i;
struct entry *entry;
+
/*
* If not -1, this entry in sequence must never be overridden.
* Therefore, overriding entries before this has no effect, so
@@ -237,13 +232,13 @@ static struct entry *find_longest_common_sequence(struct hashmap *map)
}
}
- // No common unique lines were found
+ /* No common unique lines were found */
if (!longest) {
xdl_free(sequence);
return NULL;
}
- // Iterate starting at the last element, adjusting the "next" members
+ /* Iterate starting at the last element, adjusting the "next" members */
entry = sequence[longest - 1];
entry->next = NULL;
while (entry->previous) {
@@ -258,8 +253,7 @@ static int match(struct hashmap *map, int line1, int line2)
{
xrecord_t *record1 = map->env->xdf1.recs[line1 - 1];
xrecord_t *record2 = map->env->xdf2.recs[line2 - 1];
- return xdl_recmatch(record1->ptr, record1->size,
- record2->ptr, record2->size, map->xpp->flags);
+ return record1->ha == record2->ha;
}
static int patience_diff(mmfile_t *file1, mmfile_t *file2,
@@ -273,7 +267,7 @@ static int walk_common_sequence(struct hashmap *map, struct entry *first,
int next1, next2;
for (;;) {
- // Try to grow the line ranges of common lines
+ /* Try to grow the line ranges of common lines */
if (first) {
next1 = first->line1;
next2 = first->line2;
@@ -292,11 +286,8 @@ static int walk_common_sequence(struct hashmap *map, struct entry *first,
line2++;
}
- // Recurse
+ /* Recurse */
if (next1 > line1 || next2 > line2) {
- struct hashmap submap;
-
- memset(&submap, 0, sizeof(submap));
if (patience_diff(map->file1, map->file2,
map->xpp, map->env,
line1, next1 - line1,
@@ -323,6 +314,8 @@ static int fall_back_to_classic_diff(struct hashmap *map,
int line1, int count1, int line2, int count2)
{
xpparam_t xpp;
+
+ memset(&xpp, 0, sizeof(xpp));
xpp.flags = map->xpp->flags & ~XDF_DIFF_ALGORITHM_MASK;
return xdl_fall_back_diff(map->env, &xpp,
@@ -343,7 +336,7 @@ static int patience_diff(mmfile_t *file1, mmfile_t *file2,
struct entry *first;
int result = 0;
- // trivial case: one side is empty
+ /* trivial case: one side is empty */
if (!count1) {
while(count2--)
env->xdf2.rchg[line2++ - 1] = 1;
@@ -359,7 +352,7 @@ static int patience_diff(mmfile_t *file1, mmfile_t *file2,
line1, count1, line2, count2))
return -1;
- // are there any matching lines at all?
+ /* are there any matching lines at all? */
if (!map.has_matches) {
while(count1--)
env->xdf1.rchg[line1++ - 1] = 1;
@@ -387,7 +380,7 @@ int xdl_do_patience_diff(mmfile_t *file1, mmfile_t *file2,
if (xdl_prepare_env(file1, file2, xpp, env) < 0)
return -1;
- // environment is cleaned up in xdl_diff()
+ /* environment is cleaned up in xdl_diff() */
return patience_diff(file1, file2, xpp, env,
1, env->xdf1.nrec, 1, env->xdf2.nrec);
}
diff --git a/src/nvim/xdiff/xprepare.c b/src/xdiff/xprepare.c
index abeb8fb84e..abeb8fb84e 100644
--- a/src/nvim/xdiff/xprepare.c
+++ b/src/xdiff/xprepare.c
diff --git a/src/nvim/xdiff/xprepare.h b/src/xdiff/xprepare.h
index b67b3b25ab..947d9fc1bb 100644
--- a/src/nvim/xdiff/xprepare.h
+++ b/src/xdiff/xprepare.h
@@ -31,4 +31,4 @@ void xdl_free_env(xdfenv_t *xe);
-#endif // #if !defined(XPREPARE_H)
+#endif /* #if !defined(XPREPARE_H) */
diff --git a/src/nvim/xdiff/xtypes.h b/src/xdiff/xtypes.h
index 026999c1bf..8442bd436e 100644
--- a/src/nvim/xdiff/xtypes.h
+++ b/src/xdiff/xtypes.h
@@ -64,4 +64,4 @@ typedef struct s_xdfenv {
-#endif // #if !defined(XTYPES_H)
+#endif /* #if !defined(XTYPES_H) */
diff --git a/src/nvim/xdiff/xutils.c b/src/xdiff/xutils.c
index e8c7d2f884..f13a854536 100644
--- a/src/nvim/xdiff/xutils.c
+++ b/src/xdiff/xutils.c
@@ -20,13 +20,9 @@
*
*/
-#include <limits.h>
-#include <assert.h>
#include "xinclude.h"
-
-
long xdl_bogosqrt(long n) {
long i;
@@ -54,7 +50,7 @@ int xdl_emit_diffrec(char const *rec, long size, char const *pre, long psize,
mb[2].size = (long)strlen(mb[2].ptr);
i++;
}
- if (ecb->outf(ecb->priv, mb, i) < 0) {
+ if (ecb->out_line(ecb->priv, mb, i) < 0) {
return -1;
}
@@ -168,7 +164,7 @@ static int ends_with_optional_cr(const char *l, long s, long i)
s--;
if (s == i)
return 1;
- // do not ignore CR at the end of an incomplete line
+ /* do not ignore CR at the end of an incomplete line */
if (complete && s == i + 1 && l[i] == '\r')
return 1;
return 0;
@@ -208,7 +204,7 @@ int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags)
} else if (flags & XDF_IGNORE_WHITESPACE_CHANGE) {
while (i1 < s1 && i2 < s2) {
if (XDL_ISSPACE(l1[i1]) && XDL_ISSPACE(l2[i2])) {
- // Skip matching spaces and try again
+ /* Skip matching spaces and try again */
while (i1 < s1 && XDL_ISSPACE(l1[i1]))
i1++;
while (i2 < s2 && XDL_ISSPACE(l2[i2]))
@@ -224,7 +220,7 @@ int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags)
i2++;
}
} else if (flags & XDF_IGNORE_CR_AT_EOL) {
- // Find the first difference and see how the line ends
+ /* Find the first difference and see how the line ends */
while (i1 < s1 && i2 < s2 && l1[i1] == l2[i2]) {
i1++;
i2++;
@@ -261,7 +257,7 @@ static unsigned long xdl_hash_record_with_whitespace(char const **data,
for (; ptr < top && *ptr != '\n'; ptr++) {
if (cr_at_eol_only) {
- // do not ignore CR at the end of an incomplete line
+ /* do not ignore CR at the end of an incomplete line */
if (*ptr == '\r' &&
(ptr + 1 < top && ptr[1] == '\n'))
continue;
@@ -274,7 +270,7 @@ static unsigned long xdl_hash_record_with_whitespace(char const **data,
ptr++;
at_eol = (top <= ptr + 1 || ptr[1] == '\n');
if (flags & XDF_IGNORE_WHITESPACE)
- ; // already handled
+ ; /* already handled */
else if (flags & XDF_IGNORE_WHITESPACE_CHANGE
&& !at_eol) {
ha += (ha << 5);
@@ -344,8 +340,9 @@ int xdl_num_out(char *out, long val) {
return str - out;
}
-int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2,
- const char *func, long funclen, xdemitcb_t *ecb) {
+static int xdl_format_hunk_hdr(long s1, long c1, long s2, long c2,
+ const char *func, long funclen,
+ xdemitcb_t *ecb) {
int nb = 0;
mmbuffer_t mb;
char buf[128];
@@ -387,9 +384,21 @@ int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2,
mb.ptr = buf;
mb.size = nb;
- if (ecb->outf(ecb->priv, &mb, 1) < 0)
+ if (ecb->out_line(ecb->priv, &mb, 1) < 0)
return -1;
+ return 0;
+}
+int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2,
+ const char *func, long funclen,
+ xdemitcb_t *ecb) {
+ if (!ecb->out_hunk)
+ return xdl_format_hunk_hdr(s1, c1, s2, c2, func, funclen, ecb);
+ if (ecb->out_hunk(ecb->priv,
+ c1 ? s1 : s1 - 1, c1,
+ c2 ? s2 : s2 - 1, c2,
+ func, funclen) < 0)
+ return -1;
return 0;
}
diff --git a/src/nvim/xdiff/xutils.h b/src/xdiff/xutils.h
index 0bebd93022..fba7bae03c 100644
--- a/src/nvim/xdiff/xutils.h
+++ b/src/xdiff/xutils.h
@@ -44,4 +44,4 @@ int xdl_fall_back_diff(xdfenv_t *diff_env, xpparam_t const *xpp,
-#endif // #if !defined(XUTILS_H)
+#endif /* #if !defined(XUTILS_H) */
diff --git a/test/README.md b/test/README.md
index a6e9080a40..37aa54c157 100644
--- a/test/README.md
+++ b/test/README.md
@@ -256,8 +256,15 @@ Number; !must be defined to function properly):
- `VALGRIND_LOG` (F) (S): overrides valgrind log file name used for `VALGRIND`.
+- `TEST_COLORS` (F) (U) (D): enable pretty colors in test runner.
+
- `TEST_SKIP_FRAGILE` (F) (D): makes test suite skip some fragile tests.
+- `TEST_TIMEOUT` (FU) (I): specifies maximum time, in seconds, before the test
+ suite run is killed
+
+- `NVIM_LUA_NOTRACK` (F) (D): disable reference counting of Lua objects
+
- `NVIM_PROG`, `NVIM_PRG` (F) (S): override path to Neovim executable (default
to `build/bin/nvim`).
diff --git a/test/busted/outputHandlers/nvim.lua b/test/busted/outputHandlers/nvim.lua
index 5456e9ca98..0e9801b94b 100644
--- a/test/busted/outputHandlers/nvim.lua
+++ b/test/busted/outputHandlers/nvim.lua
@@ -1,13 +1,9 @@
local pretty = require 'pl.pretty'
local global_helpers = require('test.helpers')
-local colors
-
-local isWindows = package.config:sub(1,1) == '\\'
-
-if isWindows then
- colors = setmetatable({}, {__index = function() return function(s) return s end end})
-else
+-- Colors are disabled by default. #15610
+local colors = setmetatable({}, {__index = function() return function(s) return s == nil and '' or tostring(s) end end})
+if os.getenv "TEST_COLORS" then
colors = require 'term.colors'
end
diff --git a/test/deprecated.lua b/test/deprecated.lua
new file mode 100644
index 0000000000..b162c8fc93
--- /dev/null
+++ b/test/deprecated.lua
@@ -0,0 +1,9 @@
+-- Island of Misfit Toys
+
+local M = {}
+
+function M.redir_exec()
+ error('redir_exec is deprecated, use nvim_exec() or pcall_err()')
+end
+
+return M
diff --git a/test/functional/api/buffer_updates_spec.lua b/test/functional/api/buffer_updates_spec.lua
index 05ca0d5f4d..c9c9be5406 100644
--- a/test/functional/api/buffer_updates_spec.lua
+++ b/test/functional/api/buffer_updates_spec.lua
@@ -159,9 +159,8 @@ describe('API: buffer events:', function()
tick = tick + 1
expectn('nvim_buf_lines_event', {b, tick, 29, 29, firstfour, false})
- -- create a new empty buffer and wipe out the old one ... this will
- -- turn off buffer events
- command('enew!')
+ -- delete the current buffer to turn off buffer events
+ command('bdelete!')
expectn('nvim_buf_detach_event', {b})
-- add a line at the start of an empty file
@@ -269,7 +268,7 @@ describe('API: buffer events:', function()
'original foo'}, false})
-- type text into the first line of a blank file, one character at a time
- command('enew!')
+ command('bdelete!')
tick = 2
expectn('nvim_buf_detach_event', {b})
local bnew = nvim('get_current_buf')
@@ -666,7 +665,8 @@ describe('API: buffer events:', function()
tick = tick + 1
expectn('nvim_buf_changedtick_event', {b, tick})
- -- close our buffer by creating a new one
+ -- close our buffer and create a new one
+ command('bdelete')
command('enew')
expectn('nvim_buf_detach_event', {b})
diff --git a/test/functional/api/command_spec.lua b/test/functional/api/command_spec.lua
index e6a9e11fd9..37331d11c7 100644
--- a/test/functional/api/command_spec.lua
+++ b/test/functional/api/command_spec.lua
@@ -53,7 +53,7 @@ describe('nvim_get_commands', function()
end)
it('gets various command attributes', function()
- local cmd0 = { addr='arguments', bang=false, bar=false, complete='dir', complete_arg=NIL, count='10', definition='pwd <args>', name='TestCmd', nargs='0', range='10', register=false, script_id=0, }
+ local cmd0 = { addr='arguments', bang=false, bar=false, complete='dir', complete_arg=NIL, count='10', definition='pwd <args>', name='TestCmd', nargs='1', range='10', register=false, script_id=0, }
local cmd1 = { addr=NIL, bang=false, bar=false, complete='custom', complete_arg='ListUsers', count=NIL, definition='!finger <args>', name='Finger', nargs='+', range=NIL, register=false, script_id=1, }
local cmd2 = { addr=NIL, bang=true, bar=false, complete=NIL, complete_arg=NIL, count=NIL, definition='call \128\253R2_foo(<q-args>)', name='Cmd2', nargs='*', range=NIL, register=false, script_id=2, }
local cmd3 = { addr=NIL, bang=false, bar=true, complete=NIL, complete_arg=NIL, count=NIL, definition='call \128\253R3_ohyeah()', name='Cmd3', nargs='0', range=NIL, register=false, script_id=3, }
@@ -62,7 +62,7 @@ describe('nvim_get_commands', function()
command -complete=custom,ListUsers -nargs=+ Finger !finger <args>
]])
eq({Finger=cmd1}, meths.get_commands({builtin=false}))
- command('command -complete=dir -addr=arguments -count=10 TestCmd pwd <args>')
+ command('command -nargs=1 -complete=dir -addr=arguments -count=10 TestCmd pwd <args>')
eq({Finger=cmd1, TestCmd=cmd0}, meths.get_commands({builtin=false}))
source([[
diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua
index d2b555ee5b..50b4b85d2a 100644
--- a/test/functional/api/extmark_spec.lua
+++ b/test/functional/api/extmark_spec.lua
@@ -12,6 +12,7 @@ local feed = helpers.feed
local clear = helpers.clear
local command = helpers.command
local meths = helpers.meths
+local assert_alive = helpers.assert_alive
local function expect(contents)
return eq(contents, helpers.curbuf_contents())
@@ -1381,13 +1382,13 @@ describe('API/extmarks', function()
end)
it('does not crash with append/delete/undo seqence', function()
- meths.exec([[
+ meths.exec([[
let ns = nvim_create_namespace('myplugin')
call nvim_buf_set_extmark(0, ns, 0, 0, {})
call append(0, '')
%delete
undo]],false)
- eq(2, meths.eval('1+1')) -- did not crash
+ assert_alive()
end)
it('works with left and right gravity', function()
diff --git a/test/functional/api/server_notifications_spec.lua b/test/functional/api/server_notifications_spec.lua
index 9ee2570798..6367cc5caa 100644
--- a/test/functional/api/server_notifications_spec.lua
+++ b/test/functional/api/server_notifications_spec.lua
@@ -5,6 +5,8 @@ local eq, clear, eval, command, nvim, next_msg =
local meths = helpers.meths
local exec_lua = helpers.exec_lua
local retry = helpers.retry
+local isCI = helpers.isCI
+local assert_alive = helpers.assert_alive
describe('notify', function()
local channel
@@ -72,18 +74,23 @@ describe('notify', function()
nvim('subscribe', 'event1')
nvim('unsubscribe', 'doesnotexist')
nvim('unsubscribe', 'event1')
- eq(2, eval('1+1')) -- Still alive?
+ assert_alive()
end)
it('cancels stale events on channel close', function()
+ if isCI() then
+ pending('hangs on CI #14083 #15251')
+ return
+ end
if helpers.pending_win32(pending) then return end
local catchan = eval("jobstart(['cat'], {'rpc': v:true})")
- eq({id=catchan, stream='job', mode='rpc', client = {}}, exec_lua ([[
+ local catpath = eval('exepath("cat")')
+ eq({id=catchan, argv={catpath}, stream='job', mode='rpc', client = {}}, exec_lua ([[
vim.rpcnotify(..., "nvim_call_function", 'chanclose', {..., 'rpc'})
vim.rpcnotify(..., "nvim_subscribe", "daily_rant")
return vim.api.nvim_get_chan_info(...)
]], catchan))
- eq(2, eval('1+1')) -- Still alive?
+ assert_alive()
eq({false, 'Invalid channel: '..catchan},
exec_lua ([[ return {pcall(vim.rpcrequest, ..., 'nvim_eval', '1+1')}]], catchan))
retry(nil, 3000, function() eq({}, meths.get_chan_info(catchan)) end) -- cat be dead :(
diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua
index 237a4b01e4..e408890906 100644
--- a/test/functional/api/server_requests_spec.lua
+++ b/test/functional/api/server_requests_spec.lua
@@ -11,6 +11,7 @@ local meths = helpers.meths
local spawn, merge_args = helpers.spawn, helpers.merge_args
local set_session = helpers.set_session
local pcall_err = helpers.pcall_err
+local assert_alive = helpers.assert_alive
describe('server -> client', function()
local cid
@@ -33,7 +34,7 @@ describe('server -> client', function()
call jobstop(ch1)
]])
- eq(2, eval("1+1")) -- Still alive?
+ assert_alive()
end)
describe('simple call', function()
@@ -158,7 +159,7 @@ describe('server -> client', function()
-- do some busywork, so the first request will return
-- before this one
for _ = 1, 5 do
- eq(2, eval("1+1"))
+ assert_alive()
end
eq(1, eval('rpcnotify('..cid..', "nested_done")'))
return 'done!'
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index 91d2745130..ffef6a6066 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -1,6 +1,8 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
+local fmt = string.format
+local assert_alive = helpers.assert_alive
local NIL = helpers.NIL
local clear, nvim, eq, neq = helpers.clear, helpers.nvim, helpers.eq, helpers.neq
local command = helpers.command
@@ -57,7 +59,7 @@ describe('API', function()
eq({'notification', 'nvim_error_event',
{error_types.Exception.id, 'Invalid method: nvim_bogus'}}, next_msg())
-- error didn't close channel.
- eq(2, eval('1+1'))
+ assert_alive()
end)
it('failed async request emits nvim_error_event', function()
@@ -67,7 +69,7 @@ describe('API', function()
{error_types.Exception.id, 'Vim:E492: Not an editor command: bogus'}},
next_msg())
-- error didn't close channel.
- eq(2, eval('1+1'))
+ assert_alive()
end)
it('does not set CA_COMMAND_BUSY #7254', function()
@@ -115,6 +117,19 @@ describe('API', function()
nvim('exec','autocmd BufAdd * :let x1 = "Hello"', false)
nvim('command', 'new foo')
eq('Hello', request('nvim_eval', 'g:x1'))
+
+ -- Line continuations
+ nvim('exec', [[
+ let abc = #{
+ \ a: 1,
+ "\ b: 2,
+ \ c: 3
+ \ }]], false)
+ eq({a = 1, c = 3}, request('nvim_eval', 'g:abc'))
+
+ -- try no spaces before continuations to catch off-by-one error
+ nvim('exec', 'let ab = #{\n\\a: 98,\n"\\ b: 2\n\\}', false)
+ eq({a = 98}, request('nvim_eval', 'g:ab'))
end)
it('non-ASCII input', function()
@@ -518,7 +533,7 @@ describe('API', function()
nvim("notify", "hello world", 2, {})
end)
- it('can be overriden', function()
+ it('can be overridden', function()
command("lua vim.notify = function(...) return 42 end")
eq(42, meths.exec_lua("return vim.notify('Hello world')", {}))
nvim("notify", "hello world", 4, {})
@@ -1326,10 +1341,10 @@ describe('API', function()
end)
end)
- describe('nvim_list_chans and nvim_get_chan_info', function()
+ describe('nvim_list_chans, nvim_get_chan_info', function()
before_each(function()
- command('autocmd ChanOpen * let g:opened_event = copy(v:event)')
- command('autocmd ChanInfo * let g:info_event = copy(v:event)')
+ command('autocmd ChanOpen * let g:opened_event = deepcopy(v:event)')
+ command('autocmd ChanInfo * let g:info_event = deepcopy(v:event)')
end)
local testinfo = {
stream = 'stdio',
@@ -1350,7 +1365,7 @@ describe('API', function()
eq({}, meths.get_chan_info(10))
end)
- it('works for stdio channel', function()
+ it('stream=stdio channel', function()
eq({[1]=testinfo,[2]=stderr}, meths.list_chans())
eq(testinfo, meths.get_chan_info(1))
eq(stderr, meths.get_chan_info(2))
@@ -1377,11 +1392,13 @@ describe('API', function()
eq(info, meths.get_chan_info(1))
end)
- it('works for job channel', function()
+ it('stream=job channel', function()
eq(3, eval("jobstart(['cat'], {'rpc': v:true})"))
+ local catpath = eval('exepath("cat")')
local info = {
stream='job',
id=3,
+ argv={ catpath },
mode='rpc',
client={},
}
@@ -1394,6 +1411,7 @@ describe('API', function()
info = {
stream='job',
id=3,
+ argv={ catpath },
mode='rpc',
client = {
name='amazing-cat',
@@ -1410,14 +1428,15 @@ describe('API', function()
pcall_err(eval, 'rpcrequest(3, "nvim_set_current_buf", -1)'))
end)
- it('works for :terminal channel', function()
- command(":terminal")
+ it('stream=job :terminal channel', function()
+ command(':terminal')
eq({id=1}, meths.get_current_buf())
- eq(3, meths.buf_get_option(1, "channel"))
+ eq(3, meths.buf_get_option(1, 'channel'))
local info = {
stream='job',
id=3,
+ argv={ eval('exepath(&shell)') },
mode='terminal',
buffer = 1,
pty='?',
@@ -1431,6 +1450,38 @@ describe('API', function()
info.buffer = {id=1}
eq({[1]=testinfo,[2]=stderr,[3]=info}, meths.list_chans())
eq(info, meths.get_chan_info(3))
+
+ -- :terminal with args + running process.
+ command(':exe "terminal" shellescape(v:progpath) "-u NONE -i NONE"')
+ eq(-1, eval('jobwait([&channel], 0)[0]')) -- Running?
+ local expected2 = {
+ stream = 'job',
+ id = 4,
+ argv = (
+ iswin() and {
+ eval('&shell'),
+ '/s',
+ '/c',
+ fmt('"%s -u NONE -i NONE"', eval('shellescape(v:progpath)')),
+ } or {
+ eval('&shell'),
+ eval('&shellcmdflag'),
+ fmt('%s -u NONE -i NONE', eval('shellescape(v:progpath)')),
+ }
+ ),
+ mode = 'terminal',
+ buffer = 2,
+ pty = '?',
+ }
+ local actual2 = eval('nvim_get_chan_info(&channel)')
+ expected2.pty = actual2.pty
+ eq(expected2, actual2)
+
+ -- :terminal with args + stopped process.
+ eq(1, eval('jobstop(&channel)'))
+ eval('jobwait([&channel], 1000)') -- Wait.
+ expected2.pty = (iswin() and '?' or '') -- pty stream was closed.
+ eq(expected2, eval('nvim_get_chan_info(&channel)'))
end)
end)
@@ -1540,7 +1591,10 @@ describe('API', function()
eq({'a', '', 'b'}, meths.list_runtime_paths())
meths.set_option('runtimepath', ',a,b')
eq({'', 'a', 'b'}, meths.list_runtime_paths())
+ -- trailing , is ignored, use ,, if you really really want $CWD
meths.set_option('runtimepath', 'a,b,')
+ eq({'a', 'b'}, meths.list_runtime_paths())
+ meths.set_option('runtimepath', 'a,b,,')
eq({'a', 'b', ''}, meths.list_runtime_paths())
end)
it('truncates too long paths', function()
@@ -1961,8 +2015,13 @@ describe('API', function()
ok(endswith(val[1], p"autoload/remote/define.vim")
or endswith(val[1], p"autoload/remote/host.vim"))
- eq({}, meths.get_runtime_file("lua", true))
- eq({}, meths.get_runtime_file("lua/vim", true))
+ val = meths.get_runtime_file("lua", true)
+ eq(1, #val)
+ ok(endswith(val[1], p"lua"))
+
+ val = meths.get_runtime_file("lua/vim", true)
+ eq(1, #val)
+ ok(endswith(val[1], p"lua/vim"))
end)
it('can find directories', function()
diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua
index bb72b63b6c..11755a9d97 100644
--- a/test/functional/api/window_spec.lua
+++ b/test/functional/api/window_spec.lua
@@ -1,8 +1,9 @@
local helpers = require('test.functional.helpers')(after_each)
local clear, nvim, curbuf, curbuf_contents, window, curwin, eq, neq,
- ok, feed, insert, eval = helpers.clear, helpers.nvim, helpers.curbuf,
+ ok, feed, insert, eval, tabpage = helpers.clear, helpers.nvim, helpers.curbuf,
helpers.curbuf_contents, helpers.window, helpers.curwin, helpers.eq,
- helpers.neq, helpers.ok, helpers.feed, helpers.insert, helpers.eval
+ helpers.neq, helpers.ok, helpers.feed, helpers.insert, helpers.eval,
+ helpers.tabpage
local poke_eventloop = helpers.poke_eventloop
local curwinmeths = helpers.curwinmeths
local funcs = helpers.funcs
@@ -11,6 +12,7 @@ local NIL = helpers.NIL
local meths = helpers.meths
local command = helpers.command
local pcall_err = helpers.pcall_err
+local assert_alive = helpers.assert_alive
-- check if str is visible at the beginning of some line
local function is_visible(str)
@@ -206,7 +208,7 @@ describe('API/win', function()
end)
end)
- describe('{get,set}_option', function()
+ describe('nvim_win_get_option, nvim_win_set_option', function()
it('works', function()
curwin('set_option', 'colorcolumn', '4,3')
eq('4,3', curwin('get_option', 'colorcolumn'))
@@ -224,6 +226,18 @@ describe('API/win', function()
pcall_err(curwin, 'get_option', 'statusline'))
eq('', eval('&l:statusline')) -- confirm local value was not copied
end)
+
+ it('after switching windows #15390', function()
+ nvim('command', 'tabnew')
+ local tab1 = unpack(nvim('list_tabpages'))
+ local win1 = unpack(tabpage('list_wins', tab1))
+ window('set_option', win1, 'statusline', 'window-status')
+ nvim('command', 'split')
+ nvim('command', 'wincmd J')
+ nvim('command', 'wincmd j')
+ eq('window-status', window('get_option', win1, 'statusline'))
+ assert_alive()
+ end)
end)
describe('get_position', function()
@@ -311,7 +325,8 @@ describe('API/win', function()
eq({newwin}, meths.list_wins())
end)
- it('handles changed buffer', function()
+ it("handles changed buffer when 'hidden' is unset", function()
+ command('set nohidden')
local oldwin = meths.get_current_win()
insert('text')
command('new')
@@ -346,6 +361,21 @@ describe('API/win', function()
eq(2, #meths.list_wins())
eq('', funcs.getcmdwintype())
end)
+
+ it('closing current (float) window of another tabpage #15313', function()
+ command('tabedit')
+ eq(2, eval('tabpagenr()'))
+ local win = meths.open_win(0, true, {
+ relative='editor', row=10, col=10, width=50, height=10
+ })
+ local tab = eval('tabpagenr()')
+ command('tabprevious')
+ eq(1, eval('tabpagenr()'))
+ meths.win_close(win, false)
+
+ eq(1001, meths.tabpage_get_win(tab).id)
+ assert_alive()
+ end)
end)
describe('hide', function()
diff --git a/test/functional/autoread/focus_spec.lua b/test/functional/autocmd/focus_spec.lua
index 3f9a0ad09b..3f9a0ad09b 100644
--- a/test/functional/autoread/focus_spec.lua
+++ b/test/functional/autocmd/focus_spec.lua
diff --git a/test/functional/autocmd/tabnewentered_spec.lua b/test/functional/autocmd/tabnewentered_spec.lua
index dc2fd3e97d..b186aa1f50 100644
--- a/test/functional/autocmd/tabnewentered_spec.lua
+++ b/test/functional/autocmd/tabnewentered_spec.lua
@@ -7,7 +7,7 @@ local eval = helpers.eval
local eq = helpers.eq
local feed = helpers.feed
local nvim = helpers.nvim
-local redir_exec = helpers.redir_exec
+local exec_capture = helpers.exec_capture
describe('TabNewEntered', function()
describe('au TabNewEntered', function()
@@ -77,7 +77,6 @@ describe('tabpage/previous', function()
eq(dedent([=[
-
Tab page 1
[No Name]
Tab page 2
@@ -86,7 +85,7 @@ describe('tabpage/previous', function()
> [No Name]
Tab page 4
# [No Name]]=]),
- redir_exec('tabs')
+ exec_capture('tabs')
)
-- The previous tab is now the fourth.
@@ -117,7 +116,6 @@ describe('tabpage/previous', function()
feed(characters)
eq(dedent([=[
-
Tab page 1
[No Name]
Tab page 2
@@ -128,7 +126,7 @@ describe('tabpage/previous', function()
[No Name]
Tab page 5
[No Name]]=]),
- redir_exec('tabs')
+ exec_capture('tabs')
)
-- The previous tab is now the third.
@@ -161,7 +159,6 @@ describe('tabpage/previous', function()
eq(dedent([=[
-
Tab page 1
# [No Name]
Tab page 2
@@ -170,7 +167,7 @@ describe('tabpage/previous', function()
[No Name]
Tab page 4
> [No Name]]=]),
- redir_exec('tabs')
+ exec_capture('tabs')
)
-- The previous tab is now the first.
@@ -205,7 +202,6 @@ describe('tabpage/previous', function()
eq(dedent([=[
-
Tab page 1
> [No Name]
Tab page 2
@@ -214,7 +210,7 @@ describe('tabpage/previous', function()
[No Name]
Tab page 4
# [No Name]]=]),
- redir_exec('tabs')
+ exec_capture('tabs')
)
-- The previous tab is now the fourth.
@@ -247,7 +243,6 @@ describe('tabpage/previous', function()
eq(dedent([=[
-
Tab page 1
[No Name]
Tab page 2
@@ -256,7 +251,7 @@ describe('tabpage/previous', function()
# [No Name]
Tab page 4
> [No Name]]=]),
- redir_exec('tabs')
+ exec_capture('tabs')
)
-- The previous tab is now the third.
@@ -291,7 +286,6 @@ describe('tabpage/previous', function()
eq(dedent([=[
-
Tab page 1
# [No Name]
Tab page 2
@@ -300,7 +294,7 @@ describe('tabpage/previous', function()
> [No Name]
Tab page 4
[No Name]]=]),
- redir_exec('tabs')
+ exec_capture('tabs')
)
-- The previous tab is now the first.
@@ -333,7 +327,6 @@ describe('tabpage/previous', function()
eq(dedent([=[
-
Tab page 1
[No Name]
Tab page 2
@@ -342,7 +335,7 @@ describe('tabpage/previous', function()
[No Name]
Tab page 4
> [No Name]]=]),
- redir_exec('tabs')
+ exec_capture('tabs')
)
-- The previous tab is now the second.
@@ -377,7 +370,6 @@ describe('tabpage/previous', function()
eq(dedent([=[
-
Tab page 1
[No Name]
Tab page 2
@@ -386,7 +378,7 @@ describe('tabpage/previous', function()
[No Name]
Tab page 4
# [No Name]]=]),
- redir_exec('tabs')
+ exec_capture('tabs')
)
-- The previous tab is now the fourth.
@@ -444,14 +436,13 @@ describe('tabpage/previous', function()
eq(dedent([=[
-
Tab page 1
[No Name]
Tab page 2
[No Name]
Tab page 3
> [No Name]]=]),
- redir_exec('tabs')
+ exec_capture('tabs')
)
-- The previous tab is now the "zero".
@@ -567,7 +558,6 @@ describe('tabpage/previous', function()
eq(dedent([=[
-
Tab page 1
[No Name]
Tab page 2
@@ -578,7 +568,7 @@ describe('tabpage/previous', function()
[No Name]
Tab page 4
> [No Name]]=]),
- redir_exec('tabs')
+ exec_capture('tabs')
)
end)
end)
diff --git a/test/functional/autocmd/termxx_spec.lua b/test/functional/autocmd/termxx_spec.lua
index b12c24b58d..1e8f981437 100644
--- a/test/functional/autocmd/termxx_spec.lua
+++ b/test/functional/autocmd/termxx_spec.lua
@@ -13,7 +13,7 @@ describe('autocmd TermClose', function()
before_each(function()
clear()
nvim('set_option', 'shell', nvim_dir .. '/shell-test')
- nvim('set_option', 'shellcmdflag', 'EXE')
+ command('set shellcmdflag=EXE shellredir= shellpipe= shellquote= shellxquote=')
end)
it('triggers when fast-exiting terminal job stops', function()
@@ -90,6 +90,17 @@ describe('autocmd TermClose', function()
retry(nil, nil, function() eq('3', eval('g:abuf')) end)
feed('<c-c>:qa!<cr>')
end)
+
+ it('exposes v:event.status', function()
+ command('set shellcmdflag=EXIT')
+ command('autocmd TermClose * let g:status = v:event.status')
+
+ command('terminal 0')
+ retry(nil, nil, function() eq(0, eval('g:status')) end)
+
+ command('terminal 42')
+ retry(nil, nil, function() eq(42, eval('g:status')) end)
+ end)
end)
it('autocmd TermEnter, TermLeave', function()
diff --git a/test/functional/cmdline/ctrl_r_spec.lua b/test/functional/cmdline/ctrl_r_spec.lua
deleted file mode 100644
index a0f3955282..0000000000
--- a/test/functional/cmdline/ctrl_r_spec.lua
+++ /dev/null
@@ -1,34 +0,0 @@
-local helpers = require('test.functional.helpers')(after_each)
-local clear, insert, funcs, eq, feed =
- helpers.clear, helpers.insert, helpers.funcs, helpers.eq, helpers.feed
-
-describe('cmdline CTRL-R', function()
- before_each(clear)
-
- it('pasting non-special register inserts <CR> *between* lines', function()
- insert([[
- line1abc
- line2somemoretext
- ]])
- -- Yank 2 lines linewise, then paste to cmdline.
- feed([[<C-\><C-N>gg0yj:<C-R>0]])
- -- <CR> inserted between lines, NOT after the final line.
- eq('line1abc\rline2somemoretext', funcs.getcmdline())
-
- -- Yank 2 lines charwise, then paste to cmdline.
- feed([[<C-\><C-N>gg05lyvj:<C-R>0]])
- -- <CR> inserted between lines, NOT after the final line.
- eq('abc\rline2', funcs.getcmdline())
-
- -- Yank 1 line linewise, then paste to cmdline.
- feed([[<C-\><C-N>ggyy:<C-R>0]])
- -- No <CR> inserted.
- eq('line1abc', funcs.getcmdline())
- end)
-
- it('pasting special register inserts <CR>, <NL>', function()
- feed([[:<C-R>="foo\nbar\rbaz"<CR>]])
- eq('foo\nbar\rbaz', funcs.getcmdline())
- end)
-end)
-
diff --git a/test/functional/core/channels_spec.lua b/test/functional/core/channels_spec.lua
index 1ef34c7318..6efa4f9b80 100644
--- a/test/functional/core/channels_spec.lua
+++ b/test/functional/core/channels_spec.lua
@@ -89,6 +89,9 @@ describe('channels', function()
command("call chansend(id, 'howdy')")
eq({"notification", "stdout", {id, {"[1, ['howdy'], 'stdin']"}}}, next_msg())
+ command("call chansend(id, 0z686f6c61)")
+ eq({"notification", "stdout", {id, {"[1, ['hola'], 'stdin']"}}}, next_msg())
+
command("call chanclose(id, 'stdin')")
expect_twostreams({{"notification", "stdout", {id, {"[1, [''], 'stdin']"}}},
{'notification', 'stdout', {id, {''}}}},
@@ -131,6 +134,8 @@ describe('channels', function()
command("call chansend(id, 'TEXT\n')")
expect_twoline(id, "stdout", "TEXT\r", "[1, ['TEXT', ''], 'stdin']")
+ command("call chansend(id, 0z426c6f6273210a)")
+ expect_twoline(id, "stdout", "Blobs!\r", "[1, ['Blobs!', ''], 'stdin']")
command("call chansend(id, 'neovan')")
eq({"notification", "stdout", {id, {"neovan"}}}, next_msg())
diff --git a/test/functional/core/exit_spec.lua b/test/functional/core/exit_spec.lua
index 230b7f8e01..a47e7568a9 100644
--- a/test/functional/core/exit_spec.lua
+++ b/test/functional/core/exit_spec.lua
@@ -1,5 +1,6 @@
local helpers = require('test.functional.helpers')(after_each)
+local assert_alive = helpers.assert_alive
local command = helpers.command
local feed_command = helpers.feed_command
local eval = helpers.eval
@@ -7,7 +8,8 @@ local eq = helpers.eq
local run = helpers.run
local funcs = helpers.funcs
local nvim_prog = helpers.nvim_prog
-local redir_exec = helpers.redir_exec
+local pcall_err = helpers.pcall_err
+local exec_capture = helpers.exec_capture
local poke_eventloop = helpers.poke_eventloop
describe('v:exiting', function()
@@ -51,9 +53,9 @@ end)
describe(':cquit', function()
local function test_cq(cmdline, exit_code, redir_msg)
if redir_msg then
- eq('\n' .. redir_msg, redir_exec(cmdline))
+ eq(redir_msg, pcall_err(function() return exec_capture(cmdline) end))
poke_eventloop()
- eq(2, eval("1+1")) -- Still alive?
+ assert_alive()
else
funcs.system({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--headless', '--cmd', cmdline})
eq(exit_code, eval('v:shell_error'))
@@ -85,14 +87,14 @@ describe(':cquit', function()
end)
it('exits with redir msg for multiple exit codes after :cquit 1 2', function()
- test_cq('cquit 1 2', nil, 'E488: Trailing characters: cquit 1 2')
+ test_cq('cquit 1 2', nil, 'Vim(cquit):E488: Trailing characters: cquit 1 2')
end)
it('exits with redir msg for non-number exit code after :cquit X', function()
- test_cq('cquit X', nil, 'E488: Trailing characters: cquit X')
+ test_cq('cquit X', nil, 'Vim(cquit):E488: Trailing characters: cquit X')
end)
it('exits with redir msg for negative exit code after :cquit -1', function()
- test_cq('cquit -1', nil, 'E488: Trailing characters: cquit -1')
+ test_cq('cquit -1', nil, 'Vim(cquit):E488: Trailing characters: cquit -1')
end)
end)
diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua
index 34ab90d760..5e127bce26 100644
--- a/test/functional/core/job_spec.lua
+++ b/test/functional/core/job_spec.lua
@@ -5,6 +5,7 @@ local clear, eq, eval, exc_exec, feed_command, feed, insert, neq, next_msg, nvim
helpers.insert, helpers.neq, helpers.next_msg, helpers.nvim,
helpers.nvim_dir, helpers.ok, helpers.source,
helpers.write_file, helpers.mkdir, helpers.rmdir
+local assert_alive = helpers.assert_alive
local command = helpers.command
local funcs = helpers.funcs
local os_kill = helpers.os_kill
@@ -348,6 +349,12 @@ describe('jobs', function()
eq(false, pcall(function()
nvim('command', 'call jobsend(j, ["some data"])')
end))
+
+ command("let g:job_opts.stdin = 'null'")
+ nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)")
+ eq(false, pcall(function()
+ nvim('command', 'call jobsend(j, ["some data"])')
+ end))
end)
it('disallows jobsend on a non-existent job', function()
@@ -864,7 +871,7 @@ describe('jobs', function()
-- loop tick. This is also prevented by try-block, so feed must be used.
feed_command("call DoIt()")
feed('<cr>') -- press RETURN
- eq(2,eval('1+1'))
+ assert_alive()
end)
it('jobstop() kills entire process tree #6530', function()
diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua
index a70b94c0e9..1d83eb799f 100644
--- a/test/functional/core/startup_spec.lua
+++ b/test/functional/core/startup_spec.lua
@@ -1,6 +1,7 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
+local assert_alive = helpers.assert_alive
local clear = helpers.clear
local command = helpers.command
local ok = helpers.ok
@@ -231,7 +232,7 @@ describe('startup', function()
it('does not crash if --embed is given twice', function()
clear{args={'--embed'}}
- eq(2, eval('1+1'))
+ assert_alive()
end)
it('does not crash when expanding cdpath during early_init', function()
@@ -247,9 +248,9 @@ describe('startup', function()
[[" -u NONE -i NONE --cmd "set noruler" --cmd "let g:foo = g:bar"')]])
screen:expect([[
^ |
+ |
Error detected while processing pre-vimrc command line: |
E121: Undefined variable: g:bar |
- E15: Invalid expression: g:bar |
Press ENTER or type command to continue |
|
]])
@@ -309,7 +310,8 @@ describe('startup', function()
end)
local function pack_clear(cmd)
- clear('--cmd', 'set packpath=test/functional/fixtures', '--cmd', cmd)
+ -- add packages after config dir in rtp but before config/after
+ clear{args={'--cmd', 'set packpath=test/functional/fixtures', '--cmd', 'let paths=split(&rtp, ",")', '--cmd', 'let &rtp = paths[0]..",test/functional/fixtures,test/functional/fixtures/middle,"..join(paths[1:],",")', '--cmd', cmd}, env={XDG_CONFIG_HOME='test/functional/fixtures/'}}
end
@@ -347,6 +349,22 @@ describe('startup', function()
pack_clear [[ packadd! bonus | lua _G.y = require'bonus'.launch() ]]
eq('CPE 1704 TKS', exec_lua [[ return _G.y ]])
end)
+
+ it("handles the correct order with start packages and after/", function()
+ pack_clear [[ lua _G.test_loadorder = {} vim.cmd "runtime! filen.lua" ]]
+ eq({'ordinary', 'FANCY', 'mittel', 'FANCY after', 'ordinary after'}, exec_lua [[ return _G.test_loadorder ]])
+ end)
+
+ it("handles the correct order with opt packages and after/", function()
+ pack_clear [[ lua _G.test_loadorder = {} vim.cmd "packadd! superspecial\nruntime! filen.lua" ]]
+ eq({'ordinary', 'SuperSpecial', 'FANCY', 'mittel', 'FANCY after', 'SuperSpecial after', 'ordinary after'}, exec_lua [[ return _G.test_loadorder ]])
+ end)
+
+ it("handles the correct order with a package that changes packpath", function()
+ pack_clear [[ lua _G.test_loadorder = {} vim.cmd "packadd! funky\nruntime! filen.lua" ]]
+ eq({'ordinary', 'funky!', 'FANCY', 'mittel', 'FANCY after', 'ordinary after'}, exec_lua [[ return _G.test_loadorder ]])
+ eq({'ordinary', 'funky!', 'mittel', 'ordinary after'}, exec_lua [[ return _G.nested_order ]])
+ end)
end)
describe('sysinit', function()
@@ -438,12 +456,15 @@ describe('user config init', function()
local xhome = 'Xhome'
local pathsep = helpers.get_pathsep()
local xconfig = xhome .. pathsep .. 'Xconfig'
+ local xdata = xhome .. pathsep .. 'Xdata'
local init_lua_path = table.concat({xconfig, 'nvim', 'init.lua'}, pathsep)
+ local xenv = { XDG_CONFIG_HOME=xconfig, XDG_DATA_HOME=xdata }
before_each(function()
rmdir(xhome)
mkdir_p(xconfig .. pathsep .. 'nvim')
+ mkdir_p(xdata)
write_file(init_lua_path, [[
vim.g.lua_rc = 1
@@ -455,10 +476,10 @@ describe('user config init', function()
end)
it('loads init.lua from XDG config home by default', function()
- clear{ args_rm={'-u' }, env={ XDG_CONFIG_HOME=xconfig }}
+ clear{ args_rm={'-u' }, env=xenv }
eq(1, eval('g:lua_rc'))
- eq(init_lua_path, eval('$MYVIMRC'))
+ eq(funcs.fnamemodify(init_lua_path, ':p'), eval('$MYVIMRC'))
end)
describe 'with explicitly provided config'(function()
@@ -470,7 +491,7 @@ describe('user config init', function()
end)
it('loads custom lua config and does not set $MYVIMRC', function()
- clear{ args={'-u', custom_lua_path }, env={ XDG_CONFIG_HOME=xconfig }}
+ clear{ args={'-u', custom_lua_path }, env=xenv }
eq(1, eval('g:custom_lua_rc'))
eq('', eval('$MYVIMRC'))
end)
@@ -484,10 +505,10 @@ describe('user config init', function()
end)
it('loads default lua config, but shows an error', function()
- clear{ args_rm={'-u'}, env={ XDG_CONFIG_HOME=xconfig }}
+ clear{ args_rm={'-u'}, env=xenv }
feed('<cr>') -- TODO check this, test execution is blocked without it
eq(1, eval('g:lua_rc'))
- matches('Conflicting configs', meths.exec('messages', true))
+ matches('^E5422: Conflicting configs', meths.exec('messages', true))
end)
end)
end)
@@ -496,9 +517,13 @@ describe('runtime:', function()
local xhome = 'Xhome'
local pathsep = helpers.get_pathsep()
local xconfig = xhome .. pathsep .. 'Xconfig'
+ local xdata = xhome .. pathsep .. 'Xdata'
+ local xenv = { XDG_CONFIG_HOME=xconfig, XDG_DATA_HOME=xdata }
setup(function()
+ rmdir(xhome)
mkdir_p(xconfig .. pathsep .. 'nvim')
+ mkdir_p(xdata)
end)
teardown(function()
@@ -511,13 +536,13 @@ describe('runtime:', function()
mkdir_p(plugin_folder_path)
write_file(plugin_file_path, [[ vim.g.lua_plugin = 1 ]])
- clear{ args_rm={'-u'}, env={ XDG_CONFIG_HOME=xconfig }}
+ clear{ args_rm={'-u'}, env=xenv }
eq(1, eval('g:lua_plugin'))
rmdir(plugin_folder_path)
end)
- it('loads plugin/*.lua from start plugins', function()
+ it('loads plugin/*.lua from start packages', function()
local plugin_path = table.concat({xconfig, 'nvim', 'pack', 'catagory',
'start', 'test_plugin'}, pathsep)
local plugin_folder_path = table.concat({plugin_path, 'plugin'}, pathsep)
@@ -528,7 +553,7 @@ describe('runtime:', function()
mkdir_p(plugin_folder_path)
write_file(plugin_file_path, [[vim.g.lua_plugin = 2]])
- clear{ args_rm={'-u'}, args={'--startuptime', profiler_file}, env={ XDG_CONFIG_HOME=xconfig }}
+ clear{ args_rm={'-u'}, args={'--startuptime', profiler_file}, env=xenv }
eq(2, eval('g:lua_plugin'))
-- Check if plugin_file_path is listed in :scriptname
@@ -545,6 +570,27 @@ describe('runtime:', function()
rmdir(plugin_path)
end)
+ it('loads plugin/*.lua from site packages', function()
+ local nvimdata = iswin() and "nvim-data" or "nvim"
+ local plugin_path = table.concat({xdata, nvimdata, 'site', 'pack', 'xa', 'start', 'yb'}, pathsep)
+ local plugin_folder_path = table.concat({plugin_path, 'plugin'}, pathsep)
+ local plugin_after_path = table.concat({plugin_path, 'after', 'plugin'}, pathsep)
+ local plugin_file_path = table.concat({plugin_folder_path, 'plugin.lua'}, pathsep)
+ local plugin_after_file_path = table.concat({plugin_after_path, 'helloo.lua'}, pathsep)
+
+ mkdir_p(plugin_folder_path)
+ write_file(plugin_file_path, [[table.insert(_G.lista, "unos")]])
+ mkdir_p(plugin_after_path)
+ write_file(plugin_after_file_path, [[table.insert(_G.lista, "dos")]])
+
+ clear{ args_rm={'-u'}, args={'--cmd', 'lua _G.lista = {}'}, env=xenv }
+
+ eq({'unos', 'dos'}, exec_lua "return _G.lista")
+
+ rmdir(plugin_path)
+ end)
+
+
it('loads ftdetect/*.lua', function()
local ftdetect_folder = table.concat({xconfig, 'nvim', 'ftdetect'}, pathsep)
local ftdetect_file = table.concat({ftdetect_folder , 'new-ft.lua'}, pathsep)
@@ -554,6 +600,7 @@ describe('runtime:', function()
-- TODO(shadmansaleh): Figure out why this test fails without
-- setting VIMRUNTIME
clear{ args_rm={'-u'}, env={XDG_CONFIG_HOME=xconfig,
+ XDG_DATA_HOME=xdata,
VIMRUNTIME='runtime/'}}
eq(1, eval('g:lua_ftdetect'))
diff --git a/test/functional/normal/K_spec.lua b/test/functional/editor/K_spec.lua
index 174313d80e..40f36491e4 100644
--- a/test/functional/normal/K_spec.lua
+++ b/test/functional/editor/K_spec.lua
@@ -1,6 +1,6 @@
local helpers = require('test.functional.helpers')(after_each)
-local eq, clear, eval, feed =
- helpers.eq, helpers.clear, helpers.eval, helpers.feed
+local eq, clear, eval, feed, retry =
+ helpers.eq, helpers.clear, helpers.eval, helpers.feed, helpers.retry
describe('K', function()
local test_file = 'K_spec_out'
@@ -31,7 +31,7 @@ describe('K', function()
-- K on the text "K_spec_out" resolves to `!echo fnord >> K_spec_out`.
feed('i'..test_file..'<ESC>K')
- feed('<CR>') -- Press ENTER
+ retry(nil, nil, function() eq(1, eval('filereadable("'..test_file..'")')) end)
eq({'fnord'}, eval("readfile('"..test_file.."')"))
end)
diff --git a/test/functional/viml/completion_spec.lua b/test/functional/editor/completion_spec.lua
index a4241fe5aa..befad29922 100644
--- a/test/functional/viml/completion_spec.lua
+++ b/test/functional/editor/completion_spec.lua
@@ -1,5 +1,6 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
+local assert_alive = helpers.assert_alive
local clear, feed = helpers.clear, helpers.feed
local eval, eq, neq = helpers.eval, helpers.eq, helpers.neq
local feed_command, source, expect = helpers.feed_command, helpers.source, helpers.expect
@@ -870,7 +871,7 @@ describe('completion', function()
{3:-- Keyword completion (^N^P) }{4:match 1 of 2} |
]])
- eval('1 + 1')
+ assert_alive()
-- popupmenu still visible
screen:expect{grid=[[
foobar fooegg |
diff --git a/test/functional/normal/count_spec.lua b/test/functional/editor/count_spec.lua
index 94f741250a..94f741250a 100644
--- a/test/functional/normal/count_spec.lua
+++ b/test/functional/editor/count_spec.lua
diff --git a/test/functional/normal/fold_spec.lua b/test/functional/editor/fold_spec.lua
index 00e83bedc8..00e83bedc8 100644
--- a/test/functional/normal/fold_spec.lua
+++ b/test/functional/editor/fold_spec.lua
diff --git a/test/functional/normal/jump_spec.lua b/test/functional/editor/jump_spec.lua
index 9e7158e2f7..d09c20f226 100644
--- a/test/functional/normal/jump_spec.lua
+++ b/test/functional/editor/jump_spec.lua
@@ -5,7 +5,7 @@ local command = helpers.command
local eq = helpers.eq
local funcs = helpers.funcs
local feed = helpers.feed
-local redir_exec = helpers.redir_exec
+local exec_capture = helpers.exec_capture
local write_file = helpers.write_file
describe('jumplist', function()
@@ -78,7 +78,7 @@ describe("jumpoptions=stack behaves like 'tagstack'", function()
feed('<C-O>')
feed('<C-O>')
- eq( '\n'
+ eq( ''
.. ' jump line col file/text\n'
.. ' 4 102 0 \n'
.. ' 3 1 0 Line 1\n'
@@ -87,11 +87,11 @@ describe("jumpoptions=stack behaves like 'tagstack'", function()
.. '> 0 30 0 Line 30\n'
.. ' 1 40 0 Line 40\n'
.. ' 2 50 0 Line 50',
- redir_exec('jumps'))
+ exec_capture('jumps'))
feed('90gg')
- eq( '\n'
+ eq( ''
.. ' jump line col file/text\n'
.. ' 5 102 0 \n'
.. ' 4 1 0 Line 1\n'
@@ -99,14 +99,14 @@ describe("jumpoptions=stack behaves like 'tagstack'", function()
.. ' 2 20 0 Line 20\n'
.. ' 1 30 0 Line 30\n'
.. '>',
- redir_exec('jumps'))
+ exec_capture('jumps'))
end)
it('does not add the same location twice adjacently', function()
feed('60gg')
feed('60gg')
- eq( '\n'
+ eq( ''
.. ' jump line col file/text\n'
.. ' 7 102 0 \n'
.. ' 6 1 0 Line 1\n'
@@ -116,14 +116,14 @@ describe("jumpoptions=stack behaves like 'tagstack'", function()
.. ' 2 40 0 Line 40\n'
.. ' 1 50 0 Line 50\n'
.. '>',
- redir_exec('jumps'))
+ exec_capture('jumps'))
end)
it('does add the same location twice nonadjacently', function()
feed('10gg')
feed('20gg')
- eq( '\n'
+ eq( ''
.. ' jump line col file/text\n'
.. ' 8 102 0 \n'
.. ' 7 1 0 Line 1\n'
@@ -134,6 +134,6 @@ describe("jumpoptions=stack behaves like 'tagstack'", function()
.. ' 2 50 0 Line 50\n'
.. ' 1 10 0 Line 10\n'
.. '>',
- redir_exec('jumps'))
+ exec_capture('jumps'))
end)
end)
diff --git a/test/functional/normal/lang_spec.lua b/test/functional/editor/lang_spec.lua
index 24d1262f5f..24d1262f5f 100644
--- a/test/functional/normal/lang_spec.lua
+++ b/test/functional/editor/lang_spec.lua
diff --git a/test/functional/normal/langmap_spec.lua b/test/functional/editor/langmap_spec.lua
index e4349a22e7..e4349a22e7 100644
--- a/test/functional/normal/langmap_spec.lua
+++ b/test/functional/editor/langmap_spec.lua
diff --git a/test/functional/normal/macro_spec.lua b/test/functional/editor/macro_spec.lua
index 102d8fc723..102d8fc723 100644
--- a/test/functional/normal/macro_spec.lua
+++ b/test/functional/editor/macro_spec.lua
diff --git a/test/functional/insert/insert_spec.lua b/test/functional/editor/meta_key_spec.lua
index 330cfbd830..2a9541ba96 100644
--- a/test/functional/insert/insert_spec.lua
+++ b/test/functional/editor/meta_key_spec.lua
@@ -1,32 +1,40 @@
local helpers = require('test.functional.helpers')(after_each)
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
local command = helpers.command
-local eq = helpers.eq
local expect = helpers.expect
local funcs = helpers.funcs
+local eq = helpers.eq
-describe('insert-mode', function()
+describe('meta-keys #8226 #13042', function()
before_each(function()
clear()
end)
- it('CTRL-@', function()
- -- Inserts last-inserted text, leaves insert-mode.
+ it('ALT/META, normal-mode', function()
+ -- Unmapped ALT-chords behave as ESC+c
insert('hello')
- feed('i<C-@>x')
- expect('hellhello')
-
- -- C-Space is the same as C-@.
- -- CTRL-SPC inserts last-inserted text, leaves insert-mode.
- feed('i<C-Space>x')
- expect('hellhellhello')
+ feed('0<A-x><M-x>')
+ expect('llo')
+ -- Mapped ALT-chord behaves as mapped.
+ command('nnoremap <M-l> Ameta-l<Esc>')
+ command('nnoremap <A-j> Aalt-j<Esc>')
+ feed('<A-j><M-l>')
+ expect('lloalt-jmeta-l')
+ end)
- -- CTRL-A inserts last inserted text
- feed('i<C-A>x')
- expect('hellhellhellhelloxo')
+ it('ALT/META, visual-mode', function()
+ -- Unmapped ALT-chords behave as ESC+c
+ insert('peaches')
+ feed('viw<A-x>viw<M-x>')
+ expect('peach')
+ -- Mapped ALT-chord behaves as mapped.
+ command('vnoremap <M-l> Ameta-l<Esc>')
+ command('vnoremap <A-j> Aalt-j<Esc>')
+ feed('viw<A-j>viw<M-l>')
+ expect('peachalt-jmeta-l')
end)
- it('ALT/META #8213', function()
+ it('ALT/META insert-mode', function()
-- Mapped ALT-chord behaves as mapped.
command('inoremap <M-l> meta-l')
command('inoremap <A-j> alt-j')
diff --git a/test/functional/cmdline/history_spec.lua b/test/functional/editor/mode_cmdline_spec.lua
index ee2d36f642..0f7d821bb5 100644
--- a/test/functional/cmdline/history_spec.lua
+++ b/test/functional/editor/mode_cmdline_spec.lua
@@ -1,8 +1,41 @@
+-- Cmdline-mode tests.
+
local helpers = require('test.functional.helpers')(after_each)
-local clear, meths, funcs, eq =
- helpers.clear, helpers.meths, helpers.funcs, helpers.eq
+local clear, insert, funcs, eq, feed =
+ helpers.clear, helpers.insert, helpers.funcs, helpers.eq, helpers.feed
+local meths = helpers.meths
+
+describe('cmdline CTRL-R', function()
+ before_each(clear)
+
+ it('pasting non-special register inserts <CR> *between* lines', function()
+ insert([[
+ line1abc
+ line2somemoretext
+ ]])
+ -- Yank 2 lines linewise, then paste to cmdline.
+ feed([[<C-\><C-N>gg0yj:<C-R>0]])
+ -- <CR> inserted between lines, NOT after the final line.
+ eq('line1abc\rline2somemoretext', funcs.getcmdline())
+
+ -- Yank 2 lines charwise, then paste to cmdline.
+ feed([[<C-\><C-N>gg05lyvj:<C-R>0]])
+ -- <CR> inserted between lines, NOT after the final line.
+ eq('abc\rline2', funcs.getcmdline())
+
+ -- Yank 1 line linewise, then paste to cmdline.
+ feed([[<C-\><C-N>ggyy:<C-R>0]])
+ -- No <CR> inserted.
+ eq('line1abc', funcs.getcmdline())
+ end)
+
+ it('pasting special register inserts <CR>, <NL>', function()
+ feed([[:<C-R>="foo\nbar\rbaz"<CR>]])
+ eq('foo\nbar\rbaz', funcs.getcmdline())
+ end)
+end)
-describe('history support code', function()
+describe('cmdline history', function()
before_each(clear)
it('correctly clears start of the history', function()
diff --git a/test/functional/editor/mode_insert_spec.lua b/test/functional/editor/mode_insert_spec.lua
new file mode 100644
index 0000000000..46ab483036
--- /dev/null
+++ b/test/functional/editor/mode_insert_spec.lua
@@ -0,0 +1,89 @@
+-- Insert-mode tests.
+
+local helpers = require('test.functional.helpers')(after_each)
+local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
+local expect = helpers.expect
+local command = helpers.command
+local eq = helpers.eq
+local eval = helpers.eval
+local meths = helpers.meths
+
+describe('insert-mode', function()
+ before_each(function()
+ clear()
+ end)
+
+ it('CTRL-@', function()
+ -- Inserts last-inserted text, leaves insert-mode.
+ insert('hello')
+ feed('i<C-@>x')
+ expect('hellhello')
+
+ -- C-Space is the same as C-@.
+ -- CTRL-SPC inserts last-inserted text, leaves insert-mode.
+ feed('i<C-Space>x')
+ expect('hellhellhello')
+
+ -- CTRL-A inserts last inserted text
+ feed('i<C-A>x')
+ expect('hellhellhellhelloxo')
+ end)
+
+ describe('Ctrl-R', function()
+ it('works', function()
+ command("let @@ = 'test'")
+ feed('i<C-r>"')
+ expect('test')
+ end)
+
+ it('works with multi-byte text', function()
+ command("let @@ = 'påskägg'")
+ feed('i<C-r>"')
+ expect('påskägg')
+ end)
+ end)
+
+ describe('Ctrl-O', function()
+ it('enters command mode for one command', function()
+ feed('ihello world<C-o>')
+ feed(':let ctrlo = "test"<CR>')
+ feed('iii')
+ expect('hello worldiii')
+ eq(1, eval('ctrlo ==# "test"'))
+ end)
+
+ it('re-enters insert mode at the end of the line when running startinsert', function()
+ -- #6962
+ feed('ihello world<C-o>')
+ feed(':startinsert<CR>')
+ feed('iii')
+ expect('hello worldiii')
+ end)
+
+ it('re-enters insert mode at the beginning of the line when running startinsert', function()
+ insert('hello world')
+ feed('0<C-o>')
+ feed(':startinsert<CR>')
+ feed('aaa')
+ expect('aaahello world')
+ end)
+
+ it('re-enters insert mode in the middle of the line when running startinsert', function()
+ insert('hello world')
+ feed('bi<C-o>')
+ feed(':startinsert<CR>')
+ feed('ooo')
+ expect('hello oooworld')
+ end)
+
+ it("doesn't cancel Ctrl-O mode when processing event", function()
+ feed('iHello World<c-o>')
+ eq({mode='niI', blocking=false}, meths.get_mode()) -- fast event
+ eq(2, eval('1+1')) -- causes K_EVENT key
+ eq({mode='niI', blocking=false}, meths.get_mode()) -- still in ctrl-o mode
+ feed('dd')
+ eq({mode='i', blocking=false}, meths.get_mode()) -- left ctrl-o mode
+ expect('') -- executed the command
+ end)
+ end)
+end)
diff --git a/test/functional/editor/mode_visual_spec.lua b/test/functional/editor/mode_visual_spec.lua
new file mode 100644
index 0000000000..468ae00e01
--- /dev/null
+++ b/test/functional/editor/mode_visual_spec.lua
@@ -0,0 +1,27 @@
+-- Visual-mode tests.
+
+local helpers = require('test.functional.helpers')(after_each)
+local clear = helpers.clear
+local eq = helpers.eq
+local eval = helpers.eval
+local expect = helpers.expect
+local feed = helpers.feed
+local meths = helpers.meths
+
+describe('visual-mode', function()
+ before_each(clear)
+
+ it("select-mode Ctrl-O doesn't cancel Ctrl-O mode when processing event #15688", function()
+ feed('iHello World<esc>gh<c-o>')
+ eq({mode='vs', blocking=false}, meths.get_mode()) -- fast event
+ eq({mode='vs', blocking=false}, meths.get_mode()) -- again #15288
+ eq(2, eval('1+1')) -- causes K_EVENT key
+ eq({mode='vs', blocking=false}, meths.get_mode()) -- still in ctrl-o mode
+ feed('^')
+ eq({mode='s', blocking=false}, meths.get_mode()) -- left ctrl-o mode
+ feed('h')
+ eq({mode='i', blocking=false}, meths.get_mode()) -- entered insert mode
+ expect('h') -- selection is the whole line and is replaced
+ end)
+end)
+
diff --git a/test/functional/normal/put_spec.lua b/test/functional/editor/put_spec.lua
index 26967ecbba..26967ecbba 100644
--- a/test/functional/normal/put_spec.lua
+++ b/test/functional/editor/put_spec.lua
diff --git a/test/functional/normal/search_spec.lua b/test/functional/editor/search_spec.lua
index d5df131725..d5df131725 100644
--- a/test/functional/normal/search_spec.lua
+++ b/test/functional/editor/search_spec.lua
diff --git a/test/functional/normal/tabpage_spec.lua b/test/functional/editor/tabpage_spec.lua
index d1d6854b07..d1d6854b07 100644
--- a/test/functional/normal/tabpage_spec.lua
+++ b/test/functional/editor/tabpage_spec.lua
diff --git a/test/functional/normal/undo_spec.lua b/test/functional/editor/undo_spec.lua
index a023ca3d90..a023ca3d90 100644
--- a/test/functional/normal/undo_spec.lua
+++ b/test/functional/editor/undo_spec.lua
diff --git a/test/functional/eval/backtick_expansion_spec.lua b/test/functional/eval/backtick_expansion_spec.lua
deleted file mode 100644
index b1b44cfa8b..0000000000
--- a/test/functional/eval/backtick_expansion_spec.lua
+++ /dev/null
@@ -1,50 +0,0 @@
-local lfs = require('lfs')
-local helpers = require('test.functional.helpers')(after_each)
-local clear, command, eval, eq = helpers.clear, helpers.command, helpers.eval, helpers.eq
-local write_file = helpers.write_file
-
-describe("backtick expansion", function()
- setup(function()
- clear()
- lfs.mkdir("test-backticks")
- write_file("test-backticks/file1", "test file 1")
- write_file("test-backticks/file2", "test file 2")
- write_file("test-backticks/file3", "test file 3")
- lfs.mkdir("test-backticks/subdir")
- write_file("test-backticks/subdir/file4", "test file 4")
- -- Long path might cause "Press ENTER" prompt; use :silent to avoid it.
- command('silent cd test-backticks')
- end)
-
- teardown(function()
- helpers.rmdir('test-backticks')
- end)
-
- it("with default 'shell'", function()
- if helpers.iswin() then
- command(":silent args `dir /b *2`")
- else
- command(":silent args `echo ***2`")
- end
- eq({ "file2", }, eval("argv()"))
- if helpers.iswin() then
- command(":silent args `dir /s/b *4`")
- eq({ "subdir\\file4", }, eval("map(argv(), 'fnamemodify(v:val, \":.\")')"))
- else
- command(":silent args `echo */*4`")
- eq({ "subdir/file4", }, eval("argv()"))
- end
- end)
-
- it("with shell=fish", function()
- if eval("executable('fish')") == 0 then
- pending('missing "fish" command')
- return
- end
- command("set shell=fish")
- command(":silent args `echo ***2`")
- eq({ "file2", }, eval("argv()"))
- command(":silent args `echo */*4`")
- eq({ "subdir/file4", }, eval("argv()"))
- end)
-end)
diff --git a/test/functional/eval/function_spec.lua b/test/functional/eval/function_spec.lua
deleted file mode 100644
index ce8850fcc2..0000000000
--- a/test/functional/eval/function_spec.lua
+++ /dev/null
@@ -1,37 +0,0 @@
-local helpers = require('test.functional.helpers')(after_each)
-
-local clear = helpers.clear
-local eq = helpers.eq
-local matches = helpers.matches
-local exc_exec = helpers.exc_exec
-local iswin = helpers.iswin
-local eval = helpers.eval
-
-describe('Up to MAX_FUNC_ARGS arguments are handled by', function()
- local max_func_args = 20 -- from eval.h
- local range = helpers.funcs.range
-
- before_each(clear)
-
- it('printf()', function()
- local printf = helpers.funcs.printf
- local rep = helpers.funcs['repeat']
- local expected = '2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,'
- eq(expected, printf(rep('%d,', max_func_args-1), unpack(range(2, max_func_args))))
- local ret = exc_exec('call printf("", 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)')
- eq('Vim(call):E740: Too many arguments for function printf', ret)
- end)
-
- it('rpcnotify()', function()
- local rpcnotify = helpers.funcs.rpcnotify
- local ret = rpcnotify(0, 'foo', unpack(range(3, max_func_args)))
- eq(1, ret)
- ret = exc_exec('call rpcnotify(0, "foo", 3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)')
- eq('Vim(call):E740: Too many arguments for function rpcnotify', ret)
- end)
-end)
-
-it('windowsversion()', function()
- clear()
- matches(iswin() and '^%d+%.%d+$' or '^$', eval('windowsversion()'))
-end)
diff --git a/test/functional/eval/interrupt_spec.lua b/test/functional/eval/interrupt_spec.lua
deleted file mode 100644
index 05b1f4ff57..0000000000
--- a/test/functional/eval/interrupt_spec.lua
+++ /dev/null
@@ -1,61 +0,0 @@
-local helpers = require('test.functional.helpers')(after_each)
-
-local command = helpers.command
-local meths = helpers.meths
-local clear = helpers.clear
-local sleep = helpers.sleep
-local poke_eventloop = helpers.poke_eventloop
-local feed = helpers.feed
-local eq = helpers.eq
-
-local dur
-local min_dur = 8
-local len = 131072
-
-describe('List support code', function()
- if not pending('does not actually allows interrupting with just got_int', function() end) then return end
- -- The following tests are confirmed to work with os_breakcheck() just before
- -- `if (got_int) {break;}` in tv_list_copy and list_join_inner() and not to
- -- work without.
- setup(function()
- clear()
- dur = 0
- while true do
- command(([[
- let rt = reltime()
- let bl = range(%u)
- let dur = reltimestr(reltime(rt))
- ]]):format(len))
- dur = tonumber(meths.get_var('dur'))
- if dur >= min_dur then
- -- print(('Using len %u, dur %g'):format(len, dur))
- break
- else
- len = len * 2
- end
- end
- end)
- it('allows interrupting copy', function()
- feed(':let t_rt = reltime()<CR>:let t_bl = copy(bl)<CR>')
- sleep(min_dur / 16 * 1000)
- feed('<C-c>')
- poke_eventloop()
- command('let t_dur = reltimestr(reltime(t_rt))')
- local t_dur = tonumber(meths.get_var('t_dur'))
- if t_dur >= dur / 8 then
- eq(nil, ('Took too long to cancel: %g >= %g'):format(t_dur, dur / 8))
- end
- end)
- it('allows interrupting join', function()
- feed(':let t_rt = reltime()<CR>:let t_j = join(bl)<CR>')
- sleep(min_dur / 16 * 1000)
- feed('<C-c>')
- poke_eventloop()
- command('let t_dur = reltimestr(reltime(t_rt))')
- local t_dur = tonumber(meths.get_var('t_dur'))
- print(('t_dur: %g'):format(t_dur))
- if t_dur >= dur / 8 then
- eq(nil, ('Took too long to cancel: %g >= %g'):format(t_dur, dur / 8))
- end
- end)
-end)
diff --git a/test/functional/ex_cmds/dict_notifications_spec.lua b/test/functional/ex_cmds/dict_notifications_spec.lua
index e5c9a20db3..21adcf37da 100644
--- a/test/functional/ex_cmds/dict_notifications_spec.lua
+++ b/test/functional/ex_cmds/dict_notifications_spec.lua
@@ -1,4 +1,5 @@
local helpers = require('test.functional.helpers')(after_each)
+local assert_alive = helpers.assert_alive
local clear, nvim, source = helpers.clear, helpers.nvim, helpers.source
local insert = helpers.insert
local eq, next_msg = helpers.eq, helpers.next_msg
@@ -325,7 +326,7 @@ describe('VimL dictionary notifications', function()
]])
command('call MakeWatch()')
- eq(2, eval('1+1')) -- Still alive?
+ assert_alive()
end)
end)
@@ -354,7 +355,7 @@ describe('VimL dictionary notifications', function()
command([[call dictwatcherdel(b:, 'changedtick', 'OnTickChanged')]])
insert('t');
- eq(2, eval('1+1')) -- Still alive?
+ assert_alive()
end)
it('does not cause use-after-free when unletting from callback', function()
diff --git a/test/functional/ex_cmds/drop_spec.lua b/test/functional/ex_cmds/drop_spec.lua
index ef53fe75e3..9d84a2d4f6 100644
--- a/test/functional/ex_cmds/drop_spec.lua
+++ b/test/functional/ex_cmds/drop_spec.lua
@@ -55,6 +55,7 @@ describe(":drop", function()
end)
it("splits off a new window when a buffer can't be abandoned", function()
+ command("set nohidden")
feed_command("edit tmp1")
feed_command("vsplit")
feed_command("edit tmp2")
diff --git a/test/functional/ex_cmds/echo_spec.lua b/test/functional/ex_cmds/echo_spec.lua
index 404dc39ad2..d320425de1 100644
--- a/test/functional/ex_cmds/echo_spec.lua
+++ b/test/functional/ex_cmds/echo_spec.lua
@@ -10,7 +10,7 @@ local source = helpers.source
local dedent = helpers.dedent
local command = helpers.command
local exc_exec = helpers.exc_exec
-local redir_exec = helpers.redir_exec
+local exec_capture = helpers.exec_capture
local matches = helpers.matches
describe(':echo :echon :echomsg :echoerr', function()
@@ -199,10 +199,8 @@ describe(':echo :echon :echomsg :echoerr', function()
let d.tdr = TestDictRef
]])
eq(dedent([[
-
- function('TestDict', {'tdr': function('TestDict', {...@1})})
function('TestDict', {'tdr': function('TestDict', {...@1})})]]),
- redir_exec('echo String(d.tdr)'))
+ exec_capture('echo String(d.tdr)'))
end)
it('dumps automatically created partials', function()
@@ -229,10 +227,8 @@ describe(':echo :echon :echomsg :echoerr', function()
function()
meths.set_var('d', {v=true})
eq(dedent([[
-
- {'p': function('<SNR>2_Test2', {...@0}), 'f': function('<SNR>2_Test2'), 'v': v:true}
{'p': function('<SNR>2_Test2', {...@0}), 'f': function('<SNR>2_Test2'), 'v': v:true}]]),
- redir_exec('echo String(extend(extend(g:d, {"f": g:Test2_f}), {"p": g:d.f}))'))
+ exec_capture('echo String(extend(extend(g:d, {"f": g:Test2_f}), {"p": g:d.f}))'))
end)
it('does not show errors when dumping partials referencing the same dictionary',
@@ -256,10 +252,8 @@ describe(':echo :echon :echomsg :echoerr', function()
-- test/unit/api/private_helpers_spec.lua.
eval('add(l, function("Test1", l))')
eq(dedent([=[
-
- function('Test1', [[[...@2], function('Test1', [[...@2]])], function('Test1', [[[...@4], function('Test1', [[...@4]])]])])
function('Test1', [[[...@2], function('Test1', [[...@2]])], function('Test1', [[[...@4], function('Test1', [[...@4]])]])])]=]),
- redir_exec('echo String(function("Test1", l))'))
+ exec_capture('echo String(function("Test1", l))'))
end)
it('does not crash or halt when dumping partials with reference cycles in self and arguments',
@@ -270,10 +264,8 @@ describe(':echo :echon :echomsg :echoerr', function()
eval('add(l, function("Test1", l))')
eval('add(l, function("Test1", d))')
eq(dedent([=[
-
- {'p': function('<SNR>2_Test2', [[[...@3], function('Test1', [[...@3]]), function('Test1', {...@0})], function('Test1', [[[...@5], function('Test1', [[...@5]]), function('Test1', {...@0})]]), function('Test1', {...@0})], {...@0}), 'f': function('<SNR>2_Test2'), 'v': v:true}
{'p': function('<SNR>2_Test2', [[[...@3], function('Test1', [[...@3]]), function('Test1', {...@0})], function('Test1', [[[...@5], function('Test1', [[...@5]]), function('Test1', {...@0})]]), function('Test1', {...@0})], {...@0}), 'f': function('<SNR>2_Test2'), 'v': v:true}]=]),
- redir_exec('echo String(extend(extend(g:d, {"f": g:Test2_f}), {"p": function(g:d.f, l)}))'))
+ exec_capture('echo String(extend(extend(g:d, {"f": g:Test2_f}), {"p": function(g:d.f, l)}))'))
end)
end)
@@ -303,8 +295,8 @@ describe(':echo :echon :echomsg :echoerr', function()
it('dumps recursive lists without error', function()
meths.set_var('l', {})
eval('add(l, l)')
- eq('\n[[...@0]]\n[[...@0]]', redir_exec('echo String(l)'))
- eq('\n[[[...@1]]]\n[[[...@1]]]', redir_exec('echo String([l])'))
+ eq('[[...@0]]', exec_capture('echo String(l)'))
+ eq('[[[...@1]]]', exec_capture('echo String([l])'))
end)
end)
@@ -333,10 +325,10 @@ describe(':echo :echon :echomsg :echoerr', function()
it('dumps recursive dictionaries without the error', function()
meths.set_var('d', {d=1})
eval('extend(d, {"d": d})')
- eq('\n{\'d\': {...@0}}\n{\'d\': {...@0}}',
- redir_exec('echo String(d)'))
- eq('\n{\'out\': {\'d\': {...@1}}}\n{\'out\': {\'d\': {...@1}}}',
- redir_exec('echo String({"out": d})'))
+ eq('{\'d\': {...@0}}',
+ exec_capture('echo String(d)'))
+ eq('{\'out\': {\'d\': {...@1}}}',
+ exec_capture('echo String({"out": d})'))
end)
end)
diff --git a/test/functional/ex_cmds/mksession_spec.lua b/test/functional/ex_cmds/mksession_spec.lua
index 949724bb53..09eaa36686 100644
--- a/test/functional/ex_cmds/mksession_spec.lua
+++ b/test/functional/ex_cmds/mksession_spec.lua
@@ -43,7 +43,7 @@ describe(':mksession', function()
-- Restore session.
command('source '..session_file)
- eq({3,3,2},
+ eq({2,2,4},
{funcs.winbufnr(1), funcs.winbufnr(2), funcs.winbufnr(3)})
end)
@@ -91,7 +91,12 @@ describe(':mksession', function()
command('tabnext 1')
eq(cwd_dir .. get_pathsep() .. tmpfile_base .. '1', funcs.expand('%:p'))
command('tabnext 2')
- eq(cwd_dir .. get_pathsep() .. tmpfile_base .. '2', funcs.expand('%:p'))
+ -- :mksession stores paths using unix slashes, but Nvim doesn't adjust these
+ -- for absolute paths in all cases yet. Absolute paths are used in the
+ -- session file after :tcd, so we need to expect unix slashes here for now
+ -- eq(cwd_dir .. get_pathsep() .. tmpfile_base .. '2', funcs.expand('%:p'))
+ eq(cwd_dir:gsub([[\]], '/') .. '/' .. tmpfile_base .. '2',
+ funcs.expand('%:p'))
end)
it('restores CWD for :terminal buffers #11288', function()
diff --git a/test/functional/ex_cmds/quickfix_commands_spec.lua b/test/functional/ex_cmds/quickfix_commands_spec.lua
index 3392a90270..c956a2df2d 100644
--- a/test/functional/ex_cmds/quickfix_commands_spec.lua
+++ b/test/functional/ex_cmds/quickfix_commands_spec.lua
@@ -37,9 +37,9 @@ for _, c in ipairs({'l', 'c'}) do
-- Second line of each entry (i.e. `nr=-1, …`) was obtained from actual
-- results. First line (i.e. `{lnum=…`) was obtained from legacy test.
local list = {
- {lnum=700, col=10, text='Line 700', module='',
+ {lnum=700, end_lnum=0, col=10, end_col=0, text='Line 700', module='',
nr=-1, bufnr=2, valid=1, pattern='', vcol=0, ['type']=''},
- {lnum=800, col=15, text='Line 800', module='',
+ {lnum=800, end_lnum=0, col=15, end_col=0, text='Line 800', module='',
nr=-1, bufnr=3, valid=1, pattern='', vcol=0, ['type']=''},
}
eq(list, getlist())
@@ -47,6 +47,7 @@ for _, c in ipairs({'l', 'c'}) do
eq(('%s-2.res'):format(file), funcs.bufname(list[2].bufnr))
-- Run cfile/lfile from a modified buffer
+ command('set nohidden')
command('enew!')
curbufmeths.set_lines(1, 1, true, {'Quickfix'})
eq(('Vim(%s):E37: No write since last change (add ! to override)'):format(
@@ -58,7 +59,7 @@ for _, c in ipairs({'l', 'c'}) do
]]):format(file))
command(('%s %s'):format(addfcmd, file))
list[#list + 1] = {
- lnum=900, col=30, text='Line 900', module='',
+ lnum=900, end_lnum=0, col=30, end_col=0, text='Line 900', module='',
nr=-1, bufnr=5, valid=1, pattern='', vcol=0, ['type']='',
}
eq(list, getlist())
@@ -71,9 +72,9 @@ for _, c in ipairs({'l', 'c'}) do
command('enew!')
command(('%s %s'):format(getfcmd, file))
list = {
- {lnum=222, col=77, text='Line 222', module='',
+ {lnum=222, end_lnum=0, col=77, end_col=0, text='Line 222', module='',
nr=-1, bufnr=2, valid=1, pattern='', vcol=0, ['type']=''},
- {lnum=333, col=88, text='Line 333', module='',
+ {lnum=333, end_lnum=0, col=88, end_col=0, text='Line 333', module='',
nr=-1, bufnr=3, valid=1, pattern='', vcol=0, ['type']=''},
}
eq(list, getlist())
diff --git a/test/functional/ex_cmds/source_spec.lua b/test/functional/ex_cmds/source_spec.lua
index 37c97f519a..bdf6ae76d1 100644
--- a/test/functional/ex_cmds/source_spec.lua
+++ b/test/functional/ex_cmds/source_spec.lua
@@ -8,6 +8,8 @@ local feed = helpers.feed
local feed_command = helpers.feed_command
local write_file = helpers.write_file
local exec = helpers.exec
+local exc_exec = helpers.exc_exec
+local exec_lua = helpers.exec_lua
local eval = helpers.eval
local exec_capture = helpers.exec_capture
local neq = helpers.neq
@@ -18,16 +20,30 @@ describe(':source', function()
end)
it('current buffer', function()
- insert('let a = 2')
+ insert([[
+ let a = 2
+ let b = #{
+ \ k: "v"
+ "\ (o_o)
+ \ }]])
+
command('source')
eq('2', meths.exec('echo a', true))
+ eq("{'k': 'v'}", meths.exec('echo b', true))
+
+ exec('set cpoptions+=C')
+ eq('Vim(let):E15: Invalid expression: #{', exc_exec('source'))
end)
it('selection in current buffer', function()
- insert(
- 'let a = 2\n'..
- 'let a = 3\n'..
- 'let a = 4\n')
+ insert([[
+ let a = 2
+ let a = 3
+ let a = 4
+ let b = #{
+ "\ (>_<)
+ \ K: "V"
+ \ }]])
-- Source the 2nd line only
feed('ggjV')
@@ -38,13 +54,26 @@ describe(':source', function()
feed('ggjVG')
feed_command(':source')
eq('4', meths.exec('echo a', true))
+ eq("{'K': 'V'}", meths.exec('echo b', true))
+
+ exec('set cpoptions+=C')
+ eq('Vim(let):E15: Invalid expression: #{', exc_exec("'<,'>source"))
+ end)
+
+ it('does not break if current buffer is modified while sourced', function()
+ insert [[
+ bwipeout!
+ let a = 123
+ ]]
+ command('source')
+ eq('123', meths.exec('echo a', true))
end)
it('multiline heredoc command', function()
- insert(
- 'lua << EOF\n'..
- 'y = 4\n'..
- 'EOF\n')
+ insert([[
+ lua << EOF
+ y = 4
+ EOF]])
command('source')
eq('4', meths.exec('echo luaeval("y")', true))
@@ -67,13 +96,21 @@ describe(':source', function()
vim.g.b = 5
vim.g.b = 6
vim.g.b = 7
+ a = [=[
+ "\ a
+ \ b]=]
]])
command('edit '..test_file)
+
feed('ggjV')
feed_command(':source')
-
eq(6, eval('g:b'))
+
+ feed('GVkk')
+ feed_command(':source')
+ eq(' "\\ a\n \\ b', exec_lua('return _G.a'))
+
os.remove(test_file)
end)
@@ -84,12 +121,16 @@ describe(':source', function()
vim.g.c = 10
vim.g.c = 11
vim.g.c = 12
+ a = [=[
+ \ 1
+ "\ 2]=]
]])
command('edit '..test_file)
feed_command(':source')
eq(12, eval('g:c'))
+ eq(' \\ 1\n "\\ 2', exec_lua('return _G.a'))
os.remove(test_file)
end)
diff --git a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua
index f2a381869e..d91feb4bc1 100644
--- a/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua
+++ b/test/functional/ex_cmds/swapfile_preserve_recover_spec.lua
@@ -3,6 +3,7 @@ local helpers = require('test.functional.helpers')(after_each)
local lfs = require('lfs')
local eq, eval, expect, source =
helpers.eq, helpers.eval, helpers.expect, helpers.source
+local assert_alive = helpers.assert_alive
local clear = helpers.clear
local command = helpers.command
local feed = helpers.feed
@@ -26,7 +27,7 @@ describe(':recover', function()
-- Also check filename ending with ".swp". #9504
eq('Vim(recover):E306: Cannot open '..swapname2,
pcall_err(command, 'recover '..swapname2)) -- Should not segfault. #2117
- eq(2, eval('1+1')) -- Still alive?
+ assert_alive()
end)
end)
diff --git a/test/functional/ex_cmds/write_spec.lua b/test/functional/ex_cmds/write_spec.lua
index 4f526ddfca..32fe397c03 100644
--- a/test/functional/ex_cmds/write_spec.lua
+++ b/test/functional/ex_cmds/write_spec.lua
@@ -3,8 +3,7 @@ local lfs = require('lfs')
local eq, eval, clear, write_file, source, insert =
helpers.eq, helpers.eval, helpers.clear, helpers.write_file,
helpers.source, helpers.insert
-local redir_exec = helpers.redir_exec
-local exc_exec = helpers.exc_exec
+local pcall_err = helpers.pcall_err
local command = helpers.command
local feed_command = helpers.feed_command
local funcs = helpers.funcs
@@ -96,25 +95,24 @@ describe(':write', function()
eq(funcs.fnamemodify('.', ':p:h'), funcs.fnamemodify('.', ':p:h:~'))
-- Message from check_overwrite
if not iswin() then
- eq(('\nE17: "'..funcs.fnamemodify('.', ':p:h')..'" is a directory'),
- redir_exec('write .'))
+ eq(('Vim(write):E17: "'..funcs.fnamemodify('.', ':p:h')..'" is a directory'),
+ pcall_err(command, 'write .'))
end
meths.set_option('writeany', true)
-- Message from buf_write
- eq(('\nE502: "." is a directory'),
- redir_exec('write .'))
+ eq(('Vim(write):E502: "." is a directory'), pcall_err(command, 'write .'))
funcs.mkdir(fname_bak)
meths.set_option('backupdir', '.')
meths.set_option('backup', true)
write_file(fname, 'content0')
- eq(0, exc_exec('edit ' .. fname))
+ command('edit ' .. fname)
funcs.setline(1, 'TTY')
eq('Vim(write):E510: Can\'t make backup file (add ! to override)',
- exc_exec('write'))
+ pcall_err(command, 'write'))
meths.set_option('backup', false)
funcs.setfperm(fname, 'r--------')
eq('Vim(write):E505: "Xtest-functional-ex_cmds-write" is read-only (add ! to override)',
- exc_exec('write'))
+ pcall_err(command, 'write'))
if iswin() then
eq(0, os.execute('del /q/f ' .. fname))
eq(0, os.execute('rd /q/s ' .. fname_bak))
@@ -127,6 +125,6 @@ describe(':write', function()
if iswin() then return end
lfs.link(fname_bak .. ('/xxxxx'):rep(20), fname, true)
eq('Vim(write):E166: Can\'t open linked file for writing',
- exc_exec('write!'))
+ pcall_err(command, 'write!'))
end)
end)
diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua
index b7fddc8f29..8e03d9a46e 100644
--- a/test/functional/fixtures/fake-lsp-server.lua
+++ b/test/functional/fixtures/fake-lsp-server.lua
@@ -43,11 +43,11 @@ end
local function read_message()
local line = io.read("*l")
local length = line:lower():match("content%-length:%s*(%d+)")
- return vim.fn.json_decode(io.read(2 + length):sub(2))
+ return vim.json.decode(io.read(2 + length):sub(2))
end
local function send(payload)
- io.stdout:write(format_message_with_content_length(vim.fn.json_encode(payload)))
+ io.stdout:write(format_message_with_content_length(vim.json.encode(payload)))
end
local function respond(id, err, result)
@@ -126,6 +126,89 @@ function tests.check_workspace_configuration()
}
end
+function tests.prepare_rename_nil()
+ skeleton {
+ on_init = function()
+ return { capabilities = {
+ renameProvider = true,
+ } }
+ end;
+ body = function()
+ notify('start')
+ expect_request('textDocument/prepareRename', function()
+ return nil, nil
+ end)
+ notify('shutdown')
+ end;
+ }
+end
+
+function tests.prepare_rename_placeholder()
+ skeleton {
+ on_init = function()
+ return { capabilities = {
+ renameProvider = true,
+ } }
+ end;
+ body = function()
+ notify('start')
+ expect_request('textDocument/prepareRename', function()
+ return nil, {placeholder = 'placeholder'}
+ end)
+ expect_request('textDocument/rename', function(params)
+ assert_eq(params.newName, 'renameto')
+ return nil, nil
+ end)
+ notify('shutdown')
+ end;
+ }
+end
+
+function tests.prepare_rename_range()
+ skeleton {
+ on_init = function()
+ return { capabilities = {
+ renameProvider = true,
+ } }
+ end;
+ body = function()
+ notify('start')
+ expect_request('textDocument/prepareRename', function()
+ return nil, {
+ start = { line = 1, character = 8 },
+ ['end'] = { line = 1, character = 12 },
+ }
+ end)
+ expect_request('textDocument/rename', function(params)
+ assert_eq(params.newName, 'renameto')
+ return nil, nil
+ end)
+ notify('shutdown')
+ end;
+ }
+end
+
+function tests.prepare_rename_error()
+ skeleton {
+ on_init = function()
+ return { capabilities = {
+ renameProvider = true,
+ } }
+ end;
+ body = function()
+ notify('start')
+ expect_request('textDocument/prepareRename', function()
+ return {}, nil
+ end)
+ expect_request('textDocument/rename', function(params)
+ assert_eq(params.newName, 'renameto')
+ return nil, nil
+ end)
+ notify('shutdown')
+ end;
+ }
+end
+
function tests.basic_check_capabilities()
skeleton {
on_init = function(params)
@@ -481,6 +564,35 @@ function tests.decode_nil()
}
end
+
+function tests.code_action_with_resolve()
+ skeleton {
+ on_init = function()
+ return {
+ capabilities = {
+ codeActionProvider = {
+ resolveProvider = true
+ }
+ }
+ }
+ end;
+ body = function()
+ notify('start')
+ local cmd = {
+ title = 'Command 1',
+ command = 'dummy1'
+ }
+ expect_request('textDocument/codeAction', function()
+ return nil, { cmd, }
+ end)
+ expect_request('codeAction/resolve', function()
+ return nil, cmd
+ end)
+ notify('shutdown')
+ end;
+ }
+end
+
-- Tests will be indexed by TEST_NAME
local kill_timer = vim.loop.new_timer()
diff --git a/test/functional/fixtures/middle/filen.lua b/test/functional/fixtures/middle/filen.lua
new file mode 100644
index 0000000000..fce50cc776
--- /dev/null
+++ b/test/functional/fixtures/middle/filen.lua
@@ -0,0 +1 @@
+table.insert(_G.test_loadorder, "mittel")
diff --git a/test/functional/fixtures/nvim/after/filen.lua b/test/functional/fixtures/nvim/after/filen.lua
new file mode 100644
index 0000000000..0128a0a16a
--- /dev/null
+++ b/test/functional/fixtures/nvim/after/filen.lua
@@ -0,0 +1 @@
+table.insert(_G.test_loadorder, "ordinary after")
diff --git a/test/functional/fixtures/nvim/filen.lua b/test/functional/fixtures/nvim/filen.lua
new file mode 100644
index 0000000000..e2bd5e8f7f
--- /dev/null
+++ b/test/functional/fixtures/nvim/filen.lua
@@ -0,0 +1 @@
+table.insert(_G.test_loadorder, "ordinary")
diff --git a/test/functional/fixtures/pack/foo/opt/funky/filen.lua b/test/functional/fixtures/pack/foo/opt/funky/filen.lua
new file mode 100644
index 0000000000..a33b83c2a7
--- /dev/null
+++ b/test/functional/fixtures/pack/foo/opt/funky/filen.lua
@@ -0,0 +1,12 @@
+table.insert(_G.test_loadorder, "funky!")
+
+if not _G.nesty then
+ _G.nesty = true
+ local save_order = _G.test_loadorder
+ _G.test_loadorder = {}
+ _G.vim.o.pp = "" -- funky!
+ vim.cmd [[runtime! filen.lua ]]
+ _G.nested_order = _G.test_loadorder
+ _G.test_loadorder = save_order
+ _G.nesty = nil
+end
diff --git a/test/functional/fixtures/pack/foo/opt/superspecial/after/filen.lua b/test/functional/fixtures/pack/foo/opt/superspecial/after/filen.lua
new file mode 100644
index 0000000000..94bf6850b2
--- /dev/null
+++ b/test/functional/fixtures/pack/foo/opt/superspecial/after/filen.lua
@@ -0,0 +1 @@
+table.insert(_G.test_loadorder, "SuperSpecial after")
diff --git a/test/functional/fixtures/pack/foo/opt/superspecial/filen.lua b/test/functional/fixtures/pack/foo/opt/superspecial/filen.lua
new file mode 100644
index 0000000000..cbaab1a45a
--- /dev/null
+++ b/test/functional/fixtures/pack/foo/opt/superspecial/filen.lua
@@ -0,0 +1 @@
+table.insert(_G.test_loadorder, "SuperSpecial")
diff --git a/test/functional/fixtures/pack/foo/start/fancyplugin/after/filen.lua b/test/functional/fixtures/pack/foo/start/fancyplugin/after/filen.lua
new file mode 100644
index 0000000000..9beac762ee
--- /dev/null
+++ b/test/functional/fixtures/pack/foo/start/fancyplugin/after/filen.lua
@@ -0,0 +1 @@
+table.insert(_G.test_loadorder, "FANCY after")
diff --git a/test/functional/fixtures/pack/foo/start/fancyplugin/filen.lua b/test/functional/fixtures/pack/foo/start/fancyplugin/filen.lua
new file mode 100644
index 0000000000..34e4b9c95e
--- /dev/null
+++ b/test/functional/fixtures/pack/foo/start/fancyplugin/filen.lua
@@ -0,0 +1 @@
+table.insert(_G.test_loadorder, "FANCY")
diff --git a/test/functional/fixtures/shell-test.c b/test/functional/fixtures/shell-test.c
index b95e563932..4196716799 100644
--- a/test/functional/fixtures/shell-test.c
+++ b/test/functional/fixtures/shell-test.c
@@ -19,7 +19,7 @@ static void flush_wait(void)
static void help(void)
{
- puts("A simple implementation of a shell for testing termopen().");
+ puts("Fake shell");
puts("");
puts("Usage:");
puts(" shell-test --help");
@@ -42,6 +42,8 @@ static void help(void)
puts(" 96: foo bar");
puts(" shell-test INTERACT");
puts(" Prints \"interact $ \" to stderr, and waits for \"exit\" input.");
+ puts(" shell-test EXIT {code}");
+ puts(" Exits immediately with exit code \"{code}\".");
}
int main(int argc, char **argv)
@@ -103,7 +105,6 @@ int main(int argc, char **argv)
char input[256];
char cmd[100];
int arg;
- int input_argc;
while (1) {
fprintf(stderr, "interact $ ");
@@ -112,8 +113,7 @@ int main(int argc, char **argv)
break; // EOF
}
- input_argc = sscanf(input, "%99s %d", cmd, &arg);
- if(1 == input_argc) {
+ if(1 == sscanf(input, "%99s %d", cmd, &arg)) {
arg = 0;
}
if (strcmp(cmd, "exit") == 0) {
@@ -122,6 +122,15 @@ int main(int argc, char **argv)
fprintf(stderr, "command not found: %s\n", cmd);
}
}
+ } else if (strcmp(argv[1], "EXIT") == 0) {
+ int code = 1;
+ if (argc >= 3) {
+ if (sscanf(argv[2], "%d", &code) != 1) {
+ fprintf(stderr, "Invalid exit code: %s\n", argv[2]);
+ return 2;
+ }
+ }
+ return code;
} else {
fprintf(stderr, "Unknown first argument: %s\n", argv[1]);
return 3;
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index 03ef441ef3..a26e883370 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -38,10 +38,16 @@ module.nvim_prog = (
module.nvim_set = (
'set shortmess+=IS background=light noswapfile noautoindent startofline'
..' laststatus=1 undodir=. directory=. viewdir=. backupdir=.'
- ..' belloff= wildoptions-=pum noshowcmd noruler nomore redrawdebug=invalid')
+ ..' belloff= wildoptions-=pum joinspaces noshowcmd noruler nomore redrawdebug=invalid')
module.nvim_argv = {
module.nvim_prog, '-u', 'NONE', '-i', 'NONE',
- '--cmd', module.nvim_set, '--embed'}
+ '--cmd', module.nvim_set,
+ '--cmd', 'unmap Y',
+ '--cmd', 'unmap <C-L>',
+ '--cmd', 'iunmap <C-U>',
+ '--cmd', 'iunmap <C-W>',
+ '--embed'}
+
-- Directory containing nvim.
module.nvim_dir = module.nvim_prog:gsub("[/\\][^/\\]+$", "")
if module.nvim_dir == module.nvim_prog then
@@ -416,7 +422,7 @@ end
-- Builds an argument list for use in clear().
--
---@see clear() for parameters.
+---@see clear() for parameters.
function module.new_argv(...)
local args = {unpack(module.nvim_argv)}
table.insert(args, '--headless')
@@ -567,7 +573,7 @@ function module.buf_lines(bufnr)
return module.exec_lua("return vim.api.nvim_buf_get_lines((...), 0, -1, false)", bufnr)
end
---@see buf_lines()
+---@see buf_lines()
function module.curbuf_contents()
module.poke_eventloop() -- Before inspecting the buffer, do whatever.
return table.concat(module.curbuf('get_lines', 0, -1, true), '\n')
@@ -779,19 +785,6 @@ function module.exec_lua(code, ...)
return module.meths.exec_lua(code, {...})
end
-function module.redir_exec(cmd)
- module.meths.set_var('__redir_exec_cmd', cmd)
- module.command([[
- redir => g:__redir_exec_output
- silent! execute g:__redir_exec_cmd
- redir END
- ]])
- local ret = module.meths.get_var('__redir_exec_output')
- module.meths.del_var('__redir_exec_output')
- module.meths.del_var('__redir_exec_cmd')
- return ret
-end
-
function module.get_pathsep()
return iswin() and '\\' or '/'
end
diff --git a/test/functional/insert/ctrl_o_spec.lua b/test/functional/insert/ctrl_o_spec.lua
deleted file mode 100644
index 543d0a7d68..0000000000
--- a/test/functional/insert/ctrl_o_spec.lua
+++ /dev/null
@@ -1,54 +0,0 @@
-local helpers = require('test.functional.helpers')(after_each)
-local clear = helpers.clear
-local eq = helpers.eq
-local eval = helpers.eval
-local expect = helpers.expect
-local feed = helpers.feed
-local insert = helpers.insert
-local meths = helpers.meths
-
-describe('insert-mode Ctrl-O', function()
- before_each(clear)
-
- it('enters command mode for one command', function()
- feed('ihello world<C-o>')
- feed(':let ctrlo = "test"<CR>')
- feed('iii')
- expect('hello worldiii')
- eq(1, eval('ctrlo ==# "test"'))
- end)
-
- it('re-enters insert mode at the end of the line when running startinsert', function()
- -- #6962
- feed('ihello world<C-o>')
- feed(':startinsert<CR>')
- feed('iii')
- expect('hello worldiii')
- end)
-
- it('re-enters insert mode at the beginning of the line when running startinsert', function()
- insert('hello world')
- feed('0<C-o>')
- feed(':startinsert<CR>')
- feed('aaa')
- expect('aaahello world')
- end)
-
- it('re-enters insert mode in the middle of the line when running startinsert', function()
- insert('hello world')
- feed('bi<C-o>')
- feed(':startinsert<CR>')
- feed('ooo')
- expect('hello oooworld')
- end)
-
- it("doesn't cancel Ctrl-O mode when processing event", function()
- feed('iHello World<c-o>')
- eq({mode='niI', blocking=false}, meths.get_mode()) -- fast event
- eq(2, eval('1+1')) -- causes K_EVENT key
- eq({mode='niI', blocking=false}, meths.get_mode()) -- still in ctrl-o mode
- feed('dd')
- eq({mode='i', blocking=false}, meths.get_mode()) -- left ctrl-o mode
- expect('') -- executed the command
- end)
-end)
diff --git a/test/functional/insert/ctrl_r_spec.lua b/test/functional/insert/ctrl_r_spec.lua
deleted file mode 100644
index adc3c4b406..0000000000
--- a/test/functional/insert/ctrl_r_spec.lua
+++ /dev/null
@@ -1,19 +0,0 @@
-local helpers = require('test.functional.helpers')(after_each)
-local clear, feed = helpers.clear, helpers.feed
-local expect, command = helpers.expect, helpers.command
-
-describe('insert-mode Ctrl-R', function()
- before_each(clear)
-
- it('works', function()
- command("let @@ = 'test'")
- feed('i<C-r>"')
- expect('test')
- end)
-
- it('works with multi-byte text', function()
- command("let @@ = 'påskägg'")
- feed('i<C-r>"')
- expect('påskägg')
- end)
-end)
diff --git a/test/functional/legacy/007_ball_buffer_list_spec.lua b/test/functional/legacy/007_ball_buffer_list_spec.lua
index a180e73301..d4e4547c43 100644
--- a/test/functional/legacy/007_ball_buffer_list_spec.lua
+++ b/test/functional/legacy/007_ball_buffer_list_spec.lua
@@ -8,6 +8,9 @@ describe(':ball', function()
setup(clear)
it('is working', function()
+ -- Must disable 'hidden' so that the BufReadPost autocmd is triggered
+ -- when Xxx2 is reloaded
+ feed_command('set nohidden')
insert([[
start of test file Xxx
this is a test
@@ -18,7 +21,7 @@ describe(':ball', function()
feed('gg')
-- Write test file Xxx1
- feed('A1:.,/end of/w! Xxx1<cr>')
+ feed('A1<esc>:.,/end of/w! Xxx1<cr>')
feed_command('sp Xxx1')
feed_command('close')
diff --git a/test/functional/legacy/008_autocommands_spec.lua b/test/functional/legacy/008_autocommands_spec.lua
index 939404cb5e..002f037d09 100644
--- a/test/functional/legacy/008_autocommands_spec.lua
+++ b/test/functional/legacy/008_autocommands_spec.lua
@@ -71,6 +71,9 @@ describe('autocommands that delete and unload buffers:', function()
au BufUnload * call CloseAll()
au VimLeave * call WriteToOut()
]])
+ -- Must disable 'hidden' so that the BufUnload autocmd is triggered between
+ -- each :edit
+ command('set nohidden')
command('silent! edit Xxx2')
command('silent! edit Xxx1')
command('silent! edit Makefile') -- an existing file
diff --git a/test/functional/legacy/011_autocommands_spec.lua b/test/functional/legacy/011_autocommands_spec.lua
index 7b6f2f63e9..0fa9290f3c 100644
--- a/test/functional/legacy/011_autocommands_spec.lua
+++ b/test/functional/legacy/011_autocommands_spec.lua
@@ -129,13 +129,11 @@ describe('file reading, writing and bufnew and filter autocommands', function()
-- Will load Xtest.c.
feed_command('e! foo.c')
feed_command("au FileAppendPre *.out '[,']s/new/NEW/")
- feed_command('au FileAppendPost *.out !cat Xtest.c >>test.out')
+ feed_command('au FileAppendPost *.out !cat Xtest.c >test.out')
-- Append it to the output file.
feed_command('w>>test.out')
-- Discard all prompts and messages.
feed('<C-L>')
- -- Expect the decompressed file in the buffer.
- feed_command('e test.out')
expect([[
/*
diff --git a/test/functional/legacy/012_directory_spec.lua b/test/functional/legacy/012_directory_spec.lua
index 48dd24db9e..f666e51469 100644
--- a/test/functional/legacy/012_directory_spec.lua
+++ b/test/functional/legacy/012_directory_spec.lua
@@ -80,6 +80,7 @@ describe("'directory' option", function()
eq({ "Xtest1.swp", "Xtest3" }, ls_dir_sorted("Xtest2"))
meths.set_option('directory', 'Xtest.je')
+ command('bdelete')
command('edit Xtest2/Xtest3')
eq(true, curbufmeths.get_option('swapfile'))
poke_eventloop()
diff --git a/test/functional/legacy/063_match_and_matchadd_spec.lua b/test/functional/legacy/063_match_and_matchadd_spec.lua
index a4f5d6ac5b..d164d9c02f 100644
--- a/test/functional/legacy/063_match_and_matchadd_spec.lua
+++ b/test/functional/legacy/063_match_and_matchadd_spec.lua
@@ -6,7 +6,7 @@ local Screen = require('test.functional.ui.screen')
local eval, clear, command = helpers.eval, helpers.clear, helpers.command
local eq, neq = helpers.eq, helpers.neq
local insert = helpers.insert
-local redir_exec = helpers.redir_exec
+local pcall_err = helpers.pcall_err
describe('063: Test for ":match", "matchadd()" and related functions', function()
setup(clear)
@@ -67,9 +67,7 @@ describe('063: Test for ":match", "matchadd()" and related functions', function(
-- matchdelete throws error and returns -1 on failure
neq(true, pcall(function() eval('matchdelete(42)') end))
- eq('\nE803: ID not found: 42',
- redir_exec("let r2 = matchdelete(42)"))
- eq(-1, eval('r2'))
+ eq('Vim(let):E803: ID not found: 42', pcall_err(command, 'let r2 = matchdelete(42)'))
-- Check that "clearmatches()" clears all matches defined by ":match" and
-- "matchadd()".
@@ -105,9 +103,8 @@ describe('063: Test for ":match", "matchadd()" and related functions', function(
-- Check that "setmatches()" will not add two matches with the same ID. The
-- expected behaviour (for now) is to add the first match but not the
-- second and to return -1.
- eq('\nE801: ID already taken: 1',
- redir_exec("let r1 = setmatches([{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1}, {'group': 'MyGroup2', 'pattern': 'FIXME', 'priority': 10, 'id': 1}])"))
- eq(-1, eval("r1"))
+ eq('Vim(let):E801: ID already taken: 1',
+ pcall_err(command, "let r1 = setmatches([{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1}, {'group': 'MyGroup2', 'pattern': 'FIXME', 'priority': 10, 'id': 1}])"))
eq({{group = 'MyGroup1', pattern = 'TODO', priority = 10, id = 1}}, eval('getmatches()'))
-- Check that "setmatches()" returns 0 if successful and otherwise -1.
@@ -116,14 +113,11 @@ describe('063: Test for ":match", "matchadd()" and related functions', function(
eq(0,eval("setmatches([])"))
eq(0,eval("setmatches([{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1}])"))
command("call clearmatches()")
- eq('\nE714: List required', redir_exec("let rf1 = setmatches(0)"))
- eq(-1, eval('rf1'))
- eq('\nE474: List item 0 is either not a dictionary or an empty one',
- redir_exec("let rf2 = setmatches([0])"))
- eq(-1, eval('rf2'))
- eq('\nE474: List item 0 is missing one of the required keys',
- redir_exec("let rf3 = setmatches([{'wrong key': 'wrong value'}])"))
- eq(-1, eval('rf3'))
+ eq('Vim(let):E714: List required', pcall_err(command, 'let rf1 = setmatches(0)'))
+ eq('Vim(let):E474: List item 0 is either not a dictionary or an empty one',
+ pcall_err(command, 'let rf2 = setmatches([0])'))
+ eq('Vim(let):E474: List item 0 is missing one of the required keys',
+ pcall_err(command, "let rf3 = setmatches([{'wrong key': 'wrong value'}])"))
-- Check that "matchaddpos()" positions matches correctly
insert('abcdefghijklmnopq')
diff --git a/test/functional/legacy/arglist_spec.lua b/test/functional/legacy/arglist_spec.lua
index 67c5750033..6a2e86ccb4 100644
--- a/test/functional/legacy/arglist_spec.lua
+++ b/test/functional/legacy/arglist_spec.lua
@@ -156,10 +156,12 @@ describe('argument list commands', function()
eq({'a', 'b', 'a', 'c'}, eval('argv()'))
command('0argedit x')
eq({'x', 'a', 'b', 'a', 'c'}, eval('argv()'))
+ command('set nohidden')
command('enew! | set modified')
assert_fails('argedit y', 'E37:')
command('argedit! y')
eq({'x', 'y', 'y', 'a', 'b', 'a', 'c'}, eval('argv()'))
+ command('set hidden')
command('%argd')
command('argedit a b')
eq({'a', 'b'}, eval('argv()'))
diff --git a/test/functional/legacy/assert_spec.lua b/test/functional/legacy/assert_spec.lua
index 515d6d91b8..c2b22472bf 100644
--- a/test/functional/legacy/assert_spec.lua
+++ b/test/functional/legacy/assert_spec.lua
@@ -26,6 +26,14 @@ describe('assert function:', function()
call('assert_beeps', 'normal 0')
expected_errors({'command did not beep: normal 0'})
end)
+
+ it('can be used as a method', function()
+ local tmpname = source [[
+ call assert_equal(0, 'normal h'->assert_beeps())
+ call assert_equal(1, 'normal 0'->assert_beeps())
+ ]]
+ expected_errors({tmpname .. ' line 2: command did not beep: normal 0'})
+ end)
end)
-- assert_equal({expected}, {actual}, [, {msg}])
@@ -133,6 +141,14 @@ describe('assert function:', function()
call('assert_false', {})
expected_errors({'Expected False but got []'})
end)
+
+ it('can be used as a method', function()
+ local tmpname = source [[
+ call assert_equal(0, v:false->assert_false())
+ call assert_equal(1, 123->assert_false())
+ ]]
+ expected_errors({tmpname .. ' line 2: Expected False but got 123'})
+ end)
end)
-- assert_true({actual}, [, {msg}])
@@ -148,6 +164,14 @@ describe('assert function:', function()
eq(1, call('assert_true', 1.5))
expected_errors({'Expected True but got 1.5'})
end)
+
+ it('can be used as a method', function()
+ local tmpname = source [[
+ call assert_equal(0, v:true->assert_true())
+ call assert_equal(1, 0->assert_true())
+ ]]
+ expected_errors({tmpname .. ' line 2: Expected True but got 0'})
+ end)
end)
describe('v:errors', function()
@@ -223,6 +247,15 @@ describe('assert function:', function()
call('assert_match', 'bar.*foo', 'foobar', 'wrong')
expected_errors({"wrong: Pattern 'bar.*foo' does not match 'foobar'"})
end)
+
+ it('can be used as a method', function()
+ local tmpname = source [[
+ call assert_equal(1, 'foobar'->assert_match('bar.*foo', 'wrong'))
+ ]]
+ expected_errors({
+ tmpname .. " line 1: wrong: Pattern 'bar.*foo' does not match 'foobar'"
+ })
+ end)
end)
-- assert_notmatch({pat}, {text}[, {msg}])
@@ -237,6 +270,13 @@ describe('assert function:', function()
call('assert_notmatch', 'foo', 'foobar')
expected_errors({"Pattern 'foo' does match 'foobar'"})
end)
+
+ it('can be used as a method', function()
+ local tmpname = source [[
+ call assert_equal(1, 'foobar'->assert_notmatch('foo'))
+ ]]
+ expected_errors({tmpname .. " line 1: Pattern 'foo' does match 'foobar'"})
+ end)
end)
-- assert_fails({cmd}, [, {error}])
@@ -267,6 +307,15 @@ describe('assert function:', function()
eq(1, eval([[assert_fails('echo', '', 'echo command')]]))
expected_errors({'command did not fail: echo command'})
end)
+
+ it('can be used as a method', function()
+ local tmpname = source [[
+ call assert_equal(1, 'echo'->assert_fails('', 'echo command'))
+ ]]
+ expected_errors({
+ tmpname .. ' line 1: command did not fail: echo command'
+ })
+ end)
end)
-- assert_inrange({lower}, {upper}, {actual}[, {msg}])
@@ -292,6 +341,15 @@ describe('assert function:', function()
eq('Vim(call):E119: Not enough arguments for function: assert_inrange',
exc_exec("call assert_inrange(1, 1)"))
end)
+
+ it('can be used as a method', function()
+ local tmpname = source [[
+ call assert_equal(0, 5->assert_inrange(5, 7))
+ call assert_equal(0, 7->assert_inrange(5, 7))
+ call assert_equal(1, 8->assert_inrange(5, 7))
+ ]]
+ expected_errors({tmpname .. ' line 3: Expected range 5 - 7, but got 8'})
+ end)
end)
-- assert_report({msg})
@@ -302,6 +360,13 @@ describe('assert function:', function()
command('call remove(v:errors, 0)')
expected_empty()
end)
+
+ it('can be used as a method', function()
+ local tmpname = source [[
+ call assert_equal(1, 'also wrong'->assert_report())
+ ]]
+ expected_errors({tmpname .. ' line 1: also wrong'})
+ end)
end)
-- assert_exception({cmd}, [, {error}])
diff --git a/test/functional/legacy/autocmd_option_spec.lua b/test/functional/legacy/autocmd_option_spec.lua
index 0c7e43bf31..1914818215 100644
--- a/test/functional/legacy/autocmd_option_spec.lua
+++ b/test/functional/legacy/autocmd_option_spec.lua
@@ -3,7 +3,7 @@ local nvim = helpers.meths
local clear, eq, neq = helpers.clear, helpers.eq, helpers.neq
local curbuf, buf = helpers.curbuf, helpers.bufmeths
local curwin = helpers.curwin
-local redir_exec = helpers.redir_exec
+local exec_capture = helpers.exec_capture
local source, command = helpers.source, helpers.command
local function declare_hook_function()
@@ -102,13 +102,13 @@ local function get_new_window_number()
local old_win = curwin()
command('botright new')
local new_win = curwin()
- local new_winnr = redir_exec('echo winnr()')
+ local new_winnr = exec_capture('echo winnr()')
command('wincmd p') -- move previous window
neq(old_win, new_win)
eq(old_win, curwin())
- return new_winnr:gsub('\n', '')
+ return new_winnr
end
describe('au OptionSet', function()
diff --git a/test/functional/legacy/cdo_spec.lua b/test/functional/legacy/cdo_spec.lua
index 5e46431cc1..8b3216cbfd 100644
--- a/test/functional/legacy/cdo_spec.lua
+++ b/test/functional/legacy/cdo_spec.lua
@@ -91,7 +91,8 @@ describe('cdo', function()
exe "silent! 4,5" . XdoCmd
call assert_equal([], l)
- " Run commands from an unsaved buffer
+ " Run commands from an unsaved buffer when 'hidden' is unset
+ set nohidden
let v:errmsg=''
let l = []
enew
@@ -108,6 +109,7 @@ describe('cdo', function()
if subst_count != 1 || getline('.') != 'xLine1'
call add(v:errors, 'Abort command on error test failed')
endif
+ set hidden
let l = []
exe "2,2" . Xdo . "! call add(l, GetRuler())"
diff --git a/test/functional/legacy/eval_spec.lua b/test/functional/legacy/eval_spec.lua
index ee9bd29fc4..b5de5cd232 100644
--- a/test/functional/legacy/eval_spec.lua
+++ b/test/functional/legacy/eval_spec.lua
@@ -1,6 +1,7 @@
-- Test for various eval features.
local helpers = require('test.functional.helpers')(after_each)
+local assert_alive = helpers.assert_alive
local feed, insert, source = helpers.feed, helpers.insert, helpers.source
local clear, command, expect = helpers.clear, helpers.command, helpers.expect
local eq, eval, write_file = helpers.eq, helpers.eval, helpers.write_file
@@ -506,7 +507,7 @@ describe('eval', function()
command("call setreg('0',x)")
-- nvim didn't crash and "0 was emptied
- eq(2, eval("1+1"))
+ assert_alive()
eq({}, eval("getreg('0',1,1)"))
-- x is a mutable list
@@ -599,7 +600,6 @@ describe('eval', function()
command([[call ErrExe('call setreg(1)')]])
command([[call ErrExe('call setreg(1, 2, 3, 4)')]])
command([=[call ErrExe('call setreg([], 2)')]=])
- command([[call ErrExe('call setreg(1, {})')]])
command([=[call ErrExe('call setreg(1, 2, [])')]=])
command([=[call ErrExe('call setreg("/", ["1", "2"])')]=])
command([=[call ErrExe('call setreg("=", ["1", "2"])')]=])
@@ -614,8 +614,6 @@ describe('eval', function()
Vim(call):E118: Too many arguments for function: setreg
Executing call setreg([], 2)
Vim(call):E730: using List as a String
- Executing call setreg(1, {})
- Vim(call):E731: using Dictionary as a String
Executing call setreg(1, 2, [])
Vim(call):E730: using List as a String
Executing call setreg("/", ["1", "2"])
diff --git a/test/functional/legacy/fixeol_spec.lua b/test/functional/legacy/fixeol_spec.lua
index 50236e8617..d3ff86d349 100644
--- a/test/functional/legacy/fixeol_spec.lua
+++ b/test/functional/legacy/fixeol_spec.lua
@@ -23,8 +23,6 @@ describe('fixeol', function()
it('is working', function()
-- First write two test files – with and without trailing EOL.
- -- Use Unix fileformat for consistency.
- feed_command('set ff=unix')
feed_command('enew!')
feed('awith eol<esc>:w! XXEol<cr>')
feed_command('enew!')
@@ -40,7 +38,7 @@ describe('fixeol', function()
feed_command('e! XXNoEol')
feed('ostays without<esc>:set nofixeol<cr>')
feed_command('w! XXTestNoEol')
- feed_command('bwipe XXEol XXNoEol XXTestEol XXTestNoEol')
+ feed_command('bwipe! XXEol XXNoEol XXTestEol XXTestNoEol')
feed_command('set fixeol')
-- Append "END" to each file so that we can see what the last written char was.
diff --git a/test/functional/legacy/listchars_spec.lua b/test/functional/legacy/listchars_spec.lua
index cffb9fd376..dc6ccd3628 100644
--- a/test/functional/legacy/listchars_spec.lua
+++ b/test/functional/legacy/listchars_spec.lua
@@ -8,7 +8,7 @@ local clear, feed_command, expect = helpers.clear, helpers.feed_command, helpers
describe("'listchars'", function()
before_each(function()
clear()
- feed_command('set listchars&vi')
+ feed_command('set listchars=eol:$')
end)
-- luacheck: ignore 613 (Trailing whitespace in a string)
diff --git a/test/functional/legacy/memory_usage_spec.lua b/test/functional/legacy/memory_usage_spec.lua
index 0f2d77093a..d86caca0e9 100644
--- a/test/functional/legacy/memory_usage_spec.lua
+++ b/test/functional/legacy/memory_usage_spec.lua
@@ -168,6 +168,9 @@ describe('memory usage', function()
end)
it('releases memory when closing windows when folds exist', function()
+ if helpers.is_os('mac') then
+ pending('macOS memory compression causes flakiness')
+ end
local pid = eval('getpid()')
source([[
new
diff --git a/test/functional/legacy/mksession_spec.lua b/test/functional/legacy/mksession_spec.lua
index a2af891107..bca9cd833c 100644
--- a/test/functional/legacy/mksession_spec.lua
+++ b/test/functional/legacy/mksession_spec.lua
@@ -12,7 +12,7 @@ describe('mksession', function()
end)
it('supports "skiprtp" value', function()
- command('set sessionoptions&vi')
+ command('set sessionoptions+=options')
command('set rtp+=$HOME')
command('set pp+=$HOME')
command('mksession! Xtest_mks.out')
diff --git a/test/functional/lua/api_spec.lua b/test/functional/lua/api_spec.lua
index 896554f7a3..fdf79d55b2 100644
--- a/test/functional/lua/api_spec.lua
+++ b/test/functional/lua/api_spec.lua
@@ -15,7 +15,7 @@ describe('luaeval(vim.api.…)', function()
describe('nvim_buf_get_lines', function()
it('works', function()
funcs.setline(1, {"abc", "def", "a\nb", "ttt"})
- eq({{_TYPE={}, _VAL={'a\nb'}}},
+ eq({'a\000b'},
funcs.luaeval('vim.api.nvim_buf_get_lines(1, 2, 3, false)'))
end)
end)
@@ -23,7 +23,7 @@ describe('luaeval(vim.api.…)', function()
it('works', function()
funcs.setline(1, {"abc", "def", "a\nb", "ttt"})
eq(NIL, funcs.luaeval('vim.api.nvim_buf_set_lines(1, 1, 2, false, {"b\\0a"})'))
- eq({'abc', {_TYPE={}, _VAL={'b\na'}}, {_TYPE={}, _VAL={'a\nb'}}, 'ttt'},
+ eq({'abc', 'b\000a', 'a\000b', 'ttt'},
funcs.luaeval('vim.api.nvim_buf_get_lines(1, 0, 4, false)'))
end)
end)
@@ -64,15 +64,18 @@ describe('luaeval(vim.api.…)', function()
it('correctly converts from API objects', function()
eq(1, funcs.luaeval('vim.api.nvim_eval("1")'))
eq('1', funcs.luaeval([[vim.api.nvim_eval('"1"')]]))
+ eq('Blobby', funcs.luaeval('vim.api.nvim_eval("0z426c6f626279")'))
eq({}, funcs.luaeval('vim.api.nvim_eval("[]")'))
eq({}, funcs.luaeval('vim.api.nvim_eval("{}")'))
eq(1, funcs.luaeval('vim.api.nvim_eval("1.0")'))
+ eq('\000', funcs.luaeval('vim.api.nvim_eval("0z00")'))
eq(true, funcs.luaeval('vim.api.nvim_eval("v:true")'))
eq(false, funcs.luaeval('vim.api.nvim_eval("v:false")'))
eq(NIL, funcs.luaeval('vim.api.nvim_eval("v:null")'))
eq(0, eval([[type(luaeval('vim.api.nvim_eval("1")'))]]))
eq(1, eval([[type(luaeval('vim.api.nvim_eval("''1''")'))]]))
+ eq(1, eval([[type(luaeval('vim.api.nvim_eval("0zbeef")'))]]))
eq(3, eval([[type(luaeval('vim.api.nvim_eval("[]")'))]]))
eq(4, eval([[type(luaeval('vim.api.nvim_eval("{}")'))]]))
eq(5, eval([[type(luaeval('vim.api.nvim_eval("1.0")'))]]))
diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua
index a5b613f0b2..073927bf22 100644
--- a/test/functional/lua/buffer_updates_spec.lua
+++ b/test/functional/lua/buffer_updates_spec.lua
@@ -978,6 +978,22 @@ describe('lua: nvim_buf_attach on_bytes', function()
}
end)
+ it("visual paste", function()
+ local check_events= setup_eventcheck(verify, { "aaa {", "b", "}" })
+ -- Setting up
+ feed[[jdd]]
+ check_events {
+ { "test1", "bytes", 1, 3, 1, 0, 6, 1, 0, 2, 0, 0, 0 };
+ }
+
+ -- Actually testing
+ feed[[v%p]]
+ check_events {
+ { "test1", "bytes", 1, 8, 0, 4, 4, 1, 1, 3, 0, 0, 0 };
+ { "test1", "bytes", 1, 8, 0, 4, 4, 0, 0, 0, 2, 0, 3 };
+ }
+ end)
+
it("nvim_buf_set_lines", function()
local check_events = setup_eventcheck(verify, {"AAA", "BBB"})
diff --git a/test/functional/lua/commands_spec.lua b/test/functional/lua/commands_spec.lua
index f2a1b7dede..2e0d0ea899 100644
--- a/test/functional/lua/commands_spec.lua
+++ b/test/functional/lua/commands_spec.lua
@@ -15,14 +15,14 @@ local command = helpers.command
local exc_exec = helpers.exc_exec
local pcall_err = helpers.pcall_err
local write_file = helpers.write_file
-local redir_exec = helpers.redir_exec
+local exec_capture = helpers.exec_capture
local curbufmeths = helpers.curbufmeths
before_each(clear)
describe(':lua command', function()
it('works', function()
- eq('', redir_exec(
+ eq('', exec_capture(
'lua vim.api.nvim_buf_set_lines(1, 1, 2, false, {"TEST"})'))
eq({'', 'TEST'}, curbufmeths.get_lines(0, 100, false))
source(dedent([[
@@ -67,18 +67,19 @@ describe(':lua command', function()
eq({'', 'ETTS', 'TTSE', 'STTE'}, curbufmeths.get_lines(0, 100, false))
end)
it('preserves global and not preserves local variables', function()
- eq('', redir_exec('lua gvar = 42'))
- eq('', redir_exec('lua local lvar = 100500'))
+ eq('', exec_capture('lua gvar = 42'))
+ eq('', exec_capture('lua local lvar = 100500'))
eq(NIL, funcs.luaeval('lvar'))
eq(42, funcs.luaeval('gvar'))
end)
it('works with long strings', function()
local s = ('x'):rep(100500)
- eq('\nE5107: Error loading lua [string ":lua"]:1: unfinished string near \'<eof>\'', redir_exec(('lua vim.api.nvim_buf_set_lines(1, 1, 2, false, {"%s})'):format(s)))
+ eq('Vim(lua):E5107: Error loading lua [string ":lua"]:0: unfinished string near \'<eof>\'',
+ pcall_err(command, ('lua vim.api.nvim_buf_set_lines(1, 1, 2, false, {"%s})'):format(s)))
eq({''}, curbufmeths.get_lines(0, -1, false))
- eq('', redir_exec(('lua vim.api.nvim_buf_set_lines(1, 1, 2, false, {"%s"})'):format(s)))
+ eq('', exec_capture(('lua vim.api.nvim_buf_set_lines(1, 1, 2, false, {"%s"})'):format(s)))
eq({'', s}, curbufmeths.get_lines(0, -1, false))
end)
@@ -144,34 +145,34 @@ end)
describe(':luado command', function()
it('works', function()
curbufmeths.set_lines(0, 1, false, {"ABC", "def", "gHi"})
- eq('', redir_exec('luado lines = (lines or {}) lines[#lines + 1] = {linenr, line}'))
+ eq('', exec_capture('luado lines = (lines or {}) lines[#lines + 1] = {linenr, line}'))
eq({'ABC', 'def', 'gHi'}, curbufmeths.get_lines(0, -1, false))
eq({{1, 'ABC'}, {2, 'def'}, {3, 'gHi'}}, funcs.luaeval('lines'))
-- Automatic transformation of numbers
- eq('', redir_exec('luado return linenr'))
+ eq('', exec_capture('luado return linenr'))
eq({'1', '2', '3'}, curbufmeths.get_lines(0, -1, false))
- eq('', redir_exec('luado return ("<%02x>"):format(line:byte())'))
+ eq('', exec_capture('luado return ("<%02x>"):format(line:byte())'))
eq({'<31>', '<32>', '<33>'}, curbufmeths.get_lines(0, -1, false))
end)
it('stops processing lines when suddenly out of lines', function()
curbufmeths.set_lines(0, 1, false, {"ABC", "def", "gHi"})
- eq('', redir_exec('2,$luado runs = ((runs or 0) + 1) vim.api.nvim_command("%d")'))
+ eq('', exec_capture('2,$luado runs = ((runs or 0) + 1) vim.api.nvim_command("%d")'))
eq({''}, curbufmeths.get_lines(0, -1, false))
eq(1, funcs.luaeval('runs'))
end)
it('works correctly when changing lines out of range', function()
curbufmeths.set_lines(0, 1, false, {"ABC", "def", "gHi"})
- eq('\nE322: line number out of range: 1 past the end\nE320: Cannot find line 2',
- redir_exec('2,$luado vim.api.nvim_command("%d") return linenr'))
+ eq('Vim(luado):E322: line number out of range: 1 past the end',
+ pcall_err(command, '2,$luado vim.api.nvim_command("%d") return linenr'))
eq({''}, curbufmeths.get_lines(0, -1, false))
end)
it('fails on errors', function()
- eq([[Vim(luado):E5109: Error loading lua: [string ":luado"]:1: unexpected symbol near ')']],
- exc_exec('luado ()'))
- eq([[Vim(luado):E5111: Error calling lua: [string ":luado"]:1: attempt to perform arithmetic on global 'liness' (a nil value)]],
- exc_exec('luado return liness + 1'))
+ eq([[Vim(luado):E5109: Error loading lua: [string ":luado"]:0: unexpected symbol near ')']],
+ pcall_err(command, 'luado ()'))
+ eq([[Vim(luado):E5111: Error calling lua: [string ":luado"]:0: attempt to perform arithmetic on global 'liness' (a nil value)]],
+ pcall_err(command, 'luado return liness + 1'))
end)
it('works with NULL errors', function()
eq([=[Vim(luado):E5111: Error calling lua: [NULL]]=],
@@ -179,17 +180,18 @@ describe(':luado command', function()
end)
it('fails in sandbox when needed', function()
curbufmeths.set_lines(0, 1, false, {"ABC", "def", "gHi"})
- eq('\nE48: Not allowed in sandbox: sandbox luado runs = (runs or 0) + 1',
- redir_exec('sandbox luado runs = (runs or 0) + 1'))
+ eq('Vim(luado):E48: Not allowed in sandbox',
+ pcall_err(command, 'sandbox luado runs = (runs or 0) + 1'))
eq(NIL, funcs.luaeval('runs'))
end)
it('works with long strings', function()
local s = ('x'):rep(100500)
- eq('\nE5109: Error loading lua: [string ":luado"]:1: unfinished string near \'<eof>\'', redir_exec(('luado return "%s'):format(s)))
+ eq('Vim(luado):E5109: Error loading lua: [string ":luado"]:0: unfinished string near \'<eof>\'',
+ pcall_err(command, ('luado return "%s'):format(s)))
eq({''}, curbufmeths.get_lines(0, -1, false))
- eq('', redir_exec(('luado return "%s"'):format(s)))
+ eq('', exec_capture(('luado return "%s"'):format(s)))
eq({s}, curbufmeths.get_lines(0, -1, false))
end)
end)
@@ -207,7 +209,7 @@ describe(':luafile', function()
vim.api.nvim_buf_set_lines(1, 2, 3, false, {"TTSE"})
vim.api.nvim_buf_set_lines(1, 3, 4, false, {"STTE"})
]])
- eq('', redir_exec('luafile ' .. fname))
+ eq('', exec_capture('luafile ' .. fname))
eq({'', 'ETTS', 'TTSE', 'STTE'}, curbufmeths.get_lines(0, 100, false))
end)
diff --git a/test/functional/lua/diagnostic_spec.lua b/test/functional/lua/diagnostic_spec.lua
new file mode 100644
index 0000000000..9397af9d9f
--- /dev/null
+++ b/test/functional/lua/diagnostic_spec.lua
@@ -0,0 +1,1147 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local NIL = helpers.NIL
+local command = helpers.command
+local clear = helpers.clear
+local exec_lua = helpers.exec_lua
+local eq = helpers.eq
+local nvim = helpers.nvim
+
+describe('vim.diagnostic', function()
+ before_each(function()
+ clear()
+
+ exec_lua [[
+ require('vim.diagnostic')
+
+ function make_diagnostic(msg, x1, y1, x2, y2, severity, source)
+ return {
+ lnum = x1,
+ col = y1,
+ end_lnum = x2,
+ end_col = y2,
+ message = msg,
+ severity = severity,
+ source = source,
+ }
+ end
+
+ function make_error(msg, x1, y1, x2, y2, source)
+ return make_diagnostic(msg, x1, y1, x2, y2, vim.diagnostic.severity.ERROR, source)
+ end
+
+ function make_warning(msg, x1, y1, x2, y2, source)
+ return make_diagnostic(msg, x1, y1, x2, y2, vim.diagnostic.severity.WARN, source)
+ end
+
+ function make_info(msg, x1, y1, x2, y2, source)
+ return make_diagnostic(msg, x1, y1, x2, y2, vim.diagnostic.severity.INFO, source)
+ end
+
+ function make_hint(msg, x1, y1, x2, y2, source)
+ return make_diagnostic(msg, x1, y1, x2, y2, vim.diagnostic.severity.HINT, source)
+ end
+
+ function count_diagnostics(bufnr, severity, namespace)
+ return #vim.diagnostic.get(bufnr, {severity = severity, namespace = namespace})
+ end
+
+ function count_extmarks(bufnr, namespace)
+ return #vim.api.nvim_buf_get_extmarks(bufnr, namespace, 0, -1, {})
+ end
+ ]]
+
+ exec_lua([[
+ diagnostic_ns = vim.api.nvim_create_namespace("diagnostic_spec")
+ other_ns = vim.api.nvim_create_namespace("other_namespace")
+ diagnostic_bufnr = vim.api.nvim_create_buf(true, false)
+ local lines = {"1st line of text", "2nd line of text", "wow", "cool", "more", "lines"}
+ vim.fn.bufload(diagnostic_bufnr)
+ vim.api.nvim_buf_set_lines(diagnostic_bufnr, 0, 1, false, lines)
+ return diagnostic_bufnr
+ ]])
+ end)
+
+ after_each(function()
+ clear()
+ end)
+
+ it('creates highlight groups', function()
+ command('runtime plugin/diagnostic.vim')
+ eq({
+ 'DiagnosticError',
+ 'DiagnosticFloatingError',
+ 'DiagnosticFloatingHint',
+ 'DiagnosticFloatingInfo',
+ 'DiagnosticFloatingWarn',
+ 'DiagnosticHint',
+ 'DiagnosticInfo',
+ 'DiagnosticSignError',
+ 'DiagnosticSignHint',
+ 'DiagnosticSignInfo',
+ 'DiagnosticSignWarn',
+ 'DiagnosticUnderlineError',
+ 'DiagnosticUnderlineHint',
+ 'DiagnosticUnderlineInfo',
+ 'DiagnosticUnderlineWarn',
+ 'DiagnosticVirtualTextError',
+ 'DiagnosticVirtualTextHint',
+ 'DiagnosticVirtualTextInfo',
+ 'DiagnosticVirtualTextWarn',
+ 'DiagnosticWarn',
+ }, exec_lua([[return vim.fn.getcompletion('Diagnostic', 'highlight')]]))
+ end)
+
+ it('retrieves diagnostics from all buffers and namespaces', function()
+ local result = exec_lua [[
+ vim.diagnostic.set(diagnostic_ns, 1, {
+ make_error('Diagnostic #1', 1, 1, 1, 1),
+ make_error('Diagnostic #2', 2, 1, 2, 1),
+ })
+ vim.diagnostic.set(other_ns, 2, {
+ make_error('Diagnostic #3', 3, 1, 3, 1),
+ })
+ return vim.diagnostic.get()
+ ]]
+ eq(3, #result)
+ eq(2, exec_lua([[return #vim.tbl_filter(function(d) return d.bufnr == 1 end, ...)]], result))
+ eq('Diagnostic #1', result[1].message)
+ end)
+
+ it('saves and count a single error', function()
+ eq(1, exec_lua [[
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error('Diagnostic #1', 1, 1, 1, 1),
+ })
+ return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)
+ ]])
+ end)
+
+ it('saves and count multiple errors', function()
+ eq(2, exec_lua [[
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error('Diagnostic #1', 1, 1, 1, 1),
+ make_error('Diagnostic #2', 2, 1, 2, 1),
+ })
+ return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)
+ ]])
+ end)
+
+ it('saves and count from multiple namespaces', function()
+ eq({1, 1, 2}, exec_lua [[
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error('Diagnostic From Server 1', 1, 1, 1, 1),
+ })
+ vim.diagnostic.set(other_ns, diagnostic_bufnr, {
+ make_error('Diagnostic From Server 2', 1, 1, 1, 1),
+ })
+ return {
+ -- First namespace
+ count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns),
+ -- Second namespace
+ count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, other_ns),
+ -- All namespaces
+ count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR),
+ }
+ ]])
+ end)
+
+ it('saves and count from multiple namespaces with respect to severity', function()
+ eq({3, 0, 3}, exec_lua [[
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error('Diagnostic From Server 1:1', 1, 1, 1, 1),
+ make_error('Diagnostic From Server 1:2', 2, 2, 2, 2),
+ make_error('Diagnostic From Server 1:3', 2, 3, 3, 2),
+ })
+ vim.diagnostic.set(other_ns, diagnostic_bufnr, {
+ make_warning('Warning From Server 2', 3, 3, 3, 3),
+ })
+ return {
+ -- Namespace 1
+ count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns),
+ -- Namespace 2
+ count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, other_ns),
+ -- All namespaces
+ count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR),
+ }
+ ]])
+ end)
+
+ it('handles one namespace clearing highlights while the other still has highlights', function()
+ -- 1 Error (1)
+ -- 1 Warning (2)
+ -- 1 Warning (2) + 1 Warning (1)
+ -- 2 highlights and 2 underlines (since error)
+ -- 1 highlight + 1 underline
+ local all_highlights = {1, 1, 2, 4, 2}
+ eq(all_highlights, exec_lua [[
+ local ns_1_diags = {
+ make_error("Error 1", 1, 1, 1, 5),
+ make_warning("Warning on Server 1", 2, 1, 2, 5),
+ }
+ local ns_2_diags = {
+ make_warning("Warning 1", 2, 1, 2, 5),
+ }
+
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags)
+ vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diags)
+
+ return {
+ count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns),
+ count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN, other_ns),
+ count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN),
+ count_extmarks(diagnostic_bufnr, diagnostic_ns),
+ count_extmarks(diagnostic_bufnr, other_ns),
+ }
+ ]])
+
+ -- Clear diagnostics from namespace 1, and make sure we have the right amount of stuff for namespace 2
+ eq({1, 1, 2, 0, 2}, exec_lua [[
+ vim.diagnostic.disable(diagnostic_bufnr, diagnostic_ns)
+ return {
+ count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns),
+ count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN, other_ns),
+ count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN),
+ count_extmarks(diagnostic_bufnr, diagnostic_ns),
+ count_extmarks(diagnostic_bufnr, other_ns),
+ }
+ ]])
+
+ -- Show diagnostics from namespace 1 again
+ eq(all_highlights, exec_lua([[
+ vim.diagnostic.enable(diagnostic_bufnr, diagnostic_ns)
+ return {
+ count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns),
+ count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN, other_ns),
+ count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN),
+ count_extmarks(diagnostic_bufnr, diagnostic_ns),
+ count_extmarks(diagnostic_bufnr, other_ns),
+ }
+ ]]))
+ end)
+
+ it('does not display diagnostics when disabled', function()
+ eq({0, 2}, exec_lua [[
+ local ns_1_diags = {
+ make_error("Error 1", 1, 1, 1, 5),
+ make_warning("Warning on Server 1", 2, 1, 2, 5),
+ }
+ local ns_2_diags = {
+ make_warning("Warning 1", 2, 1, 2, 5),
+ }
+
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags)
+ vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diags)
+
+ vim.diagnostic.disable(diagnostic_bufnr, diagnostic_ns)
+
+ return {
+ count_extmarks(diagnostic_bufnr, diagnostic_ns),
+ count_extmarks(diagnostic_bufnr, other_ns),
+ }
+ ]])
+
+ eq({4, 0}, exec_lua [[
+ vim.diagnostic.enable(diagnostic_bufnr, diagnostic_ns)
+ vim.diagnostic.disable(diagnostic_bufnr, other_ns)
+
+ return {
+ count_extmarks(diagnostic_bufnr, diagnostic_ns),
+ count_extmarks(diagnostic_bufnr, other_ns),
+ }
+ ]])
+ end)
+
+ describe('reset()', function()
+ it('diagnostic count is 0 and displayed diagnostics are 0 after call', function()
+ -- 1 Error (1)
+ -- 1 Warning (2)
+ -- 1 Warning (2) + 1 Warning (1)
+ -- 2 highlights and 2 underlines (since error)
+ -- 1 highlight + 1 underline
+ local all_highlights = {1, 1, 2, 4, 2}
+ eq(all_highlights, exec_lua [[
+ local ns_1_diags = {
+ make_error("Error 1", 1, 1, 1, 5),
+ make_warning("Warning on Server 1", 2, 1, 2, 5),
+ }
+ local ns_2_diags = {
+ make_warning("Warning 1", 2, 1, 2, 5),
+ }
+
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diags)
+ vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diags)
+
+ return {
+ count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns),
+ count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN, other_ns),
+ count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN),
+ count_extmarks(diagnostic_bufnr, diagnostic_ns),
+ count_extmarks(diagnostic_bufnr, other_ns),
+ }
+ ]])
+
+ -- Reset diagnostics from namespace 1
+ exec_lua([[ vim.diagnostic.reset(diagnostic_ns) ]])
+
+ -- Make sure we have the right diagnostic count
+ eq({0, 1, 1, 0, 2} , exec_lua [[
+ local diagnostic_count = {}
+ vim.wait(100, function () diagnostic_count = {
+ count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns),
+ count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN, other_ns),
+ count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN),
+ count_extmarks(diagnostic_bufnr, diagnostic_ns),
+ count_extmarks(diagnostic_bufnr, other_ns),
+ } end )
+ return diagnostic_count
+ ]])
+
+ -- Reset diagnostics from namespace 2
+ exec_lua([[ vim.diagnostic.reset(other_ns) ]])
+
+ -- Make sure we have the right diagnostic count
+ eq({0, 0, 0, 0, 0}, exec_lua [[
+ local diagnostic_count = {}
+ vim.wait(100, function () diagnostic_count = {
+ count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns),
+ count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN, other_ns),
+ count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.WARN),
+ count_extmarks(diagnostic_bufnr, diagnostic_ns),
+ count_extmarks(diagnostic_bufnr, other_ns),
+ } end )
+ return diagnostic_count
+ ]])
+
+ end)
+ end)
+
+ describe('get_next_pos()', function()
+ it('can find the next pos with only one namespace', function()
+ eq({1, 1}, exec_lua [[
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error('Diagnostic #1', 1, 1, 1, 1),
+ })
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ return vim.diagnostic.get_next_pos()
+ ]])
+ end)
+
+ it('can find next pos with two errors', function()
+ eq({4, 4}, exec_lua [[
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error('Diagnostic #1', 1, 1, 1, 1),
+ make_error('Diagnostic #2', 4, 4, 4, 4),
+ })
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, {3, 1})
+ return vim.diagnostic.get_next_pos { namespace = diagnostic_ns }
+ ]])
+ end)
+
+ it('can cycle when position is past error', function()
+ eq({1, 1}, exec_lua [[
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error('Diagnostic #1', 1, 1, 1, 1),
+ })
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, {3, 1})
+ return vim.diagnostic.get_next_pos { namespace = diagnostic_ns }
+ ]])
+ end)
+
+ it('will not cycle when wrap is off', function()
+ eq(false, exec_lua [[
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error('Diagnostic #1', 1, 1, 1, 1),
+ })
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, {3, 1})
+ return vim.diagnostic.get_next_pos { namespace = diagnostic_ns, wrap = false }
+ ]])
+ end)
+
+ it('can cycle even from the last line', function()
+ eq({4, 4}, exec_lua [[
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error('Diagnostic #2', 4, 4, 4, 4),
+ })
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, {vim.api.nvim_buf_line_count(0), 1})
+ return vim.diagnostic.get_prev_pos { namespace = diagnostic_ns }
+ ]])
+ end)
+ end)
+
+ describe('get_prev_pos()', function()
+ it('can find the prev pos with only one namespace', function()
+ eq({1, 1}, exec_lua [[
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error('Diagnostic #1', 1, 1, 1, 1),
+ })
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, {3, 1})
+ return vim.diagnostic.get_prev_pos()
+ ]])
+ end)
+
+ it('can find prev pos with two errors', function()
+ eq({1, 1}, exec_lua [[
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error('Diagnostic #1', 1, 1, 1, 1),
+ make_error('Diagnostic #2', 4, 4, 4, 4),
+ })
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, {3, 1})
+ return vim.diagnostic.get_prev_pos { namespace = diagnostic_ns }
+ ]])
+ end)
+
+ it('can cycle when position is past error', function()
+ eq({4, 4}, exec_lua [[
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error('Diagnostic #2', 4, 4, 4, 4),
+ })
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, {3, 1})
+ return vim.diagnostic.get_prev_pos { namespace = diagnostic_ns }
+ ]])
+ end)
+
+ it('respects wrap parameter', function()
+ eq(false, exec_lua [[
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error('Diagnostic #2', 4, 4, 4, 4),
+ })
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.api.nvim_win_set_cursor(0, {3, 1})
+ return vim.diagnostic.get_prev_pos { namespace = diagnostic_ns, wrap = false}
+ ]])
+ end)
+ end)
+
+ describe('get()', function()
+ it('returns an empty table when no diagnostics are present', function()
+ eq({}, exec_lua [[return vim.diagnostic.get(diagnostic_bufnr, {namespace=diagnostic_ns})]])
+ end)
+
+ it('returns all diagnostics when no severity is supplied', function()
+ eq(2, exec_lua [[
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error("Error 1", 1, 1, 1, 5),
+ make_warning("Warning on Server 1", 1, 1, 2, 5),
+ })
+
+ return #vim.diagnostic.get(diagnostic_bufnr)
+ ]])
+ end)
+
+ it('returns only requested diagnostics when severity is supplied', function()
+ eq({2, 3, 2}, exec_lua [[
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error("Error 1", 1, 1, 1, 5),
+ make_warning("Warning on Server 1", 1, 1, 2, 5),
+ make_info("Ignored information", 1, 1, 2, 5),
+ make_hint("Here's a hint", 1, 1, 2, 5),
+ })
+
+ return {
+ #vim.diagnostic.get(diagnostic_bufnr, { severity = {min=vim.diagnostic.severity.WARN} }),
+ #vim.diagnostic.get(diagnostic_bufnr, { severity = {max=vim.diagnostic.severity.WARN} }),
+ #vim.diagnostic.get(diagnostic_bufnr, {
+ severity = {
+ min=vim.diagnostic.severity.INFO,
+ max=vim.diagnostic.severity.WARN,
+ }
+ }),
+ }
+ ]])
+ end)
+
+ it('allows filtering by line', function()
+ eq(1, exec_lua [[
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error("Error 1", 1, 1, 1, 5),
+ make_warning("Warning on Server 1", 1, 1, 2, 5),
+ make_info("Ignored information", 1, 1, 2, 5),
+ make_error("Error On Other Line", 2, 1, 1, 5),
+ })
+
+ return #vim.diagnostic.get(diagnostic_bufnr, {lnum = 2})
+ ]])
+ end)
+ end)
+
+ describe('config()', function()
+ it('can use functions for config values', function()
+ exec_lua [[
+ vim.diagnostic.config({
+ virtual_text = function() return true end,
+ }, diagnostic_ns)
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error('Delayed Diagnostic', 4, 4, 4, 4),
+ })
+ ]]
+
+ eq(1, exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]])
+ eq(2, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]])
+
+ -- Now, don't enable virtual text.
+ -- We should have one less extmark displayed.
+ exec_lua [[
+ vim.diagnostic.config({
+ virtual_text = function() return false end,
+ }, diagnostic_ns)
+ ]]
+
+ eq(1, exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]])
+ eq(1, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]])
+ end)
+
+ it('allows filtering by severity', function()
+ local get_extmark_count_with_severity = function(min_severity)
+ return exec_lua([[
+ vim.diagnostic.config({
+ underline = false,
+ virtual_text = {
+ severity = {min=...},
+ },
+ })
+
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_warning('Delayed Diagnostic', 4, 4, 4, 4),
+ })
+
+ return count_extmarks(diagnostic_bufnr, diagnostic_ns)
+ ]], min_severity)
+ end
+
+ -- No messages with Error or higher
+ eq(0, get_extmark_count_with_severity("ERROR"))
+
+ -- But now we don't filter it
+ eq(1, get_extmark_count_with_severity("WARN"))
+ eq(1, get_extmark_count_with_severity("HINT"))
+ end)
+
+ it('allows sorting by severity', function()
+ exec_lua [[
+ vim.diagnostic.config({
+ underline = false,
+ signs = true,
+ virtual_text = true,
+ })
+
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_warning('Warning', 4, 4, 4, 4),
+ make_error('Error', 4, 4, 4, 4),
+ make_info('Info', 4, 4, 4, 4),
+ })
+
+ function get_virt_text_and_signs(severity_sort)
+ vim.diagnostic.config({
+ severity_sort = severity_sort,
+ })
+
+ local virt_text = vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, diagnostic_ns, 0, -1, {details = true})[1][4].virt_text
+
+ local virt_texts = {}
+ for i = 2, #virt_text do
+ table.insert(virt_texts, (string.gsub(virt_text[i][2], "DiagnosticVirtualText", "")))
+ end
+
+ local signs = {}
+ for _, v in ipairs(vim.fn.sign_getplaced(diagnostic_bufnr, {group = "*"})[1].signs) do
+ table.insert(signs, (string.gsub(v.name, "DiagnosticSign", "")))
+ end
+
+ return {virt_texts, signs}
+ end
+ ]]
+
+ local result = exec_lua [[return get_virt_text_and_signs(false)]]
+
+ -- Virt texts are defined lowest priority to highest, signs from
+ -- highest to lowest
+ eq({'Warn', 'Error', 'Info'}, result[1])
+ eq({'Info', 'Error', 'Warn'}, result[2])
+
+ result = exec_lua [[return get_virt_text_and_signs(true)]]
+ eq({'Info', 'Warn', 'Error'}, result[1])
+ eq({'Error', 'Warn', 'Info'}, result[2])
+
+ result = exec_lua [[return get_virt_text_and_signs({ reverse = true })]]
+ eq({'Error', 'Warn', 'Info'}, result[1])
+ eq({'Info', 'Warn', 'Error'}, result[2])
+ end)
+
+ it('can show diagnostic sources in virtual text', function()
+ local result = exec_lua [[
+ local diagnostics = {
+ make_error('Some error', 0, 0, 0, 0, 'source x'),
+ }
+
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics, {
+ underline = false,
+ virtual_text = {
+ prefix = '',
+ source = 'always',
+ }
+ })
+
+ local extmarks = vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, diagnostic_ns, 0, -1, {details = true})
+ local virt_text = extmarks[1][4].virt_text[2][1]
+ return virt_text
+ ]]
+ eq(' source x: Some error', result)
+
+ result = exec_lua [[
+ vim.diagnostic.config({
+ underline = false,
+ virtual_text = {
+ prefix = '',
+ source = 'if_many',
+ }
+ }, diagnostic_ns)
+
+ local extmarks = vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, diagnostic_ns, 0, -1, {details = true})
+ local virt_text = extmarks[1][4].virt_text[2][1]
+ return virt_text
+ ]]
+ eq(' Some error', result)
+
+ result = exec_lua [[
+ local diagnostics = {
+ make_error('Some error', 0, 0, 0, 0, 'source x'),
+ make_error('Another error', 1, 1, 1, 1, 'source y'),
+ }
+
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics, {
+ underline = false,
+ virtual_text = {
+ prefix = '',
+ source = 'if_many',
+ }
+ })
+
+ local extmarks = vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, diagnostic_ns, 0, -1, {details = true})
+ local virt_text = {extmarks[1][4].virt_text[2][1], extmarks[2][4].virt_text[2][1]}
+ return virt_text
+ ]]
+ eq(' source x: Some error', result[1])
+ eq(' source y: Another error', result[2])
+ end)
+
+ it('supports a format function for diagnostic messages', function()
+ local result = exec_lua [[
+ vim.diagnostic.config({
+ underline = false,
+ virtual_text = {
+ prefix = '',
+ format = function(diagnostic)
+ if diagnostic.severity == vim.diagnostic.severity.ERROR then
+ return string.format("🔥 %s", diagnostic.message)
+ end
+ return string.format("👀 %s", diagnostic.message)
+ end,
+ }
+ })
+
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_warning('Warning', 0, 0, 0, 0),
+ make_error('Error', 1, 0, 1, 0),
+ })
+
+ local extmarks = vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, diagnostic_ns, 0, -1, {details = true})
+ return {extmarks[1][4].virt_text, extmarks[2][4].virt_text}
+ ]]
+ eq(" 👀 Warning", result[1][2][1])
+ eq(" 🔥 Error", result[2][2][1])
+ end)
+
+ it('includes source for formatted diagnostics', function()
+ local result = exec_lua [[
+ vim.diagnostic.config({
+ underline = false,
+ virtual_text = {
+ prefix = '',
+ source = 'always',
+ format = function(diagnostic)
+ if diagnostic.severity == vim.diagnostic.severity.ERROR then
+ return string.format("🔥 %s", diagnostic.message)
+ end
+ return string.format("👀 %s", diagnostic.message)
+ end,
+ }
+ })
+
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_warning('Warning', 0, 0, 0, 0, 'some_linter'),
+ make_error('Error', 1, 0, 1, 0, 'another_linter'),
+ })
+
+ local extmarks = vim.api.nvim_buf_get_extmarks(diagnostic_bufnr, diagnostic_ns, 0, -1, {details = true})
+ return {extmarks[1][4].virt_text, extmarks[2][4].virt_text}
+ ]]
+ eq(" some_linter: 👀 Warning", result[1][2][1])
+ eq(" another_linter: 🔥 Error", result[2][2][1])
+ end)
+ end)
+
+ describe('set()', function()
+ it('can perform updates after insert_leave', function()
+ exec_lua [[vim.api.nvim_set_current_buf(diagnostic_bufnr)]]
+ nvim("input", "o")
+ eq({mode='i', blocking=false}, nvim("get_mode"))
+
+ -- Save the diagnostics
+ exec_lua [[
+ vim.diagnostic.config({
+ update_in_insert = false,
+ })
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error('Delayed Diagnostic', 4, 4, 4, 4),
+ })
+ ]]
+
+ -- No diagnostics displayed yet.
+ eq({mode='i', blocking=false}, nvim("get_mode"))
+ eq(1, exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]])
+ eq(0, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]])
+
+ nvim("input", "<esc>")
+ eq({mode='n', blocking=false}, nvim("get_mode"))
+
+ eq(1, exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]])
+ eq(2, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]])
+ end)
+
+ it('does not perform updates when not needed', function()
+ exec_lua [[vim.api.nvim_set_current_buf(diagnostic_bufnr)]]
+ nvim("input", "o")
+ eq({mode='i', blocking=false}, nvim("get_mode"))
+
+ -- Save the diagnostics
+ exec_lua [[
+ vim.diagnostic.config({
+ update_in_insert = false,
+ virtual_text = true,
+ })
+
+ -- Count how many times we call display.
+ SetVirtualTextOriginal = vim.diagnostic._set_virtual_text
+
+ DisplayCount = 0
+ vim.diagnostic._set_virtual_text = function(...)
+ DisplayCount = DisplayCount + 1
+ return SetVirtualTextOriginal(...)
+ end
+
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error('Delayed Diagnostic', 4, 4, 4, 4),
+ })
+ ]]
+
+ -- No diagnostics displayed yet.
+ eq({mode='i', blocking=false}, nvim("get_mode"))
+ eq(1, exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]])
+ eq(0, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]])
+ eq(0, exec_lua [[return DisplayCount]])
+
+ nvim("input", "<esc>")
+ eq({mode='n', blocking=false}, nvim("get_mode"))
+
+ eq(1, exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]])
+ eq(2, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]])
+ eq(1, exec_lua [[return DisplayCount]])
+
+ -- Go in and out of insert mode one more time.
+ nvim("input", "o")
+ eq({mode='i', blocking=false}, nvim("get_mode"))
+
+ nvim("input", "<esc>")
+ eq({mode='n', blocking=false}, nvim("get_mode"))
+
+ -- Should not have set the virtual text again.
+ eq(1, exec_lua [[return DisplayCount]])
+ end)
+
+ it('never sets virtual text, in combination with insert leave', function()
+ exec_lua [[vim.api.nvim_set_current_buf(diagnostic_bufnr)]]
+ nvim("input", "o")
+ eq({mode='i', blocking=false}, nvim("get_mode"))
+
+ -- Save the diagnostics
+ exec_lua [[
+ vim.diagnostic.config({
+ update_in_insert = false,
+ virtual_text = false,
+ })
+
+ -- Count how many times we call display.
+ SetVirtualTextOriginal = vim.diagnostic._set_virtual_text
+
+ DisplayCount = 0
+ vim.diagnostic._set_virtual_text = function(...)
+ DisplayCount = DisplayCount + 1
+ return SetVirtualTextOriginal(...)
+ end
+
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error('Delayed Diagnostic', 4, 4, 4, 4),
+ })
+ ]]
+
+ -- No diagnostics displayed yet.
+ eq({mode='i', blocking=false}, nvim("get_mode"))
+ eq(1, exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]])
+ eq(0, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]])
+ eq(0, exec_lua [[return DisplayCount]])
+
+ nvim("input", "<esc>")
+ eq({mode='n', blocking=false}, nvim("get_mode"))
+
+ eq(1, exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]])
+ eq(1, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]])
+ eq(0, exec_lua [[return DisplayCount]])
+
+ -- Go in and out of insert mode one more time.
+ nvim("input", "o")
+ eq({mode='i', blocking=false}, nvim("get_mode"))
+
+ nvim("input", "<esc>")
+ eq({mode='n', blocking=false}, nvim("get_mode"))
+
+ -- Should not have set the virtual text still.
+ eq(0, exec_lua [[return DisplayCount]])
+ end)
+
+ it('can perform updates while in insert mode, if desired', function()
+ exec_lua [[vim.api.nvim_set_current_buf(diagnostic_bufnr)]]
+ nvim("input", "o")
+ eq({mode='i', blocking=false}, nvim("get_mode"))
+
+ -- Save the diagnostics
+ exec_lua [[
+ vim.diagnostic.config({
+ update_in_insert = true,
+ })
+
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error('Delayed Diagnostic', 4, 4, 4, 4),
+ })
+ ]]
+
+ -- Diagnostics are displayed, because the user wanted them that way!
+ eq({mode='i', blocking=false}, nvim("get_mode"))
+ eq(1, exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]])
+ eq(2, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]])
+
+ nvim("input", "<esc>")
+ eq({mode='n', blocking=false}, nvim("get_mode"))
+
+ eq(1, exec_lua [[return count_diagnostics(diagnostic_bufnr, vim.diagnostic.severity.ERROR, diagnostic_ns)]])
+ eq(2, exec_lua [[return count_extmarks(diagnostic_bufnr, diagnostic_ns)]])
+ end)
+
+ it('can set diagnostics without displaying them', function()
+ eq(0, exec_lua [[
+ vim.diagnostic.disable(diagnostic_bufnr, diagnostic_ns)
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error('Diagnostic From Server 1:1', 1, 1, 1, 1),
+ })
+ return count_extmarks(diagnostic_bufnr, diagnostic_ns)
+ ]])
+
+ eq(2, exec_lua [[
+ vim.diagnostic.enable(diagnostic_bufnr, diagnostic_ns)
+ return count_extmarks(diagnostic_bufnr, diagnostic_ns)
+ ]])
+ end)
+
+ it('can set display options', function()
+ eq(0, exec_lua [[
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error('Diagnostic From Server 1:1', 1, 1, 1, 1),
+ }, { virtual_text = false, underline = false })
+ return count_extmarks(diagnostic_bufnr, diagnostic_ns)
+ ]])
+
+ eq(1, exec_lua [[
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error('Diagnostic From Server 1:1', 1, 1, 1, 1),
+ }, { virtual_text = true, underline = false })
+ return count_extmarks(diagnostic_bufnr, diagnostic_ns)
+ ]])
+ end)
+ end)
+
+ describe('show_line_diagnostics()', function()
+ it('creates floating window and returns popup bufnr and winnr if current line contains diagnostics', function()
+ -- Two lines:
+ -- Diagnostic:
+ -- 1. <msg>
+ eq(2, exec_lua [[
+ local diagnostics = {
+ make_error("Syntax error", 0, 1, 0, 3),
+ }
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
+ local popup_bufnr, winnr = vim.diagnostic.show_line_diagnostics()
+ return #vim.api.nvim_buf_get_lines(popup_bufnr, 0, -1, false)
+ ]])
+ end)
+
+ it('only reports diagnostics from the current buffer when bufnr is omitted #15710', function()
+ eq(2, exec_lua [[
+ local other_bufnr = vim.api.nvim_create_buf(true, false)
+ local buf_1_diagnostics = {
+ make_error("Syntax error", 0, 1, 0, 3),
+ }
+ local buf_2_diagnostics = {
+ make_warning("Some warning", 0, 1, 0, 3),
+ }
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, buf_1_diagnostics)
+ vim.diagnostic.set(other_ns, other_bufnr, buf_2_diagnostics)
+ local popup_bufnr, winnr = vim.diagnostic.show_line_diagnostics()
+ return #vim.api.nvim_buf_get_lines(popup_bufnr, 0, -1, false)
+ ]])
+ end)
+
+ it('allows filtering by namespace', function()
+ eq(2, exec_lua [[
+ local ns_1_diagnostics = {
+ make_error("Syntax error", 0, 1, 0, 3),
+ }
+ local ns_2_diagnostics = {
+ make_warning("Some warning", 0, 1, 0, 3),
+ }
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, ns_1_diagnostics)
+ vim.diagnostic.set(other_ns, diagnostic_bufnr, ns_2_diagnostics)
+ local popup_bufnr, winnr = vim.diagnostic.show_line_diagnostics({namespace = diagnostic_ns})
+ return #vim.api.nvim_buf_get_lines(popup_bufnr, 0, -1, false)
+ ]])
+ end)
+
+ it('creates floating window and returns popup bufnr and winnr without header, if requested', function()
+ -- One line (since no header):
+ -- 1. <msg>
+ eq(1, exec_lua [[
+ local diagnostics = {
+ make_error("Syntax error", 0, 1, 0, 3),
+ }
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
+ local popup_bufnr, winnr = vim.diagnostic.show_line_diagnostics {show_header = false}
+ return #vim.api.nvim_buf_get_lines(popup_bufnr, 0, -1, false)
+ ]])
+ end)
+
+ it('clamps diagnostic line numbers within the valid range', function()
+ eq(1, exec_lua [[
+ local diagnostics = {
+ make_error("Syntax error", 6, 0, 6, 0),
+ }
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
+ local popup_bufnr, winnr = vim.diagnostic.show_line_diagnostics({show_header = false}, diagnostic_bufnr, 5)
+ return #vim.api.nvim_buf_get_lines(popup_bufnr, 0, -1, false)
+ ]])
+ end)
+
+ it('can show diagnostic source', function()
+ exec_lua [[vim.api.nvim_win_set_buf(0, diagnostic_bufnr)]]
+
+ eq({"1. Syntax error"}, exec_lua [[
+ local diagnostics = {
+ make_error("Syntax error", 0, 1, 0, 3, "source x"),
+ }
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
+ local popup_bufnr, winnr = vim.diagnostic.show_line_diagnostics {
+ show_header = false,
+ source = "if_many",
+ }
+ local lines = vim.api.nvim_buf_get_lines(popup_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ ]])
+
+ eq({"1. source x: Syntax error"}, exec_lua [[
+ local popup_bufnr, winnr = vim.diagnostic.show_line_diagnostics {
+ show_header = false,
+ source = "always",
+ }
+ local lines = vim.api.nvim_buf_get_lines(popup_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ ]])
+
+ eq({"1. source x: Syntax error", "2. source y: Another error"}, exec_lua [[
+ local diagnostics = {
+ make_error("Syntax error", 0, 1, 0, 3, "source x"),
+ make_error("Another error", 0, 1, 0, 3, "source y"),
+ }
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
+ local popup_bufnr, winnr = vim.diagnostic.show_line_diagnostics {
+ show_header = false,
+ source = "if_many",
+ }
+ local lines = vim.api.nvim_buf_get_lines(popup_bufnr, 0, -1, false)
+ vim.api.nvim_win_close(winnr, true)
+ return lines
+ ]])
+ end)
+ end)
+
+ describe('set_signs()', function()
+ -- TODO(tjdevries): Find out why signs are not displayed when set from Lua...??
+ pending('sets signs by default', function()
+ exec_lua [[
+ vim.diagnostic.config({
+ update_in_insert = true,
+ signs = true,
+ })
+
+ local diagnostics = {
+ make_error('Delayed Diagnostic', 1, 1, 1, 2),
+ make_error('Delayed Diagnostic', 3, 3, 3, 3),
+ }
+
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, diagnostics)
+
+ vim.diagnostic._set_signs(diagnostic_ns, diagnostic_bufnr, diagnostics)
+ -- return vim.fn.sign_getplaced()
+ ]]
+
+ nvim("input", "o")
+ nvim("input", "<esc>")
+
+ -- TODO(tjdevries): Find a way to get the signs to display in the test...
+ eq(nil, exec_lua [[
+ return im.fn.sign_getplaced()[1].signs
+ ]])
+ end)
+ end)
+
+ describe('setloclist()', function()
+ it('sets diagnostics in lnum order', function()
+ local loc_list = exec_lua [[
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error('Farther Diagnostic', 4, 4, 4, 4),
+ make_error('Lower Diagnostic', 1, 1, 1, 1),
+ })
+
+ vim.diagnostic.setloclist()
+
+ return vim.fn.getloclist(0)
+ ]]
+
+ assert(loc_list[1].lnum < loc_list[2].lnum)
+ end)
+
+ it('sets diagnostics in lnum order, regardless of namespace', function()
+ local loc_list = exec_lua [[
+ vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
+
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error('Lower Diagnostic', 1, 1, 1, 1),
+ })
+
+ vim.diagnostic.set(other_ns, diagnostic_bufnr, {
+ make_warning('Farther Diagnostic', 4, 4, 4, 4),
+ })
+
+ vim.diagnostic.setloclist()
+
+ return vim.fn.getloclist(0)
+ ]]
+
+ assert(loc_list[1].lnum < loc_list[2].lnum)
+ end)
+ end)
+
+ describe('match()', function()
+ it('matches a string', function()
+ local msg = "ERROR: george.txt:19:84:Two plus two equals five"
+ local diagnostic = {
+ severity = exec_lua [[return vim.diagnostic.severity.ERROR]],
+ lnum = 18,
+ col = 83,
+ end_lnum = 18,
+ end_col = 83,
+ message = "Two plus two equals five",
+ }
+ eq(diagnostic, exec_lua([[
+ return vim.diagnostic.match(..., "^(%w+): [^:]+:(%d+):(%d+):(.+)$", {"severity", "lnum", "col", "message"})
+ ]], msg))
+ end)
+
+ it('returns nil if the pattern fails to match', function()
+ eq(NIL, exec_lua [[
+ local msg = "The answer to life, the universe, and everything is"
+ return vim.diagnostic.match(msg, "This definitely will not match", {})
+ ]])
+ end)
+
+ it('respects default values', function()
+ local msg = "anna.txt:1:Happy families are all alike"
+ local diagnostic = {
+ severity = exec_lua [[return vim.diagnostic.severity.INFO]],
+ lnum = 0,
+ col = 0,
+ end_lnum = 0,
+ end_col = 0,
+ message = "Happy families are all alike",
+ }
+ eq(diagnostic, exec_lua([[
+ return vim.diagnostic.match(..., "^[^:]+:(%d+):(.+)$", {"lnum", "message"}, nil, {severity = vim.diagnostic.severity.INFO})
+ ]], msg))
+ end)
+
+ it('accepts a severity map', function()
+ local msg = "46:FATAL:Et tu, Brute?"
+ local diagnostic = {
+ severity = exec_lua [[return vim.diagnostic.severity.ERROR]],
+ lnum = 45,
+ col = 0,
+ end_lnum = 45,
+ end_col = 0,
+ message = "Et tu, Brute?",
+ }
+ eq(diagnostic, exec_lua([[
+ return vim.diagnostic.match(..., "^(%d+):(%w+):(.+)$", {"lnum", "severity", "message"}, {FATAL = vim.diagnostic.severity.ERROR})
+ ]], msg))
+ end)
+ end)
+
+ describe('toqflist() and fromqflist()', function()
+ it('works', function()
+ local result = exec_lua [[
+ vim.diagnostic.set(diagnostic_ns, diagnostic_bufnr, {
+ make_error('Error 1', 0, 1, 0, 1),
+ make_error('Error 2', 1, 1, 1, 1),
+ make_warning('Warning', 2, 2, 2, 2),
+ })
+
+ local diagnostics = vim.diagnostic.get(diagnostic_bufnr)
+ vim.fn.setqflist(vim.diagnostic.toqflist(diagnostics))
+ local list = vim.fn.getqflist()
+ local new_diagnostics = vim.diagnostic.fromqflist(list)
+
+ -- Remove namespace since it isn't present in the return value of
+ -- fromlist()
+ for _, v in ipairs(diagnostics) do
+ v.namespace = nil
+ end
+
+ return {diagnostics, new_diagnostics}
+ ]]
+ eq(result[1], result[2])
+ end)
+ end)
+end)
diff --git a/test/functional/lua/highlight_spec.lua b/test/functional/lua/highlight_spec.lua
new file mode 100644
index 0000000000..50eecb5d09
--- /dev/null
+++ b/test/functional/lua/highlight_spec.lua
@@ -0,0 +1,25 @@
+local helpers = require('test.functional.helpers')(after_each)
+local exec_lua = helpers.exec_lua
+local eq = helpers.eq
+local eval = helpers.eval
+local command = helpers.command
+local clear = helpers.clear
+
+describe('vim.highlight.on_yank', function()
+
+ before_each(function()
+ clear()
+ end)
+
+ it('does not show errors even if buffer is wiped before timeout', function()
+ command('new')
+ exec_lua[[
+ vim.highlight.on_yank({timeout = 10, on_macro = true, event = {operator = "y", regtype = "v"}})
+ vim.cmd('bwipeout!')
+ ]]
+ helpers.sleep(10)
+ helpers.feed('<cr>') -- avoid hang if error message exists
+ eq('', eval('v:errmsg'))
+ end)
+
+end)
diff --git a/test/functional/lua/json_spec.lua b/test/functional/lua/json_spec.lua
new file mode 100644
index 0000000000..fbb21bfd57
--- /dev/null
+++ b/test/functional/lua/json_spec.lua
@@ -0,0 +1,133 @@
+local helpers = require('test.functional.helpers')(after_each)
+local clear = helpers.clear
+local NIL = helpers.NIL
+local exec_lua = helpers.exec_lua
+local eq = helpers.eq
+
+describe('vim.json.decode function', function()
+ before_each(function()
+ clear()
+ end)
+
+ it('parses null, true, false', function()
+ eq(NIL, exec_lua([[return vim.json.decode('null')]]))
+ eq(true, exec_lua([[return vim.json.decode('true')]]))
+ eq(false, exec_lua([[return vim.json.decode('false')]]))
+ end)
+
+ it('parses integer numbers', function()
+ eq(100000, exec_lua([[return vim.json.decode('100000')]]))
+ eq(-100000, exec_lua([[return vim.json.decode('-100000')]]))
+ eq(100000, exec_lua([[return vim.json.decode(' 100000 ')]]))
+ eq(-100000, exec_lua([[return vim.json.decode(' -100000 ')]]))
+ eq(0, exec_lua([[return vim.json.decode('0')]]))
+ eq(0, exec_lua([[return vim.json.decode('-0')]]))
+ end)
+
+ it('parses floating-point numbers', function()
+ -- This behavior differs from vim.fn.json_decode, which return '100000.0'
+ eq('100000', exec_lua([[return tostring(vim.json.decode('100000.0'))]]))
+ eq(100000.5, exec_lua([[return vim.json.decode('100000.5')]]))
+ eq(-100000.5, exec_lua([[return vim.json.decode('-100000.5')]]))
+ eq(-100000.5e50, exec_lua([[return vim.json.decode('-100000.5e50')]]))
+ eq(100000.5e50, exec_lua([[return vim.json.decode('100000.5e50')]]))
+ eq(100000.5e50, exec_lua([[return vim.json.decode('100000.5e+50')]]))
+ eq(-100000.5e-50, exec_lua([[return vim.json.decode('-100000.5e-50')]]))
+ eq(100000.5e-50, exec_lua([[return vim.json.decode('100000.5e-50')]]))
+ eq(100000e-50, exec_lua([[return vim.json.decode('100000e-50')]]))
+ eq(0.5, exec_lua([[return vim.json.decode('0.5')]]))
+ eq(0.005, exec_lua([[return vim.json.decode('0.005')]]))
+ eq(0.005, exec_lua([[return vim.json.decode('0.00500')]]))
+ eq(0.5, exec_lua([[return vim.json.decode('0.00500e+002')]]))
+ eq(0.00005, exec_lua([[return vim.json.decode('0.00500e-002')]]))
+
+ eq(-0.0, exec_lua([[return vim.json.decode('-0.0')]]))
+ eq(-0.0, exec_lua([[return vim.json.decode('-0.0e0')]]))
+ eq(-0.0, exec_lua([[return vim.json.decode('-0.0e+0')]]))
+ eq(-0.0, exec_lua([[return vim.json.decode('-0.0e-0')]]))
+ eq(-0.0, exec_lua([[return vim.json.decode('-0e-0')]]))
+ eq(-0.0, exec_lua([[return vim.json.decode('-0e-2')]]))
+ eq(-0.0, exec_lua([[return vim.json.decode('-0e+2')]]))
+
+ eq(0.0, exec_lua([[return vim.json.decode('0.0')]]))
+ eq(0.0, exec_lua([[return vim.json.decode('0.0e0')]]))
+ eq(0.0, exec_lua([[return vim.json.decode('0.0e+0')]]))
+ eq(0.0, exec_lua([[return vim.json.decode('0.0e-0')]]))
+ eq(0.0, exec_lua([[return vim.json.decode('0e-0')]]))
+ eq(0.0, exec_lua([[return vim.json.decode('0e-2')]]))
+ eq(0.0, exec_lua([[return vim.json.decode('0e+2')]]))
+ end)
+
+ it('parses containers', function()
+ eq({1}, exec_lua([[return vim.json.decode('[1]')]]))
+ eq({NIL, 1}, exec_lua([[return vim.json.decode('[null, 1]')]]))
+ eq({['1']=2}, exec_lua([[return vim.json.decode('{"1": 2}')]]))
+ eq({['1']=2, ['3']={{['4']={['5']={{}, 1}}}}},
+ exec_lua([[return vim.json.decode('{"1": 2, "3": [{"4": {"5": [ [], 1]}}]}')]]))
+ end)
+
+ it('parses strings properly', function()
+ eq('\n', exec_lua([=[return vim.json.decode([["\n"]])]=]))
+ eq('', exec_lua([=[return vim.json.decode([[""]])]=]))
+ eq('\\/"\t\b\n\r\f', exec_lua([=[return vim.json.decode([["\\\/\"\t\b\n\r\f"]])]=]))
+ eq('/a', exec_lua([=[return vim.json.decode([["\/a"]])]=]))
+ -- Unicode characters: 2-byte, 3-byte
+ eq('«',exec_lua([=[return vim.json.decode([["«"]])]=]))
+ eq('ફ',exec_lua([=[return vim.json.decode([["ફ"]])]=]))
+ end)
+
+ it('parses surrogate pairs properly', function()
+ eq('\240\144\128\128', exec_lua([[return vim.json.decode('"\\uD800\\uDC00"')]]))
+ end)
+
+ it('accepts all spaces in every position where space may be put', function()
+ local s = ' \t\n\r \t\r\n \n\t\r \n\r\t \r\t\n \r\n\t\t \n\r\t \r\n\t\n \r\t\n\r \t\r \n\t\r\n \n \t\r\n \r\t\n\t \r\n\t\r \n\r \t\n\r\t \r \t\n\r \n\t\r\t \n\r\t\n \r\n \t\r\n\t'
+ local str = ('%s{%s"key"%s:%s[%s"val"%s,%s"val2"%s]%s,%s"key2"%s:%s1%s}%s'):gsub('%%s', s)
+ eq({key={'val', 'val2'}, key2=1}, exec_lua([[return vim.json.decode(...)]], str))
+ end)
+
+end)
+
+describe('vim.json.encode function', function()
+ before_each(function()
+ clear()
+ end)
+
+ it('dumps strings', function()
+ eq('"Test"', exec_lua([[return vim.json.encode('Test')]]))
+ eq('""', exec_lua([[return vim.json.encode('')]]))
+ eq('"\\t"', exec_lua([[return vim.json.encode('\t')]]))
+ eq('"\\n"', exec_lua([[return vim.json.encode('\n')]]))
+ -- vim.fn.json_encode return \\u001B
+ eq('"\\u001b"', exec_lua([[return vim.json.encode('\27')]]))
+ eq('"þÿþ"', exec_lua([[return vim.json.encode('þÿþ')]]))
+ end)
+
+ it('dumps numbers', function()
+ eq('0', exec_lua([[return vim.json.encode(0)]]))
+ eq('10', exec_lua([[return vim.json.encode(10)]]))
+ eq('-10', exec_lua([[return vim.json.encode(-10)]]))
+ end)
+
+ it('dumps floats', function()
+ eq('10.5', exec_lua([[return vim.json.encode(10.5)]]))
+ eq('-10.5', exec_lua([[return vim.json.encode(-10.5)]]))
+ eq('-1e-05', exec_lua([[return vim.json.encode(-1e-5)]]))
+ end)
+
+ it('dumps lists', function()
+ eq('[]', exec_lua([[return vim.json.encode({})]]))
+ eq('[[]]', exec_lua([[return vim.json.encode({{}})]]))
+ eq('[[],[]]', exec_lua([[return vim.json.encode({{}, {}})]]))
+ end)
+
+ it('dumps dictionaries', function()
+ eq('{}', exec_lua([[return vim.json.encode(vim.empty_dict())]]))
+ eq('{"d":[]}', exec_lua([[return vim.json.encode({d={}})]]))
+ end)
+
+ it('dumps vim.NIL', function()
+ eq('null', exec_lua([[return vim.json.encode(vim.NIL)]]))
+ end)
+
+end)
diff --git a/test/functional/lua/luaeval_spec.lua b/test/functional/lua/luaeval_spec.lua
index 2ec48777fd..255e99032f 100644
--- a/test/functional/lua/luaeval_spec.lua
+++ b/test/functional/lua/luaeval_spec.lua
@@ -63,11 +63,10 @@ describe('luaeval()', function()
eq('\n[[...@0]]', funcs.execute('echo luaeval("l")'))
end)
end)
- describe('strings', function()
- it('are successfully converted to special dictionaries', function()
+ describe('strings with NULs', function()
+ it('are successfully converted to blobs', function()
command([[let s = luaeval('"\0"')]])
- eq({_TYPE={}, _VAL={'\n'}}, meths.get_var('s'))
- eq(1, funcs.eval('s._TYPE is v:msgpack_types.binary'))
+ eq('\000', meths.get_var('s'))
end)
it('are successfully converted to special dictionaries in table keys',
function()
@@ -76,13 +75,10 @@ describe('luaeval()', function()
eq(1, funcs.eval('d._TYPE is v:msgpack_types.map'))
eq(1, funcs.eval('d._VAL[0][0]._TYPE is v:msgpack_types.string'))
end)
- it('are successfully converted to special dictionaries from a list',
+ it('are successfully converted to blobs from a list',
function()
command([[let l = luaeval('{"abc", "a\0b", "c\0d", "def"}')]])
- eq({'abc', {_TYPE={}, _VAL={'a\nb'}}, {_TYPE={}, _VAL={'c\nd'}}, 'def'},
- meths.get_var('l'))
- eq(1, funcs.eval('l[1]._TYPE is v:msgpack_types.binary'))
- eq(1, funcs.eval('l[2]._TYPE is v:msgpack_types.binary'))
+ eq({'abc', 'a\000b', 'c\000d', 'def'}, meths.get_var('l'))
end)
end)
@@ -100,9 +96,9 @@ describe('luaeval()', function()
eq(1, eval('type(luaeval("\'test\'"))'))
eq('', funcs.luaeval('""'))
- eq({_TYPE={}, _VAL={'\n'}}, funcs.luaeval([['\0']]))
- eq({_TYPE={}, _VAL={'\n', '\n'}}, funcs.luaeval([['\0\n\0']]))
- eq(1, eval([[luaeval('"\0\n\0"')._TYPE is v:msgpack_types.binary]]))
+ eq('\000', funcs.luaeval([['\0']]))
+ eq('\000\n\000', funcs.luaeval([['\0\n\0']]))
+ eq(10, eval([[type(luaeval("'\\0\\n\\0'"))]]))
eq(true, funcs.luaeval('true'))
eq(false, funcs.luaeval('false'))
@@ -122,12 +118,11 @@ describe('luaeval()', function()
local level = 30
eq(nested_by_level[level].o, funcs.luaeval(nested_by_level[level].s))
- eq({_TYPE={}, _VAL={{{_TYPE={}, _VAL={'\n', '\n'}}, {_TYPE={}, _VAL={'\n', '\n\n'}}}}},
+ eq({_TYPE={}, _VAL={{{_TYPE={}, _VAL={'\n', '\n'}}, '\000\n\000\000'}}},
funcs.luaeval([[{['\0\n\0']='\0\n\0\0'}]]))
eq(1, eval([[luaeval('{["\0\n\0"]="\0\n\0\0"}')._TYPE is v:msgpack_types.map]]))
eq(1, eval([[luaeval('{["\0\n\0"]="\0\n\0\0"}')._VAL[0][0]._TYPE is v:msgpack_types.string]]))
- eq(1, eval([[luaeval('{["\0\n\0"]="\0\n\0\0"}')._VAL[0][1]._TYPE is v:msgpack_types.binary]]))
- eq({nested={{_TYPE={}, _VAL={{{_TYPE={}, _VAL={'\n', '\n'}}, {_TYPE={}, _VAL={'\n', '\n\n'}}}}}}},
+ eq({nested={{_TYPE={}, _VAL={{{_TYPE={}, _VAL={'\n', '\n'}}, '\000\n\000\000'}}}}},
funcs.luaeval([[{nested={{['\0\n\0']='\0\n\0\0'}}}]]))
end)
@@ -175,8 +170,8 @@ describe('luaeval()', function()
end
it('correctly passes special dictionaries', function()
- eq({'binary', {'\n', '\n'}}, luaevalarg(sp('binary', '["\\n", "\\n"]')))
- eq({'binary', {'\n', '\n'}}, luaevalarg(sp('string', '["\\n", "\\n"]')))
+ eq({0, '\000\n\000'}, luaevalarg(sp('binary', '["\\n", "\\n"]')))
+ eq({0, '\000\n\000'}, luaevalarg(sp('string', '["\\n", "\\n"]')))
eq({0, true}, luaevalarg(sp('boolean', 1)))
eq({0, false}, luaevalarg(sp('boolean', 0)))
eq({0, NIL}, luaevalarg(sp('nil', 0)))
@@ -458,6 +453,9 @@ describe('v:lua', function()
function mymod.crashy()
nonexistent()
end
+ function mymod.whatis(value)
+ return type(value) .. ": " .. tostring(value)
+ end
function mymod.omni(findstart, base)
if findstart == 1 then
return 5
@@ -476,11 +474,28 @@ describe('v:lua', function()
eq(true, exec_lua([[return _G.val == vim.NIL]]))
eq(NIL, eval('v:lua.mymod.noisy("eval")'))
eq("hey eval", meths.get_current_line())
+ eq("string: abc", eval('v:lua.mymod.whatis(0z616263)'))
+ eq("string: ", eval('v:lua.mymod.whatis(v:_null_blob)'))
eq("Vim:E5108: Error executing lua [string \"<nvim>\"]:0: attempt to call global 'nonexistent' (a nil value)",
pcall_err(eval, 'v:lua.mymod.crashy()'))
end)
+ it('works when called as a method', function()
+ eq(123, eval('110->v:lua.foo(13)'))
+ eq(true, exec_lua([[return _G.val == nil]]))
+
+ eq(321, eval('300->v:lua.foo(21, "boop")'))
+ eq("boop", exec_lua([[return _G.val]]))
+
+ eq(NIL, eval('"there"->v:lua.mymod.noisy()'))
+ eq("hey there", meths.get_current_line())
+ eq({5, 10, 15, 20}, eval('[[1], [2, 3], [4]]->v:lua.vim.tbl_flatten()->map({_, v -> v * 5})'))
+
+ eq("Vim:E5108: Error executing lua [string \"<nvim>\"]:0: attempt to call global 'nonexistent' (a nil value)",
+ pcall_err(eval, '"huh?"->v:lua.mymod.crashy()'))
+ end)
+
it('works in :call', function()
command(":call v:lua.mymod.noisy('command')")
eq("hey command", meths.get_current_line())
@@ -518,8 +533,15 @@ describe('v:lua', function()
eq("Vim:E15: Invalid expression: v:['lua'].foo()", pcall_err(eval, "v:['lua'].foo()"))
eq("Vim(call):E461: Illegal variable name: v:['lua']", pcall_err(command, "call v:['lua'].baar()"))
+ eq("Vim:E117: Unknown function: v:lua", pcall_err(eval, "v:lua()"))
eq("Vim(let):E46: Cannot change read-only variable \"v:['lua']\"", pcall_err(command, "let v:['lua'] = 'xx'"))
eq("Vim(let):E46: Cannot change read-only variable \"v:lua\"", pcall_err(command, "let v:lua = 'xx'"))
+
+ eq("Vim:E107: Missing parentheses: v:lua.func", pcall_err(eval, "'bad'->v:lua.func"))
+ eq("Vim:E274: No white space allowed before parenthesis", pcall_err(eval, "'bad'->v:lua.func ()"))
+ eq("Vim:E107: Missing parentheses: v:lua", pcall_err(eval, "'bad'->v:lua"))
+ eq("Vim:E117: Unknown function: v:lua", pcall_err(eval, "'bad'->v:lua()"))
+ eq("Vim:E15: Invalid expression: v:lua.()", pcall_err(eval, "'bad'->v:lua.()"))
end)
end)
diff --git a/test/functional/lua/mpack_spec.lua b/test/functional/lua/mpack_spec.lua
new file mode 100644
index 0000000000..ef693f01f3
--- /dev/null
+++ b/test/functional/lua/mpack_spec.lua
@@ -0,0 +1,23 @@
+-- Test suite for testing interactions with API bindings
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local eq = helpers.eq
+local exec_lua = helpers.exec_lua
+
+describe('lua vim.mpack', function()
+ before_each(clear)
+ it('can pack vim.NIL', function()
+ eq({true, true, true, true}, exec_lua [[
+ local var = vim.mpack.unpack(vim.mpack.pack({33, vim.NIL, 77}))
+ return {var[1]==33, var[2]==vim.NIL, var[3]==77, var[4]==nil}
+ ]])
+ end)
+
+ it('can pack vim.empty_dict()', function()
+ eq({{{}, "foo", {}}, true, false}, exec_lua [[
+ local var = vim.mpack.unpack(vim.mpack.pack({{}, "foo", vim.empty_dict()}))
+ return {var, vim.tbl_islist(var[1]), vim.tbl_islist(var[3])}
+ ]])
+ end)
+end)
diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua
index 267c759faf..636479b81f 100644
--- a/test/functional/lua/overrides_spec.lua
+++ b/test/functional/lua/overrides_spec.lua
@@ -11,8 +11,9 @@ local meths = helpers.meths
local iswin = helpers.iswin
local command = helpers.command
local write_file = helpers.write_file
-local redir_exec = helpers.redir_exec
+local exec_capture = helpers.exec_capture
local exec_lua = helpers.exec_lua
+local pcall_err = helpers.pcall_err
local screen
@@ -36,11 +37,11 @@ describe('print', function()
write_file(fname, 'print("abc")')
eq('\nabc', funcs.execute('luafile ' .. fname))
- eq('\nabc', redir_exec('lua print("abc")'))
- eq('\nabc', redir_exec('luado print("abc")'))
- eq('\nabc', redir_exec('call luaeval("print(\'abc\')")'))
+ eq('abc', exec_capture('lua print("abc")'))
+ eq('abc', exec_capture('luado print("abc")'))
+ eq('abc', exec_capture('call luaeval("print(\'abc\')")'))
write_file(fname, 'print("abc")')
- eq('\nabc', redir_exec('luafile ' .. fname))
+ eq('abc', exec_capture('luafile ' .. fname))
end)
it('handles errors in __tostring', function()
write_file(fname, [[
@@ -51,30 +52,30 @@ describe('print', function()
v_abcerr = setmetatable({}, meta_abcerr)
v_tblout = setmetatable({}, meta_tblout)
]])
- eq('', redir_exec('luafile ' .. fname))
+ eq('', exec_capture('luafile ' .. fname))
-- TODO(bfredl): these look weird, print() should not use "E5114:" style errors..
- eq('\nE5108: Error executing lua E5114: Error while converting print argument #2: [NULL]',
- redir_exec('lua print("foo", v_nilerr, "bar")'))
- eq('\nE5108: Error executing lua E5114: Error while converting print argument #2: Xtest-functional-lua-overrides-luafile:2: abc',
- redir_exec('lua print("foo", v_abcerr, "bar")'))
- eq('\nE5108: Error executing lua E5114: Error while converting print argument #2: <Unknown error: lua_tolstring returned NULL for tostring result>',
- redir_exec('lua print("foo", v_tblout, "bar")'))
+ eq('Vim(lua):E5108: Error executing lua E5114: Error while converting print argument #2: [NULL]',
+ pcall_err(command, 'lua print("foo", v_nilerr, "bar")'))
+ eq('Vim(lua):E5108: Error executing lua E5114: Error while converting print argument #2: Xtest-functional-lua-overrides-luafile:0: abc',
+ pcall_err(command, 'lua print("foo", v_abcerr, "bar")'))
+ eq('Vim(lua):E5108: Error executing lua E5114: Error while converting print argument #2: <Unknown error: lua_tolstring returned NULL for tostring result>',
+ pcall_err(command, 'lua print("foo", v_tblout, "bar")'))
end)
it('prints strings with NULs and NLs correctly', function()
meths.set_option('more', true)
- eq('\nabc ^@ def\nghi^@^@^@jkl\nTEST\n\n\nT\n',
- redir_exec([[lua print("abc \0 def\nghi\0\0\0jkl\nTEST\n\n\nT\n")]]))
- eq('\nabc ^@ def\nghi^@^@^@jkl\nTEST\n\n\nT^@',
- redir_exec([[lua print("abc \0 def\nghi\0\0\0jkl\nTEST\n\n\nT\0")]]))
- eq('\nT^@', redir_exec([[lua print("T\0")]]))
- eq('\nT\n', redir_exec([[lua print("T\n")]]))
+ eq('abc ^@ def\nghi^@^@^@jkl\nTEST\n\n\nT\n',
+ exec_capture([[lua print("abc \0 def\nghi\0\0\0jkl\nTEST\n\n\nT\n")]]))
+ eq('abc ^@ def\nghi^@^@^@jkl\nTEST\n\n\nT^@',
+ exec_capture([[lua print("abc \0 def\nghi\0\0\0jkl\nTEST\n\n\nT\0")]]))
+ eq('T^@', exec_capture([[lua print("T\0")]]))
+ eq('T\n', exec_capture([[lua print("T\n")]]))
end)
it('prints empty strings correctly', function()
-- Regression: first test used to crash
- eq('', redir_exec('lua print("")'))
- eq('\n def', redir_exec('lua print("", "def")'))
- eq('\nabc ', redir_exec('lua print("abc", "")'))
- eq('\nabc def', redir_exec('lua print("abc", "", "def")'))
+ eq('', exec_capture('lua print("")'))
+ eq(' def', exec_capture('lua print("", "def")'))
+ eq('abc ', exec_capture('lua print("abc", "")'))
+ eq('abc def', exec_capture('lua print("abc", "", "def")'))
end)
it('defers printing in luv event handlers', function()
exec_lua([[
@@ -97,7 +98,7 @@ describe('print', function()
vim.api.nvim_command("sleep 1m") -- force deferred event processing
end
]], (iswin() and "timeout 1") or "sleep 0.1")
- eq('\nvery slow\nvery fast',redir_exec('lua test()'))
+ eq('very slow\nvery fast', exec_capture('lua test()'))
end)
end)
diff --git a/test/functional/lua/ui_spec.lua b/test/functional/lua/ui_spec.lua
new file mode 100644
index 0000000000..94f1b5840b
--- /dev/null
+++ b/test/functional/lua/ui_spec.lua
@@ -0,0 +1,46 @@
+local helpers = require('test.functional.helpers')(after_each)
+local eq = helpers.eq
+local exec_lua = helpers.exec_lua
+local clear = helpers.clear
+
+describe('vim.ui', function()
+ before_each(function()
+ clear()
+ end)
+
+
+ describe('select', function()
+ it('can select an item', function()
+ local result = exec_lua[[
+ local items = {
+ { name = 'Item 1' },
+ { name = 'Item 2' },
+ }
+ local opts = {
+ format_item = function(entry)
+ return entry.name
+ end
+ }
+ local selected
+ local cb = function(item)
+ selected = item
+ end
+ -- inputlist would require input and block the test;
+ local choices
+ vim.fn.inputlist = function(x)
+ choices = x
+ return 1
+ end
+ vim.ui.select(items, opts, cb)
+ vim.wait(100, function() return selected ~= nil end)
+ return {selected, choices}
+ ]]
+ eq({ name = 'Item 1' }, result[1])
+ eq({
+ 'Select one of:',
+ '1: Item 1',
+ '2: Item 2',
+ }, result[2])
+ end)
+ end)
+end)
diff --git a/test/functional/lua/uri_spec.lua b/test/functional/lua/uri_spec.lua
index f782769935..052a8a1ecd 100644
--- a/test/functional/lua/uri_spec.lua
+++ b/test/functional/lua/uri_spec.lua
@@ -53,12 +53,18 @@ describe('URI methods', function()
describe('uri to filepath', function()
describe('decode Unix file path', function()
- it('file path includes only ascii charactors', function()
+ it('file path includes only ascii characters', function()
exec_lua("uri = 'file:///Foo/Bar/Baz.txt'")
eq('/Foo/Bar/Baz.txt', exec_lua("return vim.uri_to_fname(uri)"))
end)
+ it('local file path without hostname', function()
+ exec_lua("uri = 'file:/Foo/Bar/Baz.txt'")
+
+ eq('/Foo/Bar/Baz.txt', exec_lua("return vim.uri_to_fname(uri)"))
+ end)
+
it('file path including white space', function()
exec_lua("uri = 'file:///Foo%20/Bar/Baz.txt'")
@@ -85,6 +91,15 @@ describe('URI methods', function()
eq('C:\\Foo\\Bar\\Baz.txt', exec_lua(test_case))
end)
+ it('local file path without hostname', function()
+ local test_case = [[
+ local uri = 'file:/C:/Foo/Bar/Baz.txt'
+ return vim.uri_to_fname(uri)
+ ]]
+
+ eq('C:\\Foo\\Bar\\Baz.txt', exec_lua(test_case))
+ end)
+
it('file path includes only ascii charactors with encoded colon character', function()
local test_case = [[
local uri = 'file:///C%3A/Foo/Bar/Baz.txt'
@@ -125,6 +140,12 @@ describe('URI methods', function()
return vim.uri_to_fname('JDT://content/%5C/')
]])
end)
+
+ it('uri_to_fname returns non-file scheme URI without authority unchanged', function()
+ eq('zipfile:/path/to/archive.zip%3A%3Afilename.txt', exec_lua [[
+ return vim.uri_to_fname('zipfile:/path/to/archive.zip%3A%3Afilename.txt')
+ ]])
+ end)
end)
describe('decode URI without scheme', function()
@@ -146,5 +167,14 @@ describe('URI methods', function()
]], uri)
eq(uri, exec_lua(test_case))
end)
+
+ it('uri_to_bufnr & uri_from_bufnr returns original uri for non-file uris without authority', function()
+ local uri = 'zipfile:/path/to/archive.zip%3A%3Afilename.txt'
+ local test_case = string.format([[
+ local uri = '%s'
+ return vim.uri_from_bufnr(vim.uri_to_bufnr(uri))
+ ]], uri)
+ eq(uri, exec_lua(test_case))
+ end)
end)
end)
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index eff838aea3..a066cfbc10 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -6,6 +6,7 @@ local funcs = helpers.funcs
local meths = helpers.meths
local dedent = helpers.dedent
local command = helpers.command
+local insert = helpers.insert
local clear = helpers.clear
local eq = helpers.eq
local ok = helpers.ok
@@ -17,6 +18,7 @@ local matches = helpers.matches
local source = helpers.source
local NIL = helpers.NIL
local retry = helpers.retry
+local next_msg = helpers.next_msg
before_each(clear)
@@ -603,6 +605,31 @@ describe('lua stdlib', function()
return vim.tbl_islist(c) and count == 0
]]))
+ eq(exec_lua([[
+ local a = { a = { b = 1 } }
+ local b = { a = {} }
+ return vim.tbl_deep_extend("force", a, b)
+ ]]), {a = {b = 1}})
+
+ eq(exec_lua([[
+ local a = { a = 123 }
+ local b = { a = { b = 1} }
+ return vim.tbl_deep_extend("force", a, b)
+ ]]), {a = {b = 1}})
+
+ ok(exec_lua([[
+ local a = { a = {[2] = 3} }
+ local b = { a = {[3] = 3} }
+ local c = vim.tbl_deep_extend("force", a, b)
+ return vim.deep_equal(c, {a = {[3] = 3}})
+ ]]))
+
+ eq(exec_lua([[
+ local a = { a = { b = 1} }
+ local b = { a = 123 }
+ return vim.tbl_deep_extend("force", a, b)
+ ]]), {a = 123 })
+
eq('Error executing lua: vim/shared.lua:0: invalid "behavior": nil',
pcall_err(exec_lua, [[
return vim.tbl_deep_extend()
@@ -712,7 +739,7 @@ describe('lua stdlib', function()
eq({NIL, NIL}, exec_lua([[return vim.fn.Nilly()]]))
-- error handling
- eq({false, 'Vim:E714: List required'}, exec_lua([[return {pcall(vim.fn.add, "aa", "bb")}]]))
+ eq({false, 'Vim:E897: List or Blob required'}, exec_lua([[return {pcall(vim.fn.add, "aa", "bb")}]]))
end)
it('vim.fn should error when calling API function', function()
@@ -1332,12 +1359,12 @@ describe('lua stdlib', function()
it('should work for key-value pair options', function()
local listchars = exec_lua [[
- vim.opt.listchars = "tab:>~,space:_"
+ vim.opt.listchars = "tab:> ,space:_"
return vim.opt.listchars:get()
]]
eq({
- tab = ">~",
+ tab = "> ",
space = "_",
}, listchars)
end)
@@ -1855,7 +1882,7 @@ describe('lua stdlib', function()
end)
it('vim.region', function()
- helpers.insert(helpers.dedent( [[
+ insert(helpers.dedent( [[
text tααt tααt text
text tαxt txtα tex
text tαxt tαxt
@@ -1863,65 +1890,67 @@ describe('lua stdlib', function()
eq({5,15}, exec_lua[[ return vim.region(0,{1,5},{1,14},'v',true)[1] ]])
end)
- describe('vim.execute_on_keystroke', function()
- it('should keep track of keystrokes', function()
- helpers.insert([[hello world ]])
+ describe('vim.on_key', function()
+ it('tracks keystrokes', function()
+ insert([[hello world ]])
exec_lua [[
- KeysPressed = {}
+ keys = {}
- vim.register_keystroke_callback(function(buf)
+ vim.on_key(function(buf)
if buf:byte() == 27 then
buf = "<ESC>"
end
- table.insert(KeysPressed, buf)
+ table.insert(keys, buf)
end)
]]
- helpers.insert([[next 🤦 lines å ]])
+ insert([[next 🤦 lines å ]])
-- It has escape in the keys pressed
- eq('inext 🤦 lines å <ESC>', exec_lua [[return table.concat(KeysPressed, '')]])
+ eq('inext 🤦 lines å <ESC>', exec_lua [[return table.concat(keys, '')]])
end)
- it('should allow removing trackers.', function()
- helpers.insert([[hello world]])
+ it('allows removing on_key listeners', function()
+ insert([[hello world]])
exec_lua [[
- KeysPressed = {}
+ keys = {}
- return vim.register_keystroke_callback(function(buf)
+ return vim.on_key(function(buf)
if buf:byte() == 27 then
buf = "<ESC>"
end
- table.insert(KeysPressed, buf)
+ table.insert(keys, buf)
end, vim.api.nvim_create_namespace("logger"))
]]
- helpers.insert([[next lines]])
+ insert([[next lines]])
- exec_lua("vim.register_keystroke_callback(nil, vim.api.nvim_create_namespace('logger'))")
+ eq(1, exec_lua('return vim.on_key()'))
+ exec_lua("vim.on_key(nil, vim.api.nvim_create_namespace('logger'))")
+ eq(0, exec_lua('return vim.on_key()'))
- helpers.insert([[more lines]])
+ insert([[more lines]])
-- It has escape in the keys pressed
- eq('inext lines<ESC>', exec_lua [[return table.concat(KeysPressed, '')]])
+ eq('inext lines<ESC>', exec_lua [[return table.concat(keys, '')]])
end)
- it('should not call functions that error again.', function()
- helpers.insert([[hello world]])
+ it('skips any function that caused an error', function()
+ insert([[hello world]])
exec_lua [[
- KeysPressed = {}
+ keys = {}
- return vim.register_keystroke_callback(function(buf)
+ return vim.on_key(function(buf)
if buf:byte() == 27 then
buf = "<ESC>"
end
- table.insert(KeysPressed, buf)
+ table.insert(keys, buf)
if buf == 'l' then
error("Dumb Error")
@@ -1929,35 +1958,30 @@ describe('lua stdlib', function()
end)
]]
- helpers.insert([[next lines]])
- helpers.insert([[more lines]])
+ insert([[next lines]])
+ insert([[more lines]])
-- Only the first letter gets added. After that we remove the callback
- eq('inext l', exec_lua [[ return table.concat(KeysPressed, '') ]])
+ eq('inext l', exec_lua [[ return table.concat(keys, '') ]])
end)
- it('should process mapped keys, not unmapped keys', function()
+ it('processes mapped keys, not unmapped keys', function()
exec_lua [[
- KeysPressed = {}
+ keys = {}
vim.cmd("inoremap hello world")
- vim.register_keystroke_callback(function(buf)
+ vim.on_key(function(buf)
if buf:byte() == 27 then
buf = "<ESC>"
end
- table.insert(KeysPressed, buf)
+ table.insert(keys, buf)
end)
]]
+ insert("hello")
- helpers.insert("hello")
-
- local next_status = exec_lua [[
- return table.concat(KeysPressed, '')
- ]]
-
- eq("iworld<ESC>", next_status)
+ eq('iworld<ESC>', exec_lua[[return table.concat(keys, '')]])
end)
end)
@@ -2153,6 +2177,24 @@ describe('lua stdlib', function()
end)
end)
+ describe('vim.schedule_wrap', function()
+ it('preserves argument lists', function()
+ exec_lua [[
+ local fun = vim.schedule_wrap(function(kling, klang, klonk)
+ vim.rpcnotify(1, 'mayday_mayday', {a=kling, b=klang, c=klonk})
+ end)
+ fun("BOB", nil, "MIKE")
+ ]]
+ eq({'notification', 'mayday_mayday', {{a='BOB', c='MIKE'}}}, next_msg())
+
+ -- let's gooooo
+ exec_lua [[
+ vim.schedule_wrap(function(...) vim.rpcnotify(1, 'boogalo', select('#', ...)) end)(nil,nil,nil,nil)
+ ]]
+ eq({'notification', 'boogalo', {4}}, next_msg())
+ end)
+ end)
+
describe('vim.api.nvim_buf_call', function()
it('can access buf options', function()
local buf1 = meths.get_current_buf()
diff --git a/test/functional/lua/xdiff_spec.lua b/test/functional/lua/xdiff_spec.lua
new file mode 100644
index 0000000000..4f28f84c01
--- /dev/null
+++ b/test/functional/lua/xdiff_spec.lua
@@ -0,0 +1,112 @@
+local helpers = require('test.functional.helpers')(after_each)
+local clear = helpers.clear
+local exec_lua = helpers.exec_lua
+local eq = helpers.eq
+local pcall_err = helpers.pcall_err
+
+describe('xdiff bindings', function()
+ before_each(function()
+ clear()
+ end)
+
+ describe('can diff text', function()
+ before_each(function()
+ exec_lua[[
+ a1 = 'Hello\n'
+ b1 = 'Helli\n'
+
+ a2 = 'Hello\nbye\nfoo\n'
+ b2 = 'Helli\nbye\nbar\nbaz\n'
+ ]]
+ end)
+
+ it('with no callback', function()
+
+ eq(
+ table.concat({
+ '@@ -1 +1 @@',
+ '-Hello',
+ '+Helli',
+ ''
+ }, '\n'),
+ exec_lua("return vim.diff(a1, b1)")
+ )
+
+ eq(
+ table.concat({
+ '@@ -1 +1 @@',
+ '-Hello',
+ '+Helli',
+ '@@ -3 +3,2 @@',
+ '-foo',
+ '+bar',
+ '+baz',
+ ''
+ }, '\n'),
+ exec_lua("return vim.diff(a2, b2)")
+ )
+
+ end)
+
+ it('with callback', function()
+ exec_lua([[on_hunk = function(sa, ca, sb, cb)
+ exp[#exp+1] = {sa, ca, sb, cb}
+ end]])
+
+ eq({{1, 1, 1, 1}}, exec_lua[[
+ exp = {}
+ assert(vim.diff(a1, b1, {on_hunk = on_hunk}) == nil)
+ return exp
+ ]])
+
+ eq({{1, 1, 1, 1}, {3, 1, 3, 2}}, exec_lua[[
+ exp = {}
+ assert(vim.diff(a2, b2, {on_hunk = on_hunk}) == nil)
+ return exp
+ ]])
+
+ -- gives higher precedence to on_hunk over result_type
+ eq({{1, 1, 1, 1}, {3, 1, 3, 2}}, exec_lua[[
+ exp = {}
+ assert(vim.diff(a2, b2, {on_hunk = on_hunk, result_type='indices'}) == nil)
+ return exp
+ ]])
+ end)
+
+ it('with error callback', function()
+ exec_lua([[on_hunk = function(sa, ca, sb, cb)
+ error('ERROR1')
+ end]])
+
+ eq([[Error executing lua: [string "<nvim>"]:0: error running function on_hunk: [string "<nvim>"]:0: ERROR1]],
+ pcall_err(exec_lua, [[vim.diff(a1, b1, {on_hunk = on_hunk})]]))
+ end)
+
+ it('with hunk_lines', function()
+ eq({{1, 1, 1, 1}},
+ exec_lua([[return vim.diff(a1, b1, {result_type = 'indices'})]]))
+
+ eq({{1, 1, 1, 1}, {3, 1, 3, 2}},
+ exec_lua([[return vim.diff(a2, b2, {result_type = 'indices'})]]))
+ end)
+
+ end)
+
+ it('can handle bad args', function()
+ eq([[Error executing lua: [string "<nvim>"]:0: Expected at least 2 arguments]],
+ pcall_err(exec_lua, [[vim.diff('a')]]))
+
+ eq([[Error executing lua: [string "<nvim>"]:0: bad argument #1 to 'diff' (expected string)]],
+ pcall_err(exec_lua, [[vim.diff(1, 2)]]))
+
+ eq([[Error executing lua: [string "<nvim>"]:0: bad argument #3 to 'diff' (expected table)]],
+ pcall_err(exec_lua, [[vim.diff('a', 'b', true)]]))
+
+ eq([[Error executing lua: [string "<nvim>"]:0: unexpected key: bad_key]],
+ pcall_err(exec_lua, [[vim.diff('a', 'b', { bad_key = true })]]))
+
+ eq([[Error executing lua: [string "<nvim>"]:0: on_hunk is not a function]],
+ pcall_err(exec_lua, [[vim.diff('a', 'b', { on_hunk = true })]]))
+
+ end)
+end)
diff --git a/test/functional/normal/meta_key_spec.lua b/test/functional/normal/meta_key_spec.lua
deleted file mode 100644
index 9f9fad67d2..0000000000
--- a/test/functional/normal/meta_key_spec.lua
+++ /dev/null
@@ -1,22 +0,0 @@
-local helpers = require('test.functional.helpers')(after_each)
-local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
-local command = helpers.command
-local expect = helpers.expect
-
-describe('meta-keys-in-normal-mode', function()
- before_each(function()
- clear()
- end)
-
- it('ALT/META', function()
- -- Unmapped ALT-chords behave as Esc+c
- insert('hello')
- feed('0<A-x><M-x>')
- expect('llo')
- -- Mapped ALT-chord behaves as mapped.
- command('nnoremap <M-l> Ameta-l<Esc>')
- command('nnoremap <A-j> Aalt-j<Esc>')
- feed('<A-j><M-l>')
- expect('lloalt-jmeta-l')
- end)
-end)
diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua
index eb5e284385..6620c9acef 100644
--- a/test/functional/options/defaults_spec.lua
+++ b/test/functional/options/defaults_spec.lua
@@ -2,6 +2,7 @@ local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
+local assert_alive = helpers.assert_alive
local meths = helpers.meths
local command = helpers.command
local clear = helpers.clear
@@ -354,13 +355,13 @@ describe('XDG-based defaults', function()
.. ',' .. root_path .. ('/a'):rep(2048) .. '/nvim/after'
.. ',' .. root_path .. ('/x'):rep(4096) .. '/nvim/after'
):gsub('\\', '/')), (meths.get_option('runtimepath')):gsub('\\', '/'))
- eq('.,' .. root_path .. ('/X'):rep(4096).. '/' .. data_dir .. '/backup',
+ eq('.,' .. root_path .. ('/X'):rep(4096).. '/' .. data_dir .. '/backup//',
(meths.get_option('backupdir'):gsub('\\', '/')))
eq(root_path .. ('/X'):rep(4096) .. '/' .. data_dir .. '/swap//',
(meths.get_option('directory')):gsub('\\', '/'))
- eq(root_path .. ('/X'):rep(4096) .. '/' .. data_dir .. '/undo',
+ eq(root_path .. ('/X'):rep(4096) .. '/' .. data_dir .. '/undo//',
(meths.get_option('undodir')):gsub('\\', '/'))
- eq(root_path .. ('/X'):rep(4096) .. '/' .. data_dir .. '/view',
+ eq(root_path .. ('/X'):rep(4096) .. '/' .. data_dir .. '/view//',
(meths.get_option('viewdir')):gsub('\\', '/'))
end)
end)
@@ -404,13 +405,13 @@ describe('XDG-based defaults', function()
.. ',$XDG_DATA_DIRS/nvim/after'
.. ',$XDG_DATA_HOME/nvim/after'
):gsub('\\', '/')), (meths.get_option('runtimepath')):gsub('\\', '/'))
- eq(('.,$XDG_CONFIG_HOME/' .. data_dir .. '/backup'),
+ eq(('.,$XDG_CONFIG_HOME/' .. data_dir .. '/backup//'),
meths.get_option('backupdir'):gsub('\\', '/'))
eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/swap//'),
meths.get_option('directory'):gsub('\\', '/'))
- eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/undo'),
+ eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/undo//'),
meths.get_option('undodir'):gsub('\\', '/'))
- eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/view'),
+ eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/view//'),
meths.get_option('viewdir'):gsub('\\', '/'))
meths.command('set all&')
eq(('$XDG_DATA_HOME/nvim'
@@ -424,13 +425,13 @@ describe('XDG-based defaults', function()
.. ',$XDG_DATA_DIRS/nvim/after'
.. ',$XDG_DATA_HOME/nvim/after'
):gsub('\\', '/'), (meths.get_option('runtimepath')):gsub('\\', '/'))
- eq(('.,$XDG_CONFIG_HOME/' .. data_dir .. '/backup'),
+ eq(('.,$XDG_CONFIG_HOME/' .. data_dir .. '/backup//'),
meths.get_option('backupdir'):gsub('\\', '/'))
eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/swap//'),
meths.get_option('directory'):gsub('\\', '/'))
- eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/undo'),
+ eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/undo//'),
meths.get_option('undodir'):gsub('\\', '/'))
- eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/view'),
+ eq(('$XDG_CONFIG_HOME/' .. data_dir .. '/view//'),
meths.get_option('viewdir'):gsub('\\', '/'))
end)
end)
@@ -483,13 +484,13 @@ describe('XDG-based defaults', function()
.. ',\\,-\\,-\\,' .. path_sep ..'nvim' .. path_sep ..'after'
.. ',\\, \\, \\,' .. path_sep ..'nvim' .. path_sep ..'after'
), meths.get_option('runtimepath'))
- eq('.,\\,=\\,=\\,' .. path_sep .. data_dir .. '' .. path_sep ..'backup',
+ eq('.,\\,=\\,=\\,' .. path_sep .. data_dir .. '' .. path_sep ..'backup' .. (path_sep):rep(2),
meths.get_option('backupdir'))
eq('\\,=\\,=\\,' .. path_sep ..'' .. data_dir .. '' .. path_sep ..'swap' .. (path_sep):rep(2),
meths.get_option('directory'))
- eq('\\,=\\,=\\,' .. path_sep ..'' .. data_dir .. '' .. path_sep ..'undo',
+ eq('\\,=\\,=\\,' .. path_sep ..'' .. data_dir .. '' .. path_sep ..'undo' .. (path_sep):rep(2),
meths.get_option('undodir'))
- eq('\\,=\\,=\\,' .. path_sep ..'' .. data_dir .. '' .. path_sep ..'view',
+ eq('\\,=\\,=\\,' .. path_sep ..'' .. data_dir .. '' .. path_sep ..'view' .. (path_sep):rep(2),
meths.get_option('viewdir'))
end)
end)
@@ -510,8 +511,7 @@ describe('stdpath()', function()
eq(datadir, funcs.fnamemodify(funcs.stdpath('data'), ':t'))
eq('table', type(funcs.stdpath('config_dirs')))
eq('table', type(funcs.stdpath('data_dirs')))
- -- Check for crash. #8393
- eq(2, eval('1+1'))
+ assert_alive() -- Check for crash. #8393
end)
context('returns a String', function()
diff --git a/test/functional/options/tabstop_spec.lua b/test/functional/options/tabstop_spec.lua
index dc3ba38438..e34f678650 100644
--- a/test/functional/options/tabstop_spec.lua
+++ b/test/functional/options/tabstop_spec.lua
@@ -1,9 +1,8 @@
local helpers = require('test.functional.helpers')(after_each)
+local assert_alive = helpers.assert_alive
local clear = helpers.clear
local feed = helpers.feed
-local eq = helpers.eq
-local eval = helpers.eval
describe("'tabstop' option", function()
before_each(function()
@@ -18,6 +17,6 @@ describe("'tabstop' option", function()
-- Set 'tabstop' to a very high value.
-- Use feed(), not command(), to provoke crash.
feed(':set tabstop=3000000000<CR>')
- eq(2, eval("1+1")) -- Still alive?
+ assert_alive()
end)
end)
diff --git a/test/functional/plugin/lsp/codelens_spec.lua b/test/functional/plugin/lsp/codelens_spec.lua
index e09d93f7cc..c8b75e65fc 100644
--- a/test/functional/plugin/lsp/codelens_spec.lua
+++ b/test/functional/plugin/lsp/codelens_spec.lua
@@ -11,7 +11,7 @@ describe('vim.lsp.codelens', function()
after_each(helpers.clear)
it('on_codelens_stores_and_displays_lenses', function()
- local fake_uri = "file://fake/uri"
+ local fake_uri = "file:///fake/uri"
local bufnr = exec_lua([[
fake_uri = ...
local bufnr = vim.uri_to_bufnr(fake_uri)
@@ -32,7 +32,7 @@ describe('vim.lsp.codelens', function()
command = { title = 'Lens1', command = 'Dummy' }
},
}
- vim.lsp.codelens.on_codelens(nil, 'textDocument/codeLens', lenses, 1, bufnr)
+ vim.lsp.codelens.on_codelens(nil, lenses, {method='textDocument/codeLens', client_id=1, bufnr=bufnr})
]], bufnr)
local stored_lenses = exec_lua('return vim.lsp.codelens.get(...)', bufnr)
@@ -58,5 +58,33 @@ describe('vim.lsp.codelens', function()
]], bufnr)
eq({[1] = {'Lens1', 'LspCodeLens'}}, virtual_text_chunks)
+
+ end)
+ it('codelens uses client commands', function()
+ local fake_uri = "file:///fake/uri"
+ local cmd = exec_lua([[
+ fake_uri = ...
+ local bufnr = vim.uri_to_bufnr(fake_uri)
+ vim.fn.bufload(bufnr)
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {'One line'})
+ local lenses = {
+ {
+ range = {
+ start = { line = 0, character = 0, },
+ ['end'] = { line = 0, character = 8 }
+ },
+ command = { title = 'Lens1', command = 'Dummy' }
+ },
+ }
+ vim.lsp.codelens.on_codelens(nil, lenses, {method='textDocument/codeLens', client_id=1, bufnr=bufnr})
+ local cmd_called = nil
+ vim.lsp.commands['Dummy'] = function(command)
+ cmd_called = command
+ end
+ vim.api.nvim_set_current_buf(bufnr)
+ vim.lsp.codelens.run()
+ return cmd_called
+ ]], fake_uri)
+ eq({ command = 'Dummy', title = 'Lens1' }, cmd)
end)
end)
diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua
index 962028e7e1..243ad6bdb8 100644
--- a/test/functional/plugin/lsp/diagnostic_spec.lua
+++ b/test/functional/plugin/lsp/diagnostic_spec.lua
@@ -9,7 +9,10 @@ describe('vim.lsp.diagnostic', function()
local fake_uri
before_each(function()
- clear()
+ clear {env={
+ NVIM_LUA_NOTRACK="1";
+ VIMRUNTIME=os.getenv"VIMRUNTIME";
+ }}
exec_lua [[
require('vim.lsp')
@@ -44,12 +47,12 @@ describe('vim.lsp.diagnostic', function()
count_of_extmarks_for_client = function(bufnr, client_id)
return #vim.api.nvim_buf_get_extmarks(
- bufnr, vim.lsp.diagnostic._get_diagnostic_namespace(client_id), 0, -1, {}
+ bufnr, vim.lsp.diagnostic.get_namespace(client_id), 0, -1, {}
)
end
]]
- fake_uri = "file://fake/uri"
+ fake_uri = "file:///fake/uri"
exec_lua([[
fake_uri = ...
@@ -86,39 +89,6 @@ describe('vim.lsp.diagnostic', function()
eq(2, #result[1])
eq('Diagnostic #1', result[1][1].message)
end)
- it('Can convert diagnostic to quickfix items format', function()
- local bufnr = exec_lua([[
- local fake_uri = ...
- return vim.uri_to_bufnr(fake_uri)
- ]], fake_uri)
- local result = exec_lua([[
- local bufnr = ...
- vim.lsp.diagnostic.save(
- {
- make_error('Diagnostic #1', 1, 1, 1, 1),
- make_error('Diagnostic #2', 2, 1, 2, 1),
- }, bufnr, 1
- )
- return vim.lsp.util.diagnostics_to_items(vim.lsp.diagnostic.get_all())
- ]], bufnr)
- local expected = {
- {
- bufnr = bufnr,
- col = 2,
- lnum = 2,
- text = 'Diagnostic #1',
- type = 'E'
- },
- {
- bufnr = bufnr,
- col = 2,
- lnum = 3,
- text = 'Diagnostic #2',
- type = 'E'
- },
- }
- eq(expected, result)
- end)
it('should be able to save and count a single client error', function()
eq(1, exec_lua [[
vim.lsp.diagnostic.save(
@@ -205,8 +175,8 @@ describe('vim.lsp.diagnostic', function()
make_warning("Warning 1", 2, 1, 2, 5),
}
- vim.lsp.diagnostic.on_publish_diagnostics(nil, nil, { uri = fake_uri, diagnostics = server_1_diags }, 1)
- vim.lsp.diagnostic.on_publish_diagnostics(nil, nil, { uri = fake_uri, diagnostics = server_2_diags }, 2)
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, { uri = fake_uri, diagnostics = server_1_diags }, {client_id=1})
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, { uri = fake_uri, diagnostics = server_2_diags }, {client_id=2})
return {
vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Error", 1),
vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Warning", 2),
@@ -218,7 +188,7 @@ describe('vim.lsp.diagnostic', function()
-- Clear diagnostics from server 1, and make sure we have the right amount of stuff for client 2
eq({1, 1, 2, 0, 2}, exec_lua [[
- vim.lsp.diagnostic.clear(diagnostic_bufnr, 1)
+ vim.lsp.diagnostic.disable(diagnostic_bufnr, 1)
return {
vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Error", 1),
vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Warning", 2),
@@ -230,7 +200,7 @@ describe('vim.lsp.diagnostic', function()
-- Show diagnostics from server 1 again
eq(all_highlights, exec_lua([[
- vim.lsp.diagnostic.display(nil, diagnostic_bufnr, 1)
+ vim.lsp.diagnostic.enable(diagnostic_bufnr, 1)
return {
vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Error", 1),
vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Warning", 2),
@@ -241,6 +211,38 @@ describe('vim.lsp.diagnostic', function()
]]))
end)
+ it('should not display diagnostics when disabled', function()
+ eq({0, 2}, exec_lua [[
+ local server_1_diags = {
+ make_error("Error 1", 1, 1, 1, 5),
+ make_warning("Warning on Server 1", 2, 1, 2, 5),
+ }
+ local server_2_diags = {
+ make_warning("Warning 1", 2, 1, 2, 5),
+ }
+
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, { uri = fake_uri, diagnostics = server_1_diags }, {client_id=1})
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, { uri = fake_uri, diagnostics = server_2_diags }, {client_id=2})
+
+ vim.lsp.diagnostic.disable(diagnostic_bufnr, 1)
+
+ return {
+ count_of_extmarks_for_client(diagnostic_bufnr, 1),
+ count_of_extmarks_for_client(diagnostic_bufnr, 2),
+ }
+ ]])
+
+ eq({4, 0}, exec_lua [[
+ vim.lsp.diagnostic.enable(diagnostic_bufnr, 1)
+ vim.lsp.diagnostic.disable(diagnostic_bufnr, 2)
+
+ return {
+ count_of_extmarks_for_client(diagnostic_bufnr, 1),
+ count_of_extmarks_for_client(diagnostic_bufnr, 2),
+ }
+ ]])
+ end)
+
describe('reset', function()
it('diagnostic count is 0 and displayed diagnostics are 0 after call', function()
-- 1 Error (1)
@@ -258,8 +260,8 @@ describe('vim.lsp.diagnostic', function()
make_warning("Warning 1", 2, 1, 2, 5),
}
- vim.lsp.diagnostic.on_publish_diagnostics(nil, nil, { uri = fake_uri, diagnostics = server_1_diags }, 1)
- vim.lsp.diagnostic.on_publish_diagnostics(nil, nil, { uri = fake_uri, diagnostics = server_2_diags }, 2)
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, { uri = fake_uri, diagnostics = server_1_diags }, {client_id=1})
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, { uri = fake_uri, diagnostics = server_2_diags }, {client_id=2})
return {
vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Error", 1),
vim.lsp.diagnostic.get_count(diagnostic_bufnr, "Warning", 2),
@@ -426,6 +428,32 @@ describe('vim.lsp.diagnostic', function()
end)
end)
end)
+
+ it('maintains LSP information when translating diagnostics', function()
+ local result = exec_lua [[
+ local diagnostics = {
+ make_error("Error 1", 1, 1, 1, 5),
+ }
+
+ diagnostics[1].code = 42
+ diagnostics[1].tags = {"foo", "bar"}
+ diagnostics[1].data = "Hello world"
+
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, {
+ uri = fake_uri,
+ diagnostics = diagnostics,
+ }, {client_id=1})
+
+ return {
+ vim.diagnostic.get(diagnostic_bufnr, {lnum=1})[1],
+ vim.lsp.diagnostic.get_line_diagnostics(diagnostic_bufnr, 1)[1],
+ }
+ ]]
+ eq({code = 42, tags = {"foo", "bar"}, data = "Hello world"}, result[1].user_data.lsp)
+ eq(42, result[2].code)
+ eq({"foo", "bar"}, result[2].tags)
+ eq("Hello world", result[2].data)
+ end)
end)
describe("vim.lsp.diagnostic.get_line_diagnostics", function()
@@ -435,14 +463,14 @@ describe('vim.lsp.diagnostic', function()
it('should return all diagnostics when no severity is supplied', function()
eq(2, exec_lua [[
- vim.lsp.diagnostic.on_publish_diagnostics(nil, nil, {
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, {
uri = fake_uri,
diagnostics = {
make_error("Error 1", 1, 1, 1, 5),
make_warning("Warning on Server 1", 1, 1, 2, 5),
make_error("Error On Other Line", 2, 1, 1, 5),
}
- }, 1)
+ }, {client_id=1})
return #vim.lsp.diagnostic.get_line_diagnostics(diagnostic_bufnr, 1)
]])
@@ -450,7 +478,7 @@ describe('vim.lsp.diagnostic', function()
it('should return only requested diagnostics when severity_limit is supplied', function()
eq(2, exec_lua [[
- vim.lsp.diagnostic.on_publish_diagnostics(nil, nil, {
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, {
uri = fake_uri,
diagnostics = {
make_error("Error 1", 1, 1, 1, 5),
@@ -458,7 +486,7 @@ describe('vim.lsp.diagnostic', function()
make_information("Ignored information", 1, 1, 2, 5),
make_error("Error On Other Line", 2, 1, 1, 5),
}
- }, 1)
+ }, {client_id=1})
return #vim.lsp.diagnostic.get_line_diagnostics(diagnostic_bufnr, 1, { severity_limit = "Warning" })
]])
@@ -470,12 +498,12 @@ describe('vim.lsp.diagnostic', function()
exec_lua [[
vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
virtual_text = function() return true end,
- })(nil, nil, {
+ })(nil, {
uri = fake_uri,
diagnostics = {
make_error('Delayed Diagnostic', 4, 4, 4, 4),
}
- }, 1
+ }, {client_id=1}
)
]]
@@ -487,12 +515,12 @@ describe('vim.lsp.diagnostic', function()
exec_lua [[
vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
virtual_text = function() return false end,
- })(nil, nil, {
+ })(nil, {
uri = fake_uri,
diagnostics = {
make_error('Delayed Diagnostic', 4, 4, 4, 4),
}
- }, 1
+ }, {client_id=1}
)
]]
@@ -509,12 +537,12 @@ describe('vim.lsp.diagnostic', function()
exec_lua [[
vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
update_in_insert = false,
- })(nil, nil, {
+ })(nil, {
uri = fake_uri,
diagnostics = {
make_error('Delayed Diagnostic', 4, 4, 4, 4),
}
- }, 1
+ }, {client_id=1}
)
]]
@@ -543,20 +571,20 @@ describe('vim.lsp.diagnostic', function()
})
-- Count how many times we call display.
- SetVirtualTextOriginal = vim.lsp.diagnostic.set_virtual_text
+ SetVirtualTextOriginal = vim.diagnostic._set_virtual_text
DisplayCount = 0
- vim.lsp.diagnostic.set_virtual_text = function(...)
+ vim.diagnostic._set_virtual_text = function(...)
DisplayCount = DisplayCount + 1
return SetVirtualTextOriginal(...)
end
- PublishDiagnostics(nil, nil, {
+ PublishDiagnostics(nil, {
uri = fake_uri,
diagnostics = {
make_error('Delayed Diagnostic', 4, 4, 4, 4),
}
- }, 1
+ }, {client_id=1}
)
]]
@@ -605,12 +633,12 @@ describe('vim.lsp.diagnostic', function()
return SetVirtualTextOriginal(...)
end
- PublishDiagnostics(nil, nil, {
+ PublishDiagnostics(nil, {
uri = fake_uri,
diagnostics = {
make_error('Delayed Diagnostic', 4, 4, 4, 4),
}
- }, 1
+ }, {client_id=1}
)
]]
@@ -647,12 +675,12 @@ describe('vim.lsp.diagnostic', function()
exec_lua [[
vim.lsp.with(vim.lsp.diagnostic.on_publish_diagnostics, {
update_in_insert = true,
- })(nil, nil, {
+ })(nil, {
uri = fake_uri,
diagnostics = {
make_error('Delayed Diagnostic', 4, 4, 4, 4),
}
- }, 1
+ }, {client_id=1}
)
]]
@@ -677,17 +705,17 @@ describe('vim.lsp.diagnostic', function()
},
})
- PublishDiagnostics(nil, nil, {
+ PublishDiagnostics(nil, {
uri = fake_uri,
diagnostics = {
make_error('Delayed Diagnostic', 4, 4, 4, 4),
}
- }, 1
+ }, {client_id=1}
)
return vim.api.nvim_buf_get_extmarks(
diagnostic_bufnr,
- vim.lsp.diagnostic._get_diagnostic_namespace(1),
+ vim.lsp.diagnostic.get_namespace(1),
0,
-1,
{ details = true }
@@ -714,17 +742,17 @@ describe('vim.lsp.diagnostic', function()
end,
})
- PublishDiagnostics(nil, nil, {
+ PublishDiagnostics(nil, {
uri = fake_uri,
diagnostics = {
make_error('Delayed Diagnostic', 4, 4, 4, 4),
}
- }, 1
+ }, {client_id=1}
)
return vim.api.nvim_buf_get_extmarks(
diagnostic_bufnr,
- vim.lsp.diagnostic._get_diagnostic_namespace(1),
+ vim.lsp.diagnostic.get_namespace(1),
0,
-1,
{ details = true }
@@ -747,12 +775,12 @@ describe('vim.lsp.diagnostic', function()
},
})
- PublishDiagnostics(nil, nil, {
+ PublishDiagnostics(nil, {
uri = fake_uri,
diagnostics = {
make_warning('Delayed Diagnostic', 4, 4, 4, 4),
}
- }, 1
+ }, {client_id=1}
)
return count_of_extmarks_for_client(diagnostic_bufnr, 1)
@@ -766,6 +794,40 @@ describe('vim.lsp.diagnostic', function()
eq(1, get_extmark_count_with_severity("Warning"))
eq(1, get_extmark_count_with_severity("Hint"))
end)
+
+ it('correctly handles UTF-16 offsets', function()
+ local line = "All 💼 and no 🎉 makes Jack a dull 👦"
+ local result = exec_lua([[
+ local line = ...
+ local client_id = vim.lsp.start_client {
+ cmd_env = {
+ NVIM_LUA_NOTRACK = "1";
+ };
+ cmd = {
+ vim.v.progpath, '-es', '-u', 'NONE', '--headless'
+ };
+ offset_encoding = "utf-16";
+ }
+
+ vim.api.nvim_buf_set_lines(diagnostic_bufnr, 0, -1, false, {line})
+
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, {
+ uri = fake_uri,
+ diagnostics = {
+ make_error('UTF-16 Diagnostic', 0, 7, 0, 8),
+ }
+ }, {client_id=client_id}
+ )
+
+ local diags = vim.diagnostic.get(diagnostic_bufnr)
+ vim.lsp.stop_client(client_id)
+ vim.lsp._vim_exit_handler()
+ return diags
+ ]], line)
+ eq(1, #result)
+ eq(exec_lua([[return vim.str_byteindex(..., 7, true)]], line), result[1].col)
+ eq(exec_lua([[return vim.str_byteindex(..., 8, true)]], line), result[1].end_col)
+ end)
end)
describe('lsp.util.show_line_diagnostics', function()
@@ -838,10 +900,10 @@ describe('vim.lsp.diagnostic', function()
}
vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
- vim.lsp.diagnostic.on_publish_diagnostics(nil, nil, {
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, {
uri = fake_uri,
diagnostics = diagnostics
- }, 1
+ }, {client_id=1}
)
vim.lsp.diagnostic.set_signs(diagnostics, diagnostic_bufnr, 1)
@@ -863,13 +925,13 @@ describe('vim.lsp.diagnostic', function()
local loc_list = exec_lua [[
vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
- vim.lsp.diagnostic.on_publish_diagnostics(nil, nil, {
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, {
uri = fake_uri,
diagnostics = {
make_error('Farther Diagnostic', 4, 4, 4, 4),
make_error('Lower Diagnostic', 1, 1, 1, 1),
}
- }, 1
+ }, {client_id=1}
)
vim.lsp.diagnostic.set_loclist()
@@ -884,20 +946,20 @@ describe('vim.lsp.diagnostic', function()
local loc_list = exec_lua [[
vim.api.nvim_win_set_buf(0, diagnostic_bufnr)
- vim.lsp.diagnostic.on_publish_diagnostics(nil, nil, {
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, {
uri = fake_uri,
diagnostics = {
make_error('Lower Diagnostic', 1, 1, 1, 1),
}
- }, 1
+ }, {client_id=1}
)
- vim.lsp.diagnostic.on_publish_diagnostics(nil, nil, {
+ vim.lsp.diagnostic.on_publish_diagnostics(nil, {
uri = fake_uri,
diagnostics = {
make_warning('Farther Diagnostic', 4, 4, 4, 4),
}
- }, 2
+ }, {client_id=2}
)
vim.lsp.diagnostic.set_loclist()
diff --git a/test/functional/plugin/lsp/snippet_spec.lua b/test/functional/plugin/lsp/snippet_spec.lua
new file mode 100644
index 0000000000..4e127743eb
--- /dev/null
+++ b/test/functional/plugin/lsp/snippet_spec.lua
@@ -0,0 +1,152 @@
+local helpers = require('test.functional.helpers')(after_each)
+local snippet = require('vim.lsp._snippet')
+
+local eq = helpers.eq
+local exec_lua = helpers.exec_lua
+
+describe('vim.lsp._snippet', function()
+ before_each(helpers.clear)
+ after_each(helpers.clear)
+
+ local parse = function(...)
+ return exec_lua('return require("vim.lsp._snippet").parse(...)', ...)
+ end
+
+ it('should parse only text', function()
+ eq({
+ type = snippet.NodeType.SNIPPET,
+ children = {
+ {
+ type = snippet.NodeType.TEXT,
+ raw = 'TE\\$\\}XT',
+ esc = 'TE$}XT'
+ }
+ }
+ }, parse('TE\\$\\}XT'))
+ end)
+
+ it('should parse tabstop', function()
+ eq({
+ type = snippet.NodeType.SNIPPET,
+ children = {
+ {
+ type = snippet.NodeType.TABSTOP,
+ tabstop = 1,
+ },
+ {
+ type = snippet.NodeType.TABSTOP,
+ tabstop = 2,
+ }
+ }
+ }, parse('$1${2}'))
+ end)
+
+ it('should parse placeholders', function()
+ eq({
+ type = snippet.NodeType.SNIPPET,
+ children = {
+ {
+ type = snippet.NodeType.PLACEHOLDER,
+ tabstop = 1,
+ children = {
+ {
+ type = snippet.NodeType.PLACEHOLDER,
+ tabstop = 2,
+ children = {
+ {
+ type = snippet.NodeType.TEXT,
+ raw = 'TE\\$\\}XT',
+ esc = 'TE$}XT'
+ },
+ {
+ type = snippet.NodeType.TABSTOP,
+ tabstop = 3,
+ },
+ {
+ type = snippet.NodeType.TABSTOP,
+ tabstop = 1,
+ transform = {
+ type = snippet.NodeType.TRANSFORM,
+ pattern = 'regex',
+ option = 'i',
+ format = {
+ {
+ type = snippet.NodeType.FORMAT,
+ capture_index = 1,
+ modifier = 'upcase'
+ }
+ }
+ },
+ },
+ {
+ type = snippet.NodeType.TEXT,
+ raw = 'TE\\$\\}XT',
+ esc = 'TE$}XT'
+ },
+ }
+ }
+ }
+ },
+ }
+ }, parse('${1:${2:TE\\$\\}XT$3${1/regex/${1:/upcase}/i}TE\\$\\}XT}}'))
+ end)
+
+ it('should parse variables', function()
+ eq({
+ type = snippet.NodeType.SNIPPET,
+ children = {
+ {
+ type = snippet.NodeType.VARIABLE,
+ name = 'VAR',
+ },
+ {
+ type = snippet.NodeType.VARIABLE,
+ name = 'VAR',
+ },
+ {
+ type = snippet.NodeType.VARIABLE,
+ name = 'VAR',
+ children = {
+ {
+ type = snippet.NodeType.TABSTOP,
+ tabstop = 1,
+ }
+ }
+ },
+ {
+ type = snippet.NodeType.VARIABLE,
+ name = 'VAR',
+ transform = {
+ type = snippet.NodeType.TRANSFORM,
+ pattern = 'regex',
+ format = {
+ {
+ type = snippet.NodeType.FORMAT,
+ capture_index = 1,
+ modifier = 'upcase',
+ }
+ }
+ }
+ },
+ }
+ }, parse('$VAR${VAR}${VAR:$1}${VAR/regex/${1:/upcase}/}'))
+ end)
+
+ it('should parse choice', function()
+ eq({
+ type = snippet.NodeType.SNIPPET,
+ children = {
+ {
+ type = snippet.NodeType.CHOICE,
+ tabstop = 1,
+ items = {
+ ',',
+ '|'
+ }
+ }
+ }
+ }, parse('${1|\\,,\\||}'))
+ end)
+
+end)
+
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index 508a9f2aed..572573a3a6 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -6,6 +6,7 @@ local buf_lines = helpers.buf_lines
local dedent = helpers.dedent
local exec_lua = helpers.exec_lua
local eq = helpers.eq
+local matches = helpers.matches
local pcall_err = helpers.pcall_err
local pesc = helpers.pesc
local insert = helpers.insert
@@ -14,6 +15,7 @@ local retry = helpers.retry
local NIL = helpers.NIL
local read_file = require('test.helpers').read_file
local write_file = require('test.helpers').write_file
+local isCI = helpers.isCI
-- Use these to get access to a coroutine so that I can run async tests and use
-- yield.
@@ -216,7 +218,7 @@ describe('LSP', function()
it('should run correctly', function()
local expected_handlers = {
- {NIL, "test", {}, 1};
+ {NIL, {}, {method="test", client_id=1}};
}
test_rpc_server {
test_name = "basic_init";
@@ -241,7 +243,7 @@ describe('LSP', function()
it('should fail', function()
local expected_handlers = {
- {NIL, "test", {}, 1};
+ {NIL, {}, {method="test", client_id=1}};
}
test_rpc_server {
test_name = "basic_init";
@@ -262,15 +264,15 @@ describe('LSP', function()
end)
it('should succeed with manual shutdown', function()
- if 'openbsd' == helpers.uname() then
- pending('hangs the build on openbsd #14028, re-enable with freeze timeout #14204')
+ if isCI() then
+ pending('hangs the build on CI #14028, re-enable with freeze timeout #14204')
return
elseif helpers.skip_fragile(pending) then
return
end
local expected_handlers = {
- {NIL, "shutdown", {}, 1, NIL};
- {NIL, "test", {}, 1};
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, {}, {method="test", client_id=1}};
}
test_rpc_server {
test_name = "basic_init";
@@ -292,12 +294,12 @@ describe('LSP', function()
it('client should return settings via workspace/configuration handler', function()
local expected_handlers = {
- {NIL, "shutdown", {}, 1};
- {NIL, "workspace/configuration", { items = {
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, { items = {
{ section = "testSetting1" };
{ section = "testSetting2" };
- }}, 1};
- {NIL, "start", {}, 1};
+ }}, { method="workspace/configuration", client_id=1}};
+ {NIL, {}, {method="start", client_id=1}};
}
local client
test_rpc_server {
@@ -309,9 +311,9 @@ describe('LSP', function()
eq(0, code, "exit code", fake_lsp_logfile)
eq(0, signal, "exit signal", fake_lsp_logfile)
end;
- on_handler = function(err, method, params, client_id)
- eq(table.remove(expected_handlers), {err, method, params, client_id}, "expected handler")
- if method == 'start' then
+ on_handler = function(err, result, ctx)
+ eq(table.remove(expected_handlers), {err, result, ctx}, "expected handler")
+ if ctx.method == 'start' then
exec_lua([=[
local client = vim.lsp.get_client_by_id(TEST_RPC_CLIENT_ID)
client.config.settings = {
@@ -319,13 +321,13 @@ describe('LSP', function()
testSetting2 = false;
}]=])
end
- if method == 'workspace/configuration' then
- local result = exec_lua([=[
+ if ctx.method == 'workspace/configuration' then
+ local server_result = exec_lua([=[
local method, params = ...
- return require'vim.lsp.handlers'['workspace/configuration'](err, method, params, TEST_RPC_CLIENT_ID)]=], method, params)
- client.notify('workspace/configuration', result)
+ return require'vim.lsp.handlers'['workspace/configuration'](err, params, {method=method, client_id=TEST_RPC_CLIENT_ID})]=], ctx.method, result)
+ client.notify('workspace/configuration', server_result)
end
- if method == 'shutdown' then
+ if ctx.method == 'shutdown' then
client.stop()
end
end;
@@ -335,19 +337,19 @@ describe('LSP', function()
clear_notrace()
fake_lsp_server_setup('workspace/configuration no settings')
eq({ NIL, NIL, }, exec_lua [[
- local params = {
+ local result = {
items = {
{section = 'foo'},
{section = 'bar'},
}
}
- return vim.lsp.handlers['workspace/configuration'](nil, nil, params, TEST_RPC_CLIENT_ID)
+ return vim.lsp.handlers['workspace/configuration'](nil, result, {client_id=TEST_RPC_CLIENT_ID})
]])
end)
it('should verify capabilities sent', function()
local expected_handlers = {
- {NIL, "shutdown", {}, 1};
+ {NIL, {}, {method="shutdown", client_id=1}};
}
test_rpc_server {
test_name = "basic_check_capabilities";
@@ -371,7 +373,7 @@ describe('LSP', function()
it('client.supports_methods() should validate capabilities', function()
local expected_handlers = {
- {NIL, "shutdown", {}, 1};
+ {NIL, {}, {method="shutdown", client_id=1}};
}
test_rpc_server {
test_name = "capabilities_for_client_supports_method";
@@ -405,7 +407,7 @@ describe('LSP', function()
it('should call unsupported_method when trying to call an unsupported method', function()
local expected_handlers = {
- {NIL, "shutdown", {}, 1};
+ {NIL, {}, {method="shutdown", client_id=1}};
}
test_rpc_server {
test_name = "capabilities_for_client_supports_method";
@@ -413,7 +415,8 @@ describe('LSP', function()
exec_lua([=[
BUFFER = vim.api.nvim_get_current_buf()
lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)
- vim.lsp.handlers['textDocument/typeDefinition'] = function(err, method)
+ vim.lsp.handlers['textDocument/typeDefinition'] = function(err, result, ctx)
+ local method = ctx.method
vim.lsp._last_lsp_handler = { err = err; method = method }
end
vim.lsp._unsupported_method = function(method)
@@ -446,7 +449,7 @@ describe('LSP', function()
it('shouldn\'t call unsupported_method when no client and trying to call an unsupported method', function()
local expected_handlers = {
- {NIL, "shutdown", {}, 1};
+ {NIL, {}, {method="shutdown", client_id=1}};
}
test_rpc_server {
test_name = "capabilities_for_client_supports_method";
@@ -479,8 +482,8 @@ describe('LSP', function()
it('should not send didOpen if the buffer closes before init', function()
local expected_handlers = {
- {NIL, "shutdown", {}, 1};
- {NIL, "finish", {}, 1};
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, {}, {method="finish", client_id=1}};
}
local client
test_rpc_server {
@@ -511,9 +514,9 @@ describe('LSP', function()
eq(0, code, "exit code", fake_lsp_logfile)
eq(0, signal, "exit signal", fake_lsp_logfile)
end;
- on_handler = function(err, method, params, client_id)
- eq(table.remove(expected_handlers), {err, method, params, client_id}, "expected handler")
- if method == 'finish' then
+ on_handler = function(err, result, ctx)
+ eq(table.remove(expected_handlers), {err, result, ctx}, "expected handler")
+ if ctx.method == 'finish' then
client.stop()
end
end;
@@ -522,9 +525,9 @@ describe('LSP', function()
it('should check the body sent attaching before init', function()
local expected_handlers = {
- {NIL, "shutdown", {}, 1};
- {NIL, "finish", {}, 1};
- {NIL, "start", {}, 1};
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, {}, {method="finish", client_id=1}};
+ {NIL, {}, {method="start", client_id=1}};
}
local client
test_rpc_server {
@@ -554,12 +557,12 @@ describe('LSP', function()
eq(0, code, "exit code", fake_lsp_logfile)
eq(0, signal, "exit signal", fake_lsp_logfile)
end;
- on_handler = function(err, method, params, client_id)
- if method == 'start' then
+ on_handler = function(err, result, ctx)
+ if ctx.method == 'start' then
client.notify('finish')
end
- eq(table.remove(expected_handlers), {err, method, params, client_id}, "expected handler")
- if method == 'finish' then
+ eq(table.remove(expected_handlers), {err, result, ctx}, "expected handler")
+ if ctx.method == 'finish' then
client.stop()
end
end;
@@ -568,9 +571,9 @@ describe('LSP', function()
it('should check the body sent attaching after init', function()
local expected_handlers = {
- {NIL, "shutdown", {}, 1};
- {NIL, "finish", {}, 1};
- {NIL, "start", {}, 1};
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, {}, {method="finish", client_id=1}};
+ {NIL, {}, {method="start", client_id=1}};
}
local client
test_rpc_server {
@@ -597,12 +600,12 @@ describe('LSP', function()
eq(0, code, "exit code", fake_lsp_logfile)
eq(0, signal, "exit signal", fake_lsp_logfile)
end;
- on_handler = function(err, method, params, client_id)
- if method == 'start' then
+ on_handler = function(err, result, ctx)
+ if ctx.method == 'start' then
client.notify('finish')
end
- eq(table.remove(expected_handlers), {err, method, params, client_id}, "expected handler")
- if method == 'finish' then
+ eq(table.remove(expected_handlers), {err, result, ctx}, "expected handler")
+ if ctx.method == 'finish' then
client.stop()
end
end;
@@ -611,9 +614,9 @@ describe('LSP', function()
it('should check the body and didChange full', function()
local expected_handlers = {
- {NIL, "shutdown", {}, 1};
- {NIL, "finish", {}, 1};
- {NIL, "start", {}, 1};
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, {}, {method="finish", client_id=1}};
+ {NIL, {}, {method="start", client_id=1}};
}
local client
test_rpc_server {
@@ -640,8 +643,8 @@ describe('LSP', function()
eq(0, code, "exit code", fake_lsp_logfile)
eq(0, signal, "exit signal", fake_lsp_logfile)
end;
- on_handler = function(err, method, params, client_id)
- if method == 'start' then
+ on_handler = function(err, result, ctx)
+ if ctx.method == 'start' then
exec_lua [[
vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
"boop";
@@ -649,8 +652,8 @@ describe('LSP', function()
]]
client.notify('finish')
end
- eq(table.remove(expected_handlers), {err, method, params, client_id}, "expected handler")
- if method == 'finish' then
+ eq(table.remove(expected_handlers), {err, result, ctx}, "expected handler")
+ if ctx.method == 'finish' then
client.stop()
end
end;
@@ -659,9 +662,9 @@ describe('LSP', function()
it('should check the body and didChange full with noeol', function()
local expected_handlers = {
- {NIL, "shutdown", {}, 1};
- {NIL, "finish", {}, 1};
- {NIL, "start", {}, 1};
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, {}, {method="finish", client_id=1}};
+ {NIL, {}, {method="start", client_id=1}};
}
local client
test_rpc_server {
@@ -689,8 +692,8 @@ describe('LSP', function()
eq(0, code, "exit code", fake_lsp_logfile)
eq(0, signal, "exit signal", fake_lsp_logfile)
end;
- on_handler = function(err, method, params, client_id)
- if method == 'start' then
+ on_handler = function(err, result, ctx)
+ if ctx.method == 'start' then
exec_lua [[
vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
"boop";
@@ -698,8 +701,8 @@ describe('LSP', function()
]]
client.notify('finish')
end
- eq(table.remove(expected_handlers), {err, method, params, client_id}, "expected handler")
- if method == 'finish' then
+ eq(table.remove(expected_handlers), {err, result, ctx}, "expected handler")
+ if ctx.method == 'finish' then
client.stop()
end
end;
@@ -708,9 +711,9 @@ describe('LSP', function()
it('should check the body and didChange incremental', function()
local expected_handlers = {
- {NIL, "shutdown", {}, 1};
- {NIL, "finish", {}, 1};
- {NIL, "start", {}, 1};
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, {}, {method="finish", client_id=1}};
+ {NIL, {}, {method="start", client_id=1}};
}
local client
test_rpc_server {
@@ -738,8 +741,8 @@ describe('LSP', function()
eq(0, code, "exit code", fake_lsp_logfile)
eq(0, signal, "exit signal", fake_lsp_logfile)
end;
- on_handler = function(err, method, params, client_id)
- if method == 'start' then
+ on_handler = function(err, result, ctx)
+ if ctx.method == 'start' then
exec_lua [[
vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
"123boop";
@@ -747,8 +750,8 @@ describe('LSP', function()
]]
client.notify('finish')
end
- eq(table.remove(expected_handlers), {err, method, params, client_id}, "expected handler")
- if method == 'finish' then
+ eq(table.remove(expected_handlers), {err, result, ctx}, "expected handler")
+ if ctx.method == 'finish' then
client.stop()
end
end;
@@ -758,9 +761,9 @@ describe('LSP', function()
-- TODO(askhan) we don't support full for now, so we can disable these tests.
pending('should check the body and didChange incremental normal mode editing', function()
local expected_handlers = {
- {NIL, "shutdown", {}, 1};
- {NIL, "finish", {}, 1};
- {NIL, "start", {}, 1};
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, {}, {method="finish", client_id=1}};
+ {NIL, {}, {method="start", client_id=1}};
}
local client
test_rpc_server {
@@ -787,13 +790,13 @@ describe('LSP', function()
eq(0, code, "exit code", fake_lsp_logfile)
eq(0, signal, "exit signal", fake_lsp_logfile)
end;
- on_handler = function(err, method, params, client_id)
- if method == 'start' then
+ on_handler = function(err, result, ctx)
+ if ctx.method == 'start' then
helpers.command("normal! 1Go")
client.notify('finish')
end
- eq(table.remove(expected_handlers), {err, method, params, client_id}, "expected handler")
- if method == 'finish' then
+ eq(table.remove(expected_handlers), {err, result, ctx}, "expected handler")
+ if ctx.method == 'finish' then
client.stop()
end
end;
@@ -802,9 +805,9 @@ describe('LSP', function()
it('should check the body and didChange full with 2 changes', function()
local expected_handlers = {
- {NIL, "shutdown", {}, 1};
- {NIL, "finish", {}, 1};
- {NIL, "start", {}, 1};
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, {}, {method="finish", client_id=1}};
+ {NIL, {}, {method="start", client_id=1}};
}
local client
test_rpc_server {
@@ -831,8 +834,8 @@ describe('LSP', function()
eq(0, code, "exit code", fake_lsp_logfile)
eq(0, signal, "exit signal", fake_lsp_logfile)
end;
- on_handler = function(err, method, params, client_id)
- if method == 'start' then
+ on_handler = function(err, result, ctx)
+ if ctx.method == 'start' then
exec_lua [[
vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
"321";
@@ -843,8 +846,8 @@ describe('LSP', function()
]]
client.notify('finish')
end
- eq(table.remove(expected_handlers), {err, method, params, client_id}, "expected handler")
- if method == 'finish' then
+ eq(table.remove(expected_handlers), {err, result, ctx}, "expected handler")
+ if ctx.method == 'finish' then
client.stop()
end
end;
@@ -853,9 +856,9 @@ describe('LSP', function()
it('should check the body and didChange full lifecycle', function()
local expected_handlers = {
- {NIL, "shutdown", {}, 1};
- {NIL, "finish", {}, 1};
- {NIL, "start", {}, 1};
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, {}, {method="finish", client_id=1}};
+ {NIL, {}, {method="start", client_id=1}};
}
local client
test_rpc_server {
@@ -882,8 +885,8 @@ describe('LSP', function()
eq(0, code, "exit code", fake_lsp_logfile)
eq(0, signal, "exit signal", fake_lsp_logfile)
end;
- on_handler = function(err, method, params, client_id)
- if method == 'start' then
+ on_handler = function(err, result,ctx)
+ if ctx.method == 'start' then
exec_lua [[
vim.api.nvim_buf_set_lines(BUFFER, 1, 2, false, {
"321";
@@ -895,8 +898,8 @@ describe('LSP', function()
]]
client.notify('finish')
end
- eq(table.remove(expected_handlers), {err, method, params, client_id}, "expected handler")
- if method == 'finish' then
+ eq(table.remove(expected_handlers), {err, result, ctx}, "expected handler")
+ if ctx.method == 'finish' then
client.stop()
end
end;
@@ -907,9 +910,9 @@ describe('LSP', function()
describe("parsing tests", function()
it('should handle invalid content-length correctly', function()
local expected_handlers = {
- {NIL, "shutdown", {}, 1};
- {NIL, "finish", {}, 1};
- {NIL, "start", {}, 1};
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, {}, {method="finish", client_id=1}};
+ {NIL, {}, {method="start", client_id=1}};
}
local client
test_rpc_server {
@@ -924,22 +927,22 @@ describe('LSP', function()
eq(0, code, "exit code", fake_lsp_logfile)
eq(0, signal, "exit signal", fake_lsp_logfile)
end;
- on_handler = function(err, method, params, client_id)
- eq(table.remove(expected_handlers), {err, method, params, client_id}, "expected handler")
+ on_handler = function(err, result, ctx)
+ eq(table.remove(expected_handlers), {err, result, ctx}, "expected handler")
end;
}
end)
it('should not trim vim.NIL from the end of a list', function()
local expected_handlers = {
- {NIL, "shutdown", {}, 1};
- {NIL, "finish", {}, 1};
- {NIL, "workspace/executeCommand", {
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, {}, {method="finish", client_id=1}};
+ {NIL,{
arguments = { "EXTRACT_METHOD", {metadata = {}}, 3, 0, 6123, NIL },
command = "refactor.perform",
title = "EXTRACT_METHOD"
- }, 1};
- {NIL, "start", {}, 1};
+ }, {method="workspace/executeCommand", client_id=1}};
+ {NIL, {}, {method="start", client_id=1}};
}
local client
test_rpc_server {
@@ -963,9 +966,9 @@ describe('LSP', function()
eq(0, code, "exit code", fake_lsp_logfile)
eq(0, signal, "exit signal", fake_lsp_logfile)
end;
- on_handler = function(err, method, params, client_id)
- eq(table.remove(expected_handlers), {err, method, params, client_id}, "expected handler")
- if method == 'finish' then
+ on_handler = function(err, result, ctx)
+ eq(table.remove(expected_handlers), {err, result, ctx}, "expected handler")
+ if ctx.method == 'finish' then
client.stop()
end
end;
@@ -1014,31 +1017,6 @@ describe('LSP', function()
}
end
- it('highlight groups', function()
- eq({
- 'LspDiagnosticsDefaultError',
- 'LspDiagnosticsDefaultHint',
- 'LspDiagnosticsDefaultInformation',
- 'LspDiagnosticsDefaultWarning',
- 'LspDiagnosticsFloatingError',
- 'LspDiagnosticsFloatingHint',
- 'LspDiagnosticsFloatingInformation',
- 'LspDiagnosticsFloatingWarning',
- 'LspDiagnosticsSignError',
- 'LspDiagnosticsSignHint',
- 'LspDiagnosticsSignInformation',
- 'LspDiagnosticsSignWarning',
- 'LspDiagnosticsUnderlineError',
- 'LspDiagnosticsUnderlineHint',
- 'LspDiagnosticsUnderlineInformation',
- 'LspDiagnosticsUnderlineWarning',
- 'LspDiagnosticsVirtualTextError',
- 'LspDiagnosticsVirtualTextHint',
- 'LspDiagnosticsVirtualTextInformation',
- 'LspDiagnosticsVirtualTextWarning',
- }, exec_lua([[require'vim.lsp'; return vim.fn.getcompletion('Lsp', 'highlight')]]))
- end)
-
describe('apply_text_edits', function()
before_each(function()
insert(dedent([[
@@ -1088,6 +1066,30 @@ describe('LSP', function()
'å å ɧ 汉语 ↥ 🤦 🦄';
}, buf_lines(1))
end)
+ it('applies complex edits (reversed range)', function()
+ local edits = {
+ make_edit(0, 0, 0, 0, {"", "12"});
+ make_edit(0, 0, 0, 0, {"3", "foo"});
+ make_edit(0, 1, 0, 1, {"bar", "123"});
+ make_edit(0, #"First line of text", 0, #"First ", {"guy"});
+ make_edit(1, #'Second', 1, 0, {"baz"});
+ make_edit(2, #"Third", 2, #'Th', {"e next"});
+ make_edit(3, #"Fourth", 3, #'', {"another line of text", "before this"});
+ make_edit(3, #"Fourth line of text", 3, #'Fourth', {"!"});
+ }
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ eq({
+ '';
+ '123';
+ 'fooFbar';
+ '123irst guy';
+ 'baz line of text';
+ 'The next line of text';
+ 'another line of text';
+ 'before this!';
+ 'å å ɧ 汉语 ↥ 🤦 🦄';
+ }, buf_lines(1))
+ end)
it('applies non-ASCII characters edits', function()
local edits = {
make_edit(4, 3, 4, 4, {"ä"});
@@ -1116,6 +1118,86 @@ describe('LSP', function()
}, buf_lines(1))
end)
+ describe('cursor position', function()
+ it('don\'t fix the cursor if the range contains the cursor', function()
+ funcs.nvim_win_set_cursor(0, { 2, 6 })
+ local edits = {
+ make_edit(1, 0, 1, 19, 'Second line of text')
+ }
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ eq({
+ 'First line of text';
+ 'Second line of text';
+ 'Third line of text';
+ 'Fourth line of text';
+ 'å å ɧ 汉语 ↥ 🤦 🦄';
+ }, buf_lines(1))
+ eq({ 2, 6 }, funcs.nvim_win_get_cursor(0))
+ end)
+
+ it('fix the cursor to the valid column if the content was removed', function()
+ funcs.nvim_win_set_cursor(0, { 2, 6 })
+ local edits = {
+ make_edit(1, 0, 1, 19, '')
+ }
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ eq({
+ 'First line of text';
+ '';
+ 'Third line of text';
+ 'Fourth line of text';
+ 'å å ɧ 汉语 ↥ 🤦 🦄';
+ }, buf_lines(1))
+ eq({ 2, 0 }, funcs.nvim_win_get_cursor(0))
+ end)
+
+ it('fix the cursor row', function()
+ funcs.nvim_win_set_cursor(0, { 3, 0 })
+ local edits = {
+ make_edit(1, 0, 2, 0, '')
+ }
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ eq({
+ 'First line of text';
+ 'Third line of text';
+ 'Fourth line of text';
+ 'å å ɧ 汉语 ↥ 🤦 🦄';
+ }, buf_lines(1))
+ eq({ 2, 0 }, funcs.nvim_win_get_cursor(0))
+ end)
+
+ it('fix the cursor col', function()
+ funcs.nvim_win_set_cursor(0, { 2, 11 })
+ local edits = {
+ make_edit(1, 7, 1, 11, '')
+ }
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ eq({
+ 'First line of text';
+ 'Second of text';
+ 'Third line of text';
+ 'Fourth line of text';
+ 'å å ɧ 汉语 ↥ 🤦 🦄';
+ }, buf_lines(1))
+ eq({ 2, 7 }, funcs.nvim_win_get_cursor(0))
+ end)
+
+ it('fix the cursor row and col', function()
+ funcs.nvim_win_set_cursor(0, { 2, 12 })
+ local edits = {
+ make_edit(0, 11, 1, 12, '')
+ }
+ exec_lua('vim.lsp.util.apply_text_edits(...)', edits, 1)
+ eq({
+ 'First line of text';
+ 'Third line of text';
+ 'Fourth line of text';
+ 'å å ɧ 汉语 ↥ 🤦 🦄';
+ }, buf_lines(1))
+ eq({ 1, 11 }, funcs.nvim_win_get_cursor(0))
+ end)
+ end)
+
describe('with LSP end line after what Vim considers to be the end line', function()
it('applies edits when the last linebreak is considered a new line', function()
local edits = {
@@ -1149,14 +1231,14 @@ describe('LSP', function()
make_edit(0, 0, 0, 3, "First ↥ 🤦 🦄")
},
textDocument = {
- uri = "file://fake/uri";
+ uri = "file:///fake/uri";
version = editVersion
}
}
end
before_each(function()
target_bufnr = exec_lua [[
- local bufnr = vim.uri_to_bufnr("file://fake/uri")
+ local bufnr = vim.uri_to_bufnr("file:///fake/uri")
local lines = {"1st line of text", "2nd line of 语text"}
vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
return bufnr
@@ -1223,7 +1305,7 @@ describe('LSP', function()
label = nil;
edit = {};
}
- return vim.lsp.handlers['workspace/applyEdit'](nil, nil, apply_edit)
+ return vim.lsp.handlers['workspace/applyEdit'](nil, apply_edit)
]])
end)
end)
@@ -1236,7 +1318,7 @@ describe('LSP', function()
make_edit(row, 0, row, 1000, new_line)
},
textDocument = {
- uri = "file://fake/uri";
+ uri = "file:///fake/uri";
version = editVersion
}
}
@@ -1254,7 +1336,7 @@ describe('LSP', function()
before_each(function()
local ret = exec_lua [[
- local bufnr = vim.uri_to_bufnr("file://fake/uri")
+ local bufnr = vim.uri_to_bufnr("file:///fake/uri")
local lines = {
"Original Line #1",
"Original Line #2"
@@ -1441,8 +1523,10 @@ describe('LSP', function()
{ label='foocar', sortText="h", insertText='foodar(${1:var1} typ1, ${2:var2} *typ2) {$0\\}', insertTextFormat=2, textEdit={} },
-- nested snippet tokens
{ label='foocar', sortText="i", insertText='foodar(${1:var1 ${2|typ2,typ3|} ${3:tail}}) {$0\\}', insertTextFormat=2, textEdit={} },
+ -- braced tabstop
+ { label='foocar', sortText="j", insertText='foodar()${0}', insertTextFormat=2, textEdit={} },
-- plain text
- { label='foocar', sortText="j", insertText='foodar(${1:var1})', insertTextFormat=1, textEdit={} },
+ { label='foocar', sortText="k", insertText='foodar(${1:var1})', insertTextFormat=1, textEdit={} },
}
local completion_list_items = {items=completion_list}
local expected = {
@@ -1454,8 +1538,9 @@ describe('LSP', function()
{ abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="f", textEdit={newText='foobar'} } } } } },
{ abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foobar(place holder, more ...holder{})', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="g", insertText='foodar', insertTextFormat=2, textEdit={newText='foobar(${1:place holder}, ${2:more ...holder{\\}})'} } } } } },
{ abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(var1 typ1, var2 *typ2) {}', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="h", insertText='foodar(${1:var1} typ1, ${2:var2} *typ2) {$0\\}', insertTextFormat=2, textEdit={} } } } } },
- { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(var1 typ2,typ3 tail) {}', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="i", insertText='foodar(${1:var1 ${2|typ2,typ3|} ${3:tail}}) {$0\\}', insertTextFormat=2, textEdit={} } } } } },
- { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(${1:var1})', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="j", insertText='foodar(${1:var1})', insertTextFormat=1, textEdit={} } } } } },
+ { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(var1 typ2 tail) {}', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="i", insertText='foodar(${1:var1 ${2|typ2,typ3|} ${3:tail}}) {$0\\}', insertTextFormat=2, textEdit={} } } } } },
+ { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar()', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="j", insertText='foodar()${0}', insertTextFormat=2, textEdit={} } } } } },
+ { abbr = 'foocar', dup = 1, empty = 1, icase = 1, info = ' ', kind = 'Unknown', menu = '', word = 'foodar(${1:var1})', user_data = { nvim = { lsp = { completion_item = { label='foocar', sortText="k", insertText='foodar(${1:var1})', insertTextFormat=1, textEdit={} } } } } },
}
eq(expected, exec_lua([[return vim.lsp.util.text_document_completion_list_to_complete_items(...)]], completion_list, prefix))
@@ -1534,19 +1619,19 @@ describe('LSP', function()
it('Convert Location[] to items', function()
local expected = {
{
- filename = 'fake/uri',
+ filename = '/fake/uri',
lnum = 1,
col = 3,
text = 'testing'
},
}
local actual = exec_lua [[
- local bufnr = vim.uri_to_bufnr("file://fake/uri")
+ local bufnr = vim.uri_to_bufnr("file:///fake/uri")
local lines = {"testing", "123"}
vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
local locations = {
{
- uri = 'file://fake/uri',
+ uri = 'file:///fake/uri',
range = {
start = { line = 0, character = 2 },
['end'] = { line = 0, character = 3 },
@@ -1560,14 +1645,14 @@ describe('LSP', function()
it('Convert LocationLink[] to items', function()
local expected = {
{
- filename = 'fake/uri',
+ filename = '/fake/uri',
lnum = 1,
col = 3,
text = 'testing'
},
}
local actual = exec_lua [[
- local bufnr = vim.uri_to_bufnr("file://fake/uri")
+ local bufnr = vim.uri_to_bufnr("file:///fake/uri")
local lines = {"testing", "123"}
vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
local locations = {
@@ -1781,14 +1866,14 @@ describe('LSP', function()
local expected = {
{
col = 1,
- filename = 'test_a',
+ filename = '/test_a',
kind = 'File',
lnum = 2,
text = '[File] TestA'
},
{
col = 1,
- filename = 'test_b',
+ filename = '/test_b',
kind = 'Module',
lnum = 4,
text = '[Module] TestB'
@@ -1811,7 +1896,7 @@ describe('LSP', function()
line = 2
}
},
- uri = "file://test_a"
+ uri = "file:///test_a"
},
contanerName = "TestAContainer"
},
@@ -1830,7 +1915,7 @@ describe('LSP', function()
line = 4
}
},
- uri = "file://test_b"
+ uri = "file:///test_b"
},
contanerName = "TestBContainer"
}
@@ -1869,7 +1954,7 @@ describe('LSP', function()
before_each(function()
target_bufnr = exec_lua [[
- local bufnr = vim.uri_to_bufnr("file://fake/uri")
+ local bufnr = vim.uri_to_bufnr("file:///fake/uri")
local lines = {"1st line of text", "å å ɧ 汉语 ↥ 🤦 🦄"}
vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines)
return bufnr
@@ -1878,7 +1963,7 @@ describe('LSP', function()
local location = function(start_line, start_char, end_line, end_char)
return {
- uri = "file://fake/uri",
+ uri = "file:///fake/uri",
range = {
start = { line = start_line, character = start_char },
["end"] = { line = end_line, character = end_char },
@@ -1903,7 +1988,7 @@ describe('LSP', function()
it('jumps to a LocationLink', function()
local pos = jump({
- targetUri = "file://fake/uri",
+ targetUri = "file:///fake/uri",
targetSelectionRange = {
start = { line = 0, character = 4 },
["end"] = { line = 0, character = 4 },
@@ -1937,6 +2022,83 @@ describe('LSP', function()
end)
end)
+ describe('lsp.util.make_floating_popup_options', function()
+ before_each(function()
+ exec_lua [[
+ local bufnr = vim.uri_to_bufnr("file:///fake/uri")
+ local winheight = vim.fn.winheight(0)
+ for i = 1, winheight do
+ vim.api.nvim_buf_set_lines(bufnr, 0, 0, false, {''})
+ end
+ vim.api.nvim_win_set_buf(0, bufnr)
+ vim.api.nvim_win_set_cursor(0, {winheight, 0})
+ ]]
+ end)
+
+ local function popup_row(opts)
+ return exec_lua([[
+ return vim.lsp.util.make_floating_popup_options(...).row
+ ]], 2, 2, opts)
+ end
+
+ local err_pattern = "^Error executing lua: %.%.%./util%.lua:0: invalid floating preview border: .*%. :help vim%.api%.nvim_open_win%(%)$"
+
+ it('calculates default border height correctly', function()
+ eq(0, popup_row())
+ end)
+
+ it('calculates string border height correctly', function()
+ eq(0, popup_row({border = 'none'}))
+ eq(-2, popup_row({border = 'single'}))
+ eq(-2, popup_row({border = 'double'}))
+ eq(-2, popup_row({border = 'rounded'}))
+ eq(-2, popup_row({border = 'solid'}))
+ eq(-1, popup_row({border = 'shadow'}))
+ end)
+
+ it('error on invalid string border', function()
+ matches(err_pattern, pcall_err(popup_row, {border = ''}))
+ matches(err_pattern, pcall_err(popup_row, {border = 'invalid'}))
+ end)
+
+ it('error on invalid array border length', function()
+ matches(err_pattern, pcall_err(popup_row, {border = {}}))
+ matches(err_pattern, pcall_err(popup_row, {border = {'', '', ''}}))
+ matches(err_pattern, pcall_err(popup_row, {border = {'', '', '', '', ''}}))
+ end)
+
+ it('error on invalid array border member type', function()
+ matches(err_pattern, pcall_err(popup_row, {border = {0}}))
+ end)
+
+ it('calculates 8-array border height correctly', function()
+ eq(0, popup_row({border = {'', '', '', '', '', '', '', ''}}))
+ eq(-2, popup_row({border = {'', '~', '', '~', '', '~', '', '~'}}))
+ eq(-1, popup_row({border = {'', '', '', '~', '', '~', '', ''}}))
+ eq(0, popup_row({border = {'', '', '', {'~', 'NormalFloat'}, '', '', '', {'~', 'NormalFloat'}}}))
+ eq(-2, popup_row({border = {'', {'~', 'NormalFloat'}, '', '', '', {'~', 'NormalFloat'}, '', ''}}))
+ end)
+
+ it('calculates 4-array border height correctly', function()
+ eq(0, popup_row({border = {'', '', '', ''}}))
+ eq(-2, popup_row({border = {'', '~', '', '~'}}))
+ eq(0, popup_row({border = {'', '', '', {'~', 'NormalFloat'}}}))
+ eq(-2, popup_row({border = {'', {'~', 'NormalFloat'}, '', ''}}))
+ end)
+
+ it('calculates 2-array border height correctly', function()
+ eq(0, popup_row({border = {'', ''}}))
+ eq(-2, popup_row({border = {'', '~'}}))
+ eq(-2, popup_row({border = {'', {'~', 'NormalFloat'}}}))
+ end)
+
+ it('calculates 1-array border height correctly', function()
+ eq(0, popup_row({border = {''}}))
+ eq(-2, popup_row({border = {'~'}}))
+ eq(-2, popup_row({border = {{'~', 'NormalFloat'}}}))
+ end)
+ end)
+
describe('lsp.util._make_floating_popup_size', function()
before_each(function()
exec_lua [[ contents =
@@ -1955,6 +2117,12 @@ describe('LSP', function()
end)
end)
+ describe('lsp.util.trim.trim_empty_lines', function()
+ it('properly trims empty lines', function()
+ eq({{"foo", "bar"}}, exec_lua[[ return vim.lsp.util.trim_empty_lines({{ "foo", "bar" }, nil}) ]])
+ end)
+ end)
+
describe('lsp.util.get_effective_tabstop', function()
local function test_tabstop(tabsize, softtabstop)
exec_lua(string.format([[
@@ -1973,7 +2141,7 @@ describe('LSP', function()
describe('vim.lsp.buf.outgoing_calls', function()
it('does nothing for an empty response', function()
local qflist_count = exec_lua([=[
- require'vim.lsp.handlers'['callHierarchy/outgoingCalls']()
+ require'vim.lsp.handlers'['callHierarchy/outgoingCalls'](nil, nil, {}, nil)
return #vim.fn.getqflist()
]=])
eq(0, qflist_count)
@@ -2020,14 +2188,16 @@ describe('LSP', function()
}
} }
local handler = require'vim.lsp.handlers'['callHierarchy/outgoingCalls']
- handler(nil, nil, rust_analyzer_response)
+ handler(nil, rust_analyzer_response, {})
return vim.fn.getqflist()
]=])
local expected = { {
bufnr = 2,
col = 5,
+ end_col = 0,
lnum = 4,
+ end_lnum = 0,
module = "",
nr = 0,
pattern = "",
@@ -2044,7 +2214,7 @@ describe('LSP', function()
describe('vim.lsp.buf.incoming_calls', function()
it('does nothing for an empty response', function()
local qflist_count = exec_lua([=[
- require'vim.lsp.handlers'['callHierarchy/incomingCalls']()
+ require'vim.lsp.handlers'['callHierarchy/incomingCalls'](nil, nil, {})
return #vim.fn.getqflist()
]=])
eq(0, qflist_count)
@@ -2092,14 +2262,16 @@ describe('LSP', function()
} }
local handler = require'vim.lsp.handlers'['callHierarchy/incomingCalls']
- handler(nil, nil, rust_analyzer_response)
+ handler(nil, rust_analyzer_response, {})
return vim.fn.getqflist()
]=])
local expected = { {
bufnr = 2,
col = 5,
+ end_col = 0,
lnum = 4,
+ end_lnum = 0,
module = "",
nr = 0,
pattern = "",
@@ -2112,4 +2284,149 @@ describe('LSP', function()
eq(expected, qflist)
end)
end)
+
+ describe('vim.lsp.buf.rename', function()
+ for _, test in ipairs({
+ {
+ it = "does not attempt to rename on nil response",
+ name = "prepare_rename_nil",
+ expected_handlers = {
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, {}, {method="start", client_id=1}};
+ },
+ },
+ {
+ it = "handles prepareRename placeholder response",
+ name = "prepare_rename_placeholder",
+ expected_handlers = {
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, NIL, {method="textDocument/rename", client_id=1, bufnr=1}};
+ {NIL, {}, {method="start", client_id=1}};
+ },
+ expected_text = "placeholder", -- see fake lsp response
+ },
+ {
+ it = "handles range response",
+ name = "prepare_rename_range",
+ expected_handlers = {
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, NIL, {method="textDocument/rename", client_id=1, bufnr=1}};
+ {NIL, {}, {method="start", client_id=1}};
+ },
+ expected_text = "line", -- see test case and fake lsp response
+ },
+ {
+ it = "handles error",
+ name = "prepare_rename_error",
+ expected_handlers = {
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, NIL, {method="textDocument/rename", client_id=1, bufnr=1}};
+ {NIL, {}, {method="start", client_id=1}};
+ },
+ expected_text = "two", -- see test case
+ },
+ }) do
+ it(test.it, function()
+ local client
+ test_rpc_server {
+ test_name = test.name;
+ on_init = function(_client)
+ client = _client
+ eq(true, client.resolved_capabilities().rename)
+ end;
+ on_setup = function()
+ exec_lua([=[
+ local bufnr = vim.api.nvim_get_current_buf()
+ lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
+ vim.lsp._stubs = {}
+ vim.fn.input = function(prompt, text)
+ vim.lsp._stubs.input_prompt = prompt
+ vim.lsp._stubs.input_text = text
+ return 'renameto' -- expect this value in fake lsp
+ end
+ vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {'', 'this is line two'})
+ vim.fn.cursor(2, 13) -- the space between "line" and "two"
+ ]=])
+ end;
+ on_exit = function(code, signal)
+ eq(0, code, "exit code", fake_lsp_logfile)
+ eq(0, signal, "exit signal", fake_lsp_logfile)
+ end;
+ on_handler = function(err, result, ctx)
+ -- Don't compare & assert params, they're not relevant for the testcase
+ -- This allows us to be lazy and avoid declaring them
+ ctx.params = nil
+
+ eq(table.remove(test.expected_handlers), {err, result, ctx}, "expected handler")
+ if ctx.method == 'start' then
+ exec_lua("vim.lsp.buf.rename()")
+ end
+ if ctx.method == 'shutdown' then
+ if test.expected_text then
+ eq("New Name: ", exec_lua("return vim.lsp._stubs.input_prompt"))
+ eq(test.expected_text, exec_lua("return vim.lsp._stubs.input_text"))
+ end
+ client.stop()
+ end
+ end;
+ }
+ end)
+ end
+ end)
+
+ describe('vim.lsp.buf.code_action', function()
+ it('Calls client side command if available', function()
+ local client
+ local expected_handlers = {
+ {NIL, {}, {method="shutdown", client_id=1}};
+ {NIL, {}, {method="start", client_id=1}};
+ }
+ test_rpc_server {
+ test_name = 'code_action_with_resolve',
+ on_init = function(client_)
+ client = client_
+ end,
+ on_setup = function()
+ end,
+ on_exit = function(code, signal)
+ eq(0, code, "exit code", fake_lsp_logfile)
+ eq(0, signal, "exit signal", fake_lsp_logfile)
+ end,
+ on_handler = function(err, result, ctx)
+ eq(table.remove(expected_handlers), {err, result, ctx})
+ if ctx.method == 'start' then
+ exec_lua([[
+ vim.lsp.commands['dummy1'] = function(cmd)
+ vim.lsp.commands['dummy2'] = function()
+ end
+ end
+ local bufnr = vim.api.nvim_get_current_buf()
+ vim.lsp.buf_attach_client(bufnr, TEST_RPC_CLIENT_ID)
+ vim.fn.inputlist = function()
+ return 1
+ end
+ vim.lsp.buf.code_action()
+ ]])
+ elseif ctx.method == 'shutdown' then
+ eq('function', exec_lua[[return type(vim.lsp.commands['dummy2'])]])
+ client.stop()
+ end
+ end
+ }
+ end)
+ end)
+ describe('vim.lsp.commands', function()
+ it('Accepts only string keys', function()
+ matches(
+ '.*The key for commands in `vim.lsp.commands` must be a string',
+ pcall_err(exec_lua, 'vim.lsp.commands[1] = function() end')
+ )
+ end)
+ it('Accepts only function values', function()
+ matches(
+ '.*Command added to `vim.lsp.commands` must be a function',
+ pcall_err(exec_lua, 'vim.lsp.commands.dummy = 10')
+ )
+ end)
+ end)
end)
diff --git a/test/functional/plugin/shada_spec.lua b/test/functional/plugin/shada_spec.lua
index 5663f248bf..a4d78682ad 100644
--- a/test/functional/plugin/shada_spec.lua
+++ b/test/functional/plugin/shada_spec.lua
@@ -2161,6 +2161,12 @@ describe('plugin/shada.vim', function()
reset()
wshada('\004\000\009\147\000\196\002ab\196\001a')
wshada_tmp('\004\000\009\147\000\196\002ab\196\001b')
+
+ -- Need to set nohidden so that the buffer containing 'fname' is not unloaded
+ -- after loading 'fname_tmp', otherwise the '++opt not supported' test below
+ -- won't work since the BufReadCmd autocmd won't be triggered.
+ nvim_command('set nohidden')
+
nvim_command('edit ' .. fname)
eq({
'History entry with timestamp ' .. epoch .. ':',
diff --git a/test/functional/provider/clipboard_spec.lua b/test/functional/provider/clipboard_spec.lua
index e5e21f11a6..986db96a18 100644
--- a/test/functional/provider/clipboard_spec.lua
+++ b/test/functional/provider/clipboard_spec.lua
@@ -653,14 +653,12 @@ describe('clipboard (with fake clipboard.vim)', function()
'',
'',
'E121: Undefined variable: doesnotexist',
- 'E15: Invalid expression: doesnotexist',
}, 'v'}, eval("g:test_clip['*']"))
feed_command(':echo "Howdy!"')
eq({{
'',
'',
'E121: Undefined variable: doesnotexist',
- 'E15: Invalid expression: doesnotexist',
'',
'Howdy!',
}, 'v'}, eval("g:test_clip['*']"))
diff --git a/test/functional/provider/python3_spec.lua b/test/functional/provider/python3_spec.lua
index d254edc7d5..d100db8de2 100644
--- a/test/functional/provider/python3_spec.lua
+++ b/test/functional/provider/python3_spec.lua
@@ -1,4 +1,5 @@
local helpers = require('test.functional.helpers')(after_each)
+local assert_alive = helpers.assert_alive
local eval, command, feed = helpers.eval, helpers.command, helpers.feed
local eq, clear, insert = helpers.eq, helpers.clear, helpers.insert
local expect, write_file = helpers.expect, helpers.write_file
@@ -116,6 +117,6 @@ describe('python3 provider', function()
feed_command("exe 'split' tempname()")
feed_command("bwipeout!")
feed_command('help help')
- eq(2, eval('1+1')) -- Still alive?
+ assert_alive()
end)
end)
diff --git a/test/functional/provider/ruby_spec.lua b/test/functional/provider/ruby_spec.lua
index 2729d8dfa2..fba96100fc 100644
--- a/test/functional/provider/ruby_spec.lua
+++ b/test/functional/provider/ruby_spec.lua
@@ -1,10 +1,10 @@
local helpers = require('test.functional.helpers')(after_each)
+local assert_alive = helpers.assert_alive
local clear = helpers.clear
local command = helpers.command
local curbufmeths = helpers.curbufmeths
local eq = helpers.eq
-local eval = helpers.eval
local exc_exec = helpers.exc_exec
local expect = helpers.expect
local feed = helpers.feed
@@ -107,7 +107,7 @@ describe('ruby provider', function()
helpers.add_builddir_to_rtp()
command([=[autocmd BufDelete * ruby VIM::evaluate('expand("<afile>")')]=])
feed_command('help help')
- eq(2, eval('1+1')) -- Still alive?
+ assert_alive()
end)
end)
diff --git a/test/functional/shada/errors_spec.lua b/test/functional/shada/errors_spec.lua
index 77a41caec7..ebfd73cf85 100644
--- a/test/functional/shada/errors_spec.lua
+++ b/test/functional/shada/errors_spec.lua
@@ -342,6 +342,11 @@ describe('ShaDa error handling', function()
eq('Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 has wrong variable name type', exc_exec(sdrcmd()))
end)
+ it('fails on variable item with BIN value and type value != VAR_TYPE_BLOB', function()
+ wshada('\006\000\007\147\196\001\065\196\000\000')
+ eq('Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 has wrong variable type', exc_exec(sdrcmd()))
+ end)
+
it('fails on replacement item with NIL value', function()
wshada('\003\000\001\192')
eq('Vim(rshada):E575: Error while reading ShaDa file: sub string entry at position 0 is not an array', exc_exec(sdrcmd()))
diff --git a/test/functional/shada/history_spec.lua b/test/functional/shada/history_spec.lua
index 9291f5e100..84cc34c7cc 100644
--- a/test/functional/shada/history_spec.lua
+++ b/test/functional/shada/history_spec.lua
@@ -2,7 +2,7 @@
local helpers = require('test.functional.helpers')(after_each)
local nvim_command, funcs, meths, nvim_feed, eq =
helpers.command, helpers.funcs, helpers.meths, helpers.feed, helpers.eq
-local eval = helpers.eval
+local assert_alive = helpers.assert_alive
local shada_helpers = require('test.functional.shada.helpers')
local reset, clear = shada_helpers.reset, shada_helpers.clear
@@ -244,7 +244,7 @@ describe('ShaDa support code', function()
nvim_command('wshada')
nvim_command('set shada=\'10,:0')
nvim_command('wshada')
- eq(2, eval('1+1')) -- check nvim still running
+ assert_alive()
end)
end)
diff --git a/test/functional/shada/marks_spec.lua b/test/functional/shada/marks_spec.lua
index e319fd9e6b..153a1c346f 100644
--- a/test/functional/shada/marks_spec.lua
+++ b/test/functional/shada/marks_spec.lua
@@ -3,7 +3,7 @@ local helpers = require('test.functional.helpers')(after_each)
local meths, curwinmeths, curbufmeths, nvim_command, funcs, eq =
helpers.meths, helpers.curwinmeths, helpers.curbufmeths, helpers.command,
helpers.funcs, helpers.eq
-local exc_exec, redir_exec = helpers.exc_exec, helpers.redir_exec
+local exc_exec, exec_capture = helpers.exc_exec, helpers.exec_capture
local shada_helpers = require('test.functional.shada.helpers')
local reset, clear = shada_helpers.reset, shada_helpers.clear
@@ -144,10 +144,10 @@ describe('ShaDa support code', function()
nvim_command('normal! gg')
nvim_command('enew')
nvim_command('normal! gg')
- local saved = redir_exec('jumps')
+ local saved = exec_capture('jumps')
nvim_command('qall')
reset()
- eq(saved, redir_exec('jumps'))
+ eq(saved, exec_capture('jumps'))
end)
it('when dumping jump list also dumps current position', function()
diff --git a/test/functional/shada/merging_spec.lua b/test/functional/shada/merging_spec.lua
index 22f2b8348d..2d44b0a950 100644
--- a/test/functional/shada/merging_spec.lua
+++ b/test/functional/shada/merging_spec.lua
@@ -3,7 +3,7 @@ local helpers = require('test.functional.helpers')(after_each)
local nvim_command, funcs, curbufmeths, eq =
helpers.command, helpers.funcs,
helpers.curbufmeths, helpers.eq
-local exc_exec, redir_exec = helpers.exc_exec, helpers.redir_exec
+local exc_exec, exec_capture = helpers.exc_exec, helpers.exec_capture
local shada_helpers = require('test.functional.shada.helpers')
local reset, clear, get_shada_rw =
@@ -910,14 +910,13 @@ describe('ShaDa jumps support code', function()
.. '\008\007\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'f\161l\002')
eq(0, exc_exec(sdrcmd()))
eq('', curbufmeths.get_name())
- eq('\n'
- .. ' jump line col file/text\n'
+ eq( ' jump line col file/text\n'
.. ' 5 2 0 ' .. mock_file_path .. 'c\n'
.. ' 4 2 0 ' .. mock_file_path .. 'd\n'
.. ' 3 3 0 ' .. mock_file_path .. 'd\n'
.. ' 2 2 0 ' .. mock_file_path .. 'e\n'
.. ' 1 2 0 ' .. mock_file_path .. 'f\n'
- .. '>', redir_exec('jumps'))
+ .. '>', exec_capture('jumps'))
end)
it('merges jumps when writing', function()
@@ -1001,14 +1000,13 @@ describe('ShaDa changes support code', function()
.. '\011\004\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'c\161l\005'
.. '\011\008\018\131\162mX\195\161f\196\006' .. mock_file_path .. 'c\161l\004')
eq(0, exc_exec(sdrcmd()))
- eq('\n'
- .. 'change line col text\n'
+ eq( 'change line col text\n'
.. ' 5 1 0 0\n'
.. ' 4 2 0 1\n'
.. ' 3 5 0 4\n'
.. ' 2 3 0 2\n'
.. ' 1 4 0 3\n'
- .. '>', redir_exec('changes'))
+ .. '>', exec_capture('changes'))
end)
it('merges changes when writing', function()
diff --git a/test/functional/shada/variables_spec.lua b/test/functional/shada/variables_spec.lua
index cc0e7fa537..854add1363 100644
--- a/test/functional/shada/variables_spec.lua
+++ b/test/functional/shada/variables_spec.lua
@@ -1,7 +1,7 @@
-- ShaDa variables saving/reading support
local helpers = require('test.functional.helpers')(after_each)
-local meths, funcs, nvim_command, eq =
- helpers.meths, helpers.funcs, helpers.command, helpers.eq
+local meths, funcs, nvim_command, eq, eval =
+ helpers.meths, helpers.funcs, helpers.command, helpers.eq, helpers.eval
local shada_helpers = require('test.functional.shada.helpers')
local reset, clear = shada_helpers.reset, shada_helpers.clear
@@ -30,10 +30,12 @@ describe('ShaDa support code', function()
else
meths.set_var(varname, varval)
end
+ local vartype = eval('type(g:' .. varname .. ')')
-- Exit during `reset` is not a regular exit: it does not write shada
-- automatically
nvim_command('qall')
reset('set shada+=!')
+ eq(vartype, eval('type(g:' .. varname .. ')'))
eq(varval, meths.get_var(varname))
end)
end
@@ -47,6 +49,8 @@ describe('ShaDa support code', function()
autotest('false', 'FALSEVAR', false)
autotest('null', 'NULLVAR', 'v:null', true)
autotest('ext', 'EXTVAR', '{"_TYPE": v:msgpack_types.ext, "_VAL": [2, ["", ""]]}', true)
+ autotest('blob', 'BLOBVAR', '0z12ab34cd', true)
+ autotest('blob (with NULs)', 'BLOBVARNULS', '0z004e554c7300', true)
it('does not read back variables without `!` in &shada', function()
meths.set_var('STRVAR', 'foo')
diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua
index c61bf108cb..103ae59b8e 100644
--- a/test/functional/terminal/buffer_spec.lua
+++ b/test/functional/terminal/buffer_spec.lua
@@ -1,5 +1,6 @@
local helpers = require('test.functional.helpers')(after_each)
local thelpers = require('test.functional.terminal.helpers')
+local assert_alive = helpers.assert_alive
local feed, clear, nvim = helpers.feed, helpers.clear, helpers.nvim
local poke_eventloop = helpers.poke_eventloop
local eval, feed_command, source = helpers.eval, helpers.feed_command, helpers.source
@@ -7,6 +8,7 @@ local eq, neq = helpers.eq, helpers.neq
local write_file = helpers.write_file
local command= helpers.command
local exc_exec = helpers.exc_exec
+local matches = helpers.matches
describe(':terminal buffer', function()
local screen
@@ -255,8 +257,23 @@ describe(':terminal buffer', function()
command('bdelete!')
end)
- it('handles wqall', function()
+ it('requires bang (!) to close a running job #15402', function()
eq('Vim(wqall):E948: Job still running', exc_exec('wqall'))
+ for _, cmd in ipairs({ 'bdelete', '%bdelete', 'bwipeout', 'bunload' }) do
+ matches('^Vim%('..cmd:gsub('%%', '')..'%):E89: term://.*tty%-test.* will be killed %(add %! to override%)$',
+ exc_exec(cmd))
+ end
+ command('call jobstop(&channel)')
+ assert(0 >= eval('jobwait([&channel], 1000)[0]'))
+ command('bdelete')
+ end)
+
+ it('stops running jobs with :quit', function()
+ -- Open in a new window to avoid terminating the nvim instance
+ command('split')
+ command('terminal')
+ command('set nohidden')
+ command('quit')
end)
it('does not segfault when pasting empty buffer #13955', function()
@@ -284,7 +301,7 @@ describe('No heap-buffer-overflow when using', function()
feed('$')
-- Let termopen() modify the buffer
feed_command('call termopen("echo")')
- eq(2, eval('1+1')) -- check nvim still running
+ assert_alive()
feed_command('bdelete!')
end)
end)
@@ -294,6 +311,6 @@ describe('No heap-buffer-overflow when', function()
feed_command('set nowrap')
feed_command('autocmd TermOpen * startinsert')
feed_command('call feedkeys("4000ai\\<esc>:terminal!\\<cr>")')
- eq(2, eval('1+1'))
+ assert_alive()
end)
end)
diff --git a/test/functional/terminal/ex_terminal_spec.lua b/test/functional/terminal/ex_terminal_spec.lua
index 4b512605e1..707c355069 100644
--- a/test/functional/terminal/ex_terminal_spec.lua
+++ b/test/functional/terminal/ex_terminal_spec.lua
@@ -1,5 +1,6 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
+local assert_alive = helpers.assert_alive
local clear, poke_eventloop, nvim = helpers.clear, helpers.poke_eventloop, helpers.nvim
local nvim_dir, source, eq = helpers.nvim_dir, helpers.source, helpers.eq
local feed = helpers.feed
@@ -215,7 +216,7 @@ describe(':terminal (with fake shell)', function()
-- handler), :terminal cleanup is pending on the main-loop.
-- This write should be ignored (not crash, #5445).
feed('iiYYYYYYY')
- eq(2, eval("1+1")) -- Still alive?
+ assert_alive()
end)
it('works with findfile()', function()
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index 8a5dd7ef18..f7520b14d4 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -8,12 +8,12 @@ local helpers = require('test.functional.helpers')(after_each)
local uname = helpers.uname
local thelpers = require('test.functional.terminal.helpers')
local Screen = require('test.functional.ui.screen')
+local assert_alive = helpers.assert_alive
local eq = helpers.eq
local feed_command = helpers.feed_command
local feed_data = thelpers.feed_data
local clear = helpers.clear
local command = helpers.command
-local eval = helpers.eval
local nvim_dir = helpers.nvim_dir
local retry = helpers.retry
local nvim_prog = helpers.nvim_prog
@@ -82,7 +82,7 @@ describe('TUI', function()
command('call jobresize(b:terminal_job_id, 1, 4)')
screen:try_resize(57, 17)
command('call jobresize(b:terminal_job_id, 57, 17)')
- eq(2, eval("1+1")) -- Still alive?
+ assert_alive()
end)
it('accepts resize while pager is active', function()
diff --git a/test/functional/terminal/window_split_tab_spec.lua b/test/functional/terminal/window_split_tab_spec.lua
index 03bd336aec..188afa1e84 100644
--- a/test/functional/terminal/window_split_tab_spec.lua
+++ b/test/functional/terminal/window_split_tab_spec.lua
@@ -1,5 +1,6 @@
local helpers = require('test.functional.helpers')(after_each)
local thelpers = require('test.functional.terminal.helpers')
+local assert_alive = helpers.assert_alive
local clear = helpers.clear
local feed, nvim = helpers.feed, helpers.nvim
local feed_command = helpers.feed_command
@@ -33,7 +34,7 @@ describe(':terminal', function()
command('vsplit foo')
eq(3, eval("winnr('$')"))
feed('ZQ') -- Close split, should not crash. #7538
- eq(2, eval("1+1")) -- Still alive?
+ assert_alive()
end)
it('does not change size on WinEnter', function()
diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua
index 05e0c5fe2c..175525b3f2 100644
--- a/test/functional/treesitter/highlight_spec.lua
+++ b/test/functional/treesitter/highlight_spec.lua
@@ -570,4 +570,47 @@ describe('treesitter highlighting', function()
]]}
screen:expect{ unchanged=true }
end)
+
+ it("supports highlighting with priority", function()
+ if pending_c_parser(pending) then return end
+
+ insert([[
+ int x = INT_MAX;
+ #define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))
+ #define foo void main() { \
+ return 42; \
+ }
+ ]])
+
+ exec_lua [[
+ local parser = vim.treesitter.get_parser(0, "c")
+ test_hl = vim.treesitter.highlighter.new(parser, {queries = {c = hl_query..'\n((translation_unit) @Error (set! "priority" 101))\n'}})
+ ]]
+ -- expect everything to have Error highlight
+ screen:expect{grid=[[
+ {12:int}{8: x = INT_MAX;} |
+ {8:#define READ_STRING(x, y) (char_u *)read_string((x), (size_t)(y))}|
+ {8:#define foo void main() { \} |
+ {8: return 42; \} |
+ {8: }} |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]], attr_ids={
+ [1] = {bold = true, foreground = Screen.colors.Blue1};
+ [8] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red};
+ -- bold will not be overwritten at the moment
+ [12] = {background = Screen.colors.Red, bold = true, foreground = Screen.colors.Grey100};
+ }}
+ end)
end)
diff --git a/test/functional/treesitter/node_spec.lua b/test/functional/treesitter/node_spec.lua
new file mode 100644
index 0000000000..21c287644e
--- /dev/null
+++ b/test/functional/treesitter/node_spec.lua
@@ -0,0 +1,62 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local eq = helpers.eq
+local exec_lua = helpers.exec_lua
+local insert = helpers.insert
+local pending_c_parser = helpers.pending_c_parser
+
+before_each(clear)
+
+local function lua_eval(lua_expr)
+ return exec_lua("return " .. lua_expr)
+end
+
+describe('treesitter node API', function()
+ clear()
+
+ if pending_c_parser(pending) then
+ return
+ end
+
+ it('can move between siblings', function()
+ insert([[
+ int main(int x, int y, int z) {
+ return x + y * z
+ }
+ ]])
+
+ exec_lua([[
+ query = require"vim.treesitter.query"
+ parser = vim.treesitter.get_parser(0, "c")
+ tree = parser:parse()[1]
+ root = tree:root()
+ lang = vim.treesitter.inspect_language('c')
+
+ function node_text(node)
+ return query.get_node_text(node, 0)
+ end
+ ]])
+
+ exec_lua 'node = root:descendant_for_range(0, 11, 0, 16)'
+ eq('int x', lua_eval('node_text(node)'))
+
+ exec_lua 'node = node:next_sibling()'
+ eq(',', lua_eval('node_text(node)'))
+
+ exec_lua 'node = node:next_sibling()'
+ eq('int y', lua_eval('node_text(node)'))
+
+ exec_lua 'node = node:prev_sibling()'
+ eq(',', lua_eval('node_text(node)'))
+
+ exec_lua 'node = node:prev_sibling()'
+ eq('int x', lua_eval('node_text(node)'))
+
+ exec_lua 'node = node:next_named_sibling()'
+ eq('int y', lua_eval('node_text(node)'))
+
+ exec_lua 'node = node:prev_named_sibling()'
+ eq('int x', lua_eval('node_text(node)'))
+ end)
+end)
diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua
index d2f9148e8f..ffaa4141c4 100644
--- a/test/functional/treesitter/parser_spec.lua
+++ b/test/functional/treesitter/parser_spec.lua
@@ -10,9 +10,11 @@ local pending_c_parser = helpers.pending_c_parser
before_each(clear)
describe('treesitter parser API', function()
+ clear()
+ if pending_c_parser(pending) then return end
it('parses buffer', function()
- if helpers.pending_win32(pending) or pending_c_parser(pending) then return end
+ if helpers.pending_win32(pending) then return end
insert([[
int main() {
@@ -103,8 +105,6 @@ void ui_refresh(void)
}]]
it('allows to iterate over nodes children', function()
- if pending_c_parser(pending) then return end
-
insert(test_text);
local res = exec_lua([[
@@ -127,8 +127,6 @@ void ui_refresh(void)
end)
it('allows to get a child by field', function()
- if pending_c_parser(pending) then return end
-
insert(test_text);
local res = exec_lua([[
@@ -162,8 +160,6 @@ void ui_refresh(void)
]]
it("supports runtime queries", function()
- if pending_c_parser(pending) then return end
-
local ret = exec_lua [[
return require"vim.treesitter.query".get_query("c", "highlights").captures[1]
]]
@@ -172,8 +168,6 @@ void ui_refresh(void)
end)
it('support query and iter by capture', function()
- if pending_c_parser(pending) then return end
-
insert(test_text)
local res = exec_lua([[
@@ -203,8 +197,6 @@ void ui_refresh(void)
end)
it('support query and iter by match', function()
- if pending_c_parser(pending) then return end
-
insert(test_text)
local res = exec_lua([[
@@ -236,8 +228,6 @@ void ui_refresh(void)
end)
it('can match special regex characters like \\ * + ( with `vim-match?`', function()
- if pending_c_parser(pending) then return end
-
insert('char* astring = "\\n"; (1 + 1) * 2 != 2;')
local res = exec_lua([[
@@ -271,8 +261,6 @@ void ui_refresh(void)
end)
it('supports builtin query predicate any-of?', function()
- if pending_c_parser(pending) then return end
-
insert([[
#include <stdio.h>
@@ -330,8 +318,6 @@ void ui_refresh(void)
end)
it('allow loading query with escaped quotes and capture them with `lua-match?` and `vim-match?`', function()
- if pending_c_parser(pending) then return end
-
insert('char* astring = "Hello World!";')
local res = exec_lua([[
@@ -407,8 +393,6 @@ void ui_refresh(void)
it('allows to set simple ranges', function()
- if pending_c_parser(pending) then return end
-
insert(test_text)
local res = exec_lua [[
@@ -450,8 +434,6 @@ void ui_refresh(void)
eq(range_tbl, { { { 0, 0, 0, 17, 1, 508 } } })
end)
it("allows to set complex ranges", function()
- if pending_c_parser() then return end
-
insert(test_text)
local res = exec_lua [[
@@ -646,6 +628,19 @@ int x = INT_MAX;
{2, 29, 2, 68} -- READ_STRING_OK(x, y) (char_u *)read_string((x), (size_t)(y))
}, get_ranges())
end)
+ it("should list all directives", function()
+ local res_list = exec_lua[[
+ local query = require'vim.treesitter.query'
+
+ local list = query.list_directives()
+
+ table.sort(list)
+
+ return list
+ ]]
+
+ eq({ 'offset!', 'set!' }, res_list)
+ end)
end)
end)
diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua
index af709cd521..16ed3b9486 100644
--- a/test/functional/ui/bufhl_spec.lua
+++ b/test/functional/ui/bufhl_spec.lua
@@ -858,8 +858,8 @@ describe('Buffer highlighting', function()
it('works with cursorline', function()
command("set cursorline")
- screen:expect([[
- {14:^1 + 2 }{15:=}{16: 3}{14: }|
+ screen:expect{grid=[[
+ {14:^1 + 2 }{3:=}{2: 3}{14: }|
3 + {11:ERROR:} invalid syntax |
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
, 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
@@ -867,32 +867,32 @@ describe('Buffer highlighting', function()
{1:~ }|
{1:~ }|
|
- ]])
+ ]]}
feed('j')
- screen:expect([[
+ screen:expect{grid=[[
1 + 2 {3:=}{2: 3} |
- {14:^3 + }{11:ERROR:}{14: invalid syntax }|
+ {14:^3 + }{11:ERROR:} invalid syntax{14: }|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
, 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
x = 4 |
{1:~ }|
{1:~ }|
|
- ]])
+ ]]}
feed('j')
- screen:expect([[
+ screen:expect{grid=[[
1 + 2 {3:=}{2: 3} |
3 + {11:ERROR:} invalid syntax |
{14:^5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}|
- {14:, 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s}|
+ {14:, 5, 5, 5, 5, 5, 5, }Lorem ipsum dolor s|
x = 4 |
{1:~ }|
{1:~ }|
|
- ]])
+ ]]}
end)
it('works with color column', function()
@@ -910,11 +910,11 @@ describe('Buffer highlighting', function()
command("set colorcolumn=9")
screen:expect{grid=[[
- ^1 + 2 {3:=}{2: }{17:3} |
+ ^1 + 2 {3:=}{2: 3} |
3 + {11:ERROR:} invalid syntax |
5, 5, 5,{18: }5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5|
, 5, 5, 5, 5, 5, 5, Lorem ipsum dolor s|
- x = 4 {12:暗}{19:x}{12:事} |
+ x = 4 {12:暗x事} |
{1:~ }|
{1:~ }|
|
diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua
index 0ea8bab957..ad23402ff9 100644
--- a/test/functional/ui/cmdline_spec.lua
+++ b/test/functional/ui/cmdline_spec.lua
@@ -14,6 +14,8 @@ local function new_screen(opt)
[3] = {bold = true, reverse = true},
[4] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
[5] = {bold = true, foreground = Screen.colors.SeaGreen4},
+ [6] = {foreground = Screen.colors.Magenta},
+ [7] = {bold = true, foreground = Screen.colors.Brown},
})
return screen
end
@@ -267,7 +269,7 @@ local function test_cmdline(linegrid)
special = {'"', true},
}, {
firstc = "=",
- content = {{"1"}, {"+"}, {"2"}},
+ content = {{"1", 6}, {"+", 7}, {"2", 6}},
pos = 3,
}}
diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua
index f75f700fb5..9c035c728b 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 = 56
+ m.hl_id = 58
m.attr = {background = Screen.colors.DarkGray}
end
- if m.id_lm then m.id_lm = 57 end
+ if m.id_lm then m.id_lm = 59 end
end
-- Assert the new expectation.
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 98aafd8757..8074f91215 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -562,7 +562,7 @@ end]]
{5:l}{8:blen}{7:dy}{10:e}{7:text}{10:h}{7:-}{10:_}{7:here}ell, count = unpack(item) |
{5:i}{12:c}{11:ombining color} {13:nil} {5:then} |
{11:replacing color}d_cell |
- {5:e}{8:bl}{14:endy}{15:i}{14:text}{15:o}{14:-}{15:o}{14:h}{7:ere} |
+ {5:e}{8:bl}{7:endy}{10: }{7:text}{10: }{7:-}{10: }{7:here} |
{5:f}{12:co}{11:mbini}{16:n}{11:g color}t {5:or} {13:1}) {5:do} |
{11:replacing color} line[colpos] |
cell.text = text |
@@ -697,4 +697,604 @@ end]]
|
]]}
end)
+
+ it('can have virtual text which combines foreground and backround groups', function()
+ screen:set_default_attr_ids {
+ [1] = {bold=true, foreground=Screen.colors.Blue};
+ [2] = {background = tonumber('0x123456'), foreground = tonumber('0xbbbbbb')};
+ [3] = {background = tonumber('0x123456'), foreground = tonumber('0xcccccc')};
+ [4] = {background = tonumber('0x234567'), foreground = tonumber('0xbbbbbb')};
+ [5] = {background = tonumber('0x234567'), foreground = tonumber('0xcccccc')};
+ [6] = {bold = true, foreground = tonumber('0xcccccc'), background = tonumber('0x234567')};
+ }
+
+ exec [[
+ hi BgOne guibg=#123456
+ hi BgTwo guibg=#234567
+ hi FgEin guifg=#bbbbbb
+ hi FgZwei guifg=#cccccc
+ hi VeryBold gui=bold
+ ]]
+
+ meths.buf_set_extmark(0, ns, 0, 0, { virt_text={
+ {'a', {'BgOne', 'FgEin'}};
+ {'b', {'BgOne', 'FgZwei'}};
+ {'c', {'BgTwo', 'FgEin'}};
+ {'d', {'BgTwo', 'FgZwei'}};
+ {'X', {'BgTwo', 'FgZwei', 'VeryBold'}};
+ }})
+
+ screen:expect{grid=[[
+ ^ {2:a}{3:b}{4:c}{5:d}{6:X} |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+ end)
+
+ it('does not crash when deleting a cleared buffer #15212', function()
+ exec_lua [[
+ ns = vim.api.nvim_create_namespace("myplugin")
+ vim.api.nvim_buf_set_extmark(0, ns, 0, 0, {virt_text = {{"a"}}, end_col = 0})
+ ]]
+ screen:expect{grid=[[
+ ^ a |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ exec_lua [[
+ vim.api.nvim_buf_clear_namespace(0, ns, 0, -1)
+ vim.cmd("bdelete")
+ ]]
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+ helpers.assert_alive()
+ end)
+end)
+
+describe('decorations: virtual lines', function()
+ local screen, ns
+ before_each(function()
+ clear()
+ screen = Screen.new(50, 12)
+ screen:attach()
+ screen:set_default_attr_ids {
+ [1] = {bold=true, foreground=Screen.colors.Blue};
+ [2] = {foreground = Screen.colors.Cyan4};
+ [3] = {background = Screen.colors.Yellow1};
+ [4] = {bold = true};
+ [5] = {background = Screen.colors.Yellow, foreground = Screen.colors.Blue};
+ [6] = {foreground = Screen.colors.Blue};
+ [7] = {foreground = Screen.colors.SlateBlue};
+ [8] = {background = Screen.colors.WebGray, foreground = Screen.colors.DarkBlue};
+ [9] = {foreground = Screen.colors.Brown};
+ }
+
+ ns = meths.create_namespace 'test'
+ end)
+
+ local example_text = [[
+if (h->n_buckets < new_n_buckets) { // expand
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t));
+ h->keys = new_keys;
+ if (kh_is_map && val_size) {
+ char *new_vals = krealloc( h->vals_buf, new_n_buckets * val_size);
+ h->vals_buf = new_vals;
+ }
+}]]
+
+ it('works with one line', function()
+ insert(example_text)
+ feed 'gg'
+ meths.buf_set_extmark(0, ns, 1, 33, {
+ virt_lines={ {{">> ", "NonText"}, {"krealloc", "Identifier"}, {": change the size of an allocation"}}};
+ virt_lines_above=true;
+ })
+
+ screen:expect{grid=[[
+ ^if (h->n_buckets < new_n_buckets) { // expand |
+ {1:>> }{2:krealloc}: change the size of an allocation |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ } |
+ |
+ ]]}
+
+ feed '/krealloc<cr>'
+ screen:expect{grid=[[
+ if (h->n_buckets < new_n_buckets) { // expand |
+ {1:>> }{2:krealloc}: change the size of an allocation |
+ khkey_t *new_keys = (khkey_t *){3:^krealloc}((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = {3:krealloc}( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ } |
+ /krealloc |
+ ]]}
+
+ -- virtual line remains anchored to the extmark
+ feed 'i<cr>'
+ screen:expect{grid=[[
+ if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *) |
+ {1:>> }{2:krealloc}: change the size of an allocation |
+ {3:^krealloc}((void *)h->keys, new_n_buckets * sizeof(k|
+ hkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = {3:krealloc}( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ {4:-- INSERT --} |
+ ]]}
+
+ feed '<esc>3+'
+ screen:expect{grid=[[
+ if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *) |
+ {1:>> }{2:krealloc}: change the size of an allocation |
+ {3:krealloc}((void *)h->keys, new_n_buckets * sizeof(k|
+ hkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ ^char *new_vals = {3:krealloc}( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ |
+ ]]}
+
+ meths.buf_set_extmark(0, ns, 5, 0, {
+ virt_lines = { {{"^^ REVIEW:", "Todo"}, {" new_vals variable seems unneccesary?", "Comment"}} };
+ })
+ -- TODO: what about the cursor??
+ screen:expect{grid=[[
+ if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *) |
+ {3:krealloc}((void *)h->keys, new_n_buckets * sizeof(k|
+ hkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = {3:krealloc}( h->vals_buf, new_n_|
+ buck^ets * val_size); |
+ {5:^^ REVIEW:}{6: new_vals variable seems unneccesary?} |
+ h->vals_buf = new_vals; |
+ } |
+ |
+ ]]}
+
+ meths.buf_clear_namespace(0, ns, 0, -1)
+ screen:expect{grid=[[
+ if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *) |
+ {3:krealloc}((void *)h->keys, new_n_buckets * sizeof(k|
+ hkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = {3:krealloc}( h->vals_buf, new_n_|
+ buck^ets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ } |
+ |
+ ]]}
+ end)
+
+
+ it('works with text at the beginning of the buffer', function()
+ insert(example_text)
+ feed 'gg'
+
+ screen:expect{grid=[[
+ ^if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ } |
+ {1:~ }|
+ |
+ ]]}
+
+ meths.buf_set_extmark(0, ns, 0, 0, {
+ virt_lines={
+ {{"refactor(khash): ", "Special"}, {"take size of values as parameter"}};
+ {{"Author: Dev Devsson, "}, {"Tue Aug 31 10:13:37 2021", "Comment"}};
+ };
+ virt_lines_above=true;
+ right_gravity=false;
+ })
+
+ -- placing virt_text on topline does not automatically cause a scroll
+ screen:expect{grid=[[
+ ^if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ } |
+ {1:~ }|
+ |
+ ]], unchanged=true}
+
+ feed '<c-b>'
+ screen:expect{grid=[[
+ {7:refactor(khash): }take size of values as parameter |
+ Author: Dev Devsson, {6:Tue Aug 31 10:13:37 2021} |
+ ^if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ |
+ ]]}
+ end)
+
+ it('works with text et the end of the buffer', function()
+ insert(example_text)
+ feed 'G'
+
+ screen:expect{grid=[[
+ if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ ^} |
+ {1:~ }|
+ |
+ ]]}
+
+ local id = meths.buf_set_extmark(0, ns, 7, 0, {
+ virt_lines={{{"Grugg"}}};
+ right_gravity=false;
+ })
+
+ screen:expect{grid=[[
+ if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ ^} |
+ Grugg |
+ |
+ ]]}
+
+ meths.buf_del_extmark(0, ns, id)
+ screen:expect{grid=[[
+ if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ ^} |
+ {1:~ }|
+ |
+ ]]}
+ end)
+
+ it('works with a block scrolling up', function()
+ screen:try_resize(30, 7)
+ insert("aa\nbb\ncc\ndd\nee\nff\ngg\nhh")
+ feed 'gg'
+
+ meths.buf_set_extmark(0, ns, 6, 0, {
+ virt_lines={
+ {{"they see me"}};
+ {{"scrolling", "Special"}};
+ {{"they"}};
+ {{"hatin'", "Special"}};
+ };
+ })
+
+ screen:expect{grid=[[
+ ^aa |
+ bb |
+ cc |
+ dd |
+ ee |
+ ff |
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ ^bb |
+ cc |
+ dd |
+ ee |
+ ff |
+ gg |
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ ^cc |
+ dd |
+ ee |
+ ff |
+ gg |
+ they see me |
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ ^dd |
+ ee |
+ ff |
+ gg |
+ they see me |
+ {7:scrolling} |
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ ^ee |
+ ff |
+ gg |
+ they see me |
+ {7:scrolling} |
+ they |
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ ^ff |
+ gg |
+ they see me |
+ {7:scrolling} |
+ they |
+ {7:hatin'} |
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ ^gg |
+ they see me |
+ {7:scrolling} |
+ they |
+ {7:hatin'} |
+ hh |
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ they see me |
+ {7:scrolling} |
+ they |
+ {7:hatin'} |
+ ^hh |
+ {1:~ }|
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ {7:scrolling} |
+ they |
+ {7:hatin'} |
+ ^hh |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ they |
+ {7:hatin'} |
+ ^hh |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ {7:hatin'} |
+ ^hh |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+
+ feed '<c-e>'
+ screen:expect{grid=[[
+ ^hh |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]]}
+ end)
+
+ it('works with sign and numbercolumns', function()
+ insert(example_text)
+ feed 'gg'
+ command 'set number signcolumn=yes'
+ screen:expect{grid=[[
+ {8: }{9: 1 }^if (h->n_buckets < new_n_buckets) { // expan|
+ {8: }{9: }d |
+ {8: }{9: 2 } khkey_t *new_keys = (khkey_t *)krealloc((v|
+ {8: }{9: }oid *)h->keys, new_n_buckets * sizeof(khkey_|
+ {8: }{9: }t)); |
+ {8: }{9: 3 } h->keys = new_keys; |
+ {8: }{9: 4 } if (kh_is_map && val_size) { |
+ {8: }{9: 5 } char *new_vals = krealloc( h->vals_buf, |
+ {8: }{9: }new_n_buckets * val_size); |
+ {8: }{9: 6 } h->vals_buf = new_vals; |
+ {8: }{9: 7 } } |
+ |
+ ]]}
+
+ meths.buf_set_extmark(0, ns, 2, 0, {
+ virt_lines={
+ {{"Some special", "Special"}};
+ {{"remark about codes", "Comment"}};
+ };
+ })
+
+ screen:expect{grid=[[
+ {8: }{9: 1 }^if (h->n_buckets < new_n_buckets) { // expan|
+ {8: }{9: }d |
+ {8: }{9: 2 } khkey_t *new_keys = (khkey_t *)krealloc((v|
+ {8: }{9: }oid *)h->keys, new_n_buckets * sizeof(khkey_|
+ {8: }{9: }t)); |
+ {8: }{9: 3 } h->keys = new_keys; |
+ {8: }{9: }{7:Some special} |
+ {8: }{9: }{6:remark about codes} |
+ {8: }{9: 4 } if (kh_is_map && val_size) { |
+ {8: }{9: 5 } char *new_vals = krealloc( h->vals_buf, |
+ {8: }{9: }new_n_buckets * val_size); |
+ |
+ ]]}
+
+ meths.buf_set_extmark(0, ns, 2, 0, {
+ virt_lines={
+ {{"Some special", "Special"}};
+ {{"remark about codes", "Comment"}};
+ };
+ virt_lines_leftcol=true;
+ })
+ screen:expect{grid=[[
+ {8: }{9: 1 }^if (h->n_buckets < new_n_buckets) { // expan|
+ {8: }{9: }d |
+ {8: }{9: 2 } khkey_t *new_keys = (khkey_t *)krealloc((v|
+ {8: }{9: }oid *)h->keys, new_n_buckets * sizeof(khkey_|
+ {8: }{9: }t)); |
+ {8: }{9: 3 } h->keys = new_keys; |
+ {7:Some special} |
+ {6:remark about codes} |
+ {8: }{9: 4 } if (kh_is_map && val_size) { |
+ {8: }{9: 5 } char *new_vals = krealloc( h->vals_buf, |
+ {8: }{9: }new_n_buckets * val_size); |
+ |
+ ]]}
+ end)
+
+
+ it('works with hard tabs', function()
+ insert(example_text)
+ feed 'gg'
+ meths.buf_set_extmark(0, ns, 1, 0, {
+ virt_lines={ {{">>", "NonText"}, {"\tvery\ttabby", "Identifier"}, {"text\twith\ttabs"}}};
+ })
+ screen:expect{grid=[[
+ ^if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ {1:>>}{2: very tabby}text with tabs |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ } |
+ |
+ ]]}
+
+ command 'set tabstop=4'
+ screen:expect{grid=[[
+ ^if (h->n_buckets < new_n_buckets) { // expand |
+ khkey_t *new_keys = (khkey_t *)krealloc((void *)|
+ h->keys, new_n_buckets * sizeof(khkey_t)); |
+ {1:>>}{2: very tabby}text with tabs |
+ h->keys = new_keys; |
+ if (kh_is_map && val_size) { |
+ char *new_vals = krealloc( h->vals_buf, new_n_|
+ buckets * val_size); |
+ h->vals_buf = new_vals; |
+ } |
+ } |
+ |
+ ]]}
+ end)
+
end)
diff --git a/test/functional/ui/diff_spec.lua b/test/functional/ui/diff_spec.lua
index a8d9fb02fc..df750a1a68 100644
--- a/test/functional/ui/diff_spec.lua
+++ b/test/functional/ui/diff_spec.lua
@@ -1057,7 +1057,7 @@ it('diff updates line numbers below filler lines', function()
vnew
call setline(1, ['a', 'a', 'a', 'x', 'x', 'x', 'b', 'b', 'b', 'b', 'b'])
windo diffthis
- setlocal number rnu foldcolumn=0
+ setlocal number rnu cursorline cursorlineopt=number foldcolumn=0
]])
screen:expect([[
{1: }a {3:│}{10:1 }^a |
@@ -1109,7 +1109,7 @@ it('diff updates line numbers below filler lines', function()
{3:[No Name] [+] }{7:[No Name] [+] }|
|
]])
- command("set signcolumn number tgc cursorline")
+ command("set signcolumn number tgc cursorline cursorlineopt=number,line")
command("hi CursorLineNr guibg=red")
screen:expect{grid=[[
{1: }a {3:│}{11: 2 }a |
@@ -1128,3 +1128,72 @@ it('diff updates line numbers below filler lines', function()
signcolumn=auto |
]]}
end)
+
+it('Align the filler lines when changing text in diff mode', function()
+ clear()
+ local screen = Screen.new(40, 20)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.Gray};
+ [2] = {background = Screen.colors.LightCyan, foreground = Screen.colors.Blue1, bold = true};
+ [3] = {reverse = true};
+ [4] = {background = Screen.colors.LightBlue};
+ [5] = {background = Screen.colors.LightMagenta};
+ [6] = {background = Screen.colors.Red, bold = true};
+ [7] = {foreground = Screen.colors.Blue1, bold = true};
+ [8] = {reverse = true, bold = true};
+ })
+ source([[
+ call setline(1, range(1, 15))
+ vnew
+ call setline(1, range(9, 15))
+ windo diffthis
+ wincmd h
+ exe "normal Gl5\<C-E>"
+ ]])
+ screen:expect{grid=[[
+ {1: }{2:------------------}{3:│}{1: }{4:6 }|
+ {1: }{2:------------------}{3:│}{1: }{4:7 }|
+ {1: }{2:------------------}{3:│}{1: }{4:8 }|
+ {1: }9 {3:│}{1: }9 |
+ {1: }10 {3:│}{1: }10 |
+ {1: }11 {3:│}{1: }11 |
+ {1: }12 {3:│}{1: }12 |
+ {1: }13 {3:│}{1: }13 |
+ {1: }14 {3:│}{1: }14 |
+ {1:- }1^5 {3:│}{1:- }15 |
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {8:[No Name] [+] }{3:[No Name] [+] }|
+ |
+ ]]}
+ feed('ax<Esc>')
+ screen:expect{grid=[[
+ {1: }{2:------------------}{3:│}{1: }{4:6 }|
+ {1: }{2:------------------}{3:│}{1: }{4:7 }|
+ {1: }{2:------------------}{3:│}{1: }{4:8 }|
+ {1: }9 {3:│}{1: }9 |
+ {1: }10 {3:│}{1: }10 |
+ {1: }11 {3:│}{1: }11 |
+ {1: }12 {3:│}{1: }12 |
+ {1: }13 {3:│}{1: }13 |
+ {1: }14 {3:│}{1: }14 |
+ {1: }{5:15}{6:^x}{5: }{3:│}{1: }{5:15 }|
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {7:~ }{3:│}{7:~ }|
+ {8:[No Name] [+] }{3:[No Name] [+] }|
+ |
+ ]]}
+end)
diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index 61ed0a65b0..ccf5f963d1 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -74,7 +74,8 @@ describe('float window', function()
funcs.win_execute(win, 'bwipe!')
end)
- it('win_execute() call commands that not allowed' , function()
+ it("win_execute() call commands that are not allowed when 'hidden' is not set" , function()
+ command('set nohidden')
local buf = meths.create_buf(false, false)
meths.buf_set_lines(buf, 0, -1, true, {'the floatwin'})
local win = meths.open_win(buf, true, {relative='win', width=16, height=1, row=0, col=10})
@@ -152,6 +153,132 @@ describe('float window', function()
eq(10, width)
end)
+ it('opened with correct position', function()
+ local pos = exec_lua([[
+ local bufnr = vim.api.nvim_create_buf(false, true)
+
+ local opts = {
+ width = 10,
+ height = 10,
+ col = 7,
+ row = 9,
+ relative = 'editor',
+ style = 'minimal'
+ }
+
+ local win_id = vim.api.nvim_open_win(bufnr, false, opts)
+
+ return vim.api.nvim_win_get_position(win_id)
+ ]])
+
+ eq(9, pos[1])
+ eq(7, pos[2])
+ end)
+
+ it('opened with correct position relative to the cursor', function()
+ local pos = exec_lua([[
+ local bufnr = vim.api.nvim_create_buf(false, true)
+
+ local opts = {
+ width = 10,
+ height = 10,
+ col = 7,
+ row = 9,
+ relative = 'cursor',
+ style = 'minimal'
+ }
+
+ local win_id = vim.api.nvim_open_win(bufnr, false, opts)
+
+ return vim.api.nvim_win_get_position(win_id)
+ ]])
+
+ eq(9, pos[1])
+ eq(7, pos[2])
+ end)
+
+ it('opened with correct position relative to another window', function()
+ local pos = exec_lua([[
+ local bufnr = vim.api.nvim_create_buf(false, true)
+
+ local par_opts = {
+ width = 50,
+ height = 50,
+ col = 7,
+ row = 9,
+ relative = 'editor',
+ style = 'minimal'
+ }
+
+ local par_win_id = vim.api.nvim_open_win(bufnr, false, par_opts)
+
+ local opts = {
+ width = 10,
+ height = 10,
+ col = 7,
+ row = 9,
+ relative = 'win',
+ style = 'minimal',
+ win = par_win_id
+ }
+
+ local win_id = vim.api.nvim_open_win(bufnr, false, opts)
+
+ return vim.api.nvim_win_get_position(win_id)
+ ]])
+
+ eq(18, pos[1])
+ eq(14, pos[2])
+ end)
+
+
+ it('opened with correct position relative to another relative window', function()
+ local pos = exec_lua([[
+ local bufnr = vim.api.nvim_create_buf(false, true)
+
+ local root_opts = {
+ width = 50,
+ height = 50,
+ col = 7,
+ row = 9,
+ relative = 'editor',
+ style = 'minimal'
+ }
+
+ local root_win_id = vim.api.nvim_open_win(bufnr, false, root_opts)
+
+ local par_opts = {
+ width = 20,
+ height = 20,
+ col = 2,
+ row = 3,
+ relative = 'win',
+ win = root_win_id,
+ style = 'minimal'
+ }
+
+ local par_win_id = vim.api.nvim_open_win(bufnr, false, par_opts)
+
+ local opts = {
+ width = 10,
+ height = 10,
+ col = 3,
+ row = 2,
+ relative = 'win',
+ win = par_win_id,
+ style = 'minimal'
+ }
+
+ local win_id = vim.api.nvim_open_win(bufnr, false, opts)
+
+ return vim.api.nvim_win_get_position(win_id)
+ ]])
+
+ eq(14, pos[1])
+ eq(12, pos[2])
+ end)
+
+
local function with_ext_multigrid(multigrid)
local screen
before_each(function()
@@ -620,6 +747,134 @@ describe('float window', function()
end
end)
+ it("would not break 'minimal' style with signcolumn=auto:[min]-[max]", function()
+ command('set number')
+ command('set signcolumn=auto:1-3')
+ command('set colorcolumn=1')
+ command('set cursorline')
+ command('set foldcolumn=1')
+ command('hi NormalFloat guibg=#333333')
+ feed('ix<cr>y<cr><esc>gg')
+ local win = meths.open_win(0, false, {relative='editor', width=20, height=4, row=4, col=10, style='minimal'})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ {19: }{20: 1 }{22:^x}{21: }|
+ {19: }{14: 2 }{22:y} |
+ {19: }{14: 3 }{22: } |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ {15:x }|
+ {15:y }|
+ {15: }|
+ {15: }|
+ ]], float_pos={[4] = {{id = 1001}, "NW", 1, 4, 10, true}}}
+ else
+ screen:expect{grid=[[
+ {19: }{20: 1 }{22:^x}{21: }|
+ {19: }{14: 2 }{22:y} |
+ {19: }{14: 3 }{22: } {15:x } |
+ {0:~ }{15:y }{0: }|
+ {0:~ }{15: }{0: }|
+ {0:~ }{15: }{0: }|
+ |
+ ]]}
+ end
+
+ command('sign define piet1 text=𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄ texthl=Search')
+ command('sign place 1 line=1 name=piet1 buffer=1')
+ -- signcolumn=auto:1-3 still works if there actually are signs
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ {19: }{17:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{20: 1 }{22:^x}{21: }|
+ {19: }{14: 2 }{22:y} |
+ {19: }{14: 3 }{22: } |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ {17:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{15:x }|
+ {19: }{15:y }|
+ {19: }{15: }|
+ {15: }|
+ ]], float_pos={[4] = {{id = 1001}, "NW", 1, 4, 10, true}}}
+
+ else
+ screen:expect([[
+ {19: }{17:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{20: 1 }{22:^x}{21: }|
+ {19: }{14: 2 }{22:y} |
+ {19: }{14: 3 }{22: } {17:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{15:x } |
+ {0:~ }{19: }{15:y }{0: }|
+ {0:~ }{19: }{15: }{0: }|
+ {0:~ }{15: }{0: }|
+ |
+ ]])
+ end
+ command('sign unplace 1 buffer=1')
+
+ local buf = meths.create_buf(false, true)
+ meths.win_set_buf(win, buf)
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [3:----------------------------------------]|
+ ## grid 2
+ {19: }{20: 1 }{22:^x}{21: }|
+ {19: }{14: 2 }{22:y} |
+ {19: }{14: 3 }{22: } |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ |
+ ## grid 4
+ {15: }|
+ {15: }|
+ {15: }|
+ {15: }|
+ ]], float_pos={[4] = {{id = 1001}, "NW", 1, 4, 10, true}}}
+ else
+ screen:expect([[
+ {19: }{20: 1 }{22:^x}{21: }|
+ {19: }{14: 2 }{22:y} |
+ {19: }{14: 3 }{22: } {15: } |
+ {0:~ }{15: }{0: }|
+ {0:~ }{15: }{0: }|
+ {0:~ }{15: }{0: }|
+ |
+ ]])
+ end
+ end)
+
it('can have border', function()
local buf = meths.create_buf(false, false)
meths.buf_set_lines(buf, 0, -1, true, {' halloj! ',
@@ -653,8 +908,8 @@ describe('float window', function()
]], float_pos={
[5] = { { id = 1002 }, "NW", 1, 2, 5, true }
}, win_viewport={
- [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0};
- [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2};
}}
else
screen:expect{grid=[[
@@ -696,8 +951,8 @@ describe('float window', function()
]], float_pos={
[5] = { { id = 1002 }, "NW", 1, 2, 5, true }
}, win_viewport={
- [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0};
- [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2};
}}
else
screen:expect{grid=[[
@@ -739,8 +994,8 @@ describe('float window', function()
]], float_pos={
[5] = { { id = 1002 }, "NW", 1, 2, 5, true }
}, win_viewport={
- [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0};
- [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2};
}}
else
screen:expect{grid=[[
@@ -782,8 +1037,8 @@ describe('float window', function()
]], float_pos={
[5] = { { id = 1002 }, "NW", 1, 2, 5, true }
}, win_viewport={
- [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0};
- [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2};
}}
else
screen:expect{grid=[[
@@ -826,8 +1081,8 @@ describe('float window', function()
]], float_pos={
[5] = { { id = 1002 }, "NW", 1, 2, 5, true }
}, win_viewport={
- [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0};
- [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2};
}}
else
screen:expect{grid=[[
@@ -867,8 +1122,8 @@ describe('float window', function()
]], float_pos={
[5] = { { id = 1002 }, "NW", 1, 2, 5, true }
}, win_viewport={
- [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0};
- [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2};
}}
else
screen:expect{grid=[[
@@ -908,8 +1163,8 @@ describe('float window', function()
]], float_pos={
[5] = { { id = 1002 }, "NW", 1, 2, 5, true }
}, win_viewport={
- [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0};
- [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2};
}}
else
screen:expect{grid=[[
@@ -958,8 +1213,8 @@ describe('float window', function()
]], float_pos={
[5] = { { id = 1002 }, "NW", 1, 2, 5, true }
}, win_viewport={
- [2] = {win = {id = 1000}, topline = 0, botline = 6, curline = 5, curcol = 0};
- [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ [2] = {win = {id = 1000}, topline = 0, botline = 6, curline = 5, curcol = 0, linecount = 6};
+ [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 2};
}}
else
screen:expect{grid=[[
@@ -1009,8 +1264,8 @@ describe('float window', function()
]], float_pos={
[4] = { { id = 1001 }, "NW", 1, 0, 0, true }
}, win_viewport={
- [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0};
- [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ [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=[[
@@ -1067,8 +1322,8 @@ describe('float window', function()
]], float_pos={
[5] = { { id = 1002 }, "NW", 1, 0, 5, true }
}, win_viewport={
- [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0};
- [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 2, curcol = 0};
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 2, curcol = 0, linecount = 3};
}}
else
screen:expect{grid=[[
@@ -1126,8 +1381,8 @@ describe('float window', function()
[5] = { { id = 1002 }, "NW", 1, 0, 5, true, 50 },
[6] = { { id = -1 }, "NW", 5, 4, 0, false, 100 }
}, win_viewport={
- [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0};
- [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 2, curcol = 3};
+ [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount=1};
+ [5] = {win = {id = 1002}, topline = 0, botline = 3, curline = 2, curcol = 3, linecount=3};
}}
else
screen:expect{grid=[[
@@ -1576,6 +1831,7 @@ describe('float window', function()
botline = 3,
curline = 0,
curcol = 3,
+ linecount = 2,
win = { id = 1000 }
},
[4] = {
@@ -1583,6 +1839,7 @@ describe('float window', function()
botline = 3,
curline = 0,
curcol = 3,
+ linecount = 2,
win = { id = 1001 }
},
[5] = {
@@ -1590,6 +1847,7 @@ describe('float window', function()
botline = 2,
curline = 0,
curcol = 0,
+ linecount = 1,
win = { id = 1002 }
}
}}
@@ -4907,7 +5165,7 @@ describe('float window', function()
]])
end
- eq(2, eval('1+1'))
+ assert_alive()
end)
it("o (:only) non-float", function()
@@ -6210,8 +6468,8 @@ describe('float window', function()
]], float_pos={
[4] = { { id = 1001 }, "NW", 1, 2, 5, true };
}, win_viewport={
- [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0};
- [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ [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=[[
@@ -6267,10 +6525,10 @@ describe('float window', function()
[5] = { { id = 1002 }, "NW", 1, 3, 8, true };
[6] = { { id = 1003 }, "NW", 1, 4, 10, true };
}, win_viewport={
- [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0};
- [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0};
- [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0};
- [6] = {win = {id = 1003}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ [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};
+ [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount=1};
+ [6] = {win = {id = 1003}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount=1};
}}
else
screen:expect{grid=[[
@@ -6315,8 +6573,8 @@ describe('float window', function()
]], float_pos={
[4] = { { id = 1001 }, "NW", 1, 2, 5, true };
}, win_viewport={
- [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0};
- [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ [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=[[
@@ -6372,10 +6630,10 @@ describe('float window', function()
[5] = { { id = 1002 }, "NW", 1, 4, 10, true };
[6] = { { id = 1003 }, "NW", 1, 3, 8, true };
}, win_viewport={
- [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0};
- [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0};
- [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0};
- [6] = {win = {id = 1003}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ [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};
+ [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [6] = {win = {id = 1003}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
}}
else
screen:expect{grid=[[
@@ -6435,10 +6693,10 @@ describe('float window', function()
[5] = {{id = 1002}, "NW", 1, 2, 6, true, 50};
[6] = {{id = 1003}, "NW", 1, 3, 7, true, 40};
}, win_viewport={
- [2] = {win = {id = 1000}, topline = 0, botline = 2, curline = 0, curcol = 0};
- [4] = {win = {id = 1001}, topline = 0, botline = 2, curline = 0, curcol = 0};
- [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0};
- [6] = {win = {id = 1003}, topline = 0, botline = 2, curline = 0, curcol = 0};
+ [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};
+ [5] = {win = {id = 1002}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
+ [6] = {win = {id = 1003}, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1};
}}
else
screen:expect{grid=[[
diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua
index 8883ad8270..249686234c 100644
--- a/test/functional/ui/fold_spec.lua
+++ b/test/functional/ui/fold_spec.lua
@@ -85,7 +85,7 @@ describe("folded lines", function()
end)
it("highlighting with relative line numbers", function()
- command("set relativenumber foldmethod=marker")
+ command("set relativenumber cursorline cursorlineopt=number foldmethod=marker")
feed_command("set foldcolumn=2")
funcs.setline(1, '{{{1')
funcs.setline(2, 'line 1')
diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua
index 8992ee27ce..c00d30fe32 100644
--- a/test/functional/ui/highlight_spec.lua
+++ b/test/functional/ui/highlight_spec.lua
@@ -789,7 +789,7 @@ describe("'listchars' highlight", function()
[0] = {bold=true, foreground=Screen.colors.Blue},
[1] = {background=Screen.colors.Grey90},
[2] = {foreground=Screen.colors.Red},
- [3] = {foreground=Screen.colors.Green1},
+ [3] = {foreground=Screen.colors.X11Green, background=Screen.colors.Red1},
})
feed_command('highlight clear ModeMsg')
feed_command('highlight Whitespace guifg=#FF0000')
@@ -912,6 +912,97 @@ describe('CursorLine highlight', function()
]])
end)
+ it("'cursorlineopt' screenline", function()
+ local screen = Screen.new(20,5)
+ screen:set_default_attr_ids({
+ [1] = {foreground = Screen.colors.Black, background = Screen.colors.White};
+ [2] = {foreground = Screen.colors.Yellow};
+ [3] = {foreground = Screen.colors.Red, background = Screen.colors.Green};
+ [4] = {foreground = Screen.colors.Green, background = Screen.colors.Red};
+ })
+ screen:attach()
+
+ feed_command('set wrap cursorline cursorlineopt=screenline')
+ feed_command('set showbreak=>>>')
+ feed_command('highlight clear NonText')
+ feed_command('highlight clear CursorLine')
+ feed_command('highlight NonText guifg=Yellow gui=NONE')
+ feed_command('highlight LineNr guifg=Red guibg=Green gui=NONE')
+ feed_command('highlight CursorLine guifg=Black guibg=White gui=NONE')
+ feed_command('highlight CursorLineNr guifg=Green guibg=Red gui=NONE')
+
+ feed('30iø<esc>o<esc>30ia<esc>')
+
+ -- CursorLine should not apply to 'showbreak' when 'cursorlineopt' contains "screenline"
+ screen:expect([[
+ øøøøøøøøøøøøøøøøøøøø|
+ {2:>>>}øøøøøøøøøø |
+ aaaaaaaaaaaaaaaaaaaa|
+ {2:>>>}{1:aaaaaaaaa^a }|
+ |
+ ]])
+ feed('gk')
+ screen:expect([[
+ øøøøøøøøøøøøøøøøøøøø|
+ {2:>>>}øøøøøøøøøø |
+ {1:aaaaaaaaaaaa^aaaaaaaa}|
+ {2:>>>}aaaaaaaaaa |
+ |
+ ]])
+ feed('k')
+ screen:expect([[
+ {1:øøøøøøøøøøøø^øøøøøøøø}|
+ {2:>>>}øøøøøøøøøø |
+ aaaaaaaaaaaaaaaaaaaa|
+ {2:>>>}aaaaaaaaaa |
+ |
+ ]])
+
+ -- CursorLineNr should not apply to line number when 'cursorlineopt' does not contain "number"
+ feed_command('set relativenumber numberwidth=2')
+ screen:expect([[
+ {3:0 }{1:øøøøøøøøøøøø^øøøøøø}|
+ {3: }{2:>>>}øøøøøøøøøøøø |
+ {3:1 }aaaaaaaaaaaaaaaaaa|
+ {3: }{2:>>>}aaaaaaaaaaaa |
+ |
+ ]])
+
+ -- CursorLineNr should apply to line number when 'cursorlineopt' contains "number"
+ feed_command('set cursorlineopt+=number')
+ screen:expect([[
+ {4:0 }{1:øøøøøøøøøøøø^øøøøøø}|
+ {3: }{2:>>>}øøøøøøøøøøøø |
+ {3:1 }aaaaaaaaaaaaaaaaaa|
+ {3: }{2:>>>}aaaaaaaaaaaa |
+ |
+ ]])
+ feed('gj')
+ screen:expect([[
+ {4:0 }øøøøøøøøøøøøøøøøøø|
+ {3: }{2:>>>}{1:øøøøøøøøø^øøø }|
+ {3:1 }aaaaaaaaaaaaaaaaaa|
+ {3: }{2:>>>}aaaaaaaaaaaa |
+ |
+ ]])
+ feed('gj')
+ screen:expect([[
+ {3:1 }øøøøøøøøøøøøøøøøøø|
+ {3: }{2:>>>}øøøøøøøøøøøø |
+ {4:0 }{1:aaaaaaaaaaaa^aaaaaa}|
+ {3: }{2:>>>}aaaaaaaaaaaa |
+ |
+ ]])
+ feed('gj')
+ screen:expect([[
+ {3:1 }øøøøøøøøøøøøøøøøøø|
+ {3: }{2:>>>}øøøøøøøøøøøø |
+ {4:0 }aaaaaaaaaaaaaaaaaa|
+ {3: }{2:>>>}{1:aaaaaaaaa^aaa }|
+ |
+ ]])
+ end)
+
it('always updated. vim-patch:8.1.0849', function()
local screen = Screen.new(50,5)
screen:set_default_attr_ids({
@@ -1201,6 +1292,75 @@ describe("MsgSeparator highlight and msgsep fillchar", function()
end)
end)
+describe("'number' and 'relativenumber' highlight", function()
+ before_each(clear)
+
+ it('LineNr, LineNrAbove and LineNrBelow', function()
+ local screen = Screen.new(20,10)
+ screen:set_default_attr_ids({
+ [1] = {foreground = Screen.colors.Red},
+ [2] = {foreground = Screen.colors.Blue},
+ [3] = {foreground = Screen.colors.Green},
+ })
+ screen:attach()
+ command('set number relativenumber')
+ command('call setline(1, range(50))')
+ command('highlight LineNr guifg=Red')
+ feed('4j')
+ screen:expect([[
+ {1: 4 }0 |
+ {1: 3 }1 |
+ {1: 2 }2 |
+ {1: 1 }3 |
+ {1:5 }^4 |
+ {1: 1 }5 |
+ {1: 2 }6 |
+ {1: 3 }7 |
+ {1: 4 }8 |
+ |
+ ]])
+ command('highlight LineNrAbove guifg=Blue')
+ screen:expect([[
+ {2: 4 }0 |
+ {2: 3 }1 |
+ {2: 2 }2 |
+ {2: 1 }3 |
+ {1:5 }^4 |
+ {1: 1 }5 |
+ {1: 2 }6 |
+ {1: 3 }7 |
+ {1: 4 }8 |
+ |
+ ]])
+ command('highlight LineNrBelow guifg=Green')
+ screen:expect([[
+ {2: 4 }0 |
+ {2: 3 }1 |
+ {2: 2 }2 |
+ {2: 1 }3 |
+ {1:5 }^4 |
+ {3: 1 }5 |
+ {3: 2 }6 |
+ {3: 3 }7 |
+ {3: 4 }8 |
+ |
+ ]])
+ feed('3j')
+ screen:expect([[
+ {2: 7 }0 |
+ {2: 6 }1 |
+ {2: 5 }2 |
+ {2: 4 }3 |
+ {2: 3 }4 |
+ {2: 2 }5 |
+ {2: 1 }6 |
+ {1:8 }^7 |
+ {3: 1 }8 |
+ |
+ ]])
+ end)
+end)
+
describe("'winhighlight' highlight", function()
local screen
diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua
index 712c1f377a..b6e2f2311f 100644
--- a/test/functional/ui/inccommand_spec.lua
+++ b/test/functional/ui/inccommand_spec.lua
@@ -1487,6 +1487,29 @@ describe("inccommand=nosplit", function()
]])
eq(eval('v:null'), eval('v:exiting'))
end)
+
+ it("does not break bar-separated command #8796", function()
+ source([[
+ function! F()
+ if v:false | return | endif
+ endfun
+ ]])
+ command('call timer_start(10, {-> F()}, {"repeat":-1})')
+ feed(':%s/')
+ sleep(20) -- Allow some timer activity.
+ screen:expect([[
+ Inc substitution on |
+ two lines |
+ Inc substitution on |
+ two lines |
+ |
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ {15:~ }|
+ :%s/^ |
+ ]])
+ end)
end)
describe(":substitute, 'inccommand' with a failing expression", function()
diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua
index 7bca741ae3..d3fe38ef52 100644
--- a/test/functional/ui/mouse_spec.lua
+++ b/test/functional/ui/mouse_spec.lua
@@ -1384,4 +1384,128 @@ describe('ui/mouse/input', function()
end) -- level 3 - wrapped
end)
+
+ it('getmousepos works correctly', function()
+ local winwidth = meths.get_option('winwidth')
+ -- Set winwidth=1 so that window sizes don't change.
+ meths.set_option('winwidth', 1)
+ command('tabedit')
+ local tabpage = meths.get_current_tabpage()
+ insert('hello')
+ command('vsplit')
+ local opts = {
+ relative='editor',
+ width=12,
+ height=1,
+ col=8,
+ row=1,
+ anchor='NW',
+ style='minimal',
+ border='single',
+ focusable=1
+ }
+ local float = meths.open_win(meths.get_current_buf(), false, opts)
+ command('redraw')
+ local lines = meths.get_option('lines')
+ local columns = meths.get_option('columns')
+
+ -- Test that screenrow and screencol are set properly for all positions.
+ for row = 0, lines - 1 do
+ for col = 0, columns - 1 do
+ -- Skip the X button that would close the tab.
+ if row ~= 0 or col ~= columns - 1 then
+ meths.input_mouse('left', 'press', '', 0, row, col)
+ meths.set_current_tabpage(tabpage)
+ local mousepos = funcs.getmousepos()
+ eq(row + 1, mousepos.screenrow)
+ eq(col + 1, mousepos.screencol)
+ -- All other values should be 0 when clicking on the command line.
+ if row == lines - 1 then
+ eq(0, mousepos.winid)
+ eq(0, mousepos.winrow)
+ eq(0, mousepos.wincol)
+ eq(0, mousepos.line)
+ eq(0, mousepos.column)
+ end
+ end
+ end
+ end
+
+ -- Test that mouse position values are properly set for the floating window
+ -- with a border. 1 is added to the height and width to account for the
+ -- border.
+ for win_row = 0, opts.height + 1 do
+ for win_col = 0, opts.width + 1 do
+ local row = win_row + opts.row
+ local col = win_col + opts.col
+ meths.input_mouse('left', 'press', '', 0, row, col)
+ local mousepos = funcs.getmousepos()
+ eq(float.id, mousepos.winid)
+ eq(win_row + 1, mousepos.winrow)
+ eq(win_col + 1, mousepos.wincol)
+ local line = 0
+ local column = 0
+ if win_row > 0 and win_row < opts.height + 1
+ and win_col > 0 and win_col < opts.width + 1 then
+ -- Because of border, win_row and win_col don't need to be
+ -- incremented by 1.
+ line = math.min(win_row, funcs.line('$'))
+ column = math.min(win_col, #funcs.getline(line) + 1)
+ end
+ eq(line, mousepos.line)
+ eq(column, mousepos.column)
+ end
+ end
+
+ -- Test that mouse position values are properly set for the floating
+ -- window, after removing the border.
+ opts.border = 'none'
+ meths.win_set_config(float, opts)
+ command('redraw')
+ for win_row = 0, opts.height - 1 do
+ for win_col = 0, opts.width - 1 do
+ local row = win_row + opts.row
+ local col = win_col + opts.col
+ meths.input_mouse('left', 'press', '', 0, row, col)
+ local mousepos = funcs.getmousepos()
+ eq(float.id, mousepos.winid)
+ eq(win_row + 1, mousepos.winrow)
+ eq(win_col + 1, mousepos.wincol)
+ local line = math.min(win_row + 1, funcs.line('$'))
+ local column = math.min(win_col + 1, #funcs.getline(line) + 1)
+ eq(line, mousepos.line)
+ eq(column, mousepos.column)
+ end
+ end
+
+ -- Test that mouse position values are properly set for ordinary windows.
+ -- Set the float to be unfocusable instead of closing, to additionally test
+ -- that getmousepos does not consider unfocusable floats. (see discussion
+ -- in PR #14937 for details).
+ opts.focusable = false
+ meths.win_set_config(float, opts)
+ command('redraw')
+ for nr = 1, 2 do
+ for win_row = 0, funcs.winheight(nr) - 1 do
+ for win_col = 0, funcs.winwidth(nr) - 1 do
+ local row = win_row + funcs.win_screenpos(nr)[1] - 1
+ local col = win_col + funcs.win_screenpos(nr)[2] - 1
+ meths.input_mouse('left', 'press', '', 0, row, col)
+ local mousepos = funcs.getmousepos()
+ eq(funcs.win_getid(nr), mousepos.winid)
+ eq(win_row + 1, mousepos.winrow)
+ eq(win_col + 1, mousepos.wincol)
+ local line = math.min(win_row + 1, funcs.line('$'))
+ local column = math.min(win_col + 1, #funcs.getline(line) + 1)
+ eq(line, mousepos.line)
+ eq(column, mousepos.column)
+ end
+ end
+ end
+
+ -- Restore state and release mouse.
+ command('tabclose!')
+ meths.set_option('winwidth', winwidth)
+ meths.input_mouse('left', 'release', '', 0, 0, 0)
+ end)
end)
diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua
index 719e2ee82a..4e5e9c3a71 100644
--- a/test/functional/ui/multigrid_spec.lua
+++ b/test/functional/ui/multigrid_spec.lua
@@ -34,6 +34,7 @@ describe('ext_multigrid', function()
[17] = {background = Screen.colors.LightGrey, underline = true, bold = true, foreground = Screen.colors.Magenta},
[18] = {bold = true, foreground = Screen.colors.Magenta},
[19] = {foreground = Screen.colors.Brown},
+ [20] = {background = Screen.colors.LightGrey},
})
end)
@@ -2034,6 +2035,66 @@ describe('ext_multigrid', function()
]]}
end)
+ it('supports mouse drag with mouse=a', function()
+ command('set mouse=a')
+ command('vsplit')
+ command('wincmd l')
+ command('split')
+ command('enew')
+ feed('ifoo\nbar<esc>')
+
+ meths.input_mouse('left', 'press', '', 5, 0, 0)
+ poke_eventloop()
+ meths.input_mouse('left', 'drag', '', 5, 1, 2)
+
+ screen:expect{grid=[[
+ ## grid 1
+ [4:--------------------------]{12:│}[5:--------------------------]|
+ [4:--------------------------]{12:│}[5:--------------------------]|
+ [4:--------------------------]{12:│}[5:--------------------------]|
+ [4:--------------------------]{12:│}[5:--------------------------]|
+ [4:--------------------------]{12:│}[5:--------------------------]|
+ [4:--------------------------]{12:│}[5:--------------------------]|
+ [4:--------------------------]{12:│}{11:[No Name] [+] }|
+ [4:--------------------------]{12:│}[2:--------------------------]|
+ [4:--------------------------]{12:│}[2:--------------------------]|
+ [4:--------------------------]{12:│}[2:--------------------------]|
+ [4:--------------------------]{12:│}[2:--------------------------]|
+ [4:--------------------------]{12:│}[2:--------------------------]|
+ {12:[No Name] [No Name] }|
+ [3:-----------------------------------------------------]|
+ ## grid 2
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ {7:-- VISUAL --} |
+ ## grid 4
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 5
+ {20:foo} |
+ {20:ba}^r |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]]}
+
+ end)
+
it('has viewport information', function()
screen:try_resize(48, 8)
screen:expect{grid=[[
@@ -2056,7 +2117,7 @@ describe('ext_multigrid', function()
## grid 3
|
]], win_viewport={
- [2] = {win = { id = 1000 }, topline = 0, botline = 2, curline = 0, curcol = 0}
+ [2] = {win = { id = 1000 }, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}
}}
insert([[
Lorem ipsum dolor sit amet, consectetur
@@ -2091,7 +2152,7 @@ describe('ext_multigrid', function()
## grid 3
|
]], win_viewport={
- [2] = {win = {id = 1000}, topline = 5, botline = 11, curline = 10, curcol = 7},
+ [2] = {win = {id = 1000}, topline = 5, botline = 11, curline = 10, curcol = 7, linecount = 11},
}}
@@ -2116,7 +2177,7 @@ describe('ext_multigrid', function()
## grid 3
|
]], win_viewport={
- [2] = {win = {id = 1000}, topline = 2, botline = 9, curline = 7, curcol = 0},
+ [2] = {win = {id = 1000}, topline = 2, botline = 9, curline = 7, curcol = 0, linecount = 11},
}}
command("split")
@@ -2140,8 +2201,8 @@ describe('ext_multigrid', function()
reprehenderit in voluptate velit esse cillum |
^dolore eu fugiat nulla pariatur. Excepteur sint |
]], win_viewport={
- [2] = {win = {id = 1000}, topline = 6, botline = 9, curline = 7, curcol = 0},
- [4] = {win = {id = 1001}, topline = 5, botline = 9, curline = 7, curcol = 0},
+ [2] = {win = {id = 1000}, topline = 6, botline = 9, curline = 7, curcol = 0, linecount = 11},
+ [4] = {win = {id = 1001}, topline = 5, botline = 9, curline = 7, curcol = 0, linecount = 11},
}}
feed("b")
@@ -2165,8 +2226,8 @@ describe('ext_multigrid', function()
reprehenderit in voluptate velit esse ^cillum |
dolore eu fugiat nulla pariatur. Excepteur sint |
]], win_viewport={
- [2] = {win = {id = 1000}, topline = 6, botline = 9, curline = 7, curcol = 0},
- [4] = {win = {id = 1001}, topline = 5, botline = 9, curline = 6, curcol = 38},
+ [2] = {win = {id = 1000}, topline = 6, botline = 9, curline = 7, curcol = 0, linecount = 11},
+ [4] = {win = {id = 1001}, topline = 5, botline = 9, curline = 6, curcol = 38, linecount = 11},
}}
feed("2k")
@@ -2190,8 +2251,8 @@ describe('ext_multigrid', function()
ea commodo consequat. Duis aute irure dolor in |
reprehenderit in voluptate velit esse cillum |
]], win_viewport={
- [2] = {win = {id = 1000}, topline = 6, botline = 9, curline = 7, curcol = 0},
- [4] = {win = {id = 1001}, topline = 4, botline = 8, curline = 4, curcol = 38},
+ [2] = {win = {id = 1000}, topline = 6, botline = 9, curline = 7, curcol = 0, linecount = 11},
+ [4] = {win = {id = 1001}, topline = 4, botline = 8, curline = 4, curcol = 38, linecount = 11},
}}
-- handles non-current window
@@ -2216,8 +2277,96 @@ describe('ext_multigrid', function()
ea commodo consequat. Duis aute irure dolor in |
reprehenderit in voluptate velit esse cillum |
]], win_viewport={
- [2] = {win = {id = 1000}, topline = 0, botline = 3, curline = 0, curcol = 10},
- [4] = {win = {id = 1001}, topline = 4, botline = 8, curline = 4, curcol = 38},
+ [2] = {win = {id = 1000}, topline = 0, botline = 3, curline = 0, curcol = 10, linecount = 11},
+ [4] = {win = {id = 1001}, topline = 4, botline = 8, curline = 4, curcol = 38, linecount = 11},
+ }}
+ end)
+
+ it('does not crash when dragging mouse across grid boundary', function()
+ screen:try_resize(48, 8)
+ screen:expect{grid=[[
+ ## grid 1
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ {11:[No Name] }|
+ [3:------------------------------------------------]|
+ ## grid 2
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ## grid 3
+ |
+ ]], win_viewport={
+ [2] = {win = { id = 1000 }, topline = 0, botline = 2, curline = 0, curcol = 0, linecount = 1}
+ }}
+ insert([[
+ Lorem ipsum dolor sit amet, consectetur
+ adipisicing elit, sed do eiusmod tempor
+ incididunt ut labore et dolore magna aliqua.
+ Ut enim ad minim veniam, quis nostrud
+ exercitation ullamco laboris nisi ut aliquip ex
+ ea commodo consequat. Duis aute irure dolor in
+ reprehenderit in voluptate velit esse cillum
+ dolore eu fugiat nulla pariatur. Excepteur sint
+ occaecat cupidatat non proident, sunt in culpa
+ qui officia deserunt mollit anim id est
+ laborum.]])
+
+ screen:expect{grid=[[
+ ## grid 1
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ {11:[No Name] [+] }|
+ [3:------------------------------------------------]|
+ ## grid 2
+ ea commodo consequat. Duis aute irure dolor in |
+ reprehenderit in voluptate velit esse cillum |
+ dolore eu fugiat nulla pariatur. Excepteur sint |
+ occaecat cupidatat non proident, sunt in culpa |
+ qui officia deserunt mollit anim id est |
+ laborum^. |
+ ## grid 3
+ |
+ ]], win_viewport={
+ [2] = {win = {id = 1000}, topline = 5, botline = 11, curline = 10, curcol = 7, linecount = 11},
+ }}
+
+ meths.input_mouse('left', 'press', '', 1,5, 1)
+ poke_eventloop()
+ meths.input_mouse('left', 'drag', '', 1, 6, 1)
+
+ screen:expect{grid=[[
+ ## grid 1
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ [2:------------------------------------------------]|
+ {11:[No Name] [+] }|
+ [3:------------------------------------------------]|
+ ## grid 2
+ reprehenderit in voluptate velit esse cillum |
+ dolore eu fugiat nulla pariatur. Excepteur sint |
+ occaecat cupidatat non proident, sunt in culpa |
+ qui officia deserunt mollit anim id est |
+ l^aborum. |
+ {1:~ }|
+ ## grid 3
+ {7:-- VISUAL --} |
+ ]], win_viewport={
+ [2] = {win = {id = 1000}, topline = 6, botline = 12, curline = 10, curcol = 1, linecount = 11},
}}
end)
end)
diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua
index 3826707743..50e5dfac84 100644
--- a/test/functional/ui/output_spec.lua
+++ b/test/functional/ui/output_spec.lua
@@ -1,9 +1,9 @@
local Screen = require('test.functional.ui.screen')
local helpers = require('test.functional.helpers')(after_each)
local child_session = require('test.functional.terminal.helpers')
+local assert_alive = helpers.assert_alive
local mkdir, write_file, rmdir = helpers.mkdir, helpers.write_file, helpers.rmdir
local eq = helpers.eq
-local eval = helpers.eval
local feed = helpers.feed
local feed_command = helpers.feed_command
local iswin = helpers.iswin
@@ -86,12 +86,12 @@ describe("shell command :!", function()
it("cat a binary file #4142", function()
feed(":exe 'silent !cat '.shellescape(v:progpath)<CR>")
- eq(2, eval('1+1')) -- Still alive?
+ assert_alive()
end)
it([[display \x08 char #4142]], function()
feed(":silent !echo \08<CR>")
- eq(2, eval('1+1')) -- Still alive?
+ assert_alive()
end)
it('handles control codes', function()
diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
index 0944bfc21a..aeba049557 100644
--- a/test/functional/ui/popupmenu_spec.lua
+++ b/test/functional/ui/popupmenu_spec.lua
@@ -1,5 +1,6 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
+local assert_alive = helpers.assert_alive
local clear, feed = helpers.clear, helpers.feed
local source = helpers.source
local insert = helpers.insert
@@ -9,7 +10,6 @@ local funcs = helpers.funcs
local get_pathsep = helpers.get_pathsep
local eq = helpers.eq
local pcall_err = helpers.pcall_err
-local eval = helpers.eval
describe('ui/ext_popupmenu', function()
local screen
@@ -2211,6 +2211,6 @@ describe('builtin popupmenu', function()
feed('$i')
funcs.complete(col - max_len, items)
feed('<c-y>')
- eq(2, eval('1+1'))
+ assert_alive()
end)
end)
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index f73d051857..61f19c3794 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -773,13 +773,14 @@ function Screen:_handle_win_pos(grid, win, startrow, startcol, width, height)
self.float_pos[grid] = nil
end
-function Screen:_handle_win_viewport(grid, win, topline, botline, curline, curcol)
+function Screen:_handle_win_viewport(grid, win, topline, botline, curline, curcol, linecount)
self.win_viewport[grid] = {
win = win,
topline = topline,
botline = botline,
curline = curline,
- curcol = curcol
+ curcol = curcol,
+ linecount = linecount
}
end
@@ -1306,7 +1307,7 @@ local function fmt_ext_state(name, state)
for k,v in pairs(state) do
str = (str.." ["..k.."] = {win = {id = "..v.win.id.."}, topline = "
..v.topline..", botline = "..v.botline..", curline = "..v.curline
- ..", curcol = "..v.curcol.."};\n")
+ ..", curcol = "..v.curcol..", linecount = "..v.linecount.."};\n")
end
return str .. "}"
elseif name == "float_pos" then
diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua
index 06c92a4b10..741b93043d 100644
--- a/test/functional/ui/sign_spec.lua
+++ b/test/functional/ui/sign_spec.lua
@@ -176,8 +176,8 @@ describe('Signs', function()
command('sign place 5 line=3 name=pietWarn buffer=1')
command('sign place 3 line=3 name=pietError buffer=1')
screen:expect([[
- {1:>>}XX{6: 1 }a |
- XX{1:>>}{6: 2 }b |
+ {1:>>}{8:XX}{6: 1 }a |
+ {8:XX}{1:>>}{6: 2 }b |
{1:>>}WW{6: 3 }c |
{2: }{6: 4 }^ |
{0:~ }|
@@ -194,7 +194,7 @@ describe('Signs', function()
-- With the default setting, we get the sign with the top id.
command('set signcolumn=yes:1')
screen:expect([[
- XX{6: 1 }a |
+ {8:XX}{6: 1 }a |
{1:>>}{6: 2 }b |
WW{6: 3 }c |
{2: }{6: 4 }^ |
@@ -212,9 +212,9 @@ describe('Signs', function()
-- "auto:3" accommodates all the signs we defined so far.
command('set signcolumn=auto:3')
screen:expect([[
- {1:>>}XX{2: }{6: 1 }a |
- XX{1:>>}{2: }{6: 2 }b |
- XX{1:>>}WW{6: 3 }c |
+ {1:>>}{8:XX}{2: }{6: 1 }a |
+ {8:XX}{1:>>}{2: }{6: 2 }b |
+ {8:XX}{1:>>}WW{6: 3 }c |
{2: }{6: 4 }^ |
{0:~ }|
{0:~ }|
@@ -230,9 +230,9 @@ describe('Signs', function()
-- Check "yes:9".
command('set signcolumn=yes:9')
screen:expect([[
- {1:>>}XX{2: }{6: 1 }a |
- XX{1:>>}{2: }{6: 2 }b |
- XX{1:>>}WW{2: }{6: 3 }c |
+ {1:>>}{8:XX}{2: }{6: 1 }a |
+ {8:XX}{1:>>}{2: }{6: 2 }b |
+ {8:XX}{1:>>}WW{2: }{6: 3 }c |
{2: }{6: 4 }^ |
{0:~ }|
{0:~ }|
@@ -249,9 +249,9 @@ describe('Signs', function()
-- a single line (same result as "auto:3").
command('set signcolumn=auto:4')
screen:expect{grid=[[
- {1:>>}XX{2: }{6: 1 }a |
- XX{1:>>}{2: }{6: 2 }b |
- XX{1:>>}WW{6: 3 }c |
+ {1:>>}{8:XX}{2: }{6: 1 }a |
+ {8:XX}{1:>>}{2: }{6: 2 }b |
+ {8:XX}{1:>>}WW{6: 3 }c |
{2: }{6: 4 }^ |
{0:~ }|
{0:~ }|
@@ -267,8 +267,8 @@ describe('Signs', function()
-- line deletion deletes signs.
command('2d')
screen:expect([[
- {1:>>}XX{2: }{6: 1 }a |
- XX{1:>>}WW{6: 2 }^c |
+ {1:>>}{8:XX}{2: }{6: 1 }a |
+ {8:XX}{1:>>}WW{6: 2 }^c |
{2: }{6: 3 } |
{0:~ }|
{0:~ }|
diff --git a/test/functional/ui/syntax_conceal_spec.lua b/test/functional/ui/syntax_conceal_spec.lua
index d1af0e955c..4e1852162f 100644
--- a/test/functional/ui/syntax_conceal_spec.lua
+++ b/test/functional/ui/syntax_conceal_spec.lua
@@ -913,4 +913,46 @@ describe('Screen', function()
]]}
eq(grid_lines, {{2, 0, {{'c', 0, 3}}}})
end)
+
+ -- Copy of Test_cursor_column_in_concealed_line_after_window_scroll in
+ -- test/functional/ui/syntax_conceal_spec.lua.
+ describe('concealed line after window scroll', function()
+ after_each(function()
+ command(':qall!')
+ os.remove('Xcolesearch')
+ end)
+
+ it('has the correct cursor column', function()
+ insert([[
+ 3split
+ let m = matchadd('Conceal', '=')
+ setl conceallevel=2 concealcursor=nc
+ normal gg
+ "==expr==
+ ]])
+
+ command('write Xcolesearch')
+ feed(":so %<CR>")
+
+ -- Jump to something that is beyond the bottom of the window,
+ -- so there's a scroll down.
+ feed("/expr<CR>")
+
+ -- Are the concealed parts of the current line really hidden?
+ -- Is the window's cursor column properly updated for hidden
+ -- parts of the current line?
+ screen:expect{grid=[[
+ setl conceallevel2 concealcursornc |
+ normal gg |
+ "{5:^expr} |
+ {2:Xcolesearch }|
+ normal gg |
+ "=={5:expr}== |
+ |
+ {0:~ }|
+ {3:Xcolesearch }|
+ /expr |
+ ]]}
+ end)
+ end)
end)
diff --git a/test/functional/ui/tabline_spec.lua b/test/functional/ui/tabline_spec.lua
index ab8d63cda1..809486d4db 100644
--- a/test/functional/ui/tabline_spec.lua
+++ b/test/functional/ui/tabline_spec.lua
@@ -69,6 +69,7 @@ describe('ui/ext_tabline', function()
command("bnext")
local expected_buffers = {
+ {buffer = { id = 1 }, name = '[No Name]'},
{buffer = { id = 2 }, name = 'another-buffer'},
}
screen:expect{grid=[[
diff --git a/test/functional/viml/function_spec.lua b/test/functional/viml/function_spec.lua
deleted file mode 100644
index b8137038b1..0000000000
--- a/test/functional/viml/function_spec.lua
+++ /dev/null
@@ -1,216 +0,0 @@
-local helpers = require('test.functional.helpers')(after_each)
-
-local eq = helpers.eq
-local clear = helpers.clear
-local dedent = helpers.dedent
-local redir_exec = helpers.redir_exec
-
-before_each(clear)
-
-local function check_func(fname, body, indent)
- if type(body) == 'number' then
- body = ('return %i'):format(body)
- end
- eq(dedent(([[
-
- function %s()%s
- endfunction]]
- ), 3):format(
- fname,
- body and ('\n1' .. (' '):rep(2 + (indent or 8)) .. body) or ''),
- redir_exec('function ' .. fname))
-end
-
-describe(':endfunction', function()
- it('accepts bang', function()
- eq('', redir_exec([[
- function F()
- endfunction!
- ]]))
- check_func('F')
- eq('', redir_exec([[
- function! F()
- return 1
- endfunction!
- ]]))
- check_func('F', 1)
- end)
- it('accepts comments', function()
- eq('', redir_exec([[
- function F1()
- endfunction " Comment
- ]]))
- check_func('F1')
- eq('', redir_exec([[
- function F2()
- endfunction " }}}
- ]]))
- check_func('F2')
- eq('', redir_exec([[
- function F3()
- endfunction " F3
- ]]))
- check_func('F3')
- eq('', redir_exec([[
- function F4()
- endfunction! " F4
- ]]))
- check_func('F4')
- eq('', redir_exec([[
- function! F4()
- return 2
- endfunction! " F4
- ]]))
- check_func('F4', 2)
- end)
- it('accepts function name', function()
- eq('', redir_exec([[
- function F0()
- endfunction F0
- ]]))
- check_func('F0')
- eq('', redir_exec([[
- function F1()
- endfunction! F1
- ]]))
- check_func('F1')
- eq('', redir_exec([[
- function! F2()
- endfunction! F2
- ]]))
- check_func('F2')
- eq('', redir_exec([[
- function! F2()
- return 3
- endfunction! F2
- ]]))
- check_func('F2', 3)
- end)
- it('accepts weird characters', function()
- eq('', redir_exec([[
- function F1()
- endfunction: }}}
- ]]))
- check_func('F1')
- -- From accurev
- eq('', redir_exec([[
- function F2()
- endfunction :}}}
- ]]))
- check_func('F2')
- -- From cream-vimabbrev
- eq('', redir_exec([[
- function F3()
- endfunction 1}}}
- ]]))
- check_func('F3')
- -- From pyunit
- eq('', redir_exec([[
- function F4()
- endfunction # }}}
- ]]))
- check_func('F4')
- -- From vim-lldb
- eq('', redir_exec([[
- function F5()
- endfunction()
- ]]))
- check_func('F5')
- -- From vim-mail
- eq('', redir_exec([[
- function F6()
- endfunction;
- ]]))
- check_func('F6')
- end)
- it('accepts commented bar', function()
- eq('', redir_exec([[
- function F1()
- endfunction " F1 | echo 42
- ]]))
- check_func('F1')
- eq('', redir_exec([[
- function! F1()
- return 42
- endfunction! " F1 | echo 42
- ]]))
- check_func('F1', 42)
- end)
- it('accepts uncommented bar', function()
- eq('\n42', redir_exec([[
- function F1()
- endfunction | echo 42
- ]]))
- check_func('F1')
- end)
- it('allows running multiple commands', function()
- eq('\n2', redir_exec([[
- function F1()
- echo 2
- endfunction
- call F1()
- ]]))
- check_func('F1', 'echo 2')
- eq('\n2\n3\n4', redir_exec([[
- function F2()
- echo 2
- endfunction F2
- function F3()
- echo 3
- endfunction " F3
- function! F4()
- echo 4
- endfunction!
- call F2()
- call F3()
- call F4()
- ]]))
- check_func('F2', 'echo 2')
- check_func('F3', 'echo 3')
- check_func('F4', 'echo 4')
- end)
- it('allows running multiple commands with only one character in between',
- function()
- eq('\n3', redir_exec(dedent([[
- function! F1()
- echo 3
- endfunction!
- call F1()]])))
- check_func('F1', 'echo 3', 2)
- eq('\n4', redir_exec(dedent([[
- function F5()
- echo 4
- endfunction
- call F5()]])))
- check_func('F5', 'echo 4', 2)
- eq('\n5', redir_exec(dedent([[
- function F6()
- echo 5
- endfunction " TEST
- call F6()]])))
- check_func('F6', 'echo 5', 2)
- eq('\n6', redir_exec(dedent([[
- function F7()
- echo 6
- endfunction F7
- call F7()]])))
- check_func('F7', 'echo 6', 2)
- eq('\n2\n3\n4', redir_exec(dedent([[
- function F2()
- echo 2
- endfunction F2
- function F3()
- echo 3
- endfunction " F3
- function! F4()
- echo 4
- endfunction!
- call F2()
- call F3()
- call F4()]])))
- check_func('F2', 'echo 2', 2)
- check_func('F3', 'echo 3', 2)
- check_func('F4', 'echo 4', 2)
- end)
-end)
--- vim: foldmarker=▶,▲
diff --git a/test/functional/eval/api_functions_spec.lua b/test/functional/vimscript/api_functions_spec.lua
index 7d09a652ba..d07e74d40e 100644
--- a/test/functional/eval/api_functions_spec.lua
+++ b/test/functional/vimscript/api_functions_spec.lua
@@ -155,4 +155,13 @@ describe('eval-API', function()
pcall_err(command, "sandbox call nvim_input('ievil')"))
eq({''}, meths.buf_get_lines(0, 0, -1, true))
end)
+
+ it('converts blobs to API strings', function()
+ command('let g:v1 = nvim__id(0z68656c6c6f)')
+ command('let g:v2 = nvim__id(v:_null_blob)')
+ eq(1, eval('type(g:v1)'))
+ eq(1, eval('type(g:v2)'))
+ eq('hello', eval('g:v1'))
+ eq('', eval('g:v2'))
+ end)
end)
diff --git a/test/functional/eval/buf_functions_spec.lua b/test/functional/vimscript/buf_functions_spec.lua
index 06841a4521..e957e5f5af 100644
--- a/test/functional/eval/buf_functions_spec.lua
+++ b/test/functional/vimscript/buf_functions_spec.lua
@@ -221,9 +221,9 @@ describe('getbufvar() function', function()
eq(0, funcs.getbufvar(1, '&l:autoindent'))
eq(0, funcs.getbufvar(1, '&g:autoindent'))
-- Also works with global-only options
- eq(0, funcs.getbufvar(1, '&hidden'))
- eq(0, funcs.getbufvar(1, '&l:hidden'))
- eq(0, funcs.getbufvar(1, '&g:hidden'))
+ eq(1, funcs.getbufvar(1, '&hidden'))
+ eq(1, funcs.getbufvar(1, '&l:hidden'))
+ eq(1, funcs.getbufvar(1, '&g:hidden'))
-- Also works with window-local options
eq(0, funcs.getbufvar(1, '&number'))
eq(0, funcs.getbufvar(1, '&l:number'))
@@ -279,9 +279,9 @@ describe('setbufvar() function', function()
eq(false, winmeths.get_option(windows[3], 'number'))
eq(false, winmeths.get_option(meths.get_current_win(), 'number'))
- eq(false, meths.get_option('hidden'))
- funcs.setbufvar(1, '&hidden', true)
eq(true, meths.get_option('hidden'))
+ funcs.setbufvar(1, '&hidden', 0)
+ eq(false, meths.get_option('hidden'))
eq(false, bufmeths.get_option(buf1, 'autoindent'))
funcs.setbufvar(1, '&autoindent', true)
diff --git a/test/functional/eval/changedtick_spec.lua b/test/functional/vimscript/changedtick_spec.lua
index 99406d9d7a..8533fac9ec 100644
--- a/test/functional/eval/changedtick_spec.lua
+++ b/test/functional/vimscript/changedtick_spec.lua
@@ -8,8 +8,8 @@ local funcs = helpers.funcs
local meths = helpers.meths
local command = helpers.command
local exc_exec = helpers.exc_exec
-local redir_exec = helpers.redir_exec
local pcall_err = helpers.pcall_err
+local exec_capture = helpers.exec_capture
local curbufmeths = helpers.curbufmeths
before_each(clear)
@@ -56,35 +56,35 @@ describe('b:changedtick', function()
local ct = changedtick()
local ctn = ct + 100500
eq(0, exc_exec('let d = b:'))
- eq('\nE46: Cannot change read-only variable "b:changedtick"',
- redir_exec('let b:changedtick = ' .. ctn))
- eq('\nE46: Cannot change read-only variable "b:["changedtick"]"',
- redir_exec('let b:["changedtick"] = ' .. ctn))
- eq('\nE46: Cannot change read-only variable "b:.changedtick"',
- redir_exec('let b:.changedtick = ' .. ctn))
- eq('\nE46: Cannot change read-only variable "d.changedtick"',
- redir_exec('let d.changedtick = ' .. ctn))
+ eq('Vim(let):E46: Cannot change read-only variable "b:changedtick"',
+ pcall_err(command, 'let b:changedtick = ' .. ctn))
+ eq('Vim(let):E46: Cannot change read-only variable "b:["changedtick"]"',
+ pcall_err(command, 'let b:["changedtick"] = ' .. ctn))
+ eq('Vim(let):E46: Cannot change read-only variable "b:.changedtick"',
+ pcall_err(command, 'let b:.changedtick = ' .. ctn))
+ eq('Vim(let):E46: Cannot change read-only variable "d.changedtick"',
+ pcall_err(command, 'let d.changedtick = ' .. ctn))
eq('Key is read-only: changedtick',
pcall_err(curbufmeths.set_var, 'changedtick', ctn))
- eq('\nE795: Cannot delete variable b:changedtick',
- redir_exec('unlet b:changedtick'))
- eq('\nE46: Cannot change read-only variable "b:.changedtick"',
- redir_exec('unlet b:.changedtick'))
- eq('\nE46: Cannot change read-only variable "b:["changedtick"]"',
- redir_exec('unlet b:["changedtick"]'))
- eq('\nE46: Cannot change read-only variable "d.changedtick"',
- redir_exec('unlet d.changedtick'))
+ eq('Vim(unlet):E795: Cannot delete variable b:changedtick',
+ pcall_err(command, 'unlet b:changedtick'))
+ eq('Vim(unlet):E46: Cannot change read-only variable "b:.changedtick"',
+ pcall_err(command, 'unlet b:.changedtick'))
+ eq('Vim(unlet):E46: Cannot change read-only variable "b:["changedtick"]"',
+ pcall_err(command, 'unlet b:["changedtick"]'))
+ eq('Vim(unlet):E46: Cannot change read-only variable "d.changedtick"',
+ pcall_err(command, 'unlet d.changedtick'))
eq('Key is read-only: changedtick',
pcall_err(curbufmeths.del_var, 'changedtick'))
eq(ct, changedtick())
- eq('\nE46: Cannot change read-only variable "b:["changedtick"]"',
- redir_exec('let b:["changedtick"] += ' .. ctn))
- eq('\nE46: Cannot change read-only variable "b:["changedtick"]"',
- redir_exec('let b:["changedtick"] -= ' .. ctn))
- eq('\nE46: Cannot change read-only variable "b:["changedtick"]"',
- redir_exec('let b:["changedtick"] .= ' .. ctn))
+ eq('Vim(let):E46: Cannot change read-only variable "b:["changedtick"]"',
+ pcall_err(command, 'let b:["changedtick"] += ' .. ctn))
+ eq('Vim(let):E46: Cannot change read-only variable "b:["changedtick"]"',
+ pcall_err(command, 'let b:["changedtick"] -= ' .. ctn))
+ eq('Vim(let):E46: Cannot change read-only variable "b:["changedtick"]"',
+ pcall_err(command, 'let b:["changedtick"] .= ' .. ctn))
eq(ct, changedtick())
@@ -93,23 +93,22 @@ describe('b:changedtick', function()
eq(ct + 1, changedtick())
end)
it('is listed in :let output', function()
- eq('\nb:changedtick #2',
- redir_exec(':let b:'))
+ eq('b:changedtick #2', exec_capture(':let b:'))
end)
it('fails to unlock b:changedtick', function()
eq(0, exc_exec('let d = b:'))
eq(0, funcs.islocked('b:changedtick'))
eq(0, funcs.islocked('d.changedtick'))
- eq('\nE940: Cannot lock or unlock variable b:changedtick',
- redir_exec('unlockvar b:changedtick'))
- eq('\nE46: Cannot change read-only variable "d.changedtick"',
- redir_exec('unlockvar d.changedtick'))
+ eq('Vim(unlockvar):E940: Cannot lock or unlock variable b:changedtick',
+ pcall_err(command, 'unlockvar b:changedtick'))
+ eq('Vim(unlockvar):E46: Cannot change read-only variable "d.changedtick"',
+ pcall_err(command, 'unlockvar d.changedtick'))
eq(0, funcs.islocked('b:changedtick'))
eq(0, funcs.islocked('d.changedtick'))
- eq('\nE940: Cannot lock or unlock variable b:changedtick',
- redir_exec('lockvar b:changedtick'))
- eq('\nE46: Cannot change read-only variable "d.changedtick"',
- redir_exec('lockvar d.changedtick'))
+ eq('Vim(lockvar):E940: Cannot lock or unlock variable b:changedtick',
+ pcall_err(command, 'lockvar b:changedtick'))
+ eq('Vim(lockvar):E46: Cannot change read-only variable "d.changedtick"',
+ pcall_err(command, 'lockvar d.changedtick'))
eq(0, funcs.islocked('b:changedtick'))
eq(0, funcs.islocked('d.changedtick'))
end)
@@ -119,24 +118,24 @@ describe('b:changedtick', function()
end)
it('cannot be changed by filter() or map()', function()
eq(2, changedtick())
- eq('\nE795: Cannot delete variable filter() argument',
- redir_exec('call filter(b:, 0)'))
- eq('\nE742: Cannot change value of map() argument',
- redir_exec('call map(b:, 0)'))
- eq('\nE742: Cannot change value of map() argument',
- redir_exec('call map(b:, "v:val")'))
+ eq('Vim(call):E795: Cannot delete variable filter() argument',
+ pcall_err(command, 'call filter(b:, 0)'))
+ eq('Vim(call):E742: Cannot change value of map() argument',
+ pcall_err(command, 'call map(b:, 0)'))
+ eq('Vim(call):E742: Cannot change value of map() argument',
+ pcall_err(command, 'call map(b:, "v:val")'))
eq(2, changedtick())
end)
it('cannot be remove()d', function()
eq(2, changedtick())
- eq('\nE795: Cannot delete variable remove() argument',
- redir_exec('call remove(b:, "changedtick")'))
+ eq('Vim(call):E795: Cannot delete variable remove() argument',
+ pcall_err(command, 'call remove(b:, "changedtick")'))
eq(2, changedtick())
end)
it('does not inherit VAR_FIXED when copying dictionary over', function()
eq(2, changedtick())
- eq('', redir_exec('let d1 = copy(b:)|let d1.changedtick = 42'))
- eq('', redir_exec('let d2 = copy(b:)|unlet d2.changedtick'))
+ eq('', exec_capture('let d1 = copy(b:)|let d1.changedtick = 42'))
+ eq('', exec_capture('let d2 = copy(b:)|unlet d2.changedtick'))
eq(2, changedtick())
end)
end)
diff --git a/test/functional/eval/container_functions_spec.lua b/test/functional/vimscript/container_functions_spec.lua
index 04a3248c49..04a3248c49 100644
--- a/test/functional/eval/container_functions_spec.lua
+++ b/test/functional/vimscript/container_functions_spec.lua
diff --git a/test/functional/eval/ctx_functions_spec.lua b/test/functional/vimscript/ctx_functions_spec.lua
index f23adbc556..d92a81c55b 100644
--- a/test/functional/eval/ctx_functions_spec.lua
+++ b/test/functional/vimscript/ctx_functions_spec.lua
@@ -9,7 +9,7 @@ local feed = helpers.feed
local map = helpers.tbl_map
local nvim = helpers.nvim
local parse_context = helpers.parse_context
-local redir_exec = helpers.redir_exec
+local exec_capture = helpers.exec_capture
local source = helpers.source
local trim = helpers.trim
local write_file = helpers.write_file
@@ -163,33 +163,29 @@ describe('context functions', function()
endfunction
]])
- eq('\nHello, World!', redir_exec([[call Greet('World')]]))
- eq('\nHello, World!'..
+ eq('Hello, World!', exec_capture([[call Greet('World')]]))
+ eq('Hello, World!'..
'\nHello, One!'..
'\nHello, Two!'..
'\nHello, Three!',
- redir_exec([[call GreetAll('World', 'One', 'Two', 'Three')]]))
+ exec_capture([[call GreetAll('World', 'One', 'Two', 'Three')]]))
call('SaveSFuncs')
call('DeleteSFuncs')
- eq('\nError detected while processing function Greet:'..
- '\nline 1:'..
- '\nE117: Unknown function: s:greet',
- redir_exec([[call Greet('World')]]))
- eq('\nError detected while processing function GreetAll:'..
- '\nline 1:'..
- '\nE117: Unknown function: s:greet_all',
- redir_exec([[call GreetAll('World', 'One', 'Two', 'Three')]]))
+ eq('Vim(call):E117: Unknown function: s:greet',
+ pcall_err(command, [[call Greet('World')]]))
+ eq('Vim(call):E117: Unknown function: s:greet_all',
+ pcall_err(command, [[call GreetAll('World', 'One', 'Two', 'Three')]]))
call('RestoreFuncs')
- eq('\nHello, World!', redir_exec([[call Greet('World')]]))
- eq('\nHello, World!'..
+ eq('Hello, World!', exec_capture([[call Greet('World')]]))
+ eq('Hello, World!'..
'\nHello, One!'..
'\nHello, Two!'..
'\nHello, Three!',
- redir_exec([[call GreetAll('World', 'One', 'Two', 'Three')]]))
+ exec_capture([[call GreetAll('World', 'One', 'Two', 'Three')]]))
end)
it('saves and restores functions properly', function()
@@ -206,12 +202,12 @@ describe('context functions', function()
endfunction
]])
- eq('\nHello, World!', redir_exec([[call Greet('World')]]))
- eq('\nHello, World!'..
+ eq('Hello, World!', exec_capture([[call Greet('World')]]))
+ eq('Hello, World!'..
'\nHello, One!'..
'\nHello, Two!'..
'\nHello, Three!',
- redir_exec([[call GreetAll('World', 'One', 'Two', 'Three')]]))
+ exec_capture([[call GreetAll('World', 'One', 'Two', 'Three')]]))
call('ctxpush', {'funcs'})
command('delfunction Greet')
@@ -223,12 +219,12 @@ describe('context functions', function()
call('ctxpop')
- eq('\nHello, World!', redir_exec([[call Greet('World')]]))
- eq('\nHello, World!'..
+ eq('Hello, World!', exec_capture([[call Greet('World')]]))
+ eq('Hello, World!'..
'\nHello, One!'..
'\nHello, Two!'..
'\nHello, Three!',
- redir_exec([[call GreetAll('World', 'One', 'Two', 'Three')]]))
+ exec_capture([[call GreetAll('World', 'One', 'Two', 'Three')]]))
end)
it('errors out when context stack is empty', function()
diff --git a/test/functional/eval/environ_spec.lua b/test/functional/vimscript/environ_spec.lua
index 9e19568249..9e19568249 100644
--- a/test/functional/eval/environ_spec.lua
+++ b/test/functional/vimscript/environ_spec.lua
diff --git a/test/functional/viml/errorlist_spec.lua b/test/functional/vimscript/errorlist_spec.lua
index 077d816903..077d816903 100644
--- a/test/functional/viml/errorlist_spec.lua
+++ b/test/functional/vimscript/errorlist_spec.lua
diff --git a/test/functional/vimscript/eval_spec.lua b/test/functional/vimscript/eval_spec.lua
new file mode 100644
index 0000000000..e1459ab5b8
--- /dev/null
+++ b/test/functional/vimscript/eval_spec.lua
@@ -0,0 +1,146 @@
+-- Tests for core Vimscript "eval" behavior.
+--
+-- See also:
+-- let_spec.lua
+-- null_spec.lua
+-- operators_spec.lua
+--
+-- Tests for the Vimscript |functions| library should live in:
+-- test/functional/vimscript/<funcname>_spec.lua
+-- test/functional/vimscript/functions_spec.lua
+
+local helpers = require('test.functional.helpers')(after_each)
+
+local lfs = require('lfs')
+local clear = helpers.clear
+local eq = helpers.eq
+local exc_exec = helpers.exc_exec
+local eval = helpers.eval
+local command = helpers.command
+local write_file = helpers.write_file
+local meths = helpers.meths
+local sleep = helpers.sleep
+local poke_eventloop = helpers.poke_eventloop
+local feed = helpers.feed
+
+describe('Up to MAX_FUNC_ARGS arguments are handled by', function()
+ local max_func_args = 20 -- from eval.h
+ local range = helpers.funcs.range
+
+ before_each(clear)
+
+ it('printf()', function()
+ local printf = helpers.funcs.printf
+ local rep = helpers.funcs['repeat']
+ local expected = '2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,'
+ eq(expected, printf(rep('%d,', max_func_args-1), unpack(range(2, max_func_args))))
+ local ret = exc_exec('call printf("", 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)')
+ eq('Vim(call):E740: Too many arguments for function printf', ret)
+ end)
+
+ it('rpcnotify()', function()
+ local rpcnotify = helpers.funcs.rpcnotify
+ local ret = rpcnotify(0, 'foo', unpack(range(3, max_func_args)))
+ eq(1, ret)
+ ret = exc_exec('call rpcnotify(0, "foo", 3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)')
+ eq('Vim(call):E740: Too many arguments for function rpcnotify', ret)
+ end)
+end)
+
+describe("backtick expansion", function()
+ setup(function()
+ clear()
+ lfs.mkdir("test-backticks")
+ write_file("test-backticks/file1", "test file 1")
+ write_file("test-backticks/file2", "test file 2")
+ write_file("test-backticks/file3", "test file 3")
+ lfs.mkdir("test-backticks/subdir")
+ write_file("test-backticks/subdir/file4", "test file 4")
+ -- Long path might cause "Press ENTER" prompt; use :silent to avoid it.
+ command('silent cd test-backticks')
+ end)
+
+ teardown(function()
+ helpers.rmdir('test-backticks')
+ end)
+
+ it("with default 'shell'", function()
+ if helpers.iswin() then
+ command(":silent args `dir /b *2`")
+ else
+ command(":silent args `echo ***2`")
+ end
+ eq({ "file2", }, eval("argv()"))
+ if helpers.iswin() then
+ command(":silent args `dir /s/b *4`")
+ eq({ "subdir\\file4", }, eval("map(argv(), 'fnamemodify(v:val, \":.\")')"))
+ else
+ command(":silent args `echo */*4`")
+ eq({ "subdir/file4", }, eval("argv()"))
+ end
+ end)
+
+ it("with shell=fish", function()
+ if eval("executable('fish')") == 0 then
+ pending('missing "fish" command')
+ return
+ end
+ command("set shell=fish")
+ command(":silent args `echo ***2`")
+ eq({ "file2", }, eval("argv()"))
+ command(":silent args `echo */*4`")
+ eq({ "subdir/file4", }, eval("argv()"))
+ end)
+end)
+
+describe('List support code', function()
+ local dur
+ local min_dur = 8
+ local len = 131072
+
+ if not pending('does not actually allows interrupting with just got_int', function() end) then return end
+ -- The following tests are confirmed to work with os_breakcheck() just before
+ -- `if (got_int) {break;}` in tv_list_copy and list_join_inner() and not to
+ -- work without.
+ setup(function()
+ clear()
+ dur = 0
+ while true do
+ command(([[
+ let rt = reltime()
+ let bl = range(%u)
+ let dur = reltimestr(reltime(rt))
+ ]]):format(len))
+ dur = tonumber(meths.get_var('dur'))
+ if dur >= min_dur then
+ -- print(('Using len %u, dur %g'):format(len, dur))
+ break
+ else
+ len = len * 2
+ end
+ end
+ end)
+ it('allows interrupting copy', function()
+ feed(':let t_rt = reltime()<CR>:let t_bl = copy(bl)<CR>')
+ sleep(min_dur / 16 * 1000)
+ feed('<C-c>')
+ poke_eventloop()
+ command('let t_dur = reltimestr(reltime(t_rt))')
+ local t_dur = tonumber(meths.get_var('t_dur'))
+ if t_dur >= dur / 8 then
+ eq(nil, ('Took too long to cancel: %g >= %g'):format(t_dur, dur / 8))
+ end
+ end)
+ it('allows interrupting join', function()
+ feed(':let t_rt = reltime()<CR>:let t_j = join(bl)<CR>')
+ sleep(min_dur / 16 * 1000)
+ feed('<C-c>')
+ poke_eventloop()
+ command('let t_dur = reltimestr(reltime(t_rt))')
+ local t_dur = tonumber(meths.get_var('t_dur'))
+ print(('t_dur: %g'):format(t_dur))
+ if t_dur >= dur / 8 then
+ eq(nil, ('Took too long to cancel: %g >= %g'):format(t_dur, dur / 8))
+ end
+ end)
+end)
diff --git a/test/functional/eval/executable_spec.lua b/test/functional/vimscript/executable_spec.lua
index 28aefb72e5..28aefb72e5 100644
--- a/test/functional/eval/executable_spec.lua
+++ b/test/functional/vimscript/executable_spec.lua
diff --git a/test/functional/eval/execute_spec.lua b/test/functional/vimscript/execute_spec.lua
index f52ac4e59b..e21c71dc7f 100644
--- a/test/functional/eval/execute_spec.lua
+++ b/test/functional/vimscript/execute_spec.lua
@@ -3,7 +3,6 @@ local eq = helpers.eq
local eval = helpers.eval
local clear = helpers.clear
local source = helpers.source
-local redir_exec = helpers.redir_exec
local exc_exec = helpers.exc_exec
local funcs = helpers.funcs
local Screen = require('test.functional.ui.screen')
@@ -15,7 +14,14 @@ describe('execute()', function()
before_each(clear)
it('captures the same result as :redir', function()
- eq(redir_exec('messages'), funcs.execute('messages'))
+ command([[
+ echomsg 'foo 1'
+ echomsg 'foo 2'
+ redir => g:__redir_output
+ silent! messages
+ redir END
+ ]])
+ eq(eval('g:__redir_output'), funcs.execute('messages'))
end)
it('captures the concatenated outputs of a List of commands', function()
@@ -322,16 +328,16 @@ describe('execute()', function()
eq('Vim(call):E731: using Dictionary as a String', ret)
ret = exc_exec('call execute("echo add(1, 1)", "")')
- eq('Vim(echo):E714: List required', ret)
+ eq('Vim(echo):E897: List or Blob required', ret)
ret = exc_exec('call execute(["echon 42", "echo add(1, 1)"], "")')
- eq('Vim(echo):E714: List required', ret)
+ eq('Vim(echo):E897: List or Blob required', ret)
ret = exc_exec('call execute("echo add(1, 1)", "silent")')
- eq('Vim(echo):E714: List required', ret)
+ eq('Vim(echo):E897: List or Blob required', ret)
ret = exc_exec('call execute(["echon 42", "echo add(1, 1)"], "silent")')
- eq('Vim(echo):E714: List required', ret)
+ eq('Vim(echo):E897: List or Blob required', ret)
end)
end)
end)
diff --git a/test/functional/eval/exepath_spec.lua b/test/functional/vimscript/exepath_spec.lua
index 08d2c59af8..08d2c59af8 100644
--- a/test/functional/eval/exepath_spec.lua
+++ b/test/functional/vimscript/exepath_spec.lua
diff --git a/test/functional/eval/fnamemodify_spec.lua b/test/functional/vimscript/fnamemodify_spec.lua
index d54a6db417..d54a6db417 100644
--- a/test/functional/eval/fnamemodify_spec.lua
+++ b/test/functional/vimscript/fnamemodify_spec.lua
diff --git a/test/functional/vimscript/functions_spec.lua b/test/functional/vimscript/functions_spec.lua
new file mode 100644
index 0000000000..0ad7fd8010
--- /dev/null
+++ b/test/functional/vimscript/functions_spec.lua
@@ -0,0 +1,20 @@
+-- Tests for misc Vimscript |functions|.
+--
+-- If a function is non-trivial, consider moving its spec to:
+-- test/functional/vimscript/<funcname>_spec.lua
+--
+-- Core "eval" tests live in eval_spec.lua.
+
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local eval = helpers.eval
+local iswin = helpers.iswin
+local matches = helpers.matches
+
+before_each(clear)
+
+it('windowsversion()', function()
+ clear()
+ matches(iswin() and '^%d+%.%d+$' or '^$', eval('windowsversion()'))
+end)
diff --git a/test/functional/eval/getline_spec.lua b/test/functional/vimscript/getline_spec.lua
index 3c56bde094..3c56bde094 100644
--- a/test/functional/eval/getline_spec.lua
+++ b/test/functional/vimscript/getline_spec.lua
diff --git a/test/functional/eval/glob_spec.lua b/test/functional/vimscript/glob_spec.lua
index b8807ecfcc..b8807ecfcc 100644
--- a/test/functional/eval/glob_spec.lua
+++ b/test/functional/vimscript/glob_spec.lua
diff --git a/test/functional/eval/has_spec.lua b/test/functional/vimscript/has_spec.lua
index a3af2d1a20..a3af2d1a20 100644
--- a/test/functional/eval/has_spec.lua
+++ b/test/functional/vimscript/has_spec.lua
diff --git a/test/functional/eval/hostname_spec.lua b/test/functional/vimscript/hostname_spec.lua
index 6112cf64e3..6112cf64e3 100644
--- a/test/functional/eval/hostname_spec.lua
+++ b/test/functional/vimscript/hostname_spec.lua
diff --git a/test/functional/eval/input_spec.lua b/test/functional/vimscript/input_spec.lua
index 14c02f9eb2..14c02f9eb2 100644
--- a/test/functional/eval/input_spec.lua
+++ b/test/functional/vimscript/input_spec.lua
diff --git a/test/functional/eval/json_functions_spec.lua b/test/functional/vimscript/json_functions_spec.lua
index 8dcaea806e..c3b607b544 100644
--- a/test/functional/eval/json_functions_spec.lua
+++ b/test/functional/vimscript/json_functions_spec.lua
@@ -6,7 +6,7 @@ local eq = helpers.eq
local eval = helpers.eval
local command = helpers.command
local exc_exec = helpers.exc_exec
-local redir_exec = helpers.redir_exec
+local pcall_err = helpers.pcall_err
local NIL = helpers.NIL
local source = helpers.source
@@ -517,9 +517,8 @@ describe('json_decode() function', function()
it('does not overflow when writing error message about decoding ["", ""]',
function()
- eq('\nE474: Attempt to decode a blank string'
- .. '\nE474: Failed to parse \n',
- redir_exec('call json_decode(["", ""])'))
+ eq('Vim(call):E474: Attempt to decode a blank string',
+ pcall_err(command, 'call json_decode(["", ""])'))
end)
end)
@@ -538,6 +537,11 @@ describe('json_encode() function', function()
eq('"þÿþ"', funcs.json_encode('þÿþ'))
end)
+ it('dumps blobs', function()
+ eq('[]', eval('json_encode(0z)'))
+ eq('[222, 173, 190, 239]', eval('json_encode(0zDEADBEEF)'))
+ end)
+
it('dumps numbers', function()
eq('0', funcs.json_encode(0))
eq('10', funcs.json_encode(10))
@@ -769,6 +773,10 @@ describe('json_encode() function', function()
eq('""', eval('json_encode($XXX_UNEXISTENT_VAR_XXX)'))
end)
+ it('can dump NULL blob', function()
+ eq('[]', eval('json_encode(v:_null_blob)'))
+ end)
+
it('can dump NULL list', function()
eq('[]', eval('json_encode(v:_null_list)'))
end)
diff --git a/test/functional/viml/lang_spec.lua b/test/functional/vimscript/lang_spec.lua
index 6d603b8822..d5254986ab 100644
--- a/test/functional/viml/lang_spec.lua
+++ b/test/functional/vimscript/lang_spec.lua
@@ -2,7 +2,7 @@ local helpers = require('test.functional.helpers')(after_each)
local clear, eval, eq = helpers.clear, helpers.eval, helpers.eq
local exc_exec, source = helpers.exc_exec, helpers.source
-describe('viml', function()
+describe('vimscript', function()
before_each(clear)
it('parses `<SID>` with turkish locale', function()
diff --git a/test/functional/eval/let_spec.lua b/test/functional/vimscript/let_spec.lua
index 5bc703b567..4ff4090a18 100644
--- a/test/functional/eval/let_spec.lua
+++ b/test/functional/vimscript/let_spec.lua
@@ -5,7 +5,7 @@ local clear = helpers.clear
local command = helpers.command
local eval = helpers.eval
local meths = helpers.meths
-local redir_exec = helpers.redir_exec
+local exec_capture = helpers.exec_capture
local source = helpers.source
local nvim_dir = helpers.nvim_dir
@@ -14,14 +14,14 @@ before_each(clear)
describe(':let', function()
it('correctly lists variables with curly-braces', function()
meths.set_var('v', {0})
- eq('\nv [0]', redir_exec('let {"v"}'))
+ eq('v [0]', exec_capture('let {"v"}'))
end)
it('correctly lists variables with subscript', function()
meths.set_var('v', {0})
- eq('\nv[0] #0', redir_exec('let v[0]'))
- eq('\ng:["v"][0] #0', redir_exec('let g:["v"][0]'))
- eq('\n{"g:"}["v"][0] #0', redir_exec('let {"g:"}["v"][0]'))
+ eq('v[0] #0', exec_capture('let v[0]'))
+ eq('g:["v"][0] #0', exec_capture('let g:["v"][0]'))
+ eq('{"g:"}["v"][0] #0', exec_capture('let {"g:"}["v"][0]'))
end)
it(":unlet self-referencing node in a List graph #6070", function()
diff --git a/test/functional/eval/map_functions_spec.lua b/test/functional/vimscript/map_functions_spec.lua
index 275c72d212..275c72d212 100644
--- a/test/functional/eval/map_functions_spec.lua
+++ b/test/functional/vimscript/map_functions_spec.lua
diff --git a/test/functional/eval/match_functions_spec.lua b/test/functional/vimscript/match_functions_spec.lua
index f399ef47d3..9f168c913a 100644
--- a/test/functional/eval/match_functions_spec.lua
+++ b/test/functional/vimscript/match_functions_spec.lua
@@ -6,7 +6,6 @@ local clear = helpers.clear
local funcs = helpers.funcs
local command = helpers.command
local exc_exec = helpers.exc_exec
-local pcall_err = helpers.pcall_err
before_each(clear)
@@ -40,13 +39,13 @@ describe('setmatches()', function()
}}, funcs.getmatches())
end)
- it('fails with -1 if highlight group is not defined', function()
- eq('Vim:E28: No such highlight group name: 1',
- pcall_err(funcs.setmatches, {{group=1, pattern=2, id=3, priority=4}}))
- eq({}, funcs.getmatches())
- eq('Vim:E28: No such highlight group name: 1',
- pcall_err(funcs.setmatches, {{group=1, pos1={2}, pos2={6}, id=3, priority=4, conceal=5}}))
- eq({}, funcs.getmatches())
+ it('does not fail if highlight group is not defined', function()
+ eq(0, funcs.setmatches{{group=1, pattern=2, id=3, priority=4}})
+ eq({{group='1', pattern='2', id=3, priority=4}},
+ funcs.getmatches())
+ eq(0, funcs.setmatches{{group=1, pos1={2}, pos2={6}, id=3, priority=4, conceal=5}})
+ eq({{group='1', pos1={2}, pos2={6}, id=3, priority=4, conceal='5'}},
+ funcs.getmatches())
end)
end)
diff --git a/test/functional/eval/minmax_functions_spec.lua b/test/functional/vimscript/minmax_functions_spec.lua
index c6eb754f91..91106bef1e 100644
--- a/test/functional/eval/minmax_functions_spec.lua
+++ b/test/functional/vimscript/minmax_functions_spec.lua
@@ -2,29 +2,28 @@ local helpers = require('test.functional.helpers')(after_each)
local eq = helpers.eq
local eval = helpers.eval
+local command = helpers.command
local clear = helpers.clear
local funcs = helpers.funcs
-local redir_exec = helpers.redir_exec
+local pcall_err = helpers.pcall_err
before_each(clear)
for _, func in ipairs({'min', 'max'}) do
describe(func .. '()', function()
it('gives a single error message when multiple values failed conversions',
function()
- eq('\nE745: Using a List as a Number\n0',
- redir_exec('echo ' .. func .. '([-5, [], [], [], 5])'))
- eq('\nE745: Using a List as a Number\n0',
- redir_exec('echo ' .. func .. '({1:-5, 2:[], 3:[], 4:[], 5:5})'))
+ eq('Vim(echo):E745: Using a List as a Number',
+ pcall_err(command, 'echo ' .. func .. '([-5, [], [], [], 5])'))
+ eq('Vim(echo):E745: Using a List as a Number',
+ pcall_err(command, 'echo ' .. func .. '({1:-5, 2:[], 3:[], 4:[], 5:5})'))
for errmsg, errinput in pairs({
- ['E745: Using a List as a Number'] = '[]',
- ['E805: Using a Float as a Number'] = '0.0',
- ['E703: Using a Funcref as a Number'] = 'function("tr")',
- ['E728: Using a Dictionary as a Number'] = '{}',
+ ['Vim(echo):E745: Using a List as a Number'] = '[]',
+ ['Vim(echo):E805: Using a Float as a Number'] = '0.0',
+ ['Vim(echo):E703: Using a Funcref as a Number'] = 'function("tr")',
+ ['Vim(echo):E728: Using a Dictionary as a Number'] = '{}',
}) do
- eq('\n' .. errmsg .. '\n0',
- redir_exec('echo ' .. func .. '([' .. errinput .. '])'))
- eq('\n' .. errmsg .. '\n0',
- redir_exec('echo ' .. func .. '({1:' .. errinput .. '})'))
+ eq(errmsg, pcall_err(command, 'echo ' .. func .. '([' .. errinput .. '])'))
+ eq(errmsg, pcall_err(command, 'echo ' .. func .. '({1:' .. errinput .. '})'))
end
end)
it('works with arrays/dictionaries with zero items', function()
@@ -42,9 +41,8 @@ for _, func in ipairs({'min', 'max'}) do
it('errors out for invalid types', function()
for _, errinput in ipairs({'1', 'v:true', 'v:false', 'v:null',
'function("tr")', '""'}) do
- eq(('\nE712: Argument of %s() must be a List or Dictionary\n0'):format(
- func),
- redir_exec('echo ' .. func .. '(' .. errinput .. ')'))
+ eq(('Vim(echo):E712: Argument of %s() must be a List or Dictionary'):format(func),
+ pcall_err(command, 'echo ' .. func .. '(' .. errinput .. ')'))
end
end)
end)
diff --git a/test/functional/eval/modeline_spec.lua b/test/functional/vimscript/modeline_spec.lua
index c5bb798f4a..b2346079a1 100644
--- a/test/functional/eval/modeline_spec.lua
+++ b/test/functional/vimscript/modeline_spec.lua
@@ -1,6 +1,6 @@
local helpers = require('test.functional.helpers')(after_each)
+local assert_alive = helpers.assert_alive
local clear, command, write_file = helpers.clear, helpers.command, helpers.write_file
-local eq, eval = helpers.eq, helpers.eval
describe("modeline", function()
local tempfile = helpers.tmpname()
@@ -14,6 +14,6 @@ describe("modeline", function()
write_file(tempfile, 'vim100000000000000000000000')
command('e! ' .. tempfile)
- eq(2, eval('1+1')) -- Still alive?
+ assert_alive()
end)
end)
diff --git a/test/functional/eval/msgpack_functions_spec.lua b/test/functional/vimscript/msgpack_functions_spec.lua
index a8a413f68b..837b629858 100644
--- a/test/functional/eval/msgpack_functions_spec.lua
+++ b/test/functional/vimscript/msgpack_functions_spec.lua
@@ -13,6 +13,7 @@ describe('msgpack*() functions', function()
it(msg, function()
nvim('set_var', 'obj', obj)
eq(obj, eval('msgpackparse(msgpackdump(g:obj))'))
+ eq(obj, eval('msgpackparse(msgpackdump(g:obj, "B"))'))
end)
end
@@ -364,8 +365,7 @@ describe('msgpack*() functions', function()
command('let dumped = ["\\xC4\\x01\\n"]')
command('let parsed = msgpackparse(dumped)')
command('let dumped2 = msgpackdump(parsed)')
- eq({{_TYPE={}, _VAL={'\n'}}}, eval('parsed'))
- eq(1, eval('parsed[0]._TYPE is v:msgpack_types.binary'))
+ eq({'\000'}, eval('parsed'))
eq(1, eval('dumped ==# dumped2'))
end)
@@ -392,56 +392,61 @@ describe('msgpack*() functions', function()
end)
end)
+local blobstr = function(list)
+ local l = {}
+ for i,v in ipairs(list) do
+ l[i] = v:gsub('\n', '\000')
+ end
+ return table.concat(l, '\n')
+end
+
+-- Test msgpackparse() with a readfile()-style list and a blob argument
+local parse_eq = function(expect, list_arg)
+ local blob_expr = '0z' .. blobstr(list_arg):gsub('(.)', function(c)
+ return ('%.2x'):format(c:byte())
+ end)
+ eq(expect, funcs.msgpackparse(list_arg))
+ command('let g:parsed = msgpackparse(' .. blob_expr .. ')')
+ eq(expect, eval('g:parsed'))
+end
+
describe('msgpackparse() function', function()
before_each(clear)
it('restores nil as v:null', function()
- command('let dumped = ["\\xC0"]')
- command('let parsed = msgpackparse(dumped)')
- eq('[v:null]', eval('string(parsed)'))
+ parse_eq(eval('[v:null]'), {'\192'})
end)
it('restores boolean false as v:false', function()
- command('let dumped = ["\\xC2"]')
- command('let parsed = msgpackparse(dumped)')
- eq({false}, eval('parsed'))
+ parse_eq({false}, {'\194'})
end)
it('restores boolean true as v:true', function()
- command('let dumped = ["\\xC3"]')
- command('let parsed = msgpackparse(dumped)')
- eq({true}, eval('parsed'))
+ parse_eq({true}, {'\195'})
end)
it('restores FIXSTR as special dict', function()
- command('let dumped = ["\\xa2ab"]')
- command('let parsed = msgpackparse(dumped)')
- eq({{_TYPE={}, _VAL={'ab'}}}, eval('parsed'))
+ parse_eq({{_TYPE={}, _VAL={'ab'}}}, {'\162ab'})
eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.string'))
end)
it('restores BIN 8 as string', function()
- command('let dumped = ["\\xC4\\x02ab"]')
- eq({'ab'}, eval('msgpackparse(dumped)'))
+ parse_eq({'ab'}, {'\196\002ab'})
end)
it('restores FIXEXT1 as special dictionary', function()
- command('let dumped = ["\\xD4\\x10", ""]')
- command('let parsed = msgpackparse(dumped)')
- eq({{_TYPE={}, _VAL={0x10, {"", ""}}}}, eval('parsed'))
+ parse_eq({{_TYPE={}, _VAL={0x10, {"", ""}}}}, {'\212\016', ''})
eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.ext'))
end)
it('restores MAP with BIN key as special dictionary', function()
- command('let dumped = ["\\x81\\xC4\\x01a\\xC4\\n"]')
- command('let parsed = msgpackparse(dumped)')
- eq({{_TYPE={}, _VAL={{'a', ''}}}}, eval('parsed'))
+ parse_eq({{_TYPE={}, _VAL={{'a', ''}}}}, {'\129\196\001a\196\n'})
eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.map'))
end)
it('restores MAP with duplicate STR keys as special dictionary', function()
command('let dumped = ["\\x82\\xA1a\\xC4\\n\\xA1a\\xC4\\n"]')
- -- FIXME Internal error bug
+ -- FIXME Internal error bug, can't use parse_eq() here
command('silent! let parsed = msgpackparse(dumped)')
eq({{_TYPE={}, _VAL={ {{_TYPE={}, _VAL={'a'}}, ''},
{{_TYPE={}, _VAL={'a'}}, ''}}} }, eval('parsed'))
@@ -451,9 +456,7 @@ describe('msgpackparse() function', function()
end)
it('restores MAP with MAP key as special dictionary', function()
- command('let dumped = ["\\x81\\x80\\xC4\\n"]')
- command('let parsed = msgpackparse(dumped)')
- eq({{_TYPE={}, _VAL={{{}, ''}}}}, eval('parsed'))
+ parse_eq({{_TYPE={}, _VAL={{{}, ''}}}}, {'\129\128\196\n'})
eq(1, eval('g:parsed[0]._TYPE is v:msgpack_types.map'))
end)
@@ -478,43 +481,65 @@ describe('msgpackparse() function', function()
end)
it('fails to parse a string', function()
- eq('Vim(call):E686: Argument of msgpackparse() must be a List',
+ eq('Vim(call):E899: Argument of msgpackparse() must be a List or Blob',
exc_exec('call msgpackparse("abcdefghijklmnopqrstuvwxyz")'))
end)
it('fails to parse a number', function()
- eq('Vim(call):E686: Argument of msgpackparse() must be a List',
+ eq('Vim(call):E899: Argument of msgpackparse() must be a List or Blob',
exc_exec('call msgpackparse(127)'))
end)
it('fails to parse a dictionary', function()
- eq('Vim(call):E686: Argument of msgpackparse() must be a List',
+ eq('Vim(call):E899: Argument of msgpackparse() must be a List or Blob',
exc_exec('call msgpackparse({})'))
end)
it('fails to parse a funcref', function()
- eq('Vim(call):E686: Argument of msgpackparse() must be a List',
+ eq('Vim(call):E899: Argument of msgpackparse() must be a List or Blob',
exc_exec('call msgpackparse(function("tr"))'))
end)
it('fails to parse a partial', function()
command('function T() dict\nendfunction')
- eq('Vim(call):E686: Argument of msgpackparse() must be a List',
+ eq('Vim(call):E899: Argument of msgpackparse() must be a List or Blob',
exc_exec('call msgpackparse(function("T", [1, 2], {}))'))
end)
it('fails to parse a float', function()
- eq('Vim(call):E686: Argument of msgpackparse() must be a List',
+ eq('Vim(call):E899: Argument of msgpackparse() must be a List or Blob',
exc_exec('call msgpackparse(0.0)'))
end)
+
+ it('fails on incomplete msgpack string', function()
+ local expected = 'Vim(call):E475: Invalid argument: Incomplete msgpack string'
+ eq(expected, exc_exec([[call msgpackparse(["\xc4"])]]))
+ eq(expected, exc_exec([[call msgpackparse(["\xca", "\x02\x03"])]]))
+ eq(expected, exc_exec('call msgpackparse(0zc4)'))
+ eq(expected, exc_exec('call msgpackparse(0zca0a0203)'))
+ end)
+
+ it('fails when unable to parse msgpack string', function()
+ local expected = 'Vim(call):E475: Invalid argument: Failed to parse msgpack string'
+ eq(expected, exc_exec([[call msgpackparse(["\xc1"])]]))
+ eq(expected, exc_exec('call msgpackparse(0zc1)'))
+ end)
end)
describe('msgpackdump() function', function()
before_each(clear)
+ local dump_eq = function(exp_list, arg_expr)
+ eq(exp_list, eval('msgpackdump(' .. arg_expr .. ')'))
+ eq(blobstr(exp_list), eval('msgpackdump(' .. arg_expr .. ', "B")'))
+ end
+
it('dumps string as BIN 8', function()
- nvim('set_var', 'obj', {'Test'})
- eq({"\196\004Test"}, eval('msgpackdump(obj)'))
+ dump_eq({'\196\004Test'}, '["Test"]')
+ end)
+
+ it('dumps blob as BIN 8', function()
+ dump_eq({'\196\005Bl\nb!'}, '[0z426c006221]')
end)
it('can dump generic mapping with generic mapping keys and values', function()
@@ -522,56 +547,56 @@ describe('msgpackdump() function', function()
command('let todumpv1 = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
command('let todumpv2 = {"_TYPE": v:msgpack_types.map, "_VAL": []}')
command('call add(todump._VAL, [todumpv1, todumpv2])')
- eq({'\129\128\128'}, eval('msgpackdump([todump])'))
+ dump_eq({'\129\128\128'}, '[todump]')
end)
it('can dump v:true', function()
- eq({'\195'}, funcs.msgpackdump({true}))
+ dump_eq({'\195'}, '[v:true]')
end)
it('can dump v:false', function()
- eq({'\194'}, funcs.msgpackdump({false}))
+ dump_eq({'\194'}, '[v:false]')
end)
- it('can v:null', function()
- command('let todump = v:null')
+ it('can dump v:null', function()
+ dump_eq({'\192'}, '[v:null]')
end)
it('can dump special bool mapping (true)', function()
command('let todump = {"_TYPE": v:msgpack_types.boolean, "_VAL": 1}')
- eq({'\195'}, eval('msgpackdump([todump])'))
+ dump_eq({'\195'}, '[todump]')
end)
it('can dump special bool mapping (false)', function()
command('let todump = {"_TYPE": v:msgpack_types.boolean, "_VAL": 0}')
- eq({'\194'}, eval('msgpackdump([todump])'))
+ dump_eq({'\194'}, '[todump]')
end)
it('can dump special nil mapping', function()
command('let todump = {"_TYPE": v:msgpack_types.nil, "_VAL": 0}')
- eq({'\192'}, eval('msgpackdump([todump])'))
+ dump_eq({'\192'}, '[todump]')
end)
it('can dump special ext mapping', function()
command('let todump = {"_TYPE": v:msgpack_types.ext, "_VAL": [5, ["",""]]}')
- eq({'\212\005', ''}, eval('msgpackdump([todump])'))
+ dump_eq({'\212\005', ''}, '[todump]')
end)
it('can dump special array mapping', function()
command('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": [5, [""]]}')
- eq({'\146\005\145\196\n'}, eval('msgpackdump([todump])'))
+ dump_eq({'\146\005\145\196\n'}, '[todump]')
end)
it('can dump special UINT64_MAX mapping', function()
command('let todump = {"_TYPE": v:msgpack_types.integer}')
command('let todump._VAL = [1, 3, 0x7FFFFFFF, 0x7FFFFFFF]')
- eq({'\207\255\255\255\255\255\255\255\255'}, eval('msgpackdump([todump])'))
+ dump_eq({'\207\255\255\255\255\255\255\255\255'}, '[todump]')
end)
it('can dump special INT64_MIN mapping', function()
command('let todump = {"_TYPE": v:msgpack_types.integer}')
command('let todump._VAL = [-1, 2, 0, 0]')
- eq({'\211\128\n\n\n\n\n\n\n'}, eval('msgpackdump([todump])'))
+ dump_eq({'\211\128\n\n\n\n\n\n\n'}, '[todump]')
end)
it('fails to dump a function reference', function()
@@ -610,13 +635,13 @@ describe('msgpackdump() function', function()
it('can dump dict with two same dicts inside', function()
command('let inter = {}')
command('let todump = {"a": inter, "b": inter}')
- eq({"\130\161a\128\161b\128"}, eval('msgpackdump([todump])'))
+ dump_eq({"\130\161a\128\161b\128"}, '[todump]')
end)
it('can dump list with two same lists inside', function()
command('let inter = []')
command('let todump = [inter, inter]')
- eq({"\146\144\144"}, eval('msgpackdump([todump])'))
+ dump_eq({"\146\144\144"}, '[todump]')
end)
it('fails to dump a recursive list in a special dict', function()
@@ -667,9 +692,9 @@ describe('msgpackdump() function', function()
exc_exec('call msgpackdump()'))
end)
- it('fails when called with two arguments', function()
+ it('fails when called with three arguments', function()
eq('Vim(call):E118: Too many arguments for function: msgpackdump',
- exc_exec('call msgpackdump(["", ""], 1)'))
+ exc_exec('call msgpackdump(["", ""], 1, 2)'))
end)
it('fails to dump a string', function()
@@ -711,9 +736,13 @@ describe('msgpackdump() function', function()
end)
it('can dump NULL string', function()
- eq({'\196\n'}, eval('msgpackdump([$XXX_UNEXISTENT_VAR_XXX])'))
- eq({'\196\n'}, eval('msgpackdump([{"_TYPE": v:msgpack_types.binary, "_VAL": [$XXX_UNEXISTENT_VAR_XXX]}])'))
- eq({'\160'}, eval('msgpackdump([{"_TYPE": v:msgpack_types.string, "_VAL": [$XXX_UNEXISTENT_VAR_XXX]}])'))
+ dump_eq({'\196\n'}, '[$XXX_UNEXISTENT_VAR_XXX]')
+ dump_eq({'\196\n'}, '[{"_TYPE": v:msgpack_types.binary, "_VAL": [$XXX_UNEXISTENT_VAR_XXX]}]')
+ dump_eq({'\160'}, '[{"_TYPE": v:msgpack_types.string, "_VAL": [$XXX_UNEXISTENT_VAR_XXX]}]')
+ end)
+
+ it('can dump NULL blob', function()
+ eq({'\196\n'}, eval('msgpackdump([v:_null_blob])'))
end)
it('can dump NULL list', function()
diff --git a/test/functional/eval/null_spec.lua b/test/functional/vimscript/null_spec.lua
index b1ceff9115..7ecbcd2fd6 100644
--- a/test/functional/eval/null_spec.lua
+++ b/test/functional/vimscript/null_spec.lua
@@ -1,7 +1,6 @@
local helpers = require('test.functional.helpers')(after_each)
local curbufmeths = helpers.curbufmeths
-local redir_exec = helpers.redir_exec
local exc_exec = helpers.exc_exec
local command = helpers.command
local clear = helpers.clear
@@ -9,6 +8,19 @@ local meths = helpers.meths
local funcs = helpers.funcs
local eq = helpers.eq
+local function redir_exec(cmd)
+ meths.set_var('__redir_exec_cmd', cmd)
+ command([[
+ redir => g:__redir_exec_output
+ silent! execute g:__redir_exec_cmd
+ redir END
+ ]])
+ local ret = meths.get_var('__redir_exec_output')
+ meths.del_var('__redir_exec_output')
+ meths.del_var('__redir_exec_cmd')
+ return ret
+end
+
describe('NULL', function()
before_each(function()
clear()
@@ -44,7 +56,7 @@ describe('NULL', function()
-- Incorrect behaviour
-- FIXME Should error out with different message
null_test('makes :unlet act as if it is not a list', ':unlet L[0]',
- 'Vim(unlet):E689: Can only index a List or Dictionary')
+ 'Vim(unlet):E689: Can only index a List, Dictionary or Blob')
-- Subjectable behaviour
@@ -53,7 +65,7 @@ describe('NULL', function()
-- Correct behaviour
null_expr_test('can be indexed with error message for empty list', 'L[0]',
- 'E684: list index out of range: 0\nE15: Invalid expression: L[0]', nil)
+ 'E684: list index out of range: 0', nil)
null_expr_test('can be splice-indexed', 'L[:]', 0, {})
null_expr_test('is not locked', 'islocked("v:_null_list")', 0, 0)
null_test('is accepted by :for', 'for x in L|throw x|endfor', 0)
@@ -68,7 +80,7 @@ describe('NULL', function()
null_expr_test('can be copied', 'copy(L)', 0, {})
null_expr_test('can be deepcopied', 'deepcopy(L)', 0, {})
null_expr_test('does not crash when indexed', 'L[1]',
- 'E684: list index out of range: 1\nE15: Invalid expression: L[1]', nil)
+ 'E684: list index out of range: 1', nil)
null_expr_test('does not crash call()', 'call("arglistid", L)', 0, 0)
null_expr_test('does not crash col()', 'col(L)', 0, 0)
null_expr_test('does not crash virtcol()', 'virtcol(L)', 0, 0)
@@ -135,7 +147,7 @@ describe('NULL', function()
end)
describe('dict', function()
it('does not crash when indexing NULL dict', function()
- eq('\nE716: Key not present in Dictionary: "test"\nE15: Invalid expression: v:_null_dict.test',
+ eq('\nE716: Key not present in Dictionary: "test"',
redir_exec('echo v:_null_dict.test'))
end)
null_expr_test('makes extend error out', 'extend(D, {})', 'E742: Cannot change value of extend() argument', 0)
diff --git a/test/functional/eval/operators_spec.lua b/test/functional/vimscript/operators_spec.lua
index 4d07bc1b05..4d07bc1b05 100644
--- a/test/functional/eval/operators_spec.lua
+++ b/test/functional/vimscript/operators_spec.lua
diff --git a/test/functional/eval/printf_spec.lua b/test/functional/vimscript/printf_spec.lua
index 27e24c4118..27e24c4118 100644
--- a/test/functional/eval/printf_spec.lua
+++ b/test/functional/vimscript/printf_spec.lua
diff --git a/test/functional/eval/reltime_spec.lua b/test/functional/vimscript/reltime_spec.lua
index d87943e485..d87943e485 100644
--- a/test/functional/eval/reltime_spec.lua
+++ b/test/functional/vimscript/reltime_spec.lua
diff --git a/test/functional/eval/server_spec.lua b/test/functional/vimscript/server_spec.lua
index 238d1aeb0f..238d1aeb0f 100644
--- a/test/functional/eval/server_spec.lua
+++ b/test/functional/vimscript/server_spec.lua
diff --git a/test/functional/eval/setpos_spec.lua b/test/functional/vimscript/setpos_spec.lua
index 935f387bcc..935f387bcc 100644
--- a/test/functional/eval/setpos_spec.lua
+++ b/test/functional/vimscript/setpos_spec.lua
diff --git a/test/functional/eval/sort_spec.lua b/test/functional/vimscript/sort_spec.lua
index e1cc2c2924..e09949a0f2 100644
--- a/test/functional/eval/sort_spec.lua
+++ b/test/functional/vimscript/sort_spec.lua
@@ -8,7 +8,7 @@ local meths = helpers.meths
local funcs = helpers.funcs
local command = helpers.command
local exc_exec = helpers.exc_exec
-local redir_exec = helpers.redir_exec
+local pcall_err = helpers.pcall_err
before_each(clear)
@@ -50,8 +50,7 @@ describe('sort()', function()
return (a:a > a:b) - (a:a < a:b)
endfunction
]])
- eq('\nE745: Using a List as a Number\nE702: Sort compare function failed',
- redir_exec('let sl = sort([1, 0, [], 3, 2], "Cmp")'))
- eq({1, 0, {}, 3, 2}, meths.get_var('sl'))
+ eq('Vim(let):E745: Using a List as a Number',
+ pcall_err(command, 'let sl = sort([1, 0, [], 3, 2], "Cmp")'))
end)
end)
diff --git a/test/functional/eval/special_vars_spec.lua b/test/functional/vimscript/special_vars_spec.lua
index 97a12d490d..97a12d490d 100644
--- a/test/functional/eval/special_vars_spec.lua
+++ b/test/functional/vimscript/special_vars_spec.lua
diff --git a/test/functional/eval/string_spec.lua b/test/functional/vimscript/string_spec.lua
index adc1af9b8e..cb7e93f264 100644
--- a/test/functional/eval/string_spec.lua
+++ b/test/functional/vimscript/string_spec.lua
@@ -5,11 +5,10 @@ local command = helpers.command
local meths = helpers.meths
local eval = helpers.eval
local exc_exec = helpers.exc_exec
-local redir_exec = helpers.redir_exec
+local pcall_err = helpers.pcall_err
local funcs = helpers.funcs
local NIL = helpers.NIL
local source = helpers.source
-local dedent = helpers.dedent
describe('string() function', function()
before_each(clear)
@@ -140,8 +139,8 @@ describe('string() function', function()
let TestDictRef = function('TestDict', d)
let d.tdr = TestDictRef
]])
- eq("\nE724: unable to correctly dump variable with self-referencing container\nfunction('TestDict', {'tdr': function('TestDict', {E724@1})})",
- redir_exec('echo string(d.tdr)'))
+ eq("Vim(echo):E724: unable to correctly dump variable with self-referencing container",
+ pcall_err(command, 'echo string(d.tdr)'))
end)
it('dumps automatically created partials', function()
@@ -163,11 +162,8 @@ describe('string() function', function()
it('does not crash or halt when dumping partials with reference cycles in self',
function()
meths.set_var('d', {v=true})
- eq(dedent([[
-
- E724: unable to correctly dump variable with self-referencing container
- {'p': function('<SNR>1_Test2', {E724@0}), 'f': function('<SNR>1_Test2'), 'v': v:true}]]),
- redir_exec('echo string(extend(extend(g:d, {"f": g:Test2_f}), {"p": g:d.f}))'))
+ eq([[Vim(echo):E724: unable to correctly dump variable with self-referencing container]],
+ pcall_err(command, 'echo string(extend(extend(g:d, {"f": g:Test2_f}), {"p": g:d.f}))'))
end)
it('does not show errors when dumping partials referencing the same dictionary',
@@ -190,11 +186,8 @@ describe('string() function', function()
-- there was error in dumping partials). Tested explicitly in
-- test/unit/api/private_helpers_spec.lua.
eval('add(l, function("Test1", l))')
- eq(dedent([=[
-
- E724: unable to correctly dump variable with self-referencing container
- function('Test1', [[{E724@2}, function('Test1', [{E724@2}])], function('Test1', [[{E724@4}, function('Test1', [{E724@4}])]])])]=]),
- redir_exec('echo string(function("Test1", l))'))
+ eq([=[Vim(echo):E724: unable to correctly dump variable with self-referencing container]=],
+ pcall_err(command, 'echo string(function("Test1", l))'))
end)
it('does not crash or halt when dumping partials with reference cycles in self and arguments',
@@ -204,11 +197,8 @@ describe('string() function', function()
eval('add(l, l)')
eval('add(l, function("Test1", l))')
eval('add(l, function("Test1", d))')
- eq(dedent([=[
-
- E724: unable to correctly dump variable with self-referencing container
- {'p': function('<SNR>1_Test2', [[{E724@3}, function('Test1', [{E724@3}]), function('Test1', {E724@0})], function('Test1', [[{E724@5}, function('Test1', [{E724@5}]), function('Test1', {E724@0})]]), function('Test1', {E724@0})], {E724@0}), 'f': function('<SNR>1_Test2'), 'v': v:true}]=]),
- redir_exec('echo string(extend(extend(g:d, {"f": g:Test2_f}), {"p": function(g:d.f, l)}))'))
+ eq([=[Vim(echo):E724: unable to correctly dump variable with self-referencing container]=],
+ pcall_err(command, 'echo string(extend(extend(g:d, {"f": g:Test2_f}), {"p": function(g:d.f, l)}))'))
end)
end)
@@ -235,10 +225,10 @@ describe('string() function', function()
it('dumps recursive lists despite the error', function()
meths.set_var('l', {})
eval('add(l, l)')
- eq('\nE724: unable to correctly dump variable with self-referencing container\n[{E724@0}]',
- redir_exec('echo string(l)'))
- eq('\nE724: unable to correctly dump variable with self-referencing container\n[[{E724@1}]]',
- redir_exec('echo string([l])'))
+ eq('Vim(echo):E724: unable to correctly dump variable with self-referencing container',
+ pcall_err(command, 'echo string(l)'))
+ eq('Vim(echo):E724: unable to correctly dump variable with self-referencing container',
+ pcall_err(command, 'echo string([l])'))
end)
end)
@@ -268,10 +258,10 @@ describe('string() function', function()
it('dumps recursive dictionaries despite the error', function()
meths.set_var('d', {d=1})
eval('extend(d, {"d": d})')
- eq('\nE724: unable to correctly dump variable with self-referencing container\n{\'d\': {E724@0}}',
- redir_exec('echo string(d)'))
- eq('\nE724: unable to correctly dump variable with self-referencing container\n{\'out\': {\'d\': {E724@1}}}',
- redir_exec('echo string({"out": d})'))
+ eq('Vim(echo):E724: unable to correctly dump variable with self-referencing container',
+ pcall_err(command, 'echo string(d)'))
+ eq('Vim(echo):E724: unable to correctly dump variable with self-referencing container',
+ pcall_err(command, 'echo string({"out": d})'))
end)
end)
end)
diff --git a/test/functional/eval/system_spec.lua b/test/functional/vimscript/system_spec.lua
index c374baf695..24a1f05390 100644
--- a/test/functional/eval/system_spec.lua
+++ b/test/functional/vimscript/system_spec.lua
@@ -1,5 +1,6 @@
local helpers = require('test.functional.helpers')(after_each)
+local assert_alive = helpers.assert_alive
local nvim_dir = helpers.nvim_dir
local eq, call, clear, eval, feed_command, feed, nvim =
helpers.eq, helpers.call, helpers.clear, helpers.eval, helpers.feed_command,
@@ -302,7 +303,7 @@ describe('system()', function()
if v_errnum then
eq("E5677:", v_errnum)
end
- eq(2, eval("1+1")) -- Still alive?
+ assert_alive()
end)
end)
@@ -317,11 +318,11 @@ describe('system()', function()
if v_errnum then
eq("E5677:", v_errnum)
end
- eq(2, eval("1+1")) -- Still alive?
+ assert_alive()
end)
it('works with an empty string', function()
eq("test\n", eval('system("echo test", "")'))
- eq(2, eval("1+1")) -- Still alive?
+ assert_alive()
end)
end)
diff --git a/test/functional/eval/timer_spec.lua b/test/functional/vimscript/timer_spec.lua
index 9ee0735e40..9ee0735e40 100644
--- a/test/functional/eval/timer_spec.lua
+++ b/test/functional/vimscript/timer_spec.lua
diff --git a/test/functional/eval/uniq_spec.lua b/test/functional/vimscript/uniq_spec.lua
index 5cdba0a0f6..43ad4a7640 100644
--- a/test/functional/eval/uniq_spec.lua
+++ b/test/functional/vimscript/uniq_spec.lua
@@ -2,10 +2,9 @@ local helpers = require('test.functional.helpers')(after_each)
local eq = helpers.eq
local clear = helpers.clear
-local meths = helpers.meths
local command = helpers.command
local exc_exec = helpers.exc_exec
-local redir_exec = helpers.redir_exec
+local pcall_err = helpers.pcall_err
before_each(clear)
@@ -24,8 +23,7 @@ describe('uniq()', function()
return (a:a > a:b) - (a:a < a:b)
endfunction
]])
- eq('\nE745: Using a List as a Number\nE882: Uniq compare function failed',
- redir_exec('let fl = uniq([0, 0, [], 1, 1], "Cmp")'))
- eq({0, {}, 1, 1}, meths.get_var('fl'))
+ eq('Vim(let):E745: Using a List as a Number',
+ pcall_err(command, 'let fl = uniq([0, 0, [], 1, 1], "Cmp")'))
end)
end)
diff --git a/test/functional/eval/vvar_event_spec.lua b/test/functional/vimscript/vvar_event_spec.lua
index eec8aa917a..eec8aa917a 100644
--- a/test/functional/eval/vvar_event_spec.lua
+++ b/test/functional/vimscript/vvar_event_spec.lua
diff --git a/test/functional/eval/wait_spec.lua b/test/functional/vimscript/wait_spec.lua
index ee95e02a7f..ee95e02a7f 100644
--- a/test/functional/eval/wait_spec.lua
+++ b/test/functional/vimscript/wait_spec.lua
diff --git a/test/functional/eval/writefile_spec.lua b/test/functional/vimscript/writefile_spec.lua
index 356680ba7c..5f693249a9 100644
--- a/test/functional/eval/writefile_spec.lua
+++ b/test/functional/vimscript/writefile_spec.lua
@@ -8,7 +8,8 @@ local meths = helpers.meths
local exc_exec = helpers.exc_exec
local read_file = helpers.read_file
local write_file = helpers.write_file
-local redir_exec = helpers.redir_exec
+local pcall_err = helpers.pcall_err
+local command = helpers.command
local fname = 'Xtest-functional-eval-writefile'
local dname = fname .. '.d'
@@ -106,51 +107,51 @@ describe('writefile()', function()
it('shows correct file name when supplied numbers', function()
meths.set_current_dir(dname)
- eq('\nE482: Can\'t open file 2 for writing: illegal operation on a directory',
- redir_exec(('call writefile([42], %s)'):format(ddname_tail)))
+ eq('Vim(call):E482: Can\'t open file 2 for writing: illegal operation on a directory',
+ pcall_err(command, ('call writefile([42], %s)'):format(ddname_tail)))
end)
it('errors out with invalid arguments', function()
write_file(fname, 'TEST')
- eq('\nE119: Not enough arguments for function: writefile',
- redir_exec('call writefile()'))
- eq('\nE119: Not enough arguments for function: writefile',
- redir_exec('call writefile([])'))
- eq('\nE118: Too many arguments for function: writefile',
- redir_exec(('call writefile([], "%s", "b", 1)'):format(fname)))
+ eq('Vim(call):E119: Not enough arguments for function: writefile',
+ pcall_err(command, 'call writefile()'))
+ eq('Vim(call):E119: Not enough arguments for function: writefile',
+ pcall_err(command, 'call writefile([])'))
+ eq('Vim(call):E118: Too many arguments for function: writefile',
+ pcall_err(command, ('call writefile([], "%s", "b", 1)'):format(fname)))
for _, arg in ipairs({'0', '0.0', 'function("tr")', '{}', '"test"'}) do
- eq('\nE686: Argument of writefile() must be a List',
- redir_exec(('call writefile(%s, "%s", "b")'):format(arg, fname)))
+ eq('Vim(call):E475: Invalid argument: writefile() first argument must be a List or a Blob',
+ pcall_err(command, ('call writefile(%s, "%s", "b")'):format(arg, fname)))
end
for _, args in ipairs({'[], %s, "b"', '[], "' .. fname .. '", %s'}) do
- eq('\nE806: using Float as a String',
- redir_exec(('call writefile(%s)'):format(args:format('0.0'))))
- eq('\nE730: using List as a String',
- redir_exec(('call writefile(%s)'):format(args:format('[]'))))
- eq('\nE731: using Dictionary as a String',
- redir_exec(('call writefile(%s)'):format(args:format('{}'))))
- eq('\nE729: using Funcref as a String',
- redir_exec(('call writefile(%s)'):format(args:format('function("tr")'))))
+ eq('Vim(call):E806: using Float as a String',
+ pcall_err(command, ('call writefile(%s)'):format(args:format('0.0'))))
+ eq('Vim(call):E730: using List as a String',
+ pcall_err(command, ('call writefile(%s)'):format(args:format('[]'))))
+ eq('Vim(call):E731: using Dictionary as a String',
+ pcall_err(command, ('call writefile(%s)'):format(args:format('{}'))))
+ eq('Vim(call):E729: using Funcref as a String',
+ pcall_err(command, ('call writefile(%s)'):format(args:format('function("tr")'))))
end
- eq('\nE5060: Unknown flag: «»',
- redir_exec(('call writefile([], "%s", "bs«»")'):format(fname)))
+ eq('Vim(call):E5060: Unknown flag: «»',
+ pcall_err(command, ('call writefile([], "%s", "bs«»")'):format(fname)))
eq('TEST', read_file(fname))
end)
it('does not write to file if error in list', function()
local args = '["tset"] + repeat([%s], 3), "' .. fname .. '"'
- eq('\nE805: Expected a Number or a String, Float found',
- redir_exec(('call writefile(%s)'):format(args:format('0.0'))))
+ eq('Vim(call):E805: Expected a Number or a String, Float found',
+ pcall_err(command, ('call writefile(%s)'):format(args:format('0.0'))))
eq(nil, read_file(fname))
write_file(fname, 'TEST')
- eq('\nE745: Expected a Number or a String, List found',
- redir_exec(('call writefile(%s)'):format(args:format('[]'))))
+ eq('Vim(call):E745: Expected a Number or a String, List found',
+ pcall_err(command, ('call writefile(%s)'):format(args:format('[]'))))
eq('TEST', read_file(fname))
- eq('\nE728: Expected a Number or a String, Dictionary found',
- redir_exec(('call writefile(%s)'):format(args:format('{}'))))
+ eq('Vim(call):E728: Expected a Number or a String, Dictionary found',
+ pcall_err(command, ('call writefile(%s)'):format(args:format('{}'))))
eq('TEST', read_file(fname))
- eq('\nE703: Expected a Number or a String, Funcref found',
- redir_exec(('call writefile(%s)'):format(args:format('function("tr")'))))
+ eq('Vim(call):E703: Expected a Number or a String, Funcref found',
+ pcall_err(command, ('call writefile(%s)'):format(args:format('function("tr")'))))
eq('TEST', read_file(fname))
end)
end)
diff --git a/test/functional/visual/meta_key_spec.lua b/test/functional/visual/meta_key_spec.lua
deleted file mode 100644
index 11f7203da0..0000000000
--- a/test/functional/visual/meta_key_spec.lua
+++ /dev/null
@@ -1,22 +0,0 @@
-local helpers = require('test.functional.helpers')(after_each)
-local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
-local command = helpers.command
-local expect = helpers.expect
-
-describe('meta-keys-in-visual-mode', function()
- before_each(function()
- clear()
- end)
-
- it('ALT/META', function()
- -- Unmapped ALT-chords behave as Esc+c
- insert('peaches')
- feed('viw<A-x>viw<M-x>')
- expect('peach')
- -- Mapped ALT-chord behaves as mapped.
- command('vnoremap <M-l> Ameta-l<Esc>')
- command('vnoremap <A-j> Aalt-j<Esc>')
- feed('viw<A-j>viw<M-l>')
- expect('peachalt-jmeta-l')
- end)
-end)
diff --git a/test/helpers.lua b/test/helpers.lua
index 12d9f19187..9ac3904776 100644
--- a/test/helpers.lua
+++ b/test/helpers.lua
@@ -58,9 +58,9 @@ local check_logs_useless_lines = {
--- Invokes `fn` and includes the tail of `logfile` in the error message if it
--- fails.
---
---@param logfile Log file, defaults to $NVIM_LOG_FILE or '.nvimlog'
---@param fn Function to invoke
---@param ... Function arguments
+---@param logfile Log file, defaults to $NVIM_LOG_FILE or '.nvimlog'
+---@param fn Function to invoke
+---@param ... Function arguments
local function dumplog(logfile, fn, ...)
-- module.validate({
-- logfile={logfile,'s',true},
@@ -70,7 +70,7 @@ local function dumplog(logfile, fn, ...)
if status == false then
logfile = logfile or os.getenv('NVIM_LOG_FILE') or '.nvimlog'
local logtail = module.read_nvim_log(logfile)
- error(string.format('%s\n%s', rv, logtail))
+ error(string.format('%s\n%s', tostring(rv), logtail))
end
end
function module.eq(expected, actual, context, logfile)
@@ -102,8 +102,8 @@ end
--- Asserts that `pat` matches one or more lines in the tail of $NVIM_LOG_FILE.
---
---@param pat (string) Lua pattern to search for in the log file.
---@param logfile (string, default=$NVIM_LOG_FILE) full path to log file.
+---@param pat (string) Lua pattern to search for in the log file.
+---@param logfile (string, default=$NVIM_LOG_FILE) full path to log file.
function module.assert_log(pat, logfile)
logfile = logfile or os.getenv('NVIM_LOG_FILE') or '.nvimlog'
local nrlines = 10
@@ -810,6 +810,6 @@ function module.read_nvim_log(logfile, ci_rename)
return log
end
-module = shared.tbl_extend('error', module, Paths, shared)
+module = shared.tbl_extend('error', module, Paths, shared, require('test.deprecated'))
return module
diff --git a/test/unit/charset/vim_str2nr_spec.lua b/test/unit/charset/vim_str2nr_spec.lua
index 891e6def09..5fc3b83a13 100644
--- a/test/unit/charset/vim_str2nr_spec.lua
+++ b/test/unit/charset/vim_str2nr_spec.lua
@@ -43,7 +43,8 @@ local function argreset(arg, args)
end
end
-local function test_vim_str2nr(s, what, exp, maxlen)
+local function test_vim_str2nr(s, what, exp, maxlen, strict)
+ if strict == nil then strict = true end
local bits = {}
for k, _ in pairs(exp) do
bits[#bits + 1] = k
@@ -62,11 +63,11 @@ local function test_vim_str2nr(s, what, exp, maxlen)
cv[k] = args[k]
end
end
- lib.vim_str2nr(s, cv.pre, cv.len, what, cv.num, cv.unum, maxlen)
+ lib.vim_str2nr(s, cv.pre, cv.len, what, cv.num, cv.unum, maxlen, strict)
for cck, ccv in pairs(cv) do
if exp[cck] ~= tonumber(ccv[0]) then
- error(('Failed check (%s = %d) in test (s=%s, w=%u, m=%d): %d'):format(
- cck, exp[cck], s, tonumber(what), maxlen, tonumber(ccv[0])
+ error(('Failed check (%s = %d) in test (s=%s, w=%u, m=%d, strict=%s): %d'):format(
+ cck, exp[cck], s, tonumber(what), maxlen, tostring(strict), tonumber(ccv[0])
))
end
end
@@ -85,10 +86,13 @@ describe('vim_str2nr()', function()
test_vim_str2nr('', lib.STR2NR_ALL, {len = 0, num = 0, unum = 0, pre = 0}, 0)
test_vim_str2nr('', lib.STR2NR_BIN, {len = 0, num = 0, unum = 0, pre = 0}, 0)
test_vim_str2nr('', lib.STR2NR_OCT, {len = 0, num = 0, unum = 0, pre = 0}, 0)
+ test_vim_str2nr('', lib.STR2NR_OOCT, {len = 0, num = 0, unum = 0, pre = 0}, 0)
test_vim_str2nr('', lib.STR2NR_HEX, {len = 0, num = 0, unum = 0, pre = 0}, 0)
test_vim_str2nr('', lib.STR2NR_FORCE + lib.STR2NR_DEC, {len = 0, num = 0, unum = 0, pre = 0}, 0)
test_vim_str2nr('', lib.STR2NR_FORCE + lib.STR2NR_BIN, {len = 0, num = 0, unum = 0, pre = 0}, 0)
test_vim_str2nr('', lib.STR2NR_FORCE + lib.STR2NR_OCT, {len = 0, num = 0, unum = 0, pre = 0}, 0)
+ test_vim_str2nr('', lib.STR2NR_FORCE + lib.STR2NR_OOCT, {len = 0, num = 0, unum = 0, pre = 0}, 0)
+ test_vim_str2nr('', lib.STR2NR_FORCE + lib.STR2NR_OCT + lib.STR2NR_OOCT, {len = 0, num = 0, unum = 0, pre = 0}, 0)
test_vim_str2nr('', lib.STR2NR_FORCE + lib.STR2NR_HEX, {len = 0, num = 0, unum = 0, pre = 0}, 0)
end)
itp('works with decimal numbers', function()
@@ -97,31 +101,39 @@ describe('vim_str2nr()', function()
lib.STR2NR_BIN,
lib.STR2NR_OCT,
lib.STR2NR_HEX,
+ lib.STR2NR_OOCT,
lib.STR2NR_BIN + lib.STR2NR_OCT,
lib.STR2NR_BIN + lib.STR2NR_HEX,
lib.STR2NR_OCT + lib.STR2NR_HEX,
+ lib.STR2NR_OOCT + lib.STR2NR_HEX,
lib.STR2NR_ALL,
lib.STR2NR_FORCE + lib.STR2NR_DEC,
}) do
-- Check that all digits are recognized
test_vim_str2nr( '12345', flags, {len = 5, num = 12345, unum = 12345, pre = 0}, 0)
test_vim_str2nr( '67890', flags, {len = 5, num = 67890, unum = 67890, pre = 0}, 0)
- test_vim_str2nr( '12345A', flags, {len = 5, num = 12345, unum = 12345, pre = 0}, 0)
- test_vim_str2nr( '67890A', flags, {len = 5, num = 67890, unum = 67890, pre = 0}, 0)
+ test_vim_str2nr( '12345A', flags, {len = 0}, 0)
+ test_vim_str2nr( '67890A', flags, {len = 0}, 0)
+ test_vim_str2nr( '12345A', flags, {len = 5, num = 12345, unum = 12345, pre = 0}, 0, false)
+ test_vim_str2nr( '67890A', flags, {len = 5, num = 67890, unum = 67890, pre = 0}, 0, false)
test_vim_str2nr( '42', flags, {len = 2, num = 42, unum = 42, pre = 0}, 0)
test_vim_str2nr( '42', flags, {len = 1, num = 4, unum = 4, pre = 0}, 1)
test_vim_str2nr( '42', flags, {len = 2, num = 42, unum = 42, pre = 0}, 2)
test_vim_str2nr( '42', flags, {len = 2, num = 42, unum = 42, pre = 0}, 3) -- includes NUL byte in maxlen
- test_vim_str2nr( '42x', flags, {len = 2, num = 42, unum = 42, pre = 0}, 0)
- test_vim_str2nr( '42x', flags, {len = 2, num = 42, unum = 42, pre = 0}, 3)
+ test_vim_str2nr( '42x', flags, {len = 0}, 0)
+ test_vim_str2nr( '42x', flags, {len = 0}, 3)
+ test_vim_str2nr( '42x', flags, {len = 2, num = 42, unum = 42, pre = 0}, 0, false)
+ test_vim_str2nr( '42x', flags, {len = 2, num = 42, unum = 42, pre = 0}, 3, false)
test_vim_str2nr('-42', flags, {len = 3, num = -42, unum = 42, pre = 0}, 3)
test_vim_str2nr('-42', flags, {len = 1, num = 0, unum = 0, pre = 0}, 1)
- test_vim_str2nr('-42x', flags, {len = 3, num = -42, unum = 42, pre = 0}, 0)
- test_vim_str2nr('-42x', flags, {len = 3, num = -42, unum = 42, pre = 0}, 4)
+ test_vim_str2nr('-42x', flags, {len = 0}, 0)
+ test_vim_str2nr('-42x', flags, {len = 0}, 4)
+ test_vim_str2nr('-42x', flags, {len = 3, num = -42, unum = 42, pre = 0}, 0, false)
+ test_vim_str2nr('-42x', flags, {len = 3, num = -42, unum = 42, pre = 0}, 4, false)
end
end)
itp('works with binary numbers', function()
@@ -144,62 +156,77 @@ describe('vim_str2nr()', function()
test_vim_str2nr( '0b101', flags, {len = 5, num = 5, unum = 5, pre = bin}, 0)
test_vim_str2nr( '0b101', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 1)
- test_vim_str2nr( '0b101', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 2)
+ test_vim_str2nr( '0b101', flags, {len = 0}, 2)
+ test_vim_str2nr( '0b101', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 2, false)
test_vim_str2nr( '0b101', flags, {len = 3, num = 1, unum = 1, pre = bin}, 3)
test_vim_str2nr( '0b101', flags, {len = 4, num = 2, unum = 2, pre = bin}, 4)
test_vim_str2nr( '0b101', flags, {len = 5, num = 5, unum = 5, pre = bin}, 5)
test_vim_str2nr( '0b101', flags, {len = 5, num = 5, unum = 5, pre = bin}, 6)
- test_vim_str2nr( '0b1012', flags, {len = 5, num = 5, unum = 5, pre = bin}, 0)
- test_vim_str2nr( '0b1012', flags, {len = 5, num = 5, unum = 5, pre = bin}, 6)
+ test_vim_str2nr( '0b1012', flags, {len = 0}, 0)
+ test_vim_str2nr( '0b1012', flags, {len = 0}, 6)
+ test_vim_str2nr( '0b1012', flags, {len = 5, num = 5, unum = 5, pre = bin}, 0, false)
+ test_vim_str2nr( '0b1012', flags, {len = 5, num = 5, unum = 5, pre = bin}, 6, false)
test_vim_str2nr('-0b101', flags, {len = 6, num = -5, unum = 5, pre = bin}, 0)
test_vim_str2nr('-0b101', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr('-0b101', flags, {len = 2, num = 0, unum = 0, pre = 0 }, 2)
- test_vim_str2nr('-0b101', flags, {len = 2, num = 0, unum = 0, pre = 0 }, 3)
+ test_vim_str2nr('-0b101', flags, {len = 0}, 3)
+ test_vim_str2nr('-0b101', flags, {len = 2, num = 0, unum = 0, pre = 0 }, 3, false)
test_vim_str2nr('-0b101', flags, {len = 4, num = -1, unum = 1, pre = bin}, 4)
test_vim_str2nr('-0b101', flags, {len = 5, num = -2, unum = 2, pre = bin}, 5)
test_vim_str2nr('-0b101', flags, {len = 6, num = -5, unum = 5, pre = bin}, 6)
test_vim_str2nr('-0b101', flags, {len = 6, num = -5, unum = 5, pre = bin}, 7)
- test_vim_str2nr('-0b1012', flags, {len = 6, num = -5, unum = 5, pre = bin}, 0)
- test_vim_str2nr('-0b1012', flags, {len = 6, num = -5, unum = 5, pre = bin}, 7)
+ test_vim_str2nr('-0b1012', flags, {len = 0}, 0)
+ test_vim_str2nr('-0b1012', flags, {len = 0}, 7)
+ test_vim_str2nr('-0b1012', flags, {len = 6, num = -5, unum = 5, pre = bin}, 0, false)
+ test_vim_str2nr('-0b1012', flags, {len = 6, num = -5, unum = 5, pre = bin}, 7, false)
test_vim_str2nr( '0B101', flags, {len = 5, num = 5, unum = 5, pre = BIN}, 0)
test_vim_str2nr( '0B101', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 1)
- test_vim_str2nr( '0B101', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 2)
+ test_vim_str2nr( '0B101', flags, {len = 0}, 2)
+ test_vim_str2nr( '0B101', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 2, false)
test_vim_str2nr( '0B101', flags, {len = 3, num = 1, unum = 1, pre = BIN}, 3)
test_vim_str2nr( '0B101', flags, {len = 4, num = 2, unum = 2, pre = BIN}, 4)
test_vim_str2nr( '0B101', flags, {len = 5, num = 5, unum = 5, pre = BIN}, 5)
test_vim_str2nr( '0B101', flags, {len = 5, num = 5, unum = 5, pre = BIN}, 6)
- test_vim_str2nr( '0B1012', flags, {len = 5, num = 5, unum = 5, pre = BIN}, 0)
- test_vim_str2nr( '0B1012', flags, {len = 5, num = 5, unum = 5, pre = BIN}, 6)
+ test_vim_str2nr( '0B1012', flags, {len = 0}, 0)
+ test_vim_str2nr( '0B1012', flags, {len = 0}, 6)
+ test_vim_str2nr( '0B1012', flags, {len = 5, num = 5, unum = 5, pre = BIN}, 0, false)
+ test_vim_str2nr( '0B1012', flags, {len = 5, num = 5, unum = 5, pre = BIN}, 6, false)
test_vim_str2nr('-0B101', flags, {len = 6, num = -5, unum = 5, pre = BIN}, 0)
test_vim_str2nr('-0B101', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr('-0B101', flags, {len = 2, num = 0, unum = 0, pre = 0 }, 2)
- test_vim_str2nr('-0B101', flags, {len = 2, num = 0, unum = 0, pre = 0 }, 3)
+ test_vim_str2nr('-0B101', flags, {len = 0}, 3)
+ test_vim_str2nr('-0B101', flags, {len = 2, num = 0, unum = 0, pre = 0 }, 3, false)
test_vim_str2nr('-0B101', flags, {len = 4, num = -1, unum = 1, pre = BIN}, 4)
test_vim_str2nr('-0B101', flags, {len = 5, num = -2, unum = 2, pre = BIN}, 5)
test_vim_str2nr('-0B101', flags, {len = 6, num = -5, unum = 5, pre = BIN}, 6)
test_vim_str2nr('-0B101', flags, {len = 6, num = -5, unum = 5, pre = BIN}, 7)
- test_vim_str2nr('-0B1012', flags, {len = 6, num = -5, unum = 5, pre = BIN}, 0)
- test_vim_str2nr('-0B1012', flags, {len = 6, num = -5, unum = 5, pre = BIN}, 7)
+ test_vim_str2nr('-0B1012', flags, {len = 0}, 0)
+ test_vim_str2nr('-0B1012', flags, {len = 0}, 7)
+ test_vim_str2nr('-0B1012', flags, {len = 6, num = -5, unum = 5, pre = BIN}, 0, false)
+ test_vim_str2nr('-0B1012', flags, {len = 6, num = -5, unum = 5, pre = BIN}, 7, false)
if flags > lib.STR2NR_FORCE then
test_vim_str2nr('-101', flags, {len = 4, num = -5, unum = 5, pre = 0}, 0)
end
end
end)
- itp('works with octal numbers', function()
+ itp('works with octal numbers (0 prefix)', function()
for _, flags in ipairs({
lib.STR2NR_OCT,
lib.STR2NR_OCT + lib.STR2NR_BIN,
lib.STR2NR_OCT + lib.STR2NR_HEX,
+ lib.STR2NR_OCT + lib.STR2NR_OOCT,
lib.STR2NR_ALL,
lib.STR2NR_FORCE + lib.STR2NR_OCT,
+ lib.STR2NR_FORCE + lib.STR2NR_OOCT,
+ lib.STR2NR_FORCE + lib.STR2NR_OCT + lib.STR2NR_OOCT,
}) do
local oct
if flags > lib.STR2NR_FORCE then
@@ -218,8 +245,10 @@ describe('vim_str2nr()', function()
test_vim_str2nr( '0548', flags, {len = 3, num = 44, unum = 44, pre = oct}, 3)
test_vim_str2nr( '054', flags, {len = 3, num = 44, unum = 44, pre = oct}, 4)
- test_vim_str2nr( '054x', flags, {len = 3, num = 44, unum = 44, pre = oct}, 4)
- test_vim_str2nr( '054x', flags, {len = 3, num = 44, unum = 44, pre = oct}, 0)
+ test_vim_str2nr( '054x', flags, {len = 0}, 4)
+ test_vim_str2nr( '054x', flags, {len = 0}, 0)
+ test_vim_str2nr( '054x', flags, {len = 3, num = 44, unum = 44, pre = oct}, 4, false)
+ test_vim_str2nr( '054x', flags, {len = 3, num = 44, unum = 44, pre = oct}, 0, false)
test_vim_str2nr('-054', flags, {len = 4, num = -44, unum = 44, pre = oct}, 0)
test_vim_str2nr('-054', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 1)
@@ -229,13 +258,110 @@ describe('vim_str2nr()', function()
test_vim_str2nr('-0548', flags, {len = 4, num = -44, unum = 44, pre = oct}, 4)
test_vim_str2nr('-054', flags, {len = 4, num = -44, unum = 44, pre = oct}, 5)
- test_vim_str2nr('-054x', flags, {len = 4, num = -44, unum = 44, pre = oct}, 5)
- test_vim_str2nr('-054x', flags, {len = 4, num = -44, unum = 44, pre = oct}, 0)
+ test_vim_str2nr('-054x', flags, {len = 0}, 5)
+ test_vim_str2nr('-054x', flags, {len = 0}, 0)
+ test_vim_str2nr('-054x', flags, {len = 4, num = -44, unum = 44, pre = oct}, 5, false)
+ test_vim_str2nr('-054x', flags, {len = 4, num = -44, unum = 44, pre = oct}, 0, false)
if flags > lib.STR2NR_FORCE then
test_vim_str2nr('-54', flags, {len = 3, num = -44, unum = 44, pre = 0}, 0)
- test_vim_str2nr('-0548', flags, {len = 4, num = -44, unum = 44, pre = 0}, 5)
- test_vim_str2nr('-0548', flags, {len = 4, num = -44, unum = 44, pre = 0}, 0)
+ test_vim_str2nr('-0548', flags, {len = 0}, 5)
+ test_vim_str2nr('-0548', flags, {len = 0}, 0)
+ test_vim_str2nr('-0548', flags, {len = 4, num = -44, unum = 44, pre = 0}, 5, false)
+ test_vim_str2nr('-0548', flags, {len = 4, num = -44, unum = 44, pre = 0}, 0, false)
+ else
+ test_vim_str2nr('-0548', flags, {len = 5, num = -548, unum = 548, pre = 0}, 5)
+ test_vim_str2nr('-0548', flags, {len = 5, num = -548, unum = 548, pre = 0}, 0)
+ end
+ end
+ end)
+ itp('works with octal numbers (0o or 0O prefix)', function()
+ for _, flags in ipairs({
+ lib.STR2NR_OOCT,
+ lib.STR2NR_OOCT + lib.STR2NR_BIN,
+ lib.STR2NR_OOCT + lib.STR2NR_HEX,
+ lib.STR2NR_OCT + lib.STR2NR_OOCT,
+ lib.STR2NR_OCT + lib.STR2NR_OOCT + lib.STR2NR_BIN,
+ lib.STR2NR_OCT + lib.STR2NR_OOCT + lib.STR2NR_HEX,
+ lib.STR2NR_ALL,
+ lib.STR2NR_FORCE + lib.STR2NR_OCT,
+ lib.STR2NR_FORCE + lib.STR2NR_OOCT,
+ lib.STR2NR_FORCE + lib.STR2NR_OCT + lib.STR2NR_OOCT,
+ }) do
+ local oct
+ local OCT
+ if flags > lib.STR2NR_FORCE then
+ oct = 0
+ OCT = 0
+ else
+ oct = ('o'):byte()
+ OCT = ('O'):byte()
+ end
+
+ test_vim_str2nr( '0o054', flags, {len = 5, num = 44, unum = 44, pre = oct}, 0)
+ test_vim_str2nr( '0o054', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 1)
+ test_vim_str2nr( '0o054', flags, {len = 0}, 2)
+ test_vim_str2nr( '0o054', flags, {len = 3, num = 0, unum = 0, pre = oct}, 3)
+ test_vim_str2nr( '0o054', flags, {len = 4, num = 5, unum = 5, pre = oct}, 4)
+ test_vim_str2nr( '0o054', flags, {len = 5, num = 44, unum = 44, pre = oct}, 5)
+ test_vim_str2nr( '0o0548', flags, {len = 5, num = 44, unum = 44, pre = oct}, 5)
+ test_vim_str2nr( '0o054', flags, {len = 5, num = 44, unum = 44, pre = oct}, 6)
+
+ test_vim_str2nr( '0o054x', flags, {len = 0}, 6)
+ test_vim_str2nr( '0o054x', flags, {len = 0}, 0)
+ test_vim_str2nr( '0o054x', flags, {len = 5, num = 44, unum = 44, pre = oct}, 6, false)
+ test_vim_str2nr( '0o054x', flags, {len = 5, num = 44, unum = 44, pre = oct}, 0, false)
+
+ test_vim_str2nr('-0o054', flags, {len = 6, num = -44, unum = 44, pre = oct}, 0)
+ test_vim_str2nr('-0o054', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 1)
+ test_vim_str2nr('-0o054', flags, {len = 2, num = 0, unum = 0, pre = 0 }, 2)
+ test_vim_str2nr('-0o054', flags, {len = 0}, 3)
+ test_vim_str2nr('-0o054', flags, {len = 4, num = 0, unum = 0, pre = oct}, 4)
+ test_vim_str2nr('-0o054', flags, {len = 5, num = -5, unum = 5, pre = oct}, 5)
+ test_vim_str2nr('-0o054', flags, {len = 6, num = -44, unum = 44, pre = oct}, 6)
+ test_vim_str2nr('-0o0548', flags, {len = 6, num = -44, unum = 44, pre = oct}, 6)
+ test_vim_str2nr('-0o054', flags, {len = 6, num = -44, unum = 44, pre = oct}, 7)
+
+ test_vim_str2nr('-0o054x', flags, {len = 0}, 7)
+ test_vim_str2nr('-0o054x', flags, {len = 0}, 0)
+ test_vim_str2nr('-0o054x', flags, {len = 6, num = -44, unum = 44, pre = oct}, 7, false)
+ test_vim_str2nr('-0o054x', flags, {len = 6, num = -44, unum = 44, pre = oct}, 0, false)
+
+ test_vim_str2nr( '0O054', flags, {len = 5, num = 44, unum = 44, pre = OCT}, 0)
+ test_vim_str2nr( '0O054', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 1)
+ test_vim_str2nr( '0O054', flags, {len = 0}, 2)
+ test_vim_str2nr( '0O054', flags, {len = 3, num = 0, unum = 0, pre = OCT}, 3)
+ test_vim_str2nr( '0O054', flags, {len = 4, num = 5, unum = 5, pre = OCT}, 4)
+ test_vim_str2nr( '0O054', flags, {len = 5, num = 44, unum = 44, pre = OCT}, 5)
+ test_vim_str2nr( '0O0548', flags, {len = 5, num = 44, unum = 44, pre = OCT}, 5)
+ test_vim_str2nr( '0O054', flags, {len = 5, num = 44, unum = 44, pre = OCT}, 6)
+
+ test_vim_str2nr( '0O054x', flags, {len = 0}, 6)
+ test_vim_str2nr( '0O054x', flags, {len = 0}, 0)
+ test_vim_str2nr( '0O054x', flags, {len = 5, num = 44, unum = 44, pre = OCT}, 6, false)
+ test_vim_str2nr( '0O054x', flags, {len = 5, num = 44, unum = 44, pre = OCT}, 0, false)
+
+ test_vim_str2nr('-0O054', flags, {len = 6, num = -44, unum = 44, pre = OCT}, 0)
+ test_vim_str2nr('-0O054', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 1)
+ test_vim_str2nr('-0O054', flags, {len = 2, num = 0, unum = 0, pre = 0 }, 2)
+ test_vim_str2nr('-0O054', flags, {len = 0}, 3)
+ test_vim_str2nr('-0O054', flags, {len = 4, num = 0, unum = 0, pre = OCT}, 4)
+ test_vim_str2nr('-0O054', flags, {len = 5, num = -5, unum = 5, pre = OCT}, 5)
+ test_vim_str2nr('-0O054', flags, {len = 6, num = -44, unum = 44, pre = OCT}, 6)
+ test_vim_str2nr('-0O0548', flags, {len = 6, num = -44, unum = 44, pre = OCT}, 6)
+ test_vim_str2nr('-0O054', flags, {len = 6, num = -44, unum = 44, pre = OCT}, 7)
+
+ test_vim_str2nr('-0O054x', flags, {len = 0}, 7)
+ test_vim_str2nr('-0O054x', flags, {len = 0}, 0)
+ test_vim_str2nr('-0O054x', flags, {len = 6, num = -44, unum = 44, pre = OCT}, 7, false)
+ test_vim_str2nr('-0O054x', flags, {len = 6, num = -44, unum = 44, pre = OCT}, 0, false)
+
+ if flags > lib.STR2NR_FORCE then
+ test_vim_str2nr('-0548', flags, {len = 0}, 5)
+ test_vim_str2nr('-0548', flags, {len = 0}, 0)
+ test_vim_str2nr('-0548', flags, {len = 4, num = -44, unum = 44, pre = 0}, 5, false)
+ test_vim_str2nr('-0548', flags, {len = 4, num = -44, unum = 44, pre = 0}, 0, false)
+ test_vim_str2nr('-055', flags, {len = 4, num = -45, unum = 45, pre = 0}, 0)
else
test_vim_str2nr('-0548', flags, {len = 5, num = -548, unum = 548, pre = 0}, 5)
test_vim_str2nr('-0548', flags, {len = 5, num = -548, unum = 548, pre = 0}, 0)
@@ -268,53 +394,85 @@ describe('vim_str2nr()', function()
test_vim_str2nr( '0x101', flags, {len = 5, num = 257, unum =257, pre = hex}, 0)
test_vim_str2nr( '0x101', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 1)
- test_vim_str2nr( '0x101', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 2)
+ test_vim_str2nr( '0x101', flags, {len = 0}, 2)
+ test_vim_str2nr( '0x101', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 2, false)
test_vim_str2nr( '0x101', flags, {len = 3, num = 1, unum = 1, pre = hex}, 3)
test_vim_str2nr( '0x101', flags, {len = 4, num = 16, unum = 16, pre = hex}, 4)
test_vim_str2nr( '0x101', flags, {len = 5, num = 257, unum =257, pre = hex}, 5)
test_vim_str2nr( '0x101', flags, {len = 5, num = 257, unum =257, pre = hex}, 6)
- test_vim_str2nr( '0x101G', flags, {len = 5, num = 257, unum =257, pre = hex}, 0)
- test_vim_str2nr( '0x101G', flags, {len = 5, num = 257, unum =257, pre = hex}, 6)
+ test_vim_str2nr( '0x101G', flags, {len = 0}, 0)
+ test_vim_str2nr( '0x101G', flags, {len = 0}, 6)
+ test_vim_str2nr( '0x101G', flags, {len = 5, num = 257, unum =257, pre = hex}, 0, false)
+ test_vim_str2nr( '0x101G', flags, {len = 5, num = 257, unum =257, pre = hex}, 6, false)
test_vim_str2nr('-0x101', flags, {len = 6, num =-257, unum =257, pre = hex}, 0)
test_vim_str2nr('-0x101', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr('-0x101', flags, {len = 2, num = 0, unum = 0, pre = 0 }, 2)
- test_vim_str2nr('-0x101', flags, {len = 2, num = 0, unum = 0, pre = 0 }, 3)
+ test_vim_str2nr('-0x101', flags, {len = 0}, 3)
+ test_vim_str2nr('-0x101', flags, {len = 2, num = 0, unum = 0, pre = 0 }, 3, false)
test_vim_str2nr('-0x101', flags, {len = 4, num = -1, unum = 1, pre = hex}, 4)
test_vim_str2nr('-0x101', flags, {len = 5, num = -16, unum = 16, pre = hex}, 5)
test_vim_str2nr('-0x101', flags, {len = 6, num =-257, unum =257, pre = hex}, 6)
test_vim_str2nr('-0x101', flags, {len = 6, num =-257, unum =257, pre = hex}, 7)
- test_vim_str2nr('-0x101G', flags, {len = 6, num =-257, unum =257, pre = hex}, 0)
- test_vim_str2nr('-0x101G', flags, {len = 6, num =-257, unum =257, pre = hex}, 7)
+ test_vim_str2nr('-0x101G', flags, {len = 0}, 0)
+ test_vim_str2nr('-0x101G', flags, {len = 0}, 7)
+ test_vim_str2nr('-0x101G', flags, {len = 6, num =-257, unum =257, pre = hex}, 0, false)
+ test_vim_str2nr('-0x101G', flags, {len = 6, num =-257, unum =257, pre = hex}, 7, false)
test_vim_str2nr( '0X101', flags, {len = 5, num = 257, unum =257, pre = HEX}, 0)
test_vim_str2nr( '0X101', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 1)
- test_vim_str2nr( '0X101', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 2)
+ test_vim_str2nr( '0X101', flags, {len = 0}, 2)
+ test_vim_str2nr( '0X101', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 2, false)
test_vim_str2nr( '0X101', flags, {len = 3, num = 1, unum = 1, pre = HEX}, 3)
test_vim_str2nr( '0X101', flags, {len = 4, num = 16, unum = 16, pre = HEX}, 4)
test_vim_str2nr( '0X101', flags, {len = 5, num = 257, unum =257, pre = HEX}, 5)
test_vim_str2nr( '0X101', flags, {len = 5, num = 257, unum =257, pre = HEX}, 6)
- test_vim_str2nr( '0X101G', flags, {len = 5, num = 257, unum =257, pre = HEX}, 0)
- test_vim_str2nr( '0X101G', flags, {len = 5, num = 257, unum =257, pre = HEX}, 6)
+ test_vim_str2nr( '0X101G', flags, {len = 0}, 0)
+ test_vim_str2nr( '0X101G', flags, {len = 0}, 6)
+ test_vim_str2nr( '0X101G', flags, {len = 5, num = 257, unum =257, pre = HEX}, 0, false)
+ test_vim_str2nr( '0X101G', flags, {len = 5, num = 257, unum =257, pre = HEX}, 6, false)
test_vim_str2nr('-0X101', flags, {len = 6, num =-257, unum =257, pre = HEX}, 0)
test_vim_str2nr('-0X101', flags, {len = 1, num = 0, unum = 0, pre = 0 }, 1)
test_vim_str2nr('-0X101', flags, {len = 2, num = 0, unum = 0, pre = 0 }, 2)
- test_vim_str2nr('-0X101', flags, {len = 2, num = 0, unum = 0, pre = 0 }, 3)
+ test_vim_str2nr('-0X101', flags, {len = 0}, 3)
+ test_vim_str2nr('-0X101', flags, {len = 2, num = 0, unum = 0, pre = 0 }, 3, false)
test_vim_str2nr('-0X101', flags, {len = 4, num = -1, unum = 1, pre = HEX}, 4)
test_vim_str2nr('-0X101', flags, {len = 5, num = -16, unum = 16, pre = HEX}, 5)
test_vim_str2nr('-0X101', flags, {len = 6, num =-257, unum =257, pre = HEX}, 6)
test_vim_str2nr('-0X101', flags, {len = 6, num =-257, unum =257, pre = HEX}, 7)
- test_vim_str2nr('-0X101G', flags, {len = 6, num =-257, unum =257, pre = HEX}, 0)
- test_vim_str2nr('-0X101G', flags, {len = 6, num =-257, unum =257, pre = HEX}, 7)
+ test_vim_str2nr('-0X101G', flags, {len = 0}, 0)
+ test_vim_str2nr('-0X101G', flags, {len = 0}, 7)
+ test_vim_str2nr('-0X101G', flags, {len = 6, num =-257, unum =257, pre = HEX}, 0, false)
+ test_vim_str2nr('-0X101G', flags, {len = 6, num =-257, unum =257, pre = HEX}, 7, false)
if flags > lib.STR2NR_FORCE then
test_vim_str2nr('-101', flags, {len = 4, num = -257, unum = 257, pre = 0}, 0)
end
end
end)
+ -- Test_str2nr() in test_functions.vim already tests normal usage
+ itp('works with weirdly quoted numbers', function()
+ local flags = lib.STR2NR_DEC + lib.STR2NR_QUOTE
+ test_vim_str2nr("'027", flags, {len = 0}, 0)
+ test_vim_str2nr("'027", flags, {len = 0}, 0, false)
+ test_vim_str2nr("1'2'3'4", flags, {len = 7, num = 1234, unum = 1234, pre = 0}, 0)
+
+ -- counter-intuitive, but like Vim, strict=true should partially accept
+ -- these: (' and - are not alpha-numeric)
+ test_vim_str2nr("7''331", flags, {len = 1, num = 7, unum = 7, pre = 0}, 0)
+ test_vim_str2nr("123'x4", flags, {len = 3, num = 123, unum = 123, pre = 0}, 0)
+ test_vim_str2nr("1337'", flags, {len = 4, num = 1337, unum = 1337, pre = 0}, 0)
+ test_vim_str2nr("-'", flags, {len = 1, num = 0, unum = 0, pre = 0}, 0)
+
+ flags = lib.STR2NR_HEX + lib.STR2NR_QUOTE
+ local hex = ('x'):byte()
+ test_vim_str2nr("0x'abcd", flags, {len = 0}, 0)
+ test_vim_str2nr("0x'abcd", flags, {len = 1, num = 0, unum = 0, pre = 0}, 0, false)
+ test_vim_str2nr("0xab''cd", flags, {len = 4, num = 171, unum = 171, pre = hex}, 0)
+ end)
end)
diff --git a/test/unit/eval/typval_spec.lua b/test/unit/eval/typval_spec.lua
index d81e272877..e61b568f3a 100644
--- a/test/unit/eval/typval_spec.lua
+++ b/test/unit/eval/typval_spec.lua
@@ -2531,7 +2531,7 @@ describe('typval.c', function()
value='tr',
dict={},
})
- lib.tv_item_lock(p_tv, -1, true)
+ lib.tv_item_lock(p_tv, -1, true, false)
eq(lib.VAR_UNLOCKED, p_tv.vval.v_partial.pt_dict.dv_lock)
end)
itp('does not change VAR_FIXED values', function()
@@ -2542,14 +2542,14 @@ describe('typval.c', function()
d_tv.vval.v_dict.dv_lock = lib.VAR_FIXED
l_tv.v_lock = lib.VAR_FIXED
l_tv.vval.v_list.lv_lock = lib.VAR_FIXED
- lib.tv_item_lock(d_tv, 1, true)
- lib.tv_item_lock(l_tv, 1, true)
+ lib.tv_item_lock(d_tv, 1, true, false)
+ lib.tv_item_lock(l_tv, 1, true, false)
eq(lib.VAR_FIXED, d_tv.v_lock)
eq(lib.VAR_FIXED, l_tv.v_lock)
eq(lib.VAR_FIXED, d_tv.vval.v_dict.dv_lock)
eq(lib.VAR_FIXED, l_tv.vval.v_list.lv_lock)
- lib.tv_item_lock(d_tv, 1, false)
- lib.tv_item_lock(l_tv, 1, false)
+ lib.tv_item_lock(d_tv, 1, false, false)
+ lib.tv_item_lock(l_tv, 1, false, false)
eq(lib.VAR_FIXED, d_tv.v_lock)
eq(lib.VAR_FIXED, l_tv.v_lock)
eq(lib.VAR_FIXED, d_tv.vval.v_dict.dv_lock)
@@ -2561,9 +2561,9 @@ describe('typval.c', function()
local d_tv = lua2typvalt(null_dict)
local s_tv = lua2typvalt(null_string)
alloc_log:clear()
- lib.tv_item_lock(l_tv, 1, true)
- lib.tv_item_lock(d_tv, 1, true)
- lib.tv_item_lock(s_tv, 1, true)
+ lib.tv_item_lock(l_tv, 1, true, false)
+ lib.tv_item_lock(d_tv, 1, true, false)
+ lib.tv_item_lock(s_tv, 1, true, false)
eq(null_list, typvalt2lua(l_tv))
eq(null_dict, typvalt2lua(d_tv))
eq(null_string, typvalt2lua(s_tv))
diff --git a/test/unit/undo_spec.lua b/test/unit/undo_spec.lua
index 616c6fbe3d..f7f8d26d58 100644
--- a/test/unit/undo_spec.lua
+++ b/test/unit/undo_spec.lua
@@ -38,7 +38,7 @@ child_call_once(function()
--
-- compute a hash for this undofile
buffer_hash = ffi.new('char_u[32]')
- undo.u_compute_hash(buffer_hash)
+ undo.u_compute_hash(file_buffer, buffer_hash)
end)
diff --git a/test/unit/viml/expressions/parser_spec.lua b/test/unit/viml/expressions/parser_spec.lua
index 032baf6578..8342044b5e 100644
--- a/test/unit/viml/expressions/parser_spec.lua
+++ b/test/unit/viml/expressions/parser_spec.lua
@@ -52,6 +52,32 @@ local predefined_hl_defs = {
QuickFixLine=true,
Substitute=true,
Whitespace=true,
+ Error=true,
+ Todo=true,
+ String=true,
+ Character=true,
+ Number=true,
+ Boolean=true,
+ Float=true,
+ Function=true,
+ Conditional=true,
+ Repeat=true,
+ Label=true,
+ Operator=true,
+ Keyword=true,
+ Exception=true,
+ Include=true,
+ Define=true,
+ Macro=true,
+ PreCondit=true,
+ StorageClass=true,
+ Structure=true,
+ Typedef=true,
+ Tag=true,
+ SpecialChar=true,
+ Delimiter=true,
+ SpecialComment=true,
+ Debug=true,
-- From highlight_init_(dark|light)
ColorColumn=true,
@@ -83,8 +109,6 @@ local predefined_hl_defs = {
Visual=true,
WarningMsg=true,
Normal=true,
-
- -- From syncolor.vim, if &background
Comment=true,
Constant=true,
Special=true,
@@ -94,36 +118,6 @@ local predefined_hl_defs = {
Type=true,
Underlined=true,
Ignore=true,
-
- -- From syncolor.vim, below if &background
- Error=true,
- Todo=true,
-
- -- From syncolor.vim, links at the bottom
- String=true,
- Character=true,
- Number=true,
- Boolean=true,
- Float=true,
- Function=true,
- Conditional=true,
- Repeat=true,
- Label=true,
- Operator=true,
- Keyword=true,
- Exception=true,
- Include=true,
- Define=true,
- Macro=true,
- PreCondit=true,
- StorageClass=true,
- Structure=true,
- Typedef=true,
- Tag=true,
- SpecialChar=true,
- Delimiter=true,
- SpecialComment=true,
- Debug=true,
}
local nvim_hl_defs = {}
diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt
index e8999bf1ed..8dc9644ae5 100644
--- a/third-party/CMakeLists.txt
+++ b/third-party/CMakeLists.txt
@@ -149,8 +149,8 @@ if(WIN32)
set(LIBUV_URL https://github.com/neovim/libuv/archive/b899d12b0d56d217f31222da83f8c398355b69ef.tar.gz)
set(LIBUV_SHA256 eb7e37b824887e1b31a4e31d1d9bad4c03d8b98532d9cce5f67a3b70495a4b2a)
else()
- set(LIBUV_URL https://github.com/libuv/libuv/archive/v1.34.2.tar.gz)
- set(LIBUV_SHA256 0d9d38558b45c006c1ea4e8529bae64caf8becda570295ea74e3696362aeb7f2)
+ set(LIBUV_URL https://github.com/libuv/libuv/archive/v1.42.0.tar.gz)
+ set(LIBUV_SHA256 371e5419708f6aaeb8656671f89400b92a9bba6443369af1bb70bcd6e4b3c764)
endif()
set(MSGPACK_URL https://github.com/msgpack/msgpack-c/releases/download/cpp-3.0.0/msgpack-3.0.0.tar.gz)
@@ -163,8 +163,8 @@ set(LUAJIT_SHA256 2e3f74bc279f46cc463abfc67b36e69faaf0366237004771f4cac4bf2a9f5e
set(LUA_URL https://www.lua.org/ftp/lua-5.1.5.tar.gz)
set(LUA_SHA256 2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333)
-set(LUAROCKS_URL https://github.com/luarocks/luarocks/archive/v3.2.1.tar.gz)
-set(LUAROCKS_SHA256 0cab9f79311083f33e4d8f5a76021604f1d3f7141ce9a2ef1d8b717d92058370)
+set(LUAROCKS_URL https://github.com/luarocks/luarocks/archive/v3.7.0.tar.gz)
+set(LUAROCKS_SHA256 968c98ae894cea2c850f077133e3feb9f8ce94df7a33a5611bd4d25e07c94925)
set(UNIBILIUM_URL https://github.com/neovim/unibilium/archive/92d929f.tar.gz)
set(UNIBILIUM_SHA256 29815283c654277ef77a3adcc8840db79ddbb20a0f0b0c8f648bd8cd49a02e4b)
@@ -175,19 +175,19 @@ set(LIBTERMKEY_SHA256 6945bd3c4aaa83da83d80a045c5563da4edd7d0374c62c0d35aec09eb3
set(LIBVTERM_URL http://www.leonerd.org.uk/code/libvterm/libvterm-0.1.4.tar.gz)
set(LIBVTERM_SHA256 bc70349e95559c667672fc8c55b9527d9db9ada0fb80a3beda533418d782d3dd)
-set(LUV_VERSION 1.30.1-1)
+set(LUV_VERSION 1.42.0-0)
set(LUV_URL https://github.com/luvit/luv/archive/${LUV_VERSION}.tar.gz)
-set(LUV_SHA256 2b17921e2e18094df6221e3cd291c82d4569e50d8c081518d3e775dceae267cf)
+set(LUV_SHA256 8caee38de2fba0da32abbe96f55244e4a2c67d6cdde161a1935af94bffd5470f)
-set(LUA_COMPAT53_URL https://github.com/keplerproject/lua-compat-5.3/archive/v0.7.tar.gz)
-set(LUA_COMPAT53_SHA256 bec3a23114a3d9b3218038309657f0f506ad10dfbc03bb54e91da7e5ffdba0a2)
+set(LUA_COMPAT53_URL https://github.com/keplerproject/lua-compat-5.3/archive/v0.9.tar.gz)
+set(LUA_COMPAT53_SHA256 ad05540d2d96a48725bb79a1def35cf6652a4e2ec26376e2617c8ce2baa6f416)
set(GPERF_URL https://github.com/neovim/deps/raw/ff5b4b18a87397a8564016071ae64f64bcd8c635/opt/gperf-3.1.tar.gz)
set(GPERF_SHA256 588546b945bba4b70b6a3a616e80b4ab466e3f33024a352fc2198112cdbb3ae2)
# cat.exe curl.exe curl-ca-bundle.crt diff.exe tee.exe xxd.exe
-set(WINTOOLS_URL https://github.com/neovim/deps/raw/9efd42511dcab26995fa3490f2319b270949159e/opt/win32tools.zip)
-set(WINTOOLS_SHA256 378069d88a34e7f7283622213569020a2aba7a54f0b431fba28690f7eae3af9c)
+set(WINTOOLS_URL https://github.com/neovim/deps/raw/d66e306abf5b846484b4f2adffd896bce7e065d2/opt/win32tools.zip)
+set(WINTOOLS_SHA256 2fb2f8d69070b3f16e029913fb95008e6be33893d77fc358012396c275a0fdb7)
set(WINGUI_URL https://github.com/equalsraf/neovim-qt/releases/download/v0.2.16.1/neovim-qt.zip)
set(WINGUI_SHA256 ddb4492db03da407703fb0ab271c4eb060250d1a7d71200e2b3b981cb0de59de)
diff --git a/third-party/cmake/BuildLuarocks.cmake b/third-party/cmake/BuildLuarocks.cmake
index c5595bf840..0cef37736d 100644
--- a/third-party/cmake/BuildLuarocks.cmake
+++ b/third-party/cmake/BuildLuarocks.cmake
@@ -202,8 +202,13 @@ if(USE_BUNDLED_BUSTED)
set(LUV_ARGS "CFLAGS=-O0 -g3 -fPIC")
if(USE_BUNDLED_LIBUV)
list(APPEND LUV_ARGS LIBUV_DIR=${HOSTDEPS_INSTALL_DIR})
+ # workaround for bug introduced in
+ # https://github.com/luarocks/luarocks/commit/83126ba324846b754ffc5e0345341f01262b3f86
+ if(MSVC)
+ list(APPEND LUV_ARGS LIBUV_LIBDIR=${HOSTDEPS_INSTALL_DIR}/lib)
+ endif()
endif()
- SET(LUV_PRIVATE_ARGS LUA_COMPAT53_INCDIR=${DEPS_BUILD_DIR}/src/lua-compat-5.3)
+ SET(LUV_PRIVATE_ARGS LUA_COMPAT53_INCDIR=${DEPS_BUILD_DIR}/src/lua-compat-5.3/c-api)
add_custom_command(OUTPUT ${ROCKS_DIR}/luv
COMMAND ${LUAROCKS_BINARY}
ARGS make ${LUAROCKS_BUILDARGS} ${LUV_ARGS} ${LUV_PRIVATE_ARGS}
diff --git a/third-party/cmake/BuildLuv.cmake b/third-party/cmake/BuildLuv.cmake
index ac4196f910..f5d45c7ff7 100644
--- a/third-party/cmake/BuildLuv.cmake
+++ b/third-party/cmake/BuildLuv.cmake
@@ -71,6 +71,7 @@ set(LUV_CONFIGURE_COMMAND_COMMON
-DLUA_COMPAT53_DIR=${DEPS_BUILD_DIR}/src/lua-compat-5.3
-DWITH_SHARED_LIBUV=ON
-DBUILD_SHARED_LIBS=OFF
+ -DBUILD_STATIC_LIBS=ON
-DBUILD_MODULE=OFF)
if(USE_BUNDLED_LUAJIT)
diff --git a/third-party/cmake/DownloadAndExtractFile.cmake b/third-party/cmake/DownloadAndExtractFile.cmake
index e008fa8a8a..abb1ddc81a 100644
--- a/third-party/cmake/DownloadAndExtractFile.cmake
+++ b/third-party/cmake/DownloadAndExtractFile.cmake
@@ -59,41 +59,48 @@ string(REPLACE ";" "-" fname "${fname}")
set(file ${DOWNLOAD_DIR}/${fname})
message(STATUS "file: ${file}")
-message(STATUS "downloading...
- src='${URL}'
- dst='${file}'
- timeout='${timeout_msg}'")
-
-file(DOWNLOAD ${URL} ${file}
- ${timeout_args}
- ${hash_args}
- STATUS status
- LOG log)
-
-list(GET status 0 status_code)
-list(GET status 1 status_string)
-
-if(NOT status_code EQUAL 0)
- # Retry on certain errors, e.g. CURLE_COULDNT_RESOLVE_HOST, which is often
- # seen with libtermkey (www.leonerd.org.uk).
- if((status_code EQUAL 6) # "Couldn't resolve host name"
- OR (status_code EQUAL 7)) # "Couldn't connect to server"
- message(STATUS "warning: retrying '${URL}' (${status_string}, status ${status_code})")
- execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 10)
- file(DOWNLOAD ${URL} ${file}
- ${timeout_args}
- ${hash_args}
- STATUS status
- LOG log)
- list(GET status 0 status_code)
- list(GET status 1 status_string)
- endif()
+set(EXISTING_SHA256 "")
+if(EXISTS ${file})
+ file(SHA256 ${file} EXISTING_SHA256)
+endif()
+
+if(NOT EXISTING_SHA256 STREQUAL ${EXPECTED_SHA256})
+ message(STATUS "downloading...
+ src='${URL}'
+ dst='${file}'
+ timeout='${timeout_msg}'")
+
+ file(DOWNLOAD ${URL} ${file}
+ ${timeout_args}
+ ${hash_args}
+ STATUS status
+ LOG log)
+
+ list(GET status 0 status_code)
+ list(GET status 1 status_string)
+
if(NOT status_code EQUAL 0)
- message(FATAL_ERROR "error: downloading '${URL}' failed
- status_code: ${status_code}
- status_string: ${status_string}
- log: ${log}
-")
+ # Retry on certain errors, e.g. CURLE_COULDNT_RESOLVE_HOST, which is often
+ # seen with libtermkey (www.leonerd.org.uk).
+ if((status_code EQUAL 6) # "Couldn't resolve host name"
+ OR (status_code EQUAL 7)) # "Couldn't connect to server"
+ message(STATUS "warning: retrying '${URL}' (${status_string}, status ${status_code})")
+ execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 10)
+ file(DOWNLOAD ${URL} ${file}
+ ${timeout_args}
+ ${hash_args}
+ STATUS status
+ LOG log)
+ list(GET status 0 status_code)
+ list(GET status 1 status_string)
+ endif()
+ if(NOT status_code EQUAL 0)
+ message(FATAL_ERROR "error: downloading '${URL}' failed
+ status_code: ${status_code}
+ status_string: ${status_string}
+ log: ${log}
+ ")
+ endif()
endif()
endif()