aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaphael <glephunter@gmail.com>2023-12-14 16:08:00 +0800
committerGitHub <noreply@github.com>2023-12-14 16:08:00 +0800
commit619407eb548c7df56bc99b945338e9446f846fbb (patch)
tree7e3b4e11f467c32de90cdc1afa7de08cc725c4e7
parent36552adb39edff2d909743f16c1f061bc74b5c4e (diff)
downloadrneovim-619407eb548c7df56bc99b945338e9446f846fbb.tar.gz
rneovim-619407eb548c7df56bc99b945338e9446f846fbb.tar.bz2
rneovim-619407eb548c7df56bc99b945338e9446f846fbb.zip
feat(nvim_open_term): convert LF => CRLF (#26384)
Problem: Unlike termopen(), nvim_open_term() PTYs do not carriage-return the cursor on newline ("\n") input. nvim --clean :let chan_id = nvim_open_term(1, {}) :call chansend(chan_id, ["here", "are", "some", "lines"]) Actual behavior: here are some lines Expected behaviour: here are some lines Solution: Add `force_crlf` option, and enable it by default.
-rw-r--r--runtime/doc/api.txt2
-rw-r--r--runtime/doc/news.txt2
-rw-r--r--runtime/lua/vim/_meta/api.lua2
-rw-r--r--runtime/lua/vim/_meta/api_keysets.lua1
-rw-r--r--src/nvim/api/keysets_defs.h1
-rw-r--r--src/nvim/api/vim.c3
-rw-r--r--src/nvim/channel.c1
-rw-r--r--src/nvim/terminal.c18
-rw-r--r--src/nvim/terminal.h1
-rw-r--r--test/functional/terminal/channel_spec.lua51
-rw-r--r--test/functional/terminal/scrollback_spec.lua22
11 files changed, 91 insertions, 13 deletions
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index 4aba1f8141..48bbdc33df 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -1231,6 +1231,8 @@ nvim_open_term({buffer}, {*opts}) *nvim_open_term()*
is sent as a "\r", not as a "\n". |textlock| applies. It
is possible to call |nvim_chan_send()| directly in the
callback however. ["input", term, bufnr, data]
+ • force_crlf: (boolean, default true) Convert "\n" to
+ "\r\n".
Return: ~
Channel id, or 0 on error
diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt
index 04f143f0c3..9bfc577e87 100644
--- a/runtime/doc/news.txt
+++ b/runtime/doc/news.txt
@@ -344,6 +344,8 @@ The following changes to existing APIs or features add new behavior.
• Diagnostic sign text is no longer configured with |sign_define()|.
Use |vim.diagnostic.config()| instead.
+• Added "force_crlf" option field in |nvim_open_term()|.
+
==============================================================================
REMOVED FEATURES *news-removed*
diff --git a/runtime/lua/vim/_meta/api.lua b/runtime/lua/vim/_meta/api.lua
index 4ad0a2e791..231e1c3404 100644
--- a/runtime/lua/vim/_meta/api.lua
+++ b/runtime/lua/vim/_meta/api.lua
@@ -1446,6 +1446,8 @@ function vim.api.nvim_notify(msg, log_level, opts) end
--- is sent as a "\r", not as a "\n". `textlock` applies. It
--- is possible to call `nvim_chan_send()` directly in the
--- callback however. ["input", term, bufnr, data]
+--- • force_crlf: (boolean, default true) Convert "\n" to
+--- "\r\n".
--- @return integer
function vim.api.nvim_open_term(buffer, opts) end
diff --git a/runtime/lua/vim/_meta/api_keysets.lua b/runtime/lua/vim/_meta/api_keysets.lua
index 6a3e574455..f64cdb8afd 100644
--- a/runtime/lua/vim/_meta/api_keysets.lua
+++ b/runtime/lua/vim/_meta/api_keysets.lua
@@ -217,6 +217,7 @@ error('Cannot require a meta file')
--- @class vim.api.keyset.open_term
--- @field on_input? function
+--- @field force_crlf? boolean
--- @class vim.api.keyset.option
--- @field scope? string
diff --git a/src/nvim/api/keysets_defs.h b/src/nvim/api/keysets_defs.h
index d1cbe43de0..c0daa0ca74 100644
--- a/src/nvim/api/keysets_defs.h
+++ b/src/nvim/api/keysets_defs.h
@@ -344,4 +344,5 @@ typedef struct {
typedef struct {
OptionalKeys is_set__open_term_;
LuaRef on_input;
+ Boolean force_crlf;
} Dict(open_term);
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index a52d7493e3..2f3d527b9e 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -985,6 +985,7 @@ fail:
/// as a "\r", not as a "\n". |textlock| applies. It is possible
/// to call |nvim_chan_send()| directly in the callback however.
/// ["input", term, bufnr, data]
+/// - force_crlf: (boolean, default true) Convert "\n" to "\r\n".
/// @param[out] err Error details, if any
/// @return Channel id, or 0 on error
Integer nvim_open_term(Buffer buffer, Dict(open_term) *opts, Error *err)
@@ -1002,7 +1003,6 @@ Integer nvim_open_term(Buffer buffer, Dict(open_term) *opts, Error *err)
}
LuaRef cb = LUA_NOREF;
-
if (HAS_KEY(opts, open_term, on_input)) {
cb = opts->on_input;
opts->on_input = LUA_NOREF;
@@ -1020,6 +1020,7 @@ Integer nvim_open_term(Buffer buffer, Dict(open_term) *opts, Error *err)
.write_cb = term_write,
.resize_cb = term_resize,
.close_cb = term_close,
+ .force_crlf = GET_BOOL_OR_TRUE(opts, open_term, force_crlf),
};
channel_incref(chan);
terminal_open(&chan->term, buf, topts);
diff --git a/src/nvim/channel.c b/src/nvim/channel.c
index ca8cbed8f9..fb4711f7d9 100644
--- a/src/nvim/channel.c
+++ b/src/nvim/channel.c
@@ -801,6 +801,7 @@ void channel_terminal_open(buf_T *buf, Channel *chan)
.write_cb = term_write,
.resize_cb = term_resize,
.close_cb = term_close,
+ .force_crlf = false,
};
buf->b_p_channel = (OptInt)chan->id; // 'channel' option
channel_incref(chan);
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index af9693c4b0..3b70ee922a 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -43,6 +43,7 @@
#include <vterm.h>
#include <vterm_keycodes.h>
+#include "klib/kvec.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
#include "nvim/ascii_defs.h"
@@ -80,6 +81,7 @@
#include "nvim/optionstr.h"
#include "nvim/pos_defs.h"
#include "nvim/state.h"
+#include "nvim/strings.h"
#include "nvim/terminal.h"
#include "nvim/types_defs.h"
#include "nvim/ui.h"
@@ -786,7 +788,21 @@ void terminal_receive(Terminal *term, const char *data, size_t len)
return;
}
- vterm_input_write(term->vt, data, len);
+ if (term->opts.force_crlf) {
+ StringBuilder crlf_data = KV_INITIAL_VALUE;
+
+ for (size_t i = 0; i < len; i++) {
+ if (data[i] == '\n' && (i == 0 || (i > 0 && data[i - 1] != '\r'))) {
+ kv_push(crlf_data, '\r');
+ }
+ kv_push(crlf_data, data[i]);
+ }
+
+ vterm_input_write(term->vt, crlf_data.items, kv_size(crlf_data));
+ kv_destroy(crlf_data);
+ } else {
+ vterm_input_write(term->vt, data, len);
+ }
vterm_screen_flush_damage(term->vts);
}
diff --git a/src/nvim/terminal.h b/src/nvim/terminal.h
index db62bd2a5b..ffa97f17b2 100644
--- a/src/nvim/terminal.h
+++ b/src/nvim/terminal.h
@@ -16,6 +16,7 @@ typedef struct {
terminal_write_cb write_cb;
terminal_resize_cb resize_cb;
terminal_close_cb close_cb;
+ bool force_crlf;
} TerminalOptions;
#ifdef INCLUDE_GENERATED_DECLARATIONS
diff --git a/test/functional/terminal/channel_spec.lua b/test/functional/terminal/channel_spec.lua
index 6fb1a21561..b9abcd61c8 100644
--- a/test/functional/terminal/channel_spec.lua
+++ b/test/functional/terminal/channel_spec.lua
@@ -192,4 +192,55 @@ describe('no crash when TermOpen autocommand', function()
]]}
assert_alive()
end)
+
+ it('nvim_open_term({force_crlf=true}) converts newlines', function()
+ local buf = meths.create_buf(false, true)
+ local win = meths.get_current_win()
+ local term = meths.open_term(buf, {force_crlf = true})
+ screen:try_resize(8, 10)
+ meths.win_set_buf(win, buf)
+ meths.chan_send(term, 'here\nthere\nfoo\r\nbar\n\ntest')
+ screen:expect{grid=[[
+ ^here |
+ there |
+ foo |
+ bar |
+ |
+ test |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]]}
+ meths.chan_send(term, '\nfirst')
+ screen:expect{grid=[[
+ ^here |
+ there |
+ foo |
+ bar |
+ |
+ test |
+ first |
+ {0:~ }|
+ {0:~ }|
+ |
+ ]]}
+ meths.buf_delete(buf, {force = true})
+ buf = meths.create_buf(false, true)
+ term = meths.open_term(buf, {force_crlf = false})
+ meths.win_set_buf(win, buf)
+ meths.chan_send(term, 'here\nthere')
+ screen:expect{grid=[[
+ ^here |
+ there |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ ]]}
+ end)
end)
diff --git a/test/functional/terminal/scrollback_spec.lua b/test/functional/terminal/scrollback_spec.lua
index d2c636b03f..00104734ef 100644
--- a/test/functional/terminal/scrollback_spec.lua
+++ b/test/functional/terminal/scrollback_spec.lua
@@ -576,21 +576,21 @@ describe("pending scrollback line handling", function()
]]
screen:expect [[
{1: 1 }^a |
- {1: 2 } a |
- {1: 3 } a |
- {1: 4 } a |
- {1: 5 } a |
- {1: 6 } a |
+ {1: 2 }a |
+ {1: 3 }a |
+ {1: 4 }a |
+ {1: 5 }a |
+ {1: 6 }a |
|
]]
feed('G')
screen:expect [[
- {1: 7 } a |
- {1: 8 } a |
- {1: 9 } a |
- {1: 10 } a |
- {1: 11 } a |
- {1: 12 } ^a |
+ {1: 7 }a |
+ {1: 8 }a |
+ {1: 9 }a |
+ {1: 10 }a |
+ {1: 11 }a |
+ {1: 12 }^a |
|
]]
assert_alive()