Dont reflow the current prompt when resizing

This ensures that there is no leftover line when the shell redraws the prompt,
by making the prompt a simple single character prompt before rewrapping.
This commit is contained in:
Kovid Goyal 2021-07-14 17:15:53 +05:30
parent f2ca0424a0
commit 196200d03f
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
4 changed files with 41 additions and 7 deletions

View file

@ -266,11 +266,11 @@ clear_line_(Line *l, index_type xnum) {
}
void
linebuf_clear_line(LineBuf *self, index_type y) {
linebuf_clear_line(LineBuf *self, index_type y, bool clear_attrs) {
Line l;
init_line(self, &l, self->line_map[y]);
clear_line_(&l, self->xnum);
self->line_attrs[y] = 0;
if (clear_attrs) self->line_attrs[y] = 0;
}
static PyObject*
@ -278,7 +278,7 @@ clear_line(LineBuf *self, PyObject *val) {
#define clear_line_doc "clear_line(y) -> Clear the specified line"
index_type y = (index_type)PyLong_AsUnsignedLong(val);
if (y >= self->ynum) { PyErr_SetString(PyExc_ValueError, "Out of bounds"); return NULL; }
linebuf_clear_line(self, y);
linebuf_clear_line(self, y, true);
Py_RETURN_NONE;
}

View file

@ -106,7 +106,7 @@ void linebuf_init_line(LineBuf *, index_type);
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);
void linebuf_clear_line(LineBuf *self, index_type y, bool clear_attrs);
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_copy_line_to(LineBuf *, Line *, index_type);

View file

@ -34,7 +34,7 @@
dest->line->has_dirty_text = true; \
historybuf_add_line(historybuf, dest->line, as_ansi_buf); \
}\
linebuf_clear_line(dest, dest->ynum - 1); \
linebuf_clear_line(dest, dest->ynum - 1, true); \
} else dest_y++; \
init_dest_line(dest_y); \
set_dest_line_attrs(dest_y, continued);

View file

@ -271,11 +271,44 @@ index_selection(const Screen *self, Selections *selections, bool up) {
#define INDEX_DOWN \
if (self->overlay_line.is_active) deactivate_overlay_line(self); \
linebuf_reverse_index(self->linebuf, top, bottom); \
linebuf_clear_line(self->linebuf, top); \
linebuf_clear_line(self->linebuf, top, true); \
INDEX_GRAPHICS(1) \
self->is_dirty = true; \
index_selection(self, &self->selections, false);
static void
prevent_current_prompt_from_rewrapping(Screen *self, index_type columns) {
int y = self->cursor->y;
while (y >= 0) {
linebuf_init_line(self->main_linebuf, y);
Line *line = self->linebuf->line;
if (line->is_output_start) return;
if (line->is_prompt_start) break;
y--;
}
if (y < 0) return;
// we have identified a prompt at which the cursor is present, the shell
// will redraw this prompt. However when doing so it gets confused if the
// cursor vertical position relative to the first prompt line changes. This
// can easily be seen for instance in zsh when a right side prompt is used
// so when resizing to smaller sizes, simply blank all lines after the current
// prompt and trust the shell to redraw them
for (; y < (int)self->main_linebuf->ynum; y++) {
linebuf_mark_line_as_not_continued(self->main_linebuf, y);
if (columns < self->columns) {
linebuf_clear_line(self->main_linebuf, y, false);
linebuf_init_line(self->main_linebuf, y);
if (y <= (int)self->cursor->y) {
// this is needed because screen_resize() checks to see if the cursor is beyond the content,
// so insert some fake content
Line *line = self->linebuf->line;
line->cpu_cells[0].ch = '>';
}
}
}
}
static bool
screen_resize(Screen *self, unsigned int lines, unsigned int columns) {
if (self->overlay_line.is_active) deactivate_overlay_line(self);
@ -299,6 +332,7 @@ screen_resize(Screen *self, unsigned int lines, unsigned int columns) {
HistoryBuf *nh = realloc_hb(self->historybuf, self->historybuf->ynum, columns, &self->as_ansi_buf);
if (nh == NULL) return false;
Py_CLEAR(self->historybuf); self->historybuf = nh;
if (is_main) prevent_current_prompt_from_rewrapping(self, columns);
LineBuf *n = realloc_lb(self->main_linebuf, lines, columns, &num_content_lines_before, &num_content_lines_after, self->historybuf, &cursor, &main_saved_cursor, &self->as_ansi_buf);
if (n == NULL) return false;
Py_CLEAR(self->main_linebuf); self->main_linebuf = n;
@ -1135,7 +1169,7 @@ screen_cursor_to_column(Screen *self, unsigned int column) {
historybuf_add_line(self->historybuf, self->linebuf->line, &self->as_ansi_buf); \
self->history_line_added_count++; \
} \
linebuf_clear_line(self->linebuf, bottom); \
linebuf_clear_line(self->linebuf, bottom, true); \
self->is_dirty = true; \
index_selection(self, &self->selections, true);