diff options
34 files changed, 1186 insertions, 1025 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 223e2ad111..1334dececd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,8 +30,6 @@ include(Util) set(TOUCHES_DIR ${PROJECT_BINARY_DIR}/touches) -set_property(GLOBAL PROPERTY USE_FOLDERS ON) - find_program(CCACHE_PRG ccache) if(CCACHE_PRG) set(CMAKE_C_COMPILER_LAUNCHER ${CMAKE_COMMAND} -E env CCACHE_SLOPPINESS=pch_defines,time_macros ${CCACHE_PRG}) @@ -72,7 +70,7 @@ endif() list(INSERT CMAKE_PREFIX_PATH 0 ${DEPS_PREFIX}) -if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") +if(APPLE) # If the macOS deployment target is not set manually (via $MACOSX_DEPLOYMENT_TARGET), # fall back to local system version. Needs to be done both here and in cmake.deps. if(NOT CMAKE_OSX_DEPLOYMENT_TARGET) @@ -84,7 +82,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") message(STATUS "Using deployment target ${CMAKE_OSX_DEPLOYMENT_TARGET}") endif() -if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Darwin") +if(WIN32 OR APPLE) # Ignore case when comparing filenames on Windows and Mac. set(CASE_INSENSITIVE_FILENAME TRUE) # Enable fixing case-insensitive filenames for Windows and Mac. @@ -259,7 +257,7 @@ add_glob_target( TARGET lintsh COMMAND ${SHELLCHECK_PRG} FLAGS -x -a - GLOB_DIRS scripts ci + GLOB_DIRS scripts GLOB_PAT *.sh EXCLUDE scripts/pvscheck.sh @@ -53,7 +53,6 @@ ifeq (,$(BUILD_TOOL)) endif endif - # Only need to handle Ninja here. Make will inherit the VERBOSE variable, and the -j, -l, and -n flags. ifeq ($(CMAKE_GENERATOR),Ninja) ifneq ($(VERBOSE),) diff --git a/cmake.deps/CMakeLists.txt b/cmake.deps/CMakeLists.txt index 6c71173766..a9a3f45319 100644 --- a/cmake.deps/CMakeLists.txt +++ b/cmake.deps/CMakeLists.txt @@ -118,7 +118,7 @@ endif() # If the macOS deployment target is not set manually (via $MACOSX_DEPLOYMENT_TARGET), # fall back to local system version. Needs to be done here and in top-level CMakeLists.txt. -if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") +if(APPLE) if(NOT CMAKE_OSX_DEPLOYMENT_TARGET) execute_process(COMMAND sw_vers -productVersion OUTPUT_VARIABLE MACOS_VERSION @@ -156,7 +156,6 @@ set(LIBTERMKEY_SHA256 6945bd3c4aaa83da83d80a045c5563da4edd7d0374c62c0d35aec09eb3 set(LIBVTERM_URL https://www.leonerd.org.uk/code/libvterm/libvterm-0.3.1.tar.gz) set(LIBVTERM_SHA256 25a8ad9c15485368dfd0a8a9dca1aec8fea5c27da3fa74ec518d5d3787f0c397) -set(LUV_VERSION 1.44.2-1) set(LUV_URL https://github.com/luvit/luv/archive/e8e7b7e13225348a8806118a3ea9e021383a9536.tar.gz) set(LUV_SHA256 531dfbcb6fffe3fdfa806860b39035e54b07ee1ff3bb2af813e175febf7e9ccc) diff --git a/cmake.deps/cmake/BuildLua.cmake b/cmake.deps/cmake/BuildLua.cmake index 759211b653..c819b8661a 100644 --- a/cmake.deps/cmake/BuildLua.cmake +++ b/cmake.deps/cmake/BuildLua.cmake @@ -1,6 +1,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux") set(LUA_TARGET linux) -elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") +elseif(APPLE) set(LUA_TARGET macosx) elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") set(LUA_TARGET freebsd) diff --git a/cmake.deps/cmake/BuildLuajit.cmake b/cmake.deps/cmake/BuildLuajit.cmake index 8c6b321a32..0c882d5fd2 100644 --- a/cmake.deps/cmake/BuildLuajit.cmake +++ b/cmake.deps/cmake/BuildLuajit.cmake @@ -38,7 +38,7 @@ function(BuildLuajit) endfunction() check_c_compiler_flag(-fno-stack-check HAS_NO_STACK_CHECK) -if(CMAKE_SYSTEM_NAME MATCHES "Darwin" AND HAS_NO_STACK_CHECK) +if(APPLE AND HAS_NO_STACK_CHECK) set(NO_STACK_CHECK "CFLAGS+=-fno-stack-check") else() set(NO_STACK_CHECK "") @@ -58,7 +58,7 @@ set(BUILDCMD_UNIX ${MAKE_PRG} -j CFLAGS=-fPIC # Setting MACOSX_DEPLOYMENT_TARGET is mandatory for LuaJIT; use version set by # cmake.deps/CMakeLists.txt (either environment variable or current system version). -if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") +if(APPLE) set(DEPLOYMENT_TARGET "MACOSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}") endif() diff --git a/cmake.deps/cmake/BuildLuarocks.cmake b/cmake.deps/cmake/BuildLuarocks.cmake index cd5aa1ed34..ad0ee3f661 100644 --- a/cmake.deps/cmake/BuildLuarocks.cmake +++ b/cmake.deps/cmake/BuildLuarocks.cmake @@ -30,7 +30,7 @@ if(UNIX) list(APPEND LUAROCKS_OPTS --with-lua=${DEPS_INSTALL_DIR}) else() - find_package(LuaJit) + find_package(Luajit) if(LUAJIT_FOUND) list(APPEND LUAROCKS_OPTS --with-lua-include=${LUAJIT_INCLUDE_DIRS} diff --git a/cmake.deps/cmake/BuildLuv.cmake b/cmake.deps/cmake/BuildLuv.cmake index 0cb0208bea..c5f38fe68b 100644 --- a/cmake.deps/cmake/BuildLuv.cmake +++ b/cmake.deps/cmake/BuildLuv.cmake @@ -14,7 +14,7 @@ if(USE_BUNDLED_LUAJIT) elseif(USE_BUNDLED_LUA) list(APPEND LUV_CMAKE_ARGS -D WITH_LUA_ENGINE=Lua) else() - find_package(LuaJit) + find_package(Luajit) if(LUAJIT_FOUND) list(APPEND LUV_CMAKE_ARGS -D WITH_LUA_ENGINE=LuaJit) else() @@ -23,9 +23,7 @@ else() endif() if(USE_BUNDLED_LIBUV) - list(APPEND LUV_CMAKE_ARGS - -D CMAKE_PREFIX_PATH=${DEPS_INSTALL_DIR} - -D LIBUV_LIBRARIES=uv_a) + list(APPEND LUV_CMAKE_ARGS -D CMAKE_PREFIX_PATH=${DEPS_INSTALL_DIR}) endif() list(APPEND LUV_CMAKE_ARGS diff --git a/cmake/FindIconv.cmake b/cmake/FindIconv.cmake index b0ffa1bd75..48c1514ff2 100644 --- a/cmake/FindIconv.cmake +++ b/cmake/FindIconv.cmake @@ -6,3 +6,9 @@ find_library(ICONV_LIBRARY NAMES iconv libiconv) find_package_handle_standard_args(Iconv DEFAULT_MSG ICONV_INCLUDE_DIR) mark_as_advanced(ICONV_INCLUDE_DIR ICONV_LIBRARY) + +add_library(iconv INTERFACE) +target_include_directories(iconv SYSTEM BEFORE INTERFACE ${ICONV_INCLUDE_DIR}) +if(ICONV_LIBRARY) + target_link_libraries(iconv INTERFACE ${ICONV_LIBRARY}) +endif() diff --git a/cmake/FindLibTermkey.cmake b/cmake/FindLibTermkey.cmake deleted file mode 100644 index 368cd21354..0000000000 --- a/cmake/FindLibTermkey.cmake +++ /dev/null @@ -1,5 +0,0 @@ -find_path(LIBTERMKEY_INCLUDE_DIR termkey.h) -find_library(LIBTERMKEY_LIBRARY NAMES termkey) -find_package_handle_standard_args(LibTermkey DEFAULT_MSG - LIBTERMKEY_LIBRARY LIBTERMKEY_INCLUDE_DIR) -mark_as_advanced(LIBTERMKEY_INCLUDE_DIR LIBTERMKEY_LIBRARY) diff --git a/cmake/FindLibIntl.cmake b/cmake/FindLibintl.cmake index 8b512e5a7e..630a3545fc 100644 --- a/cmake/FindLibIntl.cmake +++ b/cmake/FindLibintl.cmake @@ -3,32 +3,32 @@ include(CheckVariableExists) # Append custom gettext path to CMAKE_PREFIX_PATH # if installed via Mac Homebrew -if (CMAKE_HOST_APPLE) - find_program(HOMEBREW_PROG brew) - if (EXISTS ${HOMEBREW_PROG}) - execute_process(COMMAND ${HOMEBREW_PROG} --prefix gettext +if (APPLE) + find_program(HOMEBREW_PRG brew) + if (EXISTS ${HOMEBREW_PRG}) + execute_process(COMMAND ${HOMEBREW_PRG} --prefix gettext OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE HOMEBREW_GETTEXT_PREFIX) list(APPEND CMAKE_PREFIX_PATH "${HOMEBREW_GETTEXT_PREFIX}") endif() endif() -find_path(LibIntl_INCLUDE_DIR +find_path(LIBINTL_INCLUDE_DIR NAMES libintl.h PATH_SUFFIXES gettext ) -find_library(LibIntl_LIBRARY +find_library(LIBINTL_LIBRARY NAMES intl libintl ) -if (LibIntl_INCLUDE_DIR) - list(APPEND CMAKE_REQUIRED_INCLUDES "${LibIntl_INCLUDE_DIR}") +if (LIBINTL_INCLUDE_DIR) + list(APPEND CMAKE_REQUIRED_INCLUDES "${LIBINTL_INCLUDE_DIR}") endif() # On some systems (linux+glibc) libintl is passively available. # So only specify the library if one was found. -if (LibIntl_LIBRARY) - list(APPEND CMAKE_REQUIRED_LIBRARIES "${LibIntl_LIBRARY}") +if (LIBINTL_LIBRARY) + list(APPEND CMAKE_REQUIRED_LIBRARIES "${LIBINTL_LIBRARY}") endif() if (MSVC) list(APPEND CMAKE_REQUIRED_LIBRARIES ${ICONV_LIBRARY}) @@ -36,7 +36,7 @@ endif() # On macOS, if libintl is a static library then we also need # to link libiconv and CoreFoundation. -get_filename_component(LibIntl_EXT "${LibIntl_LIBRARY}" EXT) +get_filename_component(LibIntl_EXT "${LIBINTL_LIBRARY}" EXT) if (APPLE AND (LibIntl_EXT STREQUAL ".a")) set(LibIntl_STATIC TRUE) find_library(CoreFoundation_FRAMEWORK CoreFoundation) @@ -59,14 +59,14 @@ endif() if (LibIntl_STATIC) list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES "${ICONV_LIBRARY}" "${CoreFoundation_FRAMEWORK}") endif() -if (LibIntl_INCLUDE_DIR) - list(REMOVE_ITEM CMAKE_REQUIRED_INCLUDES "${LibIntl_INCLUDE_DIR}") +if (LIBINTL_INCLUDE_DIR) + list(REMOVE_ITEM CMAKE_REQUIRED_INCLUDES "${LIBINTL_INCLUDE_DIR}") endif() -if (LibIntl_LIBRARY) - list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES "${LibIntl_LIBRARY}") +if (LIBINTL_LIBRARY) + list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES "${LIBINTL_LIBRARY}") endif() -set(REQUIRED_VARIABLES LibIntl_LIBRARY LIBTERMKEY_INCLUDE_DIR) +set(REQUIRED_VARIABLES LIBINTL_LIBRARY LIBINTL_INCLUDE_DIR) if (HAVE_WORKING_LIBINTL) # On some systems (linux+glibc) libintl is passively available. # If HAVE_WORKING_LIBINTL then we consider the requirement satisfied. @@ -75,6 +75,6 @@ if (HAVE_WORKING_LIBINTL) check_variable_exists(_nl_msg_cat_cntr HAVE_NL_MSG_CAT_CNTR) endif() -find_package_handle_standard_args(LibIntl DEFAULT_MSG +find_package_handle_standard_args(Libintl DEFAULT_MSG ${REQUIRED_VARIABLES}) -mark_as_advanced(LIBTERMKEY_INCLUDE_DIR LIBTERMKEY_LIBRARY) +mark_as_advanced(LIBINTL_LIBRARY LIBINTL_INCLUDE_DIR) diff --git a/cmake/FindLibLUV.cmake b/cmake/FindLibluv.cmake index 94d706e1fc..9a74d5d0e1 100644 --- a/cmake/FindLibLUV.cmake +++ b/cmake/FindLibluv.cmake @@ -8,7 +8,7 @@ find_library(LIBLUV_LIBRARY NAMES ${LIBLUV_NAMES}) set(LIBLUV_LIBRARIES ${LIBLUV_LIBRARY}) set(LIBLUV_INCLUDE_DIRS ${LIBLUV_INCLUDE_DIR}) -find_package_handle_standard_args(LibLUV DEFAULT_MSG +find_package_handle_standard_args(Libluv DEFAULT_MSG LIBLUV_LIBRARY LIBLUV_INCLUDE_DIR) mark_as_advanced(LIBLUV_INCLUDE_DIR LIBLUV_LIBRARY) diff --git a/cmake/FindLibtermkey.cmake b/cmake/FindLibtermkey.cmake new file mode 100644 index 0000000000..1fc8ac78f2 --- /dev/null +++ b/cmake/FindLibtermkey.cmake @@ -0,0 +1,9 @@ +find_path(LIBTERMKEY_INCLUDE_DIR termkey.h) +find_library(LIBTERMKEY_LIBRARY NAMES termkey) +find_package_handle_standard_args(Libtermkey DEFAULT_MSG + LIBTERMKEY_LIBRARY LIBTERMKEY_INCLUDE_DIR) +mark_as_advanced(LIBTERMKEY_INCLUDE_DIR LIBTERMKEY_LIBRARY) + +add_library(libtermkey INTERFACE) +target_include_directories(libtermkey SYSTEM BEFORE INTERFACE ${LIBTERMKEY_INCLUDE_DIR}) +target_link_libraries(libtermkey INTERFACE ${LIBTERMKEY_LIBRARY}) diff --git a/cmake/FindLibUV.cmake b/cmake/FindLibuv.cmake index a134ca0917..0f6e80d915 100644 --- a/cmake/FindLibUV.cmake +++ b/cmake/FindLibuv.cmake @@ -63,7 +63,7 @@ if(Threads_FOUND) list(APPEND LIBUV_LIBRARIES ${CMAKE_THREAD_LIBS_INIT}) endif() -find_package_handle_standard_args(LibUV DEFAULT_MSG +find_package_handle_standard_args(Libuv DEFAULT_MSG LIBUV_LIBRARY LIBUV_INCLUDE_DIR) mark_as_advanced(LIBUV_INCLUDE_DIR LIBUV_LIBRARY) diff --git a/cmake/Findlibvterm.cmake b/cmake/FindLibvterm.cmake index 4a2ae48ffa..ad2e682b30 100644 --- a/cmake/Findlibvterm.cmake +++ b/cmake/FindLibvterm.cmake @@ -11,7 +11,7 @@ if(LIBVTERM_INCLUDE_DIR AND EXISTS "${LIBVTERM_INCLUDE_DIR}/vterm.h") set(VTERM_VERSION ${VTERM_VERSION_MAJOR}.${VTERM_VERSION_MINOR}) endif() -find_package_handle_standard_args(libvterm +find_package_handle_standard_args(Libvterm REQUIRED_VARS LIBVTERM_INCLUDE_DIR LIBVTERM_LIBRARY VERSION_VAR VTERM_VERSION) diff --git a/cmake/FindLuaJit.cmake b/cmake/FindLuajit.cmake index e3f47eee83..924e4c80d4 100644 --- a/cmake/FindLuaJit.cmake +++ b/cmake/FindLuajit.cmake @@ -14,7 +14,7 @@ find_library(LUAJIT_LIBRARY NAMES ${LUAJIT_NAMES}) set(LUAJIT_LIBRARIES ${LUAJIT_LIBRARY}) set(LUAJIT_INCLUDE_DIRS ${LUAJIT_INCLUDE_DIR}) -find_package_handle_standard_args(LuaJit DEFAULT_MSG +find_package_handle_standard_args(Luajit DEFAULT_MSG LUAJIT_LIBRARY LUAJIT_INCLUDE_DIR) mark_as_advanced(LUAJIT_INCLUDE_DIR LUAJIT_LIBRARY) diff --git a/cmake/FindMsgpack.cmake b/cmake/FindMsgpack.cmake index 8187bce08d..43c4c3c16b 100644 --- a/cmake/FindMsgpack.cmake +++ b/cmake/FindMsgpack.cmake @@ -22,9 +22,25 @@ find_library(MSGPACK_LIBRARY NAMES ${MSGPACK_NAMES} mark_as_advanced(MSGPACK_INCLUDE_DIR MSGPACK_LIBRARY) -set(MSGPACK_LIBRARIES ${MSGPACK_LIBRARY}) -set(MSGPACK_INCLUDE_DIRS ${MSGPACK_INCLUDE_DIR}) - find_package_handle_standard_args(Msgpack REQUIRED_VARS MSGPACK_LIBRARY MSGPACK_INCLUDE_DIR VERSION_VAR MSGPACK_VERSION_STRING) + +add_library(msgpack INTERFACE) +target_include_directories(msgpack SYSTEM BEFORE INTERFACE ${MSGPACK_INCLUDE_DIR}) +target_link_libraries(msgpack INTERFACE ${MSGPACK_LIBRARY}) + +list(APPEND CMAKE_REQUIRED_INCLUDES "${MSGPACK_INCLUDE_DIR}") +check_c_source_compiles(" +#include <msgpack.h> + +int +main(void) +{ + return MSGPACK_OBJECT_FLOAT32; +} +" MSGPACK_HAS_FLOAT32) +list(REMOVE_ITEM CMAKE_REQUIRED_INCLUDES "${MSGPACK_INCLUDE_DIR}") +if(MSGPACK_HAS_FLOAT32) + target_compile_definitions(msgpack INTERFACE NVIM_MSGPACK_HAS_FLOAT32) +endif() diff --git a/cmake/FindTreeSitter.cmake b/cmake/FindTreeSitter.cmake deleted file mode 100644 index 2850a61b57..0000000000 --- a/cmake/FindTreeSitter.cmake +++ /dev/null @@ -1,5 +0,0 @@ -find_path(TreeSitter_INCLUDE_DIR tree_sitter/api.h) -find_library(TreeSitter_LIBRARY NAMES tree-sitter) -find_package_handle_standard_args(TreeSitter DEFAULT_MSG - TreeSitter_LIBRARY TreeSitter_INCLUDE_DIR) -mark_as_advanced(TreeSitter_LIBRARY TreeSitter_INCLUDE_DIR) diff --git a/cmake/FindTreesitter.cmake b/cmake/FindTreesitter.cmake new file mode 100644 index 0000000000..ef308ad5e1 --- /dev/null +++ b/cmake/FindTreesitter.cmake @@ -0,0 +1,40 @@ +find_path(TREESITTER_INCLUDE_DIR tree_sitter/api.h) +find_library(TREESITTER_LIBRARY NAMES tree-sitter) +find_package_handle_standard_args(Treesitter DEFAULT_MSG + TREESITTER_LIBRARY TREESITTER_INCLUDE_DIR) +mark_as_advanced(TREESITTER_LIBRARY TREESITTER_INCLUDE_DIR) + +add_library(treesitter INTERFACE) +target_include_directories(treesitter SYSTEM BEFORE INTERFACE ${TREESITTER_INCLUDE_DIR}) +target_link_libraries(treesitter INTERFACE ${TREESITTER_LIBRARY}) + +list(APPEND CMAKE_REQUIRED_INCLUDES "${TREESITTER_INCLUDE_DIR}") +list(APPEND CMAKE_REQUIRED_LIBRARIES "${TREESITTER_LIBRARY}") +check_c_source_compiles(" +#include <tree_sitter/api.h> +int +main(void) +{ + TSQueryCursor *cursor = ts_query_cursor_new(); + ts_query_cursor_set_match_limit(cursor, 32); + return 0; +} +" TS_HAS_SET_MATCH_LIMIT) +if(TS_HAS_SET_MATCH_LIMIT) + target_compile_definitions(treesitter INTERFACE NVIM_TS_HAS_SET_MATCH_LIMIT) +endif() +check_c_source_compiles(" +#include <stdlib.h> +#include <tree_sitter/api.h> +int +main(void) +{ + ts_set_allocator(malloc, calloc, realloc, free); + return 0; +} +" TS_HAS_SET_ALLOCATOR) +if(TS_HAS_SET_ALLOCATOR) + target_compile_definitions(treesitter INTERFACE NVIM_TS_HAS_SET_ALLOCATOR) +endif() +list(REMOVE_ITEM CMAKE_REQUIRED_INCLUDES "${TREESITTER_INCLUDE_DIR}") +list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES "${TREESITTER_LIBRARY}") diff --git a/cmake/Findunibilium.cmake b/cmake/FindUnibilium.cmake index 3dbac31b5b..35a9016b19 100644 --- a/cmake/Findunibilium.cmake +++ b/cmake/FindUnibilium.cmake @@ -1,7 +1,7 @@ find_path(UNIBILIUM_INCLUDE_DIR unibilium.h) find_library(UNIBILIUM_LIBRARY unibilium) -find_package_handle_standard_args(unibilium +find_package_handle_standard_args(Unibilium REQUIRED_VARS UNIBILIUM_INCLUDE_DIR UNIBILIUM_LIBRARY) add_library(unibilium INTERFACE) diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 256c053801..8911eafc71 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -156,6 +156,7 @@ local extension = { bas = function(path, bufnr) return require('vim.filetype.detect').bas(bufnr) end, + bass = 'bass', bi = function(path, bufnr) return require('vim.filetype.detect').bas(bufnr) end, diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index b2909f2154..b63247aa2c 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -47,7 +47,8 @@ function M._create_parser(bufnr, lang, opts) vim.fn.bufload(bufnr) - language.add(lang, { filetype = vim.bo[bufnr].filetype }) + local ft = vim.bo[bufnr].filetype + language.add(lang, { filetype = ft ~= '' and ft or nil }) local self = LanguageTree.new(bufnr, lang, opts) diff --git a/runtime/lua/vim/treesitter/_range.lua b/runtime/lua/vim/treesitter/_range.lua index b87542c20f..8decd3a1fd 100644 --- a/runtime/lua/vim/treesitter/_range.lua +++ b/runtime/lua/vim/treesitter/_range.lua @@ -61,7 +61,7 @@ function M.intercepts(r1, r2) local off_1 = #r1 == 6 and 1 or 0 local off_2 = #r1 == 6 and 1 or 0 - local srow_1, scol_1, erow_1, ecol_1 = r1[1], r2[2], r1[3 + off_1], r1[4 + off_1] + local srow_1, scol_1, erow_1, ecol_1 = r1[1], r1[2], r1[3 + off_1], r1[4 + off_1] local srow_2, scol_2, erow_2, ecol_2 = r2[1], r2[2], r2[3 + off_2], r2[4 + off_2] -- r1 is above r2 @@ -85,7 +85,7 @@ function M.contains(r1, r2) local off_1 = #r1 == 6 and 1 or 0 local off_2 = #r1 == 6 and 1 or 0 - local srow_1, scol_1, erow_1, ecol_1 = r1[1], r2[2], r1[3 + off_1], r1[4 + off_1] + local srow_1, scol_1, erow_1, ecol_1 = r1[1], r1[2], r1[3 + off_1], r1[4 + off_1] local srow_2, scol_2, erow_2, ecol_2 = r2[1], r2[2], r2[3 + off_2], r2[4 + off_2] -- start doesn't fit diff --git a/runtime/lua/vim/treesitter/language.lua b/runtime/lua/vim/treesitter/language.lua index 5bcc786e88..5f34d9cd56 100644 --- a/runtime/lua/vim/treesitter/language.lua +++ b/runtime/lua/vim/treesitter/language.lua @@ -60,6 +60,16 @@ function M.add(lang, opts) filetype = { filetype, { 'string', 'table' }, true }, }) + if filetype == '' then + error(string.format("'%s' is not a valid filetype", filetype)) + elseif type(filetype) == 'table' then + for _, f in ipairs(filetype) do + if f == '' then + error(string.format("'%s' is not a valid filetype", filetype)) + end + end + end + M.register(lang, filetype or lang) if vim._ts_has_language(lang) then diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index 9bd79a6ba7..8c23b501f9 100755 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -1,22 +1,19 @@ add_library(main_lib INTERFACE) add_executable(nvim main.c) -add_library(libuv_lib INTERFACE) +add_library(libuv INTERFACE) find_package(libuv CONFIG) if(TARGET libuv::uv_a) - target_link_libraries(libuv_lib INTERFACE libuv::uv_a) + target_link_libraries(libuv INTERFACE libuv::uv_a) + mark_as_advanced(libuv_DIR) else() # Fall back to find module for older libuv versions that don't provide config file - find_package(LibUV 1.28.0 REQUIRED MODULE) - target_include_directories(libuv_lib SYSTEM BEFORE INTERFACE ${LIBUV_INCLUDE_DIRS}) - target_link_libraries(libuv_lib INTERFACE ${LIBUV_LIBRARIES}) + find_package(Libuv 1.28.0 REQUIRED MODULE) + target_include_directories(libuv SYSTEM BEFORE INTERFACE ${LIBUV_INCLUDE_DIRS}) + target_link_libraries(libuv INTERFACE ${LIBUV_LIBRARIES}) endif() -find_package(Msgpack 1.0.0 REQUIRED) -target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${MSGPACK_INCLUDE_DIRS}) -target_link_libraries(main_lib INTERFACE ${MSGPACK_LIBRARIES}) - -find_package(LibLUV 1.43.0 REQUIRED) +find_package(Libluv 1.43.0 REQUIRED) target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${LIBLUV_INCLUDE_DIRS}) # Use "luv" as imported library, to work around CMake using "-lluv" for # "luv.so". #10407 @@ -24,33 +21,28 @@ add_library(luv UNKNOWN IMPORTED) set_target_properties(luv PROPERTIES IMPORTED_LOCATION ${LIBLUV_LIBRARIES}) target_link_libraries(main_lib INTERFACE luv) -find_package(TreeSitter REQUIRED) -target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${TreeSitter_INCLUDE_DIR}) -target_link_libraries(main_lib INTERFACE ${TreeSitter_LIBRARY}) - -find_package(unibilium 2.0 REQUIRED) -target_link_libraries(main_lib INTERFACE unibilium) - -find_package(LibTermkey 0.22 REQUIRED) -target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${LIBTERMKEY_INCLUDE_DIR}) -target_link_libraries(main_lib INTERFACE ${LIBTERMKEY_LIBRARY}) - -find_package(libvterm 0.3 REQUIRED) -target_link_libraries(main_lib INTERFACE libvterm) - find_package(Iconv REQUIRED) -target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${ICONV_INCLUDE_DIR}) -if(ICONV_LIBRARY) - target_link_libraries(main_lib INTERFACE ${ICONV_LIBRARY}) -endif() +find_package(Libtermkey 0.22 REQUIRED) +find_package(Libvterm 0.3 REQUIRED) +find_package(Msgpack 1.0.0 REQUIRED) +find_package(Treesitter REQUIRED) +find_package(Unibilium 2.0 REQUIRED) + +target_link_libraries(main_lib INTERFACE + iconv + libtermkey + libvterm + msgpack + treesitter + unibilium) option(ENABLE_LIBINTL "enable libintl" ON) if(ENABLE_LIBINTL) - # LibIntl (not Intl) selects our FindLibIntl.cmake script. #8464 - find_package(LibIntl REQUIRED) - target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${LibIntl_INCLUDE_DIR}) - if (LibIntl_LIBRARY) - target_link_libraries(main_lib INTERFACE ${LibIntl_LIBRARY}) + # Libintl (not Intl) selects our FindLibintl.cmake script. #8464 + find_package(Libintl REQUIRED) + target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${LIBINTL_INCLUDE_DIR}) + if (LIBINTL_LIBRARY) + target_link_libraries(main_lib INTERFACE ${LIBINTL_LIBRARY}) endif() endif() @@ -61,9 +53,9 @@ if(PREFER_LUA) target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${LUA_INCLUDE_DIR}) target_link_libraries(main_lib INTERFACE ${LUA_LIBRARIES}) # Passive (not REQUIRED): if LUAJIT_FOUND is not set, fixtures for unittests is skipped. - find_package(LuaJit) + find_package(Luajit) else() - find_package(LuaJit REQUIRED) + find_package(Luajit REQUIRED) target_include_directories(main_lib SYSTEM BEFORE INTERFACE ${LUAJIT_INCLUDE_DIRS}) target_link_libraries(main_lib INTERFACE ${LUAJIT_LIBRARIES}) endif() @@ -191,52 +183,6 @@ if(UNSIGNED_CHAR) target_compile_options(main_lib INTERFACE -funsigned-char) endif() -list(APPEND CMAKE_REQUIRED_INCLUDES "${MSGPACK_INCLUDE_DIRS}") -check_c_source_compiles(" -#include <msgpack.h> - -int -main(void) -{ - return MSGPACK_OBJECT_FLOAT32; -} -" MSGPACK_HAS_FLOAT32) -list(REMOVE_ITEM CMAKE_REQUIRED_INCLUDES "${MSGPACK_INCLUDE_DIRS}") -if(MSGPACK_HAS_FLOAT32) - target_compile_definitions(main_lib INTERFACE NVIM_MSGPACK_HAS_FLOAT32) -endif() - -list(APPEND CMAKE_REQUIRED_INCLUDES "${TreeSitter_INCLUDE_DIRS}") -list(APPEND CMAKE_REQUIRED_LIBRARIES "${TreeSitter_LIBRARIES}") -check_c_source_compiles(" -#include <tree_sitter/api.h> -int -main(void) -{ - TSQueryCursor *cursor = ts_query_cursor_new(); - ts_query_cursor_set_match_limit(cursor, 32); - return 0; -} -" TS_HAS_SET_MATCH_LIMIT) -if(TS_HAS_SET_MATCH_LIMIT) - target_compile_definitions(main_lib INTERFACE NVIM_TS_HAS_SET_MATCH_LIMIT) -endif() -check_c_source_compiles(" -#include <stdlib.h> -#include <tree_sitter/api.h> -int -main(void) -{ - ts_set_allocator(malloc, calloc, realloc, free); - return 0; -} -" TS_HAS_SET_ALLOCATOR) -if(TS_HAS_SET_ALLOCATOR) - target_compile_definitions(main_lib INTERFACE NVIM_TS_HAS_SET_ALLOCATOR) -endif() -list(REMOVE_ITEM CMAKE_REQUIRED_INCLUDES "${TreeSitter_INCLUDE_DIRS}") -list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES "${TreeSitter_LIBRARIES}") - target_compile_definitions(main_lib INTERFACE INCLUDE_GENERATED_DECLARATIONS) # Remove --sort-common from linker flags, as this seems to cause bugs (see #2641, #3374). @@ -260,7 +206,7 @@ endif() if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang") if(CMAKE_SYSTEM_NAME STREQUAL "SunOS") target_link_libraries(nvim PRIVATE -Wl,--no-undefined -lsocket) - elseif(NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin") + elseif(NOT APPLE) target_link_libraries(nvim PRIVATE -Wl,--no-undefined) endif() @@ -287,7 +233,7 @@ if(WIN32) # Enable wmain target_link_libraries(nvim PRIVATE -municode) endif() -elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") +elseif(APPLE) target_link_libraries(nvim PRIVATE "-framework CoreServices") endif() @@ -437,7 +383,7 @@ else() endif() # Log level (MIN_LOG_LEVEL in log.h) -if($ENV{CI} MATCHES "true") +if($ENV{CI}) set(MIN_LOG_LEVEL 3) endif() if("${MIN_LOG_LEVEL}" MATCHES "^$") @@ -466,7 +412,7 @@ get_target_property(prop main_lib INTERFACE_INCLUDE_DIRECTORIES) foreach(gen_include ${prop}) list(APPEND gen_cflags "-I${gen_include}") endforeach() -if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_OSX_SYSROOT) +if(APPLE AND CMAKE_OSX_SYSROOT) list(APPEND gen_cflags "-isysroot") list(APPEND gen_cflags "${CMAKE_OSX_SYSROOT}") endif() @@ -718,7 +664,7 @@ if(${CMAKE_VERSION} VERSION_LESS 3.20) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) endif() -target_link_libraries(nvim PRIVATE main_lib PUBLIC libuv_lib) +target_link_libraries(nvim PRIVATE main_lib PUBLIC libuv) install_helper(TARGETS nvim) if(MSVC) install(FILES $<TARGET_PDB_FILE:nvim> DESTINATION ${CMAKE_INSTALL_BINDIR} OPTIONAL) @@ -829,12 +775,10 @@ if(WIN32) file(WRITE ${PROJECT_BINARY_DIR}/external_blobs.cmake ${EXTERNAL_BLOBS_SCRIPT}) add_custom_target(external_blobs COMMAND ${CMAKE_COMMAND} -P ${PROJECT_BINARY_DIR}/external_blobs.cmake) - set_target_properties(external_blobs PROPERTIES FOLDER deps) add_dependencies(nvim_runtime_deps external_blobs) else() add_custom_target(nvim_runtime_deps) # Stub target to avoid CMP0046. endif() -set_target_properties(nvim_runtime_deps PROPERTIES FOLDER deps) file(MAKE_DIRECTORY ${BINARY_LIB_DIR}) @@ -862,7 +806,7 @@ set_target_properties( OUTPUT_NAME ${LIBNVIM_NAME} ) target_compile_definitions(libnvim PRIVATE MAKE_LIB) -target_link_libraries(libnvim PRIVATE main_lib PUBLIC libuv_lib) +target_link_libraries(libnvim PRIVATE main_lib PUBLIC libuv) if(CLANG_ASAN_UBSAN) message(STATUS "Enabling Clang address sanitizer and undefined behavior sanitizer for nvim.") diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index bf8649afe0..dbbeabbba2 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -68,6 +68,60 @@ typedef enum { WL_LINE, // text in the line } LineDrawState; +/// structure with variables passed between win_line() and other functions +typedef struct { + LineDrawState draw_state; ///< what to draw next + + linenr_T lnum; ///< line number to be drawn + foldinfo_T foldinfo; ///< fold info for this line + + int startrow; ///< first row in the window to be drawn + int row; ///< row in the window, excl w_winrow + + colnr_T vcol; ///< virtual column, before wrapping + int col; ///< visual column on screen, after wrapping + int boguscols; ///< nonexistent columns added to "col" to force wrapping + int vcol_off; ///< offset for concealed characters + + int off; ///< offset relative start of line + + int cul_attr; ///< set when 'cursorline' active + int line_attr; ///< attribute for the whole line + int line_attr_lowprio; ///< low-priority attribute for the line + + int fromcol; ///< start of inverting + int tocol; ///< end of inverting + + long vcol_sbr; ///< virtual column after showbreak + bool need_showbreak; ///< overlong line, skipping first x chars + + int char_attr; ///< attributes for next character + + int n_extra; ///< number of extra bytes + char *p_extra; ///< string of extra chars, plus NUL, only used + ///< when c_extra and c_final are NUL + char *p_extra_free; ///< p_extra buffer that needs to be freed + int extra_attr; ///< attributes for p_extra + int c_extra; ///< extra chars, all the same + int c_final; ///< final char, mandatory if set + + // saved "extra" items for when draw_state becomes WL_LINE (again) + int saved_n_extra; + char *saved_p_extra; + int saved_c_extra; + int saved_c_final; + int saved_char_attr; + + char extra[57]; ///< sign, line number and 'fdc' must fit in here + + hlf_T diff_hlf; ///< type of diff highlighting + + int n_virt_lines; ///< nr of virtual lines + int filler_lines; ///< nr of filler lines to be drawn + int filler_todo; ///< nr of filler lines still to do + 1 + SignTextAttrs sattrs[SIGN_SHOW_MAX]; ///< sign attributes for the sign column +} winlinevars_T; + /// for line_putchar. Contains the state that needs to be remembered from /// putting one character to the next. typedef struct { @@ -300,104 +354,230 @@ static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode, } /// Return true if CursorLineSign highlight is to be used. -static bool use_cursor_line_sign(win_T *wp, linenr_T lnum) +static bool use_cursor_line_highlight(win_T *wp, linenr_T lnum) { return wp->w_p_cul && lnum == wp->w_cursorline && (wp->w_p_culopt_flags & CULOPT_NBR); } -// Get information needed to display the sign in line 'lnum' in window 'wp'. -// If 'nrcol' is true, the sign is going to be displayed in the number column. -// Otherwise the sign is going to be displayed in the sign column. -// -// @param count max number of signs -// @param[out] n_extrap number of characters from pp_extra to display -// @param sign_idxp Index of the displayed sign -static void get_sign_display_info(bool nrcol, win_T *wp, linenr_T lnum, SignTextAttrs sattrs[], - int row, int startrow, int filler_lines, int filler_todo, - int *c_extrap, int *c_finalp, char *extra, size_t extra_size, - char **pp_extra, int *n_extrap, int *char_attrp, int sign_idx, - int cul_attr) +/// Setup for drawing the 'foldcolumn', if there is one. +static void handle_foldcolumn(win_T *wp, winlinevars_T *wlv) +{ + int fdc = compute_foldcolumn(wp, 0); + if (fdc <= 0) { + return; + } + + // Allocate a buffer, "wlv->extra[]" may already be in use. + xfree(wlv->p_extra_free); + wlv->p_extra_free = xmalloc(MAX_MCO * (size_t)fdc + 1); + wlv->n_extra = (int)fill_foldcolumn(wlv->p_extra_free, wp, wlv->foldinfo, wlv->lnum); + wlv->p_extra_free[wlv->n_extra] = NUL; + wlv->p_extra = wlv->p_extra_free; + wlv->c_extra = NUL; + wlv->c_final = NUL; + if (use_cursor_line_highlight(wp, wlv->lnum)) { + wlv->char_attr = win_hl_attr(wp, HLF_CLF); + } else { + wlv->char_attr = win_hl_attr(wp, HLF_FC); + } +} + +/// Get information needed to display the sign in line "wlv->lnum" in window "wp". +/// If "nrcol" is true, the sign is going to be displayed in the number column. +/// Otherwise the sign is going to be displayed in the sign column. +static void get_sign_display_info(bool nrcol, win_T *wp, winlinevars_T *wlv, int sign_idx, + int sign_cul_attr) { // Draw cells with the sign value or blank. - *c_extrap = ' '; - *c_finalp = NUL; + wlv->c_extra = ' '; + wlv->c_final = NUL; if (nrcol) { - *n_extrap = number_width(wp) + 1; + wlv->n_extra = number_width(wp) + 1; } else { - if (use_cursor_line_sign(wp, lnum)) { - *char_attrp = win_hl_attr(wp, HLF_CLS); + if (use_cursor_line_highlight(wp, wlv->lnum)) { + wlv->char_attr = win_hl_attr(wp, HLF_CLS); } else { - *char_attrp = win_hl_attr(wp, HLF_SC); + wlv->char_attr = win_hl_attr(wp, HLF_SC); } - *n_extrap = win_signcol_width(wp); + wlv->n_extra = win_signcol_width(wp); } - if (row == startrow + filler_lines && filler_todo <= 0) { - SignTextAttrs *sattr = sign_get_attr(sign_idx, sattrs, wp->w_scwidth); + if (wlv->row == wlv->startrow + wlv->filler_lines && wlv->filler_todo <= 0) { + SignTextAttrs *sattr = sign_get_attr(sign_idx, wlv->sattrs, wp->w_scwidth); if (sattr != NULL) { - *pp_extra = sattr->text; - if (*pp_extra != NULL) { - *c_extrap = NUL; - *c_finalp = NUL; + wlv->p_extra = sattr->text; + if (wlv->p_extra != NULL) { + wlv->c_extra = NUL; + wlv->c_final = NUL; if (nrcol) { int n, width = number_width(wp) - 2; for (n = 0; n < width; n++) { - extra[n] = ' '; + wlv->extra[n] = ' '; } - extra[n] = NUL; - STRCAT(extra, *pp_extra); - STRCAT(extra, " "); - *pp_extra = extra; - *n_extrap = (int)strlen(*pp_extra); + wlv->extra[n] = NUL; + STRCAT(wlv->extra, wlv->p_extra); + STRCAT(wlv->extra, " "); + wlv->p_extra = wlv->extra; + wlv->n_extra = (int)strlen(wlv->p_extra); } else { - size_t symbol_blen = strlen(*pp_extra); + size_t symbol_blen = strlen(wlv->p_extra); // TODO(oni-link): Is sign text already extended to // full cell width? - assert((size_t)win_signcol_width(wp) >= mb_string2cells((char *)(*pp_extra))); + assert((size_t)win_signcol_width(wp) >= mb_string2cells(wlv->p_extra)); // symbol(s) bytes + (filling spaces) (one byte each) - *n_extrap = (int)symbol_blen + win_signcol_width(wp) - - (int)mb_string2cells(*pp_extra); + wlv->n_extra = (int)symbol_blen + win_signcol_width(wp) - + (int)mb_string2cells(wlv->p_extra); - assert(extra_size > symbol_blen); - memset(extra, ' ', extra_size); - memcpy(extra, *pp_extra, symbol_blen); + assert(sizeof(wlv->extra) > symbol_blen); + memset(wlv->extra, ' ', sizeof(wlv->extra)); + memcpy(wlv->extra, wlv->p_extra, symbol_blen); - *pp_extra = extra; - (*pp_extra)[*n_extrap] = NUL; + wlv->p_extra = wlv->extra; + wlv->p_extra[wlv->n_extra] = NUL; } } - if (use_cursor_line_sign(wp, lnum) && cul_attr > 0) { - *char_attrp = cul_attr; + if (use_cursor_line_highlight(wp, wlv->lnum) && sign_cul_attr > 0) { + wlv->char_attr = sign_cul_attr; } else { - *char_attrp = sattr->hl_attr_id; + wlv->char_attr = sattr->hl_attr_id; } } } } -static int get_sign_attrs(buf_T *buf, linenr_T lnum, SignTextAttrs *sattrs, int *line_attr, - int *num_attr, int *cul_attr) +static int get_sign_attrs(buf_T *buf, winlinevars_T *wlv, int *sign_num_attrp, int *sign_cul_attrp) { - HlPriAttr line_attrs = { *line_attr, 0 }; - HlPriAttr num_attrs = { *num_attr, 0 }; - HlPriAttr cul_attrs = { *cul_attr, 0 }; + HlPriAttr line_attrs = { wlv->line_attr, 0 }; + HlPriAttr num_attrs = { *sign_num_attrp, 0 }; + HlPriAttr cul_attrs = { *sign_cul_attrp, 0 }; // TODO(bfredl, vigoux): line_attr should not take priority over decoration! - int num_signs = buf_get_signattrs(buf, lnum, sattrs, &num_attrs, &line_attrs, &cul_attrs); - decor_redraw_signs(buf, lnum - 1, &num_signs, sattrs, &num_attrs, &line_attrs, &cul_attrs); + int num_signs = buf_get_signattrs(buf, wlv->lnum, wlv->sattrs, &num_attrs, &line_attrs, + &cul_attrs); + decor_redraw_signs(buf, wlv->lnum - 1, &num_signs, wlv->sattrs, &num_attrs, &line_attrs, + &cul_attrs); - *line_attr = line_attrs.attr_id; - *num_attr = num_attrs.attr_id; - *cul_attr = cul_attrs.attr_id; + wlv->line_attr = line_attrs.attr_id; + *sign_num_attrp = num_attrs.attr_id; + *sign_cul_attrp = cul_attrs.attr_id; return num_signs; } +static inline void get_line_number_str(win_T *wp, linenr_T lnum, char *buf, size_t buf_len) +{ + long num; + char *fmt = "%*ld "; + + if (wp->w_p_nu && !wp->w_p_rnu) { + // 'number' + 'norelativenumber' + num = (long)lnum; + } else { + // 'relativenumber', don't use negative numbers + num = labs((long)get_cursor_rel_lnum(wp, lnum)); + if (num == 0 && wp->w_p_nu && wp->w_p_rnu) { + // 'number' + 'relativenumber' + num = lnum; + fmt = "%-*ld "; + } + } + + snprintf(buf, buf_len, fmt, number_width(wp), num); +} + +/// Return true if CursorLineNr highlight is to be used for the number column. +/// - 'cursorline' must be set +/// - "wlv->lnum" must be the cursor line +/// - 'cursorlineopt' has "number" +/// - don't highlight filler lines (when in diff mode) +/// - When line is wrapped and 'cursorlineopt' does not have "line", only highlight the line number +/// itself on the first screenline of the wrapped line, otherwise highlight the number column of +/// all screenlines of the wrapped line. +static bool use_cursor_line_nr(win_T *wp, winlinevars_T *wlv) +{ + return wp->w_p_cul + && wlv->lnum == wp->w_cursorline + && (wp->w_p_culopt_flags & CULOPT_NBR) + && (wlv->row == wlv->startrow + wlv->filler_lines + || (wlv->row > wlv->startrow + wlv->filler_lines + && (wp->w_p_culopt_flags & CULOPT_LINE))); +} + +static int get_line_number_attr(win_T *wp, winlinevars_T *wlv) +{ + if (use_cursor_line_nr(wp, wlv)) { + // TODO(vim): Can we use CursorLine instead of CursorLineNr + // when CursorLineNr isn't set? + return win_hl_attr(wp, HLF_CLN); + } + + if (wp->w_p_rnu) { + if (wlv->lnum < wp->w_cursor.lnum) { + // Use LineNrAbove + return win_hl_attr(wp, HLF_LNA); + } + if (wlv->lnum > wp->w_cursor.lnum) { + // Use LineNrBelow + return win_hl_attr(wp, HLF_LNB); + } + } + + return win_hl_attr(wp, HLF_N); +} + +/// Display the absolute or relative line number. After the first row fill with +/// blanks when the 'n' flag isn't in 'cpo'. +static void handle_lnum_col(win_T *wp, winlinevars_T *wlv, int num_signs, int sign_idx, + int sign_num_attr, int sign_cul_attr) +{ + if ((wp->w_p_nu || wp->w_p_rnu) + && (wlv->row == wlv->startrow + wlv->filler_lines + || vim_strchr(p_cpo, CPO_NUMCOL) == NULL)) { + // If 'signcolumn' is set to 'number' and a sign is present + // in "lnum", then display the sign instead of the line + // number. + if (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u' && num_signs > 0) { + get_sign_display_info(true, wp, wlv, sign_idx, sign_cul_attr); + } else { + // Draw the line number (empty space after wrapping). + if (wlv->row == wlv->startrow + wlv->filler_lines) { + get_line_number_str(wp, wlv->lnum, wlv->extra, sizeof(wlv->extra)); + if (wp->w_skipcol > 0) { + for (wlv->p_extra = wlv->extra; *wlv->p_extra == ' '; wlv->p_extra++) { + *wlv->p_extra = '-'; + } + } + if (wp->w_p_rl) { // reverse line numbers + // like rl_mirror(), but keep the space at the end + char *p2 = skipwhite(wlv->extra); + p2 = skiptowhite(p2) - 1; + for (char *p1 = skipwhite(wlv->extra); p1 < p2; p1++, p2--) { + const char t = *p1; + *p1 = *p2; + *p2 = t; + } + } + wlv->p_extra = wlv->extra; + wlv->c_extra = NUL; + } else { + wlv->c_extra = ' '; + } + wlv->c_final = NUL; + wlv->n_extra = number_width(wp) + 1; + if (sign_num_attr > 0) { + wlv->char_attr = sign_num_attr; + } else { + wlv->char_attr = get_line_number_attr(wp, wlv); + } + } + } +} + /// Prepare and build the 'statuscolumn' string for line "lnum" in window "wp". /// Fill "stcp" with the built status column string and attributes. /// This can be called three times per win_line(), once for virt_lines, once for @@ -449,110 +629,144 @@ static void get_statuscol_str(win_T *wp, linenr_T lnum, int virtnum, statuscol_T } /// Get information needed to display the next segment in the 'statuscolumn'. -/// If not yet at the end, prepare for next segment and decrement "draw_state". +/// If not yet at the end, prepare for next segment and decrement "wlv->draw_state". /// /// @param stcp Status column attributes -/// @param[out] draw_state Current draw state in win_line() -static void get_statuscol_display_info(statuscol_T *stcp, LineDrawState *draw_state, int *char_attr, - int *n_extrap, int *c_extrap, int *c_finalp, char **pp_extra) +/// @param[in,out] wlv +static void get_statuscol_display_info(statuscol_T *stcp, winlinevars_T *wlv) { - *c_extrap = NUL; - *c_finalp = NUL; + wlv->c_extra = NUL; + wlv->c_final = NUL; do { - *draw_state = WL_STC; - *char_attr = stcp->cur_attr; - *pp_extra = stcp->textp; - *n_extrap = (int)((stcp->hlrecp->start ? stcp->hlrecp->start : stcp->text_end) - stcp->textp); + wlv->draw_state = WL_STC; + wlv->char_attr = stcp->cur_attr; + wlv->p_extra = stcp->textp; + wlv->n_extra = + (int)((stcp->hlrecp->start ? stcp->hlrecp->start : stcp->text_end) - stcp->textp); // Prepare for next highlight section if not yet at the end - if (stcp->textp + *n_extrap < stcp->text_end) { + if (stcp->textp + wlv->n_extra < stcp->text_end) { int hl = stcp->hlrecp->userhl; stcp->textp = stcp->hlrecp->start; stcp->cur_attr = hl < 0 ? syn_id2attr(-hl) : hl > 0 ? hl : stcp->num_attr; stcp->hlrecp++; - *draw_state = WL_STC - 1; + wlv->draw_state = WL_STC - 1; } // Skip over empty highlight sections - } while (*n_extrap == 0 && stcp->textp < stcp->text_end); + } while (wlv->n_extra == 0 && stcp->textp < stcp->text_end); } -/// Return true if CursorLineNr highlight is to be used for the number column. -/// -/// - 'cursorline' must be set -/// - lnum must be the cursor line -/// - 'cursorlineopt' has "number" -/// - don't highlight filler lines (when in diff mode) -/// - When line is wrapped and 'cursorlineopt' does not have "line", only highlight the line number -/// itself on the first screenline of the wrapped line, otherwise highlight the number column of -/// all screenlines of the wrapped line. -static bool use_cursor_line_nr(win_T *wp, linenr_T lnum, int row, int startrow, int filler_lines) +static void handle_breakindent(win_T *wp, winlinevars_T *wlv) { - return wp->w_p_cul - && lnum == wp->w_cursorline - && (wp->w_p_culopt_flags & CULOPT_NBR) - && (row == startrow + filler_lines - || (row > startrow + filler_lines - && (wp->w_p_culopt_flags & CULOPT_LINE))); -} - -static inline void get_line_number_str(win_T *wp, linenr_T lnum, char *buf, size_t buf_len) -{ - long num; - char *fmt = "%*ld "; + if (wp->w_briopt_sbr && wlv->draw_state == WL_BRI - 1 + && *get_showbreak_value(wp) != NUL) { + // draw indent after showbreak value + wlv->draw_state = WL_BRI; + } else if (wp->w_briopt_sbr && wlv->draw_state == WL_SBR) { + // after the showbreak, draw the breakindent + wlv->draw_state = WL_BRI - 1; + } - if (wp->w_p_nu && !wp->w_p_rnu) { - // 'number' + 'norelativenumber' - num = (long)lnum; - } else { - // 'relativenumber', don't use negative numbers - num = labs((long)get_cursor_rel_lnum(wp, lnum)); - if (num == 0 && wp->w_p_nu && wp->w_p_rnu) { - // 'number' + 'relativenumber' - num = lnum; - fmt = "%-*ld "; + // draw 'breakindent': indent wrapped text accordingly + if (wlv->draw_state == WL_BRI - 1 && wlv->n_extra == 0) { + wlv->draw_state = WL_BRI; + // if wlv->need_showbreak is set, breakindent also applies + if (wp->w_p_bri && (wlv->row != wlv->startrow || wlv->need_showbreak) + && wlv->filler_lines == 0) { + wlv->char_attr = 0; + if (wlv->diff_hlf != (hlf_T)0) { + wlv->char_attr = win_hl_attr(wp, (int)wlv->diff_hlf); + } + wlv->p_extra = NULL; + wlv->c_extra = ' '; + wlv->c_final = NUL; + wlv->n_extra = get_breakindent_win(wp, ml_get_buf(wp->w_buffer, wlv->lnum, false)); + if (wlv->row == wlv->startrow) { + wlv->n_extra -= win_col_off2(wp); + if (wlv->n_extra < 0) { + wlv->n_extra = 0; + } + } + if (wp->w_skipcol > 0 && wp->w_p_wrap && wp->w_briopt_sbr) { + wlv->need_showbreak = false; + } + // Correct end of highlighted area for 'breakindent', + // required wen 'linebreak' is also set. + if (wlv->tocol == wlv->vcol) { + wlv->tocol += wlv->n_extra; + } } } - - snprintf(buf, buf_len, fmt, number_width(wp), num); } -static int get_line_number_attr(win_T *wp, linenr_T lnum, int row, int startrow, int filler_lines) +static void handle_showbreak_and_filler(win_T *wp, winlinevars_T *wlv) { - if (use_cursor_line_nr(wp, lnum, row, startrow, filler_lines)) { - // TODO(vim): Can we use CursorLine instead of CursorLineNr - // when CursorLineNr isn't set? - return win_hl_attr(wp, HLF_CLN); - } - - if (wp->w_p_rnu) { - if (lnum < wp->w_cursor.lnum) { - // Use LineNrAbove - return win_hl_attr(wp, HLF_LNA); + if (wlv->filler_todo > wlv->filler_lines - wlv->n_virt_lines) { + // TODO(bfredl): check this doesn't inhibit TUI-style + // clear-to-end-of-line. + wlv->c_extra = ' '; + wlv->c_final = NUL; + if (wp->w_p_rl) { + wlv->n_extra = wlv->col + 1; + } else { + wlv->n_extra = wp->w_grid.cols - wlv->col; + } + wlv->char_attr = 0; + } else if (wlv->filler_todo > 0) { + // Draw "deleted" diff line(s) + if (char2cells(wp->w_p_fcs_chars.diff) > 1) { + wlv->c_extra = '-'; + wlv->c_final = NUL; + } else { + wlv->c_extra = wp->w_p_fcs_chars.diff; + wlv->c_final = NUL; } - if (lnum > wp->w_cursor.lnum) { - // Use LineNrBelow - return win_hl_attr(wp, HLF_LNB); + if (wp->w_p_rl) { + wlv->n_extra = wlv->col + 1; + } else { + wlv->n_extra = wp->w_grid.cols - wlv->col; } + wlv->char_attr = win_hl_attr(wp, HLF_DED); } - return win_hl_attr(wp, HLF_N); + char *const sbr = get_showbreak_value(wp); + if (*sbr != NUL && wlv->need_showbreak) { + // Draw 'showbreak' at the start of each broken line. + wlv->p_extra = sbr; + wlv->c_extra = NUL; + wlv->c_final = NUL; + wlv->n_extra = (int)strlen(sbr); + wlv->char_attr = win_hl_attr(wp, HLF_AT); + if (wp->w_skipcol == 0 || !wp->w_p_wrap) { + wlv->need_showbreak = false; + } + wlv->vcol_sbr = wlv->vcol + mb_charlen(sbr); + // Correct end of highlighted area for 'showbreak', + // required when 'linebreak' is also set. + if (wlv->tocol == wlv->vcol) { + wlv->tocol += wlv->n_extra; + } + // Combine 'showbreak' with 'cursorline', prioritizing 'showbreak'. + if (wlv->cul_attr) { + wlv->char_attr = hl_combine_attr(wlv->cul_attr, wlv->char_attr); + } + } } -static void apply_cursorline_highlight(win_T *wp, linenr_T lnum, int *line_attr, int *cul_attr, - int *line_attr_lowprio) +static void apply_cursorline_highlight(win_T *wp, winlinevars_T *wlv) { - *cul_attr = win_hl_attr(wp, HLF_CUL); - HlAttrs ae = syn_attr2entry(*cul_attr); + wlv->cul_attr = win_hl_attr(wp, HLF_CUL); + HlAttrs ae = syn_attr2entry(wlv->cul_attr); // We make a compromise here (#7383): // * low-priority CursorLine if fg is not set // * high-priority ("same as Vim" priority) CursorLine if fg is set if (ae.rgb_fg_color == -1 && ae.cterm_fg_color == 0) { - *line_attr_lowprio = *cul_attr; + wlv->line_attr_lowprio = wlv->cul_attr; } else { if (!(State & MODE_INSERT) && bt_quickfix(wp->w_buffer) - && qf_current_entry(wp) == lnum) { - *line_attr = hl_combine_attr(*cul_attr, *line_attr); + && qf_current_entry(wp) == wlv->lnum) { + wlv->line_attr = hl_combine_attr(wlv->cul_attr, wlv->line_attr); } else { - *line_attr = *cul_attr; + wlv->line_attr = wlv->cul_attr; } } } @@ -604,6 +818,48 @@ static colnr_T get_leadcol(win_T *wp, const char *ptr, const char *line) return leadcol; } +/// Start a screen line at column zero. +static void win_line_start(win_T *wp, winlinevars_T *wlv, bool save_extra) +{ + wlv->col = 0; + wlv->off = 0; + + if (wp->w_p_rl) { + // Rightleft window: process the text in the normal direction, but put + // it in linebuf_char[wlv.off] from right to left. Start at the + // rightmost column of the window. + wlv->col = wp->w_grid.cols - 1; + wlv->off += wlv->col; + } + + if (save_extra) { + // reset the drawing state for the start of a wrapped line + wlv->draw_state = WL_START; + wlv->saved_n_extra = wlv->n_extra; + wlv->saved_p_extra = wlv->p_extra; + wlv->saved_c_extra = wlv->c_extra; + wlv->saved_c_final = wlv->c_final; + wlv->saved_char_attr = wlv->char_attr; + + wlv->n_extra = 0; + } +} + +/// Called when wlv->draw_state is set to WL_LINE. +static void win_line_continue(winlinevars_T *wlv) +{ + if (wlv->saved_n_extra > 0) { + // Continue item from end of wrapped line. + wlv->n_extra = wlv->saved_n_extra; + wlv->c_extra = wlv->saved_c_extra; + wlv->c_final = wlv->saved_c_final; + wlv->p_extra = wlv->saved_p_extra; + wlv->char_attr = wlv->saved_char_attr; + } else { + wlv->char_attr = 0; + } +} + /// Display line "lnum" of window 'wp' on the screen. /// wp->w_virtcol needs to be valid. /// @@ -621,34 +877,18 @@ static colnr_T get_leadcol(win_T *wp, const char *ptr, const char *line) int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, bool number_only, foldinfo_T foldinfo, DecorProviders *providers, char **provider_err) { + winlinevars_T wlv; // variables passed between functions + int c = 0; // init for GCC - colnr_T vcol = 0; // virtual column (for tabs) - long vcol_sbr = -1; // virtual column after showbreak - long vcol_prev = -1; // "vcol" of previous character + long vcol_prev = -1; // "wlv.vcol" of previous character char *line; // current line char *ptr; // current position in "line" - int row; // row in the window, excl w_winrow ScreenGrid *grid = &wp->w_grid; // grid specific to the window - char extra[57]; // sign, line number and 'fdc' must - // fit in here - int n_extra = 0; // number of extra chars - char *p_extra = NULL; // string of extra chars, plus NUL - char *p_extra_free = NULL; // p_extra needs to be freed - int c_extra = NUL; // extra chars, all the same - int c_final = NUL; // final char, mandatory if set - int extra_attr = 0; // attributes when n_extra != 0 static char *at_end_str = ""; // used for p_extra when displaying curwin->w_p_lcs_chars.eol // at end-of-line bool has_fold = foldinfo.fi_level != 0 && foldinfo.fi_lines > 0; - // saved "extra" items for when draw_state becomes WL_LINE (again) - int saved_n_extra = 0; - char *saved_p_extra = NULL; - int saved_c_extra = 0; - int saved_c_final = 0; - int saved_char_attr = 0; - int n_attr = 0; // chars with special attr int saved_attr2 = 0; // char_attr saved for n_attr int n_attr3 = 0; // chars with overruling special attr @@ -656,15 +896,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, int n_skip = 0; // nr of chars to skip for 'nowrap' - int fromcol = -10; // start of inverting - int tocol = MAXCOL; // end of inverting int fromcol_prev = -2; // start of inverting after cursor bool noinvcur = false; // don't invert the cursor bool lnum_in_visual_area = false; pos_T pos; ptrdiff_t v; - int char_attr = 0; // attributes for next character bool attr_pri = false; // char_attr has priority bool area_highlighting = false; // Visual or incsearch highlighting in this line int vi_attr = 0; // attributes for Visual and incsearch highlighting @@ -697,17 +934,11 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, int mb_c = 0; // decoded multi-byte character bool mb_utf8 = false; // screen char is UTF-8 char int u8cc[MAX_MCO]; // composing UTF-8 chars - int filler_lines; // nr of filler lines to be drawn - int filler_todo; // nr of filler lines still to do + 1 - hlf_T diff_hlf = (hlf_T)0; // type of diff highlighting int change_start = MAXCOL; // first col of changed area int change_end = -1; // last col of changed area bool in_multispace = false; // in multiple consecutive spaces int multispace_pos = 0; // position in lcs-multispace string - bool need_showbreak = false; // overlong line, skip first x chars - int line_attr = 0; // attribute for the whole line int line_attr_save; - int line_attr_lowprio = 0; // low-priority attribute for the line int line_attr_lowprio_save; int prev_c = 0; // previous Arabic character int prev_c1 = 0; // first composing char for prev_c @@ -720,7 +951,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, bool area_active = false; - int cul_attr = 0; // set when 'cursorline' active // 'cursorlineopt' has "screenline" and cursor is in this line bool cul_screenline = false; // margin columns for the screen line, needed for when 'cursorlineopt' @@ -728,8 +958,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, int left_curline_col = 0; int right_curline_col = 0; - LineDrawState draw_state = WL_START; // what to draw next - int match_conc = 0; ///< cchar for match functions bool on_last_col = false; int syntax_flags = 0; @@ -737,27 +965,32 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, int prev_syntax_id = 0; int conceal_attr = win_hl_attr(wp, HLF_CONCEAL); bool is_concealing = false; - int boguscols = 0; ///< nonexistent columns added to - ///< force wrapping - int vcol_off = 0; ///< offset for concealed characters int did_wcol = false; int old_boguscols = 0; -#define VCOL_HLC (vcol - vcol_off) +#define VCOL_HLC (wlv.vcol - wlv.vcol_off) #define FIX_FOR_BOGUSCOLS \ { \ - n_extra += vcol_off; \ - vcol -= vcol_off; \ - vcol_off = 0; \ - col -= boguscols; \ - old_boguscols = boguscols; \ - boguscols = 0; \ + wlv.n_extra += wlv.vcol_off; \ + wlv.vcol -= wlv.vcol_off; \ + wlv.vcol_off = 0; \ + wlv.col -= wlv.boguscols; \ + old_boguscols = wlv.boguscols; \ + wlv.boguscols = 0; \ } if (startrow > endrow) { // past the end already! return startrow; } - row = startrow; + CLEAR_FIELD(wlv); + + wlv.lnum = lnum; + wlv.foldinfo = foldinfo; + wlv.startrow = startrow; + wlv.row = startrow; + wlv.fromcol = -10; + wlv.tocol = MAXCOL; + wlv.vcol_sbr = -1; buf_T *buf = wp->w_buffer; bool end_fill = (lnum == buf->b_ml.ml_line_count + 1); @@ -859,37 +1092,37 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (VIsual_mode == Ctrl_V) { // block mode if (lnum_in_visual_area) { - fromcol = wp->w_old_cursor_fcol; - tocol = wp->w_old_cursor_lcol; + wlv.fromcol = wp->w_old_cursor_fcol; + wlv.tocol = wp->w_old_cursor_lcol; } } else { // non-block mode if (lnum > top->lnum && lnum <= bot->lnum) { - fromcol = 0; + wlv.fromcol = 0; } else if (lnum == top->lnum) { if (VIsual_mode == 'V') { // linewise - fromcol = 0; + wlv.fromcol = 0; } else { - getvvcol(wp, top, (colnr_T *)&fromcol, NULL, NULL); + getvvcol(wp, top, (colnr_T *)&wlv.fromcol, NULL, NULL); if (gchar_pos(top) == NUL) { - tocol = fromcol + 1; + wlv.tocol = wlv.fromcol + 1; } } } if (VIsual_mode != 'V' && lnum == bot->lnum) { if (*p_sel == 'e' && bot->col == 0 && bot->coladd == 0) { - fromcol = -10; - tocol = MAXCOL; + wlv.fromcol = -10; + wlv.tocol = MAXCOL; } else if (bot->col == MAXCOL) { - tocol = MAXCOL; + wlv.tocol = MAXCOL; } else { pos = *bot; if (*p_sel == 'e') { - getvvcol(wp, &pos, (colnr_T *)&tocol, NULL, NULL); + getvvcol(wp, &pos, (colnr_T *)&wlv.tocol, NULL, NULL); } else { - getvvcol(wp, &pos, NULL, NULL, (colnr_T *)&tocol); - tocol++; + getvvcol(wp, &pos, NULL, NULL, (colnr_T *)&wlv.tocol); + wlv.tocol++; } } } @@ -902,7 +1135,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } // if inverting in this line set area_highlighting - if (fromcol >= 0) { + if (wlv.fromcol >= 0) { area_highlighting = true; vi_attr = win_hl_attr(wp, HLF_V); } @@ -914,18 +1147,18 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, && lnum <= curwin->w_cursor.lnum + search_match_lines) { if (lnum == curwin->w_cursor.lnum) { getvcol(curwin, &(curwin->w_cursor), - (colnr_T *)&fromcol, NULL, NULL); + (colnr_T *)&wlv.fromcol, NULL, NULL); } else { - fromcol = 0; + wlv.fromcol = 0; } if (lnum == curwin->w_cursor.lnum + search_match_lines) { pos.lnum = lnum; pos.col = search_match_endcol; - getvcol(curwin, &pos, (colnr_T *)&tocol, NULL, NULL); + getvcol(curwin, &pos, (colnr_T *)&wlv.tocol, NULL, NULL); } // do at least one character; happens when past end of line - if (fromcol == tocol && search_match_endcol) { - tocol = fromcol + 1; + if (wlv.fromcol == wlv.tocol && search_match_endcol) { + wlv.tocol = wlv.fromcol + 1; } area_highlighting = true; vi_attr = win_hl_attr(wp, HLF_I); @@ -935,32 +1168,32 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, int bg_attr = win_bg_attr(wp); int linestatus = 0; - filler_lines = diff_check_with_linestatus(wp, lnum, &linestatus); - if (filler_lines < 0 || linestatus < 0) { - if (filler_lines == -1 || linestatus == -1) { + wlv.filler_lines = diff_check_with_linestatus(wp, lnum, &linestatus); + if (wlv.filler_lines < 0 || linestatus < 0) { + if (wlv.filler_lines == -1 || linestatus == -1) { if (diff_find_change(wp, lnum, &change_start, &change_end)) { - diff_hlf = HLF_ADD; // added line + wlv.diff_hlf = HLF_ADD; // added line } else if (change_start == 0) { - diff_hlf = HLF_TXD; // changed text + wlv.diff_hlf = HLF_TXD; // changed text } else { - diff_hlf = HLF_CHD; // changed line + wlv.diff_hlf = HLF_CHD; // changed line } } else { - diff_hlf = HLF_ADD; // added line + wlv.diff_hlf = HLF_ADD; // added line } if (linestatus == 0) { - filler_lines = 0; + wlv.filler_lines = 0; } area_highlighting = true; } VirtLines virt_lines = KV_INITIAL_VALUE; - int n_virt_lines = decor_virt_lines(wp, lnum, &virt_lines, has_fold); - filler_lines += n_virt_lines; + wlv.n_virt_lines = decor_virt_lines(wp, lnum, &virt_lines, has_fold); + wlv.filler_lines += wlv.n_virt_lines; if (lnum == wp->w_topline) { - filler_lines = wp->w_topfill; - n_virt_lines = MIN(n_virt_lines, filler_lines); + wlv.filler_lines = wp->w_topfill; + wlv.n_virt_lines = MIN(wlv.n_virt_lines, wlv.filler_lines); } - filler_todo = filler_lines; + wlv.filler_todo = wlv.filler_lines; // Cursor line highlighting for 'cursorline' in the current window. if (wp->w_p_cul && wp->w_p_culopt_flags != CULOPT_NBR && lnum == wp->w_cursorline @@ -969,31 +1202,29 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, && !(wp == curwin && VIsual_active)) { cul_screenline = (wp->w_p_wrap && (wp->w_p_culopt_flags & CULOPT_SCRLINE)); if (!cul_screenline) { - apply_cursorline_highlight(wp, lnum, &line_attr, &cul_attr, &line_attr_lowprio); + apply_cursorline_highlight(wp, &wlv); } else { margin_columns_win(wp, &left_curline_col, &right_curline_col); } area_highlighting = true; } - SignTextAttrs sattrs[SIGN_SHOW_MAX]; // sign attributes for the sign column int sign_num_attr = 0; // sign attribute for the number column int sign_cul_attr = 0; // sign attribute for cursorline - CLEAR_FIELD(sattrs); - int num_signs = get_sign_attrs(buf, lnum, sattrs, &line_attr, &sign_num_attr, &sign_cul_attr); + int num_signs = get_sign_attrs(buf, &wlv, &sign_num_attr, &sign_cul_attr); // Highlight the current line in the quickfix window. if (bt_quickfix(wp->w_buffer) && qf_current_entry(wp) == lnum) { - line_attr = win_hl_attr(wp, HLF_QFL); + wlv.line_attr = win_hl_attr(wp, HLF_QFL); } - if (line_attr_lowprio || line_attr) { + if (wlv.line_attr_lowprio || wlv.line_attr) { area_highlighting = true; } if (cul_screenline) { - line_attr_save = line_attr; - line_attr_lowprio_save = line_attr_lowprio; + line_attr_save = wlv.line_attr; + line_attr_lowprio_save = wlv.line_attr_lowprio; } line = end_fill ? "" : ml_get_buf(wp->w_buffer, lnum, false); @@ -1061,14 +1292,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, chartabsize_T cts; int charsize; - init_chartabsize_arg(&cts, wp, lnum, vcol, line, ptr); + init_chartabsize_arg(&cts, wp, lnum, wlv.vcol, line, ptr); while (cts.cts_vcol < v && *cts.cts_ptr != NUL) { charsize = win_lbr_chartabsize(&cts, NULL); cts.cts_vcol += charsize; prev_ptr = cts.cts_ptr; MB_PTR_ADV(cts.cts_ptr); } - vcol = cts.cts_vcol; + wlv.vcol = cts.cts_vcol; ptr = cts.cts_ptr; clear_chartabsize_arg(&cts); @@ -1078,36 +1309,36 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // - 'virtualedit' is set, or // - the visual mode is active, // the end of the line may be before the start of the displayed part. - if (vcol < v && (wp->w_p_cuc - || draw_color_col - || virtual_active() - || (VIsual_active && wp->w_buffer == curwin->w_buffer))) { - vcol = (colnr_T)v; + if (wlv.vcol < v && (wp->w_p_cuc + || draw_color_col + || virtual_active() + || (VIsual_active && wp->w_buffer == curwin->w_buffer))) { + wlv.vcol = (colnr_T)v; } // Handle a character that's not completely on the screen: Put ptr at // that character but skip the first few screen characters. - if (vcol > v) { - vcol -= charsize; + if (wlv.vcol > v) { + wlv.vcol -= charsize; ptr = prev_ptr; // If the character fits on the screen, don't need to skip it. // Except for a TAB. if (utf_ptr2cells(ptr) >= charsize || *ptr == TAB) { - n_skip = (int)(v - vcol); + n_skip = (int)(v - wlv.vcol); } } // Adjust for when the inverted text is before the screen, // and when the start of the inverted text is before the screen. - if (tocol <= vcol) { - fromcol = 0; - } else if (fromcol >= 0 && fromcol < vcol) { - fromcol = vcol; + if (wlv.tocol <= wlv.vcol) { + wlv.fromcol = 0; + } else if (wlv.fromcol >= 0 && wlv.fromcol < wlv.vcol) { + wlv.fromcol = wlv.vcol; } // When w_skipcol is non-zero, first line needs 'showbreak' if (wp->w_p_wrap) { - need_showbreak = true; + wlv.need_showbreak = true; } // When spell checking a word we need to figure out the start of the // word and if it's badly spelled or not. @@ -1151,20 +1382,20 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // Correct highlighting for cursor that can't be disabled. // Avoids having to check this for each character. - if (fromcol >= 0) { + if (wlv.fromcol >= 0) { if (noinvcur) { - if ((colnr_T)fromcol == wp->w_virtcol) { + if ((colnr_T)wlv.fromcol == wp->w_virtcol) { // highlighting starts at cursor, let it start just after the // cursor - fromcol_prev = fromcol; - fromcol = -1; - } else if ((colnr_T)fromcol < wp->w_virtcol) { + fromcol_prev = wlv.fromcol; + wlv.fromcol = -1; + } else if ((colnr_T)wlv.fromcol < wp->w_virtcol) { // restart highlighting after the cursor fromcol_prev = wp->w_virtcol; } } - if (fromcol >= tocol) { - fromcol = -1; + if (wlv.fromcol >= wlv.tocol) { + wlv.fromcol = -1; } } @@ -1176,15 +1407,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, ptr = line + v; // "line" may have been updated } - int off = 0; // Offset relative start of line - int col = 0; // Visual column on screen. - if (wp->w_p_rl) { - // Rightleft window: process the text in the normal direction, but put - // it in linebuf_char[off] from right to left. Start at the - // rightmost column of the window. - col = grid->cols - 1; - off += col; - } + win_line_start(wp, &wlv, false); // won't highlight after TERM_ATTRS_MAX columns int term_attrs[TERM_ATTRS_MAX] = { 0 }; @@ -1197,13 +1420,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (*wp->w_p_stc != NUL) { // Draw the 'statuscolumn' if option is set. statuscol.draw = true; - statuscol.sattrs = sattrs; + statuscol.sattrs = wlv.sattrs; statuscol.foldinfo = foldinfo; statuscol.width = win_col_off(wp) - (cmdwin_type != 0 && wp == curwin); - statuscol.use_cul = use_cursor_line_sign(wp, lnum); + statuscol.use_cul = use_cursor_line_highlight(wp, lnum); statuscol.sign_cul_attr = statuscol.use_cul ? sign_cul_attr : 0; - statuscol.num_attr = sign_num_attr ? sign_num_attr - : get_line_number_attr(wp, lnum, row, startrow, filler_lines); + statuscol.num_attr = sign_num_attr ? sign_num_attr : get_line_number_attr(wp, &wlv); } int sign_idx = 0; @@ -1217,27 +1439,27 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, bool did_decrement_ptr = false; // Skip this quickly when working on the text. - if (draw_state != WL_LINE) { + if (wlv.draw_state != WL_LINE) { if (cul_screenline) { - cul_attr = 0; - line_attr = line_attr_save; - line_attr_lowprio = line_attr_lowprio_save; + wlv.cul_attr = 0; + wlv.line_attr = line_attr_save; + wlv.line_attr_lowprio = line_attr_lowprio_save; } - if (draw_state == WL_CMDLINE - 1 && n_extra == 0) { - draw_state = WL_CMDLINE; + if (wlv.draw_state == WL_CMDLINE - 1 && wlv.n_extra == 0) { + wlv.draw_state = WL_CMDLINE; if (cmdwin_type != 0 && wp == curwin) { // Draw the cmdline character. - n_extra = 1; - c_extra = cmdwin_type; - c_final = NUL; - char_attr = win_hl_attr(wp, HLF_AT); + wlv.n_extra = 1; + wlv.c_extra = cmdwin_type; + wlv.c_final = NUL; + wlv.char_attr = win_hl_attr(wp, HLF_AT); } } - if (draw_state == WL_FOLD - 1 && n_extra == 0) { - if (filler_todo > 0) { - int index = filler_todo - (filler_lines - n_virt_lines); + if (wlv.draw_state == WL_FOLD - 1 && wlv.n_extra == 0) { + if (wlv.filler_todo > 0) { + int index = wlv.filler_todo - (wlv.filler_lines - wlv.n_virt_lines); if (index > 0) { virt_line_index = (int)kv_size(virt_lines) - index; assert(virt_line_index >= 0); @@ -1246,327 +1468,165 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } if (!virt_line_offset) { // Skip the column states if there is a "virt_left_col" line. - draw_state = WL_BRI - 1; + wlv.draw_state = WL_BRI - 1; } else if (statuscol.draw) { // Skip fold, sign and number states if 'statuscolumn' is set. - draw_state = WL_STC - 1; + wlv.draw_state = WL_STC - 1; } } - if (draw_state == WL_FOLD - 1 && n_extra == 0) { - int fdc = compute_foldcolumn(wp, 0); - draw_state = WL_FOLD; - if (fdc > 0) { - // Draw the 'foldcolumn'. Allocate a buffer, "extra" may - // already be in use. - xfree(p_extra_free); - p_extra_free = xmalloc(MAX_MCO * (size_t)fdc + 1); - n_extra = (int)fill_foldcolumn(p_extra_free, wp, foldinfo, lnum); - p_extra_free[n_extra] = NUL; - p_extra = p_extra_free; - c_extra = NUL; - c_final = NUL; - if (use_cursor_line_sign(wp, lnum)) { - char_attr = win_hl_attr(wp, HLF_CLF); - } else { - char_attr = win_hl_attr(wp, HLF_FC); - } - } + if (wlv.draw_state == WL_FOLD - 1 && wlv.n_extra == 0) { + wlv.draw_state = WL_FOLD; + handle_foldcolumn(wp, &wlv); } // sign column, this is hit until sign_idx reaches count - if (draw_state == WL_SIGN - 1 && n_extra == 0) { - draw_state = WL_SIGN; - // Show the sign column when there are any signs in this buffer + if (wlv.draw_state == WL_SIGN - 1 && wlv.n_extra == 0) { + // Show the sign column when desired. + wlv.draw_state = WL_SIGN; if (wp->w_scwidth > 0) { - get_sign_display_info(false, wp, lnum, sattrs, row, - startrow, filler_lines, filler_todo, - &c_extra, &c_final, extra, sizeof(extra), - &p_extra, &n_extra, &char_attr, sign_idx, - sign_cul_attr); + get_sign_display_info(false, wp, &wlv, sign_idx, sign_cul_attr); sign_idx++; if (sign_idx < wp->w_scwidth) { - draw_state = WL_SIGN - 1; + wlv.draw_state = WL_SIGN - 1; } else { sign_idx = 0; } } } - if (draw_state == WL_NR - 1 && n_extra == 0) { - draw_state = WL_NR; - // Display the absolute or relative line number. After the - // first fill with blanks when the 'n' flag isn't in 'cpo' - if ((wp->w_p_nu || wp->w_p_rnu) - && (row == startrow + filler_lines - || vim_strchr(p_cpo, CPO_NUMCOL) == NULL)) { - // If 'signcolumn' is set to 'number' and a sign is present - // in 'lnum', then display the sign instead of the line - // number. - if (*wp->w_p_scl == 'n' && *(wp->w_p_scl + 1) == 'u' && num_signs > 0) { - get_sign_display_info(true, wp, lnum, sattrs, row, - startrow, filler_lines, filler_todo, - &c_extra, &c_final, extra, sizeof(extra), - &p_extra, &n_extra, &char_attr, sign_idx, - sign_cul_attr); - } else { - // Draw the line number (empty space after wrapping). - if (row == startrow + filler_lines) { - get_line_number_str(wp, lnum, extra, sizeof(extra)); - if (wp->w_skipcol > 0) { - for (p_extra = extra; *p_extra == ' '; p_extra++) { - *p_extra = '-'; - } - } - if (wp->w_p_rl) { // reverse line numbers - // like rl_mirror(), but keep the space at the end - char *p2 = skipwhite(extra); - p2 = skiptowhite(p2) - 1; - for (char *p1 = skipwhite(extra); p1 < p2; p1++, p2--) { - const char t = *p1; - *p1 = *p2; - *p2 = t; - } - } - p_extra = extra; - c_extra = NUL; - } else { - c_extra = ' '; - } - c_final = NUL; - n_extra = number_width(wp) + 1; - if (sign_num_attr > 0) { - char_attr = sign_num_attr; - } else { - char_attr = get_line_number_attr(wp, lnum, row, startrow, filler_lines); - } - } - } + if (wlv.draw_state == WL_NR - 1 && wlv.n_extra == 0) { + // Show the line number, if desired. + wlv.draw_state = WL_NR; + handle_lnum_col(wp, &wlv, num_signs, sign_idx, sign_num_attr, sign_cul_attr); } - if (draw_state == WL_STC - 1 && n_extra == 0) { - draw_state = WL_STC; + if (wlv.draw_state == WL_STC - 1 && wlv.n_extra == 0) { + wlv.draw_state = WL_STC; // Draw the 'statuscolumn' if option is set. if (statuscol.draw) { if (statuscol.textp == NULL) { - get_statuscol_str(wp, lnum, row - startrow - filler_lines, &statuscol); + get_statuscol_str(wp, lnum, wlv.row - startrow - wlv.filler_lines, &statuscol); if (wp->w_redr_statuscol) { break; } } - get_statuscol_display_info(&statuscol, &draw_state, &char_attr, - &n_extra, &c_extra, &c_final, &p_extra); + get_statuscol_display_info(&statuscol, &wlv); } } - if (draw_state == WL_STC && n_extra == 0) { - win_col_offset = off; + if (wlv.draw_state == WL_STC && wlv.n_extra == 0) { + win_col_offset = wlv.off; } - if (wp->w_briopt_sbr && draw_state == WL_BRI - 1 - && n_extra == 0 && *get_showbreak_value(wp) != NUL) { - // draw indent after showbreak value - draw_state = WL_BRI; - } else if (wp->w_briopt_sbr && draw_state == WL_SBR && n_extra == 0) { - // after the showbreak, draw the breakindent - draw_state = WL_BRI - 1; + // Check if 'breakindent' applies and show it. + // May change wlv.draw_state to WL_BRI or WL_BRI - 1. + if (wlv.n_extra == 0) { + handle_breakindent(wp, &wlv); } - // draw 'breakindent': indent wrapped text accordingly - if (draw_state == WL_BRI - 1 && n_extra == 0) { - draw_state = WL_BRI; - // if need_showbreak is set, breakindent also applies - if (wp->w_p_bri && (row != startrow || need_showbreak) - && filler_lines == 0) { - char_attr = 0; - - if (diff_hlf != (hlf_T)0) { - char_attr = win_hl_attr(wp, (int)diff_hlf); - } - p_extra = NULL; - c_extra = ' '; - c_final = NUL; - n_extra = - get_breakindent_win(wp, ml_get_buf(wp->w_buffer, lnum, false)); - if (row == startrow) { - n_extra -= win_col_off2(wp); - if (n_extra < 0) { - n_extra = 0; - } - } - if (wp->w_skipcol > 0 && wp->w_p_wrap && wp->w_briopt_sbr) { - need_showbreak = false; - } - // Correct end of highlighted area for 'breakindent', - // required wen 'linebreak' is also set. - if (tocol == vcol) { - tocol += n_extra; - } - } - } - - if (draw_state == WL_SBR - 1 && n_extra == 0) { - draw_state = WL_SBR; - if (filler_todo > filler_lines - n_virt_lines) { - // TODO(bfredl): check this doesn't inhibit TUI-style - // clear-to-end-of-line. - c_extra = ' '; - c_final = NUL; - if (wp->w_p_rl) { - n_extra = col + 1; - } else { - n_extra = grid->cols - col; - } - char_attr = 0; - } else if (filler_todo > 0) { - // Draw "deleted" diff line(s) - if (char2cells(wp->w_p_fcs_chars.diff) > 1) { - c_extra = '-'; - c_final = NUL; - } else { - c_extra = wp->w_p_fcs_chars.diff; - c_final = NUL; - } - if (wp->w_p_rl) { - n_extra = col + 1; - } else { - n_extra = grid->cols - col; - } - char_attr = win_hl_attr(wp, HLF_DED); - } - char *const sbr = get_showbreak_value(wp); - if (*sbr != NUL && need_showbreak) { - // Draw 'showbreak' at the start of each broken line. - p_extra = sbr; - c_extra = NUL; - c_final = NUL; - n_extra = (int)strlen(sbr); - char_attr = win_hl_attr(wp, HLF_AT); - if (wp->w_skipcol == 0 || !wp->w_p_wrap) { - need_showbreak = false; - } - vcol_sbr = vcol + mb_charlen(sbr); - // Correct end of highlighted area for 'showbreak', - // required when 'linebreak' is also set. - if (tocol == vcol) { - tocol += n_extra; - } - // Combine 'showbreak' with 'cursorline', prioritizing 'showbreak'. - if (cul_attr) { - char_attr = hl_combine_attr(cul_attr, char_attr); - } - } + if (wlv.draw_state == WL_SBR - 1 && wlv.n_extra == 0) { + wlv.draw_state = WL_SBR; + handle_showbreak_and_filler(wp, &wlv); } - if (draw_state == WL_LINE - 1 && n_extra == 0) { + if (wlv.draw_state == WL_LINE - 1 && wlv.n_extra == 0) { sign_idx = 0; - draw_state = WL_LINE; - - if (has_decor && row == startrow + filler_lines) { + wlv.draw_state = WL_LINE; + if (has_decor && wlv.row == startrow + wlv.filler_lines) { // hide virt_text on text hidden by 'nowrap' - decor_redraw_col(wp->w_buffer, vcol, off, true, &decor_state); - } - - if (saved_n_extra) { - // Continue item from end of wrapped line. - n_extra = saved_n_extra; - c_extra = saved_c_extra; - c_final = saved_c_final; - p_extra = saved_p_extra; - char_attr = saved_char_attr; - } else { - char_attr = 0; + decor_redraw_col(wp->w_buffer, wlv.vcol, wlv.off, true, &decor_state); } + win_line_continue(&wlv); // use wlv.saved_ values } } - if (cul_screenline && draw_state == WL_LINE - && vcol >= left_curline_col - && vcol < right_curline_col) { - apply_cursorline_highlight(wp, lnum, &line_attr, &cul_attr, &line_attr_lowprio); + if (cul_screenline && wlv.draw_state == WL_LINE + && wlv.vcol >= left_curline_col + && wlv.vcol < right_curline_col) { + apply_cursorline_highlight(wp, &wlv); } // When still displaying '$' of change command, stop at cursor if (((dollar_vcol >= 0 && wp == curwin && lnum == wp->w_cursor.lnum - && vcol >= (long)wp->w_virtcol) - || (number_only && draw_state > WL_STC)) - && filler_todo <= 0) { - draw_virt_text(wp, buf, win_col_offset, &col, grid->cols, row); - grid_put_linebuf(grid, row, 0, col, -grid->cols, wp->w_p_rl, wp, bg_attr, false); + && wlv.vcol >= (long)wp->w_virtcol) + || (number_only && wlv.draw_state > WL_STC)) + && wlv.filler_todo <= 0) { + draw_virt_text(wp, buf, win_col_offset, &wlv.col, grid->cols, wlv.row); + grid_put_linebuf(grid, wlv.row, 0, wlv.col, -grid->cols, wp->w_p_rl, wp, bg_attr, false); // Pretend we have finished updating the window. Except when // 'cursorcolumn' is set. if (wp->w_p_cuc) { - row = wp->w_cline_row + wp->w_cline_height; + wlv.row = wp->w_cline_row + wp->w_cline_height; } else { - row = grid->rows; + wlv.row = grid->rows; } break; } - if (draw_state == WL_LINE + if (wlv.draw_state == WL_LINE && has_fold - && col == win_col_offset - && n_extra == 0 - && row == startrow + filler_lines) { - char_attr = win_hl_attr(wp, HLF_FL); + && wlv.col == win_col_offset + && wlv.n_extra == 0 + && wlv.row == startrow + wlv.filler_lines) { + wlv.char_attr = win_hl_attr(wp, HLF_FL); linenr_T lnume = lnum + foldinfo.fi_lines - 1; memset(buf_fold, ' ', FOLD_TEXT_LEN); - p_extra = get_foldtext(wp, lnum, lnume, foldinfo, buf_fold); - n_extra = (int)strlen(p_extra); + wlv.p_extra = get_foldtext(wp, lnum, lnume, foldinfo, buf_fold); + wlv.n_extra = (int)strlen(wlv.p_extra); - if (p_extra != buf_fold) { - xfree(p_extra_free); - p_extra_free = p_extra; + if (wlv.p_extra != buf_fold) { + xfree(wlv.p_extra_free); + wlv.p_extra_free = wlv.p_extra; } - c_extra = NUL; - c_final = NUL; - p_extra[n_extra] = NUL; + wlv.c_extra = NUL; + wlv.c_final = NUL; + wlv.p_extra[wlv.n_extra] = NUL; } - if (draw_state == WL_LINE + if (wlv.draw_state == WL_LINE && has_fold - && col < grid->cols - && n_extra == 0 - && row == startrow + filler_lines) { + && wlv.col < grid->cols + && wlv.n_extra == 0 + && wlv.row == startrow + wlv.filler_lines) { // fill rest of line with 'fold' - c_extra = wp->w_p_fcs_chars.fold; - c_final = NUL; + wlv.c_extra = wp->w_p_fcs_chars.fold; + wlv.c_final = NUL; - n_extra = wp->w_p_rl ? (col + 1) : (grid->cols - col); + wlv.n_extra = wp->w_p_rl ? (wlv.col + 1) : (grid->cols - wlv.col); } - if (draw_state == WL_LINE + if (wlv.draw_state == WL_LINE && has_fold - && col >= grid->cols - && n_extra != 0 - && row == startrow + filler_lines) { + && wlv.col >= grid->cols + && wlv.n_extra != 0 + && wlv.row == startrow + wlv.filler_lines) { // Truncate the folding. - n_extra = 0; + wlv.n_extra = 0; } - if (draw_state == WL_LINE && (area_highlighting || has_spell)) { + if (wlv.draw_state == WL_LINE && (area_highlighting || has_spell)) { // handle Visual or match highlighting in this line - if (vcol == fromcol - || (vcol + 1 == fromcol && n_extra == 0 + if (wlv.vcol == wlv.fromcol + || (wlv.vcol + 1 == wlv.fromcol && wlv.n_extra == 0 && utf_ptr2cells(ptr) > 1) || ((int)vcol_prev == fromcol_prev - && vcol_prev < vcol // not at margin - && vcol < tocol)) { + && vcol_prev < wlv.vcol // not at margin + && wlv.vcol < wlv.tocol)) { area_attr = vi_attr; // start highlighting if (area_highlighting) { area_active = true; } - } else if (area_attr != 0 && (vcol == tocol - || (noinvcur - && vcol == wp->w_virtcol))) { + } else if (area_attr != 0 && (wlv.vcol == wlv.tocol + || (noinvcur && wlv.vcol == wp->w_virtcol))) { area_attr = 0; // stop highlighting area_active = false; } - if (!n_extra) { + if (!wlv.n_extra) { // Check for start/end of 'hlsearch' and other matches. // After end, check for start/end of next match. // When another match, have to check for start again. @@ -1583,22 +1643,22 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } } - if (diff_hlf != (hlf_T)0) { - if (diff_hlf == HLF_CHD && ptr - line >= change_start - && n_extra == 0) { - diff_hlf = HLF_TXD; // changed text + if (wlv.diff_hlf != (hlf_T)0) { + if (wlv.diff_hlf == HLF_CHD && ptr - line >= change_start + && wlv.n_extra == 0) { + wlv.diff_hlf = HLF_TXD; // changed text } - if (diff_hlf == HLF_TXD && ptr - line > change_end - && n_extra == 0) { - diff_hlf = HLF_CHD; // changed line + if (wlv.diff_hlf == HLF_TXD && ptr - line > change_end + && wlv.n_extra == 0) { + wlv.diff_hlf = HLF_CHD; // changed line } - line_attr = win_hl_attr(wp, (int)diff_hlf); + wlv.line_attr = win_hl_attr(wp, (int)wlv.diff_hlf); // Overlay CursorLine onto diff-mode highlight. - if (cul_attr) { - line_attr = 0 != line_attr_lowprio // Low-priority CursorLine - ? hl_combine_attr(hl_combine_attr(cul_attr, line_attr), + if (wlv.cul_attr) { + wlv.line_attr = 0 != wlv.line_attr_lowprio // Low-priority CursorLine + ? hl_combine_attr(hl_combine_attr(wlv.cul_attr, wlv.line_attr), hl_get_underline()) - : hl_combine_attr(line_attr, cul_attr); + : hl_combine_attr(wlv.line_attr, wlv.cul_attr); } } @@ -1606,25 +1666,27 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, attr_pri = true; if (area_attr != 0) { - char_attr = hl_combine_attr(line_attr, area_attr); + wlv.char_attr = hl_combine_attr(wlv.line_attr, area_attr); if (!highlight_match) { // let search highlight show in Visual area if possible - char_attr = hl_combine_attr(search_attr, char_attr); + wlv.char_attr = hl_combine_attr(search_attr, wlv.char_attr); } } else if (search_attr != 0) { - char_attr = hl_combine_attr(line_attr, search_attr); - } else if (line_attr != 0 && ((fromcol == -10 && tocol == MAXCOL) - || vcol < fromcol || vcol_prev < fromcol_prev - || vcol >= tocol)) { - // Use line_attr when not in the Visual or 'incsearch' area + wlv.char_attr = hl_combine_attr(wlv.line_attr, search_attr); + } else if (wlv.line_attr != 0 + && ((wlv.fromcol == -10 && wlv.tocol == MAXCOL) + || wlv.vcol < wlv.fromcol + || vcol_prev < fromcol_prev + || wlv.vcol >= wlv.tocol)) { + // Use wlv.line_attr when not in the Visual or 'incsearch' area // (area_attr may be 0 when "noinvcur" is set). - char_attr = line_attr; + wlv.char_attr = wlv.line_attr; } else { attr_pri = false; if (has_syntax) { - char_attr = syntax_attr; + wlv.char_attr = syntax_attr; } else { - char_attr = 0; + wlv.char_attr = 0; } } } @@ -1638,23 +1700,23 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // "p_extra" must end in a NUL to avoid utfc_ptr2len() reads past // "p_extra[n_extra]". // For the '$' of the 'list' option, n_extra == 1, p_extra == "". - if (n_extra > 0) { - if (c_extra != NUL || (n_extra == 1 && c_final != NUL)) { - c = (n_extra == 1 && c_final != NUL) ? c_final : c_extra; + if (wlv.n_extra > 0) { + if (wlv.c_extra != NUL || (wlv.n_extra == 1 && wlv.c_final != NUL)) { + c = (wlv.n_extra == 1 && wlv.c_final != NUL) ? wlv.c_final : wlv.c_extra; mb_c = c; // doesn't handle non-utf-8 multi-byte! mb_utf8 = check_mb_utf8(&c, u8cc); } else { - assert(p_extra != NULL); - c = (uint8_t)(*p_extra); + assert(wlv.p_extra != NULL); + c = (uint8_t)(*wlv.p_extra); mb_c = c; // If the UTF-8 character is more than one byte: // Decode it into "mb_c". - mb_l = utfc_ptr2len(p_extra); + mb_l = utfc_ptr2len(wlv.p_extra); mb_utf8 = false; - if (mb_l > n_extra) { + if (mb_l > wlv.n_extra) { mb_l = 1; } else if (mb_l > 1) { - mb_c = utfc_ptr2char(p_extra, u8cc); + mb_c = utfc_ptr2char(wlv.p_extra, u8cc); mb_utf8 = true; c = 0xc0; } @@ -1663,7 +1725,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } // If a double-width char doesn't fit display a '>' in the last column. - if ((wp->w_p_rl ? (col <= 0) : (col >= grid->cols - 1)) + if ((wp->w_p_rl ? (wlv.col <= 0) : (wlv.col >= grid->cols - 1)) && utf_char2cells(mb_c) == 2) { c = '>'; mb_c = c; @@ -1671,32 +1733,29 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, (void)mb_l; multi_attr = win_hl_attr(wp, HLF_AT); - if (cul_attr) { - multi_attr = 0 != line_attr_lowprio - ? hl_combine_attr(cul_attr, multi_attr) - : hl_combine_attr(multi_attr, cul_attr); + if (wlv.cul_attr) { + multi_attr = 0 != wlv.line_attr_lowprio + ? hl_combine_attr(wlv.cul_attr, multi_attr) + : hl_combine_attr(multi_attr, wlv.cul_attr); } // put the pointer back to output the double-width // character at the start of the next line. - n_extra++; - p_extra--; + wlv.n_extra++; + wlv.p_extra--; } else { - n_extra -= mb_l - 1; - p_extra += mb_l - 1; + wlv.n_extra -= mb_l - 1; + wlv.p_extra += mb_l - 1; } - p_extra++; + wlv.p_extra++; } - n_extra--; + wlv.n_extra--; } else if (foldinfo.fi_lines > 0) { // skip writing the buffer line itself c = NUL; - XFREE_CLEAR(p_extra_free); } else { int c0; - XFREE_CLEAR(p_extra_free); - // Get a character from the line itself. c0 = c = (uint8_t)(*ptr); mb_c = c; @@ -1729,22 +1788,22 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, || (mb_l > 1 && (!vim_isprintc(mb_c)))) { // Illegal UTF-8 byte: display as <xx>. // Non-BMP character : display as ? or fullwidth ?. - transchar_hex(extra, mb_c); + transchar_hex(wlv.extra, mb_c); if (wp->w_p_rl) { // reverse - rl_mirror(extra); + rl_mirror(wlv.extra); } - p_extra = extra; - c = (uint8_t)(*p_extra); - mb_c = mb_ptr2char_adv((const char **)&p_extra); + wlv.p_extra = wlv.extra; + c = (uint8_t)(*wlv.p_extra); + mb_c = mb_ptr2char_adv((const char **)&wlv.p_extra); mb_utf8 = (c >= 0x80); - n_extra = (int)strlen(p_extra); - c_extra = NUL; - c_final = NUL; + wlv.n_extra = (int)strlen(wlv.p_extra); + wlv.c_extra = NUL; + wlv.c_final = NUL; if (area_attr == 0 && search_attr == 0) { - n_attr = n_extra + 1; - extra_attr = win_hl_attr(wp, HLF_8); - saved_attr2 = char_attr; // save current attr + n_attr = wlv.n_extra + 1; + wlv.extra_attr = win_hl_attr(wp, HLF_8); + saved_attr2 = wlv.char_attr; // save current attr } } else if (mb_l == 0) { // at the NUL at end-of-line mb_l = 1; @@ -1774,8 +1833,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // If a double-width char doesn't fit display a '>' in the // last column; the character is displayed at the start of the // next line. - if ((wp->w_p_rl ? (col <= 0) : - (col >= grid->cols - 1)) + if ((wp->w_p_rl ? (wlv.col <= 0) : (wlv.col >= grid->cols - 1)) && utf_char2cells(mb_c) == 2) { c = '>'; mb_c = c; @@ -1792,15 +1850,15 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // If a double-width char doesn't fit at the left side display a '<' in // the first column. Don't do this for unprintable characters. - if (n_skip > 0 && mb_l > 1 && n_extra == 0) { - n_extra = 1; - c_extra = MB_FILLER_CHAR; - c_final = NUL; + if (n_skip > 0 && mb_l > 1 && wlv.n_extra == 0) { + wlv.n_extra = 1; + wlv.c_extra = MB_FILLER_CHAR; + wlv.c_final = NUL; c = ' '; if (area_attr == 0 && search_attr == 0) { - n_attr = n_extra + 1; - extra_attr = win_hl_attr(wp, HLF_AT); - saved_attr2 = char_attr; // save current attr + n_attr = wlv.n_extra + 1; + wlv.extra_attr = win_hl_attr(wp, HLF_AT); + saved_attr2 = wlv.char_attr; // save current attr } mb_c = c; mb_utf8 = false; @@ -1841,15 +1899,15 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, ptr = line + v; if (!attr_pri) { - if (cul_attr) { - char_attr = 0 != line_attr_lowprio - ? hl_combine_attr(cul_attr, syntax_attr) - : hl_combine_attr(syntax_attr, cul_attr); + if (wlv.cul_attr) { + wlv.char_attr = 0 != wlv.line_attr_lowprio + ? hl_combine_attr(wlv.cul_attr, syntax_attr) + : hl_combine_attr(syntax_attr, wlv.cul_attr); } else { - char_attr = syntax_attr; + wlv.char_attr = syntax_attr; } } else { - char_attr = hl_combine_attr(syntax_attr, char_attr); + wlv.char_attr = hl_combine_attr(syntax_attr, wlv.char_attr); } // no concealing past the end of the line, it interferes // with line highlighting. @@ -1859,19 +1917,19 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, syntax_flags = get_syntax_info(&syntax_seqnr); } } else if (!attr_pri) { - char_attr = 0; + wlv.char_attr = 0; } if (has_decor && v > 0) { bool selected = (area_active || (area_highlighting && noinvcur - && vcol == wp->w_virtcol)); - int extmark_attr = decor_redraw_col(wp->w_buffer, (colnr_T)v - 1, off, + && wlv.vcol == wp->w_virtcol)); + int extmark_attr = decor_redraw_col(wp->w_buffer, (colnr_T)v - 1, wlv.off, selected, &decor_state); if (extmark_attr != 0) { if (!attr_pri) { - char_attr = hl_combine_attr(char_attr, extmark_attr); + wlv.char_attr = hl_combine_attr(wlv.char_attr, extmark_attr); } else { - char_attr = hl_combine_attr(extmark_attr, char_attr); + wlv.char_attr = hl_combine_attr(extmark_attr, wlv.char_attr); } } @@ -1891,7 +1949,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, if (has_spell && v >= word_end && v > cur_checked_col) { spell_attr = 0; if (!attr_pri) { - char_attr = hl_combine_attr(char_attr, syntax_attr); + wlv.char_attr = hl_combine_attr(wlv.char_attr, syntax_attr); } if (c != 0 && ((!has_syntax && !no_plain_buffer) || can_spell)) { char *prev_ptr; @@ -1956,14 +2014,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } if (spell_attr != 0) { if (!attr_pri) { - char_attr = hl_combine_attr(char_attr, spell_attr); + wlv.char_attr = hl_combine_attr(wlv.char_attr, spell_attr); } else { - char_attr = hl_combine_attr(spell_attr, char_attr); + wlv.char_attr = hl_combine_attr(spell_attr, wlv.char_attr); } } if (wp->w_buffer->terminal) { - char_attr = hl_combine_attr(term_attrs[vcol], char_attr); + wlv.char_attr = hl_combine_attr(term_attrs[wlv.vcol], wlv.char_attr); } // Found last space before word: check for line break. @@ -1973,15 +2031,15 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, char *p = ptr - (mb_off + 1); chartabsize_T cts; - init_chartabsize_arg(&cts, wp, lnum, vcol, line, p); - n_extra = win_lbr_chartabsize(&cts, NULL) - 1; + init_chartabsize_arg(&cts, wp, lnum, wlv.vcol, line, p); + wlv.n_extra = win_lbr_chartabsize(&cts, NULL) - 1; // We have just drawn the showbreak value, no need to add // space for it again. - if (vcol == vcol_sbr) { - n_extra -= mb_charlen(get_showbreak_value(wp)); - if (n_extra < 0) { - n_extra = 0; + if (wlv.vcol == wlv.vcol_sbr) { + wlv.n_extra -= mb_charlen(get_showbreak_value(wp)); + if (wlv.n_extra < 0) { + wlv.n_extra = 0; } } if (on_last_col && c != TAB) { @@ -1991,12 +2049,12 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, search_attr = 0; } - if (c == TAB && n_extra + col > grid->cols) { - n_extra = tabstop_padding(vcol, wp->w_buffer->b_p_ts, - wp->w_buffer->b_p_vts_array) - 1; + if (c == TAB && wlv.n_extra + wlv.col > grid->cols) { + wlv.n_extra = tabstop_padding(wlv.vcol, wp->w_buffer->b_p_ts, + wp->w_buffer->b_p_vts_array) - 1; } - c_extra = mb_off > 0 ? MB_FILLER_CHAR : ' '; - c_final = NUL; + wlv.c_extra = mb_off > 0 ? MB_FILLER_CHAR : ' '; + wlv.c_final = NUL; if (ascii_iswhite(c)) { if (c == TAB) { // See "Tab alignment" below. @@ -2038,8 +2096,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, c = (c == ' ') ? wp->w_p_lcs_chars.space : wp->w_p_lcs_chars.nbsp; } n_attr = 1; - extra_attr = win_hl_attr(wp, HLF_0); - saved_attr2 = char_attr; // save current attr + wlv.extra_attr = win_hl_attr(wp, HLF_0); + saved_attr2 = wlv.char_attr; // save current attr mb_c = c; mb_utf8 = check_mb_utf8(&c, u8cc); } @@ -2061,8 +2119,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } n_attr = 1; - extra_attr = win_hl_attr(wp, HLF_0); - saved_attr2 = char_attr; // save current attr + wlv.extra_attr = win_hl_attr(wp, HLF_0); + saved_attr2 = wlv.char_attr; // save current attr mb_c = c; mb_utf8 = check_mb_utf8(&c, u8cc); } @@ -2074,13 +2132,13 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // turn it into something else on the way to putting it on the screen. if (c == TAB && (!wp->w_p_list || wp->w_p_lcs_chars.tab1)) { int tab_len = 0; - long vcol_adjusted = vcol; // removed showbreak length + long vcol_adjusted = wlv.vcol; // removed showbreak length char *const sbr = get_showbreak_value(wp); // Only adjust the tab_len, when at the first column after the // showbreak value was drawn. - if (*sbr != NUL && vcol == vcol_sbr && wp->w_p_wrap) { - vcol_adjusted = vcol - mb_charlen(sbr); + if (*sbr != NUL && wlv.vcol == wlv.vcol_sbr && wp->w_p_wrap) { + vcol_adjusted = wlv.vcol - mb_charlen(sbr); } // tab amount depends on current column tab_len = tabstop_padding((colnr_T)vcol_adjusted, @@ -2088,62 +2146,65 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, wp->w_buffer->b_p_vts_array) - 1; if (!wp->w_p_lbr || !wp->w_p_list) { - n_extra = tab_len; + wlv.n_extra = tab_len; } else { char *p; - int saved_nextra = n_extra; + int saved_nextra = wlv.n_extra; - if (vcol_off > 0) { + if (wlv.vcol_off > 0) { // there are characters to conceal - tab_len += vcol_off; + tab_len += wlv.vcol_off; } // boguscols before FIX_FOR_BOGUSCOLS macro from above. if (wp->w_p_lcs_chars.tab1 && old_boguscols > 0 - && n_extra > tab_len) { - tab_len += n_extra - tab_len; + && wlv.n_extra > tab_len) { + tab_len += wlv.n_extra - tab_len; } - // If n_extra > 0, it gives the number of chars - // to use for a tab, else we need to calculate the width - // for a tab. - int len = (tab_len * utf_char2len(wp->w_p_lcs_chars.tab2)); - if (wp->w_p_lcs_chars.tab3) { - len += utf_char2len(wp->w_p_lcs_chars.tab3); - } - if (n_extra > 0) { - len += n_extra - tab_len; - } - c = wp->w_p_lcs_chars.tab1; - p = xmalloc((size_t)len + 1); - memset(p, ' ', (size_t)len); - p[len] = NUL; - xfree(p_extra_free); - p_extra_free = p; - for (int i = 0; i < tab_len; i++) { - if (*p == NUL) { - tab_len = i; - break; + if (tab_len > 0) { + // If wlv.n_extra > 0, it gives the number of chars + // to use for a tab, else we need to calculate the + // width for a tab. + int tab2_len = utf_char2len(wp->w_p_lcs_chars.tab2); + int len = tab_len * tab2_len; + if (wp->w_p_lcs_chars.tab3) { + len += utf_char2len(wp->w_p_lcs_chars.tab3) - tab2_len; } - int lcs = wp->w_p_lcs_chars.tab2; + if (wlv.n_extra > 0) { + len += wlv.n_extra - tab_len; + } + c = wp->w_p_lcs_chars.tab1; + p = xmalloc((size_t)len + 1); + memset(p, ' ', (size_t)len); + p[len] = NUL; + xfree(wlv.p_extra_free); + wlv.p_extra_free = p; + for (int i = 0; i < tab_len; i++) { + if (*p == NUL) { + tab_len = i; + break; + } + int lcs = wp->w_p_lcs_chars.tab2; - // if tab3 is given, use it for the last char - if (wp->w_p_lcs_chars.tab3 && i == tab_len - 1) { - lcs = wp->w_p_lcs_chars.tab3; + // if tab3 is given, use it for the last char + if (wp->w_p_lcs_chars.tab3 && i == tab_len - 1) { + lcs = wp->w_p_lcs_chars.tab3; + } + p += utf_char2bytes(lcs, p); + wlv.n_extra += utf_char2len(lcs) - (saved_nextra > 0 ? 1 : 0); } - p += utf_char2bytes(lcs, p); - n_extra += utf_char2len(lcs) - (saved_nextra > 0 ? 1 : 0); - } - p_extra = p_extra_free; + wlv.p_extra = wlv.p_extra_free; - // n_extra will be increased by FIX_FOX_BOGUSCOLS - // macro below, so need to adjust for that here - if (vcol_off > 0) { - n_extra -= vcol_off; + // n_extra will be increased by FIX_FOX_BOGUSCOLS + // macro below, so need to adjust for that here + if (wlv.vcol_off > 0) { + wlv.n_extra -= wlv.vcol_off; + } } } { - int vc_saved = vcol_off; + int vc_saved = wlv.vcol_off; // Tab alignment should be identical regardless of // 'conceallevel' value. So tab compensates of all @@ -2156,7 +2217,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // Make sure, the highlighting for the tab char will be // correctly set further below (effectively reverts the // FIX_FOR_BOGSUCOLS macro). - if (n_extra == tab_len + vc_saved && wp->w_p_list + if (wlv.n_extra == tab_len + vc_saved && wp->w_p_list && wp->w_p_lcs_chars.tab1) { tab_len += vc_saved; } @@ -2164,50 +2225,50 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, mb_utf8 = false; // don't draw as UTF-8 if (wp->w_p_list) { - c = (n_extra == 0 && wp->w_p_lcs_chars.tab3) + c = (wlv.n_extra == 0 && wp->w_p_lcs_chars.tab3) ? wp->w_p_lcs_chars.tab3 : wp->w_p_lcs_chars.tab1; - if (wp->w_p_lbr) { - c_extra = NUL; // using p_extra from above + if (wp->w_p_lbr && wlv.p_extra != NULL && *wlv.p_extra != NUL) { + wlv.c_extra = NUL; // using p_extra from above } else { - c_extra = wp->w_p_lcs_chars.tab2; + wlv.c_extra = wp->w_p_lcs_chars.tab2; } - c_final = wp->w_p_lcs_chars.tab3; + wlv.c_final = wp->w_p_lcs_chars.tab3; n_attr = tab_len + 1; - extra_attr = win_hl_attr(wp, HLF_0); - saved_attr2 = char_attr; // save current attr + wlv.extra_attr = win_hl_attr(wp, HLF_0); + saved_attr2 = wlv.char_attr; // save current attr mb_c = c; mb_utf8 = check_mb_utf8(&c, u8cc); } else { - c_final = NUL; - c_extra = ' '; + wlv.c_final = NUL; + wlv.c_extra = ' '; c = ' '; } } else if (c == NUL && (wp->w_p_list - || ((fromcol >= 0 || fromcol_prev >= 0) - && tocol > vcol + || ((wlv.fromcol >= 0 || fromcol_prev >= 0) + && wlv.tocol > wlv.vcol && VIsual_mode != Ctrl_V - && (wp->w_p_rl ? (col >= 0) : (col < grid->cols)) + && (wp->w_p_rl ? (wlv.col >= 0) : (wlv.col < grid->cols)) && !(noinvcur && lnum == wp->w_cursor.lnum - && vcol == wp->w_virtcol))) + && wlv.vcol == wp->w_virtcol))) && lcs_eol_one > 0) { // Display a '$' after the line or highlight an extra // character if the line break is included. // For a diff line the highlighting continues after the "$". - if (diff_hlf == (hlf_T)0 - && line_attr == 0 - && line_attr_lowprio == 0) { + if (wlv.diff_hlf == (hlf_T)0 + && wlv.line_attr == 0 + && wlv.line_attr_lowprio == 0) { // In virtualedit, visual selections may extend beyond end of line if (area_highlighting && virtual_active() - && tocol != MAXCOL && vcol < tocol) { - n_extra = 0; + && wlv.tocol != MAXCOL && wlv.vcol < wlv.tocol) { + wlv.n_extra = 0; } else { - p_extra = at_end_str; - n_extra = 1; - c_extra = NUL; - c_final = NUL; + wlv.p_extra = at_end_str; + wlv.n_extra = 1; + wlv.c_extra = NUL; + wlv.c_final = NUL; } } if (wp->w_p_list && wp->w_p_lcs_chars.eol > 0) { @@ -2217,46 +2278,46 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } lcs_eol_one = -1; ptr--; // put it back at the NUL - extra_attr = win_hl_attr(wp, HLF_AT); + wlv.extra_attr = win_hl_attr(wp, HLF_AT); n_attr = 1; mb_c = c; mb_utf8 = check_mb_utf8(&c, u8cc); } else if (c != NUL) { - p_extra = (char *)transchar_buf(wp->w_buffer, c); - if (n_extra == 0) { - n_extra = byte2cells(c) - 1; + wlv.p_extra = (char *)transchar_buf(wp->w_buffer, c); + if (wlv.n_extra == 0) { + wlv.n_extra = byte2cells(c) - 1; } if ((dy_flags & DY_UHEX) && wp->w_p_rl) { - rl_mirror(p_extra); // reverse "<12>" + rl_mirror(wlv.p_extra); // reverse "<12>" } - c_extra = NUL; - c_final = NUL; + wlv.c_extra = NUL; + wlv.c_final = NUL; if (wp->w_p_lbr) { char *p; - c = (uint8_t)(*p_extra); - p = xmalloc((size_t)n_extra + 1); - memset(p, ' ', (size_t)n_extra); + c = (uint8_t)(*wlv.p_extra); + p = xmalloc((size_t)wlv.n_extra + 1); + memset(p, ' ', (size_t)wlv.n_extra); strncpy(p, // NOLINT(runtime/printf) - p_extra + 1, - (size_t)strlen(p_extra) - 1); - p[n_extra] = NUL; - xfree(p_extra_free); - p_extra_free = p_extra = p; + wlv.p_extra + 1, + (size_t)strlen(wlv.p_extra) - 1); + p[wlv.n_extra] = NUL; + xfree(wlv.p_extra_free); + wlv.p_extra_free = wlv.p_extra = p; } else { - n_extra = byte2cells(c) - 1; - c = (uint8_t)(*p_extra++); + wlv.n_extra = byte2cells(c) - 1; + c = (uint8_t)(*wlv.p_extra++); } - n_attr = n_extra + 1; - extra_attr = win_hl_attr(wp, HLF_8); - saved_attr2 = char_attr; // save current attr + n_attr = wlv.n_extra + 1; + wlv.extra_attr = win_hl_attr(wp, HLF_8); + saved_attr2 = wlv.char_attr; // save current attr mb_utf8 = false; // don't draw as UTF-8 } else if (VIsual_active && (VIsual_mode == Ctrl_V || VIsual_mode == 'v') && virtual_active() - && tocol != MAXCOL - && vcol < tocol - && (wp->w_p_rl ? (col >= 0) : (col < grid->cols))) { + && wlv.tocol != MAXCOL + && wlv.vcol < wlv.tocol + && (wp->w_p_rl ? (wlv.col >= 0) : (wlv.col < grid->cols))) { c = ' '; ptr--; // put it back at the NUL } @@ -2266,7 +2327,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, && (wp != curwin || lnum != wp->w_cursor.lnum || conceal_cursor_line(wp)) && ((syntax_flags & HL_CONCEAL) != 0 || has_match_conc > 0 || decor_conceal > 0) && !(lnum_in_visual_area && vim_strchr(wp->w_p_cocu, 'v') == NULL)) { - char_attr = conceal_attr; + wlv.char_attr = conceal_attr; if (((prev_syntax_id != syntax_seqnr && (syntax_flags & HL_CONCEAL) != 0) || has_match_conc > 1 || decor_conceal > 1) && (syn_get_sub_char() != NUL @@ -2281,7 +2342,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } else if (decor_conceal && decor_state.conceal_char) { c = decor_state.conceal_char; if (decor_state.conceal_attr) { - char_attr = decor_state.conceal_attr; + wlv.char_attr = decor_state.conceal_attr; } } else if (syn_get_sub_char() != NUL) { c = syn_get_sub_char(); @@ -2293,20 +2354,20 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, prev_syntax_id = syntax_seqnr; - if (n_extra > 0) { - vcol_off += n_extra; + if (wlv.n_extra > 0) { + wlv.vcol_off += wlv.n_extra; } - vcol += n_extra; - if (wp->w_p_wrap && n_extra > 0) { + wlv.vcol += wlv.n_extra; + if (wp->w_p_wrap && wlv.n_extra > 0) { if (wp->w_p_rl) { - col -= n_extra; - boguscols -= n_extra; + wlv.col -= wlv.n_extra; + wlv.boguscols -= wlv.n_extra; } else { - boguscols += n_extra; - col += n_extra; + wlv.boguscols += wlv.n_extra; + wlv.col += wlv.n_extra; } } - n_extra = 0; + wlv.n_extra = 0; n_attr = 0; } else if (n_skip == 0) { is_concealing = true; @@ -2327,23 +2388,23 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // In the cursor line and we may be concealing characters: correct // the cursor column when we reach its position. - if (!did_wcol && draw_state == WL_LINE + if (!did_wcol && wlv.draw_state == WL_LINE && wp == curwin && lnum == wp->w_cursor.lnum && conceal_cursor_line(wp) - && (int)wp->w_virtcol <= vcol + n_skip) { + && (int)wp->w_virtcol <= wlv.vcol + n_skip) { if (wp->w_p_rl) { - wp->w_wcol = grid->cols - col + boguscols - 1; + wp->w_wcol = grid->cols - wlv.col + wlv.boguscols - 1; } else { - wp->w_wcol = col - boguscols; + wp->w_wcol = wlv.col - wlv.boguscols; } - wp->w_wrow = row; + wp->w_wrow = wlv.row; did_wcol = true; wp->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL; } // Don't override visual selection highlighting. - if (n_attr > 0 && draw_state == WL_LINE && !search_attr_from_match) { - char_attr = hl_combine_attr(char_attr, extra_attr); + if (n_attr > 0 && wlv.draw_state == WL_LINE && !search_attr_from_match) { + wlv.char_attr = hl_combine_attr(wlv.char_attr, wlv.extra_attr); } // Handle the case where we are in column 0 but not on the first @@ -2351,25 +2412,25 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // special character (via 'listchars' option "precedes:<char>". if (lcs_prec_todo != NUL && wp->w_p_list - && (wp->w_p_wrap ? (wp->w_skipcol > 0 && row == 0) : wp->w_leftcol > 0) - && filler_todo <= 0 - && draw_state > WL_STC + && (wp->w_p_wrap ? (wp->w_skipcol > 0 && wlv.row == 0) : wp->w_leftcol > 0) + && wlv.filler_todo <= 0 + && wlv.draw_state > WL_STC && c != NUL) { c = wp->w_p_lcs_chars.prec; lcs_prec_todo = NUL; if (utf_char2cells(mb_c) > 1) { // Double-width character being overwritten by the "precedes" // character, need to fill up half the character. - c_extra = MB_FILLER_CHAR; - c_final = NUL; - n_extra = 1; + wlv.c_extra = MB_FILLER_CHAR; + wlv.c_final = NUL; + wlv.n_extra = 1; n_attr = 2; - extra_attr = win_hl_attr(wp, HLF_AT); + wlv.extra_attr = win_hl_attr(wp, HLF_AT); } mb_c = c; mb_utf8 = check_mb_utf8(&c, u8cc); - saved_attr3 = char_attr; // save current attr - char_attr = win_hl_attr(wp, HLF_AT); // overwriting char_attr + saved_attr3 = wlv.char_attr; // save current attr + wlv.char_attr = win_hl_attr(wp, HLF_AT); // overwriting char_attr n_attr3 = 1; } @@ -2385,7 +2446,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // char on the screen, just overwrite that one (tricky!) Not // needed when a '$' was displayed for 'list'. if (wp->w_p_lcs_chars.eol == lcs_eol_one - && ((area_attr != 0 && vcol == fromcol + && ((area_attr != 0 && wlv.vcol == wlv.fromcol && (VIsual_mode != Ctrl_V || lnum == VIsual.lnum || lnum == curwin->w_cursor.lnum)) @@ -2394,22 +2455,22 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, int n = 0; if (wp->w_p_rl) { - if (col < 0) { + if (wlv.col < 0) { n = 1; } } else { - if (col >= grid->cols) { + if (wlv.col >= grid->cols) { n = -1; } } if (n != 0) { // At the window boundary, highlight the last character // instead (better than nothing). - off += n; - col += n; + wlv.off += n; + wlv.col += n; } else { // Add a blank character to highlight. - schar_from_ascii(linebuf_char[off], ' '); + schar_from_ascii(linebuf_char[wlv.off], ' '); } if (area_attr == 0 && !has_fold) { // Use attributes from match with highest priority among @@ -2417,24 +2478,28 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, get_search_match_hl(wp, &screen_search_hl, (long)(ptr - line), // NOLINT(google-readability-casting) - &char_attr); + &wlv.char_attr); } - int eol_attr = char_attr; - if (cul_attr) { - eol_attr = hl_combine_attr(cul_attr, eol_attr); + int eol_attr = wlv.char_attr; + if (wlv.cul_attr) { + eol_attr = hl_combine_attr(wlv.cul_attr, eol_attr); } - linebuf_attr[off] = eol_attr; + linebuf_attr[wlv.off] = eol_attr; if (wp->w_p_rl) { - col--; - off--; + wlv.col--; + wlv.off--; } else { - col++; - off++; + wlv.col++; + wlv.off++; } - vcol++; + wlv.vcol++; eol_hl_off = 1; } + } + + // At end of the text line. + if (c == NUL) { // Highlight 'cursorcolumn' & 'colorcolumn' past end of the line. if (wp->w_p_wrap) { v = wp->w_skipcol; @@ -2443,13 +2508,13 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } // check if line ends before left margin - if (vcol < v + col - win_col_off(wp)) { - vcol = (colnr_T)v + col - win_col_off(wp); + if (wlv.vcol < v + wlv.col - win_col_off(wp)) { + wlv.vcol = (colnr_T)v + wlv.col - win_col_off(wp); } // Get rid of the boguscols now, we want to draw until the right // edge for 'cursorcolumn'. - col -= boguscols; - // boguscols = 0; // Disabled because value never read after this + wlv.col -= wlv.boguscols; + wlv.boguscols = 0; if (draw_color_col) { draw_color_col = advance_color_col(VCOL_HLC, &color_cols); @@ -2462,17 +2527,17 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, ? 1 : 0); if (has_decor) { - has_virttext = decor_redraw_eol(wp->w_buffer, &decor_state, &line_attr, - col + eol_skip); + has_virttext = decor_redraw_eol(wp->w_buffer, &decor_state, &wlv.line_attr, + wlv.col + eol_skip); } if (((wp->w_p_cuc && (int)wp->w_virtcol >= VCOL_HLC - eol_hl_off && (int)wp->w_virtcol < - (long)grid->cols * (row - startrow + 1) + v + (long)grid->cols * (wlv.row - startrow + 1) + v && lnum != wp->w_cursor.lnum) - || draw_color_col || line_attr_lowprio || line_attr - || diff_hlf != (hlf_T)0 || has_virttext)) { + || draw_color_col || wlv.line_attr_lowprio || wlv.line_attr + || wlv.diff_hlf != (hlf_T)0 || has_virttext)) { int rightmost_vcol = 0; if (wp->w_p_cuc) { @@ -2492,23 +2557,23 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, int mc_attr = win_hl_attr(wp, HLF_MC); int diff_attr = 0; - if (diff_hlf == HLF_TXD) { - diff_hlf = HLF_CHD; + if (wlv.diff_hlf == HLF_TXD) { + wlv.diff_hlf = HLF_CHD; } - if (diff_hlf != 0) { - diff_attr = win_hl_attr(wp, (int)diff_hlf); + if (wlv.diff_hlf != 0) { + diff_attr = win_hl_attr(wp, (int)wlv.diff_hlf); } - int base_attr = hl_combine_attr(line_attr_lowprio, diff_attr); - if (base_attr || line_attr || has_virttext) { + int base_attr = hl_combine_attr(wlv.line_attr_lowprio, diff_attr); + if (base_attr || wlv.line_attr || has_virttext) { rightmost_vcol = INT_MAX; } int col_stride = wp->w_p_rl ? -1 : 1; - while (wp->w_p_rl ? col >= 0 : col < grid->cols) { - schar_from_ascii(linebuf_char[off], ' '); - col += col_stride; + while (wp->w_p_rl ? wlv.col >= 0 : wlv.col < grid->cols) { + schar_from_ascii(linebuf_char[wlv.off], ' '); + wlv.col += col_stride; if (draw_color_col) { draw_color_col = advance_color_col(VCOL_HLC, &color_cols); } @@ -2521,16 +2586,16 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, col_attr = mc_attr; } - col_attr = hl_combine_attr(col_attr, line_attr); + col_attr = hl_combine_attr(col_attr, wlv.line_attr); - linebuf_attr[off] = col_attr; - off += col_stride; + linebuf_attr[wlv.off] = col_attr; + wlv.off += col_stride; if (VCOL_HLC >= rightmost_vcol) { break; } - vcol += 1; + wlv.vcol += 1; } } @@ -2539,24 +2604,24 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // terminal buffers may need to highlight beyond the end of the // logical line int n = wp->w_p_rl ? -1 : 1; - while (col >= 0 && col < grid->cols) { - schar_from_ascii(linebuf_char[off], ' '); - linebuf_attr[off] = vcol >= TERM_ATTRS_MAX ? 0 : term_attrs[vcol]; - off += n; - vcol += n; - col += n; + while (wlv.col >= 0 && wlv.col < grid->cols) { + schar_from_ascii(linebuf_char[wlv.off], ' '); + linebuf_attr[wlv.off] = wlv.vcol >= TERM_ATTRS_MAX ? 0 : term_attrs[wlv.vcol]; + wlv.off += n; + wlv.vcol += n; + wlv.col += n; } } - draw_virt_text(wp, buf, win_col_offset, &col, grid->cols, row); - grid_put_linebuf(grid, row, 0, col, grid->cols, wp->w_p_rl, wp, bg_attr, false); - row++; + draw_virt_text(wp, buf, win_col_offset, &wlv.col, grid->cols, wlv.row); + grid_put_linebuf(grid, wlv.row, 0, wlv.col, grid->cols, wp->w_p_rl, wp, bg_attr, false); + wlv.row++; // Update w_cline_height and w_cline_folded if the cursor line was // updated (saves a call to plines_win() later). if (wp == curwin && lnum == curwin->w_cursor.lnum) { curwin->w_cline_row = startrow; - curwin->w_cline_height = row - startrow; + curwin->w_cline_height = wlv.row - startrow; curwin->w_cline_folded = foldinfo.fi_lines > 0; curwin->w_valid |= (VALID_CHEIGHT|VALID_CROW); conceal_cursor_used = conceal_cursor_line(curwin); @@ -2567,17 +2632,17 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // Show "extends" character from 'listchars' if beyond the line end and // 'list' is set. if (wp->w_p_lcs_chars.ext != NUL - && draw_state == WL_LINE + && wlv.draw_state == WL_LINE && wp->w_p_list && !wp->w_p_wrap - && filler_todo <= 0 - && (wp->w_p_rl ? col == 0 : col == grid->cols - 1) + && wlv.filler_todo <= 0 + && (wp->w_p_rl ? wlv.col == 0 : wlv.col == grid->cols - 1) && !has_fold && (*ptr != NUL || lcs_eol_one > 0 - || (n_extra && (c_extra != NUL || *p_extra != NUL)))) { + || (wlv.n_extra && (wlv.c_extra != NUL || *wlv.p_extra != NUL)))) { c = wp->w_p_lcs_chars.ext; - char_attr = win_hl_attr(wp, HLF_AT); + wlv.char_attr = win_hl_attr(wp, HLF_AT); mb_c = c; mb_utf8 = check_mb_utf8(&c, u8cc); } @@ -2594,84 +2659,84 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // Also highlight the 'colorcolumn' if 'breakindent' and/or 'showbreak' // options are set vcol_save_attr = -1; - if ((draw_state == WL_LINE - || draw_state == WL_BRI - || draw_state == WL_SBR) + if ((wlv.draw_state == WL_LINE + || wlv.draw_state == WL_BRI + || wlv.draw_state == WL_SBR) && !lnum_in_visual_area && search_attr == 0 && area_attr == 0 - && filler_todo <= 0) { + && wlv.filler_todo <= 0) { if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol && lnum != wp->w_cursor.lnum) { - vcol_save_attr = char_attr; - char_attr = hl_combine_attr(win_hl_attr(wp, HLF_CUC), char_attr); + vcol_save_attr = wlv.char_attr; + wlv.char_attr = hl_combine_attr(win_hl_attr(wp, HLF_CUC), wlv.char_attr); } else if (draw_color_col && VCOL_HLC == *color_cols) { - vcol_save_attr = char_attr; - char_attr = hl_combine_attr(win_hl_attr(wp, HLF_MC), char_attr); + vcol_save_attr = wlv.char_attr; + wlv.char_attr = hl_combine_attr(win_hl_attr(wp, HLF_MC), wlv.char_attr); } } // Apply lowest-priority line attr now, so everything can override it. - if (draw_state == WL_LINE) { - char_attr = hl_combine_attr(line_attr_lowprio, char_attr); + if (wlv.draw_state == WL_LINE) { + wlv.char_attr = hl_combine_attr(wlv.line_attr_lowprio, wlv.char_attr); } // Store character to be displayed. // Skip characters that are left of the screen for 'nowrap'. - vcol_prev = vcol; - if (draw_state < WL_LINE || n_skip <= 0) { + vcol_prev = wlv.vcol; + if (wlv.draw_state < WL_LINE || n_skip <= 0) { // // Store the character. // if (wp->w_p_rl && utf_char2cells(mb_c) > 1) { // A double-wide character is: put first half in left cell. - off--; - col--; + wlv.off--; + wlv.col--; } if (mb_utf8) { - schar_from_cc(linebuf_char[off], mb_c, u8cc); + schar_from_cc(linebuf_char[wlv.off], mb_c, u8cc); } else { - schar_from_ascii(linebuf_char[off], (char)c); + schar_from_ascii(linebuf_char[wlv.off], (char)c); } if (multi_attr) { - linebuf_attr[off] = multi_attr; + linebuf_attr[wlv.off] = multi_attr; multi_attr = 0; } else { - linebuf_attr[off] = char_attr; + linebuf_attr[wlv.off] = wlv.char_attr; } if (utf_char2cells(mb_c) > 1) { // Need to fill two screen columns. - off++; - col++; + wlv.off++; + wlv.col++; // UTF-8: Put a 0 in the second screen char. - linebuf_char[off][0] = 0; - if (draw_state > WL_STC && filler_todo <= 0) { - vcol++; + linebuf_char[wlv.off][0] = 0; + if (wlv.draw_state > WL_STC && wlv.filler_todo <= 0) { + wlv.vcol++; } - // When "tocol" is halfway through a character, set it to the end of - // the character, otherwise highlighting won't stop. - if (tocol == vcol) { - tocol++; + // When "wlv.tocol" is halfway through a character, set it to the end + // of the character, otherwise highlighting won't stop. + if (wlv.tocol == wlv.vcol) { + wlv.tocol++; } if (wp->w_p_rl) { // now it's time to backup one cell - off--; - col--; + wlv.off--; + wlv.col--; } } if (wp->w_p_rl) { - off--; - col--; + wlv.off--; + wlv.col--; } else { - off++; - col++; + wlv.off++; + wlv.col++; } } else if (wp->w_p_cole > 0 && is_concealing) { n_skip--; - vcol_off++; - if (n_extra > 0) { - vcol_off += n_extra; + wlv.vcol_off++; + if (wlv.n_extra > 0) { + wlv.vcol_off += wlv.n_extra; } if (wp->w_p_wrap) { // Special voodoo required if 'wrap' is on. @@ -2681,45 +2746,45 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, // take up the same screen space when parts are concealed, // so that cursor line computations aren't messed up. // - // To avoid the fictitious advance of 'col' causing + // To avoid the fictitious advance of 'wlv.col' causing // trailing junk to be written out of the screen line // we are building, 'boguscols' keeps track of the number // of bad columns we have advanced. - if (n_extra > 0) { - vcol += n_extra; + if (wlv.n_extra > 0) { + wlv.vcol += wlv.n_extra; if (wp->w_p_rl) { - col -= n_extra; - boguscols -= n_extra; + wlv.col -= wlv.n_extra; + wlv.boguscols -= wlv.n_extra; } else { - col += n_extra; - boguscols += n_extra; + wlv.col += wlv.n_extra; + wlv.boguscols += wlv.n_extra; } - n_extra = 0; + wlv.n_extra = 0; n_attr = 0; } if (utf_char2cells(mb_c) > 1) { // Need to fill two screen columns. if (wp->w_p_rl) { - boguscols--; - col--; + wlv.boguscols--; + wlv.col--; } else { - boguscols++; - col++; + wlv.boguscols++; + wlv.col++; } } if (wp->w_p_rl) { - boguscols--; - col--; + wlv.boguscols--; + wlv.col--; } else { - boguscols++; - col++; + wlv.boguscols++; + wlv.col++; } } else { - if (n_extra > 0) { - vcol += n_extra; - n_extra = 0; + if (wlv.n_extra > 0) { + wlv.vcol += wlv.n_extra; + wlv.n_extra = 0; n_attr = 0; } } @@ -2727,58 +2792,58 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, n_skip--; } - // Only advance the "vcol" when after the 'number' or 'relativenumber' - // column. - if (draw_state > WL_STC - && filler_todo <= 0) { - vcol++; + // Only advance the "wlv.vcol" when after the 'number' or + // 'relativenumber' column. + if (wlv.draw_state > WL_STC + && wlv.filler_todo <= 0) { + wlv.vcol++; } if (vcol_save_attr >= 0) { - char_attr = vcol_save_attr; + wlv.char_attr = vcol_save_attr; } // restore attributes after "predeces" in 'listchars' - if (draw_state > WL_STC && n_attr3 > 0 && --n_attr3 == 0) { - char_attr = saved_attr3; + if (wlv.draw_state > WL_STC && n_attr3 > 0 && --n_attr3 == 0) { + wlv.char_attr = saved_attr3; } // restore attributes after last 'listchars' or 'number' char - if (n_attr > 0 && draw_state == WL_LINE && --n_attr == 0) { - char_attr = saved_attr2; + if (n_attr > 0 && wlv.draw_state == WL_LINE && --n_attr == 0) { + wlv.char_attr = saved_attr2; } // At end of screen line and there is more to come: Display the line // so far. If there is no more to display it is caught above. - if ((wp->w_p_rl ? (col < 0) : (col >= grid->cols)) + if ((wp->w_p_rl ? (wlv.col < 0) : (wlv.col >= grid->cols)) && (!has_fold || virt_line_offset >= 0) - && (draw_state != WL_LINE + && (wlv.draw_state != WL_LINE || *ptr != NUL - || filler_todo > 0 + || wlv.filler_todo > 0 || (wp->w_p_list && wp->w_p_lcs_chars.eol != NUL - && p_extra != at_end_str) - || (n_extra != 0 - && (c_extra != NUL || *p_extra != NUL)))) { + && wlv.p_extra != at_end_str) + || (wlv.n_extra != 0 + && (wlv.c_extra != NUL || *wlv.p_extra != NUL)))) { bool wrap = wp->w_p_wrap // Wrapping enabled. - && filler_todo <= 0 // Not drawing diff filler lines. + && wlv.filler_todo <= 0 // Not drawing diff filler lines. && lcs_eol_one != -1 // Haven't printed the lcs_eol character. - && row != endrow - 1 // Not the last line being displayed. + && wlv.row != endrow - 1 // Not the last line being displayed. && (grid->cols == Columns // Window spans the width of the screen, || ui_has(kUIMultigrid)) // or has dedicated grid. && !wp->w_p_rl; // Not right-to-left. - int draw_col = col - boguscols; + int draw_col = wlv.col - wlv.boguscols; if (virt_line_offset >= 0) { draw_virt_text_item(buf, virt_line_offset, kv_A(virt_lines, virt_line_index).line, kHlModeReplace, grid->cols, 0); } else { - draw_virt_text(wp, buf, win_col_offset, &draw_col, grid->cols, row); + draw_virt_text(wp, buf, win_col_offset, &draw_col, grid->cols, wlv.row); } - grid_put_linebuf(grid, row, 0, draw_col, grid->cols, wp->w_p_rl, wp, bg_attr, wrap); + grid_put_linebuf(grid, wlv.row, 0, draw_col, grid->cols, wp->w_p_rl, wp, bg_attr, wrap); if (wrap) { ScreenGrid *current_grid = grid; - int current_row = row, dummy_col = 0; // dummy_col unused + int current_row = wlv.row, dummy_col = 0; // dummy_col unused grid_adjust(¤t_grid, ¤t_row, &dummy_col); // Force a redraw of the first column of the next line. @@ -2788,49 +2853,37 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, current_grid->line_wraps[current_row] = true; } - boguscols = 0; - row++; + wlv.boguscols = 0; + wlv.row++; // When not wrapping and finished diff lines, or when displayed // '$' and highlighting until last column, break here. - if ((!wp->w_p_wrap && filler_todo <= 0) || lcs_eol_one == -1) { + if ((!wp->w_p_wrap && wlv.filler_todo <= 0) || lcs_eol_one == -1) { break; } // When the window is too narrow draw all "@" lines. - if (draw_state != WL_LINE && filler_todo <= 0) { - win_draw_end(wp, '@', ' ', true, row, wp->w_grid.rows, HLF_AT); - set_empty_rows(wp, row); - row = endrow; + if (wlv.draw_state != WL_LINE && wlv.filler_todo <= 0) { + win_draw_end(wp, '@', ' ', true, wlv.row, wp->w_grid.rows, HLF_AT); + set_empty_rows(wp, wlv.row); + wlv.row = endrow; } // When line got too long for screen break here. - if (row == endrow) { - row++; + if (wlv.row == endrow) { + wlv.row++; break; } - col = 0; - off = 0; - if (wp->w_p_rl) { - col = grid->cols - 1; // col is not used if breaking! - off += col; - } - - // reset the drawing state for the start of a wrapped line - draw_state = WL_START; - saved_n_extra = n_extra; - saved_p_extra = p_extra; - saved_c_extra = c_extra; - saved_c_final = c_final; - saved_char_attr = char_attr; - n_extra = 0; + win_line_start(wp, &wlv, true); + lcs_prec_todo = wp->w_p_lcs_chars.prec; - if (filler_todo <= 0) { - need_showbreak = true; + if (wlv.filler_todo <= 0) { + wlv.need_showbreak = true; } if (statuscol.draw) { - if (row == startrow + filler_lines + 1 || row == startrow + filler_lines) { + if (wlv.row == startrow + wlv.filler_lines + 1 + || wlv.row == startrow + wlv.filler_lines) { // Re-evaluate 'statuscolumn' for the first wrapped row and non filler line statuscol.textp = NULL; } else if (statuscol.textp) { @@ -2840,11 +2893,11 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } // Fall back to default columns if the 'n' flag isn't in 'cpo' statuscol.draw = vim_strchr(p_cpo, CPO_NUMCOL) == NULL; } - filler_todo--; + wlv.filler_todo--; virt_line_offset = -1; // When the filler lines are actually below the last line of the // file, don't draw the line itself, break here. - if (filler_todo == 0 && (wp->w_botfill || end_fill)) { + if (wlv.filler_todo == 0 && (wp->w_botfill || end_fill)) { break; } } @@ -2857,6 +2910,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, } kv_destroy(virt_lines); - xfree(p_extra_free); - return row; + xfree(wlv.p_extra_free); + return wlv.row; } diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index 6de3b0a9d0..8928979455 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -2096,10 +2096,10 @@ bool ins_compl_prep(int c) edit_submode_extra = NULL; } - // Ignore end of Select mode mapping and mouse scroll buttons. + // Ignore end of Select mode mapping and mouse scroll/movement. if (c == K_SELECT || c == K_MOUSEDOWN || c == K_MOUSEUP - || c == K_MOUSELEFT || c == K_MOUSERIGHT || c == K_EVENT - || c == K_COMMAND || c == K_LUA) { + || c == K_MOUSELEFT || c == K_MOUSERIGHT || c == K_MOUSEMOVE + || c == K_EVENT || c == K_COMMAND || c == K_LUA) { return retval; } @@ -3043,8 +3043,8 @@ static void get_next_spell_completion(linenr_T lnum) /// @param cur_match_pos current match position /// @param match_len /// @param cont_s_ipos next ^X<> will set initial_pos -static char *ins_comp_get_next_word_or_line(buf_T *ins_buf, pos_T *cur_match_pos, int *match_len, - bool *cont_s_ipos) +static char *ins_compl_get_next_word_or_line(buf_T *ins_buf, pos_T *cur_match_pos, int *match_len, + bool *cont_s_ipos) { *match_len = 0; char *ptr = ml_get_buf(ins_buf, cur_match_pos->lnum, false) + cur_match_pos->col; @@ -3206,8 +3206,8 @@ static int get_next_default_completion(ins_compl_next_state_T *st, pos_T *start_ continue; } int len; - char *ptr = ins_comp_get_next_word_or_line(st->ins_buf, st->cur_match_pos, - &len, &cont_s_ipos); + char *ptr = ins_compl_get_next_word_or_line(st->ins_buf, st->cur_match_pos, + &len, &cont_s_ipos); if (ptr == NULL) { continue; } diff --git a/src/nvim/po/CMakeLists.txt b/src/nvim/po/CMakeLists.txt index 74f043fe03..68e572911c 100644 --- a/src/nvim/po/CMakeLists.txt +++ b/src/nvim/po/CMakeLists.txt @@ -95,7 +95,6 @@ if(HAVE_WORKING_LIBINTL AND GETTEXT_FOUND AND XGETTEXT_PRG AND ICONV_PRG) COMMENT "Checking ${name}.po" VERBATIM DEPENDS ${poFile}) - set_target_properties(check-po-${name} PROPERTIES FOLDER po/check) endmacro() macro(BuildPoIconvGenericWithCharset @@ -182,9 +181,7 @@ if(HAVE_WORKING_LIBINTL AND GETTEXT_FOUND AND XGETTEXT_PRG AND ICONV_PRG) BuildMo(${LANGUAGE}) endforeach() - set_target_properties(${UPDATE_PO_TARGETS} PROPERTIES FOLDER po/update) add_custom_target(translations ALL DEPENDS ${LANGUAGE_MO_FILES}) add_custom_target(update-po DEPENDS ${UPDATE_PO_TARGETS}) - set_target_properties(translations update-po PROPERTIES FOLDER po) endif() diff --git a/src/nvim/testdir/test_breakindent.vim b/src/nvim/testdir/test_breakindent.vim index 2e377aa434..b61c9a570d 100644 --- a/src/nvim/testdir/test_breakindent.vim +++ b/src/nvim/testdir/test_breakindent.vim @@ -1075,4 +1075,22 @@ func Test_breakindent_column() bwipeout! endfunc +func Test_linebreak_list() + " This was setting wlv.c_extra to NUL while wlv.p_extra is NULL + filetype plugin on + syntax enable + edit! $VIMRUNTIME/doc/index.txt + /v_P + + setlocal list + setlocal listchars=tab:>- + setlocal linebreak + setlocal nowrap + setlocal filetype=help + redraw! + + bwipe! +endfunc + + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim index 148f8b6d42..eb00cb98ca 100644 --- a/src/nvim/testdir/test_filetype.vim +++ b/src/nvim/testdir/test_filetype.vim @@ -80,6 +80,7 @@ let s:filename_checks = { \ 'awk': ['file.awk', 'file.gawk'], \ 'b': ['file.mch', 'file.ref', 'file.imp'], \ 'basic': ['file.bas', 'file.bi', 'file.bm'], + \ 'bass': ['file.bass'], \ 'bc': ['file.bc'], \ 'bdf': ['file.bdf'], \ 'beancount': ['file.beancount'], diff --git a/src/nvim/testdir/test_ins_complete.vim b/src/nvim/testdir/test_ins_complete.vim index ec1379a378..af0856331d 100644 --- a/src/nvim/testdir/test_ins_complete.vim +++ b/src/nvim/testdir/test_ins_complete.vim @@ -375,6 +375,54 @@ func Test_completefunc_info() set completefunc& endfunc +" Test that mouse scrolling/movement should not interrupt completion. +func Test_mouse_scroll_move_during_completion() + new + com! -buffer TestCommand1 echo 'TestCommand1' + com! -buffer TestCommand2 echo 'TestCommand2' + call setline(1, ['', '', '', '', '']) + call cursor(5, 1) + + " Without completion menu scrolling can move text. + set completeopt-=menu wrap + call feedkeys("ccT\<C-X>\<C-V>\<ScrollWheelDown>\<C-V>", 'tx') + call assert_equal('TestCommand2', getline('.')) + call assert_notequal(1, winsaveview().topline) + call feedkeys("ccT\<C-X>\<C-V>\<ScrollWheelUp>\<C-V>", 'tx') + call assert_equal('TestCommand2', getline('.')) + call assert_equal(1, winsaveview().topline) + set nowrap + call feedkeys("ccT\<C-X>\<C-V>\<ScrollWheelRight>\<C-V>", 'tx') + call assert_equal('TestCommand2', getline('.')) + call assert_notequal(0, winsaveview().leftcol) + call feedkeys("ccT\<C-X>\<C-V>\<ScrollWheelLeft>\<C-V>", 'tx') + call assert_equal('TestCommand2', getline('.')) + call assert_equal(0, winsaveview().leftcol) + call feedkeys("ccT\<C-X>\<C-V>\<MouseMove>\<C-V>", 'tx') + call assert_equal('TestCommand2', getline('.')) + + " With completion menu scrolling cannot move text. + set completeopt+=menu wrap + call feedkeys("ccT\<C-X>\<C-V>\<ScrollWheelDown>\<C-V>", 'tx') + call assert_equal('TestCommand2', getline('.')) + call assert_equal(1, winsaveview().topline) + call feedkeys("ccT\<C-X>\<C-V>\<ScrollWheelUp>\<C-V>", 'tx') + call assert_equal('TestCommand2', getline('.')) + call assert_equal(1, winsaveview().topline) + set nowrap + call feedkeys("ccT\<C-X>\<C-V>\<ScrollWheelRight>\<C-V>", 'tx') + call assert_equal('TestCommand2', getline('.')) + call assert_equal(0, winsaveview().leftcol) + call feedkeys("ccT\<C-X>\<C-V>\<ScrollWheelLeft>\<C-V>", 'tx') + call assert_equal('TestCommand2', getline('.')) + call assert_equal(0, winsaveview().leftcol) + call feedkeys("ccT\<C-X>\<C-V>\<MouseMove>\<C-V>", 'tx') + call assert_equal('TestCommand2', getline('.')) + + bwipe! + set completeopt& wrap& +endfunc + " Check that when using feedkeys() typeahead does not interrupt searching for " completions. func Test_compl_feedkeys() diff --git a/src/nvim/testdir/test_listlbr.vim b/src/nvim/testdir/test_listlbr.vim index 1cbdba5d76..a746779e73 100644 --- a/src/nvim/testdir/test_listlbr.vim +++ b/src/nvim/testdir/test_listlbr.vim @@ -73,6 +73,30 @@ func Test_linebreak_with_nolist() call s:close_windows() endfunc +func Test_linebreak_with_list_and_number() + call s:test_windows('setl list listchars+=tab:>-') + call setline(1, ["abcdefg\thijklmnopqrstu", "v"]) + let lines = s:screen_lines([1, 4], winwidth(0)) + let expect_nonumber = [ +\ "abcdefg>------------", +\ "hijklmnopqrstu$ ", +\ "v$ ", +\ "~ ", +\ ] + call s:compare_lines(expect_nonumber, lines) + + setl number + let lines = s:screen_lines([1, 4], winwidth(0)) + let expect_number = [ +\ " 1 abcdefg>--------", +\ " hijklmnopqrstu$ ", +\ " 2 v$ ", +\ "~ ", +\ ] + call s:compare_lines(expect_number, lines) + call s:close_windows() +endfunc + func Test_should_break() call s:test_windows('setl sbr=+ nolist') call setline(1, "1\t" . repeat('a', winwidth(0)-2)) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index dc74838760..b84e4f7953 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -18,7 +18,6 @@ if(BUSTED_PRG) add_custom_target(unittest COMMAND ${CMAKE_COMMAND} -D BUSTED_PRG=${BUSTED_PRG} - -D LUA_PRG=${LUA_PRG} -D NVIM_PRG=$<TARGET_FILE:nvim> -D WORKING_DIR=${PROJECT_SOURCE_DIR} -D BUSTED_OUTPUT_TYPE=${BUSTED_OUTPUT_TYPE} @@ -30,7 +29,6 @@ if(BUSTED_PRG) -P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake DEPENDS ${UNITTEST_PREREQS} USES_TERMINAL) - set_target_properties(unittest PROPERTIES FOLDER test) else() message(WARNING "disabling unit tests: no Luajit FFI in ${LUA_PRG}") endif() @@ -42,7 +40,6 @@ if(BUSTED_PRG) add_custom_target(functionaltest COMMAND ${CMAKE_COMMAND} -D BUSTED_PRG=${BUSTED_PRG} - -D LUA_PRG=${LUA_PRG} -D NVIM_PRG=$<TARGET_FILE:nvim> -D WORKING_DIR=${PROJECT_SOURCE_DIR} -D BUSTED_OUTPUT_TYPE=${BUSTED_OUTPUT_TYPE} @@ -55,12 +52,10 @@ if(BUSTED_PRG) -P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake DEPENDS ${FUNCTIONALTEST_PREREQS} USES_TERMINAL) - set_target_properties(functionaltest PROPERTIES FOLDER test) add_custom_target(benchmark COMMAND ${CMAKE_COMMAND} -D BUSTED_PRG=${BUSTED_PRG} - -D LUA_PRG=${LUA_PRG} -D NVIM_PRG=$<TARGET_FILE:nvim> -D WORKING_DIR=${PROJECT_SOURCE_DIR} -D BUSTED_OUTPUT_TYPE=${BUSTED_OUTPUT_TYPE} @@ -72,7 +67,6 @@ if(BUSTED_PRG) -P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake DEPENDS ${BENCHMARK_PREREQS} USES_TERMINAL) - set_target_properties(benchmark PROPERTIES FOLDER test) endif() find_program(BUSTED_LUA_PRG busted-lua) @@ -80,7 +74,6 @@ if(BUSTED_LUA_PRG) add_custom_target(functionaltest-lua COMMAND ${CMAKE_COMMAND} -D BUSTED_PRG=${BUSTED_LUA_PRG} - -D LUA_PRG=${LUA_PRG} -D NVIM_PRG=$<TARGET_FILE:nvim> -D WORKING_DIR=${PROJECT_SOURCE_DIR} -D BUSTED_OUTPUT_TYPE=${BUSTED_OUTPUT_TYPE} @@ -92,5 +85,4 @@ if(BUSTED_LUA_PRG) -P ${PROJECT_SOURCE_DIR}/cmake/RunTests.cmake DEPENDS ${FUNCTIONALTEST_PREREQS} USES_TERMINAL) - set_target_properties(functionaltest-lua PROPERTIES FOLDER test) endif() diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua index 2cf18242ff..747aea54b7 100644 --- a/test/functional/treesitter/language_spec.lua +++ b/test/functional/treesitter/language_spec.lua @@ -33,7 +33,12 @@ describe('treesitter language API', function() it('shows error for invalid language name', function() eq(".../language.lua:0: '/foo/' is not a valid language name", - pcall_err(exec_lua, 'vim.treesitter.add("/foo/", nil, false)')) + pcall_err(exec_lua, 'vim.treesitter.add("/foo/")')) + end) + + it('shows error for invalid filetype', function() + eq('.../language.lua:0: \'\' is not a valid filetype', + pcall_err(exec_lua, [[vim.treesitter.add('foo', { filetype = '' })]])) end) it('inspects language', function() diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index fd9822d1c0..27f2e81ab2 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -4,6 +4,7 @@ local clear = helpers.clear local eq = helpers.eq local insert = helpers.insert local exec_lua = helpers.exec_lua +local pcall_err = helpers.pcall_err local feed = helpers.feed local is_os = helpers.is_os local skip = helpers.skip @@ -124,6 +125,16 @@ void ui_refresh(void) }, res) end) + it('does not get parser for empty filetype', function() + insert(test_text); + + eq(".../language.lua:0: '' is not a valid filetype", + pcall_err(exec_lua, 'vim.treesitter.get_parser(0)')) + + -- Must provide language for buffers with an empty filetype + exec_lua("vim.treesitter.get_parser(0, 'c')") + end) + it('allows to get a child by field', function() insert(test_text); @@ -874,9 +885,10 @@ int x = INT_MAX; it("can fold via foldexpr", function() insert(test_text) - exec_lua([[vim.treesitter.get_parser(0, "c")]]) local levels = exec_lua([[ + vim.opt.filetype = 'c' + vim.treesitter.get_parser(0, "c") local res = {} for i = 1, vim.api.nvim_buf_line_count(0) do res[i] = vim.treesitter.foldexpr(i) |