diff options
98 files changed, 2020 insertions, 522 deletions
diff --git a/.gitignore b/.gitignore index 85b371b926..cf0a11804d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ # Tools .ropeproject/ +# Visual Studio +/.vs/ # Build/deps dir /build/ diff --git a/.travis.yml b/.travis.yml index b275a5262d..fa884bd021 100644 --- a/.travis.yml +++ b/.travis.yml @@ -53,6 +53,7 @@ jobs: compiler: clang env: > CLANG_SANITIZER=ASAN_UBSAN + # Use Lua so that ASAN can test our embedded Lua support. 8fec4d53d0f6 CMAKE_FLAGS="$CMAKE_FLAGS -DPREFER_LUA=ON" sudo: true - os: linux diff --git a/CMakeLists.txt b/CMakeLists.txt index 4cafdef73f..9660fae527 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,9 +13,9 @@ include(PreventInTreeBuilds) # Prefer our bundled versions of dependencies. if(DEFINED ENV{DEPS_BUILD_DIR}) -set(DEPS_PREFIX "$ENV{DEPS_BUILD_DIR}/usr" CACHE PATH "Path prefix for finding dependencies") + set(DEPS_PREFIX "$ENV{DEPS_BUILD_DIR}/usr" CACHE PATH "Path prefix for finding dependencies") else() -set(DEPS_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/.deps/usr" CACHE PATH "Path prefix for finding dependencies") + set(DEPS_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/.deps/usr" CACHE PATH "Path prefix for finding dependencies") endif() if(CMAKE_CROSSCOMPILING AND NOT UNIX) list(INSERT CMAKE_FIND_ROOT_PATH 0 ${DEPS_PREFIX}) @@ -53,6 +53,14 @@ if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Darwin") set(USE_FNAME_CASE TRUE) endif() +option(ENABLE_LIBINTL "enable libintl" ON) +if(MSVC) + add_definitions(-DDYNAMIC_ICONV) + option(ENABLE_LIBICONV "enable libiconv" OFF) +else() + option(ENABLE_LIBICONV "enable libiconv" ON) +endif() + # Set default build type. if(NOT CMAKE_BUILD_TYPE) message(STATUS "CMAKE_BUILD_TYPE not given, defaulting to 'Debug'.") @@ -331,6 +339,7 @@ if(PREFER_LUA) find_package(Lua REQUIRED) set(LUA_PREFERRED_INCLUDE_DIRS ${LUA_INCLUDE_DIR}) set(LUA_PREFERRED_LIBRARIES ${LUA_LIBRARIES}) + # Passive (not REQUIRED): if LUAJIT_FOUND is not set, nvim-test is skipped. find_package(LuaJit) else() find_package(LuaJit REQUIRED) @@ -399,31 +408,30 @@ if((CLANG_ASAN_UBSAN OR CLANG_MSAN OR CLANG_TSAN) AND NOT CMAKE_C_COMPILER_ID MA message(FATAL_ERROR "Sanitizers are only supported for Clang.") endif() -if(CMAKE_SYSTEM_NAME MATCHES "OpenBSD|FreeBSD") - message(STATUS "detected OpenBSD/FreeBSD; disabled jemalloc. #5318") +if(CMAKE_SYSTEM_NAME MATCHES "OpenBSD|FreeBSD|Windows") # see #5318 + message(STATUS "skipping jemalloc on this system: ${CMAKE_SYSTEM_NAME}") option(ENABLE_JEMALLOC "enable jemalloc" OFF) else() option(ENABLE_JEMALLOC "enable jemalloc" ON) endif() -if (ENABLE_JEMALLOC) +if(ENABLE_JEMALLOC) if(CLANG_ASAN_UBSAN OR CLANG_MSAN OR CLANG_TSAN) message(STATUS "Sanitizers have been enabled; don't use jemalloc.") else() - find_package(JeMalloc) - if(JEMALLOC_FOUND) - include_directories(SYSTEM ${JEMALLOC_INCLUDE_DIRS}) - endif() + find_package(JeMalloc REQUIRED) + include_directories(SYSTEM ${JEMALLOC_INCLUDE_DIRS}) endif() endif() -find_package(LibIntl) -if(LibIntl_FOUND) +if(ENABLE_LIBINTL) + # LibIntl (not Intl) selects our FindLibIntl.cmake script. #8464 + find_package(LibIntl REQUIRED) include_directories(SYSTEM ${LibIntl_INCLUDE_DIRS}) endif() -find_package(Iconv) -if(Iconv_FOUND) +if(ENABLE_LIBICONV) + find_package(Iconv REQUIRED) include_directories(SYSTEM ${Iconv_INCLUDE_DIRS}) endif() diff --git a/ci/build.ps1 b/ci/build.ps1 index 8eb237ccd1..7e686f3464 100644 --- a/ci/build.ps1 +++ b/ci/build.ps1 @@ -77,6 +77,7 @@ where.exe neovim-ruby-host.bat ; exitIfFailed cmd /c npm.cmd install -g neovim ; exitIfFailed where.exe neovim-node-host.cmd ; exitIfFailed +cmd /c npm link neovim function convertToCmakeArgs($vars) { return $vars.GetEnumerator() | foreach { "-D$($_.Key)=$($_.Value)" } diff --git a/ci/install.sh b/ci/install.sh index 50f3490b63..e95e2f29c1 100755 --- a/ci/install.sh +++ b/ci/install.sh @@ -33,3 +33,4 @@ fi echo "Install neovim npm package" npm install -g neovim +npm link neovim diff --git a/cmake/FindLibIntl.cmake b/cmake/FindLibIntl.cmake index f8442566a9..738ae39983 100644 --- a/cmake/FindLibIntl.cmake +++ b/cmake/FindLibIntl.cmake @@ -34,9 +34,8 @@ if (LibIntl_INCLUDE_DIR) set(CMAKE_REQUIRED_INCLUDES "${LibIntl_INCLUDE_DIR}") endif() -# This is required because some operating systems don't have a separate -# libintl--it is built into glibc. So we only need to specify the library -# if one was actually found. +# On some systems (linux+glibc) libintl is passively available. +# So only specify the library if one was found. if (LibIntl_LIBRARY) set(CMAKE_REQUIRED_LIBRARIES "${LibIntl_LIBRARY}") endif() @@ -53,6 +52,13 @@ int main(int argc, char** argv) { }" HAVE_WORKING_LIBINTL) if (HAVE_WORKING_LIBINTL) + # On some systems (linux+glibc) libintl is passively available. + # If HAVE_WORKING_LIBINTL then we consider the requirement satisfied. + # Unset REQUIRED so that libfind_process(LibIntl) can proceed. + if(LibIntl_FIND_REQUIRED) + unset(LibIntl_FIND_REQUIRED) + endif() + check_variable_exists(_nl_msg_cat_cntr HAVE_NL_MSG_CAT_CNTR) endif() diff --git a/cmake/FindLibUV.cmake b/cmake/FindLibUV.cmake index 3a60a831ea..29eaf15b8e 100644 --- a/cmake/FindLibUV.cmake +++ b/cmake/FindLibUV.cmake @@ -31,11 +31,7 @@ if(LIBUV_USE_STATIC) "${CMAKE_STATIC_LIBRARY_PREFIX}uv${CMAKE_STATIC_LIBRARY_SUFFIX}") endif(LIBUV_USE_STATIC) -if(MSVC) - list(APPEND LIBUV_NAMES libuv) -else() - list(APPEND LIBUV_NAMES uv) -endif() +list(APPEND LIBUV_NAMES uv) find_library(LIBUV_LIBRARY NAMES ${LIBUV_NAMES} HINTS ${PC_LIBUV_LIBDIR} ${PC_LIBUV_LIBRARY_DIRS} diff --git a/makedeps.bat b/makedeps.bat new file mode 100644 index 0000000000..a614885568 --- /dev/null +++ b/makedeps.bat @@ -0,0 +1,18 @@ +echo off + +if not defined VS150COMNTOOLS ( + echo error: missing VS150COMNTOOLS environment variable. + echo Run this script from the 'Developer Command Prompt'. + exit /b 1 +) + +echo on + +set CMAKE=%VS150COMNTOOLS%\..\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe + +mkdir .deps +cd .deps +"%CMAKE%" -G "Visual Studio 15 2017" "-DCMAKE_BUILD_TYPE=RelWithDebInfo" ..\third-party\ +"%CMAKE%" --build . --config RelWithDebInfo -- "/verbosity:normal" +cd .. + diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index fffdcef8d9..f404192abb 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -6789,10 +6789,12 @@ setpos({expr}, {list}) [bufnum, lnum, col, off, curswant] "bufnum" is the buffer number. Zero can be used for the - current buffer. Setting the cursor is only possible for - the current buffer. To set a mark in another buffer you can - use the |bufnr()| function to turn a file name into a buffer - number. + current buffer. When setting an uppercase mark "bufnum" is + used for the mark position. For other marks it specifies the + buffer to set the mark in. You can use the |bufnr()| function + to turn a file name into a buffer number. + For setting the cursor and the ' mark "bufnum" is ignored, + since these are associated with a window, not a buffer. Does not change the jumplist. "lnum" and "col" are the position in the buffer. The first diff --git a/runtime/doc/pattern.txt b/runtime/doc/pattern.txt index ab78b8b71c..cc485b655d 100644 --- a/runtime/doc/pattern.txt +++ b/runtime/doc/pattern.txt @@ -1071,25 +1071,27 @@ x A single character, with no special meaning, matches itself - A character class expression is evaluated to the set of characters belonging to that character class. The following character classes are supported: - Name Contents ~ -*[:alnum:]* [:alnum:] ASCII letters and digits -*[:alpha:]* [:alpha:] ASCII letters -*[:blank:]* [:blank:] space and tab characters -*[:cntrl:]* [:cntrl:] control characters -*[:digit:]* [:digit:] decimal digits -*[:graph:]* [:graph:] printable characters excluding space -*[:lower:]* [:lower:] lowercase letters (all letters when + Name Func Contents ~ +*[:alnum:]* [:alnum:] isalnum ASCII letters and digits +*[:alpha:]* [:alpha:] isalpha ASCII letters +*[:blank:]* [:blank:] space and tab +*[:cntrl:]* [:cntrl:] iscntrl ASCII control characters +*[:digit:]* [:digit:] decimal digits '0' to '9' +*[:graph:]* [:graph:] isgraph ASCII printable characters excluding + space +*[:lower:]* [:lower:] (1) lowercase letters (all letters when 'ignorecase' is used) -*[:print:]* [:print:] printable characters including space -*[:punct:]* [:punct:] ASCII punctuation characters -*[:space:]* [:space:] whitespace characters -*[:upper:]* [:upper:] uppercase letters (all letters when +*[:print:]* [:print:] (2) printable characters including space +*[:punct:]* [:punct:] ispunct ASCII punctuation characters +*[:space:]* [:space:] whitespace characters: space, tab, CR, + NL, vertical tab, form feed +*[:upper:]* [:upper:] (3) uppercase letters (all letters when 'ignorecase' is used) -*[:xdigit:]* [:xdigit:] hexadecimal digits -*[:return:]* [:return:] the <CR> character -*[:tab:]* [:tab:] the <Tab> character -*[:escape:]* [:escape:] the <Esc> character -*[:backspace:]* [:backspace:] the <BS> character +*[:xdigit:]* [:xdigit:] hexadecimal digits: 0-9, a-f, A-F +*[:return:]* [:return:] the <CR> character +*[:tab:]* [:tab:] the <Tab> character +*[:escape:]* [:escape:] the <Esc> character +*[:backspace:]* [:backspace:] the <BS> character The brackets in character class expressions are additional to the brackets delimiting a collection. For example, the following is a plausible pattern for a Unix filename: "[-./[:alnum:]_~]\+" That is, @@ -1100,6 +1102,13 @@ x A single character, with no special meaning, matches itself regexp engine. See |two-engines|. In the future these items may work for multi-byte characters. For now, to get all "alpha" characters you can use: [[:lower:][:upper:]]. + + The "Func" column shows what library function is used. The + implementation depends on the system. Otherwise: + (1) Uses islower() for ASCII and Vim builtin rules for other + characters when built with the |+multi_byte| feature. + (2) Uses Vim builtin rules + (3) As with (1) but using isupper() */[[=* *[==]* - An equivalence class. This means that characters are matched that have almost the same meaning, e.g., when ignoring accents. This diff --git a/runtime/mswin.vim b/runtime/mswin.vim index ca280d227c..da869a9fc7 100644 --- a/runtime/mswin.vim +++ b/runtime/mswin.vim @@ -1,7 +1,7 @@ " Set options and add mapping such that Vim behaves a lot like MS-Windows " " Maintainer: Bram Moolenaar <Bram@vim.org> -" Last change: 2012 Jul 25 +" Last change: 2017 Oct 28 " bail out if this isn't wanted (mrsvim.vim uses this). if exists("g:skip_loading_mswin") && g:skip_loading_mswin @@ -23,20 +23,22 @@ set backspace=indent,eol,start whichwrap+=<,>,[,] " backspace in Visual mode deletes selection vnoremap <BS> d -" CTRL-X and SHIFT-Del are Cut -vnoremap <C-X> "+x -vnoremap <S-Del> "+x +if has("clipboard") + " CTRL-X and SHIFT-Del are Cut + vnoremap <C-X> "+x + vnoremap <S-Del> "+x -" CTRL-C and CTRL-Insert are Copy -vnoremap <C-C> "+y -vnoremap <C-Insert> "+y + " CTRL-C and CTRL-Insert are Copy + vnoremap <C-C> "+y + vnoremap <C-Insert> "+y -" CTRL-V and SHIFT-Insert are Paste -map <C-V> "+gP -map <S-Insert> "+gP + " CTRL-V and SHIFT-Insert are Paste + map <C-V> "+gP + map <S-Insert> "+gP -cmap <C-V> <C-R>+ -cmap <S-Insert> <C-R>+ + cmap <C-V> <C-R>+ + cmap <S-Insert> <C-R>+ +endif " Pasting blockwise and linewise selections is not possible in Insert and " Visual mode without the +virtualedit feature. They are pasted as if they @@ -44,8 +46,10 @@ cmap <S-Insert> <C-R>+ " Uses the paste.vim autoload script. " Use CTRL-G u to have CTRL-Z only undo the paste. -exe 'inoremap <script> <C-V> <C-G>u' . paste#paste_cmd['i'] -exe 'vnoremap <script> <C-V> ' . paste#paste_cmd['v'] +if 1 + exe 'inoremap <script> <C-V> <C-G>u' . paste#paste_cmd['i'] + exe 'vnoremap <script> <C-V> ' . paste#paste_cmd['v'] +endif imap <S-Insert> <C-V> vmap <S-Insert> <C-V> @@ -99,6 +103,19 @@ inoremap <C-F4> <C-O><C-W>c cnoremap <C-F4> <C-C><C-W>c onoremap <C-F4> <C-C><C-W>c +if has("gui") + " CTRL-F is the search dialog + noremap <expr> <C-F> has("gui_running") ? ":promptfind\<CR>" : "/" + inoremap <expr> <C-F> has("gui_running") ? "\<C-\>\<C-O>:promptfind\<CR>" : "\<C-\>\<C-O>/" + cnoremap <expr> <C-F> has("gui_running") ? "\<C-\>\<C-C>:promptfind\<CR>" : "\<C-\>\<C-O>/" + + " CTRL-H is the replace dialog, + " but in console, it might be backspace, so don't map it there + nnoremap <expr> <C-H> has("gui_running") ? ":promptrepl\<CR>" : "\<C-H>" + inoremap <expr> <C-H> has("gui_running") ? "\<C-\>\<C-O>:promptrepl\<CR>" : "\<C-H>" + cnoremap <expr> <C-H> has("gui_running") ? "\<C-\>\<C-C>:promptrepl\<CR>" : "\<C-H>" +endif + " restore 'cpoptions' set cpo& if 1 diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index 2d803792c8..65c3c6bbb9 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -457,6 +457,8 @@ if(WIN32) COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/Qt5Widgets.dll" ${PROJECT_BINARY_DIR}/windows_runtime_deps/ COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/winpty.dll" ${PROJECT_BINARY_DIR}/windows_runtime_deps/ + COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/libiconv-2.dll" ${PROJECT_BINARY_DIR}/windows_runtime_deps/ + COMMAND ${CMAKE_COMMAND} -E copy "${DEPS_PREFIX}/bin/platforms/qwindows.dll" ${PROJECT_BINARY_DIR}/windows_runtime_deps/platforms/ ) add_dependencies(nvim_runtime_deps external_blobs) @@ -484,7 +486,9 @@ set_property( APPEND_STRING PROPERTY COMPILE_FLAGS " -DMAKE_LIB " ) -if(LUAJIT_FOUND) +if(NOT LUAJIT_FOUND) + message(STATUS "luajit not found, skipping nvim-test (unit tests) target") +else() set(NVIM_TEST_LINK_LIBRARIES ${NVIM_LINK_LIBRARIES} ${LUAJIT_LIBRARIES}) add_library( nvim-test diff --git a/src/nvim/api/private/dispatch.c b/src/nvim/api/private/dispatch.c index f8eebcdb10..5207a57b88 100644 --- a/src/nvim/api/private/dispatch.c +++ b/src/nvim/api/private/dispatch.c @@ -29,6 +29,8 @@ static void msgpack_rpc_add_method_handler(String method, map_put(String, MsgpackRpcRequestHandler)(methods, method, handler); } +/// @param name API method name +/// @param name_len name size (includes terminating NUL) MsgpackRpcRequestHandler msgpack_rpc_get_handler_for(const char *name, size_t name_len) { diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 4cd2657561..b6e0b9a566 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -97,6 +97,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, ui->set_icon = remote_ui_set_icon; ui->option_set = remote_ui_option_set; ui->event = remote_ui_event; + ui->inspect = remote_ui_inspect; memset(ui->ui_ext, 0, sizeof(ui->ui_ext)); @@ -275,3 +276,9 @@ static void remote_ui_event(UI *ui, char *name, Array args, bool *args_consumed) } push_call(ui, name, my_args); } + +static void remote_ui_inspect(UI *ui, Dictionary *info) +{ + UIData *data = ui->data; + PUT(*info, "chan", INTEGER_OBJ((Integer)data->channel_id)); +} diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index 96d494460b..3ef16a7ac3 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -62,7 +62,7 @@ void set_title(String title) void set_icon(String icon) FUNC_API_SINCE(3); void option_set(String name, Object value) - FUNC_API_SINCE(4); + FUNC_API_SINCE(4) FUNC_API_BRIDGE_IMPL; void popupmenu_show(Array items, Integer selected, Integer row, Integer col) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index f587948cf0..b3ae52602b 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -16,6 +16,7 @@ #include "nvim/api/private/dispatch.h" #include "nvim/api/buffer.h" #include "nvim/msgpack_rpc/channel.h" +#include "nvim/msgpack_rpc/helpers.h" #include "nvim/lua/executor.h" #include "nvim/vim.h" #include "nvim/buffer.h" @@ -1163,6 +1164,11 @@ Array nvim_call_atomic(uint64_t channel_id, Array calls, Error *err) MsgpackRpcRequestHandler handler = msgpack_rpc_get_handler_for(name.data, name.size); + if (handler.fn == msgpack_rpc_handle_missing_method) { + api_set_error(&nested_error, kErrorTypeException, "Invalid method: %s", + name.size > 0 ? name.data : "<empty>"); + break; + } Object result = handler.fn(channel_id, args, &nested_error); if (ERROR_SET(&nested_error)) { // error handled after loop @@ -1747,6 +1753,14 @@ Dictionary nvim__stats(void) /// Gets a list of dictionaries representing attached UIs. /// /// @return Array of UI dictionaries +/// +/// Each dictionary has the following keys: +/// - "height" requested height of the UI +/// - "width" requested width of the UI +/// - "rgb" whether the UI uses rgb colors (false implies cterm colors) +/// - "ext_..." Requested UI extensions, see |ui-options| +/// - "chan" Channel id of remote UI (not present for TUI) +/// Array nvim_list_uis(void) FUNC_API_SINCE(4) { diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index af77a9891b..838f267dcd 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -575,7 +575,7 @@ void close_buffer(win_T *win, buf_T *buf, int action, int abort_if_last) /* Change directories when the 'acd' option is set. */ do_autochdir(); - // disable live updates for the current buffer + // disable buffer updates for the current buffer buf_updates_unregister_all(buf); /* diff --git a/src/nvim/buffer_updates.c b/src/nvim/buffer_updates.c index 4774b969c4..157f80e55a 100644 --- a/src/nvim/buffer_updates.c +++ b/src/nvim/buffer_updates.c @@ -1,3 +1,6 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check +// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com + #include "nvim/buffer_updates.h" #include "nvim/memline.h" #include "nvim/api/private/helpers.h" @@ -199,7 +202,7 @@ void buf_updates_send_changes(buf_T *buf, // change notifications are so frequent that many dead channels will be // cleared up quickly. if (badchannelid != 0) { - ELOG("Disabling live updates for dead channel %llu", badchannelid); + ELOG("Disabling buffer updates for dead channel %llu", badchannelid); buf_updates_unregister(buf, badchannelid); } } diff --git a/src/nvim/channel.c b/src/nvim/channel.c index 64d743891b..6ad64bbb85 100644 --- a/src/nvim/channel.c +++ b/src/nvim/channel.c @@ -602,6 +602,7 @@ static void on_channel_output(Stream *stream, Channel *chan, RBuffer *buf, // process_channel_event will modify the read buffer(convert NULs into NLs) if (chan->term) { terminal_receive(chan->term, ptr, count); + terminal_flush_output(chan->term); } rbuffer_consumed(buf, count); diff --git a/src/nvim/charset.c b/src/nvim/charset.c index 7d5f80c531..4f70bcc41a 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -1018,7 +1018,7 @@ int win_lbr_chartabsize(win_T *wp, char_u *line, char_u *s, colnr_T col, int *he // needs a break here if (wp->w_p_lbr && vim_isbreak(c) - && !vim_isbreak(s[1]) + && !vim_isbreak((int)s[1]) && wp->w_p_wrap && (wp->w_width != 0)) { // Count all characters from first non-blank after a blank up to next @@ -1042,7 +1042,7 @@ int win_lbr_chartabsize(win_T *wp, char_u *line, char_u *s, colnr_T col, int *he c = *s; if (!(c != NUL - && (vim_isbreak(c) || col2 == col || !vim_isbreak(*ps)))) { + && (vim_isbreak(c) || col2 == col || !vim_isbreak((int)(*ps))))) { break; } diff --git a/src/nvim/eval.c b/src/nvim/eval.c index ffea88aa83..9c29f18c0c 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -6742,36 +6742,39 @@ static void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv, char_u *tofree; if (opt_msg_tv->v_type != VAR_UNKNOWN) { - tofree = (char_u *) encode_tv2string(opt_msg_tv, NULL); + tofree = (char_u *)encode_tv2echo(opt_msg_tv, NULL); ga_concat(gap, tofree); xfree(tofree); + ga_concat(gap, (char_u *)": "); + } + + if (atype == ASSERT_MATCH || atype == ASSERT_NOTMATCH) { + ga_concat(gap, (char_u *)"Pattern "); + } else if (atype == ASSERT_NOTEQUAL) { + ga_concat(gap, (char_u *)"Expected not equal to "); } else { - if (atype == ASSERT_MATCH || atype == ASSERT_NOTMATCH) { - ga_concat(gap, (char_u *)"Pattern "); - } else if (atype == ASSERT_NOTEQUAL) { - ga_concat(gap, (char_u *)"Expected not equal to "); - } else { - ga_concat(gap, (char_u *)"Expected "); - } - if (exp_str == NULL) { - tofree = (char_u *)encode_tv2string(exp_tv, NULL); - ga_concat_esc(gap, tofree); - xfree(tofree); + ga_concat(gap, (char_u *)"Expected "); + } + + if (exp_str == NULL) { + tofree = (char_u *)encode_tv2string(exp_tv, NULL); + ga_concat_esc(gap, tofree); + xfree(tofree); + } else { + ga_concat_esc(gap, exp_str); + } + + if (atype != ASSERT_NOTEQUAL) { + if (atype == ASSERT_MATCH) { + ga_concat(gap, (char_u *)" does not match "); + } else if (atype == ASSERT_NOTMATCH) { + ga_concat(gap, (char_u *)" does match "); } else { - ga_concat_esc(gap, exp_str); - } - if (atype != ASSERT_NOTEQUAL) { - if (atype == ASSERT_MATCH) { - ga_concat(gap, (char_u *)" does not match "); - } else if (atype == ASSERT_NOTMATCH) { - ga_concat(gap, (char_u *)" does match "); - } else { - ga_concat(gap, (char_u *)" but got "); - } - tofree = (char_u *)encode_tv2string(got_tv, NULL); - ga_concat_esc(gap, tofree); - xfree(tofree); + ga_concat(gap, (char_u *)" but got "); } + tofree = (char_u *)encode_tv2string(got_tv, NULL); + ga_concat_esc(gap, tofree); + xfree(tofree); } } @@ -14806,18 +14809,14 @@ static void f_setpos(typval_T *argvars, typval_T *rettv, FunPtr fptr) pos.col = 0; } if (name[0] == '.' && name[1] == NUL) { - // set cursor - if (fnum == curbuf->b_fnum) { - curwin->w_cursor = pos; - if (curswant >= 0) { - curwin->w_curswant = curswant - 1; - curwin->w_set_curswant = false; - } - check_cursor(); - rettv->vval.v_number = 0; - } else { - EMSG(_(e_invarg)); + // set cursor; "fnum" is ignored + curwin->w_cursor = pos; + if (curswant >= 0) { + curwin->w_curswant = curswant - 1; + curwin->w_set_curswant = false; } + check_cursor(); + rettv->vval.v_number = 0; } else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL) { // set mark if (setmark_pos((uint8_t)name[1], &pos, fnum) == OK) { diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index ce02808ad3..c87e3d4c66 100644 --- a/src/nvim/ex_cmds.lua +++ b/src/nvim/ex_cmds.lua @@ -698,7 +698,7 @@ return { }, { command='delfunction', - flags=bit.bor(NEEDARG, WORD1, CMDWIN), + flags=bit.bor(BANG, NEEDARG, WORD1, CMDWIN), addr_type=ADDR_LINES, func='ex_delfunction', }, @@ -3082,7 +3082,7 @@ return { }, { command='windo', - flags=bit.bor(BANG, NEEDARG, EXTRA, NOTRLCOM, RANGE, NOTADR, DFLALL), + flags=bit.bor(NEEDARG, EXTRA, NOTRLCOM, RANGE, NOTADR, DFLALL), addr_type=ADDR_WINDOWS, func='ex_listdo', }, diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 52b810085c..e1efd5710d 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -8104,6 +8104,7 @@ static void ex_normal(exarg_T *eap) if (eap->addr_count != 0) { curwin->w_cursor.lnum = eap->line1++; curwin->w_cursor.col = 0; + check_cursor_moved(curwin); } exec_normal_cmd( diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 96388a2a9d..2c828be083 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -295,10 +295,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) redir_off = true; // don't redirect the typed command if (!cmd_silent) { - s->i = msg_scrolled; - msg_scrolled = 0; // avoid wait_return message gotocmdline(true); - msg_scrolled += s->i; redrawcmdprompt(); // draw prompt or indent set_cmdspos(); } @@ -349,7 +346,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent) // redraw the statusline for statuslines that display the current mode // using the mode() function. - if (KeyTyped) { + if (KeyTyped && msg_scrolled == 0) { curwin->w_redr_status = true; redraw_statuslines(); } @@ -629,6 +626,7 @@ static int command_line_execute(VimState *state, int key) // Entered command line, move it up cmdline_row--; redrawcmd(); + wild_menu_showing = 0; } else if (save_p_ls != -1) { // restore 'laststatus' and 'winminheight' p_ls = save_p_ls; @@ -639,12 +637,13 @@ static int command_line_execute(VimState *state, int key) restore_cmdline(&s->save_ccline); redrawcmd(); save_p_ls = -1; + wild_menu_showing = 0; } else { win_redraw_last_status(topframe); + wild_menu_showing = 0; // must be before redraw_statuslines #8385 redraw_statuslines(); } KeyTyped = skt; - wild_menu_showing = 0; if (ccline.input_fn) { RedrawingDisabled = old_RedrawingDisabled; } diff --git a/src/nvim/fold.c b/src/nvim/fold.c index b8ace511e8..52ed2fe3dc 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -2464,27 +2464,27 @@ static linenr_T foldUpdateIEMSRecurse(garray_T *gap, int level, flp->lnum - 1 - fp->fd_top); if (lvl < level) { - /* End of fold found, update the length when it got shorter. */ + // End of fold found, update the length when it got shorter. if (fp->fd_len != flp->lnum - fp->fd_top) { - if (fp->fd_top + fp->fd_len > bot + 1) { - /* fold continued below bot */ + if (fp->fd_top + fp->fd_len - 1 > bot) { + // fold continued below bot if (getlevel == foldlevelMarker || getlevel == foldlevelExpr || getlevel == foldlevelSyntax) { - /* marker method: truncate the fold and make sure the - * previously included lines are processed again */ + // marker method: truncate the fold and make sure the + // previously included lines are processed again bot = fp->fd_top + fp->fd_len - 1; fp->fd_len = flp->lnum - fp->fd_top; } else { - /* indent or expr method: split fold to create a new one - * below bot */ + // indent or expr method: split fold to create a new one + // below bot i = (int)(fp - (fold_T *)gap->ga_data); foldSplit(gap, i, flp->lnum, bot); fp = (fold_T *)gap->ga_data + i; } } else fp->fd_len = flp->lnum - fp->fd_top; - fold_changed = TRUE; + fold_changed = true; } } diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 4aa0ef7def..2860817f79 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -745,11 +745,9 @@ EXTERN int State INIT(= NORMAL); /* This is the current state of the EXTERN bool finish_op INIT(= false); // true while an operator is pending EXTERN long opcount INIT(= 0); // count for pending operator -/* - * ex mode (Q) state - */ -EXTERN int exmode_active INIT(= 0); /* zero, EXMODE_NORMAL or EXMODE_VIM */ -EXTERN int ex_no_reprint INIT(= FALSE); /* no need to print after z or p */ +// Ex Mode (Q) state +EXTERN int exmode_active INIT(= 0); // zero, EXMODE_NORMAL or EXMODE_VIM +EXTERN int ex_no_reprint INIT(= false); // no need to print after z or p EXTERN int Recording INIT(= FALSE); /* TRUE when recording into a reg. */ EXTERN int Exec_reg INIT(= FALSE); /* TRUE when executing a register */ diff --git a/src/nvim/mark.c b/src/nvim/mark.c index 3cd26a5bf7..bcd9cf2090 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -106,39 +106,41 @@ int setmark_pos(int c, pos_T *pos, int fnum) return OK; } + // Can't set a mark in a non-existant buffer. + buf_T *buf = buflist_findnr(fnum); + if (buf == NULL) { + return FAIL; + } + if (c == '"') { - RESET_FMARK(&curbuf->b_last_cursor, *pos, curbuf->b_fnum); + RESET_FMARK(&buf->b_last_cursor, *pos, buf->b_fnum); return OK; } /* Allow setting '[ and '] for an autocommand that simulates reading a * file. */ if (c == '[') { - curbuf->b_op_start = *pos; + buf->b_op_start = *pos; return OK; } if (c == ']') { - curbuf->b_op_end = *pos; + buf->b_op_end = *pos; return OK; } if (c == '<' || c == '>') { - if (c == '<') - curbuf->b_visual.vi_start = *pos; - else - curbuf->b_visual.vi_end = *pos; - if (curbuf->b_visual.vi_mode == NUL) - /* Visual_mode has not yet been set, use a sane default. */ - curbuf->b_visual.vi_mode = 'v'; + if (c == '<') { + buf->b_visual.vi_start = *pos; + } else { + buf->b_visual.vi_end = *pos; + } + if (buf->b_visual.vi_mode == NUL) { + // Visual_mode has not yet been set, use a sane default. + buf->b_visual.vi_mode = 'v'; + } return OK; } - buf_T *buf = buflist_findnr(fnum); - // Can't set a mark in a non-existant buffer. - if (buf == NULL) { - return FAIL; - } - if (ASCII_ISLOWER(c)) { i = c - 'a'; RESET_FMARK(buf->b_namedm + i, *pos, fnum); @@ -358,13 +360,14 @@ pos_T *getmark_buf_fnum(buf_T *buf, int c, int changefile, int *fnum) } else if (c == '<' || c == '>') { /* start/end of visual area */ startp = &buf->b_visual.vi_start; endp = &buf->b_visual.vi_end; - if ((c == '<') == lt(*startp, *endp)) + if (((c == '<') == lt(*startp, *endp) || endp->lnum == 0) + && startp->lnum != 0) { posp = startp; - else + } else { posp = endp; - /* - * For Visual line mode, set mark at begin or end of line - */ + } + + // For Visual line mode, set mark at begin or end of line if (buf->b_visual.vi_mode == 'V') { pos_copy = *posp; posp = &pos_copy; @@ -647,8 +650,8 @@ void do_marks(exarg_T *eap) show_one_mark(-1, arg, NULL, NULL, false); } -static void -show_one_mark ( +static void +show_one_mark( int c, char_u *arg, pos_T *p, diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index a52ab9f5d3..05e326104b 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -37,6 +37,8 @@ #ifdef HAVE_LOCALE_H # include <locale.h> #endif +#include "nvim/eval.h" +#include "nvim/path.h" #include "nvim/iconv.h" #include "nvim/mbyte.h" #include "nvim/charset.h" @@ -72,6 +74,9 @@ struct interval { # include "unicode_tables.generated.h" #endif +char_u e_loadlib[] = "E370: Could not load library %s"; +char_u e_loadfunc[] = "E448: Could not load library function %s"; + // To speed up BYTELEN(); keep a lookup table to quickly get the length in // bytes of a UTF-8 character from the first byte of a UTF-8 string. Bytes // which are illegal when used as the first byte have a 1. The NUL byte has @@ -2038,9 +2043,10 @@ void * my_iconv_open(char_u *to, char_u *from) return (void *)-1; /* detected a broken iconv() previously */ #ifdef DYNAMIC_ICONV - /* Check if the iconv.dll can be found. */ - if (!iconv_enabled(true)) + // Check if the iconv.dll can be found. + if (!iconv_enabled(true)) { return (void *)-1; + } #endif fd = iconv_open((char *)enc_skip(to), (char *)enc_skip(from)); @@ -2162,7 +2168,7 @@ static HINSTANCE hMsvcrtDLL = 0; # ifndef DYNAMIC_ICONV_DLL # define DYNAMIC_ICONV_DLL "iconv.dll" -# define DYNAMIC_ICONV_DLL_ALT "libiconv.dll" +# define DYNAMIC_ICONV_DLL_ALT "libiconv-2.dll" # endif # ifndef DYNAMIC_MSVCRT_DLL # define DYNAMIC_MSVCRT_DLL "msvcrt.dll" @@ -2208,6 +2214,35 @@ static void * get_iconv_import_func(HINSTANCE hInst, return NULL; } +// Load library "name". +HINSTANCE vimLoadLib(char *name) +{ + HINSTANCE dll = NULL; + + // NOTE: Do not use mch_dirname() and mch_chdir() here, they may call + // vimLoadLib() recursively, which causes a stack overflow. + WCHAR old_dirw[MAXPATHL]; + + // Path to exe dir. + char *buf = xstrdup((char *)get_vim_var_str(VV_PROGPATH)); + // ptrdiff_t len = ; + // assert(len > 0); + buf[path_tail_with_sep(buf) - buf] = '\0'; + + if (GetCurrentDirectoryW(MAXPATHL, old_dirw) != 0) { + // Change directory to where the executable is, both to make + // sure we find a .dll there and to avoid looking for a .dll + // in the current directory. + SetCurrentDirectory((LPCSTR)buf); + // TODO(justinmk): use uv_dlopen instead. see os_libcall + dll = LoadLibrary(name); + SetCurrentDirectoryW(old_dirw); + } + + return dll; +} + + /* * Try opening the iconv.dll and return TRUE if iconv() can be used. */ @@ -2255,10 +2290,13 @@ bool iconv_enabled(bool verbose) void iconv_end(void) { - if (hIconvDLL != 0) + if (hIconvDLL != 0) { + // TODO(justinmk): use uv_dlclose instead. FreeLibrary(hIconvDLL); - if (hMsvcrtDLL != 0) + } + if (hMsvcrtDLL != 0) { FreeLibrary(hMsvcrtDLL); + } hIconvDLL = 0; hMsvcrtDLL = 0; } diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c index 6c5c47b91f..70733e5564 100644 --- a/src/nvim/misc1.c +++ b/src/nvim/misc1.c @@ -107,7 +107,8 @@ open_line ( char_u *p; char_u saved_char = NUL; // init for GCC pos_T *pos; - bool do_si = (!p_paste && curbuf->b_p_si && !curbuf->b_p_cin); + bool do_si = (!p_paste && curbuf->b_p_si && !curbuf->b_p_cin + && *curbuf->b_p_inde == NUL); bool no_si = false; // reset did_si afterwards int first_char = NUL; // init for GCC int vreplace_mode; diff --git a/src/nvim/move.c b/src/nvim/move.c index cb13a9e207..41859a489f 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -132,11 +132,9 @@ void update_topline(void) bool check_botline = false; long save_so = p_so; - if (!screen_valid(true)) - return; - - // If the window height is zero, just use the cursor line. - if (curwin->w_height == 0) { + // If there is no valid screen and when the window height is zero just use + // the cursor line. + if (!screen_valid(true) || curwin->w_height == 0) { curwin->w_topline = curwin->w_cursor.lnum; curwin->w_botline = curwin->w_topline; curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP; @@ -1979,6 +1977,7 @@ void halfpage(bool flag, linenr_T Prenum) int n = curwin->w_p_scr <= curwin->w_height ? (int)curwin->w_p_scr : curwin->w_height; + update_topline(); validate_botline(); int room = curwin->w_empty_rows + curwin->w_filler_rows; if (flag) { diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index 26b84b7cc7..6d0c270a51 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -312,24 +312,30 @@ static void handle_request(Channel *channel, msgpack_object *request) api_clear_error(&error); return; } + // Retrieve the request handler MsgpackRpcRequestHandler handler; + Array args = ARRAY_DICT_INIT; msgpack_object *method = msgpack_rpc_method(request); if (method) { handler = msgpack_rpc_get_handler_for(method->via.bin.ptr, method->via.bin.size); + if (handler.fn == msgpack_rpc_handle_missing_method) { + String m = method->via.bin.size > 0 + ? cbuf_to_string(method->via.bin.ptr, method->via.bin.size) + : cstr_to_string("<empty>"); + ADD(args, STRING_OBJ(m)); + handler.async = true; + } else if (!msgpack_rpc_to_array(msgpack_rpc_args(request), &args)) { + handler.fn = msgpack_rpc_handle_invalid_arguments; + handler.async = true; + } } else { handler.fn = msgpack_rpc_handle_missing_method; handler.async = true; } - Array args = ARRAY_DICT_INIT; - if (!msgpack_rpc_to_array(msgpack_rpc_args(request), &args)) { - handler.fn = msgpack_rpc_handle_invalid_arguments; - handler.async = true; - } - RequestEvent *evdata = xmalloc(sizeof(RequestEvent)); evdata->channel = channel; evdata->handler = handler; diff --git a/src/nvim/msgpack_rpc/helpers.c b/src/nvim/msgpack_rpc/helpers.c index fecae11d45..e18c4472b5 100644 --- a/src/nvim/msgpack_rpc/helpers.c +++ b/src/nvim/msgpack_rpc/helpers.c @@ -493,7 +493,8 @@ Object msgpack_rpc_handle_missing_method(uint64_t channel_id, Array args, Error *error) { - api_set_error(error, kErrorTypeException, "Invalid method name"); + api_set_error(error, kErrorTypeException, "Invalid method: %s", + args.size > 0 ? args.items[0].data.string.data : "?"); return NIL; } diff --git a/src/nvim/option.c b/src/nvim/option.c index 88c458b597..26fc164c6c 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -939,11 +939,8 @@ void set_init_2(bool headless) { int idx; - /* - * 'scroll' defaults to half the window height. Note that this default is - * wrong when the window height changes. - */ - set_number_default("scroll", Rows / 2); + // 'scroll' defaults to half the window height. The stored default is zero, + // which results in the actual value computed from the window height. idx = findoption("scroll"); if (idx >= 0 && !(options[idx].flags & P_WAS_SET)) { set_option_default(idx, OPT_LOCAL, p_cp); diff --git a/src/nvim/options.lua b/src/nvim/options.lua index f1f559fff0..47c9f5aa78 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -1922,7 +1922,7 @@ return { no_mkrc=true, vi_def=true, pv_name='p_scroll', - defaults={if_true={vi=12}} + defaults={if_true={vi=0}} }, { full_name='scrollback', abbreviation='scbk', diff --git a/src/nvim/os/users.c b/src/nvim/os/users.c index 82bb918f70..7c48ac6e5e 100644 --- a/src/nvim/os/users.c +++ b/src/nvim/os/users.c @@ -76,7 +76,7 @@ char *os_get_user_directory(const char *name) { #if defined(HAVE_GETPWNAM) && defined(HAVE_PWD_H) struct passwd *pw; - if (name == NULL) { + if (name == NULL || *name == NUL) { return NULL; } pw = getpwnam(name); // NOLINT(runtime/threadsafe_fn) diff --git a/src/nvim/os/win_defs.h b/src/nvim/os/win_defs.h index db93f016bf..356094baa1 100644 --- a/src/nvim/os/win_defs.h +++ b/src/nvim/os/win_defs.h @@ -59,7 +59,6 @@ #define BACKSLASH_IN_FILENAME #ifdef _MSC_VER -typedef SSIZE_T ssize_t; typedef int mode_t; #endif diff --git a/src/nvim/path.c b/src/nvim/path.c index 4f3f7c0661..61cfaea84a 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -1097,17 +1097,18 @@ static bool has_env_var(char_u *p) } #ifdef SPECIAL_WILDCHAR -/* - * Return TRUE if "p" contains a special wildcard character. - * Allowing for escaping. - */ + +// Return TRUE if "p" contains a special wildcard character, one that Vim +// cannot expand, requires using a shell. static bool has_special_wildchar(char_u *p) { for (; *p; mb_ptr_adv(p)) { - if (*p == '\\' && p[1] != NUL) - ++p; - else if (vim_strchr((char_u *)SPECIAL_WILDCHAR, *p) != NULL) + // Allow for escaping + if (*p == '\\' && p[1] != NUL) { + p++; + } else if (vim_strchr((char_u *)SPECIAL_WILDCHAR, *p) != NULL) { return true; + } } return false; } @@ -2033,7 +2034,7 @@ int expand_wildcards(int num_pat, char_u **pat, int *num_files, char_u ***files, break; } if (match_file_list(p_wig, (*files)[i], ffname)) { - // remove this matching files from the list + // remove this matching file from the list xfree((*files)[i]); for (j = i; j + 1 < *num_files; j++) { (*files)[j] = (*files)[j + 1]; diff --git a/src/nvim/po/CMakeLists.txt b/src/nvim/po/CMakeLists.txt index 94cc63baea..a7b910f0eb 100644 --- a/src/nvim/po/CMakeLists.txt +++ b/src/nvim/po/CMakeLists.txt @@ -1,4 +1,4 @@ -find_package(Gettext) +find_package(Gettext REQUIRED) find_program(XGETTEXT_PRG xgettext) find_program(ICONV_PRG iconv) diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index e4de43b49e..c4af7d9e4a 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -479,6 +479,8 @@ static char_u *regprop(char_u *); #endif static char_u e_missingbracket[] = N_("E769: Missing ] after %s["); +static char_u e_reverse_range[] = N_("E944: Reverse range in character class"); +static char_u e_large_class[] = N_("E945: Range too large in character class"); static char_u e_unmatchedpp[] = N_("E53: Unmatched %s%%("); static char_u e_unmatchedp[] = N_("E54: Unmatched %s("); static char_u e_unmatchedpar[] = N_("E55: Unmatched %s)"); @@ -2232,15 +2234,18 @@ collection: if (endc == '\\' && !reg_cpo_lit) endc = coll_get_char(); - if (startc > endc) - EMSG_RET_NULL(_(e_invrange)); + if (startc > endc) { + EMSG_RET_NULL(_(e_reverse_range)); + } if (has_mbyte && ((*mb_char2len)(startc) > 1 || (*mb_char2len)(endc) > 1)) { - /* Limit to a range of 256 chars */ - if (endc > startc + 256) - EMSG_RET_NULL(_(e_invrange)); - while (++startc <= endc) + // Limit to a range of 256 chars + if (endc > startc + 256) { + EMSG_RET_NULL(_(e_large_class)); + } + while (++startc <= endc) { regmbc(startc); + } } else { while (++startc <= endc) regc(startc); @@ -2328,21 +2333,21 @@ collection: regc('\t'); break; case CLASS_CNTRL: - for (cu = 1; cu <= 255; cu++) { + for (cu = 1; cu <= 127; cu++) { if (iscntrl(cu)) { regmbc(cu); } } break; case CLASS_DIGIT: - for (cu = 1; cu <= 255; cu++) { + for (cu = 1; cu <= 127; cu++) { if (ascii_isdigit(cu)) { regmbc(cu); } } break; case CLASS_GRAPH: - for (cu = 1; cu <= 255; cu++) { + for (cu = 1; cu <= 127; cu++) { if (isgraph(cu)) { regmbc(cu); } diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c index 98fae858f6..334539b228 100644 --- a/src/nvim/regexp_nfa.c +++ b/src/nvim/regexp_nfa.c @@ -1711,8 +1711,9 @@ collection: if (emit_range) { endc = startc; startc = oldstartc; - if (startc > endc) - EMSG_RET_FAIL(_(e_invrange)); + if (startc > endc) { + EMSG_RET_FAIL(_(e_reverse_range)); + } if (endc > startc + 2) { /* Emit a range instead of the sequence of @@ -4358,16 +4359,18 @@ static int check_char_class(int class, int c) return OK; break; case NFA_CLASS_CNTRL: - if (c >= 1 && c <= 255 && iscntrl(c)) + if (c >= 1 && c <= 127 && iscntrl(c)) { return OK; + } break; case NFA_CLASS_DIGIT: if (ascii_isdigit(c)) return OK; break; case NFA_CLASS_GRAPH: - if (c >= 1 && c <= 255 && isgraph(c)) + if (c >= 1 && c <= 127 && isgraph(c)) { return OK; + } break; case NFA_CLASS_LOWER: if (mb_islower(c) && c != 170 && c != 186) { diff --git a/src/nvim/screen.c b/src/nvim/screen.c index f15afa619f..b0bf3a7d5f 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -3454,7 +3454,8 @@ win_line ( } // Found last space before word: check for line break. - if (wp->w_p_lbr && c0 == c && vim_isbreak(c) && !vim_isbreak(*ptr)) { + if (wp->w_p_lbr && c0 == c && vim_isbreak(c) + && !vim_isbreak((int)(*ptr))) { int mb_off = has_mbyte ? (*mb_head_off)(line, ptr - 1) : 0; char_u *p = ptr - (mb_off + 1); // TODO: is passing p for start of the line OK? @@ -4060,7 +4061,8 @@ win_line ( * Also highlight the 'colorcolumn' if it is different than * 'cursorcolumn' */ vcol_save_attr = -1; - if (draw_state == WL_LINE && !lnum_in_visual_area) { + if (draw_state == WL_LINE && !lnum_in_visual_area + && search_attr == 0 && area_attr == 0) { if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol && lnum != wp->w_cursor.lnum) { vcol_save_attr = char_attr; diff --git a/src/nvim/search.c b/src/nvim/search.c index 84782497a0..14a7d41300 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -130,8 +130,8 @@ typedef struct SearchedFile { * * returns FAIL if failed, OK otherwise. */ -int -search_regcomp ( +int +search_regcomp( char_u *pat, int pat_save, int pat_use, @@ -2121,9 +2121,9 @@ static int check_linecomment(char_u *line) * Show the match only if it is visible on the screen. * If there isn't a match, then beep. */ -void -showmatch ( - int c /* char to show match for */ +void +showmatch( + int c // char to show match for ) { pos_T *lpos, save_cursor; @@ -2377,8 +2377,14 @@ findpar ( ++curr; curwin->w_cursor.lnum = curr; if (curr == curbuf->b_ml.ml_line_count && what != '}') { - if ((curwin->w_cursor.col = (colnr_T)STRLEN(ml_get(curr))) != 0) { - --curwin->w_cursor.col; + char_u *line = ml_get(curr); + + // Put the cursor on the last character in the last line and make the + // motion inclusive. + if ((curwin->w_cursor.col = (colnr_T)STRLEN(line)) != 0) { + curwin->w_cursor.col--; + curwin->w_cursor.col -= + (*mb_head_off)(line, line + curwin->w_cursor.col); *pincl = true; } } else @@ -2483,8 +2489,8 @@ static int cls(void) * Returns FAIL if the cursor was already at the end of the file. * If eol is TRUE, last word stops at end of line (for operators). */ -int -fwd_word ( +int +fwd_word( long count, int bigword, /* "W", "E" or "B" */ int eol @@ -2666,8 +2672,8 @@ finished: * * Returns FAIL if start of the file was reached. */ -int -bckend_word ( +int +bckend_word( long count, int bigword, /* TRUE for "B" */ int eol /* TRUE: stop at end of line. */ @@ -2756,8 +2762,8 @@ static void find_first_blank(pos_T *posp) /* * Skip count/2 sentences and count/2 separating white spaces. */ -static void -findsent_forward ( +static void +findsent_forward( long count, int at_start_sent /* cursor is at start of sentence */ ) @@ -2776,8 +2782,8 @@ findsent_forward ( * Find word under cursor, cursor at end. * Used while an operator is pending, and in Visual mode. */ -int -current_word ( +int +current_word( oparg_T *oap, long count, int include, /* TRUE: include word and white space */ @@ -3084,8 +3090,8 @@ extend: * Find block under the cursor, cursor at end. * "what" and "other" are two matching parenthesis/brace/etc. */ -int -current_block ( +int +current_block( oparg_T *oap, long count, int include, /* TRUE == include white space */ @@ -3282,8 +3288,8 @@ static int in_html_tag(int end_tag) /* * Find tag block under the cursor, cursor at end. */ -int -current_tagblock ( +int +current_tagblock( oparg_T *oap, long count_arg, int include /* TRUE == include white space */ @@ -3465,8 +3471,8 @@ theend: return retval; } -int -current_par ( +int +current_par( oparg_T *oap, long count, int include, /* TRUE == include white space */ @@ -3632,8 +3638,8 @@ extend: * as a quote. * Returns column number of "quotechar" or -1 when not found. */ -static int -find_next_quote ( +static int +find_next_quote( char_u *line, int col, int quotechar, @@ -3664,8 +3670,8 @@ find_next_quote ( * as a quote. * Return the found column or zero. */ -static int -find_prev_quote ( +static int +find_prev_quote( char_u *line, int col_start, int quotechar, @@ -3694,8 +3700,8 @@ find_prev_quote ( * Find quote under the cursor, cursor at end. * Returns TRUE if found, else FALSE. */ -int -current_quote ( +int +current_quote( oparg_T *oap, long count, int include, /* TRUE == include quote char */ @@ -3920,8 +3926,8 @@ current_quote ( * Find next search match under cursor, cursor at end. * Used while an operator is pending, and in Visual mode. */ -int -current_search ( +int +current_search( long count, int forward /* move forward or backwards */ ) @@ -4116,19 +4122,19 @@ int linewhite(linenr_T lnum) * Find identifiers or defines in included files. * If p_ic && (compl_cont_status & CONT_SOL) then ptr must be in lowercase. */ -void -find_pattern_in_path ( - char_u *ptr, /* pointer to search pattern */ - int dir, /* direction of expansion */ - size_t len, /* length of search pattern */ - int whole, /* match whole words only */ - int skip_comments, /* don't match inside comments */ - int type, /* Type of search; are we looking for a type? - a macro? */ +void +find_pattern_in_path( + char_u *ptr, // pointer to search pattern + int dir, // direction of expansion + size_t len, // length of search pattern + int whole, // match whole words only + int skip_comments, // don't match inside comments + int type, // Type of search; are we looking for a type? + // a macro? long count, - int action, /* What to do when we find it */ - linenr_T start_lnum, /* first line to start searching */ - linenr_T end_lnum /* last line for searching */ + int action, // What to do when we find it + linenr_T start_lnum, // first line to start searching + linenr_T end_lnum // last line for searching ) { SearchedFile *files; /* Stack of included files */ diff --git a/src/nvim/tag.c b/src/nvim/tag.c index ba2727f0d7..d7bdf97c48 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -2404,11 +2404,14 @@ jumpto_tag ( } } - /* If it was a CTRL-W CTRL-] command split window now. For ":tab tag" - * open a new tab page. */ + // If it was a CTRL-W CTRL-] command split window now. For ":tab tag" + // open a new tab page. if (postponed_split || cmdmod.tab != 0) { - (void)win_split(postponed_split > 0 ? postponed_split : 0, - postponed_split_flags); + if (win_split(postponed_split > 0 ? postponed_split : 0, + postponed_split_flags) == FAIL) { + RedrawingDisabled--; + goto erret; + } RESET_BINDING(curwin); } diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index c29f0b3927..c2370de0f8 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -528,6 +528,13 @@ void terminal_send(Terminal *term, char *data, size_t size) term->opts.write_cb(data, size, term->opts.data); } +void terminal_flush_output(Terminal *term) +{ + size_t len = vterm_output_read(term->vt, term->textbuf, + sizeof(term->textbuf)); + terminal_send(term, term->textbuf, len); +} + void terminal_send_key(Terminal *term, int c) { VTermModifier mod = VTERM_MOD_NONE; @@ -545,9 +552,7 @@ void terminal_send_key(Terminal *term, int c) vterm_keyboard_unichar(term->vt, (uint32_t)c, mod); } - size_t len = vterm_output_read(term->vt, term->textbuf, - sizeof(term->textbuf)); - terminal_send(term, term->textbuf, (size_t)len); + terminal_flush_output(term); } void terminal_receive(Terminal *term, char *data, size_t len) @@ -982,7 +987,7 @@ static bool send_mouse_event(Terminal *term, int c) mouse_action(term, button, row, col, drag, 0); size_t len = vterm_output_read(term->vt, term->textbuf, - sizeof(term->textbuf)); + sizeof(term->textbuf)); terminal_send(term, term->textbuf, (size_t)len); return false; } @@ -1234,8 +1239,9 @@ static void refresh_screen(Terminal *term, buf_T *buf) int change_start = row_to_linenr(term, term->invalid_start); int change_end = change_start + changed; - // Note: don't send nvim_buf_lines_event event for a :terminal buffer - changed_lines(change_start, 0, change_end, added, false); + changed_lines(change_start, 0, change_end, added, + // Don't send nvim_buf_lines_event for :terminal buffer. + false); term->invalid_start = INT_MAX; term->invalid_end = -1; } diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile index c1ede08c31..a161f14bc8 100644 --- a/src/nvim/testdir/Makefile +++ b/src/nvim/testdir/Makefile @@ -88,6 +88,8 @@ NEW_TESTS ?= \ test_options.res \ test_profile.res \ test_put.res \ + test_python2.res \ + test_python3.res \ test_quickfix.res \ test_quotestar.res \ test_recover.res \ diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim index b4baf7a8d7..c4b4a43ad4 100644 --- a/src/nvim/testdir/test_alot.vim +++ b/src/nvim/testdir/test_alot.vim @@ -27,6 +27,7 @@ source test_popup.vim source test_put.vim source test_recover.vim source test_regexp_utf8.vim +source test_scroll_opt.vim source test_source_utf8.vim source test_sha256.vim source test_statusline.vim diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim index be68e9ff9d..8139f00f0e 100644 --- a/src/nvim/testdir/test_cmdline.vim +++ b/src/nvim/testdir/test_cmdline.vim @@ -64,6 +64,10 @@ func Test_highlight_completion() hi Aardig ctermfg=green call feedkeys(":hi \<Tab>\<Home>\"\<CR>", 'xt') call assert_equal('"hi Aardig', getreg(':')) + call feedkeys(":hi default \<Tab>\<Home>\"\<CR>", 'xt') + call assert_equal('"hi default Aardig', getreg(':')) + call feedkeys(":hi clear Aa\<Tab>\<Home>\"\<CR>", 'xt') + call assert_equal('"hi clear Aardig', getreg(':')) call feedkeys(":hi li\<S-Tab>\<Home>\"\<CR>", 'xt') call assert_equal('"hi link', getreg(':')) call feedkeys(":hi d\<S-Tab>\<Home>\"\<CR>", 'xt') diff --git a/src/nvim/testdir/test_fold.vim b/src/nvim/testdir/test_fold.vim index 7c6d38d7ec..0c2ec08af3 100644 --- a/src/nvim/testdir/test_fold.vim +++ b/src/nvim/testdir/test_fold.vim @@ -9,8 +9,8 @@ func! Test_address_fold() call setline(1, ['int FuncName() {/*{{{*/', 1, 2, 3, 4, 5, '}/*}}}*/', \ 'after fold 1', 'after fold 2', 'after fold 3']) setl fen fdm=marker - " The next ccommands should all copy the same part of the buffer, - " regardless of the adressing type, since the part to be copied + " The next commands should all copy the same part of the buffer, + " regardless of the addressing type, since the part to be copied " is folded away :1y call assert_equal(['int FuncName() {/*{{{*/', '1', '2', '3', '4', '5', '}/*}}}*/'], getreg(0,1,1)) @@ -381,3 +381,56 @@ func Test_foldopen_exception() endtry call assert_match('E492:', a) endfunc + +func Test_folddoopen_folddoclosed() + new + call setline(1, range(1, 9)) + set foldmethod=manual + 1,3 fold + 6,8 fold + + " Test without range. + folddoopen s/$/o/ + folddoclosed s/$/c/ + call assert_equal(['1c', '2c', '3c', + \ '4o', '5o', + \ '6c', '7c', '8c', + \ '9o'], getline(1, '$')) + + " Test with range. + call setline(1, range(1, 9)) + 1,8 folddoopen s/$/o/ + 4,$ folddoclosed s/$/c/ + call assert_equal(['1', '2', '3', + \ '4o', '5o', + \ '6c', '7c', '8c', + \ '9'], getline(1, '$')) + + set foldmethod& + bw! +endfunc + +func Test_fold_error() + new + call setline(1, [1, 2]) + + for fm in ['indent', 'expr', 'syntax', 'diff'] + exe 'set foldmethod=' . fm + call assert_fails('norm zf', 'E350:') + call assert_fails('norm zd', 'E351:') + call assert_fails('norm zE', 'E352:') + endfor + + set foldmethod=manual + call assert_fails('norm zd', 'E490:') + call assert_fails('norm zo', 'E490:') + call assert_fails('3fold', 'E16:') + + set foldmethod=marker + set nomodifiable + call assert_fails('1,2fold', 'E21:') + + set modifiable& + set foldmethod& + bw! +endfunc diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim index 398e9ab331..8a82493ab6 100644 --- a/src/nvim/testdir/test_functions.vim +++ b/src/nvim/testdir/test_functions.vim @@ -1,5 +1,101 @@ " Tests for various functions. +" Must be done first, since the alternate buffer must be unset. +func Test_00_bufexists() + call assert_equal(0, bufexists('does_not_exist')) + call assert_equal(1, bufexists(bufnr('%'))) + call assert_equal(0, bufexists(0)) + new Xfoo + let bn = bufnr('%') + call assert_equal(1, bufexists(bn)) + call assert_equal(1, bufexists('Xfoo')) + call assert_equal(1, bufexists(getcwd() . '/Xfoo')) + call assert_equal(1, bufexists(0)) + bw + call assert_equal(0, bufexists(bn)) + call assert_equal(0, bufexists('Xfoo')) +endfunc + +func Test_empty() + call assert_equal(1, empty('')) + call assert_equal(0, empty('a')) + + call assert_equal(1, empty(0)) + call assert_equal(1, empty(-0)) + call assert_equal(0, empty(1)) + call assert_equal(0, empty(-1)) + + call assert_equal(1, empty(0.0)) + call assert_equal(1, empty(-0.0)) + call assert_equal(0, empty(1.0)) + call assert_equal(0, empty(-1.0)) + call assert_equal(0, empty(1.0/0.0)) + call assert_equal(0, empty(0.0/0.0)) + + call assert_equal(1, empty([])) + call assert_equal(0, empty(['a'])) + + call assert_equal(1, empty({})) + call assert_equal(0, empty({'a':1})) + + call assert_equal(1, empty(v:null)) + " call assert_equal(1, empty(v:none)) + call assert_equal(1, empty(v:false)) + call assert_equal(0, empty(v:true)) + + if has('channel') + call assert_equal(1, empty(test_null_channel())) + endif + if has('job') + call assert_equal(1, empty(test_null_job())) + endif + + call assert_equal(0, empty(function('Test_empty'))) +endfunc + +func Test_len() + call assert_equal(1, len(0)) + call assert_equal(2, len(12)) + + call assert_equal(0, len('')) + call assert_equal(2, len('ab')) + + call assert_equal(0, len([])) + call assert_equal(2, len([2, 1])) + + call assert_equal(0, len({})) + call assert_equal(2, len({'a': 1, 'b': 2})) + + " call assert_fails('call len(v:none)', 'E701:') + call assert_fails('call len({-> 0})', 'E701:') +endfunc + +func Test_max() + call assert_equal(0, max([])) + call assert_equal(2, max([2])) + call assert_equal(2, max([1, 2])) + call assert_equal(2, max([1, 2, v:null])) + + call assert_equal(0, max({})) + call assert_equal(2, max({'a':1, 'b':2})) + + call assert_fails('call max(1)', 'E712:') + " call assert_fails('call max(v:none)', 'E712:') +endfunc + +func Test_min() + call assert_equal(0, min([])) + call assert_equal(2, min([2])) + call assert_equal(1, min([1, 2])) + call assert_equal(0, min([1, 2, v:null])) + + call assert_equal(0, min({})) + call assert_equal(1, min({'a':1, 'b':2})) + + call assert_fails('call min(1)', 'E712:') + " call assert_fails('call min(v:none)', 'E712:') +endfunc + func Test_str2nr() call assert_equal(0, str2nr('')) call assert_equal(1, str2nr('1')) @@ -15,6 +111,77 @@ func Test_str2nr() call assert_equal(123456789, str2nr('123456789')) call assert_equal(-123456789, str2nr('-123456789')) + + call assert_equal(5, str2nr('101', 2)) + call assert_equal(5, str2nr('0b101', 2)) + call assert_equal(5, str2nr('0B101', 2)) + call assert_equal(-5, str2nr('-101', 2)) + call assert_equal(-5, str2nr('-0b101', 2)) + call assert_equal(-5, str2nr('-0B101', 2)) + + call assert_equal(65, str2nr('101', 8)) + call assert_equal(65, str2nr('0101', 8)) + call assert_equal(-65, str2nr('-101', 8)) + call assert_equal(-65, str2nr('-0101', 8)) + + call assert_equal(11259375, str2nr('abcdef', 16)) + call assert_equal(11259375, str2nr('ABCDEF', 16)) + call assert_equal(-11259375, str2nr('-ABCDEF', 16)) + call assert_equal(11259375, str2nr('0xabcdef', 16)) + call assert_equal(11259375, str2nr('0Xabcdef', 16)) + call assert_equal(11259375, str2nr('0XABCDEF', 16)) + call assert_equal(-11259375, str2nr('-0xABCDEF', 16)) + + call assert_equal(0, str2nr('0x10')) + call assert_equal(0, str2nr('0b10')) + call assert_equal(1, str2nr('12', 2)) + call assert_equal(1, str2nr('18', 8)) + call assert_equal(1, str2nr('1g', 16)) + + call assert_equal(0, str2nr(v:null)) + " call assert_equal(0, str2nr(v:none)) + + call assert_fails('call str2nr([])', 'E730:') + call assert_fails('call str2nr({->2})', 'E729:') + call assert_fails('call str2nr(1.2)', 'E806:') + call assert_fails('call str2nr(10, [])', 'E474:') +endfunc + +func Test_strftime() + if !exists('*strftime') + return + endif + " Format of strftime() depends on system. We assume + " that basic formats tested here are available and + " identical on all systems which support strftime(). + " + " The 2nd parameter of strftime() is a local time, so the output day + " of strftime() can be 17 or 18, depending on timezone. + call assert_match('^2017-01-1[78]$', strftime('%Y-%m-%d', 1484695512)) + " + call assert_match('^\d\d\d\d-\(0\d\|1[012]\)-\([012]\d\|3[01]\) \([01]\d\|2[0-3]\):[0-5]\d:\([0-5]\d\|60\)$', strftime('%Y-%m-%d %H:%M:%S')) + + call assert_fails('call strftime([])', 'E730:') + call assert_fails('call strftime("%Y", [])', 'E745:') +endfunc + +func Test_simplify() + call assert_equal('', simplify('')) + call assert_equal('/', simplify('/')) + call assert_equal('/', simplify('/.')) + call assert_equal('/', simplify('/..')) + call assert_equal('/...', simplify('/...')) + call assert_equal('./dir/file', simplify('./dir/file')) + call assert_equal('./dir/file', simplify('.///dir//file')) + call assert_equal('./dir/file', simplify('./dir/./file')) + call assert_equal('./file', simplify('./dir/../file')) + call assert_equal('../dir/file', simplify('dir/../../dir/file')) + call assert_equal('./file', simplify('dir/.././file')) + + call assert_fails('call simplify({->0})', 'E729:') + call assert_fails('call simplify([])', 'E730:') + call assert_fails('call simplify({})', 'E731:') + call assert_fails('call simplify(1.2)', 'E806:') endfunc func Test_setbufvar_options() @@ -48,6 +215,19 @@ func Test_setbufvar_options() bwipe! endfunc +func Test_strpart() + call assert_equal('de', strpart('abcdefg', 3, 2)) + call assert_equal('ab', strpart('abcdefg', -2, 4)) + call assert_equal('abcdefg', strpart('abcdefg', -2)) + call assert_equal('fg', strpart('abcdefg', 5, 4)) + call assert_equal('defg', strpart('abcdefg', 3)) + + if has('multi_byte') + call assert_equal('lép', strpart('éléphant', 2, 4)) + call assert_equal('léphant', strpart('éléphant', 2)) + endif +endfunc + func Test_tolower() call assert_equal("", tolower("")) @@ -188,7 +368,7 @@ func Test_toupper() call assert_equal("YÝŶŸẎỲỶỸ", toupper("YÝŶŸẎỲỶỸ")) call assert_equal("ZŹŻŽƵẐẔ", toupper("ZŹŻŽƵẐẔ")) - call assert_equal("ⱥ ⱦ", tolower("Ⱥ Ⱦ")) + call assert_equal("Ⱥ Ⱦ", toupper("ⱥ ⱦ")) endfunc " Tests for the mode() function @@ -353,3 +533,236 @@ func Test_getbufvar() set fileformats& endfunc + +func Test_last_buffer_nr() + call assert_equal(bufnr('$'), last_buffer_nr()) +endfunc + +func Test_stridx() + call assert_equal(-1, stridx('', 'l')) + call assert_equal(0, stridx('', '')) + call assert_equal(0, stridx('hello', '')) + call assert_equal(-1, stridx('hello', 'L')) + call assert_equal(2, stridx('hello', 'l', -1)) + call assert_equal(2, stridx('hello', 'l', 0)) + call assert_equal(2, stridx('hello', 'l', 1)) + call assert_equal(3, stridx('hello', 'l', 3)) + call assert_equal(-1, stridx('hello', 'l', 4)) + call assert_equal(-1, stridx('hello', 'l', 10)) + call assert_equal(2, stridx('hello', 'll')) + call assert_equal(-1, stridx('hello', 'hello world')) +endfunc + +func Test_strridx() + call assert_equal(-1, strridx('', 'l')) + call assert_equal(0, strridx('', '')) + call assert_equal(5, strridx('hello', '')) + call assert_equal(-1, strridx('hello', 'L')) + call assert_equal(3, strridx('hello', 'l')) + call assert_equal(3, strridx('hello', 'l', 10)) + call assert_equal(3, strridx('hello', 'l', 3)) + call assert_equal(2, strridx('hello', 'l', 2)) + call assert_equal(-1, strridx('hello', 'l', 1)) + call assert_equal(-1, strridx('hello', 'l', 0)) + call assert_equal(-1, strridx('hello', 'l', -1)) + call assert_equal(2, strridx('hello', 'll')) + call assert_equal(-1, strridx('hello', 'hello world')) +endfunc + +func Test_matchend() + call assert_equal(7, matchend('testing', 'ing')) + call assert_equal(7, matchend('testing', 'ing', 2)) + call assert_equal(-1, matchend('testing', 'ing', 5)) +endfunc + +func Test_nextnonblank_prevnonblank() + new +insert +This + + +is + +a +Test +. + call assert_equal(0, nextnonblank(-1)) + call assert_equal(0, nextnonblank(0)) + call assert_equal(1, nextnonblank(1)) + call assert_equal(4, nextnonblank(2)) + call assert_equal(4, nextnonblank(3)) + call assert_equal(4, nextnonblank(4)) + call assert_equal(6, nextnonblank(5)) + call assert_equal(6, nextnonblank(6)) + call assert_equal(7, nextnonblank(7)) + call assert_equal(0, nextnonblank(8)) + + call assert_equal(0, prevnonblank(-1)) + call assert_equal(0, prevnonblank(0)) + call assert_equal(1, prevnonblank(1)) + call assert_equal(1, prevnonblank(2)) + call assert_equal(1, prevnonblank(3)) + call assert_equal(4, prevnonblank(4)) + call assert_equal(4, prevnonblank(5)) + call assert_equal(6, prevnonblank(6)) + call assert_equal(7, prevnonblank(7)) + call assert_equal(0, prevnonblank(8)) + bw! +endfunc + +func Test_byte2line_line2byte() + new + call setline(1, ['a', 'bc', 'd']) + + set fileformat=unix + call assert_equal([-1, -1, 1, 1, 2, 2, 2, 3, 3, -1], + \ map(range(-1, 8), 'byte2line(v:val)')) + call assert_equal([-1, -1, 1, 3, 6, 8, -1], + \ map(range(-1, 5), 'line2byte(v:val)')) + + set fileformat=mac + call assert_equal([-1, -1, 1, 1, 2, 2, 2, 3, 3, -1], + \ map(range(-1, 8), 'byte2line(v:val)')) + call assert_equal([-1, -1, 1, 3, 6, 8, -1], + \ map(range(-1, 5), 'line2byte(v:val)')) + + set fileformat=dos + call assert_equal([-1, -1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, -1], + \ map(range(-1, 11), 'byte2line(v:val)')) + call assert_equal([-1, -1, 1, 4, 8, 11, -1], + \ map(range(-1, 5), 'line2byte(v:val)')) + + set fileformat& + bw! +endfunc + +func Test_count() + let l = ['a', 'a', 'A', 'b'] + call assert_equal(2, count(l, 'a')) + call assert_equal(1, count(l, 'A')) + call assert_equal(1, count(l, 'b')) + call assert_equal(0, count(l, 'B')) + + call assert_equal(2, count(l, 'a', 0)) + call assert_equal(1, count(l, 'A', 0)) + call assert_equal(1, count(l, 'b', 0)) + call assert_equal(0, count(l, 'B', 0)) + + call assert_equal(3, count(l, 'a', 1)) + call assert_equal(3, count(l, 'A', 1)) + call assert_equal(1, count(l, 'b', 1)) + call assert_equal(1, count(l, 'B', 1)) + call assert_equal(0, count(l, 'c', 1)) + + call assert_equal(1, count(l, 'a', 0, 1)) + call assert_equal(2, count(l, 'a', 1, 1)) + call assert_fails('call count(l, "a", 0, 10)', 'E684:') + + let d = {1: 'a', 2: 'a', 3: 'A', 4: 'b'} + call assert_equal(2, count(d, 'a')) + call assert_equal(1, count(d, 'A')) + call assert_equal(1, count(d, 'b')) + call assert_equal(0, count(d, 'B')) + + call assert_equal(2, count(d, 'a', 0)) + call assert_equal(1, count(d, 'A', 0)) + call assert_equal(1, count(d, 'b', 0)) + call assert_equal(0, count(d, 'B', 0)) + + call assert_equal(3, count(d, 'a', 1)) + call assert_equal(3, count(d, 'A', 1)) + call assert_equal(1, count(d, 'b', 1)) + call assert_equal(1, count(d, 'B', 1)) + call assert_equal(0, count(d, 'c', 1)) + + call assert_fails('call count(d, "a", 0, 1)', 'E474:') + call assert_fails('call count("a", "a")', 'E712:') +endfunc + +func Test_changenr() + new Xchangenr + call assert_equal(0, changenr()) + norm ifoo + call assert_equal(1, changenr()) + set undolevels=10 + norm Sbar + call assert_equal(2, changenr()) + undo + call assert_equal(1, changenr()) + redo + call assert_equal(2, changenr()) + bw! + set undolevels& +endfunc + +func Test_filewritable() + new Xfilewritable + write! + call assert_equal(1, filewritable('Xfilewritable')) + + call assert_notequal(0, setfperm('Xfilewritable', 'r--r-----')) + call assert_equal(0, filewritable('Xfilewritable')) + + call assert_notequal(0, setfperm('Xfilewritable', 'rw-r-----')) + call assert_equal(1, filewritable('Xfilewritable')) + + call assert_equal(0, filewritable('doesnotexist')) + + call delete('Xfilewritable') + bw! +endfunc + +func Test_hostname() + let hostname_vim = hostname() + if has('unix') + let hostname_system = systemlist('uname -n')[0] + call assert_equal(hostname_vim, hostname_system) + endif +endfunc + +func Test_getpid() + " getpid() always returns the same value within a vim instance. + call assert_equal(getpid(), getpid()) + if has('unix') + call assert_equal(systemlist('echo $PPID')[0], string(getpid())) + endif +endfunc + +func Test_hlexists() + call assert_equal(0, hlexists('does_not_exist')) + " call assert_equal(0, hlexists('Number')) + call assert_equal(0, highlight_exists('does_not_exist')) + " call assert_equal(0, highlight_exists('Number')) + syntax on + call assert_equal(0, hlexists('does_not_exist')) + " call assert_equal(1, hlexists('Number')) + call assert_equal(0, highlight_exists('does_not_exist')) + " call assert_equal(1, highlight_exists('Number')) + syntax off +endfunc + +func Test_col() + new + call setline(1, 'abcdef') + norm gg4|mx6|mY2| + call assert_equal(2, col('.')) + call assert_equal(7, col('$')) + call assert_equal(4, col("'x")) + call assert_equal(6, col("'Y")) + call assert_equal(2, col([1, 2])) + call assert_equal(7, col([1, '$'])) + + call assert_equal(0, col('')) + call assert_equal(0, col('x')) + call assert_equal(0, col([2, '$'])) + call assert_equal(0, col([1, 100])) + call assert_equal(0, col([1])) + bw! +endfunc + +func Test_balloon_show() + if has('balloon_eval') + " This won't do anything but must not crash either. + call balloon_show('hi!') + endif +endfunc diff --git a/src/nvim/testdir/test_listlbr_utf8.vim b/src/nvim/testdir/test_listlbr_utf8.vim index 56a4cc9b31..b648a3361b 100644 --- a/src/nvim/testdir/test_listlbr_utf8.vim +++ b/src/nvim/testdir/test_listlbr_utf8.vim @@ -194,6 +194,21 @@ func Test_multibyte_sign_and_colorcolumn() call s:close_windows() endfunc +func Test_colorcolumn_priority() + call s:test_windows('setl cc=4 cuc hls') + call setline(1, ["xxyy", ""]) + norm! gg + exe "normal! /xxyy\<CR>" + norm! G + redraw! + let line_attr = s:screen_attr(1, [1, &cc]) + " Search wins over CursorColumn + call assert_equal(line_attr[1], line_attr[0]) + " Search wins over Colorcolumn + call assert_equal(line_attr[2], line_attr[3]) + call s:close_windows('setl hls&vim') +endfunc + func Test_illegal_byte_and_breakat() call s:test_windows("setl sbr= brk+=<") vert resize 18 diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim index f5e4c4b90c..0a198763bb 100644 --- a/src/nvim/testdir/test_mapping.vim +++ b/src/nvim/testdir/test_mapping.vim @@ -160,3 +160,30 @@ func Test_map_meta_quotes() set nomodified iunmap <M-"> endfunc + +func Test_map_timeout() + nnoremap aaaa :let got_aaaa = 1<CR> + nnoremap bb :let got_bb = 1<CR> + nmap b aaa + new + func ExitInsert(timer) + let g:line = getline(1) + call feedkeys("\<Esc>", "t") + endfunc + set timeout timeoutlen=200 + call timer_start(300, 'ExitInsert') + " After the 'b' Vim waits for another character to see if it matches 'bb'. + " When it times out it is expanded to "aaa", but there is no wait for + " "aaaa". Can't check that reliably though. + call feedkeys("b", "xt!") + call assert_equal("aa", g:line) + call assert_false(exists('got_aaa')) + call assert_false(exists('got_bb')) + + bwipe! + nunmap aaaa + nunmap bb + nunmap b + set timeoutlen& + delfunc ExitInsert +endfunc diff --git a/src/nvim/testdir/test_marks.vim b/src/nvim/testdir/test_marks.vim index d00b1ddc88..18a0c71aab 100644 --- a/src/nvim/testdir/test_marks.vim +++ b/src/nvim/testdir/test_marks.vim @@ -24,3 +24,47 @@ function! Test_Incr_Marks() call assert_equal("XXX 123 123", getline(3)) enew! endfunction + +func Test_setpos() + new one + let onebuf = bufnr('%') + let onewin = win_getid() + call setline(1, ['aaa', 'bbb', 'ccc']) + new two + let twobuf = bufnr('%') + let twowin = win_getid() + call setline(1, ['aaa', 'bbb', 'ccc']) + + " for the cursor the buffer number is ignored + call setpos(".", [0, 2, 1, 0]) + call assert_equal([0, 2, 1, 0], getpos(".")) + call setpos(".", [onebuf, 3, 3, 0]) + call assert_equal([0, 3, 3, 0], getpos(".")) + + call setpos("''", [0, 1, 3, 0]) + call assert_equal([0, 1, 3, 0], getpos("''")) + call setpos("''", [onebuf, 2, 2, 0]) + call assert_equal([0, 2, 2, 0], getpos("''")) + + " buffer-local marks + for mark in ["'a", "'\"", "'[", "']", "'<", "'>"] + call win_gotoid(twowin) + call setpos(mark, [0, 2, 1, 0]) + call assert_equal([0, 2, 1, 0], getpos(mark), "for mark " . mark) + call setpos(mark, [onebuf, 1, 3, 0]) + call win_gotoid(onewin) + call assert_equal([0, 1, 3, 0], getpos(mark), "for mark " . mark) + endfor + + " global marks + call win_gotoid(twowin) + call setpos("'N", [0, 2, 1, 0]) + call assert_equal([twobuf, 2, 1, 0], getpos("'N")) + call setpos("'N", [onebuf, 1, 3, 0]) + call assert_equal([onebuf, 1, 3, 0], getpos("'N")) + + call win_gotoid(onewin) + bwipe! + call win_gotoid(twowin) + bwipe! +endfunc diff --git a/src/nvim/testdir/test_normal.vim b/src/nvim/testdir/test_normal.vim index 1d15c7f83d..27ac084ef0 100644 --- a/src/nvim/testdir/test_normal.vim +++ b/src/nvim/testdir/test_normal.vim @@ -2314,28 +2314,36 @@ func! Test_normal53_digraph() bw! endfunc -func! Test_normal54_Ctrl_bsl() - new - call setline(1, 'abcdefghijklmn') - exe "norm! df\<c-\>\<c-n>" - call assert_equal(['abcdefghijklmn'], getline(1,'$')) - exe "norm! df\<c-\>\<c-g>" - call assert_equal(['abcdefghijklmn'], getline(1,'$')) - exe "norm! df\<c-\>m" - call assert_equal(['abcdefghijklmn'], getline(1,'$')) +func Test_normal54_Ctrl_bsl() + new + call setline(1, 'abcdefghijklmn') + exe "norm! df\<c-\>\<c-n>" + call assert_equal(['abcdefghijklmn'], getline(1,'$')) + exe "norm! df\<c-\>\<c-g>" + call assert_equal(['abcdefghijklmn'], getline(1,'$')) + exe "norm! df\<c-\>m" + call assert_equal(['abcdefghijklmn'], getline(1,'$')) if !has("multi_byte") return endif - call setline(2, 'abcdefghijklmnāf') - norm! 2gg0 - exe "norm! df\<Char-0x101>" - call assert_equal(['abcdefghijklmn', 'f'], getline(1,'$')) - norm! 1gg0 - exe "norm! df\<esc>" - call assert_equal(['abcdefghijklmn', 'f'], getline(1,'$')) + call setline(2, 'abcdefghijklmnāf') + norm! 2gg0 + exe "norm! df\<Char-0x101>" + call assert_equal(['abcdefghijklmn', 'f'], getline(1,'$')) + norm! 1gg0 + exe "norm! df\<esc>" + call assert_equal(['abcdefghijklmn', 'f'], getline(1,'$')) - " clean up - bw! + " clean up + bw! +endfunc + +func Test_normal_large_count() + " This may fail with 32bit long, how do we detect that? + new + normal o + normal 6666666666dL + bwipe! endfunc " Test for the gr (virtual replace) command @@ -2379,3 +2387,15 @@ func Test_changelist() %bwipe! let &ul = save_ul endfunc + +func Test_delete_until_paragraph() + if !has('multi_byte') + return + endif + new + normal grádv} + call assert_equal('á', getline(1)) + normal grád} + call assert_equal('', getline(1)) + bwipe! +endfunc diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim index eb42e35bd3..5ae8528ee9 100644 --- a/src/nvim/testdir/test_options.vim +++ b/src/nvim/testdir/test_options.vim @@ -22,6 +22,13 @@ function! Test_whichwrap() set whichwrap& endfunction +function! Test_isfname() + " This used to cause Vim to access uninitialized memory. + set isfname= + call assert_equal("~X", expand("~X")) + set isfname& +endfunction + function! Test_options() let caught = 'ok' try diff --git a/src/nvim/testdir/test_python2.vim b/src/nvim/testdir/test_python2.vim new file mode 100644 index 0000000000..fb98c1eda7 --- /dev/null +++ b/src/nvim/testdir/test_python2.vim @@ -0,0 +1,24 @@ +" Test for python 2 commands. +" TODO: move tests from test87.in here. + +if !has('python') + finish +endif + +func Test_pydo() + " Check deleting lines does not trigger ml_get error. + py import vim + new + call setline(1, ['one', 'two', 'three']) + pydo vim.command("%d_") + bwipe! + + " Check switching to another buffer does not trigger ml_get error. + new + let wincount = winnr('$') + call setline(1, ['one', 'two', 'three']) + pydo vim.command("new") + call assert_equal(wincount + 1, winnr('$')) + bwipe! + bwipe! +endfunc diff --git a/src/nvim/testdir/test_python3.vim b/src/nvim/testdir/test_python3.vim new file mode 100644 index 0000000000..bb241dacb1 --- /dev/null +++ b/src/nvim/testdir/test_python3.vim @@ -0,0 +1,24 @@ +" Test for python 2 commands. +" TODO: move tests from test88.in here. + +if !has('python3') + finish +endif + +func Test_py3do() + " Check deleting lines does not trigger an ml_get error. + py3 import vim + new + call setline(1, ['one', 'two', 'three']) + py3do vim.command("%d_") + bwipe! + + " Check switching to another buffer does not trigger an ml_get error. + new + let wincount = winnr('$') + call setline(1, ['one', 'two', 'three']) + py3do vim.command("new") + call assert_equal(wincount + 1, winnr('$')) + bwipe! + bwipe! +endfunc diff --git a/src/nvim/testdir/test_quotestar.vim b/src/nvim/testdir/test_quotestar.vim index d0dd04f91d..37e3a10ed1 100644 --- a/src/nvim/testdir/test_quotestar.vim +++ b/src/nvim/testdir/test_quotestar.vim @@ -39,6 +39,15 @@ func Do_test_quotestar_for_x11() if cmd == '' return 'GetVimCommand() failed' endif + try + call remote_send('xxx', '') + catch + if v:exception =~ 'E240:' + " No connection to the X server, give up. + return + endif + " ignore other errors + endtry let name = 'XVIMCLIPBOARD' let cmd .= ' --servername ' . name @@ -109,8 +118,12 @@ func Test_quotestar() if has('macunix') let skipped = Do_test_quotestar_for_macunix() - elseif !empty("$DISPLAY") - let skipped = Do_test_quotestar_for_x11() + elseif has('x11') + if empty($DISPLAY) + let skipped = "Test can only run when $DISPLAY is set." + else + let skipped = Do_test_quotestar_for_x11() + endif else let skipped = "Test is not implemented yet for this platform." endif diff --git a/src/nvim/testdir/test_regexp_utf8.vim b/src/nvim/testdir/test_regexp_utf8.vim index a2f4286d4f..97638e9aac 100644 --- a/src/nvim/testdir/test_regexp_utf8.vim +++ b/src/nvim/testdir/test_regexp_utf8.vim @@ -35,12 +35,21 @@ func s:classes_test() set isprint=@,161-255 call assert_equal('Motörhead', matchstr('Motörhead', '[[:print:]]\+')) + let alnumchars = '' let alphachars = '' + let backspacechar = '' + let blankchars = '' + let cntrlchars = '' + let digitchars = '' + let escapechar = '' + let graphchars = '' let lowerchars = '' - let upperchars = '' - let alnumchars = '' let printchars = '' let punctchars = '' + let returnchar = '' + let spacechars = '' + let tabchar = '' + let upperchars = '' let xdigitchars = '' let i = 1 while i <= 255 @@ -48,21 +57,48 @@ func s:classes_test() if c =~ '[[:alpha:]]' let alphachars .= c endif - if c =~ '[[:lower:]]' - let lowerchars .= c - endif - if c =~ '[[:upper:]]' - let upperchars .= c - endif if c =~ '[[:alnum:]]' let alnumchars .= c endif + if c =~ '[[:backspace:]]' + let backspacechar .= c + endif + if c =~ '[[:blank:]]' + let blankchars .= c + endif + if c =~ '[[:cntrl:]]' + let cntrlchars .= c + endif + if c =~ '[[:digit:]]' + let digitchars .= c + endif + if c =~ '[[:escape:]]' + let escapechar .= c + endif + if c =~ '[[:graph:]]' + let graphchars .= c + endif + if c =~ '[[:lower:]]' + let lowerchars .= c + endif if c =~ '[[:print:]]' let printchars .= c endif if c =~ '[[:punct:]]' let punctchars .= c endif + if c =~ '[[:return:]]' + let returnchar .= c + endif + if c =~ '[[:space:]]' + let spacechars .= c + endif + if c =~ '[[:tab:]]' + let tabchar .= c + endif + if c =~ '[[:upper:]]' + let upperchars .= c + endif if c =~ '[[:xdigit:]]' let xdigitchars .= c endif @@ -70,11 +106,20 @@ func s:classes_test() endwhile call assert_equal('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', alphachars) - call assert_equal('abcdefghijklmnopqrstuvwxyzµßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ', lowerchars) - call assert_equal('ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ', upperchars) call assert_equal('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', alnumchars) + call assert_equal("\b", backspacechar) + call assert_equal("\t ", blankchars) + call assert_equal("\x01\x02\x03\x04\x05\x06\x07\b\t\n\x0b\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\e\x1c\x1d\x1e\x1f\x7f", cntrlchars) + call assert_equal("0123456789", digitchars) + call assert_equal("\<Esc>", escapechar) + call assert_equal('!"#$%&''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~', graphchars) + call assert_equal('abcdefghijklmnopqrstuvwxyzµßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ', lowerchars) call assert_equal(' !"#$%&''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ', printchars) call assert_equal('!"#$%&''()*+,-./:;<=>?@[\]^_`{|}~', punctchars) + call assert_equal('ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ', upperchars) + call assert_equal("\r", returnchar) + call assert_equal("\t\n\x0b\f\r ", spacechars) + call assert_equal("\t", tabchar) call assert_equal('0123456789ABCDEFabcdef', xdigitchars) endfunc @@ -121,3 +166,20 @@ func Test_eow_with_optional() call assert_equal(expected, actual) endfor endfunc + +func Test_reversed_range() + for re in range(0, 2) + exe 'set re=' . re + call assert_fails('call match("abc def", "[c-a]")', 'E944:') + endfor + set re=0 +endfunc + +func Test_large_class() + set re=1 + call assert_fails('call match("abc def", "[\u3000-\u4000]")', 'E945:') + set re=2 + call assert_equal(0, 'abc def' =~# '[\u3000-\u4000]') + call assert_equal(1, "\u3042" =~# '[\u3000-\u4000]') + set re=0 +endfunc diff --git a/src/nvim/testdir/test_scroll_opt.vim b/src/nvim/testdir/test_scroll_opt.vim new file mode 100644 index 0000000000..77920eb8b0 --- /dev/null +++ b/src/nvim/testdir/test_scroll_opt.vim @@ -0,0 +1,36 @@ +" Test for reset 'scroll' +" + +func Test_reset_scroll() + let scr = &l:scroll + + setlocal scroll=1 + setlocal scroll& + call assert_equal(scr, &l:scroll) + + setlocal scroll=1 + setlocal scroll=0 + call assert_equal(scr, &l:scroll) + + try + execute 'setlocal scroll=' . (winheight(0) + 1) + " not reached + call assert_false(1) + catch + call assert_exception('E49:') + endtry + + split + + let scr = &l:scroll + + setlocal scroll=1 + setlocal scroll& + call assert_equal(scr, &l:scroll) + + setlocal scroll=1 + setlocal scroll=0 + call assert_equal(scr, &l:scroll) + + quit! +endfunc diff --git a/src/nvim/testdir/test_smartindent.vim b/src/nvim/testdir/test_smartindent.vim index d00eac9798..9e93a55eb0 100644 --- a/src/nvim/testdir/test_smartindent.vim +++ b/src/nvim/testdir/test_smartindent.vim @@ -1,3 +1,4 @@ +" Tests for smartindent " Tests for not doing smart indenting when it isn't set. function! Test_nosmartindent() @@ -12,3 +13,29 @@ function! Test_nosmartindent() call assert_equal(" #test", getline(1)) enew! | close endfunction + +function MyIndent() +endfunction + +" When 'indentexpr' is set, setting 'si' has no effect. +function Test_smartindent_has_no_effect() + new + exe "normal! i\<Tab>one\<Esc>" + set noautoindent + set smartindent + set indentexpr= + exe "normal! Gotwo\<Esc>" + call assert_equal("\ttwo", getline("$")) + + set indentexpr=MyIndent + exe "normal! Gothree\<Esc>" + call assert_equal("three", getline("$")) + + delfunction! MyIndent + set autoindent& + set smartindent& + set indentexpr& + bwipe! +endfunction + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_startup.vim b/src/nvim/testdir/test_startup.vim index 11e26d03aa..495c561991 100644 --- a/src/nvim/testdir/test_startup.vim +++ b/src/nvim/testdir/test_startup.vim @@ -240,3 +240,14 @@ func Test_progpath() " Only expect "vim" to appear in v:progname. call assert_match('vim\c', v:progname) endfunc + +func Test_silent_ex_mode() + if !has('unix') || has('gui_running') + " can't get output of Vim. + return + endif + + " This caused an ml_get error. + let out = system(GetVimCommand() . '-u NONE -es -c''set verbose=1|h|exe "%norm\<c-y>\<c-d>"'' -c cq') + call assert_notmatch('E315:', out) +endfunc diff --git a/src/nvim/testdir/test_syntax.vim b/src/nvim/testdir/test_syntax.vim index 8465fe7d45..ebdfc250aa 100644 --- a/src/nvim/testdir/test_syntax.vim +++ b/src/nvim/testdir/test_syntax.vim @@ -301,11 +301,19 @@ func Test_syntax_arg_skipped() syn clear endfunc - -func Test_invalid_arg() + +func Test_syntax_invalid_arg() call assert_fails('syntax case asdf', 'E390:') - call assert_fails('syntax conceal asdf', 'E390:') + if has('conceal') + call assert_fails('syntax conceal asdf', 'E390:') + endif call assert_fails('syntax spell asdf', 'E390:') + call assert_fails('syntax clear @ABCD', 'E391:') + call assert_fails('syntax include @Xxx', 'E397:') + call assert_fails('syntax region X start="{"', 'E399:') + call assert_fails('syntax sync x', 'E404:') + call assert_fails('syntax keyword Abc a[', 'E789:') + call assert_fails('syntax keyword Abc a[bc]d', 'E890:') endfunc func Test_syn_sync() @@ -346,6 +354,50 @@ func Test_invalid_name() hi clear @Wrong endfunc +func Test_ownsyntax() + new Xfoo + call setline(1, '#define FOO') + syntax on + set filetype=c + ownsyntax perl + call assert_equal('perlComment', synIDattr(synID(line('.'), col('.'), 1), 'name')) + call assert_equal('c', b:current_syntax) + call assert_equal('perl', w:current_syntax) + + " A new split window should have the original syntax. + split + call assert_equal('cDefine', synIDattr(synID(line('.'), col('.'), 1), 'name')) + call assert_equal('c', b:current_syntax) + call assert_equal(0, exists('w:current_syntax')) + + wincmd x + call assert_equal('perlComment', synIDattr(synID(line("."), col("."), 1), "name")) + + syntax off + set filetype& + %bw! +endfunc + +func Test_ownsyntax_completion() + call feedkeys(":ownsyntax java\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal('"ownsyntax java javacc javascript', @:) +endfunc + +func Test_highlight_invalid_arg() + if has('gui_running') + call assert_fails('hi XXX guifg=xxx', 'E254:') + endif + call assert_fails('hi DoesNotExist', 'E411:') + call assert_fails('hi link', 'E412:') + call assert_fails('hi link a', 'E412:') + call assert_fails('hi link a b c', 'E413:') + call assert_fails('hi XXX =', 'E415:') + call assert_fails('hi XXX cterm', 'E416:') + call assert_fails('hi XXX cterm=', 'E417:') + call assert_fails('hi XXX cterm=DoesNotExist', 'E418:') + call assert_fails('hi XXX ctermfg=DoesNotExist', 'E421:') + call assert_fails('hi XXX xxx=White', 'E423:') +endfunc func Test_conceal() if !has('conceal') @@ -382,3 +434,4 @@ func Test_conceal() set conceallevel& bw! endfunc + diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 65957626cb..25c39587f4 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -405,6 +405,10 @@ static void sigwinch_cb(SignalWatcher *watcher, int signum, void *data) { got_winch = true; UI *ui = data; + if (tui_is_stopped(ui)) { + return; + } + update_size(ui); ui_schedule_refresh(); } @@ -845,7 +849,7 @@ CursorShape tui_cursor_decode_shape(const char *shape_str) static cursorentry_T decode_cursor_entry(Dictionary args) { - cursorentry_T r; + cursorentry_T r = shape_table[0]; for (size_t i = 0; i < args.size; i++) { char *key = args.items[i].key.data; diff --git a/src/nvim/ui.c b/src/nvim/ui.c index 42366fdb76..21dd6ec0dd 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -535,14 +535,18 @@ Array ui_array(void) { Array all_uis = ARRAY_DICT_INIT; for (size_t i = 0; i < ui_count; i++) { - Dictionary dic = ARRAY_DICT_INIT; - PUT(dic, "width", INTEGER_OBJ(uis[i]->width)); - PUT(dic, "height", INTEGER_OBJ(uis[i]->height)); - PUT(dic, "rgb", BOOLEAN_OBJ(uis[i]->rgb)); + UI *ui = uis[i]; + Dictionary info = ARRAY_DICT_INIT; + PUT(info, "width", INTEGER_OBJ(ui->width)); + PUT(info, "height", INTEGER_OBJ(ui->height)); + PUT(info, "rgb", BOOLEAN_OBJ(ui->rgb)); for (UIExtension j = 0; j < kUIExtCount; j++) { - PUT(dic, ui_ext_names[j], BOOLEAN_OBJ(uis[i]->ui_ext[j])); + PUT(info, ui_ext_names[j], BOOLEAN_OBJ(ui->ui_ext[j])); + } + if (ui->inspect) { + ui->inspect(ui, &info); } - ADD(all_uis, DICTIONARY_OBJ(dic)); + ADD(all_uis, DICTIONARY_OBJ(info)); } return all_uis; } diff --git a/src/nvim/ui.h b/src/nvim/ui.h index 48896a6a3f..6b04e9c67a 100644 --- a/src/nvim/ui.h +++ b/src/nvim/ui.h @@ -36,6 +36,7 @@ struct ui_t { #endif void (*event)(UI *ui, char *name, Array args, bool *args_consumed); void (*stop)(UI *ui); + void (*inspect)(UI *ui, Dictionary *info); }; #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/ui_bridge.c b/src/nvim/ui_bridge.c index a8bbeea035..56db124a46 100644 --- a/src/nvim/ui_bridge.c +++ b/src/nvim/ui_bridge.c @@ -163,3 +163,28 @@ static void ui_bridge_suspend_event(void **argv) UI *ui = UI(argv[0]); ui->suspend(ui); } + +static void ui_bridge_option_set(UI *ui, String name, Object value) +{ + String copy_name = copy_string(name); + Object *copy_value = xmalloc(sizeof(Object)); + *copy_value = copy_object(value); + UI_BRIDGE_CALL(ui, option_set, 4, ui, copy_name.data, + INT2PTR(copy_name.size), copy_value); + // TODO(bfredl): when/if TUI/bridge teardown is refactored to use events, the + // commit that introduced this special case can be reverted. + // For now this is needed for nvim_list_uis(). + if (strequal(name.data, "termguicolors")) { + ui->rgb = value.data.boolean; + } +} +static void ui_bridge_option_set_event(void **argv) +{ + UI *ui = UI(argv[0]); + String name = (String){ .data = argv[1], .size = (size_t)argv[2] }; + Object value = *(Object *)argv[3]; + ui->option_set(ui, name, value); + api_free_string(name); + api_free_object(value); + xfree(argv[3]); +} diff --git a/src/nvim/undo.c b/src/nvim/undo.c index 44bcefb332..8b290edd1f 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -1698,9 +1698,9 @@ bool u_undo_and_forget(int count) count = 1; } undo_undoes = true; - // don't send a nvim_buf_lines_event for this undo is part of 'inccommand' - // playing with buffer contents - u_doit(count, true, false); + u_doit(count, true, + // Don't send nvim_buf_lines_event for u_undo_and_forget(). + false); if (curbuf->b_u_curhead == NULL) { // nothing was undone. diff --git a/src/nvim/version.c b/src/nvim/version.c index 17f89a25d2..be160e678e 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -145,7 +145,7 @@ static const int included_patches[] = { // 1497, // 1496, // 1495, - // 1494, + 1494, 1493, // 1492, // 1491, @@ -167,7 +167,7 @@ static const int included_patches[] = { 1475, // 1474, // 1473, - // 1472, + 1472, // 1471, // 1470, // 1469, @@ -328,7 +328,7 @@ static const int included_patches[] = { // 1314, // 1313, // 1312, - // 1311, + 1311, // 1310, // 1309, // 1308, @@ -405,9 +405,9 @@ static const int included_patches[] = { // 1237, // 1236, // 1235, - // 1234, + 1234, // 1233, - // 1232, + 1232, // 1231, 1230, 1229, @@ -442,13 +442,13 @@ static const int included_patches[] = { 1200, // 1199, // 1198, - // 1197, + 1197, // 1196, // 1195, // 1194, // 1193, // 1192, - // 1191, + 1191, // 1190, 1189, 1188, @@ -458,8 +458,8 @@ static const int included_patches[] = { // 1184, // 1183, // 1182, - // 1181, - // 1180, + 1181, + 1180, // 1179, // 1178, // 1177, @@ -489,7 +489,7 @@ static const int included_patches[] = { // 1153, // 1152, // 1151, - // 1150, + 1150, // 1149, // 1148, // 1147, @@ -498,7 +498,7 @@ static const int included_patches[] = { // 1144, // 1143, // 1142, - // 1141, + 1141, // 1140, // 1139, // 1138, @@ -518,7 +518,7 @@ static const int included_patches[] = { // 1124, // 1123, // 1122, - // 1121, + 1121, // 1120, // 1119, // 1118, @@ -714,7 +714,7 @@ static const int included_patches[] = { // 928, // 927, // 926, - // 925, + 925, // 924, // 923, // 922, @@ -758,7 +758,7 @@ static const int included_patches[] = { // 884, // 883, // 882, - // 881, + 881, // 880, // 879, // 878, @@ -1077,11 +1077,11 @@ static const int included_patches[] = { 565, 564, // 563, - // 562, + 562, 561, // 560, - // 559, - // 558, + 559, + 558, // 557, // 556, 555, @@ -1120,30 +1120,30 @@ static const int included_patches[] = { // 522, // 521, // 520, - // 519, + 519, 518, 517, - // 516, - // 515, + 516, + 515, // 514, 513, // 512, - // 511, + 511, // 510, // 509, // 508, - // 507, + 507, // 506, - // 505, + 505, // 504, - // 503, + 503, 502, // 501, 500, 499, 498, - // 497, - // 496, + 497, + 496, 495, // 494, // 493, @@ -1175,36 +1175,36 @@ static const int included_patches[] = { // 467, // 466, 465, - // 464, - // 463, + 464, + 463, // 462, 461, - // 460, + 460, 459, 458, 457, - // 456, + 456, // 455, - // 454, + 454, 453, // 452, // 451, - // 450, + 450, // 449, 448, - // 447, + 447, 446, // 445, 444, 443, 442, - // 441, + 441, 440, 439, - // 438, + 438, 437, // 436, - // 435, + 435, 434, 433, // 432, @@ -1220,23 +1220,23 @@ static const int included_patches[] = { // 422, 421, 420, - // 419, + 419, // 418, 417, - // 416, - // 415, + 416, + 415, // 414, // 413, // 412, // 411, // 410, - // 409, + 409, 408, 407, 406, 405, 404, - // 403, + 403, 402, // 401, 400, @@ -1255,20 +1255,20 @@ static const int included_patches[] = { 387, // 386, 385, - // 384, - // 383, - // 382, + 384, + 383, + 382, 381, 380, 379, 378, 377, 376, - // 375, + 375, 374, // 373, // 372, - // 371, + 371, // 370, // 369, // 368, @@ -1277,27 +1277,27 @@ static const int included_patches[] = { // 365, 364, // 363, - // 362, + 362, // 361, 360, 359, 358, 357, - // 356, + 356, // 355, - // 354, + 354, 353, 352, 351, // 350, // 349, - // 348, + 348, 347, // 346, 345, 344, 343, - // 342, + 342, 341, // 340, 339, @@ -1307,10 +1307,10 @@ static const int included_patches[] = { 335, 334, 333, - // 332, + 332, 331, 330, - // 329, + 329, 328, 327, 326, @@ -1318,16 +1318,16 @@ static const int included_patches[] = { 324, 323, 322, - // 321, + 321, 320, 319, - // 318, - // 317, + 318, + 317, 316, 315, 314, - // 313, - // 312, + 313, + 312, 311, 310, 309, @@ -1335,7 +1335,7 @@ static const int included_patches[] = { 307, 306, 305, - // 304, + 304, // 303, 302, 301, @@ -1378,7 +1378,7 @@ static const int included_patches[] = { // 264, 263, 262, - // 261, + 261, 260, 259, 258, diff --git a/test/functional/api/buffer_updates_spec.lua b/test/functional/api/buffer_updates_spec.lua index 00409c1528..6da790b871 100644 --- a/test/functional/api/buffer_updates_spec.lua +++ b/test/functional/api/buffer_updates_spec.lua @@ -3,6 +3,7 @@ local eq, ok = helpers.eq, helpers.ok local buffer, command, eval, nvim, next_msg = helpers.buffer, helpers.command, helpers.eval, helpers.nvim, helpers.next_msg local expect_err = helpers.expect_err +local write_file = helpers.write_file local origlines = {"original line 1", "original line 2", @@ -18,7 +19,7 @@ end local function sendkeys(keys) nvim('input', keys) - -- give neovim some time to process msgpack requests before possibly sending + -- give nvim some time to process msgpack requests before possibly sending -- more key presses - otherwise they all pile up in the queue and get -- processed at once local ntime = os.clock() + 0.1 @@ -27,14 +28,14 @@ end local function open(activate, lines) local filename = helpers.tmpname() - helpers.write_file(filename, table.concat(lines, "\n").."\n", true) + write_file(filename, table.concat(lines, "\n").."\n", true) command('edit ' .. filename) local b = nvim('get_current_buf') -- what is the value of b:changedtick? local tick = eval('b:changedtick') - -- turn on live updates, ensure that the nvim_buf_lines_event messages - -- arrive as expectected + -- Enable buffer events, ensure that the nvim_buf_lines_event messages + -- arrive as expected if activate then local firstline = 0 ok(buffer('attach', b, true, {})) @@ -91,8 +92,8 @@ local function reopenwithfolds(b) return tick end -describe('buffer events', function() - it('when you add line to a buffer', function() +describe('API: buffer events:', function() + it('when lines are added', function() local b, tick = editoriginal(true) -- add a new line at the start of the buffer @@ -156,7 +157,7 @@ describe('buffer events', function() expectn('nvim_buf_lines_event', {b, tick, 29, 29, firstfour, false}) -- create a new empty buffer and wipe out the old one ... this will - -- turn off live updates + -- turn off buffer events command('enew!') expectn('nvim_buf_detach_event', {b}) @@ -170,7 +171,7 @@ describe('buffer events', function() tick = tick + 1 expectn('nvim_buf_lines_event', {b2, tick, 0, 0, {'new line 1'}, false}) - -- turn off live updates manually + -- turn off buffer events manually buffer('detach', b2) expectn('nvim_buf_detach_event', {b2}) @@ -192,7 +193,7 @@ describe('buffer events', function() expectn('nvim_buf_lines_event', {b3, tick, 0, 0, {"New First Line"}, false}) end) - it('knows when you remove lines from a buffer', function() + it('when lines are removed', function() local b, tick = editoriginal(true) -- remove one line from start of file @@ -231,7 +232,7 @@ describe('buffer events', function() expectn('nvim_buf_lines_event', {b, tick, 4, 6, {}, false}) end) - it('knows when you modify lines of text', function() + it('when text is changed', function() local b, tick = editoriginal(true) -- some normal text editing @@ -286,7 +287,7 @@ describe('buffer events', function() expectn('nvim_buf_lines_event', {bnew, tick + 7, 1, 2, {'world'}, false}) end) - it('knows when you replace lines', function() + it('when lines are replaced', function() local b, tick = editoriginal(true) -- blast away parts of some lines with visual mode @@ -311,7 +312,7 @@ describe('buffer events', function() expectn('nvim_buf_lines_event', {b, tick, 3, 4, {}, false}) end) - it('knows when you filter lines', function() + it('when lines are filtered', function() -- Test filtering lines with !cat local b, tick = editoriginal(true, {"A", "C", "E", "B", "D", "F"}) @@ -325,7 +326,7 @@ describe('buffer events', function() expectn('nvim_buf_lines_event', {b, tick, 1, 5, {}, false}) end) - it('sends a sensible event when you use "o"', function() + it('when you use "o"', function() local b, tick = editoriginal(true, {'AAA', 'BBB'}) command('set noautoindent nosmartindent') @@ -365,7 +366,7 @@ describe('buffer events', function() expectn('nvim_buf_lines_event', {b, tick, 0, 1, {"\tmmm"}, false}) end) - it('deactivates when your buffer changes outside vim', function() + it('deactivates if the buffer is changed externally', function() -- Test changing file from outside vim and reloading using :edit local lines = {"Line 1", "Line 2"}; local b, tick, filename = editoriginal(true, lines) @@ -380,17 +381,14 @@ describe('buffer events', function() expectn('nvim_buf_changedtick_event', {b, tick}) -- change the file directly - local f = io.open(filename, 'a') - f:write("another line\n") - f:flush() - f:close() + write_file(filename, "another line\n", true, true) - -- reopen the file and watch live updates shut down + -- reopen the file and watch buffer events shut down command('edit') expectn('nvim_buf_detach_event', {b}) end) - it('allows a channel to watch multiple buffers at once', function() + it('channel can watch many buffers at once', function() -- edit 3 buffers, make sure they all have windows visible so that when we -- move between buffers, none of them are unloaded local b1, tick1 = editoriginal(true, {'A1', 'A2'}) @@ -436,12 +434,12 @@ describe('buffer events', function() expectn('nvim_buf_changedtick_event', {b3, tick3}) end) - it('doesn\'t get confused when you turn watching on/off many times', + it('does not get confused if enabled/disabled many times', function() local channel = nvim('get_api_info')[1] local b, tick = editoriginal(false) - -- turn on live updates many times + -- Enable buffer events many times. ok(buffer('attach', b, true, {})) ok(buffer('attach', b, true, {})) ok(buffer('attach', b, true, {})) @@ -451,7 +449,7 @@ describe('buffer events', function() eval('rpcnotify('..channel..', "Hello There")') expectn('Hello There', {}) - -- turn live updates off many times + -- Disable buffer events many times. ok(buffer('detach', b)) ok(buffer('detach', b)) ok(buffer('detach', b)) @@ -462,7 +460,7 @@ describe('buffer events', function() expectn('Hello Again', {}) end) - it('is able to notify several channels at once', function() + it('can notify several channels at once', function() helpers.clear() -- create several new sessions, in addition to our main API @@ -486,11 +484,11 @@ describe('buffer events', function() eq({'notification', name, args}, session:next_message()) end - -- edit a new file, but don't turn on live updates + -- Edit a new file, but don't enable buffer events. local lines = {'AAA', 'BBB'} local b, tick = open(false, lines) - -- turn on live updates for sessions 1, 2 and 3 + -- Enable buffer events for sessions 1, 2 and 3. ok(request(1, 'nvim_buf_attach', b, true, {})) ok(request(2, 'nvim_buf_attach', b, true, {})) ok(request(3, 'nvim_buf_attach', b, true, {})) @@ -498,18 +496,18 @@ describe('buffer events', function() wantn(2, 'nvim_buf_lines_event', {b, tick, 0, -1, lines, false}) wantn(3, 'nvim_buf_lines_event', {b, tick, 0, -1, lines, false}) - -- make a change to the buffer + -- Change the buffer. command('normal! x') tick = tick + 1 wantn(1, 'nvim_buf_lines_event', {b, tick, 0, 1, {'AA'}, false}) wantn(2, 'nvim_buf_lines_event', {b, tick, 0, 1, {'AA'}, false}) wantn(3, 'nvim_buf_lines_event', {b, tick, 0, 1, {'AA'}, false}) - -- stop watching on channel 1 + -- Stop watching on channel 1. ok(request(1, 'nvim_buf_detach', b)) wantn(1, 'nvim_buf_detach_event', {b}) - -- undo the change to buffer 1 + -- Undo the change to buffer 1. command('undo') tick = tick + 1 wantn(2, 'nvim_buf_lines_event', {b, tick, 0, 1, {'AAA'}, false}) @@ -612,7 +610,7 @@ describe('buffer events', function() expectn('nvim_buf_lines_event', {b, tick, 5, 7, {}, false}) end) - it('sends sensible events when you manually add/remove folds', function() + it('when you manually add/remove folds', function() local b = editoriginal(true) local tick = reopenwithfolds(b) @@ -656,11 +654,11 @@ describe('buffer events', function() 'original line 6'}, false}) end) - it('turns off updates when a buffer is closed', function() + it('detaches if the buffer is closed', function() local b, tick = editoriginal(true, {'AAA'}) local channel = nvim('get_api_info')[1] - -- test live updates are working + -- Test that buffer events are working. command('normal! x') tick = tick + 1 expectn('nvim_buf_lines_event', {b, tick, 0, 1, {'AA'}, false}) @@ -674,7 +672,7 @@ describe('buffer events', function() command('enew') expectn('nvim_buf_detach_event', {b}) - -- reopen the original buffer, make sure there are no Live Updates sent + -- Reopen the original buffer, make sure there are no buffer events sent. command('b1') command('normal! x') @@ -682,12 +680,11 @@ describe('buffer events', function() expectn('Hello There', {}) end) - -- test what happens when a buffer is hidden - it('keeps updates turned on if the buffer is hidden', function() + it('stays attached if the buffer is hidden', function() local b, tick = editoriginal(true, {'AAA'}) local channel = nvim('get_api_info')[1] - -- test live updates are working + -- Test that buffer events are working. command('normal! x') tick = tick + 1 expectn('nvim_buf_lines_event', {b, tick, 0, 1, {'AA'}, false}) @@ -697,22 +694,22 @@ describe('buffer events', function() tick = tick + 1 expectn('nvim_buf_changedtick_event', {b, tick}) - -- close our buffer by creating a new one + -- Close our buffer by creating a new one. command('set hidden') command('enew') - -- note that no nvim_buf_detach_event is sent + -- Assert that no nvim_buf_detach_event is sent. eval('rpcnotify('..channel..', "Hello There")') expectn('Hello There', {}) - -- reopen the original buffer, make sure Live Updates are still active + -- Reopen the original buffer, assert that buffer events are still active. command('b1') command('normal! x') tick = tick + 1 expectn('nvim_buf_lines_event', {b, tick, 0, 1, {'AA'}, false}) end) - it('turns off live updates when a buffer is unloaded, deleted, or wiped', + it('detaches if the buffer is unloaded/deleted/wiped', function() -- start with a blank nvim helpers.clear() @@ -730,7 +727,7 @@ describe('buffer events', function() end end) - it('doesn\'t send the buffer\'s content when not requested', function() + it('does not send the buffer content if not requested', function() helpers.clear() local b, tick = editoriginal(false) ok(buffer('attach', b, false, {})) diff --git a/test/functional/api/highlight_spec.lua b/test/functional/api/highlight_spec.lua index fed53a3dfd..76bf338d97 100644 --- a/test/functional/api/highlight_spec.lua +++ b/test/functional/api/highlight_spec.lua @@ -5,7 +5,7 @@ local eq, eval = helpers.eq, helpers.eval local command = helpers.command local meths = helpers.meths -describe('highlight api',function() +describe('API: highlight',function() local expected_rgb = { background = Screen.colors.Yellow, foreground = Screen.colors.Red, diff --git a/test/functional/api/rpc_fixture.lua b/test/functional/api/rpc_fixture.lua index 423864740f..e885a525af 100644 --- a/test/functional/api/rpc_fixture.lua +++ b/test/functional/api/rpc_fixture.lua @@ -31,7 +31,7 @@ end local function on_notification(event, args) if event == 'ping' and #args == 0 then - session:notify("vim_eval", "rpcnotify(g:channel, 'pong')") + session:notify("nvim_eval", "rpcnotify(g:channel, 'pong')") end end diff --git a/test/functional/api/server_requests_spec.lua b/test/functional/api/server_requests_spec.lua index e79a60fb10..856e5ca4d2 100644 --- a/test/functional/api/server_requests_spec.lua +++ b/test/functional/api/server_requests_spec.lua @@ -222,7 +222,7 @@ describe('server -> client', function() end) it('returns an error if the request failed', function() - expect_err('Vim:Invalid method name', + expect_err('Vim:Invalid method: does%-not%-exist', eval, "rpcrequest(vim, 'does-not-exist')") end) end) diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 1e910b6aa7..e4b343c123 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -20,9 +20,20 @@ local format_string = global_helpers.format_string local intchar2lua = global_helpers.intchar2lua local mergedicts_copy = global_helpers.mergedicts_copy -describe('api', function() +describe('API', function() before_each(clear) + it('validates requests', function() + expect_err('Invalid method: bogus', + request, 'bogus') + expect_err('Invalid method: … の り 。…', + request, '… の り 。…') + expect_err('Invalid method: <empty>', + request, '') + expect_err("can't serialize object", + request, nil) + end) + describe('nvim_command', function() it('works', function() local fname = helpers.tmpname() @@ -924,7 +935,7 @@ describe('api', function() {'i_am_not_a_method', {'xx'}}, {'nvim_set_var', {'avar', 10}}, } - eq({{}, {0, error_types.Exception.id, 'Invalid method name'}}, + eq({{}, {0, error_types.Exception.id, 'Invalid method: i_am_not_a_method'}}, meths.call_atomic(req)) eq(5, meths.get_var('avar')) end) @@ -1226,6 +1237,7 @@ describe('api', function() screen:attach() local expected = { { + chan = 1, ext_cmdline = false, ext_popupmenu = false, ext_tabline = false, @@ -1242,6 +1254,7 @@ describe('api', function() screen:attach({ rgb = false }) expected = { { + chan = 1, ext_cmdline = false, ext_popupmenu = false, ext_tabline = false, diff --git a/test/functional/eval/setpos_spec.lua b/test/functional/eval/setpos_spec.lua index 6a8b3a8732..935f387bcc 100644 --- a/test/functional/eval/setpos_spec.lua +++ b/test/functional/eval/setpos_spec.lua @@ -27,9 +27,8 @@ describe('setpos() function', function() eq(getpos("."), {0, 2, 1, 0}) setpos(".", {2, 1, 1, 0}) eq(getpos("."), {0, 1, 1, 0}) - -- Ensure get an error attempting to set position to another buffer local ret = exc_exec('call setpos(".", [1, 1, 1, 0])') - eq('Vim(call):E474: Invalid argument', ret) + eq(0, ret) end) it('can set lowercase marks in the current buffer', function() setpos("'d", {0, 2, 1, 0}) diff --git a/test/functional/ex_cmds/debug_spec.lua b/test/functional/ex_cmds/debug_spec.lua new file mode 100644 index 0000000000..5dad8098ea --- /dev/null +++ b/test/functional/ex_cmds/debug_spec.lua @@ -0,0 +1,110 @@ +local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') +local feed = helpers.feed +local clear = helpers.clear + +describe(':debug', function() + local screen + before_each(function() + clear() + screen = Screen.new(50, 14) + screen:set_default_attr_ids({ + [1] = {bold = true, foreground = Screen.colors.Blue1}, + [2] = {bold = true, reverse = true}, + [3] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [4] = {bold = true, foreground = Screen.colors.SeaGreen4}, + }) + screen:attach() + end) + it('scrolls messages correctly', function() + feed(':echoerr bork<cr>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2: }| + {3:E121: Undefined variable: bork} | + {3:E15: Invalid expression: bork} | + {4:Press ENTER or type command to continue}^ | + ]]) + + feed(':debug echo "aa"| echo "bb"<cr>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2: }| + {3:E121: Undefined variable: bork} | + {3:E15: Invalid expression: bork} | + Entering Debug mode. Type "cont" to continue. | + cmd: echo "aa"| echo "bb" | + >^ | + ]]) + + feed('step<cr>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2: }| + {3:E121: Undefined variable: bork} | + {3:E15: Invalid expression: bork} | + Entering Debug mode. Type "cont" to continue. | + cmd: echo "aa"| echo "bb" | + >step | + aa | + cmd: echo "bb" | + >^ | + ]]) + + feed('step<cr>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {2: }| + {3:E121: Undefined variable: bork} | + {3:E15: Invalid expression: bork} | + Entering Debug mode. Type "cont" to continue. | + cmd: echo "aa"| echo "bb" | + >step | + aa | + cmd: echo "bb" | + >step | + bb | + {4:Press ENTER or type command to continue}^ | + ]]) + + feed('<cr>') + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + | + ]]) + end) +end) diff --git a/test/functional/ex_cmds/write_spec.lua b/test/functional/ex_cmds/write_spec.lua index bcf83698bb..3f54ff6f41 100644 --- a/test/functional/ex_cmds/write_spec.lua +++ b/test/functional/ex_cmds/write_spec.lua @@ -9,6 +9,7 @@ local command = helpers.command local feed_command = helpers.feed_command local funcs = helpers.funcs local meths = helpers.meths +local iswin = helpers.iswin local fname = 'Xtest-functional-ex_cmds-write' local fname_bak = fname .. '~' @@ -34,11 +35,14 @@ describe(':write', function() it('&backupcopy=auto preserves symlinks', function() command('set backupcopy=auto') write_file('test_bkc_file.txt', 'content0') - if helpers.iswin() then + if iswin() then command("silent !mklink test_bkc_link.txt test_bkc_file.txt") else command("silent !ln -s test_bkc_file.txt test_bkc_link.txt") end + if eval('v:shell_error') ~= 0 then + pending('Cannot create symlink', function()end) + end source([[ edit test_bkc_link.txt call setline(1, ['content1']) @@ -51,11 +55,14 @@ describe(':write', function() it('&backupcopy=no replaces symlink with new file', function() command('set backupcopy=no') write_file('test_bkc_file.txt', 'content0') - if helpers.iswin() then + if iswin() then command("silent !mklink test_bkc_link.txt test_bkc_file.txt") else command("silent !ln -s test_bkc_file.txt test_bkc_link.txt") end + if eval('v:shell_error') ~= 0 then + pending('Cannot create symlink', function()end) + end source([[ edit test_bkc_link.txt call setline(1, ['content1']) @@ -66,7 +73,8 @@ describe(':write', function() end) it("appends FIFO file", function() - if eval("executable('mkfifo')") == 0 then + -- mkfifo creates read-only .lnk files on Windows + if iswin() or eval("executable('mkfifo')") == 0 then pending('missing "mkfifo" command', function()end) return end @@ -88,7 +96,7 @@ describe(':write', function() command('let $HOME=""') eq(funcs.fnamemodify('.', ':p:h'), funcs.fnamemodify('.', ':p:h:~')) -- Message from check_overwrite - if not helpers.iswin() then + if not iswin() then eq(('\nE17: "'..funcs.fnamemodify('.', ':p:h')..'" is a directory'), redir_exec('write .')) end @@ -108,7 +116,7 @@ describe(':write', function() funcs.setfperm(fname, 'r--------') eq('Vim(write):E505: "Xtest-functional-ex_cmds-write" is read-only (add ! to override)', exc_exec('write')) - if helpers.iswin() then + if iswin() then eq(0, os.execute('del /q/f ' .. fname)) eq(0, os.execute('rd /q/s ' .. fname_bak)) else @@ -117,7 +125,7 @@ describe(':write', function() end write_file(fname_bak, 'TTYX') -- FIXME: exc_exec('write!') outputs 0 in Windows - if helpers.iswin() then return end + if iswin() then return end lfs.link(fname_bak .. ('/xxxxx'):rep(20), fname, true) eq('Vim(write):E166: Can\'t open linked file for writing', exc_exec('write!')) diff --git a/test/functional/ex_cmds/wviminfo_spec.lua b/test/functional/ex_cmds/wviminfo_spec.lua index eebbd70f2b..df0b9df5dd 100644 --- a/test/functional/ex_cmds/wviminfo_spec.lua +++ b/test/functional/ex_cmds/wviminfo_spec.lua @@ -3,21 +3,21 @@ local lfs = require('lfs') local command, eq, neq, spawn, nvim_prog, set_session, write_file = helpers.command, helpers.eq, helpers.neq, helpers.spawn, helpers.nvim_prog, helpers.set_session, helpers.write_file +local iswin = helpers.iswin +local read_file = helpers.read_file describe(':wshada', function() local shada_file = 'wshada_test' local session before_each(function() - if session then - session:close() - end - -- Override the default session because we need 'swapfile' for these tests. - session = spawn({nvim_prog, '-u', 'NONE', '-i', '/dev/null', '--embed', + session = spawn({nvim_prog, '-u', 'NONE', '-i', iswin() and 'nul' or '/dev/null', '--embed', '--cmd', 'set swapfile'}) set_session(session) - + end) + after_each(function () + session:close() os.remove(shada_file) end) @@ -36,7 +36,7 @@ describe(':wshada', function() write_file(shada_file, text) -- sanity check - eq(text, io.open(shada_file):read()) + eq(text, read_file(shada_file)) neq(nil, lfs.attributes(shada_file)) command('wsh! '..shada_file) @@ -49,8 +49,4 @@ describe(':wshada', function() assert(char1:byte() == 0x01, shada_file..' should be a shada file') end) - - teardown(function() - os.remove(shada_file) - end) end) diff --git a/test/functional/legacy/011_autocommands_spec.lua b/test/functional/legacy/011_autocommands_spec.lua index c2667d28d2..379646b2ba 100644 --- a/test/functional/legacy/011_autocommands_spec.lua +++ b/test/functional/legacy/011_autocommands_spec.lua @@ -17,9 +17,10 @@ local lfs = require('lfs') local clear, feed_command, expect, eq, neq, dedent, write_file, feed = helpers.clear, helpers.feed_command, helpers.expect, helpers.eq, helpers.neq, helpers.dedent, helpers.write_file, helpers.feed +local iswin = helpers.iswin local function has_gzip() - local null = helpers.iswin() and 'nul' or '/dev/null' + local null = iswin() and 'nul' or '/dev/null' return os.execute('gzip --help >' .. null .. ' 2>&1') == 0 end @@ -59,7 +60,7 @@ describe('file reading, writing and bufnew and filter autocommands', function() os.remove('test.out') end) - if not has_gzip() then + if iswin() or not has_gzip() then pending('skipped (missing `gzip` utility)', function() end) else diff --git a/test/functional/legacy/097_glob_path_spec.lua b/test/functional/legacy/097_glob_path_spec.lua index 907f0665ae..ccd93fed60 100644 --- a/test/functional/legacy/097_glob_path_spec.lua +++ b/test/functional/legacy/097_glob_path_spec.lua @@ -74,7 +74,7 @@ describe('glob() and globpath()', function() teardown(function() if helpers.iswin() then os.execute('del /q/f Xxx{ Xxx$') - os.execute('rd /q sautest') + os.execute('rd /q /s sautest') else os.execute("rm -rf sautest Xxx{ Xxx$") end diff --git a/test/functional/legacy/assert_spec.lua b/test/functional/legacy/assert_spec.lua index 381461dc4f..10703465aa 100644 --- a/test/functional/legacy/assert_spec.lua +++ b/test/functional/legacy/assert_spec.lua @@ -77,6 +77,11 @@ describe('assert function:', function() eq('Vim(call):E724: unable to correctly dump variable with self-referencing container', exc_exec('call CheckAssert()')) end) + + it('can specify a message and get a message about what failed', function() + call('assert_equal', 'foo', 'bar', 'testing') + expected_errors({"testing: Expected 'foo' but got 'bar'"}) + end) end) -- assert_notequal({expected}, {actual}[, {msg}]) @@ -164,10 +169,10 @@ describe('assert function:', function() call assert_true('', 'file two') ]]) expected_errors({ - tmpname_one .. " line 1: 'equal assertion failed'", - tmpname_one .. " line 2: 'true assertion failed'", - tmpname_one .. " line 3: 'false assertion failed'", - tmpname_two .. " line 1: 'file two'", + tmpname_one .. " line 1: equal assertion failed: Expected 1 but got 100", + tmpname_one .. " line 2: true assertion failed: Expected False but got 'true'", + tmpname_one .. " line 3: false assertion failed: Expected True but got 'false'", + tmpname_two .. " line 1: file two: Expected True but got ''", }) end) @@ -198,7 +203,7 @@ describe('assert function:', function() it('should set v:errors to msg when given and match fails', function() call('assert_match', 'bar.*foo', 'foobar', 'wrong') - expected_errors({"'wrong'"}) + expected_errors({"wrong: Pattern 'bar.*foo' does not match 'foobar'"}) end) end) diff --git a/test/functional/legacy/delete_spec.lua b/test/functional/legacy/delete_spec.lua index 5ef456bfe3..9ea3269828 100644 --- a/test/functional/legacy/delete_spec.lua +++ b/test/functional/legacy/delete_spec.lua @@ -4,6 +4,9 @@ local eq, eval, command = helpers.eq, helpers.eval, helpers.command describe('Test for delete()', function() before_each(clear) + after_each(function() + os.remove('Xfile') + end) it('file delete', function() command('split Xfile') @@ -52,6 +55,9 @@ describe('Test for delete()', function() silent !ln -s Xfile Xlink endif ]]) + if eval('v:shell_error') ~= 0 then + pending('Cannot create symlink', function()end) + end -- Delete the link, not the file eq(0, eval("delete('Xlink')")) eq(-1, eval("delete('Xlink')")) diff --git a/test/functional/provider/nodejs_spec.lua b/test/functional/provider/nodejs_spec.lua index f69c3e7c78..07a00f8a8c 100644 --- a/test/functional/provider/nodejs_spec.lua +++ b/test/functional/provider/nodejs_spec.lua @@ -16,7 +16,6 @@ end before_each(function() clear() - command([[let $NODE_PATH = get(split(system('npm root -g'), "\n"), 0, '')]]) end) describe('nodejs host', function() @@ -28,21 +27,18 @@ describe('nodejs host', function() it('works', function() local fname = 'Xtest-nodejs-hello.js' write_file(fname, [[ - const socket = process.env.NVIM_LISTEN_ADDRESS; const neovim = require('neovim'); - const nvim = neovim.attach({socket: socket}); + const nvim = neovim.attach({socket: process.env.NVIM_LISTEN_ADDRESS}); nvim.command('let g:job_out = "hello"'); - nvim.command('call jobstop(g:job_id)'); ]]) command('let g:job_id = jobstart(["node", "'..fname..'"])') - retry(nil, 2000, function() eq('hello', eval('g:job_out')) end) + retry(nil, 3000, function() eq('hello', eval('g:job_out')) end) end) it('plugin works', function() local fname = 'Xtest-nodejs-hello-plugin.js' write_file(fname, [[ - const socket = process.env.NVIM_LISTEN_ADDRESS; const neovim = require('neovim'); - const nvim = neovim.attach({socket: socket}); + const nvim = neovim.attach({socket: process.env.NVIM_LISTEN_ADDRESS}); class TestPlugin { hello() { @@ -54,6 +50,6 @@ describe('nodejs host', function() plugin.instance.hello(); ]]) command('let g:job_id = jobstart(["node", "'..fname..'"])') - retry(nil, 2000, function() eq('hello-plugin', eval('g:job_out')) end) + retry(nil, 3000, function() eq('hello-plugin', eval('g:job_out')) end) end) end) diff --git a/test/functional/terminal/ex_terminal_spec.lua b/test/functional/terminal/ex_terminal_spec.lua index 4f22f7385d..f98add41a0 100644 --- a/test/functional/terminal/ex_terminal_spec.lua +++ b/test/functional/terminal/ex_terminal_spec.lua @@ -47,6 +47,16 @@ describe(':terminal', function() ]]) end) + it("reads output buffer on terminal reporting #4151", function() + if helpers.pending_win32(pending) then return end + if iswin() then + feed_command([[terminal powershell -NoProfile -NoLogo -Command Write-Host -NoNewline "\"$([char]27)[6n\""; Start-Sleep -Milliseconds 500 ]]) + else + feed_command([[terminal printf '\e[6n'; sleep 0.5 ]]) + end + screen:expect('%^%[%[1;1R', nil, nil, nil, true) + end) + it("in normal-mode :split does not move cursor", function() if iswin() then feed_command([[terminal for /L \\%I in (1,0,2) do ( echo foo & ping -w 100 -n 1 127.0.0.1 > nul )]]) diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 0ae5802a01..5603224975 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -253,6 +253,19 @@ describe('tui', function() {4:-- TERMINAL --} | ]]) end) + + it('shows up in nvim_list_uis', function() + feed_data(':echo map(nvim_list_uis(), {k,v -> sort(items(v))})\013') + screen:expect([=[ + {5: }| + [[['ext_cmdline', v:false], ['ext_popupmenu', v:fa| + lse], ['ext_tabline', v:false], ['ext_wildmenu', v| + :false], ['height', 6], ['rgb', v:false], ['width'| + , 50]]] | + {10:Press ENTER or type command to continue}{1: } | + {3:-- TERMINAL --} | + ]=]) + end) end) describe('tui with non-tty file descriptors', function() diff --git a/test/functional/ui/cmdline_spec.lua b/test/functional/ui/cmdline_spec.lua index 41c290a462..5ce49822e5 100644 --- a/test/functional/ui/cmdline_spec.lua +++ b/test/functional/ui/cmdline_spec.lua @@ -22,6 +22,8 @@ describe('external cmdline', function() [1] = {bold = true, foreground = Screen.colors.Blue1}, [2] = {reverse = true}, [3] = {bold = true, reverse = true}, + [4] = {foreground = Screen.colors.Grey100, background = Screen.colors.Red}, + [5] = {bold = true, foreground = Screen.colors.SeaGreen4}, }) screen:set_on_event_handler(function(name, data) if name == "cmdline_show" then @@ -157,24 +159,87 @@ describe('external cmdline', function() end) end) - it("redraws statusline on entering", function() - command('set laststatus=2') - command('set statusline=%{mode()}') - feed(':') - screen:expect([[ - | - {1:~ }| - {1:~ }| - {3:c^ }| - | - ]], nil, nil, function() - eq({{ - content = { { {}, "" } }, - firstc = ":", - indent = 0, - pos = 0, - prompt = "" - }}, cmdline) + describe("redraws statusline on entering", function() + before_each(function() + command('set laststatus=2') + command('set statusline=%{mode()}') + end) + + it('from normal mode', function() + feed(':') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {3:c^ }| + | + ]], nil, nil, function() + eq({{ + content = { { {}, "" } }, + firstc = ":", + indent = 0, + pos = 0, + prompt = "" + }}, cmdline) + end) + end) + + it('but not with scrolled messages', function() + screen:try_resize(50,10) + feed(':echoerr doesnotexist<cr>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {3: }| + {4:E121: Undefined variable: doesnotexist} | + {4:E15: Invalid expression: doesnotexist} | + {5:Press ENTER or type command to continue}^ | + ]]) + feed(':echoerr doesnotexist<cr>') + screen:expect([[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {3: }| + {4:E121: Undefined variable: doesnotexist} | + {4:E15: Invalid expression: doesnotexist} | + {4:E121: Undefined variable: doesnotexist} | + {4:E15: Invalid expression: doesnotexist} | + {5:Press ENTER or type command to continue}^ | + ]]) + + feed(':echoerr doesnotexist<cr>') + screen:expect([[ + | + {1:~ }| + {3: }| + {4:E121: Undefined variable: doesnotexist} | + {4:E15: Invalid expression: doesnotexist} | + {4:E121: Undefined variable: doesnotexist} | + {4:E15: Invalid expression: doesnotexist} | + {4:E121: Undefined variable: doesnotexist} | + {4:E15: Invalid expression: doesnotexist} | + {5:Press ENTER or type command to continue}^ | + ]]) + + feed('<cr>') + screen:expect([[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {3:n }| + | + ]]) end) end) diff --git a/test/functional/ui/wildmode_spec.lua b/test/functional/ui/wildmode_spec.lua index c6ddc78618..b60d520ca0 100644 --- a/test/functional/ui/wildmode_spec.lua +++ b/test/functional/ui/wildmode_spec.lua @@ -31,6 +31,29 @@ describe("'wildmenu'", function() ]]) end) + it(':sign <tab> <space> hides wildmenu #8453', function() + command('set wildmode=full') + -- only a regression if status-line open + command('set laststatus=2') + command('set wildmenu') + feed(':sign <tab>') + screen:expect([[ + | + ~ | + ~ | + define jump list > | + :sign define^ | + ]]) + feed('<space>') + screen:expect([[ + | + ~ | + ~ | + [No Name] | + :sign define ^ | + ]]) + end) + it('does not crash after cycling back to original text', function() command('set wildmode=full') feed(':j<Tab><Tab><Tab>') diff --git a/test/helpers.lua b/test/helpers.lua index 0d3fe1316b..a774a67df3 100644 --- a/test/helpers.lua +++ b/test/helpers.lua @@ -259,7 +259,7 @@ local function check_cores(app, force) else initial_path = '.' re = '/core[^/]*$' - exc_re = { '^/%.deps$', local_tmpdir } + exc_re = { '^/%.deps$', local_tmpdir, '^/%node_modules$' } db_cmd = gdb_db_cmd random_skip = true end diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt index 654cc5846f..adb3d73293 100644 --- a/third-party/CMakeLists.txt +++ b/third-party/CMakeLists.txt @@ -81,6 +81,15 @@ if(CMAKE_GENERATOR MATCHES "Makefiles") set(MAKE_PRG "$(MAKE)") endif() +if(MINGW AND CMAKE_GENERATOR MATCHES "Ninja") + find_program(MAKE_PRG NAMES mingw32-make) + if(NOT MAKE_PRG) + message(FATAL_ERROR "GNU Make for mingw32 is required to build the dependecies.") + else() + message(STATUS "Found GNU Make for mingw32 at ${MAKE_PRG}") + endif() +endif() + if(CMAKE_C_COMPILER_ARG1) set(DEPS_C_COMPILER "${CMAKE_C_COMPILER} ${CMAKE_C_COMPILER_ARG1}") else() @@ -118,8 +127,8 @@ set(LUA_URL https://www.lua.org/ftp/lua-5.1.5.tar.gz) set(LUA_SHA256 2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333) # NOTE: Version must match LUAROCKS_VERSION in third-party/cmake/BuildLuarocks.cmake -set(LUAROCKS_URL https://github.com/luarocks/luarocks/archive/v2.4.3.tar.gz) -set(LUAROCKS_SHA256 ea1881d6954f2a98c34f93674571c8f0cbdbc28dedb3fa3cb56b6a91886d1a99) +set(LUAROCKS_URL https://github.com/luarocks/luarocks/archive/v2.4.4.tar.gz) +set(LUAROCKS_SHA256 9eb3d0738fd02ad8bf39bcedccac4e83e9b5fff2bcca247c3584b925b2075d9c) set(UNIBILIUM_URL https://github.com/mauke/unibilium/archive/v2.0.0.tar.gz) set(UNIBILIUM_SHA256 78997d38d4c8177c60d3d0c1aa8c53fd0806eb21825b7b335b1768d7116bc1c1) @@ -148,16 +157,22 @@ set(WINGUI_SHA256 260efc686423e2529360b6a45c8e241fbbf276c8de6b04d44f45ab5b6fe8df set(WIN32YANK_X86_URL https://github.com/equalsraf/win32yank/releases/download/v0.0.4/win32yank-x86.zip) set(WIN32YANK_X86_SHA256 62f34e5a46c5d4a7b3f3b512e1ff7b77fedd432f42581cbe825233a996eed62c) - set(WIN32YANK_X86_64_URL https://github.com/equalsraf/win32yank/releases/download/v0.0.4/win32yank-x64.zip) set(WIN32YANK_X86_64_SHA256 33a747a92da60fb65e668edbf7661d3d902411a2d545fe9dc08623cecd142a20) set(WINPTY_URL https://github.com/rprichard/winpty/releases/download/0.4.3/winpty-0.4.3-msvc2015.zip) set(WINPTY_SHA256 35a48ece2ff4acdcbc8299d4920de53eb86b1fb41e64d2fe5ae7898931bcee89) +# gettext source (for building/linking, does NOT provide tools like msgmerge.exe) set(GETTEXT_URL https://ftp.gnu.org/pub/gnu/gettext/gettext-0.19.8.1.tar.gz) set(GETTEXT_SHA256 ff942af0e438ced4a8b0ea4b0b6e0d6d657157c5e2364de57baa279c1c125c43) +# gettext binary (for tools like msgmerge.exe) +set(GETTEXT_X86_URL https://github.com/mlocati/gettext-iconv-windows/releases/download/v0.19.8.1-v1.15/gettext0.19.8.1-iconv1.15-shared-32.zip) +set(GETTEXT_X86_SHA256 b7d8fe2d038950bc0447d664db614ebfc3100a1ba962a959d78e41bc708a2140) +set(GETTEXT_X86_64_URL https://github.com/mlocati/gettext-iconv-windows/releases/download/v0.19.8.1-v1.15/gettext0.19.8.1-iconv1.15-shared-64.zip) +set(GETTEXT_X86_64_SHA256 c8ed2897438efc0a511892c2b38b623ef0c9092aced2acbd3f3daf2f12ba70b4) + if(USE_BUNDLED_UNIBILIUM) include(BuildUnibilium) endif() @@ -220,6 +235,9 @@ if(WIN32) GetBinaryDep(TARGET "win32yank_${TARGET_ARCH}" INSTALL_COMMAND ${CMAKE_COMMAND} -E copy win32yank.exe ${DEPS_INSTALL_DIR}/bin) + GetBinaryDep(TARGET "gettext_${TARGET_ARCH}" + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory bin ${DEPS_INSTALL_DIR}/bin) + if("${TARGET_ARCH}" STREQUAL "X86_64") set(TARGET_ARCH x64) elseif(TARGET_ARCH STREQUAL "X86") diff --git a/third-party/cmake/BuildLibtermkey.cmake b/third-party/cmake/BuildLibtermkey.cmake index 8147c47e1e..0b56674ad2 100644 --- a/third-party/cmake/BuildLibtermkey.cmake +++ b/third-party/cmake/BuildLibtermkey.cmake @@ -14,6 +14,7 @@ ExternalProject_Add(libtermkey PATCH_COMMAND ${GIT_EXECUTABLE} -C ${DEPS_BUILD_DIR}/src/libtermkey init COMMAND ${GIT_EXECUTABLE} -C ${DEPS_BUILD_DIR}/src/libtermkey apply --ignore-whitespace ${CMAKE_CURRENT_SOURCE_DIR}/patches/libtermkey-Add-support-for-Windows.patch + ${CMAKE_CURRENT_SOURCE_DIR}/patches/libtermkey-Fix-escape-sequences-for-MSVC.patch CONFIGURE_COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/cmake/libtermkeyCMakeLists.txt ${DEPS_BUILD_DIR}/src/libtermkey/CMakeLists.txt diff --git a/third-party/cmake/BuildLibuv.cmake b/third-party/cmake/BuildLibuv.cmake index 084e707f92..e1aecdc43c 100644 --- a/third-party/cmake/BuildLibuv.cmake +++ b/third-party/cmake/BuildLibuv.cmake @@ -44,7 +44,7 @@ set(UNIX_CFGCMD sh ${DEPS_BUILD_DIR}/src/libuv/autogen.sh && set(LIBUV_PATCH_COMMAND ${GIT_EXECUTABLE} -C ${DEPS_BUILD_DIR}/src/libuv init - COMMAND ${GIT_EXECUTABLE} -C ${DEPS_BUILD_DIR}/src/libuv apply + COMMAND ${GIT_EXECUTABLE} -C ${DEPS_BUILD_DIR}/src/libuv apply --ignore-whitespace ${CMAKE_CURRENT_SOURCE_DIR}/patches/libuv-overlapped.patch) if(UNIX) @@ -64,21 +64,16 @@ elseif(MINGW AND CMAKE_CROSSCOMPILING) CONFIGURE_COMMAND ${UNIX_CFGCMD} --host=${CROSS_TARGET} INSTALL_COMMAND ${MAKE_PRG} V=1 install) -elseif(MINGW) - - # Native MinGW - BuildLibUv(BUILD_IN_SOURCE - PATCH_COMMAND ${LIBUV_PATCH_COMMAND} - BUILD_COMMAND ${CMAKE_MAKE_PROGRAM} -f Makefile.mingw - INSTALL_COMMAND ${CMAKE_COMMAND} -E make_directory ${DEPS_INSTALL_DIR}/lib - COMMAND ${CMAKE_COMMAND} -E copy ${DEPS_BUILD_DIR}/src/libuv/libuv.a ${DEPS_INSTALL_DIR}/lib - COMMAND ${CMAKE_COMMAND} -E make_directory ${DEPS_INSTALL_DIR}/include - COMMAND ${CMAKE_COMMAND} -E copy_directory ${DEPS_BUILD_DIR}/src/libuv/include ${DEPS_INSTALL_DIR}/include - ) - -elseif(WIN32 AND MSVC) +elseif(WIN32) set(UV_OUTPUT_DIR ${DEPS_BUILD_DIR}/src/libuv/${CMAKE_BUILD_TYPE}) + if(MSVC) + set(BUILD_SHARED ON) + elseif(MINGW) + set(BUILD_SHARED OFF) + else() + message(FATAL_ERROR "Trying to build libuv in an unsupported system ${CMAKE_SYSTEM_NAME}/${CMAKE_C_COMPILER_ID}") + endif() BuildLibUv(BUILD_IN_SOURCE PATCH_COMMAND ${LIBUV_PATCH_COMMAND} CONFIGURE_COMMAND ${CMAKE_COMMAND} -E copy @@ -88,16 +83,10 @@ elseif(WIN32 AND MSVC) -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_GENERATOR=${CMAKE_GENERATOR} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} - -DBUILD_SHARED_LIBS=ON + -DBUILD_SHARED_LIBS=${BUILD_SHARED} -DCMAKE_INSTALL_PREFIX=${DEPS_INSTALL_DIR} BUILD_COMMAND ${CMAKE_COMMAND} --build . --config ${CMAKE_BUILD_TYPE} - INSTALL_COMMAND ${CMAKE_COMMAND} --build . --target install --config ${CMAKE_BUILD_TYPE} - # Some applications (lua-client/luarocks) look for uv.lib instead of libuv.lib - COMMAND ${CMAKE_COMMAND} -E copy ${UV_OUTPUT_DIR}/libuv.lib ${DEPS_INSTALL_DIR}/lib/uv.lib - COMMAND ${CMAKE_COMMAND} -E copy ${UV_OUTPUT_DIR}/libuv.dll ${DEPS_INSTALL_DIR}/bin/ - COMMAND ${CMAKE_COMMAND} -E copy ${UV_OUTPUT_DIR}/libuv.dll ${DEPS_INSTALL_DIR}/bin/uv.dll - COMMAND ${CMAKE_COMMAND} -E make_directory ${DEPS_INSTALL_DIR}/include - COMMAND ${CMAKE_COMMAND} -E copy_directory ${DEPS_BUILD_DIR}/src/libuv/include ${DEPS_INSTALL_DIR}/include) + INSTALL_COMMAND ${CMAKE_COMMAND} --build . --target install --config ${CMAKE_BUILD_TYPE}) else() message(FATAL_ERROR "Trying to build libuv in an unsupported system ${CMAKE_SYSTEM_NAME}/${CMAKE_C_COMPILER_ID}") diff --git a/third-party/cmake/BuildLibvterm.cmake b/third-party/cmake/BuildLibvterm.cmake index e4649986af..4720581e52 100644 --- a/third-party/cmake/BuildLibvterm.cmake +++ b/third-party/cmake/BuildLibvterm.cmake @@ -39,7 +39,8 @@ if(WIN32) set(LIBVTERM_PATCH_COMMAND ${GIT_EXECUTABLE} -C ${DEPS_BUILD_DIR}/src/libvterm init COMMAND ${GIT_EXECUTABLE} -C ${DEPS_BUILD_DIR}/src/libvterm apply --ignore-whitespace - ${CMAKE_CURRENT_SOURCE_DIR}/patches/libvterm-Remove-VLAs-for-MSVC.patch) + ${CMAKE_CURRENT_SOURCE_DIR}/patches/libvterm-Remove-VLAs-for-MSVC.patch + ${CMAKE_CURRENT_SOURCE_DIR}/patches/libvterm-Fix-escape-sequences-for-MSVC.patch) endif() set(LIBVTERM_CONFIGURE_COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/cmake/LibvtermCMakeLists.txt diff --git a/third-party/cmake/BuildLuajit.cmake b/third-party/cmake/BuildLuajit.cmake index 2fda221b12..721bca9f63 100644 --- a/third-party/cmake/BuildLuajit.cmake +++ b/third-party/cmake/BuildLuajit.cmake @@ -78,8 +78,12 @@ elseif(MINGW AND CMAKE_CROSSCOMPILING) elseif(MINGW) - - BuildLuaJit(BUILD_COMMAND ${CMAKE_MAKE_PROGRAM} CC=${DEPS_C_COMPILER} + if(CMAKE_GENERATOR MATCHES "Ninja") + set(LUAJIT_MAKE_PRG ${MAKE_PRG}) + else() + set(LUAJIT_MAKE_PRG ${CMAKE_MAKE_PROGRAM}) + endif() + BuildLuaJit(BUILD_COMMAND ${LUAJIT_MAKE_PRG} CC=${DEPS_C_COMPILER} PREFIX=${DEPS_INSTALL_DIR} CFLAGS+=-DLUAJIT_DISABLE_JIT CFLAGS+=-DLUA_USE_APICHECK @@ -87,7 +91,7 @@ elseif(MINGW) CCDEBUG+=-g BUILDMODE=static # Build a DLL too - COMMAND ${CMAKE_MAKE_PROGRAM} CC=${DEPS_C_COMPILER} BUILDMODE=dynamic + COMMAND ${LUAJIT_MAKE_PRG} CC=${DEPS_C_COMPILER} BUILDMODE=dynamic INSTALL_COMMAND ${CMAKE_COMMAND} -E make_directory ${DEPS_INSTALL_DIR}/bin COMMAND ${CMAKE_COMMAND} -E copy ${DEPS_BUILD_DIR}/src/luajit/src/luajit.exe ${DEPS_INSTALL_DIR}/bin diff --git a/third-party/cmake/BuildLuarocks.cmake b/third-party/cmake/BuildLuarocks.cmake index b5fcf7f3e5..e0ea670be1 100644 --- a/third-party/cmake/BuildLuarocks.cmake +++ b/third-party/cmake/BuildLuarocks.cmake @@ -12,7 +12,7 @@ function(BuildLuarocks) cmake_parse_arguments(_luarocks "" "" - "PATCH_COMMAND;CONFIGURE_COMMAND;BUILD_COMMAND;INSTALL_COMMAND" + "CONFIGURE_COMMAND;BUILD_COMMAND;INSTALL_COMMAND" ${ARGN}) if(NOT _luarocks_CONFIGURE_COMMAND AND NOT _luarocks_BUILD_COMMAND @@ -32,7 +32,6 @@ function(BuildLuarocks) -DTARGET=luarocks -DUSE_EXISTING_SRC_DIR=${USE_EXISTING_SRC_DIR} -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/DownloadAndExtractFile.cmake - PATCH_COMMAND "${_luarocks_PATCH_COMMAND}" BUILD_IN_SOURCE 1 CONFIGURE_COMMAND "${_luarocks_CONFIGURE_COMMAND}" BUILD_COMMAND "${_luarocks_BUILD_COMMAND}" @@ -51,11 +50,6 @@ if(NOT MSVC) # version already knows, and passing them here breaks the build set(LUAROCKS_BUILDARGS CC=${HOSTDEPS_C_COMPILER} LD=${HOSTDEPS_C_COMPILER}) endif() -if(WIN32) - # Use our bundled curl.exe for downloading packages - set(LUAROCKS_BUILDARGS ${LUAROCKS_BUILDARGS} CURL=${DEPS_BIN_DIR}/curl.exe) -endif() - if(UNIX OR (MINGW AND CMAKE_CROSSCOMPILING)) @@ -82,12 +76,7 @@ elseif(MSVC OR MINGW) endif() # Ignore USE_BUNDLED_LUAJIT - always ON for native Win32 - BuildLuarocks( - PATCH_COMMAND - ${GIT_EXECUTABLE} -C ${DEPS_BUILD_DIR}/src/luarocks init - COMMAND ${GIT_EXECUTABLE} -C ${DEPS_BUILD_DIR}/src/luarocks apply --ignore-whitespace - ${CMAKE_CURRENT_SOURCE_DIR}/patches/luarocks-Change-default-downloader-to-curl.patch - INSTALL_COMMAND install.bat /FORCECONFIG /NOREG /NOADMIN /Q /F + BuildLuarocks(INSTALL_COMMAND install.bat /FORCECONFIG /NOREG /NOADMIN /Q /F /LUA ${DEPS_INSTALL_DIR} /LIB ${DEPS_LIB_DIR} /BIN ${DEPS_BIN_DIR} @@ -99,8 +88,6 @@ elseif(MSVC OR MINGW) /LUAMOD ${DEPS_BIN_DIR}/lua) set(LUAROCKS_BINARY ${DEPS_INSTALL_DIR}/${LUAROCKS_VERSION}/luarocks.bat) - add_dependencies(luarocks wintools) - else() message(FATAL_ERROR "Trying to build luarocks in an unsupported system ${CMAKE_SYSTEM_NAME}/${CMAKE_C_COMPILER_ID}") endif() diff --git a/third-party/cmake/BuildLuv.cmake b/third-party/cmake/BuildLuv.cmake index 339264746c..a62ee72f91 100644 --- a/third-party/cmake/BuildLuv.cmake +++ b/third-party/cmake/BuildLuv.cmake @@ -58,6 +58,12 @@ set(LUV_CONFIGURE_COMMAND_COMMON -DBUILD_SHARED_LIBS=OFF -DBUILD_MODULE=OFF) +if(USE_BUNDLED_LIBUV) + set(LUV_CONFIGURE_COMMAND_COMMON + ${LUV_CONFIGURE_COMMAND_COMMON} + -DCMAKE_PREFIX_PATH=${DEPS_INSTALL_DIR}) +endif() + if(MINGW AND CMAKE_CROSSCOMPILING) get_filename_component(TOOLCHAIN ${CMAKE_TOOLCHAIN_FILE} REALPATH) set(LUV_CONFIGURE_COMMAND diff --git a/third-party/cmake/LibuvCMakeLists.txt b/third-party/cmake/LibuvCMakeLists.txt index 063e4291f2..8b51a101c6 100644 --- a/third-party/cmake/LibuvCMakeLists.txt +++ b/third-party/cmake/LibuvCMakeLists.txt @@ -4,11 +4,13 @@ project(libuv LANGUAGES C) file(GLOB UV_SOURCES_COMMON src/*.c) file(GLOB UV_SOURCES_WIN src/win/*.c) -add_library(libuv ${UV_SOURCES_COMMON} ${UV_SOURCES_WIN}) -target_compile_definitions(libuv PRIVATE WIN32_LEAN_AND_MEAN "_WIN32_WINNT=0x0600") -target_link_libraries(libuv iphlpapi psapi shell32 userenv ws2_32) -target_include_directories(libuv PUBLIC ./include PRIVATE ./src) -set_target_properties(libuv PROPERTIES DEFINE_SYMBOL BUILDING_UV_SHARED) +add_library(uv ${UV_SOURCES_COMMON} ${UV_SOURCES_WIN}) +target_compile_definitions(uv PRIVATE WIN32_LEAN_AND_MEAN "_WIN32_WINNT=0x0600") +target_link_libraries(uv iphlpapi psapi shell32 userenv ws2_32) +target_include_directories(uv PUBLIC ./include PRIVATE ./src) +if(BUILD_SHARED_LIBS) + set_target_properties(uv PROPERTIES DEFINE_SYMBOL BUILDING_UV_SHARED) +endif() install(FILES include/tree.h @@ -20,8 +22,9 @@ install(FILES DESTINATION include) include(GNUInstallDirs) -install(TARGETS libuv +install(TARGETS uv PUBLIC_HEADER ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) diff --git a/third-party/patches/libtermkey-Fix-escape-sequences-for-MSVC.patch b/third-party/patches/libtermkey-Fix-escape-sequences-for-MSVC.patch new file mode 100644 index 0000000000..c1099bd3c4 --- /dev/null +++ b/third-party/patches/libtermkey-Fix-escape-sequences-for-MSVC.patch @@ -0,0 +1,189 @@ +diff --git a/t/30mouse.c b/t/30mouse.c +--- a/t/30mouse.c ++++ b/t/30mouse.c +@@ -14,7 +14,7 @@ int main(int argc, char *argv[]) + + tk = termkey_new_abstract("vt100", 0); + +- termkey_push_bytes(tk, "\e[M !!", 6); ++ termkey_push_bytes(tk, "\x1b[M !!", 6); + + key.type = -1; + is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY for mouse press"); +@@ -38,7 +38,7 @@ int main(int argc, char *argv[]) + is_int(len, 21, "string length for press"); + is_str(buffer, "MousePress(1) @ (1,1)", "string buffer for press"); + +- termkey_push_bytes(tk, "\e[M@\"!", 6); ++ termkey_push_bytes(tk, "\x1b[M@\"!", 6); + + key.type = -1; + ev = -1; button = -1; line = -1; col = -1; +@@ -51,7 +51,7 @@ int main(int argc, char *argv[]) + is_int(col, 2, "mouse column for drag"); + is_int(key.modifiers, 0, "modifiers for press"); + +- termkey_push_bytes(tk, "\e[M##!", 6); ++ termkey_push_bytes(tk, "\x1b[M##!", 6); + + key.type = -1; + ev = -1; button = -1; line = -1; col = -1; +@@ -63,7 +63,7 @@ int main(int argc, char *argv[]) + is_int(col, 3, "mouse column for release"); + is_int(key.modifiers, 0, "modifiers for press"); + +- termkey_push_bytes(tk, "\e[M0++", 6); ++ termkey_push_bytes(tk, "\x1b[M0++", 6); + + key.type = -1; + ev = -1; button = -1; line = -1; col = -1; +@@ -81,7 +81,7 @@ int main(int argc, char *argv[]) + is_str(buffer, "C-MousePress(1)", "string buffer for Ctrl-press"); + + // rxvt protocol +- termkey_push_bytes(tk, "\e[0;20;20M", 10); ++ termkey_push_bytes(tk, "\x1b[0;20;20M", 10); + + key.type = -1; + is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY for mouse press rxvt protocol"); +@@ -96,7 +96,7 @@ int main(int argc, char *argv[]) + is_int(col, 20, "mouse column for press rxvt protocol"); + is_int(key.modifiers, 0, "modifiers for press rxvt protocol"); + +- termkey_push_bytes(tk, "\e[3;20;20M", 10); ++ termkey_push_bytes(tk, "\x1b[3;20;20M", 10); + + is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY for mouse release rxvt protocol"); + +@@ -111,7 +111,7 @@ int main(int argc, char *argv[]) + is_int(key.modifiers, 0, "modifiers for release rxvt protocol"); + + // SGR protocol +- termkey_push_bytes(tk, "\e[<0;30;30M", 11); ++ termkey_push_bytes(tk, "\x1b[<0;30;30M", 11); + + key.type = -1; + is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY for mouse press SGR encoding"); +@@ -127,7 +127,7 @@ int main(int argc, char *argv[]) + is_int(col, 30, "mouse column for press SGR"); + is_int(key.modifiers, 0, "modifiers for press SGR"); + +- termkey_push_bytes(tk, "\e[<0;30;30m", 11); ++ termkey_push_bytes(tk, "\x1b[<0;30;30m", 11); + + key.type = -1; + is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY for mouse release SGR encoding"); +@@ -139,7 +139,7 @@ int main(int argc, char *argv[]) + + is_int(ev, TERMKEY_MOUSE_RELEASE, "mouse event for release SGR"); + +- termkey_push_bytes(tk, "\e[<0;500;300M", 13); ++ termkey_push_bytes(tk, "\x1b[<0;500;300M", 13); + + key.type = -1; + ev = -1; button = -1; line = -1; col = -1; +diff --git a/t/31position.c b/t/31position.c +index 1748211..86ad1bc 100644 +--- a/t/31position.c ++++ b/t/31position.c +@@ -11,7 +11,7 @@ int main(int argc, char *argv[]) + + tk = termkey_new_abstract("vt100", 0); + +- termkey_push_bytes(tk, "\e[?15;7R", 8); ++ termkey_push_bytes(tk, "\x1b[?15;7R", 8); + + is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY for position report"); + +@@ -25,7 +25,7 @@ int main(int argc, char *argv[]) + /* A plain CSI R is likely to be <F3> though. + * This is tricky :/ + */ +- termkey_push_bytes(tk, "\e[R", 3); ++ termkey_push_bytes(tk, "\x1b[R", 3); + + is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY for <F3>"); + +diff --git a/t/32modereport.c b/t/32modereport.c +index 31de400..5e49705 100644 +--- a/t/32modereport.c ++++ b/t/32modereport.c +@@ -11,7 +11,7 @@ int main(int argc, char *argv[]) + + tk = termkey_new_abstract("vt100", 0); + +- termkey_push_bytes(tk, "\e[?1;2$y", 8); ++ termkey_push_bytes(tk, "\x1b[?1;2$y", 8); + + is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY for mode report"); + +@@ -23,7 +23,7 @@ int main(int argc, char *argv[]) + is_int(mode, 1, "mode number from mode report"); + is_int(value, 2, "mode value from mode report"); + +- termkey_push_bytes(tk, "\e[4;1$y", 7); ++ termkey_push_bytes(tk, "\x1b[4;1$y", 7); + + is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY for mode report"); + +diff --git a/t/38csi.c b/t/38csi.c +index 9d186f6..fd592d5 100644 +--- a/t/38csi.c ++++ b/t/38csi.c +@@ -13,7 +13,7 @@ int main(int argc, char *argv[]) + + tk = termkey_new_abstract("vt100", 0); + +- termkey_push_bytes(tk, "\e[5;25v", 7); ++ termkey_push_bytes(tk, "\x1b[5;25v", 7); + + is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY for CSI v"); + +@@ -26,14 +26,14 @@ int main(int argc, char *argv[]) + is_int(args[1], 25, "args[1] for unknown CSI"); + is_int(command, 'v', "command for unknown CSI"); + +- termkey_push_bytes(tk, "\e[?w", 4); ++ termkey_push_bytes(tk, "\x1b[?w", 4); + + is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY for CSI ? w"); + is_int(key.type, TERMKEY_TYPE_UNKNOWN_CSI, "key.type for unknown CSI"); + is_int(termkey_interpret_csi(tk, &key, args, &nargs, &command), TERMKEY_RES_KEY, "interpret_csi yields RES_KEY"); + is_int(command, '?'<<8 | 'w', "command for unknown CSI"); + +- termkey_push_bytes(tk, "\e[?$x", 5); ++ termkey_push_bytes(tk, "\x1b[?$x", 5); + + is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY for CSI ? $x"); + is_int(key.type, TERMKEY_TYPE_UNKNOWN_CSI, "key.type for unknown CSI"); +diff --git a/t/39dcs.c b/t/39dcs.c +index c517411..f065477 100644 +--- a/t/39dcs.c ++++ b/t/39dcs.c +@@ -12,7 +12,7 @@ int main(int argc, char *argv[]) + tk = termkey_new_abstract("xterm", 0); + + // 7bit DCS +- termkey_push_bytes(tk, "\eP1$r1 q\e\\", 10); ++ termkey_push_bytes(tk, "\x1bP1$r1 q\x1b\\", 10); + + is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY for DCS"); + +@@ -38,7 +38,7 @@ int main(int argc, char *argv[]) + is_int(termkey_getkey(tk, &key), TERMKEY_RES_NONE, "getkey again yields RES_NONE"); + + // 7bit OSC +- termkey_push_bytes(tk, "\e]15;abc\e\\", 10); ++ termkey_push_bytes(tk, "\x1b]15;abc\x1b\\", 10); + + is_int(termkey_getkey(tk, &key), TERMKEY_RES_KEY, "getkey yields RES_KEY for OSC"); + +@@ -51,7 +51,7 @@ int main(int argc, char *argv[]) + is_int(termkey_getkey(tk, &key), TERMKEY_RES_NONE, "getkey again yields RES_NONE"); + + // False alarm +- termkey_push_bytes(tk, "\eP", 2); ++ termkey_push_bytes(tk, "\x1bP", 2); + + is_int(termkey_getkey(tk, &key), TERMKEY_RES_AGAIN, "getkey yields RES_AGAIN for false alarm"); + diff --git a/third-party/patches/libvterm-Fix-escape-sequences-for-MSVC.patch b/third-party/patches/libvterm-Fix-escape-sequences-for-MSVC.patch new file mode 100644 index 0000000000..b2f0809544 --- /dev/null +++ b/third-party/patches/libvterm-Fix-escape-sequences-for-MSVC.patch @@ -0,0 +1,53 @@ +diff --git a/src/keyboard.c b/src/keyboard.c +index bc1299b..5f368f4 100644 +--- a/src/keyboard.c ++++ b/src/keyboard.c +@@ -48,7 +48,7 @@ void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod) + if(mod & VTERM_MOD_CTRL) + c &= 0x1f; + +- vterm_push_output_sprintf(vt, "%s%c", mod & VTERM_MOD_ALT ? "\e" : "", c); ++ vterm_push_output_sprintf(vt, "%s%c", mod & VTERM_MOD_ALT ? "\x1b" : "", c); + } + + typedef struct { +@@ -73,7 +73,7 @@ static keycodes_s keycodes[] = { + { KEYCODE_ENTER, '\r' }, // ENTER + { KEYCODE_TAB, '\t' }, // TAB + { KEYCODE_LITERAL, '\x7f' }, // BACKSPACE == ASCII DEL +- { KEYCODE_LITERAL, '\e' }, // ESCAPE ++ { KEYCODE_LITERAL, '\x1b' }, // ESCAPE + + { KEYCODE_CSI_CURSOR, 'A' }, // UP + { KEYCODE_CSI_CURSOR, 'B' }, // DOWN +@@ -173,7 +173,7 @@ void vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod) + if(mod & (VTERM_MOD_SHIFT|VTERM_MOD_CTRL)) + vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%du", k.literal, mod+1); + else +- vterm_push_output_sprintf(vt, mod & VTERM_MOD_ALT ? "\e%c" : "%c", k.literal); ++ vterm_push_output_sprintf(vt, mod & VTERM_MOD_ALT ? "\x1b%c" : "%c", k.literal); + break; + + case KEYCODE_SS3: case_SS3: +diff --git a/src/vterm.c b/src/vterm.c +index 826df93..262b3fc 100644 +--- a/src/vterm.c ++++ b/src/vterm.c +@@ -158,7 +158,7 @@ INTERNAL void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, cons + size_t orig_cur = vt->outbuffer_cur; + + if(ctrl >= 0x80 && !vt->mode.ctrl8bit) +- vterm_push_output_sprintf(vt, "\e%c", ctrl - 0x40); ++ vterm_push_output_sprintf(vt, "\x1b%c", ctrl - 0x40); + else + vterm_push_output_sprintf(vt, "%c", ctrl); + +@@ -176,7 +176,7 @@ INTERNAL void vterm_push_output_sprintf_dcs(VTerm *vt, const char *fmt, ...) + size_t orig_cur = vt->outbuffer_cur; + + if(!vt->mode.ctrl8bit) +- vterm_push_output_sprintf(vt, "\e%c", C1_DCS - 0x40); ++ vterm_push_output_sprintf(vt, "\x1b%c", C1_DCS - 0x40); + else + vterm_push_output_sprintf(vt, "%c", C1_DCS); + diff --git a/third-party/patches/luarocks-Change-default-downloader-to-curl.patch b/third-party/patches/luarocks-Change-default-downloader-to-curl.patch deleted file mode 100644 index b7109a3b53..0000000000 --- a/third-party/patches/luarocks-Change-default-downloader-to-curl.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 69313032fad04743c96bc8f2a029b691857488f9 Mon Sep 17 00:00:00 2001 -Date: Thu, 1 Mar 2018 21:41:29 -0600 -Subject: [PATCH] Change default downloader to curl - ---- - install.bat | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/install.bat b/install.bat -index 09cf9aa..76e4059 100644 ---- a/install.bat -+++ b/install.bat -@@ -1037,7 +1037,7 @@ f:write(S[=[ - site_config.LUAROCKS_UNAME_M=[[$UNAME_M]] - site_config.LUAROCKS_ROCKS_TREE=[[$TREE_ROOT]] - site_config.LUAROCKS_PREFIX=[[$PREFIX]] --site_config.LUAROCKS_DOWNLOADER=[[wget]] -+site_config.LUAROCKS_DOWNLOADER=[[curl]] - site_config.LUAROCKS_MD5CHECKER=[[md5sum]] - ]=]) - if FORCE_CONFIG then --- -2.16.1.windows.4 - |