diff options
54 files changed, 1140 insertions, 213 deletions
diff --git a/.gitattributes b/.gitattributes new file mode 100755 index 0000000000..15a5c58091 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.h linguist-language=C diff --git a/.travis.yml b/.travis.yml index c7c824afc0..90570637ba 100644 --- a/.travis.yml +++ b/.travis.yml @@ -47,47 +47,79 @@ env: - CCACHE_SLOPPINESS=time_macros,file_macro - CCACHE_BASEDIR="$TRAVIS_BUILD_DIR" +anchors: + envs: &common-job-env + # Do not fall back to cache for "master" for PR on "release" branch: + # adds the target branch to the cache key. + FOR_TRAVIS_CACHE=$TRAVIS_BRANCH + jobs: include: - stage: baseline + name: clang-asan os: linux compiler: clang-4.0 # Use Lua so that ASAN can test our embedded Lua support. 8fec4d53d0f6 - env: > - CLANG_SANITIZER=ASAN_UBSAN - CMAKE_FLAGS="$CMAKE_FLAGS -DPREFER_LUA=ON" - ASAN_SYMBOLIZE=asan_symbolize-4.0 - - os: linux + env: + - CLANG_SANITIZER=ASAN_UBSAN + - CMAKE_FLAGS="$CMAKE_FLAGS -DPREFER_LUA=ON" + - ASAN_SYMBOLIZE=asan_symbolize-4.0 + - *common-job-env + - name: gcc-functionaltest-lua + os: linux compiler: gcc - env: > - FUNCTIONALTEST=functionaltest-lua - CMAKE_FLAGS="$CMAKE_FLAGS -DPREFER_LUA=ON" - DEPS_CMAKE_FLAGS="$DEPS_CMAKE_FLAGS -DUSE_BUNDLED_LUAJIT=OFF" - - os: linux + env: + - FUNCTIONALTEST=functionaltest-lua + - CMAKE_FLAGS="$CMAKE_FLAGS -DPREFER_LUA=ON" + - DEPS_CMAKE_FLAGS="$DEPS_CMAKE_FLAGS -DUSE_BUNDLED_LUAJIT=OFF" + - *common-job-env + - name: gcc-32bit + os: linux # Travis creates a cache per compiler. Set a different value here to # store 32-bit dependencies in a separate cache. compiler: gcc - env: BUILD_32BIT=ON + env: + - BUILD_32BIT=ON + # Minimum required CMake. + - CMAKE_URL=https://cmake.org/files/v2.8/cmake-2.8.12-Linux-i386.sh + - *common-job-env - if: branch = master AND commit_message !~ /\[skip.lint\]/ + name: lint os: linux - env: CI_TARGET=lint + env: + - CI_TARGET=lint + - *common-job-env - stage: second stage + name: "macOS: clang" os: osx compiler: clang osx_image: xcode10.2 # macOS 10.14 - - os: osx + env: + - *common-job-env + - name: "macOS: gcc" + os: osx compiler: gcc osx_image: xcode10.2 # macOS 10.14 + env: + - *common-job-env - - os: linux + - name: gcc-coverage + os: linux compiler: gcc - env: GCOV=gcov CMAKE_FLAGS="$CMAKE_FLAGS -DUSE_GCOV=ON" - - os: linux + env: + - GCOV=gcov + - CMAKE_FLAGS="$CMAKE_FLAGS -DUSE_GCOV=ON" + - GCOV_ERROR_FILE="/tmp/libgcov-errors.log" + - *common-job-env + - name: clang-tsan + os: linux compiler: clang - env: CLANG_SANITIZER=TSAN + env: + - CLANG_SANITIZER=TSAN + - *common-job-env allow_failures: - - env: CLANG_SANITIZER=TSAN + - name: clang-tsan fast_finish: true before_install: ci/before_install.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index af526ed72d..ecb5c3cea0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,7 @@ # intro: https://codingnest.com/basic-cmake/ # best practices (3.0+): https://gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4fd1 +# Version should match the tested CMAKE_URL in .travis.yml. cmake_minimum_required(VERSION 2.8.12) project(nvim C) @@ -328,8 +329,8 @@ if(CMAKE_C_COMPILER_ID STREQUAL "GNU") # 2. But _Pragma("...ignored") is broken (unresolved) in GCC 5+: # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66099 # So we must disable -Warray-bounds globally for GCC (for kbtree.h, #7083). - check_c_compiler_flag(-Wno-array-bounds HAS_NO_ARRAY_BOUNDS_FLAG) - if(HAS_NO_ARRAY_BOUNDS_FLAG) + check_c_compiler_flag(-Warray-bounds HAS_WARRAY_BOUNDS) + if(HAS_WARRAY_BOUNDS) add_compile_options(-Wno-array-bounds) endif() endif() @@ -377,7 +378,7 @@ endif() include_directories("${PROJECT_BINARY_DIR}/config") include_directories("${PROJECT_SOURCE_DIR}/src") -find_package(LibUV REQUIRED) # minimum version: v1.12 +find_package(LibUV 1.28.0 REQUIRED) include_directories(SYSTEM ${LIBUV_INCLUDE_DIRS}) find_package(Msgpack 1.0.0 REQUIRED) diff --git a/appveyor.yml b/appveyor.yml index b41f0ee7a8..bb7bb1c4e9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -32,6 +32,8 @@ after_build: if (Test-Path $env:GCOV_ERROR_FILE) { Get-Content $env:GCOV_ERROR_FILE -Head 10 Get-Content $env:GCOV_ERROR_FILE -Tail 10 + } else { + write-host "no GCOV_ERROR_FILE" } cache: - C:\projects\nvim-deps -> third-party\** diff --git a/ci/before_install.sh b/ci/before_install.sh index ff2abc0e12..774c66d38f 100755 --- a/ci/before_install.sh +++ b/ci/before_install.sh @@ -46,3 +46,16 @@ fi source ~/.nvm/nvm.sh nvm install --lts nvm use --lts + +if [[ -n "$CMAKE_URL" ]]; then + echo "Installing custom CMake: $CMAKE_URL" + curl --retry 5 --silent --fail -o /tmp/cmake-installer.sh "$CMAKE_URL" + mkdir -p "$HOME/.local/bin" /opt/cmake-custom + bash /tmp/cmake-installer.sh --prefix=/opt/cmake-custom --skip-license + ln -sfn /opt/cmake-custom/bin/cmake "$HOME/.local/bin/cmake" + cmake_version="$(cmake --version)" + echo "$cmake_version" | grep -qF '2.8.12' || { + echo "Unexpected CMake version: $cmake_version" + exit 1 + } +fi diff --git a/ci/build.ps1 b/ci/build.ps1 index c68b3fccb4..5f0f0de218 100644 --- a/ci/build.ps1 +++ b/ci/build.ps1 @@ -50,7 +50,7 @@ if ($compiler -eq 'MINGW') { # in MSYS2, but we cannot build inside the MSYS2 shell. $cmakeGenerator = 'Ninja' $cmakeGeneratorArgs = '-v' - $mingwPackages = @('ninja', 'cmake', 'perl', 'diffutils', 'unibilium').ForEach({ + $mingwPackages = @('ninja', 'cmake', 'perl', 'diffutils').ForEach({ "mingw-w64-$arch-$_" }) diff --git a/ci/common/submit_coverage.sh b/ci/common/submit_coverage.sh index 7c343268d1..218b90d6f4 100755 --- a/ci/common/submit_coverage.sh +++ b/ci/common/submit_coverage.sh @@ -25,6 +25,7 @@ python3 -m gcovr --branches --exclude-unreachable-branches --print-summary -j 2 # Upload to codecov. # -X gcov: disable gcov, done manually above. +# -X fix: disable fixing of reports (not necessary, rather slow) # -Z: exit non-zero on failure # -F: flag(s) # NOTE: ignoring flags for now, since this causes timeouts on codecov.io then, @@ -32,7 +33,7 @@ python3 -m gcovr --branches --exclude-unreachable-branches --print-summary -j 2 # Flags must match pattern ^[\w\,]+$ ("," as separator). codecov_flags="$(uname -s),${1}" codecov_flags=$(echo "$codecov_flags" | sed 's/[^,_a-zA-Z0-9]/_/g') -if ! "$codecov_sh" -f coverage.xml -X gcov -Z -F "${codecov_flags}"; then +if ! "$codecov_sh" -f coverage.xml -X gcov -X fix -Z -F "${codecov_flags}"; then echo "codecov upload failed." fi diff --git a/ci/script.sh b/ci/script.sh index a59c40cd2d..c8025ce34d 100755 --- a/ci/script.sh +++ b/ci/script.sh @@ -11,3 +11,9 @@ if [[ "${TRAVIS_OS_NAME}" == osx ]]; then else ci/run_${CI_TARGET}.sh fi + +if [[ -s "${GCOV_ERROR_FILE}" ]]; then + echo '=== Unexpected gcov errors: ===' + cat "${GCOV_ERROR_FILE}" + exit 1 +fi diff --git a/cmake/GetCompileFlags.cmake b/cmake/GetCompileFlags.cmake index 77a5260780..482eacca16 100644 --- a/cmake/GetCompileFlags.cmake +++ b/cmake/GetCompileFlags.cmake @@ -1,6 +1,6 @@ function(get_compile_flags _compile_flags) # Create template akin to CMAKE_C_COMPILE_OBJECT. - set(compile_flags "<CMAKE_C_COMPILER> <CFLAGS> <BUILD_TYPE_CFLAGS> <COMPILE_OPTIONS> <COMPILE_DEFINITIONS> <INCLUDES>") + set(compile_flags "<CMAKE_C_COMPILER> <CFLAGS> <BUILD_TYPE_CFLAGS> <COMPILE_OPTIONS><COMPILE_DEFINITIONS> <INCLUDES>") # Get C compiler. string(REPLACE @@ -13,9 +13,11 @@ function(get_compile_flags _compile_flags) get_directory_property(compile_definitions DIRECTORY "src/nvim" COMPILE_DEFINITIONS) - # NOTE: list(JOIN) requires CMake 3.12. + # NOTE: list(JOIN) requires CMake 3.12, string(CONCAT) requires CMake 3. string(REPLACE ";" " -D" compile_definitions "${compile_definitions}") - string(CONCAT compile_definitions "-D" "${compile_definitions}") + if(compile_definitions) + set(compile_definitions " -D${compile_definitions}") + endif() string(REPLACE "<COMPILE_DEFINITIONS>" "${compile_definitions}" diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index 065a052175..709e5885e4 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -284,14 +284,18 @@ highlighting, or |api-highlights|. By default, floats will use |hl-NormalFloat| as normal highlight, which links to |hl-Pmenu| in the builtin color scheme. The 'winhighlight' option can be used to override it. Currently, floating windows don't support any visual -decorations like a border or additional widgets like scrollbar. +decorations like a border or additional widgets like scrollbar. By default, +floats will inherit options from the current window. This is not always +useful for some options, like 'number'. Use `style='minimal'` flag to +|nvim_open_win()| to disable many UI features that are unwanted for a simple +float, like end-of-buffer region or special columns. Here is an example for creating a float with scratch buffer: > let buf = nvim_create_buf(v:false, v:true) call nvim_buf_set_lines(buf, 0, -1, v:true, ["test", "text"]) let opts = {'relative': 'cursor', 'width': 10, 'height': 2, 'col': 0, - \ 'row': 1, 'anchor': 'NW'} + \ 'row': 1, 'anchor': 'NW', 'style': 'minimal'} let win = nvim_open_win(buf, 0, opts) " optional: change highlight, otherwise Pmenu is used call nvim_win_set_option(win, 'winhl', 'Normal:MyHighlight') diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 7c9ad3010e..8fc8a04df3 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -4202,7 +4202,7 @@ A jump table for the options with a short description can be found at |Q_op|. rows in the window, depending on whether 'number' or 'relativenumber' is set. Thus with the Vim default of 4 there is room for a line number up to 999. When the buffer has 1000 lines five columns will be used. - The minimum value is 1, the maximum value is 10. + The minimum value is 1, the maximum value is 20. *'omnifunc'* *'ofu'* 'omnifunc' 'ofu' string (default: empty) @@ -4552,6 +4552,25 @@ A jump table for the options with a short description can be found at |Q_op|. set for the newly edited buffer. See 'modifiable' for disallowing changes to the buffer. + *'redrawdebug'* *'rdb'* +'redrawdebug' 'rdb' string (default '') + global + Flags to change the way redrawing works, for debugging purposes. + Most useful with 'writedelay' set to some reasonable value. + Supports the following flags: + compositor Indicate what redraws come from the compositor + by briefly flashing the redrawn regions in colors + indicating the redraw type. These are the highlight + groups used (and their default colors): + RedrawDebugNormal gui=reverse normal redraw passed through + RedrawDebugClear guibg=Yellow clear event passed through + RedrawDebugComposed guibg=Green redraw event modified by the + compositor (due to + overlapping grids, etc) + RedrawDebugRecompose guibg=Red redraw generated by the + compositor itself, due to a + grid being moved or deleted. + *'redrawtime'* *'rdt'* 'redrawtime' 'rdt' number (default 2000) global diff --git a/scripts/pvscheck.sh b/scripts/pvscheck.sh index fed50dde53..c09e8c4555 100755 --- a/scripts/pvscheck.sh +++ b/scripts/pvscheck.sh @@ -369,7 +369,6 @@ run_analysis() {( analyze \ --threads "$(get_jobs_num)" \ --output-file PVS-studio.log \ - --verbose \ --file build/compile_commands.json \ --sourcetree-root . || true diff --git a/scripts/stripdecls.py b/scripts/stripdecls.py index 34be2a1578..a73b1980cb 100755 --- a/scripts/stripdecls.py +++ b/scripts/stripdecls.py @@ -18,8 +18,6 @@ Strip = namedtuple('Strip', 'start_line start_column end_line end_column') def main(progname, cfname, only_static, move_all): - only_static = False - cfname = os.path.abspath(os.path.normpath(cfname)) hfname1 = os.path.splitext(cfname)[0] + os.extsep + 'h' diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index 7807125b92..95ca1052af 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -164,8 +164,8 @@ if(NOT MSVC) set_source_files_properties( ${CONV_SOURCES} PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-conversion") # gperf generates ANSI-C with incorrect linkage, ignore it. - check_c_compiler_flag(-Wno-static-in-inline HAS_WNO_STATIC_IN_INLINE_FLAG) - if(HAS_WNO_STATIC_IN_INLINE_FLAG) + check_c_compiler_flag(-Wstatic-in-inline HAS_WSTATIC_IN_INLINE) + if(HAS_WSTATIC_IN_INLINE) set_source_files_properties( eval.c PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-static-in-inline -Wno-conversion") else() diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 8e5650633a..dbe3b66fd5 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1064,6 +1064,19 @@ fail: /// - `external`: GUI should display the window as an external /// top-level window. Currently accepts no other positioning /// configuration together with this. +/// - `style`: Configure the apparance of the window. Currently only takes +/// one non-empty value: +/// - "minimal" Nvim will display the window with many UI options +/// disabled. This is useful when displaing a temporary +/// float where the text should not be edited. Disables +/// 'number', 'relativenumber', 'cursorline', 'cursorcolumn', +/// 'spell' and 'list' options. 'signcolumn' is changed to +/// `auto`. The end-of-buffer region is hidden by setting +/// `eob` flag of 'fillchars' to a space char, and clearing +/// the |EndOfBuffer| region in 'winhighlight'. +/// +/// top-level window. Currently accepts no other positioning +/// configuration together with this. /// @param[out] err Error details, if any /// /// @return Window handle, or 0 on error @@ -1085,6 +1098,11 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dictionary config, if (buffer > 0) { nvim_win_set_buf(wp->handle, buffer, err); } + + if (fconfig.style == kWinStyleMinimal) { + win_set_minimal_style(wp); + didset_window_options(wp); + } return wp->handle; } diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 9fd1818a5c..4922dd7efc 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -13,6 +13,7 @@ #include "nvim/vim.h" #include "nvim/buffer.h" #include "nvim/cursor.h" +#include "nvim/option.h" #include "nvim/window.h" #include "nvim/screen.h" #include "nvim/move.h" @@ -475,6 +476,10 @@ void nvim_win_set_config(Window window, Dictionary config, Error *err) win_config_float(win, fconfig); win->w_pos_changed = true; } + if (fconfig.style == kWinStyleMinimal) { + win_set_minimal_style(win); + didset_window_options(win); + } } /// Return window configuration. diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 5678f518f5..cd31adbaff 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -2543,6 +2543,11 @@ void get_winopts(buf_T *buf) } else copy_winopt(&curwin->w_allbuf_opt, &curwin->w_onebuf_opt); + if (curwin->w_float_config.style == kWinStyleMinimal) { + didset_window_options(curwin); + win_set_minimal_style(curwin); + } + // Set 'foldlevel' to 'foldlevelstart' if it's not negative. if (p_fdls >= 0) { curwin->w_p_fdl = p_fdls; diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index ad10f6baa2..a27672488e 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -972,7 +972,6 @@ struct matchitem { }; typedef int FloatAnchor; -typedef int FloatRelative; enum { kFloatAnchorEast = 1, @@ -985,15 +984,20 @@ enum { // SE -> kFloatAnchorSouth | kFloatAnchorEast EXTERN const char *const float_anchor_str[] INIT(= { "NW", "NE", "SW", "SE" }); -enum { +typedef enum { kFloatRelativeEditor = 0, kFloatRelativeWindow = 1, kFloatRelativeCursor = 2, -}; +} FloatRelative; EXTERN const char *const float_relative_str[] INIT(= { "editor", "window", "cursor" }); +typedef enum { + kWinStyleUnused = 0, + kWinStyleMinimal, /// Minimal UI: no number column, eob markers, etc +} WinStyle; + typedef struct { Window window; int height, width; @@ -1002,12 +1006,14 @@ typedef struct { FloatRelative relative; bool external; bool focusable; + WinStyle style; } FloatConfig; #define FLOAT_CONFIG_INIT ((FloatConfig){ .height = 0, .width = 0, \ .row = 0, .col = 0, .anchor = 0, \ .relative = 0, .external = false, \ - .focusable = true }) + .focusable = true, \ + .style = kWinStyleUnused }) // Structure to store last cursor position and topline. Used by check_lnums() // and reset_lnums(). diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 6df2b69396..418725fa44 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -7097,10 +7097,14 @@ static void f_assert_fails(typval_T *argvars, typval_T *rettv, FunPtr fptr) { const char *const cmd = tv_get_string_chk(&argvars[0]); garray_T ga; + int save_trylevel = trylevel; + // trylevel must be zero for a ":throw" command to be considered failed + trylevel = 0; called_emsg = false; suppress_errthrow = true; emsg_silent = true; + do_cmdline_cmd(cmd); if (!called_emsg) { prepare_assert_error(&ga); @@ -7122,6 +7126,7 @@ static void f_assert_fails(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } + trylevel = save_trylevel; called_emsg = false; suppress_errthrow = false; emsg_silent = false; @@ -15873,11 +15878,10 @@ static void f_sign_getplaced(typval_T *argvars, typval_T *rettv, FunPtr fptr) } if ((di = tv_dict_find(dict, "lnum", -1)) != NULL) { // get signs placed at this line - lnum = (linenr_T)tv_get_number_chk(&di->di_tv, ¬anum); - if (notanum) { + lnum = tv_get_lnum(&di->di_tv); + if (lnum <= 0) { return; } - lnum = tv_get_lnum(&di->di_tv); } if ((di = tv_dict_find(dict, "id", -1)) != NULL) { // get sign placed with this identifier @@ -20705,11 +20709,11 @@ void ex_echohl(exarg_T *eap) */ void ex_execute(exarg_T *eap) { - char_u *arg = eap->arg; + char_u *arg = eap->arg; typval_T rettv; int ret = OK; garray_T ga; - int save_did_emsg = did_emsg; + int save_did_emsg; ga_init(&ga, 1, 80); @@ -22048,6 +22052,7 @@ static bool script_autoload(const char *const name, const size_t name_len, } /// Return the autoload script name for a function or variable name +/// Caller must make sure that "name" contains AUTOLOAD_CHAR. /// /// @param[in] name Variable/function name. /// @param[in] name_len Name length. @@ -22236,12 +22241,9 @@ static void func_clear_items(ufunc_T *fp) ga_clear_strings(&(fp->uf_args)); ga_clear_strings(&(fp->uf_lines)); - xfree(fp->uf_tml_count); - fp->uf_tml_count = NULL; - xfree(fp->uf_tml_total); - fp->uf_tml_total = NULL; - xfree(fp->uf_tml_self); - fp->uf_tml_self = NULL; + XFREE_CLEAR(fp->uf_tml_count); + XFREE_CLEAR(fp->uf_tml_total); + XFREE_CLEAR(fp->uf_tml_self); } /// Free all things that a function contains. Does not free the function diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c index 7a8a39dbcf..990dee0c7f 100644 --- a/src/nvim/event/process.c +++ b/src/nvim/event/process.c @@ -26,6 +26,11 @@ // For PTY processes SIGTERM is sent first (in case SIGHUP was not enough). #define KILL_TIMEOUT_MS 2000 +/// Externally defined with gcov. +#ifdef USE_GCOV +void __gcov_flush(void); +#endif + static bool process_is_tearing_down = false; /// @returns zero on success, or negative error code @@ -50,6 +55,11 @@ int process_spawn(Process *proc, bool in, bool out, bool err) proc->err.closed = true; } +#ifdef USE_GCOV + // Flush coverage data before forking, to avoid "Merge mismatch" errors. + __gcov_flush(); +#endif + int status; switch (proc->type) { case kProcessTypeUv: diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index a494463f89..1d27cf338e 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -6922,16 +6922,17 @@ static void ex_resize(exarg_T *eap) n = atol((char *)eap->arg); if (cmdmod.split & WSP_VERT) { - if (*eap->arg == '-' || *eap->arg == '+') + if (*eap->arg == '-' || *eap->arg == '+') { n += curwin->w_width; - else if (n == 0 && eap->arg[0] == NUL) /* default is very wide */ - n = 9999; + } else if (n == 0 && eap->arg[0] == NUL) { // default is very wide + n = Columns; + } win_setwidth_win(n, wp); } else { if (*eap->arg == '-' || *eap->arg == '+') { n += curwin->w_height; } else if (n == 0 && eap->arg[0] == NUL) { // default is very high - n = 9999; + n = Rows-1; } win_setheight_win(n, wp); } diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 1f258985a6..093067894f 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2495,7 +2495,7 @@ static void realloc_cmdbuff(int len) static char_u *arshape_buf = NULL; # if defined(EXITFREE) -void free_cmdline_buf(void) +void free_arshape_buf(void) { xfree(arshape_buf); } diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c index 15c3d0eb7b..e5cbb4f944 100644 --- a/src/nvim/highlight.c +++ b/src/nvim/highlight.c @@ -141,10 +141,12 @@ int hl_get_ui_attr(int idx, int final_id, bool optional) HlAttrs attrs = HLATTRS_INIT; bool available = false; - int syn_attr = syn_id2attr(final_id); - if (syn_attr != 0) { - attrs = syn_attr2entry(syn_attr); - available = true; + if (final_id > 0) { + int syn_attr = syn_id2attr(final_id); + if (syn_attr != 0) { + attrs = syn_attr2entry(syn_attr); + available = true; + } } if (HLF_PNI <= idx && idx <= HLF_PST) { @@ -176,15 +178,14 @@ void update_window_hl(win_T *wp, bool invalid) // determine window specific background set in 'winhighlight' bool float_win = wp->w_floating && !wp->w_float_config.external; - if (wp != curwin && wp->w_hl_ids[HLF_INACTIVE] > 0) { + if (wp != curwin && wp->w_hl_ids[HLF_INACTIVE] != 0) { wp->w_hl_attr_normal = hl_get_ui_attr(HLF_INACTIVE, wp->w_hl_ids[HLF_INACTIVE], !has_blend); - } else if (float_win && wp->w_hl_ids[HLF_NFLOAT] > 0) { + } else if (float_win && wp->w_hl_ids[HLF_NFLOAT] != 0) { wp->w_hl_attr_normal = hl_get_ui_attr(HLF_NFLOAT, - // 'cursorline' wp->w_hl_ids[HLF_NFLOAT], !has_blend); - } else if (wp->w_hl_id_normal > 0) { + } else if (wp->w_hl_id_normal != 0) { wp->w_hl_attr_normal = hl_get_ui_attr(-1, wp->w_hl_id_normal, !has_blend); } else { wp->w_hl_attr_normal = float_win ? HL_ATTR(HLF_NFLOAT) : 0; @@ -199,14 +200,14 @@ void update_window_hl(win_T *wp, bool invalid) } } - if (wp != curwin) { + if (wp != curwin && wp->w_hl_ids[HLF_INACTIVE] == 0) { wp->w_hl_attr_normal = hl_combine_attr(HL_ATTR(HLF_INACTIVE), wp->w_hl_attr_normal); } for (int hlf = 0; hlf < (int)HLF_COUNT; hlf++) { int attr; - if (wp->w_hl_ids[hlf] > 0) { + if (wp->w_hl_ids[hlf] != 0) { attr = hl_get_ui_attr(hlf, wp->w_hl_ids[hlf], false); } else { attr = HL_ATTR(hlf); diff --git a/src/nvim/main.c b/src/nvim/main.c index 306d2f7bf5..b3654a0690 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -54,6 +54,7 @@ #include "nvim/strings.h" #include "nvim/syntax.h" #include "nvim/ui.h" +#include "nvim/ui_compositor.h" #include "nvim/version.h" #include "nvim/window.h" #include "nvim/shada.h" @@ -220,6 +221,7 @@ void early_init(void) set_lang_var(); // set v:lang and v:ctype init_signs(); + ui_comp_syn_init(); } #ifdef MAKE_LIB diff --git a/src/nvim/memory.c b/src/nvim/memory.c index dced03f3d5..1384aa177b 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -648,7 +648,7 @@ void free_all_mem(void) // Free all option values. Must come after closing windows. free_all_options(); - free_cmdline_buf(); + free_arshape_buf(); /* Clear registers. */ clear_registers(); diff --git a/src/nvim/option.c b/src/nvim/option.c index e8e246c277..d6dbb14653 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -2191,6 +2191,7 @@ static void didset_options(void) (void)opt_strings_flags(p_vop, p_ssop_values, &vop_flags, true); (void)opt_strings_flags(p_fdo, p_fdo_values, &fdo_flags, true); (void)opt_strings_flags(p_dy, p_dy_values, &dy_flags, true); + (void)opt_strings_flags(p_rdb, p_rdb_values, &rdb_flags, true); (void)opt_strings_flags(p_tc, p_tc_values, &tc_flags, false); (void)opt_strings_flags(p_ve, p_ve_values, &ve_flags, true); (void)opt_strings_flags(p_wop, p_wop_values, &wop_flags, true); @@ -2650,6 +2651,10 @@ did_set_string_option( if (opt_strings_flags(p_vop, p_ssop_values, &vop_flags, true) != OK) { errmsg = e_invarg; } + } else if (varp == &p_rdb) { // 'redrawdebug' + if (opt_strings_flags(p_rdb, p_rdb_values, &rdb_flags, true) != OK) { + errmsg = e_invarg; + } } else if (varp == &p_sbo) { // 'scrollopt' if (check_opt_strings(p_sbo, p_scbopt_values, true) != OK) { errmsg = e_invarg; @@ -3762,7 +3767,8 @@ static bool parse_winhl_opt(win_T *wp) size_t nlen = (size_t)(colon-p); char *hi = colon+1; char *commap = xstrchrnul(hi, ','); - int hl_id = syn_check_group((char_u *)hi, (int)(commap-hi)); + int len = (int)(commap-hi); + int hl_id = len ? syn_check_group((char_u *)hi, len) : -1; if (strncmp("Normal", p, nlen) == 0) { w_hl_id_normal = hl_id; @@ -4274,7 +4280,7 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, } else if (pp == &curwin->w_p_nuw || pp == &curwin->w_allbuf_opt.wo_nuw) { if (value < 1) { errmsg = e_positive; - } else if (value > 10) { + } else if (value > 20) { errmsg = e_invarg; } } else if (pp == &curbuf->b_p_iminsert || pp == &p_iminsert) { diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 35fe3b5b00..a480de735d 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -511,6 +511,13 @@ EXTERN char_u *p_pm; // 'patchmode' EXTERN char_u *p_path; // 'path' EXTERN char_u *p_cdpath; // 'cdpath' EXTERN long p_pyx; // 'pyxversion' +EXTERN char_u *p_rdb; // 'redrawdebug' +EXTERN unsigned rdb_flags; +# ifdef IN_OPTION_C +static char *(p_rdb_values[]) = { "compositor", NULL }; +# endif +# define RDB_COMPOSITOR 0x001 + EXTERN long p_rdt; // 'redrawtime' EXTERN int p_remap; // 'remap' EXTERN long p_re; // 'regexpengine' diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 27f72f6441..c48366e205 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -1848,6 +1848,13 @@ return { defaults={if_true={vi=false}} }, { + full_name='redrawdebug', abbreviation='rdb', + type='string', list='onecomma', scope={'global'}, + vi_def=true, + varname='p_rdb', + defaults={if_true={vi=''}} + }, + { full_name='redrawtime', abbreviation='rdt', type='number', scope={'global'}, vi_def=true, diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c index 97545a6cb1..5fdf0e6181 100644 --- a/src/nvim/os/pty_process_unix.c +++ b/src/nvim/os/pty_process_unix.c @@ -36,11 +36,6 @@ # include "os/pty_process_unix.c.generated.h" #endif -/// Externally defined with gcov. -#ifdef USE_GCOV -void __gcov_flush(void); -#endif - /// termios saved at startup (for TUI) or initialized by pty_process_spawn(). static struct termios termios_default; @@ -64,11 +59,6 @@ int pty_process_spawn(PtyProcess *ptyproc) init_termios(&termios_default); } -#ifdef USE_GCOV - // Flush coverage data before forking, to avoid "Merge mismatch" errors. - __gcov_flush(); -#endif - int status = 0; // zero or negative error code (libuv convention) Process *proc = (Process *)ptyproc; assert(proc->err.closed); diff --git a/src/nvim/os/time.c b/src/nvim/os/time.c index 18239c5566..1094fbc946 100644 --- a/src/nvim/os/time.c +++ b/src/nvim/os/time.c @@ -39,7 +39,7 @@ void time_init(void) /// @see gettimeofday(2) /// /// @return Current time in microseconds. -uint64_t os_utime(void) +int64_t os_utime(void) FUNC_ATTR_WARN_UNUSED_RESULT { uv_timeval64_t tm; @@ -47,8 +47,8 @@ uint64_t os_utime(void) if (e != 0 || tm.tv_sec < 0 || tm.tv_usec < 0) { return 0; } - uint64_t rv = (uint64_t)tm.tv_sec * 1000 * 1000; // s => μs - STRICT_ADD(rv, tm.tv_usec, &rv, uint64_t); + int64_t rv = tm.tv_sec * 1000 * 1000; // s => μs + STRICT_ADD(rv, tm.tv_usec, &rv, int64_t); return rv; } diff --git a/src/nvim/profile.c b/src/nvim/profile.c index cc12e00396..ae3f1d9b5e 100644 --- a/src/nvim/profile.c +++ b/src/nvim/profile.c @@ -61,7 +61,7 @@ proftime_T profile_setlimit(int64_t msec) FUNC_ATTR_WARN_UNUSED_RESULT } assert(msec <= (INT64_MAX / 1000LL) - 1); - proftime_T usec = (proftime_T)msec * 1000ULL; + proftime_T usec = msec * 1000; return os_utime() + usec; } @@ -111,7 +111,7 @@ proftime_T profile_add(proftime_T tm1, proftime_T tm2) FUNC_ATTR_CONST /// @return `tm1` - `tm2` proftime_T profile_sub(proftime_T tm1, proftime_T tm2) FUNC_ATTR_CONST { - return tm1 > tm2 ? tm1 - tm2 : 0; // os_utime() may go backwards. + return tm1 - tm2; } /// Adds the `self` time from the total time and the `children` time. diff --git a/src/nvim/profile.h b/src/nvim/profile.h index 7b378577ce..2608514313 100644 --- a/src/nvim/profile.h +++ b/src/nvim/profile.h @@ -4,7 +4,7 @@ #include <stdint.h> #include <time.h> -typedef uint64_t proftime_T; +typedef int64_t proftime_T; #define TIME_MSG(s) do { \ if (time_fd != NULL) time_msg(s, NULL); \ diff --git a/src/nvim/screen.c b/src/nvim/screen.c index acff44164f..a007aa9a47 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -1612,7 +1612,8 @@ static void win_draw_end(win_T *wp, int c1, int c2, bool draw_margin, int row, } } - int attr = hl_combine_attr(wp->w_hl_attr_normal, win_hl_attr(wp, hl)); + int attr = hl_combine_attr(wp->w_hl_attr_normal, + hl ? win_hl_attr(wp, hl) : 0); if (wp->w_p_rl) { grid_fill(&wp->w_grid, row, endrow, wp->w_wincol, W_ENDCOL(wp) - 1 - n, @@ -2085,7 +2086,7 @@ win_line ( int lcs_eol_one = wp->w_p_lcs_chars.eol; // 'eol' until it's been used int lcs_prec_todo = wp->w_p_lcs_chars.prec; // 'prec' until it's been used - /* saved "extra" items for when draw_state becomes WL_LINE (again) */ + // saved "extra" items for when draw_state becomes WL_LINE (again) int saved_n_extra = 0; char_u *saved_p_extra = NULL; int saved_c_extra = 0; diff --git a/src/nvim/sign.c b/src/nvim/sign.c index 8c85fbdaa7..9c391428ca 100644 --- a/src/nvim/sign.c +++ b/src/nvim/sign.c @@ -83,11 +83,8 @@ static signgroup_T * sign_group_ref(const char_u *groupname) hi = hash_lookup(&sg_table, (char *)groupname, STRLEN(groupname), hash); if (HASHITEM_EMPTY(hi)) { // new group - group = (signgroup_T *)xmalloc( - (unsigned)(sizeof(signgroup_T) + STRLEN(groupname))); - if (group == NULL) { - return NULL; - } + group = xmalloc((unsigned)(sizeof(signgroup_T) + STRLEN(groupname))); + STRCPY(group->sg_name, groupname); group->refcount = 1; group->next_sign_id = 1; @@ -188,10 +185,6 @@ static void insert_sign( newsign->typenr = typenr; if (group != NULL) { newsign->group = sign_group_ref(group); - if (newsign->group == NULL) { - xfree(newsign); - return; - } } else { newsign->group = NULL; } @@ -1347,8 +1340,8 @@ static void sign_getinfo(sign_T *sp, dict_T *retdict) /// Otherwise, return information about the specified sign. void sign_getlist(const char_u *name, list_T *retlist) { - sign_T *sp = first_sign; - dict_T *dict; + sign_T *sp = first_sign; + dict_T *dict; if (name != NULL) { sp = sign_find(name, NULL); @@ -1358,9 +1351,7 @@ void sign_getlist(const char_u *name, list_T *retlist) } for (; sp != NULL && !got_int; sp = sp->sn_next) { - if ((dict = tv_dict_alloc()) == NULL) { - return; - } + dict = tv_dict_alloc(); tv_list_append_dict(retlist, dict); sign_getinfo(sp, dict); @@ -1374,14 +1365,13 @@ void sign_getlist(const char_u *name, list_T *retlist) list_T *get_buffer_signs(buf_T *buf) FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { - signlist_T *sign; - dict_T *d; + signlist_T *sign; + dict_T *d; list_T *const l = tv_list_alloc(kListLenMayKnow); FOR_ALL_SIGNS_IN_BUF(buf, sign) { - if ((d = sign_get_info(sign)) != NULL) { - tv_list_append_dict(l, d); - } + d = sign_get_info(sign); + tv_list_append_dict(l, d); } return l; } @@ -1394,21 +1384,16 @@ static void sign_get_placed_in_buf( const char_u *sign_group, list_T *retlist) { - dict_T *d; - list_T *l; - signlist_T *sign; - dict_T *sdict; + dict_T *d; + list_T *l; + signlist_T *sign; - if ((d = tv_dict_alloc()) == NULL) { - return; - } + d = tv_dict_alloc(); tv_list_append_dict(retlist, d); tv_dict_add_nr(d, S_LEN("bufnr"), (long)buf->b_fnum); - if ((l = tv_list_alloc(kListLenMayKnow)) == NULL) { - return; - } + l = tv_list_alloc(kListLenMayKnow); tv_dict_add_list(d, S_LEN("signs"), l); FOR_ALL_SIGNS_IN_BUF(buf, sign) { @@ -1419,9 +1404,7 @@ static void sign_get_placed_in_buf( || (sign_id == 0 && lnum == sign->lnum) || (lnum == 0 && sign_id == sign->id) || (lnum == sign->lnum && sign_id == sign->id)) { - if ((sdict = sign_get_info(sign)) != NULL) { - tv_list_append_dict(l, sdict); - } + tv_list_append_dict(l, sign_get_info(sign)); } } } diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index 354590b9ec..e39075739c 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -5970,6 +5970,10 @@ static const char *highlight_init_both[] = { "default link Whitespace NonText", "default link MsgSeparator StatusLine", "default link NormalFloat Pmenu", + "RedrawDebugNormal cterm=reverse gui=reverse", + "RedrawDebugClear ctermbg=Yellow guibg=Yellow", + "RedrawDebugComposed ctermbg=Green guibg=Green", + "RedrawDebugRecompose ctermbg=Red guibg=Red", NULL }; diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile index fe9e0bc9c8..8b43d91e25 100644 --- a/src/nvim/testdir/Makefile +++ b/src/nvim/testdir/Makefile @@ -99,23 +99,24 @@ RM_ON_RUN := test.out X* viminfo RM_ON_START := test.ok RUN_VIM := $(TOOL) $(NVIM_PRG) -u unix.vim -U NONE -i viminfo --headless --noplugin -s dotest.in +CLEAN_FILES := *.out \ + *.failed \ + *.res \ + *.rej \ + *.orig \ + *.tlog \ + test.log \ + messages \ + $(RM_ON_RUN) \ + $(RM_ON_START) \ + valgrind.* \ + .*.swp \ + .*.swo \ + .gdbinit \ + $(TMPDIR) \ + del clean: - -rm -rf *.out \ - *.failed \ - *.res \ - *.rej \ - *.orig \ - *.tlog \ - test.log \ - messages \ - $(RM_ON_RUN) \ - $(RM_ON_START) \ - valgrind.* \ - .*.swp \ - .*.swo \ - .gdbinit \ - $(TMPDIR) \ - del + $(RM) -rf $(CLEAN_FILES) test1.out: .gdbinit test1.in @echo "[OLDTEST-PREP] Running test1" diff --git a/src/nvim/testdir/test_assert.vim b/src/nvim/testdir/test_assert.vim index fe87bd6ef5..a4c8ce7e43 100644 --- a/src/nvim/testdir/test_assert.vim +++ b/src/nvim/testdir/test_assert.vim @@ -1,5 +1,11 @@ " Test that the methods used for testing work. +func Test_assert_fails_in_try_block() + try + call assert_equal(0, assert_fails('throw "error"')) + endtry +endfunc + " Must be last. func Test_zz_quit_detected() " Verify that if a test function ends Vim the test script detects this. diff --git a/src/nvim/testdir/test_diffmode.vim b/src/nvim/testdir/test_diffmode.vim index 00f4563f3d..1ba36ca8e9 100644 --- a/src/nvim/testdir/test_diffmode.vim +++ b/src/nvim/testdir/test_diffmode.vim @@ -752,6 +752,9 @@ func Test_diff_of_diff() if !CanRunVimInTerminal() return endif + if !has("rightleft") + throw 'Skipped: rightleft not supported' + endif call writefile([ \ 'call setline(1, ["aa","bb","cc","@@ -3,2 +5,7 @@","dd","ee","ff"])', diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim index 28576709a3..a6ebd7b023 100644 --- a/src/nvim/testdir/test_options.vim +++ b/src/nvim/testdir/test_options.vim @@ -231,7 +231,7 @@ func Test_set_errors() call assert_fails('set backupcopy=', 'E474:') call assert_fails('set regexpengine=3', 'E474:') call assert_fails('set history=10001', 'E474:') - call assert_fails('set numberwidth=11', 'E474:') + call assert_fails('set numberwidth=21', 'E474:') call assert_fails('set colorcolumn=-a') call assert_fails('set colorcolumn=a') call assert_fails('set colorcolumn=1,') diff --git a/src/nvim/testdir/test_suspend.vim b/src/nvim/testdir/test_suspend.vim index e569e49055..efda68de9b 100644 --- a/src/nvim/testdir/test_suspend.vim +++ b/src/nvim/testdir/test_suspend.vim @@ -2,6 +2,20 @@ source shared.vim +func CheckSuspended(buf, fileExists) + call WaitForAssert({-> assert_match('[$#] $', term_getline(a:buf, '.'))}) + + if a:fileExists + call assert_equal(['foo'], readfile('Xfoo')) + else + " Without 'autowrite', buffer should not be written. + call assert_equal(0, filereadable('Xfoo')) + endif + + call term_sendkeys(a:buf, "fg\<CR>\<C-L>") + call WaitForAssert({-> assert_equal(' 1 foo', term_getline(a:buf, '.'))}) +endfunc + func Test_suspend() if !has('terminal') || !executable('/bin/sh') return @@ -26,13 +40,7 @@ func Test_suspend() \ "\<C-Z>"] " Suspend and wait for shell prompt. call term_sendkeys(buf, suspend_cmd) - call WaitForAssert({-> assert_match('[$#] $', term_getline(buf, '.'))}) - - " Without 'autowrite', buffer should not be written. - call assert_equal(0, filereadable('Xfoo')) - - call term_sendkeys(buf, "fg\<CR>") - call WaitForAssert({-> assert_equal(' 1 foo', term_getline(buf, '.'))}) + call CheckSuspended(buf, 0) endfor " Test that :suspend! with 'autowrite' writes content of buffers if modified. @@ -40,10 +48,7 @@ func Test_suspend() call assert_equal(0, filereadable('Xfoo')) call term_sendkeys(buf, ":suspend\<CR>") " Wait for shell prompt. - call WaitForAssert({-> assert_match('[$#] $', term_getline(buf, '.'))}) - call assert_equal(['foo'], readfile('Xfoo')) - call term_sendkeys(buf, "fg\<CR>") - call WaitForAssert({-> assert_equal(' 1 foo', term_getline(buf, '.'))}) + call CheckSuspended(buf, 1) " Quit gracefully to dump coverage information. call term_sendkeys(buf, ":qall!\<CR>") diff --git a/src/nvim/ui.c b/src/nvim/ui.c index 7dbb8ec790..fc4a3a403d 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -341,15 +341,15 @@ void ui_line(ScreenGrid *grid, int row, int startcol, int endcol, int clearcol, flags, (const schar_T *)grid->chars + off, (const sattr_T *)grid->attrs + off); - if (p_wd) { // 'writedelay': flush & delay each time. - int old_row = cursor_row, old_col = cursor_col; - handle_T old_grid = cursor_grid_handle; + // 'writedelay': flush & delay each time. + if (p_wd && !(rdb_flags & RDB_COMPOSITOR)) { // If 'writedelay' is active, set the cursor to indicate what was drawn. - ui_grid_cursor_goto(grid->handle, row, MIN(clearcol, (int)Columns-1)); - ui_flush(); + ui_call_grid_cursor_goto(grid->handle, row, + MIN(clearcol, (int)grid->Columns-1)); + ui_call_flush(); uint64_t wd = (uint64_t)labs(p_wd); os_microdelay(wd * 1000u, true); - ui_grid_cursor_goto(old_grid, old_row, old_col); + pending_cursor_update = true; // restore the cursor later } } @@ -372,6 +372,14 @@ void ui_grid_cursor_goto(handle_T grid_handle, int new_row, int new_col) pending_cursor_update = true; } +/// moving the cursor grid will implicitly move the cursor +void ui_check_cursor_grid(handle_T grid_handle) +{ + if (cursor_grid_handle == grid_handle) { + pending_cursor_update = true; + } +} + void ui_mode_info_set(void) { pending_mode_info_update = true; diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c index d12a411019..858ffbe5bc 100644 --- a/src/nvim/ui_compositor.c +++ b/src/nvim/ui_compositor.c @@ -49,6 +49,8 @@ static bool valid_screen = true; static bool msg_scroll_mode = false; static int msg_first_invalid = 0; +static int dbghl_normal, dbghl_clear, dbghl_composed, dbghl_recompose; + void ui_comp_init(void) { if (compositor != NULL) { @@ -81,6 +83,13 @@ void ui_comp_init(void) ui_attach_impl(compositor); } +void ui_comp_syn_init(void) +{ + dbghl_normal = syn_check_group((char_u *)S_LEN("RedrawDebugNormal")); + dbghl_clear = syn_check_group((char_u *)S_LEN("RedrawDebugClear")); + dbghl_composed = syn_check_group((char_u *)S_LEN("RedrawDebugComposed")); + dbghl_recompose = syn_check_group((char_u *)S_LEN("RedrawDebugRecompose")); +} void ui_comp_attach(UI *ui) { @@ -290,10 +299,14 @@ static void compose_line(Integer row, Integer startcol, Integer endcol, { // in case we start on the right half of a double-width char, we need to // check the left half. But skip it in output if it wasn't doublewidth. - int skip = 0; + int skipstart = 0, skipend = 0; if (startcol > 0 && (flags & kLineFlagInvalid)) { startcol--; - skip = 1; + skipstart = 1; + } + if (endcol < default_grid.Columns && (flags & kLineFlagInvalid)) { + endcol++; + skipend = 1; } int col = (int)startcol; @@ -345,20 +358,27 @@ static void compose_line(Integer row, Integer startcol, Integer endcol, if (linebuf[col-startcol][0] == NUL) { linebuf[col-startcol][0] = ' '; linebuf[col-startcol][1] = NUL; + if (col == endcol-1) { + skipend = 0; + } } else if (n > 1 && linebuf[col-startcol+1][0] == NUL) { - skip = 0; + skipstart = 0; } if (grid->comp_col+grid->Columns > until && grid->chars[off+n][0] == NUL) { linebuf[until-1-startcol][0] = ' '; linebuf[until-1-startcol][1] = '\0'; if (col == startcol && n == 1) { - skip = 0; + skipstart = 0; } } col = until; } + if (linebuf[endcol-startcol-1][0] == NUL) { + skipend = 0; + } + assert(endcol <= chk_width); assert(row < chk_height); @@ -368,14 +388,48 @@ static void compose_line(Integer row, Integer startcol, Integer endcol, flags = flags & ~kLineFlagWrap; } - ui_composed_call_raw_line(1, row, startcol+skip, endcol, endcol, 0, flags, - (const schar_T *)linebuf+skip, - (const sattr_T *)attrbuf+skip); + ui_composed_call_raw_line(1, row, startcol+skipstart, + endcol-skipend, endcol-skipend, 0, flags, + (const schar_T *)linebuf+skipstart, + (const sattr_T *)attrbuf+skipstart); } +static void compose_debug(Integer startrow, Integer endrow, Integer startcol, + Integer endcol, int syn_id, bool delay) +{ + if (!(rdb_flags & RDB_COMPOSITOR)) { + return; + } + + endrow = MIN(endrow, default_grid.Rows); + endcol = MIN(endcol, default_grid.Columns); + int attr = syn_id2attr(syn_id); + + for (int row = (int)startrow; row < endrow; row++) { + ui_composed_call_raw_line(1, row, startcol, startcol, endcol, attr, false, + (const schar_T *)linebuf, + (const sattr_T *)attrbuf); + } + + + if (delay) { + debug_delay(endrow-startrow); + } +} + +static void debug_delay(Integer lines) +{ + ui_call_flush(); + uint64_t wd = (uint64_t)labs(p_wd); + uint64_t factor = (uint64_t)MAX(MIN(lines, 5), 1); + os_microdelay(factor * wd * 1000u, true); +} + + static void compose_area(Integer startrow, Integer endrow, Integer startcol, Integer endcol) { + compose_debug(startrow, endrow, startcol, endcol, dbghl_recompose, true); endrow = MIN(endrow, default_grid.Rows); endcol = MIN(endcol, default_grid.Columns); if (endcol <= startcol) { @@ -420,8 +474,11 @@ static void ui_comp_raw_line(UI *ui, Integer grid, Integer row, if (flags & kLineFlagInvalid || kv_size(layers) > curgrid->comp_index+1 || curgrid->blending) { + compose_debug(row, row+1, startcol, clearcol, dbghl_composed, true); compose_line(row, startcol, clearcol, flags); } else { + compose_debug(row, row+1, startcol, endcol, dbghl_normal, false); + compose_debug(row, row+1, endcol, clearcol, dbghl_clear, true); ui_composed_call_raw_line(1, row, startcol, endcol, clearcol, clearattr, flags, chunk, attrs); } @@ -481,6 +538,9 @@ static void ui_comp_grid_scroll(UI *ui, Integer grid, Integer top, } else { msg_first_invalid = MIN(msg_first_invalid, (int)top); ui_composed_call_grid_scroll(1, top, bot, left, right, rows, cols); + if (rdb_flags & RDB_COMPOSITOR) { + debug_delay(2); + } } } diff --git a/src/nvim/window.c b/src/nvim/window.c index a3b1efeaaa..6ce095f976 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -375,7 +375,7 @@ newwindow: /* set current window height */ case Ctrl__: case '_': - win_setheight(Prenum ? (int)Prenum : 9999); + win_setheight(Prenum ? (int)Prenum : Rows-1); break; /* increase current window width */ @@ -390,7 +390,7 @@ newwindow: /* set current window width */ case '|': - win_setwidth(Prenum != 0 ? (int)Prenum : 9999); + win_setwidth(Prenum != 0 ? (int)Prenum : Columns); break; /* jump to tag and split window if tag exists (in preview window) */ @@ -584,15 +584,43 @@ win_T *win_new_float(win_T *wp, FloatConfig fconfig, Error *err) wp->w_status_height = 0; wp->w_vsep_width = 0; - // TODO(bfredl): use set_option_to() after merging #9110 ? - wp->w_p_nu = false; - wp->w_allbuf_opt.wo_nu = false; win_config_float(wp, fconfig); wp->w_pos_changed = true; redraw_win_later(wp, VALID); return wp; } +void win_set_minimal_style(win_T *wp) +{ + wp->w_p_nu = false; + wp->w_p_rnu = false; + wp->w_p_cul = false; + wp->w_p_cuc = false; + wp->w_p_spell = false; + wp->w_p_list = false; + + // Hide EOB region: use " " fillchar and cleared highlighting + if (wp->w_p_fcs_chars.eob != ' ') { + char_u *old = wp->w_p_fcs; + wp->w_p_fcs = ((*old == NUL) + ? (char_u *)xstrdup("eob: ") + : concat_str(old, (char_u *)",eob: ")); + xfree(old); + } + if (wp->w_hl_ids[HLF_EOB] != -1) { + char_u *old = wp->w_p_winhl; + wp->w_p_winhl = ((*old == NUL) + ? (char_u *)xstrdup("EndOfBuffer:") + : concat_str(old, (char_u *)",EndOfBuffer:")); + xfree(old); + } + + if (wp->w_p_scl[0] != 'a') { + xfree(wp->w_p_scl); + wp->w_p_scl = (char_u *)xstrdup("auto"); + } +} + void win_config_float(win_T *wp, FloatConfig fconfig) { wp->w_width = MAX(fconfig.width, 1); @@ -666,6 +694,7 @@ static void ui_ext_win_position(win_T *wp) bool on_top = (curwin == wp) || !curwin->w_floating; ui_comp_put_grid(&wp->w_grid, comp_row, comp_col, wp->w_height, wp->w_width, valid, on_top); + ui_check_cursor_grid(wp->w_grid.handle); if (!valid) { wp->w_grid.valid = false; redraw_win_later(wp, NOT_VALID); @@ -821,6 +850,20 @@ bool parse_float_config(Dictionary config, FloatConfig *fconfig, bool reconf, "'focusable' key must be Boolean"); return false; } + } else if (!strcmp(key, "style")) { + if (val.type != kObjectTypeString) { + api_set_error(err, kErrorTypeValidation, + "'style' key must be String"); + return false; + } + if (val.data.string.data[0] == NUL) { + fconfig->style = kWinStyleUnused; + } else if (striequal(val.data.string.data, "minimal")) { + fconfig->style = kWinStyleMinimal; + } else { + api_set_error(err, kErrorTypeValidation, + "Invalid value of 'style' key"); + } } else { api_set_error(err, kErrorTypeValidation, "Invalid key '%s'", key); @@ -4823,13 +4866,9 @@ void win_setheight_win(int height, win_T *win) } if (win->w_floating) { - if (win->w_float_config.external) { - win->w_float_config.height = height; - win_config_float(win, win->w_float_config); - } else { - beep_flush(); - return; - } + win->w_float_config.height = height; + win_config_float(win, win->w_float_config); + redraw_win_later(win, NOT_VALID); } else { frame_setheight(win->w_frame, height + win->w_status_height); @@ -4844,9 +4883,9 @@ void win_setheight_win(int height, win_T *win) cmdline_row = row; msg_row = row; msg_col = 0; + redraw_all_later(NOT_VALID); } - redraw_all_later(NOT_VALID); } @@ -5029,21 +5068,17 @@ void win_setwidth_win(int width, win_T *wp) width = 1; } if (wp->w_floating) { - if (wp->w_float_config.external) { - wp->w_float_config.width = width; - win_config_float(wp, wp->w_float_config); - } else { - beep_flush(); - return; - } + wp->w_float_config.width = width; + win_config_float(wp, wp->w_float_config); + redraw_win_later(wp, NOT_VALID); } else { frame_setwidth(wp->w_frame, width + wp->w_vsep_width); // recompute the window positions (void)win_comp_pos(); + redraw_all_later(NOT_VALID); } - redraw_all_later(NOT_VALID); } /* diff --git a/test/functional/eval/executable_spec.lua b/test/functional/eval/executable_spec.lua index ca82c8c9da..e346b786a6 100644 --- a/test/functional/eval/executable_spec.lua +++ b/test/functional/eval/executable_spec.lua @@ -21,8 +21,6 @@ describe('executable()', function() -- Windows: siblings are in Nvim's "pseudo-$PATH". local expected = iswin() and 1 or 0 if iswin() then - -- $PATH on AppVeyor CI might be oversized, redefine it to a minimal one. - clear({env={PATH=[[C:\Windows\system32;C:\Windows]]}}) eq('arg1=lemon;arg2=sky;arg3=tree;', call('system', sibling_exe..' lemon sky tree')) end diff --git a/test/functional/eval/reltime_spec.lua b/test/functional/eval/reltime_spec.lua index 0181f09024..ef7a3a148f 100644 --- a/test/functional/eval/reltime_spec.lua +++ b/test/functional/eval/reltime_spec.lua @@ -33,4 +33,14 @@ describe('reltimestr(), reltimefloat()', function() ok(reltimefloat(differs) < 1.0) end) + + it('reltime() allows negative result #10452', function() + local older_time = reltime() + command('sleep 1m') + local newer_time = reltime() + -- Should be something like -0.002123. + local rv = tonumber(reltimestr(reltime(newer_time, older_time))) + ok(rv < 0) + ok(rv > -10) + end) end) diff --git a/test/functional/ex_cmds/menu_spec.lua b/test/functional/ex_cmds/menu_spec.lua index 2309e949c0..0cd32df27c 100644 --- a/test/functional/ex_cmds/menu_spec.lua +++ b/test/functional/ex_cmds/menu_spec.lua @@ -83,7 +83,7 @@ describe('menu_get', function() it("path='', modes='a'", function() local m = funcs.menu_get("","a"); -- HINT: To print the expected table and regenerate the tests: - -- print(require('inspect')(m)) + -- print(require('vim.inspect')(m)) local expected = { { shortcut = "T", diff --git a/test/functional/options/num_options_spec.lua b/test/functional/options/num_options_spec.lua index 88e554c86f..deda5c9118 100644 --- a/test/functional/options/num_options_spec.lua +++ b/test/functional/options/num_options_spec.lua @@ -74,7 +74,7 @@ describe(':set validation', function() should_fail('foldlevel', -5, 'E487') should_fail('foldcolumn', 13, 'E474') should_fail('conceallevel', 4, 'E474') - should_fail('numberwidth', 11, 'E474') + should_fail('numberwidth', 21, 'E474') should_fail('numberwidth', 0, 'E487') -- If smaller than 1 this one is set to 'lines'-1 diff --git a/test/functional/terminal/ex_terminal_spec.lua b/test/functional/terminal/ex_terminal_spec.lua index 2c731066bd..591e6340cf 100644 --- a/test/functional/terminal/ex_terminal_spec.lua +++ b/test/functional/terminal/ex_terminal_spec.lua @@ -261,4 +261,14 @@ describe(':terminal (with fake shell)', function() eq('scripts/shadacat.py', eval('bufname("%")')) end) + it('with bufhidden=delete #3958', function() + command('set hidden') + eq(1, eval('&hidden')) + command('autocmd BufNew * setlocal bufhidden=delete') + for _ = 1, 5 do + source([[ + execute 'edit '.reltimestr(reltime()) + terminal]]) + end + end) end) diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua index 4dc86f1e1f..6475eb2923 100644 --- a/test/functional/ui/cursor_spec.lua +++ b/test/functional/ui/cursor_spec.lua @@ -216,10 +216,10 @@ describe('ui/cursor', function() if m.blinkwait then m.blinkwait = 700 end end if m.hl_id then - m.hl_id = 50 + m.hl_id = 54 m.attr = {background = Screen.colors.DarkGray} end - if m.id_lm then m.id_lm = 51 end + if m.id_lm then m.id_lm = 55 end end -- Assert the new expectation. diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index 41ba542899..68a23db0a2 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -35,6 +35,10 @@ describe('floating windows', function() [15] = {background = Screen.colors.Grey20}, [16] = {background = Screen.colors.Grey20, bold = true, foreground = Screen.colors.Blue1}, [17] = {background = Screen.colors.Yellow}, + [18] = {foreground = Screen.colors.Brown, background = Screen.colors.Grey20}, + [19] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.WebGray}, + [20] = {bold = true, foreground = Screen.colors.Brown}, + [21] = {background = Screen.colors.Gray90}, } it('behavior', function() @@ -168,6 +172,121 @@ describe('floating windows', function() end end) + it('draws correctly with redrawdebug=compositor', function() + -- NB: we do not test that it produces the "correct" debug info + -- (as it is intermediate only, and is allowed to change by internal + -- refactors). Only check that it doesn't cause permanent glitches, + -- or something. + command("set redrawdebug=compositor") + command("set wd=1") + local buf = meths.create_buf(false,false) + local win = meths.open_win(buf, false, {relative='editor', width=20, height=2, row=2, col=5}) + local expected_pos = { + [3]={{id=1001}, 'NW', 1, 2, 5, true}, + } + + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + | + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + {1: }| + {2:~ }| + ]], float_pos=expected_pos} + else + screen:expect([[ + ^ | + {0:~ }| + {0:~ }{1: }{0: }| + {0:~ }{2:~ }{0: }| + {0:~ }| + {0:~ }| + | + ]]) + end + + + meths.win_set_config(win, {relative='editor', row=0, col=10}) + expected_pos[3][4] = 0 + expected_pos[3][5] = 10 + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + | + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + {1: }| + {2:~ }| + ]], float_pos=expected_pos} + else + screen:expect([[ + ^ {1: } | + {0:~ }{2:~ }{0: }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + end + + meths.win_close(win, false) + if multigrid then + screen:expect([[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + | + ## grid 2 + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ]]) + else + screen:expect([[ + ^ | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + end + end) + it('return their configuration', function() local buf = meths.create_buf(false, false) local win = meths.open_win(buf, false, {relative='editor', width=20, height=2, row=3, col=5}) @@ -182,7 +301,7 @@ describe('floating windows', function() end end) - it('defaults to nonumber and NormalFloat highlight', function() + it('defaults to NormalFloat highlight and inherited options', function() command('set number') command('hi NormalFloat guibg=#333333') feed('ix<cr>y<cr><esc>gg') @@ -205,18 +324,18 @@ describe('floating windows', function() {0:~ }| {0:~ }| ## grid 3 - {15:x }| - {15:y }| - {15: }| + {18: 1 }{15:x }| + {18: 2 }{15:y }| + {18: 3 }{15: }| {16:~ }| ]], float_pos={[3] = {{id = 1001}, "NW", 1, 4, 10, true}}} else screen:expect([[ {14: 1 }^x | {14: 2 }y | - {14: 3 } {15:x } | - {0:~ }{15:y }{0: }| - {0:~ }{15: }{0: }| + {14: 3 } {18: 1 }{15:x } | + {0:~ }{18: 2 }{15:y }{0: }| + {0:~ }{18: 3 }{15: }{0: }| {0:~ }{16:~ }{0: }| | ]]) @@ -242,7 +361,7 @@ describe('floating windows', function() {0:~ }| {0:~ }| ## grid 3 - {15: }| + {18: 1 }{15: }| {16:~ }| {16:~ }| {16:~ }| @@ -251,7 +370,7 @@ describe('floating windows', function() screen:expect([[ {14: 1 }^x | {14: 2 }y | - {14: 3 } {15: } | + {14: 3 } {18: 1 }{15: } | {0:~ }{16:~ }{0: }| {0:~ }{16:~ }{0: }| {0:~ }{16:~ }{0: }| @@ -260,6 +379,126 @@ describe('floating windows', function() end end) + it("can use 'minimal' style", function() + command('set number') + command('set signcolumn=yes') + command('set cursorline') + command('hi NormalFloat guibg=#333333') + feed('ix<cr>y<cr><esc>gg') + local win = meths.open_win(0, false, {relative='editor', width=20, height=4, row=4, col=10, style='minimal'}) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + | + ## grid 2 + {19: }{20: 1 }{21:^x }| + {19: }{14: 2 }y | + {19: }{14: 3 } | + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + {15:x }| + {15:y }| + {15: }| + {15: }| + ]], float_pos={[3] = {{id = 1001}, "NW", 1, 4, 10, true}}} + else + screen:expect([[ + {19: }{20: 1 }{21:^x }| + {19: }{14: 2 }y | + {19: }{14: 3 } {15:x } | + {0:~ }{15:y }{0: }| + {0:~ }{15: }{0: }| + {0:~ }{15: }{0: }| + | + ]]) + end + + -- signcolumn=yes still works if there actually are signs + command('sign define piet1 text=𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄ texthl=Search') + command('sign place 1 line=1 name=piet1 buffer=1') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + | + ## grid 2 + {17:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{20: 1 }{21:^x }| + {19: }{14: 2 }y | + {19: }{14: 3 } | + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + {17:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{15:x }| + {19: }{15:y }| + {19: }{15: }| + {15: }| + ]], float_pos={[3] = {{id = 1001}, "NW", 1, 4, 10, true}}} + + else + screen:expect([[ + {17:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{20: 1 }{21:^x }| + {19: }{14: 2 }y | + {19: }{14: 3 } {17:𐌢̀́̂̃̅̄𐌢̀́̂̃̅̄}{15:x } | + {0:~ }{19: }{15:y }{0: }| + {0:~ }{19: }{15: }{0: }| + {0:~ }{15: }{0: }| + | + ]]) + end + command('sign unplace 1 buffer=1') + + local buf = meths.create_buf(false, true) + meths.win_set_buf(win, buf) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + | + ## grid 2 + {19: }{20: 1 }{21:^x }| + {19: }{14: 2 }y | + {19: }{14: 3 } | + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + {15: }| + {15: }| + {15: }| + {15: }| + ]], float_pos={[3] = {{id = 1001}, "NW", 1, 4, 10, true}}} + else + screen:expect([[ + {19: }{20: 1 }{21:^x }| + {19: }{14: 2 }y | + {19: }{14: 3 } {15: } | + {0:~ }{15: }{0: }| + {0:~ }{15: }{0: }| + {0:~ }{15: }{0: }| + | + ]]) + end + end) + it('can have minimum size', function() insert("the background text") local buf = meths.create_buf(false, true) @@ -2539,6 +2778,356 @@ describe('floating windows', function() end) + it("vertical resize + - _", function() + feed('<c-w>w') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + | + ## grid 2 + x | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + {1:^y }| + {2:~ }| + ]], float_pos=expected_pos} + else + screen:expect([[ + x | + {0:~ }| + {0:~ }{1:^y }{0: }| + {0:~ }{2:~ }{0: }| + {0:~ }| + {0:~ }| + | + ]]) + end + + feed('<c-w>+') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + | + ## grid 2 + x | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + {1:^y }| + {2:~ }| + {2:~ }| + ]], float_pos=expected_pos} + else + screen:expect([[ + x | + {0:~ }| + {0:~ }{1:^y }{0: }| + {0:~ }{2:~ }{0: }| + {0:~ }{2:~ }{0: }| + {0:~ }| + | + ]]) + end + + feed('<c-w>2-') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + | + ## grid 2 + x | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + {1:^y }| + ]], float_pos=expected_pos} + else + screen:expect([[ + x | + {0:~ }| + {0:~ }{1:^y }{0: }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + end + + feed('<c-w>4_') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + | + ## grid 2 + x | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + {1:^y }| + {2:~ }| + {2:~ }| + {2:~ }| + ]], float_pos=expected_pos} + else + screen:expect([[ + x | + {0:~ }| + {0:~ }{1:^y }{0: }| + {0:~ }{2:~ }{0: }| + {0:~ }{2:~ }{0: }| + {0:~ }{2:~ }{0: }| + | + ]]) + end + + feed('<c-w>_') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + | + ## grid 2 + x | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + {1:^y }| + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + ]], float_pos=expected_pos} + else + screen:expect([[ + x {1:^y } | + {0:~ }{2:~ }{0: }| + {0:~ }{2:~ }{0: }| + {0:~ }{2:~ }{0: }| + {0:~ }{2:~ }{0: }| + {0:~ }{2:~ }{0: }| + | + ]]) + end + end) + + it("horizontal resize > < |", function() + feed('<c-w>w') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + | + ## grid 2 + x | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + {1:^y }| + {2:~ }| + ]], float_pos=expected_pos} + else + screen:expect([[ + x | + {0:~ }| + {0:~ }{1:^y }{0: }| + {0:~ }{2:~ }{0: }| + {0:~ }| + {0:~ }| + | + ]]) + end + + feed('<c-w>>') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + | + ## grid 2 + x | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + {1:^y }| + {2:~ }| + ]], float_pos=expected_pos} + else + screen:expect([[ + x | + {0:~ }| + {0:~ }{1:^y }{0: }| + {0:~ }{2:~ }{0: }| + {0:~ }| + {0:~ }| + | + ]]) + end + + feed('<c-w>10<lt>') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + | + ## grid 2 + x | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + {1:^y }| + {2:~ }| + ]], float_pos=expected_pos} + else + screen:expect([[ + x | + {0:~ }| + {0:~ }{1:^y }{0: }| + {0:~ }{2:~ }{0: }| + {0:~ }| + {0:~ }| + | + ]]) + end + + feed('<c-w>15|') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + | + ## grid 2 + x | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + {1:^y }| + {2:~ }| + ]], float_pos=expected_pos} + else + screen:expect([[ + x | + {0:~ }| + {0:~ }{1:^y }{0: }| + {0:~ }{2:~ }{0: }| + {0:~ }| + {0:~ }| + | + ]]) + end + + feed('<c-w>|') + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + | + ## grid 2 + x | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + {1:^y }| + {2:~ }| + ]], float_pos=expected_pos} + else + screen:expect([[ + x | + {0:~ }| + {1:^y }| + {2:~ }| + {0:~ }| + {0:~ }| + | + ]]) + end + end) + it("s :split (non-float)", function() feed("<c-w>s") if multigrid then @@ -3999,6 +4588,78 @@ describe('floating windows', function() ]]) end end) + + it('can overlap doublewidth chars', function() + insert([[ + # TODO: 测试字典信息的准确性 + # FIXME: 测试字典信息的准确性]]) + local buf = meths.create_buf(false,false) + local win = meths.open_win(buf, false, {relative='editor', width=5, height=3, row=0, col=11, style='minimal'}) + if multigrid then + screen:expect{grid=[[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + | + ## grid 2 + # TODO: 测试字典信息的准确性 | + # FIXME: 测试字典信息的准确^性 | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ## grid 3 + {1: }| + {1: }| + {1: }| + ]], float_pos={ [3] = { { id = 1001 }, "NW", 1, 0, 11, true } }} + else + screen:expect([[ + # TODO: 测 {1: }信息的准确性 | + # FIXME: 测{1: } 信息的准确^性 | + {0:~ }{1: }{0: }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + end + + meths.win_close(win, false) + if multigrid then + screen:expect([[ + ## grid 1 + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + [2:----------------------------------------]| + | + ## grid 2 + # TODO: 测试字典信息的准确性 | + # FIXME: 测试字典信息的准确^性 | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + ]]) + else + screen:expect([[ + # TODO: 测试字典信息的准确性 | + # FIXME: 测试字典信息的准确^性 | + {0:~ }| + {0:~ }| + {0:~ }| + {0:~ }| + | + ]]) + end + end) end describe('with ext_multigrid', function() diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua index f1254b68f6..31669f5578 100644 --- a/test/functional/ui/screen.lua +++ b/test/functional/ui/screen.lua @@ -81,7 +81,7 @@ local dedent = helpers.dedent local get_session = helpers.get_session local create_callindex = helpers.create_callindex -local inspect = require('inspect') +local inspect = require('vim.inspect') local function isempty(v) return type(v) == 'table' and next(v) == nil @@ -492,7 +492,7 @@ function Screen:_wait(check, flags) end elseif success_seen and #args > 0 then failure_after_success = true - --print(require('inspect')(args)) + -- print(inspect(args)) end return true @@ -576,8 +576,7 @@ end function Screen:_redraw(updates) local did_flush = false for k, update in ipairs(updates) do - -- print('--') - -- print(require('inspect')(update)) + -- print('--', inspect(update)) local method = update[1] for i = 2, #update do local handler_name = '_handle_'..method @@ -1339,7 +1338,7 @@ end function Screen:_pprint_hlstate(item) - --print(require('inspect')(item)) + -- print(inspect(item)) local attrdict = "{"..self:_pprint_attrs(item[1]).."}, " local attrdict2, hlinfo if self._hlstate_cterm then diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt index b2b05e1175..497e95e38c 100644 --- a/third-party/CMakeLists.txt +++ b/third-party/CMakeLists.txt @@ -125,11 +125,11 @@ include(ExternalProject) if(WIN32) # "nvim" branch of https://github.com/neovim/libuv - set(LIBUV_URL https://github.com/neovim/libuv/archive/0ac136359903c70ab1db1838c3ad06da6fa5b912.tar.gz) - set(LIBUV_SHA256 600badb81e39578ddfc8f3636f78dd308ea0915e5bf1ee56e6cdfa314d3c463f) + set(LIBUV_URL https://github.com/neovim/libuv/archive/eeae18d085de25f138c23966f98a179f0fb609e7.tar.gz) + set(LIBUV_SHA256 c37d0b7cb1defe69ae8dbb4d712c0d7cf838d6539178e8bcf71c72579ab5b666) else() - set(LIBUV_URL https://github.com/libuv/libuv/archive/v1.29.1.tar.gz) - set(LIBUV_SHA256 bdde1140087ce97080ea323c3598553ece00a24ae63ac568be78bef3e97f3e25) + set(LIBUV_URL https://github.com/libuv/libuv/archive/v1.30.0.tar.gz) + set(LIBUV_SHA256 44c8fdadf3b3f393006a4ac4ba144020673a3f9cd72bed1fbb2c366ebcf0d199) endif() set(MSGPACK_URL https://github.com/msgpack/msgpack-c/releases/download/cpp-3.0.0/msgpack-3.0.0.tar.gz) diff --git a/third-party/cmake/BuildLuarocks.cmake b/third-party/cmake/BuildLuarocks.cmake index 8ab04cf87b..7f038c732d 100644 --- a/third-party/cmake/BuildLuarocks.cmake +++ b/third-party/cmake/BuildLuarocks.cmake @@ -129,20 +129,12 @@ add_custom_command(OUTPUT ${ROCKS_DIR}/lpeg add_custom_target(lpeg DEPENDS ${ROCKS_DIR}/lpeg) list(APPEND THIRD_PARTY_DEPS lpeg) -# inspect -add_custom_command(OUTPUT ${ROCKS_DIR}/inspect - COMMAND ${LUAROCKS_BINARY} - ARGS build inspect 3.1.1-0 ${LUAROCKS_BUILDARGS} - DEPENDS lpeg) -add_custom_target(inspect DEPENDS ${ROCKS_DIR}/inspect) -list(APPEND THIRD_PARTY_DEPS inspect) - if((NOT USE_BUNDLED_LUAJIT) AND USE_BUNDLED_LUA) # luabitop add_custom_command(OUTPUT ${ROCKS_DIR}/luabitop COMMAND ${LUAROCKS_BINARY} ARGS build luabitop 1.0.2-3 ${LUAROCKS_BUILDARGS} - DEPENDS inspect) + DEPENDS lpeg) add_custom_target(luabitop DEPENDS ${ROCKS_DIR}/luabitop) list(APPEND THIRD_PARTY_DEPS luabitop) endif() @@ -151,7 +143,7 @@ if(USE_BUNDLED_BUSTED) if((NOT USE_BUNDLED_LUAJIT) AND USE_BUNDLED_LUA) set(PENLIGHT_DEPENDS luabitop) else() - set(PENLIGHT_DEPENDS inspect) + set(PENLIGHT_DEPENDS lpeg) endif() # penlight diff --git a/third-party/cmake/BuildLuv.cmake b/third-party/cmake/BuildLuv.cmake index 9f8e4bbc4f..967e0a1711 100644 --- a/third-party/cmake/BuildLuv.cmake +++ b/third-party/cmake/BuildLuv.cmake @@ -71,6 +71,19 @@ set(LUV_CONFIGURE_COMMAND_COMMON -DBUILD_SHARED_LIBS=OFF -DBUILD_MODULE=OFF) +if(USE_BUNDLED_LUAJIT) + list(APPEND LUV_CONFIGURE_COMMAND_COMMON -DWITH_LUA_ENGINE=LuaJit) +elseif(USE_BUNDLED_LUA) + list(APPEND LUV_CONFIGURE_COMMAND_COMMON -DWITH_LUA_ENGINE=Lua) +else() + find_package(LuaJit) + if(LUAJIT_FOUND) + list(APPEND LUV_CONFIGURE_COMMAND_COMMON -DWITH_LUA_ENGINE=LuaJit) + else() + list(APPEND LUV_CONFIGURE_COMMAND_COMMON -DWITH_LUA_ENGINE=Lua) + endif() +endif() + if(USE_BUNDLED_LIBUV) set(LUV_CONFIGURE_COMMAND_COMMON ${LUV_CONFIGURE_COMMAND_COMMON} |