mirror of
https://github.com/neovim/neovim.git
synced 2025-10-17 07:16:09 +00:00
feat(terminal): parse current buffer contents in nvim_open_term() (#33720)
When nvim_open_term() is called with a non-empty buffer, the buffer contents are piped into the PTY.
This commit is contained in:
@@ -1170,7 +1170,7 @@ nvim_open_term({buffer}, {opts}) *nvim_open_term()*
|
||||
By default (and currently the only option) the terminal will not be
|
||||
connected to an external process. Instead, input sent on the channel will
|
||||
be echoed directly by the terminal. This is useful to display ANSI
|
||||
terminal sequences returned as part of a rpc message, or similar.
|
||||
terminal sequences returned as part of an RPC message, or similar.
|
||||
|
||||
Note: to directly initiate the terminal using the right size, display the
|
||||
buffer in a configured window before calling this. For instance, for a
|
||||
@@ -1195,7 +1195,8 @@ nvim_open_term({buffer}, {opts}) *nvim_open_term()*
|
||||
Since: 0.5.0
|
||||
|
||||
Parameters: ~
|
||||
• {buffer} the buffer to use (expected to be empty)
|
||||
• {buffer} Buffer to use. Buffer contents (if any) will be written to
|
||||
the PTY.
|
||||
• {opts} Optional parameters.
|
||||
• on_input: Lua callback for input sent, i e keypresses in
|
||||
terminal mode. Note: keypresses are sent raw as they would
|
||||
|
@@ -172,7 +172,8 @@ STARTUP
|
||||
|
||||
TERMINAL
|
||||
|
||||
• todo
|
||||
• |nvim_open_term()| can be called with a non-empty buffer. The buffer
|
||||
contents are piped to the PTY and displayed as terminal output.
|
||||
|
||||
TREESITTER
|
||||
|
||||
|
5
runtime/lua/vim/_meta/api.lua
generated
5
runtime/lua/vim/_meta/api.lua
generated
@@ -1653,7 +1653,7 @@ function vim.api.nvim_notify(msg, log_level, opts) end
|
||||
--- By default (and currently the only option) the terminal will not be
|
||||
--- connected to an external process. Instead, input sent on the channel
|
||||
--- will be echoed directly by the terminal. This is useful to display
|
||||
--- ANSI terminal sequences returned as part of a rpc message, or similar.
|
||||
--- ANSI terminal sequences returned as part of an RPC message, or similar.
|
||||
---
|
||||
--- Note: to directly initiate the terminal using the right size, display the
|
||||
--- buffer in a configured window before calling this. For instance, for a
|
||||
@@ -1675,7 +1675,8 @@ function vim.api.nvim_notify(msg, log_level, opts) end
|
||||
--- end, { desc = 'Highlights ANSI termcodes in curbuf' })
|
||||
--- ```
|
||||
---
|
||||
--- @param buffer integer the buffer to use (expected to be empty)
|
||||
--- @param buffer integer Buffer to use. Buffer contents (if any) will be written
|
||||
--- to the PTY.
|
||||
--- @param opts vim.api.keyset.open_term Optional parameters.
|
||||
--- - on_input: Lua callback for input sent, i e keypresses in terminal
|
||||
--- mode. Note: keypresses are sent raw as they would be to the pty
|
||||
|
@@ -879,6 +879,7 @@ def CheckIncludes(filename, lines, error):
|
||||
"mpack/mpack_core.h",
|
||||
"mpack/object.h",
|
||||
"nvim/func_attr.h",
|
||||
"nvim/strings.h",
|
||||
"termkey/termkey.h",
|
||||
"vterm/vterm.h",
|
||||
"xdiff/xdiff.h",
|
||||
|
@@ -974,7 +974,7 @@ Buffer nvim_create_buf(Boolean listed, Boolean scratch, Error *err)
|
||||
/// By default (and currently the only option) the terminal will not be
|
||||
/// connected to an external process. Instead, input sent on the channel
|
||||
/// will be echoed directly by the terminal. This is useful to display
|
||||
/// ANSI terminal sequences returned as part of a rpc message, or similar.
|
||||
/// ANSI terminal sequences returned as part of an RPC message, or similar.
|
||||
///
|
||||
/// Note: to directly initiate the terminal using the right size, display the
|
||||
/// buffer in a configured window before calling this. For instance, for a
|
||||
@@ -996,7 +996,8 @@ Buffer nvim_create_buf(Boolean listed, Boolean scratch, Error *err)
|
||||
/// end, { desc = 'Highlights ANSI termcodes in curbuf' })
|
||||
/// ```
|
||||
///
|
||||
/// @param buffer the buffer to use (expected to be empty)
|
||||
/// @param buffer Buffer to use. Buffer contents (if any) will be written
|
||||
/// to the PTY.
|
||||
/// @param opts Optional parameters.
|
||||
/// - on_input: Lua callback for input sent, i e keypresses in terminal
|
||||
/// mode. Note: keypresses are sent raw as they would be to the pty
|
||||
@@ -1041,12 +1042,26 @@ Integer nvim_open_term(Buffer buffer, Dict(open_term) *opts, Error *err)
|
||||
.close_cb = term_close,
|
||||
.force_crlf = GET_BOOL_OR_TRUE(opts, open_term, force_crlf),
|
||||
};
|
||||
|
||||
// Read existing buffer contents (if any)
|
||||
StringBuilder contents = KV_INITIAL_VALUE;
|
||||
read_buffer_into(buf, 1, buf->b_ml.ml_line_count, &contents);
|
||||
|
||||
channel_incref(chan);
|
||||
terminal_open(&chan->term, buf, topts);
|
||||
if (chan->term != NULL) {
|
||||
terminal_check_size(chan->term);
|
||||
}
|
||||
channel_decref(chan);
|
||||
|
||||
// Write buffer contents to channel. channel_send takes ownership of the
|
||||
// buffer so we do not need to free it.
|
||||
if (contents.size > 0) {
|
||||
const char *error = NULL;
|
||||
channel_send(chan->id, contents.items, contents.size, true, &error);
|
||||
VALIDATE(!error, "%s", error, {});
|
||||
}
|
||||
|
||||
return (Integer)chan->id;
|
||||
}
|
||||
|
||||
|
@@ -4154,3 +4154,54 @@ void buf_set_changedtick(buf_T *const buf, const varnumber_T changedtick)
|
||||
&old_val);
|
||||
}
|
||||
}
|
||||
|
||||
/// Read the given buffer contents into a string.
|
||||
void read_buffer_into(buf_T *buf, linenr_T start, linenr_T end, StringBuilder *sb)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
assert(buf);
|
||||
assert(sb);
|
||||
|
||||
if (buf->b_ml.ml_flags & ML_EMPTY) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t written = 0;
|
||||
size_t len = 0;
|
||||
linenr_T lnum = start;
|
||||
char *lp = ml_get_buf(buf, lnum);
|
||||
size_t lplen = (size_t)ml_get_buf_len(buf, lnum);
|
||||
|
||||
while (true) {
|
||||
if (lplen == 0) {
|
||||
len = 0;
|
||||
} else if (lp[written] == NL) {
|
||||
// NL -> NUL translation
|
||||
len = 1;
|
||||
kv_push(*sb, NUL);
|
||||
} else {
|
||||
char *s = vim_strchr(lp + written, NL);
|
||||
len = s == NULL ? lplen - written : (size_t)(s - (lp + written));
|
||||
kv_concat_len(*sb, lp + written, len);
|
||||
}
|
||||
|
||||
if (len == lplen - written) {
|
||||
// Finished a line, add a NL, unless this line should not have one.
|
||||
if (lnum != end
|
||||
|| (!buf->b_p_bin && buf->b_p_fixeol)
|
||||
|| (lnum != buf->b_no_eol_lnum
|
||||
&& (lnum != buf->b_ml.ml_line_count || buf->b_p_eol))) {
|
||||
kv_push(*sb, NL);
|
||||
}
|
||||
lnum++;
|
||||
if (lnum > end) {
|
||||
break;
|
||||
}
|
||||
lp = ml_get_buf(buf, lnum);
|
||||
lplen = (size_t)ml_get_buf_len(buf, lnum);
|
||||
written = 0;
|
||||
} else if (len > 0) {
|
||||
written += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -8,6 +8,7 @@
|
||||
#include "nvim/gettext_defs.h" // IWYU pragma: keep
|
||||
#include "nvim/macros_defs.h"
|
||||
#include "nvim/marktree_defs.h"
|
||||
#include "nvim/strings.h"
|
||||
#include "nvim/types_defs.h"
|
||||
|
||||
/// Values for buflist_getfile()
|
||||
|
@@ -8,7 +8,7 @@
|
||||
#include "auto/config.h"
|
||||
#include "klib/kvec.h"
|
||||
#include "nvim/ascii_defs.h"
|
||||
#include "nvim/buffer_defs.h"
|
||||
#include "nvim/buffer.h"
|
||||
#include "nvim/charset.h"
|
||||
#include "nvim/errors.h"
|
||||
#include "nvim/eval.h"
|
||||
@@ -1204,44 +1204,7 @@ static size_t word_length(const char *str)
|
||||
/// before we finish writing.
|
||||
static void read_input(StringBuilder *buf)
|
||||
{
|
||||
size_t written = 0;
|
||||
size_t len = 0;
|
||||
linenr_T lnum = curbuf->b_op_start.lnum;
|
||||
char *lp = ml_get(lnum);
|
||||
size_t lplen = (size_t)ml_get_len(lnum);
|
||||
|
||||
while (true) {
|
||||
if (lplen == 0) {
|
||||
len = 0;
|
||||
} else if (lp[written] == NL) {
|
||||
// NL -> NUL translation
|
||||
len = 1;
|
||||
kv_push(*buf, NUL);
|
||||
} else {
|
||||
char *s = vim_strchr(lp + written, NL);
|
||||
len = s == NULL ? lplen - written : (size_t)(s - (lp + written));
|
||||
kv_concat_len(*buf, lp + written, len);
|
||||
}
|
||||
|
||||
if (len == lplen - written) {
|
||||
// Finished a line, add a NL, unless this line should not have one.
|
||||
if (lnum != curbuf->b_op_end.lnum
|
||||
|| (!curbuf->b_p_bin && curbuf->b_p_fixeol)
|
||||
|| (lnum != curbuf->b_no_eol_lnum
|
||||
&& (lnum != curbuf->b_ml.ml_line_count || curbuf->b_p_eol))) {
|
||||
kv_push(*buf, NL);
|
||||
}
|
||||
lnum++;
|
||||
if (lnum > curbuf->b_op_end.lnum) {
|
||||
break;
|
||||
}
|
||||
lp = ml_get(lnum);
|
||||
lplen = (size_t)ml_get_len(lnum);
|
||||
written = 0;
|
||||
} else if (len > 0) {
|
||||
written += len;
|
||||
}
|
||||
}
|
||||
read_buffer_into(curbuf, curbuf->b_op_start.lnum, curbuf->b_op_end.lnum, buf);
|
||||
}
|
||||
|
||||
static size_t write_output(char *output, size_t remaining, bool eof)
|
||||
|
@@ -3773,6 +3773,8 @@ describe('API', function()
|
||||
},
|
||||
[102] = { background = Screen.colors.LightMagenta, reverse = true },
|
||||
[103] = { background = Screen.colors.LightMagenta, bold = true, reverse = true },
|
||||
[104] = { fg_indexed = true, foreground = tonumber('0xe00000') },
|
||||
[105] = { fg_indexed = true, foreground = tonumber('0xe0e000') },
|
||||
}
|
||||
end)
|
||||
|
||||
@@ -3887,6 +3889,24 @@ describe('API', function()
|
||||
}
|
||||
eq('ba\024blaherrejösses!', exec_lua [[ return stream ]])
|
||||
end)
|
||||
|
||||
it('parses text from the current buffer', function()
|
||||
local b = api.nvim_create_buf(true, true)
|
||||
api.nvim_buf_set_lines(b, 0, -1, true, { '\027[31mHello\000\027[0m', '\027[33mworld\027[0m' })
|
||||
api.nvim_set_current_buf(b)
|
||||
screen:expect([[
|
||||
{18:^^[}[31mHello{18:^@^[}[0m |
|
||||
{18:^[}[33mworld{18:^[}[0m |
|
||||
{1:~ }|*32
|
||||
|
|
||||
]])
|
||||
api.nvim_open_term(b, {})
|
||||
screen:expect([[
|
||||
{104:^Hello} |
|
||||
{105:world} |
|
||||
|*33
|
||||
]])
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('nvim_del_mark', function()
|
||||
|
Reference in New Issue
Block a user