mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-07 04:06:07 -05:00
Merge branch 'pipe-command-output'
This commit is contained in:
commit
0a302265ec
12 changed files with 246 additions and 51 deletions
|
|
@ -58,6 +58,7 @@
|
|||
of floating windows to be constrained to multiples of the cell size.
|
||||
* Support for custom (i.e. other than ctrl/shift/alt/super) modifiers
|
||||
in key bindings ([#1348][1348]).
|
||||
* `pipe-command-output` key binding.
|
||||
|
||||
[1348]: https://codeberg.org/dnkl/foot/issues/1348
|
||||
|
||||
|
|
|
|||
36
README.md
36
README.md
|
|
@ -359,6 +359,42 @@ See the
|
|||
[wiki](https://codeberg.org/dnkl/foot/wiki#user-content-jumping-between-prompts)
|
||||
for details, and examples for other shells.
|
||||
|
||||
### Piping last command’s output
|
||||
|
||||
The key binding `pipe-command-output` can pipe the last command’s
|
||||
output to an application of your choice (similar to the other `pipe-*`
|
||||
key bindings):
|
||||
|
||||
```ini
|
||||
[key-bindings]
|
||||
pipe-command-output=[sh -c "f=$(mktemp); cat - > $f; footclient emacsclient -nw $f; rm $f"] Control+Shift+g
|
||||
```
|
||||
|
||||
When pressing <kbd>ctrl</kbd>+<kbd>shift</kbd>+<kbd>g</kbd>, the last
|
||||
command’s output is written to a temporary file, then an emacsclient
|
||||
is started in a new footclient instance. The temporary file is removed
|
||||
after the footclient instance has closed.
|
||||
|
||||
For this to work, the shell must emit an OSC-133;C (`\E]133;C\E\\`)
|
||||
sequence before command output starts, and an OSC-133;D
|
||||
(`\E]133;D\E\\`) when the command output ends.
|
||||
|
||||
In fish, one way to do this is to add `preexec` and `postexec` hooks:
|
||||
|
||||
```fish
|
||||
function foot_cmd_start --on-event fish_preexec
|
||||
echo -en "\e]133;C\e\\"
|
||||
end
|
||||
|
||||
function foot_cmd_end --on-event fish_postexec
|
||||
echo -en "\e]133;D\e\\"
|
||||
end
|
||||
```
|
||||
|
||||
See the
|
||||
[wiki](https://codeberg.org/dnkl/foot/wiki#user-content-piping-last-commands-output)
|
||||
for details, and examples for other shells
|
||||
|
||||
|
||||
## Alt/meta
|
||||
|
||||
|
|
|
|||
1
config.c
1
config.c
|
|
@ -111,6 +111,7 @@ static const char *const binding_action_map[] = {
|
|||
[BIND_ACTION_PIPE_SCROLLBACK] = "pipe-scrollback",
|
||||
[BIND_ACTION_PIPE_VIEW] = "pipe-visible",
|
||||
[BIND_ACTION_PIPE_SELECTED] = "pipe-selected",
|
||||
[BIND_ACTION_PIPE_COMMAND_OUTPUT] = "pipe-command-output",
|
||||
[BIND_ACTION_SHOW_URLS_COPY] = "show-urls-copy",
|
||||
[BIND_ACTION_SHOW_URLS_LAUNCH] = "show-urls-launch",
|
||||
[BIND_ACTION_SHOW_URLS_PERSISTENT] = "show-urls-persistent",
|
||||
|
|
|
|||
|
|
@ -424,6 +424,38 @@ See the wiki
|
|||
(https://codeberg.org/dnkl/foot/wiki#user-content-jumping-between-prompts)
|
||||
for details, and examples for other shells.
|
||||
|
||||
## Piping last command’s output
|
||||
|
||||
The key binding *pipe-command-output* can pipe the last command’s
|
||||
output to an application of your choice (similar to the other
|
||||
*pipe-\** key bindings):
|
||||
|
||||
*\[key-bindings\]++
|
||||
pipe-command-output=[sh -c "f=$(mktemp); cat - > $f; footclient emacsclient -nw $f; rm $f"] Control+Shift+g*
|
||||
|
||||
When pressing *ctrl*+*shift*+*g*, the last command’s output is written
|
||||
to a temporary file, then an emacsclient is started in a new
|
||||
footclient instance. The temporary file is removed after the
|
||||
footclient instance has closed.
|
||||
|
||||
For this to work, the shell must emit an OSC-133;C (*\\E]133;C\\E\\\\*)
|
||||
sequence before command output starts, and an OSC-133;D
|
||||
(*\\E]133;D\\E\\\\*) when the command output ends.
|
||||
|
||||
In fish, one way to do this is to add _preexec_ and _postexec_ hooks:
|
||||
|
||||
*function foot_cmd_start --on-event fish_preexec
|
||||
echo -en "\\e]133;C\\e\\\\"
|
||||
end*
|
||||
|
||||
*function foot_cmd_end --on-event fish_postexec
|
||||
echo -en "\\e]133;D\\e\\\\"
|
||||
end*
|
||||
|
||||
See the wiki
|
||||
(https://codeberg.org/dnkl/foot/wiki#user-content-piping-last-commands-output)
|
||||
for details, and examples for other shells
|
||||
|
||||
# TERMINFO
|
||||
|
||||
Client applications use the terminfo identifier specified by the
|
||||
|
|
|
|||
|
|
@ -844,11 +844,12 @@ e.g. *search-start=none*.
|
|||
*fullscreen*
|
||||
Toggles the fullscreen state. Default: _none_.
|
||||
|
||||
*pipe-visible*, *pipe-scrollback*, *pipe-selected*
|
||||
Pipes the currently visible text, the entire scrollback, or the
|
||||
currently selected text to an external tool. The syntax for this
|
||||
option is a bit special; the first part of the value is the
|
||||
command to execute enclosed in "[]", followed by the binding(s).
|
||||
*pipe-visible*, *pipe-scrollback*, *pipe-selected*, *pipe-command-output*
|
||||
Pipes the currently visible text, the entire scrollback, the
|
||||
currently selected text, or the last command's output to an
|
||||
external tool. The syntax for this option is a bit special; the
|
||||
first part of the value is the command to execute enclosed in
|
||||
"[]", followed by the binding(s).
|
||||
|
||||
You can configure multiple pipes as long as the command strings
|
||||
are different and the key bindings are unique.
|
||||
|
|
@ -856,10 +857,17 @@ e.g. *search-start=none*.
|
|||
Note that the command is *not* automatically run inside a shell;
|
||||
use *sh -c "command line"* if you need that.
|
||||
|
||||
Example:
|
||||
*pipe-visible=[sh -c "xurls | uniq | tac | fuzzel | xargs -r
|
||||
Example #1:
|
||||
|
||||
# Extract currently visible URLs, let user choose one (via
|
||||
fuzzel), then launch firefox with the selected URL++
|
||||
*pipe-visible=[sh -c "xurls | uniq | tac | fuzzel | xargs -r
|
||||
firefox"] Control+Print*
|
||||
|
||||
Example #2:
|
||||
# Write scrollback content to /tmp/foot-scrollback.txt++
|
||||
*pipe-scrollback=[sh -c "cat - > /tmp/foot-scrollback.txt"]
|
||||
Control+Shift+Print*
|
||||
Default: _none_
|
||||
|
||||
*show-urls-launch*
|
||||
|
|
|
|||
1
foot.ini
1
foot.ini
|
|
@ -158,6 +158,7 @@
|
|||
# pipe-visible=[sh -c "xurls | fuzzel | xargs -r firefox"] none
|
||||
# pipe-scrollback=[sh -c "xurls | fuzzel | xargs -r firefox"] none
|
||||
# pipe-selected=[xargs -r firefox] none
|
||||
# pipe-command-output=[sh -c "cat - > /tmp/foot-cmd-out.txt"] none # Write output of last command to /tmp/foot-cmd-out.txt (requires shell integration)
|
||||
# show-urls-launch=Control+Shift+o
|
||||
# show-urls-copy=none
|
||||
# show-urls-persistent=none
|
||||
|
|
|
|||
70
grid.c
70
grid.c
|
|
@ -1,5 +1,6 @@
|
|||
#include "grid.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
|
@ -231,7 +232,7 @@ grid_snapshot(const struct grid *grid)
|
|||
clone_row->cells = xmalloc(grid->num_cols * sizeof(clone_row->cells[0]));
|
||||
clone_row->linebreak = row->linebreak;
|
||||
clone_row->dirty = row->dirty;
|
||||
clone_row->prompt_marker = row->prompt_marker;
|
||||
clone_row->shell_integration = row->shell_integration;
|
||||
|
||||
for (int c = 0; c < grid->num_cols; c++)
|
||||
clone_row->cells[c] = row->cells[c];
|
||||
|
|
@ -366,7 +367,9 @@ grid_row_alloc(int cols, bool initialize)
|
|||
row->dirty = false;
|
||||
row->linebreak = false;
|
||||
row->extra = NULL;
|
||||
row->prompt_marker = false;
|
||||
row->shell_integration.prompt_marker = false;
|
||||
row->shell_integration.cmd_start = -1;
|
||||
row->shell_integration.cmd_end = -1;
|
||||
|
||||
if (initialize) {
|
||||
row->cells = xcalloc(cols, sizeof(row->cells[0]));
|
||||
|
|
@ -425,7 +428,9 @@ grid_resize_without_reflow(
|
|||
|
||||
new_row->dirty = old_row->dirty;
|
||||
new_row->linebreak = false;
|
||||
new_row->prompt_marker = old_row->prompt_marker;
|
||||
new_row->shell_integration.prompt_marker = old_row->shell_integration.prompt_marker;
|
||||
new_row->shell_integration.cmd_start = min(old_row->shell_integration.cmd_start, new_cols - 1);
|
||||
new_row->shell_integration.cmd_end = min(old_row->shell_integration.cmd_end, new_cols - 1);
|
||||
|
||||
if (new_cols > old_cols) {
|
||||
/* Clear "new" columns */
|
||||
|
|
@ -587,7 +592,9 @@ _line_wrap(struct grid *old_grid, struct row **new_grid, struct row *row,
|
|||
/* Scrollback is full, need to reuse a row */
|
||||
grid_row_reset_extra(new_row);
|
||||
new_row->linebreak = false;
|
||||
new_row->prompt_marker = false;
|
||||
new_row->shell_integration.prompt_marker = false;
|
||||
new_row->shell_integration.cmd_start = -1;
|
||||
new_row->shell_integration.cmd_end = -1;
|
||||
|
||||
tll_foreach(old_grid->sixel_images, it) {
|
||||
if (it->item.pos.row == *row_idx) {
|
||||
|
|
@ -831,35 +838,26 @@ grid_resize_and_reflow(
|
|||
int end;
|
||||
bool tp_break = false;
|
||||
bool uri_break = false;
|
||||
bool ftcs_break = false;
|
||||
|
||||
/*
|
||||
* Set end-coordinate for this chunk, by finding the next
|
||||
* point-of-interest on this row.
|
||||
*
|
||||
* If there are no more tracking points, or URI ranges,
|
||||
* the end-coordinate will be at the end of the row,
|
||||
*/
|
||||
if (range != range_terminator) {
|
||||
int uri_col = (range->start >= start ? range->start : range->end) + 1;
|
||||
/* Figure out where to end this chunk */
|
||||
{
|
||||
const int uri_col = range != range_terminator
|
||||
? ((range->start >= start ? range->start : range->end) + 1)
|
||||
: INT_MAX;
|
||||
const int tp_col = tp != NULL ? tp->col + 1 : INT_MAX;
|
||||
const int ftcs_col = old_row->shell_integration.cmd_start >= start
|
||||
? old_row->shell_integration.cmd_start + 1
|
||||
: old_row->shell_integration.cmd_end >= start
|
||||
? old_row->shell_integration.cmd_end + 1
|
||||
: INT_MAX;
|
||||
|
||||
if (tp != NULL) {
|
||||
int tp_col = tp->col + 1;
|
||||
end = min(tp_col, uri_col);
|
||||
end = min(col_count, min(min(tp_col, uri_col), ftcs_col));
|
||||
|
||||
tp_break = end == tp_col;
|
||||
uri_break = end == uri_col;
|
||||
LOG_DBG("tp+uri break at %d (%d, %d)", end, tp_col, uri_col);
|
||||
} else {
|
||||
end = uri_col;
|
||||
uri_break = true;
|
||||
LOG_DBG("uri break at %d", end);
|
||||
}
|
||||
} else if (tp != NULL) {
|
||||
end = tp->col + 1;
|
||||
tp_break = true;
|
||||
LOG_DBG("TP break at %d", end);
|
||||
} else
|
||||
end = col_count;
|
||||
uri_break = end == uri_col;
|
||||
tp_break = end == tp_col;
|
||||
ftcs_break = end == ftcs_col;
|
||||
}
|
||||
|
||||
int cols = end - start;
|
||||
xassert(cols > 0);
|
||||
|
|
@ -920,7 +918,7 @@ grid_resize_and_reflow(
|
|||
xassert(from + amount <= old_cols);
|
||||
|
||||
if (from == 0)
|
||||
new_row->prompt_marker = old_row->prompt_marker;
|
||||
new_row->shell_integration.prompt_marker = old_row->shell_integration.prompt_marker;
|
||||
|
||||
memcpy(
|
||||
&new_row->cells[new_col_idx], &old_row->cells[from],
|
||||
|
|
@ -979,6 +977,16 @@ grid_resize_and_reflow(
|
|||
}
|
||||
}
|
||||
|
||||
if (ftcs_break) {
|
||||
xassert(old_row->shell_integration.cmd_start == start + cols - 1 ||
|
||||
old_row->shell_integration.cmd_end == start + cols - 1);
|
||||
|
||||
if (old_row->shell_integration.cmd_start == start + cols - 1)
|
||||
new_row->shell_integration.cmd_start = new_col_idx - 1;
|
||||
if (old_row->shell_integration.cmd_end == start + cols - 1)
|
||||
new_row->shell_integration.cmd_end = new_col_idx - 1;
|
||||
}
|
||||
|
||||
left -= cols;
|
||||
start += cols;
|
||||
}
|
||||
|
|
|
|||
11
input.c
11
input.c
|
|
@ -227,7 +227,8 @@ execute_binding(struct seat *seat, struct terminal *term,
|
|||
break;
|
||||
/* FALLTHROUGH */
|
||||
case BIND_ACTION_PIPE_VIEW:
|
||||
case BIND_ACTION_PIPE_SELECTED: {
|
||||
case BIND_ACTION_PIPE_SELECTED:
|
||||
case BIND_ACTION_PIPE_COMMAND_OUTPUT: {
|
||||
if (binding->aux->type != BINDING_AUX_PIPE)
|
||||
return true;
|
||||
|
||||
|
|
@ -269,6 +270,10 @@ execute_binding(struct seat *seat, struct terminal *term,
|
|||
len = text != NULL ? strlen(text) : 0;
|
||||
break;
|
||||
|
||||
case BIND_ACTION_PIPE_COMMAND_OUTPUT:
|
||||
success = term_command_output_to_text(term, &text, &len);
|
||||
break;
|
||||
|
||||
default:
|
||||
BUG("Unhandled action type");
|
||||
success = false;
|
||||
|
|
@ -377,7 +382,7 @@ execute_binding(struct seat *seat, struct terminal *term,
|
|||
const struct row *row = grid->rows[r_abs];
|
||||
xassert(row != NULL);
|
||||
|
||||
if (!row->prompt_marker)
|
||||
if (!row->shell_integration.prompt_marker)
|
||||
continue;
|
||||
|
||||
grid->view = r_abs;
|
||||
|
|
@ -409,7 +414,7 @@ execute_binding(struct seat *seat, struct terminal *term,
|
|||
const struct row *row = grid->rows[r_abs];
|
||||
xassert(row != NULL);
|
||||
|
||||
if (!row->prompt_marker) {
|
||||
if (!row->shell_integration.prompt_marker) {
|
||||
if (r_abs == grid->offset + term->rows - 1) {
|
||||
/* We’ve reached the bottom of the scrollback */
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ enum bind_action_normal {
|
|||
BIND_ACTION_PIPE_SCROLLBACK,
|
||||
BIND_ACTION_PIPE_VIEW,
|
||||
BIND_ACTION_PIPE_SELECTED,
|
||||
BIND_ACTION_PIPE_COMMAND_OUTPUT,
|
||||
BIND_ACTION_SHOW_URLS_COPY,
|
||||
BIND_ACTION_SHOW_URLS_LAUNCH,
|
||||
BIND_ACTION_SHOW_URLS_PERSISTENT,
|
||||
|
|
|
|||
12
osc.c
12
osc.c
|
|
@ -893,7 +893,7 @@ osc_dispatch(struct terminal *term)
|
|||
term->grid->cursor.point.row,
|
||||
term->grid->cursor.point.col);
|
||||
|
||||
term->grid->cur_row->prompt_marker = true;
|
||||
term->grid->cur_row->shell_integration.prompt_marker = true;
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
|
|
@ -901,11 +901,17 @@ osc_dispatch(struct terminal *term)
|
|||
break;
|
||||
|
||||
case 'C':
|
||||
LOG_DBG("FTCS_COMMAND_EXECUTED");
|
||||
LOG_DBG("FTCS_COMMAND_EXECUTED: %dx%d",
|
||||
term->grid->cursor.point.row,
|
||||
term->grid->cursor.point.col);
|
||||
term->grid->cur_row->shell_integration.cmd_start = term->grid->cursor.point.col;
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
LOG_DBG("FTCS_COMMAND_FINISHED");
|
||||
LOG_DBG("FTCS_COMMAND_FINISHED: %dx%d",
|
||||
term->grid->cursor.point.row,
|
||||
term->grid->cursor.point.col);
|
||||
term->grid->cur_row->shell_integration.cmd_end = term->grid->cursor.point.col;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
101
terminal.c
101
terminal.c
|
|
@ -1825,7 +1825,9 @@ erase_line(struct terminal *term, struct row *row)
|
|||
{
|
||||
erase_cell_range(term, row, 0, term->cols - 1);
|
||||
row->linebreak = false;
|
||||
row->prompt_marker = false;
|
||||
row->shell_integration.prompt_marker = false;
|
||||
row->shell_integration.cmd_start = -1;
|
||||
row->shell_integration.cmd_end = -1;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -3611,7 +3613,7 @@ term_surface_kind(const struct terminal *term, const struct wl_surface *surface)
|
|||
|
||||
static bool
|
||||
rows_to_text(const struct terminal *term, int start, int end,
|
||||
char **text, size_t *len)
|
||||
int col_start, int col_end, char **text, size_t *len)
|
||||
{
|
||||
struct extraction_context *ctx = extract_begin(SELECTION_NONE, true);
|
||||
if (ctx == NULL)
|
||||
|
|
@ -3624,15 +3626,20 @@ rows_to_text(const struct terminal *term, int start, int end,
|
|||
const struct row *row = term->grid->rows[r];
|
||||
xassert(row != NULL);
|
||||
|
||||
for (int c = 0; c < term->cols; c++)
|
||||
const int c_end = r == end ? col_end : term->cols;
|
||||
|
||||
for (int c = col_start; c < c_end; c++) {
|
||||
if (!extract_one(term, row, &row->cells[c], c, ctx))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (r == end)
|
||||
break;
|
||||
|
||||
r++;
|
||||
r &= grid_rows - 1;
|
||||
|
||||
col_start = 0;
|
||||
}
|
||||
|
||||
out:
|
||||
|
|
@ -3664,7 +3671,7 @@ term_scrollback_to_text(const struct terminal *term, char **text, size_t *len)
|
|||
end += term->grid->num_rows;
|
||||
}
|
||||
|
||||
return rows_to_text(term, start, end, text, len);
|
||||
return rows_to_text(term, start, end, 0, term->cols, text, len);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -3672,7 +3679,91 @@ term_view_to_text(const struct terminal *term, char **text, size_t *len)
|
|||
{
|
||||
int start = grid_row_absolute_in_view(term->grid, 0);
|
||||
int end = grid_row_absolute_in_view(term->grid, term->rows - 1);
|
||||
return rows_to_text(term, start, end, text, len);
|
||||
return rows_to_text(term, start, end, 0, term->cols, text, len);
|
||||
}
|
||||
|
||||
bool
|
||||
term_command_output_to_text(const struct terminal *term, char **text, size_t *len)
|
||||
{
|
||||
int start_row = -1;
|
||||
int end_row = -1;
|
||||
int start_col = -1;
|
||||
int end_col = -1;
|
||||
|
||||
const struct grid *grid = term->grid;
|
||||
const int sb_end = grid_row_absolute(grid, term->rows - 1);
|
||||
const int sb_start = (sb_end + 1) & (grid->num_rows - 1);
|
||||
int r = sb_end;
|
||||
|
||||
while (start_row < 0) {
|
||||
const struct row *row = grid->rows[r];
|
||||
if (row == NULL)
|
||||
break;
|
||||
|
||||
if (row->shell_integration.cmd_end >= 0) {
|
||||
end_row = r;
|
||||
end_col = row->shell_integration.cmd_end;
|
||||
}
|
||||
|
||||
if (end_row >= 0 && row->shell_integration.cmd_start >= 0) {
|
||||
start_row = r;
|
||||
start_col = row->shell_integration.cmd_start;
|
||||
}
|
||||
|
||||
if (r == sb_start)
|
||||
break;
|
||||
|
||||
r = (r - 1 + grid->num_rows) & (grid->num_rows - 1);
|
||||
}
|
||||
|
||||
if (start_row < 0)
|
||||
return false;
|
||||
|
||||
bool ret = rows_to_text(term, start_row, end_row, start_col, end_col, text, len);
|
||||
if (!ret)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* If the FTCS_COMMAND_FINISHED marker was emitted at the *first*
|
||||
* column, then the *entire* previous line is part of the command
|
||||
* output. *Including* the newline, if any.
|
||||
*
|
||||
* Since rows_to_text() doesn’t extract the column
|
||||
* FTCS_COMMAND_FINISHED was emitted at (that would be wrong -
|
||||
* FTCS_COMMAND_FINISHED is emitted *after* the command output,
|
||||
* not at its last character), the extraction logic will not see
|
||||
* the last newline (this is true for all non-line-wise selection
|
||||
* types), and the extracted text will *not* end with a newline.
|
||||
*
|
||||
* Here we try to compensate for that. Note that if ‘end_col’ is
|
||||
* not 0, then the command output only covers a partial row, and
|
||||
* thus we do *not* want to append a newline.
|
||||
*/
|
||||
|
||||
if (end_col > 0) {
|
||||
/* Command output covers partial row - don’t append newline */
|
||||
return true;
|
||||
}
|
||||
|
||||
int next_to_last_row = (end_row - 1 + grid->num_rows) & (grid->num_rows - 1);
|
||||
const struct row *row = grid->rows[next_to_last_row];
|
||||
|
||||
/* Add newline if last row has a hard linebreak */
|
||||
if (row->linebreak) {
|
||||
char *new_text = xrealloc(*text, *len + 1 + 1);
|
||||
|
||||
if (new_text == NULL) {
|
||||
/* Ignore failure - use text as is (without inserting newline) */
|
||||
return true;
|
||||
}
|
||||
|
||||
*text = new_text;
|
||||
(*len)++;
|
||||
(*text)[*len - 1] = '\n';
|
||||
(*text)[*len] = '\0';
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
|||
|
|
@ -121,8 +121,11 @@ struct row {
|
|||
bool dirty;
|
||||
bool linebreak;
|
||||
|
||||
/* Shell integration */
|
||||
bool prompt_marker;
|
||||
struct {
|
||||
bool prompt_marker;
|
||||
int cmd_start; /* Column, -1 if unset */
|
||||
int cmd_end; /* Column, -1 if unset */
|
||||
} shell_integration;
|
||||
};
|
||||
|
||||
struct sixel {
|
||||
|
|
@ -844,6 +847,8 @@ bool term_scrollback_to_text(
|
|||
const struct terminal *term, char **text, size_t *len);
|
||||
bool term_view_to_text(
|
||||
const struct terminal *term, char **text, size_t *len);
|
||||
bool term_command_output_to_text(
|
||||
const struct terminal *term, char **text, size_t *len);
|
||||
|
||||
bool term_ime_is_enabled(const struct terminal *term);
|
||||
void term_ime_enable(struct terminal *term);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue