diff options
35 files changed, 1420 insertions, 669 deletions
diff --git a/runtime/autoload/remote/host.vim b/runtime/autoload/remote/host.vim index d04dea180c..24497b10c2 100644 --- a/runtime/autoload/remote/host.vim +++ b/runtime/autoload/remote/host.vim @@ -5,7 +5,7 @@ let s:remote_plugins_manifest = fnamemodify(expand($MYVIMRC, 1), ':h') " Register a host by associating it with a factory(funcref) -function! remote#host#Register(name, pattern, factory) +function! remote#host#Register(name, pattern, factory) abort let s:hosts[a:name] = {'factory': a:factory, 'channel': 0, 'initialized': 0} let s:plugin_patterns[a:name] = a:pattern if type(a:factory) == type(1) && a:factory @@ -19,7 +19,7 @@ endfunction " as `source`, but it will run as a different process. This can be used by " plugins that should run isolated from other plugins created for the same host " type -function! remote#host#RegisterClone(name, orig_name) +function! remote#host#RegisterClone(name, orig_name) abort if !has_key(s:hosts, a:orig_name) throw 'No host named "'.a:orig_name.'" is registered' endif @@ -34,7 +34,7 @@ endfunction " Get a host channel, bootstrapping it if necessary -function! remote#host#Require(name) +function! remote#host#Require(name) abort if !has_key(s:hosts, a:name) throw 'No host named "'.a:name.'" is registered' endif @@ -51,7 +51,7 @@ function! remote#host#Require(name) endfunction -function! remote#host#IsRunning(name) +function! remote#host#IsRunning(name) abort if !has_key(s:hosts, a:name) throw 'No host named "'.a:name.'" is registered' endif @@ -72,7 +72,7 @@ endfunction " " The third item in a declaration is a boolean: non zero means the command, " autocommand or function will be executed synchronously with rpcrequest. -function! remote#host#RegisterPlugin(host, path, specs) +function! remote#host#RegisterPlugin(host, path, specs) abort let plugins = remote#host#PluginsForHost(a:host) for plugin in plugins @@ -116,14 +116,14 @@ function! remote#host#RegisterPlugin(host, path, specs) endfunction -function! remote#host#LoadRemotePlugins() +function! remote#host#LoadRemotePlugins() abort if filereadable(s:remote_plugins_manifest) exe 'source '.s:remote_plugins_manifest endif endfunction -function! s:RegistrationCommands(host) +function! s:RegistrationCommands(host) abort " Register a temporary host clone for discovering specs let host_id = a:host.'-registration-clone' call remote#host#RegisterClone(host_id, a:host) @@ -163,7 +163,7 @@ function! s:RegistrationCommands(host) endfunction -function! s:UpdateRemotePlugins() +function! s:UpdateRemotePlugins() abort let commands = [] let hosts = keys(s:hosts) for host in hosts @@ -180,6 +180,8 @@ function! s:UpdateRemotePlugins() endif endfor call writefile(commands, s:remote_plugins_manifest) + echomsg printf('remote/host: generated the manifest file in "%s"', + \ s:remote_plugins_manifest) endfunction @@ -187,7 +189,7 @@ command! UpdateRemotePlugins call s:UpdateRemotePlugins() let s:plugins_for_host = {} -function! remote#host#PluginsForHost(host) +function! remote#host#PluginsForHost(host) abort if !has_key(s:plugins_for_host, a:host) let s:plugins_for_host[a:host] = [] end @@ -198,7 +200,7 @@ endfunction " Registration of standard hosts " Python/Python3 {{{ -function! s:RequirePythonHost(host) +function! s:RequirePythonHost(host) abort let ver = (a:host.orig_name ==# 'python') ? 2 : 3 " Python host arguments diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index a5f8660691..45980f5d94 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -4598,9 +4598,18 @@ matchadd({group}, {pattern}[, {priority}[, {id}]]) message will appear and the match will not be added. An ID is specified as a positive integer (zero excluded). IDs 1, 2 and 3 are reserved for |:match|, |:2match| and |:3match|, - respectively. If the {id} argument is not specified, + respectively. If the {id} argument is not specified or -1, |matchadd()| automatically chooses a free ID. + The optional {dict} argmument allows for further custom + values. Currently this is used to specify a match specifc + conceal character that will be shown for |hl-Conceal| + highlighted matches. The dict can have the following members: + + conceal Special character to show instead of the + match (only for |hl-Conceal| highlighed + matches, see |:syn-cchar|) + The number of matches is not limited, as it is the case with the |:match| commands. @@ -4614,7 +4623,7 @@ matchadd({group}, {pattern}[, {priority}[, {id}]]) available from |getmatches()|. All matches can be deleted in one operation by |clearmatches()|. -matchaddpos({group}, {pos}[, {priority}[, {id}]]) *matchaddpos()* +matchaddpos({group}, {pos}[, {priority}[, {id}[, {dict}]]]) *matchaddpos()* Same as |matchadd()|, but requires a list of positions {pos} instead of a pattern. This command is faster than |matchadd()| because it does not require to handle regular expressions and diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt index ca02050cb8..be108d4633 100644 --- a/runtime/doc/starting.txt +++ b/runtime/doc/starting.txt @@ -315,9 +315,10 @@ argument. When {vimrc} is equal to "NONE" (all uppercase), all initializations from files and environment variables are skipped, including reading the |ginit.vim| file when the GUI - starts. Loading plugins is also skipped. + starts. Plugins and syntax highlighting are also skipped. When {vimrc} is equal to "NORC" (all uppercase), this has the - same effect as "NONE", but loading plugins is not skipped. + same effect as "NONE", but plugins and syntax highlighting are + not skipped. *-i* -i {shada} The file {shada} is used instead of the default ShaDa @@ -391,7 +392,8 @@ accordingly. Vim proceeds in this order: All following initializations until 4. are skipped. $MYVIMRC is not set. "vim -u NORC" can be used to skip these initializations without - reading a file. "vim -u NONE" also skips loading plugins. |-u| + reading a file. "vim -u NONE" also skips plugins and syntax + highlighting. |-u| If Vim was started in Ex mode with the "-s" argument, all following initializations until 4. are skipped. Only the "-u" option is @@ -424,7 +426,22 @@ accordingly. Vim proceeds in this order: - The file ".exrc" (for Unix) "_exrc" (for Win32) -4. Load the plugin scripts. *load-plugins* +4. Enable filetype and indent plugins. + This does the same as the commands: > + :runtime! filetype.vim + :runtime! ftplugin.vim + :runtime! indent.vim +< This step is skipped if ":filetype ..." was called before now or if + the "-u NONE" command line argument was given. + +5. Enable syntax highlighting. + This does the same as the command: > + :runtime! syntax/syntax.vim +< Note: This enables filetype detection even if ":filetype off" was + called before now. + This step is skipped if the "-u NONE" command line argument was given. + +6. Load the plugin scripts. *load-plugins* This does the same as the command: > :runtime! plugin/**/*.vim < The result is that all directories in the 'runtimepath' option will be @@ -440,31 +457,30 @@ accordingly. Vim proceeds in this order: commands from the command line have not been executed yet. You can use "--cmd 'set noloadplugins'" |--cmd|. -5. Set 'shellpipe' and 'shellredir' +7. Set 'shellpipe' and 'shellredir' The 'shellpipe' and 'shellredir' options are set according to the value of the 'shell' option, unless they have been set before. This means that Vim will figure out the values of 'shellpipe' and 'shellredir' for you, unless you have set them yourself. -6. Set 'updatecount' to zero, if "-n" command argument used +8. Set 'updatecount' to zero, if "-n" command argument used -7. Set binary options +9. Set binary options If the "-b" flag was given to Vim, the options for binary editing will be set now. See |-b|. -8. Perform GUI initializations +10. Perform GUI initializations Only when starting "gvim", the GUI initializations will be done. See |gui-init|. -9. Read the ShaDa file - If the 'shada' option is not empty, the ShaDa file is read. See - |shada-file|. +11. Read the ShaDa file + See |shada-file|. -10. Read the quickfix file +12. Read the quickfix file If the "-q" flag was given to Vim, the quickfix file is read. If this fails, Vim exits. -11. Open all windows +13. Open all windows When the |-o| flag was given, windows will be opened (but not displayed yet). When the |-p| flag was given, tab pages will be created (but not @@ -473,7 +489,7 @@ accordingly. Vim proceeds in this order: If the "-q" flag was given to Vim, the first error is jumped to. Buffers for all windows will be loaded. -12. Execute startup commands +14. Execute startup commands If a "-t" flag was given to Vim, the tag is jumped to. The commands given with the |-c| and |+cmd| arguments are executed. The starting flag is reset, has("vim_starting") will now return zero. diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt index f76e901b9a..d3768409f5 100644 --- a/runtime/doc/vim_diff.txt +++ b/runtime/doc/vim_diff.txt @@ -11,7 +11,7 @@ the "{Nvim}" tag. This document is a complete and centralized list of all these differences. 1. Configuration |nvim-configuration| -2. Option defaults |nvim-option-defaults| +2. Defaults |nvim-defaults| 3. Changed features |nvim-features-changed| 4. New features |nvim-features-new| 5. Missing legacy features |nvim-features-missing| @@ -28,7 +28,12 @@ these differences. session information. ============================================================================== -2. Option defaults *nvim-option-defaults* +2. Defaults *nvim-defaults* + +- Syntax highlighting is enabled by default +- Filetype-related plugins and scripts are enabled by default + Note: these defaults can be disabled with the "-u NONE" command line + argument. |-u| - 'autoindent' is set by default - 'autoread' is set by default @@ -45,7 +50,7 @@ these differences. - 'listchars' defaults to "tab:> ,trail:-,nbsp:+" - 'mouse' defaults to "a" - 'nocompatible' is always set -- 'nrformats' defaults to "hex" +- 'nrformats' defaults to "bin,hex" - 'sessionoptions' doesn't include "options" - 'smarttab' is set by default - 'tabpagemax' defaults to 50 diff --git a/runtime/plugin/rplugin.vim b/runtime/plugin/rplugin.vim index 2b2d333738..879775ff0e 100644 --- a/runtime/plugin/rplugin.vim +++ b/runtime/plugin/rplugin.vim @@ -1,5 +1,5 @@ -if exists('loaded_remote_plugins') || &cp +if exists('g:loaded_remote_plugins') || &cp finish endif -let loaded_remote_plugins = 1 +let g:loaded_remote_plugins = 1 call remote#host#LoadRemotePlugins() diff --git a/scripts/gendeclarations.lua b/scripts/gendeclarations.lua index 4e74e4e301..637f4cdffa 100755 --- a/scripts/gendeclarations.lua +++ b/scripts/gendeclarations.lua @@ -239,23 +239,24 @@ end non_static = non_static .. footer static = static .. footer -local F -F = io.open(static_fname, 'w') -F:write(static) -F:close() --- Before generating the non-static headers, check if the current file(if --- exists) is different from the new one. If they are the same, we won't touch --- the current version to avoid triggering an unnecessary rebuilds of modules +-- Before generating the headers, check if the current file (if exists) is +-- different from the new one. If they are the same, we won't touch the +-- current version to avoid triggering an unnecessary rebuilds of modules -- that depend on this one -F = io.open(non_static_fname, 'r') -if F ~= nil then - if F:read('*a') == non_static then - os.exit(0) +local update_changed = function (fname, contents) + local F = io.open(fname, 'r') + if F ~= nil then + if F:read('*a') == contents then + return + end + io.close(F) end - io.close(F) + + F = io.open(fname, 'w') + F:write(contents) + F:close() end -F = io.open(non_static_fname, 'w') -F:write(non_static) -F:close() +update_changed(static_fname, static) +update_changed(non_static_fname, non_static) diff --git a/scripts/genoptions.lua b/scripts/genoptions.lua index 2859ca1795..da53d010bd 100644 --- a/scripts/genoptions.lua +++ b/scripts/genoptions.lua @@ -39,6 +39,7 @@ local redraw_flags={ local list_flags={ comma='P_COMMA', + onecomma='P_ONECOMMA', flags='P_FLAGLIST', flagscomma='P_COMMA|P_FLAGLIST', } diff --git a/scripts/legacy2luatest.pl b/scripts/legacy2luatest.pl index ebd8dad1e1..8155353fc7 100755 --- a/scripts/legacy2luatest.pl +++ b/scripts/legacy2luatest.pl @@ -287,7 +287,7 @@ local feed, insert, source = helpers.feed, helpers.insert, helpers.source local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect describe('$test_name', function() - setup(clear) + before_each(clear) it('is working', function() @{[join "\n", map { /^$/ ? '' : ' ' . $_ } @{$test_body_lines}]} diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 78d9a9484e..bdea609820 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -592,71 +592,72 @@ struct file_buffer { int b_p_scriptID[BV_COUNT]; /* SIDs for buffer-local options */ - int b_p_ai; /* 'autoindent' */ - int b_p_ai_nopaste; /* b_p_ai saved for paste mode */ - char_u *b_p_bkc; ///< 'backupcopy' - unsigned int b_bkc_flags; ///< flags for 'backupcopy' - int b_p_ci; /* 'copyindent' */ - int b_p_bin; /* 'binary' */ - int b_p_bomb; /* 'bomb' */ - char_u *b_p_bh; /* 'bufhidden' */ - char_u *b_p_bt; /* 'buftype' */ - int b_p_bl; /* 'buflisted' */ - int b_p_cin; /* 'cindent' */ - char_u *b_p_cino; /* 'cinoptions' */ - char_u *b_p_cink; /* 'cinkeys' */ - char_u *b_p_cinw; /* 'cinwords' */ - char_u *b_p_com; /* 'comments' */ - char_u *b_p_cms; /* 'commentstring' */ - char_u *b_p_cpt; /* 'complete' */ - char_u *b_p_cfu; /* 'completefunc' */ - char_u *b_p_ofu; /* 'omnifunc' */ - int b_p_eol; /* 'endofline' */ - int b_p_fixeol; /* 'fixendofline' */ - int b_p_et; /* 'expandtab' */ - int b_p_et_nobin; /* b_p_et saved for binary mode */ - char_u *b_p_fenc; /* 'fileencoding' */ - char_u *b_p_ff; /* 'fileformat' */ - char_u *b_p_ft; /* 'filetype' */ - char_u *b_p_fo; /* 'formatoptions' */ - char_u *b_p_flp; /* 'formatlistpat' */ - int b_p_inf; /* 'infercase' */ - char_u *b_p_isk; /* 'iskeyword' */ - char_u *b_p_def; /* 'define' local value */ - char_u *b_p_inc; /* 'include' */ - char_u *b_p_inex; /* 'includeexpr' */ - uint32_t b_p_inex_flags; /* flags for 'includeexpr' */ - char_u *b_p_inde; /* 'indentexpr' */ - uint32_t b_p_inde_flags; /* flags for 'indentexpr' */ - char_u *b_p_indk; /* 'indentkeys' */ - char_u *b_p_fex; /* 'formatexpr' */ - uint32_t b_p_fex_flags; /* flags for 'formatexpr' */ - char_u *b_p_kp; /* 'keywordprg' */ - int b_p_lisp; /* 'lisp' */ - char_u *b_p_mps; /* 'matchpairs' */ - int b_p_ml; /* 'modeline' */ - int b_p_ml_nobin; /* b_p_ml saved for binary mode */ - int b_p_ma; /* 'modifiable' */ - char_u *b_p_nf; /* 'nrformats' */ - int b_p_pi; /* 'preserveindent' */ - char_u *b_p_qe; /* 'quoteescape' */ - int b_p_ro; /* 'readonly' */ - long b_p_sw; /* 'shiftwidth' */ - int b_p_si; /* 'smartindent' */ - long b_p_sts; /* 'softtabstop' */ - long b_p_sts_nopaste; /* b_p_sts saved for paste mode */ - char_u *b_p_sua; /* 'suffixesadd' */ - bool b_p_swf; /* 'swapfile' */ - long b_p_smc; /* 'synmaxcol' */ - char_u *b_p_syn; /* 'syntax' */ - long b_p_ts; /* 'tabstop' */ - long b_p_tw; /* 'textwidth' */ - long b_p_tw_nobin; /* b_p_tw saved for binary mode */ - long b_p_tw_nopaste; /* b_p_tw saved for paste mode */ - long b_p_wm; /* 'wrapmargin' */ - long b_p_wm_nobin; /* b_p_wm saved for binary mode */ - long b_p_wm_nopaste; /* b_p_wm saved for paste mode */ - char_u *b_p_keymap; /* 'keymap' */ + int b_p_ai; ///< 'autoindent' + int b_p_ai_nopaste; ///< b_p_ai saved for paste mode + char_u *b_p_bkc; ///< 'backupco + unsigned int b_bkc_flags; ///< flags for 'backupco + int b_p_ci; ///< 'copyindent' + int b_p_bin; ///< 'binary' + int b_p_bomb; ///< 'bomb' + char_u *b_p_bh; ///< 'bufhidden' + char_u *b_p_bt; ///< 'buftype' + int b_p_bl; ///< 'buflisted' + int b_p_cin; ///< 'cindent' + char_u *b_p_cino; ///< 'cinoptions' + char_u *b_p_cink; ///< 'cinkeys' + char_u *b_p_cinw; ///< 'cinwords' + char_u *b_p_com; ///< 'comments' + char_u *b_p_cms; ///< 'commentstring' + char_u *b_p_cpt; ///< 'complete' + char_u *b_p_cfu; ///< 'completefunc' + char_u *b_p_ofu; ///< 'omnifunc' + int b_p_eol; ///< 'endofline' + int b_p_fixeol; ///< 'fixendofline' + int b_p_et; ///< 'expandtab' + int b_p_et_nobin; ///< b_p_et saved for binary mode + int b_p_et_nopaste; ///< b_p_et saved for paste mode + char_u *b_p_fenc; ///< 'fileencoding' + char_u *b_p_ff; ///< 'fileformat' + char_u *b_p_ft; ///< 'filetype' + char_u *b_p_fo; ///< 'formatoptions' + char_u *b_p_flp; ///< 'formatlistpat' + int b_p_inf; ///< 'infercase' + char_u *b_p_isk; ///< 'iskeyword' + char_u *b_p_def; ///< 'define' local value + char_u *b_p_inc; ///< 'include' + char_u *b_p_inex; ///< 'includeexpr' + uint32_t b_p_inex_flags; ///< flags for 'includeexpr' + char_u *b_p_inde; ///< 'indentexpr' + uint32_t b_p_inde_flags; ///< flags for 'indentexpr' + char_u *b_p_indk; ///< 'indentkeys' + char_u *b_p_fex; ///< 'formatexpr' + uint32_t b_p_fex_flags; ///< flags for 'formatexpr' + char_u *b_p_kp; ///< 'keywordprg' + int b_p_lisp; ///< 'lisp' + char_u *b_p_mps; ///< 'matchpairs' + int b_p_ml; ///< 'modeline' + int b_p_ml_nobin; ///< b_p_ml saved for binary mode + int b_p_ma; ///< 'modifiable' + char_u *b_p_nf; ///< 'nrformats' + int b_p_pi; ///< 'preserveindent' + char_u *b_p_qe; ///< 'quoteescape' + int b_p_ro; ///< 'readonly' + long b_p_sw; ///< 'shiftwidth' + int b_p_si; ///< 'smartindent' + long b_p_sts; ///< 'softtabstop' + long b_p_sts_nopaste; ///< b_p_sts saved for paste mode + char_u *b_p_sua; ///< 'suffixesadd' + bool b_p_swf; ///< 'swapfile' + long b_p_smc; ///< 'synmaxcol' + char_u *b_p_syn; ///< 'syntax' + long b_p_ts; ///< 'tabstop' + long b_p_tw; ///< 'textwidth' + long b_p_tw_nobin; ///< b_p_tw saved for binary mode + long b_p_tw_nopaste; ///< b_p_tw saved for paste mode + long b_p_wm; ///< 'wrapmargin' + long b_p_wm_nobin; ///< b_p_wm saved for binary mode + long b_p_wm_nopaste; ///< b_p_wm saved for paste mode + char_u *b_p_keymap; ///< 'keymap' /* local values for options which are normally global */ char_u *b_p_gp; /* 'grepprg' local value */ @@ -904,13 +905,14 @@ struct posmatch typedef struct matchitem matchitem_T; struct matchitem { matchitem_T *next; - int id; /* match ID */ - int priority; /* match priority */ - char_u *pattern; /* pattern to highlight */ - int hlg_id; /* highlight group ID */ - regmmatch_T match; /* regexp program for pattern */ - posmatch_T pos; // position matches - match_T hl; /* struct for doing the actual highlighting */ + int id; ///< match ID + int priority; ///< match priority + char_u *pattern; ///< pattern to highlight + int hlg_id; ///< highlight group ID + regmmatch_T match; ///< regexp program for pattern + posmatch_T pos; ///< position matches + match_T hl; ///< struct for doing the actual highlighting + int conceal_char; ///< cchar for Conceal highlighting }; /* diff --git a/src/nvim/diff.c b/src/nvim/diff.c index e06ffd0bbc..0be8b3c514 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -1531,37 +1531,37 @@ int diff_check(win_T *wp, linenr_T lnum) return maxcount - dp->df_count[idx]; } -/// Compare two entries in diff "*dp" and return TRUE if they are equal. +/// Compare two entries in diff "dp" and return true if they are equal. /// -/// @param dp -/// @param idx1 First entry in diff "*dp" -/// @param idx2 Second entry in diff "*dp" +/// @param dp diff +/// @param idx1 first entry in diff "dp" +/// @param idx2 second entry in diff "dp" /// -/// @return return TRUE if two entires are equal. -static int diff_equal_entry(diff_T *dp, int idx1, int idx2) +/// @return true if two entires are equal. +static bool diff_equal_entry(diff_T *dp, int idx1, int idx2) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1) { if (dp->df_count[idx1] != dp->df_count[idx2]) { - return FALSE; + return false; } if (diff_check_sanity(curtab, dp) == FAIL) { - return FALSE; + return false; } - int i; - for (i = 0; i < dp->df_count[idx1]; ++i) { + for (int i = 0; i < dp->df_count[idx1]; i++) { char_u *line = vim_strsave(ml_get_buf(curtab->tp_diffbuf[idx1], - dp->df_lnum[idx1] + i, FALSE)); + dp->df_lnum[idx1] + i, false)); int cmp = diff_cmp(line, ml_get_buf(curtab->tp_diffbuf[idx2], - dp->df_lnum[idx2] + i, FALSE)); + dp->df_lnum[idx2] + i, false)); xfree(line); if (cmp != 0) { - return FALSE; + return false; } } - return TRUE; + return true; } /// Compare strings "s1" and "s2" according to 'diffopt'. @@ -1830,28 +1830,30 @@ int diffopt_changed(void) return OK; } -/// Return TRUE if 'diffopt' contains "horizontal". -/// -/// @return TRUE if 'diffopt' contains "horizontal" -int diffopt_horizontal(void) +/// Check that "diffopt" contains "horizontal". +bool diffopt_horizontal(void) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { return (diff_flags & DIFF_HORIZONTAL) != 0; } /// Find the difference within a changed line. /// -/// @param startp first char of the change -/// @param endp last char of the change +/// @param wp window whose current buffer to check +/// @param lnum line number to check within the buffer +/// @param startp first char of the change +/// @param endp last char of the change /// -/// @returns TRUE if the line was added, no other buffer has it. -int diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp) +/// @return true if the line was added, no other buffer has it. +bool diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp) + FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { char_u *line_new; int si_org; int si_new; int ei_org; int ei_new; - int added = TRUE; + bool added = true; // Make a copy of the line, the next ml_get() will invalidate it. char_u *line_org = vim_strsave(ml_get_buf(wp->w_buffer, lnum, FALSE)); @@ -1860,7 +1862,7 @@ int diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp) if (idx == DB_COUNT) { // cannot happen xfree(line_org); - return FALSE; + return false; } // search for a change that includes "lnum" in the list of diffblocks. @@ -1873,7 +1875,7 @@ int diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp) if ((dp == NULL) || (diff_check_sanity(curtab, dp) == FAIL)) { xfree(line_org); - return FALSE; + return false; } int off = lnum - dp->df_lnum[idx]; @@ -1884,7 +1886,7 @@ int diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp) if (off >= dp->df_count[i]) { continue; } - added = FALSE; + added = false; line_new = ml_get_buf(curtab->tp_diffbuf[i], dp->df_lnum[i] + off, FALSE); @@ -1956,21 +1958,22 @@ int diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp) return added; } -/// Return TRUE if line "lnum" is not close to a diff block, this line should +/// Check that line "lnum" is not close to a diff block, this line should /// be in a fold. /// -/// @param wp -/// @param lnum +/// @param wp window containing the buffer to check +/// @param lnum line number to check within the buffer /// -/// @return FALSE if there are no diff blocks at all in this window. -int diff_infold(win_T *wp, linenr_T lnum) +/// @return false if there are no diff blocks at all in this window. +bool diff_infold(win_T *wp, linenr_T lnum) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1) { - int other = FALSE; + bool other = false; diff_T *dp; // Return if 'diff' isn't set. if (!wp->w_p_diff) { - return FALSE; + return false; } int idx = -1; @@ -1979,13 +1982,13 @@ int diff_infold(win_T *wp, linenr_T lnum) if (curtab->tp_diffbuf[i] == wp->w_buffer) { idx = i; } else if (curtab->tp_diffbuf[i] != NULL) { - other = TRUE; + other = true; } } // return here if there are no diffs in the window if ((idx == -1) || !other) { - return FALSE; + return false; } if (curtab->tp_diff_invalid) { @@ -1995,7 +1998,7 @@ int diff_infold(win_T *wp, linenr_T lnum) // Return if there are no diff blocks. All lines will be folded. if (curtab->tp_first_diff == NULL) { - return TRUE; + return true; } for (dp = curtab->tp_first_diff; dp != NULL; dp = dp->df_next) { @@ -2006,10 +2009,10 @@ int diff_infold(win_T *wp, linenr_T lnum) // If this change ends before the line we have a match. if (dp->df_lnum[idx] + dp->df_count[idx] + diff_context > lnum) { - return FALSE; + return false; } } - return TRUE; + return true; } /// "dp" and "do" commands. @@ -2372,12 +2375,11 @@ static void diff_fold_update(diff_T *dp, int skip_idx) } } -/// Checks if the buffer is in diff-mode. -/// -/// @param buf The buffer to check. +/// Checks that the buffer is in diff-mode. /// -/// @return TRUE if buffer "buf" is in diff-mode. +/// @param buf buffer to check. bool diff_mode_buf(buf_T *buf) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1) { FOR_ALL_TABS(tp) { if (diff_buf_idx_tp(buf, tp) != DB_COUNT) { diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 213df4f65a..d3b556f669 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -2464,6 +2464,14 @@ void ins_compl_show_pum(void) /* Need to build the popup menu list. */ compl_match_arraysize = 0; compl = compl_first_match; + /* + * If it's user complete function and refresh_always, + * not use "compl_leader" as prefix filter. + */ + if (ins_compl_need_restart()){ + xfree(compl_leader); + compl_leader = NULL; + } if (compl_leader != NULL) lead_len = (int)STRLEN(compl_leader); do { @@ -2932,11 +2940,9 @@ static void ins_compl_new_leader(void) else { spell_bad_len = 0; /* need to redetect bad word */ /* - * Matches were cleared, need to search for them now. First display - * the changed text before the cursor. Set "compl_restarting" to - * avoid that the first match is inserted. + * Matches were cleared, need to search for them now. + * Set "compl_restarting" to avoid that the first match is inserted. */ - update_screen(0); compl_restarting = TRUE; if (ins_complete(Ctrl_N) == FAIL) compl_cont_status = 0; @@ -2948,8 +2954,9 @@ static void ins_compl_new_leader(void) /* Show the popup menu with a different set of matches. */ ins_compl_show_pum(); - /* Don't let Enter select the original text when there is no popup menu. */ - if (compl_match_array == NULL) + /* Don't let Enter select the original text when there is no popup menu. + * Don't let Enter select when use user function and refresh_always is set */ + if (compl_match_array == NULL || ins_compl_need_restart()) compl_enter_selects = FALSE; } @@ -2980,27 +2987,18 @@ static void ins_compl_addleader(int c) (*mb_char2bytes)(c, buf); buf[cc] = NUL; ins_char_bytes(buf, cc); - if (compl_opt_refresh_always) - AppendToRedobuff(buf); } else { ins_char(c); - if (compl_opt_refresh_always) - AppendCharToRedobuff(c); } /* If we didn't complete finding matches we must search again. */ if (ins_compl_need_restart()) ins_compl_restart(); - /* When 'always' is set, don't reset compl_leader. While completing, - * cursor doesn't point original position, changing compl_leader would - * break redo. */ - if (!compl_opt_refresh_always) { - xfree(compl_leader); - compl_leader = vim_strnsave(get_cursor_line_ptr() + compl_col, - (int)(curwin->w_cursor.col - compl_col)); - ins_compl_new_leader(); - } + xfree(compl_leader); + compl_leader = vim_strnsave(get_cursor_line_ptr() + compl_col, + (int)(curwin->w_cursor.col - compl_col)); + ins_compl_new_leader(); } /* @@ -3009,6 +3007,10 @@ static void ins_compl_addleader(int c) */ static void ins_compl_restart(void) { + /* update screen before restart. + * so if complete is blocked, + * will stay to the last popup menu and reduce flicker */ + update_screen(0); ins_compl_free(); compl_started = FALSE; compl_matches = 0; diff --git a/src/nvim/eval.c b/src/nvim/eval.c index b9b913a969..327d0bf637 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -7270,8 +7270,8 @@ static struct fst { { "maparg", 1, 4, f_maparg }, { "mapcheck", 1, 3, f_mapcheck }, { "match", 2, 4, f_match }, - { "matchadd", 2, 4, f_matchadd }, - { "matchaddpos", 2, 4, f_matchaddpos }, + { "matchadd", 2, 5, f_matchadd }, + { "matchaddpos", 2, 5, f_matchaddpos }, { "matcharg", 1, 1, f_matcharg }, { "matchdelete", 1, 1, f_matchdelete }, { "matchend", 2, 4, f_matchend }, @@ -10422,6 +10422,14 @@ static void f_getmatches(typval_T *argvars, typval_T *rettv) dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id)); dict_add_nr_str(dict, "priority", (long)cur->priority, NULL); dict_add_nr_str(dict, "id", (long)cur->id, NULL); + + if (cur->conceal_char) { + char_u buf[MB_MAXBYTES + 1]; + + buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL; + dict_add_nr_str(dict, "conceal", 0L, (char_u *)&buf); + } + list_append_dict(rettv->vval.v_list, dict); cur = cur->next; } @@ -12487,7 +12495,8 @@ static void f_matchadd(typval_T *argvars, typval_T *rettv) char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */ int prio = 10; /* default priority */ int id = -1; - int error = FALSE; + int error = false; + char_u *conceal_char = NULL; rettv->vval.v_number = -1; @@ -12495,17 +12504,31 @@ static void f_matchadd(typval_T *argvars, typval_T *rettv) return; if (argvars[2].v_type != VAR_UNKNOWN) { prio = get_tv_number_chk(&argvars[2], &error); - if (argvars[3].v_type != VAR_UNKNOWN) + if (argvars[3].v_type != VAR_UNKNOWN) { id = get_tv_number_chk(&argvars[3], &error); + if (argvars[4].v_type != VAR_UNKNOWN) { + if (argvars[4].v_type != VAR_DICT) { + EMSG(_(e_dictreq)); + return; + } + if (dict_find(argvars[4].vval.v_dict, + (char_u *)"conceal", -1) != NULL) { + conceal_char = get_dict_string(argvars[4].vval.v_dict, + (char_u *)"conceal", false); + } + } + } } - if (error == TRUE) + if (error == true) { return; + } if (id >= 1 && id <= 3) { EMSGN("E798: ID is reserved for \":match\": %" PRId64, id); return; } - rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL); + rettv->vval.v_number = match_add(curwin, grp, pat, prio, id, NULL, + conceal_char); } static void f_matchaddpos(typval_T *argvars, typval_T *rettv) FUNC_ATTR_NONNULL_ALL @@ -12533,12 +12556,24 @@ static void f_matchaddpos(typval_T *argvars, typval_T *rettv) FUNC_ATTR_NONNULL_ int error = false; int prio = 10; int id = -1; + char_u *conceal_char = NULL; if (argvars[2].v_type != VAR_UNKNOWN) { - prio = get_tv_number_chk(&argvars[2], &error); - if (argvars[3].v_type != VAR_UNKNOWN) { - id = get_tv_number_chk(&argvars[3], &error); + prio = get_tv_number_chk(&argvars[2], &error); + if (argvars[3].v_type != VAR_UNKNOWN) { + id = get_tv_number_chk(&argvars[3], &error); + if (argvars[4].v_type != VAR_UNKNOWN) { + if (argvars[4].v_type != VAR_DICT) { + EMSG(_(e_dictreq)); + return; + } + if (dict_find(argvars[4].vval.v_dict, + (char_u *)"conceal", -1) != NULL) { + conceal_char = get_dict_string(argvars[4].vval.v_dict, + (char_u *)"conceal", false); + } } + } } if (error == true) { return; @@ -12550,7 +12585,8 @@ static void f_matchaddpos(typval_T *argvars, typval_T *rettv) FUNC_ATTR_NONNULL_ return; } - rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l); + rettv->vval.v_number = match_add(curwin, group, NULL, prio, id, l, + conceal_char); } /* @@ -15259,8 +15295,8 @@ static void f_setmatches(typval_T *argvars, typval_T *rettv) int i = 0; char_u buf[5]; dictitem_T *di; - d = li->li_tv.vval.v_dict; + d = li->li_tv.vval.v_dict; if (dict_find(d, (char_u *)"pattern", -1) == NULL) { if (s == NULL) { s = list_alloc(); @@ -15285,15 +15321,19 @@ static void f_setmatches(typval_T *argvars, typval_T *rettv) } } + char_u *group = get_dict_string(d, (char_u *)"group", false); + int priority = get_dict_number(d, (char_u *)"priority"); + int id = get_dict_number(d, (char_u *)"id"); + char_u *conceal = dict_find(d, (char_u *)"conceal", -1) != NULL + ? get_dict_string(d, (char_u *)"conceal", + false) + : NULL; if (i == 0) { - match_add(curwin, get_dict_string(d, (char_u *)"group", false), + match_add(curwin, group, get_dict_string(d, (char_u *)"pattern", false), - (int)get_dict_number(d, (char_u *)"priority"), - (int)get_dict_number(d, (char_u *)"id"), NULL); + priority, id, NULL, conceal); } else { - match_add(curwin, get_dict_string(d, (char_u *)"group", false), - NULL, (int)get_dict_number(d, (char_u *)"priority"), - (int)get_dict_number(d, (char_u *)"id"), s); + match_add(curwin, group, NULL, priority, id, s, conceal); list_unref(s); s = NULL; } diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index d6976bcb8f..dfae2b849d 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -9222,9 +9222,9 @@ char_u *get_behave_arg(expand_T *xp, int idx) return NULL; } -static int filetype_detect = FALSE; -static int filetype_plugin = FALSE; -static int filetype_indent = FALSE; +static TriState filetype_detect = kNone; +static TriState filetype_plugin = kNone; +static TriState filetype_indent = kNone; /* * ":filetype [plugin] [indent] {on,off,detect}" @@ -9238,27 +9238,27 @@ static int filetype_indent = FALSE; static void ex_filetype(exarg_T *eap) { char_u *arg = eap->arg; - int plugin = FALSE; - int indent = FALSE; + bool plugin = false; + bool indent = false; if (*eap->arg == NUL) { /* Print current status. */ smsg("filetype detection:%s plugin:%s indent:%s", - filetype_detect ? "ON" : "OFF", - filetype_plugin ? (filetype_detect ? "ON" : "(on)") : "OFF", - filetype_indent ? (filetype_detect ? "ON" : "(on)") : "OFF"); + filetype_detect == kTrue ? "ON" : "OFF", + filetype_plugin == kTrue ? (filetype_detect == kTrue ? "ON" : "(on)") : "OFF", // NOLINT(whitespace/line_length) + filetype_indent == kTrue ? (filetype_detect == kTrue ? "ON" : "(on)") : "OFF"); // NOLINT(whitespace/line_length) return; } /* Accept "plugin" and "indent" in any order. */ for (;; ) { if (STRNCMP(arg, "plugin", 6) == 0) { - plugin = TRUE; + plugin = true; arg = skipwhite(arg + 6); continue; } if (STRNCMP(arg, "indent", 6) == 0) { - indent = TRUE; + indent = true; arg = skipwhite(arg + 6); continue; } @@ -9266,15 +9266,15 @@ static void ex_filetype(exarg_T *eap) } if (STRCMP(arg, "on") == 0 || STRCMP(arg, "detect") == 0) { if (*arg == 'o' || !filetype_detect) { - source_runtime((char_u *)FILETYPE_FILE, TRUE); - filetype_detect = TRUE; + source_runtime((char_u *)FILETYPE_FILE, true); + filetype_detect = kTrue; if (plugin) { - source_runtime((char_u *)FTPLUGIN_FILE, TRUE); - filetype_plugin = TRUE; + source_runtime((char_u *)FTPLUGIN_FILE, true); + filetype_plugin = kTrue; } if (indent) { - source_runtime((char_u *)INDENT_FILE, TRUE); - filetype_indent = TRUE; + source_runtime((char_u *)INDENT_FILE, true); + filetype_indent = kTrue; } } if (*arg == 'd') { @@ -9284,21 +9284,37 @@ static void ex_filetype(exarg_T *eap) } else if (STRCMP(arg, "off") == 0) { if (plugin || indent) { if (plugin) { - source_runtime((char_u *)FTPLUGOF_FILE, TRUE); - filetype_plugin = FALSE; + source_runtime((char_u *)FTPLUGOF_FILE, true); + filetype_plugin = kFalse; } if (indent) { - source_runtime((char_u *)INDOFF_FILE, TRUE); - filetype_indent = FALSE; + source_runtime((char_u *)INDOFF_FILE, true); + filetype_indent = kFalse; } } else { - source_runtime((char_u *)FTOFF_FILE, TRUE); - filetype_detect = FALSE; + source_runtime((char_u *)FTOFF_FILE, true); + filetype_detect = kFalse; } } else EMSG2(_(e_invarg2), arg); } +/// Do ":filetype plugin indent on" if user did not already do some +/// permutation thereof. +void filetype_maybe_enable(void) +{ + if (filetype_detect == kNone + && filetype_plugin == kNone + && filetype_indent == kNone) { + source_runtime((char_u *)FILETYPE_FILE, true); + filetype_detect = kTrue; + source_runtime((char_u *)FTPLUGIN_FILE, true); + filetype_plugin = kTrue; + source_runtime((char_u *)INDENT_FILE, true); + filetype_indent = kTrue; + } +} + /* * ":setfiletype {name}" */ @@ -9388,7 +9404,7 @@ static void ex_match(exarg_T *eap) c = *end; *end = NUL; - match_add(curwin, g, p + 1, 10, id, NULL); + match_add(curwin, g, p + 1, 10, id, NULL, NULL); xfree(g); *end = c; } diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 697a4a765a..69e65c3208 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -100,6 +100,12 @@ # define VIMRC_FILE ".nvimrc" #endif +typedef enum { + kNone = -1, + kFalse = 0, + kTrue = 1, +} TriState; + /* Values for "starting" */ #define NO_SCREEN 2 /* no screen updating yet */ #define NO_BUFFERS 1 /* not all buffers loaded yet */ diff --git a/src/nvim/main.c b/src/nvim/main.c index a8c2cebbbd..d3cdfe3edf 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -332,6 +332,14 @@ int main(int argc, char **argv) /* Source startup scripts. */ source_startup_scripts(¶ms); + // If using the runtime (-u is not NONE), enable syntax & filetype plugins. + if (params.use_vimrc != NULL && strcmp(params.use_vimrc, "NONE") != 0) { + // Does ":filetype plugin indent on". + filetype_maybe_enable(); + // Sources syntax/syntax.vim, which calls `:filetype on`. + syn_maybe_on(); + } + /* * Read all the plugin files. * Only when compiled with +eval, since most plugins need it. diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 049d650f86..e6c5354941 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -1538,9 +1538,11 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) curbuf->b_visual_mode_eval = VIsual_mode; } - /* In Select mode, a linewise selection is operated upon like a - * characterwise selection. */ - if (VIsual_select && VIsual_mode == 'V') { + // In Select mode, a linewise selection is operated upon like a + // characterwise selection. + // Special case: gH<Del> deletes the last line. + if (VIsual_select && VIsual_mode == 'V' + && cap->oap->op_type != OP_DELETE) { if (lt(VIsual, curwin->w_cursor)) { VIsual.col = 0; curwin->w_cursor.col = @@ -1676,20 +1678,15 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) && (include_line_break || !virtual_op) ) { oap->inclusive = false; - /* Try to include the newline, unless it's an operator - * that works on lines only. */ - if (*p_sel != 'o' && !op_on_lines(oap->op_type)) { - if (oap->end.lnum < curbuf->b_ml.ml_line_count) { - ++oap->end.lnum; - oap->end.col = 0; - oap->end.coladd = 0; - ++oap->line_count; - } else { - /* Cannot move below the last line, make the op - * inclusive to tell the operation to include the - * line break. */ - oap->inclusive = true; - } + // Try to include the newline, unless it's an operator + // that works on lines only. + if (*p_sel != 'o' + && !op_on_lines(oap->op_type) + && oap->end.lnum < curbuf->b_ml.ml_line_count) { + oap->end.lnum++; + oap->end.col = 0; + oap->end.coladd = 0; + oap->line_count++; } } } @@ -7748,6 +7745,10 @@ static void nv_put(cmdarg_T *cap) if (was_visual) { curbuf->b_visual.vi_start = curbuf->b_op_start; curbuf->b_visual.vi_end = curbuf->b_op_end; + // need to adjust cursor position + if (*p_sel == 'e') { + inc(&curbuf->b_visual.vi_end); + } } /* When all lines were selected and deleted do_put() leaves an empty diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 7614e6365a..b1adc85e1d 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -1555,55 +1555,31 @@ int op_delete(oparg_T *oap) if (gchar_cursor() != NUL) curwin->w_cursor.coladd = 0; } - if (oap->op_type == OP_DELETE - && oap->inclusive - && oap->end.lnum == curbuf->b_ml.ml_line_count - && n > (int)STRLEN(ml_get(oap->end.lnum))) { - /* Special case: gH<Del> deletes the last line. */ - del_lines(1L, FALSE); - } else { - (void)del_bytes((long)n, !virtual_op, oap->op_type == OP_DELETE - && !oap->is_VIsual - ); - } - } else { /* delete characters between lines */ + + (void)del_bytes((long)n, !virtual_op, + oap->op_type == OP_DELETE && !oap->is_VIsual); + } else { + // delete characters between lines pos_T curpos; - int delete_last_line; /* save deleted and changed lines for undo */ if (u_save((linenr_T)(curwin->w_cursor.lnum - 1), (linenr_T)(curwin->w_cursor.lnum + oap->line_count)) == FAIL) return FAIL; - delete_last_line = (oap->end.lnum == curbuf->b_ml.ml_line_count); - truncate_line(TRUE); /* delete from cursor to end of line */ + truncate_line(true); // delete from cursor to end of line - curpos = curwin->w_cursor; /* remember curwin->w_cursor */ - ++curwin->w_cursor.lnum; - del_lines(oap->line_count - 2, FALSE); - - if (delete_last_line) - oap->end.lnum = curbuf->b_ml.ml_line_count; + curpos = curwin->w_cursor; // remember curwin->w_cursor + curwin->w_cursor.lnum++; + del_lines(oap->line_count - 2, false); + // delete from start of line until op_end n = (oap->end.col + 1 - !oap->inclusive); - if (oap->inclusive && delete_last_line - && n > (int)STRLEN(ml_get(oap->end.lnum))) { - /* Special case: gH<Del> deletes the last line. */ - del_lines(1L, FALSE); - curwin->w_cursor = curpos; /* restore curwin->w_cursor */ - if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) - curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; - } else { - /* delete from start of line until op_end */ - curwin->w_cursor.col = 0; - (void)del_bytes((long)n, !virtual_op, oap->op_type == OP_DELETE - && !oap->is_VIsual - ); - curwin->w_cursor = curpos; /* restore curwin->w_cursor */ - } - if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { - do_join(2, FALSE, FALSE, FALSE, false); - } + curwin->w_cursor.col = 0; + (void)del_bytes((long)n, !virtual_op, + oap->op_type == OP_DELETE && !oap->is_VIsual); + curwin->w_cursor = curpos; // restore curwin->w_cursor + (void)do_join(2, false, false, false, false); } } @@ -2688,17 +2664,27 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) if (y_type == MLINE) { if (flags & PUT_LINE_SPLIT) { - /* "p" or "P" in Visual mode: split the lines to put the text in - * between. */ - if (u_save_cursor() == FAIL) + // "p" or "P" in Visual mode: split the lines to put the text in + // between. + if (u_save_cursor() == FAIL) { goto end; - ptr = vim_strsave(get_cursor_pos_ptr()); - ml_append(curwin->w_cursor.lnum, ptr, (colnr_T)0, FALSE); + } + char_u *p = get_cursor_pos_ptr(); + if (dir == FORWARD && *p != NUL) { + mb_ptr_adv(p); + } + ptr = vim_strsave(p); + ml_append(curwin->w_cursor.lnum, ptr, (colnr_T)0, false); xfree(ptr); - ptr = vim_strnsave(get_cursor_line_ptr(), curwin->w_cursor.col); - ml_replace(curwin->w_cursor.lnum, ptr, FALSE); - ++nr_lines; + oldp = get_cursor_line_ptr(); + p = oldp + curwin->w_cursor.col; + if (dir == FORWARD && *p != NUL) { + mb_ptr_adv(p); + } + ptr = vim_strnsave(oldp, p - oldp); + ml_replace(curwin->w_cursor.lnum, ptr, false); + nr_lines++; dir = FORWARD; } if (flags & PUT_LINE_FORWARD) { diff --git a/src/nvim/option.c b/src/nvim/option.c index d3a2ce971d..7a98bd005d 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -168,11 +168,12 @@ static int p_ml_nobin; static long p_tw_nobin; static long p_wm_nobin; -/* Saved values for when 'paste' is set */ +// Saved values for when 'paste' is set. +static int p_ai_nopaste; +static int p_et_nopaste; +static long p_sts_nopaste; static long p_tw_nopaste; static long p_wm_nopaste; -static long p_sts_nopaste; -static int p_ai_nopaste; typedef struct vimoption { char *fullname; /* full option name */ @@ -218,20 +219,22 @@ typedef struct vimoption { #define P_RALL 0x6000U /* redraw all windows */ #define P_RCLR 0x7000U /* clear and redraw all */ -#define P_COMMA 0x8000U /* comma separated list */ -#define P_NODUP 0x10000U /* don't allow duplicate strings */ -#define P_FLAGLIST 0x20000U /* list of single-char flags */ - -#define P_SECURE 0x40000U /* cannot change in modeline or secure mode */ -#define P_GETTEXT 0x80000U /* expand default value with _() */ -#define P_NOGLOB 0x100000U /* do not use local value for global vimrc */ -#define P_NFNAME 0x200000U /* only normal file name chars allowed */ -#define P_INSECURE 0x400000U /* option was set from a modeline */ -#define P_PRI_MKRC 0x800000U /* priority for :mkvimrc (setting option has - side effects) */ -#define P_NO_ML 0x1000000U /* not allowed in modeline */ -#define P_CURSWANT 0x2000000U /* update curswant required; not needed when - * there is a redraw flag */ +#define P_COMMA 0x8000U ///< comma separated list +#define P_ONECOMMA 0x18000U ///< P_COMMA and cannot have two consecutive + ///< commas +#define P_NODUP 0x20000U ///< don't allow duplicate strings +#define P_FLAGLIST 0x40000U ///< list of single-char flags + +#define P_SECURE 0x80000U ///< cannot change in modeline or secure mode +#define P_GETTEXT 0x100000U ///< expand default value with _() +#define P_NOGLOB 0x200000U ///< do not use local value for global vimrc +#define P_NFNAME 0x400000U ///< only normal file name chars allowed +#define P_INSECURE 0x800000U ///< option was set from a modeline +#define P_PRI_MKRC 0x1000000U ///< priority for :mkvimrc (setting option + ///< has side effects) +#define P_NO_ML 0x2000000U ///< not allowed in modeline +#define P_CURSWANT 0x4000000U ///< update curswant required; not needed + ///< when there is a redraw flag #define HIGHLIGHT_INIT \ "8:SpecialKey,~:EndOfBuffer,z:TermCursor,Z:TermCursorNC,@:NonText," \ @@ -1674,9 +1677,11 @@ do_set ( if (adding) { i = (int)STRLEN(origval); // Strip a trailing comma, would get 2. - if (comma && i > 1 && origval[i - 1] == ',' + if (comma && i > 1 + && (flags & P_ONECOMMA) == P_ONECOMMA + && origval[i - 1] == ',' && origval[i - 2] != '\\') { - --i; + i--; } memmove(newval + i + comma, newval, STRLEN(newval) + 1); @@ -5499,6 +5504,7 @@ void buf_copy_options(buf_T *buf, int flags) buf->b_p_et = p_et; buf->b_p_fixeol = p_fixeol; buf->b_p_et_nobin = p_et_nobin; + buf->b_p_et_nopaste = p_et_nopaste; buf->b_p_ml = p_ml; buf->b_p_ml_nobin = p_ml_nobin; buf->b_p_inf = p_inf; @@ -6156,6 +6162,7 @@ static void paste_option_changed(void) { static int old_p_paste = FALSE; static int save_sm = 0; + static int save_sta = 0; static int save_ru = 0; static int save_ri = 0; static int save_hkmap = 0; @@ -6172,40 +6179,44 @@ static void paste_option_changed(void) buf->b_p_wm_nopaste = buf->b_p_wm; buf->b_p_sts_nopaste = buf->b_p_sts; buf->b_p_ai_nopaste = buf->b_p_ai; + buf->b_p_et_nopaste = buf->b_p_et; } - /* save global options */ + // save global options save_sm = p_sm; + save_sta = p_sta; save_ru = p_ru; save_ri = p_ri; save_hkmap = p_hkmap; - /* save global values for local buffer options */ + // save global values for local buffer options + p_ai_nopaste = p_ai; + p_et_nopaste = p_et; + p_sts_nopaste = p_sts; p_tw_nopaste = p_tw; p_wm_nopaste = p_wm; - p_sts_nopaste = p_sts; - p_ai_nopaste = p_ai; } - /* - * Always set the option values, also when 'paste' is set when it is - * already on. - */ - /* set options for each buffer */ + // Always set the option values, also when 'paste' is set when it is + // already on. + // set options for each buffer FOR_ALL_BUFFERS(buf) { - buf->b_p_tw = 0; /* textwidth is 0 */ - buf->b_p_wm = 0; /* wrapmargin is 0 */ - buf->b_p_sts = 0; /* softtabstop is 0 */ - buf->b_p_ai = 0; /* no auto-indent */ - } - - /* set global options */ - p_sm = 0; /* no showmatch */ - if (p_ru) - status_redraw_all(); /* redraw to remove the ruler */ - p_ru = 0; /* no ruler */ - p_ri = 0; /* no reverse insert */ - p_hkmap = 0; /* no Hebrew keyboard */ - /* set global values for local buffer options */ + buf->b_p_tw = 0; // textwidth is 0 + buf->b_p_wm = 0; // wrapmargin is 0 + buf->b_p_sts = 0; // softtabstop is 0 + buf->b_p_ai = 0; // no auto-indent + buf->b_p_et = 0; // no expandtab + } + + // set global options + p_sm = 0; // no showmatch + p_sta = 0; // no smarttab + if (p_ru) { + status_redraw_all(); // redraw to remove the ruler + } + p_ru = 0; // no ruler + p_ri = 0; // no reverse insert + p_hkmap = 0; // no Hebrew keyboard + // set global values for local buffer options p_tw = 0; p_wm = 0; p_sts = 0; @@ -6221,20 +6232,24 @@ static void paste_option_changed(void) buf->b_p_wm = buf->b_p_wm_nopaste; buf->b_p_sts = buf->b_p_sts_nopaste; buf->b_p_ai = buf->b_p_ai_nopaste; + buf->b_p_et = buf->b_p_et_nopaste; } /* restore global options */ p_sm = save_sm; - if (p_ru != save_ru) - status_redraw_all(); /* redraw to draw the ruler */ + p_sta = save_sta; + if (p_ru != save_ru) { + status_redraw_all(); // redraw to draw the ruler + } p_ru = save_ru; p_ri = save_ri; p_hkmap = save_hkmap; - /* set global values for local buffer options */ + // set global values for local buffer options + p_ai = p_ai_nopaste; + p_et = p_et_nopaste; + p_sts = p_sts_nopaste; p_tw = p_tw_nopaste; p_wm = p_wm_nopaste; - p_sts = p_sts_nopaste; - p_ai = p_ai_nopaste; } old_p_paste = p_paste; diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 3dd37cb5dc..df77c374ec 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -15,7 +15,7 @@ -- } -- } -- types: bool, number, string --- lists: (nil), comma, flags, flagscomma +-- lists: (nil), comma, onecomma, flags, flagscomma -- scopes: global, buffer, window -- redraw options: statuslines, current_window, current_buffer, all_windows, -- everything, curswant @@ -133,7 +133,7 @@ return { }, { full_name='backspace', abbreviation='bs', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vim=true, varname='p_bs', @@ -149,7 +149,7 @@ return { }, { full_name='backupcopy', abbreviation='bkc', - type='string', list='comma', scope={'global', 'buffer'}, + type='string', list='onecomma', scope={'global', 'buffer'}, deny_duplicates=true, vim=true, varname='p_bkc', @@ -161,7 +161,7 @@ return { }, { full_name='backupdir', abbreviation='bdir', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, secure=true, vi_def=true, @@ -179,7 +179,7 @@ return { }, { full_name='backupskip', abbreviation='bsk', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, vi_def=true, varname='p_bsk', defaults={if_true={vi=""}} @@ -227,7 +227,7 @@ return { }, { full_name='breakindentopt', abbreviation='briopt', - type='string', list='comma', scope={'window'}, + type='string', list='onecomma', scope={'window'}, deny_duplicates=true, vi_def=true, alloced=true, @@ -268,7 +268,7 @@ return { }, { full_name='casemap', abbreviation='cmp', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_cmp', @@ -307,7 +307,7 @@ return { }, { full_name='cinkeys', abbreviation='cink', - type='string', list='comma', scope={'buffer'}, + type='string', list='onecomma', scope={'buffer'}, deny_duplicates=true, vi_def=true, alloced=true, @@ -316,7 +316,7 @@ return { }, { full_name='cinoptions', abbreviation='cino', - type='string', list='comma', scope={'buffer'}, + type='string', list='onecomma', scope={'buffer'}, deny_duplicates=true, vi_def=true, alloced=true, @@ -325,7 +325,7 @@ return { }, { full_name='cinwords', abbreviation='cinw', - type='string', list='comma', scope={'buffer'}, + type='string', list='onecomma', scope={'buffer'}, deny_duplicates=true, vi_def=true, alloced=true, @@ -334,7 +334,7 @@ return { }, { full_name='clipboard', abbreviation='cb', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_cb', @@ -357,7 +357,7 @@ return { }, { full_name='colorcolumn', abbreviation='cc', - type='string', list='comma', scope={'window'}, + type='string', list='onecomma', scope={'window'}, deny_duplicates=true, vi_def=true, redraw={'current_window'}, @@ -375,7 +375,7 @@ return { }, { full_name='comments', abbreviation='com', - type='string', list='comma', scope={'buffer'}, + type='string', list='onecomma', scope={'buffer'}, deny_duplicates=true, vi_def=true, alloced=true, @@ -403,7 +403,7 @@ return { }, { full_name='complete', abbreviation='cpt', - type='string', list='comma', scope={'buffer'}, + type='string', list='onecomma', scope={'buffer'}, deny_duplicates=true, alloced=true, varname='p_cpt', @@ -435,7 +435,7 @@ return { }, { full_name='completeopt', abbreviation='cot', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_cot', @@ -483,7 +483,7 @@ return { }, { full_name='cscopequickfix', abbreviation='csqf', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_csqf', @@ -568,7 +568,7 @@ return { }, { full_name='dictionary', abbreviation='dict', - type='string', list='comma', scope={'global', 'buffer'}, + type='string', list='onecomma', scope={'global', 'buffer'}, deny_duplicates=true, vi_def=true, expand=true, @@ -594,7 +594,7 @@ return { }, { full_name='diffopt', abbreviation='dip', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, alloced=true, @@ -612,7 +612,7 @@ return { }, { full_name='directory', abbreviation='dir', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, secure=true, vi_def=true, @@ -622,7 +622,7 @@ return { }, { full_name='display', abbreviation='dy', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vim=true, redraw={'all_windows'}, @@ -696,7 +696,7 @@ return { }, { full_name='errorformat', abbreviation='efm', - type='string', list='comma', scope={'global', 'buffer'}, + type='string', list='onecomma', scope={'global', 'buffer'}, deny_duplicates=true, vi_def=true, varname='p_efm', @@ -711,7 +711,7 @@ return { }, { full_name='eventignore', abbreviation='ei', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_ei', @@ -745,7 +745,7 @@ return { }, { full_name='fileencodings', abbreviation='fencs', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, vi_def=true, varname='p_fencs', defaults={if_true={vi="ucs-bom,utf-8,default,latin1"}} @@ -762,7 +762,7 @@ return { }, { full_name='fileformats', abbreviation='ffs', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vim=true, varname='p_ffs', @@ -791,7 +791,7 @@ return { }, { full_name='fillchars', abbreviation='fcs', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, redraw={'all_windows'}, @@ -815,7 +815,7 @@ return { }, { full_name='foldclose', abbreviation='fcl', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, redraw={'current_window'}, @@ -871,7 +871,7 @@ return { }, { full_name='foldmarker', abbreviation='fmr', - type='string', list='comma', scope={'window'}, + type='string', list='onecomma', scope={'window'}, deny_duplicates=true, vi_def=true, vim=true, @@ -904,7 +904,7 @@ return { }, { full_name='foldopen', abbreviation='fdo', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, redraw={'curswant'}, @@ -972,7 +972,7 @@ return { }, { full_name='grepformat', abbreviation='gfm', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_gefm', @@ -995,7 +995,7 @@ return { }, { full_name='guicursor', abbreviation='gcr', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_guicursor', @@ -1003,7 +1003,7 @@ return { }, { full_name='guifont', abbreviation='gfn', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, redraw={'everything'}, @@ -1011,14 +1011,14 @@ return { }, { full_name='guifontset', abbreviation='gfs', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, vi_def=true, redraw={'everything'}, enable_if=false, }, { full_name='guifontwide', abbreviation='gfw', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, redraw={'everything'}, @@ -1070,7 +1070,7 @@ return { }, { full_name='helplang', abbreviation='hlg', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, vi_def=true, varname='p_hlg', defaults={if_true={vi=""}} @@ -1084,7 +1084,7 @@ return { }, { full_name='highlight', abbreviation='hl', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, redraw={'everything'}, @@ -1213,7 +1213,7 @@ return { }, { full_name='indentkeys', abbreviation='indk', - type='string', list='comma', scope={'buffer'}, + type='string', list='onecomma', scope={'buffer'}, deny_duplicates=true, vi_def=true, alloced=true, @@ -1297,7 +1297,7 @@ return { }, { full_name='keymodel', abbreviation='km', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_km', @@ -1316,7 +1316,7 @@ return { }, { full_name='langmap', abbreviation='lmap', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, secure=true, vi_def=true, @@ -1385,7 +1385,7 @@ return { }, { full_name='lispwords', abbreviation='lw', - type='string', list='comma', scope={'global', 'buffer'}, + type='string', list='onecomma', scope={'global', 'buffer'}, deny_duplicates=true, vi_def=true, varname='p_lispwords', pv_name='p_lw', @@ -1400,7 +1400,7 @@ return { }, { full_name='listchars', abbreviation='lcs', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vim=true, redraw={'all_windows'}, @@ -1441,7 +1441,7 @@ return { }, { full_name='matchpairs', abbreviation='mps', - type='string', list='comma', scope={'buffer'}, + type='string', list='onecomma', scope={'buffer'}, deny_duplicates=true, vi_def=true, alloced=true, @@ -1581,7 +1581,7 @@ return { }, { full_name='mouseshape', abbreviation='mouses', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, enable_if=false, @@ -1595,7 +1595,7 @@ return { }, { full_name='nrformats', abbreviation='nf', - type='string', list='comma', scope={'buffer'}, + type='string', list='onecomma', scope={'buffer'}, deny_duplicates=true, alloced=true, varname='p_nf', @@ -1762,7 +1762,7 @@ return { }, { full_name='printoptions', abbreviation='popt', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_popt', @@ -1877,7 +1877,7 @@ return { }, { full_name='runtimepath', abbreviation='rtp', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, secure=true, vi_def=true, @@ -1919,7 +1919,7 @@ return { }, { full_name='scrollopt', abbreviation='sbo', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_sbo', @@ -1949,7 +1949,7 @@ return { }, { full_name='selectmode', abbreviation='slm', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_slm', @@ -1957,7 +1957,7 @@ return { }, { full_name='sessionoptions', abbreviation='ssop', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vim=true, varname='p_ssop', @@ -1968,7 +1968,7 @@ return { }, { full_name='shada', abbreviation='sd', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, secure=true, varname='p_shada', @@ -2192,7 +2192,7 @@ return { }, { full_name='spellfile', abbreviation='spf', - type='string', list='comma', scope={'buffer'}, + type='string', list='onecomma', scope={'buffer'}, secure=true, vi_def=true, alloced=true, @@ -2202,7 +2202,7 @@ return { }, { full_name='spelllang', abbreviation='spl', - type='string', list='comma', scope={'buffer'}, + type='string', list='onecomma', scope={'buffer'}, vi_def=true, alloced=true, expand=true, @@ -2212,7 +2212,7 @@ return { }, { full_name='spellsuggest', abbreviation='sps', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, secure=true, vi_def=true, expand=true, @@ -2252,7 +2252,7 @@ return { }, { full_name='suffixes', abbreviation='su', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_su', @@ -2260,7 +2260,7 @@ return { }, { full_name='suffixesadd', abbreviation='sua', - type='string', list='comma', scope={'buffer'}, + type='string', list='onecomma', scope={'buffer'}, deny_duplicates=true, vi_def=true, alloced=true, @@ -2277,7 +2277,7 @@ return { }, { full_name='switchbuf', abbreviation='swb', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_swb', @@ -2347,7 +2347,7 @@ return { }, { full_name='tags', abbreviation='tag', - type='string', list='comma', scope={'global', 'buffer'}, + type='string', list='onecomma', scope={'global', 'buffer'}, deny_duplicates=true, vi_def=true, expand=true, @@ -2393,7 +2393,7 @@ return { }, { full_name='thesaurus', abbreviation='tsr', - type='string', list='comma', scope={'global', 'buffer'}, + type='string', list='onecomma', scope={'global', 'buffer'}, deny_duplicates=true, vi_def=true, expand=true, @@ -2478,7 +2478,7 @@ return { }, { full_name='undodir', abbreviation='udir', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, secure=true, vi_def=true, @@ -2549,7 +2549,7 @@ return { }, { full_name='viewoptions', abbreviation='vop', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_vop', @@ -2557,7 +2557,7 @@ return { }, { full_name='viminfo', abbreviation='vi', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, secure=true, varname='p_shada', @@ -2565,7 +2565,7 @@ return { }, { full_name='virtualedit', abbreviation='ve', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, vim=true, @@ -2610,7 +2610,7 @@ return { }, { full_name='wildignore', abbreviation='wig', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vi_def=true, varname='p_wig', @@ -2632,7 +2632,7 @@ return { }, { full_name='wildmode', abbreviation='wim', - type='string', list='comma', scope={'global'}, + type='string', list='onecomma', scope={'global'}, deny_duplicates=true, vim=true, varname='p_wim', diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c index 4020fa6e28..dd41535110 100644 --- a/src/nvim/regexp_nfa.c +++ b/src/nvim/regexp_nfa.c @@ -4048,6 +4048,7 @@ skip_add: sub->list.multi[subidx].start_col = (colnr_T)(reginput - regline + off); } + sub->list.multi[subidx].end_lnum = -1; } else { if (subidx < sub->in_use) { save_ptr = sub->list.line[subidx].start; diff --git a/src/nvim/screen.c b/src/nvim/screen.c index e036c49be4..7495647ff2 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -2199,11 +2199,13 @@ win_line ( int syntax_seqnr = 0; int prev_syntax_id = 0; int conceal_attr = hl_attr(HLF_CONCEAL); - int is_concealing = FALSE; - int boguscols = 0; /* nonexistent columns added to force - wrapping */ - int vcol_off = 0; /* offset for concealed characters */ - int did_wcol = FALSE; + int is_concealing = false; + int boguscols = 0; ///< nonexistent columns added to + ///< force wrapping + int vcol_off = 0; ///< offset for concealed characters + int did_wcol = false; + int match_conc = false; ///< cchar for match functions + int has_match_conc = false; ///< match wants to conceal int old_boguscols = 0; # define VCOL_HLC (vcol - vcol_off) # define FIX_FOR_BOGUSCOLS \ @@ -2633,11 +2635,10 @@ win_line ( extra_check = true; } - /* - * Repeat for the whole displayed line. - */ + // Repeat for the whole displayed line. for (;; ) { - /* Skip this quickly when working on the text. */ + has_match_conc = false; + // Skip this quickly when working on the text. if (draw_state != WL_LINE) { if (draw_state == WL_CMDLINE - 1 && n_extra == 0) { draw_state = WL_CMDLINE; @@ -2884,8 +2885,16 @@ win_line ( shl->endcol = tmp_col; } shl->attr_cur = shl->attr; + if (cur != NULL && syn_name2id((char_u *)"Conceal") + == cur->hlg_id) { + has_match_conc = true; + match_conc = cur->conceal_char; + } else { + has_match_conc = match_conc = false; + } } else if (v == (long)shl->endcol) { shl->attr_cur = 0; + prev_syntax_id = 0; next_search_hl(wp, shl, lnum, (colnr_T)v, cur); pos_inprogress = !(cur == NULL || cur->pos.cur == 0); @@ -3602,24 +3611,28 @@ win_line ( } } - if ( wp->w_p_cole > 0 - && (wp != curwin || lnum != wp->w_cursor.lnum || - conceal_cursor_line(wp)) - && (syntax_flags & HL_CONCEAL) != 0 - && !(lnum_in_visual_area - && vim_strchr(wp->w_p_cocu, 'v') == NULL)) { + if (wp->w_p_cole > 0 + && (wp != curwin || lnum != wp->w_cursor.lnum || + conceal_cursor_line(wp)) + && ((syntax_flags & HL_CONCEAL) != 0 || has_match_conc) + && !(lnum_in_visual_area + && vim_strchr(wp->w_p_cocu, 'v') == NULL)) { char_attr = conceal_attr; if (prev_syntax_id != syntax_seqnr - && (syn_get_sub_char() != NUL || wp->w_p_cole == 1) + && (syn_get_sub_char() != NUL || match_conc + || wp->w_p_cole == 1) && wp->w_p_cole != 3) { - /* First time at this concealed item: display one - * character. */ - if (syn_get_sub_char() != NUL) + // First time at this concealed item: display one + // character. + if (match_conc) { + c = match_conc; + } else if (syn_get_sub_char() != NUL) { c = syn_get_sub_char(); - else if (lcs_conceal != NUL) + } else if (lcs_conceal != NUL) { c = lcs_conceal; - else + } else { c = ' '; + } prev_syntax_id = syntax_seqnr; diff --git a/src/nvim/search.c b/src/nvim/search.c index 2dd0201259..827473e55d 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -497,6 +497,7 @@ int searchit( pos_T start_pos; int at_first_line; int extra_col; + int start_char_len; int match_ok; long nmatched; int submatch = 0; @@ -519,16 +520,21 @@ int searchit( // When not accepting a match at the start position set "extra_col" to a // non-zero value. Don't do that when starting at MAXCOL, since MAXCOL + 1 // is zero. - if ((options & SEARCH_START) || pos->col == MAXCOL) { - extra_col = 0; - } else if (dir != BACKWARD && has_mbyte - && pos->lnum >= 1 && pos->lnum <= buf->b_ml.ml_line_count - && pos->col < MAXCOL - 2) { + if (pos->col == MAXCOL) { + start_char_len = 0; + } else if (has_mbyte + && pos->lnum >= 1 && pos->lnum <= buf->b_ml.ml_line_count + && pos->col < MAXCOL - 2) { // Watch out for the "col" being MAXCOL - 2, used in a closed fold. - ptr = ml_get_buf(buf, pos->lnum, FALSE) + pos->col; - extra_col = *ptr == NUL ? 1 : (*mb_ptr2len)(ptr); + ptr = ml_get_buf(buf, pos->lnum, false) + pos->col; + start_char_len = *ptr == NUL ? 1 : (*mb_ptr2len)(ptr); } else { - extra_col = 1; + start_char_len = 1; + } + if (dir == FORWARD) { + extra_col = (options & SEARCH_START) ? 0 : start_char_len; + } else { + extra_col = (options & SEARCH_START) ? start_char_len : 0; } start_pos = *pos; /* remember start pos for detecting no match */ @@ -679,16 +685,14 @@ int searchit( || (lnum + regmatch.endpos[0].lnum == start_pos.lnum && (int)regmatch.endpos[0].col - 1 - + extra_col - <= (int)start_pos.col)) + < (int)start_pos.col + extra_col)) : (lnum + regmatch.startpos[0].lnum < start_pos.lnum || (lnum + regmatch.startpos[0].lnum == start_pos.lnum && (int)regmatch.startpos[0].col - + extra_col - <= (int)start_pos.col)))) { - match_ok = TRUE; + < (int)start_pos.col + extra_col)))) { + match_ok = true; matchpos = regmatch.startpos[0]; endpos = regmatch.endpos[0]; submatch = first_submatch(®match); diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 821411ec7b..b7d8a19de9 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -41,6 +41,8 @@ #include "nvim/os/os.h" #include "nvim/os/time.h" +static bool did_syntax_onoff = false; + // Structure that stores information about a highlight group. // The ID of a highlight group is also called group ID. It is the index in // the highlight_ga array PLUS ONE. @@ -3286,17 +3288,28 @@ static void syn_cmd_off(exarg_T *eap, int syncing) } static void syn_cmd_onoff(exarg_T *eap, char *name) + FUNC_ATTR_NONNULL_ALL { - char buf[100]; - + did_syntax_onoff = true; eap->nextcmd = check_nextcmd(eap->arg); if (!eap->skip) { - strcpy(buf, "so "); + char buf[100]; + strncpy(buf, "so ", 3); vim_snprintf(buf + 3, sizeof(buf) - 3, SYNTAX_FNAME, name); do_cmdline_cmd(buf); } } +void syn_maybe_on(void) +{ + if (!did_syntax_onoff) { + exarg_T ea; + ea.arg = (char_u *)""; + ea.skip = false; + syn_cmd_onoff(&ea, "syntax"); + } +} + /* * Handle ":syntax [list]" command: list current syntax words. */ @@ -5406,8 +5419,10 @@ void ex_ownsyntax(exarg_T *eap) if (curwin->w_s == &curwin->w_buffer->b_s) { curwin->w_s = xmalloc(sizeof(synblock_T)); memset(curwin->w_s, 0, sizeof(synblock_T)); - // TODO: Keep the spell checking as it was. - curwin->w_p_spell = FALSE; /* No spell checking */ + hash_init(&curwin->w_s->b_keywtab); + hash_init(&curwin->w_s->b_keywtab_ic); + // TODO: Keep the spell checking as it was. NOLINT(readability/todo) + curwin->w_p_spell = false; // No spell checking clear_string_option(&curwin->w_s->b_p_spc); clear_string_option(&curwin->w_s->b_p_spf); clear_string_option(&curwin->w_s->b_p_spl); diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile index d1a7abfbf7..f077414e18 100644 --- a/src/nvim/testdir/Makefile +++ b/src/nvim/testdir/Makefile @@ -27,8 +27,8 @@ SCRIPTS := \ test_breakindent.out \ test_charsearch.out \ test_close_count.out \ - test_command_count.out \ test_marks.out \ + test_match_conceal.out \ NEW_TESTS = diff --git a/src/nvim/testdir/test_command_count.in b/src/nvim/testdir/test_command_count.in deleted file mode 100644 index 170c810923..0000000000 --- a/src/nvim/testdir/test_command_count.in +++ /dev/null @@ -1,158 +0,0 @@ -Test for user command counts vim: set ft=vim : - -STARTTEST -:so tiny.vim -:lang C -:let g:lines = [] -:com -range=% RangeLines :call add(g:lines, 'RangeLines '.<line1>.' '.<line2>) -:com -range -addr=arguments RangeArguments :call add(g:lines, 'RangeArguments '.<line1>.' '.<line2>) -:com -range=% -addr=arguments RangeArgumentsAll :call add(g:lines, 'RangeArgumentsAll '.<line1>.' '.<line2>) -:com -range -addr=loaded_buffers RangeLoadedBuffers :call add(g:lines, 'RangeLoadedBuffers '.<line1>.' '.<line2>) -:com -range=% -addr=loaded_buffers RangeLoadedBuffersAll :call add(g:lines, 'RangeLoadedBuffersAll '.<line1>.' '.<line2>) -:com -range -addr=buffers RangeBuffers :call add(g:lines, 'RangeBuffers '.<line1>.' '.<line2>) -:com -range=% -addr=buffers RangeBuffersAll :call add(g:lines, 'RangeBuffersAll '.<line1>.' '.<line2>) -:com -range -addr=windows RangeWindows :call add(g:lines, 'RangeWindows '.<line1>.' '.<line2>) -:com -range=% -addr=windows RangeWindowsAll :call add(g:lines, 'RangeWindowsAll '.<line1>.' '.<line2>) -:com -range -addr=tabs RangeTabs :call add(g:lines, 'RangeTabs '.<line1>.' '.<line2>) -:com -range=% -addr=tabs RangeTabsAll :call add(g:lines, 'RangeTabsAll '.<line1>.' '.<line2>) -:set hidden -:arga a b c d -:argdo echo "loading buffers" -:argu 3 -:.-,$-RangeArguments -:%RangeArguments -:RangeArgumentsAll -:N -:.RangeArguments -:split|split|split|split -:3wincmd w -:.,$RangeWindows -:%RangeWindows -:RangeWindowsAll -:only -:blast|bd -:.,$RangeLoadedBuffers -:%RangeLoadedBuffers -:RangeLoadedBuffersAll -:.,$RangeBuffers -:%RangeBuffers -:RangeBuffersAll -:tabe|tabe|tabe|tabe -:normal 2gt -:.,$RangeTabs -:%RangeTabs -:RangeTabsAll -:1tabonly -:s/\n/\r\r\r\r\r/ -:2ma< -:$-ma> -:'<,'>RangeLines -:com -range=% -buffer LocalRangeLines :call add(g:lines, 'LocalRangeLines '.<line1>.' '.<line2>) -:'<,'>LocalRangeLines -:b1 -ENDTEST - -STARTTEST -:call add(g:lines, '') -:%argd -:arga a b c d -:let v:errmsg = '' -:5argu -:call add(g:lines, '5argu ' . v:errmsg) -:$argu -:call add(g:lines, '4argu ' . expand('%:t')) -:let v:errmsg = '' -:1argu -:call add(g:lines, '1argu ' . expand('%:t')) -:let v:errmsg = '' -:100b -:call add(g:lines, '100b ' . v:errmsg) -:split|split|split|split -:let v:errmsg = '' -:0close -:call add(g:lines, '0close ' . v:errmsg) -:$wincmd w -:$close -:call add(g:lines, '$close ' . winnr()) -:let v:errmsg = '' -:$+close -:call add(g:lines, '$+close ' . v:errmsg) -:$tabe -:call add(g:lines, '$tabe ' . tabpagenr()) -:let v:errmsg = '' -:$+tabe -:call add(g:lines, '$+tabe ' . v:errmsg) -:only! -:e x -:0tabm -:normal 1gt -:call add(g:lines, '0tabm ' . expand('%:t')) -:tabonly! -:only! -:e! test.out -:call append(0, g:lines) -:unlet g:lines -:w|bd -:b1 -ENDTEST - -STARTTEST -:let g:lines = [] -:func BufStatus() -: call add(g:lines, 'aaa: ' . buflisted(g:buf_aaa) . ' bbb: ' . buflisted(g:buf_bbb) . ' ccc: ' . buflisted(g:buf_ccc)) -:endfunc -:se nohidden -:e aaa -:let buf_aaa = bufnr('%') -:e bbb -:let buf_bbb = bufnr('%') -:e ccc -:let buf_ccc = bufnr('%') -:b1 -:call BufStatus() -:exe buf_bbb . "," . buf_ccc . "bdelete" -:call BufStatus() -:exe buf_aaa . "bdelete" -:call BufStatus() -:e! test.out -:call append('$', g:lines) -:unlet g:lines -:delfunc BufStatus -:w|bd -:b1 -ENDTEST - -STARTTEST -:se hidden -:only! -:let g:lines = [] -:%argd -:arga a b c d e f -:3argu -:let args = '' -:.,$-argdo let args .= ' '.expand('%') -:call add(g:lines, 'argdo:' . args) -:split|split|split|split -:2wincmd w -:let windows = '' -:.,$-windo let windows .= ' '.winnr() -:call add(g:lines, 'windo:'. windows) -:b2 -:let buffers = '' -:.,$-bufdo let buffers .= ' '.bufnr('%') -:call add(g:lines, 'bufdo:' . buffers) -:3bd -:let buffers = '' -:3,7bufdo let buffers .= ' '.bufnr('%') -:call add(g:lines, 'bufdo:' . buffers) -:tabe|tabe|tabe|tabe -:normal! 2gt -:let tabpages = '' -:.,$-tabdo let tabpages .= ' '.tabpagenr() -:call add(g:lines, 'tabdo:' . tabpages) -:e! test.out -:call append('$', g:lines) -:w|qa! -ENDTEST - - diff --git a/src/nvim/testdir/test_command_count.ok b/src/nvim/testdir/test_command_count.ok deleted file mode 100644 index e74155ec1b..0000000000 --- a/src/nvim/testdir/test_command_count.ok +++ /dev/null @@ -1,38 +0,0 @@ -RangeArguments 2 4 -RangeArguments 1 5 -RangeArgumentsAll 1 5 -RangeArguments 2 2 -RangeWindows 3 5 -RangeWindows 1 5 -RangeWindowsAll 1 5 -RangeLoadedBuffers 2 4 -RangeLoadedBuffers 1 4 -RangeLoadedBuffersAll 1 4 -RangeBuffers 2 5 -RangeBuffers 1 5 -RangeBuffersAll 1 5 -RangeTabs 2 5 -RangeTabs 1 5 -RangeTabsAll 1 5 -RangeLines 2 5 -LocalRangeLines 2 5 - -5argu E16: Invalid range -4argu d -1argu a -100b E16: Invalid range -0close -$close 3 -$+close E16: Invalid range -$tabe 2 -$+tabe E16: Invalid range -0tabm x - -aaa: 1 bbb: 1 ccc: 1 -aaa: 1 bbb: 0 ccc: 0 -aaa: 0 bbb: 0 ccc: 0 -argdo: c d e -windo: 2 3 4 -bufdo: 2 3 4 5 6 7 8 9 10 15 -bufdo: 4 5 6 7 -tabdo: 2 3 4 diff --git a/src/nvim/version.c b/src/nvim/version.c index 9a9d6dfd38..452f823539 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -357,9 +357,9 @@ static int included_patches[] = { // 934 NA // 933, // 932, - // 931, + // 931 NA // 930 NA - // 929, + 929, // 928 NA // 927 NA // 926, @@ -373,7 +373,7 @@ static int included_patches[] = { // 918 NA // 917 NA 916, - // 915, + 915, // 914, // 913 NA // 912, @@ -391,7 +391,7 @@ static int included_patches[] = { // 900 NA // 899 NA 898, - // 897, + // 897 NA // 896, // 895, // 894 NA @@ -401,7 +401,7 @@ static int included_patches[] = { // 890 NA // 889, // 888, - // 887, + 887, // 886 NA // 885, // 884 NA @@ -415,20 +415,20 @@ static int included_patches[] = { // 876 NA // 875 NA // 874 NA - // 873, + // 873 NA // 872 NA // 871, // 870, // 869 NA - // 868, + 868, // 867 NA - // 866, - // 865, + // 866 NA + // 865 NA // 864 NA // 863 NA // 862 NA // 861 NA - // 860, + // 860 NA // 859, 858, // 857, @@ -449,8 +449,8 @@ static int included_patches[] = { // 842 NA // 841 NA // 840 NA - // 839, - // 838, + // 839 NA + // 838 NA // 837 NA 836, 835, @@ -460,14 +460,14 @@ static int included_patches[] = { // 831, // 830, // 829 NA - // 828, - // 827, + 828, + // 827 NA 826, 825, // 824 NA 823, // 822, - // 821, + // 821 NA 820, // 819, // 818, @@ -476,7 +476,7 @@ static int included_patches[] = { 815, 814, 813, - // 812, + // 812 NA 811, 810, 809, @@ -484,7 +484,7 @@ static int included_patches[] = { 807, 806, 805, - // 804, + // 804 NA 803, 802, 801, @@ -496,7 +496,7 @@ static int included_patches[] = { 795, // 794 NA 793, - // 792, + 792, 791, 790, 789, @@ -517,11 +517,11 @@ static int included_patches[] = { 774, 773, // 772 NA - // 771, + 771, // 770 NA 769, 768, - // 767, + // 767 NA // 766 NA 765, 764, @@ -536,16 +536,16 @@ static int included_patches[] = { 755, 754, 753, - // 752, + // 752 NA // 751 NA // 750 NA - // 749, + 749, 748, 747, 746, 745, // 744 NA - // 743, + 743, 742, 741, 740, @@ -554,7 +554,7 @@ static int included_patches[] = { 737, 736, // 735 NA - // 734, + 734, // 733, 732, // 731 NA @@ -563,7 +563,7 @@ static int included_patches[] = { // 728 NA // 727 NA // 726 NA - // 725, + // 725 NA // 724 NA 723, 722, @@ -604,7 +604,7 @@ static int included_patches[] = { // 687 NA 686, 685, - // 684, + // 684 NA // 683 NA 682, // 681 NA diff --git a/src/nvim/window.c b/src/nvim/window.c index e84d8df36b..36cb48f3a1 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -5342,14 +5342,14 @@ void restore_buffer(buf_T *save_curbuf) } -/* - * Add match to the match list of window 'wp'. The pattern 'pat' will be - * highlighted with the group 'grp' with priority 'prio'. - * Optionally, a desired ID 'id' can be specified (greater than or equal to 1). - * If no particular ID is desired, -1 must be specified for 'id'. - * Return ID of added match, -1 on failure. - */ -int match_add(win_T *wp, char_u *grp, char_u *pat, int prio, int id, list_T *pos_list) +// Add match to the match list of window 'wp'. The pattern 'pat' will be +// highlighted with the group 'grp' with priority 'prio'. +// Optionally, a desired ID 'id' can be specified (greater than or equal to 1). +// If no particular ID is desired, -1 must be specified for 'id'. +// Return ID of added match, -1 on failure. +int match_add(win_T *wp, char_u *grp, char_u *pat, + int prio, int id, list_T *pos_list, + char_u *conceal_char) { matchitem_T *cur; matchitem_T *prev; @@ -5405,6 +5405,10 @@ int match_add(win_T *wp, char_u *grp, char_u *pat, int prio, int id, list_T *pos m->match.regprog = regprog; m->match.rmm_ic = FALSE; m->match.rmm_maxcol = 0; + m->conceal_char = 0; + if (conceal_char != NULL) { + m->conceal_char = (*mb_ptr2char)(conceal_char); + } // Set up position matches if (pos_list != NULL) diff --git a/test/functional/legacy/094_visual_mode_operators_spec.lua b/test/functional/legacy/094_visual_mode_operators_spec.lua index c4aebe4ecc..4dce39b8d2 100644 --- a/test/functional/legacy/094_visual_mode_operators_spec.lua +++ b/test/functional/legacy/094_visual_mode_operators_spec.lua @@ -24,6 +24,27 @@ local function source_user_functions() ]]) end +local function put_abc() + source([[ + $put ='a' + $put ='b' + $put ='c']]) +end + +local function put_aaabbbccc() + source([[ + $put ='aaa' + $put ='bbb' + $put ='ccc']]) +end + +local function define_select_mode_maps() + source([[ + snoremap <lt>End> <End> + snoremap <lt>Down> <Down> + snoremap <lt>Del> <Del>]]) +end + describe('Visual mode and operator', function() before_each(function() clear() @@ -150,4 +171,228 @@ describe('Visual mode and operator', function() ok ok]]) end) + + describe('characterwise visual mode:', function() + it('replace last line', function() + source([[ + $put ='a' + let @" = 'x']]) + feed('v$p') + + expect([[ + + x]]) + end) + + it('delete middle line', function() + put_abc() + feed('kkv$d') + + expect([[ + + b + c]]) + end) + + it('delete middle two line', function() + put_abc() + feed('kkvj$d') + + expect([[ + + c]]) + end) + + it('delete last line', function() + put_abc() + feed('v$d') + + expect([[ + + a + b + ]]) + end) + + it('delete last two line', function() + put_abc() + feed('kvj$d') + + expect([[ + + a + ]]) + end) + end) + + describe('characterwise select mode:', function() + before_each(function() + define_select_mode_maps() + end) + + it('delete middle line', function() + put_abc() + feed('kkgh<End><Del>') + + expect([[ + + b + c]]) + end) + + it('delete middle two line', function() + put_abc() + feed('kkgh<Down><End><Del>') + + expect([[ + + c]]) + end) + + it('delete last line', function() + put_abc() + feed('gh<End><Del>') + + expect([[ + + a + b + ]]) + end) + + it('delete last two line', function() + put_abc() + feed('kgh<Down><End><Del>') + + expect([[ + + a + ]]) + end) + end) + + describe('linewise select mode:', function() + before_each(function() + define_select_mode_maps() + end) + + it('delete middle line', function() + put_abc() + feed(' kkgH<Del> ') + + expect([[ + + b + c]]) + end) + + it('delete middle two line', function() + put_abc() + feed('kkgH<Down><Del>') + + expect([[ + + c]]) + end) + + it('delete last line', function() + put_abc() + feed('gH<Del>') + + expect([[ + + a + b]]) + end) + + it('delete last two line', function() + put_abc() + feed('kgH<Down><Del>') + + expect([[ + + a]]) + end) + end) + + describe('v_p:', function() + it('replace last character with line register at middle line', function() + put_aaabbbccc() + execute('-2yank') + feed('k$vp') + + expect([[ + + aaa + bb + aaa + + ccc]]) + end) + + it('replace last character with line register at middle line selecting newline', function() + put_aaabbbccc() + execute('-2yank') + feed('k$v$p') + + expect([[ + + aaa + bb + aaa + ccc]]) + end) + + it('replace last character with line register at last line', function() + put_aaabbbccc() + execute('-2yank') + feed('$vp') + + expect([[ + + aaa + bbb + cc + aaa + ]]) + end) + + it('replace last character with line register at last line selecting newline', function() + put_aaabbbccc() + execute('-2yank') + feed('$v$p') + + expect([[ + + aaa + bbb + cc + aaa + ]]) + end) + end) + + it('gv in exclusive select mode after operation', function() + source([[ + $put ='zzz ' + $put ='äà ' + set selection=exclusive]]) + feed('kv3lyjv3lpgvcxxx<Esc>') + + expect([[ + + zzz + xxx ]]) + end) + + it('gv in exclusive select mode without operation', function() + source([[ + $put ='zzz ' + set selection=exclusive]]) + feed('0v3l<Esc>gvcxxx<Esc>') + + expect([[ + + xxx ]]) + end) end) diff --git a/test/functional/legacy/command_count_spec.lua b/test/functional/legacy/command_count_spec.lua new file mode 100644 index 0000000000..d9b4f09263 --- /dev/null +++ b/test/functional/legacy/command_count_spec.lua @@ -0,0 +1,243 @@ +-- Test for user command counts + +local helpers = require('test.functional.helpers') +local clear, source, expect = helpers.clear, helpers.source, helpers.expect +local execute, spawn = helpers.execute, helpers.spawn +local nvim_prog = helpers.nvim_prog + +describe('command_count', function() + setup(clear) + teardown(function() + os.remove('test.out') + end) + + it('is working', function() + -- It is relevant for the test to load a file initially. If this is + -- emulated with :arg the buffer count is wrong as nvim creates an empty + -- buffer if it was started without a filename. + local nvim2 = spawn({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--embed', + 'test_command_count.in'}) + helpers.set_session(nvim2) + + source([[ + lang C + let g:lines = [] + com -range=% RangeLines + \ :call add(g:lines, 'RangeLines '.<line1>.' '.<line2>) + com -range -addr=arguments RangeArguments + \ :call add(g:lines, 'RangeArguments '.<line1>.' '.<line2>) + com -range=% -addr=arguments RangeArgumentsAll + \ :call add(g:lines, 'RangeArgumentsAll '.<line1>.' '.<line2>) + com -range -addr=loaded_buffers RangeLoadedBuffers + \ :call add(g:lines, 'RangeLoadedBuffers '.<line1>.' '.<line2>) + com -range=% -addr=loaded_buffers RangeLoadedBuffersAll + \ :call add(g:lines, 'RangeLoadedBuffersAll '.<line1>.' '.<line2>) + com -range -addr=buffers RangeBuffers + \ :call add(g:lines, 'RangeBuffers '.<line1>.' '.<line2>) + com -range=% -addr=buffers RangeBuffersAll + \ :call add(g:lines, 'RangeBuffersAll '.<line1>.' '.<line2>) + com -range -addr=windows RangeWindows + \ :call add(g:lines, 'RangeWindows '.<line1>.' '.<line2>) + com -range=% -addr=windows RangeWindowsAll + \ :call add(g:lines, 'RangeWindowsAll '.<line1>.' '.<line2>) + com -range -addr=tabs RangeTabs + \ :call add(g:lines, 'RangeTabs '.<line1>.' '.<line2>) + com -range=% -addr=tabs RangeTabsAll + \ :call add(g:lines, 'RangeTabsAll '.<line1>.' '.<line2>) + set hidden + arga a b c d + argdo echo "loading buffers" + argu 3 + .-,$-RangeArguments + %RangeArguments + RangeArgumentsAll + N + .RangeArguments + split + split + split + split + 3wincmd w + .,$RangeWindows + %RangeWindows + RangeWindowsAll + only + blast + bd + .,$RangeLoadedBuffers + %RangeLoadedBuffers + RangeLoadedBuffersAll + .,$RangeBuffers + %RangeBuffers + RangeBuffersAll + tabe + tabe + tabe + tabe + normal 2gt + .,$RangeTabs + %RangeTabs + RangeTabsAll + 1tabonly + s/\n/\r\r\r\r\r/ + 2ma< + $-ma> + '<,'>RangeLines + com -range=% -buffer LocalRangeLines + \ :call add(g:lines, 'LocalRangeLines '.<line1>.' '.<line2>) + '<,'>LocalRangeLines + b1 + call add(g:lines, '') + %argd + arga a b c d + ]]) + -- This can not be in the source() call as it will produce errors. + execute([[let v:errmsg = '']]) + execute('5argu') + execute([[call add(g:lines, '5argu ' . v:errmsg)]]) + execute('$argu') + execute([[call add(g:lines, '4argu ' . expand('%:t'))]]) + execute([[let v:errmsg = '']]) + execute('1argu') + execute([[call add(g:lines, '1argu ' . expand('%:t'))]]) + execute([[let v:errmsg = '']]) + execute('100b') + execute([[call add(g:lines, '100b ' . v:errmsg)]]) + execute('split') + execute('split') + execute('split') + execute('split') + execute([[let v:errmsg = '']]) + execute('0close') + execute([[call add(g:lines, '0close ' . v:errmsg)]]) + execute('$wincmd w') + execute('$close') + execute([[call add(g:lines, '$close ' . winnr())]]) + execute([[let v:errmsg = '']]) + execute('$+close') + execute([[call add(g:lines, '$+close ' . v:errmsg)]]) + execute('$tabe') + execute([[call add(g:lines, '$tabe ' . tabpagenr())]]) + execute([[let v:errmsg = '']]) + execute('$+tabe') + execute([[call add(g:lines, '$+tabe ' . v:errmsg)]]) + source([[ + only! + e x + 0tabm + normal 1gt + call add(g:lines, '0tabm ' . expand('%:t')) + tabonly! + only! + e! test.out + call append(0, g:lines) + unlet g:lines + w + bd + b1 + let g:lines = [] + func BufStatus() + call add(g:lines, + \ 'aaa: ' . buflisted(g:buf_aaa) . + \ ' bbb: ' . buflisted(g:buf_bbb) . + \ ' ccc: ' . buflisted(g:buf_ccc)) + endfunc + se nohidden + e aaa + let buf_aaa = bufnr('%') + e bbb + let buf_bbb = bufnr('%') + e ccc + let buf_ccc = bufnr('%') + b1 + call BufStatus() + exe buf_bbb . "," . buf_ccc . "bdelete" + call BufStatus() + exe buf_aaa . "bdelete" + call BufStatus() + e! test.out + call append('$', g:lines) + unlet g:lines + delfunc BufStatus + w + bd + b1 + se hidden + only! + let g:lines = [] + %argd + arga a b c d e f + 3argu + let args = '' + .,$-argdo let args .= ' '.expand('%') + call add(g:lines, 'argdo:' . args) + split + split + split + split + 2wincmd w + let windows = '' + .,$-windo let windows .= ' '.winnr() + call add(g:lines, 'windo:'. windows) + b2 + let buffers = '' + .,$-bufdo let buffers .= ' '.bufnr('%') + call add(g:lines, 'bufdo:' . buffers) + 3bd + let buffers = '' + 3,7bufdo let buffers .= ' '.bufnr('%') + call add(g:lines, 'bufdo:' . buffers) + tabe + tabe + tabe + tabe + normal! 2gt + let tabpages = '' + .,$-tabdo let tabpages .= ' '.tabpagenr() + call add(g:lines, 'tabdo:' . tabpages) + e! test.out + call append('$', g:lines) + ]]) + + -- Assert buffer contents. + expect([[ + RangeArguments 2 4 + RangeArguments 1 5 + RangeArgumentsAll 1 5 + RangeArguments 2 2 + RangeWindows 3 5 + RangeWindows 1 5 + RangeWindowsAll 1 5 + RangeLoadedBuffers 2 4 + RangeLoadedBuffers 1 4 + RangeLoadedBuffersAll 1 4 + RangeBuffers 2 5 + RangeBuffers 1 5 + RangeBuffersAll 1 5 + RangeTabs 2 5 + RangeTabs 1 5 + RangeTabsAll 1 5 + RangeLines 2 5 + LocalRangeLines 2 5 + + 5argu E16: Invalid range + 4argu d + 1argu a + 100b E16: Invalid range + 0close + $close 3 + $+close E16: Invalid range + $tabe 2 + $+tabe E16: Invalid range + 0tabm x + + aaa: 1 bbb: 1 ccc: 1 + aaa: 1 bbb: 0 ccc: 0 + aaa: 0 bbb: 0 ccc: 0 + argdo: c d e + windo: 2 3 4 + bufdo: 2 3 4 5 6 7 8 9 10 15 + bufdo: 4 5 6 7 + tabdo: 2 3 4]]) + end) +end) diff --git a/test/functional/legacy/match_conceal_spec.lua b/test/functional/legacy/match_conceal_spec.lua new file mode 100644 index 0000000000..0ffa3cae7a --- /dev/null +++ b/test/functional/legacy/match_conceal_spec.lua @@ -0,0 +1,228 @@ +-- Test for matchadd() and conceal feature + +local helpers = require('test.functional.helpers') +local clear = helpers.clear +local expect = helpers.expect +local source = helpers.source + +describe('match_conceal', function() + before_each(function() + clear() + + source([[ + set wildchar=^E + 10new + vsp + vert resize 20 + put =\"\#\ This\ is\ a\ Test\" + norm! mazt + + fu! ScreenChar(width, lines) + let c='' + for j in range(1,a:lines) + for i in range(1,a:width) + let c.=nr2char(screenchar(j, i)) + endfor + let c.="\n" + endfor + return c + endfu + + fu! ScreenAttr(line, pos, eval) + let g:attr=[] + for col in a:pos + call add(g:attr, screenattr(a:line,col)) + endfor + " In case all values are zero, probably the terminal + " isn't set correctly, so catch that case + let null = (eval(join(g:attr, '+')) == 0) + let str=substitute(a:eval, '\d\+', 'g:attr[&]', 'g') + if null || eval(str) + let g:attr_test="OK: ". str + else + let g:attr_test="FAILED: ".str + let g:attr_test.="\n". join(g:attr, ' ') + let g:attr_test.="\n TERM: ". &term + endif + endfu + + fu! DoRecordScreen() + wincmd l + $put =printf(\"\n%s\", g:test) + $put =g:line + $put =g:attr_test + wincmd p + endfu + ]]) + end) + + it('is working', function() + source([=[ + let g:test ="Test 1: simple addmatch()" + call matchadd('Conceal', '\%2l ') + redraw! + let line=ScreenChar(winwidth(0),1) + call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5") + call DoRecordScreen() + + let g:test ="Test 2: simple addmatch() and conceal (should be: #XThisXisXaXTest)" + norm! 'azt + call clearmatches() + syntax on + set concealcursor=n conceallevel=1 + call matchadd('Conceal', '\%2l ', 10, -1, {'conceal': 'X'}) + redraw! + let line=ScreenChar(winwidth(0),1) + call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5") + call DoRecordScreen() + + let g:test ="Test 3: addmatch() and conceallevel=3 (should be: #ThisisaTest)" + norm! 'azt + set conceallevel=3 + call clearmatches() + call matchadd('Conceal', '\%2l ', 10, -1, {'conceal': 'X'}) + redraw! + let line=ScreenChar(winwidth(0),1) + call ScreenAttr(1,[1,2,7,10,12,16], "0==1 && 1==2 && 1==3 && 1==4 && 0!=5") + call DoRecordScreen() + + let g:test ="Test 4: more match() (should be: #Thisisa Test)" + norm! 'azt + call matchadd('ErrorMsg', '\%2l Test', 20, -1, {'conceal': 'X'}) + redraw! + let line=ScreenChar(winwidth(0),1) + call ScreenAttr(1,[1,2,7,10,12,16], "0==1 && 1==2 && 0!=3 && 3==4 && 0!=5 && 3!=5") + call DoRecordScreen() + + let g:test ="Test 5/1: default conceal char (should be: # This is a Test)" + norm! 'azt + call clearmatches() + set conceallevel=1 + call matchadd('Conceal', '\%2l ', 10, -1, {}) + redraw! + let line=ScreenChar(winwidth(0),1) + call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5") + call DoRecordScreen() + let g:test ="Test 5/2: default conceal char (should be: #+This+is+a+Test)" + norm! 'azt + set listchars=conceal:+ + redraw! + let line=ScreenChar(winwidth(0),1) + call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5") + call DoRecordScreen() + set listchars&vi + + let g:test ="Test 6/1: syn and match conceal (should be: #ZThisZisZaZTest)" + norm! 'azt + call clearmatches() + set conceallevel=1 + call matchadd('Conceal', '\%2l ', 10, -1, {'conceal': 'Z'}) + syn match MyConceal /\%2l / conceal containedin=ALL cchar=* + redraw! + let line=ScreenChar(winwidth(0),1) + call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5") + call DoRecordScreen() + let g:test ="Test 6/2: syn and match conceal (should be: #*This*is*a*Test)" + norm! 'azt + call clearmatches() + redraw! + let line=ScreenChar(winwidth(0),1) + call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5") + call DoRecordScreen() + + let g:test ="Test 7/1: clear matches" + norm! 'azt + syn on + call matchadd('Conceal', '\%2l ', 10, -1, {'conceal': 'Z'}) + let a=getmatches() + call clearmatches() + redraw! + let line=ScreenChar(winwidth(0),1) + call ScreenAttr(1,[1,2,7,10,12,16], "0==1 && 0==2 && 0==3 && 0==4 && 0==5") + call DoRecordScreen() + $put =a + call setmatches(a) + norm! 'azt + let g:test ="Test 7/2: reset match using setmatches()" + norm! 'azt + redraw! + let line=ScreenChar(winwidth(0),1) + call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5") + call DoRecordScreen() + + let g:test ="Test 8: using matchaddpos() (should be #Pis a Test" + norm! 'azt + call clearmatches() + call matchaddpos('Conceal', [[2,2,6]], 10, -1, {'conceal': 'P'}) + let a=getmatches() + redraw! + let line=ScreenChar(winwidth(0),1) + call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1!=2 && 0==2 && 0==3 && 0!=4 && 0!=5 && 4==5") + call DoRecordScreen() + $put =a + + let g:test ="Test 9: match using multibyte conceal char (should be: #ˑThisˑisˑaˑTest)" + norm! 'azt + call clearmatches() + call matchadd('Conceal', '\%2l ', 20, -1, {'conceal': "\u02d1"}) + redraw! + let line=ScreenChar(winwidth(0),1) + call ScreenAttr(1,[1,2,7,10,12,16], "0!=1 && 1==2 && 1==3 && 1==4 && 0==5") + call DoRecordScreen() + ]=]) + + expect([=[ + + # This is a Test + + Test 1: simple addmatch() + # This is a Test + OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5] + + Test 2: simple addmatch() and conceal (should be: #XThisXisXaXTest) + #XThisXisXaXTest + OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5] + + Test 3: addmatch() and conceallevel=3 (should be: #ThisisaTest) + #ThisisaTest + OK: g:attr[0]==g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]!=g:attr[5] + + Test 4: more match() (should be: #Thisisa Test) + #Thisisa Test + OK: g:attr[0]==g:attr[1] && g:attr[1]==g:attr[2] && g:attr[0]!=g:attr[3] && g:attr[3]==g:attr[4] && g:attr[0]!=g:attr[5] && g:attr[3]!=g:attr[5] + + Test 5/1: default conceal char (should be: # This is a Test) + # This is a Test + OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5] + + Test 5/2: default conceal char (should be: #+This+is+a+Test) + #+This+is+a+Test + OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5] + + Test 6/1: syn and match conceal (should be: #ZThisZisZaZTest) + #ZThisZisZaZTest + OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5] + + Test 6/2: syn and match conceal (should be: #*This*is*a*Test) + #*This*is*a*Test + OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5] + + Test 7/1: clear matches + # This is a Test + OK: g:attr[0]==g:attr[1] && g:attr[0]==g:attr[2] && g:attr[0]==g:attr[3] && g:attr[0]==g:attr[4] && g:attr[0]==g:attr[5] + {'group': 'Conceal', 'pattern': '\%2l ', 'priority': 10, 'id': 10, 'conceal': 'Z'} + + Test 7/2: reset match using setmatches() + #ZThisZisZaZTest + OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5] + + Test 8: using matchaddpos() (should be #Pis a Test + #Pis a Test + OK: g:attr[0]!=g:attr[1] && g:attr[1]!=g:attr[2] && g:attr[0]==g:attr[2] && g:attr[0]==g:attr[3] && g:attr[0]!=g:attr[4] && g:attr[0]!=g:attr[5] && g:attr[4]==g:attr[5] + {'group': 'Conceal', 'id': 11, 'priority': 10, 'pos1': [2, 2, 6], 'conceal': 'P'} + + Test 9: match using multibyte conceal char (should be: #ˑThisˑisˑaˑTest) + #ˑThisˑisˑaˑTest + OK: g:attr[0]!=g:attr[1] && g:attr[1]==g:attr[2] && g:attr[1]==g:attr[3] && g:attr[1]==g:attr[4] && g:attr[0]==g:attr[5]]=]) + end) +end) diff --git a/test/functional/legacy/options_spec.lua b/test/functional/legacy/options_spec.lua index 773acb9663..21e99c4aa1 100644 --- a/test/functional/legacy/options_spec.lua +++ b/test/functional/legacy/options_spec.lua @@ -1,13 +1,27 @@ --- Test if ":options" throws any exception. The options window seems to mess --- other tests, so restart nvim in the teardown hook - local helpers = require('test.functional.helpers') local command, clear = helpers.command, helpers.clear +local source, expect = helpers.source, helpers.expect describe('options', function() setup(clear) - it('is working', function() + it('should not throw any exception', function() command('options') end) end) + +describe('set', function() + setup(clear) + + it("should keep two comma when 'path' is changed", function() + source([[ + set path=foo,,bar + set path-=bar + set path+=bar + $put =&path]]) + + expect([[ + + foo,,bar]]) + end) +end) diff --git a/test/functional/legacy/search_mbyte_spec.lua b/test/functional/legacy/search_mbyte_spec.lua new file mode 100644 index 0000000000..075b24b897 --- /dev/null +++ b/test/functional/legacy/search_mbyte_spec.lua @@ -0,0 +1,26 @@ +local helpers = require('test.functional.helpers') +local insert = helpers.insert +local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect + +describe('search_mbyte', function() + before_each(clear) + + it("search('multi-byte char', 'bce')", function() + insert([=[ + Results: + + Test bce: + A]=]) + + execute('/^Test bce:/+1') + execute([[$put =search('A', 'bce', line('.'))]]) + + -- Assert buffer contents. + expect([=[ + Results: + + Test bce: + A + 4]=]) + end) +end) diff --git a/test/functional/shada/shada_spec.lua b/test/functional/shada/shada_spec.lua index 2bc855a239..822ab3913c 100644 --- a/test/functional/shada/shada_spec.lua +++ b/test/functional/shada/shada_spec.lua @@ -174,6 +174,7 @@ describe('ShaDa support code', function() nvim_command('set shada+=%') nvim_command('wshada! ' .. shada_fname) local readme_fname = paths.test_source_path .. '/README.md' + readme_fname = helpers.eval( 'resolve("' .. readme_fname .. '")' ) eq({[7]=1, [8]=2, [9]=1, [10]=4, [11]=1}, find_file(readme_fname)) nvim_command('set shada+=r~') nvim_command('wshada! ' .. shada_fname) diff --git a/test/functional/viml/completion_spec.lua b/test/functional/viml/completion_spec.lua index 12f542de7f..4bb9707cda 100644 --- a/test/functional/viml/completion_spec.lua +++ b/test/functional/viml/completion_spec.lua @@ -2,7 +2,7 @@ local helpers = require('test.functional.helpers') local clear, feed = helpers.clear, helpers.feed local eval, eq, neq = helpers.eval, helpers.eq, helpers.neq -local execute, source = helpers.execute, helpers.source +local execute, source, expect = helpers.execute, helpers.source, helpers.expect describe('completion', function() before_each(function() @@ -100,4 +100,45 @@ describe('completion', function() eq('', eval('getline(3)')) end) end) + + describe("refresh:always", function() + before_each(function() + source([[ + function! TestCompletion(findstart, base) abort + if a:findstart + let line = getline('.') + let start = col('.') - 1 + while start > 0 && line[start - 1] =~ '\a' + let start -= 1 + endwhile + return start + else + let ret = [] + for m in split("January February March April May June July August September October November December") + if m =~ a:base " match by regex + call add(ret, m) + endif + endfor + return {'words':ret, 'refresh':'always'} + endif + endfunction + + set completeopt=menuone,noselect + set completefunc=TestCompletion + ]]) + end ) + + it('completes on each input char', function () + feed('i<C-x><C-u>gu<Down><C-y>') + expect('August') + end) + it("repeats correctly after backspace #2674", function () + feed('o<C-x><C-u>Ja<BS><C-n><C-n><Esc>') + feed('.') + expect([[ + + June + June]]) + end) + end) end) |