aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/test.yml7
-rw-r--r--CMakeLists.txt25
-rw-r--r--cmake.deps/CMakeLists.txt1
-rw-r--r--cmake.deps/deps.txt8
-rw-r--r--runtime/doc/api.txt15
-rw-r--r--runtime/doc/autocmd.txt25
-rw-r--r--runtime/doc/eval.txt43
-rw-r--r--runtime/doc/news.txt6
-rw-r--r--runtime/doc/pi_gzip.txt10
-rw-r--r--runtime/doc/pi_zip.txt7
-rw-r--r--runtime/doc/provider.txt30
-rw-r--r--runtime/doc/vim_diff.txt2
-rw-r--r--runtime/lua/vim/_editor.lua2
-rw-r--r--runtime/lua/vim/_meta/api.lua11
-rw-r--r--runtime/lua/vim/clipboard/osc52.lua38
-rw-r--r--runtime/plugin/man.lua1
-rw-r--r--src/nvim/api/ui.c27
-rw-r--r--src/nvim/charset.c4
-rw-r--r--src/nvim/drawline.c254
-rw-r--r--src/nvim/eval/funcs.c1
-rw-r--r--src/nvim/grid.c34
-rw-r--r--src/nvim/quickfix.c7
-rw-r--r--src/nvim/spellsuggest.c4
-rw-r--r--src/nvim/tui/input.c34
-rw-r--r--test/functional/core/job_spec.lua23
-rw-r--r--test/functional/lua/vim_spec.lua6
-rw-r--r--test/functional/ui/decorations_spec.lua10
27 files changed, 391 insertions, 244 deletions
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 096f86219e..1ebb26d5c0 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -136,6 +136,13 @@ jobs:
- name: Create log dir
run: mkdir -p "$LOG_DIR"
+ # FIXME(dundargoc): this workaround is needed for macos as the python3
+ # provider tests suddenly started to become extremely flaky, and this
+ # removes the flakiness for some reason.
+ - uses: actions/setup-python@v4
+ with:
+ python-version: '3.11'
+
- if: ${{ matrix.test != 'unittest' }}
name: Set up interpreter packages
run: |
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a7b7ef9c0f..72889283dc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -286,13 +286,18 @@ ExternalProject_Add(uncrustify
CMAKE_CACHE_ARGS ${DEPS_CMAKE_CACHE_ARGS}
EXCLUDE_FROM_ALL TRUE)
-ExternalProject_Add(lua-dev-deps
- URL https://github.com/neovim/deps/raw/5a1f71cceb24990a0b15fd9a472a5f549f019248/opt/lua-dev-deps.tar.gz
- URL_HASH SHA256=27db2495f5eddc7fc191701ec9b291486853530c6125609d3197d03481e8d5a2
- DOWNLOAD_NO_PROGRESS TRUE
- DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/lua-dev-deps
- SOURCE_DIR ${DEPS_SHARE_DIR}
- CONFIGURE_COMMAND ""
- BUILD_COMMAND ""
- INSTALL_COMMAND ""
- EXCLUDE_FROM_ALL TRUE)
+option(USE_BUNDLED_BUSTED "Use bundled luarocks" ON)
+if(USE_BUNDLED_BUSTED)
+ ExternalProject_Add(lua-dev-deps
+ URL https://github.com/neovim/deps/raw/5a1f71cceb24990a0b15fd9a472a5f549f019248/opt/lua-dev-deps.tar.gz
+ URL_HASH SHA256=27db2495f5eddc7fc191701ec9b291486853530c6125609d3197d03481e8d5a2
+ DOWNLOAD_NO_PROGRESS TRUE
+ DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/lua-dev-deps
+ SOURCE_DIR ${DEPS_SHARE_DIR}
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+ EXCLUDE_FROM_ALL TRUE)
+else()
+ add_custom_target(lua-dev-deps)
+endif()
diff --git a/cmake.deps/CMakeLists.txt b/cmake.deps/CMakeLists.txt
index 6dc6fcdc72..801be6be2b 100644
--- a/cmake.deps/CMakeLists.txt
+++ b/cmake.deps/CMakeLists.txt
@@ -11,6 +11,7 @@ list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" "${PROJECT_SOURCE_DI
include(ExternalProject)
include(CheckCCompilerFlag)
+include(FindPackageHandleStandardArgs)
include(Deps)
include(Find)
diff --git a/cmake.deps/deps.txt b/cmake.deps/deps.txt
index fd7b72346b..4c1502be75 100644
--- a/cmake.deps/deps.txt
+++ b/cmake.deps/deps.txt
@@ -1,11 +1,11 @@
-LIBUV_URL https://github.com/libuv/libuv/archive/v1.46.0.tar.gz
-LIBUV_SHA256 7aa66be3413ae10605e1f5c9ae934504ffe317ef68ea16fdaa83e23905c681bd
+LIBUV_URL https://github.com/libuv/libuv/archive/v1.47.0.tar.gz
+LIBUV_SHA256 d50af7e6d72526db137e66fad812421c8a1cae09d146b0ec2bb9a22c5f23ba93
MSGPACK_URL https://github.com/msgpack/msgpack-c/releases/download/c-6.0.0/msgpack-c-6.0.0.tar.gz
MSGPACK_SHA256 3654f5e2c652dc52e0a993e270bb57d5702b262703f03771c152bba51602aeba
-LUAJIT_URL https://github.com/LuaJIT/LuaJIT/archive/0afa1676b2d2aabf1f3101a2692eb0f1e291076a.tar.gz
-LUAJIT_SHA256 907f9ba0b64d1a06b6da092537e0d8b6009a34f5e1405fafaa588da7fdcefe59
+LUAJIT_URL https://github.com/LuaJIT/LuaJIT/archive/b94fbfbee9e7dd0979e35aacea7fcdd43905789b.tar.gz
+LUAJIT_SHA256 4fe0cf9323c87fdb717d3b8cd81441d2ead21c14842ed61172b3e99a5892043e
LUA_URL https://www.lua.org/ftp/lua-5.1.5.tar.gz
LUA_SHA256 2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index 2f9e8228d2..b38524bd55 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -3597,6 +3597,21 @@ nvim_ui_set_option({name}, {value}) *nvim_ui_set_option()*
Attributes: ~
|RPC| only
+nvim_ui_term_event({event}, {value}) *nvim_ui_term_event()*
+ Tells Nvim when a terminal event has occurred.
+
+ The following terminal events are supported:
+
+ • "osc_response": The terminal sent a OSC response sequence to Nvim. The
+ payload is the received OSC sequence.
+
+ Attributes: ~
+ |RPC| only
+
+ Parameters: ~
+ • {event} Event name
+ • {payload} Event payload
+
nvim_ui_try_resize({width}, {height}) *nvim_ui_try_resize()*
TODO: Documentation
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index 4b36a7d4ec..6b698b0868 100644
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -987,12 +987,25 @@ TermClose When a |terminal| job ends.
Sets these |v:event| keys:
status
*TermResponse*
-TermResponse After the response to t_RV is received from
- the terminal. The value of |v:termresponse|
- can be used to do things depending on the
- terminal version. May be triggered halfway
- through another event (file I/O, a shell
- command, or anything else that takes time).
+TermResponse When Nvim receives a OSC response from the
+ terminal. Sets |v:termresponse|. When used
+ from Lua, the response string is included in
+ the "data" field of the autocommand callback.
+ May be triggered halfway through another event
+ (file I/O, a shell command, or anything else
+ that takes time). Example: >lua
+
+ -- Query the terminal palette for the RGB value of color 1
+ -- (red) using OSC 4
+ vim.api.nvim_create_autocmd('TermResponse', {
+ once = true,
+ callback = function(args)
+ local resp = args.data
+ local r, g, b = resp:match("\x1b%]4;1;rgb:(%w+)/(%w+)/(%w+)")
+ end,
+ })
+ io.stdout:write("\x1b]4;1;?\x1b\\")
+<
*TextChanged*
TextChanged After a change was made to the text in the
current buffer in Normal mode. That is after
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index c41237b862..2223829548 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -2318,18 +2318,10 @@ v:t_string Value of |String| type. Read-only. See: |type()|
v:t_blob Value of |Blob| type. Read-only. See: |type()|
*v:termresponse* *termresponse-variable*
-v:termresponse The escape sequence returned by the terminal for the DA
- (request primary device attributes) control sequence. It is
- set when Vim receives an escape sequence that starts with ESC
- [ or CSI and ends in a 'c', with only digits, ';' and '.' in
- between.
- When this option is set, the TermResponse autocommand event is
- fired, so that you can react to the response from the
- terminal.
- The response from a new xterm is: "<Esc>[ Pp ; Pv ; Pc c". Pp
- is the terminal type: 0 for vt100 and 1 for vt220. Pv is the
- patch level (since this was introduced in patch 95, it's
- always 95 or bigger). Pc is always zero.
+v:termresponse The value of the most recent OSC escape sequence received by
+ Nvim from the terminal. This can be read in a |TermResponse|
+ event handler after querying the terminal using another escape
+ sequence.
*v:testing* *testing-variable*
v:testing Must be set before using `test_garbagecollect_now()`.
@@ -4354,6 +4346,33 @@ This is not allowed when the textlock is active:
- etc.
==============================================================================
+Vim script library *vim-script-library*
+
+Vim comes bundled with a Vim script library, that can be used by runtime,
+script authors. Currently, it only includes very few functions, but it may
+grow over time.
+
+ *dist#vim*
+The functions make use of the autoloaded prefix "dist#vim".
+
+The following functions are available:
+
+dist#vim#IsSafeExecutable(filetype, executable) ~
+
+This function takes a filetype and an executable and checks whether it is safe
+to execute the given executable. For security reasons users may not want to
+have Vim execute random executables or may have forbidden to do so for
+specific filetypes by setting the "<filetype>_exec" variable (|plugin_exec|).
+
+It returns |TRUE| or |FALSE| to indicate whether the plugin should run the given
+exectuable. It takes the following arguments:
+
+ argument type ~
+
+ filetype string
+ executable string
+
+==============================================================================
Command-line expressions highlighting *expr-highlight*
Expressions entered by the user in |i_CTRL-R_=|, |c_CTRL-\_e|, |quote=| are
diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt
index 9ddb1e91b7..ac84f59308 100644
--- a/runtime/doc/news.txt
+++ b/runtime/doc/news.txt
@@ -205,6 +205,12 @@ The following new APIs and features were added.
• Added |vim.base64.encode()| and |vim.base64.decode()| for encoding and decoding
strings using Base64 encoding.
+• The |TermResponse| autocommand event can be used with |v:termresponse| to
+ read escape sequence responses from the terminal.
+
+• A clipboard provider which uses OSC 52 to copy the selection to the system
+ clipboard is now bundled by default. |clipboard-osc52|
+
==============================================================================
CHANGED FEATURES *news-changed*
diff --git a/runtime/doc/pi_gzip.txt b/runtime/doc/pi_gzip.txt
index a709b34180..1aadc103fd 100644
--- a/runtime/doc/pi_gzip.txt
+++ b/runtime/doc/pi_gzip.txt
@@ -12,9 +12,17 @@ The functionality mentioned here is a |standard-plugin|.
This plugin is only available if 'compatible' is not set.
You can avoid loading this plugin by setting the "loaded_gzip" variable: >
:let loaded_gzip = 1
+<
+ *g:gzip_exec*
+
+For security reasons, one may prevent that Vim runs executables automatically
+when opening a buffer. This option (default: "1") can be used to prevent
+executing the executables command when set to "0": >
+ :let g:gzip_exec = 0
+<
==============================================================================
-1. Autocommands *gzip-autocmd*
+2. Autocommands *gzip-autocmd*
The plugin installs autocommands to intercept reading and writing of files
with these extensions:
diff --git a/runtime/doc/pi_zip.txt b/runtime/doc/pi_zip.txt
index 343c73839b..a8e1b8df10 100644
--- a/runtime/doc/pi_zip.txt
+++ b/runtime/doc/pi_zip.txt
@@ -70,6 +70,13 @@ Copyright: Copyright (C) 2005-2015 Charles E Campbell *zip-copyright*
extract a file from a zip archive. By default, >
let g:zip_extractcmd= g:zip_unzipcmd
<
+ *g:zip_exec*
+ For security reasons, one may prevent that Vim runs executables
+ automatically when opening a buffer. This option (default: "1")
+ can be used to prevent executing the "unzip" command when set to
+ "0": >
+ let g:zip_exec=0
+<
PREVENTING LOADING~
If for some reason you do not wish to use vim to examine zipped files,
diff --git a/runtime/doc/provider.txt b/runtime/doc/provider.txt
index 9e70ff8945..1b49ee3a3d 100644
--- a/runtime/doc/provider.txt
+++ b/runtime/doc/provider.txt
@@ -253,7 +253,35 @@ For Windows WSL, try this g:clipboard definition:
\ },
\ 'cache_enabled': 0,
\ }
-
+<
+ *clipboard-osc52*
+Nvim bundles a clipboard provider that allows copying to the system clipboard
+using OSC 52. OSC 52 is an Operating System Command control sequence that
+writes the copied text to the terminal emulator. If the terminal emulator
+supports OSC 52 then it will write the copied text into the system clipboard.
+
+This is most useful when using Nvim remotely (e.g. via ssh) as Nvim does not
+have direct access to the system clipboard in that case.
+
+Because not all terminal emulators support OSC 52, this provider must be opted
+into explicitly by setting the following |g:clipboard| definition: >lua
+
+ vim.g.clipboard = {
+ name = 'OSC 52',
+ copy = {
+ ['+'] = require('vim.clipboard.osc52').copy,
+ ['*'] = require('vim.clipboard.osc52').copy,
+ },
+ paste = {
+ ['+'] = require('vim.clipboard.osc52').paste,
+ ['*'] = require('vim.clipboard.osc52').paste,
+ },
+ }
+<
+Note that not all terminal emulators support reading from the system clipboard
+(and even for those that do, users should be aware of the security
+implications), so using OSC 52 for pasting may not be possible.
+<
==============================================================================
Paste *provider-paste* *paste*
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index 8249179187..efebf46d85 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -567,6 +567,8 @@ Working directory (Vim implemented some of these after Nvim):
Autocommands:
- Fixed inconsistent behavior in execution of nested autocommands:
https://github.com/neovim/neovim/issues/23368
+- |TermResponse| is fired for any OSC sequence received from the terminal,
+ instead of the Primary Device Attributes response. |v:termresponse|
==============================================================================
Missing features *nvim-missing*
diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua
index 0da127b18f..0bdf0c90a5 100644
--- a/runtime/lua/vim/_editor.lua
+++ b/runtime/lua/vim/_editor.lua
@@ -650,7 +650,7 @@ local on_key_cbs = {}
---if on_key() is called without arguments.
function vim.on_key(fn, ns_id)
if fn == nil and ns_id == nil then
- return #on_key_cbs
+ return vim.tbl_count(on_key_cbs)
end
vim.validate({
diff --git a/runtime/lua/vim/_meta/api.lua b/runtime/lua/vim/_meta/api.lua
index 6c6e11a0d3..2142a429a2 100644
--- a/runtime/lua/vim/_meta/api.lua
+++ b/runtime/lua/vim/_meta/api.lua
@@ -2065,6 +2065,17 @@ function vim.api.nvim_ui_set_focus(gained) end
--- @param value any
function vim.api.nvim_ui_set_option(name, value) end
+--- Tells Nvim when a terminal event has occurred.
+--- The following terminal events are supported:
+---
+--- • "osc_response": The terminal sent a OSC response sequence to Nvim. The
+--- payload is the received OSC sequence.
+---
+---
+--- @param event string Event name
+--- @param value any
+function vim.api.nvim_ui_term_event(event, value) end
+
--- @param width integer
--- @param height integer
function vim.api.nvim_ui_try_resize(width, height) end
diff --git a/runtime/lua/vim/clipboard/osc52.lua b/runtime/lua/vim/clipboard/osc52.lua
new file mode 100644
index 0000000000..0e8f9d378f
--- /dev/null
+++ b/runtime/lua/vim/clipboard/osc52.lua
@@ -0,0 +1,38 @@
+local M = {}
+
+function M.copy(lines)
+ local s = table.concat(lines, '\n')
+ io.stdout:write(string.format('\x1b]52;;%s\x1b\\', vim.base64.encode(s)))
+end
+
+function M.paste()
+ local contents = nil
+ local id = vim.api.nvim_create_autocmd('TermResponse', {
+ callback = function(args)
+ local resp = args.data ---@type string
+ local encoded = resp:match('\x1b%]52;%w?;([A-Za-z0-9+/=]*)')
+ if encoded then
+ contents = vim.base64.decode(encoded)
+ return true
+ end
+ end,
+ })
+
+ io.stdout:write('\x1b]52;;?\x1b\\')
+
+ vim.wait(1000, function()
+ return contents ~= nil
+ end)
+
+ -- Delete the autocommand if it didn't already delete itself
+ pcall(vim.api.nvim_del_autocmd, id)
+
+ if contents then
+ return vim.split(contents, '\n')
+ end
+
+ vim.notify('Timed out waiting for a clipboard response from the terminal', vim.log.levels.WARN)
+ return 0
+end
+
+return M
diff --git a/runtime/plugin/man.lua b/runtime/plugin/man.lua
index 4b1528b0cb..50a48fe7f2 100644
--- a/runtime/plugin/man.lua
+++ b/runtime/plugin/man.lua
@@ -16,6 +16,7 @@ vim.api.nvim_create_user_command('Man', function(params)
end, {
bang = true,
bar = true,
+ range = true,
addr = 'other',
nargs = '*',
complete = function(...)
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index b508a3ee94..99215f7b4f 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -16,6 +16,7 @@
#include "nvim/api/ui.h"
#include "nvim/autocmd.h"
#include "nvim/channel.h"
+#include "nvim/eval.h"
#include "nvim/event/loop.h"
#include "nvim/event/wstream.h"
#include "nvim/globals.h"
@@ -524,6 +525,32 @@ void nvim_ui_pum_set_bounds(uint64_t channel_id, Float width, Float height, Floa
ui->pum_pos = true;
}
+/// Tells Nvim when a terminal event has occurred.
+///
+/// The following terminal events are supported:
+///
+/// - "osc_response": The terminal sent a OSC response sequence to Nvim. The
+/// payload is the received OSC sequence.
+///
+/// @param channel_id
+/// @param event Event name
+/// @param payload Event payload
+/// @param[out] err Error details, if any.
+void nvim_ui_term_event(uint64_t channel_id, String event, Object value, Error *err)
+ FUNC_API_SINCE(12) FUNC_API_REMOTE_ONLY
+{
+ if (strequal("osc_response", event.data)) {
+ if (value.type != kObjectTypeString) {
+ api_set_error(err, kErrorTypeValidation, "osc_response must be a string");
+ return;
+ }
+
+ const String osc_response = value.data.string;
+ set_vim_var_string(VV_TERMRESPONSE, osc_response.data, (ptrdiff_t)osc_response.size);
+ apply_autocmds_group(EVENT_TERMRESPONSE, NULL, NULL, false, AUGROUP_ALL, NULL, NULL, &value);
+ }
+}
+
static void flush_event(UIData *data)
{
if (data->cur_event) {
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index eb858b8d5e..95229c5ffb 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -650,9 +650,9 @@ size_t transchar_hex(char *const buf, const int c)
/// Mirror text "str" for right-left displaying.
/// Only works for single-byte characters (e.g., numbers).
-void rl_mirror_ascii(char *str)
+void rl_mirror_ascii(char *str, char *end)
{
- for (char *p1 = str, *p2 = str + strlen(str) - 1; p1 < p2; p1++, p2--) {
+ for (char *p1 = str, *p2 = (end ? end : str + strlen(str)) - 1; p1 < p2; p1++, p2--) {
char t = *p1;
*p1 = *p2;
*p2 = t;
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c
index a28b6a8aa1..c353583dfa 100644
--- a/src/nvim/drawline.c
+++ b/src/nvim/drawline.c
@@ -201,20 +201,13 @@ static void margin_columns_win(win_T *wp, int *left_col, int *right_col)
prev_col_off = cur_col_off;
}
-/// If one half of a double-width char will be overwritten,
-/// change the other half to a space so that grid redraws properly.
-static void line_check_overwrite(schar_T *dest, int cells, int maxcells, bool rl)
-{
- assert(cells > 0);
- if (cells < maxcells && dest[rl ? -cells + 1 : cells] == 0) {
- dest[rl ? -cells : cells] = schar_from_ascii(' ');
- }
-}
-
/// Put a single char from an UTF-8 buffer into a line buffer.
///
+/// If `*pp` is a double-width char and only one cell is left, emit a space,
+/// and don't advance *pp
+///
/// Handles composing chars
-static int line_putchar(buf_T *buf, const char **pp, schar_T *dest, int maxcells, bool rl, int vcol)
+static int line_putchar(buf_T *buf, const char **pp, schar_T *dest, int maxcells, int vcol)
{
const char *p = *pp;
int cells = utf_ptr2cells(p);
@@ -222,17 +215,21 @@ static int line_putchar(buf_T *buf, const char **pp, schar_T *dest, int maxcells
int u8c, u8cc[MAX_MCO];
assert(maxcells > 0);
if (cells > maxcells) {
- return -1;
+ dest[0] = schar_from_ascii(' ');
+ return 1;
}
+
u8c = utfc_ptr2char(p, u8cc);
if (*p == TAB) {
cells = MIN(tabstop_padding(vcol, buf->b_p_ts, buf->b_p_vts_array), maxcells);
}
- line_check_overwrite(dest, cells, maxcells, rl);
+ if (cells < maxcells && dest[cells] == 0) {
+ dest[cells] = schar_from_ascii(' ');
+ }
if (*p == TAB) {
for (int c = 0; c < cells; c++) {
- dest[rl ? -c : c] = schar_from_ascii(' ');
+ dest[c] = schar_from_ascii(' ');
}
goto done;
} else if ((uint8_t)(*p) < 0x80 && u8cc[0] == 0) {
@@ -241,7 +238,7 @@ static int line_putchar(buf_T *buf, const char **pp, schar_T *dest, int maxcells
dest[0] = schar_from_cc(u8c, u8cc);
}
if (cells > 1) {
- dest[rl ? -1 : 1] = 0;
+ dest[1] = 0;
}
done:
*pp += c_len;
@@ -251,7 +248,7 @@ done:
static void draw_virt_text(win_T *wp, buf_T *buf, int col_off, int *end_col, int win_row)
{
DecorState *state = &decor_state;
- const int max_col = wp->w_p_rl ? -1 : wp->w_grid.cols;
+ const int max_col = wp->w_grid.cols;
int right_pos = max_col;
bool do_eol = state->eol_col > -1;
for (size_t i = 0; i < kv_size(state->active); i++) {
@@ -262,20 +259,12 @@ static void draw_virt_text(win_T *wp, buf_T *buf, int col_off, int *end_col, int
if (item->draw_col == -1) {
bool updated = true;
if (item->decor.virt_text_pos == kVTRightAlign) {
- if (wp->w_p_rl) {
- right_pos += item->decor.virt_text_width;
- } else {
- right_pos -= item->decor.virt_text_width;
- }
+ right_pos -= item->decor.virt_text_width;
item->draw_col = right_pos;
} else if (item->decor.virt_text_pos == kVTEndOfLine && do_eol) {
item->draw_col = state->eol_col;
} else if (item->decor.virt_text_pos == kVTWinCol) {
- if (wp->w_p_rl) {
- item->draw_col = MIN(col_off - item->decor.col, wp->w_grid.cols - 1);
- } else {
- item->draw_col = MAX(col_off + item->decor.col, 0);
- }
+ item->draw_col = MAX(col_off + item->decor.col, 0);
} else {
updated = false;
}
@@ -295,35 +284,27 @@ static void draw_virt_text(win_T *wp, buf_T *buf, int col_off, int *end_col, int
kv_push(win_extmark_arr, m);
}
if (kv_size(item->decor.virt_text)) {
- int vcol = wp->w_p_rl ? col_off - item->draw_col : item->draw_col - col_off;
+ int vcol = item->draw_col - col_off;
col = draw_virt_text_item(buf, item->draw_col, item->decor.virt_text,
- item->decor.hl_mode, max_col, vcol, wp->w_p_rl);
+ item->decor.hl_mode, max_col, vcol);
}
item->draw_col = INT_MIN; // deactivate
if (item->decor.virt_text_pos == kVTEndOfLine && do_eol) {
- if (wp->w_p_rl) {
- state->eol_col = col - 1;
- } else {
- state->eol_col = col + 1;
- }
+ state->eol_col = col + 1;
}
- if (wp->w_p_rl) {
- *end_col = MIN(*end_col, col);
- } else {
- *end_col = MAX(*end_col, col);
- }
+ *end_col = MAX(*end_col, col);
}
}
static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode, int max_col,
- int vcol, bool rl)
+ int vcol)
{
const char *p = "";
int virt_attr = 0;
size_t virt_pos = 0;
- while (rl ? col > max_col : col < max_col) {
+ while (col < max_col) {
if (!*p) {
if (virt_pos >= kv_size(vt)) {
break;
@@ -348,23 +329,12 @@ static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode,
attr = virt_attr;
}
schar_T dummy[2];
- int maxcells = rl ? col - max_col : max_col - col;
+ int maxcells = max_col - col;
int cells = line_putchar(buf, &p, through ? dummy : &linebuf_char[col],
- maxcells, rl, vcol);
- // If we failed to emit a char, we still need to put a space and advance.
- if (cells < 1) {
- assert(!through);
- cells = 1;
- line_check_overwrite(&linebuf_char[col], cells, maxcells, rl);
- linebuf_char[col] = schar_from_ascii(' ');
- }
+ maxcells, vcol);
for (int c = 0; c < cells; c++) {
linebuf_attr[col] = attr;
- if (rl) {
- col--;
- } else {
- col++;
- }
+ col++;
}
vcol += cells;
}
@@ -642,15 +612,9 @@ static void handle_lnum_col(win_T *wp, winlinevars_T *wlv, int num_signs, int si
*wlv->p_extra = '-';
}
}
- if (wp->w_p_rl) { // reverse line numbers
- // like rl_mirror_ascii(), 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;
- }
+ if (wp->w_p_rl) { // reverse line numbers
+ char *num = skipwhite(wlv->extra);
+ rl_mirror_ascii(num, skiptowhite(num));
}
wlv->p_extra = wlv->extra;
wlv->c_extra = NUL;
@@ -808,11 +772,7 @@ static void handle_showbreak_and_filler(win_T *wp, winlinevars_T *wlv)
// 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->n_extra = wp->w_grid.cols - wlv->col;
wlv->char_attr = 0;
} else if (wlv->filler_todo > 0) {
// Draw "deleted" diff line(s)
@@ -823,11 +783,7 @@ static void handle_showbreak_and_filler(win_T *wp, winlinevars_T *wlv)
wlv->c_extra = wp->w_p_fcs_chars.diff;
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->n_extra = wp->w_grid.cols - wlv->col;
wlv->char_attr = win_hl_attr(wp, HLF_DED);
}
@@ -1030,14 +986,6 @@ static void win_line_start(win_T *wp, winlinevars_T *wlv, bool save_extra)
wlv->off = 0;
wlv->need_lbr = false;
- 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;
@@ -1707,9 +1655,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// Skip fold, sign and number states if 'statuscolumn' is set.
wlv.draw_state = WL_STC - 1;
}
- if (virt_line_offset >= 0 && wp->w_p_rl) {
- virt_line_offset = wp->w_grid.cols - 1 - virt_line_offset;
- }
}
if (wlv.draw_state == WL_FOLD - 1 && wlv.n_extra == 0) {
@@ -1801,7 +1746,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
|| (number_only && wlv.draw_state > WL_STC))
&& wlv.filler_todo <= 0) {
draw_virt_text(wp, buf, win_col_offset, &wlv.col, wlv.row);
- win_put_linebuf(wp, wlv.row, 0, wlv.col, -grid->cols, bg_attr, false);
+ // don't clear anything after wlv.col
+ win_put_linebuf(wp, wlv.row, 0, wlv.col, wlv.col, bg_attr, false);
// Pretend we have finished updating the window. Except when
// 'cursorcolumn' is set.
if (wp->w_p_cuc) {
@@ -1978,7 +1924,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// Fill rest of line with 'fold'.
wlv.c_extra = wp->w_p_fcs_chars.fold;
wlv.c_final = NUL;
- wlv.n_extra = wp->w_p_rl ? (wlv.col + 1) : (grid->cols - wlv.col);
+ wlv.n_extra = grid->cols - wlv.col;
}
if (draw_folded && wlv.n_extra != 0 && wlv.col >= grid->cols) {
@@ -2020,8 +1966,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
}
// If a double-width char doesn't fit display a '>' in the last column.
- if ((wp->w_p_rl ? (wlv.col <= 0) : (wlv.col >= grid->cols - 1))
- && utf_char2cells(mb_c) == 2) {
+ if (wlv.col >= grid->cols - 1 && utf_char2cells(mb_c) == 2) {
c = '>';
mb_c = c;
mb_l = 1;
@@ -2118,7 +2063,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// Non-BMP character : display as ? or fullwidth ?.
transchar_hex(wlv.extra, mb_c);
if (wp->w_p_rl) { // reverse
- rl_mirror_ascii(wlv.extra);
+ rl_mirror_ascii(wlv.extra, NULL);
}
wlv.p_extra = wlv.extra;
@@ -2139,8 +2084,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// 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 ? (wlv.col <= 0) : (wlv.col >= grid->cols - 1))
- && utf_char2cells(mb_c) == 2) {
+ if (wlv.col >= grid->cols - 1 && utf_char2cells(mb_c) == 2) {
c = '>';
mb_c = c;
mb_utf8 = false;
@@ -2546,7 +2490,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
|| ((wlv.fromcol >= 0 || fromcol_prev >= 0)
&& wlv.tocol > wlv.vcol
&& VIsual_mode != Ctrl_V
- && (wp->w_p_rl ? (wlv.col >= 0) : (wlv.col < grid->cols))
+ && wlv.col < grid->cols
&& !(noinvcur
&& lnum == wp->w_cursor.lnum
&& wlv.vcol == wp->w_virtcol)))
@@ -2581,7 +2525,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
wlv.n_extra = byte2cells(c) - 1;
}
if ((dy_flags & DY_UHEX) && wp->w_p_rl) {
- rl_mirror_ascii(wlv.p_extra); // reverse "<12>"
+ rl_mirror_ascii(wlv.p_extra, NULL); // reverse "<12>"
}
wlv.c_extra = NUL;
wlv.c_final = NUL;
@@ -2610,7 +2554,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
&& virtual_active()
&& wlv.tocol != MAXCOL
&& wlv.vcol < wlv.tocol
- && (wp->w_p_rl ? (wlv.col >= 0) : (wlv.col < grid->cols))) {
+ && wlv.col < grid->cols) {
c = ' ';
ptr--; // put it back at the NUL
}
@@ -2652,13 +2596,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
}
wlv.vcol += wlv.n_extra;
if (wp->w_p_wrap && wlv.n_extra > 0) {
- if (wp->w_p_rl) {
- wlv.col -= wlv.n_extra;
- wlv.boguscols -= wlv.n_extra;
- } else {
- wlv.boguscols += wlv.n_extra;
- wlv.col += wlv.n_extra;
- }
+ wlv.boguscols += wlv.n_extra;
+ wlv.col += wlv.n_extra;
}
wlv.n_extra = 0;
wlv.n_attr = 0;
@@ -2685,11 +2624,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
&& wp == curwin && lnum == wp->w_cursor.lnum
&& conceal_cursor_line(wp)
&& (int)wp->w_virtcol <= wlv.vcol + wlv.skip_cells) {
- if (wp->w_p_rl) {
- wp->w_wcol = grid->cols - wlv.col + wlv.boguscols - 1;
- } else {
- wp->w_wcol = wlv.col - wlv.boguscols;
- }
+ wp->w_wcol = wlv.col - wlv.boguscols;
wp->w_wrow = wlv.row;
did_wcol = true;
wp->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL;
@@ -2753,14 +2688,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
|| prevcol_hl_flag)) {
int n = 0;
- if (wp->w_p_rl) {
- if (wlv.col < 0) {
- n = 1;
- }
- } else {
- if (wlv.col >= grid->cols) {
- n = -1;
- }
+ if (wlv.col >= grid->cols) {
+ n = -1;
}
if (n != 0) {
// At the window boundary, highlight the last character
@@ -2786,13 +2715,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
}
linebuf_attr[wlv.off] = eol_attr;
linebuf_vcol[wlv.off] = MAXCOL;
- if (wp->w_p_rl) {
- wlv.col--;
- wlv.off--;
- } else {
- wlv.col++;
- wlv.off++;
- }
+ wlv.col++;
+ wlv.off++;
wlv.vcol++;
eol_hl_off = 1;
}
@@ -2827,8 +2751,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
? 1 : 0);
if (has_decor) {
- has_virttext = decor_redraw_eol(wp, &decor_state, &wlv.line_attr,
- wlv.col + (wp->w_p_rl ? -eol_skip : eol_skip));
+ has_virttext = decor_redraw_eol(wp, &decor_state, &wlv.line_attr, wlv.col + eol_skip);
}
if (((wp->w_p_cuc
@@ -2868,12 +2791,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
rightmost_vcol = INT_MAX;
}
- int col_stride = wp->w_p_rl ? -1 : 1;
-
- while (wp->w_p_rl ? wlv.col >= 0 : wlv.col < grid->cols) {
+ while (wlv.col < grid->cols) {
linebuf_char[wlv.off] = schar_from_ascii(' ');
linebuf_vcol[wlv.off] = MAXCOL;
- wlv.col += col_stride;
+ wlv.col++;
if (draw_color_col) {
draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
}
@@ -2889,7 +2810,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
col_attr = hl_combine_attr(col_attr, wlv.line_attr);
linebuf_attr[wlv.off] = col_attr;
- wlv.off += col_stride;
+ wlv.off++;
if (VCOL_HLC >= rightmost_vcol) {
break;
@@ -2901,22 +2822,19 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// TODO(bfredl): integrate with the common beyond-the-end-loop
if (wp->w_buffer->terminal) {
- // terminal buffers may need to highlight beyond the end of the
- // logical line
- int n = wp->w_p_rl ? -1 : 1;
+ // terminal buffers may need to highlight beyond the end of the logical line
while (wlv.col >= 0 && wlv.col < grid->cols) {
linebuf_char[wlv.off] = schar_from_ascii(' ');
linebuf_attr[wlv.off] = wlv.vcol >= TERM_ATTRS_MAX ? 0 : term_attrs[wlv.vcol];
linebuf_vcol[wlv.off] = wlv.vcol;
- wlv.off += n;
- wlv.vcol += n;
- wlv.col += n;
+ wlv.off++;
+ wlv.vcol++;
+ wlv.col++;
}
}
if (kv_size(fold_vt) > 0) {
- draw_virt_text_item(buf, win_col_offset, fold_vt, kHlModeCombine,
- wp->w_p_rl ? -1 : grid->cols, 0, wp->w_p_rl);
+ draw_virt_text_item(buf, win_col_offset, fold_vt, kHlModeCombine, grid->cols, 0);
}
draw_virt_text(wp, buf, win_col_offset, &wlv.col, wlv.row);
win_put_linebuf(wp, wlv.row, 0, wlv.col, grid->cols, bg_attr, false);
@@ -2941,7 +2859,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
&& wp->w_p_list
&& !wp->w_p_wrap
&& wlv.filler_todo <= 0
- && (wp->w_p_rl ? wlv.col == 0 : wlv.col == grid->cols - 1)
+ && wlv.col == grid->cols - 1
&& !has_fold) {
if (has_decor && *ptr == NUL && lcs_eol_one == 0) {
// Tricky: there might be a virtual text just _after_ the last char
@@ -3000,11 +2918,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// Skip characters that are left of the screen for 'nowrap'.
if (wlv.draw_state < WL_LINE || wlv.skip_cells <= 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.
- wlv.off--;
- wlv.col--;
- }
if (mb_utf8) {
linebuf_char[wlv.off] = schar_from_cc(mb_c, u8cc);
} else {
@@ -3049,20 +2962,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
if (wlv.tocol == wlv.vcol) {
wlv.tocol++;
}
-
- if (wp->w_p_rl) {
- // now it's time to backup one cell
- wlv.off--;
- wlv.col--;
- }
- }
- if (wp->w_p_rl) {
- wlv.off--;
- wlv.col--;
- } else {
- wlv.off++;
- wlv.col++;
}
+ wlv.off++;
+ wlv.col++;
} else if (wp->w_p_cole > 0 && is_concealing) {
wlv.skip_cells--;
wlv.vcol_off++;
@@ -3083,35 +2985,20 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// of bad columns we have advanced.
if (wlv.n_extra > 0) {
wlv.vcol += wlv.n_extra;
- if (wp->w_p_rl) {
- wlv.col -= wlv.n_extra;
- wlv.boguscols -= wlv.n_extra;
- } else {
- wlv.col += wlv.n_extra;
- wlv.boguscols += wlv.n_extra;
- }
+ wlv.col += wlv.n_extra;
+ wlv.boguscols += wlv.n_extra;
wlv.n_extra = 0;
wlv.n_attr = 0;
}
if (utf_char2cells(mb_c) > 1) {
// Need to fill two screen columns.
- if (wp->w_p_rl) {
- wlv.boguscols--;
- wlv.col--;
- } else {
- wlv.boguscols++;
- wlv.col++;
- }
- }
-
- if (wp->w_p_rl) {
- wlv.boguscols--;
- wlv.col--;
- } else {
wlv.boguscols++;
wlv.col++;
}
+
+ wlv.boguscols++;
+ wlv.col++;
} else {
if (wlv.n_extra > 0) {
wlv.vcol += wlv.n_extra;
@@ -3150,8 +3037,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
wlv.char_attr = saved_attr2;
}
- if (has_decor && wlv.filler_todo <= 0
- && (wp->w_p_rl ? (wlv.col < 0) : (wlv.col >= grid->cols))) {
+ if (has_decor && wlv.filler_todo <= 0 && wlv.col >= grid->cols) {
// At the end of screen line: might need to peek for decorations just after
// this position.
if (!has_fold && wp->w_p_wrap && wlv.n_extra == 0) {
@@ -3167,8 +3053,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
// 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 ? (wlv.col < 0) : (wlv.col >= grid->cols))
- && (!has_fold || virt_line_offset >= 0)
+ if (wlv.col >= grid->cols && (!has_fold || virt_line_offset >= 0)
&& (wlv.draw_state != WL_LINE
|| *ptr != NUL
|| wlv.filler_todo > 0
@@ -3187,7 +3072,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl
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, wp->w_p_rl ? -1 : grid->cols, 0, wp->w_p_rl);
+ kHlModeReplace, grid->cols, 0);
} else if (wlv.filler_todo <= 0) {
draw_virt_text(wp, buf, win_col_offset, &draw_col, wlv.row);
}
@@ -3266,6 +3151,13 @@ static void win_put_linebuf(win_T *wp, int row, int coloff, int endcol, int clea
{
ScreenGrid *grid = &wp->w_grid;
+ int start_col = 0;
+
+ if (wp->w_p_rl) {
+ linebuf_mirror(&start_col, &clear_width, grid->cols);
+ endcol = grid->cols - 1 - endcol;
+ }
+
// Take care of putting "<<<" on the first line for 'smoothscroll'.
if (row == 0 && wp->w_skipcol > 0
// do not overwrite the 'showbreak' text with "<<<"
@@ -3293,5 +3185,5 @@ static void win_put_linebuf(win_T *wp, int row, int coloff, int endcol, int clea
}
grid_adjust(&grid, &row, &coloff);
- grid_put_linebuf(grid, row, coloff, 0, endcol, clear_width, wp->w_p_rl, bg_attr, wrap);
+ grid_put_linebuf(grid, row, coloff, start_col, endcol, clear_width, wp->w_p_rl, bg_attr, wrap);
}
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 505a91813a..550d296093 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -4187,6 +4187,7 @@ static void f_jobwait(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
ui_busy_start();
+ ui_flush();
list_T *args = argvars[0].vval.v_list;
Channel **jobs = xcalloc((size_t)tv_list_len(args), sizeof(*jobs));
MultiQueue *waiting_jobs = multiqueue_new_parent(loop_on_put, &main_loop);
diff --git a/src/nvim/grid.c b/src/nvim/grid.c
index d59c3b4803..45bffdcab5 100644
--- a/src/nvim/grid.c
+++ b/src/nvim/grid.c
@@ -477,14 +477,21 @@ void grid_line_mirror(void)
if (grid_line_first >= grid_line_last) {
return;
}
+ linebuf_mirror(&grid_line_first, &grid_line_last, grid_line_maxcol);
+}
+
+void linebuf_mirror(int *firstp, int *lastp, int maxcol)
+{
+ int first = *firstp;
+ int last = *lastp;
- size_t n = (size_t)(grid_line_last - grid_line_first);
- int mirror = grid_line_maxcol - 1; // Mirrors are more fun than television.
+ size_t n = (size_t)(last - first);
+ int mirror = maxcol - 1; // Mirrors are more fun than television.
schar_T *scratch_char = (schar_T *)linebuf_scratch;
- memcpy(scratch_char + grid_line_first, linebuf_char + grid_line_first, n * sizeof(schar_T));
- for (int col = grid_line_first; col < grid_line_last; col++) {
+ memcpy(scratch_char + first, linebuf_char + first, n * sizeof(schar_T));
+ for (int col = first; col < last; col++) {
int rev = mirror - col;
- if (col + 1 < grid_line_last && scratch_char[col + 1] == 0) {
+ if (col + 1 < last && scratch_char[col + 1] == 0) {
linebuf_char[rev - 1] = scratch_char[col];
linebuf_char[rev] = 0;
col++;
@@ -495,20 +502,19 @@ void grid_line_mirror(void)
// for attr and vcol: assumes doublewidth chars are self-consistent
sattr_T *scratch_attr = (sattr_T *)linebuf_scratch;
- memcpy(scratch_attr + grid_line_first, linebuf_attr + grid_line_first, n * sizeof(sattr_T));
- for (int col = grid_line_first; col < grid_line_last; col++) {
+ memcpy(scratch_attr + first, linebuf_attr + first, n * sizeof(sattr_T));
+ for (int col = first; col < last; col++) {
linebuf_attr[mirror - col] = scratch_attr[col];
}
colnr_T *scratch_vcol = (colnr_T *)linebuf_scratch;
- memcpy(scratch_vcol + grid_line_first, linebuf_vcol + grid_line_first, n * sizeof(colnr_T));
- for (int col = grid_line_first; col < grid_line_last; col++) {
+ memcpy(scratch_vcol + first, linebuf_vcol + first, n * sizeof(colnr_T));
+ for (int col = first; col < last; col++) {
linebuf_vcol[mirror - col] = scratch_vcol[col];
}
- int grid_line_last_copy = grid_line_last;
- grid_line_last = grid_line_maxcol - grid_line_first;
- grid_line_first = grid_line_maxcol - grid_line_last_copy;
+ *lastp = maxcol - first;
+ *firstp = maxcol - last;
}
/// End a group of grid_line_puts calls and send the screen buffer to the UI layer.
@@ -698,10 +704,10 @@ void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int col, int endcol
}
}
col = endcol + 1;
- endcol = (clear_width > 0 ? clear_width : -clear_width);
+ endcol = clear_width;
}
- if (p_arshape && !p_tbidi) {
+ if (p_arshape && !p_tbidi && endcol > col) {
line_do_arabic_shape(linebuf_char + col, endcol - col);
}
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 2e3cc4f170..61157301b6 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -4135,7 +4135,12 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int q
// delete all existing lines
while ((curbuf->b_ml.ml_flags & ML_EMPTY) == 0) {
- (void)ml_delete((linenr_T)1, false);
+ // If deletion fails, this loop may run forever, so
+ // signal error and return.
+ if (ml_delete((linenr_T)1, false) == FAIL) {
+ internal_error("qf_fill_buffer()");
+ return;
+ }
}
}
diff --git a/src/nvim/spellsuggest.c b/src/nvim/spellsuggest.c
index d1f63e537b..938e8cec8f 100644
--- a/src/nvim/spellsuggest.c
+++ b/src/nvim/spellsuggest.c
@@ -566,7 +566,7 @@ void spell_suggest(int count)
}
vim_snprintf(IObuff, IOSIZE, "%2d", i + 1);
if (cmdmsg_rl) {
- rl_mirror_ascii(IObuff);
+ rl_mirror_ascii(IObuff, NULL);
}
msg_puts(IObuff);
@@ -592,7 +592,7 @@ void spell_suggest(int count)
}
if (cmdmsg_rl) {
// Mirror the numbers, but keep the leading space.
- rl_mirror_ascii(IObuff + 1);
+ rl_mirror_ascii(IObuff + 1, NULL);
}
msg_advance(30);
msg_puts(IObuff);
diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c
index 487f8b010e..4ebf9177de 100644
--- a/src/nvim/tui/input.c
+++ b/src/nvim/tui/input.c
@@ -30,6 +30,7 @@
#include "nvim/event/rstream.h"
#include "nvim/msgpack_rpc/channel.h"
+#define READ_STREAM_SIZE 0xfff
#define KEY_BUFFER_SIZE 0xfff
static const struct kitty_key_map_entry {
@@ -152,7 +153,9 @@ void tinput_init(TermInput *input, Loop *loop)
termkey_set_canonflags(input->tk, curflags | TERMKEY_CANON_DELBS);
// setup input handle
- rstream_init_fd(loop, &input->read_stream, input->in_fd, 0xfff);
+ rstream_init_fd(loop, &input->read_stream, input->in_fd, READ_STREAM_SIZE);
+ termkey_set_buffer_size(input->tk, rbuffer_capacity(input->read_stream.buffer));
+
// initialize a timer handle for handling ESC with libtermkey
time_watcher_init(loop, &input->timer_handle, input);
}
@@ -479,6 +482,8 @@ static void tk_getkeys(TermInput *input, bool force)
}
}
}
+ } else if (key.type == TERMKEY_TYPE_OSC) {
+ handle_osc_event(input, &key);
}
}
@@ -684,6 +689,29 @@ HandleState handle_background_color(TermInput *input)
return kComplete;
}
+static void handle_osc_event(TermInput *input, const TermKeyKey *key)
+{
+ assert(input);
+
+ const char *str = NULL;
+ if (termkey_interpret_string(input->tk, key, &str) == TERMKEY_RES_KEY) {
+ assert(str != NULL);
+
+ // Send an event to nvim core. This will update the v:termresponse variable and fire the
+ // TermResponse event
+ MAXSIZE_TEMP_ARRAY(args, 2);
+ ADD_C(args, STATIC_CSTR_AS_OBJ("osc_response"));
+
+ // libtermkey strips the OSC bytes from the response. We add it back in so that downstream
+ // consumers of v:termresponse can differentiate between OSC and CSI events.
+ StringBuilder response = KV_INITIAL_VALUE;
+ kv_printf(response, "\x1b]%s", str);
+ ADD_C(args, STRING_OBJ(cbuf_as_string(response.items, response.size)));
+ rpc_send_event(ui_client_channel_id, "nvim_ui_term_event", args);
+ kv_destroy(response);
+ }
+}
+
static void handle_raw_buffer(TermInput *input, bool force)
{
HandleState is_paste = kNotApplicable;
@@ -732,9 +760,9 @@ static void handle_raw_buffer(TermInput *input, bool force)
RBUFFER_UNTIL_EMPTY(input->read_stream.buffer, ptr, len) {
size_t consumed = termkey_push_bytes(input->tk, ptr, MIN(count, len));
// termkey_push_bytes can return (size_t)-1, so it is possible that
- // `consumed > input->read_stream.buffer->size`, but since tk_getkeys is
+ // `consumed > rbuffer_size(input->read_stream.buffer)`, but since tk_getkeys is
// called soon, it shouldn't happen.
- assert(consumed <= input->read_stream.buffer->size);
+ assert(consumed <= rbuffer_size(input->read_stream.buffer));
rbuffer_consumed(input->read_stream.buffer, consumed);
// Process the keys now: there is no guarantee `count` will
// fit into libtermkey's input buffer.
diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua
index 613dff577a..befbd4bc3b 100644
--- a/test/functional/core/job_spec.lua
+++ b/test/functional/core/job_spec.lua
@@ -700,7 +700,7 @@ describe('jobs', function()
os.remove('Xtest_jobstart_env')
end)
- describe('jobwait', function()
+ describe('jobwait()', function()
before_each(function()
if is_os('win') then
helpers.set_shell_powershell()
@@ -874,6 +874,27 @@ describe('jobs', function()
eq({'notification', 'wait', {{-1, -1}}}, next_msg())
end)
end)
+
+ it('hides cursor when waiting', function()
+ local screen = Screen.new(30, 3)
+ screen:set_default_attr_ids({
+ [0] = {foreground = Screen.colors.Blue1, bold = true};
+ })
+ screen:attach()
+ command([[let g:id = jobstart([v:progpath, '--clean', '--headless'])]])
+ feed_command('call jobwait([g:id], 300)')
+ screen:expect{grid=[[
+ |
+ {0:~ }|
+ :call jobwait([g:id], 300) |
+ ]], timeout=100}
+ funcs.jobstop(meths.get_var('id'))
+ screen:expect{grid=[[
+ ^ |
+ {0:~ }|
+ :call jobwait([g:id], 300) |
+ ]]}
+ end)
end)
pending('exit event follows stdout, stderr', function()
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index c69990d84b..1ebfa9dd1d 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -2438,6 +2438,12 @@ describe('lua stdlib', function()
end)
it('allows removing on_key listeners', function()
+ -- Create some unused namespaces
+ meths.create_namespace('unused1')
+ meths.create_namespace('unused2')
+ meths.create_namespace('unused3')
+ meths.create_namespace('unused4')
+
insert([[hello world]])
exec_lua [[
diff --git a/test/functional/ui/decorations_spec.lua b/test/functional/ui/decorations_spec.lua
index 68c3e73e61..9c16f76359 100644
--- a/test/functional/ui/decorations_spec.lua
+++ b/test/functional/ui/decorations_spec.lua
@@ -2024,26 +2024,26 @@ describe('extmark decorations', function()
it("highlights do reapply to restored text after delete", function()
with_undo_restore(true) -- also default behavior
- feed 'u'
+ command('silent undo')
screen:expect{grid=[[
^for _,{1:item in} ipairs(items) do |
local text, hl_id_cell, count = unpack(item) |
if hl_id_cell ~= nil then |
hl_id = hl_id_cell |
- 1 change; before #2 0 seconds ago |
+ |
]]}
end)
- it("highlights don't reapply to restored text after delete with no_undo_restore", function()
+ it("highlights don't reapply to restored text after delete with undo_restore=false", function()
with_undo_restore(false)
- feed 'u'
+ command('silent undo')
screen:expect{grid=[[
^for _,it{1:em in} ipairs(items) do |
local text, hl_id_cell, count = unpack(item) |
if hl_id_cell ~= nil then |
hl_id = hl_id_cell |
- 1 change; before #2 0 seconds ago |
+ |
]]}
eq({ { 1, 0, 8, { end_col = 13, end_right_gravity = false, end_row = 0,