diff options
66 files changed, 931 insertions, 664 deletions
diff --git a/.travis.yml b/.travis.yml index d464d67bb1..f557daa9f4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -62,3 +62,7 @@ script: # as $USER, while retaining the environment variables defined and belonging # to secondary groups given above in usermod. - sudo -E su $USER -c "sh -e \"$CI_SCRIPTS/$CI_TARGET.sh\"" +notifications: + webhooks: + urls: + - https://webhooks.gitter.im/e/b5c38c99f9677aa3d031 diff --git a/CMakeLists.txt b/CMakeLists.txt index 1af79e60a8..c56e883f24 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -193,7 +193,7 @@ include_directories(SYSTEM ${LIBUNIBILIUM_INCLUDE_DIRS}) option(LIBTERMKEY_USE_STATIC "Use static libtermkey" ON) find_package(LibTermkey REQUIRED) -include_directories(SYSTEM ${LIBTERMEY_INCLUDE_DIRS}) +include_directories(SYSTEM ${LIBTERMKEY_INCLUDE_DIRS}) option(LIBVTERM_USE_STATIC "Use static libvterm" ON) find_package(LibVterm REQUIRED) @@ -1,6 +1,7 @@ filter-false = $(strip $(filter-out 0 off OFF false FALSE,$1)) filter-true = $(strip $(filter-out 1 on ON true TRUE,$1)) +# See contrib/local.mk.example -include local.mk CMAKE_BUILD_TYPE ?= Debug @@ -13,6 +13,7 @@ [](https://coveralls.io/r/neovim/neovim) [](https://scan.coverity.com/projects/2227) [](http://neovim.org/doc/reports/clang) +[](https://gitter.im/neovim/neovim?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) Neovim is a project that seeks to aggressively refactor Vim in order to: diff --git a/config/config.h.in b/config/config.h.in index a3cd72b57c..8f3d154553 100644 --- a/config/config.h.in +++ b/config/config.h.in @@ -31,7 +31,6 @@ #cmakedefine HAVE_LSTAT #cmakedefine HAVE_NL_LANGINFO_CODESET #cmakedefine HAVE_NL_MSG_CAT_CNTR -#cmakedefine HAVE_OPENDIR #define HAVE_OSPEED 1 #cmakedefine HAVE_PUTENV #cmakedefine HAVE_PWD_H diff --git a/contrib/YouCompleteMe/ycm_extra_conf.py b/contrib/YouCompleteMe/ycm_extra_conf.py index 0066f96dc0..7c54677c8f 100644 --- a/contrib/YouCompleteMe/ycm_extra_conf.py +++ b/contrib/YouCompleteMe/ycm_extra_conf.py @@ -29,7 +29,7 @@ def GetCompilationInfoForFile(filename): c_file = basename + '.c' # for pure headers (no c file), default to main.c if not os.path.exists(c_file): - c_file = os.path.join(DirectoryOfThisScript(), 'main.c') + c_file = os.path.join(DirectoryOfThisScript(), 'nvim', 'main.c') if os.path.exists(c_file): compilation_info = database.GetCompilationInfoForFile(c_file) if compilation_info.compiler_flags_: diff --git a/contrib/local.mk.example b/contrib/local.mk.example new file mode 100644 index 0000000000..c8ccf8c03f --- /dev/null +++ b/contrib/local.mk.example @@ -0,0 +1,30 @@ +# Copy this to 'local.mk' in the repository root to take effect. +# Individual entries must be uncommented to take effect. + +# By default, the installation prefix is '/usr/local'. +# CMAKE_EXTRA_FLAGS += -DCMAKE_INSTALL_PREFIX=/usr/local/neovim-latest + +# Sets the build type; defaults to Debug. Valid values: +# +# - Debug: Disables optimizations (-O0), enables debug information. +# +# - RelWithDebInfo: Enables optimizations that do not interfere with debugging +# (-O2) which do, enables debug information. +# +# - MinSizeRel: Enables all -O2 optimization that do not typically +# increase code size, and performs further optimizations +# designed to reduce code size. Disables debug information. +# +# - Release: Same as RelWithDebInfo, but disables debug information. +# +# CMAKE_BUILD_TYPE := Debug + +# By default, all libraries are statically linked to nvim. Uncomment these +# entries to use dynamic linking instead. +# +# CMAKE_EXTRA_FLAGS += -DLIBTERMKEY_USE_STATIC=OFF +# CMAKE_EXTRA_FLAGS += -DLIBUNIBILIUM_USE_STATIC=OFF +# CMAKE_EXTRA_FLAGS += -DLIBUV_USE_STATIC=OFF +# CMAKE_EXTRA_FLAGS += -DLIBVTERM_USE_STATIC=OFF +# CMAKE_EXTRA_FLAGS += -DLUAJIT_USE_STATIC=OFF +# CMAKE_EXTRA_FLAGS += -DMSGPACK_USE_STATIC=OFF diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh index c4bc2d156a..4935ca5994 100755 --- a/scripts/vim-patch.sh +++ b/scripts/vim-patch.sh @@ -3,37 +3,38 @@ set -e set -o pipefail -NEOVIM_SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -VIM_SOURCE_DIR_DEFAULT=${NEOVIM_SOURCE_DIR}/.vim-src -VIM_SOURCE_DIR="${VIM_SOURCE_DIR:-${VIM_SOURCE_DIR_DEFAULT}}" +readonly NEOVIM_SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +readonly VIM_SOURCE_DIR_DEFAULT=${NEOVIM_SOURCE_DIR}/.vim-src +readonly VIM_SOURCE_DIR="${VIM_SOURCE_DIR:-${VIM_SOURCE_DIR_DEFAULT}}" +readonly BASENAME="$(basename "${0}")" usage() { - >&2 echo "Helper script for porting Vim patches. For more information," - >&2 echo "see https://github.com/neovim/neovim/wiki/Merging-patches-from-upstream-vim." - >&2 echo - >&2 echo "Usage: ${0} [option]" - >&2 echo " ${0} vim-revision" - >&2 echo - >&2 echo "Options:" - >&2 echo " -h, --help Show this message." - >&2 echo " -l, --list Show list of Vim patches missing from Neovim." - >&2 echo - >&2 echo "vim-revision can be a version number in format '7.4.xxx'" - >&2 echo "or a Mercurial commit hash." - >&2 echo - >&2 echo "Set VIM_SOURCE_DIR to change where Vim's sources are stored." - >&2 echo "The default is '${VIM_SOURCE_DIR_DEFAULT}'." + echo "Helper script for porting Vim patches. For more information, see" + echo "https://github.com/neovim/neovim/wiki/Merging-patches-from-upstream-vim" + echo + echo "Usage: ${BASENAME} [option]" + echo " ${BASENAME} vim-revision" + echo + echo "Options:" + echo " -h, --help Show this message." + echo " -l, --list Show list of Vim patches missing from Neovim." + echo + echo "vim-revision can be a version number of the format '7.4.xxx'" + echo "or a Mercurial commit hash." + echo + echo "Set VIM_SOURCE_DIR to change where Vim's sources are stored." + echo "The default is '${VIM_SOURCE_DIR_DEFAULT}'." } get_vim_sources() { echo "Retrieving Vim sources." if [[ ! -d ${VIM_SOURCE_DIR} ]]; then echo "Cloning Vim sources into '${VIM_SOURCE_DIR}'." - hg clone https://code.google.com/p/vim ${VIM_SOURCE_DIR} - cd ${VIM_SOURCE_DIR} + hg clone https://code.google.com/p/vim "${VIM_SOURCE_DIR}" + cd "${VIM_SOURCE_DIR}" else echo "Updating Vim sources in '${VIM_SOURCE_DIR}'." - cd ${VIM_SOURCE_DIR} + cd "${VIM_SOURCE_DIR}" hg pull --update && echo "✔ Updated Vim sources." || echo "✘ Could not update Vim sources; ignoring error." @@ -41,7 +42,7 @@ get_vim_sources() { } get_vim_patch() { - if [[ "${1}" =~ [0-9]\.[0-9]\.[0-9]{3,4} ]]; then + if [[ ${1} =~ [0-9]\.[0-9]\.[0-9]{3,4} ]]; then # Interpret parameter as version number. vim_version="${1}" vim_commit="v${1//./-}" @@ -53,7 +54,7 @@ get_vim_patch() { strip_commit_line=false fi - hg log --rev ${vim_commit} >/dev/null 2>&1 || { + hg log --rev "${vim_commit}" >/dev/null 2>&1 || { >&2 echo "✘ Couldn't find Vim revision '${vim_commit}'." exit 3 } @@ -61,13 +62,13 @@ get_vim_patch() { echo "✔ Found Vim revision '${vim_commit}'." # Collect patch details and store into variables. - vim_full="$(hg log --patch --git --verbose --rev ${vim_commit})" - vim_message="$(hg log --template "{desc}" --rev ${vim_commit})" - if [[ "${strip_commit_line}" == "true" ]]; then + vim_full="$(hg log --patch --git --verbose --rev "${vim_commit}")" + vim_message="$(hg log --template "{desc}" --rev "${vim_commit}")" + if [[ ${strip_commit_line} == "true" ]]; then # Remove first line of commit message. vim_message="$(echo "${vim_message}" | sed -e '1d')" fi - vim_diff="$(hg diff --show-function --git --change ${vim_commit} \ + vim_diff="$(hg diff --show-function --git --change "${vim_commit}" \ | sed -e 's/\( [ab]\/src\)/\1\/nvim/g')" # Change directory to src/nvim. neovim_message=" vim-patch:${vim_version} @@ -91,7 +92,7 @@ get_vim_patch() { echo echo "Creating Git branch." - cd ${NEOVIM_SOURCE_DIR} + cd "${NEOVIM_SOURCE_DIR}" output="$(git checkout -b "${neovim_branch}" 2>&1)" && echo "✔ ${output}" || (echo "✘ ${output}"; false) @@ -104,11 +105,11 @@ get_vim_patch() { echo echo "Creating files." - echo "${vim_diff}" > ${NEOVIM_SOURCE_DIR}/${neovim_branch}.diff + echo "${vim_diff}" > "${NEOVIM_SOURCE_DIR}/${neovim_branch}.diff" echo "✔ Saved patch to '${NEOVIM_SOURCE_DIR}/${neovim_branch}.diff'." - echo "${vim_full}" > ${NEOVIM_SOURCE_DIR}/${neovim_branch}.patch + echo "${vim_full}" > "${NEOVIM_SOURCE_DIR}/${neovim_branch}.patch" echo "✔ Saved full commit details to '${NEOVIM_SOURCE_DIR}/${neovim_branch}.patch'." - echo "${neovim_pr}" > ${NEOVIM_SOURCE_DIR}/${neovim_branch}.pr + echo "${neovim_pr}" > "${NEOVIM_SOURCE_DIR}/${neovim_branch}.pr" echo "✔ Saved suggested PR description to '${NEOVIM_SOURCE_DIR}/${neovim_branch}.pr'." echo "You can use 'git clean' to remove these files when you're done." @@ -136,7 +137,7 @@ list_vim_patches() { # Start from 7.4.442. The runtime was re-integrated from 7.4.384, but # runtime patches before between 384 and 442 have already been ported # to Neovim as of the creation of this script. - local vim_commits=$(cd ${VIM_SOURCE_DIR} && \ + local vim_commits=$(cd "${VIM_SOURCE_DIR}" && \ hg log --removed --template='{if(startswith("Added tag", firstline(desc)), "{latesttag}\n", "{if(startswith(\"updated for version\", firstline(desc)), @@ -144,7 +145,7 @@ list_vim_patches() { \"{node}\n\")}")}' -r tip:v7-4-442) # Append remaining vim patches. # Start from 7.4.160, where Neovim was forked. - local vim_old_commits=$(cd ${VIM_SOURCE_DIR} && \ + local vim_old_commits=$(cd "${VIM_SOURCE_DIR}" && \ hg log --removed --template='{if(startswith("Added tag", firstline(desc)), "{latesttag}\n")}' -r v7-4-442:v7-4-161) @@ -152,21 +153,21 @@ list_vim_patches() { local vim_commit for vim_commit in ${vim_commits} ${vim_old_commits}; do local is_missing - if [[ "${vim_commit}" =~ v([0-9]-[0-9]-([0-9]{3,4})) ]]; then + if [[ ${vim_commit} =~ v([0-9]-[0-9]-([0-9]{3,4})) ]]; then local patch_number="${BASH_REMATCH[2]}" # "Proper" Vim patch # Check version.c: - is_missing="$(sed -n '/static int included_patches/,/}/p' ${NEOVIM_SOURCE_DIR}/src/nvim/version.c | + is_missing="$(sed -n '/static int included_patches/,/}/p' "${NEOVIM_SOURCE_DIR}/src/nvim/version.c" | grep -x -e "[[:space:]]*//${patch_number} NA" -e "[[:space:]]*${patch_number}," >/dev/null && echo "false" || echo "true")" vim_commit="${BASH_REMATCH[1]//-/.}" else # Untagged Vim patch, e.g. runtime updates. # Check Neovim log: - is_missing="$(cd ${NEOVIM_SOURCE_DIR} && + is_missing="$(cd "${NEOVIM_SOURCE_DIR}" && git log -1 --no-merges --grep="vim\-patch:${vim_commit:0:7}" --pretty=format:"false")" fi - if [[ "${is_missing}" != "false" ]]; then + if [[ ${is_missing} != "false" ]]; then echo " • ${vim_commit}" fi done @@ -177,19 +178,28 @@ list_vim_patches() { echo " To port one of the above patches to Neovim, execute" echo " this script with the patch revision as argument." echo - echo " Examples: './scripts/vim-patch.sh 7.4.487'" - echo " './scripts/vim-patch.sh 1e8ebf870720e7b671f98f22d653009826304c4f'" + echo " Examples: '${BASENAME} 7.4.487'" + echo " '${BASENAME} 1e8ebf870720e7b671f98f22d653009826304c4f'" } -if [[ ${#} != 1 || "${1}" == "--help" || "${1}" == "-h" ]]; then +if [[ ${1} == "--help" || ${1} == "-h" ]]; then usage + exit 0 +elif [[ ${#} != 1 ]]; then + usage + exit 1 +fi + +# Checks if mercurial is in the user's PATH, and is executable. +if [[ ! -x $(command -v hg) ]]; then + >&2 echo "${BASENAME}: 'hg' (mercurial) not found in PATH or not executable" exit 1 fi get_vim_sources -if [[ "${1}" == "--list" || "${1}" == "-l" ]]; then +if [[ ${1} == "--list" || ${1} == "-l" ]]; then list_vim_patches else - get_vim_patch ${1} + get_vim_patch "${1}" fi diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 14b3968f2d..516278f34d 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -1400,7 +1400,6 @@ void display_dollar(colnr_T col) if (!redrawing()) return; - ui_cursor_off(); save_col = curwin->w_cursor.col; curwin->w_cursor.col = col; if (has_mbyte) { diff --git a/src/nvim/eval.c b/src/nvim/eval.c index ae8e0d329f..a716bb66ab 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -7287,8 +7287,7 @@ static void f_browse(typval_T *argvars, typval_T *rettv) */ static void f_browsedir(typval_T *argvars, typval_T *rettv) { - rettv->vval.v_string = NULL; - rettv->v_type = VAR_STRING; + f_browse(argvars, rettv); } diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 739243cbee..12a634416b 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -42,7 +42,6 @@ #include "nvim/memline.h" #include "nvim/message.h" #include "nvim/misc1.h" -#include "nvim/misc2.h" #include "nvim/garray.h" #include "nvim/memory.h" #include "nvim/move.h" @@ -1063,9 +1062,7 @@ do_filter ( /* Create the shell command in allocated memory. */ cmd_buf = make_filter_cmd(cmd, itmp, otmp); - ui_cursor_goto((int)Rows - 1, 0); - ui_cursor_on(); /* * When not redirecting the output the command can write anything to the @@ -1248,7 +1245,6 @@ do_shell ( // This ui_cursor_goto is required for when the '\n' resulted in a "delete line // 1" command to the terminal. ui_cursor_goto(msg_row, msg_col); - ui_cursor_on(); (void)call_shell(cmd, flags, NULL); did_check_timestamps = FALSE; need_check_timestamps = TRUE; @@ -1963,7 +1959,6 @@ void print_line(linenr_T lnum, int use_number, int list) print_line_no_prefix(lnum, use_number, list); if (save_silent) { msg_putchar('\n'); - ui_cursor_on(); /* msg_start() switches it off */ ui_flush(); silent_mode = save_silent; } diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 8167824a41..63d94dabc0 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -6381,9 +6381,7 @@ static void ex_sleep(exarg_T *eap) void do_sleep(long msec) { long done; - - ui_cursor_on(); - ui_flush(); + ui_flush(); // flush before waiting for (done = 0; !got_int && done < msec; done += 1000L) { os_delay(msec - done > 1000L ? 1000L : msec - done, true); os_breakcheck(); diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index a7bb4afa70..d5f7a218f4 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -1364,7 +1364,7 @@ cmdline_changed: if (ccline.cmdlen == 0) i = 0; else { - ui_cursor_off(); /* so the user knows we're busy */ + ui_busy_start(); ui_flush(); ++emsg_off; /* So it doesn't beep if bad expr */ /* Set the time limit to half a second. */ @@ -1382,6 +1382,7 @@ cmdline_changed: } else if (char_avail()) /* cancelled searching because a char was typed */ incsearch_postponed = TRUE; + ui_busy_stop(); } if (i != 0) highlight_match = TRUE; /* highlight position */ @@ -1701,10 +1702,6 @@ getexmodeline ( char_u *p; int prev_char; - /* Switch cursor on now. This avoids that it happens after the "\n", which - * confuses the system function that computes tabstops. */ - ui_cursor_on(); - /* always start in column 0; write a newline if necessary */ compute_cmdrow(); if ((msg_col || msg_didout) && promptc != '?') diff --git a/src/nvim/farsi.c b/src/nvim/farsi.c index db167825ce..2ca581ebd3 100644 --- a/src/nvim/farsi.c +++ b/src/nvim/farsi.c @@ -1561,9 +1561,6 @@ int fkmap(int c) if (!curwin->w_cursor.col) { return ALEF_U_H; } - } - - if (!p_ri) { dec_cursor(); } @@ -1595,9 +1592,6 @@ int fkmap(int c) if (!curwin->w_cursor.col) { return ALEF; } - } - - if (!p_ri) { dec_cursor(); } @@ -1673,9 +1667,6 @@ int fkmap(int c) if (!curwin->w_cursor.col) { return TEE; } - } - - if (!p_ri) { dec_cursor(); } diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 24fe547e56..9d4c990f3a 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -1729,14 +1729,14 @@ failed: } } - if (set_options) - save_file_ff(curbuf); /* remember the current file format */ - - /* If editing a new file: set 'fenc' for the current buffer. - * Also for ":read ++edit file". */ - if (set_options) + if (set_options) { + // Remember the current file format. + save_file_ff(curbuf); + // If editing a new file: set 'fenc' for the current buffer. + // Also for ":read ++edit file". set_string_option_direct((char_u *)"fenc", -1, fenc, - OPT_FREE|OPT_LOCAL, 0); + OPT_FREE | OPT_LOCAL, 0); + } if (fenc_alloced) free(fenc); # ifdef USE_ICONV @@ -5878,19 +5878,20 @@ static int do_autocmd_event(event_T event, char_u *pat, int nested, char_u *cmd, is_buflocal = FALSE; buflocal_nr = 0; - if (patlen >= 7 && STRNCMP(pat, "<buffer", 7) == 0 + if (patlen >= 8 && STRNCMP(pat, "<buffer", 7) == 0 && pat[patlen - 1] == '>') { - /* Error will be printed only for addition. printing and removing - * will proceed silently. */ + /* "<buffer...>": Error will be printed only for addition. + * printing and removing will proceed silently. */ is_buflocal = TRUE; if (patlen == 8) + /* "<buffer>" */ buflocal_nr = curbuf->b_fnum; else if (patlen > 9 && pat[7] == '=') { - /* <buffer=abuf> */ - if (patlen == 13 && STRNICMP(pat, "<buffer=abuf>", 13)) + if (patlen == 13 && STRNICMP(pat, "<buffer=abuf>", 13) == 0) + /* "<buffer=abuf>" */ buflocal_nr = autocmd_bufnr; - /* <buffer=123> */ else if (skipdigits(pat + 8) == pat + patlen - 1) + /* "<buffer=123>" */ buflocal_nr = atoi((char *)pat + 8); } } diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index b3e274d952..96ce586a9e 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -2379,8 +2379,8 @@ inchar ( int retesc = FALSE; /* return ESC with gotint */ int script_char; - if (wait_time == -1L || wait_time > 100L) { /* flush output before waiting */ - ui_cursor_on(); + if (wait_time == -1L || wait_time > 100L) { + // flush output before waiting ui_flush(); } diff --git a/src/nvim/macros.h b/src/nvim/macros.h index 7dd8120d09..653f46fb44 100644 --- a/src/nvim/macros.h +++ b/src/nvim/macros.h @@ -97,15 +97,9 @@ */ #define vim_isbreak(c) (breakat_flags[(char_u)(c)]) -#ifdef BINARY_FILE_IO -# define WRITEBIN "wb" /* no CR-LF translation */ -# define READBIN "rb" -# define APPENDBIN "ab" -#else -# define WRITEBIN "w" -# define READBIN "r" -# define APPENDBIN "a" -#endif +#define WRITEBIN "wb" /* no CR-LF translation */ +#define READBIN "rb" +#define APPENDBIN "ab" # define mch_fopen(n, p) fopen((n), (p)) diff --git a/src/nvim/main.c b/src/nvim/main.c index a4f430e811..2f1e6e6d3b 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -268,6 +268,23 @@ int main(int argc, char **argv) /* Set the break level after the terminal is initialized. */ debug_break_level = params.use_debug_break_level; + bool reading_input = !params.headless && (params.input_isatty + || params.output_isatty || params.err_isatty); + + if (reading_input) { + // Its possible that one of the startup commands(arguments, sourced scripts + // or plugins) will prompt the user, so start reading from a tty stream + // now. + int fd = fileno(stdin); + if (!params.input_isatty || params.edit_type == EDIT_STDIN) { + // use stderr or stdout since stdin is not a tty and/or could be used to + // read the file we'll edit when the "-" argument is given(eg: cat file | + // nvim -) + fd = params.err_isatty ? fileno(stderr) : fileno(stdout); + } + input_start_stdin(fd); + } + /* Execute --cmd arguments. */ exe_pre_commands(¶ms); @@ -351,19 +368,19 @@ int main(int argc, char **argv) if (params.edit_type == EDIT_STDIN && !recoverymode) read_stdin(); - if (!params.headless && (params.output_isatty || params.err_isatty)) { - if (params.input_isatty && (need_wait_return || msg_didany)) { - // Since at this point there's no UI instance running yet, error messages - // would have been printed to stdout. Before starting (which can result - // in a alternate screen buffer being shown) we need confirmation that - // the user has seen the messages and that is done with a call to - // wait_return. For that to work, stdin must be openend temporarily. - input_start_stdin(); - wait_return(TRUE); - TIME_MSG("waiting for return"); - input_stop_stdin(); - } + if (reading_input && (need_wait_return || msg_didany)) { + // Since at this point there's no UI instance running yet, error messages + // would have been printed to stdout. Before starting (which can result in + // a alternate screen buffer being shown) we need confirmation that the + // user has seen the messages and that is done with a call to wait_return. + TIME_MSG("waiting for return"); + wait_return(TRUE); + } + + if (!params.headless) { + // Stop reading from stdin, the UI layer will take over now + input_stop_stdin(); ui_builtin_start(); } @@ -641,7 +658,6 @@ main_loop ( curwin->w_valid &= ~VALID_CROW; } setcursor(); - ui_cursor_on(); do_redraw = FALSE; @@ -1456,11 +1472,6 @@ static void check_tty(mparm_T *parmp) TIME_MSG("Warning delay"); } - - if (parmp->edit_type != EDIT_STDIN && !parmp->input_isatty) { - // read commands from directly from stdin - input_start_stdin(); - } } /* diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 1dc3a27415..5a577c6378 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -1277,7 +1277,6 @@ recover_names ( int num_files; int file_count = 0; char_u **files; - int i; char_u *dirp; char_u *dir_name; char_u *fname_res = NULL; @@ -1357,12 +1356,13 @@ recover_names ( } } - /* check for out-of-memory */ - for (i = 0; i < num_names; ++i) { + // check for out-of-memory + for (int i = 0; i < num_names; ++i) { if (names[i] == NULL) { - for (i = 0; i < num_names; ++i) - free(names[i]); + for (int j = 0; j < num_names; ++j) + free(names[j]); num_names = 0; + break; } } if (num_names == 0) @@ -1394,7 +1394,7 @@ recover_names ( */ if (curbuf->b_ml.ml_mfp != NULL && (p = curbuf->b_ml.ml_mfp->mf_fname) != NULL) { - for (i = 0; i < num_files; ++i) + for (int i = 0; i < num_files; ++i) if (path_full_compare(p, files[i], TRUE) & kEqualFiles) { /* Remove the name from files[i]. Move further entries * down. When the array becomes empty free it here, since @@ -1427,7 +1427,7 @@ recover_names ( } if (num_files) { - for (i = 0; i < num_files; ++i) { + for (int i = 0; i < num_files; ++i) { /* print the swap file name */ msg_outnum((long)++file_count); MSG_PUTS(". "); @@ -1441,7 +1441,7 @@ recover_names ( } else file_count += num_files; - for (i = 0; i < num_names; ++i) + for (int i = 0; i < num_names; ++i) free(names[i]); if (num_files > 0) FreeWild(num_files, files); diff --git a/src/nvim/memory.c b/src/nvim/memory.c index cb9ad97749..2223b65a93 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -7,7 +7,6 @@ #include <stdbool.h> #include "nvim/vim.h" -#include "nvim/misc2.h" #include "nvim/eval.h" #include "nvim/memfile.h" #include "nvim/memory.h" diff --git a/src/nvim/menu.c b/src/nvim/menu.c index 2b1bc3b721..95cc33e4d9 100644 --- a/src/nvim/menu.c +++ b/src/nvim/menu.c @@ -1474,7 +1474,6 @@ void ex_menutranslate(exarg_T *eap) tp->to = to; } else { free(from); - free(from_noamp); free(to); } } diff --git a/src/nvim/message.c b/src/nvim/message.c index 3a68de8881..b2e9488388 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -325,7 +325,6 @@ void trunc_string(char_u *s, char_u *buf, int room, int buflen) } /* - * Automatic prototype generation does not understand this function. * Note: Caller of smgs() and smsg_attr() must check the resulting string is * shorter than IOSIZE!!! */ @@ -581,13 +580,44 @@ int emsg2(char_u *s, char_u *a1) return emsg3(s, a1, NULL); } -/* emsg3() and emsgn() are in misc2.c to avoid warnings for the prototypes. */ - void emsg_invreg(int name) { EMSG2(_("E354: Invalid register name: '%s'"), transchar(name)); } +/// Print an error message with one or two "%s" and one or two string arguments. +int emsg3(char_u *s, char_u *a1, char_u *a2) +{ + if (emsg_not_now()) { + return TRUE; // no error messages at the moment + } + + vim_snprintf((char *)IObuff, IOSIZE, (char *)s, a1, a2); + return emsg(IObuff); +} + +/// Print an error message with one "%" PRId64 and one (int64_t) argument. +int emsgn(char_u *s, int64_t n) +{ + if (emsg_not_now()) { + return TRUE; // no error messages at the moment + } + + vim_snprintf((char *)IObuff, IOSIZE, (char *)s, n); + return emsg(IObuff); +} + +/// Print an error message with one "%" PRIu64 and one (uint64_t) argument. +int emsgu(char_u *s, uint64_t n) +{ + if (emsg_not_now()) { + return TRUE; // no error messages at the moment + } + + vim_snprintf((char *)IObuff, IOSIZE, (char *)s, n); + return emsg(IObuff); +} + /* * Like msg(), but truncate to a single line if p_shm contains 't', or when * "force" is TRUE. This truncates in another way as for normal messages. @@ -998,7 +1028,6 @@ void msg_start(void) msg_starthere(); if (msg_silent == 0) { msg_didout = FALSE; /* no output on current line yet */ - ui_cursor_off(); } /* when redirecting, may need to start a new line. */ @@ -3052,9 +3081,6 @@ static double tv_float(typval_T *tvs, int *idxp) * "typval_T". When the latter is not used it must be NULL. */ -/* When generating prototypes all of this is skipped, cproto doesn't - * understand this. */ - /* Like vim_vsnprintf() but append to the string. */ int vim_snprintf_add(char *str, size_t str_m, char *fmt, ...) { diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c index 3ed6b416d6..c9f3fbd511 100644 --- a/src/nvim/misc1.c +++ b/src/nvim/misc1.c @@ -2364,9 +2364,8 @@ int get_keystroke(void) mapped_ctrl_c = FALSE; /* mappings are not used here */ for (;; ) { - ui_cursor_on(); + // flush output before waiting ui_flush(); - /* Leave some room for check_termcode() to insert a key code into (max * 5 chars plus NUL). And fix_input_buffer() can triple the number of * bytes. */ diff --git a/src/nvim/misc2.c b/src/nvim/misc2.c index be5150fdc0..fafce66c5f 100644 --- a/src/nvim/misc2.c +++ b/src/nvim/misc2.c @@ -297,7 +297,6 @@ int call_shell(char_u *cmd, ShellOpts opts, char_u *extra_shell_arg) smsg((char_u *)_("Calling shell to execute: \"%s\""), cmd == NULL ? p_sh : cmd); ui_putc('\n'); - ui_cursor_on(); verbose_leave(); } @@ -390,42 +389,6 @@ int vim_chdir(char_u *new_dir) return r; } - -/* - * Print an error message with one or two "%s" and one or two string arguments. - * This is not in message.c to avoid a warning for prototypes. - */ -int emsg3(char_u *s, char_u *a1, char_u *a2) -{ - if (emsg_not_now()) - return TRUE; /* no error messages at the moment */ - vim_snprintf((char *)IObuff, IOSIZE, (char *)s, a1, a2); - return emsg(IObuff); -} - -/* - * Print an error message with one "%" PRId64 and one (int64_t) argument. - * This is not in message.c to avoid a warning for prototypes. - */ -int emsgn(char_u *s, int64_t n) -{ - if (emsg_not_now()) - return TRUE; /* no error messages at the moment */ - vim_snprintf((char *)IObuff, IOSIZE, (char *)s, n); - return emsg(IObuff); -} - -/* - * Print an error message with one "%" PRIu64 and one (uint64_t) argument. - */ -int emsgu(char_u *s, uint64_t n) -{ - if (emsg_not_now()) - return TRUE; /* no error messages at the moment */ - vim_snprintf((char *)IObuff, IOSIZE, (char *)s, n); - return emsg(IObuff); -} - /* * Read 2 bytes from "fd" and turn them into an int, MSB first. */ diff --git a/src/nvim/msgpack_rpc/remote_ui.c b/src/nvim/msgpack_rpc/remote_ui.c index 45b3dee0fd..b554d76bed 100644 --- a/src/nvim/msgpack_rpc/remote_ui.c +++ b/src/nvim/msgpack_rpc/remote_ui.c @@ -82,8 +82,8 @@ static Object remote_ui_attach(uint64_t channel_id, uint64_t request_id, ui->clear = remote_ui_clear; ui->eol_clear = remote_ui_eol_clear; ui->cursor_goto = remote_ui_cursor_goto; - ui->cursor_on = remote_ui_cursor_on; - ui->cursor_off = remote_ui_cursor_off; + ui->busy_start = remote_ui_busy_start; + ui->busy_stop = remote_ui_busy_stop; ui->mouse_on = remote_ui_mouse_on; ui->mouse_off = remote_ui_mouse_off; ui->insert_mode = remote_ui_insert_mode; @@ -190,16 +190,16 @@ static void remote_ui_cursor_goto(UI *ui, int row, int col) push_call(ui, "cursor_goto", args); } -static void remote_ui_cursor_on(UI *ui) +static void remote_ui_busy_start(UI *ui) { Array args = ARRAY_DICT_INIT; - push_call(ui, "cursor_on", args); + push_call(ui, "busy_start", args); } -static void remote_ui_cursor_off(UI *ui) +static void remote_ui_busy_stop(UI *ui) { Array args = ARRAY_DICT_INIT; - push_call(ui, "cursor_off", args); + push_call(ui, "busy_stop", args); } static void remote_ui_mouse_on(UI *ui) diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 4c62b0c28d..a708aca136 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -983,7 +983,6 @@ getcount: free(kmsg); } setcursor(); - ui_cursor_on(); ui_flush(); if (msg_scroll || emsg_on_display) os_delay(1000L, true); /* wait at least one second */ @@ -2998,8 +2997,6 @@ static void display_showcmd(void) { int len; - ui_cursor_off(); - len = (int)STRLEN(showcmd_buf); if (len == 0) showcmd_is_clear = true; diff --git a/src/nvim/option.c b/src/nvim/option.c index a9e271517d..98584d1567 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -64,7 +64,6 @@ #include "nvim/memory.h" #include "nvim/message.h" #include "nvim/misc1.h" -#include "nvim/misc2.h" #include "nvim/keymap.h" #include "nvim/garray.h" #include "nvim/cursor_shape.h" @@ -3042,7 +3041,6 @@ theend: silent_mode = FALSE; info_message = TRUE; /* use mch_msg(), not mch_errmsg() */ msg_putchar('\n'); - ui_cursor_on(); /* msg_start() switches it off */ ui_flush(); silent_mode = TRUE; info_message = FALSE; /* use mch_msg(), not mch_errmsg() */ diff --git a/src/nvim/os/event.h b/src/nvim/os/event.h index f8139e978d..db02b38c7f 100644 --- a/src/nvim/os/event.h +++ b/src/nvim/os/event.h @@ -8,7 +8,7 @@ #include "nvim/os/job_defs.h" #include "nvim/os/time.h" -// Poll for events until a condition is true or a timeout has passed +// Poll for events until a condition or timeout #define event_poll_until(timeout, condition) \ do { \ int remaining = timeout; \ @@ -31,4 +31,5 @@ #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os/event.h.generated.h" #endif + #endif // NVIM_OS_EVENT_H diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 00efa28161..a409a9ed13 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -46,7 +46,7 @@ void input_init(void) input_buffer = rbuffer_new(INPUT_BUFFER_SIZE + MAX_KEY_CODE_LEN); } -void input_start_stdin(void) +void input_start_stdin(int fd) { if (read_stream) { return; @@ -54,7 +54,7 @@ void input_start_stdin(void) read_buffer = rbuffer_new(READ_BUFFER_SIZE); read_stream = rstream_new(read_cb, read_buffer, NULL); - rstream_set_file(read_stream, fileno(stdin)); + rstream_set_file(read_stream, fd); rstream_start(read_stream); } @@ -69,7 +69,7 @@ void input_stop_stdin(void) read_stream = NULL; } -// Low level input function. +// Low level input function int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt) { if (rbuffer_pending(input_buffer)) { diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index 8cf7e7161d..6fcb62a5f3 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -99,7 +99,6 @@ int os_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_args) char *output = NULL, **output_ptr = NULL; int current_state = State; bool forward_output = true; - ui_flush(); // While the child is running, ignore terminating signals signal_reject_deadly(); @@ -239,7 +238,12 @@ static int shell(const char *cmd, job_close_in(job); } + // invoke busy_start here so event_poll_until wont change the busy state for + // the UI + ui_busy_start(); + ui_flush(); status = job_wait(job, -1); + ui_busy_stop(); // prepare the out parameters if requested if (output) { diff --git a/src/nvim/os_unix.c b/src/nvim/os_unix.c index 5d8b4ad26a..8e4569033a 100644 --- a/src/nvim/os_unix.c +++ b/src/nvim/os_unix.c @@ -232,15 +232,7 @@ void mch_exit(int r) { exiting = TRUE; - { - ui_builtin_stop(); - - // Cursor may have been switched off without calling starttermcap() - // when doing "vim -u vimrc" and vimrc contains ":q". */ - if (full_screen) { - ui_cursor_on(); - } - } + ui_builtin_stop(); ui_flush(); ml_close_all(TRUE); /* remove all memfiles */ diff --git a/src/nvim/os_unix_defs.h b/src/nvim/os_unix_defs.h index e5ab9fd4f7..4ffd23aa25 100644 --- a/src/nvim/os_unix_defs.h +++ b/src/nvim/os_unix_defs.h @@ -182,10 +182,6 @@ /* Special wildcards that need to be handled by the shell */ #define SPECIAL_WILDCHAR "`'{" -#ifndef HAVE_OPENDIR -# define NO_EXPANDPATH -#endif - /* * Unix has plenty of memory, use large buffers */ diff --git a/src/nvim/path.c b/src/nvim/path.c index 361a4a57f0..346be9108d 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -401,8 +401,6 @@ char_u *save_absolute_path(const char_u *name) } -#if !defined(NO_EXPANDPATH) - #if defined(UNIX) /* * Unix style wildcard expansion code. @@ -1234,7 +1232,6 @@ addfile ( add_pathsep(p); GA_APPEND(char_u *, gap, p); } -#endif /* !NO_EXPANDPATH */ /* * Converts a file name into a canonical form. It simplifies a file name into @@ -1608,7 +1605,6 @@ int same_directory(char_u *f1, char_u *f2) && pathcmp((char *)ffname, (char *)f2, (int)(t1 - ffname)) == 0; } -#if !defined(NO_EXPANDPATH) /* * Compare path "p[]" to "q[]". * If "maxlen" >= 0 compare "p[maxlen]" to "q[maxlen]" @@ -1673,9 +1669,7 @@ int pathcmp(const char *p, const char *q, int maxlen) return -1; /* no match */ return 1; } -#endif -#ifndef NO_EXPANDPATH /* * Expand a path into all matching files and/or directories. Handles "*", * "?", "[a-z]", "**", etc. @@ -1688,7 +1682,6 @@ int mch_expandpath(garray_T *gap, char_u *path, int flags) { return unix_expandpath(gap, path, 0, flags, FALSE); } -#endif /// Try to find a shortname by comparing the fullname with the current /// directory. diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c index fec7100703..6ed42303ef 100644 --- a/src/nvim/regexp_nfa.c +++ b/src/nvim/regexp_nfa.c @@ -5322,7 +5322,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm if (ireg_icombine && len == 0) { /* If \Z was present, then ignore composing characters. * When ignoring the base character this always matches. */ - if (len == 0 && sta->c != curc) + if (sta->c != curc) result = FAIL; else result = OK; diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 757bdb34b1..04a092c4f7 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -416,7 +416,6 @@ void update_screen(int type) search_hl.rm.regprog = NULL; FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_redr_type != 0) { - ui_cursor_off(); if (!did_one) { did_one = TRUE; start_search_hl(); @@ -426,7 +425,6 @@ void update_screen(int type) /* redraw status line after the window to minimize cursor movement */ if (wp->w_redr_status) { - ui_cursor_off(); win_redr_status(wp); } } @@ -521,7 +519,6 @@ void update_single_line(win_T *wp, linenr_T lnum) */ static void update_prepare(void) { - ui_cursor_off(); updating_screen = TRUE; start_search_hl(); } @@ -6566,7 +6563,6 @@ int showmode(void) /* Position on the last line in the window, column 0 */ msg_pos_mode(); - ui_cursor_off(); attr = hl_attr(HLF_CM); /* Highlight mode */ if (do_mode) { MSG_PUTS_ATTR("--", attr); @@ -7015,7 +7011,6 @@ static void win_redr_ruler(win_T *wp, int always) || wp->w_buffer->b_ml.ml_line_count != wp->w_ru_line_count || wp->w_topfill != wp->w_ru_topfill || empty_line != wp->w_ru_empty) { - ui_cursor_off(); int width; int row; @@ -7238,7 +7233,6 @@ void screen_resize(int width, int height) setcursor(); } } - ui_cursor_on(); /* redrawing may have switched it off */ } ui_flush(); --busy; diff --git a/src/nvim/search.c b/src/nvim/search.c index 6e2824bc8e..f62aeabd72 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -2044,7 +2044,6 @@ showmatch ( p_siso = 0; /* don't use 'sidescrolloff' here */ showruler(FALSE); setcursor(); - ui_cursor_on(); /* make sure that the cursor is shown */ ui_flush(); /* Restore dollar_vcol(), because setcursor() may call curs_rows() * which resets it if the matching position is in a previous line @@ -4253,7 +4252,7 @@ search_line: * looking for a define). A line starting with "# define" * is not considered to be a comment line. */ - if (!define_matched && skip_comments) { + if (skip_comments) { if ((*line != '#' || STRNCMP(skipwhite(line + 1), "define", 6) != 0) && get_leader_len(line, NULL, FALSE, TRUE)) diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 07f18bf93b..3f9466fd7c 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -5938,15 +5938,22 @@ init_highlight ( int i; char **pp; static int had_both = FALSE; - char_u *p; /* * Try finding the color scheme file. Used when a color file was loaded * and 'background' or 't_Co' is changed. */ - p = get_var_value((char_u *)"g:colors_name"); - if (p != NULL && load_colors(p) == OK) - return; + char_u *p = get_var_value((char_u *)"g:colors_name"); + if (p != NULL) { + // Value of g:colors_name could be freed in load_colors() and make + // p invalid, so copy it. + char_u *copy_p = vim_strsave(p); + bool okay = load_colors(copy_p); + free(copy_p); + if (okay) { + return; + } + } /* * Didn't use a color file, use the compiled-in colors. diff --git a/src/nvim/tag.c b/src/nvim/tag.c index 1bb18bee6e..361afb7e07 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -223,7 +223,7 @@ do_tag ( /* * Don't add a tag to the tagstack if 'tagstack' has been reset. */ - if ((!p_tgst && *tag != NUL)) { + if (!p_tgst && *tag != NUL) { use_tagstack = FALSE; new_tag = TRUE; } else { diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile index afa4ce67f4..8e0f853446 100644 --- a/src/nvim/testdir/Makefile +++ b/src/nvim/testdir/Makefile @@ -9,35 +9,28 @@ SCRIPTSOURCE := ../../../runtime SCRIPTS := test_autoformat_join.out \ test_eval.out \ - test2.out test3.out test4.out test5.out \ - test6.out test7.out test8.out test9.out test10.out \ - test11.out test12.out test13.out test14.out test15.out \ - test17.out test18.out test19.out test20.out \ - test21.out test22.out test23.out test24.out test25.out \ - test26.out test27.out test28.out test29.out test30.out \ - test31.out test32.out test33.out test34.out test35.out \ + test3.out \ + test8.out test10.out \ + test11.out test12.out test13.out test14.out \ + test17.out \ + test24.out \ + test26.out test27.out test29.out test30.out \ + test31.out test32.out test34.out \ test36.out test37.out test38.out test39.out test40.out \ - test41.out test42.out test43.out test44.out test45.out \ + test42.out test43.out test44.out test45.out \ test46.out test47.out test48.out test49.out \ - test51.out test52.out test53.out test54.out test55.out \ - test56.out test57.out test58.out test59.out test60.out \ + test52.out test53.out test55.out \ + test57.out test58.out test59.out test60.out \ test61.out test62.out test63.out test64.out test65.out \ - test66.out test67.out test68.out test69.out test70.out \ - test71.out test72.out test73.out test74.out test75.out \ - test76.out test77.out test78.out test79.out test80.out \ - test81.out test82.out test83.out test84.out test85.out \ - test86.out test87.out test88.out test89.out test90.out \ - test91.out test92.out test93.out test94.out test95.out \ - test96.out test97.out test98.out test99.out test100.out \ - test101.out test102.out test103.out test104.out test105.out \ - test106.out test107.out \ - test_options.out \ - test_listlbr.out test_listlbr_utf8.out \ - test_changelist.out \ - test_qf_title.out \ - test_breakindent.out \ - test_insertcount.out \ - test_utf8.out + test68.out test69.out test70.out \ + test71.out test73.out test74.out \ + test76.out test78.out test79.out test80.out \ + test82.out test83.out test85.out \ + test86.out test87.out test88.out \ + test92.out test93.out test94.out \ + test96.out test99.out \ + test_listlbr.out \ + test_breakindent.out SCRIPTS_GUI := test16.out diff --git a/src/nvim/testdir/test19.in b/src/nvim/testdir/test19.in deleted file mode 100644 index aafa34e521..0000000000 --- a/src/nvim/testdir/test19.in +++ /dev/null @@ -1,33 +0,0 @@ -Tests for "r<Tab>" with 'smarttab' and 'expandtab' set/not set. -Also test that dv_ works correctly - -STARTTEST -:so small.vim -:set smarttab expandtab ts=8 sw=4 -:" make sure that backspace works, no matter what termcap is used -:set t_kD=x7f t_kb=x08 -/some -r :set noexpandtab -/other -r -:" Test replacing with Tabs and then backspacing to undo it -0wR -:" Test replacing with Tabs -0wR -:" Test that copyindent works with expandtab set -:set expandtab smartindent copyindent ts=8 sw=8 sts=8 -o{ -x:set nosol -/Second line/ -fwdv_:?^start?,$w! test.out -:qa! -ENDTEST - -start text - some test text -test text - other test text - a cde - f ghi -test text - Second line beginning with whitespace diff --git a/src/nvim/testdir/test19.ok b/src/nvim/testdir/test19.ok deleted file mode 100644 index 4146214919..0000000000 --- a/src/nvim/testdir/test19.ok +++ /dev/null @@ -1,10 +0,0 @@ -start text - ome test text -test text - ther test text - a cde - hi -test text -{ - x - with whitespace diff --git a/src/nvim/testdir/test63.in b/src/nvim/testdir/test63.in deleted file mode 100644 index 7fbe0ac434..0000000000 --- a/src/nvim/testdir/test63.in +++ /dev/null @@ -1,195 +0,0 @@ -Test for ":match", ":2match", ":3match", "clearmatches()", "getmatches()", -"matchadd()", "matchaddpos()", "matcharg()", "matchdelete()", and "setmatches()". - -STARTTEST -:so small.vim -:set encoding=utf8 -:" --- Check that "matcharg()" returns the correct group and pattern if a match -:" --- is defined. -:let @r = "*** Test 1: " -:highlight MyGroup1 term=bold ctermbg=red guibg=red -:highlight MyGroup2 term=italic ctermbg=green guibg=green -:highlight MyGroup3 term=underline ctermbg=blue guibg=blue -:match MyGroup1 /TODO/ -:2match MyGroup2 /FIXME/ -:3match MyGroup3 /XXX/ -:if matcharg(1) == ['MyGroup1', 'TODO'] && matcharg(2) == ['MyGroup2', 'FIXME'] && matcharg(3) == ['MyGroup3', 'XXX'] -: let @r .= "OK\n" -:else -: let @r .= "FAILED\n" -:endif -:" --- Check that "matcharg()" returns an empty list if the argument is not 1, -:" --- 2 or 3 (only 0 and 4 are tested). -:let @r .= "*** Test 2: " -:if matcharg(0) == [] && matcharg(4) == [] -: let @r .= "OK\n" -:else -: let @r .= "FAILED\n" -:endif -:" --- Check that "matcharg()" returns ['', ''] if a match is not defined. -:let @r .= "*** Test 3: " -:match -:2match -:3match -:if matcharg(1) == ['', ''] && matcharg(2) == ['', ''] && matcharg(3) == ['', ''] -: let @r .= "OK\n" -:else -: let @r .= "FAILED\n" -:endif -:" --- Check that "matchadd()" and "getmatches()" agree on added matches and -:" --- that default values apply. -:let @r .= "*** Test 4: " -:let m1 = matchadd("MyGroup1", "TODO") -:let m2 = matchadd("MyGroup2", "FIXME", 42) -:let m3 = matchadd("MyGroup3", "XXX", 60, 17) -:if getmatches() == [{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 4}, {'group': 'MyGroup2', 'pattern': 'FIXME', 'priority': 42, 'id': 5}, {'group': 'MyGroup3', 'pattern': 'XXX', 'priority': 60, 'id': 17}] -: let @r .= "OK\n" -:else -: let @r .= "FAILED\n" -:endif -:" --- Check that "matchdelete()" deletes the matches defined in the previous -:" --- test correctly. -:let @r .= "*** Test 5: " -:call matchdelete(m1) -:call matchdelete(m2) -:call matchdelete(m3) -:unlet m1 -:unlet m2 -:unlet m3 -:if getmatches() == [] -: let @r .= "OK\n" -:else -: let @r .= "FAILED\n" -:endif -:" --- Check that "matchdelete()" returns 0 if successful and otherwise -1. -:let @r .= "*** Test 6: " -:let m = matchadd("MyGroup1", "TODO") -:let r1 = matchdelete(m) -:let r2 = matchdelete(42) -:if r1 == 0 && r2 == -1 -: let @r .= "OK\n" -:else -: let @r .= "FAILED\n" -:endif -:unlet m -:unlet r1 -:unlet r2 -:" --- Check that "clearmatches()" clears all matches defined by ":match" and -:" --- "matchadd()". -:let @r .= "*** Test 7: " -:let m1 = matchadd("MyGroup1", "TODO") -:let m2 = matchadd("MyGroup2", "FIXME", 42) -:let m3 = matchadd("MyGroup3", "XXX", 60, 17) -:match MyGroup1 /COFFEE/ -:2match MyGroup2 /HUMPPA/ -:3match MyGroup3 /VIM/ -:call clearmatches() -:if getmatches() == [] -: let @r .= "OK\n" -:else -: let @r .= "FAILED\n" -:endif -:unlet m1 -:unlet m2 -:unlet m3 -:" --- Check that "setmatches()" restores a list of matches saved by -:" --- "getmatches()" without changes. (Matches with equal priority must also -:" --- remain in the same order.) -:let @r .= "*** Test 8: " -:let m1 = matchadd("MyGroup1", "TODO") -:let m2 = matchadd("MyGroup2", "FIXME", 42) -:let m3 = matchadd("MyGroup3", "XXX", 60, 17) -:match MyGroup1 /COFFEE/ -:2match MyGroup2 /HUMPPA/ -:3match MyGroup3 /VIM/ -:let ml = getmatches() -:call clearmatches() -:call setmatches(ml) -:if getmatches() == ml -: let @r .= "OK\n" -:else -: let @r .= "FAILED\n" -:endif -:call clearmatches() -:unlet m1 -:unlet m2 -:unlet m3 -:unlet ml -:" --- Check that "setmatches()" will not add two matches with the same ID. The -:" --- expected behaviour (for now) is to add the first match but not the -:" --- second and to return 0 (even though it is a matter of debate whether -:" --- this can be considered successful behaviour). -:let @r .= "*** Test 9: " -:let r1 = setmatches([{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1}, {'group': 'MyGroup2', 'pattern': 'FIXME', 'priority': 10, 'id': 1}]) -:if getmatches() == [{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1}] && r1 == 0 -: let @r .= "OK\n" -:else -: let @r .= "FAILED\n" -:endif -:call clearmatches() -:unlet r1 -:" --- Check that "setmatches()" returns 0 if successful and otherwise -1. -:" --- (A range of valid and invalid input values are tried out to generate the -:" --- return values.) -:let @r .= "*** Test 10: " -:let rs1 = setmatches([]) -:let rs2 = setmatches([{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1}]) -:call clearmatches() -:let rf1 = setmatches(0) -:let rf2 = setmatches([0]) -:let rf3 = setmatches([{'wrong key': 'wrong value'}]) -:if rs1 == 0 && rs2 == 0 && rf1 == -1 && rf2 == -1 && rf3 == -1 -: let @r .= "OK\n" -:else -: let @r .= "FAILED\n" -:endif -:unlet rs1 -:unlet rs2 -:unlet rf1 -:unlet rf2 -:unlet rf3 -:" --- Check that "matchaddpos()" positions matches correctly -:let @r .= "*** Test 11:\n" -:set nolazyredraw -:call setline(1, 'abcdefghijklmnopq') -:call matchaddpos("MyGroup1", [[1, 5], [1, 8, 3]], 10, 3) -:1 -:redraw! -:let v1 = screenattr(1, 1) -:let v5 = screenattr(1, 5) -:let v6 = screenattr(1, 6) -:let v8 = screenattr(1, 8) -:let v10 = screenattr(1, 10) -:let v11 = screenattr(1, 11) -:let @r .= string(getmatches())."\n" -:if v1 != v5 && v6 == v1 && v8 == v5 && v10 == v5 && v11 == v1 -: let @r .= "OK\n" -:else -: let @r .= "FAILED: " . v5 . "/" . v6 . "/" . v8 . "/" . v10 . "/" . v11 . "\n" -:endif -:call clearmatches() -:" -:call setline(1, 'abcdΣabcdef') -:call matchaddpos("MyGroup1", [[1, 4, 2], [1, 9, 2]]) -:1 -:redraw! -:let v1 = screenattr(1, 1) -:let v4 = screenattr(1, 4) -:let v5 = screenattr(1, 5) -:let v6 = screenattr(1, 6) -:let v7 = screenattr(1, 7) -:let v8 = screenattr(1, 8) -:let v9 = screenattr(1, 9) -:let v10 = screenattr(1, 10) -:let @r .= string(getmatches())."\n" -:if v1 != v4 && v5 == v4 && v6 == v1 && v7 == v1 && v8 == v4 && v9 == v4 && v10 == v1 -: let @r .= "OK\n" -:else -: let @r .= "FAILED: " . v4 . "/" . v5 . "/" . v6 . "/" . v7 . "/" . v8 . "/" . v9 . "/" . v10 . "\n" -:endif -:call clearmatches() -G"rp -:/^Results/,$wq! test.out -ENDTEST - -Results of test63: diff --git a/src/nvim/testdir/test63.ok b/src/nvim/testdir/test63.ok deleted file mode 100644 index 5d619395b7..0000000000 --- a/src/nvim/testdir/test63.ok +++ /dev/null @@ -1,16 +0,0 @@ -Results of test63: -*** Test 1: OK -*** Test 2: OK -*** Test 3: OK -*** Test 4: OK -*** Test 5: OK -*** Test 6: OK -*** Test 7: OK -*** Test 8: OK -*** Test 9: OK -*** Test 10: OK -*** Test 11: -[{'group': 'MyGroup1', 'id': 3, 'priority': 10, 'pos1': [1, 5, 1], 'pos2': [1, 8, 3]}] -OK -[{'group': 'MyGroup1', 'id': 11, 'priority': 10, 'pos1': [1, 4, 2], 'pos2': [1, 9, 2]}] -OK diff --git a/src/nvim/testdir/test89.in b/src/nvim/testdir/test89.in deleted file mode 100644 index f1f64fb41f..0000000000 --- a/src/nvim/testdir/test89.in +++ /dev/null @@ -1,71 +0,0 @@ -- Some tests for setting 'number' and 'relativenumber' - This is not all that useful now that the options are no longer reset when - setting the other. -- Some tests for findfile() function - -STARTTEST -:so small.vim -:set hidden nu rnu -:redir @a | set nu? rnu? | redir END -:e! xx -:redir @b | set nu? rnu? | redir END -:e! # -:$put ='results:' -:$put a -:$put b -:" -:set nonu nornu -:setglobal nu -:setlocal rnu -:redir @c | setglobal nu? | redir END -:set nonu nornu -:setglobal rnu -:setlocal nu -:redir @d | setglobal rnu? | redir END -:$put =':setlocal must NOT reset the other global value' -:$put c -:$put d -:" -:set nonu nornu -:setglobal nu -:setglobal rnu -:redir @e | setglobal nu? | redir END -:set nonu nornu -:setglobal rnu -:setglobal nu -:redir @f | setglobal rnu? | redir END -:$put =':setglobal MUST reset the other global value' -:$put e -:$put f -:" -:set nonu nornu -:set nu -:set rnu -:redir @g | setglobal nu? | redir END -:set nonu nornu -:set rnu -:set nu -:redir @h | setglobal rnu? | redir END -:$put =':set MUST reset the other global value' -:$put g -:$put h -:" -:let cwd=getcwd() -:cd .. -:" Tests may be run from a shadow directory, so an extra cd needs to be done to -:" get above src/ -:if fnamemodify(getcwd(), ':t') != 'src' | cd ../.. | else | cd .. | endif -:$put ='' -:$put ='Testing findfile' -:$put ='' -:set ssl -:$put =findfile('test19.in','src/nvim/test*') -:exe "cd" cwd -:cd .. -:$put =findfile('test19.in','test*') -:$put =findfile('test19.in','testdir') -:exe "cd" cwd -:/^results/,$w! test.out -:q! -ENDTEST - diff --git a/src/nvim/testdir/test89.ok b/src/nvim/testdir/test89.ok deleted file mode 100644 index c8accd8569..0000000000 --- a/src/nvim/testdir/test89.ok +++ /dev/null @@ -1,28 +0,0 @@ -results: - - number - relativenumber - - number - relativenumber -:setlocal must NOT reset the other global value - - number - - relativenumber -:setglobal MUST reset the other global value - - number - - relativenumber -:set MUST reset the other global value - - number - - relativenumber - -Testing findfile - -src/nvim/testdir/test19.in -testdir/test19.in -testdir/test19.in diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index b95a22d48b..4736e7a8ba 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -16,6 +16,11 @@ #include "nvim/os/event.h" #include "nvim/tui/tui.h" +// Space reserved in the output buffer to restore the cursor to normal when +// flushing. No existing terminal will require 32 bytes to do that. +#define CNORM_COMMAND_MAX_SIZE 32 +#define OUTBUF_SIZE 0xffff + typedef struct term_input TermInput; #include "term_input.inl" @@ -31,8 +36,8 @@ typedef struct { typedef struct { unibi_var_t params[9]; - char buf[0xffff]; - size_t bufpos; + char buf[OUTBUF_SIZE]; + size_t bufpos, bufsize; TermInput *input; uv_loop_t *write_loop; unibi_term *ut; @@ -45,6 +50,7 @@ typedef struct { int out_fd; int old_height; bool can_use_terminal_scroll; + bool busy; HlAttrs attrs, print_attrs; Cell **screen; struct { @@ -86,6 +92,7 @@ void tui_start(void) data->fg = data->bg = -1; data->can_use_terminal_scroll = true; data->bufpos = 0; + data->bufsize = sizeof(data->buf) - CNORM_COMMAND_MAX_SIZE; data->unibi_ext.enable_mouse = -1; data->unibi_ext.disable_mouse = -1; data->unibi_ext.enable_bracketed_paste = -1; @@ -134,8 +141,8 @@ void tui_start(void) ui->clear = tui_clear; ui->eol_clear = tui_eol_clear; ui->cursor_goto = tui_cursor_goto; - ui->cursor_on = tui_cursor_on; - ui->cursor_off = tui_cursor_off; + ui->busy_start = tui_busy_start; + ui->busy_stop = tui_busy_stop; ui->mouse_on = tui_mouse_on; ui->mouse_off = tui_mouse_off; ui->insert_mode = tui_insert_mode; @@ -169,6 +176,7 @@ static void tui_stop(UI *ui) tui_normal_mode(ui); tui_mouse_off(ui); unibi_out(ui, unibi_exit_attribute_mode); + // cursor should be set to normal before exiting alternate screen unibi_out(ui, unibi_cursor_normal); unibi_out(ui, unibi_exit_ca_mode); // Disable bracketed paste @@ -342,14 +350,14 @@ static void tui_cursor_goto(UI *ui, int row, int col) unibi_goto(ui, row, col); } -static void tui_cursor_on(UI *ui) +static void tui_busy_start(UI *ui) { - unibi_out(ui, unibi_cursor_normal); + ((TUIData *)ui->data)->busy = true; } -static void tui_cursor_off(UI *ui) +static void tui_busy_stop(UI *ui) { - unibi_out(ui, unibi_cursor_invisible); + ((TUIData *)ui->data)->busy = false; } static void tui_mouse_on(UI *ui) @@ -527,6 +535,7 @@ static void tui_flush(UI *ui) } unibi_goto(ui, data->row, data->col); + flush_buf(ui); } @@ -657,7 +666,7 @@ static void out(void *ctx, const char *str, size_t len) { UI *ui = ctx; TUIData *data = ui->data; - size_t available = sizeof(data->buf) - data->bufpos; + size_t available = data->bufsize - data->bufpos; if (len > available) { flush_buf(ui); @@ -781,14 +790,29 @@ end: static void flush_buf(UI *ui) { - static uv_write_t req; - static uv_buf_t buf; + uv_write_t req; + uv_buf_t buf; TUIData *data = ui->data; + + if (!data->busy) { + // not busy and the cursor is invisible(see below). Append a "cursor + // normal" command to the end of the buffer. + data->bufsize += CNORM_COMMAND_MAX_SIZE; + unibi_out(ui, unibi_cursor_normal); + data->bufsize -= CNORM_COMMAND_MAX_SIZE; + } + buf.base = data->buf; buf.len = data->bufpos; uv_write(&req, (uv_stream_t *)&data->output_handle, &buf, 1, NULL); uv_run(data->write_loop, UV_RUN_DEFAULT); data->bufpos = 0; + + if (!data->busy) { + // not busy and cursor is visible(see above), append a "cursor invisible" + // command to the beginning of the buffer for the next flush + unibi_out(ui, unibi_cursor_invisible); + } } static void destroy_screen(TUIData *data) diff --git a/src/nvim/ui.c b/src/nvim/ui.c index 62cc662b5b..443b50da87 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -44,7 +44,8 @@ static struct { int top, bot, left, right; } sr; static int current_attr_code = 0; -static bool cursor_enabled = true, pending_cursor_update = false; +static bool pending_cursor_update = false; +static int busy = 0; static int height, width; // This set of macros allow us to use UI_CALL to invoke any function on @@ -150,21 +151,17 @@ void ui_resize(int new_width, int new_height) UI_CALL(resize, width, height); } -void ui_cursor_on(void) +void ui_busy_start(void) { - if (!cursor_enabled) { - UI_CALL(cursor_on); - cursor_enabled = true; + if (!(busy++)) { + UI_CALL(busy_start); } } -void ui_cursor_off(void) +void ui_busy_stop(void) { - if (full_screen) { - if (cursor_enabled) { - UI_CALL(cursor_off); - } - cursor_enabled = false; + if (!(--busy)) { + UI_CALL(busy_stop); } } diff --git a/src/nvim/ui.h b/src/nvim/ui.h index 4bc3983578..71ed9b3097 100644 --- a/src/nvim/ui.h +++ b/src/nvim/ui.h @@ -20,8 +20,8 @@ struct ui_t { void (*clear)(UI *ui); void (*eol_clear)(UI *ui); void (*cursor_goto)(UI *ui, int row, int col); - void (*cursor_on)(UI *ui); - void (*cursor_off)(UI *ui); + void (*busy_start)(UI *ui); + void (*busy_stop)(UI *ui); void (*mouse_on)(UI *ui); void (*mouse_off)(UI *ui); void (*insert_mode)(UI *ui); diff --git a/src/nvim/undo.c b/src/nvim/undo.c index 2c287e0fdf..06dc325fea 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -99,7 +99,6 @@ #include "nvim/memline.h" #include "nvim/message.h" #include "nvim/misc1.h" -#include "nvim/misc2.h" #include "nvim/memory.h" #include "nvim/garray.h" #include "nvim/option.h" diff --git a/src/nvim/version.c b/src/nvim/version.c index 2c819c6f42..f876e78388 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -178,6 +178,48 @@ static char *(features[]) = { // clang-format off static int included_patches[] = { + //662, + //661, + 660, + //659, + //658, + //657, + //656, + //655, + //654, + //653, + //652, + //651, + //650, + //649, + //648, + //647, + //646, + //645, + //644, + //643, + //642, + //641, + //640, + //639, + //638, + 637, + //636, + //635, + //634, + //633, + //632, + //631, + //630, + //629, + //628, + //627, + //626, + //625, + //624, + //623, + //622, + //621, //620, //619, //618, diff --git a/src/nvim/vim.h b/src/nvim/vim.h index 8f80efd88a..29d61dcbde 100644 --- a/src/nvim/vim.h +++ b/src/nvim/vim.h @@ -184,13 +184,6 @@ enum { }; -#ifdef NO_EXPANDPATH -# define gen_expand_wildcards mch_expand_wildcards -#endif - - - - diff --git a/test/functional/legacy/019_smarttab_expandtab_spec.lua b/test/functional/legacy/019_smarttab_expandtab_spec.lua new file mode 100644 index 0000000000..a33bd0c3ae --- /dev/null +++ b/test/functional/legacy/019_smarttab_expandtab_spec.lua @@ -0,0 +1,56 @@ +-- Tests for "r<Tab>" with 'smarttab' and 'expandtab' set/not set. +-- Also test that dv_ works correctly + +local helpers = require('test.functional.helpers') +local feed, insert = helpers.feed, helpers.insert +local clear, execute, expect = helpers.clear, helpers.execute, helpers.expect + +describe([[performing "r<Tab>" with 'smarttab' and 'expandtab' set/not set, and "dv_"]], function() + setup(clear) + + it('is working', function() + insert([[ + start text + some test text + test text + other test text + a cde + f ghi + test text + Second line beginning with whitespace]]) + + execute('set smarttab expandtab ts=8 sw=4') + -- Make sure that backspace works, no matter what termcap is used. + execute('set t_kD=x7f t_kb=x08') + + execute('/some') + feed('r ') + execute('set noexpandtab') + execute('/other') + feed('r <cr>') + -- Test replacing with Tabs and then backspacing to undo it. + feed('0wR <bs><bs><bs><esc><cr>') + -- Test replacing with Tabs. + feed('0wR <esc><cr>') + -- Test that copyindent works with expandtab set. + execute('set expandtab smartindent copyindent ts=8 sw=8 sts=8') + feed('o{<cr>x<esc>') + execute('set nosol') + execute('/Second line/') + -- Test "dv_" + feed('fwdv_') + + -- Assert buffer contents. + expect([[ + start text + ome test text + test text + ther test text + a cde + hi + test text + { + x + with whitespace]]) + end) +end) diff --git a/test/functional/legacy/063_match_and_matchadd_spec.lua b/test/functional/legacy/063_match_and_matchadd_spec.lua new file mode 100644 index 0000000000..d819db7812 --- /dev/null +++ b/test/functional/legacy/063_match_and_matchadd_spec.lua @@ -0,0 +1,141 @@ +-- Tests for adjusting window and contents + +local helpers = require('test.functional.helpers') +local Screen = require('test.functional.ui.screen') +local feed, insert, source = helpers.feed, helpers.insert, helpers.source +local eval, clear, execute, expect = helpers.eval, helpers.clear, helpers.execute +local expect, eq, neq = helpers.expect, helpers.eq, helpers.neq +local command = helpers.command + +describe('063: Test for ":match", "matchadd()" and related functions', function() + setup(clear) + + it('is working', function() + local screen = Screen.new(40, 5) + screen:attach() + + -- Check that "matcharg()" returns the correct group and pattern if a match + -- is defined. + execute("highlight MyGroup1 term=bold ctermbg=red guibg=red") + execute("highlight MyGroup2 term=italic ctermbg=green guibg=green") + execute("highlight MyGroup3 term=underline ctermbg=blue guibg=blue") + execute("match MyGroup1 /TODO/") + execute("2match MyGroup2 /FIXME/") + execute("3match MyGroup3 /XXX/") + eq({'MyGroup1', 'TODO'}, eval('matcharg(1)')) + eq({'MyGroup2', 'FIXME'}, eval('matcharg(2)')) + eq({'MyGroup3', 'XXX'}, eval('matcharg(3)')) + + -- Check that "matcharg()" returns an empty list if the argument is not 1, + -- 2 or 3 (only 0 and 4 are tested). + eq({}, eval('matcharg(0)')) + eq({}, eval('matcharg(4)')) + + -- Check that "matcharg()" returns ['', ''] if a match is not defined. + execute("match") + execute("2match") + execute("3match") + eq({'', ''}, eval('matcharg(1)')) + eq({'', ''}, eval('matcharg(2)')) + eq({'', ''}, eval('matcharg(3)')) + + -- Check that "matchadd()" and "getmatches()" agree on added matches and + -- that default values apply. + execute("let m1 = matchadd('MyGroup1', 'TODO')") + execute("let m2 = matchadd('MyGroup2', 'FIXME', 42)") + execute("let m3 = matchadd('MyGroup3', 'XXX', 60, 17)") + eq({{group = 'MyGroup1', pattern = 'TODO', priority = 10, id = 4}, + {group = 'MyGroup2', pattern = 'FIXME', priority = 42, id = 5}, + {group = 'MyGroup3', pattern = 'XXX', priority = 60, id = 17}}, + eval('getmatches()')) + + -- Check that "matchdelete()" deletes the matches defined in the previous + -- test correctly. + execute("call matchdelete(m1)") + execute("call matchdelete(m2)") + execute("call matchdelete(m3)") + eq({}, eval('getmatches()')) + + --- Check that "matchdelete()" returns 0 if successful and otherwise -1. + execute("let m = matchadd('MyGroup1', 'TODO')") + eq(0, eval('matchdelete(m)')) + + -- matchdelete throws error and returns -1 on failure + neq(true, pcall(function() eval('matchdelete(42)') end)) + execute("let r2 = matchdelete(42)") + eq(-1, eval('r2')) + + -- Check that "clearmatches()" clears all matches defined by ":match" and + -- "matchadd()". + execute("let m1 = matchadd('MyGroup1', 'TODO')") + execute("let m2 = matchadd('MyGroup2', 'FIXME', 42)") + execute("let m3 = matchadd('MyGroup3', 'XXX', 60, 17)") + execute("match MyGroup1 /COFFEE/") + execute("2match MyGroup2 /HUMPPA/") + execute("3match MyGroup3 /VIM/") + execute("call clearmatches()") + eq({}, eval('getmatches()')) + + -- Check that "setmatches()" restores a list of matches saved by + -- "getmatches()" without changes. (Matches with equal priority must also + -- remain in the same order.) + execute("let m1 = matchadd('MyGroup1', 'TODO')") + execute("let m2 = matchadd('MyGroup2', 'FIXME', 42)") + execute("let m3 = matchadd('MyGroup3', 'XXX', 60, 17)") + execute("match MyGroup1 /COFFEE/") + execute("2match MyGroup2 /HUMPPA/") + execute("3match MyGroup3 /VIM/") + execute("let ml = getmatches()") + ml = eval("ml") + execute("call clearmatches()") + execute("call setmatches(ml)") + eq(ml, eval('getmatches()')) + execute("call clearmatches()") + + -- Check that "setmatches()" will not add two matches with the same ID. The + -- expected behaviour (for now) is to add the first match but not the + -- second and to return 0 (even though it is a matter of debate whether + -- this can be considered successful behaviour). + execute("let r1 = setmatches([{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1}, {'group': 'MyGroup2', 'pattern': 'FIXME', 'priority': 10, 'id': 1}])") + feed("<cr>") + eq(0, eval("r1")) + eq({{group = 'MyGroup1', pattern = 'TODO', priority = 10, id = 1}}, eval('getmatches()')) + + -- Check that "setmatches()" returns 0 if successful and otherwise -1. + -- (A range of valid and invalid input values are tried out to generate the + -- return values.) + eq(0,eval("setmatches([])")) + eq(0,eval("setmatches([{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1}])")) + execute("call clearmatches()") + execute("let rf1 = setmatches(0)") + eq(-1, eval('rf1')) + execute("let rf2 = setmatches([0])") + eq(-1, eval('rf2')) + execute("let rf3 = setmatches([{'wrong key': 'wrong value'}])") + feed("<cr>") + eq(-1, eval('rf3')) + + -- Check that "matchaddpos()" positions matches correctly + insert('abcdefghijklmnopq') + execute("call matchaddpos('MyGroup1', [[1, 5], [1, 8, 3]], 10, 3)") + screen:expect([[ + abcd{1:e}fg{1:hij}klmnop^q | + ~ | + ~ | + ~ | + | + ]], {[1] = {background = Screen.colors.Red}}, {{bold = true, foreground = Screen.colors.Blue}}) + + execute("call clearmatches()") + execute("call setline(1, 'abcdΣabcdef')") + execute("call matchaddpos('MyGroup1', [[1, 4, 2], [1, 9, 2]])") + screen:expect([[ + abc{1:dΣ}ab{1:cd}e^f | + ~ | + ~ | + ~ | + | + ]],{[1] = {background = Screen.colors.Red}}, {{bold = true, foreground = Screen.colors.Blue}}) + end) +end) + diff --git a/test/functional/legacy/089_number_relnumber_findfile_spec.lua b/test/functional/legacy/089_number_relnumber_findfile_spec.lua new file mode 100644 index 0000000000..1f8e49cc81 --- /dev/null +++ b/test/functional/legacy/089_number_relnumber_findfile_spec.lua @@ -0,0 +1,116 @@ +-- - Some tests for setting 'number' and 'relativenumber' +-- This is not all that useful now that the options are no longer reset when +-- setting the other. + +local helpers = require('test.functional.helpers') +local feed = helpers.feed +local clear, execute, expect, source = helpers.clear, helpers.execute, helpers.expect, helpers.source + +describe("setting 'number' and 'relativenumber'", function() + setup(clear) + + it('is working', function() + source([[ + set hidden nu rnu + redir @a | set nu? | set rnu? | redir END + e! xx + redir @b | set nu? | set rnu? | redir END + e! # + $put ='results:' + $put a + $put b + + set nonu nornu + setglobal nu + setlocal rnu + redir @c | setglobal nu? | redir END + set nonu nornu + setglobal rnu + setlocal nu + redir @d | setglobal rnu? | redir END + $put =':setlocal must NOT reset the other global value' + $put c + $put d + + set nonu nornu + setglobal nu + setglobal rnu + redir @e | setglobal nu? | redir END + set nonu nornu + setglobal rnu + setglobal nu + redir @f | setglobal rnu? | redir END + $put =':setglobal MUST reset the other global value' + $put e + $put f + + set nonu nornu + set nu + set rnu + redir @g | setglobal nu? | redir END + set nonu nornu + set rnu + set nu + redir @h | setglobal rnu? | redir END + $put =':set MUST reset the other global value' + $put g + $put h + ]]) + + -- Remove empty line + feed('ggdd') + + -- Assert buffer contents. + expect([[ + results: + + number + relativenumber + + number + relativenumber + :setlocal must NOT reset the other global value + + number + + relativenumber + :setglobal MUST reset the other global value + + number + + relativenumber + :set MUST reset the other global value + + number + + relativenumber]]) + end) +end) + +-- - Some tests for findfile() function +describe('findfile', function() + setup(clear) + + it('is working', function() + -- Assume test is being run from project root + source([[ + $put ='Testing findfile' + $put ='' + set ssl + $put =findfile('vim.c','src/nvim/ap*') + cd src/nvim + $put =findfile('vim.c','ap*') + $put =findfile('vim.c','api') + ]]) + + -- Remove empty line + feed('ggdd') + + expect([[ + Testing findfile + + src/nvim/api/vim.c + api/vim.c + api/vim.c]]) + end) +end) diff --git a/test/functional/shell/viml_system_spec.lua b/test/functional/shell/viml_system_spec.lua index 2742e23e00..c9ae92048c 100644 --- a/test/functional/shell/viml_system_spec.lua +++ b/test/functional/shell/viml_system_spec.lua @@ -93,7 +93,7 @@ describe('system()', function() ~ | ~ | ~ | - ^:call system("yes") | + :call system("yes") | ]]) feed('<c-c>') screen:expect([[ @@ -259,7 +259,7 @@ describe('systemlist()', function() ~ | ~ | ~ | - ^:call systemlist("yes | xargs") | + :call systemlist("yes | xargs") | ]]) feed('<c-c>') screen:expect([[ diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index 585037466e..f79d634536 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -164,8 +164,9 @@ function Screen.new(width, height) _mouse_enabled = true, _attrs = {}, _cursor = { - enabled = true, row = 1, col = 1 - } + row = 1, col = 1 + }, + _busy = false }, Screen) self:_handle_resize(width, height) return self @@ -282,12 +283,12 @@ function Screen:_handle_cursor_goto(row, col) self._cursor.col = col + 1 end -function Screen:_handle_cursor_on() - self._cursor.enabled = true +function Screen:_handle_busy_start() + self._busy = true end -function Screen:_handle_cursor_off() - self._cursor.enabled = false +function Screen:_handle_busy_stop() + self._busy = false end function Screen:_handle_mouse_on() @@ -416,7 +417,7 @@ function Screen:_row_repr(row, attr_ids, attr_ignore) table.insert(rv, '{' .. attr_id .. ':') current_attr_id = attr_id end - if self._rows[self._cursor.row] == row and self._cursor.col == i then + if not self._busy and self._rows[self._cursor.row] == row and self._cursor.col == i then table.insert(rv, '^') end table.insert(rv, row[i].text) diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua index 366a0af453..034e9a05d7 100644 --- a/test/functional/ui/screen_basic_spec.lua +++ b/test/functional/ui/screen_basic_spec.lua @@ -10,7 +10,7 @@ describe('Screen', function() clear() screen = Screen.new() screen:attach() - screen:set_default_attr_ignore( {{}, {bold=true, foreground=255}} ) + screen:set_default_attr_ignore( {{bold=true, foreground=255}} ) end) after_each(function() diff --git a/test/functional/ui/searchhl_spec.lua b/test/functional/ui/searchhl_spec.lua new file mode 100644 index 0000000000..6986abdd65 --- /dev/null +++ b/test/functional/ui/searchhl_spec.lua @@ -0,0 +1,241 @@ +local helpers = require('test.functional.helpers') +local Screen = require('test.functional.ui.screen') +local clear, feed, nvim, insert = helpers.clear, helpers.feed, helpers.nvim, helpers.insert +local execute, request, eq = helpers.execute, helpers.request, helpers.eq + +describe('search highlighting', function() + local screen + local colors = Screen.colors + local hl_colors = { + NonText = colors.Blue, + Search = colors.Yellow, + Message = colors.Red, + } + + before_each(function() + clear() + screen = Screen.new(40, 7) + screen:attach() + --ignore highligting of ~-lines + screen:set_default_attr_ids( { + [1] = {background = hl_colors.Search}, + [2] = {reverse = true}, + [3] = {foreground = hl_colors.Message}, + }) + screen:set_default_attr_ignore( {{bold=true, foreground=hl_colors.NonText}} ) + end) + + it('is off by default', function() + insert("some text\nmore text") + feed("gg/text<cr>") + screen:expect([[ + some ^text | + more text | + ~ | + ~ | + ~ | + ~ | + /text | + ]]) + end) + + it('works', function() + execute('set hlsearch') + insert([[ + some text + more textstuff + stupidtexttextstuff + a text word + ]]) + feed("gg/text<cr>") + screen:expect([[ + some {1:^text} | + more {1:text}stuff | + stupid{1:texttext}stuff | + a {1:text} word | + | + ~ | + /text | + ]]) + + -- overlapping matches not allowed + feed("3nx") + screen:expect([[ + some {1:text} | + more {1:text}stuff | + stupid{1:text}^extstuff | + a {1:text} word | + | + ~ | + /text | + ]]) + + feed("ggn*") -- search for entire word + screen:expect([[ + some {1:text} | + more textstuff | + stupidtextextstuff | + a {1:^text} word | + | + ~ | + /\<text\> | + ]]) + + execute("nohlsearch") + screen:expect([[ + some text | + more textstuff | + stupidtextextstuff | + a ^text word | + | + ~ | + :nohlsearch | + ]]) + end) + + it('works with incsearch', function() + execute('set hlsearch') + execute('set incsearch') + insert([[ + the first line + in a little file + ]]) + feed("gg/li") + screen:expect([[ + the first {2:li}ne | + in a little file | + | + ~ | + ~ | + ~ | + /li^ | + ]]) + + feed("t") + screen:expect([[ + the first line | + in a {2:lit}tle file | + | + ~ | + ~ | + ~ | + /lit^ | + ]]) + + feed("<cr>") + screen:expect([[ + the first line | + in a {1:^lit}tle file | + | + ~ | + ~ | + ~ | + /lit | + ]]) + + feed("/fir") + screen:expect([[ + the {2:fir}st line | + in a {1:lit}tle file | + | + ~ | + ~ | + ~ | + /fir^ | + ]]) + + -- incsearch have priority over hlsearch + feed("<esc>/ttle") + screen:expect([[ + the first line | + in a {1:li}{2:ttle} file | + | + ~ | + ~ | + ~ | + /ttle^ | + ]]) + end) + + it('works with multiline regexps', function() + execute('set hlsearch') + feed('4oa repeated line<esc>') + feed('/line\\na<cr>') + screen:expect([[ + | + a repeated {1:^line} | + {1:a} repeated {1:line} | + {1:a} repeated {1:line} | + {1:a} repeated line | + ~ | + {3:search hit BOTTOM, continuing at TOP} | + ]]) + + -- it redraws rows above the changed one + feed('4Grb') + screen:expect([[ + | + a repeated {1:line} | + {1:a} repeated line | + ^b repeated {1:line} | + {1:a} repeated line | + ~ | + {3:search hit BOTTOM, continuing at TOP} | + ]]) + end) + + it('works with matchadd and syntax', function() + execute('set hlsearch') + insert([[ + very special text + ]]) + execute("syntax on") + execute("highlight MyGroup guibg=Green gui=bold") + execute("highlight MyGroup2 guibg=Magenta gui=italic") + execute("call matchadd('MyGroup', 'special')") + execute("call matchadd('MyGroup2', 'text', 0)") + + -- searchhl and matchadd matches are exclusive, only the higest priority + -- is used (and matches with lower priorities are not combined) + execute("/ial te") + screen:expect([[ + very {4:spec^ial}{1: te}{5:xt} | + | + ~ | + ~ | + ~ | + ~ | + {3:search hit BOTTOM, continuing at TOP} | + ]], {[1] = {background = hl_colors.Search}, [2] = {reverse = true}, + [3] = {foreground = hl_colors.Message}, [4] = {bold = true, background = + colors.Green}, [5] = {italic = true, background = colors.Magenta}}) + + execute("call clearmatches()") + screen:expect([[ + very spec{1:^ial te}xt | + | + ~ | + ~ | + ~ | + ~ | + :call clearmatches() | + ]]) + + -- searchhl has priority over syntax, but in this case + -- nonconflicting attributes are combined + execute("syntax keyword MyGroup special") + screen:expect([[ + very {4:spec}{5:^ial}{1: te}xt | + | + ~ | + ~ | + ~ | + ~ | + :syntax keyword MyGroup special | + ]], {[1] = {background = hl_colors.Search}, [2] = {reverse = true}, + [3] = {foreground = hl_colors.Message}, [4] = {bold = true, + background = colors.Green}, [5] = {bold = true, background = hl_colors.Search}}) + + end) +end) + diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt index 2eb1bee765..2def052aef 100644 --- a/third-party/CMakeLists.txt +++ b/third-party/CMakeLists.txt @@ -13,7 +13,7 @@ set(DEPS_DOWNLOAD_DIR "${DEPS_BUILD_DIR}/downloads") option(USE_BUNDLED "Use bundled dependencies." ON) -option(USE_BUNDLED_LIBUNIBILIUM "Use the bundled libunibilium." ${USE_BUNDLED}) +option(USE_BUNDLED_UNIBILIUM "Use the bundled unibilium." ${USE_BUNDLED}) option(USE_BUNDLED_LIBTERMKEY "Use the bundled libtermkey." ${USE_BUNDLED}) option(USE_BUNDLED_LIBVTERM "Use the bundled libvterm." ${USE_BUNDLED}) option(USE_BUNDLED_LIBUV "Use the bundled libuv." ${USE_BUNDLED}) @@ -64,8 +64,8 @@ set(LUAJIT_SHA256 55be6cb2d101ed38acca32c5b1f99ae345904b365b642203194c585d27bebd set(LUAROCKS_URL https://github.com/keplerproject/luarocks/archive/0587afbb5fe8ceb2f2eea16f486bd6183bf02f29.tar.gz) set(LUAROCKS_SHA256 c8ad50938fed66beba74a73621d14121d4a40b796e01c45238de4cdcb47d5e0b) -set(LIBUNIBILIUM_URL https://github.com/mauke/unibilium/archive/bb979ff6f66a18663e15d086dec6276561b86ee0.tar.gz) -set(LIBUNIBILIUM_SHA256 bec06ea90128b46f28b91b8b52b861dede5f4ede0a92f05178b3c7bcec237dd1) +set(UNIBILIUM_URL https://github.com/mauke/unibilium/archive/bb979ff6f66a18663e15d086dec6276561b86ee0.tar.gz) +set(UNIBILIUM_SHA256 bec06ea90128b46f28b91b8b52b861dede5f4ede0a92f05178b3c7bcec237dd1) set(LIBTERMKEY_URL https://github.com/neovim/libtermkey/archive/8c0cb7108cc63218ea19aa898968eede19e19603.tar.gz) set(LIBTERMKEY_SHA256 21846369081e6c9a0b615f4b3889c4cb809321c5ccc6e6c1640eb138f1590072) @@ -74,8 +74,8 @@ set(LIBVTERM_URL https://github.com/neovim/libvterm/archive/1b745d29d45623aa8d22 set(LIBVTERM_SHA256 3fc75908256c0d158d6c2a32d39f34e86bfd26364f5404b7d9c03bb70cdc3611) -if(USE_BUNDLED_LIBUNIBILIUM) - include(BuildLibunibilium) +if(USE_BUNDLED_UNIBILIUM) + include(BuildUnibilium) endif() if(USE_BUNDLED_LIBTERMKEY) diff --git a/third-party/cmake/BuildLibtermkey.cmake b/third-party/cmake/BuildLibtermkey.cmake index 43ecc52538..2570dadc0e 100644 --- a/third-party/cmake/BuildLibtermkey.cmake +++ b/third-party/cmake/BuildLibtermkey.cmake @@ -1,4 +1,3 @@ - ExternalProject_Add(libtermkey PREFIX ${DEPS_BUILD_DIR} URL ${LIBTERMKEY_URL} @@ -18,5 +17,6 @@ ExternalProject_Add(libtermkey PKG_CONFIG_PATH=${DEPS_LIB_DIR}/pkgconfig CFLAGS=-fPIC install) + list(APPEND THIRD_PARTY_DEPS libtermkey) -add_dependencies(libtermkey libunibilium) +add_dependencies(libtermkey unibilium) diff --git a/third-party/cmake/BuildLibuv.cmake b/third-party/cmake/BuildLibuv.cmake index df5517a17e..3033f82e96 100644 --- a/third-party/cmake/BuildLibuv.cmake +++ b/third-party/cmake/BuildLibuv.cmake @@ -1,4 +1,3 @@ - ExternalProject_Add(libuv PREFIX ${DEPS_BUILD_DIR} URL ${LIBUV_URL} @@ -15,5 +14,5 @@ ExternalProject_Add(libuv --prefix=${DEPS_INSTALL_DIR} --libdir=${DEPS_INSTALL_DIR}/lib CC=${DEPS_C_COMPILER} INSTALL_COMMAND ${MAKE_PRG} install) -list(APPEND THIRD_PARTY_DEPS libuv) +list(APPEND THIRD_PARTY_DEPS libuv) diff --git a/third-party/cmake/BuildLibvterm.cmake b/third-party/cmake/BuildLibvterm.cmake index aca48046bc..6bdb085452 100644 --- a/third-party/cmake/BuildLibvterm.cmake +++ b/third-party/cmake/BuildLibvterm.cmake @@ -1,4 +1,3 @@ - ExternalProject_Add(libvterm PREFIX ${DEPS_BUILD_DIR} URL ${LIBVTERM_URL} @@ -17,5 +16,5 @@ ExternalProject_Add(libvterm PREFIX=${DEPS_INSTALL_DIR} CFLAGS=-fPIC install) -list(APPEND THIRD_PARTY_DEPS libvterm) +list(APPEND THIRD_PARTY_DEPS libvterm) diff --git a/third-party/cmake/BuildLuajit.cmake b/third-party/cmake/BuildLuajit.cmake index b2548bd182..39207eb8b8 100644 --- a/third-party/cmake/BuildLuajit.cmake +++ b/third-party/cmake/BuildLuajit.cmake @@ -1,4 +1,3 @@ - ExternalProject_Add(luajit PREFIX ${DEPS_BUILD_DIR} URL ${LUAJIT_URL} @@ -22,5 +21,5 @@ ExternalProject_Add(luajit CCDEBUG+=-g BUILDMODE=static install) -list(APPEND THIRD_PARTY_DEPS luajit) +list(APPEND THIRD_PARTY_DEPS luajit) diff --git a/third-party/cmake/BuildLuarocks.cmake b/third-party/cmake/BuildLuarocks.cmake index 796e324297..48178ff591 100644 --- a/third-party/cmake/BuildLuarocks.cmake +++ b/third-party/cmake/BuildLuarocks.cmake @@ -1,9 +1,9 @@ - if(USE_BUNDLED_LUAJIT) list(APPEND LUAROCKS_OPTS --with-lua=${DEPS_INSTALL_DIR} --with-lua-include=${DEPS_INSTALL_DIR}/include/luajit-2.0) endif() + ExternalProject_Add(luarocks PREFIX ${DEPS_BUILD_DIR} URL ${LUAROCKS_URL} @@ -21,7 +21,9 @@ ExternalProject_Add(luarocks --lua-suffix=jit BUILD_COMMAND "" INSTALL_COMMAND ${MAKE_PRG} bootstrap) + list(APPEND THIRD_PARTY_DEPS luarocks) + if(USE_BUNDLED_LUAJIT) add_dependencies(luarocks luajit) endif() @@ -51,6 +53,8 @@ add_custom_target(stable-busted-deps add_custom_command(OUTPUT ${DEPS_BIN_DIR}/busted COMMAND ${DEPS_BIN_DIR}/luarocks ARGS build busted 2.0.rc4 CC=${DEPS_C_COMPILER} LD=${DEPS_C_COMPILER} + COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/utfTerminalDetailed.lua + ${DEPS_INSTALL_DIR}/share/lua/5.1/busted/outputHandlers DEPENDS stable-busted-deps) add_custom_target(busted DEPENDS ${DEPS_BIN_DIR}/busted) @@ -82,5 +86,3 @@ add_custom_target(nvim-client DEPENDS ${DEPS_LIB_DIR}/luarocks/rocks/nvim-client) list(APPEND THIRD_PARTY_DEPS stable-busted-deps busted lua-messagepack lpeg nvim-client) - - diff --git a/third-party/cmake/BuildLibunibilium.cmake b/third-party/cmake/BuildUnibilium.cmake index 3fb212b2a0..62f393f94c 100644 --- a/third-party/cmake/BuildLibunibilium.cmake +++ b/third-party/cmake/BuildUnibilium.cmake @@ -1,14 +1,13 @@ - -ExternalProject_Add(libunibilium +ExternalProject_Add(unibilium PREFIX ${DEPS_BUILD_DIR} - URL ${LIBUNIBILIUM_URL} - DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/libunibilium + URL ${UNIBILIUM_URL} + DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/unibilium DOWNLOAD_COMMAND ${CMAKE_COMMAND} -DPREFIX=${DEPS_BUILD_DIR} - -DDOWNLOAD_DIR=${DEPS_DOWNLOAD_DIR}/libunibilium - -DURL=${LIBUNIBILIUM_URL} - -DEXPECTED_SHA256=${LIBUNIBILIUM_SHA256} - -DTARGET=libunibilium + -DDOWNLOAD_DIR=${DEPS_DOWNLOAD_DIR}/unibilium + -DURL=${UNIBILIUM_URL} + -DEXPECTED_SHA256=${UNIBILIUM_SHA256} + -DTARGET=unibilium -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/DownloadAndExtractFile.cmake CONFIGURE_COMMAND "" BUILD_IN_SOURCE 1 @@ -16,5 +15,5 @@ ExternalProject_Add(libunibilium PREFIX=${DEPS_INSTALL_DIR} CFLAGS=-fPIC INSTALL_COMMAND ${MAKE_PRG} PREFIX=${DEPS_INSTALL_DIR} install) -list(APPEND THIRD_PARTY_DEPS libunibilium) +list(APPEND THIRD_PARTY_DEPS unibilium) diff --git a/third-party/utfTerminalDetailed.lua b/third-party/utfTerminalDetailed.lua new file mode 100644 index 0000000000..4d7a7c1d6f --- /dev/null +++ b/third-party/utfTerminalDetailed.lua @@ -0,0 +1,22 @@ +-- busted output handler that immediately prints file and test names before +-- tests are executed. It simplifies identifying which tests are +-- hanging/crashing +local ansicolors = require 'ansicolors' + +return function(options, busted) + local handler = require 'busted.outputHandlers.utfTerminal'(options, busted) + + handler.fileStart = function(name) + io.write('\n' .. ansicolors('%{cyan}' .. name) .. ':') + end + + handler.testStart = function(element, parent, status, debug) + io.write('\n ' .. handler.getFullName(element) .. ' ... ') + io.flush() + end + + busted.subscribe({ 'file', 'start' }, handler.fileStart) + busted.subscribe({ 'test', 'start' }, handler.testStart) + + return handler +end |