mirror of
https://github.com/neovim/neovim.git
synced 2025-10-10 03:46:31 +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
|
By default (and currently the only option) the terminal will not be
|
||||||
connected to an external process. Instead, input sent on the channel will
|
connected to an external process. Instead, input sent on the channel will
|
||||||
be echoed directly by the terminal. This is useful to display ANSI
|
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
|
Note: to directly initiate the terminal using the right size, display the
|
||||||
buffer in a configured window before calling this. For instance, for a
|
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
|
Since: 0.5.0
|
||||||
|
|
||||||
Parameters: ~
|
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.
|
• {opts} Optional parameters.
|
||||||
• on_input: Lua callback for input sent, i e keypresses in
|
• on_input: Lua callback for input sent, i e keypresses in
|
||||||
terminal mode. Note: keypresses are sent raw as they would
|
terminal mode. Note: keypresses are sent raw as they would
|
||||||
|
@@ -172,7 +172,8 @@ STARTUP
|
|||||||
|
|
||||||
TERMINAL
|
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
|
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
|
--- By default (and currently the only option) the terminal will not be
|
||||||
--- connected to an external process. Instead, input sent on the channel
|
--- connected to an external process. Instead, input sent on the channel
|
||||||
--- will be echoed directly by the terminal. This is useful to display
|
--- 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
|
--- Note: to directly initiate the terminal using the right size, display the
|
||||||
--- buffer in a configured window before calling this. For instance, for a
|
--- 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' })
|
--- 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.
|
--- @param opts vim.api.keyset.open_term Optional parameters.
|
||||||
--- - on_input: Lua callback for input sent, i e keypresses in terminal
|
--- - 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
|
--- 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/mpack_core.h",
|
||||||
"mpack/object.h",
|
"mpack/object.h",
|
||||||
"nvim/func_attr.h",
|
"nvim/func_attr.h",
|
||||||
|
"nvim/strings.h",
|
||||||
"termkey/termkey.h",
|
"termkey/termkey.h",
|
||||||
"vterm/vterm.h",
|
"vterm/vterm.h",
|
||||||
"xdiff/xdiff.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
|
/// By default (and currently the only option) the terminal will not be
|
||||||
/// connected to an external process. Instead, input sent on the channel
|
/// connected to an external process. Instead, input sent on the channel
|
||||||
/// will be echoed directly by the terminal. This is useful to display
|
/// 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
|
/// Note: to directly initiate the terminal using the right size, display the
|
||||||
/// buffer in a configured window before calling this. For instance, for a
|
/// 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' })
|
/// 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.
|
/// @param opts Optional parameters.
|
||||||
/// - on_input: Lua callback for input sent, i e keypresses in terminal
|
/// - 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
|
/// 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,
|
.close_cb = term_close,
|
||||||
.force_crlf = GET_BOOL_OR_TRUE(opts, open_term, force_crlf),
|
.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);
|
channel_incref(chan);
|
||||||
terminal_open(&chan->term, buf, topts);
|
terminal_open(&chan->term, buf, topts);
|
||||||
if (chan->term != NULL) {
|
if (chan->term != NULL) {
|
||||||
terminal_check_size(chan->term);
|
terminal_check_size(chan->term);
|
||||||
}
|
}
|
||||||
channel_decref(chan);
|
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;
|
return (Integer)chan->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -4154,3 +4154,54 @@ void buf_set_changedtick(buf_T *const buf, const varnumber_T changedtick)
|
|||||||
&old_val);
|
&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/gettext_defs.h" // IWYU pragma: keep
|
||||||
#include "nvim/macros_defs.h"
|
#include "nvim/macros_defs.h"
|
||||||
#include "nvim/marktree_defs.h"
|
#include "nvim/marktree_defs.h"
|
||||||
|
#include "nvim/strings.h"
|
||||||
#include "nvim/types_defs.h"
|
#include "nvim/types_defs.h"
|
||||||
|
|
||||||
/// Values for buflist_getfile()
|
/// Values for buflist_getfile()
|
||||||
|
@@ -8,7 +8,7 @@
|
|||||||
#include "auto/config.h"
|
#include "auto/config.h"
|
||||||
#include "klib/kvec.h"
|
#include "klib/kvec.h"
|
||||||
#include "nvim/ascii_defs.h"
|
#include "nvim/ascii_defs.h"
|
||||||
#include "nvim/buffer_defs.h"
|
#include "nvim/buffer.h"
|
||||||
#include "nvim/charset.h"
|
#include "nvim/charset.h"
|
||||||
#include "nvim/errors.h"
|
#include "nvim/errors.h"
|
||||||
#include "nvim/eval.h"
|
#include "nvim/eval.h"
|
||||||
@@ -1204,44 +1204,7 @@ static size_t word_length(const char *str)
|
|||||||
/// before we finish writing.
|
/// before we finish writing.
|
||||||
static void read_input(StringBuilder *buf)
|
static void read_input(StringBuilder *buf)
|
||||||
{
|
{
|
||||||
size_t written = 0;
|
read_buffer_into(curbuf, curbuf->b_op_start.lnum, curbuf->b_op_end.lnum, buf);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t write_output(char *output, size_t remaining, bool eof)
|
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 },
|
[102] = { background = Screen.colors.LightMagenta, reverse = true },
|
||||||
[103] = { background = Screen.colors.LightMagenta, bold = true, 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)
|
end)
|
||||||
|
|
||||||
@@ -3887,6 +3889,24 @@ describe('API', function()
|
|||||||
}
|
}
|
||||||
eq('ba\024blaherrejösses!', exec_lua [[ return stream ]])
|
eq('ba\024blaherrejösses!', exec_lua [[ return stream ]])
|
||||||
end)
|
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)
|
end)
|
||||||
|
|
||||||
describe('nvim_del_mark', function()
|
describe('nvim_del_mark', function()
|
||||||
|
Reference in New Issue
Block a user