mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-26 02:02:14 +02:00
Cleanup clear to prompt implementation and allow moving cleared lies into scrollback
This commit is contained in:
@@ -72,6 +72,9 @@ Detailed list of changes
|
|||||||
|
|
||||||
- icat kitten: Add a command line argument to override terminal window size detection (:iss:`7165`)
|
- icat kitten: Add a command line argument to override terminal window size detection (:iss:`7165`)
|
||||||
|
|
||||||
|
- When :ac:`clearing terminal <clear_terminal>` add a new type ``to_cursor_scroll`` which can be
|
||||||
|
used to clear to prompt while moving cleared lines into the scrollback
|
||||||
|
|
||||||
|
|
||||||
0.32.2 [2024-02-12]
|
0.32.2 [2024-02-12]
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|||||||
@@ -1170,8 +1170,11 @@ class Boss:
|
|||||||
map f1 clear_terminal scrollback active
|
map f1 clear_terminal scrollback active
|
||||||
# Scroll the contents of the screen into the scrollback
|
# Scroll the contents of the screen into the scrollback
|
||||||
map f1 clear_terminal scroll active
|
map f1 clear_terminal scroll active
|
||||||
# Clear everything up to the line with the cursor
|
# Clear everything up to the line with the cursor or if the cursor is at a prompt, the first line of the prompt.
|
||||||
|
# Useful for clearing the screen up to the shell prompt and moving the shell prompt to the top of the screen.
|
||||||
map f1 clear_terminal to_cursor active
|
map f1 clear_terminal to_cursor active
|
||||||
|
# Clear everything up to the line with the cursor or prompt, saving the cleared lines in the scrollback
|
||||||
|
map f1 clear_terminal to_cursor_scroll active
|
||||||
''')
|
''')
|
||||||
def clear_terminal(self, action: str, only_active: bool) -> None:
|
def clear_terminal(self, action: str, only_active: bool) -> None:
|
||||||
if only_active:
|
if only_active:
|
||||||
@@ -1196,6 +1199,11 @@ class Boss:
|
|||||||
elif action == 'to_cursor':
|
elif action == 'to_cursor':
|
||||||
for w in windows:
|
for w in windows:
|
||||||
w.scroll_prompt_to_top(clear_scrollback=True)
|
w.scroll_prompt_to_top(clear_scrollback=True)
|
||||||
|
elif action == 'to_cursor_scroll':
|
||||||
|
for w in windows:
|
||||||
|
w.scroll_prompt_to_top(clear_scrollback=False)
|
||||||
|
else:
|
||||||
|
self.show_error(_('Unknown clear type'), _('The clear type: {} is unknown').format(action))
|
||||||
|
|
||||||
def increase_font_size(self) -> None: # legacy
|
def increase_font_size(self) -> None: # legacy
|
||||||
cfs = global_font_size()
|
cfs = global_font_size()
|
||||||
|
|||||||
@@ -1171,7 +1171,7 @@ class Screen:
|
|||||||
def cmd_output(self, which: int, callback: Callable[[str], None], as_ansi: bool, insert_wrap_markers: bool) -> bool:
|
def cmd_output(self, which: int, callback: Callable[[str], None], as_ansi: bool, insert_wrap_markers: bool) -> bool:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def scroll_until_cursor_prompt(self) -> None:
|
def scroll_until_cursor_prompt(self, add_to_scrollback: bool = True) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def reset(self) -> None:
|
def reset(self) -> None:
|
||||||
|
|||||||
@@ -93,6 +93,11 @@ def parse_send_text_bytes(text: str) -> bytes:
|
|||||||
return defines.expand_ansi_c_escapes(text).encode('utf-8')
|
return defines.expand_ansi_c_escapes(text).encode('utf-8')
|
||||||
|
|
||||||
|
|
||||||
|
@func_with_args('scroll_prompt_to_top')
|
||||||
|
def scroll_prompt_to_top(func: str, rest: str) -> FuncArgsType:
|
||||||
|
return func, [to_bool(rest) if rest else False]
|
||||||
|
|
||||||
|
|
||||||
@func_with_args('send_text')
|
@func_with_args('send_text')
|
||||||
def send_text_parse(func: str, rest: str) -> FuncArgsType:
|
def send_text_parse(func: str, rest: str) -> FuncArgsType:
|
||||||
args = rest.split(maxsplit=1)
|
args = rest.split(maxsplit=1)
|
||||||
@@ -211,7 +216,7 @@ def clear_terminal(func: str, rest: str) -> FuncArgsType:
|
|||||||
args = ['reset', True]
|
args = ['reset', True]
|
||||||
else:
|
else:
|
||||||
action = vals[0].lower()
|
action = vals[0].lower()
|
||||||
if action not in ('reset', 'scroll', 'scrollback', 'clear', 'to_cursor',):
|
if action not in ('reset', 'scroll', 'scrollback', 'clear', 'to_cursor', 'to_cursor_scroll'):
|
||||||
log_error(f'{action} is unknown for clear_terminal, using reset')
|
log_error(f'{action} is unknown for clear_terminal, using reset')
|
||||||
action = 'reset'
|
action = 'reset'
|
||||||
args = [action, vals[1].lower() == 'active']
|
args = [action, vals[1].lower() == 'active']
|
||||||
|
|||||||
@@ -1503,10 +1503,10 @@ screen_cursor_to_column(Screen *self, unsigned int column) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define INDEX_UP \
|
#define INDEX_UP(add_to_history) \
|
||||||
linebuf_index(self->linebuf, top, bottom); \
|
linebuf_index(self->linebuf, top, bottom); \
|
||||||
INDEX_GRAPHICS(-1) \
|
INDEX_GRAPHICS(-1) \
|
||||||
if (self->linebuf == self->main_linebuf && self->margin_top == 0) { \
|
if (add_to_history) { \
|
||||||
/* Only add to history when no top margin has been set */ \
|
/* Only add to history when no top margin has been set */ \
|
||||||
linebuf_init_line(self->linebuf, bottom); \
|
linebuf_init_line(self->linebuf, bottom); \
|
||||||
historybuf_add_line(self->historybuf, self->linebuf->line, &self->as_ansi_buf); \
|
historybuf_add_line(self->historybuf, self->linebuf->line, &self->as_ansi_buf); \
|
||||||
@@ -1525,17 +1525,29 @@ screen_index(Screen *self) {
|
|||||||
// Move cursor down one line, scrolling screen if needed
|
// Move cursor down one line, scrolling screen if needed
|
||||||
unsigned int top = self->margin_top, bottom = self->margin_bottom;
|
unsigned int top = self->margin_top, bottom = self->margin_bottom;
|
||||||
if (self->cursor->y == bottom) {
|
if (self->cursor->y == bottom) {
|
||||||
INDEX_UP;
|
const bool add_to_history = self->linebuf == self->main_linebuf && self->margin_top == 0;
|
||||||
|
INDEX_UP(add_to_history);
|
||||||
} else screen_cursor_down(self, 1);
|
} else screen_cursor_down(self, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
screen_index_without_adding_to_history(Screen *self) {
|
||||||
|
// Move cursor down one line, scrolling screen if needed
|
||||||
|
unsigned int top = self->margin_top, bottom = self->margin_bottom;
|
||||||
|
if (self->cursor->y == bottom) {
|
||||||
|
INDEX_UP(false);
|
||||||
|
} else screen_cursor_down(self, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
screen_scroll(Screen *self, unsigned int count) {
|
screen_scroll(Screen *self, unsigned int count) {
|
||||||
// Scroll the screen up by count lines, not moving the cursor
|
// Scroll the screen up by count lines, not moving the cursor
|
||||||
unsigned int top = self->margin_top, bottom = self->margin_bottom;
|
unsigned int top = self->margin_top, bottom = self->margin_bottom;
|
||||||
|
const bool add_to_history = self->linebuf == self->main_linebuf && self->margin_top == 0;
|
||||||
while (count > 0) {
|
while (count > 0) {
|
||||||
count--;
|
count--;
|
||||||
INDEX_UP;
|
INDEX_UP(add_to_history);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1868,9 +1880,10 @@ screen_move_into_scrollback(Screen *self) {
|
|||||||
}
|
}
|
||||||
if (num_of_lines_to_move) {
|
if (num_of_lines_to_move) {
|
||||||
unsigned int top, bottom;
|
unsigned int top, bottom;
|
||||||
|
const bool add_to_history = self->linebuf == self->main_linebuf && self->margin_top == 0;
|
||||||
for (; num_of_lines_to_move; num_of_lines_to_move--) {
|
for (; num_of_lines_to_move; num_of_lines_to_move--) {
|
||||||
top = 0, bottom = num_of_lines_to_move - 1;
|
top = 0, bottom = num_of_lines_to_move - 1;
|
||||||
INDEX_UP
|
INDEX_UP(add_to_history);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1945,14 +1958,15 @@ screen_insert_lines(Screen *self, unsigned int count) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
screen_scroll_until_cursor_prompt(Screen *self) {
|
screen_scroll_until_cursor_prompt(Screen *self, bool add_to_scrollback) {
|
||||||
bool in_margins = cursor_within_margins(self);
|
bool in_margins = cursor_within_margins(self);
|
||||||
int q = screen_cursor_at_a_shell_prompt(self);
|
int q = screen_cursor_at_a_shell_prompt(self);
|
||||||
unsigned int y = q > -1 ? (unsigned int)q : self->cursor->y;
|
unsigned int y = q > -1 ? (unsigned int)q : self->cursor->y;
|
||||||
unsigned int num_lines_to_scroll = MIN(self->margin_bottom, y);
|
unsigned int num_lines_to_scroll = MIN(self->margin_bottom, y);
|
||||||
unsigned int final_y = num_lines_to_scroll <= self->cursor->y ? self->cursor->y - num_lines_to_scroll : 0;
|
unsigned int final_y = num_lines_to_scroll <= self->cursor->y ? self->cursor->y - num_lines_to_scroll : 0;
|
||||||
self->cursor->y = self->margin_bottom;
|
self->cursor->y = self->margin_bottom;
|
||||||
while (num_lines_to_scroll--) screen_index(self);
|
if (add_to_scrollback) while (num_lines_to_scroll--) screen_index(self);
|
||||||
|
else while (num_lines_to_scroll--) screen_index_without_adding_to_history(self);
|
||||||
self->cursor->y = final_y;
|
self->cursor->y = final_y;
|
||||||
screen_ensure_bounds(self, false, in_margins);
|
screen_ensure_bounds(self, false, in_margins);
|
||||||
}
|
}
|
||||||
@@ -3751,7 +3765,8 @@ is_using_alternate_linebuf(Screen *self, PyObject *a UNUSED) {
|
|||||||
WRAP1E(cursor_back, 1, -1)
|
WRAP1E(cursor_back, 1, -1)
|
||||||
WRAP1B(erase_in_line, 0)
|
WRAP1B(erase_in_line, 0)
|
||||||
WRAP1B(erase_in_display, 0)
|
WRAP1B(erase_in_display, 0)
|
||||||
WRAP0(scroll_until_cursor_prompt)
|
static PyObject* scroll_until_cursor_prompt(Screen *self, PyObject *args) { int b=false; if(!PyArg_ParseTuple(args, "|p", &b)) return NULL; screen_scroll_until_cursor_prompt(self, b); Py_RETURN_NONE; }
|
||||||
|
|
||||||
WRAP0(clear_scrollback)
|
WRAP0(clear_scrollback)
|
||||||
|
|
||||||
#define MODE_GETSET(name, uname) \
|
#define MODE_GETSET(name, uname) \
|
||||||
@@ -4699,7 +4714,7 @@ static PyMethodDef methods[] = {
|
|||||||
MND(erase_in_line, METH_VARARGS)
|
MND(erase_in_line, METH_VARARGS)
|
||||||
MND(erase_in_display, METH_VARARGS)
|
MND(erase_in_display, METH_VARARGS)
|
||||||
MND(clear_scrollback, METH_NOARGS)
|
MND(clear_scrollback, METH_NOARGS)
|
||||||
MND(scroll_until_cursor_prompt, METH_NOARGS)
|
MND(scroll_until_cursor_prompt, METH_VARARGS)
|
||||||
MND(hyperlinks_as_list, METH_NOARGS)
|
MND(hyperlinks_as_list, METH_NOARGS)
|
||||||
MND(garbage_collect_hyperlink_pool, METH_NOARGS)
|
MND(garbage_collect_hyperlink_pool, METH_NOARGS)
|
||||||
MND(hyperlink_for_id, METH_O)
|
MND(hyperlink_for_id, METH_O)
|
||||||
|
|||||||
@@ -1821,14 +1821,13 @@ class Window:
|
|||||||
return None
|
return None
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ac('sc', 'Scroll prompt to the top of the screen, filling screen with empty lines, when in main screen')
|
@ac('sc', 'Scroll prompt to the top of the screen, filling screen with empty lines, when in main screen.'
|
||||||
|
' To avoid putting the lines above the prompt into the scrollback use scroll_prompt_to_top y')
|
||||||
def scroll_prompt_to_top(self, clear_scrollback: bool = False) -> Optional[bool]:
|
def scroll_prompt_to_top(self, clear_scrollback: bool = False) -> Optional[bool]:
|
||||||
if self.screen.is_main_linebuf():
|
if self.screen.is_main_linebuf():
|
||||||
self.screen.scroll_until_cursor_prompt()
|
self.screen.scroll_until_cursor_prompt(not clear_scrollback)
|
||||||
if clear_scrollback:
|
if self.screen.scrolled_by > 0:
|
||||||
self.screen.clear_scrollback()
|
self.scroll_end()
|
||||||
elif self.screen.scrolled_by > 0:
|
|
||||||
self.screen.scroll(SCROLL_FULL, False)
|
|
||||||
return None
|
return None
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user