aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.flake82
-rwxr-xr-x.gitattributes1
-rw-r--r--.github/FUNDING.yml1
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.md (renamed from ISSUE_TEMPLATE.md)10
-rw-r--r--.github/ISSUE_TEMPLATE/feature_request.md27
-rw-r--r--.gitignore8
-rw-r--r--.luacheckrc20
-rw-r--r--.travis.yml143
-rw-r--r--CMakeLists.txt105
-rw-r--r--CONTRIBUTING.md104
-rw-r--r--Makefile74
-rw-r--r--appveyor.yml23
-rw-r--r--busted/outputHandlers/TAP.lua94
-rwxr-xr-xci/before_cache.sh17
-rwxr-xr-xci/before_install.sh64
-rwxr-xr-xci/before_script.sh6
-rw-r--r--ci/build.ps133
-rw-r--r--ci/common/build.sh4
-rwxr-xr-xci/common/submit_coverage.sh45
-rw-r--r--ci/common/suite.sh3
-rw-r--r--ci/common/test.sh15
-rwxr-xr-xci/install.sh16
-rwxr-xr-xci/run_lint.sh14
-rwxr-xr-xci/script.sh6
-rw-r--r--cmake/FindLibIntl.cmake13
-rw-r--r--cmake/FindLibLUV.cmake31
-rw-r--r--cmake/FindLibTermkey.cmake26
-rw-r--r--cmake/FindLibUV.cmake31
-rw-r--r--cmake/FindLibVterm.cmake43
-rw-r--r--cmake/FindLuaJit.cmake27
-rw-r--r--cmake/FindMsgpack.cmake31
-rw-r--r--cmake/FindUnibilium.cmake45
-rw-r--r--cmake/GetCompileFlags.cmake29
-rw-r--r--cmake/LibFindMacros.cmake363
-rw-r--r--cmake/RunLuacheck.cmake22
-rw-r--r--cmake/RunTests.cmake59
-rw-r--r--cmake/mingw32-w64-cross-travis.toolchain.cmake53
-rw-r--r--codecov.yml8
-rw-r--r--config/CMakeLists.txt4
-rw-r--r--config/config.h.in4
-rw-r--r--contrib/gdb/nvim-gdb-pretty-printers.py4
-rw-r--r--contrib/local.mk.example15
-rw-r--r--runtime/autoload/RstFold.vim16
-rw-r--r--runtime/autoload/dist/ft.vim4
-rw-r--r--runtime/autoload/health/nvim.vim10
-rw-r--r--runtime/autoload/health/provider.vim8
-rw-r--r--runtime/autoload/netrw.vim1982
-rw-r--r--runtime/autoload/netrwSettings.vim10
-rw-r--r--runtime/autoload/paste.vim46
-rw-r--r--runtime/autoload/provider/clipboard.vim20
-rw-r--r--runtime/autoload/provider/node.vim3
-rw-r--r--runtime/autoload/provider/python.vim8
-rw-r--r--runtime/autoload/provider/python3.vim8
-rw-r--r--runtime/autoload/provider/ruby.vim3
-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.vim57
-rw-r--r--runtime/autoload/tohtml.vim122
-rw-r--r--runtime/autoload/xmlformat.vim16
-rw-r--r--runtime/bugreport.vim2
-rw-r--r--runtime/compiler/cs.vim10
-rw-r--r--runtime/compiler/erlang.vim4
-rw-r--r--runtime/compiler/eruby.vim5
-rw-r--r--runtime/compiler/fortran_cv.vim2
-rw-r--r--runtime/compiler/gcc.vim10
-rw-r--r--runtime/compiler/jikes.vim4
-rw-r--r--runtime/compiler/ocaml.vim18
-rw-r--r--runtime/compiler/onsgmls.vim4
-rw-r--r--runtime/compiler/perl.vim4
-rw-r--r--runtime/compiler/rake.vim13
-rw-r--r--runtime/compiler/rspec.vim4
-rw-r--r--runtime/compiler/ruby.vim10
-rw-r--r--runtime/compiler/rubyunit.vim1
-rw-r--r--runtime/compiler/rustc.vim2
-rw-r--r--runtime/compiler/splint.vim4
-rw-r--r--runtime/compiler/xmlwf.vim4
-rw-r--r--runtime/doc/api.txt31
-rw-r--r--runtime/doc/autocmd.txt116
-rw-r--r--runtime/doc/change.txt21
-rw-r--r--runtime/doc/cmdline.txt5
-rw-r--r--runtime/doc/deprecated.txt9
-rw-r--r--runtime/doc/develop.txt46
-rw-r--r--runtime/doc/diff.txt4
-rw-r--r--runtime/doc/digraph.txt17
-rw-r--r--runtime/doc/editing.txt2
-rw-r--r--runtime/doc/eval.txt517
-rw-r--r--runtime/doc/filetype.txt19
-rw-r--r--runtime/doc/fold.txt2
-rw-r--r--runtime/doc/help.txt29
-rw-r--r--runtime/doc/if_lua.txt160
-rw-r--r--runtime/doc/if_pyth.txt19
-rw-r--r--runtime/doc/if_ruby.txt14
-rw-r--r--runtime/doc/indent.txt71
-rw-r--r--runtime/doc/index.txt46
-rw-r--r--runtime/doc/job_control.txt2
-rw-r--r--runtime/doc/map.txt39
-rw-r--r--runtime/doc/mbyte.txt75
-rw-r--r--runtime/doc/message.txt17
-rw-r--r--runtime/doc/mlang.txt6
-rw-r--r--runtime/doc/motion.txt13
-rw-r--r--runtime/doc/nvim_terminal_emulator.txt25
-rw-r--r--runtime/doc/options.txt223
-rw-r--r--runtime/doc/pattern.txt15
-rw-r--r--runtime/doc/pi_netrw.txt447
-rw-r--r--runtime/doc/print.txt15
-rw-r--r--runtime/doc/provider.txt20
-rw-r--r--runtime/doc/quickfix.txt45
-rw-r--r--runtime/doc/quickref.txt5
-rw-r--r--runtime/doc/repeat.txt21
-rw-r--r--runtime/doc/russian.txt3
-rw-r--r--runtime/doc/scroll.txt3
-rw-r--r--runtime/doc/sign.txt9
-rw-r--r--runtime/doc/spell.txt27
-rw-r--r--runtime/doc/starting.txt15
-rw-r--r--runtime/doc/syntax.txt110
-rw-r--r--runtime/doc/tabpage.txt2
-rw-r--r--runtime/doc/tagsrch.txt39
-rw-r--r--runtime/doc/ui.txt9
-rw-r--r--runtime/doc/usr_05.txt59
-rw-r--r--runtime/doc/usr_06.txt3
-rw-r--r--runtime/doc/usr_11.txt2
-rw-r--r--runtime/doc/usr_27.txt12
-rw-r--r--runtime/doc/usr_41.txt53
-rw-r--r--runtime/doc/usr_45.txt6
-rw-r--r--runtime/doc/usr_toc.txt13
-rw-r--r--runtime/doc/various.txt47
-rw-r--r--runtime/doc/vi_diff.txt6
-rw-r--r--runtime/doc/vim_diff.txt36
-rw-r--r--runtime/doc/visual.txt4
-rw-r--r--runtime/doc/windows.txt35
-rw-r--r--runtime/filetype.vim49
-rw-r--r--runtime/ftplugin/8th.vim25
-rw-r--r--runtime/ftplugin/bash.vim31
-rw-r--r--runtime/ftplugin/cfg.vim19
-rw-r--r--runtime/ftplugin/cobol.vim5
-rw-r--r--runtime/ftplugin/dosbatch.vim3
-rw-r--r--runtime/ftplugin/dune.vim20
-rw-r--r--runtime/ftplugin/eruby.vim34
-rw-r--r--runtime/ftplugin/help.vim2
-rw-r--r--runtime/ftplugin/logcheck.vim10
-rw-r--r--runtime/ftplugin/make.vim6
-rw-r--r--runtime/ftplugin/mma.vim16
-rw-r--r--runtime/ftplugin/nroff.vim11
-rw-r--r--runtime/ftplugin/ocaml.vim52
-rw-r--r--runtime/ftplugin/python.vim133
-rw-r--r--runtime/ftplugin/qf.vim10
-rw-r--r--runtime/ftplugin/rst.vim9
-rw-r--r--runtime/ftplugin/ruby.vim100
-rw-r--r--runtime/ftplugin/sql.vim6
-rw-r--r--runtime/ftplugin/text.vim7
-rw-r--r--runtime/ftplugin/xml.vim8
-rw-r--r--runtime/indent/awk.vim2
-rw-r--r--runtime/indent/cobol.vim11
-rw-r--r--runtime/indent/cs.vim74
-rw-r--r--runtime/indent/eruby.vim10
-rw-r--r--runtime/indent/falcon.vim2
-rw-r--r--runtime/indent/html.vim30
-rw-r--r--runtime/indent/matlab.vim187
-rw-r--r--runtime/indent/mma.vim2
-rw-r--r--runtime/indent/php.vim128
-rw-r--r--runtime/indent/python.vim104
-rw-r--r--runtime/indent/raml.vim12
-rw-r--r--runtime/indent/rmd.vim2
-rw-r--r--runtime/indent/ruby.vim886
-rw-r--r--runtime/indent/sh.vim59
-rw-r--r--runtime/indent/tcl.vim50
-rw-r--r--runtime/indent/testdir/html.in26
-rw-r--r--runtime/indent/testdir/html.ok26
-rw-r--r--runtime/indent/testdir/matlab.in80
-rw-r--r--runtime/indent/testdir/matlab.ok80
-rw-r--r--runtime/indent/testdir/tcl.in19
-rw-r--r--runtime/indent/testdir/tcl.ok19
-rw-r--r--runtime/indent/testdir/xml.in32
-rw-r--r--runtime/indent/testdir/xml.ok32
-rw-r--r--runtime/indent/typescript.vim503
-rw-r--r--runtime/indent/xml.vim165
-rw-r--r--runtime/lua/man.lua4
-rw-r--r--runtime/makemenu.vim36
-rw-r--r--runtime/menu.vim22
-rw-r--r--runtime/mswin.vim4
-rw-r--r--runtime/optwin.vim78
-rw-r--r--runtime/pack/dist/opt/matchit/autoload/matchit.vim754
-rw-r--r--runtime/pack/dist/opt/matchit/doc/matchit.txt (renamed from runtime/doc/pi_matchit.txt)97
-rw-r--r--runtime/pack/dist/opt/matchit/plugin/matchit.vim92
-rw-r--r--runtime/pack/dist/opt/termdebug/plugin/termdebug.vim10
-rw-r--r--runtime/plugin/matchit.vim819
-rw-r--r--runtime/plugin/netrwPlugin.vim14
-rw-r--r--runtime/plugin/tohtml.vim137
-rw-r--r--runtime/scripts.vim15
-rw-r--r--runtime/synmenu.vim809
-rw-r--r--runtime/syntax/2html.vim93
-rw-r--r--runtime/syntax/8th.vim335
-rw-r--r--runtime/syntax/abap.vim13
-rw-r--r--runtime/syntax/apache.vim4
-rw-r--r--runtime/syntax/automake.vim18
-rw-r--r--runtime/syntax/c.vim20
-rw-r--r--runtime/syntax/cobol.vim164
-rw-r--r--runtime/syntax/cs.vim39
-rw-r--r--runtime/syntax/dcl.vim10
-rw-r--r--runtime/syntax/debchangelog.vim6
-rw-r--r--runtime/syntax/debsources.vim7
-rw-r--r--runtime/syntax/dune.vim46
-rw-r--r--runtime/syntax/eruby.vim19
-rw-r--r--runtime/syntax/fstab.vim6
-rw-r--r--runtime/syntax/help.vim4
-rw-r--r--runtime/syntax/hitest.vim21
-rw-r--r--runtime/syntax/html.vim82
-rw-r--r--runtime/syntax/json.vim24
-rw-r--r--runtime/syntax/lisp.vim14
-rw-r--r--runtime/syntax/make.vim27
-rw-r--r--runtime/syntax/maple.vim10
-rw-r--r--runtime/syntax/matlab.vim7
-rw-r--r--runtime/syntax/netrw.vim80
-rw-r--r--runtime/syntax/ocaml.vim140
-rw-r--r--runtime/syntax/php.vim2
-rw-r--r--runtime/syntax/raml.vim106
-rw-r--r--runtime/syntax/rmd.vim10
-rw-r--r--runtime/syntax/rst.vim3
-rw-r--r--runtime/syntax/ruby.vim71
-rw-r--r--runtime/syntax/sh.vim84
-rw-r--r--runtime/syntax/spec.vim6
-rw-r--r--runtime/syntax/sshdconfig.vim24
-rw-r--r--runtime/syntax/tasm.vim4
-rw-r--r--runtime/syntax/template.vim15
-rw-r--r--runtime/syntax/tex.vim27
-rw-r--r--runtime/syntax/tmux.vim83
-rw-r--r--runtime/syntax/tpp.vim22
-rw-r--r--runtime/syntax/typescript.vim2077
-rw-r--r--runtime/syntax/upstreamrpt.vim2
-rw-r--r--runtime/syntax/valgrind.vim7
-rw-r--r--runtime/syntax/vim.vim34
-rw-r--r--runtime/syntax/vuejs.vim14
-rw-r--r--runtime/syntax/yacc.vim17
-rw-r--r--runtime/tools/check_colors.vim127
-rwxr-xr-xscripts/check-includes.py84
-rw-r--r--scripts/gen_help_html.py158
-rwxr-xr-xscripts/gen_vimdoc.py141
-rwxr-xr-xscripts/pvscheck.sh1
-rwxr-xr-xscripts/shadacat.py110
-rwxr-xr-xscripts/stripdecls.py235
-rwxr-xr-xscripts/vim-patch.sh84
-rwxr-xr-xsrc/clint.py44
-rw-r--r--src/nvim/CMakeLists.txt7
-rw-r--r--src/nvim/README.md4
-rw-r--r--src/nvim/api/buffer.c56
-rw-r--r--src/nvim/api/private/dispatch.h6
-rw-r--r--src/nvim/api/ui.c1
-rw-r--r--src/nvim/api/ui_events.in.h2
-rw-r--r--src/nvim/api/vim.c120
-rw-r--r--src/nvim/api/window.c23
-rw-r--r--src/nvim/assert.h7
-rw-r--r--src/nvim/auevents.lua1
-rw-r--r--src/nvim/buffer.c57
-rw-r--r--src/nvim/buffer_defs.h37
-rw-r--r--src/nvim/buffer_updates.c41
-rw-r--r--src/nvim/change.c1798
-rw-r--r--src/nvim/change.h11
-rw-r--r--src/nvim/channel.c231
-rw-r--r--src/nvim/channel.h11
-rw-r--r--src/nvim/context.c383
-rw-r--r--src/nvim/context.h46
-rw-r--r--src/nvim/cursor.c1
-rw-r--r--src/nvim/diff.c11
-rw-r--r--src/nvim/digraph.c9
-rw-r--r--src/nvim/edit.c242
-rw-r--r--src/nvim/eval.c1167
-rw-r--r--src/nvim/eval.h7
-rw-r--r--src/nvim/eval.lua15
-rw-r--r--src/nvim/eval/executor.c4
-rw-r--r--src/nvim/eval/typval.c12
-rw-r--r--src/nvim/eval/typval.h1
-rw-r--r--src/nvim/eval/typval_encode.c.h2
-rw-r--r--src/nvim/event/libuv_process.c6
-rw-r--r--src/nvim/event/process.c20
-rw-r--r--src/nvim/event/process.h4
-rw-r--r--src/nvim/event/stream.c5
-rw-r--r--src/nvim/ex_cmds.c90
-rw-r--r--src/nvim/ex_cmds.lua32
-rw-r--r--src/nvim/ex_cmds2.c41
-rw-r--r--src/nvim/ex_cmds_defs.h2
-rw-r--r--src/nvim/ex_docmd.c143
-rw-r--r--src/nvim/ex_getln.c654
-rw-r--r--src/nvim/fileio.c384
-rw-r--r--src/nvim/fold.c1
-rw-r--r--src/nvim/func_attr.h4
-rw-r--r--src/nvim/garray.c8
-rw-r--r--src/nvim/generators/c_grammar.lua6
-rw-r--r--src/nvim/generators/gen_api_dispatch.lua99
-rw-r--r--src/nvim/generators/gen_api_ui_events.lua39
-rw-r--r--src/nvim/generators/gen_char_blob.lua11
-rwxr-xr-xsrc/nvim/generators/gen_declarations.lua11
-rw-r--r--src/nvim/generators/gen_eval.lua16
-rw-r--r--src/nvim/generators/gen_events.lua8
-rw-r--r--src/nvim/generators/gen_ex_cmds.lua9
-rw-r--r--src/nvim/generators/gen_options.lua7
-rw-r--r--src/nvim/generators/gen_unicode_tables.lua24
-rw-r--r--src/nvim/getchar.c329
-rw-r--r--src/nvim/globals.h66
-rw-r--r--src/nvim/grid_defs.h7
-rw-r--r--src/nvim/hardcopy.c14
-rw-r--r--src/nvim/highlight.c110
-rw-r--r--src/nvim/highlight_defs.h3
-rw-r--r--src/nvim/iconv.h46
-rw-r--r--src/nvim/if_cscope.c8
-rw-r--r--src/nvim/indent.c104
-rw-r--r--src/nvim/lua/converter.c41
-rw-r--r--src/nvim/lua/executor.c250
-rw-r--r--src/nvim/lua/vim.lua11
-rw-r--r--src/nvim/macros.h11
-rw-r--r--src/nvim/main.c54
-rw-r--r--src/nvim/map.c2
-rw-r--r--src/nvim/mark.c77
-rw-r--r--src/nvim/mbyte.c280
-rw-r--r--src/nvim/mbyte.h2
-rw-r--r--src/nvim/memline.c64
-rw-r--r--src/nvim/memory.c4
-rw-r--r--src/nvim/message.c26
-rw-r--r--src/nvim/misc1.c1755
-rw-r--r--src/nvim/move.c36
-rw-r--r--src/nvim/msgpack_rpc/channel.c2
-rw-r--r--src/nvim/msgpack_rpc/helpers.c5
-rw-r--r--src/nvim/normal.c77
-rw-r--r--src/nvim/ops.c214
-rw-r--r--src/nvim/option.c80
-rw-r--r--src/nvim/option_defs.h58
-rw-r--r--src/nvim/options.lua50
-rw-r--r--src/nvim/os/dl.c1
-rw-r--r--src/nvim/os/env.c52
-rw-r--r--src/nvim/os/fs.c145
-rw-r--r--src/nvim/os/input.c11
-rw-r--r--src/nvim/os/process.c19
-rw-r--r--src/nvim/os/pty_process_unix.c2
-rw-r--r--src/nvim/os/pty_process_win.c2
-rw-r--r--src/nvim/os/time.c25
-rw-r--r--src/nvim/os_unix.c7
-rw-r--r--src/nvim/path.c12
-rw-r--r--src/nvim/popupmnu.c9
-rw-r--r--src/nvim/profile.c95
-rw-r--r--src/nvim/quickfix.c90
-rw-r--r--src/nvim/regexp.c29
-rw-r--r--src/nvim/regexp_nfa.c184
-rw-r--r--src/nvim/screen.c274
-rw-r--r--src/nvim/search.c59
-rw-r--r--src/nvim/shada.c316
-rw-r--r--src/nvim/shada.h11
-rw-r--r--src/nvim/sign.c96
-rw-r--r--src/nvim/spell.c17
-rw-r--r--src/nvim/spellfile.c25
-rw-r--r--src/nvim/state.c2
-rw-r--r--src/nvim/syntax.c157
-rw-r--r--src/nvim/tag.c43
-rw-r--r--src/nvim/terminal.c3
-rw-r--r--src/nvim/testdir/Makefile35
-rw-r--r--src/nvim/testdir/runnvim.vim5
-rw-r--r--src/nvim/testdir/runtest.vim36
-rw-r--r--src/nvim/testdir/samples/memfile_test.c2
-rw-r--r--src/nvim/testdir/setup.vim17
-rw-r--r--src/nvim/testdir/shared.vim33
-rw-r--r--src/nvim/testdir/test49.vim3
-rw-r--r--src/nvim/testdir/test_arabic.vim48
-rw-r--r--src/nvim/testdir/test_arglist.vim69
-rw-r--r--src/nvim/testdir/test_assert.vim13
-rw-r--r--src/nvim/testdir/test_autocmd.vim22
-rw-r--r--src/nvim/testdir/test_bufline.vim67
-rw-r--r--src/nvim/testdir/test_cmdline.vim49
-rw-r--r--src/nvim/testdir/test_compiler.vim6
-rw-r--r--src/nvim/testdir/test_const.vim237
-rw-r--r--src/nvim/testdir/test_cscope.vim58
-rw-r--r--src/nvim/testdir/test_cursor_func.vim20
-rw-r--r--src/nvim/testdir/test_debugger.vim16
-rw-r--r--src/nvim/testdir/test_diffmode.vim3
-rw-r--r--src/nvim/testdir/test_edit.vim7
-rw-r--r--src/nvim/testdir/test_environ.vim44
-rw-r--r--src/nvim/testdir/test_excmd.vim10
-rw-r--r--src/nvim/testdir/test_filetype.vim29
-rw-r--r--src/nvim/testdir/test_filter_cmd.vim58
-rw-r--r--src/nvim/testdir/test_filter_map.vim5
-rw-r--r--src/nvim/testdir/test_functions.vim98
-rw-r--r--src/nvim/testdir/test_getvar.vim44
-rw-r--r--src/nvim/testdir/test_ins_complete.vim36
-rw-r--r--src/nvim/testdir/test_lambda.vim38
-rw-r--r--src/nvim/testdir/test_makeencoding.py4
-rw-r--r--src/nvim/testdir/test_maparg.vim4
-rw-r--r--src/nvim/testdir/test_mapping.vim25
-rw-r--r--src/nvim/testdir/test_mksession.vim11
-rw-r--r--src/nvim/testdir/test_modeline.vim95
-rw-r--r--src/nvim/testdir/test_normal.vim15
-rw-r--r--src/nvim/testdir/test_options.vim117
-rw-r--r--src/nvim/testdir/test_partial.vim5
-rw-r--r--src/nvim/testdir/test_popup.vim36
-rw-r--r--src/nvim/testdir/test_profile.vim100
-rw-r--r--src/nvim/testdir/test_quickfix.vim46
-rw-r--r--src/nvim/testdir/test_recover.vim7
-rw-r--r--src/nvim/testdir/test_regexp_latin.vim13
-rw-r--r--src/nvim/testdir/test_regexp_utf8.vim9
-rw-r--r--src/nvim/testdir/test_registers.vim19
-rw-r--r--src/nvim/testdir/test_search.vim43
-rw-r--r--src/nvim/testdir/test_source.vim48
-rw-r--r--src/nvim/testdir/test_spell.vim54
-rw-r--r--src/nvim/testdir/test_startup.vim82
-rw-r--r--src/nvim/testdir/test_statusline.vim3
-rw-r--r--src/nvim/testdir/test_suspend.vim29
-rw-r--r--src/nvim/testdir/test_syntax.vim2
-rw-r--r--src/nvim/testdir/test_tabline.vim39
-rw-r--r--src/nvim/testdir/test_tagcase.vim1
-rw-r--r--src/nvim/testdir/test_tagjump.vim5
-rw-r--r--src/nvim/testdir/test_taglist.vim49
-rw-r--r--src/nvim/testdir/test_usercommands.vim95
-rw-r--r--src/nvim/testdir/test_vimscript.vim42
-rw-r--r--src/nvim/testdir/test_virtualedit.vim16
-rw-r--r--src/nvim/testdir/test_window_cmd.vim37
-rw-r--r--src/nvim/testdir/test_windows_home.vim2
-rw-r--r--src/nvim/testdir/test_writefile.vim2
-rw-r--r--src/nvim/tui/input.c126
-rw-r--r--src/nvim/tui/tui.c18
-rw-r--r--src/nvim/ugrid.c4
-rw-r--r--src/nvim/ui.c20
-rw-r--r--src/nvim/ui_compositor.c102
-rw-r--r--src/nvim/undo.c16
-rw-r--r--src/nvim/version.c215
-rw-r--r--src/nvim/viml/parser/expressions.c2
-rw-r--r--src/nvim/window.c371
-rw-r--r--test/.luacheckrc20
-rw-r--r--test/README.md141
-rw-r--r--test/busted/outputHandlers/TAP.lua14
-rw-r--r--test/busted/outputHandlers/nvim.lua (renamed from busted/outputHandlers/nvim.lua)19
-rw-r--r--test/functional/api/keymap_spec.lua5
-rw-r--r--test/functional/api/proc_spec.lua12
-rw-r--r--test/functional/api/server_requests_spec.lua4
-rw-r--r--test/functional/api/vim_spec.lua69
-rw-r--r--test/functional/api/window_spec.lua16
-rw-r--r--test/functional/autocmd/autocmd_spec.lua22
-rw-r--r--test/functional/autocmd/cursorhold_spec.lua31
-rw-r--r--test/functional/autocmd/termclose_spec.lua7
-rw-r--r--test/functional/autocmd/textyankpost_spec.lua5
-rw-r--r--test/functional/core/fileio_spec.lua16
-rw-r--r--test/functional/core/job_spec.lua96
-rw-r--r--test/functional/core/startup_spec.lua9
-rw-r--r--test/functional/eval/api_functions_spec.lua9
-rw-r--r--test/functional/eval/ctx_functions_spec.lua408
-rw-r--r--test/functional/eval/environ_spec.lua18
-rw-r--r--test/functional/eval/executable_spec.lua18
-rw-r--r--test/functional/eval/reltime_spec.lua19
-rw-r--r--test/functional/eval/system_spec.lua11
-rw-r--r--test/functional/eval/timer_spec.lua11
-rw-r--r--test/functional/ex_cmds/arg_spec.lua2
-rw-r--r--test/functional/ex_cmds/ctrl_c_spec.lua2
-rw-r--r--test/functional/ex_cmds/digraphs_spec.lua20
-rw-r--r--test/functional/ex_cmds/ls_spec.lua37
-rw-r--r--test/functional/ex_cmds/menu_spec.lua2
-rw-r--r--test/functional/fixtures/autoload/provider/clipboard.vim3
-rw-r--r--test/functional/fixtures/autoload/provider/python.vim6
-rw-r--r--test/functional/fixtures/autoload/provider/ruby.vim2
-rw-r--r--test/functional/fixtures/cmdscript.cmd2
-rw-r--r--test/functional/fixtures/compdir/file10
-rw-r--r--test/functional/fixtures/compdir/file20
-rw-r--r--test/functional/fixtures/shell-test.c89
-rw-r--r--test/functional/helpers.lua378
-rw-r--r--test/functional/legacy/arglist_spec.lua68
-rw-r--r--test/functional/lua/buffer_updates_spec.lua206
-rw-r--r--test/functional/lua/loop_spec.lua156
-rw-r--r--test/functional/lua/overrides_spec.lua105
-rw-r--r--test/functional/lua/utility_functions_spec.lua55
-rw-r--r--test/functional/normal/put_spec.lua2
-rw-r--r--test/functional/normal/search_spec.lua16
-rw-r--r--test/functional/options/num_options_spec.lua2
-rw-r--r--test/functional/plugin/health_spec.lua3
-rw-r--r--test/functional/plugin/helpers.lua41
-rw-r--r--test/functional/plugin/man_spec.lua33
-rw-r--r--test/functional/plugin/matchparen_spec.lua6
-rw-r--r--test/functional/plugin/msgpack_spec.lua8
-rw-r--r--test/functional/plugin/shada_spec.lua12
-rw-r--r--test/functional/provider/provider_spec.lua26
-rw-r--r--test/functional/shada/buffers_spec.lua42
-rw-r--r--test/functional/shada/helpers.lua59
-rw-r--r--test/functional/shada/marks_spec.lua34
-rw-r--r--test/functional/shada/registers_spec.lua11
-rw-r--r--test/functional/shada/shada_spec.lua4
-rw-r--r--test/functional/shada/variables_spec.lua19
-rw-r--r--test/functional/terminal/edit_spec.lua7
-rw-r--r--test/functional/terminal/ex_terminal_spec.lua12
-rw-r--r--test/functional/terminal/tui_spec.lua161
-rw-r--r--test/functional/ui/cmdline_highlight_spec.lua2
-rw-r--r--test/functional/ui/cmdline_spec.lua41
-rw-r--r--test/functional/ui/cursor_spec.lua4
-rw-r--r--test/functional/ui/float_spec.lua1004
-rw-r--r--test/functional/ui/fold_spec.lua16
-rw-r--r--test/functional/ui/highlight_spec.lua32
-rw-r--r--test/functional/ui/messages_spec.lua141
-rw-r--r--test/functional/ui/mouse_spec.lua7
-rw-r--r--test/functional/ui/output_spec.lua15
-rw-r--r--test/functional/ui/popupmenu_spec.lua112
-rw-r--r--test/functional/ui/screen.lua110
-rw-r--r--test/functional/ui/searchhl_spec.lua29
-rw-r--r--test/functional/ui/sign_spec.lua24
-rw-r--r--test/helpers.lua184
-rw-r--r--test/includes/pre/uv.h4
-rw-r--r--test/unit/helpers.lua4
-rw-r--r--test/unit/mbyte_spec.lua4
-rw-r--r--test/unit/os/fs_spec.lua4
-rw-r--r--third-party/CMakeLists.txt34
-rw-r--r--third-party/cmake/BuildGperf.cmake1
-rw-r--r--third-party/cmake/BuildLibtermkey.cmake1
-rw-r--r--third-party/cmake/BuildLua.cmake4
-rw-r--r--third-party/cmake/BuildLuajit.cmake2
-rw-r--r--third-party/cmake/BuildLuarocks.cmake133
-rw-r--r--third-party/cmake/BuildLuv.cmake49
-rw-r--r--third-party/cmake/DownloadAndExtractFile.cmake29
-rw-r--r--third-party/cmake/GetBinaryDeps.cmake7
-rw-r--r--third-party/cmake/LibvtermCMakeLists.txt5
-rw-r--r--third-party/cmake/libtermkeyCMakeLists.txt2
-rw-r--r--third-party/patches/luv-Add-missing-definitions-for-MinGW.patch24
513 files changed, 24554 insertions, 11952 deletions
diff --git a/.flake8 b/.flake8
new file mode 100644
index 0000000000..2bcd70e390
--- /dev/null
+++ b/.flake8
@@ -0,0 +1,2 @@
+[flake8]
+max-line-length = 88
diff --git a/.gitattributes b/.gitattributes
new file mode 100755
index 0000000000..15a5c58091
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+*.h linguist-language=C
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000000..50ef4e6897
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1 @@
+custom: https://salt.bountysource.com/teams/neovim
diff --git a/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE/bug_report.md
index 4126f66d6c..fc8bc230fd 100644
--- a/ISSUE_TEMPLATE.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -1,7 +1,15 @@
+---
+name: Bug report
+about: Report a problem in Nvim
+title: ''
+labels: bug
+
+---
+
<!-- Before reporting: search existing issues and check the FAQ. -->
- `nvim --version`:
-- Vim (version: ) behaves differently?
+- `vim -u DEFAULTS` (version: ) behaves differently?
- Operating system/version:
- Terminal name/version:
- `$TERM`:
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000000..928cde894c
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,27 @@
+---
+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/.gitignore b/.gitignore
index bf9928ce15..68dbb7588a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,12 +41,13 @@ tags
/src/nvim/testdir/X*
/src/nvim/testdir/valgrind.*
/src/nvim/testdir/.gdbinit
+/runtime/indent/testdir/*.out
# Generated by unit tests.
/test/includes/post/
-# Generated by luacheck during `make testlint'
-/test/.luacheckcache
+# Generated by luacheck during `make lualint'
+.luacheckcache
# local make targets
local.mk
@@ -55,3 +56,6 @@ local.mk
/runtime/doc/*.html
/runtime/doc/tags.ref
/runtime/doc/errors.log
+
+# CLion
+/.idea/
diff --git a/.luacheckrc b/.luacheckrc
new file mode 100644
index 0000000000..b945835bba
--- /dev/null
+++ b/.luacheckrc
@@ -0,0 +1,20 @@
+-- vim: ft=lua tw=80
+
+-- Ignore W211 (unused variable) with preload files.
+files["**/preload.lua"] = {ignore = { "211" }}
+
+-- Don't report unused self arguments of methods.
+self = false
+
+-- Rerun tests only if their modification time changed.
+cache = true
+
+ignore = {
+ "631", -- max_line_length
+ "212/_.*", -- unused argument, for vars with "_" prefix
+}
+
+-- Global objects defined by the C code
+read_globals = {
+ "vim",
+}
diff --git a/.travis.yml b/.travis.yml
index bcc5c11930..f234c89c26 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -10,8 +10,6 @@ env:
- BUILD_DIR="$TRAVIS_BUILD_DIR/build"
# Build directory for third-party dependencies.
- DEPS_BUILD_DIR="$HOME/nvim-deps"
- # Directory where third-party dependency sources are downloaded to.
- - DEPS_DOWNLOAD_DIR="$TRAVIS_BUILD_DIR/deps-downloads"
# Install directory for Neovim.
- INSTALL_PREFIX="$HOME/nvim-install"
# Log directory for Clang sanitizers and Valgrind.
@@ -25,7 +23,7 @@ env:
-DBUSTED_OUTPUT_TYPE=nvim
-DDEPS_PREFIX=$DEPS_BUILD_DIR/usr
-DMIN_LOG_LEVEL=3"
- - DEPS_CMAKE_FLAGS="-DDEPS_DOWNLOAD_DIR:PATH=$DEPS_DOWNLOAD_DIR -DUSE_BUNDLED_GPERF=OFF"
+ - DEPS_CMAKE_FLAGS="-DUSE_BUNDLED_GPERF=OFF"
# Additional CMake flags for 32-bit builds.
- CMAKE_FLAGS_32BIT="-DCMAKE_SYSTEM_LIBRARY_PATH=/lib32:/usr/lib32:/usr/local/lib32
-DCMAKE_IGNORE_PATH=/lib:/usr/lib:/usr/local/lib
@@ -34,11 +32,11 @@ env:
- ASAN_OPTIONS="detect_leaks=1:check_initialization_order=1:log_path=$LOG_DIR/asan"
- TSAN_OPTIONS="log_path=$LOG_DIR/tsan"
- UBSAN_OPTIONS="print_stacktrace=1 log_path=$LOG_DIR/ubsan"
- - ASAN_SYMBOLIZE=asan_symbolize
# Environment variables for Valgrind.
- VALGRIND_LOG="$LOG_DIR/valgrind-%p.log"
+ - CACHE_NVIM_DEPS_DIR="$HOME/.cache/nvim-deps"
# If this file exists, the cache is valid (compile was successful).
- - CACHE_MARKER="$HOME/.cache/nvim-deps/.travis_cache_marker"
+ - CACHE_MARKER="$CACHE_NVIM_DEPS_DIR/.travis_cache_marker"
# default target name for functional tests
- FUNCTIONALTEST=functionaltest
- CI_TARGET=tests
@@ -46,66 +44,25 @@ env:
- CCACHE_COMPRESS=1
- CCACHE_SLOPPINESS=time_macros,file_macro
- CCACHE_BASEDIR="$TRAVIS_BUILD_DIR"
+ # Default since 3.3, but Travis (Xenial) has 3.2.4; required with newer gcc/clang.
+ - CCACHE_CPP2=1
-jobs:
- include:
- - stage: normal builds
- os: linux
- compiler: clang-4.0
- # Use Lua so that ASAN can test our embedded Lua support. 8fec4d53d0f6
- env: >
- CLANG_SANITIZER=ASAN_UBSAN
- CMAKE_FLAGS="$CMAKE_FLAGS -DPREFER_LUA=ON"
- ASAN_SYMBOLIZE=asan_symbolize-4.0
- - os: linux
- compiler: gcc
- env: >
- FUNCTIONALTEST=functionaltest-lua
- CMAKE_FLAGS="$CMAKE_FLAGS -DPREFER_LUA=ON"
- DEPS_CMAKE_FLAGS="$DEPS_CMAKE_FLAGS -DUSE_BUNDLED_LUAJIT=OFF"
- - os: linux
- # Travis creates a cache per compiler. Set a different value here to
- # store 32-bit dependencies in a separate cache.
- compiler: gcc
- env: BUILD_32BIT=ON
- - os: osx
- compiler: clang
- osx_image: xcode10.1 # macOS 10.13
- - os: osx
- compiler: gcc
- osx_image: xcode10.1 # macOS 10.13
- - if: branch = master
- os: linux
- env: CI_TARGET=lint
- - stage: Flaky builds
- os: linux
- compiler: gcc
- env: GCOV=gcov CMAKE_FLAGS="$CMAKE_FLAGS -DUSE_GCOV=ON"
- - os: linux
- compiler: clang
- env: CLANG_SANITIZER=TSAN
- allow_failures:
- - env: GCOV=gcov CMAKE_FLAGS="$CMAKE_FLAGS -DUSE_GCOV=ON"
- - env: CLANG_SANITIZER=TSAN
- fast_finish: true
-
-before_install: ci/before_install.sh
-install: ci/install.sh
-before_script: ci/before_script.sh
-script: ci/script.sh
-before_cache: ci/before_cache.sh
+anchors:
+ envs: &common-job-env
+ # Do not fall back to cache for "master" for PR on "release" branch:
+ # adds the target branch to the cache key.
+ FOR_TRAVIS_CACHE=v1-$TRAVIS_BRANCH
addons:
apt:
- packages:
+ packages: &common-apt-packages
- apport
- autoconf
- automake
- build-essential
- - clang-4.0
+ - clang
- cmake
- cscope
- - g++-multilib
- gcc-multilib
- gdb
- gperf
@@ -124,6 +81,78 @@ addons:
- ccache
- ninja
+jobs:
+ include:
+ - stage: baseline
+ name: clang-asan
+ os: linux
+ compiler: clang
+ # Use Lua so that ASAN can test our embedded Lua support. 8fec4d53d0f6
+ env:
+ - CLANG_SANITIZER=ASAN_UBSAN
+ - CMAKE_FLAGS="$CMAKE_FLAGS -DPREFER_LUA=ON"
+ - *common-job-env
+ - name: gcc-coverage (gcc 9)
+ os: linux
+ compiler: gcc-9
+ env:
+ - GCOV=gcov-9
+ - CMAKE_FLAGS="$CMAKE_FLAGS -DUSE_GCOV=ON"
+ - GCOV_ERROR_FILE="/tmp/libgcov-errors.log"
+ - *common-job-env
+ addons:
+ apt:
+ sources:
+ - sourceline: 'ppa:ubuntu-toolchain-r/test'
+ packages:
+ - *common-apt-packages
+ - gcc-9
+ - if: branch = master AND commit_message !~ /\[skip.lint\]/
+ name: lint
+ os: linux
+ env:
+ - CI_TARGET=lint
+ - *common-job-env
+
+ - stage: second stage
+ name: "macOS: clang"
+ os: osx
+ compiler: clang
+ osx_image: xcode10.2 # macOS 10.14
+ env:
+ - *common-job-env
+ - name: gcc-functionaltest-lua
+ os: linux
+ compiler: gcc
+ env:
+ - FUNCTIONALTEST=functionaltest-lua
+ - CMAKE_FLAGS="$CMAKE_FLAGS -DPREFER_LUA=ON"
+ - DEPS_CMAKE_FLAGS="$DEPS_CMAKE_FLAGS -DUSE_BUNDLED_LUAJIT=OFF"
+ - *common-job-env
+ - name: gcc-32bit
+ os: linux
+ # Travis creates a cache per compiler. Set a different value here to
+ # store 32-bit dependencies in a separate cache.
+ compiler: gcc
+ env:
+ - BUILD_32BIT=ON
+ # Minimum required CMake.
+ - CMAKE_URL=https://cmake.org/files/v2.8/cmake-2.8.12-Linux-i386.sh
+ - *common-job-env
+ - name: clang-tsan
+ os: linux
+ compiler: clang
+ env:
+ - CLANG_SANITIZER=TSAN
+ - *common-job-env
+ fast_finish: true
+
+before_install: ci/before_install.sh
+install: ci/install.sh
+before_script: ci/before_script.sh
+script: ci/script.sh
+before_cache: ci/before_cache.sh
+
branches:
only:
- master
@@ -133,9 +162,7 @@ cache:
apt: true
ccache: true
directories:
- - "$HOME/.cache/pip"
- - "$HOME/.cache/nvim-deps"
- - "$HOME/.cache/nvim-deps-downloads"
+ - "$CACHE_NVIM_DEPS_DIR"
notifications:
webhooks:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 43281dee2c..1edaa63de6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,16 +2,10 @@
# intro: https://codingnest.com/basic-cmake/
# best practices (3.0+): https://gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4fd1
+# Version should match the tested CMAKE_URL in .travis.yml.
cmake_minimum_required(VERSION 2.8.12)
project(nvim C)
-if(POLICY CMP0059)
- # Needed for use of DEFINITIONS variable, which is used to collect the
- # compilation flags for reporting in "nvim --version"
- # https://github.com/neovim/neovim/pull/8558#issuecomment-398033140
- cmake_policy(SET CMP0059 OLD)
-endif()
-
# Point CMake at any custom modules we may ship
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
@@ -256,7 +250,7 @@ check_c_source_compiles("
int main(void)
{
void *trace[1];
- int trace_size = backtrace(trace, 1);
+ backtrace(trace, 1);
return 0;
}
" HAVE_EXECINFO_BACKTRACE)
@@ -264,7 +258,7 @@ int main(void)
check_c_source_compiles("
int main(void)
{
- int a;
+ int a = 42;
__builtin_add_overflow(a, a, &a);
__builtin_sub_overflow(a, a, &a);
return 0;
@@ -273,22 +267,23 @@ int main(void)
if(MSVC)
# XXX: /W4 gives too many warnings. #3241
- add_definitions(/W3 -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE)
+ add_compile_options(/W3)
+ add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE)
add_definitions(-DWIN32)
else()
- add_definitions(-Wall -Wextra -pedantic -Wno-unused-parameter
+ add_compile_options(-Wall -Wextra -pedantic -Wno-unused-parameter
-Wstrict-prototypes -std=gnu99 -Wshadow -Wconversion
-Wmissing-prototypes)
check_c_compiler_flag(-Wimplicit-fallthrough HAS_WIMPLICIT_FALLTHROUGH_FLAG)
if(HAS_WIMPLICIT_FALLTHROUGH_FLAG)
- add_definitions(-Wimplicit-fallthrough)
+ add_compile_options(-Wimplicit-fallthrough)
endif()
# On FreeBSD 64 math.h uses unguarded C11 extension, which taints clang
# 3.4.1 used there.
if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" AND CMAKE_C_COMPILER_ID MATCHES "Clang")
- add_definitions(-Wno-c11-extensions)
+ add_compile_options(-Wno-c11-extensions)
endif()
endif()
@@ -304,7 +299,7 @@ endif()
# OpenBSD's GCC (4.2.1) doesn't have -Wvla
check_c_compiler_flag(-Wvla HAS_WVLA_FLAG)
if(HAS_WVLA_FLAG)
- add_definitions(-Wvla)
+ add_compile_options(-Wvla)
endif()
if(UNIX)
@@ -313,26 +308,18 @@ if(UNIX)
check_c_compiler_flag(-fstack-protector HAS_FSTACK_PROTECTOR_FLAG)
if(HAS_FSTACK_PROTECTOR_STRONG_FLAG)
- add_definitions(-fstack-protector-strong)
+ add_compile_options(-fstack-protector-strong)
elseif(HAS_FSTACK_PROTECTOR_FLAG)
- add_definitions(-fstack-protector --param ssp-buffer-size=4)
+ add_compile_options(-fstack-protector --param ssp-buffer-size=4)
endif()
endif()
check_c_compiler_flag(-fdiagnostics-color=auto HAS_DIAG_COLOR_FLAG)
if(HAS_DIAG_COLOR_FLAG)
- add_definitions(-fdiagnostics-color=auto)
-endif()
-
-if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
- # 1. Array-bounds testing is broken in some GCC versions before 4.8.5.
- # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56273
- # 2. But _Pragma("...ignored") is broken (unresolved) in GCC 5+:
- # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66099
- # So we must disable -Warray-bounds globally for GCC (for kbtree.h, #7083).
- check_c_compiler_flag(-Wno-array-bounds HAS_NO_ARRAY_BOUNDS_FLAG)
- if(HAS_NO_ARRAY_BOUNDS_FLAG)
- add_definitions(-Wno-array-bounds)
+ if(CMAKE_GENERATOR MATCHES "Ninja")
+ add_compile_options(-fdiagnostics-color=always)
+ else()
+ add_compile_options(-fdiagnostics-color=auto)
endif()
endif()
@@ -340,10 +327,10 @@ option(TRAVIS_CI_BUILD "Travis/QuickBuild CI, extra flags will be set" OFF)
if(TRAVIS_CI_BUILD)
message(STATUS "Travis/QuickBuild CI build enabled")
- add_definitions(-Werror)
+ add_compile_options(-Werror)
if(DEFINED ENV{BUILD_32BIT})
# Get some test coverage for unsigned char
- add_definitions(-funsigned-char)
+ add_compile_options(-funsigned-char)
endif()
endif()
@@ -379,12 +366,15 @@ endif()
include_directories("${PROJECT_BINARY_DIR}/config")
include_directories("${PROJECT_SOURCE_DIR}/src")
-find_package(LibUV REQUIRED) # minimum version: v1.12
+find_package(LibUV 1.28.0 REQUIRED)
include_directories(SYSTEM ${LIBUV_INCLUDE_DIRS})
find_package(Msgpack 1.0.0 REQUIRED)
include_directories(SYSTEM ${MSGPACK_INCLUDE_DIRS})
+find_package(LibLUV 1.30.0 REQUIRED)
+include_directories(SYSTEM ${LIBLUV_INCLUDE_DIRS})
+
# Note: The test lib requires LuaJIT; it will be skipped if LuaJIT is missing.
option(PREFER_LUA "Prefer Lua over LuaJIT in the nvim executable." OFF)
@@ -410,7 +400,7 @@ main(void)
return MSGPACK_OBJECT_FLOAT32;
}
" MSGPACK_HAS_FLOAT32)
-unset(CMAKE_REQUIRED_LIBRARIES)
+list(REMOVE_ITEM CMAKE_REQUIRED_INCLUDES "${MSGPACK_INCLUDE_DIRS}")
if(MSGPACK_HAS_FLOAT32)
add_definitions(-DNVIM_MSGPACK_HAS_FLOAT32)
endif()
@@ -418,7 +408,7 @@ endif()
option(FEAT_TUI "Enable the Terminal UI" ON)
if(FEAT_TUI)
- find_package(Unibilium REQUIRED)
+ find_package(Unibilium 2.0 REQUIRED)
include_directories(SYSTEM ${UNIBILIUM_INCLUDE_DIRS})
list(APPEND CMAKE_REQUIRED_INCLUDES "${UNIBILIUM_INCLUDE_DIRS}")
@@ -432,8 +422,8 @@ if(FEAT_TUI)
return unibi_num_from_var(unibi_var_from_num(0));
}
" UNIBI_HAS_VAR_FROM)
- unset(CMAKE_REQUIRED_INCLUDES)
- unset(CMAKE_REQUIRED_LIBRARIES)
+ list(REMOVE_ITEM CMAKE_REQUIRED_INCLUDES "${UNIBILIUM_INCLUDE_DIRS}")
+ list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES "${UNIBILIUM_LIBRARIES}")
if(UNIBI_HAS_VAR_FROM)
add_definitions(-DNVIM_UNIBI_HAS_VAR_FROM)
endif()
@@ -526,6 +516,7 @@ if(NOT BUSTED_OUTPUT_TYPE)
endif()
find_program(LUACHECK_PRG luacheck)
+find_program(FLAKE8_PRG flake8)
find_program(GPERF_PRG gperf)
include(InstallHelpers)
@@ -599,7 +590,6 @@ if(BUSTED_PRG)
-DTEST_DIR=${CMAKE_CURRENT_SOURCE_DIR}/test
-DBUILD_DIR=${CMAKE_BINARY_DIR}
-DTEST_TYPE=unit
- -DSYSTEM_NAME=${CMAKE_SYSTEM_NAME}
-P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake
DEPENDS ${UNITTEST_PREREQS}
${TEST_TARGET_ARGS})
@@ -630,7 +620,6 @@ if(BUSTED_PRG)
-DTEST_DIR=${CMAKE_CURRENT_SOURCE_DIR}/test
-DBUILD_DIR=${CMAKE_BINARY_DIR}
-DTEST_TYPE=functional
- -DSYSTEM_NAME=${CMAKE_SYSTEM_NAME}
-P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake
DEPENDS ${FUNCTIONALTEST_PREREQS}
${TEST_TARGET_ARGS})
@@ -647,7 +636,6 @@ if(BUSTED_PRG)
-DTEST_DIR=${CMAKE_CURRENT_SOURCE_DIR}/test
-DBUILD_DIR=${CMAKE_BINARY_DIR}
-DTEST_TYPE=benchmark
- -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
-P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake
DEPENDS ${BENCHMARK_PREREQS}
${TEST_TARGET_ARGS})
@@ -665,7 +653,6 @@ if(BUSTED_LUA_PRG)
-DTEST_DIR=${CMAKE_CURRENT_SOURCE_DIR}/test
-DBUILD_DIR=${CMAKE_BINARY_DIR}
-DTEST_TYPE=functional
- -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
-P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake
DEPENDS ${FUNCTIONALTEST_PREREQS}
${TEST_TARGET_ARGS})
@@ -673,40 +660,12 @@ if(BUSTED_LUA_PRG)
endif()
if(LUACHECK_PRG)
- add_custom_target(testlint
- COMMAND ${CMAKE_COMMAND}
- -DLUACHECK_PRG=${LUACHECK_PRG}
- -DLUAFILES_DIR=${CMAKE_CURRENT_SOURCE_DIR}/test
- -DIGNORE_PATTERN="*/preload.lua"
- -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
- -P ${PROJECT_SOURCE_DIR}/cmake/RunLuacheck.cmake)
-
- add_custom_target(
- lintbuiltinlua
- COMMAND
- ${CMAKE_COMMAND}
- -DLUACHECK_PRG=${LUACHECK_PRG}
- -DLUAFILES_DIR=${CMAKE_CURRENT_SOURCE_DIR}/src/nvim/lua
- -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
- -DREAD_GLOBALS=vim
- -P ${PROJECT_SOURCE_DIR}/cmake/RunLuacheck.cmake
- )
- add_custom_target(
- lintruntimelua
- COMMAND
- ${CMAKE_COMMAND}
- -DLUACHECK_PRG=${LUACHECK_PRG}
- -DLUAFILES_DIR=${CMAKE_CURRENT_SOURCE_DIR}/runtime/lua
- -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
- -DREAD_GLOBALS=vim
- -P ${PROJECT_SOURCE_DIR}/cmake/RunLuacheck.cmake
- )
- # TODO(ZyX-I): Run linter for all lua code in src
- add_custom_target(
- lualint
- DEPENDS lintruntimelua
- DEPENDS lintbuiltinlua
- )
+ add_custom_target(lualint
+ COMMAND ${LUACHECK_PRG} -q runtime/ src/ test/
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
+else()
+ add_custom_target(lualint false
+ COMMENT "lualint: LUACHECK_PRG not defined")
endif()
set(CPACK_PACKAGE_NAME "Neovim")
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 630324e289..607f1aae83 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,4 +1,5 @@
-# Contributing to Neovim
+Contributing to Neovim
+======================
Getting started
---------------
@@ -11,6 +12,18 @@ low-risk/isolated tasks:
- Fix bugs found by [Clang](#clang-scan-build), [PVS](#pvs-studio) or
[Coverity](#coverity).
+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.
+- When reporting a crash, [include a stacktrace](https://github.com/neovim/neovim/wiki/FAQ#backtrace-linux).
+- [Bisect][git-bisect] to the cause of a regression, if you are able. This is _extremely_ helpful.
+- Check `$NVIM_LOG_FILE`, if it exists.
+- Include `cmake --system-information` for build-related issues.
+
Developer guidelines
--------------------
@@ -24,18 +37,6 @@ Developer guidelines
make # Nvim build system uses ninja automatically, if available.
```
-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.
-- When reporting a crash, [include a stacktrace](https://github.com/neovim/neovim/wiki/Development-tips#backtrace-linux).
-- [Bisect][git-bisect] to the cause of a regression, if you are able. This is _extremely_ helpful.
-- Check `$NVIM_LOG_FILE`, if it exists.
-- Include `cmake --system-information` for build-related issues.
-
Pull requests (PRs)
---------------------
@@ -64,20 +65,10 @@ Pull requests (PRs)
Pull requests have three stages: `[WIP]` (Work In Progress), `[RFC]` (Request
For Comment) and `[RDY]` (Ready).
-- Untagged PRs are assumed to be `[RFC]`, i.e. you are requesting a review.
-- Prepend `[WIP]` to the PR title if you are _not_ requesting feedback and the
- work is still in flux.
-- Prepend `[RDY]` to the PR title if you are _done_ with the PR and are only
- waiting on it to be merged.
-
-For example, a typical workflow is:
-
-1. You open a `[WIP]` PR where the work is _not_ ready for feedback, you just want to
- let others know what you are doing.
-2. Once the PR is ready for review, you replace `[WIP]` in the title with `[RFC]`.
- You may add fix up commits to address issues that come up during review.
-3. Once the PR is ready for merging, you rebase/squash your work appropriately and
- then replace `[RFC]` in the title with `[RDY]`.
+- `[RFC]` is assumed by default, i.e. you are requesting a review.
+- Add `[WIP]` to the PR title if you are _not_ requesting feedback and the work
+ is still in flux.
+- Add `[RDY]` if you are _done_ and only waiting on merge.
### Commit messages
@@ -106,19 +97,18 @@ and [AppVeyor].
- CI runs [ASan] and other analyzers.
- To run valgrind locally: `VALGRIND=1 make test`
- To run Clang ASan/UBSan locally: `CC=clang make CMAKE_FLAGS="-DCLANG_ASAN_UBSAN=ON"`
-- The `lint` build ([#3174][3174]) checks modified lines _and their immediate
- neighbors_. This is to encourage incrementally updating the legacy style to
- meet our style guidelines.
+- The [lint](#lint) build checks modified lines _and their immediate
+ neighbors_, to encourage incrementally updating the legacy style to meet our
+ [style](#style). (See [#3174][3174] for background.)
- [How to investigate QuickBuild failures](https://github.com/neovim/neovim/pull/4718#issuecomment-217631350)
-
-QuickBuild uses this invocation:
-
- mkdir -p build/${params.get("buildType")} \
- && cd build/${params.get("buildType")} \
- && cmake -G "Unix Makefiles" -DBUSTED_OUTPUT_TYPE=TAP -DCMAKE_BUILD_TYPE=${params.get("buildType")}
- -DTRAVIS_CI_BUILD=ON ../.. && ${node.getAttribute("make", "make")}
- VERBOSE=1 nvim unittest-prereqs functionaltest-prereqs
-
+ - QuickBuild uses this invocation:
+ ```
+ mkdir -p build/${params.get("buildType")} \
+ && cd build/${params.get("buildType")} \
+ && cmake -G "Unix Makefiles" -DBUSTED_OUTPUT_TYPE=TAP -DCMAKE_BUILD_TYPE=${params.get("buildType")}
+ -DTRAVIS_CI_BUILD=ON ../.. && ${node.getAttribute("make", "make")}
+ VERBOSE=1 nvim unittest-prereqs functionaltest-prereqs
+ ```
### Clang scan-build
@@ -165,6 +155,41 @@ master build. To view the defects, just request access; you will be approved.
git log --oneline --no-merges --grep coverity
```
+
+Coding
+------
+
+### Lint
+
+You can run the linter locally by:
+
+ make lint
+
+The lint step downloads the [master error list] and excludes them, so only lint
+errors related to the local changes are reported.
+
+You can lint a single file (but this will _not_ exclude legacy errors):
+
+ ./src/clint.py src/nvim/ops.c
+
+### 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
+
+### Navigate
+
+- 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.)
+- Explore the source code [on the web](https://sourcegraph.com/github.com/neovim/neovim).
+
+
Reviewing
---------
@@ -203,3 +228,4 @@ as context, use the `-W` argument as well.
[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
diff --git a/Makefile b/Makefile
index 4142cacc51..fff0ffef28 100644
--- a/Makefile
+++ b/Makefile
@@ -5,6 +5,8 @@ filter-true = $(strip $(filter-out 1 on ON true TRUE,$1))
# See contrib/local.mk.example
-include local.mk
+all: nvim
+
CMAKE_PRG ?= $(shell (command -v cmake3 || echo cmake))
CMAKE_BUILD_TYPE ?= Debug
CMAKE_FLAGS := -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE)
@@ -14,10 +16,23 @@ CMAKE_EXTRA_FLAGS ?=
# CMAKE_INSTALL_PREFIX
# - May be passed directly or as part of CMAKE_EXTRA_FLAGS.
# - `checkprefix` target checks that it matches the CMake-cached value. #9615
-CMAKE_INSTALL_PREFIX ?= $(shell echo $(CMAKE_EXTRA_FLAGS) | 2>/dev/null \
+ifneq (,$(CMAKE_INSTALL_PREFIX)$(CMAKE_EXTRA_FLAGS))
+CMAKE_INSTALL_PREFIX := $(shell echo $(CMAKE_EXTRA_FLAGS) | 2>/dev/null \
grep -o 'CMAKE_INSTALL_PREFIX=[^ ]\+' | cut -d '=' -f2)
+endif
ifneq (,$(CMAKE_INSTALL_PREFIX))
- CMAKE_FLAGS += -DCMAKE_INSTALL_PREFIX=$(CMAKE_INSTALL_PREFIX)
+override CMAKE_EXTRA_FLAGS += -DCMAKE_INSTALL_PREFIX=$(CMAKE_INSTALL_PREFIX)
+
+checkprefix:
+ @if [ -f build/.ran-cmake ]; then \
+ cached_prefix=$(shell $(CMAKE_PRG) -L -N build | 2>/dev/null grep 'CMAKE_INSTALL_PREFIX' | cut -d '=' -f2); \
+ if ! [ "$(CMAKE_INSTALL_PREFIX)" = "$$cached_prefix" ]; then \
+ printf "Re-running CMake: CMAKE_INSTALL_PREFIX '$(CMAKE_INSTALL_PREFIX)' does not match cached value '%s'.\n" "$$cached_prefix"; \
+ $(RM) build/.ran-cmake; \
+ fi \
+ fi
+else
+checkprefix: ;
endif
BUILD_TYPE ?= $(shell (type ninja > /dev/null 2>&1 && echo "Ninja") || \
@@ -41,15 +56,15 @@ ifeq (,$(BUILD_TOOL))
endif
endif
+BUILD_CMD = $(BUILD_TOOL)
+
ifneq ($(VERBOSE),)
# Only need to handle Ninja here. Make will inherit the VERBOSE variable.
ifeq ($(BUILD_TYPE),Ninja)
- VERBOSE_FLAG := -v
+ BUILD_CMD += -v
endif
endif
-BUILD_CMD = $(BUILD_TOOL) $(VERBOSE_FLAG)
-
DEPS_CMAKE_FLAGS ?=
# Back-compat: USE_BUNDLED_DEPS was the old name.
USE_BUNDLED ?= $(USE_BUNDLED_DEPS)
@@ -67,9 +82,7 @@ endif
# a warning, but we need to keep SCRIPTS argument.
SINGLE_MAKE = export MAKEFLAGS= ; $(MAKE)
-all: nvim
-
-nvim: checkprefix build/.ran-cmake deps
+nvim: build/.ran-cmake deps
+$(BUILD_CMD) -C build
libnvim: build/.ran-cmake deps
@@ -88,13 +101,15 @@ ifeq ($(call filter-true,$(USE_BUNDLED)),)
+$(BUILD_CMD) -C $(DEPS_BUILD_DIR)
endif
-build/.ran-third-party-cmake:
ifeq ($(call filter-true,$(USE_BUNDLED)),)
- mkdir -p $(DEPS_BUILD_DIR)
+$(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
endif
+build/.ran-third-party-cmake::
mkdir -p build
touch $@
@@ -120,12 +135,17 @@ functionaltest: | nvim
functionaltest-lua: | nvim
+$(BUILD_CMD) -C build functionaltest-lua
-testlint: | build/.ran-cmake deps
- $(BUILD_CMD) -C build testlint
-
lualint: | build/.ran-cmake deps
$(BUILD_CMD) -C build lualint
+pylint:
+ flake8 contrib/ scripts/ src/ test/
+
+# Run pylint only if flake8 is installed.
+_opt_pylint:
+ @command -v flake8 && { $(MAKE) pylint; exit $$?; } \
+ || echo "SKIP: pylint (flake8 not found)"
+
unittest: | nvim
+$(BUILD_CMD) -C build unittest
@@ -139,10 +159,11 @@ clean:
$(MAKE) -C src/nvim/testdir clean
$(MAKE) -C runtime/doc clean
-distclean: clean
+distclean:
rm -rf $(DEPS_BUILD_DIR) build
+ $(MAKE) clean
-install: | nvim
+install: checkprefix nvim
+$(BUILD_CMD) -C build install
clint: build/.ran-cmake
@@ -166,15 +187,16 @@ appimage:
appimage-%:
bash scripts/genappimage.sh $*
-lint: check-single-includes clint testlint lualint
+lint: check-single-includes clint lualint _opt_pylint
-checkprefix:
- @cached_prefix=$$("$(CMAKE_PRG)" -L -N build | 2>/dev/null grep 'CMAKE_INSTALL_PREFIX' | cut -d '=' -f2); \
- if [ -n "$(CMAKE_INSTALL_PREFIX)" ] && [ -n "$$cached_prefix" ] && ! [ "$(CMAKE_INSTALL_PREFIX)" = "$$cached_prefix" ]; then \
- printf "\nerror: CMAKE_INSTALL_PREFIX '$(CMAKE_INSTALL_PREFIX)' does not match cached value '%s'\n" "$$cached_prefix"; \
- printf " Run this command, then try again:\n"; \
- printf " cmake build -DCMAKE_INSTALL_PREFIX=$(CMAKE_INSTALL_PREFIX)\n"; \
- exit 1; \
- fi;
-
-.PHONY: test testlint lualint functionaltest unittest lint clint clean distclean nvim libnvim cmake deps install appimage checkprefix
+# Generic pattern rules, allowing for `make build/bin/nvim` etc.
+# Does not work with "Unix Makefiles".
+ifeq ($(BUILD_TYPE),Ninja)
+build/%:
+ $(BUILD_CMD) -C build $(patsubst build/%,%,$@)
+
+$(DEPS_BUILD_DIR)/%:
+ $(BUILD_CMD) -C $(DEPS_BUILD_DIR) $(patsubst $(DEPS_BUILD_DIR)/%,%,$@)
+endif
+
+.PHONY: test lualint pylint functionaltest unittest lint clint clean distclean nvim libnvim cmake deps install appimage checkprefix
diff --git a/appveyor.yml b/appveyor.yml
index 0de9174adf..756c7fea2e 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -3,32 +3,43 @@ environment:
APPVEYOR_CACHE_ENTRY_ZIP_ARGS: "-t7z -m0=lzma -mx=9"
DEPS_BUILD_DIR: "C:/projects/nvim-deps"
DEPS_PREFIX: "C:/projects/nvim-deps/usr"
+ # Silence/redirect errors due to missing locking support (via libgcov).
+ GCOV_ERROR_FILE: "$(TEMP)/libgcov-errors.log"
image: Visual Studio 2017
configuration:
+- MINGW_64-gcov
+- MINGW_32
- MSVC_64
- MSVC_32
-- MINGW_64
-- MINGW_32
-- MINGW_64-gcov
init:
- ps: |
# Pull requests: skip some build configurations to save time.
- if ($env:APPVEYOR_PULL_REQUEST_HEAD_COMMIT -and $env:CONFIGURATION -match '^(MSVC_64|MINGW_32|MINGW_64-gcov)$') {
+ if ($env:APPVEYOR_PULL_REQUEST_HEAD_COMMIT -and $env:CONFIGURATION -match '^(MSVC_64|MINGW_32)$') {
$env:APPVEYOR_CACHE_SKIP_SAVE = "true"
Exit-AppVeyorBuild
}
# RDP
#- ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
matrix:
- allow_failures:
- - configuration: MINGW_64-gcov
+ fast_finish: true
install: []
before_build:
- ps: Install-Product node 8
build_script:
- powershell ci\build.ps1
+after_build:
+- ps: |
+ if (Test-Path $env:GCOV_ERROR_FILE) {
+ Get-Content $env:GCOV_ERROR_FILE -Head 10
+ Get-Content $env:GCOV_ERROR_FILE -Tail 10
+ } else {
+ write-host "no GCOV_ERROR_FILE"
+ }
cache:
- C:\projects\nvim-deps -> third-party\**
artifacts:
- path: build/Neovim.zip
- path: build/bin/nvim.exe
+branches:
+ only:
+ - master
diff --git a/busted/outputHandlers/TAP.lua b/busted/outputHandlers/TAP.lua
deleted file mode 100644
index 612e633576..0000000000
--- a/busted/outputHandlers/TAP.lua
+++ /dev/null
@@ -1,94 +0,0 @@
--- TODO(jkeyes): Use the upstream version when busted releases it. (But how to
--- inject our call to global_helpers.read_nvim_log() ?)
-
-local pretty = require 'pl.pretty'
-local global_helpers = require('test.helpers')
-
-return function(options)
- local busted = require 'busted'
- local handler = require 'busted.outputHandlers.base'()
-
- local success = 'ok %u - %s'
- local failure = 'not ' .. success
- local skip = 'ok %u - # SKIP %s'
- local counter = 0
-
- handler.suiteReset = function()
- counter = 0
- return nil, true
- end
-
- handler.suiteEnd = function()
- io.write(global_helpers.read_nvim_log())
- print('1..' .. counter)
- io.flush()
- return nil, true
- end
-
- local function showFailure(t)
- local message = t.message
- local trace = t.trace or {}
-
- if message == nil then
- message = 'Nil error'
- elseif type(message) ~= 'string' then
- message = pretty.write(message)
- end
-
- print(failure:format(counter, t.name))
- print('# ' .. t.element.trace.short_src .. ' @ ' .. t.element.trace.currentline)
- if t.randomseed then print('# Random seed: ' .. t.randomseed) end
- print('# Failure message: ' .. message:gsub('\n', '\n# '))
- if options.verbose and trace.traceback then
- print('# ' .. trace.traceback:gsub('^\n', '', 1):gsub('\n', '\n# '))
- end
- end
-
- handler.testStart = function(element, parent)
- local trace = element.trace
- if options.verbose and trace and trace.short_src then
- local fileline = trace.short_src .. ' @ ' .. trace.currentline .. ': '
- local testName = fileline .. handler.getFullName(element)
- print('# ' .. testName)
- end
- io.flush()
-
- return nil, true
- end
-
- handler.testEnd = function(element, parent, status, trace)
- counter = counter + 1
- if status == 'success' then
- local t = handler.successes[#handler.successes]
- print(success:format(counter, t.name))
- elseif status == 'pending' then
- local t = handler.pendings[#handler.pendings]
- print(skip:format(counter, (t.message or t.name)))
- elseif status == 'failure' then
- showFailure(handler.failures[#handler.failures])
- elseif status == 'error' then
- showFailure(handler.errors[#handler.errors])
- end
- io.flush()
-
- return nil, true
- end
-
- handler.error = function(element, parent, message, debug)
- if element.descriptor ~= 'it' then
- counter = counter + 1
- showFailure(handler.errors[#handler.errors])
- end
- io.flush()
-
- return nil, true
- end
-
- busted.subscribe({ 'suite', 'reset' }, handler.suiteReset)
- busted.subscribe({ 'suite', 'end' }, handler.suiteEnd)
- busted.subscribe({ 'test', 'start' }, handler.testStart, { predicate = handler.cancelOnPending })
- busted.subscribe({ 'test', 'end' }, handler.testEnd, { predicate = handler.cancelOnPending })
- busted.subscribe({ 'error' }, handler.error)
-
- return handler
-end
diff --git a/ci/before_cache.sh b/ci/before_cache.sh
index c8a1fd5b71..c86109168e 100755
--- a/ci/before_cache.sh
+++ b/ci/before_cache.sh
@@ -7,23 +7,20 @@ CI_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${CI_DIR}/common/build.sh"
source "${CI_DIR}/common/suite.sh"
-# Don't cache pip's log and selfcheck.
-rm -rf "${HOME}/.cache/pip/log"
-rm -f "${HOME}/.cache/pip/selfcheck.json"
-
echo "before_cache.sh: cache size"
-du -d 2 "${HOME}/.cache" | sort -n
+du -chd 1 "${HOME}/.cache" | sort -rh | head -20
echo "before_cache.sh: ccache stats"
ccache -s 2>/dev/null || true
+# Do not keep ccache stats (uploaded to cache otherwise; reset initially anyway).
+find "${HOME}/.ccache" -name stats -delete
# Update the third-party dependency cache only if the build was successful.
if ended_successfully; then
- rm -rf "${HOME}/.cache/nvim-deps"
- mv "${DEPS_BUILD_DIR}" "${HOME}/.cache/nvim-deps"
-
- rm -rf "${HOME}/.cache/nvim-deps-downloads"
- mv "${DEPS_DOWNLOAD_DIR}" "${HOME}/.cache/nvim-deps-downloads"
+ # Do not cache downloads. They should not be needed with up-to-date deps.
+ rm -rf "${DEPS_BUILD_DIR}/build/downloads"
+ rm -rf "${CACHE_NVIM_DEPS_DIR}"
+ mv "${DEPS_BUILD_DIR}" "${CACHE_NVIM_DEPS_DIR}"
touch "${CACHE_MARKER}"
echo "Updated third-party dependencies (timestamp: $(_stat "${CACHE_MARKER}"))."
diff --git a/ci/before_install.sh b/ci/before_install.sh
index d8cf38d314..5cb6894b8c 100755
--- a/ci/before_install.sh
+++ b/ci/before_install.sh
@@ -7,28 +7,37 @@ if [[ "${CI_TARGET}" == lint ]]; then
exit
fi
-echo 'python info:'
+echo 'Python info:'
(
- 2>&1 python --version || true
- 2>&1 python2 --version || true
- 2>&1 python3 --version || true
- 2>&1 pip --version || true
- 2>&1 pip2 --version || true
- 2>&1 pip3 --version || true
- echo 'pyenv versions:'
- 2>&1 pyenv versions || true
-) | sed 's/^/ /'
-
-if [[ "${TRAVIS_OS_NAME}" == osx ]]; then
- echo "Upgrade Python 3 pip"
- python3 -m pip -q install --user --upgrade pip
-else
- echo "Upgrade Python 2 pip"
- python2.7 -m pip -q install --user --upgrade pip
- echo "Upgrade Python 3 pip"
- # Allow failure. pyenv pip3 on travis is broken:
- # https://github.com/travis-ci/travis-ci/issues/8363
- python3 -m pip -q install --user --upgrade pip || true
+ set -x
+ python3 --version
+ python2 --version
+ python --version
+ pip3 --version
+ pip2 --version
+ pip --version
+
+ pyenv --version
+ pyenv versions
+) 2>&1 | sed 's/^/ /' || true
+
+# Use pyenv, but not for OSX on Travis, where it only has the "system" version.
+if [[ "${TRAVIS_OS_NAME}" != osx ]] && command -v pyenv; then
+ echo 'Setting Python versions via pyenv'
+
+ # Prefer Python 2 over 3 (more conservative).
+ pyenv global 2.7.15:3.7
+
+ echo 'Updated Python info:'
+ (
+ set -x
+ python3 --version
+ python2 --version
+ python --version
+
+ python3 -m pip --version
+ python2 -m pip --version
+ ) 2>&1 | sed 's/^/ /'
fi
echo "Install node (LTS)"
@@ -40,3 +49,16 @@ fi
source ~/.nvm/nvm.sh
nvm install --lts
nvm use --lts
+
+if [[ -n "$CMAKE_URL" ]]; then
+ echo "Installing custom CMake: $CMAKE_URL"
+ curl --retry 5 --silent --fail -o /tmp/cmake-installer.sh "$CMAKE_URL"
+ mkdir -p "$HOME/.local/bin" /opt/cmake-custom
+ bash /tmp/cmake-installer.sh --prefix=/opt/cmake-custom --skip-license
+ ln -sfn /opt/cmake-custom/bin/cmake "$HOME/.local/bin/cmake"
+ cmake_version="$(cmake --version)"
+ echo "$cmake_version" | grep -qF '2.8.12' || {
+ echo "Unexpected CMake version: $cmake_version"
+ exit 1
+ }
+fi
diff --git a/ci/before_script.sh b/ci/before_script.sh
index 49b4e068b5..605ecdbf66 100755
--- a/ci/before_script.sh
+++ b/ci/before_script.sh
@@ -20,8 +20,10 @@ if [[ -n "${LLVM_SYMBOLIZER}" ]] && [[ ! $(type -P "${LLVM_SYMBOLIZER}") ]]; the
exit 1
fi
-# Show ccache stats so we can compare in before_cache
-ccache -s 2>/dev/null || true
+echo "before_script.sh: ccache stats (will be cleared)"
+ccache -s
+# Reset ccache stats for real results in before_cache.
+ccache --zero-stats
if [[ "${TRAVIS_OS_NAME}" == osx ]]; then
# Adds user to a dummy group.
diff --git a/ci/build.ps1 b/ci/build.ps1
index 4c47ac1c51..42066c462b 100644
--- a/ci/build.ps1
+++ b/ci/build.ps1
@@ -14,9 +14,11 @@ $depsCmakeVars = @{
$nvimCmakeVars = @{
CMAKE_BUILD_TYPE = $cmakeBuildType;
BUSTED_OUTPUT_TYPE = 'nvim';
- DEPS_BUILD_DIR=$(if ($env:DEPS_BUILD_DIR -ne $null) {$env:DEPS_BUILD_DIR} else {".deps"});
DEPS_PREFIX=$(if ($env:DEPS_PREFIX -ne $null) {$env:DEPS_PREFIX} else {".deps/usr"});
}
+if ($env:DEPS_BUILD_DIR -eq $null) {
+ $env:DEPS_BUILD_DIR = ".deps";
+}
$uploadToCodeCov = $false
function exitIfFailed() {
@@ -26,11 +28,11 @@ function exitIfFailed() {
}
}
-if (-Not (Test-Path -PathType container $nvimCmakeVars["DEPS_BUILD_DIR"])) {
- write-host "cache dir not found: $($nvimCmakeVars['DEPS_BUILD_DIR'])"
- mkdir $nvimCmakeVars["DEPS_BUILD_DIR"]
+if (-Not (Test-Path -PathType container $env:DEPS_BUILD_DIR)) {
+ write-host "cache dir not found: $($env:DEPS_BUILD_DIR)"
+ mkdir $env:DEPS_BUILD_DIR
} else {
- write-host "cache dir $($nvimCmakeVars['DEPS_BUILD_DIR']) size: $(Get-ChildItem $nvimCmakeVars['DEPS_BUILD_DIR'] -recurse | Measure-Object -property length -sum | Select -expand sum)"
+ write-host "cache dir $($env:DEPS_BUILD_DIR) size: $(Get-ChildItem $env:DEPS_BUILD_DIR -recurse | Measure-Object -property length -sum | Select -expand sum)"
}
if ($compiler -eq 'MINGW') {
@@ -43,13 +45,14 @@ if ($compiler -eq 'MINGW') {
if ($compileOption -eq 'gcov') {
$nvimCmakeVars['USE_GCOV'] = 'ON'
$uploadToCodecov = $true
+ $env:GCOV = "C:\msys64\mingw$bits\bin\gcov"
}
# These are native MinGW builds, but they use the toolchain inside
# MSYS2, this allows using all the dependencies and tools available
# in MSYS2, but we cannot build inside the MSYS2 shell.
$cmakeGenerator = 'Ninja'
$cmakeGeneratorArgs = '-v'
- $mingwPackages = @('ninja', 'cmake', 'perl', 'diffutils', 'unibilium').ForEach({
+ $mingwPackages = @('ninja', 'cmake', 'perl', 'diffutils').ForEach({
"mingw-w64-$arch-$_"
})
@@ -95,7 +98,7 @@ function convertToCmakeArgs($vars) {
return $vars.GetEnumerator() | foreach { "-D$($_.Key)=$($_.Value)" }
}
-cd $nvimCmakeVars["DEPS_BUILD_DIR"]
+cd $env:DEPS_BUILD_DIR
cmake -G $cmakeGenerator $(convertToCmakeArgs($depsCmakeVars)) "$buildDir/third-party/" ; exitIfFailed
cmake --build . --config $cmakeBuildType -- $cmakeGeneratorArgs ; exitIfFailed
cd $buildDir
@@ -105,7 +108,10 @@ mkdir build
cd build
cmake -G $cmakeGenerator $(convertToCmakeArgs($nvimCmakeVars)) .. ; exitIfFailed
cmake --build . --config $cmakeBuildType -- $cmakeGeneratorArgs ; exitIfFailed
-bin\nvim --version ; exitIfFailed
+.\bin\nvim --version ; exitIfFailed
+
+# Ensure that the "win32" feature is set.
+.\bin\nvim -u NONE --headless -c 'exe !has(\"win32\").\"cq\"' ; exitIfFailed
# Functional tests
# The $LastExitCode from MSBuild can't be trusted
@@ -116,21 +122,28 @@ cmake --build . --config $cmakeBuildType --target functionaltest -- $cmakeGenera
foreach { $failed = $failed -or
$_ -match 'functional tests failed with error'; $_ }
if ($failed) {
+ if ($uploadToCodecov) {
+ bash -l /c/projects/neovim/ci/common/submit_coverage.sh functionaltest
+ }
exit $LastExitCode
}
Set-PSDebug -Strict -Trace 1
if ($uploadToCodecov) {
- C:\msys64\usr\bin\bash -lc "cd /c/projects/neovim; bash <(curl -s https://codecov.io/bash) -c -F functionaltest || echo 'codecov upload failed.'"
+ bash -l /c/projects/neovim/ci/common/submit_coverage.sh functionaltest
}
# Old tests
+# Add MSYS to path, required for e.g. `find` used in test scripts.
+# But would break functionaltests, where its `more` would be used then.
+$OldPath = $env:PATH
$env:PATH = "C:\msys64\usr\bin;$env:PATH"
& "C:\msys64\mingw$bits\bin\mingw32-make.exe" -C $(Convert-Path ..\src\nvim\testdir) VERBOSE=1
+$env:PATH = $OldPath
if ($uploadToCodecov) {
- C:\msys64\usr\bin\bash -lc "cd /c/projects/neovim; bash <(curl -s https://codecov.io/bash) -c -F oldtest || echo 'codecov upload failed.'"
+ bash -l /c/projects/neovim/ci/common/submit_coverage.sh oldtest
}
# Build artifacts
diff --git a/ci/common/build.sh b/ci/common/build.sh
index 7c27d61586..bdbe012ca6 100644
--- a/ci/common/build.sh
+++ b/ci/common/build.sh
@@ -27,15 +27,13 @@ build_deps() {
fi
mkdir -p "${DEPS_BUILD_DIR}"
- mkdir -p "${DEPS_DOWNLOAD_DIR}"
# Use cached dependencies if $CACHE_MARKER exists.
if test "${CACHE_ENABLE}" = "false" ; then
export CCACHE_RECACHE=1
elif test -f "${CACHE_MARKER}" ; then
echo "Using third-party dependencies from Travis cache (last update: $(_stat "${CACHE_MARKER}"))."
- cp -r "${HOME}/.cache/nvim-deps"/. "${DEPS_BUILD_DIR}"
- cp -r "${HOME}/.cache/nvim-deps-downloads"/. "${DEPS_DOWNLOAD_DIR}"
+ cp -a "${CACHE_NVIM_DEPS_DIR}"/. "${DEPS_BUILD_DIR}"
fi
# Even if we're using cached dependencies, run CMake and make to
diff --git a/ci/common/submit_coverage.sh b/ci/common/submit_coverage.sh
new file mode 100755
index 0000000000..4e92975d22
--- /dev/null
+++ b/ci/common/submit_coverage.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+# Collect and submit coverage reports.
+#
+# Args:
+# $1: Flag(s) for codecov, separated by comma.
+
+set -ex
+
+# Change to grandparent dir (POSIXly).
+CDPATH='' cd -P -- "$(dirname -- "$0")/../.." || exit
+
+echo "=== running submit_coverage in $PWD: $* ==="
+"$GCOV" --version
+
+# Download/install codecov-bash and gcovr once.
+codecov_sh="${TEMP:-/tmp}/codecov.bash"
+if ! [ -f "$codecov_sh" ]; then
+ curl --retry 5 --silent --fail -o "$codecov_sh" https://codecov.io/bash
+ chmod +x "$codecov_sh"
+
+ python3 -m pip install --quiet --user gcovr
+fi
+
+(
+ cd build
+ python3 -m gcovr --branches --exclude-unreachable-branches --print-summary -j 2 --exclude '.*/auto/.*' --root .. --delete -o ../coverage.xml --xml
+)
+
+# Upload to codecov.
+# -X gcov: disable gcov, done manually above.
+# -X fix: disable fixing of reports (not necessary, rather slow)
+# -Z: exit non-zero on failure
+# -F: flag(s)
+# NOTE: ignoring flags for now, since this causes timeouts on codecov.io then,
+# which they know about for about a year already...
+# Flags must match pattern ^[\w\,]+$ ("," as separator).
+codecov_flags="$(uname -s),${1}"
+codecov_flags=$(echo "$codecov_flags" | sed 's/[^,_a-zA-Z0-9]/_/g')
+if ! "$codecov_sh" -f coverage.xml -X gcov -X fix -Z -F "${codecov_flags}"; then
+ echo "codecov upload failed."
+fi
+
+# Cleanup always, especially collected data.
+find . \( -name '*.gcov' -o -name '*.gcda' \) -ls -delete | wc -l
+rm -f coverage.xml
diff --git a/ci/common/suite.sh b/ci/common/suite.sh
index 8feb642547..4c42f06c60 100644
--- a/ci/common/suite.sh
+++ b/ci/common/suite.sh
@@ -39,10 +39,11 @@ enter_suite() {
exit_suite() {
set +x
- travis_fold end "${NVIM_TEST_CURRENT_SUITE}"
if test $FAILED -ne 0 ; then
echo "Suite ${NVIM_TEST_CURRENT_SUITE} failed, summary:"
echo "${FAIL_SUMMARY}"
+ else
+ travis_fold end "${NVIM_TEST_CURRENT_SUITE}"
fi
export NVIM_TEST_CURRENT_SUITE="${NVIM_TEST_CURRENT_SUITE%/*}"
if test "$1" != "--continue" ; then
diff --git a/ci/common/test.sh b/ci/common/test.sh
index f1c5454e3f..fb2dcc077e 100644
--- a/ci/common/test.sh
+++ b/ci/common/test.sh
@@ -3,10 +3,7 @@
submit_coverage() {
if [ -n "${GCOV}" ]; then
- if curl --fail --output codecov.bash --silent https://codecov.io/bash; then
- bash codecov.bash -c -F "$1" || echo "codecov upload failed."
- rm -f codecov.bash
- fi
+ "${CI_DIR}/common/submit_coverage.sh" "$@" || echo 'codecov upload failed.'
fi
}
@@ -32,11 +29,12 @@ check_core_dumps() {
shift
fi
local app="${1:-${BUILD_DIR}/bin/nvim}"
+ local cores
if test "${TRAVIS_OS_NAME}" = osx ; then
- local cores="$(find /cores/ -type f -print)"
+ cores="$(find /cores/ -type f -print)"
local _sudo='sudo'
else
- local cores="$(find ./ -type f -name 'core.*' -print)"
+ cores="$(find ./ -type f -name 'core.*' -print)"
local _sudo=
fi
@@ -71,6 +69,7 @@ check_logs() {
for log in $(find "${1}" -type f -name "${2}" -size +0); do
cat "${log}"
err=1
+ rm "${log}"
done
if test -n "${err}" ; then
fail 'logs' E 'Runtime errors detected.'
@@ -83,7 +82,7 @@ valgrind_check() {
asan_check() {
if test "${CLANG_SANITIZER}" = "ASAN_UBSAN" ; then
- check_logs "${1}" "*san.*" | $ASAN_SYMBOLIZE
+ check_logs "${1}" "*san.*"
fi
}
@@ -94,7 +93,7 @@ run_unittests() {(
fail 'unittests' F 'Unit tests failed'
fi
submit_coverage unittest
- check_core_dumps "$(which luajit)"
+ check_core_dumps "$(command -v luajit)"
exit_suite
)}
diff --git a/ci/install.sh b/ci/install.sh
index 12985098cd..134eb7968d 100755
--- a/ci/install.sh
+++ b/ci/install.sh
@@ -4,6 +4,7 @@ set -e
set -o pipefail
if [[ "${CI_TARGET}" == lint ]]; then
+ python -m pip -q install --user --upgrade flake8
exit
fi
@@ -11,18 +12,11 @@ if [[ "${TRAVIS_OS_NAME}" == osx ]]; then
export PATH="/usr/local/opt/ccache/libexec:$PATH"
fi
+# Use default CC to avoid compilation problems when installing Python modules.
echo "Install neovim module for Python 3."
-# Allow failure. pyenv pip3 on travis is broken:
-# https://github.com/travis-ci/travis-ci/issues/8363
-CC=cc python3 -m pip -q install --user --upgrade neovim || true
-
-if ! [ "${TRAVIS_OS_NAME}" = osx ] ; then
- # Update PATH for pip.
- export PATH="$(python2.7 -c 'import site; print(site.getuserbase())')/bin:$PATH"
- # Use default CC to avoid compilation problems when installing Python modules.
- echo "Install neovim module for Python 2."
- CC=cc python2.7 -m pip -q install --user --upgrade neovim
-fi
+CC=cc python3 -m pip -q install --user --upgrade pynvim
+echo "Install neovim module for Python 2."
+CC=cc python2 -m pip -q install --user --upgrade pynvim
echo "Install neovim RubyGem."
gem install --no-document --version ">= 0.8.0" neovim
diff --git a/ci/run_lint.sh b/ci/run_lint.sh
index ae9adb7c87..88af163e80 100755
--- a/ci/run_lint.sh
+++ b/ci/run_lint.sh
@@ -9,32 +9,24 @@ source "${CI_DIR}/common/build.sh"
source "${CI_DIR}/common/suite.sh"
enter_suite 'clint'
-
run_test 'make clint-full' clint
-
-exit_suite --continue
-
-enter_suite 'testlint'
-
-run_test 'make testlint' testlint
-
exit_suite --continue
enter_suite 'lualint'
-
run_test 'make lualint' lualint
+exit_suite --continue
+enter_suite 'pylint'
+run_test 'make pylint' pylint
exit_suite --continue
enter_suite single-includes
-
CLICOLOR_FORCE=1 run_test_wd \
--allow-hang \
10s \
'make check-single-includes' \
'csi_clean' \
single-includes
-
exit_suite --continue
end_tests
diff --git a/ci/script.sh b/ci/script.sh
index a59c40cd2d..c8025ce34d 100755
--- a/ci/script.sh
+++ b/ci/script.sh
@@ -11,3 +11,9 @@ if [[ "${TRAVIS_OS_NAME}" == osx ]]; then
else
ci/run_${CI_TARGET}.sh
fi
+
+if [[ -s "${GCOV_ERROR_FILE}" ]]; then
+ echo '=== Unexpected gcov errors: ==='
+ cat "${GCOV_ERROR_FILE}"
+ exit 1
+fi
diff --git a/cmake/FindLibIntl.cmake b/cmake/FindLibIntl.cmake
index 738ae39983..5663098147 100644
--- a/cmake/FindLibIntl.cmake
+++ b/cmake/FindLibIntl.cmake
@@ -31,15 +31,13 @@ find_library(LibIntl_LIBRARY
)
if (LibIntl_INCLUDE_DIR)
- set(CMAKE_REQUIRED_INCLUDES "${LibIntl_INCLUDE_DIR}")
+ list(APPEND CMAKE_REQUIRED_INCLUDES "${LibIntl_INCLUDE_DIR}")
endif()
-
# On some systems (linux+glibc) libintl is passively available.
# So only specify the library if one was found.
if (LibIntl_LIBRARY)
- set(CMAKE_REQUIRED_LIBRARIES "${LibIntl_LIBRARY}")
+ list(APPEND CMAKE_REQUIRED_LIBRARIES "${LibIntl_LIBRARY}")
endif()
-
check_c_source_compiles("
#include <libintl.h>
@@ -50,6 +48,12 @@ int main(int argc, char** argv) {
bind_textdomain_codeset(\"foo\", \"bar\");
textdomain(\"foo\");
}" HAVE_WORKING_LIBINTL)
+if (LibIntl_INCLUDE_DIR)
+ list(REMOVE_ITEM CMAKE_REQUIRED_INCLUDES "${LibIntl_INCLUDE_DIR}")
+endif()
+if (LibIntl_LIBRARY)
+ list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES "${LibIntl_LIBRARY}")
+endif()
if (HAVE_WORKING_LIBINTL)
# On some systems (linux+glibc) libintl is passively available.
@@ -58,6 +62,7 @@ if (HAVE_WORKING_LIBINTL)
if(LibIntl_FIND_REQUIRED)
unset(LibIntl_FIND_REQUIRED)
endif()
+ set(LibIntl_FIND_QUIETLY ON)
check_variable_exists(_nl_msg_cat_cntr HAVE_NL_MSG_CAT_CNTR)
endif()
diff --git a/cmake/FindLibLUV.cmake b/cmake/FindLibLUV.cmake
new file mode 100644
index 0000000000..784e3fd249
--- /dev/null
+++ b/cmake/FindLibLUV.cmake
@@ -0,0 +1,31 @@
+# - Try to find luv
+# Once done this will define
+# LIBLUV_FOUND - System has libluv
+# LIBLUV_INCLUDE_DIRS - The libluv include directories
+# LIBLUV_LIBRARIES - The libraries needed to use libluv
+
+find_package(PkgConfig)
+if (PKG_CONFIG_FOUND)
+ pkg_check_modules(PC_LIBLUV QUIET luv)
+endif()
+
+set(LIBLUV_DEFINITIONS ${PC_LIBLUV_CFLAGS_OTHER})
+
+find_path(LIBLUV_INCLUDE_DIR luv/luv.h
+ PATHS ${PC_LIBLUV_INCLUDEDIR} ${PC_LIBLUV_INCLUDE_DIRS})
+
+list(APPEND LIBLUV_NAMES luv)
+
+find_library(LIBLUV_LIBRARY NAMES ${LIBLUV_NAMES}
+ HINTS ${PC_LIBLUV_LIBDIR} ${PC_LIBLUV_LIBRARY_DIRS})
+
+set(LIBLUV_LIBRARIES ${LIBLUV_LIBRARY})
+set(LIBLUV_INCLUDE_DIRS ${LIBLUV_INCLUDE_DIR})
+
+include(FindPackageHandleStandardArgs)
+# handle the QUIETLY and REQUIRED arguments and set LIBLUV_FOUND to TRUE
+# if all listed variables are TRUE
+find_package_handle_standard_args(LibLUV DEFAULT_MSG
+ LIBLUV_LIBRARY LIBLUV_INCLUDE_DIR)
+
+mark_as_advanced(LIBLUV_INCLUDE_DIR LIBLUV_LIBRARY)
diff --git a/cmake/FindLibTermkey.cmake b/cmake/FindLibTermkey.cmake
index 66fd2e6c89..3e0c7f1bfd 100644
--- a/cmake/FindLibTermkey.cmake
+++ b/cmake/FindLibTermkey.cmake
@@ -4,36 +4,20 @@
# LIBTERMKEY_INCLUDE_DIRS - The libtermkey include directories
# LIBTERMKEY_LIBRARIES - The libraries needed to use libtermkey
-if(NOT USE_BUNDLED_LIBTERMKEY)
- find_package(PkgConfig)
- if (PKG_CONFIG_FOUND)
- pkg_check_modules(PC_LIBTERMKEY QUIET termkey)
- endif()
-else()
- set(PC_LIBTERMKEY_INCLUDEDIR)
- set(PC_LIBTERMKEY_INCLUDE_DIRS)
- set(PC_LIBTERMKEY_LIBDIR)
- set(PC_LIBTERMKEY_LIBRARY_DIRS)
- set(LIMIT_SEARCH NO_DEFAULT_PATH)
+find_package(PkgConfig)
+if (PKG_CONFIG_FOUND)
+ pkg_check_modules(PC_LIBTERMKEY QUIET termkey)
endif()
set(LIBTERMKEY_DEFINITIONS ${PC_LIBTERMKEY_CFLAGS_OTHER})
find_path(LIBTERMKEY_INCLUDE_DIR termkey.h
- PATHS ${PC_LIBTERMKEY_INCLUDEDIR} ${PC_LIBTERMKEY_INCLUDE_DIRS}
- ${LIMIT_SEARCH})
-
-# If we're asked to use static linkage, add libuv.a as a preferred library name.
-if(LIBTERMKEY_USE_STATIC)
- list(APPEND LIBTERMKEY_NAMES
- "${CMAKE_STATIC_LIBRARY_PREFIX}termkey${CMAKE_STATIC_LIBRARY_SUFFIX}")
-endif()
+ PATHS ${PC_LIBTERMKEY_INCLUDEDIR} ${PC_LIBTERMKEY_INCLUDE_DIRS})
list(APPEND LIBTERMKEY_NAMES termkey)
find_library(LIBTERMKEY_LIBRARY NAMES ${LIBTERMKEY_NAMES}
- HINTS ${PC_LIBTERMKEY_LIBDIR} ${PC_LIBTERMKEY_LIBRARY_DIRS}
- ${LIMIT_SEARCH})
+ HINTS ${PC_LIBTERMKEY_LIBDIR} ${PC_LIBTERMKEY_LIBRARY_DIRS})
set(LIBTERMKEY_LIBRARIES ${LIBTERMKEY_LIBRARY})
set(LIBTERMKEY_INCLUDE_DIRS ${LIBTERMKEY_INCLUDE_DIR})
diff --git a/cmake/FindLibUV.cmake b/cmake/FindLibUV.cmake
index 29eaf15b8e..951fb0435e 100644
--- a/cmake/FindLibUV.cmake
+++ b/cmake/FindLibUV.cmake
@@ -4,38 +4,19 @@
# LIBUV_FOUND - system has libuv
# LIBUV_INCLUDE_DIRS - the libuv include directories
# LIBUV_LIBRARIES - link these to use libuv
-#
-# Set the LIBUV_USE_STATIC variable to specify if static libraries should
-# be preferred to shared ones.
-
-if(NOT USE_BUNDLED_LIBUV)
- find_package(PkgConfig)
- if (PKG_CONFIG_FOUND)
- pkg_check_modules(PC_LIBUV QUIET libuv)
- endif()
-else()
- set(PC_LIBUV_INCLUDEDIR)
- set(PC_LIBUV_INCLUDE_DIRS)
- set(PC_LIBUV_LIBDIR)
- set(PC_LIBUV_LIBRARY_DIRS)
- set(LIMIT_SEARCH NO_DEFAULT_PATH)
+
+find_package(PkgConfig)
+if (PKG_CONFIG_FOUND)
+ pkg_check_modules(PC_LIBUV QUIET libuv)
endif()
find_path(LIBUV_INCLUDE_DIR uv.h
- HINTS ${PC_LIBUV_INCLUDEDIR} ${PC_LIBUV_INCLUDE_DIRS}
- ${LIMIT_SEARCH})
-
-# If we're asked to use static linkage, add libuv.a as a preferred library name.
-if(LIBUV_USE_STATIC)
- list(APPEND LIBUV_NAMES
- "${CMAKE_STATIC_LIBRARY_PREFIX}uv${CMAKE_STATIC_LIBRARY_SUFFIX}")
-endif(LIBUV_USE_STATIC)
+ HINTS ${PC_LIBUV_INCLUDEDIR} ${PC_LIBUV_INCLUDE_DIRS})
list(APPEND LIBUV_NAMES uv)
find_library(LIBUV_LIBRARY NAMES ${LIBUV_NAMES}
- HINTS ${PC_LIBUV_LIBDIR} ${PC_LIBUV_LIBRARY_DIRS}
- ${LIMIT_SEARCH})
+ HINTS ${PC_LIBUV_LIBDIR} ${PC_LIBUV_LIBRARY_DIRS})
mark_as_advanced(LIBUV_INCLUDE_DIR LIBUV_LIBRARY)
diff --git a/cmake/FindLibVterm.cmake b/cmake/FindLibVterm.cmake
index 2cbd3215c5..469494ddfd 100644
--- a/cmake/FindLibVterm.cmake
+++ b/cmake/FindLibVterm.cmake
@@ -4,44 +4,7 @@
# LIBVTERM_INCLUDE_DIRS - The libvterm include directories
# LIBVTERM_LIBRARIES - The libraries needed to use libvterm
-if(NOT USE_BUNDLED_LIBVTERM)
- find_package(PkgConfig)
- if (PKG_CONFIG_FOUND)
- pkg_check_modules(PC_LIBVTERM QUIET vterm)
- endif()
-else()
- set(PC_LIBVTERM_INCLUDEDIR)
- set(PC_LIBVTERM_INCLUDE_DIRS)
- set(PC_LIBVTERM_LIBDIR)
- set(PC_LIBVTERM_LIBRARY_DIRS)
- set(LIMIT_SEARCH NO_DEFAULT_PATH)
-endif()
+include(LibFindMacros)
-set(LIBVTERM_DEFINITIONS ${PC_LIBVTERM_CFLAGS_OTHER})
-
-find_path(LIBVTERM_INCLUDE_DIR vterm.h
- PATHS ${PC_LIBVTERM_INCLUDEDIR} ${PC_LIBVTERM_INCLUDE_DIRS}
- ${LIMIT_SEARCH})
-
-# If we're asked to use static linkage, add libuv.a as a preferred library name.
-if(LIBVTERM_USE_STATIC)
- list(APPEND LIBVTERM_NAMES
- "${CMAKE_STATIC_LIBRARY_PREFIX}vterm${CMAKE_STATIC_LIBRARY_SUFFIX}")
-endif()
-
-list(APPEND LIBVTERM_NAMES vterm)
-
-find_library(LIBVTERM_LIBRARY NAMES ${LIBVTERM_NAMES}
- HINTS ${PC_LIBVTERM_LIBDIR} ${PC_LIBVTERM_LIBRARY_DIRS}
- ${LIMIT_SEARCH})
-
-set(LIBVTERM_LIBRARIES ${LIBVTERM_LIBRARY})
-set(LIBVTERM_INCLUDE_DIRS ${LIBVTERM_INCLUDE_DIR})
-
-include(FindPackageHandleStandardArgs)
-# handle the QUIETLY and REQUIRED arguments and set LIBVTERM_FOUND to TRUE
-# if all listed variables are TRUE
-find_package_handle_standard_args(LibVterm DEFAULT_MSG
- LIBVTERM_LIBRARY LIBVTERM_INCLUDE_DIR)
-
-mark_as_advanced(LIBVTERM_INCLUDE_DIR LIBVTERM_LIBRARY)
+libfind_pkg_detect(LIBVTERM vterm FIND_PATH vterm.h FIND_LIBRARY vterm)
+libfind_process(LIBVTERM REQUIRED)
diff --git a/cmake/FindLuaJit.cmake b/cmake/FindLuaJit.cmake
index b8eda6388b..72795afefd 100644
--- a/cmake/FindLuaJit.cmake
+++ b/cmake/FindLuaJit.cmake
@@ -4,32 +4,16 @@
# LUAJIT_INCLUDE_DIRS - The luajit include directories
# LUAJIT_LIBRARIES - The libraries needed to use luajit
-if(NOT USE_BUNDLED_LUAJIT)
- find_package(PkgConfig)
- if (PKG_CONFIG_FOUND)
- pkg_check_modules(PC_LUAJIT QUIET luajit)
- endif()
-else()
- set(PC_LUAJIT_INCLUDEDIR)
- set(PC_LUAJIT_INCLUDE_DIRS)
- set(PC_LUAJIT_LIBDIR)
- set(PC_LUAJIT_LIBRARY_DIRS)
- set(LIMIT_SEARCH NO_DEFAULT_PATH)
+find_package(PkgConfig)
+if (PKG_CONFIG_FOUND)
+ pkg_check_modules(PC_LUAJIT QUIET luajit)
endif()
set(LUAJIT_DEFINITIONS ${PC_LUAJIT_CFLAGS_OTHER})
find_path(LUAJIT_INCLUDE_DIR luajit.h
PATHS ${PC_LUAJIT_INCLUDEDIR} ${PC_LUAJIT_INCLUDE_DIRS}
- PATH_SUFFIXES luajit-2.0
- ${LIMIT_SEARCH})
-
-# If we're asked to use static linkage, add libluajit-5.1.a as a preferred
-# library name.
-if(LUAJIT_USE_STATIC)
- list(APPEND LUAJIT_NAMES
- "${CMAKE_STATIC_LIBRARY_PREFIX}luajit-5.1${CMAKE_STATIC_LIBRARY_SUFFIX}")
-endif()
+ PATH_SUFFIXES luajit-2.0 luajit-2.1)
if(MSVC)
list(APPEND LUAJIT_NAMES lua51)
@@ -40,8 +24,7 @@ else()
endif()
find_library(LUAJIT_LIBRARY NAMES ${LUAJIT_NAMES}
- PATHS ${PC_LUAJIT_LIBDIR} ${PC_LUAJIT_LIBRARY_DIRS}
- ${LIMIT_SEARCH})
+ PATHS ${PC_LUAJIT_LIBDIR} ${PC_LUAJIT_LIBRARY_DIRS})
set(LUAJIT_LIBRARIES ${LUAJIT_LIBRARY})
set(LUAJIT_INCLUDE_DIRS ${LUAJIT_INCLUDE_DIR})
diff --git a/cmake/FindMsgpack.cmake b/cmake/FindMsgpack.cmake
index cca0a00c20..26eb19d498 100644
--- a/cmake/FindMsgpack.cmake
+++ b/cmake/FindMsgpack.cmake
@@ -4,26 +4,17 @@
# MSGPACK_INCLUDE_DIRS - The msgpack include directories
# MSGPACK_LIBRARIES - The libraries needed to use msgpack
-if(NOT USE_BUNDLED_MSGPACK)
- find_package(PkgConfig)
- if (PKG_CONFIG_FOUND)
- pkg_search_module(PC_MSGPACK QUIET
- msgpackc>=${Msgpack_FIND_VERSION}
- msgpack>=${Msgpack_FIND_VERSION})
- endif()
-else()
- set(PC_MSGPACK_INCLUDEDIR)
- set(PC_MSGPACK_INCLUDE_DIRS)
- set(PC_MSGPACK_LIBDIR)
- set(PC_MSGPACK_LIBRARY_DIRS)
- set(LIMIT_SEARCH NO_DEFAULT_PATH)
+find_package(PkgConfig)
+if (PKG_CONFIG_FOUND)
+ pkg_search_module(PC_MSGPACK QUIET
+ msgpackc>=${Msgpack_FIND_VERSION}
+ msgpack>=${Msgpack_FIND_VERSION})
endif()
set(MSGPACK_DEFINITIONS ${PC_MSGPACK_CFLAGS_OTHER})
find_path(MSGPACK_INCLUDE_DIR msgpack/version_master.h
- HINTS ${PC_MSGPACK_INCLUDEDIR} ${PC_MSGPACK_INCLUDE_DIRS}
- ${LIMIT_SEARCH})
+ HINTS ${PC_MSGPACK_INCLUDEDIR} ${PC_MSGPACK_INCLUDE_DIRS})
if(MSGPACK_INCLUDE_DIR)
file(READ ${MSGPACK_INCLUDE_DIR}/msgpack/version_master.h msgpack_version_h)
@@ -35,13 +26,6 @@ else()
set(MSGPACK_VERSION_STRING)
endif()
-# If we're asked to use static linkage, add libmsgpack{,c}.a as a preferred library name.
-if(MSGPACK_USE_STATIC)
- list(APPEND MSGPACK_NAMES
- "${CMAKE_STATIC_LIBRARY_PREFIX}msgpackc${CMAKE_STATIC_LIBRARY_SUFFIX}"
- "${CMAKE_STATIC_LIBRARY_PREFIX}msgpack${CMAKE_STATIC_LIBRARY_SUFFIX}")
-endif()
-
if(MSVC)
# The import library for the msgpack DLL has a different name
list(APPEND MSGPACK_NAMES msgpackc_import)
@@ -53,8 +37,7 @@ find_library(MSGPACK_LIBRARY NAMES ${MSGPACK_NAMES}
# Check each directory for all names to avoid using headers/libraries from
# different places.
NAMES_PER_DIR
- HINTS ${PC_MSGPACK_LIBDIR} ${PC_MSGPACK_LIBRARY_DIRS}
- ${LIMIT_SEARCH})
+ HINTS ${PC_MSGPACK_LIBDIR} ${PC_MSGPACK_LIBRARY_DIRS})
mark_as_advanced(MSGPACK_INCLUDE_DIR MSGPACK_LIBRARY)
diff --git a/cmake/FindUnibilium.cmake b/cmake/FindUnibilium.cmake
index cf0ccda877..0bf27b45e2 100644
--- a/cmake/FindUnibilium.cmake
+++ b/cmake/FindUnibilium.cmake
@@ -4,44 +4,9 @@
# UNIBILIUM_INCLUDE_DIRS - The unibilium include directories
# UNIBILIUM_LIBRARIES - The libraries needed to use unibilium
-if(NOT USE_BUNDLED_UNIBILIUM)
- find_package(PkgConfig)
- if (PKG_CONFIG_FOUND)
- pkg_check_modules(PC_UNIBILIUM QUIET unibilium)
- endif()
-else()
- set(PC_UNIBILIUM_INCLUDEDIR)
- set(PC_UNIBILIUM_INCLUDE_DIRS)
- set(PC_UNIBILIUM_LIBDIR)
- set(PC_UNIBILIUM_LIBRARY_DIRS)
- set(LIMIT_SEARCH NO_DEFAULT_PATH)
-endif()
+include(LibFindMacros)
-set(UNIBILIUM_DEFINITIONS ${PC_UNIBILIUM_CFLAGS_OTHER})
-
-find_path(UNIBILIUM_INCLUDE_DIR unibilium.h
- PATHS ${PC_UNIBILIUM_INCLUDEDIR} ${PC_UNIBILIUM_INCLUDE_DIRS}
- ${LIMIT_SEARCH})
-
-# If we're asked to use static linkage, add libunibilium.a as a preferred library name.
-if(UNIBILIUM_USE_STATIC)
- list(APPEND UNIBILIUM_NAMES
- "${CMAKE_STATIC_LIBRARY_PREFIX}unibilium${CMAKE_STATIC_LIBRARY_SUFFIX}")
-endif()
-
-list(APPEND UNIBILIUM_NAMES unibilium)
-
-find_library(UNIBILIUM_LIBRARY NAMES ${UNIBILIUM_NAMES}
- HINTS ${PC_UNIBILIUM_LIBDIR} ${PC_UNIBILIUM_LIBRARY_DIRS}
- ${LIMIT_SEARCH})
-
-set(UNIBILIUM_LIBRARIES ${UNIBILIUM_LIBRARY})
-set(UNIBILIUM_INCLUDE_DIRS ${UNIBILIUM_INCLUDE_DIR})
-
-include(FindPackageHandleStandardArgs)
-# handle the QUIETLY and REQUIRED arguments and set UNIBILIUM_FOUND to TRUE
-# if all listed variables are TRUE
-find_package_handle_standard_args(unibilium DEFAULT_MSG
- UNIBILIUM_LIBRARY UNIBILIUM_INCLUDE_DIR)
-
-mark_as_advanced(UNIBILIUM_INCLUDE_DIR UNIBILIUM_LIBRARY)
+libfind_pkg_detect(UNIBILIUM unibilium
+ FIND_PATH unibilium.h
+ FIND_LIBRARY unibilium)
+libfind_process(UNIBILIUM)
diff --git a/cmake/GetCompileFlags.cmake b/cmake/GetCompileFlags.cmake
index 527bc88cdd..482eacca16 100644
--- a/cmake/GetCompileFlags.cmake
+++ b/cmake/GetCompileFlags.cmake
@@ -1,6 +1,6 @@
function(get_compile_flags _compile_flags)
# Create template akin to CMAKE_C_COMPILE_OBJECT.
- set(compile_flags "<CMAKE_C_COMPILER> <CFLAGS> <BUILD_TYPE_CFLAGS> <DEFINITIONS> <INCLUDES>")
+ set(compile_flags "<CMAKE_C_COMPILER> <CFLAGS> <BUILD_TYPE_CFLAGS> <COMPILE_OPTIONS><COMPILE_DEFINITIONS> <INCLUDES>")
# Get C compiler.
string(REPLACE
@@ -9,13 +9,30 @@ function(get_compile_flags _compile_flags)
compile_flags
"${compile_flags}")
- # Get flags set by add_definition().
- get_directory_property(definitions
+ # Get flags set by add_definitions().
+ get_directory_property(compile_definitions
DIRECTORY "src/nvim"
- DEFINITIONS)
+ COMPILE_DEFINITIONS)
+ # NOTE: list(JOIN) requires CMake 3.12, string(CONCAT) requires CMake 3.
+ string(REPLACE ";" " -D" compile_definitions "${compile_definitions}")
+ if(compile_definitions)
+ set(compile_definitions " -D${compile_definitions}")
+ endif()
string(REPLACE
- "<DEFINITIONS>"
- "${definitions}"
+ "<COMPILE_DEFINITIONS>"
+ "${compile_definitions}"
+ compile_flags
+ "${compile_flags}")
+
+ # Get flags set by add_compile_options().
+ get_directory_property(compile_options
+ DIRECTORY "src/nvim"
+ COMPILE_OPTIONS)
+ # NOTE: list(JOIN) requires CMake 3.12.
+ string(REPLACE ";" " " compile_options "${compile_options}")
+ string(REPLACE
+ "<COMPILE_OPTIONS>"
+ "${compile_options}"
compile_flags
"${compile_flags}")
diff --git a/cmake/LibFindMacros.cmake b/cmake/LibFindMacros.cmake
index aa2143c82d..726a8631f0 100644
--- a/cmake/LibFindMacros.cmake
+++ b/cmake/LibFindMacros.cmake
@@ -1,46 +1,101 @@
-# Version 1.0 (2013-04-12)
-# Public Domain, originally written by Lasse Kärkkäinen <tronic@zi.fi>
-# Published at http://www.cmake.org/Wiki/CMake:How_To_Find_Libraries
-
-# If you improve the script, please modify the forementioned wiki page because
-# I no longer maintain my scripts (hosted as static files at zi.fi). Feel free
-# to remove this entire header if you use real version control instead.
-
-# Changelog:
-# 2013-04-12 Added version number (1.0) and this header, no other changes
-# 2009-10-08 Originally published
-
-
-# Works the same as find_package, but forwards the "REQUIRED" and "QUIET" arguments
-# used for the current package. For this to work, the first parameter must be the
-# prefix of the current package, then the prefix of the new package etc, which are
-# passed to find_package.
-macro (libfind_package PREFIX)
- set (LIBFIND_PACKAGE_ARGS ${ARGN})
- if (${PREFIX}_FIND_QUIETLY)
- set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} QUIET)
- endif (${PREFIX}_FIND_QUIETLY)
+# Version 2.2
+# Public Domain, originally written by Lasse Kärkkäinen <tronic>
+# Maintained at https://github.com/Tronic/cmake-modules
+# Please send your improvements as pull requests on Github.
+
+# Find another package and make it a dependency of the current package.
+# This also automatically forwards the "REQUIRED" argument.
+# Usage: libfind_package(<prefix> <another package> [extra args to find_package])
+macro (libfind_package PREFIX PKG)
+ set(${PREFIX}_args ${PKG} ${ARGN})
if (${PREFIX}_FIND_REQUIRED)
- set (LIBFIND_PACKAGE_ARGS ${LIBFIND_PACKAGE_ARGS} REQUIRED)
- endif (${PREFIX}_FIND_REQUIRED)
- find_package(${LIBFIND_PACKAGE_ARGS})
-endmacro (libfind_package)
-
-# CMake developers made the UsePkgConfig system deprecated in the same release (2.6)
-# where they added pkg_check_modules. Consequently I need to support both in my scripts
-# to avoid those deprecated warnings. Here's a helper that does just that.
-# Works identically to pkg_check_modules, except that no checks are needed prior to use.
-macro (libfind_pkg_check_modules PREFIX PKGNAME)
- if (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
- include(UsePkgConfig)
- pkgconfig(${PKGNAME} ${PREFIX}_INCLUDE_DIRS ${PREFIX}_LIBRARY_DIRS ${PREFIX}_LDFLAGS ${PREFIX}_CFLAGS)
- else (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
- find_package(PkgConfig)
- if (PKG_CONFIG_FOUND)
- pkg_check_modules(${PREFIX} ${PKGNAME})
- endif (PKG_CONFIG_FOUND)
- endif (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
-endmacro (libfind_pkg_check_modules)
+ set(${PREFIX}_args ${${PREFIX}_args} REQUIRED)
+ endif()
+ find_package(${${PREFIX}_args})
+ set(${PREFIX}_DEPENDENCIES ${${PREFIX}_DEPENDENCIES};${PKG})
+ unset(${PREFIX}_args)
+endmacro()
+
+# A simple wrapper to make pkg-config searches a bit easier.
+# Works the same as CMake's internal pkg_check_modules but is always quiet.
+macro (libfind_pkg_check_modules)
+ find_package(PkgConfig QUIET)
+ if (PKG_CONFIG_FOUND)
+ pkg_check_modules(${ARGN} QUIET)
+ endif()
+endmacro()
+
+# Avoid useless copy&pasta by doing what most simple libraries do anyway:
+# pkg-config, find headers, find library.
+# Usage: libfind_pkg_detect(<prefix> <pkg-config args> FIND_PATH <name> [other args] FIND_LIBRARY <name> [other args])
+# E.g. libfind_pkg_detect(SDL2 sdl2 FIND_PATH SDL.h PATH_SUFFIXES SDL2 FIND_LIBRARY SDL2)
+function (libfind_pkg_detect PREFIX)
+ # Parse arguments
+ set(argname pkgargs)
+ foreach (i ${ARGN})
+ if ("${i}" STREQUAL "FIND_PATH")
+ set(argname pathargs)
+ elseif ("${i}" STREQUAL "FIND_LIBRARY")
+ set(argname libraryargs)
+ else()
+ set(${argname} ${${argname}} ${i})
+ endif()
+ endforeach()
+ if (NOT pkgargs)
+ message(FATAL_ERROR "libfind_pkg_detect requires at least a pkg_config package name to be passed.")
+ endif()
+ # Find library
+ libfind_pkg_check_modules(${PREFIX}_PKGCONF ${pkgargs})
+ if (pathargs)
+ find_path(${PREFIX}_INCLUDE_DIR NAMES ${pathargs} HINTS ${${PREFIX}_PKGCONF_INCLUDE_DIRS})
+ endif()
+ if (libraryargs)
+ find_library(${PREFIX}_LIBRARY NAMES ${libraryargs} HINTS ${${PREFIX}_PKGCONF_LIBRARY_DIRS})
+ endif()
+ # Read pkg-config version
+ if (${PREFIX}_PKGCONF_VERSION)
+ set(${PREFIX}_VERSION ${${PREFIX}_PKGCONF_VERSION} PARENT_SCOPE)
+ endif()
+endfunction()
+
+# Extracts a version #define from a version.h file, output stored to <PREFIX>_VERSION.
+# Usage: libfind_version_header(Foobar foobar/version.h FOOBAR_VERSION_STR)
+# Fourth argument "QUIET" may be used for silently testing different define names.
+# This function does nothing if the version variable is already defined.
+function (libfind_version_header PREFIX VERSION_H DEFINE_NAME)
+ # Skip processing if we already have a version or if the include dir was not found
+ if (${PREFIX}_VERSION OR NOT ${PREFIX}_INCLUDE_DIR)
+ return()
+ endif()
+ set(quiet ${${PREFIX}_FIND_QUIETLY})
+ # Process optional arguments
+ foreach(arg ${ARGN})
+ if (arg STREQUAL "QUIET")
+ set(quiet TRUE)
+ else()
+ message(AUTHOR_WARNING "Unknown argument ${arg} to libfind_version_header ignored.")
+ endif()
+ endforeach()
+ # Read the header and parse for version number
+ set(filename "${${PREFIX}_INCLUDE_DIR}/${VERSION_H}")
+ if (NOT EXISTS ${filename})
+ if (NOT quiet)
+ message(AUTHOR_WARNING "Unable to find ${${PREFIX}_INCLUDE_DIR}/${VERSION_H}")
+ endif()
+ return()
+ endif()
+ file(READ "${filename}" header)
+ string(REGEX REPLACE ".*#[ \t]*define[ \t]*${DEFINE_NAME}[ \t]*\"([^\n]*)\".*" "\\1" match "${header}")
+ # No regex match?
+ if (match STREQUAL header)
+ if (NOT quiet)
+ message(AUTHOR_WARNING "Unable to find \#define ${DEFINE_NAME} \"<version>\" from ${${PREFIX}_INCLUDE_DIR}/${VERSION_H}")
+ endif()
+ return()
+ endif()
+ # Export the version string
+ set(${PREFIX}_VERSION "${match}" PARENT_SCOPE)
+endfunction()
# Do the final processing once the paths have been detected.
# If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain
@@ -48,65 +103,167 @@ endmacro (libfind_pkg_check_modules)
# Ditto for ${PREFIX}_PROCESS_LIBS and library files.
# Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES.
# Also handles errors in case library detection was required, etc.
-macro (libfind_process PREFIX)
- # Skip processing if already processed during this run
- if (NOT ${PREFIX}_FOUND)
- # Start with the assumption that the library was found
- set (${PREFIX}_FOUND TRUE)
-
- # Process all includes and set _FOUND to false if any are missing
- foreach (i ${${PREFIX}_PROCESS_INCLUDES})
- if (${i})
- set (${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIRS} ${${i}})
- mark_as_advanced(${i})
- else (${i})
- set (${PREFIX}_FOUND FALSE)
- endif (${i})
- endforeach (i)
-
- # Process all libraries and set _FOUND to false if any are missing
- foreach (i ${${PREFIX}_PROCESS_LIBS})
- if (${i})
- set (${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARIES} ${${i}})
- mark_as_advanced(${i})
- else (${i})
- set (${PREFIX}_FOUND FALSE)
- endif (${i})
- endforeach (i)
-
- # Print message and/or exit on fatal error
- if (${PREFIX}_FOUND)
- if (NOT ${PREFIX}_FIND_QUIETLY)
- message (STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}")
- endif (NOT ${PREFIX}_FIND_QUIETLY)
- else (${PREFIX}_FOUND)
- if (${PREFIX}_FIND_REQUIRED)
- foreach (i ${${PREFIX}_PROCESS_INCLUDES} ${${PREFIX}_PROCESS_LIBS})
- message("${i}=${${i}}")
- endforeach (i)
- message (FATAL_ERROR "Required library ${PREFIX} NOT FOUND.\nInstall the library (dev version) and try again. If the library is already installed, use ccmake to set the missing variables manually.")
- endif (${PREFIX}_FIND_REQUIRED)
- endif (${PREFIX}_FOUND)
- endif (NOT ${PREFIX}_FOUND)
-endmacro (libfind_process)
-
-macro(libfind_library PREFIX basename)
- set(TMP "")
- if(MSVC80)
- set(TMP -vc80)
- endif(MSVC80)
- if(MSVC90)
- set(TMP -vc90)
- endif(MSVC90)
- set(${PREFIX}_LIBNAMES ${basename}${TMP})
- if(${ARGC} GREATER 2)
- set(${PREFIX}_LIBNAMES ${basename}${TMP}-${ARGV2})
- string(REGEX REPLACE "\\." "_" TMP ${${PREFIX}_LIBNAMES})
- set(${PREFIX}_LIBNAMES ${${PREFIX}_LIBNAMES} ${TMP})
- endif(${ARGC} GREATER 2)
- find_library(${PREFIX}_LIBRARY
- NAMES ${${PREFIX}_LIBNAMES}
- PATHS ${${PREFIX}_PKGCONF_LIBRARY_DIRS}
- )
-endmacro(libfind_library)
+function (libfind_process PREFIX)
+ # Skip processing if already processed during this configuration run
+ if (${PREFIX}_FOUND)
+ return()
+ endif()
+
+ set(found TRUE) # Start with the assumption that the package was found
+
+ # Did we find any files? Did we miss includes? These are for formatting better error messages.
+ set(some_files FALSE)
+ set(missing_headers FALSE)
+
+ # Shorthands for some variables that we need often
+ set(quiet ${${PREFIX}_FIND_QUIETLY})
+ set(required ${${PREFIX}_FIND_REQUIRED})
+ set(exactver ${${PREFIX}_FIND_VERSION_EXACT})
+ set(findver "${${PREFIX}_FIND_VERSION}")
+ set(version "${${PREFIX}_VERSION}")
+
+ # Lists of config option names (all, includes, libs)
+ unset(configopts)
+ set(includeopts ${${PREFIX}_PROCESS_INCLUDES})
+ set(libraryopts ${${PREFIX}_PROCESS_LIBS})
+
+ # Process deps to add to
+ foreach (i ${PREFIX} ${${PREFIX}_DEPENDENCIES})
+ if (DEFINED ${i}_INCLUDE_OPTS OR DEFINED ${i}_LIBRARY_OPTS)
+ # The package seems to export option lists that we can use, woohoo!
+ list(APPEND includeopts ${${i}_INCLUDE_OPTS})
+ list(APPEND libraryopts ${${i}_LIBRARY_OPTS})
+ else()
+ # If plural forms don't exist or they equal singular forms
+ if ((NOT DEFINED ${i}_INCLUDE_DIRS AND NOT DEFINED ${i}_LIBRARIES) OR
+ (${i}_INCLUDE_DIR STREQUAL ${i}_INCLUDE_DIRS AND ${i}_LIBRARY STREQUAL ${i}_LIBRARIES))
+ # Singular forms can be used
+ if (DEFINED ${i}_INCLUDE_DIR)
+ list(APPEND includeopts ${i}_INCLUDE_DIR)
+ endif()
+ if (DEFINED ${i}_LIBRARY)
+ list(APPEND libraryopts ${i}_LIBRARY)
+ endif()
+ else()
+ # Oh no, we don't know the option names
+ message(FATAL_ERROR "We couldn't determine config variable names for ${i} includes and libs. Aieeh!")
+ endif()
+ endif()
+ endforeach()
+
+ if (includeopts)
+ list(REMOVE_DUPLICATES includeopts)
+ endif()
+
+ if (libraryopts)
+ list(REMOVE_DUPLICATES libraryopts)
+ endif()
+
+ string(REGEX REPLACE ".*[ ;]([^ ;]*(_INCLUDE_DIRS|_LIBRARIES))" "\\1" tmp "${includeopts} ${libraryopts}")
+ if (NOT tmp STREQUAL "${includeopts} ${libraryopts}")
+ message(AUTHOR_WARNING "Plural form ${tmp} found in config options of ${PREFIX}. This works as before but is now deprecated. Please only use singular forms INCLUDE_DIR and LIBRARY, and update your find scripts for LibFindMacros > 2.0 automatic dependency system (most often you can simply remove the PROCESS variables entirely).")
+ endif()
+
+ # Include/library names separated by spaces (notice: not CMake lists)
+ unset(includes)
+ unset(libs)
+
+ # Process all includes and set found false if any are missing
+ foreach (i ${includeopts})
+ list(APPEND configopts ${i})
+ if (NOT "${${i}}" STREQUAL "${i}-NOTFOUND")
+ list(APPEND includes "${${i}}")
+ else()
+ set(found FALSE)
+ set(missing_headers TRUE)
+ endif()
+ endforeach()
+
+ # Process all libraries and set found false if any are missing
+ foreach (i ${libraryopts})
+ list(APPEND configopts ${i})
+ if (NOT "${${i}}" STREQUAL "${i}-NOTFOUND")
+ list(APPEND libs "${${i}}")
+ else()
+ set (found FALSE)
+ endif()
+ endforeach()
+
+ # Version checks
+ if (found AND findver)
+ if (NOT version)
+ message(WARNING "The find module for ${PREFIX} does not provide version information, so we'll just assume that it is OK. Please fix the module or remove package version requirements to get rid of this warning.")
+ elseif (version VERSION_LESS findver OR (exactver AND NOT version VERSION_EQUAL findver))
+ set(found FALSE)
+ set(version_unsuitable TRUE)
+ endif()
+ endif()
+
+ # If all-OK, hide all config options, export variables, print status and exit
+ if (found)
+ foreach (i ${configopts})
+ mark_as_advanced(${i})
+ endforeach()
+ if (NOT quiet)
+ message(STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}")
+ if (LIBFIND_DEBUG)
+ message(STATUS " ${PREFIX}_DEPENDENCIES=${${PREFIX}_DEPENDENCIES}")
+ message(STATUS " ${PREFIX}_INCLUDE_OPTS=${includeopts}")
+ message(STATUS " ${PREFIX}_INCLUDE_DIRS=${includes}")
+ message(STATUS " ${PREFIX}_LIBRARY_OPTS=${libraryopts}")
+ message(STATUS " ${PREFIX}_LIBRARIES=${libs}")
+ endif()
+ endif()
+ set (${PREFIX}_INCLUDE_OPTS ${includeopts} PARENT_SCOPE)
+ set (${PREFIX}_LIBRARY_OPTS ${libraryopts} PARENT_SCOPE)
+ set (${PREFIX}_INCLUDE_DIRS ${includes} PARENT_SCOPE)
+ set (${PREFIX}_LIBRARIES ${libs} PARENT_SCOPE)
+ set (${PREFIX}_FOUND TRUE PARENT_SCOPE)
+ return()
+ endif()
+
+ # Format messages for debug info and the type of error
+ set(vars "Relevant CMake configuration variables:\n")
+ foreach (i ${configopts})
+ mark_as_advanced(CLEAR ${i})
+ set(val ${${i}})
+ if ("${val}" STREQUAL "${i}-NOTFOUND")
+ set (val "<not found>")
+ elseif (val AND NOT EXISTS ${val})
+ set (val "${val} (does not exist)")
+ else()
+ set(some_files TRUE)
+ endif()
+ set(vars "${vars} ${i}=${val}\n")
+ endforeach()
+ set(vars "${vars}You may use CMake GUI, cmake -D or ccmake to modify the values. Delete CMakeCache.txt to discard all values and force full re-detection if necessary.\n")
+ if (version_unsuitable)
+ set(msg "${PREFIX} ${${PREFIX}_VERSION} was found but")
+ if (exactver)
+ set(msg "${msg} only version ${findver} is acceptable.")
+ else()
+ set(msg "${msg} version ${findver} is the minimum requirement.")
+ endif()
+ else()
+ if (missing_headers)
+ set(msg "We could not find development headers for ${PREFIX}. Do you have the necessary dev package installed?")
+ elseif (some_files)
+ set(msg "We only found some files of ${PREFIX}, not all of them. Perhaps your installation is incomplete or maybe we just didn't look in the right place?")
+ if(findver)
+ set(msg "${msg} This could also be caused by incompatible version (if it helps, at least ${PREFIX} ${findver} should work).")
+ endif()
+ else()
+ set(msg "We were unable to find package ${PREFIX}.")
+ endif()
+ endif()
+ # Fatal error out if REQUIRED
+ if (required)
+ set(msg "REQUIRED PACKAGE NOT FOUND\n${msg} This package is REQUIRED and you need to install it or adjust CMake configuration in order to continue building ${CMAKE_PROJECT_NAME}.")
+ message(FATAL_ERROR "${msg}\n${vars}")
+ endif()
+ # Otherwise just print a nasty warning
+ if (NOT quiet)
+ message(WARNING "WARNING: MISSING PACKAGE\n${msg} This package is NOT REQUIRED and you may ignore this warning but by doing so you may miss some functionality of ${CMAKE_PROJECT_NAME}. \n${vars}")
+ endif()
+endfunction()
diff --git a/cmake/RunLuacheck.cmake b/cmake/RunLuacheck.cmake
deleted file mode 100644
index 4887e562a5..0000000000
--- a/cmake/RunLuacheck.cmake
+++ /dev/null
@@ -1,22 +0,0 @@
-set(LUACHECK_ARGS -q "${LUAFILES_DIR}")
-if(DEFINED IGNORE_PATTERN)
- list(APPEND LUACHECK_ARGS --exclude-files "${LUAFILES_DIR}/${IGNORE_PATTERN}")
-endif()
-if(DEFINED CHECK_PATTERN)
- list(APPEND LUACHECK_ARGS --include-files "${LUAFILES_DIR}/${CHECK_PATTERN}")
-endif()
-if(DEFINED READ_GLOBALS)
- list(APPEND LUACHECK_ARGS --read-globals "${READ_GLOBALS}")
-endif()
-
-execute_process(
- COMMAND "${LUACHECK_PRG}" ${LUACHECK_ARGS}
- WORKING_DIRECTORY "${LUAFILES_DIR}"
- ERROR_VARIABLE err
- RESULT_VARIABLE res
-)
-
-if(NOT res EQUAL 0)
- message(STATUS "Output to stderr:\n${err}")
- message(FATAL_ERROR "Linting tests failed with error: ${res}")
-endif()
diff --git a/cmake/RunTests.cmake b/cmake/RunTests.cmake
index 05c429c1f5..f000004aec 100644
--- a/cmake/RunTests.cmake
+++ b/cmake/RunTests.cmake
@@ -1,13 +1,18 @@
# Set LC_ALL to meet expectations of some locale-sensitive tests.
set(ENV{LC_ALL} "en_US.UTF-8")
+if(POLICY CMP0012)
+ # Handle CI=true, without dev warnings.
+ cmake_policy(SET CMP0012 NEW)
+endif()
+
set(ENV{VIMRUNTIME} ${WORKING_DIR}/runtime)
-set(ENV{NVIM_RPLUGIN_MANIFEST} ${WORKING_DIR}/Xtest_rplugin_manifest)
-set(ENV{XDG_CONFIG_HOME} ${WORKING_DIR}/Xtest_xdg/config)
-set(ENV{XDG_DATA_HOME} ${WORKING_DIR}/Xtest_xdg/share)
+set(ENV{NVIM_RPLUGIN_MANIFEST} ${BUILD_DIR}/Xtest_rplugin_manifest)
+set(ENV{XDG_CONFIG_HOME} ${BUILD_DIR}/Xtest_xdg/config)
+set(ENV{XDG_DATA_HOME} ${BUILD_DIR}/Xtest_xdg/share)
if(NOT DEFINED ENV{NVIM_LOG_FILE})
- set(ENV{NVIM_LOG_FILE} ${WORKING_DIR}/.nvimlog)
+ set(ENV{NVIM_LOG_FILE} ${BUILD_DIR}/.nvimlog)
endif()
if(NVIM_PRG)
@@ -20,38 +25,62 @@ else()
set(TEST_PATH "${TEST_DIR}/${TEST_TYPE}")
endif()
+# Force $TEST_PATH to workdir-relative path ("test/…").
+if(IS_ABSOLUTE ${TEST_PATH})
+ file(RELATIVE_PATH TEST_PATH "${WORKING_DIR}" "${TEST_PATH}")
+endif()
+
if(BUSTED_OUTPUT_TYPE STREQUAL junit)
set(EXTRA_ARGS OUTPUT_FILE ${BUILD_DIR}/${TEST_TYPE}test-junit.xml)
endif()
+set(BUSTED_ARGS $ENV{BUSTED_ARGS})
+separate_arguments(BUSTED_ARGS)
+
if(DEFINED ENV{TEST_TAG} AND NOT "$ENV{TEST_TAG}" STREQUAL "")
- set(TEST_TAG "--tags=$ENV{TEST_TAG}")
+ list(APPEND BUSTED_ARGS --tags $ENV{TEST_TAG})
endif()
if(DEFINED ENV{TEST_FILTER} AND NOT "$ENV{TEST_FILTER}" STREQUAL "")
- set(TEST_FILTER "--filter=$ENV{TEST_FILTER}")
+ list(APPEND BUSTED_ARGS --filter $ENV{TEST_FILTER})
endif()
-execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${WORKING_DIR}/Xtest-tmpdir)
-set(ENV{TMPDIR} ${WORKING_DIR}/Xtest-tmpdir)
-set(ENV{SYSTEM_NAME} ${SYSTEM_NAME})
+# TMPDIR: use relative test path (for parallel test runs / isolation).
+set(ENV{TMPDIR} "${BUILD_DIR}/Xtest_tmpdir/${TEST_PATH}")
+execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory $ENV{TMPDIR})
+
+set(ENV{SYSTEM_NAME} ${CMAKE_HOST_SYSTEM_NAME}) # used by test/helpers.lua.
execute_process(
- COMMAND ${BUSTED_PRG} ${TEST_TAG} ${TEST_FILTER} -v -o ${BUSTED_OUTPUT_TYPE}
- --lua=${LUA_PRG} --lazy --helper=${TEST_DIR}/${TEST_TYPE}/preload.lua
+ COMMAND ${BUSTED_PRG} -v -o test.busted.outputHandlers.${BUSTED_OUTPUT_TYPE}
+ --lazy --helper=${TEST_DIR}/${TEST_TYPE}/preload.lua
--lpath=${BUILD_DIR}/?.lua
--lpath=${WORKING_DIR}/runtime/lua/?.lua
--lpath=?.lua
+ ${BUSTED_ARGS}
${TEST_PATH}
WORKING_DIRECTORY ${WORKING_DIR}
ERROR_VARIABLE err
RESULT_VARIABLE res
${EXTRA_ARGS})
-file(REMOVE ${WORKING_DIR}/Xtest_rplugin_manifest)
-file(REMOVE_RECURSE ${WORKING_DIR}/Xtest_xdg)
-file(REMOVE_RECURSE ${WORKING_DIR}/Xtest-tmpdir)
+file(GLOB RM_FILES ${BUILD_DIR}/Xtest_*)
+file(REMOVE_RECURSE ${RM_FILES})
if(NOT res EQUAL 0)
- message(STATUS "Output to stderr:\n${err}")
+ message(STATUS "Tests exited non-zero: ${res}")
+ if("${err}" STREQUAL "")
+ message(STATUS "No output to stderr.")
+ else()
+ message(STATUS "Output to stderr:\n${err}")
+ endif()
+
+ # Dump the logfile on CI (if not displayed and moved already).
+ if($ENV{CI})
+ if(EXISTS $ENV{NVIM_LOG_FILE} AND NOT EXISTS $ENV{NVIM_LOG_FILE}.displayed)
+ file(READ $ENV{NVIM_LOG_FILE} out)
+ message(STATUS "$NVIM_LOG_FILE: $ENV{NVIM_LOG_FILE}\n${out}")
+ endif()
+ endif()
+
message(FATAL_ERROR "${TEST_TYPE} tests failed with error: ${res}")
endif()
diff --git a/cmake/mingw32-w64-cross-travis.toolchain.cmake b/cmake/mingw32-w64-cross-travis.toolchain.cmake
deleted file mode 100644
index bdd14365c6..0000000000
--- a/cmake/mingw32-w64-cross-travis.toolchain.cmake
+++ /dev/null
@@ -1,53 +0,0 @@
-#
-# Mingw-w64 cross compiler toolchain
-#
-# - The usual CMAKE variables will point to the cross compiler
-# - HOST_EXE_LINKER, HOST_C_COMPILER, HOST_EXE_LINKER_FLAGS,
-# HOST_C_FLAGS point to a host compiler
-#
-
-set(MINGW_TRIPLET i686-w64-mingw32)
-# For x86_64 use
-#set(MINGW_TRIPLET x86_64-w64-mingw32)
-
-# The location of your toolchain sys-root
-set(MINGW_PREFIX_PATH /opt/mingw32/${MINGW_TRIPLET}/)
-# or sometimes like this
-#set(MINGW_PREFIX_PATH /usr/${MINGW_TRIPLET}/sys-root)
-
-# the name of the target operating system
-set(CMAKE_SYSTEM_NAME Windows)
-
-# which compilers to use for C and C++
-set(CMAKE_C_COMPILER ${MINGW_TRIPLET}-gcc)
-set(CMAKE_CXX_COMPILER ${MINGW_TRIPLET}-g++)
-set(CMAKE_RC_COMPILER ${MINGW_TRIPLET}-windres)
-set(CMAKE_C_COMPILER ${MINGW_TRIPLET}-gcc)
-set(CMAKE_CXX_COMPILER ${MINGW_TRIPLET}-g++)
-set(CMAKE_RC_COMPILER ${MINGW_TRIPLET}-windres)
-
-# Where is the target environment located
-set(CMAKE_FIND_ROOT_PATH "${MINGW_PREFIX_PATH}/mingw")
-
-# adjust the default behaviour of the FIND_XXX() commands:
-# search headers and libraries in the target environment, search
-# programs in the host environment
-set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
-set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
-set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
-
-set(CROSS_TARGET ${MINGW_TRIPLET})
-
-# We need a host compiler too - assuming mildly sane Unix
-# defaults here
-set(HOST_C_COMPILER cc)
-set(HOST_EXE_LINKER ld)
-
-if (MINGW_TRIPLET MATCHES "^x86_64")
- set(HOST_C_FLAGS)
- set(HOST_EXE_LINKER_FLAGS)
-else()
- # In 32 bits systems have the HOST compiler generate 32 bits binaries
- set(HOST_C_FLAGS -m32)
- set(HOST_EXE_LINKER_FLAGS -m32)
-endif()
diff --git a/codecov.yml b/codecov.yml
index 5acc64f756..a83fd916ee 100644
--- a/codecov.yml
+++ b/codecov.yml
@@ -24,12 +24,4 @@ coverage:
only_pulls: true
changes: no
-parsers:
- gcov:
- branch_detection:
- conditional: yes
- loop: yes
- method: no
- macro: no
-
comment: off
diff --git a/config/CMakeLists.txt b/config/CMakeLists.txt
index 4fb44b9a27..0ca41d5dfd 100644
--- a/config/CMakeLists.txt
+++ b/config/CMakeLists.txt
@@ -20,7 +20,6 @@ endif()
check_symbol_exists(_NSGetEnviron crt_externs.h HAVE__NSGETENVIRON)
# Headers
-check_include_files(iconv.h HAVE_ICONV_H)
check_include_files(langinfo.h HAVE_LANGINFO_H)
check_include_files(locale.h HAVE_LOCALE_H)
check_include_files(pwd.h HAVE_PWD_H)
@@ -32,7 +31,6 @@ if(NOT HAVE_SYS_WAIT_H AND UNIX)
endif()
check_include_files(sys/utsname.h HAVE_SYS_UTSNAME_H)
check_include_files(termios.h HAVE_TERMIOS_H)
-check_include_files(utime.h HAVE_UTIME_H)
check_include_files(sys/uio.h HAVE_SYS_UIO_H)
# Functions
@@ -53,8 +51,6 @@ check_function_exists(setsid HAVE_SETSID)
check_function_exists(sigaction HAVE_SIGACTION)
check_function_exists(strcasecmp HAVE_STRCASECMP)
check_function_exists(strncasecmp HAVE_STRNCASECMP)
-check_function_exists(utime HAVE_UTIME)
-check_function_exists(utimes HAVE_UTIMES)
# Symbols
check_symbol_exists(FD_CLOEXEC "fcntl.h" HAVE_FD_CLOEXEC)
diff --git a/config/config.h.in b/config/config.h.in
index ae04c38272..0cb87c6b4d 100644
--- a/config/config.h.in
+++ b/config/config.h.in
@@ -21,7 +21,6 @@
#cmakedefine HAVE_GETPWNAM
#cmakedefine HAVE_GETPWUID
#cmakedefine HAVE_ICONV
-#cmakedefine HAVE_ICONV_H
#cmakedefine HAVE_LANGINFO_H
#cmakedefine HAVE_LOCALE_H
#cmakedefine HAVE_NL_LANGINFO_CODESET
@@ -37,9 +36,6 @@
#cmakedefine HAVE_SYS_UTSNAME_H
#cmakedefine HAVE_SYS_WAIT_H
#cmakedefine HAVE_TERMIOS_H
-#cmakedefine HAVE_UTIME
-#cmakedefine HAVE_UTIME_H
-#cmakedefine HAVE_UTIMES
#cmakedefine HAVE_WORKING_LIBINTL
#cmakedefine HAVE_WSL
#cmakedefine UNIX
diff --git a/contrib/gdb/nvim-gdb-pretty-printers.py b/contrib/gdb/nvim-gdb-pretty-printers.py
index 609ceeb7ab..a6a3d90ce4 100644
--- a/contrib/gdb/nvim-gdb-pretty-printers.py
+++ b/contrib/gdb/nvim-gdb-pretty-printers.py
@@ -26,13 +26,13 @@ def get_color_code(bg, color_num):
prefix += 1
color_num %= 8
else:
- prefix = '48;5;' if bg else '38;5;'
+ prefix = '48;5;' if bg else '38;5;'
return '\x1b[{0}{1}m'.format(prefix, color_num)
def highlight(attrs):
fg, bg = [int(attrs['foreground']), int(attrs['background'])]
- rv = [SGR0] # start with sgr0
+ rv = [SGR0] # start with sgr0
if fg != -1:
rv.append(get_color_code(False, fg))
if bg != -1:
diff --git a/contrib/local.mk.example b/contrib/local.mk.example
index 52a5505399..5a31ded59b 100644
--- a/contrib/local.mk.example
+++ b/contrib/local.mk.example
@@ -7,6 +7,9 @@
# These CFLAGS can be used in addition to those specified in CMakeLists.txt:
# CMAKE_EXTRA_FLAGS="-DCMAKE_C_FLAGS=-ftrapv -Wlogical-op"
+# To turn compiler warnings into errors:
+# CMAKE_EXTRA_FLAGS += "-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} -Werror"
+
# Sets the build type; defaults to Debug. Valid values:
#
# - Debug: Disables optimizations (-O0), enables debug information.
@@ -44,18 +47,6 @@
#
# DEPS_CMAKE_FLAGS += -DUSE_BUNDLED=OFF
-# By default, bundled libraries are statically linked to nvim.
-# This has no effect for non-bundled deps, which are always dynamically linked.
-# Uncomment these entries to instead use dynamic linking.
-#
-# CMAKE_EXTRA_FLAGS += -DLIBTERMKEY_USE_STATIC=OFF
-# CMAKE_EXTRA_FLAGS += -DLIBUNIBILIUM_USE_STATIC=OFF
-# CMAKE_EXTRA_FLAGS += -DLIBUV_USE_STATIC=OFF
-# CMAKE_EXTRA_FLAGS += -DLIBVTERM_USE_STATIC=OFF
-# CMAKE_EXTRA_FLAGS += -DLUAJIT_USE_STATIC=OFF
-# CMAKE_EXTRA_FLAGS += -DMSGPACK_USE_STATIC=OFF
-#
-#
# .DEFAULT_GOAL := nvim
#
# Run doxygen over the source code.
diff --git a/runtime/autoload/RstFold.vim b/runtime/autoload/RstFold.vim
index 5becb04685..238b1e3537 100644
--- a/runtime/autoload/RstFold.vim
+++ b/runtime/autoload/RstFold.vim
@@ -1,8 +1,12 @@
" Author: Antony Lee <anntzer.lee@gmail.com>
" Description: Helper functions for reStructuredText syntax folding
-" Last Modified: 2018-01-07
+" Last Modified: 2018-12-29
function s:CacheRstFold()
+ if !g:rst_fold_enabled
+ return
+ endif
+
let closure = {'header_types': {}, 'max_level': 0, 'levels': {}}
function closure.Process(match) dict
let curline = getcurpos()[1]
@@ -20,12 +24,18 @@ function s:CacheRstFold()
let self.levels[curline] = self.header_types[key]
endfunction
let save_cursor = getcurpos()
+ let save_mark = getpos("'[")
silent keeppatterns %s/\v^%(%(([=`:.'"~^_*+#-])\1+\n)?.{1,2}\n([=`:.'"~^_*+#-])\2+)|%(%(([=`:.''"~^_*+#-])\3{2,}\n)?.{3,}\n([=`:.''"~^_*+#-])\4{2,})$/\=closure.Process(submatch(0))/gn
call setpos('.', save_cursor)
+ call setpos("'[", save_mark)
let b:RstFoldCache = closure.levels
endfunction
function RstFold#GetRstFold()
+ if !g:rst_fold_enabled
+ return
+ endif
+
if !has_key(b:, 'RstFoldCache')
call s:CacheRstFold()
endif
@@ -37,6 +47,10 @@ function RstFold#GetRstFold()
endfunction
function RstFold#GetRstFoldText()
+ if !g:rst_fold_enabled
+ return
+ endif
+
if !has_key(b:, 'RstFoldCache')
call s:CacheRstFold()
endif
diff --git a/runtime/autoload/dist/ft.vim b/runtime/autoload/dist/ft.vim
index 6ed39cb9f1..e85ffc763b 100644
--- a/runtime/autoload/dist/ft.vim
+++ b/runtime/autoload/dist/ft.vim
@@ -1,7 +1,7 @@
" Vim functions for file type detection
"
" Maintainer: Bram Moolenaar <Bram@vim.org>
-" Last Change: 2019 Jan 18
+" Last Change: 2019 Mar 08
" These functions are moved here from runtime/filetype.vim to make startup
" faster.
@@ -126,7 +126,7 @@ endfunc
" This function checks if one of the first ten lines start with a '@'. In
" that case it is probably a change file.
" If the first line starts with # or ! it's probably a ch file.
-" If a line has "main", "include", "//" ir "/*" it's probably ch.
+" If a line has "main", "include", "//" or "/*" it's probably ch.
" Otherwise CHILL is assumed.
func dist#ft#FTchange()
let lnum = 1
diff --git a/runtime/autoload/health/nvim.vim b/runtime/autoload/health/nvim.vim
index 8fcea2e941..c25f5ee64f 100644
--- a/runtime/autoload/health/nvim.vim
+++ b/runtime/autoload/health/nvim.vim
@@ -8,7 +8,7 @@ function! s:check_config() abort
if !filereadable(vimrc)
let ok = v:false
let has_vim = filereadable(expand('~/.vimrc'))
- call health#report_warn('Missing user config file: '.vimrc,
+ call health#report_warn((-1 == getfsize(vimrc) ? 'Missing' : 'Unreadable').' user config file: '.vimrc,
\[ has_vim ? ':help nvim-from-vim' : ':help init.vim' ])
endif
@@ -41,6 +41,12 @@ function! s:check_config() abort
\ 'Check `:verbose set paste?` to see if a plugin or script set the option.', ])
endif
+ let shadafile = (empty(&shadafile) || &shadafile ==# 'NONE') ? stdpath('data').'/shada/main.shada' : &shadafile
+ if !empty(shadafile) && (!filereadable(shadafile) || !filewritable(shadafile))
+ let ok = v:false
+ call health#report_error('shada file is not '.(filereadable(shadafile) ? 'writeable' : 'readable').":\n".shadafile)
+ endif
+
if ok
call health#report_ok('no issues found')
endif
@@ -117,7 +123,7 @@ function! s:check_performance() abort
else
call health#report_info(buildtype)
call health#report_warn(
- \ 'Non-optimized build-type. Nvim will be slower.',
+ \ 'Non-optimized '.(has('debug')?'(DEBUG) ':'').'build. Nvim will be slower.',
\ ['Install a different Nvim package, or rebuild with `CMAKE_BUILD_TYPE=RelWithDebInfo`.',
\ s:suggest_faq])
endif
diff --git a/runtime/autoload/health/provider.vim b/runtime/autoload/health/provider.vim
index 29bbee4888..87d82150b6 100644
--- a/runtime/autoload/health/provider.vim
+++ b/runtime/autoload/health/provider.vim
@@ -564,7 +564,10 @@ function! s:check_node() abort
endif
call health#report_info('Neovim node.js host: '. host)
- let latest_npm_cmd = has('win32') ? 'cmd /c npm info neovim --json' : 'npm info neovim --json'
+ let manager = executable('npm') ? 'npm' : 'yarn'
+ let latest_npm_cmd = has('win32') ?
+ \ 'cmd /c '. manager .' info neovim --json' :
+ \ manager .' info neovim --json'
let latest_npm = s:system(split(latest_npm_cmd))
if s:shell_error || empty(latest_npm)
call health#report_error('Failed to run: '. latest_npm_cmd,
@@ -593,7 +596,8 @@ function! s:check_node() abort
call health#report_warn(
\ printf('Package "neovim" is out-of-date. Installed: %s, latest: %s',
\ current_npm, latest_npm),
- \ ['Run in shell: npm install -g neovim'])
+ \ ['Run in shell: npm install -g neovim',
+ \ 'Run in shell (if you use yarn): yarn global add neovim'])
else
call health#report_ok('Latest "neovim" npm/yarn package is installed: '. current_npm)
endif
diff --git a/runtime/autoload/netrw.vim b/runtime/autoload/netrw.vim
index 76485c2f38..a5b47e06d5 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: Apr 20, 2016
-" Version: 156
+" Date: Jul 16, 2019
+" Version: 165
" Maintainer: Charles E Campbell <NdrOchip@ScampbellPfamily.AbizM-NOSPAM>
" GetLatestVimScripts: 1075 1 :AutoInstall: netrw.vim
" Copyright: Copyright (C) 2016 Charles E. Campbell {{{1
@@ -22,15 +22,24 @@
if &cp || exists("g:loaded_netrw")
finish
endif
-" netrw requires vim having patch 7.4.213; netrw will benefit from vim's having patch#656, too
-if v:version < 704 || (v:version == 704 && !has("patch213"))
- if !exists("s:needpatch213")
- unsilent echomsg "***sorry*** this version of netrw requires vim v7.4 with patch 213"
- endif
- let s:needpatch213= 1
- finish
+
+" Check that vim has patches that netrw requires.
+" Patches needed for v7.4: 1557, and 213.
+" (netrw will benefit from vim's having patch#656, too)
+let s:needspatches=[1557,213]
+if exists("s:needspatches")
+ for ptch in s:needspatches
+ if v:version < 704 || (v:version == 704 && !has("patch".ptch))
+ if !exists("s:needpatch{ptch}")
+ unsilent echomsg "***sorry*** this version of netrw requires vim v7.4 with patch#".ptch
+ endif
+ let s:needpatch{ptch}= 1
+ finish
+ endif
+ endfor
endif
-let g:loaded_netrw = "v156"
+
+let g:loaded_netrw = "v165"
if !exists("s:NOTE")
let s:NOTE = 0
let s:WARNING = 1
@@ -39,7 +48,7 @@ endif
let s:keepcpo= &cpo
setl cpo&vim
-"let g:dechofuncname= 1
+"DechoFuncName 1
"DechoRemOn
"call Decho("doing autoload/netrw.vim version ".g:loaded_netrw,'~'.expand("<slnum>"))
@@ -55,7 +64,7 @@ setl cpo&vim
" Usage: netrw#ErrorMsg(s:NOTE | s:WARNING | s:ERROR,"some message",error-number)
" netrw#ErrorMsg(s:NOTE | s:WARNING | s:ERROR,["message1","message2",...],error-number)
" (this function can optionally take a list of messages)
-" Jan 19, 2016 : max errnum currently is 103
+" Mar 21, 2017 : max errnum currently is 105
fun! netrw#ErrorMsg(level,msg,errnum)
" call Dfunc("netrw#ErrorMsg(level=".a:level." msg<".a:msg."> errnum=".a:errnum.") g:netrw_use_errorwindow=".g:netrw_use_errorwindow)
@@ -100,7 +109,7 @@ fun! netrw#ErrorMsg(level,msg,errnum)
" call Decho("create a NetrwMessage buffer window",'~'.expand("<slnum>"))
bo 1split
sil! call s:NetrwEnew()
- sil! NetrwKeepj call s:NetrwSafeOptions()
+ sil! NetrwKeepj call s:NetrwOptionsSafe(1)
setl bt=nofile
NetrwKeepj file NetrwMessage
" call Decho("setl ma noro",'~'.expand("<slnum>"))
@@ -171,7 +180,7 @@ endfun
" ---------------------------------------------------------------------
" Netrw Constants: {{{2
-call s:NetrwInit("g:netrw_dirhist_cnt",0)
+call s:NetrwInit("g:netrw_dirhistcnt",0)
if !exists("s:LONGLIST")
call s:NetrwInit("s:THINLIST",0)
call s:NetrwInit("s:LONGLIST",1)
@@ -181,6 +190,14 @@ if !exists("s:LONGLIST")
endif
" ---------------------------------------------------------------------
+" Default option values: {{{2
+let g:netrw_localcopycmdopt = ""
+let g:netrw_localcopydircmdopt = ""
+let g:netrw_localmkdiropt = ""
+let g:netrw_localmovecmdopt = ""
+let g:netrw_localrmdiropt = ""
+
+" ---------------------------------------------------------------------
" Default values for netrw's global protocol variables {{{2
call s:NetrwInit("g:netrw_use_errorwindow",1)
@@ -215,21 +232,21 @@ if !exists("g:netrw_ftp_options")
let g:netrw_ftp_options= "-i -n"
endif
if !exists("g:netrw_http_cmd")
- if executable("elinks")
- let g:netrw_http_cmd = "elinks"
- call s:NetrwInit("g:netrw_http_xcmd","-source >")
- elseif executable("links")
- let g:netrw_http_cmd = "links"
- call s:NetrwInit("g:netrw_http_xcmd","-source >")
- elseif executable("curl")
+ if executable("curl")
let g:netrw_http_cmd = "curl"
- call s:NetrwInit("g:netrw_http_xcmd","-o")
+ call s:NetrwInit("g:netrw_http_xcmd","-L -o")
elseif executable("wget")
let g:netrw_http_cmd = "wget"
call s:NetrwInit("g:netrw_http_xcmd","-q -O")
+ elseif executable("elinks")
+ let g:netrw_http_cmd = "elinks"
+ call s:NetrwInit("g:netrw_http_xcmd","-source >")
elseif executable("fetch")
let g:netrw_http_cmd = "fetch"
call s:NetrwInit("g:netrw_http_xcmd","-o")
+ elseif executable("links")
+ let g:netrw_http_cmd = "links"
+ call s:NetrwInit("g:netrw_http_xcmd","-http.extra-header ".shellescape("Accept-Encoding: identity", 1)." -source >")
else
let g:netrw_http_cmd = ""
endif
@@ -238,6 +255,7 @@ call s:NetrwInit("g:netrw_http_put_cmd","curl -T")
call s:NetrwInit("g:netrw_keepj","keepj")
call s:NetrwInit("g:netrw_rcp_cmd" , "rcp")
call s:NetrwInit("g:netrw_rsync_cmd", "rsync")
+call s:NetrwInit("g:netrw_rsync_sep", "/")
if !exists("g:netrw_scp_cmd")
if executable("scp")
call s:NetrwInit("g:netrw_scp_cmd" , "scp -q")
@@ -299,7 +317,7 @@ let s:netrw_usercuc = &cursorcolumn
call s:NetrwInit("g:netrw_cygdrive","/cygdrive")
" Default values - d-g ---------- {{{3
call s:NetrwInit("s:didstarstar",0)
-call s:NetrwInit("g:netrw_dirhist_cnt" , 0)
+call s:NetrwInit("g:netrw_dirhistcnt" , 0)
call s:NetrwInit("g:netrw_decompress" , '{ ".gz" : "gunzip", ".bz2" : "bunzip2", ".zip" : "unzip", ".tar" : "tar -xf", ".xz" : "unxz" }')
call s:NetrwInit("g:netrw_dirhistmax" , 10)
call s:NetrwInit("g:netrw_errorlvl" , s:NOTE)
@@ -364,7 +382,8 @@ if !exists("g:netrw_localcopycmd")
if g:netrw_cygwin
let g:netrw_localcopycmd= "cp"
else
- let g:netrw_localcopycmd= expand("$COMSPEC")." /c copy"
+ let g:netrw_localcopycmd = expand("$COMSPEC")
+ let g:netrw_localcopycmdopt= " /c copy"
endif
elseif has("unix") || has("macunix")
let g:netrw_localcopycmd= "cp"
@@ -375,14 +394,20 @@ endif
if !exists("g:netrw_localcopydircmd")
if has("win32") || has("win95") || has("win64") || has("win16")
if g:netrw_cygwin
- let g:netrw_localcopydircmd= "cp -R"
+ let g:netrw_localcopydircmd = "cp"
+ let g:netrw_localcopydircmdopt= " -R"
else
- let g:netrw_localcopycmd= expand("$COMSPEC")." /c xcopy /e /c /h /i /k"
- endif
- elseif has("unix") || has("macunix")
- let g:netrw_localcopydircmd= "cp -R"
+ let g:netrw_localcopydircmd = expand("$COMSPEC")
+ let g:netrw_localcopydircmdopt= " /c xcopy /e /c /h /i /k"
+ endif
+ elseif has("unix")
+ let g:netrw_localcopydircmd = "cp"
+ let g:netrw_localcopydircmdopt= " -R"
+ elseif has("macunix")
+ let g:netrw_localcopydircmd = "cp"
+ let g:netrw_localcopydircmdopt= " -R"
else
- let g:netrw_localcopycmd= ""
+ let g:netrw_localcopydircmd= ""
endif
endif
if exists("g:netrw_local_mkdir")
@@ -393,7 +418,8 @@ if has("win32") || has("win95") || has("win64") || has("win16")
if g:netrw_cygwin
call s:NetrwInit("g:netrw_localmkdir","mkdir")
else
- let g:netrw_localmkdir= expand("$COMSPEC")." /c mkdir"
+ let g:netrw_localmkdir = expand("$COMSPEC")
+ let g:netrw_localmkdiropt= " /c mkdir"
endif
else
call s:NetrwInit("g:netrw_localmkdir","mkdir")
@@ -408,7 +434,8 @@ if !exists("g:netrw_localmovecmd")
if g:netrw_cygwin
let g:netrw_localmovecmd= "mv"
else
- let g:netrw_localmovecmd= expand("$COMSPEC")." /c move"
+ let g:netrw_localmovecmd = expand("$COMSPEC")
+ let g:netrw_localmovecmdopt= " /c move"
endif
elseif has("unix") || has("macunix")
let g:netrw_localmovecmd= "mv"
@@ -416,7 +443,8 @@ if !exists("g:netrw_localmovecmd")
let g:netrw_localmovecmd= ""
endif
endif
-if v:version < 704 || !has("patch1109")
+if v:version < 704 || (v:version == 704 && !has("patch1107"))
+ " 1109 provides for delete(tmpdir,"d") which is what will be used
if exists("g:netrw_local_rmdir")
let g:netrw_localrmdir= g:netrw_local_rmdir
call netrw#ErrorMsg(s:NOTE,"g:netrw_local_rmdir is deprecated in favor of g:netrw_localrmdir",86)
@@ -425,7 +453,8 @@ if v:version < 704 || !has("patch1109")
if g:netrw_cygwin
call s:NetrwInit("g:netrw_localrmdir","rmdir")
else
- let g:netrw_localrmdir= expand("$COMSPEC")." /c rmdir"
+ let g:netrw_localrmdir = expand("$COMSPEC")
+ let g:netrw_localrmdiropt= " /c rmdir"
endif
else
call s:NetrwInit("g:netrw_localrmdir","rmdir")
@@ -527,7 +556,7 @@ if has("gui_running") && (&enc == 'utf-8' || &enc == 'utf-16' || &enc == 'ucs-4'
else
let s:treedepthstring= "| "
endif
-call s:NetrwInit("s:netrw_nbcd",'{}')
+call s:NetrwInit("s:netrw_posn",'{}')
" BufEnter event ignored by decho when following variable is true
" Has a side effect that doau BufReadPost doesn't work, so
@@ -888,7 +917,7 @@ fun! netrw#Explore(indx,dosplit,style,...)
NetrwKeepj call netrw#ErrorMsg(s:WARNING,"using Nexplore or <s-down> improperly; see help for netrw-starstar",40)
if has("clipboard")
sil! let @* = keepregstar
- sil! let @+ = keepregstar
+ sil! let @+ = keepregplus
endif
sil! let @/ = keepregslash
" call Dret("netrw#Explore")
@@ -913,7 +942,7 @@ fun! netrw#Explore(indx,dosplit,style,...)
NetrwKeepj call netrw#ErrorMsg(s:WARNING,"using Pexplore or <s-up> improperly; see help for netrw-starstar",41)
if has("clipboard")
sil! let @* = keepregstar
- sil! let @+ = keepregstar
+ sil! let @+ = keepregplus
endif
sil! let @/ = keepregslash
" call Dret("netrw#Explore")
@@ -967,8 +996,8 @@ fun! netrw#Explore(indx,dosplit,style,...)
keepalt call netrw#ErrorMsg(s:WARNING,'no files matched pattern<'.pattern.'>',45)
if &hls | let keepregslash= s:ExplorePatHls(pattern) | endif
if has("clipboard")
- sil! let @* = keepregstar
- sil! let @+ = keepregstar
+ sil! let @* = keepregstar
+ sil! let @+ = keepregplus
endif
sil! let @/ = keepregslash
" call Dret("netrw#Explore : no files matched pattern")
@@ -1004,7 +1033,7 @@ fun! netrw#Explore(indx,dosplit,style,...)
keepalt NetrwKeepj call netrw#ErrorMsg(s:WARNING,"no files matched",42)
if has("clipboard")
sil! let @* = keepregstar
- sil! let @+ = keepregstar
+ sil! let @+ = keepregplus
endif
sil! let @/ = keepregslash
" call Dret("netrw#Explore : no files matched")
@@ -1052,7 +1081,7 @@ fun! netrw#Explore(indx,dosplit,style,...)
endif
if has("clipboard")
sil! let @* = keepregstar
- sil! let @+ = keepregstar
+ sil! let @+ = keepregplus
endif
sil! let @/ = keepregslash
" call Dret("netrw#Explore : missing +path_extra")
@@ -1106,7 +1135,9 @@ fun! netrw#Explore(indx,dosplit,style,...)
let prvfname= fname
endfor
" call Decho("explore_match<".s:explore_match.">",'~'.expand("<slnum>"))
- exe "2match netrwMarkFile /".s:explore_match."/"
+ if has("syntax") && exists("g:syntax_on") && g:syntax_on
+ exe "2match netrwMarkFile /".s:explore_match."/"
+ endif
endif
echo "<s-up>==Pexplore <s-down>==Nexplore"
else
@@ -1123,7 +1154,7 @@ fun! netrw#Explore(indx,dosplit,style,...)
let s:netrw_events= 2
if has("clipboard")
sil! let @* = keepregstar
- sil! let @+ = keepregstar
+ sil! let @+ = keepregplus
endif
sil! let @/ = keepregslash
" call Dret("netrw#Explore : @/<".@/.">")
@@ -1132,13 +1163,14 @@ endfun
" ---------------------------------------------------------------------
" netrw#Lexplore: toggle Explorer window, keeping it on the left of the current tab {{{2
fun! netrw#Lexplore(count,rightside,...)
-" call Dfunc("netrw#Lexplore(count=".a:count."rightside=".a:rightside.",...) a:0=".a:0." ft=".&ft)
+" call Dfunc("netrw#Lexplore(count=".a:count." rightside=".a:rightside.",...) a:0=".a:0." ft=".&ft)
let curwin= winnr()
if a:0 > 0 && a:1 != ""
" if a netrw window is already on the left-side of the tab
" and a directory has been specified, explore with that
" directory.
+" call Decho("case has input argument(s) (a:1<".a:1.">)")
let a1 = expand(a:1)
" call Decho("a:1<".a:1."> curwin#".curwin,'~'.expand("<slnum>"))
exe "1wincmd w"
@@ -1156,18 +1188,22 @@ fun! netrw#Lexplore(count,rightside,...)
exe curwin."wincmd w"
else
let a1= ""
+" call Decho("no input arguments")
endif
if exists("t:netrw_lexbufnr")
" check if t:netrw_lexbufnr refers to a netrw window
let lexwinnr = bufwinnr(t:netrw_lexbufnr)
+" call Decho("lexwinnr= bufwinnr(t:netrw_lexbufnr#".t:netrw_lexbufnr.")=".lexwinnr)
else
let lexwinnr= 0
+" call Decho("t:netrw_lexbufnr doesn't exist")
endif
+" call Decho("lexwinnr=".lexwinnr,'~'.expand("<slnum>"))
if lexwinnr > 0
" close down netrw explorer window
-" call Decho("t:netrw_lexbufnr#".t:netrw_lexbufnr.": close down netrw window",'~'.expand("<slnum>"))
+" call Decho("t:netrw_lexbufnr#".t:netrw_lexbufnr.": close down netrw window",'~'.expand("<slnum>"))
exe lexwinnr."wincmd w"
let g:netrw_winsize = -winwidth(0)
let t:netrw_lexposn = winsaveview()
@@ -1177,8 +1213,11 @@ fun! netrw#Lexplore(count,rightside,...)
if lexwinnr < curwin
let curwin= curwin - 1
endif
- exe curwin."wincmd w"
+ if lexwinnr != curwin
+ exe curwin."wincmd w"
+ endif
unlet t:netrw_lexbufnr
+" call Decho("unlet t:netrw_lexbufnr")
else
" open netrw explorer window
@@ -1193,15 +1232,17 @@ fun! netrw#Lexplore(count,rightside,...)
let curfile= expand("%")
" call Decho("curfile<".curfile.">",'~'.expand("<slnum>"))
exe (a:rightside? "botright" : "topleft")." vertical ".((g:netrw_winsize > 0)? (g:netrw_winsize*winwidth(0))/100 : -g:netrw_winsize) . " new"
+" call Decho("new buf#".bufnr("%")." win#".winnr())
if a:0 > 0 && a1 != ""
" call Decho("case 1: Explore ".a1,'~'.expand("<slnum>"))
+ call netrw#Explore(0,0,0,a1)
exe "Explore ".fnameescape(a1)
elseif curfile =~ '^\a\{3,}://'
" call Decho("case 2: Explore ".substitute(curfile,'[^/\\]*$','',''),'~'.expand("<slnum>"))
- exe "Explore ".substitute(curfile,'[^/\\]*$','','')
+ call netrw#Explore(0,0,0,substitute(curfile,'[^/\\]*$','',''))
else
" call Decho("case 3: Explore .",'~'.expand("<slnum>"))
- Explore .
+ call netrw#Explore(0,0,0,".")
endif
if a:count != 0
let g:netrw_winsize = netrw_winsize
@@ -1209,6 +1250,8 @@ fun! netrw#Lexplore(count,rightside,...)
setlocal winfixwidth
let g:netrw_altv = keep_altv
let t:netrw_lexbufnr = bufnr("%")
+" call Decho("let t:netrw_lexbufnr=".t:netrw_lexbufnr)
+" call Decho("t:netrw_lexposn".(exists("t:netrw_lexposn")? string(t:netrw_lexposn) : " n/a"))
if exists("t:netrw_lexposn")
" call Decho("restoring to t:netrw_lexposn",'~'.expand("<slnum>"))
" call Decho("restoring posn to t:netrw_lexposn<".string(t:netrw_lexposn).">",'~'.expand("<slnum>"))
@@ -1224,6 +1267,7 @@ fun! netrw#Lexplore(count,rightside,...)
else
let g:netrw_chgwin= 2
endif
+" call Decho("let g:netrw_chgwin=".g:netrw_chgwin)
endif
" call Dret("netrw#Lexplore")
@@ -1341,7 +1385,7 @@ fun! netrw#Obtain(islocal,fname,...)
" call Decho("transfer files one at a time",'~'.expand("<slnum>"))
for fname in fnamelist
" call Decho("system(".g:netrw_localcopycmd." ".s:ShellEscape(fname)." ".s:ShellEscape(topath).")",'~'.expand("<slnum>"))
- call system(g:netrw_localcopycmd." ".s:ShellEscape(fname)." ".s:ShellEscape(topath))
+ call system(g:netrw_localcopycmd.g:netrw_localcopycmdopt." ".s:ShellEscape(fname)." ".s:ShellEscape(topath))
if v:shell_error != 0
call netrw#ErrorMsg(s:WARNING,"consider setting g:netrw_localcopycmd<".g:netrw_localcopycmd."> to something that works",80)
" call Dret("s:NetrwObtain 0 : failed: ".g:netrw_localcopycmd." ".s:ShellEscape(fname)." ".s:ShellEscape(topath))
@@ -1353,7 +1397,7 @@ fun! netrw#Obtain(islocal,fname,...)
" call Decho("transfer files with one command",'~'.expand("<slnum>"))
let filelist= join(map(deepcopy(fnamelist),"s:ShellEscape(v:val)"))
" call Decho("system(".g:netrw_localcopycmd." ".filelist." ".s:ShellEscape(topath).")",'~'.expand("<slnum>"))
- call system(g:netrw_localcopycmd." ".filelist." ".s:ShellEscape(topath))
+ call system(g:netrw_localcopycmd.g:netrw_localcopycmdopt." ".filelist." ".s:ShellEscape(topath))
if v:shell_error != 0
call netrw#ErrorMsg(s:WARNING,"consider setting g:netrw_localcopycmd<".g:netrw_localcopycmd."> to something that works",80)
" call Dret("s:NetrwObtain 0 : failed: ".g:netrw_localcopycmd." ".filelist." ".s:ShellEscape(topath))
@@ -1387,7 +1431,7 @@ fun! netrw#Obtain(islocal,fname,...)
else
let path= ""
endif
- let filelist= join(map(deepcopy(fnamelist),'s:ShellEscape(g:netrw_machine.":".path.v:val,1)'))
+ let filelist= join(map(deepcopy(fnamelist),'escape(s:ShellEscape(g:netrw_machine.":".path.v:val,1)," ")'))
call s:NetrwExe(s:netrw_silentxfer."!".g:netrw_scp_cmd.s:ShellEscape(useport,1)." ".filelist." ".s:ShellEscape(tgtdir,1))
elseif b:netrw_method == 2
@@ -1557,134 +1601,25 @@ fun! netrw#Nread(mode,fname)
endfun
" ------------------------------------------------------------------------
-" s:NetrwOptionRestore: restore options (based on prior s:NetrwOptionSave) {{{2
-fun! s:NetrwOptionRestore(vt)
-" call Dfunc("s:NetrwOptionRestore(vt<".a:vt.">) win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> winnr($)=".winnr("$"))
-" 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 s:RestorePosn(s:netrw_nbcd)
-" 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:NetrwOptionRestore : ".a:vt."netrw_optionsave doesn't exist")
- return
- endif
- unlet {a:vt}netrw_optionsave
-
- if exists("+acd")
- if exists("{a:vt}netrw_acdkeep")
-" call Decho("g:netrw_keepdir=".g:netrw_keepdir.": getcwd<".getcwd()."> acd=".&acd,'~'.expand("<slnum>"))
- let curdir = getcwd()
- let &l:acd = {a:vt}netrw_acdkeep
- unlet {a:vt}netrw_acdkeep
- if &l:acd
- call s:NetrwLcd(curdir)
- endif
- endif
- endif
- if exists("{a:vt}netrw_aikeep") |let &l:ai = {a:vt}netrw_aikeep |unlet {a:vt}netrw_aikeep |endif
- if exists("{a:vt}netrw_awkeep") |let &l:aw = {a:vt}netrw_awkeep |unlet {a:vt}netrw_awkeep |endif
- if exists("{a:vt}netrw_blkeep") |let &l:bl = {a:vt}netrw_blkeep |unlet {a:vt}netrw_blkeep |endif
- if exists("{a:vt}netrw_btkeep") |let &l:bt = {a:vt}netrw_btkeep |unlet {a:vt}netrw_btkeep |endif
- if exists("{a:vt}netrw_bombkeep") |let &l:bomb = {a:vt}netrw_bombkeep |unlet {a:vt}netrw_bombkeep |endif
- if exists("{a:vt}netrw_cedit") |let &cedit = {a:vt}netrw_cedit |unlet {a:vt}netrw_cedit |endif
- if exists("{a:vt}netrw_cikeep") |let &l:ci = {a:vt}netrw_cikeep |unlet {a:vt}netrw_cikeep |endif
- if exists("{a:vt}netrw_cinkeep") |let &l:cin = {a:vt}netrw_cinkeep |unlet {a:vt}netrw_cinkeep |endif
- if exists("{a:vt}netrw_cinokeep") |let &l:cino = {a:vt}netrw_cinokeep |unlet {a:vt}netrw_cinokeep |endif
- if exists("{a:vt}netrw_comkeep") |let &l:com = {a:vt}netrw_comkeep |unlet {a:vt}netrw_comkeep |endif
- if exists("{a:vt}netrw_cpokeep") |let &l:cpo = {a:vt}netrw_cpokeep |unlet {a:vt}netrw_cpokeep |endif
- if exists("{a:vt}netrw_diffkeep") |let &l:diff = {a:vt}netrw_diffkeep |unlet {a:vt}netrw_diffkeep |endif
- if exists("{a:vt}netrw_fenkeep") |let &l:fen = {a:vt}netrw_fenkeep |unlet {a:vt}netrw_fenkeep |endif
- if exists("g:netrw_ffkep") && g:netrw_ffkeep
- if exists("{a:vt}netrw_ffkeep") |let &l:ff = {a:vt}netrw_ffkeep |unlet {a:vt}netrw_ffkeep |endif
- endif
- if exists("{a:vt}netrw_fokeep") |let &l:fo = {a:vt}netrw_fokeep |unlet {a:vt}netrw_fokeep |endif
- if exists("{a:vt}netrw_gdkeep") |let &l:gd = {a:vt}netrw_gdkeep |unlet {a:vt}netrw_gdkeep |endif
- if exists("{a:vt}netrw_hidkeep") |let &l:hidden = {a:vt}netrw_hidkeep |unlet {a:vt}netrw_hidkeep |endif
- if exists("{a:vt}netrw_imkeep") |let &l:im = {a:vt}netrw_imkeep |unlet {a:vt}netrw_imkeep |endif
- if exists("{a:vt}netrw_iskkeep") |let &l:isk = {a:vt}netrw_iskkeep |unlet {a:vt}netrw_iskkeep |endif
- if exists("{a:vt}netrw_lskeep") |let &l:ls = {a:vt}netrw_lskeep |unlet {a:vt}netrw_lskeep |endif
- if exists("{a:vt}netrw_makeep") |let &l:ma = {a:vt}netrw_makeep |unlet {a:vt}netrw_makeep |endif
- if exists("{a:vt}netrw_magickeep")|let &l:magic = {a:vt}netrw_magickeep |unlet {a:vt}netrw_magickeep|endif
- if exists("{a:vt}netrw_modkeep") |let &l:mod = {a:vt}netrw_modkeep |unlet {a:vt}netrw_modkeep |endif
- if exists("{a:vt}netrw_nukeep") |let &l:nu = {a:vt}netrw_nukeep |unlet {a:vt}netrw_nukeep |endif
- if exists("{a:vt}netrw_rnukeep") |let &l:rnu = {a:vt}netrw_rnukeep |unlet {a:vt}netrw_rnukeep |endif
- if exists("{a:vt}netrw_repkeep") |let &l:report = {a:vt}netrw_repkeep |unlet {a:vt}netrw_repkeep |endif
- if exists("{a:vt}netrw_rokeep") |let &l:ro = {a:vt}netrw_rokeep |unlet {a:vt}netrw_rokeep |endif
- if exists("{a:vt}netrw_selkeep") |let &l:sel = {a:vt}netrw_selkeep |unlet {a:vt}netrw_selkeep |endif
- if exists("{a:vt}netrw_spellkeep")|let &l:spell = {a:vt}netrw_spellkeep |unlet {a:vt}netrw_spellkeep|endif
- if has("clipboard")
- if exists("{a:vt}netrw_starkeep") |let @* = {a:vt}netrw_starkeep |unlet {a:vt}netrw_starkeep |endif
- endif
- " Problem: start with liststyle=0; press <i> : result, following line resets l:ts.
-" if exists("{a:vt}netrw_tskeep") |let &l:ts = {a:vt}netrw_tskeep |unlet {a:vt}netrw_tskeep |endif
- if exists("{a:vt}netrw_twkeep") |let &l:tw = {a:vt}netrw_twkeep |unlet {a:vt}netrw_twkeep |endif
- if exists("{a:vt}netrw_wigkeep") |let &l:wig = {a:vt}netrw_wigkeep |unlet {a:vt}netrw_wigkeep |endif
- if exists("{a:vt}netrw_wrapkeep") |let &l:wrap = {a:vt}netrw_wrapkeep |unlet {a:vt}netrw_wrapkeep |endif
- if exists("{a:vt}netrw_writekeep")|let &l:write = {a:vt}netrw_writekeep |unlet {a:vt}netrw_writekeep|endif
- if exists("s:yykeep") |let @@ = s:yykeep |unlet s:yykeep |endif
- if exists("{a:vt}netrw_swfkeep")
- if &directory == ""
- " user hasn't specified a swapfile directory;
- " netrw will temporarily set the swapfile directory
- " to the current directory as returned by getcwd().
- let &l:directory= getcwd()
- sil! let &l:swf = {a:vt}netrw_swfkeep
- setl directory=
- unlet {a:vt}netrw_swfkeep
- elseif &l:swf != {a:vt}netrw_swfkeep
- if !g:netrw_use_noswf
- " following line causes a Press ENTER in windows -- can't seem to work around it!!!
- sil! let &l:swf= {a:vt}netrw_swfkeep
- endif
- unlet {a:vt}netrw_swfkeep
- endif
- endif
- if exists("{a:vt}netrw_dirkeep") && isdirectory(s:NetrwFile({a:vt}netrw_dirkeep)) && g:netrw_keepdir
- let dirkeep = substitute({a:vt}netrw_dirkeep,'\\','/','g')
- if exists("{a:vt}netrw_dirkeep")
- call s:NetrwLcd(dirkeep)
- unlet {a:vt}netrw_dirkeep
- endif
- endif
- if has("clipboard")
- if exists("{a:vt}netrw_regstar") |sil! let @*= {a:vt}netrw_regstar |unlet {a:vt}netrw_regstar |endif
- endif
- if exists("{a:vt}netrw_regslash")|sil! let @/= {a:vt}netrw_regslash|unlet {a:vt}netrw_regslash|endif
- call s:RestorePosn(s:netrw_nbcd)
-
-" call Decho("g:netrw_keepdir=".g:netrw_keepdir.": getcwd<".getcwd()."> acd=".&acd,'~'.expand("<slnum>"))
-" call Decho("fo=".&fo.(exists("+acd")? " acd=".&acd : " acd doesn't exist"),'~'.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("diff=".&l:diff." win#".winnr()." w:netrw_diffkeep=".(exists("w:netrw_diffkeep")? w:netrw_diffkeep : "doesn't exist"),'~'.expand("<slnum>"))
-" call Decho("ts=".&l:ts,'~'.expand("<slnum>"))
- " Moved the filetype detect here from NetrwGetFile() because remote files
- " were having their filetype detect-generated settings overwritten by
- " NetrwOptionRestore.
- if &ft != "netrw"
-" call Decho("filetype detect (ft=".&ft.")",'~'.expand("<slnum>"))
- filetype detect
- endif
-" 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:NetrwOptionRestore : tab#".tabpagenr()." win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> modified=".&modified." modifiable=".&modifiable." readonly=".&readonly)
-endfun
-
-" ---------------------------------------------------------------------
-" s:NetrwOptionSave: save options prior to setting to "netrw-buffer-standard" form {{{2
-" Options get restored by s:NetrwOptionRestore()
-" 06/08/07 : removed call to NetrwSafeOptions(), either placed
-" immediately after NetrwOptionSave() calls in NetRead
-" and NetWrite, or after the s:NetrwEnew() call in
-" NetrwBrowse.
-" vt: normally its "w:" or "s:" (a variable type)
-fun! s:NetrwOptionSave(vt)
-" call Dfunc("s:NetrwOptionSave(vt<".a:vt.">) win#".winnr()." buf#".bufnr("%")."<".bufname(bufnr("%")).">"." winnr($)=".winnr("$")." mod=".&mod." ma=".&ma)
+" s:NetrwOptionsSave: save options prior to setting to "netrw-buffer-standard" form {{{2
+" Options get restored by s:NetrwOptionsRestore()
+"
+" Option handling:
+" * save user's options (s:NetrwOptionsSave)
+" * set netrw-safe options (s:NetrwOptionsSafe)
+" - change an option only when user option != safe option (s:netrwSetSafeSetting)
+" * restore user's options (s:netrwOPtionsRestore)
+" - restore a user option when != safe option (s:NetrwRestoreSetting)
+" vt: (variable type) normally its either "w:" or "s:"
+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>"))
if !exists("{a:vt}netrw_optionsave")
let {a:vt}netrw_optionsave= 1
else
-" call Dret("s:NetrwOptionSave : options already saved")
+" call Dret("s:NetrwOptionsSave : options already saved")
return
endif
" call Decho("prior to save: fo=".&fo.(exists("+acd")? " acd=".&acd : " acd doesn't exist")." diff=".&l:diff,'~'.expand("<slnum>"))
@@ -1707,6 +1642,7 @@ fun! s:NetrwOptionSave(vt)
let {a:vt}netrw_cpokeep = &l:cpo
let {a:vt}netrw_diffkeep = &l:diff
let {a:vt}netrw_fenkeep = &l:fen
+" call Decho("saving current settings: got here#1",'~'.expand("<slnum>"))
if !exists("g:netrw_ffkeep") || g:netrw_ffkeep
let {a:vt}netrw_ffkeep = &l:ff
endif
@@ -1725,12 +1661,10 @@ fun! s:NetrwOptionSave(vt)
let {a:vt}netrw_rokeep = &l:ro
let {a:vt}netrw_selkeep = &l:sel
let {a:vt}netrw_spellkeep = &l:spell
+" call Decho("saving current settings: got here#2",'~'.expand("<slnum>"))
if !g:netrw_use_noswf
let {a:vt}netrw_swfkeep = &l:swf
endif
- if has("clipboard")
- let {a:vt}netrw_starkeep = @*
- endif
let {a:vt}netrw_tskeep = &l:ts
let {a:vt}netrw_twkeep = &l:tw " textwidth
let {a:vt}netrw_wigkeep = &l:wig " wildignore
@@ -1743,48 +1677,53 @@ fun! s:NetrwOptionSave(vt)
let {a:vt}netrw_dirkeep = getcwd()
endif
if has("clipboard")
- if &go =~# 'a' | sil! let {a:vt}netrw_regstar = @* | endif
+ sil! let {a:vt}netrw_starkeep = @*
+ sil! let {a:vt}netrw_pluskeep = @+
endif
- sil! let {a:vt}netrw_regslash= @/
+ sil! let {a:vt}netrw_slashkeep= @/
" 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:NetrwOptionSave : tab#".tabpagenr()." win#".winnr())
+" call Dret("s:NetrwOptionsSave : tab#".tabpagenr()." win#".winnr())
endfun
-" ------------------------------------------------------------------------
-" s:NetrwSafeOptions: sets options to help netrw do its job {{{2
+" ---------------------------------------------------------------------
+" s:NetrwOptionsSafe: sets options to help netrw do its job {{{2
" Use s:NetrwSaveOptions() to save user settings
-" Use s:NetrwOptionRestore() to restore user settings
-fun! s:NetrwSafeOptions()
-" call Dfunc("s:NetrwSafeOptions() win#".winnr()." buf#".bufnr("%")."<".bufname(bufnr("%"))."> winnr($)=".winnr("$"))
+" Use s:NetrwOptionsRestore() to restore user settings
+fun! s:NetrwOptionsSafe(islocal)
+" call Dfunc("s:NetrwOptionsSafe(islocal=".a:islocal.") win#".winnr()." buf#".bufnr("%")."<".bufname(bufnr("%"))."> winnr($)=".winnr("$"))
" call Decho("win#".winnr()."'s ft=".&ft,'~'.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,'~'.expand("<slnum>"))
- if exists("+acd") | setl noacd | endif
- setl noai
- setl noaw
- setl nobl
- setl nobomb
- setl bt=nofile
- setl noci
- setl nocin
- setl bh=hide
- setl cino=
- setl com=
- setl cpo-=a
- setl cpo-=A
+ if exists("+acd") | call s:NetrwSetSafeSetting("&l:acd",0)|endif
+ call s:NetrwSetSafeSetting("&l:ai",0)
+ call s:NetrwSetSafeSetting("&l:aw",0)
+ call s:NetrwSetSafeSetting("&l:bl",0)
+ call s:NetrwSetSafeSetting("&l:bomb",0)
+ if a:islocal
+ call s:NetrwSetSafeSetting("&l:bt","nofile")
+ else
+ call s:NetrwSetSafeSetting("&l:bt","acwrite")
+ endif
+ call s:NetrwSetSafeSetting("&l:ci",0)
+ call s:NetrwSetSafeSetting("&l:cin",0)
+ call s:NetrwSetSafeSetting("&l:bh","hide")
+ 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
- setl nohid
- setl noim
+ call s:NetrwSetSafeSetting("&l:hid",0)
+ call s:NetrwSetSafeSetting("&l:im",0)
setl isk+=@ isk+=* isk+=/
- setl magic
+ call s:NetrwSetSafeSetting("&l:magic",1)
if g:netrw_use_noswf
- setl noswf
+ call s:NetrwSetSafeSetting("swf",0)
endif
- setl report=10000
- setl sel=inclusive
- setl nospell
- setl tw=0
- setl wig=
+ call s:NetrwSetSafeSetting("&l:report",10000)
+ call s:NetrwSetSafeSetting("&l:sel","inclusive")
+ call s:NetrwSetSafeSetting("&l:spell",0)
+ call s:NetrwSetSafeSetting("&l:tw",0)
+ call s:NetrwSetSafeSetting("&l:wig","")
setl cedit&
call s:NetrwCursor()
@@ -1792,12 +1731,194 @@ fun! s:NetrwSafeOptions()
" call Decho("ft<".&ft."> ei=".&ei,'~'.expand("<slnum>"))
if &ft == "netrw"
" call Decho("do any netrw FileType autocmds (doau FileType netrw)",'~'.expand("<slnum>"))
- sil! keepalt NetrwKeepj doau FileType netrw
+ keepalt NetrwKeepj doau FileType netrw
endif
" call Decho("fo=".&fo.(exists("+acd")? " acd=".&acd : " acd doesn't exist")." bh=".&l:bh." bt<".&bt.">",'~'.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,'~'.expand("<slnum>"))
-" call Dret("s:NetrwSafeOptions")
+" call Dret("s:NetrwOptionsSafe")
+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("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("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
+ unlet {a:vt}netrw_optionsave
+
+ if exists("+acd")
+ if exists("{a:vt}netrw_acdkeep")
+" call Decho("g:netrw_keepdir=".g:netrw_keepdir.": getcwd<".getcwd()."> acd=".&acd,'~'.expand("<slnum>"))
+ let curdir = getcwd()
+ let &l:acd = {a:vt}netrw_acdkeep
+ unlet {a:vt}netrw_acdkeep
+ if &l:acd
+ call s:NetrwLcd(curdir)
+ endif
+ endif
+ endif
+ 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 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 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 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_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_writekeep","&l:write")
+ 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
+ " rather than by appending a tab which previously was using "&ts" to set the desired spacing. (Sep 28, 2018)
+ call s:NetrwRestoreSetting(a:vt."netrw_tskeep","&l:ts")
+
+ if exists("{a:vt}netrw_swfkeep")
+ if &directory == ""
+ " user hasn't specified a swapfile directory;
+ " netrw will temporarily set the swapfile directory
+ " to the current directory as returned by getcwd().
+ let &l:directory= getcwd()
+ sil! let &l:swf = {a:vt}netrw_swfkeep
+ setl directory=
+ unlet {a:vt}netrw_swfkeep
+ elseif &l:swf != {a:vt}netrw_swfkeep
+ if !g:netrw_use_noswf
+ " following line causes a Press ENTER in windows -- can't seem to work around it!!!
+ sil! let &l:swf= {a:vt}netrw_swfkeep
+ endif
+ unlet {a:vt}netrw_swfkeep
+ endif
+ endif
+ if exists("{a:vt}netrw_dirkeep") && isdirectory(s:NetrwFile({a:vt}netrw_dirkeep)) && g:netrw_keepdir
+ let dirkeep = substitute({a:vt}netrw_dirkeep,'\\','/','g')
+ if exists("{a:vt}netrw_dirkeep")
+ call s:NetrwLcd(dirkeep)
+ unlet {a:vt}netrw_dirkeep
+ endif
+ endif
+ if has("clipboard")
+ call s:NetrwRestoreSetting(a:vt."netrw_starkeep","@*")
+ call s:NetrwRestoreSetting(a:vt."netrw_pluskeep","@+")
+ endif
+ call s:NetrwRestoreSetting(a:vt."netrw_slashkeep","@/")
+
+" call Decho("g:netrw_keepdir=".g:netrw_keepdir.": getcwd<".getcwd()."> acd=".&acd,'~'.expand("<slnum>"))
+" call Decho("fo=".&fo.(exists("+acd")? " acd=".&acd : " acd doesn't exist"),'~'.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("diff=".&l:diff." win#".winnr()." w:netrw_diffkeep=".(exists("w:netrw_diffkeep")? w:netrw_diffkeep : "doesn't exist"),'~'.expand("<slnum>"))
+" call Decho("ts=".&l:ts,'~'.expand("<slnum>"))
+ " Moved the filetype detect here from NetrwGetFile() because remote files
+ " were having their filetype detect-generated settings overwritten by
+ " NetrwOptionRestore.
+ if &ft != "netrw"
+" call Decho("filetype detect (ft=".&ft.")",'~'.expand("<slnum>"))
+ filetype detect
+ endif
+" 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
+
+" ---------------------------------------------------------------------
+" s:NetrwSetSafeSetting: sets an option to a safe setting {{{2
+" but only when the options' value and the safe setting differ
+" Doing this means that netrw will not come up as having changed a
+" setting last when it really didn't actually change it.
+"
+" Called from s:NetrwOptionsSafe
+" ex. call s:NetrwSetSafeSetting("&l:sel","inclusive")
+fun! s:NetrwSetSafeSetting(setting,safesetting)
+" call Dfunc("s:NetrwSetSafeSetting(setting<".a:setting."> safesetting<".a:safesetting.">)")
+
+ if a:setting =~ '^&'
+" call Decho("fyi: a:setting starts with &")
+ exe "let settingval= ".a:setting
+" call Decho("fyi: settingval<".settingval.">")
+
+ if settingval != a:safesetting
+" call Decho("set setting<".a:setting."> to option value<".a:safesetting.">")
+ if type(a:safesetting) == 0
+ exe "let ".a:setting."=".a:safesetting
+ elseif type(a:safesetting) == 1
+ exe "let ".a:setting."= '".a:safesetting."'"
+ else
+ call netrw#ErrorMsg(s:ERROR,"(s:NetrwRestoreSetting) doesn't know how to restore ".a:setting." with a safesetting of type#".type(a:safesetting),105)
+ endif
+ endif
+ endif
+
+" call Dret("s:NetrwSetSafeSetting")
+endfun
+
+" ------------------------------------------------------------------------
+" s:NetrwRestoreSetting: restores specified setting using associated keepvar, {{{2
+" but only if the setting value differs from the associated keepvar.
+" Doing this means that netrw will not come up as having changed a
+" setting last when it really didn't actually change it.
+"
+" Used by s:NetrwOptionsRestore() to restore each netrw-senstive setting
+" keepvars are set up by s:NetrwOptionsSave
+fun! s:NetrwRestoreSetting(keepvar,setting)
+"" call Dfunc("s:NetrwRestoreSetting(a:keepvar<".a:keepvar."> a:setting<".a: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
+ if exists(a:keepvar)
+ exe "let keepvarval= ".a:keepvar
+ exe "let setting= ".a:setting
+
+"" call Decho("fyi: a:keepvar<".a:keepvar."> exists")
+"" call Decho("fyi: keepvarval=".keepvarval)
+"" call Decho("fyi: a:setting<".a:setting."> setting<".setting.">")
+
+ if setting != keepvarval
+"" call Decho("restore setting<".a:setting."=".setting."> to keepvarval<".keepvarval.">")
+ if type(a:setting) == 0
+ exe "let ".a:setting."= ".keepvarval
+ elseif type(a:setting) == 1
+ exe "let ".a:setting."= '".keepvarval."'"
+ else
+ call netrw#ErrorMsg(s:ERROR,"(s:NetrwRestoreSetting) doesn't know how to restore ".a:keepvar." with a setting of type#".type(a:setting),105)
+ endif
+ endif
+
+ exe "unlet ".a:keepvar
+ endif
+
+"" call Dret("s:NetrwRestoreSetting")
endfun
" ---------------------------------------------------------------------
@@ -1833,7 +1954,7 @@ fun! NetrwStatusLine()
endif
endfun
-" ---------------------------------------------------------------------
+" ===============================
" Netrw Transfer Functions: {{{1
" ===============================
@@ -1847,13 +1968,13 @@ fun! netrw#NetRead(mode,...)
" call Dfunc("netrw#NetRead(mode=".a:mode.",...) a:0=".a:0." ".g:loaded_netrw.((a:0 > 0)? " a:1<".a:1.">" : ""))
" NetRead: save options {{{3
- call s:NetrwOptionSave("w:")
- call s:NetrwSafeOptions()
+ call s:NetrwOptionsSave("w:")
+ call s:NetrwOptionsSafe(0)
call s:RestoreCursorline()
" NetrwSafeOptions sets a buffer up for a netrw listing, which includes buflisting off.
" However, this setting is not wanted for a remote editing session. The buffer should be "nofile", still.
setl bl
-" call Decho("(netrw#NetRead) buf#".bufnr("%")."<".bufname("%")."> bl=".&bl." bt=".&bt." bh=".&bh,'~'.expand("<slnum>"))
+" call Decho("buf#".bufnr("%")."<".bufname("%")."> bl=".&bl." bt=".&bt." bh=".&bh,'~'.expand("<slnum>"))
" NetRead: interpret mode into a readcmd {{{3
if a:mode == 0 " read remote file before current line
@@ -1943,7 +2064,7 @@ fun! netrw#NetRead(mode,...)
" NetRead: Determine method of read (ftp, rcp, etc) {{{3
call s:NetrwMethod(choice)
if !exists("b:netrw_method") || b:netrw_method < 0
-" call Dfunc("netrw#NetRead : unsupported method")
+" call Dret("netrw#NetRead : unsupported method")
return
endif
let tmpfile= s:GetTempfile(b:netrw_fname) " apply correct suffix
@@ -2103,7 +2224,7 @@ fun! netrw#NetRead(mode,...)
else
let tmpfile_get = tmpfile
endif
- call s:NetrwExe(s:netrw_silentxfer."!".g:netrw_scp_cmd.useport." ".s:ShellEscape(g:netrw_machine.":".b:netrw_fname,1)." ".s:ShellEscape(tmpfile_get,1))
+ call s:NetrwExe(s:netrw_silentxfer."!".g:netrw_scp_cmd.useport." ".escape(s:ShellEscape(g:netrw_machine.":".b:netrw_fname,1),' ')." ".s:ShellEscape(tmpfile_get,1))
let result = s:NetrwGetFile(readcmd, tmpfile, b:netrw_method)
let b:netrw_lastfile = choice
@@ -2185,7 +2306,7 @@ fun! netrw#NetRead(mode,...)
" NetRead: (rsync) NetRead Method #7 {{{3
elseif b:netrw_method == 7
" call Decho("read via rsync (method #7)",'~'.expand("<slnum>"))
- call s:NetrwExe(s:netrw_silentxfer."!".g:netrw_rsync_cmd." ".s:ShellEscape(g:netrw_machine.":".b:netrw_fname,1)." ".s:ShellEscape(tmpfile,1))
+ call s:NetrwExe(s:netrw_silentxfer."!".g:netrw_rsync_cmd." ".s:ShellEscape(g:netrw_machine.g:netrw_rsync_sep.b:netrw_fname,1)." ".s:ShellEscape(tmpfile,1))
let result = s:NetrwGetFile(readcmd,tmpfile, b:netrw_method)
let b:netrw_lastfile = choice
@@ -2252,7 +2373,7 @@ fun! netrw#NetRead(mode,...)
" call Decho("cleanup by deleting tmpfile<".tmpfile.">",'~'.expand("<slnum>"))
NetrwKeepj call s:NetrwDelete(tmpfile)
endif
- NetrwKeepj call s:NetrwOptionRestore("w:")
+ NetrwKeepj call s:NetrwOptionsRestore("w:")
" call Dret("netrw#NetRead :5 getcwd<".getcwd().">")
endfun
@@ -2264,8 +2385,8 @@ fun! netrw#NetWrite(...) range
" NetWrite: option handling {{{3
let mod= 0
- call s:NetrwOptionSave("w:")
- call s:NetrwSafeOptions()
+ call s:NetrwOptionsSave("w:")
+ call s:NetrwOptionsSafe(0)
" NetWrite: Get Temporary Filename {{{3
let tmpfile= s:GetTempfile("")
@@ -2374,7 +2495,7 @@ fun! netrw#NetWrite(...) range
" ============================
if exists("g:netrw_silent") && g:netrw_silent == 0 && &ch >= 1
echo "(netrw) Processing your write request..."
-" call Decho("(netrw) Processing your write request...",'~'.expand("<slnum>"))
+" call Decho("Processing your write request...",'~'.expand("<slnum>"))
endif
".........................................
@@ -2527,7 +2648,7 @@ fun! netrw#NetWrite(...) range
let url= g:netrw_choice
call s:NetrwExe(s:netrw_silentxfer."!".g:netrw_http_put_cmd." ".s:ShellEscape(tmpfile,1)." ".s:ShellEscape(url,1) )
elseif !exists("g:netrw_quiet")
- call netrw#ErrorMsg(s:ERROR,"can't write to http using <".g:netrw_http_put_cmd".">".",16)
+ call netrw#ErrorMsg(s:ERROR,"can't write to http using <".g:netrw_http_put_cmd.">".",16)
endif
".........................................
@@ -2571,7 +2692,7 @@ fun! netrw#NetWrite(...) range
" NetWrite: (rsync) NetWrite Method #7 {{{3
elseif b:netrw_method == 7
" call Decho("write via rsync (method #7)",'~'.expand("<slnum>"))
- call s:NetrwExe(s:netrw_silentxfer."!".g:netrw_rsync_cmd." ".s:ShellEscape(tmpfile,1)." ".s:ShellEscape(g:netrw_machine.":".b:netrw_fname,1))
+ call s:NetrwExe(s:netrw_silentxfer."!".g:netrw_rsync_cmd." ".s:ShellEscape(tmpfile,1)." ".s:ShellEscape(g:netrw_machine.g:netrw_rsync_sep.b:netrw_fname,1))
let b:netrw_lastfile = choice
".........................................
@@ -2616,7 +2737,7 @@ fun! netrw#NetWrite(...) range
" call Decho("tmpfile<".tmpfile."> readable, will now delete it",'~'.expand("<slnum>"))
call s:NetrwDelete(tmpfile)
endif
- call s:NetrwOptionRestore("w:")
+ call s:NetrwOptionsRestore("w:")
if a:firstline == 1 && a:lastline == line("$")
" restore modifiability; usually equivalent to set nomod
@@ -2676,9 +2797,13 @@ endfun
" ---------------------------------------------------------------------
" netrw#SetTreetop: resets the tree top to the current directory/specified directory {{{2
" (implements the :Ntree command)
-fun! netrw#SetTreetop(...)
-" call Dfunc("netrw#SetTreetop(".((a:0 > 0)? a:1 : "").") a:0=".a:0)
+fun! netrw#SetTreetop(iscmd,...)
+" call Dfunc("netrw#SetTreetop(iscmd=".a:iscmd." ".((a:0 > 0)? a:1 : "").") a:0=".a:0)
+" call Decho("w:netrw_treetop<".w:netrw_treetop.">")
+ " iscmd==0: netrw#SetTreetop called using gn mapping
+ " iscmd==1: netrw#SetTreetop called using :Ntree from the command line
+" call Decho("(iscmd=".a:iscmd.": called using :Ntree from command line",'~'.expand("<slnum>"))
" clear out the current tree
if exists("w:netrw_treetop")
" call Decho("clearing out current tree",'~'.expand("<slnum>"))
@@ -2689,8 +2814,9 @@ fun! netrw#SetTreetop(...)
" call Decho("freeing w:netrw_treedict",'~'.expand("<slnum>"))
unlet w:netrw_treedict
endif
+" call Decho("inittreetop<".(exists("inittreetop")? inittreetop : "n/a").">")
- if a:1 == "" && exists("inittreetop")
+ if (a:iscmd == 0 || a:1 == "") && exists("inittreetop")
let treedir= s:NetrwTreePath(inittreetop)
" call Decho("treedir<".treedir.">",'~'.expand("<slnum>"))
else
@@ -2699,7 +2825,7 @@ fun! netrw#SetTreetop(...)
let treedir= a:1
elseif exists("b:netrw_curdir") && (isdirectory(s:NetrwFile(b:netrw_curdir."/".a:1)) || a:1 =~ '^\a\{3,}://')
let treedir= b:netrw_curdir."/".a:1
-" call Decho("a:1<".a:1."> is NOT a directory, trying treedir<".treedir.">",'~'.expand("<slnum>"))
+" 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.
" However, here this results in the directory being listed in the message window, which is not wanted.
@@ -2710,13 +2836,18 @@ fun! netrw#SetTreetop(...)
endif
endif
" call Decho("treedir<".treedir.">",'~'.expand("<slnum>"))
+
+ " determine if treedir is remote or local
let islocal= expand("%") !~ '^\a\{3,}://'
" call Decho("islocal=".islocal,'~'.expand("<slnum>"))
+
+ " browse the resulting directory
if islocal
call netrw#LocalBrowseCheck(s:NetrwBrowseChgDir(islocal,treedir))
else
call s:NetrwBrowse(islocal,s:NetrwBrowseChgDir(islocal,treedir))
endif
+
" call Dret("netrw#SetTreetop")
endfun
@@ -2755,8 +2886,7 @@ fun! s:NetrwGetFile(readcmd, tfile, method)
else
let tfile= a:tfile
endif
-" call Decho("exe sil! keepalt file ".fnameescape(tfile),'~'.expand("<slnum>"))
- exe "sil! keepalt file ".fnameescape(tfile)
+ call s:NetrwBufRename(tfile)
" edit temporary file (ie. read the temporary file in)
if rfile =~ '\.zip$'
@@ -2783,8 +2913,7 @@ fun! s:NetrwGetFile(readcmd, tfile, method)
endif
" rename buffer back to remote filename
-" call Decho("exe sil! keepalt file ".fnameescape(rfile),'~'.expand("<slnum>"))
- exe "sil! NetrwKeepj keepalt file ".fnameescape(rfile)
+ call s:NetrwBufRename(rfile)
" Detect filetype of local version of remote file.
" Note that isk must not include a "/" for scripts.vim
@@ -2793,7 +2922,7 @@ fun! s:NetrwGetFile(readcmd, tfile, method)
let iskkeep= &l:isk
setl isk-=/
let &l:isk= iskkeep
-" call Dredir("renamed buffer back to remote filename<".rfile."> : expand(%)<".expand("%").">","ls!")
+" call Dredir("ls!","NetrwGetFile (renamed buffer back to remote filename<".rfile."> : expand(%)<".expand("%").">)")
let line1 = 1
let line2 = line("$")
@@ -2864,13 +2993,13 @@ endfun
" g:netrw_port = optional port number (for ftp)
" g:netrw_choice = copy of input url (choice)
fun! s:NetrwMethod(choice)
-" call Dfunc("NetrwMethod(a:choice<".a:choice.">)")
+" call Dfunc("s:NetrwMethod(a:choice<".a:choice.">)")
" sanity check: choice should have at least three slashes in it
if strlen(substitute(a:choice,'[^/]','','g')) < 3
call netrw#ErrorMsg(s:ERROR,"not a netrw-style url; netrw uses protocol://[user@]hostname[:port]/[path])",78)
let b:netrw_method = -1
-" call Dret("NetrwMethod : incorrect url format<".a:choice.">")
+" call Dret("s:NetrwMethod : incorrect url format<".a:choice.">")
return
endif
@@ -2983,7 +3112,7 @@ fun! s:NetrwMethod(choice)
endif
if curmachine != g:netrw_machine
- if exists("s:netwr_hup[".g:netrw_machine."]")
+ if exists("s:netrw_hup[".g:netrw_machine."]")
call NetUserPass("ftp:".g:netrw_machine)
elseif exists("s:netrw_passwd")
" if there's a change in hostname, require password re-entry
@@ -3113,7 +3242,7 @@ fun! s:NetrwMethod(choice)
" call Decho("s:netrw_passwd <".s:netrw_passwd.">",'~'.expand("<slnum>"))
" endif "Decho
" call Decho("b:netrw_fname <".b:netrw_fname.">",'~'.expand("<slnum>"))
-" call Dret("NetrwMethod : b:netrw_method=".b:netrw_method." g:netrw_port=".g:netrw_port)
+" call Dret("s:NetrwMethod : b:netrw_method=".b:netrw_method." g:netrw_port=".g:netrw_port)
endfun
" ------------------------------------------------------------------------
@@ -3257,9 +3386,9 @@ fun! NetUserPass(...)
" call Dret("NetUserPass : uid<".g:netrw_uid."> passwd<".s:netrw_passwd.">")
endfun
-" ===========================================
+" =================================
" Shared Browsing Support: {{{1
-" ===========================================
+" =================================
" ---------------------------------------------------------------------
" s:ExplorePatHls: converts an Explore pattern into a regular expression search pattern {{{2
@@ -3284,7 +3413,7 @@ endfun
" 5: (user: <U>) go down (next) directory, using history
" 6: (user: <mB>) delete bookmark
fun! s:NetrwBookHistHandler(chg,curdir)
-" call Dfunc("s:NetrwBookHistHandler(chg=".a:chg." curdir<".a:curdir.">) cnt=".v:count." histcnt=".g:netrw_dirhist_cnt." histmax=".g:netrw_dirhistmax)
+" call Dfunc("s:NetrwBookHistHandler(chg=".a:chg." curdir<".a:curdir.">) cnt=".v:count." histcnt=".g:netrw_dirhistcnt." histmax=".g:netrw_dirhistmax)
if !exists("g:netrw_dirhistmax") || g:netrw_dirhistmax <= 0
" " call Dret("s:NetrwBookHistHandler - suppressed due to g:netrw_dirhistmax")
return
@@ -3331,12 +3460,14 @@ fun! s:NetrwBookHistHandler(chg,curdir)
endif
" list directory history
- let cnt = g:netrw_dirhist_cnt
+ " Note: history is saved only when PerformListing is done;
+ " ie. when netrw can re-use a netrw buffer, the current directory is not saved in the history.
+ let cnt = g:netrw_dirhistcnt
let first = 1
let histcnt = 0
if g:netrw_dirhistmax > 0
- while ( first || cnt != g:netrw_dirhist_cnt )
-" call Decho("first=".first." cnt=".cnt." dirhist_cnt=".g:netrw_dirhist_cnt,'~'.expand("<slnum>"))
+ while ( first || cnt != g:netrw_dirhistcnt )
+" call Decho("first=".first." cnt=".cnt." dirhistcnt=".g:netrw_dirhistcnt,'~'.expand("<slnum>"))
if exists("g:netrw_dirhist_{cnt}")
" call Decho("Netrw History#".histcnt.": ".g:netrw_dirhist_{cnt},'~'.expand("<slnum>"))
echo printf("Netrw History#%-2d: %s",histcnt,g:netrw_dirhist_{cnt})
@@ -3350,7 +3481,7 @@ fun! s:NetrwBookHistHandler(chg,curdir)
endif
endwhile
else
- let g:netrw_dirhist_cnt= 0
+ let g:netrw_dirhistcnt= 0
endif
if didwork
call inputsave()|call input("Press <cr> to continue")|call inputrestore()
@@ -3359,27 +3490,27 @@ fun! s:NetrwBookHistHandler(chg,curdir)
elseif a:chg == 3
" saves most recently visited directories (when they differ)
" call Decho("(browsing) record curdir history",'~'.expand("<slnum>"))
- if !exists("g:netrw_dirhist_cnt") || !exists("g:netrw_dirhist_{g:netrw_dirhist_cnt}") || g:netrw_dirhist_{g:netrw_dirhist_cnt} != a:curdir
+ if !exists("g:netrw_dirhistcnt") || !exists("g:netrw_dirhist_{g:netrw_dirhistcnt}") || g:netrw_dirhist_{g:netrw_dirhistcnt} != a:curdir
if g:netrw_dirhistmax > 0
- let g:netrw_dirhist_cnt = ( g:netrw_dirhist_cnt + 1 ) % g:netrw_dirhistmax
- let g:netrw_dirhist_{g:netrw_dirhist_cnt} = a:curdir
+ let g:netrw_dirhistcnt = ( g:netrw_dirhistcnt + 1 ) % g:netrw_dirhistmax
+ let g:netrw_dirhist_{g:netrw_dirhistcnt} = a:curdir
endif
-" call Decho("save dirhist#".g:netrw_dirhist_cnt."<".g:netrw_dirhist_{g:netrw_dirhist_cnt}.">",'~'.expand("<slnum>"))
+" call Decho("save dirhist#".g:netrw_dirhistcnt."<".g:netrw_dirhist_{g:netrw_dirhistcnt}.">",'~'.expand("<slnum>"))
endif
elseif a:chg == 4
" u: change to the previous directory stored on the history list
" call Decho("(user: <u>) chg to prev dir from history",'~'.expand("<slnum>"))
if g:netrw_dirhistmax > 0
- let g:netrw_dirhist_cnt= ( g:netrw_dirhist_cnt - v:count1 ) % g:netrw_dirhistmax
- if g:netrw_dirhist_cnt < 0
- let g:netrw_dirhist_cnt= g:netrw_dirhist_cnt + g:netrw_dirhistmax
+ let g:netrw_dirhistcnt= ( g:netrw_dirhistcnt - v:count1 ) % g:netrw_dirhistmax
+ if g:netrw_dirhistcnt < 0
+ let g:netrw_dirhistcnt= g:netrw_dirhistcnt + g:netrw_dirhistmax
endif
else
- let g:netrw_dirhist_cnt= 0
+ let g:netrw_dirhistcnt= 0
endif
- if exists("g:netrw_dirhist_{g:netrw_dirhist_cnt}")
-" call Decho("changedir u#".g:netrw_dirhist_cnt."<".g:netrw_dirhist_{g:netrw_dirhist_cnt}.">",'~'.expand("<slnum>"))
+ if exists("g:netrw_dirhist_{g:netrw_dirhistcnt}")
+" call Decho("changedir u#".g:netrw_dirhistcnt."<".g:netrw_dirhist_{g:netrw_dirhistcnt}.">",'~'.expand("<slnum>"))
if exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST && exists("b:netrw_curdir")
setl ma noro
" call Decho("setl ma noro",'~'.expand("<slnum>"))
@@ -3388,13 +3519,13 @@ fun! s:NetrwBookHistHandler(chg,curdir)
" call Decho("setl nomod",'~'.expand("<slnum>"))
" call Decho(" ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("<slnum>"))
endif
-" call Decho("exe e! ".fnameescape(g:netrw_dirhist_{g:netrw_dirhist_cnt}),'~'.expand("<slnum>"))
- exe "NetrwKeepj e! ".fnameescape(g:netrw_dirhist_{g:netrw_dirhist_cnt})
+" call Decho("exe e! ".fnameescape(g:netrw_dirhist_{g:netrw_dirhistcnt}),'~'.expand("<slnum>"))
+ exe "NetrwKeepj e! ".fnameescape(g:netrw_dirhist_{g:netrw_dirhistcnt})
else
if g:netrw_dirhistmax > 0
- let g:netrw_dirhist_cnt= ( g:netrw_dirhist_cnt + v:count1 ) % g:netrw_dirhistmax
+ let g:netrw_dirhistcnt= ( g:netrw_dirhistcnt + v:count1 ) % g:netrw_dirhistmax
else
- let g:netrw_dirhist_cnt= 0
+ let g:netrw_dirhistcnt= 0
endif
echo "Sorry, no predecessor directory exists yet"
endif
@@ -3403,9 +3534,9 @@ fun! s:NetrwBookHistHandler(chg,curdir)
" U: change to the subsequent directory stored on the history list
" call Decho("(user: <U>) chg to next dir from history",'~'.expand("<slnum>"))
if g:netrw_dirhistmax > 0
- let g:netrw_dirhist_cnt= ( g:netrw_dirhist_cnt + 1 ) % g:netrw_dirhistmax
- if exists("g:netrw_dirhist_{g:netrw_dirhist_cnt}")
-" call Decho("changedir U#".g:netrw_dirhist_cnt."<".g:netrw_dirhist_{g:netrw_dirhist_cnt}.">",'~'.expand("<slnum>"))
+ let g:netrw_dirhistcnt= ( g:netrw_dirhistcnt + 1 ) % g:netrw_dirhistmax
+ if exists("g:netrw_dirhist_{g:netrw_dirhistcnt}")
+" call Decho("changedir U#".g:netrw_dirhistcnt."<".g:netrw_dirhist_{g:netrw_dirhistcnt}.">",'~'.expand("<slnum>"))
if exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST && exists("b:netrw_curdir")
" call Decho("setl ma noro",'~'.expand("<slnum>"))
setl ma noro
@@ -3415,17 +3546,17 @@ fun! s:NetrwBookHistHandler(chg,curdir)
setl nomod
" call Decho("(set nomod) ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("<slnum>"))
endif
-" call Decho("exe e! ".fnameescape(g:netrw_dirhist_{g:netrw_dirhist_cnt}),'~'.expand("<slnum>"))
- exe "NetrwKeepj e! ".fnameescape(g:netrw_dirhist_{g:netrw_dirhist_cnt})
+" call Decho("exe e! ".fnameescape(g:netrw_dirhist_{g:netrw_dirhistcnt}),'~'.expand("<slnum>"))
+ exe "NetrwKeepj e! ".fnameescape(g:netrw_dirhist_{g:netrw_dirhistcnt})
else
- let g:netrw_dirhist_cnt= ( g:netrw_dirhist_cnt - 1 ) % g:netrw_dirhistmax
- if g:netrw_dirhist_cnt < 0
- let g:netrw_dirhist_cnt= g:netrw_dirhist_cnt + g:netrw_dirhistmax
+ let g:netrw_dirhistcnt= ( g:netrw_dirhistcnt - 1 ) % g:netrw_dirhistmax
+ if g:netrw_dirhistcnt < 0
+ let g:netrw_dirhistcnt= g:netrw_dirhistcnt + g:netrw_dirhistmax
endif
echo "Sorry, no successor directory exists yet"
endif
else
- let g:netrw_dirhist_cnt= 0
+ let g:netrw_dirhistcnt= 0
echo "Sorry, no successor directory exists yet (g:netrw_dirhistmax is ".g:netrw_dirhistmax.")"
endif
@@ -3460,10 +3591,12 @@ endfun
fun! s:NetrwBookHistRead()
" call Dfunc("s:NetrwBookHistRead()")
if !exists("g:netrw_dirhistmax") || g:netrw_dirhistmax <= 0
-" " call Dret("s:NetrwBookHistRead - suppressed due to g:netrw_dirhistmax")
+" call Dret("s:NetrwBookHistRead - nothing read (suppressed due to dirhistmax=".(exists("g:netrw_dirhistmax")? g:netrw_dirhistmax : "n/a").")")
return
endif
let ykeep= @@
+
+ " read bookmarks
if !exists("s:netrw_initbookhist")
let home = s:NetrwHome()
let savefile= home."/.netrwbook"
@@ -3471,6 +3604,8 @@ fun! s:NetrwBookHistRead()
" call Decho("sourcing .netrwbook",'~'.expand("<slnum>"))
exe "keepalt NetrwKeepj so ".savefile
endif
+
+ " read history
if g:netrw_dirhistmax > 0
let savefile= home."/.netrwhist"
if filereadable(s:NetrwFile(savefile))
@@ -3481,27 +3616,33 @@ fun! s:NetrwBookHistRead()
au VimLeave * call s:NetrwBookHistSave()
endif
endif
+
let @@= ykeep
+" call Decho("dirhistmax=".(exists("g:netrw_dirhistmax")? g:netrw_dirhistmax : "n/a"),'~'.expand("<slnum>"))
+" call Decho("dirhistcnt=".(exists("g:netrw_dirhistcnt")? g:netrw_dirhistcnt : "n/a"),'~'.expand("<slnum>"))
" call Dret("s:NetrwBookHistRead")
endfun
" ---------------------------------------------------------------------
-" s:NetrwBookHistSave: this function saves bookmarks and history {{{2
+" s:NetrwBookHistSave: this function saves bookmarks and history to files {{{2
" Sister function: s:NetrwBookHistRead()
" I used to do this via viminfo but that appears to
" be unreliable for long-term storage
" If g:netrw_dirhistmax is <= 0, no history or bookmarks
" will be saved.
+" (s:NetrwBookHistHandler(3,...) used to record history)
fun! s:NetrwBookHistSave()
-" call Dfunc("s:NetrwBookHistSave() dirhistmax=".g:netrw_dirhistmax)
+" call Dfunc("s:NetrwBookHistSave() dirhistmax=".g:netrw_dirhistmax." dirhistcnt=".g:netrw_dirhistcnt)
if !exists("g:netrw_dirhistmax") || g:netrw_dirhistmax <= 0
-" call Dret("s:NetrwBookHistSave : dirhistmax=".g:netrw_dirhistmax)
+" call Dret("s:NetrwBookHistSave : nothing saved (dirhistmax=".g:netrw_dirhistmax.")")
return
endif
let savefile= s:NetrwHome()."/.netrwhist"
+" call Decho("savefile<".savefile.">",'~'.expand("<slnum>"))
1split
call s:NetrwEnew()
+" call Decho("case g:netrw_use_noswf=".g:netrw_use_noswf.(exists("+acd")? " +acd" : " -acd"),'~'.expand("<slnum>"))
if g:netrw_use_noswf
setl cino= com= cpo-=a cpo-=A fo=nroql2 tw=0 report=10000 noswf
else
@@ -3512,20 +3653,37 @@ fun! s:NetrwBookHistSave()
if exists("+acd") | setl noacd | endif
sil! NetrwKeepj keepalt %d _
- " save .netrwhist -- no attempt to merge
+ " rename enew'd file: .netrwhist -- no attempt to merge
+ " record dirhistmax and current dirhistcnt
+ " save history
+" call Decho("saving history: dirhistmax=".g:netrw_dirhistmax." dirhistcnt=".g:netrw_dirhistcnt." lastline=".line("$"),'~'.expand("<slnum>"))
sil! keepalt file .netrwhist
call setline(1,"let g:netrw_dirhistmax =".g:netrw_dirhistmax)
- call setline(2,"let g:netrw_dirhist_cnt =".g:netrw_dirhist_cnt)
- let lastline = line("$")
- let cnt = 1
- while cnt <= g:netrw_dirhist_cnt
- call setline((cnt+lastline),'let g:netrw_dirhist_'.cnt."='".g:netrw_dirhist_{cnt}."'")
- let cnt= cnt + 1
- endwhile
- exe "sil! w! ".savefile
+ call setline(2,"let g:netrw_dirhistcnt =".g:netrw_dirhistcnt)
+ if g:netrw_dirhistmax > 0
+ let lastline = line("$")
+ let cnt = g:netrw_dirhistcnt
+ let first = 1
+ while ( first || cnt != g:netrw_dirhistcnt )
+ let lastline= lastline + 1
+ if exists("g:netrw_dirhist_{cnt}")
+ call setline(lastline,'let g:netrw_dirhist_'.cnt."='".g:netrw_dirhist_{cnt}."'")
+" call Decho("..".lastline.'let g:netrw_dirhist_'.cnt."='".g:netrw_dirhist_{cnt}."'",'~'.expand("<slnum>"))
+ endif
+ let first = 0
+ let cnt = ( cnt - 1 ) % g:netrw_dirhistmax
+ if cnt < 0
+ let cnt= cnt + g:netrw_dirhistmax
+ endif
+ endwhile
+ exe "sil! w! ".savefile
+" call Decho("exe sil! w! ".savefile,'~'.expand("<slnum>"))
+ endif
+ " save bookmarks
sil NetrwKeepj %d _
if exists("g:netrw_bookmarklist") && g:netrw_bookmarklist != []
+" call Decho("saving bookmarks",'~'.expand("<slnum>"))
" merge and write .netrwbook
let savefile= s:NetrwHome()."/.netrwbook"
@@ -3543,7 +3701,10 @@ fun! s:NetrwBookHistSave()
" construct and save .netrwbook
call setline(1,"let g:netrw_bookmarklist= ".string(g:netrw_bookmarklist))
exe "sil! w! ".savefile
+" call Decho("exe sil! w! ".savefile,'~'.expand("<slnum>"))
endif
+
+ " cleanup -- remove buffer used to construct history
let bgone= bufnr("%")
q!
exe "keepalt ".bgone."bwipe!"
@@ -3560,9 +3721,9 @@ endfun
fun! s:NetrwBrowse(islocal,dirname)
if !exists("w:netrw_liststyle")|let w:netrw_liststyle= g:netrw_liststyle|endif
" call Dfunc("s:NetrwBrowse(islocal=".a:islocal." dirname<".a:dirname.">) liststyle=".w:netrw_liststyle." ".g:loaded_netrw." buf#".bufnr("%")."<".bufname("%")."> win#".winnr())
-" call Decho("modified=".&modified." modifiable=".&modifiable." readonly=".&readonly,'~'.expand("<slnum>"))
-" call Decho("tab#".tabpagenr()." win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> line#".line(".")." col#".col(".")." winline#".winline()." wincol#".wincol(),'~'.expand("<slnum>"))
-" call Dredir("ls!")
+" call Decho("fyi: modified=".&modified." modifiable=".&modifiable." readonly=".&readonly,'~'.expand("<slnum>"))
+" call Decho("fyi: tab#".tabpagenr()." win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> line#".line(".")." col#".col(".")." winline#".winline()." wincol#".wincol(),'~'.expand("<slnum>"))
+" call Dredir("ls!","s:NetrwBrowse")
" save alternate-file's filename if w:netrw_rexlocal doesn't exist
" This is useful when one edits a local file, then :e ., then :Rex
@@ -3579,18 +3740,24 @@ fun! s:NetrwBrowse(islocal,dirname)
" s:NetrwBrowse : simplify the dirname (especially for ".."s in dirnames) {{{3
if a:dirname !~ '^\a\{3,}://'
let dirname= simplify(a:dirname)
+" call Decho("simplified dirname<".dirname.">")
else
let dirname= a:dirname
endif
+ " repoint t:netrw_lexbufnr if appropriate
+ if exists("t:netrw_lexbufnr") && bufnr("%") == t:netrw_lexbufnr
+" call Decho("set repointlexbufnr to true!")
+ let repointlexbufnr= 1
+ endif
+
+ " s:NetrwBrowse : sanity checks: {{{3
if exists("s:netrw_skipbrowse")
unlet s:netrw_skipbrowse
" 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:NetrwBrowse : s:netrw_skipbrowse existed")
return
endif
-
- " s:NetrwBrowse : sanity checks: {{{3
if !exists("*shellescape")
NetrwKeepj call netrw#ErrorMsg(s:ERROR,"netrw can't run -- your vim is missing shellescape()",69)
" call Dret("s:NetrwBrowse : missing shellescape()")
@@ -3603,20 +3770,25 @@ fun! s:NetrwBrowse(islocal,dirname)
endif
" s:NetrwBrowse : save options: {{{3
- call s:NetrwOptionSave("w:")
+ call s:NetrwOptionsSave("w:")
" s:NetrwBrowse : re-instate any marked files {{{3
- if exists("s:netrwmarkfilelist_{bufnr('%')}")
-" call Decho("clearing marked files",'~'.expand("<slnum>"))
- exe "2match netrwMarkFile /".s:netrwmarkfilemtch_{bufnr("%")}."/"
+ if has("syntax") && exists("g:syntax_on") && g:syntax_on
+ if exists("s:netrwmarkfilelist_{bufnr('%')}")
+" call Decho("clearing marked files",'~'.expand("<slnum>"))
+ exe "2match netrwMarkFile /".s:netrwmarkfilemtch_{bufnr("%")}."/"
+ endif
endif
if a:islocal && exists("w:netrw_acdkeep") && w:netrw_acdkeep
" s:NetrwBrowse : set up "safe" options for local directory/file {{{3
" call Decho("handle w:netrw_acdkeep:",'~'.expand("<slnum>"))
" call Decho("NetrwKeepj lcd ".fnameescape(dirname)." (due to w:netrw_acdkeep=".w:netrw_acdkeep." - acd=".&acd.")",'~'.expand("<slnum>"))
- call s:NetrwLcd(dirname)
- call s:NetrwSafeOptions()
+ if s:NetrwLcd(dirname)
+" call Dret("s:NetrwBrowse : lcd failure")
+ return
+ endif
+ " call s:NetrwOptionsSafe() " tst952 failed with this enabled.
" call Decho("getcwd<".getcwd().">",'~'.expand("<slnum>"))
elseif !a:islocal && dirname !~ '[\/]$' && dirname !~ '^"'
@@ -3638,13 +3810,12 @@ fun! s:NetrwBrowse(islocal,dirname)
" s:NetrwBrowse : remote-read the requested file into current buffer {{{3
call s:NetrwEnew(dirname)
- call s:NetrwSafeOptions()
+ call s:NetrwOptionsSafe(a:islocal)
setl ma noro
" call Decho("setl ma noro",'~'.expand("<slnum>"))
let b:netrw_curdir = dirname
let url = s:method."://".((s:user == "")? "" : s:user."@").s:machine.(s:port ? ":".s:port : "")."/".s:path
-" call Decho("exe sil! keepalt file ".fnameescape(url)." (bt=".&bt.")",'~'.expand("<slnum>"))
- exe "sil! NetrwKeepj keepalt file ".fnameescape(url)
+ call s:NetrwBufRename(url)
exe "sil! NetrwKeepj keepalt doau BufReadPre ".fnameescape(s:fname)
sil call netrw#NetRead(2,url)
" netrw.vim and tar.vim have already handled decompression of the tarball; avoiding gzip.vim error
@@ -3664,7 +3835,7 @@ fun! s:NetrwBrowse(islocal,dirname)
" s:NetrwBrowse : save certain window-oriented variables into buffer-oriented variables {{{3
call s:SetBufWinVars()
- call s:NetrwOptionRestore("w:")
+ call s:NetrwOptionsRestore("w:")
" call Decho("setl ma nomod",'~'.expand("<slnum>"))
setl ma nomod noro
" call Decho(" ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("<slnum>"))
@@ -3691,16 +3862,18 @@ fun! s:NetrwBrowse(islocal,dirname)
let reusing= s:NetrwGetBuffer(a:islocal,dirname)
" maintain markfile highlighting
- if exists("s:netrwmarkfilemtch_{bufnr('%')}") && s:netrwmarkfilemtch_{bufnr("%")} != ""
-" call Decho("bufnr(%)=".bufnr('%'),'~'.expand("<slnum>"))
-" call Decho("exe 2match netrwMarkFile /".s:netrwmarkfilemtch_{bufnr("%")}."/",'~'.expand("<slnum>"))
- exe "2match netrwMarkFile /".s:netrwmarkfilemtch_{bufnr("%")}."/"
- else
-" call Decho("2match none",'~'.expand("<slnum>"))
- 2match none
+ if has("syntax") && exists("g:syntax_on") && g:syntax_on
+ if exists("s:netrwmarkfilemtch_{bufnr('%')}") && s:netrwmarkfilemtch_{bufnr("%")} != ""
+" " call Decho("bufnr(%)=".bufnr('%'),'~'.expand("<slnum>"))
+" " call Decho("exe 2match netrwMarkFile /".s:netrwmarkfilemtch_{bufnr("%")}."/",'~'.expand("<slnum>"))
+ exe "2match netrwMarkFile /".s:netrwmarkfilemtch_{bufnr("%")}."/"
+ else
+" " call Decho("2match none",'~'.expand("<slnum>"))
+ 2match none
+ endif
endif
if reusing && line("$") > 1
- call s:NetrwOptionRestore("w:")
+ call s:NetrwOptionsRestore("w:")
" call Decho("setl noma nomod nowrap",'~'.expand("<slnum>"))
setl noma nomod nowrap
" call Decho("(set noma nomod nowrap) ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("<slnum>"))
@@ -3746,7 +3919,10 @@ fun! s:NetrwBrowse(islocal,dirname)
" call Decho("handle g:netrw_keepdir=".g:netrw_keepdir.": getcwd<".getcwd()."> acd=".&acd,'~'.expand("<slnum>"))
" call Decho("l:acd".(exists("&l:acd")? "=".&l:acd : " doesn't exist"),'~'.expand("<slnum>"))
if !exists("&l:acd") || !&l:acd
- call s:NetrwLcd(b:netrw_curdir)
+ if s:NetrwLcd(b:netrw_curdir)
+" call Dret("s:NetrwBrowse : lcd failure")
+ return
+ endif
endif
endif
@@ -3778,7 +3954,7 @@ fun! s:NetrwBrowse(islocal,dirname)
if !exists("g:netrw_quiet")
NetrwKeepj call netrw#ErrorMsg(s:ERROR,"netrw doesn't understand your dirname<".dirname.">",20)
endif
- NetrwKeepj call s:NetrwOptionRestore("w:")
+ NetrwKeepj call s:NetrwOptionsRestore("w:")
" call Decho("setl noma nomod nowrap",'~'.expand("<slnum>"))
setl noma nomod nowrap
" call Decho(" ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("<slnum>"))
@@ -3789,15 +3965,15 @@ fun! s:NetrwBrowse(islocal,dirname)
" call Decho("b:netrw_curdir<".b:netrw_curdir."> (remote)",'~'.expand("<slnum>"))
endif " (additional remote handling)
- " -----------------------
- " Directory Listing: {{{3
- " -----------------------
+ " -------------------------------
+ " Perform Directory Listing: {{{3
+ " -------------------------------
NetrwKeepj call s:NetrwMaps(a:islocal)
NetrwKeepj call s:NetrwCommands(a:islocal)
NetrwKeepj call s:PerformListing(a:islocal)
" restore option(s)
- call s:NetrwOptionRestore("w:")
+ call s:NetrwOptionsRestore("w:")
" call Decho("tab#".tabpagenr()." win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> line#".line(".")." col#".col(".")." winline#".winline()." wincol#".wincol(),'~'.expand("<slnum>"))
" If there is a rexposn: restore position with rexposn
@@ -3817,6 +3993,12 @@ fun! s:NetrwBrowse(islocal,dirname)
setl beval
endif
+ " repoint t:netrw_lexbufnr if appropriate
+ if exists("repointlexbufnr")
+ let t:netrw_lexbufnr= bufnr("%")
+" call Decho("repoint t:netrw_lexbufnr to #".t:netrw_lexbufnr)
+ endif
+
" restore position
if reusing
" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
@@ -3824,8 +4006,8 @@ fun! s:NetrwBrowse(islocal,dirname)
endif
" The s:LocalBrowseRefresh() function is called by an autocmd
- " installed by s:LocalFastBrowser() when g:netrw_fastbrowse <= 1 (ie. slow, medium speed).
- " However, s:NetrwBrowse() causes the FocusGained event to fire the firstt time.
+ " installed by s:LocalFastBrowser() when g:netrw_fastbrowse <= 1 (ie. slow or medium speed).
+ " However, s:NetrwBrowse() causes the FocusGained event to fire the first time.
" call Decho("tab#".tabpagenr()." win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> line#".line(".")." col#".col(".")." winline#".winline()." wincol#".wincol(),'~'.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:NetrwBrowse : did PerformListing ft<".&ft.">")
@@ -3837,17 +4019,18 @@ endfun
" may not apply correctly; ie. netrw's idea of the current directory may
" differ from vim's. This function insures that netrw's idea of the current
" directory is used.
+" Returns a path to the file specified by a:fname
fun! s:NetrwFile(fname)
-" call Dfunc("s:NetrwFile(fname<".a:fname.">) win#".winnr())
-" call Decho("g:netrw_keepdir =".(exists("g:netrw_keepdir")? g:netrw_keepdir : 'n/a'),'~'.expand("<slnum>"))
-" call Decho("g:netrw_cygwin =".(exists("g:netrw_cygwin")? g:netrw_cygwin : 'n/a'),'~'.expand("<slnum>"))
-" call Decho("g:netrw_liststyle=".(exists("g:netrw_liststyle")? g:netrw_liststyle : 'n/a'),'~'.expand("<slnum>"))
-" call Decho("w:netrw_liststyle=".(exists("w:netrw_liststyle")? w:netrw_liststyle : 'n/a'),'~'.expand("<slnum>"))
+" "" call Dfunc("s:NetrwFile(fname<".a:fname.">) win#".winnr())
+" "" call Decho("g:netrw_keepdir =".(exists("g:netrw_keepdir")? g:netrw_keepdir : 'n/a'),'~'.expand("<slnum>"))
+" "" call Decho("g:netrw_cygwin =".(exists("g:netrw_cygwin")? g:netrw_cygwin : 'n/a'),'~'.expand("<slnum>"))
+" "" call Decho("g:netrw_liststyle=".(exists("g:netrw_liststyle")? g:netrw_liststyle : 'n/a'),'~'.expand("<slnum>"))
+" "" call Decho("w:netrw_liststyle=".(exists("w:netrw_liststyle")? w:netrw_liststyle : 'n/a'),'~'.expand("<slnum>"))
" clean up any leading treedepthstring
if exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST
let fname= substitute(a:fname,'^'.s:treedepthstring.'\+','','')
-" call Decho("clean up any leading treedepthstring: fname<".fname.">",'~'.expand("<slnum>"))
+" "" call Decho("clean up any leading treedepthstring: fname<".fname.">",'~'.expand("<slnum>"))
else
let fname= a:fname
endif
@@ -3862,31 +4045,31 @@ fun! s:NetrwFile(fname)
if fname =~ '^\' || fname =~ '^\a:\'
" windows, but full path given
let ret= fname
-" call Decho("windows+full path: isdirectory(".fname.")",'~'.expand("<slnum>"))
+" "" call Decho("windows+full path: isdirectory(".fname.")",'~'.expand("<slnum>"))
else
" windows, relative path given
let ret= s:ComposePath(b:netrw_curdir,fname)
-" call Decho("windows+rltv path: isdirectory(".fname.")",'~'.expand("<slnum>"))
+" "" call Decho("windows+rltv path: isdirectory(".fname.")",'~'.expand("<slnum>"))
endif
elseif fname =~ '^/'
" not windows, full path given
let ret= fname
-" call Decho("unix+full path: isdirectory(".fname.")",'~'.expand("<slnum>"))
+" "" call Decho("unix+full path: isdirectory(".fname.")",'~'.expand("<slnum>"))
else
" not windows, relative path given
let ret= s:ComposePath(b:netrw_curdir,fname)
-" call Decho("unix+rltv path: isdirectory(".fname.")",'~'.expand("<slnum>"))
+" "" call Decho("unix+rltv path: isdirectory(".fname.")",'~'.expand("<slnum>"))
endif
else
" vim and netrw agree on the current directory
let ret= fname
-" call Decho("vim and netrw agree on current directory (g:netrw_keepdir=".g:netrw_keepdir.")",'~'.expand("<slnum>"))
-" call Decho("vim directory: ".getcwd(),'~'.expand("<slnum>"))
-" call Decho("netrw directory: ".(exists("b:netrw_curdir")? b:netrw_curdir : 'n/a'),'~'.expand("<slnum>"))
+" "" call Decho("vim and netrw agree on current directory (g:netrw_keepdir=".g:netrw_keepdir.")",'~'.expand("<slnum>"))
+" "" call Decho("vim directory: ".getcwd(),'~'.expand("<slnum>"))
+" "" call Decho("netrw directory: ".(exists("b:netrw_curdir")? b:netrw_curdir : 'n/a'),'~'.expand("<slnum>"))
endif
-" call Dret("s:NetrwFile ".ret)
+" "" call Dret("s:NetrwFile ".ret)
return ret
endfun
@@ -3960,31 +4143,72 @@ fun! s:NetrwFullPath(filename)
endfun
" ---------------------------------------------------------------------
-" s:NetrwGetBuffer: {{{2
+" 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)
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("netrwbuf dictionary=".string(s:netrwbuf),'~'.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
" re-use buffer if possible {{{3
" call Decho("--re-use a buffer if possible--",'~'.expand("<slnum>"))
if !exists("s:netrwbuf")
+" call Decho(" s:netrwbuf initialized to {}",'~'.expand("<slnum>"))
let s:netrwbuf= {}
endif
- if has_key(s:netrwbuf,s:NetrwFullPath(dirname))
+" call Decho(" s:netrwbuf =".string(s:netrwbuf),'~'.expand("<slnum>"))
+" call Decho(" w:netrw_liststyle =".(exists("w:netrw_liststyle")? w:netrw_liststyle : "n/a"),'~'.expand("<slnum>"))
+
+ if exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST
+ let bufnum = -1
+
+ if !empty(s:netrwbuf) && has_key(s:netrwbuf,s:NetrwFullPath(dirname))
+ if has_key(s:netrwbuf,"NetrwTreeListing")
+ let bufnum= s:netrwbuf["NetrwTreeListing"]
+ else
+ let bufnum= s:netrwbuf[s:NetrwFullPath(dirname)]
+ endif
+" call Decho(" NetrwTreeListing: bufnum#".bufnum,'~'.expand("<slnum>"))
+ if !bufexists(bufnum)
+ call remove(s:netrwbuf,"NetrwTreeListing"])
+ let bufnum= -1
+ endif
+ elseif bufnr("NetrwTreeListing") != -1
+ let bufnum= bufnr("NetrwTreeListing")
+" call Decho(" NetrwTreeListing".": bufnum#".bufnum,'~'.expand("<slnum>"))
+ else
+" call Decho(" did not find a NetrwTreeListing buffer",'~'.expand("<slnum>"))
+ let bufnum= -1
+ endif
+
+ elseif has_key(s:netrwbuf,s:NetrwFullPath(dirname))
let bufnum= s:netrwbuf[s:NetrwFullPath(dirname)]
-" call Decho("lookup netrwbuf dictionary: s:netrwbuf[".s:NetrwFullPath(dirname)."]=".bufnum)
+" call Decho(" lookup netrwbuf dictionary: s:netrwbuf[".s:NetrwFullPath(dirname)."]=".bufnum,'~'.expand("<slnum>"))
if !bufexists(bufnum)
call remove(s:netrwbuf,s:NetrwFullPath(dirname))
let bufnum= -1
endif
+
else
-" call Decho("lookup netrwbuf dictionary: s:netrwbuf[".s:NetrwFullPath(dirname)."] not a key")
+" call Decho(" lookup netrwbuf dictionary: s:netrwbuf[".s:NetrwFullPath(dirname)."] not a key",'~'.expand("<slnum>"))
let bufnum= -1
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("%") == ""
+" call Dret("s:NetrwGetBuffer 0<cleared buffer> : highjacking buffer#".bufnr("%"))
+ return 0
+ endif
" get enew buffer and name it -or- re-use buffer {{{3
if bufnum < 0 " get enew buffer and name it
@@ -3995,14 +4219,8 @@ fun! s:NetrwGetBuffer(islocal,dirname)
if exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST
" Got enew buffer; transform into a NetrwTreeListing
" call Decho("--transform enew buffer#".bufnr("%")." into a NetrwTreeListing --",'~'.expand("<slnum>"))
- if !exists("s:netrw_treelistnum")
- let s:netrw_treelistnum= 1
- else
- let s:netrw_treelistnum= s:netrw_treelistnum + 1
- endif
- let w:netrw_treebufnr= bufnr("%")
-" call Decho(" exe sil! keepalt file NetrwTreeListing ".fnameescape(s:netrw_treelistnum),'~'.expand("<slnum>"))
- exe 'sil! keepalt file NetrwTreeListing\ '.fnameescape(s:netrw_treelistnum)
+ let w:netrw_treebufnr = bufnr("%")
+ call s:NetrwBufRename("NetrwTreeListing")
if g:netrw_use_noswf
setl nobl bt=nofile noswf
else
@@ -4012,15 +4230,9 @@ fun! s:NetrwGetBuffer(islocal,dirname)
nnoremap <silent> <buffer> ]] :sil call <SID>TreeListMove(']]')<cr>
nnoremap <silent> <buffer> [] :sil call <SID>TreeListMove('[]')<cr>
nnoremap <silent> <buffer> ][ :sil call <SID>TreeListMove('][')<cr>
-" call Decho(" tree listing#".s:netrw_treelistnum." bufnr=".w:netrw_treebufnr,'~'.expand("<slnum>"))
- else
-" let v:errmsg = "" " Decho
- let escdirname = fnameescape(dirname)
-" call Decho(" errmsg<".v:errmsg."> bufnr(escdirname<".escdirname.">)=".bufnr(escdirname)." bufname()<".bufname(bufnr(escdirname)).">",'~'.expand("<slnum>"))
-" call Decho(' exe sil! keepalt file '.escdirname,'~'.expand("<slnum>"))
-" let v:errmsg= "" " Decho
- exe 'sil! keepj keepalt file '.escdirname
-" call Decho(" errmsg<".v:errmsg."> bufnr(".escdirname.")=".bufnr(escdirname)."<".bufname(bufnr(escdirname)).">",'~'.expand("<slnum>"))
+" call Decho(" tree listing bufnr=".w:netrw_treebufnr,'~'.expand("<slnum>"))
+ else
+ call s:NetrwBufRename(dirname)
" enter the new buffer into the s:netrwbuf dictionary
let s:netrwbuf[s:NetrwFullPath(dirname)]= bufnr("%")
" call Decho("update netrwbuf dictionary: s:netrwbuf[".s:NetrwFullPath(dirname)."]=".bufnr("%"),'~'.expand("<slnum>"))
@@ -4041,8 +4253,7 @@ fun! s:NetrwGetBuffer(islocal,dirname)
endif
" call Decho(" line($)=".line("$"),'~'.expand("<slnum>"))
if bufname("%") == '.'
-" call Decho("exe sil! keepalt file ".fnameescape(getcwd()),'~'.expand("<slnum>"))
- exe "sil! NetrwKeepj keepalt file ".fnameescape(getcwd())
+ call s:NetrwBufRename(getcwd())
endif
let &ei= eikeep
@@ -4066,6 +4277,7 @@ fun! s:NetrwGetBuffer(islocal,dirname)
elseif exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST
" call Decho("--re-use tree listing--",'~'.expand("<slnum>"))
" call Decho(" clear buffer<".expand("%")."> with :%d",'~'.expand("<slnum>"))
+ setl ma
sil NetrwKeepj %d _
NetrwKeepj call s:NetrwListSettings(a:islocal)
" 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>"))
@@ -4089,8 +4301,7 @@ fun! s:NetrwGetBuffer(islocal,dirname)
" call Decho("--do netrw settings: make this buffer#".bufnr("%")." not-a-file, modifiable, not line-numbered, etc--",'~'.expand("<slnum>"))
let fname= expand("%")
NetrwKeepj call s:NetrwListSettings(a:islocal)
-" call Decho("exe sil! keepalt file ".fnameescape(fname),'~'.expand("<slnum>"))
- exe "sil! NetrwKeepj keepalt file ".fnameescape(fname)
+ call s:NetrwBufRename(fname)
" delete all lines from buffer {{{3
" call Decho("--delete all lines from buffer--",'~'.expand("<slnum>"))
@@ -4148,7 +4359,7 @@ fun! s:NetrwGetWord()
let curline= getline('.')
if curline =~# '"\s*Sorted by\s'
- NetrwKeepj norm s
+ NetrwKeepj norm! s
let s:netrw_skipbrowse= 1
echo 'Pressing "s" also works'
@@ -4157,11 +4368,11 @@ fun! s:NetrwGetWord()
echo 'Press "S" to edit sorting sequence'
elseif curline =~# '"\s*Quick Help:'
- NetrwKeepj norm ?
+ NetrwKeepj norm! ?
let s:netrw_skipbrowse= 1
elseif curline =~# '"\s*\%(Hiding\|Showing\):'
- NetrwKeepj norm a
+ NetrwKeepj norm! a
let s:netrw_skipbrowse= 1
echo 'Pressing "a" also works'
@@ -4233,20 +4444,22 @@ fun! s:NetrwGetWord()
endfun
" ---------------------------------------------------------------------
-" s:NetrwListSettings: make standard settings for a netrw listing {{{2
+" s:NetrwListSettings: make standard settings for making a netrw listing {{{2
+" g:netrw_bufsettings will be used after the listing is produced.
+" Called by s:NetrwGetBuffer()
fun! s:NetrwListSettings(islocal)
" call Dfunc("s:NetrwListSettings(islocal=".a:islocal.")")
" 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>"))
let fname= bufname("%")
-" " call Decho("(NetrwListSettings) setl bt=nofile nobl ma nonu nowrap noro nornu",'~'.expand("<slnum>"))
- setl bt=nofile nobl ma nonu nowrap noro nornu
-" call Decho("(NetrwListSettings) exe sil! keepalt file ".fnameescape(fname),'~'.expand("<slnum>"))
- exe "sil! keepalt file ".fnameescape(fname)
+" " call Decho("setl bt=nofile nobl ma nonu nowrap noro nornu",'~'.expand("<slnum>"))
+ " nobl noma nomod nonu noma nowrap ro nornu (std g:netrw_bufsettings)
+ setl bt=nofile nobl ma nonu nowrap noro nornu
+ call s:NetrwBufRename(fname)
if g:netrw_use_noswf
setl noswf
endif
-" call Dredir("ls!")
-" call Decho("(NetrwListSettings) exe setl ts=".(g:netrw_maxfilenamelen+1),'~'.expand("<slnum>"))
+" call Dredir("ls!","s:NetrwListSettings")
+" call Decho("exe setl ts=".(g:netrw_maxfilenamelen+1),'~'.expand("<slnum>"))
exe "setl ts=".(g:netrw_maxfilenamelen+1)
setl isk+=.,~,-
if g:netrw_fastbrowse > a:islocal
@@ -4259,7 +4472,7 @@ fun! s:NetrwListSettings(islocal)
endfun
" ---------------------------------------------------------------------
-" s:NetrwListStyle: {{{2
+" s:NetrwListStyle: change list style (thin - long - wide - tree) {{{2
" islocal=0: remote browsing
" =1: local browsing
fun! s:NetrwListStyle(islocal)
@@ -4275,6 +4488,12 @@ fun! s:NetrwListStyle(islocal)
" call Decho("chgd w:netrw_liststyle to ".w:netrw_liststyle,'~'.expand("<slnum>"))
" call Decho("b:netrw_curdir<".(exists("b:netrw_curdir")? b:netrw_curdir : "doesn't exist").">",'~'.expand("<slnum>"))
+ " repoint t:netrw_lexbufnr if appropriate
+ if exists("t:netrw_lexbufnr") && bufnr("%") == t:netrw_lexbufnr
+" call Decho("set repointlexbufnr to true!")
+ let repointlexbufnr= 1
+ endif
+
if w:netrw_liststyle == s:THINLIST
" use one column listing
" call Decho("use one column list",'~'.expand("<slnum>"))
@@ -4316,6 +4535,12 @@ fun! s:NetrwListStyle(islocal)
NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./'))
NetrwKeepj call s:NetrwCursor()
+ " repoint t:netrw_lexbufnr if appropriate
+ if exists("repointlexbufnr")
+ let t:netrw_lexbufnr= bufnr("%")
+" call Decho("repoint t:netrw_lexbufnr to #".t:netrw_lexbufnr)
+ endif
+
" restore position; keep cursor on the filename
" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
NetrwKeepj call winrestview(svpos)
@@ -4339,12 +4564,14 @@ fun! s:NetrwBannerCtrl(islocal)
call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./'))
" keep cursor on the filename
- let fname= s:NetrwGetWord()
- sil NetrwKeepj $
- let result= search('\%(^\%(|\+\s\)\=\|\s\{2,}\)\zs'.escape(fname,'.\[]*$^').'\%(\s\{2,}\|$\)','bc')
-" call Decho("search result=".result." w:netrw_bannercnt=".(exists("w:netrw_bannercnt")? w:netrw_bannercnt : 'N/A'),'~'.expand("<slnum>"))
- if result <= 0 && exists("w:netrw_bannercnt")
- exe "NetrwKeepj ".w:netrw_bannercnt
+ if g:netrw_banner && exists("w:netrw_bannercnt") && line(".") >= w:netrw_bannercnt
+ let fname= s:NetrwGetWord()
+ sil NetrwKeepj $
+ let result= search('\%(^\%(|\+\s\)\=\|\s\{2,}\)\zs'.escape(fname,'.\[]*$^').'\%(\s\{2,}\|$\)','bc')
+" " call Decho("search result=".result." w:netrw_bannercnt=".(exists("w:netrw_bannercnt")? w:netrw_bannercnt : 'N/A'),'~'.expand("<slnum>"))
+ if result <= 0 && exists("w:netrw_bannercnt")
+ exe "NetrwKeepj ".w:netrw_bannercnt
+ endif
endif
let @@= ykeep
" call Dret("s:NetrwBannerCtrl : g:netrw_banner=".g:netrw_banner)
@@ -4435,7 +4662,7 @@ fun! s:NetrwBookmarkMenu()
if !exists("s:netrw_menucnt")
return
endif
-" call Dfunc("NetrwBookmarkMenu() histcnt=".g:netrw_dirhist_cnt." menucnt=".s:netrw_menucnt)
+" call Dfunc("NetrwBookmarkMenu() histcnt=".g:netrw_dirhistcnt." menucnt=".s:netrw_menucnt)
" the following test assures that gvim is running, has menus available, and has menus enabled.
if has("gui") && has("menu") && has("gui_running") && &go =~# 'm' && g:netrw_menu
@@ -4467,12 +4694,12 @@ fun! s:NetrwBookmarkMenu()
" show directory browsing history
if g:netrw_dirhistmax > 0
- let cnt = g:netrw_dirhist_cnt
+ let cnt = g:netrw_dirhistcnt
let first = 1
let histcnt = 0
- while ( first || cnt != g:netrw_dirhist_cnt )
+ while ( first || cnt != g:netrw_dirhistcnt )
let histcnt = histcnt + 1
- let priority = g:netrw_dirhist_cnt + histcnt
+ let priority = g:netrw_dirhistcnt + histcnt
if exists("g:netrw_dirhist_{cnt}")
let histdir= escape(g:netrw_dirhist_{cnt},g:netrw_menu_escape)
" call Decho('sil! menu '.g:NetrwMenuPriority.".3.".priority." ".g:NetrwTopLvlMenu.'History.'.histdir.' :e '.histdir,'~'.expand("<slnum>"))
@@ -4506,7 +4733,7 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
let @@= ykeep
" call Decho("b:netrw_curdir doesn't exist!",'~'.expand("<slnum>"))
" call Decho("getcwd<".getcwd().">",'~'.expand("<slnum>"))
-" call Dredir("ls!")
+" call Dredir("ls!","s:NetrwBrowseChgDir")
" call Dret("s:NetrwBrowseChgDir")
return
endif
@@ -4514,9 +4741,9 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
" NetrwBrowseChgDir: save options and initialize {{{3
" call Decho("saving options",'~'.expand("<slnum>"))
- call s:SavePosn(s:netrw_nbcd)
- NetrwKeepj call s:NetrwOptionSave("s:")
- NetrwKeepj call s:NetrwSafeOptions()
+ call s:SavePosn(s:netrw_posn)
+ NetrwKeepj call s:NetrwOptionsSave("s:")
+ NetrwKeepj call s:NetrwOptionsSafe(a:islocal)
if (has("win32") || has("win95") || has("win64") || has("win16"))
let dirname = substitute(b:netrw_curdir,'\\','/','ge')
else
@@ -4526,9 +4753,10 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
let dolockout = 0
let dorestore = 1
" call Decho("dirname<".dirname.">",'~'.expand("<slnum>"))
+" call Decho("newdir<".newdir.">",'~'.expand("<slnum>"))
" ignore <cr>s when done in the banner
-" call Decho('ignore [return]s when done in banner (g:netrw_banner='.g:netrw_banner.")",'~'.expand("<slnum>"))
+" call Decho('(s:NetrwBrowseChgDir) ignore [return]s when done in banner (g:netrw_banner='.g:netrw_banner.")",'~'.expand("<slnum>"))
if g:netrw_banner
" call Decho("w:netrw_bannercnt=".(exists("w:netrw_bannercnt")? w:netrw_bannercnt : 'n/a')." line(.)#".line('.')." line($)#".line("#"),'~'.expand("<slnum>"))
if exists("w:netrw_bannercnt") && line(".") < w:netrw_bannercnt && line("$") >= w:netrw_bannercnt
@@ -4539,13 +4767,12 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
setl ma noro nowrap
NetrwKeepj call setline(line('.'),'" Quick Help: <F1>:help '.s:QuickHelp[g:netrw_quickhelp])
setl noma nomod nowrap
- call s:RestorePosn(s:netrw_nbcd)
- NetrwKeepj call s:NetrwOptionRestore("s:")
+ NetrwKeepj call s:NetrwOptionsRestore("s:")
" call Decho("ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("<slnum>"))
endif
endif
" else " Decho
-" call Decho("(s:NetrwBrowseChgdir) g:netrw_banner=".g:netrw_banner." (no banner)",'~'.expand("<slnum>"))
+" call Decho("g:netrw_banner=".g:netrw_banner." (no banner)",'~'.expand("<slnum>"))
endif
" set up o/s-dependent directory recognition pattern
@@ -4568,7 +4795,7 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
" ------------------------------
" NetrwBrowseChgDir: edit a file {{{3
" ------------------------------
-" call Decho('edit-a-file: case "handling a file": newdir<'.newdir.'> !~ dirpat<'.dirpat.">",'~'.expand("<slnum>"))
+" call Decho('(s:NetrwBrowseChgDir) edit-a-file: case "handling a file": newdir<'.newdir.'> !~ dirpat<'.dirpat.">",'~'.expand("<slnum>"))
" save position for benefit of Rexplore
let s:rexposn_{bufnr("%")}= winsaveview()
@@ -4580,6 +4807,9 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
" 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 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?")
+ " Feb 17, 2019: following if-else-endif restored -- wasn't editing a file in tree mode
if dirname =~ '/$'
let dirname= dirname.newdir
else
@@ -4597,7 +4827,7 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
" this lets netrw#BrowseX avoid the edit
if a:0 < 1
" call Decho("edit-a-file: (a:0=".a:0."<1) set up windows for editing<".fnameescape(dirname)."> didsplit=".(exists("s:didsplit")? s:didsplit : "doesn't exist"),'~'.expand("<slnum>"))
- NetrwKeepj call s:NetrwOptionRestore("s:")
+ NetrwKeepj call s:NetrwOptionsRestore("s:")
let curdir= b:netrw_curdir
if !exists("s:didsplit")
" call Decho("edit-a-file: s:didsplit does not exist; g:netrw_browse_split=".string(g:netrw_browse_split)." win#".winnr(),'~'.expand("<slnum>"))
@@ -4712,14 +4942,14 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
" call Decho('goto-newdir: case "just go to new directory spec": newdir<'.newdir.'>','~'.expand("<slnum>"))
let dirname = newdir
NetrwKeepj call s:SetRexDir(a:islocal,dirname)
- NetrwKeepj call s:NetrwOptionRestore("s:")
+ NetrwKeepj call s:NetrwOptionsRestore("s:")
norm! m`
elseif newdir == './'
" ---------------------------------------------
" NetrwBrowseChgDir: refresh the directory list {{{3
" ---------------------------------------------
-" call Decho('refresh-dirlist: case "refresh directory listing": newdir == "./"','~'.expand("<slnum>"))
+" call Decho('(s:NetrwBrowseChgDir)refresh-dirlist: case "refresh directory listing": newdir == "./"','~'.expand("<slnum>"))
NetrwKeepj call s:SetRexDir(a:islocal,dirname)
norm! m`
@@ -4727,7 +4957,7 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
" --------------------------------------
" NetrwBrowseChgDir: go up one directory {{{3
" --------------------------------------
-" call Decho('go-up: case "go up one directory": newdir == "../"','~'.expand("<slnum>"))
+" call Decho('(s:NetrwBrowseChgDir)go-up: case "go up one directory": newdir == "../"','~'.expand("<slnum>"))
if w:netrw_liststyle == s:TREELIST && exists("w:netrw_treedict")
" force a refresh
@@ -4765,7 +4995,7 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
else
" unix or cygwin
-" call Decho('go-up: case "go up one directory": newdir == "../" and unix or cygwin','~'.expand("<slnum>"))
+" call Decho('(s:NetrwBrowseChgDir)go-up: case "go up one directory": newdir == "../" and unix or cygwin','~'.expand("<slnum>"))
if a:islocal
let dirname= substitute(dirname,'^\(.*\)/\([^/]\+\)/$','\1','')
if dirname == ""
@@ -4777,13 +5007,13 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
" call Decho("go-up: unix: dirname<".dirname."> (go up one dir)",'~'.expand("<slnum>"))
endif
NetrwKeepj call s:SetRexDir(a:islocal,dirname)
- norm m`
+ norm! m`
elseif exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST && exists("w:netrw_treedict")
" --------------------------------------
" NetrwBrowseChgDir: Handle Tree Listing {{{3
" --------------------------------------
-" call Decho('tree-list: case liststyle is TREELIST and w:netrw_treedict exists','~'.expand("<slnum>"))
+" call Decho('(s:NetrwBrowseChgDir)tree-list: case liststyle is TREELIST and w:netrw_treedict exists','~'.expand("<slnum>"))
" force a refresh (for TREELIST, NetrwTreeDir() will force the refresh)
" call Decho("tree-list: setl noro ma",'~'.expand("<slnum>"))
setl noro ma
@@ -4800,10 +5030,10 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
" search treedict for tree dir as-is
" call Decho("tree-list: search treedict for tree dir as-is",'~'.expand("<slnum>"))
if has_key(w:netrw_treedict,treedir)
-" call Decho('tree-list: ....searched for treedir<'.treedir.'> : found it!','~'.expand("<slnum>"))
+" call Decho('(s:NetrwBrowseChgDir)tree-list: ....searched for treedir<'.treedir.'> : found it!','~'.expand("<slnum>"))
let haskey= 1
else
-" call Decho('tree-list: ....searched for treedir<'.treedir.'> : not found','~'.expand("<slnum>"))
+" call Decho('(s:NetrwBrowseChgDir)tree-list: ....searched for treedir<'.treedir.'> : not found','~'.expand("<slnum>"))
endif
" search treedict for treedir with a [/@] appended
@@ -4811,10 +5041,10 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
if !haskey && treedir !~ '[/@]$'
if has_key(w:netrw_treedict,treedir."/")
let treedir= treedir."/"
-" call Decho('tree-list: ....searched.for treedir<'.treedir.'> found it!','~'.expand("<slnum>"))
+" call Decho('(s:NetrwBrowseChgDir)tree-list: ....searched.for treedir<'.treedir.'> found it!','~'.expand("<slnum>"))
let haskey = 1
else
-" call Decho('tree-list: ....searched for treedir<'.treedir.'/> : not found','~'.expand("<slnum>"))
+" call Decho('(s:NetrwBrowseChgDir)tree-list: ....searched for treedir<'.treedir.'/> : not found','~'.expand("<slnum>"))
endif
endif
@@ -4823,10 +5053,10 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
if !haskey && treedir =~ '/$'
let treedir= substitute(treedir,'/$','','')
if has_key(w:netrw_treedict,treedir)
-" call Decho('tree-list: ....searched.for treedir<'.treedir.'> found it!','~'.expand("<slnum>"))
+" call Decho('(s:NetrwBrowseChgDir)tree-list: ....searched.for treedir<'.treedir.'> found it!','~'.expand("<slnum>"))
let haskey = 1
else
-" call Decho('tree-list: ....searched for treedir<'.treedir.'> : not found','~'.expand("<slnum>"))
+" call Decho('(s:NetrwBrowseChgDir)tree-list: ....searched for treedir<'.treedir.'> : not found','~'.expand("<slnum>"))
endif
endif
@@ -4855,7 +5085,7 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
let dirname = s:ComposePath(dirname,newdir)
" call Decho("go down one dir: dirname<".dirname."> newdir<".newdir.">",'~'.expand("<slnum>"))
NetrwKeepj call s:SetRexDir(a:islocal,dirname)
- norm m`
+ norm! m`
endif
" --------------------------------------
@@ -4865,11 +5095,10 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
" dorestore is zero'd when a local file was hidden or bufhidden;
" in such a case, we want to keep whatever settings it may have.
" call Decho("doing option restore (dorestore=".dorestore.")",'~'.expand("<slnum>"))
- NetrwKeepj call s:NetrwOptionRestore("s:")
+ NetrwKeepj call s:NetrwOptionsRestore("s:")
" else " Decho
" call Decho("skipping option restore (dorestore==0): hidden=".&hidden." bufhidden=".&bufhidden." mod=".&mod,'~'.expand("<slnum>"))
endif
- call s:RestorePosn(s:netrw_nbcd)
if dolockout && dorestore
" call Decho("restore: filewritable(dirname<".dirname.">)=".filewritable(dirname),'~'.expand("<slnum>"))
if filewritable(dirname)
@@ -4884,6 +5113,7 @@ fun! s:NetrwBrowseChgDir(islocal,newdir,...)
" call Decho("restore: ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("<slnum>"))
endif
endif
+ call s:RestorePosn(s:netrw_posn)
let @@= ykeep
" call Dret("s:NetrwBrowseChgDir <".dirname."> : curpos<".string(getpos(".")).">")
@@ -4905,10 +5135,6 @@ fun! s:NetrwBrowseUpDir(islocal)
return
endif
- if !exists("w:netrw_liststyle") || w:netrw_liststyle != s:TREELIST
- call s:SavePosn(s:netrw_nbcd)
- endif
-
norm! 0
if exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST && exists("w:netrw_treedict")
" call Decho("case: treestyle",'~'.expand("<slnum>"))
@@ -4916,28 +5142,40 @@ fun! s:NetrwBrowseUpDir(islocal)
let swwline= winline() - 1
if exists("w:netrw_treetop")
let b:netrw_curdir= w:netrw_treetop
+ elseif exists("b:netrw_curdir")
+ let w:netrw_treetop= b:netrw_curdir
+ else
+ let w:netrw_treetop= getcwd()
+ let b:netrw_curdir = w:netrw_treetop
endif
- let curdir= b:netrw_curdir
+ let curfile = getline(".")
+ let curpath = s:NetrwTreePath(w:netrw_treetop)
if a:islocal
call netrw#LocalBrowseCheck(s:NetrwBrowseChgDir(1,'../'))
else
call s:NetrwBrowse(0,s:NetrwBrowseChgDir(0,'../'))
endif
- if !search('\c^'.s:treedepthstring.curline,'cw')
- if !search('\c^'.curline,'cw')
- sil! NetrwKeepj 1
- endif
+" call Decho("looking for curfile<^".s:treedepthstring.curfile.">",'~'.expand("<slnum>"))
+" call Decho("having curpath<".curpath.">",'~'.expand("<slnum>"))
+ if w:netrw_treetop == '/'
+ keepj call search('^\M'.curfile,"w")
+ elseif curfile == '../'
+ keepj call search('^\M'.curfile,"wb")
+ else
+" call Decho("search(^\\M".s:treedepthstring.curfile.") backwards"))
+ while 1
+ keepj call search('^\M'.s:treedepthstring.curfile,"wb")
+ let treepath= s:NetrwTreePath(w:netrw_treetop)
+" call Decho("..current treepath<".treepath.">",'~'.expand("<slnum>"))
+ if treepath == curpath
+ break
+ endif
+ endwhile
endif
- exe "sil! NetrwKeepj norm! z\<cr>"
- while winline() < swwline
- let curwinline= winline()
- exe "sil! NetrwKeepj norm! \<c-y>"
- if curwinline == winline()
- break
- endif
- endwhile
+
else
" call Decho("case: not treestyle",'~'.expand("<slnum>"))
+ call s:SavePosn(s:netrw_posn)
if exists("b:netrw_curdir")
let curdir= b:netrw_curdir
else
@@ -4948,17 +5186,10 @@ fun! s:NetrwBrowseUpDir(islocal)
else
call s:NetrwBrowse(0,s:NetrwBrowseChgDir(0,'../'))
endif
- if has_key(s:netrw_nbcd,bufnr("%"))
- call s:RestorePosn(s:netrw_nbcd)
- elseif exists("w:netrw_bannercnt")
-" call Decho("moving to line#".w:netrw_bannercnt,'~'.expand("<slnum>"))
- exe w:netrw_bannercnt
- else
- 1
- endif
+ call s:RestorePosn(s:netrw_posn)
+ let curdir= substitute(curdir,'^.*[\/]','','')
+ call search('\<'.curdir.'/','wc')
endif
- let curdir= substitute(curdir,'^.*[\/]','','')
- call search('\<'.curdir.'\>','wc')
" call Dret("s:NetrwBrowseUpDir")
endfun
@@ -4969,13 +5200,12 @@ endfun
fun! netrw#BrowseX(fname,remote)
" call Dfunc("netrw#BrowseX(fname<".a:fname."> remote=".a:remote.")")
- " if its really just a directory, then do a "gf" instead
- if (a:remote == 0 && isdirectory(a:fname)) || (a:remote == 1 && fname =~ '/$' && fname !~ '^https\=:')
+ " if its really just a local directory, then do a "gf" instead
+ if (a:remote == 0 && isdirectory(a:fname)) || (a:remote == 1 && a:fname =~ '/$' && a:fname !~ '^https\=:')
norm! gf
-" call Dret("netrw#BrowseX : did gf instead")
+" call Dret("(netrw#BrowseX) did gf instead")
endif
-
let ykeep = @@
let screenposn = winsaveview()
" call Decho("saving posn to screenposn<".string(screenposn).">",'~'.expand("<slnum>"))
@@ -5000,7 +5230,7 @@ fun! netrw#BrowseX(fname,remote)
endif
endfor
endif
-" call Decho("restoring posn to screenposn<".string(screenposn).">,'~'.expand("<slnum>"))"
+" call Decho("restoring posn: screenposn<".string(screenposn).">,'~'.expand("<slnum>"))"
call winrestview(screenposn)
let @@= ykeep
let &aw= awkeep
@@ -5015,6 +5245,9 @@ fun! netrw#BrowseX(fname,remote)
if has("win32") || has("win95") || has("win64") || has("win16")
let exten= substitute(exten,'^.*$','\L&\E','')
endif
+ if exten =~ "[\\/]"
+ let exten= ""
+ endif
" call Decho("exten<".exten.">",'~'.expand("<slnum>"))
if a:remote == 1
@@ -5027,11 +5260,17 @@ fun! netrw#BrowseX(fname,remote)
let newname = substitute(s:netrw_tmpfile,'^\(.*\)/\(.*\)\.\([^.]*\)$','\1/'.basename.'.\3','')
" call Decho("basename<".basename.">",'~'.expand("<slnum>"))
" call Decho("newname <".newname.">",'~'.expand("<slnum>"))
- if rename(s:netrw_tmpfile,newname) == 0
- " renaming succeeded
- let fname= newname
+ if s:netrw_tmpfile != newname && newname != ""
+ if rename(s:netrw_tmpfile,newname) == 0
+ " renaming succeeded
+" call Decho("renaming succeeded (tmpfile<".s:netrw_tmpfile."> to <".newname.">)")
+ let fname= newname
+ else
+ " renaming failed
+" call Decho("renaming failed (tmpfile<".s:netrw_tmpfile."> to <".newname.">)")
+ let fname= s:netrw_tmpfile
+ endif
else
- " renaming failed
let fname= s:netrw_tmpfile
endif
else
@@ -5098,7 +5337,7 @@ fun! netrw#BrowseX(fname,remote)
let ret= v:shell_error
elseif has("win32") || has("win64")
-" call Decho("windows",'~'.expand("<slnum>"))
+" call Decho("win".(has("win32")? "32" : "64")",'~'.expand("<slnum>"))
if executable("start")
call s:NetrwExe('sil! !start rundll32 url.dll,FileProtocolHandler '.s:ShellEscape(fname,1))
elseif executable("rundll32")
@@ -5106,7 +5345,7 @@ fun! netrw#BrowseX(fname,remote)
else
call netrw#ErrorMsg(s:WARNING,"rundll32 not on path",74)
endif
- call inputsave()|call input("Press <cr> to continue")|call inputrestore()
+ " call inputsave()|call input("Press <cr> to continue")|call inputrestore()
let ret= v:shell_error
elseif has("win32unix")
@@ -5121,7 +5360,7 @@ fun! netrw#BrowseX(fname,remote)
else
call netrw#ErrorMsg(s:WARNING,"rundll32 not on path",74)
endif
- call inputsave()|call input("Press <cr> to continue")|call inputrestore()
+ " call inputsave()|call input("Press <cr> to continue")|call inputrestore()
let ret= v:shell_error
elseif has("unix") && executable("kfmclient") && s:CheckIfKde()
@@ -5134,6 +5373,11 @@ fun! netrw#BrowseX(fname,remote)
call s:NetrwExe("sil !setsid xdg-open ".s:ShellEscape(fname,1).redir)
let ret= v:shell_error
+ elseif has("unix") && $DESKTOP_SESSION == "mate" && executable("atril")
+" call Decho("unix and atril",'~'.expand("<slnum>"))
+ call s:NetrwExe("sil !atril ".s:ShellEscape(fname,1).redir)
+ let ret= v:shell_error
+
elseif has("unix") && executable("xdg-open")
" call Decho("unix and xdg-open",'~'.expand("<slnum>"))
call s:NetrwExe("sil !xdg-open ".s:ShellEscape(fname,1).redir)
@@ -5184,22 +5428,76 @@ fun! netrw#BrowseX(fname,remote)
endfun
" ---------------------------------------------------------------------
+" netrw#GX: gets word under cursor for gx support {{{2
+" See also: netrw#BrowseXVis
+" netrw#BrowseX
+fun! netrw#GX()
+" call Dfunc("netrw#GX()")
+ if &ft == "netrw"
+ let fname= s:NetrwGetWord()
+ else
+ let fname= expand((exists("g:netrw_gx")? g:netrw_gx : '<cfile>'))
+ endif
+" call Dret("netrw#GX <".fname.">")
+ return fname
+endfun
+
+" ---------------------------------------------------------------------
" netrw#BrowseXVis: used by gx in visual mode to select a file for browsing {{{2
fun! netrw#BrowseXVis()
" call Dfunc("netrw#BrowseXVis()")
let atkeep = @@
norm! gvy
" call Decho("@@<".@@.">",'~'.expand("<slnum>"))
- call netrw#BrowseX(@@,netrw#CheckIfRemote())
+ call netrw#BrowseX(@@,netrw#CheckIfRemote(@@))
let @@ = atkeep
" call Dret("netrw#BrowseXVis")
endfun
" ---------------------------------------------------------------------
+" s:NetrwBufRename: renames a buffer without the side effect of retaining an unlisted buffer having the old name {{{2
+" Using the file command on a "[No Name]" buffer does not seem to cause the old "[No Name]" buffer
+" to become an unlisted buffer, so in that case don't bwipe it.
+fun! s:NetrwBufRename(newname)
+" call Dfunc("s:NetrwBufRename(newname<".a:newname.">) buf(%)#".bufnr("%")."<".bufname(bufnr("%")).">")
+" call Dredir("ls!","s:NetrwBufRename (before rename)")
+ let oldbufname= bufname(bufnr("%"))
+" call Decho("buf#".bufnr("%").": oldbufname<".oldbufname.">",'~'.expand("<slnum>"))
+
+ if oldbufname != a:newname
+" call Decho("do buffer rename: oldbufname<".oldbufname."> ≠ a:newname<".a:newname.">",'~'.expand("<slnum>"))
+ 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)")
+ let oldbufnr= bufnr(oldbufname)
+" call Decho("oldbufname<".oldbufname."> oldbufnr#".oldbufnr,'~'.expand("<slnum>"))
+" call Decho("bufnr(%)=".bufnr("%"),'~'.expand("<slnum>"))
+ if oldbufname != "" && oldbufnr != -1 && oldbufnr != bufnr("%")
+" call Decho("bwipe ".oldbufnr,'~'.expand("<slnum>"))
+ exe "bwipe! ".oldbufnr
+" else " Decho
+" call Decho("did *not* bwipe buf#".oldbufnr,'~'.expand("<slnum>"))
+ endif
+" call Dredir("ls!","s:NetrwBufRename (after rename)")
+" else " Decho
+" call Decho("oldbufname<".oldbufname."> == a:newname: did *not* rename",'~'.expand("<slnum>"))
+ endif
+
+" call Dret("s:NetrwBufRename : buf#".bufnr("%").": oldname<".oldbufname."> newname<".a:newname."> expand(%)<".expand("%").">")
+endfun
+
+" ---------------------------------------------------------------------
" netrw#CheckIfRemote: returns 1 if current file looks like an url, 0 else {{{2
-fun! netrw#CheckIfRemote()
-" call Dfunc("netrw#CheckIfRemote()")
- if expand("%") =~ '^\a\{3,}://'
+fun! netrw#CheckIfRemote(...)
+" call Dfunc("netrw#CheckIfRemote() a:0=".a:0)
+ if a:0 > 0
+ let curfile= a:1
+ else
+ let curfile= expand("%")
+ endif
+" call Decho("curfile<".curfile.">")
+ if curfile =~ '^\a\{3,}://'
" call Dret("netrw#CheckIfRemote 1")
return 1
else
@@ -5465,17 +5763,23 @@ fun! s:NetrwHidden(islocal)
" call Dfunc("s:NetrwHidden()")
let ykeep= @@
" save current position
- let svpos= winsaveview()
+ let svpos = winsaveview()
" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
if g:netrw_list_hide =~ '\(^\|,\)\\(^\\|\\s\\s\\)\\zs\\.\\S\\+'
- " remove pattern from hiding list
+ " remove .file pattern from hiding list
+" call Decho("remove .file pattern from hiding list",'~'.expand("<slnum>"))
let g:netrw_list_hide= substitute(g:netrw_list_hide,'\(^\|,\)\\(^\\|\\s\\s\\)\\zs\\.\\S\\+','','')
elseif s:Strlen(g:netrw_list_hide) >= 1
+" call Decho("add .file pattern from hiding list",'~'.expand("<slnum>"))
let g:netrw_list_hide= g:netrw_list_hide . ',\(^\|\s\s\)\zs\.\S\+'
else
+" call Decho("set .file pattern as hiding list",'~'.expand("<slnum>"))
let g:netrw_list_hide= '\(^\|\s\s\)\zs\.\S\+'
endif
+ if g:netrw_list_hide =~ '^,'
+ let g:netrw_list_hide= strpart(g:netrw_list_hide,1)
+ endif
" refresh screen and return to saved position
NetrwKeepj call s:NetrwRefresh(a:islocal,s:NetrwBrowseChgDir(a:islocal,'./'))
@@ -5489,7 +5793,7 @@ endfun
" s:NetrwHome: this function determines a "home" for saving bookmarks and history {{{2
fun! s:NetrwHome()
if exists("g:netrw_home")
- let home= g:netrw_home
+ let home= expand(g:netrw_home)
else
" go to vim plugin home
for home in split(&rtp,',') + ['']
@@ -5510,9 +5814,12 @@ fun! s:NetrwHome()
endif
" insure that the home directory exists
if g:netrw_dirhistmax > 0 && !isdirectory(s:NetrwFile(home))
+" call Decho("insure that the home<".home."> directory exists")
if exists("g:netrw_mkdir")
+" call Decho("call system(".g:netrw_mkdir." ".s:ShellEscape(s:NetrwFile(home)).")")
call system(g:netrw_mkdir." ".s:ShellEscape(s:NetrwFile(home)))
else
+" call Decho("mkdir(".home.")")
call mkdir(home)
endif
endif
@@ -5526,6 +5833,9 @@ fun! s:NetrwLeftmouse(islocal)
if exists("s:netrwdrag")
return
endif
+ if &ft != "netrw"
+ return
+ endif
" call Dfunc("s:NetrwLeftmouse(islocal=".a:islocal.")")
let ykeep= @@
@@ -5573,6 +5883,9 @@ endfun
" ---------------------------------------------------------------------
" s:NetrwCLeftmouse: used to select a file/directory for a target {{{2
fun! s:NetrwCLeftmouse(islocal)
+ if &ft != "netrw"
+ return
+ endif
" call Dfunc("s:NetrwCLeftmouse(islocal=".a:islocal.")")
call s:NetrwMarkFileTgt(a:islocal)
" call Dret("s:NetrwCLeftmouse")
@@ -5581,7 +5894,7 @@ endfun
" ---------------------------------------------------------------------
" s:NetrwServerEdit: edit file in a server gvim, usually NETRWSERVER (implements <c-r>){{{2
" a:islocal=0 : <c-r> not used, remote
-" a:islocal=1 : <c-r> no used, local
+" a:islocal=1 : <c-r> not used, local
" a:islocal=2 : <c-r> used, remote
" a:islocal=3 : <c-r> used, local
fun! s:NetrwServerEdit(islocal,fname)
@@ -5706,6 +6019,9 @@ endfun
" ---------------------------------------------------------------------
" s:NetrwSLeftmouse: marks the file under the cursor. May be dragged to select additional files {{{2
fun! s:NetrwSLeftmouse(islocal)
+ if &ft != "netrw"
+ return
+ endif
" call Dfunc("s:NetrwSLeftmouse(islocal=".a:islocal.")")
let s:ngw= s:NetrwGetWord()
@@ -5758,12 +6074,16 @@ endfun
" separated patterns given in g:netrw_list_hide
fun! s:NetrwListHide()
" call Dfunc("s:NetrwListHide() g:netrw_hide=".g:netrw_hide." g:netrw_list_hide<".g:netrw_list_hide.">")
+" call Decho("initial: ".string(getline(w:netrw_bannercnt,'$')))
let ykeep= @@
+" call DechoBuf(bufnr("%"),"COMBAK#3")
" find a character not in the "hide" string to use as a separator for :g and :v commands
- " How-it-works: take the hiding command, convert it into a range. Duplicate
- " characters don't matter. Remove all such characters from the '/~...90'
- " string. Use the first character left as a separator character.
+ " How-it-works: take the hiding command, convert it into a range.
+ " Duplicate characters don't matter.
+ " Remove all such characters from the '/~@#...890' string.
+ " Use the first character left as a separator character.
+" call Decho("find a character not in the hide string to use as a separator")
let listhide= g:netrw_list_hide
let sep = strpart(substitute('/~@#$%^&*{};:,<.>?|1234567890','['.escape(listhide,'-]^\').']','','ge'),1,1)
" call Decho("sep=".sep,'~'.expand("<slnum>"))
@@ -5776,24 +6096,31 @@ fun! s:NetrwListHide()
let hide = listhide
let listhide = ""
endif
+" call Decho("hide<".hide."> listhide<".listhide.'>','~'.expand("<slnum>"))
" Prune the list by hiding any files which match
+" call Decho("prune the list by hiding any files which ",((g:netrw_hide == 1)? "" : "don't")." match hide<".hide.">")
if g:netrw_hide == 1
-" call Decho("hiding<".hide."> listhide<".listhide.">",'~'.expand("<slnum>"))
+" call Decho("..hiding<".hide.">",'~'.expand("<slnum>"))
exe 'sil! NetrwKeepj '.w:netrw_bannercnt.',$g'.sep.hide.sep.'d'
elseif g:netrw_hide == 2
-" call Decho("showing<".hide."> listhide<".listhide.">",'~'.expand("<slnum>"))
+" call Decho("..showing<".hide.">",'~'.expand("<slnum>"))
exe 'sil! NetrwKeepj '.w:netrw_bannercnt.',$g'.sep.hide.sep.'s@^@ /-KEEP-/ @'
endif
+" call Decho("..result: ".string(getline(w:netrw_bannercnt,'$')),'~'.expand("<slnum>"))
endwhile
+
if g:netrw_hide == 2
exe 'sil! NetrwKeepj '.w:netrw_bannercnt.',$v@^ /-KEEP-/ @d'
+" call Decho("..v KEEP: ".string(getline(w:netrw_bannercnt,'$')),'~'.expand("<slnum>"))
exe 'sil! NetrwKeepj '.w:netrw_bannercnt.',$s@^\%( /-KEEP-/ \)\+@@e'
+" call Decho("..g KEEP: ".string(getline(w:netrw_bannercnt,'$')),'~'.expand("<slnum>"))
endif
" remove any blank lines that have somehow remained.
" This seems to happen under Windows.
exe 'sil! NetrwKeepj 1,$g@^\s*$@d'
+" call DechoBuf(bufnr("%"),"COMBAK#4")
let @@= ykeep
" call Dret("s:NetrwListHide")
@@ -5854,9 +6181,12 @@ fun! s:NetrwMakeDir(usrhost)
endif
else
let netrw_origdir= s:NetrwGetcwd(1)
- call s:NetrwLcd(b:netrw_curdir)
+ if s:NetrwLcd(b:netrw_curdir)
+" call Dret("s:NetrwMakeDir : lcd failure")
+ return
+ endif
" call Decho("netrw_origdir<".netrw_origdir.">: lcd b:netrw_curdir<".fnameescape(b:netrw_curdir).">",'~'.expand("<slnum>"))
- call s:NetrwExe("sil! !".g:netrw_localmkdir.' '.s:ShellEscape(newdirname,1))
+ call s:NetrwExe("sil! !".g:netrw_localmkdir.g:netrw_localmkdiropt.' '.s:ShellEscape(newdirname,1))
if v:shell_error != 0
let @@= ykeep
call netrw#ErrorMsg(s:ERROR,"consider setting g:netrw_localmkdir<".g:netrw_localmkdir."> to something that works",80)
@@ -5865,7 +6195,10 @@ fun! s:NetrwMakeDir(usrhost)
endif
if !g:netrw_keepdir
" call Decho("restoring netrw_origdir since g:netrw_keepdir=".g:netrw_keepdir,'~'.expand("<slnum>"))
- call s:NetrwLcd(netrw_origdir)
+ if s:NetrwLcd(netrw_origdir)
+" call Dret("s:NetrwBrowse : lcd failure")
+ return
+ endif
endif
endif
@@ -5977,6 +6310,7 @@ endfun
fun! s:NetrwMaps(islocal)
" call Dfunc("s:NetrwMaps(islocal=".a:islocal.") b:netrw_curdir<".b:netrw_curdir.">")
+ " mouse <Plug> maps: {{{3
if g:netrw_mousemaps && g:netrw_retmap
" call Decho("set up Rexplore 2-leftmouse",'~'.expand("<slnum>"))
if !hasmapto("<Plug>NetrwReturn")
@@ -5992,22 +6326,87 @@ fun! s:NetrwMaps(islocal)
" call Decho("made <Plug>NetrwReturn map",'~'.expand("<slnum>"))
endif
+ " generate default <Plug> maps {{{3
+ if !hasmapto('<Plug>NetrwHide') |nmap <buffer> <silent> <nowait> a <Plug>NetrwHide_a|endif
+ if !hasmapto('<Plug>NetrwBrowseUpDir') |nmap <buffer> <silent> <nowait> - <Plug>NetrwBrowseUpDir |endif
+ if !hasmapto('<Plug>NetrwOpenFile') |nmap <buffer> <silent> <nowait> % <Plug>NetrwOpenFile|endif
+ if !hasmapto('<Plug>NetrwBadd_cb') |nmap <buffer> <silent> <nowait> cb <Plug>NetrwBadd_cb|endif
+ if !hasmapto('<Plug>NetrwBadd_cB') |nmap <buffer> <silent> <nowait> cB <Plug>NetrwBadd_cB|endif
+ if !hasmapto('<Plug>NetrwLcd') |nmap <buffer> <silent> <nowait> cd <Plug>NetrwLcd|endif
+ if !hasmapto('<Plug>NetrwSetChgwin') |nmap <buffer> <silent> <nowait> C <Plug>NetrwSetChgwin|endif
+ if !hasmapto('<Plug>NetrwRefresh') |nmap <buffer> <silent> <nowait> <c-l> <Plug>NetrwRefresh|endif
+ if !hasmapto('<Plug>NetrwLocalBrowseCheck') |nmap <buffer> <silent> <nowait> <cr> <Plug>NetrwLocalBrowseCheck|endif
+ if !hasmapto('<Plug>NetrwServerEdit') |nmap <buffer> <silent> <nowait> <c-r> <Plug>NetrwServerEdit|endif
+ if !hasmapto('<Plug>NetrwMakeDir') |nmap <buffer> <silent> <nowait> d <Plug>NetrwMakeDir|endif
+ if !hasmapto('<Plug>NetrwBookHistHandler_gb')|nmap <buffer> <silent> <nowait> gb <Plug>NetrwBookHistHandler_gb|endif
+" ---------------------------------------------------------------------
+" if !hasmapto('<Plug>NetrwForceChgDir') |nmap <buffer> <silent> <nowait> gd <Plug>NetrwForceChgDir|endif
+" if !hasmapto('<Plug>NetrwForceFile') |nmap <buffer> <silent> <nowait> gf <Plug>NetrwForceFile|endif
+" if !hasmapto('<Plug>NetrwHidden') |nmap <buffer> <silent> <nowait> gh <Plug>NetrwHidden|endif
+" if !hasmapto('<Plug>NetrwSetTreetop') |nmap <buffer> <silent> <nowait> gn <Plug>NetrwSetTreetop|endif
+" if !hasmapto('<Plug>NetrwChgPerm') |nmap <buffer> <silent> <nowait> gp <Plug>NetrwChgPerm|endif
+" if !hasmapto('<Plug>NetrwBannerCtrl') |nmap <buffer> <silent> <nowait> I <Plug>NetrwBannerCtrl|endif
+" if !hasmapto('<Plug>NetrwListStyle') |nmap <buffer> <silent> <nowait> i <Plug>NetrwListStyle|endif
+" if !hasmapto('<Plug>NetrwMarkMoveMF2Arglist')|nmap <buffer> <silent> <nowait> ma <Plug>NetrwMarkMoveMF2Arglist|endif
+" if !hasmapto('<Plug>NetrwMarkMoveArglist2MF')|nmap <buffer> <silent> <nowait> mA <Plug>NetrwMarkMoveArglist2MF|endif
+" if !hasmapto('<Plug>NetrwBookHistHandler_mA')|nmap <buffer> <silent> <nowait> mb <Plug>NetrwBookHistHandler_mA|endif
+" if !hasmapto('<Plug>NetrwBookHistHandler_mB')|nmap <buffer> <silent> <nowait> mB <Plug>NetrwBookHistHandler_mB|endif
+" if !hasmapto('<Plug>NetrwMarkFileCopy') |nmap <buffer> <silent> <nowait> mc <Plug>NetrwMarkFileCopy|endif
+" if !hasmapto('<Plug>NetrwMarkFileDiff') |nmap <buffer> <silent> <nowait> md <Plug>NetrwMarkFileDiff|endif
+" if !hasmapto('<Plug>NetrwMarkFileEdit') |nmap <buffer> <silent> <nowait> me <Plug>NetrwMarkFileEdit|endif
+" if !hasmapto('<Plug>NetrwMarkFile') |nmap <buffer> <silent> <nowait> mf <Plug>NetrwMarkFile|endif
+" if !hasmapto('<Plug>NetrwUnmarkList') |nmap <buffer> <silent> <nowait> mF <Plug>NetrwUnmarkList|endif
+" if !hasmapto('<Plug>NetrwMarkFileGrep') |nmap <buffer> <silent> <nowait> mg <Plug>NetrwMarkFileGrep|endif
+" if !hasmapto('<Plug>NetrwMarkHideSfx') |nmap <buffer> <silent> <nowait> mh <Plug>NetrwMarkHideSfx|endif
+" if !hasmapto('<Plug>NetrwMarkFileMove') |nmap <buffer> <silent> <nowait> mm <Plug>NetrwMarkFileMove|endif
+" if !hasmapto('<Plug>NetrwMarkFilePrint') |nmap <buffer> <silent> <nowait> mp <Plug>NetrwMarkFilePrint|endif
+" if !hasmapto('<Plug>NetrwMarkFileRegexp') |nmap <buffer> <silent> <nowait> mr <Plug>NetrwMarkFileRegexp|endif
+" if !hasmapto('<Plug>NetrwMarkFileSource') |nmap <buffer> <silent> <nowait> ms <Plug>NetrwMarkFileSource|endif
+" if !hasmapto('<Plug>NetrwMarkFileTag') |nmap <buffer> <silent> <nowait> mT <Plug>NetrwMarkFileTag|endif
+" if !hasmapto('<Plug>NetrwMarkFileTgt') |nmap <buffer> <silent> <nowait> mt <Plug>NetrwMarkFileTgt|endif
+" if !hasmapto('<Plug>NetrwUnMarkFile') |nmap <buffer> <silent> <nowait> mu <Plug>NetrwUnMarkFile|endif
+" if !hasmapto('<Plug>NetrwMarkFileVimCmd') |nmap <buffer> <silent> <nowait> mv <Plug>NetrwMarkFileVimCmd|endif
+" if !hasmapto('<Plug>NetrwMarkFileExe_mx') |nmap <buffer> <silent> <nowait> mx <Plug>NetrwMarkFileExe_mx|endif
+" if !hasmapto('<Plug>NetrwMarkFileExe_mX') |nmap <buffer> <silent> <nowait> mX <Plug>NetrwMarkFileExe_mX|endif
+" if !hasmapto('<Plug>NetrwMarkFileCompress') |nmap <buffer> <silent> <nowait> mz <Plug>NetrwMarkFileCompress|endif
+" if !hasmapto('<Plug>NetrwObtain') |nmap <buffer> <silent> <nowait> O <Plug>NetrwObtain|endif
+" if !hasmapto('<Plug>NetrwSplit_o') |nmap <buffer> <silent> <nowait> o <Plug>NetrwSplit_o|endif
+" if !hasmapto('<Plug>NetrwPreview') |nmap <buffer> <silent> <nowait> p <Plug>NetrwPreview|endif
+" if !hasmapto('<Plug>NetrwPrevWinOpen') |nmap <buffer> <silent> <nowait> P <Plug>NetrwPrevWinOpen|endif
+" if !hasmapto('<Plug>NetrwBookHistHandler_qb')|nmap <buffer> <silent> <nowait> qb <Plug>NetrwBookHistHandler_qb|endif
+" if !hasmapto('<Plug>NetrwFileInfo') |nmap <buffer> <silent> <nowait> qf <Plug>NetrwFileInfo|endif
+" if !hasmapto('<Plug>NetrwMarkFileQFEL_qF') |nmap <buffer> <silent> <nowait> qF <Plug>NetrwMarkFileQFEL_qF|endif
+" if !hasmapto('<Plug>NetrwMarkFileQFEL_qL') |nmap <buffer> <silent> <nowait> qL <Plug>NetrwMarkFileQFEL_qL|endif
+" if !hasmapto('<Plug>NetrwSortStyle') |nmap <buffer> <silent> <nowait> s <Plug>NetrwSortStyle|endif
+" if !hasmapto('<Plug>NetSortSequence') |nmap <buffer> <silent> <nowait> S <Plug>NetSortSequence|endif
+" if !hasmapto('<Plug>NetrwSetTgt_Tb') |nmap <buffer> <silent> <nowait> Tb <Plug>NetrwSetTgt_Tb|endif
+" if !hasmapto('<Plug>NetrwSetTgt_Th') |nmap <buffer> <silent> <nowait> Th <Plug>NetrwSetTgt_Th|endif
+" if !hasmapto('<Plug>NetrwSplit_t') |nmap <buffer> <silent> <nowait> t <Plug>NetrwSplit_t|endif
+" if !hasmapto('<Plug>NetrwBookHistHandler_u') |nmap <buffer> <silent> <nowait> u <Plug>NetrwBookHistHandler_u|endif
+" if !hasmapto('<Plug>NetrwBookHistHandler_U') |nmap <buffer> <silent> <nowait> U <Plug>NetrwBookHistHandler_U|endif
+" if !hasmapto('<Plug>NetrwSplit_v') |nmap <buffer> <silent> <nowait> v <Plug>NetrwSplit_v|endif
+" if !hasmapto('<Plug>NetrwBrowseX') |nmap <buffer> <silent> <nowait> x <Plug>NetrwBrowseX|endif
+" if !hasmapto('<Plug>NetrwLocalExecute') |nmap <buffer> <silent> <nowait> X <Plug>NetrwLocalExecute|endif
+
if a:islocal
" call Decho("make local maps",'~'.expand("<slnum>"))
- " local normal-mode maps
- nnoremap <buffer> <silent> <nowait> a :<c-u>call <SID>NetrwHide(1)<cr>
- nnoremap <buffer> <silent> <nowait> - :<c-u>call <SID>NetrwBrowseUpDir(1)<cr>
- nnoremap <buffer> <silent> <nowait> % :<c-u>call <SID>NetrwOpenFile(1)<cr>
- nnoremap <buffer> <silent> <nowait> c :<c-u>call <SID>NetrwLcd(b:netrw_curdir)<cr>
- nnoremap <buffer> <silent> <nowait> C :<c-u>call <SID>NetrwSetChgwin()<cr>
- nnoremap <buffer> <silent> <nowait> <cr> :<c-u>call netrw#LocalBrowseCheck(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord()))<cr>
- nnoremap <buffer> <silent> <nowait> <c-r> :<c-u>call <SID>NetrwServerEdit(3,<SID>NetrwGetWord())<cr>
- nnoremap <buffer> <silent> <nowait> d :<c-u>call <SID>NetrwMakeDir("")<cr>
- nnoremap <buffer> <silent> <nowait> gb :<c-u>call <SID>NetrwBookHistHandler(1,b:netrw_curdir)<cr>
+ " local normal-mode maps {{{3
+ nnoremap <buffer> <silent> <Plug>NetrwHide_a :<c-u>call <SID>NetrwHide(1)<cr>
+ nnoremap <buffer> <silent> <Plug>NetrwBrowseUpDir :<c-u>call <SID>NetrwBrowseUpDir(1)<cr>
+ nnoremap <buffer> <silent> <Plug>NetrwOpenFile :<c-u>call <SID>NetrwOpenFile(1)<cr>
+ nnoremap <buffer> <silent> <Plug>NetrwBadd_cb :<c-u>call <SID>NetrwBadd(1,0)<cr>
+ nnoremap <buffer> <silent> <Plug>NetrwBadd_cB :<c-u>call <SID>NetrwBadd(1,1)<cr>
+ nnoremap <buffer> <silent> <Plug>NetrwLcd :<c-u>call <SID>NetrwLcd(b:netrw_curdir)<cr>
+ nnoremap <buffer> <silent> <Plug>NetrwSetChgwin :<c-u>call <SID>NetrwSetChgwin()<cr>
+ nnoremap <buffer> <silent> <Plug>NetrwLocalBrowseCheck :<c-u>call netrw#LocalBrowseCheck(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord()))<cr>
+ nnoremap <buffer> <silent> <Plug>NetrwServerEdit :<c-u>call <SID>NetrwServerEdit(3,<SID>NetrwGetWord())<cr>
+ nnoremap <buffer> <silent> <Plug>NetrwMakeDir :<c-u>call <SID>NetrwMakeDir("")<cr>
+ nnoremap <buffer> <silent> <Plug>NetrwBookHistHandler_gb :<c-u>call <SID>NetrwBookHistHandler(1,b:netrw_curdir)<cr>
+" ---------------------------------------------------------------------
nnoremap <buffer> <silent> <nowait> gd :<c-u>call <SID>NetrwForceChgDir(1,<SID>NetrwGetWord())<cr>
nnoremap <buffer> <silent> <nowait> gf :<c-u>call <SID>NetrwForceFile(1,<SID>NetrwGetWord())<cr>
nnoremap <buffer> <silent> <nowait> gh :<c-u>call <SID>NetrwHidden(1)<cr>
- nnoremap <buffer> <silent> <nowait> gn :<c-u>call netrw#SetTreetop(<SID>NetrwGetWord())<cr>
+ nnoremap <buffer> <silent> <nowait> gn :<c-u>call netrw#SetTreetop(0,<SID>NetrwGetWord())<cr>
nnoremap <buffer> <silent> <nowait> gp :<c-u>call <SID>NetrwChgPerm(1,b:netrw_curdir)<cr>
nnoremap <buffer> <silent> <nowait> I :<c-u>call <SID>NetrwBannerCtrl(1)<cr>
nnoremap <buffer> <silent> <nowait> i :<c-u>call <SID>NetrwListStyle(1)<cr>
@@ -6041,7 +6440,6 @@ fun! s:NetrwMaps(islocal)
nnoremap <buffer> <silent> <nowait> qf :<c-u>call <SID>NetrwFileInfo(1,<SID>NetrwGetWord())<cr>
nnoremap <buffer> <silent> <nowait> qF :<c-u>call <SID>NetrwMarkFileQFEL(1,getqflist())<cr>
nnoremap <buffer> <silent> <nowait> qL :<c-u>call <SID>NetrwMarkFileQFEL(1,getloclist(v:count))<cr>
- nnoremap <buffer> <silent> <nowait> r :<c-u>let g:netrw_sort_direction= (g:netrw_sort_direction =~# 'n')? 'r' : 'n'<bar>exe "norm! 0"<bar>call <SID>NetrwRefresh(1,<SID>NetrwBrowseChgDir(1,'./'))<cr>
nnoremap <buffer> <silent> <nowait> s :call <SID>NetrwSortStyle(1)<cr>
nnoremap <buffer> <silent> <nowait> S :<c-u>call <SID>NetSortSequence(1)<cr>
nnoremap <buffer> <silent> <nowait> Tb :<c-u>call <SID>NetrwSetTgt(1,'b',v:count1)<cr>
@@ -6052,104 +6450,44 @@ fun! s:NetrwMaps(islocal)
nnoremap <buffer> <silent> <nowait> v :call <SID>NetrwSplit(5)<cr>
nnoremap <buffer> <silent> <nowait> x :<c-u>call netrw#BrowseX(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord(),0),0)"<cr>
nnoremap <buffer> <silent> <nowait> X :<c-u>call <SID>NetrwLocalExecute(expand("<cword>"))"<cr>
-" " local insert-mode maps
-" inoremap <buffer> <silent> <nowait> a <c-o>:call <SID>NetrwHide(1)<cr>
-" inoremap <buffer> <silent> <nowait> c <c-o>:exe "NetrwKeepj lcd ".fnameescape(b:netrw_curdir)<cr>
-" inoremap <buffer> <silent> <nowait> c <c-o>:call <SID>NetrwLcd(b:netrw_curdir)<cr>
-" inoremap <buffer> <silent> <nowait> C <c-o>:call <SID>NetrwSetChgwin()<cr>
-" inoremap <buffer> <silent> <nowait> % <c-o>:call <SID>NetrwOpenFile(1)<cr>
-" inoremap <buffer> <silent> <nowait> - <c-o>:call <SID>NetrwBrowseUpDir(1)<cr>
-" inoremap <buffer> <silent> <nowait> <cr> <c-o>:call netrw#LocalBrowseCheck(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord()))<cr>
-" inoremap <buffer> <silent> <nowait> d <c-o>:call <SID>NetrwMakeDir("")<cr>
-" inoremap <buffer> <silent> <nowait> gb <c-o>:<c-u>call <SID>NetrwBookHistHandler(1,b:netrw_curdir)<cr>
-" inoremap <buffer> <silent> <nowait> gh <c-o>:<c-u>call <SID>NetrwHidden(1)<cr>
-" nnoremap <buffer> <silent> <nowait> gn :<c-u>call netrw#SetTreetop(<SID>NetrwGetWord())<cr>
-" inoremap <buffer> <silent> <nowait> gp <c-o>:<c-u>call <SID>NetrwChgPerm(1,b:netrw_curdir)<cr>
-" inoremap <buffer> <silent> <nowait> I <c-o>:call <SID>NetrwBannerCtrl(1)<cr>
-" inoremap <buffer> <silent> <nowait> i <c-o>:call <SID>NetrwListStyle(1)<cr>
-" inoremap <buffer> <silent> <nowait> mb <c-o>:<c-u>call <SID>NetrwBookHistHandler(0,b:netrw_curdir)<cr>
-" inoremap <buffer> <silent> <nowait> mB <c-o>:<c-u>call <SID>NetrwBookHistHandler(6,b:netrw_curdir)<cr>
-" inoremap <buffer> <silent> <nowait> mc <c-o>:<c-u>call <SID>NetrwMarkFileCopy(1)<cr>
-" inoremap <buffer> <silent> <nowait> md <c-o>:<c-u>call <SID>NetrwMarkFileDiff(1)<cr>
-" inoremap <buffer> <silent> <nowait> me <c-o>:<c-u>call <SID>NetrwMarkFileEdit(1)<cr>
-" inoremap <buffer> <silent> <nowait> mf <c-o>:<c-u>call <SID>NetrwMarkFile(1,<SID>NetrwGetWord())<cr>
-" inoremap <buffer> <silent> <nowait> mg <c-o>:<c-u>call <SID>NetrwMarkFileGrep(1)<cr>
-" inoremap <buffer> <silent> <nowait> mh <c-o>:<c-u>call <SID>NetrwMarkHideSfx(1)<cr>
-" inoremap <buffer> <silent> <nowait> mm <c-o>:<c-u>call <SID>NetrwMarkFileMove(1)<cr>
-" inoremap <buffer> <silent> <nowait> mp <c-o>:<c-u>call <SID>NetrwMarkFilePrint(1)<cr>
-" inoremap <buffer> <silent> <nowait> mr <c-o>:<c-u>call <SID>NetrwMarkFileRegexp(1)<cr>
-" inoremap <buffer> <silent> <nowait> ms <c-o>:<c-u>call <SID>NetrwMarkFileSource(1)<cr>
-" inoremap <buffer> <silent> <nowait> mT <c-o>:<c-u>call <SID>NetrwMarkFileTag(1)<cr>
-" inoremap <buffer> <silent> <nowait> mt <c-o>:<c-u>call <SID>NetrwMarkFileTgt(1)<cr>
-" inoremap <buffer> <silent> <nowait> mu <c-o>:<c-u>call <SID>NetrwUnMarkFile(1)<cr>
-" inoremap <buffer> <silent> <nowait> mv <c-o>:<c-u>call <SID>NetrwMarkFileVimCmd(1)<cr>
-" inoremap <buffer> <silent> <nowait> mx <c-o>:<c-u>call <SID>NetrwMarkFileExe(1,0)<cr>
-" inoremap <buffer> <silent> <nowait> mX <c-o>:<c-u>call <SID>NetrwMarkFileExe(1,1)<cr>
-" inoremap <buffer> <silent> <nowait> mz <c-o>:<c-u>call <SID>NetrwMarkFileCompress(1)<cr>
-" inoremap <buffer> <silent> <nowait> O <c-o>:call <SID>NetrwObtain(1)<cr>
-" inoremap <buffer> <silent> <nowait> o <c-o>:call <SID>NetrwSplit(3)<cr>
-" inoremap <buffer> <silent> <nowait> p <c-o>:call <SID>NetrwPreview(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord(),1))<cr>
-" inoremap <buffer> <silent> <nowait> P <c-o>:call <SID>NetrwPrevWinOpen(1)<cr>
-" inoremap <buffer> <silent> <nowait> qb <c-o>:<c-u>call <SID>NetrwBookHistHandler(2,b:netrw_curdir)<cr>
-" inoremap <buffer> <silent> <nowait> qf <c-o>:<c-u>call <SID>NetrwFileInfo(1,<SID>NetrwGetWord())<cr>
-" inoremap <buffer> <silent> <nowait> qF :<c-u>call <SID>NetrwMarkFileQFEL(1,getqflist())<cr>
-" inoremap <buffer> <silent> <nowait> qL :<c-u>call <SID>NetrwMarkFileQFEL(1,getloclist(v:count))<cr>
-" inoremap <buffer> <silent> <nowait> r <c-o>:let g:netrw_sort_direction= (g:netrw_sort_direction =~# 'n')? 'r' : 'n'<bar>exe "norm! 0"<bar>call <SID>NetrwRefresh(1,<SID>NetrwBrowseChgDir(1,'./'))<cr>
-" inoremap <buffer> <silent> <nowait> s <c-o>:call <SID>NetrwSortStyle(1)<cr>
-" inoremap <buffer> <silent> <nowait> S <c-o>:call <SID>NetSortSequence(1)<cr>
-" inoremap <buffer> <silent> <nowait> t <c-o>:call <SID>NetrwSplit(4)<cr>
-" inoremap <buffer> <silent> <nowait> Tb <c-o>:<c-u>call <SID>NetrwSetTgt(1,'b',v:count1)<cr>
-" inoremap <buffer> <silent> <nowait> Th <c-o>:<c-u>call <SID>NetrwSetTgt(1,'h',v:count)<cr>
-" inoremap <buffer> <silent> <nowait> u <c-o>:<c-u>call <SID>NetrwBookHistHandler(4,expand("%"))<cr>
-" inoremap <buffer> <silent> <nowait> U <c-o>:<c-u>call <SID>NetrwBookHistHandler(5,expand("%"))<cr>
-" inoremap <buffer> <silent> <nowait> v <c-o>:call <SID>NetrwSplit(5)<cr>
-" inoremap <buffer> <silent> <nowait> x <c-o>:call netrw#BrowseX(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord(),0),0)"<cr>
+
+ nnoremap <buffer> <silent> <nowait> r :<c-u>let g:netrw_sort_direction= (g:netrw_sort_direction =~# 'n')? 'r' : 'n'<bar>exe "norm! 0"<bar>call <SID>NetrwRefresh(1,<SID>NetrwBrowseChgDir(1,'./'))<cr>
if !hasmapto('<Plug>NetrwHideEdit')
nmap <buffer> <unique> <c-h> <Plug>NetrwHideEdit
-" imap <buffer> <unique> <c-h> <c-o><Plug>NetrwHideEdit
endif
nnoremap <buffer> <silent> <Plug>NetrwHideEdit :call <SID>NetrwHideEdit(1)<cr>
if !hasmapto('<Plug>NetrwRefresh')
nmap <buffer> <unique> <c-l> <Plug>NetrwRefresh
-" imap <buffer> <unique> <c-l> <c-o><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>
if s:didstarstar || !mapcheck("<s-down>","n")
nnoremap <buffer> <silent> <s-down> :Nexplore<cr>
-" inoremap <buffer> <silent> <s-down> <c-o>:Nexplore<cr>
endif
if s:didstarstar || !mapcheck("<s-up>","n")
nnoremap <buffer> <silent> <s-up> :Pexplore<cr>
-" inoremap <buffer> <silent> <s-up> <c-o>:Pexplore<cr>
endif
if !hasmapto('<Plug>NetrwTreeSqueeze')
nmap <buffer> <silent> <nowait> <s-cr> <Plug>NetrwTreeSqueeze
-" imap <buffer> <silent> <nowait> <s-cr> <c-o><Plug>NetrwTreeSqueeze
endif
nnoremap <buffer> <silent> <Plug>NetrwTreeSqueeze :call <SID>TreeSqueezeDir(1)<cr>
let mapsafecurdir = escape(b:netrw_curdir, s:netrw_map_escape)
if g:netrw_mousemaps == 1
- nmap <buffer> <leftmouse> <Plug>NetrwLeftmouse
+ nmap <buffer> <leftmouse> <Plug>NetrwLeftmouse
+ nmap <buffer> <c-leftmouse> <Plug>NetrwCLeftmouse
+ nmap <buffer> <middlemouse> <Plug>NetrwMiddlemouse
+ nmap <buffer> <s-leftmouse> <Plug>NetrwSLeftmouse
+ nmap <buffer> <s-leftdrag> <Plug>NetrwSLeftdrag
+ nmap <buffer> <2-leftmouse> <Plug>Netrw2Leftmouse
+ imap <buffer> <leftmouse> <Plug>ILeftmouse
+ imap <buffer> <middlemouse> <Plug>IMiddlemouse
nno <buffer> <silent> <Plug>NetrwLeftmouse <leftmouse>:call <SID>NetrwLeftmouse(1)<cr>
- nmap <buffer> <c-leftmouse> <Plug>NetrwCLeftmouse
nno <buffer> <silent> <Plug>NetrwCLeftmouse <leftmouse>:call <SID>NetrwCLeftmouse(1)<cr>
- nmap <buffer> <middlemouse> <Plug>NetrwMiddlemouse
nno <buffer> <silent> <Plug>NetrwMiddlemouse <leftmouse>:call <SID>NetrwPrevWinOpen(1)<cr>
- nmap <buffer> <s-leftmouse> <Plug>NetrwSLeftmouse
nno <buffer> <silent> <Plug>NetrwSLeftmouse <leftmouse>:call <SID>NetrwSLeftmouse(1)<cr>
- nmap <buffer> <s-leftdrag> <Plug>NetrwSLeftdrag
nno <buffer> <silent> <Plug>NetrwSLeftdrag <leftmouse>:call <SID>NetrwSLeftdrag(1)<cr>
- nmap <buffer> <2-leftmouse> <Plug>Netrw2Leftmouse
nmap <buffer> <silent> <Plug>Netrw2Leftmouse -
- imap <buffer> <leftmouse> <Plug>ILeftmouse
-" ino <buffer> <silent> <Plug>ILeftmouse <c-o><leftmouse><c-o>:call <SID>NetrwLeftmouse(1)<cr>
- imap <buffer> <middlemouse> <Plug>IMiddlemouse
-" ino <buffer> <silent> <Plug>IMiddlemouse <c-o><leftmouse><c-o>:call <SID>NetrwPrevWinOpen(1)<cr>
-" imap <buffer> <s-leftmouse> <Plug>ISLeftmouse
-" ino <buffer> <silent> <Plug>ISLeftmouse <c-o><leftmouse><c-o>:call <SID>NetrwMarkFile(1,<SID>NetrwGetWord())<cr>
exe 'nnoremap <buffer> <silent> <rightmouse> <leftmouse>:call <SID>NetrwLocalRm("'.mapsafecurdir.'")<cr>'
exe 'vnoremap <buffer> <silent> <rightmouse> <leftmouse>:call <SID>NetrwLocalRm("'.mapsafecurdir.'")<cr>'
-" exe 'inoremap <buffer> <silent> <rightmouse> <c-o><leftmouse><c-o>:call <SID>NetrwLocalRm("'.mapsafecurdir.'")<cr>'
endif
exe 'nnoremap <buffer> <silent> <nowait> <del> :call <SID>NetrwLocalRm("'.mapsafecurdir.'")<cr>'
exe 'nnoremap <buffer> <silent> <nowait> D :call <SID>NetrwLocalRm("'.mapsafecurdir.'")<cr>'
@@ -6158,27 +6496,27 @@ fun! s:NetrwMaps(islocal)
exe 'vnoremap <buffer> <silent> <nowait> <del> :call <SID>NetrwLocalRm("'.mapsafecurdir.'")<cr>'
exe 'vnoremap <buffer> <silent> <nowait> D :call <SID>NetrwLocalRm("'.mapsafecurdir.'")<cr>'
exe 'vnoremap <buffer> <silent> <nowait> R :call <SID>NetrwLocalRename("'.mapsafecurdir.'")<cr>'
-" exe 'inoremap <buffer> <silent> <nowait> <del> <c-o>:call <SID>NetrwLocalRm("'.mapsafecurdir.'")<cr>'
-" exe 'inoremap <buffer> <silent> <nowait> D <c-o>:call <SID>NetrwLocalRm("'.mapsafecurdir.'")<cr>'
-" exe 'inoremap <buffer> <silent> <nowait> R <c-o>:call <SID>NetrwLocalRename("'.mapsafecurdir.'")<cr>'
-" exe 'inoremap <buffer> <silent> <nowait> d <c-o>:call <SID>NetrwMakeDir("")<cr>'
nnoremap <buffer> <F1> :he netrw-quickhelp<cr>
" support user-specified maps
call netrw#UserMaps(1)
- else " remote
+ else
+ " remote normal-mode maps {{{3
" call Decho("make remote maps",'~'.expand("<slnum>"))
call s:RemotePathAnalysis(b:netrw_curdir)
- " remote normal-mode maps
- nnoremap <buffer> <silent> <nowait> a :<c-u>call <SID>NetrwHide(0)<cr>
- nnoremap <buffer> <silent> <nowait> - :<c-u>call <SID>NetrwBrowseUpDir(0)<cr>
- nnoremap <buffer> <silent> <nowait> % :<c-u>call <SID>NetrwOpenFile(0)<cr>
- nnoremap <buffer> <silent> <nowait> C :<c-u>call <SID>NetrwSetChgwin()<cr>
- nnoremap <buffer> <silent> <nowait> <c-l> :<c-u>call <SID>NetrwRefresh(0,<SID>NetrwBrowseChgDir(0,'./'))<cr>
- nnoremap <buffer> <silent> <nowait> <cr> :<c-u>call <SID>NetrwBrowse(0,<SID>NetrwBrowseChgDir(0,<SID>NetrwGetWord()))<cr>
- nnoremap <buffer> <silent> <nowait> <c-r> :<c-u>call <SID>NetrwServerEdit(2,<SID>NetrwGetWord())<cr>
- nnoremap <buffer> <silent> <nowait> gb :<c-u>call <SID>NetrwBookHistHandler(1,b:netrw_curdir)<cr>
+ nnoremap <buffer> <silent> <Plug>NetrwHide_a :<c-u>call <SID>NetrwHide(0)<cr>
+ nnoremap <buffer> <silent> <Plug>NetrwBrowseUpDir :<c-u>call <SID>NetrwBrowseUpDir(0)<cr>
+ nnoremap <buffer> <silent> <Plug>NetrwOpenFile :<c-u>call <SID>NetrwOpenFile(0)<cr>
+ nnoremap <buffer> <silent> <Plug>NetrwBadd_cb :<c-u>call <SID>NetrwBadd(0,0)<cr>
+ nnoremap <buffer> <silent> <Plug>NetrwBadd_cB :<c-u>call <SID>NetrwBadd(0,1)<cr>
+ nnoremap <buffer> <silent> <Plug>NetrwLcd :<c-u>call <SID>NetrwLcd(b:netrw_curdir)<cr>
+ nnoremap <buffer> <silent> <Plug>NetrwSetChgwin :<c-u>call <SID>NetrwSetChgwin()<cr>
+ nnoremap <buffer> <silent> <Plug>NetrwRefresh :<c-u>call <SID>NetrwRefresh(0,<SID>NetrwBrowseChgDir(0,'./'))<cr>
+ nnoremap <buffer> <silent> <Plug>NetrwLocalBrowseCheck :<c-u>call <SID>NetrwBrowse(0,<SID>NetrwBrowseChgDir(0,<SID>NetrwGetWord()))<cr>
+ nnoremap <buffer> <silent> <Plug>NetrwServerEdit :<c-u>call <SID>NetrwServerEdit(2,<SID>NetrwGetWord())<cr>
+ nnoremap <buffer> <silent> <Plug>NetrwBookHistHandler_gb :<c-u>call <SID>NetrwBookHistHandler(1,b:netrw_curdir)<cr>
+" ---------------------------------------------------------------------
nnoremap <buffer> <silent> <nowait> gd :<c-u>call <SID>NetrwForceChgDir(0,<SID>NetrwGetWord())<cr>
nnoremap <buffer> <silent> <nowait> gf :<c-u>call <SID>NetrwForceFile(0,<SID>NetrwGetWord())<cr>
nnoremap <buffer> <silent> <nowait> gh :<c-u>call <SID>NetrwHidden(0)<cr>
@@ -6225,69 +6563,15 @@ fun! s:NetrwMaps(islocal)
nnoremap <buffer> <silent> <nowait> U :<c-u>call <SID>NetrwBookHistHandler(5,b:netrw_curdir)<cr>
nnoremap <buffer> <silent> <nowait> v :call <SID>NetrwSplit(2)<cr>
nnoremap <buffer> <silent> <nowait> x :<c-u>call netrw#BrowseX(<SID>NetrwBrowseChgDir(0,<SID>NetrwGetWord()),1)<cr>
-" " remote insert-mode maps
-" inoremap <buffer> <silent> <nowait> <cr> <c-o>:call <SID>NetrwBrowse(0,<SID>NetrwBrowseChgDir(0,<SID>NetrwGetWord()))<cr>
-" inoremap <buffer> <silent> <nowait> <c-l> <c-o>:call <SID>NetrwRefresh(0,<SID>NetrwBrowseChgDir(0,'./'))<cr>
-" inoremap <buffer> <silent> <nowait> <s-cr> <c-o>:call <SID>TreeSqueezeDir(0)<cr>
-" inoremap <buffer> <silent> <nowait> - <c-o>:call <SID>NetrwBrowseUpDir(0)<cr>
-" inoremap <buffer> <silent> <nowait> a <c-o>:call <SID>NetrwHide(0)<cr>
-" inoremap <buffer> <silent> <nowait> mb <c-o>:<c-u>call <SID>NetrwBookHistHandler(0,b:netrw_curdir)<cr>
-" inoremap <buffer> <silent> <nowait> mc <c-o>:<c-u>call <SID>NetrwMarkFileCopy(0)<cr>
-" inoremap <buffer> <silent> <nowait> md <c-o>:<c-u>call <SID>NetrwMarkFileDiff(0)<cr>
-" inoremap <buffer> <silent> <nowait> me <c-o>:<c-u>call <SID>NetrwMarkFileEdit(0)<cr>
-" inoremap <buffer> <silent> <nowait> mf <c-o>:<c-u>call <SID>NetrwMarkFile(0,<SID>NetrwGetWord())<cr>
-" inoremap <buffer> <silent> <nowait> mg <c-o>:<c-u>call <SID>NetrwMarkFileGrep(0)<cr>
-" inoremap <buffer> <silent> <nowait> mh <c-o>:<c-u>call <SID>NetrwMarkHideSfx(0)<cr>
-" inoremap <buffer> <silent> <nowait> mm <c-o>:<c-u>call <SID>NetrwMarkFileMove(0)<cr>
-" inoremap <buffer> <silent> <nowait> mp <c-o>:<c-u>call <SID>NetrwMarkFilePrint(0)<cr>
-" inoremap <buffer> <silent> <nowait> mr <c-o>:<c-u>call <SID>NetrwMarkFileRegexp(0)<cr>
-" inoremap <buffer> <silent> <nowait> ms <c-o>:<c-u>call <SID>NetrwMarkFileSource(0)<cr>
-" inoremap <buffer> <silent> <nowait> mt <c-o>:<c-u>call <SID>NetrwMarkFileTgt(0)<cr>
-" inoremap <buffer> <silent> <nowait> mT <c-o>:<c-u>call <SID>NetrwMarkFileTag(0)<cr>
-" inoremap <buffer> <silent> <nowait> mu <c-o>:<c-u>call <SID>NetrwUnMarkFile(0)<cr>
-" nnoremap <buffer> <silent> <nowait> mv :<c-u>call <SID>NetrwMarkFileVimCmd(1)<cr>
-" inoremap <buffer> <silent> <nowait> mx <c-o>:<c-u>call <SID>NetrwMarkFileExe(0,0)<cr>
-" inoremap <buffer> <silent> <nowait> mX <c-o>:<c-u>call <SID>NetrwMarkFileExe(0,1)<cr>
-" inoremap <buffer> <silent> <nowait> mv <c-o>:<c-u>call <SID>NetrwMarkFileVimCmd(0)<cr>
-" inoremap <buffer> <silent> <nowait> mz <c-o>:<c-u>call <SID>NetrwMarkFileCompress(0)<cr>
-" inoremap <buffer> <silent> <nowait> gb <c-o>:<c-u>call <SID>NetrwBookHistHandler(1,b:netrw_curdir)<cr>
-" inoremap <buffer> <silent> <nowait> gh <c-o>:<c-u>call <SID>NetrwHidden(0)<cr>
-" inoremap <buffer> <silent> <nowait> gp <c-o>:<c-u>call <SID>NetrwChgPerm(0,b:netrw_curdir)<cr>
-" inoremap <buffer> <silent> <nowait> C <c-o>:call <SID>NetrwSetChgwin()<cr>
-" inoremap <buffer> <silent> <nowait> i <c-o>:call <SID>NetrwListStyle(0)<cr>
-" inoremap <buffer> <silent> <nowait> I <c-o>:call <SID>NetrwBannerCtrl(1)<cr>
-" inoremap <buffer> <silent> <nowait> o <c-o>:call <SID>NetrwSplit(0)<cr>
-" inoremap <buffer> <silent> <nowait> O <c-o>:call <SID>NetrwObtain(0)<cr>
-" inoremap <buffer> <silent> <nowait> p <c-o>:call <SID>NetrwPreview(<SID>NetrwBrowseChgDir(1,<SID>NetrwGetWord(),1))<cr>
-" inoremap <buffer> <silent> <nowait> P <c-o>:call <SID>NetrwPrevWinOpen(0)<cr>
-" inoremap <buffer> <silent> <nowait> qb <c-o>:<c-u>call <SID>NetrwBookHistHandler(2,b:netrw_curdir)<cr>
-" inoremap <buffer> <silent> <nowait> mB <c-o>:<c-u>call <SID>NetrwBookHistHandler(6,b:netrw_curdir)<cr>
-" inoremap <buffer> <silent> <nowait> qf <c-o>:<c-u>call <SID>NetrwFileInfo(0,<SID>NetrwGetWord())<cr>
-" inoremap <buffer> <silent> <nowait> qF :<c-u>call <SID>NetrwMarkFileQFEL(0,getqflist())<cr>
-" inoremap <buffer> <silent> <nowait> qL :<c-u>call <SID>NetrwMarkFileQFEL(0,getloclist(v:count))<cr>
-" inoremap <buffer> <silent> <nowait> r <c-o>:let g:netrw_sort_direction= (g:netrw_sort_direction =~# 'n')? 'r' : 'n'<bar>exe "norm! 0"<bar>call <SID>NetrwBrowse(0,<SID>NetrwBrowseChgDir(0,'./'))<cr>
-" inoremap <buffer> <silent> <nowait> s <c-o>:call <SID>NetrwSortStyle(0)<cr>
-" inoremap <buffer> <silent> <nowait> S <c-o>:call <SID>NetSortSequence(0)<cr>
-" inoremap <buffer> <silent> <nowait> t <c-o>:call <SID>NetrwSplit(1)<cr>
-" inoremap <buffer> <silent> <nowait> Tb <c-o>:<c-u>call <SID>NetrwSetTgt('b',v:count1)<cr>
-" inoremap <buffer> <silent> <nowait> Th <c-o>:<c-u>call <SID>NetrwSetTgt('h',v:count)<cr>
-" inoremap <buffer> <silent> <nowait> u <c-o>:<c-u>call <SID>NetrwBookHistHandler(4,b:netrw_curdir)<cr>
-" inoremap <buffer> <silent> <nowait> U <c-o>:<c-u>call <SID>NetrwBookHistHandler(5,b:netrw_curdir)<cr>
-" inoremap <buffer> <silent> <nowait> v <c-o>:call <SID>NetrwSplit(2)<cr>
-" inoremap <buffer> <silent> <nowait> x <c-o>:call netrw#BrowseX(<SID>NetrwBrowseChgDir(0,<SID>NetrwGetWord()),1)<cr>
-" inoremap <buffer> <silent> <nowait> % <c-o>:call <SID>NetrwOpenFile(0)<cr>
if !hasmapto('<Plug>NetrwHideEdit')
nmap <buffer> <c-h> <Plug>NetrwHideEdit
-" imap <buffer> <c-h> <Plug>NetrwHideEdit
endif
nnoremap <buffer> <silent> <Plug>NetrwHideEdit :call <SID>NetrwHideEdit(0)<cr>
if !hasmapto('<Plug>NetrwRefresh')
nmap <buffer> <c-l> <Plug>NetrwRefresh
-" imap <buffer> <c-l> <Plug>NetrwRefresh
endif
if !hasmapto('<Plug>NetrwTreeSqueeze')
nmap <buffer> <silent> <nowait> <s-cr> <Plug>NetrwTreeSqueeze
-" imap <buffer> <silent> <nowait> <s-cr> <c-o><Plug>NetrwTreeSqueeze
endif
nnoremap <buffer> <silent> <Plug>NetrwTreeSqueeze :call <SID>TreeSqueezeDir(0)<cr>
@@ -6309,14 +6593,10 @@ fun! s:NetrwMaps(islocal)
nmap <buffer> <2-leftmouse> <Plug>Netrw2Leftmouse
nmap <buffer> <silent> <Plug>Netrw2Leftmouse -
imap <buffer> <leftmouse> <Plug>ILeftmouse
-" ino <buffer> <silent> <Plug>ILeftmouse <c-o><leftmouse><c-o>:call <SID>NetrwLeftmouse(0)<cr>
imap <buffer> <middlemouse> <Plug>IMiddlemouse
-" ino <buffer> <silent> <Plug>IMiddlemouse <c-o><leftmouse><c-o>:call <SID>NetrwPrevWinOpen(0)<cr>
imap <buffer> <s-leftmouse> <Plug>ISLeftmouse
-" ino <buffer> <silent> <Plug>ISLeftmouse <c-o><leftmouse><c-o>:call <SID>NetrwMarkFile(0,<SID>NetrwGetWord())<cr>
exe 'nnoremap <buffer> <silent> <rightmouse> <leftmouse>:call <SID>NetrwRemoteRm("'.mapsafeusermach.'","'.mapsafepath.'")<cr>'
exe 'vnoremap <buffer> <silent> <rightmouse> <leftmouse>:call <SID>NetrwRemoteRm("'.mapsafeusermach.'","'.mapsafepath.'")<cr>'
-" exe 'inoremap <buffer> <silent> <rightmouse> <c-o><leftmouse><c-o>:call <SID>NetrwRemoteRm("'.mapsafeusermach.'","'.mapsafepath.'")<cr>'
endif
exe 'nnoremap <buffer> <silent> <nowait> <del> :call <SID>NetrwRemoteRm("'.mapsafeusermach.'","'.mapsafepath.'")<cr>'
exe 'nnoremap <buffer> <silent> <nowait> d :call <SID>NetrwMakeDir("'.mapsafeusermach.'")<cr>'
@@ -6325,16 +6605,11 @@ fun! s:NetrwMaps(islocal)
exe 'vnoremap <buffer> <silent> <nowait> <del> :call <SID>NetrwRemoteRm("'.mapsafeusermach.'","'.mapsafepath.'")<cr>'
exe 'vnoremap <buffer> <silent> <nowait> D :call <SID>NetrwRemoteRm("'.mapsafeusermach.'","'.mapsafepath.'")<cr>'
exe 'vnoremap <buffer> <silent> <nowait> R :call <SID>NetrwRemoteRename("'.mapsafeusermach.'","'.mapsafepath.'")<cr>'
-" exe 'inoremap <buffer> <silent> <nowait> <del> <c-o>:call <SID>NetrwRemoteRm("'.mapsafeusermach.'","'.mapsafepath.'")<cr>'
-" exe 'inoremap <buffer> <silent> <nowait> d <c-o>:call <SID>NetrwMakeDir("'.mapsafeusermach.'")<cr>'
-" exe 'inoremap <buffer> <silent> <nowait> D <c-o>:call <SID>NetrwRemoteRm("'.mapsafeusermach.'","'.mapsafepath.'")<cr>'
-" exe 'inoremap <buffer> <silent> <nowait> R <c-o>:call <SID>NetrwRemoteRename("'.mapsafeusermach.'","'.mapsafepath.'")<cr>'
nnoremap <buffer> <F1> :he netrw-quickhelp<cr>
-" inoremap <buffer> <F1> <c-o>:he netrw-quickhelp<cr>
" support user-specified maps
call netrw#UserMaps(0)
- endif
+ endif " }}}3
" call Dret("s:NetrwMaps")
endfun
@@ -6531,14 +6806,16 @@ fun! s:NetrwMarkFile(islocal,fname)
endif
" set up 2match'ing to netrwmarkfilemtch_# list
- if exists("s:netrwmarkfilemtch_{curbufnr}") && s:netrwmarkfilemtch_{curbufnr} != ""
-" call Decho("exe 2match netrwMarkFile /".s:netrwmarkfilemtch_{curbufnr}."/",'~'.expand("<slnum>"))
- if exists("g:did_drchip_netrwlist_syntax")
- exe "2match netrwMarkFile /".s:netrwmarkfilemtch_{curbufnr}."/"
+ if has("syntax") && exists("g:syntax_on") && g:syntax_on
+ if exists("s:netrwmarkfilemtch_{curbufnr}") && s:netrwmarkfilemtch_{curbufnr} != ""
+" " call Decho("exe 2match netrwMarkFile /".s:netrwmarkfilemtch_{curbufnr}."/",'~'.expand("<slnum>"))
+ if exists("g:did_drchip_netrwlist_syntax")
+ exe "2match netrwMarkFile /".s:netrwmarkfilemtch_{curbufnr}."/"
+ endif
+ else
+" " call Decho("2match none",'~'.expand("<slnum>"))
+ 2match none
endif
- else
-" call Decho("2match none",'~'.expand("<slnum>"))
- 2match none
endif
let @@= ykeep
" call Dret("s:NetrwMarkFile : s:netrwmarkfilelist_".curbufnr."<".(exists("s:netrwmarkfilelist_{curbufnr}")? string(s:netrwmarkfilelist_{curbufnr}) : " doesn't exist").">")
@@ -6624,18 +6901,15 @@ fun! s:NetrwMarkFileCompress(islocal)
if g:netrw_keepdir
let fname= s:ShellEscape(s:ComposePath(curdir,fname))
endif
- else
- let fname= s:ShellEscape(b:netrw_curdir.fname,1)
- endif
- if executable(exe)
- if a:islocal
- call system(exe." ".fname)
- else
- NetrwKeepj call s:RemoteSystem(exe." ".fname)
+ call system(exe." ".fname)
+ if v:shell_error
+ NetrwKeepj call netrw#ErrorMsg(s:WARNING,"unable to apply<".exe."> to file<".fname.">",50)
endif
else
- NetrwKeepj call netrw#ErrorMsg(s:WARNING,"unable to apply<".exe."> to file<".fname.">",50)
+ let fname= s:ShellEscape(b:netrw_curdir.fname,1)
+ NetrwKeepj call s:RemoteSystem(exe." ".fname)
endif
+
endif
unlet sfx
@@ -6644,6 +6918,9 @@ fun! s:NetrwMarkFileCompress(islocal)
elseif a:islocal
" fname not a compressed file, so compress it
call system(netrw#WinPath(g:netrw_compress)." ".s:ShellEscape(s:ComposePath(b:netrw_curdir,fname)))
+ if v:shell_error
+ call netrw#ErrorMsg(s:WARNING,"consider setting g:netrw_compress<".g:netrw_compress."> to something that works",104)
+ endif
else
" fname not a compressed file, so compress it
NetrwKeepj call s:RemoteSystem(netrw#WinPath(g:netrw_compress)." ".s:ShellEscape(fname))
@@ -6695,7 +6972,7 @@ fun! s:NetrwMarkFileCopy(islocal,...)
if a:islocal && s:netrwmftgt_islocal
" Copy marked files, local directory to local directory
" call Decho("copy from local to local",'~'.expand("<slnum>"))
- if !executable(g:netrw_localcopycmd) && g:netrw_localcopycmd !~ '^'.expand("$COMSPEC").'\s'
+ if !executable(g:netrw_localcopycmd)
call netrw#ErrorMsg(s:ERROR,"g:netrw_localcopycmd<".g:netrw_localcopycmd."> not executable on your system, aborting",91)
" call Dfunc("s:NetrwMarkFileMove : g:netrw_localcopycmd<".g:netrw_localcopycmd."> n/a!")
return
@@ -6777,10 +7054,10 @@ fun! s:NetrwMarkFileCopy(islocal,...)
" call Decho("tgt <".tgt.">",'~'.expand("<slnum>"))
" call Decho("copycmd<".copycmd.">",'~'.expand("<slnum>"))
" call Decho("system(".copycmd." '".args."' '".tgt."')",'~'.expand("<slnum>"))
- call system(copycmd." '".args."' '".tgt."'")
+ call system(copycmd.g:netrw_localcopycmdopt." '".args."' '".tgt."'")
if v:shell_error != 0
if exists("b:netrw_curdir") && b:netrw_curdir != getcwd() && !g:netrw_keepdir
- call netrw#ErrorMsg(s:ERROR,"copy failed; perhaps due to vim's current directory<".getcwd()."> not matching netrw's (".b:netrw_curdir.") (see :help netrw-c)",101)
+ call netrw#ErrorMsg(s:ERROR,"copy failed; perhaps due to vim's current directory<".getcwd()."> not matching netrw's (".b:netrw_curdir.") (see :help netrw-cd)",101)
else
call netrw#ErrorMsg(s:ERROR,"tried using g:netrw_localcopycmd<".g:netrw_localcopycmd.">; it doesn't work!",80)
endif
@@ -6809,7 +7086,7 @@ fun! s:NetrwMarkFileCopy(islocal,...)
if exists("*mkdir")
call mkdir(tmpdir)
else
- call s:NetrwExe("sil! !".g:netrw_localmkdir.' '.s:ShellEscape(tmpdir,1))
+ call s:NetrwExe("sil! !".g:netrw_localmkdir.g:netrw_localmkdiropt.' '.s:ShellEscape(tmpdir,1))
if v:shell_error != 0
call netrw#ErrorMsg(s:WARNING,"consider setting g:netrw_localmkdir<".g:netrw_localmkdir."> to something that works",80)
" call Dret("s:NetrwMarkFileCopy : failed: sil! !".g:netrw_localmkdir.' '.s:ShellEscape(tmpdir,1) )
@@ -6817,7 +7094,10 @@ fun! s:NetrwMarkFileCopy(islocal,...)
endif
endif
if isdirectory(s:NetrwFile(tmpdir))
- call s:NetrwLcd(tmpdir)
+ if s:NetrwLcd(tmpdir)
+" call Dret("s:NetrwMarkFileCopy : lcd failure")
+ return
+ endif
NetrwKeepj call netrw#Obtain(a:islocal,s:netrwmarkfilelist_{bufnr('%')},tmpdir)
let localfiles= map(deepcopy(s:netrwmarkfilelist_{bufnr('%')}),'substitute(v:val,"^.*/","","")')
NetrwKeepj call s:NetrwUpload(localfiles,s:netrwmftgt)
@@ -6825,9 +7105,12 @@ fun! s:NetrwMarkFileCopy(islocal,...)
for fname in s:netrwmarkfilelist_{bufnr('%')}
NetrwKeepj call s:NetrwDelete(fname)
endfor
- call s:NetrwLcd(curdir)
- if v:version < 704 || !has("patch1109")
- call s:NetrwExe("sil !".g:netrw_localrmdir." ".s:ShellEscape(tmpdir,1))
+ if s:NetrwLcd(curdir)
+" call Dret("s:NetrwMarkFileCopy : lcd failure")
+ return
+ endif
+ if v:version < 704 || (v:version == 704 && !has("patch1107"))
+ call s:NetrwExe("sil !".g:netrw_localrmdir.g:netrw_localrmdiropt." ".s:ShellEscape(tmpdir,1))
if v:shell_error != 0
call netrw#ErrorMsg(s:WARNING,"consider setting g:netrw_localrmdir<".g:netrw_localrmdir."> to something that works",80)
" " call Dret("s:NetrwMarkFileCopy : failed: sil !".g:netrw_localrmdir." ".s:ShellEscape(tmpdir,1) )
@@ -6839,7 +7122,10 @@ fun! s:NetrwMarkFileCopy(islocal,...)
endif
endif
else
- call s:NetrwLcd(curdir)
+ if s:NetrwLcd(curdir)
+" call Dret("s:NetrwMarkFileCopy : lcd failure")
+ return
+ endif
endif
endif
endif
@@ -7366,15 +7652,15 @@ fun! s:NetrwMarkFileMove(islocal)
" move: local -> local
" call Decho("move from local to local",'~'.expand("<slnum>"))
" call Decho("local to local move",'~'.expand("<slnum>"))
- if !executable(g:netrw_localmovecmd) && g:netrw_localmovecmd !~ '^'.expand("$COMSPEC").'\s'
+ if !executable(g:netrw_localmovecmd)
call netrw#ErrorMsg(s:ERROR,"g:netrw_localmovecmd<".g:netrw_localmovecmd."> not executable on your system, aborting",90)
" call Dfunc("s:NetrwMarkFileMove : g:netrw_localmovecmd<".g:netrw_localmovecmd."> n/a!")
return
endif
- let tgt = s:ShellEscape(s:netrwmftgt)
+ let tgt = s:ShellEscape(s:netrwmftgt)
" call Decho("tgt<".tgt.">",'~'.expand("<slnum>"))
if !g:netrw_cygwin && (has("win32") || has("win95") || has("win64") || has("win16"))
- let tgt = substitute(tgt, '/','\\','g')
+ let tgt= substitute(tgt, '/','\\','g')
" call Decho("windows exception: tgt<".tgt.">",'~'.expand("<slnum>"))
if g:netrw_localmovecmd =~ '\s'
let movecmd = substitute(g:netrw_localmovecmd,'\s.*$','','')
@@ -7394,10 +7680,10 @@ fun! s:NetrwMarkFileMove(islocal)
let fname= substitute(fname,'/','\\','g')
endif
" call Decho("system(".movecmd." ".s:ShellEscape(fname)." ".tgt.")",'~'.expand("<slnum>"))
- let ret= system(movecmd." ".s:ShellEscape(fname)." ".tgt)
+ let ret= system(movecmd.g:netrw_localmovecmdopt." ".s:ShellEscape(fname)." ".tgt)
if v:shell_error != 0
if exists("b:netrw_curdir") && b:netrw_curdir != getcwd() && !g:netrw_keepdir
- call netrw#ErrorMsg(s:ERROR,"move failed; perhaps due to vim's current directory<".getcwd()."> not matching netrw's (".b:netrw_curdir.") (see :help netrw-c)",100)
+ call netrw#ErrorMsg(s:ERROR,"move failed; perhaps due to vim's current directory<".getcwd()."> not matching netrw's (".b:netrw_curdir.") (see :help netrw-cd)",100)
else
call netrw#ErrorMsg(s:ERROR,"tried using g:netrw_localmovecmd<".g:netrw_localmovecmd.">; it doesn't work!",54)
endif
@@ -7524,21 +7810,27 @@ fun! s:NetrwMarkFileRegexp(islocal)
if a:islocal
let curdir= s:NetrwGetCurdir(a:islocal)
+" call Decho("curdir<".fnameescape(curdir).">")
" get the matching list of files using local glob()
" call Decho("handle local regexp",'~'.expand("<slnum>"))
let dirname = escape(b:netrw_curdir,g:netrw_glob_escape)
if v:version > 704 || (v:version == 704 && has("patch656"))
- let files = glob(s:ComposePath(dirname,regexp),0,0,1)
+ let filelist= glob(s:ComposePath(dirname,regexp),0,1,1)
else
let files = glob(s:ComposePath(dirname,regexp),0,0)
+ let filelist= split(files,"\n")
endif
-" call Decho("files<".files.">",'~'.expand("<slnum>"))
- let filelist= split(files,"\n")
+" call Decho("files<".string(filelist).">",'~'.expand("<slnum>"))
" mark the list of files
for fname in filelist
-" call Decho("fname<".fname.">",'~'.expand("<slnum>"))
- NetrwKeepj call s:NetrwMarkFile(a:islocal,substitute(fname,'^.*/','',''))
+ if fname =~ '^'.fnameescape(curdir)
+" call Decho("fname<".substitute(fname,'^'.fnameescape(curdir).'/','','').">",'~'.expand("<slnum>"))
+ NetrwKeepj call s:NetrwMarkFile(a:islocal,substitute(fname,'^'.fnameescape(curdir).'/','',''))
+ else
+" call Decho("fname<".fname.">",'~'.expand("<slnum>"))
+ NetrwKeepj call s:NetrwMarkFile(a:islocal,substitute(fname,'^.*/','',''))
+ endif
endfor
else
@@ -7552,7 +7844,7 @@ fun! s:NetrwMarkFileRegexp(islocal)
" call Decho("setl ei=all ma",'~'.expand("<slnum>"))
1split
NetrwKeepj call s:NetrwEnew()
- NetrwKeepj call s:NetrwSafeOptions()
+ NetrwKeepj call s:NetrwOptionsSafe(a:islocal)
sil NetrwKeepj norm! "ap
NetrwKeepj 2
let bannercnt= search('^" =====','W')
@@ -7649,12 +7941,13 @@ fun! s:NetrwMarkFileTag(islocal)
call s:NetrwUnmarkAll()
if a:islocal
- if executable(g:netrw_ctags)
-" call Decho("call system(".g:netrw_ctags." ".netrwmarkfilelist.")",'~'.expand("<slnum>"))
- call system(g:netrw_ctags." ".netrwmarkfilelist)
- else
+
+" call Decho("call system(".g:netrw_ctags." ".netrwmarkfilelist.")",'~'.expand("<slnum>"))
+ call system(g:netrw_ctags." ".netrwmarkfilelist)
+ if v:shell_error
call netrw#ErrorMsg(s:ERROR,"g:netrw_ctags<".g:netrw_ctags."> is not executable!",51)
endif
+
else
let cmd = s:RemoteSystem(g:netrw_ctags." ".netrwmarkfilelist)
call netrw#Obtain(a:islocal,"tags")
@@ -8109,7 +8402,7 @@ fun! s:NetrwObtain(islocal)
call netrw#Obtain(islocal,s:netrwmarkfilelist_{bufnr('%')})
call s:NetrwUnmarkList(bufnr('%'),b:netrw_curdir)
else
- call netrw#Obtain(a:islocal,expand("<cWORD>"))
+ call netrw#Obtain(a:islocal,s:NetrwGetWord())
endif
let @@= ykeep
@@ -8144,14 +8437,16 @@ fun! s:NetrwPrevWinOpen(islocal)
if lastwinnr == 1
" if only one window, open a new one first
" call Decho("only one window, so open a new one (g:netrw_alto=".g:netrw_alto.")",'~'.expand("<slnum>"))
+ " g:netrw_preview=0: preview window shown in a horizontally split window
+ " g:netrw_preview=1: preview window shown in a vertically split window
if g:netrw_preview
" vertically split preview window
- let winsz= (g:netrw_winsize > 0)? (g:netrw_winsize*winheight(0))/100 : -g:netrw_winsize
+ let winsz= (g:netrw_winsize > 0)? (g:netrw_winsize*winwidth(0))/100 : -g:netrw_winsize
" call Decho("exe ".(g:netrw_alto? "top " : "bot ")."vert ".winsz."wincmd s",'~'.expand("<slnum>"))
exe (g:netrw_alto? "top " : "bot ")."vert ".winsz."wincmd s"
else
" horizontally split preview window
- let winsz= (g:netrw_winsize > 0)? (g:netrw_winsize*winwidth(0))/100 : -g:netrw_winsize
+ let winsz= (g:netrw_winsize > 0)? (g:netrw_winsize*winheight(0))/100 : -g:netrw_winsize
" call Decho("exe ".(g:netrw_alto? "bel " : "abo ").winsz."wincmd s",'~'.expand("<slnum>"))
exe (g:netrw_alto? "bel " : "abo ").winsz."wincmd s"
endif
@@ -8189,7 +8484,7 @@ fun! s:NetrwPrevWinOpen(islocal)
" only one copy of the modified buffer in a window, and
" hidden not set, so overwriting will lose the modified file. Ask first...
let choice = confirm("Save modified buffer<".prevbufname."> first?","&Yes\n&No\n&Cancel")
-" call Decho("(NetrwPrevWinOpen) prevbufname<".prevbufname."> choice=".choice." current-winnr#".winnr(),'~'.expand("<slnum>"))
+" call Decho("prevbufname<".prevbufname."> choice=".choice." current-winnr#".winnr(),'~'.expand("<slnum>"))
let &ei= eikeep
if choice == 1
@@ -8283,7 +8578,10 @@ fun! s:NetrwUpload(fname,tgt,...)
" call Decho("handle uploading a list of files via scp",'~'.expand("<slnum>"))
let curdir= getcwd()
if a:tgt =~ '^scp:'
- call s:NetrwLcd(fromdir)
+ if s:NetrwLcd(fromdir)
+" call Dret("s:NetrwUpload : lcd failure")
+ return
+ endif
let filelist= deepcopy(s:netrwmarkfilelist_{bufnr('%')})
let args = join(map(filelist,"s:ShellEscape(v:val, 1)"))
if exists("g:netrw_port") && g:netrw_port != ""
@@ -8294,7 +8592,10 @@ fun! s:NetrwUpload(fname,tgt,...)
let machine = substitute(a:tgt,'^scp://\([^/:]\+\).*$','\1','')
let tgt = substitute(a:tgt,'^scp://[^/]\+/\(.*\)$','\1','')
call s:NetrwExe(s:netrw_silentxfer."!".g:netrw_scp_cmd.s:ShellEscape(useport,1)." ".args." ".s:ShellEscape(machine.":".tgt,1))
- call s:NetrwLcd(curdir)
+ if s:NetrwLcd(curdir)
+" call Dret("s:NetrwUpload : lcd failure")
+ return
+ endif
elseif a:tgt =~ '^ftp:'
call s:NetrwMethod(a:tgt)
@@ -8408,7 +8709,7 @@ fun! s:NetrwUpload(fname,tgt,...)
bw!|q
endif
elseif !exists("b:netrw_method") || b:netrw_method < 0
-" call Dfunc("netrw#NetrwUpload : unsupported method")
+" call Dret("s:#NetrwUpload : unsupported method")
return
endif
else
@@ -8420,20 +8721,49 @@ fun! s:NetrwUpload(fname,tgt,...)
endfun
" ---------------------------------------------------------------------
-" s:NetrwPreview: {{{2
+" s:NetrwPreview: supports netrw's "p" map {{{2
fun! s:NetrwPreview(path) range
" call Dfunc("NetrwPreview(path<".a:path.">)")
+" call Decho("g:netrw_alto =".(exists("g:netrw_alto")? g:netrw_alto : 'n/a'),'~'.expand("<slnum>"))
+" call Decho("g:netrw_preview=".(exists("g:netrw_preview")? g:netrw_preview : 'n/a'),'~'.expand("<slnum>"))
let ykeep= @@
- NetrwKeepj call s:NetrwOptionSave("s:")
- NetrwKeepj call s:NetrwSafeOptions()
+ NetrwKeepj call s:NetrwOptionsSave("s:")
+ if a:path !~ '^\*\{1,2}/' && a:path !~ '^\a\{3,}://'
+ NetrwKeepj call s:NetrwOptionsSafe(1)
+ else
+ NetrwKeepj call s:NetrwOptionsSafe(0)
+ endif
if has("quickfix")
+" call Decho("has quickfix",'~'.expand("<slnum>"))
if !isdirectory(s:NetrwFile(a:path))
- if g:netrw_preview && !g:netrw_alto
+" call Decho("good; not previewing a directory",'~'.expand("<slnum>"))
+ if g:netrw_preview
+ " vertical split
let pvhkeep = &pvh
let winsz = (g:netrw_winsize > 0)? (g:netrw_winsize*winwidth(0))/100 : -g:netrw_winsize
let &pvh = winwidth(0) - winsz
- endif
+" call Decho("g:netrw_preview: winsz=".winsz." &pvh=".&pvh." (temporarily) g:netrw_winsize=".g:netrw_winsize,'~'.expand("<slnum>"))
+ else
+ " horizontal split
+ let pvhkeep = &pvh
+ let winsz = (g:netrw_winsize > 0)? (g:netrw_winsize*winheight(0))/100 : -g:netrw_winsize
+ let &pvh = winheight(0) - winsz
+" call Decho("!g:netrw_preview: winsz=".winsz." &pvh=".&pvh." (temporarily) g:netrw_winsize=".g:netrw_winsize,'~'.expand("<slnum>"))
+ endif
+ " g:netrw_preview g:netrw_alto
+ " 1 : vert 1: top -- preview window is vertically split off and on the left
+ " 1 : vert 0: bot -- preview window is vertically split off and on the right
+ " 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
+ " 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
+ set ei=BufEnter
exe (g:netrw_alto? "top " : "bot ").(g:netrw_preview? "vert " : "")."pedit ".fnameescape(a:path)
+ let &ei= eikeep
+" call Decho("winnr($)=".winnr("$"),'~'.expand("<slnum>"))
if exists("pvhkeep")
let &pvh= pvhkeep
endif
@@ -8443,7 +8773,7 @@ fun! s:NetrwPreview(path) range
elseif !exists("g:netrw_quiet")
NetrwKeepj call netrw#ErrorMsg(s:WARNING,"sorry, to preview your vim needs the quickfix feature compiled in",39)
endif
- NetrwKeepj call s:NetrwOptionRestore("s:")
+ NetrwKeepj call s:NetrwOptionsRestore("s:")
let @@= ykeep
" call Dret("NetrwPreview")
endfun
@@ -8451,12 +8781,22 @@ endfun
" ---------------------------------------------------------------------
" s:NetrwRefresh: {{{2
fun! s:NetrwRefresh(islocal,dirname)
-" call Dfunc("s:NetrwRefresh(islocal<".a:islocal.">,dirname=".a:dirname.") hide=".g:netrw_hide." sortdir=".g:netrw_sort_direction)
+" call Dfunc("s:NetrwRefresh(islocal<".a:islocal.">,dirname=".a:dirname.") g:netrw_hide=".g:netrw_hide." g:netrw_sort_direction=".g:netrw_sort_direction)
" at the current time (Mar 19, 2007) all calls to NetrwRefresh() call NetrwBrowseChgDir() first.
setl ma noro
" call Decho("setl ma noro",'~'.expand("<slnum>"))
" call Decho("clear buffer<".expand("%")."> with :%d",'~'.expand("<slnum>"))
let ykeep = @@
+ if exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST
+ if !exists("w:netrw_treetop")
+ if exists("b:netrw_curdir")
+ let w:netrw_treetop= b:netrw_curdir
+ else
+ let w:netrw_treetop= getcwd()
+ endif
+ endif
+ NetrwKeepj call s:NetrwRefreshTreeDict(w:netrw_treetop)
+ endif
" save the cursor position before refresh.
let screenposn = winsaveview()
@@ -8476,13 +8816,15 @@ fun! s:NetrwRefresh(islocal,dirname)
NetrwKeepj call winrestview(screenposn)
" restore file marks
- if exists("s:netrwmarkfilemtch_{bufnr('%')}") && s:netrwmarkfilemtch_{bufnr("%")} != ""
-" call Decho("exe 2match netrwMarkFile /".s:netrwmarkfilemtch_{bufnr("%")}."/",'~'.expand("<slnum>"))
- exe "2match netrwMarkFile /".s:netrwmarkfilemtch_{bufnr("%")}."/"
- else
-" call Decho("2match none (bufnr(%)=".bufnr("%")."<".bufname("%").">)",'~'.expand("<slnum>"))
- 2match none
- endif
+ if has("syntax") && exists("g:syntax_on") && g:syntax_on
+ if exists("s:netrwmarkfilemtch_{bufnr('%')}") && s:netrwmarkfilemtch_{bufnr("%")} != ""
+" " call Decho("exe 2match netrwMarkFile /".s:netrwmarkfilemtch_{bufnr("%")}."/",'~'.expand("<slnum>"))
+ exe "2match netrwMarkFile /".s:netrwmarkfilemtch_{bufnr("%")}."/"
+ else
+" " call Decho("2match none (bufnr(%)=".bufnr("%")."<".bufname("%").">)",'~'.expand("<slnum>"))
+ 2match none
+ endif
+ endif
" restore
let @@= ykeep
@@ -8657,7 +8999,7 @@ fun! s:NetrwSetTgt(islocal,bookhist,choice)
endfun
" =====================================================================
-" s:NetrwSortStyle: change sorting style (name - time - size) and refresh display {{{2
+" s:NetrwSortStyle: change sorting style (name - time - size - exten) and refresh display {{{2
fun! s:NetrwSortStyle(islocal)
" call Dfunc("s:NetrwSortStyle(islocal=".a:islocal.") netrw_sort_by<".g:netrw_sort_by.">")
NetrwKeepj call s:NetrwSaveWordPosn()
@@ -8821,7 +9163,7 @@ fun! s:NetrwTgtMenu()
" call Decho("installing history as easy targets (histmax=".g:netrw_dirhistmax.")",'~'.expand("<slnum>"))
let histcnt = 1
while histcnt <= g:netrw_dirhistmax
- let priority = g:netrw_dirhist_cnt + histcnt
+ let priority = g:netrw_dirhistcnt + histcnt
if exists("g:netrw_dirhist_{histcnt}")
let histentry = g:netrw_dirhist_{histcnt}
if has_key(tgtdict,histentry)
@@ -8958,6 +9300,36 @@ fun! s:NetrwTreeDisplay(dir,depth)
let depth= s:treedepthstring.a:depth
" call Decho("display subtrees with depth<".depth."> and current leaves",'~'.expand("<slnum>"))
+ " implement g:netrw_hide for tree listings (uses g:netrw_list_hide)
+ if g:netrw_hide == 1
+ " hide given patterns
+ let listhide= split(g:netrw_list_hide,',')
+" call Decho("listhide=".string(listhide))
+ for pat in listhide
+ call filter(w:netrw_treedict[dir],'v:val !~ "'.pat.'"')
+ endfor
+
+ elseif g:netrw_hide == 2
+ " show given patterns (only)
+ let listhide= split(g:netrw_list_hide,',')
+" call Decho("listhide=".string(listhide))
+ let entries=[]
+ for entry in w:netrw_treedict[dir]
+ for pat in listhide
+ if entry =~ pat
+ call add(entries,entry)
+ break
+ endif
+ endfor
+ endfor
+ let w:netrw_treedict[dir]= entries
+ endif
+ if depth != ""
+ " always remove "." and ".." entries when there's depth
+ call filter(w:netrw_treedict[dir],'v:val !~ "\\.\\.$"')
+ call filter(w:netrw_treedict[dir],'v:val !~ "\\.$"')
+ endif
+
" call Decho("for every entry in w:netrw_treedict[".dir."]=".string(w:netrw_treedict[dir]),'~'.expand("<slnum>"))
for entry in w:netrw_treedict[dir]
if dir =~ '/$'
@@ -8980,6 +9352,7 @@ fun! s:NetrwTreeDisplay(dir,depth)
sil! NetrwKeepj call setline(line("$")+1,depth.entry)
endif
endfor
+" call Decho("displaying: ".string(getline(w:netrw_bannercnt,'$')))
" call Dret("NetrwTreeDisplay")
endfun
@@ -8988,6 +9361,11 @@ endfun
" s:NetrwRefreshTreeDict: updates the contents information for a tree (w:netrw_treedict) {{{2
fun! s:NetrwRefreshTreeDict(dir)
" call Dfunc("s:NetrwRefreshTreeDict(dir<".a:dir.">)")
+ if !exists("w:netrw_treedict")
+" call Dret("s:NetrwRefreshTreeDict : w:netrw_treedict doesn't exist")
+ return
+ endif
+
for entry in w:netrw_treedict[a:dir]
let direntry= substitute(a:dir.'/'.entry,'[@/]$','','e')
" call Decho("a:dir<".a:dir."> entry<".entry."> direntry<".direntry.">",'~'.expand("<slnum>"))
@@ -9016,7 +9394,7 @@ fun! s:NetrwRefreshTreeDict(dir)
" call Decho("updating w:netrw_treedict[".direntry.']='.string(w:netrw_treedict[direntry]),'~'.expand("<slnum>"))
else
-" call Decho('not updating w:netrw_treedict['.direntry.'] with entry<'.entry.'> (no subtree)',,'~'.expand("<slnum>"))
+" call Decho('not updating w:netrw_treedict['.string(direntry).'] with entry<'.string(entry).'> (no subtree)','~'.expand("<slnum>"))
endif
endfor
" call Dret("s:NetrwRefreshTreeDict")
@@ -9083,12 +9461,21 @@ fun! s:NetrwTreeListing(dirname)
endfun
" ---------------------------------------------------------------------
-" s:NetrwTreePath: returns path to current file in tree listing {{{2
+" s:NetrwTreePath: returns path to current file/directory in tree listing {{{2
" Normally, treetop is w:netrw_treetop, but a
" user of the function ( netrw#SetTreetop() )
" wipes that out prior to calling this function
fun! s:NetrwTreePath(treetop)
-" call Dfunc("s:NetrwTreePath() line#".line(".")."<".getline(".").">")
+" call Dfunc("s:NetrwTreePath(treetop<".a:treetop.">) line#".line(".")."<".getline(".").">")
+ if line(".") < w:netrw_bannercnt + 2
+ let treedir= a:treetop
+ if treedir !~ '/$'
+ let treedir= treedir.'/'
+ endif
+" call Dret("s:NetrwTreePath ".treedir." : line#".line(".")." ≤ ".(w:netrw_bannercnt+2))
+ return treedir
+ endif
+
let svpos = winsaveview()
" call Decho("saving posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))
let depth = substitute(getline('.'),'^\(\%('.s:treedepthstring.'\)*\)[^'.s:treedepthstring.'].\{-}$','\1','e')
@@ -9119,12 +9506,15 @@ fun! s:NetrwTreePath(treetop)
let depth = substitute(depth,'^'.s:treedepthstring,'','')
" call Decho("constructing treedir<".treedir.">: dirname<".dirname."> while depth<".depth.">",'~'.expand("<slnum>"))
endwhile
+" call Decho("treedir#1<".treedir.">",'~'.expand("<slnum>"))
if a:treetop =~ '/$'
let treedir= a:treetop.treedir
else
let treedir= a:treetop.'/'.treedir
endif
+" call Decho("treedir#2<".treedir.">",'~'.expand("<slnum>"))
let treedir= substitute(treedir,'//$','/','')
+" call Decho("treedir#3<".treedir.">",'~'.expand("<slnum>"))
" call Decho("restoring posn to svpos<".string(svpos).">",'~'.expand("<slnum>"))"
call winrestview(svpos)
" call Dret("s:NetrwTreePath <".treedir.">")
@@ -9195,7 +9585,7 @@ fun! s:NetrwWideListing()
exe 'nno <buffer> <silent> b :call search(''^.\\|\s\s\zs\S'',''bW'')'."\<cr>"
" call Decho("NetrwWideListing) setl noma nomod ro",'~'.expand("<slnum>"))
exe "setl ".g:netrw_bufsettings
-" call Decho("(NetrwWideListing) ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.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("NetrwWideListing")
return
else
@@ -9214,18 +9604,20 @@ endfun
fun! s:PerformListing(islocal)
" call Dfunc("s:PerformListing(islocal=".a:islocal.")")
" call Decho("tab#".tabpagenr()." win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> line#".line(".")." col#".col(".")." winline#".winline()." wincol#".wincol()." line($)=".line("$"),'~'.expand("<slnum>"))
-" call Decho("settings: ".((&l:ma == 0)? "no" : "")."ma ".((&l:mod == 0)? "no" : "")."mod ".((&l:bl == 0)? "no" : "")."bl ".((&l:ro == 0)? "no" : "")."ro fo=".&l:fo. " (enter)",'~'.expand("<slnum>"))
+" call Decho("settings: ".((&l:ma == 0)? "no" : "")."ma ".((&l:mod == 0)? "no" : "")."mod ".((&l:bl == 0)? "no" : "")."bl ".((&l:ro == 0)? "no" : "")."ro fo=".&l:fo. " (enter)"." ei<".&ei.">",'~'.expand("<slnum>"))
+ sil! NetrwKeepj %d _
+" call DechoBuf(bufnr("%"))
" set up syntax highlighting {{{3
" call Decho("--set up syntax highlighting (ie. setl ft=netrw)",'~'.expand("<slnum>"))
sil! setl ft=netrw
- NetrwKeepj call s:NetrwSafeOptions()
+ NetrwKeepj call s:NetrwOptionsSafe(a:islocal)
setl noro ma
" call Decho("setl noro ma bh=".&bh,'~'.expand("<slnum>"))
" if exists("g:netrw_silent") && g:netrw_silent == 0 && &ch >= 1 " Decho
-" call Decho("(netrw) Processing your browsing request...",'~'.expand("<slnum>"))
+" call Decho("Processing your browsing request...",'~'.expand("<slnum>"))
" endif " Decho
" call Decho('w:netrw_liststyle='.(exists("w:netrw_liststyle")? w:netrw_liststyle : 'n/a'),'~'.expand("<slnum>"))
@@ -9269,6 +9661,7 @@ fun! s:PerformListing(islocal)
" call Decho("w:netrw_bannercnt=".w:netrw_bannercnt." win#".winnr(),'~'.expand("<slnum>"))
" call Decho("tab#".tabpagenr()." win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> line#".line(".")." col#".col(".")." winline#".winline()." wincol#".wincol()." line($)=".line("$"),'~'.expand("<slnum>"))
+ " construct sortby string: [name|time|size|exten] [reversed]
let sortby= g:netrw_sort_by
if g:netrw_sort_direction =~# "^r"
let sortby= sortby." reversed"
@@ -9279,13 +9672,13 @@ fun! s:PerformListing(islocal)
" call Decho("--handle specified sorting: g:netrw_sort_by<".g:netrw_sort_by.">",'~'.expand("<slnum>"))
if g:netrw_sort_by =~# "^n"
" call Decho("directories will be sorted by name",'~'.expand("<slnum>"))
- " sorted by name
+ " sorted by name (also includes the sorting sequence in the banner)
NetrwKeepj put ='\" Sorted by '.sortby
NetrwKeepj put ='\" Sort sequence: '.g:netrw_sort_sequence
let w:netrw_bannercnt= w:netrw_bannercnt + 2
else
" call Decho("directories will be sorted by size or time",'~'.expand("<slnum>"))
- " sorted by size or date
+ " sorted by time, size, exten
NetrwKeepj put ='\" Sorted by '.sortby
let w:netrw_bannercnt= w:netrw_bannercnt + 1
endif
@@ -9294,7 +9687,7 @@ fun! s:PerformListing(islocal)
" 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>"))
endif
- " show copy/move target, if any
+ " show copy/move target, if any {{{3
if g:netrw_banner
if exists("s:netrwmftgt") && exists("s:netrwmftgt_islocal")
" call Decho("--show copy/move target<".s:netrwmftgt.">",'~'.expand("<slnum>"))
@@ -9313,7 +9706,7 @@ fun! s:PerformListing(islocal)
" Hiding... -or- Showing... {{{3
if g:netrw_banner
-" call Decho("--handle hiding/showing (g:netrw_hide=".g:netrw_list_hide." g:netrw_list_hide<".g:netrw_list_hide.">)",'~'.expand("<slnum>"))
+" call Decho("--handle hiding/showing (g:netrw_hide=".g:netrw_hide." g:netrw_list_hide<".g:netrw_list_hide.">)",'~'.expand("<slnum>"))
if g:netrw_list_hide != "" && g:netrw_hide
if g:netrw_hide == 1
NetrwKeepj put ='\" Hiding: '.g:netrw_list_hide
@@ -9376,12 +9769,13 @@ fun! s:PerformListing(islocal)
if g:netrw_sort_by =~# "^n"
" sort by name
+" call Decho("sort by name",'~'.expand("<slnum>"))
NetrwKeepj call s:NetrwSetSort()
if !g:netrw_banner || w:netrw_bannercnt < line("$")
" call Decho("g:netrw_sort_direction=".g:netrw_sort_direction." (bannercnt=".w:netrw_bannercnt.")",'~'.expand("<slnum>"))
if g:netrw_sort_direction =~# 'n'
- " normal direction sorting
+ " name: sort by name of file
exe 'sil NetrwKeepj '.w:netrw_bannercnt.',$sort'.' '.g:netrw_sort_options
else
" reverse direction sorting
@@ -9394,7 +9788,9 @@ fun! s:PerformListing(islocal)
NetrwKeepj call histdel("/",-1)
elseif g:netrw_sort_by =~# "^ext"
- " sort by extension
+ " exten: sort by extension
+ " The histdel(...,-1) calls remove the last search from the search history
+" call Decho("sort by extension",'~'.expand("<slnum>"))
exe 'sil NetrwKeepj '.w:netrw_bannercnt.',$g+/+s/^/001'.g:netrw_sepchr.'/'
NetrwKeepj call histdel("/",-1)
exe 'sil NetrwKeepj '.w:netrw_bannercnt.',$v+[./]+s/^/002'.g:netrw_sepchr.'/'
@@ -9450,7 +9846,7 @@ fun! s:PerformListing(islocal)
" resolve symbolic links if local and (thin or tree)
if a:islocal && (w:netrw_liststyle == s:THINLIST || (exists("w:netrw_liststyle") && w:netrw_liststyle == s:TREELIST))
" call Decho("--resolve symbolic links if local and thin|tree",'~'.expand("<slnum>"))
- g/@$/call s:ShowLink()
+ sil! g/@$/call s:ShowLink()
endif
if exists("w:netrw_bannercnt") && (line("$") >= w:netrw_bannercnt || !g:netrw_banner)
@@ -9475,7 +9871,7 @@ fun! s:PerformListing(islocal)
" 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. " (internal#4)",'~'.expand("<slnum>"))
NetrwKeepj call s:SetBufWinVars()
" 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. " (internal#5)",'~'.expand("<slnum>"))
- NetrwKeepj call s:NetrwOptionRestore("w:")
+ NetrwKeepj call s:NetrwOptionsRestore("w:")
" 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. " (internal#6)",'~'.expand("<slnum>"))
" set display to netrw display settings
@@ -9486,6 +9882,7 @@ fun! s:PerformListing(islocal)
" call Decho("exe setl ts=".(g:netrw_maxfilenamelen+1),'~'.expand("<slnum>"))
exe "setl ts=".(g:netrw_maxfilenamelen+1)
endif
+" call DechoBuf(bufnr("%"))
if exists("s:treecurpos")
" call Decho("s:treecurpos exists; restore posn",'~'.expand("<slnum>"))
@@ -9543,9 +9940,9 @@ fun! s:SetupNetrwStatusLine(statline)
" call Dret("SetupNetrwStatusLine : stl=".&stl)
endfun
-" ---------------------------------------------------------------------
-" Remote Directory Browsing Support: {{{1
-" ===========================================
+" =========================================
+" Remote Directory Browsing Support: {{{1
+" =========================================
" ---------------------------------------------------------------------
" s:NetrwRemoteFtpCmd: unfortunately, not all ftp servers honor options for ls {{{2
@@ -9714,7 +10111,7 @@ fun! s:NetrwRemoteListing()
if !exists("g:netrw_quiet")
call netrw#ErrorMsg(s:ERROR,"this system doesn't support remote directory listing via ftp",18)
endif
- call s:NetrwOptionRestore("w:")
+ call s:NetrwOptionsRestore("w:")
" call Dret("s:NetrwRemoteListing -1")
return -1
endif
@@ -9729,7 +10126,7 @@ fun! s:NetrwRemoteListing()
endif
endif
- NetrwKeepj call s:NetrwOptionRestore("w:")
+ NetrwKeepj call s:NetrwOptionsRestore("w:")
" call Dret("s:NetrwRemoteListing -1")
return -1
endif " (remote handling sanity check)
@@ -9762,7 +10159,7 @@ fun! s:NetrwRemoteListing()
exe w:netrw_bannercnt.",$d _"
setl noma
endif
- NetrwKeepj call s:NetrwOptionRestore("w:")
+ NetrwKeepj call s:NetrwOptionsRestore("w:")
call netrw#ErrorMsg(s:WARNING,mesg,96)
" call Dret("s:NetrwRemoteListing : -1")
return -1
@@ -10005,7 +10402,7 @@ fun! s:NetrwRemoteRmFile(path,rmfile,all)
let ret= system(netrw_rm_cmd)
if v:shell_error != 0
if exists("b:netrw_curdir") && b:netrw_curdir != getcwd() && !g:netrw_keepdir
- call netrw#ErrorMsg(s:ERROR,"remove failed; perhaps due to vim's current directory<".getcwd()."> not matching netrw's (".b:netrw_curdir.") (see :help netrw-c)",102)
+ call netrw#ErrorMsg(s:ERROR,"remove failed; perhaps due to vim's current directory<".getcwd()."> not matching netrw's (".b:netrw_curdir.") (see :help netrw-cd)",102)
else
call netrw#ErrorMsg(s:WARNING,"cmd<".netrw_rm_cmd."> failed",60)
endif
@@ -10146,12 +10543,12 @@ fun! s:NetrwRemoteRename(usrhost,path) range
" call Dret("NetrwRemoteRename")
endfun
-" ---------------------------------------------------------------------
+" ==========================================
" Local Directory Browsing Support: {{{1
" ==========================================
" ---------------------------------------------------------------------
-" netrw#FileUrlRead: handles reading file://* files {{{2
+" netrw#FileUrlEdit: handles editing file://* files {{{2
" Should accept: file://localhost/etc/fstab
" file:///etc/fstab
" file:///c:/WINDOWS/clock.avi
@@ -10161,8 +10558,8 @@ endfun
" file://c:/foo.txt
" file:///c:/foo.txt
" and %XX (where X is [0-9a-fA-F] is converted into a character with the given hexadecimal value
-fun! netrw#FileUrlRead(fname)
-" call Dfunc("netrw#FileUrlRead(fname<".a:fname.">)")
+fun! netrw#FileUrlEdit(fname)
+" call Dfunc("netrw#FileUrlEdit(fname<".a:fname.">)")
let fname = a:fname
if fname =~ '^file://localhost/'
" call Decho('converting file://localhost/ -to- file:///','~'.expand("<slnum>"))
@@ -10186,35 +10583,36 @@ fun! netrw#FileUrlRead(fname)
let plainfname= substitute(plainfname,'^/\+\(\a:\)','\1','')
endif
endif
+
" call Decho("fname2396<".fname2396.">",'~'.expand("<slnum>"))
" call Decho("plainfname<".plainfname.">",'~'.expand("<slnum>"))
exe "sil doau BufReadPre ".fname2396e
- exe 'NetrwKeepj r '.plainfname
- exe 'sil! bdelete '.plainfname
- exe 'keepalt file! '.plainfname
- NetrwKeepj 1d
-" call Decho("setl nomod",'~'.expand("<slnum>"))
- setl nomod
+ exe 'NetrwKeepj keepalt edit '.plainfname
+ exe 'sil! NetrwKeepj keepalt bdelete '.fnameescape(a:fname)
+
" call Decho("ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("<slnum>"))
-" call Dret("netrw#FileUrlRead")
+" call Dret("netrw#FileUrlEdit")
exe "sil doau BufReadPost ".fname2396e
endfun
" ---------------------------------------------------------------------
" netrw#LocalBrowseCheck: {{{2
fun! netrw#LocalBrowseCheck(dirname)
- " This function is called by netrwPlugin.vim's s:LocalBrowse(), s:NetrwRexplore(), and by <cr> when atop listed file/directory
- " unfortunate interaction -- split window debugging can't be
- " used here, must use D-echoRemOn or D-echoTabOn -- the BufEnter
- " event triggers another call to LocalBrowseCheck() when attempts
- " to write to the DBG buffer are made.
+ " This function is called by netrwPlugin.vim's s:LocalBrowse(), 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
+ " D-echoRemOn or D-echoTabOn as the BufEnter event triggers
+ " another call to LocalBrowseCheck() when attempts to write
+ " to the DBG buffer are made.
+ "
" The &ft == "netrw" test was installed because the BufEnter event
" would hit when re-entering netrw windows, creating unexpected
" refreshes (and would do so in the middle of NetrwSaveOptions(), too)
-" call Dfunc("netrw#LocalBrowseCheck(dirname<".a:dirname.">")
+" call Dfunc("netrw#LocalBrowseCheck(dirname<".a:dirname.">)")
" call Decho("isdir<".a:dirname."> =".isdirectory(s:NetrwFile(a:dirname)).((exists("s:treeforceredraw")? " treeforceredraw" : "")).'~'.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,'~'.expand("<slnum>"))
-" call Dredir("ls!","ls!")
+" call Dredir("ls!","netrw#LocalBrowseCheck")
" call Decho("tab#".tabpagenr()." win#".winnr()." buf#".bufnr("%")."<".bufname("%")."> line#".line(".")." col#".col(".")." winline#".winline()." wincol#".wincol(),'~'.expand("<slnum>"))
" call Decho("current buffer#".bufnr("%")."<".bufname("%")."> ft=".&ft,'~'.expand("<slnum>"))
@@ -10241,7 +10639,7 @@ fun! netrw#LocalBrowseCheck(dirname)
return
endif
- " following code wipes out currently unused netrw buffers
+ " The following code wipes out currently unused netrw buffers
" IF g:netrw_fastbrowse is zero (ie. slow browsing selected)
" AND IF the listing style is not a tree listing
if exists("g:netrw_fastbrowse") && g:netrw_fastbrowse == 0 && g:netrw_liststyle != s:TREELIST
@@ -10293,19 +10691,21 @@ fun! s:LocalBrowseRefresh()
while itab <= tabpagenr("$")
let buftablist = buftablist + tabpagebuflist()
let itab = itab + 1
- tabn
+ sil! tabn
endwhile
" call Decho("buftablist".string(buftablist),'~'.expand("<slnum>"))
" call Decho("s:netrw_browselist<".(exists("s:netrw_browselist")? string(s:netrw_browselist) : "").">",'~'.expand("<slnum>"))
" GO through all buffers on netrw_browselist (ie. just local-netrw buffers):
" | refresh any netrw window
" | wipe out any non-displaying netrw buffer
- let curwin = winnr()
+ let curwinid = win_getid(winnr())
let ibl = 0
for ibuf in s:netrw_browselist
" call Decho("bufwinnr(".ibuf.") index(buftablist,".ibuf.")=".index(buftablist,ibuf),'~'.expand("<slnum>"))
if bufwinnr(ibuf) == -1 && index(buftablist,ibuf) == -1
" wipe out any non-displaying netrw buffer
+ " (ibuf not shown in a current window AND
+ " ibuf not in any tab)
" call Decho("wiping buf#".ibuf,"<".bufname(ibuf).">",'~'.expand("<slnum>"))
exe "sil! keepj bd ".fnameescape(ibuf)
call remove(s:netrw_browselist,ibl)
@@ -10329,8 +10729,8 @@ fun! s:LocalBrowseRefresh()
let ibl= ibl + 1
" call Decho("bottom of s:netrw_browselist for loop: ibl=".ibl,'~'.expand("<slnum>"))
endfor
-" call Decho("restore window: exe ".curwin."wincmd w",'~'.expand("<slnum>"))
- exe curwin."wincmd w"
+" call Decho("restore window: win_gotoid(".curwinid.")")
+ call win_gotoid(curwinid)
let @@= ykeep
" call Dret("s:LocalBrowseRefresh")
@@ -10355,10 +10755,10 @@ endfun
" If :Explore used: it sets s:netrw_events to 2, so no FocusGained events are ignored.
" =2: autocmds installed (doesn't ignore any FocusGained events)
fun! s:LocalFastBrowser()
-" call Dfunc("LocalFastBrowser() g:netrw_fastbrowse=".g:netrw_fastbrowse)
-" call Decho("s:netrw_events ".(exists("s:netrw_events")? "exists" : 'n/a'),'~'.expand("<slnum>"))
-" call Decho("autocmd: ShellCmdPost ".(exists("#ShellCmdPost")? "installed" : "not installed"),'~'.expand("<slnum>"))
-" call Decho("autocmd: FocusGained ".(exists("#FocusGained")? "installed" : "not installed"),'~'.expand("<slnum>"))
+" call Dfunc("s:LocalFastBrowser() g:netrw_fastbrowse=".g:netrw_fastbrowse)
+" call Decho("s:netrw_events ".(exists("s:netrw_events")? "exists" : 'n/a'),'~'.expand("<slnum>"))
+" call Decho("autocmd: ShellCmdPost ".(exists("#ShellCmdPost")? "already installed" : "not installed"),'~'.expand("<slnum>"))
+" call Decho("autocmd: FocusGained ".(exists("#FocusGained")? "already installed" : "not installed"),'~'.expand("<slnum>"))
" initialize browselist, a list of buffer numbers that the local browser has used
if !exists("s:netrw_browselist")
@@ -10403,7 +10803,7 @@ fun! s:LocalFastBrowser()
augroup! AuNetrwEvent
endif
-" call Dret("LocalFastBrowser : browselist<".string(s:netrw_browselist).">")
+" call Dret("s:LocalFastBrowser : browselist<".string(s:netrw_browselist).">")
endfun
" ---------------------------------------------------------------------
@@ -10449,6 +10849,7 @@ fun! s:LocalListing()
for filename in filelist
" call Decho(" ",'~'.expand("<slnum>"))
" call Decho("for filename in filelist: filename<".filename.">",'~'.expand("<slnum>"))
+" call DechoBuf(bufnr("%"),"COMBAK#1")
if getftype(filename) == "link"
" indicate a symbolic link
@@ -10509,8 +10910,9 @@ fun! s:LocalListing()
if g:netrw_sizestyle =~# "[hH]"
let sz= s:NetrwHumanReadable(sz)
endif
- let fsz = strpart(" ",1,15-strlen(sz)).sz
- let pfile= pfile."\t".fsz." ".strftime(g:netrw_timefmt,getftime(filename))
+ let fsz = strpart(" ",1,15-strlen(sz)).sz
+ let longfile= printf("%-".(g:netrw_maxfilenamelen+1)."s",pfile)
+ let pfile = longfile.fsz." ".strftime(g:netrw_timefmt,getftime(filename))
" call Decho("longlist support: sz=".sz." fsz=".fsz,'~'.expand("<slnum>"))
endif
@@ -10540,6 +10942,7 @@ fun! s:LocalListing()
" call Decho("exe NetrwKeepj put ='".pfile."'",'~'.expand("<slnum>"))
sil! NetrwKeepj put=pfile
endif
+" call DechoBuf(bufnr("%"),"COMBAK#2")
endfor
" cleanup any windows mess at end-of-line
@@ -10786,7 +11189,7 @@ fun! s:NetrwLocalRmFile(path,fname,all)
let rmfile= substitute(rmfile,'[\/]$','','e')
if all || ok =~# 'y\%[es]' || ok == ""
- if v:version < 704 || !has("patch1109")
+ if v:version < 704 || (v:version == 704 && !has("patch1107"))
" " call Decho("1st attempt: system(netrw#WinPath(".g:netrw_localrmdir.') '.s:ShellEscape(rmfile).')','~'.expand("<slnum>"))
call system(netrw#WinPath(g:netrw_localrmdir).' '.s:ShellEscape(rmfile))
" " call Decho("v:shell_error=".v:shell_error,'~'.expand("<slnum>"))
@@ -10822,21 +11225,10 @@ fun! s:NetrwLocalRmFile(path,fname,all)
return ok
endfun
-" ---------------------------------------------------------------------
+" =====================================================================
" Support Functions: {{{1
" ---------------------------------------------------------------------
-" s:WinNames: COMBAK {{{2
-fun! s:WinNames(id)
- let curwin= winnr()
- 1wincmd w
-" call Decho("--- Windows By Name --- #".a:id)
-" windo call Decho("win#".winnr()."<".expand("%").">")
-" call Decho("--- --- --- --- --- ---")
- exe curwin."wincmd w"
-endfun
-
-" ---------------------------------------------------------------------
" netrw#Access: intended to provide access to variable values for netrw's test suite {{{2
" 0: marked file list of current buffer
" 1: marked file target
@@ -10849,18 +11241,13 @@ fun! netrw#Access(ilist)
endif
elseif a:ilist == 1
return s:netrwmftgt
+ endif
endfun
" ---------------------------------------------------------------------
" netrw#Call: allows user-specified mappings to call internal netrw functions {{{2
fun! netrw#Call(funcname,...)
-" call Dfunc("netrw#Call(funcname<".a:funcname.">,".string(a:000).")")
- if a:0 > 0
- exe "call s:".a:funcname."(".string(a:000).")"
- else
- exe "call s:".a:funcname."()"
- endif
-" call Dret("netrw#Call")
+ return call("s:".a:funcname,a:000)
endfun
" ---------------------------------------------------------------------
@@ -10922,7 +11309,7 @@ endfun
" or it may return a List of strings.
"
" Each keymap-sequence will be set up with a nnoremap
-" to invoke netrw#UserMaps(islocal).
+" to invoke netrw#UserMaps(a:islocal).
" Related functions:
" netrw#Expose(varname) -- see s:varname variables
" netrw#Modify(varname,newvalue) -- modify value of s:varname variable
@@ -10970,6 +11357,35 @@ fun! netrw#WinPath(path)
endfun
" ---------------------------------------------------------------------
+" s:NetrwBadd: adds marked files to buffer list or vice versa {{{2
+" cb : bl2mf=0 add marked files to buffer list
+" cB : bl2mf=1 use bufferlist to mark files
+" (mnemonic: cb = copy (marked files) to buffer list)
+fun! s:NetrwBadd(islocal,bl2mf)
+" " call Dfunc("s:NetrwBadd(islocal=".a:islocal." mf2bl=".mf2bl.")")
+ if a:bl2mf
+ " cB: add buffer list to marked files
+ redir => bufl
+ ls
+ redir END
+ let bufl = map(split(bufl,"\n"),'substitute(v:val,''^.\{-}"\(.*\)".\{-}$'',''\1'','''')')
+ for fname in bufl
+ call s:NetrwMarkFile(a:islocal,fname)
+ endfor
+ else
+ " cb: add marked files to buffer list
+ for fname in s:netrwmarkfilelist_{bufnr("%")}
+" " call Decho("badd ".fname,'~'.expand("<slnum>"))
+ exe "badd ".fnameescape(fname)
+ endfor
+ let curbufnr = bufnr("%")
+ let curdir = s:NetrwGetCurdir(a:islocal)
+ call s:NetrwUnmarkList(curbufnr,curdir) " remove markings from local buffer
+ endif
+" call Dret("s:NetrwBadd")
+endfun
+
+" ---------------------------------------------------------------------
" s:ComposePath: Appends a new part to a path taking different systems into consideration {{{2
fun! s:ComposePath(base,subdir)
" call Dfunc("s:ComposePath(base<".a:base."> subdir<".a:subdir.">)")
@@ -10983,11 +11399,12 @@ fun! s:ComposePath(base,subdir)
let ret = a:base.a:subdir
endif
- elseif a:subdir =~ '^\a:[/\\][^/\\]' && (has("win32") || has("win95") || has("win64") || has("win16"))
+ " COMBAK: test on windows with changing to root directory: :e C:/
+ elseif a:subdir =~ '^\a:[/\\]\([^/\\]\|$\)' && (has("win32") || has("win95") || has("win64") || has("win16"))
" call Decho("windows",'~'.expand("<slnum>"))
let ret= a:subdir
- elseif a:base =~ '^\a:[/\\][^/\\]' && (has("win32") || has("win95") || has("win64") || has("win16"))
+ elseif a:base =~ '^\a:[/\\]\([^/\\]\|$\)' && (has("win32") || has("win95") || has("win64") || has("win16"))
" call Decho("windows",'~'.expand("<slnum>"))
if a:base =~ '[/\\]$'
let ret= a:base.a:subdir
@@ -11329,7 +11746,7 @@ endfun
" ---------------------------------------------------------------------
" s:NetrwEnew: opens a new buffer, passes netrw buffer variables through {{{2
fun! s:NetrwEnew(...)
-" call Dfunc("s:NetrwEnew() a:0=".a:0." bufnr($)=".bufnr("$"))
+" call Dfunc("s:NetrwEnew() a:0=".a:0." bufnr($)=".bufnr("$")." expand(%)<".expand("%").">")
" call Decho("curdir<".((a:0>0)? a:1 : "")."> buf#".bufnr("%")."<".bufname("%").">",'~'.expand("<slnum>"))
" grab a function-local-variable copy of buffer variables
@@ -11351,7 +11768,7 @@ fun! s:NetrwEnew(...)
if exists("b:netrw_option") |let netrw_option = b:netrw_option |endif
if exists("b:netrw_prvdir") |let netrw_prvdir = b:netrw_prvdir |endif
- NetrwKeepj call s:NetrwOptionRestore("w:")
+ NetrwKeepj call s:NetrwOptionsRestore("w:")
" call Decho("generate a buffer with NetrwKeepj keepalt enew!",'~'.expand("<slnum>"))
" when tree listing uses file TreeListing... a new buffer is made.
" Want the old buffer to be unlisted.
@@ -11361,7 +11778,7 @@ fun! s:NetrwEnew(...)
noswapfile NetrwKeepj keepalt enew!
let &l:diff= netrw_keepdiff
" call Decho("bufnr($)=".bufnr("$")."<".bufname(bufnr("$"))."> winnr($)=".winnr("$"),'~'.expand("<slnum>"))
- NetrwKeepj call s:NetrwOptionSave("w:")
+ NetrwKeepj call s:NetrwOptionsSave("w:")
" copy function-local-variables to buffer variable equivalents
" call Decho("copy function-local variables back to buffer netrw variables",'~'.expand("<slnum>"))
@@ -11392,7 +11809,7 @@ fun! s:NetrwEnew(...)
nno <silent> <buffer> [ :sil call <SID>TreeListMove('[')<cr>
nno <silent> <buffer> ] :sil call <SID>TreeListMove(']')<cr>
else
- exe "sil! keepalt file ".fnameescape(b:netrw_curdir)
+ call s:NetrwBufRename(b:netrw_curdir)
endif
endif
endif
@@ -11403,17 +11820,19 @@ endfun
" ---------------------------------------------------------------------
" s:NetrwExe: executes a string using "!" {{{2
fun! s:NetrwExe(cmd)
-" call Dfunc("s:NetrwExe(a:cmd)")
+" call Dfunc("s:NetrwExe(a:cmd<".a:cmd.">)")
if has("win32") && &shell !~? 'cmd' && !g:netrw_cygwin
+" call Decho("using win32:",expand("<slnum>"))
let savedShell=[&shell,&shellcmdflag,&shellxquote,&shellxescape,&shellquote,&shellpipe,&shellredir,&shellslash]
set shell& shellcmdflag& shellxquote& shellxescape&
set shellquote& shellpipe& shellredir& shellslash&
exe a:cmd
let [&shell,&shellcmdflag,&shellxquote,&shellxescape,&shellquote,&shellpipe,&shellredir,&shellslash] = savedShell
else
+" call Decho("exe ".a:cmd,'~'.expand("<slnum>"))
exe a:cmd
endif
-" call Dret("s:NetrwExe")
+" call Dret("s:NetrwExe : v:shell_error=".v:shell_error)
endfun
" ---------------------------------------------------------------------
@@ -11446,9 +11865,12 @@ endfun
" ---------------------------------------------------------------------
" s:NetrwLcd: handles changing the (local) directory {{{2
+" Returns: 0=success
+" -1=failed
fun! s:NetrwLcd(newdir)
" call Dfunc("s:NetrwLcd(newdir<".a:newdir.">)")
+ let err472= 0
try
exe 'NetrwKeepj sil lcd '.fnameescape(a:newdir)
catch /^Vim\%((\a\+)\)\=:E344/
@@ -11464,21 +11886,26 @@ fun! s:NetrwLcd(newdir)
endif
endif
catch /^Vim\%((\a\+)\)\=:E472/
+ let err472= 1
+ endtry
+
+ if err472
call netrw#ErrorMsg(s:ERROR,"unable to change directory to <".a:newdir."> (permissions?)",61)
if exists("w:netrw_prvdir")
let a:newdir= w:netrw_prvdir
else
- call s:NetrwOptionRestore("w:")
+ call s:NetrwOptionsRestore("w:")
" call Decho("setl noma nomod nowrap",'~'.expand("<slnum>"))
exe "setl ".g:netrw_bufsettings
" call Decho(" ro=".&l:ro." ma=".&l:ma." mod=".&l:mod." wrap=".&l:wrap." (filename<".expand("%")."> win#".winnr()." ft<".&ft.">)",'~'.expand("<slnum>"))
let a:newdir= dirname
-" call Dret("s:NetrwBrowse : reusing buffer#".(exists("bufnum")? bufnum : 'N/A')."<".dirname."> getcwd<".getcwd().">")
- return
endif
- endtry
+" call Dret("s:NetrwBrowse -1 : reusing buffer#".(exists("bufnum")? bufnum : 'N/A')."<".dirname."> getcwd<".getcwd().">")
+ return -1
+ endif
-" call Dret("s:NetrwLcd")
+" call Dret("s:NetrwLcd 0")
+ return 0
endfun
" ------------------------------------------------------------------------
@@ -11646,7 +12073,7 @@ endfun
" s:SetRexDir() sets up <2-leftmouse> maps (if g:netrw_retmap
" is true) and a command, :Rexplore, which call this function.
"
-" s:netrw_nbcd is set up by s:NetrwBrowseChgDir()
+" s:netrw_posn is set up by s:NetrwBrowseChgDir()
"
" s:rexposn_BUFNR used to save/restore cursor position
fun! s:NetrwRexplore(islocal,dirname)
@@ -11702,8 +12129,10 @@ fun! s:NetrwRexplore(islocal,dirname)
" call Decho("s:rexposn_".bufnr('%')."<".bufname("%")."> doesn't exist",'~'.expand("<slnum>"))
endif
- if exists("s:explore_match")
- exe "2match netrwMarkFile /".s:explore_match."/"
+ if has("syntax") && exists("g:syntax_on") && g:syntax_on
+ if exists("s:explore_match")
+ exe "2match netrwMarkFile /".s:explore_match."/"
+ endif
endif
" 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>"))
@@ -11731,8 +12160,12 @@ endfun
fun! s:SavePosn(posndict)
" call Dfunc("s:SavePosn(posndict) curbuf#".bufnr("%")."<".bufname("%").">")
- let a:posndict[bufnr("%")]= winsaveview()
-" call Decho("saving posn: posndict[".bufnr("%")."]=".string(winsaveview()),'~'.expand("<slnum>"))
+ if !exists("a:posndict[bufnr('%')]")
+ let a:posndict[bufnr("%")]= []
+ endif
+" call Decho("before push: a:posndict[buf#".bufnr("%")."]=".string(a:posndict[bufnr('%')]))
+ call add(a:posndict[bufnr("%")],winsaveview())
+" call Decho("after push: a:posndict[buf#".bufnr("%")."]=".string(a:posndict[bufnr('%')]))
" call Dret("s:SavePosn posndict")
return a:posndict
@@ -11742,9 +12175,18 @@ endfun
" s:RestorePosn: restores position associated with current buffer using dictionary {{{2
fun! s:RestorePosn(posndict)
" call Dfunc("s:RestorePosn(posndict) curbuf#".bufnr("%")."<".bufname("%").">")
- if has_key(a:posndict,bufnr("%"))
- call winrestview(a:posndict[bufnr("%")])
-" call Decho("restoring posn: posndict[".bufnr("%")."]=".string(a:posndict[bufnr("%")]),'~'.expand("<slnum>"))
+ if exists("a:posndict")
+ if has_key(a:posndict,bufnr("%"))
+" call Decho("before pop: a:posndict[buf#".bufnr("%")."]=".string(a:posndict[bufnr('%')]))
+ let posnlen= len(a:posndict[bufnr("%")])
+ if posnlen > 0
+ let posnlen= posnlen - 1
+" call Decho("restoring posn posndict[".bufnr("%")."][".posnlen."]=".string(a:posndict[bufnr("%")][posnlen]),'~'.expand("<slnum>"))
+ call winrestview(a:posndict[bufnr("%")][posnlen])
+ call remove(a:posndict[bufnr("%")],posnlen)
+" call Decho("after pop: a:posndict[buf#".bufnr("%")."]=".string(a:posndict[bufnr('%')]))
+ endif
+ endif
endif
" call Dret("s:RestorePosn")
endfun
@@ -12032,11 +12474,13 @@ fun! s:UserMaps(islocal,funcname)
" call Dret("s:UserMaps")
endfun
-" ---------------------------------------------------------------------
+" ==========================
" Settings Restoration: {{{1
+" ==========================
let &cpo= s:keepcpo
unlet s:keepcpo
-" ------------------------------------------------------------------------
+" ===============
" Modelines: {{{1
+" ===============
" vim:ts=8 fdm=marker
diff --git a/runtime/autoload/netrwSettings.vim b/runtime/autoload/netrwSettings.vim
index 4639909ee8..327db6a540 100644
--- a/runtime/autoload/netrwSettings.vim
+++ b/runtime/autoload/netrwSettings.vim
@@ -1,7 +1,7 @@
" netrwSettings.vim: makes netrw settings simpler
-" Date: Dec 30, 2014
+" Date: Nov 09, 2016
" Maintainer: Charles E Campbell <drchipNOSPAM at campbellfamily dot biz>
-" Version: 15
+" Version: 16
" 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 = "v15"
+let g:loaded_netrwSettings = "v16"
if v:version < 700
echohl WarningMsg
echo "***warning*** this version of netrwSettings needs vim 7.0"
@@ -154,9 +154,13 @@ fun! netrwSettings#NetrwSettings()
put = 'let g:netrw_list_hide = '.g:netrw_list_hide
put = 'let g:netrw_liststyle = '.g:netrw_liststyle
put = 'let g:netrw_localcopycmd = '.g:netrw_localcopycmd
+ put = 'let g:netrw_localcopycmdopt = '.g:netrw_localcopycmdopt
put = 'let g:netrw_localmkdir = '.g:netrw_localmkdir
+ put = 'let g:netrw_localmkdiropt = '.g:netrw_localmkdiropt
put = 'let g:netrw_localmovecmd = '.g:netrw_localmovecmd
+ put = 'let g:netrw_localmovecmdopt = '.g:netrw_localmovecmdopt
put = 'let g:netrw_localrmdir = '.g:netrw_localrmdir
+ put = 'let g:netrw_localrmdiropt = '.g:netrw_localrmdiropt
put = 'let g:netrw_maxfilenamelen = '.g:netrw_maxfilenamelen
put = 'let g:netrw_menu = '.g:netrw_menu
put = 'let g:netrw_mousemaps = '.g:netrw_mousemaps
diff --git a/runtime/autoload/paste.vim b/runtime/autoload/paste.vim
index dd7b3ae54a..2d787e7a1d 100644
--- a/runtime/autoload/paste.vim
+++ b/runtime/autoload/paste.vim
@@ -1,35 +1,25 @@
" Vim support file to help with paste mappings and menus
" Maintainer: Bram Moolenaar <Bram@vim.org>
-" Last Change: 2017 Aug 30
+" Last Change: 2019 Jan 27
" Define the string to use for items that are present both in Edit, Popup and
" Toolbar menu. Also used in mswin.vim and macmap.vim.
-" Pasting blockwise and linewise selections is not possible in Insert and
-" Visual mode without the +virtualedit feature. They are pasted as if they
-" were characterwise instead. Add to that some tricks to leave the cursor in
-" the right position, also for "gi".
-if has("virtualedit")
- let paste#paste_cmd = {'n': ":call paste#Paste()<CR>"}
- let paste#paste_cmd['v'] = '"-c<Esc>' . paste#paste_cmd['n']
- let paste#paste_cmd['i'] = "\<c-\>\<c-o>\"+gP"
+let paste#paste_cmd = {'n': ":call paste#Paste()<CR>"}
+let paste#paste_cmd['v'] = '"-c<Esc>' . paste#paste_cmd['n']
+let paste#paste_cmd['i'] = "\<c-\>\<c-o>\"+gP"
- func! paste#Paste()
- let ove = &ve
- set ve=all
- normal! `^
- if @+ != ''
- normal! "+gP
- endif
- let c = col(".")
- normal! i
- if col(".") < c " compensate for i<ESC> moving the cursor left
- normal! l
- endif
- let &ve = ove
- endfunc
-else
- let paste#paste_cmd = {'n': "\"=@+.'xy'<CR>gPFx\"_2x"}
- let paste#paste_cmd['v'] = '"-c<Esc>gix<Esc>' . paste#paste_cmd['n'] . '"_x'
- let paste#paste_cmd['i'] = 'x<Esc>' . paste#paste_cmd['n'] . '"_s'
-endif
+func! paste#Paste()
+ let ove = &ve
+ set ve=all
+ normal! `^
+ if @+ != ''
+ normal! "+gP
+ endif
+ let c = col(".")
+ normal! i
+ if col(".") < c " compensate for i<ESC> moving the cursor left
+ normal! l
+ endif
+ let &ve = ove
+endfunc
diff --git a/runtime/autoload/provider/clipboard.vim b/runtime/autoload/provider/clipboard.vim
index 2b06ee8c48..ce140b0948 100644
--- a/runtime/autoload/provider/clipboard.vim
+++ b/runtime/autoload/provider/clipboard.vim
@@ -1,6 +1,16 @@
" The clipboard provider uses shell commands to communicate with the clipboard.
" The provider function will only be registered if a supported command is
" available.
+
+if exists('g:loaded_clipboard_provider')
+ finish
+endif
+" Default to 1. provider#clipboard#Executable() may set 2.
+" To force a reload:
+" :unlet g:loaded_clipboard_provider
+" :runtime autoload/provider/clipboard.vim
+let g:loaded_clipboard_provider = 1
+
let s:copy = {}
let s:paste = {}
let s:clipboard = {}
@@ -120,13 +130,6 @@ function! provider#clipboard#Executable() abort
return ''
endfunction
-if empty(provider#clipboard#Executable())
- " provider#clipboard#Call() *must not* be defined if the provider is broken.
- " Otherwise eval_has_provider() thinks the clipboard provider is
- " functioning, and eval_call_provider() will happily call it.
- finish
-endif
-
function! s:clipboard.get(reg) abort
if type(s:paste[a:reg]) == v:t_func
return s:paste[a:reg]()
@@ -192,3 +195,6 @@ function! provider#clipboard#Call(method, args) abort
let s:here = v:false
endtry
endfunction
+
+" eval_has_provider() decides based on this variable.
+let g:loaded_clipboard_provider = empty(provider#clipboard#Executable()) ? 1 : 2
diff --git a/runtime/autoload/provider/node.vim b/runtime/autoload/provider/node.vim
index 35882849bd..b2a3b3ee08 100644
--- a/runtime/autoload/provider/node.vim
+++ b/runtime/autoload/provider/node.vim
@@ -140,8 +140,9 @@ endfunction
let s:err = ''
let s:prog = provider#node#Detect()
+let g:loaded_node_provider = empty(s:prog) ? 1 : 2
-if empty(s:prog)
+if g:loaded_node_provider != 2
let s:err = 'Cannot find the "neovim" node package. Try :checkhealth'
endif
diff --git a/runtime/autoload/provider/python.vim b/runtime/autoload/provider/python.vim
index a06cbe4814..8a1d162784 100644
--- a/runtime/autoload/provider/python.vim
+++ b/runtime/autoload/provider/python.vim
@@ -7,9 +7,8 @@
if exists('g:loaded_python_provider')
finish
endif
-let g:loaded_python_provider = 1
-
let [s:prog, s:err] = provider#pythonx#Detect(2)
+let g:loaded_python_provider = empty(s:prog) ? 1 : 2
function! provider#python#Prog() abort
return s:prog
@@ -19,11 +18,6 @@ function! provider#python#Error() abort
return s:err
endfunction
-if s:prog == ''
- " Detection failed
- finish
-endif
-
" The Python provider plugin will run in a separate instance of the Python
" host.
call remote#host#RegisterClone('legacy-python-provider', 'python')
diff --git a/runtime/autoload/provider/python3.vim b/runtime/autoload/provider/python3.vim
index 242a224cb3..38ef0cccfc 100644
--- a/runtime/autoload/provider/python3.vim
+++ b/runtime/autoload/provider/python3.vim
@@ -7,9 +7,8 @@
if exists('g:loaded_python3_provider')
finish
endif
-let g:loaded_python3_provider = 1
-
let [s:prog, s:err] = provider#pythonx#Detect(3)
+let g:loaded_python3_provider = empty(s:prog) ? 1 : 2
function! provider#python3#Prog() abort
return s:prog
@@ -19,11 +18,6 @@ function! provider#python3#Error() abort
return s:err
endfunction
-if s:prog == ''
- " Detection failed
- finish
-endif
-
" The Python3 provider plugin will run in a separate instance of the Python3
" host.
call remote#host#RegisterClone('legacy-python3-provider', 'python3')
diff --git a/runtime/autoload/provider/ruby.vim b/runtime/autoload/provider/ruby.vim
index 3b4c6c4839..f843050df9 100644
--- a/runtime/autoload/provider/ruby.vim
+++ b/runtime/autoload/provider/ruby.vim
@@ -62,8 +62,9 @@ endfunction
let s:err = ''
let s:prog = s:detect()
let s:plugin_path = expand('<sfile>:p:h') . '/script_host.rb'
+let g:loaded_ruby_provider = empty(s:prog) ? 1 : 2
-if empty(s:prog)
+if g:loaded_ruby_provider != 2
let s:err = 'Cannot find the neovim RubyGem. Try :checkhealth'
endif
diff --git a/runtime/autoload/python3complete.vim b/runtime/autoload/python3complete.vim
index f0f3aaddb3..a3b057d4d0 100644
--- a/runtime/autoload/python3complete.vim
+++ b/runtime/autoload/python3complete.vim
@@ -44,7 +44,7 @@
"
if !has('python3')
- echo "Error: Required vim compiled with +python3"
+ echo 'Error: Requires python3 + pynvim. :help provider-python'
finish
endif
diff --git a/runtime/autoload/pythoncomplete.vim b/runtime/autoload/pythoncomplete.vim
index ecc36646d9..9cc0ae0d79 100644
--- a/runtime/autoload/pythoncomplete.vim
+++ b/runtime/autoload/pythoncomplete.vim
@@ -42,7 +42,7 @@
"
if !has('python')
- echo "Error: Required vim compiled with +python"
+ echo 'Error: Requires python + pynvim. :help provider-python'
finish
endif
diff --git a/runtime/autoload/remote/host.vim b/runtime/autoload/remote/host.vim
index 6266b312bd..1cf328e08d 100644
--- a/runtime/autoload/remote/host.vim
+++ b/runtime/autoload/remote/host.vim
@@ -147,7 +147,7 @@ function! s:RegistrationCommands(host) abort
\ a:host, string(map(registered, "fnamemodify(v:val, ':t')")))
" Delete the temporary host clone
- call rpcstop(s:hosts[host_id].channel)
+ call jobstop(s:hosts[host_id].channel)
call remove(s:hosts, host_id)
call remove(s:plugins_for_host, host_id)
return lines
diff --git a/runtime/autoload/rubycomplete.vim b/runtime/autoload/rubycomplete.vim
index 40b87f4cbe..ea18470232 100644
--- a/runtime/autoload/rubycomplete.vim
+++ b/runtime/autoload/rubycomplete.vim
@@ -1,9 +1,9 @@
" Vim completion script
-" Language: Ruby
-" Maintainer: Mark Guzman <segfault@hasno.info>
-" URL: https://github.com/vim-ruby/vim-ruby
-" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
-" Maintainer Version: 0.8.1
+" Language: Ruby
+" Maintainer: Mark Guzman <segfault@hasno.info>
+" URL: https://github.com/vim-ruby/vim-ruby
+" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
+" Last Change: 2019 Jan 06
" ----------------------------------------------------------------------------
"
" Ruby IRB/Complete author: Keiju ISHITSUKA(keiju@ishitsuka.com)
@@ -103,7 +103,7 @@ function! s:GetBufferRubyEntity( name, type, ... )
endif
let curpos = getpos(".")
- let [enum,ecol] = searchpairpos( crex, '', '\(end\|}\)', 'wr' )
+ let [enum,ecol] = searchpairpos( crex, '', '\(end\|}\)', 'W' )
call cursor(lastpos[1], lastpos[2])
if lnum > enum
@@ -253,15 +253,27 @@ class VimRubyCompletion
# {{{ buffer analysis magic
def load_requires
+
+ custom_paths = VIM::evaluate("get(g:, 'rubycomplete_load_paths', [])")
+
+ if !custom_paths.empty?
+ $LOAD_PATH.concat(custom_paths).uniq!
+ end
+
buf = VIM::Buffer.current
enum = buf.line_number
nums = Range.new( 1, enum )
nums.each do |x|
+
ln = buf[x]
begin
- eval( "require %s" % $1 ) if /.*require\s*(.*)$/.match( ln )
- rescue Exception
- #ignore?
+ if /.*require_relative\s*(.*)$/.match( ln )
+ eval( "require %s" % File.expand_path($1) )
+ elsif /.*require\s*(["'].*?["'])/.match( ln )
+ eval( "require %s" % $1 )
+ end
+ rescue Exception => e
+ dprint e.inspect
end
end
end
@@ -344,8 +356,13 @@ class VimRubyCompletion
if x != cur_line
next if x == 0
ln = buf[x]
- if /^\s*(module|class|def|include)\s+/.match(ln)
- clscnt += 1 if $1 == "class"
+ is_const = false
+ if /^\s*(module|class|def|include)\s+/.match(ln) || is_const = /^\s*?[A-Z]([A-z]|[1-9])*\s*?[|]{0,2}=\s*?.+\s*?/.match(ln)
+ clscnt += 1 if /class|module/.match($1)
+ # We must make sure to load each constant only once to avoid errors
+ if is_const
+ ln.gsub!(/\s*?[|]{0,2}=\s*?/, '||=')
+ end
#dprint "\$1$1
classdef += "%s\n" % ln
classdef += "end\n" if /def\s+/.match(ln)
@@ -423,7 +440,6 @@ class VimRubyCompletion
return get_buffer_entity_list( "class" )
end
-
def load_rails
allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails")
return if allow_rails.to_i.zero?
@@ -529,7 +545,6 @@ class VimRubyCompletion
ret += ActiveRecord::ConnectionAdapters::SchemaStatements.methods
end
-
return ret
end
@@ -587,11 +602,13 @@ class VimRubyCompletion
# {{{ main completion code
def self.preload_rails
a = VimRubyCompletion.new
- require 'Thread'
- Thread.new(a) do |b|
- begin
- b.load_rails
- rescue
+ if VIM::evaluate("has('nvim')") == 0
+ require 'thread'
+ Thread.new(a) do |b|
+ begin
+ b.load_rails
+ rescue
+ end
end
end
a.load_rails
@@ -612,7 +629,6 @@ class VimRubyCompletion
want_gems = VIM::evaluate("get(g:, 'rubycomplete_load_gemfile')")
load_gems unless want_gems.to_i.zero?
-
input = VIM::Buffer.current.line
cpos = VIM::Window.current.cursor[1] - 1
@@ -666,6 +682,7 @@ class VimRubyCompletion
message = Regexp.quote($4)
dprint "const or cls 2 [recv: \'%s\', msg: \'%s\']" % [ receiver, message ]
load_buffer_class( receiver )
+ load_buffer_module( receiver )
begin
classes = eval("#{receiver}.constants")
#methods = eval("#{receiver}.methods")
@@ -786,7 +803,6 @@ class VimRubyCompletion
methods += Kernel.public_methods
end
-
include_object = VIM::evaluate("exists('g:rubycomplete_include_object') && g:rubycomplete_include_object")
methods = clean_sel( methods, message )
methods = (methods-Object.instance_methods) if include_object == "0"
@@ -829,5 +845,4 @@ let s:rubycomplete_rails_loaded = 0
call s:DefRuby()
"}}} ruby-side code
-
" vim:tw=78:sw=4:ts=8:et:fdm=marker:ft=vim:norl:
diff --git a/runtime/autoload/tohtml.vim b/runtime/autoload/tohtml.vim
index d972ad63fe..2d874c690d 100644
--- a/runtime/autoload/tohtml.vim
+++ b/runtime/autoload/tohtml.vim
@@ -1,6 +1,6 @@
" Vim autoload file for the tohtml plugin.
" Maintainer: Ben Fritz <fritzophrenic@gmail.com>
-" Last Change: 2013 Sep 03
+" Last Change: 2018 Nov 11
"
" Additional contributors:
"
@@ -544,12 +544,16 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{
" add required javascript in reverse order so we can just call append again
" and again without adjusting {{{
- " insert script closing tag
- call append(style_start, [
- \ '',
- \ s:settings.use_xhtml ? '//]]>' : '-->',
- \ "</script>"
- \ ])
+ let s:uses_script = s:settings.dynamic_folds || s:settings.line_ids || !empty(s:settings.prevent_copy)
+
+ " insert script closing tag if needed
+ if s:uses_script
+ call append(style_start, [
+ \ '',
+ \ s:settings.use_xhtml ? '//]]>' : '-->',
+ \ "</script>"
+ \ ])
+ endif
" insert script which corrects the size of small input elements in
" prevent_copy mode. See 2html.vim for details on why this is needed and how
@@ -575,55 +579,61 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{
\ '}'
\ ])
endif
- "
+
" insert javascript to get IDs from line numbers, and to open a fold before
" jumping to any lines contained therein
- call append(style_start, [
- \ " /* Always jump to new location even if the line was hidden inside a fold, or",
- \ " * we corrected the raw number to a line ID.",
- \ " */",
- \ " if (lineElem) {",
- \ " lineElem.scrollIntoView(true);",
- \ " }",
- \ " return true;",
- \ "}",
- \ "if ('onhashchange' in window) {",
- \ " window.onhashchange = JumpToLine;",
- \ "}"
- \ ])
- if s:settings.dynamic_folds
+ if s:settings.line_ids
+ call append(style_start, [
+ \ " /* Always jump to new location even if the line was hidden inside a fold, or",
+ \ " * we corrected the raw number to a line ID.",
+ \ " */",
+ \ " if (lineElem) {",
+ \ " lineElem.scrollIntoView(true);",
+ \ " }",
+ \ " return true;",
+ \ "}",
+ \ "if ('onhashchange' in window) {",
+ \ " window.onhashchange = JumpToLine;",
+ \ "}"
+ \ ])
+
+ if s:settings.dynamic_folds
+ call append(style_start, [
+ \ "",
+ \ " /* navigate upwards in the DOM tree to open all folds containing the line */",
+ \ " var node = lineElem;",
+ \ " while (node && node.id != 'vimCodeElement".s:settings.id_suffix."')",
+ \ " {",
+ \ " if (node.className == 'closed-fold')",
+ \ " {",
+ \ " /* toggle open the fold ID (remove window ID) */",
+ \ " toggleFold(node.id.substr(4));",
+ \ " }",
+ \ " node = node.parentNode;",
+ \ " }",
+ \ ])
+ endif
+ endif
+
+ if s:settings.line_ids
call append(style_start, [
\ "",
- \ " /* navigate upwards in the DOM tree to open all folds containing the line */",
- \ " var node = lineElem;",
- \ " while (node && node.id != 'vimCodeElement".s:settings.id_suffix."')",
- \ " {",
- \ " if (node.className == 'closed-fold')",
- \ " {",
- \ " /* toggle open the fold ID (remove window ID) */",
- \ " toggleFold(node.id.substr(4));",
- \ " }",
- \ " node = node.parentNode;",
+ \ "/* function to open any folds containing a jumped-to line before jumping to it */",
+ \ "function JumpToLine()",
+ \ "{",
+ \ " var lineNum;",
+ \ " lineNum = window.location.hash;",
+ \ " lineNum = lineNum.substr(1); /* strip off '#' */",
+ \ "",
+ \ " if (lineNum.indexOf('L') == -1) {",
+ \ " lineNum = 'L'+lineNum;",
+ \ " }",
+ \ " if (lineNum.indexOf('W') == -1) {",
+ \ " lineNum = 'W1'+lineNum;",
\ " }",
+ \ " var lineElem = document.getElementById(lineNum);"
\ ])
endif
- call append(style_start, [
- \ "",
- \ "/* function to open any folds containing a jumped-to line before jumping to it */",
- \ "function JumpToLine()",
- \ "{",
- \ " var lineNum;",
- \ " lineNum = window.location.hash;",
- \ " lineNum = lineNum.substr(1); /* strip off '#' */",
- \ "",
- \ " if (lineNum.indexOf('L') == -1) {",
- \ " lineNum = 'L'+lineNum;",
- \ " }",
- \ " if (lineNum.indexOf('W') == -1) {",
- \ " lineNum = 'W1'+lineNum;",
- \ " }",
- \ " lineElem = document.getElementById(lineNum);"
- \ ])
" Insert javascript to toggle matching folds open and closed in all windows,
" if dynamic folding is active.
@@ -648,11 +658,13 @@ func! tohtml#Diff2HTML(win_list, buf_list) "{{{
\ ])
endif
- " insert script tag; javascript is always needed for the line number
- " normalization for URL hashes
- call append(style_start, [
- \ "<script type='text/javascript'>",
- \ s:settings.use_xhtml ? '//<![CDATA[' : "<!--"])
+ if s:uses_script
+ " insert script tag; javascript is always needed for the line number
+ " normalization for URL hashes
+ call append(style_start, [
+ \ "<script type='text/javascript'>",
+ \ s:settings.use_xhtml ? '//<![CDATA[' : "<!--"])
+ endif
" Insert styles from all the generated html documents and additional styles
" for the table-based layout of the side-by-side diff. The diff should take
@@ -767,7 +779,7 @@ func! tohtml#GetUserSettings() "{{{
if user_settings.no_pre == 0
call tohtml#GetOption(user_settings,
\ 'expand_tabs',
- \ &expandtab || &ts != 8 || user_settings.number_lines ||
+ \ &expandtab || &ts != 8 || &vts != '' || user_settings.number_lines ||
\ (user_settings.dynamic_folds && !user_settings.no_foldcolumn))
else
let user_settings.expand_tabs = 1
diff --git a/runtime/autoload/xmlformat.vim b/runtime/autoload/xmlformat.vim
index f227b5ee25..ea89401977 100644
--- a/runtime/autoload/xmlformat.vim
+++ b/runtime/autoload/xmlformat.vim
@@ -1,9 +1,9 @@
" Vim plugin for formatting XML
-" Last Change: Thu, 22 May 2018 21:26:55 +0100
-" Version: 0.1
-" Author: Christian Brabandt <cb@256bit.org>
-" Repository: https://github.com/chrisbra/vim-xml-ftplugin
-" License: VIM License
+" Last Change: Thu, 07 Dec 2018
+" Version: 0.1
+" Author: Christian Brabandt <cb@256bit.org>
+" Repository: https://github.com/chrisbra/vim-xml-ftplugin
+" License: VIM License
" Documentation: see :h xmlformat.txt (TODO!)
" ---------------------------------------------------------------------
" Load Once: {{{1
@@ -85,7 +85,11 @@ func! s:Trim(item)
endfunc
" Check if tag is a new opening tag <tag> {{{1
func! s:StartTag(tag)
- return a:tag =~? '^\s*<[^/?]'
+ let is_comment = s:IsComment(a:tag)
+ return a:tag =~? '^\s*<[^/?]' && !is_comment
+endfunc
+func! s:IsComment(tag)
+ return a:tag =~? '<!--'
endfunc
" Remove one level of indentation {{{1
func! s:DecreaseIndent()
diff --git a/runtime/bugreport.vim b/runtime/bugreport.vim
index 650e37940d..27761ca011 100644
--- a/runtime/bugreport.vim
+++ b/runtime/bugreport.vim
@@ -2,7 +2,7 @@
:" information about the environment of a possible bug in Vim.
:"
:" Maintainer: Bram Moolenaar <Bram@vim.org>
-:" Last change: 2005 Jun 12
+:" Last change: 2019 Jan 27
:"
:" To use inside Vim:
:" :so $VIMRUNTIME/bugreport.vim
diff --git a/runtime/compiler/cs.vim b/runtime/compiler/cs.vim
index 4cc1784678..4f6dd3cdfd 100644
--- a/runtime/compiler/cs.vim
+++ b/runtime/compiler/cs.vim
@@ -1,8 +1,8 @@
" Vim compiler file
-" Compiler: Microsoft Visual Studio C#
-" Maintainer: Zhou YiChao (broken.zhou@gmail.com)
-" Previous Maintainer: Joseph H. Yao (hyao@sina.com)
-" Last Change: 2012 Apr 30
+" Compiler: Microsoft Visual Studio C#
+" Maintainer: Yichao Zhou (broken.zhou@gmail.com)
+" Previous Maintainer: Joseph H. Yao (hyao@sina.com)
+" Last Change: Jul 22, 2019
if exists("current_compiler")
finish
@@ -20,7 +20,7 @@ CompilerSet errorformat+=%f(%l\\,%v):\ %t%*[^:]:\ %m,
\%trror%*[^:]:\ %m,
\%tarning%*[^:]:\ %m
-CompilerSet makeprg=csc\ %
+CompilerSet makeprg=csc\ %:S
let &cpo = s:keepcpo
unlet s:keepcpo
diff --git a/runtime/compiler/erlang.vim b/runtime/compiler/erlang.vim
index e177a279c5..e22887e05e 100644
--- a/runtime/compiler/erlang.vim
+++ b/runtime/compiler/erlang.vim
@@ -1,13 +1,13 @@
" Vim compiler file
" Compiler: Erlang
" Maintainer: Dmitry Vasiliev <dima at hlabs dot org>
-" Last Change: 2012-02-13
+" Last Change: 2019 Jul 23
if exists("current_compiler")
finish
endif
let current_compiler = "erlang"
-CompilerSet makeprg=erlc\ -Wall\ %
+CompilerSet makeprg=erlc\ -Wall\ %:S
CompilerSet errorformat=%f:%l:\ %m
diff --git a/runtime/compiler/eruby.vim b/runtime/compiler/eruby.vim
index 45ad5eeadf..a81a3f3b77 100644
--- a/runtime/compiler/eruby.vim
+++ b/runtime/compiler/eruby.vim
@@ -3,6 +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: 2018 Jan 25
if exists("current_compiler")
finish
@@ -28,8 +29,8 @@ CompilerSet errorformat=
\%W%f:%l:\ warning:\ %m,
\%E%f:%l:in\ %*[^:]:\ %m,
\%E%f:%l:\ %m,
- \%-C%\tfrom\ %f:%l:in\ %.%#,
- \%-Z%\tfrom\ %f:%l,
+ \%-C%\t%\\d%#:%#\ %#from\ %f:%l:in\ %.%#,
+ \%-Z%\t%\\d%#:%#\ %#from\ %f:%l,
\%-Z%p^,
\%-G%.%#
diff --git a/runtime/compiler/fortran_cv.vim b/runtime/compiler/fortran_cv.vim
index 089d3b27c2..bc217bdc66 100644
--- a/runtime/compiler/fortran_cv.vim
+++ b/runtime/compiler/fortran_cv.vim
@@ -22,7 +22,7 @@ CompilerSet errorformat=
\%-Z%p%^%.%#,
\%-G%.%#,
" Compiler call
-CompilerSet makeprg=df\ /nologo\ /noobj\ /c\ %
+CompilerSet makeprg=df\ /nologo\ /noobj\ /c\ %:S
" Visual fortran defaults to printing output on stderr
" Adjust option shellpipe accordingly
diff --git a/runtime/compiler/gcc.vim b/runtime/compiler/gcc.vim
index 1af568de57..30e5149f9f 100644
--- a/runtime/compiler/gcc.vim
+++ b/runtime/compiler/gcc.vim
@@ -2,6 +2,8 @@
" Compiler: GNU C Compiler
" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
" Latest Revision: 2010-10-14
+" changed pattern for entering/leaving directories
+" by Daniel Hahler, 2019 Jul 12
" added line suggested by Anton Lindqvist 2016 Mar 31
if exists("current_compiler")
@@ -27,10 +29,10 @@ CompilerSet errorformat=
\%f:%l:\ %m,
\%f:\\(%*[^\\)]\\):\ %m,
\\"%f\"\\,\ line\ %l%*\\D%c%*[^\ ]\ %m,
- \%D%*\\a[%*\\d]:\ Entering\ directory\ [`']%f',
- \%X%*\\a[%*\\d]:\ Leaving\ directory\ [`']%f',
- \%D%*\\a:\ Entering\ directory\ [`']%f',
- \%X%*\\a:\ Leaving\ directory\ [`']%f',
+ \%D%*\\a[%*\\d]:\ Entering\ directory\ %*[`']%f',
+ \%X%*\\a[%*\\d]:\ Leaving\ directory\ %*[`']%f',
+ \%D%*\\a:\ Entering\ directory\ %*[`']%f',
+ \%X%*\\a:\ Leaving\ directory\ %*[`']%f',
\%DMaking\ %*\\a\ in\ %f
if exists('g:compiler_gcc_ignore_unmatched_lines')
diff --git a/runtime/compiler/jikes.vim b/runtime/compiler/jikes.vim
index 5125128535..2d4500e894 100644
--- a/runtime/compiler/jikes.vim
+++ b/runtime/compiler/jikes.vim
@@ -1,7 +1,7 @@
" Vim Compiler File
" Compiler: Jikes
" Maintainer: Dan Sharp <dwsharp at hotmail dot com>
-" Last Change: 20 Jan 2009
+" Last Change: 2019 Jul 23
" URL: http://dwsharp.users.sourceforge.net/vim/compiler
if exists("current_compiler")
@@ -14,5 +14,5 @@ if exists(":CompilerSet") != 2 " older Vim always used :setlocal
endif
" Jikes defaults to printing output on stderr
-CompilerSet makeprg=jikes\ -Xstdout\ +E\ \"%\"
+CompilerSet makeprg=jikes\ -Xstdout\ +E\ \"%:S\"
CompilerSet errorformat=%f:%l:%v:%*\\d:%*\\d:%*\\s%m
diff --git a/runtime/compiler/ocaml.vim b/runtime/compiler/ocaml.vim
index da15bce8fe..7f8a7eab67 100644
--- a/runtime/compiler/ocaml.vim
+++ b/runtime/compiler/ocaml.vim
@@ -1,7 +1,11 @@
" Vim Compiler File
-" Compiler: ocaml
-" Maintainer: See ftplugin/ocaml.vim (?)
-" Last Change: June 2013 by Marc Weber
+" Compiler: ocaml
+" Maintainer: Markus Mottl <markus.mottl@gmail.com>
+" URL: https://github.com/rgrinberg/vim-ocaml
+" Last Change:
+" 2017 Nov 26 - Improved error format (Markus Mottl)
+" 2013 Aug 27 - Added a new OCaml error format (Markus Mottl)
+" 2013 Jun 30 - Initial version (Marc Weber)
"
" Marc Weber's comments:
" Setting makeprg doesn't make sense, because there is ocamlc, ocamlopt,
@@ -17,7 +21,6 @@
"
" So having it here makes people opt-in
-
if exists("current_compiler")
finish
endif
@@ -28,6 +31,7 @@ set cpo&vim
CompilerSet errorformat =
\%EFile\ \"%f\"\\,\ line\ %l\\,\ characters\ %c-%*\\d:,
+ \%EFile\ \"%f\"\\,\ line\ %l\\,\ characters\ %c-%*\\d\ %.%#,
\%EFile\ \"%f\"\\,\ line\ %l\\,\ character\ %c:%m,
\%+EReference\ to\ unbound\ regexp\ name\ %m,
\%Eocamlyacc:\ e\ -\ line\ %l\ of\ \"%f\"\\,\ %m,
@@ -38,6 +42,12 @@ CompilerSet errorformat =
\%X%*\\a[%*\\d]:\ Leaving\ directory\ `%f',
\%D%*\\a:\ Entering\ directory\ `%f',
\%X%*\\a:\ Leaving\ directory\ `%f',
+ \%D%*\\a[%*\\d]:\ Entering\ directory\ '%f',
+ \%X%*\\a[%*\\d]:\ Leaving\ directory\ '%f',
+ \%D%*\\a:\ Entering\ directory\ '%f',
+ \%X%*\\a:\ Leaving\ directory\ '%f',
+ \%DEntering\ directory\ '%f',
+ \%XLeaving\ directory\ '%f',
\%DMaking\ %*\\a\ in\ %f
let &cpo = s:cpo_save
diff --git a/runtime/compiler/onsgmls.vim b/runtime/compiler/onsgmls.vim
index 130d3e21b3..68925ef459 100644
--- a/runtime/compiler/onsgmls.vim
+++ b/runtime/compiler/onsgmls.vim
@@ -1,7 +1,7 @@
" Vim compiler file
" Compiler: onsgmls
" Maintainer: Robert Rowsome <rowsome@wam.umd.edu>
-" Last Change: 2004 Mar 27
+" Last Change: 2019 Jul 23
if exists("current_compiler")
finish
@@ -15,7 +15,7 @@ endif
let s:cpo_save = &cpo
set cpo-=C
-CompilerSet makeprg=onsgmls\ -s\ %
+CompilerSet makeprg=onsgmls\ -s\ %:S
CompilerSet errorformat=onsgmls:%f:%l:%c:%t:%m,
\onsgmls:%f:%l:%c:%m
diff --git a/runtime/compiler/perl.vim b/runtime/compiler/perl.vim
index 583c6c3787..a857caed8f 100644
--- a/runtime/compiler/perl.vim
+++ b/runtime/compiler/perl.vim
@@ -1,7 +1,7 @@
" Vim Compiler File
" Compiler: Perl syntax checks (perl -Wc)
" Maintainer: Christian J. Robinson <heptite@gmail.com>
-" Last Change: 2006 Aug 13
+" Last Change: 2019 Jul 22
if exists("current_compiler")
finish
@@ -27,7 +27,7 @@ else
let s:taintopt = ''
endif
-exe 'CompilerSet makeprg=perl\ -' . s:warnopt . s:taintopt . 'c\ %'
+exe 'CompilerSet makeprg=perl\ -' . s:warnopt . s:taintopt . 'c\ %:S'
CompilerSet errorformat=
\%-G%.%#had\ compilation\ errors.,
diff --git a/runtime/compiler/rake.vim b/runtime/compiler/rake.vim
index 8490f2a9e9..3d11a31f89 100644
--- a/runtime/compiler/rake.vim
+++ b/runtime/compiler/rake.vim
@@ -3,6 +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: 2018 Mar 02
if exists("current_compiler")
finish
@@ -20,12 +21,12 @@ CompilerSet makeprg=rake
CompilerSet errorformat=
\%D(in\ %f),
- \%\\s%#from\ %f:%l:%m,
- \%\\s%#from\ %f:%l:,
- \%\\s%##\ %f:%l:%m,
- \%\\s%##\ %f:%l,
- \%\\s%#[%f:%l:\ %#%m,
- \%\\s%#%f:%l:\ %#%m,
+ \%\\s%#%\\d%#:%#\ %#from\ %f:%l:%m,
+ \%\\s%#%\\d%#:%#\ %#from\ %f:%l:,
+ \%\\s%##\ %f:%l:%m%\\&%.%#%\\D:%\\d%\\+:%.%#,
+ \%\\s%##\ %f:%l%\\&%.%#%\\D:%\\d%\\+,
+ \%\\s%#[%f:%l:\ %#%m%\\&%.%#%\\D:%\\d%\\+:%.%#,
+ \%\\s%#%f:%l:\ %#%m%\\&%.%#%\\D:%\\d%\\+:%.%#,
\%\\s%#%f:%l:,
\%m\ [%f:%l]:,
\%+Erake\ aborted!,
diff --git a/runtime/compiler/rspec.vim b/runtime/compiler/rspec.vim
index c77bd70da7..0cfce04572 100644
--- a/runtime/compiler/rspec.vim
+++ b/runtime/compiler/rspec.vim
@@ -3,6 +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: 2018 Aug 07
if exists("current_compiler")
finish
@@ -23,7 +24,8 @@ CompilerSet errorformat=
\%E%.%#:in\ `load':\ %f:%l:%m,
\%E%f:%l:in\ `%*[^']':\ %m,
\%-Z\ \ \ \ \ %\\+\#\ %f:%l:%.%#,
- \%E\ \ %\\d%\\+)%.%#,
+ \%E\ \ \ \ \ Failure/Error:\ %m,
+ \%E\ \ \ \ \ Failure/Error:,
\%C\ \ \ \ \ %m,
\%C%\\s%#,
\%-G%.%#
diff --git a/runtime/compiler/ruby.vim b/runtime/compiler/ruby.vim
index dcf7a40129..82d4d1c876 100644
--- a/runtime/compiler/ruby.vim
+++ b/runtime/compiler/ruby.vim
@@ -4,7 +4,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
if exists("current_compiler")
finish
@@ -21,21 +21,21 @@ set cpo-=C
" default settings runs script normally
" add '-c' switch to run syntax check only:
"
-" CompilerSet makeprg=ruby\ -wc\ $*
+" CompilerSet makeprg=ruby\ -c
"
" or add '-c' at :make command line:
"
" :make -c %<CR>
"
-CompilerSet makeprg=ruby\ -w\ $*
+CompilerSet makeprg=ruby
CompilerSet errorformat=
\%+E%f:%l:\ parse\ error,
\%W%f:%l:\ warning:\ %m,
\%E%f:%l:in\ %*[^:]:\ %m,
\%E%f:%l:\ %m,
- \%-C%\tfrom\ %f:%l:in\ %.%#,
- \%-Z%\tfrom\ %f:%l,
+ \%-C%\t%\\d%#:%#\ %#from\ %f:%l:in\ %.%#,
+ \%-Z%\t%\\d%#:%#\ %#from\ %f:%l,
\%-Z%p^,
\%-G%.%#
diff --git a/runtime/compiler/rubyunit.vim b/runtime/compiler/rubyunit.vim
index ed0639b581..48e8fa41ab 100644
--- a/runtime/compiler/rubyunit.vim
+++ b/runtime/compiler/rubyunit.vim
@@ -3,6 +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: 2014 Mar 23
if exists("current_compiler")
finish
diff --git a/runtime/compiler/rustc.vim b/runtime/compiler/rustc.vim
index c27bdc9c0c..5e5b9a4e0a 100644
--- a/runtime/compiler/rustc.vim
+++ b/runtime/compiler/rustc.vim
@@ -19,7 +19,7 @@ endif
if exists("g:rustc_makeprg_no_percent") && g:rustc_makeprg_no_percent != 0
CompilerSet makeprg=rustc
else
- CompilerSet makeprg=rustc\ \%
+ CompilerSet makeprg=rustc\ \%:S
endif
" Old errorformat (before nightly 2016/08/10)
diff --git a/runtime/compiler/splint.vim b/runtime/compiler/splint.vim
index 6239ca7139..3d7ada6d1d 100644
--- a/runtime/compiler/splint.vim
+++ b/runtime/compiler/splint.vim
@@ -2,7 +2,7 @@
" Compiler: splint/lclint (C source code checker)
" Maintainer: Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
" Splint Home: http://www.splint.org/
-" Last Change: 2005 Apr 21
+" Last Change: 2019 Jul 23
" $Revision: 1.3 $
if exists("current_compiler")
@@ -19,7 +19,7 @@ set cpo-=C
" adapt this if you want to check more than one file at a time.
" put command line options in .splintrc or ~/.splintrc
-CompilerSet makeprg=splint\ %
+CompilerSet makeprg=splint\ %:S
" Note: when using the new array bounds checking flags: Each warning
" usually has several lines and several references to source code mostly
diff --git a/runtime/compiler/xmlwf.vim b/runtime/compiler/xmlwf.vim
index cd2e2bb6ad..3de9d08d55 100644
--- a/runtime/compiler/xmlwf.vim
+++ b/runtime/compiler/xmlwf.vim
@@ -1,7 +1,7 @@
" Vim Compiler File
" Compiler: xmlwf
" Maintainer: Robert Rowsome <rowsome@wam.umd.edu>
-" Last Change: 2004 Mar 27
+" Last Change: 2019 Jul 23
if exists("current_compiler")
finish
@@ -15,7 +15,7 @@ if exists(":CompilerSet") != 2 " older Vim always used :setlocal
command -nargs=* CompilerSet setlocal <args>
endif
-CompilerSet makeprg=xmlwf\ %
+CompilerSet makeprg=xmlwf\ %:S
CompilerSet errorformat=%f:%l%c:%m
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index a529a9b32e..2c6b053994 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -200,17 +200,26 @@ User reloads the buffer with ":edit", emits: >
nvim_buf_detach_event[{buf}]
*api-buffer-updates-lua*
-In-process lua plugins can also recieve buffer updates, in the form of lua
+In-process lua plugins can also receive buffer updates, in the form of lua
callbacks. These callbacks are called frequently in various contexts, buffer
contents or window layout should not be changed inside these |textlock|.
-|lua-vim.schedule| can be used to defer these operations to the main loop,
-where they are allowed.
+|vim.schedule| can be used to defer these operations to the main loop, where
+they are allowed.
|nvim_buf_attach| will take keyword args for the callbacks. "on_lines" will
-receive parameters ("lines", {buf}, {changedtick}, {firstline}, {lastline}, {new_lastline}).
-Unlike remote channels the text contents are not passed. The new text can be
-accessed inside the callback as
-`vim.api.nvim_buf_get_lines(buf, firstline, new_lastline, true)`
+receive parameters ("lines", {buf}, {changedtick}, {firstline}, {lastline},
+{new_lastline}, {old_byte_size}[, {old_utf32_size}, {old_utf16_size}]).
+Unlike remote channel events the text contents are not passed. The new text can
+be accessed inside the callback as
+
+ `vim.api.nvim_buf_get_lines(buf, firstline, new_lastline, true)`
+
+{old_byte_size} is the total size of the replaced region {firstline} to
+{lastline} in bytes, including the final newline after {lastline}. if
+`utf_sizes` is set to true in |nvim_buf_attach()| keyword args, then the
+UTF-32 and UTF-16 sizes of the deleted region is also passed as additional
+arguments {old_utf32_size} and {old_utf16_size}.
+
"on_changedtick" is invoked when |b:changedtick| was incremented but no text
was changed. The parameters recieved are ("changedtick", {buf}, {changedtick}).
@@ -284,14 +293,18 @@ highlighting, or |api-highlights|.
By default, floats will use |hl-NormalFloat| as normal highlight, which
links to |hl-Pmenu| in the builtin color scheme. The 'winhighlight' option can
be used to override it. Currently, floating windows don't support any visual
-decorations like a border or additional widgets like scrollbar.
+decorations like a border or additional widgets like scrollbar. By default,
+floats will inherit options from the current window. This is not always
+useful for some options, like 'number'. Use `style='minimal'` flag to
+|nvim_open_win()| to disable many UI features that are unwanted for a simple
+float, like end-of-buffer region or special columns.
Here is an example for creating a float with scratch buffer: >
let buf = nvim_create_buf(v:false, v:true)
call nvim_buf_set_lines(buf, 0, -1, v:true, ["test", "text"])
let opts = {'relative': 'cursor', 'width': 10, 'height': 2, 'col': 0,
- \ 'row': 1, 'anchor': 'NW'}
+ \ 'row': 1, 'anchor': 'NW', 'style': 'minimal'}
let win = nvim_open_win(buf, 0, opts)
" optional: change highlight, otherwise Pmenu is used
call nvim_win_set_option(win, 'winhl', 'Normal:MyHighlight')
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index 4cc1f53cca..6b39f1a103 100644
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -305,6 +305,7 @@ Name triggered by ~
|FuncUndefined| a user function is used but it isn't defined
|SpellFileMissing| a spell file is used but it can't be found
|SourcePre| before sourcing a Vim script
+|SourcePost| after sourcing a Vim script
|SourceCmd| before sourcing a Vim script |Cmd-event|
|VimResized| after the Vim window size changed
@@ -397,8 +398,8 @@ BufFilePost After changing the name of the current buffer
BufFilePre Before changing the name of the current buffer
with the ":file" or ":saveas" command.
*BufHidden*
-BufHidden Just after a buffer has become hidden. That
- is, when there are no longer windows that show
+BufHidden Just before a buffer becomes hidden. That is,
+ when there are no longer windows that show
the buffer, but the buffer is not unloaded or
deleted. Not used for ":qa" or ":q" when
exiting Vim.
@@ -590,18 +591,19 @@ CompleteDone After Insert mode completion is done. Either
completed item.
CompleteChanged *CompleteChanged*
- After each time popup menu changed, not fired
- on popup menu hide, use |CompleteDone| for popup
- menu hide.
+ After each time the Insert mode completion
+ menu changed. Not fired on popup menu hide,
+ use |CompleteDone| for that. Never triggered
+ recursively.
Sets these |v:event| keys:
- completed_item
- height
- width
- row
- col
- size
- scrollbar
+ completed_item See |complete-items|.
+ height nr of items visible
+ width screen cells
+ row top screen row
+ col leftmost screen column
+ size total nr of items
+ scrollbar TRUE if visible
It is not allowed to change the text |textlock|.
@@ -646,6 +648,7 @@ CursorMoved After the cursor was moved in Normal or Visual
Not triggered when there is typeahead or when
an operator is pending.
For an example see |match-parens|.
+ Note: Cannot be skipped with `:noautocmd`.
Careful: This is triggered very often, don't
do anything that the user does not expect or
that is slow.
@@ -775,13 +778,14 @@ FilterReadPre Before reading a file from a filter command.
Not triggered when 'shelltemp' is off.
*FilterWritePost*
FilterWritePost After writing a file for a filter command or
- making a diff.
+ making a diff with an external diff (see
+ DiffUpdated for internal diff).
Vim checks the pattern against the name of
the current buffer as with FilterWritePre.
Not triggered when 'shelltemp' is off.
*FilterWritePre*
FilterWritePre Before writing a file for a filter command or
- making a diff.
+ making a diff with an external diff.
Vim checks the pattern against the name of
the current buffer, not the name of the
temporary file that is the output of the
@@ -873,12 +877,33 @@ MenuPopup Just before showing the popup menu (under the
*OptionSet*
OptionSet After setting an option (except during
|startup|). The |autocmd-pattern| is matched
- against the long option name.
- |v:option_old| indicates the old option value,
- |v:option_new| indicates the new value,
+ against the long option name. |<amatch>|
+ indicates what option has been set.
+
|v:option_type| indicates whether it's global
- or local scoped and |<amatch>| indicates which
- option was set.
+ or local scoped.
+ |v:option_command| indicates what type of
+ set/let command was used (follow the tag to
+ see the table).
+ |v:option_new| indicates the newly set value.
+ |v:option_oldlocal| has the old local value.
+ |v:option_oldglobal| has the old global value.
+ |v:option_old| indicates the old option value.
+
+ |v:option_oldlocal| is only set when |:set|
+ or |:setlocal| or a |modeline| was used to set
+ the option. Similarly |v:option_oldglobal| is
+ only set when |:set| or |:setglobal| was used.
+
+ Note that when setting a |global-local| string
+ option with |:set|, then |v:option_old| is the
+ old global value. However, for all other kinds
+ of options (local string options, global-local
+ number options, ...) it is the old local
+ value.
+
+ OptionSet is not triggered on startup and for
+ the 'key' option for obvious reasons.
Usage example: Check for the existence of the
directory in the 'backupdir' and 'undodir'
@@ -955,6 +980,12 @@ ShellFilterPost After executing a shell command with
*SourcePre*
SourcePre Before sourcing a Vim script. |:source|
<afile> is the name of the file being sourced.
+ *SourcePost*
+SourcePost After sourcing a Vim script. |:source|
+ <afile> is the name of the file being sourced.
+ Not triggered when sourcing was interrupted.
+ Also triggered after a SourceCmd autocommand
+ was triggered.
*SourceCmd*
SourceCmd When sourcing a Vim script. |:source|
<afile> is the name of the file being sourced.
@@ -1035,10 +1066,13 @@ TermResponse After the response to t_RV is received from
anything else that takes time is involved).
*TextChanged*
TextChanged After a change was made to the text in the
- current buffer in Normal mode. That is when
- |b:changedtick| has changed.
+ current buffer in Normal mode. That is after
+ |b:changedtick| has changed (also when that
+ happened before the TextChanged autocommand
+ was defined).
Not triggered when there is typeahead or when
an operator is pending.
+ Note: Cannot be skipped with `:noautocmd`.
Careful: This is triggered very often, don't
do anything that the user does not expect or
that is slow.
@@ -1053,14 +1087,12 @@ TextChangedP After a change was made to the text in the
popup menu is visible. Otherwise the same as
TextChanged.
*User*
-User Never executed automatically. To be used for
- autocommands that are only executed with
- ":doautocmd".
- Note that when `:doautocmd User MyEvent` is
- used while there are no matching autocommands,
- you will get an error. If you don't want
- that, define a dummy autocommand yourself.
- *UserGettingBored*
+User Not executed automatically. Use |:doautocmd|
+ to trigger this, typically for "custom events"
+ in a plugin. Example: >
+ :autocmd User MyPlugin echom 'got MyPlugin event'
+ :doautocmd User MyPlugin
+< *UserGettingBored*
UserGettingBored When the user presses the same key 42 times.
Just kidding! :-)
*VimEnter*
@@ -1338,7 +1370,7 @@ have changed autocommands, or when Vim has executed the wrong autocommands
Note that the 'eventignore' option applies here too. Events listed in this
option will not cause any commands to be executed.
- *:do* *:doau* *:doautocmd* *E217*
+ *:do* *:doau* *:doaut* *:doautocmd* *E217*
:do[autocmd] [<nomodeline>] [group] {event} [fname]
Apply the autocommands matching [fname] (default:
current file name) for {event} to the current buffer.
@@ -1355,18 +1387,17 @@ option will not cause any commands to be executed.
When the [group] argument is not given, Vim executes
the autocommands for all groups. When the [group]
argument is included, Vim executes only the matching
- autocommands for that group. Note: if you use an
- undefined group name, Vim gives you an error message.
+ autocommands for that group. Undefined group is an
+ error.
*<nomodeline>*
After applying the autocommands the modelines are
processed, so that their settings overrule the
- settings from autocommands, like what happens when
- editing a file. This is skipped when the <nomodeline>
- argument is present. You probably want to use
- <nomodeline> for events that are not used when loading
- a buffer, such as |User|.
- Processing modelines is also skipped when no
- matching autocommands were executed.
+ settings from autocommands when editing a file. This
+ is skipped if <nomodeline> is specified. You probably
+ want to use <nomodeline> for events not used when
+ loading a buffer, such as |User|.
+ Modelines are also skipped when no matching
+ autocommands were executed.
*:doautoa* *:doautoall*
:doautoa[ll] [<nomodeline>] [group] {event} [fname]
@@ -1463,8 +1494,8 @@ If you want the buffer to be unmodified after changing it, reset the
instead of ":q!".
*autocmd-nested* *E218*
-By default, autocommands do not nest. If you use ":e" or ":w" in an
-autocommand, Vim does not execute the BufRead and BufWrite autocommands for
+By default, autocommands do not nest. For example, if you use ":e" or ":w" in
+an autocommand, Vim does not execute the BufRead and BufWrite autocommands for
those commands. If you do want this, use the "++nested" flag for those
commands in which you want nesting. For example: >
:autocmd FileChangedShell *.c ++nested e!
@@ -1610,5 +1641,8 @@ following command. Example: >
This will write the file without triggering the autocommands defined by the
gzip plugin.
+Note that some autocommands are not triggered right away, but only later.
+This specifically applies to |CursorMoved| and |TextChanged|.
+
vim:tw=78:ts=8:noet:ft=help:norl:
diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt
index 912231bfcd..bd3f22a371 100644
--- a/runtime/doc/change.txt
+++ b/runtime/doc/change.txt
@@ -162,8 +162,6 @@ gR Enter Virtual Replace mode: Each character you type
<Tab> may replace several characters at once.
Repeat the entered text [count]-1 times. See
|Virtual-Replace-mode| for more details.
- {not available when compiled without the |+vreplace|
- feature}
*c*
["x]c{motion} Delete {motion} text [into register x] and start
@@ -282,14 +280,11 @@ gr{char} Replace the virtual characters under the cursor with
space. See |gR| and |Virtual-Replace-mode| for more
details. As with |r| a count may be given.
{char} can be entered like with |r|.
- {not available when compiled without the |+vreplace|
- feature}
*digraph-arg*
The argument for Normal mode commands like |r| and |t| is a single character.
When 'cpo' doesn't contain the 'D' flag, this character can also be entered
like |digraphs|. First type CTRL-K and then the two digraph characters.
-{not available when compiled without the |+digraphs| feature}
*case*
The following commands change the case of letters. The currently active
@@ -600,11 +595,11 @@ Directory for temporary files is created in the first suitable directory of:
For the {pattern} see |pattern|.
{string} can be a literal string, or something
special; see |sub-replace-special|.
- *E939*
When [range] and [count] are omitted, replace in the
current line only. When [count] is given, replace in
[count] lines, starting with the last line in [range].
When [range] is omitted start in the current line.
+ *E939*
[count] must be a positive number. Also see
|cmdline-ranges|.
@@ -800,7 +795,7 @@ the |substitute()| function with the following exceptions:
- magic is always set without regard to 'magic'.
- A ~ inserts a tilde literally.
- <CR> and \r inserts a carriage-return (CTRL-M).
- - \<CR> does not have a special meaning. it's just one of \x.
+ - \<CR> does not have a special meaning. It's just one of \x.
Examples: >
:s/a\|b/xxx\0xxx/g modifies "a b" to "xxxaxxx xxxbxxx"
@@ -886,9 +881,9 @@ When the result is a |List| then the items are joined with separating line
breaks. Thus each item becomes a line, except that they can contain line
breaks themselves.
-The whole matched text can be accessed with "submatch(0)". The text matched
-with the first pair of () with "submatch(1)". Likewise for further
-sub-matches in ().
+The |submatch()| function can be used to obtain matched text. The whole
+matched text can be accessed with "submatch(0)". The text matched with the
+first pair of () with "submatch(1)". Likewise for further sub-matches in ().
Be careful: The separation character must not appear in the expression!
Consider using a character like "@" or ":". There is no problem if the result
@@ -1137,9 +1132,9 @@ There are ten types of registers: *registers* *E354*
2. 10 numbered registers "0 to "9
3. The small delete register "-
4. 26 named registers "a to "z or "A to "Z
-5. three read-only registers ":, "., "%
-6. alternate buffer register "#
-7. the expression register "=
+5. Three read-only registers ":, "., "%
+6. Alternate buffer register "#
+7. The expression register "=
8. The selection registers "* and "+
9. The black hole register "_
10. Last search pattern register "/
diff --git a/runtime/doc/cmdline.txt b/runtime/doc/cmdline.txt
index a3b5f6b22a..119fd924f1 100644
--- a/runtime/doc/cmdline.txt
+++ b/runtime/doc/cmdline.txt
@@ -416,6 +416,10 @@ a previous version <Esc> was used). In the pattern standard wildcards '*' and
'?' are accepted when matching file names. '*' matches any string, '?'
matches exactly one character.
+When repeating 'wildchar' or CTRL-N you cycle through the matches, eventually
+ending up back to what was typed. If the first match is not what you wanted,
+you can use <S-Tab> or CTRL-P to go straight back to what you typed.
+
The 'wildignorecase' option can be set to ignore case in filenames.
The 'wildmenu' option can be set to show the matches just above the command
@@ -495,7 +499,6 @@ that see the '"' as part of their argument:
:autocmd
:bufdo
:cexpr (and the like)
- :call
:cdo (and the like)
:command
:cscope (and the like)
diff --git a/runtime/doc/deprecated.txt b/runtime/doc/deprecated.txt
index b56240353f..27e60be368 100644
--- a/runtime/doc/deprecated.txt
+++ b/runtime/doc/deprecated.txt
@@ -44,6 +44,11 @@ Functions ~
*jobclose()* Obsolete name for |chanclose()|
*jobsend()* Obsolete name for |chansend()|
*last_buffer_nr()* Obsolete name for bufnr("$").
+*rpcstop()* Deprecated. Instead use |jobstop()| to stop any job,
+ or chanclose(id, "rpc") to close RPC communication
+ without stopping the job. Use chanclose(id) to close
+ any socket.
+
Modifiers ~
*cpo-<*
@@ -58,6 +63,10 @@ Normal commands ~
Options ~
*'cscopeverbose'* Enabled by default. Use |:silent| instead.
+*'exrc'* *'ex'* Security risk: downloaded files could include
+ a malicious .nvimrc or .exrc file. See 'secure'.
+ Recommended alternative: define an autocommand in your
+ |vimrc| to set options for a matching directory.
'gd'
'gdefault' Enables the |:substitute| flag 'g' by default.
*'fe'* 'fenc'+'enc' before Vim 6.0; no longer used.
diff --git a/runtime/doc/develop.txt b/runtime/doc/develop.txt
index 843e23ee54..3262d9dec7 100644
--- a/runtime/doc/develop.txt
+++ b/runtime/doc/develop.txt
@@ -84,12 +84,11 @@ Developer guidelines *dev-guidelines*
PROVIDERS *dev-provider*
-A goal of Nvim is to allow extension of the editor without special knowledge
-in the core. But some Vim components are too tightly coupled; in those cases
-a "provider" hook is exposed.
+A primary goal of Nvim is to allow extension of the editor without special
+knowledge in the core. Some core functions are delegated to "providers"
+implemented as external scripts.
-Consider two examples of integration with external systems that are
-implemented in Vim and are now decoupled from Nvim core as providers:
+Examples:
1. In the Vim source code, clipboard logic accounts for more than 1k lines of
C source code (ui.c), to perform two tasks that are now accomplished with
@@ -101,29 +100,28 @@ implemented in Vim and are now decoupled from Nvim core as providers:
scripting is performed by an external host process implemented in ~2k lines
of Python.
-Ideally we could implement Python and clipboard integration in pure vimscript
-and without touching the C code. But this is infeasible without compromising
-backwards compatibility with Vim; that's where providers help.
+The provider framework invokes VimL from C. It is composed of two functions
+in eval.c:
-The provider framework helps call vimscript from C. It is composed of two
-functions in eval.c:
-
-- eval_call_provider(name, method, arguments): calls provider#(name)#Call
+- eval_call_provider(name, method, arguments): calls provider#{name}#Call
with the method and arguments.
-- eval_has_provider(name): Checks if a provider is implemented. Returns true
- if the provider#(name)#Call function is implemented. Called by |has()|
- (vimscript) to check if features are available.
-
-The provider#(name)#Call function implements integration with an external
-system, because shell commands and |RPC| clients are easier to work with in
-vimscript.
+- eval_has_provider(name): Checks the `g:loaded_{name}_provider` variable
+ which must be set to 2 by the provider script to indicate that it is
+ "enabled and working". Called by |has()| to check if features are available.
For example, the Python provider is implemented by the
-autoload/provider/python.vim script; the provider#python#Call function is only
-defined if a valid external Python host is found. That works well with the
-`has('python')` expression (normally used by Python plugins) because if the
-Python host isn't installed then the plugin will "think" it is running in
-a Vim compiled without the "+python" feature.
+"autoload/provider/python.vim" script, which sets `g:loaded_python_provider`
+to 2 only if a valid external Python host is found. Then `has("python")`
+reflects whether Python support is working.
+
+ *provider-reload*
+Sometimes a GUI or other application may want to force a provider to
+"reload". To reload a provider, undefine its "loaded" flag, then use
+|:runtime| to reload it: >
+
+ :unlet g:loaded_clipboard_provider
+ :runtime autoload/provider/clipboard.vim
+
DOCUMENTATION *dev-doc*
diff --git a/runtime/doc/diff.txt b/runtime/doc/diff.txt
index ab002b4dcb..dcc3035d41 100644
--- a/runtime/doc/diff.txt
+++ b/runtime/doc/diff.txt
@@ -175,7 +175,7 @@ hidden buffers. You can use ":hide" to close a window without unloading the
buffer. If you don't want a buffer to remain used for the diff do ":set
nodiff" before hiding it.
- *:dif* *:diffupdate*
+ *:dif* *:diff* *:diffupdate*
:dif[fupdate][!] Update the diff highlighting and folds.
Vim attempts to keep the differences updated when you make changes to the
@@ -325,7 +325,7 @@ After setting this variable, reload the syntax script: >
FINDING THE DIFFERENCES *diff-diffexpr*
The 'diffexpr' option can be set to use something else than the standard
-"diff" program to compare two files and find the differences.
+"diff" program to compare two files and find the differences. *E959*
When 'diffexpr' is empty, Vim uses this command to find the differences
between file1 and file2: >
diff --git a/runtime/doc/digraph.txt b/runtime/doc/digraph.txt
index 95bc3722d0..b106e625f2 100644
--- a/runtime/doc/digraph.txt
+++ b/runtime/doc/digraph.txt
@@ -50,6 +50,10 @@ conversion to be available, it might fail. For the NUL character you will see
"10". That's because NUL characters are internally represented with a NL
character. When you write the file it will become a NUL character.
+Example: >
+ digraph oe 339
+This defines the "oe" digraph for a character that is number 339 in Unicode.
+
==============================================================================
2. Using digraphs *digraphs-use*
@@ -91,11 +95,14 @@ this, you will have to type <BS> e again. To avoid this don't set the
You may have problems using Vim with characters which have a value above 128.
For example: You insert ue (u-umlaut) and the editor echoes \334 in Insert
-mode. After leaving the Insert mode everything is fine. Note that fmt
-removes all characters with a value above 128 from the text being formatted.
-On some Unix systems this means you have to define the environment-variable
-LC_CTYPE. If you are using csh, then put the following line in your .cshrc: >
- setenv LC_CTYPE iso_8859_1
+mode. After leaving the Insert mode everything is fine. On some Unix systems
+this means you have to define the environment-variable LC_CTYPE. If you are
+using csh, then put the following line in your .cshrc: >
+ setenv LC_CTYPE en_US.utf8
+(or similar for a different language or country). The value must be a valid
+locale on your system, i.e. on Unix-like systems it must be present in the
+output of >
+ locale -a
==============================================================================
3. Default digraphs *digraphs-default*
diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt
index f4d3164dbc..23a65f16e4 100644
--- a/runtime/doc/editing.txt
+++ b/runtime/doc/editing.txt
@@ -555,7 +555,7 @@ You can use the argument list with the following commands, and with the
expression functions |argc()| and |argv()|. These all work on the argument
list of the current window.
- *:ar* *:args*
+ *:ar* *:arg* *:args*
:ar[gs] Print the argument list, with the current file in
square brackets.
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 4dc63763ab..5e8c5151f2 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -69,7 +69,7 @@ To force conversion from String to Number, add zero to it: >
To avoid a leading zero to cause octal conversion, or for using a different
base, use |str2nr()|.
- *TRUE* *FALSE*
+ *TRUE* *FALSE* *Boolean*
For boolean operators Numbers are used. Zero is FALSE, non-zero is TRUE.
You can also use |v:false| and |v:true|. When TRUE is returned from a
function it is the Number one, FALSE is the number zero.
@@ -92,10 +92,11 @@ 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*
-List, Dictionary and Funcref types are not automatically converted.
+|List|, |Dictionary|, |Funcref|, and |Blob| types are not automatically
+converted.
*E805* *E806* *E808*
-When mixing Number and Float the Number is converted to Float. Otherwise
+When mixing Number and Float the Number is converted to Float. Otherwise
there is no automatic conversion of Float. You can use str2float() for String
to Float, printf() for Float to String and float2nr() for Float to Number.
@@ -104,13 +105,14 @@ When expecting a Float a Number can also be used, but nothing else.
*no-type-checking*
You will not get an error if you try to change the type of a variable.
-
+
+
1.2 Function references ~
*Funcref* *E695* *E718*
-A Funcref variable is obtained with the |function()| function or created with
-the lambda expression |expr-lambda|. It can be used in an expression in the
-place of a function name, before the parenthesis around the arguments, to
-invoke the function it refers to. Example: >
+A Funcref variable is obtained with the |function()| function, the |funcref()|
+function or created with the lambda expression |expr-lambda|. It can be used
+in an expression in the place of a function name, before the parenthesis
+around the arguments, to invoke the function it refers to. Example: >
:let Fn = function("MyFunc")
:echo Fn()
@@ -142,14 +144,14 @@ arguments: >
*Partial*
A Funcref optionally binds a Dictionary and/or arguments. This is also called
a Partial. This is created by passing the Dictionary and/or arguments to
-function(). When calling the function the Dictionary and/or arguments will be
-passed to the function. Example: >
+function() or funcref(). When calling the function the Dictionary and/or
+arguments will be passed to the function. Example: >
let Cb = function('Callback', ['foo'], myDict)
- call Cb()
+ call Cb('bar')
This will invoke the function as if using: >
- call myDict.Callback('foo')
+ call myDict.Callback('foo', 'bar')
Note that binding a function to a Dictionary also happens when the function is
a member of the Dictionary: >
@@ -177,7 +179,7 @@ Here "self" will be "myDict", because it was bound explicitly.
1.3 Lists ~
*list* *List* *Lists* *E686*
A List is an ordered sequence of items. An item can be of any type. Items
-can be accessed by their index number. Items can be added and removed at any
+can be accessed by their index number. Items can be added and removed at any
position in the sequence.
@@ -188,7 +190,7 @@ Examples: >
:let mylist = [1, two, 3, "four"]
:let emptylist = []
-An item can be any expression. Using a List for an item creates a
+An item can be any expression. Using a List for an item creates a
List of Lists: >
:let nestlist = [[11, 12], [21, 22], [31, 32]]
@@ -247,7 +249,7 @@ length minus one is used: >
:echo mylist[2:8] " result: [2, 3]
NOTE: mylist[s:e] means using the variable "s:e" as index. Watch out for
-using a single letter variable before the ":". Insert a space when needed:
+using a single letter variable before the ":". Insert a space when needed:
mylist[s : e].
@@ -376,7 +378,7 @@ This works like: >
If all you want to do is modify each item in the list then the |map()|
function will be a simpler method than a for loop.
-Just like the |:let| command, |:for| also accepts a list of variables. This
+Just like the |:let| command, |:for| also accepts a list of variables. This
requires the argument to be a list of lists. >
:for [lnum, col] in [[1, 3], [2, 8], [3, 0]]
: call Doit(lnum, col)
@@ -433,11 +435,11 @@ only appear once. Examples: >
< *E713* *E716* *E717*
A key is always a String. You can use a Number, it will be converted to a
String automatically. Thus the String '4' and the number 4 will find the same
-entry. Note that the String '04' and the Number 04 are different, since the
+entry. Note that the String '04' and the Number 04 are different, since the
Number will be converted to the String '4'. The empty string can be used as a
key.
-A value can be any expression. Using a Dictionary for a value creates a
+A value can be any expression. Using a Dictionary for a value creates a
nested Dictionary: >
:let nestdict = {1: {11: 'a', 12: 'b'}, 2: {21: 'c'}}
@@ -464,7 +466,7 @@ key lookup can be repeated: >
Dictionary to List conversion ~
-You may want to loop over the entries in a dictionary. For this you need to
+You may want to loop over the entries in a dictionary. For this you need to
turn the Dictionary into a List and pass it to |:for|.
Most often you want to loop over the keys, using the |keys()| function: >
@@ -481,7 +483,7 @@ To loop over the values use the |values()| function: >
:endfor
If you want both the key and the value use the |items()| function. It returns
-a List in which each item is a List with two items, the key and the value: >
+a List in which each item is a List with two items, the key and the value: >
:for [key, value] in items(mydict)
: echo key . ': ' . value
:endfor
@@ -531,7 +533,7 @@ This removes all entries from "dict" with a value not matching 'x'.
Dictionary function ~
*Dictionary-function* *self* *E725* *E862*
When a function is defined with the "dict" attribute it can be used in a
-special way with a dictionary. Example: >
+special way with a dictionary. Example: >
:function Mylen() dict
: return len(self.data)
:endfunction
@@ -555,7 +557,7 @@ assigned to a Dictionary in this way: >
:echo mydict.len()
The function will then get a number and the value of dict.len is a |Funcref|
-that references this function. The function can only be used through a
+that references this function. The function can only be used through a
|Funcref|. It will automatically be deleted when there is no |Funcref|
remaining that refers to it.
@@ -815,10 +817,10 @@ values are different: >
"is#"/"isnot#" and "is?"/"isnot?" can be used to match and ignore case.
When comparing a String with a Number, the String is converted to a Number,
-and the comparison is done on Numbers. This means that: >
+and the comparison is done on Numbers. This means that: >
echo 0 == 'x'
1
-because 'x' converted to a Number is zero. However: >
+because 'x' converted to a Number is zero. However: >
echo [0] == ['x']
0
Inside a List or Dictionary this conversion is not used.
@@ -914,7 +916,7 @@ For '+' the number is unchanged.
A String will be converted to a Number first.
-These three can be repeated and mixed. Examples:
+These three can be repeated and mixed. Examples:
!-1 == 0
!!8 == 1
--9 == 9
@@ -948,7 +950,7 @@ compatibility). Use [-1:] to get the last byte.
If expr8 is a |List| then it results the item at index expr1. See |list-index|
for possible index values. If the index is out of range this results in an
-error. Example: >
+error. Example: >
:let item = mylist[-1] " get last item
Generally, if a |List| index is equal to or higher than the length of the
@@ -980,7 +982,7 @@ Examples: >
<
*slice*
If expr8 is a |List| this results in a new |List| with the items indicated by
-the indexes expr1a and expr1b. This works like with a String, as explained
+the indexes expr1a and expr1b. This works like with a String, as explained
just above. Also see |sublist| below. Examples: >
:let l = mylist[:3] " first four items
:let l = mylist[4:4] " List with one item
@@ -1008,8 +1010,9 @@ There must not be white space before or after the dot.
Examples: >
:let dict = {"one": 1, 2: "two"}
- :echo dict.one
- :echo dict .2
+ :echo dict.one " shows "1"
+ :echo dict.2 " shows "two"
+ :echo dict .2 " error because of space before the dot
Note that the dot is also used for String concatenation. To avoid confusion
always put spaces around the dot for String concatenation.
@@ -1040,7 +1043,7 @@ Floating point numbers can be written in two forms:
contain digits.
[-+] means there is an optional plus or minus sign.
{exp} is the exponent, power of 10.
-Only a decimal point is accepted, not a comma. No matter what the current
+Only a decimal point is accepted, not a comma. No matter what the current
locale is.
Examples:
@@ -1129,11 +1132,11 @@ literal-string *literal-string* *E115*
Note that single quotes are used.
-This string is taken as it is. No backslashes are removed or have a special
+This string is taken as it is. No backslashes are removed or have a special
meaning. The only exception is that two quotes stand for one quote.
Single quoted strings are useful for patterns, so that backslashes do not need
-to be doubled. These two commands are equivalent: >
+to be doubled. These two commands are equivalent: >
if a =~ "\\s*"
if a =~ '\s*'
@@ -1159,7 +1162,7 @@ register *expr-register* *@r*
The result is the contents of the named register, as a single string.
Newlines are inserted where required. To get the contents of the unnamed
-register use @" or @@. See |registers| for an explanation of the available
+register use @" or @@. See |registers| for an explanation of the available
registers.
When using the '=' register you get the expression itself, not what it
@@ -1177,6 +1180,13 @@ $VAR environment variable
The String value of any environment variable. When it is not defined, the
result is an empty string.
+
+The functions `getenv()` and `setenv()` can also be used and work for
+environment variables with non-alphanumeric names.
+The function `environ()` can be used to get a Dict with all environment
+variables.
+
+
*expr-env-expand*
Note that there is a difference between using $VAR directly and using
expand("$VAR"). Using it directly will only expand environment variables that
@@ -1321,7 +1331,7 @@ It is deleted when the tab page is closed.
*global-variable* *g:var* *g:*
Inside functions global variables are accessed with "g:". Omitting this will
-access a variable local to a function. But "g:" can also be used in any other
+access a variable local to a function. But "g:" can also be used in any other
place if you like.
*local-variable* *l:var* *l:*
@@ -1407,7 +1417,9 @@ Note that this means that filetype plugins don't get a different set of script
variables for each buffer. Use local buffer variables instead |b:var|.
-Predefined Vim variables: *vim-variable* *v:var* *v:*
+PREDEFINED VIM VARIABLES *vim-variable* *v:var* *v:*
+ *E963*
+Some variables can be set by the user, but the type cannot be changed.
*v:beval_col* *beval_col-variable*
v:beval_col The number of the column, over which the mouse pointer is.
@@ -1463,7 +1475,7 @@ v:cmdarg This variable is used for two purposes:
set before an autocommand event for a file read/write
command is triggered. There is a leading space to make it
possible to append this variable directly after the
- read/write command. Note: The "+cmd" argument isn't
+ read/write command. Note: The "+cmd" argument isn't
included here, because it will be executed anyway.
2. When printing a PostScript file with ":hardcopy" this is
the argument for the ":hardcopy" command. This can be used
@@ -1483,7 +1495,7 @@ v:completed_item
*v:count* *count-variable*
v:count The count given for the last Normal mode command. Can be used
- to get the count before a mapping. Read-only. Example: >
+ to get the count before a mapping. Read-only. Example: >
:map _x :<C-U>echo "the count is " . v:count<CR>
< Note: The <C-U> is required to remove the line range that you
get when typing ':' after a count.
@@ -1505,7 +1517,7 @@ v:ctype The current locale setting for characters of the runtime
See |multi-lang|.
*v:dying* *dying-variable*
-v:dying Normally zero. When a deadly signal is caught it's set to
+v:dying Normally zero. When a deadly signal is caught it's set to
one. When multiple signals are caught the number increases.
Can be used in an autocommand to check if Vim didn't
terminate normally. {only works on Unix}
@@ -1584,7 +1596,7 @@ v:exception The value of the exception most recently caught and not
:try
: throw "oops"
:catch /.*/
- : echo "caught" v:exception
+ : echo "caught " .. v:exception
:endtry
< Output: "caught oops".
@@ -1638,7 +1650,7 @@ v:fname_out The name of the output file. Only valid while
'diffexpr' output of diff
'patchexpr' resulting patched file
(*) When doing conversion for a write command (e.g., ":w
- file") it will be equal to v:fname_in. When doing conversion
+ file") it will be equal to v:fname_in. When doing conversion
for a read command (e.g., ":e file") it will be a temporary
file and different from v:fname_in.
@@ -1787,7 +1799,7 @@ v:prevcount The count given for the last but one Normal mode command.
< Read-only.
*v:profiling* *profiling-variable*
-v:profiling Normally zero. Set to one after using ":profile start".
+v:profiling Normally zero. Set to one after using ":profile start".
See |profiling|.
*v:progname* *progname-variable*
@@ -1867,14 +1879,14 @@ v:swapchoice |SwapExists| autocommands can set this to the selected choice
'd' Delete swapfile
'q' Quit
'a' Abort
- The value should be a single-character string. An empty value
+ The value should be a single-character string. An empty value
results in the user being asked, as would happen when there is
no SwapExists autocommand. The default is empty.
*v:swapcommand* *swapcommand-variable*
v:swapcommand Normal mode command to be executed after a file has been
opened. Can be used for a |SwapExists| autocommand to have
- another Vim open the file and jump to the right place. For
+ another Vim open the file and jump to the right place. For
example, when jumping to a tag the value is ":tag tagname\r".
For ":edit +cmd file" the value is ":cmd\r".
@@ -1917,7 +1929,7 @@ v:this_session Full filename of the last loaded or saved session file.
*v:throwpoint* *throwpoint-variable*
v:throwpoint The point where the exception most recently caught and not
- finished was thrown. Not set when commands are typed. See
+ finished was thrown. Not set when commands are typed. See
also |v:exception| and |throw-variables|.
Example: >
:try
@@ -1935,7 +1947,7 @@ v:true Special value used to put "true" in JSON and msgpack. See
|expr7| when used with numeric operators). Read-only.
*v:val* *val-variable*
-v:val Value of the current item of a |List| or |Dictionary|. Only
+v:val Value of the current item of a |List| or |Dictionary|. Only
valid while evaluating the expression used with |map()| and
|filter()|. Read-only.
@@ -2006,8 +2018,10 @@ atan2({expr}, {expr}) Float arc tangent of {expr1} / {expr2}
browse({save}, {title}, {initdir}, {default})
String put up a file requester
browsedir({title}, {initdir}) String put up a directory requester
+bufadd({name}) Number add a buffer to the buffer list
bufexists({expr}) Number |TRUE| if buffer {expr} exists
buflisted({expr}) Number |TRUE| if buffer {expr} is listed
+bufload({expr}) Number load buffer {expr} if not loaded yet
bufloaded({expr}) Number |TRUE| if buffer {expr} is loaded
bufname({expr}) String Name of the buffer {expr}
bufnr({expr} [, {create}]) Number Number of the buffer {expr}
@@ -2054,6 +2068,7 @@ did_filetype() Number |TRUE| if FileType autocommand event used
diff_filler({lnum}) Number diff filler lines about {lnum}
diff_hlID({lnum}, {col}) Number diff highlighting at {lnum}/{col}
empty({expr}) Number |TRUE| if {expr} is empty
+environ() Dict return environment variables
escape({string}, {chars}) String escape {chars} in {string} with '\'
eval({string}) any evaluate {string} into its value
eventhandler() Number |TRUE| if inside an event handler
@@ -2111,6 +2126,7 @@ getcompletion({pat}, {type} [, {filtered}])
List list of cmdline completion matches
getcurpos() List position of the cursor
getcwd([{winnr} [, {tabnr}]]) String get the current working directory
+getenv({name}) String return environment variable
getfontname([{name}]) String name of font being used
getfperm({fname}) String file permissions of file {fname}
getfsize({fname}) Number size in bytes of file {fname}
@@ -2227,8 +2243,6 @@ msgpackdump({list}) List dump a list of objects to msgpack
msgpackparse({list}) 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}
-option_restore({list}) none restore options saved by option_save()
-option_save({list}) List save options values
nvim_...({args}...) any call nvim |api| functions
or({expr}, {expr}) Number bitwise OR
pathshorten({expr}) String shorten directory names in a path
@@ -2241,6 +2255,7 @@ py3eval({expr}) any evaluate |python3| expression
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}]])
List get list of lines from file {fname}
reg_executing() Number get the executing register name
@@ -2286,9 +2301,13 @@ searchpos({pattern} [, {flags} [, {stopline} [, {timeout}]]])
server2client({clientid}, {string})
Number send reply string
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}
setcharsearch({dict}) Dict set character search from {dict}
setcmdpos({pos}) Number set cursor position in command-line
+setenv({name}, {val}) none set environment variable
setfperm({fname}, {mode} Number set {fname} file permissions to {mode}
setline({lnum}, {line}) Number set line {lnum} to {line}
setloclist({nr}, {list}[, {action}[, {what}]])
@@ -2473,7 +2492,7 @@ append({lnum}, {text}) *append()*
the current buffer.
{lnum} can be zero to insert a line before the first one.
Returns 1 for failure ({lnum} out of range or out of memory),
- 0 for success. Example: >
+ 0 for success. Example: >
:let failed = append(line('$'), "# THE END")
:let failed = append(0, ["Chapter 1", "the beginning"])
<
@@ -2569,9 +2588,9 @@ assert_false({actual} [, {msg}]) *assert_false()*
"Expected False but got {actual}" is produced.
assert_inrange({lower}, {upper}, {actual} [, {msg}]) *assert_inrange()*
- This asserts number values. When {actual} is lower than
- {lower} or higher than {upper} an error message is added to
- |v:errors|.
+ This asserts number and |Float| values. When {actual} is lower
+ than {lower} or higher than {upper} an error message is added
+ to |v:errors|. Also see |assert-return|.
When {msg} is omitted an error in the form
"Expected range {lower} - {upper}, but got {actual}" is
produced.
@@ -2676,6 +2695,14 @@ browsedir({title}, {initdir})
When the "Cancel" button is hit, something went wrong, or
browsing is not possible, an empty string is returned.
+bufadd({name}) *bufadd()*
+ Add a buffer to the buffer list with {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.
+
bufexists({expr}) *bufexists()*
The result is a Number, which is |TRUE| if a buffer called
{expr} exists.
@@ -2703,6 +2730,15 @@ buflisted({expr}) *buflisted()*
{expr} exists and is listed (has the 'buflisted' option set).
The {expr} argument is used like with |bufexists()|.
+bufload({expr}) *bufload()*
+ Ensure the buffer {expr} 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()|.
+
bufloaded({expr}) *bufloaded()*
The result is a Number, which is |TRUE| if a buffer called
{expr} exists and is loaded (shown in a window or hidden).
@@ -2714,7 +2750,7 @@ bufname({expr}) *bufname()*
If {expr} 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
- with the buffer names. This is always done like 'magic' is
+ 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.
"" or "%" can be used for the current buffer, "#" for the
@@ -2764,7 +2800,7 @@ bufwinid({expr}) *bufwinid()*
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
+ see |bufname()| above. If buffer {expr} doesn't exist or
there is no such window, -1 is returned. Example: >
echo "A window containing buffer 1 is " . (bufwinnr(1))
@@ -2921,7 +2957,7 @@ col({expr}) The result is a Number, which is the byte index of the column
col("$") length of cursor line plus one
col("'t") column of mark t
col("'" . markname) column of mark markname
-< The first column is 1. 0 is returned for an error.
+< The first column is 1. 0 is returned for an error.
For an uppercase mark the column may actually be in another
buffer.
For the cursor position, when 'virtualedit' is active, the
@@ -2968,7 +3004,7 @@ complete_add({expr}) *complete_add()*
Returns 0 for failure (empty string or out of memory),
1 when the match was added, 2 when the match was already in
the list.
- See |complete-functions| for an explanation of {expr}. It is
+ See |complete-functions| for an explanation of {expr}. It is
the same as one item in the list that 'omnifunc' would return.
complete_check() *complete_check()*
@@ -2985,7 +3021,7 @@ complete_info([{what}])
completion. See |ins-completion|.
The items are:
mode Current completion mode name string.
- See |completion_info_mode| for the values.
+ See |complete_info_mode| for the values.
pum_visible |TRUE| if popup menu is visible.
See |pumvisible()|.
items List of completion matches. Each item is a
@@ -3075,19 +3111,20 @@ confirm({msg} [, {choices} [, {default} [, {type}]]])
:endif
< In a GUI dialog, buttons are used. The layout of the buttons
depends on the 'v' flag in 'guioptions'. If it is included,
- the buttons are always put vertically. Otherwise, confirm()
+ the buttons are always put vertically. Otherwise, confirm()
tries to put the buttons in one horizontal line. If they
don't fit, a vertical layout is used anyway. For some systems
the horizontal layout is always used.
*copy()*
-copy({expr}) Make a copy of {expr}. For Numbers and Strings this isn't
+copy({expr}) Make a copy of {expr}. For Numbers and Strings this isn't
different from using {expr} directly.
When {expr} is a |List| a shallow copy is created. This means
that the original |List| can be changed without changing the
copy, and vice versa. But the items are identical, thus
- changing an item changes the contents of both |Lists|. Also
- see |deepcopy()|.
+ changing an item changes the contents of both |Lists|.
+ A |Dictionary| is copied in a similar way as a |List|.
+ Also see |deepcopy()|.
cos({expr}) *cos()*
Return the cosine of {expr}, measured in radians, as a |Float|.
@@ -3195,7 +3232,7 @@ cursor({list})
deepcopy({expr}[, {noref}]) *deepcopy()* *E698*
- Make a copy of {expr}. For Numbers and Strings this isn't
+ Make a copy of {expr}. For Numbers and Strings this isn't
different from using {expr} directly.
When {expr} is a |List| a full copy is created. This means
that the original |List| can be changed without changing the
@@ -3317,6 +3354,14 @@ diff_hlID({lnum}, {col}) *diff_hlID()*
The highlight ID can be used with |synIDattr()| to obtain
syntax information about the highlighting.
+environ() *environ()*
+ Return all of environment variables as dictionary. You can
+ check if an environment variable exists like this: >
+ :echo has_key(environ(), 'HOME')
+< Note that the variable name may be CamelCase; to ignore case
+ use this: >
+ :echo index(keys(environ()), 'HOME', 0, 1) != -1
+
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
@@ -3352,10 +3397,10 @@ executable({expr}) *executable()*
searchpath for programs. *PATHEXT*
On Windows the ".exe", ".bat", etc. can
optionally be included. Then the extensions in $PATHEXT are
- tried. Thus if "foo.exe" does not exist, "foo.exe.bat" can be
- found. If $PATHEXT is not set then ".exe;.com;.bat;.cmd" is
+ tried. Thus if "foo.exe" does not exist, "foo.exe.bat" can be
+ found. If $PATHEXT is not set then ".exe;.com;.bat;.cmd" is
used. A dot by itself can be used in $PATHEXT to try using
- the name without an extension. When 'shell' looks like a
+ the name without an extension. When 'shell' looks like a
Unix shell, then the name is also tried without adding an
extension.
On Windows it only checks if the file exists and
@@ -3418,7 +3463,7 @@ exists({expr}) The result is a Number, which is |TRUE| if {expr} is
|user-functions|). Also works for a
variable that is a Funcref.
varname internal variable (see
- |internal-variables|). Also works
+ |internal-variables|). Also works
for |curly-braces-names|, |Dictionary|
entries, |List| items, etc. Beware
that evaluating an index may cause an
@@ -3503,7 +3548,7 @@ expand({expr} [, {nosuf} [, {list}]]) *expand()*
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
+ If the expansion fails, the result is an empty string. A name
for a non-existing file is not included, unless {expr} does
not start with '%', '#' or '<', see below.
@@ -3567,7 +3612,7 @@ expand({expr} [, {nosuf} [, {list}]]) *expand()*
slow, because a shell may be used to do the expansion. See
|expr-env-expand|.
The expanded variable is still handled like a list of file
- names. When an environment variable cannot be expanded, it is
+ names. When an environment variable cannot be expanded, it is
left unchanged. Thus ":echo expand('$FOOBAR')" results in
"$FOOBAR".
@@ -3590,7 +3635,7 @@ extend({expr1}, {expr2} [, {expr3}]) *extend()*
items copied is equal to the original length of the List.
E.g., when {expr3} is 1 you get N new copies of the first item
(where N is the original length of the List).
- Use |add()| to concatenate one item to a list. To concatenate
+ Use |add()| to concatenate one item to a list. To concatenate
two lists into a new list use the + operator: >
:let newlist = [1, 2, 3] + [4, 5]
<
@@ -3790,7 +3835,7 @@ fmod({expr1}, {expr2}) *fmod()*
fnameescape({string}) *fnameescape()*
- Escape {string} for use as file name command argument. All
+ Escape {string} for use as file name command argument. All
characters that have a special meaning, such as '%' and '|'
are escaped with a backslash.
For most systems the characters escaped are
@@ -3827,7 +3872,7 @@ foldclosedend({lnum}) *foldclosedend()*
foldlevel({lnum}) *foldlevel()*
The result is a Number, which is the foldlevel of line {lnum}
- in the current buffer. For nested folds the deepest level is
+ in the current buffer. For nested folds the deepest level is
returned. If there is no fold at line {lnum}, zero is
returned. It doesn't matter if the folds are open or closed.
When used while updating folds (from 'foldexpr') -1 is
@@ -3842,7 +3887,7 @@ foldtext() Returns a String, to be displayed for a closed fold. This is
|v:foldstart|, |v:foldend| and |v:folddashes| variables.
The returned string looks like this: >
+-- 45 lines: abcdef
-< The number of leading dashes depends on the foldlevel. The
+< The number of leading dashes depends on the foldlevel. The
"45" is the number of lines in the fold. "abcdef" is the text
in the first non-blank line of the fold. Leading white space,
"//" or "/*" and the text from the 'foldmarker' and
@@ -3861,7 +3906,7 @@ foldtextresult({lnum}) *foldtextresult()*
Useful when exporting folded text, e.g., to HTML.
*foreground()*
-foreground() Move the Vim window to the foreground. Useful when sent from
+foreground() Move the Vim window to the foreground. Useful when sent from
a client to a Vim server. |remote_send()|
On Win32 systems this might not work, the OS does not always
allow a window to bring itself to the foreground. Use
@@ -3956,7 +4001,10 @@ get({list}, {idx} [, {default}]) *get()*
get({dict}, {key} [, {default}])
Get item with key {key} from |Dictionary| {dict}. When this
item is not available return {default}. Return zero when
- {default} is omitted.
+ {default} is omitted. Useful example: >
+ let val = get(g:, 'var_name', 'default')
+< This gets the value of g:var_name if it exists, and uses
+ 'default' when it does not exist.
get({func}, {what})
Get item {what} from Funcref {func}. Possible values for
{what} are:
@@ -4163,7 +4211,7 @@ getcharmod() *getcharmod()*
96 mouse quadruple click (== 32 + 64)
128 command (Macintosh only)
Only the modifiers that have not been included in the
- character itself are obtained. Thus Shift-a results in "A"
+ character itself are obtained. Thus Shift-a results in "A"
without a modifier.
getcharsearch() *getcharsearch()*
@@ -4303,14 +4351,11 @@ getcwd([{winnr}[, {tabnr}]]) *getcwd()*
< If {winnr} is -1 it is ignored, only the tab is resolved.
{winnr} can be the window number or the |window-ID|.
-
-getfsize({fname}) *getfsize()*
- The result is a Number, which is the size in bytes of the
- given file {fname}.
- If {fname} is a directory, 0 is returned.
- If the file {fname} can't be found, -1 is returned.
- If the size of {fname} is too big to fit in a Number then -2
- is returned.
+getenv({name}) *getenv()*
+ Return the value of environment variable {name}.
+ 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|.
getfontname([{name}]) *getfontname()*
Without an argument returns the name of the normal font being
@@ -4341,6 +4386,14 @@ getfperm({fname}) *getfperm()*
For setting permissions use |setfperm()|.
+getfsize({fname}) *getfsize()*
+ The result is a Number, which is the size in bytes of the
+ given file {fname}.
+ If {fname} is a directory, 0 is returned.
+ If the file {fname} can't be found, -1 is returned.
+ If the size of {fname} is too big to fit in a Number then -2
+ is returned.
+
getftime({fname}) *getftime()*
The result is a Number, which is the last modification time of
the given file {fname}. The value is measured as seconds
@@ -4606,7 +4659,7 @@ gettabinfo([{arg}]) *gettabinfo()*
tabnr tab page number.
variables a reference to the dictionary with
tabpage-local variables
- windows List of |window-ID|s in the tag page.
+ windows List of |window-ID|s in the tab page.
gettabvar({tabnr}, {varname} [, {def}]) *gettabvar()*
Get the value of a tab-local variable {varname} in tab page
@@ -4674,7 +4727,7 @@ gettagstack([{nr}]) *gettagstack()*
getwinpos([{timeout}]) *getwinpos()*
The result is a list with two numbers, the result of
- getwinposx() and getwinposy() combined:
+ getwinposx() and getwinposy() combined:
[x-pos, y-pos]
{timeout} can be used to specify how long to wait in msec for
a response from the terminal. When omitted 100 msec is used.
@@ -4687,7 +4740,7 @@ getwinposx() The result is a Number, which is the X coordinate in pixels of
*getwinposy()*
getwinposy() The result is a Number, which is the Y coordinate in pixels of
- the top of the GUI Vim window. The result will be -1 if the
+ the top of the GUI Vim window. The result will be -1 if the
information is not available.
The value can be used with `:winpos`.
@@ -4707,6 +4760,7 @@ getwininfo([{winid}]) *getwininfo()*
height window height (excluding winbar)
loclist 1 if showing a location list
quickfix 1 if quickfix or location list window
+ terminal 1 if a terminal window
tabnr tab page number
topline first displayed buffer line
variables a reference to the dictionary with
@@ -4743,6 +4797,9 @@ glob({expr} [, {nosuf} [, {list} [, {alllinks}]]]) *glob()*
If the expansion fails, the result is an empty String or List.
+ You can also use |readdir()| if you need to do complicated
+ things, such as limiting the number of matches.
+
A name for a non-existing file is not included. A symbolic
link is only included if it points to an existing file.
However, when the {alllinks} argument is present and it is
@@ -4753,7 +4810,7 @@ glob({expr} [, {nosuf} [, {list} [, {alllinks}]]]) *glob()*
:let tagfiles = glob("`find . -name tags -print`")
:let &tags = substitute(tagfiles, "\n", ",", "g")
< The result of the program inside the backticks should be one
- item per line. Spaces inside an item are allowed.
+ item per line. Spaces inside an item are allowed.
See |expand()| for expanding special Vim variables. See
|system()| for getting the raw output of an external command.
@@ -4768,7 +4825,7 @@ glob2regpat({expr}) *glob2regpat()*
< When {expr} 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 patch separator.
+ a backslash usually means a path separator.
*globpath()*
globpath({path}, {expr} [, {nosuf} [, {list} [, {allinks}]]])
@@ -4890,7 +4947,7 @@ hasmapto({what} [, {mode} [, {abbr}]]) *hasmapto()*
When {mode} is omitted, "nvo" is used.
This function is useful to check if a mapping already exists
- to a function in a Vim script. Example: >
+ to a function in a Vim script. Example: >
:if !hasmapto('\ABCdoit')
: map <Leader>d \ABCdoit
:endif
@@ -4985,7 +5042,7 @@ hlID({name}) The result is a Number, which is the ID of the highlight group
with name {name}. When the highlight group doesn't exist,
zero is returned.
This can be used to retrieve information about the highlight
- group. For example, to get the background color of the
+ group. For example, to get the background color of the
"Comment" group: >
:echo synIDattr(synIDtrans(hlID("Comment")), "bg")
@@ -5008,7 +5065,6 @@ iconv({expr}, {from}, {to}) *iconv()*
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.
- {only available when compiled with the |+multi_byte| feature}
*indent()*
indent({lnum}) The result is a Number, which is indent of line {lnum} in the
@@ -5055,7 +5111,7 @@ input({opts})
The highlighting set with |:echohl| is used for the prompt.
The input is entered just like a command-line, with the same
- editing commands and mappings. There is a separate history
+ editing commands and mappings. There is a separate history
for lines typed for input().
Example: >
:if input("Coffee or beer? ") == "beer"
@@ -5069,9 +5125,9 @@ input({opts})
< The optional {completion} argument specifies the type of
completion supported for the input. Without it completion is
- not performed. The supported completion types are the same as
+ not performed. The supported completion types are the same as
that can be supplied to a user-defined command using the
- "-complete=" argument. Refer to |:command-completion| for
+ "-complete=" argument. Refer to |:command-completion| for
more information. Example: >
let fname = input("File: ", "", "file")
@@ -5151,12 +5207,12 @@ inputlist({textlist}) *inputlist()*
displayed, one string per line. The user will be prompted to
enter a number, which is returned.
The user can also select an item by clicking on it with the
- mouse. For the first string 0 is returned. When clicking
+ mouse. For the first string 0 is returned. When clicking
above the first item a negative number is returned. When
clicking on the prompt one more than the length of {textlist}
is returned.
Make sure {textlist} has less than 'lines' entries, otherwise
- it won't work. It's a good idea to put the entry number at
+ it won't work. It's a good idea to put the entry number at
the start of the string. And put a prompt in the first item.
Example: >
let color = inputlist(['Select color:', '1. red',
@@ -5190,7 +5246,7 @@ inputsecret({prompt} [, {text}]) *inputsecret()*
insert({list}, {item} [, {idx}]) *insert()*
Insert {item} at the start of |List| {list}.
If {idx} is specified insert {item} before the item with index
- {idx}. If {idx} is zero it goes before the first item, just
+ {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: >
@@ -5328,10 +5384,12 @@ jobwait({ids}[, {timeout}]) *jobwait()*
Wait for a set of jobs to complete.
{ids} is a list of |job-id|s to wait for.
- {timeout} is the maximum number of milliseconds to wait.
- {timeout} of zero can be used to check if a job-id is valid,
- without waiting.
+ {timeout} is the maximum waiting time in milliseconds, -1
+ means forever.
+ Timeout of 0 can be used to check the status of a job: >
+ let running = jobwait([{job-id}], 0)[0] == -1
+<
During jobwait() callbacks for jobs not in the {ids} list may
be invoked. The screen will not redraw unless |:redraw| is
invoked by a callback.
@@ -5392,6 +5450,7 @@ len({expr}) The result is a Number, which is the length of the argument.
used, as with |strlen()|.
When {expr} is a |List| the number of items in the |List| is
returned.
+ When {expr} is a |Blob| the number of bytes is returned.
When {expr} is a |Dictionary| the number of entries in the
|Dictionary| is returned.
Otherwise an error is given.
@@ -5437,8 +5496,6 @@ libcall({libname}, {funcname}, {argument})
the DLL is not in the usual places.
For Unix: When compiling your own plugins, remember that the
object code must be compiled as position-independent ('PIC').
- {only in Win32 and some Unix versions, when the |+libcall|
- feature is present}
Examples: >
:echo libcall("libc.so", "getenv", "HOME")
<
@@ -5446,8 +5503,6 @@ libcall({libname}, {funcname}, {argument})
libcallnr({libname}, {funcname}, {argument})
Just like |libcall()|, but used for a function that returns an
int instead of a string.
- {only in Win32 on some Unix versions, when the |+libcall|
- feature is present}
Examples: >
:echo libcallnr("/usr/lib/libc.so", "getpid", "")
:call libcallnr("libc.so", "printf", "Hello World!\n")
@@ -5476,13 +5531,6 @@ line({expr}) The result is a Number, which is the line number of the file
line(".") line number of the cursor
line("'t") line number of mark t
line("'" . marker) line number of mark marker
-< *last-position-jump*
- This autocommand jumps to the last known position in a file
- just after opening it, if the '" mark is set: >
- :au BufReadPost *
- \ if line("'\"") > 1 && line("'\"") <= line("$") && &ft !~# 'commit'
- \ | exe "normal! g`\""
- \ | endif
line2byte({lnum}) *line2byte()*
Return the byte count from the start of the buffer for line
@@ -5532,7 +5580,7 @@ log10({expr}) *log10()*
luaeval({expr}[, {expr}])
Evaluate Lua expression {expr} and return its result converted
- to Vim data structures. See |lua-luaeval| for more details.
+ to Vim data structures. See |lua-eval| for more details.
map({expr1}, {expr2}) *map()*
{expr1} must be a |List| or a |Dictionary|.
@@ -5671,7 +5719,7 @@ match({expr}, {pat} [, {start} [, {count}]]) *match()*
first item where {pat} matches. Each item is used as a
String, |Lists| and |Dictionaries| are used as echoed.
- Otherwise, {expr} is used as a String. The result is a
+ Otherwise, {expr} is used as a String. The result is a
Number, which gives the index (byte offset) in {expr} where
{pat} matches.
@@ -5684,7 +5732,7 @@ match({expr}, {pat} [, {start} [, {count}]]) *match()*
:echo match([1, 'x'], '\a') " results in 1
< See |string-match| for how {pat} is used.
*strpbrk()*
- Vim doesn't have a strpbrk() function. But you can do: >
+ Vim doesn't have a strpbrk() function. But you can do: >
:let sepidx = match(line, '[.,;: \t]')
< *strcasestr()*
Vim doesn't have a strcasestr() function. But you can add
@@ -5721,7 +5769,7 @@ match({expr}, {pat} [, {start} [, {count}]]) *match()*
See |pattern| for the patterns that are accepted.
The 'ignorecase' option is used to set the ignore-caseness of
- the pattern. 'smartcase' is NOT used. The matching is always
+ the pattern. 'smartcase' is NOT used. The matching is always
done like 'magic' is set and 'cpoptions' is empty.
*matchadd()* *E798* *E799* *E801* *E957*
@@ -5737,7 +5785,7 @@ matchadd({group}, {pattern}[, {priority}[, {id} [, {dict}]]])
concealed.
The optional {priority} argument assigns a priority to the
- match. A match with a high priority will have its
+ match. A match with a high priority will have its
highlighting overrule that of a match with a lower priority.
A priority is specified as an integer (negative numbers are no
exception). If the {priority} argument is not specified, the
@@ -5776,7 +5824,7 @@ matchadd({group}, {pattern}[, {priority}[, {id} [, {dict}]]])
:call matchdelete(m)
< A list of matches defined by |matchadd()| and |:match| are
- available from |getmatches()|. All matches can be deleted in
+ available from |getmatches()|. All matches can be deleted in
one operation by |clearmatches()|.
*matchaddpos()*
@@ -5964,7 +6012,7 @@ mkdir({name} [, {path} [, {prot}]])
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
+ the user readable for others). Use 0700 to make it unreadable
for others.
{prot} is applied for all parts of {name}. Thus if you create
@@ -6245,7 +6293,7 @@ printf({fmt}, {expr1} ...) *printf()*
number produced by a signed conversion (d).
+ A sign must always be placed before a number
- produced by a signed conversion. A + overrides
+ produced by a signed conversion. A + overrides
a space if both are used.
field-width
@@ -6271,7 +6319,7 @@ printf({fmt}, {expr1} ...) *printf()*
A field width or precision, or both, may be indicated by an
asterisk '*' instead of a digit string. In this case, a
- Number argument supplies the field width or precision. A
+ Number argument supplies the field width or precision. A
negative field width is treated as a left adjustment flag
followed by a positive field width; a negative precision is
treated as though it were missing. Example: >
@@ -6319,8 +6367,7 @@ printf({fmt}, {expr1} ...) *printf()*
*printf-S*
S The text of the String argument is used. If a
precision is specified, no more display cells than the
- number specified are used. Without the |+multi_byte|
- feature works just like 's'.
+ number specified are used.
*printf-f* *E807*
f F The Float argument is converted into a string of the
@@ -6383,7 +6430,6 @@ py3eval({expr}) *py3eval()*
Lists are represented as Vim |List| type.
Dictionaries are represented as Vim |Dictionary| type with
keys converted to strings.
- {only available when compiled with the |+python3| feature}
*E858* *E859*
pyeval({expr}) *pyeval()*
@@ -6394,7 +6440,6 @@ pyeval({expr}) *pyeval()*
Lists are represented as Vim |List| type.
Dictionaries are represented as Vim |Dictionary| type,
non-string keys result in error.
- {only available when compiled with the |+python| feature}
pyxeval({expr}) *pyxeval()*
Evaluate Python expression {expr} and return its result
@@ -6452,6 +6497,17 @@ readfile({fname} [, {binary} [, {max}]])
the result is an empty list.
Also see |writefile()|.
+ *readdir()*
+readdir({directory} [, {expr}])
+ Return a list with file and directory names in {directory}.
+ You can also use |glob()| if you don't need to do complicated
+ things, such as limiting the number of matches.
+
+ When {expr} is omitted all entries are included.
+ When {expr} is given, it is evaluated to check what to do:
+ If {expr} results in -1 then no further entries will
+ be handled.
+
reg_executing() *reg_executing()*
Returns the single letter name of the register being executed.
Returns an empty string when no register is being executed.
@@ -6505,7 +6561,7 @@ reltimestr({time}) *reltimestr()*
*remote_expr()* *E449*
remote_expr({server}, {string} [, {idvar} [, {timeout}]])
- Send the {string} to {server}. The string is sent as an
+ Send the {string} to {server}. The string is sent as an
expression and the result is returned after evaluation.
The result must be a String or a |List|. A |List| is turned
into a String by joining the items with a line break in
@@ -6517,7 +6573,6 @@ remote_expr({server}, {string} [, {idvar} [, {timeout}]])
seconds. Otherwise a timeout of 600 seconds is used.
See also |clientserver| |RemoteReply|.
This function is not available in the |sandbox|.
- {only available when compiled with the |+clientserver| feature}
Note: Any errors will cause a local error message to be issued
and the result will be the empty string.
@@ -6547,13 +6602,12 @@ remote_foreground({server}) *remote_foreground()*
remote_peek({serverid} [, {retvar}]) *remote_peek()*
Returns a positive number if there are available strings
from {serverid}. Copies any reply string into the variable
- {retvar} if specified. {retvar} must be a string with the
+ {retvar} if specified. {retvar} must be a string with the
name of a variable.
Returns zero if none are available.
Returns -1 if something is wrong.
See also |clientserver|.
This function is not available in the |sandbox|.
- {only available when compiled with the |+clientserver| feature}
Examples: >
:let repl = ""
:echo "PEEK: ".remote_peek(id, "repl").": ".repl
@@ -6564,13 +6618,12 @@ remote_read({serverid}, [{timeout}]) *remote_read()*
reply is available.
See also |clientserver|.
This function is not available in the |sandbox|.
- {only available when compiled with the |+clientserver| feature}
Example: >
:echo remote_read(id)
<
*remote_send()* *E241*
remote_send({server}, {string} [, {idvar}])
- Send the {string} to {server}. The string is sent as input
+ Send the {string} to {server}. The string is sent as input
keys and the function returns immediately. At the Vim server
the keys are not mapped |:map|.
If {idvar} is present, it is taken as the name of a variable
@@ -6578,7 +6631,6 @@ remote_send({server}, {string} [, {idvar}])
there.
See also |clientserver| |RemoteReply|.
This function is not available in the |sandbox|.
- {only available when compiled with the |+clientserver| feature}
Note: Any errors will be reported in the server and may mess
up the display.
@@ -6595,7 +6647,6 @@ remote_send({server}, {string} [, {idvar}])
remote_startserver({name})
Become the server {name}. This fails if already running as a
server, when |v:servername| is not empty.
- {only available when compiled with the |+clientserver| feature}
remove({list}, {idx} [, {end}]) *remove()*
Without {end}: Remove the item at {idx} from |List| {list} and
@@ -6609,7 +6660,8 @@ remove({list}, {idx} [, {end}]) *remove()*
:echo "last item: " . remove(mylist, -1)
:call remove(mylist, 0, 9)
remove({dict}, {key})
- Remove the entry from {dict} with key {key}. Example: >
+ Remove the entry from {dict} with key {key} and return it.
+ Example: >
:echo "removed " . remove(dict, "one")
< If there is no {key} in {dict} this is an error.
@@ -6629,7 +6681,7 @@ repeat({expr}, {count}) *repeat()*
:let separator = repeat('-', 80)
< When {count} is zero or negative the result is empty.
When {expr} is a |List| the result is {expr} concatenated
- {count} times. Example: >
+ {count} times. Example: >
:let longlist = repeat(['a', 'b'], 3)
< Results in ['a', 'b', 'a', 'b', 'a', 'b'].
@@ -6648,7 +6700,7 @@ 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
+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: >
:let revlist = reverse(copy(mylist))
@@ -6684,11 +6736,6 @@ rpcstart({prog}[, {argv}]) *rpcstart()*
< with >
:let id = jobstart(['prog', 'arg1', 'arg2'], {'rpc': v:true})
-rpcstop({channel}) *rpcstop()*
- Deprecated. Instead use |jobstop()| to stop any job, and
- chanclose(id, "rpc") to close RPC communication without
- stopping the job. Use chanclose(id) to close any socket.
-
screenattr({row}, {col}) *screenattr()*
Like |screenchar()|, but return the attribute. This is a rather
arbitrary number that can only be used to compare to the
@@ -6767,11 +6814,10 @@ search({pattern} [, {flags} [, {stopline} [, {timeout}]]]) *search()*
A zero value is equal to not giving the argument.
When the {timeout} argument is given the search stops when
- more than this many milliseconds have passed. Thus when
+ more than this many milliseconds have passed. Thus when
{timeout} is 500 the search stops after half a second.
The value must not be negative. A zero value is like not
giving the argument.
- {only available when compiled with the |+reltime| feature}
*search()-sub-match*
With the 'p' flag the returned value is one more than the
@@ -6886,7 +6932,7 @@ searchpair({start}, {middle}, {end} [, {flags} [, {skip}
< When starting at the "if 2", with the cursor on the "i", and
searching forwards, the "endif 2" is found. When starting on
the character just before the "if 2", the "endif 1" will be
- found. That's because the "if 2" will be found first, and
+ found. That's because the "if 2" will be found first, and
then this is considered to be a nested if/endif from "if 2" to
"endif 2".
When searching backwards and {end} is more than one character,
@@ -6947,7 +6993,6 @@ searchpos({pattern} [, {flags} [, {stopline} [, {timeout}]]]) *searchpos()*
server2client({clientid}, {string}) *server2client()*
Send a reply string to {clientid}. The most recent {clientid}
that sent a string can be retrieved with expand("<client>").
- {only available when compiled with the |+clientserver| feature}
Note:
This id has to be stored before the next command can be
received. I.e. before returning from the received command and
@@ -6996,6 +7041,19 @@ 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}. To insert
+ lines use |append()|.
+
+ For the use of {expr}, see |bufname()| above.
+
+ {lnum} is used like with |setline()|.
+ This works like |setline()| for the specified buffer.
+ On success 0 is returned, on failure 1 is returned.
+
+ If {expr} 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
{val}.
@@ -7031,7 +7089,7 @@ setcharsearch({dict}) *setcharsearch()*
setcmdpos({pos}) *setcmdpos()*
Set the cursor position in the command line to byte position
- {pos}. The first position is 1.
+ {pos}. The first position is 1.
Use |getcmdpos()| to obtain the current position.
Only works while editing the command line, thus you must use
|c_CTRL-\_e|, |c_CTRL-R_=| or |c_CTRL-R_CTRL-R| with '='. For
@@ -7044,6 +7102,11 @@ setcmdpos({pos}) *setcmdpos()*
Returns 0 when successful, 1 when not editing the command
line.
+setenv({name}, {val}) *setenv()*
+ Set environment variable {name} to {val}.
+ When {val} is |v:null| the environment variable is deleted.
+ See also |expr-env|.
+
setfperm({fname}, {mode}) *setfperm()* *chmod*
Set the file permissions for {fname} to {mode}.
{mode} must be a string with 9 characters. It is of the form
@@ -7063,13 +7126,19 @@ setfperm({fname}, {mode}) *setfperm()* *chmod*
setline({lnum}, {text}) *setline()*
Set line {lnum} of the current buffer to {text}. To insert
- lines use |append()|.
+ lines use |append()|. To set lines in another buffer use
+ |setbufline()|.
+
{lnum} is used like with |getline()|.
When {lnum} is just below the last line the {text} will be
added as a new line.
+
If this succeeds, 0 is returned. If this fails (most likely
- because {lnum} is invalid) 1 is returned. Example: >
+ because {lnum} is invalid) 1 is returned.
+
+ Example: >
:call setline(5, strftime("%c"))
+
< When {text} is a |List| then line {lnum} and following lines
will be set to the items in the list. Example: >
:call setline(5, ['aaa', 'bbb', 'ccc'])
@@ -7080,7 +7149,7 @@ setline({lnum}, {text}) *setline()*
< Note: The '[ and '] marks are not set.
-setloclist({nr}, {list} [, {action}[, {what}]]) *setloclist()*
+setloclist({nr}, {list}[, {action}[, {what}]]) *setloclist()*
Create or replace or add to the location list for window {nr}.
{nr} can be the window number or the |window-ID|.
When {nr} is zero the current window is used.
@@ -7475,9 +7544,9 @@ sign_getplaced([{expr} [, {dict}]]) *sign_getplaced()*
list of signs placed in that buffer is returned. For the use
of {expr}, see |bufname()|. The optional {dict} can contain
the following entries:
- group select only signs in this group
- id select sign with this identifier
- lnum select signs placed in this line. For the use
+ group select only signs in this group
+ id select sign with this identifier
+ lnum select signs placed in this line. For the use
of {lnum}, see |line()|.
If {group} is '*', then signs in all the groups including the
global group are returned. If {group} is not supplied or is an
@@ -7518,11 +7587,11 @@ sign_getplaced([{expr} [, {dict}]]) *sign_getplaced()*
echo sign_getplaced("eval.c", {'lnum' : 10})
" Get sign with identifier 10 placed in a.py
- echo sign_getplaced("a.py", {'id' : 10'})
+ echo sign_getplaced("a.py", {'id' : 10})
" Get sign with id 20 in group 'g1' placed in a.py
echo sign_getplaced("a.py", {'group' : 'g1',
- \ 'id' : 20'})
+ \ 'id' : 20})
" Get a List of all the placed signs
echo sign_getplaced()
@@ -7607,7 +7676,7 @@ sign_undefine([{name}]) *sign_undefine()*
<
sign_unplace({group} [, {dict}]) *sign_unplace()*
Remove a previously placed sign in one or more buffers. This
- is similar to the |:sign-unplace()| command.
+ is similar to the |:sign-unplace| command.
{group} is the sign group name. To use the global sign group,
use an empty string. If {group} is set to '*', then all the
@@ -7897,7 +7966,8 @@ str2float({expr}) *str2float()*
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".
+ write "1.0e40". The hexadecimal form "0x123" is also
+ accepted, but not others, like binary or octal.
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
@@ -7953,10 +8023,10 @@ strcharpart({src}, {start} [, {len}]) *strcharpart()*
strdisplaywidth({expr} [, {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}.
- When {col} is omitted zero is used. Otherwise it is the
- screen column where to start. This matters for Tab
- characters.
+ String {expr} 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'.
@@ -8134,7 +8204,7 @@ substitute({expr}, {pat}, {sub}, {flags}) *substitute()*
A "~" in {sub} is not replaced with the previous {sub}.
Note that some codes in {sub} have a special meaning
- |sub-replace-special|. For example, to replace something with
+ |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
@@ -8155,9 +8225,9 @@ substitute({expr}, {pat}, {sub}, {flags}) *substitute()*
optional argument. Example: >
:echo substitute(s, '%\(\x\x\)', SubNr, 'g')
< The optional argument is a list which contains the whole
- matched string and up to nine submatches,like what
- |submatch()| returns. Example: >
- :echo substitute(s, '\(\x\x\)', {m -> '0x' . m[1]}, 'g')
+ matched string and up to nine submatches, like what
+ |submatch()| returns. Example: >
+ :echo substitute(s, '%\(\x\x\)', {m -> '0x' . m[1]}, 'g')
swapinfo({fname}) *swapinfo()*
The result is a dictionary, which holds information about the
@@ -8197,7 +8267,7 @@ synID({lnum}, {col}, {trans}) *synID()*
zero.
When {trans} is |TRUE|, transparent items are reduced to the
- item that they reveal. This is useful when wanting to know
+ item that they reveal. This is useful when wanting to know
the effective color. When {trans} is |FALSE|, the transparent
item is returned. This is useful when wanting to know which
syntax item is effective (e.g. inside parens).
@@ -8213,7 +8283,7 @@ synIDattr({synID}, {what} [, {mode}]) *synIDattr()*
syntax ID {synID}. This can be used to obtain information
about a syntax item.
{mode} can be "gui", "cterm" or "term", to get the attributes
- for that mode. When {mode} is omitted, or an invalid value is
+ for that mode. When {mode} is omitted, or an invalid value is
used, the attributes for the currently active highlighting are
used (GUI, cterm or term).
Use synIDtrans() to follow linked highlight groups.
@@ -8442,7 +8512,7 @@ taglist({expr} [, {filename}]) *taglist()*
tempname() *tempname()* *temp-file-name*
The result is a String, which is the name of a file that
- doesn't exist. It can be used for a temporary file. Example: >
+ doesn't exist. It can be used for a temporary file. Example: >
:let tmpfile = tempname()
:exe "redir > " . tmpfile
< For Unix, the file will be in a private directory |tempfile|.
@@ -8534,13 +8604,10 @@ timer_start({time}, {callback} [, {options}])
waiting for input.
{options} is a dictionary. Supported entries:
- "repeat" Number of times to repeat calling the
- callback. -1 means forever. When not present
- the callback will be called once.
+ "repeat" Number of times to repeat the callback.
+ -1 means forever. Default is 1.
If the timer causes an error three times in a
- row the repeat is cancelled. This avoids that
- Vim becomes unusable because of all the error
- messages.
+ row the repeat is cancelled.
Example: >
func MyHandler(timer)
@@ -8548,8 +8615,7 @@ timer_start({time}, {callback} [, {options}])
endfunc
let timer = timer_start(500, 'MyHandler',
\ {'repeat': 3})
-< This will invoke MyHandler() three times at 500 msec
- intervals.
+< This invokes MyHandler() three times at 500 msec intervals.
timer_stop({timer}) *timer_stop()*
Stop a timer. The timer callback will no longer be invoked.
@@ -8704,7 +8770,7 @@ uniq({list} [, {func} [, {dict}]]) *uniq()* *E882*
each item. For the use of {func} and {dict} see |sort()|.
values({dict}) *values()*
- Return a |List| with all the values of {dict}. The |List| is
+ Return a |List| with all the values of {dict}. The |List| is
in arbitrary order.
@@ -8740,7 +8806,7 @@ virtcol({expr}) *virtcol()*
virtcol(".") with text "foo^Lbar", with cursor on the "^L", returns 5
virtcol("$") with text "foo^Lbar", returns 9
virtcol("'t") with text " there", with 't at 'h', returns 6
-< The first column is 1. 0 is returned for an error.
+< The first column is 1. 0 is returned for an error.
A more advanced example that echoes the maximum length of
all lines: >
echo max(map(range(1, line('$')), "virtcol([v:val, '$'])"))
@@ -8784,7 +8850,7 @@ win_getid([{win} [, {tab}]]) *win_getid()*
Get the |window-ID| for the specified window.
When {win} is missing use the current window.
With {win} this is the window number. The top window has
- number 1. Use `win_getid(winnr())` for the current window.
+ number 1.
Without {tab} use the current tab, otherwise the tab with
number {tab}. The first tab has number one.
Return zero if the window cannot be found.
@@ -8867,7 +8933,7 @@ winlayout([{tabnr}]) *winlayout()*
<
*winline()*
winline() The result is a Number, which is the screen line of the cursor
- in the window. This is counting screen lines from the top of
+ in the window. This is counting screen lines from the top of
the window. The first line is one.
If the cursor was moved the view on the file will be updated
first, this may cause a scroll.
@@ -9075,9 +9141,9 @@ functions.
*:fu* *:function* *E128* *E129* *E123*
:fu[nction] List all functions and their arguments.
-:fu[nction] {name} List function {name}.
- {name} can also be a |Dictionary| entry that is a
- |Funcref|: >
+:fu[nction][!] {name} List function {name}, annotated with line numbers
+ unless "!" is given.
+ {name} may be a |Dictionary| |Funcref| entry: >
:function dict.init
:fu[nction] /{pattern} List functions with a name matching {pattern}.
@@ -9110,9 +9176,9 @@ See |:verbose-cmd| for more information.
{name} can also be a |Dictionary| entry that is a
|Funcref|: >
:function dict.init(arg)
-< "dict" must be an existing dictionary. The entry
+< "dict" must be an existing dictionary. The entry
"init" is added if it didn't exist yet. Otherwise [!]
- is required to overwrite an existing function. The
+ is required to overwrite an existing function. The
result is a |Funcref| to a numbered function. The
function can only be used with a |Funcref| and will be
deleted if there are no more references to it.
@@ -9141,7 +9207,7 @@ See |:verbose-cmd| for more information.
abort as soon as an error is detected.
*:func-dict*
When the [dict] argument is added, the function must
- be invoked through an entry in a |Dictionary|. The
+ be invoked through an entry in a |Dictionary|. The
local variable "self" will then be set to the
dictionary. See |Dictionary-function|.
*:func-closure* *E932*
@@ -9220,7 +9286,7 @@ See |:verbose-cmd| for more information.
returns at the outermost ":endtry".
*function-argument* *a:var*
-An argument can be defined by giving its name. In the function this can then
+An argument can be defined by giving its name. In the function this can then
be used as "a:name" ("a:" for argument).
*a:0* *a:1* *a:000* *E740* *...*
Up to 20 arguments can be given, separated by commas. After the named
@@ -9281,7 +9347,7 @@ This function can then be called with: >
*:cal* *:call* *E107* *E117*
:[range]cal[l] {name}([arguments])
Call a function. The name of the function and its arguments
- are as specified with |:function|. Up to 20 arguments can be
+ are as specified with `:function`. Up to 20 arguments can be
used. The returned value is discarded.
Without a range and for functions that accept a range, the
function is called once. When a range is given the cursor is
@@ -9291,7 +9357,7 @@ This function can then be called with: >
itself, the function is executed for each line in the range,
with the cursor in the first column of that line. The cursor
is left at the last line (possibly moved by the last function
- call). The arguments are re-evaluated for each line. Thus
+ call). The arguments are re-evaluated for each line. Thus
this works:
*function-range-example* >
:function Mynumber(arg)
@@ -9335,9 +9401,9 @@ Using an autocommand ~
This is introduced in the user manual, section |41.14|.
The autocommand is useful if you have a plugin that is a long Vim script file.
-You can define the autocommand and quickly quit the script with |:finish|.
-That makes Vim startup faster. The autocommand should then load the same file
-again, setting a variable to skip the |:finish| command.
+You can define the autocommand and quickly quit the script with `:finish`.
+That makes Vim startup faster. The autocommand should then load the same file
+again, setting a variable to skip the `:finish` command.
Use the FuncUndefined autocommand event with a pattern that matches the
function(s) to be defined. Example: >
@@ -9415,7 +9481,7 @@ name. So in the above example, if the variable "adjective" was set to
"adjective" was set to "quiet", then it would be to "my_quiet_variable".
One application for this is to create a set of variables governed by an option
-value. For example, the statement >
+value. For example, the statement >
echo my_{&background}_message
would output the contents of "my_dark_message" or "my_light_message" depending
@@ -9461,7 +9527,7 @@ This does NOT work: >
must be a valid index in that list. For nested list
the index can be repeated.
This cannot be used to add an item to a |List|.
- This cannot be used to set a byte in a String. You
+ 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:]
<
@@ -9510,7 +9576,7 @@ This does NOT work: >
that would match everywhere.
:let @{reg-name} .= {expr1}
- Append {expr1} to register {reg-name}. If the
+ Append {expr1} to register {reg-name}. If the
register was empty it's like setting it to {expr1}.
:let &{option-name} = {expr1} *:let-option* *:let-&*
@@ -9586,7 +9652,7 @@ This does NOT work: >
|List| item.
*E121*
-:let {var-name} .. List the value of variable {var-name}. Multiple
+:let {var-name} .. List the value of variable {var-name}. Multiple
variable names may be given. Special names recognized
here: *E738*
g: global variables
@@ -9628,7 +9694,34 @@ This does NOT work: >
No error message is given for a non-existing
variable, also without !.
If the system does not support deleting an environment
- variable, it is made emtpy.
+ variable, it is made empty.
+
+ *:cons* *:const*
+:cons[t] {var-name} = {expr1}
+:cons[t] [{name1}, {name2}, ...] = {expr1}
+:cons[t] [{name}, ..., ; {lastname}] = {expr1}
+ Similar to |:let|, but additionally lock the variable
+ after setting the value. This is the same as locking
+ the variable with |:lockvar| just after |:let|, thus: >
+ :const x = 1
+< is equivalent to: >
+ :let x = 1
+ :lockvar 1 x
+< This is useful if you want to make sure the variable
+ is not modified.
+ *E995*
+ |:const| does not allow to for changing a variable. >
+ :let x = 1
+ :const x = 2 " Error!
+< *E996*
+ Note that environment variables, option values and
+ register values cannot be used here, since they cannot
+ be locked.
+
+:cons[t]
+:cons[t] {var-name}
+ If no argument is given or only {var-name} is given,
+ the behavior is the same as |:let|.
:lockv[ar][!] [depth] {name} ... *:lockvar* *:lockv*
Lock the internal variable {name}. Locking means that
@@ -9681,7 +9774,7 @@ This does NOT work: >
opposite of |:lockvar|.
-:if {expr1} *:if* *:endif* *:en* *E171* *E579* *E580*
+:if {expr1} *:if* *:end* *:endif* *:en* *E171* *E579* *E580*
:en[dif] Execute the commands until the next matching ":else"
or ":endif" if {expr1} evaluates to non-zero.
@@ -9746,7 +9839,7 @@ This does NOT work: >
: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
+ 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): >
@@ -9965,7 +10058,7 @@ This does NOT work: >
message in the |message-history|. When used in a
script or function the line number will be added.
Spaces are placed between the arguments as with the
- :echo command. When used inside a try conditional,
+ :echo command. When used inside a try conditional,
the message is raised as an error exception instead
(see |try-echoerr|).
Example: >
@@ -10094,14 +10187,14 @@ the finally clause. It is resumed at the ":endtry", so that commands after
the ":endtry" are not executed and the exception might be caught elsewhere,
see |try-nesting|.
When during execution of a catch clause another exception is thrown, the
-remaining lines in that catch clause are not executed. The new exception is
+remaining lines in that catch clause are not executed. The new exception is
not matched against the patterns in any of the ":catch" commands of the same
try conditional and none of its catch clauses is taken. If there is, however,
a finally clause, it is executed, and the exception pends during its
execution. The commands following the ":endtry" are not executed. The new
exception might, however, be caught elsewhere, see |try-nesting|.
When during execution of the finally clause (if present) an exception is
-thrown, the remaining lines in the finally clause are skipped. If the finally
+thrown, the remaining lines in the finally clause are skipped. If the finally
clause has been taken because of an exception from the try block or one of the
catch clauses, the original (pending) exception is discarded. The commands
following the ":endtry" are not executed, and the exception from the finally
@@ -10135,7 +10228,7 @@ catch an exception thrown in its try block or throws a new exception from one
of its catch clauses or its finally clause, the outer try conditional is
checked according to the rules above. If the inner try conditional is in the
try block of the outer try conditional, its catch clauses are checked, but
-otherwise only the finally clause is executed. It does not matter for
+otherwise only the finally clause is executed. It does not matter for
nesting, whether the inner try conditional is directly contained in the outer
one, or whether the outer one sources a script or calls a function containing
the inner try conditional.
@@ -10198,7 +10291,7 @@ executed. >
however displays "in Bar" and throws 4711.
Any other command that takes an expression as argument might also be
-abandoned by an (uncaught) exception during the expression evaluation. The
+abandoned by an (uncaught) exception during the expression evaluation. The
exception is then propagated to the caller of the command.
Example: >
@@ -10382,13 +10475,13 @@ CLEANUP CODE *try-finally*
Scripts often change global settings and restore them at their end. If the
user however interrupts the script by pressing CTRL-C, the settings remain in
-an inconsistent state. The same may happen to you in the development phase of
+an inconsistent state. The same may happen to you in the development phase of
a script when an error occurs or you explicitly throw an exception without
catching it. You can solve these problems by using a try conditional with
a finally clause for restoring the settings. Its execution is guaranteed on
normal control flow, on error, on an explicit ":throw", and on interrupt.
(Note that errors and interrupts from inside the try conditional are converted
-to exceptions. When not caught, they terminate the script after the finally
+to exceptions. When not caught, they terminate the script after the finally
clause has been executed.)
Example: >
@@ -10446,7 +10539,7 @@ This displays "first", "cleanup", "second", "cleanup", and "end". >
:echo Foo() "returned by Foo"
This displays "cleanup" and "4711 returned by Foo". You don't need to add an
-extra ":return" in the finally clause. (Above all, this would override the
+extra ":return" in the finally clause. (Above all, this would override the
return value.)
*except-from-finally*
@@ -10490,7 +10583,7 @@ or >
Vim:{errmsg}
{cmdname} is the name of the command that failed; the second form is used when
-the command name is not known. {errmsg} is the error message usually produced
+the command name is not known. {errmsg} is the error message usually produced
when the error occurs outside try conditionals. It always begins with
a capital "E", followed by a two or three-digit error number, a colon, and
a space.
@@ -10595,7 +10688,7 @@ This works also when a try conditional is active.
CATCHING INTERRUPTS *catch-interrupt*
When there are active try conditionals, an interrupt (CTRL-C) is converted to
-the exception "Vim:Interrupt". You can catch it like every exception. The
+the exception "Vim:Interrupt". You can catch it like every exception. The
script is not terminated, then.
Example: >
@@ -10629,7 +10722,7 @@ script is not terminated, then.
:endwhile
You can interrupt a task here by pressing CTRL-C; the script then asks for
-a new command. If you press CTRL-C at the prompt, the script is terminated.
+a new command. If you press CTRL-C at the prompt, the script is terminated.
For testing what happens when CTRL-C would be pressed on a specific line in
your script, use the debug mode and execute the |>quit| or |>interrupt|
@@ -10786,7 +10879,7 @@ For some commands, the normal action can be replaced by a sequence of
autocommands. Exceptions from that sequence will be catchable by the caller
of the command.
Example: For the ":write" command, the caller cannot know whether the file
-had actually been written when the exception occurred. You need to tell it in
+had actually been written when the exception occurred. You need to tell it in
some way. >
:if !exists("cnt")
@@ -10934,8 +11027,8 @@ or ":endif". On the other hand, errors should be catchable as exceptions
This problem has been solved by converting errors to exceptions and using
immediate abortion (if not suppressed by ":silent!") only when a try
-conditional is active. This is no restriction since an (error) exception can
-be caught only from an active try conditional. If you want an immediate
+conditional is active. This is no restriction since an (error) exception can
+be caught only from an active try conditional. If you want an immediate
termination without catching the error, just use a try conditional without
catch clause. (You can cause cleanup code being executed before termination
by specifying a finally clause.)
@@ -10950,8 +11043,8 @@ conditional of a new script, you might change the control flow of the existing
script on error. You get the immediate abortion on error and can catch the
error in the new script. If however the sourced script suppresses error
messages by using the ":silent!" command (checking for errors by testing
-|v:errmsg| if appropriate), its execution path is not changed. The error is
-not converted to an exception. (See |:silent|.) So the only remaining cause
+|v:errmsg| if appropriate), its execution path is not changed. The error is
+not converted to an exception. (See |:silent|.) So the only remaining cause
where this happens is for scripts that don't care about errors and produce
error messages. You probably won't want to use such code from your new
scripts.
diff --git a/runtime/doc/filetype.txt b/runtime/doc/filetype.txt
index a4a5d6188b..1f7d09ae32 100644
--- a/runtime/doc/filetype.txt
+++ b/runtime/doc/filetype.txt
@@ -579,6 +579,16 @@ To disable this behavior, set the following variable in your vimrc: >
let g:python_recommended_style = 0
+QF QUICKFIX *qf.vim* *ft-qf-plugin*
+
+The "qf" filetype is used for the quickfix window, see |quickfix-window|.
+
+The quickfix filetype plugin includes configuration for displaying the command
+that produced the quickfix list in the |status-line|. To disable this setting,
+configure as follows: >
+ :let g:qf_disable_statusline = 1
+
+
R MARKDOWN *ft-rmd-plugin*
By default ftplugin/html.vim is not sourced. If you want it sourced, add to
@@ -599,6 +609,15 @@ your |vimrc|: >
let rrst_dynamic_comments = 0
+RESTRUCTUREDTEXT *ft-rst-plugin*
+
+The following formatting setting are optionally available: >
+ setlocal expandtab shiftwidth=3 softtabstop=3 tabstop=8
+
+To enable this behavior, set the following variable in your vimrc: >
+ let g:rst_style = 1
+
+
RPM SPEC *ft-spec-plugin*
Since the text for this plugin is rather long it has been put in a separate
diff --git a/runtime/doc/fold.txt b/runtime/doc/fold.txt
index b7d92fb229..f2f6c70b0c 100644
--- a/runtime/doc/fold.txt
+++ b/runtime/doc/fold.txt
@@ -436,7 +436,7 @@ zk Move upwards to the end of the previous fold. A closed fold
EXECUTING COMMANDS ON FOLDS ~
-:[range]foldd[oopen] {cmd} *:foldd* *:folddoopen*
+:[range]foldd[oopen] {cmd} *:foldd* *:folddo* *:folddoopen*
Execute {cmd} on all lines that are not in a closed fold.
When [range] is given, only these lines are used.
Each time {cmd} is executed the cursor is positioned on the
diff --git a/runtime/doc/help.txt b/runtime/doc/help.txt
index 7fcf08e2a1..68e94ef5c5 100644
--- a/runtime/doc/help.txt
+++ b/runtime/doc/help.txt
@@ -9,7 +9,7 @@ Close this window: Use ":q<Enter>".
Jump to a subject: Position the cursor on a tag (e.g. |bars|) and hit CTRL-].
With the mouse: Double-click the left mouse button on a tag, e.g. |bars|.
- Jump back: Type CTRL-T or CTRL-O. Repeat to go further back.
+ Jump back: Type CTRL-O. Repeat to go further back.
Get specific help: It is possible to go directly to whatever you want help
on, by giving an argument to the |:help| command.
@@ -30,13 +30,17 @@ Get specific help: It is possible to go directly to whatever you want help
help entries for "word".
Or use ":helpgrep word". |:helpgrep|
+ Getting started: Do the Vim tutor, a 20 minute interactive training for the
+ basic commands, see |vimtutor|.
+ Read the user manual from start to end: |usr_01.txt|
+
Vim stands for Vi IMproved. Most of Vim was made by Bram Moolenaar, but only
through the help of many others. See |credits|.
------------------------------------------------------------------------------
*doc-file-list* *Q_ct*
BASIC:
|quickref| Overview of the most common commands you will use
-|tutor| 30 minutes training course for beginners
+|tutor| 20 minutes training course for beginners
|copying| About copyrights
|iccf| Helping poor children in Uganda
|sponsor| Sponsor Vim development, become a registered Vim user
@@ -106,7 +110,6 @@ Basic editing ~
|scroll.txt| scrolling the text in the window
|insert.txt| Insert and Replace mode
|change.txt| deleting and replacing text
-|indent.txt| automatic indenting for C and other languages
|undo.txt| Undo and Redo
|repeat.txt| repeating commands, Vim scripts and debugging
|visual.txt| using the Visual mode (selecting a text area)
@@ -119,30 +122,36 @@ Advanced editing ~
|pattern.txt| regexp patterns and search commands
|map.txt| key mapping and abbreviations
|tagsrch.txt| tags and special searches
-|quickfix.txt| commands for a quick edit-compile-fix cycle
|windows.txt| commands for using multiple windows and buffers
|tabpage.txt| commands for using multiple tab pages
-|syntax.txt| syntax highlighting
|spell.txt| spell checking
|diff.txt| working with two to four versions of the same file
|autocmd.txt| automatically executing commands on an event
-|filetype.txt| settings done specifically for a type of file
|eval.txt| expression evaluation, conditional commands
|fold.txt| hide (fold) ranges of lines
Special issues ~
|print.txt| printing
|remote.txt| using Vim as a server or client
+
+Programming language support ~
+|indent.txt| automatic indenting for C and other languages
+|syntax.txt| syntax highlighting
+|textprop.txt| Attaching properties to text for highlighting or other
+|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
+
+Language support ~
|digraph.txt| list of available digraphs
|mbyte.txt| multi-byte text support
|mlang.txt| non-English language support
+|rileft.txt| right-to-left editing mode
|arabic.txt| Arabic language support and editing
|hebrew.txt| Hebrew language support and editing
|russian.txt| Russian language support and editing
-|ft_ada.txt| Ada (the programming language) support
-|ft_rust.txt| Filetype plugin for Rust
-|ft_sql.txt| about the SQL filetype plugin
-|rileft.txt| right-to-left editing mode
GUI ~
|gui.txt| Graphical User Interface (GUI)
diff --git a/runtime/doc/if_lua.txt b/runtime/doc/if_lua.txt
index 8ee5718349..a9b8c5fae8 100644
--- a/runtime/doc/if_lua.txt
+++ b/runtime/doc/if_lua.txt
@@ -189,16 +189,16 @@ To see the LuaJIT version: >
:lua print(jit.version)
<
-:[range]lua << {endmarker}
+:[range]lua << [endmarker]
{script}
{endmarker}
- Execute Lua script {script}.
+ Execute Lua script {script}. Useful for including Lua
+ code in Vim scripts.
-{endmarker} must NOT be preceded by any white space. If {endmarker} is
-omitted from after the "<<", a dot '.' must be used after {script}, like
-for the |:append| and |:insert| commands.
-This form of the |:lua| command is mainly useful for including Lua code
-in Vim scripts.
+The {endmarker} must NOT be preceded by any white space.
+
+If [endmarker] is omitted from after the "<<", a dot '.' must be used after
+{script}, like for the |:append| and |:insert| commands.
Example:
>
@@ -258,8 +258,7 @@ position are restricted when the command is executed in the |sandbox|.
==============================================================================
-luaeval() *lua-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
@@ -366,46 +365,151 @@ VIM.API *lua-api*
`vim.api` exposes the full Nvim |API| as a table of Lua functions.
-For example, to use the "nvim_get_current_line()" API function, call
+Example: to use the "nvim_get_current_line()" API function, call
"vim.api.nvim_get_current_line()": >
print(tostring(vim.api.nvim_get_current_line()))
------------------------------------------------------------------------------
-VIM *lua-util*
+VIM.LOOP *lua-loop*
+
+`vim.loop` exposes all features of the Nvim event-loop. This is a lower-level
+API that provides functionality for networking, filesystem, and process
+management. Try this command to see available functions: >
+
+ :lua print(vim.inspect(vim.loop))
+
+See http://docs.libuv.org for complete documentation.
+See https://github.com/luvit/luv/tree/master/examples for examples.
+
+ *E5560* *lua-loop-callbacks*
+Note: it is not allowed to directly invoke most of the Nvim API from `vim.loop`
+callbacks. This will result in an error: >
+
+ local timer = vim.loop.new_timer()
+ timer:start(1000, 0, function()
+ vim.api.nvim_command('echomsg "test"')
+ end)
+
+The `vim.schedule_wrap` helper can be used to defer the callback until it
+is safe to execute API methods. >
+
+ local timer = vim.loop.new_timer()
+ timer:start(1000, 0, vim.schedule_wrap(function()
+ vim.api.nvim_command('echomsg "test"')
+ end))
-vim.stricmp(a, b) *lua-vim.stricmp*
- Function used for case-insensitive string comparison. Takes two
- string arguments and returns 0, 1 or -1 if strings are equal, a is
- greater then b or a is lesser then b respectively.
+A subset of the API is available in direct luv callbacks ("fast" callbacks),
+most notably |nvim_get_mode()| and |nvim_input()|. It is possible to
+check whether code is running in this context using |vim.in_fast_event()|.
-vim.schedule(callback) *lua-vim.schedule*
- Schedule `callback` to be called soon by the main event loop. This is
- useful in contexts where some functionality is blocked, like an
- autocommand or callback running with |textlock|. Then the scheduled
- callback could invoke this functionality later when it is allowed.
-vim.type_idx *lua-vim.type_idx*
+Example: repeating timer
+ 1. Save this code to a file.
+ 2. Execute it with ":luafile %". >
+
+ -- Create a timer handle (implementation detail: uv_timer_t).
+ local timer = vim.loop.new_timer()
+ local i = 0
+ -- Waits 1000ms, then repeats every 750ms until timer:close().
+ timer:start(1000, 750, function()
+ print('timer invoked! i='..tostring(i))
+ if i > 4 then
+ timer:close() -- Always close handles to avoid leaks.
+ end
+ i = i + 1
+ end)
+ print('sleeping');
+
+
+Example: TCP echo-server *tcp-server*
+ 1. Save this code to a file.
+ 2. Execute it with ":luafile %".
+ 3. Note the port number.
+ 4. Connect from any TCP client (e.g. "nc 0.0.0.0 36795"): >
+
+ local function create_server(host, port, on_connection)
+ local server = vim.loop.new_tcp()
+ server:bind(host, port)
+ server:listen(128, function(err)
+ assert(not err, err) -- Check for errors.
+ local sock = vim.loop.new_tcp()
+ server:accept(sock) -- Accept client connection.
+ on_connection(sock) -- Start reading messages.
+ end)
+ return server
+ end
+ local server = create_server('0.0.0.0', 0, function(sock)
+ sock:read_start(function(err, chunk)
+ assert(not err, err) -- Check for errors.
+ if chunk then
+ sock:write(chunk) -- Echo received messages to the channel.
+ else -- EOF (stream closed).
+ sock:close() -- Always close handles to avoid leaks.
+ end
+ end)
+ end)
+ print('TCP echo-server listening on port: '..server:getsockname().port)
+
+------------------------------------------------------------------------------
+VIM *lua-util*
+
+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()*
+ 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.
+
+ Embedded NUL bytes are treated as terminating the string. Invalid
+ UTF-8 bytes, and embedded surrogates are counted as one code
+ point each. An {index} in the middle of a UTF-8 sequence is rounded
+ upwards to the end of that sequence.
+
+vim.str_byteindex({str}, {index}[, {use_utf16}]) *vim.str_byteindex()*
+ Convert UTF-32 or UTF-16 {index} to byte index. If {use_utf16} is not
+ supplied, it defaults to false (use UTF-32). Returns the byte index.
+
+ Invalid UTF-8 and NUL is treated like by |vim.str_byteindex()|. An {index}
+ in the middle of a UTF-16 sequence is rounded upwards to the end of that
+ sequence.
+
+vim.schedule({callback}) *vim.schedule()*
+ Schedules {callback} to be invoked soon by the main event-loop. Useful
+ to avoid |textlock| or other temporary restrictions.
+
+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 event
+ such as luv callbacks |lua-loop-callbacks|, which can be invoked at
+ any time nvim polls for input. When this returns `false` most API
+ functions are callable, but can be subjected to other restrictions,
+ such as |textlock|.
+
+vim.type_idx *vim.type_idx*
Type index for use in |lua-special-tbl|. Specifying one of the
- values from |lua-vim.types| allows typing the empty table (it is
+ 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 *lua-vim.val_idx*
+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 |lua-vim.type_idx| and |lua-special-tbl|.
+< See also |vim.type_idx| and |lua-special-tbl|.
-vim.types *lua-vim.types*
- Table with possible values for |lua-vim.type_idx|. Contains two sets
- of key-value pairs: first maps possible values for |lua-vim.type_idx|
+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 |lua-vim.type_idx|. Currently contains pairs for `float`,
+ 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`,
diff --git a/runtime/doc/if_pyth.txt b/runtime/doc/if_pyth.txt
index ac725a9b5d..ed3bdcf277 100644
--- a/runtime/doc/if_pyth.txt
+++ b/runtime/doc/if_pyth.txt
@@ -19,18 +19,17 @@ Commands *python-commands*
the `:python` command is working: >
:python print "Hello"
-:[range]py[thon] << {endmarker}
+:[range]py[thon] << [endmarker]
{script}
{endmarker}
- Execute Python script {script}.
- Note: This command doesn't work when Python isn't
- available. To avoid errors, see |script-here|.
-
-{endmarker} must NOT be preceded by any white space. If {endmarker} is
-omitted from after the "<<", a dot '.' must be used after {script}, like
-for the |:append| and |:insert| commands.
-This form of the |:python| command is mainly useful for including python code
-in Vim scripts.
+ Execute Python script {script}. Useful for including
+ python code in Vim scripts. Requires Python, see
+ |script-here|.
+
+The {endmarker} below the {script} must NOT be preceded by any white space.
+
+If [endmarker] is omitted from after the "<<", a dot '.' must be used after
+{script}, like for the |:append| and |:insert| commands.
Example: >
function! IcecreamInitialize()
diff --git a/runtime/doc/if_ruby.txt b/runtime/doc/if_ruby.txt
index 3c7c800fbf..6468e4c81e 100644
--- a/runtime/doc/if_ruby.txt
+++ b/runtime/doc/if_ruby.txt
@@ -19,15 +19,19 @@ downloading Ruby there.
:rub[y] {cmd} Execute Ruby command {cmd}. A command to try it out: >
:ruby print "Hello"
-:rub[y] << {endpattern}
+:rub[y] << [endpattern]
{script}
{endpattern}
Execute Ruby script {script}.
- {endpattern} must NOT be preceded by any white space.
- If {endpattern} is omitted, it defaults to a dot '.'
- like for the |:append| and |:insert| commands. This
- form of the |:ruby| command is mainly useful for
+ The {endpattern} after {script} must NOT be preceded
+ by any white space.
+
+ If [endpattern] is omitted, it defaults to a dot '.'
+ like for the |:append| and |:insert| commands.
+
+ 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|.
diff --git a/runtime/doc/indent.txt b/runtime/doc/indent.txt
index 6820b9c240..a99d84e969 100644
--- a/runtime/doc/indent.txt
+++ b/runtime/doc/indent.txt
@@ -585,8 +585,9 @@ The basics for using flexible indenting are explained in section |30.3| of the
user manual.
If you want to write your own indent file, it must set the 'indentexpr'
-option. Setting the 'indentkeys' option is often useful. See the
-$VIMRUNTIME/indent directory for examples.
+option. Setting the 'indentkeys' option is often useful.
+See the $VIMRUNTIME/indent/README.txt file for hints.
+See the $VIMRUNTIME/indent directory for examples.
REMARKS ABOUT SPECIFIC INDENT FILES ~
@@ -599,14 +600,14 @@ the use of square and curly brackets, and otherwise by community convention.
These conventions are not universally followed, so the Clojure indent script
offers a few configurable options, listed below.
-If the current vim does not include searchpairpos(), the indent script falls
+If the current vim does not include |searchpairpos()|, the indent script falls
back to normal 'lisp' indenting, and the following options are ignored.
*g:clojure_maxlines*
-Set maximum scan distance of searchpairpos(). Larger values trade performance
-for correctness when dealing with very long forms. A value of 0 will scan
-without limits.
+Set maximum scan distance of |searchpairpos()|. Larger values trade
+performance for correctness when dealing with very long forms. A value of 0
+will scan without limits.
>
" Default
let g:clojure_maxlines = 100
@@ -826,7 +827,7 @@ PHP indenting can be altered in several ways by modifying the values of some
global variables:
*php-comment* *PHP_autoformatcomment*
-To not enable auto-formatting of comments by default (if you want to use your
+To not enable auto-formating of comments by default (if you want to use your
own 'formatoptions'): >
:let g:PHP_autoformatcomment = 0
@@ -896,7 +897,7 @@ NOTE: Indenting will be a bit slower if this option is used because some
optimizations won't be available.
-------------
- *PHP_vintage_case_default_indent*
+ *PHP_vintage_case_default_indent*
To indent 'case:' and 'default:' statements in switch() blocks: >
:let g:PHP_vintage_case_default_indent = 1
@@ -923,6 +924,41 @@ You will obtain the following result: >
->age()
->info();
+-------------
+
+ *PHP_IndentFunctionCallParameters*
+Extra indentation levels to add to parameters in multi-line function calls. >
+ let g:PHP_IndentFunctionCallParameters = 1
+
+Function call arguments will indent 1 extra level. For two-space indentation: >
+
+ function call_the_thing(
+ $with_this,
+ $and_that
+ ) {
+ $this->do_the_thing(
+ $with_this,
+ $and_that
+ );
+ }
+
+-------------
+
+ *PHP_IndentFunctionDeclarationParameters*
+Extra indentation levels to add to arguments in multi-line function definitions. >
+ let g:PHP_IndentFunctionDeclarationParameters = 1
+
+Function arguments in declarations will indent 1 extra level. For two-space indentation: >
+
+ function call_the_thing(
+ $with_this,
+ $and_that
+ ) {
+ $this->do_the_thing(
+ $with_this,
+ $and_that
+ );
+ }
PYTHON *ft-python-indent*
@@ -932,17 +968,22 @@ given are the defaults. Note that the variables are set to an expression, so
that you can change the value of 'shiftwidth' later.
Indent after an open paren: >
- let g:pyindent_open_paren = '&sw * 2'
+ let g:pyindent_open_paren = 'shiftwidth() * 2'
Indent after a nested paren: >
- let g:pyindent_nested_paren = '&sw'
+ let g:pyindent_nested_paren = 'shiftwidth()'
Indent for a continuation line: >
- let g:pyindent_continue = '&sw * 2'
+ let g:pyindent_continue = 'shiftwidth() * 2'
-The method uses searchpair() to look back for unclosed parenthesis. This can
-sometimes be slow, thus it timeouts after 150 msec. If you notice the
+The method uses |searchpair()| to look back for unclosed parenthesis. This
+can sometimes be slow, thus it timeouts after 150 msec. If you notice the
indenting isn't correct, you can set a larger timeout in msec: >
let g:pyindent_searchpair_timeout = 500
+If looking back for unclosed parenthesis is still too slow, especially during
+a copy-paste operation, or if you don't need indenting inside multi-line
+parentheses, you can completely disable this feature: >
+ let g:pyindent_disable_parentheses_indenting = 1
+
R *ft-r-indent*
@@ -1035,7 +1076,7 @@ Furthermore, setting the variable b:verilog_indent_width to change the
indenting width (default is 'shiftwidth'): >
let b:verilog_indent_width = 4
- let b:verilog_indent_width = &sw * 2
+ let b:verilog_indent_width = shiftwidth() * 2
In addition, you can turn the verbose mode for debug issue: >
@@ -1158,7 +1199,7 @@ VIM *ft-vim-indent*
For indenting Vim scripts there is one variable that specifies the amount of
indent for a continuation line, a line that starts with a backslash: >
- :let g:vim_indent_cont = &sw * 3
+ :let g:vim_indent_cont = shiftwidth() * 3
Three times shiftwidth is the default value.
diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt
index 765f8ce3a1..47c789713c 100644
--- a/runtime/doc/index.txt
+++ b/runtime/doc/index.txt
@@ -153,7 +153,20 @@ commands in CTRL-X submode *i_CTRL-X_index*
|i_CTRL-X_CTRL-V| CTRL-X CTRL-V complete like in : command line
|i_CTRL-X_CTRL-]| CTRL-X CTRL-] complete tags
|i_CTRL-X_s| CTRL-X s spelling suggestions
-{not available when compiled without the |+insert_expand| feature}
+
+commands in completion mode (see |popupmenu-keys|)
+
+|complete_CTRL-E| CTRL-E stop completion and go back to original text
+|complete_CTRL-Y| CTRL-Y accept selected match and stop completion
+ CTRL-L insert one character from the current match
+ <CR> insert currently selected match
+ <BS> delete one character and redo search
+ CTRL-H same as <BS>
+ <Up> select the previous match
+ <Down> select the next match
+ <PageUp> select a match several entries back
+ <PageDown> select a match several entries forward
+ other stop completion and insert the typed character
==============================================================================
2. Normal mode *normal-index*
@@ -555,6 +568,8 @@ tag command action in Normal mode ~
|CTRL-W_gF| CTRL-W g F edit file name under the cursor in a new
tab page and jump to the line number
following the file name.
+|CTRL-W_gt| CTRL-W g t same as `gt`: go to next tab page
+|CTRL-W_gT| CTRL-W g T same as `gT`: go to previous tab page
|CTRL-W_h| CTRL-W h go to Nth left window (stop at first window)
|CTRL-W_i| CTRL-W i split window and jump to declaration of
identifier under the cursor
@@ -840,6 +855,17 @@ tag char note action in Normal mode ~
|z<Right>| z<Right> same as "zl"
==============================================================================
+2.6 Operator-pending mode *operator-pending-index*
+
+These can be used after an operator, but before a {motion} has been entered.
+
+tag char action in Operator-pending mode ~
+-----------------------------------------------------------------------
+|o_v| v force operator to work characterwise
+|o_V| V force operator to work linewise
+|o_CTRL-V| CTRL-V force operator to work blockwise
+
+==============================================================================
3. Visual mode *visual-index*
Most commands in Visual mode are the same as in Normal mode. The ones listed
@@ -961,7 +987,7 @@ Normal characters are inserted at the current cursor position.
"Completion" below refers to context-sensitive completion. It will complete
file names, tags, commands etc. as appropriate.
-tag command action in Command-line editing mode ~
+tag command action in Command-line editing mode ~
------------------------------------------------------------------------------
CTRL-@ not used
|c_CTRL-A| CTRL-A do completion on the pattern in front of the
@@ -1001,10 +1027,11 @@ tag command action in Command-line editing mode ~
command-line from history.
|c_CTRL-Q| CTRL-Q same as CTRL-V, unless it's used for terminal
control flow
-|c_CTRL-R| CTRL-R {0-9a-z"%#*:= CTRL-F CTRL-P CTRL-W CTRL-A}
+|c_CTRL-R| CTRL-R {regname}
insert the contents of a register or object
under the cursor as if typed
-|c_CTRL-R_CTRL-R| CTRL-R CTRL-R {0-9a-z"%#*:= CTRL-F CTRL-P CTRL-W CTRL-A}
+|c_CTRL-R_CTRL-R| CTRL-R CTRL-R {regname}
+|c_CTRL-R_CTRL-O| CTRL-R CTRL-O {regname}
insert the contents of a register or object
under the cursor literally
CTRL-S (used for terminal control flow)
@@ -1060,7 +1087,7 @@ This is a brief but complete listing of all the ":" commands, without
mentioning any arguments. The optional part of the command name is inside [].
The commands are sorted on the non-optional part of their name.
-tag command action ~
+tag command action ~
------------------------------------------------------------------------------
|:!| :! filter lines or execute an external command
|:!!| :!! repeat last ":!" command
@@ -1167,6 +1194,7 @@ tag command action ~
|:compiler| :comp[iler] do settings for a specific compiler
|:continue| :con[tinue] go back to :while
|:confirm| :conf[irm] prompt user when confirmation required
+|:const| :cons[t] create a variable as a constant
|:copen| :cope[n] open quickfix window
|:cprevious| :cp[revious] go to previous error
|:cpfile| :cpf[ile] go to last error in previous file
@@ -1429,8 +1457,9 @@ tag command action ~
|:recover| :rec[over] recover a file from a swap file
|:redo| :red[o] redo one undone change
|:redir| :redi[r] redirect messages to a file or register
-|:redraw| :redr[aw] force a redraw of the display
-|:redrawstatus| :redraws[tatus] force a redraw of the status line(s)
+|:redraw| :redr[aw] force a redraw of the display
+|:redrawstatus| :redraws[tatus] force a redraw of the status line(s)
+|:redrawtabline| :redrawt[abline] force a redraw of the tabline
|:registers| :reg[isters] display the contents of registers
|:resize| :res[ize] change current window height
|:retab| :ret[ab] change tab size
@@ -1467,7 +1496,8 @@ tag command action ~
|:sbrewind| :sbr[ewind] split window and go to first file in the
buffer list
|:scriptnames| :scr[iptnames] list names of all sourced Vim scripts
-|:scriptencoding| :scripte[ncoding] encoding used in sourced Vim script
+|:scriptencoding| :scripte[ncoding] encoding used in sourced Vim script
+|:scriptversion| :scriptv[ersion] version of Vim script used
|:scscope| :scs[cope] split window and execute cscope command
|:set| :se[t] show or set options
|:setfiletype| :setf[iletype] set 'filetype', unless it was set already
diff --git a/runtime/doc/job_control.txt b/runtime/doc/job_control.txt
index e5cd765e83..ae208c0755 100644
--- a/runtime/doc/job_control.txt
+++ b/runtime/doc/job_control.txt
@@ -67,7 +67,7 @@ For |on_stdout| and |on_stderr| see |channel-callback|.
*on_exit*
Arguments passed to on_exit callback:
0: |job-id|
- 1: Exit-code of the process.
+ 1: Exit-code of the process, or 128+SIGNUM if by signal (e.g. 143 on SIGTERM).
2: Event type: "exit"
diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt
index eac42df791..abe86749c4 100644
--- a/runtime/doc/map.txt
+++ b/runtime/doc/map.txt
@@ -39,7 +39,7 @@ modes.
:om[ap] {lhs} {rhs} |mapmode-o| *:om* *:omap*
:map! {lhs} {rhs} |mapmode-ic| *:map!*
:im[ap] {lhs} {rhs} |mapmode-i| *:im* *:imap*
-:lm[ap] {lhs} {rhs} |mapmode-l| *:lm* *:lmap*
+:lm[ap] {lhs} {rhs} |mapmode-l| *:lm* *:lma* *:lmap*
:cm[ap] {lhs} {rhs} |mapmode-c| *:cm* *:cmap*
:tma[p] {lhs} {rhs} |mapmode-t| *:tma* *:tmap*
Map the key sequence {lhs} to {rhs} for the modes
@@ -52,12 +52,12 @@ modes.
:nn[oremap] {lhs} {rhs} |mapmode-n| *:nn* *:nnoremap*
:vn[oremap] {lhs} {rhs} |mapmode-v| *:vn* *:vnoremap*
:xn[oremap] {lhs} {rhs} |mapmode-x| *:xn* *:xnoremap*
-:snor[emap] {lhs} {rhs} |mapmode-s| *:snor* *:snoremap*
+:snor[emap] {lhs} {rhs} |mapmode-s| *:snor* *:snore* *:snoremap*
:ono[remap] {lhs} {rhs} |mapmode-o| *:ono* *:onoremap*
:no[remap]! {lhs} {rhs} |mapmode-ic| *:no!* *:noremap!*
-:ino[remap] {lhs} {rhs} |mapmode-i| *:ino* *:inoremap*
+:ino[remap] {lhs} {rhs} |mapmode-i| *:ino* *:inor* *:inoremap*
:ln[oremap] {lhs} {rhs} |mapmode-l| *:ln* *:lnoremap*
-:cno[remap] {lhs} {rhs} |mapmode-c| *:cno* *:cnoremap*
+:cno[remap] {lhs} {rhs} |mapmode-c| *:cno* *:cnor* *:cnoremap*
:tno[remap] {lhs} {rhs} |mapmode-t| *:tno* *:tnoremap*
Map the key sequence {lhs} to {rhs} for the modes
where the map command applies. Disallow mapping of
@@ -74,7 +74,7 @@ modes.
:unm[ap]! {lhs} |mapmode-ic| *:unm!* *:unmap!*
:iu[nmap] {lhs} |mapmode-i| *:iu* *:iunmap*
:lu[nmap] {lhs} |mapmode-l| *:lu* *:lunmap*
-:cu[nmap] {lhs} |mapmode-c| *:cu* *:cunmap*
+:cu[nmap] {lhs} |mapmode-c| *:cu* *:cun* *:cunmap*
:tunma[p] {lhs} |mapmode-t| *:tunma* *:tunmap*
Remove the mapping of {lhs} for the modes where the
map command applies. The mapping may remain defined
@@ -438,6 +438,7 @@ When listing mappings the characters in the first two columns are:
i Insert
l ":lmap" mappings for Insert, Command-line and Lang-Arg
c Command-line
+ t Terminal-Job
Just before the {rhs} a special character can appear:
* indicates that it is not remappable
@@ -536,9 +537,9 @@ scenario: >
:imap <M-C> foo
:set encoding=utf-8
The mapping for <M-C> is defined with the latin1 encoding, resulting in a 0xc3
-byte. If you type the character á (0xe1 <M-a>) in UTF-8 encoding this is the
+byte. If you type the character á (0xe1 <M-a>) in UTF-8 encoding this is the
two bytes 0xc3 0xa1. You don't want the 0xc3 byte to be mapped then or
-otherwise it would be impossible to type the á character.
+otherwise it would be impossible to type the á character.
*<Leader>* *mapleader*
To define a mapping which uses the "mapleader" variable, the special string
@@ -789,8 +790,6 @@ g@{motion} Call the function set by the 'operatorfunc' option.
"block" {motion} was |blockwise-visual|
Although "block" would rarely appear, since it can
only result from Visual mode where "g@" is not useful.
- {not available when compiled without the |+eval|
- feature}
Here is an example that counts the number of spaces with <F4>: >
@@ -971,7 +970,7 @@ See |:verbose-cmd| for more information.
:norea[bbrev] [<expr>] [<buffer>] [lhs] [rhs]
same as ":ab", but no remapping for this {rhs}
- *:ca* *:cabbrev*
+ *:ca* *:cab* *:cabbrev*
:ca[bbrev] [<expr>] [<buffer>] [lhs] [rhs]
same as ":ab", but for Command-line mode only.
@@ -1189,7 +1188,7 @@ reported if any are supplied). However, it is possible to specify that the
command can take arguments, using the -nargs attribute. Valid cases are:
-nargs=0 No arguments are allowed (the default)
- -nargs=1 Exactly one argument is required, it includes spaces
+ -nargs=1 Exactly one argument is required, it includes spaces
-nargs=* Any number of arguments are allowed (0, 1, or many),
separated by white space
-nargs=? 0 or 1 arguments are allowed
@@ -1212,8 +1211,9 @@ defined, not where it is invoked! Example:
Executing script2.vim will result in "None" being echoed. Not what you
intended! Calling a function may be an alternative.
-Completion behavior *:command-completion* *E179*
- *E180* *E181* *:command-complete*
+Completion behavior ~
+ *:command-completion* *E179* *E180* *E181*
+ *:command-complete*
By default, the arguments of user defined commands do not undergo completion.
However, by specifying one or the other of the following attributes, argument
completion can be enabled:
@@ -1334,12 +1334,13 @@ which by default correspond to the current line, last line and the whole
buffer, relate to arguments, (loaded) buffers, windows or tab pages.
Possible values are:
- -addr=lines Range of lines (this is the default)
- -addr=arguments Range for arguments
- -addr=buffers Range for buffers (also not loaded buffers)
- -addr=loaded_buffers Range for loaded buffers
- -addr=windows Range for windows
- -addr=tabs Range for tab pages
+ -addr=lines Range of lines (this is the default)
+ -addr=arguments Range for arguments
+ -addr=buffers Range for buffers (also not loaded buffers)
+ -addr=loaded_buffers Range for loaded buffers
+ -addr=windows Range for windows
+ -addr=tabs Range for tab pages
+ -addr=other other kind of range
Special cases *:command-bang* *:command-bar*
diff --git a/runtime/doc/mbyte.txt b/runtime/doc/mbyte.txt
index 24d9d01af0..127c46c27d 100644
--- a/runtime/doc/mbyte.txt
+++ b/runtime/doc/mbyte.txt
@@ -696,80 +696,6 @@ For example, when you are using kinput2 as |IM-server| and sh, >
<
==============================================================================
-Input on MS-Windows *mbyte-IME*
-
-(Windows IME support) *multibyte-ime* *IME*
-
-{only works Windows GUI and compiled with the |+multi_byte_ime| feature}
-
-To input multibyte characters on Windows, you can use an Input Method Editor
-(IME). In process of your editing text, you must switch status (on/off) of
-IME many many many times. Because IME with status on is hooking all of your
-key inputs, you cannot input 'j', 'k', or almost all of keys to Vim directly.
-
-This |+multi_byte_ime| feature help this. It reduce times of switch status of
-IME manually. In normal mode, there are almost no need working IME, even
-editing multibyte text. So exiting insert mode with ESC, Vim memorize last
-status of IME and force turn off IME. When re-enter insert mode, Vim revert
-IME status to that memorized automatically.
-
-This works on not only insert-normal mode, but also search-command input and
-replace mode.
-The options 'iminsert', 'imsearch' and 'imcmdline' can be used to chose
-the different input methods or disable them temporarily.
-
-WHAT IS IME
- IME is a part of East asian version Windows. That helps you to input
- multibyte character. English and other language version Windows does not
- have any IME. (Also there is no need usually.) But there is one that
- called Microsoft Global IME. Global IME is a part of Internet Explorer
- 4.0 or above. You can get more information about Global IME, at below
- URL.
-
-WHAT IS GLOBAL IME *global-ime*
- Global IME enables input of Chinese, Japanese, and Korean text into Vim
- buffer on any language version of Windows. Global IME is built in, and
- the Input Locales can be added through Control Panel/Regional
- Options/Input Locales. Please see below URL for detail of Global IME.
- You can also find various language version of Global IME at same place.
-
- - Global IME detailed information.
- http://search.microsoft.com/results.aspx?q=global+ime
-
- - Active Input Method Manager (Global IME)
- http://msdn.microsoft.com/en-us/library/aa741221(v=VS.85).aspx
-
- Support for Global IME is an experimental feature.
-
-NOTE: For IME to work you must make sure the input locales of your language
-are added to your system. The exact location of this depends on the version
-of Windows you use. For example, on my Windows 2000 box:
-1. Control Panel
-2. Regional Options
-3. Input Locales Tab
-4. Add Installed input locales -> Chinese(PRC)
- The default is still English (United Stated)
-
-
-Cursor color when IME or XIM is on *CursorIM*
- There is a little cute feature for IME. Cursor can indicate status of IME
- by changing its color. Usually status of IME was indicated by little icon
- at a corner of desktop (or taskbar). It is not easy to verify status of
- IME. But this feature help this.
- This works in the same way when using XIM.
-
- You can select cursor color when status is on by using highlight group
- CursorIM. For example, add these lines to your |ginit.vim|: >
-
- if has('multi_byte_ime')
- highlight Cursor guifg=NONE guibg=Green
- highlight CursorIM guifg=NONE guibg=Purple
- endif
-<
- Cursor color with off IME is green. And purple cursor indicates that
- status is on.
-
-==============================================================================
Input with a keymap *mbyte-keymap*
When the keyboard doesn't produce the characters you want to enter in your
@@ -777,7 +703,6 @@ text, you can use the 'keymap' option. This will translate one or more
(English) characters to another (non-English) character. This only happens
when typing text, not when typing Vim commands. This avoids having to switch
between two keyboard settings.
-{only available when compiled with the |+keymap| feature}
The value of the 'keymap' option specifies a keymap file to use. The name of
this file is one of these two:
diff --git a/runtime/doc/message.txt b/runtime/doc/message.txt
index 205db12f3b..97a1882159 100644
--- a/runtime/doc/message.txt
+++ b/runtime/doc/message.txt
@@ -240,6 +240,9 @@ format of the file. The file will not be marked unmodified. If you care
about the loss of information, set the 'fileencoding' option to another value
that can handle the characters in the buffer and write again. If you don't
care, you can abandon the buffer or reset the 'modified' option.
+If there is a backup file, when 'writebackup' or 'backup' is set, it will not
+be deleted, so you can move it back into place if you want to discard the
+changes.
*E302* >
Could not rename swap file
@@ -534,14 +537,6 @@ This message is only given when Vim detects a problem when searching for a
tag. Sometimes this message is not given, even though the tags file is not
properly sorted.
- *E460* >
- The resource fork would be lost (add ! to override)
-
-On the Macintosh (classic), when writing a file, Vim attempts to preserve all
-info about a file, including its resource fork. If this is not possible you
-get this error message. Append "!" to the command name to write anyway (and
-lose the info).
-
*E424* >
Too many different highlighting attributes in use
@@ -678,11 +673,13 @@ being disabled. Remove the 'C' flag from the 'cpoptions' option to enable it.
This happens when an Ex command with mandatory argument(s) was executed, but
no argument has been specified.
- *E474* *E475* >
+ *E474* *E475* *E983* >
Invalid argument
Invalid argument: {arg}
+ Duplicate argument: {arg}
-An Ex command has been executed, but an invalid argument has been specified.
+An Ex command or function has been executed, but an invalid argument has been
+specified.
*E488* >
Trailing characters
diff --git a/runtime/doc/mlang.txt b/runtime/doc/mlang.txt
index a19d9fd2f4..03c48b962d 100644
--- a/runtime/doc/mlang.txt
+++ b/runtime/doc/mlang.txt
@@ -95,8 +95,10 @@ Or:
This also contains tools xgettext, msgformat and others.
-libintl.dll should be placed in same directory with (g)vim.exe, or some
-place where PATH environment value describe. Vim also finds libintl-8.dll.
+libintl.dll should be placed in same directory as (g)vim.exe, or one of the
+directories listed in the PATH environment value. Vim also looks for the
+alternate names "libintl-8.dll" and "intl.dll".
+
Message files (vim.mo) have to be placed in "$VIMRUNTIME/lang/xx/LC_MESSAGES",
where "xx" is the abbreviation of the language (mostly two letters).
diff --git a/runtime/doc/motion.txt b/runtime/doc/motion.txt
index d5a123e3ea..97c7d1cc43 100644
--- a/runtime/doc/motion.txt
+++ b/runtime/doc/motion.txt
@@ -46,6 +46,7 @@ or change text. The following operators are available:
|!| ! filter through an external program
|=| = filter through 'equalprg' or C-indenting if empty
|gq| gq text formatting
+ |gw| gw text formatting with no cursor movement
|g?| g? ROT13 encoding
|>| > shift right
|<| < shift left
@@ -107,7 +108,7 @@ This cannot be repeated: >
endif<CR>
Note that when using ":" any motion becomes characterwise exclusive.
-
+ *forced-motion*
FORCING A MOTION TO BE LINEWISE, CHARACTERWISE OR BLOCKWISE
When a motion is not of the type you would like to use, you can force another
@@ -310,7 +311,7 @@ _ <underscore> [count] - 1 lines downward, on the first non-blank
G Goto line [count], default last line, on the first
non-blank character |linewise|. If 'startofline' not
set, keep the same column.
- G is a one of |jump-motions|.
+ G is one of the |jump-motions|.
*<C-End>*
<C-End> Goto line [count], default last line, on the last
@@ -923,7 +924,7 @@ These commands are not marks themselves, but jump to a mark:
[` [count] times to lowercase mark before the cursor.
-:loc[kmarks] {command} *:loc* *:lockmarks*
+:loc[kmarks] {command} *:loc* *:lock* *:lockmarks*
Execute {command} without adjusting marks. This is
useful when changing text in a way that the line count
will be the same when the change has completed.
@@ -949,7 +950,7 @@ These commands are not marks themselves, but jump to a mark:
- folds
- diffs
-:kee[pmarks] {command} *:kee* *:keepmarks*
+:kee[pmarks] {command} *:kee* *:keep* *:keepmarks*
Currently only has effect for the filter command
|:range!|:
- When the number of lines after filtering is equal to
@@ -989,11 +990,11 @@ These commands are not marks themselves, but jump to a mark:
A "jump" is a command that normally moves the cursor several lines away. If
you make the cursor "jump" the position of the cursor before the jump is
-remembered. You can return to that position with the "''" and "``" command,
+remembered. You can return to that position with the "''" and "``" commands,
unless the line containing that position was changed or deleted. The
following commands are "jump" commands: "'", "`", "G", "/", "?", "n", "N",
"%", "(", ")", "[[", "]]", "{", "}", ":s", ":tag", "L", "M", "H" and the
-commands that start editing a new file.
+commands that start editing a new file.
*CTRL-O*
CTRL-O Go to [count] Older cursor position in jump list
diff --git a/runtime/doc/nvim_terminal_emulator.txt b/runtime/doc/nvim_terminal_emulator.txt
index aba0571dc0..d1831a8de6 100644
--- a/runtime/doc/nvim_terminal_emulator.txt
+++ b/runtime/doc/nvim_terminal_emulator.txt
@@ -117,21 +117,22 @@ higher precedence: it is applied after terminal colors are resolved.
==============================================================================
Status Variables *terminal-status*
-Terminal buffers maintain some information about the terminal in buffer-local
-variables:
+Terminal buffers maintain some buffer-local variables and options. The values
+are initialized before TermOpen, so you can use them in a local 'statusline'.
+Example: >
+ :autocmd TermOpen * setlocal statusline=%{b:term_title}
-- *b:term_title* The settable title of the terminal, typically displayed in
- the window title or tab title of a graphical terminal emulator. Programs
- running in the terminal can set this title via an escape sequence.
-- |'channel'| The nvim channel ID for the underlying PTY.
- |chansend()| can be used to send input to the terminal.
+- *b:term_title* Terminal title (user-writable), typically displayed in the
+ window title or tab title of a graphical terminal emulator. Terminal
+ 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.
+
+Use |jobwait()| to check if the terminal job has finished: >
+ let running = jobwait([&channel], 0)[0] == -1
-These variables are initialized before TermOpen, so you can use them in
-a local 'statusline'. Example: >
- :autocmd TermOpen * setlocal statusline=%{b:term_title}
-<
==============================================================================
-5. Debugging *terminal-debug* *terminal-debugger*
+:Termdebug plugin *terminal-debug*
The Terminal debugging plugin can be used to debug a program with gdb and view
the source code in a Vim window. Since this is completely contained inside
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index e780dba53c..6fcead0894 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -295,12 +295,12 @@ files. You use this command: >
:setlocal makeprg=perlmake
You can switch back to using the global value by making the local value empty: >
:setlocal makeprg=
-This only works for a string option. For a boolean option you need to use the
-"<" flag, like this: >
+This only works for a string option. For a number or boolean option you need
+to use the "<" flag, like this: >
:setlocal autoread<
-Note that for non-boolean options using "<" copies the global value to the
-local value, it doesn't switch back to using the global value (that matters
-when the global value changes later). You can also use: >
+Note that for non-boolean and non-number options using "<" copies the global
+value to the local value, it doesn't switch back to using the global value
+(that matters when the global value changes later). You can also use: >
:set path<
This will make the local value of 'path' empty, so that the global value is
used. Thus it does the same as: >
@@ -324,9 +324,9 @@ Setting the filetype
When the optional FALLBACK argument is present, a
later :setfiletype command will override the
- 'filetype'. This is to used for filetype detections
- that are just a guess. |did_filetype()| will return
- false after this command.
+ 'filetype'. This is to be used for filetype
+ detections that are just a guess. |did_filetype()|
+ will return false after this command.
*option-window* *optwin*
:bro[wse] se[t] *:set-browse* *:browse-set* *:opt* *:options*
@@ -478,14 +478,17 @@ backslash in front of the ':' will be removed. Example:
/* vi:set dir=c\:\tmp: */ ~
This sets the 'dir' option to "c:\tmp". Only a single backslash before the
':' is removed. Thus to include "\:" you have to specify "\\:".
-
+ *E992*
No other commands than "set" are supported, for security reasons (somebody
might create a Trojan horse text file with modelines). And not all options
-can be set. For some options a flag is set, so that when it's used the
-|sandbox| is effective. Still, there is always a small risk that a modeline
-causes trouble. E.g., when some joker sets 'textwidth' to 5 all your lines
-are wrapped unexpectedly. So disable modelines before editing untrusted text.
-The mail ftplugin does this, for example.
+can be set. For some options a flag is set, so that when the value is used
+the |sandbox| is effective. Some options can only be set from the modeline
+when 'modelineexpr' is set (the default is off).
+
+Still, there is always a small risk that a modeline causes trouble. E.g.,
+when some joker sets 'textwidth' to 5 all your lines are wrapped unexpectedly.
+So disable modelines before editing untrusted text. The mail ftplugin does
+this, for example.
Hint: If you would like to do something else than setting an option, you could
define an autocommand that checks the file for a specific string. For
@@ -874,7 +877,9 @@ A jump table for the options with a short description can be found at |Q_op|.
< Use 'backupdir' to put the backup in a different directory.
*'backupskip'* *'bsk'*
-'backupskip' 'bsk' string (default: "/tmp/*,$TMPDIR/*,$TMP/*,$TEMP/*")
+'backupskip' 'bsk' string (default: "$TMPDIR/*,$TMP/*,$TEMP/*"
+ Unix: "/tmp/*,$TMPDIR/*,$TMP/*,$TEMP/*"
+ Mac: "/private/tmp/*,$TMPDIR/*,$TMP/*,$TEMP/*")
global
A list of file patterns. When one of the patterns matches with the
name of the file which is written, no backup file is created. Both
@@ -1656,7 +1661,10 @@ A jump table for the options with a short description can be found at |Q_op|.
deleted only once. Also when repeating "R" with "."
and a count.
*cpo-y*
- y A yank command can be redone with ".".
+ y A yank command can be redone with ".". Think twice if
+ you really want to use this, it may break some
+ plugins, since most people expect "." to only repeat a
+ change.
*cpo-Z*
Z When using "w!" while the 'readonly' option is set,
don't reset 'readonly'.
@@ -1802,7 +1810,16 @@ A jump table for the options with a short description can be found at |Q_op|.
The default value is for C programs. For C++ this value would be
useful, to include const type declarations: >
^\(#\s*define\|[a-z]*\s*const\s*[a-z]*\)
+< You can also use "\ze" just before the name and continue the pattern
+ to check what is following. E.g. for Javascript, if a function is
+ defined with "func_name = function(args)": >
+ ^\s*\ze\i\+\s*=\s*function(
+< If the function is defined with "func_name : function() {...": >
+ ^\s*\ze\i\+\s*[:]\s*(*function\s*(
< When using the ":set" command, you need to double the backslashes!
+ To avoid that use `:let` with a single quote string: >
+ let &l:define = '^\s*\ze\k\+\s*=\s*function('
+<
*'delcombine'* *'deco'* *'nodelcombine'* *'nodeco'*
'delcombine' 'deco' boolean (default off)
@@ -1825,8 +1842,11 @@ A jump table for the options with a short description can be found at |Q_op|.
contain a list of words. This can be one word per line, or several
words per line, separated by non-keyword characters (white space is
preferred). Maximum line length is 510 bytes.
- When this option is empty, or an entry "spell" is present, spell
- checking is enabled the currently active spelling is used. |spell|
+
+ When this option is empty or an entry "spell" is present, and spell
+ checking is enabled, words in the word lists for the currently active
+ 'spelllang' are used. See |spell|.
+
To include a comma in a file name precede it with a backslash. Spaces
after a comma are ignored, otherwise spaces are included in the file
name. See |option-backslash| about using backslashes.
@@ -1869,6 +1889,9 @@ A jump table for the options with a short description can be found at |Q_op|.
context:{n} Use a context of {n} lines between a change
and a fold that contains unchanged lines.
When omitted a context of six lines is used.
+ When using zero the context is actually one,
+ since folds require a line in between, also
+ for a deleted line.
See |fold-diff|.
iblank Ignore changes where lines are all blank. Adds
@@ -1927,7 +1950,7 @@ A jump table for the options with a short description can be found at |Q_op|.
diff library.
algorithm:{text} Use the specified diff algorithm with the
- internal diff engine. Currently supported
+ internal diff engine. Currently supported
algorithms are:
myers the default algorithm
minimal spend extra time to generate the
@@ -2126,22 +2149,6 @@ A jump table for the options with a short description can be found at |Q_op|.
This option is reset when the 'paste' option is set and restored when
the 'paste' option is reset.
- *'exrc'* *'ex'* *'noexrc'* *'noex'*
-'exrc' 'ex' boolean (default off)
- global
- Enables the reading of .vimrc and .exrc in the current directory.
- Setting this option is a potential security leak. E.g., consider
- unpacking a package or fetching files from github, a .vimrc in there
- might be a trojan horse. BETTER NOT SET THIS OPTION!
- Instead, define an autocommand in your .vimrc to set options for a
- matching directory.
-
- If you do switch this option on you should also consider setting the
- 'secure' option (see |initialization|).
- This option cannot be set from a |modeline| or in the |sandbox|, for
- security reasons.
- Also see |init.vim| and |gui-init|.
-
*'fileencoding'* *'fenc'* *E213*
'fileencoding' 'fenc' string (default: "")
local to buffer
@@ -2422,7 +2429,7 @@ A jump table for the options with a short description can be found at |Q_op|.
The expression will be evaluated in the |sandbox| if set from a
modeline, see |sandbox-option|.
This option can't be set from a |modeline| when the 'diff' option is
- on.
+ on or the 'modelineexpr' option is off.
It is not allowed to change text or jump to another window while
evaluating 'foldexpr' |textlock|.
@@ -2537,6 +2544,7 @@ A jump table for the options with a short description can be found at |Q_op|.
The expression will be evaluated in the |sandbox| if set from a
modeline, see |sandbox-option|.
+ This option cannot be set in a modeline when 'modelineexpr' is off.
It is not allowed to change text or jump to another window while
evaluating 'foldtext' |textlock|.
@@ -2572,16 +2580,8 @@ A jump table for the options with a short description can be found at |Q_op|.
The expression will be evaluated in the |sandbox| when set from a
modeline, see |sandbox-option|. That stops the option from working,
since changing the buffer text is not allowed.
-
- *'formatoptions'* *'fo'*
-'formatoptions' 'fo' string (default: "tcqj", Vi default: "vt")
- local to buffer
- This is a sequence of letters which describes how automatic
- formatting is to be done. See |fo-table|. When the 'paste' option is
- on, no formatting is done (like 'formatoptions' is empty). Commas can
- be inserted for readability.
- To avoid problems with flags that are added in the future, use the
- "+=" and "-=" feature of ":set" |add-option-flags|.
+ This option cannot be set in a modeline when 'modelineexpr' is off.
+ NOTE: This option is set to "" when 'compatible' is set.
*'formatlistpat'* *'flp'*
'formatlistpat' 'flp' string (default: "^\s*\d\+[\]:.)}\t ]\s*")
@@ -2596,6 +2596,16 @@ A jump table for the options with a short description can be found at |Q_op|.
The default recognizes a number, followed by an optional punctuation
character and white space.
+ *'formatoptions'* *'fo'*
+'formatoptions' 'fo' string (default: "tcqj", Vi default: "vt")
+ local to buffer
+ This is a sequence of letters which describes how automatic
+ formatting is to be done. See |fo-table|. When the 'paste' option is
+ on, no formatting is done (like 'formatoptions' is empty). Commas can
+ be inserted for readability.
+ To avoid problems with flags that are added in the future, use the
+ "+=" and "-=" feature of ":set" |add-option-flags|.
+
*'formatprg'* *'fp'*
'formatprg' 'fp' string (default "")
global or local to buffer |global-local|
@@ -2626,6 +2636,9 @@ A jump table for the options with a short description can be found at |Q_op|.
- system signals low battery life
- Nvim exits abnormally
+ This option cannot be set from a |modeline| or in the |sandbox|, for
+ security reasons.
+
*'gdefault'* *'gd'* *'nogdefault'* *'nogd'*
'gdefault' 'gd' boolean (default off)
global
@@ -2948,7 +2961,13 @@ A jump table for the options with a short description can be found at |Q_op|.
the right moment, try adding this flag. This must be done
before starting the GUI. Set it in your |gvimrc|. Adding or
removing it after the GUI has started has no effect.
-
+ *'go-k'*
+ 'k' Keep the GUI window size when adding/removing a scrollbar, or
+ toolbar, tabline, etc. Instead, the behavior is similar to
+ when the window is maximized and will adjust 'lines' and
+ 'columns' to fit to the window. Without the 'k' flag Vim will
+ try to keep 'lines' and 'columns the same when adding and
+ removing GUI components.
*'guitablabel'* *'gtl'*
'guitablabel' 'gtl' string (default empty)
@@ -2961,6 +2980,7 @@ A jump table for the options with a short description can be found at |Q_op|.
'guitabtooltip' is used for the tooltip, see below.
The expression will be evaluated in the |sandbox| when set from a
modeline, see |sandbox-option|.
+ This option cannot be set in a modeline when 'modelineexpr' is off.
Only used when the GUI tab pages line is displayed. 'e' must be
present in 'guioptions'. For the non-GUI tab pages line 'tabline' is
@@ -3089,6 +3109,7 @@ A jump table for the options with a short description can be found at |Q_op|.
When this option contains printf-style '%' items, they will be
expanded according to the rules used for 'statusline'. See
'titlestring' for example settings.
+ This option cannot be set in a modeline when 'modelineexpr' is off.
*'ignorecase'* *'ic'* *'noignorecase'* *'noic'*
'ignorecase' 'ic' boolean (default off)
@@ -3124,8 +3145,6 @@ A jump table for the options with a short description can be found at |Q_op|.
0 :lmap is off and IM is off
1 :lmap is ON and IM is off
2 :lmap is off and IM is ON
- 2 is available only when compiled with the |+multi_byte_ime|, |+xim|
- or |global-ime|.
To always reset the option to zero when leaving Insert mode with <Esc>
this can be used: >
:inoremap <ESC> <ESC>:set iminsert=0<CR>
@@ -3192,6 +3211,7 @@ A jump table for the options with a short description can be found at |Q_op|.
The expression will be evaluated in the |sandbox| when set from a
modeline, see |sandbox-option|.
+ This option cannot be set in a modeline when 'modelineexpr' is off.
It is not allowed to change text or jump to another window while
evaluating 'includeexpr' |textlock|.
@@ -3203,7 +3223,7 @@ A jump table for the options with a short description can be found at |Q_op|.
so far, matches. The matched string is highlighted. If the pattern
is invalid or not found, nothing is shown. The screen will be updated
often, this is only useful on fast terminals.
-< Note that the match will be shown, but the cursor will return to its
+ Note that the match will be shown, but the cursor will return to its
original position when no match is found and when pressing <Esc>. You
still need to finish the search command with <Enter> to move the
cursor to the match.
@@ -3260,6 +3280,7 @@ A jump table for the options with a short description can be found at |Q_op|.
The expression will be evaluated in the |sandbox| when set from a
modeline, see |sandbox-option|.
+ This option cannot be set in a modeline when 'modelineexpr' is off.
It is not allowed to change text or jump to another window while
evaluating 'indentexpr' |textlock|.
@@ -3877,10 +3898,23 @@ A jump table for the options with a short description can be found at |Q_op|.
< If you have less than 512 Mbyte |:mkspell| may fail for some
languages, no matter what you set 'mkspellmem' to.
+ This option cannot be set from a |modeline| or in the |sandbox|.
+
*'modeline'* *'ml'* *'nomodeline'* *'noml'*
'modeline' 'ml' boolean (Vim default: on (off for root),
Vi default: off)
local to buffer
+ If 'modeline' is on 'modelines' gives the number of lines that is
+ checked for set commands. If 'modeline' is off or 'modelines' is zero
+ no lines are checked. See |modeline|.
+
+ *'modelineexpr'* *'mle'* *'nomodelineexpr'* *'nomle'*
+'modelineexpr' 'mle' boolean (default: off)
+ global
+ When on allow some options that are an expression to be set in the
+ modeline. Check the option for whether it is affected by
+ 'modelineexpr'. Also see |modeline|.
+
*'modelines'* *'mls'*
'modelines' 'mls' number (default 5)
global
@@ -4181,7 +4215,7 @@ A jump table for the options with a short description can be found at |Q_op|.
rows in the window, depending on whether 'number' or 'relativenumber'
is set. Thus with the Vim default of 4 there is room for a line number
up to 999. When the buffer has 1000 lines five columns will be used.
- The minimum value is 1, the maximum value is 10.
+ The minimum value is 1, the maximum value is 20.
*'omnifunc'* *'ofu'*
'omnifunc' 'ofu' string (default: empty)
@@ -4476,6 +4510,13 @@ A jump table for the options with a short description can be found at |Q_op|.
the range of 0 for fully opaque popupmenu (disabled) to 100 for fully
transparent background. Values between 0-30 are typically most useful.
+ It is possible to override the level for individual highlights within
+ the popupmenu using |highlight-blend|. For instance, to enable
+ transparency but force the current selected element to be fully opaque: >
+
+ :set pumblend=15
+ :hi PmenuSel blend=0
+<
UI-dependent. Works best with RGB colors. 'termguicolors'
*'pyxversion'* *'pyx'*
@@ -4524,6 +4565,25 @@ A jump table for the options with a short description can be found at |Q_op|.
set for the newly edited buffer.
See 'modifiable' for disallowing changes to the buffer.
+ *'redrawdebug'* *'rdb'*
+'redrawdebug' 'rdb' string (default '')
+ global
+ Flags to change the way redrawing works, for debugging purposes.
+ Most useful with 'writedelay' set to some reasonable value.
+ Supports the following flags:
+ compositor Indicate what redraws come from the compositor
+ by briefly flashing the redrawn regions in colors
+ indicating the redraw type. These are the highlight
+ groups used (and their default colors):
+ RedrawDebugNormal gui=reverse normal redraw passed through
+ RedrawDebugClear guibg=Yellow clear event passed through
+ RedrawDebugComposed guibg=Green redraw event modified by the
+ compositor (due to
+ overlapping grids, etc)
+ RedrawDebugRecompose guibg=Red redraw generated by the
+ compositor itself, due to a
+ grid being moved or deleted.
+
*'redrawtime'* *'rdt'*
'redrawtime' 'rdt' number (default 2000)
global
@@ -4657,6 +4717,8 @@ A jump table for the options with a short description can be found at |Q_op|.
When this option is not empty, it determines the content of the ruler
string, as displayed for the 'ruler' option.
The format of this option is like that of 'statusline'.
+ This option cannot be set in a modeline when 'modelineexpr' is off.
+
The default ruler width is 17 characters. To make the ruler 15
characters wide, put "%15(" at the start and "%)" at the end.
Example: >
@@ -5054,6 +5116,8 @@ A jump table for the options with a short description can be found at |Q_op|.
When equal to "NONE" no shada file will be read or written.
This option can be set with the |-i| command line flag. The |--clean|
command line flag sets it to "NONE".
+ This option cannot be set from a |modeline| or in the |sandbox|, for
+ security reasons.
*'shell'* *'sh'* *E91*
'shell' 'sh' string (default $SHELL or "sh",
@@ -5095,8 +5159,9 @@ A jump table for the options with a short description can be found at |Q_op|.
unescaping, so to keep yourself sane use |:let-&| like shown above.
*shell-powershell*
To use powershell (on Windows): >
- set shell=powershell shellquote=( shellpipe=\| shellredir=> shellxquote=
+ set shell=powershell shellquote=( shellpipe=\| shellxquote=
set shellcmdflag=-NoLogo\ -NoProfile\ -ExecutionPolicy\ RemoteSigned\ -Command
+ set shellredir=\|\ Out-File\ -Encoding\ UTF8
< This option cannot be set from a |modeline| or in the |sandbox|, for
security reasons.
@@ -5277,7 +5342,8 @@ A jump table for the options with a short description can be found at |Q_op|.
O message for reading a file overwrites any previous message.
Also for quickfix message (e.g., ":cn").
s don't give "search hit BOTTOM, continuing at TOP" or "search
- hit TOP, continuing at BOTTOM" messages
+ hit TOP, continuing at BOTTOM" messages; when using the search
+ count do not show "W" after the count message (see S below)
t truncate file message at the start if it is too long to fit
on the command-line, "<" will appear in the left most column.
Ignored in Ex mode.
@@ -5293,7 +5359,8 @@ A jump table for the options with a short description can be found at |Q_op|.
"Pattern not found", "Back at original", etc.
q use "recording" instead of "recording @a"
F don't give the file info when editing a file, like `:silent`
- was used for the command
+ was used for the command; note that this also affects messages
+ from autocommands
S do not show search count message when searching, e.g.
"[1/5]"
@@ -5548,7 +5615,8 @@ A jump table for the options with a short description can be found at |Q_op|.
set spelllang=en_us,nl,medical
< This means US English, Dutch and medical words are recognized. Words
that are not recognized will be highlighted.
- The word list name must not include a comma or dot. Using a dash is
+ The word list name must consist of alphanumeric characters, a dash or
+ an underscore. It should not include a comma or dot. Using a dash is
recommended to separate the two letter language name from a
specification. Thus "en-rare" is used for rare English words.
A region name must come last and have the form "_xx", where "xx" is
@@ -5574,8 +5642,8 @@ A jump table for the options with a short description can be found at |Q_op|.
After this option has been set successfully, Vim will source the files
"spell/LANG.vim" in 'runtimepath'. "LANG" is the value of 'spelllang'
- up to the first character that is not an ASCII letter and not a dash.
- Also see |set-spc-auto|.
+ up to the first character that is not an ASCII letter or number and
+ not a dash. Also see |set-spc-auto|.
*'spellsuggest'* *'sps'*
@@ -5820,6 +5888,7 @@ A jump table for the options with a short description can be found at |Q_op|.
The 'statusline' option will be evaluated in the |sandbox| if set from
a modeline, see |sandbox-option|.
+ This option cannot be set in a modeline when 'modelineexpr' is off.
It is not allowed to change text or jump to another window while
evaluating 'statusline' |textlock|.
@@ -5915,7 +5984,9 @@ A jump table for the options with a short description can be found at |Q_op|.
pages.
split If included, split the current window before loading
a buffer for a |quickfix| command that display errors.
- Otherwise: do not split, use current window.
+ Otherwise: do not split, use current window (when used
+ in the quickfix window: the previously used window or
+ split if there is no other window).
vsplit Just like "split" but split vertically.
newtab Like "split", but open a new tab page. Overrules
"split" when both are present.
@@ -5974,6 +6045,10 @@ A jump table for the options with a short description can be found at |Q_op|.
the text to be displayed. Use "%1T" for the first label, "%2T" for
the second one, etc. Use "%X" items for closing labels.
+ When changing something that is used in 'tabline' that does not
+ trigger it to be updated, use |:redrawtabline|.
+ This option cannot be set in a modeline when 'modelineexpr' is off.
+
Keep in mind that only one of the tab pages is the current one, others
are invisible and you can't jump to their windows.
@@ -6160,10 +6235,11 @@ A jump table for the options with a short description can be found at |Q_op|.
'thesaurus' 'tsr' string (default "")
global or local to buffer |global-local|
List of file names, separated by commas, that are used to lookup words
- for thesaurus completion commands |i_CTRL-X_CTRL-T|. Each line in
- the file should contain words with similar meaning, separated by
- non-keyword characters (white space is preferred). Maximum line
- length is 510 bytes.
+ for thesaurus completion commands |i_CTRL-X_CTRL-T|.
+
+ Each line in the file should contain words with similar meaning,
+ separated by non-keyword characters (white space is preferred).
+ Maximum line length is 510 bytes.
To include a comma in a file name precede it with a backslash. Spaces
after a comma are ignored, otherwise spaces are included in the file
@@ -6253,8 +6329,11 @@ A jump table for the options with a short description can be found at |Q_op|.
global
When this option is not empty, it will be used for the title of the
window. This happens only when the 'title' option is on.
+
When this option contains printf-style '%' items, they will be
expanded according to the rules used for 'statusline'.
+ This option cannot be set in a modeline when 'modelineexpr' is off.
+
Example: >
:auto BufEnter * let &titlestring = hostname() . "/" . expand("%:p")
:set title titlestring=%<%F%=%l/%L-%P titlelen=70
@@ -6288,6 +6367,8 @@ A jump table for the options with a short description can be found at |Q_op|.
undo file that exists is used. When it cannot be read an error is
given, no further entry is used.
See |undo-persistence|.
+ This option cannot be set from a |modeline| or in the |sandbox|, for
+ security reasons.
*'undofile'* *'noundofile'* *'udf'* *'noudf'*
'undofile' 'udf' boolean (default off)
@@ -6612,17 +6693,16 @@ A jump table for the options with a short description can be found at |Q_op|.
More info here: |cmdline-completion|.
*'wildoptions'* *'wop'*
-'wildoptions' 'wop' string (default "")
+'wildoptions' 'wop' string (default "pum,tagfile")
global
- A list of words that change how command line completion is done.
+ List of words that change how |cmdline-completion| is done.
+ pum Display the completion matches using the popupmenu
+ in the same style as the |ins-completion-menu|.
tagfile When using CTRL-D to list matching tags, the kind of
tag and the file of the tag is listed. Only one match
is displayed per line. Often used tag kinds are:
d #define
f function
- pum Display the completion matches using the popupmenu
- in the same style as the |ins-completion-menu|.
- Also see |cmdline-completion|.
*'winaltkeys'* *'wak'*
'winaltkeys' 'wak' string (default "menu")
@@ -6643,6 +6723,15 @@ A jump table for the options with a short description can be found at |Q_op|.
key is never used for the menu.
This option is not used for <F10>; on Win32.
+ *'winblend'* *'winbl'*
+'winblend' 'winbl' number (default 0)
+ local to window
+ Enables pseudo-transparency for a floating window. Valid values are in
+ the range of 0 for fully opaque window (disabled) to 100 for fully
+ transparent background. Values between 0-30 are typically most useful.
+
+ UI-dependent. Works best with RGB colors. 'termguicolors'
+
*'window'* *'wi'*
'window' 'wi' number (default screen height - 1)
global
diff --git a/runtime/doc/pattern.txt b/runtime/doc/pattern.txt
index 022dc5607e..adfab07758 100644
--- a/runtime/doc/pattern.txt
+++ b/runtime/doc/pattern.txt
@@ -295,7 +295,7 @@ the "*" is under your right hand middle finger (search to the right and down).
*E956*
In very rare cases a regular expression is used recursively. This can happen
-when executing a pattern takes a long time and when checkig for messages on
+when executing a pattern takes a long time and when checking for messages on
channels a callback is invoked that also uses a pattern or an autocommand is
triggered. In most cases this should be fine, but if a pattern is in use when
it's used again it fails. Usually this means there is something wrong with
@@ -398,11 +398,11 @@ Use of "\m" makes the pattern after it be interpreted as if 'magic' is set,
ignoring the actual value of the 'magic' option.
Use of "\M" makes the pattern after it be interpreted as if 'nomagic' is used.
*/\v* */\V*
-Use of "\v" means that in the pattern after it all ASCII characters except
-'0'-'9', 'a'-'z', 'A'-'Z' and '_' have a special meaning. "very magic"
+Use of "\v" means that after it, all ASCII characters except '0'-'9', 'a'-'z',
+'A'-'Z' and '_' have special meaning: "very magic"
-Use of "\V" means that in the pattern after it only the backslash and the
-terminating character (/ or ?) has a special meaning. "very nomagic"
+Use of "\V" means that after it, only a backslash and terminating character
+(usually / or ?) have special meaning: "very nomagic"
Examples:
after: \v \m \M \V matches ~
@@ -1125,7 +1125,7 @@ x A single character, with no special meaning, matches itself
The "Func" column shows what library function is used. The
implementation depends on the system. Otherwise:
(1) Uses islower() for ASCII and Vim builtin rules for other
- characters when built with the |+multi_byte| feature.
+ characters.
(2) Uses Vim builtin rules
(3) As with (1) but using isupper()
*/[[=* *[==]*
@@ -1189,7 +1189,6 @@ x A single character, with no special meaning, matches itself
To include a "[" use "[[]" and for "]" use []]", e.g.,: >
/index\%[[[]0[]]]
< matches "index" "index[", "index[0" and "index[0]".
- {not available when compiled without the |+syntax| feature}
*/\%d* */\%x* */\%o* */\%u* */\%U* *E678*
@@ -1201,7 +1200,7 @@ x A single character, with no special meaning, matches itself
\%u20AC Matches the character specified with up to four hexadecimal
characters.
\%U1234abcd Matches the character specified with up to eight hexadecimal
- characters.
+ characters, up to 0x7fffffff
==============================================================================
7. Ignoring case in a pattern */ignorecase*
diff --git a/runtime/doc/pi_netrw.txt b/runtime/doc/pi_netrw.txt
index a0e071d4dd..9a75a95f23 100644
--- a/runtime/doc/pi_netrw.txt
+++ b/runtime/doc/pi_netrw.txt
@@ -1,4 +1,4 @@
-*pi_netrw.txt* Nvim
+*pi_netrw.txt* For Vim version 8.1. Last change: 2019 Jul 17
------------------------------------------------
NETRW REFERENCE MANUAL by Charles E. Campbell
@@ -6,7 +6,7 @@
Author: Charles E. Campbell <NdrOchip@ScampbellPfamily.AbizM>
(remove NOSPAM from Campbell's email first)
-Copyright: Copyright (C) 2016 Charles E Campbell *netrw-copyright*
+Copyright: Copyright (C) 2017 Charles E Campbell *netrw-copyright*
The VIM LICENSE applies to the files in this package, including
netrw.vim, pi_netrw.txt, netrwFileHandlers.vim, netrwSettings.vim, and
syntax/netrw.vim. Like anything else that's free, netrw.vim and its
@@ -17,7 +17,6 @@ Copyright: Copyright (C) 2016 Charles E Campbell *netrw-copyright*
holder be liable for any damages resulting from the use of this
software. Use at your own risk!
-
*netrw*
*dav* *ftp* *netrw-file* *rcp* *scp*
*davs* *http* *netrw.vim* *rsync* *sftp*
@@ -73,7 +72,7 @@ Copyright: Copyright (C) 2016 Charles E Campbell *netrw-copyright*
Improving Browsing..................................|netrw-ssh-hack|
Listing Bookmarks And History.......................|netrw-qb|
Making A New Directory..............................|netrw-d|
- Making The Browsing Directory The Current Directory.|netrw-c|
+ Making The Browsing Directory The Current Directory.|netrw-cd|
Marking Files.......................................|netrw-mf|
Unmarking Files.....................................|netrw-mF|
Marking Files By Location List......................|netrw-qL|
@@ -83,6 +82,7 @@ Copyright: Copyright (C) 2016 Charles E Campbell *netrw-copyright*
Marked Files: Arbitrary Shell Command, En Bloc......|netrw-mX|
Marked Files: Arbitrary Vim Command.................|netrw-mv|
Marked Files: Argument List.........................|netrw-ma| |netrw-mA|
+ Marked Files: Buffer List...........................|netrw-cb| |netrw-cB|
Marked Files: Compression And Decompression.........|netrw-mz|
Marked Files: Copying...............................|netrw-mc|
Marked Files: Diff..................................|netrw-md|
@@ -153,7 +153,7 @@ Windows' ftp doesn't support .netrc; however, one may have in one's .vimrc: >
let g:netrw_ftp_cmd= 'c:\Windows\System32\ftp -s:C:\Users\MyUserName\MACHINE'
<
-Netrw will substitute the host's machine name for "MACHINE" from the url it is
+Netrw will substitute the host's machine name for "MACHINE" from the URL it is
attempting to open, and so one may specify >
userid
password
@@ -210,7 +210,7 @@ EXTERNAL APPLICATIONS AND PROTOCOLS *netrw-externapp* {{{2
http: g:netrw_http_cmd = "fetch" elseif fetch is available
http: *g:netrw_http_put_cmd* = "curl -T"
rcp: *g:netrw_rcp_cmd* = "rcp"
- rsync: *g:netrw_rsync_cmd* = "rsync -a"
+ rsync: *g:netrw_rsync_cmd* = "rsync" (see |g:netrw_rsync_sep|)
scp: *g:netrw_scp_cmd* = "scp -q"
sftp: *g:netrw_sftp_cmd* = "sftp"
file: *g:netrw_file_cmd* = "elinks" or "links"
@@ -221,7 +221,7 @@ EXTERNAL APPLICATIONS AND PROTOCOLS *netrw-externapp* {{{2
elinks : "-source >"
links : "-dump >"
- curl : "-o"
+ curl : "-L -o"
wget : "-q -O"
fetch : "-o"
<
@@ -236,7 +236,7 @@ EXTERNAL APPLICATIONS AND PROTOCOLS *netrw-externapp* {{{2
READING *netrw-read* *netrw-nread* {{{2
- Generally, one may just use the url notation with a normal editing
+ Generally, one may just use the URL notation with a normal editing
command, such as >
:e ftp://[user@]machine/path
@@ -258,7 +258,7 @@ READING *netrw-read* *netrw-nread* {{{2
WRITING *netrw-write* *netrw-nwrite* {{{2
- One may just use the url notation with a normal file writing
+ One may just use the URL notation with a normal file writing
command, such as >
:w ftp://[user@]machine/path
@@ -279,7 +279,7 @@ WRITING *netrw-write* *netrw-nwrite* {{{2
SOURCING *netrw-source* {{{2
- One may just use the url notation with the normal file sourcing
+ One may just use the URL notation with the normal file sourcing
command, such as >
:so ftp://[user@]machine/path
@@ -477,7 +477,7 @@ file using root-relative paths, use the full path:
==============================================================================
4. Network-Oriented File Transfer *netrw-xfer* {{{1
-Network-oriented file transfer under Vim is implemented by a VimL-based script
+Network-oriented file transfer under Vim is implemented by a vim script
(<netrw.vim>) using plugin techniques. It currently supports both reading and
writing across networks using rcp, scp, ftp or ftp+<.netrc>, scp, fetch,
dav/cadaver, rsync, or sftp.
@@ -530,7 +530,7 @@ variable (ex. scp uses the variable g:netrw_scp_cmd, which is defaulted to
let g:netrw_sftp_cmd= '"c:\Program Files\PuTTY\psftp.exe"'
<
(note: it has been reported that windows 7 with putty v0.6's "-batch" option
- doesn't work, so it's best to leave it off for that system)
+ doesn't work, so its best to leave it off for that system)
See |netrw-p8| for more about putty, pscp, psftp, etc.
@@ -732,11 +732,11 @@ such as netrw.
The usual read/write commands are supported. There are also a few
additional commands available. Often you won't need to use Nwrite or
Nread as shown in |netrw-transparent| (ie. simply use >
- :e url
- :r url
- :w url
+ :e URL
+ :r URL
+ :w URL
instead, as appropriate) -- see |netrw-urls|. In the explanations
-below, a {netfile} is an url to a remote file.
+below, a {netfile} is a URL to a remote file.
*:Nwrite* *:Nw*
:[range]Nw[rite] Write the specified lines to the current
@@ -866,9 +866,11 @@ variables listed below, and may be modified by the user.
g:netrw_http_cmd var ="fetch -o" if fetch is available
g:netrw_http_cmd var ="wget -O" else if wget is available
g:netrw_http_put_cmd var ="curl -T"
- |g:netrw_list_cmd| var ="ssh USEPORT HOSTNAME ls -Fa"
+ |g:netrw_list_cmd| var ="ssh USEPORT HOSTNAME ls -Fa"
g:netrw_rcp_cmd var ="rcp"
- g:netrw_rsync_cmd var ="rsync -a"
+ g:netrw_rsync_cmd var ="rsync"
+ *g:netrw_rsync_sep* var ="/" used to separate the hostname
+ from the file spec
g:netrw_scp_cmd var ="scp -q"
g:netrw_sftp_cmd var ="sftp" >
-------------------------------------------------------------------------
@@ -1005,7 +1007,7 @@ where [protocol] is typically scp or ftp. As an example, try: >
vim ftp://ftp.home.vim.org/pub/vim/
<
For local directories, the trailing slash is not required. Again, because it's
-easy to miss: to browse remote directories, the url must terminate with a
+easy to miss: to browse remote directories, the URL must terminate with a
slash!
If you'd like to avoid entering the password repeatedly for remote directory
@@ -1075,9 +1077,9 @@ QUICK REFERENCE: MAPS *netrw-browse-maps* {{{2
<c-r> Browse using a gvim server |netrw-ctrl-r|
<c-tab> Shrink/expand a netrw/explore window |netrw-c-tab|
- Makes Netrw go up one directory |netrw--|
- a Toggles between normal display, |netrw-a|
+ a Cycles between normal display, |netrw-a|
hiding (suppress display of files matching g:netrw_list_hide)
- showing (display only files which match g:netrw_list_hide)
+ and showing (display only files which match g:netrw_list_hide)
c Make browsing directory the current directory |netrw-c|
C Setting the editing window |netrw-C|
d Make a directory |netrw-d|
@@ -1088,6 +1090,7 @@ QUICK REFERENCE: MAPS *netrw-browse-maps* {{{2
gh Quick hide/unhide of dot-files |netrw-gh|
gn Make top of tree the directory below the cursor |netrw-gn|
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|
mc Copy marked files to marked-file target directory |netrw-mc|
md Apply diff to marked files (up to 3) |netrw-md|
@@ -1167,25 +1170,26 @@ QUICK REFERENCE: COMMANDS *netrw-explore-cmds* *netrw-browse-cmds* {{{2
BANNER DISPLAY *netrw-I*
-One may toggle the banner display on and off by pressing "I".
+One may toggle the displaying of the banner by pressing "I".
Also See: |g:netrw_banner|
-BOOKMARKING A DIRECTORY *netrw-mb* *netrw-bookmark* *netrw-bookmarks* {{{2
+BOOKMARKING A DIRECTORY *netrw-mb* *netrw-bookmark* *netrw-bookmarks* {{{2
One may easily "bookmark" the currently browsed directory by using >
mb
<
*.netrwbook*
-Bookmarks are retained in between sessions in a $HOME/.netrwbook file, and are
-kept in sorted order.
+Bookmarks are retained in between sessions of vim in a file called .netrwbook
+as a |List|, which is typically stored in the first directory on the user's
+'runtimepath'; entries are kept in sorted order.
If there are marked files and/or directories, mb will add them to the bookmark
list.
-*netrw-:NetrwMB*
+ *netrw-:NetrwMB*
Addtionally, one may use :NetrwMB to bookmark files or directories. >
:NetrwMB[!] [files/directories]
@@ -1204,7 +1208,7 @@ The :NetrwMB command is available outside of netrw buffers (once netrw has been
invoked in the session).
The file ".netrwbook" holds bookmarks when netrw (and vim) is not active. By
-default, it's stored on the first directory on the user's |'runtimepath'|.
+default, its stored on the first directory on the user's |'runtimepath'|.
Related Topics:
|netrw-gb| how to return (go) to a bookmark
@@ -1416,20 +1420,20 @@ Related Topics:
CHANGING TO A PREDECESSOR DIRECTORY *netrw-u* *netrw-updir* {{{2
-Every time you change to a new directory (new for the current session),
-netrw will save the directory in a recently-visited directory history
-list (unless |g:netrw_dirhistmax| is zero; by default, it's ten). With the
-"u" map, one can change to an earlier directory (predecessor). To do
-the opposite, see |netrw-U|.
+Every time you change to a new directory (new for the current session), netrw
+will save the directory in a recently-visited directory history list (unless
+|g:netrw_dirhistmax| is zero; by default, it holds ten entries). With the "u"
+map, one can change to an earlier directory (predecessor). To do the
+opposite, see |netrw-U|.
-The "u" map also accepts counts to go back in the history several slots.
-For your convenience, qb (see |netrw-qb|) lists the history number which may
-be used in that count.
+The "u" map also accepts counts to go back in the history several slots. For
+your convenience, qb (see |netrw-qb|) lists the history number which may be
+used in that count.
*.netrwhist*
See |g:netrw_dirhistmax| for how to control the quantity of history stack
slots. The file ".netrwhist" holds history when netrw (and vim) is not
-active. By default, it's stored on the first directory on the user's
+active. By default, its stored on the first directory on the user's
|'runtimepath'|.
Related Topics:
@@ -1465,10 +1469,10 @@ changing the top of the tree listing.
NETRW CLEAN *netrw-clean* *:NetrwClean* {{{2
-With NetrwClean one may easily remove netrw from one's home directory;
+With :NetrwClean one may easily remove netrw from one's home directory;
more precisely, from the first directory on your |'runtimepath'|.
-With NetrwClean!, netrw will attempt to remove netrw from all directories on
+With :NetrwClean!, netrw will attempt to remove netrw from all directories on
your |'runtimepath'|. Of course, you have to have write/delete permissions
correct to do this.
@@ -1500,7 +1504,7 @@ Netrw determines which special handler by the following method:
If g:netrw_browsex_viewer == '-', then netrwFileHandlers#Invoke() will be
used instead (see |netrw_filehandler|).
- * for Windows 32 or 64, the url and FileProtocolHandler dlls are used.
+ * 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
* for Mac OS X : open is used.
@@ -1516,9 +1520,10 @@ will apply a special handler to it (like "x" works when in a netrw buffer).
One may also use visual mode (see |visual-start|) to select the text that the
special handler will use. Normally gx uses expand("<cfile>") to pick up the
text under the cursor; one may change what |expand()| uses via the
-|g:netrw_gx| variable. Alternatively, one may select the text to be used by
-gx via first making a visual selection (see |visual-block|) or by changing
-the |'isfname'| option (which is global, so netrw doesn't modify it).
+|g:netrw_gx| variable (options include "<cword>", "<cWORD>"). Note that
+expand("<cfile>") depends on the |'isfname'| setting. Alternatively, one may
+select the text to be used by gx by making a visual selection (see
+|visual-block|) and then pressing gx.
Associated setting variables:
|g:netrw_gx| control how gx picks up the text under the cursor
@@ -1610,6 +1615,11 @@ A further approach is to delete files which match a pattern.
This will cause the matching files to be marked. Then,
press "D".
+If your vim has 7.4 with patch#1107, then |g:netrw_localrmdir| no longer
+is used to remove directories; instead, vim's |delete()| is used with
+the "d" option. Please note that only empty directories may be deleted
+with the "D" mapping. Regular files are deleted with |delete()|, too.
+
The |g:netrw_rm_cmd|, |g:netrw_rmf_cmd|, and |g:netrw_rmdir_cmd| variables are
used to control the attempts to remove remote files and directories. The
g:netrw_rm_cmd is used with files, and its default value is:
@@ -1673,17 +1683,18 @@ DIRECTORY EXPLORATION COMMANDS {{{2
The [N] specifies a |g:netrw_winsize| just for the new :Lexplore
window.
- Those who like this method often also often like tree style displays;
+ Those who like this method often also like tree style displays;
see |g:netrw_liststyle|.
+:[N]Lexplore! [dir] is similar to :Lexplore, except that the full-height
+ Explorer window will open on the right hand side and an
+ uninitialized |g:netrw_chgwin| will be set to 1 (eg. edits will
+ preferentially occur in the leftmost window).
+
Also see: |netrw-C| |g:netrw_browse_split| |g:netrw_wiw|
|netrw-p| |netrw-P| |g:netrw_chgwin|
|netrw-c-tab| |g:netrw_winsize|
-:[N]Lexplore! is like :Lexplore, except that the full-height Explorer window
- will open on the right hand side and an uninitialized |g:netrw_chgwin|
- will be set to 1.
-
*netrw-:Sexplore*
:[N]Sexplore will always split the window before invoking the local-directory
browser. As with Explore, the splitting is normally done
@@ -1845,9 +1856,11 @@ EXECUTING FILE UNDER CURSOR VIA SYSTEM() *netrw-X* {{{2
Pressing X while the cursor is atop an executable file will yield a prompt
using the filename asking for any arguments. Upon pressing a [return], netrw
-will then call |system()| with that command and arguments. The result will
-be displayed by |:echomsg|, and so |:messages| will repeat display of the
-result. Ansi escape sequences will be stripped out.
+will then call |system()| with that command and arguments. The result will be
+displayed by |:echomsg|, and so |:messages| will repeat display of the result.
+Ansi escape sequences will be stripped out.
+
+See |cmdline-window| for directions for more on how to edit the arguments.
FORCING TREATMENT AS A FILE OR DIRECTORY *netrw-gd* *netrw-gf* {{{2
@@ -2070,7 +2083,7 @@ Associated setting variables: |g:netrw_localmkdir| |g:netrw_mkdir_cmd|
|g:netrw_remote_mkdir| |netrw-%|
-MAKING THE BROWSING DIRECTORY THE CURRENT DIRECTORY *netrw-c* {{{2
+MAKING THE BROWSING DIRECTORY THE CURRENT DIRECTORY *netrw-cd* {{{2
By default, |g:netrw_keepdir| is 1. This setting means that the current
directory will not track the browsing directory. (done for backwards
@@ -2081,10 +2094,13 @@ track netrw's browsing directory.
However, given the default setting for g:netrw_keepdir of 1 where netrw
maintains its own separate notion of the current directory, in order to make
-the two directories the same, use the "c" map (just type c). That map will
+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-c* : This map's name has been 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|
MARKING FILES *netrw-:MF* *netrw-mf* {{{2
@@ -2129,6 +2145,7 @@ The following netrw maps make use of marked files:
|netrw-mg| Apply vimgrep to marked files
|netrw-mm| Move marked files to target
|netrw-mp| Print marked files
+ |netrw-ms| Netrw will source marked files
|netrw-mt| Set target for |netrw-mm| and |netrw-mc|
|netrw-mT| Generate tags using marked files
|netrw-mv| Apply vim command to marked files
@@ -2203,6 +2220,9 @@ converts "*" into ".*" (see |regexp|) and marks files based on that. In the
future I may make it possible to use |regexp|s instead of glob()-style
expressions (yet-another-option).
+See |cmdline-window| for directions on more on how to edit the regular
+expression.
+
MARKED FILES, ARBITRARY VIM COMMAND *netrw-mv* {{{2
(See |netrw-mf| and |netrw-mr| for how to mark files)
@@ -2216,8 +2236,9 @@ the local marked file list, individually:
* run vim command
* sil! keepalt wq!
-A prompt, "Enter vim command: ", will be issued to elicit the vim command
-you wish used.
+A prompt, "Enter vim command: ", will be issued to elicit the vim command you
+wish used. See |cmdline-window| for directions for more on how to edit the
+command.
MARKED FILES, ARBITRARY SHELL COMMAND *netrw-mx* {{{2
@@ -2268,7 +2289,17 @@ MARKED FILES: ARGUMENT LIST *netrw-ma* *netrw-mA*
Using ma, one moves filenames from the marked file list to the argument list.
Using mA, one moves filenames from the argument list to the marked file list.
-See Also: |netrw-qF| |argument-list| |:args|
+See Also: |netrw-cb| |netrw-cB| |netrw-qF| |argument-list| |:args|
+
+
+MARKED FILES: BUFFER LIST *netrw-cb* *netrw-cB*
+ (See |netrw-mf| and |netrw-mr| for how to mark files)
+ (uses the global marked-file list)
+
+Using cb, one moves filenames from the marked file list to the buffer list.
+Using cB, one copies filenames from the buffer list to the marked file list.
+
+See Also: |netrw-ma| |netrw-mA| |netrw-qF| |buffer-list| |:buffers|
MARKED FILES: COMPRESSION AND DECOMPRESSION *netrw-mz* {{{2
@@ -2304,15 +2335,15 @@ One may also copy directories and their contents (local only) to a target
directory.
Associated setting variables:
- |g:netrw_localcopycmd|
- |g:netrw_localcopydircmd|
+ |g:netrw_localcopycmd| |g:netrw_localcopycmdopt|
+ |g:netrw_localcopydircmd| |g:netrw_localcopydircmdopt|
|g:netrw_ssh_cmd|
MARKED FILES: DIFF *netrw-md* {{{2
(See |netrw-mf| and |netrw-mr| for how to mark files)
(uses the global marked file list)
-Use |diff-mode| to visualize difference between selected files (two or
+Use |vimdiff| to visualize difference between selected files (two or
three may be selected for this). Uses the global marked file list.
MARKED FILES: EDITING *netrw-me* {{{2
@@ -2450,8 +2481,8 @@ When a remote set of files are tagged, the resulting tags file is "obtained";
ie. a copy is transferred to the local system's directory. The now local tags
file is then modified so that one may use it through the network. The
modification made concerns the names of the files in the tags; each filename is
-preceded by the netrw-compatible url used to obtain it. When one subsequently
-uses one of the go to tag actions (|tags|), the url will be used by netrw to
+preceded by the netrw-compatible URL used to obtain it. When one subsequently
+uses one of the go to tag actions (|tags|), the URL will be used by netrw to
edit the desired file and go to the tag.
Associated setting variables: |g:netrw_ctags| |g:netrw_ssh_cmd|
@@ -2553,8 +2584,8 @@ your browsing preferences. (see also: |netrw-settings|)
editing. It will also use the specified tab
and window numbers to perform editing
(see |clientserver|, |netrw-ctrl-r|)
- This option does not affect |:Lexplore|
- windows.
+ This option does not affect the production of
+ |:Lexplore| windows.
Related topics:
|g:netrw_alto| |g:netrw_altv|
@@ -2708,11 +2739,12 @@ your browsing preferences. (see also: |netrw-settings|)
=0 : show all
=1 : show not-hidden files
=2 : show hidden files only
- default: =0
+ default: =1
*g:netrw_home* The home directory for where bookmarks and
history are saved (as .netrwbook and
.netrwhist).
+ Netrw uses |expand()|on the string.
default: the first directory on the
|'runtimepath'|
@@ -2733,7 +2765,7 @@ your browsing preferences. (see also: |netrw-settings|)
default: (if ssh is executable)
"ssh HOSTNAME ls -FLa"
- *g:netrw_list_cmd_options* If this variable exists, then its contents are
+ *g:netrw_list_cmd_options* If this variable exists, then its contents are
appended to the g:netrw_list_cmd. For
example, use "2>/dev/null" to get rid of banner
messages on unix systems.
@@ -2759,26 +2791,52 @@ your browsing preferences. (see also: |netrw-settings|)
let g:netrw_list_hide= netrw_gitignore#Hide().'.*\.swp$'
default: ""
- *g:netrw_localcopycmd* ="cp" Linux/Unix/MacOS/Cygwin
- ="copy" Windows
+ *g:netrw_localcopycmd* ="cp" Linux/Unix/MacOS/Cygwin
+ =expand("$COMSPEC") Windows
Copies marked files (|netrw-mf|) to target
directory (|netrw-mt|, |netrw-mc|)
- *g:netrw_localcopydircmd* ="cp -R" Linux/Unix/MacOS/Cygwin
- ="xcopy /e /c /h/ /i /k" Windows
+ *g:netrw_localcopycmdopt* ='' Linux/Unix/MacOS/Cygwin
+ =' \c copy' Windows
+ Options for the |g:netrw_localcopycmd|
+
+ *g:netrw_localcopydircmd* ="cp" Linux/Unix/MacOS/Cygwin
+ =expand("$COMSPEC") Windows
Copies directories to target directory.
(|netrw-mc|, |netrw-mt|)
- *g:netrw_localmkdir* command for making a local directory
- default: "mkdir"
+ *g:netrw_localcopydircmdopt* =" -R" Linux/Unix/MacOS/Cygwin
+ =" /c xcopy /e /c /h/ /i /k" Windows
+ Options for |g:netrw_localcopydircmd|
+
+ *g:netrw_localmkdir* ="mkdir" Linux/Unix/MacOS/Cygwin
+ =expand("$COMSPEC") Windows
+ command for making a local directory
- *g:netrw_localmovecmd* ="mv" Linux/Unix/MacOS/Cygwin
- ="move" Windows
+ *g:netrw_localmkdiropt* ="" Linux/Unix/MacOS/Cygwin
+ =" /c mkdir" Windows
+ Options for |g:netrw_localmkdir|
+
+ *g:netrw_localmovecmd* ="mv" Linux/Unix/MacOS/Cygwin
+ =expand("$COMSPEC") Windows
Moves marked files (|netrw-mf|) to target
directory (|netrw-mt|, |netrw-mm|)
- *g:netrw_localrmdir* remove directory command (rmdir)
- default: "rmdir"
+ *g:netrw_localmovecmdopt* ="" Linux/Unix/MacOS/Cygwin
+ =" /c move" Windows
+ Options for |g:netrw_localmovecmd|
+
+ *g:netrw_localrmdir* ="rmdir" Linux/Unix/MacOS/Cygwin
+ =expand("$COMSPEC") Windows
+ Remove directory command (rmdir)
+ This variable is only used if your vim is
+ earlier than 7.4 or if your vim doesn't
+ have patch#1107. Otherwise, |delete()|
+ is used with the "d" option.
+
+ *g:netrw_localrmdiropt* ="" Linux/Unix/MacOS/Cygwin
+ =" /c rmdir" Windows
+ Options for |g:netrw_localrmdir|
*g:netrw_maxfilenamelen* =32 by default, selected so as to make long
listings fit on 80 column displays.
@@ -2882,26 +2940,41 @@ your browsing preferences. (see also: |netrw-settings|)
netrwBak : *.bak
netrwCompress: *.gz *.bz2 *.Z *.zip
+ netrwCoreDump: core.\d\+
netrwData : *.dat
+ netrwDoc : *.doc,*.txt,*.pdf,
+ *.pdf,*.docx
netrwHdr : *.h
+ netrwLex : *.l *.lex
netrwLib : *.a *.so *.lib *.dll
netrwMakefile: [mM]akefile *.mak
netrwObj : *.o *.obj
+ netrwPix : *.bmp,*.fit,*.fits,*.gif,
+ *.jpg,*.jpeg,*.pcx,*.ppc
+ *.pgm,*.png,*.psd,*.rgb
+ *.tif,*.xbm,*.xcf
netrwTags : tags ANmenu ANtags
netrwTilde : *
netrwTmp : tmp* *tmp
-
- These syntax highlighting groups are linked
- to Folded or DiffChange by default
- (see |hl-Folded| and |hl-DiffChange|), but
- one may put lines like >
+ netrwYacc : *.y
+
+ In addition, those groups mentioned in
+ |'suffixes'| are also added to the special
+ file highlighting group.
+ These syntax highlighting groups are linked
+ to netrwGray or Folded by default
+ (see |hl-Folded|), but one may put lines like >
hi link netrwCompress Visual
< into one's <.vimrc> to use one's own
preferences. Alternatively, one may
- put such specifications into
- .vim/after/syntax/netrw.vim.
-
- As an example, I myself use a dark-background
+ put such specifications into >
+ .vim/after/syntax/netrw.vim.
+< The netrwGray highlighting is set up by
+ netrw when >
+ * netrwGray has not been previously
+ defined
+ * the gui is running
+< As an example, I myself use a dark-background
colorscheme with the following in
.vim/after/syntax/netrw.vim: >
@@ -2968,8 +3041,9 @@ your browsing preferences. (see also: |netrw-settings|)
current netrw buffer's window to be used for
the new window.
If g:netrw_winsize is less than zero, then
- the absolute value of g:netrw_winsize lines
- or columns will be used for the new window.
+ the absolute value of g:netrw_winsize will be
+ used to specify the quantity of lines or
+ columns for the new window.
If g:netrw_winsize is zero, then a normal
split will be made (ie. |'equalalways'| will
take effect, for example).
@@ -3136,8 +3210,8 @@ If there are no marked files: (see |netrw-mf|)
Renaming files and directories involves moving the cursor to the
file/directory to be moved (renamed) and pressing "R". You will then be
- queried for what you want the file/directory to be renamed to You may select
- a range of lines with the "V" command (visual selection), and then
+ queried for what you want the file/directory to be renamed to. You may
+ select a range of lines with the "V" command (visual selection), and then
press "R"; you will be queried for each file as to what you want it
renamed to.
@@ -3169,16 +3243,20 @@ If there are marked files: (see |netrw-mf|)
Note that moving files is a dangerous operation; copies are safer. That's
because a "move" for remote files is actually a copy + delete -- and if
- the copy fails and the delete does not, you may lose the file.
+ the copy fails and the delete succeeds you may lose the file.
Use at your own risk.
-The g:netrw_rename_cmd variable is used to implement remote renaming. By
-default its value is:
+The *g:netrw_rename_cmd* variable is used to implement remote renaming. By
+default its value is: >
ssh HOSTNAME mv
-
+<
One may rename a block of files and directories by selecting them with
-V (|linewise-visual|) when using thin style
+V (|linewise-visual|) when using thin style.
+
+See |cmdline-editing| for more on how to edit the command line; in particular,
+you'll find <ctrl-f> (initiates cmdline window editing) and <ctrl-c> (uses the
+command line under the cursor) useful in conjunction with the R command.
SELECTING SORTING STYLE *netrw-s* *netrw-sort* {{{2
@@ -3199,8 +3277,8 @@ number. Subsequent selection of a file to edit (|netrw-cr|) will use that
window.
* C : by itself, will select the current window holding a netrw buffer
- for editing via |netrw-cr|. The C mapping is only available while in
- netrw buffers.
+ for subsequent editing via |netrw-cr|. The C mapping is only available
+ while in netrw buffers.
* [count]C : the count will be used as the window number to be used
for subsequent editing via |netrw-cr|.
@@ -3213,7 +3291,7 @@ window.
Using >
let g:netrw_chgwin= -1
will restore the default editing behavior
-(ie. editing will use the current window).
+(ie. subsequent editing will use the current window).
Related topics: |netrw-cr| |g:netrw_browse_split|
Associated setting variables: |g:netrw_chgwin|
@@ -3234,9 +3312,9 @@ only if your terminal supports differentiating <c-tab> from a plain
* Else bring up a |:Lexplore| window
-If |g:netrw_usetab| exists or is zero, or if there is a pre-existing mapping
+If |g:netrw_usetab| exists and is zero, or if there is a pre-existing mapping
for <c-tab>, then the <c-tab> will not be mapped. One may map something other
-than a <c-tab>, too: (but you'll still need to have had g:netrw_usetab set) >
+than a <c-tab>, too: (but you'll still need to have had |g:netrw_usetab| set). >
nmap <unique> (whatever) <Plug>NetrwShrink
<
@@ -3269,9 +3347,10 @@ The user function is passed one argument; it resembles >
fun! ExampleUserMapFunc(islocal)
<
-where a:islocal is 1 if it's a local-directory system call or 0 when
+where a:islocal is 1 if its a local-directory system call or 0 when
remote-directory system call.
+ *netrw-call* *netrw-expose* *netrw-modify*
Use netrw#Expose("varname") to access netrw-internal (script-local)
variables.
Use netrw#Modify("varname",newvalue) to change netrw-internal variables.
@@ -3302,7 +3381,7 @@ Example: Clear netrw's marked file list via a mapping on gu >
(This section is likely to grow as I get feedback)
(also see |netrw-debug|)
*netrw-p1*
- P1. I use windows 95, and my ftp dumps four blank lines at the
+ P1. I use windows 95, and my ftp dumps four blank lines at the {{{2
end of every read.
See |netrw-fixup|, and put the following into your
@@ -3311,7 +3390,7 @@ Example: Clear netrw's marked file list via a mapping on gu >
let g:netrw_win95ftp= 1
*netrw-p2*
- P2. I use Windows, and my network browsing with ftp doesn't sort by
+ P2. I use Windows, and my network browsing with ftp doesn't sort by {{{2
time or size! -or- The remote system is a Windows server; why
don't I get sorts by time or size?
@@ -3338,7 +3417,7 @@ Example: Clear netrw's marked file list via a mapping on gu >
*netrw-p3*
- P3. I tried rcp://user@host/ (or protocol other than ftp) and netrw
+ P3. I tried rcp://user@host/ (or protocol other than ftp) and netrw {{{2
used ssh! That wasn't what I asked for...
Netrw has two methods for browsing remote directories: ssh
@@ -3347,7 +3426,7 @@ Example: Clear netrw's marked file list via a mapping on gu >
listing), netrw will use the given protocol to do so.
*netrw-p4*
- P4. I would like long listings to be the default.
+ P4. I would like long listings to be the default. {{{2
Put the following statement into your |.vimrc|: >
@@ -3357,7 +3436,7 @@ Example: Clear netrw's marked file list via a mapping on gu >
you can set.
*netrw-p5*
- P5. My times come up oddly in local browsing
+ P5. My times come up oddly in local browsing {{{2
Does your system's strftime() accept the "%c" to yield dates
such as "Sun Apr 27 11:49:23 1997"? If not, do a
@@ -3367,7 +3446,7 @@ Example: Clear netrw's marked file list via a mapping on gu >
let g:netrw_timefmt= "%X" (where X is the option)
<
*netrw-p6*
- P6. I want my current directory to track my browsing.
+ P6. I want my current directory to track my browsing. {{{2
How do I do that?
Put the following line in your |.vimrc|:
@@ -3375,8 +3454,8 @@ Example: Clear netrw's marked file list via a mapping on gu >
let g:netrw_keepdir= 0
<
*netrw-p7*
- P7. I use Chinese (or other non-ascii) characters in my filenames, and
- netrw (Explore, Sexplore, Hexplore, etc) doesn't display them!
+ P7. I use Chinese (or other non-ascii) characters in my filenames, {{{2
+ and netrw (Explore, Sexplore, Hexplore, etc) doesn't display them!
(taken from an answer provided by Wu Yongwei on the vim
mailing list)
@@ -3390,7 +3469,7 @@ Example: Clear netrw's marked file list via a mapping on gu >
(...it is one more reason to recommend that people use utf-8!)
*netrw-p8*
- P8. I'm getting "ssh is not executable on your system" -- what do I
+ P8. I'm getting "ssh is not executable on your system" -- what do I {{{2
do?
(Dudley Fox) Most people I know use putty for windows ssh. It
@@ -3473,7 +3552,7 @@ Example: Clear netrw's marked file list via a mapping on gu >
default.
*netrw-p9* *netrw-ml_get*
- P9. I'm browsing, changing directory, and bang! ml_get errors
+ P9. I'm browsing, changing directory, and bang! ml_get errors {{{2
appear and I have to kill vim. Any way around this?
Normally netrw attempts to avoid writing swapfiles for
@@ -3484,7 +3563,7 @@ Example: Clear netrw's marked file list via a mapping on gu >
let g:netrw_use_noswf= 0
<
*netrw-p10*
- P10. I'm being pestered with "[something] is a directory" and
+ P10. I'm being pestered with "[something] is a directory" and {{{2
"Press ENTER or type command to continue" prompts...
The "[something] is a directory" prompt is issued by Vim,
@@ -3495,8 +3574,8 @@ Example: Clear netrw's marked file list via a mapping on gu >
your <.vimrc> file.
*netrw-p11*
- P11. I want to have two windows; a thin one on the left and my editing
- window on the right. How may I accomplish this?
+ P11. I want to have two windows; a thin one on the left and my {{{2
+ editing window on the right. How may I accomplish this?
You probably want netrw running as in a side window. If so, you
will likely find that ":[N]Lexplore" does what you want. The
@@ -3521,7 +3600,7 @@ Example: Clear netrw's marked file list via a mapping on gu >
*netrw-p12*
- P12. My directory isn't sorting correctly, or unwanted letters are
+ P12. My directory isn't sorting correctly, or unwanted letters are {{{2
appearing in the listed filenames, or things aren't lining
up properly in the wide listing, ...
@@ -3531,9 +3610,9 @@ Example: Clear netrw's marked file list via a mapping on gu >
You may need to change |g:netrw_sepchr| and/or |g:netrw_xstrlen|.
*netrw-p13*
- P13. I'm a Windows + putty + ssh user, and when I attempt to browse,
- the directories are missing trailing "/"s so netrw treats them
- as file transfers instead of as attempts to browse
+ P13. I'm a Windows + putty + ssh user, and when I attempt to {{{2
+ browse, the directories are missing trailing "/"s so netrw treats
+ them as file transfers instead of as attempts to browse
subdirectories. How may I fix this?
(mikeyao) If you want to use vim via ssh and putty under Windows,
@@ -3552,7 +3631,7 @@ Example: Clear netrw's marked file list via a mapping on gu >
"let g:netrw_scp_cmd = "d:\\dev\\putty\\PSCP.exe"
<
*netrw-p14*
- P14. I would like to speed up writes using Nwrite and scp/ssh
+ P14. I would like to speed up writes using Nwrite and scp/ssh {{{2
style connections. How? (Thomer M. Gil)
Try using ssh's ControlMaster and ControlPath (see the ssh_config
@@ -3579,8 +3658,8 @@ Example: Clear netrw's marked file list via a mapping on gu >
vim scp://host.domain.com//home/user/.bashrc
<
*netrw-p15*
- P15. How may I use a double-click instead of netrw's usual single click
- to open a file or directory? (Ben Fritz)
+ P15. How may I use a double-click instead of netrw's usual single {{{2
+ click to open a file or directory? (Ben Fritz)
First, disable netrw's mapping with >
let g:netrw_mousemaps= 0
@@ -3592,8 +3671,8 @@ Example: Clear netrw's marked file list via a mapping on gu >
(see |g:netrw_mousemaps|)
*netrw-p16*
- P16. When editing remote files (ex. :e ftp://hostname/path/file),
- under Windows I get an |E303| message complaining that it's unable
+ P16. When editing remote files (ex. :e ftp://hostname/path/file), {{{2
+ under Windows I get an |E303| message complaining that its unable
to open a swap file.
(romainl) It looks like you are starting Vim from a protected
@@ -3601,7 +3680,7 @@ Example: Clear netrw's marked file list via a mapping on gu >
directory.
*netrw-p17*
- P17. Netrw is closing buffers on its own.
+ P17. Netrw is closing buffers on its own. {{{2
What steps will reproduce the problem?
1. :Explore, navigate directories, open a file
2. :Explore, open another file
@@ -3615,14 +3694,14 @@ Example: Clear netrw's marked file list via a mapping on gu >
a ":ls!" will show them (although ":ls" does not).
*netrw-P18*
- P18. How to locally edit a file that's only available via
+ P18. How to locally edit a file that's only available via {{{2
another server accessible via ssh?
See http://stackoverflow.com/questions/12469645/
"Using Vim to Remotely Edit A File on ServerB Only
Accessible From ServerA"
*netrw-P19*
- P19. How do I get numbering on in directory listings?
+ P19. How do I get numbering on in directory listings? {{{2
With |g:netrw_bufsettings|, you can control netrw's buffer
settings; try putting >
let g:netrw_bufsettings="noma nomod nu nobl nowrap ro nornu"
@@ -3631,7 +3710,7 @@ Example: Clear netrw's marked file list via a mapping on gu >
let g:netrw_bufsettings="noma nomod nonu nobl nowrap ro rnu"
<
*netrw-P20*
- P20. How may I have gvim start up showing a directory listing?
+ P20. How may I have gvim start up showing a directory listing? {{{2
Try putting the following code snippet into your .vimrc: >
augroup VimStartup
au!
@@ -3644,10 +3723,10 @@ Example: Clear netrw's marked file list via a mapping on gu >
(ie. a "huge" vim version).
*netrw-P21*
- P21. I've made a directory (or file) with an accented character, but
- netrw isn't letting me enter that directory/read that file:
+ P21. I've made a directory (or file) with an accented character, {{{2
+ but netrw isn't letting me enter that directory/read that file:
- It's likely that the shell or o/s is using a different encoding
+ Its likely that the shell or o/s is using a different encoding
than you have vim (netrw) using. A patch to vim supporting
"systemencoding" may address this issue in the future; for
now, just have netrw use the proper encoding. For example: >
@@ -3655,7 +3734,7 @@ Example: Clear netrw's marked file list via a mapping on gu >
au FileType netrw set enc=latin1
<
*netrw-P22*
- P22. I get an error message when I try to copy or move a file:
+ P22. I get an error message when I try to copy or move a file: {{{2
**error** (netrw) tried using g:netrw_localcopycmd<cp>; it doesn't work!
@@ -3719,6 +3798,8 @@ netrw:
or
http://vim.sourceforge.net/scripts/script.php?script_id=120
+ Decho.vim is provided as a "vimball"; see |vimball-intro|.
+
2. Edit the <netrw.vim> file by typing: >
vim netrw.vim
@@ -3761,6 +3842,112 @@ netrw:
==============================================================================
12. History *netrw-history* {{{1
+ v163: Dec 05, 2017 * (Cristi Balan) reported that a setting ('sel')
+ was left changed
+ * (Holger Mitschke) reported a problem with
+ saving and restoring history. Fixed.
+ * Hopefully I fixed a nasty bug that caused a
+ file rename to wipe out a buffer that it
+ should not have wiped out.
+ * (Holger Mitschke) amended this help file
+ with additional |g:netrw_special_syntax|
+ items
+ v162: Sep 19, 2016 * (haya14busa) pointed out two syntax errors
+ with a patch; these are now fixed.
+ Oct 26, 2016 * I started using mate-terminal and found that
+ x and gx (|netrw-x| and |netrw-gx|) were no
+ longer working. Fixed (using atril when
+ $DESKTOP_SESSION is "mate").
+ Nov 04, 2016 * (Martin Vuille) pointed out that @+ was
+ being restored with keepregstar rather than
+ keepregplus.
+ Nov 09, 2016 * Broke apart the command from the options,
+ mostly for Windows. Introduced new netrw
+ settings: |g:netrw_localcopycmdopt|
+ |g:netrw_localcopydircmdopt| |g:netrw_localmkdiropt|
+ |g:netrw_localmovecmdopt| |g:netrw_localrmdiropt|
+ Nov 21, 2016 * (mattn) provided a patch for preview; swapped
+ winwidth() with winheight()
+ Nov 22, 2016 * (glacambre) reported that files containing
+ spaces weren't being obtained properly via
+ scp. Fix: apparently using single quotes
+ such as with 'file name' wasn't enough; the
+ spaces inside the quotes also had to be
+ escaped (ie. 'file\ name').
+ * Also fixed obtain (|netrw-O|) to be able to
+ obtain files with spaces in their names
+ Dec 20, 2016 * (xc1427) Reported that using "I" (|netrw-I|)
+ when atop "Hiding" in the banner also caused
+ the active-banner hiding control to occur
+ Jan 03, 2017 * (Enno Nagel) reported that attempting to
+ apply netrw to a directory that was without
+ read permission caused a syntax error.
+ Jan 13, 2017 * (Ingo Karkat) provided a patch which makes
+ using netrw#Call() better. Now returns
+ value of internal routines return, for example.
+ Jan 13, 2017 * (Ingo Karkat) changed netrw#FileUrlRead to
+ use |:edit| instead of |:read|. I also
+ changed the routine name to netrw#FileUrlEdit.
+ Jan 16, 2017 * (Sayem) reported a problem where :Lexplore
+ could generate a new listing buffer and
+ window instead of toggling the netrw display.
+ Unfortunately, the directions for eliciting
+ the problem weren't complete, so I may or
+ may not have fixed that issue.
+ Feb 06, 2017 * Implemented cb and cB. Changed "c" to "cd".
+ (see |netrw-cb|, |netrw-cB|, and |netrw-cd|)
+ Mar 21, 2017 * previously, netrw would specify (safe) settings
+ even when the setting was already safe for
+ netrw. Netrw now attempts to leave such
+ already-netrw-safe settings alone.
+ (affects s:NetrwOptionRestore() and
+ s:NetrwSafeOptions(); also introduced
+ s:NetrwRestoreSetting())
+ Jun 26, 2017 * (Christian Brabandt) provided a patch to
+ allow curl to follow redirects (ie. -L
+ option)
+ Jun 26, 2017 * (Callum Howard) reported a problem with
+ :Lexpore not removing the Lexplore window
+ after a change-directory
+ Aug 30, 2017 * (Ingo Karkat) one cannot switch to the
+ previously edited file (e.g. with CTRL-^)
+ after editing a file:// URL. Patch to
+ have a "keepalt" included.
+ Oct 17, 2017 * (Adam Faryna) reported that gn (|netrw-gn|)
+ did not work on directories in the current
+ tree
+ v157: Apr 20, 2016 * (Nicola) had set up a "nmap <expr> ..." with
+ a function that returned a 0 while silently
+ invoking a shell command. The shell command
+ activated a ShellCmdPost event which in turn
+ called s:LocalBrowseRefresh(). That looks
+ over all netrw buffers for changes needing
+ refreshes. However, inside a |:map-<expr>|,
+ tab and window changes are disallowed. Fixed.
+ (affects netrw's s:LocalBrowseRefresh())
+ * |g:netrw_localrmdir| not used any more, but
+ the relevant patch that causes |delete()| to
+ take over was #1107 (not #1109).
+ * |expand()| is now used on |g:netrw_home|;
+ consequently, g:netrw_home may now use
+ environment variables
+ * s:NetrwLeftmouse and s:NetrwCLeftmouse will
+ return without doing anything if invoked
+ when inside a non-netrw window
+ Jun 15, 2016 * gx now calls netrw#GX() which returns
+ the word under the cursor. The new
+ wrinkle: if one is in a netrw buffer,
+ then netrw's s:NetrwGetWord().
+ Jun 22, 2016 * Netrw was executing all its associated
+ Filetype commands silently; I'm going
+ to try doing that "noisily" and see if
+ folks have a problem with that.
+ Aug 12, 2016 * Changed order of tool selection for
+ handling http://... viewing.
+ (Nikolay Aleksandrovich Pavlov)
+ Aug 21, 2016 * Included hiding/showing/all for tree
+ listings
+ * Fixed refresh (^L) for tree listings
v156: Feb 18, 2016 * Changed =~ to =~# where appropriate
Feb 23, 2016 * s:ComposePath(base,subdir) now uses
fnameescape() on the base portion
@@ -3792,9 +3979,9 @@ netrw:
tell me how they're useful and should be
retained?
Nov 20, 2015 * Added |netrw-ma| and |netrw-mA| support
- Nov 20, 2015 * gx (|netrw-gx|) on an url downloaded the
+ Nov 20, 2015 * gx (|netrw-gx|) on a URL downloaded the
file in addition to simply bringing up the
- url in a browser. Fixed.
+ URL in a browser. Fixed.
Nov 23, 2015 * Added |g:netrw_sizestyle| support
Nov 27, 2015 * Inserted a lot of <c-u>s into various netrw
maps.
diff --git a/runtime/doc/print.txt b/runtime/doc/print.txt
index 084ad4e521..d744735b96 100644
--- a/runtime/doc/print.txt
+++ b/runtime/doc/print.txt
@@ -44,8 +44,6 @@ Note: If you have problems printing with |:hardcopy|, an alternative is to use
{filename}.
Things like "%" are expanded |cmdline-special|
Careful: An existing file is silently overwritten.
- {only available when compiled with the |+postscript|
- feature}
On MS-Windows use the "print to file" feature of the
printer driver.
@@ -99,10 +97,9 @@ not recognized by Vim will just be converted to lower case and underscores
replaced with '-' signs.
If 'printencoding' is empty or Vim cannot find the file then it will use
-'encoding' (if Vim is compiled with |+multi_byte| and it is set an 8-bit
-encoding) to find the print character encoding file. If Vim is unable to find
-a character encoding file then it will use the "latin1" print character
-encoding file.
+'encoding' (if it is set an 8-bit encoding) to find the print character
+encoding file. If Vim is unable to find a character encoding file then it
+will use the "latin1" print character encoding file.
When 'encoding' is set to a multi-byte encoding, Vim will try to convert
characters to the printing encoding for printing (if 'printencoding' is empty
@@ -238,9 +235,9 @@ possible. The following tables show the valid combinations:
Japanese JIS_C_1978 x x
JIS_X_1983 x x
JIS_X_1990 x x x
- MSWINDOWS x
- KANJITALK6 x
- KANJITALK7 x
+ MSWINDOWS x
+ KANJITALK6 x
+ KANJITALK7 x
euc-kr cp949 ucs-2 utf-8 ~
Korean KS_X_1992 x
diff --git a/runtime/doc/provider.txt b/runtime/doc/provider.txt
index 364fbac351..dc045c360a 100644
--- a/runtime/doc/provider.txt
+++ b/runtime/doc/provider.txt
@@ -57,22 +57,22 @@ If you run into problems, uninstall _both_ then install "pynvim" again: >
PYTHON PROVIDER CONFIGURATION ~
*g:python_host_prog*
-Path to Python 2 interpreter. Setting this makes startup faster. Also useful
-for working with virtualenvs. >
- let g:python_host_prog = '/path/to/python' " Python 2
+Command to start Python 2 (executable, not directory). Setting this makes
+startup faster. Useful for working with virtualenvs. >
+ let g:python_host_prog = '/path/to/python'
<
*g:python3_host_prog*
-Path to Python 3 interpreter. Setting this makes startup faster. Also useful
-for working with virtualenvs. >
- let g:python3_host_prog = '/path/to/python3' " Python 3
+Command to start Python 3 (executable, not directory). Setting this makes
+startup faster. Useful for working with virtualenvs. >
+ let g:python3_host_prog = '/path/to/python3'
<
*g:loaded_python_provider*
To disable Python 2 support: >
- let g:loaded_python_provider = 1
+ let g:loaded_python_provider = 0
<
*g:loaded_python3_provider*
To disable Python 3 support: >
- let g:loaded_python3_provider = 1
+ let g:loaded_python3_provider = 0
PYTHON VIRTUALENVS ~
@@ -111,7 +111,7 @@ Run |:checkhealth| to see if your system is up-to-date.
RUBY PROVIDER CONFIGURATION ~
*g:loaded_ruby_provider*
To disable Ruby support: >
- let g:loaded_ruby_provider = 1
+ let g:loaded_ruby_provider = 0
<
*g:ruby_host_prog*
Command to start the Ruby host. By default this is "neovim-ruby-host". With
@@ -142,7 +142,7 @@ Run |:checkhealth| to see if your system is up-to-date.
NODEJS PROVIDER CONFIGURATION~
*g:loaded_node_provider*
To disable Node.js support: >
- :let g:loaded_node_provider = 1
+ :let g:loaded_node_provider = 0
<
*g:node_host_prog*
Command to start the Node.js host. Setting this makes startup faster.
diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt
index d20a91dc2d..14a25c102d 100644
--- a/runtime/doc/quickfix.txt
+++ b/runtime/doc/quickfix.txt
@@ -87,7 +87,7 @@ processing a quickfix or location list command, it will be aborted.
:ll[!] [nr] Same as ":cc", except the location list for the
current window is used instead of the quickfix list.
- *:cn* *:cnext* *E553*
+ *:cn* *:cne* *:cnext* *E553*
:[count]cn[ext][!] Display the [count] next error in the list that
includes a file name. If there are no file names at
all, go to the [count] next error. See |:cc| for
@@ -97,14 +97,14 @@ processing a quickfix or location list command, it will be aborted.
:[count]lne[xt][!] Same as ":cnext", except the location list for the
current window is used instead of the quickfix list.
-:[count]cN[ext][!] *:cp* *:cprevious* *:cN* *:cNext*
+:[count]cN[ext][!] *:cp* *:cprevious* *:cprev* *:cN* *:cNext*
:[count]cp[revious][!] Display the [count] previous error in the list that
includes a file name. If there are no file names at
all, go to the [count] previous error. See |:cc| for
[!] and 'switchbuf'.
-:[count]lN[ext][!] *:lp* *:lprevious* *:lN* *:lNext*
+:[count]lN[ext][!] *:lp* *:lprevious* *:lprev* *:lN* *:lNext*
:[count]lp[revious][!] Same as ":cNext" and ":cprevious", except the location
list for the current window is used instead of the
quickfix list.
@@ -177,7 +177,7 @@ processing a quickfix or location list command, it will be aborted.
'encoding' option, you can use the 'makeencoding'
option to specify the encoding.
- *:lf* *:lfile*
+ *:lf* *:lfi* *:lfile*
:lf[ile][!] [errorfile] Same as ":cfile", except the location list for the
current window is used instead of the quickfix list.
You can not use the -q command-line option to set
@@ -192,7 +192,7 @@ processing a quickfix or location list command, it will be aborted.
option to specify the encoding.
-:lg[etfile] [errorfile] *:lg* *:lgetfile*
+:lg[etfile] [errorfile] *:lg* *:lge* *:lgetfile*
Same as ":cgetfile", except the location list for the
current window is used instead of the quickfix list.
@@ -230,7 +230,7 @@ processing a quickfix or location list command, it will be aborted.
the current window is used instead of the quickfix
list.
- *:cad* *:caddbuffer*
+ *:cad* *:cadd* *:caddbuffer*
:cad[dbuffer] [bufnr] Read the error list from the current buffer and add
the errors to the current quickfix list. If a
quickfix list is not present, then a new list is
@@ -277,7 +277,7 @@ processing a quickfix or location list command, it will be aborted.
Example: >
:g/mypattern/caddexpr expand("%") . ":" . line(".") . ":" . getline(".")
<
- *:lad* *:laddexpr*
+ *:lad* *:addd* *:laddexpr*
:lad[dexpr] {expr} Same as ":caddexpr", except the location list for the
current window is used instead of the quickfix list.
@@ -355,6 +355,23 @@ modify the title of a quickfix and location list respectively. Examples: >
call setloclist(3, [], 'a', {'title' : 'Cmd output'})
echo getloclist(3, {'title' : 1})
<
+ *quickfix-index*
+When you jump to a quickfix/location list entry using any of the quickfix
+commands (e.g. |:cc|, |:cnext|, |:cprev|, etc.), that entry becomes the
+currently selected entry. The index of the currently selected entry in a
+quickfix/location list can be obtained using the getqflist()/getloclist()
+functions. Examples: >
+ echo getqflist({'idx' : 0}).idx
+ echo getqflist({'id' : qfid, 'idx' : 0}).idx
+ echo getloclist(2, {'idx' : 0}).idx
+<
+For a new quickfix list, the first entry is selected and the index is 1. Any
+entry in any quickfix/location list can be set as the currently selected entry
+using the setqflist() function. Examples: >
+ call setqflist([], 'a', {'idx' : 12})
+ call setqflist([], 'a', {'id' : qfid, 'idx' : 7})
+ call setloclist(1, [], 'a', {'idx' : 7})
+<
*quickfix-size*
You can get the number of entries (size) in a quickfix and a location list
using the |getqflist()| and |getloclist()| functions respectively. Examples: >
@@ -540,9 +557,9 @@ You can use CTRL-W <Enter> to open a new window and jump to the error there.
When the quickfix window has been filled, two autocommand events are
triggered. First the 'filetype' option is set to "qf", which triggers the
-FileType event. Then the BufReadPost event is triggered, using "quickfix" for
-the buffer name. This can be used to perform some action on the listed
-errors. Example: >
+FileType event (also see |qf.vim|). Then the BufReadPost event is triggered,
+using "quickfix" for the buffer name. This can be used to perform some action
+on the listed errors. Example: >
au BufReadPost quickfix setlocal modifiable
\ | silent exe 'g/^/s//\=line(".")." "/'
\ | setlocal nomodifiable
@@ -889,7 +906,7 @@ commands can be combined to create a NewGrep command: >
'smartcase' is not used.
If {pattern} is empty (e.g. // is specified), the last
used search pattern is used. |last-pattern|
-
+:{count}vim[grep] ...
When a number is put before the command this is used
as the maximum number of matches to find. Use
":1vimgrep pattern file" to find only the first.
@@ -1071,8 +1088,6 @@ need to write down a "todo" list.
If you use ":compiler foo" in "file.foo" and
then ":compiler! bar" in another buffer, Vim
will keep on using "foo" in "file.foo".
- {not available when compiled without the
- |+eval| feature}
The Vim plugins in the "compiler" directory will set options to use the
@@ -1257,7 +1272,7 @@ to the file.
Changing directory
The following uppercase conversion characters specify the type of special
-format strings. At most one of them may be given as a prefix at the begin
+format strings. At most one of them may be given as a prefix at the beginning
of a single comma-separated format pattern.
Some compilers produce messages that consist of directory names that have to
be prepended to each file name read by %f (example: GNU make). The following
@@ -1515,7 +1530,7 @@ The backslashes before the pipe character are required to avoid it to be
recognized as a command separator. The backslash before each space is
required for the set command.
- *cfilter-plugin* *Cfilter* *Lfilter*
+ *cfilter-plugin* *:Cfilter* *:Lfilter*
If you have too many matching messages, you can use the cfilter plugin to
reduce the number of entries. Load the plugin with: >
packadd cfilter
diff --git a/runtime/doc/quickref.txt b/runtime/doc/quickref.txt
index d3d9303d3c..87cb9b54f5 100644
--- a/runtime/doc/quickref.txt
+++ b/runtime/doc/quickref.txt
@@ -38,7 +38,7 @@ N is used to indicate an optional count that can be given before the command.
|l| N l right (also: <Space> or <Right> key)
|0| 0 to first character in the line (also: <Home> key)
|^| ^ to first non-blank character in the line
-|$| N $ to the last character in the line (N-1 lines lower)
+|$| N $ to the next EOL (end of line) position
(also: <End> key)
|g0| g0 to first character in screen line (differs from "0"
when lines wrap)
@@ -771,6 +771,7 @@ Short explanation of each option: *option-list*
'menuitems' 'mis' maximum number of items in a menu
'mkspellmem' 'msm' memory used before |:mkspell| compresses the tree
'modeline' 'ml' recognize modelines at start or end of file
+'modelineexpr' 'mle' allow setting expression options from a modeline
'modelines' 'mls' number of lines checked for modelines
'modifiable' 'ma' changes to the text are not possible
'modified' 'mod' buffer has been modified
@@ -797,6 +798,7 @@ Short explanation of each option: *option-list*
'perldll' name of the Perl dynamic library
'preserveindent' 'pi' preserve the indent structure when reindenting
'previewheight' 'pvh' height of the preview window
+'previewpopup' 'pvp' use popup window for preview
'previewwindow' 'pvw' identifies the preview window
'printdevice' 'pdev' name of the printer to be used for :hardcopy
'printencoding' 'penc' encoding to be used for printing
@@ -927,6 +929,7 @@ Short explanation of each option: *option-list*
'winaltkeys' 'wak' when the windows system handles ALT keys
'window' 'wi' nr of lines to scroll for CTRL-F and CTRL-B
'winheight' 'wh' minimum number of lines for the current window
+'winhighlight' 'winhl' window-local highlighting
'winfixheight' 'wfh' keep window height when opening/closing windows
'winfixwidth' 'wfw' keep window width when opening/closing windows
'winminheight' 'wmh' minimum number of lines for any window
diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt
index 0a552a1309..425ef4e926 100644
--- a/runtime/doc/repeat.txt
+++ b/runtime/doc/repeat.txt
@@ -165,7 +165,7 @@ For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|.
:so[urce] {file} Read Ex commands from {file}. These are commands that
start with a ":".
Triggers the |SourcePre| autocommand.
-
+ *:source!*
:so[urce]! {file} Read Vim commands from {file}. These are commands
that are executed from Normal mode, like you type
them.
@@ -173,6 +173,7 @@ For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|.
|: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|.
*:ru* *:runtime*
:ru[ntime][!] [where] {file} ..
@@ -265,9 +266,16 @@ For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|.
after loading your .vimrc file. With this command it
can be done earlier.
- Packages will be loaded only once. After this command
- it won't happen again. When the optional ! is added
- this command will load packages even when done before.
+ Packages will be loaded only once. Using
+ `:packloadall` a second time will have no effect.
+ When the optional ! is added this command will load
+ packages even when done before.
+
+ Note that when using `:packloadall` in the |vimrc|
+ file, the 'runtimepath' option is updated, and later
+ all plugins in 'runtimepath' will be loaded, which
+ means they are loaded again. Plugins are expected to
+ handle that.
An error only causes sourcing the script where it
happens to be aborted, further plugins will be loaded.
@@ -306,7 +314,10 @@ For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|.
|<SID>|.
:scr[iptnames][!] {scriptId} *:script*
- Edit script {scriptId}. Suggested name is ":script".
+ Edit script {scriptId}. Although ":scriptnames name"
+ works, using ":script name" is recommended.
+ When the current buffer can't be |abandon|ed and the !
+ is not present, the command fails.
*:fini* *:finish* *E168*
:fini[sh] Stop sourcing a script. Can only be used in a Vim
diff --git a/runtime/doc/russian.txt b/runtime/doc/russian.txt
index 724c4f9454..776630a52b 100644
--- a/runtime/doc/russian.txt
+++ b/runtime/doc/russian.txt
@@ -52,8 +52,7 @@ 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, if your version of
-Vim is compiled with |+multi_byte| feature enabled.
+$VIMRUNTIME directory. We recommend using UTF-8 archive.
In order to use the Russian documentation, make sure you have set the
'helplang' option to "ru".
diff --git a/runtime/doc/scroll.txt b/runtime/doc/scroll.txt
index 7906214111..7d1da3b409 100644
--- a/runtime/doc/scroll.txt
+++ b/runtime/doc/scroll.txt
@@ -80,9 +80,6 @@ CTRL-U Scroll window Upwards in the buffer. The number of
may be a difference). When the cursor is on the first
line of the buffer nothing happens and a beep is
produced. See also 'startofline' option.
- {difference from vi: Vim scrolls 'scroll' screen
- lines, instead of file lines; makes a difference when
- lines wrap}
<S-Up> or *<S-Up>* *<kPageUp>*
<PageUp> or *<PageUp>* *CTRL-B*
diff --git a/runtime/doc/sign.txt b/runtime/doc/sign.txt
index cf7e01bcea..4e0d91dae0 100644
--- a/runtime/doc/sign.txt
+++ b/runtime/doc/sign.txt
@@ -37,6 +37,7 @@ There are two steps in using signs:
displayed. A defined sign can be placed several times in different lines
and files.
+ *sign-column*
When signs are defined for a file, Vim will automatically add a column of two
characters to display them in. When the last sign is unplaced the column
disappears again. This behavior can be changed with the 'signcolumn' option.
@@ -49,7 +50,7 @@ Example to set the color: >
*sign-identifier*
Each placed sign is identified by a number called the sign identifier. This
identifier is used to jump to the sign or to remove the sign. The identifier
-is assigned when placing the sign using the |sign-place| command or the
+is assigned when placing the sign using the |:sign-place| command or the
|sign_place()| function. Each sign identifier should be a unique number. If
multiple placed signs use the same identifier, then jumping to or removing a
sign becomes unpredictable. To avoid overlapping identifiers, sign groups can
@@ -70,6 +71,10 @@ on the same line, the attributes of the sign with the highest priority is used
independent of the sign group. The default priority for a sign is 10. The
priority is assigned at the time of placing a sign.
+When the line on which the sign is placed is deleted, the sign is moved to the
+next line (or the last line of the buffer, if there is no next line). When
+the delete is undone the sign does not move back.
+
==============================================================================
2. Commands *sign-commands* *:sig* *:sign*
@@ -92,7 +97,7 @@ See |sign_define()| for the equivalent Vim script function.
:sign define {name} {argument}...
Define a new sign or set attributes for an existing sign.
The {name} can either be a number (all digits) or a name
- starting with a non-digit. Leading digits are ignored, thus
+ starting with a non-digit. Leading zeros are ignored, thus
"0012", "012" and "12" are considered the same name.
About 120 different signs can be defined.
diff --git a/runtime/doc/spell.txt b/runtime/doc/spell.txt
index 875f3f2c08..110c6ef221 100644
--- a/runtime/doc/spell.txt
+++ b/runtime/doc/spell.txt
@@ -298,25 +298,25 @@ Exceptions:
spell file is used.
For example, with these values:
- 'runtimepath' is "~/.config/nvim,/usr/share/vim70,~/.config/nvim/after"
+ 'runtimepath' is "~/.config/nvim,/usr/share/nvim/runtime/,~/.config/nvim/after"
'encoding' is "iso-8859-2"
'spelllang' is "pl"
Vim will look for:
1. ~/.config/nvim/spell/pl.iso-8859-2.spl
-2. /usr/share/vim70/spell/pl.iso-8859-2.spl
+2. /usr/share/nvim/runtime/spell/pl.iso-8859-2.spl
3. ~/.config/nvim/spell/pl.iso-8859-2.add.spl
-4. /usr/share/vim70/spell/pl.iso-8859-2.add.spl
+4. /usr/share/nvim/runtime/spell/pl.iso-8859-2.add.spl
5. ~/.config/nvim/after/spell/pl.iso-8859-2.add.spl
This assumes 1. is not found and 2. is found.
If 'encoding' is "latin1" Vim will look for:
1. ~/.config/nvim/spell/pl.latin1.spl
-2. /usr/share/vim70/spell/pl.latin1.spl
+2. /usr/share/nvim/runtime/spell/pl.latin1.spl
3. ~/.config/nvim/after/spell/pl.latin1.spl
4. ~/.config/nvim/spell/pl.ascii.spl
-5. /usr/share/vim70/spell/pl.ascii.spl
+5. /usr/share/nvim/runtime/spell/pl.ascii.spl
6. ~/.config/nvim/after/spell/pl.ascii.spl
This assumes none of them are found (Polish doesn't make sense when leaving
@@ -558,7 +558,7 @@ When the Myspell files are updated you can merge the differences:
nvim -d xx_YY.orig.dic xx_YY.new.dic
3. Take over the changes you like in xx_YY.dic.
You may also need to change xx_YY.aff.
-4. Rename xx_YY.new.dic to xx_YY.orig.dic and xx_YY.new.aff to xx_YY.new.aff.
+4. Rename xx_YY.new.dic to xx_YY.orig.dic and xx_YY.new.aff to xx_YY.orig.aff.
SPELL FILE VERSIONS *E770* *E771* *E772*
@@ -1562,6 +1562,10 @@ CHECKCOMPOUNDTRIPLE (Hunspell) *spell-CHECKCOMPOUNDTRIPLE*
Forbid three identical characters when compounding. Not
supported.
+CHECKSHARPS (Hunspell)) *spell-CHECKSHARPS*
+ SS letter pair in uppercased (German) words may be upper case
+ sharp s (ß). Not supported.
+
COMPLEXPREFIXES (Hunspell) *spell-COMPLEXPREFIXES*
Enables using two prefixes. Not supported.
@@ -1575,12 +1579,21 @@ COMPOUNDFIRST (Hunspell) *spell-COMPOUNDFIRST*
Use COMPOUNDRULE instead. |spell-COMPOUNDRULE|
COMPOUNDBEGIN (Hunspell) *spell-COMPOUNDBEGIN*
+ Words signed with COMPOUNDBEGIN may be first elements in
+ compound words.
Use COMPOUNDRULE instead. |spell-COMPOUNDRULE|
-COMPOUNDEND (Hunspell) *spell-COMPOUNDEND*
+COMPOUNDLAST (Hunspell) *spell-COMPOUNDLAST*
+ Words signed with COMPOUNDLAST may be last elements in
+ compound words.
Use COMPOUNDRULE instead. |spell-COMPOUNDRULE|
+COMPOUNDEND (Hunspell) *spell-COMPOUNDEND*
+ Probably the same as COMPOUNDLAST
+
COMPOUNDMIDDLE (Hunspell) *spell-COMPOUNDMIDDLE*
+ Words signed with COMPOUNDMIDDLE may be middle elements in
+ compound words.
Use COMPOUNDRULE instead. |spell-COMPOUNDRULE|
COMPOUNDRULES (Hunspell) *spell-COMPOUNDRULES*
diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt
index 2a230d9449..fa4d87e915 100644
--- a/runtime/doc/starting.txt
+++ b/runtime/doc/starting.txt
@@ -257,7 +257,6 @@ argument.
*-D*
-D Debugging. Go to debugging mode when executing the first
command from a script. |debug-mode|
- {not available when compiled without the |+eval| feature}
*-n*
-n No |swap-file| will be used. Recovery after a crash will be
@@ -451,14 +450,10 @@ accordingly. Vim proceeds in this order:
- Environment variable $EXINIT, used as an Ex command line.
c. If the 'exrc' option is on (which is NOT the default), the current
- directory is searched for three files. The first that exists is used,
+ directory is searched for two files. The first that exists is used,
the others are ignored.
- - The file ".nvimrc" (for Unix)
- "_nvimrc" (for Win32)
- - The file "_nvimrc" (for Unix)
- ".nvimrc" (for Win32)
- - The file ".exrc" (for Unix)
- "_exrc" (for Win32)
+ - The file ".nvimrc"
+ - The file ".exrc"
4. Enable filetype and indent plugins.
This does the same as the commands: >
@@ -680,7 +675,7 @@ After doing this once, Nvim sets the $VIMRUNTIME environment variable.
In case you need the value of $VIMRUNTIME in a shell (e.g., for a script that
greps in the help files) you might be able to use this: >
- VIMRUNTIME="$(nvim -e --cmd 'echo $VIMRUNTIME|quit' 2>&1)"
+ VIMRUNTIME="$(nvim --clean --headless --cmd 'echo $VIMRUNTIME|q')"
==============================================================================
4. Suspending *suspend*
@@ -735,7 +730,7 @@ vimrc file.
options to [file] (default ".exrc" in the current
directory).
- *:mkv* *:mkvimrc*
+ *:mkv* *:mkvi* *:mkvimrc*
:mkv[imrc][!] [file] Like ":mkexrc", but the default is ".nvimrc" in the
current directory. The ":version" command is also
written to the file.
diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt
index b60a952def..e5b65554d4 100644
--- a/runtime/doc/syntax.txt
+++ b/runtime/doc/syntax.txt
@@ -346,20 +346,9 @@ Upon loading a file, Vim finds the relevant syntax file as follows:
syntax.
==============================================================================
-4. Syntax file remarks *:syn-file-remarks*
+4. Conversion to HTML *2html.vim* *convert-to-HTML*
- *b:current_syntax-variable*
-Vim stores the name of the syntax that has been loaded in the
-"b:current_syntax" variable. You can use this if you want to load other
-settings, depending on which syntax is active. Example: >
- :au BufReadPost * if b:current_syntax == "csh"
- :au BufReadPost * do-some-things
- :au BufReadPost * endif
-
-
-2HTML *2html.vim* *convert-to-HTML*
-
-This is not a syntax file itself, but a script that converts the current
+2html is not a syntax file itself, but a script that converts the current
window into HTML. Vim opens a new window in which it builds the HTML file.
After you save the resulting file, you can view it with any browser. The
@@ -649,12 +638,12 @@ the rendered page generated by 2html.vim.
:let g:html_no_pre = 1
<
*g:html_expand_tabs*
-Default: 1 if 'tabstop' is 8, 'expandtab' is 0, and no fold column or line
- numbers occur in the generated HTML;
- 0 otherwise.
-When 0, <Tab> characters in the buffer text are replaced with an appropriate
+Default: 0 if 'tabstop' is 8, 'expandtab' is 0, 'vartabstop' is not in use,
+ and no fold column or line numbers occur in the generated HTML;
+ 1 otherwise.
+When 1, <Tab> characters in the buffer text are replaced with an appropriate
number of space characters, or &nbsp; references if |g:html_no_pre| is 1.
-When 1, if |g:html_no_pre| is 0 or unset, <Tab> characters in the buffer text
+When 0, if |g:html_no_pre| is 0 or unset, <Tab> characters in the buffer text
are included as-is in the generated HTML. This is useful for when you want to
allow copy and paste from a browser without losing the actual whitespace in
the source document. Note that this can easily break text alignment and
@@ -751,6 +740,18 @@ When 1, generate XHTML 1.0 instead (XML compliant HTML).
>
:let g:html_use_xhtml = 1
<
+==============================================================================
+5. Syntax file remarks *:syn-file-remarks*
+
+ *b:current_syntax-variable*
+Vim stores the name of the syntax that has been loaded in the
+"b:current_syntax" variable. You can use this if you want to load other
+settings, depending on which syntax is active. Example: >
+ :au BufReadPost * if b:current_syntax == "csh"
+ :au BufReadPost * do-some-things
+ :au BufReadPost * endif
+
+
ABEL *abel.vim* *ft-abel-syntax*
@@ -917,6 +918,9 @@ to the respective variable. Example: >
To disable them use ":unlet". Example: >
:unlet c_comment_strings
+An alternative is to switch to the C++ highlighting: >
+ :set filetype=cpp
+
Variable Highlight ~
*c_gnu* GNU gcc specific items
*c_comment_strings* strings and numbers inside a comment
@@ -2587,7 +2591,6 @@ preceding last option and unsetting all other ones): >
Note: only existence of these options matter, not their value. You can replace
1 above with anything.
-
QUAKE *quake.vim* *ft-quake-syntax*
The Quake syntax definition should work for most any FPS (First Person
@@ -2666,9 +2669,29 @@ later, and part earlier) adds.
RESTRUCTURED TEXT *rst.vim* *ft-rst-syntax*
-You may set what syntax definitions should be used for code blocks via >
+Syntax highlighting is enabled for code blocks within the document for a
+select number of file types. See $VIMRUNTIME/syntax/rst.vim for the default
+syntax list.
+
+To set a user-defined list of code block syntax highlighting: >
let rst_syntax_code_list = ['vim', 'lisp', ...]
-<
+
+To assign multiple code block types to a single syntax, define
+`rst_syntax_code_list` as a mapping: >
+ let rst_syntax_code_list = {
+ \ 'cpp' = ['cpp', 'c++'],
+ \ 'bash' = ['bash', 'sh'],
+ ...
+ }
+
+To use color highlighting for emphasis text: >
+ let rst_use_emphasis_colors = 1
+
+To enable folding of sections: >
+ let rst_fold_enabled = 1
+
+Note that folding can cause performance issues on some platforms.
+
REXX *rexx.vim* *ft-rexx-syntax*
@@ -3084,7 +3107,7 @@ in your vimrc, and :set fdm=syntax. I suggest doing the latter via a
modeline at the end of your LaTeX file: >
% vim: fdm=syntax
If your system becomes too slow, then you might wish to look into >
- https://vimhelp.appspot.com/vim_faq.txt.html#faq-29.7
+ https://vimhelp.org/vim_faq.txt.html#faq-29.7
<
*g:tex_nospell*
Tex: No Spell Checking Wanted~
@@ -3437,7 +3460,7 @@ The syntax script for zsh allows for syntax-based folding: >
:let g:zsh_fold_enable = 1
==============================================================================
-5. Defining a syntax *:syn-define* *E410*
+6. Defining a syntax *:syn-define* *E410*
Vim understands three types of syntax items:
@@ -3796,7 +3819,7 @@ DEFINING REGIONS *:syn-region* *:syn-start* *:syn-skip* *:syn-end*
The maximum number of syntax groups is 19999.
==============================================================================
-6. :syntax arguments *:syn-arguments*
+7. :syntax arguments *:syn-arguments*
The :syntax commands that define syntax items take a number of arguments.
The common ones are explained here. The arguments may be given in any order
@@ -3962,7 +3985,6 @@ This will make each {} block form one fold.
The fold will start on the line where the item starts, and end where the item
ends. If the start and end are within the same line, there is no fold.
The 'foldnestmax' option limits the nesting of syntax folds.
-{not available when Vim was compiled without |+folding| feature}
*:syn-contains* *E405* *E406* *E407* *E408* *E409*
@@ -4117,7 +4139,7 @@ IMPLICIT CONCEAL *:syn-conceal-implicit*
Show either "syntax conceal on" or "syntax conceal off" (translated).
==============================================================================
-7. Syntax patterns *:syn-pattern* *E401* *E402*
+8. Syntax patterns *:syn-pattern* *E401* *E402*
In the syntax commands, a pattern must be surrounded by two identical
characters. This is like it works for the ":s" command. The most common to
@@ -4295,7 +4317,7 @@ Note that only matches within a single line can be used. Multi-line matches
cannot be referred to.
==============================================================================
-8. Syntax clusters *:syn-cluster* *E400*
+9. Syntax clusters *:syn-cluster* *E400*
:sy[ntax] cluster {cluster-name} [contains={group-name}..]
[add={group-name}..]
@@ -4341,7 +4363,7 @@ This also has implications for nested clusters: >
The maximum number of clusters is 9767.
==============================================================================
-9. Including syntax files *:syn-include* *E397*
+10. Including syntax files *:syn-include* *E397*
It is often useful for one language's syntax file to include a syntax file for
a related language. Depending on the exact relationship, this can be done in
@@ -4382,7 +4404,7 @@ two different ways:
The maximum number of includes is 999.
==============================================================================
-10. Synchronizing *:syn-sync* *E403* *E404*
+11. Synchronizing *:syn-sync* *E403* *E404*
Vim wants to be able to start redrawing in any position in the document. To
make this possible it needs to know the syntax state at the position where
@@ -4574,7 +4596,7 @@ You can clear specific sync patterns with: >
:syntax sync clear {sync-group-name} ..
==============================================================================
-11. Listing syntax items *:syntax* *:sy* *:syn* *:syn-list*
+12. Listing syntax items *:syntax* *:sy* *:syn* *:syn-list*
This command lists all the syntax items: >
@@ -4879,6 +4901,11 @@ guisp={color-name} *highlight-guisp*
All values are hexadecimal, range from "00" to "ff". Examples: >
:highlight Comment guifg=#11f0c3 guibg=#ff00ff
<
+blend={integer} *highlight-blend*
+ Override the blend level for a highlight group within the popupmenu
+ or floating windows. Only takes effect if 'pumblend' or 'winblend'
+ is set for the menu or window. See the help at the respective option.
+
*highlight-groups* *highlight-default*
These are the builtin highlighting groups. Note that the highlighting depends
on the value of 'background'. You can see the current settings with the
@@ -5082,7 +5109,7 @@ Without the "default" in the C syntax file, the highlighting would be
overruled when the syntax file is loaded.
==============================================================================
-14. Cleaning up *:syn-clear* *E391*
+15. Cleaning up *:syn-clear* *E391*
If you want to clear the syntax stuff for the current buffer, you can use this
command: >
@@ -5095,6 +5122,15 @@ load the syntax file.
The command also deletes the "b:current_syntax" variable, since no syntax is
loaded after this command.
+To clean up specific syntax groups for the current buffer: >
+ :syntax clear {group-name} ..
+This removes all patterns and keywords for {group-name}.
+
+To clean up specific syntax group lists for the current buffer: >
+ :syntax clear @{grouplist-name} ..
+This sets {grouplist-name}'s contents to an empty list.
+
+ *:syntax-off* *:syn-off*
If you want to disable syntax highlighting for all buffers, you need to remove
the autocommands that load the syntax files: >
:syntax off
@@ -5104,14 +5140,6 @@ What this command actually does, is executing the command >
See the "nosyntax.vim" file for details. Note that for this to work
$VIMRUNTIME must be valid. See |$VIMRUNTIME|.
-To clean up specific syntax groups for the current buffer: >
- :syntax clear {group-name} ..
-This removes all patterns and keywords for {group-name}.
-
-To clean up specific syntax group lists for the current buffer: >
- :syntax clear @{grouplist-name} ..
-This sets {grouplist-name}'s contents to an empty list.
-
*:syntax-reset* *:syn-reset*
If you have changed the colors and messed them up, use this command to get the
defaults back: >
@@ -5172,7 +5200,7 @@ syntax/syncolor.vim files are loaded:
them.
==============================================================================
-15. Highlighting tags *tag-highlight*
+16. Highlighting tags *tag-highlight*
If you want to highlight all the tags in your file, you can use the following
mappings.
@@ -5207,7 +5235,7 @@ And put these lines in your vimrc: >
autocmd BufRead,BufNewFile *.[ch] endif
==============================================================================
-16. Window-local syntax *:ownsyntax*
+17. Window-local syntax *:ownsyntax*
Normally all windows on a buffer share the same syntax settings. It is
possible, however, to set a particular window on a file to have its own
diff --git a/runtime/doc/tabpage.txt b/runtime/doc/tabpage.txt
index a0459d27bc..d0a5678179 100644
--- a/runtime/doc/tabpage.txt
+++ b/runtime/doc/tabpage.txt
@@ -74,8 +74,6 @@ For the related autocommands see |tabnew-autocmd|.
:[count]tabf[ind] [++opt] [+cmd] {file} *:tabf* *:tabfind*
Open a new tab page and edit {file} in 'path', like with
|:find|. For [count] see |:tabnew| above.
- {not available when the |+file_in_path| feature was disabled
- at compile time}
:[count]tab {cmd} *:tab*
Execute {cmd} and when it opens a new window open a new tab
diff --git a/runtime/doc/tagsrch.txt b/runtime/doc/tagsrch.txt
index a4526a7f2c..bb3134feb6 100644
--- a/runtime/doc/tagsrch.txt
+++ b/runtime/doc/tagsrch.txt
@@ -79,18 +79,21 @@ changed, to avoid confusion when using ":tnext". It is changed when using
":tag {name}".
The ignore-case matches are not found for a ":tag" command when:
-- the 'ignorecase' option is off and 'tagcase' is "followic"
+- 'tagcase' is "followic" and the 'ignorecase' option is off
+- 'tagcase' is "followscs" and the 'ignorecase' option is off and the
+ 'smartcase' option is off or the pattern contains an upper case character.
- 'tagcase' is "match"
- 'tagcase' is "smart" and the pattern contains an upper case character.
-- 'tagcase' is "followscs" and 'smartcase' option is on and the pattern
- contains an upper case character.
The ignore-case matches are found when:
- a pattern is used (starting with a "/")
- for ":tselect"
-- when 'tagcase' is "followic" and 'ignorecase' is off
-- when 'tagcase' is "match"
-- when 'tagcase' is "followscs" and the 'smartcase' option is off
+- when 'tagcase' is "followic" and 'ignorecase' is on
+- when 'tagcase' is "followscs" and 'ignorecase' is on or the 'smartcase'
+ option is on and the pattern does not contain an upper case character
+- when 'tagcase' is "ignore"
+- when 'tagcase' is "smart" and the patter does not contain an upper case
+ character
Note that using ignore-case tag searching disables binary searching in the
tags file, which causes a slowdown. This can be avoided by fold-case sorting
@@ -173,8 +176,8 @@ commands explained above the tag stack will look like this:
1 1 main 1 harddisk2:text/vim/test
2 1 FuncB 59 harddisk2:text/vim/src/main.c
-The gettagstack() function returns the tag stack of a specified window. The
-settagstack() function modifies the tag stack of a window.
+The |gettagstack()| function returns the tag stack of a specified window. The
+|settagstack()| function modifies the tag stack of a window.
*E73*
When you try to use the tag stack while it doesn't contain anything you will
@@ -300,7 +303,6 @@ message is given.
*tag-preview*
The tag match list can also be used in the preview window. The commands are
the same as above, with a "p" prepended.
-{not available when compiled without the |+quickfix| feature}
*:pts* *:ptselect*
:pts[elect][!] [name] Does ":tselect[!] [name]" and shows the new tag in a
@@ -488,7 +490,7 @@ Some programs that generate tags files:
ctags As found on most Unix systems. Only supports C. Only
does the basic work.
*Exuberant_ctags*
-exuberant ctags This a very good one. It works for C, C++, Java,
+exuberant ctags This is a very good one. It works for C, C++, Java,
Fortran, Eiffel and others. It can generate tags for
many items. See http://ctags.sourceforge.net.
JTags For Java, in Java. It can be found at
@@ -523,8 +525,7 @@ only supported by new versions of ctags (such as Exuberant ctags).
be any identifier. It cannot contain a <Tab>.
{TAB} One <Tab> character. Note: previous versions allowed any
white space here. This has been abandoned to allow spaces in
- {tagfile}. It can be re-enabled by including the
- |+tag_any_white| feature at compile time. *tag-any-white*
+ {tagfile}.
{tagfile} The file that contains the definition of {tagname}. It can
have an absolute or relative path. It may contain environment
variables and wildcards (although the use of wildcards is
@@ -536,7 +537,14 @@ only supported by new versions of ctags (such as Exuberant ctags).
{term} ;" The two characters semicolon and double quote. This is
interpreted by Vi as the start of a comment, which makes the
following be ignored. This is for backwards compatibility
- with Vi, it ignores the following fields.
+ with Vi, it ignores the following fields. Example:
+ APP file /^static int APP;$/;" v
+ When {tagaddress} is not a line number or search pattern, then
+ {term} must be |;". Here the bar ends the command (excluding
+ the bar) and ;" is used to have Vi ignore the rest of the
+ line. Example:
+ APP file.c call cursor(3, 4)|;" v
+
{field} .. A list of optional fields. Each field has the form:
<Tab>{fieldname}:{value}
@@ -572,8 +580,7 @@ ignored. (Case is ignored when 'ignorecase' is set and 'tagcase' is
The value '2' should be used then:
!_TAG_FILE_SORTED<Tab>2<Tab>{anything} ~
-The other tag that Vim recognizes, but only when compiled with the
-|+multi_byte| feature, is the encoding of the tags file:
+The other tag that Vim recognizes is the encoding of the tags file:
!_TAG_FILE_ENCODING<Tab>utf-8<Tab>{anything} ~
Here "utf-8" is the encoding used for the tags. Vim will then convert the tag
being searched for from 'encoding' to the encoding of the tags file. And when
@@ -804,7 +811,7 @@ CTRL-W d Open a new window, with the cursor on the first
(default: whole file).
See |:search-args| for [/] and [!].
- *:che* *:checkpath*
+ *:che* *:chec* *:check* *:checkpath*
:che[ckpath] List all the included files that could not be found.
:che[ckpath]! List all the included files.
diff --git a/runtime/doc/ui.txt b/runtime/doc/ui.txt
index ca10edccba..1440e2ac78 100644
--- a/runtime/doc/ui.txt
+++ b/runtime/doc/ui.txt
@@ -316,6 +316,14 @@ numerical highlight ids to the actual attributes.
`info` is an empty array by default, and will be used by the
|ui-hlstate| extension explained below.
+["hl_group_set", name, hl_id]
+ The bulitin highlight group `name` was set to use the attributes `hl_id`
+ defined by a previous `hl_attr_define` call. This event is not needed
+ to render the grids which use attribute ids directly, but is useful
+ for an UI who want to render its own elements with consistent
+ highlighting. For instance an UI using |ui-popupmenu| events, might
+ use the |hl-Pmenu| family of builtin highlights.
+
*ui-event-grid_line*
["grid_line", grid, row, col_start, cells]
Redraw a continuous part of a `row` on a `grid`, starting at the column
@@ -706,6 +714,7 @@ events, which the UI must handle.
"rpc_error" Error response from |rpcrequest()|
"return_prompt" |press-enter| prompt after a multiple messages
"quickfix" Quickfix navigation message
+ "search_count" Search count message ("S" flag of 'shortmess')
"wmsg" Warning ("search hit BOTTOM", |W10|, …)
New kinds may be added in the future; clients should treat unknown
kinds as the empty kind.
diff --git a/runtime/doc/usr_05.txt b/runtime/doc/usr_05.txt
index af17d75656..70a0ad97c1 100644
--- a/runtime/doc/usr_05.txt
+++ b/runtime/doc/usr_05.txt
@@ -11,12 +11,13 @@ Vim's capabilities. Or define your own macros.
|05.1| The vimrc file
|05.2| The example vimrc file explained
-|05.3| Simple mappings
-|05.4| Adding a package
-|05.5| Adding a plugin
-|05.6| Adding a help file
-|05.7| The option window
-|05.8| Often used options
+|05.3| The defaults.vim file explained
+|05.4| Simple mappings
+|05.5| Adding a package
+|05.6| Adding a plugin
+|05.7| Adding a help file
+|05.8| The option window
+|05.9| Often used options
Next chapter: |usr_06.txt| Using syntax highlighting
Previous chapter: |usr_04.txt| Making small changes
@@ -172,21 +173,12 @@ This switches on three very clever mechanisms:
automatically. Vim comes with these indent rules for a number of
filetypes. See |:filetype-indent-on| and 'indentexpr'.
->
- autocmd FileType text setlocal textwidth=78
-
-This makes Vim break text to avoid lines getting longer than 78 characters.
-But only for files that have been detected to be plain text. There are
-actually two parts here. "autocmd FileType text" is an autocommand. This
-defines that when the file type is set to "text" the following command is
-automatically executed. "setlocal textwidth=78" sets the 'textwidth' option
-to 78, but only locally in one file.
- *restore-cursor* >
- autocmd BufReadPost *
- \ if line("'\"") > 1 && line("'\"") <= line("$") |
- \ exe "normal! g`\"" |
- \ endif
+ *restore-cursor* *last-position-jump* >
+ autocmd BufReadPost *
+ \ if line("'\"") >= 1 && line("'\"") <= line("$") && &ft !~# 'commit'
+ \ | 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
@@ -195,8 +187,22 @@ from the previous line. That avoids a line getting very long.
See |line-continuation|. This only works in a Vim script file, not when
typing commands at the command-line.
+>
+ command DiffOrig vert new | set bt=nofile | r ++edit # | 0d_ | diffthis
+ \ | wincmd p | diffthis
+
+This adds the ":DiffOrig" command. Use this in a modified buffer to see the
+differences with the file it was loaded from. See |diff| and |:DiffOrig|.
+
+>
+ set nolangremap
+
+Prevent that the langmap option applies to characters that result from a
+mapping. If set (default), this may break plugins (but it's backward
+compatible). See 'langremap'.
+
==============================================================================
-*05.3* Simple mappings
+*05.4* Simple mappings
A mapping enables you to bind a set of Vim commands to a single key. Suppose,
for example, that you need to surround certain words with curly braces. In
@@ -243,7 +249,7 @@ The ":map" command (with no arguments) lists your current mappings. At
least the ones for Normal mode. More about mappings in section |40.1|.
==============================================================================
-*05.4* Adding a package *add-package* *vimball-install*
+*05.5* Adding a package *add-package* *vimball-install*
A package is a set of files that you can add to Vim. There are two kinds of
packages: optional and automatically loaded on startup.
@@ -283,12 +289,11 @@ an archive or as a repository. For an archive you can follow these steps:
More information about packages can be found here: |packages|.
==============================================================================
-*05.5* Adding a plugin *add-plugin* *plugin*
+*05.6* Adding a plugin *add-plugin* *plugin*
Vim's functionality can be extended by adding plugins. A plugin is nothing
more than a Vim script file that is loaded automatically when Vim starts. You
can add a plugin very easily by dropping it in your plugin directory.
-{not available when Vim was compiled without the |+eval| feature}
There are two types of plugins:
@@ -420,7 +425,7 @@ Further reading:
|new-filetype| How to detect a new file type.
==============================================================================
-*05.6* Adding a help file *add-local-help*
+*05.7* Adding a help file *add-local-help*
If you are lucky, the plugin you installed also comes with a help file. We
will explain how to install the help file, so that you can easily find help
@@ -453,7 +458,7 @@ them through the tag.
For writing a local help file, see |write-local-help|.
==============================================================================
-*05.7* The option window
+*05.8* The option window
If you are looking for an option that does what you want, you can search in
the help files here: |options|. Another way is by using this command: >
@@ -492,7 +497,7 @@ border. This is what the 'scrolloff' option does, it specifies an offset
from the window border where scrolling starts.
==============================================================================
-*05.8* Often used options
+*05.9* Often used options
There are an awful lot of options. Most of them you will hardly ever use.
Some of the more useful ones will be mentioned here. Don't forget you can
diff --git a/runtime/doc/usr_06.txt b/runtime/doc/usr_06.txt
index beffb92877..360f72ec63 100644
--- a/runtime/doc/usr_06.txt
+++ b/runtime/doc/usr_06.txt
@@ -193,13 +193,12 @@ too slow, you might want to disable syntax highlighting for a moment: >
When editing another file (or the same one) the colors will come back.
- *:syn-off*
If you want to stop highlighting completely use: >
:syntax off
This will completely disable syntax highlighting and remove it immediately for
-all buffers.
+all buffers. See |:syntax-off| for more details.
*:syn-manual*
If you want syntax highlighting only for specific files, use this: >
diff --git a/runtime/doc/usr_11.txt b/runtime/doc/usr_11.txt
index 42b564e962..c26f1e8f09 100644
--- a/runtime/doc/usr_11.txt
+++ b/runtime/doc/usr_11.txt
@@ -120,7 +120,7 @@ the resulting files if they are what you expected.
USING A SPECIFIC SWAP FILE
If you know which swap file needs to be used, you can recover by giving the
-swap file name. Vim will then finds out the name of the original file from
+swap file name. Vim will then find out the name of the original file from
the swap file.
Example: >
diff --git a/runtime/doc/usr_27.txt b/runtime/doc/usr_27.txt
index cd01308c6e..637523b9ee 100644
--- a/runtime/doc/usr_27.txt
+++ b/runtime/doc/usr_27.txt
@@ -474,19 +474,19 @@ the line break happens, because all items mentioned so far don't match a line
break.
To check for a line break in a specific place, use the "\n" item: >
- /the\nword
+ /one\ntwo
-This will match at a line that ends in "the" and the next line starts with
-"word". To match "the word" as well, you need to match a space or a line
+This will match at a line that ends in "one" and the next line starts with
+"two". To match "one two" as well, you need to match a space or a line
break. The item to use for it is "\_s": >
- /the\_sword
+ /one\_stwo
To allow any amount of white space: >
- /the\_s\+word
+ /one\_s\+two
-This also matches when "the " is at the end of a line and " word" at the
+This also matches when "one " is at the end of a line and " two" at the
start of the next one.
"\s" matches white space, "\_s" matches white space or a line break.
diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt
index def781c109..b26b7cb646 100644
--- a/runtime/doc/usr_41.txt
+++ b/runtime/doc/usr_41.txt
@@ -105,20 +105,21 @@ We won't explain how |:for| and |range()| work until later. Follow the links
if you are impatient.
-THREE KINDS OF NUMBERS
+FOUR KINDS OF NUMBERS
-Numbers can be decimal, hexadecimal or octal. A hexadecimal number starts
-with "0x" or "0X". For example "0x1f" is decimal 31. An octal number starts
-with a zero. "017" is decimal 15. Careful: don't put a zero before a decimal
-number, it will be interpreted as an octal number!
+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. "017" is decimal 15. A binary number starts with "0b" or
+"0B". For example "0b101" is decimal 5. Careful: don't put a zero before a
+decimal number, it will be interpreted as an octal number!
The ":echo" command always prints decimal numbers. Example: >
:echo 0x7f 036
< 127 30 ~
-A number is made negative with a minus sign. This also works for hexadecimal
-and octal numbers. A minus sign is also used for subtraction. Compare this
-with the previous example: >
+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
< 97 ~
@@ -612,6 +613,8 @@ String manipulation: *string-functions*
repeat() repeat a string multiple times
eval() evaluate a string expression
execute() execute an Ex command and get the output
+ win_execute() like execute() but in a specified window
+ trim() trim characters from a string
List manipulation: *list-functions*
get() get an item without error for wrong index
@@ -767,9 +770,13 @@ System functions and manipulation of files:
rename() rename a file
system() get the result of a shell command as a string
systemlist() get the result of a shell command as a list
+ environ() get all environment variables
+ getenv() get one environment variable
+ setenv() set an environment variable
hostname() name of the system
readfile() read a file into a List of lines
- writefile() write a List of lines into a file
+ readdir() get a List of file names in a directory
+ writefile() write a List of lines or Blob into a file
Date and Time: *date-functions* *time-functions*
getftime() get last modification time of a file
@@ -798,6 +805,9 @@ Buffers, windows and the argument list:
bufwinnr() get the window number of a specific buffer
winbufnr() get the buffer number of a specific window
getbufline() get a list of lines from the specified buffer
+ setbufline() replace a line in the specified buffer
+ appendbufline() append a list of lines in the specified buffer
+ deletebufline() delete lines from a specified buffer
win_findbuf() find windows containing a buffer
win_getid() get window ID of a window
win_gotoid() go to window with ID
@@ -808,6 +818,8 @@ Buffers, windows and the argument list:
getwininfo() get a list with window information
getchangelist() get a list of change list entries
getjumplist() get a list of jump list entries
+ swapinfo() information about a swap file
+ swapname() get the swap file path of a buffer
Command line: *command-line-functions*
getcmdline() get the current command line
@@ -890,6 +902,7 @@ GUI: *gui-functions*
getwinposy() Y position of the Vim window
balloon_show() set the balloon content
balloon_split() split a message for a balloon
+ balloon_gettext() get the text in the balloon
Vim server: *server-functions*
serverlist() return the list of server names
@@ -906,6 +919,7 @@ Window size and position: *window-size-functions*
winheight() get height of a specific window
winwidth() get width of a specific window
win_screenpos() get screen position of a window
+ winlayout() get layout of windows in a tab page
winrestcmd() return command to restore window sizes
winsaveview() get view of current window
winrestview() restore saved view of current window
@@ -928,6 +942,7 @@ Signs: *sign-functions*
Testing: *test-functions*
assert_equal() assert that two expressions values are equal
+ assert_equalfile() assert that two file contents are equal
assert_notequal() assert that two expressions values are not equal
assert_inrange() assert that an expression is inside a range
assert_match() assert that a pattern matches the value
@@ -940,7 +955,21 @@ Testing: *test-functions*
Timers: *timer-functions*
timer_start() create a timer
+ timer_pause() pause or unpause a timer
timer_stop() stop a timer
+ timer_stopall() stop all timers
+ timer_info() get information about timers
+
+Tags: *tag-functions*
+ taglist() get list of matching tags
+ tagfiles() get a list of tags files
+ gettagstack() get the tag stack of a window
+ settagstack() modify the tag stack of a window
+
+Prompt Buffer: *promptbuffer-functions*
+ prompt_setcallback() set prompt callback for a buffer
+ prompt_setinterrupt() set interrupt callback for a buffer
+ prompt_setprompt() set the prompt text for a buffer
Various: *various-functions*
mode() get current editing mode
@@ -969,15 +998,11 @@ Various: *various-functions*
wordcount() get byte/word/char count of buffer
- taglist() get list of matching tags
- tagfiles() get a list of tags files
- gettagstack() get the tag stack
- settagstack() modify the tag stack
-
luaeval() evaluate Lua expression
py3eval() evaluate Python expression (|+python3|)
pyeval() evaluate Python expression (|+python|)
pyxeval() evaluate |python_x| expression
+ debugbreak() interrupt a program being debugged
==============================================================================
*41.7* Defining a function
diff --git a/runtime/doc/usr_45.txt b/runtime/doc/usr_45.txt
index be33f0be6d..1ce6969d37 100644
--- a/runtime/doc/usr_45.txt
+++ b/runtime/doc/usr_45.txt
@@ -152,12 +152,6 @@ language than the text.
language, the default should work fine and you don't need to do anything. The
following is only relevant when you want to edit different languages.
- Note:
- Using different encodings only works when Vim was compiled to handle
- it. To find out if it works, use the ":version" command and check the
- output for "+multi_byte". If it's there, you are OK. If you see
- "-multi_byte" you will have to find another Vim.
-
USING UNICODE IN THE GUI
diff --git a/runtime/doc/usr_toc.txt b/runtime/doc/usr_toc.txt
index 148dd161ac..69846f1bcf 100644
--- a/runtime/doc/usr_toc.txt
+++ b/runtime/doc/usr_toc.txt
@@ -99,12 +99,13 @@ Read this from start to end to learn the essential commands.
|usr_05.txt| Set your settings
|05.1| The vimrc file
|05.2| The example vimrc file explained
- |05.3| Simple mappings
- |05.4| Adding a package
- |05.5| Adding a plugin
- |05.6| Adding a help file
- |05.7| The option window
- |05.8| Often used options
+ |05.3| The defaults.vim file explained
+ |05.4| Simple mappings
+ |05.5| Adding a package
+ |05.6| Adding a plugin
+ |05.7| Adding a help file
+ |05.8| The option window
+ |05.9| Often used options
|usr_06.txt| Using syntax highlighting
|06.1| Switching it on
diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt
index 2b6afcbdbc..32551815b0 100644
--- a/runtime/doc/various.txt
+++ b/runtime/doc/various.txt
@@ -12,22 +12,29 @@ Various commands *various*
1. Various commands *various-cmds*
*CTRL-L*
-CTRL-L Clear and redraw the screen. The redraw may happen
+CTRL-L Clears and redraws the screen. The redraw may happen
later, after processing typeahead.
+ *:mod* *:mode*
+:mod[e] Clears and redraws the screen.
+
*:redr* *:redraw*
-:redr[aw][!] Redraw the screen right now. When ! is included it is
- cleared first.
- Useful to update the screen halfway through executing
- a script or function (or a mapping if 'lazyredraw'
- set).
+:redr[aw][!] Redraws pending screen updates now, or the entire
+ screen if "!" is included. To CLEAR the screen use
+ |:mode| or |CTRL-L|.
+ Useful to update the screen during a script or
+ function (or a mapping if 'lazyredraw' set).
*:redraws* *:redrawstatus*
-:redraws[tatus][!] Redraw the status line of the current window. When !
- is included all status lines are redrawn.
- Useful to update the status line(s) when 'statusline'
- includes an item that doesn't cause automatic
- updating.
+:redraws[tatus][!] Redraws the status line of the current window, or all
+ status lines if "!" is included.
+ Useful if 'statusline' includes an item that doesn't
+ cause automatic updating.
+
+ *:redrawt* *:redrawtabline*
+:redrawt[abline] Redraw the tabline. Useful to update the tabline when
+ 'tabline' includes an item that doesn't trigger
+ automatic updating.
*N<Del>*
<Del> When entering a number: Remove the last digit.
@@ -276,7 +283,7 @@ g8 Print the hex values of the bytes used in the
*:!!*
:!! Repeat last ":!{cmd}".
- *:ve* *:version*
+ *:ve* *:ver* *:version*
:ve[rsion] Print editor version and build information.
See also |feature-compile|.
@@ -356,7 +363,20 @@ g8 Print the hex values of the bytes used in the
The pattern is matched against the relevant part of
the output, not necessarily the whole line. Only some
commands support filtering, try it out to check if it
- works.
+ works. Some of the commands that support filtering:
+ |:#| - filter whole line
+ |:clist| - filter by file name or module name
+ |:command| - filter by command name
+ |:files| - filter by file name
+ |:highlight| - filter by highlight group
+ |:jumps| - filter by file name
+ |:let| - filter by variable name
+ |:list| - filter whole line
+ |:llist| - filter by file name or module name
+ |:marks| - filter by text in the current file,
+ or file name for other files
+ |:oldfiles| - filter by file name
+ |:set| - filter by variable name
Only normal messages are filtered, error messages are
not.
@@ -431,7 +451,6 @@ or an autocommand will also display where it was last defined. If it was
defined manually then there will be no "Last set" message. When it was
defined while executing a function, user command or autocommand, the script in
which it was defined is reported.
-{not available when compiled without the |+eval| feature}
*K*
[count]K Run a program to lookup the keyword under the
diff --git a/runtime/doc/vi_diff.txt b/runtime/doc/vi_diff.txt
index d908f484c6..beecca2480 100644
--- a/runtime/doc/vi_diff.txt
+++ b/runtime/doc/vi_diff.txt
@@ -179,6 +179,12 @@ Command-line editing and history. |cmdline-editing|
forward/backward one character. The shifted right/left cursor keys
can be used to move forward/backward one word. CTRL-B/CTRL-E can be
used to go to the begin/end of the command-line.
+ {Vi: can only alter the last character in the line}
+ {Vi: when hitting <Esc> the command-line is executed. This is
+ unexpected for most people; therefore it was changed in Vim. But when
+ the <Esc> is part of a mapping, the command-line is executed. If you
+ want the Vi behaviour also when typing <Esc>, use ":cmap ^V<Esc>
+ ^V^M"}
|cmdline-history|
The command-lines are remembered. The up/down cursor keys can be used
to recall previous command-lines. The 'history' option can be set to
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index fd71067542..a358da460c 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -26,13 +26,14 @@ the differences.
- Syntax highlighting is enabled by default
- ":filetype plugin indent on" is enabled by default
-- 'autoindent' is set by default
-- 'autoread' is set by default
-- 'background' always defaults to "dark"
+- 'autoindent' is enabled
+- '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|)
- 'belloff' defaults to "all"
-- 'complete' doesn't include "i"
+- 'compatible' is always disabled
+- 'complete' excludes "i"
- 'cscopeverbose' is enabled
- 'directory' defaults to ~/.local/share/nvim/swap// (|xdg|), auto-created
- 'display' defaults to "lastline,msgsep"
@@ -41,27 +42,31 @@ the differences.
- 'formatoptions' defaults to "tcqj"
- 'fsync' is disabled
- 'history' defaults to 10000 (the maximum)
-- 'hlsearch' is set by default
-- 'incsearch' is set by default
-- 'langnoremap' is enabled by default
-- 'langremap' is disabled by default
+- 'hlsearch' is enabled
+- 'incsearch' is enabled
+- 'langnoremap' is enabled
+- 'langremap' is disabled
- 'laststatus' defaults to 2 (statusline is always shown)
- 'listchars' defaults to "tab:> ,trail:-,nbsp:+"
-- 'nocompatible' is always set
- 'nrformats' defaults to "bin,hex"
-- 'ruler' is set by default
-- 'sessionoptions' doesn't include "options"
+- 'ruler' is enabled
+- 'sessionoptions' excludes "options"
- 'shortmess' includes "F", excludes "S"
-- 'showcmd' is set by default
+- 'showcmd' is enabled
- 'sidescroll' defaults to 1
-- 'smarttab' is set by default
+- 'smarttab' is enabled
- 'tabpagemax' defaults to 50
- 'tags' defaults to "./tags;,tags"
- 'ttimeoutlen' defaults to 50
- 'ttyfast' is always set
- 'undodir' defaults to ~/.local/share/nvim/undo (|xdg|), auto-created
- 'viminfo' includes "!"
-- 'wildmenu' is set by default
+- 'wildmenu' is enabled
+- 'wildoptions' defaults to "pum,tagfile"
+
+- The |man.vim| plugin is enabled, to provide the |:Man| command.
+- The |matchit| plugin is enabled. To disable it in your config: >
+ :let loaded_matchit = 1
==============================================================================
3. New Features *nvim-features*
@@ -305,6 +310,9 @@ other arguments if used).
|input()| and |inputdialog()| support user-defined cmdline highlighting.
+Commands:
+ |:doautocmd| does not warn about "No matching autocommands".
+
Highlight groups:
|hl-ColorColumn|, |hl-CursorColumn| are lower priority than most other
groups
diff --git a/runtime/doc/visual.txt b/runtime/doc/visual.txt
index 252a1ca8b8..ccbbc092ec 100644
--- a/runtime/doc/visual.txt
+++ b/runtime/doc/visual.txt
@@ -103,6 +103,8 @@ gn Search forward for the last used search pattern, like
E.g., "dgn" deletes the text of the next match.
If Visual mode is active, extends the selection
until the end of the next match.
+ Note: Unlike `n` the search direction does not depend
+ on the previous search command.
*gN* *v_gN*
gN Like |gn| but searches backward, like with `N`.
@@ -290,8 +292,6 @@ mode.
==============================================================================
5. Blockwise operators *blockwise-operators*
-{not available when compiled without the |+visualextra| feature}
-
Reminder: Use 'virtualedit' to be able to select blocks that start or end
after the end of a line or halfway through a tab.
diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt
index 63ffd91bfc..76bb096ee3 100644
--- a/runtime/doc/windows.txt
+++ b/runtime/doc/windows.txt
@@ -64,6 +64,10 @@ will not change within a Vim session. The |win_getid()| and |win_id2tabwin()|
functions can be used to convert between the window/tab number and the
identifier. There is also the window number, which may change whenever
windows are opened or closed, see |winnr()|.
+The window number is only valid in one specific tab. The window ID is valid
+across tabs. For most functions that take a window ID or a window number, the
+window number only applies to the current tab, while the window ID can refer
+to a window in any tab.
Each buffer has a unique number and the number will not change within a Vim
session. The |bufnr()| and |bufname()| functions can be used to convert
@@ -134,6 +138,10 @@ CTRL-W CTRL-S *CTRL-W_CTRL-S*
Note: CTRL-S does not work on all terminals and might block
further input, use CTRL-Q to get going again.
Also see |++opt| and |+cmd|.
+ *E242*
+ Be careful when splitting a window in an autocommand, it may
+ mess up the window layout if this happens while making other
+ window layout changes.
CTRL-W CTRL-V *CTRL-W_CTRL-V*
CTRL-W v *CTRL-W_v*
@@ -188,7 +196,7 @@ CTRL-W CTRL_N *CTRL-W_CTRL-N*
:[N]sv[iew] [++opt] [+cmd] {file} *:sv* *:sview* *splitview*
Same as ":split", but set 'readonly' option for this buffer.
-:[N]sf[ind] [++opt] [+cmd] {file} *:sf* *:sfind* *splitfind*
+:[N]sf[ind] [++opt] [+cmd] {file} *:sf* *:sfi* *:sfind* *splitfind*
Same as ":split", but search for {file} in 'path' like in
|:find|. Doesn't split if {file} is not found.
@@ -401,7 +409,6 @@ CTRL-W CTRL-P Go to previous (last accessed) window.
*CTRL-W_P* *E441*
CTRL-W P Go to preview window. When there is no preview window this is
an error.
- {not available when compiled without the |+quickfix| feature}
If Visual mode is active and the new window is not for the same buffer, the
Visual mode is ended. If the window is on the same buffer, the cursor
@@ -520,9 +527,6 @@ CTRL-W > Increase current window width by N (default 1).
:vertical res[ize] [N] *:vertical-resize* *CTRL-W_bar*
CTRL-W | Set current window width to N (default: widest possible).
- *:mod* *:mode*
-:mod[e] Detects the screen size and redraws the screen.
-
You can also resize a window by dragging a status line up or down with the
mouse. Or by dragging a vertical separator line left or right. This only
works if the version of Vim that is being used supports the mouse and the
@@ -634,6 +638,8 @@ can also get to them with the buffer list commands, like ":bnext".
|:vertical| was prepended).
Buf/Win Enter/Leave autocommands are not executed for the new
windows here, that's only done when they are really entered.
+ If autocommands change the window layout while this command is
+ busy an error will be given. *E249*
:[N]sa[rgument][!] [++opt] [+cmd] [N] *:sa* *:sargument*
Short for ":split | argument [N]": split window and go to Nth
@@ -781,30 +787,28 @@ CTRL-W CTRL-F Split current window in two. Edit file name under cursor.
If the name is a hypertext link that looks like
"type://machine/path", only "/path" is used.
If a count is given, the count'th matching file is edited.
- {not available when the |+file_in_path| feature was disabled
- at compile time}
CTRL-W F *CTRL-W_F*
Split current window in two. Edit file name under cursor and
jump to the line number following the file name. See |gF| for
details on how the line number is obtained.
- {not available when the |+file_in_path| feature was disabled
- at compile time}
CTRL-W gf *CTRL-W_gf*
Open a new tab page and edit the file name under the cursor.
Like "tab split" and "gf", but the new tab page isn't created
if the file does not exist.
- {not available when the |+file_in_path| feature was disabled
- at compile time}
CTRL-W gF *CTRL-W_gF*
Open a new tab page and edit the file name under the cursor
and jump to the line number following the file name. Like
"tab split" and "gF", but the new tab page isn't created if
the file does not exist.
- {not available when the |+file_in_path| feature was disabled
- at compile time}
+
+CTRL-W gt *CTRL-W_gt*
+ Go to next tab page, same as `gt`.
+
+CTRL-W gT *CTRL-W_gT*
+ Go to previous tab page, same as `gT`.
Also see |CTRL-W_CTRL-I|: open window for an included file that includes
the keyword under the cursor.
@@ -815,7 +819,6 @@ the keyword under the cursor.
The preview window is a special window to show (preview) another file. It is
normally a small window used to show an include file or definition of a
function.
-{not available when compiled without the |+quickfix| feature}
There can be only one preview window (per tab page). It is created with one
of the commands below. The 'previewheight' option can be set to specify the
@@ -942,7 +945,6 @@ is no word under the cursor, and a few other things: >
A hidden buffer is not displayed in a window, but is still loaded into memory.
This makes it possible to jump from file to file, without the need to read or
write the file every time you get another buffer in a window.
-{not available when compiled without the |+listcmds| feature}
*:buffer-!*
If the option 'hidden' ('hid') is set, abandoned buffers are kept for all
@@ -1147,7 +1149,6 @@ list of buffers. |unlisted-buffer|
the way when you're browsing code/text buffers. The next three
commands also work like this.
-
*:sbn* *:sbnext*
:[N]sbn[ext] [+cmd] [N]
Split window and go to [N]th next buffer in buffer list.
@@ -1168,7 +1169,7 @@ list of buffers. |unlisted-buffer|
Uses 'switchbuf'.
Also see |+cmd|.
-:br[ewind][!] [+cmd] *:br* *:brewind*
+:br[ewind][!] [+cmd] *:br* *:bre* *:brewind*
Go to first buffer in buffer list. If the buffer list is
empty, go to the first unlisted buffer.
See |:buffer-!| for [!].
diff --git a/runtime/filetype.vim b/runtime/filetype.vim
index a670f54898..4cc2f49a63 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: 2018 Feb 14
+" Last Change: 2019 Jul 27
" Listen very carefully, I will say this only once
if exists("did_load_filetypes")
@@ -42,6 +42,8 @@ endif
" Function used for patterns that end in a star: don't set the filetype if the
" file name matches ft_ignore_pat.
+" When using this, the entry should probably be further down below with the
+" other StarSetf() calls.
func! s:StarSetf(ft)
if expand("<amatch>") !~ g:ft_ignore_pat
exe 'setf ' . a:ft
@@ -54,6 +56,9 @@ au BufNewFile,BufRead $VIMRUNTIME/doc/*.txt setf help
" Abaqus or Trasys
au BufNewFile,BufRead *.inp call dist#ft#Check_inp()
+" 8th (Firth-derivative)
+au BufNewFile,BufRead *.8th setf 8th
+
" A-A-P recipe
au BufNewFile,BufRead *.aap setf aap
@@ -88,11 +93,9 @@ au BufNewFile,BufRead build.xml setf ant
" Arduino
au BufNewFile,BufRead *.ino,*.pde setf arduino
-" Apache style config file
-au BufNewFile,BufRead proftpd.conf* call s:StarSetf('apachestyle')
-
" Apache config file
au BufNewFile,BufRead .htaccess,*/etc/httpd/*.conf setf apache
+au BufNewFile,BufRead */etc/apache2/sites-*/*.com setf apache
" XA65 MOS6510 cross assembler
au BufNewFile,BufRead *.a65 setf a65
@@ -647,7 +650,6 @@ au BufNewFile,BufRead gnashrc,.gnashrc,gnashpluginrc,.gnashpluginrc setf gnash
" Gitolite
au BufNewFile,BufRead gitolite.conf setf gitolite
-au BufNewFile,BufRead */gitolite-admin/conf/* call s:StarSetf('gitolite')
au BufNewFile,BufRead {,.}gitolite.rc,example.gitolite.rc setf perl
" Gnuplot scripts
@@ -796,7 +798,6 @@ au BufNewFile,BufRead *.jsp setf jsp
" Java Properties resource file (note: doesn't catch font.properties.pl)
au BufNewFile,BufRead *.properties,*.properties_??,*.properties_??_?? setf jproperties
-au BufNewFile,BufRead *.properties_??_??_* call s:StarSetf('jproperties')
" Jess
au BufNewFile,BufRead *.clp setf jess
@@ -1169,6 +1170,10 @@ au BufNewFile,BufRead *.rcp setf pilrc
" Pine config
au BufNewFile,BufRead .pinerc,pinerc,.pinercex,pinercex setf pine
+" Pipenv Pipfiles
+au BufNewFile,BufRead Pipfile setf config
+au BufNewFile,BufRead Pipfile.lock setf json
+
" PL/1, PL/I
au BufNewFile,BufRead *.pli,*.pl1 setf pli
@@ -1454,7 +1459,6 @@ au BufNewFile,BufRead *.decl,*.dcl,*.dec
" SGML catalog file
au BufNewFile,BufRead catalog setf catalog
-au BufNewFile,BufRead sgml.catalog* call s:StarSetf('catalog')
" Shell scripts (sh, ksh, bash, bash2, csh); Allow .profile_foo etc.
" Gentoo ebuilds and Arch Linux PKGBUILDs are actually bash scripts
@@ -1609,6 +1613,10 @@ au BufNewFile,BufRead */etc/sysctl.conf,*/etc/sysctl.d/*.conf setf sysctl
" Systemd unit files
au BufNewFile,BufRead */systemd/*.{automount,mount,path,service,socket,swap,target,timer} setf systemd
+" Systemd overrides
+au BufNewFile,BufRead /etc/systemd/system/*.d/*.conf setf systemd
+" Systemd temp files
+au BufNewFile,BufRead /etc/systemd/system/*.d/.#* setf systemd
" Synopsys Design Constraints
au BufNewFile,BufRead *.sdc setf sdc
@@ -1737,7 +1745,6 @@ au BufNewFile,BufRead *.sv,*.svh setf systemverilog
" VHDL
au BufNewFile,BufRead *.hdl,*.vhd,*.vhdl,*.vbe,*.vst setf vhdl
-au BufNewFile,BufRead *.vhdl_[0-9]* call s:StarSetf('vhdl')
" Vim script
au BufNewFile,BufRead *.vim,*.vba,.exrc,_exrc setf vim
@@ -1768,12 +1775,15 @@ au BufNewFile,BufRead *.wrl setf vrml
" Vroom (vim testing and executable documentation)
au BufNewFile,BufRead *.vroom setf vroom
-" Webmacro
-au BufNewFile,BufRead *.wm setf webmacro
+" Vue.js Single File Component
+au BufNewFile,BufRead *.vue setf vue
" WebAssembly
au BufNewFile,BufRead *.wast,*.wat setf wast
+" Webmacro
+au BufNewFile,BufRead *.wm setf webmacro
+
" Wget config
au BufNewFile,BufRead .wgetrc,wgetrc setf wget
@@ -1859,7 +1869,8 @@ au BufNewFile,BufRead *.xmi setf xml
au BufNewFile,BufRead *.csproj,*.csproj.user setf xml
" Qt Linguist translation source and Qt User Interface Files are XML
-au BufNewFile,BufRead *.ts,*.ui setf xml
+" However, for .ts Typescript is more common.
+au BufNewFile,BufRead *.ui setf xml
" TPM's are RDF-based descriptions of TeX packages (Nikolai Weibull)
au BufNewFile,BufRead *.tpm setf xml
@@ -1950,6 +1961,7 @@ au StdinReadPost * if !did_filetype() | runtime! scripts.vim | endif
" More Apache style config files
au BufNewFile,BufRead */etc/proftpd/*.conf*,*/etc/proftpd/conf.*/* call s:StarSetf('apachestyle')
+au BufNewFile,BufRead proftpd.conf* call s:StarSetf('apachestyle')
" More Apache config files
au BufNewFile,BufRead access.conf*,apache.conf*,apache2.conf*,httpd.conf*,srm.conf* call s:StarSetf('apache')
@@ -2006,6 +2018,12 @@ au BufNewFile,BufRead *fvwm2rc*
" Gedcom
au BufNewFile,BufRead */tmp/lltmp* call s:StarSetf('gedcom')
+" Git
+au BufNewFile,BufRead */.gitconfig.d/*,/etc/gitconfig.d/* call s:StarSetf('gitconfig')
+
+" Gitolite
+au BufNewFile,BufRead */gitolite-admin/conf/* call s:StarSetf('gitolite')
+
" GTK RC
au BufNewFile,BufRead .gtkrc*,gtkrc* call s:StarSetf('gtkrc')
@@ -2018,6 +2036,9 @@ au! BufNewFile,BufRead *jarg*
\| call s:StarSetf('jargon')
\|endif
+" Java Properties resource file (note: doesn't catch font.properties.pl)
+au BufNewFile,BufRead *.properties_??_??_* call s:StarSetf('jproperties')
+
" Kconfig
au BufNewFile,BufRead Kconfig.* call s:StarSetf('kconfig')
@@ -2079,6 +2100,9 @@ au BufRead,BufNewFile *.rdf call dist#ft#Redif()
" Remind
au BufNewFile,BufRead .reminders* call s:StarSetf('remind')
+" SGML catalog file
+au BufNewFile,BufRead sgml.catalog* call s:StarSetf('catalog')
+
" Shell scripts ending in a star
au BufNewFile,BufRead .bashrc*,.bash[_-]profile*,.bash[_-]logout*,.bash[_-]aliases*,bash-fc[-.]*,,PKGBUILD* call dist#ft#SetFileTypeSH("bash")
au BufNewFile,BufRead .kshrc* call dist#ft#SetFileTypeSH("ksh")
@@ -2090,6 +2114,9 @@ au BufNewFile,BufRead .tcshrc* call dist#ft#SetFileTypeShell("tcsh")
" csh scripts ending in a star
au BufNewFile,BufRead .login*,.cshrc* call dist#ft#CSH()
+" VHDL
+au BufNewFile,BufRead *.vhdl_[0-9]* call s:StarSetf('vhdl')
+
" Vim script
au BufNewFile,BufRead *vimrc* call s:StarSetf('vim')
diff --git a/runtime/ftplugin/8th.vim b/runtime/ftplugin/8th.vim
new file mode 100644
index 0000000000..14301187d6
--- /dev/null
+++ b/runtime/ftplugin/8th.vim
@@ -0,0 +1,25 @@
+" Vim ftplugin file
+" Language: 8th
+" Version: any
+" Last Change: 2015/11/08
+" Maintainer: Ron Aaron <ron@aaron-tech.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
+" This goes with the syntax/8th.vim file.
+
+" Only do this when not done yet for this buffer
+if exists("b:did_8thplugin")
+ finish
+endif
+
+" Don't load another plugin for this buffer
+let b:did_8thplugin = 1
+
+setlocal ts=2 sts=2 sw=2 et
+setlocal com=s1:/*,mb:*,ex:*/,:\|,:\\
+setlocal fo=tcrqol
+setlocal matchpairs+=\::;
+setlocal iskeyword=!,@,33-35,%,$,38-64,A-Z,91-96,a-z,123-126,128-255
+setlocal suffixesadd=.8th
diff --git a/runtime/ftplugin/bash.vim b/runtime/ftplugin/bash.vim
new file mode 100644
index 0000000000..a3d01fc2ad
--- /dev/null
+++ b/runtime/ftplugin/bash.vim
@@ -0,0 +1,31 @@
+" Vim filetype plugin file
+" Language: bash
+" Maintainer: Bram Moolenaar
+" Last Changed: 2019 Jan 12
+"
+" This is not a real filetype plugin. It allows for someone to set 'filetype'
+" to "bash" in the modeline, and gets the effect of filetype "sh" with
+" b:is_bash set. Idea from Mahmode Al-Qudsi.
+
+if exists("b:did_ftplugin")
+ finish
+endif
+
+let b:is_bash = 1
+if exists("b:is_sh")
+ unlet b:is_sh
+endif
+if exists("b:is_kornshell")
+ unlet b:is_kornshell
+endif
+
+" Setting 'filetype' here directly won't work, since we are being invoked
+" through an autocommand. Do it later, on the BufWinEnter event.
+augroup bash_filetype
+ au BufWinEnter * call SetBashFt()
+augroup END
+
+func SetBashFt()
+ au! bash_filetype
+ set ft=sh
+endfunc
diff --git a/runtime/ftplugin/cfg.vim b/runtime/ftplugin/cfg.vim
new file mode 100644
index 0000000000..b5835ba7a9
--- /dev/null
+++ b/runtime/ftplugin/cfg.vim
@@ -0,0 +1,19 @@
+" Vim filetype plugin file
+" Language: Configuration File
+" Maintainer: Christian Brabandt <cb@256bit.org>
+" Latest Revision: 2018-12-24
+
+if exists("b:did_ftplugin")
+ finish
+endif
+let b:did_ftplugin = 1
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+let b:undo_ftplugin = "setl cms< fo<"
+
+setlocal commentstring=#\ %s formatoptions-=t formatoptions+=croql
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
diff --git a/runtime/ftplugin/cobol.vim b/runtime/ftplugin/cobol.vim
index 11ad3ad727..d96a1bf281 100644
--- a/runtime/ftplugin/cobol.vim
+++ b/runtime/ftplugin/cobol.vim
@@ -1,7 +1,8 @@
" Vim filetype plugin file
" Language: cobol
-" Author: Tim Pope <vimNOSPAM@tpope.info>
-" Last Update: By ZyX: use shiftwidth()
+" Maintainer: Ankit Jain <ajatkj@yahoo.co.in>
+" (formerly Tim Pope <vimNOSPAM@tpope.info>)
+" Last Update: By Ankit Jain (changed maintainer) on 22.03.2019
" Insert mode mappings: <C-T> <C-D> <Tab>
" Normal mode mappings: < > << >> [[ ]] [] ][
diff --git a/runtime/ftplugin/dosbatch.vim b/runtime/ftplugin/dosbatch.vim
index dbc02d80f8..070bdc4ba2 100644
--- a/runtime/ftplugin/dosbatch.vim
+++ b/runtime/ftplugin/dosbatch.vim
@@ -1,7 +1,7 @@
" Vim filetype plugin file
" Language: MS-DOS .bat files
" Maintainer: Mike Williams <mrw@eandem.co.uk>
-" Last Change: 8th May 2012
+" Last Change: 14th April 2019
" Only do this when not done yet for this buffer
if exists("b:did_ftplugin")
@@ -16,6 +16,7 @@ set cpo&vim
" BAT comment formatting
setlocal comments=b:rem,b:@rem,b:REM,b:@REM,:::
+setlocal commentstring=::\ %s
setlocal formatoptions-=t formatoptions+=rol
" Define patterns for the browse file filter
diff --git a/runtime/ftplugin/dune.vim b/runtime/ftplugin/dune.vim
new file mode 100644
index 0000000000..8b1f8b4125
--- /dev/null
+++ b/runtime/ftplugin/dune.vim
@@ -0,0 +1,20 @@
+" Language: Dune buildsystem
+" Maintainer: Markus Mottl <markus.mottl@gmail.com>
+" Anton Kochkov <anton.kochkov@gmail.com>
+" URL: https://github.com/rgrinberg/vim-ocaml
+" Last Change:
+" 2018 Nov 3 - Added commentstring (Markus Mottl)
+" 2017 Sep 6 - Initial version (Etienne Millon)
+
+if exists("b:did_ftplugin")
+ finish
+endif
+let b:did_ftplugin=1
+
+set lisp
+
+" Comment string
+setl commentstring=;\ %s
+setl comments=:;
+
+setl iskeyword+=#,?,.,/
diff --git a/runtime/ftplugin/eruby.vim b/runtime/ftplugin/eruby.vim
index 32f3fb868f..3c18bada78 100644
--- a/runtime/ftplugin/eruby.vim
+++ b/runtime/ftplugin/eruby.vim
@@ -3,6 +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
" Only do this when not done yet for this buffer
if exists("b:did_ftplugin")
@@ -27,7 +28,7 @@ elseif !exists("b:eruby_subtype")
let s:lines = getline(1)."\n".getline(2)."\n".getline(3)."\n".getline(4)."\n".getline(5)."\n".getline("$")
let b:eruby_subtype = matchstr(s:lines,'eruby_subtype=\zs\w\+')
if b:eruby_subtype == ''
- let b:eruby_subtype = matchstr(substitute(expand("%:t"),'\c\%(\.erb\|\.eruby\|\.erubis\)\+$','',''),'\.\zs\w\+\%(\ze+\w\+\)\=$')
+ let b:eruby_subtype = matchstr(substitute(expand("%:t"),'\c\%(\.erb\|\.eruby\|\.erubis\|\.example\)\+$','',''),'\.\zs\w\+\%(\ze+\w\+\)\=$')
endif
if b:eruby_subtype == 'rhtml'
let b:eruby_subtype = 'html'
@@ -45,7 +46,7 @@ elseif !exists("b:eruby_subtype")
endif
endif
-if exists("b:eruby_subtype") && b:eruby_subtype != ''
+if exists("b:eruby_subtype") && b:eruby_subtype != '' && b:eruby_subtype !=? 'eruby'
exe "runtime! ftplugin/".b:eruby_subtype.".vim ftplugin/".b:eruby_subtype."_*.vim ftplugin/".b:eruby_subtype."/*.vim"
else
runtime! ftplugin/html.vim ftplugin/html_*.vim ftplugin/html/*.vim
@@ -66,6 +67,21 @@ if exists("b:match_words")
unlet b:match_words
endif
+let s:cfilemap = v:version >= 704 ? maparg('<Plug><cfile>', 'c', 0, 1) : {}
+if !get(s:cfilemap, 'buffer') || !s:cfilemap.expr || s:cfilemap.rhs =~# 'ErubyAtCursor()'
+ let s:cfilemap = {}
+endif
+if !has_key(s:cfilemap, 'rhs')
+ let s:cfilemap.rhs = "substitute(&l:inex =~# '\\<v:fname\\>' && len(expand('<cfile>')) ? eval(substitute(&l:inex, '\\<v:fname\\>', '\\=string(expand(\"<cfile>\"))', 'g')) : '', '^$', \"\\022\\006\",'')"
+endif
+let s:ctagmap = v:version >= 704 ? maparg('<Plug><ctag>', 'c', 0, 1) : {}
+if !get(s:ctagmap, 'buffer') || !s:ctagmap.expr || s:ctagmap.rhs =~# 'ErubyAtCursor()'
+ let s:ctagmap = {}
+endif
+let s:include = &l:include
+let s:path = &l:path
+let s:suffixesadd = &l:suffixesadd
+
runtime! ftplugin/ruby.vim ftplugin/ruby_*.vim ftplugin/ruby/*.vim
let b:did_ftplugin = 1
@@ -80,6 +96,15 @@ if exists("b:match_words")
let s:match_words = b:match_words . ',' . s:match_words
endif
+if len(s:include)
+ let &l:include = s:include
+endif
+let &l:path = s:path . (s:path =~# ',$\|^$' ? '' : ',') . &l:path
+let &l:suffixesadd = s:suffixesadd . (s:suffixesadd =~# ',$\|^$' ? '' : ',') . &l:suffixesadd
+exe 'cmap <buffer><script><expr> <Plug><cfile> ErubyAtCursor() ? ' . maparg('<Plug><cfile>', 'c') . ' : ' . s:cfilemap.rhs
+exe 'cmap <buffer><script><expr> <Plug><ctag> ErubyAtCursor() ? ' . maparg('<Plug><ctag>', 'c') . ' : ' . get(s:ctagmap, 'rhs', '"\022\027"')
+unlet s:cfilemap s:ctagmap s:include s:path s:suffixesadd
+
" Change the browse dialog on Win32 to show mainly eRuby-related files
if has("gui_win32")
let b:browsefilter="eRuby Files (*.erb, *.rhtml)\t*.erb;*.rhtml\n" . s:browsefilter
@@ -99,4 +124,9 @@ let b:undo_ftplugin = "setl cms< "
let &cpo = s:save_cpo
unlet s:save_cpo
+function! ErubyAtCursor() abort
+ let groups = map(['erubyBlock', 'erubyComment', 'erubyExpression', 'erubyOneLiner'], 'hlID(v:val)')
+ return !empty(filter(synstack(line('.'), col('.')), 'index(groups, v:val) >= 0'))
+endfunction
+
" vim: nowrap sw=2 sts=2 ts=8:
diff --git a/runtime/ftplugin/help.vim b/runtime/ftplugin/help.vim
index 0f448bd306..a6a6652b2f 100644
--- a/runtime/ftplugin/help.vim
+++ b/runtime/ftplugin/help.vim
@@ -1,7 +1,7 @@
" Vim filetype plugin file
" Language: Vim help file
" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
-" Latest Revision: 2008-07-09
+" Latest Revision: 2018-12-29
if exists("b:did_ftplugin")
finish
diff --git a/runtime/ftplugin/logcheck.vim b/runtime/ftplugin/logcheck.vim
index 7d4671d875..9d664b2d09 100644
--- a/runtime/ftplugin/logcheck.vim
+++ b/runtime/ftplugin/logcheck.vim
@@ -1,16 +1,16 @@
" Vim filetype plugin file
" Language: Logcheck
-" Maintainer: Debian Vim Maintainers <pkg-vim-maintainers@lists.alioth.debian.org>
-" Last Change: 2012 Jan 15
+" Maintainer: Debian Vim Maintainers
+" Last Change: 2018 Dec 27
" License: Vim License
-" URL: http://hg.debian.org/hg/pkg-vim/vim/file/unstable/runtime/ftplugin/logcheck.vim
+" URL: https://salsa.debian.org/vim-team/vim-debian/blob/master/ftplugin/logcheck.vim
-if exists("b:did_ftplugin")
+if exists('b:did_ftplugin')
finish
endif
let b:did_ftplugin = 1
-let b:undo_ftplugin = "setl fo<"
+let b:undo_ftplugin = 'setl fo<'
" Do not hard-wrap non-comment lines since each line is a self-contained
" regular expression
diff --git a/runtime/ftplugin/make.vim b/runtime/ftplugin/make.vim
index fb180c0e5f..bfa8703082 100644
--- a/runtime/ftplugin/make.vim
+++ b/runtime/ftplugin/make.vim
@@ -1,7 +1,7 @@
" Vim filetype plugin file
" Language: Make
" Maintainer: Bram Moolenaar <Bram@vim.org>
-" Last Change: 2013 Apr 22
+" Last Change: 2019 Apr 02
" Only do this when not done yet for this buffer
if exists("b:did_ftplugin")
@@ -27,7 +27,7 @@ setlocal commentstring=#\ %s
" Including files.
let &l:include = '^\s*include'
-" For matchit.vim, suggested by Albert Netymk.
+" For matchit.vim, suggested by Albert Netymk and Ken Takata.
if exists("loaded_matchit")
- let b:match_words = '\<if\(n\)\=\(eq\|def\)\>:\<else\>:\<endif\>,\<define\>:\<endef\>'
+ let b:match_words = '^ *ifn\=\(eq\|def\)\>:^ *else\(\s\+ifn\=\(eq\|def\)\)\=\>:^ *endif\>,\<define\>:\<endef\>,^!\s*if\(n\=def\)\=\>:^!\s*else\(if\(n\=def\)\=\)\=\>:^!\s*endif\>'
endif
diff --git a/runtime/ftplugin/mma.vim b/runtime/ftplugin/mma.vim
new file mode 100644
index 0000000000..ce4cee18ae
--- /dev/null
+++ b/runtime/ftplugin/mma.vim
@@ -0,0 +1,16 @@
+" Vim filetype plugin file
+" Language: Mathematica
+" Maintainer: Ian Ford <ianf@wolfram.com>
+" Last Change: 22 January 2019
+
+" 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
+
+let b:undo_ftplugin = "setlocal commentstring<"
+
+setlocal commentstring=\(*%s*\)
diff --git a/runtime/ftplugin/nroff.vim b/runtime/ftplugin/nroff.vim
new file mode 100644
index 0000000000..069c02e59a
--- /dev/null
+++ b/runtime/ftplugin/nroff.vim
@@ -0,0 +1,11 @@
+" Vim filetype plugin
+" Language: roff(7)
+" Maintainer: Chris Spiegel <cspiegel@gmail.com>
+" Last Change: 2019 Apr 24
+
+if exists("b:did_ftplugin")
+ finish
+endif
+let b:did_ftplugin = 1
+
+setlocal commentstring=.\\\"%s
diff --git a/runtime/ftplugin/ocaml.vim b/runtime/ftplugin/ocaml.vim
index 3ee7849063..d9336421cf 100644
--- a/runtime/ftplugin/ocaml.vim
+++ b/runtime/ftplugin/ocaml.vim
@@ -5,12 +5,12 @@
" Pierre Vittet <pierre-vittet@pvittet.com>
" Stefano Zacchiroli <zack@bononia.it>
" Vincent Aravantinos <firstname.name@imag.fr>
-" URL: http://www.ocaml.info/vim/ftplugin/ocaml.vim
+" URL: https://github.com/rgrinberg/vim-ocaml
" Last Change:
+" 2013 Oct 27 - Added commentstring (MM)
" 2013 Jul 26 - load default compiler settings (MM)
" 2013 Jul 24 - removed superfluous efm-setting (MM)
" 2013 Jul 22 - applied fixes supplied by Hirotaka Hamada (MM)
-" 2013 Mar 15 - Improved error format (MM)
if exists("b:did_ftplugin")
finish
@@ -37,6 +37,10 @@ endif
let s:cposet=&cpoptions
set cpo&vim
+" Comment string
+setlocal comments=
+setlocal commentstring=(*%s*)
+
" Add mappings, unless the user didn't want this.
if !exists("no_plugin_maps") && !exists("no_ocaml_maps")
" (un)commenting
@@ -60,16 +64,39 @@ if !exists("no_plugin_maps") && !exists("no_ocaml_maps")
endif
" Let % jump between structure elements (due to Issac Trotts)
-let b:mw = ''
-let b:mw = b:mw . ',\<let\>:\<and\>:\(\<in\>\|;;\)'
+let b:mw = '\<let\>:\<and\>:\(\<in\>\|;;\)'
let b:mw = b:mw . ',\<if\>:\<then\>:\<else\>'
-let b:mw = b:mw . ',\<\(for\|while\)\>:\<do\>:\<done\>,'
+let b:mw = b:mw . ',\<\(for\|while\)\>:\<do\>:\<done\>'
let b:mw = b:mw . ',\<\(object\|sig\|struct\|begin\)\>:\<end\>'
let b:mw = b:mw . ',\<\(match\|try\)\>:\<with\>'
let b:match_words = b:mw
let b:match_ignorecase=0
+function! s:OcpGrep(bang,args) abort
+ let grepprg = &l:grepprg
+ let grepformat = &l:grepformat
+ let shellpipe = &shellpipe
+ try
+ let &l:grepprg = "ocp-grep -c never"
+ setlocal grepformat=%f:%l:%m
+ if &shellpipe ==# '2>&1| tee' || &shellpipe ==# '|& tee'
+ let &shellpipe = "| tee"
+ endif
+ execute 'grep! '.a:args
+ if empty(a:bang) && !empty(getqflist())
+ return 'cfirst'
+ else
+ return ''
+ endif
+ finally
+ let &l:grepprg = grepprg
+ let &l:grepformat = grepformat
+ let &shellpipe = shellpipe
+ endtry
+endfunction
+command! -bar -bang -complete=file -nargs=+ Ocpgrep exe s:OcpGrep(<q-bang>, <q-args>)
+
" switching between interfaces (.mli) and implementations (.ml)
if !exists("g:did_ocaml_switch")
let g:did_ocaml_switch = 1
@@ -97,15 +124,8 @@ endif
" Folding support
" Get the modeline because folding depends on indentation
-let s:s = line2byte(line('.'))+col('.')-1
-if search('^\s*(\*:o\?caml:')
- let s:modeline = getline(".")
-else
- let s:modeline = ""
-endif
-if s:s > 0
- exe 'goto' s:s
-endif
+let lnum = search('^\s*(\*:o\?caml:', 'n')
+let s:modeline = lnum? getline(lnum): ""
" Get the indentation params
let s:m = matchstr(s:modeline,'default\s*=\s*\d\+')
@@ -372,8 +392,8 @@ endfunction
endfun
" This variable contain a dictionnary of list. Each element of the dictionnary
- " represent an annotation system. An annotation system is a list with :
- " - annotation file name as it's key
+ " represent an annotation system. An annotation system is a list with:
+ " - annotation file name as its key
" - annotation file path as first element of the contained list
" - build path as second element of the contained list
" - annot_file_last_mod (contain the date of .annot file) as third element
diff --git a/runtime/ftplugin/python.vim b/runtime/ftplugin/python.vim
index 5c4a59b1a9..64c1a87a69 100644
--- a/runtime/ftplugin/python.vim
+++ b/runtime/ftplugin/python.vim
@@ -3,7 +3,7 @@
" Maintainer: Tom Picton <tom@tompicton.co.uk>
" Previous Maintainer: James Sully <sullyj3@gmail.com>
" Previous Maintainer: Johannes Zellner <johannes@zellner.org>
-" Last Change: Sun, 15 April 2018
+" Last Change: Sun 17 Mar 2019
" https://github.com/tpict/vim-ftplugin-python
if exists("b:did_ftplugin") | finish | endif
@@ -37,9 +37,10 @@ setlocal suffixesadd=.py
setlocal comments=b:#,fb:-
setlocal commentstring=#\ %s
-setlocal omnifunc=pythoncomplete#Complete
if has('python3')
- setlocal omnifunc=python3complete#Complete
+ setlocal omnifunc=python3complete#Complete
+elseif has('python')
+ setlocal omnifunc=pythoncomplete#Complete
endif
set wildignore+=*.pyc
@@ -53,32 +54,34 @@ let b:prev='\v^\s*(class\|def\|async def)>'
let b:next_end='\v\S\n*(%$\|^(\s*\n*)*(class\|def\|async def)\|^\S)'
let b:prev_end='\v\S\n*(^(\s*\n*)*(class\|def\|async def)\|^\S)'
-execute "nnoremap <silent> <buffer> ]] :call <SID>Python_jump('n', '". b:next_toplevel."', 'W', v:count1)<cr>"
-execute "nnoremap <silent> <buffer> [[ :call <SID>Python_jump('n', '". b:prev_toplevel."', 'Wb', v:count1)<cr>"
-execute "nnoremap <silent> <buffer> ][ :call <SID>Python_jump('n', '". b:next_endtoplevel."', 'W', 0, v:count1)<cr>"
-execute "nnoremap <silent> <buffer> [] :call <SID>Python_jump('n', '". b:prev_endtoplevel."', 'Wb', 0, v:count1)<cr>"
-execute "nnoremap <silent> <buffer> ]m :call <SID>Python_jump('n', '". b:next."', 'W', v:count1)<cr>"
-execute "nnoremap <silent> <buffer> [m :call <SID>Python_jump('n', '". b:prev."', 'Wb', v:count1)<cr>"
-execute "nnoremap <silent> <buffer> ]M :call <SID>Python_jump('n', '". b:next_end."', 'W', 0, v:count1)<cr>"
-execute "nnoremap <silent> <buffer> [M :call <SID>Python_jump('n', '". b:prev_end."', 'Wb', 0, v:count1)<cr>"
-
-execute "onoremap <silent> <buffer> ]] :call <SID>Python_jump('o', '". b:next_toplevel."', 'W', v:count1)<cr>"
-execute "onoremap <silent> <buffer> [[ :call <SID>Python_jump('o', '". b:prev_toplevel."', 'Wb', v:count1)<cr>"
-execute "onoremap <silent> <buffer> ][ :call <SID>Python_jump('o', '". b:next_endtoplevel."', 'W', 0, v:count1)<cr>"
-execute "onoremap <silent> <buffer> [] :call <SID>Python_jump('o', '". b:prev_endtoplevel."', 'Wb', 0, v:count1)<cr>"
-execute "onoremap <silent> <buffer> ]m :call <SID>Python_jump('o', '". b:next."', 'W', v:count1)<cr>"
-execute "onoremap <silent> <buffer> [m :call <SID>Python_jump('o', '". b:prev."', 'Wb', v:count1)<cr>"
-execute "onoremap <silent> <buffer> ]M :call <SID>Python_jump('o', '". b:next_end."', 'W', 0, v:count1)<cr>"
-execute "onoremap <silent> <buffer> [M :call <SID>Python_jump('o', '". b:prev_end."', 'Wb', 0, v:count1)<cr>"
-
-execute "xnoremap <silent> <buffer> ]] :call <SID>Python_jump('x', '". b:next_toplevel."', 'W', v:count1)<cr>"
-execute "xnoremap <silent> <buffer> [[ :call <SID>Python_jump('x', '". b:prev_toplevel."', 'Wb', v:count1)<cr>"
-execute "xnoremap <silent> <buffer> ][ :call <SID>Python_jump('x', '". b:next_endtoplevel."', 'W', 0, v:count1)<cr>"
-execute "xnoremap <silent> <buffer> [] :call <SID>Python_jump('x', '". b:prev_endtoplevel."', 'Wb', 0, v:count1)<cr>"
-execute "xnoremap <silent> <buffer> ]m :call <SID>Python_jump('x', '". b:next."', 'W', v:count1)<cr>"
-execute "xnoremap <silent> <buffer> [m :call <SID>Python_jump('x', '". b:prev."', 'Wb', v:count1)<cr>"
-execute "xnoremap <silent> <buffer> ]M :call <SID>Python_jump('x', '". b:next_end."', 'W', 0, v:count1)<cr>"
-execute "xnoremap <silent> <buffer> [M :call <SID>Python_jump('x', '". b:prev_end."', 'Wb', 0, v:count1)<cr>"
+if !exists('g:no_plugin_maps') && !exists('g:no_python_maps')
+ execute "nnoremap <silent> <buffer> ]] :call <SID>Python_jump('n', '". b:next_toplevel."', 'W', v:count1)<cr>"
+ execute "nnoremap <silent> <buffer> [[ :call <SID>Python_jump('n', '". b:prev_toplevel."', 'Wb', v:count1)<cr>"
+ execute "nnoremap <silent> <buffer> ][ :call <SID>Python_jump('n', '". b:next_endtoplevel."', 'W', v:count1, 0)<cr>"
+ execute "nnoremap <silent> <buffer> [] :call <SID>Python_jump('n', '". b:prev_endtoplevel."', 'Wb', v:count1, 0)<cr>"
+ execute "nnoremap <silent> <buffer> ]m :call <SID>Python_jump('n', '". b:next."', 'W', v:count1)<cr>"
+ execute "nnoremap <silent> <buffer> [m :call <SID>Python_jump('n', '". b:prev."', 'Wb', v:count1)<cr>"
+ execute "nnoremap <silent> <buffer> ]M :call <SID>Python_jump('n', '". b:next_end."', 'W', v:count1, 0)<cr>"
+ execute "nnoremap <silent> <buffer> [M :call <SID>Python_jump('n', '". b:prev_end."', 'Wb', v:count1, 0)<cr>"
+
+ execute "onoremap <silent> <buffer> ]] :call <SID>Python_jump('o', '". b:next_toplevel."', 'W', v:count1)<cr>"
+ execute "onoremap <silent> <buffer> [[ :call <SID>Python_jump('o', '". b:prev_toplevel."', 'Wb', v:count1)<cr>"
+ execute "onoremap <silent> <buffer> ][ :call <SID>Python_jump('o', '". b:next_endtoplevel."', 'W', v:count1, 0)<cr>"
+ execute "onoremap <silent> <buffer> [] :call <SID>Python_jump('o', '". b:prev_endtoplevel."', 'Wb', v:count1, 0)<cr>"
+ execute "onoremap <silent> <buffer> ]m :call <SID>Python_jump('o', '". b:next."', 'W', v:count1)<cr>"
+ execute "onoremap <silent> <buffer> [m :call <SID>Python_jump('o', '". b:prev."', 'Wb', v:count1)<cr>"
+ execute "onoremap <silent> <buffer> ]M :call <SID>Python_jump('o', '". b:next_end."', 'W', v:count1, 0)<cr>"
+ execute "onoremap <silent> <buffer> [M :call <SID>Python_jump('o', '". b:prev_end."', 'Wb', v:count1, 0)<cr>"
+
+ execute "xnoremap <silent> <buffer> ]] :call <SID>Python_jump('x', '". b:next_toplevel."', 'W', v:count1)<cr>"
+ execute "xnoremap <silent> <buffer> [[ :call <SID>Python_jump('x', '". b:prev_toplevel."', 'Wb', v:count1)<cr>"
+ execute "xnoremap <silent> <buffer> ][ :call <SID>Python_jump('x', '". b:next_endtoplevel."', 'W', v:count1, 0)<cr>"
+ execute "xnoremap <silent> <buffer> [] :call <SID>Python_jump('x', '". b:prev_endtoplevel."', 'Wb', v:count1, 0)<cr>"
+ execute "xnoremap <silent> <buffer> ]m :call <SID>Python_jump('x', '". b:next."', 'W', v:count1)<cr>"
+ execute "xnoremap <silent> <buffer> [m :call <SID>Python_jump('x', '". b:prev."', 'Wb', v:count1)<cr>"
+ execute "xnoremap <silent> <buffer> ]M :call <SID>Python_jump('x', '". b:next_end."', 'W', v:count1, 0)<cr>"
+ execute "xnoremap <silent> <buffer> [M :call <SID>Python_jump('x', '". b:prev_end."', 'Wb', v:count1, 0)<cr>"
+endif
if !exists('*<SID>Python_jump')
fun! <SID>Python_jump(mode, motion, flags, count, ...) range
@@ -123,10 +126,80 @@ if !exists('g:pydoc_executable')
let g:pydoc_executable = 0
endif
endif
+
+" Windows-specific pydoc setup
+if has('win32') || has('win64')
+ if executable('python')
+ " available as Tools\scripts\pydoc.py
+ let g:pydoc_executable = 1
+ else
+ let g:pydoc_executable = 0
+ endif
+endif
+
" If "pydoc" was found use it for keywordprg.
if g:pydoc_executable
- setlocal keywordprg=pydoc
+ if has('win32') || has('win64')
+ setlocal keywordprg=python\ -m\ pydoc\
+ else
+ setlocal keywordprg=pydoc
+ endif
endif
+" Script for filetype switching to undo the local stuff we may have changed
+let b:undo_ftplugin = 'setlocal cinkeys<'
+ \ . '|setlocal comments<'
+ \ . '|setlocal commentstring<'
+ \ . '|setlocal expandtab<'
+ \ . '|setlocal include<'
+ \ . '|setlocal includeexpr<'
+ \ . '|setlocal indentkeys<'
+ \ . '|setlocal keywordprg<'
+ \ . '|setlocal omnifunc<'
+ \ . '|setlocal shiftwidth<'
+ \ . '|setlocal softtabstop<'
+ \ . '|setlocal suffixesadd<'
+ \ . '|setlocal tabstop<'
+ \ . '|silent! nunmap <buffer> [M'
+ \ . '|silent! nunmap <buffer> [['
+ \ . '|silent! nunmap <buffer> []'
+ \ . '|silent! nunmap <buffer> [m'
+ \ . '|silent! nunmap <buffer> ]M'
+ \ . '|silent! nunmap <buffer> ]['
+ \ . '|silent! nunmap <buffer> ]]'
+ \ . '|silent! nunmap <buffer> ]m'
+ \ . '|silent! ounmap <buffer> [M'
+ \ . '|silent! ounmap <buffer> [['
+ \ . '|silent! ounmap <buffer> []'
+ \ . '|silent! ounmap <buffer> [m'
+ \ . '|silent! ounmap <buffer> ]M'
+ \ . '|silent! ounmap <buffer> ]['
+ \ . '|silent! ounmap <buffer> ]]'
+ \ . '|silent! ounmap <buffer> ]m'
+ \ . '|silent! xunmap <buffer> [M'
+ \ . '|silent! xunmap <buffer> [['
+ \ . '|silent! xunmap <buffer> []'
+ \ . '|silent! xunmap <buffer> [m'
+ \ . '|silent! xunmap <buffer> ]M'
+ \ . '|silent! xunmap <buffer> ]['
+ \ . '|silent! xunmap <buffer> ]]'
+ \ . '|silent! xunmap <buffer> ]m'
+ \ . '|unlet! b:browsefilter'
+ \ . '|unlet! b:child_match'
+ \ . '|unlet! b:child_sub'
+ \ . '|unlet! b:grandparent_match'
+ \ . '|unlet! b:grandparent_sub'
+ \ . '|unlet! b:next'
+ \ . '|unlet! b:next_end'
+ \ . '|unlet! b:next_endtoplevel'
+ \ . '|unlet! b:next_toplevel'
+ \ . '|unlet! b:parent_match'
+ \ . '|unlet! b:parent_sub'
+ \ . '|unlet! b:prev'
+ \ . '|unlet! b:prev_end'
+ \ . '|unlet! b:prev_endtoplevel'
+ \ . '|unlet! b:prev_toplevel'
+ \ . '|unlet! b:undo_ftplugin'
+
let &cpo = s:keepcpo
unlet s:keepcpo
diff --git a/runtime/ftplugin/qf.vim b/runtime/ftplugin/qf.vim
index 80e86c4d16..a3dfce0e76 100644
--- a/runtime/ftplugin/qf.vim
+++ b/runtime/ftplugin/qf.vim
@@ -1,7 +1,7 @@
" Vim filetype plugin file
" Language: Vim's quickfix window
" Maintainer: Lech Lorens <Lech.Lorens@gmail.com>
-" Last Changed: 30 Apr 2012
+" Last Change: 2019 Jul 15
if exists("b:did_ftplugin")
finish
@@ -10,10 +10,12 @@ endif
" Don't load another plugin for this buffer
let b:did_ftplugin = 1
-let b:undo_ftplugin = "set stl<"
+if !get(g:, 'qf_disable_statusline')
+ let b:undo_ftplugin = "set stl<"
-" Display the command that produced the list in the quickfix window:
-setlocal stl=%t%{exists('w:quickfix_title')?\ '\ '.w:quickfix_title\ :\ ''}\ %=%-15(%l,%c%V%)\ %P
+ " Display the command that produced the list in the quickfix window:
+ setlocal stl=%t%{exists('w:quickfix_title')?\ '\ '.w:quickfix_title\ :\ ''}\ %=%-15(%l,%c%V%)\ %P
+endif
function! s:setup_toc() abort
if get(w:, 'quickfix_title') !~# '\<TOC$' || &syntax != 'qf'
diff --git a/runtime/ftplugin/rst.vim b/runtime/ftplugin/rst.vim
index 9d737cde44..f0646e9f36 100644
--- a/runtime/ftplugin/rst.vim
+++ b/runtime/ftplugin/rst.vim
@@ -3,7 +3,7 @@
" Maintainer: Marshall Ward <marshall.ward@gmail.com>
" Original Maintainer: Nikolai Weibull <now@bitwi.se>
" Website: https://github.com/marshallward/vim-restructuredtext
-" Latest Revision: 2018-01-07
+" Latest Revision: 2018-12-29
if exists("b:did_ftplugin")
finish
@@ -13,6 +13,11 @@ let b:did_ftplugin = 1
let s:cpo_save = &cpo
set cpo&vim
+"Disable folding
+if !exists('g:rst_fold_enabled')
+ let g:rst_fold_enabled = 0
+endif
+
let b:undo_ftplugin = "setl com< cms< et< fo<"
setlocal comments=fb:.. commentstring=..\ %s expandtab
@@ -25,7 +30,7 @@ setlocal formatoptions+=tcroql
"
" More sophisticated indentation rules should be revisted in the future.
-if !exists("g:rst_style") || g:rst_style != 0
+if exists("g:rst_style") && g:rst_style != 0
setlocal expandtab shiftwidth=3 softtabstop=3 tabstop=8
endif
diff --git a/runtime/ftplugin/ruby.vim b/runtime/ftplugin/ruby.vim
index 84fb9930a4..054c35e5fa 100644
--- a/runtime/ftplugin/ruby.vim
+++ b/runtime/ftplugin/ruby.vim
@@ -2,8 +2,8 @@
" Language: Ruby
" Maintainer: Tim Pope <vimNOSPAM@tpope.org>
" URL: https://github.com/vim-ruby/vim-ruby
-" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
-" ----------------------------------------------------------------------------
+" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
+" Last Change: 2019 Jan 06
if (exists("b:did_ftplugin"))
finish
@@ -44,19 +44,12 @@ endif
setlocal formatoptions-=t formatoptions+=croql
setlocal include=^\\s*\\<\\(load\\>\\\|require\\>\\\|autoload\\s*:\\=[\"']\\=\\h\\w*[\"']\\=,\\)
-setlocal includeexpr=substitute(substitute(v:fname,'::','/','g'),'\%(\.rb\)\=$','.rb','')
setlocal suffixesadd=.rb
if exists("&ofu") && has("ruby")
setlocal omnifunc=rubycomplete#Complete
endif
-" To activate, :set ballooneval
-if has('balloon_eval') && exists('+balloonexpr')
- setlocal balloonexpr=RubyBalloonexpr()
-endif
-
-
" TODO:
"setlocal define=^\\s*def
@@ -69,7 +62,7 @@ endif
function! s:query_path(root) abort
let code = "print $:.join %q{,}"
- if &shell =~# 'sh'
+ if &shell =~# 'sh' && empty(&shellxquote)
let prefix = 'env PATH='.shellescape($PATH).' '
else
let prefix = ''
@@ -141,44 +134,54 @@ if (has("gui_win32") || has("gui_gtk")) && !exists("b:browsefilter")
\ "All Files (*.*)\t*.*\n"
endif
-let b:undo_ftplugin = "setl fo< inc< inex< sua< def< com< cms< path< tags< kp<"
+let b:undo_ftplugin = "setl inc= sua= path= tags= fo< com< cms< kp="
\."| unlet! b:browsefilter b:match_ignorecase b:match_words b:match_skip"
\."| if exists('&ofu') && has('ruby') | setl ofu< | endif"
- \."| if has('balloon_eval') && exists('+bexpr') | setl bexpr< | endif"
+
+if get(g:, 'ruby_recommended_style', 1)
+ setlocal shiftwidth=2 softtabstop=2 expandtab
+ let b:undo_ftplugin .= ' | setl sw< sts< et<'
+endif
+
+" To activate, :set ballooneval
+if exists('+balloonexpr') && get(g:, 'ruby_balloonexpr')
+ setlocal balloonexpr=RubyBalloonexpr()
+ let b:undo_ftplugin .= "| setl bexpr="
+endif
function! s:map(mode, flags, map) abort
let from = matchstr(a:map, '\S\+')
if empty(mapcheck(from, a:mode))
- exe a:mode.'map' '<buffer>'.(a:0 ? a:1 : '') a:map
+ exe a:mode.'map' '<buffer>' a:map
let b:undo_ftplugin .= '|sil! '.a:mode.'unmap <buffer> '.from
endif
endfunction
-cmap <buffer><script><expr> <Plug><cword> substitute(RubyCursorIdentifier(),'^$',"\022\027",'')
+cmap <buffer><script><expr> <Plug><ctag> substitute(RubyCursorTag(),'^$',"\022\027",'')
cmap <buffer><script><expr> <Plug><cfile> substitute(RubyCursorFile(),'^$',"\022\006",'')
-let b:undo_ftplugin .= "| sil! cunmap <buffer> <Plug><cword>| sil! cunmap <buffer> <Plug><cfile>"
+let b:undo_ftplugin .= "| sil! cunmap <buffer> <Plug><ctag>| sil! cunmap <buffer> <Plug><cfile>"
if !exists("g:no_plugin_maps") && !exists("g:no_ruby_maps")
nmap <buffer><script> <SID>: :<C-U>
nmap <buffer><script> <SID>c: :<C-U><C-R>=v:count ? v:count : ''<CR>
- nnoremap <silent> <buffer> [m :<C-U>call <SID>searchsyn('\<def\>','rubyDefine','b','n')<CR>
- nnoremap <silent> <buffer> ]m :<C-U>call <SID>searchsyn('\<def\>','rubyDefine','','n')<CR>
- nnoremap <silent> <buffer> [M :<C-U>call <SID>searchsyn('\<end\>','rubyDefine','b','n')<CR>
- nnoremap <silent> <buffer> ]M :<C-U>call <SID>searchsyn('\<end\>','rubyDefine','','n')<CR>
- xnoremap <silent> <buffer> [m :<C-U>call <SID>searchsyn('\<def\>','rubyDefine','b','v')<CR>
- xnoremap <silent> <buffer> ]m :<C-U>call <SID>searchsyn('\<def\>','rubyDefine','','v')<CR>
- xnoremap <silent> <buffer> [M :<C-U>call <SID>searchsyn('\<end\>','rubyDefine','b','v')<CR>
- xnoremap <silent> <buffer> ]M :<C-U>call <SID>searchsyn('\<end\>','rubyDefine','','v')<CR>
-
- nnoremap <silent> <buffer> [[ :<C-U>call <SID>searchsyn('\<\%(class\<Bar>module\)\>','rubyModule\<Bar>rubyClass','b','n')<CR>
- nnoremap <silent> <buffer> ]] :<C-U>call <SID>searchsyn('\<\%(class\<Bar>module\)\>','rubyModule\<Bar>rubyClass','','n')<CR>
- nnoremap <silent> <buffer> [] :<C-U>call <SID>searchsyn('\<end\>','rubyModule\<Bar>rubyClass','b','n')<CR>
- nnoremap <silent> <buffer> ][ :<C-U>call <SID>searchsyn('\<end\>','rubyModule\<Bar>rubyClass','','n')<CR>
- xnoremap <silent> <buffer> [[ :<C-U>call <SID>searchsyn('\<\%(class\<Bar>module\)\>','rubyModule\<Bar>rubyClass','b','v')<CR>
- xnoremap <silent> <buffer> ]] :<C-U>call <SID>searchsyn('\<\%(class\<Bar>module\)\>','rubyModule\<Bar>rubyClass','','v')<CR>
- xnoremap <silent> <buffer> [] :<C-U>call <SID>searchsyn('\<end\>','rubyModule\<Bar>rubyClass','b','v')<CR>
- xnoremap <silent> <buffer> ][ :<C-U>call <SID>searchsyn('\<end\>','rubyModule\<Bar>rubyClass','','v')<CR>
+ nnoremap <silent> <buffer> [m :<C-U>call <SID>searchsyn('\<def\>',['rubyDefine'],'b','n')<CR>
+ nnoremap <silent> <buffer> ]m :<C-U>call <SID>searchsyn('\<def\>',['rubyDefine'],'','n')<CR>
+ nnoremap <silent> <buffer> [M :<C-U>call <SID>searchsyn('\<end\>',['rubyDefine'],'b','n')<CR>
+ nnoremap <silent> <buffer> ]M :<C-U>call <SID>searchsyn('\<end\>',['rubyDefine'],'','n')<CR>
+ xnoremap <silent> <buffer> [m :<C-U>call <SID>searchsyn('\<def\>',['rubyDefine'],'b','v')<CR>
+ xnoremap <silent> <buffer> ]m :<C-U>call <SID>searchsyn('\<def\>',['rubyDefine'],'','v')<CR>
+ xnoremap <silent> <buffer> [M :<C-U>call <SID>searchsyn('\<end\>',['rubyDefine'],'b','v')<CR>
+ xnoremap <silent> <buffer> ]M :<C-U>call <SID>searchsyn('\<end\>',['rubyDefine'],'','v')<CR>
+
+ nnoremap <silent> <buffer> [[ :<C-U>call <SID>searchsyn('\<\%(class\<Bar>module\)\>',['rubyModule','rubyClass'],'b','n')<CR>
+ nnoremap <silent> <buffer> ]] :<C-U>call <SID>searchsyn('\<\%(class\<Bar>module\)\>',['rubyModule','rubyClass'],'','n')<CR>
+ nnoremap <silent> <buffer> [] :<C-U>call <SID>searchsyn('\<end\>',['rubyModule','rubyClass'],'b','n')<CR>
+ nnoremap <silent> <buffer> ][ :<C-U>call <SID>searchsyn('\<end\>',['rubyModule','rubyClass'],'','n')<CR>
+ xnoremap <silent> <buffer> [[ :<C-U>call <SID>searchsyn('\<\%(class\<Bar>module\)\>',['rubyModule','rubyClass'],'b','v')<CR>
+ xnoremap <silent> <buffer> ]] :<C-U>call <SID>searchsyn('\<\%(class\<Bar>module\)\>',['rubyModule','rubyClass'],'','v')<CR>
+ xnoremap <silent> <buffer> [] :<C-U>call <SID>searchsyn('\<end\>',['rubyModule','rubyClass'],'b','v')<CR>
+ xnoremap <silent> <buffer> ][ :<C-U>call <SID>searchsyn('\<end\>',['rubyModule','rubyClass'],'','v')<CR>
let b:undo_ftplugin = b:undo_ftplugin
\."| sil! exe 'unmap <buffer> [[' | sil! exe 'unmap <buffer> ]]' | sil! exe 'unmap <buffer> []' | sil! exe 'unmap <buffer> ]['"
@@ -204,19 +207,18 @@ if !exists("g:no_plugin_maps") && !exists("g:no_ruby_maps")
\."| sil! exe 'xunmap <buffer> iM' | sil! exe 'xunmap <buffer> aM'"
endif
- call s:map('c', '', '<C-R><C-W> <Plug><cword>')
call s:map('c', '', '<C-R><C-F> <Plug><cfile>')
cmap <buffer><script><expr> <SID>tagzv &foldopen =~# 'tag' ? '<Bar>norm! zv' : ''
- call s:map('n', '<silent>', '<C-]> <SID>:exe v:count1."tag <Plug><cword>"<SID>tagzv<CR>')
- call s:map('n', '<silent>', 'g<C-]> <SID>:exe "tjump <Plug><cword>"<SID>tagzv<CR>')
- call s:map('n', '<silent>', 'g] <SID>:exe "tselect <Plug><cword>"<SID>tagzv<CR>')
- call s:map('n', '<silent>', '<C-W>] <SID>:exe v:count1."stag <Plug><cword>"<SID>tagzv<CR>')
- call s:map('n', '<silent>', '<C-W><C-]> <SID>:exe v:count1."stag <Plug><cword>"<SID>tagzv<CR>')
- call s:map('n', '<silent>', '<C-W>g<C-]> <SID>:exe "stjump <Plug><cword>"<SID>tagzv<CR>')
- call s:map('n', '<silent>', '<C-W>g] <SID>:exe "stselect <Plug><cword>"<SID>tagzv<CR>')
- call s:map('n', '<silent>', '<C-W>} <SID>:exe v:count1."ptag <Plug><cword>"<CR>')
- call s:map('n', '<silent>', '<C-W>g} <SID>:exe "ptjump <Plug><cword>"<CR>')
+ call s:map('n', '<silent>', '<C-]> <SID>:exe v:count1."tag <Plug><ctag>"<SID>tagzv<CR>')
+ call s:map('n', '<silent>', 'g<C-]> <SID>:exe "tjump <Plug><ctag>"<SID>tagzv<CR>')
+ call s:map('n', '<silent>', 'g] <SID>:exe "tselect <Plug><ctag>"<SID>tagzv<CR>')
+ call s:map('n', '<silent>', '<C-W>] <SID>:exe v:count1."stag <Plug><ctag>"<SID>tagzv<CR>')
+ call s:map('n', '<silent>', '<C-W><C-]> <SID>:exe v:count1."stag <Plug><ctag>"<SID>tagzv<CR>')
+ call s:map('n', '<silent>', '<C-W>g<C-]> <SID>:exe "stjump <Plug><ctag>"<SID>tagzv<CR>')
+ call s:map('n', '<silent>', '<C-W>g] <SID>:exe "stselect <Plug><ctag>"<SID>tagzv<CR>')
+ call s:map('n', '<silent>', '<C-W>} <SID>:exe v:count1."ptag <Plug><ctag>"<CR>')
+ call s:map('n', '<silent>', '<C-W>g} <SID>:exe "ptjump <Plug><ctag>"<CR>')
call s:map('n', '<silent>', 'gf <SID>c:find <Plug><cfile><CR>')
call s:map('n', '<silent>', '<C-W>f <SID>c:sfind <Plug><cfile><CR>')
@@ -288,12 +290,13 @@ function! s:searchsyn(pattern, syn, flags, mode) abort
norm! gv
endif
let i = 0
+ call map(a:syn, 'hlID(v:val)')
while i < cnt
let i = i + 1
let line = line('.')
let col = col('.')
let pos = search(a:pattern,'W'.a:flags)
- while pos != 0 && s:synname() !~# a:syn
+ while pos != 0 && index(a:syn, s:synid()) < 0
let pos = search(a:pattern,'W'.a:flags)
endwhile
if pos == 0
@@ -303,8 +306,8 @@ function! s:searchsyn(pattern, syn, flags, mode) abort
endwhile
endfunction
-function! s:synname() abort
- return synIDattr(synID(line('.'),col('.'),0),'name')
+function! s:synid() abort
+ return synID(line('.'),col('.'),0)
endfunction
function! s:wrap_i(back,forward) abort
@@ -349,6 +352,10 @@ function! RubyCursorIdentifier() abort
return stripped == '' ? expand("<cword>") : stripped
endfunction
+function! RubyCursorTag() abort
+ return substitute(RubyCursorIdentifier(), '^[$@]*', '', '')
+endfunction
+
function! RubyCursorFile() abort
let isfname = &isfname
try
@@ -360,8 +367,9 @@ function! RubyCursorFile() abort
let pre = matchstr(strpart(getline('.'), 0, col('.')-1), '.*\f\@<!')
let post = matchstr(strpart(getline('.'), col('.')), '\f\@!.*')
let ext = getline('.') =~# '^\s*\%(require\%(_relative\)\=\|autoload\)\>' && cfile !~# '\.rb$' ? '.rb' : ''
- if s:synname() ==# 'rubyConstant'
+ if s:synid() ==# hlID('rubyConstant')
let cfile = substitute(cfile,'\.\w\+[?!=]\=$','','')
+ let cfile = substitute(cfile,'^::','','')
let cfile = substitute(cfile,'::','/','g')
let cfile = substitute(cfile,'\(\u\+\)\(\u\l\)','\1_\2', 'g')
let cfile = substitute(cfile,'\(\l\|\d\)\(\u\)','\1_\2', 'g')
diff --git a/runtime/ftplugin/sql.vim b/runtime/ftplugin/sql.vim
index 4d6fcd9564..1c02a98c7c 100644
--- a/runtime/ftplugin/sql.vim
+++ b/runtime/ftplugin/sql.vim
@@ -400,7 +400,7 @@ endif
" Predefined SQL objects what are used by the below mappings using
" the ]} style maps.
-" This global variable allows the users to override it's value
+" This global variable allows the users to override its value
" from within their vimrc.
" Note, you cannot use \?, since these patterns can be used to search
" backwards, you must use \{,1}
@@ -486,10 +486,10 @@ if exists('&omnifunc')
" OMNI function prior to setting up the SQL OMNI function
let b:sql_compl_savefunc = &omnifunc
- " Source it to determine it's version
+ " Source it to determine its version
runtime autoload/sqlcomplete.vim
" This is used by the sqlcomplete.vim plugin
- " Source it for it's global functions
+ " Source it for its global functions
runtime autoload/syntaxcomplete.vim
setlocal omnifunc=sqlcomplete#Complete
diff --git a/runtime/ftplugin/text.vim b/runtime/ftplugin/text.vim
index ec84ac6f79..c4cbcb54c3 100644
--- a/runtime/ftplugin/text.vim
+++ b/runtime/ftplugin/text.vim
@@ -1,7 +1,7 @@
" Vim filetype plugin
" Language: Text
" Maintainer: David Barnett <daviebdawg+vim@gmail.com>
-" Last Change: 2014 Jul 09
+" Last Change: 2019 Jan 10
if exists('b:did_ftplugin')
finish
@@ -12,6 +12,7 @@ let b:undo_ftplugin = 'setlocal comments< commentstring<'
" We intentionally don't set formatoptions-=t since text should wrap as text.
-" Pseudo comment leaders to indent bulleted lists.
-setlocal comments=fb:-,fb:*
+" Pseudo comment leaders to indent bulleted lists with '-' and '*'. And allow
+" for Mail quoted text with '>'.
+setlocal comments=fb:-,fb:*,n:>
setlocal commentstring=
diff --git a/runtime/ftplugin/xml.vim b/runtime/ftplugin/xml.vim
index 573a6ba441..1d43521155 100644
--- a/runtime/ftplugin/xml.vim
+++ b/runtime/ftplugin/xml.vim
@@ -1,8 +1,8 @@
" Vim filetype plugin file
-" Language: xml
-" Maintainer: Christian Brabandt <cb@256bit.org>
-" Last Changed: May 08th, 2018
-" Repository: https://github.com/chrisbra/vim-xml-ftplugin
+" Language: xml
+" Maintainer: Christian Brabandt <cb@256bit.org>
+" Last Changed: Dec 07th, 2018
+" Repository: https://github.com/chrisbra/vim-xml-ftplugin
" Previous Maintainer: Dan Sharp <dwsharp at users dot sourceforge dot net>
" URL: http://dwsharp.users.sourceforge.net/vim/ftplugin
diff --git a/runtime/indent/awk.vim b/runtime/indent/awk.vim
index aad73ee71f..e65331977c 100644
--- a/runtime/indent/awk.vim
+++ b/runtime/indent/awk.vim
@@ -47,7 +47,7 @@ endif
function! GetAwkIndent()
- " Find previous line and get it's indentation
+ " Find previous line and get its indentation
let prev_lineno = s:Get_prev_line( v:lnum )
if prev_lineno == 0
return 0
diff --git a/runtime/indent/cobol.vim b/runtime/indent/cobol.vim
index c08444ac40..590a729df4 100644
--- a/runtime/indent/cobol.vim
+++ b/runtime/indent/cobol.vim
@@ -1,7 +1,12 @@
" Vim indent file
" Language: cobol
-" Author: Tim Pope <vimNOSPAM@tpope.info>
+" Maintainer: Ankit Jain <ajatkj@yahoo.co.in>
+" (formerly Tim Pope <vimNOSPAM@tpope.info>)
" $Id: cobol.vim,v 1.1 2007/05/05 18:08:19 vimboss Exp $
+" Last Update: By Ankit Jain on 22.03.2019
+" Ankit Jain 22.03.2019 Changes & fixes:
+" Allow chars in 1st 6 columns
+" #C22032019
if exists("b:did_indent")
finish
@@ -66,7 +71,9 @@ function! GetCobolIndent(lnum) abort
let ashft = minshft + 1
let bshft = ashft + 4
" (Obsolete) numbered lines
- if getline(a:lnum) =~? '^\s*\d\{6\}\%($\|[ */$CD-]\)'
+ " #C22032019: Columns 1-6 could have alphabets as well as numbers
+ "if getline(a:lnum) =~? '^\s*\d\{6\}\%($\|[ */$CD-]\)'
+ if getline(a:lnum) =~? '^\s*[a-zA-Z0-9]\{6\}\%($\|[ */$CD-]\)'
return 0
endif
let cline = s:stripped(a:lnum)
diff --git a/runtime/indent/cs.vim b/runtime/indent/cs.vim
index 4a040b6fe2..76c12efecf 100644
--- a/runtime/indent/cs.vim
+++ b/runtime/indent/cs.vim
@@ -1,15 +1,73 @@
" Vim indent file
-" Language: C#
-" Maintainer: Johannes Zellner <johannes@zellner.org>
-" Last Change: Fri, 15 Mar 2002 07:53:54 CET
+" Language: C#
+" Maintainer: Nick Jensen <nickspoon@gmail.com>
+" Former Maintainers: Aquila Deus
+" Johannes Zellner <johannes@zellner.org>
+" Last Change: 2018-11-21
+" Filenames: *.cs
+" License: Vim (see :h license)
+" Repository: https://github.com/nickspoons/vim-cs
+"
" Only load this indent file when no other was loaded.
-if exists("b:did_indent")
- finish
+if exists('b:did_indent')
+ finish
endif
let b:did_indent = 1
-" C# is like indenting C
-setlocal cindent
+let s:save_cpo = &cpoptions
+set cpoptions&vim
-let b:undo_indent = "setl cin<"
+
+setlocal indentexpr=GetCSIndent(v:lnum)
+
+function! s:IsCompilerDirective(line)
+ return a:line =~? '^\s*#'
+endf
+
+function! s:IsAttributeLine(line)
+ return a:line =~? '^\s*\[[A-Za-z]' && a:line =~? '\]$'
+endf
+
+function! s:FindPreviousNonCompilerDirectiveLine(start_lnum)
+ for delta in range(0, a:start_lnum)
+ let lnum = a:start_lnum - delta
+ let line = getline(lnum)
+ let is_directive = s:IsCompilerDirective(line)
+ if !is_directive
+ return lnum
+ endif
+ endfor
+ return 0
+endf
+
+function! GetCSIndent(lnum) abort
+ " Hit the start of the file, use zero indent.
+ if a:lnum == 0
+ return 0
+ endif
+
+ let this_line = getline(a:lnum)
+
+ " Compiler directives use zero indent if so configured.
+ let is_first_col_macro = s:IsCompilerDirective(this_line) && stridx(&l:cinkeys, '0#') >= 0
+ if is_first_col_macro
+ return cindent(a:lnum)
+ endif
+
+ let lnum = s:FindPreviousNonCompilerDirectiveLine(a:lnum - 1)
+ let previous_code_line = getline(lnum)
+ if s:IsAttributeLine(previous_code_line)
+ let ind = indent(lnum)
+ return ind
+ else
+ return cindent(a:lnum)
+ endif
+endfunction
+
+let b:undo_indent = 'setlocal indentexpr<'
+
+let &cpoptions = s:save_cpo
+unlet s:save_cpo
+
+" vim:et:sw=2:sts=2
diff --git a/runtime/indent/eruby.vim b/runtime/indent/eruby.vim
index 5058325495..6ff15ab958 100644
--- a/runtime/indent/eruby.vim
+++ b/runtime/indent/eruby.vim
@@ -3,6 +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
if exists("b:did_indent")
finish
@@ -12,7 +13,7 @@ runtime! indent/ruby.vim
unlet! b:did_indent
setlocal indentexpr=
-if exists("b:eruby_subtype")
+if exists("b:eruby_subtype") && b:eruby_subtype != '' && b:eruby_subtype !=# 'eruby'
exe "runtime! indent/".b:eruby_subtype.".vim"
else
runtime! indent/html.vim
@@ -47,7 +48,11 @@ set cpo&vim
function! GetErubyIndent(...)
" The value of a single shift-width
- let sw = shiftwidth()
+ if exists('*shiftwidth')
+ let sw = shiftwidth()
+ else
+ let sw = &sw
+ endif
if a:0 && a:1 == '.'
let v:lnum = line('.')
@@ -91,6 +96,7 @@ function! GetErubyIndent(...)
let ind = ind + sw
endif
if line !~# '^\s*<%' && line =~# '%>\s*$' && line !~# '^\s*end\>'
+ \ && synID(v:lnum, match(cline, '\S') + 1, 1) != hlID('htmlEndTag')
let ind = ind - sw
endif
if cline =~# '^\s*[-=]\=%>\s*$'
diff --git a/runtime/indent/falcon.vim b/runtime/indent/falcon.vim
index b34e7cfd47..664ad61aa5 100644
--- a/runtime/indent/falcon.vim
+++ b/runtime/indent/falcon.vim
@@ -368,7 +368,7 @@ function FalconGetIndent(...)
return indent('.')
endif
else
- call cursor(clnum, vcol)
+ call cursor(clnum, 0) " FIXME: column was vcol
end
endif
diff --git a/runtime/indent/html.vim b/runtime/indent/html.vim
index 6c866594c5..1d2043ae9e 100644
--- a/runtime/indent/html.vim
+++ b/runtime/indent/html.vim
@@ -2,7 +2,7 @@
" Header: "{{{
" Maintainer: Bram Moolenaar
" Original Author: Andy Wokula <anwoku@yahoo.de>
-" Last Change: 2018 Mar 28
+" Last Change: 2019 Mar 20
" Version: 1.0
" Description: HTML indent script with cached state for faster indenting on a
" range of lines.
@@ -216,8 +216,9 @@ endfunc "}}}
" Add known tag pairs.
" Self-closing tags and tags that are sometimes {{{
" self-closing (e.g., <p>) are not here (when encountering </p> we can find
-" the matching <p>, but not the other way around). Known self-closing tags:
-" 'p', 'img', 'source'.
+" the matching <p>, but not the other way around).
+" Known self-closing tags: " 'p', 'img', 'source', 'area', 'keygen', 'track',
+" 'wbr'.
" Old HTML tags:
call s:AddITags(s:indent_tags, [
\ 'a', 'abbr', 'acronym', 'address', 'b', 'bdo', 'big',
@@ -232,11 +233,11 @@ call s:AddITags(s:indent_tags, [
" New HTML5 elements:
call s:AddITags(s:indent_tags, [
- \ 'area', 'article', 'aside', 'audio', 'bdi', 'canvas',
- \ 'command', 'data', 'datalist', 'details', 'embed', 'figcaption',
- \ 'figure', 'footer', 'header', 'keygen', 'main', 'mark', 'meter',
- \ 'nav', 'output', 'picture', 'progress', 'rp', 'rt', 'ruby', 'section',
- \ 'summary', 'svg', 'time', 'track', 'video', 'wbr'])
+ \ 'article', 'aside', 'audio', 'bdi', 'canvas', 'command', 'data',
+ \ 'datalist', 'details', 'dialog', 'embed', 'figcaption', 'figure',
+ \ 'footer', 'header', 'hgroup', 'main', 'mark', 'meter', 'nav', 'output',
+ \ 'picture', 'progress', 'rp', 'rt', 'ruby', 'section', 'summary',
+ \ 'svg', 'time', 'video'])
" Tags added for web components:
call s:AddITags(s:indent_tags, [
@@ -625,7 +626,7 @@ func! s:CSSIndent()
return eval(b:hi_css1indent)
endif
- " If the current line starts with "}" align with it's match.
+ " If the current line starts with "}" align with its match.
if curtext =~ '^\s*}'
call cursor(v:lnum, 1)
try
@@ -901,12 +902,19 @@ func! s:InsideTag(foundHtmlString)
"{{{
if a:foundHtmlString
" Inside an attribute string.
- " Align with the previous line or use an external function.
+ " Align with the opening quote or use an external function.
let lnum = v:lnum - 1
if lnum > 1
if exists('b:html_indent_tag_string_func')
return b:html_indent_tag_string_func(lnum)
endif
+ " If there is a double quote in the previous line, indent with the
+ " character after it.
+ if getline(lnum) =~ '"'
+ call cursor(lnum, 0)
+ normal f"
+ return virtcol('.')
+ endif
return indent(lnum)
endif
endif
@@ -934,7 +942,7 @@ func! s:InsideTag(foundHtmlString)
let idx = match(text, '<' . s:tagname . '\s\+\zs\w')
endif
if idx == -1
- " after just <tag indent one level more
+ " after just "<tag" indent one level more
let idx = match(text, '<' . s:tagname . '$')
if idx >= 0
call cursor(lnum, idx)
diff --git a/runtime/indent/matlab.vim b/runtime/indent/matlab.vim
index 6a31624389..d2818a18ea 100644
--- a/runtime/indent/matlab.vim
+++ b/runtime/indent/matlab.vim
@@ -1,74 +1,121 @@
-" Matlab indent file
-" Language: Matlab
-" Maintainer: Christophe Poucet <christophe.poucet@pandora.be>
-" Last Change: 6 January, 2001
-
-" Only load this indent file when no other was loaded.
-if exists("b:did_indent")
- finish
-endif
+" Vim indent file
+" Language: MATLAB
+" Maintainer: Axel Forsman <axelsfor@gmail.com>
+" Previous maintainer: Christophe Poucet <christophe.poucet@pandora.be>
+
+" Only load if no other indent file is loaded
+if exists('b:did_indent') | finish | endif
let b:did_indent = 1
-" Some preliminary setting
-setlocal indentkeys=!,o,O=end,=case,=else,=elseif,=otherwise,=catch
-
-
-setlocal indentexpr=GetMatlabIndent(v:lnum)
-
-" Only define the function once.
-if exists("*GetMatlabIndent")
- finish
-endif
-
-function GetMatlabIndent(lnum)
- " Give up if this line is explicitly joined.
- if getline(a:lnum - 1) =~ '\\$'
- return -1
- endif
-
- " Search backwards for the first non-empty line.
- let plnum = a:lnum - 1
- while plnum > 0 && getline(plnum) =~ '^\s*$'
- let plnum = plnum - 1
- endwhile
-
- if plnum == 0
- " This is the first non-empty line, use zero indent.
- return 0
- endif
-
- let curind = indent(plnum)
-
- " If the current line is a stop-block statement...
- if getline(v:lnum) =~ '^\s*\(end\|else\|elseif\|case\|otherwise\|catch\)\>'
- " See if this line does not follow the line right after an openblock
- if getline(plnum) =~ '^\s*\(for\|if\|else\|elseif\|case\|while\|switch\|try\|otherwise\|catch\)\>'
- " See if the user has already dedented
- elseif indent(v:lnum) > curind - shiftwidth()
- " If not, recommend one dedent
- let curind = curind - shiftwidth()
- else
- " Otherwise, trust the user
- return -1
- endif
-" endif
-
- " If the previous line opened a block
- elseif getline(plnum) =~ '^\s*\(for\|if\|else\|elseif\|case\|while\|switch\|try\|otherwise\|catch\)\>'
- " See if the user has already indented
- if indent(v:lnum) < curind + shiftwidth()
- "If not, recommend indent
- let curind = curind + shiftwidth()
- else
- " Otherwise, trust the user
- return -1
- endif
- endif
-
-
-
- " If we got to here, it means that the user takes the standardversion, so we return it
- return curind
+setlocal indentexpr=GetMatlabIndent()
+setlocal indentkeys=!,o,O,e,0=end,0=elseif,0=case,0=otherwise,0=catch,0=function,0=elsei
+
+" The value of the Function indenting format in
+" MATLAB Editor/Debugger Language Preferences.
+" The possible values are 0 for Classic, 1 for Indent nested functions
+" and 2 for Indent all functions (default).
+let b:MATLAB_function_indent = get(g:, 'MATLAB_function_indent', 2)
+" The previous value of b:changedtick
+let b:MATLAB_lasttick = -1
+" The previously indented line
+let b:MATLAB_lastline = -1
+" Whether the line above was a line continuation
+let b:MATLAB_waslc = 0
+let b:MATLAB_bracketlevel = 0
+
+" Only define the function once
+if exists("*GetMatlabIndent") | finish | endif
+
+let s:keepcpo = &cpo
+set cpo&vim
+
+let s:end = '\<end\>\%([^(]*)\)\@!' " Array indexing heuristic
+let s:open_pat = 'for\|if\|parfor\|spmd\|switch\|try\|while\|classdef\|properties\|methods\|events\|enumeration'
+let s:dedent_pat = '\C^\s*\zs\<\%(end\|else\|elseif\|catch\|\(case\|otherwise\|function\)\)\>'
+let s:start_pat = '\C\<\%(function\|' . s:open_pat . '\)\>'
+let s:bracket_pair_pat = '\(\[\|{\)\|\(\]\|}\)'
+let s:zflag = has('patch-7.4.984') ? 'z' : ''
+
+" Returns whether a comment or string envelops the specified column.
+function! s:IsCommentOrString(lnum, col)
+ return synIDattr(synID(a:lnum, a:col, 1), "name") =~# 'matlabComment\|matlabMultilineComment\|matlabString'
+endfunction
+
+" Returns whether the specified line continues on the next line.
+function! s:IsLineContinuation(lnum)
+ let l = getline(a:lnum) | let c = -3
+ while 1
+ let c = match(l, '\.\{3}', c + 3)
+ if c == -1 | return 0
+ elseif !s:IsCommentOrString(a:lnum, c) | return 1 | endif
+ endwhile
+endfunction
+
+function! s:SubmatchCount(lnum, pattern, ...)
+ let endcol = a:0 >= 1 ? a:1 : 1 / 0 | let x = [0, 0, 0, 0]
+ call cursor(a:lnum, 1)
+ while 1
+ let [lnum, c, submatch] = searchpos(a:pattern, 'cpe' . s:zflag, a:lnum)
+ if !submatch || c >= endcol | break | endif
+ if !s:IsCommentOrString(lnum, c) | let x[submatch - 2] += 1 | endif
+ if cursor(0, c + 1) == -1 || col('.') == c | break | endif
+ endwhile
+ return x
+endfunction
+
+function! s:GetOpenCloseCount(lnum, pattern, ...)
+ let counts = call('s:SubmatchCount', [a:lnum, a:pattern] + a:000)
+ return counts[0] - counts[1]
+endfunction
+
+function! GetMatlabIndent()
+ let prevlnum = prevnonblank(v:lnum - 1)
+
+ if b:MATLAB_lasttick != b:changedtick || b:MATLAB_lastline != prevlnum
+ " Recalculate bracket count (only have to check same block and line above)
+ let b:MATLAB_bracketlevel = 0
+ let previndent = indent(prevlnum) | let l = prevlnum
+ while 1
+ let l = prevnonblank(l - 1) | let indent = indent(l)
+ if l <= 0 || previndent < indent | break | endif
+ let b:MATLAB_bracketlevel += s:GetOpenCloseCount(l, s:bracket_pair_pat)
+ if previndent != indent | break | endif
+ endwhile
+
+ let b:MATLAB_waslc = s:IsLineContinuation(prevlnum - 1)
+ endif
+ " If line above was blank it can impossibly have been a LC
+ let above_lc = b:MATLAB_lasttick == b:changedtick && prevlnum != v:lnum - 1 && b:MATLAB_lastline == prevlnum ? 0 : s:IsLineContinuation(v:lnum - 1)
+
+ let pair_pat = '\C\<\(' . s:open_pat . '\|'
+ \ . (b:MATLAB_function_indent == 1 ? '^\@<!' : '')
+ \ . (b:MATLAB_function_indent >= 1 ? 'function\|' : '')
+ \ . '\|\%(^\s*\)\@<=\%(else\|elseif\|case\|otherwise\|catch\)\)\>'
+ \ . '\|\S\s*\zs\(' . s:end . '\)'
+ let [open, close, b_open, b_close] = prevlnum ? s:SubmatchCount(prevlnum,
+ \ pair_pat . '\|' . s:bracket_pair_pat) : [0, 0, 0, 0]
+ let curbracketlevel = b:MATLAB_bracketlevel + b_open - b_close
+
+ call cursor(v:lnum, 1)
+ let submatch = search(s:dedent_pat, 'cp' . s:zflag, v:lnum)
+ if submatch && !s:IsCommentOrString(v:lnum, col('.'))
+ " Align end, et cetera with start of block
+ let [lnum, col] = searchpairpos(s:start_pat, '', '\C' . s:end, 'bW', 's:IsCommentOrString(line("."), col("."))')
+ let result = lnum ? indent(lnum) + shiftwidth() * (s:GetOpenCloseCount(lnum, pair_pat, col) + submatch == 2) : 0
+ else
+ " Count how many blocks the previous line opens/closes
+ " Line continuations/brackets indent once per statement
+ let result = indent(prevlnum) + shiftwidth() * (open - close
+ \ + (b:MATLAB_bracketlevel ? -!curbracketlevel : !!curbracketlevel)
+ \ + (curbracketlevel <= 0) * (above_lc - b:MATLAB_waslc))
+ endif
+
+ let b:MATLAB_waslc = above_lc
+ let b:MATLAB_bracketlevel = curbracketlevel
+ let b:MATLAB_lasttick = b:changedtick
+ let b:MATLAB_lastline = v:lnum
+ return result
endfunction
-" vim:sw=2
+let &cpo = s:keepcpo
+unlet s:keepcpo
diff --git a/runtime/indent/mma.vim b/runtime/indent/mma.vim
index 8298ad98cd..a76fa8ede0 100644
--- a/runtime/indent/mma.vim
+++ b/runtime/indent/mma.vim
@@ -57,7 +57,7 @@ function GetMmaIndent()
if getline(v:lnum) =~ '[^[]*]\s*$'
" move to the closing bracket
call search(']','bW')
- " and find it's partner's indent
+ " and find its partner's indent
let ind = indent(searchpair('\[','',']','bWn'))
" same for ( blocks
elseif getline(v:lnum) =~ '[^(]*)$'
diff --git a/runtime/indent/php.vim b/runtime/indent/php.vim
index b0430dea8d..67a1327dc9 100644
--- a/runtime/indent/php.vim
+++ b/runtime/indent/php.vim
@@ -1,10 +1,10 @@
" Vim indent file
" Language: PHP
-" Author: John Wellesz <John.wellesz (AT) teaser (DOT) fr>
-" URL: http://www.2072productions.com/vim/indent/php.vim
+" Author: John Wellesz <John.wellesz (AT) gmail (DOT) com>
+" URL: https://www.2072productions.com/vim/indent/php.vim
" Home: https://github.com/2072/PHP-Indenting-for-VIm
-" Last Change: 2018 May 18th
-" Version: 1.66
+" Last Change: 2019 Jully 21st
+" Version: 1.70
"
"
" Type :help php-indent for available options
@@ -12,14 +12,14 @@
" A fully commented version of this file is available on github
"
"
-" If you find a bug, please open a ticket on github.org
+" If you find a bug, please open a ticket on github.com
" ( https://github.com/2072/PHP-Indenting-for-VIm/issues ) with an example of
" code that breaks the algorithm.
"
" NOTE: This script must be used with PHP syntax ON and with the php syntax
" script by Lutz Eymers (http://www.isp.de/data/php.vim ) or with the
-" script by Peter Hodge (http://www.vim.org/scripts/script.php?script_id=1571 )
+" script by Peter Hodge (https://www.vim.org/scripts/script.php?script_id=1571 )
" the later is bunbdled by default with Vim 7.
"
"
@@ -41,7 +41,6 @@
" silently remove them when VIM load this script (at each bufread).
-
if exists("b:did_indent")
finish
endif
@@ -95,7 +94,17 @@ else
let b:PHP_vintage_case_default_indent = 0
endif
+if exists("PHP_IndentFunctionCallParameters")
+ let b:PHP_IndentFunctionCallParameters = PHP_IndentFunctionCallParameters
+else
+ let b:PHP_IndentFunctionCallParameters = 0
+endif
+if exists("PHP_IndentFunctionDeclarationParameters")
+ let b:PHP_IndentFunctionDeclarationParameters = PHP_IndentFunctionDeclarationParameters
+else
+ let b:PHP_IndentFunctionDeclarationParameters = 0
+endif
let b:PHP_lastindented = 0
let b:PHP_indentbeforelast = 0
@@ -129,15 +138,19 @@ endif
if exists("*GetPhpIndent")
call ResetPhpOptions()
- finish
+ finish " XXX -- comment this line for easy dev
endif
-let s:PHP_validVariable = '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*'
-let s:notPhpHereDoc = '\%(break\|return\|continue\|exit\|die\|else\)'
-let s:blockstart = '\%(\%(\%(}\s*\)\=else\%(\s\+\)\=\)\=if\>\|\%(}\s*\)\?else\>\|do\>\|while\>\|switch\>\|case\>\|default\>\|for\%(each\)\=\>\|declare\>\|class\>\|trait\>\|use\>\|interface\>\|abstract\>\|final\>\|try\>\|\%(}\s*\)\=catch\>\|\%(}\s*\)\=finally\>\)'
-let s:functionDecl = '\<function\>\%(\s\+&\='.s:PHP_validVariable.'\)\=\s*(.*'
let s:endline = '\s*\%(//.*\|#.*\|/\*.*\*/\s*\)\=$'
+let s:PHP_validVariable = '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*'
+let s:notPhpHereDoc = '\%(break\|return\|continue\|exit\|die\|else\|end\%(if\|while\|for\|foreach\|switch\)\)'
+let s:blockstart = '\%(\%(\%(}\s*\)\=else\%(\s\+\)\=\)\=if\>\|\%(}\s*\)\?else\>\|do\>\|while\>\|switch\>\|case\>\|default\>\|for\%(each\)\=\>\|declare\>\|class\>\|trait\>\|\%()\s*\)\=use\>\|interface\>\|abstract\>\|final\>\|try\>\|\%(}\s*\)\=catch\>\|\%(}\s*\)\=finally\>\)'
+let s:functionDeclPrefix = '\<function\>\%(\s\+&\='.s:PHP_validVariable.'\)\=\s*('
+let s:functionDecl = s:functionDeclPrefix.'.*'
+let s:multilineFunctionDecl = s:functionDeclPrefix.s:endline
+let s:arrayDecl = '\<array\>\s*(.*'
+let s:multilineFunctionCall = s:PHP_validVariable.'\s*('.s:endline
let s:unstated = '\%(^\s*'.s:blockstart.'.*)\|\%(//.*\)\@<!\<e'.'lse\>\)'.s:endline
@@ -210,7 +223,7 @@ function! GetLastRealCodeLNum(startline) " {{{
while getline(lnum) !~? tofind && lnum > 1
let lnum = lnum - 1
endwhile
- elseif lastline =~ '^[^''"`]*[''"`][;,]'.s:endline
+ elseif lastline =~ '^\s*[''"`][;,]' || (lastline =~ '^[^''"`]*[''"`][;,]'.s:endline && IslinePHP(lnum, "") == "SpecStringEntrails")
let tofind=substitute( lastline, '^.*\([''"`]\)[;,].*$', '^[^\1]\\+[\1]$\\|^[^\1]\\+[=([]\\s*[\1]', '')
let trylnum = lnum
@@ -289,17 +302,23 @@ function! FindOpenBracket(lnum, blockStarter) " {{{
endfun " }}}
let s:blockChars = {'{':1, '[': 1, '(': 1, ')':-1, ']':-1, '}':-1}
+let s:blockCharsLUT = {'{':'{', '}':'{', '[':'[', ']':'[', '(':'(', ')':'('}
function! BalanceDirection (str)
- let balance = 0
+ let balance = {'{':0, '[': 0, '(': 0, 'none':0}
+ let director = 'none'
for c in split(a:str, '\zs')
if has_key(s:blockChars, c)
- let balance += s:blockChars[c]
+ let balance[s:blockCharsLUT[c]] += s:blockChars[c]
+
+ if balance[s:blockCharsLUT[c]]
+ let director = s:blockCharsLUT[c]
+ endif
endif
endfor
- return balance
+ return balance[director]
endfun
function! StripEndlineComments (line)
@@ -308,7 +327,8 @@ endfun
function! FindArrowIndent (lnum) " {{{
- let parrentArrowPos = 0
+ let parrentArrowPos = -1
+ let cursorPos = -1
let lnum = a:lnum
while lnum > 1
let last_line = getline(lnum)
@@ -316,31 +336,46 @@ function! FindArrowIndent (lnum) " {{{
let parrentArrowPos = indent(a:lnum)
break
else
- call cursor(lnum, 1)
- let cleanedLnum = StripEndlineComments(last_line)
- if cleanedLnum =~ '->'
- if ! b:PHP_noArrowMatching
- let parrentArrowPos = searchpos('->', 'W', lnum)[1] - 1
- else
- let parrentArrowPos = indent(lnum) + shiftwidth()
- endif
+
+ if b:PHP_noArrowMatching
break
- elseif cleanedLnum =~ ')'.s:endline && BalanceDirection(last_line) < 0
- call searchpos(')'.s:endline, 'cW', lnum)
- let openedparent = searchpair('(', '', ')', 'bW', 'Skippmatch()')
- if openedparent != lnum
- let lnum = openedparent
+ endif
+
+ let cleanedLnum = StripEndlineComments(last_line)
+
+ if cleanedLnum =~ ')'.s:endline
+ if BalanceDirection(cleanedLnum) <= 0
+ call cursor(lnum, 1)
+ call searchpos(')'.s:endline, 'cW', lnum)
+ let openedparent = searchpair('(', '', ')', 'bW', 'Skippmatch()')
+ let cursorPos = col(".")
+ if openedparent != lnum
+ let lnum = openedparent
+ continue
+ else
+ endif
else
- let openedparent = -1
- endif
+ let parrentArrowPos = -1
+ break
+ end
+ endif
+
+ if cleanedLnum =~ '->'
+ call cursor(lnum, cursorPos == -1 ? strwidth(cleanedLnum) : cursorPos)
+ let parrentArrowPos = searchpos('->', 'cWb', lnum)[1] - 1
+ break
else
- let parrentArrowPos = indent(lnum) + shiftwidth()
+ let parrentArrowPos = -1
break
endif
endif
endwhile
+ if parrentArrowPos == -1
+ let parrentArrowPos = indent(lnum) + shiftwidth()
+ end
+
return parrentArrowPos
endfun "}}}
@@ -432,7 +467,7 @@ function! IslinePHP (lnum, tofind) " {{{
let synname = synIDattr(synID(a:lnum, coltotest, 0), "name")
if synname ==? 'phpStringSingle' || synname ==? 'phpStringDouble' || synname ==? 'phpBacktick'
- if cline !~ '^\s*[''"`]'
+ if cline !~ '^\s*[''"`]' " ??? XXX
return "SpecStringEntrails"
else
return synname
@@ -471,7 +506,7 @@ endfunc
call ResetPhpOptions()
function! GetPhpIndentVersion()
- return "1.66-bundle"
+ return "1.70-bundle"
endfun
function! GetPhpIndent()
@@ -615,7 +650,7 @@ function! GetPhpIndent()
let b:InPHPcode_and_script = 1
endif
- elseif last_line =~ '^[^''"`]\+[''"`]$' " a string identifier with nothing after it and no other string identifier before
+ elseif last_line =~ '^[^''"`]\+[''"`]$' && last_line !~ '^\s*\%(//\|#\|/\*.*\*/\s*$\)' " a string identifier with nothing after it and no other string identifier before
let b:InPHPcode = -1
let b:InPHPcode_tofind = substitute( last_line, '^.*\([''"`]\).*$', '^[^\1]*\1[;,]$', '')
elseif last_line =~? '<<<\s*[''"]\=\a\w*[''"]\=$'
@@ -723,7 +758,7 @@ function! GetPhpIndent()
endif
- if last_line =~ '[;}]'.endline && last_line !~ '^[)\]]' && last_line !~# s:defaultORcase
+ if last_line =~ '[;}]'.endline && last_line !~ '^[)\]]' && last_line !~# s:defaultORcase && last_line !~ '^\s*[''"`][;,]'
if ind==b:PHP_default_indenting
return b:PHP_default_indenting + addSpecial
elseif b:PHP_indentinghuge && ind==b:PHP_CurrentIndentLevel && cline !~# '^\s*\%(else\|\%(case\|default\).*:\|[})];\=\)' && last_line !~# '^\s*\%(\%(}\s*\)\=else\)' && getline(GetLastRealCodeLNum(lnum - 1))=~';'.endline
@@ -869,6 +904,14 @@ function! GetPhpIndent()
let ind = ind + shiftwidth()
endif
+ if b:PHP_IndentFunctionCallParameters && last_line =~ s:multilineFunctionCall && last_line !~ s:structureHead && last_line !~ s:arrayDecl
+ let ind = ind + b:PHP_IndentFunctionCallParameters * shiftwidth()
+ endif
+
+ if b:PHP_IndentFunctionDeclarationParameters && last_line =~ s:multilineFunctionDecl
+ let ind = ind + b:PHP_IndentFunctionDeclarationParameters * shiftwidth()
+ endif
+
if b:PHP_BracesAtCodeLevel || b:PHP_vintage_case_default_indent == 1
let b:PHP_CurrentIndentLevel = ind
@@ -897,10 +940,15 @@ function! GetPhpIndent()
endif
if cline =~ '^\s*[)\]];\='
- let ind = ind - shiftwidth()
- endif
+ call cursor(v:lnum, 1)
+ call searchpos('[)\]]', 'cW')
+ let matchedBlockChar = cline[col('.')-1]
+ let openedparent = searchpair('\M'.s:blockCharsLUT[matchedBlockChar], '', '\M'.matchedBlockChar, 'bW', 'Skippmatch()')
+ if openedparent != v:lnum
+ let ind = indent(openedparent)
+ endif
- if last_line =~ '^\s*->' && last_line !~? s:structureHead && BalanceDirection(last_line) <= 0
+ elseif last_line =~ '^\s*->' && last_line !~? s:structureHead && BalanceDirection(last_line) <= 0
let ind = ind - shiftwidth()
endif
diff --git a/runtime/indent/python.vim b/runtime/indent/python.vim
index 7ab3cb9f50..e53987a0de 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: 2013 Jul 9
+" Last Change: 2019 Feb 21
" Only load this indent file when no other was loaded.
if exists("b:did_indent")
@@ -53,58 +53,68 @@ function GetPythonIndent(lnum)
return 0
endif
- " searchpair() can be slow sometimes, limit the time to 100 msec or what is
- " put in g:pyindent_searchpair_timeout
- let searchpair_stopline = 0
- let searchpair_timeout = get(g:, 'pyindent_searchpair_timeout', 150)
-
- " If the previous line is inside parenthesis, use the indent of the starting
- " line.
- " Trick: use the non-existing "dummy" variable to break out of the loop when
- " going too far back.
call cursor(plnum, 1)
- let parlnum = searchpair('(\|{\|\[', '', ')\|}\|\]', 'nbW',
- \ "line('.') < " . (plnum - s:maxoff) . " ? dummy :"
- \ . " synIDattr(synID(line('.'), col('.'), 1), 'name')"
- \ . " =~ '\\(Comment\\|Todo\\|String\\)$'",
- \ searchpair_stopline, searchpair_timeout)
- if parlnum > 0
- let plindent = indent(parlnum)
- let plnumstart = parlnum
- else
+
+ " Identing inside parentheses can be very slow, regardless of the searchpair()
+ " timeout, so let the user disable this feature if he doesn't need it
+ let disable_parentheses_indenting = get(g:, "pyindent_disable_parentheses_indenting", 0)
+
+ if disable_parentheses_indenting == 1
let plindent = indent(plnum)
let plnumstart = plnum
- endif
-
+ else
+ " searchpair() can be slow sometimes, limit the time to 150 msec or what is
+ " put in g:pyindent_searchpair_timeout
+ let searchpair_stopline = 0
+ let searchpair_timeout = get(g:, 'pyindent_searchpair_timeout', 150)
+
+ " If the previous line is inside parenthesis, use the indent of the starting
+ " line.
+ " Trick: use the non-existing "dummy" variable to break out of the loop when
+ " going too far back.
+ let parlnum = searchpair('(\|{\|\[', '', ')\|}\|\]', 'nbW',
+ \ "line('.') < " . (plnum - s:maxoff) . " ? dummy :"
+ \ . " synIDattr(synID(line('.'), col('.'), 1), 'name')"
+ \ . " =~ '\\(Comment\\|Todo\\|String\\)$'",
+ \ searchpair_stopline, searchpair_timeout)
+ if parlnum > 0
+ let plindent = indent(parlnum)
+ let plnumstart = parlnum
+ else
+ let plindent = indent(plnum)
+ let plnumstart = plnum
+ endif
- " When inside parenthesis: If at the first line below the parenthesis add
- " two 'shiftwidth', otherwise same as previous line.
- " i = (a
- " + b
- " + c)
- call cursor(a:lnum, 1)
- let p = searchpair('(\|{\|\[', '', ')\|}\|\]', 'bW',
- \ "line('.') < " . (a:lnum - s:maxoff) . " ? dummy :"
- \ . " synIDattr(synID(line('.'), col('.'), 1), 'name')"
- \ . " =~ '\\(Comment\\|Todo\\|String\\)$'",
- \ searchpair_stopline, searchpair_timeout)
- if p > 0
- if p == plnum
- " When the start is inside parenthesis, only indent one 'shiftwidth'.
- let pp = searchpair('(\|{\|\[', '', ')\|}\|\]', 'bW',
- \ "line('.') < " . (a:lnum - s:maxoff) . " ? dummy :"
- \ . " synIDattr(synID(line('.'), col('.'), 1), 'name')"
- \ . " =~ '\\(Comment\\|Todo\\|String\\)$'",
- \ searchpair_stopline, searchpair_timeout)
- if pp > 0
- return indent(plnum) + (exists("g:pyindent_nested_paren") ? eval(g:pyindent_nested_paren) : shiftwidth())
+ " When inside parenthesis: If at the first line below the parenthesis add
+ " two 'shiftwidth', otherwise same as previous line.
+ " i = (a
+ " + b
+ " + c)
+ call cursor(a:lnum, 1)
+ let p = searchpair('(\|{\|\[', '', ')\|}\|\]', 'bW',
+ \ "line('.') < " . (a:lnum - s:maxoff) . " ? dummy :"
+ \ . " synIDattr(synID(line('.'), col('.'), 1), 'name')"
+ \ . " =~ '\\(Comment\\|Todo\\|String\\)$'",
+ \ searchpair_stopline, searchpair_timeout)
+ if p > 0
+ if p == plnum
+ " When the start is inside parenthesis, only indent one 'shiftwidth'.
+ let pp = searchpair('(\|{\|\[', '', ')\|}\|\]', 'bW',
+ \ "line('.') < " . (a:lnum - s:maxoff) . " ? dummy :"
+ \ . " synIDattr(synID(line('.'), col('.'), 1), 'name')"
+ \ . " =~ '\\(Comment\\|Todo\\|String\\)$'",
+ \ searchpair_stopline, searchpair_timeout)
+ if pp > 0
+ return indent(plnum) + (exists("g:pyindent_nested_paren") ? eval(g:pyindent_nested_paren) : shiftwidth())
+ endif
+ return indent(plnum) + (exists("g:pyindent_open_paren") ? eval(g:pyindent_open_paren) : (shiftwidth() * 2))
endif
- return indent(plnum) + (exists("g:pyindent_open_paren") ? eval(g:pyindent_open_paren) : (shiftwidth() * 2))
- endif
- if plnumstart == p
- return indent(plnum)
+ if plnumstart == p
+ return indent(plnum)
+ endif
+ return plindent
endif
- return plindent
+
endif
diff --git a/runtime/indent/raml.vim b/runtime/indent/raml.vim
new file mode 100644
index 0000000000..73756ae7de
--- /dev/null
+++ b/runtime/indent/raml.vim
@@ -0,0 +1,12 @@
+" Vim indent file
+" Language: RAML (RESTful API Modeling Language)
+" Maintainer: mucheng <leisurelicht@gmail.com>
+" License: VIM LICENSE
+" Latest Revision: 2018-11-03
+
+if exists("b:did_indent")
+ finish
+endif
+
+" Same as yaml indenting.
+runtime! indent/yaml.vim
diff --git a/runtime/indent/rmd.vim b/runtime/indent/rmd.vim
index 182b07cbaa..83fe4e4fed 100644
--- a/runtime/indent/rmd.vim
+++ b/runtime/indent/rmd.vim
@@ -39,7 +39,7 @@ endfunction
function s:GetYamlIndent()
let pline = getline(v:lnum - 1)
if pline =~ ':\s*$'
- return indent(v:lnum) + &sw
+ return indent(v:lnum) + shiftwidth()
elseif pline =~ '^\s*- '
return indent(v:lnum) + 2
endif
diff --git a/runtime/indent/ruby.vim b/runtime/indent/ruby.vim
index d8733db305..5c420d7543 100644
--- a/runtime/indent/ruby.vim
+++ b/runtime/indent/ruby.vim
@@ -1,8 +1,10 @@
" Vim indent file
" Language: Ruby
-" Maintainer: Nikolai Weibull <now at bitwi.se>
+" Maintainer: Andrew Radev <andrey.radev@gmail.com>
+" 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: 2019 Jan 06
" 0. Initialization {{{1
" =================
@@ -18,6 +20,11 @@ if !exists('g:ruby_indent_access_modifier_style')
let g:ruby_indent_access_modifier_style = 'normal'
endif
+if !exists('g:ruby_indent_assignment_style')
+ " Possible values: "variable", "hanging"
+ let g:ruby_indent_assignment_style = 'hanging'
+endif
+
if !exists('g:ruby_indent_block_style')
" Possible values: "expression", "do"
let g:ruby_indent_block_style = 'expression'
@@ -42,28 +49,27 @@ set cpo&vim
" 1. Variables {{{1
" ============
-" Regex of syntax group names that are or delimit strings/symbols or are comments.
-let s:syng_strcom = '\<ruby\%(Regexp\|RegexpDelimiter\|RegexpEscape' .
- \ '\|Symbol\|String\|StringDelimiter\|StringEscape\|ASCIICode' .
- \ '\|Interpolation\|InterpolationDelimiter\|NoInterpolation\|Comment\|Documentation\)\>'
-
-" Regex of syntax group names that are strings.
+" Syntax group names that are strings.
let s:syng_string =
- \ '\<ruby\%(String\|Interpolation\|NoInterpolation\|StringEscape\)\>'
+ \ ['String', 'Interpolation', 'InterpolationDelimiter', 'NoInterpolation', 'StringEscape']
+
+" Syntax group names that are strings or documentation.
+let s:syng_stringdoc = s:syng_string + ['Documentation']
-" Regex of syntax group names that are strings or documentation.
-let s:syng_stringdoc =
- \'\<ruby\%(String\|Interpolation\|NoInterpolation\|StringEscape\|Documentation\)\>'
+" Syntax group names that are or delimit strings/symbols/regexes or are comments.
+let s:syng_strcom = s:syng_stringdoc +
+ \ ['Regexp', 'RegexpDelimiter', 'RegexpEscape',
+ \ 'Symbol', 'StringDelimiter', 'ASCIICode', 'Comment']
" Expression used to check whether we should skip a match with searchpair().
let s:skip_expr =
- \ "synIDattr(synID(line('.'),col('.'),1),'name') =~ '".s:syng_strcom."'"
+ \ 'index(map('.string(s:syng_strcom).',"hlID(''ruby''.v:val)"), synID(line("."),col("."),1)) >= 0'
" Regex used for words that, at the start of a line, add a level of indent.
let s:ruby_indent_keywords =
\ '^\s*\zs\<\%(module\|class\|if\|for' .
\ '\|while\|until\|else\|elsif\|case\|when\|unless\|begin\|ensure\|rescue' .
- \ '\|\%(public\|protected\|private\)\=\s*def\):\@!\>' .
+ \ '\|\%(\K\k*[!?]\?\)\=\s*def\):\@!\>' .
\ '\|\%([=,*/%+-]\|<<\|>>\|:\s\)\s*\zs' .
\ '\<\%(if\|for\|while\|until\|case\|unless\|begin\):\@!\>'
@@ -77,7 +83,7 @@ let s:ruby_deindent_keywords =
let s:end_start_regex =
\ '\C\%(^\s*\|[=,*/%+\-|;{]\|<<\|>>\|:\s\)\s*\zs' .
\ '\<\%(module\|class\|if\|for\|while\|until\|case\|unless\|begin' .
- \ '\|\%(public\|protected\|private\)\=\s*def\):\@!\>' .
+ \ '\|\%(\K\k*[!?]\?\)\=\s*def\):\@!\>' .
\ '\|\%(^\|[^.:@$]\)\@<=\<do:\@!\>'
" Regex that defines the middle-match for the 'end' keyword.
@@ -142,31 +148,562 @@ let s:block_continuation_regex = '^\s*[^])}\t ].*'.s:block_regex
" Regex that describes a leading operator (only a method call's dot for now)
let s:leading_operator_regex = '^\s*[.]'
-" 2. Auxiliary Functions {{{1
+" 2. GetRubyIndent Function {{{1
+" =========================
+
+function! GetRubyIndent(...) abort
+ " 2.1. Setup {{{2
+ " ----------
+
+ let indent_info = {}
+
+ " The value of a single shift-width
+ if exists('*shiftwidth')
+ let indent_info.sw = shiftwidth()
+ else
+ let indent_info.sw = &sw
+ endif
+
+ " For the current line, use the first argument if given, else v:lnum
+ let indent_info.clnum = a:0 ? a:1 : v:lnum
+ let indent_info.cline = getline(indent_info.clnum)
+
+ " Set up variables for restoring position in file. Could use clnum here.
+ let indent_info.col = col('.')
+
+ " 2.2. Work on the current line {{{2
+ " -----------------------------
+ let indent_callback_names = [
+ \ 's:AccessModifier',
+ \ 's:ClosingBracketOnEmptyLine',
+ \ 's:BlockComment',
+ \ 's:DeindentingKeyword',
+ \ 's:MultilineStringOrLineComment',
+ \ 's:ClosingHeredocDelimiter',
+ \ 's:LeadingOperator',
+ \ ]
+
+ for callback_name in indent_callback_names
+" Decho "Running: ".callback_name
+ let indent = call(function(callback_name), [indent_info])
+
+ if indent >= 0
+" Decho "Match: ".callback_name." indent=".indent." info=".string(indent_info)
+ return indent
+ endif
+ endfor
+
+ " 2.3. Work on the previous line. {{{2
+ " -------------------------------
+
+ " Special case: we don't need the real s:PrevNonBlankNonString for an empty
+ " line inside a string. And that call can be quite expensive in that
+ " particular situation.
+ let indent_callback_names = [
+ \ 's:EmptyInsideString',
+ \ ]
+
+ for callback_name in indent_callback_names
+" Decho "Running: ".callback_name
+ let indent = call(function(callback_name), [indent_info])
+
+ if indent >= 0
+" Decho "Match: ".callback_name." indent=".indent." info=".string(indent_info)
+ return indent
+ endif
+ endfor
+
+ " Previous line number
+ let indent_info.plnum = s:PrevNonBlankNonString(indent_info.clnum - 1)
+ let indent_info.pline = getline(indent_info.plnum)
+
+ let indent_callback_names = [
+ \ 's:StartOfFile',
+ \ 's:AfterAccessModifier',
+ \ 's:ContinuedLine',
+ \ 's:AfterBlockOpening',
+ \ 's:AfterHangingSplat',
+ \ 's:AfterUnbalancedBracket',
+ \ 's:AfterLeadingOperator',
+ \ 's:AfterEndKeyword',
+ \ 's:AfterIndentKeyword',
+ \ ]
+
+ for callback_name in indent_callback_names
+" Decho "Running: ".callback_name
+ let indent = call(function(callback_name), [indent_info])
+
+ if indent >= 0
+" Decho "Match: ".callback_name." indent=".indent." info=".string(indent_info)
+ return indent
+ endif
+ endfor
+
+ " 2.4. Work on the MSL line. {{{2
+ " --------------------------
+ let indent_callback_names = [
+ \ 's:PreviousNotMSL',
+ \ 's:IndentingKeywordInMSL',
+ \ 's:ContinuedHangingOperator',
+ \ ]
+
+ " Most Significant line based on the previous one -- in case it's a
+ " contination of something above
+ let indent_info.plnum_msl = s:GetMSL(indent_info.plnum)
+
+ for callback_name in indent_callback_names
+" Decho "Running: ".callback_name
+ let indent = call(function(callback_name), [indent_info])
+
+ if indent >= 0
+" Decho "Match: ".callback_name." indent=".indent." info=".string(indent_info)
+ return indent
+ endif
+ endfor
+
+ " }}}2
+
+ " By default, just return the previous line's indent
+" Decho "Default case matched"
+ return indent(indent_info.plnum)
+endfunction
+
+" 3. Indenting Logic Callbacks {{{1
+" ============================
+
+function! s:AccessModifier(cline_info) abort
+ let info = a:cline_info
+
+ " If this line is an access modifier keyword, align according to the closest
+ " class declaration.
+ if g:ruby_indent_access_modifier_style == 'indent'
+ if s:Match(info.clnum, s:access_modifier_regex)
+ let class_lnum = s:FindContainingClass()
+ if class_lnum > 0
+ return indent(class_lnum) + info.sw
+ endif
+ endif
+ elseif g:ruby_indent_access_modifier_style == 'outdent'
+ if s:Match(info.clnum, s:access_modifier_regex)
+ let class_lnum = s:FindContainingClass()
+ if class_lnum > 0
+ return indent(class_lnum)
+ endif
+ endif
+ endif
+
+ return -1
+endfunction
+
+function! s:ClosingBracketOnEmptyLine(cline_info) abort
+ let info = a:cline_info
+
+ " If we got a closing bracket on an empty line, find its match and indent
+ " according to it. For parentheses we indent to its column - 1, for the
+ " others we indent to the containing line's MSL's level. Return -1 if fail.
+ let col = matchend(info.cline, '^\s*[]})]')
+
+ if col > 0 && !s:IsInStringOrComment(info.clnum, col)
+ call cursor(info.clnum, col)
+ let closing_bracket = info.cline[col - 1]
+ let bracket_pair = strpart('(){}[]', stridx(')}]', closing_bracket) * 2, 2)
+
+ if searchpair(escape(bracket_pair[0], '\['), '', bracket_pair[1], 'bW', s:skip_expr) > 0
+ if closing_bracket == ')' && col('.') != col('$') - 1
+ let ind = virtcol('.') - 1
+ elseif g:ruby_indent_block_style == 'do'
+ let ind = indent(line('.'))
+ else " g:ruby_indent_block_style == 'expression'
+ let ind = indent(s:GetMSL(line('.')))
+ endif
+ endif
+
+ return ind
+ endif
+
+ return -1
+endfunction
+
+function! s:BlockComment(cline_info) abort
+ " If we have a =begin or =end set indent to first column.
+ if match(a:cline_info.cline, '^\s*\%(=begin\|=end\)$') != -1
+ return 0
+ endif
+ return -1
+endfunction
+
+function! s:DeindentingKeyword(cline_info) abort
+ let info = a:cline_info
+
+ " If we have a deindenting keyword, find its match and indent to its level.
+ " TODO: this is messy
+ if s:Match(info.clnum, s:ruby_deindent_keywords)
+ call cursor(info.clnum, 1)
+
+ if searchpair(s:end_start_regex, s:end_middle_regex, s:end_end_regex, 'bW',
+ \ s:end_skip_expr) > 0
+ let msl = s:GetMSL(line('.'))
+ let line = getline(line('.'))
+
+ if s:IsAssignment(line, col('.')) &&
+ \ strpart(line, col('.') - 1, 2) !~ 'do'
+ " assignment to case/begin/etc, on the same line
+ if g:ruby_indent_assignment_style == 'hanging'
+ " hanging indent
+ let ind = virtcol('.') - 1
+ else
+ " align with variable
+ let ind = indent(line('.'))
+ endif
+ elseif g:ruby_indent_block_style == 'do'
+ " align to line of the "do", not to the MSL
+ let ind = indent(line('.'))
+ elseif getline(msl) =~ '=\s*\(#.*\)\=$'
+ " in the case of assignment to the MSL, align to the starting line,
+ " not to the MSL
+ let ind = indent(line('.'))
+ else
+ " align to the MSL
+ let ind = indent(msl)
+ endif
+ endif
+ return ind
+ endif
+
+ return -1
+endfunction
+
+function! s:MultilineStringOrLineComment(cline_info) abort
+ let info = a:cline_info
+
+ " If we are in a multi-line string or line-comment, don't do anything to it.
+ if s:IsInStringOrDocumentation(info.clnum, matchend(info.cline, '^\s*') + 1)
+ return indent(info.clnum)
+ endif
+ return -1
+endfunction
+
+function! s:ClosingHeredocDelimiter(cline_info) abort
+ let info = a:cline_info
+
+ " If we are at the closing delimiter of a "<<" heredoc-style string, set the
+ " indent to 0.
+ if info.cline =~ '^\k\+\s*$'
+ \ && s:IsInStringDelimiter(info.clnum, 1)
+ \ && search('\V<<'.info.cline, 'nbW') > 0
+ return 0
+ endif
+
+ return -1
+endfunction
+
+function! s:LeadingOperator(cline_info) abort
+ " If the current line starts with a leading operator, add a level of indent.
+ if s:Match(a:cline_info.clnum, s:leading_operator_regex)
+ return indent(s:GetMSL(a:cline_info.clnum)) + a:cline_info.sw
+ endif
+ return -1
+endfunction
+
+function! s:EmptyInsideString(pline_info) abort
+ " If the line is empty and inside a string (the previous line is a string,
+ " too), use the previous line's indent
+ let info = a:pline_info
+
+ let plnum = prevnonblank(info.clnum - 1)
+ let pline = getline(plnum)
+
+ if info.cline =~ '^\s*$'
+ \ && s:IsInStringOrComment(plnum, 1)
+ \ && s:IsInStringOrComment(plnum, strlen(pline))
+ return indent(plnum)
+ endif
+ return -1
+endfunction
+
+function! s:StartOfFile(pline_info) abort
+ " At the start of the file use zero indent.
+ if a:pline_info.plnum == 0
+ return 0
+ endif
+ return -1
+endfunction
+
+function! s:AfterAccessModifier(pline_info) abort
+ let info = a:pline_info
+
+ if g:ruby_indent_access_modifier_style == 'indent'
+ " If the previous line was a private/protected keyword, add a
+ " level of indent.
+ if s:Match(info.plnum, s:indent_access_modifier_regex)
+ return indent(info.plnum) + info.sw
+ endif
+ elseif g:ruby_indent_access_modifier_style == 'outdent'
+ " If the previous line was a private/protected/public keyword, add
+ " a level of indent, since the keyword has been out-dented.
+ if s:Match(info.plnum, s:access_modifier_regex)
+ return indent(info.plnum) + info.sw
+ endif
+ endif
+ return -1
+endfunction
+
+" Example:
+"
+" if foo || bar ||
+" baz || bing
+" puts "foo"
+" end
+"
+function! s:ContinuedLine(pline_info) abort
+ let info = a:pline_info
+
+ let col = s:Match(info.plnum, s:ruby_indent_keywords)
+ if s:Match(info.plnum, s:continuable_regex) &&
+ \ s:Match(info.plnum, s:continuation_regex)
+ if col > 0 && s:IsAssignment(info.pline, col)
+ if g:ruby_indent_assignment_style == 'hanging'
+ " hanging indent
+ let ind = col - 1
+ else
+ " align with variable
+ let ind = indent(info.plnum)
+ endif
+ else
+ let ind = indent(s:GetMSL(info.plnum))
+ endif
+ return ind + info.sw + info.sw
+ endif
+ return -1
+endfunction
+
+function! s:AfterBlockOpening(pline_info) abort
+ let info = a:pline_info
+
+ " If the previous line ended with a block opening, add a level of indent.
+ if s:Match(info.plnum, s:block_regex)
+ if g:ruby_indent_block_style == 'do'
+ " don't align to the msl, align to the "do"
+ let ind = indent(info.plnum) + info.sw
+ else
+ let plnum_msl = s:GetMSL(info.plnum)
+
+ if getline(plnum_msl) =~ '=\s*\(#.*\)\=$'
+ " in the case of assignment to the msl, align to the starting line,
+ " not to the msl
+ let ind = indent(info.plnum) + info.sw
+ else
+ let ind = indent(plnum_msl) + info.sw
+ endif
+ endif
+
+ return ind
+ endif
+
+ return -1
+endfunction
+
+function! s:AfterLeadingOperator(pline_info) abort
+ " If the previous line started with a leading operator, use its MSL's level
+ " of indent
+ if s:Match(a:pline_info.plnum, s:leading_operator_regex)
+ return indent(s:GetMSL(a:pline_info.plnum))
+ endif
+ return -1
+endfunction
+
+function! s:AfterHangingSplat(pline_info) abort
+ let info = a:pline_info
+
+ " If the previous line ended with the "*" of a splat, add a level of indent
+ if info.pline =~ s:splat_regex
+ return indent(info.plnum) + info.sw
+ endif
+ return -1
+endfunction
+
+function! s:AfterUnbalancedBracket(pline_info) abort
+ let info = a:pline_info
+
+ " If the previous line contained unclosed opening brackets and we are still
+ " in them, find the rightmost one and add indent depending on the bracket
+ " type.
+ "
+ " If it contained hanging closing brackets, find the rightmost one, find its
+ " match and indent according to that.
+ if info.pline =~ '[[({]' || info.pline =~ '[])}]\s*\%(#.*\)\=$'
+ let [opening, closing] = s:ExtraBrackets(info.plnum)
+
+ if opening.pos != -1
+ if opening.type == '(' && searchpair('(', '', ')', 'bW', s:skip_expr) > 0
+ if col('.') + 1 == col('$')
+ return indent(info.plnum) + info.sw
+ else
+ return virtcol('.')
+ endif
+ else
+ let nonspace = matchend(info.pline, '\S', opening.pos + 1) - 1
+ return nonspace > 0 ? nonspace : indent(info.plnum) + info.sw
+ endif
+ elseif closing.pos != -1
+ call cursor(info.plnum, closing.pos + 1)
+ normal! %
+
+ if s:Match(line('.'), s:ruby_indent_keywords)
+ return indent('.') + info.sw
+ else
+ return indent(s:GetMSL(line('.')))
+ endif
+ else
+ call cursor(info.clnum, info.col)
+ end
+ endif
+
+ return -1
+endfunction
+
+function! s:AfterEndKeyword(pline_info) abort
+ let info = a:pline_info
+ " If the previous line ended with an "end", match that "end"s beginning's
+ " indent.
+ let col = s:Match(info.plnum, '\%(^\|[^.:@$]\)\<end\>\s*\%(#.*\)\=$')
+ if col > 0
+ call cursor(info.plnum, col)
+ if searchpair(s:end_start_regex, '', s:end_end_regex, 'bW',
+ \ s:end_skip_expr) > 0
+ let n = line('.')
+ let ind = indent('.')
+ let msl = s:GetMSL(n)
+ if msl != n
+ let ind = indent(msl)
+ end
+ return ind
+ endif
+ end
+ return -1
+endfunction
+
+function! s:AfterIndentKeyword(pline_info) abort
+ let info = a:pline_info
+ let col = s:Match(info.plnum, s:ruby_indent_keywords)
+
+ if col > 0
+ call cursor(info.plnum, col)
+ let ind = virtcol('.') - 1 + info.sw
+ " TODO: make this better (we need to count them) (or, if a searchpair
+ " fails, we know that something is lacking an end and thus we indent a
+ " level
+ if s:Match(info.plnum, s:end_end_regex)
+ let ind = indent('.')
+ elseif s:IsAssignment(info.pline, col)
+ if g:ruby_indent_assignment_style == 'hanging'
+ " hanging indent
+ let ind = col + info.sw - 1
+ else
+ " align with variable
+ let ind = indent(info.plnum) + info.sw
+ endif
+ endif
+ return ind
+ endif
+
+ return -1
+endfunction
+
+function! s:PreviousNotMSL(msl_info) abort
+ let info = a:msl_info
+
+ " If the previous line wasn't a MSL
+ if info.plnum != info.plnum_msl
+ " If previous line ends bracket and begins non-bracket continuation decrease indent by 1.
+ if s:Match(info.plnum, s:bracket_switch_continuation_regex)
+ " TODO (2016-10-07) Wrong/unused? How could it be "1"?
+ return indent(info.plnum) - 1
+ " If previous line is a continuation return its indent.
+ " TODO: the || s:IsInString() thing worries me a bit.
+ elseif s:Match(info.plnum, s:non_bracket_continuation_regex) || s:IsInString(info.plnum, strlen(line))
+ return indent(info.plnum)
+ endif
+ endif
+
+ return -1
+endfunction
+
+function! s:IndentingKeywordInMSL(msl_info) abort
+ let info = a:msl_info
+ " If the MSL line had an indenting keyword in it, add a level of indent.
+ " TODO: this does not take into account contrived things such as
+ " module Foo; class Bar; end
+ let col = s:Match(info.plnum_msl, s:ruby_indent_keywords)
+ if col > 0
+ let ind = indent(info.plnum_msl) + info.sw
+ if s:Match(info.plnum_msl, s:end_end_regex)
+ let ind = ind - info.sw
+ elseif s:IsAssignment(getline(info.plnum_msl), col)
+ if g:ruby_indent_assignment_style == 'hanging'
+ " hanging indent
+ let ind = col + info.sw - 1
+ else
+ " align with variable
+ let ind = indent(info.plnum_msl) + info.sw
+ endif
+ endif
+ return ind
+ endif
+ return -1
+endfunction
+
+function! s:ContinuedHangingOperator(msl_info) abort
+ let info = a:msl_info
+
+ " If the previous line ended with [*+/.,-=], but wasn't a block ending or a
+ " closing bracket, indent one extra level.
+ if s:Match(info.plnum_msl, s:non_bracket_continuation_regex) && !s:Match(info.plnum_msl, '^\s*\([\])}]\|end\)')
+ if info.plnum_msl == info.plnum
+ let ind = indent(info.plnum_msl) + info.sw
+ else
+ let ind = indent(info.plnum_msl)
+ endif
+ return ind
+ endif
+
+ return -1
+endfunction
+
+" 4. Auxiliary Functions {{{1
" ======================
+function! s:IsInRubyGroup(groups, lnum, col) abort
+ let ids = map(copy(a:groups), 'hlID("ruby".v:val)')
+ return index(ids, synID(a:lnum, a:col, 1)) >= 0
+endfunction
+
" Check if the character at lnum:col is inside a string, comment, or is ascii.
-function s:IsInStringOrComment(lnum, col)
- return synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_strcom
+function! s:IsInStringOrComment(lnum, col) abort
+ return s:IsInRubyGroup(s:syng_strcom, a:lnum, a:col)
endfunction
" 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') =~ s:syng_string
+function! s:IsInString(lnum, col) abort
+ return s:IsInRubyGroup(s:syng_string, a:lnum, a:col)
endfunction
" Check if the character at lnum:col is inside a string or documentation.
-function s:IsInStringOrDocumentation(lnum, col)
- return synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_stringdoc
+function! s:IsInStringOrDocumentation(lnum, col) abort
+ return s:IsInRubyGroup(s:syng_stringdoc, a:lnum, a:col)
endfunction
" Check if the character at lnum:col is inside a string delimiter
-function s:IsInStringDelimiter(lnum, col)
- return synIDattr(synID(a:lnum, a:col, 1), 'name') == 'rubyStringDelimiter'
+function! s:IsInStringDelimiter(lnum, col) abort
+ return s:IsInRubyGroup(['StringDelimiter'], a:lnum, a:col)
+endfunction
+
+function! s:IsAssignment(str, pos) abort
+ return strpart(a:str, 0, a:pos - 1) =~ '=\s*$'
endfunction
" Find line above 'lnum' that isn't empty, in a comment, or in a string.
-function s:PrevNonBlankNonString(lnum)
+function! s:PrevNonBlankNonString(lnum) abort
let in_block = 0
let lnum = prevnonblank(a:lnum)
while lnum > 0
@@ -191,10 +728,9 @@ function s:PrevNonBlankNonString(lnum)
endfunction
" Find line above 'lnum' that started the continuation 'lnum' may be part of.
-function s:GetMSL(lnum)
+function! s:GetMSL(lnum) abort
" Start on the line we're at and use its indent.
let msl = a:lnum
- let msl_body = getline(msl)
let lnum = s:PrevNonBlankNonString(a:lnum - 1)
while lnum > 0
" If we have a continuation line, or we're in a string, use line as MSL.
@@ -291,14 +827,13 @@ function s:GetMSL(lnum)
endif
endif
- let msl_body = getline(msl)
let lnum = s:PrevNonBlankNonString(lnum - 1)
endwhile
return msl
endfunction
" Check if line 'lnum' has more opening brackets than closing ones.
-function s:ExtraBrackets(lnum)
+function! s:ExtraBrackets(lnum) abort
let opening = {'parentheses': [], 'braces': [], 'brackets': []}
let closing = {'parentheses': [], 'braces': [], 'brackets': []}
@@ -360,7 +895,7 @@ function s:ExtraBrackets(lnum)
return [rightmost_opening, rightmost_closing]
endfunction
-function s:Match(lnum, regex)
+function! s:Match(lnum, regex) abort
let line = getline(a:lnum)
let offset = match(line, '\C'.a:regex)
let col = offset + 1
@@ -380,7 +915,7 @@ endfunction
" Locates the containing class/module's definition line, ignoring nested classes
" along the way.
"
-function! s:FindContainingClass()
+function! s:FindContainingClass() abort
let saved_position = getpos('.')
while searchpair(s:end_start_regex, s:end_middle_regex, s:end_end_regex, 'bW',
@@ -396,297 +931,6 @@ function! s:FindContainingClass()
return 0
endfunction
-" 3. GetRubyIndent Function {{{1
-" =========================
-
-function GetRubyIndent(...)
- " 3.1. Setup {{{2
- " ----------
-
- " The value of a single shift-width
- let sw = shiftwidth()
-
- " For the current line, use the first argument if given, else v:lnum
- let clnum = a:0 ? a:1 : v:lnum
-
- " Set up variables for restoring position in file. Could use clnum here.
- let vcol = col('.')
-
- " 3.2. Work on the current line {{{2
- " -----------------------------
-
- " Get the current line.
- let line = getline(clnum)
- let ind = -1
-
- " If this line is an access modifier keyword, align according to the closest
- " class declaration.
- if g:ruby_indent_access_modifier_style == 'indent'
- if s:Match(clnum, s:access_modifier_regex)
- let class_line = s:FindContainingClass()
- if class_line > 0
- return indent(class_line) + sw
- endif
- endif
- elseif g:ruby_indent_access_modifier_style == 'outdent'
- if s:Match(clnum, s:access_modifier_regex)
- let class_line = s:FindContainingClass()
- if class_line > 0
- return indent(class_line)
- endif
- endif
- endif
-
- " If we got a closing bracket on an empty line, find its match and indent
- " according to it. For parentheses we indent to its column - 1, for the
- " others we indent to the containing line's MSL's level. Return -1 if fail.
- let col = matchend(line, '^\s*[]})]')
- if col > 0 && !s:IsInStringOrComment(clnum, col)
- call cursor(clnum, col)
- let bs = strpart('(){}[]', stridx(')}]', line[col - 1]) * 2, 2)
- if searchpair(escape(bs[0], '\['), '', bs[1], 'bW', s:skip_expr) > 0
- if line[col-1]==')' && col('.') != col('$') - 1
- let ind = virtcol('.') - 1
- elseif g:ruby_indent_block_style == 'do'
- let ind = indent(line('.'))
- else " g:ruby_indent_block_style == 'expression'
- let ind = indent(s:GetMSL(line('.')))
- endif
- endif
- return ind
- endif
-
- " If we have a =begin or =end set indent to first column.
- if match(line, '^\s*\%(=begin\|=end\)$') != -1
- return 0
- endif
-
- " If we have a deindenting keyword, find its match and indent to its level.
- " TODO: this is messy
- if s:Match(clnum, s:ruby_deindent_keywords)
- call cursor(clnum, 1)
- if searchpair(s:end_start_regex, s:end_middle_regex, s:end_end_regex, 'bW',
- \ s:end_skip_expr) > 0
- let msl = s:GetMSL(line('.'))
- let line = getline(line('.'))
-
- if strpart(line, 0, col('.') - 1) =~ '=\s*$' &&
- \ strpart(line, col('.') - 1, 2) !~ 'do'
- " assignment to case/begin/etc, on the same line, hanging indent
- let ind = virtcol('.') - 1
- elseif g:ruby_indent_block_style == 'do'
- " align to line of the "do", not to the MSL
- let ind = indent(line('.'))
- elseif getline(msl) =~ '=\s*\(#.*\)\=$'
- " in the case of assignment to the MSL, align to the starting line,
- " not to the MSL
- let ind = indent(line('.'))
- else
- " align to the MSL
- let ind = indent(msl)
- endif
- endif
- return ind
- endif
-
- " If we are in a multi-line string or line-comment, don't do anything to it.
- if s:IsInStringOrDocumentation(clnum, matchend(line, '^\s*') + 1)
- return indent('.')
- endif
-
- " If we are at the closing delimiter of a "<<" heredoc-style string, set the
- " indent to 0.
- if line =~ '^\k\+\s*$'
- \ && s:IsInStringDelimiter(clnum, 1)
- \ && search('\V<<'.line, 'nbW') > 0
- return 0
- endif
-
- " If the current line starts with a leading operator, add a level of indent.
- if s:Match(clnum, s:leading_operator_regex)
- return indent(s:GetMSL(clnum)) + sw
- endif
-
- " 3.3. Work on the previous line. {{{2
- " -------------------------------
-
- " Find a non-blank, non-multi-line string line above the current line.
- let lnum = s:PrevNonBlankNonString(clnum - 1)
-
- " If the line is empty and inside a string, use the previous line.
- if line =~ '^\s*$' && lnum != prevnonblank(clnum - 1)
- return indent(prevnonblank(clnum))
- endif
-
- " At the start of the file use zero indent.
- if lnum == 0
- return 0
- endif
-
- " Set up variables for the previous line.
- let line = getline(lnum)
- let ind = indent(lnum)
-
- if g:ruby_indent_access_modifier_style == 'indent'
- " If the previous line was a private/protected keyword, add a
- " level of indent.
- if s:Match(lnum, s:indent_access_modifier_regex)
- return indent(lnum) + sw
- endif
- elseif g:ruby_indent_access_modifier_style == 'outdent'
- " If the previous line was a private/protected/public keyword, add
- " a level of indent, since the keyword has been out-dented.
- if s:Match(lnum, s:access_modifier_regex)
- return indent(lnum) + sw
- endif
- endif
-
- if s:Match(lnum, s:continuable_regex) && s:Match(lnum, s:continuation_regex)
- return indent(s:GetMSL(lnum)) + sw + sw
- endif
-
- " If the previous line ended with a block opening, add a level of indent.
- if s:Match(lnum, s:block_regex)
- let msl = s:GetMSL(lnum)
-
- if g:ruby_indent_block_style == 'do'
- " don't align to the msl, align to the "do"
- let ind = indent(lnum) + sw
- elseif getline(msl) =~ '=\s*\(#.*\)\=$'
- " in the case of assignment to the msl, align to the starting line,
- " not to the msl
- let ind = indent(lnum) + sw
- else
- let ind = indent(msl) + sw
- endif
- return ind
- endif
-
- " If the previous line started with a leading operator, use its MSL's level
- " of indent
- if s:Match(lnum, s:leading_operator_regex)
- return indent(s:GetMSL(lnum))
- endif
-
- " If the previous line ended with the "*" of a splat, add a level of indent
- if line =~ s:splat_regex
- return indent(lnum) + sw
- endif
-
- " If the previous line contained unclosed opening brackets and we are still
- " in them, find the rightmost one and add indent depending on the bracket
- " type.
- "
- " If it contained hanging closing brackets, find the rightmost one, find its
- " match and indent according to that.
- if line =~ '[[({]' || line =~ '[])}]\s*\%(#.*\)\=$'
- let [opening, closing] = s:ExtraBrackets(lnum)
-
- if opening.pos != -1
- if opening.type == '(' && searchpair('(', '', ')', 'bW', s:skip_expr) > 0
- if col('.') + 1 == col('$')
- return ind + sw
- else
- return virtcol('.')
- endif
- else
- let nonspace = matchend(line, '\S', opening.pos + 1) - 1
- return nonspace > 0 ? nonspace : ind + sw
- endif
- elseif closing.pos != -1
- call cursor(lnum, closing.pos + 1)
- normal! %
-
- if s:Match(line('.'), s:ruby_indent_keywords)
- return indent('.') + sw
- else
- return indent(s:GetMSL(line('.')))
- endif
- else
- call cursor(clnum, vcol)
- end
- endif
-
- " If the previous line ended with an "end", match that "end"s beginning's
- " indent.
- let col = s:Match(lnum, '\%(^\|[^.:@$]\)\<end\>\s*\%(#.*\)\=$')
- if col > 0
- call cursor(lnum, col)
- if searchpair(s:end_start_regex, '', s:end_end_regex, 'bW',
- \ s:end_skip_expr) > 0
- let n = line('.')
- let ind = indent('.')
- let msl = s:GetMSL(n)
- if msl != n
- let ind = indent(msl)
- end
- return ind
- endif
- end
-
- let col = s:Match(lnum, s:ruby_indent_keywords)
- if col > 0
- call cursor(lnum, col)
- let ind = virtcol('.') - 1 + sw
- " TODO: make this better (we need to count them) (or, if a searchpair
- " fails, we know that something is lacking an end and thus we indent a
- " level
- if s:Match(lnum, s:end_end_regex)
- let ind = indent('.')
- endif
- return ind
- endif
-
- " 3.4. Work on the MSL line. {{{2
- " --------------------------
-
- " Set up variables to use and search for MSL to the previous line.
- let p_lnum = lnum
- let lnum = s:GetMSL(lnum)
-
- " If the previous line wasn't a MSL.
- if p_lnum != lnum
- " If previous line ends bracket and begins non-bracket continuation decrease indent by 1.
- if s:Match(p_lnum, s:bracket_switch_continuation_regex)
- return ind - 1
- " If previous line is a continuation return its indent.
- " TODO: the || s:IsInString() thing worries me a bit.
- elseif s:Match(p_lnum, s:non_bracket_continuation_regex) || s:IsInString(p_lnum,strlen(line))
- return ind
- endif
- endif
-
- " Set up more variables, now that we know we wasn't continuation bound.
- let line = getline(lnum)
- let msl_ind = indent(lnum)
-
- " If the MSL line had an indenting keyword in it, add a level of indent.
- " TODO: this does not take into account contrived things such as
- " module Foo; class Bar; end
- if s:Match(lnum, s:ruby_indent_keywords)
- let ind = msl_ind + sw
- if s:Match(lnum, s:end_end_regex)
- let ind = ind - sw
- endif
- return ind
- endif
-
- " If the previous line ended with [*+/.,-=], but wasn't a block ending or a
- " closing bracket, indent one extra level.
- if s:Match(lnum, s:non_bracket_continuation_regex) && !s:Match(lnum, '^\s*\([\])}]\|end\)')
- if lnum == p_lnum
- let ind = msl_ind + sw
- else
- let ind = msl_ind
- endif
- return ind
- endif
-
- " }}}2
-
- return ind
-endfunction
-
" }}}1
let &cpo = s:cpo_save
diff --git a/runtime/indent/sh.vim b/runtime/indent/sh.vim
index 32bc9f35bb..3df6abbf97 100644
--- a/runtime/indent/sh.vim
+++ b/runtime/indent/sh.vim
@@ -3,10 +3,22 @@
" Maintainer: Christian Brabandt <cb@256bit.org>
" Original Author: Nikolai Weibull <now@bitwi.se>
" Previous Maintainer: Peter Aronoff <telemachus@arpinum.org>
-" Latest Revision: 2018-03-26
+" Latest Revision: 2019-07-26
" License: Vim (see :h license)
" Repository: https://github.com/chrisbra/vim-sh-indent
" Changelog:
+" 20190726 - Correctly skip if keywords in syntax comments
+" (issue #17)
+" 20190603 - Do not indent in zsh filetypes with an `if` in comments
+" 20190428 - De-indent fi correctly when typing with
+" https://github.com/chrisbra/vim-sh-indent/issues/15
+" 20190325 - Indent fi; correctly
+" https://github.com/chrisbra/vim-sh-indent/issues/14
+" 20190319 - Indent arrays (only zsh and bash)
+" https://github.com/chrisbra/vim-sh-indent/issues/13
+" 20190316 - Make use of searchpairpos for nested if sections
+" fixes https://github.com/chrisbra/vim-sh-indent/issues/11
+" 20190201 - Better check for closing if sections
" 20180724 - make check for zsh syntax more rigid (needs word-boundaries)
" 20180326 - better support for line continuation
" 20180325 - better detection of function definitions
@@ -59,6 +71,7 @@ function! s:indent_value(option)
endfunction
function! GetShIndent()
+ let curline = getline(v:lnum)
let lnum = prevnonblank(v:lnum - 1)
if lnum == 0
return 0
@@ -70,9 +83,10 @@ function! GetShIndent()
let ind = indent(lnum)
" Check contents of previous lines
+ " should not apply to e.g. commented lines
if line =~ '^\s*\%(if\|then\|do\|else\|elif\|case\|while\|until\|for\|select\|foreach\)\>' ||
- \ (&ft is# 'zsh' && line =~ '\<\%(if\|then\|do\|else\|elif\|case\|while\|until\|for\|select\|foreach\)\>')
- if line !~ '\<\%(fi\|esac\|done\|end\)\>\s*\%(#.*\)\=$'
+ \ (&ft is# 'zsh' && line =~ '^\s*\<\%(if\|then\|do\|else\|elif\|case\|while\|until\|for\|select\|foreach\)\>')
+ if !s:is_end_expression(line)
let ind += s:indent_value('default')
endif
elseif s:is_case_label(line, pnum)
@@ -84,13 +98,22 @@ function! GetShIndent()
if line !~ '}\s*\%(#.*\)\=$'
let ind += s:indent_value('default')
endif
+ " array (only works for zsh or bash)
+ elseif s:is_array(line) && line !~ ')\s*$' && (&ft is# 'zsh' || s:is_bash())
+ let ind += s:indent_value('continuation-line')
+ " end of array
+ elseif curline =~ '^\s*)$'
+ let ind -= s:indent_value('continuation-line')
elseif s:is_continuation_line(line)
if pnum == 0 || !s:is_continuation_line(pline)
let ind += s:indent_value('continuation-line')
endif
elseif s:end_block(line) && !s:start_block(line)
let ind -= s:indent_value('default')
- elseif pnum != 0 && s:is_continuation_line(pline) && !s:end_block(getline(v:lnum))
+ elseif pnum != 0 &&
+ \ s:is_continuation_line(pline) &&
+ \ !s:end_block(curline) &&
+ \ !s:is_end_expression(curline)
" only add indent, if line and pline is in the same block
let i = v:lnum
let ind2 = indent(s:find_continued_lnum(pnum))
@@ -106,8 +129,16 @@ function! GetShIndent()
let pine = line
" Check content of current line
- let line = getline(v:lnum)
- if line =~ '^\s*\%(then\|do\|else\|elif\|fi\|done\|end\)\>' || s:end_block(line)
+ let line = curline
+ " Current line is a endif line, so get indent from start of "if condition" line
+ " TODO: should we do the same for other "end" lines?
+ if curline =~ '^\s*\%(fi\);\?\s*\%(#.*\)\=$'
+ let ind = indent(v:lnum)
+ let previous_line = searchpair('\<if\>', '', '\<fi\>\zs', 'bnW', 'synIDattr(synID(line("."),col("."), 1),"name") =~? "comment"')
+ if previous_line > 0
+ let ind = indent(previous_line)
+ endif
+ elseif line =~ '^\s*\%(then\|do\|else\|elif\|done\|end\)\>' || s:end_block(line)
let ind -= s:indent_value('default')
elseif line =~ '^\s*esac\>' && s:is_case_empty(getline(v:lnum - 1))
let ind -= s:indent_value('default')
@@ -167,6 +198,10 @@ function! s:is_function_definition(line)
\ a:line =~ '^\s*function\s*\w\S\+\s*\%(()\)\?\s*{'
endfunction
+function! s:is_array(line)
+ return a:line =~ '^\s*\<\k\+\>=('
+endfunction
+
function! s:is_case_label(line, pnum)
if a:line !~ '^\s*(\=.*)'
return 0
@@ -210,8 +245,8 @@ endfunction
function! s:is_here_doc(line)
if a:line =~ '^\w\+$'
- let here_pat = '<<-\?'. s:escape(a:line). '\$'
- return search(here_pat, 'bnW') > 0
+ let here_pat = '<<-\?'. s:escape(a:line). '\$'
+ return search(here_pat, 'bnW') > 0
endif
return 0
endfunction
@@ -256,5 +291,13 @@ function! s:is_comment(line)
return a:line =~ '^\s*#'
endfunction
+function! s:is_end_expression(line)
+ return a:line =~ '\<\%(fi\|esac\|done\|end\)\>\s*\%(#.*\)\=$'
+endfunction
+
+function! s:is_bash()
+ return get(g:, 'is_bash', 0) || get(b:, 'is_bash', 0)
+endfunction
+
let &cpo = s:cpo_save
unlet s:cpo_save
diff --git a/runtime/indent/tcl.vim b/runtime/indent/tcl.vim
index e9d61e4366..d77081841d 100644
--- a/runtime/indent/tcl.vim
+++ b/runtime/indent/tcl.vim
@@ -1,7 +1,8 @@
" Vim indent file
-" Language: Tcl
-" Maintainer: Nikolai Weibull <now@bitwi.se>
-" Latest Revision: 2006-12-20
+" Language: Tcl
+" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
+" Latest Update: Chris Heithoff <chrisheithoff@gmail.com>
+" Latest Revision: 2018-12-05
if exists("b:did_indent")
finish
@@ -28,6 +29,15 @@ function s:prevnonblanknoncomment(lnum)
return lnum
endfunction
+function s:ends_with_backslash(lnum)
+ let line = getline(a:lnum)
+ if line =~ '\\\s*$'
+ return 1
+ else
+ return 0
+ endif
+endfunction
+
function s:count_braces(lnum, count_open)
let n_open = 0
let n_close = 0
@@ -53,23 +63,39 @@ endfunction
function GetTclIndent()
let line = getline(v:lnum)
- if line =~ '^\s*\*'
- return cindent(v:lnum)
- elseif line =~ '^\s*}'
- return indent(v:lnum) - shiftwidth()
- endif
+ " Get the line number of the previous non-blank or non-comment line.
let pnum = s:prevnonblanknoncomment(v:lnum - 1)
if pnum == 0
return 0
endif
- let ind = indent(pnum) + s:count_braces(pnum, 1) * shiftwidth()
+ " ..and the previous line before the previous line.
+ let pnum2 = s:prevnonblanknoncomment(pnum-1)
- let pline = getline(pnum)
- if pline =~ '}\s*$'
- let ind -= (s:count_braces(pnum, 0) - (pline =~ '^\s*}' ? 1 : 0)) * shiftwidth()
+ " Default indentation is to preserve the previous indentation.
+ let ind = indent(pnum)
+
+ " ...but if previous line introduces an open brace, then increase current line's indentation
+ if s:count_braces(pnum, 1) > 0
+ let ind += shiftwidth()
+ else
+ " Look for backslash line continuation on the previous two lines.
+ let slash1 = s:ends_with_backslash(pnum)
+ let slash2 = s:ends_with_backslash(pnum2)
+ if slash1 && !slash2
+ " If the previous line begins a line continuation.
+ let ind += shiftwidth()
+ elseif !slash1 && slash2
+ " If two lines ago was the end of a line continuation group of lines.
+ let ind -= shiftwidth()
+ endif
endif
+ " If the current line begins with a closed brace, then decrease the indentation by one.
+ if line =~ '^\s*}'
+ let ind -= shiftwidth()
+ endif
+
return ind
endfunction
diff --git a/runtime/indent/testdir/html.in b/runtime/indent/testdir/html.in
new file mode 100644
index 0000000000..9c776d61c6
--- /dev/null
+++ b/runtime/indent/testdir/html.in
@@ -0,0 +1,26 @@
+" vim: set ft=html sw=4 :
+
+
+" START_INDENT
+<div>
+<div>
+text
+</div>
+</div>
+
+<div
+class="foo bar">
+text
+</div>
+
+<div class="foo bar"
+data="something">
+text
+</div>
+
+<div class="foo
+bar">
+text
+</div>
+
+" END_INDENT
diff --git a/runtime/indent/testdir/html.ok b/runtime/indent/testdir/html.ok
new file mode 100644
index 0000000000..ad819333cc
--- /dev/null
+++ b/runtime/indent/testdir/html.ok
@@ -0,0 +1,26 @@
+" vim: set ft=html sw=4 :
+
+
+" START_INDENT
+<div>
+ <div>
+ text
+ </div>
+</div>
+
+<div
+ class="foo bar">
+ text
+</div>
+
+<div class="foo bar"
+ data="something">
+ text
+</div>
+
+<div class="foo
+ bar">
+ text
+</div>
+
+" END_INDENT
diff --git a/runtime/indent/testdir/matlab.in b/runtime/indent/testdir/matlab.in
new file mode 100644
index 0000000000..5bba1a56dd
--- /dev/null
+++ b/runtime/indent/testdir/matlab.in
@@ -0,0 +1,80 @@
+% vim: set ft=matlab sw=4 :
+
+% START_INDENT
+if true
+disp foo
+elseif false
+disp bar
+end
+% END_INDENT
+
+% START_INDENT
+try
+statements
+catch exception
+statements
+end
+% END_INDENT
+
+% START_INDENT
+if true, ...
+if true
+disp hello
+end
+end
+% END_INDENT
+
+% START_INDENT
+switch a
+case expr
+if true, foo; end
+disp hello
+otherwise
+disp bar
+end
+% END_INDENT
+
+% START_INDENT
+if true
+A(1:end - 1)
+disp foo
+end
+% END_INDENT
+
+% START_INDENT
+A = [{
+}
+] ...
+disp foo
+disp bar
+% END_INDENT
+
+% START_INDENT
+% INDENT_EXE let b:MATLAB_function_indent = 0
+function foo
+disp foo
+function nested
+disp bar
+end
+end
+% END_INDENT
+
+% START_INDENT
+% INDENT_EXE let b:MATLAB_function_indent = 1
+function foo
+disp foo
+function nested
+disp bar
+end
+end
+% END_INDENT
+
+% START_INDENT
+% INDENT_EXE let b:MATLAB_function_indent = 2
+function foo
+disp foo
+function nested
+disp bar
+end
+end
+% END_INDENT
diff --git a/runtime/indent/testdir/matlab.ok b/runtime/indent/testdir/matlab.ok
new file mode 100644
index 0000000000..b1112263b2
--- /dev/null
+++ b/runtime/indent/testdir/matlab.ok
@@ -0,0 +1,80 @@
+% vim: set ft=matlab sw=4 :
+
+% START_INDENT
+if true
+ disp foo
+elseif false
+ disp bar
+end
+% END_INDENT
+
+% START_INDENT
+try
+ statements
+catch exception
+ statements
+end
+% END_INDENT
+
+% START_INDENT
+if true, ...
+ if true
+ disp hello
+ end
+end
+% END_INDENT
+
+% START_INDENT
+switch a
+ case expr
+ if true, foo; end
+ disp hello
+ otherwise
+ disp bar
+end
+% END_INDENT
+
+% START_INDENT
+if true
+ A(1:end - 1)
+ disp foo
+end
+% END_INDENT
+
+% START_INDENT
+A = [{
+ }
+ ] ...
+ disp foo
+disp bar
+% END_INDENT
+
+% START_INDENT
+% INDENT_EXE let b:MATLAB_function_indent = 0
+function foo
+disp foo
+ function nested
+ disp bar
+ end
+end
+% END_INDENT
+
+% START_INDENT
+% INDENT_EXE let b:MATLAB_function_indent = 1
+function foo
+disp foo
+ function nested
+ disp bar
+ end
+end
+% END_INDENT
+
+% START_INDENT
+% INDENT_EXE let b:MATLAB_function_indent = 2
+function foo
+ disp foo
+ function nested
+ disp bar
+ end
+end
+% END_INDENT
diff --git a/runtime/indent/testdir/tcl.in b/runtime/indent/testdir/tcl.in
new file mode 100644
index 0000000000..c769d5bf5e
--- /dev/null
+++ b/runtime/indent/testdir/tcl.in
@@ -0,0 +1,19 @@
+# vim: set filetype=tcl shiftwidth=4 tabstop=8 expandtab :
+
+# START_INDENT
+proc abc {} {
+set a 5
+if {[some_cmd]==1} {
+foreach i [list {1 2 3}] {
+# Does this comment affect anything?
+puts $i
+}
+}
+}
+
+command_with_a_long_time -arg1 "First" \
+-arg2 "Second" \
+-arg3 "Third"
+
+puts "Move indent back after line continuation is complete"
+# END_INDENT \ No newline at end of file
diff --git a/runtime/indent/testdir/tcl.ok b/runtime/indent/testdir/tcl.ok
new file mode 100644
index 0000000000..77f24e9044
--- /dev/null
+++ b/runtime/indent/testdir/tcl.ok
@@ -0,0 +1,19 @@
+# vim: set filetype=tcl shiftwidth=4 tabstop=8 expandtab :
+
+# START_INDENT
+proc abc {} {
+ set a 5
+ if {[some_cmd]==1} {
+ foreach i [list {1 2 3}] {
+ # Does this comment affect anything?
+ puts $i
+ }
+ }
+}
+
+command_with_a_long_time -arg1 "First" \
+ -arg2 "Second" \
+ -arg3 "Third"
+
+puts "Move indent back after line continuation is complete"
+# END_INDENT
diff --git a/runtime/indent/testdir/xml.in b/runtime/indent/testdir/xml.in
new file mode 100644
index 0000000000..b6333340e2
--- /dev/null
+++ b/runtime/indent/testdir/xml.in
@@ -0,0 +1,32 @@
+<!-- vim: set ft=xml ts=8 sw=0 sts=-1 et : -->
+<!-- START_INDENT -->
+<?xml version="1.0" encoding="utf-8"?>
+<tag0>
+ <tag1>
+<!-- comment -->
+<tag2>
+ <tag3/>
+</tag2>
+<!-- text comment -->
+
+<!--
+text comment
+-->
+</tag1>
+<!--
+text comment
+end coment -->
+</tag0>
+<!-- END_INDENT -->
+
+<!-- START_INDENT -->
+<?xml version="1.0" encoding="utf-8"?>
+<tag0>
+ <tag1>
+<!-- comment -->
+<tag2>
+ <tag3/>
+</tag2>
+</tag1>
+</tag0>
+<!-- END_INDENT -->
diff --git a/runtime/indent/testdir/xml.ok b/runtime/indent/testdir/xml.ok
new file mode 100644
index 0000000000..cfdf701c11
--- /dev/null
+++ b/runtime/indent/testdir/xml.ok
@@ -0,0 +1,32 @@
+<!-- vim: set ft=xml ts=8 sw=0 sts=-1 et : -->
+<!-- START_INDENT -->
+<?xml version="1.0" encoding="utf-8"?>
+<tag0>
+ <tag1>
+ <!-- comment -->
+ <tag2>
+ <tag3/>
+ </tag2>
+ <!-- text comment -->
+
+ <!--
+ text comment
+ -->
+ </tag1>
+ <!--
+ text comment
+ end coment -->
+</tag0>
+<!-- END_INDENT -->
+
+<!-- START_INDENT -->
+<?xml version="1.0" encoding="utf-8"?>
+<tag0>
+ <tag1>
+ <!-- comment -->
+ <tag2>
+ <tag3/>
+ </tag2>
+ </tag1>
+</tag0>
+<!-- END_INDENT -->
diff --git a/runtime/indent/typescript.vim b/runtime/indent/typescript.vim
new file mode 100644
index 0000000000..69accaa054
--- /dev/null
+++ b/runtime/indent/typescript.vim
@@ -0,0 +1,503 @@
+" Vim indent file
+" Language: TypeScript
+" Maintainer: See https://github.com/HerringtonDarkholme/yats.vim
+" Last Change: 2019 Jun 06
+" Acknowledgement: Based off of vim-ruby maintained by Nikolai Weibull http://vim-ruby.rubyforge.org
+
+" 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=GetTypescriptIndent()
+setlocal formatexpr=Fixedgq(v:lnum,v:count)
+setlocal indentkeys=0{,0},0),0],0\,,!^F,o,O,e
+
+" Only define the function once.
+if exists("*GetTypescriptIndent")
+ finish
+endif
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+" 1. Variables {{{1
+" ============
+
+let s:js_keywords = '^\s*\(break\|case\|catch\|continue\|debugger\|default\|delete\|do\|else\|finally\|for\|function\|if\|in\|instanceof\|new\|return\|switch\|this\|throw\|try\|typeof\|var\|void\|while\|with\)'
+
+" Regex of syntax group names that are or delimit string or are comments.
+let s:syng_strcom = 'string\|regex\|comment\c'
+
+" Regex of syntax group names that are strings.
+let s:syng_string = 'regex\c'
+
+" Regex of syntax group names that are strings or documentation.
+let s:syng_multiline = 'comment\c'
+
+" Regex of syntax group names that are line comment.
+let s:syng_linecom = 'linecomment\c'
+
+" Expression used to check whether we should skip a match with searchpair().
+let s:skip_expr = "synIDattr(synID(line('.'),col('.'),1),'name') =~ '".s:syng_strcom."'"
+
+let s:line_term = '\s*\%(\%(\/\/\).*\)\=$'
+
+" Regex that defines continuation lines, not including (, {, or [.
+let s:continuation_regex = '\%([\\*+/.:]\|\%(<%\)\@<![=-]\|\W[|&?]\|||\|&&\|[^=]=[^=].*,\)' . s:line_term
+
+" Regex that defines continuation lines.
+" TODO: this needs to deal with if ...: and so on
+let s:msl_regex = s:continuation_regex
+
+let s:one_line_scope_regex = '\<\%(if\|else\|for\|while\)\>[^{;]*' . s:line_term
+
+" Regex that defines blocks.
+let s:block_regex = '\%([{[]\)\s*\%(|\%([*@]\=\h\w*,\=\s*\)\%(,\s*[*@]\=\h\w*\)*|\)\=' . s:line_term
+
+let s:var_stmt = '^\s*var'
+
+let s:comma_first = '^\s*,'
+let s:comma_last = ',\s*$'
+
+let s:ternary = '^\s\+[?|:]'
+let s:ternary_q = '^\s\+?'
+
+" 2. Auxiliary Functions {{{1
+" ======================
+
+" Check if the character at lnum:col is inside a string, comment, or is ascii.
+function s:IsInStringOrComment(lnum, col)
+ return synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_strcom
+endfunction
+
+" 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') =~ s:syng_string
+endfunction
+
+" Check if the character at lnum:col is inside a multi-line comment.
+function s:IsInMultilineComment(lnum, col)
+ return !s:IsLineComment(a:lnum, a:col) && synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_multiline
+endfunction
+
+" Check if the character at lnum:col is a line comment.
+function s:IsLineComment(lnum, col)
+ return synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_linecom
+endfunction
+
+" Find line above 'lnum' that isn't empty, in a comment, or in a string.
+function s:PrevNonBlankNonString(lnum)
+ let in_block = 0
+ let lnum = prevnonblank(a:lnum)
+ while lnum > 0
+ " Go in and out of blocks comments as necessary.
+ " If the line isn't empty (with opt. comment) or in a string, end search.
+ let line = getline(lnum)
+ if line =~ '/\*'
+ if in_block
+ let in_block = 0
+ else
+ break
+ endif
+ elseif !in_block && line =~ '\*/'
+ let in_block = 1
+ elseif !in_block && line !~ '^\s*\%(//\).*$' && !(s:IsInStringOrComment(lnum, 1) && s:IsInStringOrComment(lnum, strlen(line)))
+ break
+ endif
+ let lnum = prevnonblank(lnum - 1)
+ endwhile
+ return lnum
+endfunction
+
+" Find line above 'lnum' that started the continuation 'lnum' may be part of.
+function s:GetMSL(lnum, in_one_line_scope)
+ " Start on the line we're at and use its indent.
+ let msl = a:lnum
+ let lnum = s:PrevNonBlankNonString(a:lnum - 1)
+ while lnum > 0
+ " If we have a continuation line, or we're in a string, use line as MSL.
+ " Otherwise, terminate search as we have found our MSL already.
+ let line = getline(lnum)
+ let col = match(line, s:msl_regex) + 1
+ if (col > 0 && !s:IsInStringOrComment(lnum, col)) || s:IsInString(lnum, strlen(line))
+ let msl = lnum
+ else
+ " Don't use lines that are part of a one line scope as msl unless the
+ " flag in_one_line_scope is set to 1
+ "
+ if a:in_one_line_scope
+ break
+ end
+ let msl_one_line = s:Match(lnum, s:one_line_scope_regex)
+ if msl_one_line == 0
+ break
+ endif
+ endif
+ let lnum = s:PrevNonBlankNonString(lnum - 1)
+ endwhile
+ return msl
+endfunction
+
+function s:RemoveTrailingComments(content)
+ let single = '\/\/\(.*\)\s*$'
+ let multi = '\/\*\(.*\)\*\/\s*$'
+ return substitute(substitute(a:content, single, '', ''), multi, '', '')
+endfunction
+
+" Find if the string is inside var statement (but not the first string)
+function s:InMultiVarStatement(lnum)
+ let lnum = s:PrevNonBlankNonString(a:lnum - 1)
+
+" let type = synIDattr(synID(lnum, indent(lnum) + 1, 0), 'name')
+
+ " loop through previous expressions to find a var statement
+ while lnum > 0
+ let line = getline(lnum)
+
+ " if the line is a js keyword
+ if (line =~ s:js_keywords)
+ " check if the line is a var stmt
+ " if the line has a comma first or comma last then we can assume that we
+ " are in a multiple var statement
+ if (line =~ s:var_stmt)
+ return lnum
+ endif
+
+ " other js keywords, not a var
+ return 0
+ endif
+
+ let lnum = s:PrevNonBlankNonString(lnum - 1)
+ endwhile
+
+ " beginning of program, not a var
+ return 0
+endfunction
+
+" Find line above with beginning of the var statement or returns 0 if it's not
+" this statement
+function s:GetVarIndent(lnum)
+ let lvar = s:InMultiVarStatement(a:lnum)
+ let prev_lnum = s:PrevNonBlankNonString(a:lnum - 1)
+
+ if lvar
+ let line = s:RemoveTrailingComments(getline(prev_lnum))
+
+ " if the previous line doesn't end in a comma, return to regular indent
+ if (line !~ s:comma_last)
+ return indent(prev_lnum) - shiftwidth()
+ else
+ return indent(lvar) + shiftwidth()
+ endif
+ endif
+
+ return -1
+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
+ if !s:IsInStringOrComment(a:lnum, 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
+ 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:IsInStringOrComment(a:lnum, col) ? col : 0
+endfunction
+
+function s:IndentWithContinuation(lnum, ind, width)
+ " Set up variables to use and search for MSL to the previous line.
+ let p_lnum = a:lnum
+ let lnum = s:GetMSL(a:lnum, 1)
+ let line = getline(lnum)
+
+ " If the previous line wasn't a MSL and is continuation return its indent.
+ " TODO: the || s:IsInString() thing worries me a bit.
+ if p_lnum != lnum
+ if s:Match(p_lnum,s:continuation_regex)||s:IsInString(p_lnum,strlen(line))
+ return a:ind
+ endif
+ endif
+
+ " Set up more variables now that we know we aren't continuation bound.
+ let msl_ind = indent(lnum)
+
+ " If the previous line ended with [*+/.-=], start a continuation that
+ " indents an extra level.
+ if s:Match(lnum, s:continuation_regex)
+ if lnum == p_lnum
+ return msl_ind + a:width
+ else
+ return msl_ind
+ endif
+ endif
+
+ return a:ind
+endfunction
+
+function s:InOneLineScope(lnum)
+ let msl = s:GetMSL(a:lnum, 1)
+ if msl > 0 && s:Match(msl, s:one_line_scope_regex)
+ return msl
+ endif
+ return 0
+endfunction
+
+function s:ExitingOneLineScope(lnum)
+ let msl = s:GetMSL(a:lnum, 1)
+ if msl > 0
+ " if the current line is in a one line scope ..
+ if s:Match(msl, s:one_line_scope_regex)
+ return 0
+ else
+ let prev_msl = s:GetMSL(msl - 1, 1)
+ if s:Match(prev_msl, s:one_line_scope_regex)
+ return prev_msl
+ endif
+ endif
+ endif
+ return 0
+endfunction
+
+" 3. GetTypescriptIndent Function {{{1
+" =========================
+
+function GetTypescriptIndent()
+ " 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
+ " -----------------------------
+
+ let ind = -1
+ " Get the current line.
+ let line = getline(v:lnum)
+ " previous nonblank line number
+ let prevline = prevnonblank(v:lnum - 1)
+
+ " If we got a closing bracket on an empty line, find its match and indent
+ " according to it. For parentheses we indent to its column - 1, for the
+ " others we indent to the containing line's MSL's level. Return -1 if fail.
+ let col = matchend(line, '^\s*[],})]')
+ if col > 0 && !s:IsInStringOrComment(v:lnum, col)
+ call cursor(v:lnum, col)
+
+ let lvar = s:InMultiVarStatement(v:lnum)
+ if lvar
+ let prevline_contents = s:RemoveTrailingComments(getline(prevline))
+
+ " check for comma first
+ if (line[col - 1] =~ ',')
+ " if the previous line ends in comma or semicolon don't indent
+ if (prevline_contents =~ '[;,]\s*$')
+ return indent(s:GetMSL(line('.'), 0))
+ " get previous line indent, if it's comma first return prevline indent
+ elseif (prevline_contents =~ s:comma_first)
+ return indent(prevline)
+ " otherwise we indent 1 level
+ else
+ return indent(lvar) + shiftwidth()
+ endif
+ endif
+ endif
+
+
+ let bs = strpart('(){}[]', stridx(')}]', line[col - 1]) * 2, 2)
+ if searchpair(escape(bs[0], '\['), '', bs[1], 'bW', s:skip_expr) > 0
+ if line[col-1]==')' && col('.') != col('$') - 1
+ let ind = virtcol('.')-1
+ else
+ let ind = indent(s:GetMSL(line('.'), 0))
+ endif
+ endif
+ return ind
+ endif
+
+ " If the line is comma first, dedent 1 level
+ if (getline(prevline) =~ s:comma_first)
+ return indent(prevline) - shiftwidth()
+ endif
+
+ if (line =~ s:ternary)
+ if (getline(prevline) =~ s:ternary_q)
+ return indent(prevline)
+ else
+ return indent(prevline) + shiftwidth()
+ endif
+ endif
+
+ " If we are in a multi-line comment, cindent does the right thing.
+ if s:IsInMultilineComment(v:lnum, 1) && !s:IsLineComment(v:lnum, 1)
+ return cindent(v:lnum)
+ endif
+
+ " Check for multiple var assignments
+" let var_indent = s:GetVarIndent(v:lnum)
+" if var_indent >= 0
+" return var_indent
+" endif
+
+ " 3.3. Work on the previous line. {{{2
+ " -------------------------------
+
+ " If the line is empty and the previous nonblank line was a multi-line
+ " comment, use that comment's indent. Deduct one char to account for the
+ " space in ' */'.
+ if line =~ '^\s*$' && s:IsInMultilineComment(prevline, 1)
+ return indent(prevline) - 1
+ endif
+
+ " Find a non-blank, non-multi-line string line above the current line.
+ let lnum = s:PrevNonBlankNonString(v:lnum - 1)
+
+ " If the line is empty and inside a string, use the previous line.
+ if line =~ '^\s*$' && lnum != prevline
+ return indent(prevnonblank(v:lnum))
+ endif
+
+ " At the start of the file use zero indent.
+ 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(s:GetMSL(lnum, 0)) + 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' && searchpair('(', '', ')', 'bW', s:skip_expr) > 0
+ if col('.') + 1 == col('$')
+ return ind + shiftwidth()
+ else
+ return virtcol('.')
+ endif
+ elseif counts[1] == '1' || counts[2] == '1'
+ return ind + shiftwidth()
+ else
+ call cursor(v:lnum, vcol)
+ end
+ endif
+
+ " 3.4. Work on the MSL line. {{{2
+ " --------------------------
+
+ let ind_con = ind
+ let ind = s:IndentWithContinuation(lnum, ind_con, shiftwidth())
+
+ " }}}2
+ "
+ "
+ let ols = s:InOneLineScope(lnum)
+ if ols > 0
+ let ind = ind + shiftwidth()
+ else
+ let ols = s:ExitingOneLineScope(lnum)
+ while ols > 0 && ind > 0
+ let ind = ind - shiftwidth()
+ let ols = s:InOneLineScope(ols - 1)
+ endwhile
+ endif
+
+ return ind
+endfunction
+
+" }}}1
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
+
+function! Fixedgq(lnum, count)
+ let l:tw = &tw ? &tw : 80;
+
+ let l:count = a:count
+ let l:first_char = indent(a:lnum) + 1
+
+ if mode() == 'i' " gq was not pressed, but tw was set
+ return 1
+ endif
+
+ " This gq is only meant to do code with strings, not comments
+ if s:IsLineComment(a:lnum, l:first_char) || s:IsInMultilineComment(a:lnum, l:first_char)
+ return 1
+ endif
+
+ if len(getline(a:lnum)) < l:tw && l:count == 1 " No need for gq
+ return 1
+ endif
+
+ " Put all the lines on one line and do normal spliting after that
+ if l:count > 1
+ while l:count > 1
+ let l:count -= 1
+ normal J
+ endwhile
+ endif
+
+ let l:winview = winsaveview()
+
+ call cursor(a:lnum, l:tw + 1)
+ let orig_breakpoint = searchpairpos(' ', '', '\.', 'bcW', '', a:lnum)
+ call cursor(a:lnum, l:tw + 1)
+ let breakpoint = searchpairpos(' ', '', '\.', 'bcW', s:skip_expr, a:lnum)
+
+ " No need for special treatment, normal gq handles edgecases better
+ if breakpoint[1] == orig_breakpoint[1]
+ call winrestview(l:winview)
+ return 1
+ endif
+
+ " Try breaking after string
+ if breakpoint[1] <= indent(a:lnum)
+ call cursor(a:lnum, l:tw + 1)
+ let breakpoint = searchpairpos('\.', '', ' ', 'cW', s:skip_expr, a:lnum)
+ endif
+
+
+ if breakpoint[1] != 0
+ call feedkeys("r\<CR>")
+ else
+ let l:count = l:count - 1
+ endif
+
+ " run gq on new lines
+ if l:count == 1
+ call feedkeys("gqq")
+ endif
+
+ return 0
+endfunction
diff --git a/runtime/indent/xml.vim b/runtime/indent/xml.vim
index dcafb467a6..883af98563 100644
--- a/runtime/indent/xml.vim
+++ b/runtime/indent/xml.vim
@@ -1,13 +1,26 @@
-" Language: xml
-" Repository: https://github.com/chrisbra/vim-xml-ftplugin
-" Maintainer: Christian Brabandt <cb@256bit.org>
-" Previous Maintainer: Johannes Zellner <johannes@zellner.org>
-" Last Change: 20180724 - Correctly indent xml comments https://github.com/vim/vim/issues/3200
-" Notes: 1) does not indent pure non-xml code (e.g. embedded scripts)
-" 2) will be confused by unbalanced tags in comments
-" or CDATA sections.
-" 2009-05-26 patch by Nikolai Weibull
-" TODO: implement pre-like tags, see xml_indent_open / xml_indent_close
+" Language: xml
+" Repository: https://github.com/chrisbra/vim-xml-ftplugin
+" Last Changed: July 27, 2019
+" Maintainer: Christian Brabandt <cb@256bit.org>
+" Previous Maintainer: Johannes Zellner <johannes@zellner.org>
+" Last Change:
+" 20190726 - Correctly handle non-tagged data
+" 20190204 - correctly handle wrap tags
+" https://github.com/chrisbra/vim-xml-ftplugin/issues/5
+" 20190128 - Make sure to find previous tag
+" https://github.com/chrisbra/vim-xml-ftplugin/issues/4
+" 20181116 - Fix indentation when tags start with a colon or an underscore
+" https://github.com/vim/vim/pull/926
+" 20181022 - Do not overwrite indentkeys setting
+" https://github.com/chrisbra/vim-xml-ftplugin/issues/1
+" 20180724 - Correctly indent xml comments https://github.com/vim/vim/issues/3200
+"
+" Notes:
+" 1) does not indent pure non-xml code (e.g. embedded scripts)
+" 2) will be confused by unbalanced tags in comments
+" or CDATA sections.
+" 2009-05-26 patch by Nikolai Weibull
+" TODO: implement pre-like tags, see xml_indent_open / xml_indent_close
" Only load this indent file when no other was loaded.
if exists("b:did_indent")
@@ -18,11 +31,14 @@ let s:keepcpo= &cpo
set cpo&vim
" [-- local settings (must come before aborting the script) --]
+" Attention: Parameter use_syntax_check is used by the docbk.vim indent script
setlocal indentexpr=XmlIndentGet(v:lnum,1)
-setlocal indentkeys=o,O,*<Return>,<>>,<<>,/,{,}
+setlocal indentkeys=o,O,*<Return>,<>>,<<>,/,{,},!^F
+" autoindent: used when the indentexpr returns -1
+setlocal autoindent
if !exists('b:xml_indent_open')
- let b:xml_indent_open = '.\{-}<\a'
+ let b:xml_indent_open = '.\{-}<[:A-Z_a-z]'
" pre tag, e.g. <address>
" let b:xml_indent_open = '.\{-}<[/]\@!\(address\)\@!'
endif
@@ -38,7 +54,7 @@ unlet s:keepcpo
" [-- finish, if the function already exists --]
if exists('*XmlIndentGet')
- finish
+ finish
endif
let s:keepcpo= &cpo
@@ -51,56 +67,119 @@ endfun
" [-- check if it's xml --]
fun! <SID>XmlIndentSynCheck(lnum)
- if '' != &syntax
- let syn1 = synIDattr(synID(a:lnum, 1, 1), 'name')
- let syn2 = synIDattr(synID(a:lnum, strlen(getline(a:lnum)) - 1, 1), 'name')
- if '' != syn1 && syn1 !~ 'xml' && '' != syn2 && syn2 !~ 'xml'
- " don't indent pure non-xml code
- return 0
- endif
+ if &syntax != ''
+ let syn1 = synIDattr(synID(a:lnum, 1, 1), 'name')
+ let syn2 = synIDattr(synID(a:lnum, strlen(getline(a:lnum)) - 1, 1), 'name')
+ if syn1 != '' && syn1 !~ 'xml' && syn2 != '' && syn2 !~ 'xml'
+ " don't indent pure non-xml code
+ return 0
+ endif
endif
return 1
endfun
" [-- return the sum of indents of a:lnum --]
-fun! <SID>XmlIndentSum(lnum, style, add)
- let line = getline(a:lnum)
- if a:style == match(line, '^\s*</')
- return (shiftwidth() *
- \ (<SID>XmlIndentWithPattern(line, b:xml_indent_open)
- \ - <SID>XmlIndentWithPattern(line, b:xml_indent_close)
- \ - <SID>XmlIndentWithPattern(line, '.\{-}/>'))) + a:add
+fun! <SID>XmlIndentSum(line, style, add)
+ if <SID>IsXMLContinuation(a:line) && a:style == 0
+ " no complete tag, add one additional indent level
+ " but only for the current line
+ return a:add + shiftwidth()
+ elseif <SID>HasNoTagEnd(a:line)
+ " no complete tag, return initial indent
+ return a:add
+ endif
+ if a:style == match(a:line, '^\s*</')
+ return (shiftwidth() *
+ \ (<SID>XmlIndentWithPattern(a:line, b:xml_indent_open)
+ \ - <SID>XmlIndentWithPattern(a:line, b:xml_indent_close)
+ \ - <SID>XmlIndentWithPattern(a:line, '.\{-}/>'))) + a:add
else
- return a:add
+ return a:add
endif
endfun
+" Main indent function
fun! XmlIndentGet(lnum, use_syntax_check)
" Find a non-empty line above the current line.
- let lnum = prevnonblank(a:lnum - 1)
-
- " Hit the start of the file, use zero indent.
- if lnum == 0
- return 0
+ if prevnonblank(a:lnum - 1) == 0
+ " Hit the start of the file, use zero indent.
+ return 0
endif
+ " Find previous line with a tag (regardless whether open or closed,
+ " but always restrict the match to a line before the current one
+ " Note: xml declaration: <?xml version="1.0"?>
+ " won't be found, as it is not a legal tag name
+ let ptag_pattern = '\%(.\{-}<[/:A-Z_a-z]\)'. '\%(\&\%<'. a:lnum .'l\)'
+ let ptag = search(ptag_pattern, 'bnW')
+ " no previous tag
+ if ptag == 0
+ return 0
+ endif
+
+ let pline = getline(ptag)
+ let pind = indent(ptag)
+ let syn_name_start = '' " Syntax element at start of line (excluding whitespace)
+ let syn_name_end = '' " Syntax element at end of line
+ let curline = getline(a:lnum)
if a:use_syntax_check
- let check_lnum = <SID>XmlIndentSynCheck(lnum)
- let check_alnum = <SID>XmlIndentSynCheck(a:lnum)
- if 0 == check_lnum || 0 == check_alnum
- return indent(a:lnum)
- elseif -1 == check_lnum || -1 == check_alnum
- return -1
- endif
+ let check_lnum = <SID>XmlIndentSynCheck(ptag)
+ let check_alnum = <SID>XmlIndentSynCheck(a:lnum)
+ if check_lnum == 0 || check_alnum == 0
+ return indent(a:lnum)
+ endif
+ let syn_name_end = synIDattr(synID(a:lnum, strlen(curline) - 1, 1), 'name')
+ let syn_name_start = synIDattr(synID(a:lnum, match(curline, '\S') + 1, 1), 'name')
endif
- let ind = <SID>XmlIndentSum(lnum, -1, indent(lnum))
- let ind = <SID>XmlIndentSum(a:lnum, 0, ind)
+ if syn_name_end =~ 'Comment' && syn_name_start =~ 'Comment'
+ return <SID>XmlIndentComment(a:lnum)
+ elseif empty(syn_name_start) && empty(syn_name_end)
+ " non-xml tag content: use indent from 'autoindent'
+ return pind + shiftwidth()
+ endif
+ " Get indent from previous tag line
+ let ind = <SID>XmlIndentSum(pline, -1, pind)
+ " Determine indent from current line
+ let ind = <SID>XmlIndentSum(curline, 0, ind)
return ind
endfun
+func! <SID>IsXMLContinuation(line)
+ " Checks, whether or not the line matches a start-of-tag
+ return a:line !~ '^\s*<'
+endfunc
+
+func! <SID>HasNoTagEnd(line)
+ " Checks whether or not the line matches '>' (so finishes a tag)
+ return a:line !~ '>\s*$'
+endfunc
+
+" return indent for a commented line,
+" the middle part might be indented one additional level
+func! <SID>XmlIndentComment(lnum)
+ let ptagopen = search(b:xml_indent_open, 'bnW')
+ let ptagclose = search(b:xml_indent_close, 'bnW')
+ if getline(a:lnum) =~ '<!--'
+ " if previous tag was a closing tag, do not add
+ " one additional level of indent
+ if ptagclose > ptagopen && a:lnum > ptagclose
+ return indent(ptagclose)
+ else
+ " start of comment, add one indentation level
+ return indent(ptagopen) + shiftwidth()
+ endif
+ elseif getline(a:lnum) =~ '-->'
+ " end of comment, same as start of comment
+ return indent(search('<!--', 'bnW'))
+ else
+ " middle part of comment, add one additional level
+ return indent(search('<!--', 'bnW')) + shiftwidth()
+ endif
+endfunc
+
let &cpo = s:keepcpo
unlet s:keepcpo
-" vim:ts=8
+" vim:ts=4 et sts=-1 sw=0
diff --git a/runtime/lua/man.lua b/runtime/lua/man.lua
index 1da8ed85fc..ba6b9d09c9 100644
--- a/runtime/lua/man.lua
+++ b/runtime/lua/man.lua
@@ -107,7 +107,9 @@ local function highlight_line(line, linenr)
-- followed by '[', then a series of parameter and intermediate bytes in
-- the range 0x20 - 0x3f, then 'm'. (See ECMA-48, sections 5.4 & 8.3.117)
local sgr = prev_char:match("^%[([\032-\063]*)m$")
- if sgr then
+ -- Ignore escape sequences with : characters, as specified by ITU's T.416
+ -- Open Document Architecture and interchange format.
+ if sgr and not string.find(sgr, ":") then
local match
while sgr and #sgr > 0 do
-- Match against SGR parameters, which may be separated by ';'
diff --git a/runtime/makemenu.vim b/runtime/makemenu.vim
index 839dbdac07..7fb126977a 100644
--- a/runtime/makemenu.vim
+++ b/runtime/makemenu.vim
@@ -1,6 +1,6 @@
" Script to define the syntax menu in synmenu.vim
" Maintainer: Bram Moolenaar <Bram@vim.org>
-" Last Change: 2013 Jul 28
+" Last Change: 2018 May 17
" This is used by "make menu" in the src directory.
edit <sfile>:p:h/synmenu.vim
@@ -69,11 +69,13 @@ SynMenu AB.Applix\ ELF:elf
SynMenu AB.APT\ config:aptconf
SynMenu AB.Arc\ Macro\ Language:aml
SynMenu AB.Arch\ inventory:arch
+SynMenu AB.Arduino:arduino
SynMenu AB.ART:art
SynMenu AB.Ascii\ Doc:asciidoc
SynMenu AB.ASP\ with\ VBScript:aspvbs
SynMenu AB.ASP\ with\ Perl:aspperl
SynMenu AB.Assembly.680x0:asm68k
+SynMenu AB.Assembly.AVR:avra
SynMenu AB.Assembly.Flat:fasm
SynMenu AB.Assembly.GNU:asm
SynMenu AB.Assembly.GNU\ H-8300:asmh8300
@@ -89,6 +91,7 @@ SynMenu AB.ASN\.1:asn
SynMenu AB.Asterisk\ config:asterisk
SynMenu AB.Asterisk\ voicemail\ config:asteriskvm
SynMenu AB.Atlas:atlas
+SynMenu AB.Autodoc:autodoc
SynMenu AB.AutoHotKey:autohotkey
SynMenu AB.AutoIt:autoit
SynMenu AB.Automake:automake
@@ -103,6 +106,7 @@ SynMenu AB.Basic.IBasic:ibasic
SynMenu AB.Basic.QBasic:basic
SynMenu AB.Basic.Visual\ Basic:vb
SynMenu AB.Bazaar\ commit\ file:bzr
+SynMenu AB.Bazel:bzl
SynMenu AB.BC\ calculator:bc
SynMenu AB.BDF\ font:bdf
SynMenu AB.BibTeX.Bibliography\ database:bib
@@ -132,6 +136,7 @@ SynMenu C.Clever:cl
SynMenu C.Clipper:clipper
SynMenu C.Clojure:clojure
SynMenu C.Cmake:cmake
+SynMenu C.Cmod:cmod
SynMenu C.Cmusrc:cmusrc
SynMenu C.Cobol:cobol
SynMenu C.Coco/R:coco
@@ -158,6 +163,7 @@ SynMenu DE.D:d
SynMenu DE.Datascript:datascript
SynMenu DE.Debian.Debian\ ChangeLog:debchangelog
SynMenu DE.Debian.Debian\ Control:debcontrol
+SynMenu DE.Debian.Debian\ Copyright:debcopyright
SynMenu DE.Debian.Debian\ Sources\.list:debsources
SynMenu DE.Denyhosts:denyhosts
SynMenu DE.Desktop:desktop
@@ -166,12 +172,14 @@ SynMenu DE.Dictd\ config:dictdconf
SynMenu DE.Diff:diff
SynMenu DE.Digital\ Command\ Lang:dcl
SynMenu DE.Dircolors:dircolors
+SynMenu DE.Dirpager:dirpager
SynMenu DE.Django\ template:django
SynMenu DE.DNS/BIND\ zone:bindzone
SynMenu DE.Dnsmasq\ config:dnsmasq
SynMenu DE.DocBook.auto-detect:docbk
SynMenu DE.DocBook.SGML:docbksgml
SynMenu DE.DocBook.XML:docbkxml
+SynMenu DE.Dockerfile:dockerfile
SynMenu DE.Dot:dot
SynMenu DE.Doxygen.C\ with\ doxygen:c.doxygen
SynMenu DE.Doxygen.C++\ with\ doxygen:cpp.doxygen
@@ -199,6 +207,8 @@ SynMenu DE.ESQL-C:esqlc
SynMenu DE.Essbase\ script:csc
SynMenu DE.Esterel:esterel
SynMenu DE.Eterm\ config:eterm
+SynMenu DE.Euphoria\ 3:euphoria3
+SynMenu DE.Euphoria\ 4:euphoria4
SynMenu DE.Eviews:eviews
SynMenu DE.Exim\ conf:exim
SynMenu DE.Expect:expect
@@ -231,6 +241,8 @@ SynMenu FG.Git.Send\ Email:gitsendemail
SynMenu FG.Gitolite:gitolite
SynMenu FG.Gkrellmrc:gkrellmrc
SynMenu FG.Gnash:gnash
+SynMenu FG.Go:go
+SynMenu FG.Godoc:godoc
SynMenu FG.GP:gp
SynMenu FG.GPG:gpg
SynMenu FG.Grof:gprof
@@ -260,6 +272,7 @@ SynMenu HIJK.HTML.HTML\ with\ M4:htmlm4
SynMenu HIJK.HTML.HTML\ with\ Ruby\ (eRuby):eruby
SynMenu HIJK.HTML.Cheetah\ HTML\ template:htmlcheetah
SynMenu HIJK.HTML.Django\ HTML\ template:htmldjango
+SynMenu HIJK.HTML.Vue.js\ HTML\ template:vuejs
SynMenu HIJK.HTML.HTML/OS:htmlos
SynMenu HIJK.HTML.XHTML:xhtml
SynMenu HIJK.Host\.conf:hostconf
@@ -277,12 +290,14 @@ SynMenu HIJK.Inittab:inittab
SynMenu HIJK.Inno\ setup:iss
SynMenu HIJK.Innovation\ Data\ Processing.Upstream\ dat:upstreamdat
SynMenu HIJK.Innovation\ Data\ Processing.Upstream\ log:upstreamlog
+SynMenu HIJK.Innovation\ Data\ Processing.Upstream\ rpt:upstreamrpt
SynMenu HIJK.Innovation\ Data\ Processing.Upstream\ Install\ log:upstreaminstalllog
SynMenu HIJK.Innovation\ Data\ Processing.Usserver\ log:usserverlog
SynMenu HIJK.Innovation\ Data\ Processing.USW2KAgt\ log:usw2kagtlog
SynMenu HIJK.InstallShield\ script:ishd
SynMenu HIJK.Interactive\ Data\ Lang:idlang
SynMenu HIJK.IPfilter:ipfilter
+SynMenu HIJK.J:j
SynMenu HIJK.JAL:jal
SynMenu HIJK.JAM:jam
SynMenu HIJK.Jargon:jargon
@@ -294,9 +309,11 @@ SynMenu HIJK.JavaScript:javascript
SynMenu HIJK.Jess:jess
SynMenu HIJK.Jgraph:jgraph
SynMenu HIJK.Jovial:jovial
+SynMenu HIJK.JSON:json
SynMenu HIJK.Kconfig:kconfig
SynMenu HIJK.KDE\ script:kscript
SynMenu HIJK.Kimwitu++:kwt
+SynMenu HIJK.Kivy:kivy
SynMenu HIJK.KixTart:kix
SynMenu L.Lace:lace
@@ -305,6 +322,7 @@ SynMenu L.Latte:latte
SynMenu L.Ld\ script:ld
SynMenu L.LDAP.LDIF:ldif
SynMenu L.LDAP.Configuration:ldapconf
+SynMenu L.Less:less
SynMenu L.Lex:lex
SynMenu L.LFTP\ config:lftp
SynMenu L.Libao:libao
@@ -340,6 +358,7 @@ SynMenu M.Man\ page:man
SynMenu M.Man\.conf:manconf
SynMenu M.Maple\ V:maple
SynMenu M.Markdown:markdown
+SynMenu M.Markdown\ with\ R\ statements:rmd
SynMenu M.Mason:mason
SynMenu M.Mathematica:mma
SynMenu M.Matlab:matlab
@@ -349,6 +368,7 @@ SynMenu M.Messages\ (/var/log):messages
SynMenu M.Metafont:mf
SynMenu M.MetaPost:mp
SynMenu M.MGL:mgl
+SynMenu M.MIX:mix
SynMenu M.MMIX:mmix
SynMenu M.Modconf:modconf
SynMenu M.Model:model
@@ -356,6 +376,7 @@ SynMenu M.Modsim\ III:modsim3
SynMenu M.Modula\ 2:modula2
SynMenu M.Modula\ 3:modula3
SynMenu M.Monk:monk
+SynMenu M.Motorola\ S-Record:srec
SynMenu M.Mplayer\ config:mplayerconf
SynMenu M.MOO:moo
SynMenu M.Mrxvtrc:mrxvtrc
@@ -368,12 +389,15 @@ SynMenu M.MS-DOS/Windows.Registry:registry
SynMenu M.MS-DOS/Windows.Resource\ file:rc
SynMenu M.Msql:msql
SynMenu M.MuPAD:mupad
+SynMenu M.Murphi:murphi
SynMenu M.MUSHcode:mush
SynMenu M.Muttrc:muttrc
+SynMenu NO.N1QL:n1ql
SynMenu NO.Nanorc:nanorc
SynMenu NO.Nastran\ input/DMAP:nastran
SynMenu NO.Natural:natural
+SynMenu NO.NeoMutt\ setup\ files:neomuttrc
SynMenu NO.Netrc:netrc
SynMenu NO.Ninja:ninja
SynMenu NO.Novell\ NCF\ batch:ncf
@@ -461,14 +485,18 @@ SynMenu R.RockLinux\ package\ desc\.:desc
SynMenu R.Rpcgen:rpcgen
SynMenu R.RPL/2:rpl
SynMenu R.ReStructuredText:rst
+SynMenu M.ReStructuredText\ with\ R\ statements:rrst
SynMenu R.RTF:rtf
SynMenu R.Ruby:ruby
+SynMenu R.Rust:rust
SynMenu S-Sm.S-Lang:slang
SynMenu S-Sm.Samba\ config:samba
SynMenu S-Sm.SAS:sas
SynMenu S-Sm.Sass:sass
SynMenu S-Sm.Sather:sather
+SynMenu S-Sm.Sbt:sbt
+SynMenu S-Sm.Scala:scala
SynMenu S-Sm.Scheme:scheme
SynMenu S-Sm.Scilab:scilab
SynMenu S-Sm.Screen\ RC:screen
@@ -546,6 +574,8 @@ SynMenu Sn-Sy.Sudoers:sudoers
SynMenu Sn-Sy.SVG:svg
SynMenu Sn-Sy.Symbian\ meta-makefile:mmp
SynMenu Sn-Sy.Sysctl\.conf:sysctl
+SynMenu Sn-Sy.Systemd:systemd
+SynMenu Sn-Sy.SystemVerilog:systemverilog
SynMenu T.TADS:tads
SynMenu T.Tags:tags
@@ -560,6 +590,7 @@ SynMenu T.TealInfo:tli
SynMenu T.Telix\ Salt:tsalt
SynMenu T.Termcap/Printcap:ptcap
SynMenu T.Terminfo:terminfo
+SynMenu T.Tera\ Term:teraterm
SynMenu T.TeX.TeX/LaTeX:tex
SynMenu T.TeX.plain\ TeX:plaintex
SynMenu T.TeX.Initex:initex
@@ -569,6 +600,7 @@ SynMenu T.TeX.Texinfo:texinfo
SynMenu T.TF\ mud\ client:tf
SynMenu T.Tidy\ configuration:tidy
SynMenu T.Tilde:tilde
+SynMenu T.Tmux\ configuration:tmux
SynMenu T.TPP:tpp
SynMenu T.Trasys\ input:trasys
SynMenu T.Treetop:treetop
@@ -586,6 +618,7 @@ SynMenu UV.Updatedb\.conf:updatedb
SynMenu UV.Upstart:upstart
SynMenu UV.Valgrind:valgrind
SynMenu UV.Vera:vera
+SynMenu UV.Verbose\ TAP\ Output:tap
SynMenu UV.Verilog-AMS\ HDL:verilogams
SynMenu UV.Verilog\ HDL:verilog
SynMenu UV.Vgrindefs:vgrindefs
@@ -597,6 +630,7 @@ SynMenu UV.Virata\ config:virata
SynMenu UV.Visual\ Basic:vb
SynMenu UV.VOS\ CM\ macro:voscm
SynMenu UV.VRML:vrml
+SynMenu UV.Vroom:vroom
SynMenu UV.VSE\ JCL:vsejcl
SynMenu WXYZ.WEB.CWEB:cweb
diff --git a/runtime/menu.vim b/runtime/menu.vim
index 5e4bd1f11b..3756787e7f 100644
--- a/runtime/menu.vim
+++ b/runtime/menu.vim
@@ -2,7 +2,7 @@
" You can also use this as a start for your own set of menus.
"
" Maintainer: Bram Moolenaar <Bram@vim.org>
-" Last Change: 2018 May 17
+" Last Change: 2019 Jan 27
" Note that ":an" (short for ":anoremenu") is often used to make a menu work
" in all modes and avoid side effects from mappings defined by the user.
@@ -853,17 +853,15 @@ an 70.300 &Window.&New<Tab>^Wn <C-W>n
an 70.310 &Window.S&plit<Tab>^Ws <C-W>s
an 70.320 &Window.Sp&lit\ To\ #<Tab>^W^^ <C-W><C-^>
an 70.330 &Window.Split\ &Vertically<Tab>^Wv <C-W>v
-if has("vertsplit")
- an <silent> 70.332 &Window.Split\ File\ E&xplorer :call MenuExplOpen()<CR>
- if !exists("*MenuExplOpen")
- fun MenuExplOpen()
- if @% == ""
- 20vsp .
- else
- exe "20vsp " . s:FnameEscape(expand("%:p:h"))
- endif
- endfun
- endif
+an <silent> 70.332 &Window.Split\ File\ E&xplorer :call MenuExplOpen()<CR>
+if !exists("*MenuExplOpen")
+ fun MenuExplOpen()
+ if @% == ""
+ 20vsp .
+ else
+ exe "20vsp " . s:FnameEscape(expand("%:p:h"))
+ endif
+ endfun
endif
an 70.335 &Window.-SEP1- <Nop>
an 70.340 &Window.&Close<Tab>^Wc :confirm close<CR>
diff --git a/runtime/mswin.vim b/runtime/mswin.vim
index 5ec21491fe..2b04c1aea3 100644
--- a/runtime/mswin.vim
+++ b/runtime/mswin.vim
@@ -1,9 +1,9 @@
" Set options and add mapping such that Vim behaves a lot like MS-Windows
"
" Maintainer: Bram Moolenaar <Bram@vim.org>
-" Last change: 2017 Oct 28
+" Last Change: 2018 Dec 07
-" bail out if this isn't wanted (mrsvim.vim uses this).
+" Bail out if this isn't wanted.
if exists("g:skip_loading_mswin") && g:skip_loading_mswin
finish
endif
diff --git a/runtime/optwin.vim b/runtime/optwin.vim
index f3d7d3729b..51b2bbb583 100644
--- a/runtime/optwin.vim
+++ b/runtime/optwin.vim
@@ -1,7 +1,7 @@
" These commands create the option window.
"
" Maintainer: Bram Moolenaar <Bram@vim.org>
-" Last Change: 2018 May 15
+" Last Change: 2019 Jul 18
" If there already is an option window, jump to that one.
let buf = bufnr('option-window')
@@ -395,11 +395,9 @@ endif
call <SID>Header("syntax, highlighting and spelling")
call append("$", "background\t\"dark\" or \"light\"; the background color brightness")
call <SID>OptionG("bg", &bg)
-if has("autocmd")
- call append("$", "filetype\ttype of file; triggers the FileType event when set")
- call append("$", "\t(local to buffer)")
- call <SID>OptionL("ft")
-endif
+call append("$", "filetype\ttype of file; triggers the FileType event when set")
+call append("$", "\t(local to buffer)")
+call <SID>OptionL("ft")
if has("syntax")
call append("$", "syntax\tname of syntax highlighting used")
call append("$", "\t(local to buffer)")
@@ -454,10 +452,8 @@ if has("statusline")
endif
call append("$", "equalalways\tmake all windows the same size when adding/removing windows")
call <SID>BinOptionG("ea", &ea)
-if has("vertsplit")
- call append("$", "eadirection\tin which direction 'equalalways' works: \"ver\", \"hor\" or \"both\"")
- call <SID>OptionG("ead", &ead)
-endif
+call append("$", "eadirection\tin which direction 'equalalways' works: \"ver\", \"hor\" or \"both\"")
+call <SID>OptionG("ead", &ead)
call append("$", "winheight\tminimal number of lines used for the current window")
call append("$", " \tset wh=" . &wh)
call append("$", "winminheight\tminimal number of lines used for any window")
@@ -465,18 +461,18 @@ call append("$", " \tset wmh=" . &wmh)
call append("$", "winfixheight\tkeep the height of the window")
call append("$", "\t(local to window)")
call <SID>BinOptionL("wfh")
-if has("vertsplit")
call append("$", "winfixwidth\tkeep the width of the window")
call append("$", "\t(local to window)")
call <SID>BinOptionL("wfw")
- call append("$", "winwidth\tminimal number of columns used for the current window")
- call append("$", " \tset wiw=" . &wiw)
- call append("$", "winminwidth\tminimal number of columns used for any window")
- call append("$", " \tset wmw=" . &wmw)
-endif
+call append("$", "winwidth\tminimal number of columns used for the current window")
+call append("$", " \tset wiw=" . &wiw)
+call append("$", "winminwidth\tminimal number of columns used for any window")
+call append("$", " \tset wmw=" . &wmw)
call append("$", "helpheight\tinitial height of the help window")
call append("$", " \tset hh=" . &hh)
if has("quickfix")
+ " call append("$", "previewpopup\tuse a popup window for preview")
+ " call append("$", " \tset pvp=" . &pvp)
call append("$", "previewheight\tdefault height for the preview window")
call append("$", " \tset pvh=" . &pvh)
call append("$", "previewwindow\tidentifies the preview window")
@@ -490,22 +486,16 @@ call append("$", "\tto a buffer")
call <SID>OptionG("swb", &swb)
call append("$", "splitbelow\ta new window is put below the current one")
call <SID>BinOptionG("sb", &sb)
-if has("vertsplit")
- call append("$", "splitright\ta new window is put right of the current one")
- call <SID>BinOptionG("spr", &spr)
-endif
-if has("scrollbind")
- call append("$", "scrollbind\tthis window scrolls together with other bound windows")
- call append("$", "\t(local to window)")
- call <SID>BinOptionL("scb")
- call append("$", "scrollopt\t\"ver\", \"hor\" and/or \"jump\"; list of options for 'scrollbind'")
- call <SID>OptionG("sbo", &sbo)
-endif
-if has("cursorbind")
- call append("$", "cursorbind\tthis window's cursor moves together with other bound windows")
- call append("$", "\t(local to window)")
- call <SID>BinOptionL("crb")
-endif
+call append("$", "splitright\ta new window is put right of the current one")
+call <SID>BinOptionG("spr", &spr)
+call append("$", "scrollbind\tthis window scrolls together with other bound windows")
+call append("$", "\t(local to window)")
+call <SID>BinOptionL("scb")
+call append("$", "scrollopt\t\"ver\", \"hor\" and/or \"jump\"; list of options for 'scrollbind'")
+call <SID>OptionG("sbo", &sbo)
+call append("$", "cursorbind\tthis window's cursor moves together with other bound windows")
+call append("$", "\t(local to window)")
+call <SID>BinOptionL("crb")
if has("terminal")
call append("$", "termsize\tsize of a terminal window")
call append("$", "\t(local to window)")
@@ -944,6 +934,8 @@ call <SID>Header("reading and writing files")
call append("$", "modeline\tenable using settings from modelines when reading a file")
call append("$", "\t(local to buffer)")
call <SID>BinOptionL("ml")
+call append("$", "modelineexpr\tallow setting expression options from a modeline")
+call <SID>BinOptionG("mle", &mle)
call append("$", "modelines\tnumber of lines to check for modelines")
call append("$", " \tset mls=" . &mls)
call append("$", "binary\tbinary file editing")
@@ -1040,12 +1032,10 @@ if has("wildmenu")
call append("$", "wildmenu\tcommand-line completion shows a list of matches")
call <SID>BinOptionG("wmnu", &wmnu)
endif
-if has("vertsplit")
- call append("$", "cedit\tkey used to open the command-line window")
- call <SID>OptionG("cedit", &cedit)
- call append("$", "cmdwinheight\theight of the command-line window")
- call <SID>OptionG("cwh", &cwh)
-endif
+call append("$", "cedit\tkey used to open the command-line window")
+call <SID>OptionG("cedit", &cedit)
+call append("$", "cmdwinheight\theight of the command-line window")
+call <SID>OptionG("cwh", &cwh)
call <SID>Header("executing external commands")
@@ -1208,14 +1198,10 @@ endif
call <SID>Header("various")
-if has("virtualedit")
- call append("$", "virtualedit\twhen to use virtual editing: \"block\", \"insert\" and/or \"all\"")
- call <SID>OptionG("ve", &ve)
-endif
-if has("autocmd")
- call append("$", "eventignore\tlist of autocommand events which are to be ignored")
- call <SID>OptionG("ei", &ei)
-endif
+call append("$", "virtualedit\twhen to use virtual editing: \"block\", \"insert\" and/or \"all\"")
+call <SID>OptionG("ve", &ve)
+call append("$", "eventignore\tlist of autocommand events which are to be ignored")
+call <SID>OptionG("ei", &ei)
call append("$", "loadplugins\tload plugin scripts when starting up")
call <SID>BinOptionG("lpl", &lpl)
call append("$", "exrc\tenable reading .vimrc/.exrc/.gvimrc in the current directory")
diff --git a/runtime/pack/dist/opt/matchit/autoload/matchit.vim b/runtime/pack/dist/opt/matchit/autoload/matchit.vim
new file mode 100644
index 0000000000..abf06d3c4c
--- /dev/null
+++ b/runtime/pack/dist/opt/matchit/autoload/matchit.vim
@@ -0,0 +1,754 @@
+" matchit.vim: (global plugin) Extended "%" matching
+" autload script of matchit plugin, see ../plugin/matchit.vim
+" Last Change: 2019 Jan 28
+
+let s:last_mps = ""
+let s:last_words = ":"
+let s:patBR = ""
+
+let s:save_cpo = &cpo
+set cpo&vim
+
+" Auto-complete mappings: (not yet "ready for prime time")
+" TODO Read :help write-plugin for the "right" way to let the user
+" specify a key binding.
+" let g:match_auto = '<C-]>'
+" let g:match_autoCR = '<C-CR>'
+" if exists("g:match_auto")
+" execute "inoremap " . g:match_auto . ' x<Esc>"=<SID>Autocomplete()<CR>Pls'
+" endif
+" if exists("g:match_autoCR")
+" execute "inoremap " . g:match_autoCR . ' <CR><C-R>=<SID>Autocomplete()<CR>'
+" endif
+" if exists("g:match_gthhoh")
+" execute "inoremap " . g:match_gthhoh . ' <C-O>:call <SID>Gthhoh()<CR>'
+" endif " gthhoh = "Get the heck out of here!"
+
+let s:notslash = '\\\@1<!\%(\\\\\)*'
+
+function s:RestoreOptions()
+ " In s:CleanUp(), :execute "set" restore_options .
+ let restore_options = ""
+ if get(b:, 'match_ignorecase', &ic) != &ic
+ let restore_options .= (&ic ? " " : " no") . "ignorecase"
+ let &ignorecase = b:match_ignorecase
+ endif
+ if &ve != ''
+ let restore_options = " ve=" . &ve . restore_options
+ set ve=
+ endif
+ return restore_options
+endfunction
+
+function matchit#Match_wrapper(word, forward, mode) range
+ let restore_options = s:RestoreOptions()
+ " If this function was called from Visual mode, make sure that the cursor
+ " is at the correct end of the Visual range:
+ if a:mode == "v"
+ execute "normal! gv\<Esc>"
+ elseif a:mode == "o" && mode(1) !~# '[vV]'
+ exe "norm! v"
+ endif
+ " In s:CleanUp(), we may need to check whether the cursor moved forward.
+ let startpos = [line("."), col(".")]
+ " Use default behavior if called with a count.
+ if v:count
+ exe "normal! " . v:count . "%"
+ return s:CleanUp(restore_options, a:mode, startpos)
+ end
+
+ " First step: if not already done, set the script variables
+ " s:do_BR flag for whether there are backrefs
+ " s:pat parsed version of b:match_words
+ " s:all regexp based on s:pat and the default groups
+ if !exists("b:match_words") || b:match_words == ""
+ let match_words = ""
+ elseif b:match_words =~ ":"
+ let match_words = b:match_words
+ else
+ " Allow b:match_words = "GetVimMatchWords()" .
+ execute "let match_words =" b:match_words
+ endif
+" Thanks to Preben "Peppe" Guldberg and Bram Moolenaar for this suggestion!
+ if (match_words != s:last_words) || (&mps != s:last_mps)
+ \ || exists("b:match_debug")
+ let s:last_mps = &mps
+ " quote the special chars in 'matchpairs', replace [,:] with \| and then
+ " append the builtin pairs (/*, */, #if, #ifdef, #ifndef, #else, #elif,
+ " #endif)
+ let default = escape(&mps, '[$^.*~\\/?]') . (strlen(&mps) ? "," : "") .
+ \ '\/\*:\*\/,#\s*if\%(n\=def\)\=:#\s*else\>:#\s*elif\>:#\s*endif\>'
+ " s:all = pattern with all the keywords
+ let match_words = match_words . (strlen(match_words) ? "," : "") . default
+ let s:last_words = match_words
+ if match_words !~ s:notslash . '\\\d'
+ let s:do_BR = 0
+ let s:pat = match_words
+ else
+ let s:do_BR = 1
+ let s:pat = s:ParseWords(match_words)
+ endif
+ let s:all = substitute(s:pat, s:notslash . '\zs[,:]\+', '\\|', 'g')
+ " Just in case there are too many '\(...)' groups inside the pattern, make
+ " sure to use \%(...) groups, so that error E872 can be avoided
+ let s:all = substitute(s:all, '\\(', '\\%(', 'g')
+ let s:all = '\%(' . s:all . '\)'
+ if exists("b:match_debug")
+ let b:match_pat = s:pat
+ endif
+ " Reconstruct the version with unresolved backrefs.
+ let s:patBR = substitute(match_words.',',
+ \ s:notslash.'\zs[,:]*,[,:]*', ',', 'g')
+ let s:patBR = substitute(s:patBR, s:notslash.'\zs:\{2,}', ':', 'g')
+ endif
+
+ " Second step: set the following local variables:
+ " matchline = line on which the cursor started
+ " curcol = number of characters before match
+ " prefix = regexp for start of line to start of match
+ " suffix = regexp for end of match to end of line
+ " Require match to end on or after the cursor and prefer it to
+ " start on or before the cursor.
+ let matchline = getline(startpos[0])
+ if a:word != ''
+ " word given
+ if a:word !~ s:all
+ echohl WarningMsg|echo 'Missing rule for word:"'.a:word.'"'|echohl NONE
+ return s:CleanUp(restore_options, a:mode, startpos)
+ endif
+ let matchline = a:word
+ let curcol = 0
+ let prefix = '^\%('
+ let suffix = '\)$'
+ " Now the case when "word" is not given
+ else " Find the match that ends on or after the cursor and set curcol.
+ let regexp = s:Wholematch(matchline, s:all, startpos[1]-1)
+ let curcol = match(matchline, regexp)
+ " If there is no match, give up.
+ if curcol == -1
+ return s:CleanUp(restore_options, a:mode, startpos)
+ endif
+ let endcol = matchend(matchline, regexp)
+ let suf = strlen(matchline) - endcol
+ let prefix = (curcol ? '^.*\%' . (curcol + 1) . 'c\%(' : '^\%(')
+ let suffix = (suf ? '\)\%' . (endcol + 1) . 'c.*$' : '\)$')
+ endif
+ if exists("b:match_debug")
+ let b:match_match = matchstr(matchline, regexp)
+ let b:match_col = curcol+1
+ endif
+
+ " Third step: Find the group and single word that match, and the original
+ " (backref) versions of these. Then, resolve the backrefs.
+ " Set the following local variable:
+ " group = colon-separated list of patterns, one of which matches
+ " = ini:mid:fin or ini:fin
+ "
+ " Now, set group and groupBR to the matching group: 'if:endif' or
+ " 'while:endwhile' or whatever. A bit of a kluge: s:Choose() returns
+ " group . "," . groupBR, and we pick it apart.
+ let group = s:Choose(s:pat, matchline, ",", ":", prefix, suffix, s:patBR)
+ let i = matchend(group, s:notslash . ",")
+ let groupBR = strpart(group, i)
+ let group = strpart(group, 0, i-1)
+ " Now, matchline =~ prefix . substitute(group,':','\|','g') . suffix
+ if s:do_BR " Do the hard part: resolve those backrefs!
+ let group = s:InsertRefs(groupBR, prefix, group, suffix, matchline)
+ endif
+ if exists("b:match_debug")
+ let b:match_wholeBR = groupBR
+ let i = matchend(groupBR, s:notslash . ":")
+ let b:match_iniBR = strpart(groupBR, 0, i-1)
+ endif
+
+ " Fourth step: Set the arguments for searchpair().
+ let i = matchend(group, s:notslash . ":")
+ let j = matchend(group, '.*' . s:notslash . ":")
+ let ini = strpart(group, 0, i-1)
+ let mid = substitute(strpart(group, i,j-i-1), s:notslash.'\zs:', '\\|', 'g')
+ let fin = strpart(group, j)
+ "Un-escape the remaining , and : characters.
+ let ini = substitute(ini, s:notslash . '\zs\\\(:\|,\)', '\1', 'g')
+ let mid = substitute(mid, s:notslash . '\zs\\\(:\|,\)', '\1', 'g')
+ let fin = substitute(fin, s:notslash . '\zs\\\(:\|,\)', '\1', 'g')
+ " searchpair() requires that these patterns avoid \(\) groups.
+ let ini = substitute(ini, s:notslash . '\zs\\(', '\\%(', 'g')
+ let mid = substitute(mid, s:notslash . '\zs\\(', '\\%(', 'g')
+ let fin = substitute(fin, s:notslash . '\zs\\(', '\\%(', 'g')
+ " Set mid. This is optimized for readability, not micro-efficiency!
+ if a:forward && matchline =~ prefix . fin . suffix
+ \ || !a:forward && matchline =~ prefix . ini . suffix
+ let mid = ""
+ endif
+ " Set flag. This is optimized for readability, not micro-efficiency!
+ if a:forward && matchline =~ prefix . fin . suffix
+ \ || !a:forward && matchline !~ prefix . ini . suffix
+ let flag = "bW"
+ else
+ let flag = "W"
+ endif
+ " Set skip.
+ if exists("b:match_skip")
+ let skip = b:match_skip
+ elseif exists("b:match_comment") " backwards compatibility and testing!
+ let skip = "r:" . b:match_comment
+ else
+ let skip = 's:comment\|string'
+ endif
+ let skip = s:ParseSkip(skip)
+ if exists("b:match_debug")
+ let b:match_ini = ini
+ let b:match_tail = (strlen(mid) ? mid.'\|' : '') . fin
+ endif
+
+ " Fifth step: actually start moving the cursor and call searchpair().
+ " Later, :execute restore_cursor to get to the original screen.
+ let view = winsaveview()
+ call cursor(0, curcol + 1)
+ if skip =~ 'synID' && !(has("syntax") && exists("g:syntax_on"))
+ let skip = "0"
+ else
+ execute "if " . skip . "| let skip = '0' | endif"
+ endif
+ let sp_return = searchpair(ini, mid, fin, flag, skip)
+ let final_position = "call cursor(" . line(".") . "," . col(".") . ")"
+ " Restore cursor position and original screen.
+ call winrestview(view)
+ normal! m'
+ if sp_return > 0
+ execute final_position
+ endif
+ return s:CleanUp(restore_options, a:mode, startpos, mid.'\|'.fin)
+endfun
+
+" Restore options and do some special handling for Operator-pending mode.
+" The optional argument is the tail of the matching group.
+fun! s:CleanUp(options, mode, startpos, ...)
+ if strlen(a:options)
+ execute "set" a:options
+ endif
+ " Open folds, if appropriate.
+ if a:mode != "o"
+ if &foldopen =~ "percent"
+ normal! zv
+ endif
+ " In Operator-pending mode, we want to include the whole match
+ " (for example, d%).
+ " This is only a problem if we end up moving in the forward direction.
+ elseif (a:startpos[0] < line(".")) ||
+ \ (a:startpos[0] == line(".") && a:startpos[1] < col("."))
+ if a:0
+ " Check whether the match is a single character. If not, move to the
+ " end of the match.
+ let matchline = getline(".")
+ let currcol = col(".")
+ let regexp = s:Wholematch(matchline, a:1, currcol-1)
+ let endcol = matchend(matchline, regexp)
+ if endcol > currcol " This is NOT off by one!
+ call cursor(0, endcol)
+ endif
+ endif " a:0
+ endif " a:mode != "o" && etc.
+ return 0
+endfun
+
+" Example (simplified HTML patterns): if
+" a:groupBR = '<\(\k\+\)>:</\1>'
+" a:prefix = '^.\{3}\('
+" a:group = '<\(\k\+\)>:</\(\k\+\)>'
+" a:suffix = '\).\{2}$'
+" a:matchline = "123<tag>12" or "123</tag>12"
+" then extract "tag" from a:matchline and return "<tag>:</tag>" .
+fun! s:InsertRefs(groupBR, prefix, group, suffix, matchline)
+ if a:matchline !~ a:prefix .
+ \ substitute(a:group, s:notslash . '\zs:', '\\|', 'g') . a:suffix
+ return a:group
+ endif
+ let i = matchend(a:groupBR, s:notslash . ':')
+ let ini = strpart(a:groupBR, 0, i-1)
+ let tailBR = strpart(a:groupBR, i)
+ let word = s:Choose(a:group, a:matchline, ":", "", a:prefix, a:suffix,
+ \ a:groupBR)
+ let i = matchend(word, s:notslash . ":")
+ let wordBR = strpart(word, i)
+ let word = strpart(word, 0, i-1)
+ " Now, a:matchline =~ a:prefix . word . a:suffix
+ if wordBR != ini
+ let table = s:Resolve(ini, wordBR, "table")
+ else
+ let table = ""
+ let d = 0
+ while d < 10
+ if tailBR =~ s:notslash . '\\' . d
+ let table = table . d
+ else
+ let table = table . "-"
+ endif
+ let d = d + 1
+ endwhile
+ endif
+ let d = 9
+ while d
+ if table[d] != "-"
+ let backref = substitute(a:matchline, a:prefix.word.a:suffix,
+ \ '\'.table[d], "")
+ " Are there any other characters that should be escaped?
+ let backref = escape(backref, '*,:')
+ execute s:Ref(ini, d, "start", "len")
+ let ini = strpart(ini, 0, start) . backref . strpart(ini, start+len)
+ let tailBR = substitute(tailBR, s:notslash . '\zs\\' . d,
+ \ escape(backref, '\\&'), 'g')
+ endif
+ let d = d-1
+ endwhile
+ if exists("b:match_debug")
+ if s:do_BR
+ let b:match_table = table
+ let b:match_word = word
+ else
+ let b:match_table = ""
+ let b:match_word = ""
+ endif
+ endif
+ return ini . ":" . tailBR
+endfun
+
+" Input a comma-separated list of groups with backrefs, such as
+" a:groups = '\(foo\):end\1,\(bar\):end\1'
+" and return a comma-separated list of groups with backrefs replaced:
+" return '\(foo\):end\(foo\),\(bar\):end\(bar\)'
+fun! s:ParseWords(groups)
+ let groups = substitute(a:groups.",", s:notslash.'\zs[,:]*,[,:]*', ',', 'g')
+ let groups = substitute(groups, s:notslash . '\zs:\{2,}', ':', 'g')
+ let parsed = ""
+ while groups =~ '[^,:]'
+ let i = matchend(groups, s:notslash . ':')
+ let j = matchend(groups, s:notslash . ',')
+ let ini = strpart(groups, 0, i-1)
+ let tail = strpart(groups, i, j-i-1) . ":"
+ let groups = strpart(groups, j)
+ let parsed = parsed . ini
+ let i = matchend(tail, s:notslash . ':')
+ while i != -1
+ " In 'if:else:endif', ini='if' and word='else' and then word='endif'.
+ let word = strpart(tail, 0, i-1)
+ let tail = strpart(tail, i)
+ let i = matchend(tail, s:notslash . ':')
+ let parsed = parsed . ":" . s:Resolve(ini, word, "word")
+ endwhile " Now, tail has been used up.
+ let parsed = parsed . ","
+ endwhile " groups =~ '[^,:]'
+ let parsed = substitute(parsed, ',$', '', '')
+ return parsed
+endfun
+
+" TODO I think this can be simplified and/or made more efficient.
+" TODO What should I do if a:start is out of range?
+" Return a regexp that matches all of a:string, such that
+" matchstr(a:string, regexp) represents the match for a:pat that starts
+" as close to a:start as possible, before being preferred to after, and
+" ends after a:start .
+" Usage:
+" let regexp = s:Wholematch(getline("."), 'foo\|bar', col(".")-1)
+" let i = match(getline("."), regexp)
+" let j = matchend(getline("."), regexp)
+" let match = matchstr(getline("."), regexp)
+fun! s:Wholematch(string, pat, start)
+ let group = '\%(' . a:pat . '\)'
+ let prefix = (a:start ? '\(^.*\%<' . (a:start + 2) . 'c\)\zs' : '^')
+ let len = strlen(a:string)
+ let suffix = (a:start+1 < len ? '\(\%>'.(a:start+1).'c.*$\)\@=' : '$')
+ if a:string !~ prefix . group . suffix
+ let prefix = ''
+ endif
+ return prefix . group . suffix
+endfun
+
+" No extra arguments: s:Ref(string, d) will
+" find the d'th occurrence of '\(' and return it, along with everything up
+" to and including the matching '\)'.
+" One argument: s:Ref(string, d, "start") returns the index of the start
+" of the d'th '\(' and any other argument returns the length of the group.
+" Two arguments: s:Ref(string, d, "foo", "bar") returns a string to be
+" executed, having the effect of
+" :let foo = s:Ref(string, d, "start")
+" :let bar = s:Ref(string, d, "len")
+fun! s:Ref(string, d, ...)
+ let len = strlen(a:string)
+ if a:d == 0
+ let start = 0
+ else
+ let cnt = a:d
+ let match = a:string
+ while cnt
+ let cnt = cnt - 1
+ let index = matchend(match, s:notslash . '\\(')
+ if index == -1
+ return ""
+ endif
+ let match = strpart(match, index)
+ endwhile
+ let start = len - strlen(match)
+ if a:0 == 1 && a:1 == "start"
+ return start - 2
+ endif
+ let cnt = 1
+ while cnt
+ let index = matchend(match, s:notslash . '\\(\|\\)') - 1
+ if index == -2
+ return ""
+ endif
+ " Increment if an open, decrement if a ')':
+ let cnt = cnt + (match[index]=="(" ? 1 : -1) " ')'
+ let match = strpart(match, index+1)
+ endwhile
+ let start = start - 2
+ let len = len - start - strlen(match)
+ endif
+ if a:0 == 1
+ return len
+ elseif a:0 == 2
+ return "let " . a:1 . "=" . start . "| let " . a:2 . "=" . len
+ else
+ return strpart(a:string, start, len)
+ endif
+endfun
+
+" Count the number of disjoint copies of pattern in string.
+" If the pattern is a literal string and contains no '0' or '1' characters
+" then s:Count(string, pattern, '0', '1') should be faster than
+" s:Count(string, pattern).
+fun! s:Count(string, pattern, ...)
+ let pat = escape(a:pattern, '\\')
+ if a:0 > 1
+ let foo = substitute(a:string, '[^'.a:pattern.']', "a:1", "g")
+ let foo = substitute(a:string, pat, a:2, "g")
+ let foo = substitute(foo, '[^' . a:2 . ']', "", "g")
+ return strlen(foo)
+ endif
+ let result = 0
+ let foo = a:string
+ let index = matchend(foo, pat)
+ while index != -1
+ let result = result + 1
+ let foo = strpart(foo, index)
+ let index = matchend(foo, pat)
+ endwhile
+ return result
+endfun
+
+" s:Resolve('\(a\)\(b\)', '\(c\)\2\1\1\2') should return table.word, where
+" word = '\(c\)\(b\)\(a\)\3\2' and table = '-32-------'. That is, the first
+" '\1' in target is replaced by '\(a\)' in word, table[1] = 3, and this
+" indicates that all other instances of '\1' in target are to be replaced
+" by '\3'. The hard part is dealing with nesting...
+" Note that ":" is an illegal character for source and target,
+" unless it is preceded by "\".
+fun! s:Resolve(source, target, output)
+ let word = a:target
+ let i = matchend(word, s:notslash . '\\\d') - 1
+ let table = "----------"
+ while i != -2 " There are back references to be replaced.
+ let d = word[i]
+ let backref = s:Ref(a:source, d)
+ " The idea is to replace '\d' with backref. Before we do this,
+ " replace any \(\) groups in backref with :1, :2, ... if they
+ " correspond to the first, second, ... group already inserted
+ " into backref. Later, replace :1 with \1 and so on. The group
+ " number w+b within backref corresponds to the group number
+ " s within a:source.
+ " w = number of '\(' in word before the current one
+ let w = s:Count(
+ \ substitute(strpart(word, 0, i-1), '\\\\', '', 'g'), '\(', '1')
+ let b = 1 " number of the current '\(' in backref
+ let s = d " number of the current '\(' in a:source
+ while b <= s:Count(substitute(backref, '\\\\', '', 'g'), '\(', '1')
+ \ && s < 10
+ if table[s] == "-"
+ if w + b < 10
+ " let table[s] = w + b
+ let table = strpart(table, 0, s) . (w+b) . strpart(table, s+1)
+ endif
+ let b = b + 1
+ let s = s + 1
+ else
+ execute s:Ref(backref, b, "start", "len")
+ let ref = strpart(backref, start, len)
+ let backref = strpart(backref, 0, start) . ":". table[s]
+ \ . strpart(backref, start+len)
+ let s = s + s:Count(substitute(ref, '\\\\', '', 'g'), '\(', '1')
+ endif
+ endwhile
+ let word = strpart(word, 0, i-1) . backref . strpart(word, i+1)
+ let i = matchend(word, s:notslash . '\\\d') - 1
+ endwhile
+ let word = substitute(word, s:notslash . '\zs:', '\\', 'g')
+ if a:output == "table"
+ return table
+ elseif a:output == "word"
+ return word
+ else
+ return table . word
+ endif
+endfun
+
+" Assume a:comma = ",". Then the format for a:patterns and a:1 is
+" a:patterns = "<pat1>,<pat2>,..."
+" a:1 = "<alt1>,<alt2>,..."
+" If <patn> is the first pattern that matches a:string then return <patn>
+" if no optional arguments are given; return <patn>,<altn> if a:1 is given.
+fun! s:Choose(patterns, string, comma, branch, prefix, suffix, ...)
+ let tail = (a:patterns =~ a:comma."$" ? a:patterns : a:patterns . a:comma)
+ let i = matchend(tail, s:notslash . a:comma)
+ if a:0
+ let alttail = (a:1 =~ a:comma."$" ? a:1 : a:1 . a:comma)
+ let j = matchend(alttail, s:notslash . a:comma)
+ endif
+ let current = strpart(tail, 0, i-1)
+ if a:branch == ""
+ let currpat = current
+ else
+ let currpat = substitute(current, s:notslash . a:branch, '\\|', 'g')
+ endif
+ while a:string !~ a:prefix . currpat . a:suffix
+ let tail = strpart(tail, i)
+ let i = matchend(tail, s:notslash . a:comma)
+ if i == -1
+ return -1
+ endif
+ let current = strpart(tail, 0, i-1)
+ if a:branch == ""
+ let currpat = current
+ else
+ let currpat = substitute(current, s:notslash . a:branch, '\\|', 'g')
+ endif
+ if a:0
+ let alttail = strpart(alttail, j)
+ let j = matchend(alttail, s:notslash . a:comma)
+ endif
+ endwhile
+ if a:0
+ let current = current . a:comma . strpart(alttail, 0, j-1)
+ endif
+ return current
+endfun
+
+fun! matchit#Match_debug()
+ let b:match_debug = 1 " Save debugging information.
+ " pat = all of b:match_words with backrefs parsed
+ amenu &Matchit.&pat :echo b:match_pat<CR>
+ " match = bit of text that is recognized as a match
+ amenu &Matchit.&match :echo b:match_match<CR>
+ " curcol = cursor column of the start of the matching text
+ amenu &Matchit.&curcol :echo b:match_col<CR>
+ " wholeBR = matching group, original version
+ amenu &Matchit.wh&oleBR :echo b:match_wholeBR<CR>
+ " iniBR = 'if' piece, original version
+ amenu &Matchit.ini&BR :echo b:match_iniBR<CR>
+ " ini = 'if' piece, with all backrefs resolved from match
+ amenu &Matchit.&ini :echo b:match_ini<CR>
+ " tail = 'else\|endif' piece, with all backrefs resolved from match
+ amenu &Matchit.&tail :echo b:match_tail<CR>
+ " fin = 'endif' piece, with all backrefs resolved from match
+ amenu &Matchit.&word :echo b:match_word<CR>
+ " '\'.d in ini refers to the same thing as '\'.table[d] in word.
+ amenu &Matchit.t&able :echo '0:' . b:match_table . ':9'<CR>
+endfun
+
+" Jump to the nearest unmatched "(" or "if" or "<tag>" if a:spflag == "bW"
+" or the nearest unmatched "</tag>" or "endif" or ")" if a:spflag == "W".
+" Return a "mark" for the original position, so that
+" let m = MultiMatch("bW", "n") ... call winrestview(m)
+" will return to the original position. If there is a problem, do not
+" move the cursor and return {}, unless a count is given, in which case
+" go up or down as many levels as possible and again return {}.
+" TODO This relies on the same patterns as % matching. It might be a good
+" idea to give it its own matching patterns.
+fun! matchit#MultiMatch(spflag, mode)
+ let restore_options = s:RestoreOptions()
+ let startpos = [line("."), col(".")]
+ " save v:count1 variable, might be reset from the restore_cursor command
+ let level = v:count1
+ if a:mode == "o" && mode(1) !~# '[vV]'
+ exe "norm! v"
+ endif
+
+ " First step: if not already done, set the script variables
+ " s:do_BR flag for whether there are backrefs
+ " s:pat parsed version of b:match_words
+ " s:all regexp based on s:pat and the default groups
+ " This part is copied and slightly modified from matchit#Match_wrapper().
+ if !exists("b:match_words") || b:match_words == ""
+ let match_words = ""
+ " Allow b:match_words = "GetVimMatchWords()" .
+ elseif b:match_words =~ ":"
+ let match_words = b:match_words
+ else
+ execute "let match_words =" b:match_words
+ endif
+ if (match_words != s:last_words) || (&mps != s:last_mps) ||
+ \ exists("b:match_debug")
+ let default = escape(&mps, '[$^.*~\\/?]') . (strlen(&mps) ? "," : "") .
+ \ '\/\*:\*\/,#\s*if\%(n\=def\)\=:#\s*else\>:#\s*elif\>:#\s*endif\>'
+ let s:last_mps = &mps
+ let match_words = match_words . (strlen(match_words) ? "," : "") . default
+ let s:last_words = match_words
+ if match_words !~ s:notslash . '\\\d'
+ let s:do_BR = 0
+ let s:pat = match_words
+ else
+ let s:do_BR = 1
+ let s:pat = s:ParseWords(match_words)
+ endif
+ let s:all = '\%(' . substitute(s:pat, '[,:]\+', '\\|', 'g') . '\)'
+ if exists("b:match_debug")
+ let b:match_pat = s:pat
+ endif
+ " Reconstruct the version with unresolved backrefs.
+ let s:patBR = substitute(match_words.',',
+ \ s:notslash.'\zs[,:]*,[,:]*', ',', 'g')
+ let s:patBR = substitute(s:patBR, s:notslash.'\zs:\{2,}', ':', 'g')
+ endif
+
+ " Second step: figure out the patterns for searchpair()
+ " and save the screen, cursor position, and 'ignorecase'.
+ " - TODO: A lot of this is copied from matchit#Match_wrapper().
+ " - maybe even more functionality should be split off
+ " - into separate functions!
+ let openlist = split(s:pat . ',', s:notslash . '\zs:.\{-}' . s:notslash . ',')
+ let midclolist = split(',' . s:pat, s:notslash . '\zs,.\{-}' . s:notslash . ':')
+ call map(midclolist, {-> split(v:val, s:notslash . ':')})
+ let closelist = []
+ let middlelist = []
+ call map(midclolist, {i,v -> [extend(closelist, v[-1 : -1]),
+ \ extend(middlelist, v[0 : -2])]})
+ call map(openlist, {i,v -> v =~# s:notslash . '\\|' ? '\%(' . v . '\)' : v})
+ call map(middlelist, {i,v -> v =~# s:notslash . '\\|' ? '\%(' . v . '\)' : v})
+ call map(closelist, {i,v -> v =~# s:notslash . '\\|' ? '\%(' . v . '\)' : v})
+ let open = join(openlist, ',')
+ let middle = join(middlelist, ',')
+ let close = join(closelist, ',')
+ if exists("b:match_skip")
+ let skip = b:match_skip
+ elseif exists("b:match_comment") " backwards compatibility and testing!
+ let skip = "r:" . b:match_comment
+ else
+ let skip = 's:comment\|string'
+ endif
+ let skip = s:ParseSkip(skip)
+ let view = winsaveview()
+
+ " Third step: call searchpair().
+ " Replace '\('--but not '\\('--with '\%(' and ',' with '\|'.
+ let openpat = substitute(open, '\%(' . s:notslash . '\)\@<=\\(', '\\%(', 'g')
+ let openpat = substitute(openpat, ',', '\\|', 'g')
+ let closepat = substitute(close, '\%(' . s:notslash . '\)\@<=\\(', '\\%(', 'g')
+ let closepat = substitute(closepat, ',', '\\|', 'g')
+ let middlepat = substitute(middle, '\%(' . s:notslash . '\)\@<=\\(', '\\%(', 'g')
+ let middlepat = substitute(middlepat, ',', '\\|', 'g')
+
+ if skip =~ 'synID' && !(has("syntax") && exists("g:syntax_on"))
+ let skip = '0'
+ else
+ try
+ execute "if " . skip . "| let skip = '0' | endif"
+ catch /^Vim\%((\a\+)\)\=:E363/
+ " We won't find anything, so skip searching, should keep Vim responsive.
+ return {}
+ endtry
+ endif
+ mark '
+ while level
+ if searchpair(openpat, middlepat, closepat, a:spflag, skip) < 1
+ call s:CleanUp(restore_options, a:mode, startpos)
+ return {}
+ endif
+ let level = level - 1
+ endwhile
+
+ " Restore options and return a string to restore the original position.
+ call s:CleanUp(restore_options, a:mode, startpos)
+ return view
+endfun
+
+" Search backwards for "if" or "while" or "<tag>" or ...
+" and return "endif" or "endwhile" or "</tag>" or ... .
+" For now, this uses b:match_words and the same script variables
+" as matchit#Match_wrapper() . Later, it may get its own patterns,
+" either from a buffer variable or passed as arguments.
+" fun! s:Autocomplete()
+" echo "autocomplete not yet implemented :-("
+" if !exists("b:match_words") || b:match_words == ""
+" return ""
+" end
+" let startpos = matchit#MultiMatch("bW")
+"
+" if startpos == ""
+" return ""
+" endif
+" " - TODO: figure out whether 'if' or '<tag>' matched, and construct
+" " - the appropriate closing.
+" let matchline = getline(".")
+" let curcol = col(".") - 1
+" " - TODO: Change the s:all argument if there is a new set of match pats.
+" let regexp = s:Wholematch(matchline, s:all, curcol)
+" let suf = strlen(matchline) - matchend(matchline, regexp)
+" let prefix = (curcol ? '^.\{' . curcol . '}\%(' : '^\%(')
+" let suffix = (suf ? '\).\{' . suf . '}$' : '\)$')
+" " Reconstruct the version with unresolved backrefs.
+" let patBR = substitute(b:match_words.',', '[,:]*,[,:]*', ',', 'g')
+" let patBR = substitute(patBR, ':\{2,}', ':', "g")
+" " Now, set group and groupBR to the matching group: 'if:endif' or
+" " 'while:endwhile' or whatever.
+" let group = s:Choose(s:pat, matchline, ",", ":", prefix, suffix, patBR)
+" let i = matchend(group, s:notslash . ",")
+" let groupBR = strpart(group, i)
+" let group = strpart(group, 0, i-1)
+" " Now, matchline =~ prefix . substitute(group,':','\|','g') . suffix
+" if s:do_BR
+" let group = s:InsertRefs(groupBR, prefix, group, suffix, matchline)
+" endif
+" " let g:group = group
+"
+" " - TODO: Construct the closing from group.
+" let fake = "end" . expand("<cword>")
+" execute startpos
+" return fake
+" endfun
+
+" Close all open structures. "Get the heck out of here!"
+" fun! s:Gthhoh()
+" let close = s:Autocomplete()
+" while strlen(close)
+" put=close
+" let close = s:Autocomplete()
+" endwhile
+" endfun
+
+" Parse special strings as typical skip arguments for searchpair():
+" s:foo becomes (current syntax item) =~ foo
+" S:foo becomes (current syntax item) !~ foo
+" r:foo becomes (line before cursor) =~ foo
+" R:foo becomes (line before cursor) !~ foo
+fun! s:ParseSkip(str)
+ let skip = a:str
+ if skip[1] == ":"
+ if skip[0] == "s"
+ let skip = "synIDattr(synID(line('.'),col('.'),1),'name') =~? '" .
+ \ strpart(skip,2) . "'"
+ elseif skip[0] == "S"
+ let skip = "synIDattr(synID(line('.'),col('.'),1),'name') !~? '" .
+ \ strpart(skip,2) . "'"
+ elseif skip[0] == "r"
+ let skip = "strpart(getline('.'),0,col('.'))=~'" . strpart(skip,2). "'"
+ elseif skip[0] == "R"
+ let skip = "strpart(getline('.'),0,col('.'))!~'" . strpart(skip,2). "'"
+ endif
+ endif
+ return skip
+endfun
+
+let &cpo = s:save_cpo
+unlet s:save_cpo
+
+" vim:sts=2:sw=2:et:
diff --git a/runtime/doc/pi_matchit.txt b/runtime/pack/dist/opt/matchit/doc/matchit.txt
index 652734f7bb..b2b78089a0 100644
--- a/runtime/doc/pi_matchit.txt
+++ b/runtime/pack/dist/opt/matchit/doc/matchit.txt
@@ -1,6 +1,13 @@
-*pi_matchit.txt* Extended "%" matching
+*matchit.txt* Extended "%" matching
-For Vim version 6.3. Last change: 2017 May 14
+For instructions on installing this file, type
+ `:help matchit-install`
+inside Vim.
+
+For Vim version 8.1. Last change: 2019 May 05
+
+
+ VIM REFERENCE MANUAL by Benji Fisher et al
*matchit* *matchit.vim*
@@ -34,7 +41,7 @@ g% Cycle backwards through matching groups, as specified by
]% Go to [count] next unmatched group, as specified by
|b:match_words|. Similar to |]}|.
- *a%* *v_a%*
+ *v_a%*
a% In Visual mode, select the matching group, as specified by
|b:match_words|, containing the cursor. Similar to |v_a[|.
A [count] is ignored, and only the first character of the closing
@@ -62,12 +69,8 @@ for how to specify matching patterns.
MODES: *matchit-modes* *matchit-v_%* *matchit-o_%*
-Mostly, % and related motions (|g%| and |[%| and |]%|) work just like built-in
-motion commands in |Operator-pending| and |Visual| modes. However, you
-cannot make these motions |linewise| or |characterwise|, since the |:omap|s
-that define them start with "v" in order to make the default behavior
-inclusive. (See |o_v|.) In other words, "dV%" will not work. The
-work-around is to go through Visual mode: "V%d" will work.
+Mostly, % and related motions (|g%| and |[%| and |]%|) should just work like built-in
+|motion| commands in |Operator-pending| and |Visual| modes (as of 8.1.648)
LANGUAGES: *matchit-languages*
@@ -81,9 +84,9 @@ To support a new language, see |matchit-newlang| below.
DETAILS: *matchit-details* *matchit-parse*
Here is an outline of what matchit.vim does each time you hit the "%" key. If
-there are backrefs in |b:match_words| then the first step is to produce a
+there are |backref|s in |b:match_words| then the first step is to produce a
version in which these back references have been eliminated; if there are no
-backrefs then this step is skipped. This step is called parsing. For
+|backref|s then this step is skipped. This step is called parsing. For
example, "\(foo\|bar\):end\1" is parsed to yield
"\(foo\|bar\):end\(foo\|bar\)". This can get tricky, especially if there are
nested groups. If debugging is turned on, the parsed version is saved as
@@ -128,9 +131,9 @@ column of the start of the match is saved as |b:match_col|.
Next, the script looks through |b:match_words| (original and parsed versions)
for the group and pattern that match. If debugging is turned on, the group is
saved as |b:match_ini| (the first pattern) and |b:match_tail| (the rest). If
-there are backrefs then, in addition, the matching pattern is saved as
+there are |backref|s then, in addition, the matching pattern is saved as
|b:match_word| and a table of translations is saved as |b:match_table|. If
-there are backrefs, these are determined from the matching pattern and
+there are |backref|s, these are determined from the matching pattern and
|b:match_match| and substituted into each pattern in the matching group.
The script decides whether to search forwards or backwards and chooses
@@ -142,11 +145,32 @@ setting |b:match_skip|.
==============================================================================
2. Activation *matchit-activate*
-For a new language, you can add a line such as >
+To use the matchit plugin add this line to your |vimrc|: >
+ packadd! matchit
+
+The script should start working the next time you start Vim.
+
+(Earlier versions of the script did nothing unless a |buffer-variable| named
+|b:match_words| was defined. Even earlier versions contained autocommands
+that set this variable for various file types. Now, |b:match_words| is
+defined in many of the default |filetype-plugin|s instead.)
+
+For a new language, you can add autocommands to the script or to your vimrc
+file, but the recommended method is to add a line such as >
let b:match_words = '\<foo\>:\<bar\>'
-to the corresponding |filetype-plugin|. See |b:match_words| below for how
+to the |filetype-plugin| for your language. See |b:match_words| below for how
this variable is interpreted.
+TROUBLESHOOTING *matchit-troubleshoot*
+
+The script should work in most installations of Vim. It may not work if Vim
+was compiled with a minimal feature set, for example if the |+syntax| option
+was not enabled. If your Vim has support for syntax compiled in, but you do
+not have |syntax| highlighting turned on, matchit.vim should work, but it may
+fail to skip matching groups in comments and strings. If the |filetype|
+mechanism is turned off, the |b:match_words| variable will probably not be
+defined automatically.
+
==============================================================================
3. Configuration *matchit-configure*
@@ -235,7 +259,7 @@ have only one group; the effect is undefined if a group has only one pattern.
A simple example is >
:let b:match_words = '\<if\>:\<endif\>,'
\ . '\<while\>:\<continue\>:\<break\>:\<endwhile\>'
-(In Vim regular expressions, |/\<| and |/\>| denote word boundaries. Thus "if"
+(In Vim regular expressions, |\<| and |\>| denote word boundaries. Thus "if"
matches the end of "endif" but "\<if\>" does not.) Then banging on the "%"
key will bounce the cursor between "if" and the matching "endif"; and from
"while" to any matching "continue" or "break", then to the matching "endwhile"
@@ -256,7 +280,7 @@ definition to a |filetype-plugin| file.
Tips: Be careful that your initial pattern does not match your final pattern.
See the example above for the use of word-boundary expressions. It is usually
better to use ".\{-}" (as many as necessary) instead of ".*" (as many as
-possible). See |/\{-|. For example, in the string "<tag>label</tag>", "<.*>"
+possible). See |\{-|. For example, in the string "<tag>label</tag>", "<.*>"
matches the whole string whereas "<.\{-}>" and "<[^>]*>" match "<tag>" and
"</tag>".
@@ -275,18 +299,18 @@ if keywords are only recognized after the start of a line or after a
semicolon (;), with optional white space.
*matchit-backref* *matchit-\1*
-In any group, the expressions `\1`, `\2`, ..., `\9` (see |/\1|) refer to parts of the
-INITIAL pattern enclosed in escaped parentheses. These are referred to as
-back references, or backrefs. For example, >
+In any group, the expressions |\1|, |\2|, ..., |\9| refer to parts of the
+INITIAL pattern enclosed in |\(|escaped parentheses|\)|. These are referred
+to as back references, or backrefs. For example, >
:let b:match_words = '\<b\(o\+\)\>:\(h\)\1\>'
means that "bo" pairs with "ho" and "boo" pairs with "hoo" and so on. Note
that "\1" does not refer to the "\(h\)" in this example. If you have
"\(nested \(parentheses\)\) then "\d" refers to the d-th "\(" and everything
up to and including the matching "\)": in "\(nested\(parentheses\)\)", "\1"
refers to everything and "\2" refers to "\(parentheses\)". If you use a
-variable such as `s:notend` or `s:sol` in the previous paragraph then remember
+variable such as |s:notend| or |s:sol| in the previous paragraph then remember
to count any "\(" patterns in this variable. You do not have to count groups
-defined by |/\%(\)|.
+defined by |\%(\)|.
It should be possible to resolve back references from any pattern in the
group. For example, >
@@ -297,7 +321,7 @@ cannot be determined from "andbar". On the other hand, >
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
+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"
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
@@ -305,7 +329,7 @@ at the start of the line. For another example, if HTML had only one tag then
one could >
:let b:match_words = '<:>,<\@<=tag>:<\@<=/tag>'
so that "%" can bounce between matching "<" and ">" pairs or (starting on
-"tag" or "/tag") between matching tags. Without the |/\@<=|, the script would
+"tag" or "/tag") between matching tags. Without the |\@<=|, the script would
bounce from "tag" to the "<" in "</tag>", and another "%" would not take you
back to where you started.
@@ -322,10 +346,10 @@ the variables described below. You will probably also want to read
Defining the variable |b:match_debug| causes the script to set the following
variables, each time you hit the "%" key. Several of these are only defined
-if |b:match_words| includes backrefs.
+if |b:match_words| includes |backref|s.
*b:match_pat*
-The b:match_pat variable is set to |b:match_words| with backrefs parsed.
+The b:match_pat variable is set to |b:match_words| with |backref|s parsed.
*b:match_match*
The b:match_match variable is set to the bit of text that is recognized as a
match.
@@ -334,15 +358,15 @@ The b:match_col variable is set to the cursor column of the start of the
matching text.
*b:match_wholeBR*
The b:match_wholeBR variable is set to the comma-separated group of patterns
-that matches, with backrefs unparsed.
+that matches, with |backref|s unparsed.
*b:match_iniBR*
The b:match_iniBR variable is set to the first pattern in |b:match_wholeBR|.
*b:match_ini*
The b:match_ini variable is set to the first pattern in |b:match_wholeBR|,
-with backrefs resolved from |b:match_match|.
+with |backref|s resolved from |b:match_match|.
*b:match_tail*
The b:match_tail variable is set to the remaining patterns in
-|b:match_wholeBR|, with backrefs resolved from |b:match_match|.
+|b:match_wholeBR|, with |backref|s resolved from |b:match_match|.
*b:match_word*
The b:match_word variable is set to the pattern from |b:match_wholeBR| that
matches |b:match_match|.
@@ -353,14 +377,15 @@ The back reference '\'.d refers to the same thing as '\'.b:match_table[d] in
==============================================================================
5. Known Bugs and Limitations *matchit-bugs*
-The various |:vmap|s defined in the script (%, |g%|, |[%|, |]%|, |a%|) may
-have undesired effects in Select mode |Select-mode-mapping|. At least, if you
-want to replace the selection with any character in "ag%[]" there will be a
-pause of |'updatetime'| first. E.g., "yV%" would normally work linewise, but
-the plugin mapping makes it characterwise.
+Just because I know about a bug does not mean that it is on my todo list. I
+try to respond to reports of bugs that cause real problems. If it does not
+cause serious problems, or if there is a work-around, a bug may sit there for
+a while. Moral: if a bug (known or not) bothers you, let me know.
It would be nice if "\0" were recognized as the entire pattern. That is, it
-would be nice if "foo:\end\0" had the same effect as "\(foo\):\end\1".
+would be nice if "foo:\end\0" had the same effect as "\(foo\):\end\1". I may
+try to implement this in a future version. (This is not so easy to arrange as
+you might think!)
==============================================================================
- vim:tw=78:ts=8:noet:ft=help:norl:
+vim:tw=78:fo=tcq2:ft=help:
diff --git a/runtime/pack/dist/opt/matchit/plugin/matchit.vim b/runtime/pack/dist/opt/matchit/plugin/matchit.vim
new file mode 100644
index 0000000000..84147f1fc8
--- /dev/null
+++ b/runtime/pack/dist/opt/matchit/plugin/matchit.vim
@@ -0,0 +1,92 @@
+" matchit.vim: (global plugin) Extended "%" matching
+" Maintainer: Christian Brabandt
+" Version: 1.15
+" Last Change: 2019 Jan 28
+" Repository: https://github.com/chrisbra/matchit
+" Previous URL:http://www.vim.org/script.php?script_id=39
+" Previous Maintainer: Benji Fisher PhD <benji@member.AMS.org>
+
+" Documentation:
+" The documentation is in a separate file: ../doc/matchit.txt .
+
+" Credits:
+" Vim editor by Bram Moolenaar (Thanks, Bram!)
+" Original script and design by Raul Segura Acevedo
+" Support for comments by Douglas Potts
+" Support for back references and other improvements by Benji Fisher
+" Support for many languages by Johannes Zellner
+" Suggestions for improvement, bug reports, and support for additional
+" languages by Jordi-Albert Batalla, Neil Bird, Servatius Brandt, Mark
+" Collett, Stephen Wall, Dany St-Amant, Yuheng Xie, and Johannes Zellner.
+
+" Debugging:
+" If you'd like to try the built-in debugging commands...
+" :MatchDebug to activate debugging for the current buffer
+" This saves the values of several key script variables as buffer-local
+" variables. See the MatchDebug() function, below, for details.
+
+" TODO: I should think about multi-line patterns for b:match_words.
+" This would require an option: how many lines to scan (default 1).
+" This would be useful for Python, maybe also for *ML.
+" TODO: Maybe I should add a menu so that people will actually use some of
+" the features that I have implemented.
+" TODO: Eliminate the MultiMatch function. Add yet another argument to
+" Match_wrapper() instead.
+" TODO: Allow :let b:match_words = '\(\(foo\)\(bar\)\):\3\2:end\1'
+" TODO: Make backrefs safer by using '\V' (very no-magic).
+" TODO: Add a level of indirection, so that custom % scripts can use my
+" work but extend it.
+
+" Allow user to prevent loading and prevent duplicate loading.
+if exists("g:loaded_matchit") || &cp
+ finish
+endif
+let g:loaded_matchit = 1
+
+let s:save_cpo = &cpo
+set cpo&vim
+
+nnoremap <silent> <Plug>(MatchitNormalForward) :<C-U>call matchit#Match_wrapper('',1,'n')<CR>
+nnoremap <silent> <Plug>(MatchitNormalBackward) :<C-U>call matchit#Match_wrapper('',0,'n')<CR>
+vnoremap <silent> <Plug>(MatchitVisualForward) :<C-U>call matchit#Match_wrapper('',1,'v')<CR>m'gv``
+vnoremap <silent> <Plug>(MatchitVisualBackward) :<C-U>call matchit#Match_wrapper('',0,'v')<CR>m'gv``
+onoremap <silent> <Plug>(MatchitOperationForward) :<C-U>call matchit#Match_wrapper('',1,'o')<CR>
+onoremap <silent> <Plug>(MatchitOperationBackward) :<C-U>call matchit#Match_wrapper('',0,'o')<CR>
+
+nmap <silent> % <Plug>(MatchitNormalForward)
+nmap <silent> g% <Plug>(MatchitNormalBackward)
+xmap <silent> % <Plug>(MatchitVisualForward)
+xmap <silent> g% <Plug>(MatchitVisualBackward)
+omap <silent> % <Plug>(MatchitOperationForward)
+omap <silent> g% <Plug>(MatchitOperationBackward)
+
+" Analogues of [{ and ]} using matching patterns:
+nnoremap <silent> <Plug>(MatchitNormalMultiBackward) :<C-U>call matchit#MultiMatch("bW", "n")<CR>
+nnoremap <silent> <Plug>(MatchitNormalMultiForward) :<C-U>call matchit#MultiMatch("W", "n")<CR>
+vnoremap <silent> <Plug>(MatchitVisualMultiBackward) :<C-U>call matchit#MultiMatch("bW", "n")<CR>m'gv``
+vnoremap <silent> <Plug>(MatchitVisualMultiForward) :<C-U>call matchit#MultiMatch("W", "n")<CR>m'gv``
+onoremap <silent> <Plug>(MatchitOperationMultiBackward) :<C-U>call matchit#MultiMatch("bW", "o")<CR>
+onoremap <silent> <Plug>(MatchitOperationMultiForward) :<C-U>call matchit#MultiMatch("W", "o")<CR>
+
+nmap <silent> [% <Plug>(MatchitNormalMultiBackward)
+nmap <silent> ]% <Plug>(MatchitNormalMultiForward)
+xmap <silent> [% <Plug>(MatchitVisualMultiBackward)
+xmap <silent> ]% <Plug>(MatchitVisualMultiForward)
+omap <silent> [% <Plug>(MatchitOperationMultiBackward)
+omap <silent> ]% <Plug>(MatchitOperationMultiForward)
+
+" text object:
+vmap <silent> <Plug>(MatchitVisualTextObject) <Plug>(MatchitVisualMultiBackward)o<Plug>(MatchitVisualMultiForward)
+xmap a% <Plug>(MatchitVisualTextObject)
+
+" Call this function to turn on debugging information. Every time the main
+" script is run, buffer variables will be saved. These can be used directly
+" or viewed using the menu items below.
+if !exists(":MatchDebug")
+ command! -nargs=0 MatchDebug call matchit#Match_debug()
+endif
+
+let &cpo = s:save_cpo
+unlet s:save_cpo
+
+" vim:sts=2:sw=2:et:
diff --git a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
index 04d940948a..a3356d35a5 100644
--- a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
+++ b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
@@ -119,10 +119,14 @@ func s:StartDebug_internal(dict)
let s:startsigncolumn = &signcolumn
let s:save_columns = 0
+ let s:allleft = 0
if exists('g:termdebug_wide')
if &columns < g:termdebug_wide
let s:save_columns = &columns
let &columns = g:termdebug_wide
+ " If we make the Vim window wider, use the whole left halve for the debug
+ " windows.
+ let s:allleft = 1
endif
let s:vertical = 1
else
@@ -140,7 +144,7 @@ endfunc
func s:StartDebug_term(dict)
" Open a terminal window without a job, to run the debugged program in.
- execute 'new'
+ execute s:vertical ? 'vnew' : 'new'
let s:pty_job_id = termopen('tail -f /dev/null;#gdb program')
if s:pty_job_id == 0
echoerr 'invalid argument (or job table is full) while opening terminal window'
@@ -157,6 +161,10 @@ func s:StartDebug_term(dict)
" Assuming the source code window will get a signcolumn, use two more
" columns for that, thus one less for the terminal window.
exe (&columns / 2 - 1) . "wincmd |"
+ if s:allleft
+ " use the whole left column
+ wincmd H
+ endif
endif
" Create a hidden terminal window to communicate with gdb
diff --git a/runtime/plugin/matchit.vim b/runtime/plugin/matchit.vim
index c160522f90..63be644062 100644
--- a/runtime/plugin/matchit.vim
+++ b/runtime/plugin/matchit.vim
@@ -1,817 +1,4 @@
-" matchit.vim: (global plugin) Extended "%" matching
-" Last Change: 2018 Jul 3 by Christian Brabandt
-" Maintainer: Benji Fisher PhD <benji@member.AMS.org>
-" Version: 1.13.3, for Vim 6.3+
-" Fix from Tommy Allen included.
-" Fix from Fernando Torres included.
-" Improvement from Ken Takata included.
-" URL: http://www.vim.org/script.php?script_id=39
-
-" Documentation:
-" The documentation is in a separate file, matchit.txt .
-
-" Credits:
-" Vim editor by Bram Moolenaar (Thanks, Bram!)
-" Original script and design by Raul Segura Acevedo
-" Support for comments by Douglas Potts
-" Support for back references and other improvements by Benji Fisher
-" Support for many languages by Johannes Zellner
-" Suggestions for improvement, bug reports, and support for additional
-" languages by Jordi-Albert Batalla, Neil Bird, Servatius Brandt, Mark
-" Collett, Stephen Wall, Dany St-Amant, Yuheng Xie, and Johannes Zellner.
-
-" Debugging:
-" If you'd like to try the built-in debugging commands...
-" :MatchDebug to activate debugging for the current buffer
-" This saves the values of several key script variables as buffer-local
-" variables. See the MatchDebug() function, below, for details.
-
-" TODO: I should think about multi-line patterns for b:match_words.
-" This would require an option: how many lines to scan (default 1).
-" This would be useful for Python, maybe also for *ML.
-" TODO: Maybe I should add a menu so that people will actually use some of
-" the features that I have implemented.
-" TODO: Eliminate the MultiMatch function. Add yet another argument to
-" Match_wrapper() instead.
-" TODO: Allow :let b:match_words = '\(\(foo\)\(bar\)\):\3\2:end\1'
-" TODO: Make backrefs safer by using '\V' (very no-magic).
-" TODO: Add a level of indirection, so that custom % scripts can use my
-" work but extend it.
-
-" allow user to prevent loading
-" and prevent duplicate loading
-if exists("loaded_matchit") || &cp
- finish
+" Nvim: load the matchit plugin by default.
+if stridx(&packpath, $VIMRUNTIME) >= 0
+ packadd matchit
endif
-let loaded_matchit = 1
-let s:last_mps = ""
-let s:last_words = ":"
-let s:patBR = ""
-
-let s:save_cpo = &cpo
-set cpo&vim
-
-nnoremap <silent> % :<C-U>call <SID>Match_wrapper('',1,'n') <CR>
-nnoremap <silent> g% :<C-U>call <SID>Match_wrapper('',0,'n') <CR>
-vnoremap <silent> % :<C-U>call <SID>Match_wrapper('',1,'v') <CR>m'gv``
-vnoremap <silent> g% :<C-U>call <SID>Match_wrapper('',0,'v') <CR>m'gv``
-onoremap <silent> % v:<C-U>call <SID>Match_wrapper('',1,'o') <CR>
-onoremap <silent> g% v:<C-U>call <SID>Match_wrapper('',0,'o') <CR>
-
-" Analogues of [{ and ]} using matching patterns:
-nnoremap <silent> [% :<C-U>call <SID>MultiMatch("bW", "n") <CR>
-nnoremap <silent> ]% :<C-U>call <SID>MultiMatch("W", "n") <CR>
-vmap [% <Esc>[%m'gv``
-vmap ]% <Esc>]%m'gv``
-" vnoremap <silent> [% :<C-U>call <SID>MultiMatch("bW", "v") <CR>m'gv``
-" vnoremap <silent> ]% :<C-U>call <SID>MultiMatch("W", "v") <CR>m'gv``
-onoremap <silent> [% v:<C-U>call <SID>MultiMatch("bW", "o") <CR>
-onoremap <silent> ]% v:<C-U>call <SID>MultiMatch("W", "o") <CR>
-
-" text object:
-vmap a% <Esc>[%v]%
-
-" Auto-complete mappings: (not yet "ready for prime time")
-" TODO Read :help write-plugin for the "right" way to let the user
-" specify a key binding.
-" let g:match_auto = '<C-]>'
-" let g:match_autoCR = '<C-CR>'
-" if exists("g:match_auto")
-" execute "inoremap " . g:match_auto . ' x<Esc>"=<SID>Autocomplete()<CR>Pls'
-" endif
-" if exists("g:match_autoCR")
-" execute "inoremap " . g:match_autoCR . ' <CR><C-R>=<SID>Autocomplete()<CR>'
-" endif
-" if exists("g:match_gthhoh")
-" execute "inoremap " . g:match_gthhoh . ' <C-O>:call <SID>Gthhoh()<CR>'
-" endif " gthhoh = "Get the heck out of here!"
-
-let s:notslash = '\\\@<!\%(\\\\\)*'
-
-function! s:Match_wrapper(word, forward, mode) range
- " In s:CleanUp(), :execute "set" restore_options .
- let restore_options = ""
- if exists("b:match_ignorecase") && b:match_ignorecase != &ic
- let restore_options .= (&ic ? " " : " no") . "ignorecase"
- let &ignorecase = b:match_ignorecase
- endif
- if &ve != ''
- let restore_options = " ve=" . &ve . restore_options
- set ve=
- endif
- " If this function was called from Visual mode, make sure that the cursor
- " is at the correct end of the Visual range:
- if a:mode == "v"
- execute "normal! gv\<Esc>"
- endif
- " In s:CleanUp(), we may need to check whether the cursor moved forward.
- let startline = line(".")
- let startcol = col(".")
- " Use default behavior if called with a count.
- if v:count
- exe "normal! " . v:count . "%"
- return s:CleanUp(restore_options, a:mode, startline, startcol)
- end
-
- " First step: if not already done, set the script variables
- " s:do_BR flag for whether there are backrefs
- " s:pat parsed version of b:match_words
- " s:all regexp based on s:pat and the default groups
- "
- if !exists("b:match_words") || b:match_words == ""
- let match_words = ""
- " Allow b:match_words = "GetVimMatchWords()" .
- elseif b:match_words =~ ":"
- let match_words = b:match_words
- else
- execute "let match_words =" b:match_words
- endif
-" Thanks to Preben "Peppe" Guldberg and Bram Moolenaar for this suggestion!
- if (match_words != s:last_words) || (&mps != s:last_mps)
- \ || exists("b:match_debug")
- let s:last_mps = &mps
- " The next several lines were here before
- " BF started messing with this script.
- " quote the special chars in 'matchpairs', replace [,:] with \| and then
- " append the builtin pairs (/*, */, #if, #ifdef, #else, #elif, #endif)
- " let default = substitute(escape(&mps, '[$^.*~\\/?]'), '[,:]\+',
- " \ '\\|', 'g').'\|\/\*\|\*\/\|#if\>\|#ifdef\>\|#else\>\|#elif\>\|#endif\>'
- let default = escape(&mps, '[$^.*~\\/?]') . (strlen(&mps) ? "," : "") .
- \ '\/\*:\*\/,#\s*if\%(def\)\=:#\s*else\>:#\s*elif\>:#\s*endif\>'
- " s:all = pattern with all the keywords
- let match_words = match_words . (strlen(match_words) ? "," : "") . default
- let s:last_words = match_words
- if match_words !~ s:notslash . '\\\d'
- let s:do_BR = 0
- let s:pat = match_words
- else
- let s:do_BR = 1
- let s:pat = s:ParseWords(match_words)
- endif
- let s:all = substitute(s:pat, s:notslash . '\zs[,:]\+', '\\|', 'g')
- let s:all = '\%(' . s:all . '\)'
- " let s:all = '\%(' . substitute(s:all, '\\\ze[,:]', '', 'g') . '\)'
- if exists("b:match_debug")
- let b:match_pat = s:pat
- endif
- " Reconstruct the version with unresolved backrefs.
- let s:patBR = substitute(match_words.',',
- \ s:notslash.'\zs[,:]*,[,:]*', ',', 'g')
- let s:patBR = substitute(s:patBR, s:notslash.'\zs:\{2,}', ':', 'g')
- endif
-
- " Second step: set the following local variables:
- " matchline = line on which the cursor started
- " curcol = number of characters before match
- " prefix = regexp for start of line to start of match
- " suffix = regexp for end of match to end of line
- " Require match to end on or after the cursor and prefer it to
- " start on or before the cursor.
- let matchline = getline(startline)
- if a:word != ''
- " word given
- if a:word !~ s:all
- echohl WarningMsg|echo 'Missing rule for word:"'.a:word.'"'|echohl NONE
- return s:CleanUp(restore_options, a:mode, startline, startcol)
- endif
- let matchline = a:word
- let curcol = 0
- let prefix = '^\%('
- let suffix = '\)$'
- " Now the case when "word" is not given
- else " Find the match that ends on or after the cursor and set curcol.
- let regexp = s:Wholematch(matchline, s:all, startcol-1)
- let curcol = match(matchline, regexp)
- " If there is no match, give up.
- if curcol == -1
- return s:CleanUp(restore_options, a:mode, startline, startcol)
- endif
- let endcol = matchend(matchline, regexp)
- let suf = strlen(matchline) - endcol
- let prefix = (curcol ? '^.*\%' . (curcol + 1) . 'c\%(' : '^\%(')
- let suffix = (suf ? '\)\%' . (endcol + 1) . 'c.*$' : '\)$')
- endif
- if exists("b:match_debug")
- let b:match_match = matchstr(matchline, regexp)
- let b:match_col = curcol+1
- endif
-
- " Third step: Find the group and single word that match, and the original
- " (backref) versions of these. Then, resolve the backrefs.
- " Set the following local variable:
- " group = colon-separated list of patterns, one of which matches
- " = ini:mid:fin or ini:fin
- "
- " Now, set group and groupBR to the matching group: 'if:endif' or
- " 'while:endwhile' or whatever. A bit of a kluge: s:Choose() returns
- " group . "," . groupBR, and we pick it apart.
- let group = s:Choose(s:pat, matchline, ",", ":", prefix, suffix, s:patBR)
- let i = matchend(group, s:notslash . ",")
- let groupBR = strpart(group, i)
- let group = strpart(group, 0, i-1)
- " Now, matchline =~ prefix . substitute(group,':','\|','g') . suffix
- if s:do_BR " Do the hard part: resolve those backrefs!
- let group = s:InsertRefs(groupBR, prefix, group, suffix, matchline)
- endif
- if exists("b:match_debug")
- let b:match_wholeBR = groupBR
- let i = matchend(groupBR, s:notslash . ":")
- let b:match_iniBR = strpart(groupBR, 0, i-1)
- endif
-
- " Fourth step: Set the arguments for searchpair().
- let i = matchend(group, s:notslash . ":")
- let j = matchend(group, '.*' . s:notslash . ":")
- let ini = strpart(group, 0, i-1)
- let mid = substitute(strpart(group, i,j-i-1), s:notslash.'\zs:', '\\|', 'g')
- let fin = strpart(group, j)
- "Un-escape the remaining , and : characters.
- let ini = substitute(ini, s:notslash . '\zs\\\(:\|,\)', '\1', 'g')
- let mid = substitute(mid, s:notslash . '\zs\\\(:\|,\)', '\1', 'g')
- let fin = substitute(fin, s:notslash . '\zs\\\(:\|,\)', '\1', 'g')
- " searchpair() requires that these patterns avoid \(\) groups.
- let ini = substitute(ini, s:notslash . '\zs\\(', '\\%(', 'g')
- let mid = substitute(mid, s:notslash . '\zs\\(', '\\%(', 'g')
- let fin = substitute(fin, s:notslash . '\zs\\(', '\\%(', 'g')
- " Set mid. This is optimized for readability, not micro-efficiency!
- if a:forward && matchline =~ prefix . fin . suffix
- \ || !a:forward && matchline =~ prefix . ini . suffix
- let mid = ""
- endif
- " Set flag. This is optimized for readability, not micro-efficiency!
- if a:forward && matchline =~ prefix . fin . suffix
- \ || !a:forward && matchline !~ prefix . ini . suffix
- let flag = "bW"
- else
- let flag = "W"
- endif
- " Set skip.
- if exists("b:match_skip")
- let skip = b:match_skip
- elseif exists("b:match_comment") " backwards compatibility and testing!
- let skip = "r:" . b:match_comment
- else
- let skip = 's:comment\|string'
- endif
- let skip = s:ParseSkip(skip)
- if exists("b:match_debug")
- let b:match_ini = ini
- let b:match_tail = (strlen(mid) ? mid.'\|' : '') . fin
- endif
-
- " Fifth step: actually start moving the cursor and call searchpair().
- " Later, :execute restore_cursor to get to the original screen.
- let view = winsaveview()
- call cursor(0, curcol + 1)
- " normal! 0
- " if curcol
- " execute "normal!" . curcol . "l"
- " endif
- if skip =~ 'synID' && !(has("syntax") && exists("g:syntax_on"))
- let skip = '0'
- else
- execute "if " . skip . "| let skip = '0' | endif"
- endif
- let sp_return = searchpair(ini, mid, fin, flag, skip)
- let final_position = "call cursor(" . line(".") . "," . col(".") . ")"
- " Restore cursor position and original screen.
- call winrestview(view)
- normal! m'
- if sp_return > 0
- execute final_position
- endif
- return s:CleanUp(restore_options, a:mode, startline, startcol, mid.'\|'.fin)
-endfun
-
-" Restore options and do some special handling for Operator-pending mode.
-" The optional argument is the tail of the matching group.
-fun! s:CleanUp(options, mode, startline, startcol, ...)
- if strlen(a:options)
- execute "set" a:options
- endif
- " Open folds, if appropriate.
- if a:mode != "o"
- if &foldopen =~ "percent"
- normal! zv
- endif
- " In Operator-pending mode, we want to include the whole match
- " (for example, d%).
- " This is only a problem if we end up moving in the forward direction.
- elseif (a:startline < line(".")) ||
- \ (a:startline == line(".") && a:startcol < col("."))
- if a:0
- " Check whether the match is a single character. If not, move to the
- " end of the match.
- let matchline = getline(".")
- let currcol = col(".")
- let regexp = s:Wholematch(matchline, a:1, currcol-1)
- let endcol = matchend(matchline, regexp)
- if endcol > currcol " This is NOT off by one!
- call cursor(0, endcol)
- endif
- endif " a:0
- endif " a:mode != "o" && etc.
- return 0
-endfun
-
-" Example (simplified HTML patterns): if
-" a:groupBR = '<\(\k\+\)>:</\1>'
-" a:prefix = '^.\{3}\('
-" a:group = '<\(\k\+\)>:</\(\k\+\)>'
-" a:suffix = '\).\{2}$'
-" a:matchline = "123<tag>12" or "123</tag>12"
-" then extract "tag" from a:matchline and return "<tag>:</tag>" .
-fun! s:InsertRefs(groupBR, prefix, group, suffix, matchline)
- if a:matchline !~ a:prefix .
- \ substitute(a:group, s:notslash . '\zs:', '\\|', 'g') . a:suffix
- return a:group
- endif
- let i = matchend(a:groupBR, s:notslash . ':')
- let ini = strpart(a:groupBR, 0, i-1)
- let tailBR = strpart(a:groupBR, i)
- let word = s:Choose(a:group, a:matchline, ":", "", a:prefix, a:suffix,
- \ a:groupBR)
- let i = matchend(word, s:notslash . ":")
- let wordBR = strpart(word, i)
- let word = strpart(word, 0, i-1)
- " Now, a:matchline =~ a:prefix . word . a:suffix
- if wordBR != ini
- let table = s:Resolve(ini, wordBR, "table")
- else
- " let table = "----------"
- let table = ""
- let d = 0
- while d < 10
- if tailBR =~ s:notslash . '\\' . d
- " let table[d] = d
- let table = table . d
- else
- let table = table . "-"
- endif
- let d = d + 1
- endwhile
- endif
- let d = 9
- while d
- if table[d] != "-"
- let backref = substitute(a:matchline, a:prefix.word.a:suffix,
- \ '\'.table[d], "")
- " Are there any other characters that should be escaped?
- let backref = escape(backref, '*,:')
- execute s:Ref(ini, d, "start", "len")
- let ini = strpart(ini, 0, start) . backref . strpart(ini, start+len)
- let tailBR = substitute(tailBR, s:notslash . '\zs\\' . d,
- \ escape(backref, '\\&'), 'g')
- endif
- let d = d-1
- endwhile
- if exists("b:match_debug")
- if s:do_BR
- let b:match_table = table
- let b:match_word = word
- else
- let b:match_table = ""
- let b:match_word = ""
- endif
- endif
- return ini . ":" . tailBR
-endfun
-
-" Input a comma-separated list of groups with backrefs, such as
-" a:groups = '\(foo\):end\1,\(bar\):end\1'
-" and return a comma-separated list of groups with backrefs replaced:
-" return '\(foo\):end\(foo\),\(bar\):end\(bar\)'
-fun! s:ParseWords(groups)
- let groups = substitute(a:groups.",", s:notslash.'\zs[,:]*,[,:]*', ',', 'g')
- let groups = substitute(groups, s:notslash . '\zs:\{2,}', ':', 'g')
- let parsed = ""
- while groups =~ '[^,:]'
- let i = matchend(groups, s:notslash . ':')
- let j = matchend(groups, s:notslash . ',')
- let ini = strpart(groups, 0, i-1)
- let tail = strpart(groups, i, j-i-1) . ":"
- let groups = strpart(groups, j)
- let parsed = parsed . ini
- let i = matchend(tail, s:notslash . ':')
- while i != -1
- " In 'if:else:endif', ini='if' and word='else' and then word='endif'.
- let word = strpart(tail, 0, i-1)
- let tail = strpart(tail, i)
- let i = matchend(tail, s:notslash . ':')
- let parsed = parsed . ":" . s:Resolve(ini, word, "word")
- endwhile " Now, tail has been used up.
- let parsed = parsed . ","
- endwhile " groups =~ '[^,:]'
- let parsed = substitute(parsed, ',$', '', '')
- return parsed
-endfun
-
-" TODO I think this can be simplified and/or made more efficient.
-" TODO What should I do if a:start is out of range?
-" Return a regexp that matches all of a:string, such that
-" matchstr(a:string, regexp) represents the match for a:pat that starts
-" as close to a:start as possible, before being preferred to after, and
-" ends after a:start .
-" Usage:
-" let regexp = s:Wholematch(getline("."), 'foo\|bar', col(".")-1)
-" let i = match(getline("."), regexp)
-" let j = matchend(getline("."), regexp)
-" let match = matchstr(getline("."), regexp)
-fun! s:Wholematch(string, pat, start)
- let group = '\%(' . a:pat . '\)'
- let prefix = (a:start ? '\(^.*\%<' . (a:start + 2) . 'c\)\zs' : '^')
- let len = strlen(a:string)
- let suffix = (a:start+1 < len ? '\(\%>'.(a:start+1).'c.*$\)\@=' : '$')
- if a:string !~ prefix . group . suffix
- let prefix = ''
- endif
- return prefix . group . suffix
-endfun
-
-" No extra arguments: s:Ref(string, d) will
-" find the d'th occurrence of '\(' and return it, along with everything up
-" to and including the matching '\)'.
-" One argument: s:Ref(string, d, "start") returns the index of the start
-" of the d'th '\(' and any other argument returns the length of the group.
-" Two arguments: s:Ref(string, d, "foo", "bar") returns a string to be
-" executed, having the effect of
-" :let foo = s:Ref(string, d, "start")
-" :let bar = s:Ref(string, d, "len")
-fun! s:Ref(string, d, ...)
- let len = strlen(a:string)
- if a:d == 0
- let start = 0
- else
- let cnt = a:d
- let match = a:string
- while cnt
- let cnt = cnt - 1
- let index = matchend(match, s:notslash . '\\(')
- if index == -1
- return ""
- endif
- let match = strpart(match, index)
- endwhile
- let start = len - strlen(match)
- if a:0 == 1 && a:1 == "start"
- return start - 2
- endif
- let cnt = 1
- while cnt
- let index = matchend(match, s:notslash . '\\(\|\\)') - 1
- if index == -2
- return ""
- endif
- " Increment if an open, decrement if a ')':
- let cnt = cnt + (match[index]=="(" ? 1 : -1) " ')'
- " let cnt = stridx('0(', match[index]) + cnt
- let match = strpart(match, index+1)
- endwhile
- let start = start - 2
- let len = len - start - strlen(match)
- endif
- if a:0 == 1
- return len
- elseif a:0 == 2
- return "let " . a:1 . "=" . start . "| let " . a:2 . "=" . len
- else
- return strpart(a:string, start, len)
- endif
-endfun
-
-" Count the number of disjoint copies of pattern in string.
-" If the pattern is a literal string and contains no '0' or '1' characters
-" then s:Count(string, pattern, '0', '1') should be faster than
-" s:Count(string, pattern).
-fun! s:Count(string, pattern, ...)
- let pat = escape(a:pattern, '\\')
- if a:0 > 1
- let foo = substitute(a:string, '[^'.a:pattern.']', "a:1", "g")
- let foo = substitute(a:string, pat, a:2, "g")
- let foo = substitute(foo, '[^' . a:2 . ']', "", "g")
- return strlen(foo)
- endif
- let result = 0
- let foo = a:string
- let index = matchend(foo, pat)
- while index != -1
- let result = result + 1
- let foo = strpart(foo, index)
- let index = matchend(foo, pat)
- endwhile
- return result
-endfun
-
-" s:Resolve('\(a\)\(b\)', '\(c\)\2\1\1\2') should return table.word, where
-" word = '\(c\)\(b\)\(a\)\3\2' and table = '-32-------'. That is, the first
-" '\1' in target is replaced by '\(a\)' in word, table[1] = 3, and this
-" indicates that all other instances of '\1' in target are to be replaced
-" by '\3'. The hard part is dealing with nesting...
-" Note that ":" is an illegal character for source and target,
-" unless it is preceded by "\".
-fun! s:Resolve(source, target, output)
- let word = a:target
- let i = matchend(word, s:notslash . '\\\d') - 1
- let table = "----------"
- while i != -2 " There are back references to be replaced.
- let d = word[i]
- let backref = s:Ref(a:source, d)
- " The idea is to replace '\d' with backref. Before we do this,
- " replace any \(\) groups in backref with :1, :2, ... if they
- " correspond to the first, second, ... group already inserted
- " into backref. Later, replace :1 with \1 and so on. The group
- " number w+b within backref corresponds to the group number
- " s within a:source.
- " w = number of '\(' in word before the current one
- let w = s:Count(
- \ substitute(strpart(word, 0, i-1), '\\\\', '', 'g'), '\(', '1')
- let b = 1 " number of the current '\(' in backref
- let s = d " number of the current '\(' in a:source
- while b <= s:Count(substitute(backref, '\\\\', '', 'g'), '\(', '1')
- \ && s < 10
- if table[s] == "-"
- if w + b < 10
- " let table[s] = w + b
- let table = strpart(table, 0, s) . (w+b) . strpart(table, s+1)
- endif
- let b = b + 1
- let s = s + 1
- else
- execute s:Ref(backref, b, "start", "len")
- let ref = strpart(backref, start, len)
- let backref = strpart(backref, 0, start) . ":". table[s]
- \ . strpart(backref, start+len)
- let s = s + s:Count(substitute(ref, '\\\\', '', 'g'), '\(', '1')
- endif
- endwhile
- let word = strpart(word, 0, i-1) . backref . strpart(word, i+1)
- let i = matchend(word, s:notslash . '\\\d') - 1
- endwhile
- let word = substitute(word, s:notslash . '\zs:', '\\', 'g')
- if a:output == "table"
- return table
- elseif a:output == "word"
- return word
- else
- return table . word
- endif
-endfun
-
-" Assume a:comma = ",". Then the format for a:patterns and a:1 is
-" a:patterns = "<pat1>,<pat2>,..."
-" a:1 = "<alt1>,<alt2>,..."
-" If <patn> is the first pattern that matches a:string then return <patn>
-" if no optional arguments are given; return <patn>,<altn> if a:1 is given.
-fun! s:Choose(patterns, string, comma, branch, prefix, suffix, ...)
- let tail = (a:patterns =~ a:comma."$" ? a:patterns : a:patterns . a:comma)
- let i = matchend(tail, s:notslash . a:comma)
- if a:0
- let alttail = (a:1 =~ a:comma."$" ? a:1 : a:1 . a:comma)
- let j = matchend(alttail, s:notslash . a:comma)
- endif
- let current = strpart(tail, 0, i-1)
- if a:branch == ""
- let currpat = current
- else
- let currpat = substitute(current, s:notslash . a:branch, '\\|', 'g')
- endif
- while a:string !~ a:prefix . currpat . a:suffix
- let tail = strpart(tail, i)
- let i = matchend(tail, s:notslash . a:comma)
- if i == -1
- return -1
- endif
- let current = strpart(tail, 0, i-1)
- if a:branch == ""
- let currpat = current
- else
- let currpat = substitute(current, s:notslash . a:branch, '\\|', 'g')
- endif
- if a:0
- let alttail = strpart(alttail, j)
- let j = matchend(alttail, s:notslash . a:comma)
- endif
- endwhile
- if a:0
- let current = current . a:comma . strpart(alttail, 0, j-1)
- endif
- return current
-endfun
-
-" Call this function to turn on debugging information. Every time the main
-" script is run, buffer variables will be saved. These can be used directly
-" or viewed using the menu items below.
-if !exists(":MatchDebug")
- command! -nargs=0 MatchDebug call s:Match_debug()
-endif
-
-fun! s:Match_debug()
- let b:match_debug = 1 " Save debugging information.
- " pat = all of b:match_words with backrefs parsed
- amenu &Matchit.&pat :echo b:match_pat<CR>
- " match = bit of text that is recognized as a match
- amenu &Matchit.&match :echo b:match_match<CR>
- " curcol = cursor column of the start of the matching text
- amenu &Matchit.&curcol :echo b:match_col<CR>
- " wholeBR = matching group, original version
- amenu &Matchit.wh&oleBR :echo b:match_wholeBR<CR>
- " iniBR = 'if' piece, original version
- amenu &Matchit.ini&BR :echo b:match_iniBR<CR>
- " ini = 'if' piece, with all backrefs resolved from match
- amenu &Matchit.&ini :echo b:match_ini<CR>
- " tail = 'else\|endif' piece, with all backrefs resolved from match
- amenu &Matchit.&tail :echo b:match_tail<CR>
- " fin = 'endif' piece, with all backrefs resolved from match
- amenu &Matchit.&word :echo b:match_word<CR>
- " '\'.d in ini refers to the same thing as '\'.table[d] in word.
- amenu &Matchit.t&able :echo '0:' . b:match_table . ':9'<CR>
-endfun
-
-" Jump to the nearest unmatched "(" or "if" or "<tag>" if a:spflag == "bW"
-" or the nearest unmatched "</tag>" or "endif" or ")" if a:spflag == "W".
-" Return a "mark" for the original position, so that
-" let m = MultiMatch("bW", "n") ... execute m
-" will return to the original position. If there is a problem, do not
-" move the cursor and return "", unless a count is given, in which case
-" go up or down as many levels as possible and again return "".
-" TODO This relies on the same patterns as % matching. It might be a good
-" idea to give it its own matching patterns.
-fun! s:MultiMatch(spflag, mode)
- if !exists("b:match_words") || b:match_words == ""
- return {}
- end
- let restore_options = ""
- if exists("b:match_ignorecase") && b:match_ignorecase != &ic
- let restore_options .= (&ic ? " " : " no") . "ignorecase"
- let &ignorecase = b:match_ignorecase
- endif
- let startline = line(".")
- let startcol = col(".")
-
- " First step: if not already done, set the script variables
- " s:do_BR flag for whether there are backrefs
- " s:pat parsed version of b:match_words
- " s:all regexp based on s:pat and the default groups
- " This part is copied and slightly modified from s:Match_wrapper().
- let default = escape(&mps, '[$^.*~\\/?]') . (strlen(&mps) ? "," : "") .
- \ '\/\*:\*\/,#\s*if\%(def\)\=:#\s*else\>:#\s*elif\>:#\s*endif\>'
- " Allow b:match_words = "GetVimMatchWords()" .
- if b:match_words =~ ":"
- let match_words = b:match_words
- else
- execute "let match_words =" b:match_words
- endif
- if (match_words != s:last_words) || (&mps != s:last_mps) ||
- \ exists("b:match_debug")
- let s:last_words = match_words
- let s:last_mps = &mps
- let match_words = match_words . (strlen(match_words) ? "," : "") . default
- if match_words !~ s:notslash . '\\\d'
- let s:do_BR = 0
- let s:pat = match_words
- else
- let s:do_BR = 1
- let s:pat = s:ParseWords(match_words)
- endif
- let s:all = '\%(' . substitute(s:pat . (strlen(s:pat) ? "," : "") . default,
- \ '[,:]\+', '\\|', 'g') . '\)'
- if exists("b:match_debug")
- let b:match_pat = s:pat
- endif
- endif
-
- " Second step: figure out the patterns for searchpair()
- " and save the screen, cursor position, and 'ignorecase'.
- " - TODO: A lot of this is copied from s:Match_wrapper().
- " - maybe even more functionality should be split off
- " - into separate functions!
- let cdefault = (s:pat =~ '[^,]$' ? "," : "") . default
- let open = substitute(s:pat . cdefault,
- \ s:notslash . '\zs:.\{-}' . s:notslash . ',', '\\),\\(', 'g')
- let open = '\(' . substitute(open, s:notslash . '\zs:.*$', '\\)', '')
- let close = substitute(s:pat . cdefault,
- \ s:notslash . '\zs,.\{-}' . s:notslash . ':', '\\),\\(', 'g')
- let close = substitute(close, '^.\{-}' . s:notslash . ':', '\\(', '') . '\)'
- if exists("b:match_skip")
- let skip = b:match_skip
- elseif exists("b:match_comment") " backwards compatibility and testing!
- let skip = "r:" . b:match_comment
- else
- let skip = 's:comment\|string'
- endif
- let skip = s:ParseSkip(skip)
- let view = winsaveview()
-
- " Third step: call searchpair().
- " Replace '\('--but not '\\('--with '\%(' and ',' with '\|'.
- let openpat = substitute(open, '\(\\\@<!\(\\\\\)*\)\@<=\\(', '\\%(', 'g')
- let openpat = substitute(openpat, ',', '\\|', 'g')
- let closepat = substitute(close, '\(\\\@<!\(\\\\\)*\)\@<=\\(', '\\%(', 'g')
- let closepat = substitute(closepat, ',', '\\|', 'g')
-
- if skip =~ 'synID' && !(has("syntax") && exists("g:syntax_on"))
- let skip = '0'
- else
- try
- execute "if " . skip . "| let skip = '0' | endif"
- catch /^Vim\%((\a\+)\)\=:E363/
- " We won't find anything, so skip searching, should keep Vim responsive.
- return {}
- endtry
- endif
- mark '
- let level = v:count1
- while level
- if searchpair(openpat, '', closepat, a:spflag, skip) < 1
- call s:CleanUp(restore_options, a:mode, startline, startcol)
- return {}
- endif
- let level = level - 1
- endwhile
-
- " Restore options and return view dict to restore the original position.
- call s:CleanUp(restore_options, a:mode, startline, startcol)
- return view
-endfun
-
-" Search backwards for "if" or "while" or "<tag>" or ...
-" and return "endif" or "endwhile" or "</tag>" or ... .
-" For now, this uses b:match_words and the same script variables
-" as s:Match_wrapper() . Later, it may get its own patterns,
-" either from a buffer variable or passed as arguments.
-" fun! s:Autocomplete()
-" echo "autocomplete not yet implemented :-("
-" if !exists("b:match_words") || b:match_words == ""
-" return ""
-" end
-" let startpos = s:MultiMatch("bW")
-"
-" if startpos == ""
-" return ""
-" endif
-" " - TODO: figure out whether 'if' or '<tag>' matched, and construct
-" " - the appropriate closing.
-" let matchline = getline(".")
-" let curcol = col(".") - 1
-" " - TODO: Change the s:all argument if there is a new set of match pats.
-" let regexp = s:Wholematch(matchline, s:all, curcol)
-" let suf = strlen(matchline) - matchend(matchline, regexp)
-" let prefix = (curcol ? '^.\{' . curcol . '}\%(' : '^\%(')
-" let suffix = (suf ? '\).\{' . suf . '}$' : '\)$')
-" " Reconstruct the version with unresolved backrefs.
-" let patBR = substitute(b:match_words.',', '[,:]*,[,:]*', ',', 'g')
-" let patBR = substitute(patBR, ':\{2,}', ':', "g")
-" " Now, set group and groupBR to the matching group: 'if:endif' or
-" " 'while:endwhile' or whatever.
-" let group = s:Choose(s:pat, matchline, ",", ":", prefix, suffix, patBR)
-" let i = matchend(group, s:notslash . ",")
-" let groupBR = strpart(group, i)
-" let group = strpart(group, 0, i-1)
-" " Now, matchline =~ prefix . substitute(group,':','\|','g') . suffix
-" if s:do_BR
-" let group = s:InsertRefs(groupBR, prefix, group, suffix, matchline)
-" endif
-" " let g:group = group
-"
-" " - TODO: Construct the closing from group.
-" let fake = "end" . expand("<cword>")
-" execute startpos
-" return fake
-" endfun
-
-" Close all open structures. "Get the heck out of here!"
-" fun! s:Gthhoh()
-" let close = s:Autocomplete()
-" while strlen(close)
-" put=close
-" let close = s:Autocomplete()
-" endwhile
-" endfun
-
-" Parse special strings as typical skip arguments for searchpair():
-" s:foo becomes (current syntax item) =~ foo
-" S:foo becomes (current syntax item) !~ foo
-" r:foo becomes (line before cursor) =~ foo
-" R:foo becomes (line before cursor) !~ foo
-fun! s:ParseSkip(str)
- let skip = a:str
- if skip[1] == ":"
- if skip[0] == "s"
- let skip = "synIDattr(synID(line('.'),col('.'),1),'name') =~? '" .
- \ strpart(skip,2) . "'"
- elseif skip[0] == "S"
- let skip = "synIDattr(synID(line('.'),col('.'),1),'name') !~? '" .
- \ strpart(skip,2) . "'"
- elseif skip[0] == "r"
- let skip = "strpart(getline('.'),0,col('.'))=~'" . strpart(skip,2). "'"
- elseif skip[0] == "R"
- let skip = "strpart(getline('.'),0,col('.'))!~'" . strpart(skip,2). "'"
- endif
- endif
- return skip
-endfun
-
-let &cpo = s:save_cpo
-unlet s:save_cpo
-
-" vim:sts=2:sw=2:
diff --git a/runtime/plugin/netrwPlugin.vim b/runtime/plugin/netrwPlugin.vim
index 28e1c3ecf8..e39bde88a7 100644
--- a/runtime/plugin/netrwPlugin.vim
+++ b/runtime/plugin/netrwPlugin.vim
@@ -20,7 +20,7 @@
if &cp || exists("g:loaded_netrwPlugin")
finish
endif
-let g:loaded_netrwPlugin = "v156"
+let g:loaded_netrwPlugin = "v165"
let s:keepcpo = &cpo
set cpo&vim
"DechoRemOn
@@ -42,8 +42,8 @@ augroup END
" Network Browsing Reading Writing: {{{2
augroup Network
au!
- au BufReadCmd file://* call netrw#FileUrlRead(expand("<amatch>"))
- au BufReadCmd ftp://*,rcp://*,scp://*,http://*,file://*,https://*,dav://*,davs://*,rsync://*,sftp://* exe "sil doau BufReadPre ".fnameescape(expand("<amatch>"))|call netrw#Nread(2,expand("<amatch>"))|exe "sil doau BufReadPost ".fnameescape(expand("<amatch>"))
+ au BufReadCmd file://* call netrw#FileUrlEdit(expand("<amatch>"))
+ au BufReadCmd ftp://*,rcp://*,scp://*,http://*,https://*,dav://*,davs://*,rsync://*,sftp://* exe "sil doau BufReadPre ".fnameescape(expand("<amatch>"))|call netrw#Nread(2,expand("<amatch>"))|exe "sil doau BufReadPost ".fnameescape(expand("<amatch>"))
au FileReadCmd ftp://*,rcp://*,scp://*,http://*,file://*,https://*,dav://*,davs://*,rsync://*,sftp://* exe "sil doau FileReadPre ".fnameescape(expand("<amatch>"))|call netrw#Nread(1,expand("<amatch>"))|exe "sil doau FileReadPost ".fnameescape(expand("<amatch>"))
au BufWriteCmd ftp://*,rcp://*,scp://*,http://*,file://*,dav://*,davs://*,rsync://*,sftp://* exe "sil doau BufWritePre ".fnameescape(expand("<amatch>"))|exe 'Nwrite '.fnameescape(expand("<amatch>"))|exe "sil doau BufWritePost ".fnameescape(expand("<amatch>"))
au FileWriteCmd ftp://*,rcp://*,scp://*,http://*,file://*,dav://*,davs://*,rsync://*,sftp://* exe "sil doau FileWritePre ".fnameescape(expand("<amatch>"))|exe "'[,']".'Nwrite '.fnameescape(expand("<amatch>"))|exe "sil doau FileWritePost ".fnameescape(expand("<amatch>"))
@@ -59,7 +59,7 @@ com! -count=1 -nargs=* Nread let s:svpos= winsaveview()<bar>call netrw#NetRead(
com! -range=% -nargs=* Nwrite let s:svpos= winsaveview()<bar><line1>,<line2>call netrw#NetWrite(<f-args>)<bar>call winrestview(s:svpos)
com! -nargs=* NetUserPass call NetUserPass(<f-args>)
com! -nargs=* Nsource let s:svpos= winsaveview()<bar>call netrw#NetSource(<f-args>)<bar>call winrestview(s:svpos)
-com! -nargs=? Ntree call netrw#SetTreetop(<q-args>)
+com! -nargs=? Ntree call netrw#SetTreetop(1,<q-args>)
" Commands: :Explore, :Sexplore, Hexplore, Vexplore, Lexplore {{{2
com! -nargs=* -bar -bang -count=0 -complete=dir Explore call netrw#Explore(<count>,0,0+<bang>0,<q-args>)
@@ -81,7 +81,7 @@ if !exists("g:netrw_nogx")
if !hasmapto('<Plug>NetrwBrowseX')
nmap <unique> gx <Plug>NetrwBrowseX
endif
- nno <silent> <Plug>NetrwBrowseX :call netrw#BrowseX(expand((exists("g:netrw_gx")? g:netrw_gx : '<cfile>')),netrw#CheckIfRemote())<cr>
+ nno <silent> <Plug>NetrwBrowseX :call netrw#BrowseX(netrw#GX(),netrw#CheckIfRemote(netrw#GX()))<cr>
endif
if maparg('gx','v') == ""
if !hasmapto('<Plug>NetrwBrowseXVis')
@@ -129,19 +129,15 @@ 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")
-" call Decho("(s:LocalBrowse) COMBAK#23: buf#".bufnr("%")." file<".expand("%")."> line#".line(".")." col#".col("."))
sil! call netrw#LocalBrowseCheck(a:dirname)
-" call Decho("(s:LocalBrowse) COMBAK#24: buf#".bufnr("%")." file<".expand("%")."> line#".line(".")." col#".col("."))
if exists("w:netrw_bannercnt") && line('.') < w:netrw_bannercnt
exe w:netrw_bannercnt
-" call Decho("(s:LocalBrowse) COMBAK#25: buf#".bufnr("%")." file<".expand("%")."> line#".line(".")." col#".col("."))
endif
else
" not a directory, ignore it
" call Decho("(LocalBrowse) dirname<".a:dirname."> not a directory, ignoring...")
endif
-" call Decho("(s:LocalBrowse) COMBAK#26: buf#".bufnr("%")." file<".expand("%")."> line#".line(".")." col#".col("."))
" call Dret("s:LocalBrowse")
endfun
diff --git a/runtime/plugin/tohtml.vim b/runtime/plugin/tohtml.vim
index b438dea811..0cd931eada 100644
--- a/runtime/plugin/tohtml.vim
+++ b/runtime/plugin/tohtml.vim
@@ -1,82 +1,33 @@
" Vim plugin for converting a syntax highlighted file to HTML.
" Maintainer: Ben Fritz <fritzophrenic@gmail.com>
-" Last Change: 2015 Sep 08
+" Last Change: 2018 Nov 11
"
" The core of the code is in $VIMRUNTIME/autoload/tohtml.vim and
" $VIMRUNTIME/syntax/2html.vim
"
-" TODO: {{{
-" * Options for generating the CSS in external style sheets. New :TOcss
-" command to convert the current color scheme into a (mostly) generic CSS
-" stylesheet which can be re-used. Alternate stylesheet support? Good start
-" by Erik Falor
-" ( https://groups.google.com/d/topic/vim_use/7XTmC4D22dU/discussion ).
-" * Add optional argument to :TOhtml command to specify mode (gui, cterm,
-" term) to use for the styling. Suggestion by "nacitar".
-" * Add way to override or specify which RGB colors map to the color numbers
-" in cterm. Get better defaults than just guessing? Suggestion by "nacitar".
-" * Disable filetype detection until after all processing is done.
-" * Add option for not generating the hyperlink on stuff that looks like a
-" URL? Or just color the link to fit with the colorscheme (and only special
-" when hovering)?
-" * Bug: Opera does not allow printing more than one page if uncopyable
-" regions is turned on. Possible solution: Add normal text line numbers with
-" display:none, set to display:inline for print style sheets, and hide
-" <input> elements for print, to allow Opera printing multiple pages (and
-" other uncopyable areas?). May need to make the new text invisible to IE
-" with conditional comments to prevent copying it, IE for some reason likes
-" to copy hidden text. Other browsers too?
-" * Bug: still a 1px gap throughout the fold column when html_prevent_copy is
-" "fn" in some browsers. Specifically, in Chromium on Ubuntu (but not Chrome
-" on Windows). Perhaps it is font related?
-" * Bug: still some gaps in the fold column when html_prevent_copy contains
-" 'd' and showing the whole diff (observed in multiple browsers). Only gaps
-" on diff lines though.
-" * Undercurl support via CSS3, with fallback to dotted or something:
-" https://groups.google.com/d/topic/vim_use/BzXA6He1pHg/discussion
-" * Redo updates for modified default foldtext (v11) when/if the patch is
-" accepted to modify it.
-" * Test case +diff_one_file-dynamic_folds+expand_tabs-hover_unfold
-" +ignore_conceal-ignore_folding+no_foldcolumn+no_pre+no_progress
-" +number_lines-pre_wrap-use_css+use_xhtml+whole_filler.xhtml
-" does not show the whole diff filler as it is supposed to?
-" * Bug: when 'isprint' is wrong for the current encoding, will generate
-" invalid content. Can/should anything be done about this? Maybe a separate
-" plugin to correct 'isprint' based on encoding?
-" * Check to see if the windows-125\d encodings actually work in Unix without
-" the 8bit- prefix. Add prefix to autoload dictionaries for Unix if not.
-" * Font auto-detection similar to
-" http://www.vim.org/scripts/script.php?script_id=2384 but for a variety of
-" platforms.
-" * Error thrown when sourcing 2html.vim directly when plugins are not loaded.
-" * Pull in code from http://www.vim.org/scripts/script.php?script_id=3113 :
-" - listchars support
-" - full-line background highlight
-" - other?
-" * Make it so deleted lines in a diff don't create side-scrolling (get it
-" free with full-line background highlight above).
-" * Restore open/closed folds and cursor position after processing each file
-" with option not to restore for speed increase.
-" * Add extra meta info (generation time, etc.)?
-" * Tidy up so we can use strict doctype in even more situations
-" * Implementation detail: add threshold for writing the lines to the html
-" buffer before we're done (5000 or so lines should do it)
-" * TODO comments for code cleanup scattered throughout
-"}}}
-
if exists('g:loaded_2html_plugin')
finish
endif
-let g:loaded_2html_plugin = 'vim7.4_v2'
+let g:loaded_2html_plugin = 'vim8.1_v1'
"
" Changelog: {{{
-" 7.4_v2 (this version): Fix error raised when converting a diff containing
+" 8.1_v1 (this version): Fix Bitbucket issue #6: Don't generate empty script
+" tag.
+" Fix Bitbucket issue #5: javascript should
+" declare variables with "var".
+" Fix Bitbucket issue #13: errors thrown sourcing
+" 2html.vim directly when plugins not loaded.
+" Fix Bitbucket issue #16: support 'vartabstop'.
+"
+" 7.4 updates: {{{
+" 7.4_v2 (Vim 7.4.0899): Fix error raised when converting a diff containing
" an empty buffer. Jan Stocker: allow g:html_font to
" take a list so it is easier to specfiy fallback
" fonts in the generated CSS.
" 7.4_v1 (Vim 7.4.0000): Fix modeline mangling for new "Vim:" format, and
" also for version-specific modelines like "vim>703:".
+"}}}
"
" 7.3 updates: {{{
" 7.3_v14 (Vim 7.3.1246): Allow suppressing line number anchors using
@@ -170,9 +121,69 @@ let g:loaded_2html_plugin = 'vim7.4_v2'
"}}}
"}}}
+" TODO: {{{
+" * Check the issue tracker:
+" https://bitbucket.org/fritzophrenic/vim-tohtml/issues?status=new&status=open
+" * Options for generating the CSS in external style sheets. New :TOcss
+" command to convert the current color scheme into a (mostly) generic CSS
+" stylesheet which can be re-used. Alternate stylesheet support? Good start
+" by Erik Falor
+" ( https://groups.google.com/d/topic/vim_use/7XTmC4D22dU/discussion ).
+" * Add optional argument to :TOhtml command to specify mode (gui, cterm,
+" term) to use for the styling. Suggestion by "nacitar".
+" * Add way to override or specify which RGB colors map to the color numbers
+" in cterm. Get better defaults than just guessing? Suggestion by "nacitar".
+" * Disable filetype detection until after all processing is done.
+" * Add option for not generating the hyperlink on stuff that looks like a
+" URL? Or just color the link to fit with the colorscheme (and only special
+" when hovering)?
+" * Bug: Opera does not allow printing more than one page if uncopyable
+" regions is turned on. Possible solution: Add normal text line numbers with
+" display:none, set to display:inline for print style sheets, and hide
+" <input> elements for print, to allow Opera printing multiple pages (and
+" other uncopyable areas?). May need to make the new text invisible to IE
+" with conditional comments to prevent copying it, IE for some reason likes
+" to copy hidden text. Other browsers too?
+" * Bug: still a 1px gap throughout the fold column when html_prevent_copy is
+" "fn" in some browsers. Specifically, in Chromium on Ubuntu (but not Chrome
+" on Windows). Perhaps it is font related?
+" * Bug: still some gaps in the fold column when html_prevent_copy contains
+" 'd' and showing the whole diff (observed in multiple browsers). Only gaps
+" on diff lines though.
+" * Undercurl support via CSS3, with fallback to dotted or something:
+" https://groups.google.com/d/topic/vim_use/BzXA6He1pHg/discussion
+" * Redo updates for modified default foldtext (v11) when/if the patch is
+" accepted to modify it.
+" * Test case +diff_one_file-dynamic_folds+expand_tabs-hover_unfold
+" +ignore_conceal-ignore_folding+no_foldcolumn+no_pre+no_progress
+" +number_lines-pre_wrap-use_css+use_xhtml+whole_filler.xhtml
+" does not show the whole diff filler as it is supposed to?
+" * Bug: when 'isprint' is wrong for the current encoding, will generate
+" invalid content. Can/should anything be done about this? Maybe a separate
+" plugin to correct 'isprint' based on encoding?
+" * Check to see if the windows-125\d encodings actually work in Unix without
+" the 8bit- prefix. Add prefix to autoload dictionaries for Unix if not.
+" * Font auto-detection similar to
+" http://www.vim.org/scripts/script.php?script_id=2384 but for a variety of
+" platforms.
+" * Pull in code from http://www.vim.org/scripts/script.php?script_id=3113 :
+" - listchars support
+" - full-line background highlight
+" - other?
+" * Make it so deleted lines in a diff don't create side-scrolling (get it
+" free with full-line background highlight above).
+" * Restore open/closed folds and cursor position after processing each file
+" with option not to restore for speed increase.
+" * Add extra meta info (generation time, etc.)?
+" * Tidy up so we can use strict doctype in even more situations
+" * Implementation detail: add threshold for writing the lines to the html
+" buffer before we're done (5000 or so lines should do it)
+" * TODO comments for code cleanup scattered throughout
+"}}}
+
" Define the :TOhtml command when:
" - 'compatible' is not set
-" - this plugin was not already loaded
+" - this plugin or user override was not already loaded
" - user commands are available. {{{
if !&cp && !exists(":TOhtml") && has("user_commands")
command -range=% -bar TOhtml :call tohtml#Convert2HTML(<line1>, <line2>)
diff --git a/runtime/scripts.vim b/runtime/scripts.vim
index ab66c0c0a1..a690431014 100644
--- a/runtime/scripts.vim
+++ b/runtime/scripts.vim
@@ -1,7 +1,7 @@
" Vim support file to detect file types in scripts
"
" Maintainer: Bram Moolenaar <Bram@vim.org>
-" Last change: 2018 Feb 03
+" Last change: 2019 Jun 25
" This file is called by an autocommand for every file that has just been
" loaded into a buffer. It checks if the type of file can be recognized by
@@ -195,7 +195,7 @@ else
if s:line1 =~# '^:$'
call dist#ft#SetFileTypeSH(s:line1) " defined in filetype.vim
- " Z shell scripts
+ " Z shell scripts
elseif s:line1 =~# '^#compdef\>' || s:line1 =~# '^#autoload\>' ||
\ "\n".s:line1."\n".s:line2."\n".s:line3."\n".s:line4."\n".s:line5 =~# '\n\s*emulate\s\+\%(-[LR]\s\+\)\=[ckz]\=sh\>'
set ft=zsh
@@ -204,15 +204,20 @@ else
elseif s:line1 =~# '^From \([a-zA-Z][a-zA-Z_0-9\.=-]*\(@[^ ]*\)\=\|-\) .* \(19\|20\)\d\d$'
set ft=mail
- " Mason
+ " Mason
elseif s:line1 =~# '^<[%&].*>'
set ft=mason
- " Vim scripts (must have '" vim' as the first line to trigger this)
+ " Vim scripts (must have '" vim' as the first line to trigger this)
elseif s:line1 =~# '^" *[vV]im$'
set ft=vim
- " MOO
+ " libcxx and libstdc++ standard library headers like "iostream" do not have
+ " an extension, recognize the Emacs file mode.
+ elseif s:line1 =~? '-\*-.*C++.*-\*-'
+ set ft=cpp
+
+ " MOO
elseif s:line1 =~# '^\*\* LambdaMOO Database, Format Version \%([1-3]\>\)\@!\d\+ \*\*$'
set ft=moo
diff --git a/runtime/synmenu.vim b/runtime/synmenu.vim
index 6814c60e88..e8c9933abf 100644
--- a/runtime/synmenu.vim
+++ b/runtime/synmenu.vim
@@ -56,46 +56,50 @@ an 50.10.270 &Syntax.AB.Applix\ ELF :cal SetSyn("elf")<CR>
an 50.10.280 &Syntax.AB.APT\ config :cal SetSyn("aptconf")<CR>
an 50.10.290 &Syntax.AB.Arc\ Macro\ Language :cal SetSyn("aml")<CR>
an 50.10.300 &Syntax.AB.Arch\ inventory :cal SetSyn("arch")<CR>
-an 50.10.310 &Syntax.AB.ART :cal SetSyn("art")<CR>
-an 50.10.320 &Syntax.AB.Ascii\ Doc :cal SetSyn("asciidoc")<CR>
-an 50.10.330 &Syntax.AB.ASP\ with\ VBScript :cal SetSyn("aspvbs")<CR>
-an 50.10.340 &Syntax.AB.ASP\ with\ Perl :cal SetSyn("aspperl")<CR>
-an 50.10.350 &Syntax.AB.Assembly.680x0 :cal SetSyn("asm68k")<CR>
-an 50.10.360 &Syntax.AB.Assembly.Flat :cal SetSyn("fasm")<CR>
-an 50.10.370 &Syntax.AB.Assembly.GNU :cal SetSyn("asm")<CR>
-an 50.10.380 &Syntax.AB.Assembly.GNU\ H-8300 :cal SetSyn("asmh8300")<CR>
-an 50.10.390 &Syntax.AB.Assembly.Intel\ IA-64 :cal SetSyn("ia64")<CR>
-an 50.10.400 &Syntax.AB.Assembly.Microsoft :cal SetSyn("masm")<CR>
-an 50.10.410 &Syntax.AB.Assembly.Netwide :cal SetSyn("nasm")<CR>
-an 50.10.420 &Syntax.AB.Assembly.PIC :cal SetSyn("pic")<CR>
-an 50.10.430 &Syntax.AB.Assembly.Turbo :cal SetSyn("tasm")<CR>
-an 50.10.440 &Syntax.AB.Assembly.VAX\ Macro\ Assembly :cal SetSyn("vmasm")<CR>
-an 50.10.450 &Syntax.AB.Assembly.Z-80 :cal SetSyn("z8a")<CR>
-an 50.10.460 &Syntax.AB.Assembly.xa\ 6502\ cross\ assember :cal SetSyn("a65")<CR>
-an 50.10.470 &Syntax.AB.ASN\.1 :cal SetSyn("asn")<CR>
-an 50.10.480 &Syntax.AB.Asterisk\ config :cal SetSyn("asterisk")<CR>
-an 50.10.490 &Syntax.AB.Asterisk\ voicemail\ config :cal SetSyn("asteriskvm")<CR>
-an 50.10.500 &Syntax.AB.Atlas :cal SetSyn("atlas")<CR>
-an 50.10.510 &Syntax.AB.AutoHotKey :cal SetSyn("autohotkey")<CR>
-an 50.10.520 &Syntax.AB.AutoIt :cal SetSyn("autoit")<CR>
-an 50.10.530 &Syntax.AB.Automake :cal SetSyn("automake")<CR>
-an 50.10.540 &Syntax.AB.Avenue :cal SetSyn("ave")<CR>
-an 50.10.550 &Syntax.AB.Awk :cal SetSyn("awk")<CR>
-an 50.10.560 &Syntax.AB.AYacc :cal SetSyn("ayacc")<CR>
-an 50.10.580 &Syntax.AB.B :cal SetSyn("b")<CR>
-an 50.10.590 &Syntax.AB.Baan :cal SetSyn("baan")<CR>
-an 50.10.600 &Syntax.AB.Basic.FreeBasic :cal SetSyn("freebasic")<CR>
-an 50.10.610 &Syntax.AB.Basic.IBasic :cal SetSyn("ibasic")<CR>
-an 50.10.620 &Syntax.AB.Basic.QBasic :cal SetSyn("basic")<CR>
-an 50.10.630 &Syntax.AB.Basic.Visual\ Basic :cal SetSyn("vb")<CR>
-an 50.10.640 &Syntax.AB.Bazaar\ commit\ file :cal SetSyn("bzr")<CR>
-an 50.10.650 &Syntax.AB.BC\ calculator :cal SetSyn("bc")<CR>
-an 50.10.660 &Syntax.AB.BDF\ font :cal SetSyn("bdf")<CR>
-an 50.10.670 &Syntax.AB.BibTeX.Bibliography\ database :cal SetSyn("bib")<CR>
-an 50.10.680 &Syntax.AB.BibTeX.Bibliography\ Style :cal SetSyn("bst")<CR>
-an 50.10.690 &Syntax.AB.BIND.BIND\ config :cal SetSyn("named")<CR>
-an 50.10.700 &Syntax.AB.BIND.BIND\ zone :cal SetSyn("bindzone")<CR>
-an 50.10.710 &Syntax.AB.Blank :cal SetSyn("blank")<CR>
+an 50.10.310 &Syntax.AB.Arduino :cal SetSyn("arduino")<CR>
+an 50.10.320 &Syntax.AB.ART :cal SetSyn("art")<CR>
+an 50.10.330 &Syntax.AB.Ascii\ Doc :cal SetSyn("asciidoc")<CR>
+an 50.10.340 &Syntax.AB.ASP\ with\ VBScript :cal SetSyn("aspvbs")<CR>
+an 50.10.350 &Syntax.AB.ASP\ with\ Perl :cal SetSyn("aspperl")<CR>
+an 50.10.360 &Syntax.AB.Assembly.680x0 :cal SetSyn("asm68k")<CR>
+an 50.10.370 &Syntax.AB.Assembly.AVR :cal SetSyn("avra")<CR>
+an 50.10.380 &Syntax.AB.Assembly.Flat :cal SetSyn("fasm")<CR>
+an 50.10.390 &Syntax.AB.Assembly.GNU :cal SetSyn("asm")<CR>
+an 50.10.400 &Syntax.AB.Assembly.GNU\ H-8300 :cal SetSyn("asmh8300")<CR>
+an 50.10.410 &Syntax.AB.Assembly.Intel\ IA-64 :cal SetSyn("ia64")<CR>
+an 50.10.420 &Syntax.AB.Assembly.Microsoft :cal SetSyn("masm")<CR>
+an 50.10.430 &Syntax.AB.Assembly.Netwide :cal SetSyn("nasm")<CR>
+an 50.10.440 &Syntax.AB.Assembly.PIC :cal SetSyn("pic")<CR>
+an 50.10.450 &Syntax.AB.Assembly.Turbo :cal SetSyn("tasm")<CR>
+an 50.10.460 &Syntax.AB.Assembly.VAX\ Macro\ Assembly :cal SetSyn("vmasm")<CR>
+an 50.10.470 &Syntax.AB.Assembly.Z-80 :cal SetSyn("z8a")<CR>
+an 50.10.480 &Syntax.AB.Assembly.xa\ 6502\ cross\ assember :cal SetSyn("a65")<CR>
+an 50.10.490 &Syntax.AB.ASN\.1 :cal SetSyn("asn")<CR>
+an 50.10.500 &Syntax.AB.Asterisk\ config :cal SetSyn("asterisk")<CR>
+an 50.10.510 &Syntax.AB.Asterisk\ voicemail\ config :cal SetSyn("asteriskvm")<CR>
+an 50.10.520 &Syntax.AB.Atlas :cal SetSyn("atlas")<CR>
+an 50.10.530 &Syntax.AB.Autodoc :cal SetSyn("autodoc")<CR>
+an 50.10.540 &Syntax.AB.AutoHotKey :cal SetSyn("autohotkey")<CR>
+an 50.10.550 &Syntax.AB.AutoIt :cal SetSyn("autoit")<CR>
+an 50.10.560 &Syntax.AB.Automake :cal SetSyn("automake")<CR>
+an 50.10.570 &Syntax.AB.Avenue :cal SetSyn("ave")<CR>
+an 50.10.580 &Syntax.AB.Awk :cal SetSyn("awk")<CR>
+an 50.10.590 &Syntax.AB.AYacc :cal SetSyn("ayacc")<CR>
+an 50.10.610 &Syntax.AB.B :cal SetSyn("b")<CR>
+an 50.10.620 &Syntax.AB.Baan :cal SetSyn("baan")<CR>
+an 50.10.630 &Syntax.AB.Basic.FreeBasic :cal SetSyn("freebasic")<CR>
+an 50.10.640 &Syntax.AB.Basic.IBasic :cal SetSyn("ibasic")<CR>
+an 50.10.650 &Syntax.AB.Basic.QBasic :cal SetSyn("basic")<CR>
+an 50.10.660 &Syntax.AB.Basic.Visual\ Basic :cal SetSyn("vb")<CR>
+an 50.10.670 &Syntax.AB.Bazaar\ commit\ file :cal SetSyn("bzr")<CR>
+an 50.10.680 &Syntax.AB.Bazel :cal SetSyn("bzl")<CR>
+an 50.10.690 &Syntax.AB.BC\ calculator :cal SetSyn("bc")<CR>
+an 50.10.700 &Syntax.AB.BDF\ font :cal SetSyn("bdf")<CR>
+an 50.10.710 &Syntax.AB.BibTeX.Bibliography\ database :cal SetSyn("bib")<CR>
+an 50.10.720 &Syntax.AB.BibTeX.Bibliography\ Style :cal SetSyn("bst")<CR>
+an 50.10.730 &Syntax.AB.BIND.BIND\ config :cal SetSyn("named")<CR>
+an 50.10.740 &Syntax.AB.BIND.BIND\ zone :cal SetSyn("bindzone")<CR>
+an 50.10.750 &Syntax.AB.Blank :cal SetSyn("blank")<CR>
an 50.20.100 &Syntax.C.C :cal SetSyn("c")<CR>
an 50.20.110 &Syntax.C.C++ :cal SetSyn("cpp")<CR>
an 50.20.120 &Syntax.C.C# :cal SetSyn("cs")<CR>
@@ -117,75 +121,81 @@ an 50.20.270 &Syntax.C.Clever :cal SetSyn("cl")<CR>
an 50.20.280 &Syntax.C.Clipper :cal SetSyn("clipper")<CR>
an 50.20.290 &Syntax.C.Clojure :cal SetSyn("clojure")<CR>
an 50.20.300 &Syntax.C.Cmake :cal SetSyn("cmake")<CR>
-an 50.20.310 &Syntax.C.Cmusrc :cal SetSyn("cmusrc")<CR>
-an 50.20.320 &Syntax.C.Cobol :cal SetSyn("cobol")<CR>
-an 50.20.330 &Syntax.C.Coco/R :cal SetSyn("coco")<CR>
-an 50.20.340 &Syntax.C.Cold\ Fusion :cal SetSyn("cf")<CR>
-an 50.20.350 &Syntax.C.Conary\ Recipe :cal SetSyn("conaryrecipe")<CR>
-an 50.20.360 &Syntax.C.Config.Cfg\ Config\ file :cal SetSyn("cfg")<CR>
-an 50.20.370 &Syntax.C.Config.Configure\.in :cal SetSyn("config")<CR>
-an 50.20.380 &Syntax.C.Config.Generic\ Config\ file :cal SetSyn("conf")<CR>
-an 50.20.390 &Syntax.C.CRM114 :cal SetSyn("crm")<CR>
-an 50.20.400 &Syntax.C.Crontab :cal SetSyn("crontab")<CR>
-an 50.20.410 &Syntax.C.CSDL :cal SetSyn("csdl")<CR>
-an 50.20.420 &Syntax.C.CSP :cal SetSyn("csp")<CR>
-an 50.20.430 &Syntax.C.Ctrl-H :cal SetSyn("ctrlh")<CR>
-an 50.20.440 &Syntax.C.Cucumber :cal SetSyn("cucumber")<CR>
-an 50.20.450 &Syntax.C.CUDA :cal SetSyn("cuda")<CR>
-an 50.20.460 &Syntax.C.CUPL.CUPL :cal SetSyn("cupl")<CR>
-an 50.20.470 &Syntax.C.CUPL.Simulation :cal SetSyn("cuplsim")<CR>
-an 50.20.480 &Syntax.C.CVS.commit\ file :cal SetSyn("cvs")<CR>
-an 50.20.490 &Syntax.C.CVS.cvsrc :cal SetSyn("cvsrc")<CR>
-an 50.20.500 &Syntax.C.Cyn++ :cal SetSyn("cynpp")<CR>
-an 50.20.510 &Syntax.C.Cynlib :cal SetSyn("cynlib")<CR>
+an 50.20.310 &Syntax.C.Cmod :cal SetSyn("cmod")<CR>
+an 50.20.320 &Syntax.C.Cmusrc :cal SetSyn("cmusrc")<CR>
+an 50.20.330 &Syntax.C.Cobol :cal SetSyn("cobol")<CR>
+an 50.20.340 &Syntax.C.Coco/R :cal SetSyn("coco")<CR>
+an 50.20.350 &Syntax.C.Cold\ Fusion :cal SetSyn("cf")<CR>
+an 50.20.360 &Syntax.C.Conary\ Recipe :cal SetSyn("conaryrecipe")<CR>
+an 50.20.370 &Syntax.C.Config.Cfg\ Config\ file :cal SetSyn("cfg")<CR>
+an 50.20.380 &Syntax.C.Config.Configure\.in :cal SetSyn("config")<CR>
+an 50.20.390 &Syntax.C.Config.Generic\ Config\ file :cal SetSyn("conf")<CR>
+an 50.20.400 &Syntax.C.CRM114 :cal SetSyn("crm")<CR>
+an 50.20.410 &Syntax.C.Crontab :cal SetSyn("crontab")<CR>
+an 50.20.420 &Syntax.C.CSDL :cal SetSyn("csdl")<CR>
+an 50.20.430 &Syntax.C.CSP :cal SetSyn("csp")<CR>
+an 50.20.440 &Syntax.C.Ctrl-H :cal SetSyn("ctrlh")<CR>
+an 50.20.450 &Syntax.C.Cucumber :cal SetSyn("cucumber")<CR>
+an 50.20.460 &Syntax.C.CUDA :cal SetSyn("cuda")<CR>
+an 50.20.470 &Syntax.C.CUPL.CUPL :cal SetSyn("cupl")<CR>
+an 50.20.480 &Syntax.C.CUPL.Simulation :cal SetSyn("cuplsim")<CR>
+an 50.20.490 &Syntax.C.CVS.commit\ file :cal SetSyn("cvs")<CR>
+an 50.20.500 &Syntax.C.CVS.cvsrc :cal SetSyn("cvsrc")<CR>
+an 50.20.510 &Syntax.C.Cyn++ :cal SetSyn("cynpp")<CR>
+an 50.20.520 &Syntax.C.Cynlib :cal SetSyn("cynlib")<CR>
an 50.30.100 &Syntax.DE.D :cal SetSyn("d")<CR>
an 50.30.110 &Syntax.DE.Datascript :cal SetSyn("datascript")<CR>
an 50.30.120 &Syntax.DE.Debian.Debian\ ChangeLog :cal SetSyn("debchangelog")<CR>
an 50.30.130 &Syntax.DE.Debian.Debian\ Control :cal SetSyn("debcontrol")<CR>
-an 50.30.140 &Syntax.DE.Debian.Debian\ Sources\.list :cal SetSyn("debsources")<CR>
-an 50.30.150 &Syntax.DE.Denyhosts :cal SetSyn("denyhosts")<CR>
-an 50.30.160 &Syntax.DE.Desktop :cal SetSyn("desktop")<CR>
-an 50.30.170 &Syntax.DE.Dict\ config :cal SetSyn("dictconf")<CR>
-an 50.30.180 &Syntax.DE.Dictd\ config :cal SetSyn("dictdconf")<CR>
-an 50.30.190 &Syntax.DE.Diff :cal SetSyn("diff")<CR>
-an 50.30.200 &Syntax.DE.Digital\ Command\ Lang :cal SetSyn("dcl")<CR>
-an 50.30.210 &Syntax.DE.Dircolors :cal SetSyn("dircolors")<CR>
-an 50.30.220 &Syntax.DE.Django\ template :cal SetSyn("django")<CR>
-an 50.30.230 &Syntax.DE.DNS/BIND\ zone :cal SetSyn("bindzone")<CR>
-an 50.30.240 &Syntax.DE.Dnsmasq\ config :cal SetSyn("dnsmasq")<CR>
-an 50.30.250 &Syntax.DE.DocBook.auto-detect :cal SetSyn("docbk")<CR>
-an 50.30.260 &Syntax.DE.DocBook.SGML :cal SetSyn("docbksgml")<CR>
-an 50.30.270 &Syntax.DE.DocBook.XML :cal SetSyn("docbkxml")<CR>
-an 50.30.280 &Syntax.DE.Dot :cal SetSyn("dot")<CR>
-an 50.30.290 &Syntax.DE.Doxygen.C\ with\ doxygen :cal SetSyn("c.doxygen")<CR>
-an 50.30.300 &Syntax.DE.Doxygen.C++\ with\ doxygen :cal SetSyn("cpp.doxygen")<CR>
-an 50.30.310 &Syntax.DE.Doxygen.IDL\ with\ doxygen :cal SetSyn("idl.doxygen")<CR>
-an 50.30.320 &Syntax.DE.Doxygen.Java\ with\ doxygen :cal SetSyn("java.doxygen")<CR>
-an 50.30.330 &Syntax.DE.Doxygen.DataScript\ with\ doxygen :cal SetSyn("datascript.doxygen")<CR>
-an 50.30.340 &Syntax.DE.Dracula :cal SetSyn("dracula")<CR>
-an 50.30.350 &Syntax.DE.DSSSL :cal SetSyn("dsl")<CR>
-an 50.30.360 &Syntax.DE.DTD :cal SetSyn("dtd")<CR>
-an 50.30.370 &Syntax.DE.DTML\ (Zope) :cal SetSyn("dtml")<CR>
-an 50.30.380 &Syntax.DE.DTrace :cal SetSyn("dtrace")<CR>
-an 50.30.390 &Syntax.DE.Dts/dtsi :cal SetSyn("dts")<CR>
-an 50.30.400 &Syntax.DE.Dylan.Dylan :cal SetSyn("dylan")<CR>
-an 50.30.410 &Syntax.DE.Dylan.Dylan\ interface :cal SetSyn("dylanintr")<CR>
-an 50.30.420 &Syntax.DE.Dylan.Dylan\ lid :cal SetSyn("dylanlid")<CR>
-an 50.30.440 &Syntax.DE.EDIF :cal SetSyn("edif")<CR>
-an 50.30.450 &Syntax.DE.Eiffel :cal SetSyn("eiffel")<CR>
-an 50.30.460 &Syntax.DE.Elinks\ config :cal SetSyn("elinks")<CR>
-an 50.30.470 &Syntax.DE.Elm\ filter\ rules :cal SetSyn("elmfilt")<CR>
-an 50.30.480 &Syntax.DE.Embedix\ Component\ Description :cal SetSyn("ecd")<CR>
-an 50.30.490 &Syntax.DE.ERicsson\ LANGuage :cal SetSyn("erlang")<CR>
-an 50.30.500 &Syntax.DE.ESMTP\ rc :cal SetSyn("esmtprc")<CR>
-an 50.30.510 &Syntax.DE.ESQL-C :cal SetSyn("esqlc")<CR>
-an 50.30.520 &Syntax.DE.Essbase\ script :cal SetSyn("csc")<CR>
-an 50.30.530 &Syntax.DE.Esterel :cal SetSyn("esterel")<CR>
-an 50.30.540 &Syntax.DE.Eterm\ config :cal SetSyn("eterm")<CR>
-an 50.30.550 &Syntax.DE.Eviews :cal SetSyn("eviews")<CR>
-an 50.30.560 &Syntax.DE.Exim\ conf :cal SetSyn("exim")<CR>
-an 50.30.570 &Syntax.DE.Expect :cal SetSyn("expect")<CR>
-an 50.30.580 &Syntax.DE.Exports :cal SetSyn("exports")<CR>
+an 50.30.140 &Syntax.DE.Debian.Debian\ Copyright :cal SetSyn("debcopyright")<CR>
+an 50.30.150 &Syntax.DE.Debian.Debian\ Sources\.list :cal SetSyn("debsources")<CR>
+an 50.30.160 &Syntax.DE.Denyhosts :cal SetSyn("denyhosts")<CR>
+an 50.30.170 &Syntax.DE.Desktop :cal SetSyn("desktop")<CR>
+an 50.30.180 &Syntax.DE.Dict\ config :cal SetSyn("dictconf")<CR>
+an 50.30.190 &Syntax.DE.Dictd\ config :cal SetSyn("dictdconf")<CR>
+an 50.30.200 &Syntax.DE.Diff :cal SetSyn("diff")<CR>
+an 50.30.210 &Syntax.DE.Digital\ Command\ Lang :cal SetSyn("dcl")<CR>
+an 50.30.220 &Syntax.DE.Dircolors :cal SetSyn("dircolors")<CR>
+an 50.30.230 &Syntax.DE.Dirpager :cal SetSyn("dirpager")<CR>
+an 50.30.240 &Syntax.DE.Django\ template :cal SetSyn("django")<CR>
+an 50.30.250 &Syntax.DE.DNS/BIND\ zone :cal SetSyn("bindzone")<CR>
+an 50.30.260 &Syntax.DE.Dnsmasq\ config :cal SetSyn("dnsmasq")<CR>
+an 50.30.270 &Syntax.DE.DocBook.auto-detect :cal SetSyn("docbk")<CR>
+an 50.30.280 &Syntax.DE.DocBook.SGML :cal SetSyn("docbksgml")<CR>
+an 50.30.290 &Syntax.DE.DocBook.XML :cal SetSyn("docbkxml")<CR>
+an 50.30.300 &Syntax.DE.Dockerfile :cal SetSyn("dockerfile")<CR>
+an 50.30.310 &Syntax.DE.Dot :cal SetSyn("dot")<CR>
+an 50.30.320 &Syntax.DE.Doxygen.C\ with\ doxygen :cal SetSyn("c.doxygen")<CR>
+an 50.30.330 &Syntax.DE.Doxygen.C++\ with\ doxygen :cal SetSyn("cpp.doxygen")<CR>
+an 50.30.340 &Syntax.DE.Doxygen.IDL\ with\ doxygen :cal SetSyn("idl.doxygen")<CR>
+an 50.30.350 &Syntax.DE.Doxygen.Java\ with\ doxygen :cal SetSyn("java.doxygen")<CR>
+an 50.30.360 &Syntax.DE.Doxygen.DataScript\ with\ doxygen :cal SetSyn("datascript.doxygen")<CR>
+an 50.30.370 &Syntax.DE.Dracula :cal SetSyn("dracula")<CR>
+an 50.30.380 &Syntax.DE.DSSSL :cal SetSyn("dsl")<CR>
+an 50.30.390 &Syntax.DE.DTD :cal SetSyn("dtd")<CR>
+an 50.30.400 &Syntax.DE.DTML\ (Zope) :cal SetSyn("dtml")<CR>
+an 50.30.410 &Syntax.DE.DTrace :cal SetSyn("dtrace")<CR>
+an 50.30.420 &Syntax.DE.Dts/dtsi :cal SetSyn("dts")<CR>
+an 50.30.430 &Syntax.DE.Dylan.Dylan :cal SetSyn("dylan")<CR>
+an 50.30.440 &Syntax.DE.Dylan.Dylan\ interface :cal SetSyn("dylanintr")<CR>
+an 50.30.450 &Syntax.DE.Dylan.Dylan\ lid :cal SetSyn("dylanlid")<CR>
+an 50.30.470 &Syntax.DE.EDIF :cal SetSyn("edif")<CR>
+an 50.30.480 &Syntax.DE.Eiffel :cal SetSyn("eiffel")<CR>
+an 50.30.490 &Syntax.DE.Elinks\ config :cal SetSyn("elinks")<CR>
+an 50.30.500 &Syntax.DE.Elm\ filter\ rules :cal SetSyn("elmfilt")<CR>
+an 50.30.510 &Syntax.DE.Embedix\ Component\ Description :cal SetSyn("ecd")<CR>
+an 50.30.520 &Syntax.DE.ERicsson\ LANGuage :cal SetSyn("erlang")<CR>
+an 50.30.530 &Syntax.DE.ESMTP\ rc :cal SetSyn("esmtprc")<CR>
+an 50.30.540 &Syntax.DE.ESQL-C :cal SetSyn("esqlc")<CR>
+an 50.30.550 &Syntax.DE.Essbase\ script :cal SetSyn("csc")<CR>
+an 50.30.560 &Syntax.DE.Esterel :cal SetSyn("esterel")<CR>
+an 50.30.570 &Syntax.DE.Eterm\ config :cal SetSyn("eterm")<CR>
+an 50.30.580 &Syntax.DE.Euphoria\ 3 :cal SetSyn("euphoria3")<CR>
+an 50.30.590 &Syntax.DE.Euphoria\ 4 :cal SetSyn("euphoria4")<CR>
+an 50.30.600 &Syntax.DE.Eviews :cal SetSyn("eviews")<CR>
+an 50.30.610 &Syntax.DE.Exim\ conf :cal SetSyn("exim")<CR>
+an 50.30.620 &Syntax.DE.Expect :cal SetSyn("expect")<CR>
+an 50.30.630 &Syntax.DE.Exports :cal SetSyn("exports")<CR>
an 50.40.100 &Syntax.FG.Falcon :cal SetSyn("falcon")<CR>
an 50.40.110 &Syntax.FG.Fantom :cal SetSyn("fan")<CR>
an 50.40.120 &Syntax.FG.Fetchmail :cal SetSyn("fetchmail")<CR>
@@ -212,18 +222,20 @@ an 50.40.330 &Syntax.FG.Git.Send\ Email :cal SetSyn("gitsendemail")<CR>
an 50.40.340 &Syntax.FG.Gitolite :cal SetSyn("gitolite")<CR>
an 50.40.350 &Syntax.FG.Gkrellmrc :cal SetSyn("gkrellmrc")<CR>
an 50.40.360 &Syntax.FG.Gnash :cal SetSyn("gnash")<CR>
-an 50.40.370 &Syntax.FG.GP :cal SetSyn("gp")<CR>
-an 50.40.380 &Syntax.FG.GPG :cal SetSyn("gpg")<CR>
-an 50.40.390 &Syntax.FG.Grof :cal SetSyn("gprof")<CR>
-an 50.40.400 &Syntax.FG.Group\ file :cal SetSyn("group")<CR>
-an 50.40.410 &Syntax.FG.Grub :cal SetSyn("grub")<CR>
-an 50.40.420 &Syntax.FG.GNU\ Server\ Pages :cal SetSyn("gsp")<CR>
-an 50.40.430 &Syntax.FG.GNUplot :cal SetSyn("gnuplot")<CR>
-an 50.40.440 &Syntax.FG.GrADS\ scripts :cal SetSyn("grads")<CR>
-an 50.40.450 &Syntax.FG.Gretl :cal SetSyn("gretl")<CR>
-an 50.40.460 &Syntax.FG.Groff :cal SetSyn("groff")<CR>
-an 50.40.470 &Syntax.FG.Groovy :cal SetSyn("groovy")<CR>
-an 50.40.480 &Syntax.FG.GTKrc :cal SetSyn("gtkrc")<CR>
+an 50.40.370 &Syntax.FG.Go :cal SetSyn("go")<CR>
+an 50.40.380 &Syntax.FG.Godoc :cal SetSyn("godoc")<CR>
+an 50.40.390 &Syntax.FG.GP :cal SetSyn("gp")<CR>
+an 50.40.400 &Syntax.FG.GPG :cal SetSyn("gpg")<CR>
+an 50.40.410 &Syntax.FG.Grof :cal SetSyn("gprof")<CR>
+an 50.40.420 &Syntax.FG.Group\ file :cal SetSyn("group")<CR>
+an 50.40.430 &Syntax.FG.Grub :cal SetSyn("grub")<CR>
+an 50.40.440 &Syntax.FG.GNU\ Server\ Pages :cal SetSyn("gsp")<CR>
+an 50.40.450 &Syntax.FG.GNUplot :cal SetSyn("gnuplot")<CR>
+an 50.40.460 &Syntax.FG.GrADS\ scripts :cal SetSyn("grads")<CR>
+an 50.40.470 &Syntax.FG.Gretl :cal SetSyn("gretl")<CR>
+an 50.40.480 &Syntax.FG.Groff :cal SetSyn("groff")<CR>
+an 50.40.490 &Syntax.FG.Groovy :cal SetSyn("groovy")<CR>
+an 50.40.500 &Syntax.FG.GTKrc :cal SetSyn("gtkrc")<CR>
an 50.50.100 &Syntax.HIJK.Haml :cal SetSyn("haml")<CR>
an 50.50.110 &Syntax.HIJK.Hamster :cal SetSyn("hamster")<CR>
an 50.50.120 &Syntax.HIJK.Haskell.Haskell :cal SetSyn("haskell")<CR>
@@ -240,72 +252,78 @@ an 50.50.220 &Syntax.HIJK.HTML.HTML\ with\ M4 :cal SetSyn("htmlm4")<CR>
an 50.50.230 &Syntax.HIJK.HTML.HTML\ with\ Ruby\ (eRuby) :cal SetSyn("eruby")<CR>
an 50.50.240 &Syntax.HIJK.HTML.Cheetah\ HTML\ template :cal SetSyn("htmlcheetah")<CR>
an 50.50.250 &Syntax.HIJK.HTML.Django\ HTML\ template :cal SetSyn("htmldjango")<CR>
-an 50.50.260 &Syntax.HIJK.HTML.HTML/OS :cal SetSyn("htmlos")<CR>
-an 50.50.270 &Syntax.HIJK.HTML.XHTML :cal SetSyn("xhtml")<CR>
-an 50.50.280 &Syntax.HIJK.Host\.conf :cal SetSyn("hostconf")<CR>
-an 50.50.290 &Syntax.HIJK.Hosts\ access :cal SetSyn("hostsaccess")<CR>
-an 50.50.300 &Syntax.HIJK.Hyper\ Builder :cal SetSyn("hb")<CR>
-an 50.50.320 &Syntax.HIJK.Icewm\ menu :cal SetSyn("icemenu")<CR>
-an 50.50.330 &Syntax.HIJK.Icon :cal SetSyn("icon")<CR>
-an 50.50.340 &Syntax.HIJK.IDL\Generic\ IDL :cal SetSyn("idl")<CR>
-an 50.50.350 &Syntax.HIJK.IDL\Microsoft\ IDL :cal SetSyn("msidl")<CR>
-an 50.50.360 &Syntax.HIJK.Indent\ profile :cal SetSyn("indent")<CR>
-an 50.50.370 &Syntax.HIJK.Inform :cal SetSyn("inform")<CR>
-an 50.50.380 &Syntax.HIJK.Informix\ 4GL :cal SetSyn("fgl")<CR>
-an 50.50.390 &Syntax.HIJK.Initng :cal SetSyn("initng")<CR>
-an 50.50.400 &Syntax.HIJK.Inittab :cal SetSyn("inittab")<CR>
-an 50.50.410 &Syntax.HIJK.Inno\ setup :cal SetSyn("iss")<CR>
-an 50.50.420 &Syntax.HIJK.Innovation\ Data\ Processing.Upstream\ dat :cal SetSyn("upstreamdat")<CR>
-an 50.50.430 &Syntax.HIJK.Innovation\ Data\ Processing.Upstream\ log :cal SetSyn("upstreamlog")<CR>
-an 50.50.440 &Syntax.HIJK.Innovation\ Data\ Processing.Upstream\ Install\ log :cal SetSyn("upstreaminstalllog")<CR>
-an 50.50.450 &Syntax.HIJK.Innovation\ Data\ Processing.Usserver\ log :cal SetSyn("usserverlog")<CR>
-an 50.50.460 &Syntax.HIJK.Innovation\ Data\ Processing.USW2KAgt\ log :cal SetSyn("usw2kagtlog")<CR>
-an 50.50.470 &Syntax.HIJK.InstallShield\ script :cal SetSyn("ishd")<CR>
-an 50.50.480 &Syntax.HIJK.Interactive\ Data\ Lang :cal SetSyn("idlang")<CR>
-an 50.50.490 &Syntax.HIJK.IPfilter :cal SetSyn("ipfilter")<CR>
-an 50.50.510 &Syntax.HIJK.JAL :cal SetSyn("jal")<CR>
-an 50.50.520 &Syntax.HIJK.JAM :cal SetSyn("jam")<CR>
-an 50.50.530 &Syntax.HIJK.Jargon :cal SetSyn("jargon")<CR>
-an 50.50.540 &Syntax.HIJK.Java.Java :cal SetSyn("java")<CR>
-an 50.50.550 &Syntax.HIJK.Java.JavaCC :cal SetSyn("javacc")<CR>
-an 50.50.560 &Syntax.HIJK.Java.Java\ Server\ Pages :cal SetSyn("jsp")<CR>
-an 50.50.570 &Syntax.HIJK.Java.Java\ Properties :cal SetSyn("jproperties")<CR>
-an 50.50.580 &Syntax.HIJK.JavaScript :cal SetSyn("javascript")<CR>
-an 50.50.590 &Syntax.HIJK.Jess :cal SetSyn("jess")<CR>
-an 50.50.600 &Syntax.HIJK.Jgraph :cal SetSyn("jgraph")<CR>
-an 50.50.610 &Syntax.HIJK.Jovial :cal SetSyn("jovial")<CR>
-an 50.50.630 &Syntax.HIJK.Kconfig :cal SetSyn("kconfig")<CR>
-an 50.50.640 &Syntax.HIJK.KDE\ script :cal SetSyn("kscript")<CR>
-an 50.50.650 &Syntax.HIJK.Kimwitu++ :cal SetSyn("kwt")<CR>
-an 50.50.660 &Syntax.HIJK.KixTart :cal SetSyn("kix")<CR>
+an 50.50.260 &Syntax.HIJK.HTML.Vue.js\ HTML\ template :cal SetSyn("vuejs")<CR>
+an 50.50.270 &Syntax.HIJK.HTML.HTML/OS :cal SetSyn("htmlos")<CR>
+an 50.50.280 &Syntax.HIJK.HTML.XHTML :cal SetSyn("xhtml")<CR>
+an 50.50.290 &Syntax.HIJK.Host\.conf :cal SetSyn("hostconf")<CR>
+an 50.50.300 &Syntax.HIJK.Hosts\ access :cal SetSyn("hostsaccess")<CR>
+an 50.50.310 &Syntax.HIJK.Hyper\ Builder :cal SetSyn("hb")<CR>
+an 50.50.330 &Syntax.HIJK.Icewm\ menu :cal SetSyn("icemenu")<CR>
+an 50.50.340 &Syntax.HIJK.Icon :cal SetSyn("icon")<CR>
+an 50.50.350 &Syntax.HIJK.IDL\Generic\ IDL :cal SetSyn("idl")<CR>
+an 50.50.360 &Syntax.HIJK.IDL\Microsoft\ IDL :cal SetSyn("msidl")<CR>
+an 50.50.370 &Syntax.HIJK.Indent\ profile :cal SetSyn("indent")<CR>
+an 50.50.380 &Syntax.HIJK.Inform :cal SetSyn("inform")<CR>
+an 50.50.390 &Syntax.HIJK.Informix\ 4GL :cal SetSyn("fgl")<CR>
+an 50.50.400 &Syntax.HIJK.Initng :cal SetSyn("initng")<CR>
+an 50.50.410 &Syntax.HIJK.Inittab :cal SetSyn("inittab")<CR>
+an 50.50.420 &Syntax.HIJK.Inno\ setup :cal SetSyn("iss")<CR>
+an 50.50.430 &Syntax.HIJK.Innovation\ Data\ Processing.Upstream\ dat :cal SetSyn("upstreamdat")<CR>
+an 50.50.440 &Syntax.HIJK.Innovation\ Data\ Processing.Upstream\ log :cal SetSyn("upstreamlog")<CR>
+an 50.50.450 &Syntax.HIJK.Innovation\ Data\ Processing.Upstream\ rpt :cal SetSyn("upstreamrpt")<CR>
+an 50.50.460 &Syntax.HIJK.Innovation\ Data\ Processing.Upstream\ Install\ log :cal SetSyn("upstreaminstalllog")<CR>
+an 50.50.470 &Syntax.HIJK.Innovation\ Data\ Processing.Usserver\ log :cal SetSyn("usserverlog")<CR>
+an 50.50.480 &Syntax.HIJK.Innovation\ Data\ Processing.USW2KAgt\ log :cal SetSyn("usw2kagtlog")<CR>
+an 50.50.490 &Syntax.HIJK.InstallShield\ script :cal SetSyn("ishd")<CR>
+an 50.50.500 &Syntax.HIJK.Interactive\ Data\ Lang :cal SetSyn("idlang")<CR>
+an 50.50.510 &Syntax.HIJK.IPfilter :cal SetSyn("ipfilter")<CR>
+an 50.50.530 &Syntax.HIJK.J :cal SetSyn("j")<CR>
+an 50.50.540 &Syntax.HIJK.JAL :cal SetSyn("jal")<CR>
+an 50.50.550 &Syntax.HIJK.JAM :cal SetSyn("jam")<CR>
+an 50.50.560 &Syntax.HIJK.Jargon :cal SetSyn("jargon")<CR>
+an 50.50.570 &Syntax.HIJK.Java.Java :cal SetSyn("java")<CR>
+an 50.50.580 &Syntax.HIJK.Java.JavaCC :cal SetSyn("javacc")<CR>
+an 50.50.590 &Syntax.HIJK.Java.Java\ Server\ Pages :cal SetSyn("jsp")<CR>
+an 50.50.600 &Syntax.HIJK.Java.Java\ Properties :cal SetSyn("jproperties")<CR>
+an 50.50.610 &Syntax.HIJK.JavaScript :cal SetSyn("javascript")<CR>
+an 50.50.620 &Syntax.HIJK.Jess :cal SetSyn("jess")<CR>
+an 50.50.630 &Syntax.HIJK.Jgraph :cal SetSyn("jgraph")<CR>
+an 50.50.640 &Syntax.HIJK.Jovial :cal SetSyn("jovial")<CR>
+an 50.50.650 &Syntax.HIJK.JSON :cal SetSyn("json")<CR>
+an 50.50.670 &Syntax.HIJK.Kconfig :cal SetSyn("kconfig")<CR>
+an 50.50.680 &Syntax.HIJK.KDE\ script :cal SetSyn("kscript")<CR>
+an 50.50.690 &Syntax.HIJK.Kimwitu++ :cal SetSyn("kwt")<CR>
+an 50.50.700 &Syntax.HIJK.Kivy :cal SetSyn("kivy")<CR>
+an 50.50.710 &Syntax.HIJK.KixTart :cal SetSyn("kix")<CR>
an 50.60.100 &Syntax.L.Lace :cal SetSyn("lace")<CR>
an 50.60.110 &Syntax.L.LamdaProlog :cal SetSyn("lprolog")<CR>
an 50.60.120 &Syntax.L.Latte :cal SetSyn("latte")<CR>
an 50.60.130 &Syntax.L.Ld\ script :cal SetSyn("ld")<CR>
an 50.60.140 &Syntax.L.LDAP.LDIF :cal SetSyn("ldif")<CR>
an 50.60.150 &Syntax.L.LDAP.Configuration :cal SetSyn("ldapconf")<CR>
-an 50.60.160 &Syntax.L.Lex :cal SetSyn("lex")<CR>
-an 50.60.170 &Syntax.L.LFTP\ config :cal SetSyn("lftp")<CR>
-an 50.60.180 &Syntax.L.Libao :cal SetSyn("libao")<CR>
-an 50.60.190 &Syntax.L.LifeLines\ script :cal SetSyn("lifelines")<CR>
-an 50.60.200 &Syntax.L.Lilo :cal SetSyn("lilo")<CR>
-an 50.60.210 &Syntax.L.Limits\ config :cal SetSyn("limits")<CR>
-an 50.60.220 &Syntax.L.Linden\ scripting :cal SetSyn("lsl")<CR>
-an 50.60.230 &Syntax.L.Liquid :cal SetSyn("liquid")<CR>
-an 50.60.240 &Syntax.L.Lisp :cal SetSyn("lisp")<CR>
-an 50.60.250 &Syntax.L.Lite :cal SetSyn("lite")<CR>
-an 50.60.260 &Syntax.L.LiteStep\ RC :cal SetSyn("litestep")<CR>
-an 50.60.270 &Syntax.L.Locale\ Input :cal SetSyn("fdcc")<CR>
-an 50.60.280 &Syntax.L.Login\.access :cal SetSyn("loginaccess")<CR>
-an 50.60.290 &Syntax.L.Login\.defs :cal SetSyn("logindefs")<CR>
-an 50.60.300 &Syntax.L.Logtalk :cal SetSyn("logtalk")<CR>
-an 50.60.310 &Syntax.L.LOTOS :cal SetSyn("lotos")<CR>
-an 50.60.320 &Syntax.L.LotusScript :cal SetSyn("lscript")<CR>
-an 50.60.330 &Syntax.L.Lout :cal SetSyn("lout")<CR>
-an 50.60.340 &Syntax.L.LPC :cal SetSyn("lpc")<CR>
-an 50.60.350 &Syntax.L.Lua :cal SetSyn("lua")<CR>
-an 50.60.360 &Syntax.L.Lynx\ Style :cal SetSyn("lss")<CR>
-an 50.60.370 &Syntax.L.Lynx\ config :cal SetSyn("lynx")<CR>
+an 50.60.160 &Syntax.L.Less :cal SetSyn("less")<CR>
+an 50.60.170 &Syntax.L.Lex :cal SetSyn("lex")<CR>
+an 50.60.180 &Syntax.L.LFTP\ config :cal SetSyn("lftp")<CR>
+an 50.60.190 &Syntax.L.Libao :cal SetSyn("libao")<CR>
+an 50.60.200 &Syntax.L.LifeLines\ script :cal SetSyn("lifelines")<CR>
+an 50.60.210 &Syntax.L.Lilo :cal SetSyn("lilo")<CR>
+an 50.60.220 &Syntax.L.Limits\ config :cal SetSyn("limits")<CR>
+an 50.60.230 &Syntax.L.Linden\ scripting :cal SetSyn("lsl")<CR>
+an 50.60.240 &Syntax.L.Liquid :cal SetSyn("liquid")<CR>
+an 50.60.250 &Syntax.L.Lisp :cal SetSyn("lisp")<CR>
+an 50.60.260 &Syntax.L.Lite :cal SetSyn("lite")<CR>
+an 50.60.270 &Syntax.L.LiteStep\ RC :cal SetSyn("litestep")<CR>
+an 50.60.280 &Syntax.L.Locale\ Input :cal SetSyn("fdcc")<CR>
+an 50.60.290 &Syntax.L.Login\.access :cal SetSyn("loginaccess")<CR>
+an 50.60.300 &Syntax.L.Login\.defs :cal SetSyn("logindefs")<CR>
+an 50.60.310 &Syntax.L.Logtalk :cal SetSyn("logtalk")<CR>
+an 50.60.320 &Syntax.L.LOTOS :cal SetSyn("lotos")<CR>
+an 50.60.330 &Syntax.L.LotusScript :cal SetSyn("lscript")<CR>
+an 50.60.340 &Syntax.L.Lout :cal SetSyn("lout")<CR>
+an 50.60.350 &Syntax.L.LPC :cal SetSyn("lpc")<CR>
+an 50.60.360 &Syntax.L.Lua :cal SetSyn("lua")<CR>
+an 50.60.370 &Syntax.L.Lynx\ Style :cal SetSyn("lss")<CR>
+an 50.60.380 &Syntax.L.Lynx\ config :cal SetSyn("lynx")<CR>
an 50.70.100 &Syntax.M.M4 :cal SetSyn("m4")<CR>
an 50.70.110 &Syntax.M.MaGic\ Point :cal SetSyn("mgp")<CR>
an 50.70.120 &Syntax.M.Mail :cal SetSyn("mail")<CR>
@@ -318,55 +336,60 @@ an 50.70.180 &Syntax.M.Man\ page :cal SetSyn("man")<CR>
an 50.70.190 &Syntax.M.Man\.conf :cal SetSyn("manconf")<CR>
an 50.70.200 &Syntax.M.Maple\ V :cal SetSyn("maple")<CR>
an 50.70.210 &Syntax.M.Markdown :cal SetSyn("markdown")<CR>
-an 50.70.220 &Syntax.M.Mason :cal SetSyn("mason")<CR>
-an 50.70.230 &Syntax.M.Mathematica :cal SetSyn("mma")<CR>
-an 50.70.240 &Syntax.M.Matlab :cal SetSyn("matlab")<CR>
-an 50.70.250 &Syntax.M.Maxima :cal SetSyn("maxima")<CR>
-an 50.70.260 &Syntax.M.MEL\ (for\ Maya) :cal SetSyn("mel")<CR>
-an 50.70.270 &Syntax.M.Messages\ (/var/log) :cal SetSyn("messages")<CR>
-an 50.70.280 &Syntax.M.Metafont :cal SetSyn("mf")<CR>
-an 50.70.290 &Syntax.M.MetaPost :cal SetSyn("mp")<CR>
-an 50.70.300 &Syntax.M.MGL :cal SetSyn("mgl")<CR>
-an 50.70.310 &Syntax.M.MMIX :cal SetSyn("mmix")<CR>
-an 50.70.320 &Syntax.M.Modconf :cal SetSyn("modconf")<CR>
-an 50.70.330 &Syntax.M.Model :cal SetSyn("model")<CR>
-an 50.70.340 &Syntax.M.Modsim\ III :cal SetSyn("modsim3")<CR>
-an 50.70.350 &Syntax.M.Modula\ 2 :cal SetSyn("modula2")<CR>
-an 50.70.360 &Syntax.M.Modula\ 3 :cal SetSyn("modula3")<CR>
-an 50.70.370 &Syntax.M.Monk :cal SetSyn("monk")<CR>
-an 50.70.380 &Syntax.M.Mplayer\ config :cal SetSyn("mplayerconf")<CR>
-an 50.70.390 &Syntax.M.MOO :cal SetSyn("moo")<CR>
-an 50.70.400 &Syntax.M.Mrxvtrc :cal SetSyn("mrxvtrc")<CR>
-an 50.70.410 &Syntax.M.MS-DOS/Windows.4DOS\ \.bat\ file :cal SetSyn("btm")<CR>
-an 50.70.420 &Syntax.M.MS-DOS/Windows.\.bat\/\.cmd\ file :cal SetSyn("dosbatch")<CR>
-an 50.70.430 &Syntax.M.MS-DOS/Windows.\.ini\ file :cal SetSyn("dosini")<CR>
-an 50.70.440 &Syntax.M.MS-DOS/Windows.Message\ text :cal SetSyn("msmessages")<CR>
-an 50.70.450 &Syntax.M.MS-DOS/Windows.Module\ Definition :cal SetSyn("def")<CR>
-an 50.70.460 &Syntax.M.MS-DOS/Windows.Registry :cal SetSyn("registry")<CR>
-an 50.70.470 &Syntax.M.MS-DOS/Windows.Resource\ file :cal SetSyn("rc")<CR>
-an 50.70.480 &Syntax.M.Msql :cal SetSyn("msql")<CR>
-an 50.70.490 &Syntax.M.MuPAD :cal SetSyn("mupad")<CR>
-an 50.70.500 &Syntax.M.MUSHcode :cal SetSyn("mush")<CR>
-an 50.70.510 &Syntax.M.Muttrc :cal SetSyn("muttrc")<CR>
-an 50.80.100 &Syntax.NO.Nanorc :cal SetSyn("nanorc")<CR>
-an 50.80.110 &Syntax.NO.Nastran\ input/DMAP :cal SetSyn("nastran")<CR>
-an 50.80.120 &Syntax.NO.Natural :cal SetSyn("natural")<CR>
-an 50.80.130 &Syntax.NO.Neomuttrc :cal SetSyn("neomuttrc")<CR>
-an 50.80.140 &Syntax.NO.Netrc :cal SetSyn("netrc")<CR>
-an 50.80.150 &Syntax.NO.Ninja :cal SetSyn("ninja")<CR>
-an 50.80.160 &Syntax.NO.Novell\ NCF\ batch :cal SetSyn("ncf")<CR>
-an 50.80.170 &Syntax.NO.Not\ Quite\ C\ (LEGO) :cal SetSyn("nqc")<CR>
-an 50.80.180 &Syntax.NO.Nroff :cal SetSyn("nroff")<CR>
-an 50.80.190 &Syntax.NO.NSIS\ script :cal SetSyn("nsis")<CR>
-an 50.80.200 &Syntax.NO.Obj\ 3D\ wavefront :cal SetSyn("obj")<CR>
-an 50.80.210 &Syntax.NO.Objective\ C :cal SetSyn("objc")<CR>
-an 50.80.220 &Syntax.NO.Objective\ C++ :cal SetSyn("objcpp")<CR>
-an 50.80.230 &Syntax.NO.OCAML :cal SetSyn("ocaml")<CR>
-an 50.80.240 &Syntax.NO.Occam :cal SetSyn("occam")<CR>
-an 50.80.250 &Syntax.NO.Omnimark :cal SetSyn("omnimark")<CR>
-an 50.80.260 &Syntax.NO.OpenROAD :cal SetSyn("openroad")<CR>
-an 50.80.270 &Syntax.NO.Open\ Psion\ Lang :cal SetSyn("opl")<CR>
-an 50.80.280 &Syntax.NO.Oracle\ config :cal SetSyn("ora")<CR>
+an 50.70.220 &Syntax.M.Markdown\ with\ R\ statements :cal SetSyn("rmd")<CR>
+an 50.70.230 &Syntax.M.Mason :cal SetSyn("mason")<CR>
+an 50.70.240 &Syntax.M.Mathematica :cal SetSyn("mma")<CR>
+an 50.70.250 &Syntax.M.Matlab :cal SetSyn("matlab")<CR>
+an 50.70.260 &Syntax.M.Maxima :cal SetSyn("maxima")<CR>
+an 50.70.270 &Syntax.M.MEL\ (for\ Maya) :cal SetSyn("mel")<CR>
+an 50.70.280 &Syntax.M.Messages\ (/var/log) :cal SetSyn("messages")<CR>
+an 50.70.290 &Syntax.M.Metafont :cal SetSyn("mf")<CR>
+an 50.70.300 &Syntax.M.MetaPost :cal SetSyn("mp")<CR>
+an 50.70.310 &Syntax.M.MGL :cal SetSyn("mgl")<CR>
+an 50.70.320 &Syntax.M.MIX :cal SetSyn("mix")<CR>
+an 50.70.330 &Syntax.M.MMIX :cal SetSyn("mmix")<CR>
+an 50.70.340 &Syntax.M.Modconf :cal SetSyn("modconf")<CR>
+an 50.70.350 &Syntax.M.Model :cal SetSyn("model")<CR>
+an 50.70.360 &Syntax.M.Modsim\ III :cal SetSyn("modsim3")<CR>
+an 50.70.370 &Syntax.M.Modula\ 2 :cal SetSyn("modula2")<CR>
+an 50.70.380 &Syntax.M.Modula\ 3 :cal SetSyn("modula3")<CR>
+an 50.70.390 &Syntax.M.Monk :cal SetSyn("monk")<CR>
+an 50.70.400 &Syntax.M.Motorola\ S-Record :cal SetSyn("srec")<CR>
+an 50.70.410 &Syntax.M.Mplayer\ config :cal SetSyn("mplayerconf")<CR>
+an 50.70.420 &Syntax.M.MOO :cal SetSyn("moo")<CR>
+an 50.70.430 &Syntax.M.Mrxvtrc :cal SetSyn("mrxvtrc")<CR>
+an 50.70.440 &Syntax.M.MS-DOS/Windows.4DOS\ \.bat\ file :cal SetSyn("btm")<CR>
+an 50.70.450 &Syntax.M.MS-DOS/Windows.\.bat\/\.cmd\ file :cal SetSyn("dosbatch")<CR>
+an 50.70.460 &Syntax.M.MS-DOS/Windows.\.ini\ file :cal SetSyn("dosini")<CR>
+an 50.70.470 &Syntax.M.MS-DOS/Windows.Message\ text :cal SetSyn("msmessages")<CR>
+an 50.70.480 &Syntax.M.MS-DOS/Windows.Module\ Definition :cal SetSyn("def")<CR>
+an 50.70.490 &Syntax.M.MS-DOS/Windows.Registry :cal SetSyn("registry")<CR>
+an 50.70.500 &Syntax.M.MS-DOS/Windows.Resource\ file :cal SetSyn("rc")<CR>
+an 50.70.510 &Syntax.M.Msql :cal SetSyn("msql")<CR>
+an 50.70.520 &Syntax.M.MuPAD :cal SetSyn("mupad")<CR>
+an 50.70.530 &Syntax.M.Murphi :cal SetSyn("murphi")<CR>
+an 50.70.540 &Syntax.M.MUSHcode :cal SetSyn("mush")<CR>
+an 50.70.550 &Syntax.M.Muttrc :cal SetSyn("muttrc")<CR>
+an 50.80.100 &Syntax.NO.N1QL :cal SetSyn("n1ql")<CR>
+an 50.80.110 &Syntax.NO.Nanorc :cal SetSyn("nanorc")<CR>
+an 50.80.120 &Syntax.NO.Nastran\ input/DMAP :cal SetSyn("nastran")<CR>
+an 50.80.130 &Syntax.NO.Natural :cal SetSyn("natural")<CR>
+an 50.80.140 &Syntax.NO.NeoMutt\ setup\ files :cal SetSyn("neomuttrc")<CR>
+an 50.80.150 &Syntax.NO.Netrc :cal SetSyn("netrc")<CR>
+an 50.80.160 &Syntax.NO.Ninja :cal SetSyn("ninja")<CR>
+an 50.80.170 &Syntax.NO.Novell\ NCF\ batch :cal SetSyn("ncf")<CR>
+an 50.80.180 &Syntax.NO.Not\ Quite\ C\ (LEGO) :cal SetSyn("nqc")<CR>
+an 50.80.190 &Syntax.NO.Nroff :cal SetSyn("nroff")<CR>
+an 50.80.200 &Syntax.NO.NSIS\ script :cal SetSyn("nsis")<CR>
+an 50.80.220 &Syntax.NO.Obj\ 3D\ wavefront :cal SetSyn("obj")<CR>
+an 50.80.230 &Syntax.NO.Objective\ C :cal SetSyn("objc")<CR>
+an 50.80.240 &Syntax.NO.Objective\ C++ :cal SetSyn("objcpp")<CR>
+an 50.80.250 &Syntax.NO.OCAML :cal SetSyn("ocaml")<CR>
+an 50.80.260 &Syntax.NO.Occam :cal SetSyn("occam")<CR>
+an 50.80.270 &Syntax.NO.Omnimark :cal SetSyn("omnimark")<CR>
+an 50.80.280 &Syntax.NO.OpenROAD :cal SetSyn("openroad")<CR>
+an 50.80.290 &Syntax.NO.Open\ Psion\ Lang :cal SetSyn("opl")<CR>
+an 50.80.300 &Syntax.NO.Oracle\ config :cal SetSyn("ora")<CR>
an 50.90.100 &Syntax.PQ.Packet\ filter\ conf :cal SetSyn("pf")<CR>
an 50.90.110 &Syntax.PQ.Palm\ resource\ compiler :cal SetSyn("pilrc")<CR>
an 50.90.120 &Syntax.PQ.Pam\ config :cal SetSyn("pamconf")<CR>
@@ -437,168 +460,178 @@ an 50.100.300 &Syntax.R.RockLinux\ package\ desc\. :cal SetSyn("desc")<CR>
an 50.100.310 &Syntax.R.Rpcgen :cal SetSyn("rpcgen")<CR>
an 50.100.320 &Syntax.R.RPL/2 :cal SetSyn("rpl")<CR>
an 50.100.330 &Syntax.R.ReStructuredText :cal SetSyn("rst")<CR>
-an 50.100.340 &Syntax.R.RTF :cal SetSyn("rtf")<CR>
-an 50.100.350 &Syntax.R.Ruby :cal SetSyn("ruby")<CR>
-an 50.110.100 &Syntax.S-Sm.S-Lang :cal SetSyn("slang")<CR>
-an 50.110.110 &Syntax.S-Sm.Samba\ config :cal SetSyn("samba")<CR>
-an 50.110.120 &Syntax.S-Sm.SAS :cal SetSyn("sas")<CR>
-an 50.110.130 &Syntax.S-Sm.Sass :cal SetSyn("sass")<CR>
-an 50.110.140 &Syntax.S-Sm.Sather :cal SetSyn("sather")<CR>
-an 50.110.150 &Syntax.S-Sm.Scheme :cal SetSyn("scheme")<CR>
-an 50.110.160 &Syntax.S-Sm.Scilab :cal SetSyn("scilab")<CR>
-an 50.110.170 &Syntax.S-Sm.Screen\ RC :cal SetSyn("screen")<CR>
-an 50.110.180 &Syntax.S-Sm.SCSS :cal SetSyn("scss")<CR>
-an 50.110.190 &Syntax.S-Sm.SDC\ Synopsys\ Design\ Constraints :cal SetSyn("sdc")<CR>
-an 50.110.200 &Syntax.S-Sm.SDL :cal SetSyn("sdl")<CR>
-an 50.110.210 &Syntax.S-Sm.Sed :cal SetSyn("sed")<CR>
-an 50.110.220 &Syntax.S-Sm.Sendmail\.cf :cal SetSyn("sm")<CR>
-an 50.110.230 &Syntax.S-Sm.Send-pr :cal SetSyn("sendpr")<CR>
-an 50.110.240 &Syntax.S-Sm.Sensors\.conf :cal SetSyn("sensors")<CR>
-an 50.110.250 &Syntax.S-Sm.Service\ Location\ config :cal SetSyn("slpconf")<CR>
-an 50.110.260 &Syntax.S-Sm.Service\ Location\ registration :cal SetSyn("slpreg")<CR>
-an 50.110.270 &Syntax.S-Sm.Service\ Location\ SPI :cal SetSyn("slpspi")<CR>
-an 50.110.280 &Syntax.S-Sm.Services :cal SetSyn("services")<CR>
-an 50.110.290 &Syntax.S-Sm.Setserial\ config :cal SetSyn("setserial")<CR>
-an 50.110.300 &Syntax.S-Sm.SGML.SGML\ catalog :cal SetSyn("catalog")<CR>
-an 50.110.310 &Syntax.S-Sm.SGML.SGML\ DTD :cal SetSyn("sgml")<CR>
-an 50.110.320 &Syntax.S-Sm.SGML.SGML\ Declaration :cal SetSyn("sgmldecl")<CR>
-an 50.110.330 &Syntax.S-Sm.SGML.SGML-linuxdoc :cal SetSyn("sgmllnx")<CR>
-an 50.110.340 &Syntax.S-Sm.Shell\ script.sh\ and\ ksh :cal SetSyn("sh")<CR>
-an 50.110.350 &Syntax.S-Sm.Shell\ script.csh :cal SetSyn("csh")<CR>
-an 50.110.360 &Syntax.S-Sm.Shell\ script.tcsh :cal SetSyn("tcsh")<CR>
-an 50.110.370 &Syntax.S-Sm.Shell\ script.zsh :cal SetSyn("zsh")<CR>
-an 50.110.380 &Syntax.S-Sm.SiCAD :cal SetSyn("sicad")<CR>
-an 50.110.390 &Syntax.S-Sm.Sieve :cal SetSyn("sieve")<CR>
-an 50.110.400 &Syntax.S-Sm.Simula :cal SetSyn("simula")<CR>
-an 50.110.410 &Syntax.S-Sm.Sinda.Sinda\ compare :cal SetSyn("sindacmp")<CR>
-an 50.110.420 &Syntax.S-Sm.Sinda.Sinda\ input :cal SetSyn("sinda")<CR>
-an 50.110.430 &Syntax.S-Sm.Sinda.Sinda\ output :cal SetSyn("sindaout")<CR>
-an 50.110.440 &Syntax.S-Sm.SiSU :cal SetSyn("sisu")<CR>
-an 50.110.450 &Syntax.S-Sm.SKILL.SKILL :cal SetSyn("skill")<CR>
-an 50.110.460 &Syntax.S-Sm.SKILL.SKILL\ for\ Diva :cal SetSyn("diva")<CR>
-an 50.110.470 &Syntax.S-Sm.Slice :cal SetSyn("slice")<CR>
-an 50.110.480 &Syntax.S-Sm.SLRN.Slrn\ rc :cal SetSyn("slrnrc")<CR>
-an 50.110.490 &Syntax.S-Sm.SLRN.Slrn\ score :cal SetSyn("slrnsc")<CR>
-an 50.110.500 &Syntax.S-Sm.SmallTalk :cal SetSyn("st")<CR>
-an 50.110.510 &Syntax.S-Sm.Smarty\ Templates :cal SetSyn("smarty")<CR>
-an 50.110.520 &Syntax.S-Sm.SMIL :cal SetSyn("smil")<CR>
-an 50.110.530 &Syntax.S-Sm.SMITH :cal SetSyn("smith")<CR>
-an 50.120.100 &Syntax.Sn-Sy.SNMP\ MIB :cal SetSyn("mib")<CR>
-an 50.120.110 &Syntax.Sn-Sy.SNNS.SNNS\ network :cal SetSyn("snnsnet")<CR>
-an 50.120.120 &Syntax.Sn-Sy.SNNS.SNNS\ pattern :cal SetSyn("snnspat")<CR>
-an 50.120.130 &Syntax.Sn-Sy.SNNS.SNNS\ result :cal SetSyn("snnsres")<CR>
-an 50.120.140 &Syntax.Sn-Sy.Snobol4 :cal SetSyn("snobol4")<CR>
-an 50.120.150 &Syntax.Sn-Sy.Snort\ Configuration :cal SetSyn("hog")<CR>
-an 50.120.160 &Syntax.Sn-Sy.SPEC\ (Linux\ RPM) :cal SetSyn("spec")<CR>
-an 50.120.170 &Syntax.Sn-Sy.Specman :cal SetSyn("specman")<CR>
-an 50.120.180 &Syntax.Sn-Sy.Spice :cal SetSyn("spice")<CR>
-an 50.120.190 &Syntax.Sn-Sy.Spyce :cal SetSyn("spyce")<CR>
-an 50.120.200 &Syntax.Sn-Sy.Speedup :cal SetSyn("spup")<CR>
-an 50.120.210 &Syntax.Sn-Sy.Splint :cal SetSyn("splint")<CR>
-an 50.120.220 &Syntax.Sn-Sy.Squid\ config :cal SetSyn("squid")<CR>
-an 50.120.230 &Syntax.Sn-Sy.SQL.SAP\ HANA :cal SetSyn("sqlhana")<CR>
-an 50.120.240 &Syntax.Sn-Sy.SQL.ESQL-C :cal SetSyn("esqlc")<CR>
-an 50.120.250 &Syntax.Sn-Sy.SQL.MySQL :cal SetSyn("mysql")<CR>
-an 50.120.260 &Syntax.Sn-Sy.SQL.PL/SQL :cal SetSyn("plsql")<CR>
-an 50.120.270 &Syntax.Sn-Sy.SQL.SQL\ Anywhere :cal SetSyn("sqlanywhere")<CR>
-an 50.120.280 &Syntax.Sn-Sy.SQL.SQL\ (automatic) :cal SetSyn("sql")<CR>
-an 50.120.290 &Syntax.Sn-Sy.SQL.SQL\ (Oracle) :cal SetSyn("sqloracle")<CR>
-an 50.120.300 &Syntax.Sn-Sy.SQL.SQL\ Forms :cal SetSyn("sqlforms")<CR>
-an 50.120.310 &Syntax.Sn-Sy.SQL.SQLJ :cal SetSyn("sqlj")<CR>
-an 50.120.320 &Syntax.Sn-Sy.SQL.SQL-Informix :cal SetSyn("sqlinformix")<CR>
-an 50.120.330 &Syntax.Sn-Sy.SQR :cal SetSyn("sqr")<CR>
-an 50.120.340 &Syntax.Sn-Sy.Ssh.ssh_config :cal SetSyn("sshconfig")<CR>
-an 50.120.350 &Syntax.Sn-Sy.Ssh.sshd_config :cal SetSyn("sshdconfig")<CR>
-an 50.120.360 &Syntax.Sn-Sy.Standard\ ML :cal SetSyn("sml")<CR>
-an 50.120.370 &Syntax.Sn-Sy.Stata.SMCL :cal SetSyn("smcl")<CR>
-an 50.120.380 &Syntax.Sn-Sy.Stata.Stata :cal SetSyn("stata")<CR>
-an 50.120.390 &Syntax.Sn-Sy.Stored\ Procedures :cal SetSyn("stp")<CR>
-an 50.120.400 &Syntax.Sn-Sy.Strace :cal SetSyn("strace")<CR>
-an 50.120.410 &Syntax.Sn-Sy.Streaming\ descriptor\ file :cal SetSyn("sd")<CR>
-an 50.120.420 &Syntax.Sn-Sy.Subversion\ commit :cal SetSyn("svn")<CR>
-an 50.120.430 &Syntax.Sn-Sy.Sudoers :cal SetSyn("sudoers")<CR>
-an 50.120.440 &Syntax.Sn-Sy.SVG :cal SetSyn("svg")<CR>
-an 50.120.450 &Syntax.Sn-Sy.Symbian\ meta-makefile :cal SetSyn("mmp")<CR>
-an 50.120.460 &Syntax.Sn-Sy.Sysctl\.conf :cal SetSyn("sysctl")<CR>
-an 50.130.100 &Syntax.T.TADS :cal SetSyn("tads")<CR>
-an 50.130.110 &Syntax.T.Tags :cal SetSyn("tags")<CR>
-an 50.130.120 &Syntax.T.TAK.TAK\ compare :cal SetSyn("takcmp")<CR>
-an 50.130.130 &Syntax.T.TAK.TAK\ input :cal SetSyn("tak")<CR>
-an 50.130.140 &Syntax.T.TAK.TAK\ output :cal SetSyn("takout")<CR>
-an 50.130.150 &Syntax.T.Tar\ listing :cal SetSyn("tar")<CR>
-an 50.130.160 &Syntax.T.Task\ data :cal SetSyn("taskdata")<CR>
-an 50.130.170 &Syntax.T.Task\ 42\ edit :cal SetSyn("taskedit")<CR>
-an 50.130.180 &Syntax.T.Tcl/Tk :cal SetSyn("tcl")<CR>
-an 50.130.190 &Syntax.T.TealInfo :cal SetSyn("tli")<CR>
-an 50.130.200 &Syntax.T.Telix\ Salt :cal SetSyn("tsalt")<CR>
-an 50.130.210 &Syntax.T.Termcap/Printcap :cal SetSyn("ptcap")<CR>
-an 50.130.220 &Syntax.T.Terminfo :cal SetSyn("terminfo")<CR>
-an 50.130.230 &Syntax.T.TeX.TeX/LaTeX :cal SetSyn("tex")<CR>
-an 50.130.240 &Syntax.T.TeX.plain\ TeX :cal SetSyn("plaintex")<CR>
-an 50.130.250 &Syntax.T.TeX.Initex :cal SetSyn("initex")<CR>
-an 50.130.260 &Syntax.T.TeX.ConTeXt :cal SetSyn("context")<CR>
-an 50.130.270 &Syntax.T.TeX.TeX\ configuration :cal SetSyn("texmf")<CR>
-an 50.130.280 &Syntax.T.TeX.Texinfo :cal SetSyn("texinfo")<CR>
-an 50.130.290 &Syntax.T.TF\ mud\ client :cal SetSyn("tf")<CR>
-an 50.130.300 &Syntax.T.Tidy\ configuration :cal SetSyn("tidy")<CR>
-an 50.130.310 &Syntax.T.Tilde :cal SetSyn("tilde")<CR>
-an 50.130.320 &Syntax.T.TPP :cal SetSyn("tpp")<CR>
-an 50.130.330 &Syntax.T.Trasys\ input :cal SetSyn("trasys")<CR>
-an 50.130.340 &Syntax.T.Treetop :cal SetSyn("treetop")<CR>
-an 50.130.350 &Syntax.T.Trustees :cal SetSyn("trustees")<CR>
-an 50.130.360 &Syntax.T.TSS.Command\ Line :cal SetSyn("tsscl")<CR>
-an 50.130.370 &Syntax.T.TSS.Geometry :cal SetSyn("tssgm")<CR>
-an 50.130.380 &Syntax.T.TSS.Optics :cal SetSyn("tssop")<CR>
-an 50.140.100 &Syntax.UV.Udev\ config :cal SetSyn("udevconf")<CR>
-an 50.140.110 &Syntax.UV.Udev\ permissions :cal SetSyn("udevperm")<CR>
-an 50.140.120 &Syntax.UV.Udev\ rules :cal SetSyn("udevrules")<CR>
-an 50.140.130 &Syntax.UV.UIT/UIL :cal SetSyn("uil")<CR>
-an 50.140.140 &Syntax.UV.UnrealScript :cal SetSyn("uc")<CR>
-an 50.140.150 &Syntax.UV.Updatedb\.conf :cal SetSyn("updatedb")<CR>
-an 50.140.160 &Syntax.UV.Upstart :cal SetSyn("upstart")<CR>
-an 50.140.180 &Syntax.UV.Valgrind :cal SetSyn("valgrind")<CR>
-an 50.140.190 &Syntax.UV.Vera :cal SetSyn("vera")<CR>
-an 50.140.200 &Syntax.UV.Verilog-AMS\ HDL :cal SetSyn("verilogams")<CR>
-an 50.140.210 &Syntax.UV.Verilog\ HDL :cal SetSyn("verilog")<CR>
-an 50.140.220 &Syntax.UV.Vgrindefs :cal SetSyn("vgrindefs")<CR>
-an 50.140.230 &Syntax.UV.VHDL :cal SetSyn("vhdl")<CR>
-an 50.140.240 &Syntax.UV.Vim.Vim\ help\ file :cal SetSyn("help")<CR>
-an 50.140.250 &Syntax.UV.Vim.Vim\ script :cal SetSyn("vim")<CR>
-an 50.140.260 &Syntax.UV.Vim.Viminfo\ file :cal SetSyn("viminfo")<CR>
-an 50.140.270 &Syntax.UV.Virata\ config :cal SetSyn("virata")<CR>
-an 50.140.280 &Syntax.UV.Visual\ Basic :cal SetSyn("vb")<CR>
-an 50.140.290 &Syntax.UV.VOS\ CM\ macro :cal SetSyn("voscm")<CR>
-an 50.140.300 &Syntax.UV.VRML :cal SetSyn("vrml")<CR>
-an 50.140.310 &Syntax.UV.VSE\ JCL :cal SetSyn("vsejcl")<CR>
-an 50.150.100 &Syntax.WXYZ.WEB.CWEB :cal SetSyn("cweb")<CR>
-an 50.150.110 &Syntax.WXYZ.WEB.WEB :cal SetSyn("web")<CR>
-an 50.150.120 &Syntax.WXYZ.WEB.WEB\ Changes :cal SetSyn("change")<CR>
-an 50.150.130 &Syntax.WXYZ.Webmacro :cal SetSyn("webmacro")<CR>
-an 50.150.140 &Syntax.WXYZ.Website\ MetaLanguage :cal SetSyn("wml")<CR>
-an 50.150.160 &Syntax.WXYZ.wDiff :cal SetSyn("wdiff")<CR>
-an 50.150.180 &Syntax.WXYZ.Wget\ config :cal SetSyn("wget")<CR>
-an 50.150.190 &Syntax.WXYZ.Whitespace\ (add) :cal SetSyn("whitespace")<CR>
-an 50.150.200 &Syntax.WXYZ.WildPackets\ EtherPeek\ Decoder :cal SetSyn("dcd")<CR>
-an 50.150.210 &Syntax.WXYZ.WinBatch/Webbatch :cal SetSyn("winbatch")<CR>
-an 50.150.220 &Syntax.WXYZ.Windows\ Scripting\ Host :cal SetSyn("wsh")<CR>
-an 50.150.230 &Syntax.WXYZ.WSML :cal SetSyn("wsml")<CR>
-an 50.150.240 &Syntax.WXYZ.WvDial :cal SetSyn("wvdial")<CR>
-an 50.150.260 &Syntax.WXYZ.X\ Keyboard\ Extension :cal SetSyn("xkb")<CR>
-an 50.150.270 &Syntax.WXYZ.X\ Pixmap :cal SetSyn("xpm")<CR>
-an 50.150.280 &Syntax.WXYZ.X\ Pixmap\ (2) :cal SetSyn("xpm2")<CR>
-an 50.150.290 &Syntax.WXYZ.X\ resources :cal SetSyn("xdefaults")<CR>
-an 50.150.300 &Syntax.WXYZ.XBL :cal SetSyn("xbl")<CR>
-an 50.150.310 &Syntax.WXYZ.Xinetd\.conf :cal SetSyn("xinetd")<CR>
-an 50.150.320 &Syntax.WXYZ.Xmodmap :cal SetSyn("xmodmap")<CR>
-an 50.150.330 &Syntax.WXYZ.Xmath :cal SetSyn("xmath")<CR>
-an 50.150.340 &Syntax.WXYZ.XML :cal SetSyn("xml")<CR>
-an 50.150.350 &Syntax.WXYZ.XML\ Schema\ (XSD) :cal SetSyn("xsd")<CR>
-an 50.150.360 &Syntax.WXYZ.XQuery :cal SetSyn("xquery")<CR>
-an 50.150.370 &Syntax.WXYZ.Xslt :cal SetSyn("xslt")<CR>
-an 50.150.380 &Syntax.WXYZ.XFree86\ Config :cal SetSyn("xf86conf")<CR>
-an 50.150.400 &Syntax.WXYZ.YAML :cal SetSyn("yaml")<CR>
-an 50.150.410 &Syntax.WXYZ.Yacc :cal SetSyn("yacc")<CR>
-an 50.150.430 &Syntax.WXYZ.Zimbu :cal SetSyn("zimbu")<CR>
+an 50.110.100 &Syntax.M.ReStructuredText\ with\ R\ statements :cal SetSyn("rrst")<CR>
+an 50.120.100 &Syntax.R.RTF :cal SetSyn("rtf")<CR>
+an 50.120.110 &Syntax.R.Ruby :cal SetSyn("ruby")<CR>
+an 50.120.120 &Syntax.R.Rust :cal SetSyn("rust")<CR>
+an 50.130.100 &Syntax.S-Sm.S-Lang :cal SetSyn("slang")<CR>
+an 50.130.110 &Syntax.S-Sm.Samba\ config :cal SetSyn("samba")<CR>
+an 50.130.120 &Syntax.S-Sm.SAS :cal SetSyn("sas")<CR>
+an 50.130.130 &Syntax.S-Sm.Sass :cal SetSyn("sass")<CR>
+an 50.130.140 &Syntax.S-Sm.Sather :cal SetSyn("sather")<CR>
+an 50.130.150 &Syntax.S-Sm.Sbt :cal SetSyn("sbt")<CR>
+an 50.130.160 &Syntax.S-Sm.Scala :cal SetSyn("scala")<CR>
+an 50.130.170 &Syntax.S-Sm.Scheme :cal SetSyn("scheme")<CR>
+an 50.130.180 &Syntax.S-Sm.Scilab :cal SetSyn("scilab")<CR>
+an 50.130.190 &Syntax.S-Sm.Screen\ RC :cal SetSyn("screen")<CR>
+an 50.130.200 &Syntax.S-Sm.SCSS :cal SetSyn("scss")<CR>
+an 50.130.210 &Syntax.S-Sm.SDC\ Synopsys\ Design\ Constraints :cal SetSyn("sdc")<CR>
+an 50.130.220 &Syntax.S-Sm.SDL :cal SetSyn("sdl")<CR>
+an 50.130.230 &Syntax.S-Sm.Sed :cal SetSyn("sed")<CR>
+an 50.130.240 &Syntax.S-Sm.Sendmail\.cf :cal SetSyn("sm")<CR>
+an 50.130.250 &Syntax.S-Sm.Send-pr :cal SetSyn("sendpr")<CR>
+an 50.130.260 &Syntax.S-Sm.Sensors\.conf :cal SetSyn("sensors")<CR>
+an 50.130.270 &Syntax.S-Sm.Service\ Location\ config :cal SetSyn("slpconf")<CR>
+an 50.130.280 &Syntax.S-Sm.Service\ Location\ registration :cal SetSyn("slpreg")<CR>
+an 50.130.290 &Syntax.S-Sm.Service\ Location\ SPI :cal SetSyn("slpspi")<CR>
+an 50.130.300 &Syntax.S-Sm.Services :cal SetSyn("services")<CR>
+an 50.130.310 &Syntax.S-Sm.Setserial\ config :cal SetSyn("setserial")<CR>
+an 50.130.320 &Syntax.S-Sm.SGML.SGML\ catalog :cal SetSyn("catalog")<CR>
+an 50.130.330 &Syntax.S-Sm.SGML.SGML\ DTD :cal SetSyn("sgml")<CR>
+an 50.130.340 &Syntax.S-Sm.SGML.SGML\ Declaration :cal SetSyn("sgmldecl")<CR>
+an 50.130.350 &Syntax.S-Sm.SGML.SGML-linuxdoc :cal SetSyn("sgmllnx")<CR>
+an 50.130.360 &Syntax.S-Sm.Shell\ script.sh\ and\ ksh :cal SetSyn("sh")<CR>
+an 50.130.370 &Syntax.S-Sm.Shell\ script.csh :cal SetSyn("csh")<CR>
+an 50.130.380 &Syntax.S-Sm.Shell\ script.tcsh :cal SetSyn("tcsh")<CR>
+an 50.130.390 &Syntax.S-Sm.Shell\ script.zsh :cal SetSyn("zsh")<CR>
+an 50.130.400 &Syntax.S-Sm.SiCAD :cal SetSyn("sicad")<CR>
+an 50.130.410 &Syntax.S-Sm.Sieve :cal SetSyn("sieve")<CR>
+an 50.130.420 &Syntax.S-Sm.Simula :cal SetSyn("simula")<CR>
+an 50.130.430 &Syntax.S-Sm.Sinda.Sinda\ compare :cal SetSyn("sindacmp")<CR>
+an 50.130.440 &Syntax.S-Sm.Sinda.Sinda\ input :cal SetSyn("sinda")<CR>
+an 50.130.450 &Syntax.S-Sm.Sinda.Sinda\ output :cal SetSyn("sindaout")<CR>
+an 50.130.460 &Syntax.S-Sm.SiSU :cal SetSyn("sisu")<CR>
+an 50.130.470 &Syntax.S-Sm.SKILL.SKILL :cal SetSyn("skill")<CR>
+an 50.130.480 &Syntax.S-Sm.SKILL.SKILL\ for\ Diva :cal SetSyn("diva")<CR>
+an 50.130.490 &Syntax.S-Sm.Slice :cal SetSyn("slice")<CR>
+an 50.130.500 &Syntax.S-Sm.SLRN.Slrn\ rc :cal SetSyn("slrnrc")<CR>
+an 50.130.510 &Syntax.S-Sm.SLRN.Slrn\ score :cal SetSyn("slrnsc")<CR>
+an 50.130.520 &Syntax.S-Sm.SmallTalk :cal SetSyn("st")<CR>
+an 50.130.530 &Syntax.S-Sm.Smarty\ Templates :cal SetSyn("smarty")<CR>
+an 50.130.540 &Syntax.S-Sm.SMIL :cal SetSyn("smil")<CR>
+an 50.130.550 &Syntax.S-Sm.SMITH :cal SetSyn("smith")<CR>
+an 50.140.100 &Syntax.Sn-Sy.SNMP\ MIB :cal SetSyn("mib")<CR>
+an 50.140.110 &Syntax.Sn-Sy.SNNS.SNNS\ network :cal SetSyn("snnsnet")<CR>
+an 50.140.120 &Syntax.Sn-Sy.SNNS.SNNS\ pattern :cal SetSyn("snnspat")<CR>
+an 50.140.130 &Syntax.Sn-Sy.SNNS.SNNS\ result :cal SetSyn("snnsres")<CR>
+an 50.140.140 &Syntax.Sn-Sy.Snobol4 :cal SetSyn("snobol4")<CR>
+an 50.140.150 &Syntax.Sn-Sy.Snort\ Configuration :cal SetSyn("hog")<CR>
+an 50.140.160 &Syntax.Sn-Sy.SPEC\ (Linux\ RPM) :cal SetSyn("spec")<CR>
+an 50.140.170 &Syntax.Sn-Sy.Specman :cal SetSyn("specman")<CR>
+an 50.140.180 &Syntax.Sn-Sy.Spice :cal SetSyn("spice")<CR>
+an 50.140.190 &Syntax.Sn-Sy.Spyce :cal SetSyn("spyce")<CR>
+an 50.140.200 &Syntax.Sn-Sy.Speedup :cal SetSyn("spup")<CR>
+an 50.140.210 &Syntax.Sn-Sy.Splint :cal SetSyn("splint")<CR>
+an 50.140.220 &Syntax.Sn-Sy.Squid\ config :cal SetSyn("squid")<CR>
+an 50.140.230 &Syntax.Sn-Sy.SQL.SAP\ HANA :cal SetSyn("sqlhana")<CR>
+an 50.140.240 &Syntax.Sn-Sy.SQL.ESQL-C :cal SetSyn("esqlc")<CR>
+an 50.140.250 &Syntax.Sn-Sy.SQL.MySQL :cal SetSyn("mysql")<CR>
+an 50.140.260 &Syntax.Sn-Sy.SQL.PL/SQL :cal SetSyn("plsql")<CR>
+an 50.140.270 &Syntax.Sn-Sy.SQL.SQL\ Anywhere :cal SetSyn("sqlanywhere")<CR>
+an 50.140.280 &Syntax.Sn-Sy.SQL.SQL\ (automatic) :cal SetSyn("sql")<CR>
+an 50.140.290 &Syntax.Sn-Sy.SQL.SQL\ (Oracle) :cal SetSyn("sqloracle")<CR>
+an 50.140.300 &Syntax.Sn-Sy.SQL.SQL\ Forms :cal SetSyn("sqlforms")<CR>
+an 50.140.310 &Syntax.Sn-Sy.SQL.SQLJ :cal SetSyn("sqlj")<CR>
+an 50.140.320 &Syntax.Sn-Sy.SQL.SQL-Informix :cal SetSyn("sqlinformix")<CR>
+an 50.140.330 &Syntax.Sn-Sy.SQR :cal SetSyn("sqr")<CR>
+an 50.140.340 &Syntax.Sn-Sy.Ssh.ssh_config :cal SetSyn("sshconfig")<CR>
+an 50.140.350 &Syntax.Sn-Sy.Ssh.sshd_config :cal SetSyn("sshdconfig")<CR>
+an 50.140.360 &Syntax.Sn-Sy.Standard\ ML :cal SetSyn("sml")<CR>
+an 50.140.370 &Syntax.Sn-Sy.Stata.SMCL :cal SetSyn("smcl")<CR>
+an 50.140.380 &Syntax.Sn-Sy.Stata.Stata :cal SetSyn("stata")<CR>
+an 50.140.390 &Syntax.Sn-Sy.Stored\ Procedures :cal SetSyn("stp")<CR>
+an 50.140.400 &Syntax.Sn-Sy.Strace :cal SetSyn("strace")<CR>
+an 50.140.410 &Syntax.Sn-Sy.Streaming\ descriptor\ file :cal SetSyn("sd")<CR>
+an 50.140.420 &Syntax.Sn-Sy.Subversion\ commit :cal SetSyn("svn")<CR>
+an 50.140.430 &Syntax.Sn-Sy.Sudoers :cal SetSyn("sudoers")<CR>
+an 50.140.440 &Syntax.Sn-Sy.SVG :cal SetSyn("svg")<CR>
+an 50.140.450 &Syntax.Sn-Sy.Symbian\ meta-makefile :cal SetSyn("mmp")<CR>
+an 50.140.460 &Syntax.Sn-Sy.Sysctl\.conf :cal SetSyn("sysctl")<CR>
+an 50.140.470 &Syntax.Sn-Sy.Systemd :cal SetSyn("systemd")<CR>
+an 50.140.480 &Syntax.Sn-Sy.SystemVerilog :cal SetSyn("systemverilog")<CR>
+an 50.150.100 &Syntax.T.TADS :cal SetSyn("tads")<CR>
+an 50.150.110 &Syntax.T.Tags :cal SetSyn("tags")<CR>
+an 50.150.120 &Syntax.T.TAK.TAK\ compare :cal SetSyn("takcmp")<CR>
+an 50.150.130 &Syntax.T.TAK.TAK\ input :cal SetSyn("tak")<CR>
+an 50.150.140 &Syntax.T.TAK.TAK\ output :cal SetSyn("takout")<CR>
+an 50.150.150 &Syntax.T.Tar\ listing :cal SetSyn("tar")<CR>
+an 50.150.160 &Syntax.T.Task\ data :cal SetSyn("taskdata")<CR>
+an 50.150.170 &Syntax.T.Task\ 42\ edit :cal SetSyn("taskedit")<CR>
+an 50.150.180 &Syntax.T.Tcl/Tk :cal SetSyn("tcl")<CR>
+an 50.150.190 &Syntax.T.TealInfo :cal SetSyn("tli")<CR>
+an 50.150.200 &Syntax.T.Telix\ Salt :cal SetSyn("tsalt")<CR>
+an 50.150.210 &Syntax.T.Termcap/Printcap :cal SetSyn("ptcap")<CR>
+an 50.150.220 &Syntax.T.Terminfo :cal SetSyn("terminfo")<CR>
+an 50.150.230 &Syntax.T.Tera\ Term :cal SetSyn("teraterm")<CR>
+an 50.150.240 &Syntax.T.TeX.TeX/LaTeX :cal SetSyn("tex")<CR>
+an 50.150.250 &Syntax.T.TeX.plain\ TeX :cal SetSyn("plaintex")<CR>
+an 50.150.260 &Syntax.T.TeX.Initex :cal SetSyn("initex")<CR>
+an 50.150.270 &Syntax.T.TeX.ConTeXt :cal SetSyn("context")<CR>
+an 50.150.280 &Syntax.T.TeX.TeX\ configuration :cal SetSyn("texmf")<CR>
+an 50.150.290 &Syntax.T.TeX.Texinfo :cal SetSyn("texinfo")<CR>
+an 50.150.300 &Syntax.T.TF\ mud\ client :cal SetSyn("tf")<CR>
+an 50.150.310 &Syntax.T.Tidy\ configuration :cal SetSyn("tidy")<CR>
+an 50.150.320 &Syntax.T.Tilde :cal SetSyn("tilde")<CR>
+an 50.150.330 &Syntax.T.Tmux\ configuration :cal SetSyn("tmux")<CR>
+an 50.150.340 &Syntax.T.TPP :cal SetSyn("tpp")<CR>
+an 50.150.350 &Syntax.T.Trasys\ input :cal SetSyn("trasys")<CR>
+an 50.150.360 &Syntax.T.Treetop :cal SetSyn("treetop")<CR>
+an 50.150.370 &Syntax.T.Trustees :cal SetSyn("trustees")<CR>
+an 50.150.380 &Syntax.T.TSS.Command\ Line :cal SetSyn("tsscl")<CR>
+an 50.150.390 &Syntax.T.TSS.Geometry :cal SetSyn("tssgm")<CR>
+an 50.150.400 &Syntax.T.TSS.Optics :cal SetSyn("tssop")<CR>
+an 50.160.100 &Syntax.UV.Udev\ config :cal SetSyn("udevconf")<CR>
+an 50.160.110 &Syntax.UV.Udev\ permissions :cal SetSyn("udevperm")<CR>
+an 50.160.120 &Syntax.UV.Udev\ rules :cal SetSyn("udevrules")<CR>
+an 50.160.130 &Syntax.UV.UIT/UIL :cal SetSyn("uil")<CR>
+an 50.160.140 &Syntax.UV.UnrealScript :cal SetSyn("uc")<CR>
+an 50.160.150 &Syntax.UV.Updatedb\.conf :cal SetSyn("updatedb")<CR>
+an 50.160.160 &Syntax.UV.Upstart :cal SetSyn("upstart")<CR>
+an 50.160.180 &Syntax.UV.Valgrind :cal SetSyn("valgrind")<CR>
+an 50.160.190 &Syntax.UV.Vera :cal SetSyn("vera")<CR>
+an 50.160.200 &Syntax.UV.Verbose\ TAP\ Output :cal SetSyn("tap")<CR>
+an 50.160.210 &Syntax.UV.Verilog-AMS\ HDL :cal SetSyn("verilogams")<CR>
+an 50.160.220 &Syntax.UV.Verilog\ HDL :cal SetSyn("verilog")<CR>
+an 50.160.230 &Syntax.UV.Vgrindefs :cal SetSyn("vgrindefs")<CR>
+an 50.160.240 &Syntax.UV.VHDL :cal SetSyn("vhdl")<CR>
+an 50.160.250 &Syntax.UV.Vim.Vim\ help\ file :cal SetSyn("help")<CR>
+an 50.160.260 &Syntax.UV.Vim.Vim\ script :cal SetSyn("vim")<CR>
+an 50.160.270 &Syntax.UV.Vim.Viminfo\ file :cal SetSyn("viminfo")<CR>
+an 50.160.280 &Syntax.UV.Virata\ config :cal SetSyn("virata")<CR>
+an 50.160.290 &Syntax.UV.Visual\ Basic :cal SetSyn("vb")<CR>
+an 50.160.300 &Syntax.UV.VOS\ CM\ macro :cal SetSyn("voscm")<CR>
+an 50.160.310 &Syntax.UV.VRML :cal SetSyn("vrml")<CR>
+an 50.160.320 &Syntax.UV.Vroom :cal SetSyn("vroom")<CR>
+an 50.160.330 &Syntax.UV.VSE\ JCL :cal SetSyn("vsejcl")<CR>
+an 50.170.100 &Syntax.WXYZ.WEB.CWEB :cal SetSyn("cweb")<CR>
+an 50.170.110 &Syntax.WXYZ.WEB.WEB :cal SetSyn("web")<CR>
+an 50.170.120 &Syntax.WXYZ.WEB.WEB\ Changes :cal SetSyn("change")<CR>
+an 50.170.130 &Syntax.WXYZ.Webmacro :cal SetSyn("webmacro")<CR>
+an 50.170.140 &Syntax.WXYZ.Website\ MetaLanguage :cal SetSyn("wml")<CR>
+an 50.170.160 &Syntax.WXYZ.wDiff :cal SetSyn("wdiff")<CR>
+an 50.170.180 &Syntax.WXYZ.Wget\ config :cal SetSyn("wget")<CR>
+an 50.170.190 &Syntax.WXYZ.Whitespace\ (add) :cal SetSyn("whitespace")<CR>
+an 50.170.200 &Syntax.WXYZ.WildPackets\ EtherPeek\ Decoder :cal SetSyn("dcd")<CR>
+an 50.170.210 &Syntax.WXYZ.WinBatch/Webbatch :cal SetSyn("winbatch")<CR>
+an 50.170.220 &Syntax.WXYZ.Windows\ Scripting\ Host :cal SetSyn("wsh")<CR>
+an 50.170.230 &Syntax.WXYZ.WSML :cal SetSyn("wsml")<CR>
+an 50.170.240 &Syntax.WXYZ.WvDial :cal SetSyn("wvdial")<CR>
+an 50.170.260 &Syntax.WXYZ.X\ Keyboard\ Extension :cal SetSyn("xkb")<CR>
+an 50.170.270 &Syntax.WXYZ.X\ Pixmap :cal SetSyn("xpm")<CR>
+an 50.170.280 &Syntax.WXYZ.X\ Pixmap\ (2) :cal SetSyn("xpm2")<CR>
+an 50.170.290 &Syntax.WXYZ.X\ resources :cal SetSyn("xdefaults")<CR>
+an 50.170.300 &Syntax.WXYZ.XBL :cal SetSyn("xbl")<CR>
+an 50.170.310 &Syntax.WXYZ.Xinetd\.conf :cal SetSyn("xinetd")<CR>
+an 50.170.320 &Syntax.WXYZ.Xmodmap :cal SetSyn("xmodmap")<CR>
+an 50.170.330 &Syntax.WXYZ.Xmath :cal SetSyn("xmath")<CR>
+an 50.170.340 &Syntax.WXYZ.XML :cal SetSyn("xml")<CR>
+an 50.170.350 &Syntax.WXYZ.XML\ Schema\ (XSD) :cal SetSyn("xsd")<CR>
+an 50.170.360 &Syntax.WXYZ.XQuery :cal SetSyn("xquery")<CR>
+an 50.170.370 &Syntax.WXYZ.Xslt :cal SetSyn("xslt")<CR>
+an 50.170.380 &Syntax.WXYZ.XFree86\ Config :cal SetSyn("xf86conf")<CR>
+an 50.170.400 &Syntax.WXYZ.YAML :cal SetSyn("yaml")<CR>
+an 50.170.410 &Syntax.WXYZ.Yacc :cal SetSyn("yacc")<CR>
+an 50.170.430 &Syntax.WXYZ.Zimbu :cal SetSyn("zimbu")<CR>
" The End Of The Syntax Menu
diff --git a/runtime/syntax/2html.vim b/runtime/syntax/2html.vim
index ddc7819be2..4a2d1d3959 100644
--- a/runtime/syntax/2html.vim
+++ b/runtime/syntax/2html.vim
@@ -1,6 +1,6 @@
" Vim syntax support file
" Maintainer: Ben Fritz <fritzophrenic@gmail.com>
-" Last Change: 2015 Sep 08
+" Last Change: 2018 Nov 11
"
" Additional contributors:
"
@@ -633,6 +633,45 @@ if s:current_syntax == ''
let s:current_syntax = 'none'
endif
+" If the user is sourcing this script directly then the plugin version isn't
+" known because the main plugin script didn't load. In the usual case where the
+" user still has the full Vim runtime installed, or has this full plugin
+" installed in a package or something, then we can extract the version from the
+" main plugin file at it's usual spot relative to this file. Otherwise the user
+" is assembling their runtime piecemeal and we have no idea what versions of
+" other files may be present so don't even try to make a guess or assume the
+" presence of other specific files with specific meaning.
+"
+" We don't want to actually source the main plugin file here because the user
+" may have a good reason not to (e.g. they define their own TOhtml command or
+" something).
+"
+" If this seems way too complicated and convoluted, it is. Probably I should
+" have put the version information in the autoload file from the start. But the
+" version has been in the global variable for so long that changing it could
+" break a lot of user scripts.
+if exists("g:loaded_2html_plugin")
+ let s:pluginversion = g:loaded_2html_plugin
+else
+ if !exists("g:unloaded_tohtml_plugin")
+ let s:main_plugin_path = expand("<sfile>:p:h:h")."/plugin/tohtml.vim"
+ if filereadable(s:main_plugin_path)
+ let s:lines = readfile(s:main_plugin_path, "", 20)
+ call filter(s:lines, 'v:val =~ "loaded_2html_plugin = "')
+ if empty(s:lines)
+ let g:unloaded_tohtml_plugin = "unknown"
+ else
+ let g:unloaded_tohtml_plugin = substitute(s:lines[0], '.*loaded_2html_plugin = \([''"]\)\(\%(\1\@!.\)\+\)\1', '\2', '')
+ endif
+ unlet s:lines
+ else
+ let g:unloaded_tohtml_plugin = "unknown"
+ endif
+ unlet s:main_plugin_path
+ endif
+ let s:pluginversion = g:unloaded_tohtml_plugin
+endif
+
" Split window to create a buffer with the HTML file.
let s:orgbufnr = winbufnr(0)
let s:origwin_stl = &l:stl
@@ -721,7 +760,7 @@ endif
call extend(s:lines, [
\ ("<title>".expand("%:p:~")."</title>"),
\ ("<meta name=\"Generator\" content=\"Vim/".v:version/100.".".v:version%100.'"'.s:tag_close),
- \ ("<meta name=\"plugin-version\" content=\"".g:loaded_2html_plugin.'"'.s:tag_close)
+ \ ("<meta name=\"plugin-version\" content=\"".s:pluginversion.'"'.s:tag_close)
\ ])
call add(s:lines, '<meta name="syntax" content="'.s:current_syntax.'"'.s:tag_close)
call add(s:lines, '<meta name="settings" content="'.
@@ -807,12 +846,15 @@ if s:settings.use_css
endif
endif
-" insert script tag; javascript is always needed for the line number
-" normalization for URL hashes
-call extend(s:lines, [
- \ "",
- \ "<script type='text/javascript'>",
- \ s:settings.use_xhtml ? '//<![CDATA[' : "<!--"])
+let s:uses_script = s:settings.dynamic_folds || s:settings.line_ids || !empty(s:settings.prevent_copy)
+
+" insert script tag if needed
+if s:uses_script
+ call extend(s:lines, [
+ \ "",
+ \ "<script type='text/javascript'>",
+ \ s:settings.use_xhtml ? '//<![CDATA[' : "<!--"])
+endif
" insert javascript to toggle folds open and closed
if s:settings.dynamic_folds
@@ -849,8 +891,9 @@ if s:settings.line_ids
\ " if (lineNum.indexOf('L') == -1) {",
\ " lineNum = 'L'+lineNum;",
\ " }",
- \ " lineElem = document.getElementById(lineNum);"
+ \ " var lineElem = document.getElementById(lineNum);"
\ ])
+
if s:settings.dynamic_folds
call extend(s:lines, [
\ "",
@@ -940,12 +983,14 @@ if !empty(s:settings.prevent_copy)
\ ])
endif
-" insert script closing tag
-call extend(s:lines, [
- \ '',
- \ s:settings.use_xhtml ? '//]]>' : '-->',
- \ "</script>"
- \ ])
+" insert script closing tag if needed
+if s:uses_script
+ call extend(s:lines, [
+ \ '',
+ \ s:settings.use_xhtml ? '//]]>' : '-->',
+ \ "</script>"
+ \ ])
+endif
call extend(s:lines, ["</head>"])
if !empty(s:settings.prevent_copy)
@@ -1525,10 +1570,22 @@ while s:lnum <= s:end
if s:settings.expand_tabs
let s:offset = 0
let s:idx = stridx(s:expandedtab, "\t")
+ let s:tablist = split(&vts,',')
+ if empty(s:tablist)
+ let s:tablist = [ &ts ]
+ endif
+ let s:tabidx = 0
+ let s:tabwidth = 0
while s:idx >= 0
+ while s:startcol+s:idx > s:tabwidth + s:tablist[s:tabidx]
+ let s:tabwidth += s:tablist[s:tabidx]
+ if s:tabidx < len(s:tablist)-1
+ let s:tabidx = s:tabidx+1
+ endif
+ endwhile
if has("multi_byte_encoding")
if s:startcol + s:idx == 1
- let s:i = &ts
+ let s:i = s:tablist[s:tabidx]
else
if s:idx == 0
let s:prevc = matchstr(s:line, '.\%' . (s:startcol + s:idx + s:offset) . 'c')
@@ -1536,11 +1593,11 @@ while s:lnum <= s:end
let s:prevc = matchstr(s:expandedtab, '.\%' . (s:idx + 1) . 'c')
endif
let s:vcol = virtcol([s:lnum, s:startcol + s:idx + s:offset - len(s:prevc)])
- let s:i = &ts - (s:vcol % &ts)
+ let s:i = s:tablist[s:tabidx] - (s:vcol - s:tabwidth)
endif
let s:offset -= s:i - 1
else
- let s:i = &ts - ((s:idx + s:startcol - 1) % &ts)
+ let s:i = s:tablist[s:tabidx] - ((s:idx + s:startcol - 1) - s:tabwidth)
endif
let s:expandedtab = substitute(s:expandedtab, '\t', repeat(' ', s:i), '')
let s:idx = stridx(s:expandedtab, "\t")
diff --git a/runtime/syntax/8th.vim b/runtime/syntax/8th.vim
new file mode 100644
index 0000000000..ddc1084c9f
--- /dev/null
+++ b/runtime/syntax/8th.vim
@@ -0,0 +1,335 @@
+" Vim syntax file
+" Language: 8th
+" Version: 19.01d
+" Maintainer: Ron Aaron <ron@aaron-tech.com>
+" URL: https://8th-dev.com/
+" Filetypes: *.8th
+" NOTE: You should also have the ftplugin/8th.vim file to set 'isk'
+
+if version < 600
+ syntax clear
+ finish
+elseif exists("b:current_syntax")
+ finish
+endif
+
+let s:cpo_save = &cpo
+set cpo&vim
+syn clear
+" Synchronization method
+syn sync ccomment
+syn sync maxlines=100
+syn case match
+syn match eighthColonName "\S\+" contained
+syn match eighthColonDef ":\s\+\S\+" contains=eighthColonName
+
+" new words
+syn match eighthClasses "\<\S\+:" contained
+syn match eighthClassWord "\<\S\+:.\+" contains=eighthClasses
+
+syn keyword eighthEndOfColonDef ; i;
+syn keyword eighthDefine var var,
+
+" Built in words
+com! -nargs=+ Builtin syn keyword eighthBuiltin <args>
+"Builtin ^ < <# <#> = > - -- ,# ; ;; ! ??? / . .# ' () @ * */ \
+
+Builtin ! G:! #! G:#! ## G:## #> G:#> #if G:#if ' G:' ( G:( (* G:(* (:) G:(:) (code) G:(code) (getc) G:(getc)
+Builtin (gets) G:(gets) (interp) G:(interp) (needs) G:(needs) (putc) G:(putc) (puts) G:(puts) (putslim) G:(putslim)
+Builtin (say) G:(say) (stat) G:(stat) ) G:) +listener G:+listener +ref G:+ref ,# G:,# -- G:-- -----BEGIN G:-----BEGIN
+Builtin -Inf G:-Inf -Inf? G:-Inf? -listener G:-listener -ref G:-ref -rot G:-rot . G:. .# G:.# .needs G:.needs
+Builtin .r G:.r .s G:.s .stats G:.stats .ver G:.ver .with G:.with 0; G:0; 2dip G:2dip 2drop G:2drop
+Builtin 2dup G:2dup 2over G:2over 2swap G:2swap 3drop G:3drop 4drop G:4drop 8thdt? G:8thdt? 8thver? G:8thver?
+Builtin : G:: ; G:; ;; G:;; ;;; G:;;; ;then G:;then ;with G:;with <# G:<# <#> G:<#> >clip G:>clip >json G:>json
+Builtin >kind G:>kind >n G:>n >r G:>r >s G:>s ?: G:?: ??? G:??? @ G:@ Inf G:Inf Inf? G:Inf? NaN G:NaN
+Builtin NaN? G:NaN? SED-CHECK G:SED-CHECK SED: G:SED: SED: G:SED: \ G:\ ` G:` `` G:`` actor: G:actor:
+Builtin again G:again ahead G:ahead and G:and appname G:appname apropos G:apropos argc G:argc args G:args
+Builtin array? G:array? assert G:assert base G:base bi G:bi bits G:bits break G:break break? G:break?
+Builtin build? G:build? buildver? G:buildver? bye G:bye c# G:c# c/does G:c/does case G:case caseof G:caseof
+Builtin chdir G:chdir clip> G:clip> clone G:clone clone-shallow G:clone-shallow cold G:cold compat-level G:compat-level
+Builtin compile G:compile compile? G:compile? conflict G:conflict const G:const container? G:container?
+Builtin cr G:cr curlang G:curlang curry G:curry curry: G:curry: decimal G:decimal defer: G:defer: deg>rad G:deg>rad
+Builtin depth G:depth die G:die dip G:dip drop G:drop dstack G:dstack dump G:dump dup G:dup dup? G:dup?
+Builtin else G:else enum: G:enum: eval G:eval eval! G:eval! eval0 G:eval0 execnull G:execnull expect G:expect
+Builtin extra! G:extra! extra@ G:extra@ false G:false fnv G:fnv fourth G:fourth free G:free func: G:func:
+Builtin getc G:getc getcwd G:getcwd getenv G:getenv gets G:gets handler G:handler header G:header help G:help
+Builtin hex G:hex i: G:i: i; G:i; if G:if if; G:if; isa? G:isa? items-used G:items-used jcall G:jcall
+Builtin jclass G:jclass jmethod G:jmethod json-nesting G:json-nesting json-pretty G:json-pretty json-throw G:json-throw
+Builtin json> G:json> k32 G:k32 keep G:keep l: G:l: last G:last lib G:lib libbin G:libbin libc G:libc
+Builtin listener@ G:listener@ literal G:literal locals: G:locals: lock G:lock lock-to G:lock-to locked? G:locked?
+Builtin log G:log log-async G:log-async log-task G:log-task log-time G:log-time log-time-local G:log-time-local
+Builtin long-days G:long-days long-months G:long-months loop G:loop loop- G:loop- map? G:map? mark G:mark
+Builtin mark? G:mark? memfree G:memfree mobile? G:mobile? n# G:n# name>os G:name>os name>sem G:name>sem
+Builtin ndrop G:ndrop needs G:needs new G:new next-arg G:next-arg nip G:nip noop G:noop not G:not ns G:ns
+Builtin ns: G:ns: ns>ls G:ns>ls ns>s G:ns>s ns? G:ns? null G:null null; G:null; null? G:null? number? G:number?
+Builtin off G:off on G:on onexit G:onexit only G:only op! G:op! or G:or os G:os os-names G:os-names
+Builtin os>long-name G:os>long-name os>name G:os>name over G:over p: G:p: pack G:pack parse G:parse
+Builtin parsech G:parsech parseln G:parseln parsews G:parsews pick G:pick poke G:poke pool-clear G:pool-clear
+Builtin prior G:prior private G:private process-args G:process-args prompt G:prompt public G:public
+Builtin putc G:putc puts G:puts putslim G:putslim quote G:quote r! G:r! r> G:r> r@ G:r@ rad>deg G:rad>deg
+Builtin rand G:rand rand-pcg G:rand-pcg rand-pcg-seed G:rand-pcg-seed randbuf G:randbuf randbuf-pcg G:randbuf-pcg
+Builtin rdrop G:rdrop recurse G:recurse recurse-stack G:recurse-stack ref@ G:ref@ reg! G:reg! reg@ G:reg@
+Builtin regbin@ G:regbin@ remaining-args G:remaining-args repeat G:repeat reset G:reset roll G:roll
+Builtin rop! G:rop! rot G:rot rpick G:rpick rroll G:rroll rstack G:rstack rswap G:rswap rusage G:rusage
+Builtin s>ns G:s>ns same? G:same? scriptdir G:scriptdir scriptfile G:scriptfile sem G:sem sem-post G:sem-post
+Builtin sem-rm G:sem-rm sem-wait G:sem-wait sem-wait? G:sem-wait? sem>name G:sem>name semi-throw G:semi-throw
+Builtin set-wipe G:set-wipe setenv G:setenv settings! G:settings! settings![] G:settings![] settings@ G:settings@
+Builtin settings@? G:settings@? settings@[] G:settings@[] sh G:sh sh$ G:sh$ short-days G:short-days
+Builtin short-months G:short-months sleep G:sleep space G:space stack-check G:stack-check stack-size G:stack-size
+Builtin step G:step string? G:string? struct: G:struct: swap G:swap syslang G:syslang sysregion G:sysregion
+Builtin tab-hook G:tab-hook tell-conflict G:tell-conflict tempdir G:tempdir tempfilename G:tempfilename
+Builtin then G:then third G:third throw G:throw thrownull G:thrownull times G:times tlog G:tlog tri G:tri
+Builtin true G:true tuck G:tuck type-check G:type-check typeassert G:typeassert unlock G:unlock unpack G:unpack
+Builtin until G:until until! G:until! var G:var var, G:var, while G:while while! G:while! with: G:with:
+Builtin words G:words words-like G:words-like words/ G:words/ xchg G:xchg xor G:xor >auth HTTP:>auth
+Builtin sh I:sh tpush I:tpush trace-word I:trace-word call JSONRPC:call auth-string OAuth:auth-string
+Builtin gen-nonce OAuth:gen-nonce params OAuth:params call SOAP:call ! a:! + a:+ - a:- 2each a:2each
+Builtin 2map a:2map 2map+ a:2map+ 2map= a:2map= = a:= >map a:>map @ a:@ @@ a:@@ bsearch a:bsearch clear a:clear
+Builtin close a:close diff a:diff dot a:dot each a:each each-slice a:each-slice exists? a:exists? filter a:filter
+Builtin generate a:generate group a:group indexof a:indexof insert a:insert intersect a:intersect join a:join
+Builtin len a:len map a:map map+ a:map+ map= a:map= mean a:mean mean&variance a:mean&variance new a:new
+Builtin op a:op op! a:op! op= a:op= open a:open pop a:pop push a:push qsort a:qsort randeach a:randeach
+Builtin reduce a:reduce reduce+ a:reduce+ rev a:rev shift a:shift shuffle a:shuffle slice a:slice slice+ a:slice+
+Builtin slide a:slide sort a:sort union a:union when a:when when! a:when! x a:x x-each a:x-each xchg a:xchg
+Builtin y a:y zip a:zip 8thdir app:8thdir asset app:asset atrun app:atrun atrun app:atrun atrun app:atrun
+Builtin basedir app:basedir current app:current datadir app:datadir exename app:exename isgui app:isgui
+Builtin main app:main oncrash app:oncrash orientation app:orientation pid app:pid restart app:restart
+Builtin resumed app:resumed shared? app:shared? standalone app:standalone subdir app:subdir suspended app:suspended
+Builtin sysquit app:sysquit (here) asm:(here) >n asm:>n avail asm:avail c, asm:c, here! asm:here! n> asm:n>
+Builtin used asm:used w, asm:w, ! b:! + b:+ / b:/ = b:= >base64 b:>base64 >hex b:>hex >mpack b:>mpack
+Builtin @ b:@ append b:append base64> b:base64> bit! b:bit! bit@ b:bit@ clear b:clear compress b:compress
+Builtin conv b:conv each b:each each-slice b:each-slice expand b:expand fill b:fill getb b:getb hex> b:hex>
+Builtin len b:len mem> b:mem> move b:move mpack-date b:mpack-date mpack-ignore b:mpack-ignore mpack> b:mpack>
+Builtin new b:new op b:op rev b:rev search b:search shmem b:shmem slice b:slice splice b:splice ungetb b:ungetb
+Builtin writable b:writable xor b:xor +block bc:+block .blocks bc:.blocks add-block bc:add-block block-hash bc:block-hash
+Builtin block@ bc:block@ first-block bc:first-block hash bc:hash last-block bc:last-block load bc:load
+Builtin new bc:new save bc:save set-sql bc:set-sql validate bc:validate validate-block bc:validate-block
+Builtin add bloom:add filter bloom:filter in? bloom:in? accept bt:accept ch! bt:ch! ch@ bt:ch@ connect bt:connect
+Builtin disconnect bt:disconnect err? bt:err? leconnect bt:leconnect lescan bt:lescan listen bt:listen
+Builtin on? bt:on? read bt:read scan bt:scan service? bt:service? services? bt:services? write bt:write
+Builtin * c:* * c:* + c:+ + c:+ = c:= = c:= >ri c:>ri >ri c:>ri abs c:abs abs c:abs arg c:arg arg c:arg
+Builtin conj c:conj conj c:conj im c:im n> c:n> new c:new new c:new re c:re >aes128gcm cr:>aes128gcm
+Builtin >aes256gcm cr:>aes256gcm >cp cr:>cp >cpe cr:>cpe >decrypt cr:>decrypt >edbox cr:>edbox >encrypt cr:>encrypt
+Builtin >nbuf cr:>nbuf >rsabox cr:>rsabox >uuid cr:>uuid CBC cr:CBC CFB cr:CFB CTR cr:CTR ECB cr:ECB
+Builtin GCM cr:GCM OFB cr:OFB aad? cr:aad? aes128box-sig cr:aes128box-sig aes128gcm> cr:aes128gcm>
+Builtin aes256box-sig cr:aes256box-sig aes256gcm> cr:aes256gcm> aesgcm cr:aesgcm blakehash cr:blakehash
+Builtin chacha20box-sig cr:chacha20box-sig chachapoly cr:chachapoly cipher! cr:cipher! cipher@ cr:cipher@
+Builtin cp> cr:cp> cpe> cr:cpe> decrypt cr:decrypt decrypt+ cr:decrypt+ decrypt> cr:decrypt> dh-genkey cr:dh-genkey
+Builtin dh-secret cr:dh-secret dh-sign cr:dh-sign dh-verify cr:dh-verify ebox-sig cr:ebox-sig ecc-genkey cr:ecc-genkey
+Builtin ecc-secret cr:ecc-secret ecc-sign cr:ecc-sign ecc-verify cr:ecc-verify edbox-sig cr:edbox-sig
+Builtin edbox> cr:edbox> encrypt cr:encrypt encrypt+ cr:encrypt+ encrypt> cr:encrypt> ensurekey cr:ensurekey
+Builtin err? cr:err? gcm-tag-size cr:gcm-tag-size genkey cr:genkey hash cr:hash hash! cr:hash! hash+ cr:hash+
+Builtin hash>b cr:hash>b hash>s cr:hash>s hash@ cr:hash@ hmac cr:hmac hotp cr:hotp iv? cr:iv? mode cr:mode
+Builtin mode@ cr:mode@ randkey cr:randkey restore cr:restore root-certs cr:root-certs rsa_decrypt cr:rsa_decrypt
+Builtin rsa_encrypt cr:rsa_encrypt rsa_sign cr:rsa_sign rsa_verify cr:rsa_verify rsabox-sig cr:rsabox-sig
+Builtin rsabox> cr:rsabox> rsagenkey cr:rsagenkey save cr:save sbox-sig cr:sbox-sig sha1-hmac cr:sha1-hmac
+Builtin shard cr:shard tag? cr:tag? totp cr:totp totp-epoch cr:totp-epoch totp-time-step cr:totp-time-step
+Builtin unshard cr:unshard uuid cr:uuid uuid> cr:uuid> validate-pgp-sig cr:validate-pgp-sig (.hebrew) d:(.hebrew)
+Builtin (.islamic) d:(.islamic) + d:+ +day d:+day +hour d:+hour +min d:+min +msec d:+msec - d:- .hebrew d:.hebrew
+Builtin .islamic d:.islamic .time d:.time / d:/ = d:= >fixed d:>fixed >hebepoch d:>hebepoch >msec d:>msec
+Builtin >unix d:>unix >ymd d:>ymd Adar d:Adar Adar2 d:Adar2 Adar2 d:Adar2 Av d:Av Elul d:Elul Fri d:Fri
+Builtin Heshvan d:Heshvan Iyar d:Iyar Kislev d:Kislev Mon d:Mon Nissan d:Nissan Sat d:Sat Shevat d:Shevat
+Builtin Sivan d:Sivan Sun d:Sun Tammuz d:Tammuz Tevet d:Tevet Thu d:Thu Tishrei d:Tishrei Tue d:Tue
+Builtin Wed d:Wed adjust-dst d:adjust-dst between d:between d. d:d. dawn d:dawn days-in-hebrew-year d:days-in-hebrew-year
+Builtin displaying-hebrew d:displaying-hebrew do-dawn d:do-dawn do-dusk d:do-dusk do-rise d:do-rise
+Builtin doy d:doy dst? d:dst? dstquery d:dstquery dstzones? d:dstzones? dusk d:dusk elapsed-timer d:elapsed-timer
+Builtin elapsed-timer-seconds d:elapsed-timer-seconds first-dow d:first-dow fixed> d:fixed> fixed>dow d:fixed>dow
+Builtin fixed>hebrew d:fixed>hebrew fixed>islamic d:fixed>islamic format d:format hanukkah d:hanukkah
+Builtin hebrew-epoch d:hebrew-epoch hebrew>fixed d:hebrew>fixed hebrewtoday d:hebrewtoday hmonth-name d:hmonth-name
+Builtin islamic.epoch d:islamic.epoch islamic>fixed d:islamic>fixed islamictoday d:islamictoday join d:join
+Builtin last-day-of-hebrew-month d:last-day-of-hebrew-month last-dow d:last-dow last-month d:last-month
+Builtin last-week d:last-week last-year d:last-year latitude d:latitude longitude d:longitude longitude d:longitude
+Builtin msec d:msec msec> d:msec> new d:new next-dow d:next-dow next-month d:next-month next-week d:next-week
+Builtin next-year d:next-year number>hebrew d:number>hebrew omer d:omer parse d:parse pesach d:pesach
+Builtin prev-dow d:prev-dow purim d:purim rosh-chodesh? d:rosh-chodesh? rosh-hashanah d:rosh-hashanah
+Builtin shavuot d:shavuot start-timer d:start-timer sunrise d:sunrise taanit-esther d:taanit-esther
+Builtin ticks d:ticks ticks/sec d:ticks/sec timer d:timer tisha-beav d:tisha-beav tzadjust d:tzadjust
+Builtin unix> d:unix> updatetz d:updatetz year@ d:year@ ymd d:ymd ymd> d:ymd> yom-haatsmaut d:yom-haatsmaut
+Builtin yom-kippur d:yom-kippur add-func db:add-func bind db:bind close db:close col db:col col[] db:col[]
+Builtin col{} db:col{} err? db:err? errmsg db:errmsg exec db:exec exec-cb db:exec-cb key db:key mysql? db:mysql?
+Builtin odbc? db:odbc? open db:open open? db:open? prepare db:prepare query db:query query-all db:query-all
+Builtin rekey db:rekey sqlerrmsg db:sqlerrmsg bp dbg:bp except-task@ dbg:except-task@ go dbg:go line-info dbg:line-info
+Builtin prompt dbg:prompt stop dbg:stop trace dbg:trace trace-enter dbg:trace-enter trace-leave dbg:trace-leave
+Builtin abspath f:abspath append f:append associate f:associate atime f:atime canwrite? f:canwrite?
+Builtin chmod f:chmod close f:close copy f:copy copydir f:copydir create f:create ctime f:ctime dir? f:dir?
+Builtin dname f:dname eachbuf f:eachbuf eachline f:eachline enssep f:enssep eof? f:eof? err? f:err?
+Builtin exists? f:exists? flush f:flush fname f:fname getb f:getb getc f:getc getline f:getline getmod f:getmod
+Builtin glob f:glob glob-nocase f:glob-nocase include f:include launch f:launch link f:link link> f:link>
+Builtin link? f:link? mkdir f:mkdir mmap f:mmap mmap-range f:mmap-range mmap-range? f:mmap-range? mtime f:mtime
+Builtin mv f:mv open f:open open-ro f:open-ro popen f:popen print f:print read f:read relpath f:relpath
+Builtin rglob f:rglob rm f:rm rmdir f:rmdir seek f:seek sep f:sep show f:show size f:size slurp f:slurp
+Builtin stderr f:stderr stdin f:stdin stdout f:stdout tell f:tell times f:times trash f:trash ungetb f:ungetb
+Builtin ungetc f:ungetc unzip f:unzip unzip-entry f:unzip-entry watch f:watch write f:write writen f:writen
+Builtin zip+ f:zip+ zip@ f:zip@ zipentry f:zipentry zipnew f:zipnew zipopen f:zipopen zipsave f:zipsave
+Builtin bold font:bold face? font:face? glyph-path font:glyph-path glyph-pos font:glyph-pos info font:info
+Builtin italic font:italic ls font:ls measure font:measure new font:new pixels font:pixels pixels? font:pixels?
+Builtin points font:points points? font:points? styles font:styles styles? font:styles? underline font:underline
+Builtin +child g:+child +kind g:+kind +path g:+path -child g:-child /path g:/path >img g:>img >progress g:>progress
+Builtin add-items g:add-items adjustwidth g:adjustwidth allow-orient g:allow-orient arc g:arc arc2 g:arc2
+Builtin autohide g:autohide back g:back bezier g:bezier bg g:bg bg? g:bg? bounds g:bounds bounds? g:bounds?
+Builtin box-label g:box-label btn-font g:btn-font bubble g:bubble button-size g:button-size buttons-visible g:buttons-visible
+Builtin c-text g:c-text callout g:callout center g:center child g:child clear g:clear clearpath g:clearpath
+Builtin clr>n g:clr>n coleven g:coleven colordlg g:colordlg colwidth g:colwidth connectededges g:connectededges
+Builtin contrasting g:contrasting cp g:cp curmouse? g:curmouse? default-font g:default-font deselect-row g:deselect-row
+Builtin dismiss g:dismiss do g:do draw-fitted-text g:draw-fitted-text draw-text g:draw-text draw-text-at g:draw-text-at
+Builtin each g:each edit-on-double-click g:edit-on-double-click editable g:editable editdlg g:editdlg
+Builtin empty-text g:empty-text enable g:enable enabled? g:enabled? fade g:fade fb-files g:fb-files
+Builtin fcolor g:fcolor fg g:fg fg? g:fg? file-filter g:file-filter file-name g:file-name filedlg g:filedlg
+Builtin fill g:fill fillall g:fillall fit-text g:fit-text flex! g:flex! focus g:focus fontdlg g:fontdlg
+Builtin forward g:forward fullscreen g:fullscreen get-lasso-items g:get-lasso-items get-tab g:get-tab
+Builtin getclr g:getclr getfont g:getfont getimage g:getimage getpath g:getpath getroot g:getroot gradient g:gradient
+Builtin gui? g:gui? handle g:handle headerheight g:headerheight hide g:hide image g:image image-at g:image-at
+Builtin invalidate g:invalidate ix? g:ix? justify g:justify keyinfo g:keyinfo l-text g:l-text laf g:laf
+Builtin laf! g:laf! laf? g:laf? len g:len line-width g:line-width lineto g:lineto list+ g:list+ list- g:list-
+Builtin loadcontent g:loadcontent localize g:localize m! g:m! m@ g:m@ menu-font g:menu-font menu-update g:menu-update
+Builtin menuenabled g:menuenabled mouse? g:mouse? mousepos? g:mousepos? moveto g:moveto msgdlg g:msgdlg
+Builtin multi g:multi name g:name named-skin g:named-skin new g:new new-laf g:new-laf next g:next obj g:obj
+Builtin on g:on on? g:on? ontop g:ontop oshandle g:oshandle outlinethickness g:outlinethickness panel-size g:panel-size
+Builtin panel-size? g:panel-size? parent g:parent path g:path path>s g:path>s pie g:pie pix! g:pix!
+Builtin pop g:pop popmenu g:popmenu pos? g:pos? prev g:prev propval! g:propval! propval@ g:propval@
+Builtin push g:push qbezier g:qbezier quit g:quit r-text g:r-text readonly g:readonly rect g:rect refresh g:refresh
+Builtin restore g:restore root g:root root-item-visible g:root-item-visible rotate g:rotate rowheight g:rowheight
+Builtin rrect g:rrect s>path g:s>path save g:save say g:say scale g:scale scolor g:scolor scrollthickness g:scrollthickness
+Builtin sectionenable g:sectionenable select! g:select! select@ g:select@ selected-rows g:selected-rows
+Builtin set-lasso g:set-lasso set-long-press g:set-long-press set-popup-font g:set-popup-font set-range g:set-range
+Builtin set-swipe g:set-swipe set-value g:set-value setcursor g:setcursor setfont g:setfont setheader g:setheader
+Builtin sethtml g:sethtml setimage g:setimage setname g:setname setroot g:setroot settab g:settab show g:show
+Builtin show-line-numbers g:show-line-numbers show-pct g:show-pct showmenu g:showmenu showtooltip g:showtooltip
+Builtin size g:size size? g:size? skin g:skin skin-class g:skin-class stackix g:stackix state g:state
+Builtin state? g:state? stepsize g:stepsize stroke g:stroke stroke-fill g:stroke-fill style g:style
+Builtin tabname g:tabname text g:text text-box-style g:text-box-style text? g:text? textcolor g:textcolor
+Builtin textsize g:textsize timer! g:timer! timer@ g:timer@ toback g:toback tofront g:tofront toggle-row g:toggle-row
+Builtin tooltip g:tooltip top g:top transition g:transition translate g:translate tree-open g:tree-open
+Builtin triangle g:triangle update g:update updateitems g:updateitems url g:url user g:user user! g:user!
+Builtin vertical g:vertical view g:view visible? g:visible? vpos! g:vpos! vpos@ g:vpos@ waitcursor g:waitcursor
+Builtin winding g:winding xy g:xy xy? g:xy? +edge gr:+edge +edge+w gr:+edge+w +node gr:+node connect gr:connect
+Builtin edges gr:edges m! gr:m! m@ gr:m@ neighbors gr:neighbors new gr:new node-edges gr:node-edges
+Builtin nodes gr:nodes traverse gr:traverse + h:+ clear h:clear len h:len new h:new peek h:peek pop h:pop
+Builtin push h:push unique h:unique arm? hw:arm? camera hw:camera camera-fmt hw:camera-fmt camera-img hw:camera-img
+Builtin camera? hw:camera? cpu? hw:cpu? device? hw:device? displays? hw:displays? displaysize? hw:displaysize?
+Builtin err? hw:err? gpio hw:gpio gpio! hw:gpio! gpio-mmap hw:gpio-mmap gpio@ hw:gpio@ i2c hw:i2c i2c! hw:i2c!
+Builtin i2c!reg hw:i2c!reg i2c@ hw:i2c@ i2c@reg hw:i2c@reg isround? hw:isround? iswatch? hw:iswatch?
+Builtin mac? hw:mac? mem? hw:mem? poll hw:poll sensor hw:sensor start hw:start stop hw:stop fetch-full imap:fetch-full
+Builtin fetch-uid-mail imap:fetch-uid-mail login imap:login new imap:new select-inbox imap:select-inbox
+Builtin >file img:>file copy img:copy crop img:crop data img:data desat img:desat fill img:fill filter img:filter
+Builtin flip img:flip from-svg img:from-svg new img:new pix! img:pix! pix@ img:pix@ qr-gen img:qr-gen
+Builtin qr-parse img:qr-parse rotate img:rotate scale img:scale scroll img:scroll size img:size countries iso:countries
+Builtin find loc:find sort loc:sort ! m:! !? m:!? + m:+ +? m:+? - m:- @ m:@ @? m:@? @@ m:@@ clear m:clear
+Builtin data m:data each m:each exists? m:exists? iter m:iter iter-all m:iter-all keys m:keys len m:len
+Builtin map m:map new m:new op! m:op! open m:open vals m:vals xchg m:xchg ! mat:! * mat:* + mat:+ = mat:=
+Builtin @ mat:@ col mat:col data mat:data det mat:det dim? mat:dim? get-n mat:get-n ident mat:ident
+Builtin m. mat:m. minor mat:minor n* mat:n* new mat:new row mat:row same-size? mat:same-size? trans mat:trans
+Builtin ! n:! * n:* */ n:*/ + n:+ +! n:+! - n:- / n:/ /mod n:/mod 1+ n:1+ 1- n:1- < n:< = n:= > n:>
+Builtin BIGE n:BIGE BIGPI n:BIGPI E n:E PI n:PI ^ n:^ abs n:abs acos n:acos acos n:acos asin n:asin
+Builtin asin n:asin atan n:atan atan n:atan atan2 n:atan2 band n:band between n:between bfloat n:bfloat
+Builtin bic n:bic bint n:bint binv n:binv bnot n:bnot bor n:bor bxor n:bxor ceil n:ceil clamp n:clamp
+Builtin cmp n:cmp comb n:comb cos n:cos cosd n:cosd exp n:exp expmod n:expmod float n:float floor n:floor
+Builtin fmod n:fmod frac n:frac gcd n:gcd int n:int invmod n:invmod kind? n:kind? lcm n:lcm ln n:ln
+Builtin max n:max median n:median min n:min mod n:mod neg n:neg odd? n:odd? perm n:perm prime? n:prime?
+Builtin quantize n:quantize quantize! n:quantize! r+ n:r+ range n:range rot32l n:rot32l rot32r n:rot32r
+Builtin round n:round round2 n:round2 running-variance n:running-variance running-variance-finalize n:running-variance-finalize
+Builtin sgn n:sgn shl n:shl shr n:shr sin n:sin sind n:sind sqr n:sqr sqrt n:sqrt tan n:tan tand n:tand
+Builtin trunc n:trunc ~= n:~= ! net:! >url net:>url @ net:@ DGRAM net:DGRAM INET4 net:INET4 INET6 net:INET6
+Builtin PROTO_TCP net:PROTO_TCP PROTO_UDP net:PROTO_UDP STREAM net:STREAM accept net:accept addrinfo>o net:addrinfo>o
+Builtin again? net:again? alloc-and-read net:alloc-and-read alloc-buf net:alloc-buf bind net:bind browse net:browse
+Builtin close net:close connect net:connect err>s net:err>s err? net:err? get net:get getaddrinfo net:getaddrinfo
+Builtin getpeername net:getpeername head net:head ifaces? net:ifaces? listen net:listen net-socket net:net-socket
+Builtin opts net:opts port-is-ssl? net:port-is-ssl? post net:post proxy! net:proxy! read net:read recvfrom net:recvfrom
+Builtin s>url net:s>url sendto net:sendto server net:server setsockopt net:setsockopt socket net:socket
+Builtin tlshello net:tlshello url> net:url> user-agent net:user-agent wait net:wait write net:write
+Builtin MAX ns:MAX cast ptr:cast len ptr:len pack ptr:pack unpack ptr:unpack unpack_orig ptr:unpack_orig
+Builtin + q:+ clear q:clear len q:len new q:new notify q:notify overwrite q:overwrite peek q:peek pick q:pick
+Builtin pop q:pop push q:push shift q:shift size q:size slide q:slide throwing q:throwing wait q:wait
+Builtin ++match r:++match +/ r:+/ +match r:+match / r:/ @ r:@ err? r:err? len r:len match r:match new r:new
+Builtin rx r:rx str r:str ! s:! * s:* + s:+ - s:- / s:/ /scripts s:/scripts <+ s:<+ = s:= =ic s:=ic
+Builtin >base64 s:>base64 >ucs2 s:>ucs2 @ s:@ append s:append base64> s:base64> clear s:clear cmp s:cmp
+Builtin cmpi s:cmpi compress s:compress days! s:days! each s:each eachline s:eachline expand s:expand
+Builtin fill s:fill fmt s:fmt gershayim s:gershayim globmatch s:globmatch hexupr s:hexupr insert s:insert
+Builtin intl s:intl intl! s:intl! lang s:lang lc s:lc len s:len lsub s:lsub ltrim s:ltrim map s:map
+Builtin months! s:months! new s:new replace s:replace replace! s:replace! rev s:rev rsearch s:rsearch
+Builtin rsub s:rsub rtrim s:rtrim script? s:script? search s:search size s:size slice s:slice strfmap s:strfmap
+Builtin strfmt s:strfmt trim s:trim tsub s:tsub uc s:uc ucs2> s:ucs2> utf8? s:utf8? zt s:zt close sio:close
+Builtin enum sio:enum open sio:open opts! sio:opts! opts@ sio:opts@ read sio:read write sio:write new smtp:new
+Builtin send smtp:send apply-filter snd:apply-filter devices? snd:devices? end-record snd:end-record
+Builtin filter snd:filter formats? snd:formats? freq snd:freq gain snd:gain gain? snd:gain? len snd:len
+Builtin loop snd:loop mix snd:mix new snd:new pause snd:pause play snd:play played snd:played rate snd:rate
+Builtin record snd:record seek snd:seek stop snd:stop stopall snd:stopall unmix snd:unmix volume snd:volume
+Builtin volume? snd:volume? + st:+ . st:. clear st:clear len st:len ndrop st:ndrop new st:new op! st:op!
+Builtin peek st:peek pick st:pick pop st:pop push st:push roll st:roll shift st:shift size st:size
+Builtin slide st:slide swap st:swap throwing st:throwing >buf struct:>buf arr> struct:arr> buf struct:buf
+Builtin buf> struct:buf> byte struct:byte double struct:double field! struct:field! field@ struct:field@
+Builtin float struct:float ignore struct:ignore int struct:int long struct:long struct; struct:struct;
+Builtin word struct:word ! t:! @ t:@ assign t:assign curtask t:curtask def-queue t:def-queue def-stack t:def-stack
+Builtin done? t:done? err! t:err! err? t:err? getq t:getq guitask t:guitask handler t:handler kill t:kill
+Builtin list t:list main t:main name! t:name! name@ t:name@ notify t:notify pop t:pop priority t:priority
+Builtin push t:push push< t:push< q-notify t:q-notify q-wait t:q-wait qlen t:qlen result t:result task t:task
+Builtin task-n t:task-n task-stop t:task-stop wait t:wait ! w:! @ w:@ alias: w:alias: cb w:cb deprecate w:deprecate
+Builtin exec w:exec exec? w:exec? ffifail w:ffifail find w:find forget w:forget is w:is undo w:undo
+Builtin >s xml:>s >txt xml:>txt parse xml:parse parse-html xml:parse-html parse-stream xml:parse-stream
+Builtin getmsg[] zmq:getmsg[] sendmsg[] zmq:sendmsg[]
+" numbers
+syn keyword eighthMath decimal hex base@ base!
+syn match eighthInteger '\<-\=[0-9.]*[0-9.]\+\>'
+" recognize hex and binary numbers, the '$' and '%' notation is for eighth
+syn match eighthInteger '\<\$\x*\x\+\>' " *1* --- dont't mess
+syn match eighthInteger '\<\x*\d\x*\>' " *2* --- this order!
+syn match eighthInteger '\<%[0-1]*[0-1]\+\>'
+syn match eighthInteger "\<'.\>"
+
+" Strings
+syn region eighthString start=+\.\?\"+ skip=+"+ end=+$+
+syn keyword jsonNull null
+syn keyword jsonBool /\(true\|false\)/
+ syn region eighthString start=/\<"/ end=/"\>/
+syn match jsonObjEntry /"\"[^"]\+\"\ze\s*:/
+
+"syn region jsonObject start=/{/ end=/}/ contained contains=jsonObjEntry,jsonArray,jsonObject, jsonBool, eighthString
+"syn region jsonArray start=/\[/ end=/\]/ contained contains=jsonArray,jsonObject, jsonBool, eighthString
+
+" Include files
+" syn match eighthInclude '\<\(libinclude\|include\|needs\)\s\+\S\+'
+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.
+ hi def link eighthTodo Todo
+ hi def link eighthOperators Operator
+ hi def link eighthMath Number
+ hi def link eighthInteger Number
+ hi def link eighthStack Special
+ hi def link eighthFStack Special
+ hi def link eighthSP Special
+ hi def link eighthColonDef Define
+ hi def link eighthColonName Operator
+ hi def link eighthEndOfColonDef Define
+ hi def link eighthDefine Define
+ hi def link eighthDebug Debug
+ hi def link eighthCharOps Character
+ hi def link eighthConversion String
+ hi def link eighthForth Statement
+ hi def link eighthVocs Statement
+ hi def link eighthString String
+ hi def link eighthComment Comment
+ hi def link eighthClassDef Define
+ hi def link eighthEndOfClassDef Define
+ hi def link eighthObjectDef Define
+ hi def link eighthEndOfObjectDef Define
+ hi def link eighthInclude Include
+ hi def link eighthBuiltin Define
+ hi def link eighthClasses Define
+ hi def link eighthClassWord Keyword
+
+ hi def link jsonObject Delimiter
+ hi def link jsonObjEntry Label
+ hi def link jsonArray Special
+ hi def link jsonNull Function
+ hi def link jsonBool Boolean
+endif
+
+let b:current_syntax = "8th"
+let &cpo = s:cpo_save
+unlet s:cpo_save
+
+" vim: ts=8:sw=4:nocindent:smartindent:
diff --git a/runtime/syntax/abap.vim b/runtime/syntax/abap.vim
index c2857a5f30..4650109fb1 100644
--- a/runtime/syntax/abap.vim
+++ b/runtime/syntax/abap.vim
@@ -1,11 +1,10 @@
" Vim ABAP syntax file
" Language: SAP - ABAP/R4
-" Revision: 2.1
" Maintainer: Marius Piedallu van Wyk <lailoken@gmail.com>
-" Last Change: 2013 Jun 13
+" Last Change: 2018 Dec 12
" Comment: Thanks to EPI-USE Labs for all your assistance. :)
-" quit when a syntax file was already loaded
+" Quit when a syntax file was already loaded
if exists("b:current_syntax")
finish
endif
@@ -55,6 +54,7 @@ syn match abapComplexStatement "\<RESPECTING\W\+BLANKS\>"
syn match abapComplexStatement "\<SEPARATED\W\+BY\>"
syn match abapComplexStatement "\<USING\(\W\+EDIT\W\+MASK\)\?\>"
syn match abapComplexStatement "\<WHERE\(\W\+LINE\)\?\>"
+syn match abapComplexStatement "\<GET\W\+\(TIME\(\W\+STAMP\)\?\(\W\+FIELD\)\?\|PF-STATUS\|BADI\|BIT\|CONNECTION\|CURSOR\|REFERENCE\W\+OF\)\>"
syn match abapComplexStatement "\<RADIOBUTTON\W\+GROUP\>"
syn match abapComplexStatement "\<REF\W\+TO\>"
syn match abapComplexStatement "\<\(PUBLIC\|PRIVATE\|PROTECTED\)\(\W\+SECTION\)\?\>"
@@ -109,7 +109,7 @@ syn keyword abapStatement CALL CASE CATCH CHECK CLASS CLEAR CLOSE CNT COLLECT CO
syn keyword abapStatement DATA DEFINE DEFINITION DEFERRED DELETE DESCRIBE DETAIL DIVIDE DO
syn keyword abapStatement ELSE ELSEIF ENDAT ENDCASE ENDCLASS ENDDO ENDEXEC ENDFORM ENDFUNCTION ENDIF ENDIFEND ENDINTERFACE ENDLOOP ENDMETHOD ENDMODULE ENDON ENDPROVIDE ENDSELECT ENDTRY ENDWHILE EVENT EVENTS EXEC EXIT EXPORT EXPORTING EXTRACT
syn keyword abapStatement FETCH FIELDS FORM FORMAT FREE FROM FUNCTION
-syn keyword abapStatement GENERATE GET
+syn keyword abapStatement GENERATE
syn keyword abapStatement HIDE
syn keyword abapStatement IF IMPORT IMPORTING INDEX INFOTYPES INITIALIZATION INTERFACE INTERFACES INPUT INSERT IMPLEMENTATION
syn keyword abapStatement LEAVE LIKE LINE LOAD LOCAL LOOP
@@ -147,7 +147,7 @@ syn keyword abapSpecial TRUE FALSE NULL SPACE
syn region abapInclude start="include" end="." contains=abapComment
" Types
-syn keyword abapTypes c n i p f d t x string xstring decfloat16 decfloat34
+syn keyword abapTypes c n i int8 p f d t x string xstring decfloat16 decfloat34
" Atritmitic operators
syn keyword abapOperator abs sign ceil floor trunc frac acos asin atan cos sin tan
@@ -193,5 +193,4 @@ hi def link abapHex Number
let b:current_syntax = "abap"
-" vim: ts=8 sw=2
-
+" vim: ts=8 sw=2 \ No newline at end of file
diff --git a/runtime/syntax/apache.vim b/runtime/syntax/apache.vim
index e2315db0d7..71babfba36 100644
--- a/runtime/syntax/apache.vim
+++ b/runtime/syntax/apache.vim
@@ -3,7 +3,7 @@
" Maintainer: David Necas (Yeti) <yeti@physics.muni.cz>
" License: This file can be redistribued and/or modified under the same terms
" as Vim itself.
-" Last Change: 2014-03-04
+" Last Change: 2018-12-06
" Notes: Last synced with apache-2.2.3, version 1.x is no longer supported
" TODO: see particular FIXME's scattered through the file
" make it really linewise?
@@ -159,7 +159,7 @@ syn keyword apacheOption inherit
syn keyword apacheDeclaration BrowserMatch BrowserMatchNoCase SetEnvIf SetEnvIfNoCase
syn keyword apacheDeclaration LoadFile LoadModule
syn keyword apacheDeclaration CheckSpelling CheckCaseOnly
-syn keyword apacheDeclaration SSLCACertificateFile SSLCACertificatePath SSLCADNRequestFile SSLCADNRequestPath SSLCARevocationFile SSLCARevocationPath SSLCertificateChainFile SSLCertificateFile SSLCertificateKeyFile SSLCipherSuite SSLCryptoDevice SSLEngine SSLHonorCipherOrder SSLMutex SSLOptions SSLPassPhraseDialog SSLProtocol SSLProxyCACertificateFile SSLProxyCACertificatePath SSLProxyCARevocationFile SSLProxyCARevocationPath SSLProxyCipherSuite SSLProxyEngine SSLProxyMachineCertificateFile SSLProxyMachineCertificatePath SSLProxyProtocol SSLProxyVerify SSLProxyVerifyDepth SSLRandomSeed SSLRequire SSLRequireSSL SSLSessionCache SSLSessionCacheTimeout SSLUserName SSLVerifyClient SSLVerifyDepth
+syn keyword apacheDeclaration SSLCACertificateFile SSLCACertificatePath SSLCADNRequestFile SSLCADNRequestPath SSLCARevocationFile SSLCARevocationPath SSLCertificateChainFile SSLCertificateFile SSLCertificateKeyFile SSLCipherSuite SSLCompression SSLCryptoDevice SSLEngine SSLFIPS SSLHonorCipherOrder SSLInsecureRenegotiation SSLMutex SSLOptions SSLPassPhraseDialog SSLProtocol SSLProxyCACertificateFile SSLProxyCACertificatePath SSLProxyCARevocationFile SSLProxyCARevocationPath SSLProxyCheckPeerCN SSLProxyCheckPeerExpire SSLProxyCipherSuite SSLProxyEngine SSLProxyMachineCertificateChainFile SSLProxyMachineCertificateFile SSLProxyMachineCertificatePath SSLProxyProtocol SSLProxyVerify SSLProxyVerifyDepth SSLRandomSeed SSLRenegBufferSize SSLRequire SSLRequireSSL SSLSessionCache SSLSessionCacheTimeout SSLSessionTicketKeyFile SSLSessionTickets SSLStrictSNIVHostCheck SSLUserName SSLVerifyClient SSLVerifyDepth
syn match apacheOption "[+-]\?\<\(StdEnvVars\|CompatEnvVars\|ExportCertData\|FakeBasicAuth\|StrictRequire\|OptRenegotiate\)\>"
syn keyword apacheOption builtin sem
syn match apacheOption "\(file\|exec\|egd\|dbm\|shm\):"
diff --git a/runtime/syntax/automake.vim b/runtime/syntax/automake.vim
index 2a215a9e04..8a7db7c27b 100644
--- a/runtime/syntax/automake.vim
+++ b/runtime/syntax/automake.vim
@@ -1,9 +1,9 @@
" Vim syntax file
-" Language: automake Makefile.am
-" Maintainer: Debian VIM Maintainers <pkg-vim-maintainers@lists.alioth.debian.org>
-" Former Maintainer: John Williams <jrw@pobox.com>
-" Last Change: 2011-06-13
-" URL: http://anonscm.debian.org/hg/pkg-vim/vim/raw-file/unstable/runtime/syntax/automake.vim
+" Language: automake Makefile.am
+" Maintainer: Debian Vim Maintainers
+" Former Maintainer: John Williams <jrw@pobox.com>
+" Last Change: 2018 Dec 27
+" URL: https://salsa.debian.org/vim-team/vim-debian/blob/master/syntax/automake.vim
"
" XXX This file is in need of a new maintainer, Debian VIM Maintainers maintain
" it only because patches have been submitted for it by Debian users and the
@@ -18,7 +18,7 @@
" EXTRA_SOURCES.
" Standard syntax initialization
-if exists("b:current_syntax")
+if exists('b:current_syntax')
finish
endif
@@ -37,8 +37,8 @@ syn match automakeConditional "^\(if\s*!\=\w\+\|else\|endif\)\s*$"
syn match automakeSubst "@\w\+@"
syn match automakeSubst "^\s*@\w\+@"
-syn match automakeComment1 "#.*$" contains=automakeSubst
-syn match automakeComment2 "##.*$"
+syn match automakeComment1 "#.*$" contains=automakeSubst,@Spell
+syn match automakeComment2 "##.*$" contains=@Spell
syn match automakeMakeError "$[{(][^})]*[^a-zA-Z0-9_})][^})]*[})]" " GNU make function call
syn match automakeMakeError "^AM_LDADD\s*\ze+\==" " Common mistake
@@ -72,6 +72,6 @@ hi def link automakeMakeSString makeSString
hi def link automakeMakeBString makeBString
-let b:current_syntax = "automake"
+let b:current_syntax = 'automake'
" vi: ts=8 sw=4 sts=4
diff --git a/runtime/syntax/c.vim b/runtime/syntax/c.vim
index 95d3455dde..2a14ae0c46 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: 2018 Sep 21
+" Last Change: 2019 Apr 23
" Quit when a (custom) syntax file was already loaded
if exists("b:current_syntax")
@@ -289,6 +289,22 @@ if !exists("c_no_c11")
syn keyword cOperator _Static_assert static_assert
syn keyword cStorageClass _Thread_local thread_local
syn keyword cType char16_t char32_t
+ " C11 atomics (take down the shield wall!)
+ syn keyword cType atomic_bool atomic_char atomic_schar atomic_uchar
+ syn keyword Ctype atomic_short atomic_ushort atomic_int atomic_uint
+ syn keyword cType atomic_long atomic_ulong atomic_llong atomic_ullong
+ syn keyword cType atomic_char16_t atomic_char32_t atomic_wchar_t
+ syn keyword cType atomic_int_least8_t atomic_uint_least8_t
+ syn keyword cType atomic_int_least16_t atomic_uint_least16_t
+ syn keyword cType atomic_int_least32_t atomic_uint_least32_t
+ syn keyword cType atomic_int_least64_t atomic_uint_least64_t
+ syn keyword cType atomic_int_fast8_t atomic_uint_fast8_t
+ syn keyword cType atomic_int_fast16_t atomic_uint_fast16_t
+ syn keyword cType atomic_int_fast32_t atomic_uint_fast32_t
+ syn keyword cType atomic_int_fast64_t atomic_uint_fast64_t
+ syn keyword cType atomic_intptr_t atomic_uintptr_t
+ syn keyword cType atomic_size_t atomic_ptrdiff_t
+ syn keyword cType atomic_intmax_t atomic_uintmax_t
endif
if !exists("c_no_ansi") || exists("c_ansi_constants") || exists("c_gnu")
@@ -342,7 +358,7 @@ if !exists("c_no_ansi") || exists("c_ansi_constants") || exists("c_gnu")
syn keyword cConstant EINPROGRESS EINTR EINVAL EIO EISCONN EISDIR ELOOP EMFILE EMLINK EMSGSIZE
syn keyword cConstant EMULTIHOP ENAMETOOLONG ENETDOWN ENETRESET ENETUNREACH ENFILE ENOBUFS ENODATA
syn keyword cConstant ENODEV ENOENT ENOEXEC ENOLCK ENOLINK ENOMEM ENOMSG ENOPROTOOPT ENOSPC ENOSR
- syn keyword cConstant ENOSTR ENOSYS ENOTCONN ENOTDIR ENOTEMPTY ENOTRECOVERABLE ENOTSOCK ENOTSUP
+ syn keyword cConstant ENOSTR ENOSYS ENOTBLK ENOTCONN ENOTDIR ENOTEMPTY ENOTRECOVERABLE ENOTSOCK ENOTSUP
syn keyword cConstant ENOTTY ENXIO EOPNOTSUPP EOVERFLOW EOWNERDEAD EPERM EPIPE EPROTO
syn keyword cConstant EPROTONOSUPPORT EPROTOTYPE ERANGE EROFS ESPIPE ESRCH ESTALE ETIME ETIMEDOUT
syn keyword cConstant ETXTBSY EWOULDBLOCK EXDEV
diff --git a/runtime/syntax/cobol.vim b/runtime/syntax/cobol.vim
index 2d481bba0b..5d649441a3 100644
--- a/runtime/syntax/cobol.vim
+++ b/runtime/syntax/cobol.vim
@@ -1,10 +1,23 @@
" Vim syntax file
" Language: COBOL
-" Maintainer: Tim Pope <vimNOSPAM@tpope.org>
+" Maintainer: Ankit Jain <ajatkj@yahoo.co.in>
+" (formerly Tim Pope <vimNOSPAM@tpope.info>)
" (formerly Davyd Ondrejko <vondraco@columbus.rr.com>)
" (formerly Sitaram Chamarty <sitaram@diac.com> and
" James Mitchell <james_mitchell@acm.org>)
-" Last Change: 2015 Feb 13
+" Last Change: 2019 Mar 22
+" Ankit Jain 22.03.2019 Changes & fixes:
+" 1. Include inline comments
+" 2. Use comment highlight for bad lines
+" 3. Change certain 'keywords' to 'matches'
+" for additional highlighting
+" 4. Different highlighting for COPY, GO TO &
+" CALL lines
+" 5. Fix for COMP keyword
+" 6. Fix for PROCEDURE DIVISION highlighting
+" 7. Highlight EXIT PROGRAM like STOP RUN
+" 8. Highlight X & A in PIC clause
+" Tag: #C22032019
" quit when a syntax file was already loaded
if exists("b:current_syntax")
@@ -12,7 +25,11 @@ if exists("b:current_syntax")
endif
" MOST important - else most of the keywords wont work!
-setlocal isk=@,48-57,-
+setlocal isk=@,48-57,-,_
+
+if !exists('g:cobol_inline_comment')
+ let g:cobol_inline_comment=0
+endif
syn case ignore
@@ -29,7 +46,10 @@ syn match cobolComment "[/*C].*$" contained
syn match cobolCompiler "$.*$" contained
syn match cobolLine ".*$" contained contains=cobolReserved,@cobolLine
-syn match cobolDivision "[A-Z][A-Z0-9-]*[A-Z0-9]\s\+DIVISION\."he=e-1 contained contains=cobolDivisionName
+"#C22032019: Fix for PROCEDURE DIVISION USING highlighting, removed . from the
+"end of the regex
+"syn match cobolDivision \"[A-Z][A-Z0-9-]*[A-Z0-9]\s\+DIVISION\."he=e-1 contained contains=cobolDivisionName
+syn match cobolDivision "[A-Z][A-Z0-9-]*[A-Z0-9]\s\+DIVISION" contained contains=cobolDivisionName
syn keyword cobolDivisionName contained IDENTIFICATION ENVIRONMENT DATA PROCEDURE
syn match cobolSection "[A-Z][A-Z0-9-]*[A-Z0-9]\s\+SECTION\."he=e-1 contained contains=cobolSectionName
syn keyword cobolSectionName contained CONFIGURATION INPUT-OUTPUT FILE WORKING-STORAGE LOCAL-STORAGE LINKAGE
@@ -38,10 +58,12 @@ syn keyword cobolParagraphName contained PROGRAM-ID SOURCE-COMPUTER OBJECT-COMP
"syn match cobolKeys "^\a\{1,6\}" contains=cobolReserved
+"#C22032019: Remove BY, REPLACING, PROGRAM, TO, IN from 'keyword' group and add
+"to 'match' group or other 'keyword' group
syn keyword cobolReserved contained ACCEPT ACCESS ADD ADDRESS ADVANCING AFTER ALPHABET ALPHABETIC
syn keyword cobolReserved contained ALPHABETIC-LOWER ALPHABETIC-UPPER ALPHANUMERIC ALPHANUMERIC-EDITED ALS
syn keyword cobolReserved contained ALTERNATE AND ANY ARE AREA AREAS ASCENDING ASSIGN AT AUTHOR BEFORE BINARY
-syn keyword cobolReserved contained BLANK BLOCK BOTTOM BY CANCEL CBLL CD CF CH CHARACTER CHARACTERS CLASS
+syn keyword cobolReserved contained BLANK BLOCK BOTTOM CANCEL CBLL CD CF CH CHARACTER CHARACTERS CLASS
syn keyword cobolReserved contained CLOCK-UNITS CLOSE COBOL CODE CODE-SET COLLATING COLUMN COMMA COMMON
syn keyword cobolReserved contained COMMUNICATIONS COMPUTATIONAL COMPUTE CONTENT CONTINUE
syn keyword cobolReserved contained CONTROL CONVERTING CORR CORRESPONDING COUNT CURRENCY DATE DATE-COMPILED
@@ -55,52 +77,79 @@ syn keyword cobolReserved contained END-REWRITE END-SEARCH END-START END-STRING
syn keyword cobolReserved contained END-WRITE EQUAL ERROR ESI EVALUATE EVERY EXCEPTION EXIT
syn keyword cobolReserved contained EXTEND EXTERNAL FALSE FD FILLER FINAL FIRST FOOTING FOR FROM
syn keyword cobolReserved contained GENERATE GIVING GLOBAL GREATER GROUP HEADING HIGH-VALUE HIGH-VALUES I-O
-syn keyword cobolReserved contained IN INDEX INDEXED INDICATE INITIAL INITIALIZE
+syn keyword cobolReserved contained INDEX INDEXED INDICATE INITIAL INITIALIZE
syn keyword cobolReserved contained INITIATE INPUT INSPECT INSTALLATION INTO IS JUST
syn keyword cobolReserved contained JUSTIFIED KEY LABEL LAST LEADING LEFT LENGTH LOCK MEMORY
syn keyword cobolReserved contained MERGE MESSAGE MODE MODULES MOVE MULTIPLE MULTIPLY NATIVE NEGATIVE NEXT NO NOT
syn keyword cobolReserved contained NUMBER NUMERIC NUMERIC-EDITED OCCURS OF OFF OMITTED ON OPEN
syn keyword cobolReserved contained OPTIONAL OR ORDER ORGANIZATION OTHER OUTPUT OVERFLOW PACKED-DECIMAL PADDING
syn keyword cobolReserved contained PAGE PAGE-COUNTER PERFORM PF PH PIC PICTURE PLUS POINTER POSITION POSITIVE
-syn keyword cobolReserved contained PRINTING PROCEDURES PROCEDD PROGRAM PURGE QUEUE QUOTES
+syn keyword cobolReserved contained PRINTING PROCEDURES PROCEDD PURGE QUEUE QUOTES
syn keyword cobolReserved contained RANDOM RD READ RECEIVE RECORD RECORDS REDEFINES REEL REFERENCE REFERENCES
-syn keyword cobolReserved contained RELATIVE RELEASE REMAINDER REMOVAL REPLACE REPLACING REPORT REPORTING
+syn keyword cobolReserved contained RELATIVE RELEASE REMAINDER REMOVAL REPLACE REPORT REPORTING
syn keyword cobolReserved contained REPORTS RERUN RESERVE RESET RETURN RETURNING REVERSED REWIND REWRITE RF RH
syn keyword cobolReserved contained RIGHT ROUNDED RUN SAME SD SEARCH SECTION SECURITY SEGMENT SEGMENT-LIMITED
syn keyword cobolReserved contained SELECT SEND SENTENCE SEPARATE SEQUENCE SEQUENTIAL SET SIGN SIZE SORT
syn keyword cobolReserved contained SORT-MERGE SOURCE STANDARD
syn keyword cobolReserved contained STANDARD-1 STANDARD-2 START STATUS STOP STRING SUB-QUEUE-1 SUB-QUEUE-2
syn keyword cobolReserved contained SUB-QUEUE-3 SUBTRACT SUM SUPPRESS SYMBOLIC SYNC SYNCHRONIZED TABLE TALLYING
-syn keyword cobolReserved contained TAPE TERMINAL TERMINATE TEST TEXT THAN THEN THROUGH THRU TIME TIMES TO TOP
+syn keyword cobolReserved contained TAPE TERMINAL TERMINATE TEST TEXT THAN THEN THROUGH THRU TIME TIMES TOP
syn keyword cobolReserved contained TRAILING TRUE TYPE UNIT UNSTRING UNTIL UP UPON USAGE USE USING VALUE VALUES
syn keyword cobolReserved contained VARYING WHEN WITH WORDS WRITE
syn match cobolReserved contained "\<CONTAINS\>"
syn match cobolReserved contained "\<\(IF\|INVALID\|END\|EOP\)\>"
syn match cobolReserved contained "\<ALL\>"
+" #C22032019: Add BY as match instead of keyword: BY not followed by ==
+syn match cobolReserved contained "\<BY\>\s\+\(==\)\@!"
+syn match cobolReserved contained "\<TO\>"
syn cluster cobolLine add=cobolConstant,cobolNumber,cobolPic
syn keyword cobolConstant SPACE SPACES NULL ZERO ZEROES ZEROS LOW-VALUE LOW-VALUES
+" #C22032019: Fix for many pic clauses
syn match cobolNumber "\<-\=\d*\.\=\d\+\>" contained
-syn match cobolPic "\<S*9\+\>" contained
+" syn match cobolPic \"\<S*9\+\>" contained
+syn match cobolPic "\<S*9\+V*9*\>" contained
syn match cobolPic "\<$*\.\=9\+\>" contained
syn match cobolPic "\<Z*\.\=9\+\>" contained
syn match cobolPic "\<V9\+\>" contained
syn match cobolPic "\<9\+V\>" contained
-syn match cobolPic "\<-\+[Z9]\+\>" contained
-syn match cobolTodo "todo" contained containedin=cobolComment
+" syn match cobolPic \"\<-\+[Z9]\+\>" contained
+syn match cobolPic "\<-*[Z9]\+-*\>" contained
+" #C22032019: Add Z,X and A to cobolPic
+syn match cobolPic "\<[ZXA]\+\>" contained
+syn match cobolTodo "todo" contained containedin=cobolInlineComment,cobolComment
" For MicroFocus or other inline comments, include this line.
-" syn region cobolComment start="*>" end="$" contains=cobolTodo,cobolMarker
+if g:cobol_inline_comment == 1
+ syn region cobolInlineComment start="*>" end="$" contains=cobolTodo,cobolMarker
+ syn cluster cobolLine add=cobolInlineComment
+endif
syn match cobolBadLine "[^ D\*$/-].*" contained
+
" If comment mark somehow gets into column past Column 7.
-syn match cobolBadLine "\s\+\*.*" contained
+if g:cobol_inline_comment == 1
+ " #C22032019: It is a bad line only if * is not followed by > when inline
+ " comments enabled
+ syn match cobolBadLine "\s\+\*\(>\)\@!.*" contained
+else
+ syn match cobolBadLine "\s\+\*.*" contained
+endif
syn cluster cobolStart add=cobolBadLine
-
-syn keyword cobolGoTo GO GOTO
-syn keyword cobolCopy COPY
+" #C22032019: Different highlighting for GO TO statements
+" syn keyword cobolGoTo GO GOTO
+syn keyword cobolGoTo GOTO
+syn match cobolGoTo /\<GO\>\s\+\<TO\>/
+syn match cobolGoToPara /\<GO\>\s\+\<TO\>\s\+[A-Z0-9-]\+/ contains=cobolGoTo
+" #C22032019: Highlight copybook name and location in using different group
+" syn keyword cobolCopy COPY
+syn match cobolCopy "\<COPY\>\|\<IN\>"
+syn match cobolCopy "\<REPLACING\>\s\+\(==\)\@="
+syn match cobolCopy "\<BY\>\s\+\(==\)\@="
+syn match cobolCopyName "\<COPY\>\s\+[A-Z0-9]\+\(\s\+\<IN\>\s\+[A-Z0-9]\+\)\?" contains=cobolCopy
+syn cluster cobolLine add=cobolGoToPara,cobolCopyName
" cobolBAD: things that are BAD NEWS!
syn keyword cobolBAD ALTER ENTER RENAMES
@@ -109,8 +158,14 @@ syn cluster cobolLine add=cobolGoTo,cobolCopy,cobolBAD,cobolWatch,cobolEXE
" cobolWatch: things that are important when trying to understand a program
syn keyword cobolWatch OCCURS DEPENDING VARYING BINARY COMP REDEFINES
-syn keyword cobolWatch REPLACING RUN
-syn match cobolWatch "COMP-[123456XN]"
+" #C22032019: Remove REPLACING from cobolWatch 'keyword' group and add to cobolCopy &
+" cobolWatch 'match' group
+" syn keyword cobolWatch REPLACING RUN
+syn keyword cobolWatch RUN PROGRAM
+syn match cobolWatch contained "\<REPLACING\>\s\+\(==\)\@!"
+" #C22032019: Look for word starting with COMP
+" syn match cobolWatch \"COMP-[123456XN]"
+syn match cobolWatch "\<COMP-[123456XN]"
syn keyword cobolEXECs EXEC END-EXEC
@@ -127,9 +182,15 @@ syn match cobolWatch "88 " contained nextgroup=cobolLine
"syn match cobolBadID "\k\+-\($\|[^-A-Z0-9]\)" contained
syn cluster cobolLine add=cobolCALLs,cobolString,cobolCondFlow
-syn keyword cobolCALLs CALL END-CALL CANCEL GOBACK PERFORM END-PERFORM INVOKE
-syn match cobolCALLs "EXIT \+PROGRAM"
+" #C22032019: Changes for cobolCALLs group to include thru
+" syn keyword cobolCALLs CALL END-CALL CANCEL GOBACK PERFORM END-PERFORM INVOKE
+syn keyword cobolCALLs END-CALL CANCEL GOBACK PERFORM END-PERFORM INVOKE THRU
+" #C22032019: Highlight called program
+" syn match cobolCALLs \"EXIT \+PROGRAM"
+syn match cobolCALLs "\<CALL\>"
+syn match cobolCALLProg /\<CALL\>\s\+"\{0,1\}[A-Z0-9]\+"\{0,1\}/ contains=cobolCALLs
syn match cobolExtras /\<VALUE \+\d\+\./hs=s+6,he=e-1
+syn cluster cobolLine add=cobolCALLProg
syn match cobolString /"[^"]*\("\|$\)/
syn match cobolString /'[^']*\('\|$\)/
@@ -138,7 +199,7 @@ syn match cobolString /'[^']*\('\|$\)/
syn match cobolIndicator "\%7c[D-]" contained
if exists("cobol_legacy_code")
- syn region cobolCondFlow contains=ALLBUT,cobolLine,cobolBadLine start="\<\(IF\|INVALID\|END\|EOP\)\>" skip=/\('\|"\)[^"]\{-}\("\|'\|$\)/ end="\." keepend
+ syn region cobolCondFlow contains=ALLBUT,cobolLine start="\<\(IF\|INVALID\|END\|EOP\)\>" skip=/\('\|"\)[^"]\{-}\("\|'\|$\)/ end="\." keepend
endif
" many legacy sources have junk in columns 1-6: must be before others
@@ -146,7 +207,9 @@ endif
if exists("cobol_legacy_code")
syn match cobolBadLine "\%73c.*" containedin=ALLBUT,cobolComment
else
- syn match cobolBadLine "\%73c.*" containedin=ALL
+ " #C22032019: Use comment highlighting for bad lines
+ " syn match cobolBadLine \"\%73c.*" containedin=ALL
+ syn match cobolBadLine "\%73c.*" containedin=ALL,cobolInlineComment,cobolComment
endif
" Define the default highlighting.
@@ -160,31 +223,36 @@ if exists("g:cobol_legacy_code")
else
hi def link cobolMarker Error
endif
-hi def link cobolCALLs Function
-hi def link cobolComment Comment
-hi def link cobolKeys Comment
-hi def link cobolAreaB Special
-hi def link cobolCompiler PreProc
-hi def link cobolCondFlow Special
-hi def link cobolCopy PreProc
-hi def link cobolDeclA cobolDecl
-hi def link cobolDecl Type
-hi def link cobolExtras Special
-hi def link cobolGoTo Special
-hi def link cobolConstant Constant
-hi def link cobolNumber Constant
-hi def link cobolPic Constant
-hi def link cobolReserved Statement
-hi def link cobolDivision Label
-hi def link cobolSection Label
-hi def link cobolParagraph Label
-hi def link cobolDivisionName Keyword
-hi def link cobolSectionName Keyword
-hi def link cobolParagraphName Keyword
-hi def link cobolString Constant
-hi def link cobolTodo Todo
-hi def link cobolWatch Special
-hi def link cobolIndicator Special
+hi def link cobolCALLs Function
+hi def link cobolCALLProg Special
+hi def link cobolComment Comment
+hi def link cobolInlineComment Comment
+hi def link cobolKeys Comment
+hi def link cobolAreaB Special
+hi def link cobolCompiler PreProc
+hi def link cobolCondFlow Special
+hi def link cobolCopy PreProc
+hi def link cobolCopyName Special
+hi def link cobolDeclA cobolDecl
+hi def link cobolDecl Type
+hi def link cobolExtras Special
+hi def link cobolGoTo Special
+hi def link cobolGoToPara Function
+hi def link cobolConstant Constant
+hi def link cobolNumber Constant
+hi def link cobolPic Constant
+hi def link cobolReserved Statement
+hi def link cobolDivision Label
+hi def link cobolSection Label
+hi def link cobolParagraph Label
+hi def link cobolDivisionName Keyword
+hi def link cobolSectionName Keyword
+hi def link cobolParagraphName Keyword
+hi def link cobolString Constant
+hi def link cobolTodo Todo
+hi def link cobolWatch Special
+hi def link cobolIndicator Special
+hi def link cobolStart Comment
let b:current_syntax = "cobol"
diff --git a/runtime/syntax/cs.vim b/runtime/syntax/cs.vim
index 116afe0b72..1652cb63c3 100644
--- a/runtime/syntax/cs.vim
+++ b/runtime/syntax/cs.vim
@@ -3,7 +3,7 @@
" Maintainer: Nick Jensen <nickspoon@gmail.com>
" Former Maintainers: Anduin Withers <awithers@anduin.com>
" Johannes Zellner <johannes@zellner.org>
-" Last Change: 2018-06-29
+" Last Change: 2018-11-26
" Filenames: *.cs
" License: Vim (see :h license)
" Repository: https://github.com/nickspoons/vim-cs
@@ -11,12 +11,12 @@
" REFERENCES:
" [1] ECMA TC39: C# Language Specification (WD13Oct01.doc)
-if exists("b:current_syntax")
- finish
+if exists('b:current_syntax')
+ finish
endif
-let s:cs_cpo_save = &cpo
-set cpo&vim
+let s:save_cpo = &cpoptions
+set cpoptions&vim
syn keyword csType bool byte char decimal double float int long object sbyte short string T uint ulong ushort var void dynamic
@@ -34,7 +34,7 @@ syn keyword csException try catch finally throw when
syn keyword csLinq ascending by descending equals from group in into join let on orderby select where
syn keyword csAsync async await
-syn keyword csUnspecifiedStatement as base checked event fixed in is lock nameof operator out params ref sizeof stackalloc this typeof unchecked unsafe using
+syn keyword csUnspecifiedStatement as base checked event fixed in is lock nameof operator out params ref sizeof stackalloc this unchecked unsafe using
syn keyword csUnsupportedStatement add remove value
syn keyword csUnspecifiedKeyword explicit implicit
@@ -44,10 +44,16 @@ syn match csContextualStatement /\<partial[[:space:]\n]\+\(class\|struct\|interf
syn match csContextualStatement /\<\(get\|set\)\(;\|[[:space:]\n]*{\)/me=s+3
syn match csContextualStatement /\<where\>[^:]\+:/me=s+5
+" Operators
+syn keyword csTypeOf typeof contained
+syn region csTypeOfStatement start="typeof(" end=")" contains=csType, csTypeOf
+
" Punctuation
syn match csBraces "[{}\[\]]" display
syn match csParens "[()]" display
-syn match csOpSymbols "[+\-><=]\{1,2}" display
+syn match csOpSymbols "[+\-=]\{1,2}" display
+syn match csOpSymbols "[><]\{2}" display
+syn match csOpSymbols "\s\zs[><]\ze\_s" display
syn match csOpSymbols "[!><+\-*/]=" display
syn match csOpSymbols "[!*/^]" display
syn match csOpSymbols "=>" display
@@ -144,17 +150,18 @@ syn cluster csAll contains=csCharacter,csClassType,csComment,csContextualStateme
" The default highlighting.
hi def link csType Type
-hi def link csNewType Type
hi def link csClassType Type
hi def link csIsType Type
-hi def link csStorage StorageClass
-hi def link csClass StorageClass
+hi def link csStorage Structure
+hi def link csClass Structure
hi def link csRepeat Repeat
hi def link csConditional Conditional
hi def link csLabel Label
hi def link csModifier StorageClass
hi def link csConstant Constant
hi def link csException Exception
+hi def link csTypeOf Operator
+hi def link csTypeOfStatement Typedef
hi def link csUnspecifiedStatement Statement
hi def link csUnsupportedStatement Statement
hi def link csUnspecifiedKeyword Keyword
@@ -164,16 +171,12 @@ hi def link csIsAs Keyword
hi def link csAsync Keyword
hi def link csContextualStatement Statement
hi def link csOperatorError Error
-hi def link csInterfaceDeclaration Include
hi def link csTodo Todo
hi def link csComment Comment
-hi def link csEndColon Statement
hi def link csOpSymbols Operator
-hi def link csLogicSymbols Boolean
-hi def link csBraces Function
-hi def link csParens Operator
+hi def link csLogicSymbols Operator
hi def link csSpecialError Error
hi def link csSpecialCharError Error
@@ -200,9 +203,9 @@ hi def link csXmlCommentLeader Comment
hi def link csXmlComment Comment
hi def link csXmlTag Statement
-let b:current_syntax = "cs"
+let b:current_syntax = 'cs'
-let &cpo = s:cs_cpo_save
-unlet s:cs_cpo_save
+let &cpoptions = s:save_cpo
+unlet s:save_cpo
" vim: vts=16,28
diff --git a/runtime/syntax/dcl.vim b/runtime/syntax/dcl.vim
index b973db3434..c0d0ebcf95 100644
--- a/runtime/syntax/dcl.vim
+++ b/runtime/syntax/dcl.vim
@@ -1,8 +1,8 @@
" Vim syntax file
" Language: DCL (Digital Command Language - vms)
" Maintainer: Charles E. Campbell <NdrOchipS@PcampbellAfamily.Mbiz>
-" Last Change: Aug 31, 2016
-" Version: 11
+" Last Change: Mar 26, 2019
+" Version: 12
" URL: http://www.drchip.org/astronaut/vim/index.html#SYNTAX_DCL
" quit when a syntax file was already loaded
@@ -10,10 +10,10 @@ if exists("b:current_syntax")
finish
endif
-if !has("patch-7.4.1142")
- setlocal iskeyword=$,@,48-57,_
-else
+if (v:version == 704 && has("patch-7.4.1142")) || v:version > 704
syn iskeyword $,@,48-57,_
+else
+ setlocal iskeyword=$,@,48-57,_
endif
syn case ignore
diff --git a/runtime/syntax/debchangelog.vim b/runtime/syntax/debchangelog.vim
index edaaf6128f..9d6dfe96a5 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: 2018 May 03
+" Last Change: 2019 Apr 21
" URL: https://salsa.debian.org/vim-team/vim-debian/blob/master/syntax/debchangelog.vim
" Standard syntax initialization
@@ -14,14 +14,14 @@ endif
" Case doesn't matter for us
syn case ignore
-let s:urgency='urgency=\(low\|medium\|high\|critical\)\( [^[:space:],][^,]*\)\='
+let s:urgency='urgency=\(low\|medium\|high\|emergency\|critical\)\( [^[:space:],][^,]*\)\='
let s:binNMU='binary-only=yes'
" Define some common expressions we can use later on
syn match debchangelogName contained "^[[:alnum:]][[:alnum:].+-]\+ "
exe 'syn match debchangelogFirstKV contained "; \('.s:urgency.'\|'.s:binNMU.'\)"'
exe 'syn match debchangelogOtherKV contained ", \('.s:urgency.'\|'.s:binNMU.'\)"'
-syn match debchangelogTarget contained "\v %(frozen|unstable|sid|%(testing|%(old)=stable)%(-proposed-updates|-security)=|experimental|squeeze-%(backports%(-sloppy)=|volatile|lts|security)|%(wheezy|jessie)%(-backports%(-sloppy)=|-security)=|stretch%(-backports|-security)=|%(devel|precise|trusty|vivid|wily|xenial|yakkety|zesty|artful|bionic|cosmic)%(-%(security|proposed|updates|backports|commercial|partner))=)+"
+syn match debchangelogTarget contained "\v %(frozen|unstable|sid|%(testing|%(old)=stable)%(-proposed-updates|-security)=|experimental|%(squeeze|wheezy|jessie)-%(backports%(-sloppy)=|lts|security)|stretch%(-backports%(-sloppy)=|-security)=|buster%(-backports|-security)=|bullseye|%(devel|precise|trusty|vivid|wily|xenial|yakkety|zesty|artful|bionic|cosmic|disco|eoan)%(-%(security|proposed|updates|backports|commercial|partner))=)+"
syn match debchangelogVersion contained "(.\{-})"
syn match debchangelogCloses contained "closes:\_s*\(bug\)\=#\=\_s\=\d\+\(,\_s*\(bug\)\=#\=\_s\=\d\+\)*"
syn match debchangelogLP contained "\clp:\s\+#\d\+\(,\s*#\d\+\)*"
diff --git a/runtime/syntax/debsources.vim b/runtime/syntax/debsources.vim
index 74e8d42d1c..f90476fe25 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: 2018 Aug 11
+" Last Change: 2019 Apr 21
" URL: https://salsa.debian.org/vim-team/vim-debian/blob/master/syntax/debsources.vim
" Standard syntax initialization
@@ -23,9 +23,10 @@ let s:cpo = &cpo
set cpo-=C
let s:supported = [
\ 'oldstable', 'stable', 'testing', 'unstable', 'experimental',
- \ 'wheezy', 'jessie', 'stretch', 'sid', 'rc-buggy',
+ \ 'wheezy', 'jessie', 'stretch', 'buster', 'bullseye', 'bookworm',
+ \ 'sid', 'rc-buggy',
\
- \ 'trusty', 'xenial', 'bionic', 'cosmic', 'devel'
+ \ 'trusty', 'xenial', 'bionic', 'cosmic', 'disco', 'eoan', 'devel'
\ ]
let s:unsupported = [
\ 'buzz', 'rex', 'bo', 'hamm', 'slink', 'potato',
diff --git a/runtime/syntax/dune.vim b/runtime/syntax/dune.vim
new file mode 100644
index 0000000000..f901813d24
--- /dev/null
+++ b/runtime/syntax/dune.vim
@@ -0,0 +1,46 @@
+" Language: Dune buildsystem
+" Maintainer: Markus Mottl <markus.mottl@gmail.com>
+" Anton Kochkov <anton.kochkov@gmail.com>
+" URL: https://github.com/rgrinberg/vim-ocaml
+" Last Change:
+" 2019 Feb 27 - Add newer keywords to the syntax (Simon Cruanes)
+" 2018 May 8 - Check current_syntax (Kawahara Satoru)
+" 2018 Mar 29 - Extend jbuild syntax with more keywords (Petter A. Urkedal)
+" 2017 Sep 6 - Initial version (Etienne Millon)
+
+if exists("b:current_syntax")
+ finish
+endif
+
+set syntax=lisp
+syn case match
+
+" The syn-iskeyword setting lacks #,? from the iskeyword setting here.
+" Clearing it avoids maintaining keyword characters in multiple places.
+syn iskeyword clear
+
+syn keyword lispDecl jbuild_version library executable executables rule ocamllex ocamlyacc menhir alias install
+
+syn keyword lispKey name public_name synopsis modules libraries wrapped
+syn keyword lispKey preprocess preprocessor_deps optional c_names cxx_names
+syn keyword lispKey install_c_headers modes no_dynlink self_build_stubs_archive
+syn keyword lispKey ppx_runtime_libraries virtual_deps js_of_ocaml link_flags
+syn keyword lispKey javascript_files flags ocamlc_flags ocamlopt_flags pps staged_pps
+syn keyword lispKey library_flags c_flags c_library_flags kind package action
+syn keyword lispKey deps targets locks fallback
+syn keyword lispKey inline_tests tests names
+
+syn keyword lispAtom true false
+
+syn keyword lispFunc cat chdir copy# diff? echo run setenv
+syn keyword lispFunc ignore-stdout ignore-stderr ignore-outputs
+syn keyword lispFunc with-stdout-to with-stderr-to with-outputs-to
+syn keyword lispFunc write-file system bash
+
+syn cluster lispBaseListCluster add=duneVar
+syn match duneVar '\${[@<^]}' containedin=lispSymbol
+syn match duneVar '\${\k\+\(:\k\+\)\?}' containedin=lispSymbol
+
+hi def link duneVar Identifier
+
+let b:current_syntax = "dune"
diff --git a/runtime/syntax/eruby.vim b/runtime/syntax/eruby.vim
index 4e175bcc25..6bb24fe562 100644
--- a/runtime/syntax/eruby.vim
+++ b/runtime/syntax/eruby.vim
@@ -3,8 +3,9 @@
" Maintainer: Tim Pope <vimNOSPAM@tpope.org>
" URL: https://github.com/vim-ruby/vim-ruby
" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
+" Last Change: 2018 Jul 04
-if exists("b:current_syntax")
+if &syntax !~# '\<eruby\>' || get(b:, 'current_syntax') =~# '\<eruby\>'
finish
endif
@@ -18,11 +19,13 @@ endif
if &filetype =~ '^eruby\.'
let b:eruby_subtype = matchstr(&filetype,'^eruby\.\zs\w\+')
+elseif &filetype =~ '^.*\.eruby\>'
+ let b:eruby_subtype = matchstr(&filetype,'^.\{-\}\ze\.eruby\>')
elseif !exists("b:eruby_subtype") && main_syntax == 'eruby'
let s:lines = getline(1)."\n".getline(2)."\n".getline(3)."\n".getline(4)."\n".getline(5)."\n".getline("$")
let b:eruby_subtype = matchstr(s:lines,'eruby_subtype=\zs\w\+')
if b:eruby_subtype == ''
- let b:eruby_subtype = matchstr(substitute(expand("%:t"),'\c\%(\.erb\|\.eruby\|\.erubis\)\+$','',''),'\.\zs\w\+\%(\ze+\w\+\)\=$')
+ let b:eruby_subtype = matchstr(substitute(expand("%:t"),'\c\%(\.erb\|\.eruby\|\.erubis\|\.example\)\+$','',''),'\.\zs\w\+\%(\ze+\w\+\)\=$')
endif
if b:eruby_subtype == 'rhtml'
let b:eruby_subtype = 'html'
@@ -41,16 +44,20 @@ elseif !exists("b:eruby_subtype") && main_syntax == 'eruby'
endif
if !exists("b:eruby_nest_level")
- let b:eruby_nest_level = strlen(substitute(substitute(substitute(expand("%:t"),'@','','g'),'\c\.\%(erb\|rhtml\)\>','@','g'),'[^@]','','g'))
+ if &syntax =~# '\<eruby\.eruby\>'
+ let b:eruby_nest_level = strlen(substitute(substitute(&filetype,'\C\<eruby\>','@','g'),'[^@]','','g'))
+ else
+ let b:eruby_nest_level = strlen(substitute(substitute(substitute(expand("%:t"),'@','','g'),'\c\.\%(erb\|rhtml\)\>','@','g'),'[^@]','','g'))
+ endif
endif
if !b:eruby_nest_level
let b:eruby_nest_level = 1
endif
-if exists("b:eruby_subtype") && b:eruby_subtype != ''
+if get(b:, 'eruby_subtype', '') !~# '^\%(eruby\)\=$' && &syntax =~# '^eruby\>'
exe "runtime! syntax/".b:eruby_subtype.".vim"
- unlet! b:current_syntax
endif
+unlet! b:current_syntax
syn include @rubyTop syntax/ruby.vim
syn cluster erubyRegions contains=erubyOneLiner,erubyBlock,erubyExpression,erubyComment
@@ -65,7 +72,7 @@ exe 'syn region erubyComment matchgroup=erubyDelimiter start="<%\{1,'.b:erub
hi def link erubyDelimiter PreProc
hi def link erubyComment Comment
-let b:current_syntax = 'eruby'
+let b:current_syntax = matchstr(&syntax, '^.*\<eruby\>')
if main_syntax == 'eruby'
unlet main_syntax
diff --git a/runtime/syntax/fstab.vim b/runtime/syntax/fstab.vim
index 56237c0770..e416a9abfc 100644
--- a/runtime/syntax/fstab.vim
+++ b/runtime/syntax/fstab.vim
@@ -2,8 +2,8 @@
" Language: fstab file
" Maintainer: Radu Dineiu <radu.dineiu@gmail.com>
" URL: https://raw.github.com/rid9/vim-fstab/master/fstab.vim
-" Last Change: 2017 Nov 09
-" Version: 1.2
+" Last Change: 2019 Jun 06
+" Version: 1.3
"
" Credits:
" David Necas (Yeti) <yeti@physics.muni.cz>
@@ -68,7 +68,7 @@ syn match fsOptionsString /[a-zA-Z0-9_-]\+/
syn keyword fsOptionsYesNo yes no
syn cluster fsOptionsCheckCluster contains=fsOptionsExt2Check,fsOptionsFatCheck
syn keyword fsOptionsSize 512 1024 2048
-syn keyword fsOptionsGeneral async atime auto bind current defaults dev devgid devmode devmtime devuid dirsync exec force fstab kudzu loop mand move noatime noauto noclusterr noclusterw nodev nodevmtime nodiratime noexec nomand norelatime nosuid nosymfollow nouser owner rbind rdonly relatime remount ro rq rw suid suiddir supermount sw sync union update user users wxallowed xx
+syn keyword fsOptionsGeneral async atime auto bind current defaults dev devgid devmode devmtime devuid dirsync exec force fstab kudzu loop mand move noatime noauto noclusterr noclusterw nodev nodevmtime nodiratime noexec nomand norelatime nosuid nosymfollow nouser owner rbind rdonly relatime remount ro rq rw suid suiddir supermount sw sync union update user users wxallowed xx nofail
syn match fsOptionsGeneral /_netdev/
" Options: adfs
diff --git a/runtime/syntax/help.vim b/runtime/syntax/help.vim
index db5ad3728c..642d177cdd 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: 2017 Oct 19
+" Last Change: 2019 May 12
" Quit when a (custom) syntax file was already loaded
if exists("b:current_syntax")
@@ -11,7 +11,7 @@ endif
let s:cpo_save = &cpo
set cpo&vim
-syn match helpHeadline "^[-A-Z .][-A-Z0-9 .()]*[ \t]\+\*"me=e-1
+syn match helpHeadline "^[-A-Z .][-A-Z0-9 .()_]*[ \t]\+\*"me=e-1
syn match helpSectionDelim "^===.*===$"
syn match helpSectionDelim "^---.*--$"
if has("conceal")
diff --git a/runtime/syntax/hitest.vim b/runtime/syntax/hitest.vim
index 1e39451dcd..9d60cec802 100644
--- a/runtime/syntax/hitest.vim
+++ b/runtime/syntax/hitest.vim
@@ -1,8 +1,9 @@
" Vim syntax file
" Language: none; used to see highlighting
" Maintainer: Ronald Schild <rs@scutum.de>
-" Last Change: 2017 Jul 28
+" Last Change: 2019 Jun 06
" Version: 5.4n.1
+" Additional Changes By: Lifepillar, Bram
" To see your current highlight settings, do
" :so $VIMRUNTIME/syntax/hitest.vim
@@ -12,6 +13,7 @@ let s:hidden = &hidden
let s:lazyredraw = &lazyredraw
let s:more = &more
let s:report = &report
+let s:whichwrap = &whichwrap
let s:shortmess = &shortmess
let s:wrapscan = &wrapscan
let s:register_a = @a
@@ -19,10 +21,11 @@ let s:register_se = @/
" set global options
set hidden lazyredraw nomore report=99999 shortmess=aoOstTW wrapscan
+set whichwrap&
" print current highlight settings into register a
redir @a
-highlight
+silent highlight
redir END
" Open a new window if the current one isn't empty
@@ -34,25 +37,32 @@ endif
edit Highlight\ test
" set local options
-setlocal autoindent noexpandtab formatoptions=t shiftwidth=16 noswapfile tabstop=16
+setlocal autoindent noexpandtab formatoptions=t shiftwidth=18 noswapfile tabstop=18
let &textwidth=&columns
" insert highlight settings
% delete
put a
+" remove cleared groups
+silent! g/ cleared$/d
+
" remove the colored xxx items
g/xxx /s///e
" remove color settings (not needed here)
global! /links to/ substitute /\s.*$//e
+" Move split 'links to' lines to the same line
+% substitute /^\(\w\+\)\n\s*\(links to.*\)/\1\t\2/e
+
" move linked groups to the end of file
global /links to/ move $
" move linked group names to the matching preferred groups
+" TODO: this fails if the group linked to isn't defined
% substitute /^\(\w\+\)\s*\(links to\)\s*\(\w\+\)$/\3\t\2 \1/e
-global /links to/ normal mz3ElD0#$p'zdd
+silent! global /links to/ normal mz3ElD0#$p'zdd
" delete empty lines
global /^ *$/ delete
@@ -124,6 +134,7 @@ let &lazyredraw = s:lazyredraw
let &more = s:more
let &report = s:report
let &shortmess = s:shortmess
+let &whichwrap = s:whichwrap
let &wrapscan = s:wrapscan
let @a = s:register_a
@@ -133,6 +144,6 @@ let @/ = s:register_se
" remove variables
unlet s:hidden s:lazyredraw s:more s:report s:shortmess
-unlet s:wrapscan s:register_a s:register_se
+unlet s:whichwrap s:wrapscan s:register_a s:register_se
" vim: ts=8
diff --git a/runtime/syntax/html.vim b/runtime/syntax/html.vim
index cde5269d02..d16ee1817f 100644
--- a/runtime/syntax/html.vim
+++ b/runtime/syntax/html.vim
@@ -3,8 +3,8 @@
" Maintainer: Jorge Maldonado Ventura <jorgesumle@freakspot.net>
" Previous Maintainer: Claudio Fleiner <claudio@fleiner.com>
" Repository: https://notabug.org/jorgesumle/vim-html-syntax
-" Last Change: 2018 May 31
-" Included patch from Jay Sitter to add WAI-ARIA htmlArg keywords
+" Last Change: 2018 Apr 7
+" Included patch from Jorge Maldonado Ventura to fix rendering
"
" Please check :help html.vim for some comments and a description of the options
@@ -159,47 +159,47 @@ if !exists("html_no_rendering")
" rendering
syn cluster htmlTop contains=@Spell,htmlTag,htmlEndTag,htmlSpecialChar,htmlPreProc,htmlComment,htmlLink,javaScript,@htmlPreproc
- syn region htmlStrike start="<del\>" end="</del>"me=e-6 contains=@htmlTop
- syn region htmlStrike start="<strike\>" end="</strike>"me=e-9 contains=@htmlTop
-
- syn region htmlBold start="<b\>" end="</b>"me=e-4 contains=@htmlTop,htmlBoldUnderline,htmlBoldItalic
- syn region htmlBold start="<strong\>" end="</strong>"me=e-9 contains=@htmlTop,htmlBoldUnderline,htmlBoldItalic
- syn region htmlBoldUnderline contained start="<u\>" end="</u>"me=e-4 contains=@htmlTop,htmlBoldUnderlineItalic
- syn region htmlBoldItalic contained start="<i\>" end="</i>"me=e-4 contains=@htmlTop,htmlBoldItalicUnderline
- syn region htmlBoldItalic contained start="<em\>" end="</em>"me=e-5 contains=@htmlTop,htmlBoldItalicUnderline
- syn region htmlBoldUnderlineItalic contained start="<i\>" end="</i>"me=e-4 contains=@htmlTop
- syn region htmlBoldUnderlineItalic contained start="<em\>" end="</em>"me=e-5 contains=@htmlTop
- syn region htmlBoldItalicUnderline contained start="<u\>" end="</u>"me=e-4 contains=@htmlTop,htmlBoldUnderlineItalic
-
- syn region htmlUnderline start="<u\>" end="</u>"me=e-4 contains=@htmlTop,htmlUnderlineBold,htmlUnderlineItalic
- syn region htmlUnderlineBold contained start="<b\>" end="</b>"me=e-4 contains=@htmlTop,htmlUnderlineBoldItalic
- syn region htmlUnderlineBold contained start="<strong\>" end="</strong>"me=e-9 contains=@htmlTop,htmlUnderlineBoldItalic
- syn region htmlUnderlineItalic contained start="<i\>" end="</i>"me=e-4 contains=@htmlTop,htmlUnderlineItalicBold
- syn region htmlUnderlineItalic contained start="<em\>" end="</em>"me=e-5 contains=@htmlTop,htmlUnderlineItalicBold
- syn region htmlUnderlineItalicBold contained start="<b\>" end="</b>"me=e-4 contains=@htmlTop
- syn region htmlUnderlineItalicBold contained start="<strong\>" end="</strong>"me=e-9 contains=@htmlTop
- syn region htmlUnderlineBoldItalic contained start="<i\>" end="</i>"me=e-4 contains=@htmlTop
- syn region htmlUnderlineBoldItalic contained start="<em\>" end="</em>"me=e-5 contains=@htmlTop
-
- syn region htmlItalic start="<i\>" end="</i>"me=e-4 contains=@htmlTop,htmlItalicBold,htmlItalicUnderline
- syn region htmlItalic start="<em\>" end="</em>"me=e-5 contains=@htmlTop
- syn region htmlItalicBold contained start="<b\>" end="</b>"me=e-4 contains=@htmlTop,htmlItalicBoldUnderline
- syn region htmlItalicBold contained start="<strong\>" end="</strong>"me=e-9 contains=@htmlTop,htmlItalicBoldUnderline
- syn region htmlItalicBoldUnderline contained start="<u\>" end="</u>"me=e-4 contains=@htmlTop
- syn region htmlItalicUnderline contained start="<u\>" end="</u>"me=e-4 contains=@htmlTop,htmlItalicUnderlineBold
- syn region htmlItalicUnderlineBold contained start="<b\>" end="</b>"me=e-4 contains=@htmlTop
- syn region htmlItalicUnderlineBold contained start="<strong\>" end="</strong>"me=e-9 contains=@htmlTop
+ syn region htmlStrike start="<del\>" end="</del\_s*>"me=s-1 contains=@htmlTop
+ syn region htmlStrike start="<strike\>" end="</strike\_s*>"me=s-1 contains=@htmlTop
+
+ syn region htmlBold start="<b\>" end="</b\_s*>"me=s-1 contains=@htmlTop,htmlBoldUnderline,htmlBoldItalic
+ syn region htmlBold start="<strong\>" end="</strong\_s*>"me=s-1 contains=@htmlTop,htmlBoldUnderline,htmlBoldItalic
+ syn region htmlBoldUnderline contained start="<u\>" end="</u\_s*>"me=s-1 contains=@htmlTop,htmlBoldUnderlineItalic
+ syn region htmlBoldItalic contained start="<i\>" end="</i\_s*>"me=s-1 contains=@htmlTop,htmlBoldItalicUnderline
+ syn region htmlBoldItalic contained start="<em\>" end="</em\_s*>"me=s-1 contains=@htmlTop,htmlBoldItalicUnderline
+ syn region htmlBoldUnderlineItalic contained start="<i\>" end="</i\_s*>"me=s-1 contains=@htmlTop
+ syn region htmlBoldUnderlineItalic contained start="<em\>" end="</em\_s*>"me=s-1 contains=@htmlTop
+ syn region htmlBoldItalicUnderline contained start="<u\>" end="</u\_s*>"me=s-1 contains=@htmlTop,htmlBoldUnderlineItalic
+
+ syn region htmlUnderline start="<u\>" end="</u\_s*>"me=s-1 contains=@htmlTop,htmlUnderlineBold,htmlUnderlineItalic
+ syn region htmlUnderlineBold contained start="<b\>" end="</b\_s*>"me=s-1 contains=@htmlTop,htmlUnderlineBoldItalic
+ syn region htmlUnderlineBold contained start="<strong\>" end="</strong\_s*>"me=s-1 contains=@htmlTop,htmlUnderlineBoldItalic
+ syn region htmlUnderlineItalic contained start="<i\>" end="</i\_s*>"me=s-1 contains=@htmlTop,htmlUnderlineItalicBold
+ syn region htmlUnderlineItalic contained start="<em\>" end="</em\_s*>"me=s-1 contains=@htmlTop,htmlUnderlineItalicBold
+ syn region htmlUnderlineItalicBold contained start="<b\>" end="</b\_s*>"me=s-1 contains=@htmlTop
+ syn region htmlUnderlineItalicBold contained start="<strong\>" end="</strong\_s*>"me=s-1 contains=@htmlTop
+ syn region htmlUnderlineBoldItalic contained start="<i\>" end="</i\_s*>"me=s-1 contains=@htmlTop
+ syn region htmlUnderlineBoldItalic contained start="<em\>" end="</em\_s*>"me=s-1 contains=@htmlTop
+
+ syn region htmlItalic start="<i\>" end="</i\_s*>"me=s-1 contains=@htmlTop,htmlItalicBold,htmlItalicUnderline
+ syn region htmlItalic start="<em\>" end="</em\_s*>"me=s-1 contains=@htmlTop
+ syn region htmlItalicBold contained start="<b\>" end="</b\_s*>"me=s-1 contains=@htmlTop,htmlItalicBoldUnderline
+ syn region htmlItalicBold contained start="<strong\>" end="</strong\_s*>"me=s-1 contains=@htmlTop,htmlItalicBoldUnderline
+ syn region htmlItalicBoldUnderline contained start="<u\>" end="</u\_s*>"me=s-1 contains=@htmlTop
+ syn region htmlItalicUnderline contained start="<u\>" end="</u\_s*>"me=s-1 contains=@htmlTop,htmlItalicUnderlineBold
+ syn region htmlItalicUnderlineBold contained start="<b\>" end="</b\_s*>"me=s-1 contains=@htmlTop
+ syn region htmlItalicUnderlineBold contained start="<strong\>" end="</strong\_s*>"me=s-1 contains=@htmlTop
syn match htmlLeadingSpace "^\s\+" contained
- syn region htmlLink start="<a\>\_[^>]*\<href\>" end="</a>"me=e-4 contains=@Spell,htmlTag,htmlEndTag,htmlSpecialChar,htmlPreProc,htmlComment,htmlLeadingSpace,javaScript,@htmlPreproc
- syn region htmlH1 start="<h1\>" end="</h1>"me=e-5 contains=@htmlTop
- syn region htmlH2 start="<h2\>" end="</h2>"me=e-5 contains=@htmlTop
- syn region htmlH3 start="<h3\>" end="</h3>"me=e-5 contains=@htmlTop
- syn region htmlH4 start="<h4\>" end="</h4>"me=e-5 contains=@htmlTop
- syn region htmlH5 start="<h5\>" end="</h5>"me=e-5 contains=@htmlTop
- syn region htmlH6 start="<h6\>" end="</h6>"me=e-5 contains=@htmlTop
- syn region htmlHead start="<head\>" end="</head>"me=e-7 end="<body\>"me=e-5 end="<h[1-6]\>"me=e-3 contains=htmlTag,htmlEndTag,htmlSpecialChar,htmlPreProc,htmlComment,htmlLink,htmlTitle,javaScript,cssStyle,@htmlPreproc
- syn region htmlTitle start="<title\>" end="</title>"me=e-8 contains=htmlTag,htmlEndTag,htmlSpecialChar,htmlPreProc,htmlComment,javaScript,@htmlPreproc
+ syn region htmlLink start="<a\>\_[^>]*\<href\>" end="</a\_s*>"me=s-1 contains=@Spell,htmlTag,htmlEndTag,htmlSpecialChar,htmlPreProc,htmlComment,htmlLeadingSpace,javaScript,@htmlPreproc
+ syn region htmlH1 start="<h1\>" end="</h1\_s*>"me=s-1 contains=@htmlTop
+ syn region htmlH2 start="<h2\>" end="</h2\_s*>"me=s-1 contains=@htmlTop
+ syn region htmlH3 start="<h3\>" end="</h3\_s*>"me=s-1 contains=@htmlTop
+ syn region htmlH4 start="<h4\>" end="</h4\_s*>"me=s-1 contains=@htmlTop
+ syn region htmlH5 start="<h5\>" end="</h5\_s*>"me=s-1 contains=@htmlTop
+ syn region htmlH6 start="<h6\>" end="</h6\_s*>"me=s-1 contains=@htmlTop
+ syn region htmlHead start="<head\>" end="</head\_s*>"me=s-1 end="<body\>"me=s-1 end="<h[1-6]\>"me=s-1 contains=htmlTag,htmlEndTag,htmlSpecialChar,htmlPreProc,htmlComment,htmlLink,htmlTitle,javaScript,cssStyle,@htmlPreproc
+ syn region htmlTitle start="<title\>" end="</title\_s*>"me=s-1 contains=htmlTag,htmlEndTag,htmlSpecialChar,htmlPreProc,htmlComment,javaScript,@htmlPreproc
endif
syn keyword htmlTagName contained noscript
diff --git a/runtime/syntax/json.vim b/runtime/syntax/json.vim
index d80af84312..e3210a9702 100644
--- a/runtime/syntax/json.vim
+++ b/runtime/syntax/json.vim
@@ -1,7 +1,8 @@
" Vim syntax file
" Language: JSON
-" Maintainer: Eli Parra <eli@elzr.com>
-" Last Change: 2014 Aug 23
+" Maintainer: vacancy
+" Previous Maintainer: Eli Parra <eli@elzr.com>
+" Last Change: 2019 Jul 08
" Version: 0.12
if !exists("main_syntax")
@@ -16,8 +17,19 @@ syntax match jsonNoise /\%(:\|,\)/
" NOTE that for the concealing to work your conceallevel should be set to 2
+" Syntax: JSON Keywords
+" Separated into a match and region because a region by itself is always greedy
+syn match jsonKeywordMatch /"\([^"]\|\\\"\)\+"[[:blank:]\r\n]*\:/ contains=jsonKeyword
+if has('conceal')
+ syn region jsonKeyword matchgroup=jsonQuote start=/"/ end=/"\ze[[:blank:]\r\n]*\:/ concealends contained
+else
+ syn region jsonKeyword matchgroup=jsonQuote start=/"/ end=/"\ze[[:blank:]\r\n]*\:/ contained
+endif
+
" Syntax: Strings
" Separated into a match and region because a region by itself is always greedy
+" Needs to come after keywords or else a json encoded string will break the
+" syntax
syn match jsonStringMatch /"\([^"]\|\\\"\)\+"\ze[[:blank:]\r\n]*[,}\]]/ contains=jsonString
if has('conceal')
syn region jsonString oneline matchgroup=jsonQuote start=/"/ skip=/\\\\\|\\"/ end=/"/ concealends contains=jsonEscape contained
@@ -28,14 +40,6 @@ endif
" Syntax: JSON does not allow strings with single quotes, unlike JavaScript.
syn region jsonStringSQError oneline start=+'+ skip=+\\\\\|\\"+ end=+'+
-" Syntax: JSON Keywords
-" Separated into a match and region because a region by itself is always greedy
-syn match jsonKeywordMatch /"\([^"]\|\\\"\)\+"[[:blank:]\r\n]*\:/ contains=jsonKeyword
-if has('conceal')
- syn region jsonKeyword matchgroup=jsonQuote start=/"/ end=/"\ze[[:blank:]\r\n]*\:/ concealends contained
-else
- syn region jsonKeyword matchgroup=jsonQuote start=/"/ end=/"\ze[[:blank:]\r\n]*\:/ contained
-endif
" Syntax: Escape sequences
syn match jsonEscape "\\["\\/bfnrt]" contained
diff --git a/runtime/syntax/lisp.vim b/runtime/syntax/lisp.vim
index b6aa04b2c7..17c54d1a4f 100644
--- a/runtime/syntax/lisp.vim
+++ b/runtime/syntax/lisp.vim
@@ -1,8 +1,8 @@
" Vim syntax file
" Language: Lisp
" Maintainer: Charles E. Campbell <NdrOchipS@PcampbellAfamily.Mbiz>
-" Last Change: Feb 15, 2018
-" Version: 27
+" Last Change: Jul 11, 2019
+" Version: 29
" URL: http://www.drchip.org/astronaut/vim/index.html#SYNTAX_LISP
"
" Thanks to F Xavier Noria for a list of 978 Common Lisp symbols taken from HyperSpec
@@ -16,10 +16,10 @@ endif
if exists("g:lisp_isk")
exe "setl isk=".g:lisp_isk
-elseif !has("patch-7.4.1142")
- setl isk=38,42,43,45,47-58,60-62,64-90,97-122,_
-else
+elseif (v:version == 704 && has("patch-7.4.1142")) || v:version > 704
syn iskeyword 38,42,43,45,47-58,60-62,64-90,97-122,_
+else
+ setl isk=38,42,43,45,47-58,60-62,64-90,97-122,_
endif
if exists("g:lispsyntax_ignorecase") || exists("g:lispsyntax_clisp")
@@ -54,7 +54,7 @@ if exists("g:lisp_rainbow") && g:lisp_rainbow != 0
syn region lispParen8 contained matchgroup=hlLevel8 start="`\=(" end=")" skip="|.\{-}|" contains=@lispListCluster,lispParen9
syn region lispParen9 contained matchgroup=hlLevel9 start="`\=(" end=")" skip="|.\{-}|" contains=@lispListCluster,lispParen0
else
- syn region lispList matchgroup=Delimiter start="(" skip="|.\{-}|" matchgroup=Delimiter end=")" contains=@lispListCluster
+ syn region lispList matchgroup=lispParen start="(" skip="|.\{-}|" matchgroup=lispParen end=")" contains=@lispListCluster
syn region lispBQList matchgroup=PreProc start="`(" skip="|.\{-}|" matchgroup=PreProc end=")" contains=@lispListCluster
endif
@@ -608,6 +608,8 @@ if !exists("skip_lisp_syntax_inits")
hi def hlLevel8 ctermfg=blue guifg=darkslateblue
hi def hlLevel9 ctermfg=darkmagenta guifg=darkviolet
endif
+ else
+ hi def link lispParen Delimiter
endif
endif
diff --git a/runtime/syntax/make.vim b/runtime/syntax/make.vim
index 7072bab988..377e4450d9 100644
--- a/runtime/syntax/make.vim
+++ b/runtime/syntax/make.vim
@@ -1,8 +1,9 @@
" Vim syntax file
" Language: Makefile
-" Maintainer: Claudio Fleiner <claudio@fleiner.com>
-" URL: http://www.fleiner.com/vim/syntax/make.vim
-" Last Change: 2015 Feb 28
+" Maintainer: Roland Hieber <rohieb+vim-iR0jGdkV@rohieb.name>
+" Previous Maintainer: Claudio Fleiner <claudio@fleiner.com>
+" URL: https://github.com/vim/vim/syntax/make.vim
+" Last Change: 2019 Apr 02
" quit when a syntax file was already loaded
if exists("b:current_syntax")
@@ -18,7 +19,7 @@ syn match makeSpecial "^\s*[@+-]\+"
syn match makeNextLine "\\\n\s*"
" some directives
-syn match makePreCondit "^ *\(ifeq\>\|else\>\|endif\>\|ifneq\>\|ifdef\>\|ifndef\>\)"
+syn match makePreCondit "^ *\(ifn\=\(eq\|def\)\>\|else\(\s\+ifn\=\(eq\|def\)\)\=\>\|endif\>\)"
syn match makeInclude "^ *[-s]\=include"
syn match makeStatement "^ *vpath"
syn match makeExport "^ *\(export\|unexport\)\>"
@@ -31,8 +32,8 @@ syn region makeDefine start="^\s*define\s" end="^\s*endef\s*\(#.*\)\?$" contains
" Microsoft Makefile specials
syn case ignore
-syn match makeInclude "^! *include"
-syn match makePreCondit "! *\(cmdswitches\|error\|message\|include\|if\|ifdef\|ifndef\|else\|elseif\|else if\|else\s*ifdef\|else\s*ifndef\|endif\|undef\)\>"
+syn match makeInclude "^!\s*include"
+syn match makePreCondit "^!\s*\(cmdswitches\|error\|message\|include\|if\|ifdef\|ifndef\|else\|else\s*if\|else\s*ifdef\|else\s*ifndef\|endif\|undef\)\>"
syn case match
" identifiers
@@ -64,7 +65,7 @@ syn match makeCmdNextLine "\\\n."he=e-1 contained
" Statements / Functions (GNU make)
-syn match makeStatement contained "(\(subst\|abspath\|addprefix\|addsuffix\|and\|basename\|call\|dir\|error\|eval\|filter-out\|filter\|findstring\|firstword\|flavor\|foreach\|if\|info\|join\|lastword\|notdir\|or\|origin\|patsubst\|realpath\|shell\|sort\|strip\|suffix\|value\|warning\|wildcard\|word\|wordlist\|words\)\>"ms=s+1
+syn match makeStatement contained "(\(abspath\|addprefix\|addsuffix\|and\|basename\|call\|dir\|error\|eval\|file\|filter-out\|filter\|findstring\|firstword\|flavor\|foreach\|guile\|if\|info\|join\|lastword\|notdir\|or\|origin\|patsubst\|realpath\|shell\|sort\|strip\|subst\|suffix\|value\|warning\|wildcard\|word\|wordlist\|words\)\>"ms=s+1
" Comment
if exists("make_microsoft")
@@ -100,17 +101,17 @@ syn sync match makeCommandSync groupthere makeCommands "^[A-Za-z0-9_./$()%-][A-Z
" Define the default highlighting.
" Only when an item doesn't have highlighting yet
-hi def link makeNextLine makeSpecial
+hi def link makeNextLine makeSpecial
hi def link makeCmdNextLine makeSpecial
-hi def link makeSpecTarget Statement
+hi def link makeSpecTarget Statement
if !exists("make_no_commands")
-hi def link makeCommands Number
+hi def link makeCommands Number
endif
-hi def link makeImplicit Function
+hi def link makeImplicit Function
hi def link makeTarget Function
hi def link makeInclude Include
-hi def link makePreCondit PreCondit
-hi def link makeStatement Statement
+hi def link makePreCondit PreCondit
+hi def link makeStatement Statement
hi def link makeIdent Identifier
hi def link makeSpecial Special
hi def link makeComment Comment
diff --git a/runtime/syntax/maple.vim b/runtime/syntax/maple.vim
index 1261ff5a47..f14cf79cf4 100644
--- a/runtime/syntax/maple.vim
+++ b/runtime/syntax/maple.vim
@@ -1,8 +1,8 @@
" Vim syntax file
" Language: Maple V (based on release 4)
" Maintainer: Charles E. Campbell <NdrOchipS@PcampbellAfamily.Mbiz>
-" Last Change: Aug 31, 2016
-" Version: 15
+" Last Change: Mar 26, 2019
+" Version: 16
" URL: http://www.drchip.org/astronaut/vim/index.html#SYNTAX_MAPLE
"
" Package Function Selection: {{{1
@@ -27,10 +27,10 @@ if exists("b:current_syntax")
endif
" Iskeyword Effects: {{{1
-if !has("patch-7.4.1142")
- setl isk=$,48-57,_,a-z,@-Z
-else
+if (v:version == 704 && has("patch-7.4.1142")) || v:version > 704
syn iskeyword $,48-57,_,a-z,@-Z
+else
+ setl isk=$,48-57,_,a-z,@-Z
endif
" Package Selection: {{{1
diff --git a/runtime/syntax/matlab.vim b/runtime/syntax/matlab.vim
index 5228bb5c43..520280980a 100644
--- a/runtime/syntax/matlab.vim
+++ b/runtime/syntax/matlab.vim
@@ -4,9 +4,10 @@
" Credits: Preben 'Peppe' Guldberg <peppe-vim@wielders.org>
" Maurizio Tranchero - maurizio(.)tranchero(@)gmail(.)com
" Original author: Mario Eusebio
-" Last Change: Mon Jan 23 2017
-" added support for cell mode
+" Last Change: June 10 2019
+" added highlight rule for double-quoted string literals
" Change History:
+" - double-quoted string literals added
" - now highlights cell-mode separator comments
" - 'global' and 'persistent' keyword are now recognized
@@ -40,6 +41,7 @@ syn match matlabLineContinuation "\.\{3}"
" String
" MT_ADDON - added 'skip' in order to deal with 'tic' escaping sequence
syn region matlabString start=+'+ end=+'+ oneline skip=+''+
+syn region matlabStringArray start=+"+ end=+"+ oneline skip=+""+
" If you don't like tabs
syn match matlabTab "\t"
@@ -87,6 +89,7 @@ hi def link matlabExceptions Conditional
hi def link matlabRepeat Repeat
hi def link matlabTodo Todo
hi def link matlabString String
+hi def link matlabStringArray String
hi def link matlabDelimiter Identifier
hi def link matlabTransposeOther Identifier
hi def link matlabNumber Number
diff --git a/runtime/syntax/netrw.vim b/runtime/syntax/netrw.vim
index 3d3aa993bd..c4d3cf5fda 100644
--- a/runtime/syntax/netrw.vim
+++ b/runtime/syntax/netrw.vim
@@ -1,11 +1,8 @@
-" Language : Netrw Remote-Directory Listing Syntax
+" Language : Netrw Listing Syntax
" Maintainer : Charles E. Campbell
-" Last change: Oct 06, 2014
-" Version : 19
+" Last change: Oct 31, 2016
+" Version : 20 NOT RELEASED
" ---------------------------------------------------------------------
-
-" Syntax Clearing: {{{1
-" quit when a syntax file was already loaded
if exists("b:current_syntax")
finish
endif
@@ -55,24 +52,30 @@ syn match netrwLink "-->" contained skipwhite
" -----------------------------
" Special filetype highlighting {{{1
" -----------------------------
-if exists("g:netrw_special_syntax") && netrw_special_syntax
- syn match netrwBak "\(\S\+ \)*\S\+\.bak\>" contains=netrwTreeBar,@NoSpell
- syn match netrwCompress "\(\S\+ \)*\S\+\.\%(gz\|bz2\|Z\|zip\)\>" contains=netrwTreeBar,@NoSpell
+if exists("g:netrw_special_syntax") && g:netrw_special_syntax
+ if exists("+suffixes") && &suffixes != ""
+ let suflist= join(split(&suffixes,','))
+ let suflist= escape(substitute(suflist," ",'\\|','g'),'.~')
+ exe "syn match netrwSpecFile '\\(\\S\\+ \\)*\\S*\\(".suflist."\\)\\>' contains=netrwTreeBar,@NoSpell"
+ endif
+ syn match netrwBak "\(\S\+ \)*\S\+\.bak\>" contains=netrwTreeBar,@NoSpell
+ syn match netrwCompress "\(\S\+ \)*\S\+\.\%(gz\|bz2\|Z\|zip\)\>" contains=netrwTreeBar,@NoSpell
if has("unix")
- syn match netrwCoreDump "\<core\%(\.\d\+\)\=\>" contains=netrwTreeBar,@NoSpell
+ syn match netrwCoreDump "\<core\%(\.\d\+\)\=\>" contains=netrwTreeBar,@NoSpell
endif
- syn match netrwLex "\(\S\+ \)*\S\+\.\%(l\|lex\)\>" contains=netrwTreeBar,@NoSpell
- syn match netrwYacc "\(\S\+ \)*\S\+\.y\>" contains=netrwTreeBar,@NoSpell
- syn match netrwData "\(\S\+ \)*\S\+\.dat\>" contains=netrwTreeBar,@NoSpell
- syn match netrwDoc "\(\S\+ \)*\S\+\.\%(doc\|txt\|pdf\|ps\)" contains=netrwTreeBar,@NoSpell
- syn match netrwHdr "\(\S\+ \)*\S\+\.\%(h\|hpp\)\>" contains=netrwTreeBar,@NoSpell
- syn match netrwLib "\(\S\+ \)*\S*\.\%(a\|so\|lib\|dll\)\>" contains=netrwTreeBar,@NoSpell
- syn match netrwMakeFile "\<[mM]akefile\>\|\(\S\+ \)*\S\+\.mak\>" contains=netrwTreeBar,@NoSpell
- syn match netrwObj "\(\S\+ \)*\S*\.\%(o\|obj\)\>" contains=netrwTreeBar,@NoSpell
- syn match netrwTags "\<\(ANmenu\|ANtags\)\>" contains=netrwTreeBar,@NoSpell
- syn match netrwTags "\<tags\>" contains=netrwTreeBar,@NoSpell
- syn match netrwTilde "\(\S\+ \)*\S\+\~\*\=\>" contains=netrwTreeBar,@NoSpell
- syn match netrwTmp "\<tmp\(\S\+ \)*\S\+\>\|\(\S\+ \)*\S*tmp\>" contains=netrwTreeBar,@NoSpell
+ syn match netrwLex "\(\S\+ \)*\S\+\.\%(l\|lex\)\>" contains=netrwTreeBar,@NoSpell
+ syn match netrwYacc "\(\S\+ \)*\S\+\.y\>" contains=netrwTreeBar,@NoSpell
+ syn match netrwData "\(\S\+ \)*\S\+\.dat\>" contains=netrwTreeBar,@NoSpell
+ syn match netrwDoc "\(\S\+ \)*\S\+\.\%(doc\|txt\|pdf\|ps\|docx\)\>" contains=netrwTreeBar,@NoSpell
+ syn match netrwHdr "\(\S\+ \)*\S\+\.\%(h\|hpp\)\>" contains=netrwTreeBar,@NoSpell
+ syn match netrwLib "\(\S\+ \)*\S*\.\%(a\|so\|lib\|dll\)\>" contains=netrwTreeBar,@NoSpell
+ syn match netrwMakeFile "\<[mM]akefile\>\|\(\S\+ \)*\S\+\.mak\>" contains=netrwTreeBar,@NoSpell
+ syn match netrwObj "\(\S\+ \)*\S*\.\%(o\|obj\)\>" contains=netrwTreeBar,@NoSpell
+ syn match netrwPix "\c\(\S\+ \)*\S*\.\%(bmp\|fits\=\|gif\|je\=pg\|pcx\|ppc\|pgm\|png\|ppm\|psd\|rgb\|tif\|xbm\|xcf\)\>" contains=netrwTreeBar,@NoSpell
+ syn match netrwTags "\<\(ANmenu\|ANtags\)\>" contains=netrwTreeBar,@NoSpell
+ syn match netrwTags "\<tags\>" contains=netrwTreeBar,@NoSpell
+ syn match netrwTilde "\(\S\+ \)*\S\+\~\*\=\>" contains=netrwTreeBar,@NoSpell
+ syn match netrwTmp "\<tmp\(\S\+ \)*\S\+\>\|\(\S\+ \)*\S*tmp\>" contains=netrwTreeBar,@NoSpell
endif
" ---------------------------------------------------------------------
@@ -101,21 +104,42 @@ if !exists("did_drchip_netrwlist_syntax")
hi default link netrwLink Special
" special syntax highlighting (see :he g:netrw_special_syntax)
- hi default link netrwBak NonText
- hi default link netrwCompress Folded
hi default link netrwCoreDump WarningMsg
hi default link netrwData DiffChange
hi default link netrwHdr netrwPlain
hi default link netrwLex netrwPlain
hi default link netrwLib DiffChange
hi default link netrwMakefile DiffChange
- hi default link netrwObj Folded
- hi default link netrwTilde Folded
- hi default link netrwTmp Folded
- hi default link netrwTags Folded
hi default link netrwYacc netrwPlain
+ hi default link netrwPix Special
+
+ hi default link netrwBak netrwGray
+ hi default link netrwCompress netrwGray
+ hi default link netrwSpecFile netrwGray
+ hi default link netrwObj netrwGray
+ hi default link netrwTags netrwGray
+ hi default link netrwTilde netrwGray
+ hi default link netrwTmp netrwGray
endif
+ " set up netrwGray to be understated (but not Ignore'd or Conceal'd, as those
+ " can be hard/impossible to read). Users may override this in a colorscheme by
+ " specifying netrwGray highlighting.
+ redir => s:netrwgray
+ sil hi netrwGray
+ redir END
+ if s:netrwgray !~ 'guifg'
+ if has("gui") && has("gui_running")
+ if &bg == "dark"
+ exe "hi netrwGray gui=NONE guifg=gray30"
+ else
+ exe "hi netrwGray gui=NONE guifg=gray70"
+ endif
+ else
+ hi link netrwGray Folded
+ endif
+ endif
+
" Current Syntax: {{{1
let b:current_syntax = "netrwlist"
" ---------------------------------------------------------------------
diff --git a/runtime/syntax/ocaml.vim b/runtime/syntax/ocaml.vim
index 68c1feddae..42913f228e 100644
--- a/runtime/syntax/ocaml.vim
+++ b/runtime/syntax/ocaml.vim
@@ -4,10 +4,15 @@
" Maintainers: Markus Mottl <markus.mottl@gmail.com>
" Karl-Heinz Sylla <Karl-Heinz.Sylla@gmd.de>
" Issac Trotts <ijtrotts@ucdavis.edu>
-" URL: http://www.ocaml.info/vim/syntax/ocaml.vim
-" Last Change: 2012 May 12 - Added Dominique Pellé's spell checking patch (MM)
-" 2012 Feb 01 - Improved module path highlighting (MM)
-" 2010 Oct 11 - Added highlighting of lnot (MM, thanks to Erick Matsen)
+" URL: https://github.com/rgrinberg/vim-ocaml
+" Last Change:
+" 2018 Nov 08 - Improved highlighting of operators (Maëlan)
+" 2018 Apr 22 - Improved support for PPX (Andrey Popp)
+" 2018 Mar 16 - Remove raise, lnot and not from keywords (Étienne Millon, "copy")
+" 2017 Apr 11 - Improved matching of negative numbers (MM)
+" 2016 Mar 11 - Improved support for quoted strings (Glen Mével)
+" 2015 Aug 13 - Allow apostrophes in identifiers (Jonathan Chan, Einar Lielmanis)
+" 2015 Jun 17 - Added new "nonrec" keyword (MM)
" A minor patch was applied to the official version so that object/end
" can be distinguished from begin/end, which is used for indentation,
@@ -18,6 +23,9 @@ if exists("b:current_syntax") && b:current_syntax == "ocaml"
finish
endif
+" ' can be used in OCaml identifiers
+setlocal iskeyword+='
+
" OCaml is case sensitive.
syn case match
@@ -28,7 +36,7 @@ syn match ocamlMethod "#"
syn match ocamlComment "^#!.*" contains=@Spell
" Scripting directives
-syn match ocamlScript "^#\<\(quit\|labels\|warnings\|directory\|cd\|load\|use\|install_printer\|remove_printer\|require\|thread\|trace\|untrace\|untrace_all\|print_depth\|print_length\|camlp4o\)\>"
+syn match ocamlScript "^#\<\(quit\|labels\|warnings\|warn_error\|directory\|remove_directory\|cd\|load\|load_rec\|use\|mod_use\|install_printer\|remove_printer\|require\|list\|ppx\|principal\|predicates\|rectypes\|thread\|trace\|untrace\|untrace_all\|print_depth\|print_length\|camlp4o\|camlp4r\|topfind_log\|topfind_verbose\)\>"
" lowercase identifier - the standard way to match
syn match ocamlLCIdentifier /\<\(\l\|_\)\(\w\|'\)*\>/
@@ -66,7 +74,7 @@ syn cluster ocamlAllErrs contains=ocamlBraceErr,ocamlBrackErr,ocamlParenErr,oca
syn cluster ocamlAENoParen contains=ocamlBraceErr,ocamlBrackErr,ocamlCommentErr,ocamlCountErr,ocamlDoErr,ocamlDoneErr,ocamlEndErr,ocamlThenErr
-syn cluster ocamlContained contains=ocamlTodo,ocamlPreDef,ocamlModParam,ocamlModParam1,ocamlPreMPRestr,ocamlMPRestr,ocamlMPRestr1,ocamlMPRestr2,ocamlMPRestr3,ocamlModRHS,ocamlFuncWith,ocamlFuncStruct,ocamlModTypeRestr,ocamlModTRWith,ocamlWith,ocamlWithRest,ocamlModType,ocamlFullMod,ocamlVal
+syn cluster ocamlContained contains=ocamlTodo,ocamlPreDef,ocamlModParam,ocamlModParam1,ocamlMPRestr,ocamlMPRestr1,ocamlMPRestr2,ocamlMPRestr3,ocamlModRHS,ocamlFuncWith,ocamlFuncStruct,ocamlModTypeRestr,ocamlModTRWith,ocamlWith,ocamlWithRest,ocamlModType,ocamlFullMod,ocamlVal
" Enclosing delimiters
@@ -103,11 +111,15 @@ endif
" "if"
syn region ocamlNone matchgroup=ocamlKeyword start="\<if\>" matchgroup=ocamlKeyword end="\<then\>" contains=ALLBUT,@ocamlContained,ocamlThenErr
+"" PPX nodes
+
+syn match ocamlPpxIdentifier /\(\[@\{1,3\}\)\@<=\w\+\(\.\w\+\)*/
+syn region ocamlPpx matchgroup=ocamlPpxEncl start="\[@\{1,3\}" contains=TOP end="\]"
"" Modules
" "sig"
-syn region ocamlSig matchgroup=ocamlModule start="\<sig\>" matchgroup=ocamlModule end="\<end\>" contains=ALLBUT,@ocamlContained,ocamlEndErr,ocamlModule
+syn region ocamlSig matchgroup=ocamlSigEncl start="\<sig\>" matchgroup=ocamlSigEncl end="\<end\>" contains=ALLBUT,@ocamlContained,ocamlEndErr,ocamlModule
syn region ocamlModSpec matchgroup=ocamlKeyword start="\<module\>" matchgroup=ocamlModule end="\<\u\(\w\|'\)*\>" contained contains=@ocamlAllErrs,ocamlComment skipwhite skipempty nextgroup=ocamlModTRWith,ocamlMPRestr
" "open"
@@ -118,15 +130,14 @@ syn match ocamlKeyword "\<include\>" skipwhite skipempty nextgroup=ocamlModPa
" "module" - somewhat complicated stuff ;-)
syn region ocamlModule matchgroup=ocamlKeyword start="\<module\>" matchgroup=ocamlModule end="\<\u\(\w\|'\)*\>" contains=@ocamlAllErrs,ocamlComment skipwhite skipempty nextgroup=ocamlPreDef
-syn region ocamlPreDef start="."me=e-1 matchgroup=ocamlKeyword end="\l\|=\|)"me=e-1 contained contains=@ocamlAllErrs,ocamlComment,ocamlModParam,ocamlModTypeRestr,ocamlModTRWith nextgroup=ocamlModPreRHS
-syn region ocamlModParam start="([^*]" end=")" contained contains=@ocamlAENoParen,ocamlModParam1,ocamlVal
-syn match ocamlModParam1 "\<\u\(\w\|'\)*\>" contained skipwhite skipempty nextgroup=ocamlPreMPRestr
-
-syn region ocamlPreMPRestr start="."me=e-1 end=")"me=e-1 contained contains=@ocamlAllErrs,ocamlComment,ocamlMPRestr,ocamlModTypeRestr
+syn region ocamlPreDef start="."me=e-1 matchgroup=ocamlKeyword end="\l\|=\|)"me=e-1 contained contains=@ocamlAllErrs,ocamlComment,ocamlModParam,ocamlGenMod,ocamlModTypeRestr,ocamlModTRWith nextgroup=ocamlModPreRHS
+syn region ocamlModParam start="([^*]" end=")" contained contains=ocamlGenMod,ocamlModParam1,ocamlSig,ocamlVal
+syn match ocamlModParam1 "\<\u\(\w\|'\)*\>" contained skipwhite skipempty
+syn match ocamlGenMod "()" contained skipwhite skipempty
syn region ocamlMPRestr start=":" end="."me=e-1 contained contains=@ocamlComment skipwhite skipempty nextgroup=ocamlMPRestr1,ocamlMPRestr2,ocamlMPRestr3
-syn region ocamlMPRestr1 matchgroup=ocamlModule start="\ssig\s\=" matchgroup=ocamlModule end="\<end\>" contained contains=ALLBUT,@ocamlContained,ocamlEndErr,ocamlModule
-syn region ocamlMPRestr2 start="\sfunctor\(\s\|(\)\="me=e-1 matchgroup=ocamlKeyword end="->" contained contains=@ocamlAllErrs,ocamlComment,ocamlModParam skipwhite skipempty nextgroup=ocamlFuncWith,ocamlMPRestr2
+syn region ocamlMPRestr1 matchgroup=ocamlSigEncl start="\ssig\s\=" matchgroup=ocamlSigEncl end="\<end\>" contained contains=ALLBUT,@ocamlContained,ocamlEndErr,ocamlModule
+syn region ocamlMPRestr2 start="\sfunctor\(\s\|(\)\="me=e-1 matchgroup=ocamlKeyword end="->" contained contains=@ocamlAllErrs,ocamlComment,ocamlModParam,ocamlGenMod skipwhite skipempty nextgroup=ocamlFuncWith,ocamlMPRestr2
syn match ocamlMPRestr3 "\w\(\w\|'\)*\( *\. *\w\(\w\|'\)*\)*" contained
syn match ocamlModPreRHS "=" contained skipwhite skipempty nextgroup=ocamlModParam,ocamlFullMod
syn keyword ocamlKeyword val
@@ -134,8 +145,8 @@ syn region ocamlVal matchgroup=ocamlKeyword start="\<val\>" matchgroup=ocamlLC
syn region ocamlModRHS start="." end=". *\w\|([^*]"me=e-2 contained contains=ocamlComment skipwhite skipempty nextgroup=ocamlModParam,ocamlFullMod
syn match ocamlFullMod "\<\u\(\w\|'\)*\( *\. *\u\(\w\|'\)*\)*" contained skipwhite skipempty nextgroup=ocamlFuncWith
-syn region ocamlFuncWith start="([^*]"me=e-1 end=")" contained contains=ocamlComment,ocamlWith,ocamlFuncStruct skipwhite skipempty nextgroup=ocamlFuncWith
-syn region ocamlFuncStruct matchgroup=ocamlModule start="[^a-zA-Z]struct\>"hs=s+1 matchgroup=ocamlModule end="\<end\>" contains=ALLBUT,@ocamlContained,ocamlEndErr
+syn region ocamlFuncWith start="([^*)]"me=e-1 end=")" contained contains=ocamlComment,ocamlWith,ocamlFuncStruct skipwhite skipempty nextgroup=ocamlFuncWith
+syn region ocamlFuncStruct matchgroup=ocamlStructEncl start="[^a-zA-Z]struct\>"hs=s+1 matchgroup=ocamlStructEncl end="\<end\>" contains=ALLBUT,@ocamlContained,ocamlEndErr
syn match ocamlModTypeRestr "\<\w\(\w\|'\)*\( *\. *\w\(\w\|'\)*\)*\>" contained
syn region ocamlModTRWith start=":\s*("hs=s+1 end=")" contained contains=@ocamlAENoParen,ocamlWith
@@ -143,20 +154,23 @@ syn match ocamlWith "\<\(\u\(\w\|'\)* *\. *\)*\w\(\w\|'\)*\>" contained skipw
syn region ocamlWithRest start="[^)]" end=")"me=e-1 contained contains=ALLBUT,@ocamlContained
" "struct"
-syn region ocamlStruct matchgroup=ocamlModule start="\<\(module\s\+\)\=struct\>" matchgroup=ocamlModule end="\<end\>" contains=ALLBUT,@ocamlContained,ocamlEndErr
+syn region ocamlStruct matchgroup=ocamlStructEncl start="\<\(module\s\+\)\=struct\>" matchgroup=ocamlStructEncl end="\<end\>" contains=ALLBUT,@ocamlContained,ocamlEndErr
" "module type"
syn region ocamlKeyword start="\<module\>\s*\<type\>\(\s*\<of\>\)\=" matchgroup=ocamlModule end="\<\w\(\w\|'\)*\>" contains=ocamlComment skipwhite skipempty nextgroup=ocamlMTDef
syn match ocamlMTDef "=\s*\w\(\w\|'\)*\>"hs=s+1,me=s+1 skipwhite skipempty nextgroup=ocamlFullMod
+" Quoted strings
+syn region ocamlString matchgroup=ocamlQuotedStringDelim start="{\z\([a-z_]*\)|" end="|\z1}" contains=@Spell
+
syn keyword ocamlKeyword and as assert class
syn keyword ocamlKeyword constraint else
syn keyword ocamlKeyword exception external fun
syn keyword ocamlKeyword in inherit initializer
-syn keyword ocamlKeyword land lazy let match
-syn keyword ocamlKeyword method mutable new of
-syn keyword ocamlKeyword parser private raise rec
+syn keyword ocamlKeyword lazy let match
+syn keyword ocamlKeyword method mutable new nonrec of
+syn keyword ocamlKeyword parser private rec
syn keyword ocamlKeyword try type
syn keyword ocamlKeyword virtual when while with
@@ -166,14 +180,11 @@ if exists("ocaml_revised")
else
syn keyword ocamlKeyword function
syn keyword ocamlBoolean true false
- syn match ocamlKeyChar "!"
endif
syn keyword ocamlType array bool char exn float format format4
syn keyword ocamlType int int32 int64 lazy_t list nativeint option
-syn keyword ocamlType string unit
-
-syn keyword ocamlOperator asr lnot lor lsl lsr lxor mod not
+syn keyword ocamlType bytes string unit
syn match ocamlConstructor "(\s*)"
syn match ocamlConstructor "\[\s*\]"
@@ -193,39 +204,61 @@ syn match ocamlCharErr "'\\\d\d'\|'\\\d'"
syn match ocamlCharErr "'\\[^\'ntbr]'"
syn region ocamlString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=@Spell
-syn match ocamlFunDef "->"
-syn match ocamlRefAssign ":="
syn match ocamlTopStop ";;"
-syn match ocamlOperator "\^"
-syn match ocamlOperator "::"
-syn match ocamlOperator "&&"
-syn match ocamlOperator "<"
-syn match ocamlOperator ">"
syn match ocamlAnyVar "\<_\>"
syn match ocamlKeyChar "|[^\]]"me=e-1
syn match ocamlKeyChar ";"
syn match ocamlKeyChar "\~"
syn match ocamlKeyChar "?"
-syn match ocamlKeyChar "\*"
-syn match ocamlKeyChar "="
+"" Operators
+
+" The grammar of operators is found there:
+" https://caml.inria.fr/pub/docs/manual-ocaml/names.html#operator-name
+" https://caml.inria.fr/pub/docs/manual-ocaml/extn.html#s:ext-ops
+" https://caml.inria.fr/pub/docs/manual-ocaml/extn.html#s:index-operators
+" =, *, < and > are both operator names and keywords, we let the user choose how
+" to display them (has to be declared before regular infix operators):
+syn match ocamlEqual "="
+syn match ocamlStar "*"
+syn match ocamlAngle "<"
+syn match ocamlAngle ">"
+" Custom indexing operators:
+syn match ocamlIndexingOp "\.[~?!:|&$%=>@^/*+-][~?!.:|&$%<=>@^*/+-]*\(()\|\[]\|{}\)\(<-\)\?"
+" Extension operators (has to be declared before regular infix operators):
+syn match ocamlExtensionOp "#[#~?!.:|&$%<=>@^*/+-]\+"
+" Infix and prefix operators:
+syn match ocamlPrefixOp "![~?!.:|&$%<=>@^*/+-]*"
+syn match ocamlPrefixOp "[~?][~?!.:|&$%<=>@^*/+-]\+"
+syn match ocamlInfixOp "[&$%@^/+-][~?!.:|&$%<=>@^*/+-]*"
+syn match ocamlInfixOp "[|<=>*][~?!.:|&$%<=>@^*/+-]\+"
+syn match ocamlInfixOp "#[~?!.:|&$%<=>@^*/+-]\+#\@!"
+syn match ocamlInfixOp "!=[~?!.:|&$%<=>@^*/+-]\@!"
+syn keyword ocamlInfixOpKeyword asr land lor lsl lsr lxor mod or
+" := is technically an infix operator, but we may want to show it as a keyword
+" (somewhat analogously to = for letâ€bindings and <- for assignations):
+syn match ocamlRefAssign ":="
+" :: is technically not an operator, but we may want to show it as such:
+syn match ocamlCons "::"
+" -> and <- are keywords, not operators (but can appear in longer operators):
+syn match ocamlArrow "->[~?!.:|&$%<=>@^*/+-]\@!"
if exists("ocaml_revised")
- syn match ocamlErr "<-"
+ syn match ocamlErr "<-[~?!.:|&$%<=>@^*/+-]\@!"
else
- syn match ocamlOperator "<-"
+ syn match ocamlKeyChar "<-[~?!.:|&$%<=>@^*/+-]\@!"
endif
-syn match ocamlNumber "\<-\=\d\(_\|\d\)*[l|L|n]\?\>"
-syn match ocamlNumber "\<-\=0[x|X]\(\x\|_\)\+[l|L|n]\?\>"
-syn match ocamlNumber "\<-\=0[o|O]\(\o\|_\)\+[l|L|n]\?\>"
-syn match ocamlNumber "\<-\=0[b|B]\([01]\|_\)\+[l|L|n]\?\>"
-syn match ocamlFloat "\<-\=\d\(_\|\d\)*\.\?\(_\|\d\)*\([eE][-+]\=\d\(_\|\d\)*\)\=\>"
+syn match ocamlNumber "-\=\<\d\(_\|\d\)*[l|L|n]\?\>"
+syn match ocamlNumber "-\=\<0[x|X]\(\x\|_\)\+[l|L|n]\?\>"
+syn match ocamlNumber "-\=\<0[o|O]\(\o\|_\)\+[l|L|n]\?\>"
+syn match ocamlNumber "-\=\<0[b|B]\([01]\|_\)\+[l|L|n]\?\>"
+syn match ocamlFloat "-\=\<\d\(_\|\d\)*\.\?\(_\|\d\)*\([eE][-+]\=\d\(_\|\d\)*\)\=\>"
" Labels
syn match ocamlLabel "\~\(\l\|_\)\(\w\|'\)*"lc=1
syn match ocamlLabel "?\(\l\|_\)\(\w\|'\)*"lc=1
-syn region ocamlLabel transparent matchgroup=ocamlLabel start="?(\(\l\|_\)\(\w\|'\)*"lc=2 end=")"me=e-1 contains=ALLBUT,@ocamlContained,ocamlParenErr
+syn region ocamlLabel transparent matchgroup=ocamlLabel start="[~?](\(\l\|_\)\(\w\|'\)*"lc=2 end=")"me=e-1 contains=ALLBUT,@ocamlContained,ocamlParenErr
" Synchronization
@@ -281,6 +314,8 @@ hi def link ocamlFullMod Include
hi def link ocamlModTypeRestr Include
hi def link ocamlWith Include
hi def link ocamlMTDef Include
+hi def link ocamlSigEncl ocamlModule
+hi def link ocamlStructEncl ocamlModule
hi def link ocamlScript Include
@@ -291,18 +326,34 @@ hi def link ocamlModPreRHS Keyword
hi def link ocamlMPRestr2 Keyword
hi def link ocamlKeyword Keyword
hi def link ocamlMethod Include
-hi def link ocamlFunDef Keyword
-hi def link ocamlRefAssign Keyword
hi def link ocamlKeyChar Keyword
hi def link ocamlAnyVar Keyword
hi def link ocamlTopStop Keyword
-hi def link ocamlOperator Keyword
+
+hi def link ocamlRefAssign ocamlKeyChar
+hi def link ocamlEqual ocamlKeyChar
+hi def link ocamlStar ocamlInfixOp
+hi def link ocamlAngle ocamlInfixOp
+hi def link ocamlCons ocamlInfixOp
+
+hi def link ocamlPrefixOp ocamlOperator
+hi def link ocamlInfixOp ocamlOperator
+hi def link ocamlExtensionOp ocamlOperator
+hi def link ocamlIndexingOp ocamlOperator
+
+if exists("ocaml_highlight_operators")
+ hi def link ocamlInfixOpKeyword ocamlOperator
+ hi def link ocamlOperator Operator
+else
+ hi def link ocamlInfixOpKeyword Keyword
+endif
hi def link ocamlBoolean Boolean
hi def link ocamlCharacter Character
hi def link ocamlNumber Number
hi def link ocamlFloat Float
hi def link ocamlString String
+hi def link ocamlQuotedStringDelim Identifier
hi def link ocamlLabel Identifier
@@ -312,6 +363,7 @@ hi def link ocamlTodo Todo
hi def link ocamlEncl Keyword
+hi def link ocamlPpxEncl ocamlEncl
let b:current_syntax = "ocaml"
diff --git a/runtime/syntax/php.vim b/runtime/syntax/php.vim
index 5a7a2c3794..1c5c24e56b 100644
--- a/runtime/syntax/php.vim
+++ b/runtime/syntax/php.vim
@@ -261,7 +261,7 @@ syn keyword phpStatement return break continue exit goto yield contained
syn keyword phpKeyword var const contained
" Type
-syn keyword phpType bool boolean int integer real double float string array object NULL callable iterable contained
+syn keyword phpType void bool boolean int integer real double float string array object NULL callable iterable contained
" Structure
syn keyword phpStructure namespace extends implements instanceof parent self contained
diff --git a/runtime/syntax/raml.vim b/runtime/syntax/raml.vim
new file mode 100644
index 0000000000..062a71c81b
--- /dev/null
+++ b/runtime/syntax/raml.vim
@@ -0,0 +1,106 @@
+" Vim syntax file
+" Language: RAML (RESTful API Modeling Language)
+" Maintainer: Eric Hopkins <eric.on.tech@gmail.com>
+" URL: https://github.com/in3d/vim-raml
+" License: Same as Vim
+" Last Change: 2018-11-03
+
+if exists("b:current_syntax")
+ finish
+endif
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+syn keyword ramlTodo contained TODO FIXME XXX NOTE
+
+syn region ramlComment display oneline start='\%(^\|\s\)#' end='$'
+ \ contains=ramlTodo,@Spell
+
+syn region ramlVersion display oneline start='#%RAML' end='$'
+
+syn match ramlNodeProperty '!\%(![^\\^% ]\+\|[^!][^:/ ]*\)'
+
+syn match ramlAnchor '&.\+'
+
+syn match ramlAlias '\*.\+'
+
+syn match ramlDelimiter '[-,:]'
+syn match ramlBlock '[\[\]{}>|]'
+syn match ramlOperator '[?+-]'
+syn match ramlKey '\h\+\(?\)\?\ze\s*:'
+syn match ramlKey '\w\+\(\s\+\w\+\)*\(?\)\?\ze\s*:'
+syn match routeKey '\/\w\+\(\s\+\w\+\)*\ze\s*:'
+syn match routeKey 'application\/\w\+\ze\s*:'
+syn match routeParamKey '\/{\w\+}*\ze\s*:'
+
+syn region ramlString matchgroup=ramlStringDelimiter
+ \ start=+\s"+ skip=+\\"+ end=+"+
+ \ contains=ramlEscape
+syn region ramlString matchgroup=ramlStringDelimiter
+ \ start=+\s'+ skip=+''+ end=+'+
+ \ contains=ramlStringEscape
+syn region ramlParameter matchgroup=ramlParameterDelimiter
+ \ start=+<<+ skip=+''+ end=+>>+
+syn match ramlEscape contained display +\\[\\"abefnrtv^0_ NLP]+
+syn match ramlEscape contained display '\\x\x\{2}'
+syn match ramlEscape contained display '\\u\x\{4}'
+syn match ramlEscape contained display '\\U\x\{8}'
+syn match ramlEscape display '\\\%(\r\n\|[\r\n]\)'
+syn match ramlStringEscape contained +''+
+
+syn match ramlNumber display
+ \ '\<[+-]\=\d\+\%(\.\d\+\%([eE][+-]\=\d\+\)\=\)\='
+syn match ramlNumber display '0\o\+'
+syn match ramlNumber display '0x\x\+'
+syn match ramlNumber display '([+-]\=[iI]nf)'
+syn match ramlNumber display '(NaN)'
+
+syn match ramlConstant '\<[~yn]\>'
+syn keyword ramlConstant true True TRUE false False FALSE
+syn keyword ramlConstant yes Yes on ON no No off OFF
+syn keyword ramlConstant null Null NULL nil Nil NIL
+
+syn keyword httpVerbs get post put delete head patch options
+syn keyword ramlTypes string number integer date boolean file
+
+syn match ramlTimestamp '\d\d\d\d-\%(1[0-2]\|\d\)-\%(3[0-2]\|2\d\|1\d\|\d\)\%( \%([01]\d\|2[0-3]\):[0-5]\d:[0-5]\d.\d\d [+-]\%([01]\d\|2[0-3]\):[0-5]\d\|t\%([01]\d\|2[0-3]\):[0-5]\d:[0-5]\d.\d\d[+-]\%([01]\d\|2[0-3]\):[0-5]\d\|T\%([01]\d\|2[0-3]\):[0-5]\d:[0-5]\d.\dZ\)\='
+
+syn region ramlDocumentHeader start='---' end='$' contains=ramlDirective
+syn match ramlDocumentEnd '\.\.\.'
+
+syn match ramlDirective contained '%[^:]\+:.\+'
+
+hi def link ramlVersion String
+hi def link routeInterpolation String
+hi def link ramlInterpolation Constant
+hi def link ramlTodo Todo
+hi def link ramlComment Comment
+hi def link ramlDocumentHeader PreProc
+hi def link ramlDocumentEnd PreProc
+hi def link ramlDirective Keyword
+hi def link ramlNodeProperty Type
+hi def link ramlAnchor Type
+hi def link ramlAlias Type
+hi def link ramlBlock Operator
+hi def link ramlOperator Operator
+hi def link routeParamKey SpecialChar
+hi def link ramlKey Identifier
+hi def link routeKey SpecialChar
+hi def link ramlParameterDelimiter Type
+hi def link ramlParameter Type
+hi def link ramlString String
+hi def link ramlStringDelimiter ramlString
+hi def link ramlEscape SpecialChar
+hi def link ramlStringEscape SpecialChar
+hi def link ramlNumber Number
+hi def link ramlConstant Constant
+hi def link ramlTimestamp Number
+hi def link httpVerbs Statement
+hi def link ramlTypes Type
+hi def link ramlDelimiter Delimiter
+
+let b:current_syntax = "raml"
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
diff --git a/runtime/syntax/rmd.vim b/runtime/syntax/rmd.vim
index a26389024d..d852d225bc 100644
--- a/runtime/syntax/rmd.vim
+++ b/runtime/syntax/rmd.vim
@@ -1,7 +1,7 @@
" markdown Text with R statements
" Language: markdown with R code chunks
" Homepage: https://github.com/jalvesaq/R-Vim-runtime
-" Last Change: Sat Aug 25, 2018 03:44PM
+" Last Change: Thu Apr 18, 2019 09:17PM
"
" For highlighting pandoc extensions to markdown like citations and TeX and
" many other advanced features like folding of markdown sections, it is
@@ -54,14 +54,14 @@ runtime syntax/markdown.vim
" Now highlight chunks:
for s:type in g:rmd_fenced_languages
if s:type =~ '='
- let s:lng = substitute(s:type, '=.*', '')
- let s:nm = substitute(s:type, '.*=', '')
+ let s:ft = substitute(s:type, '.*=', '', '')
+ let s:nm = substitute(s:type, '=.*', '', '')
else
- let s:lng = s:type
+ let s:ft = s:type
let s:nm = s:type
endif
unlet! b:current_syntax
- exe 'syn include @Rmd'.s:nm.' syntax/'.s:lng.'.vim'
+ exe 'syn include @Rmd'.s:nm.' syntax/'.s:ft.'.vim'
if g:rmd_syn_hl_chunk
exe 'syn region rmd'.s:nm.'ChunkDelim matchgroup=rmdCodeDelim start="^\s*```\s*{\s*'.s:nm.'\>" matchgroup=rmdCodeDelim end="}$" keepend containedin=rmd'.s:nm.'Chunk contains=@Rmd'.s:nm
exe 'syn region rmd'.s:nm.'Chunk start="^\s*```\s*{\s*'.s:nm.'\>.*$" matchgroup=rmdCodeDelim end="^\s*```\ze\s*$" keepend contains=rmd'.s:nm.'ChunkDelim,@Rmd'.s:nm
diff --git a/runtime/syntax/rst.vim b/runtime/syntax/rst.vim
index d620d91f4a..c865cf6905 100644
--- a/runtime/syntax/rst.vim
+++ b/runtime/syntax/rst.vim
@@ -3,7 +3,7 @@
" Maintainer: Marshall Ward <marshall.ward@gmail.com>
" Previous Maintainer: Nikolai Weibull <now@bitwi.se>
" Website: https://github.com/marshallward/vim-restructuredtext
-" Latest Revision: 2018-07-23
+" Latest Revision: 2018-12-29
if exists("b:current_syntax")
finish
@@ -59,6 +59,7 @@ syn keyword rstTodo contained FIXME TODO XXX NOTE
execute 'syn region rstComment contained' .
\ ' start=/.*/'
+ \ ' skip=+^$+' .
\ ' end=/^\s\@!/ contains=rstTodo'
execute 'syn region rstFootnote contained matchgroup=rstDirective' .
diff --git a/runtime/syntax/ruby.vim b/runtime/syntax/ruby.vim
index ca7f51b1ea..8b88378e60 100644
--- a/runtime/syntax/ruby.vim
+++ b/runtime/syntax/ruby.vim
@@ -3,6 +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: 2018 Jul 09
" ----------------------------------------------------------------------------
"
" Previous Maintainer: Mirko Nasato
@@ -45,7 +46,7 @@ function! s:foldable(...) abort
return 0
endfunction " }}}
-syn cluster rubyNotTop contains=@rubyExtendedStringSpecial,@rubyRegexpSpecial,@rubyDeclaration,rubyConditional,rubyExceptional,rubyMethodExceptional,rubyTodo
+syn cluster rubyNotTop contains=@rubyExtendedStringSpecial,@rubyRegexpSpecial,@rubyDeclaration,rubyConditional,rubyExceptional,rubyMethodExceptional,rubyTodo,rubyModuleName,rubyClassName,rubySymbolDelimiter
" Whitespace Errors {{{1
if exists("ruby_space_errors")
@@ -122,21 +123,24 @@ syn match rubyFloat "\%(\%(\w\|[]})\"']\s*\)\@<!-\)\=\<\%(0\|[1-9]\d*\%(_\d\+\)*
syn match rubyLocalVariableOrMethod "\<[_[:lower:]][_[:alnum:]]*[?!=]\=" contains=NONE display transparent
syn match rubyBlockArgument "&[_[:lower:]][_[:alnum:]]" contains=NONE display transparent
+syn match rubyClassName "\%(\%(^\|[^.]\)\.\s*\)\@<!\<\u\%(\w\|[^\x00-\x7F]\)*\>\%(\s*(\)\@!" contained
+syn match rubyModuleName "\%(\%(^\|[^.]\)\.\s*\)\@<!\<\u\%(\w\|[^\x00-\x7F]\)*\>\%(\s*(\)\@!" contained
syn match rubyConstant "\%(\%(^\|[^.]\)\.\s*\)\@<!\<\u\%(\w\|[^\x00-\x7F]\)*\>\%(\s*(\)\@!"
syn match rubyClassVariable "@@\%(\h\|[^\x00-\x7F]\)\%(\w\|[^\x00-\x7F]\)*" display
syn match rubyInstanceVariable "@\%(\h\|[^\x00-\x7F]\)\%(\w\|[^\x00-\x7F]\)*" display
syn match rubyGlobalVariable "$\%(\%(\h\|[^\x00-\x7F]\)\%(\w\|[^\x00-\x7F]\)*\|-.\)"
-syn match rubySymbol "[]})\"':]\@1<!:\%(\^\|\~@\|\~\|<<\|<=>\|<=\|<\|===\|[=!]=\|[=!]\~\|!@\|!\|>>\|>=\|>\||\|-@\|-\|/\|\[]=\|\[]\|\*\*\|\*\|&\|%\|+@\|+\|`\)"
-syn match rubySymbol "[]})\"':]\@1<!:\$\%(-.\|[`~<=>_,;:!?/.'"@$*\&+0]\)"
-syn match rubySymbol "[]})\"':]\@1<!:\%(\$\|@@\=\)\=\%(\h\|[^\x00-\x7F]\)\%(\w\|[^\x00-\x7F]\)*"
-syn match rubySymbol "[]})\"':]\@1<!:\%(\h\|[^\x00-\x7F]\)\%(\w\|[^\x00-\x7F]\)*\%([?!=]>\@!\)\="
+syn match rubySymbolDelimiter ":" contained
+syn match rubySymbol "[]})\"':]\@1<!:\%(\^\|\~@\|\~\|<<\|<=>\|<=\|<\|===\|[=!]=\|[=!]\~\|!@\|!\|>>\|>=\|>\||\|-@\|-\|/\|\[]=\|\[]\|\*\*\|\*\|&\|%\|+@\|+\|`\)" contains=rubySymbolDelimiter
+syn match rubySymbol "[]})\"':]\@1<!:\$\%(-.\|[`~<=>_,;:!?/.'"@$*\&+0]\)" contains=rubySymbolDelimiter
+syn match rubySymbol "[]})\"':]\@1<!:\%(\$\|@@\=\)\=\%(\h\|[^\x00-\x7F]\)\%(\w\|[^\x00-\x7F]\)*" contains=rubySymbolDelimiter
+syn match rubySymbol "[]})\"':]\@1<!:\%(\h\|[^\x00-\x7F]\)\%(\w\|[^\x00-\x7F]\)*\%([?!=]>\@!\)\=" contains=rubySymbolDelimiter
if s:foldable(':')
- syn region rubySymbol start="[]})\"':]\@1<!:'" end="'" skip="\\\\\|\\'" contains=rubyQuoteEscape fold
- syn region rubySymbol start="[]})\"':]\@1<!:\"" end="\"" skip="\\\\\|\\\"" contains=@rubyStringSpecial fold
+ syn region rubySymbol matchgroup=rubySymbolDelimiter start="[]})\"':]\@1<!:'" end="'" skip="\\\\\|\\'" contains=rubyQuoteEscape fold
+ syn region rubySymbol matchgroup=rubySymbolDelimiter start="[]})\"':]\@1<!:\"" end="\"" skip="\\\\\|\\\"" contains=@rubyStringSpecial fold
else
- syn region rubySymbol start="[]})\"':]\@1<!:'" end="'" skip="\\\\\|\\'" contains=rubyQuoteEscape
- syn region rubySymbol start="[]})\"':]\@1<!:\"" end="\"" skip="\\\\\|\\\"" contains=@rubyStringSpecial
+ syn region rubySymbol matchgroup=rubySymbolDelimiter start="[]})\"':]\@1<!:'" end="'" skip="\\\\\|\\'" contains=rubyQuoteEscape
+ syn region rubySymbol matchgroup=rubySymbolDelimiter start="[]})\"':]\@1<!:\"" end="\"" skip="\\\\\|\\\"" contains=@rubyStringSpecial
endif
syn match rubyCapitalizedMethod "\%(\%(^\|[^.]\)\.\s*\)\@<!\<\u\%(\w\|[^\x00-\x7F]\)*\>\%(\s*(\)*\s*(\@="
@@ -157,10 +161,10 @@ syn match rubyPredefinedConstant "\%(\%(^\|[^.]\)\.\s*\)\@<!\<\%(RUBY_\%(VERSION
" Normal Regular Expression {{{1
if s:foldable('/')
syn region rubyRegexp matchgroup=rubyRegexpDelimiter start="\%(\%(^\|\<\%(and\|or\|while\|until\|unless\|if\|elsif\|when\|not\|then\|else\)\|[;\~=!|&(,{[<>?:*+-]\)\s*\)\@<=/" end="/[iomxneus]*" skip="\\\\\|\\/" contains=@rubyRegexpSpecial fold
- syn region rubyRegexp matchgroup=rubyRegexpDelimiter start="\%(\h\k*\s\+\)\@<=/[ \t=]\@!" end="/[iomxneus]*" skip="\\\\\|\\/" contains=@rubyRegexpSpecial fold
+ syn region rubyRegexp matchgroup=rubyRegexpDelimiter start="\%(\h\k*\s\+\)\@<=/\%([ \t=]\|$\)\@!" end="/[iomxneus]*" skip="\\\\\|\\/" contains=@rubyRegexpSpecial fold
else
syn region rubyRegexp matchgroup=rubyRegexpDelimiter start="\%(\%(^\|\<\%(and\|or\|while\|until\|unless\|if\|elsif\|when\|not\|then\|else\)\|[;\~=!|&(,{[<>?:*+-]\)\s*\)\@<=/" end="/[iomxneus]*" skip="\\\\\|\\/" contains=@rubyRegexpSpecial
- syn region rubyRegexp matchgroup=rubyRegexpDelimiter start="\%(\h\k*\s\+\)\@<=/[ \t=]\@!" end="/[iomxneus]*" skip="\\\\\|\\/" contains=@rubyRegexpSpecial
+ syn region rubyRegexp matchgroup=rubyRegexpDelimiter start="\%(\h\k*\s\+\)\@<=/\%([ \t=]\|$\)\@!" end="/[iomxneus]*" skip="\\\\\|\\/" contains=@rubyRegexpSpecial
endif
" Generalized Regular Expression {{{1
@@ -275,10 +279,10 @@ else
endif
" Here Document {{{1
-syn region rubyHeredocStart matchgroup=rubyStringDelimiter start=+\%(\%(class\s*\|\%([]})"'.]\|::\)\)\_s*\|\w\)\@<!<<[-~]\=\zs\%(\%(\h\|[^\x00-\x7F]\)\%(\w\|[^\x00-\x7F]\)*\)+ end=+$+ oneline contains=ALLBUT,@rubyNotTop
-syn region rubyHeredocStart matchgroup=rubyStringDelimiter start=+\%(\%(class\s*\|\%([]})"'.]\|::\)\)\_s*\|\w\)\@<!<<[-~]\=\zs"\%([^"]*\)"+ end=+$+ oneline contains=ALLBUT,@rubyNotTop
-syn region rubyHeredocStart matchgroup=rubyStringDelimiter start=+\%(\%(class\s*\|\%([]})"'.]\|::\)\)\_s*\|\w\)\@<!<<[-~]\=\zs'\%([^']*\)'+ end=+$+ oneline contains=ALLBUT,@rubyNotTop
-syn region rubyHeredocStart matchgroup=rubyStringDelimiter start=+\%(\%(class\s*\|\%([]})"'.]\|::\)\)\_s*\|\w\)\@<!<<[-~]\=\zs`\%([^`]*\)`+ end=+$+ oneline contains=ALLBUT,@rubyNotTop
+syn region rubyHeredocStart matchgroup=rubyStringDelimiter start=+\%(\%(class\|::\)\_s*\|\%([]})"'.]\)\s\|\w\)\@<!<<[-~]\=\zs\%(\%(\h\|[^\x00-\x7F]\)\%(\w\|[^\x00-\x7F]\)*\)+ end=+$+ oneline contains=ALLBUT,@rubyNotTop
+syn region rubyHeredocStart matchgroup=rubyStringDelimiter start=+\%(\%(class\|::\)\_s*\|\%([]})"'.]\)\s\|\w\)\@<!<<[-~]\=\zs"\%([^"]*\)"+ end=+$+ oneline contains=ALLBUT,@rubyNotTop
+syn region rubyHeredocStart matchgroup=rubyStringDelimiter start=+\%(\%(class\|::\)\_s*\|\%([]})"'.]\)\s\|\w\)\@<!<<[-~]\=\zs'\%([^']*\)'+ end=+$+ oneline contains=ALLBUT,@rubyNotTop
+syn region rubyHeredocStart matchgroup=rubyStringDelimiter start=+\%(\%(class\|::\)\_s*\|\%([]})"'.]\)\s\|\w\)\@<!<<[-~]\=\zs`\%([^`]*\)`+ end=+$+ oneline contains=ALLBUT,@rubyNotTop
if s:foldable('<<')
syn region rubyString start=+\%(\%(class\|::\)\_s*\|\%([]})"'.]\)\s\|\w\)\@<!<<\z(\%(\h\|[^\x00-\x7F]\)\%(\w\|[^\x00-\x7F]\)*\)\ze\%(.*<<[-~]\=['`"]\=\h\)\@!+hs=s+2 matchgroup=rubyStringDelimiter end=+^\z1$+ contains=rubyHeredocStart,rubyHeredoc,@rubyStringSpecial fold keepend
@@ -305,19 +309,19 @@ endif
" eRuby Config {{{1
if exists('main_syntax') && main_syntax == 'eruby'
let b:ruby_no_expensive = 1
-end
+endif
" Module, Class, Method and Alias Declarations {{{1
syn match rubyAliasDeclaration "[^[:space:];#.()]\+" contained contains=rubySymbol,rubyGlobalVariable,rubyPredefinedVariable nextgroup=rubyAliasDeclaration2 skipwhite
syn match rubyAliasDeclaration2 "[^[:space:];#.()]\+" contained contains=rubySymbol,rubyGlobalVariable,rubyPredefinedVariable
syn match rubyMethodDeclaration "[^[:space:];#(]\+" contained contains=rubyConstant,rubyBoolean,rubyPseudoVariable,rubyInstanceVariable,rubyClassVariable,rubyGlobalVariable
-syn match rubyClassDeclaration "[^[:space:];#<]\+" contained contains=rubyConstant,rubyOperator
-syn match rubyModuleDeclaration "[^[:space:];#<]\+" contained contains=rubyConstant,rubyOperator
-syn match rubyFunction "\<[_[:alpha:]][_[:alnum:]]*[?!=]\=[[:alnum:]_.:?!=]\@!" contained containedin=rubyMethodDeclaration
-syn match rubyFunction "\%(\s\|^\)\@1<=[_[:alpha:]][_[:alnum:]]*[?!=]\=\%(\s\|$\)\@=" contained containedin=rubyAliasDeclaration,rubyAliasDeclaration2
-syn match rubyFunction "\%([[:space:].]\|^\)\@2<=\%(\[\]=\=\|\*\*\|[-+!~]@\=\|[*/%|&^~]\|<<\|>>\|[<>]=\=\|<=>\|===\|[=!]=\|[=!]\~\|!\|`\)\%([[:space:];#(]\|$\)\@=" contained containedin=rubyAliasDeclaration,rubyAliasDeclaration2,rubyMethodDeclaration
+syn match rubyClassDeclaration "[^[:space:];#<]\+" contained contains=rubyClassName,rubyOperator
+syn match rubyModuleDeclaration "[^[:space:];#<]\+" contained contains=rubyModuleName,rubyOperator
+syn match rubyMethodName "\<[_[:alpha:]][_[:alnum:]]*[?!=]\=[[:alnum:]_.:?!=]\@!" contained containedin=rubyMethodDeclaration
+syn match rubyMethodName "\%(\s\|^\)\@1<=[_[:alpha:]][_[:alnum:]]*[?!=]\=\%(\s\|$\)\@=" contained containedin=rubyAliasDeclaration,rubyAliasDeclaration2
+syn match rubyMethodName "\%([[:space:].]\|^\)\@2<=\%(\[\]=\=\|\*\*\|[-+!~]@\=\|[*/%|&^~]\|<<\|>>\|[<>]=\=\|<=>\|===\|[=!]=\|[=!]\~\|!\|`\)\%([[:space:];#(]\|$\)\@=" contained containedin=rubyAliasDeclaration,rubyAliasDeclaration2,rubyMethodDeclaration
-syn cluster rubyDeclaration contains=rubyAliasDeclaration,rubyAliasDeclaration2,rubyMethodDeclaration,rubyModuleDeclaration,rubyClassDeclaration,rubyFunction,rubyBlockParameter
+syn cluster rubyDeclaration contains=rubyAliasDeclaration,rubyAliasDeclaration2,rubyMethodDeclaration,rubyModuleDeclaration,rubyClassDeclaration,rubyMethodName,rubyBlockParameter
" Keywords {{{1
" Note: the following keywords have already been defined:
@@ -335,7 +339,7 @@ syn match rubyBeginEnd "\<\%(BEGIN\|END\)\>[?!]\@!"
if !exists("b:ruby_no_expensive") && !exists("ruby_no_expensive")
syn match rubyDefine "\<alias\>" nextgroup=rubyAliasDeclaration skipwhite skipnl
syn match rubyDefine "\<def\>" nextgroup=rubyMethodDeclaration skipwhite skipnl
- syn match rubyDefine "\<undef\>" nextgroup=rubyFunction skipwhite skipnl
+ syn match rubyDefine "\<undef\>" nextgroup=rubyMethodName skipwhite skipnl
syn match rubyClass "\<class\>" nextgroup=rubyClassDeclaration skipwhite skipnl
syn match rubyModule "\<module\>" nextgroup=rubyModuleDeclaration skipwhite skipnl
@@ -377,8 +381,6 @@ if !exists("b:ruby_no_expensive") && !exists("ruby_no_expensive")
if s:foldable('[')
syn region rubyArrayLiteral matchgroup=rubyArrayDelimiter start="\%(\w\|[\]})]\)\@<!\[" end="]" contains=ALLBUT,@rubyNotTop fold
- else
- syn region rubyArrayLiteral matchgroup=rubyArrayDelimiter start="\%(\w\|[\]})]\)\@<!\[" end="]" contains=ALLBUT,@rubyNotTop
endif
" statements without 'do'
@@ -437,10 +439,12 @@ if !exists("ruby_no_special_methods")
syn match rubyControl "\<\%(exit!\|\%(abort\|at_exit\|exit\|fork\|loop\|trap\)\>[?!]\@!\)"
syn keyword rubyEval eval class_eval instance_eval module_eval
syn keyword rubyException raise fail catch throw
- " false positive with 'include?'
- syn match rubyInclude "\<include\>[?!]\@!"
- syn keyword rubyInclude autoload extend load prepend refine require require_relative using
+ syn keyword rubyInclude autoload gem load require require_relative
syn keyword rubyKeyword callcc caller lambda proc
+ " false positive with 'include?'
+ syn match rubyMacro "\<include\>[?!]\@!"
+ syn keyword rubyMacro extend prepend refine using
+ syn keyword rubyMacro alias_method define_method define_singleton_method remove_method undef_method
endif
" Comments and Documentation {{{1
@@ -461,7 +465,7 @@ syn match rubyKeywordAsMethod "\(defined?\|exit!\)\@!\<[_[:lower:]][_[:alnum:]]*
" More Symbols {{{1
syn match rubySymbol "\%([{(,]\_s*\)\zs\l\w*[!?]\=::\@!"he=e-1
-syn match rubySymbol "[]})\"':]\@1<!\%(\h\|[^\x00-\x7F]\)\%(\w\|[^\x00-\x7F]\)*[!?]\=:[[:space:],]\@="he=e-1
+syn match rubySymbol "[]})\"':]\@1<!\<\%(\h\|[^\x00-\x7F]\)\%(\w\|[^\x00-\x7F]\)*[!?]\=:[[:space:],]\@="he=e-1
syn match rubySymbol "\%([{(,]\_s*\)\zs[[:space:],{]\l\w*[!?]\=::\@!"hs=s+1,he=e-1
syn match rubySymbol "[[:space:],{(]\%(\h\|[^\x00-\x7F]\)\%(\w\|[^\x00-\x7F]\)*[!?]\=:[[:space:],]\@="hs=s+1,he=e-1
@@ -477,6 +481,10 @@ hi def link rubyClass rubyDefine
hi def link rubyModule rubyDefine
hi def link rubyMethodExceptional rubyDefine
hi def link rubyDefine Define
+hi def link rubyAccess rubyMacro
+hi def link rubyAttribute rubyMacro
+hi def link rubyMacro Macro
+hi def link rubyMethodName rubyFunction
hi def link rubyFunction Function
hi def link rubyConditional Conditional
hi def link rubyConditionalModifier rubyConditional
@@ -498,8 +506,9 @@ else
endif
hi def link rubyClassVariable rubyIdentifier
hi def link rubyConstant Type
+hi def link rubyClassName rubyConstant
+hi def link rubyModuleName rubyConstant
hi def link rubyGlobalVariable rubyIdentifier
-hi def link rubyBlockParameter rubyIdentifier
hi def link rubyInstanceVariable rubyIdentifier
hi def link rubyPredefinedIdentifier rubyIdentifier
hi def link rubyPredefinedConstant rubyPredefinedIdentifier
@@ -508,8 +517,6 @@ hi def link rubySymbol Constant
hi def link rubyKeyword Keyword
hi def link rubyOperator Operator
hi def link rubyBeginEnd Statement
-hi def link rubyAccess Statement
-hi def link rubyAttribute Statement
hi def link rubyEval Statement
hi def link rubyPseudoVariable Constant
hi def link rubyCapitalizedMethod rubyLocalVariableOrMethod
diff --git a/runtime/syntax/sh.vim b/runtime/syntax/sh.vim
index 5e0d1fd76a..ae62e195a4 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 <NdrOchipS@PcampbellAfamily.Mbiz>
" Previous Maintainer: Lennart Schultz <Lennart.Schultz@ecmwf.int>
-" Last Change: Sep 04, 2018
-" Version: 182
+" Last Change: Jun 16, 2019
+" Version: 188
" 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)
@@ -89,7 +89,7 @@ if g:sh_fold_enabled && &fdm == "manual"
endif
" set up the syntax-highlighting iskeyword
-if has("patch-7.4.1142")
+if (v:version == 704 && has("patch-7.4.1142")) || v:version > 704
if exists("b:is_bash")
exe "syn iskeyword ".&iskeyword.",-,:"
else
@@ -144,12 +144,12 @@ endif
syn cluster shHereBeginList contains=@shCommandSubList
syn cluster shHereList contains=shBeginHere,shHerePayload
syn cluster shHereListDQ contains=shBeginHere,@shDblQuoteList,shHerePayload
-syn cluster shIdList contains=shCommandSub,shCommandSubBQ,shWrapLineOperator,shSetOption,shComment,shDeref,shDerefSimple,shHereString,shRedir,shExSingleQuote,shExDoubleQuote,shSingleQuote,shDoubleQuote,shExpr,shCtrlSeq,shStringSpecial,shAtExpr
+syn cluster shIdList contains=shCommandSub,shCommandSubBQ,shWrapLineOperator,shSetOption,shComment,shDeref,shDerefSimple,shHereString,shNumber,shOperator,shRedir,shExSingleQuote,shExDoubleQuote,shSingleQuote,shDoubleQuote,shExpr,shCtrlSeq,shStringSpecial,shAtExpr
syn cluster shIfList contains=@shLoopList,shDblBrace,shDblParen,shFunctionKey,shFunctionOne,shFunctionTwo
syn cluster shLoopList contains=@shCaseList,@shErrorList,shCaseEsac,shConditional,shDblBrace,shExpr,shFor,shForPP,shIf,shOption,shSet,shTest,shTestOpr,shTouch
syn cluster shPPSRightList contains=shComment,shDeref,shDerefSimple,shEscape,shPosnParm
syn cluster shSubShList contains=@shCommandSubList,shCommandSubBQ,shCaseEsac,shColon,shCommandSub,shComment,shDo,shEcho,shExpr,shFor,shIf,shHereString,shRedir,shSetList,shSource,shStatement,shVariable,shCtrlSeq,shOperator
-syn cluster shTestList contains=shCharClass,shCommandSub,shCommandSubBQ,shCtrlSeq,shDeref,shDerefSimple,shDoubleQuote,shSpecialDQ,shExDoubleQuote,shExpr,shExSingleQuote,shNumber,shOperator,shSingleQuote,shTest,shTestOpr
+syn cluster shTestList contains=shArithmetic,shCharClass,shCommandSub,shCommandSubBQ,shCtrlSeq,shDeref,shDerefSimple,shDoubleQuote,shSpecialDQ,shExDoubleQuote,shExpr,shExSingleQuote,shNumber,shOperator,shSingleQuote,shTest,shTestOpr
syn cluster shNoZSList contains=shSpecialNoZS
syn cluster shForList contains=shTestOpr,shNumber,shDerefSimple,shDeref,shCommandSub,shCommandSubBQ,shArithmetic
@@ -292,7 +292,9 @@ endif
"======
syn match shWrapLineOperator "\\$"
syn region shCommandSubBQ start="`" skip="\\\\\|\\." end="`" contains=shBQComment,@shCommandSubList
-syn match shEscape contained '\%(^\)\@!\%(\\\\\)*\\.' nextgroup=shSingleQuote,shDoubleQuote,shComment
+"see ksh13
+"syn match shEscape contained '\%(^\)\@!\%(\\\\\)*\\.' nextgroup=shSingleQuote,shDoubleQuote,shComment
+syn match shEscape contained '\%(^\)\@!\%(\\\\\)*\\.' nextgroup=shComment
" $() and $(()): {{{1
" $(..) is not supported by sh (Bourne shell). However, apparently
@@ -379,22 +381,23 @@ syn match shBQComment contained "#.\{-}\ze`" contains=@shCommentGroup
" Here Documents: {{{1
" =========================================
-ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc01 start="<<\s*\\\=\z([^ \t0-9|>]\+\)" matchgroup=shHereDoc01 end="^\z1\s*$" contains=@shDblQuoteList
-ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc02 start="<<\s*\"\z([^ \t|>]\+\)\"" matchgroup=shHereDoc02 end="^\z1\s*$"
-ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc03 start="<<-\s*\z([^ \t0-9|>]\+\)" matchgroup=shHereDoc03 end="^\s*\z1\s*$" contains=@shDblQuoteList
+" Note : shHereDoc0[137] only had shDblQuoteList contained
+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([^"]\+\)\"" matchgroup=shHereDoc02 end="^\z1\s*$"
+ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc03 start="<<-\s*\z([^ \t|>]\+\)" matchgroup=shHereDoc03 end="^\s*\z1\s*$" contains=@shDblQuoteList
ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc04 start="<<-\s*'\z([^']\+\)'" matchgroup=shHereDoc04 end="^\s*\z1\s*$"
ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc05 start="<<\s*'\z([^']\+\)'" matchgroup=shHereDoc05 end="^\z1\s*$"
-ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc06 start="<<-\s*\"\z([^ \t|>]\+\)\"" matchgroup=shHereDoc06 end="^\s*\z1\s*$"
-ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc07 start="<<\s*\\\_$\_s*\z([^ \t0-9|>]\+\)" matchgroup=shHereDoc07 end="^\z1\s*$" contains=@shDblQuoteList
-ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc08 start="<<\s*\\\_$\_s*'\z([^ \t0-9|>]\+\)'" matchgroup=shHereDoc08 end="^\z1\s*$"
-ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc09 start="<<\s*\\\_$\_s*\"\z([^ \t0-9|>]\+\)\"" matchgroup=shHereDoc09 end="^\z1\s*$"
-ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc10 start="<<-\s*\\\_$\_s*\z([^ \t0-9|>]\+\)" matchgroup=shHereDoc10 end="^\s*\z1\s*$"
-ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc11 start="<<-\s*\\\_$\_s*\\\z([^ \t0-9|>]\+\)" matchgroup=shHereDoc11 end="^\s*\z1\s*$"
-ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc12 start="<<-\s*\\\_$\_s*'\z([^ \t|>]\+\)'" matchgroup=shHereDoc12 end="^\s*\z1\s*$"
-ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc13 start="<<-\s*\\\_$\_s*\"\z([^ \t|>]\+\)\"" matchgroup=shHereDoc13 end="^\s*\z1\s*$"
-ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc14 start="<<\\\z([^ \t0-9|>]\+\)" matchgroup=shHereDoc14 end="^\z1\s*$"
-ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc15 start="<<-\s*\\\z([^ \t0-9|>]\+\)" matchgroup=shHereDoc15 end="^\s*\z1\s*$"
-ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc16 start="<<-\s*\\\z([^ \t0-9|>]\+\)" matchgroup=shHereDoc15 end="^\s*\z1\s*$"
+ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc06 start="<<-\s*\"\z([^"]\+\)\"" matchgroup=shHereDoc06 end="^\s*\z1\s*$"
+ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc07 start="<<\s*\\\_$\_s*\z([^ \t'"|>]\+\)" matchgroup=shHereDoc07 end="^\z1\s*$"
+ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc08 start="<<\s*\\\_$\_s*'\z([^\t|>]\+\)'" matchgroup=shHereDoc08 end="^\z1\s*$"
+ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc09 start="<<\s*\\\_$\_s*\"\z([^\t|>]\+\)\"" matchgroup=shHereDoc09 end="^\z1\s*$"
+ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc10 start="<<-\s*\\\_$\_s*\z([^ \t|>]\+\)" matchgroup=shHereDoc10 end="^\s*\z1\s*$"
+ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc11 start="<<-\s*\\\_$\_s*\\\z([^ \t|>]\+\)" matchgroup=shHereDoc11 end="^\s*\z1\s*$" contains=@shDblQuoteList
+ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc12 start="<<-\s*\\\_$\_s*'\z([^']\+\)'" matchgroup=shHereDoc12 end="^\s*\z1\s*$"
+ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc13 start="<<-\s*\\\_$\_s*\"\z([^"]\+\)\"" matchgroup=shHereDoc13 end="^\s*\z1\s*$"
+ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc14 start="<<\\\z([^ \t|>]\+\)" matchgroup=shHereDoc14 end="^\z1\s*$" contains=@shDblQuoteList
+ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc15 start="<<-\s*\\\z([^ \t|>]\+\)" matchgroup=shHereDoc15 end="^\s*\z1\s*$" contains=@shDblQuoteList
+ShFoldHereDoc syn region shHereDoc matchgroup=shHereDoc16 start="<<-\s*\\\z([^ \t|>]\+\)" matchgroup=shHereDoc15 end="^\s*\z1\s*$" contains=@shDblQuoteList
" Here Strings: {{{1
" =============
@@ -407,18 +410,19 @@ endif
"=============
syn match shSetOption "\s\zs[-+][a-zA-Z0-9]\+\>" contained
syn match shVariable "\<\([bwglsav]:\)\=[a-zA-Z0-9.!@_%+,]*\ze=" nextgroup=shVarAssign
-syn match shVarAssign "=" contained nextgroup=shCmdParenRegion,shPattern,shDeref,shDerefSimple,shDoubleQuote,shExDoubleQuote,shSingleQuote,shExSingleQuote
+syn match shVarAssign "=" contained nextgroup=shCmdParenRegion,shPattern,shDeref,shDerefSimple,shDoubleQuote,shExDoubleQuote,shSingleQuote,shExSingleQuote,shVar
+syn match shVar contained "\h\w*"
syn region shAtExpr contained start="@(" end=")" contains=@shIdList
if exists("b:is_bash")
- syn match shSet "^\s*set\ze\s*$"
- syn region shSetList oneline matchgroup=shSet start="\<\(declare\|typeset\|local\|export\|unset\)\>\ze[^/]" end="$" matchgroup=shSetListDelim end="\ze[}|);&]" matchgroup=NONE end="\ze\s\+#\|=" contains=@shIdList
- syn region shSetList oneline matchgroup=shSet start="\<set\>\ze[^/]" end="\ze[;|#)]\|$" matchgroup=shSetListDelim end="\ze[}|);&]" matchgroup=NONE end="\ze\s\+=" contains=@shIdList nextgroup=shComment
+ syn match shSet "^\s*set\ze\s\+$"
+ syn region shSetList oneline matchgroup=shSet start="\<\%(declare\|local\|export\)\>\ze[/a-zA-Z_]\@!" end="$" matchgroup=shSetListDelim end="\ze[}|);&]" matchgroup=NONE end="\ze\s\+#\|=" contains=@shIdList
+ syn region shSetList oneline matchgroup=shSet start="\<\%(set\|unset\)\>[/a-zA-Z_]\@!" end="\ze[;|#)]\|$" matchgroup=shSetListDelim end="\ze[}|);&]" matchgroup=NONE end="\ze\s\+=" contains=@shIdList nextgroup=shComment
elseif exists("b:is_kornshell") || exists("b:is_posix")
- syn match shSet "^\s*set\ze\s*$"
- syn region shSetList oneline matchgroup=shSet start="\<\(typeset\|export\|unset\)\>\ze[^/]" end="$" matchgroup=shSetListDelim end="\ze[}|);&]" matchgroup=NONE end="\ze\s\+[#=]" contains=@shIdList
- syn region shSetList oneline matchgroup=shSet start="\<set\>\ze[^/]" end="$" matchgroup=shSetListDelim end="\ze[}|);&]" matchgroup=NONE end="\ze\s\+[#=]" contains=@shIdList
+ syn match shSet "^\s*set\ze\s\+$"
+ syn region shSetList oneline matchgroup=shSet start="\<\(export\)\>\ze[/]\@!" end="$" matchgroup=shSetListDelim end="\ze[}|);&]" matchgroup=NONE end="\ze\s\+[#=]" contains=@shIdList
+ syn region shSetList oneline matchgroup=shSet start="\<\%(set\|unset\>\)\ze[/a-zA-Z_]\@!" end="\ze[;|#)]\|$" matchgroup=shSetListDelim end="\ze[}|);&]" matchgroup=NONE end="\ze\s\+[#=]" contains=@shIdList nextgroup=shComment
else
- syn region shSetList oneline matchgroup=shSet start="\<\(set\|export\|unset\)\>\ze[^/]" end="$" matchgroup=shSetListDelim end="\ze[}|);&]" matchgroup=NONE end="\ze\s\+[#=]" contains=@shIdList
+ syn region shSetList oneline matchgroup=shSet start="\<\(set\|export\|unset\)\>\ze[/a-zA-Z_]\@!" end="\ze[;|#)]\|$" matchgroup=shSetListDelim end="\ze[}|);&]" matchgroup=NONE end="\ze\s\+[#=]" contains=@shIdList
endif
" Functions: {{{1
@@ -523,12 +527,12 @@ if exists("b:is_bash")
" bash : ${parameter//pattern/string}
" bash : ${parameter//pattern}
syn match shDerefPPS contained '/\{1,2}' nextgroup=shDerefPPSleft
- syn region shDerefPPSleft contained start='.' skip=@\%(\\\\\)*\\/@ matchgroup=shDerefOp end='/' end='\ze}' nextgroup=shDerefPPSright contains=@shCommandSubList
- syn region shDerefPPSright contained start='.' skip=@\%(\\\\\)\+@ end='\ze}' contains=@shPPSRightList
+ syn region shDerefPPSleft contained start='.' skip=@\%(\\\\\)*\\/@ matchgroup=shDerefOp end='/' end='\ze}' nextgroup=shDerefPPSright contains=@shCommandSubList
+ syn region shDerefPPSright contained start='.' skip=@\%(\\\\\)\+@ end='\ze}' contains=@shPPSRightList
" bash : ${parameter/#substring/replacement}
syn match shDerefPSR contained '/#' nextgroup=shDerefPSRleft,shDoubleQuote,shSingleQuote
- syn region shDerefPSRleft contained start='[^"']' skip=@\%(\\\\\)*\\/@ matchgroup=shDerefOp end='/' end='\ze}' nextgroup=shDerefPSRright
+ syn region shDerefPSRleft contained start='[^"']' skip=@\%(\\\\\)*\\/@ matchgroup=shDerefOp end='/' end='\ze}' nextgroup=shDerefPSRright
syn region shDerefPSRright contained start='.' skip=@\%(\\\\\)\+@ end='\ze}'
endif
@@ -546,8 +550,9 @@ endif
" Additional ksh Keywords and Aliases: {{{1
" ===================================
-if exists("b:is_kornshell") || exists("b:is_bash") || exists("b:is_posix")
- syn keyword shStatement bg builtin disown enum export false fg getconf getopts hist jobs let printf sleep true typeset unalias unset whence
+if exists("b:is_kornshell") || exists("b:is_posix")
+ syn keyword shStatement bg builtin disown enum export false fg getconf getopts hist jobs let printf sleep true unalias whence
+ syn keyword shStatement typeset skipwhite nextgroup=shSetOption
syn keyword shStatement autoload compound fc float functions hash history integer nameref nohup r redirect source stop suspend times type
if exists("b:is_posix")
syn keyword shStatement command
@@ -557,12 +562,13 @@ if exists("b:is_kornshell") || exists("b:is_bash") || exists("b:is_posix")
" Additional bash Keywords: {{{1
" =====================
- if exists("b:is_bash")
-" syn keyword shStatement bind builtin dirs disown enable help logout popd pushd shopt source
-syn keyword shStatement bind builtin caller compopt declare dirs disown enable export help local logout mapfile popd pushd readarray shopt source typeset unset
- else
- syn keyword shStatement login newgrp
- endif
+elseif exists("b:is_bash")
+ syn keyword shStatement bg builtin disown export false fg getopts jobs let printf sleep true unalias
+ syn keyword shStatement typeset nextgroup=shSetOption
+ syn keyword shStatement fc hash history source suspend times type
+ syn keyword shStatement bind builtin caller compopt declare dirs disown enable export help logout mapfile popd pushd readarray shopt source typeset
+else
+ syn keyword shStatement login newgrp
endif
" Synchronization: {{{1
diff --git a/runtime/syntax/spec.vim b/runtime/syntax/spec.vim
index 3a7dc9e422..2d2550559b 100644
--- a/runtime/syntax/spec.vim
+++ b/runtime/syntax/spec.vim
@@ -3,7 +3,7 @@
" Language: SPEC: Build/install scripts for Linux RPM packages
" Maintainer: Igor Gnatenko i.gnatenko.brain@gmail.com
" Former Maintainer: Donovan Rebbechi elflord@panix.com (until March 2014)
-" Last Change: Sat Apr 9 15:30 2016 Filip Szymański
+" Last Change: 2019 May 07
" quit when a syntax file was already loaded
if exists("b:current_syntax")
@@ -86,9 +86,9 @@ syn region specSectionMacroBracketArea oneline matchgroup=specSectionMacro start
"%% Files Section %%
"TODO %config valid parameters: missingok\|noreplace
"TODO %verify valid parameters: \(not\)\= \(md5\|atime\|...\)
-syn region specFilesArea matchgroup=specSection start='^%[Ff][Ii][Ll][Ee][Ss]\>' skip='%\(attrib\|defattr\|attr\|dir\|config\|docdir\|doc\|lang\|verify\|ghost\)\>' end='^%[a-zA-Z]'me=e-2 contains=specFilesOpts,specFilesDirective,@specListedFiles,specComment,specCommandSpecial,specMacroIdentifier
+syn region specFilesArea matchgroup=specSection start='^%[Ff][Ii][Ll][Ee][Ss]\>' skip='%\(attrib\|defattr\|attr\|dir\|config\|docdir\|doc\|lang\|license\|verify\|ghost\|exclude\)\>' end='^%[a-zA-Z]'me=e-2 contains=specFilesOpts,specFilesDirective,@specListedFiles,specComment,specCommandSpecial,specMacroIdentifier
"tip: remember to include new itens in specFilesArea above
-syn match specFilesDirective contained '%\(attrib\|defattr\|attr\|dir\|config\|docdir\|doc\|lang\|verify\|ghost\)\>'
+syn match specFilesDirective contained '%\(attrib\|defattr\|attr\|dir\|config\|docdir\|doc\|lang\|license\|verify\|ghost\|exclude\)\>'
"valid options for certain section headers
syn match specDescriptionOpts contained '\s-[ln]\s*\a'ms=s+1,me=e-1
diff --git a/runtime/syntax/sshdconfig.vim b/runtime/syntax/sshdconfig.vim
index 3924aaf94a..f381668d16 100644
--- a/runtime/syntax/sshdconfig.vim
+++ b/runtime/syntax/sshdconfig.vim
@@ -6,8 +6,8 @@
" Contributor: Leonard Ehrenfried <leonard.ehrenfried@web.de>
" Contributor: Karsten Hopp <karsten@redhat.com>
" Originally: 2009-07-09
-" Last Change: 2017 Oct 25
-" SSH Version: 7.6p1
+" Last Change: 2019-05-31
+" SSH Version: 7.9p1
"
" Setup
@@ -137,7 +137,8 @@ syn case ignore
" Keywords
-syn keyword sshdconfigMatch Host User Group Address
+" Also includes RDomain, but that is a keyword.
+syn keyword sshdconfigMatch Host User Group Address LocalAddress LocalPort
syn keyword sshdconfigKeyword AcceptEnv
syn keyword sshdconfigKeyword AddressFamily
@@ -150,8 +151,11 @@ syn keyword sshdconfigKeyword AuthenticationMethods
syn keyword sshdconfigKeyword AuthorizedKeysFile
syn keyword sshdconfigKeyword AuthorizedKeysCommand
syn keyword sshdconfigKeyword AuthorizedKeysCommandUser
+syn keyword sshdconfigKeyword AuthorizedPrincipalsCommand
+syn keyword sshdconfigKeyword AuthorizedPrincipalsCommandUser
syn keyword sshdconfigKeyword AuthorizedPrincipalsFile
syn keyword sshdconfigKeyword Banner
+syn keyword sshdconfigKeyword CASignatureAlgorithms
syn keyword sshdconfigKeyword ChallengeResponseAuthentication
syn keyword sshdconfigKeyword ChrootDirectory
syn keyword sshdconfigKeyword Ciphers
@@ -162,13 +166,17 @@ syn keyword sshdconfigKeyword DebianBanner
syn keyword sshdconfigKeyword DenyGroups
syn keyword sshdconfigKeyword DenyUsers
syn keyword sshdconfigKeyword DisableForwarding
+syn keyword sshdconfigKeyword ExposeAuthInfo
+syn keyword sshdconfigKeyword FingerprintHash
syn keyword sshdconfigKeyword ForceCommand
+syn keyword sshdconfigKeyword GatewayPorts
syn keyword sshdconfigKeyword GSSAPIAuthentication
syn keyword sshdconfigKeyword GSSAPICleanupCredentials
+syn keyword sshdconfigKeyword GSSAPIEnablek5users
syn keyword sshdconfigKeyword GSSAPIKeyExchange
+syn keyword sshdconfigKeyword GSSAPIKexAlgorithms
syn keyword sshdconfigKeyword GSSAPIStoreCredentialsOnRekey
syn keyword sshdconfigKeyword GSSAPIStrictAcceptorCheck
-syn keyword sshdconfigKeyword GatewayPorts
syn keyword sshdconfigKeyword HostCertificate
syn keyword sshdconfigKeyword HostKey
syn keyword sshdconfigKeyword HostKeyAgent
@@ -184,6 +192,8 @@ syn keyword sshdconfigKeyword KerberosAuthentication
syn keyword sshdconfigKeyword KerberosGetAFSToken
syn keyword sshdconfigKeyword KerberosOrLocalPasswd
syn keyword sshdconfigKeyword KerberosTicketCleanup
+syn keyword sshdconfigKeyword KerberosUniqueCCache
+syn keyword sshdconfigKeyword KerberosUseKuserok
syn keyword sshdconfigKeyword KexAlgorithms
syn keyword sshdconfigKeyword KeyRegenerationInterval
syn keyword sshdconfigKeyword ListenAddress
@@ -197,6 +207,7 @@ syn keyword sshdconfigKeyword MaxStartups
syn keyword sshdconfigKeyword PasswordAuthentication
syn keyword sshdconfigKeyword PermitBlacklistedKeys
syn keyword sshdconfigKeyword PermitEmptyPasswords
+syn keyword sshdconfigKeyword PermitListen
syn keyword sshdconfigKeyword PermitOpen
syn keyword sshdconfigKeyword PermitRootLogin
syn keyword sshdconfigKeyword PermitTTY
@@ -213,10 +224,14 @@ syn keyword sshdconfigKeyword PubkeyAuthentication
syn keyword sshdconfigKeyword RSAAuthentication
syn keyword sshdconfigKeyword RekeyLimit
syn keyword sshdconfigKeyword RevokedKeys
+syn keyword sshdconfigKeyword RDomain
syn keyword sshdconfigKeyword RhostsRSAAuthentication
syn keyword sshdconfigKeyword ServerKeyBits
+syn keyword sshdconfigKeyword SetEnv
syn keyword sshdconfigKeyword ShowPatchLevel
syn keyword sshdconfigKeyword StrictModes
+syn keyword sshdconfigKeyword StreamLocalBindMask
+syn keyword sshdconfigKeyword StreamLocalBindUnlink
syn keyword sshdconfigKeyword Subsystem
syn keyword sshdconfigKeyword SyslogFacility
syn keyword sshdconfigKeyword TCPKeepAlive
@@ -227,6 +242,7 @@ syn keyword sshdconfigKeyword UsePAM
syn keyword sshdconfigKeyword VersionAddendum
syn keyword sshdconfigKeyword X11DisplayOffset
syn keyword sshdconfigKeyword X11Forwarding
+syn keyword sshdconfigKeyword X11MaxDisplays
syn keyword sshdconfigKeyword X11UseLocalhost
syn keyword sshdconfigKeyword XAuthLocation
diff --git a/runtime/syntax/tasm.vim b/runtime/syntax/tasm.vim
index c9fc8186d0..1d6e570752 100644
--- a/runtime/syntax/tasm.vim
+++ b/runtime/syntax/tasm.vim
@@ -1,7 +1,7 @@
" Vim syntax file
" Language: TASM: turbo assembler by Borland
" Maintaner: FooLman of United Force <foolman@bigfoot.com>
-" Last Change: 2012 Feb 03 by Thilo Six
+" Last Change: 2012 Feb 03 by Thilo Six, and 2018 Nov 27.
" quit when a syntax file was already loaded
if exists("b:current_syntax")
@@ -109,7 +109,7 @@ hi def link tasmComment Comment
hi def link tasmLabel Label
-let b:curret_syntax = "tasm"
+let b:current_syntax = "tasm"
let &cpo = s:cpo_save
unlet s:cpo_save
diff --git a/runtime/syntax/template.vim b/runtime/syntax/template.vim
new file mode 100644
index 0000000000..5bf580fc11
--- /dev/null
+++ b/runtime/syntax/template.vim
@@ -0,0 +1,15 @@
+" Vim syntax file
+" Language: Generic template
+" Maintainer: Bram Moolenaar <Bram@vim.org>
+" Last Change: 2019 May 06
+
+" Quit when a (custom) syntax file was already loaded
+if exists("b:current_syntax")
+ finish
+endif
+
+" Known template types are very similar to HTML, E.g. golang and "Xfire User
+" Interface Template"
+" If you know how to recognize a more specific type for *.tmpl suggest a
+" change to runtime/scripts.vim.
+runtime! syntax/html.vim
diff --git a/runtime/syntax/tex.vim b/runtime/syntax/tex.vim
index 18c3a04877..363c781d0f 100644
--- a/runtime/syntax/tex.vim
+++ b/runtime/syntax/tex.vim
@@ -1,8 +1,8 @@
" Vim syntax file
" Language: TeX
" Maintainer: Charles E. Campbell <NdrchipO@ScampbellPfamily.AbizM>
-" Last Change: Sep 09, 2018
-" Version: 110
+" Last Change: May 14, 2019
+" Version: 114
" URL: http://www.drchip.org/astronaut/vim/index.html#SYNTAX_TEX
"
" Notes: {{{1
@@ -127,7 +127,7 @@ elseif b:tex_stylish
else
let b:tex_isk="48-57,a-z,A-Z,192-255"
endif
-if v:version > 704 || (v:version == 704 && has("patch-7.4.1142"))
+if (v:version == 704 && has("patch-7.4.1142")) || v:version > 704
exe "syn iskeyword ".b:tex_isk
else
exe "setl isk=".b:tex_isk
@@ -155,13 +155,13 @@ if !s:tex_no_error
syn cluster texCmdGroup add=texMathError
endif
syn cluster texEnvGroup contains=texMatcher,texMathDelim,texSpecialChar,texStatement
-syn cluster texFoldGroup contains=texAccent,texBadMath,texComment,texDefCmd,texDelimiter,texDocType,texInput,texInputFile,texLength,texLigature,texMatcher,texMathZoneV,texMathZoneW,texMathZoneX,texMathZoneY,texMathZoneZ,texNewCmd,texNewEnv,texOnlyMath,texOption,texParen,texRefZone,texSection,texBeginEnd,texSectionZone,texSpaceCode,texSpecialChar,texStatement,texString,texTypeSize,texTypeStyle,texZone,@texMathZones,texTitle,texAbstract,texBoldStyle,texItalStyle,texNoSpell
+syn cluster texFoldGroup contains=texAccent,texBadMath,texComment,texDefCmd,texDelimiter,texDocType,texInput,texInputFile,texLength,texLigature,texMatcher,texMathZoneV,texMathZoneW,texMathZoneX,texMathZoneY,texMathZoneZ,texNewCmd,texNewEnv,texOnlyMath,texOption,texParen,texRefZone,texSection,texBeginEnd,texSectionZone,texSpaceCode,texSpecialChar,texStatement,texString,texTypeSize,texTypeStyle,texZone,@texMathZones,texTitle,texAbstract,texBoldStyle,texItalStyle,texEmphStyle,texNoSpell
syn cluster texBoldGroup contains=texAccent,texBadMath,texComment,texDefCmd,texDelimiter,texDocType,texInput,texInputFile,texLength,texLigature,texMatcher,texMathZoneV,texMathZoneW,texMathZoneX,texMathZoneY,texMathZoneZ,texNewCmd,texNewEnv,texOnlyMath,texOption,texParen,texRefZone,texSection,texBeginEnd,texSectionZone,texSpaceCode,texSpecialChar,texStatement,texString,texTypeSize,texTypeStyle,texZone,@texMathZones,texTitle,texAbstract,texBoldStyle,texBoldItalStyle,texNoSpell
-syn cluster texItalGroup contains=texAccent,texBadMath,texComment,texDefCmd,texDelimiter,texDocType,texInput,texInputFile,texLength,texLigature,texMatcher,texMathZoneV,texMathZoneW,texMathZoneX,texMathZoneY,texMathZoneZ,texNewCmd,texNewEnv,texOnlyMath,texOption,texParen,texRefZone,texSection,texBeginEnd,texSectionZone,texSpaceCode,texSpecialChar,texStatement,texString,texTypeSize,texTypeStyle,texZone,@texMathZones,texTitle,texAbstract,texItalStyle,texItalBoldStyle,texNoSpell
+syn cluster texItalGroup contains=texAccent,texBadMath,texComment,texDefCmd,texDelimiter,texDocType,texInput,texInputFile,texLength,texLigature,texMatcher,texMathZoneV,texMathZoneW,texMathZoneX,texMathZoneY,texMathZoneZ,texNewCmd,texNewEnv,texOnlyMath,texOption,texParen,texRefZone,texSection,texBeginEnd,texSectionZone,texSpaceCode,texSpecialChar,texStatement,texString,texTypeSize,texTypeStyle,texZone,@texMathZones,texTitle,texAbstract,texItalStyle,texEmphStyle,texItalBoldStyle,texNoSpell
if !s:tex_nospell
- syn cluster texMatchGroup contains=texAccent,texBadMath,texComment,texDefCmd,texDelimiter,texDocType,texInput,texLength,texLigature,texMatcher,texNewCmd,texNewEnv,texOnlyMath,texParen,texRefZone,texSection,texSpecialChar,texStatement,texString,texTypeSize,texTypeStyle,texZone,texInputFile,texOption,@Spell
- syn cluster texMatchNMGroup contains=texAccent,texBadMath,texComment,texDefCmd,texDelimiter,texDocType,texInput,texLength,texLigature,texMatcherNM,texNewCmd,texNewEnv,texOnlyMath,texParen,texRefZone,texSection,texSpecialChar,texStatement,texString,texTypeSize,texTypeStyle,texZone,texInputFile,texOption,@Spell
- syn cluster texStyleGroup contains=texAccent,texBadMath,texComment,texDefCmd,texDelimiter,texDocType,texInput,texLength,texLigature,texNewCmd,texNewEnv,texOnlyMath,texParen,texRefZone,texSection,texSpecialChar,texStatement,texString,texTypeSize,texTypeStyle,texZone,texInputFile,texOption,texStyleStatement,@Spell,texStyleMatcher
+ syn cluster texMatchGroup contains=texAccent,texBadMath,texComment,texDefCmd,texDelimiter,texDocType,texInput,texLength,texLigature,texMatcher,texNewCmd,texNewEnv,texOnlyMath,texParen,texRefZone,texSection,texSpecialChar,texStatement,texString,texTypeSize,texTypeStyle,texBoldStyle,texBoldItalStyle,texItalStyle,texItalBoldStyle,texZone,texInputFile,texOption,@Spell
+ syn cluster texMatchNMGroup contains=texAccent,texBadMath,texComment,texDefCmd,texDelimiter,texDocType,texInput,texLength,texLigature,texMatcherNM,texNewCmd,texNewEnv,texOnlyMath,texParen,texRefZone,texSection,texSpecialChar,texStatement,texString,texTypeSize,texTypeStyle,texBoldStyle,texBoldItalStyle,texItalStyle,texItalBoldStyle,texZone,texInputFile,texOption,@Spell
+ syn cluster texStyleGroup contains=texAccent,texBadMath,texComment,texDefCmd,texDelimiter,texDocType,texInput,texLength,texLigature,texNewCmd,texNewEnv,texOnlyMath,texParen,texRefZone,texSection,texSpecialChar,texStatement,texString,texTypeSize,texTypeStyle,texBoldStyle,texBoldItalStyle,texItalStyle,texItalBoldStyle,texZone,texInputFile,texOption,texStyleStatement,texStyleMatcher,@Spell
else
syn cluster texMatchGroup contains=texAccent,texBadMath,texComment,texDefCmd,texDelimiter,texDocType,texInput,texLength,texLigature,texMatcher,texNewCmd,texNewEnv,texOnlyMath,texParen,texRefZone,texSection,texSpecialChar,texStatement,texString,texTypeSize,texTypeStyle,texZone,texInputFile,texOption
syn cluster texMatchNMGroup contains=texAccent,texBadMath,texComment,texDefCmd,texDelimiter,texDocType,texInput,texLength,texLigature,texMatcherNM,texNewCmd,texNewEnv,texOnlyMath,texParen,texRefZone,texSection,texSpecialChar,texStatement,texString,texTypeSize,texTypeStyle,texZone,texInputFile,texOption
@@ -301,6 +301,7 @@ syn match texTypeStyle "\\tt\>"
if s:tex_conceal !~# 'b'
syn match texTypeStyle "\\textbf\>"
syn match texTypeStyle "\\textit\>"
+ syn match texTypeStyle "\\emph\>"
endif
syn match texTypeStyle "\\textmd\>"
syn match texTypeStyle "\\textrm\>"
@@ -309,7 +310,6 @@ syn match texTypeStyle "\\textsf\>"
syn match texTypeStyle "\\textsl\>"
syn match texTypeStyle "\\texttt\>"
syn match texTypeStyle "\\textup\>"
-syn match texTypeStyle "\\emph\>"
syn match texTypeStyle "\\mathbb\>"
syn match texTypeStyle "\\mathbf\>"
@@ -385,11 +385,13 @@ if s:tex_fast =~# 'b'
syn region texBoldItalStyle matchgroup=texTypeStyle start="\\textit\s*{" matchgroup=texTypeStyle end="}" concealends contains=@texItalGroup,@Spell
syn region texItalStyle matchgroup=texTypeStyle start="\\textit\s*{" matchgroup=texTypeStyle end="}" concealends contains=@texItalGroup,@Spell
syn region texItalBoldStyle matchgroup=texTypeStyle start="\\textbf\s*{" matchgroup=texTypeStyle end="}" concealends contains=@texBoldGroup,@Spell
+ syn region texEmphStyle matchgroup=texTypeStyle start="\\emph\s*{" matchgroup=texTypeStyle end="}" concealends contains=@texItalGroup,@Spell
else
syn region texBoldStyle matchgroup=texTypeStyle start="\\textbf\s*{" matchgroup=texTypeStyle end="}" concealends contains=@texBoldGroup
syn region texBoldItalStyle matchgroup=texTypeStyle start="\\textit\s*{" matchgroup=texTypeStyle end="}" concealends contains=@texItalGroup
syn region texItalStyle matchgroup=texTypeStyle start="\\textit\s*{" matchgroup=texTypeStyle end="}" concealends contains=@texItalGroup
syn region texItalBoldStyle matchgroup=texTypeStyle start="\\textbf\s*{" matchgroup=texTypeStyle end="}" concealends contains=@texBoldGroup
+ syn region texEmphStyle matchgroup=texTypeStyle start="\\emph\s*{" matchgroup=texTypeStyle end="}" concealends contains=@texItalGroup
endif
endif
endif
@@ -790,6 +792,8 @@ if has("conceal") && &enc == 'utf-8'
\ ['propto' , 'âˆ'],
\ ['rceil' , '⌉'],
\ ['Re' , 'ℜ'],
+ \ ['quad' , ' '],
+ \ ['qquad' , 'â€'],
\ ['rfloor' , '⌋'],
\ ['right)' , ')'],
\ ['right]' , ']'],
@@ -943,6 +947,7 @@ if has("conceal") && &enc == 'utf-8'
call s:Greek('texGreek','\\eta\>' ,'η')
call s:Greek('texGreek','\\theta\>' ,'θ')
call s:Greek('texGreek','\\vartheta\>' ,'Ï‘')
+ call s:Greek('texGreek','\\iota\>' ,'ι')
call s:Greek('texGreek','\\kappa\>' ,'κ')
call s:Greek('texGreek','\\lambda\>' ,'λ')
call s:Greek('texGreek','\\mu\>' ,'μ')
@@ -965,11 +970,12 @@ if has("conceal") && &enc == 'utf-8'
call s:Greek('texGreek','\\Delta\>' ,'Δ')
call s:Greek('texGreek','\\Theta\>' ,'Θ')
call s:Greek('texGreek','\\Lambda\>' ,'Λ')
- call s:Greek('texGreek','\\Xi\>' ,'Χ')
+ call s:Greek('texGreek','\\Xi\>' ,'Ξ')
call s:Greek('texGreek','\\Pi\>' ,'Π')
call s:Greek('texGreek','\\Sigma\>' ,'Σ')
call s:Greek('texGreek','\\Upsilon\>' ,'Î¥')
call s:Greek('texGreek','\\Phi\>' ,'Φ')
+ call s:Greek('texGreek','\\Chi\>' ,'Χ')
call s:Greek('texGreek','\\Psi\>' ,'Ψ')
call s:Greek('texGreek','\\Omega\>' ,'Ω')
delfun s:Greek
@@ -1228,6 +1234,7 @@ if !exists("skip_tex_syntax_inits")
hi texItalStyle gui=italic cterm=italic
hi texBoldItalStyle gui=bold,italic cterm=bold,italic
hi texItalBoldStyle gui=bold,italic cterm=bold,italic
+ hi def link texEmphStyle texItalStyle
hi def link texCite texRefZone
hi def link texDefCmd texDef
hi def link texDefName texDef
diff --git a/runtime/syntax/tmux.vim b/runtime/syntax/tmux.vim
index 62c0ce521a..d32016e566 100644
--- a/runtime/syntax/tmux.vim
+++ b/runtime/syntax/tmux.vim
@@ -1,5 +1,5 @@
" Language: tmux(1) configuration file
-" Version: 2.7 (git-e4e060f2)
+" Version: 2.9a (git-0d64531f)
" URL: https://github.com/ericpruitt/tmux.vim/
" Maintainer: Eric Pruitt <eric.pruitt@gmail.com>
" License: 2-Clause BSD (http://opensource.org/licenses/BSD-2-Clause)
@@ -64,60 +64,51 @@ endfor
syn keyword tmuxOptions
\ buffer-limit command-alias default-terminal escape-time exit-empty
\ activity-action assume-paste-time base-index bell-action default-command
-\ default-shell destroy-unattached detach-on-destroy
+\ default-shell default-size destroy-unattached detach-on-destroy
\ display-panes-active-colour display-panes-colour display-panes-time
\ display-time exit-unattached focus-events history-file history-limit
-\ key-table lock-after-time lock-command message-attr message-bg
-\ message-command-attr message-command-bg message-command-fg
-\ message-command-style message-fg message-limit message-style mouse
-\ aggressive-resize allow-rename alternate-screen automatic-rename
-\ automatic-rename-format clock-mode-colour clock-mode-style force-height
-\ force-width main-pane-height main-pane-width mode-attr mode-bg mode-fg
-\ mode-keys mode-style monitor-activity monitor-bell monitor-silence
-\ other-pane-height other-pane-width pane-active-border-bg
-\ pane-active-border-fg pane-active-border-style pane-base-index
-\ pane-border-bg pane-border-fg pane-border-format pane-border-status
-\ pane-border-style prefix prefix2 remain-on-exit renumber-windows
-\ repeat-time set-clipboard set-titles set-titles-string silence-action
-\ status status-attr status-bg status-fg status-interval status-justify
-\ status-keys status-left status-left-attr status-left-bg status-left-fg
-\ status-left-length status-left-style status-position status-right
-\ status-right-attr status-right-bg status-right-fg status-right-length
+\ key-table lock-after-time lock-command message-command-style message-limit
+\ message-style mouse aggressive-resize allow-rename alternate-screen
+\ automatic-rename automatic-rename-format clock-mode-colour
+\ clock-mode-style main-pane-height main-pane-width mode-keys mode-style
+\ monitor-activity monitor-bell monitor-silence other-pane-height
+\ other-pane-width pane-active-border-style pane-base-index
+\ pane-border-format pane-border-status pane-border-style prefix prefix2
+\ remain-on-exit renumber-windows repeat-time set-clipboard set-titles
+\ set-titles-string silence-action status status-bg status-fg status-format
+\ status-interval status-justify status-keys status-left status-left-length
+\ status-left-style status-position status-right status-right-length
\ status-right-style status-style synchronize-panes terminal-overrides
\ update-environment user-keys visual-activity visual-bell visual-silence
-\ window-active-style window-status-activity-attr window-status-activity-bg
-\ window-status-activity-fg window-status-activity-style window-status-attr
-\ window-status-bell-attr window-status-bell-bg window-status-bell-fg
-\ window-status-bell-style window-status-bg window-status-current-attr
-\ window-status-current-bg window-status-current-fg
-\ window-status-current-format window-status-current-style window-status-fg
-\ window-status-format window-status-last-attr window-status-last-bg
-\ window-status-last-fg window-status-last-style window-status-separator
-\ window-status-style window-style word-separators wrap-search xterm-keys
+\ window-active-style window-size window-status-activity-style
+\ window-status-bell-style window-status-current-format
+\ window-status-current-style window-status-format window-status-last-style
+\ window-status-separator window-status-style window-style word-separators
+\ wrap-search xterm-keys
syn keyword tmuxCommands
\ attach attach-session bind bind-key break-pane breakp capture-pane
\ capturep choose-buffer choose-client choose-tree clear-history clearhist
\ clock-mode command-prompt confirm confirm-before copy-mode detach
-\ detach-client display display-message display-panes displayp find-window
-\ findw if if-shell join-pane joinp kill-pane kill-server kill-session
-\ kill-window killp has-session has killw link-window linkw list-buffers
-\ list-clients list-commands list-keys list-panes list-sessions list-windows
-\ load-buffer loadb lock lock-client lock-server lock-session last-pane
-\ lastp lockc locks last-window last ls lsb delete-buffer deleteb lsc lscm
-\ lsk lsp lsw move-pane move-window movep movew new new-session new-window
-\ neww next next-layout next-window nextl paste-buffer pasteb pipe-pane
-\ pipep prev previous-layout previous-window prevl refresh refresh-client
-\ rename rename-session rename-window renamew resize-pane resizep
-\ respawn-pane respawn-window respawnp respawnw rotate-window rotatew run
-\ run-shell save-buffer saveb select-layout select-pane select-window
-\ selectl selectp selectw send send-keys send-prefix set set-buffer
-\ set-environment set-hook set-option set-window-option setb setenv setw
-\ show show-buffer show-environment show-hooks show-messages show-options
-\ show-window-options showb showenv showmsgs showw source source-file
-\ split-window splitw start start-server suspend-client suspendc swap-pane
-\ swap-window swapp swapw switch-client switchc unbind unbind-key
-\ unlink-window unlinkw wait wait-for
+\ detach-client display display-menu display-message display-panes displayp
+\ find-window findw if if-shell join-pane joinp kill-pane kill-server
+\ kill-session kill-window killp has-session has killw link-window linkw
+\ list-buffers list-clients list-commands list-keys list-panes list-sessions
+\ list-windows load-buffer loadb lock lock-client lock-server lock-session
+\ lockc last-pane lastp locks ls last-window last lsb lsc delete-buffer
+\ deleteb lscm lsk lsp lsw menu move-pane move-window movep movew new
+\ new-session new-window neww next next-layout next-window nextl
+\ paste-buffer pasteb pipe-pane pipep prev previous-layout previous-window
+\ prevl refresh refresh-client rename rename-session rename-window renamew
+\ resize-pane resize-window resizep resizew respawn-pane respawn-window
+\ respawnp respawnw rotate-window rotatew run run-shell save-buffer saveb
+\ select-layout select-pane select-window selectl selectp selectw send
+\ send-keys send-prefix set set-buffer set-environment set-hook set-option
+\ set-window-option setb setenv setw show show-buffer show-environment
+\ show-hooks show-messages show-options show-window-options showb showenv
+\ showmsgs showw source source-file split-window splitw start start-server
+\ suspend-client suspendc swap-pane swap-window swapp swapw switch-client
+\ switchc unbind unbind-key unlink-window unlinkw wait wait-for
let &cpo = s:original_cpo
unlet! s:original_cpo s:bg s:i
diff --git a/runtime/syntax/tpp.vim b/runtime/syntax/tpp.vim
index 1244b97f08..ca64b5dce1 100644
--- a/runtime/syntax/tpp.vim
+++ b/runtime/syntax/tpp.vim
@@ -1,11 +1,11 @@
" Vim syntax file
-" Language: tpp - Text Presentation Program
-" Maintainer: Debian Vim Maintainers <pkg-vim-maintainers@lists.alioth.debian.org>
-" Former Maintainer: Gerfried Fuchs <alfie@ist.org>
-" Last Change: 2007-10-14
-" URL: http://git.debian.org/?p=pkg-vim/vim.git;a=blob_plain;f=runtime/syntax/tpp.vim;hb=debian
-" Filenames: *.tpp
-" License: BSD
+" Language: tpp - Text Presentation Program
+" Maintainer: Debian Vim Maintainers
+" Former Maintainer: Gerfried Fuchs <alfie@ist.org>
+" Last Change: 2018 Dec 27
+" URL: https://salsa.debian.org/vim-team/vim-debian/master/syntax/tpp.vim
+" Filenames: *.tpp
+" License: BSD
"
" XXX This file is in need of a new maintainer, Debian VIM Maintainers maintain
" it only because patches have been submitted for it by Debian users and the
@@ -18,11 +18,11 @@
" SPAM is _NOT_ welcome - be ready to be reported!
" quit when a syntax file was already loaded
-if exists("b:current_syntax")
+if exists('b:current_syntax')
finish
endif
-if !exists("main_syntax")
+if !exists('main_syntax')
let main_syntax = 'tpp'
endif
@@ -46,7 +46,7 @@ syn region tppNewPageOption start="^--newpage" end="$" contains=tppNewPageOption
syn region tppPageLocalOption start="^--\%(heading\|center\|right\|huge\|sethugefont\|exec\)" end="$" contains=tppPageLocalOptionKey oneline
syn region tppAbstractOption start="^--\%(author\|title\|date\|footer\)" end="$" contains=tppAbstractOptionKey oneline
-if main_syntax != 'sh'
+if main_syntax !=# 'sh'
" shell command
syn include @tppShExec syntax/sh.vim
unlet b:current_syntax
@@ -78,6 +78,6 @@ hi def link tppNewPageOption Error
hi def link tppTimeOption Error
-let b:current_syntax = "tpp"
+let b:current_syntax = 'tpp'
" vim: ts=8 sw=2
diff --git a/runtime/syntax/typescript.vim b/runtime/syntax/typescript.vim
new file mode 100644
index 0000000000..bc382610a9
--- /dev/null
+++ b/runtime/syntax/typescript.vim
@@ -0,0 +1,2077 @@
+" Vim syntax file
+" Language: TypeScript
+" Maintainer: Bram Moolenaar
+" Last Change: 2019 Jun 07
+" Based On: Herrington Darkholme's yats.vim
+" Changes: See https:github.com/HerringtonDarkholme/yats.vim
+" Credits: See yats.vim
+
+" This is the same syntax that is in yats.vim, but:
+" - flattened into one file
+" - HiLink commands changed to "hi def link"
+" - Setting 'cpo' to the Vim value
+
+if !exists("main_syntax")
+ if exists("b:current_syntax")
+ finish
+ endif
+ let main_syntax = 'typescript'
+endif
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+" nextgroup doesn't contain objectLiteral, let outer region contains it
+syntax region typescriptTypeCast matchgroup=typescriptTypeBrackets
+ \ start=/< \@!/ end=/>/
+ \ contains=@typescriptType
+ \ nextgroup=@typescriptExpression
+ \ contained skipwhite oneline
+
+" runtime syntax/common.vim
+
+" NOTE: this results in accurate highlighting, but can be slow.
+syntax sync fromstart
+
+"Dollar sign is permitted anywhere in an identifier
+setlocal iskeyword-=$
+if main_syntax == 'typescript' || main_syntax == 'typescript.tsx'
+ setlocal iskeyword+=$
+ " syntax cluster htmlJavaScript contains=TOP
+endif
+
+" lowest priority on least used feature
+syntax match typescriptLabel /[a-zA-Z_$]\k*:/he=e-1 contains=typescriptReserved nextgroup=@typescriptStatement skipwhite skipempty
+
+" other keywords like return,case,yield uses containedin
+syntax region typescriptBlock matchgroup=typescriptBraces start=/{/ end=/}/ contains=@typescriptStatement,@typescriptComments fold
+
+
+"runtime syntax/basic/identifiers.vim
+syntax cluster afterIdentifier contains=
+ \ typescriptDotNotation,
+ \ typescriptFuncCallArg,
+ \ typescriptTemplate,
+ \ typescriptIndexExpr,
+ \ @typescriptSymbols,
+ \ typescriptTypeArguments
+
+syntax match typescriptIdentifierName /\<\K\k*/
+ \ nextgroup=@afterIdentifier
+ \ transparent
+ \ contains=@_semantic
+ \ skipnl skipwhite
+
+syntax match typescriptProp contained /\K\k*!\?/
+ \ transparent
+ \ contains=@props
+ \ nextgroup=@afterIdentifier
+ \ skipwhite skipempty
+
+syntax region typescriptIndexExpr contained matchgroup=typescriptProperty start=/\[/rs=s+1 end=/]/he=e-1 contains=@typescriptValue nextgroup=@typescriptSymbols,typescriptDotNotation,typescriptFuncCallArg skipwhite skipempty
+
+syntax match typescriptDotNotation /\./ nextgroup=typescriptProp skipnl
+syntax match typescriptDotStyleNotation /\.style\./ nextgroup=typescriptDOMStyle transparent
+" syntax match typescriptFuncCall contained /[a-zA-Z]\k*\ze(/ nextgroup=typescriptFuncCallArg
+syntax region typescriptParenExp matchgroup=typescriptParens start=/(/ end=/)/ contains=@typescriptComments,@typescriptValue,typescriptCastKeyword nextgroup=@typescriptSymbols skipwhite skipempty
+syntax region typescriptFuncCallArg contained matchgroup=typescriptParens start=/(/ end=/)/ contains=@typescriptValue,@typescriptComments nextgroup=@typescriptSymbols,typescriptDotNotation skipwhite skipempty skipnl
+syntax region typescriptEventFuncCallArg contained matchgroup=typescriptParens start=/(/ end=/)/ contains=@typescriptEventExpression
+syntax region typescriptEventString contained start=/\z(["']\)/ skip=/\\\\\|\\\z1\|\\\n/ end=/\z1\|$/ contains=typescriptASCII,@events
+
+"runtime syntax/basic/literal.vim
+"Syntax in the JavaScript code
+
+" String
+syntax match typescriptASCII contained /\\\d\d\d/
+
+syntax region typescriptTemplateSubstitution matchgroup=typescriptTemplateSB
+ \ start=/\${/ end=/}/
+ \ contains=@typescriptValue
+ \ contained
+
+
+syntax region typescriptString
+ \ start=+\z(["']\)+ skip=+\\\%(\z1\|$\)+ end=+\z1+ end=+$+
+ \ contains=typescriptSpecial,@Spell
+ \ extend
+
+syntax match typescriptSpecial contained "\v\\%(x\x\x|u%(\x{4}|\{\x{4,5}})|c\u|.)"
+
+" From vim runtime
+" <https://github.com/vim/vim/blob/master/runtime/syntax/javascript.vim#L48>
+syntax region typescriptRegexpString start=+/[^/*]+me=e-1 skip=+\\\\\|\\/+ end=+/[gimuy]\{0,5\}\s*$+ end=+/[gimuy]\{0,5\}\s*[;.,)\]}]+me=e-1 nextgroup=typescriptDotNotation oneline
+
+syntax region typescriptTemplate
+ \ start=/`/ skip=/\\\\\|\\`\|\n/ end=/`\|$/
+ \ contains=typescriptTemplateSubstitution
+ \ nextgroup=@typescriptSymbols
+ \ skipwhite skipempty
+
+"Array
+syntax region typescriptArray matchgroup=typescriptBraces
+ \ start=/\[/ end=/]/
+ \ contains=@typescriptValue,@typescriptComments
+ \ nextgroup=@typescriptSymbols,typescriptDotNotation
+ \ skipwhite skipempty fold
+
+" Number
+syntax match typescriptNumber /\<0[bB][01][01_]*\>/ nextgroup=@typescriptSymbols skipwhite skipempty
+syntax match typescriptNumber /\<0[oO][0-7][0-7_]*\>/ nextgroup=@typescriptSymbols skipwhite skipempty
+syntax match typescriptNumber /\<0[xX][0-9a-fA-F][0-9a-fA-F_]*\>/ nextgroup=@typescriptSymbols skipwhite skipempty
+syntax match typescriptNumber /\d[0-9_]*\.\d[0-9_]*\|\d[0-9_]*\|\.\d[0-9]*/
+ \ nextgroup=typescriptExponent,@typescriptSymbols skipwhite skipempty
+syntax match typescriptExponent /[eE][+-]\=\d[0-9]*\>/
+ \ nextgroup=@typescriptSymbols skipwhite skipempty contained
+
+
+" runtime syntax/basic/object.vim
+syntax region typescriptObjectLiteral matchgroup=typescriptBraces
+ \ start=/{/ end=/}/
+ \ contains=@typescriptComments,typescriptObjectLabel,typescriptStringProperty,typescriptComputedPropertyName
+ \ fold contained
+
+syntax match typescriptObjectLabel contained /\k\+\_s*/
+ \ nextgroup=typescriptObjectColon,@typescriptCallImpl
+ \ skipwhite skipempty
+
+syntax region typescriptStringProperty contained
+ \ start=/\z(["']\)/ skip=/\\\\\|\\\z1\|\\\n/ end=/\z1/
+ \ nextgroup=typescriptObjectColon,@typescriptCallImpl
+ \ skipwhite skipempty
+
+" syntax region typescriptPropertyName contained start=/\z(["']\)/ skip=/\\\\\|\\\z1\|\\\n/ end=/\z1(/me=e-1 nextgroup=@typescriptCallSignature skipwhite skipempty oneline
+syntax region typescriptComputedPropertyName contained matchgroup=typescriptBraces
+ \ start=/\[/rs=s+1 end=/]/
+ \ contains=@typescriptValue
+ \ nextgroup=typescriptObjectColon,@typescriptCallImpl
+ \ skipwhite skipempty
+
+" syntax region typescriptComputedPropertyName contained matchgroup=typescriptPropertyName start=/\[/rs=s+1 end=/]\_s*:/he=e-1 contains=@typescriptValue nextgroup=@typescriptValue skipwhite skipempty
+" syntax region typescriptComputedPropertyName contained matchgroup=typescriptPropertyName start=/\[/rs=s+1 end=/]\_s*(/me=e-1 contains=@typescriptValue nextgroup=@typescriptCallSignature skipwhite skipempty
+" Value for object, statement for label statement
+syntax match typescriptRestOrSpread /\.\.\./ contained
+syntax match typescriptObjectSpread /\.\.\./ contained containedin=typescriptObjectLiteral,typescriptArray nextgroup=@typescriptValue
+
+syntax match typescriptObjectColon contained /:/ nextgroup=@typescriptValue skipwhite skipempty
+
+"runtime syntax/basic/symbols.vim
+" + - ^ ~
+syntax match typescriptUnaryOp /[+\-~!]/
+ \ nextgroup=@typescriptValue
+ \ skipwhite
+
+syntax region typescriptTernary matchgroup=typescriptTernaryOp start=/?/ end=/:/ contained contains=@typescriptValue,@typescriptComments nextgroup=@typescriptValue skipwhite skipempty
+
+syntax match typescriptAssign /=/ nextgroup=@typescriptValue
+ \ skipwhite skipempty
+
+" 2: ==, ===
+syntax match typescriptBinaryOp contained /===\?/ nextgroup=@typescriptValue skipwhite skipempty
+" 6: >>>=, >>>, >>=, >>, >=, >
+syntax match typescriptBinaryOp contained />\(>>=\|>>\|>=\|>\|=\)\?/ nextgroup=@typescriptValue skipwhite skipempty
+" 4: <<=, <<, <=, <
+syntax match typescriptBinaryOp contained /<\(<=\|<\|=\)\?/ nextgroup=@typescriptValue skipwhite skipempty
+" 3: ||, |=, |
+syntax match typescriptBinaryOp contained /|\(|\|=\)\?/ nextgroup=@typescriptValue skipwhite skipempty
+" 3: &&, &=, &
+syntax match typescriptBinaryOp contained /&\(&\|=\)\?/ nextgroup=@typescriptValue skipwhite skipempty
+" 2: *=, *
+syntax match typescriptBinaryOp contained /\*=\?/ nextgroup=@typescriptValue skipwhite skipempty
+" 2: %=, %
+syntax match typescriptBinaryOp contained /%=\?/ nextgroup=@typescriptValue skipwhite skipempty
+" 2: /=, /
+syntax match typescriptBinaryOp contained +/\(=\|[^\*/]\@=\)+ nextgroup=@typescriptValue skipwhite skipempty
+syntax match typescriptBinaryOp contained /!==\?/ nextgroup=@typescriptValue skipwhite skipempty
+" 2: !=, !==
+syntax match typescriptBinaryOp contained /+\(+\|=\)\?/ nextgroup=@typescriptValue skipwhite skipempty
+" 3: +, ++, +=
+syntax match typescriptBinaryOp contained /-\(-\|=\)\?/ nextgroup=@typescriptValue skipwhite skipempty
+" 3: -, --, -=
+
+" exponentiation operator
+" 2: **, **=
+syntax match typescriptBinaryOp contained /\*\*=\?/ nextgroup=@typescriptValue
+
+syntax cluster typescriptSymbols contains=typescriptBinaryOp,typescriptKeywordOp,typescriptTernary,typescriptAssign,typescriptCastKeyword
+
+"" runtime syntax/basic/reserved.vim
+
+"runtime syntax/basic/keyword.vim
+"Import
+syntax keyword typescriptImport from as import
+syntax keyword typescriptExport export
+syntax keyword typescriptModule namespace module
+
+"this
+
+"JavaScript Prototype
+syntax keyword typescriptPrototype prototype
+ \ nextgroup=@afterIdentifier
+
+syntax keyword typescriptCastKeyword as
+ \ nextgroup=@typescriptType
+ \ skipwhite
+
+"Program Keywords
+syntax keyword typescriptIdentifier arguments this super
+ \ nextgroup=@afterIdentifier
+
+syntax keyword typescriptVariable let var
+ \ nextgroup=typescriptVariableDeclaration
+ \ skipwhite skipempty skipnl
+
+syntax keyword typescriptVariable const
+ \ nextgroup=typescriptEnum,typescriptVariableDeclaration
+ \ skipwhite
+
+syntax match typescriptVariableDeclaration /[A-Za-z_$]\k*/
+ \ nextgroup=typescriptTypeAnnotation,typescriptAssign
+ \ contained skipwhite skipempty skipnl
+
+syntax region typescriptEnum matchgroup=typescriptEnumKeyword start=/enum / end=/\ze{/
+ \ nextgroup=typescriptBlock
+ \ skipwhite
+
+syntax keyword typescriptKeywordOp
+ \ contained in instanceof nextgroup=@typescriptValue
+syntax keyword typescriptOperator delete new typeof void
+ \ nextgroup=@typescriptValue
+ \ skipwhite skipempty
+
+syntax keyword typescriptForOperator contained in of
+syntax keyword typescriptBoolean true false nextgroup=@typescriptSymbols skipwhite skipempty
+syntax keyword typescriptNull null undefined nextgroup=@typescriptSymbols skipwhite skipempty
+syntax keyword typescriptMessage alert confirm prompt status
+ \ nextgroup=typescriptDotNotation,typescriptFuncCallArg
+syntax keyword typescriptGlobal self top parent
+ \ nextgroup=@afterIdentifier
+
+"Statement Keywords
+syntax keyword typescriptConditional if else switch
+ \ nextgroup=typescriptConditionalParen
+ \ skipwhite skipempty skipnl
+syntax keyword typescriptConditionalElse else
+syntax keyword typescriptRepeat do while for nextgroup=typescriptLoopParen skipwhite skipempty
+syntax keyword typescriptRepeat for nextgroup=typescriptLoopParen,typescriptAsyncFor skipwhite skipempty
+syntax keyword typescriptBranch break continue containedin=typescriptBlock
+syntax keyword typescriptCase case nextgroup=@typescriptPrimitive skipwhite containedin=typescriptBlock
+syntax keyword typescriptDefault default containedin=typescriptBlock nextgroup=@typescriptValue,typescriptClassKeyword,typescriptInterfaceKeyword skipwhite oneline
+syntax keyword typescriptStatementKeyword with
+syntax keyword typescriptStatementKeyword yield skipwhite nextgroup=@typescriptValue containedin=typescriptBlock
+syntax keyword typescriptStatementKeyword return skipwhite contained nextgroup=@typescriptValue containedin=typescriptBlock
+
+syntax keyword typescriptTry try
+syntax keyword typescriptExceptions catch throw finally
+syntax keyword typescriptDebugger debugger
+
+syntax keyword typescriptAsyncFor await nextgroup=typescriptLoopParen skipwhite skipempty contained
+
+syntax region typescriptLoopParen contained matchgroup=typescriptParens
+ \ start=/(/ end=/)/
+ \ contains=typescriptVariable,typescriptForOperator,typescriptEndColons,@typescriptValue,@typescriptComments
+ \ nextgroup=typescriptBlock
+ \ skipwhite skipempty
+syntax region typescriptConditionalParen contained matchgroup=typescriptParens
+ \ start=/(/ end=/)/
+ \ contains=@typescriptValue,@typescriptComments
+ \ nextgroup=typescriptBlock
+ \ skipwhite skipempty
+syntax match typescriptEndColons /[;,]/ contained
+
+syntax keyword typescriptAmbientDeclaration declare nextgroup=@typescriptAmbients
+ \ skipwhite skipempty
+
+syntax cluster typescriptAmbients contains=
+ \ typescriptVariable,
+ \ typescriptFuncKeyword,
+ \ typescriptClassKeyword,
+ \ typescriptAbstract,
+ \ typescriptEnumKeyword,typescriptEnum,
+ \ typescriptModule
+
+"runtime syntax/basic/doc.vim
+"Syntax coloring for Node.js shebang line
+syntax match shellbang "^#!.*node\>"
+syntax match shellbang "^#!.*iojs\>"
+
+
+"JavaScript comments
+syntax keyword typescriptCommentTodo TODO FIXME XXX TBD
+syntax match typescriptLineComment "//.*"
+ \ contains=@Spell,typescriptCommentTodo,typescriptRef
+syntax region typescriptComment
+ \ start="/\*" end="\*/"
+ \ contains=@Spell,typescriptCommentTodo extend
+syntax cluster typescriptComments
+ \ contains=typescriptDocComment,typescriptComment,typescriptLineComment
+
+syntax match typescriptRef +///\s*<reference\s\+.*\/>$+
+ \ contains=typescriptString
+syntax match typescriptRef +///\s*<amd-dependency\s\+.*\/>$+
+ \ contains=typescriptString
+syntax match typescriptRef +///\s*<amd-module\s\+.*\/>$+
+ \ contains=typescriptString
+
+"JSDoc
+syntax case ignore
+
+syntax region typescriptDocComment matchgroup=typescriptComment
+ \ start="/\*\*" end="\*/"
+ \ contains=typescriptDocNotation,typescriptCommentTodo,@Spell
+ \ fold keepend
+syntax match typescriptDocNotation contained /@/ nextgroup=typescriptDocTags
+
+syntax keyword typescriptDocTags contained constant constructor constructs function ignore inner private public readonly static
+syntax keyword typescriptDocTags contained const dict expose inheritDoc interface nosideeffects override protected struct internal
+syntax keyword typescriptDocTags contained example global
+
+" syntax keyword typescriptDocTags contained ngdoc nextgroup=typescriptDocNGDirective
+syntax keyword typescriptDocTags contained ngdoc scope priority animations
+syntax keyword typescriptDocTags contained ngdoc restrict methodOf propertyOf eventOf eventType nextgroup=typescriptDocParam skipwhite
+syntax keyword typescriptDocNGDirective contained overview service object function method property event directive filter inputType error
+
+syntax keyword typescriptDocTags contained abstract virtual access augments
+
+syntax keyword typescriptDocTags contained arguments callback lends memberOf name type kind link mixes mixin tutorial nextgroup=typescriptDocParam skipwhite
+syntax keyword typescriptDocTags contained variation nextgroup=typescriptDocNumParam skipwhite
+
+syntax keyword typescriptDocTags contained author class classdesc copyright default defaultvalue nextgroup=typescriptDocDesc skipwhite
+syntax keyword typescriptDocTags contained deprecated description external host nextgroup=typescriptDocDesc skipwhite
+syntax keyword typescriptDocTags contained file fileOverview overview namespace requires since version nextgroup=typescriptDocDesc skipwhite
+syntax keyword typescriptDocTags contained summary todo license preserve nextgroup=typescriptDocDesc skipwhite
+
+syntax keyword typescriptDocTags contained borrows exports nextgroup=typescriptDocA skipwhite
+syntax keyword typescriptDocTags contained param arg argument property prop module nextgroup=typescriptDocNamedParamType,typescriptDocParamName skipwhite
+syntax keyword typescriptDocTags contained define enum extends implements this typedef nextgroup=typescriptDocParamType skipwhite
+syntax keyword typescriptDocTags contained return returns throws exception nextgroup=typescriptDocParamType,typescriptDocParamName skipwhite
+syntax keyword typescriptDocTags contained see nextgroup=typescriptDocRef skipwhite
+
+syntax keyword typescriptDocTags contained function func method nextgroup=typescriptDocName skipwhite
+syntax match typescriptDocName contained /\h\w*/
+
+syntax keyword typescriptDocTags contained fires event nextgroup=typescriptDocEventRef skipwhite
+syntax match typescriptDocEventRef contained /\h\w*#\(\h\w*\:\)\?\h\w*/
+
+syntax match typescriptDocNamedParamType contained /{.\+}/ nextgroup=typescriptDocParamName skipwhite
+syntax match typescriptDocParamName contained /\[\?0-9a-zA-Z_\.]\+\]\?/ nextgroup=typescriptDocDesc skipwhite
+syntax match typescriptDocParamType contained /{.\+}/ nextgroup=typescriptDocDesc skipwhite
+syntax match typescriptDocA contained /\%(#\|\w\|\.\|:\|\/\)\+/ nextgroup=typescriptDocAs skipwhite
+syntax match typescriptDocAs contained /\s*as\s*/ nextgroup=typescriptDocB skipwhite
+syntax match typescriptDocB contained /\%(#\|\w\|\.\|:\|\/\)\+/
+syntax match typescriptDocParam contained /\%(#\|\w\|\.\|:\|\/\|-\)\+/
+syntax match typescriptDocNumParam contained /\d\+/
+syntax match typescriptDocRef contained /\%(#\|\w\|\.\|:\|\/\)\+/
+syntax region typescriptDocLinkTag contained matchgroup=typescriptDocLinkTag start=/{/ end=/}/ contains=typescriptDocTags
+
+syntax cluster typescriptDocs contains=typescriptDocParamType,typescriptDocNamedParamType,typescriptDocParam
+
+if main_syntax == "typescript"
+ syntax sync clear
+ syntax sync ccomment typescriptComment minlines=200
+endif
+
+syntax case match
+
+"runtime syntax/basic/type.vim
+" Types
+syntax match typescriptOptionalMark /?/ contained
+
+syntax region typescriptTypeParameters matchgroup=typescriptTypeBrackets
+ \ start=/</ end=/>/
+ \ contains=typescriptTypeParameter
+ \ contained
+
+syntax match typescriptTypeParameter /\K\k*/
+ \ nextgroup=typescriptConstraint,typescriptGenericDefault
+ \ contained skipwhite skipnl
+
+syntax keyword typescriptConstraint extends
+ \ nextgroup=@typescriptType
+ \ contained skipwhite skipnl
+
+syntax match typescriptGenericDefault /=/
+ \ nextgroup=@typescriptType
+ \ contained skipwhite
+
+"><
+" class A extend B<T> {} // ClassBlock
+" func<T>() // FuncCallArg
+syntax region typescriptTypeArguments matchgroup=typescriptTypeBrackets
+ \ start=/\></ end=/>/
+ \ contains=@typescriptType
+ \ nextgroup=typescriptFuncCallArg,@typescriptTypeOperator
+ \ contained skipwhite
+
+
+syntax cluster typescriptType contains=
+ \ @typescriptPrimaryType,
+ \ typescriptUnion,
+ \ @typescriptFunctionType,
+ \ typescriptConstructorType
+
+" array type: A[]
+" type indexing A['key']
+syntax region typescriptTypeBracket contained
+ \ start=/\[/ end=/\]/
+ \ contains=typescriptString,typescriptNumber
+ \ nextgroup=@typescriptTypeOperator
+ \ skipwhite skipempty
+
+syntax cluster typescriptPrimaryType contains=
+ \ typescriptParenthesizedType,
+ \ typescriptPredefinedType,
+ \ typescriptTypeReference,
+ \ typescriptObjectType,
+ \ typescriptTupleType,
+ \ typescriptTypeQuery,
+ \ typescriptStringLiteralType,
+ \ typescriptReadonlyArrayKeyword
+
+syntax region typescriptStringLiteralType contained
+ \ start=/\z(["']\)/ skip=/\\\\\|\\\z1\|\\\n/ end=/\z1\|$/
+ \ nextgroup=typescriptUnion
+ \ skipwhite skipempty
+
+syntax region typescriptParenthesizedType matchgroup=typescriptParens
+ \ start=/(/ end=/)/
+ \ contains=@typescriptType
+ \ nextgroup=@typescriptTypeOperator
+ \ contained skipwhite skipempty fold
+
+syntax match typescriptTypeReference /\K\k*\(\.\K\k*\)*/
+ \ nextgroup=typescriptTypeArguments,@typescriptTypeOperator,typescriptUserDefinedType
+ \ skipwhite contained skipempty
+
+syntax keyword typescriptPredefinedType any number boolean string void never undefined null object unknown
+ \ nextgroup=@typescriptTypeOperator
+ \ contained skipwhite skipempty
+
+syntax match typescriptPredefinedType /unique symbol/
+ \ nextgroup=@typescriptTypeOperator
+ \ contained skipwhite skipempty
+
+syntax region typescriptObjectType matchgroup=typescriptBraces
+ \ start=/{/ end=/}/
+ \ contains=@typescriptTypeMember,typescriptEndColons,@typescriptComments,typescriptAccessibilityModifier,typescriptReadonlyModifier
+ \ nextgroup=@typescriptTypeOperator
+ \ contained skipwhite fold
+
+syntax cluster typescriptTypeMember contains=
+ \ @typescriptCallSignature,
+ \ typescriptConstructSignature,
+ \ typescriptIndexSignature,
+ \ @typescriptMembers
+
+syntax region typescriptTupleType matchgroup=typescriptBraces
+ \ start=/\[/ end=/\]/
+ \ contains=@typescriptType
+ \ contained skipwhite oneline
+
+syntax cluster typescriptTypeOperator
+ \ contains=typescriptUnion,typescriptTypeBracket
+
+syntax match typescriptUnion /|\|&/ contained nextgroup=@typescriptPrimaryType skipwhite skipempty
+
+syntax cluster typescriptFunctionType contains=typescriptGenericFunc,typescriptFuncType
+syntax region typescriptGenericFunc matchgroup=typescriptTypeBrackets
+ \ start=/</ end=/>/
+ \ contains=typescriptTypeParameter
+ \ nextgroup=typescriptFuncType
+ \ containedin=typescriptFunctionType
+ \ contained skipwhite skipnl
+
+syntax region typescriptFuncType matchgroup=typescriptParens
+ \ start=/(/ end=/)\s*=>/me=e-2
+ \ contains=@typescriptParameterList
+ \ nextgroup=typescriptFuncTypeArrow
+ \ contained skipwhite skipnl oneline
+
+syntax match typescriptFuncTypeArrow /=>/
+ \ nextgroup=@typescriptType
+ \ containedin=typescriptFuncType
+ \ contained skipwhite skipnl
+
+
+syntax keyword typescriptConstructorType new
+ \ nextgroup=@typescriptFunctionType
+ \ contained skipwhite skipnl
+
+syntax keyword typescriptUserDefinedType is
+ \ contained nextgroup=@typescriptType skipwhite skipempty
+
+syntax keyword typescriptTypeQuery typeof keyof
+ \ nextgroup=typescriptTypeReference
+ \ contained skipwhite skipnl
+
+syntax cluster typescriptCallSignature contains=typescriptGenericCall,typescriptCall
+syntax region typescriptGenericCall matchgroup=typescriptTypeBrackets
+ \ start=/</ end=/>/
+ \ contains=typescriptTypeParameter
+ \ nextgroup=typescriptCall
+ \ contained skipwhite skipnl
+syntax region typescriptCall matchgroup=typescriptParens
+ \ start=/(/ end=/)/
+ \ contains=typescriptDecorator,@typescriptParameterList,@typescriptComments
+ \ nextgroup=typescriptTypeAnnotation,typescriptBlock
+ \ contained skipwhite skipnl
+
+syntax match typescriptTypeAnnotation /:/
+ \ nextgroup=@typescriptType
+ \ contained skipwhite skipnl
+
+syntax cluster typescriptParameterList contains=
+ \ typescriptTypeAnnotation,
+ \ typescriptAccessibilityModifier,
+ \ typescriptOptionalMark,
+ \ typescriptRestOrSpread,
+ \ typescriptFuncComma,
+ \ typescriptDefaultParam
+
+syntax match typescriptFuncComma /,/ contained
+
+syntax match typescriptDefaultParam /=/
+ \ nextgroup=@typescriptValue
+ \ contained skipwhite
+
+syntax keyword typescriptConstructSignature new
+ \ nextgroup=@typescriptCallSignature
+ \ contained skipwhite
+
+syntax region typescriptIndexSignature matchgroup=typescriptBraces
+ \ start=/\[/ end=/\]/
+ \ contains=typescriptPredefinedType,typescriptMappedIn,typescriptString
+ \ nextgroup=typescriptTypeAnnotation
+ \ contained skipwhite oneline
+
+syntax keyword typescriptMappedIn in
+ \ nextgroup=@typescriptType
+ \ contained skipwhite skipnl skipempty
+
+syntax keyword typescriptAliasKeyword type
+ \ nextgroup=typescriptAliasDeclaration
+ \ skipwhite skipnl skipempty
+
+syntax region typescriptAliasDeclaration matchgroup=typescriptUnion
+ \ start=/ / end=/=/
+ \ nextgroup=@typescriptType
+ \ contains=typescriptConstraint,typescriptTypeParameters
+ \ contained skipwhite skipempty
+
+syntax keyword typescriptReadonlyArrayKeyword readonly
+ \ nextgroup=@typescriptPrimaryType
+ \ skipwhite
+
+" extension
+if get(g:, 'yats_host_keyword', 1)
+ "runtime syntax/yats.vim
+ "runtime syntax/yats/typescript.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Function Boolean
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Error EvalError
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName InternalError
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName RangeError ReferenceError
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName StopIteration
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName SyntaxError TypeError
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName URIError Date
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Float32Array
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Float64Array
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Int16Array Int32Array
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Int8Array Uint16Array
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Uint32Array Uint8Array
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Uint8ClampedArray
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName ParallelArray
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName ArrayBuffer DataView
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Iterator Generator
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Reflect Proxy
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName arguments
+ hi def link typescriptGlobal Structure
+ syntax keyword typescriptGlobalMethod containedin=typescriptIdentifierName eval uneval nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptGlobalMethod containedin=typescriptIdentifierName isFinite nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptGlobalMethod containedin=typescriptIdentifierName isNaN parseFloat nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptGlobalMethod containedin=typescriptIdentifierName parseInt nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptGlobalMethod containedin=typescriptIdentifierName decodeURI nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptGlobalMethod containedin=typescriptIdentifierName decodeURIComponent nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptGlobalMethod containedin=typescriptIdentifierName encodeURI nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptGlobalMethod containedin=typescriptIdentifierName encodeURIComponent nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptGlobalMethod
+ hi def link typescriptGlobalMethod Structure
+
+ "runtime syntax/yats/es6-number.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Number nextgroup=typescriptGlobalNumberDot,typescriptFuncCallArg
+ syntax match typescriptGlobalNumberDot /\./ contained nextgroup=typescriptNumberStaticProp,typescriptNumberStaticMethod,typescriptProp
+ syntax keyword typescriptNumberStaticProp contained EPSILON MAX_SAFE_INTEGER MAX_VALUE
+ syntax keyword typescriptNumberStaticProp contained MIN_SAFE_INTEGER MIN_VALUE NEGATIVE_INFINITY
+ syntax keyword typescriptNumberStaticProp contained NaN POSITIVE_INFINITY
+ hi def link typescriptNumberStaticProp Keyword
+ syntax keyword typescriptNumberStaticMethod contained isFinite isInteger isNaN isSafeInteger nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptNumberStaticMethod contained parseFloat parseInt nextgroup=typescriptFuncCallArg
+ hi def link typescriptNumberStaticMethod Keyword
+ syntax keyword typescriptNumberMethod contained toExponential toFixed toLocaleString nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptNumberMethod contained toPrecision toSource toString valueOf nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptNumberMethod
+ hi def link typescriptNumberMethod Keyword
+
+ "runtime syntax/yats/es6-string.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName String nextgroup=typescriptGlobalStringDot,typescriptFuncCallArg
+ syntax match typescriptGlobalStringDot /\./ contained nextgroup=typescriptStringStaticMethod,typescriptProp
+ syntax keyword typescriptStringStaticMethod contained fromCharCode fromCodePoint raw nextgroup=typescriptFuncCallArg
+ hi def link typescriptStringStaticMethod Keyword
+ syntax keyword typescriptStringMethod contained anchor charAt charCodeAt codePointAt nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptStringMethod contained concat endsWith includes indexOf lastIndexOf nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptStringMethod contained link localeCompare match normalize nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptStringMethod contained padStart padEnd repeat replace search nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptStringMethod contained slice split startsWith substr substring nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptStringMethod contained toLocaleLowerCase toLocaleUpperCase nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptStringMethod contained toLowerCase toString toUpperCase trim nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptStringMethod contained valueOf nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptStringMethod
+ hi def link typescriptStringMethod Keyword
+
+ "runtime syntax/yats/es6-array.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Array nextgroup=typescriptGlobalArrayDot,typescriptFuncCallArg
+ syntax match typescriptGlobalArrayDot /\./ contained nextgroup=typescriptArrayStaticMethod,typescriptProp
+ syntax keyword typescriptArrayStaticMethod contained from isArray of nextgroup=typescriptFuncCallArg
+ hi def link typescriptArrayStaticMethod Keyword
+ syntax keyword typescriptArrayMethod contained concat copyWithin entries every fill nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptArrayMethod contained filter find findIndex forEach indexOf nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptArrayMethod contained includes join keys lastIndexOf map nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptArrayMethod contained pop push reduce reduceRight reverse nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptArrayMethod contained shift slice some sort splice toLocaleString nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptArrayMethod contained toSource toString unshift nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptArrayMethod
+ hi def link typescriptArrayMethod Keyword
+
+ "runtime syntax/yats/es6-object.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Object nextgroup=typescriptGlobalObjectDot,typescriptFuncCallArg
+ syntax match typescriptGlobalObjectDot /\./ contained nextgroup=typescriptObjectStaticMethod,typescriptProp
+ syntax keyword typescriptObjectStaticMethod contained create defineProperties defineProperty nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptObjectStaticMethod contained entries freeze getOwnPropertyDescriptors nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptObjectStaticMethod contained getOwnPropertyDescriptor getOwnPropertyNames nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptObjectStaticMethod contained getOwnPropertySymbols getPrototypeOf nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptObjectStaticMethod contained is isExtensible isFrozen isSealed nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptObjectStaticMethod contained keys preventExtensions values nextgroup=typescriptFuncCallArg
+ hi def link typescriptObjectStaticMethod Keyword
+ syntax keyword typescriptObjectMethod contained getOwnPropertyDescriptors hasOwnProperty nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptObjectMethod contained isPrototypeOf propertyIsEnumerable nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptObjectMethod contained toLocaleString toString valueOf seal nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptObjectMethod contained setPrototypeOf nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptObjectMethod
+ hi def link typescriptObjectMethod Keyword
+
+ "runtime syntax/yats/es6-symbol.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Symbol nextgroup=typescriptGlobalSymbolDot,typescriptFuncCallArg
+ syntax match typescriptGlobalSymbolDot /\./ contained nextgroup=typescriptSymbolStaticProp,typescriptSymbolStaticMethod,typescriptProp
+ syntax keyword typescriptSymbolStaticProp contained length iterator match replace
+ syntax keyword typescriptSymbolStaticProp contained search split hasInstance isConcatSpreadable
+ syntax keyword typescriptSymbolStaticProp contained unscopables species toPrimitive
+ syntax keyword typescriptSymbolStaticProp contained toStringTag
+ hi def link typescriptSymbolStaticProp Keyword
+ syntax keyword typescriptSymbolStaticMethod contained for keyFor nextgroup=typescriptFuncCallArg
+ hi def link typescriptSymbolStaticMethod Keyword
+
+ "runtime syntax/yats/es6-function.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Function
+ syntax keyword typescriptFunctionMethod contained apply bind call nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptFunctionMethod
+ hi def link typescriptFunctionMethod Keyword
+
+ "runtime syntax/yats/es6-math.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Math nextgroup=typescriptGlobalMathDot,typescriptFuncCallArg
+ syntax match typescriptGlobalMathDot /\./ contained nextgroup=typescriptMathStaticProp,typescriptMathStaticMethod,typescriptProp
+ syntax keyword typescriptMathStaticProp contained E LN10 LN2 LOG10E LOG2E PI SQRT1_2
+ syntax keyword typescriptMathStaticProp contained SQRT2
+ hi def link typescriptMathStaticProp Keyword
+ syntax keyword typescriptMathStaticMethod contained abs acos acosh asin asinh atan nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptMathStaticMethod contained atan2 atanh cbrt ceil clz32 cos nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptMathStaticMethod contained cosh exp expm1 floor fround hypot nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptMathStaticMethod contained imul log log10 log1p log2 max nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptMathStaticMethod contained min pow random round sign sin nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptMathStaticMethod contained sinh sqrt tan tanh trunc nextgroup=typescriptFuncCallArg
+ hi def link typescriptMathStaticMethod Keyword
+
+ "runtime syntax/yats/es6-date.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Date nextgroup=typescriptGlobalDateDot,typescriptFuncCallArg
+ syntax match typescriptGlobalDateDot /\./ contained nextgroup=typescriptDateStaticMethod,typescriptProp
+ syntax keyword typescriptDateStaticMethod contained UTC now parse nextgroup=typescriptFuncCallArg
+ hi def link typescriptDateStaticMethod Keyword
+ syntax keyword typescriptDateMethod contained getDate getDay getFullYear getHours nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDateMethod contained getMilliseconds getMinutes getMonth nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDateMethod contained getSeconds getTime getTimezoneOffset nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDateMethod contained getUTCDate getUTCDay getUTCFullYear nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDateMethod contained getUTCHours getUTCMilliseconds getUTCMinutes nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDateMethod contained getUTCMonth getUTCSeconds setDate setFullYear nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDateMethod contained setHours setMilliseconds setMinutes nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDateMethod contained setMonth setSeconds setTime setUTCDate nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDateMethod contained setUTCFullYear setUTCHours setUTCMilliseconds nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDateMethod contained setUTCMinutes setUTCMonth setUTCSeconds nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDateMethod contained toDateString toISOString toJSON toLocaleDateString nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDateMethod contained toLocaleFormat toLocaleString toLocaleTimeString nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDateMethod contained toSource toString toTimeString toUTCString nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDateMethod contained valueOf nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptDateMethod
+ hi def link typescriptDateMethod Keyword
+
+ "runtime syntax/yats/es6-json.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName JSON nextgroup=typescriptGlobalJSONDot,typescriptFuncCallArg
+ syntax match typescriptGlobalJSONDot /\./ contained nextgroup=typescriptJSONStaticMethod,typescriptProp
+ syntax keyword typescriptJSONStaticMethod contained parse stringify nextgroup=typescriptFuncCallArg
+ hi def link typescriptJSONStaticMethod Keyword
+
+ "runtime syntax/yats/es6-regexp.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName RegExp nextgroup=typescriptGlobalRegExpDot,typescriptFuncCallArg
+ syntax match typescriptGlobalRegExpDot /\./ contained nextgroup=typescriptRegExpStaticProp,typescriptProp
+ syntax keyword typescriptRegExpStaticProp contained lastIndex
+ hi def link typescriptRegExpStaticProp Keyword
+ syntax keyword typescriptRegExpProp contained global ignoreCase multiline source sticky
+ syntax cluster props add=typescriptRegExpProp
+ hi def link typescriptRegExpProp Keyword
+ syntax keyword typescriptRegExpMethod contained exec test nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptRegExpMethod
+ hi def link typescriptRegExpMethod Keyword
+
+ "runtime syntax/yats/es6-map.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Map WeakMap
+ syntax keyword typescriptES6MapProp contained size
+ syntax cluster props add=typescriptES6MapProp
+ hi def link typescriptES6MapProp Keyword
+ syntax keyword typescriptES6MapMethod contained clear delete entries forEach get has nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptES6MapMethod contained keys set values nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptES6MapMethod
+ hi def link typescriptES6MapMethod Keyword
+
+ "runtime syntax/yats/es6-set.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Set WeakSet
+ syntax keyword typescriptES6SetProp contained size
+ syntax cluster props add=typescriptES6SetProp
+ hi def link typescriptES6SetProp Keyword
+ syntax keyword typescriptES6SetMethod contained add clear delete entries forEach has nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptES6SetMethod contained values nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptES6SetMethod
+ hi def link typescriptES6SetMethod Keyword
+
+ "runtime syntax/yats/es6-proxy.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Proxy
+ syntax keyword typescriptProxyAPI contained getOwnPropertyDescriptor getOwnPropertyNames
+ syntax keyword typescriptProxyAPI contained defineProperty deleteProperty freeze seal
+ syntax keyword typescriptProxyAPI contained preventExtensions has hasOwn get set enumerate
+ syntax keyword typescriptProxyAPI contained iterate ownKeys apply construct
+ hi def link typescriptProxyAPI Keyword
+
+ "runtime syntax/yats/es6-promise.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Promise nextgroup=typescriptGlobalPromiseDot,typescriptFuncCallArg
+ syntax match typescriptGlobalPromiseDot /\./ contained nextgroup=typescriptPromiseStaticMethod,typescriptProp
+ syntax keyword typescriptPromiseStaticMethod contained resolve reject all race nextgroup=typescriptFuncCallArg
+ hi def link typescriptPromiseStaticMethod Keyword
+ syntax keyword typescriptPromiseMethod contained then catch finally nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptPromiseMethod
+ hi def link typescriptPromiseMethod Keyword
+
+ "runtime syntax/yats/es6-reflect.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Reflect
+ syntax keyword typescriptReflectMethod contained apply construct defineProperty deleteProperty nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptReflectMethod contained enumerate get getOwnPropertyDescriptor nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptReflectMethod contained getPrototypeOf has isExtensible ownKeys nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptReflectMethod contained preventExtensions set setPrototypeOf nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptReflectMethod
+ hi def link typescriptReflectMethod Keyword
+
+ "runtime syntax/yats/ecma-402.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Intl
+ syntax keyword typescriptIntlMethod contained Collator DateTimeFormat NumberFormat nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptIntlMethod contained PluralRules nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptIntlMethod
+ hi def link typescriptIntlMethod Keyword
+
+ "runtime syntax/yats/node.vim
+ syntax keyword typescriptNodeGlobal containedin=typescriptIdentifierName global process
+ syntax keyword typescriptNodeGlobal containedin=typescriptIdentifierName console Buffer
+ syntax keyword typescriptNodeGlobal containedin=typescriptIdentifierName module exports
+ syntax keyword typescriptNodeGlobal containedin=typescriptIdentifierName setTimeout
+ syntax keyword typescriptNodeGlobal containedin=typescriptIdentifierName clearTimeout
+ syntax keyword typescriptNodeGlobal containedin=typescriptIdentifierName setInterval
+ syntax keyword typescriptNodeGlobal containedin=typescriptIdentifierName clearInterval
+ hi def link typescriptNodeGlobal Structure
+
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName describe it test
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName before after
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName beforeEach afterEach
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName beforeAll afterAll
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName expect assert
+
+ "runtime syntax/yats/web.vim
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName AbortController
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName AbstractWorker AnalyserNode
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName App Apps ArrayBuffer
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName ArrayBufferView
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Attr AudioBuffer
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName AudioBufferSourceNode
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName AudioContext AudioDestinationNode
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName AudioListener AudioNode
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName AudioParam BatteryManager
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName BiquadFilterNode
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName BlobEvent BluetoothAdapter
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName BluetoothDevice
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName BluetoothManager
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CameraCapabilities
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CameraControl CameraManager
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CanvasGradient CanvasImageSource
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CanvasPattern CanvasRenderingContext2D
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CaretPosition CDATASection
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName ChannelMergerNode
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName ChannelSplitterNode
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CharacterData ChildNode
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName ChromeWorker Comment
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Connection Console
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName ContactManager Contacts
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName ConvolverNode Coordinates
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CSS CSSConditionRule
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CSSGroupingRule
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CSSKeyframeRule
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CSSKeyframesRule
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CSSMediaRule CSSNamespaceRule
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CSSPageRule CSSRule
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CSSRuleList CSSStyleDeclaration
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CSSStyleRule CSSStyleSheet
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName CSSSupportsRule
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DataTransfer DataView
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DedicatedWorkerGlobalScope
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DelayNode DeviceAcceleration
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DeviceRotationRate
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DeviceStorage DirectoryEntry
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DirectoryEntrySync
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DirectoryReader
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DirectoryReaderSync
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Document DocumentFragment
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DocumentTouch DocumentType
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DOMCursor DOMError
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DOMException DOMHighResTimeStamp
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DOMImplementation
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DOMImplementationRegistry
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DOMParser DOMRequest
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DOMString DOMStringList
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DOMStringMap DOMTimeStamp
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName DOMTokenList DynamicsCompressorNode
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Element Entry EntrySync
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Extensions FileException
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Float32Array Float64Array
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName FMRadio FormData
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName GainNode Gamepad
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName GamepadButton Geolocation
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName History HTMLAnchorElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLAreaElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLAudioElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLBaseElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLBodyElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLBRElement HTMLButtonElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLCanvasElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLCollection HTMLDataElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLDataListElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLDivElement HTMLDListElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLDocument HTMLElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLEmbedElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLFieldSetElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLFormControlsCollection
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLFormElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLHeadElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLHeadingElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLHRElement HTMLHtmlElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLIFrameElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLImageElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLInputElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLKeygenElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLLabelElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLLegendElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLLIElement HTMLLinkElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLMapElement HTMLMediaElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLMetaElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLMeterElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLModElement HTMLObjectElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLOListElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLOptGroupElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLOptionElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLOptionsCollection
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLOutputElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLParagraphElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLParamElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLPreElement HTMLProgressElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLQuoteElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLScriptElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLSelectElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLSourceElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLSpanElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLStyleElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTableCaptionElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTableCellElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTableColElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTableDataCellElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTableElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTableHeaderCellElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTableRowElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTableSectionElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTextAreaElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTimeElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTitleElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLTrackElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLUListElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLUnknownElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName HTMLVideoElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBCursor IDBCursorSync
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBCursorWithValue
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBDatabase IDBDatabaseSync
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBEnvironment IDBEnvironmentSync
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBFactory IDBFactorySync
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBIndex IDBIndexSync
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBKeyRange IDBObjectStore
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBObjectStoreSync
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBOpenDBRequest
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBRequest IDBTransaction
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBTransactionSync
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName IDBVersionChangeEvent
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName ImageData IndexedDB
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Int16Array Int32Array
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Int8Array L10n LinkStyle
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName LocalFileSystem
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName LocalFileSystemSync
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Location LockedFile
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName MediaQueryList MediaQueryListListener
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName MediaRecorder MediaSource
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName MediaStream MediaStreamTrack
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName MutationObserver
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Navigator NavigatorGeolocation
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName NavigatorID NavigatorLanguage
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName NavigatorOnLine
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName NavigatorPlugins
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Node NodeFilter
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName NodeIterator NodeList
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Notification OfflineAudioContext
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName OscillatorNode PannerNode
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName ParentNode Performance
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName PerformanceNavigation
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName PerformanceTiming
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Permissions PermissionSettings
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Plugin PluginArray
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Position PositionError
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName PositionOptions
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName PowerManager ProcessingInstruction
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName PromiseResolver
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName PushManager Range
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName RTCConfiguration
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName RTCPeerConnection
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName RTCPeerConnectionErrorCallback
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName RTCSessionDescription
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName RTCSessionDescriptionCallback
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName ScriptProcessorNode
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Selection SettingsLock
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SettingsManager
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SharedWorker StyleSheet
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName StyleSheetList SVGAElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAngle SVGAnimateColorElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedAngle
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedBoolean
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedEnumeration
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedInteger
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedLength
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedLengthList
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedNumber
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedNumberList
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedPoints
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedPreserveAspectRatio
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedRect
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedString
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimatedTransformList
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimateElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimateMotionElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimateTransformElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGAnimationElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGCircleElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGClipPathElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGCursorElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGDefsElement SVGDescElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGElement SVGEllipseElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGFilterElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGFontElement SVGFontFaceElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGFontFaceFormatElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGFontFaceNameElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGFontFaceSrcElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGFontFaceUriElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGForeignObjectElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGGElement SVGGlyphElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGGradientElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGHKernElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGImageElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGLength SVGLengthList
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGLinearGradientElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGLineElement SVGMaskElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGMatrix SVGMissingGlyphElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGMPathElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGNumber SVGNumberList
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGPathElement SVGPatternElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGPoint SVGPolygonElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGPolylineElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGPreserveAspectRatio
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGRadialGradientElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGRect SVGRectElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGScriptElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGSetElement SVGStopElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGStringList SVGStylable
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGStyleElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGSVGElement SVGSwitchElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGSymbolElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGTests SVGTextElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGTextPositioningElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGTitleElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGTransform SVGTransformable
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGTransformList
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGTRefElement SVGTSpanElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGUseElement SVGViewElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName SVGVKernElement
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName TCPServerSocket
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName TCPSocket Telephony
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName TelephonyCall Text
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName TextDecoder TextEncoder
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName TextMetrics TimeRanges
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Touch TouchList
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Transferable TreeWalker
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Uint16Array Uint32Array
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Uint8Array Uint8ClampedArray
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName URLSearchParams
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName URLUtilsReadOnly
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName UserProximityEvent
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName ValidityState VideoPlaybackQuality
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName WaveShaperNode WebBluetooth
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName WebGLRenderingContext
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName WebSMS WebSocket
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName WebVTT WifiManager
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName Window Worker WorkerConsole
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName WorkerLocation WorkerNavigator
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName XDomainRequest XMLDocument
+ syntax keyword typescriptBOM containedin=typescriptIdentifierName XMLHttpRequestEventTarget
+ hi def link typescriptBOM Structure
+
+ "runtime syntax/yats/web-window.vim
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName applicationCache
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName closed
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName Components
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName controllers
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName dialogArguments
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName document
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName frameElement
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName frames
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName fullScreen
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName history
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName innerHeight
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName innerWidth
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName length
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName location
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName locationbar
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName menubar
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName messageManager
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName name navigator
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName opener
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName outerHeight
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName outerWidth
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName pageXOffset
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName pageYOffset
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName parent
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName performance
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName personalbar
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName returnValue
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName screen
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName screenX
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName screenY
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName scrollbars
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName scrollMaxX
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName scrollMaxY
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName scrollX
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName scrollY
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName self sidebar
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName status
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName statusbar
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName toolbar
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName top visualViewport
+ syntax keyword typescriptBOMWindowProp containedin=typescriptIdentifierName window
+ syntax cluster props add=typescriptBOMWindowProp
+ hi def link typescriptBOMWindowProp Structure
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName alert nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName atob nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName blur nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName btoa nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName clearImmediate nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName clearInterval nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName clearTimeout nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName close nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName confirm nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName dispatchEvent nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName find nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName focus nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName getAttention nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName getAttentionWithCycleCount nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName getComputedStyle nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName getDefaulComputedStyle nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName getSelection nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName matchMedia nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName maximize nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName moveBy nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName moveTo nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName open nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName openDialog nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName postMessage nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName print nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName prompt nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName removeEventListener nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName resizeBy nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName resizeTo nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName restore nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName scroll nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName scrollBy nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName scrollByLines nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName scrollByPages nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName scrollTo nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName setCursor nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName setImmediate nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName setInterval nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName setResizable nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName setTimeout nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName showModalDialog nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName sizeToContent nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName stop nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMWindowMethod containedin=typescriptIdentifierName updateCommands nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptBOMWindowMethod
+ hi def link typescriptBOMWindowMethod Structure
+ syntax keyword typescriptBOMWindowEvent contained onabort onbeforeunload onblur onchange
+ syntax keyword typescriptBOMWindowEvent contained onclick onclose oncontextmenu ondevicelight
+ syntax keyword typescriptBOMWindowEvent contained ondevicemotion ondeviceorientation
+ syntax keyword typescriptBOMWindowEvent contained ondeviceproximity ondragdrop onerror
+ syntax keyword typescriptBOMWindowEvent contained onfocus onhashchange onkeydown onkeypress
+ syntax keyword typescriptBOMWindowEvent contained onkeyup onload onmousedown onmousemove
+ syntax keyword typescriptBOMWindowEvent contained onmouseout onmouseover onmouseup
+ syntax keyword typescriptBOMWindowEvent contained onmozbeforepaint onpaint onpopstate
+ syntax keyword typescriptBOMWindowEvent contained onreset onresize onscroll onselect
+ syntax keyword typescriptBOMWindowEvent contained onsubmit onunload onuserproximity
+ syntax keyword typescriptBOMWindowEvent contained onpageshow onpagehide
+ hi def link typescriptBOMWindowEvent Keyword
+ syntax keyword typescriptBOMWindowCons containedin=typescriptIdentifierName DOMParser
+ syntax keyword typescriptBOMWindowCons containedin=typescriptIdentifierName QueryInterface
+ syntax keyword typescriptBOMWindowCons containedin=typescriptIdentifierName XMLSerializer
+ hi def link typescriptBOMWindowCons Structure
+
+ "runtime syntax/yats/web-navigator.vim
+ syntax keyword typescriptBOMNavigatorProp contained battery buildID connection cookieEnabled
+ syntax keyword typescriptBOMNavigatorProp contained doNotTrack maxTouchPoints oscpu
+ syntax keyword typescriptBOMNavigatorProp contained productSub push serviceWorker
+ syntax keyword typescriptBOMNavigatorProp contained vendor vendorSub
+ syntax cluster props add=typescriptBOMNavigatorProp
+ hi def link typescriptBOMNavigatorProp Keyword
+ syntax keyword typescriptBOMNavigatorMethod contained addIdleObserver geolocation nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMNavigatorMethod contained getDeviceStorage getDeviceStorages nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMNavigatorMethod contained getGamepads getUserMedia registerContentHandler nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMNavigatorMethod contained removeIdleObserver requestWakeLock nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMNavigatorMethod contained share vibrate watch registerProtocolHandler nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptBOMNavigatorMethod contained sendBeacon nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptBOMNavigatorMethod
+ hi def link typescriptBOMNavigatorMethod Keyword
+ syntax keyword typescriptServiceWorkerMethod contained register nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptServiceWorkerMethod
+ hi def link typescriptServiceWorkerMethod Keyword
+
+ "runtime syntax/yats/web-location.vim
+ syntax keyword typescriptBOMLocationProp contained href protocol host hostname port
+ syntax keyword typescriptBOMLocationProp contained pathname search hash username password
+ syntax keyword typescriptBOMLocationProp contained origin
+ syntax cluster props add=typescriptBOMLocationProp
+ hi def link typescriptBOMLocationProp Keyword
+ syntax keyword typescriptBOMLocationMethod contained assign reload replace toString nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptBOMLocationMethod
+ hi def link typescriptBOMLocationMethod Keyword
+
+ "runtime syntax/yats/web-history.vim
+ syntax keyword typescriptBOMHistoryProp contained length current next previous state
+ syntax keyword typescriptBOMHistoryProp contained scrollRestoration
+ syntax cluster props add=typescriptBOMHistoryProp
+ hi def link typescriptBOMHistoryProp Keyword
+ syntax keyword typescriptBOMHistoryMethod contained back forward go pushState replaceState nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptBOMHistoryMethod
+ hi def link typescriptBOMHistoryMethod Keyword
+
+ "runtime syntax/yats/web-console.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName console
+ syntax keyword typescriptConsoleMethod contained count dir error group groupCollapsed nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptConsoleMethod contained groupEnd info log time timeEnd trace nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptConsoleMethod contained warn nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptConsoleMethod
+ hi def link typescriptConsoleMethod Keyword
+
+ "runtime syntax/yats/web-xhr.vim
+ syntax keyword typescriptXHRGlobal containedin=typescriptIdentifierName XMLHttpRequest
+ hi def link typescriptXHRGlobal Structure
+ syntax keyword typescriptXHRProp contained onreadystatechange readyState response
+ syntax keyword typescriptXHRProp contained responseText responseType responseXML status
+ syntax keyword typescriptXHRProp contained statusText timeout ontimeout upload withCredentials
+ syntax cluster props add=typescriptXHRProp
+ hi def link typescriptXHRProp Keyword
+ syntax keyword typescriptXHRMethod contained abort getAllResponseHeaders getResponseHeader nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptXHRMethod contained open overrideMimeType send setRequestHeader nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptXHRMethod
+ hi def link typescriptXHRMethod Keyword
+
+ "runtime syntax/yats/web-blob.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Blob BlobBuilder
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName File FileReader
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName FileReaderSync
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName URL nextgroup=typescriptGlobalURLDot,typescriptFuncCallArg
+ syntax match typescriptGlobalURLDot /\./ contained nextgroup=typescriptURLStaticMethod,typescriptProp
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName URLUtils
+ syntax keyword typescriptFileMethod contained readAsArrayBuffer readAsBinaryString nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptFileMethod contained readAsDataURL readAsText nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptFileMethod
+ hi def link typescriptFileMethod Keyword
+ syntax keyword typescriptFileReaderProp contained error readyState result
+ syntax cluster props add=typescriptFileReaderProp
+ hi def link typescriptFileReaderProp Keyword
+ syntax keyword typescriptFileReaderMethod contained abort readAsArrayBuffer readAsBinaryString nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptFileReaderMethod contained readAsDataURL readAsText nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptFileReaderMethod
+ hi def link typescriptFileReaderMethod Keyword
+ syntax keyword typescriptFileListMethod contained item nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptFileListMethod
+ hi def link typescriptFileListMethod Keyword
+ syntax keyword typescriptBlobMethod contained append getBlob getFile nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptBlobMethod
+ hi def link typescriptBlobMethod Keyword
+ syntax keyword typescriptURLUtilsProp contained hash host hostname href origin password
+ syntax keyword typescriptURLUtilsProp contained pathname port protocol search searchParams
+ syntax keyword typescriptURLUtilsProp contained username
+ syntax cluster props add=typescriptURLUtilsProp
+ hi def link typescriptURLUtilsProp Keyword
+ syntax keyword typescriptURLStaticMethod contained createObjectURL revokeObjectURL nextgroup=typescriptFuncCallArg
+ hi def link typescriptURLStaticMethod Keyword
+
+ "runtime syntax/yats/web-crypto.vim
+ syntax keyword typescriptCryptoGlobal containedin=typescriptIdentifierName crypto
+ hi def link typescriptCryptoGlobal Structure
+ syntax keyword typescriptSubtleCryptoMethod contained encrypt decrypt sign verify nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptSubtleCryptoMethod contained digest nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptSubtleCryptoMethod
+ hi def link typescriptSubtleCryptoMethod Keyword
+ syntax keyword typescriptCryptoProp contained subtle
+ syntax cluster props add=typescriptCryptoProp
+ hi def link typescriptCryptoProp Keyword
+ syntax keyword typescriptCryptoMethod contained getRandomValues nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptCryptoMethod
+ hi def link typescriptCryptoMethod Keyword
+
+ "runtime syntax/yats/web-fetch.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Headers Request
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Response
+ syntax keyword typescriptGlobalMethod containedin=typescriptIdentifierName fetch nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptGlobalMethod
+ hi def link typescriptGlobalMethod Structure
+ syntax keyword typescriptHeadersMethod contained append delete get getAll has set nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptHeadersMethod
+ hi def link typescriptHeadersMethod Keyword
+ syntax keyword typescriptRequestProp contained method url headers context referrer
+ syntax keyword typescriptRequestProp contained mode credentials cache
+ syntax cluster props add=typescriptRequestProp
+ hi def link typescriptRequestProp Keyword
+ syntax keyword typescriptRequestMethod contained clone nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptRequestMethod
+ hi def link typescriptRequestMethod Keyword
+ syntax keyword typescriptResponseProp contained type url status statusText headers
+ syntax keyword typescriptResponseProp contained redirected
+ syntax cluster props add=typescriptResponseProp
+ hi def link typescriptResponseProp Keyword
+ syntax keyword typescriptResponseMethod contained clone nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptResponseMethod
+ hi def link typescriptResponseMethod Keyword
+
+ "runtime syntax/yats/web-service-worker.vim
+ syntax keyword typescriptServiceWorkerProp contained controller ready
+ syntax cluster props add=typescriptServiceWorkerProp
+ hi def link typescriptServiceWorkerProp Keyword
+ syntax keyword typescriptServiceWorkerMethod contained register getRegistration nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptServiceWorkerMethod
+ hi def link typescriptServiceWorkerMethod Keyword
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Cache
+ syntax keyword typescriptCacheMethod contained match matchAll add addAll put delete nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptCacheMethod contained keys nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptCacheMethod
+ hi def link typescriptCacheMethod Keyword
+
+ "runtime syntax/yats/web-encoding.vim
+ syntax keyword typescriptEncodingGlobal containedin=typescriptIdentifierName TextEncoder
+ syntax keyword typescriptEncodingGlobal containedin=typescriptIdentifierName TextDecoder
+ hi def link typescriptEncodingGlobal Structure
+ syntax keyword typescriptEncodingProp contained encoding fatal ignoreBOM
+ syntax cluster props add=typescriptEncodingProp
+ hi def link typescriptEncodingProp Keyword
+ syntax keyword typescriptEncodingMethod contained encode decode nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptEncodingMethod
+ hi def link typescriptEncodingMethod Keyword
+
+ "runtime syntax/yats/web-geo.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName Geolocation
+ syntax keyword typescriptGeolocationMethod contained getCurrentPosition watchPosition nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptGeolocationMethod contained clearWatch nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptGeolocationMethod
+ hi def link typescriptGeolocationMethod Keyword
+
+ "runtime syntax/yats/web-network.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName NetworkInformation
+ syntax keyword typescriptBOMNetworkProp contained downlink downlinkMax effectiveType
+ syntax keyword typescriptBOMNetworkProp contained rtt type
+ syntax cluster props add=typescriptBOMNetworkProp
+ hi def link typescriptBOMNetworkProp Keyword
+
+ "runtime syntax/yats/web-payment.vim
+ syntax keyword typescriptGlobal containedin=typescriptIdentifierName PaymentRequest
+ syntax keyword typescriptPaymentMethod contained show abort canMakePayment nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptPaymentMethod
+ hi def link typescriptPaymentMethod Keyword
+ syntax keyword typescriptPaymentProp contained shippingAddress shippingOption result
+ syntax cluster props add=typescriptPaymentProp
+ hi def link typescriptPaymentProp Keyword
+ syntax keyword typescriptPaymentEvent contained onshippingaddresschange onshippingoptionchange
+ hi def link typescriptPaymentEvent Keyword
+ syntax keyword typescriptPaymentResponseMethod contained complete nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptPaymentResponseMethod
+ hi def link typescriptPaymentResponseMethod Keyword
+ syntax keyword typescriptPaymentResponseProp contained details methodName payerEmail
+ syntax keyword typescriptPaymentResponseProp contained payerPhone shippingAddress
+ syntax keyword typescriptPaymentResponseProp contained shippingOption
+ syntax cluster props add=typescriptPaymentResponseProp
+ hi def link typescriptPaymentResponseProp Keyword
+ syntax keyword typescriptPaymentAddressProp contained addressLine careOf city country
+ syntax keyword typescriptPaymentAddressProp contained country dependentLocality languageCode
+ syntax keyword typescriptPaymentAddressProp contained organization phone postalCode
+ syntax keyword typescriptPaymentAddressProp contained recipient region sortingCode
+ syntax cluster props add=typescriptPaymentAddressProp
+ hi def link typescriptPaymentAddressProp Keyword
+ syntax keyword typescriptPaymentShippingOptionProp contained id label amount selected
+ syntax cluster props add=typescriptPaymentShippingOptionProp
+ hi def link typescriptPaymentShippingOptionProp Keyword
+
+ "runtime syntax/yats/dom-node.vim
+ syntax keyword typescriptDOMNodeProp contained attributes baseURI baseURIObject childNodes
+ syntax keyword typescriptDOMNodeProp contained firstChild lastChild localName namespaceURI
+ syntax keyword typescriptDOMNodeProp contained nextSibling nodeName nodePrincipal
+ syntax keyword typescriptDOMNodeProp contained nodeType nodeValue ownerDocument parentElement
+ syntax keyword typescriptDOMNodeProp contained parentNode prefix previousSibling textContent
+ syntax cluster props add=typescriptDOMNodeProp
+ hi def link typescriptDOMNodeProp Keyword
+ syntax keyword typescriptDOMNodeMethod contained appendChild cloneNode compareDocumentPosition nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMNodeMethod contained getUserData hasAttributes hasChildNodes nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMNodeMethod contained insertBefore isDefaultNamespace isEqualNode nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMNodeMethod contained isSameNode isSupported lookupNamespaceURI nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMNodeMethod contained lookupPrefix normalize removeChild nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMNodeMethod contained replaceChild setUserData nextgroup=typescriptFuncCallArg
+ syntax match typescriptDOMNodeMethod contained /contains/
+ syntax cluster props add=typescriptDOMNodeMethod
+ hi def link typescriptDOMNodeMethod Keyword
+ syntax keyword typescriptDOMNodeType contained ELEMENT_NODE ATTRIBUTE_NODE TEXT_NODE
+ syntax keyword typescriptDOMNodeType contained CDATA_SECTION_NODEN_NODE ENTITY_REFERENCE_NODE
+ syntax keyword typescriptDOMNodeType contained ENTITY_NODE PROCESSING_INSTRUCTION_NODEN_NODE
+ syntax keyword typescriptDOMNodeType contained COMMENT_NODE DOCUMENT_NODE DOCUMENT_TYPE_NODE
+ syntax keyword typescriptDOMNodeType contained DOCUMENT_FRAGMENT_NODE NOTATION_NODE
+ hi def link typescriptDOMNodeType Keyword
+
+ "runtime syntax/yats/dom-elem.vim
+ syntax keyword typescriptDOMElemAttrs contained accessKey clientHeight clientLeft
+ syntax keyword typescriptDOMElemAttrs contained clientTop clientWidth id innerHTML
+ syntax keyword typescriptDOMElemAttrs contained length onafterscriptexecute onbeforescriptexecute
+ syntax keyword typescriptDOMElemAttrs contained oncopy oncut onpaste onwheel scrollHeight
+ syntax keyword typescriptDOMElemAttrs contained scrollLeft scrollTop scrollWidth tagName
+ syntax keyword typescriptDOMElemAttrs contained classList className name outerHTML
+ syntax keyword typescriptDOMElemAttrs contained style
+ hi def link typescriptDOMElemAttrs Keyword
+ syntax keyword typescriptDOMElemFuncs contained getAttributeNS getAttributeNode getAttributeNodeNS
+ syntax keyword typescriptDOMElemFuncs contained getBoundingClientRect getClientRects
+ syntax keyword typescriptDOMElemFuncs contained getElementsByClassName getElementsByTagName
+ syntax keyword typescriptDOMElemFuncs contained getElementsByTagNameNS hasAttribute
+ syntax keyword typescriptDOMElemFuncs contained hasAttributeNS insertAdjacentHTML
+ syntax keyword typescriptDOMElemFuncs contained matches querySelector querySelectorAll
+ syntax keyword typescriptDOMElemFuncs contained removeAttribute removeAttributeNS
+ syntax keyword typescriptDOMElemFuncs contained removeAttributeNode requestFullscreen
+ syntax keyword typescriptDOMElemFuncs contained requestPointerLock scrollIntoView
+ syntax keyword typescriptDOMElemFuncs contained setAttribute setAttributeNS setAttributeNode
+ syntax keyword typescriptDOMElemFuncs contained setAttributeNodeNS setCapture supports
+ syntax keyword typescriptDOMElemFuncs contained getAttribute
+ hi def link typescriptDOMElemFuncs Keyword
+
+ "runtime syntax/yats/dom-document.vim
+ syntax keyword typescriptDOMDocProp contained activeElement body cookie defaultView
+ syntax keyword typescriptDOMDocProp contained designMode dir domain embeds forms head
+ syntax keyword typescriptDOMDocProp contained images lastModified links location plugins
+ syntax keyword typescriptDOMDocProp contained postMessage readyState referrer registerElement
+ syntax keyword typescriptDOMDocProp contained scripts styleSheets title vlinkColor
+ syntax keyword typescriptDOMDocProp contained xmlEncoding characterSet compatMode
+ syntax keyword typescriptDOMDocProp contained contentType currentScript doctype documentElement
+ syntax keyword typescriptDOMDocProp contained documentURI documentURIObject firstChild
+ syntax keyword typescriptDOMDocProp contained implementation lastStyleSheetSet namespaceURI
+ syntax keyword typescriptDOMDocProp contained nodePrincipal ononline pointerLockElement
+ syntax keyword typescriptDOMDocProp contained popupNode preferredStyleSheetSet selectedStyleSheetSet
+ syntax keyword typescriptDOMDocProp contained styleSheetSets textContent tooltipNode
+ syntax cluster props add=typescriptDOMDocProp
+ hi def link typescriptDOMDocProp Keyword
+ syntax keyword typescriptDOMDocMethod contained caretPositionFromPoint close createNodeIterator nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMDocMethod contained createRange createTreeWalker elementFromPoint nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMDocMethod contained getElementsByName adoptNode createAttribute nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMDocMethod contained createCDATASection createComment createDocumentFragment nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMDocMethod contained createElement createElementNS createEvent nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMDocMethod contained createExpression createNSResolver nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMDocMethod contained createProcessingInstruction createTextNode nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMDocMethod contained enableStyleSheetsForSet evaluate execCommand nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMDocMethod contained exitPointerLock getBoxObjectFor getElementById nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMDocMethod contained getElementsByClassName getElementsByTagName nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMDocMethod contained getElementsByTagNameNS getSelection nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMDocMethod contained hasFocus importNode loadOverlay open nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMDocMethod contained queryCommandSupported querySelector nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMDocMethod contained querySelectorAll write writeln nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptDOMDocMethod
+ hi def link typescriptDOMDocMethod Keyword
+
+ "runtime syntax/yats/dom-event.vim
+ syntax keyword typescriptDOMEventTargetMethod contained addEventListener removeEventListener nextgroup=typescriptEventFuncCallArg
+ syntax keyword typescriptDOMEventTargetMethod contained dispatchEvent waitUntil nextgroup=typescriptEventFuncCallArg
+ syntax cluster props add=typescriptDOMEventTargetMethod
+ hi def link typescriptDOMEventTargetMethod Keyword
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName AnimationEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName AudioProcessingEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName BeforeInputEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName BeforeUnloadEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName BlobEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName ClipboardEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName CloseEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName CompositionEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName CSSFontFaceLoadEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName CustomEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName DeviceLightEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName DeviceMotionEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName DeviceOrientationEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName DeviceProximityEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName DOMTransactionEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName DragEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName EditingBeforeInputEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName ErrorEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName FocusEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName GamepadEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName HashChangeEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName IDBVersionChangeEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName KeyboardEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName MediaStreamEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName MessageEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName MouseEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName MutationEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName OfflineAudioCompletionEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName PageTransitionEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName PointerEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName PopStateEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName ProgressEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName RelatedEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName RTCPeerConnectionIceEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName SensorEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName StorageEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName SVGEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName SVGZoomEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName TimeEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName TouchEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName TrackEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName TransitionEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName UIEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName UserProximityEvent
+ syntax keyword typescriptDOMEventCons containedin=typescriptIdentifierName WheelEvent
+ hi def link typescriptDOMEventCons Structure
+ syntax keyword typescriptDOMEventProp contained bubbles cancelable currentTarget defaultPrevented
+ syntax keyword typescriptDOMEventProp contained eventPhase target timeStamp type isTrusted
+ syntax keyword typescriptDOMEventProp contained isReload
+ syntax cluster props add=typescriptDOMEventProp
+ hi def link typescriptDOMEventProp Keyword
+ syntax keyword typescriptDOMEventMethod contained initEvent preventDefault stopImmediatePropagation nextgroup=typescriptEventFuncCallArg
+ syntax keyword typescriptDOMEventMethod contained stopPropagation respondWith default nextgroup=typescriptEventFuncCallArg
+ syntax cluster props add=typescriptDOMEventMethod
+ hi def link typescriptDOMEventMethod Keyword
+
+ "runtime syntax/yats/dom-storage.vim
+ syntax keyword typescriptDOMStorage contained sessionStorage localStorage
+ hi def link typescriptDOMStorage Keyword
+ syntax keyword typescriptDOMStorageProp contained length
+ syntax cluster props add=typescriptDOMStorageProp
+ hi def link typescriptDOMStorageProp Keyword
+ syntax keyword typescriptDOMStorageMethod contained getItem key setItem removeItem nextgroup=typescriptFuncCallArg
+ syntax keyword typescriptDOMStorageMethod contained clear nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptDOMStorageMethod
+ hi def link typescriptDOMStorageMethod Keyword
+
+ "runtime syntax/yats/dom-form.vim
+ syntax keyword typescriptDOMFormProp contained acceptCharset action elements encoding
+ syntax keyword typescriptDOMFormProp contained enctype length method name target
+ syntax cluster props add=typescriptDOMFormProp
+ hi def link typescriptDOMFormProp Keyword
+ syntax keyword typescriptDOMFormMethod contained reportValidity reset submit nextgroup=typescriptFuncCallArg
+ syntax cluster props add=typescriptDOMFormMethod
+ hi def link typescriptDOMFormMethod Keyword
+
+ "runtime syntax/yats/css.vim
+ syntax keyword typescriptDOMStyle contained alignContent alignItems alignSelf animation
+ syntax keyword typescriptDOMStyle contained animationDelay animationDirection animationDuration
+ syntax keyword typescriptDOMStyle contained animationFillMode animationIterationCount
+ syntax keyword typescriptDOMStyle contained animationName animationPlayState animationTimingFunction
+ syntax keyword typescriptDOMStyle contained appearance backfaceVisibility background
+ syntax keyword typescriptDOMStyle contained backgroundAttachment backgroundBlendMode
+ syntax keyword typescriptDOMStyle contained backgroundClip backgroundColor backgroundImage
+ syntax keyword typescriptDOMStyle contained backgroundOrigin backgroundPosition backgroundRepeat
+ syntax keyword typescriptDOMStyle contained backgroundSize border borderBottom borderBottomColor
+ syntax keyword typescriptDOMStyle contained borderBottomLeftRadius borderBottomRightRadius
+ syntax keyword typescriptDOMStyle contained borderBottomStyle borderBottomWidth borderCollapse
+ syntax keyword typescriptDOMStyle contained borderColor borderImage borderImageOutset
+ syntax keyword typescriptDOMStyle contained borderImageRepeat borderImageSlice borderImageSource
+ syntax keyword typescriptDOMStyle contained borderImageWidth borderLeft borderLeftColor
+ syntax keyword typescriptDOMStyle contained borderLeftStyle borderLeftWidth borderRadius
+ syntax keyword typescriptDOMStyle contained borderRight borderRightColor borderRightStyle
+ syntax keyword typescriptDOMStyle contained borderRightWidth borderSpacing borderStyle
+ syntax keyword typescriptDOMStyle contained borderTop borderTopColor borderTopLeftRadius
+ syntax keyword typescriptDOMStyle contained borderTopRightRadius borderTopStyle borderTopWidth
+ syntax keyword typescriptDOMStyle contained borderWidth bottom boxDecorationBreak
+ syntax keyword typescriptDOMStyle contained boxShadow boxSizing breakAfter breakBefore
+ syntax keyword typescriptDOMStyle contained breakInside captionSide caretColor caretShape
+ syntax keyword typescriptDOMStyle contained caret clear clip clipPath color columns
+ syntax keyword typescriptDOMStyle contained columnCount columnFill columnGap columnRule
+ syntax keyword typescriptDOMStyle contained columnRuleColor columnRuleStyle columnRuleWidth
+ syntax keyword typescriptDOMStyle contained columnSpan columnWidth content counterIncrement
+ syntax keyword typescriptDOMStyle contained counterReset cursor direction display
+ syntax keyword typescriptDOMStyle contained emptyCells flex flexBasis flexDirection
+ syntax keyword typescriptDOMStyle contained flexFlow flexGrow flexShrink flexWrap
+ syntax keyword typescriptDOMStyle contained float font fontFamily fontFeatureSettings
+ syntax keyword typescriptDOMStyle contained fontKerning fontLanguageOverride fontSize
+ syntax keyword typescriptDOMStyle contained fontSizeAdjust fontStretch fontStyle fontSynthesis
+ syntax keyword typescriptDOMStyle contained fontVariant fontVariantAlternates fontVariantCaps
+ syntax keyword typescriptDOMStyle contained fontVariantEastAsian fontVariantLigatures
+ syntax keyword typescriptDOMStyle contained fontVariantNumeric fontVariantPosition
+ syntax keyword typescriptDOMStyle contained fontWeight grad grid gridArea gridAutoColumns
+ syntax keyword typescriptDOMStyle contained gridAutoFlow gridAutoPosition gridAutoRows
+ syntax keyword typescriptDOMStyle contained gridColumn gridColumnStart gridColumnEnd
+ syntax keyword typescriptDOMStyle contained gridRow gridRowStart gridRowEnd gridTemplate
+ syntax keyword typescriptDOMStyle contained gridTemplateAreas gridTemplateRows gridTemplateColumns
+ syntax keyword typescriptDOMStyle contained height hyphens imageRendering imageResolution
+ syntax keyword typescriptDOMStyle contained imageOrientation imeMode inherit justifyContent
+ syntax keyword typescriptDOMStyle contained left letterSpacing lineBreak lineHeight
+ syntax keyword typescriptDOMStyle contained listStyle listStyleImage listStylePosition
+ syntax keyword typescriptDOMStyle contained listStyleType margin marginBottom marginLeft
+ syntax keyword typescriptDOMStyle contained marginRight marginTop marks mask maskType
+ syntax keyword typescriptDOMStyle contained maxHeight maxWidth minHeight minWidth
+ syntax keyword typescriptDOMStyle contained mixBlendMode objectFit objectPosition
+ syntax keyword typescriptDOMStyle contained opacity order orphans outline outlineColor
+ syntax keyword typescriptDOMStyle contained outlineOffset outlineStyle outlineWidth
+ syntax keyword typescriptDOMStyle contained overflow overflowWrap overflowX overflowY
+ syntax keyword typescriptDOMStyle contained overflowClipBox padding paddingBottom
+ syntax keyword typescriptDOMStyle contained paddingLeft paddingRight paddingTop pageBreakAfter
+ syntax keyword typescriptDOMStyle contained pageBreakBefore pageBreakInside perspective
+ syntax keyword typescriptDOMStyle contained perspectiveOrigin pointerEvents position
+ syntax keyword typescriptDOMStyle contained quotes resize right shapeImageThreshold
+ syntax keyword typescriptDOMStyle contained shapeMargin shapeOutside tableLayout tabSize
+ syntax keyword typescriptDOMStyle contained textAlign textAlignLast textCombineHorizontal
+ syntax keyword typescriptDOMStyle contained textDecoration textDecorationColor textDecorationLine
+ syntax keyword typescriptDOMStyle contained textDecorationStyle textIndent textOrientation
+ syntax keyword typescriptDOMStyle contained textOverflow textRendering textShadow
+ syntax keyword typescriptDOMStyle contained textTransform textUnderlinePosition top
+ syntax keyword typescriptDOMStyle contained touchAction transform transformOrigin
+ syntax keyword typescriptDOMStyle contained transformStyle transition transitionDelay
+ syntax keyword typescriptDOMStyle contained transitionDuration transitionProperty
+ syntax keyword typescriptDOMStyle contained transitionTimingFunction unicodeBidi unicodeRange
+ syntax keyword typescriptDOMStyle contained userSelect userZoom verticalAlign visibility
+ syntax keyword typescriptDOMStyle contained whiteSpace width willChange wordBreak
+ syntax keyword typescriptDOMStyle contained wordSpacing wordWrap writingMode zIndex
+ hi def link typescriptDOMStyle Keyword
+
+
+
+ let typescript_props = 1
+
+ "runtime syntax/yats/event.vim
+ syntax keyword typescriptAnimationEvent contained animationend animationiteration
+ syntax keyword typescriptAnimationEvent contained animationstart beginEvent endEvent
+ syntax keyword typescriptAnimationEvent contained repeatEvent
+ syntax cluster events add=typescriptAnimationEvent
+ hi def link typescriptAnimationEvent Title
+ syntax keyword typescriptCSSEvent contained CssRuleViewRefreshed CssRuleViewChanged
+ syntax keyword typescriptCSSEvent contained CssRuleViewCSSLinkClicked transitionend
+ syntax cluster events add=typescriptCSSEvent
+ hi def link typescriptCSSEvent Title
+ syntax keyword typescriptDatabaseEvent contained blocked complete error success upgradeneeded
+ syntax keyword typescriptDatabaseEvent contained versionchange
+ syntax cluster events add=typescriptDatabaseEvent
+ hi def link typescriptDatabaseEvent Title
+ syntax keyword typescriptDocumentEvent contained DOMLinkAdded DOMLinkRemoved DOMMetaAdded
+ syntax keyword typescriptDocumentEvent contained DOMMetaRemoved DOMWillOpenModalDialog
+ syntax keyword typescriptDocumentEvent contained DOMModalDialogClosed unload
+ syntax cluster events add=typescriptDocumentEvent
+ hi def link typescriptDocumentEvent Title
+ syntax keyword typescriptDOMMutationEvent contained DOMAttributeNameChanged DOMAttrModified
+ syntax keyword typescriptDOMMutationEvent contained DOMCharacterDataModified DOMContentLoaded
+ syntax keyword typescriptDOMMutationEvent contained DOMElementNameChanged DOMNodeInserted
+ syntax keyword typescriptDOMMutationEvent contained DOMNodeInsertedIntoDocument DOMNodeRemoved
+ syntax keyword typescriptDOMMutationEvent contained DOMNodeRemovedFromDocument DOMSubtreeModified
+ syntax cluster events add=typescriptDOMMutationEvent
+ hi def link typescriptDOMMutationEvent Title
+ syntax keyword typescriptDragEvent contained drag dragdrop dragend dragenter dragexit
+ syntax keyword typescriptDragEvent contained draggesture dragleave dragover dragstart
+ syntax keyword typescriptDragEvent contained drop
+ syntax cluster events add=typescriptDragEvent
+ hi def link typescriptDragEvent Title
+ syntax keyword typescriptElementEvent contained invalid overflow underflow DOMAutoComplete
+ syntax keyword typescriptElementEvent contained command commandupdate
+ syntax cluster events add=typescriptElementEvent
+ hi def link typescriptElementEvent Title
+ syntax keyword typescriptFocusEvent contained blur change DOMFocusIn DOMFocusOut focus
+ syntax keyword typescriptFocusEvent contained focusin focusout
+ syntax cluster events add=typescriptFocusEvent
+ hi def link typescriptFocusEvent Title
+ syntax keyword typescriptFormEvent contained reset submit
+ syntax cluster events add=typescriptFormEvent
+ hi def link typescriptFormEvent Title
+ syntax keyword typescriptFrameEvent contained DOMFrameContentLoaded
+ syntax cluster events add=typescriptFrameEvent
+ hi def link typescriptFrameEvent Title
+ syntax keyword typescriptInputDeviceEvent contained click contextmenu DOMMouseScroll
+ syntax keyword typescriptInputDeviceEvent contained dblclick gamepadconnected gamepaddisconnected
+ syntax keyword typescriptInputDeviceEvent contained keydown keypress keyup MozGamepadButtonDown
+ syntax keyword typescriptInputDeviceEvent contained MozGamepadButtonUp mousedown mouseenter
+ syntax keyword typescriptInputDeviceEvent contained mouseleave mousemove mouseout
+ syntax keyword typescriptInputDeviceEvent contained mouseover mouseup mousewheel MozMousePixelScroll
+ syntax keyword typescriptInputDeviceEvent contained pointerlockchange pointerlockerror
+ syntax keyword typescriptInputDeviceEvent contained wheel
+ syntax cluster events add=typescriptInputDeviceEvent
+ hi def link typescriptInputDeviceEvent Title
+ syntax keyword typescriptMediaEvent contained audioprocess canplay canplaythrough
+ syntax keyword typescriptMediaEvent contained durationchange emptied ended ended loadeddata
+ syntax keyword typescriptMediaEvent contained loadedmetadata MozAudioAvailable pause
+ syntax keyword typescriptMediaEvent contained play playing ratechange seeked seeking
+ syntax keyword typescriptMediaEvent contained stalled suspend timeupdate volumechange
+ syntax keyword typescriptMediaEvent contained waiting complete
+ syntax cluster events add=typescriptMediaEvent
+ hi def link typescriptMediaEvent Title
+ syntax keyword typescriptMenuEvent contained DOMMenuItemActive DOMMenuItemInactive
+ syntax cluster events add=typescriptMenuEvent
+ hi def link typescriptMenuEvent Title
+ syntax keyword typescriptNetworkEvent contained datachange dataerror disabled enabled
+ syntax keyword typescriptNetworkEvent contained offline online statuschange connectionInfoUpdate
+ syntax cluster events add=typescriptNetworkEvent
+ hi def link typescriptNetworkEvent Title
+ syntax keyword typescriptProgressEvent contained abort error load loadend loadstart
+ syntax keyword typescriptProgressEvent contained progress timeout uploadprogress
+ syntax cluster events add=typescriptProgressEvent
+ hi def link typescriptProgressEvent Title
+ syntax keyword typescriptResourceEvent contained cached error load
+ syntax cluster events add=typescriptResourceEvent
+ hi def link typescriptResourceEvent Title
+ syntax keyword typescriptScriptEvent contained afterscriptexecute beforescriptexecute
+ syntax cluster events add=typescriptScriptEvent
+ hi def link typescriptScriptEvent Title
+ syntax keyword typescriptSensorEvent contained compassneedscalibration devicelight
+ syntax keyword typescriptSensorEvent contained devicemotion deviceorientation deviceproximity
+ syntax keyword typescriptSensorEvent contained orientationchange userproximity
+ syntax cluster events add=typescriptSensorEvent
+ hi def link typescriptSensorEvent Title
+ syntax keyword typescriptSessionHistoryEvent contained pagehide pageshow popstate
+ syntax cluster events add=typescriptSessionHistoryEvent
+ hi def link typescriptSessionHistoryEvent Title
+ syntax keyword typescriptStorageEvent contained change storage
+ syntax cluster events add=typescriptStorageEvent
+ hi def link typescriptStorageEvent Title
+ syntax keyword typescriptSVGEvent contained SVGAbort SVGError SVGLoad SVGResize SVGScroll
+ syntax keyword typescriptSVGEvent contained SVGUnload SVGZoom
+ syntax cluster events add=typescriptSVGEvent
+ hi def link typescriptSVGEvent Title
+ syntax keyword typescriptTabEvent contained visibilitychange
+ syntax cluster events add=typescriptTabEvent
+ hi def link typescriptTabEvent Title
+ syntax keyword typescriptTextEvent contained compositionend compositionstart compositionupdate
+ syntax keyword typescriptTextEvent contained copy cut paste select text
+ syntax cluster events add=typescriptTextEvent
+ hi def link typescriptTextEvent Title
+ syntax keyword typescriptTouchEvent contained touchcancel touchend touchenter touchleave
+ syntax keyword typescriptTouchEvent contained touchmove touchstart
+ syntax cluster events add=typescriptTouchEvent
+ hi def link typescriptTouchEvent Title
+ syntax keyword typescriptUpdateEvent contained checking downloading error noupdate
+ syntax keyword typescriptUpdateEvent contained obsolete updateready
+ syntax cluster events add=typescriptUpdateEvent
+ hi def link typescriptUpdateEvent Title
+ syntax keyword typescriptValueChangeEvent contained hashchange input readystatechange
+ syntax cluster events add=typescriptValueChangeEvent
+ hi def link typescriptValueChangeEvent Title
+ syntax keyword typescriptViewEvent contained fullscreen fullscreenchange fullscreenerror
+ syntax keyword typescriptViewEvent contained resize scroll
+ syntax cluster events add=typescriptViewEvent
+ hi def link typescriptViewEvent Title
+ syntax keyword typescriptWebsocketEvent contained close error message open
+ syntax cluster events add=typescriptWebsocketEvent
+ hi def link typescriptWebsocketEvent Title
+ syntax keyword typescriptWindowEvent contained DOMWindowCreated DOMWindowClose DOMTitleChanged
+ syntax cluster events add=typescriptWindowEvent
+ hi def link typescriptWindowEvent Title
+ syntax keyword typescriptUncategorizedEvent contained beforeunload message open show
+ syntax cluster events add=typescriptUncategorizedEvent
+ hi def link typescriptUncategorizedEvent Title
+ syntax keyword typescriptServiceWorkerEvent contained install activate fetch
+ syntax cluster events add=typescriptServiceWorkerEvent
+ hi def link typescriptServiceWorkerEvent Title
+
+
+endif
+
+" patch
+"runtime syntax/basic/patch.vim
+" patch for generated code
+syntax keyword typescriptGlobal Promise
+ \ nextgroup=typescriptGlobalPromiseDot,typescriptFuncCallArg,typescriptTypeArguments oneline
+syntax keyword typescriptGlobal Map WeakMap
+ \ nextgroup=typescriptGlobalPromiseDot,typescriptFuncCallArg,typescriptTypeArguments oneline
+
+"runtime syntax/basic/members.vim
+syntax keyword typescriptConstructor contained constructor
+ \ nextgroup=@typescriptCallSignature
+ \ skipwhite skipempty
+
+
+syntax cluster memberNextGroup contains=typescriptMemberOptionality,typescriptTypeAnnotation,@typescriptCallSignature
+
+syntax match typescriptMember /\K\k*/
+ \ nextgroup=@memberNextGroup
+ \ contained skipwhite
+
+syntax match typescriptMethodAccessor contained /\v(get|set)\s\K/me=e-1
+ \ nextgroup=@typescriptMembers
+
+syntax cluster typescriptPropertyMemberDeclaration contains=
+ \ typescriptClassStatic,
+ \ typescriptAccessibilityModifier,
+ \ typescriptReadonlyModifier,
+ \ typescriptMethodAccessor,
+ \ @typescriptMembers
+ " \ typescriptMemberVariableDeclaration
+
+syntax match typescriptMemberOptionality /?\|!/ contained
+ \ nextgroup=typescriptTypeAnnotation,@typescriptCallSignature
+ \ skipwhite skipempty
+
+syntax cluster typescriptMembers contains=typescriptMember,typescriptStringMember,typescriptComputedMember
+
+syntax keyword typescriptClassStatic static
+ \ nextgroup=@typescriptMembers,typescriptAsyncFuncKeyword,typescriptReadonlyModifier
+ \ skipwhite contained
+
+syntax keyword typescriptAccessibilityModifier public private protected contained
+
+syntax keyword typescriptReadonlyModifier readonly contained
+
+syntax region typescriptStringMember contained
+ \ start=/\z(["']\)/ skip=/\\\\\|\\\z1\|\\\n/ end=/\z1/
+ \ nextgroup=@memberNextGroup
+ \ skipwhite skipempty
+
+syntax region typescriptComputedMember contained matchgroup=typescriptProperty
+ \ start=/\[/rs=s+1 end=/]/
+ \ contains=@typescriptValue,typescriptMember,typescriptMappedIn
+ \ nextgroup=@memberNextGroup
+ \ skipwhite skipempty
+
+"runtime syntax/basic/class.vim
+"don't add typescriptMembers to nextgroup, let outer scope match it
+" so we won't match abstract method outside abstract class
+syntax keyword typescriptAbstract abstract
+ \ nextgroup=typescriptClassKeyword
+ \ skipwhite skipnl
+syntax keyword typescriptClassKeyword class
+ \ nextgroup=typescriptClassName,typescriptClassExtends,typescriptClassBlock
+ \ skipwhite
+
+syntax match typescriptClassName contained /\K\k*/
+ \ nextgroup=typescriptClassBlock,typescriptClassExtends,typescriptClassTypeParameter
+ \ skipwhite skipnl
+
+syntax region typescriptClassTypeParameter
+ \ start=/</ end=/>/
+ \ contains=typescriptTypeParameter
+ \ nextgroup=typescriptClassBlock,typescriptClassExtends
+ \ contained skipwhite skipnl
+
+syntax keyword typescriptClassExtends contained extends implements nextgroup=typescriptClassHeritage skipwhite skipnl
+
+syntax match typescriptClassHeritage contained /\v(\k|\.|\(|\))+/
+ \ nextgroup=typescriptClassBlock,typescriptClassExtends,typescriptMixinComma,typescriptClassTypeArguments
+ \ contains=@typescriptValue
+ \ skipwhite skipnl
+ \ contained
+
+syntax region typescriptClassTypeArguments matchgroup=typescriptTypeBrackets
+ \ start=/</ end=/>/
+ \ contains=@typescriptType
+ \ nextgroup=typescriptClassExtends,typescriptClassBlock,typescriptMixinComma
+ \ contained skipwhite skipnl
+
+syntax match typescriptMixinComma /,/ contained nextgroup=typescriptClassHeritage skipwhite skipnl
+
+" we need add arrowFunc to class block for high order arrow func
+" see test case
+syntax region typescriptClassBlock matchgroup=typescriptBraces start=/{/ end=/}/
+ \ contains=@typescriptPropertyMemberDeclaration,typescriptAbstract,@typescriptComments,typescriptBlock,typescriptAssign,typescriptDecorator,typescriptAsyncFuncKeyword,typescriptArrowFunc
+ \ contained fold
+
+syntax keyword typescriptInterfaceKeyword interface nextgroup=typescriptInterfaceName skipwhite
+syntax match typescriptInterfaceName contained /\k\+/
+ \ nextgroup=typescriptObjectType,typescriptInterfaceExtends,typescriptInterfaceTypeParameter
+ \ skipwhite skipnl
+syntax region typescriptInterfaceTypeParameter
+ \ start=/</ end=/>/
+ \ contains=typescriptTypeParameter
+ \ nextgroup=typescriptObjectType,typescriptInterfaceExtends
+ \ contained
+ \ skipwhite skipnl
+
+syntax keyword typescriptInterfaceExtends contained extends nextgroup=typescriptInterfaceHeritage skipwhite skipnl
+
+syntax match typescriptInterfaceHeritage contained /\v(\k|\.)+/
+ \ nextgroup=typescriptObjectType,typescriptInterfaceComma,typescriptInterfaceTypeArguments
+ \ skipwhite
+
+syntax region typescriptInterfaceTypeArguments matchgroup=typescriptTypeBrackets
+ \ start=/</ end=/>/ skip=/\s*,\s*/
+ \ contains=@typescriptType
+ \ nextgroup=typescriptObjectType,typescriptInterfaceComma
+ \ contained skipwhite
+
+syntax match typescriptInterfaceComma /,/ contained nextgroup=typescriptInterfaceHeritage skipwhite skipnl
+
+"runtime syntax/basic/cluster.vim
+"Block VariableStatement EmptyStatement ExpressionStatement IfStatement IterationStatement ContinueStatement BreakStatement ReturnStatement WithStatement LabelledStatement SwitchStatement ThrowStatement TryStatement DebuggerStatement
+syntax cluster typescriptStatement
+ \ contains=typescriptBlock,typescriptVariable,
+ \ @typescriptTopExpression,typescriptAssign,
+ \ typescriptConditional,typescriptRepeat,typescriptBranch,
+ \ typescriptLabel,typescriptStatementKeyword,
+ \ typescriptFuncKeyword,
+ \ typescriptTry,typescriptExceptions,typescriptDebugger,
+ \ typescriptExport,typescriptInterfaceKeyword,typescriptEnum,
+ \ typescriptModule,typescriptAliasKeyword,typescriptImport
+
+syntax cluster typescriptPrimitive contains=typescriptString,typescriptTemplate,typescriptRegexpString,typescriptNumber,typescriptBoolean,typescriptNull,typescriptArray
+
+syntax cluster typescriptEventTypes contains=typescriptEventString,typescriptTemplate,typescriptNumber,typescriptBoolean,typescriptNull
+
+" top level expression: no arrow func
+" also no func keyword. funcKeyword is contained in statement
+" funcKeyword allows overloading (func without body)
+" funcImpl requires body
+syntax cluster typescriptTopExpression
+ \ contains=@typescriptPrimitive,
+ \ typescriptIdentifier,typescriptIdentifierName,
+ \ typescriptOperator,typescriptUnaryOp,
+ \ typescriptParenExp,typescriptRegexpString,
+ \ typescriptGlobal,typescriptAsyncFuncKeyword,
+ \ typescriptClassKeyword,typescriptTypeCast
+
+" no object literal, used in type cast and arrow func
+" TODO: change func keyword to funcImpl
+syntax cluster typescriptExpression
+ \ contains=@typescriptTopExpression,
+ \ typescriptArrowFuncDef,
+ \ typescriptFuncImpl
+
+syntax cluster typescriptValue
+ \ contains=@typescriptExpression,typescriptObjectLiteral
+
+syntax cluster typescriptEventExpression contains=typescriptArrowFuncDef,typescriptParenExp,@typescriptValue,typescriptRegexpString,@typescriptEventTypes,typescriptOperator,typescriptGlobal,jsxRegion
+
+"runtime syntax/basic/function.vim
+syntax keyword typescriptAsyncFuncKeyword async
+ \ nextgroup=typescriptFuncKeyword,typescriptArrowFuncDef
+ \ skipwhite
+
+syntax keyword typescriptAsyncFuncKeyword await
+ \ nextgroup=@typescriptValue
+ \ skipwhite
+
+syntax keyword typescriptFuncKeyword function
+ \ nextgroup=typescriptAsyncFunc,typescriptFuncName,@typescriptCallSignature
+ \ skipwhite skipempty
+
+syntax match typescriptAsyncFunc contained /*/
+ \ nextgroup=typescriptFuncName,@typescriptCallSignature
+ \ skipwhite skipempty
+
+syntax match typescriptFuncName contained /\K\k*/
+ \ nextgroup=@typescriptCallSignature
+ \ skipwhite
+
+" destructuring ({ a: ee }) =>
+syntax match typescriptArrowFuncDef contained /({\_[^}]*}\(:\_[^)]\)\?)\s*=>/
+ \ contains=typescriptArrowFuncArg,typescriptArrowFunc
+ \ nextgroup=@typescriptExpression,typescriptBlock
+ \ skipwhite skipempty
+
+" matches `(a) =>` or `([a]) =>` or
+" `(
+" a) =>`
+syntax match typescriptArrowFuncDef contained /(\(\_s*[a-zA-Z\$_\[]\_[^)]*\)*)\s*=>/
+ \ contains=typescriptArrowFuncArg,typescriptArrowFunc
+ \ nextgroup=@typescriptExpression,typescriptBlock
+ \ skipwhite skipempty
+
+syntax match typescriptArrowFuncDef contained /\K\k*\s*=>/
+ \ contains=typescriptArrowFuncArg,typescriptArrowFunc
+ \ nextgroup=@typescriptExpression,typescriptBlock
+ \ skipwhite skipempty
+
+" TODO: optimize this pattern
+syntax region typescriptArrowFuncDef contained start=/(\_[^)]*):/ end=/=>/
+ \ contains=typescriptArrowFuncArg,typescriptArrowFunc,typescriptTypeAnnotation
+ \ nextgroup=@typescriptExpression,typescriptBlock
+ \ skipwhite skipempty keepend
+
+syntax match typescriptArrowFunc /=>/
+syntax match typescriptArrowFuncArg contained /\K\k*/
+syntax region typescriptArrowFuncArg contained start=/<\|(/ end=/\ze=>/ contains=@typescriptCallSignature
+
+syntax region typescriptReturnAnnotation contained start=/:/ end=/{/me=e-1 contains=@typescriptType nextgroup=typescriptBlock
+
+
+syntax region typescriptFuncImpl contained start=/function/ end=/{/me=e-1
+ \ contains=typescriptFuncKeyword
+ \ nextgroup=typescriptBlock
+
+syntax cluster typescriptCallImpl contains=typescriptGenericImpl,typescriptParamImpl
+syntax region typescriptGenericImpl matchgroup=typescriptTypeBrackets
+ \ start=/</ end=/>/ skip=/\s*,\s*/
+ \ contains=typescriptTypeParameter
+ \ nextgroup=typescriptParamImpl
+ \ contained skipwhite
+syntax region typescriptParamImpl matchgroup=typescriptParens
+ \ start=/(/ end=/)/
+ \ contains=typescriptDecorator,@typescriptParameterList,@typescriptComments
+ \ nextgroup=typescriptReturnAnnotation,typescriptBlock
+ \ contained skipwhite skipnl
+
+"runtime syntax/basic/decorator.vim
+syntax match typescriptDecorator /@\([_$a-zA-Z][_$a-zA-Z0-9]*\.\)*[_$a-zA-Z][_$a-zA-Z0-9]*\>/
+ \ nextgroup=typescriptArgumentList
+ \ contains=@_semantic,typescriptDotNotation
+
+" Define the default highlighting.
+hi def link typescriptReserved Error
+
+hi def link typescriptEndColons Exception
+hi def link typescriptSymbols Normal
+hi def link typescriptBraces Function
+hi def link typescriptParens Normal
+hi def link typescriptComment Comment
+hi def link typescriptLineComment Comment
+hi def link typescriptDocComment Comment
+hi def link typescriptCommentTodo Todo
+hi def link typescriptRef Include
+hi def link typescriptDocNotation SpecialComment
+hi def link typescriptDocTags SpecialComment
+hi def link typescriptDocNGParam typescriptDocParam
+hi def link typescriptDocParam Function
+hi def link typescriptDocNumParam Function
+hi def link typescriptDocEventRef Function
+hi def link typescriptDocNamedParamType Type
+hi def link typescriptDocParamName Type
+hi def link typescriptDocParamType Type
+hi def link typescriptString String
+hi def link typescriptSpecial Special
+hi def link typescriptStringLiteralType String
+hi def link typescriptStringMember String
+hi def link typescriptTemplate String
+hi def link typescriptEventString String
+hi def link typescriptASCII Special
+hi def link typescriptTemplateSB Label
+hi def link typescriptRegexpString String
+hi def link typescriptGlobal Constant
+hi def link typescriptPrototype Type
+hi def link typescriptConditional Conditional
+hi def link typescriptConditionalElse Conditional
+hi def link typescriptCase Conditional
+hi def link typescriptDefault typescriptCase
+hi def link typescriptBranch Conditional
+hi def link typescriptIdentifier Structure
+hi def link typescriptVariable Identifier
+hi def link typescriptEnumKeyword Identifier
+hi def link typescriptRepeat Repeat
+hi def link typescriptForOperator Repeat
+hi def link typescriptStatementKeyword Statement
+hi def link typescriptMessage Keyword
+hi def link typescriptOperator Identifier
+hi def link typescriptKeywordOp Identifier
+hi def link typescriptCastKeyword Special
+hi def link typescriptType Type
+hi def link typescriptNull Boolean
+hi def link typescriptNumber Number
+hi def link typescriptExponent Number
+hi def link typescriptBoolean Boolean
+hi def link typescriptObjectLabel typescriptLabel
+hi def link typescriptLabel Label
+hi def link typescriptStringProperty String
+hi def link typescriptImport Special
+hi def link typescriptAmbientDeclaration Special
+hi def link typescriptExport Special
+hi def link typescriptModule Special
+hi def link typescriptTry Special
+hi def link typescriptExceptions Special
+
+hi def link typescriptMember Function
+hi def link typescriptMethodAccessor Operator
+
+hi def link typescriptAsyncFuncKeyword Keyword
+hi def link typescriptAsyncFor Keyword
+hi def link typescriptFuncKeyword Keyword
+hi def link typescriptAsyncFunc Keyword
+hi def link typescriptArrowFunc Type
+hi def link typescriptFuncName Function
+hi def link typescriptFuncArg PreProc
+hi def link typescriptArrowFuncArg PreProc
+hi def link typescriptFuncComma Operator
+
+hi def link typescriptClassKeyword Keyword
+hi def link typescriptClassExtends Keyword
+" hi def link typescriptClassName Function
+hi def link typescriptAbstract Special
+" hi def link typescriptClassHeritage Function
+" hi def link typescriptInterfaceHeritage Function
+hi def link typescriptClassStatic StorageClass
+hi def link typescriptReadonlyModifier Keyword
+hi def link typescriptInterfaceKeyword Keyword
+hi def link typescriptInterfaceExtends Keyword
+hi def link typescriptInterfaceName Function
+
+hi def link shellbang Comment
+
+hi def link typescriptTypeParameter Identifier
+hi def link typescriptConstraint Keyword
+hi def link typescriptPredefinedType Type
+hi def link typescriptReadonlyArrayKeyword Keyword
+hi def link typescriptUnion Operator
+hi def link typescriptFuncTypeArrow Function
+hi def link typescriptConstructorType Function
+hi def link typescriptTypeQuery Keyword
+hi def link typescriptAccessibilityModifier Keyword
+hi def link typescriptOptionalMark PreProc
+hi def link typescriptFuncType Special
+hi def link typescriptMappedIn Special
+hi def link typescriptCall PreProc
+hi def link typescriptParamImpl PreProc
+hi def link typescriptConstructSignature Identifier
+hi def link typescriptAliasDeclaration Identifier
+hi def link typescriptAliasKeyword Keyword
+hi def link typescriptUserDefinedType Keyword
+hi def link typescriptTypeReference Identifier
+hi def link typescriptConstructor Keyword
+hi def link typescriptDecorator Special
+
+hi link typeScript NONE
+
+let b:current_syntax = "typescript"
+if main_syntax == 'typescript'
+ unlet main_syntax
+endif
+
+let &cpo = s:cpo_save
+unlet s:cpo_save
diff --git a/runtime/syntax/upstreamrpt.vim b/runtime/syntax/upstreamrpt.vim
index 170fc8f509..21c25633a2 100644
--- a/runtime/syntax/upstreamrpt.vim
+++ b/runtime/syntax/upstreamrpt.vim
@@ -307,4 +307,4 @@ hi def link upstreamdat_Parameter Type
"hi def link upstreamdat_Filespec Underlined
hi def link upstreamdat_Comment Comment
-let b:current_syntax = "upstreamdat"
+let b:current_syntax = "upstreamrpt"
diff --git a/runtime/syntax/valgrind.vim b/runtime/syntax/valgrind.vim
index d099971826..a9b4a8c8e7 100644
--- a/runtime/syntax/valgrind.vim
+++ b/runtime/syntax/valgrind.vim
@@ -2,8 +2,7 @@
" Language: Valgrind Memory Debugger Output
" Maintainer: Roger Luethi <rl@hellgate.ch>
" Program URL: http://devel-home.kde.org/~sewardj/
-" Last Change: 2015 Jan 27
-" Included improvement by Dominique Pelle
+" Last Change: 2019 Jul 24
"
" Notes: mostly based on strace.vim and xml.vim
"
@@ -26,7 +25,7 @@ syn match valgrindSpecLine "^[+-]\{2}\d\+[+-]\{2}.*$"
syn region valgrindRegion
\ start=+^==\z(\d\+\)== \w.*$+
- \ skip=+^==\z1==\( \| .*\)$+
+ \ skip=+^==\z1==\( \| .*\| \S.*\)$+
\ end=+^+
\ fold
\ keepend
@@ -70,7 +69,7 @@ syn match valgrindLoc "\s\+\(by\|at\|Address\).*$" contained
syn match valgrindAt "at\s\@=" contained
syn match valgrindAddr "\W\zs0x\x\+" contained
-syn match valgrindFunc ": \zs\h[a-zA-Z0-9_:\[\]()<>&*+\-,=%!|^ ]*\ze([^)]*)$" contained
+syn match valgrindFunc ": \zs\h[a-zA-Z0-9_:\[\]()<>&*+\-,=%!|^ @.]*\ze([^)]*)$" contained
syn match valgrindBin "(\(with\)\=in \zs\S\+)\@=" contained
syn match valgrindSrc "(\zs[^)]*:\d\+)\@=" contained
diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim
index 444b6d8d17..b177fe641d 100644
--- a/runtime/syntax/vim.vim
+++ b/runtime/syntax/vim.vim
@@ -142,7 +142,7 @@ syn match vimNumber "-\d\+\%(\.\d\+\%([eE][+-]\=\d\+\)\=\)\=" skipwhite nextgro
syn match vimNumber "\<0[xX]\x\+" skipwhite nextgroup=vimGlobal,vimSubst,vimCommand,vimComment
syn match vimNumber "\%(^\|\A\)\zs#\x\{6}" skipwhite nextgroup=vimGlobal,vimSubst,vimCommand,vimComment
-" All vimCommands are contained by vimIsCommands. {{{2
+" All vimCommands are contained by vimIsCommand. {{{2
syn match vimCmdSep "[:|]\+" skipwhite nextgroup=vimAddress,vimAutoCmd,vimEcho,vimIsCommand,vimExtCmd,vimFilter,vimLet,vimMap,vimMark,vimSet,vimSyntax,vimUserCmd
syn match vimIsCommand "\<\h\w*\>" contains=vimCommand
syn match vimVar contained "\<\h[a-zA-Z0-9#_]*\>"
@@ -177,7 +177,7 @@ syn keyword vimFTOption contained detect indent off on plugin
" Augroup : vimAugroupError removed because long augroups caused sync'ing problems. {{{2
" ======= : Trade-off: Increasing synclines with slower editing vs augroup END error checking.
-syn cluster vimAugroupList contains=vimAugroup,vimIsCommand,vimCommand,vimUserCmd,vimExecute,vimNotFunc,vimFuncName,vimFunction,vimFunctionError,vimLineComment,vimMap,vimSpecFile,vimOper,vimNumber,vimOperParen,vimComment,vimString,vimSubst,vimMark,vimRegister,vimAddress,vimFilter,vimCmplxRepeat,vimComment,vimLet,vimSet,vimAutoCmd,vimRegion,vimSynLine,vimNotation,vimCtrlChar,vimFuncVar,vimContinue,vimSetEqual,vimOption
+syn cluster vimAugroupList contains=vimAugroup,vimIsCommand,vimUserCmd,vimExecute,vimNotFunc,vimFuncName,vimFunction,vimFunctionError,vimLineComment,vimNotFunc,vimMap,vimSpecFile,vimOper,vimNumber,vimOperParen,vimComment,vimString,vimSubst,vimMark,vimRegister,vimAddress,vimFilter,vimCmplxRepeat,vimComment,vimLet,vimSet,vimAutoCmd,vimRegion,vimSynLine,vimNotation,vimCtrlChar,vimFuncVar,vimContinue,vimSetEqual,vimOption
if exists("g:vimsyn_folding") && g:vimsyn_folding =~# 'a'
syn region vimAugroup fold matchgroup=vimAugroupKey start="\<aug\%[roup]\>\ze\s\+\K\k*" end="\<aug\%[roup]\>\ze\s\+[eE][nN][dD]\>" contains=vimAutoCmd,@vimAugroupList
else
@@ -193,8 +193,8 @@ syn keyword vimAugroupKey contained aug[roup]
" =========
syn cluster vimOperGroup contains=vimEnvvar,vimFunc,vimFuncVar,vimOper,vimOperParen,vimNumber,vimString,vimRegister,vimContinue
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
+syn match vimOper "\(\<is\|\<isnot\)[?#]\{0,2}\>" skipwhite nextgroup=vimString,vimSpecFile
+syn match vimOper "||\|&&\|[-+.!]" skipwhite nextgroup=vimString,vimSpecFile
syn region vimOperParen matchgroup=vimParenSep start="(" end=")" contains=@vimOperGroup
syn region vimOperParen matchgroup=vimSep start="{" end="}" contains=@vimOperGroup nextgroup=vimVar,vimFuncVar
if !exists("g:vimsyn_noerror") && !exists("g:vimsyn_noopererror")
@@ -231,7 +231,7 @@ syn match vimSpecFileMod "\(:[phtre]\)\+" contained
" User-Specified Commands: {{{2
" =======================
-syn cluster vimUserCmdList contains=vimAddress,vimSyntax,vimHighlight,vimAutoCmd,vimCmplxRepeat,vimComment,vimCtrlChar,vimEscapeBrace,vimFilter,vimFunc,vimFuncName,vimFunction,vimFunctionError,vimIsCommand,vimMark,vimNotation,vimNumber,vimOper,vimRegion,vimRegister,vimLet,vimSet,vimSetEqual,vimSetString,vimSpecFile,vimString,vimSubst,vimSubstRep,vimSubstRange,vimSynLine
+syn cluster vimUserCmdList contains=vimAddress,vimSyntax,vimHighlight,vimAutoCmd,vimCmplxRepeat,vimComment,vimCtrlChar,vimEscapeBrace,vimFunc,vimFuncName,vimFunction,vimFunctionError,vimIsCommand,vimMark,vimNotation,vimNumber,vimOper,vimRegion,vimRegister,vimLet,vimSet,vimSetEqual,vimSetString,vimSpecFile,vimString,vimSubst,vimSubstRep,vimSubstRange,vimSynLine
syn keyword vimUserCommand contained com[mand]
syn match vimUserCmd "\<com\%[mand]!\=\>.*$" contains=vimUserAttrb,vimUserAttrbError,vimUserCommand,@vimUserCmdList
syn match vimUserAttrbError contained "-\a\+\ze\s"
@@ -273,7 +273,7 @@ syn match vimEnvvar "\${\I\i*}"
syn region vimEscapeBrace oneline contained transparent start="[^\\]\(\\\\\)*\[\zs\^\=\]\=" skip="\\\\\|\\\]" end="]"me=e-1
syn match vimPatSepErr contained "\\)"
syn match vimPatSep contained "\\|"
-syn region vimPatSepZone oneline contained matchgroup=vimPatSepZ start="\\%\=\ze(" skip="\\\\" end="\\)\|[^\]['"]" contains=@vimStringGroup
+syn region vimPatSepZone oneline contained matchgroup=vimPatSepZ start="\\%\=\ze(" skip="\\\\" end="\\)\|[^\\]['"]" contains=@vimStringGroup
syn region vimPatRegion contained transparent matchgroup=vimPatSepR start="\\[z%]\=(" end="\\)" contains=@vimSubstList oneline
syn match vimNotPatSep contained "\\\\"
syn cluster vimStringGroup contains=vimEscapeBrace,vimPatSep,vimNotPatSep,vimPatSepErr,vimPatSepZone,@Spell
@@ -310,13 +310,14 @@ syn match vimSubstFlags contained "[&cegiIpr]\+"
syn match vimString "[^(,]'[^']\{-}\zs'"
" Marks, Registers, Addresses, Filters: {{{2
-syn match vimMark "'[a-zA-Z0-9]\ze[-+,!]" nextgroup=vimOper,vimMarkNumber,vimSubst
-syn match vimMark "'[<>]\ze[-+,!]" nextgroup=vimOper,vimMarkNumber,vimSubst
-syn match vimMark ",\zs'[<>]\ze" nextgroup=vimOper,vimMarkNumber,vimSubst
-syn match vimMark "[!,:]\zs'[a-zA-Z0-9]" nextgroup=vimOper,vimMarkNumber,vimSubst
-syn match vimMark "\<norm\%[al]\s\zs'[a-zA-Z0-9]" nextgroup=vimOper,vimMarkNumber,vimSubst
+syn match vimMark "'[a-zA-Z0-9]\ze[-+,!]" nextgroup=vimFilter,vimMarkNumber,vimSubst
+syn match vimMark "'[<>]\ze[-+,!]" nextgroup=vimFilter,vimMarkNumber,vimSubst
+syn match vimMark ",\zs'[<>]\ze" nextgroup=vimFilter,vimMarkNumber,vimSubst
+syn match vimMark "[!,:]\zs'[a-zA-Z0-9]" nextgroup=vimFilter,vimMarkNumber,vimSubst
+syn match vimMark "\<norm\%[al]\s\zs'[a-zA-Z0-9]" nextgroup=vimFilter,vimMarkNumber,vimSubst
syn match vimMarkNumber "[-+]\d\+" contained contains=vimOper nextgroup=vimSubst2
syn match vimPlainMark contained "'[a-zA-Z0-9]"
+syn match vimRange "[`'][a-zA-Z0-9],[`'][a-zA-Z0-9]" contains=vimMark skipwhite nextgroup=vimFilter
syn match vimRegister '[^,;[{: \t]\zs"[a-zA-Z0-9.%#:_\-/]\ze[^a-zA-Z_":0-9]'
syn match vimRegister '\<norm\s\+\zs"[a-zA-Z0-9]'
@@ -327,8 +328,8 @@ syn match vimPlainRegister contained '"[a-zA-Z0-9\-:.%#*+=]'
syn match vimAddress ",\zs[.$]" skipwhite nextgroup=vimSubst1
syn match vimAddress "%\ze\a" skipwhite nextgroup=vimString,vimSubst1
-syn match vimFilter contained "^!.\{-}\(|\|$\)" contains=vimSpecFile
-syn match vimFilter contained "\A!.\{-}\(|\|$\)"ms=s+1 contains=vimSpecFile,vimFunction,vimFuncName,vimOperParen
+syn match vimFilter "^!!\=[^"]\{-}\(|\|\ze\"\|$\)" contains=vimOper,vimSpecFile
+syn match vimFilter contained "!!\=[^"]\{-}\(|\|\ze\"\|$\)" contains=vimOper,vimSpecFile
" Complex repeats (:h complex-repeat) {{{2
syn match vimCmplxRepeat '[^a-zA-Z_/\\()]q[0-9a-zA-Z"]\>'lc=1
@@ -411,17 +412,18 @@ syn case match
" ==========================
syn match vimFunc "\%(\%([sSgGbBwWtTlL]:\|<[sS][iI][dD]>\)\=\%(\w\+\.\)*\I[a-zA-Z0-9_.]*\)\ze\s*(" contains=vimFuncName,vimUserFunc,vimExecute
syn match vimUserFunc contained "\%(\%([sSgGbBwWtTlL]:\|<[sS][iI][dD]>\)\=\%(\w\+\.\)*\I[a-zA-Z0-9_.]*\)\|\<\u[a-zA-Z0-9.]*\>\|\<if\>" contains=vimNotation
-syn match vimNotFunc "\<if\>\|\<el\%[seif]\>\|\<return\>\|\<while\>"
" Errors And Warnings: {{{2
" ====================
if !exists("g:vimsyn_noerror") && !exists("g:vimsyn_novimfunctionerror")
syn match vimFunctionError "\s\zs[a-z0-9]\i\{-}\ze\s*(" contained contains=vimFuncKey,vimFuncBlank
-" syn match vimFunctionError "\s\zs\%(<[sS][iI][dD]>\|[sSgGbBwWtTlL]:\)\d\i\{-}\ze\s*(" contained contains=vimFuncKey,vimFuncBlank
+ syn match vimFunctionError "\s\zs\%(<[sS][iI][dD]>\|[sSgGbBwWtTlL]:\)\d\i\{-}\ze\s*(" contained contains=vimFuncKey,vimFuncBlank
syn match vimElseIfErr "\<else\s\+if\>"
syn match vimBufnrWarn /\<bufnr\s*(\s*["']\.['"]\s*)/
endif
+syn match vimNotFunc "\<if\>\|\<el\%[seif]\>\|\<return\>\|\<while\>" skipwhite nextgroup=vimOper,vimOperParen,vimVar,vimFunc,vimNotation
+
" Norm {{{2
" ====
syn match vimNorm "\<norm\%[al]!\=" skipwhite nextgroup=vimNormCmds
@@ -631,7 +633,7 @@ if g:vimsyn_embed =~# 'l' && filereadable(s:luapath)
syn cluster vimFuncBodyList add=vimLuaRegion
exe "syn include @vimLuaScript ".s:luapath
VimFoldl syn region vimLuaRegion matchgroup=vimScriptDelim start=+lua\s*<<\s*\z(.*\)$+ end=+^\z1$+ contains=@vimLuaScript
- VimFoldl syn region vimLuaRegion matchgroup=vimScriptDelim start=+lua\s*<<\s*$+ end=+\.$+ contains=@vimLuaScript
+ VimFoldl syn region vimLuaRegion matchgroup=vimScriptDelim start=+lua\s*<<\s*$+ end=+\.$+ contains=@vimLuaScript
syn cluster vimFuncBodyList add=vimLuaRegion
else
syn region vimEmbedError start=+lua\s*<<\s*\z(.*\)$+ end=+^\z1$+
diff --git a/runtime/syntax/vuejs.vim b/runtime/syntax/vuejs.vim
new file mode 100644
index 0000000000..bad0e26c42
--- /dev/null
+++ b/runtime/syntax/vuejs.vim
@@ -0,0 +1,14 @@
+" Vim syntax file
+" Language: Vue.js Single File Component
+" Maintainer: Ralph Giles <giles@thaumas.net>
+" URL: https://vuejs.org/v2/guide/single-file-components.html
+" Last Change: 2019 Jul 8
+
+" Quit if a syntax file was already loaded.
+if exists("b:current_syntax")
+ finish
+endif
+
+" We have a collection of html, css and javascript wrapped in
+" tags. The default HTML syntax highlight works well enough.
+runtime! syntax/html.vim
diff --git a/runtime/syntax/yacc.vim b/runtime/syntax/yacc.vim
index 8d5eb13071..3f27bce443 100644
--- a/runtime/syntax/yacc.vim
+++ b/runtime/syntax/yacc.vim
@@ -1,8 +1,8 @@
" Vim syntax file
" Language: Yacc
" Maintainer: Charles E. Campbell <NdrOchipS@PcampbellAfamily.Mbiz>
-" Last Change: Aug 31, 2016
-" Version: 15
+" Last Change: Mar 25, 2019
+" Version: 16
" URL: http://www.drchip.org/astronaut/vim/index.html#SYNTAX_YACC
"
" Options: {{{1
@@ -43,12 +43,12 @@ syn cluster yaccRulesCluster contains=yaccNonterminal,yaccString
" ---------------------------------------------------------------------
" Yacc Sections: {{{1
-SynFold syn region yaccInit start='.'ms=s-1,rs=s-1 matchgroup=yaccSectionSep end='^%%$'me=e-2,re=e-2 contains=@yaccInitCluster nextgroup=yaccRules skipwhite skipempty contained
-SynFold syn region yaccInit2 start='\%^.'ms=s-1,rs=s-1 matchgroup=yaccSectionSep end='^%%$'me=e-2,re=e-2 contains=@yaccInitCluster nextgroup=yaccRules skipwhite skipempty
-SynFold syn region yaccHeader2 matchgroup=yaccSep start="^\s*\zs%{" end="^\s*%}" contains=@yaccCode nextgroup=yaccInit skipwhite skipempty contained
-SynFold syn region yaccHeader matchgroup=yaccSep start="^\s*\zs%{" end="^\s*%}" contains=@yaccCode nextgroup=yaccInit skipwhite skipempty
-SynFold syn region yaccRules matchgroup=yaccSectionSep start='^%%$' end='^%%$'me=e-2,re=e-2 contains=@yaccRulesCluster nextgroup=yaccEndCode skipwhite skipempty contained
-SynFold syn region yaccEndCode matchgroup=yaccSectionSep start='^%%$' end='\%$' contains=@yaccCode contained
+SynFold syn region yaccInit start='.'ms=s-1,rs=s-1 matchgroup=yaccSectionSep end='^%%\ze\(\s*/[*/].*\)\=$'me=e-2,re=e-2 contains=@yaccInitCluster nextgroup=yaccRules skipwhite skipempty contained
+SynFold syn region yaccInit2 start='\%^.'ms=s-1,rs=s-1 matchgroup=yaccSectionSep end='^%%\ze\(\s*/[*/].*\)\=$'me=e-2,re=e-2 contains=@yaccInitCluster nextgroup=yaccRules skipwhite skipempty
+SynFold syn region yaccHeader2 matchgroup=yaccSep start="^\s*\zs%{" end="^\s*%}" contains=@yaccCode nextgroup=yaccInit skipwhite skipempty contained
+SynFold syn region yaccHeader matchgroup=yaccSep start="^\s*\zs%{" end="^\s*%}" contains=@yaccCode nextgroup=yaccInit skipwhite skipempty
+SynFold syn region yaccRules matchgroup=yaccSectionSep start='^%%\ze\(\s*/[*/].*\)\=$' end='^%%\ze\(\s*/[*/].*\)\=$'me=e-2,re=e-2 contains=@yaccRulesCluster nextgroup=yaccEndCode skipwhite skipempty contained
+SynFold syn region yaccEndCode matchgroup=yaccSectionSep start='^%%\ze\(\s*/[*/].*\)\=$' end='\%$' contains=@yaccCode contained
" ---------------------------------------------------------------------
" Yacc Commands: {{{1
@@ -72,6 +72,7 @@ syn match yaccType "<[a-zA-Z_][a-zA-Z0-9_]*>" contains=yaccBrkt contained
SynFold syn region yaccNonterminal start="^\s*\a\w*\ze\_s*\(/\*\_.\{-}\*/\)\=\_s*:" matchgroup=yaccDelim end=";" matchgroup=yaccSectionSep end='^%%$'me=e-2,re=e-2 contains=yaccAction,yaccDelim,yaccString,yaccComment contained
syn region yaccComment start="/\*" end="\*/"
+syn region yaccComment start="//" end="$"
syn match yaccString "'[^']*'" contained
diff --git a/runtime/tools/check_colors.vim b/runtime/tools/check_colors.vim
index b1aefa1126..57b71b19db 100644
--- a/runtime/tools/check_colors.vim
+++ b/runtime/tools/check_colors.vim
@@ -1,11 +1,12 @@
-" This script tests a color scheme for some errors. Load the scheme and source
-" this script. e.g. :e colors/desert.vim | :so check_colors.vim
-" Will output possible errors.
+" This script tests a color scheme for some errors and lists potential errors.
+" Load the scheme and source this script, like this:
+" :edit colors/desert.vim | :so colors/tools/check_colors.vim
let s:save_cpo= &cpo
set cpo&vim
func! Test_check_colors()
+ let l:savedview = winsaveview()
call cursor(1,1)
let err={}
@@ -17,11 +18,69 @@ func! Test_check_colors()
endif
" 2) Check for some well-defined highlighting groups
- " Some items, check several groups, e.g. Diff, Spell
- let hi_groups = ['ColorColumn', 'Diff', 'ErrorMsg', 'Folded',
- \ 'FoldColumn', 'IncSearch', 'LineNr', 'ModeMsg', 'MoreMsg', 'NonText',
- \ 'Normal', 'Pmenu', 'Todo', 'Search', 'Spell', 'StatusLine', 'TabLine',
- \ 'Title', 'Visual', 'WarningMsg', 'WildMenu']
+ let hi_groups = [
+ \ 'ColorColumn',
+ \ 'Comment',
+ \ 'Conceal',
+ \ 'Constant',
+ \ 'Cursor',
+ \ 'CursorColumn',
+ \ 'CursorLine',
+ \ 'CursorLineNr',
+ \ 'DiffAdd',
+ \ 'DiffChange',
+ \ 'DiffDelete',
+ \ 'DiffText',
+ \ 'Directory',
+ \ 'EndOfBuffer',
+ \ 'Error',
+ \ 'ErrorMsg',
+ \ 'FoldColumn',
+ \ 'Folded',
+ \ 'Identifier',
+ \ 'Ignore',
+ \ 'IncSearch',
+ \ 'LineNr',
+ \ 'MatchParen',
+ \ 'ModeMsg',
+ \ 'MoreMsg',
+ \ 'NonText',
+ \ 'Normal',
+ \ 'Pmenu',
+ \ 'PmenuSbar',
+ \ 'PmenuSel',
+ \ 'PmenuThumb',
+ \ 'PreProc',
+ \ 'Question',
+ \ 'QuickFixLine',
+ \ 'Search',
+ \ 'SignColumn',
+ \ 'Special',
+ \ 'SpecialKey',
+ \ 'SpellBad',
+ \ 'SpellCap',
+ \ 'SpellLocal',
+ \ 'SpellRare',
+ \ 'Statement',
+ \ 'StatusLine',
+ \ 'StatusLineNC',
+ \ 'StatusLineTerm',
+ \ 'StatusLineTermNC',
+ \ 'TabLine',
+ \ 'TabLineFill',
+ \ 'TabLineSel',
+ \ 'Title',
+ \ 'Todo',
+ \ 'ToolbarButton',
+ \ 'ToolbarLine',
+ \ 'Type',
+ \ 'Underlined',
+ \ 'VertSplit',
+ \ 'Visual',
+ \ 'VisualNOS',
+ \ 'WarningMsg',
+ \ 'WildMenu',
+ \ ]
let groups={}
for group in hi_groups
if search('\c@suppress\s\+'.group, 'cnW')
@@ -30,6 +89,9 @@ func! Test_check_colors()
let groups[group] = 'Ignoring '.group
continue
endif
+ if search('hi\%[ghlight]!\= \+link \+'.group, 'cnW') " Linked group
+ continue
+ endif
if !search('hi\%[ghlight] \+'.group, 'cnW')
let groups[group] = 'No highlight definition for '.group
continue
@@ -43,12 +105,15 @@ func! Test_check_colors()
let groups[group] = 'Missing bg terminal color for '.group
continue
endif
- call search('hi\%[ghlight] \+'.group, 'cW')
- " only check in the current line
- if !search('guifg', 'cnW', line('.')) || !search('ctermfg', 'cnW', line('.'))
- " do not check for background colors, they could be intentionally left out
- let groups[group] = 'Missing fg definition for '.group
+ if !search('hi\%[ghlight] \+'.group. '.*guifg=', 'cnW')
+ let groups[group] = 'Missing guifg definition for '.group
+ continue
endif
+ if !search('hi\%[ghlight] \+'.group. '.*ctermfg=', 'cnW')
+ let groups[group] = 'Missing ctermfg definition for '.group
+ continue
+ endif
+ " do not check for background colors, they could be intentionally left out
call cursor(1,1)
endfor
let err['highlight'] = groups
@@ -91,15 +156,43 @@ func! Test_check_colors()
endif
" 7) Does not define filetype specific groups like vimCommand, htmlTag,
- let hi_groups = ['vim', 'html', 'python', 'sh', 'ruby']
+ let hi_groups = filter(getcompletion('', 'filetype'), { _,v -> v !~# '\%[no]syn\%(color\|load\|tax\)' })
+ let ft_groups = []
+ " let group = '\%('.join(hi_groups, '\|').'\)' " More efficient than a for loop, but less informative
for group in hi_groups
- let pat='\Chi\%[ghlight]\s*\zs'.group.'\w\+\>'
+ let pat='\Chi\%[ghlight]!\= *\%[link] \+\zs'.group.'\w\+\>\ze \+.' " Skips `hi clear`
+ if search(pat, 'cW')
+ call add(ft_groups, matchstr(getline('.'), pat))
+ endif
+ call cursor(1,1)
+ endfor
+ if !empty(ft_groups)
+ let err['filetype'] = get(err, 'filetype', 'Should not define: ') . join(uniq(sort(ft_groups)))
+ endif
+
+ " 8) Were debugPC and debugBreakpoint defined?
+ for group in ['debugPC', 'debugBreakpoint']
+ let pat='\Chi\%[ghlight]!\= *\%[link] \+\zs'.group.'\>'
if search(pat, 'cnW')
let line = search(pat, 'cW')
let err['filetype'] = get(err, 'filetype', 'Should not define: ') . matchstr(getline('.'), pat). ' '
endif
call cursor(1,1)
endfor
+
+ " 9) Normal should be defined first, not use reverse, fg or bg
+ call cursor(1,1)
+ let pat = 'hi\%[light] \+\%(link\|clear\)\@!\w\+\>'
+ call search(pat, 'cW') " Look for the first hi def, skipping `hi link` and `hi clear`
+ if getline('.') !~# '\m\<Normal\>'
+ let err['highlight']['Normal'] = 'Should be defined first'
+ elseif getline('.') =~# '\m\%(=\%(fg\|bg\)\)'
+ let err['highlight']['Normal'] = "Should not use 'fg' or 'bg'"
+ elseif getline('.') =~# '\m=\%(inv\|rev\)erse'
+ let err['highlight']['Normal'] = 'Should not use reverse mode'
+ endif
+
+ call winrestview(l:savedview)
let g:err = err
" print Result
@@ -107,11 +200,11 @@ func! Test_check_colors()
endfu
fu! Result(err)
- let do_roups = 0
+ let do_groups = 0
echohl Title|echomsg "---------------"|echohl Normal
for key in sort(keys(a:err))
if key is# 'highlight'
- let do_groups = 1
+ let do_groups = !empty(a:err[key])
continue
else
if a:err[key] !~ 'OK'
diff --git a/scripts/check-includes.py b/scripts/check-includes.py
index 21308a21aa..ed1fe407c5 100755
--- a/scripts/check-includes.py
+++ b/scripts/check-includes.py
@@ -9,58 +9,56 @@ from argparse import ArgumentParser
GENERATED_INCLUDE_RE = re.compile(
- r'^\s*#\s*include\s*"([/a-z_0-9.]+\.generated\.h)"(\s+//.*)?$')
+ r'^\s*#\s*include\s*"([/a-z_0-9.]+\.generated\.h)"(\s+//.*)?$')
def main(argv):
- argparser = ArgumentParser()
- argparser.add_argument('--generated-includes-dir', action='append',
- help='Directory where generated includes are located.')
- argparser.add_argument('--file', type=open, help='File to check.')
- argparser.add_argument('iwyu_args', nargs='*',
- help='IWYU arguments, must go after --.')
- args = argparser.parse_args(argv)
+ argparser = ArgumentParser()
+ argparser.add_argument('--generated-includes-dir', action='append',
+ help='Directory where generated includes are located.')
+ argparser.add_argument('--file', type=open, help='File to check.')
+ argparser.add_argument('iwyu_args', nargs='*',
+ help='IWYU arguments, must go after --.')
+ args = argparser.parse_args(argv)
- with args.file:
- include_dirs = []
+ with args.file:
+ iwyu = Popen(['include-what-you-use', '-xc'] + args.iwyu_args + ['/dev/stdin'],
+ stdin=PIPE, stdout=PIPE, stderr=PIPE)
- iwyu = Popen(['include-what-you-use', '-xc'] + args.iwyu_args + ['/dev/stdin'],
- stdin=PIPE, stdout=PIPE, stderr=PIPE)
+ for line in args.file:
+ match = GENERATED_INCLUDE_RE.match(line)
+ if match:
+ for d in args.generated_includes_dir:
+ try:
+ f = open(os.path.join(d, match.group(1)))
+ except IOError:
+ continue
+ else:
+ with f:
+ for generated_line in f:
+ iwyu.stdin.write(generated_line)
+ break
+ else:
+ raise IOError('Failed to find {0}'.format(match.group(1)))
+ else:
+ iwyu.stdin.write(line)
- for line in args.file:
- match = GENERATED_INCLUDE_RE.match(line)
- if match:
- for d in args.generated_includes_dir:
- try:
- f = open(os.path.join(d, match.group(1)))
- except IOError:
- continue
- else:
- with f:
- for generated_line in f:
- iwyu.stdin.write(generated_line)
- break
- else:
- raise IOError('Failed to find {0}'.format(match.group(1)))
- else:
- iwyu.stdin.write(line)
+ iwyu.stdin.close()
- iwyu.stdin.close()
+ out = iwyu.stdout.read()
+ err = iwyu.stderr.read()
- out = iwyu.stdout.read()
- err = iwyu.stderr.read()
+ ret = iwyu.wait()
- ret = iwyu.wait()
-
- if ret != 2:
- print('IWYU failed with exit code {0}:'.format(ret))
- print('{0} stdout {0}'.format('=' * ((80 - len(' stdout ')) // 2)))
- print(out)
- print('{0} stderr {0}'.format('=' * ((80 - len(' stderr ')) // 2)))
- print(err)
- return 1
- return 0
+ if ret != 2:
+ print('IWYU failed with exit code {0}:'.format(ret))
+ print('{0} stdout {0}'.format('=' * ((80 - len(' stdout ')) // 2)))
+ print(out)
+ print('{0} stderr {0}'.format('=' * ((80 - len(' stderr ')) // 2)))
+ print(err)
+ return 1
+ return 0
if __name__ == '__main__':
- raise SystemExit(main(sys.argv[1:]))
+ raise SystemExit(main(sys.argv[1:]))
diff --git a/scripts/gen_help_html.py b/scripts/gen_help_html.py
index dbdeb3c162..0b8e77ac22 100644
--- a/scripts/gen_help_html.py
+++ b/scripts/gen_help_html.py
@@ -81,12 +81,12 @@ SITENAVI_PLAIN = '<p>' + SITENAVI_LINKS_PLAIN + '</p>'
SITENAVI_WEB = '<p>' + SITENAVI_LINKS_WEB + '</p>'
SITENAVI_SEARCH = '<table width="100%"><tbody><tr><td>' + SITENAVI_LINKS_WEB + \
-'</td><td style="text-align: right; max-width: 25vw"><div class="gcse-searchbox">' \
-'</div></td></tr></tbody></table><div class="gcse-searchresults"></div>'
+ '</td><td style="text-align: right; max-width: 25vw"><div class="gcse-searchbox">' \
+ '</div></td></tr></tbody></table><div class="gcse-searchresults"></div>'
TEXTSTART = """
<div id="d1">
-<pre id="sp"> </pre>
+<pre id="sp">""" + (" " * 80) + """</pre>
<div id="d2">
<pre>
"""
@@ -100,74 +100,76 @@ FOOTER2 = """
</body>
</html>
""".format(
- generated_date='{0:%Y-%m-%d %H:%M:%S}'.format(datetime.datetime.now()),
- commit='?')
+ generated_date='{0:%Y-%m-%d %H:%M:%S}'.format(datetime.datetime.now()),
+ commit='?')
RE_TAGLINE = re.compile(r'(\S+)\s+(\S+)')
PAT_WORDCHAR = '[!#-)+-{}~\xC0-\xFF]'
-PAT_HEADER = r'(^.*~$)'
-PAT_GRAPHIC = r'(^.* `$)'
+PAT_HEADER = r'(^.*~$)'
+PAT_GRAPHIC = r'(^.* `$)'
PAT_PIPEWORD = r'(?<!\\)\|([#-)!+-~]+)\|'
PAT_STARWORD = r'\*([#-)!+-~]+)\*(?:(?=\s)|$)'
-PAT_COMMAND = r'`([^` ]+)`'
-PAT_OPTWORD = r"('(?:[a-z]{2,}|t_..)')"
-PAT_CTRL = r'(CTRL-(?:W_)?(?:\{char\}|<[A-Za-z]+?>|.)?)'
-PAT_SPECIAL = r'(<.+?>|\{.+?}|' \
- r'\[(?:range|line|count|offset|\+?cmd|[-+]?num|\+\+opt|' \
- r'arg|arguments|ident|addr|group)]|' \
- r'(?<=\s)\[[-a-z^A-Z0-9_]{2,}])'
-PAT_TITLE = r'(Vim version [0-9.a-z]+|VIM REFERENCE.*)'
-PAT_NOTE = r'((?<!' + PAT_WORDCHAR + r')(?:note|NOTE|Notes?):?' \
- r'(?!' + PAT_WORDCHAR + r'))'
-PAT_URL = r'((?:https?|ftp)://[^\'"<> \t]+[a-zA-Z0-9/])'
-PAT_WORD = r'((?<!' + PAT_WORDCHAR + r')' + PAT_WORDCHAR + r'+' \
- r'(?!' + PAT_WORDCHAR + r'))'
+PAT_COMMAND = r'`([^` ]+)`'
+PAT_OPTWORD = r"('(?:[a-z]{2,}|t_..)')"
+PAT_CTRL = r'(CTRL-(?:W_)?(?:\{char\}|<[A-Za-z]+?>|.)?)'
+PAT_SPECIAL = r'(<.+?>|\{.+?}|' \
+ r'\[(?:range|line|count|offset|\+?cmd|[-+]?num|\+\+opt|' \
+ r'arg|arguments|ident|addr|group)]|' \
+ r'(?<=\s)\[[-a-z^A-Z0-9_]{2,}])'
+PAT_TITLE = r'(Vim version [0-9.a-z]+|VIM REFERENCE.*)'
+PAT_NOTE = r'((?<!' + PAT_WORDCHAR + r')(?:note|NOTE|Notes?):?' \
+ r'(?!' + PAT_WORDCHAR + r'))'
+PAT_URL = r'((?:https?|ftp)://[^\'"<> \t]+[a-zA-Z0-9/])'
+PAT_WORD = r'((?<!' + PAT_WORDCHAR + r')' + PAT_WORDCHAR + r'+' \
+ r'(?!' + PAT_WORDCHAR + r'))'
RE_LINKWORD = re.compile(
- PAT_OPTWORD + '|' +
- PAT_CTRL + '|' +
- PAT_SPECIAL)
+ PAT_OPTWORD + '|' +
+ PAT_CTRL + '|' +
+ PAT_SPECIAL)
RE_TAGWORD = re.compile(
- PAT_HEADER + '|' +
- PAT_GRAPHIC + '|' +
- PAT_PIPEWORD + '|' +
- PAT_STARWORD + '|' +
- PAT_COMMAND + '|' +
- PAT_OPTWORD + '|' +
- PAT_CTRL + '|' +
- PAT_SPECIAL + '|' +
- PAT_TITLE + '|' +
- PAT_NOTE + '|' +
- PAT_URL + '|' +
- PAT_WORD)
-RE_NEWLINE = re.compile(r'[\r\n]')
+ PAT_HEADER + '|' +
+ PAT_GRAPHIC + '|' +
+ PAT_PIPEWORD + '|' +
+ PAT_STARWORD + '|' +
+ PAT_COMMAND + '|' +
+ PAT_OPTWORD + '|' +
+ PAT_CTRL + '|' +
+ PAT_SPECIAL + '|' +
+ PAT_TITLE + '|' +
+ PAT_NOTE + '|' +
+ PAT_URL + '|' +
+ PAT_WORD)
+RE_NEWLINE = re.compile(r'[\r\n]')
# H1 header "=====…"
# H2 header "-----…"
-RE_HRULE = re.compile(r'[-=]{3,}.*[-=]{3,3}$')
-RE_EG_START = re.compile(r'(?:.* )?>$')
-RE_EG_END = re.compile(r'\S')
-RE_SECTION = re.compile(r'[-A-Z .][-A-Z0-9 .()]*(?=\s+\*)')
-RE_STARTAG = re.compile(r'\s\*([^ \t|]+)\*(?:\s|$)')
+RE_HRULE = re.compile(r'[-=]{3,}.*[-=]{3,3}$')
+RE_EG_START = re.compile(r'(?:.* )?>$')
+RE_EG_END = re.compile(r'\S')
+RE_SECTION = re.compile(r'[-A-Z .][-A-Z0-9 .()]*(?=\s+\*)')
+RE_STARTAG = re.compile(r'\s\*([^ \t|]+)\*(?:\s|$)')
RE_LOCAL_ADD = re.compile(r'LOCAL ADDITIONS:\s+\*local-additions\*$')
+
class Link(object):
__slots__ = 'link_plain_same', 'link_pipe_same', \
'link_plain_foreign', 'link_pipe_foreign', \
'filename'
def __init__(self, link_plain_same, link_plain_foreign,
- link_pipe_same, link_pipe_foreign, filename):
- self.link_plain_same = link_plain_same
+ link_pipe_same, link_pipe_foreign, filename):
+ self.link_plain_same = link_plain_same
self.link_plain_foreign = link_plain_foreign
- self.link_pipe_same = link_pipe_same
- self.link_pipe_foreign = link_pipe_foreign
- self.filename = filename
+ self.link_pipe_same = link_pipe_same
+ self.link_pipe_foreign = link_pipe_foreign
+ self.filename = filename
+
class VimH2H(object):
def __init__(self, tags, version=None, is_web_version=True):
- self._urls = { }
+ self._urls = {}
self._version = version
self._is_web_version = is_web_version
for line in RE_NEWLINE.split(tags):
@@ -183,6 +185,7 @@ class VimH2H(object):
def do_add_tag(self, filename, tag):
tag_quoted = urllib.parse.quote_plus(tag)
+
def mkpart1(doc):
return '<a href="' + doc + '#' + tag_quoted + '" class="'
part1_same = mkpart1('')
@@ -192,16 +195,20 @@ class VimH2H(object):
doc = filename + '.html'
part1_foreign = mkpart1(doc)
part2 = '">' + html_escape[tag] + '</a>'
+
def mklinks(cssclass):
- return (part1_same + cssclass + part2,
+ return (part1_same + cssclass + part2,
part1_foreign + cssclass + part2)
cssclass_plain = 'd'
m = RE_LINKWORD.match(tag)
if m:
opt, ctrl, special = m.groups()
- if opt is not None: cssclass_plain = 'o'
- elif ctrl is not None: cssclass_plain = 'k'
- elif special is not None: cssclass_plain = 's'
+ if opt is not None:
+ cssclass_plain = 'o'
+ elif ctrl is not None:
+ cssclass_plain = 'k'
+ elif special is not None:
+ cssclass_plain = 's'
links_plain = mklinks(cssclass_plain)
links_pipe = mklinks('l')
self._urls[tag] = Link(
@@ -213,18 +220,23 @@ class VimH2H(object):
links = self._urls.get(tag)
if links is not None:
if links.filename == curr_filename:
- if css_class == 'l': return links.link_pipe_same
- else: return links.link_plain_same
+ if css_class == 'l':
+ return links.link_pipe_same
+ else:
+ return links.link_plain_same
else:
- if css_class == 'l': return links.link_pipe_foreign
- else: return links.link_plain_foreign
+ if css_class == 'l':
+ return links.link_pipe_foreign
+ else:
+ return links.link_plain_foreign
elif css_class is not None:
return '<span class="' + css_class + '">' + html_escape[tag] + \
- '</span>'
- else: return html_escape[tag]
+ '</span>'
+ else:
+ return html_escape[tag]
def to_html(self, filename, contents, encoding):
- out = [ ]
+ out = []
inexample = 0
filename = str(filename)
@@ -247,10 +259,11 @@ class VimH2H(object):
if inexample == 2:
if RE_EG_END.match(line):
inexample = 0
- if line[0] == '<': line = line[1:]
+ if line[0] == '<':
+ line = line[1:]
else:
out.extend(('<span class="e">', html_escape[line],
- '</span>\n'))
+ '</span>\n'))
continue
if RE_EG_START.match(line_tabs):
inexample = 1
@@ -266,12 +279,12 @@ class VimH2H(object):
out.append(html_escape[line[lastpos:pos]])
lastpos = match.end()
header, graphic, pipeword, starword, command, opt, ctrl, \
- special, title, note, url, word = match.groups()
+ special, title, note, url, word = match.groups()
if pipeword is not None:
out.append(self.maplink(pipeword, filename, 'l'))
elif starword is not None:
out.extend(('<a name="', urllib.parse.quote_plus(starword),
- '" class="t">', html_escape[starword], '</a>'))
+ '" class="t">', html_escape[starword], '</a>'))
elif command is not None:
out.extend(('<span class="e">', html_escape[command],
'</span>'))
@@ -300,14 +313,15 @@ class VimH2H(object):
if lastpos < len(line):
out.append(html_escape[line[lastpos:]])
out.append('\n')
- if inexample == 1: inexample = 2
+ if inexample == 1:
+ inexample = 2
header = []
header.append(HEAD.format(encoding=encoding, filename=filename))
header.append(HEAD_END)
if self._is_web_version and is_help_txt:
vers_note = VERSION_NOTE.replace('{version}', self._version) \
- if self._version else ''
+ if self._version else ''
header.append(INTRO.replace('{vers-note}', vers_note))
if self._is_web_version:
header.append(SITENAVI_SEARCH)
@@ -318,6 +332,7 @@ class VimH2H(object):
header.append(TEXTSTART)
return ''.join(chain(header, out, (FOOTER, sitenavi_footer, FOOTER2)))
+
class HtmlEscCache(dict):
def __missing__(self, key):
r = key.replace('&', '&amp;') \
@@ -326,9 +341,8 @@ class HtmlEscCache(dict):
self[key] = r
return r
-html_escape = HtmlEscCache()
-
+html_escape = HtmlEscCache()
def slurp(filename):
@@ -340,17 +354,20 @@ def slurp(filename):
with open(filename, encoding='latin-1') as f:
return f.read(), 'latin-1'
+
def usage():
return "usage: " + sys.argv[0] + " IN_DIR OUT_DIR [BASENAMES...]"
+
def main():
- if len(sys.argv) < 3: sys.exit(usage())
+ if len(sys.argv) < 3:
+ sys.exit(usage())
in_dir = sys.argv[1]
out_dir = sys.argv[2]
basenames = sys.argv[3:]
- print( "Processing tags...")
+ print("Processing tags...")
h2h = VimH2H(slurp(os.path.join(in_dir, 'tags'))[0], is_web_version=False)
if len(basenames) == 0:
@@ -358,9 +375,9 @@ def main():
for basename in basenames:
if os.path.splitext(basename)[1] != '.txt' and basename != 'tags':
- print( "Ignoring " + basename)
+ print("Ignoring " + basename)
continue
- print( "Processing " + basename + "...")
+ print("Processing " + basename + "...")
path = os.path.join(in_dir, basename)
text, encoding = slurp(path)
outpath = os.path.join(out_dir, basename + '.html')
@@ -368,4 +385,5 @@ def main():
of.write(h2h.to_html(basename, text, encoding))
of.close()
+
main()
diff --git a/scripts/gen_vimdoc.py b/scripts/gen_vimdoc.py
index 8db5d4de5b..edfb38e617 100755
--- a/scripts/gen_vimdoc.py
+++ b/scripts/gen_vimdoc.py
@@ -36,7 +36,6 @@ import shutil
import textwrap
import subprocess
import collections
-import pprint
from xml.dom import minidom
@@ -57,54 +56,55 @@ seen_funcs = set()
lua2dox_filter = os.path.join(base_dir, 'scripts', 'lua2dox_filter')
CONFIG = {
- 'api': {
- 'filename': 'api.txt',
- # String used to find the start of the generated part of the doc.
- 'section_start_token': '*api-global*',
- # Section ordering.
- 'section_order' : [
- 'vim.c',
- 'buffer.c',
- 'window.c',
- 'tabpage.c',
- 'ui.c',
- ],
- # List of files/directories for doxygen to read, separated by blanks
- 'files': os.path.join(base_dir, 'src/nvim/api'),
- # file patterns used by doxygen
- 'file_patterns': '*.h *.c',
- # Only function with this prefix are considered
- 'func_name_prefix': 'nvim_',
- # Section name overrides.
- 'section_name': {
- 'vim.c': 'Global',
+ 'api': {
+ 'filename': 'api.txt',
+ # String used to find the start of the generated part of the doc.
+ 'section_start_token': '*api-global*',
+ # Section ordering.
+ 'section_order': [
+ 'vim.c',
+ 'buffer.c',
+ 'window.c',
+ 'tabpage.c',
+ 'ui.c',
+ ],
+ # List of files/directories for doxygen to read, separated by blanks
+ 'files': os.path.join(base_dir, 'src/nvim/api'),
+ # file patterns used by doxygen
+ 'file_patterns': '*.h *.c',
+ # Only function with this prefix are considered
+ 'func_name_prefix': 'nvim_',
+ # Section name overrides.
+ 'section_name': {
+ 'vim.c': 'Global',
+ },
+ # Module name overrides (for Lua).
+ 'module_override': {},
+ # Append the docs for these modules, do not start a new section.
+ 'append_only': [],
},
- # Module name overrides (for Lua).
- 'module_override': {},
- # Append the docs for these modules, do not start a new section.
- 'append_only' : [],
- },
- 'lua': {
- 'filename': 'if_lua.txt',
- 'section_start_token': '*lua-vim*',
- 'section_order' : [
- 'vim.lua',
- 'shared.lua',
- ],
- 'files': ' '.join([
- os.path.join(base_dir, 'src/nvim/lua/vim.lua'),
- os.path.join(base_dir, 'runtime/lua/vim/shared.lua'),
+ 'lua': {
+ 'filename': 'if_lua.txt',
+ 'section_start_token': '*lua-vim*',
+ 'section_order': [
+ 'vim.lua',
+ 'shared.lua',
+ ],
+ 'files': ' '.join([
+ os.path.join(base_dir, 'src/nvim/lua/vim.lua'),
+ os.path.join(base_dir, 'runtime/lua/vim/shared.lua'),
]),
- 'file_patterns': '*.lua',
- 'func_name_prefix': '',
- 'section_name': {},
- 'module_override': {
- 'shared': 'vim', # `shared` functions are exposed on the `vim` module.
+ 'file_patterns': '*.lua',
+ 'func_name_prefix': '',
+ 'section_name': {},
+ 'module_override': {
+ # `shared` functions are exposed on the `vim` module.
+ 'shared': 'vim',
+ },
+ 'append_only': [
+ 'shared.lua',
+ ],
},
- 'append_only' : [
- 'shared.lua',
- ],
- },
}
param_exclude = (
@@ -121,6 +121,7 @@ annotation_map = {
# deprecated functions.
xrefs = set()
+
def debug_this(s, n):
o = n if isinstance(n, str) else n.toprettyxml(indent=' ', newl='\n')
name = '' if isinstance(n, str) else n.nodeName
@@ -191,7 +192,7 @@ def len_lastline(text):
if -1 == lastnl:
return len(text)
if '\n' == text[-1]:
- return lastnl - (1+ text.rfind('\n', 0, lastnl))
+ return lastnl - (1 + text.rfind('\n', 0, lastnl))
return len(text) - (1 + lastnl)
@@ -209,6 +210,7 @@ def is_inline(n):
return False
return True
+
def doc_wrap(text, prefix='', width=70, func=False, indent=None):
"""Wraps text to `width`.
@@ -237,8 +239,8 @@ def doc_wrap(text, prefix='', width=70, func=False, indent=None):
if indent_only:
prefix = indent
- tw = textwrap.TextWrapper(break_long_words = False,
- break_on_hyphens = False,
+ tw = textwrap.TextWrapper(break_long_words=False,
+ break_on_hyphens=False,
width=width,
initial_indent=prefix,
subsequent_indent=indent)
@@ -287,13 +289,14 @@ def render_params(parent, width=62):
desc_node = get_child(node, 'parameterdescription')
if desc_node:
desc = parse_parblock(desc_node, width=width,
- indent=(' ' * len(name)))
+ indent=(' ' * len(name)))
out += '{}{}\n'.format(name, desc)
return out.rstrip()
-# Renders a node as Vim help text, recursively traversing all descendants.
+
def render_node(n, text, prefix='', indent='', width=62):
+ """Renders a node as Vim help text, recursively traversing all descendants."""
text = ''
# space_preceding = (len(text) > 0 and ' ' == text[-1][-1])
# text += (int(not space_preceding) * ' ')
@@ -317,7 +320,11 @@ def render_node(n, text, prefix='', indent='', width=62):
text += ' [verbatim] {}'.format(get_text(n))
elif n.nodeName == 'listitem':
for c in n.childNodes:
- text += indent + prefix + render_node(c, text, indent=indent+(' ' * len(prefix)), width=width)
+ text += (
+ indent
+ + prefix
+ + render_node(c, text, indent=indent + (' ' * len(prefix)), width=width)
+ )
elif n.nodeName in ('para', 'heading'):
for c in n.childNodes:
text += render_node(c, text, indent=indent, width=width)
@@ -326,7 +333,7 @@ def render_node(n, text, prefix='', indent='', width=62):
elif n.nodeName == 'itemizedlist':
for c in n.childNodes:
text += '{}\n'.format(render_node(c, text, prefix='• ',
- indent=indent, width=width))
+ indent=indent, width=width))
elif n.nodeName == 'orderedlist':
i = 1
for c in n.childNodes:
@@ -334,7 +341,7 @@ def render_node(n, text, prefix='', indent='', width=62):
text += '\n'
continue
text += '{}\n'.format(render_node(c, text, prefix='{}. '.format(i),
- indent=indent, width=width))
+ indent=indent, width=width))
i = i + 1
elif n.nodeName == 'simplesect' and 'note' == n.getAttribute('kind'):
text += 'Note:\n '
@@ -356,6 +363,7 @@ def render_node(n, text, prefix='', indent='', width=62):
n.nodeName, n.toprettyxml(indent=' ', newl='\n')))
return text
+
def render_para(parent, indent='', width=62):
"""Renders Doxygen <para> containing arbitrary nodes.
@@ -363,7 +371,7 @@ def render_para(parent, indent='', width=62):
"""
if is_inline(parent):
return clean_lines(doc_wrap(render_node(parent, ''),
- indent=indent, width=width).strip())
+ indent=indent, width=width).strip())
# Ordered dict of ordered lists.
groups = collections.OrderedDict([
@@ -407,17 +415,19 @@ def render_para(parent, indent='', width=62):
if len(groups['return']) > 0:
chunks.append('\nReturn: ~')
for child in groups['return']:
- chunks.append(render_node(child, chunks[-1][-1], indent=indent, width=width))
+ chunks.append(render_node(
+ child, chunks[-1][-1], indent=indent, width=width))
if len(groups['seealso']) > 0:
chunks.append('\nSee also: ~')
for child in groups['seealso']:
- chunks.append(render_node(child, chunks[-1][-1], indent=indent, width=width))
+ chunks.append(render_node(
+ child, chunks[-1][-1], indent=indent, width=width))
for child in groups['xrefs']:
title = get_text(get_child(child, 'xreftitle'))
xrefs.add(title)
xrefdesc = render_para(get_child(child, 'xrefdescription'), width=width)
chunks.append(doc_wrap(xrefdesc, prefix='{}: '.format(title),
- width=width) + '\n')
+ width=width) + '\n')
return clean_lines('\n'.join(chunks).strip())
@@ -587,6 +597,7 @@ def delete_lines_below(filename, tokenstr):
with open(filename, 'wt') as fp:
fp.writelines(lines[0:i])
+
def gen_docs(config):
"""Generate documentation.
@@ -619,7 +630,8 @@ def gen_docs(config):
continue
groupname = get_text(find_first(compound, 'name'))
- groupxml = os.path.join(base, '%s.xml' % compound.getAttribute('refid'))
+ groupxml = os.path.join(base, '%s.xml' %
+ compound.getAttribute('refid'))
desc = find_first(minidom.parse(groupxml), 'detaileddescription')
if desc:
@@ -635,7 +647,7 @@ def gen_docs(config):
if filename.endswith('.c') or filename.endswith('.lua'):
functions, deprecated = parse_source_xml(
os.path.join(base, '%s.xml' %
- compound.getAttribute('refid')), mode)
+ compound.getAttribute('refid')), mode)
if not functions and not deprecated:
continue
@@ -680,12 +692,15 @@ def gen_docs(config):
i = 0
for filename in CONFIG[mode]['section_order']:
if filename not in sections:
- raise RuntimeError('found new module "{}"; update the "section_order" map'.format(filename))
+ raise RuntimeError(
+ 'found new module "{}"; update the "section_order" map'.format(
+ filename))
title, helptag, section_doc = sections.pop(filename)
i += 1
if filename not in CONFIG[mode]['append_only']:
docs += sep
- docs += '\n%s%s' % (title, helptag.rjust(text_width - len(title)))
+ docs += '\n%s%s' % (title,
+ helptag.rjust(text_width - len(title)))
docs += section_doc
docs += '\n\n\n'
@@ -693,7 +708,7 @@ def gen_docs(config):
docs += ' vim:tw=78:ts=8:ft=help:norl:\n'
doc_file = os.path.join(base_dir, 'runtime', 'doc',
- CONFIG[mode]['filename'])
+ CONFIG[mode]['filename'])
delete_lines_below(doc_file, CONFIG[mode]['section_start_token'])
with open(doc_file, 'ab') as fp:
diff --git a/scripts/pvscheck.sh b/scripts/pvscheck.sh
index fed50dde53..c09e8c4555 100755
--- a/scripts/pvscheck.sh
+++ b/scripts/pvscheck.sh
@@ -369,7 +369,6 @@ run_analysis() {(
analyze \
--threads "$(get_jobs_num)" \
--output-file PVS-studio.log \
- --verbose \
--file build/compile_commands.json \
--sourcetree-root . || true
diff --git a/scripts/shadacat.py b/scripts/shadacat.py
index 522379aad4..89846427a5 100755
--- a/scripts/shadacat.py
+++ b/scripts/shadacat.py
@@ -12,27 +12,27 @@ import msgpack
class EntryTypes(Enum):
- Unknown = -1
- Missing = 0
- Header = 1
- SearchPattern = 2
- SubString = 3
- HistoryEntry = 4
- Register = 5
- Variable = 6
- GlobalMark = 7
- Jump = 8
- BufferList = 9
- LocalMark = 10
- Change = 11
+ Unknown = -1
+ Missing = 0
+ Header = 1
+ SearchPattern = 2
+ SubString = 3
+ HistoryEntry = 4
+ Register = 5
+ Variable = 6
+ GlobalMark = 7
+ Jump = 8
+ BufferList = 9
+ LocalMark = 10
+ Change = 11
def strtrans_errors(e):
- if not isinstance(e, UnicodeDecodeError):
- raise NotImplementedError('don’t know how to handle {0} error'.format(
- e.__class__.__name__))
- return '<{0:x}>'.format(reduce((lambda a, b: a*0x100+b),
- list(e.object[e.start:e.end]))), e.end
+ if not isinstance(e, UnicodeDecodeError):
+ raise NotImplementedError('don’t know how to handle {0} error'.format(
+ e.__class__.__name__))
+ return '<{0:x}>'.format(reduce((lambda a, b: a*0x100+b),
+ list(e.object[e.start:e.end]))), e.end
codecs.register_error('strtrans', strtrans_errors)
@@ -56,54 +56,54 @@ ctable = {
def mnormalize(o):
- return ctable.get(type(o), idfunc)(o)
+ return ctable.get(type(o), idfunc)(o)
fname = sys.argv[1]
try:
- filt = sys.argv[2]
+ filt = sys.argv[2]
except IndexError:
- filt = lambda entry: True
+ def filt(entry): return True
else:
- _filt = filt
- filt = lambda entry: eval(_filt, globals(), {'entry': entry})
+ _filt = filt
+ def filt(entry): return eval(_filt, globals(), {'entry': entry})
poswidth = len(str(os.stat(fname).st_size or 1000))
class FullEntry(dict):
- def __init__(self, val):
- self.__dict__.update(val)
+ def __init__(self, val):
+ self.__dict__.update(val)
with open(fname, 'rb') as fp:
- unpacker = msgpack.Unpacker(file_like=fp, read_size=1)
- max_type = max(typ.value for typ in EntryTypes)
- while True:
- try:
- pos = fp.tell()
- typ = unpacker.unpack()
- except msgpack.OutOfData:
- break
- else:
- timestamp = unpacker.unpack()
- time = datetime.fromtimestamp(timestamp)
- length = unpacker.unpack()
- if typ > max_type:
- entry = fp.read(length)
- typ = EntryTypes.Unknown
- else:
- entry = unpacker.unpack()
- typ = EntryTypes(typ)
- full_entry = FullEntry({
- 'value': entry,
- 'timestamp': timestamp,
- 'time': time,
- 'length': length,
- 'pos': pos,
- 'type': typ,
- })
- if not filt(full_entry):
- continue
- print('%*u %13s %s %5u %r' % (
- poswidth, pos, typ.name, time.isoformat(), length, mnormalize(entry)))
+ unpacker = msgpack.Unpacker(file_like=fp, read_size=1)
+ max_type = max(typ.value for typ in EntryTypes)
+ while True:
+ try:
+ pos = fp.tell()
+ typ = unpacker.unpack()
+ except msgpack.OutOfData:
+ break
+ else:
+ timestamp = unpacker.unpack()
+ time = datetime.fromtimestamp(timestamp)
+ length = unpacker.unpack()
+ if typ > max_type:
+ entry = fp.read(length)
+ typ = EntryTypes.Unknown
+ else:
+ entry = unpacker.unpack()
+ typ = EntryTypes(typ)
+ full_entry = FullEntry({
+ 'value': entry,
+ 'timestamp': timestamp,
+ 'time': time,
+ 'length': length,
+ 'pos': pos,
+ 'type': typ,
+ })
+ if not filt(full_entry):
+ continue
+ print('%*u %13s %s %5u %r' % (
+ poswidth, pos, typ.name, time.isoformat(), length, mnormalize(entry)))
diff --git a/scripts/stripdecls.py b/scripts/stripdecls.py
index 34be2a1578..b4ac34dcfe 100755
--- a/scripts/stripdecls.py
+++ b/scripts/stripdecls.py
@@ -10,7 +10,7 @@ import os
DECL_KINDS = {
- CursorKind.FUNCTION_DECL,
+ CursorKind.FUNCTION_DECL,
}
@@ -18,124 +18,123 @@ Strip = namedtuple('Strip', 'start_line start_column end_line end_column')
def main(progname, cfname, only_static, move_all):
- only_static = False
-
- cfname = os.path.abspath(os.path.normpath(cfname))
-
- hfname1 = os.path.splitext(cfname)[0] + os.extsep + 'h'
- hfname2 = os.path.splitext(cfname)[0] + '_defs' + os.extsep + 'h'
-
- files_to_modify = (cfname, hfname1, hfname2)
-
- index = Index.create()
- src_dirname = os.path.join(os.path.dirname(__file__), '..', 'src')
- src_dirname = os.path.abspath(os.path.normpath(src_dirname))
- relname = os.path.join(src_dirname, 'nvim')
- unit = index.parse(cfname, args=('-I' + src_dirname,
- '-DUNIX',
- '-DEXITFREE',
- '-DFEAT_USR_CMDS',
- '-DFEAT_CMDL_COMPL',
- '-DFEAT_COMPL_FUNC',
- '-DPROTO',
- '-DUSE_MCH_ERRMSG'))
- cursor = unit.cursor
-
- tostrip = defaultdict(OrderedDict)
- definitions = set()
-
- for child in cursor.get_children():
- if not (child.location and child.location.file):
- continue
- fname = os.path.abspath(os.path.normpath(child.location.file.name))
- if fname not in files_to_modify:
- continue
- if child.kind not in DECL_KINDS:
- continue
- if only_static and next(child.get_tokens()).spelling == 'static':
- continue
-
- if child.is_definition() and fname == cfname:
- definitions.add(child.spelling)
- else:
- stripdict = tostrip[fname]
- assert(child.spelling not in stripdict)
- stripdict[child.spelling] = Strip(
- child.extent.start.line,
- child.extent.start.column,
- child.extent.end.line,
- child.extent.end.column,
- )
-
- for (fname, stripdict) in tostrip.items():
- if not move_all:
- for name in set(stripdict) - definitions:
- stripdict.pop(name)
-
- if not stripdict:
- continue
-
- if fname.endswith('.h'):
- is_h_file = True
- include_line = next(reversed(stripdict.values())).start_line + 1
- else:
- is_h_file = False
- include_line = next(iter(stripdict.values())).start_line
-
- lines = None
- generated_existed = os.path.exists(fname + '.generated.h')
- with open(fname, 'rb') as F:
- lines = list(F)
-
- stripped = []
-
- for name, position in reversed(stripdict.items()):
- sl = slice(position.start_line - 1, position.end_line)
- if is_h_file:
- include_line -= sl.stop - sl.start
- stripped += lines[sl]
- lines[sl] = ()
+ cfname = os.path.abspath(os.path.normpath(cfname))
+
+ hfname1 = os.path.splitext(cfname)[0] + os.extsep + 'h'
+ hfname2 = os.path.splitext(cfname)[0] + '_defs' + os.extsep + 'h'
+
+ files_to_modify = (cfname, hfname1, hfname2)
+
+ index = Index.create()
+ src_dirname = os.path.join(os.path.dirname(__file__), '..', 'src')
+ src_dirname = os.path.abspath(os.path.normpath(src_dirname))
+ relname = os.path.join(src_dirname, 'nvim')
+ unit = index.parse(cfname, args=('-I' + src_dirname,
+ '-DUNIX',
+ '-DEXITFREE',
+ '-DFEAT_USR_CMDS',
+ '-DFEAT_CMDL_COMPL',
+ '-DFEAT_COMPL_FUNC',
+ '-DPROTO',
+ '-DUSE_MCH_ERRMSG'))
+ cursor = unit.cursor
+
+ tostrip = defaultdict(OrderedDict)
+ definitions = set()
+
+ for child in cursor.get_children():
+ if not (child.location and child.location.file):
+ continue
+ fname = os.path.abspath(os.path.normpath(child.location.file.name))
+ if fname not in files_to_modify:
+ continue
+ if child.kind not in DECL_KINDS:
+ continue
+ if only_static and next(child.get_tokens()).spelling == 'static':
+ continue
+
+ if child.is_definition() and fname == cfname:
+ definitions.add(child.spelling)
+ else:
+ stripdict = tostrip[fname]
+ assert(child.spelling not in stripdict)
+ stripdict[child.spelling] = Strip(
+ child.extent.start.line,
+ child.extent.start.column,
+ child.extent.end.line,
+ child.extent.end.column,
+ )
+
+ for (fname, stripdict) in tostrip.items():
+ if not move_all:
+ for name in set(stripdict) - definitions:
+ stripdict.pop(name)
+
+ if not stripdict:
+ continue
+
+ if fname.endswith('.h'):
+ is_h_file = True
+ include_line = next(reversed(stripdict.values())).start_line + 1
+ else:
+ is_h_file = False
+ include_line = next(iter(stripdict.values())).start_line
+
+ lines = None
+ generated_existed = os.path.exists(fname + '.generated.h')
+ with open(fname, 'rb') as F:
+ lines = list(F)
+
+ stripped = []
+
+ for name, position in reversed(stripdict.items()):
+ sl = slice(position.start_line - 1, position.end_line)
+ if is_h_file:
+ include_line -= sl.stop - sl.start
+ stripped += lines[sl]
+ lines[sl] = ()
+
+ if not generated_existed:
+ lines[include_line:include_line] = [
+ '#ifdef INCLUDE_GENERATED_DECLARATIONS\n',
+ '# include "{0}.generated.h"\n'.format(
+ os.path.relpath(fname, relname)),
+ '#endif\n',
+ ]
+
+ with open(fname, 'wb') as F:
+ F.writelines(lines)
- if not generated_existed:
- lines[include_line:include_line] = [
- '#ifdef INCLUDE_GENERATED_DECLARATIONS\n',
- '# include "{0}.generated.h"\n'.format(os.path.relpath(fname, relname)),
- '#endif\n',
- ]
- with open(fname, 'wb') as F:
- F.writelines(lines)
+if __name__ == '__main__':
+ progname = sys.argv[0]
+ args = sys.argv[1:]
+ if not args or '--help' in args:
+ print('Usage:')
+ print('')
+ print(' {0} [--static [--all]] file.c...'.format(progname))
+ print('')
+ print('Stripts all declarations from file.c, file.h and file_defs.h.')
+ print('If --static argument is given then only static declarations are')
+ print('stripped. Declarations are stripped only if corresponding')
+ print('definition is found unless --all argument was given.')
+ print('')
+ print('Note: it is assumed that static declarations starts with "static"')
+ print(' keyword.')
+ sys.exit(0 if args else 1)
+
+ if args[0] == '--static':
+ only_static = True
+ args = args[1:]
+ else:
+ only_static = False
+ if args[0] == '--all':
+ move_all = True
+ args = args[1:]
+ else:
+ move_all = False
-if __name__ == '__main__':
- progname = sys.argv[0]
- args = sys.argv[1:]
- if not args or '--help' in args:
- print('Usage:')
- print('')
- print(' {0} [--static [--all]] file.c...'.format(progname))
- print('')
- print('Stripts all declarations from file.c, file.h and file_defs.h.')
- print('If --static argument is given then only static declarations are')
- print('stripped. Declarations are stripped only if corresponding')
- print('definition is found unless --all argument was given.')
- print('')
- print('Note: it is assumed that static declarations starts with "static"')
- print(' keyword.')
- sys.exit(0 if args else 1)
-
- if args[0] == '--static':
- only_static = True
- args = args[1:]
- else:
- only_static = False
-
- if args[0] == '--all':
- move_all = True
- args = args[1:]
- else:
- move_all = False
-
- for cfname in args:
- print('Processing {0}'.format(cfname))
- main(progname, cfname, only_static, move_all)
+ for cfname in args:
+ print('Processing {0}'.format(cfname))
+ main(progname, cfname, only_static, move_all)
diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh
index a9e9c5d6c3..2fb114017b 100755
--- a/scripts/vim-patch.sh
+++ b/scripts/vim-patch.sh
@@ -21,8 +21,8 @@ usage() {
echo
echo "Options:"
echo " -h Show this message and exit."
- echo " -l List missing Vim patches."
- echo " -L List missing Vim patches (for scripts)."
+ echo " -l [git-log opts] List missing Vim patches."
+ echo " -L [git-log opts] List missing Vim patches (for scripts)."
echo " -M List all merged patch-numbers (at current v:version)."
echo " -p {vim-revision} Download and generate a Vim patch. vim-revision"
echo " can be a Vim version (8.0.xxx) or a Git hash."
@@ -34,6 +34,11 @@ usage() {
echo
echo " \$VIM_SOURCE_DIR controls where Vim sources are found"
echo " (default: '${VIM_SOURCE_DIR_DEFAULT}')"
+ echo
+ echo "Examples:"
+ echo
+ echo " - List missing patches for a given file (in the Vim source):"
+ echo " $0 -l -- src/edit.c"
}
msg_ok() {
@@ -41,7 +46,7 @@ msg_ok() {
}
msg_err() {
- printf '\e[31m✘\e[0m %s\n' "$@"
+ printf '\e[31m✘\e[0m %s\n' "$@" >&2
}
# Checks if a program is in the user's PATH, and is executable.
@@ -110,30 +115,44 @@ commit_message() {
}
find_git_remote() {
- git remote -v \
- | awk '$2 ~ /github.com[:\/]neovim\/neovim/ && $3 == "(fetch)" {print $1; exit}'
+ git_remote=$(git remote -v \
+ | awk '$2 ~ /github.com[:\/]neovim\/neovim/ && $3 == "(fetch)" {print $1; exit}')
+ if [[ -z "$git_remote" ]]; then
+ git_remote="origin"
+ fi
+ echo "$git_remote"
}
+# Assign variables for a given Vim tag, patch version, or commit.
+# Might exit in case it cannot be found.
assign_commit_details() {
- if [[ ${1} =~ [0-9]\.[0-9]\.[0-9]{3,4} ]]; then
+ local vim_commit_ref
+ if [[ ${1} =~ v?[0-9]\.[0-9]\.[0-9]{3,4} ]]; then
# Interpret parameter as version number (tag).
- vim_version="${1}"
- vim_tag="v${1}"
- vim_commit=$(cd "${VIM_SOURCE_DIR}" \
- && git log -1 --format="%H" "${vim_tag}")
+ if [[ "${1:0:1}" == v ]]; then
+ vim_version="${1:1}"
+ vim_tag="${1}"
+ else
+ vim_version="${1}"
+ vim_tag="v${1}"
+ fi
+ vim_commit_ref="$vim_tag"
local munge_commit_line=true
else
# Interpret parameter as commit hash.
vim_version="${1:0:12}"
vim_tag=
- vim_commit=$(cd "${VIM_SOURCE_DIR}" \
- && git log -1 --format="%H" "${vim_version}")
+ vim_commit_ref="$vim_version"
local munge_commit_line=false
fi
+ vim_commit=$(git -C "${VIM_SOURCE_DIR}" log -1 --format="%H" "${vim_commit_ref}" --) || {
+ >&2 msg_err "Couldn't find Vim revision '${vim_commit_ref}'."
+ exit 3
+ }
+
vim_commit_url="https://github.com/vim/vim/commit/${vim_commit}"
- vim_message="$(cd "${VIM_SOURCE_DIR}" \
- && git log -1 --pretty='format:%B' "${vim_commit}" \
+ vim_message="$(git -C "${VIM_SOURCE_DIR}" log -1 --pretty='format:%B' "${vim_commit}" \
| sed -e 's/\(#[0-9]\{1,\}\)/vim\/vim\1/g')"
if [[ ${munge_commit_line} == "true" ]]; then
# Remove first line of commit message.
@@ -178,12 +197,6 @@ preprocess_patch() {
LC_ALL=C sed -e 's/\( [ab]\/src\)/\1\/nvim/g' \
"$file" > "$file".tmp && mv "$file".tmp "$file"
- # Rename path to matchit plugin.
- LC_ALL=C sed -e 's@\( [ab]/runtime\)/pack/dist/opt/matchit/\(plugin/matchit.vim\)@\1/\2@g' \
- "$file" > "$file".tmp && mv "$file".tmp "$file"
- LC_ALL=C sed -e 's@\( [ab]/runtime\)/pack/dist/opt/matchit/doc/\(matchit.txt\)@\1/doc/pi_\2@g' \
- "$file" > "$file".tmp && mv "$file".tmp "$file"
-
# Rename test_urls.vim to check_urls.vim
LC_ALL=C sed -e 's@\( [ab]\)/runtime/doc/test\(_urls.vim\)@\1/scripts/check\2@g' \
"$file" > "$file".tmp && mv "$file".tmp "$file"
@@ -198,10 +211,6 @@ get_vimpatch() {
assign_commit_details "${1}"
- git log -1 "${vim_commit}" -- >/dev/null 2>&1 || {
- >&2 msg_err "Couldn't find Vim revision '${vim_commit}'."
- exit 3
- }
msg_ok "Found Vim revision '${vim_commit}'."
local patch_content
@@ -357,7 +366,7 @@ submit_pr() {
# Gets all Vim commits since the "start" commit.
list_vim_commits() { (
- cd "${VIM_SOURCE_DIR}" && git log --reverse --format='%H' v8.0.0000..HEAD
+ cd "${VIM_SOURCE_DIR}" && git log --reverse --format='%H' v8.0.0000..HEAD "$@"
) }
# Prints all (sorted) "vim-patch:xxx" tokens found in the Nvim git log.
@@ -380,6 +389,7 @@ list_vimpatch_numbers() {
}
# Prints a newline-delimited list of Vim commits, for use by scripts.
+# "$@" is passed to list_vim_commits, as extra arguments to git-log.
list_missing_vimpatches() {
local token vim_commit vim_tag patch_number
declare -A tokens
@@ -393,13 +403,18 @@ list_missing_vimpatches() {
# Create an associative array mapping Vim commits to tags.
eval "declare -A vim_commit_tags=(
$(git -C "${VIM_SOURCE_DIR}" for-each-ref refs/tags \
- --format '[%(objectname)]=%(refname:lstrip=2)' \
+ --format '[%(objectname)]=%(refname:strip=2)' \
--sort='-*authordate' \
--shell)
)"
+ # Exit in case of errors from the above eval (empty vim_commit_tags).
+ if ! (( "${#vim_commit_tags[@]}" )); then
+ msg_err "Could not get Vim commits/tags."
+ exit 1
+ fi
# Get missing Vim commits
- for vim_commit in $(list_vim_commits); do
+ for vim_commit in $(list_vim_commits "$@"); do
# Check for vim-patch:<commit_hash> (usually runtime updates).
token="vim-patch:${vim_commit:0:7}"
if [[ "${tokens[$token]-}" ]]; then
@@ -425,8 +440,13 @@ show_vimpatches() {
get_vim_sources
printf "\nVim patches missing from Neovim:\n"
- list_missing_vimpatches | while read -r vim_commit; do
- if [ -n "$(git -C "$VIM_SOURCE_DIR" diff-tree --no-commit-id --name-only "${vim_commit}" -- runtime)" ]; then
+ local -A runtime_commits
+ for commit in $(git -C "${VIM_SOURCE_DIR}" log --format="%H %D" -- runtime | sed 's/,\? tag: / /g'); do
+ runtime_commits[$commit]=1
+ done
+
+ list_missing_vimpatches "$@" | while read -r vim_commit; do
+ if [[ "${runtime_commits[$vim_commit]-}" ]]; then
printf ' • %s (+runtime)\n' "${vim_commit}"
else
printf ' • %s\n' "${vim_commit}"
@@ -551,11 +571,13 @@ while getopts "hlLMVp:P:g:r:s" opt; do
exit 0
;;
l)
- show_vimpatches
+ shift # remove opt
+ show_vimpatches "$@"
exit 0
;;
L)
- list_missing_vimpatches
+ shift # remove opt
+ list_missing_vimpatches "$@"
exit 0
;;
M)
diff --git a/src/clint.py b/src/clint.py
index 862fdbc06b..675b67ccef 100755
--- a/src/clint.py
+++ b/src/clint.py
@@ -7,15 +7,14 @@
# modification, are permitted provided that the following conditions are
# met:
#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of Google Inc. nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
@@ -49,7 +48,6 @@ from __future__ import unicode_literals
import codecs
import copy
-import fileinput
import getopt
import math # for log
import os
@@ -567,6 +565,7 @@ class _CppLintState(object):
return
self.record_errors_file = open(fname, 'w')
+
_cpplint_state = _CppLintState()
@@ -2124,7 +2123,7 @@ def CheckExpressionAlignment(filename, clean_lines, linenum, error, startpos=0):
'Inner expression indentation should be 4')
else:
if (pos != level_starts[depth][0] + 1
- + (level_starts[depth][2] == '{')):
+ + (level_starts[depth][2] == '{')):
if depth not in ignore_error_levels:
error(filename, linenum, 'whitespace/alignment', 2,
('Inner expression should be aligned '
@@ -2297,7 +2296,7 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
line = clean_lines.elided[linenum] # get rid of comments and strings
# Don't try to do spacing checks for operator methods
- line = re.sub(r'operator(==|!=|<|<<|<=|>=|>>|>)\(', 'operator\(', line)
+ line = re.sub(r'operator(==|!=|<|<<|<=|>=|>>|>)\(', r'operator\(', line)
# We allow no-spaces around = within an if: "if ( (a=Foo()) == 0 )".
# Otherwise not. Note we only check for non-spaces on *both* sides;
@@ -2598,8 +2597,8 @@ def CheckBraces(filename, clean_lines, linenum, error):
if (not Search(r'[,;:}{(]\s*$', prevline) and
not Match(r'\s*#', prevline)):
error(filename, linenum, 'whitespace/braces', 4,
- '{ should almost always be at the end'
- ' of the previous line')
+ '{ should almost always be at the end'
+ ' of the previous line')
# Brace must appear after function signature, but on the *next* line
if Match(r'^(?:\w+(?: ?\*+)? )+\w+\(', line):
@@ -2611,9 +2610,13 @@ def CheckBraces(filename, clean_lines, linenum, error):
'Brace starting function body must be placed on its own line')
else:
func_start_linenum = end_linenum + 1
- while not clean_lines.lines[func_start_linenum] == '{':
- attrline = Match(r'^((?!# *define).*?)(?:FUNC_ATTR|FUNC_API|REAL_FATTR)_\w+(?:\(\d+(, \d+)*\))?',
- clean_lines.lines[func_start_linenum])
+ while not clean_lines.lines[func_start_linenum] == "{":
+ attrline = Match(
+ r'^((?!# *define).*?)'
+ r'(?:FUNC_ATTR|FUNC_API|REAL_FATTR)_\w+'
+ r'(?:\(\d+(, \d+)*\))?',
+ clean_lines.lines[func_start_linenum],
+ )
if attrline:
if len(attrline.group(1)) != 2:
error(filename, func_start_linenum,
@@ -3179,11 +3182,12 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension,
if not Search(r'eval/typval\.[ch]$', filename):
match = Search(r'(?:\.|->)'
r'(?:lv_(?:first|last|refcount|len|watch|idx(?:_item)?'
- r'|copylist|lock)'
- r'|li_(?:next|prev|tv))\b', line)
+ r'|copylist|lock)'
+ r'|li_(?:next|prev|tv))\b', line)
if match:
error(filename, linenum, 'runtime/deprecated', 4,
- 'Accessing list_T internals directly is prohibited (hint: see commit d46e37cb4c71)')
+ 'Accessing list_T internals directly is prohibited '
+ '(hint: see commit d46e37cb4c71)')
# Check for suspicious usage of "if" like
# } if (a == b) {
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index 8abc43c2aa..0fc7c780ca 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -7,6 +7,7 @@ if(USE_GCOV)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} --coverage")
+ add_definitions(-DUSE_GCOV)
endif()
endif()
@@ -138,7 +139,6 @@ set(CONV_SOURCES
eval.c
ex_cmds.c
ex_docmd.c
- ex_getln.c
fileio.c
mbyte.c
memline.c
@@ -163,8 +163,8 @@ if(NOT MSVC)
set_source_files_properties(
${CONV_SOURCES} PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-conversion")
# gperf generates ANSI-C with incorrect linkage, ignore it.
- check_c_compiler_flag(-Wno-static-in-inline HAS_WNO_STATIC_IN_INLINE_FLAG)
- if(HAS_WNO_STATIC_IN_INLINE_FLAG)
+ check_c_compiler_flag(-Wstatic-in-inline HAS_WSTATIC_IN_INLINE)
+ if(HAS_WSTATIC_IN_INLINE)
set_source_files_properties(
eval.c PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-static-in-inline -Wno-conversion")
else()
@@ -383,6 +383,7 @@ endif()
# Put these last on the link line, since multiple things may depend on them.
list(APPEND NVIM_LINK_LIBRARIES
+ ${LIBLUV_LIBRARIES}
${LIBUV_LIBRARIES}
${MSGPACK_LIBRARIES}
${LIBVTERM_LIBRARIES}
diff --git a/src/nvim/README.md b/src/nvim/README.md
index 02464c2500..3c956cb2e9 100644
--- a/src/nvim/README.md
+++ b/src/nvim/README.md
@@ -60,9 +60,9 @@ Enable the sanitizer(s) via these environment variables:
# Change to detect_leaks=1 to detect memory leaks (slower).
export ASAN_OPTIONS="detect_leaks=0:log_path=$HOME/logs/asan"
- export ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-5.0/bin/llvm-symbolizer
+ export ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer
- export MSAN_SYMBOLIZER_PATH=/usr/lib/llvm-5.0/bin/llvm-symbolizer
+ export MSAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer
export TSAN_OPTIONS="external_symbolizer_path=/usr/lib/llvm-5.0/bin/llvm-symbolizer log_path=${HOME}/logs/tsan"
Logs will be written to `${HOME}/logs/*san.PID`.
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index 81b3851c53..41d7d8ba6b 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -12,8 +12,10 @@
#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/buffer.h"
+#include "nvim/change.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
#include "nvim/getchar.h"
@@ -108,9 +110,11 @@ String buffer_get_line(Buffer buffer, Integer index, Error *err)
/// `nvim_buf_lines_event`. Otherwise, the first notification will be
/// a `nvim_buf_changedtick_event`. Not used for lua callbacks.
/// @param opts Optional parameters.
-/// `on_lines`: lua callback received on change.
+/// `on_lines`: lua callback received on change.
/// `on_changedtick`: lua callback received on changedtick
/// increment without text change.
+/// `utf_sizes`: include UTF-32 and UTF-16 size of
+/// the replaced region.
/// See |api-buffer-updates-lua| for more information
/// @param[out] err Error details, if any
/// @return False when updates couldn't be enabled because the buffer isn't
@@ -137,24 +141,44 @@ Boolean nvim_buf_attach(uint64_t channel_id,
if (is_lua && strequal("on_lines", k.data)) {
if (v->type != kObjectTypeLuaRef) {
api_set_error(err, kErrorTypeValidation, "callback is not a function");
- return false;
+ goto error;
}
cb.on_lines = v->data.luaref;
v->data.integer = LUA_NOREF;
} else if (is_lua && strequal("on_changedtick", k.data)) {
if (v->type != kObjectTypeLuaRef) {
api_set_error(err, kErrorTypeValidation, "callback is not a function");
- return false;
+ goto error;
}
cb.on_changedtick = v->data.luaref;
v->data.integer = LUA_NOREF;
+ } else if (is_lua && strequal("on_detach", k.data)) {
+ if (v->type != kObjectTypeLuaRef) {
+ api_set_error(err, kErrorTypeValidation, "callback is not a function");
+ goto error;
+ }
+ cb.on_detach = v->data.luaref;
+ v->data.integer = LUA_NOREF;
+ } else if (is_lua && strequal("utf_sizes", k.data)) {
+ if (v->type != kObjectTypeBoolean) {
+ api_set_error(err, kErrorTypeValidation, "utf_sizes must be boolean");
+ goto error;
+ }
+ cb.utf_sizes = v->data.boolean;
} else {
api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data);
- return false;
+ goto error;
}
}
return buf_updates_register(buf, channel_id, cb, send_buffer);
+
+error:
+ // TODO(bfredl): ASAN build should check that the ref table is empty?
+ executor_free_luaref(cb.on_lines);
+ executor_free_luaref(cb.on_changedtick);
+ executor_free_luaref(cb.on_detach);
+ return false;
}
/// Deactivates buffer-update events on the channel.
@@ -1161,6 +1185,30 @@ free_exit:
return 0;
}
+Dictionary nvim__buf_stats(Buffer buffer, Error *err)
+{
+ Dictionary rv = ARRAY_DICT_INIT;
+
+ buf_T *buf = find_buffer_by_handle(buffer, err);
+ if (!buf) {
+ return rv;
+ }
+
+ // Number of times the cached line was flushed.
+ // This should generally not increase while editing the same
+ // line in the same mode.
+ PUT(rv, "flush_count", INTEGER_OBJ(buf->flush_count));
+ // lnum of current line
+ PUT(rv, "current_lnum", INTEGER_OBJ(buf->b_ml.ml_line_lnum));
+ // whether the line has unflushed changes.
+ PUT(rv, "line_dirty", BOOLEAN_OBJ(buf->b_ml.ml_flags & ML_LINE_DIRTY));
+ // NB: this should be zero at any time API functions are called,
+ // this exists to debug issues
+ PUT(rv, "dirty_bytes", INTEGER_OBJ((Integer)buf->deleted_bytes));
+
+ return rv;
+}
+
// Check if deleting lines made the cursor position invalid.
// Changed lines from `lo` to `hi`; added `extra` lines (negative if deleted).
static void fix_cursor(linenr_T lo, linenr_T hi, linenr_T extra)
diff --git a/src/nvim/api/private/dispatch.h b/src/nvim/api/private/dispatch.h
index 39aabd708a..bad5a13934 100644
--- a/src/nvim/api/private/dispatch.h
+++ b/src/nvim/api/private/dispatch.h
@@ -11,8 +11,10 @@ typedef Object (*ApiDispatchWrapper)(uint64_t channel_id,
/// functions of this type.
typedef struct {
ApiDispatchWrapper fn;
- bool async; // function is always safe to run immediately instead of being
- // put in a request queue for handling when nvim waits for input.
+ bool fast; // Function is safe to be executed immediately while running the
+ // uv loop (the loop is run very frequently due to breakcheck).
+ // If "fast" is false, the function is deferred, i e the call will
+ // be put in the event queue, for safe handling later.
} MsgpackRpcRequestHandler;
#ifdef INCLUDE_GENERATED_DECLARATIONS
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index 4f28ea5af3..20ed77afad 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -123,6 +123,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height,
ui->mode_change = remote_ui_mode_change;
ui->grid_scroll = remote_ui_grid_scroll;
ui->hl_attr_define = remote_ui_hl_attr_define;
+ ui->hl_group_set = remote_ui_hl_group_set;
ui->raw_line = remote_ui_raw_line;
ui->bell = remote_ui_bell;
ui->visual_bell = remote_ui_visual_bell;
diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h
index a1d25766fe..41bf0af65b 100644
--- a/src/nvim/api/ui_events.in.h
+++ b/src/nvim/api/ui_events.in.h
@@ -73,6 +73,8 @@ void default_colors_set(Integer rgb_fg, Integer rgb_bg, Integer rgb_sp,
void hl_attr_define(Integer id, HlAttrs rgb_attrs, HlAttrs cterm_attrs,
Array info)
FUNC_API_SINCE(5) FUNC_API_REMOTE_IMPL FUNC_API_BRIDGE_IMPL;
+void hl_group_set(String name, Integer id)
+ FUNC_API_SINCE(6) FUNC_API_BRIDGE_IMPL;
void grid_resize(Integer grid, Integer width, Integer height)
FUNC_API_SINCE(5) FUNC_API_REMOTE_IMPL FUNC_API_COMPOSITOR_IMPL;
void grid_clear(Integer grid)
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 2e8ca384b4..ed6a28bcda 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -21,6 +21,7 @@
#include "nvim/lua/executor.h"
#include "nvim/vim.h"
#include "nvim/buffer.h"
+#include "nvim/context.h"
#include "nvim/file_search.h"
#include "nvim/highlight.h"
#include "nvim/window.h"
@@ -30,6 +31,7 @@
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/message.h"
+#include "nvim/popupmnu.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
@@ -208,7 +210,7 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_csi)
/// @return Number of bytes actually written (can be fewer than
/// requested if the buffer becomes full).
Integer nvim_input(String keys)
- FUNC_API_SINCE(1) FUNC_API_ASYNC
+ FUNC_API_SINCE(1) FUNC_API_FAST
{
return (Integer)input_enqueue(keys);
}
@@ -237,7 +239,7 @@ Integer nvim_input(String keys)
/// @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)
- FUNC_API_SINCE(6) FUNC_API_ASYNC
+ FUNC_API_SINCE(6) FUNC_API_FAST
{
if (button.data == NULL || action.data == NULL) {
goto error;
@@ -1063,6 +1065,19 @@ fail:
/// - `external`: GUI should display the window as an external
/// top-level window. Currently accepts no other positioning
/// configuration together with this.
+/// - `style`: Configure the apparance of the window. Currently only takes
+/// one non-empty value:
+/// - "minimal" Nvim will display the window with many UI options
+/// disabled. This is useful when displaing a temporary
+/// float where the text should not be edited. Disables
+/// 'number', 'relativenumber', 'cursorline', 'cursorcolumn',
+/// 'spell' and 'list' options. 'signcolumn' is changed to
+/// `auto`. The end-of-buffer region is hidden by setting
+/// `eob` flag of 'fillchars' to a space char, and clearing
+/// the |EndOfBuffer| region in 'winhighlight'.
+///
+/// top-level window. Currently accepts no other positioning
+/// configuration together with this.
/// @param[out] err Error details, if any
///
/// @return Window handle, or 0 on error
@@ -1084,6 +1099,11 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dictionary config,
if (buffer > 0) {
nvim_win_set_buf(wp->handle, buffer, err);
}
+
+ if (fconfig.style == kWinStyleMinimal) {
+ win_set_minimal_style(wp);
+ didset_window_options(wp);
+ }
return wp->handle;
}
@@ -1249,13 +1269,74 @@ Dictionary nvim_get_color_map(void)
return colors;
}
+/// Gets a map of the current editor state.
+///
+/// @param types Context types ("regs", "jumps", "buflist", "gvars", ...)
+/// to gather, or NIL for all.
+///
+/// @return map of global context
+Dictionary nvim_get_context(Array types)
+ FUNC_API_SINCE(6)
+{
+ int int_types = 0;
+ if (types.size == 1 && types.items[0].type == kObjectTypeNil) {
+ int_types = kCtxAll;
+ } else {
+ for (size_t i = 0; i < types.size; i++) {
+ if (types.items[i].type == kObjectTypeString) {
+ const char *const current = types.items[i].data.string.data;
+ if (strequal(current, "regs")) {
+ int_types |= kCtxRegs;
+ } else if (strequal(current, "jumps")) {
+ int_types |= kCtxJumps;
+ } else if (strequal(current, "buflist")) {
+ int_types |= kCtxBuflist;
+ } else if (strequal(current, "gvars")) {
+ int_types |= kCtxGVars;
+ } else if (strequal(current, "sfuncs")) {
+ int_types |= kCtxSFuncs;
+ } else if (strequal(current, "funcs")) {
+ int_types |= kCtxFuncs;
+ }
+ }
+ }
+ }
+
+ Context ctx = CONTEXT_INIT;
+ ctx_save(&ctx, int_types);
+ Dictionary dict = ctx_to_dict(&ctx);
+ ctx_free(&ctx);
+ return dict;
+}
+
+/// Sets the current editor state to that in given context dictionary.
+///
+/// @param ctx_dict Context dictionary.
+Object nvim_load_context(Dictionary dict)
+ FUNC_API_SINCE(6)
+{
+ Context ctx = CONTEXT_INIT;
+
+ int save_did_emsg = did_emsg;
+ did_emsg = false;
+
+ ctx_from_dict(dict, &ctx);
+ if (!did_emsg) {
+ ctx_restore(&ctx, kCtxAll);
+ }
+
+ ctx_free(&ctx);
+
+ did_emsg = save_did_emsg;
+ return (Object)OBJECT_INIT;
+}
/// Gets the current mode. |mode()|
/// "blocking" is true if Nvim is waiting for input.
///
/// @returns Dictionary { "mode": String, "blocking": Boolean }
Dictionary nvim_get_mode(void)
- FUNC_API_SINCE(2) FUNC_API_ASYNC
+ FUNC_API_SINCE(2) FUNC_API_FAST
{
Dictionary rv = ARRAY_DICT_INIT;
char *modestr = get_mode();
@@ -1341,7 +1422,7 @@ Dictionary nvim_get_commands(Dictionary opts, Error *err)
///
/// @returns 2-tuple [{channel-id}, {api-metadata}]
Array nvim_get_api_info(uint64_t channel_id)
- FUNC_API_SINCE(1) FUNC_API_ASYNC FUNC_API_REMOTE_ONLY
+ FUNC_API_SINCE(1) FUNC_API_FAST FUNC_API_REMOTE_ONLY
{
Array rv = ARRAY_DICT_INIT;
@@ -1651,7 +1732,7 @@ typedef kvec_withinit_t(ExprASTConvStackItem, 16) ExprASTConvStack;
/// @param[out] err Error details, if any
Dictionary nvim_parse_expression(String expr, String flags, Boolean highlight,
Error *err)
- FUNC_API_SINCE(4) FUNC_API_ASYNC
+ FUNC_API_SINCE(4) FUNC_API_FAST
{
int pflags = 0;
for (size_t i = 0 ; i < flags.size ; i++) {
@@ -2239,16 +2320,33 @@ void nvim_select_popupmenu_item(Integer item, Boolean insert, Boolean finish,
}
/// NB: if your UI doesn't use hlstate, this will not return hlstate first time
-Array nvim__inspect_cell(Integer row, Integer col, Error *err)
+Array nvim__inspect_cell(Integer grid, Integer row, Integer col, Error *err)
{
Array ret = ARRAY_DICT_INIT;
- if (row < 0 || row >= default_grid.Rows
- || col < 0 || col >= default_grid.Columns) {
+
+ // TODO(bfredl): if grid == 0 we should read from the compositor's buffer.
+ // The only problem is that it does not yet exist.
+ ScreenGrid *g = &default_grid;
+ if (grid == pum_grid.handle) {
+ g = &pum_grid;
+ } else if (grid > 1) {
+ win_T *wp = get_win_by_grid_handle((handle_T)grid);
+ if (wp != NULL && wp->w_grid.chars != NULL) {
+ g = &wp->w_grid;
+ } else {
+ api_set_error(err, kErrorTypeValidation,
+ "No grid with the given handle");
+ return ret;
+ }
+ }
+
+ if (row < 0 || row >= g->Rows
+ || col < 0 || col >= g->Columns) {
return ret;
}
- size_t off = default_grid.line_offset[(size_t)row] + (size_t)col;
- ADD(ret, STRING_OBJ(cstr_to_string((char *)default_grid.chars[off])));
- int attr = default_grid.attrs[off];
+ size_t off = g->line_offset[(size_t)row] + (size_t)col;
+ ADD(ret, STRING_OBJ(cstr_to_string((char *)g->chars[off])));
+ int attr = g->attrs[off];
ADD(ret, DICTIONARY_OBJ(hl_get_attr_by_id(attr, true, err)));
// will not work first time
if (!highlight_use_hlstate()) {
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index 9fd1818a5c..e279edebde 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -6,6 +6,8 @@
#include <stdlib.h>
#include <limits.h>
+#include "nvim/ascii.h"
+#include "nvim/globals.h"
#include "nvim/api/window.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
@@ -13,11 +15,11 @@
#include "nvim/vim.h"
#include "nvim/buffer.h"
#include "nvim/cursor.h"
+#include "nvim/option.h"
#include "nvim/window.h"
#include "nvim/screen.h"
#include "nvim/move.h"
-
/// Gets the current buffer in a window
///
/// @param window Window handle
@@ -475,6 +477,10 @@ void nvim_win_set_config(Window window, Dictionary config, Error *err)
win_config_float(win, fconfig);
win->w_pos_changed = true;
}
+ if (fconfig.style == kWinStyleMinimal) {
+ win_set_minimal_style(win);
+ didset_window_options(win);
+ }
}
/// Return window configuration.
@@ -521,9 +527,7 @@ Dictionary nvim_win_get_config(Window window, Error *err)
return rv;
}
-/// Close a window.
-///
-/// This is equivalent to |:close| with count except that it takes a window id.
+/// Closes the window (like |:close| with a |window-ID|).
///
/// @param window Window handle
/// @param force Behave like `:close!` The last window of a buffer with
@@ -537,8 +541,17 @@ void nvim_win_close(Window window, Boolean force, Error *err)
if (!win) {
return;
}
- tabpage_T *tabpage = win_find_tabpage(win);
+ if (cmdwin_type != 0) {
+ if (win == curwin) {
+ cmdwin_result = Ctrl_C;
+ } else {
+ api_set_error(err, kErrorTypeException, "%s", _(e_cmdwin));
+ }
+ return;
+ }
+
+ tabpage_T *tabpage = win_find_tabpage(win);
TryState tstate;
try_enter(&tstate);
ex_win_close(force, win, tabpage == curtab ? NULL : tabpage);
diff --git a/src/nvim/assert.h b/src/nvim/assert.h
index 34734f294d..1361879876 100644
--- a/src/nvim/assert.h
+++ b/src/nvim/assert.h
@@ -133,8 +133,10 @@
/// Alternative for compilers without __builtin_xx_overflow ?
/// https://stackoverflow.com/a/44830670/152142
///
-/// @param MAX Maximum value of the narrowest type of operand.
-/// Not used if compiler supports __builtin_add_overflow.
+/// @param a Operand 1.
+/// @param b Operand 2.
+/// @param c Where to store the result.
+/// @param t Result type. Not used if compiler supports __builtin_add_overflow.
#ifdef HAVE_BUILTIN_ADD_OVERFLOW
# define STRICT_ADD(a, b, c, t) \
do { \
@@ -150,6 +152,7 @@
/// @def STRICT_SUB
/// @brief Subtracts (a - b) and stores result in `c`. Aborts on overflow.
+/// @see STRICT_ADD
#ifdef HAVE_BUILTIN_ADD_OVERFLOW
# define STRICT_SUB(a, b, c, t) \
do { \
diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua
index ef528f72b8..12fc8fd02a 100644
--- a/src/nvim/auevents.lua
+++ b/src/nvim/auevents.lua
@@ -77,6 +77,7 @@ return {
'Signal', -- after nvim process received a signal
'SourceCmd', -- sourcing a Vim script using command
'SourcePre', -- before sourcing a Vim script
+ 'SourcePost', -- after sourcing a Vim script
'SpellFileMissing', -- spell file missing
'StdinReadPost', -- after reading from stdin
'StdinReadPre', -- before reading from stdin
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 52dc359716..a545112360 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -29,8 +29,10 @@
#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/change.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
#include "nvim/diff.h"
@@ -1425,7 +1427,7 @@ do_buffer(
}
}
if (bufIsChanged(curbuf)) {
- EMSG(_(e_nowrtmsg));
+ no_write_message();
return FAIL;
}
}
@@ -1626,6 +1628,16 @@ void do_autochdir(void)
}
}
+void no_write_message(void)
+{
+ EMSG(_("E37: No write since last change (add ! to override)"));
+}
+
+void no_write_message_nobang(void)
+{
+ EMSG(_("E37: No write since last change"));
+}
+
//
// functions for dealing with the buffer list
//
@@ -2532,6 +2544,11 @@ void get_winopts(buf_T *buf)
} else
copy_winopt(&curwin->w_allbuf_opt, &curwin->w_onebuf_opt);
+ if (curwin->w_float_config.style == kWinStyleMinimal) {
+ didset_window_options(curwin);
+ win_set_minimal_style(curwin);
+ }
+
// Set 'foldlevel' to 'foldlevelstart' if it's not negative.
if (p_fdls >= 0) {
curwin->w_p_fdl = p_fdls;
@@ -2595,14 +2612,23 @@ void buflist_list(exarg_T *eap)
continue;
}
+ const int changed_char = (buf->b_flags & BF_READERR)
+ ? 'x'
+ : (bufIsChanged(buf) ? '+' : ' ');
+ int ro_char = !MODIFIABLE(buf) ? '-' : (buf->b_p_ro ? '=' : ' ');
+ if (buf->terminal) {
+ ro_char = channel_job_running((uint64_t)buf->b_p_channel) ? 'R' : 'F';
+ }
+
msg_putchar('\n');
- len = vim_snprintf((char *)IObuff, IOSIZE - 20, "%3d%c%c%c%c%c \"%s\"",
+ 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'),
- !MODIFIABLE(buf) ? '-' : (buf->b_p_ro ? '=' : ' '),
- (buf->b_flags & BF_READERR) ? 'x' : (bufIsChanged(buf) ? '+' : ' '),
+ ro_char,
+ changed_char,
NameBuff);
if (len > IOSIZE - 20) {
@@ -3341,7 +3367,6 @@ int build_stl_str_hl(
char_u *usefmt = fmt;
const int save_must_redraw = must_redraw;
const int save_redr_type = curwin->w_redr_type;
- const int save_highlight_shcnaged = need_highlight_changed;
// When the format starts with "%!" then evaluate it as an expression and
// use the result as the actual format string.
@@ -4405,12 +4430,12 @@ int build_stl_str_hl(
cur_tab_rec->def.func = NULL;
}
- // We do not want redrawing a stausline, ruler, title, etc. to trigger
- // another redraw, it may cause an endless loop. This happens when a
- // statusline changes a highlight group.
- must_redraw = save_must_redraw;
- curwin->w_redr_type = save_redr_type;
- need_highlight_changed = save_highlight_shcnaged;
+ // When inside update_screen we do not want redrawing a stausline, ruler,
+ // title, etc. to trigger another redraw, it may cause an endless loop.
+ if (updating_screen) {
+ must_redraw = save_must_redraw;
+ curwin->w_redr_type = save_redr_type;
+ }
return width;
}
@@ -5147,18 +5172,21 @@ chk_modeline(
// Return true if "buf" is a help buffer.
bool bt_help(const buf_T *const buf)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
return buf != NULL && buf->b_help;
}
// Return true if "buf" is the quickfix buffer.
bool bt_quickfix(const buf_T *const buf)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
return buf != NULL && buf->b_p_bt[0] == 'q';
}
// Return true if "buf" is a terminal buffer.
bool bt_terminal(const buf_T *const buf)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
return buf != NULL && buf->b_p_bt[0] == 't';
}
@@ -5166,6 +5194,7 @@ bool bt_terminal(const buf_T *const buf)
// Return true if "buf" is a "nofile", "acwrite" or "terminal" buffer.
// This means the buffer name is not a file name.
bool bt_nofile(const buf_T *const buf)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
return buf != NULL && ((buf->b_p_bt[0] == 'n' && buf->b_p_bt[2] == 'f')
|| buf->b_p_bt[0] == 'a' || buf->terminal);
@@ -5173,11 +5202,13 @@ bool bt_nofile(const buf_T *const buf)
// Return true if "buf" is a "nowrite", "nofile" or "terminal" buffer.
bool bt_dontwrite(const buf_T *const buf)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
return buf != NULL && (buf->b_p_bt[0] == 'n' || buf->terminal);
}
bool bt_dontwrite_msg(const buf_T *const buf)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
if (bt_dontwrite(buf)) {
EMSG(_("E382: Cannot write, 'buftype' option is set"));
@@ -5223,8 +5254,8 @@ char_u *buf_spname(buf_T *buf)
// There is no _file_ when 'buftype' is "nofile", b_sfname
// contains the name as specified by the user.
if (bt_nofile(buf)) {
- if (buf->b_sfname != NULL) {
- return buf->b_sfname;
+ if (buf->b_fname != NULL) {
+ return buf->b_fname;
}
return (char_u *)_("[Scratch]");
}
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 117a9183a4..b11eaefdd0 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -252,6 +252,8 @@ typedef struct {
# define w_p_fcs w_onebuf_opt.wo_fcs // 'fillchars'
char_u *wo_lcs;
# define w_p_lcs w_onebuf_opt.wo_lcs // 'listchars'
+ long wo_winbl;
+# define w_p_winbl w_onebuf_opt.wo_winbl // 'winblend'
LastSet wo_scriptID[WV_COUNT]; // SIDs for window-local options
# define w_p_scriptID w_onebuf_opt.wo_scriptID
@@ -456,8 +458,10 @@ typedef TV_DICTITEM_STRUCT(sizeof("changedtick")) ChangedtickDictItem;
typedef struct {
LuaRef on_lines;
LuaRef on_changedtick;
+ LuaRef on_detach;
+ bool utf_sizes;
} BufUpdateCallbacks;
-#define BUF_UPDATE_CALLBACKS_INIT { LUA_NOREF, LUA_NOREF }
+#define BUF_UPDATE_CALLBACKS_INIT { LUA_NOREF, LUA_NOREF, LUA_NOREF, false }
#define BUF_HAS_QF_ENTRY 1
#define BUF_HAS_LL_ENTRY 2
@@ -799,11 +803,26 @@ struct file_buffer {
kvec_t(BufhlLine *) b_bufhl_move_space; // temporary space for highlights
- // array of channelids which have asked to receive updates for this
+ // array of channel_id:s which have asked to receive updates for this
// buffer.
kvec_t(uint64_t) update_channels;
+ // array of lua callbacks for buffer updates.
kvec_t(BufUpdateCallbacks) update_callbacks;
+ // whether an update callback has requested codepoint size of deleted regions.
+ bool update_need_codepoints;
+
+ // Measurements of the deleted or replaced region since the last update
+ // event. Some consumers of buffer changes need to know the byte size (like
+ // tree-sitter) or the corresponding UTF-32/UTF-16 size (like LSP) of the
+ // deleted text.
+ size_t deleted_bytes;
+ size_t deleted_codepoints;
+ size_t deleted_codeunits;
+
+ // The number for times the current line has been flushed in the memline.
+ int flush_count;
+
int b_diff_failed; // internal diff failed for this buffer
};
@@ -969,7 +988,6 @@ struct matchitem {
};
typedef int FloatAnchor;
-typedef int FloatRelative;
enum {
kFloatAnchorEast = 1,
@@ -982,15 +1000,20 @@ enum {
// SE -> kFloatAnchorSouth | kFloatAnchorEast
EXTERN const char *const float_anchor_str[] INIT(= { "NW", "NE", "SW", "SE" });
-enum {
+typedef enum {
kFloatRelativeEditor = 0,
kFloatRelativeWindow = 1,
kFloatRelativeCursor = 2,
-};
+} FloatRelative;
EXTERN const char *const float_relative_str[] INIT(= { "editor", "window",
"cursor" });
+typedef enum {
+ kWinStyleUnused = 0,
+ kWinStyleMinimal, /// Minimal UI: no number column, eob markers, etc
+} WinStyle;
+
typedef struct {
Window window;
int height, width;
@@ -999,12 +1022,14 @@ typedef struct {
FloatRelative relative;
bool external;
bool focusable;
+ WinStyle style;
} FloatConfig;
#define FLOAT_CONFIG_INIT ((FloatConfig){ .height = 0, .width = 0, \
.row = 0, .col = 0, .anchor = 0, \
.relative = 0, .external = false, \
- .focusable = true })
+ .focusable = true, \
+ .style = kWinStyleUnused })
// Structure to store last cursor position and topline. Used by check_lnums()
// and reset_lnums().
diff --git a/src/nvim/buffer_updates.c b/src/nvim/buffer_updates.c
index 2515e3f8aa..3604578b50 100644
--- a/src/nvim/buffer_updates.c
+++ b/src/nvim/buffer_updates.c
@@ -26,6 +26,9 @@ bool buf_updates_register(buf_T *buf, uint64_t channel_id,
if (channel_id == LUA_INTERNAL_CALL) {
kv_push(buf->update_callbacks, cb);
+ if (cb.utf_sizes) {
+ buf->update_need_codepoints = true;
+ }
return true;
}
@@ -143,7 +146,21 @@ void buf_updates_unregister_all(buf_T *buf)
}
for (size_t i = 0; i < kv_size(buf->update_callbacks); i++) {
- free_update_callbacks(kv_A(buf->update_callbacks, i));
+ BufUpdateCallbacks cb = kv_A(buf->update_callbacks, i);
+ if (cb.on_detach != LUA_NOREF) {
+ Array args = ARRAY_DICT_INIT;
+ Object items[1];
+ args.size = 1;
+ args.items = items;
+
+ // the first argument is always the buffer handle
+ args.items[0] = BUFFER_OBJ(buf->handle);
+
+ textlock++;
+ executor_exec_lua_cb(cb.on_detach, "detach", args, false);
+ textlock--;
+ }
+ free_update_callbacks(cb);
}
kv_destroy(buf->update_callbacks);
kv_init(buf->update_callbacks);
@@ -155,6 +172,10 @@ void buf_updates_send_changes(buf_T *buf,
int64_t num_removed,
bool send_tick)
{
+ size_t deleted_codepoints, deleted_codeunits;
+ size_t deleted_bytes = ml_flush_deleted_bytes(buf, &deleted_codepoints,
+ &deleted_codeunits);
+
if (!buf_updates_active(buf)) {
return;
}
@@ -217,8 +238,8 @@ void buf_updates_send_changes(buf_T *buf,
bool keep = true;
if (cb.on_lines != LUA_NOREF) {
Array args = ARRAY_DICT_INIT;
- Object items[5];
- args.size = 5;
+ Object items[8];
+ args.size = 6; // may be increased to 8 below
args.items = items;
// the first argument is always the buffer handle
@@ -236,14 +257,22 @@ void buf_updates_send_changes(buf_T *buf,
// the last line in the updated range
args.items[4] = INTEGER_OBJ(firstline - 1 + num_added);
+ // byte count of previous contents
+ args.items[5] = INTEGER_OBJ((Integer)deleted_bytes);
+ if (cb.utf_sizes) {
+ args.size = 8;
+ args.items[6] = INTEGER_OBJ((Integer)deleted_codepoints);
+ args.items[7] = INTEGER_OBJ((Integer)deleted_codeunits);
+ }
textlock++;
- Object res = executor_exec_lua_cb(cb.on_lines, "lines", args);
+ Object res = executor_exec_lua_cb(cb.on_lines, "lines", args, true);
textlock--;
if (res.type == kObjectTypeBoolean && res.data.boolean == true) {
free_update_callbacks(cb);
keep = false;
}
+ api_free_object(res);
}
if (keep) {
kv_A(buf->update_callbacks, j++) = kv_A(buf->update_callbacks, i);
@@ -276,13 +305,15 @@ void buf_updates_changedtick(buf_T *buf)
args.items[1] = INTEGER_OBJ(buf_get_changedtick(buf));
textlock++;
- Object res = executor_exec_lua_cb(cb.on_changedtick, "changedtick", args);
+ Object res = executor_exec_lua_cb(cb.on_changedtick, "changedtick",
+ args, true);
textlock--;
if (res.type == kObjectTypeBoolean && res.data.boolean == true) {
free_update_callbacks(cb);
keep = false;
}
+ api_free_object(res);
}
if (keep) {
kv_A(buf->update_callbacks, j++) = kv_A(buf->update_callbacks, i);
diff --git a/src/nvim/change.c b/src/nvim/change.c
new file mode 100644
index 0000000000..2363578139
--- /dev/null
+++ b/src/nvim/change.c
@@ -0,0 +1,1798 @@
+// 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
+
+/// change.c: functions related to changing text
+
+#include "nvim/assert.h"
+#include "nvim/buffer.h"
+#include "nvim/buffer_updates.h"
+#include "nvim/change.h"
+#include "nvim/charset.h"
+#include "nvim/cursor.h"
+#include "nvim/diff.h"
+#include "nvim/edit.h"
+#include "nvim/eval.h"
+#include "nvim/fileio.h"
+#include "nvim/fold.h"
+#include "nvim/indent.h"
+#include "nvim/indent_c.h"
+#include "nvim/mark.h"
+#include "nvim/memline.h"
+#include "nvim/misc1.h"
+#include "nvim/move.h"
+#include "nvim/option.h"
+#include "nvim/screen.h"
+#include "nvim/search.h"
+#include "nvim/state.h"
+#include "nvim/ui.h"
+#include "nvim/undo.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "change.c.generated.h"
+#endif
+
+/// If the file is readonly, give a warning message with the first change.
+/// Don't do this for autocommands.
+/// Doesn't use emsg(), because it flushes the macro buffer.
+/// If we have undone all changes b_changed will be false, but "b_did_warn"
+/// will be true.
+/// "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)
+{
+ static char *w_readonly = N_("W10: Warning: Changing a readonly file");
+
+ if (curbuf->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;
+ }
+ // 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_source(HL_ATTR(HLF_W));
+ msg_ext_set_kind("wmsg");
+ MSG_PUTS_ATTR(_(w_readonly), HL_ATTR(HLF_W) | MSG_HIST);
+ set_vim_var_string(VV_WARNINGMSG, _(w_readonly), -1);
+ msg_clr_eos();
+ (void)msg_end();
+ if (msg_silent == 0 && !silent_mode && ui_active()) {
+ ui_flush();
+ os_delay(1000L, true); // give the user time to think about it
+ }
+ curbuf->b_did_warn = true;
+ redraw_cmdline = false; // don't redraw and erase the message
+ if (msg_row < Rows - 1) {
+ showmode();
+ }
+ }
+}
+
+/// Call this function when something in the current buffer is changed.
+///
+/// Most often called through changed_bytes() and changed_lines(), which also
+/// mark the area of the display to be redrawn.
+///
+/// Careful: may trigger autocommands that reload the buffer.
+void changed(void)
+{
+ if (!curbuf->b_changed) {
+ int save_msg_scroll = msg_scroll;
+
+ // Give a warning about changing a read-only file. This may also
+ // check-out the file, thus change "curbuf"!
+ change_warning(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;
+
+ need_wait_return = false;
+ ml_open_file(curbuf);
+
+ // The ml_open_file() can cause an ATTENTION message.
+ // Wait two seconds, to make sure the user reads this unexpected
+ // message. Since we could be anywhere, call wait_return() now,
+ // and don't let the emsg() set msg_scroll.
+ if (need_wait_return && emsg_silent == 0) {
+ ui_flush();
+ os_delay(2000L, true);
+ wait_return(true);
+ msg_scroll = save_msg_scroll;
+ } else {
+ need_wait_return = save_need_wait_return;
+ }
+ }
+ changed_internal();
+ }
+ buf_inc_changedtick(curbuf);
+
+ // If a pattern is highlighted, the position may now be invalid.
+ highlight_match = false;
+}
+
+/// Internal part of changed(), no user interaction.
+/// Also used for recovery.
+void changed_internal(void)
+{
+ curbuf->b_changed = true;
+ ml_setflags(curbuf);
+ check_status(curbuf);
+ redraw_tabline = true;
+ need_maketitle = true; // set window title later
+}
+
+/// 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)
+{
+ int i;
+ int cols;
+ pos_T *p;
+ int add;
+
+ // mark the buffer as modified
+ changed();
+
+ if (curwin->w_p_diff && diff_internal()) {
+ curtab->tp_diff_update = true;
+ }
+
+ // set the '. mark
+ if (!cmdmod.keepjumps) {
+ RESET_FMARK(&curbuf->b_last_change, ((pos_T) { lnum, col, 0 }), 0);
+
+ // Create a new entry if a new undo-able change was started or we
+ // don't have an entry yet.
+ if (curbuf->b_new_change || curbuf->b_changelistlen == 0) {
+ if (curbuf->b_changelistlen == 0) {
+ 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;
+ } else {
+ cols = comp_textwidth(false);
+ if (cols == 0) {
+ cols = 79;
+ }
+ add = (p->col + cols < col || col + cols < p->col);
+ }
+ }
+ if (add) {
+ // This is the first of a new sequence of undo-able changes
+ // and it's at some distance of the last change. Use a new
+ // position in the changelist.
+ curbuf->b_new_change = false;
+
+ if (curbuf->b_changelistlen == JUMPLISTSIZE) {
+ // changelist is full: remove oldest entry
+ curbuf->b_changelistlen = JUMPLISTSIZE - 1;
+ memmove(curbuf->b_changelist, curbuf->b_changelist + 1,
+ sizeof(curbuf->b_changelist[0]) * (JUMPLISTSIZE - 1));
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ // Correct position in changelist for other windows on
+ // this buffer.
+ if (wp->w_buffer == curbuf && wp->w_changelistidx > 0) {
+ wp->w_changelistidx--;
+ }
+ }
+ }
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ // For other windows, if the position in the changelist is
+ // at the end it stays at the end.
+ if (wp->w_buffer == curbuf
+ && wp->w_changelistidx == curbuf->b_changelistlen) {
+ wp->w_changelistidx++;
+ }
+ }
+ curbuf->b_changelistlen++;
+ }
+ }
+ curbuf->b_changelist[curbuf->b_changelistlen - 1] =
+ curbuf->b_last_change;
+ // The current window is always after the last change, so that "g,"
+ // takes you back to it.
+ curwin->w_changelistidx = curbuf->b_changelistlen;
+ }
+
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
+ if (wp->w_buffer == curbuf) {
+ // Mark this window to be redrawn later.
+ if (wp->w_redr_type < VALID) {
+ wp->w_redr_type = VALID;
+ }
+
+ // Check if a change in the buffer has invalidated the cached
+ // values for the cursor.
+ // Update the folds for this window. Can't postpone this, because
+ // a following operator might work on the whole fold: ">>dd".
+ foldUpdate(wp, lnum, lnume + xtra - 1);
+
+ // The change may cause lines above or below the change to become
+ // included in a fold. Set lnum/lnume to the first/last line that
+ // might be displayed differently.
+ // Set w_cline_folded here as an efficient way to update it when
+ // 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;
+ }
+ folded = hasFoldingWin(wp, lnume, NULL, &lnume, false, NULL);
+ if (wp->w_cursor.lnum == lnume) {
+ wp->w_cline_folded = folded;
+ }
+
+ // If the changed line is in a range of previously folded lines,
+ // compare with the first line in that range.
+ 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);
+ }
+ }
+
+ if (wp->w_cursor.lnum > lnum) {
+ changed_line_abv_curs_win(wp);
+ } else if (wp->w_cursor.lnum == lnum && wp->w_cursor.col >= col) {
+ changed_cline_bef_curs_win(wp);
+ }
+ if (wp->w_botline >= lnum) {
+ // Assume that botline doesn't change (inserted lines make
+ // other lines scroll down below botline).
+ approximate_botline_win(wp);
+ }
+
+ // Check if any w_lines[] entries have become invalid.
+ // For entries below the change: Correct the lnums for
+ // inserted/deleted lines. Makes it possible to stop displaying
+ // after the change.
+ for (i = 0; i < wp->w_lines_valid; i++) {
+ if (wp->w_lines[i].wl_valid) {
+ if (wp->w_lines[i].wl_lnum >= lnum) {
+ if (wp->w_lines[i].wl_lnum < lnume) {
+ // line included in change
+ wp->w_lines[i].wl_valid = false;
+ } else if (xtra != 0) {
+ // line below change
+ wp->w_lines[i].wl_lnum += xtra;
+ wp->w_lines[i].wl_lastlnum += xtra;
+ }
+ } else if (wp->w_lines[i].wl_lastlnum >= lnum) {
+ // change somewhere inside this range of folded lines,
+ // may need to be redrawn
+ wp->w_lines[i].wl_valid = false;
+ }
+ }
+ }
+
+ // Take care of side effects for setting w_topline when folds have
+ // changed. Esp. when the buffer was changed in another window.
+ if (hasAnyFolding(wp)) {
+ set_topline(wp, wp->w_topline);
+ }
+
+ // relative numbering may require updating more
+ if (wp->w_p_rnu) {
+ redraw_win_later(wp, SOME_VALID);
+ }
+ }
+ }
+
+ // Call update_screen() later, which checks out what needs to be redrawn,
+ // since it notices b_mod_set and then uses b_mod_*.
+ if (must_redraw < VALID) {
+ must_redraw = VALID;
+ }
+
+ // when the cursor line is changed always trigger CursorMoved
+ if (lnum <= curwin->w_cursor.lnum
+ && lnume + (xtra < 0 ? -xtra : xtra) > curwin->w_cursor.lnum) {
+ curwin->w_last_cursormoved.lnum = 0;
+ }
+}
+
+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;
+ } else if (lnum >= buf->b_mod_bot) {
+ buf->b_mod_bot = lnum + 1;
+ }
+ } else {
+ // set the area that must be redisplayed to one line
+ buf->b_mod_set = true;
+ buf->b_mod_top = lnum;
+ buf->b_mod_bot = lnum + 1;
+ buf->b_mod_xlines = 0;
+ }
+}
+
+/// Changed bytes within a single line for the current buffer.
+/// - marks the windows on this buffer to be redisplayed
+/// - marks the buffer changed by calling changed()
+/// - invalidates cached values
+/// Careful: may trigger autocommands that reload the buffer.
+void changed_bytes(linenr_T lnum, colnr_T col)
+{
+ changedOneline(curbuf, lnum);
+ changed_common(lnum, col, lnum + 1, 0L);
+ // notify any channels that are watching
+ buf_updates_send_changes(curbuf, lnum, 1, 1, true);
+
+ // Diff highlighting in other diff windows may need to be updated too.
+ if (curwin->w_p_diff) {
+ linenr_T wlnum;
+
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ if (wp->w_p_diff && wp != curwin) {
+ redraw_win_later(wp, VALID);
+ wlnum = diff_lnum_win(lnum, wp);
+ if (wlnum > 0) {
+ changedOneline(wp->w_buffer, wlnum);
+ }
+ }
+ }
+ }
+}
+
+/// Appended "count" lines below line "lnum" in the current buffer.
+/// Must be called AFTER the change and after mark_adjust().
+/// Takes care of marking the buffer to be redrawn and sets the changed flag.
+void appended_lines(linenr_T lnum, long count)
+{
+ changed_lines(lnum + 1, 0, lnum + 1, count, true);
+}
+
+/// Like appended_lines(), but adjust marks first.
+void appended_lines_mark(linenr_T lnum, long count)
+{
+ // Skip mark_adjust when adding a line after the last one, there can't
+ // be marks there. But it's still needed in diff mode.
+ if (lnum + count < curbuf->b_ml.ml_line_count || curwin->w_p_diff) {
+ mark_adjust(lnum + 1, (linenr_T)MAXLNUM, count, 0L, false);
+ }
+ changed_lines(lnum + 1, 0, lnum + 1, count, true);
+}
+
+/// Deleted "count" lines at line "lnum" in the current buffer.
+/// Must be called AFTER the change and after mark_adjust().
+/// Takes care of marking the buffer to be redrawn and sets the changed flag.
+void deleted_lines(linenr_T lnum, long count)
+{
+ changed_lines(lnum, 0, lnum + count, -count, true);
+}
+
+/// Like deleted_lines(), but adjust marks first.
+/// Make sure the cursor is on a valid line before calling, a GUI callback may
+/// be triggered to display the cursor.
+void deleted_lines_mark(linenr_T lnum, long count)
+{
+ mark_adjust(lnum, (linenr_T)(lnum + count - 1), (long)MAXLNUM, -count, false);
+ changed_lines(lnum, 0, lnum + count, -count, true);
+}
+
+/// Marks the area to be redrawn after a change.
+///
+/// @param buf the buffer where lines were changed
+/// @param lnum first line with change
+/// @param lnume line below last changed line
+/// @param xtra number of extra lines (negative when deleting)
+void changed_lines_buf(buf_T *buf, linenr_T lnum, linenr_T lnume, long xtra)
+{
+ if (buf->b_mod_set) {
+ // find the maximum area that must be redisplayed
+ if (lnum < buf->b_mod_top) {
+ buf->b_mod_top = lnum;
+ }
+ if (lnum < buf->b_mod_bot) {
+ // adjust old bot position for xtra lines
+ buf->b_mod_bot += xtra;
+ if (buf->b_mod_bot < lnum) {
+ buf->b_mod_bot = lnum;
+ }
+ }
+ if (lnume + xtra > buf->b_mod_bot) {
+ buf->b_mod_bot = lnume + xtra;
+ }
+ buf->b_mod_xlines += xtra;
+ } else {
+ // set the area that must be redisplayed
+ buf->b_mod_set = true;
+ buf->b_mod_top = lnum;
+ buf->b_mod_bot = lnume + xtra;
+ buf->b_mod_xlines = xtra;
+ }
+}
+
+/// Changed lines for the current buffer.
+/// Must be called AFTER the change and after mark_adjust().
+/// - mark the buffer changed by calling changed()
+/// - mark the windows on this buffer to be redisplayed
+/// - invalidate cached values
+/// "lnum" is the first line that needs displaying, "lnume" the first line
+/// below the changed lines (BEFORE the change).
+/// 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.
+)
+{
+ changed_lines_buf(curbuf, lnum, lnume, xtra);
+
+ if (xtra == 0 && curwin->w_p_diff && !diff_internal()) {
+ // When the number of lines doesn't change then mark_adjust() isn't
+ // called and other diff buffers still need to be marked for
+ // displaying.
+ linenr_T wlnum;
+
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ if (wp->w_p_diff && wp != curwin) {
+ redraw_win_later(wp, VALID);
+ wlnum = diff_lnum_win(lnum, wp);
+ if (wlnum > 0) {
+ changed_lines_buf(wp->w_buffer, wlnum,
+ lnume - lnum + wlnum, 0L);
+ }
+ }
+ }
+ }
+
+ changed_common(lnum, col, lnume, xtra);
+
+ if (do_buf_event) {
+ int64_t num_added = (int64_t)(lnume + xtra - lnum);
+ int64_t num_removed = lnume - lnum;
+ buf_updates_send_changes(curbuf, lnum, num_added, num_removed, true);
+ }
+}
+
+/// Called when the changed flag must be reset for buffer "buf".
+/// When "ff" is true also reset 'fileformat'.
+void unchanged(buf_T *buf, int ff)
+{
+ if (buf->b_changed || (ff && file_ff_differs(buf, false))) {
+ buf->b_changed = false;
+ ml_setflags(buf);
+ if (ff) {
+ save_file_ff(buf);
+ }
+ check_status(buf);
+ redraw_tabline = true;
+ need_maketitle = true; // set window title later
+ }
+ buf_inc_changedtick(buf);
+}
+
+/// Insert string "p" at the cursor position. Stops at a NUL byte.
+/// Handles Replace mode and multi-byte characters.
+void ins_bytes(char_u *p)
+{
+ ins_bytes_len(p, STRLEN(p));
+}
+
+/// Insert string "p" with length "len" at the cursor position.
+/// Handles Replace mode and multi-byte characters.
+void ins_bytes_len(char_u *p, size_t len)
+{
+ size_t n;
+ for (size_t i = 0; i < len; i += n) {
+ if (enc_utf8) {
+ // avoid reading past p[len]
+ n = (size_t)utfc_ptr2len_len(p + i, (int)(len - i));
+ } else {
+ n = (size_t)(*mb_ptr2len)(p + i);
+ }
+ ins_char_bytes(p + i, n);
+ }
+}
+
+/// Insert or replace a single character at the cursor position.
+/// When in REPLACE or VREPLACE mode, replace any existing character.
+/// Caller must have prepared for undo.
+/// For multi-byte characters we get the whole character, the caller must
+/// convert bytes to a character.
+void ins_char(int c)
+{
+ char_u buf[MB_MAXBYTES + 1];
+ size_t n = (size_t)utf_char2bytes(c, buf);
+
+ // When "c" is 0x100, 0x200, etc. we don't want to insert a NUL byte.
+ // Happens for CTRL-Vu9900.
+ if (buf[0] == 0) {
+ buf[0] = '\n';
+ }
+ ins_char_bytes(buf, n);
+}
+
+void ins_char_bytes(char_u *buf, size_t charlen)
+{
+ // Break tabs if needed.
+ if (virtual_active() && curwin->w_cursor.coladd > 0) {
+ coladvance_force(getviscol());
+ }
+
+ size_t col = (size_t)curwin->w_cursor.col;
+ linenr_T lnum = curwin->w_cursor.lnum;
+ char_u *oldp = ml_get(lnum);
+ size_t linelen = STRLEN(oldp) + 1; // length of old line including NUL
+
+ // The lengths default to the values for when not replacing.
+ size_t oldlen = 0; // nr of bytes inserted
+ size_t newlen = charlen; // nr of bytes deleted (0 when not replacing)
+
+ if (State & REPLACE_FLAG) {
+ if (State & VREPLACE_FLAG) {
+ // Disable 'list' temporarily, unless 'cpo' contains the 'L' flag.
+ // Returns the old value of list, so when finished,
+ // curwin->w_p_list should be set back to this.
+ int old_list = curwin->w_p_list;
+ if (old_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL) {
+ curwin->w_p_list = false;
+ }
+ // In virtual replace mode each character may replace one or more
+ // characters (zero if it's a TAB). Count the number of bytes to
+ // be deleted to make room for the new character, counting screen
+ // 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);
+ while (oldp[col + oldlen] != NUL && vcol < new_vcol) {
+ vcol += chartabsize(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) {
+ break;
+ }
+ oldlen += (size_t)(*mb_ptr2len)(oldp + col + oldlen);
+ // Deleted a bit too much, insert spaces.
+ if (vcol > new_vcol) {
+ newlen += (size_t)(vcol - new_vcol);
+ }
+ }
+ curwin->w_p_list = old_list;
+ } else if (oldp[col] != NUL) {
+ // normal replace
+ oldlen = (size_t)(*mb_ptr2len)(oldp + col);
+ }
+
+
+ // Push the replaced bytes onto the replace stack, so that they can be
+ // put back when BS is used. The bytes of a multi-byte character are
+ // done the other way around, so that the first byte is popped off
+ // first (it tells the byte length of the character).
+ replace_push(NUL);
+ for (size_t i = 0; i < oldlen; i++) {
+ i += (size_t)replace_push_mb(oldp + col + i) - 1;
+ }
+ }
+
+ char_u *newp = xmalloc((size_t)(linelen + newlen - oldlen));
+
+ // Copy bytes before the cursor.
+ if (col > 0) {
+ memmove(newp, oldp, (size_t)col);
+ }
+
+ // Copy bytes after the changed character(s).
+ char_u *p = newp + col;
+ if (linelen > col + oldlen) {
+ memmove(p + newlen, oldp + col + oldlen,
+ (size_t)(linelen - col - oldlen));
+ }
+
+ // Insert or overwrite the new character.
+ memmove(p, buf, charlen);
+
+ // Fill with spaces when necessary.
+ for (size_t i = charlen; i < newlen; i++) {
+ p[i] = ' ';
+ }
+
+ // Replace the line in the buffer.
+ ml_replace(lnum, newp, false);
+
+ // mark the buffer as changed and prepare for displaying
+ changed_bytes(lnum, (colnr_T)col);
+
+ // If we're in Insert or Replace mode and 'showmatch' is set, then briefly
+ // show the match for right parens and braces.
+ if (p_sm && (State & INSERT)
+ && msg_silent == 0
+ && !ins_compl_active()
+ ) {
+ showmatch(utf_ptr2char(buf));
+ }
+
+ if (!p_ri || (State & REPLACE_FLAG)) {
+ // Normal insert: move cursor right
+ curwin->w_cursor.col += (int)charlen;
+ }
+ // TODO(Bram): should try to update w_row here, to avoid recomputing it later.
+}
+
+/// Insert a string at the cursor position.
+/// Note: Does NOT handle Replace mode.
+/// Caller must have prepared for undo.
+void ins_str(char_u *s)
+{
+ char_u *oldp, *newp;
+ int newlen = (int)STRLEN(s);
+ int oldlen;
+ colnr_T col;
+ linenr_T lnum = curwin->w_cursor.lnum;
+
+ if (virtual_active() && curwin->w_cursor.coladd > 0) {
+ coladvance_force(getviscol());
+ }
+
+ col = curwin->w_cursor.col;
+ oldp = ml_get(lnum);
+ oldlen = (int)STRLEN(oldp);
+
+ newp = (char_u *)xmalloc((size_t)oldlen + (size_t)newlen + 1);
+ if (col > 0) {
+ memmove(newp, oldp, (size_t)col);
+ }
+ memmove(newp + col, s, (size_t)newlen);
+ int bytes = oldlen - col + 1;
+ assert(bytes >= 0);
+ memmove(newp + col + newlen, oldp + col, (size_t)bytes);
+ ml_replace(lnum, newp, false);
+ changed_bytes(lnum, col);
+ curwin->w_cursor.col += newlen;
+}
+
+// Delete one character under the cursor.
+// If "fixpos" is true, don't leave the cursor on the NUL after the line.
+// Caller must have prepared for undo.
+//
+// return FAIL for failure, OK otherwise
+int del_char(bool fixpos)
+{
+ // Make sure the cursor is at the start of a character.
+ mb_adjust_cursor();
+ if (*get_cursor_pos_ptr() == NUL) {
+ return FAIL;
+ }
+ return del_chars(1L, fixpos);
+}
+
+/// Like del_bytes(), but delete characters instead of bytes.
+int del_chars(long count, int fixpos)
+{
+ int bytes = 0;
+ long i;
+ char_u *p;
+ int l;
+
+ p = get_cursor_pos_ptr();
+ for (i = 0; i < count && *p != NUL; i++) {
+ l = (*mb_ptr2len)(p);
+ bytes += l;
+ p += l;
+ }
+ return del_bytes(bytes, fixpos, true);
+}
+
+/// Delete "count" bytes under the cursor.
+/// If "fixpos" is true, don't leave the cursor on the NUL after the line.
+/// Caller must have prepared for undo.
+///
+/// @param count number of bytes to be deleted
+/// @param fixpos_arg leave the cursor on the NUL after the line
+/// @param use_delcombine 'delcombine' option applies
+///
+/// @return FAIL for failure, OK otherwise
+int del_bytes(colnr_T count, bool fixpos_arg, bool use_delcombine)
+{
+ linenr_T lnum = curwin->w_cursor.lnum;
+ colnr_T col = curwin->w_cursor.col;
+ bool fixpos = fixpos_arg;
+ char_u *oldp = ml_get(lnum);
+ colnr_T oldlen = (colnr_T)STRLEN(oldp);
+
+ // Can't do anything when the cursor is on the NUL after the line.
+ if (col >= oldlen) {
+ return FAIL;
+ }
+ // If "count" is zero there is nothing to do.
+ if (count == 0) {
+ return OK;
+ }
+ // If "count" is negative the caller must be doing something wrong.
+ if (count < 1) {
+ IEMSGN("E950: Invalid count for del_bytes(): %ld", count);
+ return FAIL;
+ }
+
+ // If 'delcombine' is set and deleting (less than) one character, only
+ // delete the last combining character.
+ if (p_deco && use_delcombine && enc_utf8
+ && utfc_ptr2len(oldp + col) >= count) {
+ int cc[MAX_MCO];
+ int n;
+
+ (void)utfc_ptr2char(oldp + col, cc);
+ if (cc[0] != NUL) {
+ // Find the last composing char, there can be several.
+ n = col;
+ do {
+ col = n;
+ count = utf_ptr2len(oldp + n);
+ n += count;
+ } while (UTF_COMPOSINGLIKE(oldp + col, oldp + n));
+ fixpos = false;
+ }
+ }
+
+ // When count is too big, reduce it.
+ 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,
+ // unless "restart_edit" is set or 'virtualedit' contains "onemore".
+ if (col > 0 && fixpos && restart_edit == 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);
+ }
+ count = oldlen - col;
+ movelen = 1;
+ }
+
+ // If the old line has been allocated the deletion can be done in the
+ // existing line. Otherwise a new line has to be allocated.
+ bool was_alloced = ml_line_alloced(); // check if oldp was allocated
+ char_u *newp;
+ if (was_alloced) {
+ ml_add_deleted_len(curbuf->b_ml.ml_line_ptr, oldlen);
+ newp = oldp; // use same allocated memory
+ } else { // need to allocate a new line
+ newp = xmalloc((size_t)(oldlen + 1 - count));
+ memmove(newp, oldp, (size_t)col);
+ }
+ memmove(newp + col, oldp + col + count, (size_t)movelen);
+ if (!was_alloced) {
+ ml_replace(lnum, newp, false);
+ }
+
+ // mark the buffer as changed and prepare for displaying
+ changed_bytes(lnum, curwin->w_cursor.col);
+
+ return OK;
+}
+
+/// Copy the indent from ptr to the current line (and fill to size).
+/// Leaves the cursor on the first non-blank in the line.
+/// @return true if the line was changed.
+int copy_indent(int size, char_u *src)
+{
+ char_u *p = NULL;
+ char_u *line = NULL;
+ char_u *s;
+ int todo;
+ int ind_len;
+ int line_len = 0;
+ int tab_pad;
+ int ind_done;
+ int round;
+
+ // Round 1: compute the number of characters needed for the indent
+ // Round 2: copy the characters.
+ for (round = 1; round <= 2; round++) {
+ todo = size;
+ ind_len = 0;
+ ind_done = 0;
+ s = src;
+
+ // Count/copy the usable portion of the source line.
+ while (todo > 0 && ascii_iswhite(*s)) {
+ if (*s == TAB) {
+ tab_pad = (int)curbuf->b_p_ts
+ - (ind_done % (int)curbuf->b_p_ts);
+
+ // Stop if this tab will overshoot the target.
+ if (todo < tab_pad) {
+ break;
+ }
+ todo -= tab_pad;
+ ind_done += tab_pad;
+ } else {
+ todo--;
+ ind_done++;
+ }
+ ind_len++;
+
+ if (p != NULL) {
+ *p++ = *s;
+ }
+ s++;
+ }
+
+ // Fill to next tabstop with a tab, if possible.
+ tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts);
+
+ if ((todo >= tab_pad) && !curbuf->b_p_et) {
+ todo -= tab_pad;
+ ind_len++;
+
+ if (p != NULL) {
+ *p++ = TAB;
+ }
+ }
+
+ // Add tabs required for indent.
+ while (todo >= (int)curbuf->b_p_ts && !curbuf->b_p_et) {
+ todo -= (int)curbuf->b_p_ts;
+ ind_len++;
+
+ if (p != NULL) {
+ *p++ = TAB;
+ }
+ }
+
+ // Count/add spaces required for indent.
+ while (todo > 0) {
+ todo--;
+ ind_len++;
+
+ if (p != NULL) {
+ *p++ = ' ';
+ }
+ }
+
+ if (p == NULL) {
+ // Allocate memory for the result: the copied indent, new indent
+ // and the rest of the line.
+ line_len = (int)STRLEN(get_cursor_line_ptr()) + 1;
+ assert(ind_len + line_len >= 0);
+ size_t line_size;
+ STRICT_ADD(ind_len, line_len, &line_size, size_t);
+ line = xmalloc(line_size);
+ p = line;
+ }
+ }
+
+ // Append the original line
+ memmove(p, get_cursor_line_ptr(), (size_t)line_len);
+
+ // Replace the line
+ ml_replace(curwin->w_cursor.lnum, line, false);
+
+ // Put the cursor after the indent.
+ curwin->w_cursor.col = ind_len;
+ return true;
+}
+
+/// open_line: Add a new line below or above the current line.
+///
+/// For VREPLACE mode, we only add a new line when we get to the end of the
+/// file, otherwise we just start replacing the next line.
+///
+/// Caller must take care of undo. Since VREPLACE may affect any number of
+/// lines however, it may call u_save_cursor() again when starting to change a
+/// new line.
+/// "flags": OPENLINE_DELSPACES delete spaces after cursor
+/// OPENLINE_DO_COM format comments
+/// OPENLINE_KEEPTRAIL keep trailing spaces
+/// OPENLINE_MARKFIX adjust mark positions after the line break
+/// OPENLINE_COM_LIST format comments with list or 2nd line indent
+///
+/// "second_line_indent": indent for after ^^D in Insert mode or if flag
+/// OPENLINE_COM_LIST
+///
+/// @return true on success, false on failure
+int open_line(
+ int dir, // FORWARD or BACKWARD
+ 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
+ colnr_T less_cols = 0; // less columns for mark in new line
+ colnr_T less_cols_off = 0; // columns to skip for mark adjust
+ pos_T old_cursor; // old cursor position
+ colnr_T newcol = 0; // new cursor column
+ int newindent = 0; // auto-indent of the new line
+ bool trunc_line = false; // truncate current line afterwards
+ bool retval = false; // return value
+ int extra_len = 0; // length of p_extra string
+ int lead_len; // length of comment leader
+ char_u *lead_flags; // position in 'comments' for comment leader
+ char_u *leader = NULL; // copy of comment leader
+ char_u *allocated = NULL; // allocated memory
+ char_u *p;
+ char_u saved_char = NUL; // init for GCC
+ pos_T *pos;
+ bool do_si = (!p_paste && curbuf->b_p_si && !curbuf->b_p_cin
+ && *curbuf->b_p_inde == NUL);
+ bool no_si = false; // reset did_si afterwards
+ int first_char = NUL; // init for GCC
+ int vreplace_mode;
+ bool did_append; // appended a new line
+ int saved_pi = curbuf->b_p_pi; // copy of preserveindent setting
+
+ // make a copy of the current line so we can mess with it
+ char_u *saved_line = vim_strsave(get_cursor_line_ptr());
+
+ if (State & VREPLACE_FLAG) {
+ // With VREPLACE we make a copy of the next line, which we will be
+ // starting to replace. First make the new line empty and let vim play
+ // with the indenting and comment leader to its heart's content. Then
+ // we grab what it ended up putting on the new line, put back the
+ // original line, and call ins_char() to put each new character onto
+ // 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));
+ } else {
+ next_line = vim_strsave((char_u *)"");
+ }
+
+ // In VREPLACE mode, a NL replaces the rest of the line, and starts
+ // replacing the next line, so push all of the characters left on the
+ // line onto the replace stack. We'll push any other characters that
+ // might be replaced at the start of the next line (due to autoindent
+ // etc) a bit later.
+ replace_push(NUL); // Call twice because BS over NL expects it
+ replace_push(NUL);
+ p = saved_line + curwin->w_cursor.col;
+ while (*p != NUL) {
+ p += replace_push_mb(p);
+ }
+ saved_line[curwin->w_cursor.col] = NUL;
+ }
+
+ if ((State & INSERT)
+ && !(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);
+ first_char = *p;
+ }
+ extra_len = (int)STRLEN(p_extra);
+ saved_char = *p_extra;
+ *p_extra = NUL;
+ }
+
+ u_clearline(); // cannot do "U" command when adding lines
+ did_si = false;
+ ai_col = 0;
+
+ // If we just did an auto-indent, then we didn't type anything on
+ // 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;
+ }
+
+ // 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
+ ) {
+ // count white space on current line
+ newindent = get_indent_str(saved_line, (int)curbuf->b_p_ts, false);
+ if (newindent == 0 && !(flags & OPENLINE_COM_LIST)) {
+ newindent = second_line_indent; // for ^^D command in insert mode
+ }
+
+ // Do smart indenting.
+ // In insert/replace mode (only when dir == FORWARD)
+ // we may move some text to the next line. If it starts with '{'
+ // don't add an indent. Fixes inserting a NL before '{' in line
+ // "if (condition) {"
+ if (!trunc_line && do_si && *saved_line != NUL
+ && (p_extra == NULL || first_char != '{')) {
+ 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);
+ } else {
+ lead_len = 0;
+ }
+ if (dir == FORWARD) {
+ // Skip preprocessor directives, unless they are
+ // recognised as comments.
+ if (lead_len == 0 && ptr[0] == '#') {
+ while (ptr[0] == '#' && curwin->w_cursor.lnum > 1) {
+ ptr = ml_get(--curwin->w_cursor.lnum);
+ }
+ newindent = get_indent();
+ }
+ if (flags & OPENLINE_DO_COM) {
+ lead_len = get_leader_len(ptr, NULL, false, true);
+ } else {
+ lead_len = 0;
+ }
+ if (lead_len > 0) {
+ // This case gets the following right:
+ // \*
+ // * A comment (read '\' as '/').
+ // */
+ // #define IN_THE_WAY
+ // This should line up here;
+ p = skipwhite(ptr);
+ if (p[0] == '/' && p[1] == '*') {
+ p++;
+ }
+ if (p[0] == '*') {
+ for (p++; *p; p++) {
+ if (p[0] == '/' && p[-1] == '*') {
+ // End of C comment, indent should line up
+ // with the line containing the start of
+ // the comment
+ curwin->w_cursor.col = (colnr_T)(p - ptr);
+ if ((pos = findmatch(NULL, NUL)) != NULL) {
+ curwin->w_cursor.lnum = pos->lnum;
+ newindent = get_indent();
+ }
+ }
+ }
+ }
+ } else { // Not a comment line
+ // Find last non-blank in line
+ p = ptr + STRLEN(ptr) - 1;
+ while (p > ptr && ascii_iswhite(*p)) {
+ p--;
+ }
+ last_char = *p;
+
+ // find the character just before the '{' or ';'
+ if (last_char == '{' || last_char == ';') {
+ if (p > ptr) {
+ p--;
+ }
+ while (p > ptr && ascii_iswhite(*p)) {
+ p--;
+ }
+ }
+ // Try to catch lines that are split over multiple
+ // lines. eg:
+ // if (condition &&
+ // condition) {
+ // Should line up here!
+ // }
+ if (*p == ')') {
+ curwin->w_cursor.col = (colnr_T)(p - ptr);
+ if ((pos = findmatch(NULL, '(')) != NULL) {
+ curwin->w_cursor.lnum = pos->lnum;
+ newindent = get_indent();
+ ptr = get_cursor_line_ptr();
+ }
+ }
+ // If last character is '{' do indent, without
+ // checking for "if" and the like.
+ 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
+ // '}'.
+ } else if (last_char != ';' && last_char != '}'
+ && cin_is_cinword(ptr)) {
+ did_si = true;
+ }
+ }
+ } else { // dir == BACKWARD
+ // Skip preprocessor directives, unless they are
+ // recognised as comments.
+ if (lead_len == 0 && ptr[0] == '#') {
+ bool was_backslashed = false;
+
+ while ((ptr[0] == '#' || was_backslashed)
+ && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) {
+ if (*ptr && ptr[STRLEN(ptr) - 1] == '\\') {
+ was_backslashed = true;
+ } else {
+ was_backslashed = false;
+ }
+ ptr = ml_get(++curwin->w_cursor.lnum);
+ }
+ if (was_backslashed) {
+ newindent = 0; // Got to end of file
+ } else {
+ newindent = get_indent();
+ }
+ }
+ p = skipwhite(ptr);
+ if (*p == '}') { // if line starts with '}': do indent
+ did_si = true;
+ } else { // can delete indent when '{' typed
+ can_si_back = true;
+ }
+ }
+ curwin->w_cursor = old_cursor;
+ }
+ if (do_si) {
+ can_si = true;
+ }
+
+ did_ai = true;
+ }
+
+ // Find out if the current line starts with a comment leader.
+ // This may then be inserted in front of the new line.
+ end_comment_pending = NUL;
+ if (flags & OPENLINE_DO_COM) {
+ lead_len = get_leader_len(saved_line, &lead_flags, dir == BACKWARD, true);
+ } else {
+ lead_len = 0;
+ }
+ if (lead_len > 0) {
+ 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
+ int extra_space = false; // append extra space
+ int current_flag;
+ int require_blank = false; // requires blank after middle
+ 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.
+ for (p = lead_flags; *p && *p != ':'; p++) {
+ if (*p == COM_BLANK) {
+ require_blank = true;
+ continue;
+ }
+ if (*p == COM_START || *p == COM_MIDDLE) {
+ current_flag = *p;
+ if (*p == COM_START) {
+ // Doing "O" on a start of comment does not insert leader.
+ if (dir == BACKWARD) {
+ lead_len = 0;
+ break;
+ }
+
+ // find start of middle part
+ (void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ",");
+ require_blank = false;
+ }
+
+ // Isolate the strings of the middle and end leader.
+ while (*p && p[-1] != ':') { // find end of middle flags
+ if (*p == COM_BLANK) {
+ require_blank = true;
+ }
+ p++;
+ }
+ (void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ",");
+
+ while (*p && p[-1] != ':') { // find end of end flags
+ // Check whether we allow automatic ending of comments
+ if (*p == COM_AUTO_END) {
+ end_comment_pending = -1; // means we want to set it
+ }
+ p++;
+ }
+ size_t n = copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
+
+ if (end_comment_pending == -1) { // we can set it now
+ end_comment_pending = lead_end[n - 1];
+ }
+
+ // If the end of the comment is in the same line, don't use
+ // the comment leader.
+ if (dir == FORWARD) {
+ for (p = saved_line + lead_len; *p; p++) {
+ if (STRNCMP(p, lead_end, n) == 0) {
+ comment_end = p;
+ lead_len = 0;
+ break;
+ }
+ }
+ }
+
+ // Doing "o" on a start of comment inserts the middle leader.
+ if (lead_len > 0) {
+ if (current_flag == COM_START) {
+ lead_repl = lead_middle;
+ lead_repl_len = (int)STRLEN(lead_middle);
+ }
+
+ // If we have hit RETURN immediately after the start
+ // comment leader, then put a space after the middle
+ // comment leader on the next line.
+ if (!ascii_iswhite(saved_line[lead_len - 1])
+ && ((p_extra != NULL
+ && (int)curwin->w_cursor.col == lead_len)
+ || (p_extra == NULL
+ && saved_line[lead_len] == NUL)
+ || require_blank)) {
+ extra_space = true;
+ }
+ }
+ break;
+ }
+ if (*p == COM_END) {
+ // Doing "o" on the end of a comment does not insert leader.
+ // Remember where the end is, might want to use it to find the
+ // start (for C-comments).
+ if (dir == FORWARD) {
+ comment_end = skipwhite(saved_line);
+ lead_len = 0;
+ break;
+ }
+
+ // 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--;
+ }
+ for (lead_repl = p; lead_repl > curbuf->b_p_com
+ && lead_repl[-1] != ':'; lead_repl--) {
+ }
+ lead_repl_len = (int)(p - lead_repl);
+
+ // We can probably always add an extra space when doing "O" on
+ // the comment-end
+ extra_space = true;
+
+ // 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
+ }
+ }
+ if (end_comment_pending == -1) {
+ // Find last character in end-comment string
+ while (*p2 && *p2 != ',') {
+ p2++;
+ }
+ end_comment_pending = p2[-1];
+ }
+ break;
+ }
+ if (*p == COM_FIRST) {
+ // 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;
+ } else {
+ lead_repl = (char_u *)"";
+ lead_repl_len = 0;
+ }
+ break;
+ }
+ }
+ 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;
+ assert(bytes >= 0);
+ leader = xmalloc((size_t)bytes);
+ allocated = leader; // remember to free it later
+
+ STRLCPY(leader, saved_line, lead_len + 1);
+
+ // Replace leader with lead_repl, right or left adjusted
+ if (lead_repl != NULL) {
+ int c = 0;
+ int off = 0;
+
+ for (p = lead_flags; *p != NUL && *p != ':'; ) {
+ if (*p == COM_RIGHT || *p == COM_LEFT) {
+ c = *p++;
+ } else if (ascii_isdigit(*p) || *p == '-') {
+ off = getdigits_int(&p);
+ } else {
+ p++;
+ }
+ }
+ if (c == COM_RIGHT) { // right adjusted leader
+ // find last non-white in the leader to line up with
+ for (p = leader + lead_len - 1; p > leader
+ && ascii_iswhite(*p); p--) {
+ }
+ p++;
+
+ // Compute the length of the replaced characters in
+ // screen characters, not bytes.
+ {
+ int repl_size = vim_strnsize(lead_repl,
+ lead_repl_len);
+ int old_size = 0;
+ char_u *endp = p;
+ int l;
+
+ while (old_size < repl_size && p > leader) {
+ MB_PTR_BACK(leader, p);
+ old_size += ptr2cells(p);
+ }
+ l = lead_repl_len - (int)(endp - p);
+ if (l != 0) {
+ 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;
+ }
+
+ // blank-out any other chars from the old leader.
+ while (--p >= leader) {
+ int l = utf_head_off(leader, p);
+
+ if (l > 1) {
+ p -= l;
+ if (ptr2cells(p) > 1) {
+ p[1] = ' ';
+ l--;
+ }
+ memmove(p + 1, p + l + 1,
+ (size_t)((leader + lead_len) - (p + l + 1)));
+ lead_len -= l;
+ *p = ' ';
+ } else if (!ascii_iswhite(*p)) {
+ *p = ' ';
+ }
+ }
+ } else { // left adjusted leader
+ p = skipwhite(leader);
+ // Compute the length of the replaced characters in
+ // screen characters, not bytes. Move the part that is
+ // not to be overwritten.
+ {
+ int repl_size = vim_strnsize(lead_repl,
+ lead_repl_len);
+ int i;
+ int l;
+
+ 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;
+ }
+ }
+ if (i != lead_repl_len) {
+ memmove(p + lead_repl_len, p + i,
+ (size_t)(lead_len - i - (p - leader)));
+ lead_len += lead_repl_len - i;
+ }
+ }
+ memmove(p, lead_repl, (size_t)lead_repl_len);
+
+ // Replace any remaining non-white chars in the old
+ // leader by spaces. Keep Tabs, the indent must
+ // remain the same.
+ for (p += lead_repl_len; p < leader + lead_len; p++) {
+ if (!ascii_iswhite(*p)) {
+ // Don't put a space before a TAB.
+ if (p + 1 < leader + lead_len && p[1] == TAB) {
+ lead_len--;
+ memmove(p, p + 1, (size_t)(leader + lead_len - p));
+ } else {
+ int l = (*mb_ptr2len)(p);
+
+ if (l > 1) {
+ if (ptr2cells(p) > 1) {
+ // Replace a double-wide char with
+ // two spaces
+ l--;
+ *p++ = ' ';
+ }
+ memmove(p + 1, p + l, (size_t)(leader + lead_len - p));
+ lead_len -= l - 1;
+ }
+ *p = ' ';
+ }
+ }
+ }
+ *p = NUL;
+ }
+
+ // Recompute the indent, it may have changed.
+ if (curbuf->b_p_ai
+ || do_si
+ ) {
+ newindent = get_indent_str(leader, (int)curbuf->b_p_ts, false);
+ }
+
+ // Add the indent offset
+ if (newindent + off < 0) {
+ off = -newindent;
+ newindent = 0;
+ } else {
+ newindent += off;
+ }
+
+ // Correct trailing spaces for the shift, so that
+ // alignment remains equal.
+ while (off > 0 && lead_len > 0
+ && leader[lead_len - 1] == ' ') {
+ // Don't do it when there is a tab before the space
+ if (vim_strchr(skipwhite(leader), '\t') != NULL) {
+ break;
+ }
+ lead_len--;
+ off--;
+ }
+
+ // 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;
+ }
+ leader[lead_len] = NUL;
+ }
+
+ if (extra_space) {
+ leader[lead_len++] = ' ';
+ leader[lead_len] = NUL;
+ }
+
+ newcol = lead_len;
+
+ // if a new indent will be set below, remove the indent that
+ // is in the comment leader
+ if (newindent
+ || did_si
+ ) {
+ while (lead_len && ascii_iswhite(*leader)) {
+ lead_len--;
+ newcol--;
+ leader++;
+ }
+ }
+
+ did_si = can_si = false;
+ } else if (comment_end != NULL) {
+ // We have finished a comment, so we don't use the leader.
+ // If this was a C-comment and 'ai' or 'si' is set do a normal
+ // indent to align with the line containing the start of the
+ // comment.
+ if (comment_end[0] == '*' && comment_end[1] == '/'
+ && (curbuf->b_p_ai || do_si)) {
+ old_cursor = curwin->w_cursor;
+ curwin->w_cursor.col = (colnr_T)(comment_end - saved_line);
+ if ((pos = findmatch(NULL, NUL)) != NULL) {
+ curwin->w_cursor.lnum = pos->lnum;
+ newindent = get_indent();
+ }
+ curwin->w_cursor = old_cursor;
+ }
+ }
+ }
+
+ // (State == INSERT || State == REPLACE), only when dir == FORWARD
+ if (p_extra != NULL) {
+ *p_extra = saved_char; // restore char that NUL replaced
+
+ // When 'ai' set or "flags" has OPENLINE_DELSPACES, skip to the first
+ // non-blank.
+ //
+ // 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
+ }
+ if (curbuf->b_p_ai || (flags & OPENLINE_DELSPACES)) {
+ while ((*p_extra == ' ' || *p_extra == '\t')
+ && !utf_iscomposing(utf_ptr2char(p_extra + 1))) {
+ if (REPLACE_NORMAL(State)) {
+ replace_push(*p_extra);
+ }
+ p_extra++;
+ less_cols_off++;
+ }
+ }
+
+ // columns for marks adjusted for removed columns
+ less_cols = (int)(p_extra - saved_line);
+ }
+
+ if (p_extra == NULL) {
+ p_extra = (char_u *)""; // append empty line
+ }
+
+ // concatenate leader and p_extra, if there is a leader
+ if (lead_len > 0) {
+ if (flags & OPENLINE_COM_LIST && second_line_indent > 0) {
+ int i;
+ int padding = second_line_indent
+ - (newindent + (int)STRLEN(leader));
+
+ // Here whitespace is inserted after the comment char.
+ // Below, set_indent(newindent, SIN_INSERT) will insert the
+ // whitespace needed before the comment char.
+ for (i = 0; i < padding; i++) {
+ STRCAT(leader, " ");
+ less_cols--;
+ newcol++;
+ }
+ }
+ STRCAT(leader, p_extra);
+ p_extra = leader;
+ did_ai = true; // So truncating blanks works with comments
+ less_cols -= lead_len;
+ } else {
+ end_comment_pending = NUL; // turns out there was no leader
+ }
+
+ old_cursor = curwin->w_cursor;
+ if (dir == BACKWARD) {
+ curwin->w_cursor.lnum--;
+ }
+ if (!(State & VREPLACE_FLAG) || old_cursor.lnum >= orig_line_count) {
+ if (ml_append(curwin->w_cursor.lnum, p_extra, (colnr_T)0, false) == FAIL) {
+ goto theend;
+ }
+ // Postpone calling changed_lines(), because it would mess up folding
+ // with markers.
+ // Skip mark_adjust when adding a line after the last one, there can't
+ // be marks there. But still needed in diff mode.
+ if (curwin->w_cursor.lnum + 1 < curbuf->b_ml.ml_line_count
+ || curwin->w_p_diff) {
+ mark_adjust(curwin->w_cursor.lnum + 1, (linenr_T)MAXLNUM, 1L, 0L, false);
+ }
+ did_append = true;
+ } else {
+ // In VREPLACE mode we are starting to replace the next line.
+ curwin->w_cursor.lnum++;
+ if (curwin->w_cursor.lnum >= Insstart.lnum + vr_lines_changed) {
+ // In case we NL to a new line, BS to the previous one, and NL
+ // again, we don't want to save the new line for undo twice.
+ (void)u_save_cursor(); // errors are ignored!
+ vr_lines_changed++;
+ }
+ ml_replace(curwin->w_cursor.lnum, p_extra, true);
+ changed_bytes(curwin->w_cursor.lnum, 0);
+ curwin->w_cursor.lnum--;
+ did_append = false;
+ }
+
+ inhibit_delete_count++;
+ if (newindent
+ || did_si
+ ) {
+ curwin->w_cursor.lnum++;
+ if (did_si) {
+ int sw = get_sw_value(curbuf);
+
+ if (p_sr) {
+ newindent -= newindent % sw;
+ }
+ newindent += sw;
+ }
+ // Copy the indent
+ if (curbuf->b_p_ci) {
+ (void)copy_indent(newindent, saved_line);
+
+ // Set the 'preserveindent' option so that any further screwing
+ // with the line doesn't entirely destroy our efforts to preserve
+ // it. It gets restored at the function end.
+ curbuf->b_p_pi = true;
+ } else {
+ (void)set_indent(newindent, SIN_INSERT);
+ }
+ less_cols -= curwin->w_cursor.col;
+
+ ai_col = curwin->w_cursor.col;
+
+ // In REPLACE mode, for each character in the new indent, there must
+ // be a NUL on the replace stack, for when it is deleted with BS
+ if (REPLACE_NORMAL(State)) {
+ for (colnr_T n = 0; n < curwin->w_cursor.col; n++) {
+ replace_push(NUL);
+ }
+ }
+ newcol += curwin->w_cursor.col;
+ if (no_si) {
+ did_si = false;
+ }
+ }
+ inhibit_delete_count--;
+
+ // In REPLACE mode, for each character in the extra leader, there must be
+ // a NUL on the replace stack, for when it is deleted with BS.
+ if (REPLACE_NORMAL(State)) {
+ while (lead_len-- > 0) {
+ replace_push(NUL);
+ }
+ }
+
+ curwin->w_cursor = old_cursor;
+
+ if (dir == FORWARD) {
+ if (trunc_line || (State & INSERT)) {
+ // truncate current line at cursor
+ saved_line[curwin->w_cursor.col] = NUL;
+ // Remove trailing white space, unless OPENLINE_KEEPTRAIL used.
+ if (trunc_line && !(flags & OPENLINE_KEEPTRAIL)) {
+ truncate_spaces(saved_line);
+ }
+ ml_replace(curwin->w_cursor.lnum, saved_line, false);
+ saved_line = NULL;
+ if (did_append) {
+ changed_lines(curwin->w_cursor.lnum, curwin->w_cursor.col,
+ curwin->w_cursor.lnum + 1, 1L, true);
+ did_append = false;
+
+ // Move marks after the line break to the new line.
+ if (flags & OPENLINE_MARKFIX) {
+ mark_col_adjust(curwin->w_cursor.lnum,
+ curwin->w_cursor.col + less_cols_off,
+ 1L, (long)-less_cols, 0);
+ }
+ } else {
+ changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col);
+ }
+ }
+
+ // Put the cursor on the new line. Careful: the scrollup() above may
+ // have moved w_cursor, we must use old_cursor.
+ curwin->w_cursor.lnum = old_cursor.lnum + 1;
+ }
+ if (did_append) {
+ changed_lines(curwin->w_cursor.lnum, 0, curwin->w_cursor.lnum, 1L, true);
+ }
+
+ curwin->w_cursor.col = newcol;
+ curwin->w_cursor.coladd = 0;
+
+ // In VREPLACE mode, we are handling the replace stack ourselves, so stop
+ // fixthisline() from doing it (via change_indent()) by telling it we're in
+ // normal INSERT mode.
+ if (State & VREPLACE_FLAG) {
+ vreplace_mode = State; // So we know to put things right later
+ State = INSERT;
+ } else {
+ vreplace_mode = 0;
+ }
+ // May do lisp indenting.
+ if (!p_paste
+ && leader == NULL
+ && curbuf->b_p_lisp
+ && curbuf->b_p_ai) {
+ fixthisline(get_lisp_indent);
+ ai_col = (colnr_T)getwhitecols_curline();
+ }
+ // May do indenting after opening a new line.
+ if (!p_paste
+ && (curbuf->b_p_cin
+ || *curbuf->b_p_inde != NUL
+ )
+ && in_cinkeys(dir == FORWARD
+ ? KEY_OPEN_FORW
+ : KEY_OPEN_BACK, ' ', linewhite(curwin->w_cursor.lnum))) {
+ do_c_expr_indent();
+ ai_col = (colnr_T)getwhitecols_curline();
+ }
+ if (vreplace_mode != 0) {
+ State = vreplace_mode;
+ }
+
+ // Finally, VREPLACE gets the stuff on the new line, then puts back the
+ // original line, and inserts the new stuff char by char, pushing old stuff
+ // onto the replace stack (via ins_char()).
+ if (State & VREPLACE_FLAG) {
+ // Put new line in p_extra
+ p_extra = vim_strsave(get_cursor_line_ptr());
+
+ // Put back original line
+ ml_replace(curwin->w_cursor.lnum, next_line, false);
+
+ // Insert new stuff into line again
+ curwin->w_cursor.col = 0;
+ curwin->w_cursor.coladd = 0;
+ ins_bytes(p_extra); // will call changed_bytes()
+ xfree(p_extra);
+ next_line = NULL;
+ }
+
+ retval = true; // success!
+theend:
+ curbuf->b_p_pi = saved_pi;
+ xfree(saved_line);
+ xfree(next_line);
+ xfree(allocated);
+ return retval;
+} // NOLINT(readability/fn_size)
+
+/// Delete from cursor to end of line.
+/// Caller must have prepared for undo.
+/// If "fixpos" is true fix the cursor position when done.
+void truncate_line(int fixpos)
+{
+ char_u *newp;
+ linenr_T lnum = curwin->w_cursor.lnum;
+ colnr_T col = curwin->w_cursor.col;
+
+ if (col == 0) {
+ newp = vim_strsave((char_u *)"");
+ } else {
+ newp = vim_strnsave(ml_get(lnum), (size_t)col);
+ }
+ ml_replace(lnum, newp, false);
+
+ // mark the buffer as changed and prepare for displaying
+ changed_bytes(lnum, curwin->w_cursor.col);
+
+ // If "fixpos" is true we don't want to end up positioned at the NUL.
+ if (fixpos && curwin->w_cursor.col > 0) {
+ curwin->w_cursor.col--;
+ }
+}
+
+/// Delete "nlines" lines at the cursor.
+/// Saves the lines for undo first if "undo" is true.
+void del_lines(long nlines, int undo)
+{
+ long n;
+ linenr_T first = curwin->w_cursor.lnum;
+
+ if (nlines <= 0) {
+ return;
+ }
+
+ // save the deleted lines for undo
+ if (undo && u_savedel(first, nlines) == FAIL) {
+ return;
+ }
+
+ for (n = 0; n < nlines; ) {
+ if (curbuf->b_ml.ml_flags & ML_EMPTY) { // nothing to delete
+ break;
+ }
+
+ ml_delete(first, true);
+ n++;
+
+ // If we delete the last line in the file, stop
+ if (first > curbuf->b_ml.ml_line_count) {
+ break;
+ }
+ }
+
+ // Correct the cursor position before calling deleted_lines_mark(), it may
+ // trigger a callback to display the cursor.
+ curwin->w_cursor.col = 0;
+ check_cursor_lnum();
+
+ // adjust marks, mark the buffer as changed and prepare for displaying
+ deleted_lines_mark(first, n);
+}
diff --git a/src/nvim/change.h b/src/nvim/change.h
new file mode 100644
index 0000000000..e1a1bfba17
--- /dev/null
+++ b/src/nvim/change.h
@@ -0,0 +1,11 @@
+#ifndef NVIM_CHANGE_H
+#define NVIM_CHANGE_H
+
+#include "nvim/buffer_defs.h" // for buf_T
+#include "nvim/pos.h" // for linenr_T
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "change.h.generated.h"
+#endif
+
+#endif // NVIM_CHANGE_H
diff --git a/src/nvim/channel.c b/src/nvim/channel.c
index 8b8d27affd..104c79efd9 100644
--- a/src/nvim/channel.c
+++ b/src/nvim/channel.c
@@ -22,19 +22,10 @@ PMap(uint64_t) *channels = NULL;
/// 2 is reserved for stderr channel
static uint64_t next_chan_id = CHAN_STDERR+1;
-
-typedef struct {
- Channel *chan;
- Callback *callback;
- const char *type;
- // if reader is set, status is ignored.
- CallbackReader *reader;
- int status;
-} ChannelEvent;
-
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "channel.c.generated.h"
#endif
+
/// Teardown the module
void channel_teardown(void)
{
@@ -179,6 +170,7 @@ static Channel *channel_alloc(ChannelStreamType type)
}
chan->events = multiqueue_new_child(main_loop.events);
chan->refcount = 1;
+ chan->exit_status = -1;
chan->streamtype = type;
pmap_put(uint64_t)(channels, chan->id, chan);
return chan;
@@ -234,9 +226,10 @@ void callback_reader_free(CallbackReader *reader)
ga_clear(&reader->buffer);
}
-void callback_reader_start(CallbackReader *reader)
+void callback_reader_start(CallbackReader *reader, const char *type)
{
ga_init(&reader->buffer, sizeof(char *), 32);
+ reader->type = type;
}
static void free_channel_event(void **argv)
@@ -246,7 +239,7 @@ static void free_channel_event(void **argv)
rpc_free(chan);
}
- callback_reader_free(&chan->on_stdout);
+ callback_reader_free(&chan->on_data);
callback_reader_free(&chan->on_stderr);
callback_free(&chan->on_exit);
@@ -286,7 +279,7 @@ Channel *channel_job_start(char **argv, CallbackReader on_stdout,
assert(cwd == NULL || os_isdir_executable(cwd));
Channel *chan = channel_alloc(kChannelStreamProc);
- chan->on_stdout = on_stdout;
+ chan->on_data = on_stdout;
chan->on_stderr = on_stderr;
chan->on_exit = on_exit;
@@ -326,7 +319,7 @@ Channel *channel_job_start(char **argv, CallbackReader on_stdout,
has_out = true;
has_err = false;
} else {
- has_out = rpc || callback_reader_set(chan->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);
@@ -352,13 +345,13 @@ Channel *channel_job_start(char **argv, CallbackReader on_stdout,
rpc_start(chan);
} else {
if (has_out) {
- callback_reader_start(&chan->on_stdout);
- rstream_start(&proc->out, on_job_stdout, chan);
+ callback_reader_start(&chan->on_data, "stdout");
+ rstream_start(&proc->out, on_channel_data, chan);
}
}
if (has_err) {
- callback_reader_start(&chan->on_stderr);
+ callback_reader_start(&chan->on_stderr, "stderr");
rstream_init(&proc->err, 0);
rstream_start(&proc->err, on_job_stderr, chan);
}
@@ -402,9 +395,9 @@ uint64_t channel_connect(bool tcp, const char *address,
if (rpc) {
rpc_start(channel);
} else {
- channel->on_stdout = on_output;
- callback_reader_start(&channel->on_stdout);
- rstream_start(&channel->stream.socket, on_socket_output, channel);
+ channel->on_data = on_output;
+ callback_reader_start(&channel->on_data, "data");
+ rstream_start(&channel->stream.socket, on_channel_data, channel);
}
end:
@@ -452,9 +445,9 @@ uint64_t channel_from_stdio(bool rpc, CallbackReader on_output,
if (rpc) {
rpc_start(channel);
} else {
- channel->on_stdout = on_output;
- callback_reader_start(&channel->on_stdout);
- rstream_start(&channel->stream.stdio.in, on_stdio_input, channel);
+ channel->on_data = on_output;
+ callback_reader_start(&channel->on_data, "stdin");
+ rstream_start(&channel->stream.stdio.in, on_channel_data, channel);
}
return channel->id;
@@ -519,55 +512,22 @@ static inline list_T *buffer_to_tv_list(const char *const buf, const size_t len)
return l;
}
-// vimscript job callbacks must be executed on Nvim main loop
-static inline void process_channel_event(Channel *chan, Callback *callback,
- const char *type,
- CallbackReader *reader, int status)
-{
- assert(callback);
- ChannelEvent *event_data = xmalloc(sizeof(*event_data));
- event_data->reader = reader;
- event_data->status = status;
- channel_incref(chan); // Hold on ref to callback
- event_data->chan = chan;
- event_data->callback = callback;
- event_data->type = type;
-
- multiqueue_put(chan->events, on_channel_event, 1, event_data);
-}
-
-void on_job_stdout(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_stdout, "stdout");
+ 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)
{
Channel *chan = data;
- on_channel_output(stream, chan, buf, count, eof, &chan->on_stderr, "stderr");
-}
-
-static void on_socket_output(Stream *stream, RBuffer *buf, size_t count,
- void *data, bool eof)
-{
- Channel *chan = data;
- on_channel_output(stream, chan, buf, count, eof, &chan->on_stdout, "data");
-}
-
-static void on_stdio_input(Stream *stream, RBuffer *buf, size_t count,
- void *data, bool eof)
-{
- Channel *chan = data;
- on_channel_output(stream, chan, buf, count, eof, &chan->on_stdout, "stdin");
+ on_channel_output(stream, chan, buf, count, eof, &chan->on_stderr);
}
-/// @param type must have static lifetime
static void on_channel_output(Stream *stream, Channel *chan, RBuffer *buf,
- size_t count, bool eof, CallbackReader *reader,
- const char *type)
+ size_t count, bool eof, CallbackReader *reader)
{
// stub variable, to keep reading consistent with the order of events, only
// consider the count parameter.
@@ -575,57 +535,93 @@ static void on_channel_output(Stream *stream, Channel *chan, RBuffer *buf,
char *ptr = rbuffer_read_ptr(buf, &r);
if (eof) {
- if (reader->buffered) {
- if (reader->cb.type != kCallbackNone) {
- process_channel_event(chan, &reader->cb, type, reader, 0);
- } else if (reader->self) {
- if (tv_dict_find(reader->self, type, -1) == NULL) {
- list_T *data = buffer_to_tv_list(reader->buffer.ga_data,
- (size_t)reader->buffer.ga_len);
- tv_dict_add_list(reader->self, type, strlen(type), data);
- } else {
- // can't display error message now, defer it.
- channel_incref(chan);
- multiqueue_put(chan->events, on_buffered_error, 2, chan, type);
- }
- ga_clear(&reader->buffer);
- } else {
- abort();
- }
- } else if (reader->cb.type != kCallbackNone) {
- process_channel_event(chan, &reader->cb, type, reader, 0);
+ reader->eof = true;
+ } else {
+ if (chan->term) {
+ terminal_receive(chan->term, ptr, count);
+ terminal_flush_output(chan->term);
}
- return;
- }
- // The order here matters, the terminal must receive the data first because
- // process_channel_event will modify the read buffer(convert NULs into NLs)
- if (chan->term) {
- terminal_receive(chan->term, ptr, count);
- terminal_flush_output(chan->term);
+ rbuffer_consumed(buf, count);
+
+ if (callback_reader_set(*reader)) {
+ ga_concat_len(&reader->buffer, ptr, count);
+ }
}
- rbuffer_consumed(buf, count);
+ if (callback_reader_set(*reader)) {
+ schedule_channel_event(chan);
+ }
+}
- if (callback_reader_set(*reader) || reader->buffered) {
- // if buffer wasn't consumed, a pending callback is stalled. Aggregate the
- // received data and avoid a "burst" of multiple callbacks.
- bool buffer_set = reader->buffer.ga_len > 0;
- ga_concat_len(&reader->buffer, ptr, count);
- if (callback_reader_set(*reader) && !reader->buffered && !buffer_set) {
- process_channel_event(chan, &reader->cb, type, reader, 0);
+/// schedule the necessary callbacks to be invoked as a deferred event
+static void schedule_channel_event(Channel *chan)
+{
+ if (!chan->callback_scheduled) {
+ if (!chan->callback_busy) {
+ multiqueue_put(chan->events, on_channel_event, 1, chan);
+ channel_incref(chan);
}
+ chan->callback_scheduled = true;
}
}
-static void on_buffered_error(void **args)
+static void on_channel_event(void **args)
{
Channel *chan = (Channel *)args[0];
- const char *stream = (const char *)args[1];
- EMSG3(_(e_streamkey), stream, chan->id);
+
+ chan->callback_busy = true;
+ chan->callback_scheduled = false;
+
+ int exit_status = chan->exit_status;
+ channel_reader_callbacks(chan, &chan->on_data);
+ channel_reader_callbacks(chan, &chan->on_stderr);
+ if (exit_status > -1) {
+ channel_callback_call(chan, NULL);
+ chan->exit_status = -1;
+ }
+
+ chan->callback_busy = false;
+ if (chan->callback_scheduled) {
+ // further callback was deferred to avoid recursion.
+ multiqueue_put(chan->events, on_channel_event, 1, chan);
+ channel_incref(chan);
+ }
+
channel_decref(chan);
}
+void channel_reader_callbacks(Channel *chan, CallbackReader *reader)
+{
+ if (reader->buffered) {
+ if (reader->eof) {
+ if (reader->self) {
+ if (tv_dict_find(reader->self, reader->type, -1) == NULL) {
+ list_T *data = buffer_to_tv_list(reader->buffer.ga_data,
+ (size_t)reader->buffer.ga_len);
+ tv_dict_add_list(reader->self, reader->type, strlen(reader->type),
+ data);
+ } else {
+ EMSG3(_(e_streamkey), reader->type, chan->id);
+ }
+ } else {
+ channel_callback_call(chan, reader);
+ }
+ reader->eof = false;
+ }
+ } else {
+ bool is_eof = reader->eof;
+ if (reader->buffer.ga_len > 0) {
+ channel_callback_call(chan, reader);
+ }
+ // if the stream reached eof, invoke extra callback with no data
+ if (is_eof) {
+ channel_callback_call(chan, reader);
+ reader->eof = false;
+ }
+ }
+}
+
static void channel_process_exit_cb(Process *proc, int status, void *data)
{
Channel *chan = data;
@@ -637,45 +633,46 @@ static void channel_process_exit_cb(Process *proc, int status, void *data)
// If process did not exit, we only closed the handle of a detached process.
bool exited = (status >= 0);
- if (exited) {
- process_channel_event(chan, &chan->on_exit, "exit", NULL, status);
+ if (exited && chan->on_exit.type != kCallbackNone) {
+ schedule_channel_event(chan);
+ chan->exit_status = status;
}
channel_decref(chan);
}
-static void on_channel_event(void **args)
+static void channel_callback_call(Channel *chan, CallbackReader *reader)
{
- ChannelEvent *ev = (ChannelEvent *)args[0];
-
+ Callback *cb;
typval_T argv[4];
argv[0].v_type = VAR_NUMBER;
argv[0].v_lock = VAR_UNLOCKED;
- argv[0].vval.v_number = (varnumber_T)ev->chan->id;
+ argv[0].vval.v_number = (varnumber_T)chan->id;
- if (ev->reader) {
+ if (reader) {
argv[1].v_type = VAR_LIST;
argv[1].v_lock = VAR_UNLOCKED;
- argv[1].vval.v_list = buffer_to_tv_list(ev->reader->buffer.ga_data,
- (size_t)ev->reader->buffer.ga_len);
+ argv[1].vval.v_list = buffer_to_tv_list(reader->buffer.ga_data,
+ (size_t)reader->buffer.ga_len);
tv_list_ref(argv[1].vval.v_list);
- ga_clear(&ev->reader->buffer);
+ ga_clear(&reader->buffer);
+ cb = &reader->cb;
+ argv[2].vval.v_string = (char_u *)reader->type;
} else {
argv[1].v_type = VAR_NUMBER;
argv[1].v_lock = VAR_UNLOCKED;
- argv[1].vval.v_number = ev->status;
+ argv[1].vval.v_number = chan->exit_status;
+ cb = &chan->on_exit;
+ argv[2].vval.v_string = (char_u *)"exit";
}
argv[2].v_type = VAR_STRING;
argv[2].v_lock = VAR_UNLOCKED;
- argv[2].vval.v_string = (uint8_t *)ev->type;
typval_T rettv = TV_INITIAL_VALUE;
- callback_call(ev->callback, 3, argv, &rettv);
+ callback_call(cb, 3, argv, &rettv);
tv_clear(&rettv);
- channel_decref(ev->chan);
- xfree(ev);
}
@@ -765,6 +762,14 @@ static void set_info_event(void **argv)
channel_decref(chan);
}
+bool channel_job_running(uint64_t id)
+{
+ Channel *chan = find_channel(id);
+ return (chan
+ && chan->streamtype == kChannelStreamProc
+ && !process_is_stopped(&chan->stream.proc));
+}
+
Dictionary channel_info(uint64_t id)
{
Channel *chan = find_channel(id);
diff --git a/src/nvim/channel.h b/src/nvim/channel.h
index b856d197f1..c733e276be 100644
--- a/src/nvim/channel.h
+++ b/src/nvim/channel.h
@@ -42,13 +42,16 @@ typedef struct {
Callback cb;
dict_T *self;
garray_T buffer;
+ bool eof;
bool buffered;
+ const char *type;
} CallbackReader;
#define CALLBACK_READER_INIT ((CallbackReader){ .cb = CALLBACK_NONE, \
.self = NULL, \
.buffer = GA_EMPTY_INIT_VALUE, \
- .buffered = false })
+ .buffered = false, \
+ .type = NULL })
static inline bool callback_reader_set(CallbackReader reader)
{
return reader.cb.type != kCallbackNone || reader.self;
@@ -73,9 +76,13 @@ struct Channel {
RpcState rpc;
Terminal *term;
- CallbackReader on_stdout;
+ CallbackReader on_data;
CallbackReader on_stderr;
Callback on_exit;
+ int exit_status;
+
+ bool callback_busy;
+ bool callback_scheduled;
};
EXTERN PMap(uint64_t) *channels;
diff --git a/src/nvim/context.c b/src/nvim/context.c
new file mode 100644
index 0000000000..b2a2fd3fd9
--- /dev/null
+++ b/src/nvim/context.c
@@ -0,0 +1,383 @@
+// 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
+
+// Context: snapshot of the entire editor state as one big object/map
+
+#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"
+#endif
+
+int kCtxAll = (kCtxRegs | kCtxJumps | kCtxBuflist | kCtxGVars | kCtxSFuncs
+ | kCtxFuncs);
+
+static ContextVec ctx_stack = KV_INITIAL_VALUE;
+
+/// Clears and frees the context stack
+void ctx_free_all(void)
+{
+ for (size_t i = 0; i < kv_size(ctx_stack); i++) {
+ ctx_free(&kv_A(ctx_stack, i));
+ }
+ kv_destroy(ctx_stack);
+}
+
+/// Returns the size of the context stack.
+size_t ctx_size(void)
+{
+ return kv_size(ctx_stack);
+}
+
+/// Returns pointer to Context object with given zero-based index from the top
+/// of context stack or NULL if index is out of bounds.
+Context *ctx_get(size_t index)
+{
+ if (index < kv_size(ctx_stack)) {
+ return &kv_Z(ctx_stack, index);
+ }
+ return NULL;
+}
+
+/// Free resources used by Context object.
+///
+/// param[in] ctx pointer to Context object to free.
+void ctx_free(Context *ctx)
+ FUNC_ATTR_NONNULL_ALL
+{
+ if (ctx->regs.data) {
+ msgpack_sbuffer_destroy(&ctx->regs);
+ }
+ if (ctx->jumps.data) {
+ msgpack_sbuffer_destroy(&ctx->jumps);
+ }
+ if (ctx->buflist.data) {
+ msgpack_sbuffer_destroy(&ctx->buflist);
+ }
+ if (ctx->gvars.data) {
+ msgpack_sbuffer_destroy(&ctx->gvars);
+ }
+ if (ctx->funcs.items) {
+ api_free_array(ctx->funcs);
+ }
+}
+
+/// Saves the editor state to a context.
+///
+/// If "context" is NULL, pushes context on context stack.
+/// Use "flags" to select particular types of context.
+///
+/// @param ctx Save to this context, or push on context stack if NULL.
+/// @param flags Flags, see ContextTypeFlags enum.
+void ctx_save(Context *ctx, const int flags)
+{
+ if (ctx == NULL) {
+ kv_push(ctx_stack, CONTEXT_INIT);
+ ctx = &kv_last(ctx_stack);
+ }
+
+ if (flags & kCtxRegs) {
+ ctx_save_regs(ctx);
+ }
+
+ if (flags & kCtxJumps) {
+ ctx_save_jumps(ctx);
+ }
+
+ if (flags & kCtxBuflist) {
+ ctx_save_buflist(ctx);
+ }
+
+ if (flags & kCtxGVars) {
+ ctx_save_gvars(ctx);
+ }
+
+ if (flags & kCtxFuncs) {
+ ctx_save_funcs(ctx, false);
+ } else if (flags & kCtxSFuncs) {
+ ctx_save_funcs(ctx, true);
+ }
+}
+
+/// Restores the editor state from a context.
+///
+/// If "context" is NULL, pops context from context stack.
+/// Use "flags" to select particular types of context.
+///
+/// @param ctx Restore from this context. Pop from context stack if NULL.
+/// @param flags Flags, see ContextTypeFlags enum.
+///
+/// @return true on success, false otherwise (i.e.: empty context stack).
+bool ctx_restore(Context *ctx, const int flags)
+{
+ bool free_ctx = false;
+ if (ctx == NULL) {
+ if (ctx_stack.size == 0) {
+ return false;
+ }
+ ctx = &kv_pop(ctx_stack);
+ free_ctx = true;
+ }
+
+ char_u *op_shada;
+ get_option_value((char_u *)"shada", NULL, &op_shada, OPT_GLOBAL);
+ set_option_value("shada", 0L, "!,'100,%", OPT_GLOBAL);
+
+ if (flags & kCtxRegs) {
+ ctx_restore_regs(ctx);
+ }
+
+ if (flags & kCtxJumps) {
+ ctx_restore_jumps(ctx);
+ }
+
+ if (flags & kCtxBuflist) {
+ ctx_restore_buflist(ctx);
+ }
+
+ if (flags & kCtxGVars) {
+ ctx_restore_gvars(ctx);
+ }
+
+ if (flags & kCtxFuncs) {
+ ctx_restore_funcs(ctx);
+ }
+
+ if (free_ctx) {
+ ctx_free(ctx);
+ }
+
+ set_option_value("shada", 0L, (char *)op_shada, OPT_GLOBAL);
+ xfree(op_shada);
+
+ return true;
+}
+
+/// Saves the global registers to a context.
+///
+/// @param ctx Save to this context.
+static inline void ctx_save_regs(Context *ctx)
+ FUNC_ATTR_NONNULL_ALL
+{
+ msgpack_sbuffer_init(&ctx->regs);
+ shada_encode_regs(&ctx->regs);
+}
+
+/// Restores the global registers from a context.
+///
+/// @param ctx Restore from this context.
+static inline void ctx_restore_regs(Context *ctx)
+ FUNC_ATTR_NONNULL_ALL
+{
+ shada_read_sbuf(&ctx->regs, kShaDaWantInfo | kShaDaForceit);
+}
+
+/// Saves the jumplist to a context.
+///
+/// @param ctx Save to this context.
+static inline void ctx_save_jumps(Context *ctx)
+ FUNC_ATTR_NONNULL_ALL
+{
+ msgpack_sbuffer_init(&ctx->jumps);
+ shada_encode_jumps(&ctx->jumps);
+}
+
+/// Restores the jumplist from a context.
+///
+/// @param ctx Restore from this context.
+static inline void ctx_restore_jumps(Context *ctx)
+ FUNC_ATTR_NONNULL_ALL
+{
+ shada_read_sbuf(&ctx->jumps, kShaDaWantInfo | kShaDaForceit);
+}
+
+/// Saves the buffer list to a context.
+///
+/// @param ctx Save to this context.
+static inline void ctx_save_buflist(Context *ctx)
+ FUNC_ATTR_NONNULL_ALL
+{
+ msgpack_sbuffer_init(&ctx->buflist);
+ shada_encode_buflist(&ctx->buflist);
+}
+
+/// Restores the buffer list from a context.
+///
+/// @param ctx Restore from this context.
+static inline void ctx_restore_buflist(Context *ctx)
+ FUNC_ATTR_NONNULL_ALL
+{
+ shada_read_sbuf(&ctx->buflist, kShaDaWantInfo | kShaDaForceit);
+}
+
+/// Saves global variables to a context.
+///
+/// @param ctx Save to this context.
+static inline void ctx_save_gvars(Context *ctx)
+ FUNC_ATTR_NONNULL_ALL
+{
+ msgpack_sbuffer_init(&ctx->gvars);
+ shada_encode_gvars(&ctx->gvars);
+}
+
+/// Restores global variables from a context.
+///
+/// @param ctx Restore from this context.
+static inline void ctx_restore_gvars(Context *ctx)
+ FUNC_ATTR_NONNULL_ALL
+{
+ shada_read_sbuf(&ctx->gvars, kShaDaWantInfo | kShaDaForceit);
+}
+
+/// Saves functions to a context.
+///
+/// @param ctx Save to this context.
+/// @param scriptonly Save script-local (s:) functions only.
+static inline void ctx_save_funcs(Context *ctx, bool scriptonly)
+ FUNC_ATTR_NONNULL_ALL
+{
+ ctx->funcs = (Array)ARRAY_DICT_INIT;
+ Error err = ERROR_INIT;
+
+ HASHTAB_ITER(&func_hashtab, hi, {
+ const char_u *const name = hi->hi_key;
+ bool islambda = (STRNCMP(name, "<lambda>", 8) == 0);
+ bool isscript = (name[0] == K_SPECIAL);
+
+ if (!islambda && (!scriptonly || isscript)) {
+ size_t cmd_len = sizeof("func! ") + STRLEN(name);
+ char *cmd = xmalloc(cmd_len);
+ snprintf(cmd, cmd_len, "func! %s", name);
+ String func_body = nvim_command_output(cstr_as_string(cmd), &err);
+ xfree(cmd);
+ if (!ERROR_SET(&err)) {
+ ADD(ctx->funcs, STRING_OBJ(func_body));
+ }
+ api_clear_error(&err);
+ }
+ });
+}
+
+/// Restores functions from a context.
+///
+/// @param ctx Restore from this context.
+static inline void ctx_restore_funcs(Context *ctx)
+ FUNC_ATTR_NONNULL_ALL
+{
+ for (size_t i = 0; i < ctx->funcs.size; i++) {
+ do_cmdline_cmd(ctx->funcs.items[i].data.string.data);
+ }
+}
+
+/// Convert msgpack_sbuffer to readfile()-style array.
+///
+/// @param[in] sbuf msgpack_sbuffer to convert.
+///
+/// @return readfile()-style array representation of "sbuf".
+static inline Array sbuf_to_array(msgpack_sbuffer sbuf)
+{
+ list_T *const list = tv_list_alloc(kListLenMayKnow);
+ tv_list_append_string(list, "", 0);
+ if (sbuf.size > 0) {
+ encode_list_write(list, sbuf.data, sbuf.size);
+ }
+
+ typval_T list_tv = (typval_T) {
+ .v_lock = VAR_UNLOCKED,
+ .v_type = VAR_LIST,
+ .vval.v_list = list
+ };
+
+ Array array = vim_to_object(&list_tv).data.array;
+ tv_clear(&list_tv);
+ return array;
+}
+
+/// Convert readfile()-style array to msgpack_sbuffer.
+///
+/// @param[in] array readfile()-style array to convert.
+///
+/// @return msgpack_sbuffer with conversion result.
+static inline msgpack_sbuffer array_to_sbuf(Array array)
+{
+ msgpack_sbuffer sbuf;
+ msgpack_sbuffer_init(&sbuf);
+
+ typval_T list_tv;
+ Error err = ERROR_INIT;
+ object_to_vim(ARRAY_OBJ(array), &list_tv, &err);
+
+ if (!encode_vim_list_to_buf(list_tv.vval.v_list, &sbuf.size, &sbuf.data)) {
+ EMSG(_("E474: Failed to convert list to msgpack string buffer"));
+ }
+ sbuf.alloc = sbuf.size;
+
+ tv_clear(&list_tv);
+ api_clear_error(&err);
+ return sbuf;
+}
+
+/// Converts Context to Dictionary representation.
+///
+/// @param[in] ctx Context to convert.
+///
+/// @return Dictionary representing "ctx".
+Dictionary ctx_to_dict(Context *ctx)
+ FUNC_ATTR_NONNULL_ALL
+{
+ assert(ctx != NULL);
+
+ Dictionary rv = ARRAY_DICT_INIT;
+
+ PUT(rv, "regs", ARRAY_OBJ(sbuf_to_array(ctx->regs)));
+ PUT(rv, "jumps", ARRAY_OBJ(sbuf_to_array(ctx->jumps)));
+ PUT(rv, "buflist", ARRAY_OBJ(sbuf_to_array(ctx->buflist)));
+ PUT(rv, "gvars", ARRAY_OBJ(sbuf_to_array(ctx->gvars)));
+ PUT(rv, "funcs", ARRAY_OBJ(copy_array(ctx->funcs)));
+
+ return rv;
+}
+
+/// Converts Dictionary representation of Context back to Context object.
+///
+/// @param[in] dict Context Dictionary representation.
+/// @param[out] ctx Context object to store conversion result into.
+///
+/// @return types of included context items.
+int ctx_from_dict(Dictionary dict, Context *ctx)
+ FUNC_ATTR_NONNULL_ALL
+{
+ assert(ctx != NULL);
+
+ int types = 0;
+ for (size_t i = 0; i < dict.size; i++) {
+ KeyValuePair item = dict.items[i];
+ if (item.value.type != kObjectTypeArray) {
+ continue;
+ }
+ if (strequal(item.key.data, "regs")) {
+ types |= kCtxRegs;
+ ctx->regs = array_to_sbuf(item.value.data.array);
+ } else if (strequal(item.key.data, "jumps")) {
+ types |= kCtxJumps;
+ ctx->jumps = array_to_sbuf(item.value.data.array);
+ } else if (strequal(item.key.data, "buflist")) {
+ types |= kCtxBuflist;
+ ctx->buflist = array_to_sbuf(item.value.data.array);
+ } else if (strequal(item.key.data, "gvars")) {
+ types |= kCtxGVars;
+ ctx->gvars = array_to_sbuf(item.value.data.array);
+ } else if (strequal(item.key.data, "funcs")) {
+ types |= kCtxFuncs;
+ ctx->funcs = copy_object(item.value).data.array;
+ }
+ }
+
+ return types;
+}
diff --git a/src/nvim/context.h b/src/nvim/context.h
new file mode 100644
index 0000000000..328e12c6a6
--- /dev/null
+++ b/src/nvim/context.h
@@ -0,0 +1,46 @@
+#ifndef NVIM_CONTEXT_H
+#define NVIM_CONTEXT_H
+
+#include <msgpack.h>
+#include "nvim/api/private/defs.h"
+#include "nvim/lib/kvec.h"
+
+typedef struct {
+ msgpack_sbuffer regs; ///< Registers.
+ msgpack_sbuffer jumps; ///< Jumplist.
+ msgpack_sbuffer buflist; ///< Buffer list.
+ msgpack_sbuffer gvars; ///< Global variables.
+ Array funcs; ///< Functions.
+} Context;
+typedef kvec_t(Context) ContextVec;
+
+#define MSGPACK_SBUFFER_INIT (msgpack_sbuffer) { \
+ .size = 0, \
+ .data = NULL, \
+ .alloc = 0, \
+}
+
+#define CONTEXT_INIT (Context) { \
+ .regs = MSGPACK_SBUFFER_INIT, \
+ .jumps = MSGPACK_SBUFFER_INIT, \
+ .buflist = MSGPACK_SBUFFER_INIT, \
+ .gvars = MSGPACK_SBUFFER_INIT, \
+ .funcs = ARRAY_DICT_INIT, \
+}
+
+typedef enum {
+ kCtxRegs = 1, ///< Registers
+ kCtxJumps = 2, ///< Jumplist
+ kCtxBuflist = 4, ///< Buffer list
+ kCtxGVars = 8, ///< Global variables
+ kCtxSFuncs = 16, ///< Script functions
+ kCtxFuncs = 32, ///< Functions
+} ContextTypeFlags;
+
+extern int kCtxAll;
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "context.h.generated.h"
+#endif
+
+#endif // NVIM_CONTEXT_H
diff --git a/src/nvim/cursor.c b/src/nvim/cursor.c
index bc14761877..f2b3cfe690 100644
--- a/src/nvim/cursor.c
+++ b/src/nvim/cursor.c
@@ -5,6 +5,7 @@
#include <inttypes.h>
#include "nvim/assert.h"
+#include "nvim/change.h"
#include "nvim/cursor.h"
#include "nvim/charset.h"
#include "nvim/fold.h"
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index f720e702a4..7328b88a40 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -18,6 +18,7 @@
#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/eval.h"
@@ -951,7 +952,7 @@ static int check_external_diff(diffio_T *diffio)
TriState ok = kFalse;
for (;;) {
ok = kFalse;
- FILE *fd = mch_fopen((char *)diffio->dio_orig.din_fname, "w");
+ FILE *fd = os_fopen((char *)diffio->dio_orig.din_fname, "w");
if (fd == NULL) {
io_error = true;
@@ -960,7 +961,7 @@ static int check_external_diff(diffio_T *diffio)
io_error = true;
}
fclose(fd);
- fd = mch_fopen((char *)diffio->dio_new.din_fname, "w");
+ fd = os_fopen((char *)diffio->dio_new.din_fname, "w");
if (fd == NULL) {
io_error = true;
@@ -971,7 +972,7 @@ static int check_external_diff(diffio_T *diffio)
fclose(fd);
fd = NULL;
if (diff_file(diffio) == OK) {
- fd = mch_fopen((char *)diffio->dio_diff.dout_fname, "r");
+ fd = os_fopen((char *)diffio->dio_diff.dout_fname, "r");
}
if (fd == NULL) {
@@ -1505,7 +1506,7 @@ static void diff_read(int idx_orig, int idx_new, diffout_T *dout)
if (dout->dout_fname == NULL) {
diffstyle = DIFF_UNIFIED;
} else {
- fd = mch_fopen((char *)dout->dout_fname, "r");
+ fd = os_fopen((char *)dout->dout_fname, "r");
if (fd == NULL) {
EMSG(_("E98: Cannot read diff output"));
return;
@@ -2190,7 +2191,7 @@ int diffopt_changed(void)
}
diff_flags = diff_flags_new;
- diff_context = diff_context_new;
+ diff_context = diff_context_new == 0 ? 1 : diff_context_new;
diff_foldcolumn = diff_foldcolumn_new;
diff_algorithm = diff_algorithm_new;
diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c
index 3329290634..d47ad3f1c0 100644
--- a/src/nvim/digraph.c
+++ b/src/nvim/digraph.c
@@ -18,6 +18,7 @@
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
#include "nvim/getchar.h"
+#include "nvim/misc1.h"
#include "nvim/mbyte.h"
#include "nvim/message.h"
#include "nvim/memory.h"
@@ -1496,8 +1497,8 @@ int get_digraph(int cmdline)
}
if (cmdline) {
- if ((char2cells(c) == 1) && (cmdline_star == 0)) {
- putcmdline(c, TRUE);
+ if ((char2cells(c) == 1) && c < 128 && (cmdline_star == 0)) {
+ putcmdline((char)c, true);
}
} else {
add_to_showcmd(c);
@@ -1663,13 +1664,13 @@ void listdigraphs(void)
printdigraph(&tmp);
}
dp++;
- os_breakcheck();
+ fast_breakcheck();
}
dp = (digr_T *)user_digraphs.ga_data;
for (int i = 0; i < user_digraphs.ga_len && !got_int; ++i) {
printdigraph(dp);
- os_breakcheck();
+ fast_breakcheck();
dp++;
}
}
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 9af003f140..2ac429cf9e 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -14,6 +14,7 @@
#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"
@@ -64,6 +65,7 @@
#define CTRL_X_WANT_IDENT 0x100
+#define CTRL_X_NORMAL 0 ///< CTRL-N CTRL-P completion, default
#define CTRL_X_NOT_DEFINED_YET 1
#define CTRL_X_SCROLL 2
#define CTRL_X_WHOLE_LINE 3
@@ -78,11 +80,12 @@
#define CTRL_X_FUNCTION 12
#define CTRL_X_OMNI 13
#define CTRL_X_SPELL 14
-#define CTRL_X_LOCAL_MSG 15 /* only used in "ctrl_x_msgs" */
+#define CTRL_X_LOCAL_MSG 15 ///< only used in "ctrl_x_msgs"
#define CTRL_X_EVAL 16 ///< for builtin function complete()
#define CTRL_X_MSG(i) ctrl_x_msgs[(i) & ~CTRL_X_WANT_IDENT]
-#define CTRL_X_MODE_LINE_OR_EVAL(m) (m == CTRL_X_WHOLE_LINE || m == CTRL_X_EVAL)
+#define CTRL_X_MODE_LINE_OR_EVAL(m) \
+ ((m) == CTRL_X_WHOLE_LINE || (m) == CTRL_X_EVAL)
// Message for CTRL-X mode, index is ctrl_x_mode.
static char *ctrl_x_msgs[] =
@@ -192,6 +195,9 @@ static int compl_restarting = FALSE; /* don't insert match */
* FALSE the word to be completed must be located. */
static int compl_started = FALSE;
+// Which Ctrl-X mode are we in?
+static int ctrl_x_mode = CTRL_X_NORMAL;
+
static int compl_matches = 0;
static char_u *compl_pattern = NULL;
static int compl_direction = FORWARD;
@@ -276,7 +282,7 @@ static int ins_need_undo; /* call u_save() before inserting a
static bool did_add_space = false; // auto_format() added an extra space
// under the cursor
static TriState dont_sync_undo = kFalse; // CTRL-G U prevents syncing undo
- // for the next left/right cursor
+ // for the next left/right cursor key
static linenr_T o_lnum = 0;
@@ -509,7 +515,7 @@ static int insert_check(VimState *state)
// If typed something may trigger CursorHoldI again.
if (s->c != K_EVENT
// but not in CTRL-X mode, a script can't restore the state
- && ctrl_x_mode == 0) {
+ && ctrl_x_mode == CTRL_X_NORMAL) {
did_cursorhold = false;
}
@@ -518,7 +524,10 @@ static int insert_check(VimState *state)
s->inserted_space = false;
}
- if (can_cindent && cindent_on() && ctrl_x_mode == 0 && !compl_started) {
+ if (can_cindent
+ && cindent_on()
+ && ctrl_x_mode == CTRL_X_NORMAL
+ && !compl_started) {
insert_do_cindent(s);
}
@@ -641,7 +650,9 @@ static int insert_execute(VimState *state, int key)
s->c = key;
// Don't want K_EVENT with cursorhold for the second key, e.g., after CTRL-V.
- did_cursorhold = true;
+ if (key != K_EVENT) {
+ did_cursorhold = true;
+ }
if (p_hkmap && KeyTyped) {
s->c = hkmap(s->c); // Hebrew mode mapping
@@ -1037,7 +1048,7 @@ check_pum:
if (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL)) {
ins_s_left();
} else {
- ins_left(dont_sync_undo == kFalse);
+ ins_left();
}
break;
@@ -1050,7 +1061,7 @@ check_pum:
if (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL)) {
ins_s_right();
} else {
- ins_right(dont_sync_undo == kFalse);
+ ins_right();
}
break;
@@ -1204,7 +1215,8 @@ check_pum:
// if 'complete' is empty then plain ^P is no longer special,
// but it is under other ^X modes
if (*curbuf->b_p_cpt == NUL
- && ctrl_x_mode != 0
+ && (ctrl_x_mode == CTRL_X_NORMAL
+ || ctrl_x_mode == CTRL_X_WHOLE_LINE)
&& !(compl_cont_status & CONT_LOCAL)) {
goto normalchar;
}
@@ -1921,6 +1933,19 @@ static void ins_ctrl_x(void)
}
}
+// Whether other than default completion has been selected.
+bool ctrl_x_mode_not_default(void)
+{
+ return ctrl_x_mode != CTRL_X_NORMAL;
+}
+
+// Whether CTRL-X was typed without a following character.
+bool ctrl_x_mode_not_defined_yet(void)
+{
+ return ctrl_x_mode == CTRL_X_NOT_DEFINED_YET;
+}
+
+
/// Check that the "dict" or "tsr" option can be used.
///
/// @param dict_opt check "dict" when true, "tsr" when false.
@@ -1929,7 +1954,7 @@ static bool check_compl_option(bool dict_opt)
if (dict_opt
? (*curbuf->b_p_dict == NUL && *p_dict == NUL && !curwin->w_p_spell)
: (*curbuf->b_p_tsr == NUL && *p_tsr == NUL)) {
- ctrl_x_mode = 0;
+ ctrl_x_mode = CTRL_X_NORMAL;
edit_submode = NULL;
msg_attr((dict_opt
? _("'dictionary' option is empty")
@@ -2460,7 +2485,7 @@ void completeopt_was_set(void)
void set_completion(colnr_T startcol, list_T *list)
{
// If already doing completions stop it.
- if (ctrl_x_mode != 0) {
+ if (ctrl_x_mode != CTRL_X_NORMAL) {
ins_compl_prep(' ');
}
ins_compl_clear();
@@ -2556,10 +2581,35 @@ static bool pum_enough_matches(void)
return i >= 2;
}
-/*
- * Show the popup menu for the list of matches.
- * Also adjusts "compl_shown_match" to an entry that is actually displayed.
- */
+static void trigger_complete_changed_event(int cur)
+{
+ static bool recursive = false;
+
+ if (recursive) {
+ return;
+ }
+
+ dict_T *v_event = get_vim_var_dict(VV_EVENT);
+ if (cur < 0) {
+ tv_dict_add_dict(v_event, S_LEN("completed_item"), tv_dict_alloc());
+ } else {
+ dict_T *item = ins_compl_dict_alloc(compl_curr_match);
+ tv_dict_add_dict(v_event, S_LEN("completed_item"), item);
+ }
+ pum_set_event_info(v_event);
+ tv_dict_set_keys_readonly(v_event);
+
+ recursive = true;
+ textlock++;
+ apply_autocmds(EVENT_COMPLETECHANGED, NULL, NULL, false, curbuf);
+ textlock--;
+ recursive = false;
+
+ tv_dict_clear(v_event);
+}
+
+/// Show the popup menu for the list of matches.
+/// Also adjusts "compl_shown_match" to an entry that is actually displayed.
void ins_compl_show_pum(void)
{
compl_T *compl;
@@ -2691,22 +2741,9 @@ void ins_compl_show_pum(void)
pum_display(compl_match_array, compl_match_arraysize, cur, array_changed, 0);
curwin->w_cursor.col = col;
- if (!has_event(EVENT_COMPLETECHANGED)) {
- return;
- }
- dict_T *dict = get_vim_var_dict(VV_EVENT);
- if (cur < 0) {
- tv_dict_add_dict(dict, S_LEN("completed_item"), tv_dict_alloc());
- } else {
- dict_T *item = ins_compl_dict_alloc(compl_curr_match);
- tv_dict_add_dict(dict, S_LEN("completed_item"), item);
+ if (has_event(EVENT_COMPLETECHANGED)) {
+ trigger_complete_changed_event(cur);
}
- pum_set_boundings(dict);
- tv_dict_set_keys_readonly(dict);
- textlock++;
- apply_autocmds(EVENT_COMPLETECHANGED, NULL, NULL, false, curbuf);
- textlock--;
- tv_dict_clear(dict);
}
#define DICT_FIRST (1) /* use just first element in "dict" */
@@ -2820,7 +2857,7 @@ static void ins_compl_files(int count, char_u **files, int thesaurus, int flags,
int add_r;
for (i = 0; i < count && !got_int && !compl_interrupted; i++) {
- fp = mch_fopen((char *)files[i], "r"); /* open dictionary file */
+ fp = os_fopen((char *)files[i], "r"); // open dictionary file
if (flags != DICT_EXACT) {
vim_snprintf((char *)IObuff, IOSIZE,
_("Scanning dictionary: %s"), (char *)files[i]);
@@ -3086,6 +3123,7 @@ void get_complete_info(list_T *what_list, dict_T *retdict)
? compl_curr_match->cp_number - 1 : -1);
}
+ (void)ret;
// TODO(vim):
// if (ret == OK && (what_flag & CI_WHAT_INSERTED))
}
@@ -3331,7 +3369,7 @@ static bool ins_compl_prep(int c)
/* Set "compl_get_longest" when finding the first matches. */
if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET
- || (ctrl_x_mode == 0 && !compl_started)) {
+ || (ctrl_x_mode == CTRL_X_NORMAL && !compl_started)) {
compl_get_longest = (strstr((char *)p_cot, "longest") != NULL);
compl_used_match = TRUE;
@@ -3426,18 +3464,19 @@ static bool ins_compl_prep(int c)
else
compl_cont_mode = CTRL_X_NOT_DEFINED_YET;
}
- ctrl_x_mode = 0;
+ ctrl_x_mode = CTRL_X_NORMAL;
edit_submode = NULL;
showmode();
break;
}
- } else if (ctrl_x_mode != 0) {
- /* We're already in CTRL-X mode, do we stay in it? */
+ } else if (ctrl_x_mode != CTRL_X_NORMAL) {
+ // We're already in CTRL-X mode, do we stay in it?
if (!vim_is_ctrl_x_key(c)) {
- if (ctrl_x_mode == CTRL_X_SCROLL)
- ctrl_x_mode = 0;
- else
+ if (ctrl_x_mode == CTRL_X_SCROLL) {
+ ctrl_x_mode = CTRL_X_NORMAL;
+ } else {
ctrl_x_mode = CTRL_X_FINISHED;
+ }
edit_submode = NULL;
}
showmode();
@@ -3448,7 +3487,10 @@ static bool ins_compl_prep(int c)
* 'Pattern not found') until another key is hit, then go back to
* showing what mode we are in. */
showmode();
- if ((ctrl_x_mode == 0 && c != Ctrl_N && c != Ctrl_P && c != Ctrl_R
+ if ((ctrl_x_mode == CTRL_X_NORMAL
+ && c != Ctrl_N
+ && c != Ctrl_P
+ && c != Ctrl_R
&& !ins_compl_pum_key(c))
|| ctrl_x_mode == CTRL_X_FINISHED) {
/* Get here when we have finished typing a sequence of ^N and
@@ -3526,8 +3568,8 @@ static bool ins_compl_prep(int c)
if (!shortmess(SHM_COMPLETIONMENU)) {
msg_clr_cmdline(); // necessary for "noshowmode"
}
- ctrl_x_mode = 0;
- compl_enter_selects = FALSE;
+ ctrl_x_mode = CTRL_X_NORMAL;
+ compl_enter_selects = false;
if (edit_submode != NULL) {
edit_submode = NULL;
showmode();
@@ -3654,14 +3696,19 @@ expand_by_function (
return;
// Call 'completefunc' to obtain the list of matches.
- const char_u *const args[2] = { (char_u *)"0", base };
+ typval_T args[3];
+ args[0].v_type = VAR_NUMBER;
+ args[1].v_type = VAR_STRING;
+ args[2].v_type = VAR_UNKNOWN;
+ args[0].vval.v_number = 0;
+ args[1].vval.v_string = base != NULL ? base : (char_u *)"";
pos = curwin->w_cursor;
curwin_save = curwin;
curbuf_save = curbuf;
- /* Call a function, which returns a list or dict. */
- if (call_vim_function(funcname, 2, args, FALSE, FALSE, &rettv) == OK) {
+ // Call a function, which returns a list or dict.
+ if (call_vim_function(funcname, 2, args, &rettv, false) == OK) {
switch (rettv.v_type) {
case VAR_LIST:
matchlist = rettv.vval.v_list;
@@ -3838,11 +3885,14 @@ static int ins_compl_get_exp(pos_T *ini)
e_cpt = (compl_cont_status & CONT_LOCAL)
? (char_u *)"." : curbuf->b_p_cpt;
last_match_pos = first_match_pos = *ini;
+ } else if (ins_buf != curbuf && !buf_valid(ins_buf)) {
+ ins_buf = curbuf; // In case the buffer was wiped out.
}
compl_old_match = compl_curr_match; // remember the last current match
pos = (compl_direction == FORWARD) ? &last_match_pos : &first_match_pos;
- /* For ^N/^P loop over all the flags/windows/buffers in 'complete' */
+
+ // For ^N/^P loop over all the flags/windows/buffers in 'complete'
for (;; ) {
found_new_match = FAIL;
set_match_pos = FALSE;
@@ -3852,7 +3902,8 @@ static int ins_compl_get_exp(pos_T *ini)
/* For ^N/^P pick a new entry from e_cpt if compl_started is off,
* or if found_all says this entry is done. For ^X^L only use the
* entries from 'complete' that look in loaded buffers. */
- if ((l_ctrl_x_mode == 0 || CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode))
+ 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 == ' ')
@@ -3862,7 +3913,7 @@ static int ins_compl_get_exp(pos_T *ini)
first_match_pos = *ini;
// Move the cursor back one character so that ^N can match the
// word immediately after the cursor.
- if (ctrl_x_mode == 0 && dec(&first_match_pos) < 0) {
+ if (ctrl_x_mode == CTRL_X_NORMAL && dec(&first_match_pos) < 0) {
// Move the cursor to after the last character in the
// buffer, so that word at start of buffer is found
// correctly.
@@ -3980,9 +4031,9 @@ static int ins_compl_get_exp(pos_T *ini)
/* Find up to TAG_MANY matches. Avoids that an enormous number
* of matches is found when compl_pattern is empty */
if (find_tags(compl_pattern, &num_matches, &matches,
- TAG_REGEXP | TAG_NAMES | TAG_NOIC |
- TAG_INS_COMP | (l_ctrl_x_mode ? TAG_VERBOSE : 0),
- TAG_MANY, curbuf->b_ffname) == OK && num_matches > 0) {
+ TAG_REGEXP | TAG_NAMES | TAG_NOIC | TAG_INS_COMP
+ | (l_ctrl_x_mode != CTRL_X_NORMAL ? TAG_VERBOSE : 0),
+ TAG_MANY, curbuf->b_ffname) == OK && num_matches > 0) {
ins_compl_add_matches(num_matches, matches, p_ic);
}
p_ic = save_p_ic;
@@ -4156,9 +4207,10 @@ static int ins_compl_get_exp(pos_T *ini)
found_new_match = OK;
}
- /* break the loop for specialized modes (use 'complete' just for the
- * generic l_ctrl_x_mode == 0) or when we've found a new match */
- if ((l_ctrl_x_mode != 0 && !CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode))
+ // break the loop for specialized modes (use 'complete' just for the
+ // generic l_ctrl_x_mode == CTRL_X_NORMAL) or when we've found a new match
+ 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)
break;
@@ -4166,7 +4218,8 @@ static int ins_compl_get_exp(pos_T *ini)
if (type != -1)
ins_compl_check_keys(0, false);
- if ((l_ctrl_x_mode != 0 && !CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode))
+ if ((l_ctrl_x_mode != CTRL_X_NORMAL
+ && !CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode))
|| compl_interrupted) {
break;
}
@@ -4183,14 +4236,16 @@ static int ins_compl_get_exp(pos_T *ini)
}
compl_started = TRUE;
- if ((l_ctrl_x_mode == 0 || CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode))
+ if ((l_ctrl_x_mode == CTRL_X_NORMAL
+ || CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode))
&& *e_cpt == NUL) { // Got to end of 'complete'
found_new_match = FAIL;
}
i = -1; /* total of matches, unknown */
if (found_new_match == FAIL
- || (l_ctrl_x_mode != 0 && !CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode))) {
+ || (l_ctrl_x_mode != CTRL_X_NORMAL
+ && !CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode))) {
i = ins_compl_make_cyclic();
}
@@ -4505,12 +4560,12 @@ void ins_compl_check_keys(int frequency, int in_compl_func)
{
static int count = 0;
- int c;
-
- /* Don't check when reading keys from a script. That would break the test
- * scripts */
- if (using_script())
+ // Don't check when reading keys from a script, :normal or feedkeys().
+ // That would break the test scripts. But do check for keys when called
+ // from complete_check().
+ if (!in_compl_func && (using_script() || ex_normal_busy)) {
return;
+ }
/* Only do this at regular intervals */
if (++count < frequency)
@@ -4519,7 +4574,7 @@ void ins_compl_check_keys(int frequency, int in_compl_func)
/* Check for a typed key. Do use mappings, otherwise vim_is_ctrl_x_key()
* can't do its work correctly. */
- c = vpeekc_any();
+ int c = vpeekc_any();
if (c != NUL) {
if (vim_is_ctrl_x_key(c) && c != Ctrl_X && c != Ctrl_R) {
c = safe_vgetc(); /* Eat the character */
@@ -4668,8 +4723,9 @@ static int ins_complete(int c, bool enable_pum)
/*
* it is a continued search
*/
- compl_cont_status &= ~CONT_INTRPT; /* remove INTRPT */
- if (ctrl_x_mode == 0 || ctrl_x_mode == CTRL_X_PATH_PATTERNS
+ compl_cont_status &= ~CONT_INTRPT; // remove INTRPT
+ if (ctrl_x_mode == CTRL_X_NORMAL
+ || ctrl_x_mode == CTRL_X_PATH_PATTERNS
|| ctrl_x_mode == CTRL_X_PATH_DEFINES) {
if (compl_startpos.lnum != curwin->w_cursor.lnum) {
/* line (probably) wrapped, set compl_startpos to the
@@ -4713,16 +4769,18 @@ static int ins_complete(int c, bool enable_pum)
if (!(compl_cont_status & CONT_ADDING)) { /* normal expansion */
compl_cont_mode = ctrl_x_mode;
- if (ctrl_x_mode != 0) /* Remove LOCAL if ctrl_x_mode != 0 */
+ if (ctrl_x_mode != CTRL_X_NORMAL) {
+ // Remove LOCAL if ctrl_x_mode != CTRL_X_NORMAL
compl_cont_status = 0;
+ }
compl_cont_status |= CONT_N_ADDS;
compl_startpos = curwin->w_cursor;
startcol = (int)curs_col;
compl_col = 0;
}
- /* Work out completion pattern and original text -- webb */
- if (ctrl_x_mode == 0 || (ctrl_x_mode & CTRL_X_WANT_IDENT)) {
+ // Work out completion pattern and original text -- webb
+ if (ctrl_x_mode == CTRL_X_NORMAL || (ctrl_x_mode & CTRL_X_WANT_IDENT)) {
if ((compl_cont_status & CONT_SOL)
|| ctrl_x_mode == CTRL_X_PATH_DEFINES) {
if (!(compl_cont_status & CONT_ADDING)) {
@@ -4853,7 +4911,13 @@ static int ins_complete(int c, bool enable_pum)
return FAIL;
}
- const char_u *const args[2] = { (char_u *)"1", NULL };
+ typval_T args[3];
+ args[0].v_type = VAR_NUMBER;
+ args[1].v_type = VAR_STRING;
+ args[2].v_type = VAR_UNKNOWN;
+ args[0].vval.v_number = 1;
+ args[1].vval.v_string = (char_u *)"";
+
pos = curwin->w_cursor;
curwin_save = curwin;
curbuf_save = curbuf;
@@ -4877,7 +4941,7 @@ static int ins_complete(int c, bool enable_pum)
if (col == -2)
return FAIL;
if (col == -3) {
- ctrl_x_mode = 0;
+ ctrl_x_mode = CTRL_X_NORMAL;
edit_submode = NULL;
if (!shortmess(SHM_COMPLETIONMENU)) {
msg_clr_cmdline();
@@ -5008,12 +5072,13 @@ static int ins_complete(int c, bool enable_pum)
* because we couldn't expand anything at first place, but if we used
* ^P, ^N, ^X^I or ^X^D we might want to add-expand a single-char-word
* (such as M in M'exico) if not tried already. -- Acevedo */
- if ( compl_length > 1
- || (compl_cont_status & CONT_ADDING)
- || (ctrl_x_mode != 0
- && ctrl_x_mode != CTRL_X_PATH_PATTERNS
- && ctrl_x_mode != CTRL_X_PATH_DEFINES))
+ if (compl_length > 1
+ || (compl_cont_status & CONT_ADDING)
+ || (ctrl_x_mode != CTRL_X_NORMAL
+ && ctrl_x_mode != CTRL_X_PATH_PATTERNS
+ && ctrl_x_mode != CTRL_X_PATH_DEFINES)) {
compl_cont_status &= ~CONT_N_ADDS;
+ }
}
if (compl_curr_match->cp_flags & CONT_S_IPOS)
@@ -8100,9 +8165,10 @@ static void ins_mousescroll(int dir)
-static void ins_left(bool end_change)
+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)
foldOpenCursor();
@@ -8164,23 +8230,31 @@ static void ins_end(int c)
static void ins_s_left(void)
{
- if ((fdo_flags & FDO_HOR) && KeyTyped)
+ const bool end_change = dont_sync_undo == kFalse; // end undoable change
+ if ((fdo_flags & FDO_HOR) && KeyTyped) {
foldOpenCursor();
+ }
undisplay_dollar();
if (curwin->w_cursor.lnum > 1 || curwin->w_cursor.col > 0) {
- start_arrow(&curwin->w_cursor);
+ start_arrow_with_change(&curwin->w_cursor, end_change);
+ if (!end_change) {
+ AppendCharToRedobuff(K_S_LEFT);
+ }
(void)bck_word(1L, false, false);
curwin->w_set_curswant = true;
} else {
vim_beep(BO_CRSR);
}
+ dont_sync_undo = kFalse;
}
/// @param end_change end undoable change
-static void ins_right(bool end_change)
+static void ins_right(void)
{
- if ((fdo_flags & FDO_HOR) && KeyTyped)
+ const bool end_change = dont_sync_undo == kFalse; // end undoable change
+ if ((fdo_flags & FDO_HOR) && KeyTyped) {
foldOpenCursor();
+ }
undisplay_dollar();
if (gchar_cursor() != NUL || virtual_active()) {
start_arrow_with_change(&curwin->w_cursor, end_change);
@@ -8217,17 +8291,23 @@ static void ins_right(bool end_change)
static void ins_s_right(void)
{
- if ((fdo_flags & FDO_HOR) && KeyTyped)
+ const bool end_change = dont_sync_undo == kFalse; // end undoable change
+ if ((fdo_flags & FDO_HOR) && KeyTyped) {
foldOpenCursor();
+ }
undisplay_dollar();
if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count
|| gchar_cursor() != NUL) {
- start_arrow(&curwin->w_cursor);
+ start_arrow_with_change(&curwin->w_cursor, end_change);
+ if (!end_change) {
+ AppendCharToRedobuff(K_S_RIGHT);
+ }
(void)fwd_word(1L, false, 0);
curwin->w_set_curswant = true;
} else {
vim_beep(BO_CRSR);
}
+ dont_sync_undo = kFalse;
}
static void
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 942f8d5e09..a3a66a5764 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -24,8 +24,10 @@
#endif
#include "nvim/eval.h"
#include "nvim/buffer.h"
+#include "nvim/change.h"
#include "nvim/channel.h"
#include "nvim/charset.h"
+#include "nvim/context.h"
#include "nvim/cursor.h"
#include "nvim/diff.h"
#include "nvim/edit.h"
@@ -176,6 +178,7 @@ static char *e_funcref = N_("E718: Funcref required");
static char *e_dictrange = N_("E719: Cannot use [:] with a Dictionary");
static char *e_nofunc = N_("E130: Unknown function: %s");
static char *e_illvar = N_("E461: Illegal variable name: %s");
+static char *e_cannot_mod = N_("E995: Cannot modify existing variable");
static const char *e_readonlyvar = N_(
"E46: Cannot change read-only variable \"%.*s\"");
@@ -302,15 +305,6 @@ typedef struct {
list_T *fi_list; /* list being used */
} forinfo_T;
-/*
- * enum used by var_flavour()
- */
-typedef enum {
- VAR_FLAVOUR_DEFAULT, /* doesn't start with uppercase */
- VAR_FLAVOUR_SESSION, /* starts with uppercase, some lower */
- VAR_FLAVOUR_SHADA /* all uppercase */
-} var_flavour_T;
-
/* values for vv_flags: */
#define VV_COMPAT 1 /* compatible, also used without "v:" */
#define VV_RO 2 /* read-only */
@@ -533,6 +527,35 @@ const list_T *eval_msgpack_type_lists[] = {
[kMPExt] = NULL,
};
+// Return "n1" divided by "n2", taking care of dividing by zero.
+varnumber_T num_divide(varnumber_T n1, varnumber_T n2)
+ FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ varnumber_T result;
+
+ if (n2 == 0) { // give an error message?
+ if (n1 == 0) {
+ result = VARNUMBER_MIN; // similar to NaN
+ } else if (n1 < 0) {
+ result = -VARNUMBER_MAX;
+ } else {
+ result = VARNUMBER_MAX;
+ }
+ } else {
+ result = n1 / n2;
+ }
+
+ return result;
+}
+
+// Return "n1" modulus "n2", taking care of dividing by zero.
+varnumber_T num_modulus(varnumber_T n1, varnumber_T n2)
+ FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ // Give an error when n2 is 0?
+ return (n2 == 0) ? 0 : (n1 % n2);
+}
+
/*
* Initialize the global and v: variables.
*/
@@ -776,10 +799,11 @@ var_redir_start(
did_emsg = FALSE;
tv.v_type = VAR_STRING;
tv.vval.v_string = (char_u *)"";
- if (append)
- set_var_lval(redir_lval, redir_endp, &tv, TRUE, (char_u *)".");
- else
- set_var_lval(redir_lval, redir_endp, &tv, TRUE, (char_u *)"=");
+ if (append) {
+ set_var_lval(redir_lval, redir_endp, &tv, true, false, (char_u *)".");
+ } else {
+ set_var_lval(redir_lval, redir_endp, &tv, true, false, (char_u *)"=");
+ }
clear_lval(redir_lval);
err = did_emsg;
did_emsg |= save_emsg;
@@ -837,7 +861,7 @@ void var_redir_stop(void)
redir_endp = (char_u *)get_lval(redir_varname, NULL, redir_lval,
false, false, 0, FNE_CHECK_START);
if (redir_endp != NULL && redir_lval->ll_name != NULL) {
- set_var_lval(redir_lval, redir_endp, &tv, false, (char_u *)".");
+ set_var_lval(redir_lval, redir_endp, &tv, false, false, (char_u *)".");
}
clear_lval(redir_lval);
}
@@ -955,6 +979,89 @@ eval_to_bool(
return retval;
}
+// Call eval1() and give an error message if not done at a lower level.
+static int eval1_emsg(char_u **arg, typval_T *rettv, bool evaluate)
+ FUNC_ATTR_NONNULL_ARG(1, 2)
+{
+ const char_u *const start = *arg;
+ const int did_emsg_before = did_emsg;
+ const int called_emsg_before = called_emsg;
+
+ const int ret = eval1(arg, rettv, evaluate);
+ if (ret == FAIL) {
+ // Report the invalid expression unless the expression evaluation has
+ // been cancelled due to an aborting error, an interrupt, or an
+ // 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), start);
+ }
+ }
+ return ret;
+}
+
+static 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;
+
+ 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, (int)STRLEN(s), rettv, argc, argv, NULL,
+ 0L, 0L, &dummy, true, NULL, NULL) == FAIL) {
+ return FAIL;
+ }
+ } else if (expr->v_type == VAR_PARTIAL) {
+ partial_T *const partial = expr->vval.v_partial;
+ const char_u *const s = partial_name(partial);
+ if (s == NULL || *s == NUL) {
+ return FAIL;
+ }
+ if (call_func(s, (int)STRLEN(s), rettv, argc, argv, NULL,
+ 0L, 0L, &dummy, true, partial, NULL) == FAIL) {
+ return FAIL;
+ }
+ } else {
+ char buf[NUMBUFLEN];
+ char_u *s = (char_u *)tv_get_string_buf_chk(expr, buf);
+ if (s == NULL) {
+ return FAIL;
+ }
+ s = skipwhite(s);
+ if (eval1_emsg(&s, rettv, true) == FAIL) {
+ return FAIL;
+ }
+ if (*s != NUL) { // check for trailing chars after expr
+ tv_clear(rettv);
+ emsgf(_(e_invexpr2), s);
+ return FAIL;
+ }
+ }
+ return OK;
+}
+
+/// Like eval_to_bool() but using a typval_T instead of a string.
+/// Works for string, funcref and partial.
+static bool eval_expr_to_bool(const typval_T *expr, bool *error)
+ FUNC_ATTR_NONNULL_ARG(1, 2)
+{
+ typval_T argv, rettv;
+
+ if (eval_expr_typval(expr, &argv, 0, &rettv) == FAIL) {
+ *error = true;
+ return false;
+ }
+ const bool res = (tv_get_number_chk(&rettv, error) != 0);
+ tv_clear(&rettv);
+ return res;
+}
+
/// Top level evaluation function, returning a string
///
/// @param[in] arg String to evaluate.
@@ -1190,68 +1297,35 @@ int get_spellword(list_T *const list, const char **ret_word)
// Call some vim script function and return the result in "*rettv".
-// Uses argv[argc] for the function arguments. Only Number and String
-// arguments are currently supported.
+// Uses argv[0] to argv[argc-1] for the function arguments. argv[argc]
+// should have type VAR_UNKNOWN.
//
// Return OK or FAIL.
int call_vim_function(
const char_u *func,
int argc,
- const char_u *const *const argv,
- bool safe, // use the sandbox
- int str_arg_only, // all arguments are strings
- typval_T *rettv
+ typval_T *argv,
+ typval_T *rettv,
+ bool safe // use the sandbox
)
{
- varnumber_T n;
- int len;
int doesrange;
void *save_funccalp = NULL;
int ret;
- typval_T *argvars = xmalloc((argc + 1) * sizeof(typval_T));
-
- for (int i = 0; i < argc; i++) {
- // Pass a NULL or empty argument as an empty string
- if (argv[i] == NULL || *argv[i] == NUL) {
- argvars[i].v_type = VAR_STRING;
- argvars[i].vval.v_string = (char_u *)"";
- continue;
- }
-
- if (str_arg_only) {
- len = 0;
- } else {
- // Recognize a number argument, the others must be strings. A dash
- // is a string too.
- vim_str2nr(argv[i], NULL, &len, STR2NR_ALL, &n, NULL, 0);
- if (len == 1 && *argv[i] == '-') {
- len = 0;
- }
- }
- if (len != 0 && len == (int)STRLEN(argv[i])) {
- argvars[i].v_type = VAR_NUMBER;
- argvars[i].vval.v_number = n;
- } else {
- argvars[i].v_type = VAR_STRING;
- argvars[i].vval.v_string = (char_u *)argv[i];
- }
- }
-
if (safe) {
save_funccalp = save_funccal();
++sandbox;
}
rettv->v_type = VAR_UNKNOWN; // tv_clear() uses this.
- ret = call_func(func, (int)STRLEN(func), rettv, argc, argvars, NULL,
+ ret = call_func(func, (int)STRLEN(func), rettv, argc, argv, NULL,
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
&doesrange, true, NULL, NULL);
if (safe) {
--sandbox;
restore_funccal(save_funccalp);
}
- xfree(argvars);
if (ret == FAIL) {
tv_clear(rettv);
@@ -1259,47 +1333,44 @@ int call_vim_function(
return ret;
}
-
/// Call Vim script function and return the result as a number
///
/// @param[in] func Function name.
/// @param[in] argc Number of arguments.
-/// @param[in] argv Array with string arguments.
+/// @param[in] argv Array with typval_T arguments.
/// @param[in] safe Use with sandbox.
///
/// @return -1 when calling function fails, result of function otherwise.
varnumber_T call_func_retnr(char_u *func, int argc,
- const char_u *const *const argv, int safe)
+ typval_T *argv, int safe)
{
typval_T rettv;
varnumber_T retval;
- /* All arguments are passed as strings, no conversion to number. */
- if (call_vim_function(func, argc, argv, safe, TRUE, &rettv) == FAIL)
+ if (call_vim_function(func, argc, argv, &rettv, safe) == FAIL) {
return -1;
-
+ }
retval = tv_get_number_chk(&rettv, NULL);
tv_clear(&rettv);
return retval;
}
-
/// Call Vim script function and return the result as a string
///
/// @param[in] func Function name.
/// @param[in] argc Number of arguments.
-/// @param[in] argv Array with string arguments.
+/// @param[in] argv Array with typval_T arguments.
/// @param[in] safe Use the sandbox.
///
/// @return [allocated] NULL when calling function fails, allocated string
/// otherwise.
char *call_func_retstr(const char *const func, int argc,
- const char_u *const *argv,
+ typval_T *argv,
bool safe)
FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_MALLOC
{
typval_T rettv;
// All arguments are passed as strings, no conversion to number.
- if (call_vim_function((const char_u *)func, argc, argv, safe, true, &rettv)
+ if (call_vim_function((const char_u *)func, argc, argv, &rettv, safe)
== FAIL) {
return NULL;
}
@@ -1308,24 +1379,24 @@ char *call_func_retstr(const char *const func, int argc,
tv_clear(&rettv);
return retval;
}
-
/// Call Vim script function and return the result as a List
///
/// @param[in] func Function name.
/// @param[in] argc Number of arguments.
-/// @param[in] argv Array with string arguments.
+/// @param[in] argv Array with typval_T arguments.
/// @param[in] safe Use the sandbox.
///
/// @return [allocated] NULL when calling function fails or return tv is not a
/// List, allocated List otherwise.
-void *call_func_retlist(char_u *func, int argc, const char_u *const *argv,
+void *call_func_retlist(char_u *func, int argc, typval_T *argv,
bool safe)
{
typval_T rettv;
- /* All arguments are passed as strings, no conversion to number. */
- if (call_vim_function(func, argc, argv, safe, TRUE, &rettv) == FAIL)
+ // All arguments are passed as strings, no conversion to number.
+ if (call_vim_function(func, argc, argv, &rettv, safe) == FAIL) {
return NULL;
+ }
if (rettv.v_type != VAR_LIST) {
tv_clear(&rettv);
@@ -1436,21 +1507,33 @@ int eval_foldexpr(char_u *arg, int *cp)
return (int)retval;
}
-/*
- * ":let" list all variable values
- * ":let var1 var2" list variable values
- * ":let var = expr" assignment command.
- * ":let var += expr" assignment command.
- * ":let var -= expr" assignment command.
- * ":let var *= expr" assignment command.
- * ":let var /= expr" assignment command.
- * ":let var %= expr" assignment command.
- * ":let var .= expr" assignment command.
- * ":let var ..= expr" assignment command.
- * ":let [var1, var2] = expr" unpack list.
- */
+// ":cons[t] var = expr1" define constant
+// ":cons[t] [name1, name2, ...] = expr1" define constants unpacking list
+// ":cons[t] [name, ..., ; lastname] = expr" define constants unpacking list
+void ex_const(exarg_T *eap)
+{
+ ex_let_const(eap, true);
+}
+
+// ":let" list all variable values
+// ":let var1 var2" list variable values
+// ":let var = expr" assignment command.
+// ":let var += expr" assignment command.
+// ":let var -= expr" assignment command.
+// ":let var *= expr" assignment command.
+// ":let var /= expr" assignment command.
+// ":let var %= expr" assignment command.
+// ":let var .= expr" assignment command.
+// ":let var ..= expr" assignment command.
+// ":let [var1, var2] = expr" unpack list.
+// ":let [name, ..., ; lastname] = expr" unpack list.
void ex_let(exarg_T *eap)
{
+ ex_let_const(eap, false);
+}
+
+static void ex_let_const(exarg_T *eap, const bool is_const)
+{
char_u *arg = eap->arg;
char_u *expr = NULL;
typval_T rettv;
@@ -1512,7 +1595,8 @@ void ex_let(exarg_T *eap)
}
emsg_skip--;
} else if (i != FAIL) {
- (void)ex_let_vars(eap->arg, &rettv, false, semicolon, var_count, op);
+ (void)ex_let_vars(eap->arg, &rettv, false, semicolon, var_count,
+ is_const, op);
tv_clear(&rettv);
}
}
@@ -1530,9 +1614,10 @@ 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 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
)
{
@@ -1543,8 +1628,9 @@ ex_let_vars(
/*
* ":let var = expr" or ":for var in list"
*/
- if (ex_let_one(arg, tv, copy, nextchars, nextchars) == NULL)
+ if (ex_let_one(arg, tv, copy, is_const, nextchars, nextchars) == NULL) {
return FAIL;
+ }
return OK;
}
@@ -1572,8 +1658,8 @@ ex_let_vars(
size_t rest_len = tv_list_len(l);
while (*arg != ']') {
arg = skipwhite(arg + 1);
- arg = ex_let_one(arg, TV_LIST_ITEM_TV(item), true, (const char_u *)",;]",
- nextchars);
+ arg = ex_let_one(arg, TV_LIST_ITEM_TV(item), true, is_const,
+ (const char_u *)",;]", nextchars);
if (arg == NULL) {
return FAIL;
}
@@ -1595,7 +1681,7 @@ ex_let_vars(
ltv.vval.v_list = rest_list;
tv_list_ref(rest_list);
- arg = ex_let_one(skipwhite(arg + 1), &ltv, false,
+ arg = ex_let_one(skipwhite(arg + 1), &ltv, false, is_const,
(char_u *)"]", nextchars);
tv_clear(&ltv);
if (arg == NULL) {
@@ -1683,6 +1769,15 @@ static void list_hashtable_vars(hashtab_T *ht, const char *prefix, int empty,
if (!HASHITEM_EMPTY(hi)) {
todo--;
di = TV_DICT_HI2DI(hi);
+ char buf[IOSIZE];
+
+ // apply :filter /pat/ to variable name
+ xstrlcpy(buf, prefix, IOSIZE - 1);
+ xstrlcat(buf, (char *)di->di_key, IOSIZE);
+ if (message_filtered((char_u *)buf)) {
+ continue;
+ }
+
if (empty || di->di_tv.v_type != VAR_STRING
|| di->di_tv.vval.v_string != NULL) {
list_one_var(di, prefix, first);
@@ -1851,8 +1946,8 @@ 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 char_u *const endchars,
- const char_u *const op)
+ 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
{
char_u *arg_end = NULL;
@@ -1864,6 +1959,10 @@ static char_u *ex_let_one(char_u *arg, typval_T *const tv,
* ":let $VAR = expr": Set environment variable.
*/
if (*arg == '$') {
+ if (is_const) {
+ EMSG(_("E996: Cannot lock an environment variable"));
+ return NULL;
+ }
// Find the end of the name.
arg++;
char *name = (char *)arg;
@@ -1909,6 +2008,10 @@ static char_u *ex_let_one(char_u *arg, typval_T *const tv,
// ":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"));
+ return NULL;
+ }
// Find the end of the name.
char *const p = (char *)find_option_end((const char **)&arg, &opt_flags);
if (p == NULL
@@ -1938,8 +2041,8 @@ static char_u *ex_let_one(char_u *arg, typval_T *const tv,
case '+': n = numval + n; break;
case '-': n = 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;
@@ -1959,6 +2062,10 @@ static char_u *ex_let_one(char_u *arg, typval_T *const tv,
}
// ":let @r = expr": Set register contents.
} else if (*arg == '@') {
+ if (is_const) {
+ EMSG(_("E996: Cannot lock a register"));
+ return NULL;
+ }
arg++;
if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL) {
emsgf(_(e_letwrong), op);
@@ -1998,7 +2105,7 @@ static char_u *ex_let_one(char_u *arg, typval_T *const tv,
if (endchars != NULL && vim_strchr(endchars, *skipwhite(p)) == NULL) {
EMSG(_(e_letunexp));
} else {
- set_var_lval(&lv, p, tv, copy, op);
+ set_var_lval(&lv, p, tv, copy, is_const, op);
arg_end = p;
}
}
@@ -2249,6 +2356,7 @@ static char_u *get_lval(char_u *const name, typval_T *const rettv,
/* Can't add "v:" variable. */
if (lp->ll_dict == &vimvardict) {
EMSG2(_(e_illvar), name);
+ tv_clear(&var1);
return NULL;
}
@@ -2363,7 +2471,7 @@ static void clear_lval(lval_T *lp)
* "%" for "%=", "." for ".=" or "=" for "=".
*/
static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv,
- int copy, const char_u *op)
+ int copy, const bool is_const, const char_u *op)
{
int cc;
listitem_T *ri;
@@ -2375,6 +2483,12 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv,
if (op != NULL && *op != '=') {
typval_T tv;
+ if (is_const) {
+ EMSG(_(e_cannot_mod));
+ *endp = cc;
+ return;
+ }
+
// handle +=, -=, *=, /=, %= and .=
di = NULL;
if (get_var_tv((const char *)lp->ll_name, (int)STRLEN(lp->ll_name),
@@ -2390,7 +2504,7 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv,
tv_clear(&tv);
}
} else {
- set_var(lp->ll_name, lp->ll_name_len, rettv, copy);
+ set_var_const(lp->ll_name, lp->ll_name_len, rettv, copy, is_const);
}
*endp = cc;
} else if (tv_check_lock(lp->ll_newkey == NULL
@@ -2401,6 +2515,11 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv,
listitem_T *ll_li = lp->ll_li;
int ll_n1 = lp->ll_n1;
+ if (is_const) {
+ EMSG(_("E996: Cannot lock a range"));
+ return;
+ }
+
// Check whether any of the list items is locked
for (ri = tv_list_first(rettv->vval.v_list);
ri != NULL && ll_li != NULL; ) {
@@ -2456,6 +2575,11 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv,
dict_T *dict = lp->ll_dict;
bool watched = tv_dict_is_watched(dict);
+ if (is_const) {
+ EMSG(_("E996: Cannot lock a list or dict"));
+ return;
+ }
+
// Assign to a List or Dictionary item.
if (lp->ll_newkey != NULL) {
if (op != NULL && *op != '=') {
@@ -2579,7 +2703,7 @@ bool next_for_item(void *fi_void, char_u *arg)
} else {
fi->fi_lw.lw_item = TV_LIST_ITEM_NEXT(fi->fi_list, item);
return (ex_let_vars(arg, TV_LIST_ITEM_TV(item), true,
- fi->fi_semicolon, fi->fi_varcount, NULL) == OK);
+ fi->fi_semicolon, fi->fi_varcount, false, NULL) == OK);
}
}
@@ -4048,22 +4172,9 @@ static int eval6(char_u **arg, typval_T *rettv, int evaluate, int want_string)
if (op == '*') {
n1 = n1 * n2;
} else if (op == '/') {
- if (n2 == 0) { // give an error message?
- if (n1 == 0) {
- n1 = VARNUMBER_MIN; // similar to NaN
- } else if (n1 < 0) {
- n1 = -VARNUMBER_MAX;
- } else {
- n1 = VARNUMBER_MAX;
- }
- } else {
- n1 = n1 / n2;
- }
+ n1 = num_divide(n1, n2);
} else {
- if (n2 == 0) /* give an error message? */
- n1 = 0;
- else
- n1 = n1 % n2;
+ n1 = num_modulus(n1, n2);
}
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = n1;
@@ -4199,7 +4310,7 @@ static int eval7(
// Dictionary: {key: val, key: val}
case '{': ret = get_lambda_tv(arg, rettv, evaluate);
if (ret == NOTDONE) {
- ret = get_dict_tv(arg, rettv, evaluate);
+ ret = dict_get_tv(arg, rettv, evaluate);
}
break;
@@ -5123,7 +5234,7 @@ bool garbage_collect(bool testing)
yankreg_T reg;
char name = NUL;
bool is_unnamed = false;
- reg_iter = op_register_iter(reg_iter, &name, &reg, &is_unnamed);
+ reg_iter = op_global_reg_iter(reg_iter, &name, &reg, &is_unnamed);
if (name != NUL) {
ABORTING(set_ref_dict)(reg.additional_data, copyID);
}
@@ -5165,7 +5276,7 @@ bool garbage_collect(bool testing)
{
Channel *data;
map_foreach_value(channels, data, {
- set_ref_in_callback_reader(&data->on_stdout, copyID, NULL, NULL);
+ 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);
})
@@ -5583,7 +5694,7 @@ static bool set_ref_in_funccal(funccall_T *fc, int copyID)
* Allocate a variable for a Dictionary and fill it from "*arg".
* Return OK or FAIL. Returns NOTDONE for {expr}.
*/
-static int get_dict_tv(char_u **arg, typval_T *rettv, int evaluate)
+static int dict_get_tv(char_u **arg, typval_T *rettv, int evaluate)
{
dict_T *d = NULL;
typval_T tvkey;
@@ -5871,10 +5982,6 @@ static int get_lambda_tv(char_u **arg, typval_T *rettv, bool evaluate)
fp->uf_scoped = NULL;
}
- fp->uf_tml_count = NULL;
- fp->uf_tml_total = NULL;
- fp->uf_tml_self = NULL;
- fp->uf_profiling = false;
if (prof_def_func()) {
func_do_profile(fp);
}
@@ -6312,6 +6419,7 @@ call_func(
partial_T *partial, // optional, can be NULL
dict_T *selfdict_in // Dictionary for "self"
)
+ FUNC_ATTR_NONNULL_ARG(1, 3, 5, 9)
{
int ret = FAIL;
int error = ERROR_NONE;
@@ -6545,6 +6653,10 @@ static void float_op_wrapper(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void api_wrapper(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
+ if (check_restricted() || check_secure()) {
+ return;
+ }
+
ApiDispatchWrapper fn = (ApiDispatchWrapper)fptr;
Array args = ARRAY_DICT_INIT;
@@ -6969,10 +7081,14 @@ static void f_assert_fails(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
const char *const cmd = tv_get_string_chk(&argvars[0]);
garray_T ga;
+ int save_trylevel = trylevel;
+ // trylevel must be zero for a ":throw" command to be considered failed
+ trylevel = 0;
called_emsg = false;
suppress_errthrow = true;
emsg_silent = true;
+
do_cmdline_cmd(cmd);
if (!called_emsg) {
prepare_assert_error(&ga);
@@ -6994,6 +7110,7 @@ static void f_assert_fails(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
+ trylevel = save_trylevel;
called_emsg = false;
suppress_errthrow = false;
emsg_silent = false;
@@ -7161,6 +7278,14 @@ static buf_T *find_buffer(typval_T *avar)
return buf;
}
+// "bufadd(expr)" function
+static void f_bufadd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ char_u *name = (char_u *)tv_get_string(&argvars[0]);
+
+ rettv->vval.v_number = buflist_add(*name == NUL ? NULL : name, 0);
+}
+
/*
* "bufexists(expr)" function
*/
@@ -7180,6 +7305,21 @@ static void f_buflisted(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
}
+// "bufload(expr)" function
+static void f_bufload(typval_T *argvars, typval_T *unused, FunPtr fptr)
+{
+ buf_T *buf = get_buf_arg(&argvars[0]);
+
+ if (buf != NULL && buf->b_ml.ml_mfp == NULL) {
+ aco_save_T aco;
+
+ aucmd_prepbuf(&aco, buf);
+ swap_exists_action = SEA_NONE;
+ open_buffer(false, NULL, 0);
+ aucmd_restbuf(&aco);
+ }
+}
+
/*
* "bufloaded(expr)" function
*/
@@ -7856,6 +7996,116 @@ static void f_cscope_connection(typval_T *argvars, typval_T *rettv, FunPtr fptr)
(char_u *)prepend);
}
+/// "ctxget([{index}])" function
+static void f_ctxget(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ size_t index = 0;
+ if (argvars[0].v_type == VAR_NUMBER) {
+ index = argvars[0].vval.v_number;
+ } else if (argvars[0].v_type != VAR_UNKNOWN) {
+ EMSG2(_(e_invarg2), "expected nothing or a Number as an argument");
+ return;
+ }
+
+ Context *ctx = ctx_get(index);
+ if (ctx == NULL) {
+ EMSG3(_(e_invargNval), "index", "out of bounds");
+ return;
+ }
+
+ Dictionary ctx_dict = ctx_to_dict(ctx);
+ Error err = ERROR_INIT;
+ object_to_vim(DICTIONARY_OBJ(ctx_dict), rettv, &err);
+ api_free_dictionary(ctx_dict);
+ api_clear_error(&err);
+}
+
+/// "ctxpop()" function
+static void f_ctxpop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ if (!ctx_restore(NULL, kCtxAll)) {
+ EMSG(_("Context stack is empty"));
+ }
+}
+
+/// "ctxpush([{types}])" function
+static void f_ctxpush(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ int types = kCtxAll;
+ if (argvars[0].v_type == VAR_LIST) {
+ types = 0;
+ TV_LIST_ITER(argvars[0].vval.v_list, li, {
+ typval_T *tv_li = TV_LIST_ITEM_TV(li);
+ if (tv_li->v_type == VAR_STRING) {
+ if (strequal((char *)tv_li->vval.v_string, "regs")) {
+ types |= kCtxRegs;
+ } else if (strequal((char *)tv_li->vval.v_string, "jumps")) {
+ types |= kCtxJumps;
+ } else if (strequal((char *)tv_li->vval.v_string, "buflist")) {
+ types |= kCtxBuflist;
+ } else if (strequal((char *)tv_li->vval.v_string, "gvars")) {
+ types |= kCtxGVars;
+ } else if (strequal((char *)tv_li->vval.v_string, "sfuncs")) {
+ types |= kCtxSFuncs;
+ } else if (strequal((char *)tv_li->vval.v_string, "funcs")) {
+ types |= kCtxFuncs;
+ }
+ }
+ });
+ } else if (argvars[0].v_type != VAR_UNKNOWN) {
+ EMSG2(_(e_invarg2), "expected nothing or a List as an argument");
+ return;
+ }
+ ctx_save(NULL, types);
+}
+
+/// "ctxset({context}[, {index}])" function
+static void f_ctxset(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ if (argvars[0].v_type != VAR_DICT) {
+ EMSG2(_(e_invarg2), "expected dictionary as first argument");
+ return;
+ }
+
+ size_t index = 0;
+ if (argvars[1].v_type == VAR_NUMBER) {
+ index = argvars[1].vval.v_number;
+ } else if (argvars[1].v_type != VAR_UNKNOWN) {
+ EMSG2(_(e_invarg2), "expected nothing or a Number as second argument");
+ return;
+ }
+
+ Context *ctx = ctx_get(index);
+ if (ctx == NULL) {
+ EMSG3(_(e_invargNval), "index", "out of bounds");
+ return;
+ }
+
+ int save_did_emsg = did_emsg;
+ did_emsg = false;
+
+ Dictionary dict = vim_to_object(&argvars[0]).data.dictionary;
+ Context tmp = CONTEXT_INIT;
+ ctx_from_dict(dict, &tmp);
+
+ if (did_emsg) {
+ ctx_free(&tmp);
+ } else {
+ ctx_free(ctx);
+ *ctx = tmp;
+ }
+
+ api_free_dictionary(dict);
+ did_emsg = save_did_emsg;
+}
+
+/// "ctxsize()" function
+static void f_ctxsize(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = ctx_size();
+}
+
/// "cursor(lnum, col)" function, or
/// "cursor(list)"
///
@@ -8246,6 +8496,25 @@ static void f_empty(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = n;
}
+/// "environ()" function
+static void f_environ(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ tv_dict_alloc_ret(rettv);
+
+ for (int i = 0; ; i++) {
+ // TODO(justinmk): use os_copyfullenv from #7202 ?
+ char *envname = os_getenvname_at_index((size_t)i);
+ if (envname == NULL) {
+ break;
+ }
+ const char *value = os_getenv(envname);
+ tv_dict_add_str(rettv->vval.v_dict,
+ (char *)envname, STRLEN((char *)envname),
+ value == NULL ? "" : value);
+ xfree(envname);
+ }
+}
+
/*
* "escape({string}, {chars})" function
*/
@@ -8259,6 +8528,20 @@ static void f_escape(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->v_type = VAR_STRING;
}
+/// "getenv()" function
+static void f_getenv(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ char_u *p = (char_u *)vim_getenv(tv_get_string(&argvars[0]));
+
+ if (p == NULL) {
+ rettv->v_type = VAR_SPECIAL;
+ rettv->vval.v_number = kSpecialVarNull;
+ return;
+ }
+ rettv->vval.v_string = p;
+ rettv->v_type = VAR_STRING;
+}
+
/*
* "eval()" function
*/
@@ -8298,10 +8581,7 @@ static void f_executable(typval_T *argvars, typval_T *rettv, FunPtr fptr)
const char *name = tv_get_string(&argvars[0]);
// Check in $PATH and also check directly if there is a directory name
- rettv->vval.v_number = (
- os_can_exe((const char_u *)name, NULL, true)
- || (gettail_dir(name) != name
- && os_can_exe((const char_u *)name, NULL, false)));
+ rettv->vval.v_number = os_can_exe(name, NULL, true);
}
typedef struct {
@@ -8406,12 +8686,12 @@ static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void f_exepath(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
const char *arg = tv_get_string(&argvars[0]);
- char_u *path = NULL;
+ char *path = NULL;
- (void)os_can_exe((const char_u *)arg, &path, true);
+ (void)os_can_exe(arg, &path, true);
rettv->v_type = VAR_STRING;
- rettv->vval.v_string = path;
+ rettv->vval.v_string = (char_u *)path;
}
/// Find a window: When using a Window ID in any tab page, when using a number
@@ -8438,7 +8718,7 @@ static void f_exists(typval_T *argvars, typval_T *rettv, FunPtr fptr)
const char *p = tv_get_string(&argvars[0]);
if (*p == '$') { // Environment variable.
// First try "normal" environment variables (fast).
- if (os_getenv(p + 1) != NULL) {
+ if (os_env_exists(p + 1)) {
n = true;
} else {
// Try expanding things like $VIM and ${HOME}.
@@ -8834,6 +9114,7 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map)
}
hash_unlock(ht);
} else {
+ assert(argvars[0].v_type == VAR_LIST);
vimvars[VV_KEY].vv_type = VAR_NUMBER;
for (listitem_T *li = tv_list_first(l); li != NULL;) {
@@ -8864,44 +9145,17 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map)
}
static int filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp)
+ FUNC_ATTR_NONNULL_ARG(1, 2)
{
typval_T rettv;
typval_T argv[3];
int retval = FAIL;
- int dummy;
tv_copy(tv, &vimvars[VV_VAL].vv_tv);
argv[0] = vimvars[VV_KEY].vv_tv;
argv[1] = vimvars[VV_VAL].vv_tv;
- if (expr->v_type == VAR_FUNC) {
- const char_u *const s = expr->vval.v_string;
- if (call_func(s, (int)STRLEN(s), &rettv, 2, argv, NULL,
- 0L, 0L, &dummy, true, NULL, NULL) == FAIL) {
- goto theend;
- }
- } else if (expr->v_type == VAR_PARTIAL) {
- partial_T *partial = expr->vval.v_partial;
-
- const char_u *const s = partial_name(partial);
- if (call_func(s, (int)STRLEN(s), &rettv, 2, argv, NULL,
- 0L, 0L, &dummy, true, partial, NULL) == FAIL) {
- goto theend;
- }
- } else {
- char buf[NUMBUFLEN];
- const char *s = tv_get_string_buf_chk(expr, buf);
- if (s == NULL) {
- goto theend;
- }
- s = (const char *)skipwhite((const char_u *)s);
- if (eval1((char_u **)&s, &rettv, true) == FAIL) {
- goto theend;
- }
-
- if (*s != NUL) { // check for trailing chars after expr
- emsgf(_(e_invexpr2), s);
- goto theend;
- }
+ if (eval_expr_typval(expr, argv, 2, &rettv) == FAIL) {
+ goto theend;
}
if (map) {
// map(): replace the list item value.
@@ -9360,6 +9614,7 @@ static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr)
dictitem_T *di;
dict_T *d;
typval_T *tv = NULL;
+ bool what_is_dict = false;
if (argvars[0].v_type == VAR_LIST) {
if ((l = argvars[0].vval.v_list) != NULL) {
@@ -9401,7 +9656,10 @@ static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr)
func_ref(rettv->vval.v_string);
}
} else if (strcmp(what, "dict") == 0) {
- tv_dict_set_ret(rettv, pt->pt_dict);
+ what_is_dict = true;
+ if (pt->pt_dict != NULL) {
+ tv_dict_set_ret(rettv, pt->pt_dict);
+ }
} else if (strcmp(what, "args") == 0) {
rettv->v_type = VAR_LIST;
if (tv_list_alloc_ret(rettv, pt->pt_argc) != NULL) {
@@ -9412,7 +9670,12 @@ static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr)
} else {
EMSG2(_(e_invarg2), what);
}
- return;
+
+ // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
+ // third argument
+ if (!what_is_dict) {
+ return;
+ }
}
} else {
EMSG2(_(e_listdictarg), "get()");
@@ -9886,13 +10149,13 @@ static void f_getcompletion(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (strcmp(tv_get_string(&argvars[1]), "cmdline") == 0) {
set_one_cmd_context(&xpc, tv_get_string(&argvars[0]));
- xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
+ xpc.xp_pattern_len = STRLEN(xpc.xp_pattern);
goto theend;
}
ExpandInit(&xpc);
xpc.xp_pattern = (char_u *)tv_get_string(&argvars[0]);
- xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
+ xpc.xp_pattern_len = STRLEN(xpc.xp_pattern);
xpc.xp_context = cmdcomplete_str_to_type(
(char_u *)tv_get_string(&argvars[1]));
if (xpc.xp_context == EXPAND_NOTHING) {
@@ -9902,17 +10165,17 @@ static void f_getcompletion(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (xpc.xp_context == EXPAND_MENUS) {
set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, false);
- xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
+ xpc.xp_pattern_len = STRLEN(xpc.xp_pattern);
}
if (xpc.xp_context == EXPAND_CSCOPE) {
set_context_in_cscope_cmd(&xpc, (const char *)xpc.xp_pattern, CMD_cscope);
- xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
+ xpc.xp_pattern_len = STRLEN(xpc.xp_pattern);
}
if (xpc.xp_context == EXPAND_SIGN) {
set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
- xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
+ xpc.xp_pattern_len = STRLEN(xpc.xp_pattern);
}
theend:
@@ -10619,6 +10882,7 @@ static dict_T *get_win_info(win_T *wp, int16_t tpnr, int16_t winnr)
tv_dict_add_nr(dict, S_LEN("bufnr"), wp->w_buffer->b_fnum);
tv_dict_add_nr(dict, S_LEN("wincol"), wp->w_wincol);
+ tv_dict_add_nr(dict, S_LEN("terminal"), bt_terminal(wp->w_buffer));
tv_dict_add_nr(dict, S_LEN("quickfix"), bt_quickfix(wp->w_buffer));
tv_dict_add_nr(dict, S_LEN("loclist"),
(bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
@@ -10996,7 +11260,7 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr)
"fork",
#endif
"gettext",
-#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
+#if defined(HAVE_ICONV)
"iconv",
#endif
"insert_expand",
@@ -11109,10 +11373,6 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr)
n = stdout_isatty;
} else if (STRICMP(name, "multi_byte_encoding") == 0) {
n = has_mbyte != 0;
-#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
- } else if (STRICMP(name, "iconv") == 0) {
- n = iconv_enabled(false);
-#endif
} else if (STRICMP(name, "syntax_items") == 0) {
n = syntax_present(curwin);
#ifdef UNIX
@@ -11935,9 +12195,18 @@ static void f_jobresize(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->vval.v_number = 1;
}
+/// Builds a process argument vector from a VimL object (typval_T).
+///
+/// @param[in] cmd_tv VimL object
+/// @param[out] cmd Returns the command or executable name.
+/// @param[out] executable Returns `false` if argv[0] is not executable.
+///
+/// @returns Result of `shell_build_argv()` if `cmd_tv` is a String.
+/// Else, string values of `cmd_tv` copied to a (char **) list with
+/// argv[0] resolved to full path ($PATHEXT-resolved on Windows).
static char **tv_to_argv(typval_T *cmd_tv, const char **cmd, bool *executable)
{
- if (cmd_tv->v_type == VAR_STRING) {
+ if (cmd_tv->v_type == VAR_STRING) { // String => "shell semantics".
const char *cmd_str = tv_get_string(cmd_tv);
if (cmd) {
*cmd = cmd_str;
@@ -11957,16 +12226,17 @@ static char **tv_to_argv(typval_T *cmd_tv, const char **cmd, bool *executable)
return NULL;
}
- const char *exe = tv_get_string_chk(TV_LIST_ITEM_TV(tv_list_first(argl)));
- if (!exe || !os_can_exe((const char_u *)exe, NULL, true)) {
- if (exe && executable) {
+ const char *arg0 = tv_get_string_chk(TV_LIST_ITEM_TV(tv_list_first(argl)));
+ char *exe_resolved = NULL;
+ if (!arg0 || !os_can_exe(arg0, &exe_resolved, true)) {
+ if (arg0 && executable) {
*executable = false;
}
return NULL;
}
if (cmd) {
- *cmd = exe;
+ *cmd = exe_resolved;
}
// Build the argument vector
@@ -11977,10 +12247,15 @@ static char **tv_to_argv(typval_T *cmd_tv, const char **cmd, bool *executable)
if (!a) {
// Did emsg in tv_get_string_chk; just deallocate argv.
shell_free_argv(argv);
+ xfree(exe_resolved);
return NULL;
}
argv[i++] = xstrdup(a);
});
+ // Replace argv[0] with absolute path. The only reason for this is to make
+ // $PATHEXT work on Windows with jobstart([…]). #9569
+ xfree(argv[0]);
+ argv[0] = exe_resolved;
return argv;
}
@@ -12080,14 +12355,21 @@ static void f_jobstop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
return;
}
-
Channel *data = find_job(argvars[0].vval.v_number, true);
if (!data) {
return;
}
+ const char *error = NULL;
+ if (data->is_rpc) {
+ // Ignore return code, but show error later.
+ (void)channel_close(data->id, kChannelPartRpc, &error);
+ }
process_stop((Process *)&data->stream.proc);
rettv->vval.v_number = 1;
+ if (error) {
+ EMSG(error);
+ }
}
// "jobwait(ids[, timeout])" function
@@ -13454,7 +13736,7 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
// 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 (*fname == NUL || (fd = mch_fopen(fname, READBIN)) == NULL) {
+ if (*fname == NUL || (fd = os_fopen(fname, READBIN)) == NULL) {
EMSG2(_(e_notopen), *fname == NUL ? _("<empty>") : fname);
return;
}
@@ -13686,11 +13968,7 @@ static void f_reltime(typval_T *argvars, typval_T *rettv, FunPtr fptr)
tv_list_append_number(rettv->vval.v_list, u.split.low);
}
-/// f_reltimestr - return a string that represents the value of {time}
-///
-/// @return The string representation of the argument, the format is the
-/// number of seconds followed by a dot, followed by the number
-/// of microseconds.
+/// "reltimestr()" function
static void f_reltimestr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
FUNC_ATTR_NONNULL_ALL
{
@@ -13699,7 +13977,7 @@ static void f_reltimestr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
rettv->v_type = VAR_STRING;
rettv->vval.v_string = NULL;
if (list2proftime(&argvars[0], &tm) == OK) {
- rettv->vval.v_string = (char_u *) xstrdup(profile_msg(tm));
+ rettv->vval.v_string = (char_u *)xstrdup(profile_msg(tm));
}
}
@@ -14501,10 +14779,10 @@ static int searchpair_cmn(typval_T *argvars, pos_T *match_pos)
long lnum_stop = 0;
long time_limit = 0;
- // Get the three pattern arguments: start, middle, end.
+ // Get the three pattern arguments: start, middle, end. Will result in an
+ // error if not a valid argument.
char nbuf1[NUMBUFLEN];
char nbuf2[NUMBUFLEN];
- char nbuf3[NUMBUFLEN];
const char *spat = tv_get_string_chk(&argvars[0]);
const char *mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
const char *epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
@@ -14532,23 +14810,28 @@ static int searchpair_cmn(typval_T *argvars, pos_T *match_pos)
}
// Optional fifth argument: skip expression.
- const char *skip;
+ const typval_T *skip;
if (argvars[3].v_type == VAR_UNKNOWN
|| argvars[4].v_type == VAR_UNKNOWN) {
- skip = "";
+ skip = NULL;
} else {
- skip = tv_get_string_buf_chk(&argvars[4], nbuf3);
- if (skip == NULL) {
+ skip = &argvars[4];
+ if (skip->v_type != VAR_FUNC
+ && skip->v_type != VAR_PARTIAL
+ && skip->v_type != VAR_STRING) {
+ emsgf(_(e_invarg2), tv_get_string(&argvars[4]));
goto theend; // Type error.
}
if (argvars[5].v_type != VAR_UNKNOWN) {
lnum_stop = tv_get_number_chk(&argvars[5], NULL);
if (lnum_stop < 0) {
+ emsgf(_(e_invarg2), tv_get_string(&argvars[5]));
goto theend;
}
if (argvars[6].v_type != VAR_UNKNOWN) {
time_limit = tv_get_number_chk(&argvars[6], NULL);
if (time_limit < 0) {
+ emsgf(_(e_invarg2), tv_get_string(&argvars[6]));
goto theend;
}
}
@@ -14556,7 +14839,7 @@ static int searchpair_cmn(typval_T *argvars, pos_T *match_pos)
}
retval = do_searchpair(
- (char_u *)spat, (char_u *)mpat, (char_u *)epat, dir, (char_u *)skip,
+ (char_u *)spat, (char_u *)mpat, (char_u *)epat, dir, skip,
flags, match_pos, lnum_stop, time_limit);
theend:
@@ -14604,7 +14887,7 @@ do_searchpair(
char_u *mpat, // middle pattern
char_u *epat, // end pattern
int dir, // BACKWARD or FORWARD
- char_u *skip, // skip expression
+ 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
@@ -14620,8 +14903,8 @@ do_searchpair(
pos_T save_cursor;
pos_T save_pos;
int n;
- int r;
int nest = 1;
+ bool use_skip = false;
int options = SEARCH_KEEP;
proftime_T tm;
size_t pat2_len;
@@ -14651,6 +14934,13 @@ do_searchpair(
options |= SEARCH_START;
}
+ if (skip != NULL) {
+ // Empty string means to not use the skip expression.
+ if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC) {
+ use_skip = skip->vval.v_string != NULL && *skip->vval.v_string != NUL;
+ }
+ }
+
save_cursor = curwin->w_cursor;
pos = curwin->w_cursor;
clearpos(&firstpos);
@@ -14680,12 +14970,12 @@ do_searchpair(
/* clear the start flag to avoid getting stuck here */
options &= ~SEARCH_START;
- /* If the skip pattern matches, ignore this match. */
- if (*skip != NUL) {
+ // If the skip pattern matches, ignore this match.
+ if (use_skip) {
save_pos = curwin->w_cursor;
curwin->w_cursor = pos;
- bool err;
- r = eval_to_bool(skip, &err, NULL, false);
+ bool err = false;
+ const bool r = eval_expr_to_bool(skip, &err);
curwin->w_cursor = save_pos;
if (err) {
/* Evaluating {skip} caused an error, break here. */
@@ -14846,6 +15136,123 @@ static void f_serverstop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
+/// Set line or list of lines in buffer "buf".
+static void set_buffer_lines(buf_T *buf, linenr_T lnum, typval_T *lines,
+ typval_T *rettv)
+{
+ list_T *l = NULL;
+ listitem_T *li = NULL;
+ long added = 0;
+ linenr_T lcount;
+ buf_T *curbuf_save = NULL;
+ win_T *curwin_save = NULL;
+ int is_curbuf = buf == curbuf;
+
+ // When using the current buffer ml_mfp will be set if needed. Useful when
+ // setline() is used on startup. For other buffers the buffer must be
+ // loaded.
+ if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1) {
+ rettv->vval.v_number = 1; // FAIL
+ return;
+ }
+
+ if (!is_curbuf) {
+ wininfo_T *wip;
+
+ curbuf_save = curbuf;
+ curwin_save = curwin;
+ curbuf = buf;
+ for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next) {
+ if (wip->wi_win != NULL) {
+ curwin = wip->wi_win;
+ break;
+ }
+ }
+ }
+
+ lcount = curbuf->b_ml.ml_line_count;
+
+ const char *line = NULL;
+
+ if (lines->v_type == VAR_LIST) {
+ l = lines->vval.v_list;
+ li = tv_list_first(l);
+ } else {
+ line = tv_get_string_chk(lines);
+ }
+
+ // Default result is zero == OK.
+ for (;; ) {
+ if (lines->v_type == VAR_LIST) {
+ // List argument, get next string.
+ if (li == NULL) {
+ break;
+ }
+ line = tv_get_string_chk(TV_LIST_ITEM_TV(li));
+ li = TV_LIST_ITEM_NEXT(l, li);
+ }
+
+ rettv->vval.v_number = 1; // FAIL
+ if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1) {
+ break;
+ }
+
+ // When coming here from Insert mode, sync undo, so that this can be
+ // undone separately from what was previously inserted.
+ if (u_sync_once == 2) {
+ u_sync_once = 1; // notify that u_sync() was called
+ u_sync(true);
+ }
+
+ if (lnum <= curbuf->b_ml.ml_line_count) {
+ // Existing line, replace it.
+ if (u_savesub(lnum) == OK
+ && ml_replace(lnum, (char_u *)line, true) == OK) {
+ changed_bytes(lnum, 0);
+ if (is_curbuf && lnum == curwin->w_cursor.lnum) {
+ check_cursor_col();
+ }
+ rettv->vval.v_number = 0; // OK
+ }
+ } else if (added > 0 || u_save(lnum - 1, lnum) == OK) {
+ // lnum is one past the last line, append the line.
+ added++;
+ if (ml_append(lnum - 1, (char_u *)line, 0, false) == OK) {
+ rettv->vval.v_number = 0; // OK
+ }
+ }
+
+ if (l == NULL) /* only one string argument */
+ break;
+ ++lnum;
+ }
+
+ if (added > 0) {
+ appended_lines_mark(lcount, added);
+ }
+
+ if (!is_curbuf) {
+ curbuf = curbuf_save;
+ curwin = curwin_save;
+ }
+}
+
+/// "setbufline()" function
+static void f_setbufline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ 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, &argvars[2], rettv);
+ }
+}
+
/*
* "setbufvar()" function
*/
@@ -14941,6 +15348,20 @@ static void f_setcmdpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
+/// "setenv()" function
+static void f_setenv(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ char namebuf[NUMBUFLEN];
+ char valbuf[NUMBUFLEN];
+ const char *name = tv_get_string_buf(&argvars[0], namebuf);
+
+ if (argvars[1].v_type == VAR_SPECIAL
+ && argvars[1].vval.v_number == kSpecialVarNull) {
+ os_unsetenv(name);
+ } else {
+ os_setenv(name, tv_get_string_buf(&argvars[1], valbuf), 1);
+ }
+}
/// "setfperm({fname}, {mode})" function
static void f_setfperm(typval_T *argvars, typval_T *rettv, FunPtr fptr)
@@ -14978,67 +15399,8 @@ static void f_setfperm(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_setline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- list_T *l = NULL;
- listitem_T *li = NULL;
- long added = 0;
- linenr_T lcount = curbuf->b_ml.ml_line_count;
-
linenr_T lnum = tv_get_lnum(&argvars[0]);
- const char *line = NULL;
- if (argvars[1].v_type == VAR_LIST) {
- l = argvars[1].vval.v_list;
- li = tv_list_first(l);
- } else {
- line = tv_get_string_chk(&argvars[1]);
- }
-
- // Default result is zero == OK.
- for (;; ) {
- if (argvars[1].v_type == VAR_LIST) {
- // List argument, get next string.
- if (li == NULL) {
- break;
- }
- line = tv_get_string_chk(TV_LIST_ITEM_TV(li));
- li = TV_LIST_ITEM_NEXT(l, li);
- }
-
- rettv->vval.v_number = 1; // FAIL
- if (line == NULL || lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1) {
- break;
- }
-
- /* When coming here from Insert mode, sync undo, so that this can be
- * undone separately from what was previously inserted. */
- if (u_sync_once == 2) {
- u_sync_once = 1; /* notify that u_sync() was called */
- u_sync(TRUE);
- }
-
- if (lnum <= curbuf->b_ml.ml_line_count) {
- // Existing line, replace it.
- if (u_savesub(lnum) == OK
- && ml_replace(lnum, (char_u *)line, true) == OK) {
- changed_bytes(lnum, 0);
- if (lnum == curwin->w_cursor.lnum)
- check_cursor_col();
- rettv->vval.v_number = 0; /* OK */
- }
- } else if (added > 0 || u_save(lnum - 1, lnum) == OK) {
- // lnum is one past the last line, append the line.
- added++;
- if (ml_append(lnum - 1, (char_u *)line, 0, false) == OK) {
- rettv->vval.v_number = 0; // OK
- }
- }
-
- if (l == NULL) /* only one string argument */
- break;
- ++lnum;
- }
-
- if (added > 0)
- appended_lines_mark(lcount, added);
+ set_buffer_lines(curbuf, lnum, &argvars[1], rettv);
}
/// Create quickfix/location list from VimL values
@@ -15390,7 +15752,7 @@ free_lstval:
if (set_unnamed) {
// Discard the result. We already handle the error case.
- if (op_register_set_previous(regname)) { }
+ if (op_reg_set_previous(regname)) { }
}
}
@@ -15503,7 +15865,7 @@ static void f_setwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
static void setwinvar(typval_T *argvars, typval_T *rettv, int off)
{
- if (check_restricted() || check_secure()) {
+ if (check_secure()) {
return;
}
@@ -15681,6 +16043,7 @@ static void f_sign_getplaced(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (notanum) {
return;
}
+ (void)lnum;
lnum = tv_get_lnum(&di->di_tv);
}
if ((di = tv_dict_find(dict, "id", -1)) != NULL) {
@@ -15735,9 +16098,6 @@ static void f_sign_jump(typval_T *argvars, typval_T *rettv, FunPtr fptr)
sign_group = NULL; // global sign group
} else {
sign_group = xstrdup(sign_group_chk);
- if (sign_group == NULL) {
- return;
- }
}
// Buffer to place the sign
@@ -15786,9 +16146,6 @@ static void f_sign_place(typval_T *argvars, typval_T *rettv, FunPtr fptr)
group = NULL; // global sign group
} else {
group = vim_strsave((const char_u *)group_chk);
- if (group == NULL) {
- return;
- }
}
// Sign name
@@ -15816,6 +16173,7 @@ static void f_sign_place(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (notanum) {
goto cleanup;
}
+ (void)lnum;
lnum = tv_get_lnum(&di->di_tv);
}
if ((di = tv_dict_find(dict, "priority", -1)) != NULL) {
@@ -15881,9 +16239,6 @@ static void f_sign_unplace(typval_T *argvars, typval_T *rettv, FunPtr fptr)
group = NULL; // global sign group
} else {
group = vim_strsave((const char_u *)group_chk);
- if (group == NULL) {
- return;
- }
}
if (argvars[1].v_type != VAR_UNKNOWN) {
@@ -16352,9 +16707,7 @@ static void f_uniq(typval_T *argvars, typval_T *rettv, FunPtr fptr)
do_sort_uniq(argvars, rettv, false);
}
-//
// "reltimefloat()" function
-//
static void f_reltimefloat(typval_T *argvars , typval_T *rettv, FunPtr fptr)
FUNC_ATTR_NONNULL_ALL
{
@@ -16363,7 +16716,7 @@ static void f_reltimefloat(typval_T *argvars , typval_T *rettv, FunPtr fptr)
rettv->v_type = VAR_FLOAT;
rettv->vval.v_float = 0;
if (list2proftime(&argvars[0], &tm) == OK) {
- rettv->vval.v_float = ((float_T)tm) / 1000000000;
+ rettv->vval.v_float = (float_T)profile_signed(tm) / 1000000000.0;
}
}
@@ -16406,6 +16759,8 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, FunPtr fptr)
break;
}
str += len;
+ capcol -= len;
+ len = 0;
}
}
}
@@ -17776,7 +18131,6 @@ static void add_timer_info(typval_T *rettv, timer_T *timer)
di->di_tv.v_type = VAR_FUNC;
di->di_tv.vval.v_string = vim_strsave(timer->callback.data.funcref);
}
- di->di_tv.v_lock = 0;
}
static void add_timer_info_all(typval_T *rettv)
@@ -19033,8 +19387,11 @@ static int get_name_len(const char **const arg,
}
len += get_id_len(arg);
- if (len == 0 && verbose)
+ // Only give an error when there is something, otherwise it will be
+ // reported at a higher level.
+ if (len == 0 && verbose && **arg != NUL) {
EMSG2(_(e_invexpr2), *arg);
+ }
return len;
}
@@ -20047,6 +20404,24 @@ static 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);
+}
+
+/// Set variable to the given value
+///
+/// If the variable already exists, the value is updated. Otherwise the variable
+/// is created.
+///
+/// @param[in] name Variable name to set.
+/// @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.
+/// @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)
+ FUNC_ATTR_NONNULL_ALL
+{
dictitem_T *v;
hashtab_T *ht;
dict_T *dict;
@@ -20072,6 +20447,11 @@ static void set_var(const char *name, const size_t name_len, typval_T *const tv,
typval_T oldtv = TV_INITIAL_VALUE;
if (v != NULL) {
+ if (is_const) {
+ EMSG(_(e_cannot_mod));
+ return;
+ }
+
// existing variable, need to clear the value
if (var_check_ro(v->di_flags, name, name_len)
|| tv_check_lock(v->di_tv.v_lock, name, name_len)) {
@@ -20138,6 +20518,9 @@ static void set_var(const char *name, const size_t name_len, typval_T *const tv,
return;
}
v->di_flags = DI_FLAGS_ALLOC;
+ if (is_const) {
+ v->di_flags |= DI_FLAGS_LOCK;
+ }
}
if (copy || tv->v_type == VAR_NUMBER || tv->v_type == VAR_FLOAT) {
@@ -20156,6 +20539,10 @@ static void set_var(const char *name, const size_t name_len, typval_T *const tv,
tv_clear(&oldtv);
}
}
+
+ if (is_const) {
+ v->di_tv.v_lock |= VAR_LOCKED;
+ }
}
/// Check whether variable is read-only (DI_FLAGS_RO, DI_FLAGS_RO_SBX)
@@ -20480,29 +20867,19 @@ void ex_echohl(exarg_T *eap)
*/
void ex_execute(exarg_T *eap)
{
- char_u *arg = eap->arg;
+ char_u *arg = eap->arg;
typval_T rettv;
int ret = OK;
- char_u *p;
garray_T ga;
- int save_did_emsg = did_emsg;
+ int save_did_emsg;
ga_init(&ga, 1, 80);
if (eap->skip)
++emsg_skip;
while (*arg != NUL && *arg != '|' && *arg != '\n') {
- p = arg;
- if (eval1(&arg, &rettv, !eap->skip) == FAIL) {
- /*
- * 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 == save_did_emsg) {
- EMSG2(_(e_invexpr2), p);
- }
- ret = FAIL;
+ ret = eval1_emsg(&arg, &rettv, !eap->skip);
+ if (ret == FAIL) {
break;
}
@@ -20632,8 +21009,11 @@ void ex_function(exarg_T *eap)
if (!HASHITEM_EMPTY(hi)) {
--todo;
fp = HI2UF(hi);
+ if (message_filtered(fp->uf_name)) {
+ continue;
+ }
if (!func_name_refcount(fp->uf_name)) {
- list_func_head(fp, false);
+ list_func_head(fp, false, false);
}
}
}
@@ -20664,7 +21044,7 @@ void ex_function(exarg_T *eap)
fp = HI2UF(hi);
if (!isdigit(*fp->uf_name)
&& vim_regexec(&regmatch, fp->uf_name, 0))
- list_func_head(fp, FALSE);
+ list_func_head(fp, false, false);
}
}
vim_regfree(regmatch.regprog);
@@ -20714,9 +21094,12 @@ void ex_function(exarg_T *eap)
saved_did_emsg = did_emsg;
did_emsg = FALSE;
- /*
- * ":function func" with only function name: list function.
- */
+ //
+ // ":function func" with only function name: list function.
+ // If bang is given:
+ // - include "!" in function head
+ // - exclude line numbers from function body
+ //
if (!paren) {
if (!ends_excmd(*skipwhite(p))) {
EMSG(_(e_trailing));
@@ -20728,17 +21111,20 @@ void ex_function(exarg_T *eap)
if (!eap->skip && !got_int) {
fp = find_func(name);
if (fp != NULL) {
- list_func_head(fp, TRUE);
- for (int j = 0; j < fp->uf_lines.ga_len && !got_int; ++j) {
- if (FUNCLINE(fp, j) == NULL)
+ list_func_head(fp, !eap->forceit, eap->forceit);
+ for (int j = 0; j < fp->uf_lines.ga_len && !got_int; j++) {
+ if (FUNCLINE(fp, j) == NULL) {
continue;
- msg_putchar('\n');
- msg_outnum((long)j + 1);
- if (j < 9) {
- msg_putchar(' ');
}
- if (j < 99) {
- msg_putchar(' ');
+ msg_putchar('\n');
+ if (!eap->forceit) {
+ msg_outnum((long)j + 1);
+ if (j < 9) {
+ msg_putchar(' ');
+ }
+ if (j < 99) {
+ msg_putchar(' ');
+ }
}
msg_prt_line(FUNCLINE(fp, j), false);
ui_flush(); // show a line at a time
@@ -20746,7 +21132,7 @@ void ex_function(exarg_T *eap)
}
if (!got_int) {
msg_putchar('\n');
- msg_puts(" endfunction");
+ msg_puts(eap->forceit ? "endfunction" : " endfunction");
}
} else
emsg_funcname(N_("E123: Undefined function: %s"), name);
@@ -20895,7 +21281,8 @@ void ex_function(exarg_T *eap)
goto erret;
}
if (show_block) {
- ui_ext_cmdline_block_append(indent, (const char *)theline);
+ assert(indent >= 0);
+ ui_ext_cmdline_block_append((size_t)indent, (const char *)theline);
}
/* Detect line continuation: sourcing_lnum increased more than one. */
@@ -21064,9 +21451,10 @@ void ex_function(exarg_T *eap)
overwrite = true;
} else {
// redefine existing function
- ga_clear_strings(&(fp->uf_args));
- ga_clear_strings(&(fp->uf_lines));
XFREE_CLEAR(name);
+ func_clear_items(fp);
+ fp->uf_profiling = false;
+ fp->uf_prof_initialized = false;
}
}
} else {
@@ -21137,7 +21525,6 @@ void ex_function(exarg_T *eap)
tv_clear(&fudi.fd_di->di_tv);
}
fudi.fd_di->di_tv.v_type = VAR_FUNC;
- fudi.fd_di->di_tv.v_lock = 0;
fudi.fd_di->di_tv.vval.v_string = vim_strsave(name);
/* behave like "dict" was used */
@@ -21162,12 +21549,9 @@ void ex_function(exarg_T *eap)
} else {
fp->uf_scoped = NULL;
}
- fp->uf_tml_count = NULL;
- fp->uf_tml_total = NULL;
- fp->uf_tml_self = NULL;
- fp->uf_profiling = FALSE;
- if (prof_def_func())
+ if (prof_def_func()) {
func_do_profile(fp);
+ }
fp->uf_varargs = varargs;
if (sandbox) {
flags |= FC_SANDBOX;
@@ -21438,15 +21822,17 @@ static inline bool eval_fname_sid(const char *const name)
return *name == 's' || TOUPPER_ASC(name[2]) == 'I';
}
-/*
- * List the head of the function: "name(arg1, arg2)".
- */
-static void list_func_head(ufunc_T *fp, int indent)
+/// List the head of the function: "name(arg1, arg2)".
+///
+/// @param[in] fp Function pointer.
+/// @param[in] indent Indent line.
+/// @param[in] force Include bang "!" (i.e.: "function!").
+static void list_func_head(ufunc_T *fp, int indent, bool force)
{
msg_start();
if (indent)
MSG_PUTS(" ");
- MSG_PUTS("function ");
+ MSG_PUTS(force ? "function! " : "function ");
if (fp->uf_name[0] == K_SPECIAL) {
MSG_PUTS_ATTR("<SNR>", HL_ATTR(HLF_8));
msg_puts((const char *)fp->uf_name + 3);
@@ -21628,25 +22014,29 @@ static void func_do_profile(ufunc_T *fp)
{
int len = fp->uf_lines.ga_len;
- if (len == 0)
- len = 1; /* avoid getting error for allocating zero bytes */
- fp->uf_tm_count = 0;
- fp->uf_tm_self = profile_zero();
- fp->uf_tm_total = profile_zero();
+ if (!fp->uf_prof_initialized) {
+ if (len == 0) {
+ len = 1; // avoid getting error for allocating zero bytes
+ }
+ fp->uf_tm_count = 0;
+ fp->uf_tm_self = profile_zero();
+ fp->uf_tm_total = profile_zero();
- if (fp->uf_tml_count == NULL) {
- fp->uf_tml_count = xcalloc(len, sizeof(int));
- }
+ if (fp->uf_tml_count == NULL) {
+ fp->uf_tml_count = xcalloc(len, sizeof(int));
+ }
- if (fp->uf_tml_total == NULL) {
- fp->uf_tml_total = xcalloc(len, sizeof(proftime_T));
- }
+ if (fp->uf_tml_total == NULL) {
+ fp->uf_tml_total = xcalloc(len, sizeof(proftime_T));
+ }
- if (fp->uf_tml_self == NULL) {
- fp->uf_tml_self = xcalloc(len, sizeof(proftime_T));
- }
+ if (fp->uf_tml_self == NULL) {
+ fp->uf_tml_self = xcalloc(len, sizeof(proftime_T));
+ }
- fp->uf_tml_idx = -1;
+ fp->uf_tml_idx = -1;
+ fp->uf_prof_initialized = true;
+ }
fp->uf_profiling = TRUE;
}
@@ -21672,7 +22062,7 @@ void func_dump_profile(FILE *fd)
if (!HASHITEM_EMPTY(hi)) {
--todo;
fp = HI2UF(hi);
- if (fp->uf_profiling) {
+ if (fp->uf_prof_initialized) {
sorttab[st_len++] = fp;
if (fp->uf_name[0] == K_SPECIAL)
@@ -21832,6 +22222,7 @@ static bool script_autoload(const char *const name, const size_t name_len,
}
/// Return the autoload script name for a function or variable name
+/// Caller must make sure that "name" contains AUTOLOAD_CHAR.
///
/// @param[in] name Variable/function name.
/// @param[in] name_len Name length.
@@ -22015,6 +22406,16 @@ static bool func_remove(ufunc_T *fp)
return false;
}
+static void func_clear_items(ufunc_T *fp)
+{
+ ga_clear_strings(&(fp->uf_args));
+ ga_clear_strings(&(fp->uf_lines));
+
+ XFREE_CLEAR(fp->uf_tml_count);
+ XFREE_CLEAR(fp->uf_tml_total);
+ XFREE_CLEAR(fp->uf_tml_self);
+}
+
/// Free all things that a function contains. Does not free the function
/// itself, use func_free() for that.
///
@@ -22027,11 +22428,7 @@ static void func_clear(ufunc_T *fp, bool force)
fp->uf_cleared = true;
// clear this function
- ga_clear_strings(&(fp->uf_args));
- ga_clear_strings(&(fp->uf_lines));
- xfree(fp->uf_tml_count);
- xfree(fp->uf_tml_total);
- xfree(fp->uf_tml_self);
+ func_clear_items(fp);
funccal_unref(fp->uf_scoped, fp, force);
}
@@ -22174,6 +22571,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
char_u *name;
proftime_T wait_start;
proftime_T call_start;
+ int started_profiling = false;
bool did_save_redo = false;
save_redo_T save_redo;
@@ -22393,8 +22791,10 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
do_profiling_yes
&& !fp->uf_profiling && has_profiling(false, fp->uf_name, NULL);
- if (func_not_yet_profiling_but_should)
+ if (func_not_yet_profiling_but_should) {
+ started_profiling = true;
func_do_profile(fp);
+ }
bool func_or_func_caller_profiling =
do_profiling_yes
@@ -22442,6 +22842,10 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
fc->caller->func->uf_tml_children =
profile_add(fc->caller->func->uf_tml_children, call_start);
}
+ if (started_profiling) {
+ // make a ":profdel func" stop profiling the function
+ fp->uf_profiling = false;
+ }
}
/* when being verbose, mention the return value */
@@ -23012,7 +23416,7 @@ dictitem_T *find_var_in_scoped_ht(const char *name, const size_t namelen,
/// @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)
+ typval_T *rettv, var_flavour_T flavour)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(2, 3)
{
const hashitem_T *hi;
@@ -23023,7 +23427,7 @@ const void *var_shada_iter(const void *const iter, const char **const name,
hi = globvarht.ht_array;
while ((size_t) (hi - hifirst) < hinum
&& (HASHITEM_EMPTY(hi)
- || var_flavour(hi->hi_key) != VAR_FLAVOUR_SHADA)) {
+ || !(var_flavour(hi->hi_key) & flavour))) {
hi++;
}
if ((size_t) (hi - hifirst) == hinum) {
@@ -23035,7 +23439,7 @@ const void *var_shada_iter(const void *const iter, const char **const name,
*name = (char *)TV_DICT_HI2DI(hi)->di_key;
tv_copy(&TV_DICT_HI2DI(hi)->di_tv, rettv);
while ((size_t)(++hi - hifirst) < hinum) {
- if (!HASHITEM_EMPTY(hi) && var_flavour(hi->hi_key) == VAR_FLAVOUR_SHADA) {
+ if (!HASHITEM_EMPTY(hi) && (var_flavour(hi->hi_key) & flavour)) {
return hi;
}
}
@@ -23609,50 +24013,57 @@ typval_T eval_call_provider(char *provider, char *method, list_T *arguments)
return rettv;
}
+/// Checks if a named provider is enabled.
bool eval_has_provider(const char *name)
{
-#define CHECK_PROVIDER(name) \
- if (has_##name == -1) { \
- has_##name = !!find_func((char_u *)"provider#" #name "#Call"); \
- if (!has_##name) { \
- script_autoload("provider#" #name "#Call", \
- sizeof("provider#" #name "#Call") - 1, \
- false); \
- has_##name = !!find_func((char_u *)"provider#" #name "#Call"); \
- } \
- }
-
- static int has_clipboard = -1;
- static int has_python = -1;
- static int has_python3 = -1;
- static int has_ruby = -1;
-
- if (strequal(name, "clipboard")) {
- CHECK_PROVIDER(clipboard);
- return has_clipboard;
- } else if (strequal(name, "python3")) {
- CHECK_PROVIDER(python3);
- return has_python3;
- } else if (strequal(name, "python")) {
- CHECK_PROVIDER(python);
- return has_python;
- } else if (strequal(name, "ruby")) {
- bool need_check_ruby = (has_ruby == -1);
- CHECK_PROVIDER(ruby);
- if (need_check_ruby && has_ruby == 1) {
- char *rubyhost = call_func_retstr("provider#ruby#Detect", 0, NULL, true);
- if (rubyhost) {
- if (*rubyhost == NUL) {
- // Invalid rubyhost executable. Gem is probably not installed.
- has_ruby = 0;
- }
- xfree(rubyhost);
+ if (!strequal(name, "clipboard")
+ && !strequal(name, "python")
+ && !strequal(name, "python3")
+ && !strequal(name, "ruby")
+ && !strequal(name, "node")) {
+ // Avoid autoload for non-provider has() features.
+ return false;
+ }
+
+ char buf[256];
+ int len;
+ typval_T tv;
+
+ // Get the g:loaded_xx_provider variable.
+ len = snprintf(buf, sizeof(buf), "g:loaded_%s_provider", name);
+ if (get_var_tv(buf, len, &tv, NULL, false, true) == FAIL) {
+ // Trigger autoload once.
+ len = snprintf(buf, sizeof(buf), "provider#%s#bogus", name);
+ script_autoload(buf, len, false);
+
+ // Retry the (non-autoload-style) variable.
+ len = snprintf(buf, sizeof(buf), "g:loaded_%s_provider", name);
+ if (get_var_tv(buf, len, &tv, NULL, false, true) == FAIL) {
+ // Show a hint if Call() is defined but g:loaded_xx_provider is missing.
+ snprintf(buf, sizeof(buf), "provider#%s#Call", name);
+ if (!!find_func((char_u *)buf) && p_lpl) {
+ emsgf("provider: %s: missing required variable g:loaded_%s_provider",
+ name, name);
}
+ return false;
}
- return has_ruby;
}
- return false;
+ bool ok = (tv.v_type == VAR_NUMBER)
+ ? 2 == tv.vval.v_number // Value of 2 means "loaded and working".
+ : false;
+
+ if (ok) {
+ // Call() must be defined if provider claims to be working.
+ snprintf(buf, sizeof(buf), "provider#%s#Call", name);
+ if (!find_func((char_u *)buf)) {
+ emsgf("provider: %s: g:loaded_%s_provider=2 but %s is not defined",
+ name, name, buf);
+ ok = false;
+ }
+ }
+
+ return ok;
}
/// Writes "<sourcing_name>:<sourcing_lnum>" to `buf[bufsize]`.
diff --git a/src/nvim/eval.h b/src/nvim/eval.h
index 149dae688e..abe032a96e 100644
--- a/src/nvim/eval.h
+++ b/src/nvim/eval.h
@@ -24,6 +24,13 @@ EXTERN ufunc_T dumuf;
#define HIKEY2UF(p) ((ufunc_T *)(p - offsetof(ufunc_T, uf_name)))
#define HI2UF(hi) HIKEY2UF((hi)->hi_key)
+/// enum used by var_flavour()
+typedef enum {
+ VAR_FLAVOUR_DEFAULT = 1, // doesn't start with uppercase
+ VAR_FLAVOUR_SESSION = 2, // starts with uppercase, some lower
+ VAR_FLAVOUR_SHADA = 4 // all uppercase
+} var_flavour_T;
+
/// Defines for Vim variables
typedef enum {
VV_COUNT,
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index f36a7ea6c0..db45409e77 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -20,10 +20,10 @@ return {
['and']={args=2},
api_info={},
append={args=2},
- argc={},
+ argc={args={0, 1}},
argidx={},
arglistid={args={0, 2}},
- argv={args={0, 1}},
+ argv={args={0, 2}},
asin={args=1, func="float_op_wrapper", data="&asin"}, -- WJMc
assert_beeps={args={1, 2}},
assert_equal={args={2, 3}},
@@ -40,11 +40,13 @@ return {
atan2={args=2},
browse={args=4},
browsedir={args=2},
+ bufadd={args=1},
bufexists={args=1},
buffer_exists={args=1, func='f_bufexists'}, -- obsolete
buffer_name={args=1, func='f_bufname'}, -- obsolete
buffer_number={args=1, func='f_bufnr'}, -- obsolete
buflisted={args=1},
+ bufload={args=1},
bufloaded={args=1},
bufname={args=1},
bufnr={args={1, 2}},
@@ -72,6 +74,11 @@ return {
cosh={args=1, func="float_op_wrapper", data="&cosh"},
count={args={2, 4}},
cscope_connection={args={0, 3}},
+ ctxget={args={0, 1}},
+ ctxpop={},
+ ctxpush={args={0, 1}},
+ ctxset={args={1, 2}},
+ ctxsize={},
cursor={args={1, 3}},
deepcopy={args={1, 2}},
delete={args={1,2}},
@@ -82,6 +89,7 @@ return {
diff_filler={args=1},
diff_hlID={args=2},
empty={args=1},
+ environ={},
escape={args=2},
eval={args=1},
eventhandler={},
@@ -128,6 +136,7 @@ return {
getcompletion={args={2, 3}},
getcurpos={},
getcwd={args={0,2}},
+ getenv={args={1}},
getfontname={args={0, 1}},
getfperm={args=1},
getfsize={args=1},
@@ -263,9 +272,11 @@ return {
serverlist={},
serverstart={args={0, 1}},
serverstop={args=1},
+ setbufline={args=3},
setbufvar={args=3},
setcharsearch={args=1},
setcmdpos={args=1},
+ setenv={args=2},
setfperm={args=2},
setline={args=2},
setloclist={args={2, 4}},
diff --git a/src/nvim/eval/executor.c b/src/nvim/eval/executor.c
index e972c506dd..8cd21f8d62 100644
--- a/src/nvim/eval/executor.c
+++ b/src/nvim/eval/executor.c
@@ -74,8 +74,8 @@ int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2,
case '+': n += tv_get_number(tv2); break;
case '-': n -= tv_get_number(tv2); break;
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;
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
index ffb46abfea..91a1d083c7 100644
--- a/src/nvim/eval/typval.c
+++ b/src/nvim/eval/typval.c
@@ -1221,7 +1221,8 @@ void tv_dict_watcher_notify(dict_T *const dict, const char *const key,
/// Allocate a dictionary item
///
-/// @note that the value of the item (->di_tv) still needs to be initialized.
+/// @note that the type and value of the item (->di_tv) still needs to
+/// be initialized.
///
/// @param[in] key Key, is copied to the new item.
/// @param[in] key_len Key length.
@@ -1235,12 +1236,14 @@ dictitem_T *tv_dict_item_alloc_len(const char *const key, const size_t key_len)
memcpy(di->di_key, key, key_len);
di->di_key[key_len] = NUL;
di->di_flags = DI_FLAGS_ALLOC;
+ di->di_tv.v_lock = VAR_UNLOCKED;
return di;
}
/// Allocate a dictionary item
///
-/// @note that the value of the item (->di_tv) still needs to be initialized.
+/// @note that the type and value of the item (->di_tv) still needs to
+/// be initialized.
///
/// @param[in] key Key, is copied to the new item.
///
@@ -1572,7 +1575,6 @@ int tv_dict_add_list(dict_T *const d, const char *const key,
{
dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
- item->di_tv.v_lock = VAR_UNLOCKED;
item->di_tv.v_type = VAR_LIST;
item->di_tv.vval.v_list = list;
tv_list_ref(list);
@@ -1597,7 +1599,6 @@ int tv_dict_add_dict(dict_T *const d, const char *const key,
{
dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
- item->di_tv.v_lock = VAR_UNLOCKED;
item->di_tv.v_type = VAR_DICT;
item->di_tv.vval.v_dict = dict;
dict->dv_refcount++;
@@ -1621,7 +1622,6 @@ int tv_dict_add_nr(dict_T *const d, const char *const key,
{
dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
- item->di_tv.v_lock = VAR_UNLOCKED;
item->di_tv.v_type = VAR_NUMBER;
item->di_tv.vval.v_number = nr;
if (tv_dict_add(d, item) == FAIL) {
@@ -1644,7 +1644,6 @@ int tv_dict_add_special(dict_T *const d, const char *const key,
{
dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
- item->di_tv.v_lock = VAR_UNLOCKED;
item->di_tv.v_type = VAR_SPECIAL;
item->di_tv.vval.v_special = val;
if (tv_dict_add(d, item) == FAIL) {
@@ -1706,7 +1705,6 @@ int tv_dict_add_allocated_str(dict_T *const d,
{
dictitem_T *const item = tv_dict_item_alloc_len(key, key_len);
- item->di_tv.v_lock = VAR_UNLOCKED;
item->di_tv.v_type = VAR_STRING;
item->di_tv.vval.v_string = (char_u *)val;
if (tv_dict_add(d, item) == FAIL) {
diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h
index e99289c430..5c0f872b38 100644
--- a/src/nvim/eval/typval.h
+++ b/src/nvim/eval/typval.h
@@ -260,6 +260,7 @@ struct ufunc {
garray_T uf_args; ///< arguments
garray_T uf_lines; ///< function lines
int uf_profiling; ///< true when func is being profiled
+ int uf_prof_initialized;
// Profiling the function as a whole.
int uf_tm_count; ///< nr of calls
proftime_T uf_tm_total; ///< time spent in function + children
diff --git a/src/nvim/eval/typval_encode.c.h b/src/nvim/eval/typval_encode.c.h
index 623bdfc93b..289c3ee99c 100644
--- a/src/nvim/eval/typval_encode.c.h
+++ b/src/nvim/eval/typval_encode.c.h
@@ -382,7 +382,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
case VAR_SPECIAL: {
switch (tv->vval.v_special) {
case kSpecialVarNull: {
- TYPVAL_ENCODE_CONV_NIL(tv);
+ TYPVAL_ENCODE_CONV_NIL(tv); // -V1037
break;
}
case kSpecialVarTrue:
diff --git a/src/nvim/event/libuv_process.c b/src/nvim/event/libuv_process.c
index ffe2db9b76..63efee59a8 100644
--- a/src/nvim/event/libuv_process.c
+++ b/src/nvim/event/libuv_process.c
@@ -101,6 +101,10 @@ static void close_cb(uv_handle_t *handle)
static void exit_cb(uv_process_t *handle, int64_t status, int term_signal)
{
Process *proc = handle->data;
- proc->status = (int)status;
+#if defined(WIN32)
+ // Use stored/expected signal.
+ term_signal = proc->exit_signal;
+#endif
+ proc->status = term_signal ? 128 + term_signal : (int)status;
proc->internal_exit_cb(proc);
}
diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c
index 7a8a39dbcf..c31ecdaddf 100644
--- a/src/nvim/event/process.c
+++ b/src/nvim/event/process.c
@@ -26,6 +26,11 @@
// For PTY processes SIGTERM is sent first (in case SIGHUP was not enough).
#define KILL_TIMEOUT_MS 2000
+/// Externally defined with gcov.
+#ifdef USE_GCOV
+void __gcov_flush(void);
+#endif
+
static bool process_is_tearing_down = false;
/// @returns zero on success, or negative error code
@@ -50,6 +55,11 @@ int process_spawn(Process *proc, bool in, bool out, bool err)
proc->err.closed = true;
}
+#ifdef USE_GCOV
+ // Flush coverage data before forking, to avoid "Merge mismatch" errors.
+ __gcov_flush();
+#endif
+
int status;
switch (proc->type) {
case kProcessTypeUv:
@@ -149,7 +159,7 @@ void process_close_streams(Process *proc) FUNC_ATTR_NONNULL_ALL
/// 0 for no wait. -1 to wait until the process quits.
/// @return Exit code of the process. proc->status will have the same value.
/// -1 if the timeout expired while the process is still running.
-/// -2 if the user interruped the wait.
+/// -2 if the user interrupted the wait.
int process_wait(Process *proc, int ms, MultiQueue *events)
FUNC_ATTR_NONNULL_ARG(1)
{
@@ -210,13 +220,10 @@ void process_stop(Process *proc) FUNC_ATTR_NONNULL_ALL
return;
}
proc->stopped_time = os_hrtime();
+ proc->exit_signal = SIGTERM;
switch (proc->type) {
case kProcessTypeUv:
- // Close the process's stdin. If the process doesn't close its own
- // stdout/stderr, they will be closed when it exits(possibly due to being
- // terminated after a timeout)
- stream_may_close(&proc->in);
os_proc_tree_kill(proc->pid, SIGTERM);
break;
case kProcessTypePty:
@@ -247,8 +254,10 @@ static void children_kill_cb(uv_timer_t *handle)
}
uint64_t term_sent = UINT64_MAX == proc->stopped_time;
if (kProcessTypePty != proc->type || term_sent) {
+ proc->exit_signal = SIGKILL;
os_proc_tree_kill(proc->pid, SIGKILL);
} else {
+ proc->exit_signal = SIGTERM;
os_proc_tree_kill(proc->pid, SIGTERM);
proc->stopped_time = UINT64_MAX; // Flag: SIGTERM was sent.
// Restart timer.
@@ -397,4 +406,3 @@ static void on_process_stream_close(Stream *stream, void *data)
Process *proc = data;
decref(proc);
}
-
diff --git a/src/nvim/event/process.h b/src/nvim/event/process.h
index ba2c2a6a11..ef9d953ab7 100644
--- a/src/nvim/event/process.h
+++ b/src/nvim/event/process.h
@@ -19,6 +19,7 @@ struct process {
Loop *loop;
void *data;
int pid, status, refcount;
+ uint8_t exit_signal; // Signal used when killing (on Windows).
uint64_t stopped_time; // process_stop() timestamp
const char *cwd;
char **argv;
@@ -56,7 +57,8 @@ static inline Process process_init(Loop *loop, ProcessType type, void *data)
static inline bool process_is_stopped(Process *proc)
{
- return proc->stopped_time != 0;
+ bool exited = (proc->status >= 0);
+ return exited || (proc->stopped_time != 0);
}
#ifdef INCLUDE_GENERATED_DECLARATIONS
diff --git a/src/nvim/event/stream.c b/src/nvim/event/stream.c
index 7aaac0b03b..7c8014dead 100644
--- a/src/nvim/event/stream.c
+++ b/src/nvim/event/stream.c
@@ -113,6 +113,11 @@ void stream_close_handle(Stream *stream)
FUNC_ATTR_NONNULL_ALL
{
if (stream->uvstream) {
+ if (uv_stream_get_write_queue_size(stream->uvstream) > 0) {
+ WLOG("closed Stream (%p) with %zu unwritten bytes",
+ (void *)stream,
+ uv_stream_get_write_queue_size(stream->uvstream));
+ }
uv_close((uv_handle_t *)stream->uvstream, close_cb);
} else {
uv_close((uv_handle_t *)&stream->uv.idle, close_cb);
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index abed909008..a0fbde008b 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -20,6 +20,7 @@
#include "nvim/ascii.h"
#include "nvim/ex_cmds.h"
#include "nvim/buffer.h"
+#include "nvim/change.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
#include "nvim/diff.h"
@@ -335,7 +336,7 @@ static int linelen(int *has_tab)
len = linetabsize(line);
// Check for embedded TAB.
if (has_tab != NULL) {
- *has_tab = STRRCHR(first, TAB) != NULL;
+ *has_tab = vim_strchr(first, TAB) != NULL;
}
*last = save;
@@ -1230,7 +1231,7 @@ static void do_filter(
/* Create the shell command in allocated memory. */
cmd_buf = make_filter_cmd(cmd, itmp, otmp);
- ui_cursor_goto((int)Rows - 1, 0);
+ ui_cursor_goto(Rows - 1, 0);
if (do_out) {
if (u_save((linenr_T)(line2), (linenr_T)(line2 + 1)) == FAIL) {
@@ -1931,11 +1932,12 @@ void do_wqall(exarg_T *eap)
int error = 0;
int save_forceit = eap->forceit;
- if (eap->cmdidx == CMD_xall || eap->cmdidx == CMD_wqall)
- exiting = TRUE;
+ if (eap->cmdidx == CMD_xall || eap->cmdidx == CMD_wqall) {
+ exiting = true;
+ }
FOR_ALL_BUFFERS(buf) {
- if (!bufIsChanged(buf)) {
+ if (!bufIsChanged(buf) || bt_dontwrite(buf)) {
continue;
}
/*
@@ -2073,7 +2075,7 @@ int getfile(int fnum, char_u *ffname, char_u *sfname, int setpm, linenr_T lnum,
}
if (curbufIsChanged()) {
no_wait_return--;
- EMSG(_(e_nowrtmsg));
+ no_write_message();
retval = GETFILE_NOT_WRITTEN; // File has been changed.
goto theend;
}
@@ -4553,7 +4555,7 @@ void ex_help(exarg_T *eap)
} else {
// There is no help window yet.
// Try to open the file specified by the "helpfile" option.
- if ((helpfd = mch_fopen((char *)p_hf, READBIN)) == NULL) {
+ if ((helpfd = os_fopen((char *)p_hf, READBIN)) == NULL) {
smsg(_("Sorry, help file \"%s\" not found"), p_hf);
goto erret;
}
@@ -5083,7 +5085,7 @@ void fix_help_buffer(void)
continue;
}
- FILE *const fd = mch_fopen((char *)fnames[fi], "r");
+ FILE *const fd = os_fopen((char *)fnames[fi], "r");
if (fd == NULL) {
continue;
}
@@ -5219,17 +5221,15 @@ static void helptags_one(char_u *const dir, const char_u *const ext,
return;
}
- FILE *const fd_tags = mch_fopen((char *)NameBuff, "w");
+ FILE *const fd_tags = os_fopen((char *)NameBuff, "w");
if (fd_tags == NULL) {
EMSG2(_("E152: Cannot open %s for writing"), NameBuff);
FreeWild(filecount, files);
return;
}
- /*
- * If using the "++t" argument or generating tags for "$VIMRUNTIME/doc"
- * add the "help-tags" tag.
- */
+ // If using the "++t" argument or generating tags for "$VIMRUNTIME/doc"
+ // add the "help-tags" tag.
ga_init(&ga, (int)sizeof(char_u *), 100);
if (add_help_tags
|| path_full_compare((char_u *)"$VIMRUNTIME/doc",
@@ -5239,11 +5239,9 @@ static void helptags_one(char_u *const dir, const char_u *const ext,
GA_APPEND(char_u *, &ga, s);
}
- /*
- * Go over all the files and extract the tags.
- */
+ // Go over all the files and extract the tags.
for (int fi = 0; fi < filecount && !got_int; fi++) {
- FILE *const fd = mch_fopen((char *)files[fi], "r");
+ FILE *const fd = os_fopen((char *)files[fi], "r");
if (fd == NULL) {
EMSG2(_("E153: Unable to open %s for reading"), files[fi]);
continue;
@@ -5281,21 +5279,19 @@ static void helptags_one(char_u *const dir, const char_u *const ext,
}
firstline = false;
}
- p1 = vim_strchr(IObuff, '*'); /* find first '*' */
+ p1 = vim_strchr(IObuff, '*'); // find first '*'
while (p1 != NULL) {
p2 = (char_u *)strchr((const char *)p1 + 1, '*'); // Find second '*'.
- if (p2 != NULL && p2 > p1 + 1) { // Skip "*" and "**".
+ if (p2 != NULL && p2 > p1 + 1) { // Skip "*" and "**".
for (s = p1 + 1; s < p2; s++) {
if (*s == ' ' || *s == '\t' || *s == '|') {
break;
}
}
- /*
- * Only accept a *tag* when it consists of valid
- * characters, there is white space before it and is
- * followed by a white character or end-of-line.
- */
+ // Only accept a *tag* when it consists of valid
+ // characters, there is white space before it and is
+ // followed by a white character or end-of-line.
if (s == p2
&& (p1 == IObuff || p1[-1] == ' ' || p1[-1] == '\t')
&& (vim_strchr((char_u *)" \t\n\r", s[1]) != NULL
@@ -5306,7 +5302,7 @@ static void helptags_one(char_u *const dir, const char_u *const ext,
GA_APPEND(char_u *, &ga, s);
sprintf((char *)s, "%s\t%s", p1, fname);
- /* find next '*' */
+ // find next '*'
p2 = vim_strchr(p2 + 1, '*');
}
}
@@ -5320,18 +5316,12 @@ static void helptags_one(char_u *const dir, const char_u *const ext,
FreeWild(filecount, files);
- if (!got_int) {
- /*
- * Sort the tags.
- */
- if (ga.ga_data != NULL) {
- sort_strings((char_u **)ga.ga_data, ga.ga_len);
- }
+ if (!got_int && ga.ga_data != NULL) {
+ // Sort the tags.
+ sort_strings((char_u **)ga.ga_data, ga.ga_len);
- /*
- * Check for duplicates.
- */
- for (int i = 1; i < ga.ga_len; ++i) {
+ // Check for duplicates.
+ for (int i = 1; i < ga.ga_len; i++) {
p1 = ((char_u **)ga.ga_data)[i - 1];
p2 = ((char_u **)ga.ga_data)[i];
while (*p1 == *p2) {
@@ -5353,31 +5343,31 @@ static void helptags_one(char_u *const dir, const char_u *const ext,
fprintf(fd_tags, "!_TAG_FILE_ENCODING\tutf-8\t//\n");
}
- /*
- * Write the tags into the file.
- */
- for (int i = 0; i < ga.ga_len; ++i) {
+ // Write the tags into the file.
+ for (int i = 0; i < ga.ga_len; i++) {
s = ((char_u **)ga.ga_data)[i];
- if (STRNCMP(s, "help-tags\t", 10) == 0)
- /* help-tags entry was added in formatted form */
+ if (STRNCMP(s, "help-tags\t", 10) == 0) {
+ // help-tags entry was added in formatted form
fputs((char *)s, fd_tags);
- else {
- fprintf(fd_tags, "%s\t/*", s);
- for (p1 = s; *p1 != '\t'; ++p1) {
- /* insert backslash before '\\' and '/' */
- if (*p1 == '\\' || *p1 == '/')
+ } else {
+ fprintf(fd_tags, "%s\t/" "*", s);
+ for (p1 = s; *p1 != '\t'; p1++) {
+ // insert backslash before '\\' and '/'
+ if (*p1 == '\\' || *p1 == '/') {
putc('\\', fd_tags);
+ }
putc(*p1, fd_tags);
}
fprintf(fd_tags, "*\n");
}
}
}
- if (mix)
- got_int = FALSE; /* continue with other languages */
+ if (mix) {
+ got_int = false; // continue with other languages
+ }
GA_DEEP_CLEAR_PTR(&ga);
- fclose(fd_tags); /* there is no check for an error... */
+ fclose(fd_tags); // there is no check for an error...
}
/// Generate tags in one help directory, taking care of translations.
diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua
index 0f69d476f9..8c0d22809f 100644
--- a/src/nvim/ex_cmds.lua
+++ b/src/nvim/ex_cmds.lua
@@ -601,6 +601,12 @@ return {
func='ex_wrongmodifier',
},
{
+ command='const',
+ flags=bit.bor(NEEDARG, EXTRA, NOTRLCOM, CMDWIN),
+ addr_type=ADDR_LINES,
+ func='ex_const',
+ },
+ {
command='copen',
flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR),
addr_type=ADDR_LINES,
@@ -2145,6 +2151,12 @@ return {
func='ex_redrawstatus',
},
{
+ command='redrawtabline',
+ flags=bit.bor(TRLBAR, CMDWIN),
+ addr_type=ADDR_LINES,
+ func='ex_redrawtabline',
+ },
+ {
command='registers',
flags=bit.bor(EXTRA, NOTRLCOM, TRLBAR, CMDWIN),
addr_type=ADDR_LINES,
@@ -2793,6 +2805,12 @@ return {
func='ex_tag',
},
{
+ command='tmenu',
+ flags=bit.bor(RANGE, NOTADR, ZEROR, EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN),
+ addr_type=ADDR_LINES,
+ func='ex_menu',
+ },
+ {
command='tmap',
flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN),
addr_type=ADDR_LINES,
@@ -2805,12 +2823,6 @@ return {
func='ex_mapclear',
},
{
- command='tmenu',
- flags=bit.bor(RANGE, NOTADR, ZEROR, EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN),
- addr_type=ADDR_LINES,
- func='ex_menu',
- },
- {
command='tnext',
flags=bit.bor(RANGE, NOTADR, BANG, TRLBAR, ZEROR),
addr_type=ADDR_LINES,
@@ -2853,16 +2865,16 @@ return {
func='ex_tag',
},
{
- command='tunmap',
+ command='tunmenu',
flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN),
addr_type=ADDR_LINES,
- func='ex_unmap',
+ func='ex_menu',
},
{
- command='tunmenu',
+ command='tunmap',
flags=bit.bor(EXTRA, TRLBAR, NOTRLCOM, USECTRLV, CMDWIN),
addr_type=ADDR_LINES,
- func='ex_menu',
+ func='ex_unmap',
},
{
command='undo',
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 5ad285c387..408c6dce79 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -18,6 +18,7 @@
#endif
#include "nvim/ex_cmds2.h"
#include "nvim/buffer.h"
+#include "nvim/change.h"
#include "nvim/charset.h"
#include "nvim/eval.h"
#include "nvim/ex_cmds.h"
@@ -43,6 +44,7 @@
#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"
@@ -611,7 +613,7 @@ static int dbg_parsearg(char_u *arg, garray_T *gap)
return OK;
}
-/// ":breakadd".
+/// ":breakadd". Also used for ":profile".
void ex_breakadd(exarg_T *eap)
{
struct debuggy *bp;
@@ -989,7 +991,7 @@ void profile_dump(void)
FILE *fd;
if (profile_fname != NULL) {
- fd = mch_fopen((char *)profile_fname, "w");
+ fd = os_fopen((char *)profile_fname, "w");
if (fd == NULL) {
EMSG2(_(e_notopen), profile_fname);
} else {
@@ -1138,7 +1140,7 @@ static void script_dump_profile(FILE *fd)
fprintf(fd, "\n");
fprintf(fd, "count total (s) self (s)\n");
- sfd = mch_fopen((char *)si->sn_name, "r");
+ sfd = os_fopen((char *)si->sn_name, "r");
if (sfd == NULL) {
fprintf(fd, "Cannot open file!\n");
} else {
@@ -1274,9 +1276,9 @@ bool check_changed(buf_T *buf, int flags)
return bufIsChanged(buf);
}
if (flags & CCGD_EXCMD) {
- EMSG(_(e_nowrtmsg));
+ no_write_message();
} else {
- EMSG(_(e_nowrtmsg_nobang));
+ no_write_message_nobang();
}
return true;
}
@@ -1791,19 +1793,15 @@ void ex_args(exarg_T *eap)
} else if (eap->cmdidx == CMD_args) {
// ":args": list arguments.
if (ARGCOUNT > 0) {
+ char_u **items = xmalloc(sizeof(char_u *) * (size_t)ARGCOUNT);
// Overwrite the command, for a short list there is no scrolling
// required and no wait_return().
gotocmdline(true);
for (int i = 0; i < ARGCOUNT; i++) {
- if (i == curwin->w_arg_idx) {
- msg_putchar('[');
- }
- msg_outtrans(alist_name(&ARGLIST[i]));
- if (i == curwin->w_arg_idx) {
- msg_putchar(']');
- }
- msg_putchar(' ');
+ items[i] = alist_name(&ARGLIST[i]);
}
+ list_in_columns(items, ARGCOUNT, curwin->w_arg_idx);
+ xfree(items);
}
} else if (eap->cmdidx == CMD_arglocal) {
garray_T *gap = &curwin->w_alist->al_ga;
@@ -2858,7 +2856,7 @@ static int requires_py_version(char_u *filename)
lines = 5;
}
- file = mch_fopen((char *)filename, "r");
+ file = os_fopen((char *)filename, "r");
if (file != NULL) {
for (i = 0; i < lines; i++) {
if (vim_fgets(IObuff, IOSIZE, file)) {
@@ -3039,6 +3037,7 @@ int do_source(char_u *fname, int check_other, int is_vimrc)
int save_debug_break_level = debug_break_level;
scriptitem_T *si = NULL;
proftime_T wait_start;
+ bool trigger_source_post = false;
p = expand_env_save(fname);
if (p == NULL) {
@@ -3059,6 +3058,10 @@ int do_source(char_u *fname, int check_other, int is_vimrc)
&& apply_autocmds(EVENT_SOURCECMD, fname_exp, fname_exp,
false, curbuf)) {
retval = aborting() ? FAIL : OK;
+ if (retval == OK) {
+ // Apply SourcePost autocommands.
+ apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, false, curbuf);
+ }
goto theend;
}
@@ -3181,7 +3184,7 @@ int do_source(char_u *fname, int check_other, int is_vimrc)
}
si = &SCRIPT_ITEM(current_SID);
si->sn_name = fname_exp;
- fname_exp = NULL;
+ fname_exp = vim_strsave(si->sn_name); // used for autocmd
if (file_id_ok) {
si->file_id_valid = true;
si->file_id = file_id;
@@ -3261,6 +3264,10 @@ int do_source(char_u *fname, int check_other, int is_vimrc)
time_pop(rel_time);
}
+ if (!got_int) {
+ trigger_source_post = true;
+ }
+
// After a "finish" in debug mode, need to break at first command of next
// sourced file.
if (save_debug_break_level > ex_nesting_level
@@ -3278,6 +3285,10 @@ int do_source(char_u *fname, int check_other, int is_vimrc)
xfree(firstline);
convert_setup(&cookie.conv, NULL, NULL);
+ if (trigger_source_post) {
+ apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, false, curbuf);
+ }
+
theend:
xfree(fname_exp);
return retval;
diff --git a/src/nvim/ex_cmds_defs.h b/src/nvim/ex_cmds_defs.h
index 6c36922c09..bc7e1e9b59 100644
--- a/src/nvim/ex_cmds_defs.h
+++ b/src/nvim/ex_cmds_defs.h
@@ -143,7 +143,7 @@ struct exarg {
struct expand {
int xp_context; // type of expansion
char_u *xp_pattern; // start of item to expand
- int xp_pattern_len; // bytes in xp_pattern before cursor
+ size_t xp_pattern_len; // bytes in xp_pattern before cursor
char_u *xp_arg; // completion function
int xp_scriptID; // SID for completion function
int xp_backslash; // one of the XP_BS_ values
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index fb15bd4e66..0f345df22b 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -16,6 +16,7 @@
#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/diff.h"
@@ -1108,9 +1109,8 @@ static int current_tab_nr(tabpage_T *tab)
#define CURRENT_TAB_NR current_tab_nr(curtab)
#define LAST_TAB_NR current_tab_nr(NULL)
-/*
-* Figure out the address type for ":wincmd".
-*/
+
+/// Figure out the address type for ":wincmd".
static void get_wincmd_addr_type(char_u *arg, exarg_T *eap)
{
switch (*arg) {
@@ -1156,13 +1156,13 @@ static void get_wincmd_addr_type(char_u *arg, exarg_T *eap)
case Ctrl_I:
case 'd':
case Ctrl_D:
- /* window size or any count */
- eap->addr_type = ADDR_LINES;
+ // window size or any count
+ eap->addr_type = ADDR_LINES; // -V1037
break;
case Ctrl_HAT:
case '^':
- /* buffer number */
+ // buffer number
eap->addr_type = ADDR_BUFFERS;
break;
@@ -1177,7 +1177,7 @@ static void get_wincmd_addr_type(char_u *arg, exarg_T *eap)
case 'W':
case 'x':
case Ctrl_X:
- /* window number */
+ // window number
eap->addr_type = ADDR_WINDOWS;
break;
@@ -1192,7 +1192,7 @@ static void get_wincmd_addr_type(char_u *arg, exarg_T *eap)
case Ctrl_P:
case '=':
case CAR:
- /* no count */
+ // no count
eap->addr_type = 0;
break;
}
@@ -2452,7 +2452,7 @@ static char_u *find_command(exarg_T *eap, int *full)
if (ASCII_ISLOWER(eap->cmd[0])) {
const int c1 = eap->cmd[0];
- const int c2 = eap->cmd[1];
+ const int c2 = len == 1 ? NUL : eap->cmd[1];
if (command_count != (int)CMD_SIZE) {
iemsg((char *)_("E943: Command table needs to be updated, run 'make'"));
@@ -2503,10 +2503,10 @@ static char_u *find_command(exarg_T *eap, int *full)
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 *compl /* completion flags or NULL */
+ 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
)
{
int len = (int)(p - eap->cmd);
@@ -2559,8 +2559,9 @@ find_ucmd (
eap->useridx = j;
eap->addr_type = uc->uc_addr_type;
- if (compl != NULL)
- *compl = uc->uc_compl;
+ if (complp != NULL) {
+ *complp = uc->uc_compl;
+ }
if (xp != NULL) {
xp->xp_arg = uc->uc_compl_arg;
xp->xp_scriptID = uc->uc_scriptID;
@@ -4060,10 +4061,9 @@ static char_u *replace_makeprg(exarg_T *eap, char_u *p, char_u **cmdlinep)
return p;
}
-/*
- * Expand file name in Ex command argument.
- * Return FAIL for failure, OK otherwise.
- */
+// Expand file name in Ex command argument.
+// When an error is detected, "errormsgp" is set to a non-NULL pointer.
+// 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 */
@@ -4614,7 +4614,7 @@ static void ex_doautocmd(exarg_T *eap)
int call_do_modelines = check_nomodeline(&arg);
bool did_aucmd;
- (void)do_doautocmd(arg, true, &did_aucmd);
+ (void)do_doautocmd(arg, false, &did_aucmd);
// Only when there is no <nomodeline>.
if (call_do_modelines && did_aucmd) {
do_modelines(0);
@@ -5088,7 +5088,7 @@ static void uc_list(char_u *name, size_t name_len)
}
static int uc_scan_attr(char_u *attr, size_t len, uint32_t *argt, long *def,
- int *flags, int * compl, char_u **compl_arg,
+ int *flags, int *complp, char_u **compl_arg,
int *addr_type_arg)
{
char_u *p;
@@ -5185,9 +5185,10 @@ invalid_count:
return FAIL;
}
- if (parse_compl_arg(val, (int)vallen, compl, argt, compl_arg)
- == FAIL)
+ if (parse_compl_arg(val, (int)vallen, complp, argt, compl_arg)
+ == FAIL) {
return FAIL;
+ }
} else if (STRNICMP(attr, "addr", attrlen) == 0) {
*argt |= RANGE;
if (val == NULL) {
@@ -6018,7 +6019,7 @@ static void ex_highlight(exarg_T *eap)
*/
void not_exiting(void)
{
- exiting = FALSE;
+ exiting = false;
}
static bool before_quit_autocmds(win_T *wp, bool quit_all, int forceit)
@@ -6216,7 +6217,7 @@ ex_win_close(
}
need_hide = false;
} else {
- EMSG(_(e_nowrtmsg));
+ no_write_message();
return;
}
}
@@ -6418,7 +6419,7 @@ static void ex_stop(exarg_T *eap)
apply_autocmds(EVENT_VIMSUSPEND, NULL, NULL, false, NULL);
// TODO(bfredl): the TUI should do this on suspend
- ui_cursor_goto((int)Rows - 1, 0);
+ ui_cursor_goto(Rows - 1, 0);
ui_call_grid_scroll(1, 0, Rows, 0, Columns, 1, 0);
ui_flush();
ui_call_suspend(); // call machine specific function
@@ -6762,8 +6763,9 @@ void ex_splitview(exarg_T *eap)
if (*eap->arg != NUL
) {
RESET_BINDING(curwin);
- } else
- do_check_scrollbind(FALSE);
+ } else {
+ do_check_scrollbind(false);
+ }
do_exedit(eap, old_curwin);
}
@@ -6922,16 +6924,17 @@ static void ex_resize(exarg_T *eap)
n = atol((char *)eap->arg);
if (cmdmod.split & WSP_VERT) {
- if (*eap->arg == '-' || *eap->arg == '+')
+ if (*eap->arg == '-' || *eap->arg == '+') {
n += curwin->w_width;
- else if (n == 0 && eap->arg[0] == NUL) /* default is very wide */
- n = 9999;
+ } else if (n == 0 && eap->arg[0] == NUL) { // default is very wide
+ n = Columns;
+ }
win_setwidth_win(n, wp);
} else {
if (*eap->arg == '-' || *eap->arg == '+') {
n += curwin->w_height;
} else if (n == 0 && eap->arg[0] == NUL) { // default is very high
- n = 9999;
+ n = Rows-1;
}
win_setheight_win(n, wp);
}
@@ -7520,7 +7523,7 @@ static void ex_operators(exarg_T *eap)
case CMD_yank:
oa.op_type = OP_YANK;
- (void)op_yank(&oa, true);
+ (void)op_yank(&oa, true, false);
break;
default: /* CMD_rshift or CMD_lshift */
@@ -7874,6 +7877,22 @@ static void ex_redrawstatus(exarg_T *eap)
ui_flush();
}
+// ":redrawtabline": force redraw of the tabline
+static void ex_redrawtabline(exarg_T *eap FUNC_ATTR_UNUSED)
+{
+ const int r = RedrawingDisabled;
+ const int p = p_lz;
+
+ RedrawingDisabled = 0;
+ p_lz = false;
+
+ draw_tabline();
+
+ RedrawingDisabled = r;
+ p_lz = p;
+ ui_flush();
+}
+
static void close_redir(void)
{
if (redir_fd != NULL) {
@@ -8090,8 +8109,9 @@ open_exfile (
return NULL;
}
- if ((fd = mch_fopen((char *)fname, mode)) == NULL)
+ if ((fd = os_fopen((char *)fname, mode)) == NULL) {
EMSG2(_("E190: Cannot open \"%s\" for writing"), fname);
+ }
return fd;
}
@@ -8452,24 +8472,23 @@ 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': cmd = DT_PREV; /* ":tprevious" */
+ case 'p': // ":tprevious"
+ case 'N': cmd = DT_PREV; // ":tNext"
break;
- case 'N': cmd = DT_PREV; /* ":tNext" */
+ case 'n': cmd = DT_NEXT; // ":tnext"
break;
- case 'n': cmd = DT_NEXT; /* ":tnext" */
+ case 'o': cmd = DT_POP; // ":pop"
break;
- case 'o': cmd = DT_POP; /* ":pop" */
+ case 'f': // ":tfirst"
+ case 'r': cmd = DT_FIRST; // ":trewind"
break;
- case 'f': /* ":tfirst" */
- case 'r': cmd = DT_FIRST; /* ":trewind" */
+ case 'l': cmd = DT_LAST; // ":tlast"
break;
- case 'l': cmd = DT_LAST; /* ":tlast" */
- break;
- default: /* ":tag" */
+ default: // ":tag"
if (p_cst && *eap->arg != NUL) {
ex_cstag(eap);
return;
@@ -9322,26 +9341,30 @@ static frame_T *ses_skipframe(frame_T *fr)
{
frame_T *frc;
- for (frc = fr; frc != NULL; frc = frc->fr_next)
- if (ses_do_frame(frc))
+ FOR_ALL_FRAMES(frc, fr) {
+ if (ses_do_frame(frc)) {
break;
+ }
+ }
return frc;
}
-/*
- * Return TRUE if frame "fr" has a window somewhere that we want to save in
- * the Session.
- */
-static int ses_do_frame(frame_T *fr)
+// Return true if frame "fr" has a window somewhere that we want to save in
+// the Session.
+static bool ses_do_frame(const frame_T *fr)
+ FUNC_ATTR_NONNULL_ARG(1)
{
- frame_T *frc;
+ const frame_T *frc;
- if (fr->fr_layout == FR_LEAF)
+ if (fr->fr_layout == FR_LEAF) {
return ses_do_win(fr->fr_win);
- for (frc = fr->fr_child; frc != NULL; frc = frc->fr_next)
- if (ses_do_frame(frc))
- return TRUE;
- return FALSE;
+ }
+ FOR_ALL_FRAMES(frc, fr->fr_child) {
+ if (ses_do_frame(frc)) {
+ return true;
+ }
+ }
+ return false;
}
/// Return non-zero if window "wp" is to be stored in the Session.
@@ -9584,7 +9607,7 @@ ses_arglist(
if (fputs(cmd, fd) < 0 || put_eol(fd) == FAIL) {
return FAIL;
}
- if (put_line(fd, "silent! argdel *") == FAIL) {
+ if (put_line(fd, "%argdel") == FAIL) {
return FAIL;
}
for (int i = 0; i < gap->ga_len; ++i) {
@@ -10153,7 +10176,7 @@ Dictionary commands_array(buf_T *buf)
Dictionary rv = ARRAY_DICT_INIT;
Object obj = NIL;
(void)obj; // Avoid "dead assignment" warning.
- char str[10];
+ char str[20];
garray_T *gap = (buf == NULL) ? &ucmds : &buf->b_ucmds;
for (int i = 0; i < gap->ga_len; i++) {
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 479d195966..38432a34db 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -142,12 +142,12 @@ typedef struct command_line_state {
long count;
int indent;
int c;
- int i;
- int j;
int gotesc; // TRUE when <ESC> just typed
int do_abbr; // when TRUE check for abbr.
char_u *lookfor; // string to match
int hiscnt; // current history line in use
+ int save_hiscnt; // history line before attempting
+ // to jump to next match
int histype; // history type to be used
pos_T search_start; // where 'incsearch' starts searching
pos_T save_cursor;
@@ -200,7 +200,7 @@ static Array cmdline_block = ARRAY_DICT_INIT;
*/
typedef void *(*user_expand_func_T)(const char_u *,
int,
- const char_u * const *,
+ typval_T *,
bool);
static histentry_T *(history[HIST_COUNT]) = {NULL, NULL, NULL, NULL, NULL};
@@ -279,6 +279,8 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
s->old_topfill = curwin->w_topfill;
s->old_botline = curwin->w_botline;
+ assert(indent >= 0);
+
// set some variables for redrawcmd()
ccline.cmdfirstc = (s->firstc == '@' ? 0 : s->firstc);
ccline.cmdindent = (s->firstc > 0 ? s->indent : 0);
@@ -294,7 +296,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
// autoindent for :insert and :append
if (s->firstc <= 0) {
- memset(ccline.cmdbuff, ' ', s->indent);
+ memset(ccline.cmdbuff, ' ', (size_t)s->indent);
ccline.cmdbuff[s->indent] = NUL;
ccline.cmdpos = s->indent;
ccline.cmdspos = s->indent;
@@ -315,7 +317,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
if (!cmd_silent) {
gotocmdline(true);
redrawcmdprompt(); // draw prompt or indent
- set_cmdspos();
+ ccline.cmdspos = cmd_startcol();
if (!msg_scroll) {
msg_ext_clear(false);
}
@@ -382,7 +384,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
bool tl_ret = true;
dict_T *dict = get_vim_var_dict(VV_EVENT);
char firstcbuf[2];
- firstcbuf[0] = firstc > 0 ? firstc : '-';
+ firstcbuf[0] = (char)(firstc > 0 ? firstc : '-');
firstcbuf[1] = 0;
if (has_event(EVENT_CMDLINEENTER)) {
@@ -676,37 +678,37 @@ static int command_line_execute(VimState *state, int key)
// Hitting <Down> after "emenu Name.": complete submenu
if (s->c == K_DOWN && ccline.cmdpos > 0
&& ccline.cmdbuff[ccline.cmdpos - 1] == '.') {
- s->c = p_wc;
+ s->c = (int)p_wc;
} else if (s->c == K_UP) {
// Hitting <Up>: Remove one submenu name in front of the
// cursor
int found = false;
- s->j = (int)(s->xpc.xp_pattern - ccline.cmdbuff);
- s->i = 0;
- while (--s->j > 0) {
+ int j = (int)(s->xpc.xp_pattern - ccline.cmdbuff);
+ int i = 0;
+ while (--j > 0) {
// check for start of menu name
- if (ccline.cmdbuff[s->j] == ' '
- && ccline.cmdbuff[s->j - 1] != '\\') {
- s->i = s->j + 1;
+ if (ccline.cmdbuff[j] == ' '
+ && ccline.cmdbuff[j - 1] != '\\') {
+ i = j + 1;
break;
}
// check for start of submenu name
- if (ccline.cmdbuff[s->j] == '.'
- && ccline.cmdbuff[s->j - 1] != '\\') {
+ if (ccline.cmdbuff[j] == '.'
+ && ccline.cmdbuff[j - 1] != '\\') {
if (found) {
- s->i = s->j + 1;
+ i = j + 1;
break;
} else {
found = true;
}
}
}
- if (s->i > 0) {
- cmdline_del(s->i);
+ if (i > 0) {
+ cmdline_del(i);
}
- s->c = p_wc;
+ s->c = (int)p_wc;
s->xpc.xp_context = EXPAND_NOTHING;
}
}
@@ -728,44 +730,44 @@ static int command_line_execute(VimState *state, int key)
|| ccline.cmdbuff[ccline.cmdpos - 2] != '.'
|| ccline.cmdbuff[ccline.cmdpos - 3] != '.')) {
// go down a directory
- s->c = p_wc;
+ s->c = (int)p_wc;
} else if (STRNCMP(s->xpc.xp_pattern, upseg + 1, 3) == 0
&& s->c == K_DOWN) {
// If in a direct ancestor, strip off one ../ to go down
int found = false;
- s->j = ccline.cmdpos;
- s->i = (int)(s->xpc.xp_pattern - ccline.cmdbuff);
- while (--s->j > s->i) {
- s->j -= utf_head_off(ccline.cmdbuff, ccline.cmdbuff + s->j);
- if (vim_ispathsep(ccline.cmdbuff[s->j])) {
+ int j = ccline.cmdpos;
+ int i = (int)(s->xpc.xp_pattern - ccline.cmdbuff);
+ while (--j > i) {
+ j -= utf_head_off(ccline.cmdbuff, ccline.cmdbuff + j);
+ if (vim_ispathsep(ccline.cmdbuff[j])) {
found = true;
break;
}
}
if (found
- && ccline.cmdbuff[s->j - 1] == '.'
- && ccline.cmdbuff[s->j - 2] == '.'
- && (vim_ispathsep(ccline.cmdbuff[s->j - 3]) || s->j == s->i + 2)) {
- cmdline_del(s->j - 2);
- s->c = p_wc;
+ && ccline.cmdbuff[j - 1] == '.'
+ && ccline.cmdbuff[j - 2] == '.'
+ && (vim_ispathsep(ccline.cmdbuff[j - 3]) || j == i + 2)) {
+ cmdline_del(j - 2);
+ s->c = (int)p_wc;
}
} else if (s->c == K_UP) {
// go up a directory
int found = false;
- s->j = ccline.cmdpos - 1;
- s->i = (int)(s->xpc.xp_pattern - ccline.cmdbuff);
- while (--s->j > s->i) {
- s->j -= utf_head_off(ccline.cmdbuff, ccline.cmdbuff + s->j);
- if (vim_ispathsep(ccline.cmdbuff[s->j])
+ int j = ccline.cmdpos - 1;
+ int i = (int)(s->xpc.xp_pattern - ccline.cmdbuff);
+ while (--j > i) {
+ j -= utf_head_off(ccline.cmdbuff, ccline.cmdbuff + j);
+ if (vim_ispathsep(ccline.cmdbuff[j])
#ifdef BACKSLASH_IN_FILENAME
- && vim_strchr((const char_u *)" *?[{`$%#", ccline.cmdbuff[s->j + 1])
+ && vim_strchr((const char_u *)" *?[{`$%#", ccline.cmdbuff[j + 1])
== NULL
#endif
) {
if (found) {
- s->i = s->j + 1;
+ i = j + 1;
break;
} else {
found = true;
@@ -774,28 +776,28 @@ static int command_line_execute(VimState *state, int key)
}
if (!found) {
- s->j = s->i;
- } else if (STRNCMP(ccline.cmdbuff + s->j, upseg, 4) == 0) {
- s->j += 4;
- } else if (STRNCMP(ccline.cmdbuff + s->j, upseg + 1, 3) == 0
- && s->j == s->i) {
- s->j += 3;
+ j = i;
+ } else if (STRNCMP(ccline.cmdbuff + j, upseg, 4) == 0) {
+ j += 4;
+ } else if (STRNCMP(ccline.cmdbuff + j, upseg + 1, 3) == 0
+ && j == i) {
+ j += 3;
} else {
- s->j = 0;
+ j = 0;
}
- if (s->j > 0) {
+ if (j > 0) {
// TODO(tarruda): this is only for DOS/Unix systems - need to put in
// machine-specific stuff here and in upseg init
- cmdline_del(s->j);
+ cmdline_del(j);
put_on_cmdline(upseg + 1, 3, false);
- } else if (ccline.cmdpos > s->i) {
- cmdline_del(s->i);
+ } else if (ccline.cmdpos > i) {
+ cmdline_del(i);
}
// Now complete in the new directory. Set KeyTyped in case the
// Up key came from a mapping.
- s->c = p_wc;
+ s->c = (int)p_wc;
KeyTyped = true;
}
}
@@ -943,7 +945,7 @@ static int command_line_execute(VimState *state, int key)
}
} else { // typed p_wc first time
s->wim_index = 0;
- s->j = ccline.cmdpos;
+ int j = ccline.cmdpos;
// if 'wildmode' first contains "longest", get longest
// common part
@@ -970,7 +972,7 @@ static int command_line_execute(VimState *state, int key)
if (s->res == OK && s->xpc.xp_numfiles > 1) {
// a "longest" that didn't do anything is skipped (but not
// "list:longest")
- if (wim_flags[0] == WIM_LONGEST && ccline.cmdpos == s->j) {
+ if (wim_flags[0] == WIM_LONGEST && ccline.cmdpos == j) {
s->wim_index = 1;
}
if ((wim_flags[s->wim_index] & WIM_LIST)
@@ -1069,13 +1071,13 @@ static void command_line_next_incsearch(CommandLineState *s, bool next_match)
search_flags += SEARCH_KEEP;
}
emsg_off++;
- s->i = searchit(curwin, curbuf, &t, NULL,
- next_match ? FORWARD : BACKWARD,
- pat, s->count, search_flags,
- RE_SEARCH, 0, NULL, NULL);
+ int found = searchit(curwin, curbuf, &t, NULL,
+ next_match ? FORWARD : BACKWARD,
+ pat, s->count, search_flags,
+ RE_SEARCH, 0, NULL, NULL);
emsg_off--;
ui_busy_stop();
- if (s->i) {
+ if (found) {
s->search_start = s->match_start;
s->match_end = t;
s->match_start = t;
@@ -1124,7 +1126,7 @@ static void command_line_next_incsearch(CommandLineState *s, bool next_match)
static void command_line_next_histidx(CommandLineState *s, bool next_match)
{
- s->j = (int)STRLEN(s->lookfor);
+ int j = (int)STRLEN(s->lookfor);
for (;; ) {
// one step backwards
if (!next_match) {
@@ -1137,7 +1139,7 @@ static void command_line_next_histidx(CommandLineState *s, bool next_match)
s->hiscnt--;
} else {
// at top of list
- s->hiscnt = s->i;
+ s->hiscnt = s->save_hiscnt;
break;
}
} else { // one step forwards
@@ -1161,14 +1163,14 @@ static void command_line_next_histidx(CommandLineState *s, bool next_match)
}
if (s->hiscnt < 0 || history[s->histype][s->hiscnt].hisstr == NULL) {
- s->hiscnt = s->i;
+ s->hiscnt = s->save_hiscnt;
break;
}
if ((s->c != K_UP && s->c != K_DOWN)
- || s->hiscnt == s->i
+ || s->hiscnt == s->save_hiscnt
|| STRNCMP(history[s->histype][s->hiscnt].hisstr,
- s->lookfor, (size_t)s->j) == 0) {
+ s->lookfor, (size_t)j) == 0) {
break;
}
}
@@ -1193,7 +1195,7 @@ static int command_line_handle_key(CommandLineState *s)
++ccline.cmdpos;
}
- if (has_mbyte && s->c == K_DEL) {
+ if (s->c == K_DEL) {
ccline.cmdpos += mb_off_next(ccline.cmdbuff,
ccline.cmdbuff + ccline.cmdpos);
}
@@ -1201,43 +1203,30 @@ static int command_line_handle_key(CommandLineState *s)
if (ccline.cmdpos > 0) {
char_u *p;
- s->j = ccline.cmdpos;
- p = ccline.cmdbuff + s->j;
- if (has_mbyte) {
- p = mb_prevptr(ccline.cmdbuff, p);
-
- if (s->c == Ctrl_W) {
- while (p > ccline.cmdbuff && ascii_isspace(*p)) {
- p = mb_prevptr(ccline.cmdbuff, p);
- }
+ int j = ccline.cmdpos;
+ p = mb_prevptr(ccline.cmdbuff, ccline.cmdbuff + j);
- s->i = mb_get_class(p);
- while (p > ccline.cmdbuff && mb_get_class(p) == s->i)
- p = mb_prevptr(ccline.cmdbuff, p);
-
- if (mb_get_class(p) != s->i) {
- p += (*mb_ptr2len)(p);
- }
+ if (s->c == Ctrl_W) {
+ while (p > ccline.cmdbuff && ascii_isspace(*p)) {
+ p = mb_prevptr(ccline.cmdbuff, p);
}
- } else if (s->c == Ctrl_W) {
- while (p > ccline.cmdbuff && ascii_isspace(p[-1])) {
- --p;
+
+ int i = mb_get_class(p);
+ while (p > ccline.cmdbuff && mb_get_class(p) == i) {
+ p = mb_prevptr(ccline.cmdbuff, p);
}
- s->i = vim_iswordc(p[-1]);
- while (p > ccline.cmdbuff && !ascii_isspace(p[-1])
- && vim_iswordc(p[-1]) == s->i)
- --p;
- } else {
- --p;
+ if (mb_get_class(p) != i) {
+ p += utfc_ptr2len(p);
+ }
}
ccline.cmdpos = (int)(p - ccline.cmdbuff);
- ccline.cmdlen -= s->j - ccline.cmdpos;
- s->i = ccline.cmdpos;
+ ccline.cmdlen -= j - ccline.cmdpos;
+ int i = ccline.cmdpos;
- while (s->i < ccline.cmdlen) {
- ccline.cmdbuff[s->i++] = ccline.cmdbuff[s->j++];
+ while (i < ccline.cmdlen) {
+ ccline.cmdbuff[i++] = ccline.cmdbuff[j++];
}
// Truncate at the end, required for multi-byte chars.
@@ -1307,13 +1296,13 @@ static int command_line_handle_key(CommandLineState *s)
status_redraw_curbuf();
return command_line_not_changed(s);
- case Ctrl_U:
+ case Ctrl_U: {
// delete all characters left of the cursor
- s->j = ccline.cmdpos;
- ccline.cmdlen -= s->j;
- s->i = ccline.cmdpos = 0;
- while (s->i < ccline.cmdlen) {
- ccline.cmdbuff[s->i++] = ccline.cmdbuff[s->j++];
+ int j = ccline.cmdpos;
+ ccline.cmdlen -= j;
+ int i = ccline.cmdpos = 0;
+ while (i < ccline.cmdlen) {
+ ccline.cmdbuff[i++] = ccline.cmdbuff[j++];
}
// Truncate at the end, required for multi-byte chars.
@@ -1323,6 +1312,7 @@ static int command_line_handle_key(CommandLineState *s)
}
redrawcmd();
return command_line_changed(s);
+ }
case ESC: // get here if p_wc != ESC or when ESC typed twice
case Ctrl_C:
@@ -1339,15 +1329,15 @@ static int command_line_handle_key(CommandLineState *s)
// putting it in history
return 0; // back to cmd mode
- case Ctrl_R: // insert register
+ case Ctrl_R: { // insert register
putcmdline('"', true);
- ++no_mapping;
- s->i = s->c = plain_vgetc(); // CTRL-R <char>
- if (s->i == Ctrl_O) {
- s->i = Ctrl_R; // CTRL-R CTRL-O == CTRL-R CTRL-R
+ no_mapping++;
+ int i = s->c = plain_vgetc(); // CTRL-R <char>
+ if (i == Ctrl_O) {
+ i = Ctrl_R; // CTRL-R CTRL-O == CTRL-R CTRL-R
}
- if (s->i == Ctrl_R) {
+ if (i == Ctrl_R) {
s->c = plain_vgetc(); // CTRL-R CTRL-R <char>
}
--no_mapping;
@@ -1369,7 +1359,7 @@ static int command_line_handle_key(CommandLineState *s)
}
if (s->c != ESC) { // use ESC to cancel inserting register
- cmdline_paste(s->c, s->i == Ctrl_R, false);
+ cmdline_paste(s->c, i == Ctrl_R, false);
// When there was a serious error abort getting the
// command line.
@@ -1391,6 +1381,7 @@ static int command_line_handle_key(CommandLineState *s)
ccline.special_char = NUL;
redrawcmd();
return command_line_changed(s);
+ }
case Ctrl_D:
if (showmatches(&s->xpc, false) == EXPAND_NOTHING) {
@@ -1409,24 +1400,17 @@ static int command_line_handle_key(CommandLineState *s)
break;
}
- s->i = cmdline_charsize(ccline.cmdpos);
- if (KeyTyped && ccline.cmdspos + s->i >= Columns * Rows) {
+ int cells = cmdline_charsize(ccline.cmdpos);
+ if (KeyTyped && ccline.cmdspos + cells >= Columns * Rows) {
break;
}
- ccline.cmdspos += s->i;
- if (has_mbyte) {
- ccline.cmdpos += (*mb_ptr2len)(ccline.cmdbuff
- + ccline.cmdpos);
- } else {
- ++ccline.cmdpos;
- }
+ ccline.cmdspos += cells;
+ ccline.cmdpos += utfc_ptr2len(ccline.cmdbuff + ccline.cmdpos);
} while ((s->c == K_S_RIGHT || s->c == K_C_RIGHT
|| (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL)))
&& ccline.cmdbuff[ccline.cmdpos] != ' ');
- if (has_mbyte) {
- set_cmdspos_cursor();
- }
+ ccline.cmdspos = cmd_screencol(ccline.cmdpos);
return command_line_not_changed(s);
case K_LEFT:
@@ -1446,7 +1430,7 @@ static int command_line_handle_key(CommandLineState *s)
|| (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL)))
&& ccline.cmdbuff[ccline.cmdpos - 1] != ' ');
- set_cmdspos_cursor();
+ ccline.cmdspos = cmd_screencol(ccline.cmdpos);
if (ccline.special_char != NUL) {
putcmdline(ccline.special_char, ccline.special_shift);
}
@@ -1493,22 +1477,19 @@ static int command_line_handle_key(CommandLineState *s)
return command_line_not_changed(s); // Ignore mouse
}
- set_cmdspos();
+ ccline.cmdspos = cmd_startcol();
for (ccline.cmdpos = 0; ccline.cmdpos < ccline.cmdlen;
- ++ccline.cmdpos) {
- s->i = cmdline_charsize(ccline.cmdpos);
+ ccline.cmdpos++) {
+ int cells = cmdline_charsize(ccline.cmdpos);
if (mouse_row <= cmdline_row + ccline.cmdspos / Columns
- && mouse_col < ccline.cmdspos % Columns + s->i) {
+ && mouse_col < ccline.cmdspos % Columns + cells) {
break;
}
- if (has_mbyte) {
- // Count ">" for double-wide char that doesn't fit.
- correct_cmdspos(ccline.cmdpos, s->i);
- ccline.cmdpos += (*mb_ptr2len)(ccline.cmdbuff
- + ccline.cmdpos) - 1;
- }
- ccline.cmdspos += s->i;
+ // Count ">" for double-wide char that doesn't fit.
+ correct_screencol(ccline.cmdpos, cells, &ccline.cmdspos);
+ ccline.cmdpos += utfc_ptr2len(ccline.cmdbuff + ccline.cmdpos) - 1;
+ ccline.cmdspos += cells;
}
return command_line_not_changed(s);
@@ -1537,7 +1518,7 @@ static int command_line_handle_key(CommandLineState *s)
case K_S_HOME:
case K_C_HOME:
ccline.cmdpos = 0;
- set_cmdspos();
+ ccline.cmdspos = cmd_startcol();
return command_line_not_changed(s);
case Ctrl_E: // end of command line
@@ -1546,7 +1527,7 @@ static int command_line_handle_key(CommandLineState *s)
case K_S_END:
case K_C_END:
ccline.cmdpos = ccline.cmdlen;
- set_cmdspos_cursor();
+ ccline.cmdspos = cmd_screencol(ccline.cmdpos);
return command_line_not_changed(s);
case Ctrl_A: // all matches
@@ -1613,7 +1594,7 @@ static int command_line_handle_key(CommandLineState *s)
return command_line_not_changed(s);
}
- s->i = s->hiscnt;
+ s->save_hiscnt = s->hiscnt;
// save current command string so it can be restored later
if (s->lookfor == NULL) {
@@ -1625,7 +1606,7 @@ static int command_line_handle_key(CommandLineState *s)
|| s->c == K_PAGEDOWN || s->c == K_KPAGEDOWN);
command_line_next_histidx(s, next_match);
- if (s->hiscnt != s->i) {
+ if (s->hiscnt != s->save_hiscnt) {
// jumped to other entry
char_u *p;
int len = 0;
@@ -1646,35 +1627,35 @@ static int command_line_handle_key(CommandLineState *s)
// adding the history entry vs the one used now.
// First loop: count length.
// Second loop: copy the characters.
- for (s->i = 0; s->i <= 1; ++s->i) {
+ for (int i = 0; i <= 1; i++) {
len = 0;
- for (s->j = 0; p[s->j] != NUL; ++s->j) {
+ for (int j = 0; p[j] != NUL; j++) {
// Replace old sep with new sep, unless it is
// escaped.
- if (p[s->j] == old_firstc
- && (s->j == 0 || p[s->j - 1] != '\\')) {
- if (s->i > 0) {
- ccline.cmdbuff[len] = s->firstc;
+ if (p[j] == old_firstc
+ && (j == 0 || p[j - 1] != '\\')) {
+ if (i > 0) {
+ ccline.cmdbuff[len] = (char_u)s->firstc;
}
} else {
// Escape new sep, unless it is already
// escaped.
- if (p[s->j] == s->firstc
- && (s->j == 0 || p[s->j - 1] != '\\')) {
- if (s->i > 0) {
+ if (p[j] == s->firstc
+ && (j == 0 || p[j - 1] != '\\')) {
+ if (i > 0) {
ccline.cmdbuff[len] = '\\';
}
++len;
}
- if (s->i > 0) {
- ccline.cmdbuff[len] = p[s->j];
+ if (i > 0) {
+ ccline.cmdbuff[len] = p[j];
}
}
++len;
}
- if (s->i == 0) {
+ if (i == 0) {
alloc_cmdbuff(len);
}
}
@@ -1766,9 +1747,9 @@ static int command_line_handle_key(CommandLineState *s)
if (IS_SPECIAL(s->c) || mod_mask != 0) {
put_on_cmdline(get_special_key_name(s->c, mod_mask), -1, true);
} else {
- s->j = utf_char2bytes(s->c, IObuff);
- IObuff[s->j] = NUL; // exclude composing chars
- put_on_cmdline(IObuff, s->j, true);
+ int j = utf_char2bytes(s->c, IObuff);
+ IObuff[j] = NUL; // exclude composing chars
+ put_on_cmdline(IObuff, j, true);
}
return command_line_changed(s);
}
@@ -1810,7 +1791,7 @@ static int command_line_changed(CommandLineState *s)
dict_T *dict = get_vim_var_dict(VV_EVENT);
char firstcbuf[2];
- firstcbuf[0] = s->firstc > 0 ? s->firstc : '-';
+ firstcbuf[0] = (char)(s->firstc > 0 ? s->firstc : '-');
firstcbuf[1] = 0;
// set v:event to a dictionary with information about the commandline
@@ -1845,10 +1826,11 @@ static int command_line_changed(CommandLineState *s)
s->incsearch_postponed = false;
curwin->w_cursor = s->search_start; // start at old position
save_last_search_pattern();
+ int i;
// If there is no command line, don't do anything
if (ccline.cmdlen == 0) {
- s->i = 0;
+ i = 0;
SET_NO_HLSEARCH(true); // turn off previous highlight
redraw_all_later(SOME_VALID);
} else {
@@ -1861,15 +1843,14 @@ static int command_line_changed(CommandLineState *s)
if (!p_hls) {
search_flags += SEARCH_KEEP;
}
- s->i = do_search(NULL, s->firstc, ccline.cmdbuff, s->count,
- search_flags,
- &tm, NULL);
+ i = do_search(NULL, s->firstc, ccline.cmdbuff, s->count,
+ search_flags, &tm, NULL);
emsg_off--;
// if interrupted while searching, behave like it failed
if (got_int) {
(void)vpeekc(); // remove <C-C> from input stream
got_int = false; // don't abandon the command line
- s->i = 0;
+ i = 0;
} else if (char_avail()) {
// cancelled searching because a char was typed
s->incsearch_postponed = true;
@@ -1877,7 +1858,7 @@ static int command_line_changed(CommandLineState *s)
ui_busy_stop();
}
- if (s->i != 0) {
+ if (i != 0) {
highlight_match = true; // highlight position
} else {
highlight_match = false; // remove highlight
@@ -1892,7 +1873,7 @@ static int command_line_changed(CommandLineState *s)
changed_cline_bef_curs();
update_topline();
- if (s->i != 0) {
+ if (i != 0) {
pos_T save_pos = curwin->w_cursor;
s->match_start = curwin->w_cursor;
@@ -1921,7 +1902,7 @@ static int command_line_changed(CommandLineState *s)
restore_last_search_pattern();
// Leave it at the end to make CTRL-R CTRL-W work.
- if (s->i != 0) {
+ if (i != 0) {
curwin->w_cursor = end_pos;
}
@@ -1978,6 +1959,7 @@ static int command_line_changed(CommandLineState *s)
static void abandon_cmdline(void)
{
XFREE_CLEAR(ccline.cmdbuff);
+ ccline.redraw_state = kCmdRedrawNone;
if (msg_scrolled == 0) {
compute_cmdrow();
}
@@ -2131,58 +2113,52 @@ static int cmdline_charsize(int idx)
return ptr2cells(ccline.cmdbuff + idx);
}
-/*
- * Compute the offset of the cursor on the command line for the prompt and
- * indent.
- */
-static void set_cmdspos(void)
+/// Compute the offset of the cursor on the command line for the prompt and
+/// indent.
+static int cmd_startcol(void)
{
- if (ccline.cmdfirstc != NUL)
- ccline.cmdspos = 1 + ccline.cmdindent;
- else
- ccline.cmdspos = 0 + ccline.cmdindent;
+ return ccline.cmdindent + ((ccline.cmdfirstc != NUL) ? 1 : 0);
}
-/*
- * Compute the screen position for the cursor on the command line.
- */
-static void set_cmdspos_cursor(void)
+
+/// Compute the column position for a byte position on the command line.
+static int cmd_screencol(int bytepos)
{
- int i, m, c;
+ int m; // maximum column
- set_cmdspos();
+ int col = cmd_startcol();
if (KeyTyped) {
m = Columns * Rows;
if (m < 0) /* overflow, Columns or Rows at weird value */
m = MAXCOL;
- } else
+ } else {
m = MAXCOL;
- for (i = 0; i < ccline.cmdlen && i < ccline.cmdpos; ++i) {
- c = cmdline_charsize(i);
- /* Count ">" for double-wide multi-byte char that doesn't fit. */
- if (has_mbyte)
- correct_cmdspos(i, c);
- /* If the cmdline doesn't fit, show cursor on last visible char.
- * Don't move the cursor itself, so we can still append. */
- if ((ccline.cmdspos += c) >= m) {
- ccline.cmdspos -= c;
+ }
+
+ for (int i = 0; i < ccline.cmdlen && i < bytepos;
+ i += utfc_ptr2len(ccline.cmdbuff + i)) {
+ int c = cmdline_charsize(i);
+ // Count ">" for double-wide multi-byte char that doesn't fit.
+ correct_screencol(i, c, &col);
+
+ // If the cmdline doesn't fit, show cursor on last visible char.
+ // Don't move the cursor itself, so we can still append.
+ if ((col += c) >= m) {
+ col -= c;
break;
}
- if (has_mbyte)
- i += (*mb_ptr2len)(ccline.cmdbuff + i) - 1;
}
+ return col;
}
-/*
- * Check if the character at "idx", which is "cells" wide, is a multi-byte
- * character that doesn't fit, so that a ">" must be displayed.
- */
-static void correct_cmdspos(int idx, int cells)
+/// Check if the character at "idx", which is "cells" wide, is a multi-byte
+/// character that doesn't fit, so that a ">" must be displayed.
+static void correct_screencol(int idx, int cells, int *col)
{
if (utfc_ptr2len(ccline.cmdbuff + idx) > 1
&& utf_ptr2cells(ccline.cmdbuff + idx) > 1
- && ccline.cmdspos % Columns + cells > Columns) {
- ccline.cmdspos++;
+ && (*col) % Columns + cells > Columns) {
+ (*col)++;
}
}
@@ -2323,8 +2299,10 @@ add_indent:
char_u *s = skipwhite(p);
// Insert spaces after leading whitespaces.
- memmove(s + num_spaces, s, line_ga.ga_len - (s - p) + 1);
- memset(s, ' ', num_spaces);
+ 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;
}
@@ -2377,8 +2355,10 @@ redraw:
while ((old_indent = get_indent_str(p, 8, FALSE)) > indent) {
*--to = NUL;
}
- memmove(to, from, line_ga.ga_len - (from - p) + 1);
- line_ga.ga_len -= from - to;
+ 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;
@@ -2484,7 +2464,7 @@ static void alloc_cmdbuff(int len)
else
len += 20;
- ccline.cmdbuff = xmalloc(len);
+ ccline.cmdbuff = xmalloc((size_t)len);
ccline.cmdbufflen = len;
}
@@ -2521,7 +2501,7 @@ static void realloc_cmdbuff(int len)
static char_u *arshape_buf = NULL;
# if defined(EXITFREE)
-void free_cmdline_buf(void)
+void free_arshape_buf(void)
{
xfree(arshape_buf);
}
@@ -2561,26 +2541,28 @@ static void color_expr_cmdline(const CmdlineInfo *const colored_ccline,
size_t prev_end = 0;
for (size_t i = 0 ; i < kv_size(colors) ; i++) {
const ParserHighlightChunk chunk = kv_A(colors, i);
+ assert(chunk.start.col < INT_MAX);
+ assert(chunk.end_col < INT_MAX);
if (chunk.start.col != prev_end) {
kv_push(ret_ccline_colors->colors, ((CmdlineColorChunk) {
- .start = prev_end,
- .end = chunk.start.col,
+ .start = (int)prev_end,
+ .end = (int)chunk.start.col,
.attr = 0,
}));
}
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 = chunk.start.col,
- .end = chunk.end_col,
+ .start = (int)chunk.start.col,
+ .end = (int)chunk.end_col,
.attr = attr,
}));
prev_end = chunk.end_col;
}
if (prev_end < (size_t)colored_ccline->cmdlen) {
kv_push(ret_ccline_colors->colors, ((CmdlineColorChunk) {
- .start = prev_end,
- .end = (size_t)colored_ccline->cmdlen,
+ .start = (int)prev_end,
+ .end = colored_ccline->cmdlen,
.attr = 0,
}));
}
@@ -2745,8 +2727,8 @@ static bool color_cmdline(CmdlineInfo *colored_ccline)
}
if (start != prev_end) {
kv_push(ccline_colors->colors, ((CmdlineColorChunk) {
- .start = prev_end,
- .end = start,
+ .start = (int)prev_end,
+ .end = (int)start,
.attr = 0,
}));
}
@@ -2775,15 +2757,15 @@ static bool color_cmdline(CmdlineInfo *colored_ccline)
const int id = syn_name2id((char_u *)group);
const int attr = (id == 0 ? 0 : syn_id2attr(id));
kv_push(ccline_colors->colors, ((CmdlineColorChunk) {
- .start = start,
- .end = end,
+ .start = (int)start,
+ .end = (int)end,
.attr = attr,
}));
i++;
});
if (prev_end < colored_ccline->cmdlen) {
kv_push(ccline_colors->colors, ((CmdlineColorChunk) {
- .start = prev_end,
+ .start = (int)prev_end,
.end = colored_ccline->cmdlen,
.attr = 0,
}));
@@ -2861,15 +2843,16 @@ static void draw_cmdline(int start, int len)
goto draw_cmdline_no_arabicshape;
}
- static int buflen = 0;
+ static size_t buflen = 0;
+ assert(len >= 0);
// Do arabic shaping into a temporary buffer. This is very
// inefficient!
- if (len * 2 + 2 > buflen) {
+ if ((size_t)len * 2 + 2 > buflen) {
// Re-allocate the buffer. We keep it around to avoid a lot of
// alloc()/free() calls.
xfree(arshape_buf);
- buflen = len * 2 + 2;
+ buflen = (size_t)len * 2 + 2;
arshape_buf = xmalloc(buflen);
}
@@ -2927,7 +2910,7 @@ static void draw_cmdline(int start, int len)
}
} else {
prev_c = u8c;
- memmove(arshape_buf + newlen, p, mb_l);
+ memmove(arshape_buf + newlen, p, (size_t)mb_l);
newlen += mb_l;
}
}
@@ -2972,8 +2955,9 @@ static void ui_ext_cmdline_show(CmdlineInfo *line)
Array item = ARRAY_DICT_INIT;
ADD(item, INTEGER_OBJ(chunk.attr));
+ assert(chunk.end >= chunk.start);
ADD(item, STRING_OBJ(cbuf_to_string((char *)line->cmdbuff + chunk.start,
- chunk.end-chunk.start)));
+ (size_t)(chunk.end-chunk.start))));
ADD(content, ARRAY_OBJ(item));
}
} else {
@@ -2994,7 +2978,7 @@ static void ui_ext_cmdline_show(CmdlineInfo *line)
}
}
-void ui_ext_cmdline_block_append(int indent, const char *line)
+void ui_ext_cmdline_block_append(size_t indent, const char *line)
{
char *buf = xmallocz(indent + strlen(line));
memset(buf, ' ', indent);
@@ -3073,7 +3057,7 @@ void cmdline_ui_flush(void)
* right when "shift" is TRUE. Used for CTRL-V, CTRL-K, etc.
* "c" must be printable (fit in one display cell)!
*/
-void putcmdline(int c, int shift)
+void putcmdline(char c, int shift)
{
if (cmd_silent) {
return;
@@ -3215,7 +3199,7 @@ void put_on_cmdline(char_u *str, int len, int redraw)
c = cmdline_charsize(ccline.cmdpos);
// count ">" for a double-wide char that doesn't fit.
if (has_mbyte) {
- correct_cmdspos(ccline.cmdpos, c);
+ correct_screencol(ccline.cmdpos, c, &ccline.cmdspos);
}
// Stop cursor at the end of the screen, but do increment the
// insert position, so that entering a very long command
@@ -3392,8 +3376,9 @@ void cmdline_paste_str(char_u *s, int literally)
/// Delete characters on the command line, from "from" to the current position.
static void cmdline_del(int from)
{
+ assert(ccline.cmdpos <= ccline.cmdlen);
memmove(ccline.cmdbuff + from, ccline.cmdbuff + ccline.cmdpos,
- (size_t)ccline.cmdlen - ccline.cmdpos + 1);
+ (size_t)ccline.cmdlen - (size_t)ccline.cmdpos + 1);
ccline.cmdlen -= ccline.cmdpos - from;
ccline.cmdpos = from;
}
@@ -3428,7 +3413,7 @@ static void redrawcmdprompt(void)
if (ccline.cmdprompt != NULL) {
msg_puts_attr((const char *)ccline.cmdprompt, ccline.cmdattr);
ccline.cmdindent = msg_col + (msg_row - cmdline_row) * Columns;
- // do the reverse of set_cmdspos()
+ // do the reverse of cmd_startcol()
if (ccline.cmdfirstc != NUL) {
ccline.cmdindent--;
}
@@ -3470,7 +3455,7 @@ void redrawcmd(void)
msg_clr_eos();
msg_no_more = FALSE;
- set_cmdspos_cursor();
+ ccline.cmdspos = cmd_screencol(ccline.cmdpos);
if (ccline.special_char != NUL) {
putcmdline(ccline.special_char, ccline.special_shift);
@@ -3514,15 +3499,17 @@ static void cursorcmd(void)
}
if (cmdmsg_rl) {
- msg_row = cmdline_row + (ccline.cmdspos / (int)(Columns - 1));
- msg_col = (int)Columns - (ccline.cmdspos % (int)(Columns - 1)) - 1;
- if (msg_row <= 0)
+ msg_row = cmdline_row + (ccline.cmdspos / (Columns - 1));
+ msg_col = Columns - (ccline.cmdspos % (Columns - 1)) - 1;
+ if (msg_row <= 0) {
msg_row = Rows - 1;
+ }
} else {
- msg_row = cmdline_row + (ccline.cmdspos / (int)Columns);
- msg_col = ccline.cmdspos % (int)Columns;
- if (msg_row >= Rows)
+ msg_row = cmdline_row + (ccline.cmdspos / Columns);
+ msg_col = ccline.cmdspos % Columns;
+ if (msg_row >= Rows) {
msg_row = Rows - 1;
+ }
}
ui_cursor_goto(msg_row, msg_col);
@@ -3624,7 +3611,8 @@ nextwild (
}
i = (int)(xp->xp_pattern - ccline.cmdbuff);
- xp->xp_pattern_len = ccline.cmdpos - i;
+ assert(ccline.cmdpos >= i);
+ xp->xp_pattern_len = (size_t)ccline.cmdpos - (size_t)i;
if (type == WILD_NEXT || type == WILD_PREV) {
// Get next/previous match for a previous expanded pattern.
@@ -3644,7 +3632,7 @@ nextwild (
xfree(p1);
// Longest match: make sure it is not shorter, happens with :help.
if (p2 != NULL && type == WILD_LONGEST) {
- for (j = 0; j < xp->xp_pattern_len; j++) {
+ for (j = 0; (size_t)j < xp->xp_pattern_len; j++) {
if (ccline.cmdbuff[i + j] == '*'
|| ccline.cmdbuff[i + j] == '?') {
break;
@@ -3657,14 +3645,15 @@ nextwild (
}
if (p2 != NULL && !got_int) {
- difflen = (int)STRLEN(p2) - xp->xp_pattern_len;
+ difflen = (int)STRLEN(p2) - (int)xp->xp_pattern_len;
if (ccline.cmdlen + difflen + 4 > ccline.cmdbufflen) {
realloc_cmdbuff(ccline.cmdlen + difflen + 4);
xp->xp_pattern = ccline.cmdbuff + i;
}
+ assert(ccline.cmdpos <= ccline.cmdlen);
memmove(&ccline.cmdbuff[ccline.cmdpos + difflen],
&ccline.cmdbuff[ccline.cmdpos],
- (size_t)ccline.cmdlen - ccline.cmdpos + 1);
+ (size_t)ccline.cmdlen - (size_t)ccline.cmdpos + 1);
memmove(&ccline.cmdbuff[i], p2, STRLEN(p2));
ccline.cmdlen += difflen;
ccline.cmdpos += difflen;
@@ -3861,7 +3850,7 @@ ExpandOne (
size_t len = 0;
for (size_t mb_len; xp->xp_files[0][len]; len += mb_len) {
- mb_len = utfc_ptr2len(&xp->xp_files[0][len]);
+ mb_len = (size_t)utfc_ptr2len(&xp->xp_files[0][len]);
int c0 = utf_ptr2char(&xp->xp_files[0][len]);
for (i = 1; i < xp->xp_numfiles; i++) {
int ci = utf_ptr2char(&xp->xp_files[i][len]);
@@ -4100,7 +4089,8 @@ void cmdline_pum_display(bool changed_array)
*/
static int showmatches(expand_T *xp, int wildmenu)
{
-#define L_SHOWFILE(m) (showtail ? sm_gettail(files_found[m]) : files_found[m])
+#define L_SHOWFILE(m) (showtail \
+ ? sm_gettail(files_found[m], false) : files_found[m])
int num_files;
char_u **files_found;
int i, j, k;
@@ -4132,19 +4122,19 @@ static int showmatches(expand_T *xp, int wildmenu)
|| ui_has(kUIWildmenu);
if (compl_use_pum) {
+ assert(num_files >= 0);
compl_match_arraysize = num_files;
- compl_match_array = xcalloc(compl_match_arraysize, sizeof(pumitem_T));
+ compl_match_array = xcalloc((size_t)compl_match_arraysize,
+ sizeof(pumitem_T));
for (i = 0; i < num_files; i++) {
compl_match_array[i].pum_text = L_SHOWFILE(i);
}
- ssize_t offset = showtail ? sm_gettail(xp->xp_pattern)-xp->xp_pattern : 0;
+ char_u *endpos = (showtail
+ ? sm_gettail(xp->xp_pattern, true) : xp->xp_pattern);
if (ui_has(kUICmdline)) {
- compl_startcol = ccline.cmdpos - strnlen((char *)xp->xp_pattern+offset,
- xp->xp_pattern_len-offset);
+ compl_startcol = (int)(endpos - ccline.cmdbuff);
} else {
- compl_startcol = ccline.cmdspos
- - mb_string2cells_len(xp->xp_pattern+offset,
- xp->xp_pattern_len-offset);
+ compl_startcol = cmd_screencol((int)(endpos - ccline.cmdbuff));
}
compl_selected = -1;
cmdline_pum_display(true);
@@ -4180,14 +4170,15 @@ static int showmatches(expand_T *xp, int wildmenu)
maxlen = j;
}
- if (xp->xp_context == EXPAND_TAGS_LISTFILES)
+ if (xp->xp_context == EXPAND_TAGS_LISTFILES) {
lines = num_files;
- else {
- /* compute the number of columns and lines for the listing */
- maxlen += 2; /* two spaces between file names */
- columns = ((int)Columns + 2) / maxlen;
- if (columns < 1)
+ } else {
+ // compute the number of columns and lines for the listing
+ maxlen += 2; // two spaces between file names
+ columns = (Columns + 2) / maxlen;
+ if (columns < 1) {
columns = 1;
+ }
lines = (num_files + columns - 1) / columns;
}
@@ -4276,7 +4267,7 @@ static int showmatches(expand_T *xp, int wildmenu)
* Private path_tail for showmatches() (and win_redr_status_matches()):
* Find tail of file name path, but ignore trailing "/".
*/
-char_u *sm_gettail(char_u *s)
+char_u *sm_gettail(char_u *s, bool eager)
{
char_u *p;
char_u *t = s;
@@ -4287,9 +4278,13 @@ char_u *sm_gettail(char_u *s)
#ifdef BACKSLASH_IN_FILENAME
&& !rem_backslash(p)
#endif
- )
- had_sep = TRUE;
- else if (had_sep) {
+ ) {
+ if (eager) {
+ t = p+1;
+ } else {
+ had_sep = true;
+ }
+ } else if (had_sep) {
t = p;
had_sep = FALSE;
}
@@ -4329,24 +4324,20 @@ static int expand_showtail(expand_T *xp)
return TRUE;
}
-/*
- * Prepare a string for expansion.
- * When expanding file names: The string will be used with expand_wildcards().
- * Copy "fname[len]" into allocated memory and add a '*' at the end.
- * When expanding other names: The string will be used with regcomp(). Copy
- * the name into allocated memory and prepend "^".
- */
-char_u *
-addstar (
- char_u *fname,
- int len,
- int context /* EXPAND_FILES etc. */
-)
+/// Prepare a string for expansion.
+///
+/// When expanding file names: The string will be used with expand_wildcards().
+/// Copy "fname[len]" into allocated memory and add a '*' at the end.
+/// When expanding other names: The string will be used with regcomp(). Copy
+/// the name into allocated memory and prepend "^".
+///
+/// @param context EXPAND_FILES etc.
+char_u *addstar(char_u *fname, size_t len, int context)
FUNC_ATTR_NONNULL_RET
{
char_u *retval;
- int i, j;
- int new_len;
+ size_t i, j;
+ size_t new_len;
char_u *tail;
int ends_in_star;
@@ -4437,9 +4428,10 @@ addstar (
tail = path_tail(retval);
ends_in_star = (len > 0 && retval[len - 1] == '*');
#ifndef BACKSLASH_IN_FILENAME
- for (i = len - 2; i >= 0; --i) {
- if (retval[i] != '\\')
+ for (ssize_t k = (ssize_t)len - 2; k >= 0; k--) {
+ if (retval[k] != '\\') {
break;
+ }
ends_in_star = !ends_in_star;
}
#endif
@@ -4520,7 +4512,7 @@ set_cmd_context (
int use_ccline // use ccline for info
)
{
- int old_char = NUL;
+ char_u old_char = NUL;
/*
* Avoid a UMR warning from Purify, only save the character if it has been
@@ -4584,8 +4576,9 @@ expand_cmdline (
return EXPAND_NOTHING;
}
- /* add star to file name, or convert to regexp if not exp. files. */
- xp->xp_pattern_len = (int)(str + col - xp->xp_pattern);
+ // add star to file name, or convert to regexp if not exp. files.
+ assert((str + col) - xp->xp_pattern >= 0);
+ 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)
@@ -4875,7 +4868,7 @@ void ExpandGeneric(
)
{
int i;
- int count = 0;
+ size_t count = 0;
char_u *str;
// count the number of matching names
@@ -4891,7 +4884,8 @@ void ExpandGeneric(
}
if (count == 0)
return;
- *num_file = count;
+ assert(count < INT_MAX);
+ *num_file = (int)count;
*file = (char_u **)xmalloc(count * sizeof(char_u *));
// copy the matching names into allocated memory
@@ -4952,7 +4946,7 @@ static void expand_shellcmd(char_u *filepat, int *num_file, char_u ***file,
{
char_u *pat;
int i;
- char_u *path;
+ char_u *path = NULL;
garray_T ga;
char_u *buf = xmalloc(MAXPATHL);
size_t l;
@@ -4971,15 +4965,14 @@ static void expand_shellcmd(char_u *filepat, int *num_file, char_u ***file,
flags |= EW_FILE | EW_EXEC | EW_SHELLCMD;
bool mustfree = false; // Track memory allocation for *path.
- // For an absolute name we don't use $PATH.
- if (path_is_absolute(pat)) {
- path = (char_u *)" ";
- } else if (pat[0] == '.' && (vim_ispathsep(pat[1])
- || (pat[1] == '.'
- && vim_ispathsep(pat[2])))) {
+ if (pat[0] == '.' && (vim_ispathsep(pat[1])
+ || (pat[1] == '.' && vim_ispathsep(pat[2])))) {
path = (char_u *)".";
} else {
- path = (char_u *)vim_getenv("PATH");
+ // For an absolute name we don't use $PATH.
+ if (!path_is_absolute(pat)) {
+ path = (char_u *)vim_getenv("PATH");
+ }
if (path == NULL) {
path = (char_u *)"";
} else {
@@ -4993,6 +4986,8 @@ static void expand_shellcmd(char_u *filepat, int *num_file, char_u ***file,
* current directory, to find "subdir/cmd".
*/
ga_init(&ga, (int)sizeof(char *), 10);
+ hashtab_T found_ht;
+ hash_init(&found_ht);
for (s = path; ; s = e) {
if (*s == NUL) {
if (did_curdir) {
@@ -5004,17 +4999,15 @@ static void expand_shellcmd(char_u *filepat, int *num_file, char_u ***file,
did_curdir = true;
}
- if (*s == ' ') {
- s++; // Skip space used for absolute path name.
- }
-
- e = vim_strchr(s, ':');
- if (e == NULL)
+ e = vim_strchr(s, ENV_SEPCHAR);
+ if (e == NULL) {
e = s + STRLEN(s);
+ }
- l = e - s;
- if (l > MAXPATHL - 5)
+ l = (size_t)(e - s);
+ if (l > MAXPATHL - 5) {
break;
+ }
STRLCPY(buf, s, l + 1);
add_pathsep((char *)buf);
l = STRLEN(buf);
@@ -5025,14 +5018,24 @@ static void expand_shellcmd(char_u *filepat, int *num_file, char_u ***file,
if (ret == OK) {
ga_grow(&ga, *num_file);
{
- for (i = 0; i < *num_file; ++i) {
- s = (*file)[i];
- if (STRLEN(s) > l) {
- /* Remove the path again. */
- STRMOVE(s, s + l);
- ((char_u **)ga.ga_data)[ga.ga_len++] = s;
- } else
- xfree(s);
+ for (i = 0; i < *num_file; i++) {
+ char_u *name = (*file)[i];
+
+ if (STRLEN(name) > l) {
+ // Check if this name was already found.
+ hash_T hash = hash_hash(name + l);
+ hashitem_T *hi =
+ hash_lookup(&found_ht, (const char *)(name + l),
+ STRLEN(name + l), hash);
+ if (HASHITEM_EMPTY(hi)) {
+ // Remove the path that was prepended.
+ STRMOVE(name, name + l);
+ ((char_u **)ga.ga_data)[ga.ga_len++] = name;
+ hash_add_item(&found_ht, hi, name, hash);
+ name = NULL;
+ }
+ }
+ xfree(name);
}
xfree(*file);
}
@@ -5048,6 +5051,7 @@ static void expand_shellcmd(char_u *filepat, int *num_file, char_u ***file,
if (mustfree) {
xfree(path);
}
+ hash_clear(&found_ht);
}
/// Call "user_expand_func()" to invoke a user defined Vim script function and
@@ -5055,9 +5059,9 @@ static void expand_shellcmd(char_u *filepat, 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)
{
- int keep = 0;
- char_u num[50];
- char_u *args[3];
+ char_u keep = 0;
+ typval_T args[4];
+ char_u *pat = NULL;
int save_current_SID = current_SID;
void *ret;
struct cmdline_info save_ccline;
@@ -5072,10 +5076,14 @@ static void * call_user_expand_func(user_expand_func_T user_expand_func,
ccline.cmdbuff[ccline.cmdlen] = 0;
}
- args[0] = vim_strnsave(xp->xp_pattern, xp->xp_pattern_len);
- args[1] = xp->xp_line;
- sprintf((char *)num, "%d", xp->xp_col);
- args[2] = num;
+ pat = vim_strnsave(xp->xp_pattern, xp->xp_pattern_len);
+ args[0].v_type = VAR_STRING;
+ args[1].v_type = VAR_STRING;
+ args[2].v_type = VAR_NUMBER;
+ args[3].v_type = VAR_UNKNOWN;
+ args[0].vval.v_string = pat;
+ 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_ccline = ccline;
@@ -5085,7 +5093,7 @@ static void * call_user_expand_func(user_expand_func_T user_expand_func,
ret = user_expand_func(xp->xp_arg,
3,
- (const char_u * const *)args,
+ args,
false);
ccline = save_ccline;
@@ -5093,7 +5101,7 @@ static void * call_user_expand_func(user_expand_func_T user_expand_func,
if (ccline.cmdbuff != NULL)
ccline.cmdbuff[ccline.cmdlen] = keep;
- xfree(args[0]);
+ xfree(pat);
return ret;
}
@@ -5117,14 +5125,14 @@ static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, int *num_file,
e = vim_strchr(s, '\n');
if (e == NULL)
e = s + STRLEN(s);
- const int keep = *e;
+ const char_u keep = *e;
*e = NUL;
const bool skip = xp->xp_pattern[0]
&& vim_regexec(regmatch, s, (colnr_T)0) == 0;
*e = keep;
if (!skip) {
- GA_APPEND(char_u *, &ga, vim_strnsave(s, (int)(e - s)));
+ GA_APPEND(char_u *, &ga, vim_strnsave(s, (size_t)(e - s)));
}
if (*e != NUL) {
@@ -5226,7 +5234,8 @@ static int ExpandRTDir(char_u *pat, int flags, int *num_file, char_u ***file,
}
s++;
*e = NUL;
- memmove(match, s, e - s + 1);
+ assert((e - s) + 1 >= 0);
+ memmove(match, s, (size_t)(e - s) + 1);
}
}
@@ -5262,8 +5271,7 @@ static int ExpandPackAddDir(char_u *pat, int *num_file, char_u ***file)
for (int i = 0; i < ga.ga_len; i++) {
char_u *match = ((char_u **)ga.ga_data)[i];
s = path_tail(match);
- char_u *e = s + STRLEN(s);
- memmove(match, s, e - s + 1);
+ memmove(match, s, STRLEN(s)+1);
}
if (GA_EMPTY(&ga)) {
@@ -5407,7 +5415,9 @@ void init_history(void)
// On copying them to the new arrays, we take the chance to reorder them.
if (newlen != oldlen) {
for (int type = 0; type < HIST_COUNT; type++) {
- histentry_T *temp = newlen ? xmalloc(newlen * sizeof(*temp)) : NULL;
+ histentry_T *temp = (newlen
+ ? xmalloc((size_t)newlen * sizeof(*temp))
+ : NULL);
int j = hisidx[type];
if (j >= 0) {
@@ -5572,7 +5582,6 @@ add_to_history (
)
{
histentry_T *hisptr;
- int len;
if (hislen == 0 || histype == HIST_INVALID) { // no history
return;
@@ -5604,12 +5613,12 @@ add_to_history (
hisptr = &history[histype][hisidx[histype]];
hist_free_entry(hisptr);
- /* Store the separator after the NUL of the string. */
- len = (int)STRLEN(new_entry);
+ // Store the separator after the NUL of the string.
+ size_t len = STRLEN(new_entry);
hisptr->hisstr = vim_strnsave(new_entry, len + 2);
hisptr->timestamp = os_time();
hisptr->additional_elements = NULL;
- hisptr->hisstr[len + 1] = sep;
+ hisptr->hisstr[len + 1] = (char_u)sep;
hisptr->hisnum = ++hisnum[histype];
if (histype == HIST_SEARCH && in_map)
@@ -5663,7 +5672,7 @@ char_u *get_cmdline_str(void)
if (p == NULL)
return NULL;
- return vim_strnsave(p->cmdbuff, p->cmdlen);
+ return vim_strnsave(p->cmdbuff, (size_t)p->cmdlen);
}
/*
@@ -5932,7 +5941,7 @@ void ex_history(exarg_T *eap)
while (ASCII_ISALPHA(*end)
|| vim_strchr((char_u *)":=@>/?", *end) != NULL)
end++;
- histype1 = get_histtype((const char *)arg, end - arg, false);
+ histype1 = get_histtype((const char *)arg, (size_t)(end - arg), false);
if (histype1 == HIST_INVALID) {
if (STRNICMP(arg, "all", end - arg) == 0) {
histype1 = 0;
@@ -5971,13 +5980,14 @@ void ex_history(exarg_T *eap)
if (hist[i].hisstr != NULL
&& hist[i].hisnum >= j && hist[i].hisnum <= k) {
msg_putchar('\n');
- sprintf((char *)IObuff, "%c%6d ", i == idx ? '>' : ' ',
- hist[i].hisnum);
- if (vim_strsize(hist[i].hisstr) > (int)Columns - 10)
+ snprintf((char *)IObuff, IOSIZE, "%c%6d ", i == idx ? '>' : ' ',
+ hist[i].hisnum);
+ if (vim_strsize(hist[i].hisstr) > Columns - 10) {
trunc_string(hist[i].hisstr, IObuff + STRLEN(IObuff),
- (int)Columns - 10, IOSIZE - (int)STRLEN(IObuff));
- else
+ Columns - 10, IOSIZE - (int)STRLEN(IObuff));
+ } else {
STRCAT(IObuff, hist[i].hisstr);
+ }
msg_outtrans(IObuff);
ui_flush();
}
@@ -6138,8 +6148,8 @@ static int open_cmdwin(void)
State = NORMAL;
setmouse();
- /* Trigger CmdwinEnter autocommands. */
- typestr[0] = cmdwin_type;
+ // Trigger CmdwinEnter autocommands.
+ typestr[0] = (char_u)cmdwin_type;
typestr[1] = NUL;
apply_autocmds(EVENT_CMDWINENTER, typestr, typestr, FALSE, curbuf);
if (restart_edit != 0) /* autocmd with ":startinsert" */
@@ -6217,7 +6227,7 @@ static int open_cmdwin(void)
if (ccline.cmdpos > ccline.cmdlen)
ccline.cmdpos = ccline.cmdlen;
if (cmdwin_result == K_IGNORE) {
- set_cmdspos_cursor();
+ ccline.cmdspos = cmd_screencol(ccline.cmdpos);
redrawcmd();
}
}
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index f2a664288b..d2620376c6 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -15,6 +15,7 @@
#include "nvim/ascii.h"
#include "nvim/fileio.h"
#include "nvim/buffer.h"
+#include "nvim/change.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
#include "nvim/diff.h"
@@ -58,10 +59,6 @@
#include "nvim/os/time.h"
#include "nvim/os/input.h"
-#if defined(HAVE_UTIME) && defined(HAVE_UTIME_H)
-# include <utime.h> /* for struct utimbuf */
-#endif
-
#define BUFSIZE 8192 /* size of normal write buffer */
#define SMBUFSIZE 256 /* size of emergency write buffer */
@@ -167,22 +164,22 @@ typedef struct AutoPatCmd {
* Structure to pass arguments from buf_write() to buf_write_bytes().
*/
struct bw_info {
- int bw_fd; /* file descriptor */
- char_u *bw_buf; /* buffer with data to be written */
- int bw_len; /* length of data */
+ int bw_fd; // file descriptor
+ 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 */
+ int bw_flags; // FIO_ flags
#endif
- 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 */
- 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 USE_ICONV
- iconv_t bw_iconv_fd; /* descriptor for iconv() or -1 */
+ 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
+ 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
+ iconv_t bw_iconv_fd; // descriptor for iconv() or -1
# endif
};
@@ -190,10 +187,6 @@ struct bw_info {
# include "fileio.c.generated.h"
#endif
-#ifdef UNIX
-#endif
-
-
static char *e_auchangedbuf = N_(
"E812: Autocommands changed buffer or buffer name");
@@ -266,8 +259,8 @@ static AutoPat *last_autopat[NUM_EVENTS] = {
*
* return FAIL for failure, NOTDONE for directory (failure), or OK
*/
-int
-readfile (
+int
+readfile(
char_u *fname,
char_u *sfname,
linenr_T from,
@@ -297,7 +290,7 @@ readfile (
int wasempty; /* buffer was empty before reading */
colnr_T len;
long size = 0;
- char_u *p = NULL;
+ uint8_t *p = NULL;
off_T filesize = 0;
int skip_read = false;
context_sha256_T sha_ctx;
@@ -335,10 +328,10 @@ readfile (
char_u *fenc_next = NULL; // next item in 'fencs' or NULL
bool advance_fenc = false;
long real_size = 0;
-# ifdef USE_ICONV
- iconv_t iconv_fd = (iconv_t)-1; /* descriptor for iconv() or -1 */
- int did_iconv = FALSE; /* TRUE when iconv() failed and trying
- 'charconvert' next */
+# 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
+ // 'charconvert' next
# endif
int converted = FALSE; /* TRUE if conversion done */
int notconverted = FALSE; /* TRUE if conversion wanted but it
@@ -849,7 +842,7 @@ retry:
fileformat = EOL_UNKNOWN; /* detect from file */
}
-# ifdef USE_ICONV
+# ifdef HAVE_ICONV
if (iconv_fd != (iconv_t)-1) {
/* aborted conversion with iconv(), close the descriptor */
iconv_close(iconv_fd);
@@ -916,15 +909,14 @@ retry:
-# ifdef USE_ICONV
- /*
- * Try using iconv() if we can't convert internally.
- */
+# ifdef HAVE_ICONV
+ // Try using iconv() if we can't convert internally.
if (fio_flags == 0
&& !did_iconv
- )
+ ) {
iconv_fd = (iconv_t)my_iconv_open(
enc_utf8 ? (char_u *)"utf-8" : p_enc, fenc);
+ }
# endif
/*
@@ -933,12 +925,12 @@ retry:
*/
if (fio_flags == 0 && !read_stdin && !read_buffer && *p_ccv != NUL
&& !read_fifo
-# ifdef USE_ICONV
+# ifdef HAVE_ICONV
&& iconv_fd == (iconv_t)-1
# endif
) {
-# ifdef USE_ICONV
- did_iconv = FALSE;
+# ifdef HAVE_ICONV
+ did_iconv = false;
# endif
/* Skip conversion when it's already done (retry for wrong
* "fileformat"). */
@@ -958,7 +950,7 @@ retry:
}
} else {
if (fio_flags == 0
-# ifdef USE_ICONV
+# ifdef HAVE_ICONV
&& iconv_fd == (iconv_t)-1
# endif
) {
@@ -1031,20 +1023,23 @@ retry:
* ucs-4 to utf-8: 4 bytes become up to 6 bytes, size must be
* multiple of 4 */
real_size = (int)size;
-# ifdef USE_ICONV
- if (iconv_fd != (iconv_t)-1)
+# ifdef HAVE_ICONV
+ if (iconv_fd != (iconv_t)-1) {
size = size / ICONV_MULT;
- else
+ } else {
# endif
- if (fio_flags & FIO_LATIN1)
+ if (fio_flags & FIO_LATIN1) {
size = size / 2;
- else if (fio_flags & (FIO_UCS2 | FIO_UTF16))
+ } else if (fio_flags & (FIO_UCS2 | FIO_UTF16)) {
size = (size * 2 / 3) & ~1;
- else if (fio_flags & FIO_UCS4)
+ } else if (fio_flags & FIO_UCS4) {
size = (size * 2 / 3) & ~3;
- else if (fio_flags == FIO_UCSBOM)
- size = size / ICONV_MULT; /* worst case */
-
+ } else if (fio_flags == FIO_UCSBOM) {
+ size = size / ICONV_MULT; // worst case
+ }
+# ifdef HAVE_ICONV
+ }
+# endif
if (conv_restlen > 0) {
// Insert unconverted bytes from previous line.
memmove(ptr, conv_rest, conv_restlen); // -V614
@@ -1120,7 +1115,7 @@ retry:
/* When we did a conversion report an error. */
if (fio_flags != 0
-# ifdef USE_ICONV
+# ifdef HAVE_ICONV
|| iconv_fd != (iconv_t)-1
# endif
) {
@@ -1143,7 +1138,7 @@ retry:
* leave the UTF8 checking code to do it, as it
* works slightly differently. */
if (bad_char_behavior != BAD_KEEP && (fio_flags != 0
-# ifdef USE_ICONV
+# ifdef HAVE_ICONV
|| iconv_fd != (iconv_t)-1
# endif
)) {
@@ -1152,8 +1147,8 @@ retry:
--conv_restlen;
}
}
- fio_flags = 0; /* don't convert this */
-# ifdef USE_ICONV
+ fio_flags = 0; // don't convert this
+# ifdef HAVE_ICONV
if (iconv_fd != (iconv_t)-1) {
iconv_close(iconv_fd);
iconv_fd = (iconv_t)-1;
@@ -1224,7 +1219,7 @@ retry:
if (size <= 0)
break;
-# ifdef USE_ICONV
+# ifdef HAVE_ICONV
if (iconv_fd != (iconv_t)-1) {
/*
* Attempt conversion of the read bytes to 'encoding' using
@@ -1283,7 +1278,7 @@ retry:
# endif
if (fio_flags != 0) {
- int u8c;
+ unsigned int u8c;
char_u *dest;
char_u *tail = NULL;
@@ -1431,33 +1426,13 @@ retry:
}
}
}
- if (enc_utf8) { /* produce UTF-8 */
- dest -= utf_char2len(u8c);
- (void)utf_char2bytes(u8c, dest);
- } else { /* produce Latin1 */
- --dest;
- if (u8c >= 0x100) {
- /* character doesn't fit in latin1, retry with
- * another fenc when possible, otherwise just
- * report the error. */
- if (can_retry)
- goto rewind_retry;
- if (conv_error == 0)
- conv_error = readfile_linenr(linecnt, ptr, p);
- if (bad_char_behavior == BAD_DROP)
- ++dest;
- else if (bad_char_behavior == BAD_KEEP)
- *dest = u8c;
- else if (eap != NULL && eap->bad_char != 0)
- *dest = bad_char_behavior;
- else
- *dest = 0xBF;
- } else
- *dest = u8c;
- }
+ assert(u8c <= INT_MAX);
+ // produce UTF-8
+ dest -= utf_char2len((int)u8c);
+ (void)utf_char2bytes((int)u8c, dest);
}
- /* move the linerest to before the converted characters */
+ // 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);
@@ -1465,18 +1440,19 @@ retry:
} else if (enc_utf8 && !curbuf->b_p_bin) {
int incomplete_tail = FALSE;
- /* Reading UTF-8: Check if the bytes are valid UTF-8. */
- for (p = ptr;; ++p) {
+ // Reading UTF-8: Check if the bytes are valid UTF-8.
+ for (p = ptr;; p++) {
int todo = (int)((ptr + size) - p);
int l;
- if (todo <= 0)
+ if (todo <= 0) {
break;
+ }
if (*p >= 0x80) {
- /* A length of 1 means it's an illegal byte. Accept
- * an incomplete character at the end though, the next
- * read() will get the next bytes, we'll check it
- * then. */
+ // A length of 1 means it's an illegal byte. Accept
+ // an incomplete character at the end though, the next
+ // read() will get the next bytes, we'll check it
+ // then.
l = utf_ptr2len_len(p, todo);
if (l > todo && !incomplete_tail) {
/* Avoid retrying with a different encoding when
@@ -1501,10 +1477,11 @@ retry:
* file is more likely than a conversion error. */
if (can_retry && !incomplete_tail)
break;
-# ifdef USE_ICONV
- /* When we did a conversion report an error. */
- if (iconv_fd != (iconv_t)-1 && conv_error == 0)
+# 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)
@@ -1524,15 +1501,18 @@ retry:
if (p < ptr + size && !incomplete_tail) {
/* Detected a UTF-8 error. */
rewind_retry:
- /* Retry reading with another conversion. */
-# ifdef USE_ICONV
- if (*p_ccv != NUL && iconv_fd != (iconv_t)-1)
- /* iconv() failed, try 'charconvert' */
- did_iconv = TRUE;
- else
+ // Retry reading with another conversion.
+# ifdef HAVE_ICONV
+ if (*p_ccv != NUL && iconv_fd != (iconv_t)-1) {
+ // iconv() failed, try 'charconvert'
+ did_iconv = true;
+ } else {
# endif
// use next item from 'fileencodings'
advance_fenc = true;
+# ifdef HAVE_ICONV
+ }
+# endif
file_rewind = true;
goto retry;
}
@@ -1731,13 +1711,13 @@ failed:
// Remember the current file format.
save_file_ff(curbuf);
// If editing a new file: set 'fenc' for the current buffer.
- // Also for ":read ++edit file".
+ // Also for ":read ++edit file".
set_string_option_direct((char_u *)"fenc", -1, fenc,
OPT_FREE | OPT_LOCAL, 0);
}
if (fenc_alloced)
xfree(fenc);
-# ifdef USE_ICONV
+# ifdef HAVE_ICONV
if (iconv_fd != (iconv_t)-1) {
iconv_close(iconv_fd);
# ifndef __clang_analyzer__
@@ -1782,6 +1762,9 @@ failed:
ml_delete(curbuf->b_ml.ml_line_count, false);
linecnt--;
}
+ curbuf->deleted_bytes = 0;
+ curbuf->deleted_codepoints = 0;
+ curbuf->deleted_codeunits = 0;
linecnt = curbuf->b_ml.ml_line_count - linecnt;
if (filesize == 0)
linecnt = 0;
@@ -2030,11 +2013,11 @@ bool is_dev_fd_file(char_u *fname)
* 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 */
+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
)
{
char_u *s;
@@ -2198,34 +2181,6 @@ static void check_marks_read(void)
curbuf->b_marks_read = true;
}
-#ifdef UNIX
-static void
-set_file_time (
- char_u *fname,
- time_t atime, /* access time */
- time_t mtime /* modification time */
-)
-{
-# if defined(HAVE_UTIME) && defined(HAVE_UTIME_H)
- struct utimbuf buf;
-
- buf.actime = atime;
- buf.modtime = mtime;
- (void)utime((char *)fname, &buf);
-# else
-# if defined(HAVE_UTIMES)
- struct timeval tvp[2];
-
- tvp[0].tv_sec = atime;
- tvp[0].tv_usec = 0;
- tvp[1].tv_sec = mtime;
- tvp[1].tv_usec = 0;
- (void)utimes((char *)fname, (const struct timeval *)&tvp);
-# endif
-# endif
-}
-#endif /* UNIX */
-
/*
* buf_write() - write to file "fname" lines "start" through "end"
*
@@ -2242,8 +2197,8 @@ set_file_time (
*
* return FAIL for failure, OK otherwise
*/
-int
-buf_write (
+int
+buf_write(
buf_T *buf,
char_u *fname,
char_u *sfname,
@@ -2346,7 +2301,7 @@ buf_write (
write_info.bw_conv_error = FALSE;
write_info.bw_conv_error_lnum = 0;
write_info.bw_restlen = 0;
-# ifdef USE_ICONV
+# ifdef HAVE_ICONV
write_info.bw_iconv_fd = (iconv_t)-1;
# endif
@@ -2887,9 +2842,9 @@ buf_write (
}
#ifdef UNIX
- set_file_time(backup,
- file_info_old.stat.st_atim.tv_sec,
- file_info_old.stat.st_mtim.tv_sec);
+ os_file_settime((char *)backup,
+ file_info_old.stat.st_atim.tv_sec,
+ file_info_old.stat.st_mtim.tv_sec);
#endif
#ifdef HAVE_ACL
mch_set_acl(backup, acl);
@@ -3067,7 +3022,7 @@ nobackup:
if (converted && wb_flags == 0) {
-# ifdef USE_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,
@@ -3097,7 +3052,7 @@ nobackup:
}
}
if (converted && wb_flags == 0
-# ifdef USE_ICONV
+# ifdef HAVE_ICONV
&& write_info.bw_iconv_fd == (iconv_t)-1
# endif
&& wfname == fname
@@ -3572,9 +3527,9 @@ restore_backup:
vim_rename(backup, (char_u *)org);
XFREE_CLEAR(backup); // don't delete the file
#ifdef UNIX
- set_file_time((char_u *)org,
- file_info_old.stat.st_atim.tv_sec,
- file_info_old.stat.st_mtim.tv_sec);
+ os_file_settime(org,
+ file_info_old.stat.st_atim.tv_sec,
+ file_info_old.stat.st_mtim.tv_sec);
#endif
}
}
@@ -3625,7 +3580,7 @@ nofail:
xfree(buffer);
xfree(fenc_tofree);
xfree(write_info.bw_conv_buf);
-# ifdef USE_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;
@@ -4000,7 +3955,7 @@ static int buf_write_bytes(struct bw_info *ip)
}
}
-# ifdef USE_ICONV
+# ifdef HAVE_ICONV
if (ip->bw_iconv_fd != (iconv_t)-1) {
const char *from;
size_t fromlen;
@@ -4303,15 +4258,13 @@ void shorten_buf_fname(buf_T *buf, char_u *dirname, int force)
buf->b_sfname = vim_strsave(p);
buf->b_fname = buf->b_sfname;
}
- if (p == NULL || buf->b_fname == NULL) {
+ if (p == NULL) {
buf->b_fname = buf->b_ffname;
}
}
}
-/*
- * Shorten filenames for all buffers.
- */
+/// Shorten filenames for all buffers.
void shorten_fnames(int force)
{
char_u dirname[MAXPATHL];
@@ -4320,8 +4273,8 @@ void shorten_fnames(int force)
FOR_ALL_BUFFERS(buf) {
shorten_buf_fname(buf, dirname, force);
- /* Always make the swap file name a full path, a "nofile" buffer may
- * also have a swap file. */
+ // 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();
@@ -4743,17 +4696,15 @@ 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.
+// Returns TRUE if some message was written (screen should be redrawn and
+// cursor positioned).
+int
+check_timestamps(
+ int focus // called for GUI focus event
)
{
int didit = 0;
@@ -4855,8 +4806,8 @@ static int move_lines(buf_T *frombuf, buf_T *tobuf)
* return 2 if a message has been displayed.
* return 0 otherwise.
*/
-int
-buf_check_timestamp (
+int
+buf_check_timestamp(
buf_T *buf,
int focus /* called for GUI focus event */
)
@@ -4866,13 +4817,12 @@ buf_check_timestamp (
char_u *path;
char *mesg = NULL;
char *mesg2 = "";
- int helpmesg = FALSE;
- int reload = FALSE;
- int can_reload = FALSE;
+ 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 int busy = FALSE;
- int n;
+ static bool busy = false;
char_u *s;
char *reason;
@@ -4897,16 +4847,16 @@ buf_check_timestamp (
&& buf->b_mtime != 0
&& (!(file_info_ok = os_fileinfo((char *)buf->b_ffname, &file_info))
|| time_differs(file_info.stat.st_mtim.tv_sec, buf->b_mtime)
- || (int)file_info.stat.st_mode != buf->b_orig_mode
- )) {
+ || (int)file_info.stat.st_mode != buf->b_orig_mode)) {
+ const long prev_b_mtime = buf->b_mtime;
+
retval = 1;
// set b_mtime to stop further warnings (e.g., when executing
// FileChangedShell autocmd)
if (!file_info_ok) {
- // When 'autoread' is set we'll check the file again to see if it
- // re-appears.
- buf->b_mtime = buf->b_p_ar;
+ // Check the file again later to see if it re-appears.
+ buf->b_mtime = -1;
buf->b_orig_size = 0;
buf->b_orig_mode = 0;
} else {
@@ -4915,28 +4865,25 @@ buf_check_timestamp (
/* Don't do anything for a directory. Might contain the file
* explorer. */
- if (os_isdir(buf->b_fname))
- ;
-
- /*
- * If 'autoread' is set, the buffer has no changes and the file still
- * exists, reload the buffer. Use the buffer-local option value if it
- * was set, the global option value otherwise.
- */
- else if ((buf->b_p_ar >= 0 ? buf->b_p_ar : p_ar)
- && !bufIsChanged(buf) && file_info_ok)
- reload = TRUE;
- else {
- if (!file_info_ok)
+ if (os_isdir(buf->b_fname)) {
+ } else if ((buf->b_p_ar >= 0 ? buf->b_p_ar : p_ar)
+ && !bufIsChanged(buf) && file_info_ok) {
+ // If 'autoread' is set, the buffer has no changes and the file still
+ // exists, reload the buffer. Use the buffer-local option value if it
+ // was set, the global option value otherwise.
+ reload = true;
+ } else {
+ if (!file_info_ok) {
reason = "deleted";
- else if (bufIsChanged(buf))
+ } else if (bufIsChanged(buf)) {
reason = "conflict";
- else if (orig_size != buf->b_orig_size || buf_contents_changed(buf))
+ } else if (orig_size != buf->b_orig_size || buf_contents_changed(buf)) {
reason = "changed";
- else if (orig_mode != buf->b_orig_mode)
+ } else if (orig_mode != buf->b_orig_mode) {
reason = "mode";
- else
+ } else {
reason = "time";
+ }
// Only give the warning if there are no FileChangedShell
// autocommands.
@@ -4945,8 +4892,8 @@ buf_check_timestamp (
set_vim_var_string(VV_FCS_REASON, reason, -1);
set_vim_var_string(VV_FCS_CHOICE, "", -1);
allbuf_lock++;
- n = apply_autocmds(EVENT_FILECHANGEDSHELL,
- buf->b_fname, buf->b_fname, false, buf);
+ bool n = apply_autocmds(EVENT_FILECHANGEDSHELL,
+ buf->b_fname, buf->b_fname, false, buf);
allbuf_lock--;
busy = false;
if (n) {
@@ -4954,25 +4901,28 @@ buf_check_timestamp (
EMSG(_("E246: FileChangedShell autocommand deleted buffer"));
}
s = get_vim_var_str(VV_FCS_CHOICE);
- if (STRCMP(s, "reload") == 0 && *reason != 'd')
- reload = TRUE;
- else if (STRCMP(s, "ask") == 0)
- n = FALSE;
- else
+ if (STRCMP(s, "reload") == 0 && *reason != 'd') {
+ reload = true;
+ } else if (STRCMP(s, "ask") == 0) {
+ n = false;
+ } else {
return 2;
+ }
}
if (!n) {
- if (*reason == 'd')
- mesg = _("E211: File \"%s\" no longer available");
- else {
- helpmesg = TRUE;
- can_reload = TRUE;
- /*
- * Check if the file contents really changed to avoid
- * giving a warning when only the timestamp was set (e.g.,
- * checked out of CVS). Always warn when the buffer was
- * changed.
- */
+ if (*reason == 'd') {
+ // Only give the message once.
+ if (prev_b_mtime != -1) {
+ mesg = _("E211: File \"%s\" no longer available");
+ }
+ } else {
+ helpmesg = true;
+ can_reload = true;
+
+ // Check if the file contents really changed to avoid
+ // giving a warning when only the timestamp was set (e.g.,
+ // checked out of CVS). Always warn when the buffer was
+ // changed.
if (reason[2] == 'n') {
mesg = _(
"W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as well");
@@ -4998,7 +4948,7 @@ buf_check_timestamp (
retval = 1;
mesg = _("W13: Warning: File \"%s\" has been created after editing started");
buf->b_flags |= BF_NEW_W;
- can_reload = TRUE;
+ can_reload = true;
}
if (mesg != NULL) {
@@ -6304,12 +6254,10 @@ static int do_autocmd_event(event_T event, char_u *pat, bool once, int nested,
return OK;
}
-/*
- * Implementation of ":doautocmd [group] event [fname]".
- * Return OK for success, FAIL for failure;
- */
-int
-do_doautocmd (
+// Implementation of ":doautocmd [group] event [fname]".
+// Return OK for success, FAIL for failure;
+int
+do_doautocmd(
char_u *arg,
int do_msg, // give message for no matching autocmds?
bool *did_something
@@ -7093,11 +7041,9 @@ void unblock_autocmds(void)
apply_autocmds(EVENT_TERMRESPONSE, NULL, NULL, FALSE, curbuf);
}
-/*
- * Find next autocommand pattern that matches.
- */
-static void
-auto_next_pat (
+// Find next autocommand pattern that matches.
+static void
+auto_next_pat(
AutoPatCmd *apc,
int stop_at_last /* stop when 'last' flag is set */
)
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index 72d8c14468..ad0bfe29e2 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -13,6 +13,7 @@
#include "nvim/vim.h"
#include "nvim/ascii.h"
#include "nvim/fold.h"
+#include "nvim/change.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
#include "nvim/diff.h"
diff --git a/src/nvim/func_attr.h b/src/nvim/func_attr.h
index d3b600a40c..14b8158c7f 100644
--- a/src/nvim/func_attr.h
+++ b/src/nvim/func_attr.h
@@ -205,8 +205,8 @@
#endif
#ifdef DEFINE_FUNC_ATTRIBUTES
-/// Non-deferred API function.
-# define FUNC_API_ASYNC
+/// Fast (non-deferred) API function.
+# define FUNC_API_FAST
/// Internal C function not exposed in the RPC API.
# define FUNC_API_NOEXPORT
/// API function not exposed in VimL/eval.
diff --git a/src/nvim/garray.c b/src/nvim/garray.c
index 74fd9d89cb..1cfc2b6176 100644
--- a/src/nvim/garray.c
+++ b/src/nvim/garray.c
@@ -89,6 +89,14 @@ void ga_grow(garray_T *gap, int n)
if (n < gap->ga_growsize) {
n = gap->ga_growsize;
}
+
+ // A linear growth is very inefficient when the array grows big. This
+ // is a compromise between allocating memory that won't be used and too
+ // many copy operations. A factor of 1.5 seems reasonable.
+ if (n < gap->ga_len / 2) {
+ n = gap->ga_len / 2;
+ }
+
int new_maxlen = gap->ga_len + n;
size_t new_size = (size_t)gap->ga_itemsize * (size_t)new_maxlen;
diff --git a/src/nvim/generators/c_grammar.lua b/src/nvim/generators/c_grammar.lua
index 40bdc3e30c..1aa8223da0 100644
--- a/src/nvim/generators/c_grammar.lua
+++ b/src/nvim/generators/c_grammar.lua
@@ -1,4 +1,4 @@
-lpeg = require('lpeg')
+local lpeg = require('lpeg')
-- lpeg grammar for building api metadata from a set of header files. It
-- ignores comments and preprocessor commands and parses a very small subset
@@ -35,11 +35,11 @@ local c_params = Ct(c_void + c_param_list)
local c_proto = Ct(
Cg(c_type, 'return_type') * Cg(c_id, 'name') *
fill * P('(') * fill * Cg(c_params, 'parameters') * fill * P(')') *
- Cg(Cc(false), 'async') *
+ Cg(Cc(false), 'fast') *
(fill * Cg((P('FUNC_API_SINCE(') * C(num ^ 1)) * P(')'), 'since') ^ -1) *
(fill * Cg((P('FUNC_API_DEPRECATED_SINCE(') * C(num ^ 1)) * P(')'),
'deprecated_since') ^ -1) *
- (fill * Cg((P('FUNC_API_ASYNC') * Cc(true)), 'async') ^ -1) *
+ (fill * Cg((P('FUNC_API_FAST') * Cc(true)), 'fast') ^ -1) *
(fill * Cg((P('FUNC_API_NOEXPORT') * Cc(true)), 'noexport') ^ -1) *
(fill * Cg((P('FUNC_API_REMOTE_ONLY') * Cc(true)), 'remote_only') ^ -1) *
(fill * Cg((P('FUNC_API_REMOTE_IMPL') * Cc(true)), 'remote_impl') ^ -1) *
diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua
index f52d05a4a5..76dcf849d1 100644
--- a/src/nvim/generators/gen_api_dispatch.lua
+++ b/src/nvim/generators/gen_api_dispatch.lua
@@ -1,4 +1,4 @@
-mpack = require('mpack')
+local mpack = require('mpack')
-- we need at least 4 arguments since the last two are output files
if arg[1] == '--help' then
@@ -11,27 +11,27 @@ if arg[1] == '--help' then
print(' rest: C files where API functions are defined')
end
assert(#arg >= 4)
-functions = {}
+local functions = {}
local nvimdir = arg[1]
package.path = nvimdir .. '/?.lua;' .. package.path
-- names of all headers relative to the source root (for inclusion in the
-- generated file)
-headers = {}
+local headers = {}
-- output h file with generated dispatch functions
-dispatch_outputf = arg[2]
+local dispatch_outputf = arg[2]
-- output h file with packed metadata
-funcs_metadata_outputf = arg[3]
+local funcs_metadata_outputf = arg[3]
-- output metadata mpack file, for use by other build scripts
-mpack_outputf = arg[4]
-lua_c_bindings_outputf = arg[5]
+local mpack_outputf = arg[4]
+local lua_c_bindings_outputf = arg[5]
-- set of function names, used to detect duplicates
-function_names = {}
+local function_names = {}
-c_grammar = require('generators.c_grammar')
+local c_grammar = require('generators.c_grammar')
-- read each input file, parse and append to the api metadata
for i = 6, #arg do
@@ -45,10 +45,10 @@ for i = 6, #arg do
local input = io.open(full_path, 'rb')
local tmp = c_grammar.grammar:match(input:read('*all'))
- for i = 1, #tmp do
- local fn = tmp[i]
+ for j = 1, #tmp do
+ local fn = tmp[j]
if not fn.noexport then
- functions[#functions + 1] = tmp[i]
+ functions[#functions + 1] = tmp[j]
function_names[fn.name] = true
if #fn.parameters ~= 0 and fn.parameters[1][2] == 'channel_id' then
-- this function should receive the channel id
@@ -83,7 +83,7 @@ end
-- Export functions under older deprecated names.
-- These will be removed eventually.
local deprecated_aliases = require("api.dispatch_deprecated")
-for i,f in ipairs(shallowcopy(functions)) do
+for _,f in ipairs(shallowcopy(functions)) do
local ismethod = false
if startswith(f.name, "nvim_") then
if startswith(f.name, "nvim__") then
@@ -135,9 +135,9 @@ for i,f in ipairs(shallowcopy(functions)) do
end
-- don't expose internal attributes like "impl_name" in public metadata
-exported_attributes = {'name', 'return_type', 'method',
- 'since', 'deprecated_since'}
-exported_functions = {}
+local exported_attributes = {'name', 'return_type', 'method',
+ 'since', 'deprecated_since'}
+local exported_functions = {}
for _,f in ipairs(functions) do
if not startswith(f.name, "nvim__") then
local f_exported = {}
@@ -158,14 +158,14 @@ end
-- serialize the API metadata using msgpack and embed into the resulting
-- binary for easy querying by clients
-funcs_metadata_output = io.open(funcs_metadata_outputf, 'wb')
-packed = mpack.pack(exported_functions)
-dump_bin_array = require("generators.dump_bin_array")
+local funcs_metadata_output = io.open(funcs_metadata_outputf, 'wb')
+local packed = mpack.pack(exported_functions)
+local dump_bin_array = require("generators.dump_bin_array")
dump_bin_array(funcs_metadata_output, 'funcs_metadata', packed)
funcs_metadata_output:close()
-- start building the dispatch wrapper output
-output = io.open(dispatch_outputf, 'wb')
+local output = io.open(dispatch_outputf, 'wb')
local function real_type(type)
local rv = type
@@ -198,7 +198,8 @@ for i = 1, #functions do
output:write('Object handle_'..fn.name..'(uint64_t channel_id, Array args, Error *error)')
output:write('\n{')
output:write('\n#if MIN_LOG_LEVEL <= DEBUG_LOG_LEVEL')
- output:write('\n logmsg(DEBUG_LOG_LEVEL, "RPC: ", NULL, -1, true, "invoke '..fn.name..'");')
+ output:write('\n logmsg(DEBUG_LOG_LEVEL, "RPC: ", NULL, -1, true, "ch %" PRIu64 ": invoke '
+ ..fn.name..'", channel_id);')
output:write('\n#endif')
output:write('\n Object ret = NIL;')
-- Declare/initialize variables that will hold converted arguments
@@ -209,20 +210,22 @@ for i = 1, #functions do
end
output:write('\n')
output:write('\n if (args.size != '..#fn.parameters..') {')
- output:write('\n api_set_error(error, kErrorTypeException, "Wrong number of arguments: expecting '..#fn.parameters..' but got %zu", args.size);')
+ output:write('\n api_set_error(error, kErrorTypeException, \
+ "Wrong number of arguments: expecting '..#fn.parameters..' but got %zu", args.size);')
output:write('\n goto cleanup;')
output:write('\n }\n')
-- Validation/conversion for each argument
for j = 1, #fn.parameters do
- local converted, convert_arg, param, arg
+ local converted, param
param = fn.parameters[j]
converted = 'arg_'..j
local rt = real_type(param[1])
if rt ~= 'Object' then
if rt:match('^Buffer$') or rt:match('^Window$') or rt:match('^Tabpage$') then
-- Buffer, Window, and Tabpage have a specific type, but are stored in integer
- output:write('\n if (args.items['..(j - 1)..'].type == kObjectType'..rt..' && args.items['..(j - 1)..'].data.integer >= 0) {')
+ output:write('\n if (args.items['..
+ (j - 1)..'].type == kObjectType'..rt..' && args.items['..(j - 1)..'].data.integer >= 0) {')
output:write('\n '..converted..' = (handle_T)args.items['..(j - 1)..'].data.integer;')
else
output:write('\n if (args.items['..(j - 1)..'].type == kObjectType'..rt..') {')
@@ -230,16 +233,18 @@ for i = 1, #functions do
end
if rt:match('^Buffer$') or rt:match('^Window$') or rt:match('^Tabpage$') or rt:match('^Boolean$') then
-- accept nonnegative integers for Booleans, Buffers, Windows and Tabpages
- output:write('\n } else if (args.items['..(j - 1)..'].type == kObjectTypeInteger && args.items['..(j - 1)..'].data.integer >= 0) {')
+ output:write('\n } else if (args.items['..
+ (j - 1)..'].type == kObjectTypeInteger && args.items['..(j - 1)..'].data.integer >= 0) {')
output:write('\n '..converted..' = (handle_T)args.items['..(j - 1)..'].data.integer;')
end
-- accept empty lua tables as empty dictionarys
if rt:match('^Dictionary') then
- output:write('\n } else if (args.items['..(j - 1)..'].type == kObjectTypeArray && args.items['..(j - 1)..'].data.array.size == 0) {')
+ 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;')
end
output:write('\n } else {')
- output:write('\n api_set_error(error, kErrorTypeException, "Wrong type for argument '..j..', expecting '..param[1]..'");')
+ output:write('\n api_set_error(error, kErrorTypeException, \
+ "Wrong type for argument '..j..', expecting '..param[1]..'");')
output:write('\n goto cleanup;')
output:write('\n }\n')
else
@@ -309,26 +314,26 @@ for i = 1, #functions do
'(String) {.data = "'..fn.name..'", '..
'.size = sizeof("'..fn.name..'") - 1}, '..
'(MsgpackRpcRequestHandler) {.fn = handle_'.. (fn.impl_name or fn.name)..
- ', .async = '..tostring(fn.async)..'});\n')
+ ', .fast = '..tostring(fn.fast)..'});\n')
end
output:write('\n}\n\n')
output:close()
-mpack_output = io.open(mpack_outputf, 'wb')
+local mpack_output = io.open(mpack_outputf, 'wb')
mpack_output:write(mpack.pack(functions))
mpack_output:close()
-local function include_headers(output, headers)
- for i = 1, #headers do
- if headers[i]:sub(-12) ~= '.generated.h' then
- output:write('\n#include "nvim/'..headers[i]..'"')
+local function include_headers(output_handle, headers_to_include)
+ for i = 1, #headers_to_include do
+ if headers_to_include[i]:sub(-12) ~= '.generated.h' then
+ output_handle:write('\n#include "nvim/'..headers_to_include[i]..'"')
end
end
end
-local function write_shifted_output(output, str)
+local function write_shifted_output(_, str)
str = str:gsub('\n ', '\n')
str = str:gsub('^ ', '')
str = str:gsub(' +$', '')
@@ -349,14 +354,15 @@ output:write([[
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
#include "nvim/lua/converter.h"
+#include "nvim/lua/executor.h"
]])
include_headers(output, headers)
output:write('\n')
-lua_c_functions = {}
+local lua_c_functions = {}
local function process_function(fn)
- lua_c_function_name = ('nlua_msgpack_%s'):format(fn.name)
+ local lua_c_function_name = ('nlua_msgpack_%s'):format(fn.name)
write_shifted_output(output, string.format([[
static int %s(lua_State *lstate)
@@ -372,14 +378,22 @@ local function process_function(fn)
binding=lua_c_function_name,
api=fn.name
}
+
+ if not fn.fast then
+ write_shifted_output(output, string.format([[
+ if (!nlua_is_deferred_safe(lstate)) {
+ return luaL_error(lstate, e_luv_api_disabled, "%s");
+ }
+ ]], fn.name))
+ end
local cparams = ''
local free_code = {}
for j = #fn.parameters,1,-1 do
- param = fn.parameters[j]
- cparam = string.format('arg%u', j)
- param_type = real_type(param[1])
- lc_param_type = real_type(param[1]):lower()
- extra = ((param_type == "Object" or param_type == "Dictionary") and "false, ") or ""
+ local param = fn.parameters[j]
+ local cparam = string.format('arg%u', j)
+ local param_type = real_type(param[1])
+ local lc_param_type = real_type(param[1]):lower()
+ local extra = ((param_type == "Object" or param_type == "Dictionary") and "false, ") or ""
if param[1] == "DictionaryOf(LuaRef)" then
extra = "true, "
end
@@ -424,6 +438,7 @@ local function process_function(fn)
return lua_error(lstate);
}
]]
+ local return_type
if fn.return_type ~= 'void' then
if fn.return_type:match('^ArrayOf') then
return_type = 'Array'
@@ -432,7 +447,7 @@ local function process_function(fn)
end
write_shifted_output(output, string.format([[
const %s ret = %s(%s);
- nlua_push_%s(lstate, ret);
+ nlua_push_%s(lstate, ret, true);
api_free_%s(ret);
%s
%s
diff --git a/src/nvim/generators/gen_api_ui_events.lua b/src/nvim/generators/gen_api_ui_events.lua
index c8ab310b02..3cb117d8b5 100644
--- a/src/nvim/generators/gen_api_ui_events.lua
+++ b/src/nvim/generators/gen_api_ui_events.lua
@@ -1,20 +1,20 @@
-mpack = require('mpack')
+local mpack = require('mpack')
local nvimdir = arg[1]
package.path = nvimdir .. '/?.lua;' .. package.path
assert(#arg == 7)
-input = io.open(arg[2], 'rb')
-proto_output = io.open(arg[3], 'wb')
-call_output = io.open(arg[4], 'wb')
-remote_output = io.open(arg[5], 'wb')
-bridge_output = io.open(arg[6], 'wb')
-metadata_output = io.open(arg[7], 'wb')
-
-c_grammar = require('generators.c_grammar')
+local input = io.open(arg[2], 'rb')
+local proto_output = io.open(arg[3], 'wb')
+local call_output = io.open(arg[4], 'wb')
+local remote_output = io.open(arg[5], 'wb')
+local bridge_output = io.open(arg[6], 'wb')
+local metadata_output = io.open(arg[7], 'wb')
+
+local c_grammar = require('generators.c_grammar')
local events = c_grammar.grammar:match(input:read('*all'))
-function write_signature(output, ev, prefix, notype)
+local function write_signature(output, ev, prefix, notype)
output:write('('..prefix)
if prefix == "" and #ev.parameters == 0 then
output:write('void')
@@ -32,7 +32,7 @@ function write_signature(output, ev, prefix, notype)
output:write(')')
end
-function write_arglist(output, ev, need_copy)
+local function write_arglist(output, ev, need_copy)
output:write(' Array args = ARRAY_DICT_INIT;\n')
for j = 1, #ev.parameters do
local param = ev.parameters[j]
@@ -51,7 +51,7 @@ function write_arglist(output, ev, need_copy)
end
for i = 1, #events do
- ev = events[i]
+ local ev = events[i]
assert(ev.return_type == 'void')
if ev.since == nil and not ev.noexport then
@@ -75,11 +75,11 @@ for i = 1, #events do
end
if not ev.bridge_impl and not ev.noexport then
- send, argv, recv, recv_argv, recv_cleanup = '', '', '', '', ''
- argc = 1
+ local send, argv, recv, recv_argv, recv_cleanup = '', '', '', '', ''
+ local argc = 1
for j = 1, #ev.parameters do
local param = ev.parameters[j]
- copy = 'copy_'..param[2]
+ local copy = 'copy_'..param[2]
if param[1] == 'String' then
send = send..' String copy_'..param[2]..' = copy_string('..param[2]..');\n'
argv = argv..', '..copy..'.data, INT2PTR('..copy..'.size)'
@@ -160,7 +160,6 @@ for i = 1, #events do
call_output:write(";\n")
call_output:write("}\n\n")
end
-
end
proto_output:close()
@@ -169,9 +168,9 @@ remote_output:close()
bridge_output:close()
-- don't expose internal attributes like "impl_name" in public metadata
-exported_attributes = {'name', 'parameters',
+local exported_attributes = {'name', 'parameters',
'since', 'deprecated_since'}
-exported_events = {}
+local exported_events = {}
for _,ev in ipairs(events) do
local ev_exported = {}
for _,attr in ipairs(exported_attributes) do
@@ -187,7 +186,7 @@ for _,ev in ipairs(events) do
end
end
-packed = mpack.pack(exported_events)
-dump_bin_array = require("generators.dump_bin_array")
+local packed = mpack.pack(exported_events)
+local dump_bin_array = require("generators.dump_bin_array")
dump_bin_array(metadata_output, 'ui_events_metadata', packed)
metadata_output:close()
diff --git a/src/nvim/generators/gen_char_blob.lua b/src/nvim/generators/gen_char_blob.lua
index d860375e26..1702add2e4 100644
--- a/src/nvim/generators/gen_char_blob.lua
+++ b/src/nvim/generators/gen_char_blob.lua
@@ -13,16 +13,17 @@ local source_file = arg[1]
local target_file = arg[2]
local varname = arg[3]
-source = io.open(source_file, 'r')
-target = io.open(target_file, 'w')
+local source = io.open(source_file, 'r')
+local target = io.open(target_file, 'w')
target:write('#include <stdint.h>\n\n')
target:write(('static const uint8_t %s[] = {\n'):format(varname))
-num_bytes = 0
-MAX_NUM_BYTES = 15 -- 78 / 5: maximum number of bytes on one line
+local num_bytes = 0
+local MAX_NUM_BYTES = 15 -- 78 / 5: maximum number of bytes on one line
target:write(' ')
+local increase_num_bytes
increase_num_bytes = function()
num_bytes = num_bytes + 1
if num_bytes == MAX_NUM_BYTES then
@@ -33,7 +34,7 @@ end
for line in source:lines() do
for i = 1,string.len(line) do
- byte = string.byte(line, i)
+ local byte = string.byte(line, i)
assert(byte ~= 0)
target:write(string.format(' %3u,', byte))
increase_num_bytes()
diff --git a/src/nvim/generators/gen_declarations.lua b/src/nvim/generators/gen_declarations.lua
index c40c37bb3e..ad44613f42 100755
--- a/src/nvim/generators/gen_declarations.lua
+++ b/src/nvim/generators/gen_declarations.lua
@@ -10,7 +10,7 @@ local lpeg = require('lpeg')
local fold = function (func, ...)
local result = nil
- for i, v in ipairs({...}) do
+ for _, v in ipairs({...}) do
if result == nil then
result = v
else
@@ -107,7 +107,7 @@ local typ_part = concat(
)),
spaces
)
-local typ = one_or_more(typ_part)
+
local typ_id = two_or_more(typ_part)
local arg = typ_id -- argument name is swallowed by typ
local pattern = concat(
@@ -222,7 +222,6 @@ local non_static = header
local static = header
local filepattern = '^#%a* (%d+) "([^"]-)/?([^"/]+)"'
-local curfile
local init = 1
local curfile = nil
@@ -248,14 +247,14 @@ while init ~= nil do
else
declline = declline - 1
end
- elseif init < declendpos then
+ elseif init < declendpos then -- luacheck: ignore 542
-- Skipping over declaration
elseif is_needed_file then
s = init
- e = pattern:match(text, init)
+ local e = pattern:match(text, init)
if e ~= nil then
local declaration = text:sub(s, e - 1)
- -- Comments are really handled by preprocessor, so the following is not
+ -- Comments are really handled by preprocessor, so the following is not
-- needed
declaration = declaration:gsub('/%*.-%*/', '')
declaration = declaration:gsub('//.-\n', '\n')
diff --git a/src/nvim/generators/gen_eval.lua b/src/nvim/generators/gen_eval.lua
index 23435a1d0b..2c6f8f2603 100644
--- a/src/nvim/generators/gen_eval.lua
+++ b/src/nvim/generators/gen_eval.lua
@@ -1,4 +1,4 @@
-mpack = require('mpack')
+local mpack = require('mpack')
local nvimsrcdir = arg[1]
local autodir = arg[2]
@@ -8,9 +8,9 @@ local funcs_file = arg[4]
if nvimsrcdir == '--help' then
print([[
Usage:
- lua geneval.lua src/nvim build/src/nvim/auto
+ lua gen_eval.lua src/nvim build/src/nvim/auto
-Will generate build/src/nvim/auto/funcs.generated.h with definition of functions
+Will generate build/src/nvim/auto/funcs.generated.h with definition of functions
static const array.
]])
os.exit(0)
@@ -23,8 +23,8 @@ local funcsfname = autodir .. '/funcs.generated.h'
local gperfpipe = io.open(funcsfname .. '.gperf', 'wb')
local funcs = require('eval').funcs
-local metadata = mpack.unpack(io.open(arg[3], 'rb'):read("*all"))
-for i,fun in ipairs(metadata) do
+local metadata = mpack.unpack(io.open(metadata_file, 'rb'):read("*all"))
+for _,fun in ipairs(metadata) do
if not fun.remote_only then
funcs[fun.name] = {
args=#fun.parameters,
@@ -53,14 +53,14 @@ VimLFuncDef;
]])
for name, def in pairs(funcs) do
- args = def.args or 0
+ local args = def.args or 0
if type(args) == 'number' then
args = {args, args}
elseif #args == 1 then
args[2] = 'MAX_FUNC_ARGS'
end
- func = def.func or ('f_' .. name)
- data = def.data or "NULL"
+ 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))
end
diff --git a/src/nvim/generators/gen_events.lua b/src/nvim/generators/gen_events.lua
index d03c787b2b..98c3254e7a 100644
--- a/src/nvim/generators/gen_events.lua
+++ b/src/nvim/generators/gen_events.lua
@@ -13,8 +13,8 @@ local auevents = require('auevents')
local events = auevents.events
local aliases = auevents.aliases
-enum_tgt = io.open(fileio_enum_file, 'w')
-names_tgt = io.open(names_file, 'w')
+local enum_tgt = io.open(fileio_enum_file, 'w')
+local names_tgt = io.open(names_file, 'w')
enum_tgt:write('typedef enum auto_event {')
names_tgt:write([[
@@ -42,8 +42,8 @@ enum_tgt:write('\n} event_T;\n')
names_tgt:write('\n};\n')
names_tgt:write('\nstatic AutoPat *first_autopat[NUM_EVENTS] = {\n ')
-line_len = 1
-for i = 1,((#events) - 1) do
+local line_len = 1
+for _ = 1,((#events) - 1) do
line_len = line_len + #(' NULL,')
if line_len > 80 then
names_tgt:write('\n ')
diff --git a/src/nvim/generators/gen_ex_cmds.lua b/src/nvim/generators/gen_ex_cmds.lua
index 7859d7c71a..075d8ba9cc 100644
--- a/src/nvim/generators/gen_ex_cmds.lua
+++ b/src/nvim/generators/gen_ex_cmds.lua
@@ -7,8 +7,8 @@ if nvimsrcdir == '--help' then
Usage:
lua genex_cmds.lua src/nvim build/include build/src/nvim/auto
-Will generate files build/include/ex_cmds_enum.generated.h with cmdidx_T
-enum and build/src/nvim/auto/ex_cmds_defs.generated.h with main Ex commands
+Will generate files build/include/ex_cmds_enum.generated.h with cmdidx_T
+enum and build/src/nvim/auto/ex_cmds_defs.generated.h with main Ex commands
definitions.
]])
os.exit(0)
@@ -23,10 +23,7 @@ local enumfile = io.open(enumfname, 'w')
local defsfile = io.open(defsfname, 'w')
local defs = require('ex_cmds')
-local lastchar = nil
-local i
-local cmd
local first = true
local byte_a = string.byte('a')
@@ -58,7 +55,7 @@ defsfile:write(string.format([[
static CommandDefinition cmdnames[%u] = {
]], #defs))
local cmds, cmdidxs1, cmdidxs2 = {}, {}, {}
-for i, cmd in ipairs(defs) do
+for _, cmd in ipairs(defs) do
local enumname = cmd.enum or ('CMD_' .. cmd.command)
local byte_cmd = cmd.command:sub(1, 1):byte()
if byte_a <= byte_cmd and byte_cmd <= byte_z then
diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua
index fdc00d5dc0..a8cf496cb9 100644
--- a/src/nvim/generators/gen_options.lua
+++ b/src/nvim/generators/gen_options.lua
@@ -20,7 +20,7 @@ end
local options = require('options')
-cstr = options.cstr
+local cstr = options.cstr
local type_flags={
bool='P_BOOL',
@@ -79,6 +79,7 @@ local get_flags = function(o)
{'pri_mkrc'},
{'deny_in_modelines', 'P_NO_ML'},
{'deny_duplicates', 'P_NODUP'},
+ {'modelineexpr', 'P_MLE'},
}) do
local key_name = flag_desc[1]
local def_name = flag_desc[2] or ('P_' .. key_name:upper())
@@ -107,12 +108,12 @@ get_cond = function(c, base_string)
return cond_string
end
-value_dumpers = {
+local value_dumpers = {
['function']=function(v) return v() end,
string=cstr,
boolean=function(v) return v and 'true' or 'false' end,
number=function(v) return ('%iL'):format(v) end,
- ['nil']=function(v) return '0L' end,
+ ['nil']=function(_) return '0L' end,
}
local get_value = function(v)
diff --git a/src/nvim/generators/gen_unicode_tables.lua b/src/nvim/generators/gen_unicode_tables.lua
index 3130cecd82..aa96c97bc1 100644
--- a/src/nvim/generators/gen_unicode_tables.lua
+++ b/src/nvim/generators/gen_unicode_tables.lua
@@ -1,16 +1,16 @@
-- Script creates the following tables in unicode_tables.generated.h:
--
--- 1. doublewidth and ambiguous tables: sorted list of non-overlapping closed
--- intervals. Codepoints in these intervals have double (W or F) or ambiguous
+-- 1. doublewidth and ambiguous tables: sorted list of non-overlapping closed
+-- intervals. Codepoints in these intervals have double (W or F) or ambiguous
-- (A) east asian width respectively.
--- 2. combining table: same as the above, but characters inside are combining
+-- 2. combining table: same as the above, but characters inside are combining
-- characters (i.e. have general categories equal to Mn, Mc or Me).
--- 3. foldCase, toLower and toUpper tables used to convert characters to
--- folded/lower/upper variants. In these tables first two values are
--- character ranges: like in previous tables they are sorted and must be
--- non-overlapping. Third value means step inside the range: e.g. if it is
--- 2 then interval applies only to first, third, fifth, … character in range.
--- Fourth value is number that should be added to the codepoint to yield
+-- 3. foldCase, toLower and toUpper tables used to convert characters to
+-- folded/lower/upper variants. In these tables first two values are
+-- character ranges: like in previous tables they are sorted and must be
+-- non-overlapping. Third value means step inside the range: e.g. if it is
+-- 2 then interval applies only to first, third, fifth, … character in range.
+-- Fourth value is number that should be added to the codepoint to yield
-- folded/lower/upper codepoint.
-- 4. emoji_width and emoji_all tables: sorted lists of non-overlapping closed
-- intervals of Emoji characters. emoji_width contains all the characters
@@ -38,7 +38,7 @@ local split_on_semicolons = function(s)
local ret = {}
local idx = 1
while idx <= #s + 1 do
- item = s:match('^[^;]*', idx)
+ local item = s:match('^[^;]*', idx)
idx = idx + #item + 1
if idx <= #s + 1 then
assert(s:sub(idx - 1, idx - 1) == ';')
@@ -208,7 +208,7 @@ local build_width_table = function(ut_fp, dataprops, widthprops, widths,
-- But use all chars from a range.
local dp = dataprops[dataidx]
if (n_last > n) or (not (({Mn=true, Mc=true, Me=true})[dp[3]])) then
- if start >= 0 and end_ + 1 == n then
+ if start >= 0 and end_ + 1 == n then -- luacheck: ignore 542
-- Continue with the same range.
else
if start >= 0 then
@@ -235,6 +235,8 @@ local build_emoji_table = function(ut_fp, emojiprops, doublewidth, ambiwidth)
for _, p in ipairs(emojiprops) do
if p[2]:match('Emoji%s+#') then
local rng_start, rng_end = p[1]:find('%.%.')
+ local n
+ local n_last
if rng_start then
n = tonumber(p[1]:sub(1, rng_start - 1), 16)
n_last = tonumber(p[1]:sub(rng_end + 1), 16)
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 7e4a0e1321..03f64c2019 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -15,6 +15,7 @@
#include <string.h>
#include <inttypes.h>
+#include "nvim/assert.h"
#include "nvim/vim.h"
#include "nvim/ascii.h"
#include "nvim/getchar.h"
@@ -82,10 +83,10 @@ static buffheader_T old_redobuff = { { NULL, { NUL } }, NULL, 0, 0 };
static buffheader_T recordbuff = { { NULL, { NUL } }, NULL, 0, 0 };
// First read ahead buffer. Used for translated commands.
-static buffheader_T readbuf1 = {{NULL, {NUL}}, NULL, 0, 0};
+static buffheader_T readbuf1 = { { NULL, { NUL } }, NULL, 0, 0 };
// Second read ahead buffer. Used for redo.
-static buffheader_T readbuf2 = {{NULL, {NUL}}, NULL, 0, 0};
+static buffheader_T readbuf2 = { { NULL, { NUL } }, NULL, 0, 0 };
static int typeahead_char = 0; /* typeahead char that's not flushed */
@@ -181,18 +182,22 @@ static char_u *get_buffcont(buffheader_T *buffer,
size_t count = 0;
char_u *p = NULL;
char_u *p2;
- char_u *str;
- /* compute the total length of the string */
- for (buffblock_T *bp = buffer->bh_first.b_next; bp != NULL; bp = bp->b_next)
+ // compute the total length of the string
+ for (const buffblock_T *bp = buffer->bh_first.b_next;
+ bp != NULL; bp = bp->b_next) {
count += STRLEN(bp->b_str);
+ }
if (count || dozero) {
p = xmalloc(count + 1);
p2 = p;
- for (buffblock_T *bp = buffer->bh_first.b_next; bp != NULL; bp = bp->b_next)
- for (str = bp->b_str; *str; )
+ for (const buffblock_T *bp = buffer->bh_first.b_next;
+ bp != NULL; bp = bp->b_next) {
+ for (const char_u *str = bp->b_str; *str;) {
*p2++ = *str++;
+ }
+ }
*p2 = NUL;
}
return p;
@@ -356,12 +361,12 @@ static int read_readbuffers(int advance)
static int read_readbuf(buffheader_T *buf, int advance)
{
char_u c;
- buffblock_T *curr;
- if (buf->bh_first.b_next == NULL) /* buffer is empty */
+ if (buf->bh_first.b_next == NULL) { // buffer is empty
return NUL;
+ }
- curr = buf->bh_first.b_next;
+ buffblock_T *const curr = buf->bh_first.b_next;
c = curr->b_str[buf->bh_index];
if (advance) {
@@ -668,12 +673,10 @@ static int read_redo(bool init, bool old_redo)
int i;
if (init) {
- if (old_redo)
- bp = old_redobuff.bh_first.b_next;
- else
- bp = redobuff.bh_first.b_next;
- if (bp == NULL)
+ bp = old_redo ? old_redobuff.bh_first.b_next : redobuff.bh_first.b_next;
+ if (bp == NULL) {
return FAIL;
+ }
p = bp->b_str;
return OK;
}
@@ -896,18 +899,19 @@ int ins_typebuf(char_u *str, int noremap, int offset, int nottyped, bool silent)
s2 = xmalloc((size_t)newlen);
typebuf.tb_buflen = newlen;
- /* copy the old chars, before the insertion point */
- memmove(s1 + newoff, typebuf.tb_buf + typebuf.tb_off,
- (size_t)offset);
- /* copy the new chars */
+ // copy the old chars, before the insertion point
+ memmove(s1 + newoff, typebuf.tb_buf + typebuf.tb_off, (size_t)offset);
+ // copy the new chars
memmove(s1 + newoff + offset, str, (size_t)addlen);
- /* copy the old chars, after the insertion point, including the NUL at
- * the end */
+ // copy the old chars, after the insertion point, including the NUL at
+ // the end
+ int bytes = typebuf.tb_len - offset + 1;
+ assert(bytes > 0);
memmove(s1 + newoff + offset + addlen,
- typebuf.tb_buf + typebuf.tb_off + offset,
- (size_t)(typebuf.tb_len - offset + 1));
- if (typebuf.tb_buf != typebuf_init)
+ typebuf.tb_buf + typebuf.tb_off + offset, (size_t)bytes);
+ if (typebuf.tb_buf != typebuf_init) {
xfree(typebuf.tb_buf);
+ }
typebuf.tb_buf = s1;
memmove(s2 + newoff, typebuf.tb_noremap + typebuf.tb_off,
@@ -1053,11 +1057,12 @@ void del_typebuf(int len, int offset)
typebuf.tb_noremap + typebuf.tb_off, (size_t)offset);
typebuf.tb_off = MAXMAPLEN;
}
- /* adjust typebuf.tb_buf (include the NUL at the end) */
+ // adjust typebuf.tb_buf (include the NUL at the end)
+ int bytes = typebuf.tb_len - offset + 1;
+ assert(bytes > 0);
memmove(typebuf.tb_buf + typebuf.tb_off + offset,
- typebuf.tb_buf + i + len,
- (size_t)(typebuf.tb_len - offset + 1));
- /* adjust typebuf.tb_noremap[] */
+ 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));
@@ -1244,9 +1249,17 @@ openscript (
EMSG(_(e_nesting));
return;
}
- if (ignore_script)
- /* Not reading from script, also don't open one. Warning message? */
+
+ // Disallow sourcing a file in the sandbox, the commands would be executed
+ // later, possibly outside of the sandbox.
+ if (check_secure()) {
+ return;
+ }
+
+ if (ignore_script) {
+ // Not reading from script, also don't open one. Warning message?
return;
+ }
if (scriptin[curscript] != NULL) /* already reading script */
++curscript;
@@ -1761,7 +1774,7 @@ static int vgetorpeek(int advance)
&& !(State == HITRETURN && (c1 == CAR || c1 == ' '))
&& State != ASKMORE
&& State != CONFIRM
- && !((ctrl_x_mode != 0 && vim_is_ctrl_x_key(c1))
+ && !((ctrl_x_mode_not_default() && vim_is_ctrl_x_key(c1))
|| ((compl_cont_status & CONT_LOCAL)
&& (c1 == Ctrl_N || c1 == Ctrl_P)))
) {
@@ -1908,7 +1921,7 @@ static int vgetorpeek(int advance)
set_option_value("paste", !p_paste, NULL, 0);
if (!(State & INSERT)) {
msg_col = 0;
- msg_row = (int)Rows - 1;
+ msg_row = Rows - 1;
msg_clr_eos(); // clear ruler
}
status_redraw_all();
@@ -1927,10 +1940,12 @@ static int vgetorpeek(int advance)
}
if ((mp == NULL || max_mlen >= mp_match_len)
- && keylen != KEYLEN_PART_MAP) {
+ && keylen != KEYLEN_PART_MAP
+ && !(keylen == KEYLEN_PART_KEY && c1 == ui_toggle[0])) {
// No matching mapping found or found a non-matching mapping that
// matches at least what the matching mapping matched
keylen = 0;
+ (void)keylen; // suppress clang/dead assignment
// If there was no mapping, use the character from the typeahead
// buffer right here. Otherwise, use the mapping (loop around).
if (mp == NULL) {
@@ -2252,14 +2267,13 @@ static int vgetorpeek(int advance)
curwin->w_wrow = old_wrow;
}
- /* this looks nice when typing a dead character map */
- if ((State & CMDLINE)
- && cmdline_star == 0
- && ptr2cells(typebuf.tb_buf + typebuf.tb_off
- + typebuf.tb_len - 1) == 1) {
- putcmdline(typebuf.tb_buf[typebuf.tb_off
- + typebuf.tb_len - 1], FALSE);
- c1 = 1;
+ // this looks nice when typing a dead character map
+ if ((State & CMDLINE) && cmdline_star == 0) {
+ char_u *p = typebuf.tb_buf + typebuf.tb_off + typebuf.tb_len - 1;
+ if (ptr2cells(p) == 1 && *p < 128) {
+ putcmdline((char)(*p), false);
+ c1 = 1;
+ }
}
}
@@ -2342,6 +2356,17 @@ static int vgetorpeek(int advance)
}
}
+ if (timedout && c == ESC) {
+ char_u nop_buf[3];
+
+ // When recording there will be no timeout. Add a <Nop> after the ESC
+ // to avoid that it forms a key code with following characters.
+ nop_buf[0] = K_SPECIAL;
+ nop_buf[1] = KS_EXTRA;
+ nop_buf[2] = KE_NOP;
+ gotchars(nop_buf, 3);
+ }
+
--vgetc_busy;
return c;
@@ -3264,29 +3289,36 @@ char *map_mode_to_chars(int mode)
ga_init(&mapmode, 1, 7);
- if ((mode & (INSERT + CMDLINE)) == INSERT + CMDLINE)
- ga_append(&mapmode, '!'); /* :map! */
- else if (mode & INSERT)
- ga_append(&mapmode, 'i'); /* :imap */
- else if (mode & LANGMAP)
- ga_append(&mapmode, 'l'); /* :lmap */
- else if (mode & CMDLINE)
- ga_append(&mapmode, 'c'); /* :cmap */
- else if ((mode & (NORMAL + VISUAL + SELECTMODE + OP_PENDING))
- == NORMAL + VISUAL + SELECTMODE + OP_PENDING)
- ga_append(&mapmode, ' '); /* :map */
- else {
- if (mode & NORMAL)
- ga_append(&mapmode, 'n'); /* :nmap */
- if (mode & OP_PENDING)
- ga_append(&mapmode, 'o'); /* :omap */
- if ((mode & (VISUAL + SELECTMODE)) == VISUAL + SELECTMODE)
- ga_append(&mapmode, 'v'); /* :vmap */
- else {
- if (mode & VISUAL)
- ga_append(&mapmode, 'x'); /* :xmap */
- if (mode & SELECTMODE)
- ga_append(&mapmode, 's'); /* :smap */
+ if ((mode & (INSERT + CMDLINE)) == INSERT + CMDLINE) {
+ ga_append(&mapmode, '!'); // :map!
+ } else if (mode & INSERT) {
+ ga_append(&mapmode, 'i'); // :imap
+ } else if (mode & LANGMAP) {
+ ga_append(&mapmode, 'l'); // :lmap
+ } else if (mode & CMDLINE) {
+ ga_append(&mapmode, 'c'); // :cmap
+ } else if ((mode & (NORMAL + VISUAL + SELECTMODE + OP_PENDING))
+ == NORMAL + VISUAL + SELECTMODE + OP_PENDING) {
+ ga_append(&mapmode, ' '); // :map
+ } else {
+ if (mode & NORMAL) {
+ ga_append(&mapmode, 'n'); // :nmap
+ }
+ if (mode & OP_PENDING) {
+ ga_append(&mapmode, 'o'); // :omap
+ }
+ if (mode & TERM_FOCUS) {
+ ga_append(&mapmode, 't'); // :tmap
+ }
+ if ((mode & (VISUAL + SELECTMODE)) == VISUAL + SELECTMODE) {
+ ga_append(&mapmode, 'v'); // :vmap
+ } else {
+ if (mode & VISUAL) {
+ ga_append(&mapmode, 'x'); // :xmap
+ }
+ if (mode & SELECTMODE) {
+ ga_append(&mapmode, 's'); // :smap
+ }
}
}
@@ -3417,7 +3449,7 @@ int map_to_exists_mode(const char *const rhs, const int mode, const bool abbr)
{
mapblock_T *mp;
int hash;
- bool expand_buffer = false;
+ bool exp_buffer = false;
validate_maphash();
@@ -3428,12 +3460,12 @@ int map_to_exists_mode(const char *const rhs, const int mode, const bool abbr)
if (hash > 0) { // There is only one abbr list.
break;
}
- if (expand_buffer) {
+ if (exp_buffer) {
mp = curbuf->b_first_abbr;
} else {
mp = first_abbr;
}
- } else if (expand_buffer) {
+ } else if (exp_buffer) {
mp = curbuf->b_maphash[hash];
} else {
mp = maphash[hash];
@@ -3445,10 +3477,10 @@ int map_to_exists_mode(const char *const rhs, const int mode, const bool abbr)
}
}
}
- if (expand_buffer) {
+ if (exp_buffer) {
break;
}
- expand_buffer = true;
+ exp_buffer = true;
}
return false;
@@ -3527,11 +3559,9 @@ set_context_in_map_cmd (
return NULL;
}
-/*
- * Find all mapping/abbreviation names that match regexp 'prog'.
- * For command line expansion of ":[un]map" and ":[un]abbrev" in all modes.
- * Return OK if matches found, FAIL otherwise.
- */
+// Find all mapping/abbreviation names that match regexp "regmatch".
+// For command line expansion of ":[un]map" and ":[un]abbrev" in all modes.
+// Return OK if matches found, FAIL otherwise.
int ExpandMappings(regmatch_T *regmatch, int *num_file, char_u ***file)
{
mapblock_T *mp;
@@ -3591,7 +3621,7 @@ int ExpandMappings(regmatch_T *regmatch, int *num_file, char_u ***file)
mp = maphash[hash];
for (; mp; mp = mp->m_next) {
if (mp->m_mode & expand_mapmodes) {
- p = translate_mapping(mp->m_keys, true, CPO_TO_CPO_FLAGS);
+ p = translate_mapping(mp->m_keys, CPO_TO_CPO_FLAGS);
if (p != NULL && vim_regexec(regmatch, p, (colnr_T)0)) {
if (round == 1)
++count;
@@ -3642,7 +3672,9 @@ int ExpandMappings(regmatch_T *regmatch, int *num_file, char_u ***file)
/*
* Check for an abbreviation.
- * Cursor is at ptr[col]. When inserting, mincol is where insert started.
+ * Cursor is at ptr[col].
+ * When inserting, mincol is where insert started.
+ * For the command line, mincol is what is to be skipped over.
* "c" is the character typed before check_abbr was called. It may have
* ABBR_OFF added to avoid prepending a CTRL-V to it.
*
@@ -3921,10 +3953,10 @@ void vim_unescape_csi(char_u *p)
* Write map commands for the current mappings to an .exrc file.
* Return FAIL on error, OK otherwise.
*/
-int
-makemap (
+int
+makemap(
FILE *fd,
- buf_T *buf /* buffer for local mappings or NULL */
+ buf_T *buf // buffer for local mappings or NULL
)
{
mapblock_T *mp;
@@ -3937,50 +3969,56 @@ makemap (
validate_maphash();
- /*
- * Do the loop twice: Once for mappings, once for abbreviations.
- * Then loop over all map hash lists.
- */
- for (abbr = 0; abbr < 2; ++abbr)
- for (hash = 0; hash < 256; ++hash) {
+ // Do the loop twice: Once for mappings, once for abbreviations.
+ // Then loop over all map hash lists.
+ for (abbr = 0; abbr < 2; abbr++) {
+ for (hash = 0; hash < 256; hash++) {
if (abbr) {
- if (hash > 0) /* there is only one abbr list */
+ if (hash > 0) { // there is only one abbr list
break;
- if (buf != NULL)
+ }
+ if (buf != NULL) {
mp = buf->b_first_abbr;
- else
+ } else {
mp = first_abbr;
+ }
} else {
- if (buf != NULL)
+ if (buf != NULL) {
mp = buf->b_maphash[hash];
- else
+ } else {
mp = maphash[hash];
+ }
}
for (; mp; mp = mp->m_next) {
- /* skip script-local mappings */
- if (mp->m_noremap == REMAP_SCRIPT)
+ // skip script-local mappings
+ if (mp->m_noremap == REMAP_SCRIPT) {
continue;
+ }
- /* skip mappings that contain a <SNR> (script-local thing),
- * they probably don't work when loaded again */
- for (p = mp->m_str; *p != NUL; ++p)
+ // skip mappings that contain a <SNR> (script-local thing),
+ // they probably don't work when loaded again
+ for (p = mp->m_str; *p != NUL; p++) {
if (p[0] == K_SPECIAL && p[1] == KS_EXTRA
- && p[2] == (int)KE_SNR)
+ && p[2] == (int)KE_SNR) {
break;
- if (*p != NUL)
+ }
+ }
+ if (*p != NUL) {
continue;
+ }
- /* It's possible to create a mapping and then ":unmap" certain
- * modes. We recreate this here by mapping the individual
- * modes, which requires up to three of them. */
+ // It's possible to create a mapping and then ":unmap" certain
+ // modes. We recreate this here by mapping the individual
+ // modes, which requires up to three of them.
c1 = NUL;
c2 = NUL;
c3 = NUL;
- if (abbr)
+ if (abbr) {
cmd = "abbr";
- else
+ } else {
cmd = "map";
+ }
switch (mp->m_mode) {
case NORMAL + VISUAL + SELECTMODE + OP_PENDING:
break;
@@ -4038,8 +4076,9 @@ makemap (
c2 = 'o';
break;
case CMDLINE + INSERT:
- if (!abbr)
+ if (!abbr) {
cmd = "map!";
+ }
break;
case CMDLINE:
c1 = 'c';
@@ -4057,9 +4096,10 @@ makemap (
IEMSG(_("E228: makemap: Illegal mode"));
return FAIL;
}
- do { /* do this twice if c2 is set, 3 times with c3 */
- /* When outputting <> form, need to make sure that 'cpo'
- * is set to the Vim default. */
+ do {
+ // do this twice if c2 is set, 3 times with c3 */
+ // When outputting <> form, need to make sure that 'cpo'
+ // is set to the Vim default.
if (!did_cpo) {
if (*mp->m_str == NUL) { // Will use <Nop>.
did_cpo = true;
@@ -4074,63 +4114,69 @@ makemap (
if (fprintf(fd, "let s:cpo_save=&cpo") < 0
|| put_eol(fd) < 0
|| fprintf(fd, "set cpo&vim") < 0
- || put_eol(fd) < 0)
+ || put_eol(fd) < 0) {
return FAIL;
+ }
}
}
- if (c1 && putc(c1, fd) < 0)
+ if (c1 && putc(c1, fd) < 0) {
return FAIL;
- if (mp->m_noremap != REMAP_YES && fprintf(fd, "nore") < 0)
- return FAIL;
- if (fputs(cmd, fd) < 0)
+ }
+ if (mp->m_noremap != REMAP_YES && fprintf(fd, "nore") < 0) {
return FAIL;
- if (buf != NULL && fputs(" <buffer>", fd) < 0)
+ }
+ if (fputs(cmd, fd) < 0) {
return FAIL;
- if (mp->m_nowait && fputs(" <nowait>", fd) < 0)
+ }
+ if (buf != NULL && fputs(" <buffer>", fd) < 0) {
return FAIL;
- if (mp->m_silent && fputs(" <silent>", fd) < 0)
+ }
+ if (mp->m_nowait && fputs(" <nowait>", fd) < 0) {
return FAIL;
- if (mp->m_noremap == REMAP_SCRIPT
- && fputs("<script>", fd) < 0)
+ }
+ if (mp->m_silent && fputs(" <silent>", fd) < 0) {
return FAIL;
- if (mp->m_expr && fputs(" <expr>", fd) < 0)
+ }
+ if (mp->m_expr && fputs(" <expr>", fd) < 0) {
return FAIL;
+ }
- if ( putc(' ', fd) < 0
- || put_escstr(fd, mp->m_keys, 0) == FAIL
- || putc(' ', fd) < 0
- || put_escstr(fd, mp->m_str, 1) == FAIL
- || put_eol(fd) < 0)
+ if (putc(' ', fd) < 0
+ || put_escstr(fd, mp->m_keys, 0) == FAIL
+ || putc(' ', fd) < 0
+ || put_escstr(fd, mp->m_str, 1) == FAIL
+ || put_eol(fd) < 0) {
return FAIL;
+ }
c1 = c2;
c2 = c3;
c3 = NUL;
} while (c1 != NUL);
}
}
-
- if (did_cpo)
+ }
+ if (did_cpo) {
if (fprintf(fd, "let &cpo=s:cpo_save") < 0
|| put_eol(fd) < 0
|| fprintf(fd, "unlet s:cpo_save") < 0
- || put_eol(fd) < 0)
+ || put_eol(fd) < 0) {
return FAIL;
+ }
+ }
return OK;
}
-/*
- * write escape string to file
- * "what": 0 for :map lhs, 1 for :map rhs, 2 for :set
- *
- * return FAIL for failure, OK otherwise
- */
+// write escape string to file
+// "what": 0 for :map lhs, 1 for :map rhs, 2 for :set
+//
+// return FAIL for failure, OK otherwise
int put_escstr(FILE *fd, char_u *strstart, int what)
{
char_u *str = strstart;
int c;
int modifiers;
- /* :map xx <Nop> */
+ // :map xx <Nop>
if (*str == NUL && what == 1) {
if (fprintf(fd, "<Nop>") < 0)
return FAIL;
@@ -4299,16 +4345,15 @@ void add_map(char_u *map, int mode)
// corresponding external one recognized by :map/:abbrev commands.
//
// This function is called when expanding mappings/abbreviations on the
-// command-line, and for building the "Ambiguous mapping..." error message.
+// 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.
+// 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 expmap, // True when expanding mappings on command-line
int cpo_flags // Value of various flags present in &cpo
)
{
@@ -4326,12 +4371,8 @@ static char_u * translate_mapping (
modifiers = *++str;
c = *++str;
}
-
+
if (c == K_SPECIAL && str[1] != NUL && str[2] != NUL) {
- if (expmap) {
- ga_clear(&ga);
- return NULL;
- }
c = TO_SPECIAL(str[1], str[2]);
if (c == K_ZERO) {
// display <Nul> as ^@
@@ -4340,10 +4381,6 @@ static char_u * translate_mapping (
str += 2;
}
if (IS_SPECIAL(c) || modifiers) { // special key
- if (expmap) {
- ga_clear(&ga);
- return NULL;
- }
ga_concat(&ga, get_special_key_name(c, modifiers));
continue; /* for (str) */
}
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 6d602d2712..3bdbff79b4 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -88,18 +88,15 @@ EXTERN struct nvim_stats_s {
#define NO_BUFFERS 1 // not all buffers loaded yet
// 0 not starting anymore
-/*
- * Number of Rows and Columns in the screen.
- * Must be long to be able to use them as options in option.c.
- * Note: Use default_grid.Rows and default_grid.Columns to access items in
- * default_grid.chars[]. They may have different values when the screen
- * wasn't (re)allocated yet after setting Rows or Columns (e.g., when starting
- * up).
- */
+// Number of Rows and Columns in the screen.
+// Note: Use default_grid.Rows and default_grid.Columns to access items in
+// default_grid.chars[]. They may have different values when the screen
+// wasn't (re)allocated yet after setting Rows or Columns (e.g., when starting
+// up).
#define DFLT_COLS 80 // default value for 'columns'
#define DFLT_ROWS 24 // default value for 'lines'
-EXTERN long Rows INIT(= DFLT_ROWS); // nr of rows in the screen
-EXTERN long Columns INIT(= DFLT_COLS); // nr of columns in the screen
+EXTERN int Rows INIT(= DFLT_ROWS); // nr of rows in the screen
+EXTERN int Columns INIT(= DFLT_COLS); // nr of columns in the screen
// We use 64-bit file functions here, if available. E.g. ftello() returns
// off_t instead of long, which helps if long is 32 bit and off_t is 64 bit.
@@ -435,10 +432,11 @@ EXTERN win_T *firstwin; /* first window */
EXTERN win_T *lastwin; /* last window */
EXTERN win_T *prevwin INIT(= NULL); /* previous window */
# define ONE_WINDOW (firstwin == lastwin)
-/*
- * When using this macro "break" only breaks out of the inner loop. Use "goto"
- * to break out of the tabpage loop.
- */
+# define FOR_ALL_FRAMES(frp, first_frame) \
+ for (frp = first_frame; frp != NULL; frp = frp->fr_next) // NOLINT
+
+// When using this macro "break" only breaks out of the inner loop. Use "goto"
+// to break out of the tabpage loop.
# define FOR_ALL_TAB_WINDOWS(tp, wp) \
FOR_ALL_TABS(tp) \
FOR_ALL_WINDOWS_IN_TAB(wp, tp)
@@ -510,7 +508,7 @@ EXTERN int sc_col; /* column for shown command */
// First NO_SCREEN, then NO_BUFFERS, then 0 when startup finished.
EXTERN int starting INIT(= NO_SCREEN);
// true when planning to exit. Might keep running if there is a changed buffer.
-EXTERN int exiting INIT(= false);
+EXTERN bool exiting INIT(= false);
// is stdin a terminal?
EXTERN int stdin_isatty INIT(= true);
// is stdout a terminal?
@@ -629,6 +627,8 @@ EXTERN pos_T Insstart_orig;
EXTERN int orig_line_count INIT(= 0); /* Line count when "gR" started */
EXTERN int vr_lines_changed INIT(= 0); /* #Lines changed by "gR" so far */
+// increase around internal delete/replace
+EXTERN int inhibit_delete_count INIT(= 0);
/*
* These flags are set based upon 'fileencoding'.
@@ -655,16 +655,6 @@ EXTERN int vr_lines_changed INIT(= 0); /* #Lines changed by "gR" so far */
/// Encoding used when 'fencs' is set to "default"
EXTERN char_u *fenc_default INIT(= NULL);
-# if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
-/* Pointers to functions and variables to be loaded at runtime */
-EXTERN size_t (*iconv)(iconv_t cd, const char **inbuf, size_t *inbytesleft,
- char **outbuf, size_t *outbytesleft);
-EXTERN iconv_t (*iconv_open)(const char *tocode, const char *fromcode);
-EXTERN int (*iconv_close)(iconv_t cd);
-EXTERN int (*iconvctl)(iconv_t cd, int request, void *argument);
-EXTERN int* (*iconv_errno)(void);
-# endif
-
/// "State" is the main state of Vim.
/// There are other variables that modify the state:
/// Visual_mode: When State is NORMAL or INSERT.
@@ -700,11 +690,10 @@ EXTERN int arrow_used; /* Normally FALSE, set to TRUE after
* to call u_sync() */
EXTERN int ins_at_eol INIT(= FALSE); /* put cursor after eol when
restarting edit after CTRL-O */
-EXTERN char_u *edit_submode INIT(= NULL); /* msg for CTRL-X submode */
-EXTERN char_u *edit_submode_pre INIT(= NULL); /* prepended to edit_submode */
-EXTERN char_u *edit_submode_extra INIT(= NULL); /* appended to edit_submode */
-EXTERN hlf_T edit_submode_highl; /* highl. method for extra info */
-EXTERN int ctrl_x_mode INIT(= 0); /* Which Ctrl-X mode are we in? */
+EXTERN char_u *edit_submode INIT(= NULL); // msg for CTRL-X submode
+EXTERN char_u *edit_submode_pre INIT(= NULL); // prepended to edit_submode
+EXTERN char_u *edit_submode_extra INIT(= NULL); // appended to edit_submode
+EXTERN hlf_T edit_submode_highl; // highl. method for extra info
EXTERN int no_abbr INIT(= TRUE); /* TRUE when no abbreviations loaded */
@@ -757,9 +746,11 @@ EXTERN bool KeyTyped; // true if user typed current char
EXTERN int KeyStuffed; // TRUE if current char from stuffbuf
EXTERN int maptick INIT(= 0); // tick for each non-mapped char
-EXTERN int must_redraw INIT(= 0); /* type of redraw necessary */
-EXTERN int skip_redraw INIT(= FALSE); /* skip redraw once */
-EXTERN int do_redraw INIT(= FALSE); /* extra redraw once */
+EXTERN int must_redraw INIT(= 0); // type of redraw necessary
+EXTERN bool skip_redraw INIT(= false); // skip redraw once
+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);
@@ -933,6 +924,9 @@ EXTERN char_u e_interr[] INIT(= N_("Interrupted"));
EXTERN char_u e_invaddr[] INIT(= N_("E14: Invalid address"));
EXTERN char_u e_invarg[] INIT(= N_("E474: Invalid argument"));
EXTERN char_u e_invarg2[] INIT(= N_("E475: Invalid argument: %s"));
+EXTERN char_u e_invargval[] INIT(= N_("E475: Invalid value for argument %s"));
+EXTERN char_u e_invargNval[] INIT(= N_(
+ "E475: Invalid value for argument %s: %s"));
EXTERN char_u e_duparg2[] INIT(= N_("E983: Duplicate argument: %s"));
EXTERN char_u e_invexpr2[] INIT(= N_("E15: Invalid expression: %s"));
EXTERN char_u e_invrange[] INIT(= N_("E16: Invalid range"));
@@ -980,9 +974,6 @@ EXTERN char_u e_notmp[] INIT(= N_("E483: Can't get temp file name"));
EXTERN char_u e_notopen[] INIT(= N_("E484: Can't open file %s"));
EXTERN char_u e_notopen_2[] INIT(= N_("E484: Can't open file %s: %s"));
EXTERN char_u e_notread[] INIT(= N_("E485: Can't read file %s"));
-EXTERN char_u e_nowrtmsg[] INIT(= N_(
- "E37: No write since last change (add ! to override)"));
-EXTERN char_u e_nowrtmsg_nobang[] INIT(= N_("E37: No write since last change"));
EXTERN char_u e_null[] INIT(= N_("E38: Null argument"));
EXTERN char_u e_number_exp[] INIT(= N_("E39: Number expected"));
EXTERN char_u e_openerrf[] INIT(= N_("E40: Can't open errorfile %s"));
@@ -1055,6 +1046,9 @@ EXTERN char_u e_cmdmap_key[] INIT(=N_(
EXTERN char_u e_api_error[] INIT(=N_(
"E5555: API call: %s"));
+EXTERN char e_luv_api_disabled[] INIT(=N_(
+ "E5560: %s must not be called in a lua loop callback"));
+
EXTERN char_u e_floatonly[] INIT(=N_(
"E5601: Cannot close window, only floating window would remain"));
EXTERN char_u e_floatexchange[] INIT(=N_(
diff --git a/src/nvim/grid_defs.h b/src/nvim/grid_defs.h
index 38fc513baa..e4021c033b 100644
--- a/src/nvim/grid_defs.h
+++ b/src/nvim/grid_defs.h
@@ -54,6 +54,9 @@ typedef struct {
int row_offset;
int col_offset;
+ // whether the compositor should blend the grid with the background grid
+ bool blending;
+
// state owned by the compositor.
int comp_row;
int comp_col;
@@ -61,7 +64,7 @@ typedef struct {
bool comp_disabled;
} ScreenGrid;
-#define SCREEN_GRID_INIT { 0, NULL, NULL, NULL, NULL, 0, 0, false, 0, 0, 0, \
- 0, 0, false }
+#define SCREEN_GRID_INIT { 0, NULL, NULL, NULL, NULL, 0, 0, false, 0, 0, \
+ false, 0, 0, 0, false }
#endif // NVIM_GRID_DEFS_H
diff --git a/src/nvim/hardcopy.c b/src/nvim/hardcopy.c
index bf2ac35554..3e0e438434 100644
--- a/src/nvim/hardcopy.c
+++ b/src/nvim/hardcopy.c
@@ -582,9 +582,9 @@ static void prt_header(prt_settings_T *const psettings, const int pagenum,
*/
static void prt_message(char_u *s)
{
- grid_fill(&default_grid, (int)Rows - 1, (int)Rows, 0, (int)Columns, ' ', ' ',
- 0);
- grid_puts(&default_grid, s, (int)Rows - 1, 0, HL_ATTR(HLF_R));
+ // TODO(bfredl): delete this
+ grid_fill(&default_grid, Rows - 1, Rows, 0, Columns, ' ', ' ', 0);
+ grid_puts(&default_grid, s, Rows - 1, 0, HL_ATTR(HLF_R));
ui_flush();
}
@@ -1670,7 +1670,7 @@ static int prt_open_resource(struct prt_ps_resource_S *resource)
FILE *fd_resource;
struct prt_dsc_line_S dsc_line;
- fd_resource = mch_fopen((char *)resource->filename, READBIN);
+ fd_resource = os_fopen((char *)resource->filename, READBIN);
if (fd_resource == NULL) {
EMSG2(_("E624: Can't open file \"%s\""), resource->filename);
return FALSE;
@@ -2343,11 +2343,11 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit)
EMSG(_(e_notmp));
return FAIL;
}
- prt_ps_fd = mch_fopen((char *)prt_ps_file_name, WRITEBIN);
+ prt_ps_fd = os_fopen((char *)prt_ps_file_name, WRITEBIN);
} else {
p = expand_env_save(psettings->outfile);
if (p != NULL) {
- prt_ps_fd = mch_fopen((char *)p, WRITEBIN);
+ prt_ps_fd = os_fopen((char *)p, WRITEBIN);
xfree(p);
}
}
@@ -2382,7 +2382,7 @@ static int prt_add_resource(struct prt_ps_resource_S *resource)
char_u resource_buffer[512];
size_t bytes_read;
- fd_resource = mch_fopen((char *)resource->filename, READBIN);
+ fd_resource = os_fopen((char *)resource->filename, READBIN);
if (fd_resource == NULL) {
EMSG2(_("E456: Can't open file \"%s\""), resource->filename);
return FALSE;
diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c
index 3ba02be32d..f11880cb2b 100644
--- a/src/nvim/highlight.c
+++ b/src/nvim/highlight.c
@@ -7,6 +7,7 @@
#include "nvim/highlight.h"
#include "nvim/highlight_defs.h"
#include "nvim/map.h"
+#include "nvim/popupmnu.h"
#include "nvim/screen.h"
#include "nvim/syntax.h"
#include "nvim/ui.h"
@@ -105,14 +106,19 @@ static int get_attr_entry(HlEntry entry)
/// When a UI connects, we need to send it the table of highlights used so far.
void ui_send_all_hls(UI *ui)
{
- if (!ui->hl_attr_define) {
- return;
+ if (ui->hl_attr_define) {
+ for (size_t i = 1; i < kv_size(attr_entries); i++) {
+ Array inspect = hl_inspect((int)i);
+ ui->hl_attr_define(ui, (Integer)i, kv_A(attr_entries, i).attr,
+ kv_A(attr_entries, i).attr, inspect);
+ api_free_array(inspect);
+ }
}
- for (size_t i = 1; i < kv_size(attr_entries); i++) {
- Array inspect = hl_inspect((int)i);
- ui->hl_attr_define(ui, (Integer)i, kv_A(attr_entries, i).attr,
- kv_A(attr_entries, i).attr, inspect);
- api_free_array(inspect);
+ if (ui->hl_group_set) {
+ for (size_t hlf = 0; hlf < HLF_COUNT; hlf++) {
+ ui->hl_group_set(ui, cstr_as_string((char *)hlf_names[hlf]),
+ highlight_attr[hlf]);
+ }
}
}
@@ -140,11 +146,23 @@ int hl_get_ui_attr(int idx, int final_id, bool optional)
HlAttrs attrs = HLATTRS_INIT;
bool available = false;
- int syn_attr = syn_id2attr(final_id);
- if (syn_attr != 0) {
- attrs = syn_attr2entry(syn_attr);
- available = true;
+ if (final_id > 0) {
+ int syn_attr = syn_id2attr(final_id);
+ if (syn_attr != 0) {
+ attrs = syn_attr2entry(syn_attr);
+ available = true;
+ }
+ }
+
+ if (HLF_PNI <= idx && idx <= HLF_PST) {
+ if (attrs.hl_blend == -1 && p_pb > 0) {
+ attrs.hl_blend = (int)p_pb;
+ }
+ if (pum_drawn()) {
+ must_redraw_pum = true;
+ }
}
+
if (optional && !available) {
return 0;
}
@@ -159,28 +177,42 @@ void update_window_hl(win_T *wp, bool invalid)
}
wp->w_hl_needs_update = false;
+ // If a floating window is blending it always have a named
+ // wp->w_hl_attr_normal group. HL_ATTR(HLF_NFLOAT) is always named.
+ bool has_blend = wp->w_floating && wp->w_p_winbl != 0;
+
// determine window specific background set in 'winhighlight'
bool float_win = wp->w_floating && !wp->w_float_config.external;
- if (wp != curwin && wp->w_hl_ids[HLF_INACTIVE] > 0) {
+ if (wp != curwin && wp->w_hl_ids[HLF_INACTIVE] != 0) {
wp->w_hl_attr_normal = hl_get_ui_attr(HLF_INACTIVE,
- wp->w_hl_ids[HLF_INACTIVE], true);
- } else if (float_win && wp->w_hl_ids[HLF_NFLOAT] > 0) {
+ wp->w_hl_ids[HLF_INACTIVE],
+ !has_blend);
+ } else if (float_win && wp->w_hl_ids[HLF_NFLOAT] != 0) {
wp->w_hl_attr_normal = hl_get_ui_attr(HLF_NFLOAT,
- wp->w_hl_ids[HLF_NFLOAT], true);
- } else if (wp->w_hl_id_normal > 0) {
- wp->w_hl_attr_normal = hl_get_ui_attr(-1, wp->w_hl_id_normal, true);
+ wp->w_hl_ids[HLF_NFLOAT], !has_blend);
+ } else if (wp->w_hl_id_normal != 0) {
+ wp->w_hl_attr_normal = hl_get_ui_attr(-1, wp->w_hl_id_normal, !has_blend);
} else {
wp->w_hl_attr_normal = float_win ? HL_ATTR(HLF_NFLOAT) : 0;
}
- if (wp != curwin) {
+ // if blend= attribute is not set, 'winblend' value overrides it.
+ if (wp->w_floating && wp->w_p_winbl > 0) {
+ HlEntry entry = kv_A(attr_entries, wp->w_hl_attr_normal);
+ if (entry.attr.hl_blend == -1) {
+ entry.attr.hl_blend = (int)wp->w_p_winbl;
+ wp->w_hl_attr_normal = get_attr_entry(entry);
+ }
+ }
+
+ if (wp != curwin && wp->w_hl_ids[HLF_INACTIVE] == 0) {
wp->w_hl_attr_normal = hl_combine_attr(HL_ATTR(HLF_INACTIVE),
wp->w_hl_attr_normal);
}
for (int hlf = 0; hlf < (int)HLF_COUNT; hlf++) {
int attr;
- if (wp->w_hl_ids[hlf] > 0) {
+ if (wp->w_hl_ids[hlf] != 0) {
attr = hl_get_ui_attr(hlf, wp->w_hl_ids[hlf], false);
} else {
attr = HL_ATTR(hlf);
@@ -224,6 +256,7 @@ void clear_hl_tables(bool reinit)
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();
@@ -240,6 +273,8 @@ void hl_invalidate_blends(void)
{
map_clear(int, int)(blend_attr_entries);
map_clear(int, int)(blendthrough_attr_entries);
+ highlight_changed();
+ update_window_hl(curwin, true);
}
// Combine special attributes (e.g., for spelling) with other attributes
@@ -292,6 +327,10 @@ int hl_combine_attr(int char_attr, int prim_attr)
new_en.rgb_sp_color = spell_aep.rgb_sp_color;
}
+ if (spell_aep.hl_blend >= 0) {
+ new_en.hl_blend = spell_aep.hl_blend;
+ }
+
id = get_attr_entry((HlEntry){ .attr = new_en, .kind = kHlCombine,
.id1 = char_attr, .id2 = prim_attr });
if (id > 0) {
@@ -336,50 +375,59 @@ static HlAttrs get_colors_force(int attr)
/// This is called per-cell, so cache the result.
///
/// @return the resulting attributes.
-int hl_blend_attrs(int back_attr, int front_attr, bool through)
+int hl_blend_attrs(int back_attr, int front_attr, bool *through)
{
+ HlAttrs fattrs = get_colors_force(front_attr);
+ int ratio = fattrs.hl_blend;
+ if (ratio <= 0) {
+ *through = false;
+ return front_attr;
+ }
+
int combine_tag = (back_attr << 16) + front_attr;
- Map(int, int) *map = through ? blendthrough_attr_entries : blend_attr_entries;
+ Map(int, int) *map = (*through
+ ? blendthrough_attr_entries
+ : blend_attr_entries);
int id = map_get(int, int)(map, combine_tag);
if (id > 0) {
return id;
}
HlAttrs battrs = get_colors_force(back_attr);
- HlAttrs fattrs = get_colors_force(front_attr);
HlAttrs cattrs;
- if (through) {
+
+ if (*through) {
cattrs = battrs;
- cattrs.rgb_fg_color = rgb_blend((int)p_pb, battrs.rgb_fg_color,
+ cattrs.rgb_fg_color = rgb_blend(ratio, battrs.rgb_fg_color,
fattrs.rgb_bg_color);
if (cattrs.rgb_ae_attr & (HL_UNDERLINE|HL_UNDERCURL)) {
- cattrs.rgb_sp_color = rgb_blend((int)p_pb, battrs.rgb_sp_color,
+ cattrs.rgb_sp_color = rgb_blend(ratio, battrs.rgb_sp_color,
fattrs.rgb_bg_color);
} else {
cattrs.rgb_sp_color = -1;
}
cattrs.cterm_bg_color = fattrs.cterm_bg_color;
- cattrs.cterm_fg_color = cterm_blend((int)p_pb, battrs.cterm_fg_color,
+ cattrs.cterm_fg_color = cterm_blend(ratio, battrs.cterm_fg_color,
fattrs.cterm_bg_color);
} else {
cattrs = fattrs;
- if (p_pb >= 50) {
+ if (ratio >= 50) {
cattrs.rgb_ae_attr |= battrs.rgb_ae_attr;
}
- cattrs.rgb_fg_color = rgb_blend((int)p_pb/2, battrs.rgb_fg_color,
+ cattrs.rgb_fg_color = rgb_blend(ratio/2, battrs.rgb_fg_color,
fattrs.rgb_fg_color);
if (cattrs.rgb_ae_attr & (HL_UNDERLINE|HL_UNDERCURL)) {
- cattrs.rgb_sp_color = rgb_blend((int)p_pb/2, battrs.rgb_bg_color,
+ cattrs.rgb_sp_color = rgb_blend(ratio/2, battrs.rgb_bg_color,
fattrs.rgb_sp_color);
} else {
cattrs.rgb_sp_color = -1;
}
}
- cattrs.rgb_bg_color = rgb_blend((int)p_pb, battrs.rgb_bg_color,
+ cattrs.rgb_bg_color = rgb_blend(ratio, battrs.rgb_bg_color,
fattrs.rgb_bg_color);
- HlKind kind = through ? kHlBlendThrough : kHlBlend;
+ HlKind kind = *through ? kHlBlendThrough : kHlBlend;
id = get_attr_entry((HlEntry){ .attr = cattrs, .kind = kind,
.id1 = back_attr, .id2 = front_attr });
if (id > 0) {
diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h
index 746d2c2dfc..afccf9e6f6 100644
--- a/src/nvim/highlight_defs.h
+++ b/src/nvim/highlight_defs.h
@@ -25,6 +25,7 @@ typedef struct attr_entry {
int16_t rgb_ae_attr, cterm_ae_attr; ///< HlAttrFlags
RgbValue rgb_fg_color, rgb_bg_color, rgb_sp_color;
int cterm_fg_color, cterm_bg_color;
+ int hl_blend;
} HlAttrs;
#define HLATTRS_INIT (HlAttrs) { \
@@ -35,6 +36,7 @@ typedef struct attr_entry {
.rgb_sp_color = -1, \
.cterm_fg_color = 0, \
.cterm_bg_color = 0, \
+ .hl_blend = -1, \
}
/// Values for index in highlight_attr[].
@@ -148,6 +150,7 @@ EXTERN const char *hlf_names[] INIT(= {
EXTERN int highlight_attr[HLF_COUNT]; // Highl. attr for each context.
+EXTERN int highlight_attr_last[HLF_COUNT]; // copy for detecting changed groups
EXTERN int highlight_user[9]; // User[1-9] attributes
EXTERN int highlight_stlnc[9]; // On top of user
EXTERN int cterm_normal_fg_color INIT(= 0);
diff --git a/src/nvim/iconv.h b/src/nvim/iconv.h
index d7234090c4..a7c9ad4040 100644
--- a/src/nvim/iconv.h
+++ b/src/nvim/iconv.h
@@ -1,52 +1,20 @@
#ifndef NVIM_ICONV_H
#define NVIM_ICONV_H
-// iconv can be linked at compile-time as well as loaded at runtime. In the
-// latter case, some function pointers need to be initialized after loading
-// the library (see `iconv_enabled()` in mbyte.c). These function pointers
-// are stored in globals.h. Since globals.h includes iconv.h to get the
-// definition of USE_ICONV, we can't include it from iconv.h. One way to
-// solve this conundrum would be perhaps to let cmake decide the value of
-// USE_ICONV, or to put the USE_ICONV definition in config.h.in directly. As
-// it stands, globals.h needs to be included alongside iconv.h.
-
#include "auto/config.h"
-// Use iconv() when it's available, either by linking to the library at
-// compile time or by loading it at runtime.
-#if (defined(HAVE_ICONV_H) && defined(HAVE_ICONV)) || defined(DYNAMIC_ICONV)
-# define USE_ICONV
-#endif
-
-// If we don't have the actual iconv header files present but USE_ICONV was
-// defined, we provide a type shim (pull in errno.h and define iconv_t).
-// This enables us to still load and use iconv dynamically at runtime.
-#ifdef USE_ICONV
+#ifdef HAVE_ICONV
# include <errno.h>
-# ifdef HAVE_ICONV_H
-# include <iconv.h>
-# else
-typedef void *iconv_t;
-# endif
-#endif
+# include <iconv.h>
// define some missing constants if necessary
-# ifdef USE_ICONV
# ifndef EILSEQ
# define EILSEQ 123
# endif
-# ifdef DYNAMIC_ICONV
-// on win32 iconv.dll is dynamically loaded
-# define ICONV_ERRNO (*iconv_errno())
-# define ICONV_E2BIG 7
-# define ICONV_EINVAL 22
-# define ICONV_EILSEQ 42
-# else
-# define ICONV_ERRNO errno
-# define ICONV_E2BIG E2BIG
-# define ICONV_EINVAL EINVAL
-# define ICONV_EILSEQ EILSEQ
-# endif
-# endif
+# define ICONV_ERRNO errno
+# define ICONV_E2BIG E2BIG
+# define ICONV_EINVAL EINVAL
+# define ICONV_EILSEQ EILSEQ
+#endif
#endif // NVIM_ICONV_H
diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c
index a3eabed8a0..0f9984ec38 100644
--- a/src/nvim/if_cscope.c
+++ b/src/nvim/if_cscope.c
@@ -1008,10 +1008,10 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose,
qf_info_T *qi = NULL;
win_T *wp = NULL;
- f = mch_fopen((char *)tmp, "w");
- if (f == NULL)
+ f = os_fopen((char *)tmp, "w");
+ if (f == NULL) {
EMSG2(_(e_notopen), tmp);
- else {
+ } else {
cs_file_results(f, nummatches);
fclose(f);
if (use_ll) /* Use location list */
@@ -1648,7 +1648,7 @@ static void cs_print_tags_priv(char **matches, char **cntxts,
assert(buf_len >= 0);
// Print the context only if it fits on the same line.
- if (msg_col + buf_len >= (int)Columns) {
+ if (msg_col + buf_len >= Columns) {
msg_putchar('\n');
}
msg_advance(12);
diff --git a/src/nvim/indent.c b/src/nvim/indent.c
index 8e20aa5be4..efbfea33aa 100644
--- a/src/nvim/indent.c
+++ b/src/nvim/indent.c
@@ -7,6 +7,7 @@
#include "nvim/ascii.h"
#include "nvim/assert.h"
+#include "nvim/change.h"
#include "nvim/indent.h"
#include "nvim/eval.h"
#include "nvim/charset.h"
@@ -316,109 +317,6 @@ int set_indent(int size, int flags)
}
-// Copy the indent from ptr to the current line (and fill to size).
-// Leaves the cursor on the first non-blank in the line.
-// @return true if the line was changed.
-int copy_indent(int size, char_u *src)
-{
- char_u *p = NULL;
- char_u *line = NULL;
- char_u *s;
- int todo;
- int ind_len;
- int line_len = 0;
- int tab_pad;
- int ind_done;
- int round;
-
- // Round 1: compute the number of characters needed for the indent
- // Round 2: copy the characters.
- for (round = 1; round <= 2; ++round) {
- todo = size;
- ind_len = 0;
- ind_done = 0;
- s = src;
-
- // Count/copy the usable portion of the source line.
- while (todo > 0 && ascii_iswhite(*s)) {
- if (*s == TAB) {
- tab_pad = (int)curbuf->b_p_ts
- - (ind_done % (int)curbuf->b_p_ts);
-
- // Stop if this tab will overshoot the target.
- if (todo < tab_pad) {
- break;
- }
- todo -= tab_pad;
- ind_done += tab_pad;
- } else {
- todo--;
- ind_done++;
- }
- ind_len++;
-
- if (p != NULL) {
- *p++ = *s;
- }
- s++;
- }
-
- // Fill to next tabstop with a tab, if possible.
- tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts);
-
- if ((todo >= tab_pad) && !curbuf->b_p_et) {
- todo -= tab_pad;
- ind_len++;
-
- if (p != NULL) {
- *p++ = TAB;
- }
- }
-
- // Add tabs required for indent.
- while (todo >= (int)curbuf->b_p_ts && !curbuf->b_p_et) {
- todo -= (int)curbuf->b_p_ts;
- ind_len++;
-
- if (p != NULL) {
- *p++ = TAB;
- }
- }
-
- // Count/add spaces required for indent.
- while (todo > 0) {
- todo--;
- ind_len++;
-
- if (p != NULL) {
- *p++ = ' ';
- }
- }
-
- if (p == NULL) {
- // Allocate memory for the result: the copied indent, new indent
- // and the rest of the line.
- line_len = (int)STRLEN(get_cursor_line_ptr()) + 1;
- assert(ind_len + line_len >= 0);
- size_t line_size;
- STRICT_ADD(ind_len, line_len, &line_size, size_t);
- line = xmalloc(line_size);
- p = line;
- }
- }
-
- // Append the original line
- memmove(p, get_cursor_line_ptr(), (size_t)line_len);
-
- // Replace the line
- ml_replace(curwin->w_cursor.lnum, line, false);
-
- // Put the cursor after the indent.
- curwin->w_cursor.col = ind_len;
- return true;
-}
-
-
// Return the indent of the current line after a number. Return -1 if no
// number was found. Used for 'n' in 'formatoptions': numbered list.
// Since a pattern is used it can actually handle more than numbers.
diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c
index 3729e42b99..9665655e74 100644
--- a/src/nvim/lua/converter.c
+++ b/src/nvim/lua/converter.c
@@ -615,7 +615,7 @@ static inline void nlua_create_typed_table(lua_State *lstate,
/// Convert given String to lua string
///
/// Leaves converted string on top of the stack.
-void nlua_push_String(lua_State *lstate, const String s)
+void nlua_push_String(lua_State *lstate, const String s, bool special)
FUNC_ATTR_NONNULL_ALL
{
lua_pushlstring(lstate, s.data, s.size);
@@ -624,7 +624,7 @@ void nlua_push_String(lua_State *lstate, const String s)
/// Convert given Integer to lua number
///
/// Leaves converted number on top of the stack.
-void nlua_push_Integer(lua_State *lstate, const Integer n)
+void nlua_push_Integer(lua_State *lstate, const Integer n, bool special)
FUNC_ATTR_NONNULL_ALL
{
lua_pushnumber(lstate, (lua_Number)n);
@@ -633,19 +633,23 @@ void nlua_push_Integer(lua_State *lstate, const Integer n)
/// Convert given Float to lua table
///
/// Leaves converted table on top of the stack.
-void nlua_push_Float(lua_State *lstate, const Float f)
+void nlua_push_Float(lua_State *lstate, const Float f, bool special)
FUNC_ATTR_NONNULL_ALL
{
- nlua_create_typed_table(lstate, 0, 1, kObjectTypeFloat);
- nlua_push_val_idx(lstate);
- lua_pushnumber(lstate, (lua_Number)f);
- lua_rawset(lstate, -3);
+ if (special) {
+ nlua_create_typed_table(lstate, 0, 1, kObjectTypeFloat);
+ nlua_push_val_idx(lstate);
+ lua_pushnumber(lstate, (lua_Number)f);
+ lua_rawset(lstate, -3);
+ } else {
+ lua_pushnumber(lstate, (lua_Number)f);
+ }
}
/// Convert given Float to lua boolean
///
/// Leaves converted value on top of the stack.
-void nlua_push_Boolean(lua_State *lstate, const Boolean b)
+void nlua_push_Boolean(lua_State *lstate, const Boolean b, bool special)
FUNC_ATTR_NONNULL_ALL
{
lua_pushboolean(lstate, b);
@@ -654,17 +658,18 @@ void nlua_push_Boolean(lua_State *lstate, const Boolean b)
/// Convert given Dictionary to lua table
///
/// Leaves converted table on top of the stack.
-void nlua_push_Dictionary(lua_State *lstate, const Dictionary dict)
+void nlua_push_Dictionary(lua_State *lstate, const Dictionary dict,
+ bool special)
FUNC_ATTR_NONNULL_ALL
{
- if (dict.size == 0) {
+ if (dict.size == 0 && special) {
nlua_create_typed_table(lstate, 0, 0, kObjectTypeDictionary);
} else {
lua_createtable(lstate, 0, (int)dict.size);
}
for (size_t i = 0; i < dict.size; i++) {
- nlua_push_String(lstate, dict.items[i].key);
- nlua_push_Object(lstate, dict.items[i].value);
+ nlua_push_String(lstate, dict.items[i].key, special);
+ nlua_push_Object(lstate, dict.items[i].value, special);
lua_rawset(lstate, -3);
}
}
@@ -672,18 +677,18 @@ void nlua_push_Dictionary(lua_State *lstate, const Dictionary dict)
/// Convert given Array to lua table
///
/// Leaves converted table on top of the stack.
-void nlua_push_Array(lua_State *lstate, const Array array)
+void nlua_push_Array(lua_State *lstate, const Array array, bool special)
FUNC_ATTR_NONNULL_ALL
{
lua_createtable(lstate, (int)array.size, 0);
for (size_t i = 0; i < array.size; i++) {
- nlua_push_Object(lstate, array.items[i]);
+ nlua_push_Object(lstate, array.items[i], special);
lua_rawseti(lstate, -2, (int)i + 1);
}
}
#define GENERATE_INDEX_FUNCTION(type) \
-void nlua_push_##type(lua_State *lstate, const type item) \
+void nlua_push_##type(lua_State *lstate, const type item, bool special) \
FUNC_ATTR_NONNULL_ALL \
{ \
lua_pushnumber(lstate, (lua_Number)(item)); \
@@ -698,7 +703,7 @@ GENERATE_INDEX_FUNCTION(Tabpage)
/// Convert given Object to lua value
///
/// Leaves converted value on top of the stack.
-void nlua_push_Object(lua_State *lstate, const Object obj)
+void nlua_push_Object(lua_State *lstate, const Object obj, bool special)
FUNC_ATTR_NONNULL_ALL
{
switch (obj.type) {
@@ -712,7 +717,7 @@ void nlua_push_Object(lua_State *lstate, const Object obj)
}
#define ADD_TYPE(type, data_key) \
case kObjectType##type: { \
- nlua_push_##type(lstate, obj.data.data_key); \
+ nlua_push_##type(lstate, obj.data.data_key, special); \
break; \
}
ADD_TYPE(Boolean, boolean)
@@ -724,7 +729,7 @@ void nlua_push_Object(lua_State *lstate, const Object obj)
#undef ADD_TYPE
#define ADD_REMOTE_TYPE(type) \
case kObjectType##type: { \
- nlua_push_##type(lstate, (type)obj.data.integer); \
+ nlua_push_##type(lstate, (type)obj.data.integer, special); \
break; \
}
ADD_REMOTE_TYPE(Buffer)
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index df08a9dd87..3de1b531e6 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -23,6 +23,7 @@
#include "nvim/cursor.h"
#include "nvim/undo.h"
#include "nvim/ascii.h"
+#include "nvim/change.h"
#ifdef WIN32
#include "nvim/os/os.h"
@@ -31,6 +32,10 @@
#include "nvim/lua/executor.h"
#include "nvim/lua/converter.h"
+#include "luv/luv.h"
+
+static int in_fast_callback = 0;
+
typedef struct {
Error err;
String lua_err_str;
@@ -108,6 +113,109 @@ static int nlua_stricmp(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
return 1;
}
+/// convert byte index to UTF-32 and UTF-16 indicies
+///
+/// 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.
+static int nlua_str_utfindex(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
+{
+ size_t s1_len;
+ const char *s1 = luaL_checklstring(lstate, 1, &s1_len);
+ intptr_t idx;
+ if (lua_gettop(lstate) >= 2) {
+ idx = luaL_checkinteger(lstate, 2);
+ if (idx < 0 || idx > (intptr_t)s1_len) {
+ return luaL_error(lstate, "index out of range");
+ }
+ } else {
+ idx = (intptr_t)s1_len;
+ }
+
+ size_t codepoints = 0, codeunits = 0;
+ mb_utflen((const char_u *)s1, (size_t)idx, &codepoints, &codeunits);
+
+ lua_pushinteger(lstate, (long)codepoints);
+ lua_pushinteger(lstate, (long)codeunits);
+
+ return 2;
+}
+
+/// convert UTF-32 or UTF-16 indicies 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)
+///
+/// Returns the byte index.
+static int nlua_str_byteindex(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
+{
+ size_t s1_len;
+ const char *s1 = luaL_checklstring(lstate, 1, &s1_len);
+ intptr_t idx = luaL_checkinteger(lstate, 2);
+ if (idx < 0) {
+ return luaL_error(lstate, "index out of range");
+ }
+ bool use_utf16 = false;
+ if (lua_gettop(lstate) >= 3) {
+ use_utf16 = lua_toboolean(lstate, 3);
+ }
+
+ ssize_t byteidx = mb_utf_index_to_bytes((const char_u *)s1, s1_len,
+ (size_t)idx, use_utf16);
+ if (byteidx == -1) {
+ return luaL_error(lstate, "index out of range");
+ }
+
+ lua_pushinteger(lstate, (long)byteidx);
+
+ return 1;
+}
+
+static void nlua_luv_error_event(void **argv)
+{
+ char *error = (char *)argv[0];
+ msg_ext_set_kind("lua_error");
+ emsgf_multiline("Error executing luv callback:\n%s", error);
+ xfree(error);
+}
+
+static int nlua_luv_cfpcall(lua_State *lstate, int nargs, int nresult,
+ int flags)
+ FUNC_ATTR_NONNULL_ALL
+{
+ int retval;
+
+ // luv callbacks might be executed at any os_breakcheck/line_breakcheck
+ // call, so using the API directly here is not safe.
+ in_fast_callback++;
+
+ int top = lua_gettop(lstate);
+ int status = lua_pcall(lstate, nargs, nresult, 0);
+ if (status) {
+ if (status == LUA_ERRMEM && !(flags & LUVF_CALLBACK_NOEXIT)) {
+ // consider out of memory errors unrecoverable, just like xmalloc()
+ mch_errmsg(e_outofmem);
+ mch_errmsg("\n");
+ preserve_exit();
+ }
+ const char *error = lua_tostring(lstate, -1);
+
+ multiqueue_put(main_loop.events, nlua_luv_error_event,
+ 1, xstrdup(error));
+ lua_pop(lstate, 1); // error mesage
+ retval = -status;
+ } else { // LUA_OK
+ if (nresult == LUA_MULTRET) {
+ nresult = lua_gettop(lstate) - top + nargs + 1;
+ }
+ retval = nresult;
+ }
+
+ in_fast_callback--;
+ return retval;
+}
+
static void nlua_schedule_event(void **argv)
{
LuaRef cb = (LuaRef)(ptrdiff_t)argv[0];
@@ -172,9 +280,33 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
// stricmp
lua_pushcfunction(lstate, &nlua_stricmp);
lua_setfield(lstate, -2, "stricmp");
+ // str_utfindex
+ lua_pushcfunction(lstate, &nlua_str_utfindex);
+ lua_setfield(lstate, -2, "str_utfindex");
+ // str_byteindex
+ lua_pushcfunction(lstate, &nlua_str_byteindex);
+ lua_setfield(lstate, -2, "str_byteindex");
// schedule
lua_pushcfunction(lstate, &nlua_schedule);
lua_setfield(lstate, -2, "schedule");
+ // in_fast_event
+ lua_pushcfunction(lstate, &nlua_in_fast_event);
+ lua_setfield(lstate, -2, "in_fast_event");
+
+ // vim.loop
+ luv_set_loop(lstate, &main_loop.uv);
+ luv_set_callback(lstate, nlua_luv_cfpcall);
+ luaopen_luv(lstate);
+ lua_pushvalue(lstate, -1);
+ lua_setfield(lstate, -3, "loop");
+
+ // package.loaded.luv = vim.loop
+ // otherwise luv will be reinitialized when require'luv'
+ lua_getglobal(lstate, "package");
+ lua_getfield(lstate, -1, "loaded");
+ lua_pushvalue(lstate, -3);
+ lua_setfield(lstate, -2, "luv");
+ lua_pop(lstate, 3);
lua_setglobal(lstate, "vim");
return 0;
@@ -260,6 +392,42 @@ void executor_exec_lua(const String str, typval_T *const ret_tv)
nlua_pop_typval(lstate, ret_tv);
}
+static void nlua_print_event(void **argv)
+{
+ char *str = argv[0];
+ const size_t len = (size_t)(intptr_t)argv[1]-1; // exclude final NUL
+
+ for (size_t i = 0; i < len;) {
+ 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;
+ }
+ }
+ break;
+ }
+ msg((char_u *)str + start);
+ }
+ if (len && str[len - 1] == NUL) { // Last was newline
+ msg((char_u *)"");
+ }
+ xfree(str);
+}
+
/// Print as a Vim message
///
/// @param lstate Lua interpreter state.
@@ -299,47 +467,24 @@ static int nlua_print(lua_State *const lstate)
lua_pop(lstate, 1);
}
#undef PRINT_ERROR
- lua_pop(lstate, nargs + 1);
ga_append(&msg_ga, NUL);
- {
- const size_t len = (size_t)msg_ga.ga_len - 1;
- char *const str = (char *)msg_ga.ga_data;
-
- for (size_t i = 0; i < len;) {
- const size_t start = i;
- while (i < len) {
- switch (str[i]) {
- case NUL: {
- str[i] = NL;
- i++;
- continue;
- }
- case NL: {
- str[i] = NUL;
- i++;
- break;
- }
- default: {
- i++;
- continue;
- }
- }
- break;
- }
- msg((char_u *)str + start);
- }
- if (len && str[len - 1] == NUL) { // Last was newline
- msg((char_u *)"");
- }
+
+ if (in_fast_callback) {
+ multiqueue_put(main_loop.events, nlua_print_event,
+ 2, msg_ga.ga_data, msg_ga.ga_len);
+ } else {
+ nlua_print_event((void *[]){ msg_ga.ga_data,
+ (void *)(intptr_t)msg_ga.ga_len });
}
- ga_clear(&msg_ga);
return 0;
+
nlua_print_error:
- emsgf(_("E5114: Error while converting print argument #%i: %.*s"),
- curargidx, (int)errmsg_len, errmsg);
ga_clear(&msg_ga);
- lua_pop(lstate, lua_gettop(lstate));
- return 0;
+ const char *fmt = _("E5114: Error while converting print argument #%i: %.*s");
+ size_t len = (size_t)vim_snprintf((char *)IObuff, IOSIZE, fmt, curargidx,
+ (int)errmsg_len, errmsg);
+ lua_pushlstring(lstate, (char *)IObuff, len);
+ return lua_error(lstate);
}
/// debug.debug: interaction with user while debugging.
@@ -373,15 +518,20 @@ int nlua_debug(lua_State *lstate)
if (luaL_loadbuffer(lstate, (const char *)input.vval.v_string,
STRLEN(input.vval.v_string), "=(debug command)")) {
nlua_error(lstate, _("E5115: Error while loading debug string: %.*s"));
- }
- tv_clear(&input);
- if (lua_pcall(lstate, 0, 0, 0)) {
+ } else if (lua_pcall(lstate, 0, 0, 0)) {
nlua_error(lstate, _("E5116: Error while calling debug string: %.*s"));
}
+ tv_clear(&input);
}
return 0;
}
+int nlua_in_fast_event(lua_State *lstate)
+{
+ lua_pushboolean(lstate, in_fast_callback > 0);
+ return 1;
+}
+
#ifdef WIN32
/// os.getenv: override os.getenv to maintain coherency. #9681
///
@@ -499,7 +649,7 @@ Object executor_exec_lua_api(const String str, const Array args, Error *err)
}
for (size_t i = 0; i < args.size; i++) {
- nlua_push_Object(lstate, args.items[i]);
+ nlua_push_Object(lstate, args.items[i], false);
}
if (lua_pcall(lstate, (int)args.size, 1, 0)) {
@@ -513,16 +663,17 @@ Object executor_exec_lua_api(const String str, const Array args, Error *err)
return nlua_pop_Object(lstate, false, err);
}
-Object executor_exec_lua_cb(LuaRef ref, const char *name, Array args)
+Object executor_exec_lua_cb(LuaRef ref, const char *name, Array args,
+ bool retval)
{
lua_State *const lstate = nlua_enter();
nlua_pushref(lstate, ref);
lua_pushstring(lstate, name);
for (size_t i = 0; i < args.size; i++) {
- nlua_push_Object(lstate, args.items[i]);
+ nlua_push_Object(lstate, args.items[i], false);
}
- if (lua_pcall(lstate, (int)args.size+1, 1, 0)) {
+ if (lua_pcall(lstate, (int)args.size+1, retval ? 1 : 0, 0)) {
// TODO(bfredl): callbacks:s might not always be msg-safe, for instance
// lua callbacks for redraw events. Later on let the caller deal with the
// error instead.
@@ -531,7 +682,18 @@ Object executor_exec_lua_cb(LuaRef ref, const char *name, Array args)
}
Error err = ERROR_INIT;
- return nlua_pop_Object(lstate, false, &err);
+ if (retval) {
+ return nlua_pop_Object(lstate, false, &err);
+ } else {
+ return NIL;
+ }
+}
+
+/// check if the current execution context is safe for calling deferred API
+/// methods. Luv callbacks are unsafe as they are called inside the uv loop.
+bool nlua_is_deferred_safe(lua_State *lstate)
+{
+ return in_fast_callback == 0;
}
/// Run lua string
diff --git a/src/nvim/lua/vim.lua b/src/nvim/lua/vim.lua
index 848bccaae6..46c96b455f 100644
--- a/src/nvim/lua/vim.lua
+++ b/src/nvim/lua/vim.lua
@@ -172,11 +172,22 @@ local function __index(t, key)
end
end
+--- Defers the wrapped callback until when the nvim API is safe to call.
+---
+--- See |vim-loop-callbacks|
+local function schedule_wrap(cb)
+ return (function (...)
+ local args = {...}
+ vim.schedule(function() cb(unpack(args)) end)
+ end)
+end
+
local module = {
_update_package_paths = _update_package_paths,
_os_proc_children = _os_proc_children,
_os_proc_info = _os_proc_info,
_system = _system,
+ schedule_wrap = schedule_wrap,
}
setmetatable(module, {
diff --git a/src/nvim/macros.h b/src/nvim/macros.h
index 61009528a8..018985fad2 100644
--- a/src/nvim/macros.h
+++ b/src/nvim/macros.h
@@ -86,8 +86,6 @@
#define READBIN "rb"
#define APPENDBIN "ab"
-# define mch_fopen(n, p) fopen((n), (p))
-
/* mch_open_rw(): invoke os_open() with third argument for user R/W. */
#if defined(UNIX) /* open in rw------- mode */
# define mch_open_rw(n, f) os_open((n), (f), (mode_t)0600)
@@ -129,7 +127,11 @@
# define MB_CHAR2LEN(c) mb_char2len(c)
# define PTR2CHAR(p) utf_ptr2char(p)
-# define RESET_BINDING(wp) (wp)->w_p_scb = FALSE; (wp)->w_p_crb = FALSE
+# define RESET_BINDING(wp) \
+ do { \
+ (wp)->w_p_scb = false; \
+ (wp)->w_p_crb = false; \
+ } while (0)
/// Calculate the length of a C array
///
@@ -165,7 +167,8 @@
# define NVIM_HAS_ATTRIBUTE __has_attribute
#endif
-#if NVIM_HAS_ATTRIBUTE(fallthrough)
+#if NVIM_HAS_ATTRIBUTE(fallthrough) \
+ && (!defined(__apple_build_version__) || __apple_build_version__ >= 7000000)
# define FALLTHROUGH __attribute__((fallthrough))
#else
# define FALLTHROUGH
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 28ef8e04ea..5aa7ed42d3 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -54,6 +54,7 @@
#include "nvim/strings.h"
#include "nvim/syntax.h"
#include "nvim/ui.h"
+#include "nvim/ui_compositor.h"
#include "nvim/version.h"
#include "nvim/window.h"
#include "nvim/shada.h"
@@ -141,15 +142,12 @@ static const char *err_extra_cmd =
void event_init(void)
{
+ log_init();
loop_init(&main_loop, NULL);
// early msgpack-rpc initialization
msgpack_rpc_init_method_table();
msgpack_rpc_helpers_init();
- // Initialize input events
input_init();
- // Timer to wake the event loop if a timeout argument is passed to
- // `event_poll`
- // Signals
signal_init();
// finish mspgack-rpc initialization
channel_init();
@@ -185,7 +183,6 @@ bool event_teardown(void)
/// Needed for unit tests. Must be called after `time_init()`.
void early_init(void)
{
- log_init();
env_init();
fs_init();
handle_init();
@@ -222,6 +219,9 @@ void early_init(void)
TIME_MSG("inits 1");
set_lang_var(); // set v:lang and v:ctype
+
+ init_signs();
+ ui_comp_syn_init();
}
#ifdef MAKE_LIB
@@ -257,12 +257,13 @@ int main(int argc, char **argv)
init_startuptime(&params);
+ event_init();
+
early_init();
// Check if we have an interactive window.
check_and_set_isatty(&params);
- event_init();
// Process the command line arguments. File names are put in the global
// argument list "global_alist".
command_line_scan(&params);
@@ -343,10 +344,8 @@ int main(int argc, char **argv)
p_lpl = false;
}
- // give embedders a chance to set up nvim, by processing a request before
- // startup. This allows an external UI to show messages and prompts from
- // --cmd and buffer loading (e.g. swap files)
- bool early_ui = false;
+ // Wait for UIs to set up Nvim or show early messages
+ // and prompts (--cmd, swapfile dialog, …).
bool use_remote_ui = (embedded_mode && !headless_mode);
bool use_builtin_ui = (!headless_mode && !embedded_mode && !silent_mode);
if (use_remote_ui || use_builtin_ui) {
@@ -361,7 +360,6 @@ int main(int argc, char **argv)
// prepare screen now, so external UIs can display messages
starting = NO_BUFFERS;
screenclear();
- early_ui = true;
TIME_MSG("initialized screen early for UI");
}
@@ -458,7 +456,7 @@ int main(int argc, char **argv)
setmouse(); // may start using the mouse
- if (exmode_active || early_ui) {
+ if (exmode_active || use_remote_ui || use_builtin_ui) {
// Don't clear the screen when starting in Ex mode, or when a UI might have
// displayed messages.
redraw_later(VALID);
@@ -581,9 +579,7 @@ int main(int argc, char **argv)
void getout(int exitval)
FUNC_ATTR_NORETURN
{
- tabpage_T *tp, *next_tp;
-
- exiting = TRUE;
+ exiting = true;
/* 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
@@ -593,15 +589,17 @@ void getout(int exitval)
set_vim_var_nr(VV_EXITING, exitval);
- /* Position the cursor on the last screen line, below all the text */
- ui_cursor_goto((int)Rows - 1, 0);
+ // Position the cursor on the last screen line, below all the text
+ ui_cursor_goto(Rows - 1, 0);
/* Optionally print hashtable efficiency. */
hash_debug_results();
if (get_vim_var_nr(VV_DYING) <= 1) {
- /* Trigger BufWinLeave for all windows, but only once per buffer. */
- for (tp = first_tabpage; tp != NULL; tp = next_tp) {
+ const tabpage_T *next_tp;
+
+ // Trigger BufWinLeave for all windows, but only once per buffer.
+ for (const tabpage_T *tp = first_tabpage; tp != NULL; tp = next_tp) {
next_tp = tp->tp_next;
FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
if (wp->w_buffer == NULL) {
@@ -658,17 +656,14 @@ void getout(int exitval)
wait_return(FALSE);
}
- /* Position the cursor again, the autocommands may have moved it */
- ui_cursor_goto((int)Rows - 1, 0);
+ // Position the cursor again, the autocommands may have moved it
+ ui_cursor_goto(Rows - 1, 0);
// Apply 'titleold'.
if (p_title && *p_titleold != NUL) {
ui_call_set_title(cstr_as_string((char *)p_titleold));
}
-#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
- iconv_end();
-#endif
cs_end();
if (garbage_collect_at_exit) {
garbage_collect(false);
@@ -1168,8 +1163,8 @@ scripterror:
if (scriptout != NULL) {
goto scripterror;
}
- if ((scriptout = mch_fopen(argv[0],
- c == 'w' ? APPENDBIN : WRITEBIN)) == NULL) {
+ 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");
@@ -1257,8 +1252,9 @@ static void init_params(mparm_T *paramp, int argc, char **argv)
static void init_startuptime(mparm_T *paramp)
{
for (int i = 1; i < paramp->argc; i++) {
- if (STRICMP(paramp->argv[i], "--startuptime") == 0 && i + 1 < paramp->argc) {
- time_fd = mch_fopen(paramp->argv[i + 1], "a");
+ if (STRICMP(paramp->argv[i], "--startuptime") == 0
+ && i + 1 < paramp->argc) {
+ time_fd = os_fopen(paramp->argv[i + 1], "a");
time_start("--- NVIM STARTING ---");
break;
}
@@ -1304,8 +1300,6 @@ static void init_path(const char *exename)
// shipped with Windows package. This also mimics SearchPath().
os_setenv_append_path(exepath);
#endif
-
- init_signs();
}
/// Get filename from command line, if any.
diff --git a/src/nvim/map.c b/src/nvim/map.c
index 90da27cf9f..cdade5ee71 100644
--- a/src/nvim/map.c
+++ b/src/nvim/map.c
@@ -179,7 +179,7 @@ MAP_IMPL(cstr_t, ptr_t, DEFAULT_INITIALIZER)
MAP_IMPL(ptr_t, ptr_t, DEFAULT_INITIALIZER)
MAP_IMPL(uint64_t, ptr_t, DEFAULT_INITIALIZER)
MAP_IMPL(handle_T, ptr_t, DEFAULT_INITIALIZER)
-#define MSGPACK_HANDLER_INITIALIZER { .fn = NULL, .async = false }
+#define MSGPACK_HANDLER_INITIALIZER { .fn = NULL, .fast = false }
MAP_IMPL(String, MsgpackRpcRequestHandler, MSGPACK_HANDLER_INITIALIZER)
#define KVEC_INITIALIZER { .size = 0, .capacity = 0, .items = NULL }
MAP_IMPL(HlEntry, int, DEFAULT_INITIALIZER)
diff --git a/src/nvim/mark.c b/src/nvim/mark.c
index 2f2f2a7d74..9f357575d0 100644
--- a/src/nvim/mark.c
+++ b/src/nvim/mark.c
@@ -656,48 +656,51 @@ show_one_mark(
int c,
char_u *arg,
pos_T *p,
- char_u *name,
- int current /* in current file */
+ char_u *name_arg,
+ int current // in current file
)
{
- static int did_title = FALSE;
- int mustfree = FALSE;
-
- if (c == -1) { /* finish up */
- if (did_title)
- did_title = FALSE;
- else {
- if (arg == NULL)
+ static bool did_title = false;
+ bool mustfree = false;
+ char_u *name = name_arg;
+
+ if (c == -1) { // finish up
+ if (did_title) {
+ did_title = false;
+ } else {
+ if (arg == NULL) {
MSG(_("No marks set"));
- else
+ } else {
EMSG2(_("E283: No marks matching \"%s\""), arg);
+ }
}
- }
- /* don't output anything if 'q' typed at --more-- prompt */
- else if (!got_int
- && (arg == NULL || vim_strchr(arg, c) != NULL)
- && p->lnum != 0) {
- if (!did_title) {
- /* Highlight title */
- MSG_PUTS_TITLE(_("\nmark line col file/text"));
- did_title = TRUE;
+ } else if (!got_int
+ && (arg == NULL || vim_strchr(arg, c) != NULL)
+ && p->lnum != 0) {
+ // don't output anything if 'q' typed at --more-- prompt
+ if (name == NULL && current) {
+ name = mark_line(p, 15);
+ mustfree = true;
}
- msg_putchar('\n');
- if (!got_int) {
- sprintf((char *)IObuff, " %c %6ld %4d ", c, p->lnum, p->col);
- msg_outtrans(IObuff);
- if (name == NULL && current) {
- name = mark_line(p, 15);
- mustfree = TRUE;
+ if (!message_filtered(name)) {
+ if (!did_title) {
+ // Highlight title
+ msg_puts_title(_("\nmark line col file/text"));
+ did_title = true;
}
- if (name != NULL) {
- msg_outtrans_attr(name, current ? HL_ATTR(HLF_D) : 0);
- if (mustfree) {
- xfree(name);
+ msg_putchar('\n');
+ if (!got_int) {
+ snprintf((char *)IObuff, IOSIZE, " %c %6ld %4d ", c, p->lnum, p->col);
+ msg_outtrans(IObuff);
+ if (name != NULL) {
+ msg_outtrans_attr(name, current ? HL_ATTR(HLF_D) : 0);
}
}
+ ui_flush(); // show one line at a time
+ }
+ if (mustfree) {
+ xfree(name);
}
- ui_flush(); /* show one line at a time */
}
}
@@ -786,8 +789,12 @@ void ex_jumps(exarg_T *eap)
for (i = 0; i < curwin->w_jumplistlen && !got_int; ++i) {
if (curwin->w_jumplist[i].fmark.mark.lnum != 0) {
name = fm_getname(&curwin->w_jumplist[i].fmark, 16);
- if (name == NULL) /* file name not available */
+
+ // apply :filter /pat/ or file name not available
+ if (name == NULL || message_filtered(name)) {
+ xfree(name);
continue;
+ }
msg_putchar('\n');
if (got_int) {
@@ -1206,8 +1213,8 @@ void cleanup_jumplist(win_T *wp, bool loadfiles)
// When pointer is below last jump, remove the jump if it matches the current
// line. This avoids useless/phantom jumps. #9805
- if (wp->w_jumplistlen
- && wp->w_jumplistidx == wp->w_jumplistlen) {
+ if (loadfiles // otherwise (i.e.: Shada), last entry should be kept
+ && wp->w_jumplistlen && wp->w_jumplistidx == wp->w_jumplistlen) {
const xfmark_T *fm_last = &wp->w_jumplist[wp->w_jumplistlen - 1];
if (fm_last->fmark.fnum == curbuf->b_fnum
&& fm_last->fmark.mark.lnum == wp->w_cursor.lnum) {
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index 683087bd7b..fae7635d34 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -456,43 +456,50 @@ static bool intable(const struct interval *table, size_t n_items, int c)
return false;
}
-/*
- * For UTF-8 character "c" return 2 for a double-width character, 1 for others.
- * Returns 4 or 6 for an unprintable character.
- * Is only correct for characters >= 0x80.
- * When p_ambw is "double", return 2 for a character with East Asian Width
- * class 'A'(mbiguous).
- */
+/// For UTF-8 character "c" return 2 for a double-width character, 1 for others.
+/// Returns 4 or 6 for an unprintable character.
+/// Is only correct for characters >= 0x80.
+/// When p_ambw is "double", return 2 for a character with East Asian Width
+/// class 'A'(mbiguous).
+///
+/// @note Tables `doublewidth` and `ambiguous` are generated by
+/// gen_unicode_tables.lua, which must be manually invoked as needed.
int utf_char2cells(int c)
{
if (c >= 0x100) {
#ifdef USE_WCHAR_FUNCTIONS
- /*
- * Assume the library function wcwidth() works better than our own
- * stuff. It should return 1 for ambiguous width chars!
- */
+ //
+ // Assume the library function wcwidth() works better than our own
+ // stuff. It should return 1 for ambiguous width chars!
+ //
int n = wcwidth(c);
- if (n < 0)
- return 6; /* unprintable, displays <xxxx> */
- if (n > 1)
+ if (n < 0) {
+ return 6; // unprintable, displays <xxxx>
+ }
+ if (n > 1) {
return n;
+ }
#else
- if (!utf_printable(c))
- return 6; /* unprintable, displays <xxxx> */
- if (intable(doublewidth, ARRAY_SIZE(doublewidth), c))
+ if (!utf_printable(c)) {
+ return 6; // unprintable, displays <xxxx>
+ }
+ if (intable(doublewidth, ARRAY_SIZE(doublewidth), c)) {
return 2;
+ }
#endif
if (p_emoji && intable(emoji_width, ARRAY_SIZE(emoji_width), c)) {
return 2;
}
+ } else if (c >= 0x80 && !vim_isprintc(c)) {
+ // Characters below 0x100 are influenced by 'isprint' option.
+ return 4; // unprintable, displays <xx>
}
- /* Characters below 0x100 are influenced by 'isprint' option */
- else if (c >= 0x80 && !vim_isprintc(c))
- return 4; /* unprintable, displays <xx> */
- if (c >= 0x80 && *p_ambw == 'd' && intable(ambiguous, ARRAY_SIZE(ambiguous), c))
+ if (c >= 0x80 && *p_ambw == 'd'
+ && intable(ambiguous, ARRAY_SIZE(ambiguous), c)) {
return 2;
+ }
return 1;
}
@@ -1431,6 +1438,64 @@ int utf16_to_utf8(const wchar_t *strw, char **str)
#endif
+/// Measure the length of a string in corresponding UTF-32 and UTF-16 units.
+///
+/// Invalid UTF-8 bytes, or embedded surrogates, count as one code point/unit
+/// each.
+///
+/// The out parameters are incremented. This is used to measure the size of
+/// a buffer region consisting of multiple line segments.
+///
+/// @param s the string
+/// @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)
+ FUNC_ATTR_NONNULL_ALL
+{
+ size_t count = 0, extra = 0;
+ size_t clen;
+ for (size_t i = 0; i < len && s[i] != NUL; i += clen) {
+ clen = utf_ptr2len_len(s+i, len-i);
+ // NB: gets the byte value of invalid sequence bytes.
+ // we only care whether the char fits in the BMP or not
+ int c = (clen > 1) ? utf_ptr2char(s+i) : s[i];
+ count++;
+ if (c > 0xFFFF) {
+ extra++;
+ }
+ }
+ *codepoints += count;
+ *codeunits += count + extra;
+}
+
+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;
+ size_t clen, i;
+ if (index == 0) {
+ return 0;
+ }
+ for (i = 0; i < len && s[i] != NUL; i += clen) {
+ clen = utf_ptr2len_len(s+i, len-i);
+ // NB: gets the byte value of invalid sequence bytes.
+ // we only care whether the char fits in the BMP or not
+ int c = (clen > 1) ? utf_ptr2char(s+i) : s[i];
+ count++;
+ if (use_utf16_units && c > 0xFFFF) {
+ count++;
+ }
+ if (count >= index) {
+ return i+clen;
+ }
+ }
+ return -1;
+}
+
+
/*
* Version of strnicmp() that handles multi-byte characters.
* Needed for Big5, Shift-JIS and UTF-8 encoding. Other DBCS encodings can
@@ -1997,7 +2062,7 @@ enc_locale_copy_enc:
return enc_canonize((char_u *)buf);
}
-# if defined(USE_ICONV)
+# if defined(HAVE_ICONV)
/*
@@ -2018,13 +2083,6 @@ void * my_iconv_open(char_u *to, char_u *from)
if (iconv_working == kBroken)
return (void *)-1; /* detected a broken iconv() previously */
-#ifdef DYNAMIC_ICONV
- // Check if the iconv.dll can be found.
- if (!iconv_enabled(true)) {
- return (void *)-1;
- }
-#endif
-
fd = iconv_open((char *)enc_skip(to), (char *)enc_skip(from));
if (fd != (iconv_t)-1 && iconv_working == kUnknown) {
@@ -2131,152 +2189,7 @@ static char_u *iconv_string(const vimconv_T *const vcp, char_u *str,
return result;
}
-# if defined(DYNAMIC_ICONV)
-// Dynamically load the "iconv.dll" on Win32.
-
-#ifndef DYNAMIC_ICONV // just generating prototypes
-# define HINSTANCE int
-#endif
-static HINSTANCE hIconvDLL = 0;
-static HINSTANCE hMsvcrtDLL = 0;
-
-# ifndef DYNAMIC_ICONV_DLL
-# define DYNAMIC_ICONV_DLL "iconv.dll"
-# define DYNAMIC_ICONV_DLL_ALT "libiconv-2.dll"
-# endif
-# ifndef DYNAMIC_MSVCRT_DLL
-# define DYNAMIC_MSVCRT_DLL "msvcrt.dll"
-# endif
-
-/*
- * Get the address of 'funcname' which is imported by 'hInst' DLL.
- */
-static void * get_iconv_import_func(HINSTANCE hInst,
- const char *funcname)
-{
- PBYTE pImage = (PBYTE)hInst;
- PIMAGE_DOS_HEADER pDOS = (PIMAGE_DOS_HEADER)hInst;
- PIMAGE_NT_HEADERS pPE;
- PIMAGE_IMPORT_DESCRIPTOR pImpDesc;
- PIMAGE_THUNK_DATA pIAT; /* Import Address Table */
- PIMAGE_THUNK_DATA pINT; /* Import Name Table */
- PIMAGE_IMPORT_BY_NAME pImpName;
-
- if (pDOS->e_magic != IMAGE_DOS_SIGNATURE)
- return NULL;
- pPE = (PIMAGE_NT_HEADERS)(pImage + pDOS->e_lfanew);
- if (pPE->Signature != IMAGE_NT_SIGNATURE)
- return NULL;
- pImpDesc = (PIMAGE_IMPORT_DESCRIPTOR)(pImage
- + pPE->OptionalHeader.DataDirectory[
- IMAGE_DIRECTORY_ENTRY_IMPORT]
- .VirtualAddress);
- for (; pImpDesc->FirstThunk; ++pImpDesc) {
- if (!pImpDesc->OriginalFirstThunk)
- continue;
- pIAT = (PIMAGE_THUNK_DATA)(pImage + pImpDesc->FirstThunk);
- pINT = (PIMAGE_THUNK_DATA)(pImage + pImpDesc->OriginalFirstThunk);
- for (; pIAT->u1.Function; ++pIAT, ++pINT) {
- if (IMAGE_SNAP_BY_ORDINAL(pINT->u1.Ordinal))
- continue;
- pImpName = (PIMAGE_IMPORT_BY_NAME)(pImage
- + (UINT_PTR)(pINT->u1.AddressOfData));
- if (strcmp(pImpName->Name, funcname) == 0)
- return (void *)pIAT->u1.Function;
- }
- }
- return NULL;
-}
-
-// Load library "name".
-HINSTANCE vimLoadLib(char *name)
-{
- HINSTANCE dll = NULL;
-
- // NOTE: Do not use mch_dirname() and mch_chdir() here, they may call
- // vimLoadLib() recursively, which causes a stack overflow.
- wchar_t old_dirw[MAXPATHL];
-
- // Path to exe dir.
- char *buf = xstrdup((char *)get_vim_var_str(VV_PROGPATH));
- // ptrdiff_t len = ;
- // assert(len > 0);
- buf[path_tail_with_sep(buf) - buf] = '\0';
-
- if (GetCurrentDirectoryW(MAXPATHL, old_dirw) != 0) {
- // Change directory to where the executable is, both to make
- // sure we find a .dll there and to avoid looking for a .dll
- // in the current directory.
- SetCurrentDirectory((LPCSTR)buf);
- // TODO(justinmk): use uv_dlopen instead. see os_libcall
- dll = LoadLibrary(name);
- SetCurrentDirectoryW(old_dirw);
- }
-
- return dll;
-}
-
-
-/*
- * Try opening the iconv.dll and return TRUE if iconv() can be used.
- */
-bool iconv_enabled(bool verbose)
-{
- if (hIconvDLL != 0 && hMsvcrtDLL != 0)
- return true;
- hIconvDLL = vimLoadLib(DYNAMIC_ICONV_DLL);
- if (hIconvDLL == 0) /* sometimes it's called libiconv.dll */
- hIconvDLL = vimLoadLib(DYNAMIC_ICONV_DLL_ALT);
- if (hIconvDLL != 0)
- hMsvcrtDLL = vimLoadLib(DYNAMIC_MSVCRT_DLL);
- if (hIconvDLL == 0 || hMsvcrtDLL == 0) {
- /* Only give the message when 'verbose' is set, otherwise it might be
- * done whenever a conversion is attempted. */
- if (verbose && p_verbose > 0) {
- verbose_enter();
- EMSG2(_(e_loadlib),
- hIconvDLL == 0 ? DYNAMIC_ICONV_DLL : DYNAMIC_MSVCRT_DLL);
- verbose_leave();
- }
- iconv_end();
- return false;
- }
-
- iconv = (void *)GetProcAddress(hIconvDLL, "libiconv");
- iconv_open = (void *)GetProcAddress(hIconvDLL, "libiconv_open");
- iconv_close = (void *)GetProcAddress(hIconvDLL, "libiconv_close");
- iconvctl = (void *)GetProcAddress(hIconvDLL, "libiconvctl");
- iconv_errno = get_iconv_import_func(hIconvDLL, "_errno");
- if (iconv_errno == NULL)
- iconv_errno = (void *)GetProcAddress(hMsvcrtDLL, "_errno");
- if (iconv == NULL || iconv_open == NULL || iconv_close == NULL
- || iconvctl == NULL || iconv_errno == NULL) {
- iconv_end();
- if (verbose && p_verbose > 0) {
- verbose_enter();
- EMSG2(_(e_loadfunc), "for libiconv");
- verbose_leave();
- }
- return false;
- }
- return true;
-}
-
-void iconv_end(void)
-{
- if (hIconvDLL != 0) {
- // TODO(justinmk): use uv_dlclose instead.
- FreeLibrary(hIconvDLL);
- }
- if (hMsvcrtDLL != 0) {
- FreeLibrary(hMsvcrtDLL);
- }
- hIconvDLL = 0;
- hMsvcrtDLL = 0;
-}
-
-# endif /* DYNAMIC_ICONV */
-# endif /* USE_ICONV */
+# endif // HAVE_ICONV
@@ -2307,10 +2220,11 @@ int convert_setup_ext(vimconv_T *vcp, char_u *from, bool from_unicode_is_utf8,
int from_is_utf8;
int to_is_utf8;
- /* Reset to no conversion. */
-# ifdef USE_ICONV
- if (vcp->vc_type == CONV_ICONV && vcp->vc_fd != (iconv_t)-1)
+ // Reset to no conversion.
+# ifdef HAVE_ICONV
+ if (vcp->vc_type == CONV_ICONV && vcp->vc_fd != (iconv_t)-1) {
iconv_close(vcp->vc_fd);
+ }
# endif
*vcp = (vimconv_T)MBYTE_NONE_CONV;
@@ -2345,9 +2259,9 @@ int convert_setup_ext(vimconv_T *vcp, char_u *from, bool from_unicode_is_utf8,
/* Internal utf-8 -> latin9 conversion. */
vcp->vc_type = CONV_TO_LATIN9;
}
-# ifdef USE_ICONV
- else {
- /* Use iconv() for conversion. */
+# 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);
@@ -2499,8 +2413,8 @@ char_u * string_convert_ext(const vimconv_T *const vcp, char_u *ptr,
*lenp = (size_t)(d - retval);
break;
-# ifdef USE_ICONV
- case CONV_ICONV: /* conversion with vcp->vc_fd */
+# ifdef HAVE_ICONV
+ case CONV_ICONV: // conversion with vcp->vc_fd
retval = iconv_string(vcp, ptr, len, unconvlenp, lenp);
break;
# endif
diff --git a/src/nvim/mbyte.h b/src/nvim/mbyte.h
index ed48705c6d..536d58be1f 100644
--- a/src/nvim/mbyte.h
+++ b/src/nvim/mbyte.h
@@ -63,7 +63,7 @@ typedef enum {
typedef struct {
int vc_type; ///< Zero or more ConvFlags.
int vc_factor; ///< Maximal expansion factor.
-# ifdef USE_ICONV
+# ifdef HAVE_ICONV
iconv_t vc_fd; ///< Value for CONV_ICONV.
# endif
bool vc_fail; ///< What to do with invalid characters: if true, fail,
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index a69669f680..34774055c1 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.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
-/* for debugging */
-/* #define CHECK(c, s) if (c) EMSG(s) */
-#define CHECK(c, s)
+// for debugging
+// #define CHECK(c, s) do { if (c) EMSG(s); } while (0)
+#define CHECK(c, s) do { } while (0)
/*
* memline.c: Contains the functions for appending, deleting and changing the
@@ -47,6 +47,7 @@
#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"
@@ -1178,7 +1179,7 @@ void ml_recover(void)
/* Recovering an empty file results in two lines and the first line is
* empty. Don't set the modified flag then. */
if (!(curbuf->b_ml.ml_line_count == 2 && *ml_get(1) == NUL)) {
- changed_int();
+ changed_internal();
buf_inc_changedtick(curbuf);
}
} else {
@@ -1188,7 +1189,7 @@ void ml_recover(void)
i = STRCMP(p, ml_get(idx + lnum));
xfree(p);
if (i != 0) {
- changed_int();
+ changed_internal();
buf_inc_changedtick(curbuf);
break;
}
@@ -2383,6 +2384,23 @@ static int ml_append_int(
return OK;
}
+void ml_add_deleted_len(char_u *ptr, ssize_t len)
+{
+ if (inhibit_delete_count) {
+ return;
+ }
+ if (len == -1) {
+ len = STRLEN(ptr);
+ }
+ curbuf->deleted_bytes += len+1;
+ if (curbuf->update_need_codepoints) {
+ mb_utflen(ptr, len, &curbuf->deleted_codepoints,
+ &curbuf->deleted_codeunits);
+ curbuf->deleted_codepoints++; // NL char
+ curbuf->deleted_codeunits++;
+ }
+}
+
/*
* Replace line lnum, with buffering, in current buffer.
*
@@ -2403,13 +2421,24 @@ int ml_replace(linenr_T lnum, char_u *line, bool copy)
if (curbuf->b_ml.ml_mfp == NULL && open_buffer(FALSE, NULL, 0) == FAIL)
return FAIL;
+ bool readlen = true;
+
if (copy) {
line = vim_strsave(line);
}
- if (curbuf->b_ml.ml_line_lnum != lnum) /* other line buffered */
- ml_flush_line(curbuf); /* flush it */
- else if (curbuf->b_ml.ml_flags & ML_LINE_DIRTY) /* same line allocated */
- xfree(curbuf->b_ml.ml_line_ptr); /* free it */
+ if (curbuf->b_ml.ml_line_lnum != lnum) { // other line buffered
+ ml_flush_line(curbuf); // flush it
+ } else if (curbuf->b_ml.ml_flags & ML_LINE_DIRTY) { // same line allocated
+ ml_add_deleted_len(curbuf->b_ml.ml_line_ptr, -1);
+ readlen = false; // already added the length
+
+ xfree(curbuf->b_ml.ml_line_ptr); // free it
+ }
+
+ if (readlen && kv_size(curbuf->update_callbacks)) {
+ ml_add_deleted_len(ml_get_buf(curbuf, lnum, false), -1);
+ }
+
curbuf->b_ml.ml_line_ptr = line;
curbuf->b_ml.ml_line_lnum = lnum;
curbuf->b_ml.ml_flags = (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY;
@@ -2491,6 +2520,10 @@ static int ml_delete_int(buf_T *buf, linenr_T lnum, bool message)
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.
+ assert(line_size >= 1);
+ ml_add_deleted_len((char_u *)dp + line_start, line_size-1);
/*
* special case: If there is only one line in the data block it becomes empty.
@@ -2676,6 +2709,17 @@ void ml_clearmarked(void)
return;
}
+size_t ml_flush_deleted_bytes(buf_T *buf, size_t *codepoints, size_t *codeunits)
+{
+ size_t ret = buf->deleted_bytes;
+ *codepoints = buf->deleted_codepoints;
+ *codeunits = buf->deleted_codeunits;
+ buf->deleted_bytes = 0;
+ buf->deleted_codepoints = 0;
+ buf->deleted_codeunits = 0;
+ return ret;
+}
+
/*
* flush ml_line if necessary
*/
@@ -2704,6 +2748,8 @@ static void ml_flush_line(buf_T *buf)
return;
entered = TRUE;
+ buf->flush_count++;
+
lnum = buf->b_ml.ml_line_lnum;
new_line = buf->b_ml.ml_line_ptr;
diff --git a/src/nvim/memory.c b/src/nvim/memory.c
index dced03f3d5..64aae71433 100644
--- a/src/nvim/memory.c
+++ b/src/nvim/memory.c
@@ -9,6 +9,7 @@
#include <stdbool.h>
#include "nvim/vim.h"
+#include "nvim/context.h"
#include "nvim/eval.h"
#include "nvim/highlight.h"
#include "nvim/memfile.h"
@@ -648,7 +649,7 @@ void free_all_mem(void)
// Free all option values. Must come after closing windows.
free_all_options();
- free_cmdline_buf();
+ free_arshape_buf();
/* Clear registers. */
clear_registers();
@@ -671,6 +672,7 @@ void free_all_mem(void)
eval_clear();
api_vim_free_all_mem();
+ ctx_free_all();
// Free all buffers. Reset 'autochdir' to avoid accessing things that
// were freed already.
diff --git a/src/nvim/message.c b/src/nvim/message.c
index e1164ad326..b043df17d3 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -116,6 +116,7 @@ static const char *msg_ext_kind = NULL;
static Array msg_ext_chunks = ARRAY_DICT_INIT;
static garray_T msg_ext_last_chunk = GA_INIT(sizeof(char), 40);
static sattr_T msg_ext_last_attr = -1;
+static size_t msg_ext_cur_len = 0;
static bool msg_ext_overwrite = false; ///< will overwrite last message
static int msg_ext_visible = 0; ///< number of messages currently visible
@@ -1877,8 +1878,9 @@ static void msg_puts_display(const char_u *str, int maxlen, int attr,
msg_ext_last_attr = attr;
}
// Concat pieces with the same highlight
- ga_concat_len(&msg_ext_last_chunk, (char *)str,
- strnlen((char *)str, maxlen)); // -V781
+ size_t len = strnlen((char *)str, maxlen); // -V781
+ ga_concat_len(&msg_ext_last_chunk, (char *)str, len);
+ msg_ext_cur_len += len;
return;
}
@@ -2323,8 +2325,8 @@ static void msg_puts_printf(const char *str, const ptrdiff_t maxlen)
}
}
- // primitive way to compute the current column
int cw = utf_char2cells(utf_ptr2char((const char_u *)s));
+ // primitive way to compute the current column
if (cmdmsg_rl) {
if (*s == '\r' || *s == '\n') {
msg_col = Columns - 1;
@@ -2567,6 +2569,7 @@ void mch_errmsg(char *str)
}
}
+// Give a message. To be used when the UI is not initialized yet.
void mch_msg(char *str)
{
wchar_t *utf16str;
@@ -2722,6 +2725,7 @@ void msg_ext_ui_flush(void)
}
msg_ext_kind = NULL;
msg_ext_chunks = (Array)ARRAY_DICT_INIT;
+ msg_ext_cur_len = 0;
msg_ext_overwrite = false;
}
}
@@ -2734,6 +2738,7 @@ void msg_ext_flush_showmode(void)
msg_ext_emit_chunk();
ui_call_msg_showmode(msg_ext_chunks);
msg_ext_chunks = (Array)ARRAY_DICT_INIT;
+ msg_ext_cur_len = 0;
}
}
@@ -2940,7 +2945,7 @@ int verbose_open(void)
/* Only give the error message once. */
verbose_did_open = TRUE;
- verbose_fd = mch_fopen((char *)p_vfile, "a");
+ verbose_fd = os_fopen((char *)p_vfile, "a");
if (verbose_fd == NULL) {
EMSG2(_(e_notopen), p_vfile);
return FAIL;
@@ -2970,7 +2975,10 @@ void give_warning(char_u *message, bool hl) FUNC_ATTR_NONNULL_ARG(1)
} else {
keep_msg_attr = 0;
}
- msg_ext_set_kind("wmsg");
+
+ if (msg_ext_kind == NULL) {
+ msg_ext_set_kind("wmsg");
+ }
if (msg_attr((const char *)message, keep_msg_attr) && msg_scrolled == 0) {
set_keep_msg(message, keep_msg_attr);
@@ -2997,6 +3005,14 @@ void msg_advance(int col)
msg_col = col; /* for redirection, may fill it up later */
return;
}
+ if (ui_has(kUIMessages)) {
+ // TODO(bfredl): use byte count as a basic proxy.
+ // later on we might add proper support for formatted messages.
+ while (msg_ext_cur_len < (size_t)col) {
+ msg_putchar(' ');
+ }
+ return;
+ }
if (col >= Columns) /* not enough room */
col = Columns - 1;
if (cmdmsg_rl)
diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c
index 45e03681eb..44e2c7df5f 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -65,872 +65,6 @@
static garray_T ga_users = GA_EMPTY_INIT_VALUE;
/*
- * open_line: Add a new line below or above the current line.
- *
- * For VREPLACE mode, we only add a new line when we get to the end of the
- * file, otherwise we just start replacing the next line.
- *
- * Caller must take care of undo. Since VREPLACE may affect any number of
- * lines however, it may call u_save_cursor() again when starting to change a
- * new line.
- * "flags": OPENLINE_DELSPACES delete spaces after cursor
- * OPENLINE_DO_COM format comments
- * OPENLINE_KEEPTRAIL keep trailing spaces
- * OPENLINE_MARKFIX adjust mark positions after the line break
- * OPENLINE_COM_LIST format comments with list or 2nd line indent
- *
- * "second_line_indent": indent for after ^^D in Insert mode or if flag
- * OPENLINE_COM_LIST
- *
- * Return TRUE for success, FALSE for failure
- */
-int
-open_line (
- int dir, /* FORWARD or BACKWARD */
- 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
- colnr_T less_cols = 0; // less columns for mark in new line
- colnr_T less_cols_off = 0; // columns to skip for mark adjust
- pos_T old_cursor; // old cursor position
- colnr_T newcol = 0; // new cursor column
- int newindent = 0; // auto-indent of the new line
- bool trunc_line = false; // truncate current line afterwards
- bool retval = false; // return value
- int extra_len = 0; // length of p_extra string
- int lead_len; // length of comment leader
- char_u *lead_flags; // position in 'comments' for comment leader
- char_u *leader = NULL; // copy of comment leader
- char_u *allocated = NULL; // allocated memory
- char_u *p;
- char_u saved_char = NUL; // init for GCC
- pos_T *pos;
- bool do_si = (!p_paste && curbuf->b_p_si && !curbuf->b_p_cin
- && *curbuf->b_p_inde == NUL);
- bool no_si = false; // reset did_si afterwards
- int first_char = NUL; // init for GCC
- int vreplace_mode;
- bool did_append; // appended a new line
- int saved_pi = curbuf->b_p_pi; // copy of preserveindent setting
-
- // make a copy of the current line so we can mess with it
- char_u *saved_line = vim_strsave(get_cursor_line_ptr());
-
- if (State & VREPLACE_FLAG) {
- /*
- * With VREPLACE we make a copy of the next line, which we will be
- * starting to replace. First make the new line empty and let vim play
- * with the indenting and comment leader to its heart's content. Then
- * we grab what it ended up putting on the new line, put back the
- * original line, and call ins_char() to put each new character onto
- * 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));
- else
- next_line = vim_strsave((char_u *)"");
-
- /*
- * In VREPLACE mode, a NL replaces the rest of the line, and starts
- * replacing the next line, so push all of the characters left on the
- * line onto the replace stack. We'll push any other characters that
- * might be replaced at the start of the next line (due to autoindent
- * etc) a bit later.
- */
- replace_push(NUL); /* Call twice because BS over NL expects it */
- replace_push(NUL);
- p = saved_line + curwin->w_cursor.col;
- while (*p != NUL) {
- if (has_mbyte)
- p += replace_push_mb(p);
- else
- replace_push(*p++);
- }
- saved_line[curwin->w_cursor.col] = NUL;
- }
-
- if ((State & INSERT)
- && !(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);
- first_char = *p;
- }
- extra_len = (int)STRLEN(p_extra);
- saved_char = *p_extra;
- *p_extra = NUL;
- }
-
- u_clearline(); // cannot do "U" command when adding lines
- did_si = false;
- ai_col = 0;
-
- /*
- * If we just did an auto-indent, then we didn't type anything on
- * 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;
-
- /*
- * 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
- ) {
- // count white space on current line
- newindent = get_indent_str(saved_line, (int)curbuf->b_p_ts, false);
- if (newindent == 0 && !(flags & OPENLINE_COM_LIST)) {
- newindent = second_line_indent; // for ^^D command in insert mode
- }
-
- /*
- * Do smart indenting.
- * In insert/replace mode (only when dir == FORWARD)
- * we may move some text to the next line. If it starts with '{'
- * don't add an indent. Fixes inserting a NL before '{' in line
- * "if (condition) {"
- */
- if (!trunc_line && do_si && *saved_line != NUL
- && (p_extra == NULL || first_char != '{')) {
- 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);
- else
- lead_len = 0;
- if (dir == FORWARD) {
- // Skip preprocessor directives, unless they are
- // recognised as comments.
- if (lead_len == 0 && ptr[0] == '#') {
- while (ptr[0] == '#' && curwin->w_cursor.lnum > 1) {
- ptr = ml_get(--curwin->w_cursor.lnum);
- }
- newindent = get_indent();
- }
- if (flags & OPENLINE_DO_COM)
- lead_len = get_leader_len(ptr, NULL, FALSE, TRUE);
- else
- lead_len = 0;
- if (lead_len > 0) {
- /*
- * This case gets the following right:
- * \*
- * * A comment (read '\' as '/').
- * *\
- * #define IN_THE_WAY
- * This should line up here;
- */
- p = skipwhite(ptr);
- if (p[0] == '/' && p[1] == '*')
- p++;
- if (p[0] == '*') {
- for (p++; *p; p++) {
- if (p[0] == '/' && p[-1] == '*') {
- /*
- * End of C comment, indent should line up
- * with the line containing the start of
- * the comment
- */
- curwin->w_cursor.col = (colnr_T)(p - ptr);
- if ((pos = findmatch(NULL, NUL)) != NULL) {
- curwin->w_cursor.lnum = pos->lnum;
- newindent = get_indent();
- }
- }
- }
- }
- } else { /* Not a comment line */
- /* Find last non-blank in line */
- p = ptr + STRLEN(ptr) - 1;
- while (p > ptr && ascii_iswhite(*p))
- --p;
- last_char = *p;
-
- /*
- * find the character just before the '{' or ';'
- */
- if (last_char == '{' || last_char == ';') {
- if (p > ptr)
- --p;
- while (p > ptr && ascii_iswhite(*p))
- --p;
- }
- /*
- * Try to catch lines that are split over multiple
- * lines. eg:
- * if (condition &&
- * condition) {
- * Should line up here!
- * }
- */
- if (*p == ')') {
- curwin->w_cursor.col = (colnr_T)(p - ptr);
- if ((pos = findmatch(NULL, '(')) != NULL) {
- curwin->w_cursor.lnum = pos->lnum;
- newindent = get_indent();
- ptr = get_cursor_line_ptr();
- }
- }
- /*
- * If last character is '{' do indent, without
- * checking for "if" and the like.
- */
- 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
- * '}'.
- */
- else if (last_char != ';' && last_char != '}'
- && cin_is_cinword(ptr))
- did_si = true;
- }
- } else { // dir == BACKWARD
- // Skip preprocessor directives, unless they are
- // recognised as comments.
- if (lead_len == 0 && ptr[0] == '#') {
- bool was_backslashed = false;
-
- while ((ptr[0] == '#' || was_backslashed)
- && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) {
- if (*ptr && ptr[STRLEN(ptr) - 1] == '\\') {
- was_backslashed = true;
- } else {
- was_backslashed = false;
- }
- ptr = ml_get(++curwin->w_cursor.lnum);
- }
- if (was_backslashed) {
- newindent = 0; // Got to end of file
- } else {
- newindent = get_indent();
- }
- }
- p = skipwhite(ptr);
- if (*p == '}') { // if line starts with '}': do indent
- did_si = true;
- } else { // can delete indent when '{' typed
- can_si_back = true;
- }
- }
- curwin->w_cursor = old_cursor;
- }
- if (do_si) {
- can_si = true;
- }
-
- did_ai = true;
- }
-
- /*
- * Find out if the current line starts with a comment leader.
- * This may then be inserted in front of the new line.
- */
- end_comment_pending = NUL;
- if (flags & OPENLINE_DO_COM)
- lead_len = get_leader_len(saved_line, &lead_flags, dir == BACKWARD, TRUE);
- else
- lead_len = 0;
- if (lead_len > 0) {
- 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 */
- int extra_space = FALSE; /* append extra space */
- int current_flag;
- int require_blank = FALSE; /* requires blank after middle */
- 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.
- */
- for (p = lead_flags; *p && *p != ':'; ++p) {
- if (*p == COM_BLANK) {
- require_blank = TRUE;
- continue;
- }
- if (*p == COM_START || *p == COM_MIDDLE) {
- current_flag = *p;
- if (*p == COM_START) {
- /*
- * Doing "O" on a start of comment does not insert leader.
- */
- if (dir == BACKWARD) {
- lead_len = 0;
- break;
- }
-
- /* find start of middle part */
- (void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ",");
- require_blank = FALSE;
- }
-
- /*
- * Isolate the strings of the middle and end leader.
- */
- while (*p && p[-1] != ':') { /* find end of middle flags */
- if (*p == COM_BLANK)
- require_blank = TRUE;
- ++p;
- }
- (void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ",");
-
- while (*p && p[-1] != ':') { /* find end of end flags */
- /* Check whether we allow automatic ending of comments */
- if (*p == COM_AUTO_END)
- end_comment_pending = -1; /* means we want to set it */
- ++p;
- }
- size_t n = copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
-
- if (end_comment_pending == -1) /* we can set it now */
- end_comment_pending = lead_end[n - 1];
-
- /*
- * If the end of the comment is in the same line, don't use
- * the comment leader.
- */
- if (dir == FORWARD) {
- for (p = saved_line + lead_len; *p; ++p)
- if (STRNCMP(p, lead_end, n) == 0) {
- comment_end = p;
- lead_len = 0;
- break;
- }
- }
-
- /*
- * Doing "o" on a start of comment inserts the middle leader.
- */
- if (lead_len > 0) {
- if (current_flag == COM_START) {
- lead_repl = lead_middle;
- lead_repl_len = (int)STRLEN(lead_middle);
- }
-
- /*
- * If we have hit RETURN immediately after the start
- * comment leader, then put a space after the middle
- * comment leader on the next line.
- */
- if (!ascii_iswhite(saved_line[lead_len - 1])
- && ((p_extra != NULL
- && (int)curwin->w_cursor.col == lead_len)
- || (p_extra == NULL
- && saved_line[lead_len] == NUL)
- || require_blank))
- extra_space = TRUE;
- }
- break;
- }
- if (*p == COM_END) {
- /*
- * Doing "o" on the end of a comment does not insert leader.
- * Remember where the end is, might want to use it to find the
- * start (for C-comments).
- */
- if (dir == FORWARD) {
- comment_end = skipwhite(saved_line);
- lead_len = 0;
- break;
- }
-
- /*
- * 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;
- for (lead_repl = p; lead_repl > curbuf->b_p_com
- && lead_repl[-1] != ':'; --lead_repl)
- ;
- lead_repl_len = (int)(p - lead_repl);
-
- /* We can probably always add an extra space when doing "O" on
- * the comment-end */
- extra_space = TRUE;
-
- /* 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 */
- }
- if (end_comment_pending == -1) {
- /* Find last character in end-comment string */
- while (*p2 && *p2 != ',')
- p2++;
- end_comment_pending = p2[-1];
- }
- break;
- }
- if (*p == COM_FIRST) {
- /*
- * 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;
- else {
- lead_repl = (char_u *)"";
- lead_repl_len = 0;
- }
- break;
- }
- }
- if (lead_len > 0) {
- // allocate buffer (may concatenate p_extra later)
- leader = xmalloc((size_t)(lead_len + lead_repl_len + extra_space
- + extra_len + (second_line_indent > 0
- ? second_line_indent : 0) + 1));
- allocated = leader; // remember to free it later
-
- STRLCPY(leader, saved_line, lead_len + 1);
-
- /*
- * Replace leader with lead_repl, right or left adjusted
- */
- if (lead_repl != NULL) {
- int c = 0;
- int off = 0;
-
- for (p = lead_flags; *p != NUL && *p != ':'; ) {
- if (*p == COM_RIGHT || *p == COM_LEFT)
- c = *p++;
- else if (ascii_isdigit(*p) || *p == '-')
- off = getdigits_int(&p);
- else
- ++p;
- }
- if (c == COM_RIGHT) { /* right adjusted leader */
- /* find last non-white in the leader to line up with */
- for (p = leader + lead_len - 1; p > leader
- && ascii_iswhite(*p); --p)
- ;
- ++p;
-
- /* Compute the length of the replaced characters in
- * screen characters, not bytes. */
- {
- int repl_size = vim_strnsize(lead_repl,
- lead_repl_len);
- int old_size = 0;
- char_u *endp = p;
- int l;
-
- while (old_size < repl_size && p > leader) {
- MB_PTR_BACK(leader, p);
- old_size += ptr2cells(p);
- }
- l = lead_repl_len - (int)(endp - p);
- if (l != 0)
- 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;
-
- /* blank-out any other chars from the old leader. */
- while (--p >= leader) {
- int l = utf_head_off(leader, p);
-
- if (l > 1) {
- p -= l;
- if (ptr2cells(p) > 1) {
- p[1] = ' ';
- --l;
- }
- memmove(p + 1, p + l + 1,
- (size_t)((leader + lead_len) - (p + l + 1)));
- lead_len -= l;
- *p = ' ';
- } else if (!ascii_iswhite(*p))
- *p = ' ';
- }
- } else { /* left adjusted leader */
- p = skipwhite(leader);
- /* Compute the length of the replaced characters in
- * screen characters, not bytes. Move the part that is
- * not to be overwritten. */
- {
- int repl_size = vim_strnsize(lead_repl,
- lead_repl_len);
- int i;
- int l;
-
- 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;
- }
- if (i != lead_repl_len) {
- memmove(p + lead_repl_len, p + i,
- (size_t)(lead_len - i - (p - leader)));
- lead_len += lead_repl_len - i;
- }
- }
- memmove(p, lead_repl, (size_t)lead_repl_len);
-
- /* Replace any remaining non-white chars in the old
- * leader by spaces. Keep Tabs, the indent must
- * remain the same. */
- for (p += lead_repl_len; p < leader + lead_len; ++p)
- if (!ascii_iswhite(*p)) {
- /* Don't put a space before a TAB. */
- if (p + 1 < leader + lead_len && p[1] == TAB) {
- lead_len--;
- memmove(p, p + 1, (size_t)(leader + lead_len - p));
- } else {
- int l = (*mb_ptr2len)(p);
-
- if (l > 1) {
- if (ptr2cells(p) > 1) {
- /* Replace a double-wide char with
- * two spaces */
- --l;
- *p++ = ' ';
- }
- memmove(p + 1, p + l, (size_t)(leader + lead_len - p));
- lead_len -= l - 1;
- }
- *p = ' ';
- }
- }
- *p = NUL;
- }
-
- /* Recompute the indent, it may have changed. */
- if (curbuf->b_p_ai
- || do_si
- )
- newindent = get_indent_str(leader, (int)curbuf->b_p_ts, false);
-
- /* Add the indent offset */
- if (newindent + off < 0) {
- off = -newindent;
- newindent = 0;
- } else
- newindent += off;
-
- /* Correct trailing spaces for the shift, so that
- * alignment remains equal. */
- while (off > 0 && lead_len > 0
- && leader[lead_len - 1] == ' ') {
- /* Don't do it when there is a tab before the space */
- if (vim_strchr(skipwhite(leader), '\t') != NULL)
- break;
- --lead_len;
- --off;
- }
-
- /* 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;
- leader[lead_len] = NUL;
- }
-
- if (extra_space) {
- leader[lead_len++] = ' ';
- leader[lead_len] = NUL;
- }
-
- newcol = lead_len;
-
- /*
- * if a new indent will be set below, remove the indent that
- * is in the comment leader
- */
- if (newindent
- || did_si
- ) {
- while (lead_len && ascii_iswhite(*leader)) {
- --lead_len;
- --newcol;
- ++leader;
- }
- }
-
- did_si = can_si = false;
- } else if (comment_end != NULL) {
- // We have finished a comment, so we don't use the leader.
- // If this was a C-comment and 'ai' or 'si' is set do a normal
- // indent to align with the line containing the start of the
- // comment.
- if (comment_end[0] == '*' && comment_end[1] == '/'
- && (curbuf->b_p_ai || do_si)) {
- old_cursor = curwin->w_cursor;
- curwin->w_cursor.col = (colnr_T)(comment_end - saved_line);
- if ((pos = findmatch(NULL, NUL)) != NULL) {
- curwin->w_cursor.lnum = pos->lnum;
- newindent = get_indent();
- }
- curwin->w_cursor = old_cursor;
- }
- }
- }
-
- /* (State == INSERT || State == REPLACE), only when dir == FORWARD */
- if (p_extra != NULL) {
- *p_extra = saved_char; /* restore char that NUL replaced */
-
- /*
- * When 'ai' set or "flags" has OPENLINE_DELSPACES, skip to the first
- * non-blank.
- *
- * 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 */
- if (curbuf->b_p_ai || (flags & OPENLINE_DELSPACES)) {
- while ((*p_extra == ' ' || *p_extra == '\t')
- && !utf_iscomposing(utf_ptr2char(p_extra + 1))) {
- if (REPLACE_NORMAL(State)) {
- replace_push(*p_extra);
- }
- p_extra++;
- less_cols_off++;
- }
- }
-
- /* columns for marks adjusted for removed columns */
- less_cols = (int)(p_extra - saved_line);
- }
-
- if (p_extra == NULL)
- p_extra = (char_u *)""; /* append empty line */
-
- /* concatenate leader and p_extra, if there is a leader */
- if (lead_len > 0) {
- if (flags & OPENLINE_COM_LIST && second_line_indent > 0) {
- int i;
- int padding = second_line_indent
- - (newindent + (int)STRLEN(leader));
-
- /* Here whitespace is inserted after the comment char.
- * Below, set_indent(newindent, SIN_INSERT) will insert the
- * whitespace needed before the comment char. */
- for (i = 0; i < padding; i++) {
- STRCAT(leader, " ");
- less_cols--;
- newcol++;
- }
- }
- STRCAT(leader, p_extra);
- p_extra = leader;
- did_ai = true; // So truncating blanks works with comments
- less_cols -= lead_len;
- } else
- end_comment_pending = NUL; /* turns out there was no leader */
-
- old_cursor = curwin->w_cursor;
- if (dir == BACKWARD)
- --curwin->w_cursor.lnum;
- if (!(State & VREPLACE_FLAG) || old_cursor.lnum >= orig_line_count) {
- if (ml_append(curwin->w_cursor.lnum, p_extra, (colnr_T)0, false) == FAIL) {
- goto theend;
- }
- // Postpone calling changed_lines(), because it would mess up folding
- // with markers.
- // Skip mark_adjust when adding a line after the last one, there can't
- // be marks there. But still needed in diff mode.
- if (curwin->w_cursor.lnum + 1 < curbuf->b_ml.ml_line_count
- || curwin->w_p_diff) {
- mark_adjust(curwin->w_cursor.lnum + 1, (linenr_T)MAXLNUM, 1L, 0L, false);
- }
- did_append = true;
- } else {
- /*
- * In VREPLACE mode we are starting to replace the next line.
- */
- curwin->w_cursor.lnum++;
- if (curwin->w_cursor.lnum >= Insstart.lnum + vr_lines_changed) {
- /* In case we NL to a new line, BS to the previous one, and NL
- * again, we don't want to save the new line for undo twice.
- */
- (void)u_save_cursor(); /* errors are ignored! */
- vr_lines_changed++;
- }
- ml_replace(curwin->w_cursor.lnum, p_extra, true);
- changed_bytes(curwin->w_cursor.lnum, 0);
- curwin->w_cursor.lnum--;
- did_append = FALSE;
- }
-
- if (newindent
- || did_si
- ) {
- ++curwin->w_cursor.lnum;
- if (did_si) {
- int sw = get_sw_value(curbuf);
-
- if (p_sr)
- newindent -= newindent % sw;
- newindent += sw;
- }
- /* Copy the indent */
- if (curbuf->b_p_ci) {
- (void)copy_indent(newindent, saved_line);
-
- /*
- * Set the 'preserveindent' option so that any further screwing
- * with the line doesn't entirely destroy our efforts to preserve
- * it. It gets restored at the function end.
- */
- curbuf->b_p_pi = TRUE;
- } else
- (void)set_indent(newindent, SIN_INSERT);
- less_cols -= curwin->w_cursor.col;
-
- ai_col = curwin->w_cursor.col;
-
- /*
- * In REPLACE mode, for each character in the new indent, there must
- * be a NUL on the replace stack, for when it is deleted with BS
- */
- if (REPLACE_NORMAL(State)) {
- for (colnr_T n = 0; n < curwin->w_cursor.col; n++) {
- replace_push(NUL);
- }
- }
- newcol += curwin->w_cursor.col;
- if (no_si) {
- did_si = false;
- }
- }
-
- /*
- * In REPLACE mode, for each character in the extra leader, there must be
- * a NUL on the replace stack, for when it is deleted with BS.
- */
- if (REPLACE_NORMAL(State))
- while (lead_len-- > 0)
- replace_push(NUL);
-
- curwin->w_cursor = old_cursor;
-
- if (dir == FORWARD) {
- if (trunc_line || (State & INSERT)) {
- // truncate current line at cursor
- saved_line[curwin->w_cursor.col] = NUL;
- // Remove trailing white space, unless OPENLINE_KEEPTRAIL used.
- if (trunc_line && !(flags & OPENLINE_KEEPTRAIL)) {
- truncate_spaces(saved_line);
- }
- ml_replace(curwin->w_cursor.lnum, saved_line, false);
- saved_line = NULL;
- if (did_append) {
- changed_lines(curwin->w_cursor.lnum, curwin->w_cursor.col,
- curwin->w_cursor.lnum + 1, 1L, true);
- did_append = false;
-
- /* Move marks after the line break to the new line. */
- if (flags & OPENLINE_MARKFIX)
- mark_col_adjust(curwin->w_cursor.lnum,
- curwin->w_cursor.col + less_cols_off,
- 1L, (long)-less_cols, 0);
- } else {
- changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col);
- }
- }
-
- /*
- * Put the cursor on the new line. Careful: the scrollup() above may
- * have moved w_cursor, we must use old_cursor.
- */
- curwin->w_cursor.lnum = old_cursor.lnum + 1;
- }
- if (did_append) {
- changed_lines(curwin->w_cursor.lnum, 0, curwin->w_cursor.lnum, 1L, true);
- }
-
- curwin->w_cursor.col = newcol;
- curwin->w_cursor.coladd = 0;
-
- /*
- * In VREPLACE mode, we are handling the replace stack ourselves, so stop
- * fixthisline() from doing it (via change_indent()) by telling it we're in
- * normal INSERT mode.
- */
- if (State & VREPLACE_FLAG) {
- vreplace_mode = State; /* So we know to put things right later */
- State = INSERT;
- } else
- vreplace_mode = 0;
- /*
- * May do lisp indenting.
- */
- if (!p_paste
- && leader == NULL
- && curbuf->b_p_lisp
- && curbuf->b_p_ai) {
- fixthisline(get_lisp_indent);
- ai_col = (colnr_T)getwhitecols_curline();
- }
- /*
- * May do indenting after opening a new line.
- */
- if (!p_paste
- && (curbuf->b_p_cin
- || *curbuf->b_p_inde != NUL
- )
- && in_cinkeys(dir == FORWARD
- ? KEY_OPEN_FORW
- : KEY_OPEN_BACK, ' ', linewhite(curwin->w_cursor.lnum))) {
- do_c_expr_indent();
- ai_col = (colnr_T)getwhitecols_curline();
- }
- if (vreplace_mode != 0)
- State = vreplace_mode;
-
- /*
- * Finally, VREPLACE gets the stuff on the new line, then puts back the
- * original line, and inserts the new stuff char by char, pushing old stuff
- * onto the replace stack (via ins_char()).
- */
- if (State & VREPLACE_FLAG) {
- /* Put new line in p_extra */
- p_extra = vim_strsave(get_cursor_line_ptr());
-
- // Put back original line
- ml_replace(curwin->w_cursor.lnum, next_line, false);
-
- /* Insert new stuff into line again */
- curwin->w_cursor.col = 0;
- curwin->w_cursor.coladd = 0;
- ins_bytes(p_extra); /* will call changed_bytes() */
- xfree(p_extra);
- next_line = NULL;
- }
-
- retval = true; // success!
-theend:
- curbuf->b_p_pi = saved_pi;
- xfree(saved_line);
- xfree(next_line);
- xfree(allocated);
- return retval;
-}
-
-/*
* get_leader_len() returns the length in bytes of the prefix of the given
* string which introduces a comment. If this string is not a comment then
* 0 is returned.
@@ -1373,398 +507,8 @@ int plines_m_win(win_T *wp, linenr_T first, linenr_T last)
return count;
}
-/*
- * Insert string "p" at the cursor position. Stops at a NUL byte.
- * Handles Replace mode and multi-byte characters.
- */
-void ins_bytes(char_u *p)
-{
- ins_bytes_len(p, STRLEN(p));
-}
-
-/// Insert string "p" with length "len" at the cursor position.
-/// Handles Replace mode and multi-byte characters.
-void ins_bytes_len(char_u *p, size_t len)
-{
- if (has_mbyte) {
- size_t n;
- for (size_t i = 0; i < len; i += n) {
- if (enc_utf8) {
- // avoid reading past p[len]
- n = (size_t)utfc_ptr2len_len(p + i, (int)(len - i));
- } else {
- n = (size_t)(*mb_ptr2len)(p + i);
- }
- ins_char_bytes(p + i, n);
- }
- } else {
- for (size_t i = 0; i < len; i++) {
- ins_char(p[i]);
- }
- }
-}
-
-/// Insert or replace a single character at the cursor position.
-/// When in REPLACE or VREPLACE mode, replace any existing character.
-/// Caller must have prepared for undo.
-/// For multi-byte characters we get the whole character, the caller must
-/// convert bytes to a character.
-void ins_char(int c)
-{
- char_u buf[MB_MAXBYTES + 1];
- size_t n = (size_t)utf_char2bytes(c, buf);
-
- // When "c" is 0x100, 0x200, etc. we don't want to insert a NUL byte.
- // Happens for CTRL-Vu9900.
- if (buf[0] == 0) {
- buf[0] = '\n';
- }
- ins_char_bytes(buf, n);
-}
-
-void ins_char_bytes(char_u *buf, size_t charlen)
-{
- // Break tabs if needed.
- if (virtual_active() && curwin->w_cursor.coladd > 0) {
- coladvance_force(getviscol());
- }
-
- size_t col = (size_t)curwin->w_cursor.col;
- linenr_T lnum = curwin->w_cursor.lnum;
- char_u *oldp = ml_get(lnum);
- size_t linelen = STRLEN(oldp) + 1; // length of old line including NUL
-
- // The lengths default to the values for when not replacing.
- size_t oldlen = 0; // nr of bytes inserted
- size_t newlen = charlen; // nr of bytes deleted (0 when not replacing)
-
- if (State & REPLACE_FLAG) {
- if (State & VREPLACE_FLAG) {
- // Disable 'list' temporarily, unless 'cpo' contains the 'L' flag.
- // Returns the old value of list, so when finished,
- // curwin->w_p_list should be set back to this.
- int old_list = curwin->w_p_list;
- if (old_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL) {
- curwin->w_p_list = false;
- }
- // In virtual replace mode each character may replace one or more
- // characters (zero if it's a TAB). Count the number of bytes to
- // be deleted to make room for the new character, counting screen
- // 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);
- while (oldp[col + oldlen] != NUL && vcol < new_vcol) {
- vcol += chartabsize(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) {
- break;
- }
- oldlen += (size_t)(*mb_ptr2len)(oldp + col + oldlen);
- // Deleted a bit too much, insert spaces.
- if (vcol > new_vcol) {
- newlen += (size_t)(vcol - new_vcol);
- }
- }
- curwin->w_p_list = old_list;
- } else if (oldp[col] != NUL) {
- // normal replace
- oldlen = (size_t)(*mb_ptr2len)(oldp + col);
- }
-
-
- /* Push the replaced bytes onto the replace stack, so that they can be
- * put back when BS is used. The bytes of a multi-byte character are
- * done the other way around, so that the first byte is popped off
- * first (it tells the byte length of the character). */
- replace_push(NUL);
- for (size_t i = 0; i < oldlen; i++) {
- if (has_mbyte) {
- i += (size_t)replace_push_mb(oldp + col + i) - 1;
- } else {
- replace_push(oldp[col + i]);
- }
- }
- }
-
- char_u *newp = xmalloc((size_t)(linelen + newlen - oldlen));
-
- // Copy bytes before the cursor.
- if (col > 0) {
- memmove(newp, oldp, (size_t)col);
- }
-
- // Copy bytes after the changed character(s).
- char_u *p = newp + col;
- if (linelen > col + oldlen) {
- memmove(p + newlen, oldp + col + oldlen,
- (size_t)(linelen - col - oldlen));
- }
-
- // Insert or overwrite the new character.
- memmove(p, buf, charlen);
-
- // Fill with spaces when necessary.
- for (size_t i = charlen; i < newlen; i++) {
- p[i] = ' ';
- }
-
- // Replace the line in the buffer.
- ml_replace(lnum, newp, false);
-
- // mark the buffer as changed and prepare for displaying
- changed_bytes(lnum, (colnr_T)col);
-
- /*
- * If we're in Insert or Replace mode and 'showmatch' is set, then briefly
- * show the match for right parens and braces.
- */
- if (p_sm && (State & INSERT)
- && msg_silent == 0
- && !ins_compl_active()
- ) {
- showmatch(utf_ptr2char(buf));
- }
-
- if (!p_ri || (State & REPLACE_FLAG)) {
- // Normal insert: move cursor right
- curwin->w_cursor.col += (int)charlen;
- }
- /*
- * TODO: should try to update w_row here, to avoid recomputing it later.
- */
-}
-
-/*
- * Insert a string at the cursor position.
- * Note: Does NOT handle Replace mode.
- * Caller must have prepared for undo.
- */
-void ins_str(char_u *s)
-{
- char_u *oldp, *newp;
- int newlen = (int)STRLEN(s);
- int oldlen;
- colnr_T col;
- linenr_T lnum = curwin->w_cursor.lnum;
-
- if (virtual_active() && curwin->w_cursor.coladd > 0)
- coladvance_force(getviscol());
-
- col = curwin->w_cursor.col;
- oldp = ml_get(lnum);
- oldlen = (int)STRLEN(oldp);
-
- newp = (char_u *) xmalloc((size_t)(oldlen + newlen + 1));
- if (col > 0)
- memmove(newp, oldp, (size_t)col);
- memmove(newp + col, s, (size_t)newlen);
- memmove(newp + col + newlen, oldp + col, (size_t)(oldlen - col + 1));
- ml_replace(lnum, newp, false);
- changed_bytes(lnum, col);
- curwin->w_cursor.col += newlen;
-}
-
-// Delete one character under the cursor.
-// If "fixpos" is true, don't leave the cursor on the NUL after the line.
-// Caller must have prepared for undo.
-//
-// return FAIL for failure, OK otherwise
-int del_char(bool fixpos)
-{
- if (has_mbyte) {
- /* Make sure the cursor is at the start of a character. */
- mb_adjust_cursor();
- if (*get_cursor_pos_ptr() == NUL)
- return FAIL;
- return del_chars(1L, fixpos);
- }
- return del_bytes(1, fixpos, true);
-}
-
-/*
- * Like del_bytes(), but delete characters instead of bytes.
- */
-int del_chars(long count, int fixpos)
-{
- int bytes = 0;
- long i;
- char_u *p;
- int l;
-
- p = get_cursor_pos_ptr();
- for (i = 0; i < count && *p != NUL; ++i) {
- l = (*mb_ptr2len)(p);
- bytes += l;
- p += l;
- }
- return del_bytes(bytes, fixpos, TRUE);
-}
-
-/// Delete "count" bytes under the cursor.
-/// If "fixpos" is true, don't leave the cursor on the NUL after the line.
-/// Caller must have prepared for undo.
-///
-/// @param count number of bytes to be deleted
-/// @param fixpos_arg leave the cursor on the NUL after the line
-/// @param use_delcombine 'delcombine' option applies
-///
-/// @return FAIL for failure, OK otherwise
-int del_bytes(colnr_T count, bool fixpos_arg, bool use_delcombine)
-{
- linenr_T lnum = curwin->w_cursor.lnum;
- colnr_T col = curwin->w_cursor.col;
- bool fixpos = fixpos_arg;
- char_u *oldp = ml_get(lnum);
- colnr_T oldlen = (colnr_T)STRLEN(oldp);
-
- // Can't do anything when the cursor is on the NUL after the line.
- if (col >= oldlen) {
- return FAIL;
- }
- // If "count" is zero there is nothing to do.
- if (count == 0) {
- return OK;
- }
- // If "count" is negative the caller must be doing something wrong.
- if (count < 1) {
- IEMSGN("E950: Invalid count for del_bytes(): %ld", count);
- return FAIL;
- }
-
- /* If 'delcombine' is set and deleting (less than) one character, only
- * delete the last combining character. */
- if (p_deco && use_delcombine && enc_utf8
- && utfc_ptr2len(oldp + col) >= count) {
- int cc[MAX_MCO];
- int n;
-
- (void)utfc_ptr2char(oldp + col, cc);
- if (cc[0] != NUL) {
- /* Find the last composing char, there can be several. */
- n = col;
- do {
- col = n;
- count = utf_ptr2len(oldp + n);
- n += count;
- } while (UTF_COMPOSINGLIKE(oldp + col, oldp + n));
- fixpos = false;
- }
- }
-
- // When count is too big, reduce it.
- 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,
- * unless "restart_edit" is set or 'virtualedit' contains "onemore".
- */
- if (col > 0 && fixpos && restart_edit == 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);
- }
- count = oldlen - col;
- movelen = 1;
- }
-
- // If the old line has been allocated the deletion can be done in the
- // existing line. Otherwise a new line has to be allocated.
- bool was_alloced = ml_line_alloced(); // check if oldp was allocated
- char_u *newp;
- if (was_alloced) {
- newp = oldp; // use same allocated memory
- } else { // need to allocate a new line
- newp = xmalloc((size_t)(oldlen + 1 - count));
- memmove(newp, oldp, (size_t)col);
- }
- memmove(newp + col, oldp + col + count, (size_t)movelen);
- if (!was_alloced) {
- ml_replace(lnum, newp, false);
- }
-
- /* mark the buffer as changed and prepare for displaying */
- changed_bytes(lnum, curwin->w_cursor.col);
-
- return OK;
-}
-
-/*
- * Delete from cursor to end of line.
- * Caller must have prepared for undo.
- */
-void
-truncate_line (
- int fixpos /* if TRUE fix the cursor position when done */
-)
-{
- char_u *newp;
- linenr_T lnum = curwin->w_cursor.lnum;
- colnr_T col = curwin->w_cursor.col;
-
- if (col == 0) {
- newp = vim_strsave((char_u *)"");
- } else {
- newp = vim_strnsave(ml_get(lnum), (size_t)col);
- }
- ml_replace(lnum, newp, false);
-
- /* mark the buffer as changed and prepare for displaying */
- changed_bytes(lnum, curwin->w_cursor.col);
-
- /*
- * If "fixpos" is TRUE we don't want to end up positioned at the NUL.
- */
- if (fixpos && curwin->w_cursor.col > 0)
- --curwin->w_cursor.col;
-}
-
-/*
- * Delete "nlines" lines at the cursor.
- * Saves the lines for undo first if "undo" is TRUE.
- */
-void
-del_lines (
- long nlines, /* number of lines to delete */
- int undo /* if TRUE, prepare for undo */
-)
-{
- long n;
- linenr_T first = curwin->w_cursor.lnum;
-
- if (nlines <= 0)
- return;
-
- /* save the deleted lines for undo */
- if (undo && u_savedel(first, nlines) == FAIL)
- return;
-
- for (n = 0; n < nlines; ) {
- if (curbuf->b_ml.ml_flags & ML_EMPTY) /* nothing to delete */
- break;
-
- ml_delete(first, true);
- n++;
-
- /* If we delete the last line in the file, stop */
- if (first > curbuf->b_ml.ml_line_count)
- break;
- }
-
- /* Correct the cursor position before calling deleted_lines_mark(), it may
- * trigger a callback to display the cursor. */
- curwin->w_cursor.col = 0;
- check_cursor_lnum();
-
- /* adjust marks, mark the buffer as changed and prepare for displaying */
- deleted_lines_mark(first, n);
-}
-
int gchar_pos(pos_T *pos)
+ FUNC_ATTR_NONNULL_ARG(1)
{
// When searching columns is sometimes put at the end of a line.
if (pos->col == MAXCOL) {
@@ -1774,430 +518,6 @@ int gchar_pos(pos_T *pos)
}
/*
- * Call this function when something in the current buffer is changed.
- *
- * Most often called through changed_bytes() and changed_lines(), which also
- * mark the area of the display to be redrawn.
- *
- * Careful: may trigger autocommands that reload the buffer.
- */
-void changed(void)
-{
-
- if (!curbuf->b_changed) {
- int save_msg_scroll = msg_scroll;
-
- /* Give a warning about changing a read-only file. This may also
- * check-out the file, thus change "curbuf"! */
- change_warning(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;
-
- need_wait_return = false;
- ml_open_file(curbuf);
-
- /* The ml_open_file() can cause an ATTENTION message.
- * Wait two seconds, to make sure the user reads this unexpected
- * message. Since we could be anywhere, call wait_return() now,
- * and don't let the emsg() set msg_scroll. */
- if (need_wait_return && emsg_silent == 0) {
- ui_flush();
- os_delay(2000L, true);
- wait_return(TRUE);
- msg_scroll = save_msg_scroll;
- } else {
- need_wait_return = save_need_wait_return;
- }
- }
- changed_int();
- }
- buf_inc_changedtick(curbuf);
-
- // If a pattern is highlighted, the position may now be invalid.
- highlight_match = false;
-}
-
-/*
- * Internal part of changed(), no user interaction.
- */
-void changed_int(void)
-{
- curbuf->b_changed = true;
- ml_setflags(curbuf);
- check_status(curbuf);
- redraw_tabline = TRUE;
- need_maketitle = TRUE; /* set window title later */
-}
-
-
-/*
- * Changed bytes within a single line for the current buffer.
- * - marks the windows on this buffer to be redisplayed
- * - marks the buffer changed by calling changed()
- * - invalidates cached values
- * Careful: may trigger autocommands that reload the buffer.
- */
-void changed_bytes(linenr_T lnum, colnr_T col)
-{
- changedOneline(curbuf, lnum);
- changed_common(lnum, col, lnum + 1, 0L);
- // notify any channels that are watching
- buf_updates_send_changes(curbuf, lnum, 1, 1, true);
-
- /* Diff highlighting in other diff windows may need to be updated too. */
- if (curwin->w_p_diff) {
- linenr_T wlnum;
-
- FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- if (wp->w_p_diff && wp != curwin) {
- redraw_win_later(wp, VALID);
- wlnum = diff_lnum_win(lnum, wp);
- if (wlnum > 0)
- changedOneline(wp->w_buffer, wlnum);
- }
- }
- }
-}
-
-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;
- else if (lnum >= buf->b_mod_bot)
- buf->b_mod_bot = lnum + 1;
- } else {
- /* set the area that must be redisplayed to one line */
- buf->b_mod_set = true;
- buf->b_mod_top = lnum;
- buf->b_mod_bot = lnum + 1;
- buf->b_mod_xlines = 0;
- }
-}
-
-/*
- * Appended "count" lines below line "lnum" in the current buffer.
- * Must be called AFTER the change and after mark_adjust().
- * Takes care of marking the buffer to be redrawn and sets the changed flag.
- */
-void appended_lines(linenr_T lnum, long count)
-{
- changed_lines(lnum + 1, 0, lnum + 1, count, true);
-}
-
-/*
- * Like appended_lines(), but adjust marks first.
- */
-void appended_lines_mark(linenr_T lnum, long count)
-{
- // Skip mark_adjust when adding a line after the last one, there can't
- // be marks there. But it's still needed in diff mode.
- if (lnum + count < curbuf->b_ml.ml_line_count || curwin->w_p_diff) {
- mark_adjust(lnum + 1, (linenr_T)MAXLNUM, count, 0L, false);
- }
- changed_lines(lnum + 1, 0, lnum + 1, count, true);
-}
-
-/*
- * Deleted "count" lines at line "lnum" in the current buffer.
- * Must be called AFTER the change and after mark_adjust().
- * Takes care of marking the buffer to be redrawn and sets the changed flag.
- */
-void deleted_lines(linenr_T lnum, long count)
-{
- changed_lines(lnum, 0, lnum + count, -count, true);
-}
-
-/*
- * Like deleted_lines(), but adjust marks first.
- * Make sure the cursor is on a valid line before calling, a GUI callback may
- * be triggered to display the cursor.
- */
-void deleted_lines_mark(linenr_T lnum, long count)
-{
- mark_adjust(lnum, (linenr_T)(lnum + count - 1), (long)MAXLNUM, -count, false);
- changed_lines(lnum, 0, lnum + count, -count, true);
-}
-
-/*
- * Changed lines for the current buffer.
- * Must be called AFTER the change and after mark_adjust().
- * - mark the buffer changed by calling changed()
- * - mark the windows on this buffer to be redisplayed
- * - invalidate cached values
- * "lnum" is the first line that needs displaying, "lnume" the first line
- * below the changed lines (BEFORE the change).
- * 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.
-)
-{
- changed_lines_buf(curbuf, lnum, lnume, xtra);
-
- if (xtra == 0 && curwin->w_p_diff && !diff_internal()) {
- // When the number of lines doesn't change then mark_adjust() isn't
- // called and other diff buffers still need to be marked for
- // displaying.
- linenr_T wlnum;
-
- FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- if (wp->w_p_diff && wp != curwin) {
- redraw_win_later(wp, VALID);
- wlnum = diff_lnum_win(lnum, wp);
- if (wlnum > 0) {
- changed_lines_buf(wp->w_buffer, wlnum,
- lnume - lnum + wlnum, 0L);
- }
- }
- }
- }
-
- changed_common(lnum, col, lnume, xtra);
-
- if (do_buf_event) {
- int64_t num_added = (int64_t)(lnume + xtra - lnum);
- int64_t num_removed = lnume - lnum;
- buf_updates_send_changes(curbuf, lnum, num_added, num_removed, true);
- }
-}
-
-/// Mark line range in buffer as changed.
-///
-/// @param buf the buffer where lines were changed
-/// @param lnum first line with change
-/// @param lnume line below last changed line
-/// @param xtra number of extra lines (negative when deleting)
-void changed_lines_buf(buf_T *buf, linenr_T lnum, linenr_T lnume, long xtra)
-{
- if (buf->b_mod_set) {
- /* find the maximum area that must be redisplayed */
- if (lnum < buf->b_mod_top)
- buf->b_mod_top = lnum;
- if (lnum < buf->b_mod_bot) {
- /* adjust old bot position for xtra lines */
- buf->b_mod_bot += xtra;
- if (buf->b_mod_bot < lnum)
- buf->b_mod_bot = lnum;
- }
- if (lnume + xtra > buf->b_mod_bot)
- buf->b_mod_bot = lnume + xtra;
- buf->b_mod_xlines += xtra;
- } else {
- /* set the area that must be redisplayed */
- buf->b_mod_set = true;
- buf->b_mod_top = lnum;
- buf->b_mod_bot = lnume + xtra;
- buf->b_mod_xlines = xtra;
- }
-}
-
-/*
- * Common code for when a change is 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)
-{
- int i;
- int cols;
- pos_T *p;
- int add;
-
- /* mark the buffer as modified */
- changed();
-
- if (curwin->w_p_diff && diff_internal()) {
- curtab->tp_diff_update = true;
- }
-
- /* set the '. mark */
- if (!cmdmod.keepjumps) {
- RESET_FMARK(&curbuf->b_last_change, ((pos_T) {lnum, col, 0}), 0);
-
- /* Create a new entry if a new undo-able change was started or we
- * don't have an entry yet. */
- if (curbuf->b_new_change || curbuf->b_changelistlen == 0) {
- if (curbuf->b_changelistlen == 0)
- 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;
- else {
- cols = comp_textwidth(FALSE);
- if (cols == 0)
- cols = 79;
- add = (p->col + cols < col || col + cols < p->col);
- }
- }
- if (add) {
- /* This is the first of a new sequence of undo-able changes
- * and it's at some distance of the last change. Use a new
- * position in the changelist. */
- curbuf->b_new_change = false;
-
- if (curbuf->b_changelistlen == JUMPLISTSIZE) {
- /* changelist is full: remove oldest entry */
- curbuf->b_changelistlen = JUMPLISTSIZE - 1;
- memmove(curbuf->b_changelist, curbuf->b_changelist + 1,
- sizeof(curbuf->b_changelist[0]) * (JUMPLISTSIZE - 1));
- FOR_ALL_TAB_WINDOWS(tp, wp) {
- /* Correct position in changelist for other windows on
- * this buffer. */
- if (wp->w_buffer == curbuf && wp->w_changelistidx > 0) {
- --wp->w_changelistidx;
- }
- }
- }
- FOR_ALL_TAB_WINDOWS(tp, wp) {
- /* For other windows, if the position in the changelist is
- * at the end it stays at the end. */
- if (wp->w_buffer == curbuf
- && wp->w_changelistidx == curbuf->b_changelistlen) {
- ++wp->w_changelistidx;
- }
- }
- ++curbuf->b_changelistlen;
- }
- }
- curbuf->b_changelist[curbuf->b_changelistlen - 1] =
- curbuf->b_last_change;
- /* The current window is always after the last change, so that "g,"
- * takes you back to it. */
- curwin->w_changelistidx = curbuf->b_changelistlen;
- }
-
- FOR_ALL_TAB_WINDOWS(tp, wp) {
- if (wp->w_buffer == curbuf) {
- /* Mark this window to be redrawn later. */
- if (wp->w_redr_type < VALID)
- wp->w_redr_type = VALID;
-
- /* Check if a change in the buffer has invalidated the cached
- * values for the cursor. */
- /*
- * Update the folds for this window. Can't postpone this, because
- * a following operator might work on the whole fold: ">>dd".
- */
- foldUpdate(wp, lnum, lnume + xtra - 1);
-
- /* The change may cause lines above or below the change to become
- * included in a fold. Set lnum/lnume to the first/last line that
- * might be displayed differently.
- * Set w_cline_folded here as an efficient way to update it when
- * 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;
- folded = hasFoldingWin(wp, lnume, NULL, &lnume, false, NULL);
- if (wp->w_cursor.lnum == lnume)
- wp->w_cline_folded = folded;
-
- /* If the changed line is in a range of previously folded lines,
- * compare with the first line in that range. */
- 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);
- }
-
- if (wp->w_cursor.lnum > lnum)
- changed_line_abv_curs_win(wp);
- else if (wp->w_cursor.lnum == lnum && wp->w_cursor.col >= col)
- changed_cline_bef_curs_win(wp);
- if (wp->w_botline >= lnum) {
- /* Assume that botline doesn't change (inserted lines make
- * other lines scroll down below botline). */
- approximate_botline_win(wp);
- }
-
- /* Check if any w_lines[] entries have become invalid.
- * For entries below the change: Correct the lnums for
- * inserted/deleted lines. Makes it possible to stop displaying
- * after the change. */
- for (i = 0; i < wp->w_lines_valid; ++i)
- if (wp->w_lines[i].wl_valid) {
- if (wp->w_lines[i].wl_lnum >= lnum) {
- if (wp->w_lines[i].wl_lnum < lnume) {
- /* line included in change */
- wp->w_lines[i].wl_valid = FALSE;
- } else if (xtra != 0) {
- /* line below change */
- wp->w_lines[i].wl_lnum += xtra;
- wp->w_lines[i].wl_lastlnum += xtra;
- }
- } else if (wp->w_lines[i].wl_lastlnum >= lnum) {
- /* change somewhere inside this range of folded lines,
- * may need to be redrawn */
- wp->w_lines[i].wl_valid = FALSE;
- }
- }
-
- /* Take care of side effects for setting w_topline when folds have
- * changed. Esp. when the buffer was changed in another window. */
- if (hasAnyFolding(wp))
- set_topline(wp, wp->w_topline);
-
- // relative numbering may require updating more
- if (wp->w_p_rnu) {
- redraw_win_later(wp, SOME_VALID);
- }
- }
- }
-
- /* Call update_screen() later, which checks out what needs to be redrawn,
- * since it notices b_mod_set and then uses b_mod_*. */
- if (must_redraw < VALID)
- must_redraw = VALID;
-
- /* when the cursor line is changed always trigger CursorMoved */
- if (lnum <= curwin->w_cursor.lnum
- && lnume + (xtra < 0 ? -xtra : xtra) > curwin->w_cursor.lnum)
- curwin->w_last_cursormoved.lnum = 0;
-}
-
-/*
- * unchanged() is called when the changed flag must be reset for buffer 'buf'
- */
-void
-unchanged (
- buf_T *buf,
- int ff /* also reset 'fileformat' */
-)
-{
- if (buf->b_changed || (ff && file_ff_differs(buf, false))) {
- buf->b_changed = false;
- ml_setflags(buf);
- if (ff)
- save_file_ff(buf);
- check_status(buf);
- redraw_tabline = TRUE;
- need_maketitle = TRUE; /* set window title later */
- }
- buf_inc_changedtick(buf);
-}
-
-/*
* check_status: called when the status bars for the buffer 'buf'
* need to be updated
*/
@@ -2213,55 +533,6 @@ void check_status(buf_T *buf)
}
}
-/*
- * If the file is readonly, give a warning message with the first change.
- * Don't do this for autocommands.
- * Don't use emsg(), because it flushes the macro buffer.
- * If we have undone all changes b_changed will be false, but "b_did_warn"
- * will be true.
- * Careful: may trigger autocommands that reload the buffer.
- */
-void
-change_warning (
- int col /* column for message; non-zero when in insert
- mode and 'showmode' is on */
-)
-{
- static char *w_readonly = N_("W10: Warning: Changing a readonly file");
-
- if (curbuf->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;
- /*
- * 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_source(HL_ATTR(HLF_W));
- msg_ext_set_kind("wmsg");
- MSG_PUTS_ATTR(_(w_readonly), HL_ATTR(HLF_W) | MSG_HIST);
- set_vim_var_string(VV_WARNINGMSG, _(w_readonly), -1);
- msg_clr_eos();
- (void)msg_end();
- if (msg_silent == 0 && !silent_mode && ui_active()) {
- ui_flush();
- os_delay(1000L, true); /* give the user time to think about it */
- }
- curbuf->b_did_warn = true;
- redraw_cmdline = FALSE; /* don't redraw and erase the message */
- if (msg_row < Rows - 1)
- showmode();
- }
-}
-
/// Ask for a reply from the user, 'y' or 'n'
///
/// No other characters are accepted, the message is repeated until a valid
@@ -2503,18 +774,24 @@ int prompt_for_number(int *mouse_used)
cmdline_row = 0;
save_State = State;
State = ASKMORE; // prevents a screen update when using a timer
+ // May show different mouse shape.
+ setmouse();
i = get_number(TRUE, mouse_used);
if (KeyTyped) {
- /* don't call wait_return() now */
- /* msg_putchar('\n'); */
- cmdline_row = msg_row - 1;
- need_wait_return = FALSE;
- msg_didany = FALSE;
- msg_didout = FALSE;
- } else
+ // don't call wait_return() now
+ if (msg_row > 0) {
+ cmdline_row = msg_row - 1;
+ }
+ need_wait_return = false;
+ msg_didany = false;
+ msg_didout = false;
+ } else {
cmdline_row = save_cmdline_row;
+ }
State = save_State;
+ // May need to restore mouse shape.
+ setmouse();
return i;
}
@@ -2720,7 +997,7 @@ void preserve_exit(void)
*/
#ifndef BREAKCHECK_SKIP
-# define BREAKCHECK_SKIP 32
+# define BREAKCHECK_SKIP 1000
#endif
static int breakcheck_count = 0;
@@ -2821,7 +1098,7 @@ char_u *get_cmd_output(char_u *cmd, char_u *infile, ShellOpts flags,
xfree(command);
// read the names from the file into memory
- FILE *fd = mch_fopen((char *)tempname, READBIN);
+ FILE *fd = os_fopen((char *)tempname, READBIN);
if (fd == NULL) {
EMSG2(_(e_notopen), tempname);
diff --git a/src/nvim/move.c b/src/nvim/move.c
index e076543614..4a87f82eb7 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -103,7 +103,8 @@ void reset_cursorline(void)
}
// Redraw when w_cline_row changes and 'relativenumber' or 'cursorline' is set.
-static void redraw_for_cursorline(win_T *wp)
+void redraw_for_cursorline(win_T *wp)
+ FUNC_ATTR_NONNULL_ALL
{
if ((wp->w_p_rnu || win_cursorline_standout(wp))
&& (wp->w_valid & VALID_CROW) == 0
@@ -119,11 +120,9 @@ static void redraw_for_cursorline(win_T *wp)
// the current window.
redrawWinline(wp, wp->w_last_cursorline);
redrawWinline(wp, wp->w_cursor.lnum);
- redraw_win_later(wp, VALID);
} else {
redraw_win_later(wp, SOME_VALID);
}
- wp->w_last_cursorline = wp->w_cursor.lnum;
}
}
}
@@ -847,11 +846,11 @@ void curs_columns(
prev_skipcol = curwin->w_skipcol;
- int p_lines = 0;
+ int plines = 0;
if ((curwin->w_wrow >= curwin->w_height_inner
|| ((prev_skipcol > 0
|| curwin->w_wrow + p_so >= curwin->w_height_inner)
- && (p_lines =
+ && (plines =
plines_win_nofill(curwin, curwin->w_cursor.lnum, false)) - 1
>= curwin->w_height_inner))
&& curwin->w_height_inner != 0
@@ -870,20 +869,21 @@ void curs_columns(
extra = 1;
/* Compute last display line of the buffer line that we want at the
* bottom of the window. */
- if (p_lines == 0)
- p_lines = plines_win(curwin, curwin->w_cursor.lnum, false);
- --p_lines;
- if (p_lines > curwin->w_wrow + p_so) {
+ if (plines == 0) {
+ plines = plines_win(curwin, curwin->w_cursor.lnum, false);
+ }
+ plines--;
+ if (plines > curwin->w_wrow + p_so) {
assert(p_so <= INT_MAX);
n = curwin->w_wrow + (int)p_so;
+ } else {
+ n = plines;
}
- else
- n = p_lines;
if ((colnr_T)n >= curwin->w_height_inner + curwin->w_skipcol / width) {
extra += 2;
}
- if (extra == 3 || p_lines < p_so * 2) {
+ if (extra == 3 || plines < p_so * 2) {
// not enough room for 'scrolloff', put cursor in the middle
n = curwin->w_virtcol / width;
if (n > curwin->w_height_inner / 2) {
@@ -892,8 +892,8 @@ void curs_columns(
n = 0;
}
// don't skip more than necessary
- if (n > p_lines - curwin->w_height_inner + 1) {
- n = p_lines - curwin->w_height_inner + 1;
+ if (n > plines - curwin->w_height_inner + 1) {
+ n = plines - curwin->w_height_inner + 1;
}
curwin->w_skipcol = n * width;
} else if (extra == 1) {
@@ -1245,12 +1245,12 @@ static void botline_forw(lineoff_T *lp)
} else {
++lp->lnum;
lp->fill = 0;
- if (lp->lnum > curbuf->b_ml.ml_line_count)
+ if (lp->lnum > curbuf->b_ml.ml_line_count) {
lp->height = MAXCOL;
- else if (hasFolding(lp->lnum, NULL, &lp->lnum))
- /* Add a closed fold */
+ } else if (hasFolding(lp->lnum, NULL, &lp->lnum)) {
+ // Add a closed fold
lp->height = 1;
- else {
+ } else {
lp->height = plines_nofill(lp->lnum);
}
}
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
index c1ad3bd829..81c9f1e3f4 100644
--- a/src/nvim/msgpack_rpc/channel.c
+++ b/src/nvim/msgpack_rpc/channel.c
@@ -344,7 +344,7 @@ static void handle_request(Channel *channel, msgpack_object *request)
evdata->args = args;
evdata->request_id = request_id;
channel_incref(channel);
- if (handler.async) {
+ if (handler.fast) {
bool is_get_mode = handler.fn == handle_nvim_get_mode;
if (is_get_mode && !input_blocking()) {
diff --git a/src/nvim/msgpack_rpc/helpers.c b/src/nvim/msgpack_rpc/helpers.c
index 3f768dcc0c..18b0bf3c16 100644
--- a/src/nvim/msgpack_rpc/helpers.c
+++ b/src/nvim/msgpack_rpc/helpers.c
@@ -384,10 +384,7 @@ void msgpack_rpc_from_object(const Object result, msgpack_packer *const res)
&& kObjectTypeTabpage == kObjectTypeWindow + 1,
"Buffer, window and tabpage enum items are in order");
switch (cur.aobj->type) {
- case kObjectTypeNil: {
- msgpack_pack_nil(res);
- break;
- }
+ 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,
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index af2d24e9db..73841cf449 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -18,6 +18,7 @@
#include "nvim/ascii.h"
#include "nvim/normal.h"
#include "nvim/buffer.h"
+#include "nvim/change.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
#include "nvim/diff.h"
@@ -1376,9 +1377,8 @@ static void set_vcount_ca(cmdarg_T *cap, bool *set_prevcount)
*set_prevcount = false; /* only set v:prevcount once */
}
-/*
- * Handle an operator after visual mode or when the movement is finished
- */
+// 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;
@@ -1402,8 +1402,12 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
* If an operation is pending, handle it...
*/
if ((finish_op
- || VIsual_active
- ) && oap->op_type != OP_NOP) {
+ || VIsual_active)
+ && oap->op_type != OP_NOP) {
+ // Yank can be redone when 'y' is in 'cpoptions', but not when yanking
+ // for the clipboard.
+ const bool redo_yank = vim_strchr(p_cpo, CPO_YANK) != NULL && !gui_yank;
+
// Avoid a problem with unwanted linebreaks in block mode
if (curwin->w_p_lbr) {
curwin->w_valid &= ~VALID_VIRTCOL;
@@ -1433,9 +1437,9 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
VIsual_reselect = false;
}
- /* Only redo yank when 'y' flag is in 'cpoptions'. */
- /* Never redo "zf" (define fold). */
- if ((vim_strchr(p_cpo, CPO_YANK) != NULL || oap->op_type != OP_YANK)
+ // Only redo yank when 'y' flag is in 'cpoptions'.
+ // Never redo "zf" (define fold).
+ if ((redo_yank || oap->op_type != OP_YANK)
&& ((!VIsual_active || oap->motion_force)
// Also redo Operator-pending Visual mode mappings.
|| (cap->cmdchar == ':' && oap->op_type != OP_COLON))
@@ -1608,8 +1612,8 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
resel_VIsual_line_count = oap->line_count;
}
- /* can't redo yank (unless 'y' is in 'cpoptions') and ":" */
- if ((vim_strchr(p_cpo, CPO_YANK) != NULL || oap->op_type != OP_YANK)
+ // can't redo yank (unless 'y' is in 'cpoptions') and ":"
+ if ((redo_yank || oap->op_type != OP_YANK)
&& oap->op_type != OP_COLON
&& oap->op_type != OP_FOLD
&& oap->op_type != OP_FOLDOPEN
@@ -1814,7 +1818,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
}
} else {
curwin->w_p_lbr = lbr_saved;
- (void)op_yank(oap, !gui_yank);
+ (void)op_yank(oap, !gui_yank, false);
}
check_cursor_col();
break;
@@ -2093,13 +2097,15 @@ static void op_function(oparg_T *oap)
decl(&curbuf->b_op_end);
}
- const char_u *const argv[1] = {
- (const char_u *)(((const char *const[]) {
+ typval_T argv[2];
+ argv[0].v_type = VAR_STRING;
+ 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]),
- };
+ })[oap->motion_type]);
// Reset virtual_op so that 'virtualedit' can be changed in the
// function.
@@ -3386,8 +3392,8 @@ bool add_to_showcmd(int c)
void add_to_showcmd_c(int c)
{
- if (!add_to_showcmd(c))
- setcursor();
+ add_to_showcmd(c);
+ setcursor();
}
/*
@@ -3448,18 +3454,18 @@ static void display_showcmd(void)
return;
}
+ int showcmd_row = Rows - 1;
+ grid_puts_line_start(&default_grid, showcmd_row);
+
if (!showcmd_is_clear) {
- grid_puts(&default_grid, showcmd_buf, (int)Rows - 1, sc_col, 0);
+ grid_puts(&default_grid, showcmd_buf, showcmd_row, sc_col, 0);
}
- /*
- * clear the rest of an old message by outputting up to SHOWCMD_COLS
- * spaces
- */
- grid_puts(&default_grid, (char_u *)" " + len, (int)Rows - 1,
+ // clear the rest of an old message by outputting up to SHOWCMD_COLS spaces
+ grid_puts(&default_grid, (char_u *)" " + len, showcmd_row,
sc_col + len, 0);
- setcursor(); /* put cursor back where it belongs */
+ grid_puts_line_flush(false);
}
/*
@@ -4035,6 +4041,9 @@ static void nv_mousescroll(cmdarg_T *cap)
} else {
mouse_scroll_horiz(cap->arg);
}
+ if (curwin != old_curwin && curwin->w_p_cul) {
+ redraw_for_cursorline(curwin);
+ }
curwin->w_redr_status = true;
@@ -5227,12 +5236,8 @@ static void nv_down(cmdarg_T *cap)
cap->arg = FORWARD;
nv_page(cap);
} else if (bt_quickfix(curbuf) && cap->cmdchar == CAR) {
- // In a quickfix window a <CR> jumps to the error under the cursor.
- if (curwin->w_llist_ref == NULL) {
- do_cmdline_cmd(".cc"); // quickfix window
- } else {
- do_cmdline_cmd(".ll"); // location list window
- }
+ // Quickfix window only: view the result under the cursor.
+ qf_view_result(false);
} else {
// In the cmdline window a <CR> executes the command.
if (cmdwin_type != 0 && cap->cmdchar == CAR) {
@@ -7463,8 +7468,12 @@ static void nv_esc(cmdarg_T *cap)
&& cmdwin_type == 0
&& !VIsual_active
&& no_reason) {
- MSG(_("Type :qa! and press <Enter> to abandon all changes"
- " and exit Nvim"));
+ if (anyBufIsChanged()) {
+ MSG(_("Type :qa! and press <Enter> to abandon all changes"
+ " and exit Nvim"));
+ } else {
+ MSG(_("Type :qa and press <Enter> to exit Nvim"));
+ }
}
/* Don't reset "restart_edit" when 'insertmode' is set, it won't be
@@ -7987,8 +7996,8 @@ static void nv_event(cmdarg_T *cap)
multiqueue_process_events(main_loop.events);
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 allow to trigger :startinsert
+ // 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
}
}
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 2a3b7beb8e..4f1709bb1f 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -15,6 +15,7 @@
#include "nvim/ascii.h"
#include "nvim/ops.h"
#include "nvim/buffer.h"
+#include "nvim/change.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
#include "nvim/assert.h"
@@ -379,8 +380,10 @@ static void shift_block(oparg_T *oap, int amount)
/* if we're splitting a TAB, allow for it */
bd.textcol -= bd.pre_whitesp_c - (bd.startspaces != 0);
const int len = (int)STRLEN(bd.textstart) + 1;
- newp = (char_u *)xmalloc((size_t)(bd.textcol + i + j + len));
- memset(newp, NUL, (size_t)(bd.textcol + i + j + len));
+ int col = bd.textcol + i +j + len;
+ assert(col >= 0);
+ newp = (char_u *)xmalloc((size_t)col);
+ memset(newp, NUL, (size_t)col);
memmove(newp, oldp, (size_t)bd.textcol);
memset(newp + bd.textcol, TAB, (size_t)i);
memset(newp + bd.textcol + i, ' ', (size_t)j);
@@ -1398,9 +1401,11 @@ int op_delete(oparg_T *oap)
*/
if (oap->regname != '_') {
yankreg_T *reg = NULL;
+ int did_yank = false;
if (oap->regname != 0) {
- //yank without message
- if (!op_yank(oap, false)) {
+ // yank without message
+ did_yank = op_yank(oap, false, true);
+ if (!did_yank) {
// op_yank failed, don't do anything
return OK;
}
@@ -1421,6 +1426,7 @@ int op_delete(oparg_T *oap)
y_regs[1].y_array = NULL; // set register "1 to empty
reg = &y_regs[1];
op_yank_reg(oap, false, reg, false);
+ did_yank = true;
}
/* Yank into small delete register when no named register specified
@@ -1429,13 +1435,14 @@ int op_delete(oparg_T *oap)
&& oap->line_count == 1) {
reg = get_yank_register('-', YREG_YANK);
op_yank_reg(oap, false, reg, false);
+ did_yank = true;
}
- if (oap->regname == 0) {
+ if (did_yank || oap->regname == 0) {
if (reg == NULL) {
abort();
}
- set_clipboard(0, reg);
+ set_clipboard(oap->regname, reg);
do_autocmd_textyankpost(oap, reg);
}
@@ -1471,7 +1478,8 @@ int op_delete(oparg_T *oap)
// copy up to deleted part
memmove(newp, oldp, (size_t)bd.textcol);
// insert spaces
- memset(newp + bd.textcol, ' ', (size_t)(bd.startspaces + bd.endspaces));
+ memset(newp + bd.textcol, ' ', (size_t)bd.startspaces +
+ (size_t)bd.endspaces);
// copy the part after the deleted part
oldp += bd.textcol + bd.textlen;
STRMOVE(newp + bd.textcol + bd.startspaces + bd.endspaces, oldp);
@@ -1638,12 +1646,25 @@ static void mb_adjust_opend(oparg_T *oap)
/*
* Put character 'c' at position 'lp'
*/
-static inline void pchar(pos_T lp, int c)
+static inline void pbyte(pos_T lp, int c)
{
assert(c <= UCHAR_MAX);
*(ml_get_buf(curbuf, lp.lnum, true) + lp.col) = (char_u)c;
}
+// Replace the character under the cursor with "c".
+// This takes care of multi-byte characters.
+static void replace_character(int c)
+{
+ const int n = State;
+
+ State = REPLACE;
+ ins_char(c);
+ State = n;
+ // Backup to the replaced character.
+ dec_cursor();
+}
+
/*
* Replace a whole area with one character.
*/
@@ -1730,7 +1751,7 @@ int op_replace(oparg_T *oap, int c)
oldp = get_cursor_line_ptr();
oldlen = (int)STRLEN(oldp);
- size_t newp_size = (size_t)(bd.textcol + bd.startspaces);
+ size_t newp_size = (size_t)bd.textcol + (size_t)bd.startspaces;
if (had_ctrl_v_cr || (c != '\r' && c != '\n')) {
newp_size += (size_t)numc;
if (!bd.is_short) {
@@ -1747,6 +1768,8 @@ int op_replace(oparg_T *oap, int c)
// insert replacement chars CHECK FOR ALLOCATED SPACE
// REPLACE_CR_NCHAR/REPLACE_NL_NCHAR is used for entering CR literally.
size_t after_p_len = 0;
+ int col = oldlen - bd.textcol - bd.textlen + 1;
+ assert(col >= 0);
if (had_ctrl_v_cr || (c != '\r' && c != '\n')) {
// strlen(newp) at this point
int newp_len = bd.textcol + bd.startspaces;
@@ -1758,12 +1781,11 @@ int op_replace(oparg_T *oap, int c)
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)(oldlen - bd.textcol - bd.textlen + 1));
+ memmove(newp + newp_len, oldp, (size_t)col);
}
} else {
// Replacing with \r or \n means splitting the line.
- after_p_len = (size_t)(oldlen - bd.textcol - bd.textlen + 1);
+ after_p_len = (size_t)col;
after_p = (char_u *)xmalloc(after_p_len);
memmove(after_p, oldp, after_p_len);
}
@@ -1795,12 +1817,7 @@ int op_replace(oparg_T *oap, int c)
* with a multi-byte and the other way around. */
if (curwin->w_cursor.lnum == oap->end.lnum)
oap->end.col += (*mb_char2len)(c) - (*mb_char2len)(n);
- n = State;
- State = REPLACE;
- ins_char(c);
- State = n;
- /* Backup to the replaced character. */
- dec_cursor();
+ replace_character(c);
} else {
if (n == TAB) {
int end_vcol = 0;
@@ -1815,7 +1832,7 @@ int op_replace(oparg_T *oap, int c)
if (curwin->w_cursor.lnum == oap->end.lnum)
getvpos(&oap->end, end_vcol);
}
- pchar(curwin->w_cursor, c);
+ pbyte(curwin->w_cursor, c);
}
} else if (virtual_op && curwin->w_cursor.lnum == oap->end.lnum) {
int virtcols = oap->end.coladd;
@@ -1830,9 +1847,14 @@ int op_replace(oparg_T *oap, int c)
coladvance_force(getviscol2(oap->end.col, oap->end.coladd) + 1);
curwin->w_cursor.col -= (virtcols + 1);
for (; virtcols >= 0; virtcols--) {
- pchar(curwin->w_cursor, c);
- if (inc(&curwin->w_cursor) == -1)
+ if (utf_char2len(c) > 1) {
+ replace_character(c);
+ } else {
+ pbyte(curwin->w_cursor, c);
+ }
+ if (inc(&curwin->w_cursor) == -1) {
break;
+ }
}
}
@@ -1953,23 +1975,20 @@ static int swapchars(int op_type, pos_T *pos, int length)
return did_change;
}
-/*
- * If op_type == OP_UPPER: make uppercase,
- * if op_type == OP_LOWER: make lowercase,
- * if op_type == OP_ROT13: do rot13 encoding,
- * else swap case of character at 'pos'
- * returns TRUE when something actually changed.
- */
-int swapchar(int op_type, pos_T *pos)
+// If op_type == OP_UPPER: make uppercase,
+// if op_type == OP_LOWER: make lowercase,
+// if op_type == OP_ROT13: do rot13 encoding,
+// else swap case of character at 'pos'
+// returns true when something actually changed.
+bool swapchar(int op_type, pos_T *pos)
+ FUNC_ATTR_NONNULL_ARG(2)
{
- int c;
- int nc;
-
- c = gchar_pos(pos);
+ const int c = gchar_pos(pos);
- /* Only do rot13 encoding for ASCII characters. */
- if (c >= 0x80 && op_type == OP_ROT13)
- return FALSE;
+ // Only do rot13 encoding for ASCII characters.
+ if (c >= 0x80 && op_type == OP_ROT13) {
+ return false;
+ }
if (op_type == OP_UPPER && c == 0xdf) {
pos_T sp = curwin->w_cursor;
@@ -1983,7 +2002,7 @@ int swapchar(int op_type, pos_T *pos)
inc(pos);
}
- nc = c;
+ int nc = c;
if (mb_islower(c)) {
if (op_type == OP_ROT13) {
nc = ROT13(c, 'a');
@@ -1998,7 +2017,7 @@ int swapchar(int op_type, pos_T *pos)
}
}
if (nc != c) {
- if (enc_utf8 && (c >= 0x80 || nc >= 0x80)) {
+ if (c >= 0x80 || nc >= 0x80) {
pos_T sp = curwin->w_cursor;
curwin->w_cursor = *pos;
@@ -2006,11 +2025,12 @@ int swapchar(int op_type, pos_T *pos)
del_bytes(utf_ptr2len(get_cursor_pos_ptr()), FALSE, FALSE);
ins_char(nc);
curwin->w_cursor = sp;
- } else
- pchar(*pos, nc);
- return TRUE;
+ } else {
+ pbyte(*pos, nc);
+ }
+ return true;
}
- return FALSE;
+ return false;
}
/*
@@ -2361,8 +2381,9 @@ void free_register(yankreg_T *reg)
///
/// @param oap operator arguments
/// @param message show message when more than `&report` lines are yanked.
+/// @param deleting whether the function was called from a delete operation.
/// @returns whether the operation register was writable.
-bool op_yank(oparg_T *oap, bool message)
+bool op_yank(oparg_T *oap, bool message, int deleting)
FUNC_ATTR_NONNULL_ALL
{
// check for read-only register
@@ -2376,8 +2397,11 @@ bool op_yank(oparg_T *oap, bool message)
yankreg_T *reg = get_yank_register(oap->regname, YREG_YANK);
op_yank_reg(oap, message, reg, is_append_register(oap->regname));
- set_clipboard(oap->regname, reg);
- do_autocmd_textyankpost(oap, reg);
+ // op_delete will set_clipboard and do_autocmd
+ if (!deleting) {
+ set_clipboard(oap->regname, reg);
+ do_autocmd_textyankpost(oap, reg);
+ }
return true;
}
@@ -2496,9 +2520,9 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
endcol = (colnr_T)STRLEN(p);
if (startcol > endcol
|| is_oneChar
- )
+ ) {
bd.textlen = 0;
- else {
+ } else {
bd.textlen = endcol - startcol + oap->inclusive;
}
bd.textstart = p + startcol;
@@ -2591,8 +2615,9 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
static void yank_copy_line(yankreg_T *reg, struct block_def *bd, size_t y_idx)
{
- char_u *pnew = xmallocz((size_t)(bd->startspaces + bd->endspaces
- + bd->textlen));
+ int size = bd->startspaces + bd->endspaces + bd->textlen;
+ assert(size >= 0);
+ char_u *pnew = xmallocz((size_t)size);
reg->y_array[y_idx] = pnew;
memset(pnew, ' ', (size_t)bd->startspaces);
pnew += bd->startspaces;
@@ -3074,8 +3099,9 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
memset(ptr, ' ', (size_t)bd.endspaces);
ptr += bd.endspaces;
// move the text after the cursor to the end of the line.
- memmove(ptr, oldp + bd.textcol + delcount,
- (size_t)((int)oldlen - bd.textcol - delcount + 1));
+ int columns = (int)oldlen - bd.textcol - delcount + 1;
+ assert(columns >= 0);
+ memmove(ptr, oldp + bd.textcol + delcount, (size_t)columns);
ml_replace(curwin->w_cursor.lnum, newp, false);
++curwin->w_cursor.lnum;
@@ -3198,11 +3224,11 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
xfree(newp);
oldp = ml_get(lnum);
- newp = (char_u *) xmalloc((size_t)(col + yanklen + 1));
- /* copy first part of line */
+ newp = (char_u *)xmalloc((size_t)col + (size_t)yanklen + 1);
+ // copy first part of line
memmove(newp, oldp, (size_t)col);
- /* append to first line */
- memmove(newp + col, y_array[0], (size_t)(yanklen + 1));
+ // append to first line
+ memmove(newp + col, y_array[0], (size_t)yanklen + 1);
ml_replace(lnum, newp, false);
curwin->w_cursor.lnum = lnum;
@@ -3416,13 +3442,13 @@ void ex_display(exarg_T *eap)
msg_putchar(name);
MSG_PUTS(" ");
- int n = (int)Columns - 6;
+ int n = Columns - 6;
for (size_t j = 0; j < yb->y_size && n > 1; j++) {
if (j) {
MSG_PUTS_ATTR("^J", attr);
n -= 2;
}
- for (p = yb->y_array[j]; *p && (n -= ptr2cells(p)) >= 0; ++p) {
+ for (p = yb->y_array[j]; *p && (n -= ptr2cells(p)) >= 0; p++) { // -V1019 NOLINT(whitespace/line_length)
clen = (*mb_ptr2len)(p);
msg_outtrans_len(p, clen);
p += clen - 1;
@@ -3499,8 +3525,8 @@ void ex_display(exarg_T *eap)
* display a string for do_dis()
* truncate at end of screen line
*/
-static void
-dis_msg (
+static void
+dis_msg(
char_u *p,
int skip_esc /* if TRUE, ignore trailing ESC */
)
@@ -3508,7 +3534,7 @@ dis_msg (
int n;
int l;
- n = (int)Columns - 6;
+ n = Columns - 6;
while (*p != NUL
&& !(*p == ESC && skip_esc && *(p + 1) == NUL)
&& (n -= ptr2cells(p)) >= 0) {
@@ -3694,11 +3720,11 @@ int do_join(size_t count,
}
}
- /* store the column position before last line */
+ // store the column position before last line
col = sumsize - currsize - spaces[count - 1];
- /* allocate the space for the new line */
- newp = (char_u *) xmalloc((size_t)(sumsize + 1));
+ // allocate the space for the new line
+ newp = (char_u *)xmalloc((size_t)sumsize + 1);
cend = newp + sumsize;
*cend = 0;
@@ -3738,7 +3764,7 @@ int do_join(size_t count,
if (setmark) {
// Set the '] mark.
curwin->w_buffer->b_op_end.lnum = curwin->w_cursor.lnum;
- curwin->w_buffer->b_op_end.col = (colnr_T)STRLEN(newp);
+ curwin->w_buffer->b_op_end.col = sumsize;
}
/* Only report the change in the first line here, del_lines() will report
@@ -3840,8 +3866,8 @@ static int same_leader(linenr_T lnum, int leader1_len, char_u *leader1_flags, in
/*
* Implementation of the format operator 'gq'.
*/
-void
-op_format (
+void
+op_format(
oparg_T *oap,
int keep_cursor /* keep cursor on same text char */
)
@@ -3920,8 +3946,8 @@ void op_formatexpr(oparg_T *oap)
op_format(oap, FALSE);
}
-int
-fex_format (
+int
+fex_format(
linenr_T lnum,
long count,
int c /* character to be inserted */
@@ -3963,8 +3989,8 @@ fex_format (
* Lines after the cursor line are saved for undo, caller must have saved the
* first line.
*/
-void
-format_lines (
+void
+format_lines(
linenr_T line_count,
int avoid_fex /* don't use 'formatexpr' */
)
@@ -5461,7 +5487,7 @@ void cursor_pos_info(dict_T *dict)
byte_count_cursor = byte_count
+ line_count_info(ml_get(lnum), &word_count_cursor,
&char_count_cursor,
- (varnumber_T)(curwin->w_cursor.col + 1),
+ (varnumber_T)curwin->w_cursor.col + 1,
eol_size);
}
}
@@ -5479,8 +5505,10 @@ void cursor_pos_info(dict_T *dict)
if (l_VIsual_active) {
if (l_VIsual_mode == Ctrl_V && curwin->w_curswant < MAXCOL) {
getvcols(curwin, &min_pos, &max_pos, &min_pos.col, &max_pos.col);
+ int64_t cols;
+ STRICT_SUB(oparg.end_vcol + 1, oparg.start_vcol, &cols, int64_t);
vim_snprintf((char *)buf1, sizeof(buf1), _("%" PRId64 " Cols; "),
- (int64_t)(oparg.end_vcol - oparg.start_vcol + 1));
+ cols);
} else {
buf1[0] = NUL;
}
@@ -5873,33 +5901,45 @@ static inline bool reg_empty(const yankreg_T *const reg)
&& *(reg->y_array[0]) == NUL));
}
-/// Iterate over registerrs
+/// 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)
+ FUNC_ATTR_NONNULL_ARG(2, 3, 4) FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ return op_reg_iter(iter, y_regs, name, reg, is_unnamed);
+}
+
+/// Iterate over registers `regs`.
///
/// @param[in] iter Iterator. Pass NULL to start iteration.
+/// @param[in] regs Registers list to be iterated.
/// @param[out] name Register name.
/// @param[out] reg Register contents.
///
-/// @return Pointer that needs to be passed to next `op_register_iter` call or
+/// @return Pointer that must be passed to next `op_register_iter` call or
/// NULL if iteration is over.
-const void *op_register_iter(const void *const iter, char *const name,
- yankreg_T *const reg, bool *is_unnamed)
- FUNC_ATTR_NONNULL_ARG(2, 3) FUNC_ATTR_WARN_UNUSED_RESULT
+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;
const yankreg_T *iter_reg = (iter == NULL
- ? &(y_regs[0])
- : (const yankreg_T *const) iter);
- while (iter_reg - &(y_regs[0]) < NUM_SAVED_REGISTERS && reg_empty(iter_reg)) {
+ ? &(regs[0])
+ : (const yankreg_T *const)iter);
+ while (iter_reg - &(regs[0]) < NUM_SAVED_REGISTERS && reg_empty(iter_reg)) {
iter_reg++;
}
- if (iter_reg - &(y_regs[0]) == NUM_SAVED_REGISTERS || reg_empty(iter_reg)) {
+ if (iter_reg - &(regs[0]) == NUM_SAVED_REGISTERS || reg_empty(iter_reg)) {
return NULL;
}
- int iter_off = (int)(iter_reg - &(y_regs[0]));
+ int iter_off = (int)(iter_reg - &(regs[0]));
*name = (char)get_register_name(iter_off);
*reg = *iter_reg;
*is_unnamed = (iter_reg == y_previous);
- while (++iter_reg - &(y_regs[0]) < NUM_SAVED_REGISTERS) {
+ while (++iter_reg - &(regs[0]) < NUM_SAVED_REGISTERS) {
if (!reg_empty(iter_reg)) {
return (void *) iter_reg;
}
@@ -5908,7 +5948,7 @@ const void *op_register_iter(const void *const iter, char *const name,
}
/// Get a number of non-empty registers
-size_t op_register_amount(void)
+size_t op_reg_amount(void)
FUNC_ATTR_WARN_UNUSED_RESULT
{
size_t ret = 0;
@@ -5927,7 +5967,7 @@ size_t op_register_amount(void)
/// @param[in] is_unnamed Whether to set the unnamed regiseter to reg
///
/// @return true on success, false on failure.
-bool op_register_set(const char name, const yankreg_T reg, bool is_unnamed)
+bool op_reg_set(const char name, const yankreg_T reg, bool is_unnamed)
{
int i = op_reg_index(name);
if (i == -1) {
@@ -5947,7 +5987,7 @@ bool op_register_set(const char name, const yankreg_T reg, bool is_unnamed)
/// @param[in] name Register name.
///
/// @return Pointer to the register contents or NULL.
-const yankreg_T *op_register_get(const char name)
+const yankreg_T *op_reg_get(const char name)
{
int i = op_reg_index(name);
if (i == -1) {
@@ -5961,7 +6001,7 @@ const yankreg_T *op_register_get(const char name)
/// @param[in] name Register name.
///
/// @return true on success, false on failure.
-bool op_register_set_previous(const char name)
+bool op_reg_set_previous(const char name)
FUNC_ATTR_WARN_UNUSED_RESULT
{
int i = op_reg_index(name);
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 8ff62d5b12..55b69edba0 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -74,6 +74,7 @@
#include "nvim/strings.h"
#include "nvim/syntax.h"
#include "nvim/ui.h"
+#include "nvim/ui_compositor.h"
#include "nvim/undo.h"
#include "nvim/window.h"
#include "nvim/os/os.h"
@@ -253,6 +254,7 @@ typedef struct vimoption {
#define P_RWINONLY 0x10000000U ///< only redraw current window
#define P_NDNAME 0x20000000U ///< only normal dir name chars allowed
#define P_UI_OPTION 0x40000000U ///< send option to remote ui
+#define P_MLE 0x80000000U ///< under control of 'modelineexpr'
#define HIGHLIGHT_INIT \
"8:SpecialKey,~:EndOfBuffer,z:TermCursor,Z:TermCursorNC,@:NonText," \
@@ -626,7 +628,11 @@ void set_init_1(void)
char *p;
# ifdef UNIX
if (*names[n] == NUL) {
+# ifdef __APPLE__
+ p = "/private/tmp";
+# else
p = "/tmp";
+# endif
mustfree = false;
} else
# endif
@@ -1323,6 +1329,11 @@ int do_set(
errmsg = (char_u *)_("E520: Not allowed in a modeline");
goto skip;
}
+ if ((flags & P_MLE) && !p_mle) {
+ errmsg = (char_u *)_(
+ "E992: Not allowed in a modeline when 'modelineexpr' is off");
+ goto skip;
+ }
// In diff mode some options are overruled. This avoids that
// 'foldmethod' becomes "marker" instead of "diff" and that
// "wrap" gets set.
@@ -2166,10 +2177,8 @@ static char_u *option_expand(int opt_idx, char_u *val)
return NameBuff;
}
-/*
- * After setting various option values: recompute variables that depend on
- * option values.
- */
+// After setting various option values: recompute variables that depend on
+// option values.
static void didset_options(void)
{
// initialize the table for 'iskeyword' et.al.
@@ -2182,8 +2191,10 @@ static void didset_options(void)
(void)opt_strings_flags(p_vop, p_ssop_values, &vop_flags, true);
(void)opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, true);
(void)opt_strings_flags(p_dy, p_dy_values, &dy_flags, true);
+ (void)opt_strings_flags(p_rdb, p_rdb_values, &rdb_flags, true);
(void)opt_strings_flags(p_tc, p_tc_values, &tc_flags, false);
(void)opt_strings_flags(p_ve, p_ve_values, &ve_flags, true);
+ (void)opt_strings_flags(p_wop, p_wop_values, &wop_flags, true);
(void)spell_check_msm();
(void)spell_check_sps();
(void)compile_cap_prog(curwin->w_s);
@@ -2640,6 +2651,10 @@ did_set_string_option(
if (opt_strings_flags(p_vop, p_ssop_values, &vop_flags, true) != OK) {
errmsg = e_invarg;
}
+ } else if (varp == &p_rdb) { // 'redrawdebug'
+ if (opt_strings_flags(p_rdb, p_rdb_values, &rdb_flags, true) != OK) {
+ errmsg = e_invarg;
+ }
} else if (varp == &p_sbo) { // 'scrollopt'
if (check_opt_strings(p_sbo, p_scbopt_values, true) != OK) {
errmsg = e_invarg;
@@ -3493,7 +3508,9 @@ static char_u *set_chars_option(win_T *wp, char_u **varp)
{
int round, i, len, entries;
char_u *p, *s;
- int c1 = 0, c2 = 0, c3 = 0;
+ int c1;
+ int c2 = 0;
+ int c3 = 0;
struct chars_tab {
int *cp; ///< char value
@@ -3560,7 +3577,7 @@ static char_u *set_chars_option(win_T *wp, char_u **varp)
if (STRNCMP(p, tab[i].name, len) == 0
&& p[len] == ':'
&& p[len + 1] != NUL) {
- c1 = c2 = c3 = 0;
+ c2 = c3 = 0;
s = p + len + 1;
// TODO(bfredl): use schar_T representation and utfc_ptr2len
@@ -3752,7 +3769,8 @@ static bool parse_winhl_opt(win_T *wp)
size_t nlen = (size_t)(colon-p);
char *hi = colon+1;
char *commap = xstrchrnul(hi, ',');
- int hl_id = syn_check_group((char_u *)hi, (int)(commap-hi));
+ int len = (int)(commap-hi);
+ int hl_id = len ? syn_check_group((char_u *)hi, len) : -1;
if (strncmp("Normal", p, nlen) == 0) {
w_hl_id_normal = hl_id;
@@ -4149,7 +4167,6 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
char_u *errmsg = NULL;
long old_value = *(long *)varp;
long old_Rows = Rows; // remember old Rows
- long old_Columns = Columns; // remember old Columns
long *pp = (long *)varp;
// Disallow changing some options from secure mode.
@@ -4264,7 +4281,7 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
} else if (pp == &curwin->w_p_nuw || pp == &curwin->w_allbuf_opt.wo_nuw) {
if (value < 1) {
errmsg = e_positive;
- } else if (value > 10) {
+ } else if (value > 20) {
errmsg = e_invarg;
}
} else if (pp == &curbuf->b_p_iminsert || pp == &p_iminsert) {
@@ -4381,11 +4398,10 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
}
} else if (pp == &p_pb) {
p_pb = MAX(MIN(p_pb, 100), 0);
- if (old_value != 0) {
- hl_invalidate_blends();
- }
+ hl_invalidate_blends();
+ pum_grid.blending = (p_pb > 0);
if (pum_drawn()) {
- pum_recompose();
+ pum_redraw();
}
} else if (pp == &p_pyx) {
if (p_pyx != 0 && p_pyx != 2 && p_pyx != 3) {
@@ -4408,40 +4424,50 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
}
} else if (pp == &curwin->w_p_nuw) {
curwin->w_nrwidth_line_count = 0;
+ } else if (pp == &curwin->w_p_winbl && value != old_value) {
+ // 'floatblend'
+ curwin->w_p_winbl = MAX(MIN(curwin->w_p_winbl, 100), 0);
+ curwin->w_hl_needs_update = true;
+ curwin->w_grid.blending = curwin->w_p_winbl > 0;
}
// Check the (new) bounds for Rows and Columns here.
- if (Rows < min_rows() && full_screen) {
+ if (p_lines < min_rows() && full_screen) {
if (errbuf != NULL) {
vim_snprintf((char *)errbuf, errbuflen,
_("E593: Need at least %d lines"), min_rows());
errmsg = errbuf;
}
- Rows = min_rows();
+ p_lines = min_rows();
}
- if (Columns < MIN_COLUMNS && full_screen) {
+ if (p_columns < MIN_COLUMNS && full_screen) {
if (errbuf != NULL) {
vim_snprintf((char *)errbuf, errbuflen,
_("E594: Need at least %d columns"), MIN_COLUMNS);
errmsg = errbuf;
}
- Columns = MIN_COLUMNS;
+ p_columns = MIN_COLUMNS;
}
- limit_screen_size();
+ // True max size is defined by check_shellsize()
+ p_lines = MIN(p_lines, INT_MAX);
+ p_columns = MIN(p_columns, INT_MAX);
// If the screen (shell) height has been changed, assume it is the
// physical screenheight.
- if (old_Rows != Rows || old_Columns != Columns) {
+ if (p_lines != Rows || p_columns != Columns) {
// Changing the screen size is not allowed while updating the screen.
if (updating_screen) {
*pp = old_value;
} else if (full_screen) {
- screen_resize((int)Columns, (int)Rows);
+ screen_resize((int)p_columns, (int)p_lines);
} else {
+ // TODO(bfredl): is this branch ever needed?
// Postpone the resizing; check the size and cmdline position for
// messages.
+ Rows = (int)p_lines;
+ Columns = (int)p_columns;
check_shellsize();
if (cmdline_row > Rows - p_ch && Rows > p_ch) {
assert(p_ch >= 0 && Rows - p_ch <= INT_MAX);
@@ -5027,6 +5053,11 @@ showoptions(
// collect the items in items[]
item_count = 0;
for (p = &options[0]; p->fullname != NULL; p++) {
+ // apply :filter /pat/
+ if (message_filtered((char_u *)p->fullname)) {
+ continue;
+ }
+
varp = NULL;
if (opt_flags != 0) {
if (p->indir != PV_NONE) {
@@ -5054,8 +5085,8 @@ showoptions(
* display the items
*/
if (run == 1) {
- assert(Columns <= LONG_MAX - GAP
- && Columns + GAP >= LONG_MIN + 3
+ assert(Columns <= INT_MAX - GAP
+ && Columns + GAP >= INT_MIN + 3
&& (Columns + GAP - 3) / INC >= INT_MIN
&& (Columns + GAP - 3) / INC <= INT_MAX);
cols = (int)((Columns + GAP - 3) / INC);
@@ -5703,6 +5734,7 @@ static char_u *get_varp(vimoption_T *p)
case PV_WINHL: return (char_u *)&(curwin->w_p_winhl);
case PV_FCS: return (char_u *)&(curwin->w_p_fcs);
case PV_LCS: return (char_u *)&(curwin->w_p_lcs);
+ 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!
@@ -5782,6 +5814,7 @@ void copy_winopt(winopt_T *from, winopt_T *to)
to->wo_winhl = vim_strsave(from->wo_winhl);
to->wo_fcs = vim_strsave(from->wo_fcs);
to->wo_lcs = vim_strsave(from->wo_lcs);
+ to->wo_winbl = from->wo_winbl;
check_winopt(to); // don't want NULL pointers
}
@@ -5844,7 +5877,8 @@ void didset_window_options(win_T *wp)
briopt_check(wp);
set_chars_option(wp, &wp->w_p_fcs);
set_chars_option(wp, &wp->w_p_lcs);
- parse_winhl_opt(wp);
+ parse_winhl_opt(wp); // sets w_hl_needs_update also for w_p_winbl
+ wp->w_grid.blending = wp->w_p_winbl > 0;
}
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index a9f44976c9..fa6ebc70e5 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -181,28 +181,29 @@ enum {
0, \
})
-/* characters for p_go: */
-#define GO_ASEL 'a' /* autoselect */
-#define GO_ASELML 'A' /* autoselect modeless selection */
-#define GO_BOT 'b' /* use bottom scrollbar */
-#define GO_CONDIALOG 'c' /* use console dialog */
-#define GO_TABLINE 'e' /* may show tabline */
-#define GO_FORG 'f' /* start GUI in foreground */
-#define GO_GREY 'g' /* use grey menu items */
-#define GO_HORSCROLL 'h' /* flexible horizontal scrolling */
-#define GO_ICON 'i' /* use Vim icon */
-#define GO_LEFT 'l' /* use left scrollbar */
-#define GO_VLEFT 'L' /* left scrollbar with vert split */
-#define GO_MENUS 'm' /* use menu bar */
-#define GO_NOSYSMENU 'M' /* don't source system menu */
-#define GO_POINTER 'p' /* pointer enter/leave callbacks */
-#define GO_ASELPLUS 'P' /* autoselectPlus */
-#define GO_RIGHT 'r' /* use right scrollbar */
-#define GO_VRIGHT 'R' /* right scrollbar with vert split */
-#define GO_TOOLBAR 'T' /* add toolbar */
-#define GO_FOOTER 'F' /* add footer */
-#define GO_VERTICAL 'v' /* arrange dialog buttons vertically */
-#define GO_ALL "aAbcefFghilmMprTv" /* all possible flags for 'go' */
+// characters for p_go:
+#define GO_ASEL 'a' // autoselect
+#define GO_ASELML 'A' // autoselect modeless selection
+#define GO_BOT 'b' // use bottom scrollbar
+#define GO_CONDIALOG 'c' // use console dialog
+#define GO_TABLINE 'e' // may show tabline
+#define GO_FORG 'f' // start GUI in foreground
+#define GO_GREY 'g' // use grey menu items
+#define GO_HORSCROLL 'h' // flexible horizontal scrolling
+#define GO_ICON 'i' // use Vim icon
+#define GO_LEFT 'l' // use left scrollbar
+#define GO_VLEFT 'L' // left scrollbar with vert split
+#define GO_MENUS 'm' // use menu bar
+#define GO_NOSYSMENU 'M' // don't source system menu
+#define GO_POINTER 'p' // pointer enter/leave callbacks
+#define GO_ASELPLUS 'P' // autoselectPlus
+#define GO_RIGHT 'r' // use right scrollbar
+#define GO_VRIGHT 'R' // right scrollbar with vert split
+#define GO_TOOLBAR 'T' // add toolbar
+#define GO_FOOTER 'F' // add footer
+#define GO_VERTICAL 'v' // arrange dialog buttons vertically
+#define GO_KEEPWINSIZE 'k' // keep GUI window size
+#define GO_ALL "aAbcefFghilmMprTvk" // all possible flags for 'go'
/* flags for 'comments' option */
#define COM_NEST 'n' /* comments strings nest */
@@ -365,6 +366,7 @@ static char *(p_cb_values[]) = {"unnamed", "unnamedplus", NULL};
# define CB_UNNAMEDMASK (CB_UNNAMED | CB_UNNAMEDPLUS)
EXTERN long p_cwh; // 'cmdwinheight'
EXTERN long p_ch; // 'cmdheight'
+EXTERN long p_columns; // 'columns'
EXTERN int p_confirm; // 'confirm'
EXTERN int p_cp; // 'compatible'
EXTERN char_u *p_cot; // 'completeopt'
@@ -475,7 +477,8 @@ EXTERN char_u *p_langmap; // 'langmap'
EXTERN int p_lnr; // 'langnoremap'
EXTERN int p_lrm; // 'langremap'
EXTERN char_u *p_lm; // 'langmenu'
-EXTERN long *p_linespace; // 'linespace'
+EXTERN long p_lines; // 'lines'
+EXTERN long p_linespace; // 'linespace'
EXTERN char_u *p_lispwords; // 'lispwords'
EXTERN long p_ls; // 'laststatus'
EXTERN long p_stal; // 'showtabline'
@@ -495,6 +498,7 @@ EXTERN long p_mmd; // 'maxmapdepth'
EXTERN long p_mmp; // 'maxmempattern'
EXTERN long p_mis; // 'menuitems'
EXTERN char_u *p_msm; // 'mkspellmem'
+EXTERN long p_mle; // 'modelineexpr'
EXTERN long p_mls; // 'modelines'
EXTERN char_u *p_mouse; // 'mouse'
EXTERN char_u *p_mousem; // 'mousemodel'
@@ -509,6 +513,13 @@ EXTERN char_u *p_pm; // 'patchmode'
EXTERN char_u *p_path; // 'path'
EXTERN char_u *p_cdpath; // 'cdpath'
EXTERN long p_pyx; // 'pyxversion'
+EXTERN char_u *p_rdb; // 'redrawdebug'
+EXTERN unsigned rdb_flags;
+# ifdef IN_OPTION_C
+static char *(p_rdb_values[]) = { "compositor", NULL };
+# endif
+# define RDB_COMPOSITOR 0x001
+
EXTERN long p_rdt; // 'redrawtime'
EXTERN int p_remap; // 'remap'
EXTERN long p_re; // 'regexpengine'
@@ -814,6 +825,7 @@ enum {
, WV_WINHL
, WV_FCS
, WV_LCS
+ , WV_WINBL
, WV_COUNT // must be the last one
};
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 96e098778c..3280c92b2d 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -8,6 +8,7 @@
-- defaults={condition=nil, if_true={vi=224, vim=0}, 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,
-- alloced=nil,
-- save_pv_indir=nil,
@@ -39,7 +40,7 @@ local imacros=function(s)
return '(intptr_t)' .. s
end
end
-local N_=function(s)
+local N_=function(s) -- luacheck: ignore 211 (currently unused)
return function()
return 'N_(' .. cstr(s) .. ')'
end
@@ -188,7 +189,6 @@ return {
},
{
full_name='belloff', abbreviation='bo',
- deny_duplicates=true,
type='string', list='comma', scope={'global'},
deny_duplicates=true,
vi_def=true,
@@ -283,6 +283,7 @@ return {
deny_duplicates=true,
vi_def=true,
expand=true,
+ secure=true,
varname='p_cdpath',
defaults={if_true={vi=",,"}}
},
@@ -378,10 +379,9 @@ return {
full_name='columns', abbreviation='co',
type='number', scope={'global'},
no_mkrc=true,
- nodefault=true,
vi_def=true,
redraw={'everything'},
- varname='Columns',
+ varname='p_columns',
defaults={if_true={vi=macros('DFLT_COLS')}}
},
{
@@ -543,7 +543,7 @@ return {
full_name='cursorcolumn', abbreviation='cuc',
type='bool', scope={'window'},
vi_def=true,
- redraw={'current_window'},
+ redraw={'current_window_only'},
defaults={if_true={vi=false}}
},
{
@@ -847,6 +847,7 @@ return {
type='string', scope={'window'},
vi_def=true,
vim=true,
+ modelineexpr=true,
alloced=true,
redraw={'current_window'},
defaults={if_true={vi="0"}}
@@ -922,6 +923,7 @@ return {
type='string', scope={'window'},
vi_def=true,
vim=true,
+ modelineexpr=true,
alloced=true,
redraw={'current_window'},
defaults={if_true={vi="foldtext()"}}
@@ -931,6 +933,7 @@ return {
type='string', scope={'buffer'},
vi_def=true,
vim=true,
+ modelineexpr=true,
alloced=true,
varname='p_fex',
defaults={if_true={vi=""}}
@@ -1045,6 +1048,7 @@ return {
full_name='guitablabel', abbreviation='gtl',
type='string', scope={'global'},
vi_def=true,
+ modelineexpr=true,
redraw={'current_window'},
enable_if=false,
},
@@ -1136,6 +1140,7 @@ return {
full_name='iconstring',
type='string', scope={'global'},
vi_def=true,
+ modelineexpr=true,
varname='p_iconstring',
defaults={if_true={vi=""}}
},
@@ -1198,6 +1203,7 @@ return {
full_name='includeexpr', abbreviation='inex',
type='string', scope={'buffer'},
vi_def=true,
+ modelineexpr=true,
alloced=true,
varname='p_inex',
defaults={if_true={vi=""}}
@@ -1214,6 +1220,7 @@ return {
type='string', scope={'buffer'},
vi_def=true,
vim=true,
+ modelineexpr=true,
alloced=true,
varname='p_inde',
defaults={if_true={vi=""}}
@@ -1376,10 +1383,9 @@ return {
full_name='lines',
type='number', scope={'global'},
no_mkrc=true,
- nodefault=true,
vi_def=true,
redraw={'everything'},
- varname='Rows',
+ varname='p_lines',
defaults={if_true={vi=macros('DFLT_ROWS')}}
},
{
@@ -1528,6 +1534,14 @@ return {
defaults={if_true={vi=false, vim=true}}
},
{
+ full_name='modelineexpr', abbreviation='mle',
+ type='bool', scope={'global'},
+ vi_def=true,
+ secure=true,
+ varname='p_mle',
+ defaults={if_true={vi=false}}
+ },
+ {
full_name='modelines', abbreviation='mls',
type='number', scope={'global'},
vi_def=true,
@@ -1832,6 +1846,13 @@ return {
defaults={if_true={vi=false}}
},
{
+ full_name='redrawdebug', abbreviation='rdb',
+ type='string', list='onecomma', scope={'global'},
+ vi_def=true,
+ varname='p_rdb',
+ defaults={if_true={vi=''}}
+ },
+ {
full_name='redrawtime', abbreviation='rdt',
type='number', scope={'global'},
vi_def=true,
@@ -1903,6 +1924,7 @@ return {
type='string', scope={'global'},
vi_def=true,
alloced=true,
+ modelineexpr=true,
redraw={'statuslines'},
varname='p_ruf',
defaults={if_true={vi=""}}
@@ -2310,6 +2332,7 @@ return {
type='string', scope={'global', 'window'},
vi_def=true,
alloced=true,
+ modelineexpr=true,
redraw={'statuslines'},
varname='p_stl',
defaults={if_true={vi=""}}
@@ -2369,6 +2392,7 @@ return {
full_name='tabline', abbreviation='tal',
type='string', scope={'global'},
vi_def=true,
+ modelineexpr=true,
redraw={'all_windows'},
varname='p_tal',
defaults={if_true={vi=""}}
@@ -2528,6 +2552,7 @@ return {
full_name='titlestring',
type='string', scope={'global'},
vi_def=true,
+ modelineexpr=true,
varname='p_titlestring',
defaults={if_true={vi=""}}
},
@@ -2729,9 +2754,9 @@ return {
full_name='wildoptions', abbreviation='wop',
type='string', list='onecomma', scope={'global'},
deny_duplicates=true,
- vi_def=true,
+ vim=true,
varname='p_wop',
- defaults={if_true={vi=""}}
+ defaults={if_true={vi='', vim='pum,tagfile'}}
},
{
full_name='winaltkeys', abbreviation='wak',
@@ -2741,6 +2766,13 @@ return {
defaults={if_true={vi="menu"}}
},
{
+ full_name='winblend', abbreviation='winbl',
+ type='number', scope={'window'},
+ vi_def=true,
+ redraw={'current_window'},
+ defaults={if_true={vi=0}}
+ },
+ {
full_name='winhighlight', abbreviation='winhl',
type='string', scope={'window'},
vi_def=true,
diff --git a/src/nvim/os/dl.c b/src/nvim/os/dl.c
index bbd0424a82..f0fadb16f2 100644
--- a/src/nvim/os/dl.c
+++ b/src/nvim/os/dl.c
@@ -54,6 +54,7 @@ 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;
}
diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c
index 871298f415..62457e155c 100644
--- a/src/nvim/os/env.c
+++ b/src/nvim/os/env.c
@@ -45,6 +45,7 @@ void env_init(void)
}
/// Like getenv(), but returns NULL if the variable is empty.
+/// @see os_env_exists
const char *os_getenv(const char *name)
FUNC_ATTR_NONNULL_ALL
{
@@ -101,10 +102,19 @@ bool os_env_exists(const char *name)
assert(r != UV_EINVAL);
if (r != 0 && r != UV_ENOENT && r != UV_ENOBUFS) {
ELOG("uv_os_getenv(%s) failed: %d %s", name, r, uv_err_name(r));
+#ifdef WIN32
+ return (r == UV_UNKNOWN);
+#endif
}
return (r == 0 || r == UV_ENOBUFS);
}
+/// Sets an environment variable.
+///
+/// Windows (Vim-compat): Empty string (:let $FOO="") undefines the env var.
+///
+/// @warning Existing pointers to the result of os_getenv("foo") are
+/// INVALID after os_setenv("foo", …).
int os_setenv(const char *name, const char *value, int overwrite)
FUNC_ATTR_NONNULL_ALL
{
@@ -115,15 +125,21 @@ int os_setenv(const char *name, const char *value, int overwrite)
if (!overwrite && os_getenv(name) != NULL) {
return 0;
}
+ if (value[0] == '\0') {
+ // Windows (Vim-compat): Empty string undefines the env var.
+ return os_unsetenv(name);
+ }
#else
if (!overwrite && os_env_exists(name)) {
return 0;
}
#endif
uv_mutex_lock(&mutex);
- pmap_del2(envmap, name);
int r = uv_os_setenv(name, value);
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);
if (r != 0) {
ELOG("uv_os_setenv(%s) failed: %d %s", name, r, uv_err_name(r));
}
@@ -294,6 +310,30 @@ void init_homedir(void)
if (var == NULL) {
var = os_getenv("USERPROFILE");
}
+
+ // Weird but true: $HOME may contain an indirect reference to another
+ // variable, esp. "%USERPROFILE%". Happens when $USERPROFILE isn't set
+ // when $HOME is being set.
+ if (var != NULL && *var == '%') {
+ const char *p = strchr(var + 1, '%');
+ if (p != NULL) {
+ vim_snprintf(os_buf, (size_t)(p - var), "%s", var + 1);
+ const char *exp = os_getenv(os_buf);
+ if (exp != NULL && *exp != NUL
+ && STRLEN(exp) + STRLEN(p) < MAXPATHL) {
+ vim_snprintf(os_buf, MAXPATHL, "%s%s", exp, p + 1);
+ var = os_buf;
+ }
+ }
+ }
+
+ // Default home dir is C:/
+ // Best assumption we can make in such a situation.
+ if (var == NULL
+ // Empty means "undefined"
+ || *var == NUL) {
+ var = "C:/";
+ }
#endif
if (var != NULL) {
@@ -695,17 +735,17 @@ char *vim_getenv(const char *name)
// init_path() should have been called before now.
assert(get_vim_var_str(VV_PROGPATH)[0] != NUL);
- const char *kos_env_path = os_getenv(name);
- if (kos_env_path != NULL) {
- return xstrdup(kos_env_path);
- }
-
#ifdef WIN32
if (strcmp(name, "HOME") == 0) {
return xstrdup(homedir);
}
#endif
+ const char *kos_env_path = os_getenv(name);
+ if (kos_env_path != NULL) {
+ return xstrdup(kos_env_path);
+ }
+
bool vimruntime = (strcmp(name, "VIMRUNTIME") == 0);
if (!vimruntime && strcmp(name, "VIM") != 0) {
return NULL;
diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c
index d5500b230c..dcb3ef7c4a 100644
--- a/src/nvim/os/fs.c
+++ b/src/nvim/os/fs.c
@@ -24,6 +24,7 @@
#include "nvim/message.h"
#include "nvim/assert.h"
#include "nvim/misc1.h"
+#include "nvim/option.h"
#include "nvim/path.h"
#include "nvim/strings.h"
@@ -229,7 +230,7 @@ int os_exepath(char *buffer, size_t *size)
/// Checks if the file `name` is executable.
///
/// @param[in] name Filename to check.
-/// @param[out] abspath Returns resolved executable path, if not NULL.
+/// @param[out,allocated] abspath Returns resolved exe path, if not NULL.
/// @param[in] use_path Also search $PATH.
///
/// @return true if `name` is executable and
@@ -238,27 +239,16 @@ int os_exepath(char *buffer, size_t *size)
/// - is absolute.
///
/// @return `false` otherwise.
-bool os_can_exe(const char_u *name, char_u **abspath, bool use_path)
+bool os_can_exe(const char *name, char **abspath, bool use_path)
FUNC_ATTR_NONNULL_ARG(1)
{
- bool no_path = !use_path || path_is_absolute(name);
- // If the filename is "qualified" (relative or absolute) do not check $PATH.
-#ifdef WIN32
- no_path |= (name[0] == '.'
- && ((name[1] == '/' || name[1] == '\\')
- || (name[1] == '.' && (name[2] == '/' || name[2] == '\\'))));
-#else
- no_path |= (name[0] == '.'
- && (name[1] == '/' || (name[1] == '.' && name[2] == '/')));
-#endif
-
- if (no_path) {
+ if (!use_path || gettail_dir(name) != name) {
#ifdef WIN32
- if (is_executable_ext((char *)name, abspath)) {
+ if (is_executable_ext(name, abspath)) {
#else
// Must have path separator, cannot execute files in the current directory.
- if ((const char_u *)gettail_dir((const char *)name) != name
- && is_executable((char *)name, abspath)) {
+ if ((use_path || gettail_dir(name) != name)
+ && is_executable(name, abspath)) {
#endif
return true;
} else {
@@ -270,10 +260,13 @@ bool os_can_exe(const char_u *name, char_u **abspath, bool use_path)
}
/// Returns true if `name` is an executable file.
-static bool is_executable(const char *name, char_u **abspath)
+///
+/// @param[in] name Filename to check.
+/// @param[out,allocated] abspath Returns full exe path, if not NULL.
+static bool is_executable(const char *name, char **abspath)
FUNC_ATTR_NONNULL_ARG(1)
{
- int32_t mode = os_getperm((const char *)name);
+ int32_t mode = os_getperm(name);
if (mode < 0) {
return false;
@@ -291,7 +284,7 @@ static bool is_executable(const char *name, char_u **abspath)
const bool ok = (r == 0);
#endif
if (ok && abspath != NULL) {
- *abspath = save_abs_path((char_u *)name);
+ *abspath = save_abs_path(name);
}
return ok;
}
@@ -300,7 +293,7 @@ static bool is_executable(const char *name, char_u **abspath)
/// Checks if file `name` is executable under any of these conditions:
/// - extension is in $PATHEXT and `name` is executable
/// - result of any $PATHEXT extension appended to `name` is executable
-static bool is_executable_ext(char *name, char_u **abspath)
+static bool is_executable_ext(char *name, char **abspath)
FUNC_ATTR_NONNULL_ARG(1)
{
const bool is_unix_shell = strstr((char *)path_tail(p_sh), "sh") != NULL;
@@ -312,7 +305,8 @@ static bool is_executable_ext(char *name, char_u **abspath)
if (!pathext) {
pathext = ".com;.exe;.bat;.cmd";
}
- for (const char *ext = pathext; *ext; ext++) {
+ const char *ext = pathext;
+ while (*ext) {
// If $PATHEXT itself contains dot:
if (ext[0] == '.' && (ext[1] == '\0' || ext[1] == ENV_SEPCHAR)) {
if (is_executable(name, abspath)) {
@@ -320,13 +314,17 @@ static bool is_executable_ext(char *name, char_u **abspath)
}
// Skip it.
ext++;
+ if (*ext) {
+ ext++;
+ }
continue;
}
- const char *ext_end = xstrchrnul(ext, ENV_SEPCHAR);
- size_t ext_len = (size_t)(ext_end - ext);
+ const char *ext_end = ext;
+ size_t ext_len =
+ copy_option_part((char_u **)&ext_end, (char_u *)buf_end,
+ sizeof(os_buf) - (size_t)(buf_end - os_buf), ENV_SEPSTR);
if (ext_len != 0) {
- STRLCPY(buf_end, ext, ext_len + 1);
bool in_pathext = nameext_len == ext_len
&& 0 == mb_strnicmp((char_u *)nameext, (char_u *)ext, ext_len);
@@ -347,7 +345,7 @@ static bool is_executable_ext(char *name, char_u **abspath)
/// @param[out] abspath Returns resolved executable path, if not NULL.
///
/// @return `true` if `name` is an executable inside `$PATH`.
-static bool is_executable_in_path(const char_u *name, char_u **abspath)
+static bool is_executable_in_path(const char *name, char **abspath)
FUNC_ATTR_NONNULL_ARG(1)
{
const char *path_env = os_getenv("PATH");
@@ -358,13 +356,13 @@ static bool is_executable_in_path(const char_u *name, char_u **abspath)
#ifdef WIN32
// Prepend ".;" to $PATH.
size_t pathlen = strlen(path_env);
- char *path = memcpy(xmallocz(pathlen + 3), "." ENV_SEPSTR, 2);
+ char *path = memcpy(xmallocz(pathlen + 2), "." ENV_SEPSTR, 2);
memcpy(path + 2, path_env, pathlen);
#else
char *path = xstrdup(path_env);
#endif
- size_t buf_len = STRLEN(name) + strlen(path) + 2;
+ size_t buf_len = strlen(name) + strlen(path) + 2;
char *buf = xmalloc(buf_len);
// Walk through all entries in $PATH to check if "name" exists there and
@@ -376,7 +374,7 @@ static bool is_executable_in_path(const char_u *name, char_u **abspath)
// Combine the $PATH segment with `name`.
STRLCPY(buf, p, e - p + 1);
- append_path(buf, (char *)name, buf_len);
+ append_path(buf, name, buf_len);
#ifdef WIN32
if (is_executable_ext(buf, abspath)) {
@@ -406,10 +404,11 @@ end:
/// calls (read, write, lseek, fcntl, etc.). If the operation fails, a libuv
/// error code is returned, and no file is created or modified.
///
+/// @param path Filename
/// @param flags Bitwise OR of flags defined in <fcntl.h>
/// @param mode Permissions for the newly-created file (IGNORED if 'flags' is
/// not `O_CREAT` or `O_TMPFILE`), subject to the current umask
-/// @return file descriptor, or libuv error code on failure
+/// @return file descriptor, or negative error code on failure
int os_open(const char *path, int flags, int mode)
{
if (path == NULL) { // uv_fs_open asserts on NULL. #7561
@@ -420,6 +419,68 @@ int os_open(const char *path, int flags, int mode)
return r;
}
+/// Compatibility wrapper conforming to fopen(3).
+///
+/// Windows: works with UTF-16 filepaths by delegating to libuv (os_open).
+///
+/// Future: remove this, migrate callers to os/fileio.c ?
+/// But file_open_fd does not support O_RDWR yet.
+///
+/// @param path Filename
+/// @param flags String flags, one of { r w a r+ w+ a+ rb wb ab }
+/// @return FILE pointer, or NULL on error.
+FILE *os_fopen(const char *path, const char *flags)
+{
+ assert(flags != NULL && strlen(flags) > 0 && strlen(flags) <= 2);
+ int iflags = 0;
+ // 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();
+ }
+#ifdef WIN32
+ if (flags[1] == 'b') {
+ iflags |= O_BINARY;
+ }
+#endif
+ } else {
+ // char 0 must be one of ('r','w','a').
+ // 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();
+ }
+ }
+ // Per open(2) manpage.
+ assert((iflags|O_RDONLY) || (iflags|O_WRONLY) || (iflags|O_RDWR));
+ // Per fopen(3) manpage: default to 0666, it will be umask-adjusted.
+ int fd = os_open(path, iflags, 0666);
+ if (fd < 0) {
+ return NULL;
+ }
+ return fdopen(fd, flags);
+}
+
/// Sets file descriptor `fd` to close-on-exec.
//
// @return -1 if failed to set, 0 otherwise.
@@ -746,6 +807,22 @@ bool os_path_exists(const char_u *path)
return os_stat((char *)path, &statbuf) == kLibuvSuccess;
}
+/// Sets file access and modification times.
+///
+/// @see POSIX utime(2)
+///
+/// @param path File path.
+/// @param atime Last access time.
+/// @param mtime Last modification time.
+///
+/// @return 0 on success, or negative error code.
+int os_file_settime(const char *path, double atime, double mtime)
+{
+ int r;
+ RUN_UV_FS_FUNC(r, uv_fs_utime, path, atime, mtime, NULL);
+ return r;
+}
+
/// Check if a file is readable.
///
/// @return true if `name` is readable, otherwise false.
@@ -815,12 +892,12 @@ int os_mkdir_recurse(const char *const dir, int32_t mode,
// We're done when it's "/" or "c:/".
const size_t dirlen = strlen(dir);
char *const curdir = xmemdupz(dir, dirlen);
- char *const past_head = (char *) get_past_head((char_u *) curdir);
+ char *const past_head = (char *)get_past_head((char_u *)curdir);
char *e = curdir + dirlen;
const char *const real_end = e;
const char past_head_save = *past_head;
- while (!os_isdir((char_u *) curdir)) {
- e = (char *) path_tail_with_sep((char_u *) curdir);
+ while (!os_isdir((char_u *)curdir)) {
+ e = (char *)path_tail_with_sep((char_u *)curdir);
if (e <= past_head) {
*past_head = NUL;
break;
@@ -972,7 +1049,7 @@ bool os_fileinfo_fd(int file_descriptor, FileInfo *file_info)
///
/// @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)
+ const FileInfo *file_info_2)
FUNC_ATTR_NONNULL_ALL
{
return file_info_1->stat.st_ino == file_info_2->stat.st_ino
diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c
index 8070f4c420..95e9e8e414 100644
--- a/src/nvim/os/input.c
+++ b/src/nvim/os/input.c
@@ -50,6 +50,11 @@ void input_init(void)
input_buffer = rbuffer_new(INPUT_BUFFER_SIZE + MAX_KEY_CODE_LEN);
}
+void input_global_fd_init(int fd)
+{
+ global_fd = fd;
+}
+
/// Global TTY (or pipe for "-es") input stream, before UI starts.
int input_global_fd(void)
{
@@ -62,7 +67,7 @@ void input_start(int fd)
return;
}
- global_fd = fd;
+ input_global_fd_init(fd);
rstream_init_fd(&main_loop, &read_stream, fd, READ_BUFFER_SIZE);
rstream_start(&read_stream, input_read_cb, NULL);
}
@@ -316,10 +321,10 @@ static unsigned int handle_mouse_event(char **ptr, uint8_t *buf,
// Make sure the mouse position is valid. Some terminals may
// return weird values.
if (col >= Columns) {
- col = (int)Columns - 1;
+ col = Columns - 1;
}
if (row >= Rows) {
- row = (int)Rows - 1;
+ row = Rows - 1;
}
mouse_grid = 0;
mouse_row = row;
diff --git a/src/nvim/os/process.c b/src/nvim/os/process.c
index a1020be215..c7b473a012 100644
--- a/src/nvim/os/process.c
+++ b/src/nvim/os/process.c
@@ -89,21 +89,12 @@ bool os_proc_tree_kill(int pid, int sig)
bool os_proc_tree_kill(int pid, int sig)
{
assert(sig == SIGTERM || sig == SIGKILL);
- int pgid = getpgid(pid);
- if (pgid > 0) { // Ignore error. Never kill self (pid=0).
- if (pgid == pid) {
- ILOG("sending %s to process group: -%d",
- sig == SIGTERM ? "SIGTERM" : "SIGKILL", pgid);
- int rv = uv_kill(-pgid, sig);
- return rv == 0;
- } else {
- // Should never happen, because process_spawn() did setsid() in the child.
- ELOG("pgid %d != pid %d", pgid, pid);
- }
- } else {
- ELOG("getpgid(%d) returned %d", pid, pgid);
+ if (pid == 0) {
+ // Never kill self (pid=0).
+ return false;
}
- return false;
+ ILOG("sending %s to PID %d", sig == SIGTERM ? "SIGTERM" : "SIGKILL", -pid);
+ return uv_kill(-pid, sig) == 0;
}
#endif
diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c
index 5fdf0e6181..f0bc13783c 100644
--- a/src/nvim/os/pty_process_unix.c
+++ b/src/nvim/os/pty_process_unix.c
@@ -288,7 +288,7 @@ static void chld_handler(uv_signal_t *handle, int signum)
if (WIFEXITED(stat)) {
proc->status = WEXITSTATUS(stat);
} else if (WIFSIGNALED(stat)) {
- proc->status = WTERMSIG(stat);
+ proc->status = 128 + WTERMSIG(stat);
}
proc->internal_exit_cb(proc);
}
diff --git a/src/nvim/os/pty_process_win.c b/src/nvim/os/pty_process_win.c
index c5f8efadff..290668bca3 100644
--- a/src/nvim/os/pty_process_win.c
+++ b/src/nvim/os/pty_process_win.c
@@ -252,7 +252,7 @@ static void pty_process_finish2(PtyProcess *ptyproc)
DWORD exit_code = 0;
GetExitCodeProcess(ptyproc->process_handle, &exit_code);
- proc->status = (int)exit_code;
+ proc->status = proc->exit_signal ? 128 + proc->exit_signal : (int)exit_code;
CloseHandle(ptyproc->process_handle);
ptyproc->process_handle = NULL;
diff --git a/src/nvim/os/time.c b/src/nvim/os/time.c
index 31ef1a0cd6..4dd0614fe2 100644
--- a/src/nvim/os/time.c
+++ b/src/nvim/os/time.c
@@ -9,6 +9,7 @@
#include <uv.h>
+#include "nvim/assert.h"
#include "nvim/os/time.h"
#include "nvim/os/input.h"
#include "nvim/event/loop.h"
@@ -22,6 +23,7 @@ static uv_cond_t delay_cond;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/time.c.generated.h"
#endif
+
/// Initializes the time module
void time_init(void)
{
@@ -29,15 +31,32 @@ void time_init(void)
uv_cond_init(&delay_cond);
}
-/// Obtain a high-resolution timer value
+/// Gets a high-resolution (nanosecond), monotonically-increasing time relative
+/// to an arbitrary time in the past.
+///
+/// Not related to the time of day and therefore not subject to clock drift.
///
-/// @return a timer value, not related to the time of day and not subject
-/// to clock drift. The value is expressed in nanoseconds.
+/// @return Relative time value with nanosecond precision.
uint64_t os_hrtime(void)
+ FUNC_ATTR_WARN_UNUSED_RESULT
{
return uv_hrtime();
}
+/// Gets a millisecond-resolution, monotonically-increasing time relative to an
+/// arbitrary time in the past.
+///
+/// Not related to the time of day and therefore not subject to clock drift.
+/// The value is cached by the loop, it will not change until the next
+/// loop-tick (unless uv_update_time is called).
+///
+/// @return Relative time value with millisecond precision.
+uint64_t os_now(void)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ return uv_now(&main_loop.uv);
+}
+
/// Sleeps for `ms` milliseconds.
///
/// @param ms Number of milliseconds to sleep
diff --git a/src/nvim/os_unix.c b/src/nvim/os_unix.c
index 35a7942059..ded575529f 100644
--- a/src/nvim/os_unix.c
+++ b/src/nvim/os_unix.c
@@ -369,10 +369,7 @@ int mch_expand_wildcards(int num_pat, char_u **pat, int *num_file,
// With interactive completion, the error message is not printed.
if (!(flags & EW_SILENT)) {
msg_putchar('\n'); // clear bottom line quickly
-#if SIZEOF_LONG > SIZEOF_INT
- assert(Rows <= (long)INT_MAX + 1);
-#endif
- cmdline_row = (int)(Rows - 1); // continue on last line
+ cmdline_row = Rows - 1; // continue on last line
MSG(_(e_wildexpand));
msg_start(); // don't overwrite this message
}
@@ -538,7 +535,7 @@ int mch_expand_wildcards(int num_pat, char_u **pat, int *num_file,
// Skip files that are not executable if we check for that.
if (!dir && (flags & EW_EXEC)
- && !os_can_exe((*file)[i], NULL, !(flags & EW_SHELLCMD))) {
+ && !os_can_exe((char *)(*file)[i], NULL, !(flags & EW_SHELLCMD))) {
continue;
}
diff --git a/src/nvim/path.c b/src/nvim/path.c
index b43a172991..75a26d88c1 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -453,13 +453,13 @@ char *FullName_save(const char *fname, bool force)
/// Saves the absolute path.
/// @param name An absolute or relative path.
/// @return The absolute path of `name`.
-char_u *save_abs_path(const char_u *name)
+char *save_abs_path(const char *name)
FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL
{
- if (!path_is_absolute(name)) {
- return (char_u *)FullName_save((char *)name, true);
+ if (!path_is_absolute((char_u *)name)) {
+ return FullName_save(name, true);
}
- return vim_strsave((char_u *) name);
+ return (char *)vim_strsave((char_u *)name);
}
/// Checks if a path has a wildcard character including '~', unless at the end.
@@ -1401,7 +1401,7 @@ void addfile(
// If the file isn't executable, may not add it. Do accept directories.
// When invoked from expand_shellcmd() do not use $PATH.
if (!isdir && (flags & EW_EXEC)
- && !os_can_exe(f, NULL, !(flags & EW_SHELLCMD))) {
+ && !os_can_exe((char *)f, NULL, !(flags & EW_SHELLCMD))) {
return;
}
@@ -2306,7 +2306,7 @@ void path_guess_exepath(const char *argv0, char *buf, size_t bufsize)
xstrlcpy((char *)NameBuff, dir, dir_len + 1);
xstrlcat((char *)NameBuff, PATHSEPSTR, sizeof(NameBuff));
xstrlcat((char *)NameBuff, argv0, sizeof(NameBuff));
- if (os_can_exe(NameBuff, NULL, false)) {
+ if (os_can_exe((char *)NameBuff, NULL, false)) {
xstrlcpy(buf, (char *)NameBuff, bufsize);
return;
}
diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c
index 58a0008e04..ce40bc15e0 100644
--- a/src/nvim/popupmnu.c
+++ b/src/nvim/popupmnu.c
@@ -376,6 +376,7 @@ void pum_redraw(void)
pum_height, grid_width, false, true);
bool invalid_grid = moved || pum_invalid;
pum_invalid = false;
+ must_redraw_pum = false;
if (!pum_grid.chars
|| pum_grid.Rows != pum_height || pum_grid.Columns != grid_width) {
@@ -412,7 +413,7 @@ void pum_redraw(void)
idx = i + pum_first;
attr = (idx == pum_selected) ? attr_select : attr_norm;
- screen_puts_line_start(row);
+ grid_puts_line_start(&pum_grid, row);
// prepend a space if there is room
if (extra_space) {
@@ -564,7 +565,7 @@ void pum_redraw(void)
? attr_thumb : attr_scroll);
}
}
- grid_puts_line_flush(&pum_grid, false);
+ grid_puts_line_flush(false);
row++;
}
}
@@ -790,6 +791,7 @@ void pum_undisplay(bool immediate)
{
pum_is_visible = false;
pum_array = NULL;
+ must_redraw_pum = false;
if (immediate) {
pum_check_clear();
@@ -853,7 +855,8 @@ int pum_get_height(void)
return pum_height;
}
-void pum_set_boundings(dict_T *dict)
+/// Add size information about the pum to "dict".
+void pum_set_event_info(dict_T *dict)
{
if (!pum_visible()) {
return;
diff --git a/src/nvim/profile.c b/src/nvim/profile.c
index 8fb8e92add..0a5030edae 100644
--- a/src/nvim/profile.c
+++ b/src/nvim/profile.c
@@ -5,6 +5,7 @@
#include <math.h>
#include <assert.h>
+#include "nvim/assert.h"
#include "nvim/profile.h"
#include "nvim/os/time.h"
#include "nvim/func_attr.h"
@@ -16,11 +17,9 @@
# include "profile.c.generated.h"
#endif
-/// functions for profiling
-
static proftime_T prof_wait_time;
-/// profile_start - return the current time
+/// Gets the current time.
///
/// @return the current time
proftime_T profile_start(void) FUNC_ATTR_WARN_UNUSED_RESULT
@@ -28,31 +27,29 @@ proftime_T profile_start(void) FUNC_ATTR_WARN_UNUSED_RESULT
return os_hrtime();
}
-/// profile_end - compute the time elapsed
+/// Computes the time elapsed.
///
-/// @return the elapsed time from `tm` until now.
+/// @return Elapsed time from `tm` until now.
proftime_T profile_end(proftime_T tm) FUNC_ATTR_WARN_UNUSED_RESULT
{
- return os_hrtime() - tm;
+ return profile_sub(os_hrtime(), tm);
}
-/// profile_msg - return a string that represents the time in `tm`
+/// Gets a string representing time `tm`.
///
/// @warning Do not modify or free this string, not multithread-safe.
///
-/// @param tm The time to be represented
-/// @return a static string representing `tm` in the
-/// form "seconds.microseconds".
+/// @param tm Time
+/// @return Static string representing `tm` in the form "seconds.microseconds".
const char *profile_msg(proftime_T tm) FUNC_ATTR_WARN_UNUSED_RESULT
{
static char buf[50];
-
- snprintf(buf, sizeof(buf), "%10.6lf", (double)tm / 1000000000.0);
-
+ snprintf(buf, sizeof(buf), "%10.6lf",
+ (double)profile_signed(tm) / 1000000000.0);
return buf;
}
-/// profile_setlimit - return the time `msec` into the future
+/// Gets the time `msec` into the future.
///
/// @param msec milliseconds, the maximum number of milliseconds is
/// (2^63 / 10^6) - 1 = 9.223372e+12.
@@ -64,14 +61,12 @@ proftime_T profile_setlimit(int64_t msec) FUNC_ATTR_WARN_UNUSED_RESULT
// no limit
return profile_zero();
}
-
assert(msec <= (INT64_MAX / 1000000LL) - 1);
-
- proftime_T nsec = (proftime_T) msec * 1000000ULL;
+ proftime_T nsec = (proftime_T)msec * 1000000ULL;
return os_hrtime() + nsec;
}
-/// profile_passed_limit - check if current time has passed `tm`
+/// Checks if current time has passed `tm`.
///
/// @return true if the current time is past `tm`, false if not or if the
/// timer was not set.
@@ -85,7 +80,7 @@ bool profile_passed_limit(proftime_T tm) FUNC_ATTR_WARN_UNUSED_RESULT
return profile_cmp(os_hrtime(), tm) < 0;
}
-/// profile_zero - obtain the zero time
+/// Gets the zero time.
///
/// @return the zero time
proftime_T profile_zero(void) FUNC_ATTR_CONST
@@ -93,7 +88,7 @@ proftime_T profile_zero(void) FUNC_ATTR_CONST
return 0;
}
-/// profile_divide - divide the time `tm` by `count`.
+/// Divides time `tm` by `count`.
///
/// @return 0 if count <= 0, otherwise tm / count
proftime_T profile_divide(proftime_T tm, int count) FUNC_ATTR_CONST
@@ -105,7 +100,7 @@ proftime_T profile_divide(proftime_T tm, int count) FUNC_ATTR_CONST
return (proftime_T) round((double) tm / (double) count);
}
-/// profile_add - add the time `tm2` to `tm1`
+/// Adds time `tm2` to `tm1`.
///
/// @return `tm1` + `tm2`
proftime_T profile_add(proftime_T tm1, proftime_T tm2) FUNC_ATTR_CONST
@@ -113,7 +108,12 @@ proftime_T profile_add(proftime_T tm1, proftime_T tm2) FUNC_ATTR_CONST
return tm1 + tm2;
}
-/// profile_sub - subtract `tm2` from `tm1`
+/// Subtracts time `tm2` from `tm1`.
+///
+/// Unsigned overflow (wraparound) occurs if `tm2` is greater than `tm1`.
+/// Use `profile_signed()` to get the signed integer value.
+///
+/// @see profile_signed
///
/// @return `tm1` - `tm2`
proftime_T profile_sub(proftime_T tm1, proftime_T tm2) FUNC_ATTR_CONST
@@ -121,8 +121,7 @@ proftime_T profile_sub(proftime_T tm1, proftime_T tm2) FUNC_ATTR_CONST
return tm1 - tm2;
}
-/// profile_self - add the `self` time from the total time and the
-/// children's time
+/// Adds the `self` time from the total time and the `children` time.
///
/// @return if `total` <= `children`, then self, otherwise `self` + `total` -
/// `children`
@@ -139,7 +138,7 @@ proftime_T profile_self(proftime_T self, proftime_T total, proftime_T children)
return profile_sub(profile_add(self, total), children);
}
-/// profile_get_wait - get the current waittime
+/// Gets the current waittime.
///
/// @return the current waittime
proftime_T profile_get_wait(void) FUNC_ATTR_PURE
@@ -147,13 +146,13 @@ proftime_T profile_get_wait(void) FUNC_ATTR_PURE
return prof_wait_time;
}
-/// profile_set_wait - set the current waittime
+/// Sets the current waittime.
void profile_set_wait(proftime_T wait)
{
prof_wait_time = wait;
}
-/// profile_sub_wait - subtract the passed waittime since `tm`
+/// Subtracts the passed waittime since `tm`.
///
/// @return `tma` - (waittime - `tm`)
proftime_T profile_sub_wait(proftime_T tm, proftime_T tma) FUNC_ATTR_PURE
@@ -162,7 +161,7 @@ proftime_T profile_sub_wait(proftime_T tm, proftime_T tma) FUNC_ATTR_PURE
return profile_sub(tma, tm3);
}
-/// profile_equal - check if `tm1` is equal to `tm2`
+/// Checks if time `tm1` is equal to `tm2`.
///
/// @return true if `tm1` == `tm2`
bool profile_equal(proftime_T tm1, proftime_T tm2) FUNC_ATTR_CONST
@@ -170,30 +169,38 @@ bool profile_equal(proftime_T tm1, proftime_T tm2) FUNC_ATTR_CONST
return tm1 == tm2;
}
-/// sgn64 - calculates the sign of a 64-bit integer
+/// Converts time duration `tm` (`profile_sub` result) to a signed integer.
///
-/// @return -1, 0, or +1
-static inline int sgn64(int64_t x) FUNC_ATTR_CONST
+/// @return signed representation of the given time value
+int64_t profile_signed(proftime_T tm)
+ FUNC_ATTR_CONST
{
- return (int) ((x > 0) - (x < 0));
+ // (tm > INT64_MAX) is >=150 years, so we can assume it was produced by
+ // arithmetic of two proftime_T values. For human-readable representation
+ // (and Vim-compat) we want the difference after unsigned wraparound. #10452
+ return (tm <= INT64_MAX) ? (int64_t)tm : -(int64_t)(UINT64_MAX - tm);
}
-/// profile_cmp - compare profiling times
+/// Compares profiling times.
///
-/// Only guarantees correct results if both input times are not more than
-/// 150 years apart.
+/// Times `tm1` and `tm2` must be less than 150 years apart.
///
-/// @return <0, 0 or >0 if `tm2` < `tm1`, `tm2` == `tm1` or `tm2` > `tm1`
+/// @return <0: `tm2` < `tm1`
+/// 0: `tm2` == `tm1`
+/// >0: `tm2` > `tm1`
int profile_cmp(proftime_T tm1, proftime_T tm2) FUNC_ATTR_CONST
{
- return sgn64((int64_t)(tm2 - tm1));
+ if (tm1 == tm2) {
+ return 0;
+ }
+ return profile_signed(tm2 - tm1) < 0 ? -1 : 1;
}
/// globals for use in the startuptime related functionality (time_*).
static proftime_T g_start_time;
static proftime_T g_prev_time;
-/// time_push - save the previous time before doing something that could nest
+/// Saves the previous time before doing something that could nest.
///
/// After calling this function, the static global `g_prev_time` will
/// contain the current time.
@@ -212,7 +219,7 @@ void time_push(proftime_T *rel, proftime_T *start)
g_prev_time = now;
}
-/// time_pop - compute the prev time after doing something that could nest
+/// Computes the prev time after doing something that could nest.
///
/// Subtracts `tp` from the static global `g_prev_time`.
///
@@ -222,18 +229,18 @@ void time_pop(proftime_T tp)
g_prev_time -= tp;
}
-/// time_diff - print the difference between `then` and `now`
+/// Prints the difference between `then` and `now`.
///
/// the format is "msec.usec".
static void time_diff(proftime_T then, proftime_T now)
{
proftime_T diff = profile_sub(now, then);
- fprintf(time_fd, "%07.3lf", (double) diff / 1.0E6);
+ fprintf(time_fd, "%07.3lf", (double)diff / 1.0E6);
}
-/// time_start - initialize the startuptime code
+/// Initializes the startuptime code.
///
-/// Needs to be called once before calling other startuptime code (such as
+/// Must be called once before calling other startuptime code (such as
/// time_{push,pop,msg,...}).
///
/// @param message the message that will be displayed
@@ -253,7 +260,7 @@ void time_start(const char *message)
time_msg(message, NULL);
}
-/// time_msg - print out timing info
+/// Prints out timing info.
///
/// @warning don't forget to call `time_start()` once before calling this.
///
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index ced0cf0f80..1eb616bca7 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -863,7 +863,7 @@ qf_init_ext(
fields.errmsg = xmalloc(fields.errmsglen);
fields.pattern = xmalloc(CMDBUFFSIZE + 1);
- if (efile != NULL && (state.fd = mch_fopen((char *)efile, "r")) == NULL) {
+ if (efile != NULL && (state.fd = os_fopen((char *)efile, "r")) == NULL) {
EMSG2(_(e_openerrf), efile);
goto qf_init_end;
}
@@ -1326,7 +1326,7 @@ static int qf_parse_multiline_pfx(qf_info_T *qi, int qf_idx, int idx,
if (qfprev == NULL) {
return QF_FAIL;
}
- if (*fields->errmsg && !qfl->qf_multiignore) {
+ if (*fields->errmsg) {
size_t textlen = strlen((char *)qfprev->qf_text);
size_t errlen = strlen((char *)fields->errmsg);
qfprev->qf_text = xrealloc(qfprev->qf_text, textlen + errlen + 2);
@@ -2056,7 +2056,7 @@ static int qf_jump_to_usable_window(int qf_fnum, int *opened_window)
win_T *usable_win_ptr = NULL;
int usable_win;
int flags;
- win_T *win = NULL;
+ win_T *win;
win_T *altwin;
usable_win = 0;
@@ -2079,7 +2079,6 @@ static int qf_jump_to_usable_window(int qf_fnum, int *opened_window)
// Locate a window showing a normal buffer
FOR_ALL_WINDOWS_IN_TAB(win2, curtab) {
if (win2->w_buffer->b_p_bt[0] == NUL) {
- win = win2;
usable_win = 1;
break;
}
@@ -2204,7 +2203,7 @@ static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit,
// Open help file (do_ecmd() will set b_help flag, readfile() will
// set b_p_ro flag).
if (!can_abandon(curbuf, forceit)) {
- EMSG(_(e_nowrtmsg));
+ no_write_message();
retval = false;
} else {
retval = do_ecmd(qf_ptr->qf_fnum, NULL, NULL, NULL, (linenr_T)1,
@@ -2212,7 +2211,6 @@ static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit,
oldwin == curwin ? curwin : NULL);
}
} else {
- int old_qf_curlist = qi->qf_curlist;
unsigned save_qfid = qi->qf_lists[qi->qf_curlist].qf_id;
retval = buflist_getfile(qf_ptr->qf_fnum, (linenr_T)1,
@@ -2229,8 +2227,7 @@ static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit,
EMSG(_(e_loc_list_changed));
*abort = true;
}
- } else if (old_qf_curlist != qi->qf_curlist
- || !is_qf_entry_present(qi, qf_ptr)) {
+ } else if (!is_qf_entry_present(qi, qf_ptr)) {
if (IS_QF_STACK(qi)) {
EMSG(_("E925: Current quickfix was changed"));
} else {
@@ -2528,9 +2525,9 @@ void qf_list(exarg_T *eap)
qfp = qi->qf_lists[qi->qf_curlist].qf_start;
for (i = 1; !got_int && i <= qi->qf_lists[qi->qf_curlist].qf_count; ) {
if ((qfp->qf_valid || all) && idx1 <= i && i <= idx2) {
- msg_putchar('\n');
- if (got_int)
+ if (got_int) {
break;
+ }
fname = NULL;
if (qfp->qf_module != NULL && *qfp->qf_module != NUL) {
@@ -2549,6 +2546,27 @@ void qf_list(exarg_T *eap)
vim_snprintf((char *)IObuff, IOSIZE, "%2d %s", i, (char *)fname);
}
}
+
+ // Support for filtering entries using :filter /pat/ clist
+ // Match against the module name, file name, search pattern and
+ // text of the entry.
+ bool filter_entry = true;
+ if (qfp->qf_module != NULL && *qfp->qf_module != NUL) {
+ filter_entry &= message_filtered(qfp->qf_module);
+ }
+ if (filter_entry && fname != NULL) {
+ filter_entry &= message_filtered(fname);
+ }
+ if (filter_entry && qfp->qf_pattern != NULL) {
+ filter_entry &= message_filtered(qfp->qf_pattern);
+ }
+ if (filter_entry) {
+ filter_entry &= message_filtered(qfp->qf_text);
+ }
+ if (filter_entry) {
+ goto next_entry;
+ }
+ msg_putchar('\n');
msg_outtrans_attr(IObuff, i == qi->qf_lists[qi->qf_curlist].qf_index
? HL_ATTR(HLF_QFL) : HL_ATTR(HLF_D));
if (qfp->qf_lnum == 0) {
@@ -2579,6 +2597,7 @@ void qf_list(exarg_T *eap)
ui_flush(); /* show one line at a time */
}
+next_entry:
qfp = qfp->qf_next;
if (qfp == NULL) {
break;
@@ -2632,7 +2651,7 @@ static void qf_msg(qf_info_T *qi, int which, char *lead)
}
xstrlcat((char *)buf, title, IOSIZE);
}
- trunc_string(buf, buf, (int)Columns - 1, IOSIZE);
+ trunc_string(buf, buf, Columns - 1, IOSIZE);
msg(buf);
}
@@ -2845,6 +2864,39 @@ static char_u *qf_types(int c, int nr)
return buf;
}
+// When "split" is false: Open the entry/result under the cursor.
+// 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;
+
+ if (!bt_quickfix(curbuf)) {
+ return;
+ }
+ if (IS_LL_WINDOW(curwin)) {
+ qi = GET_LOC_LIST(curwin);
+ }
+ if (qi == NULL
+ || qi->qf_lists[qi->qf_curlist].qf_count == 0) {
+ EMSG(_(e_quickfix));
+ return;
+ }
+
+ if (split) {
+ char cmd[32];
+
+ snprintf(cmd, sizeof(cmd), "split +%" PRId64 "%s",
+ (int64_t)curwin->w_cursor.lnum,
+ IS_LL_WINDOW(curwin) ? "ll" : "cc");
+ if (do_cmdline_cmd(cmd) == OK) {
+ do_cmdline_cmd("clearjumps");
+ }
+ return;
+ }
+
+ do_cmdline_cmd((IS_LL_WINDOW(curwin) ? ".ll" : ".cc"));
+}
+
/*
* ":cwindow": open the quickfix window if we have errors to display,
* close it if not.
@@ -4688,11 +4740,8 @@ static int qf_getprop_defaults(qf_info_T *qi, int flags, dict_T *retdict)
/// Return the quickfix list title as 'title' in retdict
static int qf_getprop_title(qf_info_T *qi, int qf_idx, dict_T *retdict)
{
- char_u *t = qi->qf_lists[qf_idx].qf_title;
- if (t == NULL) {
- t = (char_u *)"";
- }
- return tv_dict_add_str(retdict, S_LEN("title"), (const char *)t);
+ return tv_dict_add_str(retdict, S_LEN("title"),
+ (const char *)qi->qf_lists[qf_idx].qf_title);
}
/// Return the quickfix list items/entries as 'items' in retdict
@@ -5335,8 +5384,11 @@ void ex_cexpr(exarg_T *eap)
apply_autocmds(EVENT_QUICKFIXCMDPOST, (char_u *)au_name,
curbuf->b_fname, true, curbuf);
}
- if (res > 0 && (eap->cmdidx == CMD_cexpr || eap->cmdidx == CMD_lexpr)) {
- qf_jump(qi, 0, 0, eap->forceit); // display first error
+ if (res > 0
+ && (eap->cmdidx == CMD_cexpr || eap->cmdidx == CMD_lexpr)
+ && qi == GET_LOC_LIST(curwin)) {
+ // Jump to the first error if autocmds didn't free the list.
+ qf_jump(qi, 0, 0, eap->forceit);
}
} else {
EMSG(_("E777: String or List expected"));
@@ -5440,7 +5492,7 @@ void ex_helpgrep(exarg_T *eap)
+ STRLEN(fnames[fi]) - 3, 3) == 0)) {
continue;
}
- fd = mch_fopen((char *)fnames[fi], "r");
+ fd = os_fopen((char *)fnames[fi], "r");
if (fd != NULL) {
lnum = 1;
while (!vim_fgets(IObuff, IOSIZE, fd) && !got_int) {
diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c
index 8598da6376..06b99d0b75 100644
--- a/src/nvim/regexp.c
+++ b/src/nvim/regexp.c
@@ -247,9 +247,9 @@
#define BRACE_COMPLEX 140 /* -149 node Match nodes between m & n times */
-#define NOPEN 150 /* Mark this point in input as start of
- \%( subexpr. */
-#define NCLOSE 151 /* Analogous to NOPEN. */
+#define NOPEN 150 // Mark this point in input as start of
+ // \%( subexpr.
+#define NCLOSE 151 // Analogous to NOPEN.
#define MULTIBYTECODE 200 /* mbc Match one multi-byte character */
#define RE_BOF 201 /* Match "" at beginning of file. */
@@ -348,13 +348,13 @@ typedef enum regstate_E {
* more things.
*/
typedef struct regitem_S {
- regstate_T rs_state; /* what we are doing, one of RS_ above */
- char_u *rs_scan; /* current node in program */
+ regstate_T rs_state; // what we are doing, one of RS_ above
+ uint16_t rs_no; // submatch nr or BEHIND/NOBEHIND
+ char_u *rs_scan; // current node in program
union {
save_se_T sesave;
regsave_T regsave;
- } rs_un; /* room for saving reginput */
- short rs_no; /* submatch nr or BEHIND/NOBEHIND */
+ } rs_un; // room for saving reginput
} regitem_T;
@@ -2058,10 +2058,14 @@ static char_u *regatom(int *flagp)
EMSG2_RET_NULL(_(e_missing_sb),
reg_magic == MAGIC_ALL);
br = regnode(BRANCH);
- if (ret == NULL)
+ if (ret == NULL) {
ret = br;
- else
+ } else {
regtail(lastnode, br);
+ if (reg_toolong) {
+ return NULL;
+ }
+ }
ungetchr();
one_exactly = TRUE;
@@ -2083,6 +2087,9 @@ static char_u *regatom(int *flagp)
for (br = ret; br != lastnode; ) {
if (OP(br) == BRANCH) {
regtail(br, lastbranch);
+ if (reg_toolong) {
+ return NULL;
+ }
br = OPERAND(br);
} else
br = regnext(br);
@@ -4316,8 +4323,10 @@ static int regmatch(
/* Still at same position as last time, fail. */
status = RA_NOMATCH;
- if (status != RA_FAIL && status != RA_NOMATCH)
+ assert(status != RA_FAIL);
+ if (status != RA_NOMATCH) {
reg_save(&bp[i].bp_pos, &backpos);
+ }
}
break;
diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c
index dc1ab971ab..c0129a00fb 100644
--- a/src/nvim/regexp_nfa.c
+++ b/src/nvim/regexp_nfa.c
@@ -1263,8 +1263,8 @@ static int nfa_regatom(void)
IEMSGN("INTERNAL: Unknown character class char: %" PRId64, c);
return FAIL;
}
- /* When '.' is followed by a composing char ignore the dot, so that
- * the composing char is matched here. */
+ // When '.' is followed by a composing char ignore the dot, so that
+ // the composing char is matched here.
if (enc_utf8 && c == Magic('.') && utf_iscomposing(peekchr())) {
old_regparse = regparse;
c = getchr();
@@ -1279,25 +1279,26 @@ static int nfa_regatom(void)
break;
case Magic('n'):
- if (reg_string)
- /* In a string "\n" matches a newline character. */
+ if (reg_string) {
+ // In a string "\n" matches a newline character.
EMIT(NL);
- else {
- /* In buffer text "\n" matches the end of a line. */
+ } else {
+ // In buffer text "\n" matches the end of a line.
EMIT(NFA_NEWL);
regflags |= RF_HASNL;
}
break;
case Magic('('):
- if (nfa_reg(REG_PAREN) == FAIL)
- return FAIL; /* cascaded error */
+ if (nfa_reg(REG_PAREN) == FAIL) {
+ return FAIL; // cascaded error
+ }
break;
case Magic('|'):
case Magic('&'):
case Magic(')'):
- EMSGN(_(e_misplaced), no_Magic(c));
+ EMSGN(_(e_misplaced), no_Magic(c)); // -V1037
return FAIL;
case Magic('='):
@@ -1306,7 +1307,7 @@ static int nfa_regatom(void)
case Magic('@'):
case Magic('*'):
case Magic('{'):
- /* these should follow an atom, not form an atom */
+ // these should follow an atom, not form an atom
EMSGN(_(e_misplaced), no_Magic(c));
return FAIL;
@@ -1314,8 +1315,8 @@ static int nfa_regatom(void)
{
char_u *lp;
- /* Previous substitute pattern.
- * Generated as "\%(pattern\)". */
+ // Previous substitute pattern.
+ // Generated as "\%(pattern\)".
if (reg_prev_sub == NULL) {
EMSG(_(e_nopresub));
return FAIL;
@@ -1492,16 +1493,22 @@ static int nfa_regatom(void)
default:
{
- long n = 0;
- int cmp = c;
+ int64_t n = 0;
+ const int cmp = c;
if (c == '<' || c == '>')
c = getchr();
while (ascii_isdigit(c)) {
+ if (n > (INT32_MAX - (c - '0')) / 10) {
+ EMSG(_("E951: \\% value too large"));
+ return FAIL;
+ }
n = n * 10 + (c - '0');
c = getchr();
}
if (c == 'l' || c == 'c' || c == 'v') {
+ int32_t limit = INT32_MAX;
+
if (c == 'l') {
// \%{n}l \%{n}<l \%{n}>l
EMIT(cmp == '<' ? NFA_LNUM_LT :
@@ -1517,13 +1524,12 @@ static int nfa_regatom(void)
// \%{n}v \%{n}<v \%{n}>v
EMIT(cmp == '<' ? NFA_VCOL_LT :
cmp == '>' ? NFA_VCOL_GT : NFA_VCOL);
+ limit = INT32_MAX / MB_MAXBYTES;
}
-#if SIZEOF_INT < SIZEOF_LONG
- if (n > INT_MAX) {
+ if (n >= limit) {
EMSG(_("E951: \\% value too large"));
return FAIL;
}
-#endif
EMIT((int)n);
break;
} else if (c == '\'' && n == 0) {
@@ -3002,8 +3008,8 @@ static nfa_state_T *post2nfa(int *postfix, int *end, int nfa_calc_size)
return NULL; \
}
- if (nfa_calc_size == FALSE) {
- /* Allocate space for the stack. Max states on the stack : nstate */
+ if (nfa_calc_size == false) {
+ // Allocate space for the stack. Max states on the stack: "nstate".
stack = xmalloc((nstate + 1) * sizeof(Frag_T));
stackp = stack;
stack_end = stack + (nstate + 1);
@@ -3925,13 +3931,14 @@ state_in_list (
// Add "state" and possibly what follows to state list ".".
// Returns "subs_arg", possibly copied into temp_subs.
-static regsubs_T *
-addstate (
- nfa_list_T *l, /* runtime state list */
- nfa_state_T *state, /* state to update */
- regsubs_T *subs_arg, /* pointers to subexpressions */
- nfa_pim_T *pim, /* postponed look-behind match */
- int off_arg) /* byte offset, when -1 go to next line */
+// Returns NULL when recursiveness is too deep.
+static regsubs_T *addstate(
+ nfa_list_T *l, // runtime state list
+ nfa_state_T *state, // state to update
+ regsubs_T *subs_arg, // pointers to subexpressions
+ nfa_pim_T *pim, // postponed look-behind match
+ int off_arg) // byte offset, when -1 go to next line
+ FUNC_ATTR_NONNULL_ARG(1, 2) FUNC_ATTR_WARN_UNUSED_RESULT
{
int subidx;
int off = off_arg;
@@ -3950,6 +3957,14 @@ addstate (
#ifdef REGEXP_DEBUG
int did_print = FALSE;
#endif
+ static int depth = 0;
+
+ // This function is called recursively. When the depth is too much we run
+ // out of stack and crash, limit recursiveness here.
+ if (++depth >= 5000 || subs == NULL) {
+ depth--;
+ return NULL;
+ }
if (off_arg <= -ADDSTATE_HERE_OFFSET) {
add_here = true;
@@ -4053,6 +4068,7 @@ skip_add:
abs(state->id), l->id, state->c, code,
pim == NULL ? "NULL" : "yes", l->has_pim, found);
#endif
+ depth--;
return subs;
}
}
@@ -4063,11 +4079,17 @@ skip_add:
goto skip_add;
}
- /* When there are backreferences or PIMs the number of states may
- * be (a lot) bigger than anticipated. */
+ // When there are backreferences or PIMs the number of states may
+ // be (a lot) bigger than anticipated.
if (l->n == l->len) {
- int newlen = l->len * 3 / 2 + 50;
+ const int newlen = l->len * 3 / 2 + 50;
+ const size_t newsize = newlen * sizeof(nfa_thread_T);
+ if ((long)(newsize >> 10) >= p_mmp) {
+ EMSG(_(e_maxmempat));
+ depth--;
+ return NULL;
+ }
if (subs != &temp_subs) {
/* "subs" may point into the current array, need to make a
* copy before it becomes invalid. */
@@ -4077,7 +4099,8 @@ skip_add:
subs = &temp_subs;
}
- l->t = xrealloc(l->t, newlen * sizeof(nfa_thread_T));
+ nfa_thread_T *const newt = xrealloc(l->t, newsize);
+ l->t = newt;
l->len = newlen;
}
@@ -4196,6 +4219,9 @@ skip_add:
}
subs = addstate(l, state->out, subs, pim, off_arg);
+ if (subs == NULL) {
+ break;
+ }
// "subs" may have changed, need to set "sub" again.
if (state->c >= NFA_ZOPEN && state->c <= NFA_ZOPEN9) { // -V560
sub = &subs->synt;
@@ -4217,7 +4243,7 @@ skip_add:
if (nfa_has_zend && (REG_MULTI
? subs->norm.list.multi[0].end_lnum >= 0
: subs->norm.list.line[0].end != NULL)) {
- /* Do not overwrite the position set by \ze. */
+ // Do not overwrite the position set by \ze.
subs = addstate(l, state->out, subs, pim, off_arg);
break;
}
@@ -4278,6 +4304,9 @@ skip_add:
}
subs = addstate(l, state->out, subs, pim, off_arg);
+ if (subs == NULL) {
+ break;
+ }
// "subs" may have changed, need to set "sub" again.
if (state->c >= NFA_ZCLOSE && state->c <= NFA_ZCLOSE9) { // -V560
sub = &subs->synt;
@@ -4293,6 +4322,7 @@ skip_add:
sub->in_use = save_in_use;
break;
}
+ depth--;
return subs;
}
@@ -4302,14 +4332,14 @@ skip_add:
* This makes sure the order of states to be tried does not change, which
* matters for alternatives.
*/
-static void
-addstate_here (
- nfa_list_T *l, /* runtime state list */
- nfa_state_T *state, /* state to update */
- regsubs_T *subs, /* pointers to subexpressions */
- nfa_pim_T *pim, /* postponed look-behind match */
+static regsubs_T *addstate_here(
+ nfa_list_T *l, // runtime state list
+ nfa_state_T *state, // state to update
+ regsubs_T *subs, // pointers to subexpressions
+ nfa_pim_T *pim, // postponed look-behind match
int *ip
)
+ FUNC_ATTR_NONNULL_ARG(1, 2, 5) FUNC_ATTR_WARN_UNUSED_RESULT
{
int tlen = l->n;
int count;
@@ -4318,26 +4348,37 @@ addstate_here (
/* First add the state(s) at the end, so that we know how many there are.
* Pass the listidx as offset (avoids adding another argument to
* addstate(). */
- addstate(l, state, subs, pim, -listidx - ADDSTATE_HERE_OFFSET);
+ regsubs_T *r = addstate(l, state, subs, pim, -listidx - ADDSTATE_HERE_OFFSET);
+ if (r == NULL) {
+ return NULL;
+ }
- /* when "*ip" was at the end of the list, nothing to do */
- if (listidx + 1 == tlen)
- return;
+ // when "*ip" was at the end of the list, nothing to do
+ if (listidx + 1 == tlen) {
+ return r;
+ }
- /* re-order to put the new state at the current position */
+ // re-order to put the new state at the current position
count = l->n - tlen;
- if (count == 0)
- return; /* no state got added */
+ if (count == 0) {
+ return r; // no state got added
+ }
if (count == 1) {
- /* overwrite the current state */
+ // overwrite the current state
l->t[listidx] = l->t[l->n - 1];
} else if (count > 1) {
if (l->n + count - 1 >= l->len) {
/* not enough space to move the new states, reallocate the list
* and move the states to the right position */
+ const int newlen = l->len * 3 / 2 + 50;
+ const size_t newsize = newlen * sizeof(nfa_thread_T);
- l->len = l->len * 3 / 2 + 50;
- nfa_thread_T *newl = xmalloc(l->len * sizeof(nfa_thread_T));
+ if ((long)(newsize >> 10) >= p_mmp) {
+ EMSG(_(e_maxmempat));
+ return NULL;
+ }
+ nfa_thread_T *const newl = xmalloc(newsize);
+ l->len = newlen;
memmove(&(newl[0]),
&(l->t[0]),
sizeof(nfa_thread_T) * listidx);
@@ -4362,6 +4403,8 @@ addstate_here (
}
--l->n;
*ip = listidx - 1;
+
+ return r;
}
/*
@@ -4991,6 +5034,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
int add_count;
int add_off = 0;
int toplevel = start->c == NFA_MOPEN;
+ regsubs_T *r;
#ifdef NFA_REGEXP_DEBUG_LOG
FILE *debug = fopen(NFA_REGEXP_DEBUG_LOG, "a");
@@ -5058,9 +5102,14 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
} else
m->norm.list.line[0].start = reginput;
m->norm.in_use = 1;
- addstate(thislist, start->out, m, NULL, 0);
- } else
- addstate(thislist, start, m, NULL, 0);
+ r = addstate(thislist, start->out, m, NULL, 0);
+ } else {
+ r = addstate(thislist, start, m, NULL, 0);
+ }
+ if (r == NULL) {
+ nfa_match = NFA_TOO_EXPENSIVE;
+ goto theend;
+ }
#define ADD_STATE_IF_MATCH(state) \
if (result) { \
@@ -5327,8 +5376,11 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
// t->state->out1 is the corresponding END_INVISIBLE
// node; Add its out to the current list (zero-width
// match).
- addstate_here(thislist, t->state->out1->out, &t->subs,
- &pim, &listidx);
+ if (addstate_here(thislist, t->state->out1->out, &t->subs,
+ &pim, &listidx) == NULL) {
+ nfa_match = NFA_TOO_EXPENSIVE;
+ goto theend;
+ }
}
}
break;
@@ -6144,12 +6196,17 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
pim = &pim_copy;
}
- if (add_here)
- addstate_here(thislist, add_state, &t->subs, pim, &listidx);
- else {
- addstate(nextlist, add_state, &t->subs, pim, add_off);
- if (add_count > 0)
+ if (add_here) {
+ r = addstate_here(thislist, add_state, &t->subs, pim, &listidx);
+ } else {
+ r = addstate(nextlist, add_state, &t->subs, pim, add_off);
+ if (add_count > 0) {
nextlist->t[nextlist->n - 1].count = add_count;
+ }
+ }
+ if (r == NULL) {
+ nfa_match = NFA_TOO_EXPENSIVE;
+ goto theend;
}
}
} // for (thislist = thislist; thislist->state; thislist++)
@@ -6219,10 +6276,17 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
(colnr_T)(reginput - regline) + clen;
else
m->norm.list.line[0].start = reginput + clen;
- addstate(nextlist, start->out, m, NULL, clen);
+ if (addstate(nextlist, start->out, m, NULL, clen) == NULL) {
+ nfa_match = NFA_TOO_EXPENSIVE;
+ goto theend;
+ }
}
- } else
- addstate(nextlist, start, m, NULL, clen);
+ } else {
+ if (addstate(nextlist, start, m, NULL, clen) == NULL) {
+ nfa_match = NFA_TOO_EXPENSIVE;
+ goto theend;
+ }
+ }
}
#ifdef REGEXP_DEBUG
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 84c3f169ef..99ccce1793 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -153,6 +153,8 @@ static bool conceal_cursor_used = false;
static bool redraw_popupmenu = false;
+static bool resizing = false;
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "screen.c.generated.h"
#endif
@@ -169,6 +171,7 @@ void redraw_later(int type)
}
void redraw_win_later(win_T *wp, int type)
+ FUNC_ATTR_NONNULL_ALL
{
if (!exiting && wp->w_redr_type < type) {
wp->w_redr_type = type;
@@ -241,6 +244,7 @@ redrawWinline(
win_T *wp,
linenr_T lnum
)
+ FUNC_ATTR_NONNULL_ALL
{
if (lnum >= wp->w_topline
&& lnum < wp->w_botline) {
@@ -269,14 +273,16 @@ void update_curbuf(int type)
/// and redraw_all_later() to mark parts of the screen as needing a redraw.
///
/// @param type set to a NOT_VALID to force redraw of entire screen
-void update_screen(int type)
+int update_screen(int type)
{
static int did_intro = FALSE;
int did_one;
// Don't do anything if the screen structures are (not yet) valid.
- if (!default_grid.chars) {
- return;
+ // A VimResized autocmd can invoke redrawing in the middle of a resize,
+ // which would bypass the checks in screen_resize for popupmenu etc.
+ if (!default_grid.chars || resizing) {
+ return FAIL;
}
if (must_redraw) {
@@ -299,9 +305,10 @@ void update_screen(int type)
if (!redrawing() || updating_screen) {
redraw_later(type); /* remember type for next time */
must_redraw = type;
- if (type > INVERTED_ALL)
- curwin->w_lines_valid = 0; /* don't use w_lines[].wl_size now */
- return;
+ if (type > INVERTED_ALL) {
+ curwin->w_lines_valid = 0; // don't use w_lines[].wl_size now
+ }
+ return FAIL;
}
updating_screen = TRUE;
@@ -336,8 +343,7 @@ void update_screen(int type)
type = CLEAR;
} else if (type != CLEAR) {
check_for_delay(false);
- grid_ins_lines(&default_grid, 0, msg_scrolled, (int)Rows,
- 0, (int)Columns);
+ grid_ins_lines(&default_grid, 0, msg_scrolled, Rows, 0, Columns);
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->w_floating) {
continue;
@@ -482,13 +488,13 @@ void update_screen(int type)
}
end_search_hl();
+
// May need to redraw the popup menu.
- if (pum_drawn() && redraw_popupmenu) {
+ if (pum_drawn() && must_redraw_pum) {
pum_redraw();
}
send_grid_resize = false;
- redraw_popupmenu = false;
/* Reset b_mod_set flags. Going through all windows is probably faster
* than going through all buffers (there could be many buffers). */
@@ -511,28 +517,30 @@ void update_screen(int type)
// either cmdline is cleared, not drawn or mode is last drawn
cmdline_was_last_drawn = false;
+ return OK;
}
-/*
- * Return TRUE if the cursor line in window "wp" may be concealed, according
- * to the 'concealcursor' option.
- */
-int conceal_cursor_line(win_T *wp)
+// Return true if the cursor line in window "wp" may be concealed, according
+// to the 'concealcursor' option.
+bool conceal_cursor_line(const win_T *wp)
+ FUNC_ATTR_NONNULL_ALL
{
int c;
- if (*wp->w_p_cocu == NUL)
- return FALSE;
- if (get_real_state() & VISUAL)
+ if (*wp->w_p_cocu == NUL) {
+ return false;
+ }
+ if (get_real_state() & VISUAL) {
c = 'v';
- else if (State & INSERT)
+ } else if (State & INSERT) {
c = 'i';
- else if (State & NORMAL)
+ } else if (State & NORMAL) {
c = 'n';
- else if (State & CMDLINE)
+ } else if (State & CMDLINE) {
c = 'c';
- else
- return FALSE;
+ } else {
+ return false;
+ }
return vim_strchr(wp->w_p_cocu, c) != NULL;
}
@@ -554,7 +562,8 @@ void conceal_check_cursor_line(void)
///
/// If true, both old and new cursorline will need
/// need to be redrawn when moving cursor within windows.
-bool win_cursorline_standout(win_T *wp)
+bool win_cursorline_standout(const win_T *wp)
+ FUNC_ATTR_NONNULL_ALL
{
return wp->w_p_cul || (wp->w_p_cole > 0 && !conceal_cursor_line(wp));
}
@@ -600,8 +609,7 @@ static void win_update(win_T *wp)
updating. 999 when no bot area updating */
int scrolled_down = FALSE; /* TRUE when scrolled down when
w_topline got smaller a bit */
- matchitem_T *cur; /* points to the match list */
- int top_to_mod = FALSE; /* redraw above mod_top */
+ bool top_to_mod = false; // redraw above mod_top
int row; /* current window row to display */
linenr_T lnum; /* current buffer lnum to display */
@@ -696,21 +704,20 @@ static void win_update(win_T *wp)
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
- * previous line invalid. Simple solution: redraw all visible
- * lines above the change.
- * Same for a match pattern.
- */
+ // When 'hlsearch' is on and using a multi-line search pattern, a
+ // change in one line may make the Search highlighting in a
+ // previous line invalid. Simple solution: redraw all visible
+ // lines above the change.
+ // Same for a match pattern.
if (search_hl.rm.regprog != NULL
- && re_multiline(search_hl.rm.regprog))
- top_to_mod = TRUE;
- else {
- cur = wp->w_match_head;
+ && re_multiline(search_hl.rm.regprog)) {
+ top_to_mod = true;
+ } else {
+ const matchitem_T *cur = wp->w_match_head;
while (cur != NULL) {
if (cur->match.regprog != NULL
&& re_multiline(cur->match.regprog)) {
- top_to_mod = TRUE;
+ top_to_mod = true;
break;
}
cur = cur->next;
@@ -1457,7 +1464,7 @@ static void win_update(win_T *wp)
// Last line isn't finished: Display "@@@" in the last screen line.
grid_puts_len(&wp->w_grid, (char_u *)"@@", 2, scr_row, 0, at_attr);
- grid_fill(&wp->w_grid, scr_row, scr_row + 1, 2, (int)wp->w_grid.Columns,
+ grid_fill(&wp->w_grid, scr_row, scr_row + 1, 2, wp->w_grid.Columns,
'@', ' ', at_attr);
set_empty_rows(wp, srow);
wp->w_botline = lnum;
@@ -1468,7 +1475,7 @@ static void win_update(win_T *wp)
set_empty_rows(wp, srow);
wp->w_botline = lnum;
} else {
- win_draw_end(wp, '@', ' ', true, srow, wp->w_grid.Rows, at_attr);
+ win_draw_end(wp, '@', ' ', true, srow, wp->w_grid.Rows, HLF_AT);
wp->w_botline = lnum;
}
} else {
@@ -1584,6 +1591,7 @@ static int win_fill_end(win_T *wp, int c1, int c2, int off, int width, int row,
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;
if (draw_margin) {
@@ -1709,7 +1717,6 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
int col;
int txtcol;
int off;
- int ri;
/* Build the fold line:
* 1. Add the cmdwin_type for the command-line window
@@ -1753,15 +1760,18 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
col += fdc;
}
-# define RL_MEMSET(p, v, l) if (wp->w_p_rl) { \
- for (ri = 0; ri < l; ri++) { \
- linebuf_attr[off + (wp->w_grid.Columns - (p) - (l)) + ri] = v; \
- } \
- } else { \
- for (ri = 0; ri < l; ri++) { \
- linebuf_attr[off + (p) + ri] = v; \
+# define RL_MEMSET(p, v, l) \
+ do { \
+ if (wp->w_p_rl) { \
+ for (int ri = 0; ri < l; ri++) { \
+ linebuf_attr[off + (wp->w_grid.Columns - (p) - (l)) + ri] = v; \
+ } \
+ } else { \
+ for (int ri = 0; ri < l; ri++) { \
+ linebuf_attr[off + (p) + ri] = v; \
+ } \
} \
- }
+ } while (0)
/* Set all attributes of the 'number' or 'relativenumber' column and the
* text */
@@ -1775,7 +1785,9 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
if (len > len_max) {
len = len_max;
}
- copy_text_attr(off + col, (char_u *)" ", len,
+ char_u space_buf[18] = " ";
+ assert((size_t)len_max <= sizeof(space_buf));
+ copy_text_attr(off + col, space_buf, len,
win_hl_attr(wp, HLF_FL));
col += len;
}
@@ -2061,7 +2073,8 @@ win_line (
int row; // row in the window, excl w_winrow
ScreenGrid *grid = &wp->w_grid; // grid specfic to the window
- char_u extra[18]; // line number and 'fdc' must fit in here
+ 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
@@ -2074,7 +2087,7 @@ win_line (
int lcs_eol_one = wp->w_p_lcs_chars.eol; // 'eol' until it's been used
int lcs_prec_todo = wp->w_p_lcs_chars.prec; // 'prec' until it's been used
- /* saved "extra" items for when draw_state becomes WL_LINE (again) */
+ // saved "extra" items for when draw_state becomes WL_LINE (again)
int saved_n_extra = 0;
char_u *saved_p_extra = NULL;
int saved_c_extra = 0;
@@ -2712,15 +2725,24 @@ win_line (
sign_idx, count);
if (text_sign != 0) {
p_extra = sign_get_text(text_sign);
- int symbol_blen = (int)STRLEN(p_extra);
if (p_extra != NULL) {
+ int symbol_blen = (int)STRLEN(p_extra);
+
c_extra = NUL;
c_final = NUL;
+
+ // TODO(oni-link): Is sign text already extended to
+ // full cell width?
+ assert((size_t)win_signcol_width(wp)
+ >= mb_string2cells(p_extra));
// symbol(s) bytes + (filling spaces) (one byte each)
n_extra = symbol_blen +
(win_signcol_width(wp) - mb_string2cells(p_extra));
+
+ assert(sizeof(extra) > (size_t)symbol_blen);
memset(extra, ' ', sizeof(extra));
- STRNCPY(extra, p_extra, STRLEN(p_extra));
+ memcpy(extra, p_extra, symbol_blen);
+
p_extra = extra;
p_extra[n_extra] = NUL;
}
@@ -3121,7 +3143,7 @@ win_line (
c = '>';
mb_c = c;
mb_l = 1;
- mb_utf8 = false;
+ (void)mb_l;
multi_attr = win_hl_attr(wp, HLF_AT);
// put the pointer back to output the double-width
@@ -3132,9 +3154,9 @@ win_line (
n_extra -= mb_l - 1;
p_extra += mb_l - 1;
}
- ++p_extra;
+ p_extra++;
}
- --n_extra;
+ n_extra--;
} else {
int c0;
@@ -3753,15 +3775,14 @@ win_line (
n_attr3 = 1;
}
- /*
- * At end of the text line or just after the last character.
- */
+ // At end of the text line or just after the last character.
if (c == NUL) {
- long prevcol = (long)(ptr - line) - (c == NUL);
+ long prevcol = (long)(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)
- ++prevcol;
+ // we're not really at that column when skipping some text
+ if ((long)(wp->w_p_wrap ? wp->w_skipcol : wp->w_leftcol) > prevcol) {
+ prevcol++;
+ }
// Invert at least one char, used for Visual and empty line or
// highlight match at end of line. If it's beyond the last
@@ -3784,8 +3805,7 @@ win_line (
&& ((area_attr != 0 && vcol == fromcol
&& (VIsual_mode != Ctrl_V
|| lnum == VIsual.lnum
- || lnum == curwin->w_cursor.lnum)
- && c == NUL)
+ || lnum == curwin->w_cursor.lnum))
// highlight 'hlsearch' match at end of line
|| prevcol_hl_flag)) {
int n = 0;
@@ -4012,7 +4032,7 @@ win_line (
&& filler_todo <= 0
&& (wp->w_p_rl ? col == 0 : col == grid->Columns - 1)
&& (*ptr != NUL
- || (wp->w_p_list && lcs_eol_one > 0)
+ || lcs_eol_one > 0
|| (n_extra && (c_extra != NUL || *p_extra != NUL)))) {
c = wp->w_p_lcs_chars.ext;
char_attr = win_hl_attr(wp, HLF_AT);
@@ -4026,14 +4046,15 @@ win_line (
}
}
- /* advance to the next 'colorcolumn' */
- if (draw_color_col)
+ // advance to the next 'colorcolumn'
+ if (draw_color_col) {
draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
+ }
- /* Highlight the cursor column if 'cursorcolumn' is set. But don't
- * highlight the cursor position itself.
- * Also highlight the 'colorcolumn' if it is different than
- * 'cursorcolumn' */
+ // Highlight the cursor column if 'cursorcolumn' is set. But don't
+ // highlight the cursor position itself.
+ // Also highlight the 'colorcolumn' if it is different than
+ // 'cursorcolumn'
vcol_save_attr = -1;
if (draw_state == WL_LINE && !lnum_in_visual_area
&& search_attr == 0 && area_attr == 0) {
@@ -4052,10 +4073,8 @@ win_line (
char_attr = hl_combine_attr(line_attr_lowprio, char_attr);
}
- /*
- * Store character to be displayed.
- * Skip characters that are left of the screen for 'nowrap'.
- */
+ // Store character to be displayed.
+ // Skip characters that are left of the screen for 'nowrap'.
vcol_prev = vcol;
if (draw_state < WL_LINE || n_skip <= 0) {
//
@@ -4355,6 +4374,12 @@ static void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol,
screen_adjust_grid(&grid, &row, &coloff);
+ // Safety check. Avoids clang warnings down the call stack.
+ if (grid->chars == NULL || row >= grid->Rows || col >= grid->Columns) {
+ DLOG("invalid state, skipped");
+ return;
+ }
+
off_from = 0;
off_to = grid->line_offset[row] + coloff;
max_off_from = linebuf_size;
@@ -4550,17 +4575,21 @@ void redraw_statuslines(void)
/*
* Redraw all status lines at the bottom of frame "frp".
*/
-void win_redraw_last_status(frame_T *frp)
+void win_redraw_last_status(const frame_T *frp)
+ FUNC_ATTR_NONNULL_ARG(1)
{
- if (frp->fr_layout == FR_LEAF)
- frp->fr_win->w_redr_status = TRUE;
- else if (frp->fr_layout == FR_ROW) {
- for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
+ if (frp->fr_layout == FR_LEAF) {
+ frp->fr_win->w_redr_status = true;
+ } else if (frp->fr_layout == FR_ROW) {
+ FOR_ALL_FRAMES(frp, frp->fr_child) {
win_redraw_last_status(frp);
- } else { /* frp->fr_layout == FR_COL */
+ }
+ } else {
+ assert(frp->fr_layout == FR_COL);
frp = frp->fr_child;
- while (frp->fr_next != NULL)
+ while (frp->fr_next != NULL) {
frp = frp->fr_next;
+ }
win_redraw_last_status(frp);
}
}
@@ -4641,7 +4670,7 @@ win_redr_status_matches (
int showtail
)
{
-#define L_MATCH(m) (showtail ? sm_gettail(matches[m]) : matches[m])
+#define L_MATCH(m) (showtail ? sm_gettail(matches[m], false) : matches[m])
int row;
char_u *buf;
int len;
@@ -4798,7 +4827,7 @@ win_redr_status_matches (
grid_puts(&default_grid, selstart, row, selstart_col, HL_ATTR(HLF_WM));
}
- grid_fill(&default_grid, row, row + 1, clen, (int)Columns,
+ grid_fill(&default_grid, row, row + 1, clen, Columns,
fillchar, fillchar, attr);
}
@@ -5141,7 +5170,7 @@ win_redr_custom (
/*
* Draw each snippet with the specified highlighting.
*/
- screen_puts_line_start(row);
+ grid_puts_line_start(&default_grid, row);
curattr = attr;
p = buf;
@@ -5164,7 +5193,7 @@ win_redr_custom (
grid_puts(&default_grid, p >= buf + len ? (char_u *)"" : p, row, col,
curattr);
- grid_puts_line_flush(&default_grid, false);
+ grid_puts_line_flush(false);
if (wp == NULL) {
// Fill the tab_page_click_defs array for clicking in the tab pages line.
@@ -5310,18 +5339,20 @@ void grid_puts(ScreenGrid *grid, char_u *text, int row, int col, int attr)
grid_puts_len(grid, text, -1, row, col, attr);
}
+static ScreenGrid *put_dirty_grid = NULL;
static int put_dirty_row = -1;
static int put_dirty_first = INT_MAX;
static int put_dirty_last = 0;
-/// Start a group of screen_puts_len calls that builds a single screen line.
+/// Start a group of grid_puts_len calls that builds a single grid line.
///
-/// Must be matched with a screen_puts_line_flush call before moving to
+/// Must be matched with a grid_puts_line_flush call before moving to
/// another line.
-void screen_puts_line_start(int row)
+void grid_puts_line_start(ScreenGrid *grid, int row)
{
assert(put_dirty_row == -1);
put_dirty_row = row;
+ put_dirty_grid = grid;
}
/// like grid_puts(), but output "text[len]". When "len" is -1 output up to
@@ -5347,16 +5378,19 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row,
screen_adjust_grid(&grid, &row, &col);
- // safety check
- if (grid->chars == NULL || row >= grid->Rows || col >= grid->Columns) {
+ // Safety check. The check for negative row and column is to fix issue
+ // vim/vim#4102. TODO: find out why row/col could be negative.
+ if (grid->chars == NULL
+ || row >= grid->Rows || row < 0
+ || col >= grid->Columns || col < 0) {
return;
}
if (put_dirty_row == -1) {
- screen_puts_line_start(row);
+ grid_puts_line_start(grid, row);
do_flush = true;
} else {
- if (row != put_dirty_row) {
+ if (grid != put_dirty_grid || row != put_dirty_row) {
abort();
}
}
@@ -5459,31 +5493,31 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row,
}
if (do_flush) {
- grid_puts_line_flush(grid, true);
+ grid_puts_line_flush(true);
}
}
-/// End a group of screen_puts_len calls and send the screen buffer to the UI
+/// End a group of grid_puts_len calls and send the screen buffer to the UI
/// layer.
///
-/// @param grid The grid which contains the buffer.
/// @param set_cursor Move the visible cursor to the end of the changed region.
/// This is a workaround for not yet refactored code paths
/// and shouldn't be used in new code.
-void grid_puts_line_flush(ScreenGrid *grid, bool set_cursor)
+void grid_puts_line_flush(bool set_cursor)
{
assert(put_dirty_row != -1);
if (put_dirty_first < put_dirty_last) {
if (set_cursor) {
- ui_grid_cursor_goto(grid->handle, put_dirty_row,
- MIN(put_dirty_last, grid->Columns-1));
+ ui_grid_cursor_goto(put_dirty_grid->handle, put_dirty_row,
+ MIN(put_dirty_last, put_dirty_grid->Columns-1));
}
- ui_line(grid, put_dirty_row, put_dirty_first, put_dirty_last,
+ ui_line(put_dirty_grid, put_dirty_row, put_dirty_first, put_dirty_last,
put_dirty_last, 0, false);
put_dirty_first = INT_MAX;
put_dirty_last = 0;
}
put_dirty_row = -1;
+ put_dirty_grid = NULL;
}
/*
@@ -5971,7 +6005,14 @@ void grid_assign_handle(ScreenGrid *grid)
/// needed.
void screenalloc(void)
{
- static bool entered = false; // avoid recursiveness
+ // It's possible that we produce an out-of-memory message below, which
+ // will cause this function to be called again. To break the loop, just
+ // return here.
+ if (resizing) {
+ return;
+ }
+ resizing = true;
+
int retry_count = 0;
retry:
@@ -5985,19 +6026,11 @@ retry:
|| Rows == 0
|| Columns == 0
|| (!full_screen && default_grid.chars == NULL)) {
+ resizing = false;
return;
}
/*
- * It's possible that we produce an out-of-memory message below, which
- * will cause this function to be called again. To break the loop, just
- * return here.
- */
- if (entered)
- return;
- entered = TRUE;
-
- /*
* Note that the window sizes are updated before reallocating the arrays,
* thus we must not redraw here!
*/
@@ -6037,8 +6070,7 @@ retry:
must_redraw = CLEAR; // need to clear the screen later
- entered = FALSE;
- --RedrawingDisabled;
+ RedrawingDisabled--;
/*
* Do not apply autocommands more than 3 times to avoid an endless loop
@@ -6050,14 +6082,16 @@ retry:
* jump back to check if we need to allocate the screen again. */
goto retry;
}
+
+ resizing = false;
}
void grid_alloc(ScreenGrid *grid, int rows, int columns, bool copy, bool valid)
{
int new_row;
ScreenGrid new = *grid;
-
- size_t ncells = (size_t)((rows+1) * columns);
+ assert(rows >= 0 && columns >= 0);
+ size_t ncells = (size_t)rows * columns;
new.chars = xmalloc(ncells * sizeof(schar_T));
new.attrs = xmalloc(ncells * sizeof(sattr_T));
new.line_offset = xmalloc((size_t)(rows * sizeof(unsigned)));
@@ -6623,7 +6657,7 @@ static void recording_mode(int attr)
/*
* Draw the tab pages line at the top of the Vim window.
*/
-static void draw_tabline(void)
+void draw_tabline(void)
{
int tabcount = 0;
int tabwidth = 0;
@@ -6781,13 +6815,11 @@ static void draw_tabline(void)
c = '_';
else
c = ' ';
- grid_fill(&default_grid, 0, 1, col, (int)Columns, c, c,
- attr_fill);
+ grid_fill(&default_grid, 0, 1, col, Columns, c, c, attr_fill);
/* Put an "X" for closing the current tab if there are several. */
if (first_tabpage->tp_next != NULL) {
- grid_putchar(&default_grid, 'X', 0, (int)Columns - 1,
- attr_nosel);
+ grid_putchar(&default_grid, 'X', 0, Columns - 1, attr_nosel);
tab_page_click_defs[Columns - 1] = (StlClickDefinition) {
.type = kStlClickTabClose,
.tabnr = 999,
@@ -7150,6 +7182,8 @@ void screen_resize(int width, int height)
check_shellsize();
height = Rows;
width = Columns;
+ p_lines = Rows;
+ p_columns = Columns;
ui_call_grid_resize(1, width, height);
send_grid_resize = true;
diff --git a/src/nvim/search.c b/src/nvim/search.c
index 4d02a07cbd..fe4fdf57ba 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -352,7 +352,7 @@ int ignorecase_opt(char_u *pat, int ic_in, int scs)
{
int ic = ic_in;
if (ic && !no_smartcase && scs
- && !(ctrl_x_mode && curbuf->b_p_inf)
+ && !(ctrl_x_mode_not_default() && curbuf->b_p_inf)
) {
ic = !pat_has_uppercase(pat);
}
@@ -864,13 +864,11 @@ int searchit(
}
at_first_line = FALSE;
- /*
- * Stop the search if wrapscan isn't set, "stop_lnum" is
- * specified, after an interrupt, after a match and after looping
- * twice.
- */
+ // Stop the search if wrapscan isn't set, "stop_lnum" is
+ // specified, after an interrupt, after a match and after looping
+ // twice.
if (!p_ws || stop_lnum != 0 || got_int || called_emsg
- || (timed_out != NULL && timed_out)
+ || (timed_out != NULL && *timed_out)
|| break_loop
|| found || loop) {
break;
@@ -1132,14 +1130,14 @@ int do_search(
&& !cmd_silent && msg_silent == 0) {
char_u *trunc;
char_u off_buf[40];
- int off_len = 0;
+ size_t off_len = 0;
// Compute msg_row early.
msg_start();
// Get the offset, so we know how long it is.
if (spats[0].off.line || spats[0].off.end || spats[0].off.off) {
- p = off_buf;
+ p = off_buf; // -V507
*p++ = dirc;
if (spats[0].off.end) {
*p++ = 'e';
@@ -1168,12 +1166,14 @@ int do_search(
// search stat. Use all the space available, so that the
// search state is right aligned. If there is not enough space
// msg_strtrunc() will shorten in the middle.
- if (msg_scrolled != 0) {
+ if (ui_has(kUIMessages)) {
+ len = 0; // adjusted below
+ } else if (msg_scrolled != 0) {
// Use all the columns.
- len = (int)(Rows - msg_row) * Columns - 1;
+ len = (Rows - msg_row) * Columns - 1;
} else {
// Use up to 'showcmd' column.
- len = (int)(Rows - msg_row - 1) * Columns + sc_col - 1;
+ len = (Rows - msg_row - 1) * Columns + sc_col - 1;
}
if (len < STRLEN(p) + off_len + SEARCH_STAT_BUF_LEN + 3) {
len = STRLEN(p) + off_len + SEARCH_STAT_BUF_LEN + 3;
@@ -1183,7 +1183,7 @@ int do_search(
len = STRLEN(p) + off_len + 3;
}
- msgbuf = xmalloc((int)len);
+ msgbuf = xmalloc(len);
{
memset(msgbuf, ' ', len);
msgbuf[0] = dirc;
@@ -1215,7 +1215,7 @@ int do_search(
xfree(msgbuf);
msgbuf = r;
// move reversed text to beginning of buffer
- while (*r != NUL && *r == ' ') {
+ while (*r == ' ') {
r++;
}
size_t pat_len = msgbuf + STRLEN(msgbuf) - r;
@@ -3368,7 +3368,6 @@ current_tagblock(
)
{
long count = count_arg;
- long n;
pos_T old_pos;
pos_T start_pos;
pos_T end_pos;
@@ -3377,7 +3376,6 @@ current_tagblock(
char_u *p;
char_u *cp;
int len;
- int r;
bool do_include = include;
bool save_p_ws = p_ws;
int retval = FAIL;
@@ -3426,12 +3424,12 @@ again:
* Search backwards for unclosed "<aaa>".
* Put this position in start_pos.
*/
- for (n = 0; n < count; ++n) {
- if (do_searchpair((char_u *)
- "<[^ \t>/!]\\+\\%(\\_s\\_[^>]\\{-}[^/]>\\|$\\|\\_s\\=>\\)",
- (char_u *)"",
- (char_u *)"</[^>]*>", BACKWARD, (char_u *)"", 0,
- NULL, (linenr_T)0, 0L) <= 0) {
+ for (long n = 0; n < count; n++) {
+ if (do_searchpair(
+ (char_u *)"<[^ \t>/!]\\+\\%(\\_s\\_[^>]\\{-}[^/]>\\|$\\|\\_s\\=>\\)",
+ (char_u *)"",
+ (char_u *)"</[^>]*>", BACKWARD, NULL, 0,
+ NULL, (linenr_T)0, 0L) <= 0) {
curwin->w_cursor = old_pos;
goto theend;
}
@@ -3457,8 +3455,8 @@ again:
sprintf((char *)spat, "<%.*s\\>\\%%(\\s\\_[^>]\\{-}[^/]>\\|>\\)\\c", len, p);
sprintf((char *)epat, "</%.*s>\\c", len, p);
- r = do_searchpair(spat, (char_u *)"", epat, FORWARD, (char_u *)"",
- 0, NULL, (linenr_T)0, 0L);
+ const int r = do_searchpair(spat, (char_u *)"", epat, FORWARD, NULL,
+ 0, NULL, (linenr_T)0, 0L);
xfree(spat);
xfree(epat);
@@ -4244,6 +4242,7 @@ static void search_stat(int dirc, pos_T *pos,
// STRNICMP ignores case, but we should not ignore case.
// Unfortunately, there is no STRNICMP 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, curwin->w_cursor)
@@ -4289,7 +4288,7 @@ static void search_stat(int dirc, pos_T *pos,
if (curwin->w_p_rl && *curwin->w_p_rlc == 's') {
if (cur == OUT_OF_TIME) {
- vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]");
+ vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?\?/?]");
} else if (cnt > 99 && cur > 99) {
vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>99/>99]");
} else if (cnt > 99) {
@@ -4328,6 +4327,7 @@ static void search_stat(int dirc, pos_T *pos,
// 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;
}
@@ -4343,8 +4343,8 @@ find_pattern_in_path(
char_u *ptr, // pointer to search pattern
int dir, // direction of expansion
size_t len, // length of search pattern
- int whole, // match whole words only
- int skip_comments, // don't match inside comments
+ 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,
@@ -4574,10 +4574,9 @@ find_pattern_in_path(
xfree(files);
files = bigger;
}
- if ((files[depth + 1].fp = mch_fopen((char *)new_fname, "r"))
- == NULL)
+ if ((files[depth + 1].fp = os_fopen((char *)new_fname, "r")) == NULL) {
xfree(new_fname);
- else {
+ } else {
if (++depth == old_files) {
// Something wrong. We will forget one of our already visited files
// now.
diff --git a/src/nvim/shada.c b/src/nvim/shada.c
index 4aafc669dc..3ebe75b980 100644
--- a/src/nvim/shada.c
+++ b/src/nvim/shada.c
@@ -151,15 +151,6 @@ KHASH_SET_INIT_STR(strset)
/// Callback function for add_search_pattern
typedef void (*SearchPatternGetter)(SearchPattern *);
-/// Flags for shada_read_file and children
-typedef enum {
- kShaDaWantInfo = 1, ///< Load non-mark information
- kShaDaWantMarks = 2, ///< Load local file marks and change list
- kShaDaForceit = 4, ///< Overwrite info already read
- kShaDaGetOldfiles = 8, ///< Load v:oldfiles.
- kShaDaMissingError = 16, ///< Error out when os_open returns -ENOENT.
-} ShaDaReadFileFlags;
-
/// Possible ShaDa entry types
///
/// @warning Enum values are part of the API and must not be altered.
@@ -283,7 +274,7 @@ typedef struct {
char sep;
list_T *additional_elements;
} history_item;
- struct reg {
+ struct reg { // yankreg_T
char name;
MotionType type;
char **contents;
@@ -1328,13 +1319,13 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
break;
}
if (!force) {
- const yankreg_T *const reg = op_register_get(cur_entry.data.reg.name);
+ 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_register_set(cur_entry.data.reg.name, (yankreg_T) {
+ 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,
@@ -2496,7 +2487,7 @@ static inline void shada_initialize_registers(WriteMergerState *const wms,
yankreg_T reg;
char name = NUL;
bool is_unnamed = false;
- reg_iter = op_register_iter(reg_iter, &name, &reg, &is_unnamed);
+ reg_iter = op_global_reg_iter(reg_iter, &name, &reg, &is_unnamed);
if (name == NUL) {
break;
}
@@ -2552,6 +2543,19 @@ static inline void replace_numbered_mark(WriteMergerState *const wms,
wms->numbered_marks[idx].data.data.filemark.name = (char)('0' + (int)idx);
}
+/// Find buffers ignored due to their location.
+///
+/// @param[out] removable_bufs Cache of buffers ignored due to their location.
+static inline void find_removable_bufs(khash_t(bufset) *removable_bufs)
+{
+ FOR_ALL_BUFFERS(buf) {
+ if (buf->b_ffname != NULL && shada_removable((char *)buf->b_ffname)) {
+ int kh_ret;
+ (void)kh_put(bufset, removable_bufs, (uintptr_t)buf, &kh_ret);
+ }
+ }
+}
+
/// Write ShaDa file
///
/// @param[in] sd_writer Structure containing file writer definition.
@@ -2621,12 +2625,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
set_last_cursor(wp);
}
- FOR_ALL_BUFFERS(buf) {
- if (buf->b_ffname != NULL && shada_removable((char *) buf->b_ffname)) {
- int kh_ret;
- (void) kh_put(bufset, &removable_bufs, (uintptr_t) buf, &kh_ret);
- }
- }
+ find_removable_bufs(&removable_bufs);
// Write header
if (shada_pack_entry(packer, (ShadaEntry) {
@@ -2673,7 +2672,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
do {
typval_T vartv;
const char *name = NULL;
- var_iter = var_shada_iter(var_iter, &name, &vartv);
+ var_iter = var_shada_iter(var_iter, &name, &vartv, VAR_FLAVOUR_SHADA);
if (name == NULL) {
break;
}
@@ -2737,49 +2736,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer,
}
// Initialize jump list
- const void *jump_iter = NULL;
- cleanup_jumplist(curwin, false);
- setpcmark();
- do {
- xfmark_T fm;
- jump_iter = mark_jumplist_iter(jump_iter, curwin, &fm);
-
- if (fm.fmark.mark.lnum == 0) {
- iemsgf("ShaDa: mark lnum zero (ji:%p, js:%p, len:%i)",
- (void *)jump_iter, (void *)&curwin->w_jumplist[0],
- curwin->w_jumplistlen);
- continue;
- }
- const buf_T *const buf = (fm.fmark.fnum == 0
- ? NULL
- : buflist_findnr(fm.fmark.fnum));
- if (buf != NULL
- ? in_bufset(&removable_bufs, buf)
- : fm.fmark.fnum != 0) {
- continue;
- }
- const char *const fname = (char *) (fm.fmark.fnum == 0
- ? (fm.fname == NULL ? NULL : fm.fname)
- : buf->b_ffname);
- if (fname == NULL) {
- continue;
- }
- wms->jumps[wms->jumps_size++] = (PossiblyFreedShadaEntry) {
- .can_free_entry = false,
- .data = {
- .type = kSDItemJump,
- .timestamp = fm.fmark.timestamp,
- .data = {
- .filemark = {
- .name = NUL,
- .mark = fm.fmark.mark,
- .fname = (char *) fname,
- .additional_data = fm.fmark.additional_data,
- }
- }
- }
- };
- } while (jump_iter != NULL);
+ wms->jumps_size = shada_init_jumps(wms->jumps, &removable_bufs);
// Initialize global marks
if (dump_global_marks) {
@@ -4117,3 +4074,236 @@ static bool shada_removable(const char *name)
xfree(new_name);
return retval;
}
+
+/// Initialize ShaDa jumplist entries.
+///
+/// @param[in,out] jumps Array of ShaDa entries to set.
+/// @param[in] removable_bufs Cache of buffers ignored due to their
+/// location.
+///
+/// @return number of jumplist entries
+static inline size_t shada_init_jumps(
+ PossiblyFreedShadaEntry *jumps, khash_t(bufset) *const removable_bufs)
+{
+ // Initialize jump list
+ size_t jumps_size = 0;
+ const void *jump_iter = NULL;
+ setpcmark();
+ cleanup_jumplist(curwin, false);
+ do {
+ xfmark_T fm;
+ jump_iter = mark_jumplist_iter(jump_iter, curwin, &fm);
+
+ if (fm.fmark.mark.lnum == 0) {
+ iemsgf("ShaDa: mark lnum zero (ji:%p, js:%p, len:%i)",
+ (void *)jump_iter, (void *)&curwin->w_jumplist[0],
+ curwin->w_jumplistlen);
+ continue;
+ }
+ const buf_T *const buf = (fm.fmark.fnum == 0
+ ? NULL
+ : buflist_findnr(fm.fmark.fnum));
+ if (buf != NULL
+ ? in_bufset(removable_bufs, buf)
+ : fm.fmark.fnum != 0) {
+ continue;
+ }
+ const char *const fname = (char *) (fm.fmark.fnum == 0
+ ? (fm.fname == NULL ? NULL : fm.fname)
+ : buf->b_ffname);
+ if (fname == NULL) {
+ continue;
+ }
+ jumps[jumps_size++] = (PossiblyFreedShadaEntry) {
+ .can_free_entry = false,
+ .data = {
+ .type = kSDItemJump,
+ .timestamp = fm.fmark.timestamp,
+ .data = {
+ .filemark = {
+ .name = NUL,
+ .mark = fm.fmark.mark,
+ .fname = (char *) fname,
+ .additional_data = fm.fmark.additional_data,
+ }
+ }
+ }
+ };
+ } while (jump_iter != NULL);
+ return jumps_size;
+}
+
+/// Write registers ShaDa entries in given msgpack_sbuffer.
+///
+/// @param[in] sbuf target msgpack_sbuffer to write to.
+void shada_encode_regs(msgpack_sbuffer *const sbuf)
+ FUNC_ATTR_NONNULL_ALL
+{
+ WriteMergerState *const wms = xcalloc(1, sizeof(*wms));
+ shada_initialize_registers(wms, -1);
+ msgpack_packer packer;
+ msgpack_packer_init(&packer, sbuf, msgpack_sbuffer_write);
+ for (size_t i = 0; i < ARRAY_SIZE(wms->registers); i++) {
+ if (wms->registers[i].data.type == kSDItemRegister) {
+ if (kSDWriteFailed
+ == shada_pack_pfreed_entry(&packer, wms->registers[i], 0)) {
+ abort();
+ }
+ }
+ }
+ xfree(wms);
+}
+
+/// Write jumplist ShaDa entries in given msgpack_sbuffer.
+///
+/// @param[in] sbuf target msgpack_sbuffer to write to.
+void shada_encode_jumps(msgpack_sbuffer *const sbuf)
+ FUNC_ATTR_NONNULL_ALL
+{
+ khash_t(bufset) removable_bufs = KHASH_EMPTY_TABLE(bufset);
+ find_removable_bufs(&removable_bufs);
+ PossiblyFreedShadaEntry jumps[JUMPLISTSIZE];
+ size_t jumps_size = shada_init_jumps(jumps, &removable_bufs);
+ msgpack_packer packer;
+ msgpack_packer_init(&packer, sbuf, msgpack_sbuffer_write);
+ for (size_t i = 0; i < jumps_size; i++) {
+ if (kSDWriteFailed == shada_pack_pfreed_entry(&packer, jumps[i], 0)) {
+ abort();
+ }
+ }
+}
+
+/// Write buffer list ShaDa entry in given msgpack_sbuffer.
+///
+/// @param[in] sbuf target msgpack_sbuffer to write to.
+void shada_encode_buflist(msgpack_sbuffer *const sbuf)
+ FUNC_ATTR_NONNULL_ALL
+{
+ khash_t(bufset) removable_bufs = KHASH_EMPTY_TABLE(bufset);
+ find_removable_bufs(&removable_bufs);
+ ShadaEntry buflist_entry = shada_get_buflist(&removable_bufs);
+ msgpack_packer packer;
+ msgpack_packer_init(&packer, sbuf, msgpack_sbuffer_write);
+ if (kSDWriteFailed == shada_pack_entry(&packer, buflist_entry, 0)) {
+ abort();
+ }
+ xfree(buflist_entry.data.buffer_list.buffers);
+}
+
+/// Write global variables ShaDa entries in given msgpack_sbuffer.
+///
+/// @param[in] sbuf target msgpack_sbuffer to write to.
+void shada_encode_gvars(msgpack_sbuffer *const sbuf)
+ FUNC_ATTR_NONNULL_ALL
+{
+ msgpack_packer packer;
+ msgpack_packer_init(&packer, sbuf, msgpack_sbuffer_write);
+ const void *var_iter = NULL;
+ const Timestamp cur_timestamp = os_time();
+ 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);
+ if (name == NULL) {
+ break;
+ }
+ if (vartv.v_type != VAR_FUNC && vartv.v_type != VAR_PARTIAL) {
+ typval_T tgttv;
+ tv_copy(&vartv, &tgttv);
+ ShaDaWriteResult r = shada_pack_entry(&packer, (ShadaEntry) {
+ .type = kSDItemVariable,
+ .timestamp = cur_timestamp,
+ .data = {
+ .global_var = {
+ .name = (char *)name,
+ .value = tgttv,
+ .additional_elements = NULL,
+ }
+ }
+ }, 0);
+ if (kSDWriteFailed == r) {
+ abort();
+ }
+ tv_clear(&tgttv);
+ }
+ tv_clear(&vartv);
+ } while (var_iter != NULL);
+}
+
+/// 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)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ msgpack_sbuffer *sbuf = (msgpack_sbuffer *)sd_reader->cookie;
+ const uintmax_t bytes_read = MIN(size, sbuf->size - sd_reader->fpos);
+ if (bytes_read < size) {
+ sd_reader->eof = true;
+ }
+ memcpy(dest, sbuf->data + sd_reader->fpos, (size_t)bytes_read);
+ sd_reader->fpos += bytes_read;
+ return (ptrdiff_t)bytes_read;
+}
+
+/// Wrapper for read that ignores bytes read from msgpack_sbuffer.
+///
+/// Used for skipping.
+///
+/// @param[in,out] sd_reader ShaDaReadDef with msgpack_sbuffer.
+/// @param[in] offset Amount of bytes to skip.
+///
+/// @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)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ msgpack_sbuffer *sbuf = (msgpack_sbuffer *)sd_reader->cookie;
+ assert(sbuf->size >= sd_reader->fpos);
+ const uintmax_t skip_bytes = MIN(offset, sbuf->size - sd_reader->fpos);
+ if (skip_bytes < offset) {
+ sd_reader->eof = true;
+ return FAIL;
+ }
+ sd_reader->fpos += offset;
+ return OK;
+}
+
+/// Prepare ShaDaReadDef with msgpack_sbuffer for reading.
+///
+/// @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)
+ FUNC_ATTR_NONNULL_ALL
+{
+ *sd_reader = (ShaDaReadDef) {
+ .read = &read_sbuf,
+ .close = NULL,
+ .skip = &sd_sbuf_reader_skip_read,
+ .error = NULL,
+ .eof = false,
+ .fpos = 0,
+ .cookie = (void *)sbuf,
+ };
+}
+
+/// Read ShaDa from msgpack_sbuffer.
+///
+/// @param[in] file msgpack_sbuffer to read from.
+/// @param[in] flags Flags, see ShaDaReadFileFlags enum.
+void shada_read_sbuf(msgpack_sbuffer *const sbuf, const int flags)
+ FUNC_ATTR_NONNULL_ALL
+{
+ assert(sbuf != NULL);
+ if (sbuf->data == NULL) {
+ return;
+ }
+ ShaDaReadDef sd_reader;
+ open_shada_sbuf_for_reading(sbuf, &sd_reader);
+ shada_read(&sd_reader, flags);
+}
diff --git a/src/nvim/shada.h b/src/nvim/shada.h
index 49986ac1c1..2a945a06bc 100644
--- a/src/nvim/shada.h
+++ b/src/nvim/shada.h
@@ -1,6 +1,17 @@
#ifndef NVIM_SHADA_H
#define NVIM_SHADA_H
+#include <msgpack.h>
+
+/// Flags for shada_read_file and children
+typedef enum {
+ kShaDaWantInfo = 1, ///< Load non-mark information
+ kShaDaWantMarks = 2, ///< Load local file marks and change list
+ kShaDaForceit = 4, ///< Overwrite info already read
+ kShaDaGetOldfiles = 8, ///< Load v:oldfiles.
+ kShaDaMissingError = 16, ///< Error out when os_open returns -ENOENT.
+} ShaDaReadFileFlags;
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "shada.h.generated.h"
#endif
diff --git a/src/nvim/sign.c b/src/nvim/sign.c
index 8c85fbdaa7..16ab00a52b 100644
--- a/src/nvim/sign.c
+++ b/src/nvim/sign.c
@@ -28,9 +28,6 @@ struct sign
int sn_typenr; // type number of sign
char_u *sn_name; // name of sign
char_u *sn_icon; // name of pixmap
-# ifdef FEAT_SIGN_ICONS
- void *sn_image; // icon image
-# endif
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
@@ -83,11 +80,8 @@ static signgroup_T * sign_group_ref(const char_u *groupname)
hi = hash_lookup(&sg_table, (char *)groupname, STRLEN(groupname), hash);
if (HASHITEM_EMPTY(hi)) {
// new group
- group = (signgroup_T *)xmalloc(
- (unsigned)(sizeof(signgroup_T) + STRLEN(groupname)));
- if (group == NULL) {
- return NULL;
- }
+ group = xmalloc((unsigned)(sizeof(signgroup_T) + STRLEN(groupname)));
+
STRCPY(group->sg_name, groupname);
group->refcount = 1;
group->next_sign_id = 1;
@@ -188,10 +182,6 @@ static void insert_sign(
newsign->typenr = typenr;
if (group != NULL) {
newsign->group = sign_group_ref(group);
- if (newsign->group == NULL) {
- xfree(newsign);
- return;
- }
} else {
newsign->group = NULL;
}
@@ -263,11 +253,7 @@ char_u * sign_typenr2name(int typenr)
/// Return information about a sign in a Dict
dict_T * sign_get_info(signlist_T *sign)
{
- dict_T *d;
-
- if ((d = tv_dict_alloc()) == NULL) {
- return NULL;
- }
+ dict_T *d = tv_dict_alloc();
tv_dict_add_nr(d, S_LEN("id"), sign->id);
tv_dict_add_str(d, S_LEN("group"), ((sign->group == NULL)
? (char *)""
@@ -696,15 +682,6 @@ static void sign_define_init_icon(sign_T *sp, char_u *icon)
xfree(sp->sn_icon);
sp->sn_icon = vim_strsave(icon);
backslash_halve(sp->sn_icon);
-# ifdef FEAT_SIGN_ICONS
- if (gui.in_use) {
- out_flush();
- if (sp->sn_image != NULL) {
- gui_mch_destroy_sign(sp->sn_image);
- }
- sp->sn_image = gui_mch_register_sign(sp->sn_icon);
- }
-# endif
}
/// Initialize the text for a new sign
@@ -1347,8 +1324,8 @@ static void sign_getinfo(sign_T *sp, dict_T *retdict)
/// Otherwise, return information about the specified sign.
void sign_getlist(const char_u *name, list_T *retlist)
{
- sign_T *sp = first_sign;
- dict_T *dict;
+ sign_T *sp = first_sign;
+ dict_T *dict;
if (name != NULL) {
sp = sign_find(name, NULL);
@@ -1358,9 +1335,7 @@ void sign_getlist(const char_u *name, list_T *retlist)
}
for (; sp != NULL && !got_int; sp = sp->sn_next) {
- if ((dict = tv_dict_alloc()) == NULL) {
- return;
- }
+ dict = tv_dict_alloc();
tv_list_append_dict(retlist, dict);
sign_getinfo(sp, dict);
@@ -1374,14 +1349,13 @@ void sign_getlist(const char_u *name, list_T *retlist)
list_T *get_buffer_signs(buf_T *buf)
FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
- signlist_T *sign;
- dict_T *d;
+ signlist_T *sign;
+ dict_T *d;
list_T *const l = tv_list_alloc(kListLenMayKnow);
FOR_ALL_SIGNS_IN_BUF(buf, sign) {
- if ((d = sign_get_info(sign)) != NULL) {
- tv_list_append_dict(l, d);
- }
+ d = sign_get_info(sign);
+ tv_list_append_dict(l, d);
}
return l;
}
@@ -1394,21 +1368,16 @@ static void sign_get_placed_in_buf(
const char_u *sign_group,
list_T *retlist)
{
- dict_T *d;
- list_T *l;
- signlist_T *sign;
- dict_T *sdict;
+ dict_T *d;
+ list_T *l;
+ signlist_T *sign;
- if ((d = tv_dict_alloc()) == NULL) {
- return;
- }
+ d = tv_dict_alloc();
tv_list_append_dict(retlist, d);
tv_dict_add_nr(d, S_LEN("bufnr"), (long)buf->b_fnum);
- if ((l = tv_list_alloc(kListLenMayKnow)) == NULL) {
- return;
- }
+ l = tv_list_alloc(kListLenMayKnow);
tv_dict_add_list(d, S_LEN("signs"), l);
FOR_ALL_SIGNS_IN_BUF(buf, sign) {
@@ -1419,9 +1388,7 @@ static void sign_get_placed_in_buf(
|| (sign_id == 0 && lnum == sign->lnum)
|| (lnum == 0 && sign_id == sign->id)
|| (lnum == sign->lnum && sign_id == sign->id)) {
- if ((sdict = sign_get_info(sign)) != NULL) {
- tv_list_append_dict(l, sdict);
- }
+ tv_list_append_dict(l, sign_get_info(sign));
}
}
}
@@ -1448,21 +1415,6 @@ void sign_get_placed(
}
}
-# if defined(FEAT_SIGN_ICONS) || defined(PROTO)
-/// Allocate the icons. Called when the GUI has started. Allows defining
-/// signs before it starts.
-void sign_gui_started(void)
-{
- sign_T *sp;
-
- for (sp = first_sign; sp != NULL; sp = sp->sn_next) {
- if (sp->sn_icon != NULL) {
- sp->sn_image = gui_mch_register_sign(sp->sn_icon);
- }
- }
-}
-# endif
-
/// List one sign.
static void sign_list_defined(sign_T *sp)
{
@@ -1566,22 +1518,6 @@ char_u * sign_get_text(int typenr)
return NULL;
}
-# if defined(FEAT_SIGN_ICONS) || defined(PROTO)
-void * sign_get_image(
- int typenr // the attribute which may have a sign
-)
-{
- sign_T *sp;
-
- for (sp = first_sign; sp != NULL; sp = sp->sn_next) {
- if (sp->sn_typenr == typenr) {
- return sp->sn_image;
- }
- }
- return NULL;
-}
-# endif
-
/// Undefine/free all signs.
void free_signs(void)
{
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 6fd22a6537..8d800843f8 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -84,6 +84,7 @@
#include "nvim/ascii.h"
#include "nvim/spell.h"
#include "nvim/buffer.h"
+#include "nvim/change.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
#include "nvim/edit.h"
@@ -1626,7 +1627,7 @@ static void spell_load_lang(char_u *lang)
if (starting) {
// Prompt the user at VimEnter if spell files are missing. #3027
// Plugins aren't loaded yet, so spellfile.vim cannot handle this case.
- char autocmd_buf[128] = { 0 };
+ char autocmd_buf[512] = { 0 };
snprintf(autocmd_buf, sizeof(autocmd_buf),
"autocmd VimEnter * call spellfile#LoadFile('%s')|set spell",
lang);
@@ -1807,9 +1808,11 @@ void count_common_word(slang_T *lp, char_u *word, int len, int count)
char_u buf[MAXWLEN];
char_u *p;
- if (len == -1)
+ if (len == -1) {
p = word;
- else {
+ } else if (len >= MAXWLEN) {
+ return;
+ } else {
STRLCPY(buf, word, len + 1);
p = buf;
}
@@ -2616,7 +2619,7 @@ static bool spell_mb_isword_class(int cl, win_T *wp)
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;
+ return cl >= 2 && cl != 0x2070 && cl != 0x2080 && cl != 3;
}
// Returns true if "p" points to a word character.
@@ -3262,7 +3265,7 @@ static void spell_suggest_file(suginfo_T *su, char_u *fname)
char_u cword[MAXWLEN];
// Open the file.
- fd = mch_fopen((char *)fname, "r");
+ fd = os_fopen((char *)fname, "r");
if (fd == NULL) {
EMSG2(_(e_notopen), fname);
return;
@@ -4500,7 +4503,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
sp->ts_state = STATE_SWAP3;
break;
}
- if (c2 != NUL && TRY_DEEPER(su, stack, depth, SCORE_SWAP)) {
+ if (TRY_DEEPER(su, stack, depth, SCORE_SWAP)) {
go_deeper(stack, depth, SCORE_SWAP);
#ifdef DEBUG_TRIEWALK
snprintf(changename[depth], sizeof(changename[0]),
@@ -5283,7 +5286,7 @@ add_sound_suggest (
}
// Go over the list of good words that produce this soundfold word
- nrline = ml_get_buf(slang->sl_sugbuf, (linenr_T)(sfwordnr + 1), FALSE);
+ nrline = ml_get_buf(slang->sl_sugbuf, (linenr_T)sfwordnr + 1, false);
orgnr = 0;
while (*nrline != NUL) {
// The wordnr was stored in a minimal nr of bytes as an offset to the
diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c
index 5f5f74cf2e..405e390589 100644
--- a/src/nvim/spellfile.c
+++ b/src/nvim/spellfile.c
@@ -586,7 +586,7 @@ spell_load_file (
int c = 0;
int res;
- fd = mch_fopen((char *)fname, "r");
+ fd = os_fopen((char *)fname, "r");
if (fd == NULL) {
if (!silent)
EMSG2(_(e_notopen), fname);
@@ -885,9 +885,10 @@ void suggest_load_files(void)
continue;
}
STRCPY(dotp, ".sug");
- fd = mch_fopen((char *)slang->sl_fname, "r");
- if (fd == NULL)
+ fd = os_fopen((char *)slang->sl_fname, "r");
+ if (fd == NULL) {
goto nextone;
+ }
// <SUGHEADER>: <fileID> <versionnr> <timestamp>
for (i = 0; i < VIMSUGMAGICL; ++i)
@@ -1984,7 +1985,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
char_u *sofoto = NULL; // SOFOTO value
// Open the file.
- fd = mch_fopen((char *)fname, "r");
+ fd = os_fopen((char *)fname, "r");
if (fd == NULL) {
EMSG2(_(e_notopen), fname);
return NULL;
@@ -3019,7 +3020,7 @@ static int spell_read_dic(spellinfo_T *spin, char_u *fname, afffile_T *affile)
int duplicate = 0;
// Open the file.
- fd = mch_fopen((char *)fname, "r");
+ fd = os_fopen((char *)fname, "r");
if (fd == NULL) {
EMSG2(_(e_notopen), fname);
return FAIL;
@@ -3539,7 +3540,7 @@ static int spell_read_wordfile(spellinfo_T *spin, char_u *fname)
int regionmask;
// Open the file.
- fd = mch_fopen((char *)fname, "r");
+ fd = os_fopen((char *)fname, "r");
if (fd == NULL) {
EMSG2(_(e_notopen), fname);
return FAIL;
@@ -4185,7 +4186,7 @@ static int write_vim_spell(spellinfo_T *spin, char_u *fname)
int retval = OK;
int regionmask;
- FILE *fd = mch_fopen((char *)fname, "w");
+ FILE *fd = os_fopen((char *)fname, "w");
if (fd == NULL) {
EMSG2(_(e_notopen), fname);
return FAIL;
@@ -4986,7 +4987,7 @@ static int offset2bytes(int nr, char_u *buf)
static void sug_write(spellinfo_T *spin, char_u *fname)
{
// Create the file. Note that an existing file is silently overwritten!
- FILE *fd = mch_fopen((char *)fname, "w");
+ FILE *fd = os_fopen((char *)fname, "w");
if (fd == NULL) {
EMSG2(_(e_notopen), fname);
return;
@@ -5365,7 +5366,7 @@ spell_add_word (
if (bad || undo) {
// When the word appears as good word we need to remove that one,
// since its flags sort before the one with WF_BANNED.
- fd = mch_fopen((char *)fname, "r");
+ fd = os_fopen((char *)fname, "r");
if (fd != NULL) {
while (!vim_fgets(line, MAXWLEN * 2, fd)) {
fpos = fpos_next;
@@ -5376,7 +5377,7 @@ spell_add_word (
// the start of the line. Mixing reading and writing
// doesn't work for all systems, close the file first.
fclose(fd);
- fd = mch_fopen((char *)fname, "r+");
+ fd = os_fopen((char *)fname, "r+");
if (fd == NULL) {
break;
}
@@ -5399,7 +5400,7 @@ spell_add_word (
}
if (!undo) {
- fd = mch_fopen((char *)fname, "a");
+ fd = os_fopen((char *)fname, "a");
if (fd == NULL && new_spf) {
char_u *p;
@@ -5415,7 +5416,7 @@ spell_add_word (
*p = NUL;
os_mkdir((char *)fname, 0755);
*p = c;
- fd = mch_fopen((char *)fname, "a");
+ fd = os_fopen((char *)fname, "a");
}
}
diff --git a/src/nvim/state.c b/src/nvim/state.c
index e6eeaac8d0..7c7d035366 100644
--- a/src/nvim/state.c
+++ b/src/nvim/state.c
@@ -143,7 +143,7 @@ char *get_mode(void)
}
if (ins_compl_active()) {
buf[1] = 'c';
- } else if (ctrl_x_mode == 1) {
+ } else if (ctrl_x_mode_not_defined_yet()) {
buf[1] = 'x';
}
}
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index 418756abc4..4fa70c0684 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -14,6 +14,7 @@
#include "nvim/vim.h"
#include "nvim/ascii.h"
+#include "nvim/api/private/helpers.h"
#include "nvim/syntax.h"
#include "nvim/charset.h"
#include "nvim/cursor_shape.h"
@@ -75,6 +76,8 @@ struct hl_group {
uint8_t *sg_rgb_fg_name; ///< RGB foreground color name
uint8_t *sg_rgb_bg_name; ///< RGB background color name
uint8_t *sg_rgb_sp_name; ///< RGB special color name
+
+ int sg_blend; ///< blend level (0-100 inclusive), -1 if unset
};
/// \addtogroup SG_SET
@@ -348,7 +351,7 @@ static reg_extmatch_T *next_match_extmatch = NULL;
/*
* A state stack is an array of integers or stateitem_T, stored in a
- * garray_T. A state stack is invalid if it's itemsize entry is zero.
+ * garray_T. A state stack is invalid if its itemsize entry is zero.
*/
#define INVALID_STATE(ssp) ((ssp)->ga_itemsize == 0)
#define VALID_STATE(ssp) ((ssp)->ga_itemsize != 0)
@@ -997,6 +1000,7 @@ static void syn_stack_free_block(synblock_T *block)
clear_syn_state(p);
}
XFREE_CLEAR(block->b_sst_array);
+ block->b_sst_first = NULL;
block->b_sst_len = 0;
}
}
@@ -1108,9 +1112,6 @@ static void syn_stack_apply_changes_block(synblock_T *block, buf_T *buf)
synstate_T *p, *prev, *np;
linenr_T n;
- if (block->b_sst_array == NULL) /* nothing to do */
- return;
-
prev = NULL;
for (p = block->b_sst_first; p != NULL; ) {
if (p->sst_lnum + block->b_syn_sync_linebreaks > buf->b_mod_top) {
@@ -1158,8 +1159,9 @@ static int syn_stack_cleanup(void)
int dist;
int retval = FALSE;
- if (syn_block->b_sst_array == NULL || syn_block->b_sst_first == NULL)
+ if (syn_block->b_sst_first == NULL) {
return retval;
+ }
/* Compute normal distance between non-displayed entries. */
if (syn_block->b_sst_len <= Rows)
@@ -2923,8 +2925,9 @@ static int syn_regexec(regmmatch_T *rmp, linenr_T lnum, colnr_T col, syn_time_T
if (r > 0)
++st->match;
}
- if (timed_out) {
+ if (timed_out && !syn_win->w_s->b_syn_slow) {
syn_win->w_s->b_syn_slow = true;
+ MSG(_("'redrawtime' exceeded, syntax highlighting disabled"));
}
if (r > 0) {
@@ -3124,11 +3127,11 @@ static void syn_cmd_iskeyword(exarg_T *eap, int syncing)
arg = skipwhite(arg);
if (*arg == NUL) {
MSG_PUTS("\n");
- MSG_PUTS(_("syntax iskeyword "));
if (curwin->w_s->b_syn_isk != empty_option) {
+ MSG_PUTS(_("syntax iskeyword "));
msg_outtrans(curwin->w_s->b_syn_isk);
} else {
- msg_outtrans((char_u *)"not set");
+ msg_outtrans((char_u *)_("syntax iskeyword not set"));
}
} else {
if (STRNICMP(arg, "clear", 5) == 0) {
@@ -3606,7 +3609,7 @@ syn_list_one(
continue;
}
- (void)syn_list_header(did_header, 999, id);
+ (void)syn_list_header(did_header, 0, id, true);
did_header = true;
last_matchgroup = 0;
if (spp->sp_type == SPTYPE_MATCH) {
@@ -3655,7 +3658,7 @@ syn_list_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, 999, id);
+ (void)syn_list_header(did_header, 0, id, true);
msg_puts_attr("links to", attr);
msg_putchar(' ');
msg_outtrans(HL_TABLE()[HL_TABLE()[id - 1].sg_link - 1].sg_name);
@@ -3797,7 +3800,6 @@ static bool syn_list_keywords(
const int attr
)
{
- int outlen;
int prev_contained = 0;
const int16_t *prev_next_list = NULL;
const int16_t *prev_cont_in_list = NULL;
@@ -3815,17 +3817,20 @@ static bool syn_list_keywords(
todo--;
for (keyentry_T *kp = HI2KE(hi); kp != NULL && !got_int; kp = kp->ke_next) {
if (kp->k_syn.id == id) {
+ int outlen = 0;
+ bool force_newline = false;
if (prev_contained != (kp->flags & HL_CONTAINED)
|| prev_skipnl != (kp->flags & HL_SKIPNL)
|| prev_skipwhite != (kp->flags & HL_SKIPWHITE)
|| prev_skipempty != (kp->flags & HL_SKIPEMPTY)
|| prev_cont_in_list != kp->k_syn.cont_in_list
- || prev_next_list != kp->next_list)
- outlen = 9999;
- else
+ || prev_next_list != kp->next_list) {
+ force_newline = true;
+ } else {
outlen = (int)STRLEN(kp->keyword);
- /* output "contained" and "nextgroup" on each line */
- if (syn_list_header(did_header, outlen, id)) {
+ }
+ // output "contained" and "nextgroup" on each line
+ if (syn_list_header(did_header, outlen, id, force_newline)) {
prev_contained = 0;
prev_next_list = NULL;
prev_cont_in_list = NULL;
@@ -5968,6 +5973,10 @@ static const char *highlight_init_both[] = {
"default link Whitespace NonText",
"default link MsgSeparator StatusLine",
"default link NormalFloat Pmenu",
+ "RedrawDebugNormal cterm=reverse gui=reverse",
+ "RedrawDebugClear ctermbg=Yellow guibg=Yellow",
+ "RedrawDebugComposed ctermbg=Green guibg=Green",
+ "RedrawDebugRecompose ctermbg=Red guibg=Red",
NULL
};
@@ -6465,6 +6474,7 @@ void do_highlight(const char *line, const bool forceit, const bool init)
int id;
int idx;
struct hl_group item_before;
+ bool did_change = false;
bool dodefault = false;
bool doclear = false;
bool dolink = false;
@@ -6821,18 +6831,23 @@ void do_highlight(const char *line, const bool forceit, const bool init)
}
}
} else if (strcmp(key, "GUIFG") == 0) {
+ char_u **const namep = &HL_TABLE()[idx].sg_rgb_fg_name;
+
if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) {
if (!init) {
HL_TABLE()[idx].sg_set |= SG_GUI;
}
- xfree(HL_TABLE()[idx].sg_rgb_fg_name);
- if (strcmp(arg, "NONE")) {
- HL_TABLE()[idx].sg_rgb_fg_name = (char_u *)xstrdup((char *)arg);
- HL_TABLE()[idx].sg_rgb_fg = name_to_color((const char_u *)arg);
- } else {
- HL_TABLE()[idx].sg_rgb_fg_name = NULL;
- HL_TABLE()[idx].sg_rgb_fg = -1;
+ if (*namep == NULL || STRCMP(*namep, arg) != 0) {
+ xfree(*namep);
+ if (strcmp(arg, "NONE") != 0) {
+ *namep = (char_u *)xstrdup(arg);
+ HL_TABLE()[idx].sg_rgb_fg = name_to_color((char_u *)arg);
+ } else {
+ *namep = NULL;
+ HL_TABLE()[idx].sg_rgb_fg = -1;
+ }
+ did_change = true;
}
}
@@ -6840,18 +6855,23 @@ void do_highlight(const char *line, const bool forceit, const bool init)
normal_fg = HL_TABLE()[idx].sg_rgb_fg;
}
} else if (STRCMP(key, "GUIBG") == 0) {
+ char_u **const namep = &HL_TABLE()[idx].sg_rgb_bg_name;
+
if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) {
if (!init) {
HL_TABLE()[idx].sg_set |= SG_GUI;
}
- xfree(HL_TABLE()[idx].sg_rgb_bg_name);
- if (STRCMP(arg, "NONE") != 0) {
- HL_TABLE()[idx].sg_rgb_bg_name = (char_u *)xstrdup((char *)arg);
- HL_TABLE()[idx].sg_rgb_bg = name_to_color((const char_u *)arg);
- } else {
- HL_TABLE()[idx].sg_rgb_bg_name = NULL;
- HL_TABLE()[idx].sg_rgb_bg = -1;
+ if (*namep == NULL || STRCMP(*namep, arg) != 0) {
+ xfree(*namep);
+ if (STRCMP(arg, "NONE") != 0) {
+ *namep = (char_u *)xstrdup(arg);
+ HL_TABLE()[idx].sg_rgb_bg = name_to_color((char_u *)arg);
+ } else {
+ *namep = NULL;
+ HL_TABLE()[idx].sg_rgb_bg = -1;
+ }
+ did_change = true;
}
}
@@ -6859,18 +6879,23 @@ void do_highlight(const char *line, const bool forceit, const bool init)
normal_bg = HL_TABLE()[idx].sg_rgb_bg;
}
} else if (strcmp(key, "GUISP") == 0) {
+ char_u **const namep = &HL_TABLE()[idx].sg_rgb_sp_name;
+
if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) {
if (!init) {
HL_TABLE()[idx].sg_set |= SG_GUI;
}
- xfree(HL_TABLE()[idx].sg_rgb_sp_name);
- if (strcmp(arg, "NONE") != 0) {
- HL_TABLE()[idx].sg_rgb_sp_name = (char_u *)xstrdup((char *)arg);
- HL_TABLE()[idx].sg_rgb_sp = name_to_color((const char_u *)arg);
- } else {
- HL_TABLE()[idx].sg_rgb_sp_name = NULL;
- HL_TABLE()[idx].sg_rgb_sp = -1;
+ if (*namep == NULL || STRCMP(*namep, arg) != 0) {
+ xfree(*namep);
+ if (strcmp(arg, "NONE") != 0) {
+ *namep = (char_u *)xstrdup(arg);
+ HL_TABLE()[idx].sg_rgb_sp = name_to_color((char_u *)arg);
+ } else {
+ *namep = NULL;
+ HL_TABLE()[idx].sg_rgb_sp = -1;
+ }
+ did_change = true;
}
}
@@ -6879,6 +6904,12 @@ void do_highlight(const char *line, const bool forceit, const bool init)
}
} else if (strcmp(key, "START") == 0 || strcmp(key, "STOP") == 0) {
// Ignored for now
+ } else if (strcmp(key, "BLEND") == 0) {
+ if (strcmp(arg, "NONE") != 0) {
+ HL_TABLE()[idx].sg_blend = strtol(arg, NULL, 10);
+ } else {
+ HL_TABLE()[idx].sg_blend = -1;
+ }
} else {
emsgf(_("E423: Illegal argument: %s"), key_start);
error = true;
@@ -6926,9 +6957,15 @@ void do_highlight(const char *line, const bool forceit, const bool init)
// Only call highlight_changed() once, after a sequence of highlight
// commands, and only if an attribute actually changed
- if (memcmp(&HL_TABLE()[idx], &item_before, sizeof(item_before)) != 0
+ if ((did_change
+ || memcmp(&HL_TABLE()[idx], &item_before, sizeof(item_before)) != 0)
&& !did_highlight_changed) {
- redraw_all_later(NOT_VALID);
+ // Do not trigger a redraw when highlighting is changed while
+ // redrawing. This may happen when evaluating 'statusline' changes the
+ // StatusLine group.
+ if (!updating_screen) {
+ redraw_all_later(NOT_VALID);
+ }
need_highlight_changed = true;
}
}
@@ -6993,6 +7030,7 @@ static void highlight_clear(int idx)
XFREE_CLEAR(HL_TABLE()[idx].sg_rgb_fg_name);
XFREE_CLEAR(HL_TABLE()[idx].sg_rgb_bg_name);
XFREE_CLEAR(HL_TABLE()[idx].sg_rgb_sp_name);
+ HL_TABLE()[idx].sg_blend = -1;
// Clear the script ID only when there is no link, since that is not
// cleared.
if (HL_TABLE()[idx].sg_link == 0) {
@@ -7013,6 +7051,10 @@ static void highlight_list_one(const int id)
struct hl_group *const sgp = &HL_TABLE()[id - 1]; // index is ID minus one
bool didh = false;
+ if (message_filtered(sgp->sg_name)) {
+ return;
+ }
+
didh = highlight_list_arg(id, didh, LIST_ATTR,
sgp->sg_cterm, NULL, "cterm");
didh = highlight_list_arg(id, didh, LIST_INT,
@@ -7029,8 +7071,11 @@ static void highlight_list_one(const int id)
didh = highlight_list_arg(id, didh, LIST_STRING,
0, sgp->sg_rgb_sp_name, "guisp");
+ didh = highlight_list_arg(id, didh, LIST_INT,
+ sgp->sg_blend+1, NULL, "blend");
+
if (sgp->sg_link && !got_int) {
- (void)syn_list_header(didh, 9999, id);
+ (void)syn_list_header(didh, 0, id, true);
didh = true;
msg_puts_attr("links to", HL_ATTR(HLF_D));
msg_putchar(' ');
@@ -7075,7 +7120,8 @@ static bool highlight_list_arg(
}
}
- (void)syn_list_header(didh, (int)(vim_strsize(ts) + STRLEN(name) + 1), id);
+ (void)syn_list_header(didh, (int)(vim_strsize(ts) + STRLEN(name) + 1), id,
+ false);
didh = true;
if (!got_int) {
if (*name != NUL) {
@@ -7193,12 +7239,14 @@ const char *highlight_color(const int id, const char *const what,
/// @param did_header did header already
/// @param outlen length of string that comes
/// @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)
+ const int id, bool force_newline)
{
int endcol = 19;
bool newline = true;
+ bool adjust = true;
if (!did_header) {
msg_putchar('\n');
@@ -7207,7 +7255,10 @@ static bool syn_list_header(const bool did_header, const int outlen,
}
msg_outtrans(HL_TABLE()[id - 1].sg_name);
endcol = 15;
- } else if (msg_col + outlen + 1 >= Columns) {
+ } else if ((ui_has(kUIMessages) || msg_silent) && !force_newline) {
+ msg_putchar(' ');
+ adjust = false;
+ } else if (msg_col + outlen + 1 >= Columns || force_newline) {
msg_putchar('\n');
if (got_int) {
return true;
@@ -7218,12 +7269,14 @@ static bool syn_list_header(const bool did_header, const int outlen,
}
}
- if (msg_col >= endcol) /* output at least one space */
- endcol = msg_col + 1;
- if (Columns <= endcol) /* avoid hang for tiny window */
- endcol = Columns - 1;
+ if (adjust) {
+ if (msg_col >= endcol) {
+ // output at least one space
+ endcol = msg_col + 1;
+ }
- msg_advance(endcol);
+ msg_advance(endcol);
+ }
/* Show "xxx" with the attributes. */
if (!did_header) {
@@ -7252,6 +7305,7 @@ static void set_hl_attr(int idx)
at_en.rgb_fg_color = sgp->sg_rgb_fg_name ? sgp->sg_rgb_fg : -1;
at_en.rgb_bg_color = sgp->sg_rgb_bg_name ? sgp->sg_rgb_bg : -1;
at_en.rgb_sp_color = sgp->sg_rgb_sp_name ? sgp->sg_rgb_sp : -1;
+ at_en.hl_blend = sgp->sg_blend;
sgp->sg_attr = hl_get_syn_attr(idx+1, at_en);
@@ -7377,6 +7431,7 @@ static int syn_add_group(char_u *name)
hlgp->sg_rgb_bg = -1;
hlgp->sg_rgb_fg = -1;
hlgp->sg_rgb_sp = -1;
+ hlgp->sg_blend = -1;
hlgp->sg_name_u = vim_strsave_up(name);
return highlight_ga.ga_len; /* ID is index plus one */
@@ -7476,6 +7531,12 @@ void highlight_changed(void)
highlight_attr[hlf] = hl_get_ui_attr(hlf, final_id,
hlf == (int)HLF_INACTIVE);
+
+ if (highlight_attr[hlf] != highlight_attr_last[hlf]) {
+ ui_call_hl_group_set(cstr_as_string((char *)hlf_names[hlf]),
+ highlight_attr[hlf]);
+ highlight_attr_last[hlf] = highlight_attr[hlf];
+ }
}
/* Setup the user highlights
diff --git a/src/nvim/tag.c b/src/nvim/tag.c
index 6e883a1c3d..88676abc2e 100644
--- a/src/nvim/tag.c
+++ b/src/nvim/tag.c
@@ -1303,8 +1303,9 @@ find_tags (
}
}
- if ((fp = mch_fopen((char *)tag_fname, "r")) == NULL)
+ if ((fp = os_fopen((char *)tag_fname, "r")) == NULL) {
continue;
+ }
if (p_verbose >= 5) {
verbose_enter();
@@ -2235,8 +2236,13 @@ parse_match (
p = tagp->command;
if (find_extra(&p) == OK) {
tagp->command_end = p;
- p += 2; /* skip ";\"" */
- if (*p++ == TAB)
+ if (p > tagp->command && p[-1] == '|') {
+ tagp->command_end = p - 1; // drop trailing bar
+ } else {
+ tagp->command_end = p;
+ }
+ p += 2; // skip ";\""
+ if (*p++ == TAB) {
while (ASCII_ISALPHA(*p)) {
if (STRNCMP(p, "kind:", 5) == 0) {
tagp->tagkind = p + 5;
@@ -2252,6 +2258,7 @@ parse_match (
break;
p = pt + 1;
}
+ }
}
if (tagp->tagkind != NULL) {
for (p = tagp->tagkind;
@@ -2676,22 +2683,30 @@ static int find_extra(char_u **pp)
{
char_u *str = *pp;
- /* Repeat for addresses separated with ';' */
+ // Repeat for addresses separated with ';'
for (;; ) {
- if (ascii_isdigit(*str))
+ if (ascii_isdigit(*str)) {
str = skipdigits(str);
- else if (*str == '/' || *str == '?') {
- str = skip_regexp(str + 1, *str, FALSE, NULL);
- if (*str != **pp)
+ } else if (*str == '/' || *str == '?') {
+ str = skip_regexp(str + 1, *str, false, NULL);
+ if (*str != **pp) {
str = NULL;
- else
- ++str;
- } else
- str = NULL;
+ } else {
+ str++;
+ }
+ } else {
+ // not a line number or search string, look for terminator.
+ str = (char_u *)strstr((char *)str, "|;\"");
+ if (str != NULL) {
+ str++;
+ break;
+ }
+ }
if (str == NULL || *str != ';'
- || !(ascii_isdigit(str[1]) || str[1] == '/' || str[1] == '?'))
+ || !(ascii_isdigit(str[1]) || str[1] == '/' || str[1] == '?')) {
break;
- ++str; /* skip ';' */
+ }
+ str++; // skip ';'
}
if (str != NULL && STRNCMP(str, ";\"", 2) == 0) {
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index d8d529d0f6..5aeea3223b 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -53,6 +53,7 @@
#include "nvim/macros.h"
#include "nvim/mbyte.h"
#include "nvim/buffer.h"
+#include "nvim/change.h"
#include "nvim/ascii.h"
#include "nvim/getchar.h"
#include "nvim/ui.h"
@@ -1306,7 +1307,7 @@ static void refresh_screen(Terminal *term, buf_T *buf)
static void adjust_topline(Terminal *term, buf_T *buf, long added)
{
- FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ FOR_ALL_TAB_WINDOWS(tp, wp) {
if (wp->w_buffer == buf) {
linenr_T ml_end = buf->b_ml.ml_line_count;
bool following = ml_end == wp->w_cursor.lnum + added; // cursor at end?
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index 7b1f0f59cc..8b43d91e25 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -32,14 +32,12 @@ NEW_TESTS_ALOT := test_alot_utf8 test_alot
NEW_TESTS_IN_ALOT := $(shell sed '/^source/ s/^source //;s/\.vim$$//' test_alot*.vim)
# Ignored tests.
# test_alot_latin: Nvim does not allow setting encoding.
-# test_arglist: ported to Lua, but kept for easier merging.
# test_autochdir: ported to Lua, but kept for easier merging.
# test_eval_func: used as include in old-style test (test_eval.in).
# test_listlbr: Nvim does not allow setting encoding.
# test_largefile: uses too much resources to run on CI.
NEW_TESTS_IGNORE := $(NEW_TESTS_IN_ALOT) $(NEW_TESTS_ALOT) \
test_alot_latin \
- test_arglist \
test_autochdir \
test_eval_func \
test_listlbr \
@@ -101,23 +99,24 @@ RM_ON_RUN := test.out X* viminfo
RM_ON_START := test.ok
RUN_VIM := $(TOOL) $(NVIM_PRG) -u unix.vim -U NONE -i viminfo --headless --noplugin -s dotest.in
+CLEAN_FILES := *.out \
+ *.failed \
+ *.res \
+ *.rej \
+ *.orig \
+ *.tlog \
+ test.log \
+ messages \
+ $(RM_ON_RUN) \
+ $(RM_ON_START) \
+ valgrind.* \
+ .*.swp \
+ .*.swo \
+ .gdbinit \
+ $(TMPDIR) \
+ del
clean:
- -rm -rf *.out \
- *.failed \
- *.res \
- *.rej \
- *.orig \
- *.tlog \
- test.log \
- messages \
- $(RM_ON_RUN) \
- $(RM_ON_START) \
- valgrind.* \
- .*.swp \
- .*.swo \
- .gdbinit \
- $(TMPDIR) \
- del
+ $(RM) -rf $(CLEAN_FILES)
test1.out: .gdbinit test1.in
@echo "[OLDTEST-PREP] Running test1"
diff --git a/src/nvim/testdir/runnvim.vim b/src/nvim/testdir/runnvim.vim
index 396a3a6477..52e05cfbeb 100644
--- a/src/nvim/testdir/runnvim.vim
+++ b/src/nvim/testdir/runnvim.vim
@@ -20,7 +20,7 @@ function Main()
let results = jobwait([job], 5 * 60 * 1000)
" TODO(ZyX-I): Get colors
let screen = getline(1, '$')
- bwipeout!
+ bwipeout! " kills the job always.
let stringified_events = map(s:logger.d_events,
\'v:val[0] . ": " . ' .
\'join(map(v:val[1], '.
@@ -43,9 +43,6 @@ function Main()
\])
write
if results[0] != 0
- if results[0] != -1
- call jobstop(job)
- endif
cquit
else
qall
diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim
index aaddc90c99..c8161b1f9b 100644
--- a/src/nvim/testdir/runtest.vim
+++ b/src/nvim/testdir/runtest.vim
@@ -35,8 +35,11 @@ if &lines < 24 || &columns < 80
echoerr error
split test.log
$put =error
- w
- cquit
+ write
+ split messages
+ call append(line('$'), error)
+ write
+ qa!
endif
" Common with all tests on all systems.
@@ -121,7 +124,10 @@ func RunTheTest(test)
exe 'call ' . a:test
else
try
+ let s:test = a:test
+ au VimLeavePre * call EarlyExit(s:test)
exe 'call ' . a:test
+ au! VimLeavePre
catch /^\cskipped/
call add(s:messages, ' Skipped')
call add(s:skipped, 'SKIPPED ' . a:test . ': ' . substitute(v:exception, '^\S*\s\+', '', ''))
@@ -175,6 +181,15 @@ func AfterTheTest()
endif
endfunc
+func EarlyExit(test)
+ " It's OK for the test we use to test the quit detection.
+ if a:test != 'Test_zz_quit_detected()'
+ call add(v:errors, 'Test caused Vim to exit: ' . a:test)
+ endif
+
+ call FinishTesting()
+endfunc
+
" This function can be called by a test if it wants to abort testing.
func FinishTesting()
call AfterTheTest()
@@ -200,7 +215,11 @@ func FinishTesting()
write
endif
- let message = 'Executed ' . s:done . (s:done > 1 ? ' tests' : ' test')
+ if s:done == 0
+ let message = 'NO tests executed'
+ else
+ let message = 'Executed ' . s:done . (s:done > 1 ? ' tests' : ' test')
+ endif
echo message
call add(s:messages, message)
if s:fail > 0
@@ -244,7 +263,8 @@ else
endif
" Names of flaky tests.
-let s:flaky = [
+let s:flaky_tests = [
+ \ 'Test_cursorhold_insert()',
\ 'Test_exit_callback_interval()',
\ 'Test_oneshot()',
\ 'Test_out_cb()',
@@ -258,9 +278,11 @@ let s:flaky = [
\ 'Test_terminal_redir_file()',
\ 'Test_terminal_tmap()',
\ 'Test_with_partial_callback()',
- \ 'Test_lambda_with_timer()',
\ ]
+" Pattern indicating a common flaky test failure.
+let s:flaky_errors_re = 'StopVimInTerminal\|VerifyScreenDump'
+
" Locate Test_ functions and execute them.
redir @q
silent function /^Test_
@@ -285,7 +307,9 @@ for s:test in sort(s:tests)
" Repeat a flaky test. Give up when:
" - it fails again with the same message
" - it fails five times (with a different mesage)
- if len(v:errors) > 0 && index(s:flaky, s:test) >= 0
+ if len(v:errors) > 0
+ \ && (index(s:flaky_tests, s:test) >= 0
+ \ || v:errors[0] =~ s:flaky_errors_re)
while 1
call add(s:messages, 'Found errors in ' . s:test . ':')
call extend(s:messages, v:errors)
diff --git a/src/nvim/testdir/samples/memfile_test.c b/src/nvim/testdir/samples/memfile_test.c
index 3c8f108255..c71a5c8f40 100644
--- a/src/nvim/testdir/samples/memfile_test.c
+++ b/src/nvim/testdir/samples/memfile_test.c
@@ -70,7 +70,7 @@ test_mf_hash(void)
assert(mf_hash_find(&ht, key) == NULL);
/* allocate and add new item */
- item = (mf_hashitem_T *)lalloc_clear(sizeof(mf_hashtab_T), FALSE);
+ item = (mf_hashitem_T *)lalloc_clear(sizeof(*item), FALSE);
assert(item != NULL);
item->mhi_key = key;
mf_hash_add_item(&ht, item);
diff --git a/src/nvim/testdir/setup.vim b/src/nvim/testdir/setup.vim
index c75b00d5de..f79fb9e518 100644
--- a/src/nvim/testdir/setup.vim
+++ b/src/nvim/testdir/setup.vim
@@ -7,16 +7,19 @@ endif
let s:did_load = 1
" Align Nvim defaults to Vim.
-set sidescroll=0
-set directory^=.
-set undodir^=.
set backspace=
-set nrformats+=octal
-set nohidden smarttab noautoindent noautoread complete-=i noruler noshowcmd
-set listchars=eol:$
+set directory^=.
set fillchars=vert:\|,fold:-
-set shortmess-=F
set laststatus=1
+set listchars=eol:$
+set nohidden smarttab noautoindent noautoread complete-=i noruler noshowcmd
+set nrformats+=octal
+set shortmess-=F
+set sidescroll=0
+set tags=./tags,tags
+set undodir^=.
+set wildoptions=
+
" 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/shared.vim b/src/nvim/testdir/shared.vim
index eb6798f353..6cc2d06a36 100644
--- a/src/nvim/testdir/shared.vim
+++ b/src/nvim/testdir/shared.vim
@@ -133,7 +133,11 @@ func s:kill_server(cmd)
endif
endfunc
-" Wait for up to a second for "expr" to become true.
+" Wait for up to a second for "expr" to become true. "expr" can be a
+" stringified expression to evaluate, or a funcref without arguments.
+"
+" A second argument can be used to specify a different timeout in msec.
+"
" Return time slept in milliseconds. With the +reltime feature this can be
" more than the actual waiting time. Without +reltime it can also be less.
func WaitFor(expr, ...)
@@ -144,8 +148,13 @@ func WaitFor(expr, ...)
else
let slept = 0
endif
+ if type(a:expr) == v:t_func
+ let Test = a:expr
+ else
+ let Test = {-> eval(a:expr) }
+ endif
for i in range(timeout / 10)
- if eval(a:expr)
+ if Test()
if has('reltime')
return float2nr(reltimefloat(reltime(start)) * 1000)
endif
@@ -156,7 +165,7 @@ func WaitFor(expr, ...)
endif
sleep 10m
endfor
- return timeout
+ throw 'WaitFor() timed out after ' . timeout . ' msec'
endfunc
" Wait for up to a given milliseconds.
@@ -188,12 +197,18 @@ func s:feedkeys(timer)
endfunc
" Get the command to run Vim, with -u NONE and --headless arguments.
+" If there is an argument use it instead of "NONE".
" Returns an empty string on error.
-func GetVimCommand()
+func GetVimCommand(...)
+ if a:0 == 0
+ let name = 'NONE'
+ else
+ let name = a:1
+ endif
let cmd = v:progpath
- let cmd = substitute(cmd, '-u \f\+', '-u NONE', '')
- if cmd !~ '-u NONE'
- let cmd = cmd . ' -u NONE'
+ let cmd = substitute(cmd, '-u \f\+', '-u ' . name, '')
+ if cmd !~ '-u '. name
+ let cmd = cmd . ' -u ' . name
endif
let cmd .= ' --headless -i NONE'
let cmd = substitute(cmd, 'VIMRUNTIME=.*VIMRUNTIME;', '', '')
@@ -246,3 +261,7 @@ func! Screenline(lnum)
let line = join(chars, '')
return matchstr(line, '^.\{-}\ze\s*$')
endfunc
+
+func CanRunGui()
+ return has('gui') && ($DISPLAY != "" || has('gui_running'))
+endfunc
diff --git a/src/nvim/testdir/test49.vim b/src/nvim/testdir/test49.vim
index 467abcd9b9..837e55ebca 100644
--- a/src/nvim/testdir/test49.vim
+++ b/src/nvim/testdir/test49.vim
@@ -1,6 +1,6 @@
" Vim script language tests
" Author: Servatius Brandt <Servatius.Brandt@fujitsu-siemens.com>
-" Last Change: 2016 Feb 07
+" Last Change: 2019 May 24
"-------------------------------------------------------------------------------
" Test environment {{{1
@@ -9005,5 +9005,4 @@ Xcheck 50443995
"-------------------------------------------------------------------------------
" Modelines {{{1
" vim: ts=8 sw=4 tw=80 fdm=marker
-" vim: fdt=substitute(substitute(foldtext(),\ '\\%(^+--\\)\\@<=\\(\\s*\\)\\(.\\{-}\\)\:\ \\%(\"\ \\)\\=\\(Test\ \\d*\\)\:\\s*',\ '\\3\ (\\2)\:\ \\1',\ \"\"),\ '\\(Test\\s*\\)\\(\\d\\)\\D\\@=',\ '\\1\ \\2',\ "")
"-------------------------------------------------------------------------------
diff --git a/src/nvim/testdir/test_arabic.vim b/src/nvim/testdir/test_arabic.vim
index 17e925ee7f..d67f875f97 100644
--- a/src/nvim/testdir/test_arabic.vim
+++ b/src/nvim/testdir/test_arabic.vim
@@ -524,54 +524,6 @@ func Test_shape_final()
bwipe!
endfunc
-func Test_shape_final_to_medial()
- new
- set arabicshape
-
- " Shaping arabic {testchar} arabic Tests chg_c_f2m().
- " This does not test much...
- " pair[0] = testchar, pair[1] = current-result
- for pair in [[s:a_f_YEH_HAMZA, s:a_f_BEH],
- \[s:a_f_WAW_HAMZA, s:a_s_BEH],
- \[s:a_f_ALEF, s:a_s_BEH],
- \[s:a_f_TEH_MARBUTA, s:a_s_BEH],
- \[s:a_f_DAL, s:a_s_BEH],
- \[s:a_f_THAL, s:a_s_BEH],
- \[s:a_f_REH, s:a_s_BEH],
- \[s:a_f_ZAIN, s:a_s_BEH],
- \[s:a_f_WAW, s:a_s_BEH],
- \[s:a_f_ALEF_MAKSURA, s:a_s_BEH],
- \[s:a_f_BEH, s:a_f_BEH],
- \[s:a_f_TEH, s:a_f_BEH],
- \[s:a_f_THEH, s:a_f_BEH],
- \[s:a_f_JEEM, s:a_f_BEH],
- \[s:a_f_HAH, s:a_f_BEH],
- \[s:a_f_KHAH, s:a_f_BEH],
- \[s:a_f_SEEN, s:a_f_BEH],
- \[s:a_f_SHEEN, s:a_f_BEH],
- \[s:a_f_SAD, s:a_f_BEH],
- \[s:a_f_DAD, s:a_f_BEH],
- \[s:a_f_TAH, s:a_f_BEH],
- \[s:a_f_ZAH, s:a_f_BEH],
- \[s:a_f_AIN, s:a_f_BEH],
- \[s:a_f_GHAIN, s:a_f_BEH],
- \[s:a_f_FEH, s:a_f_BEH],
- \[s:a_f_QAF, s:a_f_BEH],
- \[s:a_f_KAF, s:a_f_BEH],
- \[s:a_f_LAM, s:a_f_BEH],
- \[s:a_f_MEEM, s:a_f_BEH],
- \[s:a_f_NOON, s:a_f_BEH],
- \[s:a_f_HEH, s:a_f_BEH],
- \[s:a_f_YEH, s:a_f_BEH],
- \ ]
- call setline(1, ' ' . s:a_BEH . pair[0])
- call assert_equal([' ' . pair[1] . pair[0]], ScreenLines(1, 3))
- endfor
-
- set arabicshape&
- bwipe!
-endfunc
-
func Test_shape_combination_final()
new
set arabicshape
diff --git a/src/nvim/testdir/test_arglist.vim b/src/nvim/testdir/test_arglist.vim
index 6468819198..df72ff0a32 100644
--- a/src/nvim/testdir/test_arglist.vim
+++ b/src/nvim/testdir/test_arglist.vim
@@ -74,7 +74,6 @@ func Test_argadd()
call assert_equal(1, len(argv()))
call assert_equal('some file', get(argv(), 0, ''))
- call delete('Xargadd')
%argd
new
arga
@@ -122,10 +121,7 @@ func Test_argument()
call assert_equal(['d', 'c', 'b', 'a', 'c'], g:buffers)
- redir => result
- ar
- redir END
- call assert_true(result =~# 'a b \[c] d')
+ call assert_equal("\na b [c] d ", execute(':args'))
.argd
call assert_equal(['a', 'b', 'd'], argv())
@@ -154,6 +150,25 @@ func Test_argument()
let &hidden = save_hidden
+ let save_columns = &columns
+ let &columns = 79
+ exe 'args ' .. join(range(1, 81))
+ call assert_equal(join([
+ \ '',
+ \ '[1] 6 11 16 21 26 31 36 41 46 51 56 61 66 71 76 81 ',
+ \ '2 7 12 17 22 27 32 37 42 47 52 57 62 67 72 77 ',
+ \ '3 8 13 18 23 28 33 38 43 48 53 58 63 68 73 78 ',
+ \ '4 9 14 19 24 29 34 39 44 49 54 59 64 69 74 79 ',
+ \ '5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 ',
+ \ ], "\n"),
+ \ execute('args'))
+
+ " No trailing newline with one item per row.
+ let long_arg = repeat('X', 81)
+ exe 'args ' .. long_arg
+ call assert_equal("\n[".long_arg.']', execute('args'))
+ let &columns = save_columns
+
" Setting argument list should fail when the current buffer has unsaved
" changes
%argd
@@ -171,6 +186,34 @@ func Test_argument()
call assert_fails('argument', 'E163:')
endfunc
+func Test_list_arguments()
+ " Clean the argument list
+ arga a | %argd
+
+ " four args half the screen width makes two lines with two columns
+ let aarg = repeat('a', &columns / 2 - 4)
+ let barg = repeat('b', &columns / 2 - 4)
+ let carg = repeat('c', &columns / 2 - 4)
+ let darg = repeat('d', &columns / 2 - 4)
+ exe 'argadd ' aarg barg carg darg
+
+ redir => result
+ args
+ redir END
+ call assert_match('\[' . aarg . '] \+' . carg . '\n' . barg . ' \+' . darg, trim(result))
+
+ " if one arg is longer than half the screen make one column
+ exe 'argdel' aarg
+ let aarg = repeat('a', &columns / 2 + 2)
+ exe '0argadd' aarg
+ redir => result
+ args
+ redir END
+ call assert_match(aarg . '\n\[' . barg . ']\n' . carg . '\n' . darg, trim(result))
+
+ %argdelete
+endfunc
+
func Test_args_with_quote()
" Only on Unix can a file name include a double quote.
if has('unix')
@@ -427,3 +470,19 @@ func Test_arg_all_expand()
call assert_equal('notexist Xx\ x runtest.vim', expand('##'))
call delete('Xx x')
endfunc
+
+func Test_large_arg()
+ " Argument longer or equal to the number of columns used to cause
+ " access to invalid memory.
+ exe 'argadd ' .repeat('x', &columns)
+ args
+endfunc
+
+func Test_argdo()
+ next! Xa.c Xb.c Xc.c
+ new
+ let l = []
+ argdo call add(l, expand('%'))
+ call assert_equal(['Xa.c', 'Xb.c', 'Xc.c'], l)
+ bwipe Xa.c Xb.c Xc.c
+endfunc
diff --git a/src/nvim/testdir/test_assert.vim b/src/nvim/testdir/test_assert.vim
new file mode 100644
index 0000000000..a4c8ce7e43
--- /dev/null
+++ b/src/nvim/testdir/test_assert.vim
@@ -0,0 +1,13 @@
+" Test that the methods used for testing work.
+
+func Test_assert_fails_in_try_block()
+ try
+ call assert_equal(0, assert_fails('throw "error"'))
+ endtry
+endfunc
+
+" Must be last.
+func Test_zz_quit_detected()
+ " Verify that if a test function ends Vim the test script detects this.
+ quit
+endfunc
diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim
index d66e237e45..b686d0292f 100644
--- a/src/nvim/testdir/test_autocmd.vim
+++ b/src/nvim/testdir/test_autocmd.vim
@@ -635,7 +635,8 @@ func Test_OptionSet()
" Cleanup
au! OptionSet
- for opt in ['nu', 'ai', 'acd', 'ar', 'bs', 'backup', 'cul', 'cp']
+ " set tags&
+ for opt in ['nu', 'ai', 'acd', 'ar', 'bs', 'backup', 'cul', 'cp', 'tags']
exe printf(":set %s&vim", opt)
endfor
call test_override('starting', 0)
@@ -1672,6 +1673,25 @@ func Test_ReadWrite_Autocmds()
call delete('test.out')
endfunc
+func Test_throw_in_BufWritePre()
+ new
+ call setline(1, ['one', 'two', 'three'])
+ call assert_false(filereadable('Xthefile'))
+ augroup throwing
+ au BufWritePre X* throw 'do not write'
+ augroup END
+ try
+ w Xthefile
+ catch
+ let caught = 1
+ endtry
+ call assert_equal(1, caught)
+ call assert_false(filereadable('Xthefile'))
+
+ bwipe!
+ au! throwing
+endfunc
+
func Test_FileChangedShell_reload()
if !has('unix')
return
diff --git a/src/nvim/testdir/test_bufline.vim b/src/nvim/testdir/test_bufline.vim
new file mode 100644
index 0000000000..b886e99506
--- /dev/null
+++ b/src/nvim/testdir/test_bufline.vim
@@ -0,0 +1,67 @@
+" Tests for setbufline() and getbufline()
+
+source shared.vim
+
+func Test_setbufline_getbufline()
+ new
+ let b = bufnr('%')
+ hide
+ call assert_equal(0, setbufline(b, 1, ['foo', 'bar']))
+ call assert_equal(['foo'], getbufline(b, 1))
+ call assert_equal(['bar'], getbufline(b, 2))
+ call assert_equal(['foo', 'bar'], getbufline(b, 1, 2))
+ exe "bd!" b
+ call assert_equal([], getbufline(b, 1, 2))
+
+ split Xtest
+ call setline(1, ['a', 'b', 'c'])
+ let b = bufnr('%')
+ wincmd w
+ call assert_equal(1, setbufline(b, 5, ['x']))
+ call assert_equal(1, setbufline(1234, 1, ['x']))
+ call assert_equal(0, setbufline(b, 4, ['d', 'e']))
+ call assert_equal(['c'], getbufline(b, 3))
+ call assert_equal(['d'], getbufline(b, 4))
+ call assert_equal(['e'], getbufline(b, 5))
+ call assert_equal([], getbufline(b, 6))
+ exe "bwipe! " . b
+endfunc
+
+func Test_setbufline_getbufline_fold()
+ split Xtest
+ setlocal foldmethod=expr foldexpr=0
+ let b = bufnr('%')
+ new
+ call assert_equal(0, setbufline(b, 1, ['foo', 'bar']))
+ call assert_equal(['foo'], getbufline(b, 1))
+ call assert_equal(['bar'], getbufline(b, 2))
+ call assert_equal(['foo', 'bar'], getbufline(b, 1, 2))
+ exe "bwipe!" b
+ bwipe!
+endfunc
+
+func Test_setbufline_getbufline_fold_tab()
+ split Xtest
+ setlocal foldmethod=expr foldexpr=0
+ let b = bufnr('%')
+ tab new
+ call assert_equal(0, setbufline(b, 1, ['foo', 'bar']))
+ call assert_equal(['foo'], getbufline(b, 1))
+ call assert_equal(['bar'], getbufline(b, 2))
+ call assert_equal(['foo', 'bar'], getbufline(b, 1, 2))
+ exe "bwipe!" b
+ bwipe!
+endfunc
+
+func Test_setline_startup()
+ let cmd = GetVimCommand('Xscript')
+ if cmd == ''
+ return
+ endif
+ call writefile(['call setline(1, "Hello")', 'silent w Xtest', 'q!'], 'Xscript')
+ call system(cmd)
+ call assert_equal(['Hello'], readfile('Xtest'))
+
+ call delete('Xscript')
+ call delete('Xtest')
+endfunc
diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim
index 75832a798c..4b333e444a 100644
--- a/src/nvim/testdir/test_cmdline.vim
+++ b/src/nvim/testdir/test_cmdline.vim
@@ -44,6 +44,42 @@ func Test_map_completion()
call assert_equal('"map <special> <nowait>', getreg(':'))
call feedkeys(":map <silent> <sp\<Tab>\<Home>\"\<CR>", 'xt')
call assert_equal('"map <silent> <special>', getreg(':'))
+
+ map ,f commaf
+ map ,g commaf
+ call feedkeys(":map ,\<Tab>\<Home>\"\<CR>", 'xt')
+ call assert_equal('"map ,f', getreg(':'))
+ call feedkeys(":map ,\<Tab>\<Tab>\<Home>\"\<CR>", 'xt')
+ call assert_equal('"map ,g', getreg(':'))
+ unmap ,f
+ unmap ,g
+
+ set cpo-=< cpo-=B cpo-=k
+ map <Left> left
+ call feedkeys(":map <L\<Tab>\<Home>\"\<CR>", 'xt')
+ call assert_equal('"map <Left>', getreg(':'))
+ unmap <Left>
+
+ " set cpo+=<
+ map <Left> left
+ call feedkeys(":map <L\<Tab>\<Home>\"\<CR>", 'xt')
+ call assert_equal('"map <Left>', getreg(':'))
+ unmap <Left>
+ set cpo-=<
+
+ set cpo+=B
+ map <Left> left
+ call feedkeys(":map <L\<Tab>\<Home>\"\<CR>", 'xt')
+ call assert_equal('"map <Left>', getreg(':'))
+ unmap <Left>
+ set cpo-=B
+
+ " set cpo+=k
+ map <Left> left
+ call feedkeys(":map <L\<Tab>\<Home>\"\<CR>", 'xt')
+ call assert_equal('"map <Left>', getreg(':'))
+ unmap <Left>
+ " set cpo-=k
endfunc
func Test_match_completion()
@@ -232,6 +268,15 @@ func Test_getcompletion()
let l = getcompletion('not', 'mapclear')
call assert_equal([], l)
+ let l = getcompletion('.', 'shellcmd')
+ call assert_equal(['./', '../'], l[0:1])
+ call assert_equal(-1, match(l[2:], '^\.\.\?/$'))
+ let root = has('win32') ? 'C:\\' : '/'
+ let l = getcompletion(root, 'shellcmd')
+ let expected = map(filter(glob(root . '*', 0, 1),
+ \ 'isdirectory(v:val) || executable(v:val)'), 'isdirectory(v:val) ? v:val . ''/'' : v:val')
+ call assert_equal(expected, l)
+
if has('cscope')
let l = getcompletion('', 'cscope')
let cmds = ['add', 'find', 'help', 'kill', 'reset', 'show']
@@ -273,8 +318,7 @@ func Test_getcompletion()
call assert_equal([], l)
" For others test if the name is recognized.
- let names = ['buffer', 'environment', 'file_in_path',
- \ 'mapping', 'shellcmd', 'tag', 'tag_listfiles', 'user']
+ let names = ['buffer', 'environment', 'file_in_path', 'mapping', 'tag', 'tag_listfiles', 'user']
if has('cmdline_hist')
call add(names, 'history')
endif
@@ -294,6 +338,7 @@ func Test_getcompletion()
endfor
call delete('Xtags')
+ set tags&
call assert_fails('call getcompletion("", "burp")', 'E475:')
endfunc
diff --git a/src/nvim/testdir/test_compiler.vim b/src/nvim/testdir/test_compiler.vim
index 4600a28da5..46c14d8bc3 100644
--- a/src/nvim/testdir/test_compiler.vim
+++ b/src/nvim/testdir/test_compiler.vim
@@ -33,9 +33,9 @@ endfunc
func Test_compiler_without_arg()
let a=split(execute('compiler'))
- call assert_match(expand('^.*runtime/compiler/ant.vim$'), a[0])
- call assert_match(expand('^.*runtime/compiler/bcc.vim$'), a[1])
- call assert_match(expand('^.*runtime/compiler/xmlwf.vim$'), a[-1])
+ call assert_match('^.*runtime/compiler/ant.vim$', a[0])
+ call assert_match('^.*runtime/compiler/bcc.vim$', a[1])
+ call assert_match('^.*runtime/compiler/xmlwf.vim$', a[-1])
endfunc
func Test_compiler_completion()
diff --git a/src/nvim/testdir/test_const.vim b/src/nvim/testdir/test_const.vim
new file mode 100644
index 0000000000..06062c5e58
--- /dev/null
+++ b/src/nvim/testdir/test_const.vim
@@ -0,0 +1,237 @@
+
+" Test for :const
+
+func s:noop()
+endfunc
+
+func Test_define_var_with_lock()
+ const i = 1
+ const f = 1.1
+ const s = 'vim'
+ const F = funcref('s:noop')
+ const l = [1, 2, 3]
+ const d = {'foo': 10}
+ if has('channel')
+ const j = test_null_job()
+ const c = test_null_channel()
+ endif
+ const b = v:true
+ const n = v:null
+
+ call assert_true(exists('i'))
+ call assert_true(exists('f'))
+ call assert_true(exists('s'))
+ call assert_true(exists('F'))
+ call assert_true(exists('l'))
+ call assert_true(exists('d'))
+ if has('channel')
+ call assert_true(exists('j'))
+ call assert_true(exists('c'))
+ endif
+ call assert_true(exists('b'))
+ call assert_true(exists('n'))
+
+ call assert_fails('let i = 1', 'E741:')
+ call assert_fails('let f = 1.1', 'E741:')
+ call assert_fails('let s = "vim"', 'E741:')
+ call assert_fails('let F = funcref("s:noop")', 'E741:')
+ call assert_fails('let l = [1, 2, 3]', 'E741:')
+ call assert_fails('let d = {"foo": 10}', 'E741:')
+ if has('channel')
+ call assert_fails('let j = test_null_job()', 'E741:')
+ call assert_fails('let c = test_null_channel()', 'E741:')
+ endif
+ call assert_fails('let b = v:true', 'E741:')
+ call assert_fails('let n = v:null', 'E741:')
+
+ " Unlet
+ unlet i
+ unlet f
+ unlet s
+ unlet F
+ unlet l
+ unlet d
+ if has('channel')
+ unlet j
+ unlet c
+ endif
+ unlet b
+ unlet n
+endfunc
+
+func Test_define_l_var_with_lock()
+ " With l: prefix
+ const l:i = 1
+ const l:f = 1.1
+ const l:s = 'vim'
+ const l:F = funcref('s:noop')
+ const l:l = [1, 2, 3]
+ const l:d = {'foo': 10}
+ if has('channel')
+ const l:j = test_null_job()
+ const l:c = test_null_channel()
+ endif
+ const l:b = v:true
+ const l:n = v:null
+
+ call assert_fails('let l:i = 1', 'E741:')
+ call assert_fails('let l:f = 1.1', 'E741:')
+ call assert_fails('let l:s = "vim"', 'E741:')
+ call assert_fails('let l:F = funcref("s:noop")', 'E741:')
+ call assert_fails('let l:l = [1, 2, 3]', 'E741:')
+ call assert_fails('let l:d = {"foo": 10}', 'E741:')
+ if has('channel')
+ call assert_fails('let l:j = test_null_job()', 'E741:')
+ call assert_fails('let l:c = test_null_channel()', 'E741:')
+ endif
+ call assert_fails('let l:b = v:true', 'E741:')
+ call assert_fails('let l:n = v:null', 'E741:')
+
+ " Unlet
+ unlet l:i
+ unlet l:f
+ unlet l:s
+ unlet l:F
+ unlet l:l
+ unlet l:d
+ if has('channel')
+ unlet l:j
+ unlet l:c
+ endif
+ unlet l:b
+ unlet l:n
+endfunc
+
+func Test_define_script_var_with_lock()
+ const s:x = 0
+ call assert_fails('let s:x = 1', 'E741:')
+ unlet s:x
+endfunc
+
+func Test_descructuring_with_lock()
+ const [a, b, c] = [1, 1.1, 'vim']
+
+ call assert_fails('let a = 1', 'E741:')
+ call assert_fails('let b = 1.1', 'E741:')
+ call assert_fails('let c = "vim"', 'E741:')
+
+ const [d; e] = [1, 1.1, 'vim']
+ call assert_fails('let d = 1', 'E741:')
+ call assert_fails('let e = [2.2, "a"]', 'E741:')
+endfunc
+
+func Test_cannot_modify_existing_variable()
+ let i = 1
+ let f = 1.1
+ let s = 'vim'
+ let F = funcref('s:noop')
+ let l = [1, 2, 3]
+ let d = {'foo': 10}
+ if has('channel')
+ let j = test_null_job()
+ let c = test_null_channel()
+ endif
+ let b = v:true
+ let n = v:null
+
+ call assert_fails('const i = 1', 'E995:')
+ call assert_fails('const f = 1.1', 'E995:')
+ call assert_fails('const s = "vim"', 'E995:')
+ call assert_fails('const F = funcref("s:noop")', 'E995:')
+ call assert_fails('const l = [1, 2, 3]', 'E995:')
+ call assert_fails('const d = {"foo": 10}', 'E995:')
+ if has('channel')
+ call assert_fails('const j = test_null_job()', 'E995:')
+ call assert_fails('const c = test_null_channel()', 'E995:')
+ endif
+ call assert_fails('const b = v:true', 'E995:')
+ call assert_fails('const n = v:null', 'E995:')
+ call assert_fails('const [i, f, s] = [1, 1.1, "vim"]', 'E995:')
+
+ const i2 = 1
+ const f2 = 1.1
+ const s2 = 'vim'
+ const F2 = funcref('s:noop')
+ const l2 = [1, 2, 3]
+ const d2 = {'foo': 10}
+ if has('channel')
+ const j2 = test_null_job()
+ const c2 = test_null_channel()
+ endif
+ const b2 = v:true
+ const n2 = v:null
+
+ call assert_fails('const i2 = 1', 'E995:')
+ call assert_fails('const f2 = 1.1', 'E995:')
+ call assert_fails('const s2 = "vim"', 'E995:')
+ call assert_fails('const F2 = funcref("s:noop")', 'E995:')
+ call assert_fails('const l2 = [1, 2, 3]', 'E995:')
+ call assert_fails('const d2 = {"foo": 10}', 'E995:')
+ if has('channel')
+ call assert_fails('const j2 = test_null_job()', 'E995:')
+ call assert_fails('const c2 = test_null_channel()', 'E995:')
+ endif
+ call assert_fails('const b2 = v:true', 'E995:')
+ call assert_fails('const n2 = v:null', 'E995:')
+ call assert_fails('const [i2, f2, s2] = [1, 1.1, "vim"]', 'E995:')
+endfunc
+
+func Test_const_with_index_access()
+ let l = [1, 2, 3]
+ call assert_fails('const l[0] = 4', 'E996:')
+ call assert_fails('const l[0:1] = [1, 2]', 'E996:')
+
+ let d = {'aaa': 0}
+ call assert_fails("const d['aaa'] = 4", 'E996:')
+ call assert_fails("const d.aaa = 4", 'E996:')
+endfunc
+
+func Test_const_with_compound_assign()
+ let i = 0
+ call assert_fails('const i += 4', 'E995:')
+ call assert_fails('const i -= 4', 'E995:')
+ call assert_fails('const i *= 4', 'E995:')
+ call assert_fails('const i /= 4', 'E995:')
+ call assert_fails('const i %= 4', 'E995:')
+
+ let s = 'a'
+ call assert_fails('const s .= "b"', 'E995:')
+
+ let [a, b, c] = [1, 2, 3]
+ call assert_fails('const [a, b, c] += [4, 5, 6]', 'E995:')
+
+ let [d; e] = [1, 2, 3]
+ call assert_fails('const [d; e] += [4, 5, 6]', 'E995:')
+endfunc
+
+func Test_const_with_special_variables()
+ call assert_fails('const $FOO = "hello"', 'E996:')
+ call assert_fails('const @a = "hello"', 'E996:')
+ call assert_fails('const &filetype = "vim"', 'E996:')
+ call assert_fails('const &l:filetype = "vim"', 'E996:')
+ call assert_fails('const &g:encoding = "utf-8"', 'E996:')
+endfunc
+
+func Test_const_with_eval_name()
+ let s = 'foo'
+
+ " eval name with :const should work
+ const abc_{s} = 1
+ const {s}{s} = 1
+
+ let s2 = 'abc_foo'
+ 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
+ call add(l, 4)
+ let l[0] = 42
+
+ " Modify dict
+ let d['bar'] = 'hello'
+ let d.foo = 44
+endfunc
diff --git a/src/nvim/testdir/test_cscope.vim b/src/nvim/testdir/test_cscope.vim
index bcb0d0dec5..e5dab05511 100644
--- a/src/nvim/testdir/test_cscope.vim
+++ b/src/nvim/testdir/test_cscope.vim
@@ -36,7 +36,7 @@ func Test_cscopeWithCscopeConnections()
" Test 1: Find this C-Symbol
for cmd in ['cs find s main', 'cs find 0 main']
- let a=execute(cmd)
+ let a = execute(cmd)
" Test 1.1 test where it moves the cursor
call assert_equal('main(void)', getline('.'))
" Test 1.2 test the output of the :cs command
@@ -51,21 +51,21 @@ func Test_cscopeWithCscopeConnections()
" Test 3: Find functions called by this function
for cmd in ['cs find d test_mf_hash', 'cs find 2 test_mf_hash']
- let a=execute(cmd)
+ let a = execute(cmd)
call assert_match('\n(1 of 42): <<mf_hash_init>> mf_hash_init(&ht);', a)
call assert_equal(' mf_hash_init(&ht);', getline('.'))
endfor
" Test 4: Find functions calling this function
for cmd in ['cs find c test_mf_hash', 'cs find 3 test_mf_hash']
- let a=execute(cmd)
+ let a = execute(cmd)
call assert_match('\n(1 of 1): <<main>> test_mf_hash();', a)
call assert_equal(' test_mf_hash();', getline('.'))
endfor
" Test 5: Find this text string
for cmd in ['cs find t Bram', 'cs find 4 Bram']
- let a=execute(cmd)
+ let a = execute(cmd)
call assert_match('(1 of 1): <<<unknown>>> \* VIM - Vi IMproved^Iby Bram Moolenaar', a)
call assert_equal(' * VIM - Vi IMproved by Bram Moolenaar', getline('.'))
endfor
@@ -73,7 +73,7 @@ func Test_cscopeWithCscopeConnections()
" Test 6: Find this egrep pattern
" test all matches returned by cscope
for cmd in ['cs find e ^\#includ.', 'cs find 6 ^\#includ.']
- let a=execute(cmd)
+ let a = execute(cmd)
call assert_match('\n(1 of 3): <<<unknown>>> #include <assert.h>', a)
call assert_equal('#include <assert.h>', getline('.'))
cnext
@@ -84,7 +84,7 @@ func Test_cscopeWithCscopeConnections()
endfor
" Test 7: Find the same egrep pattern using lcscope this time.
- let a=execute('lcs find e ^\#includ.')
+ let a = execute('lcs find e ^\#includ.')
call assert_match('\n(1 of 3): <<<unknown>>> #include <assert.h>', a)
call assert_equal('#include <assert.h>', getline('.'))
lnext
@@ -96,7 +96,7 @@ func Test_cscopeWithCscopeConnections()
" Test 8: Find this file
for cmd in ['cs find f Xmemfile_test.c', 'cs find 7 Xmemfile_test.c']
enew
- let a=execute(cmd)
+ let a = execute(cmd)
call assert_true(a =~ '"Xmemfile_test.c" \d\+L, \d\+C')
call assert_equal('Xmemfile_test.c', @%)
endfor
@@ -104,7 +104,7 @@ func Test_cscopeWithCscopeConnections()
" Test 9: Find files #including this file
for cmd in ['cs find i assert.h', 'cs find 8 assert.h']
enew
- let a=execute(cmd)
+ let a = execute(cmd)
let alines = split(a, '\n', 1)
call assert_equal('', alines[0])
call assert_true(alines[1] =~ '"Xmemfile_test.c" \d\+L, \d\+C')
@@ -118,13 +118,13 @@ func Test_cscopeWithCscopeConnections()
" Test 11: Find places where this symbol is assigned a value
" this needs a cscope >= 15.8
" unfortunately, Travis has cscope version 15.7
- let cscope_version=systemlist('cscope --version')[0]
- let cs_version=str2float(matchstr(cscope_version, '\d\+\(\.\d\+\)\?'))
+ let cscope_version = systemlist('cscope --version')[0]
+ let cs_version = str2float(matchstr(cscope_version, '\d\+\(\.\d\+\)\?'))
if cs_version >= 15.8
for cmd in ['cs find a item', 'cs find 9 item']
- let a=execute(cmd)
- call assert_equal(['', '(1 of 4): <<test_mf_hash>> item = (mf_hashitem_T *)lalloc_clear(sizeof(mf_hashtab_T), FALSE);'], split(a, '\n', 1))
- call assert_equal(' item = (mf_hashitem_T *)lalloc_clear(sizeof(mf_hashtab_T), FALSE);', getline('.'))
+ let a = execute(cmd)
+ call assert_equal(['', '(1 of 4): <<test_mf_hash>> item = (mf_hashitem_T *)lalloc_clear(sizeof(*item), FALSE);'], split(a, '\n', 1))
+ call assert_equal(' item = (mf_hashitem_T *)lalloc_clear(sizeof(*item), FALSE);', getline('.'))
cnext
call assert_equal(' item = mf_hash_find(&ht, key);', getline('.'))
cnext
@@ -135,18 +135,18 @@ func Test_cscopeWithCscopeConnections()
endif
" Test 12: leading whitespace is not removed for cscope find text
- let a=execute('cscope find t test_mf_hash')
+ let a = execute('cscope find t test_mf_hash')
call assert_equal(['', '(1 of 1): <<<unknown>>> test_mf_hash();'], split(a, '\n', 1))
call assert_equal(' test_mf_hash();', getline('.'))
" Test 13: test with scscope
- let a=execute('scs find t Bram')
+ let a = execute('scs find t Bram')
call assert_match('(1 of 1): <<<unknown>>> \* VIM - Vi IMproved^Iby Bram Moolenaar', a)
call assert_equal(' * VIM - Vi IMproved by Bram Moolenaar', getline('.'))
" Test 14: cscope help
for cmd in ['cs', 'cs help', 'cs xxx']
- let a=execute(cmd)
+ let a = execute(cmd)
call assert_match('^cscope commands:\n', a)
call assert_match('\nadd :', a)
call assert_match('\nfind :', a)
@@ -155,25 +155,25 @@ func Test_cscopeWithCscopeConnections()
call assert_match('\nreset: Reinit all connections', a)
call assert_match('\nshow : Show connections', a)
endfor
- let a=execute('scscope help')
+ let a = execute('scscope help')
call assert_match('This cscope command does not support splitting the window\.', a)
" Test 15: reset connections
- let a=execute('cscope reset')
+ let a = execute('cscope reset')
call assert_match('\nAdded cscope database.*Xcscope.out (#0)', a)
call assert_match('\nAll cscope databases reset', a)
" Test 16: cscope show
- let a=execute('cscope show')
+ let a = execute('cscope show')
call assert_match('\n 0 \d\+.*Xcscope.out\s*<none>', a)
" Test 17: cstag and 'csto' option
set csto=0
- let a=execute('cstag TEST_COUNT')
+ let a = execute('cstag TEST_COUNT')
call assert_match('(1 of 1): <<TEST_COUNT>> #define TEST_COUNT 50000', a)
call assert_equal('#define TEST_COUNT 50000', getline('.'))
set csto=1
- let a=execute('cstag index_to_key')
+ let a = execute('cstag index_to_key')
call assert_match('(1 of 1): <<index_to_key>> #define index_to_key(i) ((i) ^ 15167)', a)
call assert_equal('#define index_to_key(i) ((i) ^ 15167)', getline('.'))
call assert_fails('cstag xxx', 'E257:')
@@ -183,10 +183,10 @@ func Test_cscopeWithCscopeConnections()
set nocst
call assert_fails('tag TEST_COUNT', 'E426:')
set cst
- let a=execute('tag TEST_COUNT')
+ let a = execute('tag TEST_COUNT')
call assert_match('(1 of 1): <<TEST_COUNT>> #define TEST_COUNT 50000', a)
call assert_equal('#define TEST_COUNT 50000', getline('.'))
- let a=execute('tags')
+ let a = execute('tags')
call assert_match('1 1 TEST_COUNT\s\+\d\+\s\+#define index_to_key', a)
" Test 19: this should trigger call to cs_print_tags()
@@ -198,17 +198,17 @@ func Test_cscopeWithCscopeConnections()
call assert_fails('cscope kill 2', 'E261:')
call assert_fails('cscope kill xxx', 'E261:')
- let a=execute('cscope kill 0')
+ let a = execute('cscope kill 0')
call assert_match('cscope connection 0 closed', a)
cscope add Xcscope.out
- let a=execute('cscope kill Xcscope.out')
+ let a = execute('cscope kill Xcscope.out')
call assert_match('cscope connection Xcscope.out closed', a)
cscope add Xcscope.out .
- let a=execute('cscope kill -1')
+ let a = execute('cscope kill -1')
call assert_match('cscope connection .*Xcscope.out closed', a)
- let a=execute('cscope kill -1')
+ let a = execute('cscope kill -1')
call assert_equal('', a)
" Test 21: 'csprg' option
@@ -220,7 +220,7 @@ func Test_cscopeWithCscopeConnections()
" Test 22: multiple cscope connections
cscope add Xcscope.out
cscope add Xcscope2.out . -C
- let a=execute('cscope show')
+ let a = execute('cscope show')
call assert_match('\n 0 \d\+.*Xcscope.out\s*<none>', a)
call assert_match('\n 1 \d\+.*Xcscope2.out\s*\.', a)
@@ -294,7 +294,7 @@ func Test_withoutCscopeConnection()
call assert_equal(cscope_connection(), 0)
call assert_fails('cscope find s main', 'E567:')
- let a=execute('cscope show')
+ let a = execute('cscope show')
call assert_match('no cscope connections', a)
endfunc
diff --git a/src/nvim/testdir/test_cursor_func.vim b/src/nvim/testdir/test_cursor_func.vim
index e1b9651c84..6bc9535aaf 100644
--- a/src/nvim/testdir/test_cursor_func.vim
+++ b/src/nvim/testdir/test_cursor_func.vim
@@ -44,3 +44,23 @@ func Test_curswant_with_autocommand()
quit!
endfunc
+" Tests for behavior of curswant with cursorcolumn/line
+func Test_curswant_with_cursorcolumn()
+ new
+ call setline(1, ['01234567', ''])
+ exe "normal! ggf6j"
+ call assert_equal(6, winsaveview().curswant)
+ set cursorcolumn
+ call assert_equal(6, winsaveview().curswant)
+ quit!
+endfunc
+
+func Test_curswant_with_cursorline()
+ new
+ call setline(1, ['01234567', ''])
+ exe "normal! ggf6j"
+ call assert_equal(6, winsaveview().curswant)
+ set cursorline
+ call assert_equal(6, winsaveview().curswant)
+ quit!
+endfunc
diff --git a/src/nvim/testdir/test_debugger.vim b/src/nvim/testdir/test_debugger.vim
index c923b22836..bb87ef9c58 100644
--- a/src/nvim/testdir/test_debugger.vim
+++ b/src/nvim/testdir/test_debugger.vim
@@ -52,16 +52,16 @@ func Test_Debugger()
let buf = RunVimInTerminal('-S Xtest.vim', {})
" Start the Vim debugger
- call RunDbgCmd(buf, ':debug echo Foo()')
+ call RunDbgCmd(buf, ':debug echo Foo()', ['cmd: echo Foo()'])
" Create a few stack frames by stepping through functions
- call RunDbgCmd(buf, 'step')
- call RunDbgCmd(buf, 'step')
- call RunDbgCmd(buf, 'step')
- call RunDbgCmd(buf, 'step')
- call RunDbgCmd(buf, 'step')
- call RunDbgCmd(buf, 'step')
- call RunDbgCmd(buf, 'step')
+ call RunDbgCmd(buf, 'step', ['line 1: let var1 = 1'])
+ call RunDbgCmd(buf, 'step', ['line 2: let var2 = Bar(var1) + 9'])
+ call RunDbgCmd(buf, 'step', ['line 1: let var1 = 2 + a:var'])
+ call RunDbgCmd(buf, 'step', ['line 2: let var2 = Bazz(var1) + 4'])
+ call RunDbgCmd(buf, 'step', ['line 1: try'])
+ call RunDbgCmd(buf, 'step', ['line 2: let var1 = 3 + a:var'])
+ call RunDbgCmd(buf, 'step', ['line 3: let var3 = "another var"'])
" check backtrace
call RunDbgCmd(buf, 'backtrace', [
diff --git a/src/nvim/testdir/test_diffmode.vim b/src/nvim/testdir/test_diffmode.vim
index 00f4563f3d..1ba36ca8e9 100644
--- a/src/nvim/testdir/test_diffmode.vim
+++ b/src/nvim/testdir/test_diffmode.vim
@@ -752,6 +752,9 @@ func Test_diff_of_diff()
if !CanRunVimInTerminal()
return
endif
+ if !has("rightleft")
+ throw 'Skipped: rightleft not supported'
+ endif
call writefile([
\ 'call setline(1, ["aa","bb","cc","@@ -3,2 +5,7 @@","dd","ee","ff"])',
diff --git a/src/nvim/testdir/test_edit.vim b/src/nvim/testdir/test_edit.vim
index 7f3994300f..48376d7922 100644
--- a/src/nvim/testdir/test_edit.vim
+++ b/src/nvim/testdir/test_edit.vim
@@ -643,11 +643,11 @@ func! Test_edit_CTRL_L()
call feedkeys("cct\<c-x>\<c-l>\<c-n>\<esc>", 'tnix')
call assert_equal(['one', 'two', 'three', 't', '', '', ''], getline(1, '$'))
call feedkeys("cct\<c-x>\<c-l>\<c-n>\<c-n>\<esc>", 'tnix')
- call assert_equal(['one', 'two', 'three', 't', '', '', ''], getline(1, '$'))
- call feedkeys("cct\<c-x>\<c-l>\<c-n>\<c-n>\<c-n>\<esc>", 'tnix')
call assert_equal(['one', 'two', 'three', 'two', '', '', ''], getline(1, '$'))
- call feedkeys("cct\<c-x>\<c-l>\<c-n>\<c-n>\<c-n>\<c-n>\<esc>", 'tnix')
+ call feedkeys("cct\<c-x>\<c-l>\<c-n>\<c-n>\<c-n>\<esc>", 'tnix')
call assert_equal(['one', 'two', 'three', 'three', '', '', ''], getline(1, '$'))
+ call feedkeys("cct\<c-x>\<c-l>\<c-n>\<c-n>\<c-n>\<c-n>\<esc>", 'tnix')
+ call assert_equal(['one', 'two', 'three', 't', '', '', ''], getline(1, '$'))
call feedkeys("cct\<c-x>\<c-l>\<c-p>\<esc>", 'tnix')
call assert_equal(['one', 'two', 'three', 'two', '', '', ''], getline(1, '$'))
call feedkeys("cct\<c-x>\<c-l>\<c-p>\<c-p>\<esc>", 'tnix')
@@ -1408,7 +1408,6 @@ func Test_edit_complete_very_long_name()
let save_columns = &columns
" Need at least about 1100 columns to reproduce the problem.
set columns=2000
- call assert_equal(2000, &columns)
set noswapfile
let longfilename = longdirname . '/' . repeat('a', 255)
diff --git a/src/nvim/testdir/test_environ.vim b/src/nvim/testdir/test_environ.vim
new file mode 100644
index 0000000000..21bb09a690
--- /dev/null
+++ b/src/nvim/testdir/test_environ.vim
@@ -0,0 +1,44 @@
+scriptencoding utf-8
+
+func Test_environ()
+ unlet! $TESTENV
+ call assert_equal(0, has_key(environ(), 'TESTENV'))
+ let $TESTENV = 'foo'
+ call assert_equal(1, has_key(environ(), 'TESTENV'))
+ let $TESTENV = 'ã“ã‚“ã«ã¡ã‚'
+ call assert_equal('ã“ã‚“ã«ã¡ã‚', environ()['TESTENV'])
+endfunc
+
+func Test_getenv()
+ unlet! $TESTENV
+ call assert_equal(v:null, getenv('TESTENV'))
+ let $TESTENV = 'foo'
+ call assert_equal('foo', getenv('TESTENV'))
+endfunc
+
+func Test_setenv()
+ unlet! $TESTENV
+ call setenv('TEST ENV', 'foo')
+ call assert_equal('foo', getenv('TEST ENV'))
+ call setenv('TEST ENV', v:null)
+ call assert_equal(v:null, getenv('TEST ENV'))
+endfunc
+
+func Test_external_env()
+ call setenv('FOO', 'HelloWorld')
+ if has('win32')
+ let result = system('echo %FOO%')
+ else
+ let result = system('echo $FOO')
+ endif
+ let result = substitute(result, '[ \r\n]', '', 'g')
+ call assert_equal('HelloWorld', result)
+
+ call setenv('FOO', v:null)
+ if has('win32')
+ let result = system('set | findstr "^FOO="')
+ else
+ let result = system('env | grep ^FOO=')
+ endif
+ call assert_equal('', result)
+endfunc
diff --git a/src/nvim/testdir/test_excmd.vim b/src/nvim/testdir/test_excmd.vim
new file mode 100644
index 0000000000..f5ce979208
--- /dev/null
+++ b/src/nvim/testdir/test_excmd.vim
@@ -0,0 +1,10 @@
+" Tests for various Ex commands.
+
+func Test_ex_delete()
+ new
+ call setline(1, ['a', 'b', 'c'])
+ 2
+ " :dl is :delete with the "l" flag, not :dlist
+ .dl
+ call assert_equal(['a', 'c'], getline(1, 2))
+endfunc
diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim
index 7a99a37be4..a9ade9155a 100644
--- a/src/nvim/testdir/test_filetype.vim
+++ b/src/nvim/testdir/test_filetype.vim
@@ -44,8 +44,10 @@ endfunc
" Filetypes detected just from matching the file name.
let s:filename_checks = {
+ \ '8th': ['file.8th'],
\ 'a2ps': ['/etc/a2ps.cfg', '/etc/a2ps/file.cfg', 'a2psrc', '.a2psrc'],
\ 'a65': ['file.a65'],
+ \ 'aap': ['file.aap'],
\ 'abap': ['file.abap'],
\ 'abc': ['file.abc'],
\ 'abel': ['file.abl'],
@@ -56,7 +58,8 @@ let s:filename_checks = {
\ 'aml': ['file.aml'],
\ 'ampl': ['file.run'],
\ 'ant': ['build.xml'],
- \ 'apache': ['.htaccess', '/etc/httpd/file.conf'],
+ \ 'apache': ['.htaccess', '/etc/httpd/file.conf', '/etc/apache2/sites-2/file.com', '/etc/apache2/some.config', '/etc/apache2/conf.file/conf', '/etc/apache2/mods-some/file', '/etc/apache2/sites-some/file', '/etc/httpd/conf.d/file.config'],
+ \ 'apachestyle': ['/etc/proftpd/file.config,/etc/proftpd/conf.file/file'],
\ 'applescript': ['file.scpt'],
\ 'aptconf': ['apt.conf', '/.aptitude/config'],
\ 'arch': ['.arch-inventory'],
@@ -81,7 +84,7 @@ let s:filename_checks = {
\ 'c': ['enlightenment/file.cfg', 'file.qc', 'file.c'],
\ 'cabal': ['file.cabal'],
\ 'calendar': ['calendar'],
- \ 'catalog': ['catalog'],
+ \ 'catalog': ['catalog', 'sgml.catalogfile'],
\ 'cdl': ['file.cdl'],
\ 'cdrdaoconf': ['/etc/cdrdao.conf', '/etc/defaults/cdrdao', '/etc/default/cdrdao', '.cdrdao'],
\ 'cdrtoc': ['file.toc'],
@@ -102,7 +105,7 @@ let s:filename_checks = {
\ 'coco': ['file.atg'],
\ 'conaryrecipe': ['file.recipe'],
\ 'conf': ['auto.master'],
- \ 'config': ['configure.in', 'configure.ac'],
+ \ 'config': ['configure.in', 'configure.ac', 'Pipfile'],
\ 'context': ['tex/context/any/file.tex', 'file.mkii', 'file.mkiv', 'file.mkvi'],
\ 'cpp': ['file.cxx', 'file.c++', 'file.hh', 'file.hxx', 'file.hpp', 'file.ipp', 'file.moc', 'file.tcc', 'file.inl', 'file.tlh'],
\ 'crm': ['file.crm'],
@@ -223,7 +226,7 @@ let s:filename_checks = {
\ 'jgraph': ['file.jgr'],
\ 'jovial': ['file.jov', 'file.j73', 'file.jovial'],
\ 'jproperties': ['file.properties', 'file.properties_xx', 'file.properties_xx_xx'],
- \ 'json': ['file.json', 'file.jsonp', 'file.webmanifest'],
+ \ 'json': ['file.json', 'file.jsonp', 'file.webmanifest', 'Pipfile.lock'],
\ 'jsp': ['file.jsp'],
\ 'kconfig': ['Kconfig', 'Kconfig.debug'],
\ 'kivy': ['file.kv'],
@@ -424,7 +427,7 @@ let s:filename_checks = {
\ 'svg': ['file.svg'],
\ 'svn': ['svn-commitfile.tmp'],
\ 'sysctl': ['/etc/sysctl.conf', '/etc/sysctl.d/file.conf'],
- \ 'systemd': ['any/systemd/file.automount', 'any/systemd/file.mount', 'any/systemd/file.path', 'any/systemd/file.service', 'any/systemd/file.socket', 'any/systemd/file.swap', 'any/systemd/file.target', 'any/systemd/file.timer'],
+ \ 'systemd': ['any/systemd/file.automount', 'any/systemd/file.mount', 'any/systemd/file.path', 'any/systemd/file.service', 'any/systemd/file.socket', 'any/systemd/file.swap', 'any/systemd/file.target', 'any/systemd/file.timer', '/etc/systemd/system/some.d/file.conf', '/etc/systemd/system/some.d/.#file'],
\ 'systemverilog': ['file.sv', 'file.svh'],
\ 'tags': ['tags'],
\ 'tak': ['file.tak'],
@@ -467,13 +470,14 @@ let s:filename_checks = {
\ 'verilog': ['file.v'],
\ 'verilogams': ['file.va', 'file.vams'],
\ 'vgrindefs': ['vgrindefs'],
- \ 'vhdl': ['file.hdl', 'file.vhd', 'file.vhdl', 'file.vbe', 'file.vst'],
+ \ 'vhdl': ['file.hdl', 'file.vhd', 'file.vhdl', 'file.vbe', 'file.vst', 'file.vhdl_123'],
\ 'vim': ['file.vim', 'file.vba', '.exrc', '_exrc'],
\ 'viminfo': ['.viminfo', '_viminfo'],
\ 'vmasm': ['file.mar'],
\ 'voscm': ['file.cm'],
\ 'vrml': ['file.wrl'],
\ 'vroom': ['file.vroom'],
+ \ 'vue': ['file.vue'],
\ 'wast': ['file.wast', 'file.wat'],
\ 'webmacro': ['file.wm'],
\ 'wget': ['.wgetrc', 'wgetrc'],
@@ -501,7 +505,6 @@ let s:filename_checks = {
\ 'zimbutempl': ['file.zut'],
\ 'zsh': ['.zprofile', '/etc/zprofile', '.zfbfmarks', 'file.zsh'],
\
- \ 'aap': ['file.aap'],
\ 'help': [$VIMRUNTIME . '/doc/help.txt'],
\ 'xpm': ['file.xpm'],
\ }
@@ -515,11 +518,15 @@ func CheckItems(checks)
for i in range(0, len(names) - 1)
new
try
- exe 'edit ' . names[i]
+ exe 'edit ' . fnameescape(names[i])
catch
- call assert_report('cannot edit "' . names[i] . '": ' . v:errmsg)
+ call assert_report('cannot edit "' . names[i] . '": ' . v:exception)
endtry
- call assert_equal(ft, &filetype, 'with file name: ' . names[i])
+ if &filetype == '' && &readonly
+ " File exists but not able to edit it (permission denied)
+ else
+ call assert_equal(ft, &filetype, 'with file name: ' . names[i])
+ endif
bwipe!
endfor
endfor
@@ -581,6 +588,8 @@ let s:script_checks = {
\ 'cfengine': [['#!/path/cfengine']],
\ 'erlang': [['#!/path/escript']],
\ 'haskell': [['#!/path/haskell']],
+ \ 'cpp': [['// Standard iostream objects -*- C++ -*-'],
+ \ ['// -*- C++ -*-']],
\ }
func Test_script_detection()
diff --git a/src/nvim/testdir/test_filter_cmd.vim b/src/nvim/testdir/test_filter_cmd.vim
index 86347ab77f..0c45db049b 100644
--- a/src/nvim/testdir/test_filter_cmd.vim
+++ b/src/nvim/testdir/test_filter_cmd.vim
@@ -87,3 +87,61 @@ func Test_filter_cmd_with_filter()
call assert_equal('a|b', out)
set shelltemp&
endfunction
+
+func Test_filter_commands()
+ let g:test_filter_a = 1
+ let b:test_filter_b = 2
+ let test_filter_c = 3
+
+ " Test filtering :let command
+ let res = split(execute("filter /^test_filter/ let"), "\n")
+ call assert_equal(["test_filter_a #1"], res)
+
+ let res = split(execute("filter /\\v^(b:)?test_filter/ let"), "\n")
+ call assert_equal(["test_filter_a #1", "b:test_filter_b #2"], res)
+
+ unlet g:test_filter_a
+ unlet b:test_filter_b
+ unlet test_filter_c
+
+ " Test filtering :set command
+ let helplang=&helplang
+ set helplang=en
+ let res = join(split(execute("filter /^help/ set"), "\n")[1:], " ")
+ call assert_match('^\s*helplang=\w*$', res)
+ let &helplang=helplang
+
+ " Test filtering :llist command
+ call setloclist(0, [{"filename": "/path/vim.c"}, {"filename": "/path/vim.h"}, {"module": "Main.Test"}])
+ let res = split(execute("filter /\\.c$/ llist"), "\n")
+ call assert_equal([" 1 /path/vim.c: "], res)
+
+ let res = split(execute("filter /\\.Test$/ llist"), "\n")
+ call assert_equal([" 3 Main.Test: "], res)
+
+ " Test filtering :jump command
+ e file.c
+ e file.h
+ e file.hs
+ let res = split(execute("filter /\.c$/ jumps"), "\n")[1:]
+ call assert_equal([" 2 1 0 file.c", ">"], res)
+
+ " Test filtering :marks command
+ b file.c
+ mark A
+ b file.h
+ mark B
+ let res = split(execute("filter /\.c$/ marks"), "\n")[1:]
+ call assert_equal([" A 1 0 file.c"], res)
+
+ call setline(1, ['one', 'two', 'three'])
+ 1mark a
+ 2mark b
+ 3mark c
+ let res = split(execute("filter /two/ marks abc"), "\n")[1:]
+ call assert_equal([" b 2 0 two"], res)
+
+ bwipe! file.c
+ bwipe! file.h
+ bwipe! file.hs
+endfunc
diff --git a/src/nvim/testdir/test_filter_map.vim b/src/nvim/testdir/test_filter_map.vim
index c8d64ce0a4..1dd3a5b29f 100644
--- a/src/nvim/testdir/test_filter_map.vim
+++ b/src/nvim/testdir/test_filter_map.vim
@@ -79,3 +79,8 @@ func Test_filter_map_dict_expr_funcref()
endfunc
call assert_equal({"foo": "f", "bar": "b", "baz": "b"}, map(copy(dict), function('s:filter4')))
endfunc
+
+func Test_map_fails()
+ call assert_fails('call map([1], "42 +")', 'E15:')
+ call assert_fails('call filter([1], "42 +")', 'E15:')
+endfunc
diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim
index ed9c70403e..fab1d7790d 100644
--- a/src/nvim/testdir/test_functions.vim
+++ b/src/nvim/testdir/test_functions.vim
@@ -1,4 +1,5 @@
" Tests for various functions.
+source shared.vim
" Must be done first, since the alternate buffer must be unset.
func Test_00_bufexists()
@@ -886,6 +887,14 @@ func Test_Executable()
elseif has('unix')
call assert_equal(1, executable('cat'))
call assert_equal(0, executable('nodogshere'))
+
+ " get "cat" path and remove the leading /
+ let catcmd = exepath('cat')[1:]
+ new
+ lcd /
+ call assert_equal(1, executable(catcmd))
+ call assert_equal('/' .. catcmd, exepath(catcmd))
+ bwipe
endif
endfunc
@@ -1140,3 +1149,92 @@ func Test_reg_executing_and_recording()
delfunc s:save_reg_stat
unlet s:reg_stat
endfunc
+
+func Test_libcall_libcallnr()
+ if !has('libcall')
+ return
+ endif
+
+ if has('win32')
+ let libc = 'msvcrt.dll'
+ elseif has('mac')
+ let libc = 'libSystem.B.dylib'
+ elseif system('uname -s') =~ 'SunOS'
+ " Set the path to libc.so according to the architecture.
+ let test_bits = system('file ' . GetVimProg())
+ let test_arch = system('uname -p')
+ if test_bits =~ '64-bit' && test_arch =~ 'sparc'
+ let libc = '/usr/lib/sparcv9/libc.so'
+ elseif test_bits =~ '64-bit' && test_arch =~ 'i386'
+ let libc = '/usr/lib/amd64/libc.so'
+ else
+ let libc = '/usr/lib/libc.so'
+ endif
+ else
+ " On Unix, libc.so can be in various places.
+ " Interestingly, using an empty string for the 1st argument of libcall
+ " allows to call functions from libc which is not documented.
+ let libc = ''
+ endif
+
+ if has('win32')
+ call assert_equal($USERPROFILE, libcall(libc, 'getenv', 'USERPROFILE'))
+ else
+ call assert_equal($HOME, libcall(libc, 'getenv', 'HOME'))
+ endif
+
+ " If function returns NULL, libcall() should return an empty string.
+ call assert_equal('', libcall(libc, 'getenv', 'X_ENV_DOES_NOT_EXIT'))
+
+ " Test libcallnr() with string and integer argument.
+ call assert_equal(4, libcallnr(libc, 'strlen', 'abcd'))
+ call assert_equal(char2nr('A'), libcallnr(libc, 'toupper', char2nr('a')))
+
+ call assert_fails("call libcall(libc, 'Xdoesnotexist_', '')", 'E364:')
+ call assert_fails("call libcallnr(libc, 'Xdoesnotexist_', '')", 'E364:')
+
+ call assert_fails("call libcall('Xdoesnotexist_', 'getenv', 'HOME')", 'E364:')
+ call assert_fails("call libcallnr('Xdoesnotexist_', 'strlen', 'abcd')", 'E364:')
+endfunc
+
+func Test_bufadd_bufload()
+ call assert_equal(0, bufexists('someName'))
+ let buf = bufadd('someName')
+ call assert_notequal(0, buf)
+ call assert_equal(1, bufexists('someName'))
+ call assert_equal(0, getbufvar(buf, '&buflisted'))
+ call assert_equal(0, bufloaded(buf))
+ call bufload(buf)
+ call assert_equal(1, bufloaded(buf))
+ call assert_equal([''], getbufline(buf, 1, '$'))
+
+ let curbuf = bufnr('')
+ call writefile(['some', 'text'], 'otherName')
+ let buf = bufadd('otherName')
+ call assert_notequal(0, buf)
+ call assert_equal(1, bufexists('otherName'))
+ call assert_equal(0, getbufvar(buf, '&buflisted'))
+ call assert_equal(0, bufloaded(buf))
+ call bufload(buf)
+ call assert_equal(1, bufloaded(buf))
+ call assert_equal(['some', 'text'], getbufline(buf, 1, '$'))
+ call assert_equal(curbuf, bufnr(''))
+
+ let buf1 = bufadd('')
+ let buf2 = bufadd('')
+ call assert_notequal(0, buf1)
+ call assert_notequal(0, buf2)
+ call assert_notequal(buf1, buf2)
+ call assert_equal(1, bufexists(buf1))
+ call assert_equal(1, bufexists(buf2))
+ call assert_equal(0, bufloaded(buf1))
+ exe 'bwipe ' .. buf1
+ call assert_equal(0, bufexists(buf1))
+ call assert_equal(1, bufexists(buf2))
+ exe 'bwipe ' .. buf2
+ call assert_equal(0, bufexists(buf2))
+
+ bwipe someName
+ bwipe otherName
+ call assert_equal(0, bufexists('someName'))
+endfunc
diff --git a/src/nvim/testdir/test_getvar.vim b/src/nvim/testdir/test_getvar.vim
index d6b6b69aa8..3b61d68ebc 100644
--- a/src/nvim/testdir/test_getvar.vim
+++ b/src/nvim/testdir/test_getvar.vim
@@ -1,4 +1,5 @@
-" Tests for getwinvar(), gettabvar() and gettabwinvar().
+" Tests for getwinvar(), gettabvar(), gettabwinvar() and get().
+
func Test_var()
" Use strings to test for memory leaks. First, check that in an empty
" window, gettabvar() returns the correct value
@@ -102,3 +103,44 @@ func Test_gettabvar_in_tabline()
close
redrawstatus!
endfunc
+
+" Test get() function using default value.
+
+" get({dict}, {key} [, {default}])
+func Test_get_dict()
+ let d = {'foo': 42}
+ call assert_equal(42, get(d, 'foo', 99))
+ call assert_equal(999, get(d, 'bar', 999))
+endfunc
+
+" get({list}, {idx} [, {default}])
+func Test_get_list()
+ let l = [1,2,3]
+ call assert_equal(1, get(l, 0, 999))
+ call assert_equal(3, get(l, -1, 999))
+ call assert_equal(999, get(l, 3, 999))
+endfunc
+
+" get({blob}, {idx} [, {default}]) - in test_blob.vim
+
+" get({lambda}, {what} [, {default}])
+func Test_get_lambda()
+ let l:L = {-> 42}
+ call assert_match('^<lambda>', get(l:L, 'name'))
+ call assert_equal(l:L, get(l:L, 'func'))
+ call assert_equal({'lambda has': 'no dict'}, get(l:L, 'dict', {'lambda has': 'no dict'}))
+ call assert_equal(0, get(l:L, 'dict'))
+ call assert_equal([], get(l:L, 'args'))
+endfunc
+
+" get({func}, {what} [, {default}])
+func Test_get_func()
+ let l:F = function('tr')
+ call assert_equal('tr', get(l:F, 'name'))
+ call assert_equal(l:F, get(l:F, 'func'))
+ call assert_equal({'func has': 'no dict'}, get(l:F, 'dict', {'func has': 'no dict'}))
+ call assert_equal(0, get(l:F, 'dict'))
+ call assert_equal([], get(l:F, 'args'))
+endfunc
+
+" get({partial}, {what} [, {default}]) - in test_partial.vim
diff --git a/src/nvim/testdir/test_ins_complete.vim b/src/nvim/testdir/test_ins_complete.vim
index d3429617d0..7f52481ba8 100644
--- a/src/nvim/testdir/test_ins_complete.vim
+++ b/src/nvim/testdir/test_ins_complete.vim
@@ -249,3 +249,39 @@ func Test_omni_dash()
delfunc Omni
set omnifunc=
endfunc
+
+func Test_completefunc_args()
+ let s:args = []
+ func! CompleteFunc(findstart, base)
+ let s:args += [[a:findstart, empty(a:base)]]
+ endfunc
+ new
+
+ set completefunc=CompleteFunc
+ call feedkeys("i\<C-X>\<C-U>\<Esc>", 'x')
+ call assert_equal([1, 1], s:args[0])
+ call assert_equal(0, s:args[1][0])
+ set completefunc=
+
+ let s:args = []
+ set omnifunc=CompleteFunc
+ call feedkeys("i\<C-X>\<C-O>\<Esc>", 'x')
+ call assert_equal([1, 1], s:args[0])
+ call assert_equal(0, s:args[1][0])
+ set omnifunc=
+
+ bwipe!
+ unlet s:args
+ delfunc CompleteFunc
+endfunc
+
+" Check that when using feedkeys() typeahead does not interrupt searching for
+" completions.
+func Test_compl_feedkeys()
+ new
+ set completeopt=menuone,noselect
+ call feedkeys("ajump ju\<C-X>\<C-N>\<C-P>\<ESC>", "tx")
+ call assert_equal("jump jump", getline(1))
+ bwipe!
+ set completeopt&
+endfunc
diff --git a/src/nvim/testdir/test_lambda.vim b/src/nvim/testdir/test_lambda.vim
index bc7817cef8..bfbb3e5c5b 100644
--- a/src/nvim/testdir/test_lambda.vim
+++ b/src/nvim/testdir/test_lambda.vim
@@ -23,30 +23,36 @@ function! Test_lambda_with_timer()
return
endif
- source load.vim
-
let s:n = 0
let s:timer_id = 0
- function! s:Foo()
- "let n = 0
- let s:timer_id = timer_start(50, {-> execute("let s:n += 1 | echo s:n", "")}, {"repeat": -1})
- endfunction
+ func! s:Foo()
+ let s:timer_id = timer_start(10, {-> execute("let s:n += 1 | echo s:n", "")}, {"repeat": -1})
+ endfunc
call s:Foo()
- sleep 210m
+ " check timer works
+ for i in range(0, 10)
+ if s:n > 0
+ break
+ endif
+ sleep 10m
+ endfor
+
" do not collect lambda
call test_garbagecollect_now()
- let m = LoadAdjust(s:n)
- sleep 230m
- call timer_stop(s:timer_id)
- let n = LoadAdjust(s:n)
- let nine = LoadAdjust(9)
+ " check timer still works
+ let m = s:n
+ for i in range(0, 10)
+ if s:n > m
+ break
+ endif
+ sleep 10m
+ endfor
- call assert_true(m > 1)
- call assert_true(n > m + 1)
- call assert_true(n < nine)
-endfunction
+ call timer_stop(s:timer_id)
+ call assert_true(s:n > m)
+endfunc
function! Test_lambda_with_partial()
let l:Cb = function({... -> ['zero', a:1, a:2, a:3]}, ['one', 'two'])
diff --git a/src/nvim/testdir/test_makeencoding.py b/src/nvim/testdir/test_makeencoding.py
index 041edadc0a..f6dc0f8d1c 100644
--- a/src/nvim/testdir/test_makeencoding.py
+++ b/src/nvim/testdir/test_makeencoding.py
@@ -8,6 +8,7 @@ import locale
import io
import sys
+
def set_output_encoding(enc=None):
"""Set the encoding of stdout and stderr
@@ -20,7 +21,7 @@ def set_output_encoding(enc=None):
def get_text_writer(fo, **kwargs):
kw = dict(kwargs)
- kw.setdefault('errors', 'backslashreplace') # use \uXXXX style
+ kw.setdefault('errors', 'backslashreplace') # use \uXXXX style
kw.setdefault('closefd', False)
if sys.version_info[0] < 3:
@@ -29,6 +30,7 @@ def set_output_encoding(enc=None):
writer = io.open(fo.fileno(), mode='w', newline='', **kw)
write = writer.write # save the original write() function
enc = locale.getpreferredencoding()
+
def convwrite(s):
if isinstance(s, bytes):
write(s.decode(enc)) # convert to unistr
diff --git a/src/nvim/testdir/test_maparg.vim b/src/nvim/testdir/test_maparg.vim
index 0fb878b04a..ee16a22398 100644
--- a/src/nvim/testdir/test_maparg.vim
+++ b/src/nvim/testdir/test_maparg.vim
@@ -27,6 +27,10 @@ function Test_maparg()
call assert_equal({'silent': 0, 'noremap': 0, 'lhs': 'foo', 'mode': ' ',
\ 'nowait': 1, 'expr': 0, 'sid': sid, 'rhs': 'bar', 'buffer': 1},
\ maparg('foo', '', 0, 1))
+ tmap baz foo
+ call assert_equal({'silent': 0, 'noremap': 0, 'lhs': 'baz', 'mode': 't',
+ \ 'nowait': 0, 'expr': 0, 'sid': sid, 'rhs': 'foo', 'buffer': 0},
+ \ maparg('baz', 't', 0, 1))
map abc x<char-114>x
call assert_equal("xrx", maparg('abc'))
diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim
index 84a118aef2..9f253604ed 100644
--- a/src/nvim/testdir/test_mapping.vim
+++ b/src/nvim/testdir/test_mapping.vim
@@ -187,9 +187,32 @@ func Test_map_cursor()
imapclear
endfunc
+func Test_map_cursor_ctrl_gU()
+ " <c-g>U<cursor> works only within a single line
+ nnoremap c<* *Ncgn<C-r>"<C-G>U<S-Left>
+ call setline(1, ['foo', 'foobar', '', 'foo'])
+ call cursor(1,2)
+ call feedkeys("c<*PREFIX\<esc>.", 'xt')
+ call assert_equal(['PREFIXfoo', 'foobar', '', 'PREFIXfoo'], getline(1,'$'))
+ " break undo manually
+ set ul=1000
+ exe ":norm! uu"
+ call assert_equal(['foo', 'foobar', '', 'foo'], getline(1,'$'))
+
+ " Test that it does not work if the cursor moves to the previous line
+ " 2 times <S-Left> move to the previous line
+ nnoremap c<* *Ncgn<C-r>"<C-G>U<S-Left><C-G>U<S-Left>
+ call setline(1, ['', ' foo', 'foobar', '', 'foo'])
+ call cursor(2,3)
+ call feedkeys("c<*PREFIX\<esc>.", 'xt')
+ call assert_equal(['PREFIXPREFIX', ' foo', 'foobar', '', 'foo'], getline(1,'$'))
+ nmapclear
+endfunc
+
+
" This isn't actually testing a mapping, but similar use of CTRL-G U as above.
func Test_break_undo()
- :set whichwrap=<,>,[,]
+ set whichwrap=<,>,[,]
call feedkeys("G4o2k", "xt")
exe ":norm! iTest3: text with a (parenthesis here\<C-G>U\<Right>new line here\<esc>\<up>\<up>."
call assert_equal('new line here', getline(line('$') - 3))
diff --git a/src/nvim/testdir/test_mksession.vim b/src/nvim/testdir/test_mksession.vim
index 7c5b95ae96..d77dac69c7 100644
--- a/src/nvim/testdir/test_mksession.vim
+++ b/src/nvim/testdir/test_mksession.vim
@@ -238,6 +238,17 @@ func Test_mkview_no_file_name()
%bwipe
endfunc
+" A clean session (one empty buffer, one window, and one tab) should not
+" set any error messages when sourced because no commands should fail.
+func Test_mksession_no_errmsg()
+ let v:errmsg = ''
+ %bwipe!
+ mksession! Xtest_mks.out
+ source Xtest_mks.out
+ call assert_equal('', v:errmsg)
+ call delete('Xtest_mks.out')
+endfunc
+
func Test_mksession_quote_in_filename()
if !has('unix')
" only Unix can handle this weird filename
diff --git a/src/nvim/testdir/test_modeline.vim b/src/nvim/testdir/test_modeline.vim
index 091a833774..1e196e07f0 100644
--- a/src/nvim/testdir/test_modeline.vim
+++ b/src/nvim/testdir/test_modeline.vim
@@ -60,14 +60,17 @@ func Test_modeline_keymap()
set keymap= iminsert=0 imsearch=-1
endfunc
-func s:modeline_fails(what, text)
+func s:modeline_fails(what, text, error)
+ if !exists('+' . a:what)
+ return
+ endif
let fname = "Xmodeline_fails_" . a:what
call writefile(['vim: set ' . a:text . ' :', 'nothing'], fname)
let modeline = &modeline
set modeline
filetype plugin on
syntax enable
- call assert_fails('split ' . fname, 'E474:')
+ call assert_fails('split ' . fname, a:error)
call assert_equal("", &filetype)
call assert_equal("", &syntax)
@@ -79,16 +82,92 @@ func s:modeline_fails(what, text)
endfunc
func Test_modeline_filetype_fails()
- call s:modeline_fails('filetype', 'ft=evil$CMD')
+ call s:modeline_fails('filetype', 'ft=evil$CMD', 'E474:')
endfunc
func Test_modeline_syntax_fails()
- call s:modeline_fails('syntax', 'syn=evil$CMD')
+ call s:modeline_fails('syntax', 'syn=evil$CMD', 'E474:')
endfunc
func Test_modeline_keymap_fails()
- if !has('keymap')
- return
- endif
- call s:modeline_fails('keymap', 'keymap=evil$CMD')
+ call s:modeline_fails('keymap', 'keymap=evil$CMD', 'E474:')
+endfunc
+
+func Test_modeline_fails_always()
+ call s:modeline_fails('backupdir', 'backupdir=Something()', 'E520:')
+ call s:modeline_fails('cdpath', 'cdpath=Something()', 'E520:')
+ call s:modeline_fails('charconvert', 'charconvert=Something()', 'E520:')
+ call s:modeline_fails('completefunc', 'completefunc=Something()', 'E520:')
+ call s:modeline_fails('cscopeprg', 'cscopeprg=Something()', 'E520:')
+ call s:modeline_fails('diffexpr', 'diffexpr=Something()', 'E520:')
+ call s:modeline_fails('directory', 'directory=Something()', 'E520:')
+ call s:modeline_fails('equalprg', 'equalprg=Something()', 'E520:')
+ call s:modeline_fails('errorfile', 'errorfile=Something()', 'E520:')
+ call s:modeline_fails('exrc', 'exrc=Something()', 'E520:')
+ call s:modeline_fails('formatprg', 'formatprg=Something()', 'E520:')
+ call s:modeline_fails('fsync', 'fsync=Something()', 'E520:')
+ call s:modeline_fails('grepprg', 'grepprg=Something()', 'E520:')
+ call s:modeline_fails('helpfile', 'helpfile=Something()', 'E520:')
+ call s:modeline_fails('imactivatefunc', 'imactivatefunc=Something()', 'E520:')
+ call s:modeline_fails('imstatusfunc', 'imstatusfunc=Something()', 'E520:')
+ call s:modeline_fails('imstyle', 'imstyle=Something()', 'E520:')
+ call s:modeline_fails('keywordprg', 'keywordprg=Something()', 'E520:')
+ call s:modeline_fails('langmap', 'langmap=Something()', 'E520:')
+ call s:modeline_fails('luadll', 'luadll=Something()', 'E520:')
+ call s:modeline_fails('makeef', 'makeef=Something()', 'E520:')
+ call s:modeline_fails('makeprg', 'makeprg=Something()', 'E520:')
+ call s:modeline_fails('mkspellmem', 'mkspellmem=Something()', 'E520:')
+ call s:modeline_fails('mzschemedll', 'mzschemedll=Something()', 'E520:')
+ call s:modeline_fails('mzschemegcdll', 'mzschemegcdll=Something()', 'E520:')
+ call s:modeline_fails('modelineexpr', 'modelineexpr=Something()', 'E520:')
+ call s:modeline_fails('omnifunc', 'omnifunc=Something()', 'E520:')
+ call s:modeline_fails('operatorfunc', 'operatorfunc=Something()', 'E520:')
+ call s:modeline_fails('perldll', 'perldll=Something()', 'E520:')
+ call s:modeline_fails('printdevice', 'printdevice=Something()', 'E520:')
+ call s:modeline_fails('patchexpr', 'patchexpr=Something()', 'E520:')
+ call s:modeline_fails('printexpr', 'printexpr=Something()', 'E520:')
+ call s:modeline_fails('pythondll', 'pythondll=Something()', 'E520:')
+ call s:modeline_fails('pythonhome', 'pythonhome=Something()', 'E520:')
+ call s:modeline_fails('pythonthreedll', 'pythonthreedll=Something()', 'E520:')
+ call s:modeline_fails('pythonthreehome', 'pythonthreehome=Something()', 'E520:')
+ call s:modeline_fails('pyxversion', 'pyxversion=Something()', 'E520:')
+ call s:modeline_fails('rubydll', 'rubydll=Something()', 'E520:')
+ call s:modeline_fails('runtimepath', 'runtimepath=Something()', 'E520:')
+ call s:modeline_fails('secure', 'secure=Something()', 'E520:')
+ call s:modeline_fails('shell', 'shell=Something()', 'E520:')
+ call s:modeline_fails('shellcmdflag', 'shellcmdflag=Something()', 'E520:')
+ call s:modeline_fails('shellpipe', 'shellpipe=Something()', 'E520:')
+ call s:modeline_fails('shellquote', 'shellquote=Something()', 'E520:')
+ call s:modeline_fails('shellredir', 'shellredir=Something()', 'E520:')
+ call s:modeline_fails('shellxquote', 'shellxquote=Something()', 'E520:')
+ call s:modeline_fails('spellfile', 'spellfile=Something()', 'E520:')
+ call s:modeline_fails('spellsuggest', 'spellsuggest=Something()', 'E520:')
+ call s:modeline_fails('tcldll', 'tcldll=Something()', 'E520:')
+ call s:modeline_fails('titleold', 'titleold=Something()', 'E520:')
+ call s:modeline_fails('viewdir', 'viewdir=Something()', 'E520:')
+ call s:modeline_fails('viminfo', 'viminfo=Something()', 'E520:')
+ call s:modeline_fails('viminfofile', 'viminfofile=Something()', 'E520:')
+ call s:modeline_fails('winptydll', 'winptydll=Something()', 'E520:')
+ call s:modeline_fails('undodir', 'undodir=Something()', 'E520:')
+ " only check a few terminal options
+ " Skip these since nvim doesn't support termcodes as options
+ "call s:modeline_fails('t_AB', 't_AB=Something()', 'E520:')
+ "call s:modeline_fails('t_ce', 't_ce=Something()', 'E520:')
+ "call s:modeline_fails('t_sr', 't_sr=Something()', 'E520:')
+ "call s:modeline_fails('t_8b', 't_8b=Something()', 'E520:')
+endfunc
+
+func Test_modeline_fails_modelineexpr()
+ call s:modeline_fails('balloonexpr', 'balloonexpr=Something()', 'E992:')
+ call s:modeline_fails('foldexpr', 'foldexpr=Something()', 'E992:')
+ call s:modeline_fails('foldtext', 'foldtext=Something()', 'E992:')
+ call s:modeline_fails('formatexpr', 'formatexpr=Something()', 'E992:')
+ call s:modeline_fails('guitablabel', 'guitablabel=Something()', 'E992:')
+ call s:modeline_fails('iconstring', 'iconstring=Something()', 'E992:')
+ call s:modeline_fails('includeexpr', 'includeexpr=Something()', 'E992:')
+ call s:modeline_fails('indentexpr', 'indentexpr=Something()', 'E992:')
+ call s:modeline_fails('rulerformat', 'rulerformat=Something()', 'E992:')
+ call s:modeline_fails('statusline', 'statusline=Something()', 'E992:')
+ call s:modeline_fails('tabline', 'tabline=Something()', 'E992:')
+ call s:modeline_fails('titlestring', 'titlestring=Something()', 'E992:')
endfunc
diff --git a/src/nvim/testdir/test_normal.vim b/src/nvim/testdir/test_normal.vim
index ef17209f74..945cd5a617 100644
--- a/src/nvim/testdir/test_normal.vim
+++ b/src/nvim/testdir/test_normal.vim
@@ -2552,6 +2552,21 @@ func Test_delete_until_paragraph()
bwipe!
endfunc
+func Test_message_when_using_ctrl_c()
+ " Make sure no buffers are changed.
+ %bwipe!
+
+ exe "normal \<C-C>"
+ call assert_match("Type :qa and press <Enter> to exit Nvim", Screenline(&lines))
+
+ new
+ cal setline(1, 'hi!')
+ exe "normal \<C-C>"
+ call assert_match("Type :qa! and press <Enter> to abandon all changes and exit Nvim", Screenline(&lines))
+
+ bwipe!
+endfunc
+
" Test for '[m', ']m', '[M' and ']M'
" Jumping to beginning and end of methods in Java-like languages
func Test_java_motion()
diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim
index 78afa929d0..a6ebd7b023 100644
--- a/src/nvim/testdir/test_options.vim
+++ b/src/nvim/testdir/test_options.vim
@@ -92,9 +92,6 @@ function! Test_path_keep_commas()
endfunction
func Test_filetype_valid()
- if !has('autocmd')
- return
- endif
set ft=valid_name
call assert_equal("valid_name", &filetype)
set ft=valid-name
@@ -180,6 +177,15 @@ func Test_thesaurus()
call Check_dir_option('thesaurus')
endfun
+func Test_complete()
+ " Trailing single backslash used to cause invalid memory access.
+ set complete=s\
+ new
+ call feedkeys("i\<C-N>\<Esc>", 'xt')
+ bwipe!
+ set complete&
+endfun
+
func Test_set_completion()
call feedkeys(":set di\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"set dictionary diff diffexpr diffopt digraph directory display', @:)
@@ -216,6 +222,7 @@ func Test_set_completion()
call feedkeys(":set tags=./\\\\ dif\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"set tags=./\\ diff diffexpr diffopt', @:)
+ set tags&
let &shellslash = shellslash
endfunc
@@ -224,7 +231,7 @@ func Test_set_errors()
call assert_fails('set backupcopy=', 'E474:')
call assert_fails('set regexpengine=3', 'E474:')
call assert_fails('set history=10001', 'E474:')
- call assert_fails('set numberwidth=11', 'E474:')
+ call assert_fails('set numberwidth=21', 'E474:')
call assert_fails('set colorcolumn=-a')
call assert_fails('set colorcolumn=a')
call assert_fails('set colorcolumn=1,')
@@ -305,14 +312,23 @@ func Test_set_ttytype()
endif
endfunc
-func Test_complete()
- " Trailing single backslash used to cause invalid memory access.
- set complete=s\
- new
- call feedkeys("i\<C-N>\<Esc>", 'xt')
- bwipe!
- set complete&
-endfun
+func Test_set_all()
+ set tw=75
+ set iskeyword=a-z,A-Z
+ set nosplitbelow
+ let out = execute('set all')
+ call assert_match('textwidth=75', out)
+ call assert_match('iskeyword=a-z,A-Z', out)
+ call assert_match('nosplitbelow', out)
+ set tw& iskeyword& splitbelow&
+endfunc
+
+func Test_set_values()
+ " The file is only generated when running "make test" in the src directory.
+ if filereadable('opt_test.vim')
+ source opt_test.vim
+ endif
+endfunc
func ResetIndentexpr()
set indentexpr=
@@ -327,6 +343,65 @@ func Test_set_indentexpr()
bwipe!
endfunc
+func Test_backupskip()
+ " Option 'backupskip' may contain several comma-separated path
+ " specifications if one or more of the environment variables TMPDIR, TMP,
+ " or TEMP is defined. To simplify testing, convert the string value into a
+ " list.
+ let bsklist = split(&bsk, ',')
+
+ if has("mac")
+ let found = (index(bsklist, '/private/tmp/*') >= 0)
+ call assert_true(found, '/private/tmp not in option bsk: ' . &bsk)
+ elseif has("unix")
+ let found = (index(bsklist, '/tmp/*') >= 0)
+ call assert_true(found, '/tmp not in option bsk: ' . &bsk)
+ endif
+
+ " If our test platform is Windows, the path(s) in option bsk will use
+ " backslash for the path separator and the components could be in short
+ " (8.3) format. As such, we need to replace the backslashes with forward
+ " slashes and convert the path components to long format. The expand()
+ " function will do this but it cannot handle comma-separated paths. This is
+ " why bsk was converted from a string into a list of strings above.
+ "
+ " One final complication is that the wildcard "/*" is at the end of each
+ " path and so expand() might return a list of matching files. To prevent
+ " this, we need to remove the wildcard before calling expand() and then
+ " append it afterwards.
+ if has('win32')
+ let item_nbr = 0
+ while item_nbr < len(bsklist)
+ let path_spec = bsklist[item_nbr]
+ let path_spec = strcharpart(path_spec, 0, strlen(path_spec)-2)
+ let path_spec = substitute(expand(path_spec), '\\', '/', 'g')
+ let bsklist[item_nbr] = path_spec . '/*'
+ let item_nbr += 1
+ endwhile
+ endif
+
+ " Option bsk will also include these environment variables if defined.
+ " If they're defined, verify they appear in the option value.
+ for var in ['$TMPDIR', '$TMP', '$TEMP']
+ if exists(var)
+ let varvalue = substitute(expand(var), '\\', '/', 'g')
+ let varvalue = substitute(varvalue, '/$', '', '')
+ let varvalue .= '/*'
+ let found = (index(bsklist, varvalue) >= 0)
+ call assert_true(found, var . ' (' . varvalue . ') not in option bsk: ' . &bsk)
+ endif
+ endfor
+
+ " Duplicates should be filtered out (option has P_NODUP)
+ let backupskip = &backupskip
+ set backupskip=
+ set backupskip+=/test/dir
+ set backupskip+=/other/dir
+ set backupskip+=/test/dir
+ call assert_equal('/test/dir,/other/dir', &backupskip)
+ let &backupskip = backupskip
+endfunc
+
func Test_copy_winopt()
set hidden
@@ -395,24 +470,6 @@ func Test_shortmess_F()
bwipe
endfunc
-func Test_set_all()
- set tw=75
- set iskeyword=a-z,A-Z
- set nosplitbelow
- let out = execute('set all')
- call assert_match('textwidth=75', out)
- call assert_match('iskeyword=a-z,A-Z', out)
- call assert_match('nosplitbelow', out)
- set tw& iskeyword& splitbelow&
-endfunc
-
-func Test_set_values()
- " The file is only generated when running "make test" in the src directory.
- if filereadable('opt_test.vim')
- source opt_test.vim
- endif
-endfunc
-
func Test_shortmess_F2()
e file1
e file2
diff --git a/src/nvim/testdir/test_partial.vim b/src/nvim/testdir/test_partial.vim
index de5c26c2dd..590e18e024 100644
--- a/src/nvim/testdir/test_partial.vim
+++ b/src/nvim/testdir/test_partial.vim
@@ -285,6 +285,11 @@ func Test_get_partial_items()
call assert_equal('MyDictFunc', get(Func, 'name'))
call assert_equal([], get(Func, 'args'))
call assert_true(empty( get(Func, 'dict')))
+
+ let P = function('substitute', ['hello there', 'there'])
+ let dict = {'partial has': 'no dict'}
+ call assert_equal(dict, get(P, 'dict', dict))
+ call assert_equal(0, get(l:P, 'dict'))
endfunc
func Test_compare_partials()
diff --git a/src/nvim/testdir/test_popup.vim b/src/nvim/testdir/test_popup.vim
index 96f4bfc71b..98e9de9ffb 100644
--- a/src/nvim/testdir/test_popup.vim
+++ b/src/nvim/testdir/test_popup.vim
@@ -641,7 +641,7 @@ func Test_popup_and_preview_autocommand()
norm! gt
call assert_equal(0, &previewwindow)
norm! gT
- call assert_equal(12, tabpagenr('$'))
+ call assert_equal(10, tabpagenr('$'))
tabonly
pclose
augroup MyBufAdd
@@ -841,4 +841,38 @@ func Test_popup_complete_info_02()
bwipe!
endfunc
+func Test_CompleteChanged()
+ new
+ call setline(1, ['foo', 'bar', 'foobar', ''])
+ set complete=. completeopt=noinsert,noselect,menuone
+ function! OnPumChange()
+ let g:event = copy(v:event)
+ let g:item = get(v:event, 'completed_item', {})
+ let g:word = get(g:item, 'word', v:null)
+ endfunction
+ augroup AAAAA_Group
+ au!
+ autocmd CompleteChanged * :call OnPumChange()
+ augroup END
+ call cursor(4, 1)
+
+ call feedkeys("Sf\<C-N>", 'tx')
+ call assert_equal({'completed_item': {}, 'width': 15,
+ \ 'height': 2, 'size': 2,
+ \ 'col': 0, 'row': 4, 'scrollbar': v:false}, g:event)
+ call feedkeys("a\<C-N>\<C-N>\<C-E>", 'tx')
+ call assert_equal('foo', g:word)
+ call feedkeys("a\<C-N>\<C-N>\<C-N>\<C-E>", 'tx')
+ call assert_equal('foobar', g:word)
+ call feedkeys("a\<C-N>\<C-N>\<C-N>\<C-N>\<C-E>", 'tx')
+ call assert_equal(v:null, g:word)
+ call feedkeys("a\<C-N>\<C-N>\<C-N>\<C-N>\<C-P>", 'tx')
+ call assert_equal('foobar', g:word)
+
+ autocmd! AAAAA_Group
+ set complete& completeopt&
+ delfunc! OnPumchange
+ bw!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_profile.vim b/src/nvim/testdir/test_profile.vim
index 8996e86b43..1aa4d5eaf8 100644
--- a/src/nvim/testdir/test_profile.vim
+++ b/src/nvim/testdir/test_profile.vim
@@ -5,6 +5,8 @@ endif
func Test_profile_func()
let lines = [
+ \ 'profile start Xprofile_func.log',
+ \ 'profile func Foo*"',
\ "func! Foo1()",
\ "endfunc",
\ "func! Foo2()",
@@ -33,9 +35,7 @@ func Test_profile_func()
call writefile(lines, 'Xprofile_func.vim')
call system(v:progpath
- \ . ' -es -u NONE -U NONE -i NONE --noplugin'
- \ . ' -c "profile start Xprofile_func.log"'
- \ . ' -c "profile func Foo*"'
+ \ . ' -es --clean'
\ . ' -c "so Xprofile_func.vim"'
\ . ' -c "qall!"')
call assert_equal(0, v:shell_error)
@@ -97,7 +97,7 @@ func Test_profile_file()
call writefile(lines, 'Xprofile_file.vim')
call system(v:progpath
- \ . ' -es -u NONE -U NONE -i NONE --noplugin'
+ \ . ' -es --clean'
\ . ' -c "profile start Xprofile_file.log"'
\ . ' -c "profile file Xprofile_file.vim"'
\ . ' -c "so Xprofile_file.vim"'
@@ -152,17 +152,17 @@ func Test_profile_file_with_cont()
let lines = readfile('Xprofile_file.log')
call assert_equal(11, len(lines))
- call assert_match('^SCRIPT .*Xprofile_file.vim$', lines[0])
- call assert_equal('Sourced 1 time', lines[1])
- call assert_match('^Total time:\s\+\d\+\.\d\+$', lines[2])
- call assert_match('^ Self time:\s\+\d\+\.\d\+$', lines[3])
- call assert_equal('', lines[4])
- call assert_equal('count total (s) self (s)', lines[5])
- call assert_match(' 1 0.\d\+ echo "hello', lines[6])
- call assert_equal(' \ world"', lines[7])
- call assert_match(' 1 0.\d\+ echo "foo ', lines[8])
- call assert_equal(' \bar"', lines[9])
- call assert_equal('', lines[10])
+ call assert_match('^SCRIPT .*Xprofile_file.vim$', lines[0])
+ call assert_equal('Sourced 1 time', lines[1])
+ call assert_match('^Total time:\s\+\d\+\.\d\+$', lines[2])
+ call assert_match('^ Self time:\s\+\d\+\.\d\+$', lines[3])
+ call assert_equal('', lines[4])
+ call assert_equal('count total (s) self (s)', lines[5])
+ call assert_match(' 1 0.\d\+ echo "hello', lines[6])
+ call assert_equal(' \ world"', lines[7])
+ call assert_match(' 1 0.\d\+ echo "foo ', lines[8])
+ call assert_equal(' \bar"', lines[9])
+ call assert_equal('', lines[10])
call delete('Xprofile_file.vim')
call delete('Xprofile_file.log')
@@ -222,3 +222,73 @@ func Test_profile_truncate_mbyte()
call delete('Xprofile_file.vim')
call delete('Xprofile_file.log')
endfunc
+
+func Test_profdel_func()
+ let lines = [
+ \ 'profile start Xprofile_file.log',
+ \ 'func! Foo1()',
+ \ 'endfunc',
+ \ 'func! Foo2()',
+ \ 'endfunc',
+ \ 'func! Foo3()',
+ \ 'endfunc',
+ \ '',
+ \ 'profile func Foo1',
+ \ 'profile func Foo2',
+ \ 'call Foo1()',
+ \ 'call Foo2()',
+ \ '',
+ \ 'profile func Foo3',
+ \ 'profdel func Foo2',
+ \ 'profdel func Foo3',
+ \ 'call Foo1()',
+ \ 'call Foo2()',
+ \ 'call Foo3()' ]
+ call writefile(lines, 'Xprofile_file.vim')
+ call system(v:progpath . ' -es --clean -c "so Xprofile_file.vim" -c q')
+ call assert_equal(0, v:shell_error)
+
+ let lines = readfile('Xprofile_file.log')
+ call assert_equal(24, len(lines))
+
+ " Check that:
+ " - Foo1() is called twice (profdel not invoked)
+ " - Foo2() is called once (profdel invoked after it was called)
+ " - Foo3() is not called (profdel invoked before it was called)
+ call assert_equal('FUNCTION Foo1()', lines[0])
+ call assert_equal('Called 2 times', lines[1])
+ call assert_equal('FUNCTION Foo2()', lines[7])
+ call assert_equal('Called 1 time', lines[8])
+ call assert_equal('FUNCTIONS SORTED ON TOTAL TIME', lines[14])
+ call assert_equal('FUNCTIONS SORTED ON SELF TIME', lines[19])
+
+ call delete('Xprofile_file.vim')
+ call delete('Xprofile_file.log')
+endfunc
+
+func Test_profdel_star()
+ " Foo() is invoked once before and once after 'profdel *'.
+ " So profiling should report it only once.
+ let lines = [
+ \ 'profile start Xprofile_file.log',
+ \ 'func! Foo()',
+ \ 'endfunc',
+ \ 'profile func Foo',
+ \ 'call Foo()',
+ \ 'profdel *',
+ \ 'call Foo()' ]
+ call writefile(lines, 'Xprofile_file.vim')
+ call system(v:progpath . ' -es --clean -c "so Xprofile_file.vim" -c q')
+ call assert_equal(0, v:shell_error)
+
+ let lines = readfile('Xprofile_file.log')
+ call assert_equal(15, len(lines))
+
+ call assert_equal('FUNCTION Foo()', lines[0])
+ call assert_equal('Called 1 time', lines[1])
+ call assert_equal('FUNCTIONS SORTED ON TOTAL TIME', lines[7])
+ call assert_equal('FUNCTIONS SORTED ON SELF TIME', lines[11])
+
+ call delete('Xprofile_file.vim')
+ call delete('Xprofile_file.log')
+endfunc
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index 16fb86ea08..ce0b8f1be8 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -3372,3 +3372,49 @@ func Test_lbuffer_with_bwipe()
au!
augroup END
endfunc
+
+" Tests for the ':filter /pat/ clist' command
+func Test_filter_clist()
+ cexpr ['Xfile1:10:10:Line 10', 'Xfile2:15:15:Line 15']
+ call assert_equal([' 2 Xfile2:15 col 15: Line 15'],
+ \ split(execute('filter /Line 15/ clist'), "\n"))
+ call assert_equal([' 1 Xfile1:10 col 10: Line 10'],
+ \ split(execute('filter /Xfile1/ clist'), "\n"))
+ call assert_equal([], split(execute('filter /abc/ clist'), "\n"))
+
+ call setqflist([{'module' : 'abc', 'pattern' : 'pat1'},
+ \ {'module' : 'pqr', 'pattern' : 'pat2'}], ' ')
+ call assert_equal([' 2 pqr:pat2: '],
+ \ split(execute('filter /pqr/ clist'), "\n"))
+ call assert_equal([' 1 abc:pat1: '],
+ \ split(execute('filter /pat1/ clist'), "\n"))
+endfunc
+
+func Test_setloclist_in_aucmd()
+ " This was using freed memory.
+ augroup nasty
+ au * * call setloclist(0, [], 'f')
+ augroup END
+ lexpr "x"
+ augroup nasty
+ au!
+ augroup END
+endfunc
+
+" Tests for the "CTRL-W <CR>" command.
+func Xview_result_split_tests(cchar)
+ call s:setup_commands(a:cchar)
+
+ " Test that "CTRL-W <CR>" in a qf/ll window fails with empty list.
+ call g:Xsetlist([])
+ Xopen
+ let l:win_count = winnr('$')
+ call assert_fails('execute "normal! \<C-W>\<CR>"', 'E42')
+ call assert_equal(l:win_count, winnr('$'))
+ Xclose
+endfunc
+
+func Test_view_result_split()
+ call Xview_result_split_tests('c')
+ call Xview_result_split_tests('l')
+endfunc
diff --git a/src/nvim/testdir/test_recover.vim b/src/nvim/testdir/test_recover.vim
index beecb4cd0d..09c8d1cda6 100644
--- a/src/nvim/testdir/test_recover.vim
+++ b/src/nvim/testdir/test_recover.vim
@@ -6,6 +6,13 @@ func Test_recover_root_dir()
set dir=/
call assert_fails('recover', 'E305:')
close!
+
+ if has('win32')
+ " can write in / directory on MS-Windows
+ let &directory = 'F:\\'
+ elseif filewritable('/') == 2
+ set dir=/notexist/
+ endif
call assert_fails('split Xtest', 'E303:')
set dir&
endfunc
diff --git a/src/nvim/testdir/test_regexp_latin.vim b/src/nvim/testdir/test_regexp_latin.vim
index de209fa9ec..b5e99b0ed3 100644
--- a/src/nvim/testdir/test_regexp_latin.vim
+++ b/src/nvim/testdir/test_regexp_latin.vim
@@ -85,3 +85,16 @@ func Test_multi_failure()
call assert_fails('/a\{a}', 'E870:')
set re=0
endfunc
+
+func Test_recursive_addstate()
+ " This will call addstate() recursively until it runs into the limit.
+ let lnum = search('\v((){328}){389}')
+ call assert_equal(0, lnum)
+endfunc
+
+func Test_out_of_memory()
+ new
+ s/^/,n
+ " This will be slow...
+ call assert_fails('call search("\\v((n||<)+);")', 'E363:')
+endfunc
diff --git a/src/nvim/testdir/test_regexp_utf8.vim b/src/nvim/testdir/test_regexp_utf8.vim
index 97638e9aac..e06c7d6368 100644
--- a/src/nvim/testdir/test_regexp_utf8.vim
+++ b/src/nvim/testdir/test_regexp_utf8.vim
@@ -183,3 +183,12 @@ func Test_large_class()
call assert_equal(1, "\u3042" =~# '[\u3000-\u4000]')
set re=0
endfunc
+
+func Test_optmatch_toolong()
+ set re=1
+ " Can only handle about 8000 characters.
+ let pat = '\\%[' .. repeat('x', 9000) .. ']'
+ call assert_fails('call match("abc def", "' .. pat .. '")', 'E339:')
+ set re=0
+endfunc
+
diff --git a/src/nvim/testdir/test_registers.vim b/src/nvim/testdir/test_registers.vim
index d7b6de5652..298268a994 100644
--- a/src/nvim/testdir/test_registers.vim
+++ b/src/nvim/testdir/test_registers.vim
@@ -63,3 +63,22 @@ func Test_display_registers()
bwipe!
endfunc
+
+" Check that replaying a typed sequence does not use an Esc and following
+" characters as an escape sequence.
+func Test_recording_esc_sequence()
+ new
+ try
+ let save_F2 = &t_F2
+ catch
+ endtry
+ let t_F2 = "\<Esc>OQ"
+ call feedkeys("qqiTest\<Esc>", "xt")
+ call feedkeys("OQuirk\<Esc>q", "xt")
+ call feedkeys("Go\<Esc>@q", "xt")
+ call assert_equal(['Quirk', 'Test', 'Quirk', 'Test'], getline(1, 4))
+ bwipe!
+ if exists('save_F2')
+ let &t_F2 = save_F2
+ endif
+endfunc
diff --git a/src/nvim/testdir/test_search.vim b/src/nvim/testdir/test_search.vim
index 87cad241e2..8e284ba042 100644
--- a/src/nvim/testdir/test_search.vim
+++ b/src/nvim/testdir/test_search.vim
@@ -1,5 +1,7 @@
" Test for the search command
+source shared.vim
+
func Test_search_cmdline()
" See test/functional/legacy/search_spec.lua
throw 'skipped: Nvim does not support test_override()'
@@ -288,16 +290,53 @@ func Test_searchpair()
new
call setline(1, ['other code here', '', '[', '" cursor here', ']'])
4
- let a=searchpair('\[','',']','bW')
+ let a = searchpair('\[','',']','bW')
call assert_equal(3, a)
set nomagic
4
- let a=searchpair('\[','',']','bW')
+ let a = searchpair('\[','',']','bW')
call assert_equal(3, a)
set magic
q!
endfunc
+func Test_searchpair_errors()
+ call assert_fails("call searchpair([0], 'middle', 'end', 'bW', 'skip', 99, 100)", 'E730: using List as a String')
+ call assert_fails("call searchpair('start', {-> 0}, 'end', 'bW', 'skip', 99, 100)", 'E729: using Funcref as a String')
+ call assert_fails("call searchpair('start', 'middle', {'one': 1}, 'bW', 'skip', 99, 100)", 'E731: using Dictionary as a String')
+ call assert_fails("call searchpair('start', 'middle', 'end', 'flags', 'skip', 99, 100)", 'E475: Invalid argument: flags')
+ call assert_fails("call searchpair('start', 'middle', 'end', 'bW', 0, 99, 100)", 'E475: Invalid argument: 0')
+ call assert_fails("call searchpair('start', 'middle', 'end', 'bW', 'func', -99, 100)", 'E475: Invalid argument: -99')
+ call assert_fails("call searchpair('start', 'middle', 'end', 'bW', 'func', 99, -100)", 'E475: Invalid argument: -100')
+endfunc
+
+func Test_searchpair_skip()
+ func Zero()
+ return 0
+ endfunc
+ func Partial(x)
+ return a:x
+ endfunc
+ new
+ call setline(1, ['{', 'foo', 'foo', 'foo', '}'])
+ 3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', ''))
+ 3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', '0'))
+ 3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', {-> 0}))
+ 3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', function('Zero')))
+ 3 | call assert_equal(1, searchpair('{', '', '}', 'bWn', function('Partial', [0])))
+ bw!
+endfunc
+
+func Test_searchpair_leak()
+ new
+ call setline(1, 'if one else another endif')
+
+ " The error in the skip expression caused memory to leak.
+ call assert_fails("call searchpair('\\<if\\>', '\\<else\\>', '\\<endif\\>', '', '\"foo\" 2')", 'E15:')
+
+ bwipe!
+endfunc
+
func Test_searchc()
" These commands used to cause memory overflow in searchc().
new
diff --git a/src/nvim/testdir/test_source.vim b/src/nvim/testdir/test_source.vim
new file mode 100644
index 0000000000..09baec0b7d
--- /dev/null
+++ b/src/nvim/testdir/test_source.vim
@@ -0,0 +1,48 @@
+" Tests for the :source command.
+
+func Test_source_autocmd()
+ call writefile([
+ \ 'let did_source = 1',
+ \ ], 'Xsourced')
+ au SourcePre *source* let did_source_pre = 1
+ au SourcePost *source* let did_source_post = 1
+
+ source Xsourced
+
+ call assert_equal(g:did_source, 1)
+ call assert_equal(g:did_source_pre, 1)
+ call assert_equal(g:did_source_post, 1)
+
+ call delete('Xsourced')
+ au! SourcePre
+ au! SourcePost
+ unlet g:did_source
+ unlet g:did_source_pre
+ unlet g:did_source_post
+endfunc
+
+func Test_source_cmd()
+ au SourceCmd *source* let did_source = expand('<afile>')
+ au SourcePre *source* let did_source_pre = 2
+ au SourcePost *source* let did_source_post = 2
+
+ source Xsourced
+
+ call assert_equal(g:did_source, 'Xsourced')
+ call assert_false(exists('g:did_source_pre'))
+ call assert_equal(g:did_source_post, 2)
+
+ au! SourceCmd
+ au! SourcePre
+ au! SourcePost
+endfunc
+
+func Test_source_sandbox()
+ new
+ call writefile(["Ohello\<Esc>"], 'Xsourcehello')
+ source! Xsourcehello | echo
+ call assert_equal('hello', getline(1))
+ call assert_fails('sandbox source! Xsourcehello', 'E48:')
+ bwipe!
+ call delete('Xsourcehello')
+endfunc
diff --git a/src/nvim/testdir/test_spell.vim b/src/nvim/testdir/test_spell.vim
index b3438cc649..230cb72335 100644
--- a/src/nvim/testdir/test_spell.vim
+++ b/src/nvim/testdir/test_spell.vim
@@ -1,4 +1,5 @@
" Test spell checking
+" Note: this file uses latin1 encoding, but is used with utf-8 encoding.
if !has('spell')
finish
@@ -68,6 +69,47 @@ func Test_z_equal_on_invalid_utf8_word()
bwipe!
endfunc
+" Test spellbadword() with argument
+func Test_spellbadword()
+ set spell
+
+ call assert_equal(['bycycle', 'bad'], spellbadword('My bycycle.'))
+ call assert_equal(['another', 'caps'], spellbadword('A sentence. another sentence'))
+
+ set spelllang=en
+ call assert_equal(['', ''], spellbadword('centre'))
+ call assert_equal(['', ''], spellbadword('center'))
+ set spelllang=en_us
+ call assert_equal(['centre', 'local'], spellbadword('centre'))
+ call assert_equal(['', ''], spellbadword('center'))
+ set spelllang=en_gb
+ call assert_equal(['', ''], spellbadword('centre'))
+ call assert_equal(['center', 'local'], spellbadword('center'))
+
+ " Create a small word list to test that spellbadword('...')
+ " can return ['...', 'rare'].
+ e Xwords
+ insert
+foo
+foobar/?
+.
+ w!
+ mkspell! Xwords.spl Xwords
+ set spelllang=Xwords.spl
+ call assert_equal(['foobar', 'rare'], spellbadword('foo foobar'))
+
+ " Typo should not be detected without the 'spell' option.
+ set spelllang=en_gb nospell
+ call assert_equal(['', ''], spellbadword('centre'))
+ call assert_equal(['', ''], spellbadword('My bycycle.'))
+ call assert_equal(['', ''], spellbadword('A sentence. another sentence'))
+
+ call delete('Xwords.spl')
+ call delete('Xwords')
+ set spelllang&
+ set spell&
+endfunc
+
func Test_spellreall()
new
set spell
@@ -351,6 +393,18 @@ func Test_zeq_crash()
bwipe!
endfunc
+" Check handling a word longer than MAXWLEN.
+func Test_spell_long_word()
+ set enc=utf-8
+ new
+ call setline(1, "d\xCC\xB4\xCC\xBD\xCD\x88\xCD\x94a\xCC\xB5\xCD\x84\xCD\x84\xCC\xA8\xCD\x9Cr\xCC\xB5\xCC\x8E\xCD\x85\xCD\x85k\xCC\xB6\xCC\x89\xCC\x9D \xCC\xB6\xCC\x83\xCC\x8F\xCC\xA4\xCD\x8Ef\xCC\xB7\xCC\x81\xCC\x80\xCC\xA9\xCC\xB0\xCC\xAC\xCC\xA2\xCD\x95\xCD\x87\xCD\x8D\xCC\x9E\xCD\x99\xCC\xAD\xCC\xAB\xCC\x97\xCC\xBBo\xCC\xB6\xCC\x84\xCC\x95\xCC\x8C\xCC\x8B\xCD\x9B\xCD\x9C\xCC\xAFr\xCC\xB7\xCC\x94\xCD\x83\xCD\x97\xCC\x8C\xCC\x82\xCD\x82\xCD\x80\xCD\x91\xCC\x80\xCC\xBE\xCC\x82\xCC\x8F\xCC\xA3\xCD\x85\xCC\xAE\xCD\x8D\xCD\x99\xCC\xBC\xCC\xAB\xCC\xA7\xCD\x88c\xCC\xB7\xCD\x83\xCC\x84\xCD\x92\xCC\x86\xCC\x83\xCC\x88\xCC\x92\xCC\x94\xCC\xBE\xCC\x9D\xCC\xAF\xCC\x98\xCC\x9D\xCC\xBB\xCD\x8E\xCC\xBB\xCC\xB3\xCC\xA3\xCD\x8E\xCD\x99\xCC\xA5\xCC\xAD\xCC\x99\xCC\xB9\xCC\xAE\xCC\xA5\xCC\x9E\xCD\x88\xCC\xAE\xCC\x9E\xCC\xA9\xCC\x97\xCC\xBC\xCC\x99\xCC\xA5\xCD\x87\xCC\x97\xCD\x8E\xCD\x94\xCC\x99\xCC\x9D\xCC\x96\xCD\x94\xCC\xAB\xCC\xA7\xCC\xA5\xCC\x98\xCC\xBB\xCC\xAF\xCC\xABe\xCC\xB7\xCC\x8E\xCC\x82\xCD\x86\xCD\x9B\xCC\x94\xCD\x83\xCC\x85\xCD\x8A\xCD\x8C\xCC\x8B\xCD\x92\xCD\x91\xCC\x8F\xCC\x81\xCD\x95\xCC\xA2\xCC\xB9\xCC\xB2\xCD\x9C\xCC\xB1\xCC\xA6\xCC\xB3\xCC\xAF\xCC\xAE\xCC\x9C\xCD\x99s\xCC\xB8\xCC\x8C\xCC\x8E\xCC\x87\xCD\x81\xCD\x82\xCC\x86\xCD\x8C\xCD\x8C\xCC\x8B\xCC\x84\xCC\x8C\xCD\x84\xCD\x9B\xCD\x86\xCC\x93\xCD\x90\xCC\x85\xCC\x94\xCD\x98\xCD\x84\xCD\x92\xCD\x8B\xCC\x90\xCC\x83\xCC\x8F\xCD\x84\xCD\x81\xCD\x9B\xCC\x90\xCD\x81\xCC\x8F\xCC\xBD\xCC\x88\xCC\xBF\xCC\x88\xCC\x84\xCC\x8E\xCD\x99\xCD\x94\xCC\x99\xCD\x99\xCC\xB0\xCC\xA8\xCC\xA3\xCC\xA8\xCC\x96\xCC\x99\xCC\xAE\xCC\xBC\xCC\x99\xCD\x9A\xCC\xB2\xCC\xB1\xCC\x9F\xCC\xBB\xCC\xA6\xCD\x85\xCC\xAA\xCD\x89\xCC\x9D\xCC\x99\xCD\x96\xCC\xB1\xCC\xB1\xCC\x99\xCC\xA6\xCC\xA5\xCD\x95\xCC\xB2\xCC\xA0\xCD\x99 within")
+ set spell spelllang=en
+ redraw
+ redraw!
+ bwipe!
+ set nospell
+endfunc
+
func LoadAffAndDic(aff_contents, dic_contents)
throw 'skipped: Nvim does not support enc=latin1'
set enc=latin1
diff --git a/src/nvim/testdir/test_startup.vim b/src/nvim/testdir/test_startup.vim
index 873f2e8731..b5647b610d 100644
--- a/src/nvim/testdir/test_startup.vim
+++ b/src/nvim/testdir/test_startup.vim
@@ -339,6 +339,88 @@ func Test_A_F_H_arg()
call delete('Xtestout')
endfunc
+func Test_invalid_args()
+ if !has('unix') || has('gui_running')
+ " can't get output of Vim.
+ return
+ endif
+
+ for opt in ['-Y', '--does-not-exist']
+ let out = split(system(GetVimCommand() .. ' ' .. opt), "\n")
+ call assert_equal(1, v:shell_error)
+ call assert_equal('nvim: Unknown option argument: "' .. opt .. '"', out[0])
+ call assert_equal('More info with "nvim -h"', out[1])
+ endfor
+
+ for opt in ['-c', '-i', '-s', '-t', '-u', '-U', '-w', '-W', '--cmd', '--startuptime']
+ let out = split(system(GetVimCommand() .. ' ' .. opt), "\n")
+ call assert_equal(1, v:shell_error)
+ call assert_equal('nvim: Argument missing after: "' .. opt .. '"', out[0])
+ call assert_equal('More info with "nvim -h"', out[1])
+ endfor
+
+ if has('clientserver')
+ " FIXME: need to add --servername to this list
+ " but it causes vim-8.1.1282 to crash!
+ for opt in ['--remote', '--remote-send', '--remote-silent', '--remote-expr',
+ \ '--remote-tab', '--remote-tab-wait',
+ \ '--remote-tab-wait-silent', '--remote-tab-silent',
+ \ '--remote-wait', '--remote-wait-silent',
+ \ ]
+ let out = split(system(GetVimCommand() .. ' ' .. opt), "\n")
+ call assert_equal(1, v:shell_error)
+ call assert_match('^VIM - Vi IMproved .* (.*)$', out[0])
+ call assert_equal('Argument missing after: "' .. opt .. '"', out[1])
+ call assert_equal('More info with: "vim -h"', out[2])
+ endfor
+ endif
+
+ " FIXME: commented out as this causes vim-8.1.1282 to crash!
+ "if has('clipboard')
+ " let out = split(system(GetVimCommand() .. ' --display'), "\n")
+ " call assert_equal(1, v:shell_error)
+ " call assert_match('^VIM - Vi IMproved .* (.*)$', out[0])
+ " call assert_equal('Argument missing after: "--display"', out[1])
+ " call assert_equal('More info with: "vim -h"', out[2])
+ "endif
+
+ let out = split(system(GetVimCommand() .. ' -ix'), "\n")
+ call assert_equal(1, v:shell_error)
+ call assert_equal('nvim: Garbage after option argument: "-ix"', out[0])
+ call assert_equal('More info with "nvim -h"', out[1])
+
+ " Not an error in Nvim. The "-" file is allowed with -t, -q, or [file].
+ let out = split(system(GetVimCommand() .. ' - xxx -cq'), "\n")
+ call assert_equal(0, v:shell_error)
+
+ " Detect invalid repeated arguments '-t foo -t foo", '-q foo -q foo'.
+ for opt in ['-t', '-q']
+ let out = split(system(GetVimCommand() .. repeat(' ' .. opt .. ' foo', 2)), "\n")
+ call assert_equal(1, v:shell_error)
+ call assert_equal('nvim: Too many edit arguments: "' .. opt .. '"', out[0])
+ call assert_equal('More info with "nvim -h"', out[1])
+ endfor
+
+ for opt in [' -cq', ' --cmd q', ' +', ' -S foo']
+ let out = split(system(GetVimCommand() .. repeat(opt, 11)), "\n")
+ call assert_equal(1, v:shell_error)
+ " FIXME: The error message given by Vim is not ideal in case of repeated
+ " -S foo since it does not mention -S.
+ call assert_equal('nvim: Too many "+command", "-c command" or "--cmd command" arguments', out[0])
+ call assert_equal('More info with "nvim -h"', out[1])
+ endfor
+
+ if has('gui_gtk')
+ for opt in ['--socketid x', '--socketid 0xg']
+ let out = split(system(GetVimCommand() .. ' ' .. opt), "\n")
+ call assert_equal(1, v:shell_error)
+ call assert_match('^VIM - Vi IMproved .* (.*)$', out[0])
+ call assert_equal('Invalid argument for: "--socketid"', out[1])
+ call assert_equal('More info with: "vim -h"', out[2])
+ endfor
+ endif
+endfunc
+
func Test_file_args()
let after = [
\ 'call writefile(argv(), "Xtestout")',
diff --git a/src/nvim/testdir/test_statusline.vim b/src/nvim/testdir/test_statusline.vim
index b86340a23a..ea29da0262 100644
--- a/src/nvim/testdir/test_statusline.vim
+++ b/src/nvim/testdir/test_statusline.vim
@@ -86,8 +86,11 @@ func Test_statusline()
call assert_match('^Xstatusline\s*$', s:get_statusline())
" %F: Full path to the file in the buffer.
+ let shellslash = &shellslash
+ set shellslash
set statusline=%F
call assert_match('/testdir/Xstatusline\s*$', s:get_statusline())
+ let &shellslash = shellslash
" %h: Help buffer flag, text is "[help]".
" %H: Help buffer flag, text is ",HLP".
diff --git a/src/nvim/testdir/test_suspend.vim b/src/nvim/testdir/test_suspend.vim
index e569e49055..ef5a96bd72 100644
--- a/src/nvim/testdir/test_suspend.vim
+++ b/src/nvim/testdir/test_suspend.vim
@@ -2,6 +2,20 @@
source shared.vim
+func CheckSuspended(buf, fileExists)
+ call WaitForAssert({-> assert_match('[$#] $', term_getline(a:buf, '.'))})
+
+ if a:fileExists
+ call assert_equal(['foo'], readfile('Xfoo'))
+ else
+ " Without 'autowrite', buffer should not be written.
+ call assert_equal(0, filereadable('Xfoo'))
+ endif
+
+ call term_sendkeys(a:buf, "fg\<CR>\<C-L>")
+ call WaitForAssert({-> assert_equal(' 1 foo', term_getline(a:buf, '.'))})
+endfunc
+
func Test_suspend()
if !has('terminal') || !executable('/bin/sh')
return
@@ -26,13 +40,7 @@ func Test_suspend()
\ "\<C-Z>"]
" Suspend and wait for shell prompt.
call term_sendkeys(buf, suspend_cmd)
- call WaitForAssert({-> assert_match('[$#] $', term_getline(buf, '.'))})
-
- " Without 'autowrite', buffer should not be written.
- call assert_equal(0, filereadable('Xfoo'))
-
- call term_sendkeys(buf, "fg\<CR>")
- call WaitForAssert({-> assert_equal(' 1 foo', term_getline(buf, '.'))})
+ call CheckSuspended(buf, 0)
endfor
" Test that :suspend! with 'autowrite' writes content of buffers if modified.
@@ -40,14 +48,13 @@ func Test_suspend()
call assert_equal(0, filereadable('Xfoo'))
call term_sendkeys(buf, ":suspend\<CR>")
" Wait for shell prompt.
- call WaitForAssert({-> assert_match('[$#] $', term_getline(buf, '.'))})
- call assert_equal(['foo'], readfile('Xfoo'))
- call term_sendkeys(buf, "fg\<CR>")
- call WaitForAssert({-> assert_equal(' 1 foo', term_getline(buf, '.'))})
+ call CheckSuspended(buf, 1)
" Quit gracefully to dump coverage information.
call term_sendkeys(buf, ":qall!\<CR>")
call term_wait(buf)
+ " Wait until Vim actually exited and shell shows a prompt
+ call WaitForAssert({-> assert_match('[$#] $', term_getline(buf, '.'))})
call Stop_shell_in_terminal(buf)
exe buf . 'bwipe!'
diff --git a/src/nvim/testdir/test_syntax.vim b/src/nvim/testdir/test_syntax.vim
index 850947f89f..a3de879b2a 100644
--- a/src/nvim/testdir/test_syntax.vim
+++ b/src/nvim/testdir/test_syntax.vim
@@ -466,6 +466,8 @@ func Test_bg_detection()
set bg=dark
hi Normal ctermbg=12
call assert_equal('dark', &bg)
+
+ hi Normal ctermbg=NONE
endfunc
fun Test_synstack_synIDtrans()
diff --git a/src/nvim/testdir/test_tabline.vim b/src/nvim/testdir/test_tabline.vim
index 6c7a02d650..f24552088b 100644
--- a/src/nvim/testdir/test_tabline.vim
+++ b/src/nvim/testdir/test_tabline.vim
@@ -1,19 +1,22 @@
-function! TablineWithCaughtError()
+
+source shared.vim
+
+func TablineWithCaughtError()
let s:func_in_tabline_called = 1
try
call eval('unknown expression')
catch
endtry
return ''
-endfunction
+endfunc
-function! TablineWithError()
+func TablineWithError()
let s:func_in_tabline_called = 1
call eval('unknown expression')
return ''
-endfunction
+endfunc
-function! Test_caught_error_in_tabline()
+func Test_caught_error_in_tabline()
let showtabline_save = &showtabline
set showtabline=2
let s:func_in_tabline_called = 0
@@ -24,9 +27,9 @@ function! Test_caught_error_in_tabline()
call assert_equal(tabline, &tabline)
set tabline=
let &showtabline = showtabline_save
-endfunction
+endfunc
-function! Test_tabline_will_be_disabled_with_error()
+func Test_tabline_will_be_disabled_with_error()
let showtabline_save = &showtabline
set showtabline=2
let s:func_in_tabline_called = 0
@@ -40,4 +43,24 @@ function! Test_tabline_will_be_disabled_with_error()
call assert_equal('', &tabline)
set tabline=
let &showtabline = showtabline_save
-endfunction
+endfunc
+
+func Test_redrawtabline()
+ if has('gui')
+ set guioptions-=e
+ endif
+ let showtabline_save = &showtabline
+ set showtabline=2
+ set tabline=%{bufnr('$')}
+ edit Xtabline1
+ edit Xtabline2
+ redraw
+ call assert_match(bufnr('$') . '', Screenline(1))
+ au BufAdd * redrawtabline
+ badd Xtabline3
+ call assert_match(bufnr('$') . '', Screenline(1))
+
+ set tabline=
+ let &showtabline = showtabline_save
+ au! Bufadd
+endfunc
diff --git a/src/nvim/testdir/test_tagcase.vim b/src/nvim/testdir/test_tagcase.vim
index 833cb9f990..53c08ccf1e 100644
--- a/src/nvim/testdir/test_tagcase.vim
+++ b/src/nvim/testdir/test_tagcase.vim
@@ -44,6 +44,7 @@ func Test_tagcase()
endfor
call delete('Xtags')
+ set tags&
set ic&
setg tc&
setl tc&
diff --git a/src/nvim/testdir/test_tagjump.vim b/src/nvim/testdir/test_tagjump.vim
index 21ea00cab7..ce527a5e1d 100644
--- a/src/nvim/testdir/test_tagjump.vim
+++ b/src/nvim/testdir/test_tagjump.vim
@@ -20,6 +20,7 @@ func Test_cancel_ptjump()
call assert_equal(2, winnr('$'))
call delete('Xtags')
+ set tags&
quit
endfunc
@@ -104,6 +105,7 @@ func Test_tagjump_switchbuf()
enew | only
call delete('Xfile1')
call delete('Xtags')
+ set tags&
set switchbuf&vim
endfunc
@@ -424,7 +426,7 @@ func Test_tagnr_recall()
tag
call assert_equal(bufname('%'), 'Xtest.h')
- set tag&
+ set tags&
call delete('Xtags')
bwipe Xtest.h
bwipe Xtest.c
@@ -460,6 +462,7 @@ func Test_tag_line_toolong()
endtry
call assert_equal('Ignoring long line in tags file', split(execute('messages'), '\n')[-1])
call delete('Xtags')
+ set tags&
let &verbose = old_vbs
endfunc
diff --git a/src/nvim/testdir/test_taglist.vim b/src/nvim/testdir/test_taglist.vim
index ea0a6b9678..eb64e59509 100644
--- a/src/nvim/testdir/test_taglist.vim
+++ b/src/nvim/testdir/test_taglist.vim
@@ -5,7 +5,9 @@ func Test_taglist()
\ "FFoo\tXfoo\t1",
\ "FBar\tXfoo\t2",
\ "BFoo\tXbar\t1",
- \ "BBar\tXbar\t2"
+ \ "BBar\tXbar\t2",
+ \ "Kindly\tXbar\t3;\"\tv\tfile:",
+ \ "Command\tXbar\tcall cursor(3, 4)|;\"\td",
\ ], 'Xtags')
set tags=Xtags
split Xtext
@@ -15,7 +17,20 @@ func Test_taglist()
call assert_equal(['FFoo', 'BFoo'], map(taglist("Foo", "Xfoo"), {i, v -> v.name}))
call assert_equal(['BFoo', 'FFoo'], map(taglist("Foo", "Xbar"), {i, v -> v.name}))
+ let kind = taglist("Kindly")
+ call assert_equal(1, len(kind))
+ call assert_equal('v', kind[0]['kind'])
+ call assert_equal('3', kind[0]['cmd'])
+ call assert_equal(1, kind[0]['static'])
+ call assert_equal('Xbar', kind[0]['filename'])
+
+ let cmd = taglist("Command")
+ call assert_equal(1, len(cmd))
+ call assert_equal('d', cmd[0]['kind'])
+ call assert_equal('call cursor(3, 4)', cmd[0]['cmd'])
+
call delete('Xtags')
+ set tags&
bwipe
endfunc
@@ -36,6 +51,7 @@ func Test_taglist_native_etags()
\ map(taglist('set_signals'), {i, v -> [v.name, v.cmd]}))
call delete('Xtags')
+ set tags&
endfunc
func Test_taglist_ctags_etags()
@@ -55,6 +71,7 @@ func Test_taglist_ctags_etags()
\ map(taglist('set_signals'), {i, v -> [v.name, v.cmd]}))
call delete('Xtags')
+ set tags&
endfunc
func Test_tags_too_long()
@@ -62,19 +79,6 @@ func Test_tags_too_long()
tags
endfunc
-" For historical reasons we support a tags file where the last line is missing
-" the newline.
-func Test_tagsfile_without_trailing_newline()
- call writefile(["Foo\tfoo\t1"], 'Xtags', 'b')
- set tags=Xtags
-
- let tl = taglist('.*')
- call assert_equal(1, len(tl))
- call assert_equal('Foo', tl[0].name)
-
- call delete('Xtags')
-endfunc
-
func Test_tagfiles()
call assert_equal([], tagfiles())
@@ -90,10 +94,25 @@ func Test_tagfiles()
\ fnamemodify(tf[0], ':p:gs?\\?/?'))
helpclose
call assert_equal(['Xtags1', 'Xtags2'], tagfiles())
- set tags&
+ " Nvim: defaults to "./tags;,tags", which might cause false positives.
+ set tags=./tags,tags
call assert_equal([], tagfiles())
call delete('Xtags1')
call delete('Xtags2')
bd
endfunc
+
+" For historical reasons we support a tags file where the last line is missing
+" the newline.
+func Test_tagsfile_without_trailing_newline()
+ call writefile(["Foo\tfoo\t1"], 'Xtags', 'b')
+ set tags=Xtags
+
+ let tl = taglist('.*')
+ call assert_equal(1, len(tl))
+ call assert_equal('Foo', tl[0].name)
+
+ call delete('Xtags')
+ set tags&
+endfunc
diff --git a/src/nvim/testdir/test_usercommands.vim b/src/nvim/testdir/test_usercommands.vim
index 1520c2f32a..b23a4aa62f 100644
--- a/src/nvim/testdir/test_usercommands.vim
+++ b/src/nvim/testdir/test_usercommands.vim
@@ -73,6 +73,97 @@ function Test_cmdmods()
unlet g:mods
endfunction
+func SaveCmdArgs(...)
+ let g:args = a:000
+endfunc
+
+func Test_f_args()
+ command -nargs=* TestFArgs call SaveCmdArgs(<f-args>)
+
+ TestFArgs
+ call assert_equal([], g:args)
+
+ TestFArgs one two three
+ call assert_equal(['one', 'two', 'three'], g:args)
+
+ TestFArgs one\\two three
+ call assert_equal(['one\two', 'three'], g:args)
+
+ TestFArgs one\ two three
+ call assert_equal(['one two', 'three'], g:args)
+
+ TestFArgs one\"two three
+ call assert_equal(['one\"two', 'three'], g:args)
+
+ delcommand TestFArgs
+endfunc
+
+func Test_q_args()
+ command -nargs=* TestQArgs call SaveCmdArgs(<q-args>)
+
+ TestQArgs
+ call assert_equal([''], g:args)
+
+ TestQArgs one two three
+ call assert_equal(['one two three'], g:args)
+
+ TestQArgs one\\two three
+ call assert_equal(['one\\two three'], g:args)
+
+ TestQArgs one\ two three
+ call assert_equal(['one\ two three'], g:args)
+
+ TestQArgs one\"two three
+ call assert_equal(['one\"two three'], g:args)
+
+ delcommand TestQArgs
+endfunc
+
+func Test_reg_arg()
+ command -nargs=* -reg TestRegArg call SaveCmdArgs("<reg>", "<register>")
+
+ TestRegArg
+ call assert_equal(['', ''], g:args)
+
+ TestRegArg x
+ call assert_equal(['x', 'x'], g:args)
+
+ delcommand TestRegArg
+endfunc
+
+func Test_no_arg()
+ command -nargs=* TestNoArg call SaveCmdArgs("<args>", "<>", "<x>", "<lt>")
+
+ TestNoArg
+ call assert_equal(['', '<>', '<x>', '<'], g:args)
+
+ TestNoArg one
+ call assert_equal(['one', '<>', '<x>', '<'], g:args)
+
+ delcommand TestNoArg
+endfunc
+
+func Test_range_arg()
+ command -range TestRangeArg call SaveCmdArgs(<range>, <line1>, <line2>)
+ new
+ call setline(1, range(100))
+ let lnum = line('.')
+
+ TestRangeArg
+ call assert_equal([0, lnum, lnum], g:args)
+
+ 99TestRangeArg
+ call assert_equal([1, 99, 99], g:args)
+
+ 88,99TestRangeArg
+ call assert_equal([2, 88, 99], g:args)
+
+ call assert_fails('102TestRangeArg', 'E16:')
+
+ bwipe!
+ delcommand TestRangeArg
+endfunc
+
func Test_Ambiguous()
command Doit let g:didit = 'yes'
command Dothat let g:didthat = 'also'
@@ -88,6 +179,9 @@ func Test_Ambiguous()
Do
call assert_equal('also', g:didthat)
delcommand Dothat
+
+ " Nvim removed the ":Ni!" easter egg in 87e107d92.
+ call assert_fails("\x4ei\041", 'E492: Not an editor command: Ni!')
endfunc
func Test_CmdUndefined()
@@ -111,6 +205,7 @@ func Test_CmdErrors()
call assert_fails('com! - DoCmd :', 'E175:')
call assert_fails('com! -xxx DoCmd :', 'E181:')
call assert_fails('com! -addr DoCmd :', 'E179:')
+ call assert_fails('com! -addr=asdf DoCmd :', 'E180:')
call assert_fails('com! -complete DoCmd :', 'E179:')
call assert_fails('com! -complete=xxx DoCmd :', 'E180:')
call assert_fails('com! -complete=custom DoCmd :', 'E467:')
diff --git a/src/nvim/testdir/test_vimscript.vim b/src/nvim/testdir/test_vimscript.vim
index 05abf04d65..f39e53d6dd 100644
--- a/src/nvim/testdir/test_vimscript.vim
+++ b/src/nvim/testdir/test_vimscript.vim
@@ -1,4 +1,4 @@
-" Test various aspects of the Vim language.
+" Test various aspects of the Vim script language.
" Most of this was formerly in test49.
"-------------------------------------------------------------------------------
@@ -21,7 +21,7 @@ com! -nargs=1 Xout call Xout(<args>)
"
" Create a script that consists of the body of the function a:funcname.
" Replace any ":return" by a ":finish", any argument variable by a global
-" variable, and and every ":call" by a ":source" for the next following argument
+" variable, and every ":call" by a ":source" for the next following argument
" in the variable argument list. This function is useful if similar tests are
" to be made for a ":return" from a function call or a ":finish" in a script
" file.
@@ -1310,6 +1310,43 @@ func Test_compound_assignment_operators()
let x .= 'n'
call assert_equal('2n', x)
+ " Test special cases: division or modulus with 0.
+ let x = 1
+ let x /= 0
+ if has('num64')
+ call assert_equal(0x7FFFFFFFFFFFFFFF, x)
+ else
+ call assert_equal(0x7fffffff, x)
+ endif
+
+ let x = -1
+ let x /= 0
+ if has('num64')
+ call assert_equal(-0x7FFFFFFFFFFFFFFF, x)
+ else
+ call assert_equal(-0x7fffffff, x)
+ endif
+
+ let x = 0
+ let x /= 0
+ if has('num64')
+ call assert_equal(-0x7FFFFFFFFFFFFFFF - 1, x)
+ else
+ call assert_equal(-0x7FFFFFFF - 1, x)
+ endif
+
+ let x = 1
+ let x %= 0
+ call assert_equal(0, x)
+
+ let x = -1
+ let x %= 0
+ call assert_equal(0, x)
+
+ let x = 0
+ let x %= 0
+ call assert_equal(0, x)
+
" Test for string
let x = 'str'
let x .= 'ing'
@@ -1375,5 +1412,4 @@ endfunc
"-------------------------------------------------------------------------------
" Modelines {{{1
" vim: ts=8 sw=4 tw=80 fdm=marker
-" vim: fdt=substitute(substitute(foldtext(),\ '\\%(^+--\\)\\@<=\\(\\s*\\)\\(.\\{-}\\)\:\ \\%(\"\ \\)\\=\\(Test\ \\d*\\)\:\\s*',\ '\\3\ (\\2)\:\ \\1',\ \"\"),\ '\\(Test\\s*\\)\\(\\d\\)\\D\\@=',\ '\\1\ \\2',\ "")
"-------------------------------------------------------------------------------
diff --git a/src/nvim/testdir/test_virtualedit.vim b/src/nvim/testdir/test_virtualedit.vim
index d49025237b..abe79f6a4a 100644
--- a/src/nvim/testdir/test_virtualedit.vim
+++ b/src/nvim/testdir/test_virtualedit.vim
@@ -42,6 +42,22 @@ func Test_paste_end_of_line()
set virtualedit=
endfunc
+func Test_replace_end_of_line()
+ new
+ set virtualedit=all
+ call setline(1, range(20))
+ exe "normal! gg2jv10lr-"
+ call assert_equal(["1", "-----------", "3"], getline(2,4))
+ if has('multi_byte')
+ call setline(1, range(20))
+ exe "normal! gg2jv10lr\<c-k>hh"
+ call assert_equal(["1", "───────────", "3"], getline(2,4))
+ endif
+
+ bwipe!
+ set virtualedit=
+endfunc
+
func Test_edit_CTRL_G()
new
set virtualedit=insert
diff --git a/src/nvim/testdir/test_window_cmd.vim b/src/nvim/testdir/test_window_cmd.vim
index 003a23ea7b..2a07a04401 100644
--- a/src/nvim/testdir/test_window_cmd.vim
+++ b/src/nvim/testdir/test_window_cmd.vim
@@ -518,6 +518,43 @@ func Test_winrestcmd()
only
endfunc
+function! Fun_RenewFile()
+ sleep 2
+ silent execute '!echo "1" > tmp.txt'
+ sp
+ wincmd p
+ edit! tmp.txt
+endfunction
+
+func Test_window_prevwin()
+ " Can we make this work on MS-Windows?
+ if !has('unix')
+ return
+ endif
+
+ set hidden autoread
+ call writefile(['2'], 'tmp.txt')
+ new tmp.txt
+ q
+ " Need to wait a bit for the timestamp to be older.
+ call Fun_RenewFile()
+ call assert_equal(2, winnr())
+ wincmd p
+ call assert_equal(1, winnr())
+ wincmd p
+ q
+ call Fun_RenewFile()
+ call assert_equal(2, winnr())
+ wincmd p
+ call assert_equal(1, winnr())
+ wincmd p
+ " reset
+ q
+ call delete('tmp.txt')
+ set hidden&vim autoread&vim
+ delfunc Fun_RenewFile
+endfunc
+
func Test_relative_cursor_position_in_one_line_window()
new
only
diff --git a/src/nvim/testdir/test_windows_home.vim b/src/nvim/testdir/test_windows_home.vim
index bbcbf96050..2e311b9aa5 100644
--- a/src/nvim/testdir/test_windows_home.vim
+++ b/src/nvim/testdir/test_windows_home.vim
@@ -86,7 +86,7 @@ func Test_WindowsHome()
let $HOME = '%USERPROFILE%\bar'
let $HOMEDRIVE = 'unused'
let $HOMEPATH = 'unused'
- " call CheckHome('C:\foo\bar', '%USERPROFILE%\bar')
+ call CheckHome('C:\foo\bar', '%USERPROFILE%\bar')
" Invalid $HOME is kept
let $USERPROFILE = 'C:\foo'
diff --git a/src/nvim/testdir/test_writefile.vim b/src/nvim/testdir/test_writefile.vim
index 9da9df2150..6d88c0d8cd 100644
--- a/src/nvim/testdir/test_writefile.vim
+++ b/src/nvim/testdir/test_writefile.vim
@@ -33,7 +33,7 @@ func Test_writefile_fails_gently()
endfunc
func Test_writefile_fails_conversion()
- if !has('multi_byte') || !has('iconv')
+ if !has('multi_byte') || !has('iconv') || system('uname -s') =~ 'SunOS'
return
endif
" Without a backup file the write won't happen if there is a conversion
diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c
index 7a725df0a1..fe8ffee8e0 100644
--- a/src/nvim/tui/input.c
+++ b/src/nvim/tui/input.c
@@ -32,23 +32,6 @@ void tinput_init(TermInput *input, Loop *loop)
uv_mutex_init(&input->key_buffer_mutex);
uv_cond_init(&input->key_buffer_cond);
- const char *term = os_getenv("TERM");
- if (!term) {
- term = ""; // termkey_new_abstract assumes non-null (#2745)
- }
-
-#if TERMKEY_VERSION_MAJOR > 0 || TERMKEY_VERSION_MINOR > 18
- input->tk = termkey_new_abstract(term,
- TERMKEY_FLAG_UTF8 | TERMKEY_FLAG_NOSTART);
- termkey_hook_terminfo_getstr(input->tk, input->tk_ti_hook_fn, NULL);
- termkey_start(input->tk);
-#else
- input->tk = termkey_new_abstract(term, TERMKEY_FLAG_UTF8);
-#endif
-
- int curflags = termkey_get_canonflags(input->tk);
- termkey_set_canonflags(input->tk, curflags | TERMKEY_CANON_DELBS);
-
// If stdin is not a pty, switch to stderr. For cases like:
// echo q | nvim -es
// ls *.md | xargs nvim
@@ -67,6 +50,24 @@ void tinput_init(TermInput *input, Loop *loop)
input->in_fd = 2;
}
#endif
+ input_global_fd_init(input->in_fd);
+
+ const char *term = os_getenv("TERM");
+ if (!term) {
+ term = ""; // termkey_new_abstract assumes non-null (#2745)
+ }
+
+#if TERMKEY_VERSION_MAJOR > 0 || TERMKEY_VERSION_MINOR > 18
+ input->tk = termkey_new_abstract(term,
+ TERMKEY_FLAG_UTF8 | TERMKEY_FLAG_NOSTART);
+ termkey_hook_terminfo_getstr(input->tk, input->tk_ti_hook_fn, NULL);
+ termkey_start(input->tk);
+#else
+ input->tk = termkey_new_abstract(term, TERMKEY_FLAG_UTF8);
+#endif
+
+ int curflags = termkey_get_canonflags(input->tk);
+ termkey_set_canonflags(input->tk, curflags | TERMKEY_CANON_DELBS);
// setup input handle
rstream_init_fd(loop, &input->read_stream, input->in_fd, 0xfff);
@@ -387,17 +388,20 @@ static void set_bg_deferred(void **argv)
// During startup, tui.c requests the background color (see `ext.get_bg`).
//
// Here in input.c, we watch for the terminal response `\e]11;COLOR\a`. If
-// COLOR matches `rgb:RRRR/GGGG/BBBB` where R, G, and B are hex digits, then
-// compute the luminance[1] of the RGB color and classify it as light/dark
+// COLOR matches `rgb:RRRR/GGGG/BBBB/AAAA` where R, G, B, and A are hex digits,
+// then compute the luminance[1] of the RGB color and classify it as light/dark
// accordingly. Note that the color components may have anywhere from one to
// four hex digits, and require scaling accordingly as values out of 4, 8, 12,
-// or 16 bits.
+// or 16 bits. Also note the A(lpha) component is optional, and is parsed but
+// ignored in the calculations.
//
// [1] https://en.wikipedia.org/wiki/Luma_%28video%29
static bool handle_background_color(TermInput *input)
{
size_t count = 0;
size_t component = 0;
+ size_t header_size = 0;
+ size_t num_components = 0;
uint16_t rgb[] = { 0, 0, 0 };
uint16_t rgb_max[] = { 0, 0, 0 };
bool eat_backslash = false;
@@ -405,48 +409,54 @@ static bool handle_background_color(TermInput *input)
bool bad = false;
if (rbuffer_size(input->read_stream.buffer) >= 9
&& !rbuffer_cmp(input->read_stream.buffer, "\x1b]11;rgb:", 9)) {
- rbuffer_consumed(input->read_stream.buffer, 9);
- RBUFFER_EACH(input->read_stream.buffer, c, i) {
- count = i + 1;
- if (eat_backslash) {
- done = true;
- break;
- } else if (c == '\x07') {
- done = true;
- break;
- } else if (c == '\x1b') {
- eat_backslash = true;
- } else if (bad) {
- // ignore
- } else if (c == '/') {
- if (component < 3) {
- component++;
- }
- } else if (ascii_isxdigit(c)) {
- if (component < 3 && rgb_max[component] != 0xffff) {
- rgb_max[component] = (uint16_t)((rgb_max[component] << 4) | 0xf);
- rgb[component] = (uint16_t)((rgb[component] << 4) | hex2nr(c));
- }
- } else {
- bad = true;
+ header_size = 9;
+ num_components = 3;
+ } else if (rbuffer_size(input->read_stream.buffer) >= 10
+ && !rbuffer_cmp(input->read_stream.buffer, "\x1b]11;rgba:", 10)) {
+ header_size = 10;
+ num_components = 4;
+ } else {
+ return false;
+ }
+ rbuffer_consumed(input->read_stream.buffer, header_size);
+ RBUFFER_EACH(input->read_stream.buffer, c, i) {
+ count = i + 1;
+ if (eat_backslash) {
+ done = true;
+ break;
+ } else if (c == '\x07') {
+ done = true;
+ break;
+ } else if (c == '\x1b') {
+ eat_backslash = true;
+ } else if (bad) {
+ // ignore
+ } else if ((c == '/') && (++component < num_components)) {
+ // work done in condition
+ } else if (ascii_isxdigit(c)) {
+ if (component < 3 && rgb_max[component] != 0xffff) {
+ rgb_max[component] = (uint16_t)((rgb_max[component] << 4) | 0xf);
+ rgb[component] = (uint16_t)((rgb[component] << 4) | hex2nr(c));
}
- }
- rbuffer_consumed(input->read_stream.buffer, count);
- if (done && !bad && rgb_max[0] && rgb_max[1] && rgb_max[2]) {
- double r = (double)rgb[0] / (double)rgb_max[0];
- double g = (double)rgb[1] / (double)rgb_max[1];
- double b = (double)rgb[2] / (double)rgb_max[2];
- double luminance = (0.299 * r) + (0.587 * g) + (0.114 * b); // CCIR 601
- char *bgvalue = luminance < 0.5 ? "dark" : "light";
- DLOG("bg response: %s", bgvalue);
- loop_schedule_deferred(&main_loop,
- event_create(set_bg_deferred, 1, bgvalue));
} else {
- DLOG("failed to parse bg response");
+ bad = true;
}
- return true;
}
- return false;
+ rbuffer_consumed(input->read_stream.buffer, count);
+ if (done && !bad && rgb_max[0] && rgb_max[1] && rgb_max[2]) {
+ double r = (double)rgb[0] / (double)rgb_max[0];
+ double g = (double)rgb[1] / (double)rgb_max[1];
+ double b = (double)rgb[2] / (double)rgb_max[2];
+ double luminance = (0.299 * r) + (0.587 * g) + (0.114 * b); // CCIR 601
+ char *bgvalue = luminance < 0.5 ? "dark" : "light";
+ DLOG("bg response: %s", bgvalue);
+ loop_schedule_deferred(&main_loop,
+ event_create(set_bg_deferred, 1, bgvalue));
+ } else {
+ DLOG("failed to parse bg response");
+ return false;
+ }
+ return true;
}
static void tinput_read_cb(Stream *stream, RBuffer *buf, size_t count_,
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index 42e5b9b270..519ef1cccd 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -222,15 +222,20 @@ static void terminfo_start(UI *ui)
#ifdef WIN32
os_tty_guess_term(&term, data->out_fd);
os_setenv("TERM", term, 1);
+ // Old os_getenv() pointer is invalid after os_setenv(), fetch it again.
+ term = os_getenv("TERM");
#endif
// Set up unibilium/terminfo.
- data->ut = unibi_from_env();
char *termname = NULL;
- if (!term || !data->ut) {
+ if (term) {
+ data->ut = unibi_from_term(term);
+ if (data->ut) {
+ termname = xstrdup(term);
+ }
+ }
+ if (!data->ut) {
data->ut = terminfo_from_builtin(term, &termname);
- } else {
- termname = xstrdup(term);
}
// Update 'term' option.
loop_schedule_deferred(&main_loop,
@@ -1585,6 +1590,11 @@ static void patch_terminfo_bugs(TUIData *data, const char *term,
unibi_set_if_empty(ut, unibi_set_left_margin_parm, "\x1b[%i%p1%ds");
unibi_set_if_empty(ut, unibi_set_right_margin_parm, "\x1b[%i;%p2%ds");
}
+
+#ifdef WIN32
+ // XXX: workaround libuv implicit LF => CRLF conversion. #10558
+ unibi_set_str(ut, unibi_cursor_down, "\x1b[B");
+#endif
} else if (rxvt) {
// 2017-04 terminfo.src lacks these. Unicode rxvt has them.
unibi_set_if_empty(ut, unibi_enter_italics_mode, "\x1b[3m");
diff --git a/src/nvim/ugrid.c b/src/nvim/ugrid.c
index 8adb421ee1..9e4aaff878 100644
--- a/src/nvim/ugrid.c
+++ b/src/nvim/ugrid.c
@@ -6,6 +6,7 @@
#include <stdio.h>
#include <limits.h>
+#include "nvim/assert.h"
#include "nvim/vim.h"
#include "nvim/ui.h"
#include "nvim/ugrid.h"
@@ -72,8 +73,9 @@ void ugrid_scroll(UGrid *grid, int top, int bot, int left, int right, int count)
for (i = start; i != stop; i += step) {
UCell *target_row = grid->cells[i] + left;
UCell *source_row = grid->cells[i + count] + left;
+ assert(right >= left && left >= 0);
memcpy(target_row, source_row,
- sizeof(UCell) * (size_t)(right - left + 1));
+ sizeof(UCell) * ((size_t)right - (size_t)left + 1));
}
}
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index 7dbb8ec790..fc4a3a403d 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -341,15 +341,15 @@ void ui_line(ScreenGrid *grid, int row, int startcol, int endcol, int clearcol,
flags, (const schar_T *)grid->chars + off,
(const sattr_T *)grid->attrs + off);
- if (p_wd) { // 'writedelay': flush & delay each time.
- int old_row = cursor_row, old_col = cursor_col;
- handle_T old_grid = cursor_grid_handle;
+ // 'writedelay': flush & delay each time.
+ if (p_wd && !(rdb_flags & RDB_COMPOSITOR)) {
// If 'writedelay' is active, set the cursor to indicate what was drawn.
- ui_grid_cursor_goto(grid->handle, row, MIN(clearcol, (int)Columns-1));
- ui_flush();
+ ui_call_grid_cursor_goto(grid->handle, row,
+ MIN(clearcol, (int)grid->Columns-1));
+ ui_call_flush();
uint64_t wd = (uint64_t)labs(p_wd);
os_microdelay(wd * 1000u, true);
- ui_grid_cursor_goto(old_grid, old_row, old_col);
+ pending_cursor_update = true; // restore the cursor later
}
}
@@ -372,6 +372,14 @@ void ui_grid_cursor_goto(handle_T grid_handle, int new_row, int new_col)
pending_cursor_update = true;
}
+/// moving the cursor grid will implicitly move the cursor
+void ui_check_cursor_grid(handle_T grid_handle)
+{
+ if (cursor_grid_handle == grid_handle) {
+ pending_cursor_update = true;
+ }
+}
+
void ui_mode_info_set(void)
{
pending_mode_info_update = true;
diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c
index f6573e7488..2cb3cf7ee7 100644
--- a/src/nvim/ui_compositor.c
+++ b/src/nvim/ui_compositor.c
@@ -49,6 +49,8 @@ static bool valid_screen = true;
static bool msg_scroll_mode = false;
static int msg_first_invalid = 0;
+static int dbghl_normal, dbghl_clear, dbghl_composed, dbghl_recompose;
+
void ui_comp_init(void)
{
if (compositor != NULL) {
@@ -81,6 +83,13 @@ void ui_comp_init(void)
ui_attach_impl(compositor);
}
+void ui_comp_syn_init(void)
+{
+ dbghl_normal = syn_check_group((char_u *)S_LEN("RedrawDebugNormal"));
+ dbghl_clear = syn_check_group((char_u *)S_LEN("RedrawDebugClear"));
+ dbghl_composed = syn_check_group((char_u *)S_LEN("RedrawDebugComposed"));
+ dbghl_recompose = syn_check_group((char_u *)S_LEN("RedrawDebugRecompose"));
+}
void ui_comp_attach(UI *ui)
{
@@ -290,10 +299,14 @@ static void compose_line(Integer row, Integer startcol, Integer endcol,
{
// in case we start on the right half of a double-width char, we need to
// check the left half. But skip it in output if it wasn't doublewidth.
- int skip = 0;
+ int skipstart = 0, skipend = 0;
if (startcol > 0 && (flags & kLineFlagInvalid)) {
startcol--;
- skip = 1;
+ skipstart = 1;
+ }
+ if (endcol < default_grid.Columns && (flags & kLineFlagInvalid)) {
+ endcol++;
+ skipend = 1;
}
int col = (int)startcol;
@@ -329,13 +342,24 @@ static void compose_line(Integer row, Integer startcol, Integer endcol,
memcpy(linebuf+(col-startcol), grid->chars+off, n * sizeof(*linebuf));
memcpy(attrbuf+(col-startcol), grid->attrs+off, n * sizeof(*attrbuf));
- // 'pumblend'
- if (grid == &pum_grid && p_pb) {
- for (int i = col-(int)startcol; i < until-startcol; i++) {
- bool thru = strequal((char *)linebuf[i], " "); // negative space
- attrbuf[i] = (sattr_T)hl_blend_attrs(bg_attrs[i], attrbuf[i], thru);
+ // 'pumblend' and 'winblend'
+ if (grid->blending) {
+ int width;
+ for (int i = col-(int)startcol; i < until-startcol; i += width) {
+ width = 1;
+ // negative space
+ bool thru = strequal((char *)linebuf[i], " ") && bg_line[i][0] != NUL;
+ if (i+1 < endcol-startcol && bg_line[i+1][0] == NUL) {
+ width = 2;
+ thru &= strequal((char *)linebuf[i+1], " ");
+ }
+ attrbuf[i] = (sattr_T)hl_blend_attrs(bg_attrs[i], attrbuf[i], &thru);
+ if (width == 2) {
+ attrbuf[i+1] = (sattr_T)hl_blend_attrs(bg_attrs[i+1],
+ attrbuf[i+1], &thru);
+ }
if (thru) {
- memcpy(linebuf[i], bg_line[i], sizeof(linebuf[i]));
+ memcpy(linebuf + i, bg_line + i, (size_t)width * sizeof(linebuf[i]));
}
}
}
@@ -345,20 +369,27 @@ static void compose_line(Integer row, Integer startcol, Integer endcol,
if (linebuf[col-startcol][0] == NUL) {
linebuf[col-startcol][0] = ' ';
linebuf[col-startcol][1] = NUL;
+ if (col == endcol-1) {
+ skipend = 0;
+ }
} else if (n > 1 && linebuf[col-startcol+1][0] == NUL) {
- skip = 0;
+ skipstart = 0;
}
if (grid->comp_col+grid->Columns > until
&& grid->chars[off+n][0] == NUL) {
linebuf[until-1-startcol][0] = ' ';
linebuf[until-1-startcol][1] = '\0';
if (col == startcol && n == 1) {
- skip = 0;
+ skipstart = 0;
}
}
col = until;
}
+ if (linebuf[endcol-startcol-1][0] == NUL) {
+ skipend = 0;
+ }
+
assert(endcol <= chk_width);
assert(row < chk_height);
@@ -368,14 +399,48 @@ static void compose_line(Integer row, Integer startcol, Integer endcol,
flags = flags & ~kLineFlagWrap;
}
- ui_composed_call_raw_line(1, row, startcol+skip, endcol, endcol, 0, flags,
- (const schar_T *)linebuf+skip,
- (const sattr_T *)attrbuf+skip);
+ ui_composed_call_raw_line(1, row, startcol+skipstart,
+ endcol-skipend, endcol-skipend, 0, flags,
+ (const schar_T *)linebuf+skipstart,
+ (const sattr_T *)attrbuf+skipstart);
}
+static void compose_debug(Integer startrow, Integer endrow, Integer startcol,
+ Integer endcol, int syn_id, bool delay)
+{
+ if (!(rdb_flags & RDB_COMPOSITOR)) {
+ return;
+ }
+
+ endrow = MIN(endrow, default_grid.Rows);
+ endcol = MIN(endcol, default_grid.Columns);
+ int attr = syn_id2attr(syn_id);
+
+ for (int row = (int)startrow; row < endrow; row++) {
+ ui_composed_call_raw_line(1, row, startcol, startcol, endcol, attr, false,
+ (const schar_T *)linebuf,
+ (const sattr_T *)attrbuf);
+ }
+
+
+ if (delay) {
+ debug_delay(endrow-startrow);
+ }
+}
+
+static void debug_delay(Integer lines)
+{
+ ui_call_flush();
+ uint64_t wd = (uint64_t)labs(p_wd);
+ uint64_t factor = (uint64_t)MAX(MIN(lines, 5), 1);
+ os_microdelay(factor * wd * 1000u, true);
+}
+
+
static void compose_area(Integer startrow, Integer endrow,
Integer startcol, Integer endcol)
{
+ compose_debug(startrow, endrow, startcol, endcol, dbghl_recompose, true);
endrow = MIN(endrow, default_grid.Rows);
endcol = MIN(endcol, default_grid.Columns);
if (endcol <= startcol) {
@@ -419,9 +484,12 @@ static void ui_comp_raw_line(UI *ui, Integer grid, Integer row,
assert(clearcol <= default_grid.Columns);
if (flags & kLineFlagInvalid
|| kv_size(layers) > curgrid->comp_index+1
- || (p_pb && curgrid == &pum_grid)) {
+ || curgrid->blending) {
+ compose_debug(row, row+1, startcol, clearcol, dbghl_composed, true);
compose_line(row, startcol, clearcol, flags);
} else {
+ compose_debug(row, row+1, startcol, endcol, dbghl_normal, false);
+ compose_debug(row, row+1, endcol, clearcol, dbghl_clear, true);
ui_composed_call_raw_line(1, row, startcol, endcol, clearcol, clearattr,
flags, chunk, attrs);
}
@@ -467,7 +535,8 @@ static void ui_comp_grid_scroll(UI *ui, Integer grid, Integer top,
bot += curgrid->comp_row;
left += curgrid->comp_col;
right += curgrid->comp_col;
- if (!msg_scroll_mode && kv_size(layers) > curgrid->comp_index+1) {
+ bool covered = kv_size(layers) > curgrid->comp_index+1 || curgrid->blending;
+ if (!msg_scroll_mode && covered) {
// TODO(bfredl):
// 1. check if rectangles actually overlap
// 2. calulate subareas that can scroll.
@@ -480,6 +549,9 @@ static void ui_comp_grid_scroll(UI *ui, Integer grid, Integer top,
} else {
msg_first_invalid = MIN(msg_first_invalid, (int)top);
ui_composed_call_grid_scroll(1, top, bot, left, right, rows, cols);
+ if (rdb_flags & RDB_COMPOSITOR) {
+ debug_delay(2);
+ }
}
}
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index 116bdd02b8..1a31f6a6c7 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -85,6 +85,7 @@
#include "nvim/buffer.h"
#include "nvim/ascii.h"
+#include "nvim/change.h"
#include "nvim/undo.h"
#include "nvim/cursor.h"
#include "nvim/edit.h"
@@ -1299,7 +1300,7 @@ void u_read_undo(char *name, char_u *hash, char_u *orig_name)
verbose_leave();
}
- FILE *fp = mch_fopen(file_name, "r");
+ FILE *fp = os_fopen(file_name, "r");
if (fp == NULL) {
if (name != NULL || p_verbose > 0) {
EMSG2(_("E822: Cannot open undo file for reading: %s"), file_name);
@@ -2961,10 +2962,23 @@ static char_u *u_save_line(linenr_T lnum)
///
/// @return true if the buffer has changed
bool bufIsChanged(buf_T *buf)
+ FUNC_ATTR_WARN_UNUSED_RESULT
{
return !bt_dontwrite(buf) && (buf->b_changed || file_ff_differs(buf, true));
}
+// Return true if any buffer has changes. Also buffers that are not written.
+bool anyBufIsChanged(void)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ FOR_ALL_BUFFERS(buf) {
+ if (bufIsChanged(buf)) {
+ return true;
+ }
+ }
+ return false;
+}
+
/// Check if the 'modified' flag is set, or 'ff' has changed (only need to
/// check the first character, because it can only be "dos", "unix" or "mac").
/// "nofile" and "scratch" type buffers are considered to always be unchanged.
diff --git a/src/nvim/version.c b/src/nvim/version.c
index be7a2ffcad..74a4852def 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -52,12 +52,8 @@ static char *features[] = {
"-acl",
#endif
-#if (defined(HAVE_ICONV_H) && defined(USE_ICONV)) || defined(DYNAMIC_ICONV)
-# ifdef DYNAMIC_ICONV
-"+iconv/dyn",
-# else
+#if defined(HAVE_ICONV)
"+iconv",
-# endif
#else
"-iconv",
#endif
@@ -76,7 +72,7 @@ static const int included_patches[] = {
// 1848,
1847,
// 1846,
- // 1845,
+ 1845,
// 1844,
1843,
// 1842,
@@ -137,7 +133,7 @@ static const int included_patches[] = {
1787,
// 1786,
1785,
- // 1784,
+ 1784,
// 1783,
1782,
1781,
@@ -165,7 +161,7 @@ static const int included_patches[] = {
// 1759,
1758,
1757,
- // 1756,
+ 1756,
1755,
// 1754,
// 1753,
@@ -186,7 +182,7 @@ static const int included_patches[] = {
// 1738,
1737,
1736,
- // 1735,
+ 1735,
1734,
// 1733,
// 1732,
@@ -195,10 +191,10 @@ static const int included_patches[] = {
// 1729,
// 1728,
1727,
- // 1726,
+ 1726,
// 1725,
// 1724,
- // 1723,
+ 1723,
// 1722,
// 1721,
// 1720,
@@ -217,9 +213,9 @@ static const int included_patches[] = {
1707,
// 1706,
1705,
- // 1704,
+ 1704,
// 1703,
- // 1702,
+ 1702,
1701,
1700,
1699,
@@ -232,7 +228,7 @@ static const int included_patches[] = {
1692,
// 1691,
// 1690,
- // 1689,
+ 1689,
// 1688,
1687,
1686,
@@ -252,7 +248,7 @@ static const int included_patches[] = {
1672,
// 1671,
// 1670,
- // 1669,
+ 1669,
// 1668,
// 1667,
// 1666,
@@ -372,7 +368,7 @@ static const int included_patches[] = {
// 1552,
// 1551,
// 1550,
- // 1549,
+ 1549,
1548,
1547,
// 1546,
@@ -403,9 +399,9 @@ static const int included_patches[] = {
// 1521,
// 1520,
1519,
- // 1518,
+ 1518,
1517,
- // 1516,
+ 1516,
// 1515,
1514,
1513,
@@ -507,9 +503,9 @@ static const int included_patches[] = {
1417,
1416,
1415,
- // 1414,
+ 1414,
1413,
- // 1412,
+ 1412,
1411,
1410,
1409,
@@ -537,7 +533,7 @@ static const int included_patches[] = {
1387,
// 1386,
1385,
- // 1384,
+ 1384,
1383,
// 1382,
// 1381,
@@ -616,7 +612,7 @@ static const int included_patches[] = {
1308,
// 1307,
1306,
- // 1305,
+ 1305,
1304,
1303,
1302,
@@ -643,7 +639,7 @@ static const int included_patches[] = {
1281,
1280,
1279,
- // 1278,
+ 1278,
// 1277,
// 1276,
1275,
@@ -676,7 +672,7 @@ static const int included_patches[] = {
1248,
1247,
// 1246,
- // 1245,
+ 1245,
// 1244,
1243,
1242,
@@ -968,7 +964,7 @@ static const int included_patches[] = {
// 956,
955,
954,
- // 953,
+ 953,
952,
951,
950,
@@ -988,9 +984,9 @@ static const int included_patches[] = {
// 936,
// 935,
// 934,
- // 933,
+ 933,
// 932,
- // 931,
+ 931,
// 930,
// 929,
928,
@@ -1008,7 +1004,7 @@ static const int included_patches[] = {
// 916,
915,
// 914,
- // 913,
+ 913,
// 912,
911,
// 910,
@@ -1022,43 +1018,43 @@ static const int included_patches[] = {
// 902,
901,
900,
- // 899,
- // 898,
+ 899,
+ 898,
897,
- // 896,
+ 896,
895,
894,
- // 893,
- // 892,
+ 893,
+ 892,
891,
890,
889,
888,
- // 887,
+ 887,
886,
- // 885,
- // 884,
+ 885,
+ 884,
883,
- // 882,
+ 882,
881,
880,
879,
878,
- // 877,
+ 877,
876,
875,
- // 874,
+ 874,
873,
872,
871,
- // 870,
- // 869,
+ 870,
+ 869,
868,
- // 867,
+ 867,
866,
865,
- // 864,
- // 863,
+ 864,
+ 863,
862,
861,
860,
@@ -1100,12 +1096,12 @@ static const int included_patches[] = {
824,
823,
822,
- // 821,
+ 821,
820,
819,
- // 818,
- // 817,
- // 816,
+ 818,
+ 817,
+ 816,
815,
814,
813,
@@ -1118,7 +1114,7 @@ static const int included_patches[] = {
806,
805,
804,
- // 803,
+ 803,
802,
801,
800,
@@ -2002,30 +1998,78 @@ void ex_version(exarg_T *eap)
}
}
-/// List all features aligned in columns, dictionary style.
+/// Output a string for the version message. If it's going to wrap, output a
+/// newline, unless the message is too long to fit on the screen anyway.
+/// When "wrap" is TRUE wrap the string in [].
+/// @param s
+/// @param wrap
+static void version_msg_wrap(char_u *s, int wrap)
+{
+ int len = (int)vim_strsize(s) + (wrap ? 2 : 0);
+
+ if (!got_int
+ && (len < Columns)
+ && (msg_col + len >= Columns)
+ && (*s != '\n')) {
+ msg_putchar('\n');
+ }
+
+ if (!got_int) {
+ if (wrap) {
+ msg_puts("[");
+ }
+ msg_puts((char *)s);
+ if (wrap) {
+ msg_puts("]");
+ }
+ }
+}
+
+static void version_msg(char *s)
+{
+ version_msg_wrap((char_u *)s, false);
+}
+
+/// List all features.
+/// This does not use list_in_columns (as in Vim), because there are only a
+/// few, and we do not start at a new line.
static void list_features(void)
{
- int nfeat = 0;
+ version_msg(_("\n\nFeatures: "));
+ for (int i = 0; features[i] != NULL; i++) {
+ version_msg(features[i]);
+ if (features[i+1] != NULL) {
+ version_msg(" ");
+ }
+ }
+ version_msg("\nSee \":help feature-compile\"\n\n");
+}
+
+/// List string items nicely aligned in columns.
+/// When "size" is < 0 then the last entry is marked with NULL.
+/// The entry with index "current" is inclosed in [].
+void list_in_columns(char_u **items, int size, int current)
+{
+ int item_count = 0;
int width = 0;
- // Find the length of the longest feature name, use that + 1 as the column
- // width
+ // Find the length of the longest item, use that + 1 as the column width.
int i;
- for (i = 0; features[i] != NULL; ++i) {
- int l = (int)STRLEN(features[i]);
+ for (i = 0; size < 0 ? items[i] != NULL : i < size; i++) {
+ int l = (int)vim_strsize(items[i]) + (i == current ? 2 : 0);
if (l > width) {
width = l;
}
- nfeat++;
+ item_count++;
}
width += 1;
if (Columns < width) {
// Not enough screen columns - show one per line
- for (i = 0; features[i] != NULL; ++i) {
- version_msg(features[i]);
- if (msg_col > 0) {
+ for (i = 0; i < item_count; i++) {
+ version_msg_wrap(items[i], i == current);
+ if (msg_col > 0 && i < item_count - 1) {
msg_putchar('\n');
}
}
@@ -2035,28 +2079,41 @@ static void list_features(void)
// The rightmost column doesn't need a separator.
// Sacrifice it to fit in one more column if possible.
int ncol = (int)(Columns + 1) / width;
- int nrow = nfeat / ncol + (nfeat % ncol ? 1 : 0);
+ int nrow = item_count / ncol + (item_count % ncol ? 1 : 0);
+ int cur_row = 1;
- // i counts columns then rows. idx counts rows then columns.
- for (i = 0; !got_int && i < nrow * ncol; ++i) {
+ // "i" counts columns then rows. "idx" counts rows then columns.
+ for (i = 0; !got_int && i < nrow * ncol; i++) {
int idx = (i / ncol) + (i % ncol) * nrow;
- if (idx < nfeat) {
+ if (idx < item_count) {
int last_col = (i + 1) % ncol == 0;
- msg_puts(features[idx]);
+ if (idx == current) {
+ msg_putchar('[');
+ }
+ msg_puts((char *)items[idx]);
+ if (idx == current) {
+ msg_putchar(']');
+ }
if (last_col) {
- if (msg_col > 0) {
+ if (msg_col > 0 && cur_row < nrow) {
msg_putchar('\n');
}
+ cur_row++;
} else {
- msg_putchar(' ');
+ while (msg_col % width) {
+ msg_putchar(' ');
+ }
}
} else {
+ // this row is out of items, thus at the end of the row
if (msg_col > 0) {
- msg_putchar('\n');
+ if (cur_row < nrow) {
+ msg_putchar('\n');
+ }
+ cur_row++;
}
}
}
- MSG_PUTS("See \":help feature-compile\"\n\n");
}
void list_lua_version(void)
@@ -2094,8 +2151,6 @@ void list_version(void)
}
#endif // ifdef HAVE_PATHDEF
- version_msg(_("\n\nFeatures: "));
-
list_features();
#ifdef SYS_VIMRC_FILE
@@ -2121,26 +2176,6 @@ void list_version(void)
version_msg("\nRun :checkhealth for more info");
}
-/// Output a string for the version message. If it's going to wrap, output a
-/// newline, unless the message is too long to fit on the screen anyway.
-///
-/// @param s
-static void version_msg(char *s)
-{
- int len = (int)STRLEN(s);
-
- if (!got_int
- && (len < (int)Columns)
- && (msg_col + len >= (int)Columns)
- && (*s != '\n')) {
- msg_putchar('\n');
- }
-
- if (!got_int) {
- MSG_PUTS(s);
- }
-}
-
/// Show the intro message when not editing a file.
void maybe_intro_message(void)
diff --git a/src/nvim/viml/parser/expressions.c b/src/nvim/viml/parser/expressions.c
index dcc64db8a0..b4a0f57e99 100644
--- a/src/nvim/viml/parser/expressions.c
+++ b/src/nvim/viml/parser/expressions.c
@@ -2330,7 +2330,7 @@ viml_pexpr_parse_invalid_comma:
break;
} else if (eastnode_type == kExprNodeSubscript) {
is_subscript = true;
- can_be_ternary = false;
+ // can_be_ternary = false;
assert(!is_ternary);
break;
} else if (eastnode_type == kExprNodeColon) {
diff --git a/src/nvim/window.c b/src/nvim/window.c
index e6b19cf88d..22a8969b88 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -90,36 +90,47 @@ do_window (
else
Prenum1 = Prenum;
-# define CHECK_CMDWIN if (cmdwin_type != 0) { EMSG(_(e_cmdwin)); break; }
+# define CHECK_CMDWIN \
+ do { \
+ if (cmdwin_type != 0) { \
+ EMSG(_(e_cmdwin)); \
+ return; \
+ } \
+ } while (0)
switch (nchar) {
/* split current window in two parts, horizontally */
case 'S':
case Ctrl_S:
case 's':
- CHECK_CMDWIN reset_VIsual_and_resel(); /* stop Visual mode */
- /* When splitting the quickfix window open a new buffer in it,
- * don't replicate the quickfix buffer. */
- if (bt_quickfix(curbuf))
+ CHECK_CMDWIN;
+ reset_VIsual_and_resel(); // stop Visual mode
+ // When splitting the quickfix window open a new buffer in it,
+ // don't replicate the quickfix buffer.
+ if (bt_quickfix(curbuf)) {
goto newwindow;
+ }
(void)win_split((int)Prenum, 0);
break;
/* split current window in two parts, vertically */
case Ctrl_V:
case 'v':
- CHECK_CMDWIN reset_VIsual_and_resel(); /* stop Visual mode */
- /* When splitting the quickfix window open a new buffer in it,
- * don't replicate the quickfix buffer. */
- if (bt_quickfix(curbuf))
+ CHECK_CMDWIN;
+ reset_VIsual_and_resel(); // stop Visual mode
+ // When splitting the quickfix window open a new buffer in it,
+ // don't replicate the quickfix buffer.
+ if (bt_quickfix(curbuf)) {
goto newwindow;
+ }
(void)win_split((int)Prenum, WSP_VERT);
break;
/* split current window and edit alternate file */
case Ctrl_HAT:
case '^':
- CHECK_CMDWIN reset_VIsual_and_resel(); /* stop Visual mode */
+ CHECK_CMDWIN;
+ reset_VIsual_and_resel(); // stop Visual mode
cmd_with_count("split #", (char_u *)cbuf, sizeof(cbuf), Prenum);
do_cmdline_cmd(cbuf);
break;
@@ -127,7 +138,8 @@ do_window (
/* open new window */
case Ctrl_N:
case 'n':
- CHECK_CMDWIN reset_VIsual_and_resel(); /* stop Visual mode */
+ CHECK_CMDWIN;
+ reset_VIsual_and_resel(); // stop Visual mode
newwindow:
if (Prenum)
/* window height */
@@ -160,7 +172,8 @@ newwindow:
/* close preview window */
case Ctrl_Z:
case 'z':
- CHECK_CMDWIN reset_VIsual_and_resel(); /* stop Visual mode */
+ CHECK_CMDWIN;
+ reset_VIsual_and_resel(); // stop Visual mode
do_cmdline_cmd("pclose");
break;
@@ -183,7 +196,8 @@ newwindow:
/* close all but current window */
case Ctrl_O:
case 'o':
- CHECK_CMDWIN reset_VIsual_and_resel(); /* stop Visual mode */
+ CHECK_CMDWIN;
+ reset_VIsual_and_resel(); // stop Visual mode
cmd_with_count("only", (char_u *)cbuf, sizeof(cbuf), Prenum);
do_cmdline_cmd(cbuf);
break;
@@ -193,11 +207,11 @@ newwindow:
case 'w':
/* cursor to previous window with wrap around */
case 'W':
- CHECK_CMDWIN
- if (ONE_WINDOW && Prenum != 1) /* just one window */
+ CHECK_CMDWIN;
+ if (ONE_WINDOW && Prenum != 1) { // just one window
beep_flush();
- else {
- if (Prenum) { /* go to specified window */
+ } else {
+ if (Prenum) { // go to specified window
for (wp = firstwin; --Prenum > 0; ) {
if (wp->w_next == NULL)
break;
@@ -233,14 +247,16 @@ newwindow:
case 'j':
case K_DOWN:
case Ctrl_J:
- CHECK_CMDWIN win_goto_ver(FALSE, Prenum1);
+ CHECK_CMDWIN;
+ win_goto_ver(false, Prenum1);
break;
/* cursor to window above */
case 'k':
case K_UP:
case Ctrl_K:
- CHECK_CMDWIN win_goto_ver(TRUE, Prenum1);
+ CHECK_CMDWIN;
+ win_goto_ver(true, Prenum1);
break;
/* cursor to left window */
@@ -248,14 +264,16 @@ newwindow:
case K_LEFT:
case Ctrl_H:
case K_BS:
- CHECK_CMDWIN win_goto_hor(TRUE, Prenum1);
+ CHECK_CMDWIN;
+ win_goto_hor(true, Prenum1);
break;
/* cursor to right window */
case 'l':
case K_RIGHT:
case Ctrl_L:
- CHECK_CMDWIN win_goto_hor(FALSE, Prenum1);
+ CHECK_CMDWIN;
+ win_goto_hor(false, Prenum1);
break;
/* move window to new tab page */
@@ -309,20 +327,23 @@ newwindow:
/* exchange current and next window */
case 'x':
case Ctrl_X:
- CHECK_CMDWIN win_exchange(Prenum);
+ CHECK_CMDWIN;
+ win_exchange(Prenum);
break;
/* rotate windows downwards */
case Ctrl_R:
case 'r':
- CHECK_CMDWIN reset_VIsual_and_resel(); /* stop Visual mode */
- win_rotate(FALSE, (int)Prenum1); /* downwards */
+ CHECK_CMDWIN;
+ reset_VIsual_and_resel(); // stop Visual mode
+ win_rotate(false, (int)Prenum1); // downwards
break;
/* rotate windows upwards */
case 'R':
- CHECK_CMDWIN reset_VIsual_and_resel(); /* stop Visual mode */
- win_rotate(TRUE, (int)Prenum1); /* upwards */
+ 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 */
@@ -330,9 +351,10 @@ newwindow:
case 'J':
case 'H':
case 'L':
- CHECK_CMDWIN win_totop((int)Prenum,
- ((nchar == 'H' || nchar == 'L') ? WSP_VERT : 0)
- | ((nchar == 'H' || nchar == 'K') ? WSP_TOP : WSP_BOT));
+ CHECK_CMDWIN;
+ win_totop((int)Prenum,
+ ((nchar == 'H' || nchar == 'L') ? WSP_VERT : 0)
+ | ((nchar == 'H' || nchar == 'K') ? WSP_TOP : WSP_BOT));
break;
/* make all windows the same height */
@@ -353,7 +375,7 @@ newwindow:
/* set current window height */
case Ctrl__:
case '_':
- win_setheight(Prenum ? (int)Prenum : 9999);
+ win_setheight(Prenum ? (int)Prenum : Rows-1);
break;
/* increase current window width */
@@ -368,20 +390,21 @@ newwindow:
/* set current window width */
case '|':
- win_setwidth(Prenum != 0 ? (int)Prenum : 9999);
+ win_setwidth(Prenum != 0 ? (int)Prenum : Columns);
break;
/* jump to tag and split window if tag exists (in preview window) */
case '}':
- CHECK_CMDWIN
- if (Prenum)
+ CHECK_CMDWIN;
+ if (Prenum) {
g_do_tagpreview = Prenum;
- else
+ } else {
g_do_tagpreview = p_pvh;
+ }
FALLTHROUGH;
case ']':
case Ctrl_RSB:
- CHECK_CMDWIN
+ CHECK_CMDWIN;
// Keep visual mode, can select words to use as a tag.
if (Prenum)
postponed_split = Prenum;
@@ -402,7 +425,7 @@ newwindow:
case 'F':
case Ctrl_F:
wingotofile:
- CHECK_CMDWIN
+ CHECK_CMDWIN;
ptr = grab_file_name(Prenum1, &lnum);
if (ptr != NULL) {
@@ -434,26 +457,20 @@ wingotofile:
FALLTHROUGH;
case 'd': // Go to definition, using 'define'
case Ctrl_D:
- CHECK_CMDWIN
- if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0)
+ CHECK_CMDWIN;
+ if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0) {
break;
- find_pattern_in_path(ptr, 0, len, TRUE,
- Prenum == 0 ? TRUE : FALSE,
+ }
+ find_pattern_in_path(ptr, 0, len, true, Prenum == 0,
type, Prenum1, ACTION_SPLIT, 1, MAXLNUM);
curwin->w_set_curswant = TRUE;
break;
+ // Quickfix window only: view the result under the cursor in a new split.
case K_KENTER:
case CAR:
- /*
- * In a quickfix window a <CR> jumps to the error under the
- * cursor in a new window.
- */
if (bt_quickfix(curbuf)) {
- sprintf(cbuf, "split +%" PRId64 "%s",
- (int64_t)curwin->w_cursor.lnum,
- (curwin->w_llist_ref == NULL) ? "cc" : "ll");
- do_cmdline_cmd(cbuf);
+ qf_view_result(true);
}
break;
@@ -461,7 +478,7 @@ wingotofile:
/* CTRL-W g extended commands */
case 'g':
case Ctrl_G:
- CHECK_CMDWIN
+ CHECK_CMDWIN;
no_mapping++;
if (xchar == NUL) {
xchar = plain_vgetc();
@@ -567,15 +584,43 @@ win_T *win_new_float(win_T *wp, FloatConfig fconfig, Error *err)
wp->w_status_height = 0;
wp->w_vsep_width = 0;
- // TODO(bfredl): use set_option_to() after merging #9110 ?
- wp->w_p_nu = false;
- wp->w_allbuf_opt.wo_nu = false;
win_config_float(wp, fconfig);
wp->w_pos_changed = true;
redraw_win_later(wp, VALID);
return wp;
}
+void win_set_minimal_style(win_T *wp)
+{
+ wp->w_p_nu = false;
+ wp->w_p_rnu = false;
+ wp->w_p_cul = false;
+ wp->w_p_cuc = false;
+ wp->w_p_spell = false;
+ wp->w_p_list = false;
+
+ // Hide EOB region: use " " fillchar and cleared highlighting
+ if (wp->w_p_fcs_chars.eob != ' ') {
+ char_u *old = wp->w_p_fcs;
+ wp->w_p_fcs = ((*old == NUL)
+ ? (char_u *)xstrdup("eob: ")
+ : concat_str(old, (char_u *)",eob: "));
+ xfree(old);
+ }
+ if (wp->w_hl_ids[HLF_EOB] != -1) {
+ char_u *old = wp->w_p_winhl;
+ wp->w_p_winhl = ((*old == NUL)
+ ? (char_u *)xstrdup("EndOfBuffer:")
+ : concat_str(old, (char_u *)",EndOfBuffer:"));
+ xfree(old);
+ }
+
+ if (wp->w_p_scl[0] != 'a') {
+ xfree(wp->w_p_scl);
+ wp->w_p_scl = (char_u *)xstrdup("auto");
+ }
+}
+
void win_config_float(win_T *wp, FloatConfig fconfig)
{
wp->w_width = MAX(fconfig.width, 1);
@@ -649,6 +694,7 @@ static void ui_ext_win_position(win_T *wp)
bool on_top = (curwin == wp) || !curwin->w_floating;
ui_comp_put_grid(&wp->w_grid, comp_row, comp_col, wp->w_height,
wp->w_width, valid, on_top);
+ ui_check_cursor_grid(wp->w_grid.handle);
if (!valid) {
wp->w_grid.valid = false;
redraw_win_later(wp, NOT_VALID);
@@ -804,6 +850,20 @@ bool parse_float_config(Dictionary config, FloatConfig *fconfig, bool reconf,
"'focusable' key must be Boolean");
return false;
}
+ } else if (!strcmp(key, "style")) {
+ if (val.type != kObjectTypeString) {
+ api_set_error(err, kErrorTypeValidation,
+ "'style' key must be String");
+ return false;
+ }
+ if (val.data.string.data[0] == NUL) {
+ fconfig->style = kWinStyleUnused;
+ } else if (striequal(val.data.string.data, "minimal")) {
+ fconfig->style = kWinStyleMinimal;
+ } else {
+ api_set_error(err, kErrorTypeValidation,
+ "Invalid value of 'style' key");
+ }
} else {
api_set_error(err, kErrorTypeValidation,
"Invalid key '%s'", key);
@@ -964,7 +1024,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
for (frp = oldwin->w_frame->fr_parent; frp != NULL;
frp = frp->fr_parent) {
if (frp->fr_layout == FR_ROW) {
- for (frp2 = frp->fr_child; frp2 != NULL; frp2 = frp2->fr_next) {
+ FOR_ALL_FRAMES(frp2, frp->fr_child) {
if (frp2 != prevfrp) {
minwidth += frame_minwidth(frp2, NOWIN);
}
@@ -1042,7 +1102,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
for (frp = oldwin->w_frame->fr_parent; frp != NULL;
frp = frp->fr_parent) {
if (frp->fr_layout == FR_COL) {
- for (frp2 = frp->fr_child; frp2 != NULL; frp2 = frp2->fr_next) {
+ FOR_ALL_FRAMES(frp2, frp->fr_child) {
if (frp2 != prevfrp) {
minheight += frame_minheight(frp2, NOWIN);
}
@@ -1187,11 +1247,13 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
curfrp->fr_child = frp;
curfrp->fr_win = NULL;
curfrp = frp;
- if (frp->fr_win != NULL)
+ if (frp->fr_win != NULL) {
oldwin->w_frame = frp;
- else
- for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
+ } else {
+ FOR_ALL_FRAMES(frp, frp->fr_child) {
frp->fr_parent = curfrp;
+ }
+ }
}
if (new_wp == NULL)
@@ -1637,11 +1699,9 @@ static void win_exchange(long Prenum)
redraw_win_later(wp, NOT_VALID);
}
-/*
- * rotate windows: if upwards TRUE the second window becomes the first one
- * if upwards FALSE the first window becomes the second one
- */
-static void win_rotate(int upwards, int count)
+// rotate windows: if upwards true the second window becomes the first one
+// if upwards false the first window becomes the second one
+static void win_rotate(bool upwards, int count)
{
win_T *wp1;
win_T *wp2;
@@ -1653,19 +1713,19 @@ static void win_rotate(int upwards, int count)
return;
}
- if (firstwin == curwin && lastwin_nofloating() == curwin) {
+ if (count <= 0 || (firstwin == curwin && lastwin_nofloating() == curwin)) {
// nothing to do
beep_flush();
return;
}
- /* Check if all frames in this row/col have one window. */
- for (frp = curwin->w_frame->fr_parent->fr_child; frp != NULL;
- frp = frp->fr_next)
+ // Check if all frames in this row/col have one window.
+ FOR_ALL_FRAMES(frp, curwin->w_frame->fr_parent->fr_child) {
if (frp->fr_win == NULL) {
EMSG(_("E443: Cannot rotate when another window is split"));
return;
}
+ }
while (count--) {
if (upwards) { /* first window becomes last window */
@@ -1832,8 +1892,8 @@ void win_equal(
if (dir == 0)
dir = *p_ead;
win_equal_rec(next_curwin == NULL ? curwin : next_curwin, current,
- topframe, dir, 0, tabline_height(),
- (int)Columns, topframe->fr_height);
+ topframe, dir, 0, tabline_height(),
+ Columns, topframe->fr_height);
}
/*
@@ -1903,10 +1963,10 @@ static void win_equal_rec(
room = 0;
} else {
next_curwin_size = -1;
- for (fr = topfr->fr_child; fr != NULL; fr = fr->fr_next) {
- /* If 'winfixwidth' set keep the window width if
- * possible.
- * Watch out for this window being the next_curwin. */
+ FOR_ALL_FRAMES(fr, topfr->fr_child) {
+ // If 'winfixwidth' set keep the window width if
+ // possible.
+ // Watch out for this window being the next_curwin.
if (!frame_fixed_width(fr)) {
continue;
}
@@ -1949,7 +2009,7 @@ static void win_equal_rec(
--totwincount; /* don't count curwin */
}
- for (fr = topfr->fr_child; fr != NULL; fr = fr->fr_next) {
+ FOR_ALL_FRAMES(fr, topfr->fr_child) {
wincount = 1;
if (fr->fr_next == NULL)
/* last frame gets all that remains (avoid roundoff error) */
@@ -2024,10 +2084,10 @@ static void win_equal_rec(
room = 0;
} else {
next_curwin_size = -1;
- for (fr = topfr->fr_child; fr != NULL; fr = fr->fr_next) {
- /* If 'winfixheight' set keep the window height if
- * possible.
- * Watch out for this window being the next_curwin. */
+ FOR_ALL_FRAMES(fr, topfr->fr_child) {
+ // If 'winfixheight' set keep the window height if
+ // possible.
+ // Watch out for this window being the next_curwin.
if (!frame_fixed_height(fr)) {
continue;
}
@@ -2070,7 +2130,7 @@ static void win_equal_rec(
--totwincount; /* don't count curwin */
}
- for (fr = topfr->fr_child; fr != NULL; fr = fr->fr_next) {
+ FOR_ALL_FRAMES(fr, topfr->fr_child) {
wincount = 1;
if (fr->fr_next == NULL)
/* last frame gets all that remains (avoid roundoff error) */
@@ -2757,8 +2817,9 @@ winframe_remove (
* and remove it. */
frp2->fr_parent->fr_layout = frp2->fr_layout;
frp2->fr_parent->fr_child = frp2->fr_child;
- for (frp = frp2->fr_child; frp != NULL; frp = frp->fr_next)
+ FOR_ALL_FRAMES(frp, frp2->fr_child) {
frp->fr_parent = frp2->fr_parent;
+ }
frp2->fr_parent->fr_win = frp2->fr_win;
if (frp2->fr_win != NULL)
frp2->fr_win->w_frame = frp2->fr_parent;
@@ -2879,13 +2940,14 @@ static win_T *frame2win(frame_T *frp)
///
/// @param frp frame
/// @param wp window
-static bool frame_has_win(frame_T *frp, win_T *wp)
+static bool frame_has_win(const frame_T *frp, const win_T *wp)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1)
{
if (frp->fr_layout == FR_LEAF) {
return frp->fr_win == wp;
}
- for (frame_T *p = frp->fr_child; p != NULL; p = p->fr_next) {
+ const frame_T *p;
+ FOR_ALL_FRAMES(p, frp->fr_child) {
if (frame_has_win(p, wp)) {
return true;
}
@@ -2916,8 +2978,8 @@ frame_new_height (
height - topfrp->fr_win->w_status_height);
} else if (topfrp->fr_layout == FR_ROW) {
do {
- /* All frames in this row get the same new height. */
- for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next) {
+ // All frames in this row get the same 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. */
@@ -2998,7 +3060,7 @@ static bool frame_fixed_height(frame_T *frp)
if (frp->fr_layout == FR_ROW) {
// The frame is fixed height if one of the frames in the row is fixed
// height.
- for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next) {
+ FOR_ALL_FRAMES(frp, frp->fr_child) {
if (frame_fixed_height(frp)) {
return true;
}
@@ -3008,7 +3070,7 @@ static bool frame_fixed_height(frame_T *frp)
// frp->fr_layout == FR_COL: The frame is fixed height if all of the
// frames in the row are fixed height.
- for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next) {
+ FOR_ALL_FRAMES(frp, frp->fr_child) {
if (!frame_fixed_height(frp)) {
return false;
}
@@ -3032,7 +3094,7 @@ static bool frame_fixed_width(frame_T *frp)
if (frp->fr_layout == FR_COL) {
// The frame is fixed width if one of the frames in the row is fixed
// width.
- for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next) {
+ FOR_ALL_FRAMES(frp, frp->fr_child) {
if (frame_fixed_width(frp)) {
return true;
}
@@ -3042,7 +3104,7 @@ static bool frame_fixed_width(frame_T *frp)
// frp->fr_layout == FR_ROW: The frame is fixed width if all of the
// frames in the row are fixed width.
- for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next) {
+ FOR_ALL_FRAMES(frp, frp->fr_child) {
if (!frame_fixed_width(frp)) {
return false;
}
@@ -3066,13 +3128,15 @@ static void frame_add_statusline(frame_T *frp)
wp->w_status_height = STATUS_HEIGHT;
}
} else if (frp->fr_layout == FR_ROW) {
- /* Handle all the frames in the row. */
- for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
+ // Handle all the frames in the row.
+ FOR_ALL_FRAMES(frp, frp->fr_child) {
frame_add_statusline(frp);
- } else { /* frp->fr_layout == FR_COL */
- /* Only need to handle the last frame in the column. */
- for (frp = frp->fr_child; frp->fr_next != NULL; frp = frp->fr_next)
- ;
+ }
+ } else {
+ assert(frp->fr_layout == FR_COL);
+ // Only need to handle the last frame in the column.
+ for (frp = frp->fr_child; frp->fr_next != NULL; frp = frp->fr_next) {
+ }
frame_add_statusline(frp);
}
}
@@ -3107,8 +3171,8 @@ frame_new_width (
win_new_width(wp, width - wp->w_vsep_width);
} else if (topfrp->fr_layout == FR_COL) {
do {
- /* All frames in this column get the same new width. */
- for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next) {
+ // All frames in this column get the same 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. */
@@ -3177,7 +3241,8 @@ frame_new_width (
* Add the vertical separator to windows at the right side of "frp".
* Note: Does not check if there is room!
*/
-static void frame_add_vsep(frame_T *frp)
+static void frame_add_vsep(const frame_T *frp)
+ FUNC_ATTR_NONNULL_ARG(1)
{
win_T *wp;
@@ -3189,11 +3254,13 @@ static void frame_add_vsep(frame_T *frp)
wp->w_vsep_width = 1;
}
} else if (frp->fr_layout == FR_COL) {
- /* Handle all the frames in the column. */
- for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
+ // Handle all the frames in the column.
+ FOR_ALL_FRAMES(frp, frp->fr_child) {
frame_add_vsep(frp);
- } else { /* frp->fr_layout == FR_ROW */
- /* Only need to handle the last frame in the row. */
+ }
+ } else {
+ 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)
frp = frp->fr_next;
@@ -3243,7 +3310,7 @@ 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 */
m = 0;
- for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next) {
+ FOR_ALL_FRAMES(frp, topfrp->fr_child) {
n = frame_minheight(frp, next_curwin);
if (n > m)
m = n;
@@ -3251,8 +3318,9 @@ static int frame_minheight(frame_T *topfrp, win_T *next_curwin)
} else {
/* Add up the minimal heights for all frames in this column. */
m = 0;
- for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
+ FOR_ALL_FRAMES(frp, topfrp->fr_child) {
m += frame_minheight(frp, next_curwin);
+ }
}
return m;
@@ -3286,7 +3354,7 @@ frame_minwidth (
} else if (topfrp->fr_layout == FR_COL) {
/* get the minimal width from each frame in this column */
m = 0;
- for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next) {
+ FOR_ALL_FRAMES(frp, topfrp->fr_child) {
n = frame_minwidth(frp, next_curwin);
if (n > m)
m = n;
@@ -3294,8 +3362,9 @@ frame_minwidth (
} else {
/* Add up the minimal widths for all frames in this row. */
m = 0;
- for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
+ FOR_ALL_FRAMES(frp, topfrp->fr_child) {
m += frame_minwidth(frp, next_curwin);
+ }
}
return m;
@@ -4673,9 +4742,10 @@ void shell_new_columns(void)
/* First try setting the widths of windows with 'winfixwidth'. If that
* doesn't result in the right width, forget about that option. */
- frame_new_width(topframe, (int)Columns, FALSE, TRUE);
- if (!frame_check_width(topframe, Columns))
- frame_new_width(topframe, (int)Columns, FALSE, FALSE);
+ frame_new_width(topframe, Columns, false, true);
+ if (!frame_check_width(topframe, Columns)) {
+ frame_new_width(topframe, Columns, false, false);
+ }
(void)win_comp_pos(); /* recompute w_winrow and w_wincol */
}
@@ -4772,11 +4842,12 @@ static void frame_comp_pos(frame_T *topfrp, int *row, int *col)
} else {
startrow = *row;
startcol = *col;
- for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next) {
- if (topfrp->fr_layout == FR_ROW)
- *row = startrow; /* all frames are at the same row */
- else
- *col = startcol; /* all frames are at the same col */
+ FOR_ALL_FRAMES(frp, topfrp->fr_child) {
+ if (topfrp->fr_layout == FR_ROW) {
+ *row = startrow; // all frames are at the same row
+ } else {
+ *col = startcol; // all frames are at the same col
+ }
frame_comp_pos(frp, row, col);
}
}
@@ -4808,13 +4879,9 @@ void win_setheight_win(int height, win_T *win)
}
if (win->w_floating) {
- if (win->w_float_config.external) {
- win->w_float_config.height = height;
- win_config_float(win, win->w_float_config);
- } else {
- beep_flush();
- return;
- }
+ win->w_float_config.height = height;
+ win_config_float(win, win->w_float_config);
+ redraw_win_later(win, NOT_VALID);
} else {
frame_setheight(win->w_frame, height + win->w_status_height);
@@ -4824,14 +4891,14 @@ void win_setheight_win(int height, win_T *win)
// If there is extra space created between the last window and the command
// line, clear it.
if (full_screen && msg_scrolled == 0 && row < cmdline_row) {
- grid_fill(&default_grid, row, cmdline_row, 0, (int)Columns, ' ', ' ', 0);
+ grid_fill(&default_grid, row, cmdline_row, 0, Columns, ' ', ' ', 0);
}
cmdline_row = row;
msg_row = row;
msg_col = 0;
+ redraw_all_later(NOT_VALID);
}
- redraw_all_later(NOT_VALID);
}
@@ -4889,15 +4956,16 @@ static void frame_setheight(frame_T *curfrp, int height)
for (run = 1; run <= 2; ++run) {
room = 0;
room_reserved = 0;
- for (frp = curfrp->fr_parent->fr_child; frp != NULL;
- frp = frp->fr_next) {
+ FOR_ALL_FRAMES(frp, curfrp->fr_parent->fr_child) {
if (frp != curfrp
&& frp->fr_win != NULL
- && frp->fr_win->w_p_wfh)
+ && frp->fr_win->w_p_wfh) {
room_reserved += frp->fr_height;
+ }
room += frp->fr_height;
- if (frp != curfrp)
+ if (frp != curfrp) {
room -= frame_minheight(frp, NULL);
+ }
}
if (curfrp->fr_width != Columns) {
room_cmdline = 0;
@@ -5014,21 +5082,17 @@ void win_setwidth_win(int width, win_T *wp)
width = 1;
}
if (wp->w_floating) {
- if (wp->w_float_config.external) {
- wp->w_float_config.width = width;
- win_config_float(wp, wp->w_float_config);
- } else {
- beep_flush();
- return;
- }
+ wp->w_float_config.width = width;
+ win_config_float(wp, wp->w_float_config);
+ redraw_win_later(wp, NOT_VALID);
} else {
frame_setwidth(wp->w_frame, width + wp->w_vsep_width);
// recompute the window positions
(void)win_comp_pos();
+ redraw_all_later(NOT_VALID);
}
- redraw_all_later(NOT_VALID);
}
/*
@@ -5074,15 +5138,16 @@ static void frame_setwidth(frame_T *curfrp, int width)
for (run = 1; run <= 2; ++run) {
room = 0;
room_reserved = 0;
- for (frp = curfrp->fr_parent->fr_child; frp != NULL;
- frp = frp->fr_next) {
+ FOR_ALL_FRAMES(frp, curfrp->fr_parent->fr_child) {
if (frp != curfrp
&& frp->fr_win != NULL
- && frp->fr_win->w_p_wfw)
+ && frp->fr_win->w_p_wfw) {
room_reserved += frp->fr_width;
+ }
room += frp->fr_width;
- if (frp != curfrp)
+ if (frp != curfrp) {
room -= frame_minwidth(frp, NULL);
+ }
}
if (width <= room)
@@ -5246,10 +5311,11 @@ void win_drag_status_line(win_T *dragwin, int offset)
room -= p_ch;
if (room < 0)
room = 0;
- /* sum up the room of frames below of the current one */
- for (fr = curfr->fr_next; fr != NULL; fr = fr->fr_next)
+ // 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);
- fr = curfr; /* put fr at window that grows */
+ }
+ fr = curfr; // put fr at window that grows
}
if (room < offset) /* Not enough room */
@@ -5287,7 +5353,7 @@ void win_drag_status_line(win_T *dragwin, int offset)
fr = fr->fr_next;
}
row = win_comp_pos();
- grid_fill(&default_grid, row, cmdline_row, 0, (int)Columns, ' ', ' ', 0);
+ grid_fill(&default_grid, row, cmdline_row, 0, Columns, ' ', ' ', 0);
cmdline_row = row;
p_ch = Rows - cmdline_row;
if (p_ch < 1)
@@ -5349,9 +5415,10 @@ void win_drag_vsep_line(win_T *dragwin, int offset)
left = FALSE;
/* sum up the room of frames right of the current one */
room = 0;
- for (fr = curfr->fr_next; fr != NULL; fr = fr->fr_next)
+ FOR_ALL_FRAMES(fr, curfr->fr_next) {
room += fr->fr_width - frame_minwidth(fr, NULL);
- fr = curfr; /* put fr at window that grows */
+ }
+ fr = curfr; // put fr at window that grows
}
assert(fr);
@@ -5655,8 +5722,7 @@ void command_height(void)
// clear the lines added to cmdline
if (full_screen) {
- grid_fill(&default_grid, cmdline_row, (int)Rows, 0, (int)Columns, ' ',
- ' ', 0);
+ grid_fill(&default_grid, cmdline_row, Rows, 0, Columns, ' ', ' ', 0);
}
msg_row = cmdline_row;
redraw_cmdline = TRUE;
@@ -5883,9 +5949,10 @@ static void last_status_rec(frame_T *fr, int statusline)
redraw_all_later(SOME_VALID);
}
} else if (fr->fr_layout == FR_ROW) {
- /* vertically split windows, set status line for each one */
- for (fp = fr->fr_child; fp != NULL; fp = fp->fr_next)
+ // vertically split windows, set status line for each one
+ FOR_ALL_FRAMES(fp, fr->fr_child) {
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)
@@ -6501,14 +6568,15 @@ matchitem_T *get_match(win_T *wp, int id)
///
/// @param topfrp top frame pointer
/// @param height expected height
-static bool frame_check_height(frame_T *topfrp, int height)
+static bool frame_check_height(const frame_T *topfrp, int height)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
if (topfrp->fr_height != height) {
return false;
}
if (topfrp->fr_layout == FR_ROW) {
- for (frame_T *frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next) {
+ const frame_T *frp;
+ FOR_ALL_FRAMES(frp, topfrp->fr_child) {
if (frp->fr_height != height) {
return false;
}
@@ -6521,14 +6589,15 @@ static bool frame_check_height(frame_T *topfrp, int height)
///
/// @param topfrp top frame pointer
/// @param width expected width
-static bool frame_check_width(frame_T *topfrp, int width)
+static bool frame_check_width(const frame_T *topfrp, int width)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
if (topfrp->fr_width != width) {
return false;
}
if (topfrp->fr_layout == FR_COL) {
- for (frame_T *frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next) {
+ const frame_T *frp;
+ FOR_ALL_FRAMES(frp, topfrp->fr_child) {
if (frp->fr_width != width) {
return false;
}
diff --git a/test/.luacheckrc b/test/.luacheckrc
deleted file mode 100644
index abfa881754..0000000000
--- a/test/.luacheckrc
+++ /dev/null
@@ -1,20 +0,0 @@
--- vim: ft=lua tw=80
-
--- Don't report globals from luajit or busted (e.g. jit.os or describe).
-std = '+luajit +busted'
-
--- One can't test these files properly; assume correctness.
-exclude_files = { '*/preload.lua' }
-
--- Don't report unused self arguments of methods.
-self = false
-
--- Rerun tests only if their modification time changed.
-cache = true
-
-ignore = {
- "631", -- max_line_length
-}
-
--- Ignore whitespace issues in converted Vim legacy tests.
---files["functional/legacy"] = {ignore = { "611", "612", "613", "621" }}
diff --git a/test/README.md b/test/README.md
index c87f835f79..73d51c995c 100644
--- a/test/README.md
+++ b/test/README.md
@@ -26,7 +26,7 @@ available in this version` errors.
- [Running tests](#running-tests)
- [Writing tests](#writing-tests)
- [Lint](#lint)
-- [Environment variables](#environment-variables)
+- [Configuration](#configuration)
---
@@ -208,8 +208,6 @@ Guidelines
[contained in an `it()` block](https://github.com/neovim/neovim/blob/d21690a66e7eb5ebef18046c7a79ef898966d786/test/functional/ex_cmds/grep_spec.lua#L11).
Provide empty function argument if the `pending()` call is outside of `it()`
([example](https://github.com/neovim/neovim/commit/5c1dc0fbe7388528875aff9d7b5055ad718014de#diff-bf80b24c724b0004e8418102f68b0679R18)).
-- Use `make testlint` for using the shipped luacheck program ([supported by syntastic](https://github.com/scrooloose/syntastic/blob/d6b96c079be137c83009827b543a83aa113cc011/doc/syntastic-checkers.txt#L3546))
- to lint all tests.
- Really long `source([=[...]=])` blocks may break syntax highlighting. Try
`:syntax sync fromstart` to fix it.
@@ -235,7 +233,7 @@ by the semantic component they are testing.
Lint
====
-`make lint` (and `make testlint`) runs [luacheck](https://github.com/mpeterv/luacheck)
+`make lint` (and `make lualint`) runs [luacheck](https://github.com/mpeterv/luacheck)
on the test code.
If a luacheck warning must be ignored, specify the warning code. Example:
@@ -248,95 +246,102 @@ Ignore the smallest applicable scope (e.g. inside a function, not at the top of
the file).
-Environment variables
-=====================
+Configuration
+=============
+
+busted (luassert) by default does not print the full result of deeply-nested
+tables. But sometimes it's useful while debugging a test.
+
+ assert:set_parameter('TableFormatLevel', 1000000)
Test behaviour is affected by environment variables. Currently supported
(Functional, Unit, Benchmarks) (when Defined; when set to _1_; when defined,
treated as Integer; when defined, treated as String; when defined, treated as
Number; !must be defined to function properly):
-`GDB` (F) (D): makes nvim instances to be run under `gdbserver`. It will be
-accessible on `localhost:7777`: use `gdb build/bin/nvim`, type `target remote
-:7777` inside.
+- `GDB` (F) (D): makes nvim instances to be run under `gdbserver`. It will be
+ accessible on `localhost:7777`: use `gdb build/bin/nvim`, type `target remote
+ :7777` inside.
-`GDBSERVER_PORT` (F) (I): overrides port used for `GDB`.
+- `GDBSERVER_PORT` (F) (I): overrides port used for `GDB`.
-`VALGRIND` (F) (D): makes nvim instances to be run under `valgrind`. Log files
-are named `valgrind-%p.log` in this case. Note that non-empty valgrind log may
-fail tests. Valgrind arguments may be seen in `/test/functional/helpers.lua`.
-May be used in conjunction with `GDB`.
+- `VALGRIND` (F) (D): makes nvim instances to be run under `valgrind`. Log
+ files are named `valgrind-%p.log` in this case. Note that non-empty valgrind
+ log may fail tests. Valgrind arguments may be seen in
+ `/test/functional/helpers.lua`. May be used in conjunction with `GDB`.
-`VALGRIND_LOG` (F) (S): overrides valgrind log file name used for `VALGRIND`.
+- `VALGRIND_LOG` (F) (S): overrides valgrind log file name used for `VALGRIND`.
-`TEST_SKIP_FRAGILE` (F) (D): makes test suite skip some fragile tests.
+- `TEST_SKIP_FRAGILE` (F) (D): makes test suite skip some fragile tests.
-`NVIM_PROG`, `NVIM_PRG` (F) (S): override path to Neovim executable (default to
-`build/bin/nvim`).
+- `NVIM_PROG`, `NVIM_PRG` (F) (S): override path to Neovim executable (default
+ to `build/bin/nvim`).
-`CC` (U) (S): specifies which C compiler to use to preprocess files. Currently
-only compilers with gcc-compatible arguments are supported.
+- `CC` (U) (S): specifies which C compiler to use to preprocess files.
+ Currently only compilers with gcc-compatible arguments are supported.
-`NVIM_TEST_MAIN_CDEFS` (U) (1): makes `ffi.cdef` run in main process. This
-raises a possibility of bugs due to conflicts in header definitions, despite the
-counters, but greatly speeds up unit tests by not requiring `ffi.cdef` to do
-parsing of big strings with C definitions.
+- `NVIM_TEST_MAIN_CDEFS` (U) (1): makes `ffi.cdef` run in main process. This
+ raises a possibility of bugs due to conflicts in header definitions, despite
+ the counters, but greatly speeds up unit tests by not requiring `ffi.cdef` to
+ do parsing of big strings with C definitions.
-`NVIM_TEST_PRINT_I` (U) (1): makes `cimport` print preprocessed, but not yet
-filtered through `formatc` headers. Used to debug `formatc`. Printing is done
-with the line numbers.
+- `NVIM_TEST_PRINT_I` (U) (1): makes `cimport` print preprocessed, but not yet
+ filtered through `formatc` headers. Used to debug `formatc`. Printing is done
+ with the line numbers.
-`NVIM_TEST_PRINT_CDEF` (U) (1): makes `cimport` print final lines which will be
-then passed to `ffi.cdef`. Used to debug errors `ffi.cdef` happens to throw
-sometimes.
+- `NVIM_TEST_PRINT_CDEF` (U) (1): makes `cimport` print final lines which will
+ be then passed to `ffi.cdef`. Used to debug errors `ffi.cdef` happens to
+ throw sometimes.
-`NVIM_TEST_PRINT_SYSCALLS` (U) (1): makes it print to stderr when syscall
-wrappers are called and what they returned. Used to debug code which makes unit
-tests be executed in separate processes.
+- `NVIM_TEST_PRINT_SYSCALLS` (U) (1): makes it print to stderr when syscall
+ wrappers are called and what they returned. Used to debug code which makes
+ unit tests be executed in separate processes.
-`NVIM_TEST_RUN_FAILING_TESTS` (U) (1): makes `itp` run tests which are known to
-fail (marked by setting third argument to `true`).
+- `NVIM_TEST_RUN_FAILING_TESTS` (U) (1): makes `itp` run tests which are known
+ to fail (marked by setting third argument to `true`).
-`LOG_DIR` (FU) (S!): specifies where to seek for valgrind and ASAN log files.
+- `LOG_DIR` (FU) (S!): specifies where to seek for valgrind and ASAN log files.
-`NVIM_TEST_CORE_*` (FU) (S): a set of environment variables which specify where
-to search for core files. Are supposed to be defined all at once.
+- `NVIM_TEST_CORE_*` (FU) (S): a set of environment variables which specify
+ where to search for core files. Are supposed to be defined all at once.
-`NVIM_TEST_CORE_GLOB_DIRECTORY` (FU) (S): directory where core files are
-located. May be `.`. This directory is then recursively searched for core files.
-Note: this variable must be defined for any of the following to have any effect.
+- `NVIM_TEST_CORE_GLOB_DIRECTORY` (FU) (S): directory where core files are
+ located. May be `.`. This directory is then recursively searched for core
+ files. Note: this variable must be defined for any of the following to have
+ any effect.
-`NVIM_TEST_CORE_GLOB_RE` (FU) (S): regular expression which must be matched by
-core files. E.g. `/core[^/]*$`. May be absent, in which case any file is
-considered to be matched.
+- `NVIM_TEST_CORE_GLOB_RE` (FU) (S): regular expression which must be matched
+ by core files. E.g. `/core[^/]*$`. May be absent, in which case any file is
+ considered to be matched.
-`NVIM_TEST_CORE_EXC_RE` (FU) (S): regular expression which excludes certain
-directories from searching for core files inside. E.g. use `^/%.deps$` to not
-search inside `/.deps`. If absent, nothing is excluded.
+- `NVIM_TEST_CORE_EXC_RE` (FU) (S): regular expression which excludes certain
+ directories from searching for core files inside. E.g. use `^/%.deps$` to not
+ search inside `/.deps`. If absent, nothing is excluded.
-`NVIM_TEST_CORE_DB_CMD` (FU) (S): command to get backtrace out of the debugger.
-E.g. `gdb -n -batch -ex "thread apply all bt full" "$_NVIM_TEST_APP" -c
-"$_NVIM_TEST_CORE"`. Defaults to the example command. This debug command may use
-environment variables `_NVIM_TEST_APP` (path to application which is being
-debugged: normally either nvim or luajit) and `_NVIM_TEST_CORE` (core file to
-get backtrace from).
+- `NVIM_TEST_CORE_DB_CMD` (FU) (S): command to get backtrace out of the
+ debugger. E.g. `gdb -n -batch -ex "thread apply all bt full"
+ "$_NVIM_TEST_APP" -c "$_NVIM_TEST_CORE"`. Defaults to the example command.
+ This debug command may use environment variables `_NVIM_TEST_APP` (path to
+ application which is being debugged: normally either nvim or luajit) and
+ `_NVIM_TEST_CORE` (core file to get backtrace from).
-`NVIM_TEST_CORE_RANDOM_SKIP` (FU) (D): makes `check_cores` not check cores after
-approximately 90% of the tests. Should be used when finding cores is too hard
-for some reason. Normally (on OS X or when `NVIM_TEST_CORE_GLOB_DIRECTORY` is
-defined and this variable is not) cores are checked for after each test.
+- `NVIM_TEST_CORE_RANDOM_SKIP` (FU) (D): makes `check_cores` not check cores
+ after approximately 90% of the tests. Should be used when finding cores is
+ too hard for some reason. Normally (on OS X or when
+ `NVIM_TEST_CORE_GLOB_DIRECTORY` is defined and this variable is not) cores
+ are checked for after each test.
-`NVIM_TEST_RUN_TESTTEST` (U) (1): allows running `test/unit/testtest_spec.lua`
-used to check how testing infrastructure works.
+- `NVIM_TEST_RUN_TESTTEST` (U) (1): allows running
+ `test/unit/testtest_spec.lua` used to check how testing infrastructure works.
-`NVIM_TEST_TRACE_LEVEL` (U) (N): specifies unit tests tracing level: `0`
-disables tracing (the fastest, but you get no data if tests crash and there was
-no core dump generated), `1` or empty/undefined leaves only C function cals and
-returns in the trace (faster then recording everything), `2` records all
-function calls, returns and lua source lines exuecuted.
+- `NVIM_TEST_TRACE_LEVEL` (U) (N): specifies unit tests tracing level: `0`
+ disables tracing (the fastest, but you get no data if tests crash and there
+ was no core dump generated), `1` or empty/undefined leaves only C function
+ cals and returns in the trace (faster then recording everything), `2` records
+ all function calls, returns and lua source lines exuecuted.
-`NVIM_TEST_TRACE_ON_ERROR` (U) (1): makes unit tests yield trace on error in
-addition to regular error message.
+- `NVIM_TEST_TRACE_ON_ERROR` (U) (1): makes unit tests yield trace on error in
+ addition to regular error message.
-`NVIM_TEST_MAXTRACE` (U) (N): specifies maximum number of trace lines to keep.
-Default is 1024.
+- `NVIM_TEST_MAXTRACE` (U) (N): specifies maximum number of trace lines to
+ keep. Default is 1024.
diff --git a/test/busted/outputHandlers/TAP.lua b/test/busted/outputHandlers/TAP.lua
new file mode 100644
index 0000000000..3dd171dc1b
--- /dev/null
+++ b/test/busted/outputHandlers/TAP.lua
@@ -0,0 +1,14 @@
+-- Extends the upstream TAP handler, to display the log with suiteEnd.
+
+local global_helpers = require('test.helpers')
+
+return function(options)
+ local handler = require 'busted.outputHandlers.TAP'(options)
+
+ handler.suiteEnd = function()
+ io.write(global_helpers.read_nvim_log())
+ return handler.suiteEnd()
+ end
+
+ return handler
+end
diff --git a/busted/outputHandlers/nvim.lua b/test/busted/outputHandlers/nvim.lua
index d137300a7e..1b500fc999 100644
--- a/busted/outputHandlers/nvim.lua
+++ b/test/busted/outputHandlers/nvim.lua
@@ -1,6 +1,4 @@
-local s = require 'say'
local pretty = require 'pl.pretty'
-local term = require 'term'
local global_helpers = require('test.helpers')
local colors
@@ -65,8 +63,6 @@ return function(options)
},
}
- c = nil
-
local fileCount = 0
local fileTestCount = 0
local testCount = 0
@@ -76,7 +72,6 @@ return function(options)
local errorCount = 0
local pendingDescription = function(pending)
- local name = pending.name
local string = ''
if type(pending.message) == 'string' then
@@ -175,7 +170,7 @@ return function(options)
return nil, true
end
- handler.suiteStart = function(suite, count, total, randomseed)
+ handler.suiteStart = function(_suite, count, total, randomseed)
if total > 1 then
io.write(repeatSuiteString:format(count, total))
end
@@ -196,7 +191,7 @@ return function(options)
end
end
- handler.suiteEnd = function(suite, count, total)
+ handler.suiteEnd = function(suite, _count, _total)
local elapsedTime_ms = getElapsedTime(suite)
local tests = (testCount == 1 and 'test' or 'tests')
local files = (fileCount == 1 and 'file' or 'files')
@@ -225,14 +220,14 @@ return function(options)
return nil, true
end
- handler.testStart = function(element, parent)
+ handler.testStart = function(element, _parent)
io.write(runString:format(handler.getFullName(element)))
io.flush()
return nil, true
end
- handler.testEnd = function(element, parent, status, debug)
+ handler.testEnd = function(element, _parent, status, _debug)
local elapsedTime_ms = getElapsedTime(element)
local string
@@ -263,7 +258,7 @@ return function(options)
return nil, true
end
- handler.testFailure = function(element, parent, message, debug)
+ handler.testFailure = function(_element, _parent, _message, _debug)
io.write(failureString)
io.flush()
@@ -272,7 +267,7 @@ return function(options)
return nil, true
end
- handler.testError = function(element, parent, message, debug)
+ handler.testError = function(_element, _parent, _message, _debug)
io.write(errorString)
io.flush()
@@ -281,7 +276,7 @@ return function(options)
return nil, true
end
- handler.error = function(element, parent, message, debug)
+ handler.error = function(element, _parent, _message, _debug)
if element.descriptor ~= 'it' then
io.write(failureDescription(handler.errors[#handler.errors]))
io.flush()
diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua
index b3f6bb7895..73c55a342c 100644
--- a/test/functional/api/keymap_spec.lua
+++ b/test/functional/api/keymap_spec.lua
@@ -346,11 +346,6 @@ describe('nvim_set_keymap, nvim_del_keymap', function()
to_return.sid = not opts.sid and 0 or opts.sid
to_return.buffer = not opts.buffer and 0 or opts.buffer
- -- mode 't' doesn't print when calling maparg
- if mode == 't' then
- to_return.mode = ''
- end
-
return to_return
end
diff --git a/test/functional/api/proc_spec.lua b/test/functional/api/proc_spec.lua
index d99c26b6c2..e11e03203f 100644
--- a/test/functional/api/proc_spec.lua
+++ b/test/functional/api/proc_spec.lua
@@ -17,24 +17,28 @@ describe('api', function()
it('returns child process ids', function()
local this_pid = funcs.getpid()
+ -- Might be non-zero already (left-over from some other test?),
+ -- but this is not what is tested here.
+ local initial_childs = request('nvim_get_proc_children', this_pid)
+
local job1 = funcs.jobstart(nvim_argv)
retry(nil, nil, function()
- eq(1, #request('nvim_get_proc_children', this_pid))
+ eq(#initial_childs + 1, #request('nvim_get_proc_children', this_pid))
end)
local job2 = funcs.jobstart(nvim_argv)
retry(nil, nil, function()
- eq(2, #request('nvim_get_proc_children', this_pid))
+ eq(#initial_childs + 2, #request('nvim_get_proc_children', this_pid))
end)
funcs.jobstop(job1)
retry(nil, nil, function()
- eq(1, #request('nvim_get_proc_children', this_pid))
+ eq(#initial_childs + 1, #request('nvim_get_proc_children', this_pid))
end)
funcs.jobstop(job2)
retry(nil, nil, function()
- eq(0, #request('nvim_get_proc_children', this_pid))
+ eq(#initial_childs, #request('nvim_get_proc_children', this_pid))
end)
end)
diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua
index 07218f11dd..dbe9f20412 100644
--- a/test/functional/api/server_requests_spec.lua
+++ b/test/functional/api/server_requests_spec.lua
@@ -181,7 +181,7 @@ describe('server -> client', function()
end)
describe('recursive (child) nvim client', function()
- if os.getenv("TRAVIS") and helpers.os_name() == "osx" then
+ if helpers.isCI('travis') and helpers.os_name() == 'osx' then
-- XXX: Hangs Travis macOS since e9061117a5b8f195c3f26a5cb94e18ddd7752d86.
pending("[Hangs on Travis macOS. #5002]", function() end)
return
@@ -340,7 +340,7 @@ describe('server -> client', function()
describe('connecting to its own pipe address', function()
it('does not deadlock', function()
- if not os.getenv("TRAVIS") and helpers.os_name() == "osx" then
+ if not helpers.isCI('travis') and helpers.os_name() == 'osx' then
-- It does, in fact, deadlock on QuickBuild. #6851
pending("deadlocks on QuickBuild", function() end)
return
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index 4279a5d420..110b3a4b16 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -11,6 +11,7 @@ local meth_pcall = helpers.meth_pcall
local meths = helpers.meths
local ok, nvim_async, feed = helpers.ok, helpers.nvim_async, helpers.feed
local os_name = helpers.os_name
+local parse_context = helpers.parse_context
local request = helpers.request
local source = helpers.source
local next_msg = helpers.next_msg
@@ -339,6 +340,15 @@ describe('API', function()
"did\nthe\nfail"},
meth_pcall(meths.execute_lua, 'error("did\\nthe\\nfail")', {}))
end)
+
+ it('uses native float values', function()
+ eq(2.5, meths.execute_lua("return select(1, ...)", {2.5}))
+ eq("2.5", meths.execute_lua("return vim.inspect(...)", {2.5}))
+
+ -- "special" float values are still accepted as return values.
+ eq(2.5, meths.execute_lua("return vim.api.nvim_eval('2.5')", {}))
+ eq("{\n [false] = 2.5,\n [true] = 3\n}", meths.execute_lua("return vim.inspect(vim.api.nvim_eval('2.5'))", {}))
+ end)
end)
describe('nvim_input', function()
@@ -671,6 +681,65 @@ describe('API', function()
end)
end)
+ describe('nvim_get_context', function()
+ it('returns context dictionary of current editor state', function()
+ local ctx_items = {'regs', 'jumps', 'buflist', 'gvars'}
+ eq({}, parse_context(nvim('get_context', ctx_items)))
+
+ feed('i1<cr>2<cr>3<c-[>ddddddqahjklquuu')
+ feed('gg')
+ feed('G')
+ command('edit! BUF1')
+ command('edit BUF2')
+ nvim('set_var', 'one', 1)
+ nvim('set_var', 'Two', 2)
+ nvim('set_var', 'THREE', 3)
+
+ local expected_ctx = {
+ ['regs'] = {
+ {['rt'] = 1, ['rc'] = {'1'}, ['n'] = 49, ['ru'] = true},
+ {['rt'] = 1, ['rc'] = {'2'}, ['n'] = 50},
+ {['rt'] = 1, ['rc'] = {'3'}, ['n'] = 51},
+ {['rc'] = {'hjkl'}, ['n'] = 97},
+ },
+
+ ['jumps'] = eval(([[
+ filter(map(add(
+ getjumplist()[0], { 'bufnr': bufnr('%'), 'lnum': getcurpos()[1] }),
+ 'filter(
+ { "f": expand("#".v:val.bufnr.":p"), "l": v:val.lnum },
+ { k, v -> k != "l" || v != 1 })'), '!empty(v:val.f)')
+ ]]):gsub('\n', '')),
+
+ ['buflist'] = eval([[
+ filter(map(getbufinfo(), '{ "f": v:val.name }'), '!empty(v:val.f)')
+ ]]),
+
+ ['gvars'] = {{'one', 1}, {'Two', 2}, {'THREE', 3}},
+ }
+
+ eq(expected_ctx, parse_context(nvim('get_context', ctx_items)))
+ end)
+ end)
+
+ describe('nvim_load_context', function()
+ it('sets current editor state to given context dictionary', function()
+ local ctx_items = {'regs', 'jumps', 'buflist', 'gvars'}
+ eq({}, parse_context(nvim('get_context', ctx_items)))
+
+ nvim('set_var', 'one', 1)
+ nvim('set_var', 'Two', 2)
+ nvim('set_var', 'THREE', 3)
+ local ctx = nvim('get_context', ctx_items)
+ nvim('set_var', 'one', 'a')
+ nvim('set_var', 'Two', 'b')
+ nvim('set_var', 'THREE', 'c')
+ eq({'a', 'b' ,'c'}, eval('[g:one, g:Two, g:THREE]'))
+ nvim('load_context', ctx)
+ eq({1, 2 ,3}, eval('[g:one, g:Two, g:THREE]'))
+ end)
+ end)
+
describe('nvim_replace_termcodes', function()
it('escapes K_SPECIAL as K_SPECIAL KS_SPECIAL KE_FILLER', function()
eq('\128\254X', helpers.nvim('replace_termcodes', '\128', true, true, true))
diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua
index 4ff299cd18..9af1bdb93b 100644
--- a/test/functional/api/window_spec.lua
+++ b/test/functional/api/window_spec.lua
@@ -322,5 +322,21 @@ describe('API/win', function()
meths.win_close(oldwin,true)
eq({newwin}, meths.list_wins())
end)
+
+ it('in cmdline-window #9767', function()
+ command('split')
+ eq(2, #meths.list_wins())
+ local oldwin = meths.get_current_win()
+ -- Open cmdline-window.
+ feed('q:')
+ eq(3, #meths.list_wins())
+ eq(':', funcs.getcmdwintype())
+ -- Vim: not allowed to close other windows from cmdline-window.
+ expect_err('E11: Invalid in command%-line window; <CR> executes, CTRL%-C quits$', meths.win_close, oldwin, true)
+ -- Close cmdline-window.
+ meths.win_close(0,true)
+ eq(2, #meths.list_wins())
+ eq('', funcs.getcmdwintype())
+ end)
end)
end)
diff --git a/test/functional/autocmd/autocmd_spec.lua b/test/functional/autocmd/autocmd_spec.lua
index 20538d7141..0a583b6d8d 100644
--- a/test/functional/autocmd/autocmd_spec.lua
+++ b/test/functional/autocmd/autocmd_spec.lua
@@ -260,4 +260,26 @@ describe('autocmd', function()
eq({false, 'Vim(call):E5555: API call: Invalid window id'},
meth_pcall(command, "call nvim_set_current_win(g:winid)"))
end)
+
+ it(':doautocmd does not warn "No matching autocommands" #10689', function()
+ local screen = Screen.new(32, 3)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue1},
+ })
+
+ feed(':doautocmd User Foo<cr>')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ :doautocmd User Foo |
+ ]]}
+ feed(':autocmd! SessionLoadPost<cr>')
+ feed(':doautocmd SessionLoadPost<cr>')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ :doautocmd SessionLoadPost |
+ ]]}
+ end)
end)
diff --git a/test/functional/autocmd/cursorhold_spec.lua b/test/functional/autocmd/cursorhold_spec.lua
new file mode 100644
index 0000000000..506b688853
--- /dev/null
+++ b/test/functional/autocmd/cursorhold_spec.lua
@@ -0,0 +1,31 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local clear = helpers.clear
+local eq = helpers.eq
+local eval = helpers.eval
+local feed = helpers.feed
+local retry = helpers.retry
+local source = helpers.source
+local sleep = helpers.sleep
+
+describe('CursorHoldI', function()
+ before_each(clear)
+
+ -- NOTE: since this test uses RPC it is not necessary to trigger the initial
+ -- issue (#3757) via timer's or RPC callbacks in the first place.
+ it('is triggered after input', function()
+ source([[
+ set updatetime=1
+
+ let g:cursorhold = 0
+ augroup test
+ au CursorHoldI * let g:cursorhold += 1
+ augroup END
+ ]])
+ feed('ifoo')
+ retry(5, nil, function()
+ sleep(1)
+ eq(1, eval('g:cursorhold'))
+ end)
+ end)
+end)
diff --git a/test/functional/autocmd/termclose_spec.lua b/test/functional/autocmd/termclose_spec.lua
index 62eac59b16..50bcf1af5a 100644
--- a/test/functional/autocmd/termclose_spec.lua
+++ b/test/functional/autocmd/termclose_spec.lua
@@ -3,8 +3,8 @@ local helpers = require('test.functional.helpers')(after_each)
local clear, command, nvim, nvim_dir =
helpers.clear, helpers.command, helpers.nvim, helpers.nvim_dir
-local eval, eq, retry =
- helpers.eval, helpers.eq, helpers.retry
+local eval, eq, neq, retry =
+ helpers.eval, helpers.eq, helpers.neq, helpers.retry
local ok = helpers.ok
local feed = helpers.feed
local iswin = helpers.iswin
@@ -20,7 +20,8 @@ describe('TermClose event', function()
it('triggers when fast-exiting terminal job stops', function()
command('autocmd TermClose * let g:test_termclose = 23')
command('terminal')
- command('call jobstop(b:terminal_job_id)')
+ -- shell-test exits immediately.
+ retry(nil, nil, function() neq(-1, eval('jobwait([&channel], 0)[0]')) end)
retry(nil, nil, function() eq(23, eval('g:test_termclose')) end)
end)
diff --git a/test/functional/autocmd/textyankpost_spec.lua b/test/functional/autocmd/textyankpost_spec.lua
index 5849679dd2..8c23b72cff 100644
--- a/test/functional/autocmd/textyankpost_spec.lua
+++ b/test/functional/autocmd/textyankpost_spec.lua
@@ -229,4 +229,9 @@ describe('TextYankPost', function()
eq(4, eval('g:count'))
end)
+ it('updates numbered registers correctly #10225', function()
+ command('autocmd TextYankPost * let g:reg = getreg("1")')
+ feed('"adj')
+ eq('foo\nbar\nbaz text\n', eval('g:reg'))
+ end)
end)
diff --git a/test/functional/core/fileio_spec.lua b/test/functional/core/fileio_spec.lua
index c74eb3bb02..e6bce85b8a 100644
--- a/test/functional/core/fileio_spec.lua
+++ b/test/functional/core/fileio_spec.lua
@@ -22,6 +22,7 @@ describe('fileio', function()
os.remove('Xtest_startup_file1')
os.remove('Xtest_startup_file1~')
os.remove('Xtest_startup_file2')
+ os.remove('Xtest_теÑÑ‚.md')
rmdir('Xtest_startup_swapdir')
end)
@@ -85,7 +86,22 @@ describe('fileio', function()
eq('foobar', foobar_contents);
eq('foo', bar_contents);
+ end)
+ it('readfile() on multibyte filename #10586', function()
+ clear()
+ local text = {
+ 'line1',
+ ' ...line2... ',
+ '',
+ 'line3!',
+ 'теÑÑ‚ yay теÑÑ‚.',
+ '',
+ }
+ local fname = 'Xtest_теÑÑ‚.md'
+ funcs.writefile(text, fname, 's')
+ table.insert(text, '')
+ eq(text, funcs.readfile(fname, 'b'))
end)
end)
diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua
index eb02610df0..180ed9aa02 100644
--- a/test/functional/core/job_spec.lua
+++ b/test/functional/core/job_spec.lua
@@ -159,7 +159,7 @@ describe('jobs', function()
end)
it('allows interactive commands', function()
- nvim('command', "let j = jobstart(has('win32') ? ['find', '/v', ''] : ['cat', '-'], g:job_opts)")
+ nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)")
neq(0, eval('j'))
nvim('command', 'call jobsend(j, "abc\\n")')
eq({'notification', 'stdout', {0, {'abc', ''}}}, next_msg())
@@ -183,11 +183,10 @@ describe('jobs', function()
)
nvim('command', "call jobstop(j)")
eq({'notification', 'stdout', {0, {''}}}, next_msg())
- eq({'notification', 'exit', {0, 0}}, next_msg())
+ eq({'notification', 'exit', {0, 143}}, next_msg())
end)
it('preserves NULs', function()
- if helpers.pending_win32(pending) then return end -- TODO: Need `cat`.
-- Make a file with NULs in it.
local filename = helpers.tmpname()
write_file(filename, "abc\0def\n")
@@ -206,8 +205,7 @@ describe('jobs', function()
end)
it("will not buffer data if it doesn't end in newlines", function()
- if helpers.pending_win32(pending) then return end -- TODO: Need `cat`.
- if os.getenv("TRAVIS") and os.getenv("CC") == "gcc-4.9"
+ if helpers.isCI('travis') and os.getenv('CC') == 'gcc-4.9'
and helpers.os_name() == "osx" then
-- XXX: Hangs Travis macOS since e9061117a5b8f195c3f26a5cb94e18ddd7752d86.
pending("[Hangs on Travis macOS. #5002]", function() end)
@@ -219,11 +217,10 @@ describe('jobs', function()
eq({'notification', 'stdout', {0, {'abc', 'xyz'}}}, next_msg())
nvim('command', "call jobstop(j)")
eq({'notification', 'stdout', {0, {''}}}, next_msg())
- eq({'notification', 'exit', {0, 0}}, next_msg())
+ eq({'notification', 'exit', {0, 143}}, next_msg())
end)
it('preserves newlines', function()
- if helpers.pending_win32(pending) then return end -- TODO: Need `cat`.
nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)")
nvim('command', 'call jobsend(j, "a\\n\\nc\\n\\n\\n\\nb\\n\\n")')
eq({'notification', 'stdout',
@@ -231,36 +228,34 @@ describe('jobs', function()
end)
it('preserves NULs', function()
- if helpers.pending_win32(pending) then return end -- TODO: Need `cat`.
nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)")
nvim('command', 'call jobsend(j, ["\n123\n", "abc\\nxyz\n", ""])')
eq({'notification', 'stdout', {0, {'\n123\n', 'abc\nxyz\n', ''}}},
next_msg())
nvim('command', "call jobstop(j)")
eq({'notification', 'stdout', {0, {''}}}, next_msg())
- eq({'notification', 'exit', {0, 0}}, next_msg())
+ eq({'notification', 'exit', {0, 143}}, next_msg())
end)
it('avoids sending final newline', function()
- if helpers.pending_win32(pending) then return end -- TODO: Need `cat`.
nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)")
nvim('command', 'call jobsend(j, ["some data", "without\nfinal nl"])')
eq({'notification', 'stdout', {0, {'some data', 'without\nfinal nl'}}},
next_msg())
nvim('command', "call jobstop(j)")
eq({'notification', 'stdout', {0, {''}}}, next_msg())
- eq({'notification', 'exit', {0, 0}}, next_msg())
+ eq({'notification', 'exit', {0, 143}}, next_msg())
end)
it('closes the job streams with jobclose', function()
- nvim('command', "let j = jobstart(has('win32') ? ['find', '/v', ''] : ['cat', '-'], g:job_opts)")
+ nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)")
nvim('command', 'call jobclose(j, "stdin")')
eq({'notification', 'stdout', {0, {''}}}, next_msg())
- eq({'notification', 'exit', {0, iswin() and 1 or 0}}, next_msg())
+ eq({'notification', 'exit', {0, 0}}, next_msg())
end)
it("disallows jobsend on a job that closed stdin", function()
- nvim('command', "let j = jobstart(has('win32') ? ['find', '/v', ''] : ['cat', '-'], g:job_opts)")
+ nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)")
nvim('command', 'call jobclose(j, "stdin")')
eq(false, pcall(function()
nvim('command', 'call jobsend(j, ["some data"])')
@@ -273,7 +268,7 @@ describe('jobs', function()
end)
it('disallows jobstop twice on the same job', function()
- nvim('command', "let j = jobstart(has('win32') ? ['find', '/v', ''] : ['cat', '-'], g:job_opts)")
+ nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)")
neq(0, eval('j'))
eq(true, pcall(eval, "jobstop(j)"))
eq(false, pcall(eval, "jobstop(j)"))
@@ -284,23 +279,12 @@ describe('jobs', function()
end)
it('can get the pid value using getpid', function()
- nvim('command', "let j = jobstart(has('win32') ? ['find', '/v', ''] : ['cat', '-'], g:job_opts)")
+ nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)")
local pid = eval('jobpid(j)')
neq(NIL, meths.get_proc(pid))
nvim('command', 'call jobstop(j)')
eq({'notification', 'stdout', {0, {''}}}, next_msg())
- if iswin() then
- expect_msg_seq(
- -- win64
- { {'notification', 'exit', {0, 1}}
- },
- -- win32
- { {'notification', 'exit', {0, 15}}
- }
- )
- else
- eq({'notification', 'exit', {0, 0}}, next_msg())
- end
+ eq({'notification', 'exit', {0, 143}}, next_msg())
eq(NIL, meths.get_proc(pid))
end)
@@ -439,16 +423,66 @@ describe('jobs', function()
call add(self.data, Normalize(a:data))
sleep 200m
endfunction
+ function! d.on_exit(job, data, event) dict
+ let g:exit_data = copy(self.data)
+ endfunction
+ if has('win32')
+ let cmd = 'for /L %I in (1,1,5) do @(echo %I& ping -n 2 127.0.0.1 > nul)'
+ else
+ let cmd = ['sh', '-c', 'for i in $(seq 1 5); do echo $i; sleep 0.1; done']
+ endif
+ let g:id = jobstart(cmd, d)
+ sleep 1500m
+ call jobwait([g:id])
+ ]])
+
+ local expected = {'1', '2', '3', '4', '5', ''}
+ local chunks = eval('d.data')
+ -- check nothing was received after exit, including EOF
+ eq(eval('g:exit_data'), chunks)
+ local received = {''}
+ for i, chunk in ipairs(chunks) do
+ if i < #chunks then
+ -- if chunks got joined, a spurious [''] callback was not sent
+ neq({''}, chunk)
+ else
+ -- but EOF callback is still sent
+ eq({''}, chunk)
+ end
+ received[#received] = received[#received]..chunk[1]
+ for j = 2, #chunk do
+ received[#received+1] = chunk[j]
+ end
+ end
+ eq(expected, received)
+ end)
+
+ it('does not invoke callbacks recursively', function()
+ source([[
+ let d = {'data': []}
+ function! d.on_stdout(job, data, event) dict
+ " if callbacks were invoked recursively, this would cause on_stdout
+ " to be invoked recursively and the data reversed on the call stack
+ sleep 200m
+ call add(self.data, Normalize(a:data))
+ endfunction
+ function! d.on_exit(job, data, event) dict
+ let g:exit_data = copy(self.data)
+ endfunction
if has('win32')
let cmd = 'for /L %I in (1,1,5) do @(echo %I& ping -n 2 127.0.0.1 > nul)'
else
let cmd = ['sh', '-c', 'for i in $(seq 1 5); do echo $i; sleep 0.1; done']
endif
- call jobwait([jobstart(cmd, d)])
+ let g:id = jobstart(cmd, d)
+ sleep 1500m
+ call jobwait([g:id])
]])
local expected = {'1', '2', '3', '4', '5', ''}
local chunks = eval('d.data')
+ -- check nothing was received after exit, including EOF
+ eq(eval('g:exit_data'), chunks)
local received = {''}
for i, chunk in ipairs(chunks) do
if i < #chunks then
@@ -709,7 +743,7 @@ describe('jobs', function()
it('cannot have both rpc and pty options', function()
command("let g:job_opts.pty = v:true")
command("let g:job_opts.rpc = v:true")
- local _, err = pcall(command, "let j = jobstart(has('win32') ? ['find', '/v', ''] : ['cat', '-'], g:job_opts)")
+ local _, err = pcall(command, "let j = jobstart(['cat', '-'], g:job_opts)")
ok(string.find(err, "E475: Invalid argument: job cannot have both 'pty' and 'rpc' options set") ~= nil)
end)
@@ -752,7 +786,7 @@ describe('jobs', function()
eq(ppid, info.ppid)
end
-- Kill the root of the tree.
- funcs.jobstop(j)
+ eq(1, funcs.jobstop(j))
-- Assert that the children were killed.
retry(nil, nil, function()
for _, child_pid in ipairs(children) do
diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua
index 23e1ac7c93..3b32c42ec0 100644
--- a/test/functional/core/startup_spec.lua
+++ b/test/functional/core/startup_spec.lua
@@ -222,7 +222,12 @@ describe('startup', function()
eq(2, eval('1+1'))
end)
- it('message display ends with enter #7967', function()
+ it('does not crash when expanding cdpath during early_init', function()
+ clear{env={CDPATH='~doesnotexist'}}
+ eq(',~doesnotexist', eval('&cdpath'))
+ end)
+
+ it('ENTER dismisses early message #7967', function()
local screen
screen = Screen.new(60, 6)
screen:attach()
@@ -236,7 +241,7 @@ describe('startup', function()
Press ENTER or type command to continue |
|
]])
- command('call chansend(g:id, "\n")')
+ command([[call chansend(g:id, "\n")]])
screen:expect([[
^ |
~ |
diff --git a/test/functional/eval/api_functions_spec.lua b/test/functional/eval/api_functions_spec.lua
index 0e3a88802d..3947f88c0a 100644
--- a/test/functional/eval/api_functions_spec.lua
+++ b/test/functional/eval/api_functions_spec.lua
@@ -4,7 +4,8 @@ local lfs = require('lfs')
local neq, eq, command = helpers.neq, helpers.eq, helpers.command
local clear, curbufmeths = helpers.clear, helpers.curbufmeths
local exc_exec, expect, eval = helpers.exc_exec, helpers.expect, helpers.eval
-local insert = helpers.insert
+local insert, meth_pcall = helpers.insert, helpers.meth_pcall
+local meths = helpers.meths
describe('eval-API', function()
before_each(clear)
@@ -145,4 +146,10 @@ describe('eval-API', function()
]])
screen:detach()
end)
+
+ it('cannot be called from sandbox', function()
+ eq({false, 'Vim(call):E48: Not allowed in sandbox'},
+ meth_pcall(command, "sandbox call nvim_input('ievil')"))
+ eq({''}, meths.buf_get_lines(0, 0, -1, true))
+ end)
end)
diff --git a/test/functional/eval/ctx_functions_spec.lua b/test/functional/eval/ctx_functions_spec.lua
new file mode 100644
index 0000000000..35133e2341
--- /dev/null
+++ b/test/functional/eval/ctx_functions_spec.lua
@@ -0,0 +1,408 @@
+local helpers = require('test.functional.helpers')(after_each)
+
+local call = helpers.call
+local clear = helpers.clear
+local command = helpers.command
+local eq = helpers.eq
+local eval = helpers.eval
+local expect_err = helpers.expect_err
+local feed = helpers.feed
+local map = helpers.map
+local nvim = helpers.nvim
+local parse_context = helpers.parse_context
+local redir_exec = helpers.redir_exec
+local source = helpers.source
+local trim = helpers.trim
+local write_file = helpers.write_file
+
+describe('context functions', function()
+ local fname1 = 'Xtest-functional-eval-ctx1'
+ local fname2 = 'Xtest-functional-eval-ctx2'
+ local outofbounds =
+ 'Vim:E475: Invalid value for argument index: out of bounds'
+
+ before_each(function()
+ clear()
+ write_file(fname1, "1\n2\n3")
+ write_file(fname2, "a\nb\nc")
+ end)
+
+ after_each(function()
+ os.remove(fname1)
+ os.remove(fname2)
+ end)
+
+ describe('ctxpush/ctxpop', function()
+ it('saves and restores registers properly', function()
+ local regs = {'1', '2', '3', 'a'}
+ local vals = {'1', '2', '3', 'hjkl'}
+ feed('i1<cr>2<cr>3<c-[>ddddddqahjklq')
+ eq(vals, map(function(r) return trim(call('getreg', r)) end, regs))
+ call('ctxpush')
+ call('ctxpush', {'regs'})
+
+ map(function(r) call('setreg', r, {}) end, regs)
+ eq({'', '', '', ''},
+ map(function(r) return trim(call('getreg', r)) end, regs))
+
+ call('ctxpop')
+ eq(vals, map(function(r) return trim(call('getreg', r)) end, regs))
+
+ map(function(r) call('setreg', r, {}) end, regs)
+ eq({'', '', '', ''},
+ map(function(r) return trim(call('getreg', r)) end, regs))
+
+ call('ctxpop')
+ eq(vals, map(function(r) return trim(call('getreg', r)) end, regs))
+ end)
+
+ it('saves and restores jumplist properly', function()
+ command('edit '..fname1)
+ feed('G')
+ feed('gg')
+ command('edit '..fname2)
+ local jumplist = call('getjumplist')
+ call('ctxpush')
+ call('ctxpush', {'jumps'})
+
+ command('clearjumps')
+ eq({{}, 0}, call('getjumplist'))
+
+ call('ctxpop')
+ eq(jumplist, call('getjumplist'))
+
+ command('clearjumps')
+ eq({{}, 0}, call('getjumplist'))
+
+ call('ctxpop')
+ eq(jumplist, call('getjumplist'))
+ end)
+
+ it('saves and restores buffer list properly', function()
+ command('edit '..fname1)
+ command('edit '..fname2)
+ command('edit TEST')
+ local buflist = call('map', call('getbufinfo'), 'v:val.name')
+ call('ctxpush')
+ call('ctxpush', {'buflist'})
+
+ command('%bwipeout')
+ eq({''}, call('map', call('getbufinfo'), 'v:val.name'))
+
+ call('ctxpop')
+ eq({'', unpack(buflist)}, call('map', call('getbufinfo'), 'v:val.name'))
+
+ command('%bwipeout')
+ eq({''}, call('map', call('getbufinfo'), 'v:val.name'))
+
+ call('ctxpop')
+ eq({'', unpack(buflist)}, call('map', call('getbufinfo'), 'v:val.name'))
+ end)
+
+ it('saves and restores global variables properly', function()
+ nvim('set_var', 'one', 1)
+ nvim('set_var', 'Two', 2)
+ nvim('set_var', 'THREE', 3)
+ eq({1, 2 ,3}, eval('[g:one, g:Two, g:THREE]'))
+ call('ctxpush')
+ call('ctxpush', {'gvars'})
+
+ nvim('del_var', 'one')
+ nvim('del_var', 'Two')
+ nvim('del_var', 'THREE')
+ expect_err('E121: Undefined variable: g:one', eval, 'g:one')
+ expect_err('E121: Undefined variable: g:Two', eval, 'g:Two')
+ expect_err('E121: Undefined variable: g:THREE', eval, 'g:THREE')
+
+ call('ctxpop')
+ eq({1, 2 ,3}, eval('[g:one, g:Two, g:THREE]'))
+
+ nvim('del_var', 'one')
+ nvim('del_var', 'Two')
+ nvim('del_var', 'THREE')
+ expect_err('E121: Undefined variable: g:one', eval, 'g:one')
+ expect_err('E121: Undefined variable: g:Two', eval, 'g:Two')
+ expect_err('E121: Undefined variable: g:THREE', eval, 'g:THREE')
+
+ call('ctxpop')
+ eq({1, 2 ,3}, eval('[g:one, g:Two, g:THREE]'))
+ end)
+
+ it('saves and restores script functions properly', function()
+ source([[
+ function s:greet(name)
+ echom 'Hello, '.a:name.'!'
+ endfunction
+
+ function s:greet_all(name, ...)
+ echom 'Hello, '.a:name.'!'
+ for more in a:000
+ echom 'Hello, '.more.'!'
+ endfor
+ endfunction
+
+ function Greet(name)
+ call call('s:greet', [a:name])
+ endfunction
+
+ function GreetAll(name, ...)
+ call call('s:greet_all', extend([a:name], a:000))
+ endfunction
+
+ function SaveSFuncs()
+ call ctxpush(['sfuncs'])
+ endfunction
+
+ function DeleteSFuncs()
+ delfunction s:greet
+ delfunction s:greet_all
+ endfunction
+
+ function RestoreFuncs()
+ call ctxpop()
+ endfunction
+ ]])
+
+ eq('\nHello, World!', redir_exec([[call Greet('World')]]))
+ eq('\nHello, World!'..
+ '\nHello, One!'..
+ '\nHello, Two!'..
+ '\nHello, Three!',
+ redir_exec([[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')]]))
+
+ call('RestoreFuncs')
+
+ eq('\nHello, World!', redir_exec([[call Greet('World')]]))
+ eq('\nHello, World!'..
+ '\nHello, One!'..
+ '\nHello, Two!'..
+ '\nHello, Three!',
+ redir_exec([[call GreetAll('World', 'One', 'Two', 'Three')]]))
+ end)
+
+ it('saves and restores functions properly', function()
+ source([[
+ function Greet(name)
+ echom 'Hello, '.a:name.'!'
+ endfunction
+
+ function GreetAll(name, ...)
+ echom 'Hello, '.a:name.'!'
+ for more in a:000
+ echom 'Hello, '.more.'!'
+ endfor
+ endfunction
+ ]])
+
+ eq('\nHello, World!', redir_exec([[call Greet('World')]]))
+ eq('\nHello, World!'..
+ '\nHello, One!'..
+ '\nHello, Two!'..
+ '\nHello, Three!',
+ redir_exec([[call GreetAll('World', 'One', 'Two', 'Three')]]))
+
+ call('ctxpush', {'funcs'})
+ command('delfunction Greet')
+ command('delfunction GreetAll')
+
+ expect_err('Vim:E117: Unknown function: Greet', call, 'Greet', 'World')
+ expect_err('Vim:E117: Unknown function: Greet', call, 'GreetAll',
+ 'World', 'One', 'Two', 'Three')
+
+ call('ctxpop')
+
+ eq('\nHello, World!', redir_exec([[call Greet('World')]]))
+ eq('\nHello, World!'..
+ '\nHello, One!'..
+ '\nHello, Two!'..
+ '\nHello, Three!',
+ redir_exec([[call GreetAll('World', 'One', 'Two', 'Three')]]))
+ end)
+
+ it('errors out when context stack is empty', function()
+ local err = 'Vim:Context stack is empty'
+ expect_err(err, call, 'ctxpop')
+ expect_err(err, call, 'ctxpop')
+ call('ctxpush')
+ call('ctxpush')
+ call('ctxpop')
+ call('ctxpop')
+ expect_err(err, call, 'ctxpop')
+ end)
+ end)
+
+ describe('ctxsize()', function()
+ it('returns context stack size', function()
+ eq(0, call('ctxsize'))
+ call('ctxpush')
+ eq(1, call('ctxsize'))
+ call('ctxpush')
+ eq(2, call('ctxsize'))
+ call('ctxpush')
+ eq(3, call('ctxsize'))
+ call('ctxpop')
+ eq(2, call('ctxsize'))
+ call('ctxpop')
+ eq(1, call('ctxsize'))
+ call('ctxpop')
+ eq(0, call('ctxsize'))
+ end)
+ end)
+
+ describe('ctxget()', function()
+ it('errors out when index is out of bounds', function()
+ expect_err(outofbounds, call, 'ctxget')
+ call('ctxpush')
+ expect_err(outofbounds, call, 'ctxget', 1)
+ call('ctxpop')
+ expect_err(outofbounds, call, 'ctxget', 0)
+ end)
+
+ it('returns context dictionary at index in context stack', function()
+ feed('i1<cr>2<cr>3<c-[>ddddddqahjklq')
+ command('edit! '..fname1)
+ feed('G')
+ feed('gg')
+ command('edit '..fname2)
+ nvim('set_var', 'one', 1)
+ nvim('set_var', 'Two', 2)
+ nvim('set_var', 'THREE', 3)
+
+ local with_regs = {
+ ['regs'] = {
+ {['rt'] = 1, ['rc'] = {'1'}, ['n'] = 49, ['ru'] = true},
+ {['rt'] = 1, ['rc'] = {'2'}, ['n'] = 50},
+ {['rt'] = 1, ['rc'] = {'3'}, ['n'] = 51},
+ {['rc'] = {'hjkl'}, ['n'] = 97},
+ }
+ }
+
+ local with_jumps = {
+ ['jumps'] = eval(([[
+ filter(map(add(
+ getjumplist()[0], { 'bufnr': bufnr('%'), 'lnum': getcurpos()[1] }),
+ 'filter(
+ { "f": expand("#".v:val.bufnr.":p"), "l": v:val.lnum },
+ { k, v -> k != "l" || v != 1 })'), '!empty(v:val.f)')
+ ]]):gsub('\n', ''))
+ }
+
+ local with_buflist = {
+ ['buflist'] = eval([[
+ filter(map(getbufinfo(), '{ "f": v:val.name }'), '!empty(v:val.f)')
+ ]])
+ }
+
+ local with_gvars = {
+ ['gvars'] = {{'one', 1}, {'Two', 2}, {'THREE', 3}}
+ }
+
+ local with_all = {
+ ['regs'] = with_regs['regs'],
+ ['jumps'] = with_jumps['jumps'],
+ ['buflist'] = with_buflist['buflist'],
+ ['gvars'] = with_gvars['gvars'],
+ }
+
+ call('ctxpush')
+ eq(with_all, parse_context(call('ctxget')))
+ eq(with_all, parse_context(call('ctxget', 0)))
+
+ call('ctxpush', {'gvars'})
+ eq(with_gvars, parse_context(call('ctxget')))
+ eq(with_gvars, parse_context(call('ctxget', 0)))
+ eq(with_all, parse_context(call('ctxget', 1)))
+
+ call('ctxpush', {'buflist'})
+ eq(with_buflist, parse_context(call('ctxget')))
+ eq(with_buflist, parse_context(call('ctxget', 0)))
+ eq(with_gvars, parse_context(call('ctxget', 1)))
+ eq(with_all, parse_context(call('ctxget', 2)))
+
+ call('ctxpush', {'jumps'})
+ eq(with_jumps, parse_context(call('ctxget')))
+ eq(with_jumps, parse_context(call('ctxget', 0)))
+ eq(with_buflist, parse_context(call('ctxget', 1)))
+ eq(with_gvars, parse_context(call('ctxget', 2)))
+ eq(with_all, parse_context(call('ctxget', 3)))
+
+ call('ctxpush', {'regs'})
+ eq(with_regs, parse_context(call('ctxget')))
+ eq(with_regs, parse_context(call('ctxget', 0)))
+ eq(with_jumps, parse_context(call('ctxget', 1)))
+ eq(with_buflist, parse_context(call('ctxget', 2)))
+ eq(with_gvars, parse_context(call('ctxget', 3)))
+ eq(with_all, parse_context(call('ctxget', 4)))
+
+ call('ctxpop')
+ eq(with_jumps, parse_context(call('ctxget')))
+ eq(with_jumps, parse_context(call('ctxget', 0)))
+ eq(with_buflist, parse_context(call('ctxget', 1)))
+ eq(with_gvars, parse_context(call('ctxget', 2)))
+ eq(with_all, parse_context(call('ctxget', 3)))
+
+ call('ctxpop')
+ eq(with_buflist, parse_context(call('ctxget')))
+ eq(with_buflist, parse_context(call('ctxget', 0)))
+ eq(with_gvars, parse_context(call('ctxget', 1)))
+ eq(with_all, parse_context(call('ctxget', 2)))
+
+ call('ctxpop')
+ eq(with_gvars, parse_context(call('ctxget')))
+ eq(with_gvars, parse_context(call('ctxget', 0)))
+ eq(with_all, parse_context(call('ctxget', 1)))
+
+ call('ctxpop')
+ eq(with_all, parse_context(call('ctxget')))
+ eq(with_all, parse_context(call('ctxget', 0)))
+ end)
+ end)
+
+ describe('ctxset()', function()
+ it('errors out when index is out of bounds', function()
+ expect_err(outofbounds, call, 'ctxset', {dummy = 1})
+ call('ctxpush')
+ expect_err(outofbounds, call, 'ctxset', {dummy = 1}, 1)
+ call('ctxpop')
+ expect_err(outofbounds, call, 'ctxset', {dummy = 1}, 0)
+ end)
+
+ it('sets context dictionary at index in context stack', function()
+ nvim('set_var', 'one', 1)
+ nvim('set_var', 'Two', 2)
+ nvim('set_var', 'THREE', 3)
+ call('ctxpush')
+ local ctx1 = call('ctxget')
+ nvim('set_var', 'one', 'a')
+ nvim('set_var', 'Two', 'b')
+ nvim('set_var', 'THREE', 'c')
+ call('ctxpush')
+ call('ctxpush')
+ local ctx2 = call('ctxget')
+
+ eq({'a', 'b' ,'c'}, eval('[g:one, g:Two, g:THREE]'))
+ call('ctxset', ctx1)
+ call('ctxset', ctx2, 2)
+ call('ctxpop')
+ eq({1, 2 ,3}, eval('[g:one, g:Two, g:THREE]'))
+ call('ctxpop')
+ eq({'a', 'b' ,'c'}, eval('[g:one, g:Two, g:THREE]'))
+ nvim('set_var', 'one', 1.5)
+ eq({1.5, 'b' ,'c'}, eval('[g:one, g:Two, g:THREE]'))
+ call('ctxpop')
+ eq({'a', 'b' ,'c'}, eval('[g:one, g:Two, g:THREE]'))
+ end)
+ end)
+end)
diff --git a/test/functional/eval/environ_spec.lua b/test/functional/eval/environ_spec.lua
new file mode 100644
index 0000000000..4c2adcf1bf
--- /dev/null
+++ b/test/functional/eval/environ_spec.lua
@@ -0,0 +1,18 @@
+local helpers = require('test.functional.helpers')(after_each)
+local clear = helpers.clear
+local eq = helpers.eq
+local environ = helpers.funcs.environ
+local exists = helpers.funcs.exists
+
+describe('environment variables', function()
+ it('environ() handles empty env variable', function()
+ clear({env={EMPTY_VAR=""}})
+ eq("", environ()['EMPTY_VAR'])
+ eq(nil, environ()['DOES_NOT_EXIST'])
+ end)
+ it('exists() handles empty env variable', function()
+ clear({env={EMPTY_VAR=""}})
+ eq(1, exists('$EMPTY_VAR'))
+ eq(0, exists('$DOES_NOT_EXIST'))
+ end)
+end)
diff --git a/test/functional/eval/executable_spec.lua b/test/functional/eval/executable_spec.lua
index 6a95128a4d..a1cf056907 100644
--- a/test/functional/eval/executable_spec.lua
+++ b/test/functional/eval/executable_spec.lua
@@ -2,6 +2,7 @@ local helpers = require('test.functional.helpers')(after_each)
local eq, clear, call, iswin, write_file, command =
helpers.eq, helpers.clear, helpers.call, helpers.iswin, helpers.write_file,
helpers.command
+local eval = helpers.eval
describe('executable()', function()
before_each(clear)
@@ -21,15 +22,10 @@ describe('executable()', function()
-- Windows: siblings are in Nvim's "pseudo-$PATH".
local expected = iswin() and 1 or 0
if iswin() then
- -- $PATH on AppVeyor CI might be oversized, redefine it to a minimal one.
- clear({env={PATH=[[C:\Windows\system32;C:\Windows]]}})
eq('arg1=lemon;arg2=sky;arg3=tree;',
call('system', sibling_exe..' lemon sky tree'))
end
- local is_executable = call('executable', sibling_exe)
- if iswin() and is_executable ~= expected then
- pending('XXX: sometimes fails on AppVeyor')
- end
+ eq(expected, call('executable', sibling_exe))
end)
describe('exec-bit', function()
@@ -100,10 +96,16 @@ describe('executable() (Windows)', function()
eq(0, call('executable', '.\\test_executable_zzz'))
end)
+ it('system([…]), jobstart([…]) use $PATHEXT #9569', function()
+ -- Invoking `cmdscript` should find/execute `cmdscript.cmd`.
+ eq('much success\n', call('system', {'test/functional/fixtures/cmdscript'}))
+ assert(0 < call('jobstart', {'test/functional/fixtures/cmdscript'}))
+ end)
+
it('full path with extension', function()
-- Some executable we can expect in the test env.
local exe = 'printargs-test'
- local exedir = helpers.eval("fnamemodify(v:progpath, ':h')")
+ local exedir = eval("fnamemodify(v:progpath, ':h')")
local exepath = exedir..'/'..exe..'.exe'
eq(1, call('executable', exepath))
eq('arg1=lemon;arg2=sky;arg3=tree;',
@@ -113,7 +115,7 @@ describe('executable() (Windows)', function()
it('full path without extension', function()
-- Some executable we can expect in the test env.
local exe = 'printargs-test'
- local exedir = helpers.eval("fnamemodify(v:progpath, ':h')")
+ local exedir = eval("fnamemodify(v:progpath, ':h')")
local exepath = exedir..'/'..exe
eq('arg1=lemon;arg2=sky;arg3=tree;',
call('system', exepath..' lemon sky tree'))
diff --git a/test/functional/eval/reltime_spec.lua b/test/functional/eval/reltime_spec.lua
index 0181f09024..d87943e485 100644
--- a/test/functional/eval/reltime_spec.lua
+++ b/test/functional/eval/reltime_spec.lua
@@ -6,7 +6,7 @@ local reltime, reltimestr, reltimefloat = funcs.reltime, funcs.reltimestr, funcs
describe('reltimestr(), reltimefloat()', function()
before_each(clear)
- it('Checks', function()
+ it('acceptance', function()
local now = reltime()
command('sleep 10m')
local later = reltime()
@@ -31,6 +31,23 @@ describe('reltimestr(), reltimefloat()', function()
-- original vim test for < 0.1, but easily fails on travis
ok(nil ~= string.match(reltimestr(differs), "0%."))
ok(reltimefloat(differs) < 1.0)
+ end)
+
+ it('(start - end) returns negative #10452', function()
+ local older_time = reltime()
+ command('sleep 1m')
+ local newer_time = reltime()
+
+ -- Start/end swapped: should be something like -0.002123.
+ local tm_s = tonumber(reltimestr(reltime(newer_time, older_time)))
+ local tm_f = reltimefloat(reltime(newer_time, older_time))
+ ok(tm_s < 0 and tm_s > -10)
+ ok(tm_f < 0 and tm_f > -10)
+ -- Not swapped: should be something like 0.002123.
+ tm_s = tonumber(reltimestr(reltime(older_time, newer_time)))
+ tm_f = reltimefloat(reltime(older_time, newer_time))
+ ok(tm_s > 0 and tm_s < 10)
+ ok(tm_f > 0 and tm_f < 10)
end)
end)
diff --git a/test/functional/eval/system_spec.lua b/test/functional/eval/system_spec.lua
index 5cbf34365b..13134bc6e7 100644
--- a/test/functional/eval/system_spec.lua
+++ b/test/functional/eval/system_spec.lua
@@ -203,12 +203,15 @@ describe('system()', function()
end)
it('prints verbose information', function()
+ nvim('set_option', 'shell', 'fake_shell')
+ nvim('set_option', 'shellcmdflag', 'cmdflag')
+
screen:try_resize(72, 14)
feed(':4verbose echo system("echo hi")<cr>')
if iswin() then
- screen:expect{any=[[Executing command: "'cmd.exe' '/s' '/c' '"echo hi"'"]]}
+ screen:expect{any=[[Executing command: "'fake_shell' 'cmdflag' '"echo hi"'"]]}
else
- screen:expect{any=[[Executing command: "'/[^']*sh' '%-c' 'echo hi'"]]}
+ screen:expect{any=[[Executing command: "'fake_shell' 'cmdflag' 'echo hi'"]]}
end
feed('<cr>')
end)
@@ -272,7 +275,7 @@ describe('system()', function()
~ |
~ |
~ |
- Type :qa! and press <E...all changes and exit Nvim |
+ Type :qa and press <Enter> to exit Nvim |
]])
end)
end)
@@ -478,7 +481,7 @@ describe('systemlist()', function()
~ |
~ |
~ |
- Type :qa! and press <E...all changes and exit Nvim |
+ Type :qa and press <Enter> to exit Nvim |
]])
end)
end)
diff --git a/test/functional/eval/timer_spec.lua b/test/functional/eval/timer_spec.lua
index 14f3c29fb7..cd099e30ed 100644
--- a/test/functional/eval/timer_spec.lua
+++ b/test/functional/eval/timer_spec.lua
@@ -5,6 +5,7 @@ local source, nvim_async, run = helpers.source, helpers.nvim_async, helpers.run
local clear, command, funcs = helpers.clear, helpers.command, helpers.funcs
local curbufmeths = helpers.curbufmeths
local load_adjust = helpers.load_adjust
+local retry = helpers.retry
describe('timers', function()
before_each(function()
@@ -161,10 +162,12 @@ describe('timers', function()
endif
endfunc
]])
- command("call timer_start(50, 'MyHandler', {'repeat': -1})")
+ command("call timer_start(10, 'MyHandler', {'repeat': -1})")
eq(0,eval("g:val"))
- run(nil, nil, nil, load_adjust(300))
- eq(3,eval("g:val"))
+ run(nil, nil, nil, load_adjust(50))
+ retry(nil, 5000, function()
+ eq(3, eval("g:val"))
+ end)
end)
it('can have two timers', function()
@@ -225,7 +228,7 @@ describe('timers', function()
{0:~ }|
{0:~ }|
:good^ |
- ]], intermediate=true, timeout=200}
+ ]], intermediate=true, timeout=1000}
eq(1, eval('g:val'))
end)
diff --git a/test/functional/ex_cmds/arg_spec.lua b/test/functional/ex_cmds/arg_spec.lua
index 6d31f05c2a..4dea50b53e 100644
--- a/test/functional/ex_cmds/arg_spec.lua
+++ b/test/functional/ex_cmds/arg_spec.lua
@@ -22,7 +22,7 @@ describe(":argument", function()
local bufname_after = funcs.bufname("%")
local bufnr_after = funcs.bufnr("%")
- eq("\n["..bufname_before.."] ", helpers.eval('execute("args")'))
+ eq("["..bufname_before.."]", helpers.eval('trim(execute("args"))'))
ok(funcs.line('$') > 1)
eq(bufname_before, bufname_after)
eq(bufnr_before, bufnr_after)
diff --git a/test/functional/ex_cmds/ctrl_c_spec.lua b/test/functional/ex_cmds/ctrl_c_spec.lua
index 4c5383b712..f65d9f0d01 100644
--- a/test/functional/ex_cmds/ctrl_c_spec.lua
+++ b/test/functional/ex_cmds/ctrl_c_spec.lua
@@ -11,7 +11,7 @@ describe("CTRL-C (mapped)", function()
it("interrupts :global", function()
-- Crashes luajit.
if helpers.skip_fragile(pending,
- os.getenv("TRAVIS") or os.getenv("APPVEYOR")) then
+ helpers.isCI('travis') or helpers.isCI('appveyor')) then
return
end
diff --git a/test/functional/ex_cmds/digraphs_spec.lua b/test/functional/ex_cmds/digraphs_spec.lua
index 37d3814136..5de2adc191 100644
--- a/test/functional/ex_cmds/digraphs_spec.lua
+++ b/test/functional/ex_cmds/digraphs_spec.lua
@@ -1,5 +1,6 @@
local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
+local command = helpers.command
local feed = helpers.feed
local Screen = require('test.functional.ui.screen')
@@ -21,18 +22,17 @@ describe(':digraphs', function()
end)
it('displays digraphs', function()
+ command('set more')
feed(':digraphs<CR>')
screen:expect([[
- E` {6:È} 200 E^ {6:Ê} 202 E" {6:Ë} 203 I` {6:Ì} 204 I^ {6:Î} 206 |
- I" {6:Ã} 207 N~ {6:Ñ} 209 O` {6:Ã’} 210 O^ {6:Ô} 212 O~ {6:Õ} 213 |
- /\ {6:×} 215 U` {6:Ù} 217 U^ {6:Û} 219 Ip {6:Þ} 222 a` {6:à} 224 |
- a^ {6:â} 226 a~ {6:ã} 227 a" {6:ä} 228 a@ {6:å} 229 e` {6:è} 232 |
- e^ {6:ê} 234 e" {6:ë} 235 i` {6:ì} 236 i^ {6:î} 238 n~ {6:ñ} 241 |
- o` {6:ò} 242 o^ {6:ô} 244 o~ {6:õ} 245 u` {6:ù} 249 u^ {6:û} 251 |
- y" {6:ÿ} 255 |
- {3:Press ENTER or type command to continue}^ |
+ :digraphs |
+ NU {6:^@} 10 SH {6:^A} 1 SX {6:^B} 2 EX {6:^C} 3 ET {6:^D} 4 |
+ EQ {6:^E} 5 AK {6:^F} 6 BL {6:^G} 7 BS {6:^H} 8 HT {6:^I} 9 |
+ LF {6:^@} 10 VT {6:^K} 11 FF {6:^L} 12 CR {6:^M} 13 SO {6:^N} 14 |
+ SI {6:^O} 15 DL {6:^P} 16 D1 {6:^Q} 17 D2 {6:^R} 18 D3 {6:^S} 19 |
+ D4 {6:^T} 20 NK {6:^U} 21 SY {6:^V} 22 EB {6:^W} 23 CN {6:^X} 24 |
+ EM {6:^Y} 25 SB {6:^Z} 26 EC {6:^[} 27 FS {6:^\} 28 GS {6:^]} 29 |
+ {3:-- More --}^ |
]])
end)
-
end)
-
diff --git a/test/functional/ex_cmds/ls_spec.lua b/test/functional/ex_cmds/ls_spec.lua
new file mode 100644
index 0000000000..f7bacd7386
--- /dev/null
+++ b/test/functional/ex_cmds/ls_spec.lua
@@ -0,0 +1,37 @@
+local helpers = require('test.functional.helpers')(after_each)
+local clear = helpers.clear
+local command = helpers.command
+local eq = helpers.eq
+local eval = helpers.eval
+local feed = helpers.feed
+local nvim = helpers.nvim
+local nvim_dir = helpers.nvim_dir
+local retry = helpers.retry
+
+describe(':ls', function()
+ before_each(function()
+ clear()
+ end)
+
+ it('R, F for :terminal buffers', function()
+ nvim('set_option', 'shell', string.format('"%s" INTERACT', nvim_dir..'/shell-test'))
+
+ command('edit foo')
+ command('set hidden')
+ command('terminal')
+ command('vsplit')
+ command('terminal')
+ feed('iexit<cr>')
+ retry(nil, 5000, function()
+ local ls_output = eval('execute("ls")')
+ -- Normal buffer.
+ eq('\n 1 h ', string.match(ls_output, '\n *1....'))
+ -- Terminal buffer [R]unning.
+ eq('\n 2 #aR', string.match(ls_output, '\n *2....'))
+ -- Terminal buffer [F]inished.
+ eq('\n 3 %aF', string.match(ls_output, '\n *3....'))
+ end)
+ end)
+
+end)
+
diff --git a/test/functional/ex_cmds/menu_spec.lua b/test/functional/ex_cmds/menu_spec.lua
index 2309e949c0..0cd32df27c 100644
--- a/test/functional/ex_cmds/menu_spec.lua
+++ b/test/functional/ex_cmds/menu_spec.lua
@@ -83,7 +83,7 @@ describe('menu_get', function()
it("path='', modes='a'", function()
local m = funcs.menu_get("","a");
-- HINT: To print the expected table and regenerate the tests:
- -- print(require('inspect')(m))
+ -- print(require('vim.inspect')(m))
local expected = {
{
shortcut = "T",
diff --git a/test/functional/fixtures/autoload/provider/clipboard.vim b/test/functional/fixtures/autoload/provider/clipboard.vim
index 6d777255c8..41e486b745 100644
--- a/test/functional/fixtures/autoload/provider/clipboard.vim
+++ b/test/functional/fixtures/autoload/provider/clipboard.vim
@@ -1,3 +1,5 @@
+let g:loaded_clipboard_provider = 2
+
let g:test_clip = { '+': [''], '*': [''], }
let s:methods = {}
@@ -35,7 +37,6 @@ function! s:methods.set(lines, regtype, reg)
let g:test_clip[a:reg] = [a:lines, a:regtype]
endfunction
-
function! provider#clipboard#Call(method, args)
return call(s:methods[a:method],a:args,s:methods)
endfunction
diff --git a/test/functional/fixtures/autoload/provider/python.vim b/test/functional/fixtures/autoload/provider/python.vim
new file mode 100644
index 0000000000..d68360ac30
--- /dev/null
+++ b/test/functional/fixtures/autoload/provider/python.vim
@@ -0,0 +1,6 @@
+" Dummy test provider, missing this required variable:
+" let g:loaded_brokenenabled_provider = 0
+
+function! provider#python#Call(method, args)
+ return 42
+endfunction
diff --git a/test/functional/fixtures/autoload/provider/ruby.vim b/test/functional/fixtures/autoload/provider/ruby.vim
new file mode 100644
index 0000000000..35becc27ff
--- /dev/null
+++ b/test/functional/fixtures/autoload/provider/ruby.vim
@@ -0,0 +1,2 @@
+" A dummy test provider
+let g:loaded_ruby_provider = 2
diff --git a/test/functional/fixtures/cmdscript.cmd b/test/functional/fixtures/cmdscript.cmd
new file mode 100644
index 0000000000..b680d24900
--- /dev/null
+++ b/test/functional/fixtures/cmdscript.cmd
@@ -0,0 +1,2 @@
+@echo off
+echo much success
diff --git a/test/functional/fixtures/compdir/file1 b/test/functional/fixtures/compdir/file1
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/functional/fixtures/compdir/file1
diff --git a/test/functional/fixtures/compdir/file2 b/test/functional/fixtures/compdir/file2
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/functional/fixtures/compdir/file2
diff --git a/test/functional/fixtures/shell-test.c b/test/functional/fixtures/shell-test.c
index a744d5df46..550e5dd997 100644
--- a/test/functional/fixtures/shell-test.c
+++ b/test/functional/fixtures/shell-test.c
@@ -11,10 +11,10 @@
#include <unistd.h>
#endif
-static void wait(void)
+static void flush_wait(void)
{
fflush(stdout);
- usleep(10*1000);
+ usleep(10*1000); // Wait 10 ms.
}
static void help(void)
@@ -33,13 +33,16 @@ static void help(void)
puts(" Prints \"ready $ prog args...\\n\" to stderr.");
puts(" shell-test -t {prompt text} EXE \"prog args...\"");
puts(" Prints \"{prompt text} $ progs args...\" to stderr.");
- puts(" shell-test REP {byte} \"line line line\"");
- puts(" Prints \"{lnr}: line line line\\n\" to stdout {byte} times.");
- puts(" I.e. for `shell-test REP ab \"test\"'");
- puts(" 0: test");
+ puts(" shell-test REP N {text}");
+ puts(" Prints \"{lnr}: {text}\\n\" to stdout N times, taking N milliseconds.");
+ puts(" Example:");
+ puts(" shell-test REP 97 \"foo bar\"");
+ puts(" 0: foo bar");
puts(" ...");
- puts(" 96: test");
- puts(" will be printed because byte `a' is equal to 97.");
+ puts(" 96: foo bar");
+ puts(" shell-test REP_NODELAY N {text}");
+ puts(" shell-test INTERACT");
+ puts(" Prints \"interact $ \" to stderr, and waits for \"exit\" input.");
}
int main(int argc, char **argv)
@@ -64,35 +67,73 @@ int main(int argc, char **argv)
if (argc >= 3) {
fprintf(stderr, "%s\n", argv[2]);
}
- } else if (strcmp(argv[1], "REP") == 0) {
- if (argc < 4) {
- fprintf(stderr, "Not enough REP arguments\n");
+ } else if (strcmp(argv[1], "REP") == 0 ||
+ strcmp(argv[1], "REP_NODELAY") == 0) {
+ if (argc != 4) {
+ fprintf(stderr, "REP expects exactly 3 arguments\n");
return 4;
}
- uint8_t number = (uint8_t) *argv[2];
- for (uint8_t i = 0; i < number; i++) {
- printf("%d: %s\n", (int) i, argv[3]);
+ int count = 0;
+ if (sscanf(argv[2], "%d", &count) != 1) {
+ fprintf(stderr, "Invalid count: %s\n", argv[2]);
+ return 4;
+ }
+ if (strcmp(argv[1], "REP_NODELAY") == 0) {
+ for (int i = 0; i < count; i++) {
+ printf("%d: %s\n", i, argv[3]);
+ fflush(stdout);
+ }
+ } else {
+ for (int i = 0; i < count; i++) {
+ printf("%d: %s\n", i, argv[3]);
+ fflush(stdout);
+ usleep(1000); // Wait 1 ms (simulate typical output).
+ }
}
} else if (strcmp(argv[1], "UTF-8") == 0) {
// test split-up UTF-8 sequence
- printf("\xc3"); wait();
- printf("\xa5\n"); wait();
+ printf("\xc3"); flush_wait();
+ printf("\xa5\n"); flush_wait();
// split up a 2+2 grapheme clusters all possible ways
- printf("ref: \xc3\xa5\xcc\xb2\n"); wait();
+ printf("ref: \xc3\xa5\xcc\xb2\n"); flush_wait();
+
+ printf("1: \xc3"); flush_wait();
+ printf("\xa5\xcc\xb2\n"); flush_wait();
- printf("1: \xc3"); wait();
- printf("\xa5\xcc\xb2\n"); wait();
+ printf("2: \xc3\xa5"); flush_wait();
+ printf("\xcc\xb2\n"); flush_wait();
- printf("2: \xc3\xa5"); wait();
- printf("\xcc\xb2\n"); wait();
+ printf("3: \xc3\xa5\xcc"); flush_wait();
+ printf("\xb2\n"); flush_wait();
+ } else if (strcmp(argv[1], "INTERACT") == 0) {
+ char input[256];
+ char cmd[100];
+ int arg;
+ int input_argc;
- printf("3: \xc3\xa5\xcc"); wait();
- printf("\xb2\n"); wait();
+ while (1) {
+ fprintf(stderr, "interact $ ");
+
+ if (fgets(input, sizeof(input), stdin) == NULL) {
+ break; // EOF
+ }
+
+ input_argc = sscanf(input, "%99s %d", cmd, &arg);
+ if(1 == input_argc) {
+ arg = 0;
+ }
+ if (strcmp(cmd, "exit") == 0) {
+ return arg;
+ } else {
+ fprintf(stderr, "command not found: %s\n", cmd);
+ }
+ }
} else {
- fprintf(stderr, "Unknown first argument\n");
+ fprintf(stderr, "Unknown first argument: %s\n", argv[1]);
return 3;
}
+ fflush(stdout);
return 0;
} else if (argc == 1) {
fprintf(stderr, "ready $ ");
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index cf4c7ce9b7..d4ace3030c 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -1,6 +1,7 @@
require('coxpcall')
local luv = require('luv')
local lfs = require('lfs')
+local mpack = require('mpack')
local global_helpers = require('test.helpers')
-- nvim client: Found in .deps/usr/share/lua/<version>/nvim/ if "bundled".
@@ -13,31 +14,39 @@ local check_cores = global_helpers.check_cores
local check_logs = global_helpers.check_logs
local dedent = global_helpers.dedent
local eq = global_helpers.eq
+local filter = global_helpers.filter
+local map = global_helpers.map
local ok = global_helpers.ok
local sleep = global_helpers.sleep
local tbl_contains = global_helpers.tbl_contains
local write_file = global_helpers.write_file
+local module = {
+ NIL = mpack.NIL,
+ mkdir = lfs.mkdir,
+}
+
local start_dir = lfs.currentdir()
-- XXX: NVIM_PROG takes precedence, QuickBuild sets it.
-local nvim_prog = (
+module.nvim_prog = (
os.getenv('NVIM_PROG')
or os.getenv('NVIM_PRG')
or global_helpers.test_build_dir .. '/bin/nvim'
)
-- Default settings for the test session.
-local nvim_set = 'set shortmess+=IS background=light noswapfile noautoindent'
- ..' laststatus=1 undodir=. directory=. viewdir=. backupdir=.'
- ..' belloff= noshowcmd noruler nomore'
-local nvim_argv = {nvim_prog, '-u', 'NONE', '-i', 'NONE',
- '--cmd', nvim_set, '--embed'}
+module.nvim_set = (
+ 'set shortmess+=IS background=light noswapfile noautoindent'
+ ..' laststatus=1 undodir=. directory=. viewdir=. backupdir=.'
+ ..' belloff= wildoptions-=pum noshowcmd noruler nomore')
+module.nvim_argv = {
+ module.nvim_prog, '-u', 'NONE', '-i', 'NONE',
+ '--cmd', module.nvim_set, '--embed'}
-- Directory containing nvim.
-local nvim_dir = nvim_prog:gsub("[/\\][^/\\]+$", "")
-if nvim_dir == nvim_prog then
- nvim_dir = "."
+module.nvim_dir = module.nvim_prog:gsub("[/\\][^/\\]+$", "")
+if module.nvim_dir == module.nvim_prog then
+ module.nvim_dir = "."
end
-local mpack = require('mpack')
local tmpname = global_helpers.tmpname
local uname = global_helpers.uname
local prepend_argv
@@ -67,26 +76,27 @@ if prepend_argv then
for i = 1, len do
new_nvim_argv[i] = prepend_argv[i]
end
- for i = 1, #nvim_argv do
- new_nvim_argv[i + len] = nvim_argv[i]
+ for i = 1, #module.nvim_argv do
+ new_nvim_argv[i + len] = module.nvim_argv[i]
end
- nvim_argv = new_nvim_argv
+ module.nvim_argv = new_nvim_argv
+ module.prepend_argv = prepend_argv
end
local session, loop_running, last_error, method_error
-local function get_session()
+function module.get_session()
return session
end
-local function set_session(s, keep)
+function module.set_session(s, keep)
if session and not keep then
session:close()
end
session = s
end
-local function request(method, ...)
+function module.request(method, ...)
local status, rv = session:request(method, ...)
if not status then
if loop_running then
@@ -99,14 +109,14 @@ local function request(method, ...)
return rv
end
-local function next_msg(timeout)
+function module.next_msg(timeout)
return session:next_message(timeout and timeout or 10000)
end
-local function expect_twostreams(msgs1, msgs2)
+function module.expect_twostreams(msgs1, msgs2)
local pos1, pos2 = 1, 1
while pos1 <= #msgs1 or pos2 <= #msgs2 do
- local msg = next_msg()
+ local msg = module.next_msg()
if pos1 <= #msgs1 and pcall(eq, msgs1[pos1], msg) then
pos1 = pos1 + 1
elseif pos2 <= #msgs2 then
@@ -129,7 +139,7 @@ end
--
-- ignore: List of ignored event names.
-- seqs: List of one or more potential event sequences.
-local function expect_msg_seq(...)
+function module.expect_msg_seq(...)
if select('#', ...) < 1 then
error('need at least 1 argument')
end
@@ -155,11 +165,12 @@ local function expect_msg_seq(...)
end
return string.format('%s\n%s\n%s', err1, string.rep('=', 78), err2)
end
+ local msg_timeout = module.load_adjust(10000) -- Big timeout for ASAN/valgrind.
for anum = 1, #seqs do
local expected_seq = seqs[anum]
-- Collect enough messages to compare the next expected sequence.
while #actual_seq < #expected_seq do
- local msg = next_msg(10000) -- Big timeout for ASAN/valgrind.
+ local msg = module.next_msg(msg_timeout)
local msg_type = msg and msg[2] or nil
if msg == nil then
error(cat_err(final_error,
@@ -190,11 +201,11 @@ local function call_and_stop_on_error(lsession, ...)
return result
end
-local function set_method_error(err)
+function module.set_method_error(err)
method_error = err
end
-local function run_session(lsession, request_cb, notification_cb, setup_cb, timeout)
+function module.run_session(lsession, request_cb, notification_cb, setup_cb, timeout)
local on_request, on_notification, on_setup
if request_cb then
@@ -230,43 +241,43 @@ local function run_session(lsession, request_cb, notification_cb, setup_cb, time
end
end
-local function run(request_cb, notification_cb, setup_cb, timeout)
- run_session(session, request_cb, notification_cb, setup_cb, timeout)
+function module.run(request_cb, notification_cb, setup_cb, timeout)
+ module.run_session(session, request_cb, notification_cb, setup_cb, timeout)
end
-local function stop()
+function module.stop()
session:stop()
end
-local function nvim_prog_abs()
+function module.nvim_prog_abs()
-- system(['build/bin/nvim']) does not work for whatever reason. It must
-- be executable searched in $PATH or something starting with / or ./.
- if nvim_prog:match('[/\\]') then
- return request('nvim_call_function', 'fnamemodify', {nvim_prog, ':p'})
+ if module.nvim_prog:match('[/\\]') then
+ return module.request('nvim_call_function', 'fnamemodify', {module.nvim_prog, ':p'})
else
- return nvim_prog
+ return module.nvim_prog
end
end
-- Executes an ex-command. VimL errors manifest as client (lua) errors, but
-- v:errmsg will not be updated.
-local function nvim_command(cmd)
- request('nvim_command', cmd)
+function module.command(cmd)
+ module.request('nvim_command', cmd)
end
-- Evaluates a VimL expression.
-- Fails on VimL error, but does not update v:errmsg.
-local function nvim_eval(expr)
- return request('nvim_eval', expr)
+function module.eval(expr)
+ return module.request('nvim_eval', expr)
end
-local os_name = (function()
+module.os_name = (function()
local name = nil
return (function()
if not name then
- if nvim_eval('has("win32")') == 1 then
+ if module.eval('has("win32")') == 1 then
name = 'windows'
- elseif nvim_eval('has("macunix")') == 1 then
+ elseif module.eval('has("macunix")') == 1 then
name = 'osx'
else
name = 'unix'
@@ -276,38 +287,38 @@ local os_name = (function()
end)
end)()
-local function iswin()
+function module.iswin()
return package.config:sub(1,1) == '\\'
end
-- Executes a VimL function.
-- Fails on VimL error, but does not update v:errmsg.
-local function nvim_call(name, ...)
- return request('nvim_call_function', name, {...})
+function module.call(name, ...)
+ return module.request('nvim_call_function', name, {...})
end
-- Sends user input to Nvim.
-- Does not fail on VimL error, but v:errmsg will be updated.
local function nvim_feed(input)
while #input > 0 do
- local written = request('nvim_input', input)
+ local written = module.request('nvim_input', input)
input = input:sub(written + 1)
end
end
-local function feed(...)
+function module.feed(...)
for _, v in ipairs({...}) do
nvim_feed(dedent(v))
end
end
-local function rawfeed(...)
+function module.rawfeed(...)
for _, v in ipairs({...}) do
nvim_feed(dedent(v))
end
end
-local function merge_args(...)
+function module.merge_args(...)
local i = 1
local argv = {}
for anum = 1,select('#', ...) do
@@ -359,15 +370,15 @@ local function remove_args(args, args_rm)
return new_args
end
-local function spawn(argv, merge, env)
+function module.spawn(argv, merge, env)
local child_stream = ChildProcessStream.spawn(
- merge and merge_args(prepend_argv, argv) or argv,
+ merge and module.merge_args(prepend_argv, argv) or argv,
env)
return Session.new(child_stream)
end
-- Creates a new Session connected by domain socket (named pipe) or TCP.
-local function connect(file_or_address)
+function module.connect(file_or_address)
local addr, port = string.match(file_or_address, "(.*):(%d+)")
local stream = (addr and port) and TcpStream.open(addr, port) or
SocketStream.open(file_or_address)
@@ -376,7 +387,7 @@ end
-- Calls fn() until it succeeds, up to `max` times or until `max_ms`
-- milliseconds have passed.
-local function retry(max, max_ms, fn)
+function module.retry(max, max_ms, fn)
assert(max == nil or max > 0)
assert(max_ms == nil or max_ms > 0)
local tries = 1
@@ -408,8 +419,16 @@ end
-- Example:
-- clear('-e')
-- clear{args={'-e'}, args_rm={'-i'}, env={TERM=term}}
-local function clear(...)
- local args = {unpack(nvim_argv)}
+function module.clear(...)
+ local argv, env = module.new_argv(...)
+ module.set_session(module.spawn(argv, nil, env))
+end
+
+-- Builds an argument list for use in clear().
+--
+--@see clear() for parameters.
+function module.new_argv(...)
+ local args = {unpack(module.nvim_argv)}
table.insert(args, '--headless')
local new_args
local env = nil
@@ -430,6 +449,7 @@ local function clear(...)
'PATH',
'NVIM_LOG_FILE',
'NVIM_RPLUGIN_MANIFEST',
+ 'GCOV_ERROR_FILE',
}) do
if not env_tbl[k] then
env_tbl[k] = os.getenv(k)
@@ -447,21 +467,21 @@ local function clear(...)
for _, arg in ipairs(new_args) do
table.insert(args, arg)
end
- set_session(spawn(args, nil, env))
+ return args, env
end
-local function insert(...)
+function module.insert(...)
nvim_feed('i')
for _, v in ipairs({...}) do
local escaped = v:gsub('<', '<lt>')
- rawfeed(escaped)
+ module.rawfeed(escaped)
end
nvim_feed('<ESC>')
end
-- Executes an ex-command by user input. Because nvim_input() is used, VimL
-- errors will not manifest as client (lua) errors. Use command() for that.
-local function feed_command(...)
+function module.feed_command(...)
for _, v in ipairs({...}) do
if v:sub(1, 1) ~= '/' then
-- not a search command, prefix with colon
@@ -473,10 +493,10 @@ local function feed_command(...)
end
local sourced_fnames = {}
-local function source(code)
+function module.source(code)
local fname = tmpname()
write_file(fname, code)
- nvim_command('source '..fname)
+ module.command('source '..fname)
-- DO NOT REMOVE FILE HERE.
-- do_source() has a habit of checking whether files are “same†by using inode
-- and device IDs. If you run two source() calls in quick succession there is
@@ -492,76 +512,76 @@ local function source(code)
return fname
end
-local function set_shell_powershell()
- source([[
+function module.set_shell_powershell()
+ module.source([[
set shell=powershell shellquote=( shellpipe=\| shellredir=> shellxquote=
- let &shellcmdflag = '-NoLogo -NoProfile -ExecutionPolicy RemoteSigned -Command Remove-Item -Force alias:sleep;'
+ let &shellcmdflag = '-NoLogo -NoProfile -ExecutionPolicy RemoteSigned -Command Remove-Item -Force alias:sleep; Remove-Item -Force alias:cat;'
]])
end
-local function nvim(method, ...)
- return request('nvim_'..method, ...)
+function module.nvim(method, ...)
+ return module.request('nvim_'..method, ...)
end
local function ui(method, ...)
- return request('nvim_ui_'..method, ...)
+ return module.request('nvim_ui_'..method, ...)
end
-local function nvim_async(method, ...)
+function module.nvim_async(method, ...)
session:notify('nvim_'..method, ...)
end
-local function buffer(method, ...)
- return request('nvim_buf_'..method, ...)
+function module.buffer(method, ...)
+ return module.request('nvim_buf_'..method, ...)
end
-local function window(method, ...)
- return request('nvim_win_'..method, ...)
+function module.window(method, ...)
+ return module.request('nvim_win_'..method, ...)
end
-local function tabpage(method, ...)
- return request('nvim_tabpage_'..method, ...)
+function module.tabpage(method, ...)
+ return module.request('nvim_tabpage_'..method, ...)
end
-local function curbuf(method, ...)
+function module.curbuf(method, ...)
if not method then
- return nvim('get_current_buf')
+ return module.nvim('get_current_buf')
end
- return buffer(method, 0, ...)
+ return module.buffer(method, 0, ...)
end
-local function wait()
+function module.wait()
-- Execute 'nvim_eval' (a deferred function) to block
-- until all pending input is processed.
session:request('nvim_eval', '1')
end
-local function curbuf_contents()
- wait() -- Before inspecting the buffer, process all input.
- return table.concat(curbuf('get_lines', 0, -1, true), '\n')
+function module.curbuf_contents()
+ module.wait() -- Before inspecting the buffer, process all input.
+ return table.concat(module.curbuf('get_lines', 0, -1, true), '\n')
end
-local function curwin(method, ...)
+function module.curwin(method, ...)
if not method then
- return nvim('get_current_win')
+ return module.nvim('get_current_win')
end
- return window(method, 0, ...)
+ return module.window(method, 0, ...)
end
-local function curtab(method, ...)
+function module.curtab(method, ...)
if not method then
- return nvim('get_current_tabpage')
+ return module.nvim('get_current_tabpage')
end
- return tabpage(method, 0, ...)
+ return module.tabpage(method, 0, ...)
end
-local function expect(contents)
- return eq(dedent(contents), curbuf_contents())
+function module.expect(contents)
+ return eq(dedent(contents), module.curbuf_contents())
end
-local function expect_any(contents)
+function module.expect_any(contents)
contents = dedent(contents)
- return ok(nil ~= string.find(curbuf_contents(), contents, 1, true))
+ return ok(nil ~= string.find(module.curbuf_contents(), contents, 1, true))
end
local function do_rmdir(path)
@@ -581,8 +601,8 @@ local function do_rmdir(path)
else
-- Try Nvim delete(): it handles `readonly` attribute on Windows,
-- and avoids Lua cross-version/platform incompatibilities.
- if -1 == nvim_call('delete', abspath) then
- local hint = (os_name() == 'windows'
+ if -1 == module.call('delete', abspath) then
+ local hint = (module.os_name() == 'windows'
and ' (hint: try :%bwipeout! before rmdir())' or '')
error('delete() failed'..hint..': '..abspath)
end
@@ -597,12 +617,12 @@ local function do_rmdir(path)
end
end
-local function rmdir(path)
+function module.rmdir(path)
local ret, _ = pcall(do_rmdir, path)
- if not ret and os_name() == "windows" then
+ if not ret and module.os_name() == "windows" then
-- Maybe "Permission denied"; try again after changing the nvim
-- process to the top-level directory.
- nvim_command([[exe 'cd '.fnameescape(']]..start_dir.."')")
+ module.command([[exe 'cd '.fnameescape(']]..start_dir.."')")
ret, _ = pcall(do_rmdir, path)
end
-- During teardown, the nvim process may not exit quickly enough, then rmdir()
@@ -613,20 +633,20 @@ local function rmdir(path)
end
end
-local exc_exec = function(cmd)
- nvim_command(([[
+function module.exc_exec(cmd)
+ module.command(([[
try
execute "%s"
catch
let g:__exception = v:exception
endtry
]]):format(cmd:gsub('\n', '\\n'):gsub('[\\"]', '\\%0')))
- local ret = nvim_eval('get(g:, "__exception", 0)')
- nvim_command('unlet! g:__exception')
+ local ret = module.eval('get(g:, "__exception", 0)')
+ module.command('unlet! g:__exception')
return ret
end
-local function create_callindex(func)
+function module.create_callindex(func)
local table = {}
setmetatable(table, {
__index = function(tbl, arg1)
@@ -640,7 +660,7 @@ end
-- Helper to skip tests. Returns true in Windows systems.
-- pending_fn is pending() from busted
-local function pending_win32(pending_fn)
+function module.pending_win32(pending_fn)
if uname() == 'Windows' then
if pending_fn ~= nil then
pending_fn('FIXME: Windows', function() end)
@@ -653,7 +673,7 @@ end
-- Calls pending() and returns `true` if the system is too slow to
-- run fragile or expensive tests. Else returns `false`.
-local function skip_fragile(pending_fn, cond)
+function module.skip_fragile(pending_fn, cond)
if pending_fn == nil or type(pending_fn) ~= type(function()end) then
error("invalid pending_fn")
end
@@ -667,7 +687,7 @@ local function skip_fragile(pending_fn, cond)
return false
end
-local function meth_pcall(...)
+function module.meth_pcall(...)
local ret = {pcall(...)}
if type(ret[2]) == 'string' then
ret[2] = ret[2]:gsub('^[^:]+:%d+: ', '')
@@ -675,62 +695,66 @@ local function meth_pcall(...)
return ret
end
-local funcs = create_callindex(nvim_call)
-local meths = create_callindex(nvim)
-local uimeths = create_callindex(ui)
-local bufmeths = create_callindex(buffer)
-local winmeths = create_callindex(window)
-local tabmeths = create_callindex(tabpage)
-local curbufmeths = create_callindex(curbuf)
-local curwinmeths = create_callindex(curwin)
-local curtabmeths = create_callindex(curtab)
+module.funcs = module.create_callindex(module.call)
+module.meths = module.create_callindex(module.nvim)
+module.uimeths = module.create_callindex(ui)
+module.bufmeths = module.create_callindex(module.buffer)
+module.winmeths = module.create_callindex(module.window)
+module.tabmeths = module.create_callindex(module.tabpage)
+module.curbufmeths = module.create_callindex(module.curbuf)
+module.curwinmeths = module.create_callindex(module.curwin)
+module.curtabmeths = module.create_callindex(module.curtab)
-local function redir_exec(cmd)
- meths.set_var('__redir_exec_cmd', cmd)
- nvim_command([[
+function module.exec_lua(code, ...)
+ return module.meths.execute_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 = meths.get_var('__redir_exec_output')
- meths.del_var('__redir_exec_output')
- meths.del_var('__redir_exec_cmd')
+ 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
-local function get_pathsep()
- return iswin() and '\\' or '/'
+function module.get_pathsep()
+ return module.iswin() and '\\' or '/'
end
-local function pathroot()
+function module.pathroot()
local pathsep = package.config:sub(1,1)
- return iswin() and (nvim_dir:sub(1,2)..pathsep) or '/'
+ return module.iswin() and (module.nvim_dir:sub(1,2)..pathsep) or '/'
end
-- Returns a valid, platform-independent $NVIM_LISTEN_ADDRESS.
-- Useful for communicating with child instances.
-local function new_pipename()
+function module.new_pipename()
-- HACK: Start a server temporarily, get the name, then stop it.
- local pipename = nvim_eval('serverstart()')
- funcs.serverstop(pipename)
+ local pipename = module.eval('serverstart()')
+ module.funcs.serverstop(pipename)
return pipename
end
-local function missing_provider(provider)
+function module.missing_provider(provider)
if provider == 'ruby' or provider == 'node' then
- local prog = funcs['provider#' .. provider .. '#Detect']()
+ local prog = module.funcs['provider#' .. provider .. '#Detect']()
return prog == '' and (provider .. ' not detected') or false
elseif provider == 'python' or provider == 'python3' then
local py_major_version = (provider == 'python3' and 3 or 2)
- local errors = funcs['provider#pythonx#Detect'](py_major_version)[2]
+ local errors = module.funcs['provider#pythonx#Detect'](py_major_version)[2]
return errors ~= '' and errors or false
else
assert(false, 'Unknown provider: ' .. provider)
end
end
-local function alter_slashes(obj)
- if not iswin() then
+function module.alter_slashes(obj)
+ if not module.iswin() then
return obj
end
if type(obj) == 'string' then
@@ -739,7 +763,7 @@ local function alter_slashes(obj)
elseif type(obj) == 'table' then
local ret = {}
for k, v in pairs(obj) do
- ret[k] = alter_slashes(v)
+ ret[k] = module.alter_slashes(v)
end
return ret
else
@@ -747,87 +771,33 @@ local function alter_slashes(obj)
end
end
+local load_factor = 1
+if global_helpers.isCI() then
+ -- Compute load factor only once (but outside of any tests).
+ module.clear()
+ module.request('nvim_command', 'source src/nvim/testdir/load.vim')
+ load_factor = module.request('nvim_eval', 'g:test_load_factor')
+end
+function module.load_adjust(num)
+ return math.ceil(num * load_factor)
+end
-local load_factor = nil
-local function load_adjust(num)
- if load_factor == nil then -- Compute load factor only once.
- clear()
- request('nvim_command', 'source src/nvim/testdir/load.vim')
- load_factor = request('nvim_eval', 'g:test_load_factor')
+function module.parse_context(ctx)
+ local parsed = {}
+ for _, item in ipairs({'regs', 'jumps', 'buflist', 'gvars'}) do
+ parsed[item] = filter(function(v)
+ return type(v) == 'table'
+ end, module.call('msgpackparse', ctx[item]))
end
- return math.ceil(num * load_factor)
+ parsed['buflist'] = parsed['buflist'][1]
+ return map(function(v)
+ if #v == 0 then
+ return nil
+ end
+ return v
+ end, parsed)
end
-local module = {
- NIL = mpack.NIL,
- alter_slashes = alter_slashes,
- buffer = buffer,
- bufmeths = bufmeths,
- call = nvim_call,
- create_callindex = create_callindex,
- clear = clear,
- command = nvim_command,
- connect = connect,
- curbuf = curbuf,
- curbuf_contents = curbuf_contents,
- curbufmeths = curbufmeths,
- curtab = curtab,
- curtabmeths = curtabmeths,
- curwin = curwin,
- curwinmeths = curwinmeths,
- eval = nvim_eval,
- exc_exec = exc_exec,
- expect = expect,
- expect_any = expect_any,
- expect_msg_seq = expect_msg_seq,
- expect_twostreams = expect_twostreams,
- feed = feed,
- feed_command = feed_command,
- funcs = funcs,
- get_pathsep = get_pathsep,
- get_session = get_session,
- insert = insert,
- iswin = iswin,
- merge_args = merge_args,
- meth_pcall = meth_pcall,
- meths = meths,
- missing_provider = missing_provider,
- mkdir = lfs.mkdir,
- load_adjust = load_adjust,
- new_pipename = new_pipename,
- next_msg = next_msg,
- nvim = nvim,
- nvim_argv = nvim_argv,
- nvim_async = nvim_async,
- nvim_dir = nvim_dir,
- nvim_prog = nvim_prog,
- nvim_prog_abs = nvim_prog_abs,
- nvim_set = nvim_set,
- os_name = os_name,
- pathroot = pathroot,
- pending_win32 = pending_win32,
- prepend_argv = prepend_argv,
- rawfeed = rawfeed,
- redir_exec = redir_exec,
- request = request,
- retry = retry,
- rmdir = rmdir,
- run = run,
- run_session = run_session,
- set_session = set_session,
- set_method_error = set_method_error,
- set_shell_powershell = set_shell_powershell,
- skip_fragile = skip_fragile,
- source = source,
- spawn = spawn,
- stop = stop,
- tabmeths = tabmeths,
- tabpage = tabpage,
- uimeths = uimeths,
- wait = wait,
- window = window,
- winmeths = winmeths,
-}
module = global_helpers.tbl_extend('error', module, global_helpers)
return function(after_each)
diff --git a/test/functional/legacy/arglist_spec.lua b/test/functional/legacy/arglist_spec.lua
index bd65e549ef..241a19d940 100644
--- a/test/functional/legacy/arglist_spec.lua
+++ b/test/functional/legacy/arglist_spec.lua
@@ -92,74 +92,6 @@ describe('argument list commands', function()
eq(0, eval('len(argv())'))
end)
- it('test for [count]argument and [count]argdelete commands', function()
- reset_arglist()
- command('let save_hidden = &hidden')
- command('set hidden')
- command('let g:buffers = []')
- command('augroup TEST')
- command([[au BufEnter * call add(buffers, expand('%:t'))]])
- command('augroup END')
-
- command('argadd a b c d')
- command('$argu')
- command('$-argu')
- command('-argu')
- command('1argu')
- command('+2argu')
-
- command('augroup TEST')
- command('au!')
- command('augroup END')
-
- eq({'d', 'c', 'b', 'a', 'c'}, eval('g:buffers'))
-
- command('redir => result')
- command('ar')
- command('redir END')
- eq(1, eval([[result =~# 'a b \[c] d']]))
-
- command('.argd')
- eq({'a', 'b', 'd'}, eval('argv()'))
-
- command('-argd')
- eq({'a', 'd'}, eval('argv()'))
-
- command('$argd')
- eq({'a'}, eval('argv()'))
-
- command('1arga c')
- command('1arga b')
- command('$argu')
- command('$arga x')
- eq({'a', 'b', 'c', 'x'}, eval('argv()'))
-
- command('0arga Y')
- eq({'Y', 'a', 'b', 'c', 'x'}, eval('argv()'))
-
- command('%argd')
- eq({}, eval('argv()'))
-
- command('arga a b c d e f')
- command('2,$-argd')
- eq({'a', 'f'}, eval('argv()'))
-
- command('let &hidden = save_hidden')
-
- -- Setting the argument list should fail when the current buffer has
- -- unsaved changes
- command('%argd')
- command('enew!')
- command('set modified')
- assert_fails('args x y z', 'E37:')
- command('args! x y z')
- eq({'x', 'y', 'z'}, eval('argv()'))
- eq('x', eval('expand("%:t")'))
-
- command('%argdelete')
- assert_fails('argument', 'E163:')
- end)
-
it('test for 0argadd and 0argedit', function()
reset_arglist()
diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua
new file mode 100644
index 0000000000..990cb97fec
--- /dev/null
+++ b/test/functional/lua/buffer_updates_spec.lua
@@ -0,0 +1,206 @@
+-- Test suite for testing interactions with API bindings
+local helpers = require('test.functional.helpers')(after_each)
+
+local command = helpers.command
+local meths = helpers.meths
+local clear = helpers.clear
+local eq = helpers.eq
+local exec_lua = helpers.exec_lua
+local feed = helpers.feed
+
+local origlines = {"original line 1",
+ "original line 2",
+ "original line 3",
+ "original line 4",
+ "original line 5",
+ "original line 6",
+ " indented line"}
+
+describe('lua: buffer event callbacks', function()
+ before_each(function()
+ clear()
+ exec_lua([[
+ local events = {}
+
+ function test_register(bufnr, id, changedtick, utf_sizes)
+ local function callback(...)
+ table.insert(events, {id, ...})
+ if test_unreg == id then
+ return true
+ end
+ end
+ local opts = {on_lines=callback, on_detach=callback, utf_sizes=utf_sizes}
+ if changedtick then
+ opts.on_changedtick = callback
+ end
+ vim.api.nvim_buf_attach(bufnr, false, opts)
+ end
+
+ function get_events()
+ local ret_events = events
+ events = {}
+ return ret_events
+ end
+ ]])
+ end)
+
+
+ -- verifying the sizes with nvim_buf_get_offset is nice (checks we cannot
+ -- assert the wrong thing), but masks errors with unflushed lines (as
+ -- nvim_buf_get_offset forces a flush of the memline). To be safe run the
+ -- test both ways.
+ local function check(verify,utf_sizes)
+ local lastsize
+ meths.buf_set_lines(0, 0, -1, true, origlines)
+ if verify then
+ lastsize = meths.buf_get_offset(0, meths.buf_line_count(0))
+ end
+ exec_lua("return test_register(...)", 0, "test1",false,utf_sizes)
+ local tick = meths.buf_get_changedtick(0)
+
+ local verify_name = "test1"
+ local function check_events(expected)
+ local events = exec_lua("return get_events(...)" )
+ if utf_sizes then
+ -- this test case uses ASCII only, so sizes sshould be the same.
+ -- Unicode is tested below.
+ for _, event in ipairs(expected) do
+ event[9] = event[8]
+ event[10] = event[8]
+ end
+ end
+ eq(expected, events)
+ if verify then
+ for _, event in ipairs(events) do
+ if event[1] == verify_name and event[2] == "lines" then
+ local startline, endline = event[5], event[7]
+ local newrange = meths.buf_get_offset(0, endline) - meths.buf_get_offset(0, startline)
+ local newsize = meths.buf_get_offset(0, meths.buf_line_count(0))
+ local oldrange = newrange + lastsize - newsize
+ eq(oldrange, event[8])
+ lastsize = newsize
+ end
+ end
+ end
+ end
+
+ command('set autoindent')
+ command('normal! GyyggP')
+ tick = tick + 1
+ check_events({{ "test1", "lines", 1, tick, 0, 0, 1, 0}})
+
+ meths.buf_set_lines(0, 3, 5, true, {"changed line"})
+ tick = tick + 1
+ check_events({{ "test1", "lines", 1, tick, 3, 5, 4, 32 }})
+
+ exec_lua("return test_register(...)", 0, "test2", true, utf_sizes)
+ tick = tick + 1
+ command('undo')
+
+ -- plugins can opt in to receive changedtick events, or choose
+ -- to only recieve actual changes.
+ check_events({{ "test1", "lines", 1, tick, 3, 4, 5, 13 },
+ { "test2", "lines", 1, tick, 3, 4, 5, 13 },
+ { "test2", "changedtick", 1, tick+1 } })
+ tick = tick + 1
+
+ -- simulate next callback returning true
+ exec_lua("test_unreg = 'test1'")
+
+ meths.buf_set_lines(0, 6, 7, true, {"x1","x2","x3"})
+ tick = tick + 1
+
+ -- plugins can opt in to receive changedtick events, or choose
+ -- to only recieve actual changes.
+ check_events({{ "test1", "lines", 1, tick, 6, 7, 9, 16 },
+ { "test2", "lines", 1, tick, 6, 7, 9, 16 }})
+
+ verify_name = "test2"
+
+ meths.buf_set_lines(0, 1, 1, true, {"added"})
+ tick = tick + 1
+ check_events({{ "test2", "lines", 1, tick, 1, 1, 2, 0 }})
+
+ feed('wix')
+ tick = tick + 1
+ check_events({{ "test2", "lines", 1, tick, 4, 5, 5, 16 }})
+
+ -- check hot path for multiple insert
+ feed('yz')
+ tick = tick + 1
+ check_events({{ "test2", "lines", 1, tick, 4, 5, 5, 17 }})
+
+ feed('<bs>')
+ tick = tick + 1
+ check_events({{ "test2", "lines", 1, tick, 4, 5, 5, 19 }})
+
+ feed('<esc>Go')
+ tick = tick + 1
+ check_events({{ "test2", "lines", 1, tick, 11, 11, 12, 0 }})
+
+ feed('x')
+ tick = tick + 1
+ check_events({{ "test2", "lines", 1, tick, 11, 12, 12, 5 }})
+
+ command('bwipe!')
+ check_events({{ "test2", "detach", 1 }})
+ end
+
+ it('works', function()
+ check(false)
+ end)
+
+ it('works with verify', function()
+ check(true)
+ end)
+
+ it('works with utf_sizes and ASCII text', function()
+ check(false,true)
+ end)
+
+ it('works with utf_sizes and unicode text', function()
+ local unicode_text = {"ascii text",
+ "latin text åäö",
+ "BMP text ɧ αλφά",
+ "BMP text 汉语 ↥↧",
+ "SMP 🤦 🦄🦃",
+ "combining aÌŠ بÙيَّة"}
+ meths.buf_set_lines(0, 0, -1, true, unicode_text)
+ feed('gg')
+ exec_lua("return test_register(...)", 0, "test1", false, true)
+ local tick = meths.buf_get_changedtick(0)
+
+ feed('dd')
+ tick = tick + 1
+ eq({{ "test1", "lines", 1, tick, 0, 1, 0, 11, 11, 11 }}, exec_lua("return get_events(...)" ))
+
+ feed('A<bs>')
+ tick = tick + 1
+ eq({{ "test1", "lines", 1, tick, 0, 1, 1, 18, 15, 15 }}, exec_lua("return get_events(...)" ))
+
+ feed('<esc>jylp')
+ tick = tick + 1
+ eq({{ "test1", "lines", 1, tick, 1, 2, 2, 21, 16, 16 }}, exec_lua("return get_events(...)" ))
+
+ feed('+eea<cr>')
+ tick = tick + 1
+ eq({{ "test1", "lines", 1, tick, 2, 3, 4, 23, 15, 15 }}, exec_lua("return get_events(...)" ))
+
+ feed('<esc>jdw')
+ tick = tick + 1
+ -- non-BMP chars count as 2 UTF-2 codeunits
+ eq({{ "test1", "lines", 1, tick, 4, 5, 5, 18, 9, 12 }}, exec_lua("return get_events(...)" ))
+
+ feed('+rx')
+ tick = tick + 1
+ -- count the individual codepoints of a composed character.
+ eq({{ "test1", "lines", 1, tick, 5, 6, 6, 27, 20, 20 }}, exec_lua("return get_events(...)" ))
+
+ feed('kJ')
+ tick = tick + 1
+ -- NB: this is inefficient (but not really wrong).
+ eq({{ "test1", "lines", 1, tick, 4, 5, 5, 14, 5, 8 },
+ { "test1", "lines", 1, tick+1, 5, 6, 5, 27, 20, 20 }}, exec_lua("return get_events(...)" ))
+ end)
+
+end)
diff --git a/test/functional/lua/loop_spec.lua b/test/functional/lua/loop_spec.lua
new file mode 100644
index 0000000000..992d1666f6
--- /dev/null
+++ b/test/functional/lua/loop_spec.lua
@@ -0,0 +1,156 @@
+-- Test suite for testing interactions with API bindings
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local funcs = helpers.funcs
+local meths = helpers.meths
+local clear = helpers.clear
+local sleep = helpers.sleep
+local feed = helpers.feed
+local eq = helpers.eq
+local eval = helpers.eval
+local matches = helpers.matches
+local exec_lua = helpers.exec_lua
+local retry = helpers.retry
+
+before_each(clear)
+
+describe('vim.loop', function()
+
+ it('version', function()
+ assert(funcs.luaeval('vim.loop.version()')>=72961, "libuv version too old")
+ matches("(%d+)%.(%d+)%.(%d+)", funcs.luaeval('vim.loop.version_string()'))
+ end)
+
+ it('timer', function()
+ exec_lua('vim.api.nvim_set_var("coroutine_cnt", 0)', {})
+
+ local code=[[
+ local loop = vim.loop
+
+ local touch = 0
+ local function wait(ms)
+ local this = coroutine.running()
+ assert(this)
+ local timer = loop.new_timer()
+ timer:start(ms, 0, vim.schedule_wrap(function ()
+ timer:close()
+ touch = touch + 1
+ coroutine.resume(this)
+ touch = touch + 1
+ assert(touch==3)
+ vim.api.nvim_set_var("coroutine_cnt_1", touch)
+ end))
+ coroutine.yield()
+ touch = touch + 1
+ return touch
+ end
+ coroutine.wrap(function()
+ local touched = wait(10)
+ assert(touched==touch)
+ vim.api.nvim_set_var("coroutine_cnt", touched)
+ end)()
+ ]]
+
+ eq(0, meths.get_var('coroutine_cnt'))
+ exec_lua(code)
+ retry(2, nil, function()
+ sleep(50)
+ eq(2, meths.get_var('coroutine_cnt'))
+ end)
+ eq(3, meths.get_var('coroutine_cnt_1'))
+ end)
+
+ it('is API safe', function()
+ local screen = Screen.new(50,10)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {bold = true, foreground = Screen.colors.Blue1},
+ [2] = {bold = true, reverse = true},
+ [3] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
+ [4] = {bold = true, foreground = Screen.colors.SeaGreen4},
+ [5] = {bold = true},
+ })
+
+ -- deferred API functions are disabled, as their safety can't be guaranteed
+ exec_lua([[
+ local timer = vim.loop.new_timer()
+ timer:start(20, 0, function ()
+ _G.is_fast = vim.in_fast_event()
+ timer:close()
+ vim.api.nvim_set_var("valid", true)
+ vim.api.nvim_command("echomsg 'howdy'")
+ end)
+ ]])
+
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2: }|
+ {3:Error executing luv callback:} |
+ {3:[string "<nvim>"]:5: E5560: nvim_set_var must not }|
+ {3:be called in a lua loop callback} |
+ {4:Press ENTER or type command to continue}^ |
+ ]])
+ feed('<cr>')
+ eq(false, eval("get(g:, 'valid', v:false)"))
+ eq(true, exec_lua("return _G.is_fast"))
+
+ -- callbacks can be scheduled to be executed in the main event loop
+ -- where the entire API is available
+ exec_lua([[
+ local timer = vim.loop.new_timer()
+ timer:start(20, 0, vim.schedule_wrap(function ()
+ _G.is_fast = vim.in_fast_event()
+ timer:close()
+ vim.api.nvim_set_var("valid", true)
+ vim.api.nvim_command("echomsg 'howdy'")
+ end))
+ ]])
+
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ howdy |
+ ]])
+ eq(true, eval("get(g:, 'valid', v:false)"))
+ eq(false, exec_lua("return _G.is_fast"))
+
+ -- fast (not deferred) API functions are allowed to be called directly
+ exec_lua([[
+ local timer = vim.loop.new_timer()
+ timer:start(20, 0, function ()
+ timer:close()
+ -- input is queued for processing after the callback returns
+ vim.api.nvim_input("isneaky")
+ _G.mode = vim.api.nvim_get_mode()
+ end)
+ ]])
+ screen:expect([[
+ sneaky^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {5:-- INSERT --} |
+ ]])
+ eq({blocking=false, mode='n'}, exec_lua("return _G.mode"))
+ end)
+
+ it("is equal to require('luv')", function()
+ eq(true, exec_lua("return vim.loop == require('luv')"))
+ end)
+end)
diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua
index 8f318e3503..f6439001ac 100644
--- a/test/functional/lua/overrides_spec.lua
+++ b/test/functional/lua/overrides_spec.lua
@@ -14,6 +14,7 @@ local command = helpers.command
local write_file = helpers.write_file
local redir_exec = helpers.redir_exec
local alter_slashes = helpers.alter_slashes
+local exec_lua = helpers.exec_lua
local screen
@@ -53,11 +54,11 @@ describe('print', function()
v_tblout = setmetatable({}, meta_tblout)
]])
eq('', redir_exec('luafile ' .. fname))
- eq('\nE5114: Error while converting print argument #2: [NULL]',
+ eq('\nE5105: Error while calling lua chunk: E5114: Error while converting print argument #2: [NULL]',
redir_exec('lua print("foo", v_nilerr, "bar")'))
- eq('\nE5114: Error while converting print argument #2: Xtest-functional-lua-overrides-luafile:2: abc',
+ eq('\nE5105: Error while calling lua chunk: E5114: Error while converting print argument #2: Xtest-functional-lua-overrides-luafile:2: abc',
redir_exec('lua print("foo", v_abcerr, "bar")'))
- eq('\nE5114: Error while converting print argument #2: <Unknown error: lua_tolstring returned NULL for tostring result>',
+ eq('\nE5105: Error while calling lua chunk: E5114: Error while converting print argument #2: <Unknown error: lua_tolstring returned NULL for tostring result>',
redir_exec('lua print("foo", v_tblout, "bar")'))
end)
it('prints strings with NULs and NLs correctly', function()
@@ -76,6 +77,29 @@ describe('print', function()
eq('\nabc ', redir_exec('lua print("abc", "")'))
eq('\nabc def', redir_exec('lua print("abc", "", "def")'))
end)
+ it('defers printing in luv event handlers', function()
+ exec_lua([[
+ local cmd = ...
+ function test()
+ local timer = vim.loop.new_timer()
+ local done = false
+ timer:start(10, 0, function()
+ print("very fast")
+ timer:close()
+ done = true
+ end)
+ -- be kind to slow travis OS X jobs:
+ -- loop until we know for sure the callback has been executed
+ while not done do
+ os.execute(cmd)
+ vim.loop.run("nowait") -- fake os_breakcheck()
+ end
+ print("very slow")
+ 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()'))
+ end)
end)
describe('debug.debug', function()
@@ -183,6 +207,81 @@ describe('debug.debug', function()
{cr:Press ENTER or type command to continue}^ |
]])
end)
+
+ it("can be safely exited with 'cont'", function()
+ feed('<cr>')
+ feed(':lua debug.debug() print("x")<cr>')
+ screen:expect{grid=[[
+ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ lua_debug> ^ |
+ ]]}
+
+ feed("conttt<cr>") -- misspelled cont; invalid syntax
+ screen:expect{grid=[[
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ lua_debug> conttt |
+ {E:E5115: Error while loading debug string: (debug comma}|
+ {E:nd):1: '=' expected near '<eof>'} |
+ lua_debug> ^ |
+ ]]}
+
+ feed("cont<cr>") -- exactly "cont", exit now
+ screen:expect{grid=[[
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ lua_debug> conttt |
+ {E:E5115: Error while loading debug string: (debug comma}|
+ {E:nd):1: '=' expected near '<eof>'} |
+ lua_debug> cont |
+ x |
+ {cr:Press ENTER or type command to continue}^ |
+ ]]}
+
+ feed('<cr>')
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]]}
+ end)
end)
describe('package.path/package.cpath', function()
diff --git a/test/functional/lua/utility_functions_spec.lua b/test/functional/lua/utility_functions_spec.lua
index 780d3a1565..0d93914119 100644
--- a/test/functional/lua/utility_functions_spec.lua
+++ b/test/functional/lua/utility_functions_spec.lua
@@ -2,12 +2,12 @@
local helpers = require('test.functional.helpers')(after_each)
local funcs = helpers.funcs
-local meths = helpers.meths
local clear = helpers.clear
local eq = helpers.eq
local eval = helpers.eval
local feed = helpers.feed
local meth_pcall = helpers.meth_pcall
+local exec_lua = helpers.exec_lua
before_each(clear)
@@ -110,28 +110,53 @@ describe('lua function', function()
eq(1, funcs.luaeval('vim.stricmp("\\0C\\0", "\\0B\\0")'))
end)
+ it("vim.str_utfindex/str_byteindex", function()
+ exec_lua([[_G.test_text = "xy åäö ɧ 汉语 ↥ 🤦x🦄 aÌŠ بÙÙŠÙŽÙ‘"]])
+ local indicies32 = {[0]=0,1,2,3,5,7,9,10,12,13,16,19,20,23,24,28,29,33,34,35,37,38,40,42,44,46,48}
+ local indicies16 = {[0]=0,1,2,3,5,7,9,10,12,13,16,19,20,23,24,28,28,29,33,33,34,35,37,38,40,42,44,46,48}
+ for i,k in pairs(indicies32) do
+ eq(k, exec_lua("return vim.str_byteindex(_G.test_text, ...)", i), i)
+ end
+ for i,k in pairs(indicies16) do
+ eq(k, exec_lua("return vim.str_byteindex(_G.test_text, ..., true)", i), i)
+ end
+ local i32, i16 = 0, 0
+ for k = 0,48 do
+ if indicies32[i32] < k then
+ i32 = i32 + 1
+ end
+ if indicies16[i16] < k then
+ i16 = i16 + 1
+ if indicies16[i16+1] == indicies16[i16] then
+ i16 = i16 + 1
+ end
+ end
+ eq({i32, i16}, exec_lua("return {vim.str_utfindex(_G.test_text, ...)}", k), k)
+ end
+ end)
+
it("vim.schedule", function()
- meths.execute_lua([[
+ exec_lua([[
test_table = {}
vim.schedule(function()
table.insert(test_table, "xx")
end)
table.insert(test_table, "yy")
- ]], {})
- eq({"yy","xx"}, meths.execute_lua("return test_table", {}))
+ ]])
+ eq({"yy","xx"}, exec_lua("return test_table"))
-- type checked args
eq({false, 'Error executing lua: vim.schedule: expected function'},
- meth_pcall(meths.execute_lua, "vim.schedule('stringly')", {}))
+ meth_pcall(exec_lua, "vim.schedule('stringly')"))
eq({false, 'Error executing lua: vim.schedule: expected function'},
- meth_pcall(meths.execute_lua, "vim.schedule()", {}))
+ meth_pcall(exec_lua, "vim.schedule()"))
- meths.execute_lua([[
+ exec_lua([[
vim.schedule(function()
error("big failure\nvery async")
end)
- ]], {})
+ ]])
feed("<cr>")
eq('Error executing vim.schedule lua callback: [string "<nvim>"]:2: big failure\nvery async', eval("v:errmsg"))
@@ -139,7 +164,7 @@ describe('lua function', function()
it("vim.split", function()
local split = function(str, sep)
- return meths.execute_lua('return vim.split(...)', {str, sep})
+ return exec_lua('return vim.split(...)', str, sep)
end
local tests = {
@@ -172,7 +197,7 @@ describe('lua function', function()
it('vim.trim', function()
local trim = function(s)
- return meths.execute_lua('return vim.trim(...)', { s })
+ return exec_lua('return vim.trim(...)', s)
end
local trims = {
@@ -194,7 +219,7 @@ describe('lua function', function()
it('vim.inspect', function()
-- just make sure it basically works, it has its own test suite
local inspect = function(t, opts)
- return meths.execute_lua('return vim.inspect(...)', { t, opts })
+ return exec_lua('return vim.inspect(...)', t, opts)
end
eq('2', inspect(2))
@@ -202,18 +227,18 @@ describe('lua function', function()
inspect({ a = { b = 1 } }, { newline = '+', indent = '' }))
-- special value vim.inspect.KEY works
- eq('{ KEY_a = "x", KEY_b = "y"}', meths.execute_lua([[
+ eq('{ KEY_a = "x", KEY_b = "y"}', exec_lua([[
return vim.inspect({a="x", b="y"}, {newline = '', process = function(item, path)
if path[#path] == vim.inspect.KEY then
return 'KEY_'..item
end
return item
end})
- ]], {}))
+ ]]))
end)
it("vim.deepcopy", function()
- local is_dc = meths.execute_lua([[
+ local is_dc = exec_lua([[
local a = { x = { 1, 2 }, y = 5}
local b = vim.deepcopy(a)
@@ -222,7 +247,7 @@ describe('lua function', function()
return b.x[1] == 1 and b.x[2] == 2 and b.y == 5 and count == 2
and tostring(a) ~= tostring(b)
- ]], {})
+ ]])
assert(is_dc)
end)
diff --git a/test/functional/normal/put_spec.lua b/test/functional/normal/put_spec.lua
index 29cef13e39..40a4f051e3 100644
--- a/test/functional/normal/put_spec.lua
+++ b/test/functional/normal/put_spec.lua
@@ -659,6 +659,7 @@ describe('put command', function()
end)
describe('put after the line with virtualedit', function()
+ -- luacheck: ignore 621
local test_string = [[
Line of words 1 test_stringx"
Line of words 2]]
@@ -855,6 +856,7 @@ describe('put command', function()
end)
describe('. register special tests', function()
+ -- luacheck: ignore 621
before_each(reset)
it('applies control character actions', function()
feed('i<C-t><esc>u')
diff --git a/test/functional/normal/search_spec.lua b/test/functional/normal/search_spec.lua
new file mode 100644
index 0000000000..cc5a3c4599
--- /dev/null
+++ b/test/functional/normal/search_spec.lua
@@ -0,0 +1,16 @@
+local helpers = require('test.functional.helpers')(after_each)
+local clear = helpers.clear
+local command = helpers.command
+local expect_err = helpers.expect_err
+
+describe('search (/)', function()
+ before_each(clear)
+
+ it('fails with huge column (%c) value #9930', function()
+ expect_err("Vim:E951: \\%% value too large",
+ command, "/\\v%18446744071562067968c")
+ expect_err("Vim:E951: \\%% value too large",
+ command, "/\\v%2147483648c")
+ end)
+end)
+
diff --git a/test/functional/options/num_options_spec.lua b/test/functional/options/num_options_spec.lua
index 88e554c86f..deda5c9118 100644
--- a/test/functional/options/num_options_spec.lua
+++ b/test/functional/options/num_options_spec.lua
@@ -74,7 +74,7 @@ describe(':set validation', function()
should_fail('foldlevel', -5, 'E487')
should_fail('foldcolumn', 13, 'E474')
should_fail('conceallevel', 4, 'E474')
- should_fail('numberwidth', 11, 'E474')
+ should_fail('numberwidth', 21, 'E474')
should_fail('numberwidth', 0, 'E487')
-- If smaller than 1 this one is set to 'lines'-1
diff --git a/test/functional/plugin/health_spec.lua b/test/functional/plugin/health_spec.lua
index f2d5e433db..3525e235de 100644
--- a/test/functional/plugin/health_spec.lua
+++ b/test/functional/plugin/health_spec.lua
@@ -1,6 +1,5 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
-local plugin_helpers = require('test.functional.plugin.helpers')
local clear = helpers.clear
local curbuf_contents = helpers.curbuf_contents
@@ -41,7 +40,7 @@ end)
describe('health.vim', function()
before_each(function()
- plugin_helpers.reset()
+ clear{args={'-u', 'NORC'}}
-- Provides functions:
-- health#broken#check()
-- health#success1#check()
diff --git a/test/functional/plugin/helpers.lua b/test/functional/plugin/helpers.lua
deleted file mode 100644
index 4359380bd7..0000000000
--- a/test/functional/plugin/helpers.lua
+++ /dev/null
@@ -1,41 +0,0 @@
-local paths = require('test.config.paths')
-
-local helpers = require('test.functional.helpers')(nil)
-local spawn, set_session, nvim_prog, merge_args =
- helpers.spawn, helpers.set_session, helpers.nvim_prog, helpers.merge_args
-
-local additional_cmd = ''
-
-local function nvim_argv(shada_file)
- local rtp_value = ('\'%s/runtime\''):format(
- paths.test_source_path:gsub('\'', '\'\''))
- local nvim_args = {nvim_prog, '-u', 'NORC', '-i', shada_file or 'NONE', '-N',
- '--cmd', 'set shortmess+=I background=light noswapfile belloff= noshowcmd noruler',
- '--cmd', 'let &runtimepath=' .. rtp_value,
- '--cmd', additional_cmd,
- '--embed', '--headless'}
- if helpers.prepend_argv then
- return merge_args(helpers.prepend_argv, nvim_args)
- else
- return nvim_args
- end
-end
-
-local session = nil
-
-local function reset(...)
- if session then
- session:close()
- end
- session = spawn(nvim_argv(...))
- set_session(session)
-end
-
-local function set_additional_cmd(s)
- additional_cmd = s
-end
-
-return {
- reset=reset,
- set_additional_cmd=set_additional_cmd,
-}
diff --git a/test/functional/plugin/man_spec.lua b/test/functional/plugin/man_spec.lua
index e5da7932a5..d95995797e 100644
--- a/test/functional/plugin/man_spec.lua
+++ b/test/functional/plugin/man_spec.lua
@@ -1,23 +1,17 @@
local helpers = require('test.functional.helpers')(after_each)
-local plugin_helpers = require('test.functional.plugin.helpers')
-
local Screen = require('test.functional.ui.screen')
-
local command, eval, rawfeed = helpers.command, helpers.eval, helpers.rawfeed
-
-before_each(function()
- plugin_helpers.reset()
- helpers.clear()
- command('syntax on')
- command('set filetype=man')
-end)
+local clear = helpers.clear
describe(':Man', function()
describe('man.lua: highlight_line()', function()
local screen
before_each(function()
- command('syntax off') -- Ignore syntax groups
+ clear()
+ command('syntax on')
+ command('set filetype=man')
+ command('syntax off') -- Ignore syntax groups
screen = Screen.new(52, 5)
screen:set_default_attr_ids({
b = { bold = true },
@@ -131,5 +125,22 @@ describe(':Man', function()
|
]])
end)
+
+ it('handles : characters in input', function()
+ rawfeed([[
+ i<C-v><C-[>[40m 0 <C-v><C-[>[41m 1 <C-v><C-[>[42m 2 <C-v><C-[>[43m 3
+ <C-v><C-[>[44m 4 <C-v><C-[>[45m 5 <C-v><C-[>[46m 6 <C-v><C-[>[47m 7 <C-v><C-[>[100m 8 <C-v><C-[>[101m 9
+ <C-v><C-[>[102m 10 <C-v><C-[>[103m 11 <C-v><C-[>[104m 12 <C-v><C-[>[105m 13 <C-v><C-[>[106m 14 <C-v><C-[>[107m 15
+ <C-v><C-[>[48:5:16m 16 <ESC>]])
+ eval('man#init_pager()')
+
+ screen:expect([[
+ ^ 0 1 2 3 |
+ 4 5 6 7 8 9 |
+ 10 11 12 13 14 15 |
+ 16 |
+ |
+ ]])
+ end)
end)
end)
diff --git a/test/functional/plugin/matchparen_spec.lua b/test/functional/plugin/matchparen_spec.lua
index 51ec7e4870..13e1283e2c 100644
--- a/test/functional/plugin/matchparen_spec.lua
+++ b/test/functional/plugin/matchparen_spec.lua
@@ -1,19 +1,17 @@
local helpers = require('test.functional.helpers')(after_each)
-local plugin_helpers = require('test.functional.plugin.helpers')
local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
local command = helpers.command
local meths = helpers.meths
local feed = helpers.feed
local eq = helpers.eq
-local reset = plugin_helpers.reset
-
describe('matchparen', function()
local screen
before_each(function()
- reset()
+ clear{args={'-u', 'NORC'}}
screen = Screen.new(20,5)
screen:attach()
screen:set_default_attr_ids( {
diff --git a/test/functional/plugin/msgpack_spec.lua b/test/functional/plugin/msgpack_spec.lua
index 2ce9974812..d841cb8ce0 100644
--- a/test/functional/plugin/msgpack_spec.lua
+++ b/test/functional/plugin/msgpack_spec.lua
@@ -1,15 +1,15 @@
local helpers = require('test.functional.helpers')(after_each)
+local clear = helpers.clear
local meths = helpers.meths
local eq, nvim_eval, nvim_command, exc_exec =
helpers.eq, helpers.eval, helpers.command, helpers.exc_exec
local ok = helpers.ok
local NIL = helpers.NIL
-local plugin_helpers = require('test.functional.plugin.helpers')
-local reset = plugin_helpers.reset
-
describe('autoload/msgpack.vim', function()
- before_each(reset)
+ before_each(function()
+ clear{args={'-u', 'NORC'}}
+ end)
local sp = function(typ, val)
return ('{"_TYPE": v:msgpack_types.%s, "_VAL": %s}'):format(typ, val)
diff --git a/test/functional/plugin/shada_spec.lua b/test/functional/plugin/shada_spec.lua
index 1482d83ee6..c0104a58f7 100644
--- a/test/functional/plugin/shada_spec.lua
+++ b/test/functional/plugin/shada_spec.lua
@@ -1,4 +1,5 @@
local helpers = require('test.functional.helpers')(after_each)
+local clear = helpers.clear
local eq, nvim_eval, nvim_command, nvim, exc_exec, funcs, nvim_feed, curbuf =
helpers.eq, helpers.eval, helpers.command, helpers.nvim, helpers.exc_exec,
helpers.funcs, helpers.feed, helpers.curbuf
@@ -7,12 +8,15 @@ local read_file = helpers.read_file
local mpack = require('mpack')
-local plugin_helpers = require('test.functional.plugin.helpers')
-local reset = plugin_helpers.reset
-
local shada_helpers = require('test.functional.shada.helpers')
local get_shada_rw = shada_helpers.get_shada_rw
+local function reset(shada_file)
+ clear{ args={'-u', 'NORC',
+ '-i', shada_file or 'NONE',
+ }}
+end
+
local mpack_eq = function(expected, mpack_result)
local mpack_keys = {'type', 'timestamp', 'length', 'value'}
@@ -2543,6 +2547,7 @@ describe('syntax/shada.vim', function()
it('works', function()
nvim_command('syntax on')
nvim_command('setlocal syntax=shada')
+ nvim_command('set laststatus&')
curbuf('set_lines', 0, 1, true, {
'Header with timestamp ' .. epoch .. ':',
' % Key Value',
@@ -2879,4 +2884,3 @@ describe('syntax/shada.vim', function()
eq(exp, act)
end)
end)
-
diff --git a/test/functional/provider/provider_spec.lua b/test/functional/provider/provider_spec.lua
new file mode 100644
index 0000000000..bfb0bbc3a3
--- /dev/null
+++ b/test/functional/provider/provider_spec.lua
@@ -0,0 +1,26 @@
+
+local helpers = require('test.functional.helpers')(after_each)
+local clear, eval = helpers.clear, helpers.eval
+local command = helpers.command
+local expect_err = helpers.expect_err
+
+describe('providers', function()
+ before_each(function()
+ clear('--cmd', 'let &rtp = "test/functional/fixtures,".&rtp')
+ end)
+
+ it('with #Call(), missing g:loaded_xx_provider', function()
+ command('set loadplugins')
+ -- Using test-fixture with broken impl:
+ -- test/functional/fixtures/autoload/provider/python.vim
+ expect_err('Vim:provider: python: missing required variable g:loaded_python_provider',
+ eval, "has('python')")
+ end)
+
+ it('with g:loaded_xx_provider, missing #Call()', function()
+ -- Using test-fixture with broken impl:
+ -- test/functional/fixtures/autoload/provider/ruby.vim
+ expect_err('Vim:provider: ruby: g:loaded_ruby_provider=2 but provider#ruby#Call is not defined',
+ eval, "has('ruby')")
+ end)
+end)
diff --git a/test/functional/shada/buffers_spec.lua b/test/functional/shada/buffers_spec.lua
index a4746c2205..04c9c01d7c 100644
--- a/test/functional/shada/buffers_spec.lua
+++ b/test/functional/shada/buffers_spec.lua
@@ -1,26 +1,22 @@
--- ShaDa buffer list saving/reading support
+-- shada buffer list saving/reading support
local helpers = require('test.functional.helpers')(after_each)
local nvim_command, funcs, eq, curbufmeths =
helpers.command, helpers.funcs, helpers.eq, helpers.curbufmeths
local shada_helpers = require('test.functional.shada.helpers')
-local reset, set_additional_cmd, clear =
- shada_helpers.reset, shada_helpers.set_additional_cmd,
- shada_helpers.clear
+local reset, clear = shada_helpers.reset, shada_helpers.clear
-describe('ShaDa support code', function()
+describe('shada support code', function()
local testfilename = 'Xtestfile-functional-shada-buffers'
local testfilename_2 = 'Xtestfile-functional-shada-buffers-2'
- before_each(reset)
after_each(clear)
it('is able to dump and restore buffer list', function()
- set_additional_cmd('set shada+=%')
- reset()
+ reset('set shada+=%')
nvim_command('edit ' .. testfilename)
nvim_command('edit ' .. testfilename_2)
nvim_command('qall')
- reset()
+ reset('set shada+=%')
eq(3, funcs.bufnr('$'))
eq('', funcs.bufname(1))
eq(testfilename, funcs.bufname(2))
@@ -28,11 +24,9 @@ describe('ShaDa support code', function()
end)
it('does not restore buffer list without % in &shada', function()
- set_additional_cmd('set shada+=%')
- reset()
+ reset('set shada+=%')
nvim_command('edit ' .. testfilename)
nvim_command('edit ' .. testfilename_2)
- set_additional_cmd('')
nvim_command('qall')
reset()
eq(1, funcs.bufnr('$'))
@@ -40,61 +34,57 @@ describe('ShaDa support code', function()
end)
it('does not dump buffer list without % in &shada', function()
+ reset()
nvim_command('edit ' .. testfilename)
nvim_command('edit ' .. testfilename_2)
- set_additional_cmd('set shada+=%')
nvim_command('qall')
- reset()
+ reset('set shada+=%')
eq(1, funcs.bufnr('$'))
eq('', funcs.bufname(1))
end)
it('does not dump unlisted buffer', function()
- set_additional_cmd('set shada+=%')
- reset()
+ reset('set shada+=%')
nvim_command('edit ' .. testfilename)
nvim_command('edit ' .. testfilename_2)
curbufmeths.set_option('buflisted', false)
nvim_command('qall')
- reset()
+ reset('set shada+=%')
eq(2, funcs.bufnr('$'))
eq('', funcs.bufname(1))
eq(testfilename, funcs.bufname(2))
end)
it('does not dump quickfix buffer', function()
- set_additional_cmd('set shada+=%')
- reset()
+ reset('set shada+=%')
nvim_command('edit ' .. testfilename)
nvim_command('edit ' .. testfilename_2)
curbufmeths.set_option('buftype', 'quickfix')
nvim_command('qall')
- reset()
+ reset('set shada+=%')
eq(2, funcs.bufnr('$'))
eq('', funcs.bufname(1))
eq(testfilename, funcs.bufname(2))
end)
it('does not dump unnamed buffers', function()
- set_additional_cmd('set shada+=% hidden')
- reset()
+ reset('set shada+=% hidden')
curbufmeths.set_lines(0, 1, true, {'foo'})
nvim_command('enew')
curbufmeths.set_lines(0, 1, true, {'bar'})
eq(2, funcs.bufnr('$'))
nvim_command('qall!')
- reset()
+ reset('set shada+=% hidden')
eq(1, funcs.bufnr('$'))
eq('', funcs.bufname(1))
end)
it('restores 1 buffer with %1 in &shada, #5759', function()
- set_additional_cmd('set shada+=%1')
- reset()
+ reset('set shada+=%1')
nvim_command('edit ' .. testfilename)
nvim_command('edit ' .. testfilename_2)
nvim_command('qall')
- reset()
+ reset('set shada+=%1')
eq(2, funcs.bufnr('$'))
eq('', funcs.bufname(1))
eq(testfilename, funcs.bufname(2))
diff --git a/test/functional/shada/helpers.lua b/test/functional/shada/helpers.lua
index d5e061bb50..fb3ec4a87c 100644
--- a/test/functional/shada/helpers.lua
+++ b/test/functional/shada/helpers.lua
@@ -1,47 +1,39 @@
local helpers = require('test.functional.helpers')(nil)
-local spawn, set_session, meths, nvim_prog =
- helpers.spawn, helpers.set_session, helpers.meths, helpers.nvim_prog
-local write_file, merge_args = helpers.write_file, helpers.merge_args
+local meths = helpers.meths
+local write_file = helpers.write_file
+local concat_tables = helpers.concat_tables
local mpack = require('mpack')
local tmpname = helpers.tmpname()
-local append_argv = nil
-local function nvim_argv(shada_file, embed)
- if embed == nil then
- embed = true
+-- o={
+-- args=…,
+-- args_rm=…,
+-- shadafile=…,
+-- }
+local function reset(o)
+ assert(o == nil or type(o) == 'table' or type(o) == 'string')
+ o = o and o or {}
+ local args_rm = o.args_rm or {}
+ table.insert(args_rm, '-i')
+ local args={
+ '-i', o.shadafile or tmpname,
+ }
+ if type(o) == 'string' then
+ args = concat_tables(args, {'--cmd', o})
+ elseif o.args then
+ args = concat_tables(args, o.args)
end
- local argv = {nvim_prog, '-u', 'NONE', '-i', shada_file or tmpname, '-N',
- '--cmd', 'set shortmess+=I background=light noswapfile',
- '--headless', embed and '--embed' or nil}
- if helpers.prepend_argv or append_argv then
- return merge_args(helpers.prepend_argv, argv, append_argv)
- else
- return argv
- end
-end
-
-local reset = function(shada_file)
- set_session(spawn(nvim_argv(shada_file)))
+ helpers.clear{
+ args_rm=args_rm,
+ args=args,
+ }
meths.set_var('tmpname', tmpname)
end
-local set_additional_cmd = function(s)
- append_argv = {'--cmd', s}
-end
-
-local function add_argv(...)
- if select('#', ...) == 0 then
- append_argv = nil
- else
- append_argv = {...}
- end
-end
-
local clear = function()
os.remove(tmpname)
- append_argv = nil
end
local get_shada_rw = function(fname)
@@ -89,10 +81,7 @@ end
return {
reset=reset,
- set_additional_cmd=set_additional_cmd,
- add_argv=add_argv,
clear=clear,
get_shada_rw=get_shada_rw,
read_shada_file=read_shada_file,
- nvim_argv=nvim_argv,
}
diff --git a/test/functional/shada/marks_spec.lua b/test/functional/shada/marks_spec.lua
index e6450e68b3..e319fd9e6b 100644
--- a/test/functional/shada/marks_spec.lua
+++ b/test/functional/shada/marks_spec.lua
@@ -6,11 +6,7 @@ local meths, curwinmeths, curbufmeths, nvim_command, funcs, eq =
local exc_exec, redir_exec = helpers.exc_exec, helpers.redir_exec
local shada_helpers = require('test.functional.shada.helpers')
-local reset, set_additional_cmd, clear =
- shada_helpers.reset, shada_helpers.set_additional_cmd,
- shada_helpers.clear
-local add_argv = shada_helpers.add_argv
-local nvim_argv = shada_helpers.nvim_argv
+local reset, clear = shada_helpers.reset, shada_helpers.clear
local nvim_current_line = function()
return curwinmeths.get_cursor()[1]
@@ -71,8 +67,7 @@ describe('ShaDa support code', function()
nvim_command('2')
nvim_command('kB')
nvim_command('wshada')
- set_additional_cmd('set shada=\'0,f0')
- reset()
+ reset('set shada=\'0,f0')
nvim_command('language C')
nvim_command('normal! `A')
eq(testfilename, funcs.fnamemodify(curbufmeths.get_name(), ':t'))
@@ -223,17 +218,32 @@ describe('ShaDa support code', function()
-- during -c used to add item with zero lnum to jump list.
it('does not create incorrect file for non-existent buffers when writing from -c',
function()
- add_argv('--cmd', 'silent edit ' .. non_existent_testfilename, '-c', 'qall')
- local argv = nvim_argv(nil, false) -- no --embed
+ local argv = helpers.new_argv{
+ args_rm={
+ '-i',
+ '--embed', -- no --embed
+ },
+ args={
+ '-i', meths.get_var('tmpname'), -- Use same shada file as parent.
+ '--cmd', 'silent edit '..non_existent_testfilename,
+ '-c', 'qall'},
+ }
eq('', funcs.system(argv))
eq(0, exc_exec('rshada'))
end)
it('does not create incorrect file for non-existent buffers opened from -c',
function()
- add_argv('-c', 'silent edit ' .. non_existent_testfilename,
- '-c', 'autocmd VimEnter * qall')
- local argv = nvim_argv(nil, false) -- no --embed
+ local argv = helpers.new_argv{
+ args_rm={
+ '-i',
+ '--embed', -- no --embed
+ },
+ args={
+ '-i', meths.get_var('tmpname'), -- Use same shada file as parent.
+ '-c', 'silent edit '..non_existent_testfilename,
+ '-c', 'autocmd VimEnter * qall'},
+ }
eq('', funcs.system(argv))
eq(0, exc_exec('rshada'))
end)
diff --git a/test/functional/shada/registers_spec.lua b/test/functional/shada/registers_spec.lua
index 71af14aba8..1f06cbe350 100644
--- a/test/functional/shada/registers_spec.lua
+++ b/test/functional/shada/registers_spec.lua
@@ -3,9 +3,7 @@ local helpers = require('test.functional.helpers')(after_each)
local nvim_command, funcs, eq = helpers.command, helpers.funcs, helpers.eq
local shada_helpers = require('test.functional.shada.helpers')
-local reset, set_additional_cmd, clear =
- shada_helpers.reset, shada_helpers.set_additional_cmd,
- shada_helpers.clear
+local reset, clear = shada_helpers.reset, shada_helpers.clear
local setreg = function(name, contents, typ)
if type(contents) == 'string' then
@@ -52,9 +50,8 @@ describe('ShaDa support code', function()
setreg('c', {'d', 'e', ''}, 'c')
setreg('l', {'a', 'b', 'cde'}, 'l')
setreg('b', {'bca', 'abc', 'cba'}, 'b3')
- set_additional_cmd('set shada=\'0,<0')
nvim_command('qall')
- reset()
+ reset('set shada=\'0,<0')
eq({{'d', 'e', ''}, 'v'}, getreg('c'))
eq({{'a', 'b', 'cde'}, 'V'}, getreg('l'))
eq({{'bca', 'abc', 'cba'}, '\0223'}, getreg('b'))
@@ -76,9 +73,8 @@ describe('ShaDa support code', function()
setreg('c', {'d', 'e', ''}, 'c')
setreg('l', {'a', 'b', 'cde'}, 'l')
setreg('b', {'bca', 'abc', 'cba'}, 'b3')
- set_additional_cmd('set shada=\'0,\\"0')
nvim_command('qall')
- reset()
+ reset('set shada=\'0,\\"0')
eq({{'d', 'e', ''}, 'v'}, getreg('c'))
eq({{'a', 'b', 'cde'}, 'V'}, getreg('l'))
eq({{'bca', 'abc', 'cba'}, '\0223'}, getreg('b'))
@@ -142,7 +138,6 @@ describe('ShaDa support code', function()
reset()
-- \171 is U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK in latin1
setreg('e', {'\171«'}, 'c')
- set_additional_cmd('')
nvim_command('qall')
reset()
eq({{'\171«'}, 'v'}, getreg('e'))
diff --git a/test/functional/shada/shada_spec.lua b/test/functional/shada/shada_spec.lua
index 5f7daf73e5..ff63aed235 100644
--- a/test/functional/shada/shada_spec.lua
+++ b/test/functional/shada/shada_spec.lua
@@ -15,7 +15,6 @@ local shada_helpers = require('test.functional.shada.helpers')
local reset, clear, get_shada_rw =
shada_helpers.reset, shada_helpers.clear, shada_helpers.get_shada_rw
local read_shada_file = shada_helpers.read_shada_file
-local set_additional_cmd = shada_helpers.set_additional_cmd
local wshada, _, shada_fname, clean =
get_shada_rw('Xtest-functional-shada-shada.shada')
@@ -244,8 +243,7 @@ describe('ShaDa support code', function()
funcs.mkdir(dirname, '', 0)
eq(0, funcs.filewritable(dirname))
- set_additional_cmd('set shada=')
- reset(dirshada)
+ reset{shadafile=dirshada, args={'--cmd', 'set shada='}}
meths.set_option('shada', '\'10')
eq('Vim(wshada):E886: System error while opening ShaDa file '
.. 'Xtest-functional-shada-shada.d/main.shada for reading to merge '
diff --git a/test/functional/shada/variables_spec.lua b/test/functional/shada/variables_spec.lua
index f817bcef74..74bbceddcc 100644
--- a/test/functional/shada/variables_spec.lua
+++ b/test/functional/shada/variables_spec.lua
@@ -4,9 +4,7 @@ local meths, funcs, nvim_command, eq, exc_exec =
helpers.meths, helpers.funcs, helpers.command, helpers.eq, helpers.exc_exec
local shada_helpers = require('test.functional.shada.helpers')
-local reset, set_additional_cmd, clear =
- shada_helpers.reset, shada_helpers.set_additional_cmd,
- shada_helpers.clear
+local reset, clear = shada_helpers.reset, shada_helpers.clear
describe('ShaDa support code', function()
before_each(reset)
@@ -25,8 +23,7 @@ describe('ShaDa support code', function()
local autotest = function(tname, varname, varval, val_is_expr)
it('is able to dump and read back ' .. tname .. ' variable automatically',
function()
- set_additional_cmd('set shada+=!')
- reset()
+ reset('set shada+=!')
if val_is_expr then
nvim_command('let g:' .. varname .. ' = ' .. varval)
varval = meths.get_var(varname)
@@ -36,7 +33,7 @@ describe('ShaDa support code', function()
-- Exit during `reset` is not a regular exit: it does not write shada
-- automatically
nvim_command('qall')
- reset()
+ reset('set shada+=!')
eq(varval, meths.get_var(varname))
end)
end
@@ -55,8 +52,7 @@ describe('ShaDa support code', function()
meths.set_var('STRVAR', 'foo')
nvim_command('set shada+=!')
nvim_command('wshada')
- set_additional_cmd('set shada-=!')
- reset()
+ reset('set shada-=!')
nvim_command('rshada')
eq(0, funcs.exists('g:STRVAR'))
end)
@@ -98,7 +94,6 @@ describe('ShaDa support code', function()
meths.set_var('LSTVAR', {'«'})
meths.set_var('DCTVAR', {['«']='«'})
meths.set_var('NESTEDVAR', {['«']={{'«'}, {['«']='«'}, {a='Test'}}})
- set_additional_cmd('')
nvim_command('qall')
reset()
eq('«', meths.get_var('STRVAR'))
@@ -131,11 +126,10 @@ describe('ShaDa support code', function()
nvim_command('let F = function("tr")')
meths.set_var('U', '10')
nvim_command('set shada+=!')
- set_additional_cmd('set shada+=!')
eq('Vim(wshada):E5004: Error while dumping variable g:F, itself: attempt to dump function reference',
exc_exec('wshada'))
meths.set_option('shada', '')
- reset()
+ reset('set shada+=!')
eq('10', meths.get_var('U'))
end)
@@ -148,8 +142,7 @@ describe('ShaDa support code', function()
eq('Vim(wshada):E5005: Unable to dump variable g:L: container references itself in index 0',
exc_exec('wshada'))
meths.set_option('shada', '')
- set_additional_cmd('set shada+=!')
- reset()
+ reset('set shada+=!')
eq('10', meths.get_var('U'))
end)
end)
diff --git a/test/functional/terminal/edit_spec.lua b/test/functional/terminal/edit_spec.lua
index 84d7ae6e9c..d213bae7b3 100644
--- a/test/functional/terminal/edit_spec.lua
+++ b/test/functional/terminal/edit_spec.lua
@@ -34,10 +34,9 @@ describe(':edit term://*', function()
it("runs TermOpen early enough to set buffer-local 'scrollback'", function()
local columns, lines = 20, 4
local scr = get_screen(columns, lines)
- local rep = 'a'
+ local rep = 97
meths.set_option('shellcmdflag', 'REP ' .. rep)
command('set shellxquote=') -- win: avoid extra quotes
- local rep_size = rep:byte() -- 'a' => 97
local sb = 10
command('autocmd TermOpen * :setlocal scrollback='..tostring(sb)
..'|call feedkeys("G", "n")')
@@ -45,8 +44,8 @@ describe(':edit term://*', function()
local bufcontents = {}
local winheight = curwinmeths.get_height()
- local buf_cont_start = rep_size - sb - winheight + 2
- for i = buf_cont_start,(rep_size - 1) do
+ local buf_cont_start = rep - sb - winheight + 2
+ for i = buf_cont_start,(rep - 1) do
bufcontents[#bufcontents + 1] = ('%d: foobar'):format(i)
end
bufcontents[#bufcontents + 1] = ''
diff --git a/test/functional/terminal/ex_terminal_spec.lua b/test/functional/terminal/ex_terminal_spec.lua
index f3849709e3..591e6340cf 100644
--- a/test/functional/terminal/ex_terminal_spec.lua
+++ b/test/functional/terminal/ex_terminal_spec.lua
@@ -137,7 +137,7 @@ describe(':terminal (with fake shell)', function()
it('with no argument, acts like termopen()', function()
terminal_with_fake_shell()
- retry(3, 4 * screen.timeout, function()
+ retry(nil, 4 * screen.timeout, function()
screen:expect([[
^ready $ |
[Process exited 0] |
@@ -261,4 +261,14 @@ describe(':terminal (with fake shell)', function()
eq('scripts/shadacat.py', eval('bufname("%")'))
end)
+ it('with bufhidden=delete #3958', function()
+ command('set hidden')
+ eq(1, eval('&hidden'))
+ command('autocmd BufNew * setlocal bufhidden=delete')
+ for _ = 1, 5 do
+ source([[
+ execute 'edit '.reltimestr(reltime())
+ terminal]])
+ end
+ end)
end)
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index 56d6f68b7a..af55ec1555 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -182,6 +182,21 @@ describe('TUI', function()
]])
end)
+ it('handles pasting a specific amount of text', function()
+ -- Need extra time for this test, specially in ASAN.
+ screen.timeout = 60000
+ feed_data('i\027[200~'..string.rep('z', 64)..'\027[201~')
+ screen:expect([[
+ zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz|
+ zzzzzzzzzzzzzz{1: } |
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ {3:-- INSERT --} |
+ {3:-- TERMINAL --} |
+ ]])
+ end)
+
it('can handle arbitrarily long bursts of input', function()
-- Need extra time for this test, specially in ASAN.
screen.timeout = 60000
@@ -268,14 +283,13 @@ describe('TUI', function()
end)
end)
-describe('TUI with non-tty file descriptors', function()
- before_each(helpers.clear)
-
+describe('TUI', function()
+ before_each(clear)
after_each(function()
- os.remove('testF') -- ensure test file is removed
+ os.remove('testF')
end)
- it('can handle pipes as stdout and stderr', function()
+ it('with non-tty (pipe) stdout/stderr', function()
local screen = thelpers.screen_setup(0, '"'..nvim_prog
..' -u NONE -i NONE --cmd \'set noswapfile noshowcmd noruler\' --cmd \'normal iabc\' > /dev/null 2>&1 && cat testF && rm testF"')
feed_data(':w testF\n:q\n')
@@ -289,6 +303,22 @@ describe('TUI with non-tty file descriptors', function()
{3:-- TERMINAL --} |
]])
end)
+
+ it('<C-h> #10134', function()
+ local screen = thelpers.screen_setup(0, '["'..nvim_prog
+ ..[[", "-u", "NONE", "-i", "NONE", "--cmd", "set noruler", "--cmd", ':nnoremap <C-h> :echomsg "\<C-h\>"<CR>']]..']')
+
+ command([[call chansend(b:terminal_job_id, "\<C-h>")]])
+ screen:expect([[
+ {1: } |
+ {4:~ }|
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] }|
+ <C-h> |
+ {3:-- TERMINAL --} |
+ ]])
+ end)
end)
describe('TUI FocusGained/FocusLost', function()
@@ -714,7 +744,9 @@ describe("TUI 't_Co' (terminal colors)", function()
-- others:
- it("TERM=interix uses 8 colors", function()
+ -- TODO(blueyed): this is made pending, since it causes failure + later hang
+ -- when using non-compatible libvterm (#9494/#10179).
+ pending("TERM=interix uses 8 colors", function()
assert_term_colors("interix", nil, 8)
end)
@@ -856,9 +888,9 @@ describe('TUI background color', function()
screen:expect{any='did OptionSet, yay!'}
end)
- local function assert_bg(color, bg)
- it('handles '..color..' as '..bg, function()
- feed_data('\027]11;rgb:'..color..'\007')
+ it("handles deferred background color", function()
+ local last_bg = 'dark'
+ local function wait_for_bg(bg)
-- Retry until the terminal response is handled.
retry(100, nil, function()
feed_data(':echo &background\n')
@@ -875,45 +907,76 @@ describe('TUI background color', function()
]], bg)
})
end)
- end)
- end
+ last_bg = bg
+ end
+
+ local function assert_bg(colorspace, color, bg)
+ -- Ensure the opposite of the expected bg is active.
+ local other_bg = (bg == 'dark' and 'light' or 'dark')
+ if last_bg ~= other_bg then
+ feed_data(other_bg == 'light' and '\027]11;rgb:f/f/f\007'
+ or '\027]11;rgb:0/0/0\007')
+ wait_for_bg(other_bg)
+ end
+
+ feed_data('\027]11;'..colorspace..':'..color..'\007')
+ wait_for_bg(bg)
+ end
- assert_bg('0000/0000/0000', 'dark')
- assert_bg('ffff/ffff/ffff', 'light')
- assert_bg('000/000/000', 'dark')
- assert_bg('fff/fff/fff', 'light')
- assert_bg('00/00/00', 'dark')
- assert_bg('ff/ff/ff', 'light')
- assert_bg('0/0/0', 'dark')
- assert_bg('f/f/f', 'light')
-
- assert_bg('f/0/0', 'dark')
- assert_bg('0/f/0', 'light')
- assert_bg('0/0/f', 'dark')
-
- assert_bg('1/1/1', 'dark')
- assert_bg('2/2/2', 'dark')
- assert_bg('3/3/3', 'dark')
- assert_bg('4/4/4', 'dark')
- assert_bg('5/5/5', 'dark')
- assert_bg('6/6/6', 'dark')
- assert_bg('7/7/7', 'dark')
- assert_bg('8/8/8', 'light')
- assert_bg('9/9/9', 'light')
- assert_bg('a/a/a', 'light')
- assert_bg('b/b/b', 'light')
- assert_bg('c/c/c', 'light')
- assert_bg('d/d/d', 'light')
- assert_bg('e/e/e', 'light')
-
- assert_bg('0/e/0', 'light')
- assert_bg('0/d/0', 'light')
- assert_bg('0/c/0', 'dark')
- assert_bg('0/b/0', 'dark')
-
- assert_bg('f/0/f', 'dark')
- assert_bg('f/1/f', 'dark')
- assert_bg('f/2/f', 'dark')
- assert_bg('f/3/f', 'light')
- assert_bg('f/4/f', 'light')
+ assert_bg('rgb', '0000/0000/0000', 'dark')
+ assert_bg('rgb', 'ffff/ffff/ffff', 'light')
+ assert_bg('rgb', '000/000/000', 'dark')
+ assert_bg('rgb', 'fff/fff/fff', 'light')
+ assert_bg('rgb', '00/00/00', 'dark')
+ assert_bg('rgb', 'ff/ff/ff', 'light')
+ assert_bg('rgb', '0/0/0', 'dark')
+ assert_bg('rgb', 'f/f/f', 'light')
+
+ assert_bg('rgb', 'f/0/0', 'dark')
+ assert_bg('rgb', '0/f/0', 'light')
+ assert_bg('rgb', '0/0/f', 'dark')
+
+ assert_bg('rgb', '1/1/1', 'dark')
+ assert_bg('rgb', '2/2/2', 'dark')
+ assert_bg('rgb', '3/3/3', 'dark')
+ assert_bg('rgb', '4/4/4', 'dark')
+ assert_bg('rgb', '5/5/5', 'dark')
+ assert_bg('rgb', '6/6/6', 'dark')
+ assert_bg('rgb', '7/7/7', 'dark')
+ assert_bg('rgb', '8/8/8', 'light')
+ assert_bg('rgb', '9/9/9', 'light')
+ assert_bg('rgb', 'a/a/a', 'light')
+ assert_bg('rgb', 'b/b/b', 'light')
+ assert_bg('rgb', 'c/c/c', 'light')
+ assert_bg('rgb', 'd/d/d', 'light')
+ assert_bg('rgb', 'e/e/e', 'light')
+
+ assert_bg('rgb', '0/e/0', 'light')
+ assert_bg('rgb', '0/d/0', 'light')
+ assert_bg('rgb', '0/c/0', 'dark')
+ assert_bg('rgb', '0/b/0', 'dark')
+
+ assert_bg('rgb', 'f/0/f', 'dark')
+ assert_bg('rgb', 'f/1/f', 'dark')
+ assert_bg('rgb', 'f/2/f', 'dark')
+ assert_bg('rgb', 'f/3/f', 'light')
+ assert_bg('rgb', 'f/4/f', 'light')
+
+ assert_bg('rgba', '0000/0000/0000/0000', 'dark')
+ assert_bg('rgba', '0000/0000/0000/ffff', 'dark')
+ assert_bg('rgba', 'ffff/ffff/ffff/0000', 'light')
+ assert_bg('rgba', 'ffff/ffff/ffff/ffff', 'light')
+ assert_bg('rgba', '000/000/000/000', 'dark')
+ assert_bg('rgba', '000/000/000/fff', 'dark')
+ assert_bg('rgba', 'fff/fff/fff/000', 'light')
+ assert_bg('rgba', 'fff/fff/fff/fff', 'light')
+ assert_bg('rgba', '00/00/00/00', 'dark')
+ assert_bg('rgba', '00/00/00/ff', 'dark')
+ assert_bg('rgba', 'ff/ff/ff/00', 'light')
+ assert_bg('rgba', 'ff/ff/ff/ff', 'light')
+ assert_bg('rgba', '0/0/0/0', 'dark')
+ assert_bg('rgba', '0/0/0/f', 'dark')
+ assert_bg('rgba', 'f/f/f/0', 'light')
+ assert_bg('rgba', 'f/f/f/f', 'light')
+ end)
end)
diff --git a/test/functional/ui/cmdline_highlight_spec.lua b/test/functional/ui/cmdline_highlight_spec.lua
index 45808b3b1b..052414a43d 100644
--- a/test/functional/ui/cmdline_highlight_spec.lua
+++ b/test/functional/ui/cmdline_highlight_spec.lua
@@ -494,7 +494,7 @@ describe('Command-line coloring', function()
{EOB:~ }|
{EOB:~ }|
{EOB:~ }|
- Type :qa! and pr...nges and exit Nvim |
+ Type :qa and pre...nter> to exit Nvim |
]])
end)
it('works fine with NUL, NL, CR', function()
diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua
index 915e7ae867..1c4d5a5c6b 100644
--- a/test/functional/ui/cmdline_spec.lua
+++ b/test/functional/ui/cmdline_spec.lua
@@ -761,8 +761,42 @@ local function test_cmdline(linegrid)
}}, wildmenu_items=expected, wildmenu_pos=0}
end)
+ it("doesn't send invalid events when aborting mapping #10000", function()
+ command('cnoremap ab c')
+
+ feed(':xa')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]], cmdline={{
+ content = { { "x" } },
+ firstc = ":",
+ pos = 1,
+ special = { "a", false }
+ }}}
+
+ -- This used to send an invalid event where pos where larger than the total
+ -- lenght of content. Checked in _handle_cmdline_show.
+ feed('<esc>')
+ screen:expect([[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ end)
+
end
+-- the representation of cmdline and cmdline_block contents changed with ext_linegrid
+-- (which uses indexed highlights) so make sure to test both
+describe('ui/ext_cmdline', function() test_cmdline(true) end)
+describe('ui/ext_cmdline (legacy highlights)', function() test_cmdline(false) end)
+
describe('cmdline redraw', function()
local screen
before_each(function()
@@ -794,7 +828,7 @@ describe('cmdline redraw', function()
end)
it('with <Cmd>', function()
- command('cmap a <Cmd>0<CR>') -- no-op
+ command('cmap a <Cmd>call sin(0)<CR>') -- no-op
feed(':012345678901234567890123456789')
screen:expect{grid=[[
|
@@ -813,8 +847,3 @@ describe('cmdline redraw', function()
]], unchanged=true}
end)
end)
-
--- the representation of cmdline and cmdline_block contents changed with ext_linegrid
--- (which uses indexed highlights) so make sure to test both
-describe('ui/ext_cmdline', function() test_cmdline(true) end)
-describe('ui/ext_cmdline (legacy highlights)', function() test_cmdline(false) end)
diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua
index 4dc86f1e1f..6475eb2923 100644
--- a/test/functional/ui/cursor_spec.lua
+++ b/test/functional/ui/cursor_spec.lua
@@ -216,10 +216,10 @@ describe('ui/cursor', function()
if m.blinkwait then m.blinkwait = 700 end
end
if m.hl_id then
- m.hl_id = 50
+ m.hl_id = 54
m.attr = {background = Screen.colors.DarkGray}
end
- if m.id_lm then m.id_lm = 51 end
+ if m.id_lm then m.id_lm = 55 end
end
-- Assert the new expectation.
diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua
index a567fbb941..8a1758c4a0 100644
--- a/test/functional/ui/float_spec.lua
+++ b/test/functional/ui/float_spec.lua
@@ -35,6 +35,10 @@ describe('floating windows', function()
[15] = {background = Screen.colors.Grey20},
[16] = {background = Screen.colors.Grey20, bold = true, foreground = Screen.colors.Blue1},
[17] = {background = Screen.colors.Yellow},
+ [18] = {foreground = Screen.colors.Brown, background = Screen.colors.Grey20},
+ [19] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGray},
+ [20] = {bold = true, foreground = Screen.colors.Brown},
+ [21] = {background = Screen.colors.Gray90},
}
it('behavior', function()
@@ -168,6 +172,121 @@ describe('floating windows', function()
end
end)
+ it('draws correctly with redrawdebug=compositor', function()
+ -- NB: we do not test that it produces the "correct" debug info
+ -- (as it is intermediate only, and is allowed to change by internal
+ -- refactors). Only check that it doesn't cause permanent glitches,
+ -- or something.
+ command("set redrawdebug=compositor")
+ command("set wd=1")
+ local buf = meths.create_buf(false,false)
+ local win = meths.open_win(buf, false, {relative='editor', width=20, height=2, row=2, col=5})
+ local expected_pos = {
+ [3]={{id=1001}, 'NW', 1, 2, 5, true},
+ }
+
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {1: }|
+ {2:~ }|
+ ]], float_pos=expected_pos}
+ else
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }{1: }{0: }|
+ {0:~ }{2:~ }{0: }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end
+
+
+ meths.win_set_config(win, {relative='editor', row=0, col=10})
+ expected_pos[3][4] = 0
+ expected_pos[3][5] = 10
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {1: }|
+ {2:~ }|
+ ]], float_pos=expected_pos}
+ else
+ screen:expect([[
+ ^ {1: } |
+ {0:~ }{2:~ }{0: }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end
+
+ meths.win_close(win, false)
+ if multigrid then
+ screen:expect([[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ]])
+ else
+ screen:expect([[
+ ^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end
+ end)
+
it('return their configuration', function()
local buf = meths.create_buf(false, false)
local win = meths.open_win(buf, false, {relative='editor', width=20, height=2, row=3, col=5})
@@ -182,7 +301,7 @@ describe('floating windows', function()
end
end)
- it('defaults to nonumber and NormalFloat highlight', function()
+ it('defaults to NormalFloat highlight and inherited options', function()
command('set number')
command('hi NormalFloat guibg=#333333')
feed('ix<cr>y<cr><esc>gg')
@@ -205,18 +324,18 @@ describe('floating windows', function()
{0:~ }|
{0:~ }|
## grid 3
- {15:x }|
- {15:y }|
- {15: }|
+ {18: 1 }{15:x }|
+ {18: 2 }{15:y }|
+ {18: 3 }{15: }|
{16:~ }|
]], float_pos={[3] = {{id = 1001}, "NW", 1, 4, 10, true}}}
else
screen:expect([[
{14: 1 }^x |
{14: 2 }y |
- {14: 3 } {15:x } |
- {0:~ }{15:y }{0: }|
- {0:~ }{15: }{0: }|
+ {14: 3 } {18: 1 }{15:x } |
+ {0:~ }{18: 2 }{15:y }{0: }|
+ {0:~ }{18: 3 }{15: }{0: }|
{0:~ }{16:~ }{0: }|
|
]])
@@ -242,7 +361,7 @@ describe('floating windows', function()
{0:~ }|
{0:~ }|
## grid 3
- {15: }|
+ {18: 1 }{15: }|
{16:~ }|
{16:~ }|
{16:~ }|
@@ -251,7 +370,7 @@ describe('floating windows', function()
screen:expect([[
{14: 1 }^x |
{14: 2 }y |
- {14: 3 } {15: } |
+ {14: 3 } {18: 1 }{15: } |
{0:~ }{16:~ }{0: }|
{0:~ }{16:~ }{0: }|
{0:~ }{16:~ }{0: }|
@@ -260,6 +379,126 @@ describe('floating windows', function()
end
end)
+ it("can use 'minimal' style", function()
+ command('set number')
+ command('set signcolumn=yes')
+ command('set cursorline')
+ 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:----------------------------------------]|
+ |
+ ## grid 2
+ {19: }{20: 1 }{21:^x }|
+ {19: }{14: 2 }y |
+ {19: }{14: 3 } |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {15:x }|
+ {15:y }|
+ {15: }|
+ {15: }|
+ ]], float_pos={[3] = {{id = 1001}, "NW", 1, 4, 10, true}}}
+ else
+ screen:expect([[
+ {19: }{20: 1 }{21:^x }|
+ {19: }{14: 2 }y |
+ {19: }{14: 3 } {15:x } |
+ {0:~ }{15:y }{0: }|
+ {0:~ }{15: }{0: }|
+ {0:~ }{15: }{0: }|
+ |
+ ]])
+ end
+
+ -- signcolumn=yes still works if there actually are signs
+ command('sign define piet1 text=ðŒ¢Ì€Ì̂̃̅̄ðŒ¢Ì€Ì̂̃̅̄ texthl=Search')
+ command('sign place 1 line=1 name=piet1 buffer=1')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ {17:ðŒ¢Ì€Ì̂̃̅̄ðŒ¢Ì€Ì̂̃̅̄}{20: 1 }{21:^x }|
+ {19: }{14: 2 }y |
+ {19: }{14: 3 } |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {17:ðŒ¢Ì€Ì̂̃̅̄ðŒ¢Ì€Ì̂̃̅̄}{15:x }|
+ {19: }{15:y }|
+ {19: }{15: }|
+ {15: }|
+ ]], float_pos={[3] = {{id = 1001}, "NW", 1, 4, 10, true}}}
+
+ else
+ screen:expect([[
+ {17:ðŒ¢Ì€Ì̂̃̅̄ðŒ¢Ì€Ì̂̃̅̄}{20: 1 }{21:^x }|
+ {19: }{14: 2 }y |
+ {19: }{14: 3 } {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:----------------------------------------]|
+ |
+ ## grid 2
+ {19: }{20: 1 }{21:^x }|
+ {19: }{14: 2 }y |
+ {19: }{14: 3 } |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {15: }|
+ {15: }|
+ {15: }|
+ {15: }|
+ ]], float_pos={[3] = {{id = 1001}, "NW", 1, 4, 10, true}}}
+ else
+ screen:expect([[
+ {19: }{20: 1 }{21:^x }|
+ {19: }{14: 2 }y |
+ {19: }{14: 3 } {15: } |
+ {0:~ }{15: }{0: }|
+ {0:~ }{15: }{0: }|
+ {0:~ }{15: }{0: }|
+ |
+ ]])
+ end
+ end)
+
it('can have minimum size', function()
insert("the background text")
local buf = meths.create_buf(false, true)
@@ -2539,6 +2778,356 @@ describe('floating windows', function()
end)
+ it("vertical resize + - _", function()
+ feed('<c-w>w')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ x |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {1:^y }|
+ {2:~ }|
+ ]], float_pos=expected_pos}
+ else
+ screen:expect([[
+ x |
+ {0:~ }|
+ {0:~ }{1:^y }{0: }|
+ {0:~ }{2:~ }{0: }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end
+
+ feed('<c-w>+')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ x |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {1:^y }|
+ {2:~ }|
+ {2:~ }|
+ ]], float_pos=expected_pos}
+ else
+ screen:expect([[
+ x |
+ {0:~ }|
+ {0:~ }{1:^y }{0: }|
+ {0:~ }{2:~ }{0: }|
+ {0:~ }{2:~ }{0: }|
+ {0:~ }|
+ |
+ ]])
+ end
+
+ feed('<c-w>2-')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ x |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {1:^y }|
+ ]], float_pos=expected_pos}
+ else
+ screen:expect([[
+ x |
+ {0:~ }|
+ {0:~ }{1:^y }{0: }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end
+
+ feed('<c-w>4_')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ x |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {1:^y }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ ]], float_pos=expected_pos}
+ else
+ screen:expect([[
+ x |
+ {0:~ }|
+ {0:~ }{1:^y }{0: }|
+ {0:~ }{2:~ }{0: }|
+ {0:~ }{2:~ }{0: }|
+ {0:~ }{2:~ }{0: }|
+ |
+ ]])
+ end
+
+ feed('<c-w>_')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ x |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {1:^y }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ {2:~ }|
+ ]], float_pos=expected_pos}
+ else
+ screen:expect([[
+ x {1:^y } |
+ {0:~ }{2:~ }{0: }|
+ {0:~ }{2:~ }{0: }|
+ {0:~ }{2:~ }{0: }|
+ {0:~ }{2:~ }{0: }|
+ {0:~ }{2:~ }{0: }|
+ |
+ ]])
+ end
+ end)
+
+ it("horizontal resize > < |", function()
+ feed('<c-w>w')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ x |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {1:^y }|
+ {2:~ }|
+ ]], float_pos=expected_pos}
+ else
+ screen:expect([[
+ x |
+ {0:~ }|
+ {0:~ }{1:^y }{0: }|
+ {0:~ }{2:~ }{0: }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end
+
+ feed('<c-w>>')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ x |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {1:^y }|
+ {2:~ }|
+ ]], float_pos=expected_pos}
+ else
+ screen:expect([[
+ x |
+ {0:~ }|
+ {0:~ }{1:^y }{0: }|
+ {0:~ }{2:~ }{0: }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end
+
+ feed('<c-w>10<lt>')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ x |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {1:^y }|
+ {2:~ }|
+ ]], float_pos=expected_pos}
+ else
+ screen:expect([[
+ x |
+ {0:~ }|
+ {0:~ }{1:^y }{0: }|
+ {0:~ }{2:~ }{0: }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end
+
+ feed('<c-w>15|')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ x |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {1:^y }|
+ {2:~ }|
+ ]], float_pos=expected_pos}
+ else
+ screen:expect([[
+ x |
+ {0:~ }|
+ {0:~ }{1:^y }{0: }|
+ {0:~ }{2:~ }{0: }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end
+
+ feed('<c-w>|')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ x |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {1:^y }|
+ {2:~ }|
+ ]], float_pos=expected_pos}
+ else
+ screen:expect([[
+ x |
+ {0:~ }|
+ {1:^y }|
+ {2:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end
+ end)
+
it("s :split (non-float)", function()
feed("<c-w>s")
if multigrid then
@@ -3764,6 +4353,403 @@ describe('floating windows', function()
end
end)
end)
+
+ it("'winblend' option", function()
+ screen:try_resize(50,9)
+ screen:set_default_attr_ids({
+ [1] = {background = Screen.colors.LightMagenta},
+ [2] = {foreground = Screen.colors.Grey0, background = tonumber('0xffcfff')},
+ [3] = {foreground = tonumber('0xb282b2'), background = tonumber('0xffcfff')},
+ [4] = {foreground = Screen.colors.Red, background = Screen.colors.LightMagenta},
+ [5] = {foreground = tonumber('0x990000'), background = tonumber('0xfff1ff')},
+ [6] = {foreground = tonumber('0x332533'), background = tonumber('0xfff1ff')},
+ [7] = {background = tonumber('0xffcfff'), bold = true, foreground = tonumber('0x0000d8')},
+ [8] = {background = Screen.colors.LightMagenta, bold = true, foreground = Screen.colors.Blue1}
+ })
+ 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.]])
+ local buf = meths.create_buf(false,false)
+ meths.buf_set_lines(buf, 0, -1, true, {"test", "", "popup text"})
+ local win = meths.open_win(buf, false, {relative='editor', width=15, height=3, row=2, col=5})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ |
+ ## grid 2
+ 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^. |
+ ## grid 4
+ {1:test }|
+ {1: }|
+ {1:popup text }|
+ ]], float_pos={[4] = {{id = 1002}, "NW", 1, 2, 5, true}}}
+ else
+ screen:expect([[
+ Ut enim ad minim veniam, quis nostrud |
+ exercitation ullamco laboris nisi ut aliquip ex |
+ ea co{1:test }. Duis aute irure dolor in |
+ repre{1: }uptate velit esse cillum |
+ dolor{1:popup text }la pariatur. Excepteur sint |
+ occaecat cupidatat non proident, sunt in culpa |
+ qui officia deserunt mollit anim id est |
+ laborum^. |
+ |
+ ]])
+ end
+
+ meths.win_set_option(win, "winblend", 30)
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ |
+ ## grid 2
+ 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^. |
+ ## grid 4
+ {1:test }|
+ {1: }|
+ {1:popup text }|
+ ]], float_pos={[4] = {{id = 1002}, "NW", 1, 2, 5, true}}, unchanged=true}
+ else
+ screen:expect([[
+ Ut enim ad minim veniam, quis nostrud |
+ exercitation ullamco laboris nisi ut aliquip ex |
+ ea co{2:test}{3:o consequat}. Duis aute irure dolor in |
+ repre{3:henderit in vol}uptate velit esse cillum |
+ dolor{2:popup}{3:fugi}{2:text}{3:ul}la pariatur. Excepteur sint |
+ occaecat cupidatat non proident, sunt in culpa |
+ qui officia deserunt mollit anim id est |
+ laborum^. |
+ |
+ ]])
+ end
+
+ command('hi SpecialRegion guifg=Red blend=0')
+ meths.buf_add_highlight(buf, -1, "SpecialRegion", 2, 0, -1)
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ |
+ ## grid 2
+ 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^. |
+ ## grid 4
+ {1:test }|
+ {1: }|
+ {4:popup text}{1: }|
+ ]], float_pos={[4] = {{id = 1002}, "NW", 1, 2, 5, true}}}
+ else
+ screen:expect([[
+ Ut enim ad minim veniam, quis nostrud |
+ exercitation ullamco laboris nisi ut aliquip ex |
+ ea co{2:test}{3:o consequat}. Duis aute irure dolor in |
+ repre{3:henderit in vol}uptate velit esse cillum |
+ dolor{4:popup text}{3:ul}la pariatur. Excepteur sint |
+ occaecat cupidatat non proident, sunt in culpa |
+ qui officia deserunt mollit anim id est |
+ laborum^. |
+ |
+ ]])
+ end
+
+ command('hi SpecialRegion guifg=Red blend=80')
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ |
+ ## grid 2
+ 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^. |
+ ## grid 4
+ {1:test }|
+ {1: }|
+ {4:popup text}{1: }|
+ ]], float_pos={[4] = {{id = 1002}, "NW", 1, 2, 5, true}}, unchanged=true}
+ else
+ screen:expect([[
+ Ut enim ad minim veniam, quis nostrud |
+ exercitation ullamco laboris nisi ut aliquip ex |
+ ea co{2:test}{3:o consequat}. Duis aute irure dolor in |
+ repre{3:henderit in vol}uptate velit esse cillum |
+ dolor{5:popup}{6:fugi}{5:text}{3:ul}la pariatur. Excepteur sint |
+ occaecat cupidatat non proident, sunt in culpa |
+ qui officia deserunt mollit anim id est |
+ laborum^. |
+ |
+ ]])
+ end
+
+ -- Test scrolling by mouse
+ if multigrid then
+ meths.input_mouse('wheel', 'down', '', 4, 2, 2)
+ screen:expect{grid=[[
+ ## grid 1
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ [2:--------------------------------------------------]|
+ |
+ ## grid 2
+ 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^. |
+ ## grid 4
+ {4:popup text}{1: }|
+ {8:~ }|
+ {8:~ }|
+ ]], float_pos={[4] = {{id = 1002}, "NW", 1, 2, 5, true}}}
+ else
+ meths.input_mouse('wheel', 'down', '', 0, 4, 7)
+ screen:expect([[
+ Ut enim ad minim veniam, quis nostrud |
+ exercitation ullamco laboris nisi ut aliquip ex |
+ ea co{5:popup}{6: con}{5:text}{3:at}. Duis aute irure dolor in |
+ repre{7:~}{3:enderit in vol}uptate velit esse cillum |
+ dolor{7:~}{3: eu fugiat nul}la pariatur. Excepteur sint |
+ occaecat cupidatat non proident, sunt in culpa |
+ qui officia deserunt mollit anim id est |
+ laborum^. |
+ |
+ ]])
+ end
+ end)
+
+ it('can overlap doublewidth chars', function()
+ insert([[
+ # TODO: 测试字典信æ¯çš„准确性
+ # FIXME: 测试字典信æ¯çš„准确性]])
+ local buf = meths.create_buf(false,false)
+ local win = meths.open_win(buf, false, {relative='editor', width=5, height=3, row=0, col=11, style='minimal'})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ # TODO: 测试字典信æ¯çš„准确性 |
+ # FIXME: 测试字典信æ¯çš„准确^性 |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ## grid 3
+ {1: }|
+ {1: }|
+ {1: }|
+ ]], float_pos={ [3] = { { id = 1001 }, "NW", 1, 0, 11, true } }}
+ else
+ screen:expect([[
+ # TODO: 测 {1: }ä¿¡æ¯çš„准确性 |
+ # FIXME: 测{1: } ä¿¡æ¯çš„准确^性 |
+ {0:~ }{1: }{0: }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end
+
+ meths.win_close(win, false)
+ if multigrid then
+ screen:expect([[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ # TODO: 测试字典信æ¯çš„准确性 |
+ # FIXME: 测试字典信æ¯çš„准确^性 |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ ]])
+ else
+ screen:expect([[
+ # TODO: 测试字典信æ¯çš„准确性 |
+ # FIXME: 测试字典信æ¯çš„准确^性 |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end
+
+ -- The interaction between 'winblend' and doublewidth chars in the background
+ -- does not look very good. But check no chars get incorrectly placed
+ -- at least. Also check invisible EndOfBuffer region blends correctly.
+ meths.buf_set_lines(buf, 0, -1, true, {" x x x xx", " x x x x"})
+ win = meths.open_win(buf, false, {relative='editor', width=12, height=3, row=0, col=11, style='minimal'})
+ meths.win_set_option(win, 'winblend', 30)
+ screen:set_default_attr_ids({
+ [1] = {foreground = tonumber('0xb282b2'), background = tonumber('0xffcfff')},
+ [2] = {foreground = Screen.colors.Grey0, background = tonumber('0xffcfff')},
+ [3] = {bold = true, foreground = Screen.colors.Blue1},
+ [4] = {background = tonumber('0xffcfff'), bold = true, foreground = tonumber('0xb282ff')},
+ [5] = {background = Screen.colors.LightMagenta},
+ })
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ # TODO: 测试字典信æ¯çš„准确性 |
+ # FIXME: 测试字典信æ¯çš„准确^性 |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ ## grid 5
+ {5: x x x xx}|
+ {5: x x x x}|
+ {5: }|
+ ]], float_pos={
+ [5] = { {
+ id = 1003
+ }, "NW", 1, 0, 11, true }
+ }}
+ else
+ screen:expect([[
+ # TODO: 测 {2: x x x}{1:æ¯}{2: xx} 确性 |
+ # FIXME: 测{1:试}{2:x x x}{1:æ¯}{2: x}准确^性 |
+ {3:~ }{4: }{3: }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ |
+ ]])
+ end
+
+ meths.win_set_config(win, {relative='editor', row=0, col=12})
+ if multigrid then
+ screen:expect{grid=[[
+ ## grid 1
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ [2:----------------------------------------]|
+ |
+ ## grid 2
+ # TODO: 测试字典信æ¯çš„准确性 |
+ # FIXME: 测试字典信æ¯çš„准确^性 |
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ ## grid 5
+ {5: x x x xx}|
+ {5: x x x x}|
+ {5: }|
+ ]], float_pos={
+ [5] = { {
+ id = 1003
+ }, "NW", 1, 0, 12, true }
+ }}
+ else
+ screen:expect([[
+ # TODO: 测试{2: x x}{1:信}{2:x }{1:的}{2:xx}确性 |
+ # FIXME: 测 {2: x x}{1:信}{2:x }{1:的}{2:x} 确^性 |
+ {3:~ }{4: }{3: }|
+ {3:~ }|
+ {3:~ }|
+ {3:~ }|
+ |
+ ]])
+ end
+ end)
end
describe('with ext_multigrid', function()
diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua
index 5fa299bed9..c5ef718883 100644
--- a/test/functional/ui/fold_spec.lua
+++ b/test/functional/ui/fold_spec.lua
@@ -28,6 +28,22 @@ describe("folded lines", function()
screen:detach()
end)
+ it("work with more than one signcolumn", function()
+ command("set signcolumn=yes:9")
+ feed("i<cr><esc>")
+ feed("vkzf")
+ screen:expect([[
+ {5: ^+-- 2 lines: ·············}|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ |
+ ]])
+ end)
+
it("highlighting with relative line numbers", function()
command("set relativenumber foldmethod=marker")
feed_command("set foldcolumn=2")
diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua
index 85b5aed2f8..08566fe493 100644
--- a/test/functional/ui/highlight_spec.lua
+++ b/test/functional/ui/highlight_spec.lua
@@ -311,6 +311,38 @@ describe('highlight defaults', function()
[1] = {foreground=Screen.colors.Blue},
})
end)
+
+ it('are sent to UIs', function()
+ screen:try_resize(53, 4)
+ screen:set_default_attr_ids({
+ [0] = {},
+ [1] = {bold = true, foreground = Screen.colors.Blue1},
+ [2] = {bold = true, reverse = true},
+ [3] = {italic=true}
+ })
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ |
+ ]], hl_groups={EndOfBuffer=1, MsgSeparator=2}}
+
+ command('highlight EndOfBuffer gui=italic')
+ screen:expect{grid=[[
+ ^ |
+ {3:~ }|
+ {3:~ }|
+ |
+ ]], hl_groups={EndOfBuffer=3, MsgSeparator=2}}
+
+ command('highlight clear EndOfBuffer')
+ screen:expect{grid=[[
+ ^ |
+ ~ |
+ ~ |
+ |
+ ]], hl_groups={EndOfBuffer=0, MsgSeparator=2}}
+ end)
end)
describe('highlight', function()
diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua
index 8924a4b824..ed65c4526f 100644
--- a/test/functional/ui/messages_spec.lua
+++ b/test/functional/ui/messages_spec.lua
@@ -5,12 +5,12 @@ local eval = helpers.eval
local eq = helpers.eq
local command = helpers.command
local set_method_error = helpers.set_method_error
+local meths = helpers.meths
local test_build_dir = helpers.test_build_dir
local nvim_prog = helpers.nvim_prog
local iswin = helpers.iswin
local exc_exec = helpers.exc_exec
-
describe('ui/ext_messages', function()
local screen
@@ -25,6 +25,8 @@ describe('ui/ext_messages', function()
[4] = {bold = true, foreground = Screen.colors.SeaGreen4},
[5] = {foreground = Screen.colors.Blue1},
[6] = {bold = true, reverse = true},
+ [7] = {background = Screen.colors.Yellow},
+ [8] = {foreground = Screen.colors.Red},
})
end)
after_each(function()
@@ -307,6 +309,65 @@ describe('ui/ext_messages', function()
}}
end)
+ it('shortmess-=S', function()
+ command('set shortmess-=S')
+ feed('iline 1\nline 2<esc>')
+
+ feed('/line<cr>')
+ screen:expect{grid=[[
+ {7:^line} 1 |
+ {7:line} 2 |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], messages={
+ {content = {{"/line [1/2] W"}}, kind = "search_count"}
+ }}
+
+ feed('n')
+ screen:expect{grid=[[
+ {7:line} 1 |
+ {7:^line} 2 |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], messages={
+ {content = {{"/line [2/2]"}}, kind = "search_count"}
+ }}
+ end)
+
+ it(':hi Group output', function()
+ feed(':hi ErrorMsg<cr>')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], messages={
+ {content = {{"\nErrorMsg " }, {"xxx", 2}, {" "},
+ {"ctermfg=", 5 }, { "15 " }, { "ctermbg=", 5 }, { "1 " },
+ {"guifg=", 5 }, { "White " }, { "guibg=", 5 }, { "Red" }},
+ kind = ""}
+ }}
+ end)
+
+ it("doesn't crash with column adjustment #10069", function()
+ feed(':let [x,y] = [1,2]<cr>')
+ feed(':let x y<cr>')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ ]], messages={
+ {content = {{ "x #1" }}, kind = ""},
+ {content = {{ "y #2" }}, kind = ""},
+ {content = {{ "Press ENTER or type command to continue", 4 }}, kind = "return_prompt"}
+ }}
+ end)
+
it('&showmode', function()
command('imap <f2> <cmd>echomsg "stuff"<cr>')
feed('i')
@@ -573,7 +634,7 @@ describe('ui/ext_messages', function()
{1:~ }|
{1:~ }|
]], messages={{
- content = {{ "Type :qa! and press <Enter> to abandon all changes and exit Nvim" }},
+ content = {{ "Type :qa and press <Enter> to exit Nvim" }},
kind = ""}
}}
@@ -620,7 +681,7 @@ describe('ui/ext_messages', function()
{1:~ }|
]], messages={
{kind="echomsg", content={{"howdy"}}},
- {kind="", content={{"Type :qa! and press <Enter> to abandon all changes and exit Nvim"}}},
+ {kind="", content={{"Type :qa and press <Enter> to exit Nvim"}}},
{kind="echoerr", content={{"bork", 2}}},
{kind="emsg", content={{"E117: Unknown function: nosuchfunction", 2}}}
}}
@@ -745,6 +806,8 @@ describe('ui/builtin messages', function()
[2] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red},
[3] = {bold = true, reverse = true},
[4] = {bold = true, foreground = Screen.colors.SeaGreen4},
+ [5] = {foreground = Screen.colors.Blue1},
+ [6] = {bold = true, foreground = Screen.colors.Magenta},
})
end)
@@ -765,6 +828,78 @@ describe('ui/builtin messages', function()
end
end}
end)
+
+ it(':hi Group output', function()
+ screen:try_resize(70,7)
+ feed(':hi ErrorMsg<cr>')
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {3: }|
+ :hi ErrorMsg |
+ ErrorMsg {2:xxx} {5:ctermfg=}15 {5:ctermbg=}1 {5:guifg=}White {5:guibg=}Red |
+ {4:Press ENTER or type command to continue}^ |
+ ]])
+
+ feed('<cr>')
+ screen:try_resize(30,7)
+ feed(':hi ErrorMsg<cr>')
+ screen:expect([[
+ :hi ErrorMsg |
+ ErrorMsg {2:xxx} {5:ctermfg=}15 |
+ {5:ctermbg=}1 |
+ {5:guifg=}White|
+ {5:guibg=}Red |
+ {4:Press ENTER or type command to}|
+ {4: continue}^ |
+ ]])
+ feed('<cr>')
+
+ -- screen size doesn't affect internal output #10285
+ eq('ErrorMsg xxx ctermfg=15 ctermbg=1 guifg=White guibg=Red',
+ meths.command_output("hi ErrorMsg"))
+ end)
+
+ it(':syntax list langGroup output', function()
+ command("syntax on")
+ command("set syntax=vim")
+ screen:try_resize(110,7)
+ feed(':syntax list vimComment<cr>')
+ screen:expect([[
+ {6:--- Syntax items ---} |
+ vimComment {5:xxx} {5:match} /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 {5:excludenl} {5:contains}=@vimCommentGroup,vimCommentString |
+ |
+ {5:match} /\<endif\s\+".*$/ms=s+5,lc=5 {5:contains}=@vimCommentGroup,vimCommentString |
+ {5:match} /\<else\s\+".*$/ms=s+4,lc=4 {5:contains}=@vimCommentGroup,vimCommentString |
+ {5:links to} Comment |
+ {4:Press ENTER or type command to continue}^ |
+ ]])
+
+ feed('<cr>')
+ screen:try_resize(55,7)
+ feed(':syntax list vimComment<cr>')
+ screen:expect([[
+ |
+ {5:match} /\<endif\s\+".*$/ms=s+5,lc=5 |
+ {5:contains}=@vimCommentGroup,vimCommentString |
+ {5:match} /\<else\s\+".*$/ms=s+4,lc=4 {5:c}|
+ {5:ontains}=@vimCommentGroup,vimCommentString |
+ {5:links to} Comment |
+ {4:Press ENTER or type command to continue}^ |
+ ]])
+ feed('<cr>')
+
+ -- ignore final whitespace inside string
+ -- luacheck: push ignore
+ eq([[--- Syntax items ---
+vimComment xxx match /\s"[^\-:.%#=*].*$/ms=s+1,lc=1 excludenl contains=@vimCommentGroup,vimCommentString
+ match /\<endif\s\+".*$/ms=s+5,lc=5 contains=@vimCommentGroup,vimCommentString
+ match /\<else\s\+".*$/ms=s+4,lc=4 contains=@vimCommentGroup,vimCommentString
+ links to Comment]],
+ meths.command_output('syntax list vimComment'))
+ -- luacheck: pop
+ end)
end)
describe('ui/ext_messages', function()
diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua
index c1a350dc34..3bd6b81ff1 100644
--- a/test/functional/ui/mouse_spec.lua
+++ b/test/functional/ui/mouse_spec.lua
@@ -150,13 +150,6 @@ describe('ui/mouse/input', function()
end)
it('in tabline to the left moves tab left', function()
- if helpers.skip_fragile(pending,
- os.getenv("TRAVIS") and (helpers.os_name() == "osx"
- or os.getenv("CLANG_SANITIZER") == "ASAN_UBSAN")) -- #4874
- then
- return
- end
-
feed_command('%delete')
insert('this is foo')
feed_command('silent file foo | tabnew | file bar')
diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua
index 38c4527a5b..24bf66e2d8 100644
--- a/test/functional/ui/output_spec.lua
+++ b/test/functional/ui/output_spec.lua
@@ -51,12 +51,7 @@ describe("shell command :!", function()
end)
it("throttles shell-command output greater than ~10KB", function()
- if helpers.skip_fragile(pending,
- (os.getenv("TRAVIS") and helpers.os_name() == "osx")) then
- return
- end
- child_session.feed_data(
- ":!for i in $(seq 2 30000); do echo XXXXXXXXXX $i; done\n")
+ child_session.feed_data(":!"..nvim_dir.."/shell-test REP_NODELAY 30001 foo\n")
-- If we observe any line starting with a dot, then throttling occurred.
-- Avoid false failure on slow systems.
@@ -65,10 +60,10 @@ describe("shell command :!", function()
-- Final chunk of output should always be displayed, never skipped.
-- (Throttling is non-deterministic, this test is merely a sanity check.)
screen:expect([[
- XXXXXXXXXX 29997 |
- XXXXXXXXXX 29998 |
- XXXXXXXXXX 29999 |
- XXXXXXXXXX 30000 |
+ 29997: foo |
+ 29998: foo |
+ 29999: foo |
+ 30000: foo |
|
{10:Press ENTER or type command to continue}{1: } |
{3:-- TERMINAL --} |
diff --git a/test/functional/ui/popupmenu_spec.lua b/test/functional/ui/popupmenu_spec.lua
index b457ebebab..9bfea28ed7 100644
--- a/test/functional/ui/popupmenu_spec.lua
+++ b/test/functional/ui/popupmenu_spec.lua
@@ -6,6 +6,7 @@ local insert = helpers.insert
local meths = helpers.meths
local command = helpers.command
local funcs = helpers.funcs
+local get_pathsep = helpers.get_pathsep
describe('ui/ext_popupmenu', function()
local screen
@@ -1151,6 +1152,50 @@ describe('builtin popupmenu', function()
]])
end)
+ it('behaves correcty with VimResized autocmd', function()
+ feed('isome long prefix before the ')
+ command("set completeopt+=noinsert,noselect")
+ command("autocmd VimResized * redraw!")
+ command("set linebreak")
+ funcs.complete(29, {'word', 'choice', 'text', 'thing'})
+ screen:expect([[
+ some long prefix before the ^ |
+ {1:~ }{n: word }|
+ {1:~ }{n: choice}|
+ {1:~ }{n: text }|
+ {1:~ }{n: thing }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]])
+
+ screen:try_resize(16,10)
+ screen:expect([[
+ some long |
+ prefix before |
+ the ^ |
+ {1:~ }{n: word }|
+ {1:~ }{n: choice }|
+ {1:~ }{n: text }|
+ {1:~ }{n: thing }|
+ {1:~ }|
+ {1:~ }|
+ {2:-- INSERT --} |
+ ]])
+ end)
+
it('works with rightleft window', function()
command("set rl")
feed('isome rightleft ')
@@ -1503,6 +1548,53 @@ describe('builtin popupmenu', function()
{3:lå}{n: långfile2 }{3: }|
:b långfile1^ |
]])
+
+ -- position is calculated correctly with "longest"
+ feed('<esc>')
+ command('set wildmode=longest:full,full')
+ feed(':b lå<tab>')
+ screen:expect([[
+ |
+ {1:~ }|
+ {4:långfile2 }|
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }{n: långfile1 }{1: }|
+ {3:lå}{n: långfile2 }{3: }|
+ :b långfile^ |
+ ]])
+
+ -- special case: when patterns ends with "/", show menu items aligned
+ -- after the "/"
+ feed('<esc>')
+ command("close")
+ command('set wildmode=full')
+ command("cd test/functional/fixtures/")
+ feed(':e compdir/<tab>')
+ screen:expect([[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }{s: file1 }{1: }|
+ {1:~ }{n: file2 }{1: }|
+ :e compdir]]..get_pathsep()..[[file1^ |
+ ]])
end)
it("'pumblend' RGB-color", function()
@@ -1662,6 +1754,26 @@ describe('builtin popupmenu', function()
{20:-- Keyword Local completion (^N^P) }{21:match 1 of 65} |
]])
+ -- can disable blending for indiviual attribute. For instance current
+ -- selected item. (also tests that `hi Pmenu*` take immediate effect)
+ command('hi PMenuSel blend=0')
+ screen:expect([[
+ Lorem ipsum d{1:ol}or sit amet, consectetur |
+ adipisicing elit, sed do eiusmod tempor |
+ bla bla incididunt^ |
+ incidid{22: incididunt }{27: }d{1:ol}ore magna aliqua. |
+ Ut enim{28: }{29:ut}{28: minim veniam}{25:,} quis nostrud |
+ exercit{28:a}{29:labore}{28:llamco la}{25:b}oris nisi ut aliquip ex |
+ {2:[No Nam}{30:e}{43:et}{30:[+] }{32: }{2: }|
+ incidid{28:u}{29:dol}{41:or}{29:e}{28:labore et}{25: }d{1:ol}ore magna aliqua. |
+ Ut enim{28: }{29:magna}{28:nim veniam}{25:,} quis nostrud |
+ exercit{28:a}{29:aliqua}{28:llamco la}{25:b}oris nisi {4:ut} aliquip ex |
+ ea comm{28:o}{29:Ut}{28: consequat. D}{25:u}is a{4:ut}e irure d{1:ol}or in |
+ reprehe{28:n}{29:enim}{28:t in v}{34:ol}{28:upt}{25:a}te v{3:el}it esse cillum |
+ {5:[No Nam}{38:e}{44:ad}{38:[+] }{40: }{5: }|
+ {20:-- Keyword Local completion (^N^P) }{21:match 1 of 65} |
+ ]])
+
feed('<c-e>')
screen:expect([[
Lorem ipsum d{1:ol}or sit amet, consectetur |
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index 044e4cc39c..81a15cada2 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -81,7 +81,7 @@ local dedent = helpers.dedent
local get_session = helpers.get_session
local create_callindex = helpers.create_callindex
-local inspect = require('inspect')
+local inspect = require('vim.inspect')
local function isempty(v)
return type(v) == 'table' and next(v) == nil
@@ -165,6 +165,7 @@ function Screen.new(width, height)
showmode = {},
showcmd = {},
ruler = {},
+ hl_groups = {},
_default_attr_ids = nil,
_default_attr_ignore = nil,
_mouse_enabled = true,
@@ -322,7 +323,7 @@ function Screen:expect(expected, attr_ids, attr_ignore)
assert(not (attr_ids ~= nil or attr_ignore ~= nil))
local is_key = {grid=true, attr_ids=true, attr_ignore=true, condition=true,
any=true, mode=true, unchanged=true, intermediate=true,
- reset=true, timeout=true, request_cb=true}
+ reset=true, timeout=true, request_cb=true, hl_groups=true}
for _, v in ipairs(ext_keys) do
is_key[v] = true
end
@@ -418,9 +419,10 @@ screen:redraw_debug() to show all intermediate screen states. ]])
-- (e.g. no external cmdline visible). Some extensions require
-- preprocessing to represent highlights in a reproducible way.
local extstate = self:_extstate_repr(attr_state)
- if expected['mode'] ~= nil then
- extstate['mode'] = self.mode
+ if expected.mode ~= nil then
+ extstate.mode = self.mode
end
+
-- Convert assertion errors into invalid screen state descriptions.
for _, k in ipairs(concat_tables(ext_keys, {'mode'})) do
-- Empty states are considered the default and need not be mentioned.
@@ -431,9 +433,32 @@ screen:redraw_debug() to show all intermediate screen states. ]])
end
end
end
+
+ if expected.hl_groups ~= nil then
+ for name, id in pairs(expected.hl_groups) do
+ local expected_hl = attr_state.ids[id]
+ local actual_hl = self._attr_table[self.hl_groups[name]][(self._options.rgb and 1) or 2]
+ local status, res = pcall(eq, expected_hl, actual_hl, "highlight "..name)
+ if not status then
+ return tostring(res)
+ end
+ end
+ end
end, expected)
end
+function Screen:expect_unchanged(waittime_ms, ignore_attrs, request_cb)
+ waittime_ms = waittime_ms and waittime_ms or 100
+ -- Collect the current screen state.
+ self:sleep(0, request_cb)
+ local kwargs = self:get_snapshot(nil, ignore_attrs)
+
+ -- Check that screen state does not change.
+ kwargs.unchanged = true
+ kwargs.timeout = waittime_ms
+ self:expect(kwargs)
+end
+
function Screen:_wait(check, flags)
local err, checked = false, false
local success_seen = false
@@ -464,8 +489,8 @@ function Screen:_wait(check, flags)
immediate_seen = true
end
- -- for an unchanged test, flags.timeout means the time during the state is
- -- expected to be unchanged, so always wait this full time.
+ -- For an "unchanged" test, flags.timeout is the time during which the state
+ -- must not change, so always wait this full time.
if (flags.unchanged or flags.intermediate) and flags.timeout ~= nil then
minimal_timeout = timeout
end
@@ -492,7 +517,7 @@ function Screen:_wait(check, flags)
end
elseif success_seen and #args > 0 then
failure_after_success = true
- --print(require('inspect')(args))
+ -- print(inspect(args))
end
return true
@@ -576,8 +601,7 @@ end
function Screen:_redraw(updates)
local did_flush = false
for k, update in ipairs(updates) do
- -- print('--')
- -- print(require('inspect')(update))
+ -- print('--', inspect(update))
local method = update[1]
for i = 2, #update do
local handler_name = '_handle_'..method
@@ -837,6 +861,10 @@ function Screen:_handle_hl_attr_define(id, rgb_attrs, cterm_attrs, info)
self._new_attrs = true
end
+function Screen:_handle_hl_group_set(name, id)
+ self.hl_groups[name] = id
+end
+
function Screen:get_hl(val)
if self._options.ext_newgrid then
return self._attr_table[val][1]
@@ -946,6 +974,14 @@ function Screen:_handle_cmdline_show(content, pos, firstc, prompt, indent, level
if firstc == '' then firstc = nil end
if prompt == '' then prompt = nil end
if indent == 0 then indent = nil end
+
+ -- check position is valid #10000
+ local len = 0
+ for _, chunk in ipairs(content) do
+ len = len + string.len(chunk[2])
+ end
+ assert(pos <= len)
+
self.cmdline[level] = {content=content, pos=pos, firstc=firstc,
prompt=prompt, indent=indent}
end
@@ -1186,7 +1222,13 @@ function Screen:render(headers, attr_state, preview)
return rv
end
-function Screen:print_snapshot(attrs, ignore)
+local remove_all_metatables = function(item, path)
+ if path[#path] ~= inspect.METATABLE then return item end
+end
+
+-- Returns the current screen state in the form of a screen:expect()
+-- keyword-args map.
+function Screen:get_snapshot(attrs, ignore)
attrs = attrs or self._default_attr_ids
if ignore == nil then
ignore = self._default_attr_ignore
@@ -1209,15 +1251,32 @@ function Screen:print_snapshot(attrs, ignore)
local lines = self:render(true, attr_state, true)
local ext_state = self:_extstate_repr(attr_state)
- local keys = false
for k, v in pairs(ext_state) do
if isempty(v) then
ext_state[k] = nil -- deleting keys while iterating is ok
- else
- keys = true
end
end
+ -- Build keyword-args for screen:expect().
+ local kwargs = {}
+ if attr_state.modified then
+ kwargs['attr_ids'] = {}
+ for i, a in pairs(attr_state.ids) do
+ kwargs['attr_ids'][i] = a
+ end
+ end
+ kwargs['grid'] = table.concat(lines, '\n')
+ for _, k in ipairs(ext_keys) do
+ if ext_state[k] ~= nil then
+ kwargs[k] = ext_state[k]
+ end
+ end
+
+ return kwargs, ext_state, attr_state
+end
+
+function Screen:print_snapshot(attrs, ignore)
+ local kwargs, ext_state, attr_state = self:get_snapshot(attrs, ignore)
local attrstr = ""
if attr_state.modified then
local attrstrs = {}
@@ -1231,19 +1290,18 @@ function Screen:print_snapshot(attrs, ignore)
local keyval = (type(i) == "number") and "["..tostring(i).."]" or i
table.insert(attrstrs, " "..keyval.." = "..dict..",")
end
- attrstr = (", "..(keys and "attr_ids=" or "")
- .."{\n"..table.concat(attrstrs, "\n").."\n}")
+ attrstr = (", attr_ids={\n"..table.concat(attrstrs, "\n").."\n}")
end
- print( "\nscreen:expect"..(keys and "{grid=" or "(").."[[")
- print( table.concat(lines, '\n'))
+ print( "\nscreen:expect{grid=[[")
+ print(kwargs.grid)
io.stdout:write( "]]"..attrstr)
for _, k in ipairs(ext_keys) do
if ext_state[k] ~= nil then
- -- TODO(bfredl): improve formating, remove ext metatables
- io.stdout:write(", "..k.."="..inspect(ext_state[k]))
+ -- TODO(bfredl): improve formatting
+ io.stdout:write(", "..k.."="..inspect(ext_state[k],{process=remove_all_metatables}))
end
end
- print((keys and "}" or ")").."\n")
+ print("}\n")
io.stdout:flush()
end
@@ -1327,7 +1385,7 @@ end
function Screen:_pprint_hlstate(item)
- --print(require('inspect')(item))
+ -- print(inspect(item))
local attrdict = "{"..self:_pprint_attrs(item[1]).."}, "
local attrdict2, hlinfo
if self._hlstate_cterm then
@@ -1400,17 +1458,17 @@ function Screen:_get_attr_id(attr_state, attrs, hl_id)
end
return "UNEXPECTED "..self:_pprint_attrs(self._attr_table[hl_id][1])
else
- for id, a in pairs(attr_state.ids) do
- if self:_equal_attrs(a, attrs) then
- return id
- end
- end
if self:_equal_attrs(attrs, {}) or
attr_state.ignore == true or
self:_attr_index(attr_state.ignore, attrs) ~= nil then
-- ignore this attrs
return nil
end
+ for id, a in pairs(attr_state.ids) do
+ if self:_equal_attrs(a, attrs) then
+ return id
+ end
+ end
if attr_state.mutable then
table.insert(attr_state.ids, attrs)
attr_state.modified = true
diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua
index 65ae124353..486de02a09 100644
--- a/test/functional/ui/searchhl_spec.lua
+++ b/test/functional/ui/searchhl_spec.lua
@@ -5,8 +5,7 @@ local command = helpers.command
local feed_command = helpers.feed_command
local eq = helpers.eq
local eval = helpers.eval
-local iswin = helpers.iswin
-local sleep = helpers.sleep
+local nvim_dir = helpers.nvim_dir
describe('search highlighting', function()
local screen
@@ -148,13 +147,10 @@ describe('search highlighting', function()
end)
it('is preserved during :terminal activity', function()
- if iswin() then
- feed([[:terminal for /L \%I in (1,1,5000) do @(echo xxx & echo xxx & echo xxx)<cr>]])
- else
- feed([[:terminal for i in $(seq 1 5000); do printf 'xxx\nxxx\nxxx\n'; done<cr>]])
- end
+ feed([[:terminal "]]..nvim_dir..[[/shell-test" REP 5000 foo<cr>]])
feed(':file term<CR>')
+ feed('G') -- Follow :terminal output.
feed(':vnew<CR>')
insert([[
foo bar baz
@@ -162,23 +158,8 @@ describe('search highlighting', function()
bar foo baz
]])
feed('/foo')
- sleep(50) -- Allow some terminal activity.
- -- NB: in earlier versions terminal output was redrawn during cmdline mode.
- -- For now just assert that the screens remain unchanged.
- screen:expect([[
- {3:foo} bar baz {3:│} |
- bar baz {2:foo} {3:│} |
- bar {2:foo} baz {3:│} |
- {3:│} |
- {1:~ }{3:│} |
- {5:[No Name] [+] }{3:term }|
- /foo^ |
- ]], { [1] = {bold = true, foreground = Screen.colors.Blue1},
- [2] = {background = Screen.colors.Yellow},
- [3] = {reverse = true},
- [4] = {foreground = Screen.colors.Red},
- [5] = {bold = true, reverse = true},
- })
+ helpers.wait()
+ screen:expect_unchanged()
end)
it('works with incsearch', function()
diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua
index 2b38a2a58d..68e675b8e5 100644
--- a/test/functional/ui/sign_spec.lua
+++ b/test/functional/ui/sign_spec.lua
@@ -31,6 +31,30 @@ describe('Signs', function()
end)
describe(':sign place', function()
+ it('allows signs with combining characters', function()
+ feed('ia<cr>b<cr><esc>')
+ command('sign define piet1 text=ðŒ¢Ì€Ì̂̃̅̄ðŒ¢Ì€Ì̂̃̅̄ texthl=Search')
+ command('sign define piet2 text=𠜎̀Ì̂̃̄̅ texthl=Search')
+ command('sign place 1 line=1 name=piet1 buffer=1')
+ command('sign place 2 line=2 name=piet2 buffer=1')
+ screen:expect([[
+ {1:ðŒ¢Ì€Ì̂̃̅̄ðŒ¢Ì€Ì̂̃̅̄}a |
+ {1:𠜎̀Ì̂̃̄̅}b |
+ {2: }^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ end)
+
it('shadows previously placed signs', function()
feed('ia<cr>b<cr>c<cr><esc>')
command('sign define piet text=>> texthl=Search')
diff --git a/test/helpers.lua b/test/helpers.lua
index 3311f3ef97..e14bcff2c8 100644
--- a/test/helpers.lua
+++ b/test/helpers.lua
@@ -15,7 +15,11 @@ local function shell_quote(str)
end
end
-local function argss_to_cmd(...)
+local module = {
+ REMOVE_THIS = {},
+}
+
+function module.argss_to_cmd(...)
local cmd = ''
for i = 1, select('#', ...) do
local arg = select(i, ...)
@@ -30,16 +34,16 @@ local function argss_to_cmd(...)
return cmd
end
-local function popen_r(...)
- return io.popen(argss_to_cmd(...), 'r')
+function module.popen_r(...)
+ return io.popen(module.argss_to_cmd(...), 'r')
end
-local function popen_w(...)
- return io.popen(argss_to_cmd(...), 'w')
+function module.popen_w(...)
+ return io.popen(module.argss_to_cmd(...), 'w')
end
-- sleeps the test runner (_not_ the nvim instance)
-local function sleep(ms)
+function module.sleep(ms)
luv.sleep(ms)
end
@@ -49,26 +53,26 @@ local check_logs_useless_lines = {
['See README_MISSING_SYSCALL_OR_IOCTL for guidance']=3,
}
-local function eq(expected, actual, context)
+function module.eq(expected, actual, context)
return assert.are.same(expected, actual, context)
end
-local function neq(expected, actual, context)
+function module.neq(expected, actual, context)
return assert.are_not.same(expected, actual, context)
end
-local function ok(res)
+function module.ok(res)
return assert.is_true(res)
end
-local function near(actual, expected, tolerance)
+function module.near(actual, expected, tolerance)
return assert.is.near(actual, expected, tolerance)
end
-local function matches(pat, actual)
+function module.matches(pat, actual)
if nil ~= string.match(actual, pat) then
return true
end
error(string.format('Pattern does not match.\nPattern:\n%s\nActual:\n%s', pat, actual))
end
-- Expect an error matching pattern `pat`.
-local function expect_err(pat, ...)
+function module.expect_err(pat, ...)
local fn = select(1, ...)
local fn_args = {...}
table.remove(fn_args, 1)
@@ -78,7 +82,7 @@ end
-- initial_path: directory to recurse into
-- re: include pattern (string)
-- exc_re: exclude pattern(s) (string or table)
-local function glob(initial_path, re, exc_re)
+function module.glob(initial_path, re, exc_re)
exc_re = type(exc_re) == 'table' and exc_re or { exc_re }
local paths_to_check = {initial_path}
local ret = {}
@@ -118,7 +122,7 @@ local function glob(initial_path, re, exc_re)
return ret
end
-local function check_logs()
+function module.check_logs()
local log_dir = os.getenv('LOG_DIR')
local runtime_errors = 0
if log_dir and lfs.attributes(log_dir, 'mode') == 'directory' then
@@ -153,7 +157,7 @@ local function check_logs()
end
-- Tries to get platform name from $SYSTEM_NAME, uname; fallback is "Windows".
-local uname = (function()
+module.uname = (function()
local platform = nil
return (function()
if platform then
@@ -165,7 +169,7 @@ local uname = (function()
return platform
end
- local status, f = pcall(popen_r, 'uname', '-s')
+ local status, f = pcall(module.popen_r, 'uname', '-s')
if status then
platform = f:read("*l")
f:close()
@@ -185,7 +189,7 @@ local function tmpdir_is_local(dir)
return not not (dir and string.find(dir, 'Xtest'))
end
-local tmpname = (function()
+module.tmpname = (function()
local seq = 0
local tmpdir = tmpdir_get()
return (function()
@@ -197,11 +201,11 @@ local tmpname = (function()
return fname
else
local fname = os.tmpname()
- if uname() == 'Windows' and fname:sub(1, 2) == '\\s' then
+ if module.uname() == 'Windows' and fname:sub(1, 2) == '\\s' then
-- In Windows tmpname() returns a filename starting with
-- special sequence \s, prepend $TEMP path
return tmpdir..fname
- elseif fname:match('^/tmp') and uname() == 'Darwin' then
+ elseif fname:match('^/tmp') and module.uname() == 'Darwin' then
-- In OS X /tmp links to /private/tmp
return '/private'..fname
else
@@ -211,7 +215,7 @@ local tmpname = (function()
end)
end)()
-local function map(func, tab)
+function module.map(func, tab)
local rettab = {}
for k, v in pairs(tab) do
rettab[k] = func(v)
@@ -219,7 +223,7 @@ local function map(func, tab)
return rettab
end
-local function filter(filter_func, tab)
+function module.filter(filter_func, tab)
local rettab = {}
for _, entry in pairs(tab) do
if filter_func(entry) then
@@ -229,7 +233,7 @@ local function filter(filter_func, tab)
return rettab
end
-local function hasenv(name)
+function module.hasenv(name)
local env = os.getenv(name)
if env and env ~= '' then
return env
@@ -244,7 +248,7 @@ end
local tests_skipped = 0
-local function check_cores(app, force)
+function module.check_cores(app, force)
app = app or 'build/bin/nvim'
local initial_path, re, exc_re
local gdb_db_cmd = 'gdb -n -batch -ex "thread apply all bt full" "$_NVIM_TEST_APP" -c "$_NVIM_TEST_CORE"'
@@ -256,7 +260,7 @@ local function check_cores(app, force)
and relpath(tmpdir_get()):gsub('^[ ./]+',''):gsub('%/+$',''):gsub('([^%w])', '%%%1')
or nil)
local db_cmd
- if hasenv('NVIM_TEST_CORE_GLOB_DIRECTORY') then
+ if module.hasenv('NVIM_TEST_CORE_GLOB_DIRECTORY') then
initial_path = os.getenv('NVIM_TEST_CORE_GLOB_DIRECTORY')
re = os.getenv('NVIM_TEST_CORE_GLOB_RE')
exc_re = { os.getenv('NVIM_TEST_CORE_EXC_RE'), local_tmpdir }
@@ -279,7 +283,7 @@ local function check_cores(app, force)
tests_skipped = tests_skipped + 1
return
end
- local cores = glob(initial_path, re, exc_re)
+ local cores = module.glob(initial_path, re, exc_re)
local found_cores = 0
local out = io.stdout
for _, core in ipairs(cores) do
@@ -301,8 +305,8 @@ local function check_cores(app, force)
end
end
-local function which(exe)
- local pipe = popen_r('which', exe)
+function module.which(exe)
+ local pipe = module.popen_r('which', exe)
local ret = pipe:read('*a')
pipe:close()
if ret == '' then
@@ -312,20 +316,20 @@ local function which(exe)
end
end
-local function repeated_read_cmd(...)
+function module.repeated_read_cmd(...)
for _ = 1, 10 do
- local stream = popen_r(...)
+ local stream = module.popen_r(...)
local ret = stream:read('*a')
stream:close()
if ret then
return ret
end
end
- print('ERROR: Failed to execute ' .. argss_to_cmd(...) .. ': nil return after 10 attempts')
+ print('ERROR: Failed to execute ' .. module.argss_to_cmd(...) .. ': nil return after 10 attempts')
return nil
end
-local function shallowcopy(orig)
+function module.shallowcopy(orig)
if type(orig) ~= 'table' then
return orig
end
@@ -336,15 +340,13 @@ local function shallowcopy(orig)
return copy
end
-local REMOVE_THIS = {}
-
-local function mergedicts_copy(d1, d2)
- local ret = shallowcopy(d1)
+function module.mergedicts_copy(d1, d2)
+ local ret = module.shallowcopy(d1)
for k, v in pairs(d2) do
- if d2[k] == REMOVE_THIS then
+ if d2[k] == module.REMOVE_THIS then
ret[k] = nil
elseif type(d1[k]) == 'table' and type(v) == 'table' then
- ret[k] = mergedicts_copy(d1[k], v)
+ ret[k] = module.mergedicts_copy(d1[k], v)
else
ret[k] = v
end
@@ -355,16 +357,16 @@ end
-- dictdiff: find a diff so that mergedicts_copy(d1, diff) is equal to d2
--
-- Note: does not do copies of d2 values used.
-local function dictdiff(d1, d2)
+function module.dictdiff(d1, d2)
local ret = {}
local hasdiff = false
for k, v in pairs(d1) do
if d2[k] == nil then
hasdiff = true
- ret[k] = REMOVE_THIS
+ ret[k] = module.REMOVE_THIS
elseif type(v) == type(d2[k]) then
if type(v) == 'table' then
- local subdiff = dictdiff(v, d2[k])
+ local subdiff = module.dictdiff(v, d2[k])
if subdiff ~= nil then
hasdiff = true
ret[k] = subdiff
@@ -378,6 +380,7 @@ local function dictdiff(d1, d2)
hasdiff = true
end
end
+ local shallowcopy = module.shallowcopy
for k, v in pairs(d2) do
if d1[k] == nil then
ret[k] = shallowcopy(v)
@@ -391,7 +394,7 @@ local function dictdiff(d1, d2)
end
end
-local function updated(d, d2)
+function module.updated(d, d2)
for k, v in pairs(d2) do
d[k] = v
end
@@ -399,7 +402,7 @@ local function updated(d, d2)
end
-- Concat list-like tables.
-local function concat_tables(...)
+function module.concat_tables(...)
local ret = {}
for i = 1, select('#', ...) do
local tbl = select(i, ...)
@@ -412,7 +415,7 @@ local function concat_tables(...)
return ret
end
-local function dedent(str, leave_indent)
+function module.dedent(str, leave_indent)
-- find minimum common indent across lines
local indent = nil
for line in str:gmatch('[^\n]+') do
@@ -452,9 +455,7 @@ local SUBTBL = {
'\\030', '\\031',
}
-local format_luav
-
-format_luav = function(v, indent, opts)
+function module.format_luav(v, indent, opts)
opts = opts or {}
local linesep = '\n'
local next_indent_arg = nil
@@ -484,12 +485,13 @@ format_luav = function(v, indent, opts)
end) .. quote
end
elseif type(v) == 'table' then
- if v == REMOVE_THIS then
+ if v == module.REMOVE_THIS then
ret = 'REMOVE_THIS'
else
local processed_keys = {}
ret = '{' .. linesep
local non_empty = false
+ local format_luav = module.format_luav
for i, subv in ipairs(v) do
ret = ('%s%s%s,%s'):format(ret, next_indent,
format_luav(subv, next_indent_arg, opts), nl)
@@ -531,7 +533,7 @@ format_luav = function(v, indent, opts)
return ret
end
-local function format_string(fmt, ...)
+function module.format_string(fmt, ...)
local i = 0
local args = {...}
local function getarg()
@@ -552,7 +554,7 @@ local function format_string(fmt, ...)
-- Builtin %q is replaced here as it gives invalid and inconsistent with
-- luajit results for e.g. "\e" on lua: luajit transforms that into `\27`,
-- lua leaves as-is.
- arg = format_luav(arg, nil, {dquote_strings = (subfmt:sub(-1) == 'q')})
+ arg = module.format_luav(arg, nil, {dquote_strings = (subfmt:sub(-1) == 'q')})
subfmt = subfmt:sub(1, -2) .. 's'
end
if subfmt == '%e' then
@@ -564,7 +566,7 @@ local function format_string(fmt, ...)
return ret
end
-local function intchar2lua(ch)
+function module.intchar2lua(ch)
ch = tonumber(ch)
return (20 <= ch and ch < 127) and ('%c'):format(ch) or ch
end
@@ -575,20 +577,21 @@ local fixtbl_metatable = {
end,
}
-local function fixtbl(tbl)
+function module.fixtbl(tbl)
return setmetatable(tbl, fixtbl_metatable)
end
-local function fixtbl_rec(tbl)
+function module.fixtbl_rec(tbl)
+ local fixtbl_rec = module.fixtbl_rec
for _, v in pairs(tbl) do
if type(v) == 'table' then
fixtbl_rec(v)
end
end
- return fixtbl(tbl)
+ return module.fixtbl(tbl)
end
-local function hexdump(str)
+function module.hexdump(str)
local len = string.len(str)
local dump = ""
local hex = ""
@@ -617,7 +620,7 @@ end
--
-- filename: path to file
-- start: start line (1-indexed), negative means "lines before end" (tail)
-local function read_file_list(filename, start)
+function module.read_file_list(filename, start)
local lnum = (start ~= nil and type(start) == 'number') and start or 1
local tail = (lnum < 0)
local maxlines = tail and math.abs(lnum) or nil
@@ -643,7 +646,7 @@ end
-- Reads the entire contents of `filename` into a string.
--
-- filename: path to file
-local function read_file(filename)
+function module.read_file(filename)
local file = io.open(filename, 'r')
if not file then
return nil
@@ -654,7 +657,7 @@ local function read_file(filename)
end
-- Dedent the given text and write it to the file name.
-local function write_file(name, text, no_dedent, append)
+function module.write_file(name, text, no_dedent, append)
local file = io.open(name, (append and 'a' or 'w'))
if type(text) == 'table' then
-- Byte blob
@@ -664,26 +667,29 @@ local function write_file(name, text, no_dedent, append)
text = ('%s%c'):format(text, char)
end
elseif not no_dedent then
- text = dedent(text)
+ text = module.dedent(text)
end
file:write(text)
file:flush()
file:close()
end
-local function isCI()
- local is_travis = nil ~= os.getenv('TRAVIS')
- local is_appveyor = nil ~= os.getenv('APPVEYOR')
- local is_quickbuild = nil ~= lfs.attributes('/usr/home/quickbuild')
- return is_travis or is_appveyor or is_quickbuild
+function module.isCI(name)
+ local any = (name == nil)
+ assert(any or name == 'appveyor' or name == 'quickbuild' or name == 'travis')
+ local av = ((any or name == 'appveyor') and nil ~= os.getenv('APPVEYOR'))
+ local tr = ((any or name == 'travis') and nil ~= os.getenv('TRAVIS'))
+ local qb = ((any or name == 'quickbuild') and nil ~= lfs.attributes('/usr/home/quickbuild'))
+ return tr or av or qb
end
-- Gets the contents of $NVIM_LOG_FILE for printing to the build log.
--- Also removes the file, if the current environment looks like CI.
-local function read_nvim_log()
+-- Also moves the file to "${NVIM_LOG_FILE}.displayed" on CI environments.
+function module.read_nvim_log()
local logfile = os.getenv('NVIM_LOG_FILE') or '.nvimlog'
- local keep = isCI() and 999 or 10
- local lines = read_file_list(logfile, -keep) or {}
+ local is_ci = module.isCI()
+ local keep = is_ci and 999 or 10
+ local lines = module.read_file_list(logfile, -keep) or {}
local log = (('-'):rep(78)..'\n'
..string.format('$NVIM_LOG_FILE: %s\n', logfile)
..(#lines > 0 and '(last '..tostring(keep)..' lines)\n' or '(empty)\n'))
@@ -691,52 +697,12 @@ local function read_nvim_log()
log = log..line..'\n'
end
log = log..('-'):rep(78)..'\n'
- if isCI() then
- os.remove(logfile)
+ if is_ci then
+ os.rename(logfile, logfile .. '.displayed')
end
return log
end
-local module = {
- REMOVE_THIS = REMOVE_THIS,
- argss_to_cmd = argss_to_cmd,
- check_cores = check_cores,
- check_logs = check_logs,
- concat_tables = concat_tables,
- dedent = dedent,
- dictdiff = dictdiff,
- eq = eq,
- expect_err = expect_err,
- filter = filter,
- fixtbl = fixtbl,
- fixtbl_rec = fixtbl_rec,
- format_luav = format_luav,
- format_string = format_string,
- glob = glob,
- hasenv = hasenv,
- hexdump = hexdump,
- intchar2lua = intchar2lua,
- isCI = isCI,
- map = map,
- matches = matches,
- mergedicts_copy = mergedicts_copy,
- near = near,
- neq = neq,
- ok = ok,
- popen_r = popen_r,
- popen_w = popen_w,
- read_file = read_file,
- read_file_list = read_file_list,
- read_nvim_log = read_nvim_log,
- repeated_read_cmd = repeated_read_cmd,
- shallowcopy = shallowcopy,
- sleep = sleep,
- tmpname = tmpname,
- uname = uname,
- updated = updated,
- which = which,
- write_file = write_file,
-}
module = shared.tbl_extend('error', module, Paths, shared)
return module
diff --git a/test/includes/pre/uv.h b/test/includes/pre/uv.h
deleted file mode 100644
index da7818cd07..0000000000
--- a/test/includes/pre/uv.h
+++ /dev/null
@@ -1,4 +0,0 @@
-#include <uv.h>
-
-static const int kUV_ENOENT = UV_ENOENT;
-static const int kUV_EEXIST = UV_EEXIST;
diff --git a/test/unit/helpers.lua b/test/unit/helpers.lua
index b5d3dd9f47..24dbc65bd0 100644
--- a/test/unit/helpers.lua
+++ b/test/unit/helpers.lua
@@ -456,8 +456,8 @@ else
if bytes_written == -1 then
local err = ffi.errno(0)
if err ~= ffi.C.kPOSIXErrnoEINTR then
- assert(false, ("write() error: %u: %s"):format(
- err, ffi.string(ffi.C.strerror(err))))
+ assert(false, ("write() error: %u: %s ('%s')"):format(
+ err, ffi.string(ffi.C.strerror(err)), s))
end
elseif bytes_written == 0 then
break
diff --git a/test/unit/mbyte_spec.lua b/test/unit/mbyte_spec.lua
index 3e65537270..d27f52923a 100644
--- a/test/unit/mbyte_spec.lua
+++ b/test/unit/mbyte_spec.lua
@@ -8,6 +8,10 @@ local mbyte = helpers.cimport("./src/nvim/mbyte.h")
local charset = helpers.cimport('./src/nvim/charset.h')
describe('mbyte', function()
+ if helpers.isCI('quickbuild') then
+ pending("crashes on quickbuild", function() end)
+ return
+ end
-- Array for composing characters
local intp = ffi.typeof('int[?]')
diff --git a/test/unit/os/fs_spec.lua b/test/unit/os/fs_spec.lua
index f1ec94ae87..526a09e845 100644
--- a/test/unit/os/fs_spec.lua
+++ b/test/unit/os/fs_spec.lua
@@ -27,7 +27,7 @@ cimport('./src/nvim/fileio.h')
local fs = cimport('./src/nvim/os/os.h', './src/nvim/path.h')
cppimport('sys/stat.h')
cppimport('fcntl.h')
-cppimport('uv.h')
+cimport('uv.h')
local s = ''
for i = 0, 255 do
@@ -540,7 +540,7 @@ describe('fs.c', function()
itp('returns UV_EEXIST for O_CREAT|O_EXCL on a existing file', function()
assert_file_exists(existing_file)
- eq(ffi.C.kUV_EEXIST, (os_open(existing_file, (bit.bor(ffi.C.kO_CREAT, ffi.C.kO_EXCL)), 0)))
+ eq(ffi.C.UV_EEXIST, (os_open(existing_file, (bit.bor(ffi.C.kO_CREAT, ffi.C.kO_EXCL)), 0)))
end)
itp('sets `rwx` permissions for O_CREAT 700 which then can be closed', function()
diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt
index db4dae4b39..6824e208aa 100644
--- a/third-party/CMakeLists.txt
+++ b/third-party/CMakeLists.txt
@@ -1,12 +1,12 @@
# This is not meant to be included by the top-level.
cmake_minimum_required (VERSION 2.8.12)
-project(NVIM_DEPS)
+project(NVIM_DEPS C)
# Needed for: check_c_compiler_flag()
include(CheckCCompilerFlag)
# Point CMake at any custom modules we may ship
-list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
+list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" "${PROJECT_SOURCE_DIR}/../cmake")
# In Windows/MSVC CMAKE_BUILD_TYPE changes the paths/linking of the build
# recipes (libuv, msgpack), make sure it is set
@@ -101,6 +101,7 @@ set(DEPS_CXX_COMPILER "${CMAKE_CXX_COMPILER}")
if(CMAKE_OSX_SYSROOT)
set(DEPS_C_COMPILER "${DEPS_C_COMPILER} -isysroot${CMAKE_OSX_SYSROOT}")
+ set(DEPS_CXX_COMPILER "${DEPS_CXX_COMPILER} -isysroot${CMAKE_OSX_SYSROOT}")
endif()
# Cross compiling: use these for dependencies built for the
@@ -125,23 +126,23 @@ include(ExternalProject)
if(WIN32)
# "nvim" branch of https://github.com/neovim/libuv
- set(LIBUV_URL https://github.com/neovim/libuv/archive/0ac136359903c70ab1db1838c3ad06da6fa5b912.tar.gz)
- set(LIBUV_SHA256 600badb81e39578ddfc8f3636f78dd308ea0915e5bf1ee56e6cdfa314d3c463f)
+ set(LIBUV_URL https://github.com/neovim/libuv/archive/eeae18d085de25f138c23966f98a179f0fb609e7.tar.gz)
+ set(LIBUV_SHA256 c37d0b7cb1defe69ae8dbb4d712c0d7cf838d6539178e8bcf71c72579ab5b666)
else()
- set(LIBUV_URL https://github.com/libuv/libuv/archive/v1.29.1.tar.gz)
- set(LIBUV_SHA256 bdde1140087ce97080ea323c3598553ece00a24ae63ac568be78bef3e97f3e25)
+ set(LIBUV_URL https://github.com/libuv/libuv/archive/v1.30.0.tar.gz)
+ set(LIBUV_SHA256 44c8fdadf3b3f393006a4ac4ba144020673a3f9cd72bed1fbb2c366ebcf0d199)
endif()
set(MSGPACK_URL https://github.com/msgpack/msgpack-c/releases/download/cpp-3.0.0/msgpack-3.0.0.tar.gz)
set(MSGPACK_SHA256 bfbb71b7c02f806393bc3cbc491b40523b89e64f83860c58e3e54af47de176e4)
-set(LUAJIT_URL https://github.com/LuaJIT/LuaJIT/archive/7dbf0b05f1228c1c719866db5e5f3d58f87f74c8.tar.gz)
-set(LUAJIT_SHA256 cbae019b5e396164eb5f0d07777b55cc03931bb944f83c61a010c053c9f5fd5b)
+# https://github.com/LuaJIT/LuaJIT/tree/v2.0
+set(LUAJIT_URL https://github.com/LuaJIT/LuaJIT/archive/61464b0a5b685489bee7b6680c0e9663f2143a84.tar.gz)
+set(LUAJIT_SHA256 033fa4ef19f559ef18a9b9fb017d0cb8be58befe05ab604e92814234910f1c68)
set(LUA_URL https://www.lua.org/ftp/lua-5.1.5.tar.gz)
set(LUA_SHA256 2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333)
-# NOTE: Version must match LUAROCKS_VERSION in third-party/cmake/BuildLuarocks.cmake
set(LUAROCKS_URL https://github.com/luarocks/luarocks/archive/v2.4.4.tar.gz)
set(LUAROCKS_SHA256 9eb3d0738fd02ad8bf39bcedccac4e83e9b5fff2bcca247c3584b925b2075d9c)
@@ -154,8 +155,12 @@ set(LIBTERMKEY_SHA256 cecbf737f35d18f433c8d7864f63c0f878af41f8bd0255a3ebb16010dc
set(LIBVTERM_URL https://github.com/neovim/libvterm/archive/b45b648cab73f9667bde7c0c6045b285e22b3ecd.tar.gz)
set(LIBVTERM_SHA256 37cc123deff29327efa654358c2ebaaf8589da03754ca5adb8ec47be386a0433)
-set(LUV_URL https://github.com/luvit/luv/archive/1.9.1-1.tar.gz)
-set(LUV_SHA256 562b9efaad30aa051a40eac9ade0c3df48bb8186763769abe47ec3fb3edb1268)
+set(LUV_VERSION 1.30.0-0)
+set(LUV_URL https://github.com/luvit/luv/archive/${LUV_VERSION}.tar.gz)
+set(LUV_SHA256 6e468fa17bf222ca8ce0bfffdbdf947fc897da48643a12955db92f80e2c852f5)
+
+set(LUA_COMPAT53_URL https://github.com/keplerproject/lua-compat-5.3/archive/v0.7.tar.gz)
+set(LUA_COMPAT53_SHA256 bec3a23114a3d9b3218038309657f0f506ad10dfbc03bb54e91da7e5ffdba0a2)
set(GPERF_URL https://github.com/neovim/deps/raw/ff5b4b18a87397a8564016071ae64f64bcd8c635/opt/gperf-3.1.tar.gz)
set(GPERF_SHA256 588546b945bba4b70b6a3a616e80b4ab466e3f33024a352fc2198112cdbb3ae2)
@@ -187,6 +192,9 @@ endif()
if(USE_BUNDLED_LIBTERMKEY)
include(BuildLibtermkey)
+ if(USE_BUNDLED_UNIBILIUM)
+ add_dependencies(libtermkey unibilium)
+ endif()
endif()
if(USE_BUNDLED_LIBVTERM)
@@ -229,9 +237,9 @@ if(USE_BUNDLED_LIBICONV)
include(BuildLibiconv)
endif()
-include(GetBinaryDeps)
-
if(WIN32)
+ include(GetBinaryDeps)
+
GetBinaryDep(TARGET wintools
INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory . ${DEPS_INSTALL_DIR}/bin)
diff --git a/third-party/cmake/BuildGperf.cmake b/third-party/cmake/BuildGperf.cmake
index 71c3cc1eef..e922f71ed5 100644
--- a/third-party/cmake/BuildGperf.cmake
+++ b/third-party/cmake/BuildGperf.cmake
@@ -2,6 +2,7 @@
# cross compiling we still want to build for the HOST system, whenever
# writing a recipe that is meant for cross-compile, use the HOSTDEPS_* variables
# instead of DEPS_* - check the main CMakeLists.txt for a list.
+enable_language(CXX)
# BuildGperf(CONFIGURE_COMMAND ... BUILD_COMMAND ... INSTALL_COMMAND ...)
# Reusable function to build Gperf, wraps ExternalProject_Add.
diff --git a/third-party/cmake/BuildLibtermkey.cmake b/third-party/cmake/BuildLibtermkey.cmake
index da65c87972..b2332ed65a 100644
--- a/third-party/cmake/BuildLibtermkey.cmake
+++ b/third-party/cmake/BuildLibtermkey.cmake
@@ -53,4 +53,3 @@ ExternalProject_Add(libtermkey
endif()
list(APPEND THIRD_PARTY_DEPS libtermkey)
-add_dependencies(libtermkey unibilium)
diff --git a/third-party/cmake/BuildLua.cmake b/third-party/cmake/BuildLua.cmake
index da617e3ccd..c3f789509e 100644
--- a/third-party/cmake/BuildLua.cmake
+++ b/third-party/cmake/BuildLua.cmake
@@ -41,7 +41,7 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
set(LUA_TARGET freebsd)
elseif(CMAKE_SYSTEM_NAME MATCHES "BSD")
set(CMAKE_LUA_TARGET bsd)
-elseif(SYSTEM_NAME MATCHES "^MINGW")
+elseif(CMAKE_SYSTEM_NAME MATCHES "^MINGW")
set(CMAKE_LUA_TARGET mingw)
else()
if(UNIX)
@@ -91,7 +91,7 @@ set(BUSTED_LUA ${BUSTED}-lua)
add_custom_command(OUTPUT ${BUSTED_LUA}
COMMAND sed -e 's/^exec/exec $$LUA_DEBUGGER/' -e 's/jit//g' < ${BUSTED} > ${BUSTED_LUA} && chmod +x ${BUSTED_LUA}
- DEPENDS lua busted)
+ DEPENDS lua busted ${BUSTED})
add_custom_target(busted-lua
DEPENDS ${DEPS_INSTALL_DIR}/bin/busted-lua)
diff --git a/third-party/cmake/BuildLuajit.cmake b/third-party/cmake/BuildLuajit.cmake
index e965927f4e..791da4b7df 100644
--- a/third-party/cmake/BuildLuajit.cmake
+++ b/third-party/cmake/BuildLuajit.cmake
@@ -41,7 +41,6 @@ else()
set(AMD64_ABI "")
endif()
set(INSTALLCMD_UNIX ${MAKE_PRG} CFLAGS=-fPIC
- CFLAGS+=-DLUAJIT_DISABLE_JIT
CFLAGS+=-DLUA_USE_APICHECK
CFLAGS+=-DLUA_USE_ASSERT
${AMD64_ABI}
@@ -94,7 +93,6 @@ elseif(MINGW)
endif()
BuildLuaJit(BUILD_COMMAND ${LUAJIT_MAKE_PRG} CC=${DEPS_C_COMPILER}
PREFIX=${DEPS_INSTALL_DIR}
- CFLAGS+=-DLUAJIT_DISABLE_JIT
CFLAGS+=-DLUA_USE_APICHECK
CFLAGS+=-DLUA_USE_ASSERT
CCDEBUG+=-g
diff --git a/third-party/cmake/BuildLuarocks.cmake b/third-party/cmake/BuildLuarocks.cmake
index de4db35bfd..87e2946c96 100644
--- a/third-party/cmake/BuildLuarocks.cmake
+++ b/third-party/cmake/BuildLuarocks.cmake
@@ -2,6 +2,10 @@
# cross compiling we still want to build for the HOST system, whenever
# writing a recipe that is meant for cross-compile, use the HOSTDEPS_* variables
# instead of DEPS_* - check the main CMakeLists.txt for a list.
+#
+# NOTE: LuaRocks rocks need to "DEPENDS" on the previous module, because
+# running luarocks in parallel will break, e.g. when some rocks have
+# the same dependency..
option(USE_BUNDLED_BUSTED "Use the bundled version of busted to run tests." ON)
@@ -41,9 +45,6 @@ endfunction()
# The luarocks binary location
set(LUAROCKS_BINARY ${HOSTDEPS_BIN_DIR}/luarocks)
-# NOTE: Version must match version of LuaRocks in third-party/CMakeLists.txt
-set(LUAROCKS_VERSION 2.4)
-
# Arguments for calls to 'luarocks build'
if(NOT MSVC)
# In MSVC don't pass the compiler/linker to luarocks, the bundled
@@ -61,6 +62,14 @@ if(UNIX OR (MINGW AND CMAKE_CROSSCOMPILING))
elseif(USE_BUNDLED_LUA)
list(APPEND LUAROCKS_OPTS
--with-lua=${HOSTDEPS_INSTALL_DIR})
+ else()
+ find_package(LuaJit)
+ if(LUAJIT_FOUND)
+ list(APPEND LUAROCKS_OPTS
+ --lua-version=5.1
+ --with-lua-include=${LUAJIT_INCLUDE_DIRS}
+ --lua-suffix=jit)
+ endif()
endif()
BuildLuarocks(
@@ -80,14 +89,14 @@ elseif(MSVC OR MINGW)
/LUA ${DEPS_INSTALL_DIR}
/LIB ${DEPS_LIB_DIR}
/BIN ${DEPS_BIN_DIR}
- /INC ${DEPS_INSTALL_DIR}/include/luajit-2.0/
- /P ${DEPS_INSTALL_DIR}/${LUAROCKS_VERSION} /TREE ${DEPS_INSTALL_DIR}
+ /INC ${DEPS_INSTALL_DIR}/include/luajit-2.0
+ /P ${DEPS_INSTALL_DIR}/luarocks /TREE ${DEPS_INSTALL_DIR}
/SCRIPTS ${DEPS_BIN_DIR}
/CMOD ${DEPS_BIN_DIR}
${COMPILER_FLAG}
/LUAMOD ${DEPS_BIN_DIR}/lua)
- set(LUAROCKS_BINARY ${DEPS_INSTALL_DIR}/${LUAROCKS_VERSION}/luarocks.bat)
+ set(LUAROCKS_BINARY ${DEPS_INSTALL_DIR}/luarocks/luarocks.bat)
else()
message(FATAL_ERROR "Trying to build luarocks in an unsupported system ${CMAKE_SYSTEM_NAME}/${CMAKE_C_COMPILER_ID}")
endif()
@@ -102,45 +111,31 @@ if(USE_BUNDLED_LUAJIT)
elseif(USE_BUNDLED_LUA)
add_dependencies(luarocks lua)
endif()
+set(ROCKS_DIR ${HOSTDEPS_LIB_DIR}/luarocks/rocks)
-# DEPENDS on the previous module, because Luarocks breaks if parallel.
-add_custom_command(OUTPUT ${HOSTDEPS_LIB_DIR}/luarocks/rocks/mpack
+# mpack
+add_custom_command(OUTPUT ${ROCKS_DIR}/mpack
COMMAND ${LUAROCKS_BINARY}
- ARGS build mpack 1.0.7-0 ${LUAROCKS_BUILDARGS}
+ ARGS build mpack 1.0.8-0 ${LUAROCKS_BUILDARGS}
DEPENDS luarocks)
-add_custom_target(mpack
- DEPENDS ${HOSTDEPS_LIB_DIR}/luarocks/rocks/mpack)
+add_custom_target(mpack DEPENDS ${ROCKS_DIR}/mpack)
list(APPEND THIRD_PARTY_DEPS mpack)
-# DEPENDS on the previous module, because Luarocks breaks if parallel.
-add_custom_command(OUTPUT ${HOSTDEPS_LIB_DIR}/luarocks/rocks/lpeg
+# lpeg
+add_custom_command(OUTPUT ${ROCKS_DIR}/lpeg
COMMAND ${LUAROCKS_BINARY}
- ARGS build lpeg 1.0.1-1 ${LUAROCKS_BUILDARGS}
+ ARGS build lpeg 1.0.2-1 ${LUAROCKS_BUILDARGS}
DEPENDS mpack)
-add_custom_target(lpeg
- DEPENDS ${HOSTDEPS_LIB_DIR}/luarocks/rocks/lpeg)
-
+add_custom_target(lpeg DEPENDS ${ROCKS_DIR}/lpeg)
list(APPEND THIRD_PARTY_DEPS lpeg)
-# DEPENDS on the previous module, because Luarocks breaks if parallel.
-add_custom_command(OUTPUT ${HOSTDEPS_LIB_DIR}/luarocks/rocks/inspect
- COMMAND ${LUAROCKS_BINARY}
- ARGS build inspect 3.1.1-0 ${LUAROCKS_BUILDARGS}
- DEPENDS lpeg)
-add_custom_target(inspect
- DEPENDS ${HOSTDEPS_LIB_DIR}/luarocks/rocks/inspect)
-
-list(APPEND THIRD_PARTY_DEPS inspect)
-
if((NOT USE_BUNDLED_LUAJIT) AND USE_BUNDLED_LUA)
- # DEPENDS on the previous module, because Luarocks breaks if parallel.
- add_custom_command(OUTPUT ${HOSTDEPS_LIB_DIR}/luarocks/rocks/luabitop
+ # luabitop
+ add_custom_command(OUTPUT ${ROCKS_DIR}/luabitop
COMMAND ${LUAROCKS_BINARY}
ARGS build luabitop 1.0.2-3 ${LUAROCKS_BUILDARGS}
- DEPENDS inspect)
- add_custom_target(luabitop
- DEPENDS ${HOSTDEPS_LIB_DIR}/luarocks/rocks/luabitop)
-
+ DEPENDS lpeg)
+ add_custom_target(luabitop DEPENDS ${ROCKS_DIR}/luabitop)
list(APPEND THIRD_PARTY_DEPS luabitop)
endif()
@@ -148,17 +143,17 @@ if(USE_BUNDLED_BUSTED)
if((NOT USE_BUNDLED_LUAJIT) AND USE_BUNDLED_LUA)
set(PENLIGHT_DEPENDS luabitop)
else()
- set(PENLIGHT_DEPENDS inspect)
+ set(PENLIGHT_DEPENDS lpeg)
endif()
- # DEPENDS on the previous module, because Luarocks breaks if parallel.
- add_custom_command(OUTPUT ${HOSTDEPS_LIB_DIR}/luarocks/rocks/penlight
+ # penlight
+ add_custom_command(OUTPUT ${ROCKS_DIR}/penlight
COMMAND ${LUAROCKS_BINARY}
ARGS build penlight 1.5.4-1 ${LUAROCKS_BUILDARGS}
DEPENDS ${PENLIGHT_DEPENDS})
- add_custom_target(penlight
- DEPENDS ${HOSTDEPS_LIB_DIR}/luarocks/rocks/penlight)
+ add_custom_target(penlight DEPENDS ${ROCKS_DIR}/penlight)
+ # busted
if(WIN32)
set(BUSTED_EXE "${HOSTDEPS_BIN_DIR}/busted.bat")
set(LUACHECK_EXE "${HOSTDEPS_BIN_DIR}/luacheck.bat")
@@ -166,46 +161,50 @@ if(USE_BUNDLED_BUSTED)
set(BUSTED_EXE "${HOSTDEPS_BIN_DIR}/busted")
set(LUACHECK_EXE "${HOSTDEPS_BIN_DIR}/luacheck")
endif()
- # DEPENDS on the previous module, because Luarocks breaks if parallel.
add_custom_command(OUTPUT ${BUSTED_EXE}
COMMAND ${LUAROCKS_BINARY}
- ARGS build busted 2.0.rc12-1 ${LUAROCKS_BUILDARGS}
+ ARGS build busted 2.0.0 ${LUAROCKS_BUILDARGS}
DEPENDS penlight)
- add_custom_target(busted
- DEPENDS ${BUSTED_EXE})
+ add_custom_target(busted DEPENDS ${BUSTED_EXE})
- # DEPENDS on the previous module, because Luarocks breaks if parallel.
+ # luacheck
add_custom_command(OUTPUT ${LUACHECK_EXE}
COMMAND ${LUAROCKS_BINARY}
- ARGS build luacheck 0.21.2-1 ${LUAROCKS_BUILDARGS}
+ ARGS build luacheck 0.23.0-1 ${LUAROCKS_BUILDARGS}
DEPENDS busted)
- add_custom_target(luacheck
- DEPENDS ${LUACHECK_EXE})
-
- set(LUV_DEPS luacheck luv-static)
- if(MINGW AND CMAKE_CROSSCOMPILING)
- set(LUV_DEPS ${LUV_DEPS} libuv_host)
- endif()
- set(LUV_ARGS "CFLAGS=-O0 -g3 -fPIC")
- if(USE_BUNDLED_LIBUV)
- list(APPEND LUV_ARGS LIBUV_DIR=${HOSTDEPS_INSTALL_DIR})
+ add_custom_target(luacheck DEPENDS ${LUACHECK_EXE})
+
+ # luv
+ set(LUV_DEPS luacheck)
+ if(USE_BUNDLED_LUV)
+ list(APPEND LUV_DEPS luv-static lua-compat-5.3)
+ if(MINGW AND CMAKE_CROSSCOMPILING)
+ list(APPEND LUV_DEPS libuv_host)
+ endif()
+ set(LUV_ARGS "CFLAGS=-O0 -g3 -fPIC")
+ if(USE_BUNDLED_LIBUV)
+ list(APPEND LUV_ARGS LIBUV_DIR=${HOSTDEPS_INSTALL_DIR})
+ endif()
+ SET(LUV_PRIVATE_ARGS LUA_COMPAT53_INCDIR=${DEPS_BUILD_DIR}/src/lua-compat-5.3)
+ add_custom_command(OUTPUT ${ROCKS_DIR}/luv
+ COMMAND ${LUAROCKS_BINARY}
+ ARGS make ${LUAROCKS_BUILDARGS} ${LUV_ARGS} ${LUV_PRIVATE_ARGS}
+ WORKING_DIRECTORY ${DEPS_BUILD_DIR}/src/luv
+ DEPENDS ${LUV_DEPS})
+ else()
+ add_custom_command(OUTPUT ${ROCKS_DIR}/luv
+ COMMAND ${LUAROCKS_BINARY}
+ ARGS build luv ${LUV_VERSION} ${LUAROCKS_BUILDARGS}
+ DEPENDS ${LUV_DEPS})
endif()
- # DEPENDS on the previous module, because Luarocks breaks if parallel.
- add_custom_command(OUTPUT ${HOSTDEPS_LIB_DIR}/luarocks/rocks/luv
- COMMAND ${LUAROCKS_BINARY}
- ARGS make ${LUAROCKS_BUILDARGS} ${LUV_ARGS}
- WORKING_DIRECTORY ${DEPS_BUILD_DIR}/src/luv
- DEPENDS ${LUV_DEPS})
- add_custom_target(luv
- DEPENDS ${HOSTDEPS_LIB_DIR}/luarocks/rocks/luv)
-
- # DEPENDS on the previous module, because Luarocks breaks if parallel.
- add_custom_command(OUTPUT ${HOSTDEPS_LIB_DIR}/luarocks/rocks/nvim-client
+ add_custom_target(luv DEPENDS ${ROCKS_DIR}/luv)
+
+ # nvim-client
+ add_custom_command(OUTPUT ${ROCKS_DIR}/nvim-client
COMMAND ${LUAROCKS_BINARY}
ARGS build nvim-client 0.2.0-1 ${LUAROCKS_BUILDARGS}
DEPENDS luv)
- add_custom_target(nvim-client
- DEPENDS ${HOSTDEPS_LIB_DIR}/luarocks/rocks/nvim-client)
+ add_custom_target(nvim-client DEPENDS ${ROCKS_DIR}/nvim-client)
list(APPEND THIRD_PARTY_DEPS busted luacheck nvim-client)
endif()
diff --git a/third-party/cmake/BuildLuv.cmake b/third-party/cmake/BuildLuv.cmake
index a62ee72f91..967e0a1711 100644
--- a/third-party/cmake/BuildLuv.cmake
+++ b/third-party/cmake/BuildLuv.cmake
@@ -15,8 +15,26 @@ function(BuildLuv)
message(FATAL_ERROR "Must pass at least one of CONFIGURE_COMMAND, BUILD_COMMAND, INSTALL_COMMAND")
endif()
+ ExternalProject_Add(lua-compat-5.3
+ PREFIX ${DEPS_BUILD_DIR}
+ URL ${LUA_COMPAT53_URL}
+ DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/lua-compat-5.3
+ DOWNLOAD_COMMAND ${CMAKE_COMMAND}
+ -DPREFIX=${DEPS_BUILD_DIR}
+ -DDOWNLOAD_DIR=${DEPS_DOWNLOAD_DIR}/lua-compat-5.3
+ -DURL=${LUA_COMPAT53_URL}
+ -DEXPECTED_SHA256=${LUA_COMPAT53_SHA256}
+ -DTARGET=lua-compat-5.3
+ -DUSE_EXISTING_SRC_DIR=${USE_EXISTING_SRC_DIR}
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/DownloadAndExtractFile.cmake
+ PATCH_COMMAND ""
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND ""
+ INSTALL_COMMAND "")
+
ExternalProject_Add(luv-static
PREFIX ${DEPS_BUILD_DIR}
+ DEPENDS lua-compat-5.3
URL ${LUV_URL}
DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/luv
DOWNLOAD_COMMAND ${CMAKE_COMMAND}
@@ -24,7 +42,9 @@ function(BuildLuv)
-DDOWNLOAD_DIR=${DEPS_DOWNLOAD_DIR}/luv
-DURL=${LUV_URL}
-DEXPECTED_SHA256=${LUV_SHA256}
- -DTARGET=luv
+ -DTARGET=luv-static
+ # The source is shared with BuildLuarocks (with USE_BUNDLED_LUV).
+ -DSRC_DIR=${DEPS_BUILD_DIR}/src/luv
-DUSE_EXISTING_SRC_DIR=${USE_EXISTING_SRC_DIR}
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/DownloadAndExtractFile.cmake
PATCH_COMMAND "${_luv_PATCH_COMMAND}"
@@ -41,13 +61,6 @@ set(LUV_INCLUDE_FLAGS
# directory
set(LUV_PATCH_COMMAND
${CMAKE_COMMAND} -E copy_directory ${LUV_SRC_DIR}/rockspecs ${LUV_SRC_DIR})
-if(MINGW)
- set(LUV_PATCH_COMMAND
- ${LUV_PATCH_COMMAND}
- COMMAND ${GIT_EXECUTABLE} -C ${LUV_SRC_DIR} init
- COMMAND ${GIT_EXECUTABLE} -C ${LUV_SRC_DIR} apply --ignore-whitespace
- ${CMAKE_CURRENT_SOURCE_DIR}/patches/luv-Add-missing-definitions-for-MinGW.patch)
-endif()
set(LUV_CONFIGURE_COMMAND_COMMON
${CMAKE_COMMAND} ${LUV_SRC_DIR}
@@ -58,6 +71,19 @@ set(LUV_CONFIGURE_COMMAND_COMMON
-DBUILD_SHARED_LIBS=OFF
-DBUILD_MODULE=OFF)
+if(USE_BUNDLED_LUAJIT)
+ list(APPEND LUV_CONFIGURE_COMMAND_COMMON -DWITH_LUA_ENGINE=LuaJit)
+elseif(USE_BUNDLED_LUA)
+ list(APPEND LUV_CONFIGURE_COMMAND_COMMON -DWITH_LUA_ENGINE=Lua)
+else()
+ find_package(LuaJit)
+ if(LUAJIT_FOUND)
+ list(APPEND LUV_CONFIGURE_COMMAND_COMMON -DWITH_LUA_ENGINE=LuaJit)
+ else()
+ list(APPEND LUV_CONFIGURE_COMMAND_COMMON -DWITH_LUA_ENGINE=Lua)
+ endif()
+endif()
+
if(USE_BUNDLED_LIBUV)
set(LUV_CONFIGURE_COMMAND_COMMON
${LUV_CONFIGURE_COMMAND_COMMON}
@@ -94,9 +120,12 @@ endif()
if(CMAKE_GENERATOR MATCHES "Unix Makefiles" AND
(CMAKE_SYSTEM_NAME MATCHES ".*BSD" OR CMAKE_SYSTEM_NAME MATCHES "DragonFly"))
- set(LUV_BUILD_COMMAND ${CMAKE_COMMAND} "-DCMAKE_MAKE_PROGRAM=gmake" --build .)
+ set(LUV_BUILD_COMMAND ${CMAKE_COMMAND}
+ "-DLUA_COMPAT53_DIR=${DEPS_BUILD_DIR}/src/lua-compat-5.3"
+ "-DCMAKE_MAKE_PROGRAM=gmake" --build .)
else()
- set(LUV_BUILD_COMMAND ${CMAKE_COMMAND} --build .)
+ set(LUV_BUILD_COMMAND ${CMAKE_COMMAND}
+ "-DLUA_COMPAT53_DIR=${DEPS_BUILD_DIR}/src/lua-compat-5.3" --build .)
endif()
set(LUV_INSTALL_COMMAND ${CMAKE_COMMAND} --build . --target install)
diff --git a/third-party/cmake/DownloadAndExtractFile.cmake b/third-party/cmake/DownloadAndExtractFile.cmake
index 2fc6e0415f..bb8cf1b674 100644
--- a/third-party/cmake/DownloadAndExtractFile.cmake
+++ b/third-party/cmake/DownloadAndExtractFile.cmake
@@ -18,7 +18,10 @@ if(NOT DEFINED TARGET)
message(FATAL_ERROR "TARGET must be defined.")
endif()
-set(SRC_DIR ${PREFIX}/src/${TARGET})
+if(NOT DEFINED SRC_DIR)
+ set(SRC_DIR ${PREFIX}/src/${TARGET})
+endif()
+set(BINARY_DIR ${PREFIX}/src/${TARGET}-build)
# Check whether the source has been downloaded. If true, skip it.
# Useful for external downloads like homebrew.
@@ -71,11 +74,26 @@ 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
+ # 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"
+ 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()
set(NULL_SHA256 "0000000000000000000000000000000000000000000000000000000000000000")
@@ -154,6 +172,13 @@ file(REMOVE_RECURSE ${SRC_DIR})
get_filename_component(contents ${contents} ABSOLUTE)
file(RENAME ${contents} ${SRC_DIR})
+# Remove any existing BINARY_DIR, to force a new build.
+# Without this a necessary output (e.g. libluv.a) might not be updated/installed.
+#
+message(STATUS "extracting... [clean binary dir]")
+file(REMOVE_RECURSE ${BINARY_DIR})
+file(MAKE_DIRECTORY ${BINARY_DIR})
+
# Clean up:
#
message(STATUS "extracting... [clean up]")
diff --git a/third-party/cmake/GetBinaryDeps.cmake b/third-party/cmake/GetBinaryDeps.cmake
index 1d98177924..f262ae7159 100644
--- a/third-party/cmake/GetBinaryDeps.cmake
+++ b/third-party/cmake/GetBinaryDeps.cmake
@@ -2,9 +2,10 @@
include(CMakeParseArguments)
# This is similar to the build recipes, but instead downloads a third party
-# binary and installs it under the the DEPS_PREFIX. The INSTALL_COMMAND is
-# executed in the folder where downloaded files are extracted and the
-# ${DEPS_INSTALL_DIR} holds the path to the third-party install root.
+# binary and installs it under the DEPS_PREFIX.
+# The INSTALL_COMMAND is executed in the folder where downloaded files are
+# extracted and the ${DEPS_INSTALL_DIR} holds the path to the third-party
+# install root.
function(GetBinaryDep)
cmake_parse_arguments(_gettool
"BUILD_IN_SOURCE"
diff --git a/third-party/cmake/LibvtermCMakeLists.txt b/third-party/cmake/LibvtermCMakeLists.txt
index dad3ef62c2..16c4d542c4 100644
--- a/third-party/cmake/LibvtermCMakeLists.txt
+++ b/third-party/cmake/LibvtermCMakeLists.txt
@@ -5,9 +5,10 @@ include(GNUInstallDirs)
find_package(Perl)
if(MSVC)
- add_definitions(/W3 -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE)
+ add_compile_options(/W3)
+ add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE)
else()
- add_definitions(-Wall -std=c99)
+ add_compile_options(-Wall -std=c99)
endif()
# Generate includes from tables
diff --git a/third-party/cmake/libtermkeyCMakeLists.txt b/third-party/cmake/libtermkeyCMakeLists.txt
index c55da7929a..af54c1daec 100644
--- a/third-party/cmake/libtermkeyCMakeLists.txt
+++ b/third-party/cmake/libtermkeyCMakeLists.txt
@@ -4,7 +4,7 @@ project(libtermkey)
add_definitions(-D _CRT_SECURE_NO_WARNINGS)
add_definitions(-DHAVE_UNIBILIUM)
if(NOT MSVC)
- add_definitions(-std=c99)
+ add_compile_options(-std=c99)
endif()
include_directories(${PROJECT_BINARY_DIR}/t)
diff --git a/third-party/patches/luv-Add-missing-definitions-for-MinGW.patch b/third-party/patches/luv-Add-missing-definitions-for-MinGW.patch
deleted file mode 100644
index 8954ae21c3..0000000000
--- a/third-party/patches/luv-Add-missing-definitions-for-MinGW.patch
+++ /dev/null
@@ -1,24 +0,0 @@
-diff --git a/src/dns.c b/src/dns.c
-index 8634157..5f36625 100644
---- a/src/dns.c
-+++ b/src/dns.c
-@@ -20,6 +20,19 @@
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netdb.h>
-+#elif __MINGW32__
-+# ifndef AI_NUMERICSERV
-+# define AI_NUMERICSERV 0x0008
-+# endif
-+# ifndef AI_ALL
-+# define AI_ALL 0x00000100
-+# endif
-+# ifndef AI_ADDRCONFIG
-+# define AI_ADDRCONFIG 0x00000400
-+# endif
-+# ifndef AI_V4MAPPED
-+# define AI_V4MAPPED 0x00000800
-+# endif
- #endif
-
- static void luv_pushaddrinfo(lua_State* L, struct addrinfo* res) {