Allows to open the command output in pager by mouse click
This commit is contained in:
parent
17a48f6b9f
commit
b91809eaa4
@ -74,29 +74,40 @@ on the output, define the following in :file:`kitty.conf`:
|
||||
|
||||
.. code:: conf
|
||||
|
||||
mouse_map right press ungrabbed mouse_select_command_output
|
||||
mouse_map right press ungrabbed mouse_select_command_output
|
||||
|
||||
Now, when you right click on the output, the entire output is selected, ready
|
||||
to be copied.
|
||||
|
||||
The feature to jump to previous prompts (
|
||||
:sc:`scroll_to_previous_prompt` and :sc:`scroll_to_next_prompt`) can be
|
||||
integrated with browsing command output as well. For example, define the
|
||||
:sc:`scroll_to_previous_prompt` and :sc:`scroll_to_next_prompt`) and mouse
|
||||
actions (``mouse_select_command_output`` and ``mouse_show_command_output``) can
|
||||
be integrated with browsing command output as well. For example, define the
|
||||
following mapping in :file:`kitty.conf`:
|
||||
|
||||
.. code:: conf
|
||||
|
||||
map f1 show_last_visited_command_output
|
||||
map f1 show_last_visited_command_output
|
||||
|
||||
Now, pressing :kbd:`F1` will cause the output of the last jumped to command to
|
||||
be opened in a pager for easy browsing.
|
||||
Now, pressing :kbd:`F1` will cause the output of the last jumped to command or
|
||||
the last mouse clicked command output to be opened in a pager for easy browsing.
|
||||
|
||||
In addition, You can define shortcut to get the first command output on screen.
|
||||
For example, define the following in :file:`kitty.conf`:
|
||||
|
||||
.. code:: conf
|
||||
|
||||
map f1 show_first_command_output_on_screen
|
||||
|
||||
Now, pressing :kbd:`F1` will cause the output of the first command output on
|
||||
screen to be opened in a pager.
|
||||
|
||||
You can also add shortcut to scroll to the last jumped position. For example,
|
||||
define the following in :file:`kitty.conf`:
|
||||
|
||||
.. code:: conf
|
||||
|
||||
map f1 scroll_to_prompt 0
|
||||
map f1 scroll_to_prompt 0
|
||||
|
||||
|
||||
How it works
|
||||
@ -110,9 +121,9 @@ different shells.
|
||||
|
||||
.. tab:: bash/zsh
|
||||
|
||||
For these shells, kitty adds a couple of lines to
|
||||
the bottom of the shell's rc files (in an atomic manner) to load the shell
|
||||
integration code.
|
||||
For these shells, kitty adds a couple of lines to
|
||||
the bottom of the shell's rc files (in an atomic manner) to load the shell
|
||||
integration code.
|
||||
|
||||
.. tab:: fish
|
||||
|
||||
|
||||
@ -1272,7 +1272,7 @@ def set_window_padding(os_window_id: int, tab_id: int, window_id: int, left: int
|
||||
def click_mouse_url(os_window_id: int, tab_id: int, window_id: int) -> bool:
|
||||
pass
|
||||
|
||||
def click_mouse_cmd_output(os_window_id: int, tab_id: int, window_id: int) -> bool:
|
||||
def click_mouse_cmd_output(os_window_id: int, tab_id: int, window_id: int, select_cmd_output: bool) -> bool:
|
||||
pass
|
||||
|
||||
def move_cursor_to_mouse_if_in_prompt(os_window_id: int, tab_id: int, window_id: int) -> bool:
|
||||
|
||||
@ -424,6 +424,12 @@ mouse_open_url(Window *w) {
|
||||
return screen_open_url(screen);
|
||||
}
|
||||
|
||||
bool
|
||||
mouse_set_last_visited_cmd_output(Window *w) {
|
||||
Screen *screen = w->render_data.screen;
|
||||
return screen_set_last_visited_prompt(screen, w->mouse_pos.cell_y);
|
||||
}
|
||||
|
||||
bool
|
||||
mouse_select_cmd_output(Window *w) {
|
||||
Screen *screen = w->render_data.screen;
|
||||
|
||||
@ -616,6 +616,13 @@ mma('Select line from point even when grabbed',
|
||||
mma('Extend the current selection even when grabbed',
|
||||
'extend_selection_grabbed shift+right press ungrabbed,grabbed mouse_selection extend',
|
||||
)
|
||||
|
||||
mma('Show clicked command output in pager',
|
||||
'show_clicked_cmd_output_ungrabbed ctrl+shift+right press ungrabbed mouse_show_command_output',
|
||||
long_text='''
|
||||
Requires :ref:`shell_integration` to work.
|
||||
'''
|
||||
)
|
||||
egr() # }}}
|
||||
egr() # }}}
|
||||
|
||||
@ -3006,11 +3013,14 @@ Requires :ref:`shell_integration` to work.
|
||||
map('Scroll to next shell prompt',
|
||||
'scroll_to_next_prompt kitty_mod+x scroll_to_prompt 1',
|
||||
long_text='''
|
||||
When the parameter is zero, scroll to the last jumped position, or the last clicked position by
|
||||
command output related mouse actions.
|
||||
|
||||
Requires :ref:`shell_integration` to work.
|
||||
'''
|
||||
)
|
||||
|
||||
map('Browse scrollback buffer in less',
|
||||
map('Browse scrollback buffer in pager',
|
||||
'show_scrollback kitty_mod+h show_scrollback',
|
||||
long_text='''
|
||||
You can pipe the contents of the current screen + history buffer as
|
||||
@ -3024,17 +3034,27 @@ see :doc:`launch`.
|
||||
'''
|
||||
)
|
||||
|
||||
map('Browse output of the last shell command in less',
|
||||
map('Browse output of the last shell command in pager',
|
||||
'show_last_command_output kitty_mod+g show_last_command_output',
|
||||
long_text='''
|
||||
Requires :ref:`shell_integration` to work. You can pipe the output
|
||||
of the last command run in the shell using the :doc:`launch` function.
|
||||
You can also define additional shortcuts to get the command output.
|
||||
For example, to get the first command output on screen::
|
||||
|
||||
map f1 show_first_command_output_on_screen
|
||||
|
||||
To get the command output that was last accessed by a keyboard action or mouse action::
|
||||
|
||||
map f1 show_last_visited_command_output
|
||||
|
||||
You can pipe the output of the last command run in the shell using the :doc:`launch` function.
|
||||
For example, the following opens the output in less in an overlay window::
|
||||
|
||||
map f1 launch --stdin-source=@last_cmd_output --stdin-add-formatting --type=overlay less +G -R
|
||||
|
||||
To get the output of the first command on the screen, use :code:`@first_cmd_output_on_screen`.
|
||||
To get the output of the last jumped to command, use :code:`@last_visited_cmd_output`.
|
||||
|
||||
Requires :ref:`shell_integration` to work.
|
||||
''')
|
||||
egr() # }}}
|
||||
|
||||
|
||||
2
kitty/options/types.py
generated
2
kitty/options/types.py
generated
@ -951,4 +951,6 @@ defaults.mouse_map = [
|
||||
MouseMapping(1, 1, 1, True, KeyAction('mouse_selection', (1,))),
|
||||
# extend_selection_grabbed
|
||||
MouseMapping(1, 1, 1, False, KeyAction('mouse_selection', (1,))),
|
||||
# show_clicked_cmd_output_ungrabbed
|
||||
MouseMapping(1, 5, 1, False, KeyAction('mouse_show_command_output')),
|
||||
]
|
||||
|
||||
@ -1269,7 +1269,7 @@ screen_cursor_to_column(Screen *self, unsigned int column) {
|
||||
linebuf_init_line(self->linebuf, bottom); \
|
||||
historybuf_add_line(self->historybuf, self->linebuf->line, &self->as_ansi_buf); \
|
||||
self->history_line_added_count++; \
|
||||
if (self->last_visited_prompt.is_set && self->last_visited_prompt.scrolled_by < self->historybuf->count) self->last_visited_prompt.scrolled_by++; \
|
||||
if (self->last_visited_prompt.is_set && self->last_visited_prompt.scrolled_by <= self->historybuf->count) self->last_visited_prompt.scrolled_by++; \
|
||||
} \
|
||||
linebuf_clear_line(self->linebuf, bottom, true); \
|
||||
self->is_dirty = true; \
|
||||
@ -2024,7 +2024,7 @@ screen_history_scroll_to_prompt(Screen *self, int num_of_prompts_to_jump) {
|
||||
if (self->linebuf != self->main_linebuf) return false;
|
||||
unsigned int old = self->scrolled_by;
|
||||
if (num_of_prompts_to_jump == 0) {
|
||||
if (!self->last_visited_prompt.is_set || self->last_visited_prompt.scrolled_by > self->historybuf->count) return false;
|
||||
if (!self->last_visited_prompt.is_set || self->last_visited_prompt.scrolled_by > self->historybuf->count || self->last_visited_prompt.y >= self->lines) return false;
|
||||
self->scrolled_by = self->last_visited_prompt.scrolled_by;
|
||||
} else {
|
||||
int delta = num_of_prompts_to_jump < 0 ? -1 : 1;
|
||||
@ -2041,8 +2041,7 @@ screen_history_scroll_to_prompt(Screen *self, int num_of_prompts_to_jump) {
|
||||
}
|
||||
#undef ensure_y_ok
|
||||
self->scrolled_by = y >= 0 ? 0 : -y;
|
||||
self->last_visited_prompt.scrolled_by = self->scrolled_by;
|
||||
self->last_visited_prompt.is_set = true;
|
||||
screen_set_last_visited_prompt(self, 0);
|
||||
}
|
||||
if (old != self->scrolled_by) self->scroll_changed = true;
|
||||
return old != self->scrolled_by;
|
||||
@ -2756,7 +2755,7 @@ cmd_output(Screen *self, PyObject *args) {
|
||||
break;
|
||||
case 2: // last visited cmd
|
||||
if (self->last_visited_prompt.scrolled_by <= self->historybuf->count && self->last_visited_prompt.is_set) {
|
||||
found = find_cmd_output(self, &oo, 0, self->last_visited_prompt.scrolled_by, 0, false);
|
||||
found = find_cmd_output(self, &oo, self->last_visited_prompt.y, self->last_visited_prompt.scrolled_by, 0, false);
|
||||
} break;
|
||||
default:
|
||||
PyErr_Format(PyExc_KeyError, "%u is not a valid type of command", which);
|
||||
@ -2766,6 +2765,15 @@ cmd_output(Screen *self, PyObject *args) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
bool
|
||||
screen_set_last_visited_prompt(Screen *self, index_type y) {
|
||||
if (y >= self->lines) return false;
|
||||
self->last_visited_prompt.scrolled_by = self->scrolled_by;
|
||||
self->last_visited_prompt.y = y;
|
||||
self->last_visited_prompt.is_set = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
screen_select_cmd_output(Screen *self, index_type y) {
|
||||
if (y >= self->lines) return false;
|
||||
|
||||
@ -146,6 +146,7 @@ typedef struct {
|
||||
} last_rendered_window_char;
|
||||
struct {
|
||||
unsigned int scrolled_by;
|
||||
index_type y;
|
||||
bool is_set;
|
||||
} last_visited_prompt;
|
||||
} Screen;
|
||||
@ -246,6 +247,7 @@ void set_active_hyperlink(Screen*, char*, char*);
|
||||
hyperlink_id_type screen_mark_hyperlink(Screen*, index_type, index_type);
|
||||
void screen_handle_graphics_command(Screen *self, const GraphicsCommand *cmd, const uint8_t *payload);
|
||||
bool screen_open_url(Screen*);
|
||||
bool screen_set_last_visited_prompt(Screen*, index_type);
|
||||
bool screen_select_cmd_output(Screen*, index_type);
|
||||
void screen_dirty_sprite_positions(Screen *self);
|
||||
void screen_rescale_images(Screen *self);
|
||||
|
||||
@ -1091,12 +1091,13 @@ click_mouse_url(id_type os_window_id, id_type tab_id, id_type window_id) {
|
||||
}
|
||||
|
||||
static bool
|
||||
click_mouse_cmd_output(id_type os_window_id, id_type tab_id, id_type window_id) {
|
||||
bool selected = false;
|
||||
click_mouse_cmd_output(id_type os_window_id, id_type tab_id, id_type window_id, int select_cmd_output) {
|
||||
bool handled = false;
|
||||
WITH_WINDOW(os_window_id, tab_id, window_id);
|
||||
selected = mouse_select_cmd_output(window);
|
||||
handled = mouse_set_last_visited_cmd_output(window);
|
||||
if (select_cmd_output && handled) handled = mouse_select_cmd_output(window);
|
||||
END_WITH_WINDOW;
|
||||
return selected;
|
||||
return handled;
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -1127,8 +1128,8 @@ PYWRAP1(click_mouse_url) {
|
||||
}
|
||||
|
||||
PYWRAP1(click_mouse_cmd_output) {
|
||||
id_type a, b, c; PA("KKK", &a, &b, &c);
|
||||
if (click_mouse_cmd_output(a, b, c)) { Py_RETURN_TRUE; }
|
||||
id_type a, b, c; int d; PA("KKKp", &a, &b, &c, &d);
|
||||
if (click_mouse_cmd_output(a, b, c, d)) { Py_RETURN_TRUE; }
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
|
||||
@ -311,6 +311,7 @@ void update_os_window_title(OSWindow *os_window);
|
||||
void fake_scroll(Window *w, int amount, bool upwards);
|
||||
Window* window_for_window_id(id_type kitty_window_id);
|
||||
bool mouse_open_url(Window *w);
|
||||
bool mouse_set_last_visited_cmd_output(Window *w);
|
||||
bool mouse_select_cmd_output(Window *w);
|
||||
bool move_cursor_to_mouse_if_at_shell_prompt(Window *w);
|
||||
void mouse_selection(Window *w, int code, int button);
|
||||
|
||||
@ -1014,8 +1014,17 @@ class Window:
|
||||
|
||||
Requires :ref:`shell_integration` to work
|
||||
''')
|
||||
def mouse_select_cmd_output(self) -> None:
|
||||
click_mouse_cmd_output(self.os_window_id, self.tab_id, self.id)
|
||||
def mouse_select_command_output(self) -> None:
|
||||
click_mouse_cmd_output(self.os_window_id, self.tab_id, self.id, True)
|
||||
|
||||
@ac('mouse', '''
|
||||
Show clicked command output in a pager like less
|
||||
|
||||
Requires :ref:`shell_integration` to work
|
||||
''')
|
||||
def mouse_show_command_output(self) -> None:
|
||||
if click_mouse_cmd_output(self.os_window_id, self.tab_id, self.id, False):
|
||||
self.show_cmd_output(CommandOutput.last_visited, 'Clicked command output')
|
||||
# }}}
|
||||
|
||||
def text_for_selection(self) -> str:
|
||||
@ -1087,15 +1096,18 @@ class Window:
|
||||
cursor_on_screen = self.screen.scrolled_by < self.screen.lines - self.screen.cursor.y
|
||||
get_boss().display_scrollback(self, data['text'], data['input_line_number'], report_cursor=cursor_on_screen)
|
||||
|
||||
def show_cmd_output(self, which: CommandOutput, title: str = 'Command ouptut', as_ansi: bool = True, add_wrap_markers: bool = True) -> None:
|
||||
text = self.cmd_output(which, as_ansi=as_ansi, add_wrap_markers=add_wrap_markers)
|
||||
text = text.replace('\r\n', '\n').replace('\r', '\n')
|
||||
get_boss().display_scrollback(self, text, title=title, report_cursor=False)
|
||||
|
||||
@ac('cp', '''
|
||||
Show output from the first shell command on screen in a pager like less
|
||||
|
||||
Requires :ref:`shell_integration` to work
|
||||
''')
|
||||
def show_first_command_output_on_screen(self) -> None:
|
||||
text = self.cmd_output(CommandOutput.first_on_screen, as_ansi=True, add_wrap_markers=True)
|
||||
text = text.replace('\r\n', '\n').replace('\r', '\n')
|
||||
get_boss().display_scrollback(self, text, title='First command output on screen', report_cursor=False)
|
||||
self.show_cmd_output(CommandOutput.first_on_screen, 'First command output on screen')
|
||||
|
||||
@ac('cp', '''
|
||||
Show output from the last shell command in a pager like less
|
||||
@ -1103,19 +1115,16 @@ class Window:
|
||||
Requires :ref:`shell_integration` to work
|
||||
''')
|
||||
def show_last_command_output(self) -> None:
|
||||
text = self.cmd_output(CommandOutput.last_run, as_ansi=True, add_wrap_markers=True)
|
||||
text = text.replace('\r\n', '\n').replace('\r', '\n')
|
||||
get_boss().display_scrollback(self, text, title='Last command output', report_cursor=False)
|
||||
self.show_cmd_output(CommandOutput.last_run, 'Last command output')
|
||||
|
||||
@ac('cp', '''
|
||||
Show the first output below the last scrolled position via scroll_to_prompt in a pager like less
|
||||
Show the first command output below the last scrolled position via scroll_to_prompt
|
||||
or the last mouse clicked command output in a pager like less
|
||||
|
||||
Requires :ref:`shell_integration` to work
|
||||
''')
|
||||
def show_last_visited_command_output(self) -> None:
|
||||
text = self.cmd_output(CommandOutput.last_visited, as_ansi=True, add_wrap_markers=True)
|
||||
text = text.replace('\r\n', '\n').replace('\r', '\n')
|
||||
get_boss().display_scrollback(self, text, title='Last visited command output', report_cursor=False)
|
||||
self.show_cmd_output(CommandOutput.last_visited, 'Last visited command output')
|
||||
|
||||
def paste_bytes(self, text: Union[str, bytes]) -> None:
|
||||
# paste raw bytes without any processing
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user