Allow getting the last non-empty command output easily via an action or remote control
Fixes #4973
This commit is contained in:
parent
4c74462763
commit
0509855930
@ -39,6 +39,9 @@ Detailed list of changes
|
||||
|
||||
- A new command :command:`edit-in-kitty` to :ref:`edit_file`
|
||||
|
||||
- Allow getting the last non-empty command output easily via an action or
|
||||
remote control (:pull:`4973`)
|
||||
|
||||
- Fix a bug that caused :opt:`macos_colorspace` to always be ``default`` regardless of its actual value (:iss:`5129`)
|
||||
|
||||
- ssh kitten: Fix bash not being executed as a login shell since kitty 0.25.0 (:iss:`5130`)
|
||||
|
||||
@ -73,6 +73,13 @@ left_shift_line(Line *line, index_type at, index_type num) {
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool
|
||||
line_is_empty(const Line *line) {
|
||||
for (index_type i = 0; i < line->xnum; i++) {
|
||||
if (line->cpu_cells[i].ch != BLANK_CHAR) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef Line*(get_line_func)(void *, int);
|
||||
void line_clear_text(Line *self, unsigned int at, unsigned int num, char_type ch);
|
||||
|
||||
@ -30,14 +30,15 @@ class GetText(RemoteCommand):
|
||||
options_spec = MATCH_WINDOW_OPTION + '''\n
|
||||
--extent
|
||||
default=screen
|
||||
choices=screen, all, selection, first_cmd_output_on_screen, last_cmd_output, last_visited_cmd_output
|
||||
choices=screen, all, selection, first_cmd_output_on_screen, last_cmd_output, last_visited_cmd_output, last_non_empty_output
|
||||
What text to get. The default of :code:`screen` means all text currently on the screen.
|
||||
:code:`all` means all the screen+scrollback and :code:`selection` means the
|
||||
currently selected text. :code:`first_cmd_output_on_screen` means the output of the first
|
||||
command that was run in the window on screen. :code:`last_cmd_output` means
|
||||
the output of the last command that was run in the window. :code:`last_visited_cmd_output` means
|
||||
the first command output below the last scrolled position via scroll_to_prompt. The last three
|
||||
requires :ref:`shell_integration` to be enabled.
|
||||
the first command output below the last scrolled position via scroll_to_prompt.
|
||||
:code:`last_non_empty_output` is the output from the last command run in the window that had
|
||||
some non empty output. The last four require :ref:`shell_integration` to be enabled.
|
||||
|
||||
|
||||
--ansi
|
||||
@ -99,6 +100,12 @@ Get text from the window this command is run in, rather than the active window.
|
||||
as_ansi=bool(payload_get('ansi')),
|
||||
add_wrap_markers=bool(payload_get('wrap_markers')),
|
||||
)
|
||||
elif payload_get('extent') == 'last_non_empty_output':
|
||||
ans = window.cmd_output(
|
||||
CommandOutput.last_non_empty,
|
||||
as_ansi=bool(payload_get('ansi')),
|
||||
add_wrap_markers=bool(payload_get('wrap_markers')),
|
||||
)
|
||||
elif payload_get('extent') == 'last_visited_cmd_output':
|
||||
ans = window.cmd_output(
|
||||
CommandOutput.last_visited,
|
||||
|
||||
@ -2859,6 +2859,30 @@ cmd_output(Screen *self, PyObject *args) {
|
||||
if (self->last_visited_prompt.scrolled_by <= self->historybuf->count && self->last_visited_prompt.is_set) {
|
||||
found = find_cmd_output(self, &oo, self->last_visited_prompt.y, self->last_visited_prompt.scrolled_by, 0, false);
|
||||
} break;
|
||||
case 3: { // last non-empty output
|
||||
int y = self->cursor->y;
|
||||
Line *line;
|
||||
bool reached_upper_limit = false;
|
||||
while (!found && !reached_upper_limit) {
|
||||
line = checked_range_line(self, y);
|
||||
if (!line || (line->attrs.prompt_kind == OUTPUT_START && !line->attrs.continued)) {
|
||||
int start = line ? y : y + 1; reached_upper_limit = !line;
|
||||
int y2 = start; unsigned int num_lines = 0;
|
||||
bool found_content = false;
|
||||
while ((line = checked_range_line(self, y2)) && line->attrs.prompt_kind != PROMPT_START) {
|
||||
if (!found_content) found_content = !line_is_empty(line);
|
||||
num_lines++; y2++;
|
||||
}
|
||||
if (found_content) {
|
||||
found = true;
|
||||
oo.reached_upper_limit = reached_upper_limit;
|
||||
oo.start = start; oo.num_lines = num_lines;
|
||||
break;
|
||||
}
|
||||
}
|
||||
y--;
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
PyErr_Format(PyExc_KeyError, "%u is not a valid type of command", which);
|
||||
return NULL;
|
||||
|
||||
@ -164,7 +164,7 @@ class DynamicColor(IntEnum):
|
||||
|
||||
|
||||
class CommandOutput(IntEnum):
|
||||
last_run, first_on_screen, last_visited = 0, 1, 2
|
||||
last_run, first_on_screen, last_visited, last_non_empty = 0, 1, 2, 3
|
||||
|
||||
|
||||
DYNAMIC_COLOR_CODES = {
|
||||
@ -1460,6 +1460,14 @@ class Window:
|
||||
def show_last_visited_command_output(self) -> None:
|
||||
self.show_cmd_output(CommandOutput.last_visited, 'Last visited command output')
|
||||
|
||||
@ac('cp', '''
|
||||
Show the last non-empty output from a shell command in a pager like less
|
||||
|
||||
Requires :ref:`shell_integration` to work
|
||||
''')
|
||||
def show_last_non_empty_command_output(self) -> None:
|
||||
self.show_cmd_output(CommandOutput.last_non_empty, 'Last non-empty command output')
|
||||
|
||||
@ac('cp', 'Paste the specified text into the current window')
|
||||
def paste(self, text: str) -> None:
|
||||
self.paste_with_actions(text)
|
||||
|
||||
@ -1009,9 +1009,9 @@ class TestScreen(BaseTest):
|
||||
self.assertTrue(s.scroll_to_prompt())
|
||||
self.ae(str(s.visual_line(0)), '$ 1')
|
||||
|
||||
def lco(as_ansi=False):
|
||||
def lco(as_ansi=False, which=0):
|
||||
a = []
|
||||
if s.cmd_output(0, a.append, as_ansi):
|
||||
if s.cmd_output(which, a.append, as_ansi):
|
||||
pht = pagerhist(s, as_ansi=as_ansi, upto_output_start=True)
|
||||
if pht:
|
||||
a.insert(0, pht)
|
||||
@ -1098,3 +1098,11 @@ class TestScreen(BaseTest):
|
||||
draw_prompt('p1')
|
||||
draw_output(30)
|
||||
self.ae(tuple(map(int, lco().split())), tuple(range(0, 30)))
|
||||
|
||||
# last non empty command output
|
||||
draw_prompt('a'), draw_output(2, 'a')
|
||||
draw_prompt('b'), mark_output()
|
||||
self.ae(lco(), '')
|
||||
self.ae(lco(which=3), '0a\n1a')
|
||||
s.draw('running'), s.index(), s.carriage_return()
|
||||
self.ae(lco(which=3), 'running\n')
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user