From 3b8da7e4c2e71fa60854632f77d0b7d378262ede Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 13 Jul 2021 11:52:24 +0530 Subject: [PATCH] implementation of scroll_to_prompt --- kitty/screen.c | 30 ++++++++++++++++++++++++++++++ kitty_tests/screen.py | 23 +++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/kitty/screen.c b/kitty/screen.c index 8bfc74ecf..ca14de667 100644 --- a/kitty/screen.c +++ b/kitty/screen.c @@ -1729,6 +1729,26 @@ shell_prompt_marking(Screen *self, PyObject *data) { } } +static bool +screen_history_scroll_to_prompt(Screen *self, int num_of_prompts_to_jump) { + if (self->linebuf != self->main_linebuf) return false; + int delta = num_of_prompts_to_jump < 0 ? -1 : 1; + num_of_prompts_to_jump = num_of_prompts_to_jump < 0 ? -num_of_prompts_to_jump : num_of_prompts_to_jump; + int y = -self->scrolled_by; + while (num_of_prompts_to_jump) { + y += delta; + if (y >= (int)self->lines || -y > (int)self->historybuf->count) return false; + if (range_line_(self, y)->is_prompt_start) num_of_prompts_to_jump--; + } + if (delta < 0) { + while (-y + 1 < (int)self->historybuf->count && range_line_(self, y - 1)->is_prompt_start) y--; + } + unsigned int old = self->scrolled_by; + self->scrolled_by = y >= 0 ? 0 : -y; + if (old != self->scrolled_by) self->scroll_changed = true; + return old != self->scrolled_by; +} + void set_color_table_color(Screen *self, unsigned int code, PyObject *color) { if (color == NULL) { CALLBACK("set_color_table_color", "Is", code, ""); } @@ -2707,6 +2727,15 @@ scroll(Screen *self, PyObject *args) { Py_RETURN_FALSE; } +static PyObject* +scroll_to_prompt(Screen *self, PyObject *args) { + int num_of_prompts = -1; + if (!PyArg_ParseTuple(args, "|i", &num_of_prompts)) return NULL; + if (screen_history_scroll_to_prompt(self, num_of_prompts)) { Py_RETURN_TRUE; } + Py_RETURN_FALSE; +} + + bool screen_is_selection_dirty(Screen *self) { IterationData q; @@ -3237,6 +3266,7 @@ static PyMethodDef methods[] = { MND(text_for_marked_url, METH_NOARGS) MND(is_rectangle_select, METH_NOARGS) MND(scroll, METH_VARARGS) + MND(scroll_to_prompt, METH_VARARGS) MND(send_escape_code_to_child, METH_VARARGS) MND(hyperlink_at, METH_VARARGS) MND(toggle_alt_screen, METH_NOARGS) diff --git a/kitty_tests/screen.py b/kitty_tests/screen.py index 9b50be280..5b807616b 100644 --- a/kitty_tests/screen.py +++ b/kitty_tests/screen.py @@ -912,3 +912,26 @@ class TestScreen(BaseTest): for trailer in '{([': t('http://moo.com', after=trailer) t('http://moo.com', x=s.columns - 9) + + def test_prompt_marking(self): + s = self.create_screen() + + def mark_prompt(): + parse_bytes(s, '\033]133;A\007'.encode('ascii')) + + for i in range(4): + mark_prompt() + s.draw(f'$ {i}') + s.carriage_return() + s.index(), s.index() + self.ae(s.scrolled_by, 0) + self.assertTrue(s.scroll_to_prompt()) + self.ae(str(s.visual_line(0)), '$ 1') + self.assertTrue(s.scroll_to_prompt()) + self.ae(str(s.visual_line(0)), '$ 0') + self.assertFalse(s.scroll_to_prompt()) + self.assertTrue(s.scroll_to_prompt(1)) + self.ae(str(s.visual_line(0)), '$ 1') + self.assertTrue(s.scroll_to_prompt(1)) + self.ae(str(s.visual_line(0)), '$ 2') + self.assertFalse(s.scroll_to_prompt(1))