Merge branch 'scrollback-fill-enlarged-window' of https://github.com/elebow/kitty
This commit is contained in:
@@ -514,6 +514,10 @@ The current implementation stores the data in UTF-8, so approximatively
|
||||
10000 lines per megabyte at 100 chars per line, for pure ASCII text, unformatted text.
|
||||
A value of zero or less disables this feature. The maximum allowed size is 4GB.'''))
|
||||
|
||||
o('scrollback_fill_enlarged_window', False, long_text=_('''
|
||||
Fill new space with lines from the scrollback buffer after enlarging a window.
|
||||
'''))
|
||||
|
||||
o('wheel_scroll_multiplier', 5.0, long_text=_('''
|
||||
Modify the amount scrolled by the mouse wheel. Note this is only used for low
|
||||
precision scrolling devices, not for high precision scrolling on platforms such
|
||||
|
||||
@@ -252,6 +252,19 @@ historybuf_add_line(HistoryBuf *self, const Line *line, ANSIBuf *as_ansi_buf) {
|
||||
*attrptr(self, idx) = (line->continued & CONTINUED_MASK) | (line->has_dirty_text ? TEXT_DIRTY_MASK : 0);
|
||||
}
|
||||
|
||||
bool
|
||||
historybuf_pop_line(HistoryBuf *self, Line *line) {
|
||||
if (self->count <= 0)
|
||||
return false;
|
||||
|
||||
index_type idx = (self->start_of_data + self->count-1) % self->ynum;
|
||||
init_line(self, idx, line);
|
||||
|
||||
self->count--;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
line(HistoryBuf *self, PyObject *val) {
|
||||
#define line_doc "Return the line with line number val. This buffer grows upwards, i.e. 0 is the most recently added line"
|
||||
|
||||
@@ -326,6 +326,15 @@ is_continued(LineBuf *self, PyObject *val) {
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
linebuf_continued_lines_count(LineBuf *self, index_type stop_at_line) {
|
||||
unsigned int count = 0;
|
||||
for (unsigned int i = 0; i < self->ynum && i < stop_at_line; i++)
|
||||
if (self->line_attrs[i] & CONTINUED_MASK) count++;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void
|
||||
linebuf_insert_lines(LineBuf *self, unsigned int num, unsigned int y, unsigned int bottom) {
|
||||
index_type i;
|
||||
@@ -396,6 +405,13 @@ delete_lines(LineBuf *self, PyObject *args) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
linebuf_add_line_to_top(LineBuf *self, Line *line) {
|
||||
init_line(self, self->line, self->line_map[0]);
|
||||
copy_line(line, self->line);
|
||||
self->line_attrs[0] = TEXT_DIRTY_MASK | (line->continued ? CONTINUED_MASK : 0);
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
as_ansi(LineBuf *self, PyObject *callback) {
|
||||
#define as_ansi_doc "as_ansi(callback) -> The contents of this buffer as ANSI escaped text. callback is called with each successive line."
|
||||
|
||||
@@ -91,8 +91,10 @@ void linebuf_clear(LineBuf *, char_type ch);
|
||||
void linebuf_index(LineBuf* self, index_type top, index_type bottom);
|
||||
void linebuf_reverse_index(LineBuf *self, index_type top, index_type bottom);
|
||||
void linebuf_clear_line(LineBuf *self, index_type y);
|
||||
unsigned int linebuf_continued_lines_count(LineBuf *, index_type);
|
||||
void linebuf_insert_lines(LineBuf *self, unsigned int num, unsigned int y, unsigned int bottom);
|
||||
void linebuf_delete_lines(LineBuf *self, index_type num, index_type y, index_type bottom);
|
||||
void linebuf_add_line_to_top(LineBuf *, Line *);
|
||||
void linebuf_set_attribute(LineBuf *, unsigned int , unsigned int );
|
||||
void linebuf_rewrap(LineBuf *self, LineBuf *other, index_type *, index_type *, HistoryBuf *, index_type *, index_type *, ANSIBuf*);
|
||||
void linebuf_mark_line_dirty(LineBuf *self, index_type y);
|
||||
@@ -101,6 +103,7 @@ void linebuf_mark_line_as_not_continued(LineBuf *self, index_type y);
|
||||
unsigned int linebuf_char_width_at(LineBuf *self, index_type x, index_type y);
|
||||
void linebuf_refresh_sprite_positions(LineBuf *self);
|
||||
void historybuf_add_line(HistoryBuf *self, const Line *line, ANSIBuf*);
|
||||
bool historybuf_pop_line(HistoryBuf *, Line *);
|
||||
void historybuf_rewrap(HistoryBuf *self, HistoryBuf *other, ANSIBuf*);
|
||||
void historybuf_init_line(HistoryBuf *self, index_type num, Line *l);
|
||||
CPUCell* historybuf_cpu_cells(HistoryBuf *self, index_type num);
|
||||
|
||||
@@ -212,6 +212,15 @@ realloc_lb(LineBuf *old, unsigned int lines, unsigned int columns, index_type *n
|
||||
return ans;
|
||||
}
|
||||
|
||||
#define INDEX_GRAPHICS(amtv) { \
|
||||
bool is_main = self->linebuf == self->main_linebuf; \
|
||||
static ScrollData s; \
|
||||
s.amt = amtv; s.limit = is_main ? -self->historybuf->ynum : 0; \
|
||||
s.has_margins = self->margin_top != 0 || self->margin_bottom != self->lines - 1; \
|
||||
s.margin_top = top; s.margin_bottom = bottom; \
|
||||
grman_scroll_images(self->grman, &s, self->cell_size); \
|
||||
}
|
||||
|
||||
static bool
|
||||
screen_resize(Screen *self, unsigned int lines, unsigned int columns) {
|
||||
if (self->overlay_line.is_active) deactivate_overlay_line(self);
|
||||
@@ -236,6 +245,31 @@ screen_resize(Screen *self, unsigned int lines, unsigned int columns) {
|
||||
index_type x = self->cursor->x, y = self->cursor->y;
|
||||
LineBuf *n = realloc_lb(self->main_linebuf, lines, columns, &num_content_lines_before, &num_content_lines_after, self->historybuf, &x, &y, &self->as_ansi_buf);
|
||||
if (n == NULL) return false;
|
||||
|
||||
|
||||
if (OPT(scrollback_fill_enlarged_window)) {
|
||||
int lines_to_fill = (lines - self->main_linebuf->ynum) \
|
||||
+ (linebuf_continued_lines_count(self->main_linebuf, y) - linebuf_continued_lines_count(n, y));
|
||||
|
||||
while (lines_to_fill > 0) {
|
||||
if (self->historybuf->count <= 0) break;
|
||||
|
||||
unsigned int top = 0, bottom = lines-1;
|
||||
|
||||
linebuf_reverse_index(n, top, bottom);
|
||||
y++;
|
||||
INDEX_GRAPHICS(1);
|
||||
|
||||
Line last_history_line = {.xnum=self->historybuf->xnum};
|
||||
bool line_popped = historybuf_pop_line(self->historybuf, &last_history_line);
|
||||
if (!line_popped)
|
||||
break;
|
||||
linebuf_add_line_to_top(n, &last_history_line);
|
||||
|
||||
lines_to_fill--;
|
||||
}
|
||||
}
|
||||
|
||||
Py_CLEAR(self->main_linebuf); self->main_linebuf = n;
|
||||
if (is_main) setup_cursor();
|
||||
grman_resize(self->main_grman, self->lines, lines, self->columns, columns);
|
||||
@@ -1054,15 +1088,6 @@ index_selection(const Screen *self, Selections *selections, bool up) {
|
||||
}
|
||||
}
|
||||
|
||||
#define INDEX_GRAPHICS(amtv) { \
|
||||
bool is_main = self->linebuf == self->main_linebuf; \
|
||||
static ScrollData s; \
|
||||
s.amt = amtv; s.limit = is_main ? -self->historybuf->ynum : 0; \
|
||||
s.has_margins = self->margin_top != 0 || self->margin_bottom != self->lines - 1; \
|
||||
s.margin_top = top; s.margin_bottom = bottom; \
|
||||
grman_scroll_images(self->grman, &s, self->cell_size); \
|
||||
}
|
||||
|
||||
#define INDEX_UP \
|
||||
if (self->overlay_line.is_active) deactivate_overlay_line(self); \
|
||||
linebuf_index(self->linebuf, top, bottom); \
|
||||
|
||||
@@ -688,6 +688,7 @@ PYWRAP1(set_options) {
|
||||
S(dynamic_background_opacity, PyObject_IsTrue);
|
||||
S(inactive_text_alpha, PyFloat_AsFloat);
|
||||
S(scrollback_pager_history_size, PyLong_AsUnsignedLong);
|
||||
S(scrollback_fill_enlarged_window, PyObject_IsTrue);
|
||||
S(cursor_shape, PyLong_AsLong);
|
||||
S(cursor_beam_thickness, PyFloat_AsFloat);
|
||||
S(cursor_underline_thickness, PyFloat_AsFloat);
|
||||
|
||||
@@ -32,6 +32,7 @@ typedef struct {
|
||||
unsigned int terminal_select_modifiers;
|
||||
unsigned int url_style;
|
||||
unsigned int scrollback_pager_history_size;
|
||||
bool scrollback_fill_enlarged_window;
|
||||
char_type select_by_word_characters[256]; size_t select_by_word_characters_count;
|
||||
color_type url_color, background, foreground, active_border_color, inactive_border_color, bell_border_color;
|
||||
color_type mark1_foreground, mark1_background, mark2_foreground, mark2_background, mark3_foreground, mark3_background;
|
||||
|
||||
@@ -91,10 +91,15 @@ class BaseTest(TestCase):
|
||||
options = Options(merge_configs(defaults._asdict(), final_options))
|
||||
set_options(options)
|
||||
|
||||
def create_screen(self, cols=5, lines=5, scrollback=5, cell_width=10, cell_height=20, options=None):
|
||||
def create_screen(self, cols=5, lines=5, scrollback=5, cell_width=10, cell_height=20, options=None, content=tuple()):
|
||||
self.set_options(options)
|
||||
c = Callbacks()
|
||||
return Screen(c, lines, cols, scrollback, cell_width, cell_height, 0, c)
|
||||
s = Screen(c, lines, cols, scrollback, cell_width, cell_height, 0, c)
|
||||
for content_line in content:
|
||||
s.draw(content_line)
|
||||
s.linefeed()
|
||||
s.carriage_return()
|
||||
return s
|
||||
|
||||
def assertEqualAttributes(self, c1, c2):
|
||||
x1, y1, c1.x, c1.y = c1.x, c1.y, 0, 0
|
||||
|
||||
@@ -303,6 +303,48 @@ class TestScreen(BaseTest):
|
||||
s.resize(s.lines - 1, s.columns)
|
||||
self.ae(x_before, s.cursor.x)
|
||||
|
||||
def test_scrollback_fill_after_resize(self):
|
||||
def prepare_screen(content=tuple()):
|
||||
return self.create_screen(
|
||||
lines=5,
|
||||
cols=5,
|
||||
options={'scrollback_fill_enlarged_window': True},
|
||||
content=content,
|
||||
)
|
||||
|
||||
def assert_lines(lines, s):
|
||||
return self.ae(lines, str(s.linebuf).split("\n"))
|
||||
|
||||
# Height increased, width unchanged → pull down lines to fill new space at the top
|
||||
s = prepare_screen([str(i) for i in range(0, 6)])
|
||||
assert_lines(['2', '3', '4', '5', ''], s)
|
||||
s.resize(7, s.columns)
|
||||
assert_lines(['0', '1', '2', '3', '4', '5', ''], s)
|
||||
|
||||
# Height increased, width increased → rewrap, pull down
|
||||
s = prepare_screen(['0', '1', '2', '3' * 15])
|
||||
assert_lines(['2', '33333', '33333', '33333', ''], s)
|
||||
s.resize(7, 12)
|
||||
assert_lines(['0', '1', '2', '333333333333', '333', '', ''], s)
|
||||
|
||||
# Height increased, width decreased → rewrap, pull down if possible
|
||||
s = prepare_screen(['0', '1', '2', '3' * 5])
|
||||
assert_lines(['0', '1', '2', '33333', ''], s)
|
||||
s.resize(6, 4)
|
||||
assert_lines(['0', '1', '2', '3333', '3', ''], s)
|
||||
|
||||
# Height unchanged, width increased → rewrap, pull down if possible
|
||||
s = prepare_screen(['0', '1', '2', '3' * 15])
|
||||
assert_lines(['2', '33333', '33333', '33333', ''], s)
|
||||
s.resize(s.lines, 12)
|
||||
assert_lines(['1', '2', '333333333333', '333', ''], s)
|
||||
|
||||
# Height decreased, width increased → rewrap, pull down if possible
|
||||
s = prepare_screen(['0', '1', '2', '3' * 15])
|
||||
assert_lines(['2', '33333', '33333', '33333', ''], s)
|
||||
s.resize(4, 12)
|
||||
assert_lines(['2', '333333333333', '333', ''], s)
|
||||
|
||||
def test_tab_stops(self):
|
||||
# Taken from vttest/main.c
|
||||
s = self.create_screen(cols=80, lines=2)
|
||||
|
||||
Reference in New Issue
Block a user