diff options
95 files changed, 1403 insertions, 994 deletions
diff --git a/.gitattributes b/.gitattributes index 15a5c58091..cb5934a2a1 100755 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ *.h linguist-language=C +src/nvim/testdir/test42.in diff diff --git a/CMakeLists.txt b/CMakeLists.txt index 98a32a116b..790fc9fb41 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -317,10 +317,10 @@ if(HAS_DIAG_COLOR_FLAG) endif() endif() -option(TRAVIS_CI_BUILD "Travis/QuickBuild CI, extra flags will be set" OFF) +option(TRAVIS_CI_BUILD "Travis/sourcehut CI, extra flags will be set" OFF) if(TRAVIS_CI_BUILD) - message(STATUS "Travis/QuickBuild CI build enabled") + message(STATUS "Travis/sourcehut CI build enabled") add_compile_options(-Werror) if(DEFINED ENV{BUILD_32BIT}) # Get some test coverage for unsigned char @@ -562,10 +562,7 @@ if(BUSTED_PRG) endif() set(UNITTEST_PREREQS nvim-test unittest-headers) - set(FUNCTIONALTEST_PREREQS nvim printargs-test shell-test streams-test ${GENERATED_HELP_TAGS}) - if(NOT WIN32) - list(APPEND FUNCTIONALTEST_PREREQS tty-test) - endif() + set(FUNCTIONALTEST_PREREQS nvim printenv-test printargs-test shell-test streams-test tty-test ${GENERATED_HELP_TAGS}) set(BENCHMARK_PREREQS nvim tty-test) # Useful for automated build systems, if they want to manually run the tests. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 607f1aae83..04b4d23a2e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -85,7 +85,7 @@ the VCS/git logs more valuable. ### Automated builds (CI) -Each pull request must pass the automated builds on [Travis CI], [QuickBuild] +Each pull request must pass the automated builds on [Travis CI], [sourcehut] and [AppVeyor]. - CI builds are compiled with [`-Werror`][gcc-warnings], so compiler warnings @@ -100,14 +100,19 @@ and [AppVeyor]. - The [lint](#lint) build checks modified lines _and their immediate neighbors_, to encourage incrementally updating the legacy style to meet our [style](#style). (See [#3174][3174] for background.) -- [How to investigate QuickBuild failures](https://github.com/neovim/neovim/pull/4718#issuecomment-217631350) - - QuickBuild uses this invocation: - ``` - mkdir -p build/${params.get("buildType")} \ - && cd build/${params.get("buildType")} \ - && cmake -G "Unix Makefiles" -DBUSTED_OUTPUT_TYPE=TAP -DCMAKE_BUILD_TYPE=${params.get("buildType")} - -DTRAVIS_CI_BUILD=ON ../.. && ${node.getAttribute("make", "make")} - VERBOSE=1 nvim unittest-prereqs functionaltest-prereqs +- CI for freebsd and openbsd runs on [sourcehut]. + - To get a backtrace on freebsd (after connecting via ssh): + ```sh + sudo pkg install tmux # If you want tmux. + lldb build/bin/nvim -c nvim.core + + # To get a full backtrace: + # 1. Rebuild with debug info. + rm -rf nvim.core build + gmake CMAKE_BUILD_TYPE=RelWithDebInfo CMAKE_EXTRA_FLAGS="-DTRAVIS_CI_BUILD=ON -DMIN_LOG_LEVEL=3" nvim + # 2. Run the failing test to generate a new core file. + TEST_FILE=test/functional/foo.lua gmake functionaltest + lldb build/bin/nvim -c nvim.core ``` ### Clang scan-build @@ -223,7 +228,7 @@ as context, use the `-W` argument as well. [review-checklist]: https://github.com/neovim/neovim/wiki/Code-review-checklist [3174]: https://github.com/neovim/neovim/issues/3174 [Travis CI]: https://travis-ci.org/neovim/neovim -[QuickBuild]: http://neovim-qb.szakmeister.net/dashboard +[sourcehut]: https://builds.sr.ht/~jmk [AppVeyor]: https://ci.appveyor.com/project/neovim/neovim [Merge a Vim patch]: https://github.com/neovim/neovim/wiki/Merging-patches-from-upstream-Vim [Clang report]: https://neovim.io/doc/reports/clang/ diff --git a/ci/install.sh b/ci/install.sh index 21175f63e0..24a4bd7450 100755 --- a/ci/install.sh +++ b/ci/install.sh @@ -26,7 +26,11 @@ npm install -g neovim npm link neovim echo "Install tree-sitter npm package" -npm install -g tree-sitter-cli + +# FIXME +# https://github.com/tree-sitter/tree-sitter/commit/e14e285a1087264a8c74a7c62fcaecc49db9d904 +# If queries added to tree-sitter-c, we can use latest tree-sitter-cli +npm install -g tree-sitter-cli@v0.15.9 npm link tree-sitter-cli echo "Install tree-sitter c parser" diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 607e88b7c8..77b6ee24a4 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -9779,27 +9779,37 @@ This does NOT work: > Like above, but append/add/subtract the value for each |List| item. - *:let=<<* *:let-heredoc* *E990* *E991* + *:let=<<* *:let-heredoc* + *E990* *E991* *E172* *E221* :let {var-name} =<< [trim] {marker} text... text... {marker} Set internal variable {var-name} to a List containing the lines of text bounded by the string {marker}. - {marker} must not contain white space. + {marker} cannot start with a lower case character. The last line should end only with the {marker} string without any other character. Watch out for white space after {marker}! - If {marker} is not supplied, then "." is used as the - default marker. - - Any white space characters in the lines of text are - preserved. If "trim" is specified before {marker}, - then all the leading indentation exactly matching the - leading indentation before `let` is stripped from the - input lines and the line containing {marker}. Note - that the difference between space and tab matters - here. + + Without "trim" any white space characters in the lines + of text are preserved. If "trim" is specified before + {marker}, then indentation is stripped so you can do: > + let text =<< trim END + if ok + echo 'done' + endif + END +< Results in: ["if ok", " echo 'done'", "endif"] + The marker must line up with "let" and the indentation + of the first line is removed from all the text lines. + Specifically: all the leading indentation exactly + matching the leading indentation of the first + non-empty text line is stripped from the input lines. + All leading indentation exactly matching the leading + indentation before `let` is stripped from the line + containing {marker}. Note that the difference between + space and tab matters here. If {var-name} didn't exist yet, it is created. Cannot be followed by another command, but can be diff --git a/runtime/doc/if_lua.txt b/runtime/doc/if_lua.txt index 0ba35aeae6..8528085f47 100644 --- a/runtime/doc/if_lua.txt +++ b/runtime/doc/if_lua.txt @@ -361,7 +361,7 @@ Note that underscore-prefixed functions (e.g. "_os_proc_children") are internal/private and must not be used by plugins. ------------------------------------------------------------------------------ -VIM.API *lua-api* +VIM.API *lua-api* *vim.api* `vim.api` exposes the full Nvim |API| as a table of Lua functions. @@ -371,7 +371,7 @@ Example: to use the "nvim_get_current_line()" API function, call print(tostring(vim.api.nvim_get_current_line())) ------------------------------------------------------------------------------ -VIM.LOOP *lua-loop* +VIM.LOOP *lua-loop* *vim.loop* `vim.loop` exposes all features of the Nvim event-loop. This is a low-level API that provides functionality for networking, filesystem, and process diff --git a/runtime/doc/intro.txt b/runtime/doc/intro.txt index 887ef764bd..3292489eda 100644 --- a/runtime/doc/intro.txt +++ b/runtime/doc/intro.txt @@ -378,11 +378,11 @@ notation meaning equivalent decimal value(s) ~ <kEqual> keypad = *keypad-equal* <kEnter> keypad Enter *keypad-enter* <k0> - <k9> keypad 0 to 9 *keypad-0* *keypad-9* -<S-...> shift-key *shift* *<S-* -<C-...> control-key *control* *ctrl* *<C-* -<M-...> alt-key or meta-key *META* *ALT* *<M-* -<A-...> same as <M-...> *<A-* -<D-...> command-key or "super" key *<D-* +<S-…> shift-key *shift* *<S-* +<C-…> control-key *control* *ctrl* *<C-* +<M-…> alt-key or meta-key *META* *ALT* *<M-* +<A-…> same as <M-…> *<A-* +<D-…> command-key or "super" key *<D-* ----------------------------------------------------------------------- Note: The shifted cursor keys, the help key, and the undo key are only diff --git a/runtime/doc/message.txt b/runtime/doc/message.txt index e8c76adad4..965b062728 100644 --- a/runtime/doc/message.txt +++ b/runtime/doc/message.txt @@ -556,7 +556,8 @@ allowed for the command that was used. Vim was not able to create a swap file. You can still edit the file, but if Vim unexpectedly exits the changes will be lost. And Vim may consume a lot of memory when editing a big file. You may want to change the 'directory' option -to avoid this error. See |swap-file|. +to avoid this error. This error is not given when 'directory' is empty. See +|swap-file|. *E140* > Use ! to write partial buffer diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 65d2a7652c..e12a7d4986 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1978,7 +1978,7 @@ A jump table for the options with a short description can be found at |Q_op|. possible. If it is not possible in any directory, but last directory listed in the option does not exist, it is created. - Empty means that no swap file will be used (recovery is - impossible!). + impossible!) and no |E303| error will be given. - A directory "." means to put the swap file in the same directory as the edited file. On Unix, a dot is prepended to the file name, so it doesn't show in a directory listing. On MS-Windows the "hidden" diff --git a/runtime/filetype.vim b/runtime/filetype.vim index 6abf9da55f..8ce45b6a50 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -421,6 +421,9 @@ au BufNewFile,BufRead *.csp,*.fdr setf csp au BufNewFile,BufRead *.pld setf cupl au BufNewFile,BufRead *.si setf cuplsim +" Dart +au BufRead,BufNewfile *.dart,*.drt setf dart + " Debian Control au BufNewFile,BufRead */debian/control setf debcontrol au BufNewFile,BufRead control @@ -975,6 +978,9 @@ au BufNewFile,BufRead hg-editor-*.txt setf hgcommit " Mercurial config (looks like generic config file) au BufNewFile,BufRead *.hgrc,*hgrc setf cfg +" Meson Build system config +au BufNewFile,BufRead meson.build,meson_options.txt setf meson + " Messages (logs mostly) au BufNewFile,BufRead */log/{auth,cron,daemon,debug,kern,lpr,mail,messages,news/news,syslog,user}{,.log,.err,.info,.warn,.crit,.notice}{,.[0-9]*,-[0-9]*} setf messages diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh index 2cc32f0dd0..2a04805606 100755 --- a/scripts/vim-patch.sh +++ b/scripts/vim-patch.sh @@ -89,7 +89,7 @@ get_vim_sources() { echo "Cloning Vim into: ${VIM_SOURCE_DIR}" git clone https://github.com/vim/vim.git "${VIM_SOURCE_DIR}" cd "${VIM_SOURCE_DIR}" - else + elif [[ "${1-}" == update ]]; then cd "${VIM_SOURCE_DIR}" if ! [ -d ".git" ] \ && ! [ "$(git rev-parse --show-toplevel)" = "${VIM_SOURCE_DIR}" ]; then @@ -103,6 +103,8 @@ get_vim_sources() { else msg_err "Could not update Vim sources; ignoring error." fi + else + cd "${VIM_SOURCE_DIR}" fi } @@ -124,7 +126,7 @@ find_git_remote() { } # Assign variables for a given Vim tag, patch version, or commit. -# Might exit in case it cannot be found. +# Might exit in case it cannot be found, after updating Vim sources. assign_commit_details() { local vim_commit_ref if [[ ${1} =~ v?[0-9]\.[0-9]\.[0-9]{3,4} ]]; then @@ -146,9 +148,14 @@ assign_commit_details() { local munge_commit_line=false fi - vim_commit=$(git -C "${VIM_SOURCE_DIR}" log -1 --format="%H" "${vim_commit_ref}" --) || { - >&2 msg_err "Couldn't find Vim revision '${vim_commit_ref}'." - exit 3 + local get_vim_commit_cmd="git -C ${VIM_SOURCE_DIR} log -1 --format=%H ${vim_commit_ref} --" + vim_commit=$($get_vim_commit_cmd 2>&1) || { + # Update Vim sources. + get_vim_sources update + vim_commit=$($get_vim_commit_cmd 2>&1) || { + >&2 msg_err "Couldn't find Vim revision '${vim_commit_ref}': git error: ${vim_commit}." + exit 3 + } } vim_commit_url="https://github.com/vim/vim/commit/${vim_commit}" @@ -366,7 +373,7 @@ submit_pr() { # Gets all Vim commits since the "start" commit. list_vim_commits() { ( - cd "${VIM_SOURCE_DIR}" && git log --reverse --format='%H' v8.0.0000..HEAD "$@" + cd "${VIM_SOURCE_DIR}" && git log --reverse v8.0.0000..HEAD "$@" ) } # Prints all (sorted) "vim-patch:xxx" tokens found in the Nvim git log. @@ -389,6 +396,7 @@ list_vimpatch_numbers() { } # Prints a newline-delimited list of Vim commits, for use by scripts. +# "$1": use extended format? # "$@" is passed to list_vim_commits, as extra arguments to git-log. list_missing_vimpatches() { local token vim_commit vim_tag patch_number @@ -396,6 +404,13 @@ list_missing_vimpatches() { declare -A vim_commit_tags declare -a git_log_args + local extended_format=$1; shift + if [[ "$extended_format" == 1 ]]; then + git_log_args=("--format=%H %s") + else + git_log_args=("--format=%H") + fi + # Massage arguments for git-log. declare -A git_log_replacements=( [^\(.*/\)?src/nvim/\(.*\)]="\${BASH_REMATCH[1]}src/\${BASH_REMATCH[2]}" @@ -431,13 +446,27 @@ list_missing_vimpatches() { # Get missing Vim commits set +u # Avoid "unbound variable" with bash < 4.4 below. - for vim_commit in $(list_vim_commits "${git_log_args[@]}"); do + local vim_commit info + while IFS=' ' read -r line; do # Check for vim-patch:<commit_hash> (usually runtime updates). - token="vim-patch:${vim_commit:0:7}" + token="vim-patch:${line:0:7}" if [[ "${tokens[$token]-}" ]]; then continue fi + # Get commit hash, and optional info from line. This is used in + # extended mode, and when using e.g. '--format' manually. + vim_commit=${line%% *} + if [[ "$vim_commit" == "$line" ]]; then + info= + else + info=${line#* } + if [[ -n $info ]]; then + # Remove any "patch 8.0.0902: " prefixes, and prefix with ": ". + info=": ${info#patch*: }" + fi + fi + vim_tag="${vim_commit_tags[$vim_commit]-}" if [[ -n "$vim_tag" ]]; then # Check for vim-patch:<tag> (not commit hash). @@ -445,26 +474,26 @@ list_missing_vimpatches() { if [[ "${tokens[$patch_number]-}" ]]; then continue fi - echo "$vim_tag" + printf '%s%s\n' "$vim_tag" "$info" else - echo "$vim_commit" + printf '%s%s\n' "$vim_commit" "$info" fi - done + done < <(list_vim_commits "${git_log_args[@]}") set -u } # Prints a human-formatted list of Vim commits, with instructional messages. # Passes "$@" onto list_missing_vimpatches (args for git-log). show_vimpatches() { - get_vim_sources - printf "\nVim patches missing from Neovim:\n" + get_vim_sources update + printf "Vim patches missing from Neovim:\n" local -A runtime_commits for commit in $(git -C "${VIM_SOURCE_DIR}" log --format="%H %D" -- runtime | sed 's/,\? tag: / /g'); do runtime_commits[$commit]=1 done - list_missing_vimpatches "$@" | while read -r vim_commit; do + list_missing_vimpatches 1 "$@" | while read -r vim_commit; do if [[ "${runtime_commits[$vim_commit]-}" ]]; then printf ' • %s (+runtime)\n' "${vim_commit}" else @@ -472,17 +501,12 @@ show_vimpatches() { fi done - printf "Instructions: - - To port one of the above patches to Neovim, execute - this script with the patch revision as argument and - follow the instructions. - - Examples: '%s -p 7.4.487' - '%s -p 1e8ebf870720e7b671f98f22d653009826304c4f' + printf "\nInstructions: + To port one of the above patches to Neovim, execute this script with the patch revision as argument and follow the instructions, e.g. + '%s -p v8.0.1234', or '%s -P v8.0.1234' NOTE: Please port the _oldest_ patch if you possibly can. - Out-of-order patches increase the possibility of bugs. + You can use '%s -l path/to/file' to see what patches are missing for a file. " "${BASENAME}" "${BASENAME}" } @@ -596,7 +620,7 @@ while getopts "hlLMVp:P:g:r:s" opt; do ;; L) shift # remove opt - list_missing_vimpatches "$@" + list_missing_vimpatches 0 "$@" exit 0 ;; M) @@ -624,7 +648,7 @@ while getopts "hlLMVp:P:g:r:s" opt; do exit 0 ;; V) - get_vim_sources + get_vim_sources update exit 0 ;; *) diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index a64944ab0d..b00ac866b7 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -419,6 +419,7 @@ if(Iconv_LIBRARIES) endif() if(WIN32) + list(APPEND NVIM_LINK_LIBRARIES netapi32) list(APPEND NVIM_LINK_LIBRARIES ${WINPTY_LIBRARIES}) endif() diff --git a/src/nvim/cursor.c b/src/nvim/cursor.c index f2b3cfe690..036ae32589 100644 --- a/src/nvim/cursor.c +++ b/src/nvim/cursor.c @@ -93,11 +93,12 @@ int coladvance(colnr_T wcol) static int coladvance2( pos_T *pos, - bool addspaces, /* change the text to achieve our goal? */ - bool finetune, /* change char offset for the exact column */ - colnr_T wcol /* column to move to */ + bool addspaces, // change the text to achieve our goal? + bool finetune, // change char offset for the exact column + colnr_T wcol_arg // column to move to (can be negative) ) { + colnr_T wcol = wcol_arg; int idx; char_u *ptr; char_u *line; @@ -165,6 +166,7 @@ static int coladvance2( if (virtual_active() && addspaces + && wcol >= 0 && ((col != wcol && col != wcol + 1) || csize > 1)) { /* 'virtualedit' is set: The difference between wcol and col is * filled with spaces. */ @@ -244,8 +246,9 @@ static int coladvance2( mark_mb_adjustpos(curbuf, pos); } - if (col < wcol) + if (wcol < 0 || col < wcol) { return FAIL; + } return OK; } diff --git a/src/nvim/edit.c b/src/nvim/edit.c index a4b4e0d980..62e4f77e6e 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -5481,10 +5481,10 @@ insertchar ( if (c == NUL) /* only formatting was wanted */ return; - /* Check whether this character should end a comment. */ + // Check whether this character should end a comment. if (did_ai && c == end_comment_pending) { char_u *line; - char_u lead_end[COM_MAX_LEN]; /* end-comment string */ + char_u lead_end[COM_MAX_LEN]; // end-comment string int middle_len, end_len; int i; @@ -5492,39 +5492,40 @@ insertchar ( * Need to remove existing (middle) comment leader and insert end * comment leader. First, check what comment leader we can find. */ - i = get_leader_len(line = get_cursor_line_ptr(), &p, FALSE, TRUE); - if (i > 0 && vim_strchr(p, COM_MIDDLE) != NULL) { /* Just checking */ - /* Skip middle-comment string */ - while (*p && p[-1] != ':') /* find end of middle flags */ - ++p; + i = get_leader_len(line = get_cursor_line_ptr(), &p, false, true); + if (i > 0 && vim_strchr(p, COM_MIDDLE) != NULL) { // Just checking + // Skip middle-comment string + while (*p && p[-1] != ':') { // find end of middle flags + p++; + } middle_len = copy_option_part(&p, lead_end, COM_MAX_LEN, ","); - /* Don't count trailing white space for middle_len */ - while (middle_len > 0 && ascii_iswhite(lead_end[middle_len - 1])) - --middle_len; + // Don't count trailing white space for middle_len + while (middle_len > 0 && ascii_iswhite(lead_end[middle_len - 1])) { + middle_len--; + } - /* Find the end-comment string */ - while (*p && p[-1] != ':') /* find end of end flags */ - ++p; + // Find the end-comment string + while (*p && p[-1] != ':') { // find end of end flags + p++; + } end_len = copy_option_part(&p, lead_end, COM_MAX_LEN, ","); - /* Skip white space before the cursor */ + // Skip white space before the cursor i = curwin->w_cursor.col; while (--i >= 0 && ascii_iswhite(line[i])) ; i++; - /* Skip to before the middle leader */ + // Skip to before the middle leader i -= middle_len; - /* Check some expected things before we go on */ + // Check some expected things before we go on if (i >= 0 && lead_end[end_len - 1] == end_comment_pending) { - /* Backspace over all the stuff we want to replace */ + // Backspace over all the stuff we want to replace backspace_until_column(i); - /* - * Insert the end-comment string, except for the last - * character, which will get inserted as normal later. - */ + // Insert the end-comment string, except for the last + // character, which will get inserted as normal later. ins_bytes_len(lead_end, end_len - 1); } } diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 7d641f1295..71ffb26cc2 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -1521,7 +1521,9 @@ heredoc_get(exarg_T *eap, char_u *cmd) { char_u *marker; char_u *p; - int indent_len = 0; + int marker_indent_len = 0; + int text_indent_len = 0; + char_u *text_indent = NULL; if (eap->getline == NULL) { EMSG(_("E991: cannot use =<< here")); @@ -1534,17 +1536,19 @@ heredoc_get(exarg_T *eap, char_u *cmd) && (cmd[4] == NUL || ascii_iswhite(cmd[4]))) { cmd = skipwhite(cmd + 4); - // Trim the indentation from all the lines in the here document + // Trim the indentation from all the lines in the here document. // The amount of indentation trimmed is the same as the indentation of - // the :let command line. + // the first line after the :let command line. To find the end marker + // the indent of the :let command line is trimmed. p = *eap->cmdlinep; while (ascii_iswhite(*p)) { p++; - indent_len++; + marker_indent_len++; } + text_indent_len = -1; } - // The marker is the next word. Default marker is "." + // The marker is the next word. if (*cmd != NUL && *cmd != '"') { marker = skipwhite(cmd); p = skiptowhite(marker); @@ -1553,34 +1557,59 @@ heredoc_get(exarg_T *eap, char_u *cmd) return NULL; } *p = NUL; + if (islower(*marker)) { + EMSG(_("E221: Marker cannot start with lower case letter")); + return NULL; + } } else { - marker = (char_u *)"."; + EMSG(_("E172: Missing marker")); + return NULL; } list_T *l = tv_list_alloc(0); for (;;) { - int i = 0; + int mi = 0; + int ti = 0; char_u *theline = eap->getline(NUL, eap->cookie, 0, false); - if (theline != NULL && indent_len > 0) { - // trim the indent matching the first line - if (STRNCMP(theline, *eap->cmdlinep, indent_len) == 0) { - i = indent_len; - } - } - if (theline == NULL) { EMSG2(_("E990: Missing end marker '%s'"), marker); break; } - if (STRCMP(marker, theline + i) == 0) { + + // with "trim": skip the indent matching the :let line to find the + // marker + if (marker_indent_len > 0 + && STRNCMP(theline, *eap->cmdlinep, marker_indent_len) == 0) { + mi = marker_indent_len; + } + if (STRCMP(marker, theline + mi) == 0) { xfree(theline); break; } + if (text_indent_len == -1 && *theline != NUL) { + // set the text indent from the first line. + p = theline; + text_indent_len = 0; + while (ascii_iswhite(*p)) { + p++; + text_indent_len++; + } + text_indent = vim_strnsave(theline, text_indent_len); + } + // with "trim": skip the indent matching the first line + if (text_indent != NULL) { + for (ti = 0; ti < text_indent_len; ti++) { + if (theline[ti] != text_indent[ti]) { + break; + } + } + } - tv_list_append_string(l, (char *)(theline + i), -1); + tv_list_append_string(l, (char *)(theline + ti), -1); xfree(theline); } + xfree(text_indent); return l; } @@ -1646,10 +1675,12 @@ static void ex_let_const(exarg_T *eap, const bool is_const) list_T *l = heredoc_get(eap, expr + 3); if (l != NULL) { tv_list_set_ret(&rettv, l); - op[0] = '='; - op[1] = NUL; - (void)ex_let_vars(eap->arg, &rettv, false, semicolon, var_count, - is_const, op); + if (!eap->skip) { + op[0] = '='; + op[1] = NUL; + (void)ex_let_vars(eap->arg, &rettv, false, semicolon, var_count, + is_const, op); + } tv_clear(&rettv); } } else { @@ -21268,8 +21299,6 @@ void ex_function(exarg_T *eap) bool overwrite = false; int indent; int nesting; - char_u *skip_until = NULL; - char_u *trimmed = NULL; dictitem_T *v; funcdict_T fudi; static int func_nr = 0; /* number for nameless function */ @@ -21277,7 +21306,11 @@ void ex_function(exarg_T *eap) hashtab_T *ht; int todo; hashitem_T *hi; - int sourcing_lnum_off; + linenr_T sourcing_lnum_off; + linenr_T sourcing_lnum_top; + bool is_heredoc = false; + char_u *skip_until = NULL; + char_u *heredoc_trimmed = NULL; bool show_block = false; bool do_concat = true; @@ -21526,15 +21559,17 @@ void ex_function(exarg_T *eap) cmdline_row = msg_row; } + // Save the starting line number. + sourcing_lnum_top = sourcing_lnum; + indent = 2; nesting = 0; for (;; ) { if (KeyTyped) { - msg_scroll = TRUE; - saved_wait_return = FALSE; + msg_scroll = true; + saved_wait_return = false; } - need_wait_return = FALSE; - sourcing_lnum_off = sourcing_lnum; + need_wait_return = false; if (line_arg != NULL) { /* Use eap->arg, split up in parts by line breaks. */ @@ -21567,21 +21602,36 @@ void ex_function(exarg_T *eap) ui_ext_cmdline_block_append((size_t)indent, (const char *)theline); } - /* Detect line continuation: sourcing_lnum increased more than one. */ - if (sourcing_lnum > sourcing_lnum_off + 1) - sourcing_lnum_off = sourcing_lnum - sourcing_lnum_off - 1; - else + // Detect line continuation: sourcing_lnum increased more than one. + sourcing_lnum_off = get_sourced_lnum(eap->getline, eap->cookie); + if (sourcing_lnum < sourcing_lnum_off) { + sourcing_lnum_off -= sourcing_lnum; + } else { sourcing_lnum_off = 0; + } if (skip_until != NULL) { - // Between ":append" and "." and between ":python <<EOF" and "EOF" - // don't check for ":endfunc". - if (trimmed == NULL || STRNCMP(theline, trimmed, STRLEN(trimmed)) == 0) { - p = trimmed == NULL ? theline : theline + STRLEN(trimmed); + // Don't check for ":endfunc" between + // * ":append" and "." + // * ":python <<EOF" and "EOF" + // * ":let {var-name} =<< [trim] {marker}" and "{marker}" + if (heredoc_trimmed == NULL + || (is_heredoc && skipwhite(theline) == theline) + || STRNCMP(theline, heredoc_trimmed, + STRLEN(heredoc_trimmed)) == 0) { + if (heredoc_trimmed == NULL) { + p = theline; + } else if (is_heredoc) { + p = skipwhite(theline) == theline + ? theline : theline + STRLEN(heredoc_trimmed); + } else { + p = theline + STRLEN(heredoc_trimmed); + } if (STRCMP(p, skip_until) == 0) { XFREE_CLEAR(skip_until); - XFREE_CLEAR(trimmed); + XFREE_CLEAR(heredoc_trimmed); do_concat = true; + is_heredoc = false; } } } else { @@ -21689,19 +21739,16 @@ void ex_function(exarg_T *eap) && ((p[0] == 'l' && p[1] == 'e' && (!ASCII_ISALNUM(p[2]) || (p[2] == 't' && !ASCII_ISALNUM(p[3])))))) { - // ":let v =<<" continues until a dot p = skipwhite(arg + 3); if (STRNCMP(p, "trim", 4) == 0) { // Ignore leading white space. p = skipwhite(p + 4); - trimmed = vim_strnsave(theline, (int)(skipwhite(theline) - theline)); - } - if (*p == NUL) { - skip_until = vim_strsave((char_u *)"."); - } else { - skip_until = vim_strnsave(p, (int)(skiptowhite(p) - p)); + heredoc_trimmed = vim_strnsave(theline, + (int)(skipwhite(theline) - theline)); } + skip_until = vim_strnsave(p, (int)(skiptowhite(p) - p)); do_concat = false; + is_heredoc = true; } } @@ -21872,7 +21919,8 @@ void ex_function(exarg_T *eap) fp->uf_flags = flags; fp->uf_calls = 0; fp->uf_script_ctx = current_sctx; - fp->uf_script_ctx.sc_lnum += sourcing_lnum - newlines.ga_len - 1; + fp->uf_script_ctx.sc_lnum += sourcing_lnum_top; + goto ret_free; erret: @@ -24051,22 +24099,47 @@ repeat: * - for second :e: before the current fname * - otherwise: The last '.' */ - if (src[*usedlen + 1] == 'e' && *fnamep > tail) + const bool is_second_e = *fnamep > tail; + if (src[*usedlen + 1] == 'e' && is_second_e) { s = *fnamep - 2; - else + } else { s = *fnamep + *fnamelen - 1; - for (; s > tail; --s) - if (s[0] == '.') + } + + for (; s > tail; s--) { + if (s[0] == '.') { break; - if (src[*usedlen + 1] == 'e') { /* :e */ - if (s > tail) { - *fnamelen += (size_t)(*fnamep - (s + 1)); - *fnamep = s + 1; - } else if (*fnamep <= tail) + } + } + if (src[*usedlen + 1] == 'e') { + if (s > tail || (0 && is_second_e && s == tail)) { + // we stopped at a '.' (so anchor to &'.' + 1) + char_u *newstart = s + 1; + size_t distance_stepped_back = *fnamep - newstart; + *fnamelen += distance_stepped_back; + *fnamep = newstart; + } else if (*fnamep <= tail) { *fnamelen = 0; - } else { /* :r */ - if (s > tail) /* remove one extension */ + } + } else { + // :r - Remove one extension + // + // Ensure that `s` doesn't go before `*fnamep`, + // since then we're taking too many roots: + // + // "path/to/this.file.ext" :e:e:r:r + // ^ ^-------- *fnamep + // +------------- tail + // + // Also ensure `s` doesn't go before `tail`, + // since then we're taking too many roots again: + // + // "path/to/this.file.ext" :r:r:r + // ^ ^------------- tail + // +--------------------- *fnamep + if (s > MAX(tail, *fnamep)) { *fnamelen = (size_t)(s - *fnamep); + } } *usedlen += 2; } diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index 272c81e29b..84291b3637 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -97,10 +97,11 @@ typedef struct sn_prl_S { struct source_cookie { FILE *fp; ///< opened file for sourcing char_u *nextline; ///< if not NULL: line that was read ahead + linenr_T sourcing_lnum; ///< line number of the source file int finished; ///< ":finish" used #if defined(USE_CRNL) int fileformat; ///< EOL_UNKNOWN, EOL_UNIX or EOL_DOS - bool error; ///< true if LF found after CR-LF + bool error; ///< true if LF found after CR-LF #endif linenr_T breakpoint; ///< next line with breakpoint or zero char_u *fname; ///< name of sourced file @@ -3124,6 +3125,7 @@ int do_source(char_u *fname, int check_other, int is_vimrc) #endif cookie.nextline = NULL; + cookie.sourcing_lnum = 0; cookie.finished = false; // Check if this script has a breakpoint. @@ -3375,6 +3377,13 @@ void free_scriptnames(void) } # endif +linenr_T get_sourced_lnum(LineGetter fgetline, void *cookie) +{ + return fgetline == getsourceline + ? ((struct source_cookie *)cookie)->sourcing_lnum + : sourcing_lnum; +} + /// Get one full line from a sourced file. /// Called by do_cmdline() when it's called from do_source(). @@ -3395,6 +3404,8 @@ char_u *getsourceline(int c, void *cookie, int indent, bool do_concat) if (do_profiling == PROF_YES) { script_line_end(); } + // Set the current sourcing line number. + sourcing_lnum = sp->sourcing_lnum + 1; // Get current line. If there is a read-ahead line, use it, otherwise get // one now. if (sp->finished) { @@ -3404,7 +3415,7 @@ char_u *getsourceline(int c, void *cookie, int indent, bool do_concat) } else { line = sp->nextline; sp->nextline = NULL; - sourcing_lnum++; + sp->sourcing_lnum++; } if (line != NULL && do_profiling == PROF_YES) { script_line_start(); @@ -3414,7 +3425,7 @@ char_u *getsourceline(int c, void *cookie, int indent, bool do_concat) // contain the 'C' flag. if (line != NULL && do_concat && (vim_strchr(p_cpo, CPO_CONCAT) == NULL)) { // compensate for the one line read-ahead - sourcing_lnum--; + sp->sourcing_lnum--; // Get the next line and concatenate it when it starts with a // backslash. We always need to read the next line, keep it in @@ -3492,7 +3503,7 @@ static char_u *get_one_sourceline(struct source_cookie *sp) ga_init(&ga, 1, 250); // Loop until there is a finished line (or end-of-file). - sourcing_lnum++; + sp->sourcing_lnum++; for (;; ) { // make room to read at least 120 (more) characters ga_grow(&ga, 120); @@ -3559,7 +3570,7 @@ retry: // len&c parities (is faster than ((len-c)%2 == 0)) -- Acevedo for (c = len - 2; c >= 0 && buf[c] == Ctrl_V; c--) {} if ((len & 1) != (c & 1)) { // escaped NL, read more - sourcing_lnum++; + sp->sourcing_lnum++; continue; } diff --git a/src/nvim/main.c b/src/nvim/main.c index ba15dcedad..e0a1e60fc0 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -957,6 +957,7 @@ static void command_line_scan(mparm_T *parmp) case 'r': // "-r" recovery mode case 'L': { // "-L" recovery mode recoverymode = 1; + headless_mode = true; break; } case 's': { diff --git a/src/nvim/memline.c b/src/nvim/memline.c index f1d6ee064c..b85c23e50f 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -523,9 +523,9 @@ void ml_open_file(buf_T *buf) } } - if (mfp->mf_fname == NULL) { /* Failed! */ - need_wait_return = TRUE; /* call wait_return later */ - ++no_wait_return; + if (*p_dir != NUL && mfp->mf_fname == NULL) { + need_wait_return = true; // call wait_return later + no_wait_return++; (void)EMSG2(_( "E303: Unable to open swap file for \"%s\", recovery impossible"), buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname); diff --git a/src/nvim/message.c b/src/nvim/message.c index b518664f32..03cbe8ec18 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -233,7 +233,10 @@ void msg_multiline_attr(const char *s, int attr, bool check_int) { const char *next_spec = s; - while (next_spec != NULL && (!check_int || !got_int)) { + while (next_spec != NULL) { + if (check_int && got_int) { + return; + } next_spec = strpbrk(s, "\t\n\r"); if (next_spec != NULL) { diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c index c1de7ab9a4..1db8a1fa11 100644 --- a/src/nvim/misc1.c +++ b/src/nvim/misc1.c @@ -792,8 +792,6 @@ int prompt_for_number(int *mouse_used) cmdline_row = msg_row - 1; } need_wait_return = false; - msg_didany = false; - msg_didout = false; } else { cmdline_row = save_cmdline_row; } diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 28183ffa1d..f6222f9d3f 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -3925,15 +3925,17 @@ static bool nv_screengo(oparg_T *oap, int dir, long dist) n = ((linelen - width1 - 1) / width2 + 1) * width2 + width1; else n = width1; - if (curwin->w_curswant > (colnr_T)n + 1) - curwin->w_curswant -= ((curwin->w_curswant - n) / width2 + 1) - * width2; + if (curwin->w_curswant >= n) { + curwin->w_curswant = n - 1; + } } while (dist--) { if (dir == BACKWARD) { - if (curwin->w_curswant > width2) { - // move back within line + if (curwin->w_curswant >= width1) { + // Move back within the line. This can give a negative value + // for w_curswant if width1 < width2 (with cpoptions+=n), + // which will get clipped to column 0. curwin->w_curswant -= width2; } else { // to previous line @@ -3973,6 +3975,13 @@ static bool nv_screengo(oparg_T *oap, int dir, long dist) } curwin->w_cursor.lnum++; curwin->w_curswant %= width2; + // Check if the cursor has moved below the number display + // when width1 < width2 (with cpoptions+=n). Subtract width2 + // to get a negative value for w_curswant, which will get + // clipped to column 0. + if (curwin->w_curswant >= width1) { + curwin->w_curswant -= width2; + } linelen = linetabsize(get_cursor_line_ptr()); } } diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 0d27365d2b..030782cbcc 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -270,20 +270,21 @@ void shift_line( int left, int round, int amount, - int call_changed_bytes /* call changed_bytes() */ + int call_changed_bytes // call changed_bytes() ) { int count; int i, j; int p_sw = get_sw_value(curbuf); - count = get_indent(); /* get current indent */ + count = get_indent(); // get current indent - if (round) { /* round off indent */ - i = count / p_sw; /* number of p_sw rounded down */ - j = count % p_sw; /* extra spaces */ - if (j && left) /* first remove extra spaces */ - --amount; + if (round) { // round off indent + i = count / p_sw; // number of p_sw rounded down + j = count % p_sw; // extra spaces + if (j && left) { // first remove extra spaces + amount--; + } if (left) { i -= amount; if (i < 0) @@ -291,7 +292,7 @@ void shift_line( } else i += amount; count = i * p_sw; - } else { /* original vi indent */ + } else { // original vi indent if (left) { count -= p_sw * amount; if (count < 0) @@ -300,11 +301,12 @@ void shift_line( count += p_sw * amount; } - /* Set new indent */ - if (State & VREPLACE_FLAG) - change_indent(INDENT_SET, count, FALSE, NUL, call_changed_bytes); - else + // Set new indent + if (State & VREPLACE_FLAG) { + change_indent(INDENT_SET, count, false, NUL, call_changed_bytes); + } else { (void)set_indent(count, call_changed_bytes ? SIN_CHANGED : 0); + } } /* @@ -4281,15 +4283,13 @@ int paragraph_start(linenr_T lnum) return TRUE; /* after empty line */ do_comments = has_format_option(FO_Q_COMS); - if (fmt_check_par(lnum - 1 - , &leader_len, &leader_flags, do_comments - )) - return TRUE; /* after non-paragraph line */ + if (fmt_check_par(lnum - 1, &leader_len, &leader_flags, do_comments)) { + return true; // after non-paragraph line + } - if (fmt_check_par(lnum - , &next_leader_len, &next_leader_flags, do_comments - )) - return TRUE; /* "lnum" is not a paragraph line */ + if (fmt_check_par(lnum, &next_leader_len, &next_leader_flags, do_comments)) { + return true; // "lnum" is not a paragraph line + } if (has_format_option(FO_WHITE_PAR) && !ends_in_white(lnum - 1)) return TRUE; /* missing trailing space in previous line. */ diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index ae61e54993..eb86cb8ac7 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -44,6 +44,16 @@ void env_init(void) uv_mutex_init(&mutex); } +void os_env_var_lock(void) +{ + uv_mutex_lock(&mutex); +} + +void os_env_var_unlock(void) +{ + uv_mutex_unlock(&mutex); +} + /// Like getenv(), but returns NULL if the variable is empty. /// @see os_env_exists const char *os_getenv(const char *name) diff --git a/src/nvim/os/users.c b/src/nvim/os/users.c index c6463c2c92..9374693550 100644 --- a/src/nvim/os/users.c +++ b/src/nvim/os/users.c @@ -13,6 +13,25 @@ #ifdef HAVE_PWD_H # include <pwd.h> #endif +#ifdef WIN32 +# include <lm.h> +#endif + +// Add a user name to the list of users in garray_T *users. +// Do nothing if user name is NULL or empty. +static void add_user(garray_T *users, char *user, bool need_copy) +{ + char *user_copy = (user != NULL && need_copy) + ? xstrdup(user) : user; + + if (user_copy == NULL || *user_copy == NUL) { + if (need_copy) { + xfree(user); + } + return; + } + GA_APPEND(char *, users, user_copy); +} // Initialize users garray and fill it with os usernames. // Return Ok for success, FAIL for failure. @@ -24,16 +43,66 @@ int os_get_usernames(garray_T *users) ga_init(users, sizeof(char *), 20); # if defined(HAVE_GETPWENT) && defined(HAVE_PWD_H) - struct passwd *pw; + { + struct passwd *pw; + + setpwent(); + while ((pw = getpwent()) != NULL) { + add_user(users, pw->pw_name, true); + } + endpwent(); + } +# elif defined(WIN32) + { + DWORD nusers = 0, ntotal = 0, i; + PUSER_INFO_0 uinfo; + + if (NetUserEnum(NULL, 0, 0, (LPBYTE *)&uinfo, MAX_PREFERRED_LENGTH, + &nusers, &ntotal, NULL) == NERR_Success) { + for (i = 0; i < nusers; i++) { + char *user; + int conversion_result = utf16_to_utf8(uinfo[i].usri0_name, -1, &user); + if (conversion_result != 0) { + EMSG2("utf16_to_utf8 failed: %d", conversion_result); + break; + } + add_user(users, user, false); + } + + NetApiBufferFree(uinfo); + } + } +# endif +# if defined(HAVE_GETPWNAM) + { + const char *user_env = os_getenv("USER"); + + // The $USER environment variable may be a valid remote user name (NIS, + // LDAP) not already listed by getpwent(), as getpwent() only lists + // local user names. If $USER is not already listed, check whether it + // is a valid remote user name using getpwnam() and if it is, add it to + // the list of user names. + + if (user_env != NULL && *user_env != NUL) { + int i; + + for (i = 0; i < users->ga_len; i++) { + char *local_user = ((char **)users->ga_data)[i]; + + if (STRCMP(local_user, user_env) == 0) { + break; + } + } + + if (i == users->ga_len) { + struct passwd *pw = getpwnam(user_env); // NOLINT - setpwent(); - while ((pw = getpwent()) != NULL) { - // pw->pw_name shouldn't be NULL but just in case... - if (pw->pw_name != NULL) { - GA_APPEND(char *, users, xstrdup(pw->pw_name)); + if (pw != NULL) { + add_user(users, pw->pw_name, true); + } + } } } - endpwent(); # endif return OK; diff --git a/src/nvim/search.c b/src/nvim/search.c index 1f382d31c5..fb31e76986 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -4184,7 +4184,7 @@ static int is_one_char(char_u *pattern, bool move, pos_T *cur, nmatched = vim_regexec_multi(®match, curwin, curbuf, pos.lnum, regmatch.startpos[0].col, NULL, NULL); - if (!nmatched) { + if (nmatched != 0) { break; } } while (direction == FORWARD @@ -4196,7 +4196,10 @@ static int is_one_char(char_u *pattern, bool move, pos_T *cur, && regmatch.startpos[0].lnum == regmatch.endpos[0].lnum && regmatch.startpos[0].col == regmatch.endpos[0].col); // one char width - if (!result && inc(&pos) >= 0 && pos.col == regmatch.endpos[0].col) { + if (!result + && nmatched != 0 + && inc(&pos) >= 0 + && pos.col == regmatch.endpos[0].col) { result = true; } } diff --git a/src/nvim/tag.c b/src/nvim/tag.c index 872fc0f279..0d42deed2b 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -1402,7 +1402,6 @@ find_tags( int low_char; // first char at low_offset int high_char; // first char at high_offset } search_info; - off_T filesize; int tagcmp; off_T offset; int round; @@ -1822,19 +1821,21 @@ line_read_in: state = TS_LINEAR; } - /* - * When starting a binary search, get the size of the file and - * compute the first offset. - */ + // When starting a binary search, get the size of the file and + // compute the first offset. if (state == TS_BINARY) { - // Get the tag file size. - if ((filesize = vim_lseek(fileno(fp), (off_T)0L, SEEK_END)) <= 0) { + if (vim_fseek(fp, 0, SEEK_END) != 0) { + // can't seek, don't use binary search state = TS_LINEAR; } else { - vim_lseek(fileno(fp), (off_T)0L, SEEK_SET); - - /* Calculate the first read offset in the file. Start - * the search in the middle of the file. */ + // Get the tag file size. + // Don't use lseek(), it doesn't work + // properly on MacOS Catalina. + const off_T filesize = vim_ftell(fp); + vim_fseek(fp, 0, SEEK_SET); + + // Calculate the first read offset in the file. Start + // the search in the middle of the file. search_info.low_offset = 0; search_info.low_char = 0; search_info.high_offset = filesize; diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index 8fcc8bf0a5..7609006906 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -220,8 +220,6 @@ Terminal *terminal_open(TerminalOptions opts) rv->sb_size = (size_t)curbuf->b_p_scbk; rv->sb_buffer = xmalloc(sizeof(ScrollbackLine *) * rv->sb_size); - vterm_state_set_bold_highbright(state, true); - // Configure the color palette. Try to get the color from: // // - b:terminal_color_{NUM} diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim index 8f5f3f82e7..5c2e570adf 100644 --- a/src/nvim/testdir/runtest.vim +++ b/src/nvim/testdir/runtest.vim @@ -289,11 +289,13 @@ let s:flaky_tests = [ \ 'Test_oneshot()', \ 'Test_out_cb()', \ 'Test_paused()', + \ 'Test_popup_and_window_resize()', \ 'Test_quoteplus()', \ 'Test_quotestar()', \ 'Test_reltime()', \ 'Test_repeat_many()', \ 'Test_repeat_three()', + \ 'Test_state()', \ 'Test_stop_all_in_callback()', \ 'Test_terminal_composing_unicode()', \ 'Test_terminal_redir_file()', diff --git a/src/nvim/testdir/test42.in b/src/nvim/testdir/test42.in Binary files differindex baa6e67d26..d9057e72fb 100644 --- a/src/nvim/testdir/test42.in +++ b/src/nvim/testdir/test42.in diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim index a871924d32..f1274b01c8 100644 --- a/src/nvim/testdir/test_alot.vim +++ b/src/nvim/testdir/test_alot.vim @@ -27,7 +27,6 @@ source test_jumps.vim source test_fileformat.vim source test_filetype.vim source test_lambda.vim -source test_mapping.vim source test_menu.vim source test_messages.vim source test_modeline.vim diff --git a/src/nvim/testdir/test_cindent.vim b/src/nvim/testdir/test_cindent.vim index f979e354ba..d9795d9335 100644 --- a/src/nvim/testdir/test_cindent.vim +++ b/src/nvim/testdir/test_cindent.vim @@ -19,23 +19,23 @@ func Test_cino_extern_c() " Test for cino-E let without_ind =<< trim [CODE] - #ifdef __cplusplus - extern "C" { - #endif - int func_a(void); - #ifdef __cplusplus - } - #endif + #ifdef __cplusplus + extern "C" { + #endif + int func_a(void); + #ifdef __cplusplus + } + #endif [CODE] let with_ind =<< trim [CODE] - #ifdef __cplusplus - extern "C" { - #endif - int func_a(void); - #ifdef __cplusplus - } - #endif + #ifdef __cplusplus + extern "C" { + #endif + int func_a(void); + #ifdef __cplusplus + } + #endif [CODE] new setlocal cindent cinoptions=E0 @@ -90,30 +90,30 @@ func Test_cindent_expr() endfunc setl expandtab sw=8 indentkeys+=; indentexpr=MyIndentFunction() let testinput =<< trim [CODE] - var_a = something() - b = something() + var_a = something() + b = something() [CODE] call setline(1, testinput) call cursor(1, 1) call feedkeys("^\<c-v>j$A;\<esc>", 'tnix') - let expected =<< trim [CODE] - var_a = something(); - b = something(); - [CODE] + let expected =<< [CODE] + var_a = something(); +b = something(); +[CODE] call assert_equal(expected, getline(1, '$')) %d - let testinput =<< trim [CODE] - var_a = something() - b = something() - [CODE] + let testinput =<< [CODE] + var_a = something() + b = something() +[CODE] call setline(1, testinput) call cursor(1, 1) call feedkeys("^\<c-v>j$A;\<esc>", 'tnix') - let expected =<< trim [CODE] - var_a = something(); - b = something() - [CODE] + let expected =<< [CODE] + var_a = something(); + b = something() +[CODE] call assert_equal(expected, getline(1, '$')) bw! endfunc diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim index e6aafd964b..0a3e6ae625 100644 --- a/src/nvim/testdir/test_cmdline.vim +++ b/src/nvim/testdir/test_cmdline.vim @@ -1,6 +1,5 @@ " Tests for editing the command line. - func Test_complete_tab() call writefile(['testfile'], 'Xtestfile') call feedkeys(":e Xtestf\t\r", "tx") @@ -477,6 +476,50 @@ func Test_cmdline_complete_user_cmd() delcommand Foo endfunc +func Test_cmdline_complete_user_names() + if has('unix') && executable('whoami') + let whoami = systemlist('whoami')[0] + let first_letter = whoami[0] + if len(first_letter) > 0 + " Trying completion of :e ~x where x is the first letter of + " the user name should complete to at least the user name. + call feedkeys(':e ~' . first_letter . "\<c-a>\<c-B>\"\<cr>", 'tx') + call assert_match('^"e \~.*\<' . whoami . '\>', @:) + endif + endif + if has('win32') + " Just in case: check that the system has an Administrator account. + let names = system('net user') + if names =~ 'Administrator' + " Trying completion of :e ~A should complete to Administrator. + call feedkeys(':e ~A' . "\<c-a>\<c-B>\"\<cr>", 'tx') + call assert_match('^"e \~Administrator', @:) + endif + endif +endfunc + +funct Test_cmdline_complete_languages() + let lang = substitute(execute('language messages'), '.*"\(.*\)"$', '\1', '') + + call feedkeys(":language \<c-a>\<c-b>\"\<cr>", 'tx') + call assert_match('^"language .*\<ctype\>.*\<messages\>.*\<time\>', @:) + + if has('unix') + " TODO: these tests don't work on Windows. lang appears to be 'C' + " but C does not appear in the completion. Why? + call assert_match('^"language .*\<' . lang . '\>', @:) + + call feedkeys(":language messages \<c-a>\<c-b>\"\<cr>", 'tx') + call assert_match('^"language .*\<' . lang . '\>', @:) + + call feedkeys(":language ctype \<c-a>\<c-b>\"\<cr>", 'tx') + call assert_match('^"language .*\<' . lang . '\>', @:) + + call feedkeys(":language time \<c-a>\<c-b>\"\<cr>", 'tx') + call assert_match('^"language .*\<' . lang . '\>', @:) + endif +endfunc + func Test_cmdline_write_alternatefile() new call setline('.', ['one', 'two']) diff --git a/src/nvim/testdir/test_debugger.vim b/src/nvim/testdir/test_debugger.vim index 3ef460b4fe..130bcf8910 100644 --- a/src/nvim/testdir/test_debugger.vim +++ b/src/nvim/testdir/test_debugger.vim @@ -26,27 +26,29 @@ func Test_Debugger() endif " Create a Vim script with some functions - call writefile([ - \ 'func Foo()', - \ ' let var1 = 1', - \ ' let var2 = Bar(var1) + 9', - \ ' return var2', - \ 'endfunc', - \ 'func Bar(var)', - \ ' let var1 = 2 + a:var', - \ ' let var2 = Bazz(var1) + 4', - \ ' return var2', - \ 'endfunc', - \ 'func Bazz(var)', - \ ' try', - \ ' let var1 = 3 + a:var', - \ ' let var3 = "another var"', - \ ' let var3 = "value2"', - \ ' catch', - \ ' let var4 = "exception"', - \ ' endtry', - \ ' return var1', - \ 'endfunc'], 'Xtest.vim') + let lines =<< trim END + func Foo() + let var1 = 1 + let var2 = Bar(var1) + 9 + return var2 + endfunc + func Bar(var) + let var1 = 2 + a:var + let var2 = Bazz(var1) + 4 + return var2 + endfunc + func Bazz(var) + try + let var1 = 3 + a:var + let var3 = "another var" + let var3 = "value2" + catch + let var4 = "exception" + endtry + return var1 + endfunc + END + call writefile(lines, 'Xtest.vim') " Start Vim in a terminal let buf = RunVimInTerminal('-S Xtest.vim', {}) @@ -294,11 +296,13 @@ func Test_Debugger() " Tests for :breakadd file and :breakadd here " Breakpoints should be set before sourcing the file - call writefile([ - \ 'let var1 = 10', - \ 'let var2 = 20', - \ 'let var3 = 30', - \ 'let var4 = 40'], 'Xtest.vim') + let lines =<< trim END + let var1 = 10 + let var2 = 20 + let var3 = 30 + let var4 = 40 + END + call writefile(lines, 'Xtest.vim') " Start Vim in a terminal let buf = RunVimInTerminal('Xtest.vim', {}) diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim index 7512d599b8..4053746c82 100644 --- a/src/nvim/testdir/test_filetype.vim +++ b/src/nvim/testdir/test_filetype.vim @@ -122,6 +122,7 @@ let s:filename_checks = { \ 'cvs': ['cvs123'], \ 'cvsrc': ['.cvsrc'], \ 'cynpp': ['file.cyn'], + \ 'dart': ['file.dart', 'file.drt'], \ 'datascript': ['file.ds'], \ 'dcd': ['file.dcd'], \ 'debcontrol': ['/debian/control'], @@ -201,6 +202,7 @@ let s:filename_checks = { \ 'hex': ['file.hex', 'file.h32'], \ 'hgcommit': ['hg-editor-file.txt'], \ 'hog': ['file.hog', 'snort.conf', 'vision.conf'], + \ 'hollywood': ['file.hws'], \ 'hostconf': ['/etc/host.conf'], \ 'hostsaccess': ['/etc/hosts.allow', '/etc/hosts.deny'], \ 'template': ['file.tmpl'], @@ -273,6 +275,7 @@ let s:filename_checks = { \ 'mason': ['file.mason', 'file.mhtml', 'file.comp'], \ 'master': ['file.mas', 'file.master'], \ 'mel': ['file.mel'], + \ 'meson': ['meson.build', 'meson_options.txt'], \ 'messages': ['/log/auth', '/log/cron', '/log/daemon', '/log/debug', '/log/kern', '/log/lpr', '/log/mail', '/log/messages', '/log/news/news', '/log/syslog', '/log/user', \ '/log/auth.log', '/log/cron.log', '/log/daemon.log', '/log/debug.log', '/log/kern.log', '/log/lpr.log', '/log/mail.log', '/log/messages.log', '/log/news/news.log', '/log/syslog.log', '/log/user.log', \ '/log/auth.err', '/log/cron.err', '/log/daemon.err', '/log/debug.err', '/log/kern.err', '/log/lpr.err', '/log/mail.err', '/log/messages.err', '/log/news/news.err', '/log/syslog.err', '/log/user.err', diff --git a/src/nvim/testdir/test_fnamemodify.vim b/src/nvim/testdir/test_fnamemodify.vim index 63f273677d..116d23ba88 100644 --- a/src/nvim/testdir/test_fnamemodify.vim +++ b/src/nvim/testdir/test_fnamemodify.vim @@ -45,3 +45,31 @@ func Test_fnamemodify() let $HOME = save_home let &shell = save_shell endfunc + +func Test_fnamemodify_er() + call assert_equal("with", fnamemodify("path/to/file.with.extensions", ':e:e:r:r')) + + call assert_equal('c', fnamemodify('a.c', ':e')) + call assert_equal('c', fnamemodify('a.c', ':e:e')) + call assert_equal('c', fnamemodify('a.c', ':e:e:r')) + call assert_equal('c', fnamemodify('a.c', ':e:e:r:r')) + + call assert_equal('rb', fnamemodify('a.spec.rb', ':e:r')) + call assert_equal('rb', fnamemodify('a.spec.rb', ':e:r')) + call assert_equal('spec.rb', fnamemodify('a.spec.rb', ':e:e')) + call assert_equal('spec', fnamemodify('a.spec.rb', ':e:e:r')) + call assert_equal('spec', fnamemodify('a.spec.rb', ':e:e:r:r')) + call assert_equal('spec', fnamemodify('a.b.spec.rb', ':e:e:r')) + call assert_equal('b.spec', fnamemodify('a.b.spec.rb', ':e:e:e:r')) + call assert_equal('b', fnamemodify('a.b.spec.rb', ':e:e:e:r:r')) + + call assert_equal('spec', fnamemodify('a.b.spec.rb', ':r:e')) + call assert_equal('b', fnamemodify('a.b.spec.rb', ':r:r:e')) + + call assert_equal('c', fnamemodify('a.b.c.d.e', ':r:r:e')) + call assert_equal('b.c', fnamemodify('a.b.c.d.e', ':r:r:e:e')) + + " :e never includes the whole filename, so "a.b":e:e:e --> "b" + call assert_equal('b.c', fnamemodify('a.b.c.d.e', ':r:r:e:e:e')) + call assert_equal('b.c', fnamemodify('a.b.c.d.e', ':r:r:e:e:e:e')) +endfunc diff --git a/src/nvim/testdir/test_goto.vim b/src/nvim/testdir/test_goto.vim index f04a5a7e3d..19513b315a 100644 --- a/src/nvim/testdir/test_goto.vim +++ b/src/nvim/testdir/test_goto.vim @@ -16,12 +16,12 @@ endfunc func Test_gD() let lines =<< trim [CODE] - int x; - - int func(void) - { - return x; - } + int x; + + int func(void) + { + return x; + } [CODE] call XTest_goto_decl('gD', lines, 1, 5) @@ -29,12 +29,12 @@ endfunc func Test_gD_too() let lines =<< trim [CODE] - Filename x; - - int Filename - int func() { Filename x; - return x; + + int Filename + int func() { + Filename x; + return x; [CODE] call XTest_goto_decl('gD', lines, 1, 10) @@ -42,13 +42,13 @@ endfunc func Test_gD_comment() let lines =<< trim [CODE] - /* int x; */ - int x; - - int func(void) - { - return x; - } + /* int x; */ + int x; + + int func(void) + { + return x; + } [CODE] call XTest_goto_decl('gD', lines, 2, 5) @@ -56,13 +56,13 @@ endfunc func Test_gD_inline_comment() let lines =<< trim [CODE] - int y /* , x */; - int x; - - int func(void) - { - return x; - } + int y /* , x */; + int x; + + int func(void) + { + return x; + } [CODE] call XTest_goto_decl('gD', lines, 2, 5) @@ -70,13 +70,13 @@ endfunc func Test_gD_string() let lines =<< trim [CODE] - char *s[] = "x"; - int x = 1; - - int func(void) - { - return x; - } + char *s[] = "x"; + int x = 1; + + int func(void) + { + return x; + } [CODE] call XTest_goto_decl('gD', lines, 2, 5) @@ -84,12 +84,12 @@ endfunc func Test_gD_string_same_line() let lines =<< trim [CODE] - char *s[] = "x", int x = 1; - - int func(void) - { - return x; - } + char *s[] = "x", int x = 1; + + int func(void) + { + return x; + } [CODE] call XTest_goto_decl('gD', lines, 1, 22) @@ -97,13 +97,13 @@ endfunc func Test_gD_char() let lines =<< trim [CODE] - char c = 'x'; - int x = 1; - - int func(void) - { - return x; - } + char c = 'x'; + int x = 1; + + int func(void) + { + return x; + } [CODE] call XTest_goto_decl('gD', lines, 2, 5) @@ -111,12 +111,12 @@ endfunc func Test_gd() let lines =<< trim [CODE] - int x; - - int func(int x) - { - return x; - } + int x; + + int func(int x) + { + return x; + } [CODE] call XTest_goto_decl('gd', lines, 3, 14) @@ -124,15 +124,15 @@ endfunc func Test_gd_not_local() let lines =<< trim [CODE] - int func1(void) - { - return x; - } - - int func2(int x) - { - return x; - } + int func1(void) + { + return x; + } + + int func2(int x) + { + return x; + } [CODE] call XTest_goto_decl('gd', lines, 3, 10) @@ -140,11 +140,11 @@ endfunc func Test_gd_kr_style() let lines =<< trim [CODE] - int func(x) - int x; - { - return x; - } + int func(x) + int x; + { + return x; + } [CODE] call XTest_goto_decl('gd', lines, 2, 7) @@ -152,15 +152,15 @@ endfunc func Test_gd_missing_braces() let lines =<< trim [CODE] - def func1(a) - a + 1 - end - - a = 1 - - def func2() - return a - end + def func1(a) + a + 1 + end + + a = 1 + + def func2() + return a + end [CODE] call XTest_goto_decl('gd', lines, 1, 11) @@ -168,12 +168,12 @@ endfunc func Test_gd_comment() let lines =<< trim [CODE] - int func(void) - { - /* int x; */ - int x; - return x; - } + int func(void) + { + /* int x; */ + int x; + return x; + } [CODE] call XTest_goto_decl('gd', lines, 4, 7) @@ -181,12 +181,12 @@ endfunc func Test_gd_comment_in_string() let lines =<< trim [CODE] - int func(void) - { - char *s ="//"; int x; - int x; - return x; - } + int func(void) + { + char *s ="//"; int x; + int x; + return x; + } [CODE] call XTest_goto_decl('gd', lines, 3, 22) @@ -195,12 +195,12 @@ endfunc func Test_gd_string_in_comment() set comments= let lines =<< trim [CODE] - int func(void) - { - /* " */ int x; - int x; - return x; - } + int func(void) + { + /* " */ int x; + int x; + return x; + } [CODE] call XTest_goto_decl('gd', lines, 3, 15) @@ -209,10 +209,10 @@ endfunc func Test_gd_inline_comment() let lines =<< trim [CODE] - int func(/* x is an int */ int x) - { - return x; - } + int func(/* x is an int */ int x) + { + return x; + } [CODE] call XTest_goto_decl('gd', lines, 1, 32) @@ -220,10 +220,10 @@ endfunc func Test_gd_inline_comment_only() let lines =<< trim [CODE] - int func(void) /* one lonely x */ - { - return x; - } + int func(void) /* one lonely x */ + { + return x; + } [CODE] call XTest_goto_decl('gd', lines, 3, 10) @@ -231,16 +231,16 @@ endfunc func Test_gd_inline_comment_body() let lines =<< trim [CODE] - int func(void) - { - int y /* , x */; - - for (/* int x = 0 */; y < 2; y++); - - int x = 0; - - return x; - } + int func(void) + { + int y /* , x */; + + for (/* int x = 0 */; y < 2; y++); + + int x = 0; + + return x; + } [CODE] call XTest_goto_decl('gd', lines, 7, 7) @@ -248,10 +248,10 @@ endfunc func Test_gd_trailing_multiline_comment() let lines =<< trim [CODE] - int func(int x) /* x is an int */ - { - return x; - } + int func(int x) /* x is an int */ + { + return x; + } [CODE] call XTest_goto_decl('gd', lines, 1, 14) @@ -259,10 +259,10 @@ endfunc func Test_gd_trailing_comment() let lines =<< trim [CODE] - int func(int x) // x is an int - { - return x; - } + int func(int x) // x is an int + { + return x; + } [CODE] call XTest_goto_decl('gd', lines, 1, 14) @@ -270,13 +270,13 @@ endfunc func Test_gd_string() let lines =<< trim [CODE] - int func(void) - { - char *s = "x"; - int x = 1; - - return x; - } + int func(void) + { + char *s = "x"; + int x = 1; + + return x; + } [CODE] call XTest_goto_decl('gd', lines, 4, 7) @@ -284,12 +284,12 @@ endfunc func Test_gd_string_only() let lines =<< trim [CODE] - int func(void) - { - char *s = "x"; - - return x; - } + int func(void) + { + char *s = "x"; + + return x; + } [CODE] call XTest_goto_decl('gd', lines, 5, 10) @@ -312,21 +312,21 @@ endfunc func Test_gd_local_block() let lines =<< trim [CODE] int main() - { - char *a = "NOT NULL"; - if(a) - { - char *b = a; - printf("%s\n", b); - } - else { - char *b = "NULL"; - return b; + char *a = "NOT NULL"; + if(a) + { + char *b = a; + printf("%s\n", b); + } + else + { + char *b = "NULL"; + return b; + } + + return 0; } - - return 0; - } [CODE] call XTest_goto_decl('1gd', lines, 11, 11) diff --git a/src/nvim/testdir/test_let.vim b/src/nvim/testdir/test_let.vim index 43f35e2b9d..1fce3d6937 100644 --- a/src/nvim/testdir/test_let.vim +++ b/src/nvim/testdir/test_let.vim @@ -153,14 +153,37 @@ func Test_let_heredoc_fails() call assert_fails('source XheredocFail', 'E126:') call delete('XheredocFail') - let text =<< trim END + let text =<< trim CodeEnd func MissingEnd() let v =<< END endfunc - END + CodeEnd call writefile(text, 'XheredocWrong') call assert_fails('source XheredocWrong', 'E126:') call delete('XheredocWrong') + + let text =<< trim TEXTend + let v =<< " comment + TEXTend + call writefile(text, 'XheredocNoMarker') + call assert_fails('source XheredocNoMarker', 'E172:') + call delete('XheredocNoMarker') + + let text =<< trim TEXTend + let v =<< text + TEXTend + call writefile(text, 'XheredocBadMarker') + call assert_fails('source XheredocBadMarker', 'E221:') + call delete('XheredocBadMarker') +endfunc + +func Test_let_heredoc_trim_no_indent_marker() + let text =<< trim END + Text + with + indent +END + call assert_equal(['Text', 'with', 'indent'], text) endfunc " Test for the setting a variable using the heredoc syntax @@ -173,9 +196,9 @@ END call assert_equal(["Some sample text", "\tText with indent", " !@#$%^&*()-+_={}|[]\\~`:\";'<>?,./"], var1) - let var2 =<< + let var2 =<< XXX Editor -. +XXX call assert_equal(['Editor'], var2) let var3 =<<END @@ -199,10 +222,18 @@ END END call assert_equal(['Line1', ' Line2', "\tLine3", ' END'], var1) - let var1 =<< trim + let var1 =<< trim !!! + Line1 + line2 + Line3 + !!! + !!! + call assert_equal(['Line1', ' line2', "\tLine3", '!!!',], var1) + + let var1 =<< trim XX Line1 - . - call assert_equal([' Line1'], var1) + XX + call assert_equal(['Line1'], var1) " ignore "endfunc" let var1 =<< END @@ -233,16 +264,24 @@ END call assert_equal(['something', 'python << xx'], var1) " ignore "append" - let var1 =<< + let var1 =<< E something app -. +E call assert_equal(['something', 'app'], var1) " ignore "append" with trim - let var1 =<< trim + let var1 =<< trim END something app - . + END call assert_equal(['something', 'app'], var1) + + let check = [] + if 0 + let check =<< trim END + from heredoc + END + endif + call assert_equal([], check) endfunc diff --git a/src/nvim/testdir/test_mksession_utf8.vim b/src/nvim/testdir/test_mksession_utf8.vim index 36f07512a8..722fd28beb 100644 --- a/src/nvim/testdir/test_mksession_utf8.vim +++ b/src/nvim/testdir/test_mksession_utf8.vim @@ -66,32 +66,32 @@ func Test_mksession_utf8() mksession! test_mks.out let li = filter(readfile('test_mks.out'), 'v:val =~# "\\(^ *normal! 0\\|^ *exe ''normal!\\)"') let expected =<< trim [DATA] - normal! 016| - normal! 016| - normal! 016| - normal! 08| - normal! 08| - normal! 016| - normal! 016| - normal! 016| - exe 'normal! ' . s:c . '|zs' . 16 . '|' normal! 016| - exe 'normal! ' . s:c . '|zs' . 16 . '|' normal! 016| - exe 'normal! ' . s:c . '|zs' . 16 . '|' normal! 016| - exe 'normal! ' . s:c . '|zs' . 8 . '|' normal! 08| - exe 'normal! ' . s:c . '|zs' . 8 . '|' normal! 08| - exe 'normal! ' . s:c . '|zs' . 16 . '|' normal! 016| - exe 'normal! ' . s:c . '|zs' . 16 . '|' normal! 016| - exe 'normal! ' . s:c . '|zs' . 16 . '|' - normal! 016| - exe 'normal! ' . s:c . '|zs' . 16 . '|' normal! 016| + exe 'normal! ' . s:c . '|zs' . 16 . '|' + normal! 016| + exe 'normal! ' . s:c . '|zs' . 16 . '|' + normal! 016| + exe 'normal! ' . s:c . '|zs' . 16 . '|' + normal! 016| + exe 'normal! ' . s:c . '|zs' . 8 . '|' + normal! 08| + exe 'normal! ' . s:c . '|zs' . 8 . '|' + normal! 08| + exe 'normal! ' . s:c . '|zs' . 16 . '|' + normal! 016| + exe 'normal! ' . s:c . '|zs' . 16 . '|' + normal! 016| + exe 'normal! ' . s:c . '|zs' . 16 . '|' + normal! 016| + exe 'normal! ' . s:c . '|zs' . 16 . '|' + normal! 016| [DATA] call assert_equal(expected, li) diff --git a/src/nvim/testdir/test_normal.vim b/src/nvim/testdir/test_normal.vim index b967f84626..07d250cace 100644 --- a/src/nvim/testdir/test_normal.vim +++ b/src/nvim/testdir/test_normal.vim @@ -1564,34 +1564,34 @@ endfunc fun! Test_normal29_brace() " basic test for { and } movements let text =<< trim [DATA] - A paragraph begins after each empty line, and also at each of a set of - paragraph macros, specified by the pairs of characters in the 'paragraphs' - option. The default is "IPLPPPQPP TPHPLIPpLpItpplpipbp", which corresponds to - the macros ".IP", ".LP", etc. (These are nroff macros, so the dot must be in - the first column). A section boundary is also a paragraph boundary. - Note that a blank line (only containing white space) is NOT a paragraph - boundary. - - - Also note that this does not include a '{' or '}' in the first column. When - the '{' flag is in 'cpoptions' then '{' in the first column is used as a - paragraph boundary |posix|. - { - This is no paragraph - unless the '{' is set - in 'cpoptions' - } - .IP - The nroff macros IP separates a paragraph - That means, it must be a '.' - followed by IP - .LPIt does not matter, if afterwards some - more characters follow. - .SHAlso section boundaries from the nroff - macros terminate a paragraph. That means - a character like this: - .NH - End of text here + A paragraph begins after each empty line, and also at each of a set of + paragraph macros, specified by the pairs of characters in the 'paragraphs' + option. The default is "IPLPPPQPP TPHPLIPpLpItpplpipbp", which corresponds to + the macros ".IP", ".LP", etc. (These are nroff macros, so the dot must be in + the first column). A section boundary is also a paragraph boundary. + Note that a blank line (only containing white space) is NOT a paragraph + boundary. + + + Also note that this does not include a '{' or '}' in the first column. When + the '{' flag is in 'cpoptions' then '{' in the first column is used as a + paragraph boundary |posix|. + { + This is no paragraph + unless the '{' is set + in 'cpoptions' + } + .IP + The nroff macros IP separates a paragraph + That means, it must be a '.' + followed by IP + .LPIt does not matter, if afterwards some + more characters follow. + .SHAlso section boundaries from the nroff + macros terminate a paragraph. That means + a character like this: + .NH + End of text here [DATA] new @@ -1600,17 +1600,17 @@ fun! Test_normal29_brace() norm! 0d2} let expected =<< trim [DATA] - .IP - The nroff macros IP separates a paragraph - That means, it must be a '.' - followed by IP - .LPIt does not matter, if afterwards some - more characters follow. - .SHAlso section boundaries from the nroff - macros terminate a paragraph. That means - a character like this: - .NH - End of text here + .IP + The nroff macros IP separates a paragraph + That means, it must be a '.' + followed by IP + .LPIt does not matter, if afterwards some + more characters follow. + .SHAlso section boundaries from the nroff + macros terminate a paragraph. That means + a character like this: + .NH + End of text here [DATA] call assert_equal(expected, getline(1, '$')) @@ -1618,13 +1618,13 @@ fun! Test_normal29_brace() norm! 0d} let expected =<< trim [DATA] - .LPIt does not matter, if afterwards some - more characters follow. - .SHAlso section boundaries from the nroff - macros terminate a paragraph. That means - a character like this: - .NH - End of text here + .LPIt does not matter, if afterwards some + more characters follow. + .SHAlso section boundaries from the nroff + macros terminate a paragraph. That means + a character like this: + .NH + End of text here [DATA] call assert_equal(expected, getline(1, '$')) @@ -1633,11 +1633,11 @@ fun! Test_normal29_brace() norm! d{ let expected =<< trim [DATA] - .LPIt does not matter, if afterwards some - more characters follow. - .SHAlso section boundaries from the nroff - macros terminate a paragraph. That means - a character like this: + .LPIt does not matter, if afterwards some + more characters follow. + .SHAlso section boundaries from the nroff + macros terminate a paragraph. That means + a character like this: [DATA] call assert_equal(expected, getline(1, '$')) @@ -1645,8 +1645,8 @@ fun! Test_normal29_brace() norm! d{ let expected =<< trim [DATA] - .LPIt does not matter, if afterwards some - more characters follow. + .LPIt does not matter, if afterwards some + more characters follow. [DATA] call assert_equal(expected, getline(1, '$')) @@ -1659,22 +1659,22 @@ fun! Test_normal29_brace() " 1 " norm! 0d2} " let expected =<< trim [DATA] - " { - " This is no paragraph - " unless the '{' is set - " in 'cpoptions' - " } - " .IP - " The nroff macros IP separates a paragraph - " That means, it must be a '.' - " followed by IP - " .LPIt does not matter, if afterwards some - " more characters follow. - " .SHAlso section boundaries from the nroff - " macros terminate a paragraph. That means - " a character like this: - " .NH - " End of text here + " { + " This is no paragraph + " unless the '{' is set + " in 'cpoptions' + " } + " .IP + " The nroff macros IP separates a paragraph + " That means, it must be a '.' + " followed by IP + " .LPIt does not matter, if afterwards some + " more characters follow. + " .SHAlso section boundaries from the nroff + " macros terminate a paragraph. That means + " a character like this: + " .NH + " End of text here " " [DATA] " call assert_equal(expected, getline(1, '$')) @@ -1682,22 +1682,22 @@ fun! Test_normal29_brace() " $ " norm! d} " let expected =<< trim [DATA] - " { - " This is no paragraph - " unless the '{' is set - " in 'cpoptions' - " } - " .IP - " The nroff macros IP separates a paragraph - " That means, it must be a '.' - " followed by IP - " .LPIt does not matter, if afterwards some - " more characters follow. - " .SHAlso section boundaries from the nroff - " macros terminate a paragraph. That means - " a character like this: - " .NH - " End of text here + " { + " This is no paragraph + " unless the '{' is set + " in 'cpoptions' + " } + " .IP + " The nroff macros IP separates a paragraph + " That means, it must be a '.' + " followed by IP + " .LPIt does not matter, if afterwards some + " more characters follow. + " .SHAlso section boundaries from the nroff + " macros terminate a paragraph. That means + " a character like this: + " .NH + " End of text here " " [DATA] " call assert_equal(expected, getline(1, '$')) @@ -1706,11 +1706,11 @@ fun! Test_normal29_brace() " norm! d5} " " let expected =<< trim [DATA] - " { - " This is no paragraph - " unless the '{' is set - " in 'cpoptions' - " } + " { + " This is no paragraph + " unless the '{' is set + " in 'cpoptions' + " } " [DATA] " call assert_equal(expected, getline(1, '$')) @@ -2813,4 +2813,29 @@ func Test_normal_gk() call assert_equal(95, virtcol('.')) bw! bw! + + " needs 80 column new window + new + vert 80new + set number + set numberwidth=10 + set cpoptions+=n + put =[repeat('0',90), repeat('1',90)] + norm! 075l + call assert_equal(76, col('.')) + norm! gk + call assert_equal(1, col('.')) + norm! gk + call assert_equal(76, col('.')) + norm! gk + call assert_equal(1, col('.')) + norm! gj + call assert_equal(76, col('.')) + norm! gj + call assert_equal(1, col('.')) + norm! gj + call assert_equal(76, col('.')) + bw! + bw! + set cpoptions& number& numberwidth& endfunc diff --git a/src/nvim/testdir/test_popup.vim b/src/nvim/testdir/test_popup.vim index c63269e5d2..8083672808 100644 --- a/src/nvim/testdir/test_popup.vim +++ b/src/nvim/testdir/test_popup.vim @@ -737,11 +737,12 @@ func Test_popup_position() if !CanRunVimInTerminal() return endif - call writefile([ - \ '123456789_123456789_123456789_a', - \ '123456789_123456789_123456789_b', - \ ' 123', - \ ], 'Xtest') + let lines =<< trim END + 123456789_123456789_123456789_a + 123456789_123456789_123456789_b + 123 + END + call writefile(lines, 'Xtest') let buf = RunVimInTerminal('Xtest', {}) call term_sendkeys(buf, ":vsplit\<CR>") diff --git a/src/nvim/testdir/test_profile.vim b/src/nvim/testdir/test_profile.vim index 4ab20a9c77..f3eb88abf0 100644 --- a/src/nvim/testdir/test_profile.vim +++ b/src/nvim/testdir/test_profile.vim @@ -312,13 +312,13 @@ endfunc func Test_profile_file() let lines =<< trim [CODE] - func! Foo() - endfunc - for i in range(10) - " a comment + func! Foo() + endfunc + for i in range(10) + " a comment + call Foo() + endfor call Foo() - endfor - call Foo() [CODE] call writefile(lines, 'Xprofile_file.vim') diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index b9a22aff51..fc514fc9e6 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -776,67 +776,67 @@ func Test_efm1() endif let l =<< trim [DATA] - "Xtestfile", line 4.12: 1506-045 (S) Undeclared identifier fd_set. - "Xtestfile", line 6 col 19; this is an error - gcc -c -DHAVE_CONFIsing-prototypes -I/usr/X11R6/include version.c - Xtestfile:9: parse error before `asd' - make: *** [vim] Error 1 - in file "Xtestfile" linenr 10: there is an error - - 2 returned - "Xtestfile", line 11 col 1; this is an error - "Xtestfile", line 12 col 2; this is another error - "Xtestfile", line 14:10; this is an error in column 10 - =Xtestfile=, line 15:10; this is another error, but in vcol 10 this time - "Xtestfile", linenr 16: yet another problem - Error in "Xtestfile" at line 17: - x should be a dot - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 17 - ^ - Error in "Xtestfile" at line 18: - x should be a dot - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 18 - .............^ - Error in "Xtestfile" at line 19: - x should be a dot - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 19 - --------------^ - Error in "Xtestfile" at line 20: - x should be a dot - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 20 - ^ - - Does anyone know what is the problem and how to correction it? - "Xtestfile", line 21 col 9: What is the title of the quickfix window? - "Xtestfile", line 22 col 9: What is the title of the quickfix window? + "Xtestfile", line 4.12: 1506-045 (S) Undeclared identifier fd_set. + "Xtestfile", line 6 col 19; this is an error + gcc -c -DHAVE_CONFIsing-prototypes -I/usr/X11R6/include version.c + Xtestfile:9: parse error before `asd' + make: *** [vim] Error 1 + in file "Xtestfile" linenr 10: there is an error + + 2 returned + "Xtestfile", line 11 col 1; this is an error + "Xtestfile", line 12 col 2; this is another error + "Xtestfile", line 14:10; this is an error in column 10 + =Xtestfile=, line 15:10; this is another error, but in vcol 10 this time + "Xtestfile", linenr 16: yet another problem + Error in "Xtestfile" at line 17: + x should be a dot + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 17 + ^ + Error in "Xtestfile" at line 18: + x should be a dot + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 18 + .............^ + Error in "Xtestfile" at line 19: + x should be a dot + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 19 + --------------^ + Error in "Xtestfile" at line 20: + x should be a dot + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 20 + ^ + + Does anyone know what is the problem and how to correction it? + "Xtestfile", line 21 col 9: What is the title of the quickfix window? + "Xtestfile", line 22 col 9: What is the title of the quickfix window? [DATA] call writefile(l, 'Xerrorfile1') call writefile(l[:-2], 'Xerrorfile2') - let m =<< trim [DATA] - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 2 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 3 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 4 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 5 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 6 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 7 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 8 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 9 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 10 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 11 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 12 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 13 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 14 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 15 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 16 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 17 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 18 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 19 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 20 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 21 - xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 22 - [DATA] + let m =<< [DATA] + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 2 + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 3 + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 4 + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 5 + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 6 + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 7 + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 8 + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 9 + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 10 + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 11 + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 12 + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 13 + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 14 + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 15 + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 16 + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 17 + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 18 + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 19 + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 20 + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 21 + xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx line 22 +[DATA] call writefile(m, 'Xtestfile') let save_efm = &efm @@ -1053,20 +1053,20 @@ func Test_efm2() " Test for %P, %Q and %t format specifiers let lines =<< trim [DATA] - [Xtestfile1] - (1,17) error: ';' missing - (21,2) warning: variable 'z' not defined - (67,3) error: end of file found before string ended - -- - - [Xtestfile2] - -- - - [Xtestfile3] - NEW compiler v1.1 - (2,2) warning: variable 'x' not defined - (67,3) warning: 's' already defined - - + [Xtestfile1] + (1,17) error: ';' missing + (21,2) warning: variable 'z' not defined + (67,3) error: end of file found before string ended + -- + + [Xtestfile2] + -- + + [Xtestfile3] + NEW compiler v1.1 + (2,2) warning: variable 'x' not defined + (67,3) warning: 's' already defined + -- [DATA] set efm=%+P[%f]%r,(%l\\,%c)%*[\ ]%t%*[^:]:\ %m,%+Q--%r " To exercise the push/pop file functionality in quickfix, the test files @@ -1090,10 +1090,10 @@ func Test_efm2() " Tests for %E, %C and %Z format specifiers let lines =<< trim [DATA] - Error 275 - line 42 - column 3 - ' ' expected after '--' + Error 275 + line 42 + column 3 + ' ' expected after '--' [DATA] set efm=%EError\ %n,%Cline\ %l,%Ccolumn\ %c,%Z%m @@ -1107,8 +1107,8 @@ func Test_efm2() " Test for %> let lines =<< trim [DATA] - Error in line 147 of foo.c: - unknown variable 'i' + Error in line 147 of foo.c: + unknown variable 'i' [DATA] set efm=unknown\ variable\ %m,%E%>Error\ in\ line\ %l\ of\ %f:,%Z%m diff --git a/src/nvim/testdir/test_recover.vim b/src/nvim/testdir/test_recover.vim index 09c8d1cda6..fc073cacd2 100644 --- a/src/nvim/testdir/test_recover.vim +++ b/src/nvim/testdir/test_recover.vim @@ -14,6 +14,12 @@ func Test_recover_root_dir() set dir=/notexist/ endif call assert_fails('split Xtest', 'E303:') + + " No error with empty 'directory' setting. + set directory= + split XtestOK + close! + set dir& endfunc diff --git a/src/nvim/testdir/test_vimscript.vim b/src/nvim/testdir/test_vimscript.vim index f39e53d6dd..3fcba4134e 100644 --- a/src/nvim/testdir/test_vimscript.vim +++ b/src/nvim/testdir/test_vimscript.vim @@ -1409,6 +1409,76 @@ func Test_compound_assignment_operators() let @/ = '' endfunc +func Test_function_defined_line() + if has('gui_running') + " Can't catch the output of gvim. + return + endif + + let lines =<< trim [CODE] + " F1 + func F1() + " F2 + func F2() + " + " + " + return + endfunc + " F3 + execute "func F3()\n\n\n\nreturn\nendfunc" + " F4 + execute "func F4()\n + \\n + \\n + \\n + \return\n + \endfunc" + endfunc + " F5 + execute "func F5()\n\n\n\nreturn\nendfunc" + " F6 + execute "func F6()\n + \\n + \\n + \\n + \return\n + \endfunc" + call F1() + verbose func F1 + verbose func F2 + verbose func F3 + verbose func F4 + verbose func F5 + verbose func F6 + qall! + [CODE] + + call writefile(lines, 'Xtest.vim') + let res = system(v:progpath .. ' --clean -es -X -S Xtest.vim') + call assert_equal(0, v:shell_error) + + let m = matchstr(res, 'function F1()[^[:print:]]*[[:print:]]*') + call assert_match(' line 2$', m) + + let m = matchstr(res, 'function F2()[^[:print:]]*[[:print:]]*') + call assert_match(' line 4$', m) + + let m = matchstr(res, 'function F3()[^[:print:]]*[[:print:]]*') + call assert_match(' line 11$', m) + + let m = matchstr(res, 'function F4()[^[:print:]]*[[:print:]]*') + call assert_match(' line 13$', m) + + let m = matchstr(res, 'function F5()[^[:print:]]*[[:print:]]*') + call assert_match(' line 21$', m) + + let m = matchstr(res, 'function F6()[^[:print:]]*[[:print:]]*') + call assert_match(' line 23$', m) + + call delete('Xtest.vim') +endfunc + "------------------------------------------------------------------------------- " Modelines {{{1 " vim: ts=8 sw=4 tw=80 fdm=marker diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 150862bb18..945b093f32 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -234,7 +234,9 @@ static void terminfo_start(UI *ui) // Set up unibilium/terminfo. char *termname = NULL; if (term) { + os_env_var_lock(); data->ut = unibi_from_term(term); + os_env_var_unlock(); if (data->ut) { termname = xstrdup(term); } diff --git a/test/functional/api/menu_spec.lua b/test/functional/api/menu_spec.lua index 2cfa0e3e47..34a92477f3 100644 --- a/test/functional/api/menu_spec.lua +++ b/test/functional/api/menu_spec.lua @@ -15,10 +15,6 @@ describe("update_menu notification", function() screen:attach() end) - after_each(function() - screen:detach() - end) - local function expect_sent(expected) screen:expect{condition=function() if screen.update_menu ~= expected then diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua index 5a9ef7dd40..237a4b01e4 100644 --- a/test/functional/api/server_requests_spec.lua +++ b/test/functional/api/server_requests_spec.lua @@ -317,8 +317,7 @@ describe('server -> client', function() set_session(server) local status, address = pcall(funcs.serverstart, "127.0.0.1:") if not status then - pending('no ipv4 stack', function() end) - return + pending('no ipv4 stack') end eq('127.0.0.1:', string.sub(address,1,10)) connect_test(server, 'tcp', address) @@ -329,8 +328,7 @@ describe('server -> client', function() set_session(server) local status, address = pcall(funcs.serverstart, '::1:') if not status then - pending('no ipv6 stack', function() end) - return + pending('no ipv6 stack') end eq('::1:', string.sub(address,1,4)) connect_test(server, 'tcp', address) @@ -347,11 +345,6 @@ describe('server -> client', function() describe('connecting to its own pipe address', function() it('does not deadlock', function() - if not helpers.isCI('travis') and helpers.is_os('mac') then - -- It does, in fact, deadlock on QuickBuild. #6851 - pending("deadlocks on QuickBuild", function() end) - return - end local address = funcs.serverlist()[1] local first = string.sub(address,1,1) ok(first == '/' or first == '\\') diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua index 9c37e55f42..d285008a33 100644 --- a/test/functional/core/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -202,8 +202,7 @@ describe('jobs', function() if helpers.isCI('travis') and os.getenv('CC') == 'gcc-4.9' and helpers.is_os('mac') then -- XXX: Hangs Travis macOS since e9061117a5b8f195c3f26a5cb94e18ddd7752d86. - pending("[Hangs on Travis macOS. #5002]", function() end) - return + pending("[Hangs on Travis macOS. #5002]") end nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)") @@ -963,9 +962,6 @@ describe("pty process teardown", function() | ]]) end) - after_each(function() - screen:detach() - end) it("does not prevent/delay exit. #4798 #4900", function() if helpers.pending_win32(pending) then return end diff --git a/test/functional/eval/api_functions_spec.lua b/test/functional/eval/api_functions_spec.lua index 4fbd08f102..f527aff33f 100644 --- a/test/functional/eval/api_functions_spec.lua +++ b/test/functional/eval/api_functions_spec.lua @@ -144,7 +144,6 @@ describe('eval-API', function() {5:~ }| | ]]) - screen:detach() end) it('cannot be called from sandbox', function() diff --git a/test/functional/eval/fnamemodify_spec.lua b/test/functional/eval/fnamemodify_spec.lua index fe6b50a544..d54a6db417 100644 --- a/test/functional/eval/fnamemodify_spec.lua +++ b/test/functional/eval/fnamemodify_spec.lua @@ -3,8 +3,14 @@ local clear = helpers.clear local eq = helpers.eq local iswin = helpers.iswin local fnamemodify = helpers.funcs.fnamemodify +local getcwd = helpers.funcs.getcwd local command = helpers.command local write_file = helpers.write_file +local alter_slashes = helpers.alter_slashes + +local function eq_slashconvert(expected, got) + eq(alter_slashes(expected), alter_slashes(got)) +end describe('fnamemodify()', function() setup(function() @@ -17,7 +23,7 @@ describe('fnamemodify()', function() os.remove('Xtest-fnamemodify.txt') end) - it('works', function() + it('handles the root path', function() local root = helpers.pathroot() eq(root, fnamemodify([[/]], ':p:h')) eq(root, fnamemodify([[/]], ':p')) @@ -36,4 +42,115 @@ describe('fnamemodify()', function() it(':8 works', function() eq('Xtest-fnamemodify.txt', fnamemodify([[Xtest-fnamemodify.txt]], ':8')) end) + + it('handles examples from ":help filename-modifiers"', function() + local filename = "src/version.c" + local cwd = getcwd() + + eq_slashconvert(cwd .. '/src/version.c', fnamemodify(filename, ':p')) + + eq_slashconvert('src/version.c', fnamemodify(filename, ':p:.')) + eq_slashconvert(cwd .. '/src', fnamemodify(filename, ':p:h')) + eq_slashconvert(cwd .. '', fnamemodify(filename, ':p:h:h')) + eq('version.c', fnamemodify(filename, ':p:t')) + eq_slashconvert(cwd .. '/src/version', fnamemodify(filename, ':p:r')) + + eq_slashconvert(cwd .. '/src/main.c', fnamemodify(filename, ':s?version?main?:p')) + + local converted_cwd = cwd:gsub('/', '\\') + eq(converted_cwd .. '\\src\\version.c', fnamemodify(filename, ':p:gs?/?\\\\?')) + + eq('src', fnamemodify(filename, ':h')) + eq('version.c', fnamemodify(filename, ':t')) + eq_slashconvert('src/version', fnamemodify(filename, ':r')) + eq('version', fnamemodify(filename, ':t:r')) + eq('c', fnamemodify(filename, ':e')) + + eq_slashconvert('src/main.c', fnamemodify(filename, ':s?version?main?')) + end) + + it('handles advanced examples from ":help filename-modifiers"', function() + local filename = "src/version.c.gz" + + eq('gz', fnamemodify(filename, ':e')) + eq('c.gz', fnamemodify(filename, ':e:e')) + eq('c.gz', fnamemodify(filename, ':e:e:e')) + + eq('c', fnamemodify(filename, ':e:e:r')) + + eq_slashconvert('src/version.c', fnamemodify(filename, ':r')) + eq('c', fnamemodify(filename, ':r:e')) + + eq_slashconvert('src/version', fnamemodify(filename, ':r:r')) + eq_slashconvert('src/version', fnamemodify(filename, ':r:r:r')) + end) + + it('handles :h', function() + eq('.', fnamemodify('hello.txt', ':h')) + + eq_slashconvert('path/to', fnamemodify('path/to/hello.txt', ':h')) + end) + + it('handles :t', function() + eq('hello.txt', fnamemodify('hello.txt', ':t')) + eq_slashconvert('hello.txt', fnamemodify('path/to/hello.txt', ':t')) + end) + + it('handles :r', function() + eq('hello', fnamemodify('hello.txt', ':r')) + eq_slashconvert('path/to/hello', fnamemodify('path/to/hello.txt', ':r')) + end) + + it('handles :e', function() + eq('txt', fnamemodify('hello.txt', ':e')) + eq_slashconvert('txt', fnamemodify('path/to/hello.txt', ':e')) + end) + + it('handles regex replacements', function() + eq('content-there-here.txt', fnamemodify('content-here-here.txt', ':s/here/there/')) + eq('content-there-there.txt', fnamemodify('content-here-here.txt', ':gs/here/there/')) + end) + + it('handles shell escape', function() + local expected + + if iswin() then + -- we expand with double-quotes on Windows + expected = [["hello there! quote ' newline]] .. '\n' .. [["]] + else + expected = [['hello there! quote '\'' newline]] .. '\n' .. [[']] + end + + eq(expected, fnamemodify("hello there! quote ' newline\n", ':S')) + end) + + it('can combine :e and :r', function() + -- simple, single extension filename + eq('c', fnamemodify('a.c', ':e')) + eq('c', fnamemodify('a.c', ':e:e')) + eq('c', fnamemodify('a.c', ':e:e:r')) + eq('c', fnamemodify('a.c', ':e:e:r:r')) + + -- multi extension filename + eq('rb', fnamemodify('a.spec.rb', ':e:r')) + eq('rb', fnamemodify('a.spec.rb', ':e:r:r')) + + eq('spec', fnamemodify('a.spec.rb', ':e:e:r')) + eq('spec', fnamemodify('a.spec.rb', ':e:e:r:r')) + + eq('spec', fnamemodify('a.b.spec.rb', ':e:e:r')) + eq('b.spec', fnamemodify('a.b.spec.rb', ':e:e:e:r')) + eq('b', fnamemodify('a.b.spec.rb', ':e:e:e:r:r')) + + eq('spec', fnamemodify('a.b.spec.rb', ':r:e')) + eq('b', fnamemodify('a.b.spec.rb', ':r:r:e')) + + -- extraneous :e expansions + eq('c', fnamemodify('a.b.c.d.e', ':r:r:e')) + eq('b.c', fnamemodify('a.b.c.d.e', ':r:r:e:e')) + + -- :e never includes the whole filename, so "a.b":e:e:e --> "b" + eq('b.c', fnamemodify('a.b.c.d.e', ':r:r:e:e:e')) + eq('b.c', fnamemodify('a.b.c.d.e', ':r:r:e:e:e:e')) + end) end) diff --git a/test/functional/eval/let_spec.lua b/test/functional/eval/let_spec.lua index 63e18f943f..f8fcdfd41f 100644 --- a/test/functional/eval/let_spec.lua +++ b/test/functional/eval/let_spec.lua @@ -59,10 +59,6 @@ describe(':let', function() end) it("multibyte env var to child process #8398 #9267", function() - if (not helpers.iswin()) and helpers.isCI() then - -- Fails on non-Windows CI. Buffering/timing issue? - pending('fails on unix CI', function() end) - end local cmd_get_child_env = "let g:env_from_child = system(['"..nvim_dir.."/printenv-test', 'NVIM_TEST'])" command("let $NVIM_TEST = 'AìaB'") command(cmd_get_child_env) diff --git a/test/functional/eval/system_spec.lua b/test/functional/eval/system_spec.lua index 0a478fd05c..1e4d760dbc 100644 --- a/test/functional/eval/system_spec.lua +++ b/test/functional/eval/system_spec.lua @@ -84,7 +84,7 @@ describe('system()', function() it('does NOT run in shell', function() if iswin() then - eq("%PATH%\n", eval("system(['powershell', '-NoProfile', '-NoLogo', '-ExecutionPolicy', 'RemoteSigned', '-Command', 'echo', '%PATH%'])")) + eq("%PATH%\n", eval("system(['powershell', '-NoProfile', '-NoLogo', '-ExecutionPolicy', 'RemoteSigned', '-Command', 'Write-Output', '%PATH%'])")) else eq("* $PATH %PATH%\n", eval("system(['echo', '*', '$PATH', '%PATH%'])")) end @@ -121,10 +121,6 @@ describe('system()', function() screen:attach() end) - after_each(function() - screen:detach() - end) - if iswin() then local function test_more() eq('root = true', eval([[get(split(system('"more" ".editorconfig"'), "\n"), 0, '')]])) @@ -133,7 +129,7 @@ describe('system()', function() eval([[system('"ping" "-n" "1" "127.0.0.1"')]]) eq(0, eval('v:shell_error')) eq('"a b"\n', eval([[system('cmd /s/c "cmd /s/c "cmd /s/c "echo "a b""""')]])) - eq('"a b"\n', eval([[system('powershell -NoProfile -NoLogo -ExecutionPolicy RemoteSigned -Command echo ''\^"a b\^"''')]])) + eq('"a b"\n', eval([[system('powershell -NoProfile -NoLogo -ExecutionPolicy RemoteSigned -Command Write-Output ''\^"a b\^"''')]])) end it('with shell=cmd.exe', function() @@ -169,9 +165,9 @@ describe('system()', function() it('works with powershell', function() helpers.set_shell_powershell() - eq('a\nb\n', eval([[system('echo a b')]])) + eq('a\nb\n', eval([[system('Write-Output a b')]])) eq('C:\\\n', eval([[system('cd c:\; (Get-Location).Path')]])) - eq('a b\n', eval([[system('echo "a b"')]])) + eq('a b\n', eval([[system('Write-Output "a b"')]])) end) end diff --git a/test/functional/ex_cmds/drop_spec.lua b/test/functional/ex_cmds/drop_spec.lua index d6da0d8e88..762ea3d166 100644 --- a/test/functional/ex_cmds/drop_spec.lua +++ b/test/functional/ex_cmds/drop_spec.lua @@ -19,10 +19,6 @@ describe(":drop", function() command("set laststatus=2 shortmess-=F") end) - after_each(function() - screen:detach() - end) - it("works like :e when called with only one window open", function() feed_command("drop tmp1.vim") screen:expect([[ diff --git a/test/functional/ex_cmds/highlight_spec.lua b/test/functional/ex_cmds/highlight_spec.lua index 25968b8204..1cd6759a53 100644 --- a/test/functional/ex_cmds/highlight_spec.lua +++ b/test/functional/ex_cmds/highlight_spec.lua @@ -13,10 +13,6 @@ describe(':highlight', function() screen:attach() end) - after_each(function() - screen:detach() - end) - it('invalid color name', function() eq('Vim(highlight):E421: Color name or number not recognized: ctermfg=#181818', exc_exec("highlight normal ctermfg=#181818")) diff --git a/test/functional/ex_cmds/write_spec.lua b/test/functional/ex_cmds/write_spec.lua index 3f54ff6f41..4f526ddfca 100644 --- a/test/functional/ex_cmds/write_spec.lua +++ b/test/functional/ex_cmds/write_spec.lua @@ -41,7 +41,7 @@ describe(':write', function() command("silent !ln -s test_bkc_file.txt test_bkc_link.txt") end if eval('v:shell_error') ~= 0 then - pending('Cannot create symlink', function()end) + pending('Cannot create symlink') end source([[ edit test_bkc_link.txt @@ -61,7 +61,7 @@ describe(':write', function() command("silent !ln -s test_bkc_file.txt test_bkc_link.txt") end if eval('v:shell_error') ~= 0 then - pending('Cannot create symlink', function()end) + pending('Cannot create symlink') end source([[ edit test_bkc_link.txt @@ -75,8 +75,7 @@ describe(':write', function() it("appends FIFO file", function() -- mkfifo creates read-only .lnk files on Windows if iswin() or eval("executable('mkfifo')") == 0 then - pending('missing "mkfifo" command', function()end) - return + pending('missing "mkfifo" command') end local text = "some fifo text from write_spec" diff --git a/test/functional/fixtures/CMakeLists.txt b/test/functional/fixtures/CMakeLists.txt index dbcb157956..270540de2e 100644 --- a/test/functional/fixtures/CMakeLists.txt +++ b/test/functional/fixtures/CMakeLists.txt @@ -1,12 +1,12 @@ -add_executable(tty-test tty-test.c) +add_executable(tty-test EXCLUDE_FROM_ALL tty-test.c) target_link_libraries(tty-test ${LIBUV_LIBRARIES}) -add_executable(shell-test shell-test.c) -add_executable(printargs-test printargs-test.c) -add_executable(printenv-test printenv-test.c) +add_executable(shell-test EXCLUDE_FROM_ALL shell-test.c) +add_executable(printargs-test EXCLUDE_FROM_ALL printargs-test.c) +add_executable(printenv-test EXCLUDE_FROM_ALL printenv-test.c) if(WIN32) set_target_properties(printenv-test PROPERTIES LINK_FLAGS -municode) endif() -add_executable(streams-test streams-test.c) +add_executable(streams-test EXCLUDE_FROM_ALL streams-test.c) target_link_libraries(streams-test ${LIBUV_LIBRARIES}) diff --git a/test/functional/fixtures/printenv-test.c b/test/functional/fixtures/printenv-test.c index 5ac076f653..0e68129543 100644 --- a/test/functional/fixtures/printenv-test.c +++ b/test/functional/fixtures/printenv-test.c @@ -44,7 +44,7 @@ int main(int argc, char **argv) utf8_len, NULL, NULL); - fprintf(stderr, "%s", utf8_value); + fprintf(stdout, "%s", utf8_value); free(utf8_value); #else char *value = getenv(argv[1]); @@ -52,8 +52,8 @@ int main(int argc, char **argv) fprintf(stderr, "env var not found: %s", argv[1]); return 1; } - // Print to stderr to avoid buffering. - fprintf(stderr, "%s", value); + fprintf(stdout, "%s", value); #endif + fflush(stdout); return 0; } diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 20371b8ab0..1108fbb2ba 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -1,4 +1,5 @@ require('coxpcall') +local busted = require('busted') local luv = require('luv') local lfs = require('lfs') local mpack = require('mpack') @@ -28,10 +29,8 @@ local module = { } local start_dir = lfs.currentdir() --- XXX: NVIM_PROG takes precedence, QuickBuild sets it. module.nvim_prog = ( - os.getenv('NVIM_PROG') - or os.getenv('NVIM_PRG') + os.getenv('NVIM_PRG') or global_helpers.test_build_dir .. '/bin/nvim' ) -- Default settings for the test session. @@ -385,7 +384,7 @@ function module.retry(max, max_ms, fn) end luv.update_time() -- Update cached value of luv.now() (libuv: uv_now()). if (max and tries >= max) or (luv.now() - start_time > timeout) then - error("\nretry() attempts: "..tostring(tries).."\n"..tostring(result)) + busted.fail(string.format("retry() attempts: %d\n%s", tries, tostring(result)), 2) end tries = tries + 1 luv.sleep(20) -- Avoid hot loop... @@ -502,14 +501,10 @@ end function module.set_shell_powershell() local shell = iswin() and 'powershell' or 'pwsh' - if not module.eval('executable("'..shell..'")') then - error(shell..' is not executable') - end - local aliases = iswin() and {'cat', 'sleep'} or {} - local cmd = '' - for _, alias in ipairs(aliases) do - cmd = cmd .. 'Remove-Item -Force alias:' .. alias .. ';' - end + assert(module.eval('executable("'..shell..'")')) + local cmd = 'Remove-Item -Force '..table.concat(iswin() + and {'alias:cat', 'alias:echo', 'alias:sleep'} + or {'alias:echo'}, ',')..';' module.source([[ let &shell = ']]..shell..[[' set shellquote= shellpipe=\| shellxquote= diff --git a/test/functional/legacy/045_folding_spec.lua b/test/functional/legacy/045_folding_spec.lua index 6ca1176aea..1e5239ceac 100644 --- a/test/functional/legacy/045_folding_spec.lua +++ b/test/functional/legacy/045_folding_spec.lua @@ -14,9 +14,6 @@ describe('folding', function() screen = Screen.new(20, 8) screen:attach() end) - after_each(function() - screen:detach() - end) it('creation, opening, moving (to the end) and closing', function() insert([[ diff --git a/test/functional/legacy/063_match_and_matchadd_spec.lua b/test/functional/legacy/063_match_and_matchadd_spec.lua index 518d79861b..a4f5d6ac5b 100644 --- a/test/functional/legacy/063_match_and_matchadd_spec.lua +++ b/test/functional/legacy/063_match_and_matchadd_spec.lua @@ -14,6 +14,10 @@ describe('063: Test for ":match", "matchadd()" and related functions', function( it('is working', function() local screen = Screen.new(40, 5) screen:attach() + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}, + [1] = {background = Screen.colors.Red}, + }) -- Check that "matcharg()" returns the correct group and pattern if a match -- is defined. @@ -126,22 +130,22 @@ describe('063: Test for ":match", "matchadd()" and related functions', function( command("call matchaddpos('MyGroup1', [[1, 5], [1, 8, 3]], 10, 3)") screen:expect([[ abcd{1:e}fg{1:hij}klmnop^q | - ~ | - ~ | - ~ | + {0:~ }| + {0:~ }| + {0:~ }| | - ]], {[1] = {background = Screen.colors.Red}}, {{bold = true, foreground = Screen.colors.Blue}}) + ]]) command("call clearmatches()") command("call setline(1, 'abcdΣabcdef')") command("call matchaddpos('MyGroup1', [[1, 4, 2], [1, 9, 2]])") screen:expect([[ abc{1:dΣ}ab{1:cd}e^f | - ~ | - ~ | - ~ | + {0:~ }| + {0:~ }| + {0:~ }| | - ]],{[1] = {background = Screen.colors.Red}}, {{bold = true, foreground = Screen.colors.Blue}}) + ]]) end) end) diff --git a/test/functional/legacy/delete_spec.lua b/test/functional/legacy/delete_spec.lua index 9ea3269828..f2ced8942d 100644 --- a/test/functional/legacy/delete_spec.lua +++ b/test/functional/legacy/delete_spec.lua @@ -56,7 +56,7 @@ describe('Test for delete()', function() endif ]]) if eval('v:shell_error') ~= 0 then - pending('Cannot create symlink', function()end) + pending('Cannot create symlink') end -- Delete the link, not the file eq(0, eval("delete('Xlink')")) diff --git a/test/functional/legacy/search_spec.lua b/test/functional/legacy/search_spec.lua index 3ed06a22e7..a207b176d3 100644 --- a/test/functional/legacy/search_spec.lua +++ b/test/functional/legacy/search_spec.lua @@ -17,7 +17,10 @@ describe('search cmdline', function() screen = Screen.new(20, 3) screen:attach() screen:set_default_attr_ids({ - inc = {reverse = true} + inc = {reverse = true}, + err = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, + more = { bold = true, foreground = Screen.colors.SeaGreen4 }, + tilde = { bold = true, foreground = Screen.colors.Blue1 }, }) end) @@ -404,15 +407,7 @@ describe('search cmdline', function() end) it('keeps the view after deleting a char from the search', function() - screen:detach() - screen = Screen.new(20, 6) - screen:attach() - screen:set_default_attr_ids({ - inc = {reverse = true} - }) - screen:set_default_attr_ignore({ - {bold=true, reverse=true}, {bold=true, foreground=Screen.colors.Blue1} - }) + screen:try_resize(20, 6) tenlines() feed('/foo') @@ -448,14 +443,7 @@ describe('search cmdline', function() end) it('restores original view after failed search', function() - screen:detach() - screen = Screen.new(40, 3) - screen:attach() - screen:set_default_attr_ids({ - inc = {reverse = true}, - err = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, - more = { bold = true, foreground = Screen.colors.SeaGreen4 }, - }) + screen:try_resize(40, 3) tenlines() feed('0') feed('/foo') @@ -484,15 +472,7 @@ describe('search cmdline', function() it("CTRL-G with 'incsearch' and ? goes in the right direction", function() -- oldtest: Test_search_cmdline4(). - screen:detach() - screen = Screen.new(40, 4) - screen:attach() - screen:set_default_attr_ids({ - inc = {reverse = true}, - err = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, - more = { bold = true, foreground = Screen.colors.SeaGreen4 }, - tilde = { bold = true, foreground = Screen.colors.Blue1 }, - }) + screen:try_resize(40, 4) command('enew!') funcs.setline(1, {' 1 the first', ' 2 the second', ' 3 the third'}) command('set laststatus=0 shortmess+=s') diff --git a/test/functional/options/chars_spec.lua b/test/functional/options/chars_spec.lua index 1330c29e61..3453e79429 100644 --- a/test/functional/options/chars_spec.lua +++ b/test/functional/options/chars_spec.lua @@ -16,10 +16,6 @@ describe("'fillchars'", function() screen:attach() end) - after_each(function() - screen:detach() - end) - local function shouldfail(val,errval) errval = errval or val eq('Vim(set):E474: Invalid argument: fillchars='..errval, @@ -100,10 +96,6 @@ describe("'listchars'", function() screen:attach() end) - after_each(function() - screen:detach() - end) - it('is local to window', function() feed('i<tab><tab><tab><esc>') command('set laststatus=0') diff --git a/test/functional/plugin/health_spec.lua b/test/functional/plugin/health_spec.lua index 3525e235de..a78ed07876 100644 --- a/test/functional/plugin/health_spec.lua +++ b/test/functional/plugin/health_spec.lua @@ -116,8 +116,6 @@ describe('health.vim', function() screen:set_default_attr_ids({ Ok = { foreground = Screen.colors.Grey3, background = 6291200 }, Error = { foreground = Screen.colors.Grey100, background = Screen.colors.Red }, - }) - screen:set_default_attr_ignore({ Heading = { bold=true, foreground=Screen.colors.Magenta }, Heading2 = { foreground = Screen.colors.SlateBlue }, Bar = { foreground=Screen.colors.Purple }, @@ -126,18 +124,18 @@ describe('health.vim', function() command("checkhealth foo success1") command("1tabclose") command("set laststatus=0") - screen:expect([[ + screen:expect{grid=[[ ^ | - health#foo#check | - ========================================================================| - - {Error:ERROR:} No healthcheck found for "foo" plugin. | + {Heading:health#foo#check} | + {Bar:========================================================================}| + {Bullet: -} {Error:ERROR:} No healthcheck found for "foo" plugin. | | - health#success1#check | - ========================================================================| - ## report 1 | - - {Ok:OK:} everything is fine | + {Heading:health#success1#check} | + {Bar:========================================================================}| + {Heading2:##}{Heading: report 1} | + {Bullet: -} {Ok:OK:} everything is fine | | - ]]) + ]]} end) it("gracefully handles invalid healthcheck", function() diff --git a/test/functional/plugin/man_spec.lua b/test/functional/plugin/man_spec.lua index d95995797e..e5b2e7dc1f 100644 --- a/test/functional/plugin/man_spec.lua +++ b/test/functional/plugin/man_spec.lua @@ -19,38 +19,32 @@ describe(':Man', function() u = { underline = true }, bi = { bold = true, italic = true }, biu = { bold = true, italic = true, underline = true }, - }) - screen:set_default_attr_ignore({ - { foreground = Screen.colors.Blue }, -- control chars - { bold = true, foreground = Screen.colors.Blue } -- empty line '~'s + c = { foreground = Screen.colors.Blue }, -- control chars + eob = { bold = true, foreground = Screen.colors.Blue } -- empty line '~'s }) screen:attach() end) - after_each(function() - screen:detach() - end) - it('clears backspaces from text and adds highlights', function() rawfeed([[ ithis i<C-v><C-h>is<C-v><C-h>s a<C-v><C-h>a test with _<C-v><C-h>o_<C-v><C-h>v_<C-v><C-h>e_<C-v><C-h>r_<C-v><C-h>s_<C-v><C-h>t_<C-v><C-h>r_<C-v><C-h>u_<C-v><C-h>c_<C-v><C-h>k text<ESC>]]) - screen:expect([[ - this i^His^Hs a^Ha test | - with _^Ho_^Hv_^He_^Hr_^Hs_^Ht_^Hr_^Hu_^Hc_^Hk tex^t | - ~ | - ~ | - | - ]]) + screen:expect{grid=[[ + this i{c:^H}is{c:^H}s a{c:^H}a test | + with _{c:^H}o_{c:^H}v_{c:^H}e_{c:^H}r_{c:^H}s_{c:^H}t_{c:^H}r_{c:^H}u_{c:^H}c_{c:^H}k tex^t | + {eob:~ }| + {eob:~ }| + | + ]]} eval('man#init_pager()') screen:expect([[ ^this {b:is} {b:a} test | with {u:overstruck} text | - ~ | - ~ | + {eob:~ }| + {eob:~ }| | ]]) end) @@ -60,21 +54,21 @@ describe(':Man', function() ithis <C-v><ESC>[1mis <C-v><ESC>[3ma <C-v><ESC>[4mtest<C-v><ESC>[0m <C-v><ESC>[4mwith<C-v><ESC>[24m <C-v><ESC>[4mescaped<C-v><ESC>[24m <C-v><ESC>[4mtext<C-v><ESC>[24m<ESC>]]) - screen:expect([=[ - this ^[[1mis ^[[3ma ^[[4mtest^[[0m | - ^[[4mwith^[[24m ^[[4mescaped^[[24m ^[[4mtext^[[24^m | - ~ | - ~ | - | - ]=]) + screen:expect{grid=[=[ + this {c:^[}[1mis {c:^[}[3ma {c:^[}[4mtest{c:^[}[0m | + {c:^[}[4mwith{c:^[}[24m {c:^[}[4mescaped{c:^[}[24m {c:^[}[4mtext{c:^[}[24^m | + {eob:~ }| + {eob:~ }| + | + ]=]} eval('man#init_pager()') screen:expect([[ ^this {b:is }{bi:a }{biu:test} | {u:with} {u:escaped} {u:text} | - ~ | - ~ | + {eob:~ }| + {eob:~ }| | ]]) end) @@ -88,8 +82,8 @@ describe(':Man', function() screen:expect([[ ^this {b:is} {b:あ} test | with {u:överstrũck} te{i:xt¶} | - ~ | - ~ | + {eob:~ }| + {eob:~ }| | ]]) end) @@ -105,7 +99,7 @@ describe(':Man', function() {b:^_begins} | {b:mid_dle} | {u:mid_dle} | - ~ | + {eob:~ }| | ]]) end) @@ -121,7 +115,7 @@ describe(':Man', function() ^· {b:·} | {b:·} | {b:·} double | - ~ | + {eob:~ }| | ]]) end) diff --git a/test/functional/provider/clipboard_spec.lua b/test/functional/provider/clipboard_spec.lua index b2d75db745..da9dd09129 100644 --- a/test/functional/provider/clipboard_spec.lua +++ b/test/functional/provider/clipboard_spec.lua @@ -88,6 +88,11 @@ describe('clipboard', function() before_each(function() clear() screen = Screen.new(72, 4) + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}, + [1] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [2] = {bold = true, foreground = Screen.colors.SeaGreen4}, + }) screen:attach() command("set display-=msgsep") end) @@ -103,22 +108,22 @@ describe('clipboard', function() feed_command('redir @+> | :silent echo system("cat CONTRIBUTING.md") | redir END') screen:expect([[ ^ | - ~ | - ~ | + {0:~ }| + {0:~ }| clipboard: No provider. Try ":checkhealth" or ":h clipboard". | - ]], nil, {{bold = true, foreground = Screen.colors.Blue}}) + ]]) end) it('`:redir @+>|bogus_cmd|redir END` + invalid g:clipboard must not recurse #7184', function() command("let g:clipboard = 'bogus'") feed_command('redir @+> | bogus_cmd | redir END') - screen:expect([[ - ~ | + screen:expect{grid=[[ + {0:~ }| clipboard: No provider. Try ":checkhealth" or ":h clipboard". | - E492: Not an editor command: bogus_cmd | redir END | - Press ENTER or type command to continue^ | - ]], nil, {{bold = true, foreground = Screen.colors.Blue}}) + {1:E492: Not an editor command: bogus_cmd | redir END} | + {2:Press ENTER or type command to continue}^ | + ]]} end) it('invalid g:clipboard shows hint if :redir is not active', function() @@ -131,10 +136,10 @@ describe('clipboard', function() feed_command('let @+="foo"') screen:expect([[ ^ | - ~ | - ~ | + {0:~ }| + {0:~ }| clipboard: No provider. Try ":checkhealth" or ":h clipboard". | - ]], nil, {{bold = true, foreground = Screen.colors.Blue}}) + ]]) end) it('valid g:clipboard', function() @@ -266,13 +271,17 @@ describe('clipboard (with fake clipboard.vim)', function() function() local screen = Screen.new(72, 4) screen:attach() + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}, + [1] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + }) feed_command('redir @+> | bogus_cmd | redir END') screen:expect([[ ^ | - ~ | - ~ | - E492: Not an editor command: bogus_cmd | redir END | - ]], nil, {{bold = true, foreground = Screen.colors.Blue}}) + {0:~ }| + {0:~ }| + {1:E492: Not an editor command: bogus_cmd | redir END} | + ]]) end) it('has independent "* and unnamed registers by default', function() @@ -637,6 +646,9 @@ describe('clipboard (with fake clipboard.vim)', function() feed_command('set mouse=a') local screen = Screen.new(30, 5) + screen:set_default_attr_ids({ + [0] = {bold = true, foreground = Screen.colors.Blue}, + }) screen:attach() insert([[ the source @@ -646,10 +658,10 @@ describe('clipboard (with fake clipboard.vim)', function() screen:expect([[ the ^source | a target | - ~ | - ~ | + {0:~ }| + {0:~ }| | - ]], nil, {{bold = true, foreground = Screen.colors.Blue}}) + ]]) feed('<MiddleMouse><0,1>') expect([[ diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua index 1763574bf9..7560b0e872 100644 --- a/test/functional/terminal/buffer_spec.lua +++ b/test/functional/terminal/buffer_spec.lua @@ -208,18 +208,18 @@ describe(':terminal buffer', function() feed_command('terminal') feed('<c-\\><c-n>') feed_command('confirm bdelete') - screen:expect{any='Close "term://', attr_ignore=true} + screen:expect{any='Close "term://'} end) it('with &confirm', function() feed_command('terminal') feed('<c-\\><c-n>') feed_command('bdelete') - screen:expect{any='E89', attr_ignore=true} + screen:expect{any='E89'} feed('<cr>') eq('terminal', eval('&buftype')) feed_command('set confirm | bdelete') - screen:expect{any='Close "term://', attr_ignore=true} + screen:expect{any='Close "term://'} feed('y') neq('terminal', eval('&buftype')) end) diff --git a/test/functional/terminal/helpers.lua b/test/functional/terminal/helpers.lua index f6cab6bd1e..d909888613 100644 --- a/test/functional/terminal/helpers.lua +++ b/test/functional/terminal/helpers.lua @@ -52,7 +52,7 @@ local function screen_setup(extra_rows, command, cols, opts) [3] = {bold = true}, [4] = {foreground = 12}, [5] = {bold = true, reverse = true}, - [6] = {background = 11}, + -- 6 was a duplicate item [7] = {foreground = 130}, [8] = {foreground = 15, background = 1}, -- error message [9] = {foreground = 4}, diff --git a/test/functional/terminal/mouse_spec.lua b/test/functional/terminal/mouse_spec.lua index 64f437f206..ee3db7ae97 100644 --- a/test/functional/terminal/mouse_spec.lua +++ b/test/functional/terminal/mouse_spec.lua @@ -31,10 +31,6 @@ describe(':terminal mouse', function() ]]) end) - after_each(function() - screen:detach() - end) - describe('when the terminal has focus', function() it('will exit focus on mouse-scroll', function() eq('t', eval('mode()')) diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua index ff6a74fe89..060f065bfc 100644 --- a/test/functional/terminal/scrollback_spec.lua +++ b/test/functional/terminal/scrollback_spec.lua @@ -21,10 +21,6 @@ describe(':terminal scrollback', function() screen = thelpers.screen_setup(nil, nil, 30) end) - after_each(function() - screen:detach() - end) - describe('when the limit is exceeded', function() before_each(function() local lines = {} @@ -406,8 +402,6 @@ describe("'scrollback' option", function() feed_data(nvim_dir..'/shell-test REP 31 line'..(iswin() and '\r' or '\n')) screen:expect{any='30: line '} retry(nil, nil, function() expect_lines(7) end) - - screen:detach() end) it('deletes lines (only) if necessary', function() @@ -464,8 +458,6 @@ describe("'scrollback' option", function() -- Verify off-screen state eq((iswin() and '36: line' or '35: line'), eval("getline(line('w0') - 1)")) eq((iswin() and '27: line' or '26: line'), eval("getline(line('w0') - 10)")) - - screen:detach() end) it('defaults to 10000 in :terminal buffers', function() diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 978267e040..bc83660c19 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -45,10 +45,6 @@ describe('TUI', function() child_session = helpers.connect(child_server) end) - after_each(function() - screen:detach() - end) - -- Wait for mode in the child Nvim (avoid "typeahead race" #10826). local function wait_for_mode(mode) retry(nil, nil, function() @@ -928,7 +924,15 @@ describe('TUI FocusGained/FocusLost', function() feed_data(':terminal\n') -- Wait for terminal to be ready. - screen:expect{any='-- TERMINAL --'} + screen:expect{grid=[[ + {1:r}eady $ | + [Process exited 0] | + | + | + | + :terminal | + {3:-- TERMINAL --} | + ]]} feed_data('\027[I') screen:expect{grid=[[ @@ -1283,7 +1287,7 @@ describe("TUI 'term' option", function() elseif is_macos then local status, _ = pcall(assert_term, "xterm", "xterm") if not status then - pending("macOS: unibilium could not find terminfo", function() end) + pending("macOS: unibilium could not find terminfo") end else assert_term("xterm", "xterm") diff --git a/test/functional/ui/bufhl_spec.lua b/test/functional/ui/bufhl_spec.lua index d8ca947645..5df909f79c 100644 --- a/test/functional/ui/bufhl_spec.lua +++ b/test/functional/ui/bufhl_spec.lua @@ -37,10 +37,6 @@ describe('Buffer highlighting', function() }) end) - after_each(function() - screen:detach() - end) - local add_highlight = curbufmeths.add_highlight local clear_namespace = curbufmeths.clear_namespace diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index f9769c706f..c2354103c2 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -25,10 +25,6 @@ local function test_cmdline(linegrid) screen = new_screen({rgb=true, ext_cmdline=true, ext_linegrid=linegrid}) end) - after_each(function() - screen:detach() - end) - it('works', function() feed(':') screen:expect{grid=[[ @@ -804,10 +800,6 @@ describe('cmdline redraw', function() screen = new_screen({rgb=true}) end) - after_each(function() - screen:detach() - end) - it('with timer', function() feed(':012345678901234567890123456789') screen:expect{grid=[[ @@ -829,8 +821,7 @@ describe('cmdline redraw', function() it('with <Cmd>', function() if 'openbsd' == helpers.uname() then - pending('FIXME #10804', function() end) - return + pending('FIXME #10804') end command('cmap a <Cmd>call sin(0)<CR>') -- no-op feed(':012345678901234567890123456789') diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua index 67aba919b0..8ad4182f41 100644 --- a/test/functional/ui/cursor_spec.lua +++ b/test/functional/ui/cursor_spec.lua @@ -13,10 +13,6 @@ describe('ui/cursor', function() screen:attach() end) - after_each(function() - screen:detach() - end) - it("'guicursor' is published as a UI event", function() local expected_mode_info = { [1] = { diff --git a/test/functional/ui/embed_spec.lua b/test/functional/ui/embed_spec.lua index f3cd223f53..8218c8e12d 100644 --- a/test/functional/ui/embed_spec.lua +++ b/test/functional/ui/embed_spec.lua @@ -50,8 +50,7 @@ local function test_embed(ext_linegrid) it("doesn't erase output when setting color scheme", function() if 'openbsd' == helpers.uname() then - pending('FIXME #10804', function() end) - return + pending('FIXME #10804') end startup('--cmd', 'echoerr "foo"', '--cmd', 'color default', '--cmd', 'echoerr "bar"') screen:expect([[ diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua index c5ef718883..eb81aba131 100644 --- a/test/functional/ui/fold_spec.lua +++ b/test/functional/ui/fold_spec.lua @@ -24,10 +24,6 @@ describe("folded lines", function() }) end) - after_each(function() - screen:detach() - end) - it("work with more than one signcolumn", function() command("set signcolumn=yes:9") feed("i<cr><esc>") diff --git a/test/functional/ui/highlight_spec.lua b/test/functional/ui/highlight_spec.lua index 1b25570997..d7791a3107 100644 --- a/test/functional/ui/highlight_spec.lua +++ b/test/functional/ui/highlight_spec.lua @@ -35,7 +35,6 @@ describe('highlight: `:syntax manual`', function() end) after_each(function() - screen:detach() os.remove('Xtest-functional-ui-highlight.tmp.vim') end) @@ -97,10 +96,6 @@ describe('highlight defaults', function() command("set display-=msgsep") end) - after_each(function() - screen:detach() - end) - it('window status bar', function() screen:set_default_attr_ids({ [0] = {bold=true, foreground=Screen.colors.Blue}, @@ -346,17 +341,10 @@ describe('highlight defaults', function() end) describe('highlight', function() - local screen - - before_each(function() - clear() - screen = Screen.new(25,10) - screen:attach() - end) + before_each(clear) it('visual', function() - screen:detach() - screen = Screen.new(20,4) + local screen = Screen.new(20,4) screen:attach() screen:set_default_attr_ids({ [1] = {background = Screen.colors.LightGrey}, @@ -389,8 +377,7 @@ describe('highlight', function() end) it('cterm=standout gui=standout', function() - screen:detach() - screen = Screen.new(20,5) + local screen = Screen.new(20,5) screen:attach() screen:set_default_attr_ids({ [1] = {bold = true, foreground = Screen.colors.Blue1}, @@ -413,8 +400,7 @@ describe('highlight', function() end) it('strikethrough', function() - screen:detach() - screen = Screen.new(25,6) + local screen = Screen.new(25,6) screen:attach() feed_command('syntax on') feed_command('syn keyword TmpKeyword foo') @@ -439,8 +425,7 @@ describe('highlight', function() end) it('nocombine', function() - screen:detach() - screen = Screen.new(25,6) + local screen = Screen.new(25,6) screen:set_default_attr_ids{ [1] = {foreground = Screen.colors.SlateBlue, underline = true}, [2] = {bold = true, foreground = Screen.colors.Blue1}, @@ -487,6 +472,8 @@ describe('highlight', function() end) it('guisp (special/undercurl)', function() + local screen = Screen.new(25,10) + screen:attach() feed_command('syntax on') feed_command('syn keyword TmpKeyword neovim') feed_command('syn keyword TmpKeyword1 special') @@ -542,10 +529,6 @@ describe("'listchars' highlight", function() screen:attach() end) - after_each(function() - screen:detach() - end) - it("'cursorline' and 'cursorcolumn'", function() screen:set_default_attr_ids({ [0] = {bold=true, foreground=Screen.colors.Blue}, diff --git a/test/functional/ui/hlstate_spec.lua b/test/functional/ui/hlstate_spec.lua index d1c115587e..1e18df835a 100644 --- a/test/functional/ui/hlstate_spec.lua +++ b/test/functional/ui/hlstate_spec.lua @@ -259,7 +259,7 @@ describe('ext_hlstate detailed highlights', function() it("can use independent cterm and rgb colors", function() -- tell test module to save all attributes (doesn't change nvim options) - screen:set_hlstate_cterm(true) + screen:set_rgb_cterm(true) screen:set_default_attr_ids({ [1] = {{bold = true, foreground = Screen.colors.Blue1}, {foreground = 12}, {{hi_name = "NonText", ui_name = "EndOfBuffer", kind = "ui"}}}, diff --git a/test/functional/ui/inccommand_spec.lua b/test/functional/ui/inccommand_spec.lua index e9a7c8c2df..d60cd08fb0 100644 --- a/test/functional/ui/inccommand_spec.lua +++ b/test/functional/ui/inccommand_spec.lua @@ -556,7 +556,6 @@ describe(":substitute, 'inccommand' preserves undo", function() ]]) end end - screen:detach() end) it('with undolevels=2', function() @@ -647,7 +646,6 @@ describe(":substitute, 'inccommand' preserves undo", function() Already ...t change | ]]) end - screen:detach() end end) @@ -713,7 +711,6 @@ describe(":substitute, 'inccommand' preserves undo", function() Already ...t change | ]]) end - screen:detach() end) end) @@ -726,10 +723,6 @@ describe(":substitute, inccommand=split", function() common_setup(screen, "split", default_text .. default_text) end) - after_each(function() - screen:detach() - end) - it("preserves 'modified' buffer flag", function() feed_command("set nomodified") feed(":%s/tw") @@ -1241,10 +1234,6 @@ describe("inccommand=nosplit", function() common_setup(screen, "nosplit", default_text .. default_text) end) - after_each(function() - if screen then screen:detach() end - end) - it("works with :smagic, :snomagic", function() feed_command("set hlsearch") insert("Line *.3.* here") @@ -1719,10 +1708,6 @@ describe("'inccommand' split windows", function() common_setup(screen, "split", default_text) end - after_each(function() - screen:detach() - end) - it('work after more splits', function() refresh() diff --git a/test/functional/ui/messages_spec.lua b/test/functional/ui/messages_spec.lua index 377d49c036..d16559bab2 100644 --- a/test/functional/ui/messages_spec.lua +++ b/test/functional/ui/messages_spec.lua @@ -1125,7 +1125,7 @@ aliquip ex ea commodo consequat.]]) it('can be quit', function() screen:try_resize(25,5) - feed(':echon join(map(range(0, &lines*2), "v:val"), "\\n")<cr>') + feed(':echon join(map(range(0, &lines*10), "v:val"), "\\n")<cr>') screen:expect{grid=[[ 0 | 1 | diff --git a/test/functional/ui/mouse_spec.lua b/test/functional/ui/mouse_spec.lua index 440bae58e0..7840ba9167 100644 --- a/test/functional/ui/mouse_spec.lua +++ b/test/functional/ui/mouse_spec.lua @@ -26,6 +26,8 @@ describe('ui/mouse/input', function() }, [4] = {reverse = true}, [5] = {bold = true, reverse = true}, + [6] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [7] = {bold = true, foreground = Screen.colors.SeaGreen4}, }) command("set display-=msgsep") feed('itesting<cr>mouse<cr>support and selection<esc>') @@ -38,10 +40,6 @@ describe('ui/mouse/input', function() ]]) end) - after_each(function() - screen:detach() - end) - it('single left click moves cursor', function() feed('<LeftMouse><2,1>') screen:expect([[ @@ -620,12 +618,12 @@ describe('ui/mouse/input', function() meths.set_option('tags', './non-existent-tags-file') feed('<C-LeftMouse><0,0>') screen:expect([[ - E433: No tags file | - E426: tag not found: test| - ing | - Press ENTER or type comma| - nd to continue^ | - ]],nil,true) + {6:E433: No tags file} | + {6:E426: tag not found: test}| + {6:ing} | + {7:Press ENTER or type comma}| + {7:nd to continue}^ | + ]]) feed('<cr>') end) diff --git a/test/functional/ui/multibyte_spec.lua b/test/functional/ui/multibyte_spec.lua index 3e63353ad2..8122cb08a3 100644 --- a/test/functional/ui/multibyte_spec.lua +++ b/test/functional/ui/multibyte_spec.lua @@ -21,10 +21,6 @@ describe("multibyte rendering", function() }) end) - after_each(function() - screen:detach() - end) - it("works with composed char at start of line", function() insert([[ ̊ @@ -131,10 +127,6 @@ describe('multibyte rendering: statusline', function() command('set laststatus=2') end) - after_each(function() - screen:detach() - end) - it('last char shows (multibyte)', function() command('set statusline=你好') screen:expect([[ diff --git a/test/functional/ui/multigrid_spec.lua b/test/functional/ui/multigrid_spec.lua index 30a5b63d89..01ffe80be3 100644 --- a/test/functional/ui/multigrid_spec.lua +++ b/test/functional/ui/multigrid_spec.lua @@ -37,10 +37,6 @@ describe('ext_multigrid', function() }) end) - after_each(function() - screen:detach() - end) - it('default initial screen', function() screen:expect{grid=[[ ## grid 1 diff --git a/test/functional/ui/options_spec.lua b/test/functional/ui/options_spec.lua index 93192934c7..ea71f5eae9 100644 --- a/test/functional/ui/options_spec.lua +++ b/test/functional/ui/options_spec.lua @@ -40,10 +40,6 @@ describe('ui receives option updates', function() return defaults end - after_each(function() - screen:detach() - end) - it("for defaults", function() local expected = reset() screen:expect(function() diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua index c5d3e536ad..9b1e803649 100644 --- a/test/functional/ui/output_spec.lua +++ b/test/functional/ui/output_spec.lua @@ -31,7 +31,6 @@ describe("shell command :!", function() after_each(function() child_session.feed_data("\3") -- Ctrl-C - screen:detach() end) it("displays output without LF/EOF. #4646 #4569 #3772", function() @@ -52,8 +51,7 @@ describe("shell command :!", function() it("throttles shell-command output greater than ~10KB", function() if 'openbsd' == helpers.uname() then - pending('FIXME #10804', function() end) - return + pending('FIXME #10804') end child_session.feed_data(":!"..nvim_dir.."/shell-test REP 30001 foo\n") @@ -97,8 +95,7 @@ describe("shell command :!", function() it('handles control codes', function() if iswin() then - pending('missing printf', function() end) - return + pending('missing printf') end local screen = Screen.new(50, 4) screen:attach() @@ -236,14 +233,18 @@ describe("shell command :!", function() set_shell_powershell() local screen = Screen.new(30, 4) screen:attach() - feed_command([[!'echo $a']]) - screen:expect{any='\necho %$a', timeout=10000} - feed_command([[!$a = 1; echo '$a']]) + feed_command([[!'Write-Output $a']]) + screen:expect{any='\nWrite%-Output %$a', timeout=10000} + feed_command([[!$a = 1; Write-Output '$a']]) screen:expect{any='\n%$a', timeout=10000} - feed_command([[!"echo $a"]]) - screen:expect{any='\necho', timeout=10000} - feed_command([[!$a = 1; echo "$a"]]) + feed_command([[!"Write-Output $a"]]) + screen:expect{any='\nWrite%-Output', timeout=10000} + feed_command([[!$a = 1; Write-Output "$a"]]) screen:expect{any='\n1', timeout=10000} + feed_command(iswin() + and [[!& 'C:\\Windows\\system32\\cmd.exe' /c 'echo $a']] + or [[!& '/bin/sh' -c 'echo ''$a''']]) + screen:expect{any='\n%$a', timeout=10000} end) end end) diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 06a2ac3ca2..b57e13fea1 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -66,12 +66,12 @@ -- [1] = {reverse = true, bold = true}, -- [2] = {reverse = true} -- }) --- screen:set_default_attr_ignore( {{}, {bold=true, foreground=NonText}} ) -- -- To help write screen tests, see Screen:snapshot_util(). -- To debug screen tests, see Screen:redraw_debug(). local helpers = require('test.functional.helpers')(nil) +local busted = require('busted') local deepcopy = helpers.deepcopy local shallowcopy = helpers.shallowcopy local concat_tables = helpers.concat_tables @@ -169,12 +169,11 @@ function Screen.new(width, height) ruler = {}, hl_groups = {}, _default_attr_ids = nil, - _default_attr_ignore = nil, _mouse_enabled = true, _attrs = {}, - _hl_info = {}, + _hl_info = {[0]={}}, _attr_table = {[0]={{},{}}}, - _clear_attrs = {}, + _clear_attrs = nil, _new_attrs = false, _width = width, _height = height, @@ -202,12 +201,8 @@ function Screen:get_default_attr_ids() return deepcopy(self._default_attr_ids) end -function Screen:set_default_attr_ignore(attr_ignore) - self._default_attr_ignore = attr_ignore -end - -function Screen:set_hlstate_cterm(val) - self._hlstate_cterm = val +function Screen:set_rgb_cterm(val) + self._rgb_cterm = val end function Screen:attach(options, session) @@ -223,7 +218,7 @@ function Screen:attach(options, session) self._session = session self._options = options - self._clear_attrs = (options.ext_linegrid and {{},{}}) or {} + self._clear_attrs = (not options.ext_linegrid) and {} or nil self:_handle_resize(self._width, self._height) self.uimeths.attach(self._width, self._height, options) if self._options.rgb == nil then @@ -265,7 +260,7 @@ local ext_keys = { -- Asserts that the screen state eventually matches an expected state. -- -- Can be called with positional args: --- screen:expect(grid, [attr_ids, attr_ignore]) +-- screen:expect(grid, [attr_ids]) -- screen:expect(condition) -- or keyword args (supports more options): -- screen:expect{grid=[[...]], cmdline={...}, condition=function() ... end} @@ -282,8 +277,6 @@ local ext_keys = { -- attributes in the final state are an error. -- Use screen:set_default_attr_ids() to define attributes for many -- expect() calls. --- attr_ignore: Ignored text attributes, or `true` to ignore all. By default --- nothing is ignored. -- condition: Function asserting some arbitrary condition. Return value is -- ignored, throw an error (use eq() or similar) to signal failure. -- any: Lua pattern string expected to match a screen line. NB: the @@ -318,13 +311,13 @@ local ext_keys = { -- cmdline_block: Expected ext_cmdline block (for function definitions) -- wildmenu_items: Expected items for ext_wildmenu -- wildmenu_pos: Expected position for ext_wildmenu -function Screen:expect(expected, attr_ids, attr_ignore, ...) +function Screen:expect(expected, attr_ids, ...) local grid, condition = nil, nil local expected_rows = {} assert(next({...}) == nil, "invalid args to expect()") if type(expected) == "table" then - assert(not (attr_ids ~= nil or attr_ignore ~= nil)) - local is_key = {grid=true, attr_ids=true, attr_ignore=true, condition=true, + assert(not (attr_ids ~= nil)) + local is_key = {grid=true, attr_ids=true, condition=true, any=true, mode=true, unchanged=true, intermediate=true, reset=true, timeout=true, request_cb=true, hl_groups=true} for _, v in ipairs(ext_keys) do @@ -337,14 +330,13 @@ function Screen:expect(expected, attr_ids, attr_ignore, ...) end grid = expected.grid attr_ids = expected.attr_ids - attr_ignore = expected.attr_ignore condition = expected.condition assert(not (expected.any ~= nil and grid ~= nil)) elseif type(expected) == "string" then grid = expected expected = {} elseif type(expected) == "function" then - assert(not (attr_ids ~= nil or attr_ignore ~= nil)) + assert(not (attr_ids ~= nil)) condition = expected expected = {} else @@ -361,10 +353,9 @@ function Screen:expect(expected, attr_ids, attr_ignore, ...) end local attr_state = { ids = attr_ids or self._default_attr_ids, - ignore = attr_ignore or self._default_attr_ignore, } - if self._options.ext_hlstate then - attr_state.id_to_index = self:hlstate_check_attrs(attr_state.ids or {}) + if self._options.ext_linegrid then + attr_state.id_to_index = self:linegrid_check_attrs(attr_state.ids or {}) end self._new_attrs = false self:_wait(function() @@ -375,8 +366,8 @@ function Screen:expect(expected, attr_ids, attr_ignore, ...) end end - if self._options.ext_hlstate and self._new_attrs then - attr_state.id_to_index = self:hlstate_check_attrs(attr_state.ids or {}) + if self._options.ext_linegrid and self._new_attrs then + attr_state.id_to_index = self:linegrid_check_attrs(attr_state.ids or {}) end local actual_rows = self:render(not expected.any, attr_state) @@ -584,7 +575,7 @@ asynchronous (feed(), nvim_input()) and synchronous API calls. if err then - assert(false, err) + busted.fail(err, 3) elseif did_warn then local tb = debug.traceback() local index = string.find(tb, '\n%s*%[C]') @@ -898,19 +889,16 @@ function Screen:_handle_grid_line(grid, row, col, items) assert(self._options.ext_linegrid) local line = self._grids[grid].rows[row+1] local colpos = col+1 - local hl = self._clear_attrs local hl_id = 0 for _,item in ipairs(items) do local text, hl_id_cell, count = unpack(item) if hl_id_cell ~= nil then hl_id = hl_id_cell - hl = self._attr_table[hl_id] end for _ = 1, (count or 1) do local cell = line[colpos] cell.text = text cell.hl_id = hl_id - cell.attrs = hl colpos = colpos+1 end end @@ -1070,6 +1058,7 @@ function Screen:_clear_row_section(grid, rownum, startcol, stopcol, invalid) for i = startcol, stopcol do row[i].text = (invalid and '�' or ' ') row[i].attrs = self._clear_attrs + row[i].hl_id = 0 end end @@ -1100,11 +1089,7 @@ function Screen:_row_repr(gridnr, rownr, attr_state, cursor) end if not did_window then - local attrs = row[i].attrs - if self._options.ext_linegrid then - attrs = attrs[(self._options.rgb and 1) or 2] - end - local attr_id = self:_get_attr_id(attr_state, attrs, row[i].hl_id) + local attr_id = self:_get_attr_id(attr_state, row[i].attrs, row[i].hl_id) if current_attr_id and attr_id ~= current_attr_id then -- close current attribute bracket table.insert(rv, '}') @@ -1261,8 +1246,8 @@ function Screen:get_snapshot(attrs, ignore) attr_state.ids[i] = a end end - if self._options.ext_hlstate then - attr_state.id_to_index = self:hlstate_check_attrs(attr_state.ids) + if self._options.ext_linegrid then + attr_state.id_to_index = self:linegrid_check_attrs(attr_state.ids) end local lines = self:render(true, attr_state, true) @@ -1299,8 +1284,8 @@ function Screen:print_snapshot(attrs, ignore) local attrstrs = {} for i, a in pairs(attr_state.ids) do local dict - if self._options.ext_hlstate then - dict = self:_pprint_hlstate(a) + if self._options.ext_linegrid then + dict = self:_pprint_hlitem(a) else dict = "{"..self:_pprint_attrs(a).."}" end @@ -1328,37 +1313,41 @@ function Screen:_insert_hl_id(attr_state, hl_id) return attr_state.id_to_index[hl_id] end local raw_info = self._hl_info[hl_id] - local info = {} - if #raw_info > 1 then - for i, item in ipairs(raw_info) do - info[i] = self:_insert_hl_id(attr_state, item.id) - end - else - info[1] = {} - for k, v in pairs(raw_info[1]) do - if k ~= "id" then - info[1][k] = v + local info = nil + if self._options.ext_hlstate then + info = {} + if #raw_info > 1 then + for i, item in ipairs(raw_info) do + info[i] = self:_insert_hl_id(attr_state, item.id) + end + else + info[1] = {} + for k, v in pairs(raw_info[1]) do + if k ~= "id" then + info[1][k] = v + end end end end local entry = self._attr_table[hl_id] local attrval - if self._hlstate_cterm then + if self._rgb_cterm then attrval = {entry[1], entry[2], info} -- unpack() doesn't work - else + elseif self._options.ext_hlstate then attrval = {entry[1], info} + else + attrval = self._options.rgb and entry[1] or entry[2] end - table.insert(attr_state.ids, attrval) attr_state.id_to_index[hl_id] = #attr_state.ids return #attr_state.ids end -function Screen:hlstate_check_attrs(attrs) +function Screen:linegrid_check_attrs(attrs) local id_to_index = {} - for i = 1,#self._attr_table do + for i, def_attr in pairs(self._attr_table) do local iinfo = self._hl_info[i] local matchinfo = {} if #iinfo > 1 then @@ -1370,13 +1359,16 @@ function Screen:hlstate_check_attrs(attrs) end for k,v in pairs(attrs) do local attr, info, attr_rgb, attr_cterm - if self._hlstate_cterm then + if self._rgb_cterm then attr_rgb, attr_cterm, info = unpack(v) attr = {attr_rgb, attr_cterm} - else + elseif self._options.ext_hlstate then attr, info = unpack(v) + else + attr = v + info = {} end - if self:_equal_attr_def(attr, self._attr_table[i]) then + if self:_equal_attr_def(attr, def_attr) then if #info == #matchinfo then local match = false if #info == 1 then @@ -1397,24 +1389,31 @@ function Screen:hlstate_check_attrs(attrs) end end end + if self:_equal_attr_def(self._rgb_cterm and {{}, {}} or {}, def_attr) and #self._hl_info[i] == 0 then + id_to_index[i] = "" + end end return id_to_index end -function Screen:_pprint_hlstate(item) +function Screen:_pprint_hlitem(item) -- print(inspect(item)) - local attrdict = "{"..self:_pprint_attrs(item[1]).."}, " + local multi = self._rgb_cterm or self._options.ext_hlstate + local attrdict = "{"..self:_pprint_attrs(multi and item[1] or item).."}" local attrdict2, hlinfo - if self._hlstate_cterm then - attrdict2 = "{"..self:_pprint_attrs(item[2]).."}, " + local descdict = "" + if self._rgb_cterm then + attrdict2 = ", {"..self:_pprint_attrs(item[2]).."}" hlinfo = item[3] else attrdict2 = "" hlinfo = item[2] end - local descdict = "{"..self:_pprint_hlinfo(hlinfo).."}" - return "{"..attrdict..attrdict2..descdict.."}" + if self._options.ext_hlstate then + descdict = ", {"..self:_pprint_hlinfo(hlinfo).."}" + end + return (multi and "{" or "")..attrdict..attrdict2..descdict..(multi and "}" or "") end function Screen:_pprint_hlinfo(states) @@ -1464,9 +1463,11 @@ function Screen:_get_attr_id(attr_state, attrs, hl_id) return end - if self._options.ext_hlstate then + if self._options.ext_linegrid then local id = attr_state.id_to_index[hl_id] - if id ~= nil or hl_id == 0 then + if id == "" then -- sentinel for empty it + return nil + elseif id ~= nil then return id end if attr_state.mutable then @@ -1476,9 +1477,7 @@ function Screen:_get_attr_id(attr_state, attrs, hl_id) end return "UNEXPECTED "..self:_pprint_attrs(self._attr_table[hl_id][1]) else - if self:_equal_attrs(attrs, {}) or - attr_state.ignore == true or - self:_attr_index(attr_state.ignore, attrs) ~= nil then + if self:_equal_attrs(attrs, {}) then -- ignore this attrs return nil end @@ -1497,10 +1496,12 @@ function Screen:_get_attr_id(attr_state, attrs, hl_id) end function Screen:_equal_attr_def(a, b) - if self._hlstate_cterm then + if self._rgb_cterm then return self:_equal_attrs(a[1],b[1]) and self:_equal_attrs(a[2],b[2]) - else + elseif self._options.rgb then return self:_equal_attrs(a,b[1]) + else + return self:_equal_attrs(a,b[2]) end end diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua index 68e675b8e5..0ed62b21b2 100644 --- a/test/functional/ui/sign_spec.lua +++ b/test/functional/ui/sign_spec.lua @@ -26,10 +26,6 @@ describe('Signs', function() } ) end) - after_each(function() - screen:detach() - end) - describe(':sign place', function() it('allows signs with combining characters', function() feed('ia<cr>b<cr><esc>') diff --git a/test/functional/ui/spell_spec.lua b/test/functional/ui/spell_spec.lua index 913f1b9bed..243b737583 100644 --- a/test/functional/ui/spell_spec.lua +++ b/test/functional/ui/spell_spec.lua @@ -20,10 +20,6 @@ describe("'spell'", function() }) end) - after_each(function() - screen:detach() - end) - it('joins long lines #7937', function() feed_command('set spell') insert([[ diff --git a/test/functional/ui/syntax_conceal_spec.lua b/test/functional/ui/syntax_conceal_spec.lua index 566d183f11..d1af0e955c 100644 --- a/test/functional/ui/syntax_conceal_spec.lua +++ b/test/functional/ui/syntax_conceal_spec.lua @@ -22,10 +22,6 @@ describe('Screen', function() } ) end) - after_each(function() - screen:detach() - end) - describe("match and conceal", function() before_each(function() diff --git a/test/functional/ui/tabline_spec.lua b/test/functional/ui/tabline_spec.lua index dcab9f7ef4..0ee7e03fac 100644 --- a/test/functional/ui/tabline_spec.lua +++ b/test/functional/ui/tabline_spec.lua @@ -17,10 +17,6 @@ describe('ui/ext_tabline', function() end) end) - after_each(function() - screen:detach() - end) - it('publishes UI events', function() command("tabedit another-tab") diff --git a/test/helpers.lua b/test/helpers.lua index 30e43a9ea4..4c526d217f 100644 --- a/test/helpers.lua +++ b/test/helpers.lua @@ -715,13 +715,11 @@ end function module.isCI(name) local any = (name == nil) - assert(any or name == 'appveyor' or name == 'quickbuild' or name == 'travis' - or name == 'sourcehut') + assert(any or name == 'appveyor' or name == 'travis' or name == 'sourcehut') local av = ((any or name == 'appveyor') and nil ~= os.getenv('APPVEYOR')) local tr = ((any or name == 'travis') and nil ~= os.getenv('TRAVIS')) - local qb = ((any or name == 'quickbuild') and nil ~= lfs.attributes('/usr/home/quickbuild')) local sh = ((any or name == 'sourcehut') and nil ~= os.getenv('SOURCEHUT')) - return tr or av or qb or sh + return tr or av or sh end diff --git a/test/unit/mbyte_spec.lua b/test/unit/mbyte_spec.lua index d27f52923a..fdb1bceab0 100644 --- a/test/unit/mbyte_spec.lua +++ b/test/unit/mbyte_spec.lua @@ -8,11 +8,6 @@ local mbyte = helpers.cimport("./src/nvim/mbyte.h") local charset = helpers.cimport('./src/nvim/charset.h') describe('mbyte', function() - if helpers.isCI('quickbuild') then - pending("crashes on quickbuild", function() end) - return - end - -- Array for composing characters local intp = ffi.typeof('int[?]') local function to_intp() diff --git a/third-party/cmake/BuildLibtermkey.cmake b/third-party/cmake/BuildLibtermkey.cmake index b2332ed65a..10e98fbab3 100644 --- a/third-party/cmake/BuildLibtermkey.cmake +++ b/third-party/cmake/BuildLibtermkey.cmake @@ -48,6 +48,7 @@ ExternalProject_Add(libtermkey PREFIX=${DEPS_INSTALL_DIR} PKG_CONFIG_PATH=${DEPS_LIB_DIR}/pkgconfig CFLAGS=-fPIC + LDFLAGS+=-static ${DEFAULT_MAKE_CFLAGS} install) endif() diff --git a/third-party/cmake/BuildLibvterm.cmake b/third-party/cmake/BuildLibvterm.cmake index e4649986af..61c1c90fa6 100644 --- a/third-party/cmake/BuildLibvterm.cmake +++ b/third-party/cmake/BuildLibvterm.cmake @@ -58,6 +58,7 @@ else() set(LIBVTERM_INSTALL_COMMAND ${MAKE_PRG} CC=${DEPS_C_COMPILER} PREFIX=${DEPS_INSTALL_DIR} CFLAGS=-fPIC + LDFLAGS+=-static ${DEFAULT_MAKE_CFLAGS} install) endif() diff --git a/third-party/cmake/BuildUnibilium.cmake b/third-party/cmake/BuildUnibilium.cmake index e9deeb4987..74c1cbddb0 100644 --- a/third-party/cmake/BuildUnibilium.cmake +++ b/third-party/cmake/BuildUnibilium.cmake @@ -40,6 +40,7 @@ else() BUILD_COMMAND ${MAKE_PRG} CC=${DEPS_C_COMPILER} PREFIX=${DEPS_INSTALL_DIR} CFLAGS=-fPIC + LDFLAGS+=-static INSTALL_COMMAND ${MAKE_PRG} PREFIX=${DEPS_INSTALL_DIR} install) endif() |