diff options
69 files changed, 1370 insertions, 533 deletions
diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml new file mode 100644 index 0000000000..d4187d9dad --- /dev/null +++ b/.github/workflows/nightly.yml @@ -0,0 +1,128 @@ +name: Nightly release +on: + schedule: + - cron: '5 5 * * *' + +jobs: + linux: + runs-on: ubuntu-20.04 + outputs: + version: ${{ steps.build.outputs.version }} + release: ${{ steps.build.outputs.release }} + steps: + - uses: actions/checkout@v2 + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y autoconf automake build-essential ccache cmake cpanminus cscope gcc-multilib gdb gettext gperf language-pack-tr libtool-bin locales ninja-build pkg-config python3 python3-pip python3-setuptools unzip valgrind xclip + - name: Build nightly + id: build + run: | + make CMAKE_BUILD_TYPE=RelWithDebinfo CMAKE_EXTRA_FLAGS="-DCMAKE_INSTALL_PREFIX:PATH=" + printf '::set-output name=version::%s\n' "$(./build/bin/nvim --version | head -n 3 | sed -z 's/\n/%0A/g')" + printf '::set-output name=release::%s\n' "$(./build/bin/nvim --version | head -n 1 | sed 's/-.*//')" + make DESTDIR="$GITHUB_WORKSPACE/build/nightly/nvim-linux64" install + cd "$GITHUB_WORKSPACE/build/nightly" + tar cfz nvim-linux64.tar.gz nvim-linux64 + - uses: actions/upload-artifact@v2 + with: + name: nvim-linux64.tar.gz + path: build/nightly/nvim-linux64.tar.gz + retention-days: 1 + + macOS: + runs-on: macos-10.15 + steps: + - uses: actions/checkout@v2 + - name: Install brew packages + run: | + brew update >/dev/null + brew install automake ninja + - name: Build nightly + run: | + make CMAKE_BUILD_TYPE=Release CMAKE_EXTRA_FLAGS="-DCMAKE_INSTALL_PREFIX:PATH= -DCMAKE_OSX_DEPLOYMENT_TARGET=10.11" + make DESTDIR="$GITHUB_WORKSPACE/build/nightly/nvim-osx64" install + - name: Create package + run: | + cd "$GITHUB_WORKSPACE/build/nightly" + mkdir -p bundle/nvim/libs + mkdir -p bundle/nvim/bin + cp nvim-osx64/bin/nvim bundle/nvim/bin/ + libs=($(otool -L nvim-osx64/bin/nvim | sed 1d | sed -E -e 's|^[[:space:]]*||' -e 's| .*||')) + echo "libs:" + for lib in "${libs[@]}"; do + if echo "$lib" | grep -q -E 'libSystem|CoreFoundation' 2>/dev/null; then + echo " [skipped] $lib" + else + echo " $lib" + relname="libs/${lib##*/}" + cp -L "$lib" "bundle/nvim/$relname" + install_name_tool -change "$lib" "@executable_path/../$relname" bundle/nvim/bin/nvim + fi + done + tar cjSf nvim-macos.tar.bz2 -C bundle nvim + - uses: actions/upload-artifact@v2 + with: + name: nvim-macos.tar.bz2 + path: build/nightly/nvim-macos.tar.bz2 + retention-days: 1 + + publish: + needs: [linux, macOS] + runs-on: ubuntu-20.04 + steps: + - uses: actions/download-artifact@v2 + - uses: actions/create-release@v1 + id: create_release + with: + tag_name: nightly + release_name: NVIM ${{ needs.linux.outputs.release }} + body: | + Nvim development (prerelease) build. + ``` + ${{ needs.linux.outputs.version }} + ``` + + ## Install + + ### Windows + + 1. Extract **nvim-win64.zip** (or **nvim-win32.zip**) + 2. Run `nvim-qt.exe` + + ### macOS + + 1. Download **nvim-macos.tar.gz** + 2. Extract: `tar xzvf nvim-macos.tar.gz` + 3. Run `./nvim-osx64/bin/nvim` + + ### Linux (x64) + + 1. Download **nvim.appimage** + 2. Run `chmod u+x nvim.appimage && ./nvim.appimage` + - If your system does not have FUSE you can [extract the appimage](https://github.com/AppImage/AppImageKit/wiki/FUSE#type-2-appimage): + ``` + ./nvim.appimage --appimage-extract + ./squashfs-root/usr/bin/nvim + ``` + + ### Other + + - Install by [package manager](https://github.com/neovim/neovim/wiki/Installing-Neovim) + prerelease: true + - uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./nvim-macos.tar.bz2 + asset_name: nvim-macos.tar.bz2 + asset_content_type: application/x-bzip2 + - uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./nvim-linux64.tar.gz + asset_name: nvim-linux64.tar.gz + asset_content_type: application/gzip diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index 58633455c3..755e7becb3 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -933,6 +933,39 @@ nvim_get_option({name}) *nvim_get_option()* Return: ~ Option value (global) +nvim_get_option_info({name}) *nvim_get_option_info()* + Gets the option information for one option + + Resulting dictionary has keys: + • name (string): Name of the option + • shortname (shortname): Shortened name of the option + • type (string): Name of the type of option + • default (Any): The default value for the option + + Script-Related Keys: + • was_set (bool): Whether the option was set. + • last_set_sid (int): Last set script id + • last_set_linenr (int): Last set script id, -1 if invalid. + • last_set_lchan (int): Last set script id, -1 if invalid. + + Flag-Related Keys: + • win (bool): Window-local option + • buf (bool): Buffer-local option + • global_local (bool): Global or Buffer local option + • flaglist (bool): List of single char flags + + Parameters: ~ + {name} Option name + + Return: ~ + Option Information + +nvim_get_options_info() *nvim_get_options_info()* + Gets the option information for all options. + + Return: ~ + Map<option_name, option_info> + nvim_get_proc({pid}) *nvim_get_proc()* Gets info describing process `pid` . @@ -950,11 +983,16 @@ nvim_get_runtime_file({name}, {all}) *nvim_get_runtime_file()* 'name' can contain wildcards. For example nvim_get_runtime_file("colors/*.vim", true) will return all - color scheme files. + color scheme files. Always use forward slashes (/) in the + search pattern for subdirectories regardless of platform. It is not an error to not find any files. An empty array is returned then. + To find a directory, `name` must end with a forward slash, + like "rplugin/python/". Without the slash it would instead + look for an ordinary file called "rplugin/python". + Attributes: ~ {fast} @@ -1535,7 +1573,9 @@ nvim_set_hl({ns_id}, {name}, {val}) *nvim_set_hl()* {ns_id} number of namespace for this highlight {name} highlight group name, like ErrorMsg {val} highlight definiton map, like - |nvim_get_hl_by_name|. + |nvim_get_hl_by_name|. in addition the following + keys are also recognized: `default` : don't + override existing definition, like `hi default` nvim_set_hl_ns({ns_id}) *nvim_set_hl_ns()* Set active namespace for highlights. diff --git a/runtime/doc/cmdline.txt b/runtime/doc/cmdline.txt index 562a1f23ac..098245b5a8 100644 --- a/runtime/doc/cmdline.txt +++ b/runtime/doc/cmdline.txt @@ -215,6 +215,9 @@ CTRL-Y When there is a modeless selection, copy the selection into the clipboard. If there is no selection CTRL-Y is inserted as a character. + *c_CTRL-Z* +CTRL-Z Trigger 'wildmode'. Same as 'wildcharm', but always available. + CTRL-M or CTRL-J *c_CTRL-M* *c_CTRL-J* *c_<NL>* *c_<CR>* *c_CR* <CR> or <NL> start entered command diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt index 78829fbba1..c8a44dfb75 100644 --- a/runtime/doc/lsp.txt +++ b/runtime/doc/lsp.txt @@ -1049,7 +1049,7 @@ get_all() *vim.lsp.diagnostic.get_all()* Get all diagnostics for all clients Return: ~ - Diagnostic[] + {bufnr:Diagnostic[]} *vim.lsp.diagnostic.get_count()* get_count({bufnr}, {severity}, {client_id}) diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt index f58b0d5030..160995b440 100644 --- a/runtime/doc/starting.txt +++ b/runtime/doc/starting.txt @@ -104,7 +104,7 @@ argument. --startuptime {fname} *--startuptime* During startup write timing messages to the file {fname}. This can be used to find out where time is spent while loading - your |init.vim|, plugins and opening the first file. + your |config|, plugins and opening the first file. When {fname} already exists new messages are appended. (Only available when compiled with the |+startuptime| feature). @@ -211,7 +211,7 @@ argument. When 'verbose' is set messages are printed to stderr. > echo foo | nvim -V1 -es -< User |init.vim| is skipped (unless given with |-u|). +< User |config| is skipped (unless given with |-u|). Swap file is skipped (like |-n|). User |shada| is loaded (unless "-i NONE" is given). @@ -406,12 +406,14 @@ accordingly. Vim proceeds in this order: proceeding to load user configuration. 4. Load user config (execute Ex commands from files, environment, …). - $VIMINIT environment variable is read as one Ex command line (separate - multiple commands with '|' or <NL>). - *config* *init.vim* *vimrc* *exrc* - A file containing init commands is generically called a "vimrc" or - "config". Each line in such a file is executed as an Ex command. - |vimrc-intro| |base-directories| + An environment variable (e.g. $VIMINIT) is read as one Ex command + line, where multiple commands must be separated with '|' or <NL>. + *config* *init.vim* *init.lua* *vimrc* *exrc* + A file that contains initialization commands is generically called + a "vimrc" or config file. It can be a Vimscript or Lua file named + "init.vim" or "init.lua" respectively. It is an error to use both at + the same time. Each line in a "init.vim" is executed as an Ex command + line. See also |vimrc-intro| and |base-directories|. The Nvim config file is "init.vim", located at: Unix ~/.config/nvim/init.vim @@ -578,7 +580,7 @@ The extreme flexibility of editors like Vim and Emacs means that any plugin or setting can affect the entire editor in ways that are not initially obvious. To find the cause of a problem in your config, you must "bisect" it: -1. Remove or disable half of your `init.vim`. +1. Remove or disable half of your |config|. 2. Restart Nvim. 3. If the problem still occurs, goto 1. 4. If the problem is gone, restore half of the removed lines. @@ -597,7 +599,7 @@ to 'shortmess'. $VIM and $VIMRUNTIME *$VIM* The environment variable "$VIM" is used to locate various user files for Nvim, -such as the user startup script |init.vim|. This depends on the system, see +such as the user |config|. This depends on the system, see |startup|. Nvim will try to get the value for $VIM in this order: @@ -709,11 +711,11 @@ can be used with different terminals. Only global mappings are stored, not mappings local to a buffer. -A common method is to use a default |init.vim| file, make some modifications +A common method is to use a default |config| file, make some modifications with ":map" and ":set" commands and write the modified file. First read the default vimrc in with a command like ":source ~piet/.vimrc.Cprogs", change the settings and then save them in the current directory with ":mkvimrc!". If -you want to make this file your default |init.vim|, move it to +you want to make this file your default |config|, move it to $XDG_CONFIG_HOME/nvim. You could also use autocommands |autocommand| and/or modelines |modeline|. @@ -1065,7 +1067,7 @@ do this. This can be useful in order to create a second file, say "~/.my.shada" which could contain certain settings that you always want when you first start Neovim. For example, you can preload registers with particular data, or put certain commands in the command line history. A line -in your |init.vim| file like > +in your |config| file like > :rshada! ~/.my.shada can be used to load this information. You could even have different ShaDa files for different types of files (e.g., C code) and load them based on the diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt index 0f15aefd17..808af5f544 100644 --- a/runtime/doc/vim_diff.txt +++ b/runtime/doc/vim_diff.txt @@ -182,8 +182,6 @@ Highlight groups: |hl-Whitespace| highlights 'listchars' whitespace Input/Mappings: - |<Cmd>| pseudokey - ALT (|META|) chords always work (even in the |TUI|). Map |<M-| with any key: <M-1>, <M-BS>, <M-Del>, <M-Ins>, <M-/>, <M-\>, <M-Space>, <M-Enter>, etc. Case-sensitive: <M-a> and <M-A> are two different keycodes. @@ -215,7 +213,6 @@ Signs: Signs are removed if the associated line is deleted. Variables: - |v:exiting| |v:progpath| is always absolute ("full") |v:windowid| is always available (for use by external UIs) diff --git a/runtime/filetype.vim b/runtime/filetype.vim index b9d2a43d5d..ed19fa1a43 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -1768,8 +1768,13 @@ au BufNewFile,BufReadPost *.tutor setf tutor " TWIG files au BufNewFile,BufReadPost *.twig setf twig -" Typescript -au BufNewFile,BufReadPost *.ts setf typescript +" Typescript or Qt translation file (which is XML) +au BufNewFile,BufReadPost *.ts + \ if getline(1) =~ '<?xml' | + \ setf xml | + \ else | + \ setf typescript | + \ endif " TypeScript with React au BufNewFile,BufRead *.tsx setf typescriptreact diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index 92f56b2ddf..f082fe29f2 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -1032,9 +1032,9 @@ function lsp.buf_request(bufnr, method, params, handler) end end) - -- if no clients support the given method, call the handler with the proper + -- if has client but no clients support the given method, call the callback with the proper -- error message. - if not method_supported then + if not tbl_isempty(all_buffer_active_clients[resolve_bufnr(bufnr)] or {}) and not method_supported then local unsupported_err = lsp._unsupported_method(method) handler = handler or lsp.handlers[method] if handler then diff --git a/runtime/lua/vim/lsp/diagnostic.lua b/runtime/lua/vim/lsp/diagnostic.lua index 1570d4a122..27a1f53f89 100644 --- a/runtime/lua/vim/lsp/diagnostic.lua +++ b/runtime/lua/vim/lsp/diagnostic.lua @@ -308,15 +308,16 @@ end --- Get all diagnostics for all clients --- ----@return Diagnostic[] +---@return {bufnr: Diagnostic[]} function M.get_all() - local all_diagnostics = {} - for _, buf_diagnostics in pairs(diagnostic_cache) do + local diagnostics_by_bufnr = {} + for bufnr, buf_diagnostics in pairs(diagnostic_cache) do + diagnostics_by_bufnr[bufnr] = {} for _, client_diagnostics in pairs(buf_diagnostics) do - vim.list_extend(all_diagnostics, client_diagnostics) + vim.list_extend(diagnostics_by_bufnr[bufnr], client_diagnostics) end end - return all_diagnostics + return diagnostics_by_bufnr end --- Return associated diagnostics for bufnr diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index f78a36fda2..5804ac6656 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -957,6 +957,7 @@ function M.open_floating_preview(contents, filetype, opts) end api.nvim_buf_set_lines(floating_bufnr, 0, -1, true, contents) api.nvim_buf_set_option(floating_bufnr, 'modifiable', false) + api.nvim_buf_set_option(floating_bufnr, 'bufhidden', 'wipe') M.close_preview_autocmd({"CursorMoved", "CursorMovedI", "BufHidden", "BufLeave"}, floating_winnr) return floating_bufnr, floating_winnr end diff --git a/runtime/syntax/dockerfile.vim b/runtime/syntax/dockerfile.vim index 4cf50d999f..ce52e697cd 100644 --- a/runtime/syntax/dockerfile.vim +++ b/runtime/syntax/dockerfile.vim @@ -1,26 +1,45 @@ " dockerfile.vim - Syntax highlighting for Dockerfiles " Maintainer: Honza Pokorny <https://honza.ca> -" Version: 0.6 -" Last Change: 2019 Aug 16 +" Last Change: 2020 Feb 11 " License: BSD +" https://docs.docker.com/engine/reference/builder/ if exists("b:current_syntax") finish endif -let b:current_syntax = "dockerfile" +syntax include @JSON syntax/json.vim +unlet b:current_syntax + +syntax include @Shell syntax/sh.vim +unlet b:current_syntax syntax case ignore +syntax match dockerfileLinePrefix /\v^\s*(ONBUILD\s+)?\ze\S/ contains=dockerfileKeyword nextgroup=dockerfileInstruction skipwhite +syntax region dockerfileFrom matchgroup=dockerfileKeyword start=/\v^\s*(FROM)\ze(\s|$)/ skip=/\v\\\_./ end=/\v((^|\s)AS(\s|$)|$)/ contains=dockerfileOption -syntax match dockerfileKeyword /\v^\s*(ONBUILD\s+)?(ADD|ARG|CMD|COPY|ENTRYPOINT|ENV|EXPOSE|FROM|HEALTHCHECK|LABEL|MAINTAINER|RUN|SHELL|STOPSIGNAL|USER|VOLUME|WORKDIR)\s/ +syntax keyword dockerfileKeyword contained ADD ARG CMD COPY ENTRYPOINT ENV EXPOSE HEALTHCHECK LABEL MAINTAINER ONBUILD RUN SHELL STOPSIGNAL USER VOLUME WORKDIR +syntax match dockerfileOption contained /\v(^|\s)\zs--\S+/ -syntax match dockerfileKeyword /\v(AS)/ +syntax match dockerfileInstruction contained /\v<(\S+)>(\s+--\S+)*/ contains=dockerfileKeyword,dockerfileOption skipwhite nextgroup=dockerfileValue +syntax match dockerfileInstruction contained /\v<(ADD|COPY)>(\s+--\S+)*/ contains=dockerfileKeyword,dockerfileOption skipwhite nextgroup=dockerfileJSON +syntax match dockerfileInstruction contained /\v<(HEALTHCHECK)>(\s+--\S+)*/ contains=dockerfileKeyword,dockerfileOption skipwhite nextgroup=dockerfileInstruction +syntax match dockerfileInstruction contained /\v<(CMD|ENTRYPOINT|RUN)>/ contains=dockerfileKeyword skipwhite nextgroup=dockerfileShell +syntax match dockerfileInstruction contained /\v<(CMD|ENTRYPOINT|RUN)>\ze\s+\[/ contains=dockerfileKeyword skipwhite nextgroup=dockerfileJSON +syntax match dockerfileInstruction contained /\v<(SHELL|VOLUME)>/ contains=dockerfileKeyword skipwhite nextgroup=dockerfileJSON -syntax region dockerfileString start=/\v"/ skip=/\v\\./ end=/\v"/ +syntax region dockerfileString contained start=/\v"/ skip=/\v\\./ end=/\v"/ +syntax region dockerfileJSON contained keepend start=/\v\[/ skip=/\v\\\_./ end=/\v$/ contains=@JSON +syntax region dockerfileShell contained keepend start=/\v/ skip=/\v\\\_./ end=/\v$/ contains=@Shell +syntax region dockerfileValue contained keepend start=/\v/ skip=/\v\\\_./ end=/\v$/ contains=dockerfileString -syntax match dockerfileComment "\v^\s*#.*$" +syntax region dockerfileComment start=/\v^\s*#/ end=/\v$/ +set commentstring=#\ %s hi def link dockerfileString String hi def link dockerfileKeyword Keyword hi def link dockerfileComment Comment +hi def link dockerfileOption Special + +let b:current_syntax = "dockerfile" diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index 271fd5b485..055abb797f 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -16,6 +16,7 @@ #define BOOLEAN_OBJ(b) ((Object) { \ .type = kObjectTypeBoolean, \ .data.boolean = b }) +#define BOOL(b) BOOLEAN_OBJ(b) #define INTEGER_OBJ(i) ((Object) { \ .type = kObjectTypeInteger, \ @@ -29,6 +30,8 @@ .type = kObjectTypeString, \ .data.string = s }) +#define CSTR_TO_OBJ(s) STRING_OBJ(cstr_to_string(s)) + #define BUFFER_OBJ(s) ((Object) { \ .type = kObjectTypeBuffer, \ .data.integer = s }) @@ -59,6 +62,8 @@ #define PUT(dict, k, v) \ kv_push(dict, ((KeyValuePair) { .key = cstr_to_string(k), .value = v })) +#define PUT_BOOL(dict, name, condition) PUT(dict, name, BOOLEAN_OBJ(condition)); + #define ADD(array, item) \ kv_push(array, item) diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 77002697fe..8ac820abd9 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -970,6 +970,47 @@ Object nvim_get_option(String name, Error *err) return get_option_from(NULL, SREQ_GLOBAL, name, err); } +/// Gets the option information for all options. +/// +/// The dictionary has the full option names as keys and option metadata +/// dictionaries as detailed at |nvim_get_option_info|. +/// +/// @return dictionary of all options +Dictionary nvim_get_all_options_info(Error *err) + FUNC_API_SINCE(7) +{ + return get_all_vimoptions(); +} + +/// Gets the option information for one option +/// +/// Resulting dictionary has keys: +/// - name: Name of the option (like 'filetype') +/// - shortname: Shortened name of the option (like 'ft') +/// - type: type of option ("string", "integer" or "boolean") +/// - default: The default value for the option +/// - was_set: Whether the option was set. +/// +/// - last_set_sid: Last set script id (if any) +/// - last_set_linenr: line number where option was set +/// - last_set_chan: Channel where option was set (0 for local) +/// +/// - scope: one of "global", "win", or "buf" +/// - global_local: whether win or buf option has a global value +/// +/// - commalist: List of comma separated values +/// - flaglist: List of single char flags +/// +/// +/// @param name Option name +/// @param[out] err Error details, if any +/// @return Option Information +Dictionary nvim_get_option_info(String name, Error *err) + FUNC_API_SINCE(7) +{ + return get_vimoption(name, err); +} + /// Sets an option value. /// /// @param channel_id diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index ffa44c33cd..839d61cd2e 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -1637,12 +1637,23 @@ void do_autochdir(void) void no_write_message(void) { - EMSG(_("E37: No write since last change (add ! to override)")); + if (curbuf->terminal + && channel_job_running((uint64_t)curbuf->b_p_channel)) { + EMSG(_("E948: Job still running (add ! to end the job)")); + } else { + EMSG(_("E37: No write since last change (add ! to override)")); + } } -void no_write_message_nobang(void) +void no_write_message_nobang(const buf_T *const buf) + FUNC_ATTR_NONNULL_ALL { - EMSG(_("E37: No write since last change")); + if (buf->terminal + && channel_job_running((uint64_t)buf->b_p_channel)) { + EMSG(_("E948: Job still running")); + } else { + EMSG(_("E37: No write since last change")); + } } // diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 5d44c3274e..7fefa8520a 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -196,8 +196,8 @@ static int ctrl_x_mode = CTRL_X_NORMAL; static int compl_matches = 0; static char_u *compl_pattern = NULL; -static int compl_direction = FORWARD; -static int compl_shows_dir = FORWARD; +static Direction compl_direction = FORWARD; +static Direction compl_shows_dir = FORWARD; static int compl_pending = 0; // > 1 for postponed CTRL-N static pos_T compl_startpos; static colnr_T compl_col = 0; /* column where the text starts @@ -2156,7 +2156,7 @@ static bool ins_compl_accept_char(int c) /// /// @param[in] cont_s_ipos next ^X<> will set initial_pos int ins_compl_add_infercase(char_u *str_arg, int len, bool icase, char_u *fname, - int dir, bool cont_s_ipos) + Direction dir, bool cont_s_ipos) FUNC_ATTR_NONNULL_ARG(1) { char_u *str = str_arg; @@ -2308,7 +2308,7 @@ static int ins_compl_add(char_u *const str, int len, FUNC_ATTR_NONNULL_ARG(1) { compl_T *match; - int dir = (cdir == kDirectionNotSet ? compl_direction : cdir); + const Direction dir = (cdir == kDirectionNotSet ? compl_direction : cdir); int flags = flags_arg; os_breakcheck(); @@ -2511,7 +2511,7 @@ static void ins_compl_add_matches(int num_matches, char_u **matches, int icase) FUNC_ATTR_NONNULL_ALL { int add_r = OK; - int dir = compl_direction; + Direction dir = compl_direction; for (int i = 0; i < num_matches && add_r != FAIL; i++) { if ((add_r = ins_compl_add(matches[i], -1, NULL, NULL, false, NULL, dir, @@ -2864,7 +2864,7 @@ ins_compl_dictionaries ( char_u **files; int count; int save_p_scs; - int dir = compl_direction; + Direction dir = compl_direction; if (*dict == NUL) { /* When 'dictionary' is empty and spell checking is enabled use @@ -2945,7 +2945,10 @@ theend: xfree(buf); } -static void ins_compl_files(int count, char_u **files, int thesaurus, int flags, regmatch_T *regmatch, char_u *buf, int *dir) +static void ins_compl_files(int count, char_u **files, int thesaurus, + int flags, regmatch_T *regmatch, char_u *buf, + Direction *dir) + FUNC_ATTR_NONNULL_ARG(2, 7) { char_u *ptr; int i; @@ -3137,6 +3140,56 @@ bool ins_compl_active(void) return compl_started; } +static void ins_compl_update_sequence_numbers(void) +{ + int number = 0; + compl_T *match; + + if (compl_direction == FORWARD) { + // search backwards for the first valid (!= -1) number. + // This should normally succeed already at the first loop + // cycle, so it's fast! + for (match = compl_curr_match->cp_prev; + match != NULL && match != compl_first_match; + match = match->cp_prev) { + if (match->cp_number != -1) { + number = match->cp_number; + break; + } + } + if (match != NULL) { + // go up and assign all numbers which are not assigned yet + for (match = match->cp_next; + match != NULL && match->cp_number == -1; + match = match->cp_next) { + match->cp_number = ++number; + } + } + } else { // BACKWARD + assert(compl_direction == BACKWARD); + // search forwards (upwards) for the first valid (!= -1) + // number. This should normally succeed already at the + // first loop cycle, so it's fast! + for (match = compl_curr_match->cp_next; + match != NULL && match != compl_first_match; + match = match->cp_next) { + if (match->cp_number != -1) { + number = match->cp_number; + break; + } + } + if (match != NULL) { + // go down and assign all numbers which are not + // assigned yet + for (match = match->cp_prev; + match && match->cp_number == -1; + match = match->cp_prev) { + match->cp_number = ++number; + } + } + } +} + // Get complete information void get_complete_info(list_T *what_list, dict_T *retdict) { @@ -3214,6 +3267,9 @@ void get_complete_info(list_T *what_list, dict_T *retdict) } if (ret == OK && (what_flag & CI_WHAT_SELECTED)) { + if (compl_curr_match != NULL && compl_curr_match->cp_number == -1) { + ins_compl_update_sequence_numbers(); + } ret = tv_dict_add_nr(retdict, S_LEN("selected"), (compl_curr_match != NULL) ? compl_curr_match->cp_number - 1 : -1); @@ -3865,7 +3921,7 @@ theend: */ static void ins_compl_add_list(list_T *const list) { - int dir = compl_direction; + Direction dir = compl_direction; // Go through the List with matches and add each of them. TV_LIST_ITER(list, li, { @@ -5242,52 +5298,11 @@ static int ins_complete(int c, bool enable_pum) } else if (compl_curr_match->cp_next == compl_curr_match->cp_prev) { edit_submode_extra = (char_u *)_("The only match"); edit_submode_highl = HLF_COUNT; + compl_curr_match->cp_number = 1; } else { // Update completion sequence number when needed. if (compl_curr_match->cp_number == -1) { - int number = 0; - compl_T *match; - - if (compl_direction == FORWARD) { - /* search backwards for the first valid (!= -1) number. - * This should normally succeed already at the first loop - * cycle, so it's fast! */ - for (match = compl_curr_match->cp_prev; match != NULL - && match != compl_first_match; - match = match->cp_prev) - if (match->cp_number != -1) { - number = match->cp_number; - break; - } - if (match != NULL) - /* go up and assign all numbers which are not assigned - * yet */ - for (match = match->cp_next; - match != NULL && match->cp_number == -1; - match = match->cp_next) - match->cp_number = ++number; - } else { // BACKWARD - // search forwards (upwards) for the first valid (!= -1) - // number. This should normally succeed already at the - // first loop cycle, so it's fast! - for (match = compl_curr_match->cp_next; - match != NULL && match != compl_first_match; - match = match->cp_next) { - if (match->cp_number != -1) { - number = match->cp_number; - break; - } - } - if (match != NULL) { - // go down and assign all numbers which are not - // assigned yet - for (match = match->cp_prev; - match && match->cp_number == -1; - match = match->cp_prev) { - match->cp_number = ++number; - } - } - } + ins_compl_update_sequence_numbers(); } /* The match should always have a sequence number now, this is diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 054b788940..fa037b59d7 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -64,6 +64,7 @@ static char *e_dictrange = N_("E719: Cannot use [:] with a Dictionary"); static char *e_illvar = N_("E461: Illegal variable name: %s"); static char *e_cannot_mod = N_("E995: Cannot modify existing variable"); static char *e_invalwindow = N_("E957: Invalid window number"); +static char *e_lock_unlock = N_("E940: Cannot lock or unlock variable %s"); // TODO(ZyX-I): move to eval/executor static char *e_letwrong = N_("E734: Wrong variable type for %s="); @@ -2638,22 +2639,18 @@ void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx) xp->xp_pattern = arg; } -/* - * ":unlet[!] var1 ... " command. - */ +/// ":unlet[!] var1 ... " command. void ex_unlet(exarg_T *eap) { - ex_unletlock(eap, eap->arg, 0); + ex_unletlock(eap, eap->arg, 0, do_unlet_var); } // TODO(ZyX-I): move to eval/ex_cmds -/* - * ":lockvar" and ":unlockvar" commands - */ +/// ":lockvar" and ":unlockvar" commands void ex_lockvar(exarg_T *eap) { - char_u *arg = eap->arg; + char_u *arg = eap->arg; int deep = 2; if (eap->forceit) { @@ -2663,30 +2660,41 @@ void ex_lockvar(exarg_T *eap) arg = skipwhite(arg); } - ex_unletlock(eap, arg, deep); + ex_unletlock(eap, arg, deep, do_lock_var); } // TODO(ZyX-I): move to eval/ex_cmds -/* - * ":unlet", ":lockvar" and ":unlockvar" are quite similar. - */ -static void ex_unletlock(exarg_T *eap, char_u *argstart, int deep) +/// Common parsing logic for :unlet, :lockvar and :unlockvar. +/// +/// Invokes `callback` afterwards if successful and `eap->skip == false`. +/// +/// @param[in] eap Ex command arguments for the command. +/// @param[in] argstart Start of the string argument for the command. +/// @param[in] deep Levels to (un)lock for :(un)lockvar, -1 to (un)lock +/// everything. +/// @param[in] callback Appropriate handler for the command. +static void ex_unletlock(exarg_T *eap, char_u *argstart, int deep, + ex_unletlock_callback callback) + FUNC_ATTR_NONNULL_ALL { - char_u *arg = argstart; + char_u *arg = argstart; char_u *name_end; bool error = false; lval_T lv; do { if (*arg == '$') { - const char *name = (char *)++arg; - + lv.ll_name = (const char *)arg; + lv.ll_tv = NULL; + arg++; if (get_env_len((const char_u **)&arg) == 0) { - EMSG2(_(e_invarg2), name - 1); + EMSG2(_(e_invarg2), arg - 1); return; } - os_unsetenv(name); + if (!error && !eap->skip && callback(&lv, arg, eap, deep) == FAIL) { + error = true; + } name_end = arg; } else { // Parse the name and find the end. @@ -2707,17 +2715,8 @@ static void ex_unletlock(exarg_T *eap, char_u *argstart, int deep) break; } - if (!error && !eap->skip) { - if (eap->cmdidx == CMD_unlet) { - if (do_unlet_var(&lv, name_end, eap->forceit) == FAIL) { - error = true; - } - } else { - if (do_lock_var(&lv, name_end, deep, - eap->cmdidx == CMD_lockvar) == FAIL) { - error = true; - } - } + if (!error && !eap->skip && callback(&lv, name_end, eap, deep) == FAIL) { + error = true; } if (!eap->skip) { @@ -2732,8 +2731,19 @@ static void ex_unletlock(exarg_T *eap, char_u *argstart, int deep) // TODO(ZyX-I): move to eval/ex_cmds -static int do_unlet_var(lval_T *const lp, char_u *const name_end, int forceit) +/// Unlet a variable indicated by `lp`. +/// +/// @param[in] lp The lvalue. +/// @param[in] name_end End of the string argument for the command. +/// @param[in] eap Ex command arguments for :unlet. +/// @param[in] deep Unused. +/// +/// @return OK on success, or FAIL on failure. +static int do_unlet_var(lval_T *lp, char_u *name_end, exarg_T *eap, + int deep FUNC_ATTR_UNUSED) + FUNC_ATTR_NONNULL_ALL { + int forceit = eap->forceit; int ret = OK; int cc; @@ -2741,8 +2751,10 @@ static int do_unlet_var(lval_T *const lp, char_u *const name_end, int forceit) cc = *name_end; *name_end = NUL; - // Normal name or expanded name. - if (do_unlet(lp->ll_name, lp->ll_name_len, forceit) == FAIL) { + // Environment variable, normal name or expanded name. + if (*lp->ll_name == '$') { + os_unsetenv(lp->ll_name + 1); + } else if (do_unlet(lp->ll_name, lp->ll_name_len, forceit) == FAIL) { ret = FAIL; } *name_end = cc; @@ -2816,7 +2828,7 @@ static int do_unlet_var(lval_T *const lp, char_u *const name_end, int forceit) /// /// @param[in] name Variable name to unlet. /// @param[in] name_len Variable name length. -/// @param[in] fonceit If true, do not complain if variable doesn’t exist. +/// @param[in] forceit If true, do not complain if variable doesn’t exist. /// /// @return OK if it existed, FAIL otherwise. int do_unlet(const char *const name, const size_t name_len, const bool forceit) @@ -2883,14 +2895,21 @@ int do_unlet(const char *const name, const size_t name_len, const bool forceit) // TODO(ZyX-I): move to eval/ex_cmds -/* - * Lock or unlock variable indicated by "lp". - * "deep" is the levels to go (-1 for unlimited); - * "lock" is TRUE for ":lockvar", FALSE for ":unlockvar". - */ -static int do_lock_var(lval_T *lp, char_u *const name_end, const int deep, - const bool lock) +/// Lock or unlock variable indicated by `lp`. +/// +/// Locks if `eap->cmdidx == CMD_lockvar`, unlocks otherwise. +/// +/// @param[in] lp The lvalue. +/// @param[in] name_end Unused. +/// @param[in] eap Ex command arguments for :(un)lockvar. +/// @param[in] deep Levels to (un)lock, -1 to (un)lock everything. +/// +/// @return OK on success, or FAIL on failure. +static int do_lock_var(lval_T *lp, char_u *name_end FUNC_ATTR_UNUSED, + exarg_T *eap, int deep) + FUNC_ATTR_NONNULL_ARG(1, 3) { + bool lock = eap->cmdidx == CMD_lockvar; int ret = OK; if (deep == 0) { // Nothing to do. @@ -2898,25 +2917,31 @@ static int do_lock_var(lval_T *lp, char_u *const name_end, const int deep, } if (lp->ll_tv == NULL) { - // Normal name or expanded name. - dictitem_T *const di = find_var( - (const char *)lp->ll_name, lp->ll_name_len, NULL, - true); - if (di == NULL) { + if (*lp->ll_name == '$') { + EMSG2(_(e_lock_unlock), lp->ll_name); ret = FAIL; - } else if ((di->di_flags & DI_FLAGS_FIX) - && di->di_tv.v_type != VAR_DICT - && di->di_tv.v_type != VAR_LIST) { - // For historical reasons this error is not given for Lists and - // Dictionaries. E.g. b: dictionary may be locked/unlocked. - emsgf(_("E940: Cannot lock or unlock variable %s"), lp->ll_name); } else { - if (lock) { - di->di_flags |= DI_FLAGS_LOCK; + // Normal name or expanded name. + dictitem_T *const di = find_var( + (const char *)lp->ll_name, lp->ll_name_len, NULL, + true); + if (di == NULL) { + ret = FAIL; + } else if ((di->di_flags & DI_FLAGS_FIX) + && di->di_tv.v_type != VAR_DICT + && di->di_tv.v_type != VAR_LIST) { + // For historical reasons this error is not given for Lists and + // Dictionaries. E.g. b: dictionary may be locked/unlocked. + EMSG2(_(e_lock_unlock), lp->ll_name); + ret = FAIL; } else { - di->di_flags &= ~DI_FLAGS_LOCK; + if (lock) { + di->di_flags |= DI_FLAGS_LOCK; + } else { + di->di_flags &= ~DI_FLAGS_LOCK; + } + tv_item_lock(&di->di_tv, deep, lock); } - tv_item_lock(&di->di_tv, deep, lock); } } else if (lp->ll_range) { listitem_T *li = lp->ll_li; diff --git a/src/nvim/eval.h b/src/nvim/eval.h index 0b4cbb3b4d..06b7f9e21d 100644 --- a/src/nvim/eval.h +++ b/src/nvim/eval.h @@ -233,6 +233,8 @@ typedef enum { kDictListItems, ///< List dictionary contents: [keys, values]. } DictListType; +typedef int (*ex_unletlock_callback)(lval_T *, char_u *, exarg_T *, int); + // Used for checking if local variables or arguments used in a lambda. extern bool *eval_lavars_used; diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index b08ee3794d..4df935469a 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -7044,7 +7044,8 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, FunPtr fptr) xfree(buf); } # else - rettv->vval.v_string = (char_u *)xstrdup(p); + char *v = os_realpath(fname, NULL); + rettv->vval.v_string = (char_u *)(v == NULL ? xstrdup(fname) : v); # endif #endif diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index d2ccbe3e6d..b0a51eaefd 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -1965,7 +1965,12 @@ void do_wqall(exarg_T *eap) } FOR_ALL_BUFFERS(buf) { - if (!bufIsChanged(buf) || bt_dontwrite(buf)) { + if (exiting + && buf->terminal + && channel_job_running((uint64_t)buf->b_p_channel)) { + no_write_message_nobang(buf); + error++; + } else if (!bufIsChanged(buf) || bt_dontwrite(buf)) { continue; } /* diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index 6b03117ff3..3b9c44c3cd 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -1297,7 +1297,7 @@ bool check_changed(buf_T *buf, int flags) if (flags & CCGD_EXCMD) { no_write_message(); } else { - no_write_message_nobang(); + no_write_message_nobang(curbuf); } return true; } @@ -1503,8 +1503,10 @@ bool check_changed_any(bool hidden, bool unload) msg_col = 0; msg_didout = false; } - if (EMSG2(_("E162: No write since last change for buffer \"%s\""), - buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname)) { + if ((buf->terminal && channel_job_running((uint64_t)buf->b_p_channel)) + ? EMSG2(_("E947: Job still running in buffer \"%s\""), buf->b_fname) + : EMSG2(_("E162: No write since last change for buffer \"%s\""), + buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname)) { save = no_wait_return; no_wait_return = false; wait_return(false); diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 0100be15bc..ed408c28e5 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -1024,7 +1024,7 @@ static int command_line_execute(VimState *state, int key) } // free expanded names when finished walking through matches - if (!(s->c == p_wc && KeyTyped) && s->c != p_wcm + if (!(s->c == p_wc && KeyTyped) && s->c != p_wcm && s->c != Ctrl_Z && s->c != Ctrl_N && s->c != Ctrl_P && s->c != Ctrl_A && s->c != Ctrl_L) { if (compl_match_array) { @@ -1328,7 +1328,8 @@ static int command_line_execute(VimState *state, int key) // - hitting <ESC> twice means: abandon command line. // - wildcard expansion is only done when the 'wildchar' key is really // typed, not when it comes from a macro - if ((s->c == p_wc && !s->gotesc && KeyTyped) || s->c == p_wcm) { + if ((s->c == p_wc && !s->gotesc && KeyTyped) || s->c == p_wcm + || s->c == Ctrl_Z) { int options = WILD_NO_BEEP; if (wim_flags[s->wim_index] & WIM_BUFLASTUSED) { options |= WILD_BUFLASTUSED; diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 0a3c30134b..344a2387d6 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -927,7 +927,7 @@ void nlua_typval_eval(const String str, typval_T *const arg, memcpy(lcmd + sizeof(EVALHEADER) - 1, str.data, str.size); lcmd[lcmd_len - 1] = ')'; #undef EVALHEADER - typval_exec_lua(lcmd, lcmd_len, "luaeval()", arg, 1, true, ret_tv); + nlua_typval_exec(lcmd, lcmd_len, "luaeval()", arg, 1, true, ret_tv); if (lcmd != (char *)IObuff) { xfree(lcmd); @@ -954,16 +954,16 @@ void nlua_typval_call(const char *str, size_t len, typval_T *const args, #undef CALLHEADER #undef CALLSUFFIX - typval_exec_lua(lcmd, lcmd_len, "v:lua", args, argcount, false, ret_tv); + nlua_typval_exec(lcmd, lcmd_len, "v:lua", args, argcount, false, ret_tv); if (lcmd != (char *)IObuff) { xfree(lcmd); } } -static void typval_exec_lua(const char *lcmd, size_t lcmd_len, const char *name, - typval_T *const args, int argcount, bool special, - typval_T *ret_tv) +static void nlua_typval_exec(const char *lcmd, size_t lcmd_len, + const char *name, typval_T *const args, + int argcount, bool special, typval_T *ret_tv) { if (check_secure()) { if (ret_tv) { @@ -1140,7 +1140,7 @@ void ex_lua(exarg_T *const eap) xfree(code); return; } - typval_exec_lua(code, len, ":lua", NULL, 0, false, NULL); + nlua_typval_exec(code, len, ":lua", NULL, 0, false, NULL); xfree(code); } @@ -1231,17 +1231,30 @@ void ex_luado(exarg_T *const eap) void ex_luafile(exarg_T *const eap) FUNC_ATTR_NONNULL_ALL { + nlua_exec_file((const char *)eap->arg); +} + +/// execute lua code from a file. +/// +/// @param path path of the file +/// +/// @return true if everything ok, false if there was an error (echoed) +bool nlua_exec_file(const char *path) + FUNC_ATTR_NONNULL_ALL +{ lua_State *const lstate = nlua_enter(); - if (luaL_loadfile(lstate, (const char *)eap->arg)) { + if (luaL_loadfile(lstate, path)) { nlua_error(lstate, _("E5112: Error while creating lua chunk: %.*s")); - return; + return false; } if (lua_pcall(lstate, 0, 0, 0)) { nlua_error(lstate, _("E5113: Error while calling lua chunk: %.*s")); - return; + return false; } + + return true; } static void nlua_add_treesitter(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL diff --git a/src/nvim/main.c b/src/nvim/main.c index 63249416b1..79c165419e 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -1069,9 +1069,14 @@ static void command_line_scan(mparm_T *parmp) } else { a = argv[0]; } - size_t s_size = STRLEN(a) + 4; + + size_t s_size = STRLEN(a) + 9; char *s = xmalloc(s_size); - snprintf(s, s_size, "so %s", a); + if (path_with_extension(a, "lua")) { + snprintf(s, s_size, "luafile %s", a); + } else { + snprintf(s, s_size, "so %s", a); + } parmp->cmds_tofree[parmp->n_commands] = true; parmp->commands[parmp->n_commands++] = s; } else { @@ -1770,6 +1775,23 @@ static bool do_user_initialization(void) do_exrc = p_exrc; return do_exrc; } + + char_u *init_lua_path = (char_u *)stdpaths_user_conf_subpath("init.lua"); + if (os_path_exists(init_lua_path) + && nlua_exec_file((const char *)init_lua_path)) { + os_setenv("MYVIMRC", (const char *)init_lua_path, 1); + char_u *vimrc_path = (char_u *)stdpaths_user_conf_subpath("init.vim"); + + if (os_path_exists(vimrc_path)) { + EMSG3(_("Conflicting configs: \"%s\" \"%s\""), init_lua_path, vimrc_path); + } + + xfree(vimrc_path); + xfree(init_lua_path); + return false; + } + xfree(init_lua_path); + char_u *user_vimrc = (char_u *)stdpaths_user_conf_subpath("init.vim"); if (do_source(user_vimrc, true, DOSO_VIMRC) != FAIL) { do_exrc = p_exrc; @@ -1829,8 +1851,12 @@ static void source_startup_scripts(const mparm_T *const parmp) || strequal(parmp->use_vimrc, "NORC")) { // Do nothing. } else { - if (do_source((char_u *)parmp->use_vimrc, false, DOSO_NONE) != OK) { - EMSG2(_("E282: Cannot read from \"%s\""), parmp->use_vimrc); + if (path_with_extension(parmp->use_vimrc, "lua")) { + nlua_exec_file(parmp->use_vimrc); + } else { + if (do_source((char_u *)parmp->use_vimrc, false, DOSO_NONE) != OK) { + EMSG2(_("E282: Cannot read from \"%s\""), parmp->use_vimrc); + } } } } else if (!silent_mode) { diff --git a/src/nvim/message.c b/src/nvim/message.c index f76a408481..ad38e6d060 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -1711,8 +1711,11 @@ void msg_prt_line(char_u *s, int list) } else if ((l = utfc_ptr2len(s)) > 1) { col += utf_ptr2cells(s); char buf[MB_MAXBYTES + 1]; - if (curwin->w_p_lcs_chars.nbsp != NUL && list - && (utf_ptr2char(s) == 160 || utf_ptr2char(s) == 0x202f)) { + if (l >= MB_MAXBYTES) { + xstrlcpy(buf, "¿", sizeof(buf)); + } else if (curwin->w_p_lcs_chars.nbsp != NUL && list + && (utf_ptr2char(s) == 160 + || utf_ptr2char(s) == 0x202f)) { utf_char2bytes(curwin->w_p_lcs_chars.nbsp, (char_u *)buf); buf[utfc_ptr2len((char_u *)buf)] = NUL; } else { diff --git a/src/nvim/option.c b/src/nvim/option.c index 0034117ddc..acca6fe681 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -352,9 +352,6 @@ void set_init_1(bool clean_arg) langmap_init(); - // Be nocompatible - p_cp = false; - /* * Find default value for 'shell' option. * Don't use it if it is empty. @@ -683,7 +680,7 @@ set_options_default( { for (int i = 0; options[i].fullname; i++) { if (!(options[i].flags & P_NODEFAULT)) { - set_option_default(i, opt_flags, p_cp); + set_option_default(i, opt_flags, false); } } @@ -763,7 +760,7 @@ void set_init_2(bool headless) // which results in the actual value computed from the window height. idx = findoption("scroll"); if (idx >= 0 && !(options[idx].flags & P_WAS_SET)) { - set_option_default(idx, OPT_LOCAL, p_cp); + set_option_default(idx, OPT_LOCAL, false); } comp_col(); @@ -1113,7 +1110,7 @@ int do_set( if (vim_strchr((char_u *)"?=:!&<", nextchar) != NULL) { arg += len; - cp_val = p_cp; + cp_val = false; if (nextchar == '&' && arg[1] == 'v' && arg[2] == 'i') { if (arg[3] == 'm') { // "opt&vim": set to Vim default cp_val = false; @@ -3617,10 +3614,14 @@ static void set_option_sctx_idx(int opt_idx, int opt_flags, sctx_T script_ctx) { int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0; int indir = (int)options[opt_idx].indir; - const LastSet last_set = { .script_ctx = - { script_ctx.sc_sid, script_ctx.sc_seq, - script_ctx.sc_lnum + sourcing_lnum }, - current_channel_id }; + const LastSet last_set = { + .script_ctx = { + script_ctx.sc_sid, + script_ctx.sc_seq, + script_ctx.sc_lnum + sourcing_lnum + }, + current_channel_id + }; // Remember where the option was set. For local options need to do that // in the buffer or window structure. @@ -4950,7 +4951,7 @@ static int optval_default(vimoption_T *p, char_u *varp) if (varp == NULL) { return true; // hidden option is always at default } - dvi = ((p->flags & P_VI_DEF) || p_cp) ? VI_DEFAULT : VIM_DEFAULT; + dvi = (p->flags & P_VI_DEF) ? VI_DEFAULT : VIM_DEFAULT; if (p->flags & P_NUM) { return *(long *)varp == (long)(intptr_t)p->def_val[dvi]; } @@ -7174,3 +7175,75 @@ long get_sidescrolloff_value(void) { return curwin->w_p_siso < 0 ? p_siso : curwin->w_p_siso; } + +Dictionary get_vimoption(String name, Error *err) +{ + int opt_idx = findoption_len((const char *)name.data, name.size); + if (opt_idx < 0) { + api_set_error(err, kErrorTypeValidation, "no such option: '%s'", name.data); + return (Dictionary)ARRAY_DICT_INIT; + } + return vimoption2dict(&options[opt_idx]); +} + +Dictionary get_all_vimoptions(void) +{ + Dictionary retval = ARRAY_DICT_INIT; + for (size_t i = 0; i < PARAM_COUNT; i++) { + Dictionary opt_dict = vimoption2dict(&options[i]); + PUT(retval, options[i].fullname, DICTIONARY_OBJ(opt_dict)); + } + return retval; +} + +static Dictionary vimoption2dict(vimoption_T *opt) +{ + Dictionary dict = ARRAY_DICT_INIT; + + PUT(dict, "name", CSTR_TO_OBJ(opt->fullname)); + PUT(dict, "shortname", CSTR_TO_OBJ(opt->shortname)); + + const char *scope; + if (opt->indir & PV_BUF) { + scope = "buf"; + } else if (opt->indir & PV_WIN) { + scope = "win"; + } else { + scope = "global"; + } + + PUT(dict, "scope", CSTR_TO_OBJ(scope)); + + // welcome to the jungle + PUT(dict, "global_local", BOOL(opt->indir & PV_BOTH)); + PUT(dict, "commalist", BOOL(opt->flags & P_COMMA)); + PUT(dict, "flaglist", BOOL(opt->flags & P_FLAGLIST)); + + PUT(dict, "was_set", BOOL(opt->flags & P_WAS_SET)); + + PUT(dict, "last_set_sid", INTEGER_OBJ(opt->last_set.script_ctx.sc_sid)); + PUT(dict, "last_set_linenr", INTEGER_OBJ(opt->last_set.script_ctx.sc_lnum)); + PUT(dict, "last_set_chan", INTEGER_OBJ((int64_t)opt->last_set.channel_id)); + + const char *type; + Object def; + // TODO(bfredl): do you even nocp? + char_u *def_val = opt->def_val[(opt->flags & P_VI_DEF) + ? VI_DEFAULT : VIM_DEFAULT]; + if (opt->flags & P_STRING) { + type = "string"; + def = CSTR_TO_OBJ(def_val ? (char *)def_val : ""); + } else if (opt->flags & P_NUM) { + type = "number"; + def = INTEGER_OBJ((Integer)(intptr_t)def_val); + } else if (opt->flags & P_BOOL) { + type = "boolean"; + def = BOOL((intptr_t)def_val); + } else { + type = ""; def = NIL; + } + PUT(dict, "type", CSTR_TO_OBJ(type)); + PUT(dict, "default", def); + + return dict; +} diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index af0ea7f4a2..ec2160d365 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -372,7 +372,6 @@ EXTERN long p_cwh; // 'cmdwinheight' EXTERN long p_ch; // 'cmdheight' EXTERN long p_columns; // 'columns' EXTERN int p_confirm; // 'confirm' -EXTERN int p_cp; // 'compatible' EXTERN char_u *p_cot; // 'completeopt' # ifdef BACKSLASH_IN_FILENAME EXTERN char_u *p_csl; // 'completeslash' diff --git a/src/nvim/path.c b/src/nvim/path.c index f52fbbd5c8..2de7e00ddb 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -1704,6 +1704,13 @@ int path_with_url(const char *fname) return path_is_url(p); } +bool path_with_extension(const char *path, const char *extension) +{ + const char *last_dot = strrchr(path, '.'); + if (!last_dot) { return false; } + return strcmp(last_dot + 1, extension) == 0; +} + /* * Return TRUE if "name" is a full (absolute) path name or URL. */ diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 3d7d587ed2..7fdc998e20 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -6155,7 +6155,7 @@ static int qf_setprop_items_from_lines( qf_free_items(&qi->qf_lists[qf_idx]); } if (qf_init_ext(qi, qf_idx, NULL, NULL, &di->di_tv, errorformat, - false, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0) { + false, (linenr_T)0, (linenr_T)0, NULL, NULL) >= 0) { retval = OK; } @@ -6256,9 +6256,12 @@ static int qf_set_properties(qf_info_T *qi, const dict_T *what, int action, retval = qf_setprop_curidx(qi, qfl, di); } - if (retval == OK) { + if (newlist || retval == OK) { qf_list_changed(qfl); } + if (newlist) { + qf_update_buffer(qi, NULL); + } return retval; } diff --git a/src/nvim/search.c b/src/nvim/search.c index 90e1e25de2..787a464070 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -89,7 +89,7 @@ static struct spat spats[2] = static int last_idx = 0; /* index in spats[] for RE_LAST */ static char_u lastc[2] = { NUL, NUL }; // last character searched for -static int lastcdir = FORWARD; // last direction of character search +static Direction lastcdir = FORWARD; // last direction of character search static int last_t_cmd = true; // last search t_cmd static char_u lastc_bytes[MB_MAXBYTES + 1]; static int lastc_bytelen = 1; // >1 for multi-byte char @@ -437,7 +437,7 @@ void set_last_csearch(int c, char_u *s, int len) memset(lastc_bytes, 0, sizeof(lastc_bytes)); } -void set_csearch_direction(int cdir) +void set_csearch_direction(Direction cdir) { lastcdir = cdir; } @@ -1430,7 +1430,7 @@ end_do_search: * ADDING is set. If p_ic is set then the pattern must be in lowercase. * Return OK for success, or FAIL if no line found. */ -int search_for_exact_line(buf_T *buf, pos_T *pos, int dir, char_u *pat) +int search_for_exact_line(buf_T *buf, pos_T *pos, Direction dir, char_u *pat) { linenr_T start = 0; char_u *ptr; @@ -1496,10 +1496,11 @@ int search_for_exact_line(buf_T *buf, pos_T *pos, int dir, char_u *pat) * Return FAIL or OK. */ int searchc(cmdarg_T *cap, int t_cmd) + FUNC_ATTR_NONNULL_ALL { - int c = cap->nchar; /* char to search for */ - int dir = cap->arg; /* TRUE for searching forward */ - long count = cap->count1; /* repeat count */ + int c = cap->nchar; // char to search for + Direction dir = cap->arg; // TRUE for searching forward + long count = cap->count1; // repeat count int col; char_u *p; int len; @@ -4462,7 +4463,7 @@ static void search_stat(int dirc, pos_T *pos, void find_pattern_in_path( char_u *ptr, // pointer to search pattern - int dir, // direction of expansion + Direction dir, // direction of expansion size_t len, // length of search pattern bool whole, // match whole words only bool skip_comments, // don't match inside comments diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 797fe41320..5714f5e425 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -79,7 +79,6 @@ /* for offsetof() */ #include <stddef.h> -#include "nvim/vim.h" #include "nvim/ascii.h" #include "nvim/spell.h" #include "nvim/buffer.h" @@ -6653,7 +6652,7 @@ void spell_dump_compl ( char_u *pat, // leading part of the word int ic, // ignore case - int *dir, // direction for adding matches + Direction *dir, // direction for adding matches int dumpflags_arg // DUMPFLAG_* ) { @@ -6820,7 +6819,9 @@ spell_dump_compl ( // Dumps one word: apply case modifications and append a line to the buffer. // When "lnum" is zero add insert mode completion. -static void dump_word(slang_T *slang, char_u *word, char_u *pat, int *dir, int dumpflags, int wordflags, linenr_T lnum) +static void dump_word(slang_T *slang, char_u *word, char_u *pat, + Direction *dir, int dumpflags, int wordflags, + linenr_T lnum) { bool keepcap = false; char_u *p; @@ -6906,7 +6907,7 @@ dump_prefixes ( slang_T *slang, char_u *word, // case-folded word char_u *pat, - int *dir, + Direction *dir, int dumpflags, int flags, // flags with prefix ID linenr_T startlnum diff --git a/src/nvim/spell.h b/src/nvim/spell.h index ad66df4c5d..e93c82b91d 100644 --- a/src/nvim/spell.h +++ b/src/nvim/spell.h @@ -6,6 +6,7 @@ #include "nvim/spell_defs.h" #include "nvim/ex_cmds_defs.h" #include "nvim/globals.h" +#include "nvim/vim.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "spell.h.generated.h" diff --git a/src/nvim/testdir/test49.vim b/src/nvim/testdir/test49.vim index c86fdf25ab..5468f7c4aa 100644 --- a/src/nvim/testdir/test49.vim +++ b/src/nvim/testdir/test49.vim @@ -318,7 +318,7 @@ let ExtraVimCount = 0 let ExtraVimBase = expand("<sfile>") let ExtraVimTestEnv = "" " -function! ExtraVim(...) +function ExtraVim(...) " Count how often this function is called. let g:ExtraVimCount = g:ExtraVimCount + 1 @@ -500,7 +500,7 @@ endfunction " an ExtraVim script as passed by ExtraVim() in ExtraVimBegin. " " EXTRA_VIM_START - do not change or remove this line. -function! ExtraVimThrowpoint() +function ExtraVimThrowpoint() if !exists("g:ExtraVimBegin") Xout "ExtraVimThrowpoint() used outside ExtraVim() script." return v:throwpoint @@ -530,7 +530,7 @@ endfunction " as a script file, use ExecAsScript below. " " EXTRA_VIM_START - do not change or remove this line. -function! MakeScript(funcname, ...) +function MakeScript(funcname, ...) let script = tempname() execute "redir! >" . script execute "function" a:funcname @@ -568,7 +568,7 @@ endfunction " location specified in the function. " " EXTRA_VIM_START - do not change or remove this line. -function! ExecAsScript(funcname) +function ExecAsScript(funcname) " Make a script from the function passed as argument. let script = MakeScript(a:funcname) @@ -3694,7 +3694,7 @@ endif if ExtraVim(msgfile) try Xpath 4194304 " X: 4194304 - let x = novar " error E121/E15; exception: E121 + let x = novar " error E121; exception: E121 catch /E15:/ " should not catch Xpath 8388608 " X: 0 endtry @@ -3702,7 +3702,7 @@ if ExtraVim(msgfile) endif Xpath 33554432 " X: 33554432 -if !MESSAGES('E121', "Undefined variable", 'E15', "Invalid expression") +if !MESSAGES('E121', "Undefined variable") Xpath 67108864 " X: 0 endif @@ -8548,7 +8548,7 @@ endfunction " Remove the autocommands for the events specified as arguments in all used " autogroups. -function! Delete_autocommands(...) +function Delete_autocommands(...) let augfile = tempname() while 1 try diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim index 7647475427..4f056abdc0 100644 --- a/src/nvim/testdir/test_alot.vim +++ b/src/nvim/testdir/test_alot.vim @@ -1,7 +1,6 @@ " A series of tests that can run in one Vim invocation. " This makes testing go faster, since Vim doesn't need to restart. -source test_assign.vim source test_backup.vim source test_behave.vim source test_cd.vim diff --git a/src/nvim/testdir/test_assign.vim b/src/nvim/testdir/test_assign.vim deleted file mode 100644 index 50415ad6fd..0000000000 --- a/src/nvim/testdir/test_assign.vim +++ /dev/null @@ -1,47 +0,0 @@ -" Test for assignment - -func Test_no_type_checking() - let v = 1 - let v = [1,2,3] - let v = {'a': 1, 'b': 2} - let v = 3.4 - let v = 'hello' -endfunc - -func Test_let_termcap() - " Nvim does not support `:set termcap`. - return - " Terminal code - let old_t_te = &t_te - let &t_te = "\<Esc>[yes;" - call assert_match('t_te.*^[[yes;', execute("set termcap")) - let &t_te = old_t_te - - if exists("+t_k1") - " Key code - let old_t_k1 = &t_k1 - let &t_k1 = "that" - call assert_match('t_k1.*that', execute("set termcap")) - let &t_k1 = old_t_k1 - endif - - call assert_fails('let x = &t_xx', 'E15') - let &t_xx = "yes" - call assert_equal("yes", &t_xx) - let &t_xx = "" - call assert_fails('let x = &t_xx', 'E15') -endfunc - -func Test_let_option_error() - let _w = &tw - let &tw = 80 - call assert_fails('let &tw .= 1', 'E734') - call assert_equal(80, &tw) - let &tw = _w - - let _w = &fillchars - let &fillchars = "vert:|" - call assert_fails('let &fillchars += "diff:-"', 'E734') - call assert_equal("vert:|", &fillchars) - let &fillchars = _w -endfunc diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index 1fa7eeaea0..641e98ab30 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -1359,7 +1359,7 @@ func Test_ChangedP() endfunc let g:setline_handled = v:false -func! SetLineOne() +func SetLineOne() if !g:setline_handled call setline(1, "(x)") let g:setline_handled = v:true diff --git a/src/nvim/testdir/test_charsearch.vim b/src/nvim/testdir/test_charsearch.vim index 8b313b5a35..17a49e02be 100644 --- a/src/nvim/testdir/test_charsearch.vim +++ b/src/nvim/testdir/test_charsearch.vim @@ -1,5 +1,5 @@ -function! Test_charsearch() +func Test_charsearch() enew! call append(0, ['Xabcdefghijkemnopqretuvwxyz', \ 'Yabcdefghijkemnopqretuvwxyz', @@ -29,10 +29,10 @@ function! Test_charsearch() normal! ;;p call assert_equal('ZabcdeZfghijkZZemnokqretkZvwxyz', getline(3)) enew! -endfunction +endfunc " Test for t,f,F,T movement commands and 'cpo-;' setting -function! Test_search_cmds() +func Test_search_cmds() enew! call append(0, ["aaa two three four", " zzz", "yyy ", \ "bbb yee yoo four", "ccc two three four", @@ -59,4 +59,4 @@ function! Test_search_cmds() call assert_equal('ccc', getline(5)) call assert_equal('ddd yee y', getline(6)) enew! -endfunction +endfunc diff --git a/src/nvim/testdir/test_charsearch_utf8.vim b/src/nvim/testdir/test_charsearch_utf8.vim index eac5d46ad8..09341a90b0 100644 --- a/src/nvim/testdir/test_charsearch_utf8.vim +++ b/src/nvim/testdir/test_charsearch_utf8.vim @@ -14,6 +14,6 @@ function! Test_search_cmds() normal! , call assert_equal([0, 1, 28, 0], getpos('.')) bw! -endfunction +endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_edit.vim b/src/nvim/testdir/test_edit.vim index abad6983dc..e1393e875b 100644 --- a/src/nvim/testdir/test_edit.vim +++ b/src/nvim/testdir/test_edit.vim @@ -11,7 +11,7 @@ source view_util.vim " Needs to come first until the bug in getchar() is " fixed: https://groups.google.com/d/msg/vim_dev/fXL9yme4H4c/bOR-U6_bAQAJ -func! Test_edit_00b() +func Test_edit_00b() new call setline(1, ['abc ']) inoreabbr <buffer> h here some more @@ -23,7 +23,7 @@ func! Test_edit_00b() bw! endfunc -func! Test_edit_01() +func Test_edit_01() " set for Travis CI? " set nocp noesckeys new @@ -61,7 +61,7 @@ func! Test_edit_01() bw! endfunc -func! Test_edit_02() +func Test_edit_02() " Change cursor position in InsertCharPre command new call setline(1, 'abc') @@ -101,7 +101,7 @@ func! Test_edit_02() bw! endfunc -func! Test_edit_03() +func Test_edit_03() " Change cursor after <c-o> command to end of line new call setline(1, 'abc') @@ -120,7 +120,7 @@ func! Test_edit_03() bw! endfunc -func! Test_edit_04() +func Test_edit_04() " test for :stopinsert new call setline(1, 'abc') @@ -132,7 +132,7 @@ func! Test_edit_04() bw! endfunc -func! Test_edit_05() +func Test_edit_05() " test for folds being opened new call setline(1, ['abcX', 'abcX', 'zzzZ']) @@ -154,7 +154,7 @@ func! Test_edit_05() bw! endfunc -func! Test_edit_06() +func Test_edit_06() " Test in diff mode if !has("diff") || !executable("diff") return @@ -176,7 +176,7 @@ func! Test_edit_06() bw! endfunc -func! Test_edit_07() +func Test_edit_07() " 1) Test with completion <c-l> when popupmenu is visible new call setline(1, 'J') @@ -228,7 +228,7 @@ func! Test_edit_08() unlet g:bufnr endfunc -func! Test_edit_09() +func Test_edit_09() " test i_CTRL-\ combinations new call setline(1, ['abc', 'def', 'ghi']) @@ -258,7 +258,7 @@ func! Test_edit_09() bw! endfunc -func! Test_edit_10() +func Test_edit_10() " Test for starting selectmode new set selectmode=key keymodel=startsel @@ -270,7 +270,7 @@ func! Test_edit_10() bw! endfunc -func! Test_edit_11() +func Test_edit_11() " Test that indenting kicks in new set cindent @@ -314,7 +314,7 @@ func! Test_edit_11() bw! endfunc -func! Test_edit_11_indentexpr() +func Test_edit_11_indentexpr() " Test that indenting kicks in new " Use indentexpr instead of cindenting @@ -341,7 +341,7 @@ func! Test_edit_11_indentexpr() bw! endfunc -func! Test_edit_12() +func Test_edit_12() " Test changing indent in replace mode new call setline(1, ["\tabc", "\tdef"]) @@ -393,7 +393,7 @@ func! Test_edit_12() bw! endfunc -func! Test_edit_13() +func Test_edit_13() " Test smartindenting if exists("+smartindent") new @@ -481,7 +481,7 @@ func! Test_edit_CTRL_() endfunc " needs to come first, to have the @. register empty -func! Test_edit_00a_CTRL_A() +func Test_edit_00a_CTRL_A() " Test pressing CTRL-A new call setline(1, repeat([''], 5)) @@ -501,7 +501,7 @@ func! Test_edit_00a_CTRL_A() bw! endfunc -func! Test_edit_CTRL_EY() +func Test_edit_CTRL_EY() " Ctrl-E/ Ctrl-Y in insert mode completion to scroll 10new call setline(1, range(1, 100)) @@ -517,7 +517,7 @@ func! Test_edit_CTRL_EY() bw! endfunc -func! Test_edit_CTRL_G() +func Test_edit_CTRL_G() new call setline(1, ['foobar', 'foobar', 'foobar']) call cursor(2, 4) @@ -535,7 +535,7 @@ func! Test_edit_CTRL_G() bw! endfunc -func! Test_edit_CTRL_I() +func Test_edit_CTRL_I() " Tab in completion mode let path=expand("%:p:h") new @@ -559,7 +559,7 @@ func! Test_edit_CTRL_I() bw! endfunc -func! Test_edit_CTRL_K() +func Test_edit_CTRL_K() " Test pressing CTRL-K (basically only dictionary completion and digraphs " the rest is already covered call writefile(['A', 'AA', 'AAA', 'AAAA'], 'Xdictionary.txt') @@ -632,7 +632,7 @@ func! Test_edit_CTRL_K() bw! endfunc -func! Test_edit_CTRL_L() +func Test_edit_CTRL_L() " Test Ctrl-X Ctrl-L (line completion) new set complete=. @@ -688,7 +688,7 @@ func! Test_edit_CTRL_L() bw! endfunc -func! Test_edit_CTRL_N() +func Test_edit_CTRL_N() " Check keyword completion new set complete=. @@ -709,7 +709,7 @@ func! Test_edit_CTRL_N() bw! endfunc -func! Test_edit_CTRL_O() +func Test_edit_CTRL_O() " Check for CTRL-O in insert mode new inoreabbr <buffer> h here some more @@ -749,7 +749,7 @@ func! Test_edit_CTRL_R() bw! endfunc -func! Test_edit_CTRL_S() +func Test_edit_CTRL_S() " Test pressing CTRL-S (basically only spellfile completion) " the rest is already covered new @@ -793,7 +793,7 @@ func! Test_edit_CTRL_S() bw! endfunc -func! Test_edit_CTRL_T() +func Test_edit_CTRL_T() " Check for CTRL-T and CTRL-X CTRL-T in insert mode " 1) increase indent new @@ -870,7 +870,7 @@ func! Test_edit_CTRL_T() bw! endfunc -func! Test_edit_CTRL_U() +func Test_edit_CTRL_U() " Test 'completefunc' new " -1, -2 and -3 are special return values @@ -929,7 +929,7 @@ func! Test_edit_CTRL_U() bw! endfunc -func! Test_edit_CTRL_Z() +func Test_edit_CTRL_Z() " Ctrl-Z when insertmode is not set inserts it literally new call setline(1, 'abc') @@ -939,7 +939,7 @@ func! Test_edit_CTRL_Z() " TODO: How to Test Ctrl-Z in insert mode, e.g. suspend? endfunc -func! Test_edit_DROP() +func Test_edit_DROP() if !has("dnd") return endif @@ -955,7 +955,7 @@ func! Test_edit_DROP() bw! endfunc -func! Test_edit_CTRL_V() +func Test_edit_CTRL_V() if has("ebcdic") return endif @@ -983,7 +983,7 @@ func! Test_edit_CTRL_V() bw! endfunc -func! Test_edit_F1() +func Test_edit_F1() " Pressing <f1> new call feedkeys(":set im\<cr>\<f1>\<c-l>", 'tnix') @@ -993,7 +993,7 @@ func! Test_edit_F1() bw endfunc -func! Test_edit_F21() +func Test_edit_F21() " Pressing <f21> " sends a netbeans command if has("netbeans_intg") @@ -1004,7 +1004,7 @@ func! Test_edit_F21() endif endfunc -func! Test_edit_HOME_END() +func Test_edit_HOME_END() " Test Home/End Keys new set foldopen+=hor @@ -1019,7 +1019,7 @@ func! Test_edit_HOME_END() bw! endfunc -func! Test_edit_INS() +func Test_edit_INS() " Test for Pressing <Insert> new call setline(1, ['abc', 'def']) @@ -1033,7 +1033,7 @@ func! Test_edit_INS() bw! endfunc -func! Test_edit_LEFT_RIGHT() +func Test_edit_LEFT_RIGHT() " Left, Shift-Left, Right, Shift-Right new call setline(1, ['abc def ghi', 'ABC DEF GHI', 'ZZZ YYY XXX']) @@ -1080,7 +1080,7 @@ func! Test_edit_LEFT_RIGHT() bw! endfunc -func! Test_edit_MOUSE() +func Test_edit_MOUSE() " This is a simple test, since we not really using the mouse here if !has("mouse") return @@ -1135,7 +1135,7 @@ func! Test_edit_MOUSE() bw! endfunc -func! Test_edit_PAGEUP_PAGEDOWN() +func Test_edit_PAGEUP_PAGEDOWN() 10new call setline(1, repeat(['abc def ghi'], 30)) call cursor(1, 1) @@ -1234,7 +1234,7 @@ func! Test_edit_PAGEUP_PAGEDOWN() bw! endfunc -func! Test_edit_forbidden() +func Test_edit_forbidden() new " 1) edit in the sandbox is not allowed call setline(1, 'a') @@ -1294,7 +1294,7 @@ func! Test_edit_forbidden() bw! endfunc -func! Test_edit_rightleft() +func Test_edit_rightleft() " Cursor in rightleft mode moves differently if !exists("+rightleft") return diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim index 52b5884c8b..f3c3e085f6 100644 --- a/src/nvim/testdir/test_filetype.vim +++ b/src/nvim/testdir/test_filetype.vim @@ -471,7 +471,6 @@ let s:filename_checks = { \ 'tssgm': ['file.tssgm'], \ 'tssop': ['file.tssop'], \ 'twig': ['file.twig'], - \ 'typescript': ['file.ts'], \ 'typescriptreact': ['file.tsx'], \ 'uc': ['file.uc'], \ 'udevconf': ['/etc/udev/udev.conf'], @@ -668,5 +667,22 @@ func Test_hook_file() filetype off endfunc +func Test_ts_file() + filetype on + + call writefile(['<?xml version="1.0" encoding="utf-8"?>'], 'Xfile.ts') + split Xfile.ts + call assert_equal('xml', &filetype) + bwipe! + + call writefile(['// looks like Typescript'], 'Xfile.ts') + split Xfile.ts + call assert_equal('typescript', &filetype) + bwipe! + + call delete('Xfile.hook') + filetype off +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_fnameescape.vim b/src/nvim/testdir/test_fnameescape.vim index cdff0dfbd9..5382b89aa6 100644 --- a/src/nvim/testdir/test_fnameescape.vim +++ b/src/nvim/testdir/test_fnameescape.vim @@ -1,6 +1,6 @@ " Test if fnameescape is correct for special chars like ! -function! Test_fnameescape() +func Test_fnameescape() let fname = 'Xspa ce' let status = v:false try @@ -18,4 +18,4 @@ function! Test_fnameescape() endtry call assert_true(status, "ExclamationMark") call delete(fname) -endfunction +endfunc diff --git a/src/nvim/testdir/test_getcwd.vim b/src/nvim/testdir/test_getcwd.vim index 5d97295e9a..ca098781e4 100644 --- a/src/nvim/testdir/test_getcwd.vim +++ b/src/nvim/testdir/test_getcwd.vim @@ -1,112 +1,112 @@ -function! GetCwdInfo(win, tab) - let tab_changed = 0 - let mod = ":t" - if a:tab > 0 && a:tab != tabpagenr() - let tab_changed = 1 - exec "tabnext " . a:tab - endif - let bufname = fnamemodify(bufname(winbufnr(a:win)), mod) - if tab_changed - tabprevious - endif - if a:win == 0 && a:tab == 0 - let dirname = fnamemodify(getcwd(), mod) - let lflag = haslocaldir() - elseif a:tab == 0 - let dirname = fnamemodify(getcwd(a:win), mod) - let lflag = haslocaldir(a:win) - else - let dirname = fnamemodify(getcwd(a:win, a:tab), mod) - let lflag = haslocaldir(a:win, a:tab) - endif - return bufname . ' ' . dirname . ' ' . lflag -endfunction +func GetCwdInfo(win, tab) + let tab_changed = 0 + let mod = ":t" + if a:tab > 0 && a:tab != tabpagenr() + let tab_changed = 1 + exec "tabnext " . a:tab + endif + let bufname = fnamemodify(bufname(winbufnr(a:win)), mod) + if tab_changed + tabprevious + endif + if a:win == 0 && a:tab == 0 + let dirname = fnamemodify(getcwd(), mod) + let lflag = haslocaldir() + elseif a:tab == 0 + let dirname = fnamemodify(getcwd(a:win), mod) + let lflag = haslocaldir(a:win) + else + let dirname = fnamemodify(getcwd(a:win, a:tab), mod) + let lflag = haslocaldir(a:win, a:tab) + endif + return bufname . ' ' . dirname . ' ' . lflag +endfunc " Do all test in a separate window to avoid E211 when we recursively " delete the Xtopdir directory during cleanup function SetUp() - set visualbell - set nocp viminfo+=nviminfo + set visualbell + set nocp viminfo+=nviminfo - " On windows a swapfile in Xtopdir prevents it from being cleaned up. - set noswapfile + " On windows a swapfile in Xtopdir prevents it from being cleaned up. + set noswapfile - " On windows a stale "Xtopdir" directory may exist, remove it so that - " we start from a clean state. - call delete("Xtopdir", "rf") - new - call mkdir('Xtopdir') - cd Xtopdir - let g:topdir = getcwd() - call mkdir('Xdir1') - call mkdir('Xdir2') - call mkdir('Xdir3') + " On windows a stale "Xtopdir" directory may exist, remove it so that + " we start from a clean state. + call delete("Xtopdir", "rf") + new + call mkdir('Xtopdir') + cd Xtopdir + let g:topdir = getcwd() + call mkdir('Xdir1') + call mkdir('Xdir2') + call mkdir('Xdir3') endfunction let g:cwd=getcwd() function TearDown() - q - exec "cd " . g:cwd - call delete("Xtopdir", "rf") + q + exec "cd " . g:cwd + call delete("Xtopdir", "rf") endfunction function Test_GetCwd() - new a - new b - new c - 3wincmd w - lcd Xdir1 - call assert_equal("a Xdir1 1", GetCwdInfo(0, 0)) - call assert_equal(g:topdir, getcwd(-1)) - wincmd W - call assert_equal("b Xtopdir 0", GetCwdInfo(0, 0)) - call assert_equal(g:topdir, getcwd(-1)) - wincmd W - lcd Xdir3 - call assert_equal("c Xdir3 1", GetCwdInfo(0, 0)) - call assert_equal("a Xdir1 1", GetCwdInfo(bufwinnr("a"), 0)) - call assert_equal("b Xtopdir 0", GetCwdInfo(bufwinnr("b"), 0)) - call assert_equal("c Xdir3 1", GetCwdInfo(bufwinnr("c"), 0)) - call assert_equal(g:topdir, getcwd(-1)) - wincmd W - call assert_equal("a Xdir1 1", GetCwdInfo(bufwinnr("a"), tabpagenr())) - call assert_equal("b Xtopdir 0", GetCwdInfo(bufwinnr("b"), tabpagenr())) - call assert_equal("c Xdir3 1", GetCwdInfo(bufwinnr("c"), tabpagenr())) - call assert_equal(g:topdir, getcwd(-1)) + new a + new b + new c + 3wincmd w + lcd Xdir1 + call assert_equal("a Xdir1 1", GetCwdInfo(0, 0)) + call assert_equal(g:topdir, getcwd(-1)) + wincmd W + call assert_equal("b Xtopdir 0", GetCwdInfo(0, 0)) + call assert_equal(g:topdir, getcwd(-1)) + wincmd W + lcd Xdir3 + call assert_equal("c Xdir3 1", GetCwdInfo(0, 0)) + call assert_equal("a Xdir1 1", GetCwdInfo(bufwinnr("a"), 0)) + call assert_equal("b Xtopdir 0", GetCwdInfo(bufwinnr("b"), 0)) + call assert_equal("c Xdir3 1", GetCwdInfo(bufwinnr("c"), 0)) + call assert_equal(g:topdir, getcwd(-1)) + wincmd W + call assert_equal("a Xdir1 1", GetCwdInfo(bufwinnr("a"), tabpagenr())) + call assert_equal("b Xtopdir 0", GetCwdInfo(bufwinnr("b"), tabpagenr())) + call assert_equal("c Xdir3 1", GetCwdInfo(bufwinnr("c"), tabpagenr())) + call assert_equal(g:topdir, getcwd(-1)) - tabnew x - new y - new z - 3wincmd w - call assert_equal("x Xtopdir 0", GetCwdInfo(0, 0)) - call assert_equal(g:topdir, getcwd(-1)) - wincmd W - lcd Xdir2 - call assert_equal("y Xdir2 1", GetCwdInfo(0, 0)) - call assert_equal(g:topdir, getcwd(-1)) - wincmd W - lcd Xdir3 - call assert_equal("z Xdir3 1", GetCwdInfo(0, 0)) - call assert_equal("x Xtopdir 0", GetCwdInfo(bufwinnr("x"), 0)) - call assert_equal("y Xdir2 1", GetCwdInfo(bufwinnr("y"), 0)) - call assert_equal("z Xdir3 1", GetCwdInfo(bufwinnr("z"), 0)) - call assert_equal(g:topdir, getcwd(-1)) - let tp_nr = tabpagenr() - tabrewind - call assert_equal("x Xtopdir 0", GetCwdInfo(3, tp_nr)) - call assert_equal("y Xdir2 1", GetCwdInfo(2, tp_nr)) - call assert_equal("z Xdir3 1", GetCwdInfo(1, tp_nr)) - call assert_equal(g:topdir, getcwd(-1)) + tabnew x + new y + new z + 3wincmd w + call assert_equal("x Xtopdir 0", GetCwdInfo(0, 0)) + call assert_equal(g:topdir, getcwd(-1)) + wincmd W + lcd Xdir2 + call assert_equal("y Xdir2 1", GetCwdInfo(0, 0)) + call assert_equal(g:topdir, getcwd(-1)) + wincmd W + lcd Xdir3 + call assert_equal("z Xdir3 1", GetCwdInfo(0, 0)) + call assert_equal("x Xtopdir 0", GetCwdInfo(bufwinnr("x"), 0)) + call assert_equal("y Xdir2 1", GetCwdInfo(bufwinnr("y"), 0)) + call assert_equal("z Xdir3 1", GetCwdInfo(bufwinnr("z"), 0)) + call assert_equal(g:topdir, getcwd(-1)) + let tp_nr = tabpagenr() + tabrewind + call assert_equal("x Xtopdir 0", GetCwdInfo(3, tp_nr)) + call assert_equal("y Xdir2 1", GetCwdInfo(2, tp_nr)) + call assert_equal("z Xdir3 1", GetCwdInfo(1, tp_nr)) + call assert_equal(g:topdir, getcwd(-1)) endfunc function Test_GetCwd_lcd_shellslash() - new - let root = fnamemodify('/', ':p') - exe 'lcd '.root - let cwd = getcwd() - if !exists('+shellslash') || &shellslash - call assert_equal(cwd[-1:], '/') - else - call assert_equal(cwd[-1:], '\') - endif + new + let root = fnamemodify('/', ':p') + exe 'lcd '.root + let cwd = getcwd() + if !exists('+shellslash') || &shellslash + call assert_equal(cwd[-1:], '/') + else + call assert_equal(cwd[-1:], '\') + endif endfunc diff --git a/src/nvim/testdir/test_highlight.vim b/src/nvim/testdir/test_highlight.vim index a80a73161f..8f6834c2ab 100644 --- a/src/nvim/testdir/test_highlight.vim +++ b/src/nvim/testdir/test_highlight.vim @@ -39,15 +39,15 @@ func Test_highlight() call assert_fails("hi Crash term='asdf", "E475:") endfunc -function! HighlightArgs(name) +func HighlightArgs(name) return 'hi ' . substitute(split(execute('hi ' . a:name), '\n')[0], '\<xxx\>', '', '') -endfunction +endfunc -function! IsColorable() +func IsColorable() return has('gui_running') || str2nr(&t_Co) >= 8 -endfunction +endfunc -function! HiCursorLine() +func HiCursorLine() let hiCursorLine = HighlightArgs('CursorLine') if has('gui_running') let guibg = matchstr(hiCursorLine, 'guibg=\w\+') @@ -58,9 +58,9 @@ function! HiCursorLine() let hi_bg = 'hi CursorLine cterm=NONE ctermbg=Gray' endif return [hiCursorLine, hi_ul, hi_bg] -endfunction +endfunc -function! Check_lcs_eol_attrs(attrs, row, col) +func Check_lcs_eol_attrs(attrs, row, col) let save_lcs = &lcs set list @@ -68,7 +68,7 @@ function! Check_lcs_eol_attrs(attrs, row, col) set nolist let &lcs = save_lcs -endfunction +endfunc func Test_highlight_eol_with_cursorline() let [hiCursorLine, hi_ul, hi_bg] = HiCursorLine() diff --git a/src/nvim/testdir/test_hlsearch.vim b/src/nvim/testdir/test_hlsearch.vim index 97f6ae7b51..cf2791113a 100644 --- a/src/nvim/testdir/test_hlsearch.vim +++ b/src/nvim/testdir/test_hlsearch.vim @@ -1,6 +1,6 @@ " Test for v:hlsearch -function! Test_hlsearch() +func Test_hlsearch() new call setline(1, repeat(['aaa'], 10)) set hlsearch nolazyredraw @@ -30,7 +30,7 @@ function! Test_hlsearch() call garbagecollect(1) call getchar(1) enew! -endfunction +endfunc func Test_hlsearch_hangs() if !has('reltime') || !has('float') diff --git a/src/nvim/testdir/test_ins_complete.vim b/src/nvim/testdir/test_ins_complete.vim index 57a0a7aaf4..6fe1d29434 100644 --- a/src/nvim/testdir/test_ins_complete.vim +++ b/src/nvim/testdir/test_ins_complete.vim @@ -312,6 +312,24 @@ func Test_completefunc_args() delfunc CompleteFunc endfunc +func CompleteTest(findstart, query) + if a:findstart + return col('.') + endif + return ['matched'] +endfunc + +func Test_completefunc_info() + new + set completeopt=menuone + set completefunc=CompleteTest + call feedkeys("i\<C-X>\<C-U>\<C-R>\<C-R>=string(complete_info())\<CR>\<ESC>", "tx") + call assert_equal("matched{'pum_visible': 1, 'mode': 'function', 'selected': 0, 'items': [{'word': 'matched', 'menu': '', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''}]}", getline(1)) + bwipe! + set completeopt& + set completefunc& +endfunc + " Check that when using feedkeys() typeahead does not interrupt searching for " completions. func Test_compl_feedkeys() diff --git a/src/nvim/testdir/test_let.vim b/src/nvim/testdir/test_let.vim index 0b9331ee38..a5cbd8f6a6 100644 --- a/src/nvim/testdir/test_let.vim +++ b/src/nvim/testdir/test_let.vim @@ -150,6 +150,59 @@ func Test_let_utf8_environment() call assert_equal('ĀĒĪŌŪあいうえお', $a) endfunc +func Test_let_no_type_checking() + let v = 1 + let v = [1,2,3] + let v = {'a': 1, 'b': 2} + let v = 3.4 + let v = 'hello' +endfunc + +func Test_let_termcap() + throw 'skipped: Nvim does not support termcap option' + " Terminal code + let old_t_te = &t_te + let &t_te = "\<Esc>[yes;" + call assert_match('t_te.*^[[yes;', execute("set termcap")) + let &t_te = old_t_te + + if exists("+t_k1") + " Key code + let old_t_k1 = &t_k1 + let &t_k1 = "that" + call assert_match('t_k1.*that', execute("set termcap")) + let &t_k1 = old_t_k1 + endif + + call assert_fails('let x = &t_xx', 'E113') + let &t_xx = "yes" + call assert_equal("yes", &t_xx) + let &t_xx = "" + call assert_fails('let x = &t_xx', 'E113') +endfunc + +func Test_let_option_error() + let _w = &tw + let &tw = 80 + call assert_fails('let &tw .= 1', 'E734') + call assert_equal(80, &tw) + let &tw = _w + + let _w = &fillchars + let &fillchars = "vert:|" + call assert_fails('let &fillchars += "diff:-"', 'E734') + call assert_equal("vert:|", &fillchars) + let &fillchars = _w +endfunc + +func Test_let_errors() + let s = 'abcd' + call assert_fails('let s[1] = 5', 'E689:') + + let l = [1, 2, 3] + call assert_fails('let l[:] = 5', 'E709:') +endfunc + func Test_let_heredoc_fails() call assert_fails('let v =<< marker', 'E991:') diff --git a/src/nvim/testdir/test_listlbr.vim b/src/nvim/testdir/test_listlbr.vim index cdc5e4cc7c..d619ac0eb5 100644 --- a/src/nvim/testdir/test_listlbr.vim +++ b/src/nvim/testdir/test_listlbr.vim @@ -16,9 +16,9 @@ function s:screen_lines(lnum, width) abort return ScreenLines(a:lnum, a:width) endfunction -function! s:compare_lines(expect, actual) +func s:compare_lines(expect, actual) call assert_equal(join(a:expect, "\n"), join(a:actual, "\n")) -endfunction +endfunc function s:test_windows(...) call NewWindow(10, 20) diff --git a/src/nvim/testdir/test_listlbr_utf8.vim b/src/nvim/testdir/test_listlbr_utf8.vim index b648a3361b..c38e0c5f3c 100644 --- a/src/nvim/testdir/test_listlbr_utf8.vim +++ b/src/nvim/testdir/test_listlbr_utf8.vim @@ -9,15 +9,15 @@ endif source view_util.vim -function s:screen_lines(lnum, width) abort +func s:screen_lines(lnum, width) abort return ScreenLines(a:lnum, a:width) -endfunction +endfunc -function! s:compare_lines(expect, actual) +func s:compare_lines(expect, actual) call assert_equal(a:expect, a:actual) -endfunction +endfunc -function s:screen_attr(lnum, chars, ...) abort +func s:screen_attr(lnum, chars, ...) abort let line = getline(a:lnum) let attr = [] let prefix = get(a:000, 0, 0) @@ -26,18 +26,18 @@ function s:screen_attr(lnum, chars, ...) abort let attr += [screenattr(a:lnum, scol + prefix)] endfor return attr -endfunction +endfunc -function s:test_windows(...) +func s:test_windows(...) call NewWindow(10, 20) setl ts=4 sw=4 sts=4 linebreak sbr=+ wrap exe get(a:000, 0, '') -endfunction +endfunc -function s:close_windows(...) +func s:close_windows(...) call CloseWindow() exe get(a:000, 0, '') -endfunction +endfunc func Test_linebreak_with_fancy_listchars() call s:test_windows("setl list listchars=nbsp:\u2423,tab:\u2595\u2014,trail:\u02d1,eol:\ub6") diff --git a/src/nvim/testdir/test_matchadd_conceal.vim b/src/nvim/testdir/test_matchadd_conceal.vim index 393e183ddb..f9e40a9b43 100644 --- a/src/nvim/testdir/test_matchadd_conceal.vim +++ b/src/nvim/testdir/test_matchadd_conceal.vim @@ -27,9 +27,9 @@ function! Test_simple_matchadd() call assert_equal(screenattr(lnum, 1), screenattr(lnum, 16)) quit! -endfunction +endfunc -function! Test_simple_matchadd_and_conceal() +func Test_simple_matchadd_and_conceal() new setlocal concealcursor=n conceallevel=1 @@ -49,9 +49,9 @@ function! Test_simple_matchadd_and_conceal() call assert_equal(screenattr(lnum, 1), screenattr(lnum, 16)) quit! -endfunction +endfunc -function! Test_matchadd_and_conceallevel_3() +func Test_matchadd_and_conceallevel_3() new setlocal conceallevel=3 @@ -90,9 +90,9 @@ function! Test_matchadd_and_conceallevel_3() syntax off quit! -endfunction +endfunc -function! Test_default_conceal_char() +func Test_default_conceal_char() new setlocal concealcursor=n conceallevel=1 @@ -126,9 +126,9 @@ function! Test_default_conceal_char() let &listchars = listchars_save quit! -endfunction +endfunc -function! Test_syn_and_match_conceal() +func Test_syn_and_match_conceal() new setlocal concealcursor=n conceallevel=1 @@ -162,9 +162,9 @@ function! Test_syn_and_match_conceal() syntax off quit! -endfunction +endfunc -function! Test_clearmatches() +func Test_clearmatches() new setlocal concealcursor=n conceallevel=1 @@ -201,9 +201,9 @@ function! Test_clearmatches() call assert_equal({'group': 'Conceal', 'pattern': '\%2l ', 'priority': 10, 'id': a[0].id, 'conceal': 'Z'}, a[0]) quit! -endfunction +endfunc -function! Test_using_matchaddpos() +func Test_using_matchaddpos() new setlocal concealcursor=n conceallevel=1 " set filetype and :syntax on to change screenattr() @@ -232,9 +232,9 @@ function! Test_using_matchaddpos() syntax off quit! -endfunction +endfunc -function! Test_matchadd_repeat_conceal_with_syntax_off() +func Test_matchadd_repeat_conceal_with_syntax_off() new " To test targets in the same line string is replaced with conceal char @@ -251,9 +251,9 @@ function! Test_matchadd_repeat_conceal_with_syntax_off() call assert_equal('t_tt', Screenline(2)) quit! -endfunction +endfunc -function! Test_matchadd_and_syn_conceal() +func Test_matchadd_and_syn_conceal() new let cnt='Inductive bool : Type := | true : bool | false : bool.' let expect = 'Inductive - : Type := | true : - | false : -.' diff --git a/src/nvim/testdir/test_matchadd_conceal_utf8.vim b/src/nvim/testdir/test_matchadd_conceal_utf8.vim index 160d0598a1..34c8c49dd5 100644 --- a/src/nvim/testdir/test_matchadd_conceal_utf8.vim +++ b/src/nvim/testdir/test_matchadd_conceal_utf8.vim @@ -36,4 +36,4 @@ function! Test_match_using_multibyte_conceal_char() call assert_equal(screenattr(lnum, 1), screenattr(lnum, 16)) quit! -endfunction +endfunc diff --git a/src/nvim/testdir/test_number.vim b/src/nvim/testdir/test_number.vim index 3c9afc41d5..81326bce14 100644 --- a/src/nvim/testdir/test_number.vim +++ b/src/nvim/testdir/test_number.vim @@ -2,23 +2,23 @@ source view_util.vim -func! s:screen_lines(start, end) abort +func s:screen_lines(start, end) abort return ScreenLines([a:start, a:end], 8) endfunc -func! s:compare_lines(expect, actual) +func s:compare_lines(expect, actual) call assert_equal(a:expect, a:actual) endfunc -func! s:test_windows(h, w) abort +func s:test_windows(h, w) abort call NewWindow(a:h, a:w) endfunc -func! s:close_windows() abort +func s:close_windows() abort call CloseWindow() endfunc -func! s:validate_cursor() abort +func s:validate_cursor() abort " update skipcol. " wincol(): " f_wincol diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim index 10e16f4198..15c1836c9a 100644 --- a/src/nvim/testdir/test_options.vim +++ b/src/nvim/testdir/test_options.vim @@ -1,6 +1,6 @@ " Test for options -function! Test_whichwrap() +func Test_whichwrap() set whichwrap=b,s call assert_equal('b,s', &whichwrap) diff --git a/src/nvim/testdir/test_partial.vim b/src/nvim/testdir/test_partial.vim index 590e18e024..52aac05ea1 100644 --- a/src/nvim/testdir/test_partial.vim +++ b/src/nvim/testdir/test_partial.vim @@ -113,9 +113,9 @@ func Test_function_in_dict() call OuterCall() endfunc -function! s:cache_clear() dict +func s:cache_clear() dict return self.name -endfunction +endfunc func Test_script_function_in_dict() let s:obj = {'name': 'foo'} @@ -135,10 +135,10 @@ func Test_script_function_in_dict() call assert_equal('bar', B()) endfunc -function! s:cache_arg(arg) dict +func s:cache_arg(arg) dict let s:result = self.name . '/' . a:arg return s:result -endfunction +endfunc func Test_script_function_in_dict_arg() let s:obj = {'name': 'foo'} diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index 5c84e45a79..e06c4f59da 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -4485,4 +4485,62 @@ func Test_quickfix_window_fails_to_open() call delete('XquickfixFails') endfunc +" Test for updating the quickfix buffer whenever the assocaited quickfix list +" is changed. +func Xqfbuf_update(cchar) + call s:setup_commands(a:cchar) + + Xexpr "F1:1:line1" + Xopen + call assert_equal(['F1|1| line1'], getline(1, '$')) + call assert_equal(1, g:Xgetlist({'changedtick' : 0}).changedtick) + + " Test setqflist() using the 'lines' key in 'what' + " add a new entry + call g:Xsetlist([], 'a', {'lines' : ['F2:2: line2']}) + call assert_equal(['F1|1| line1', 'F2|2| line2'], getline(1, '$')) + call assert_equal(2, g:Xgetlist({'changedtick' : 0}).changedtick) + " replace all the entries with a single entry + call g:Xsetlist([], 'r', {'lines' : ['F3:3: line3']}) + call assert_equal(['F3|3| line3'], getline(1, '$')) + call assert_equal(3, g:Xgetlist({'changedtick' : 0}).changedtick) + " remove all the entries + call g:Xsetlist([], 'r', {'lines' : []}) + call assert_equal([''], getline(1, '$')) + call assert_equal(4, g:Xgetlist({'changedtick' : 0}).changedtick) + " add a new list + call g:Xsetlist([], ' ', {'lines' : ['F4:4: line4']}) + call assert_equal(['F4|4| line4'], getline(1, '$')) + call assert_equal(1, g:Xgetlist({'changedtick' : 0}).changedtick) + + " Test setqflist() using the 'items' key in 'what' + " add a new entry + call g:Xsetlist([], 'a', {'items' : [{'filename' : 'F5', 'lnum' : 5, 'text' : 'line5'}]}) + call assert_equal(['F4|4| line4', 'F5|5| line5'], getline(1, '$')) + call assert_equal(2, g:Xgetlist({'changedtick' : 0}).changedtick) + " replace all the entries with a single entry + call g:Xsetlist([], 'r', {'items' : [{'filename' : 'F6', 'lnum' : 6, 'text' : 'line6'}]}) + call assert_equal(['F6|6| line6'], getline(1, '$')) + call assert_equal(3, g:Xgetlist({'changedtick' : 0}).changedtick) + " remove all the entries + call g:Xsetlist([], 'r', {'items' : []}) + call assert_equal([''], getline(1, '$')) + call assert_equal(4, g:Xgetlist({'changedtick' : 0}).changedtick) + " add a new list + call g:Xsetlist([], ' ', {'items' : [{'filename' : 'F7', 'lnum' : 7, 'text' : 'line7'}]}) + call assert_equal(['F7|7| line7'], getline(1, '$')) + call assert_equal(1, g:Xgetlist({'changedtick' : 0}).changedtick) + + call g:Xsetlist([], ' ', {}) + call assert_equal([''], getline(1, '$')) + call assert_equal(1, g:Xgetlist({'changedtick' : 0}).changedtick) + + Xclose +endfunc + +func Test_qfbuf_update() + call Xqfbuf_update('c') + call Xqfbuf_update('l') +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_smartindent.vim b/src/nvim/testdir/test_smartindent.vim index 9e93a55eb0..e89ad19d34 100644 --- a/src/nvim/testdir/test_smartindent.vim +++ b/src/nvim/testdir/test_smartindent.vim @@ -1,24 +1,24 @@ " Tests for smartindent " Tests for not doing smart indenting when it isn't set. -function! Test_nosmartindent() +func Test_nosmartindent() new call append(0, [" some test text", - \ " test text", - \ "test text", - \ " test text"]) + \ " test text", + \ "test text", + \ " test text"]) set nocindent nosmartindent autoindent exe "normal! gg/some\<CR>" exe "normal! 2cc#test\<Esc>" call assert_equal(" #test", getline(1)) enew! | close -endfunction +endfunc -function MyIndent() -endfunction +func MyIndent() +endfunc " When 'indentexpr' is set, setting 'si' has no effect. -function Test_smartindent_has_no_effect() +func Test_smartindent_has_no_effect() new exe "normal! i\<Tab>one\<Esc>" set noautoindent @@ -36,6 +36,6 @@ function Test_smartindent_has_no_effect() set smartindent& set indentexpr& bwipe! -endfunction +endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_substitute.vim b/src/nvim/testdir/test_substitute.vim index ff07d8eceb..2a27f7a3a1 100644 --- a/src/nvim/testdir/test_substitute.vim +++ b/src/nvim/testdir/test_substitute.vim @@ -1,6 +1,6 @@ " Tests for multi-line regexps with ":s". -function! Test_multiline_subst() +func Test_multiline_subst() enew! call append(0, ["1 aa", \ "bb", @@ -38,9 +38,9 @@ function! Test_multiline_subst() call assert_equal('7x7f', getline(12)) call assert_equal('xxxxx', getline(13)) enew! -endfunction +endfunc -function! Test_substitute_variants() +func Test_substitute_variants() " Validate that all the 2-/3-letter variants which embed the flags into the " command name actually work. enew! @@ -248,9 +248,9 @@ func Test_sub_cmd_4() " List entry format: [input, cmd, output] let tests = [ ['aAa', "s/A/\\=substitute(submatch(0), '.', '\\', '')/", - \ ['a\a']], + \ ['a\a']], \ ['bBb', "s/B/\\=substitute(submatch(0), '.', '\\', '')/", - \ ['b\b']], + \ ['b\b']], \ ['cCc', "s/C/\\=substitute(submatch(0), '.', '\<C-V>\<C-M>', '')/", \ ["c\<C-V>", 'c']], \ ['dDd', "s/D/\\=substitute(submatch(0), '.', '\\\<C-V>\<C-M>', '')/", diff --git a/src/nvim/testdir/test_textobjects.vim b/src/nvim/testdir/test_textobjects.vim index f70cc1f70a..9b800d0fa9 100644 --- a/src/nvim/testdir/test_textobjects.vim +++ b/src/nvim/testdir/test_textobjects.vim @@ -301,7 +301,7 @@ func Test_sentence_with_quotes() %delete _ endfunc -func! Test_sentence_with_cursor_on_delimiter() +func Test_sentence_with_cursor_on_delimiter() enew! call setline(1, "A '([sentence.])' A sentence.") diff --git a/src/nvim/testdir/test_utf8.vim b/src/nvim/testdir/test_utf8.vim index 1b4ce4c4af..e8161f8fcb 100644 --- a/src/nvim/testdir/test_utf8.vim +++ b/src/nvim/testdir/test_utf8.vim @@ -22,17 +22,17 @@ func Test_strchars() endfunc " Test for customlist completion -function! CustomComplete1(lead, line, pos) +func CustomComplete1(lead, line, pos) return ['あ', 'い'] -endfunction +endfunc -function! CustomComplete2(lead, line, pos) +func CustomComplete2(lead, line, pos) return ['あたし', 'あたま', 'あたりめ'] -endfunction +endfunc -function! CustomComplete3(lead, line, pos) +func CustomComplete3(lead, line, pos) return ['Nこ', 'Nん', 'Nぶ'] -endfunction +endfunc func Test_customlist_completion() command -nargs=1 -complete=customlist,CustomComplete1 Test1 echo @@ -103,3 +103,14 @@ func Test_list2str_str2list_latin1() call assert_equal(l, lres) call assert_equal(s, sres) endfunc + +func Test_print_overlong() + " Text with more composing characters than MB_MAXBYTES. + new + call setline(1, 'axxxxxxxxxxxxxxxxxxxxxxxxxxxxxx') + s/x/\=nr2char(1629)/g + print + bwipe! +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_utf8_comparisons.vim b/src/nvim/testdir/test_utf8_comparisons.vim index 1fc670aafd..fdf9d80802 100644 --- a/src/nvim/testdir/test_utf8_comparisons.vim +++ b/src/nvim/testdir/test_utf8_comparisons.vim @@ -29,26 +29,26 @@ function! Chk(a, b, result) call Ch(a:a, '<?', a:b, 1) call Ch(a:a, '>?', a:b, 0) endif -endfunction +endfunc -function! Check(a, b, result) +func Check(a, b, result) call Chk(a:a, a:b, a:result) call Chk(a:b, a:a, -a:result) -endfunction +endfunc -function! LT(a, b) +func LT(a, b) call Check(a:a, a:b, -1) -endfunction +endfunc -function! GT(a, b) +func GT(a, b) call Check(a:a, a:b, 1) -endfunction +endfunc -function! EQ(a, b) +func EQ(a, b) call Check(a:a, a:b, 0) -endfunction +endfunc -function Test_comparisons() +func Test_comparisons() call EQ('', '') call LT('', 'a') call EQ('abc', 'abc') @@ -81,11 +81,11 @@ function Test_comparisons() for n in range(0xC0, 0xFF) call LT(printf('xYz\xc2\x%.2XUvW', n), printf('XyZ\xc2\x%.2XuVw', n)) endfor -endfunction +endfunc " test that g~ap changes one paragraph only. -function Test_gap() +func Test_gap() new call feedkeys("iabcd\n\ndefggg0g~ap", "tx") call assert_equal(["ABCD", "", "defg"], getline(1,3)) -endfunction +endfunc diff --git a/src/nvim/testdir/test_vimscript.vim b/src/nvim/testdir/test_vimscript.vim index 118a5dab2b..4edf8308e7 100644 --- a/src/nvim/testdir/test_vimscript.vim +++ b/src/nvim/testdir/test_vimscript.vim @@ -5,11 +5,11 @@ " Test environment {{{1 "------------------------------------------------------------------------------- -com! XpathINIT let g:Xpath = '' +com! XpathINIT let g:Xpath = '' com! -nargs=1 -bar Xpath let g:Xpath = g:Xpath . <args> " Append a message to the "messages" file -func! Xout(text) +func Xout(text) split messages $put =a:text wq @@ -50,7 +50,7 @@ function! MakeScript(funcname, ...) write bwipeout return script -endfunction +endfunc " ExecAsScript - Source a temporary script made from a function. {{{2 " @@ -301,9 +301,9 @@ XpathINIT " let calls = "" com! -nargs=1 CALL - \ if !exists("calls") && !exists("outer") | - \ let g:calls = g:calls . <args> | - \ endif + \ if !exists("calls") && !exists("outer") | + \ let g:calls = g:calls . <args> | + \ endif let i = 0 while i < 3 @@ -357,7 +357,7 @@ endif if exists("*F1") call F1("F1") if exists("*G1") - call G1("G1") + call G1("G1") endif endif @@ -367,13 +367,13 @@ endif if exists("*F2") call F2(2, "F2") if exists("*G21") - call G21("G21") + call G21("G21") endif if exists("*G22") - call G22("G22") + call G22("G22") endif if exists("*G23") - call G23("G23") + call G23("G23") endif endif @@ -383,13 +383,13 @@ endif if exists("*F3") call F3(3, "F3") if exists("*G31") - call G31("G31") + call G31("G31") endif if exists("*G32") - call G32("G32") + call G32("G32") endif if exists("*G33") - call G33("G33") + call G33("G33") endif endif @@ -640,7 +640,7 @@ function! MSG(enr, emsg) endif endif return match -endfunction +endfunc if 1 || strlen("\"") | Xpath 'a' Xpath 'b' @@ -1099,70 +1099,70 @@ endfunction func Test_script_lines() " :append try - call DefineFunction('T_Append', [ - \ 'append', - \ 'py <<EOS', - \ '.', - \ ]) + call DefineFunction('T_Append', [ + \ 'append', + \ 'py <<EOS', + \ '.', + \ ]) catch - call assert_report("Can't define function") + call assert_report("Can't define function") endtry try - call DefineFunction('T_Append', [ - \ 'append', - \ 'abc', - \ ]) - call assert_report("Shouldn't be able to define function") + call DefineFunction('T_Append', [ + \ 'append', + \ 'abc', + \ ]) + call assert_report("Shouldn't be able to define function") catch - call assert_exception('Vim(function):E126: Missing :endfunction') + call assert_exception('Vim(function):E126: Missing :endfunction') endtry " :change try - call DefineFunction('T_Change', [ - \ 'change', - \ 'py <<EOS', - \ '.', - \ ]) + call DefineFunction('T_Change', [ + \ 'change', + \ 'py <<EOS', + \ '.', + \ ]) catch - call assert_report("Can't define function") + call assert_report("Can't define function") endtry try - call DefineFunction('T_Change', [ - \ 'change', - \ 'abc', - \ ]) - call assert_report("Shouldn't be able to define function") + call DefineFunction('T_Change', [ + \ 'change', + \ 'abc', + \ ]) + call assert_report("Shouldn't be able to define function") catch - call assert_exception('Vim(function):E126: Missing :endfunction') + call assert_exception('Vim(function):E126: Missing :endfunction') endtry " :insert try - call DefineFunction('T_Insert', [ - \ 'insert', - \ 'py <<EOS', - \ '.', - \ ]) + call DefineFunction('T_Insert', [ + \ 'insert', + \ 'py <<EOS', + \ '.', + \ ]) catch - call assert_report("Can't define function") + call assert_report("Can't define function") endtry try - call DefineFunction('T_Insert', [ - \ 'insert', - \ 'abc', - \ ]) - call assert_report("Shouldn't be able to define function") + call DefineFunction('T_Insert', [ + \ 'insert', + \ 'abc', + \ ]) + call assert_report("Shouldn't be able to define function") catch - call assert_exception('Vim(function):E126: Missing :endfunction') + call assert_exception('Vim(function):E126: Missing :endfunction') endtry endfunc "------------------------------------------------------------------------------- " Test 96: line continuation {{{1 " -" Undefined behavior was detected by ubsan with line continuation -" after an empty line. +" Undefined behavior was detected by ubsan with line continuation +" after an empty line. "------------------------------------------------------------------------------- func Test_script_emty_line_continuation() @@ -1393,6 +1393,20 @@ func Test_compound_assignment_operators() let @/ = '' endfunc +func Test_unlet_env() + let $TESTVAR = 'yes' + call assert_equal('yes', $TESTVAR) + call assert_fails('lockvar $TESTVAR', 'E940') + call assert_fails('unlockvar $TESTVAR', 'E940') + call assert_equal('yes', $TESTVAR) + if 0 + unlet $TESTVAR + endif + call assert_equal('yes', $TESTVAR) + unlet $TESTVAR + call assert_equal('', $TESTVAR) +endfunc + func Test_funccall_garbage_collect() func Func(x, ...) call add(a:x, a:000) diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index eb5fd7eca7..c42d5c34cc 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -1921,4 +1921,79 @@ describe('API', function() eq({}, meths.get_runtime_file("foobarlang/", true)) end) end) + + describe('nvim_get_all_options_info', function() + it('should have key value pairs of option names', function() + local options_info = meths.get_all_options_info() + neq(nil, options_info.listchars) + neq(nil, options_info.tabstop) + + eq(meths.get_option_info'winhighlight', options_info.winhighlight) + end) + end) + + describe('nvim_get_option_info', function() + it('should error for unknown options', function() + eq("no such option: 'bogus'", pcall_err(meths.get_option_info, 'bogus')) + end) + + it('should return the same options for short and long name', function() + eq(meths.get_option_info'winhl', meths.get_option_info'winhighlight') + end) + + it('should have information about window options', function() + eq({ + commalist = false; + default = ""; + flaglist = false; + global_local = false; + last_set_chan = 0; + last_set_linenr = 0; + last_set_sid = 0; + name = "winhighlight"; + scope = "win"; + shortname = "winhl"; + type = "string"; + was_set = false; + }, meths.get_option_info'winhl') + end) + + it('should have information about buffer options', function() + eq({ + commalist = false, + default = "", + flaglist = false, + global_local = false, + last_set_chan = 0, + last_set_linenr = 0, + last_set_sid = 0, + name = "filetype", + scope = "buf", + shortname = "ft", + type = "string", + was_set = false + }, meths.get_option_info'filetype') + end) + + it('should have information about global options', function() + -- precondition: the option was changed from its default + -- in test setup. + eq(false, meths.get_option'showcmd') + + eq({ + commalist = false, + default = true, + flaglist = false, + global_local = false, + last_set_chan = 0, + last_set_linenr = 0, + last_set_sid = -2, + name = "showcmd", + scope = "global", + shortname = "sc", + type = "boolean", + was_set = true + }, meths.get_option_info'showcmd') + end) + end) end) diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua index 27793ab936..ff0fdbea45 100644 --- a/test/functional/core/startup_spec.lua +++ b/test/functional/core/startup_spec.lua @@ -432,3 +432,88 @@ describe('clean', function() clear('--clean') ok(string.match(meths.get_option('runtimepath'), funcs.stdpath('config')) == nil) end) + +describe('user config init', function() + local xhome = 'Xhome' + local pathsep = helpers.get_pathsep() + local xconfig = xhome .. pathsep .. 'Xconfig' + local init_lua_path = table.concat({xconfig, 'nvim', 'init.lua'}, pathsep) + + before_each(function() + rmdir(xhome) + + -- TODO, make mkdir_p helper + mkdir(xhome) + mkdir(xconfig) + mkdir(xconfig .. pathsep .. 'nvim') + + write_file(init_lua_path, [[ + vim.g.lua_rc = 1 + ]]) + end) + + after_each(function() + rmdir(xhome) + end) + + it('loads init.lua from XDG config home by default', function() + clear{ args_rm={'-u' }, env={ XDG_CONFIG_HOME=xconfig }} + + eq(1, eval('g:lua_rc')) + eq(init_lua_path, eval('$MYVIMRC')) + end) + + describe 'with explicitly provided config'(function() + local custom_lua_path = table.concat({xhome, 'custom.lua'}, pathsep) + before_each(function() + write_file(custom_lua_path, [[ + vim.g.custom_lua_rc = 1 + ]]) + end) + + it('loads custom lua config and does not set $MYVIMRC', function() + clear{ args={'-u', custom_lua_path }, env={ XDG_CONFIG_HOME=xconfig }} + eq(1, eval('g:custom_lua_rc')) + eq('', eval('$MYVIMRC')) + end) + end) + + describe 'VIMRC also exists'(function() + before_each(function() + write_file(table.concat({xconfig, 'nvim', 'init.vim'}, pathsep), [[ + let g:vim_rc = 1 + ]]) + end) + + it('loads default lua config, but shows an error', function() + clear{ args_rm={'-u'}, env={ XDG_CONFIG_HOME=xconfig }} + feed('<cr>') -- TODO check this, test execution is blocked without it + eq(1, eval('g:lua_rc')) + matches('Conflicting configs', meths.exec('messages', true)) + end) + end) +end) + +describe('user session', function() + local xhome = 'Xhome' + local pathsep = helpers.get_pathsep() + local session_file = table.concat({xhome, 'session.lua'}, pathsep) + + before_each(function() + rmdir(xhome) + + mkdir(xhome) + write_file(session_file, [[ + vim.g.lua_session = 1 + ]]) + end) + + after_each(function() + rmdir(xhome) + end) + + it('loads session from the provided lua file', function() + clear{ args={'-S', session_file }, env={ HOME=xhome }} + eq(1, eval('g:lua_session')) + end) +end) diff --git a/test/functional/eval/timer_spec.lua b/test/functional/eval/timer_spec.lua index ef7df69fdb..9ee0735e40 100644 --- a/test/functional/eval/timer_spec.lua +++ b/test/functional/eval/timer_spec.lua @@ -215,8 +215,8 @@ describe('timers', function() endfunc ]]) command("call timer_start(5, 'MyHandler', {'repeat': 1})") - run(nil, nil, nil, load_adjust(10)) - retry(nil, load_adjust(100), function() + run(nil, nil, nil, load_adjust(20)) + retry(nil, load_adjust(150), function() eq(1, eval("g:val")) end) end) diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index d85a6a3cfe..0829560b9c 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -442,6 +442,7 @@ function module.new_argv(...) 'NVIM_LOG_FILE', 'NVIM_RPLUGIN_MANIFEST', 'GCOV_ERROR_FILE', + 'XDG_DATA_DIRS', 'TMPDIR', }) do if not env_tbl[k] then diff --git a/test/functional/plugin/lsp/diagnostic_spec.lua b/test/functional/plugin/lsp/diagnostic_spec.lua index 11b2beba7a..3a676359ab 100644 --- a/test/functional/plugin/lsp/diagnostic_spec.lua +++ b/test/functional/plugin/lsp/diagnostic_spec.lua @@ -68,20 +68,23 @@ describe('vim.lsp.diagnostic', function() describe('vim.lsp.diagnostic', function() describe('handle_publish_diagnostics', function() it('should be able to retrieve diagnostics from all buffers and clients', function() - eq(3, exec_lua [[ + local result = exec_lua [[ vim.lsp.diagnostic.save( { make_error('Diagnostic #1', 1, 1, 1, 1), make_error('Diagnostic #2', 2, 1, 2, 1), - }, 0, 1 + }, 1, 1 ) vim.lsp.diagnostic.save( { make_error('Diagnostic #3', 3, 1, 3, 1), - }, 1, 2 + }, 2, 2 ) - return #vim.lsp.diagnostic.get_all() - ]]) + return vim.lsp.diagnostic.get_all() + ]] + eq(2, #result) + eq(2, #result[1]) + eq('Diagnostic #1', result[1][1].message) end) it('should be able to save and count a single client error', function() eq(1, exec_lua [[ @@ -153,7 +156,6 @@ describe('vim.lsp.diagnostic', function() } ]]) end) - it('should handle one server clearing highlights while the other still has highlights', function() -- 1 Error (1) -- 1 Warning (2) diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 5b048f57e9..f01d90bbeb 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -323,23 +323,61 @@ describe('LSP', function() test_name = "capabilities_for_client_supports_method"; on_setup = function() exec_lua([=[ - vim.lsp.handlers['textDocument/hover'] = function(err, method) + BUFFER = vim.api.nvim_get_current_buf() + lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID) + vim.lsp.callbacks['textDocument/typeDefinition'] = function(err, method) vim.lsp._last_lsp_callback = { err = err; method = method } end vim.lsp._unsupported_method = function(method) vim.lsp._last_unsupported_method = method return 'fake-error' end - vim.lsp.buf.hover() + vim.lsp.buf.type_definition() ]=]) end; on_init = function(client) client.stop() local method = exec_lua("return vim.lsp._last_unsupported_method") - eq("textDocument/hover", method) + eq("textDocument/typeDefinition", method) local lsp_cb_call = exec_lua("return vim.lsp._last_lsp_callback") eq("fake-error", lsp_cb_call.err) - eq("textDocument/hover", lsp_cb_call.method) + eq("textDocument/typeDefinition", lsp_cb_call.method) + exec_lua [[ + vim.api.nvim_command(BUFFER.."bwipeout") + ]] + end; + on_exit = function(code, signal) + eq(0, code, "exit code", fake_lsp_logfile) + eq(0, signal, "exit signal", fake_lsp_logfile) + end; + on_callback = function(...) + eq(table.remove(expected_callbacks), {...}, "expected callback") + end; + } + end) + + it('shouldn\'t call unsupported_method when no client and trying to call an unsupported method', function() + local expected_callbacks = { + {NIL, "shutdown", {}, 1}; + } + test_rpc_server { + test_name = "capabilities_for_client_supports_method"; + on_setup = function() + exec_lua([=[ + vim.lsp.callbacks['textDocument/typeDefinition'] = function(err, method) + vim.lsp._last_lsp_callback = { err = err; method = method } + end + vim.lsp._unsupported_method = function(method) + vim.lsp._last_unsupported_method = method + return 'fake-error' + end + vim.lsp.buf.type_definition() + ]=]) + end; + on_init = function(client) + client.stop() + eq(NIL, exec_lua("return vim.lsp._last_unsupported_method")) + eq(NIL, exec_lua("return vim.lsp._last_lsp_callback")) end; on_exit = function(code, signal) eq(0, code, "exit code", fake_lsp_logfile) diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua index 8e171d31aa..209537831f 100644 --- a/test/functional/terminal/buffer_spec.lua +++ b/test/functional/terminal/buffer_spec.lua @@ -6,6 +6,7 @@ local eval, feed_command, source = helpers.eval, helpers.feed_command, helpers.s local eq, neq = helpers.eq, helpers.neq local write_file = helpers.write_file local command= helpers.command +local exc_exec = helpers.exc_exec describe(':terminal buffer', function() local screen @@ -253,6 +254,10 @@ describe(':terminal buffer', function() ]]) command('bdelete!') end) + + it('handles wqall', function() + eq('Vim(wqall):E948: Job still running', exc_exec('wqall')) + end) end) describe('No heap-buffer-overflow when using', function() diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua index 77fdba7fc4..b932c58430 100644 --- a/test/functional/terminal/scrollback_spec.lua +++ b/test/functional/terminal/scrollback_spec.lua @@ -410,6 +410,7 @@ describe("'scrollback' option", function() command([[let $PROMPT='$$']]) screen = thelpers.screen_setup(nil, "['cmd.exe']", 30) else + command('let $PS1 = "$"') screen = thelpers.screen_setup(nil, "['sh']", 30) end diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua index 99ebc4971e..65c6fabfa8 100644 --- a/test/functional/ui/wildmode_spec.lua +++ b/test/functional/ui/wildmode_spec.lua @@ -3,6 +3,7 @@ local Screen = require('test.functional.ui.screen') local clear, feed, command = helpers.clear, helpers.feed, helpers.command local iswin = helpers.iswin local funcs = helpers.funcs +local meths = helpers.meths local eq = helpers.eq local eval = helpers.eval local retry = helpers.retry @@ -160,6 +161,7 @@ describe("'wildmenu'", function() if not iswin() then command('set shell=sh') -- Need a predictable "$" prompt. + command('let $PS1 = "$"') end command('set laststatus=0') command('vsplit') @@ -396,6 +398,64 @@ describe("'wildmenu'", function() | ]]) end) + + it('works with c_CTRL_Z standard mapping', function() + screen:set_default_attr_ids { + [1] = {bold = true, foreground = Screen.colors.Blue1}; + [2] = {foreground = Screen.colors.Grey0, background = Screen.colors.Yellow}; + [3] = {bold = true, reverse = true}; + } + + -- Wildcharm? where we are going we aint't no need no wildcharm. + eq(0, meths.get_option'wildcharm') + -- Don't mess the defaults yet (neovim is about backwards compatibility) + eq(9, meths.get_option'wildchar') + -- Lol what is cnoremap? Some say it can define mappings. + command 'set wildchar=0' + eq(0, meths.get_option'wildchar') + + command 'cnoremap <f2> <c-z>' + feed(':syntax <f2>') + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {2:case}{3: clear cluster > }| + :syntax case^ | + ]]} + feed '<esc>' + + command 'set wildmode=longest:full,full' + -- this will get cleaner once we have native lua expr mappings: + command [[cnoremap <expr> <tab> luaeval("not rawset(_G, 'coin', not coin).coin") ? "<c-z>" : "c"]] + + feed ':syntax <tab>' + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {1:~ }| + :syntax c^ | + ]]} + + feed '<tab>' + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {3:case clear cluster > }| + :syntax c^ | + ]]} + + feed '<tab>' + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {1:~ }| + :syntax cc^ | + ]]} + end) end) describe('command line completion', function() diff --git a/test/unit/path_spec.lua b/test/unit/path_spec.lua index 356c4997fa..41954de9be 100644 --- a/test/unit/path_spec.lua +++ b/test/unit/path_spec.lua @@ -603,4 +603,21 @@ describe('path.c', function() eq(FAIL, path_is_absolute('not/in/my/home~/directory')) end) end) + + describe('path_with_extension', function() + local function path_with_extension(filename, extension) + local c_filename = to_cstr(filename) + local c_extension = to_cstr(extension) + return cimp.path_with_extension(c_filename, c_extension) + end + + itp('returns true if filename includes a provided extension', function() + eq(true, path_with_extension('/some/path/file.lua', 'lua')) + end) + + itp('returns false if filename does not include a provided extension', function() + eq(false, path_with_extension('/some/path/file.vim', 'lua')) + eq(false, path_with_extension('/some/path/file', 'lua')) + end) + end) end) |