mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-31 23:28:45 +00:00
Switch screen.h free functions to member functions on screen_t
Refactoring only, no functional change here.
This commit is contained in:
parent
26f3cee86c
commit
8878672014
3 changed files with 258 additions and 242 deletions
|
@ -1092,9 +1092,9 @@ void reader_data_t::paint_layout(const wchar_t *reason) {
|
||||||
indents.resize(full_line.size(), 0);
|
indents.resize(full_line.size(), 0);
|
||||||
|
|
||||||
// Prepend the mode prompt to the left prompt.
|
// Prepend the mode prompt to the left prompt.
|
||||||
s_write(&screen, mode_prompt_buff + left_prompt_buff, right_prompt_buff, full_line,
|
screen.write(mode_prompt_buff + left_prompt_buff, right_prompt_buff, full_line,
|
||||||
cmd_line->size(), colors, indents, data.position, pager, current_page_rendering,
|
cmd_line->size(), colors, indents, data.position, pager, current_page_rendering,
|
||||||
data.focused_on_pager);
|
data.focused_on_pager);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internal helper function for handling killing parts of text.
|
/// Internal helper function for handling killing parts of text.
|
||||||
|
@ -2618,7 +2618,7 @@ void reader_pop() {
|
||||||
reader_interactive_destroy();
|
reader_interactive_destroy();
|
||||||
*commandline_state_snapshot() = commandline_state_t{};
|
*commandline_state_snapshot() = commandline_state_t{};
|
||||||
} else {
|
} else {
|
||||||
s_reset_abandoning_line(&new_reader->screen, termsize_last().width);
|
new_reader->screen.reset_abandoning_line(termsize_last().width);
|
||||||
new_reader->update_commandline_state();
|
new_reader->update_commandline_state();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3000,7 +3000,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat
|
||||||
outp.push_back('\n');
|
outp.push_back('\n');
|
||||||
|
|
||||||
set_command_line_and_position(&command_line, L"", 0);
|
set_command_line_and_position(&command_line, L"", 0);
|
||||||
s_reset_abandoning_line(&screen, termsize_last().width - command_line.size());
|
screen.reset_abandoning_line(termsize_last().width - command_line.size());
|
||||||
|
|
||||||
// Post fish_cancel.
|
// Post fish_cancel.
|
||||||
event_fire_generic(parser(), L"fish_cancel");
|
event_fire_generic(parser(), L"fish_cancel");
|
||||||
|
@ -3038,7 +3038,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat
|
||||||
parser().libdata().is_repaint = true;
|
parser().libdata().is_repaint = true;
|
||||||
exec_mode_prompt();
|
exec_mode_prompt();
|
||||||
if (!mode_prompt_buff.empty()) {
|
if (!mode_prompt_buff.empty()) {
|
||||||
s_reset_line(&screen, true /* redraw prompt */);
|
screen.reset_line(true /* redraw prompt */);
|
||||||
if (this->is_repaint_needed()) this->layout_and_repaint(L"mode");
|
if (this->is_repaint_needed()) this->layout_and_repaint(L"mode");
|
||||||
parser().libdata().is_repaint = false;
|
parser().libdata().is_repaint = false;
|
||||||
break;
|
break;
|
||||||
|
@ -3050,7 +3050,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat
|
||||||
case rl::repaint: {
|
case rl::repaint: {
|
||||||
parser().libdata().is_repaint = true;
|
parser().libdata().is_repaint = true;
|
||||||
exec_prompt();
|
exec_prompt();
|
||||||
s_reset_line(&screen, true /* redraw prompt */);
|
screen.reset_line(true /* redraw prompt */);
|
||||||
this->layout_and_repaint(L"readline");
|
this->layout_and_repaint(L"readline");
|
||||||
force_exec_prompt_and_repaint = false;
|
force_exec_prompt_and_repaint = false;
|
||||||
parser().libdata().is_repaint = false;
|
parser().libdata().is_repaint = false;
|
||||||
|
@ -3370,7 +3370,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat
|
||||||
// already be printed, all we need to do is repaint.
|
// already be printed, all we need to do is repaint.
|
||||||
wcstring_list_t argv(1, el->text());
|
wcstring_list_t argv(1, el->text());
|
||||||
event_fire_generic(parser(), L"fish_posterror", &argv);
|
event_fire_generic(parser(), L"fish_posterror", &argv);
|
||||||
s_reset_abandoning_line(&screen, termsize_last().width);
|
screen.reset_abandoning_line(termsize_last().width);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -3950,7 +3950,7 @@ maybe_t<wcstring> reader_data_t::readline(int nchars_or_0) {
|
||||||
//
|
//
|
||||||
// I can't see a good way around this.
|
// I can't see a good way around this.
|
||||||
if (!first_prompt) {
|
if (!first_prompt) {
|
||||||
s_reset_abandoning_line(&screen, termsize_last().width);
|
screen.reset_abandoning_line(termsize_last().width);
|
||||||
}
|
}
|
||||||
first_prompt = false;
|
first_prompt = false;
|
||||||
|
|
||||||
|
|
367
src/screen.cpp
367
src/screen.cpp
|
@ -46,10 +46,8 @@
|
||||||
/// The number of characters to indent new blocks.
|
/// The number of characters to indent new blocks.
|
||||||
#define INDENT_STEP 4u
|
#define INDENT_STEP 4u
|
||||||
|
|
||||||
static void invalidate_soft_wrap(screen_t *scr);
|
|
||||||
|
|
||||||
/// RAII class to begin and end buffering around stdoutput().
|
/// RAII class to begin and end buffering around stdoutput().
|
||||||
class scoped_buffer_t {
|
class screen_t::scoped_buffer_t {
|
||||||
screen_t &screen_;
|
screen_t &screen_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -466,17 +464,14 @@ static size_t calc_prompt_lines(const wcstring &prompt) {
|
||||||
|
|
||||||
/// Stat stdout and stderr and save result. This should be done before calling a function that may
|
/// Stat stdout and stderr and save result. This should be done before calling a function that may
|
||||||
/// cause output.
|
/// cause output.
|
||||||
void s_save_status(screen_t *s) {
|
void screen_t::save_status() {
|
||||||
fstat(STDOUT_FILENO, &s->prev_buff_1);
|
fstat(STDOUT_FILENO, &this->prev_buff_1);
|
||||||
fstat(STDERR_FILENO, &s->prev_buff_2);
|
fstat(STDERR_FILENO, &this->prev_buff_2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stat stdout and stderr and compare result to previous result in reader_save_status. Repaint if
|
/// Stat stdout and stderr and compare result to previous result in reader_save_status. Repaint if
|
||||||
/// modification time has changed.
|
/// modification time has changed.
|
||||||
///
|
void screen_t::check_status() {
|
||||||
/// Unfortunately, for some reason this call seems to give a lot of false positives, at least under
|
|
||||||
/// Linux.
|
|
||||||
static void s_check_status(screen_t *s) {
|
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
if (!has_working_tty_timestamps) {
|
if (!has_working_tty_timestamps) {
|
||||||
|
@ -491,15 +486,16 @@ static void s_check_status(screen_t *s) {
|
||||||
fstat(STDOUT_FILENO, &post_buff_1);
|
fstat(STDOUT_FILENO, &post_buff_1);
|
||||||
fstat(STDERR_FILENO, &post_buff_2);
|
fstat(STDERR_FILENO, &post_buff_2);
|
||||||
|
|
||||||
bool changed = (s->prev_buff_1.st_mtime != post_buff_1.st_mtime) ||
|
bool changed = (this->prev_buff_1.st_mtime != post_buff_1.st_mtime) ||
|
||||||
(s->prev_buff_2.st_mtime != post_buff_2.st_mtime);
|
(this->prev_buff_2.st_mtime != post_buff_2.st_mtime);
|
||||||
|
|
||||||
#if defined HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
|
#if defined HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
|
||||||
changed = changed || s->prev_buff_1.st_mtimespec.tv_nsec != post_buff_1.st_mtimespec.tv_nsec ||
|
changed = changed ||
|
||||||
s->prev_buff_2.st_mtimespec.tv_nsec != post_buff_2.st_mtimespec.tv_nsec;
|
this->prev_buff_1.st_mtimespec.tv_nsec != post_buff_1.st_mtimespec.tv_nsec ||
|
||||||
|
this->prev_buff_2.st_mtimespec.tv_nsec != post_buff_2.st_mtimespec.tv_nsec;
|
||||||
#elif defined HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
|
#elif defined HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
|
||||||
changed = changed || s->prev_buff_1.st_mtim.tv_nsec != post_buff_1.st_mtim.tv_nsec ||
|
changed = changed || this->prev_buff_1.st_mtim.tv_nsec != post_buff_1.st_mtim.tv_nsec ||
|
||||||
s->prev_buff_2.st_mtim.tv_nsec != post_buff_2.st_mtim.tv_nsec;
|
this->prev_buff_2.st_mtim.tv_nsec != post_buff_2.st_mtim.tv_nsec;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
|
@ -507,99 +503,91 @@ static void s_check_status(screen_t *s) {
|
||||||
// know where the cursor is. It is our best bet that we are still on the same line, so we
|
// know where the cursor is. It is our best bet that we are still on the same line, so we
|
||||||
// move to the beginning of the line, reset the modelled screen contents, and then set the
|
// move to the beginning of the line, reset the modelled screen contents, and then set the
|
||||||
// modeled cursor y-pos to its earlier value.
|
// modeled cursor y-pos to its earlier value.
|
||||||
int prev_line = s->actual.cursor.y;
|
int prev_line = this->actual.cursor.y;
|
||||||
s_reset_line(s, true /* repaint prompt */);
|
this->reset_line(true /* repaint prompt */);
|
||||||
s->actual.cursor.y = prev_line;
|
this->actual.cursor.y = prev_line;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Appends a character to the end of the line that the output cursor is on. This function
|
void screen_t::desired_append_char(wchar_t b, highlight_spec_t c, int indent, size_t prompt_width,
|
||||||
/// automatically handles linebreaks and lines longer than the screen width.
|
size_t bwidth) {
|
||||||
static void s_desired_append_char(screen_t *s, wchar_t b, highlight_spec_t c, int indent,
|
int line_no = this->desired.cursor.y;
|
||||||
size_t prompt_width, size_t bwidth) {
|
|
||||||
int line_no = s->desired.cursor.y;
|
|
||||||
|
|
||||||
if (b == L'\n') {
|
if (b == L'\n') {
|
||||||
// Current line is definitely hard wrapped.
|
// Current line is definitely hard wrapped.
|
||||||
// Create the next line.
|
// Create the next line.
|
||||||
s->desired.create_line(s->desired.cursor.y + 1);
|
this->desired.create_line(this->desired.cursor.y + 1);
|
||||||
s->desired.line(s->desired.cursor.y).is_soft_wrapped = false;
|
this->desired.line(this->desired.cursor.y).is_soft_wrapped = false;
|
||||||
int line_no = ++s->desired.cursor.y;
|
int line_no = ++this->desired.cursor.y;
|
||||||
s->desired.cursor.x = 0;
|
this->desired.cursor.x = 0;
|
||||||
size_t indentation = prompt_width + indent * INDENT_STEP;
|
size_t indentation = prompt_width + indent * INDENT_STEP;
|
||||||
line_t &line = s->desired.line(line_no);
|
line_t &line = this->desired.line(line_no);
|
||||||
line.indentation = indentation;
|
line.indentation = indentation;
|
||||||
for (size_t i = 0; i < indentation; i++) {
|
for (size_t i = 0; i < indentation; i++) {
|
||||||
s_desired_append_char(s, L' ', highlight_spec_t{}, indent, prompt_width, 1);
|
desired_append_char(L' ', highlight_spec_t{}, indent, prompt_width, 1);
|
||||||
}
|
}
|
||||||
} else if (b == L'\r') {
|
} else if (b == L'\r') {
|
||||||
line_t ¤t = s->desired.line(line_no);
|
line_t ¤t = this->desired.line(line_no);
|
||||||
current.clear();
|
current.clear();
|
||||||
s->desired.cursor.x = 0;
|
this->desired.cursor.x = 0;
|
||||||
} else {
|
} else {
|
||||||
int screen_width = s->desired.screen_width;
|
int screen_width = this->desired.screen_width;
|
||||||
int cw = bwidth;
|
int cw = bwidth;
|
||||||
|
|
||||||
s->desired.create_line(line_no);
|
this->desired.create_line(line_no);
|
||||||
|
|
||||||
// Check if we are at the end of the line. If so, continue on the next line.
|
// Check if we are at the end of the line. If so, continue on the next line.
|
||||||
if ((s->desired.cursor.x + cw) > screen_width) {
|
if ((this->desired.cursor.x + cw) > screen_width) {
|
||||||
// Current line is soft wrapped (assuming we support it).
|
// Current line is soft wrapped (assuming we support it).
|
||||||
s->desired.line(s->desired.cursor.y).is_soft_wrapped = true;
|
this->desired.line(this->desired.cursor.y).is_soft_wrapped = true;
|
||||||
|
|
||||||
line_no = static_cast<int>(s->desired.line_count());
|
line_no = static_cast<int>(this->desired.line_count());
|
||||||
s->desired.add_line();
|
this->desired.add_line();
|
||||||
s->desired.cursor.y++;
|
this->desired.cursor.y++;
|
||||||
s->desired.cursor.x = 0;
|
this->desired.cursor.x = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
line_t &line = s->desired.line(line_no);
|
line_t &line = this->desired.line(line_no);
|
||||||
line.append(b, c);
|
line.append(b, c);
|
||||||
s->desired.cursor.x += cw;
|
this->desired.cursor.x += cw;
|
||||||
|
|
||||||
// Maybe wrap the cursor to the next line, even if the line itself did not wrap. This
|
// Maybe wrap the cursor to the next line, even if the line itself did not wrap. This
|
||||||
// avoids wonkiness in the last column.
|
// avoids wonkiness in the last column.
|
||||||
if (s->desired.cursor.x >= screen_width) {
|
if (this->desired.cursor.x >= screen_width) {
|
||||||
line.is_soft_wrapped = true;
|
line.is_soft_wrapped = true;
|
||||||
s->desired.cursor.x = 0;
|
this->desired.cursor.x = 0;
|
||||||
s->desired.cursor.y++;
|
this->desired.cursor.y++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write the bytes needed to move screen cursor to the specified position to the specified buffer.
|
void screen_t::move(int new_x, int new_y) {
|
||||||
/// The actual_cursor field of the specified screen_t will be updated.
|
if (this->actual.cursor.x == new_x && this->actual.cursor.y == new_y) return;
|
||||||
///
|
|
||||||
/// \param s the screen to operate on
|
|
||||||
/// \param new_x the new x position
|
|
||||||
/// \param new_y the new y position
|
|
||||||
static void s_move(screen_t *s, int new_x, int new_y) {
|
|
||||||
if (s->actual.cursor.x == new_x && s->actual.cursor.y == new_y) return;
|
|
||||||
|
|
||||||
const scoped_buffer_t buffering(*s);
|
const scoped_buffer_t buffering(*this);
|
||||||
|
|
||||||
// If we are at the end of our window, then either the cursor stuck to the edge or it didn't. We
|
// If we are at the end of our window, then either the cursor stuck to the edge or it didn't. We
|
||||||
// don't know! We can fix it up though.
|
// don't know! We can fix it up though.
|
||||||
if (s->actual.cursor.x == s->actual.screen_width) {
|
if (this->actual.cursor.x == this->actual.screen_width) {
|
||||||
// Either issue a cr to go back to the beginning of this line, or a nl to go to the
|
// Either issue a cr to go back to the beginning of this line, or a nl to go to the
|
||||||
// beginning of the next one, depending on what we think is more efficient.
|
// beginning of the next one, depending on what we think is more efficient.
|
||||||
if (new_y <= s->actual.cursor.y) {
|
if (new_y <= this->actual.cursor.y) {
|
||||||
s->outp().push_back('\r');
|
this->outp().push_back('\r');
|
||||||
} else {
|
} else {
|
||||||
s->outp().push_back('\n');
|
this->outp().push_back('\n');
|
||||||
s->actual.cursor.y++;
|
this->actual.cursor.y++;
|
||||||
}
|
}
|
||||||
// Either way we're not in the first column.
|
// Either way we're not in the first column.
|
||||||
s->actual.cursor.x = 0;
|
this->actual.cursor.x = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
int x_steps, y_steps;
|
int x_steps, y_steps;
|
||||||
|
|
||||||
const char *str;
|
const char *str;
|
||||||
auto &outp = s->outp();
|
auto &outp = this->outp();
|
||||||
|
|
||||||
y_steps = new_y - s->actual.cursor.y;
|
y_steps = new_y - this->actual.cursor.y;
|
||||||
|
|
||||||
if (y_steps < 0) {
|
if (y_steps < 0) {
|
||||||
str = cursor_up;
|
str = cursor_up;
|
||||||
|
@ -613,7 +601,7 @@ static void s_move(screen_t *s, int new_x, int new_y) {
|
||||||
// We could do:
|
// We could do:
|
||||||
// if (std::strcmp(cursor_up, "\x1B[A") == 0) str = "\x1B[B";
|
// if (std::strcmp(cursor_up, "\x1B[A") == 0) str = "\x1B[B";
|
||||||
// else ... but that doesn't work for unknown reasons.
|
// else ... but that doesn't work for unknown reasons.
|
||||||
s->actual.cursor.x = 0;
|
this->actual.cursor.x = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -621,7 +609,7 @@ static void s_move(screen_t *s, int new_x, int new_y) {
|
||||||
writembs(outp, str);
|
writembs(outp, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
x_steps = new_x - s->actual.cursor.x;
|
x_steps = new_x - this->actual.cursor.x;
|
||||||
|
|
||||||
if (x_steps && new_x == 0) {
|
if (x_steps && new_x == 0) {
|
||||||
outp.push_back('\r');
|
outp.push_back('\r');
|
||||||
|
@ -650,32 +638,32 @@ static void s_move(screen_t *s, int new_x, int new_y) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s->actual.cursor.x = new_x;
|
this->actual.cursor.x = new_x;
|
||||||
s->actual.cursor.y = new_y;
|
this->actual.cursor.y = new_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a wide character to a multibyte string and append it to the buffer.
|
/// Convert a wide character to a multibyte string and append it to the buffer.
|
||||||
static void s_write_char(screen_t *s, wchar_t c, size_t width) {
|
void screen_t::write_char(wchar_t c, size_t width) {
|
||||||
scoped_buffer_t outp(*s);
|
scoped_buffer_t outp(*this);
|
||||||
s->actual.cursor.x += width;
|
this->actual.cursor.x += width;
|
||||||
s->outp().writech(c);
|
this->outp().writech(c);
|
||||||
if (s->actual.cursor.x == s->actual.screen_width && allow_soft_wrap()) {
|
if (this->actual.cursor.x == this->actual.screen_width && allow_soft_wrap()) {
|
||||||
s->soft_wrap_location = screen_data_t::cursor_t{0, s->actual.cursor.y + 1};
|
this->soft_wrap_location = screen_data_t::cursor_t{0, this->actual.cursor.y + 1};
|
||||||
|
|
||||||
// Note that our cursor position may be a lie: Apple Terminal makes the right cursor stick
|
// Note that our cursor position may be a lie: Apple Terminal makes the right cursor stick
|
||||||
// to the margin, while Ubuntu makes it "go off the end" (but still doesn't wrap). We rely
|
// to the margin, while Ubuntu makes it "go off the end" (but still doesn't wrap). We rely
|
||||||
// on s_move to fix this up.
|
// on s_move to fix this up.
|
||||||
} else {
|
} else {
|
||||||
invalidate_soft_wrap(s);
|
this->soft_wrap_location = none();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send the specified string through tputs and append the output to the screen's outputter.
|
/// Send the specified string through tputs and append the output to the screen's outputter.
|
||||||
static void s_write_mbs(screen_t *screen, const char *s) { writembs(screen->outp(), s); }
|
void screen_t::write_mbs(const char *s) { writembs(this->outp(), s); }
|
||||||
|
|
||||||
/// Convert a wide string to a multibyte string and append it to the buffer.
|
/// Convert a wide string to a multibyte string and append it to the buffer.
|
||||||
static void s_write_str(screen_t *screen, const wchar_t *s) { screen->outp().writestr(s); }
|
void screen_t::write_str(const wchar_t *s) { this->outp().writestr(s); }
|
||||||
static void s_write_str(screen_t *screen, const wcstring &s) { screen->outp().writestr(s); }
|
void screen_t::write_str(const wcstring &s) { this->outp().writestr(s); }
|
||||||
|
|
||||||
/// Returns the length of the "shared prefix" of the two lines, which is the run of matching text
|
/// Returns the length of the "shared prefix" of the two lines, which is the run of matching text
|
||||||
/// and colors. If the prefix ends on a combining character, do not include the previous character
|
/// and colors. If the prefix ends on a combining character, do not include the previous character
|
||||||
|
@ -714,37 +702,34 @@ static size_t line_shared_prefix(const line_t &a, const line_t &b) {
|
||||||
// end of previous line, and the previous line is marked as soft wrapping, then tweak the screen so
|
// end of previous line, and the previous line is marked as soft wrapping, then tweak the screen so
|
||||||
// we believe we are already in the target position. This lets the terminal take care of wrapping,
|
// we believe we are already in the target position. This lets the terminal take care of wrapping,
|
||||||
// which means that if you copy and paste the text, it won't have an embedded newline.
|
// which means that if you copy and paste the text, it won't have an embedded newline.
|
||||||
static bool perform_any_impending_soft_wrap(screen_t *scr, int x, int y) {
|
bool screen_t::handle_soft_wrap(int x, int y) {
|
||||||
if (scr->soft_wrap_location && x == scr->soft_wrap_location->x &&
|
if (this->soft_wrap_location && x == this->soft_wrap_location->x &&
|
||||||
y == scr->soft_wrap_location->y) { //!OCLINT
|
y == this->soft_wrap_location->y) { //!OCLINT
|
||||||
// We can soft wrap; but do we want to?
|
// We can soft wrap; but do we want to?
|
||||||
if (scr->desired.line(y - 1).is_soft_wrapped && allow_soft_wrap()) {
|
if (this->desired.line(y - 1).is_soft_wrapped && allow_soft_wrap()) {
|
||||||
// Yes. Just update the actual cursor; that will cause us to elide emitting the commands
|
// Yes. Just update the actual cursor; that will cause us to elide emitting the commands
|
||||||
// to move here, so we will just output on "one big line" (which the terminal soft
|
// to move here, so we will just output on "one big line" (which the terminal soft
|
||||||
// wraps.
|
// wraps.
|
||||||
scr->actual.cursor = scr->soft_wrap_location.value();
|
this->actual.cursor = this->soft_wrap_location.value();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Make sure we don't soft wrap.
|
|
||||||
static void invalidate_soft_wrap(screen_t *scr) { scr->soft_wrap_location = none(); }
|
|
||||||
|
|
||||||
/// Update the screen to match the desired output.
|
/// Update the screen to match the desired output.
|
||||||
static void s_update(screen_t *scr, const wcstring &left_prompt, const wcstring &right_prompt) {
|
void screen_t::update(const wcstring &left_prompt, const wcstring &right_prompt) {
|
||||||
// TODO: this should be passed in.
|
// TODO: this should be passed in.
|
||||||
const environment_t &vars = env_stack_t::principal();
|
const environment_t &vars = env_stack_t::principal();
|
||||||
|
|
||||||
// Helper function to set a resolved color, using the caching resolver.
|
// Helper function to set a resolved color, using the caching resolver.
|
||||||
highlight_color_resolver_t color_resolver{};
|
highlight_color_resolver_t color_resolver{};
|
||||||
auto set_color = [&](highlight_spec_t c) {
|
auto set_color = [&](highlight_spec_t c) {
|
||||||
scr->outp().set_color(color_resolver.resolve_spec(c, false, vars),
|
this->outp().set_color(color_resolver.resolve_spec(c, false, vars),
|
||||||
color_resolver.resolve_spec(c, true, vars));
|
color_resolver.resolve_spec(c, true, vars));
|
||||||
};
|
};
|
||||||
|
|
||||||
layout_cache_t &cached_layouts = layout_cache_t::shared;
|
layout_cache_t &cached_layouts = layout_cache_t::shared;
|
||||||
const scoped_buffer_t buffering(*scr);
|
const scoped_buffer_t buffering(*this);
|
||||||
|
|
||||||
// Determine size of left and right prompt. Note these have already been truncated.
|
// Determine size of left and right prompt. Note these have already been truncated.
|
||||||
const prompt_layout_t left_prompt_layout = cached_layouts.calc_prompt_layout(left_prompt);
|
const prompt_layout_t left_prompt_layout = cached_layouts.calc_prompt_layout(left_prompt);
|
||||||
|
@ -753,56 +738,56 @@ static void s_update(screen_t *scr, const wcstring &left_prompt, const wcstring
|
||||||
cached_layouts.calc_prompt_layout(right_prompt).last_line_width;
|
cached_layouts.calc_prompt_layout(right_prompt).last_line_width;
|
||||||
|
|
||||||
// Figure out how many following lines we need to clear (probably 0).
|
// Figure out how many following lines we need to clear (probably 0).
|
||||||
size_t actual_lines_before_reset = scr->actual_lines_before_reset;
|
size_t actual_lines_before_reset = this->actual_lines_before_reset;
|
||||||
scr->actual_lines_before_reset = 0;
|
this->actual_lines_before_reset = 0;
|
||||||
|
|
||||||
bool need_clear_lines = scr->need_clear_lines;
|
bool need_clear_lines = this->need_clear_lines;
|
||||||
bool need_clear_screen = scr->need_clear_screen;
|
bool need_clear_screen = this->need_clear_screen;
|
||||||
bool has_cleared_screen = false;
|
bool has_cleared_screen = false;
|
||||||
|
|
||||||
const int screen_width = scr->desired.screen_width;
|
const int screen_width = this->desired.screen_width;
|
||||||
|
|
||||||
if (scr->actual.screen_width != screen_width) {
|
if (this->actual.screen_width != screen_width) {
|
||||||
// Ensure we don't issue a clear screen for the very first output, to avoid issue #402.
|
// Ensure we don't issue a clear screen for the very first output, to avoid issue #402.
|
||||||
if (scr->actual.screen_width > 0) {
|
if (this->actual.screen_width > 0) {
|
||||||
need_clear_screen = true;
|
need_clear_screen = true;
|
||||||
s_move(scr, 0, 0);
|
this->move(0, 0);
|
||||||
s_reset_line(scr);
|
this->reset_line();
|
||||||
|
|
||||||
need_clear_lines = need_clear_lines || scr->need_clear_lines;
|
need_clear_lines = need_clear_lines || this->need_clear_lines;
|
||||||
need_clear_screen = need_clear_screen || scr->need_clear_screen;
|
need_clear_screen = need_clear_screen || this->need_clear_screen;
|
||||||
}
|
}
|
||||||
scr->actual.screen_width = screen_width;
|
this->actual.screen_width = screen_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
scr->need_clear_lines = false;
|
this->need_clear_lines = false;
|
||||||
scr->need_clear_screen = false;
|
this->need_clear_screen = false;
|
||||||
|
|
||||||
// Determine how many lines have stuff on them; we need to clear lines with stuff that we don't
|
// Determine how many lines have stuff on them; we need to clear lines with stuff that we don't
|
||||||
// want.
|
// want.
|
||||||
const size_t lines_with_stuff = std::max(actual_lines_before_reset, scr->actual.line_count());
|
const size_t lines_with_stuff = std::max(actual_lines_before_reset, this->actual.line_count());
|
||||||
if (scr->desired.line_count() < lines_with_stuff) need_clear_screen = true;
|
if (this->desired.line_count() < lines_with_stuff) need_clear_screen = true;
|
||||||
|
|
||||||
// Output the left prompt if it has changed.
|
// Output the left prompt if it has changed.
|
||||||
if (left_prompt != scr->actual_left_prompt) {
|
if (left_prompt != this->actual_left_prompt) {
|
||||||
s_move(scr, 0, 0);
|
this->move(0, 0);
|
||||||
size_t start = 0;
|
size_t start = 0;
|
||||||
for (const size_t line_break : left_prompt_layout.line_breaks) {
|
for (const size_t line_break : left_prompt_layout.line_breaks) {
|
||||||
s_write_str(scr, left_prompt.substr(start, line_break - start));
|
this->write_str(left_prompt.substr(start, line_break - start));
|
||||||
if (clr_eol) {
|
if (clr_eol) {
|
||||||
s_write_mbs(scr, clr_eol);
|
this->write_mbs(clr_eol);
|
||||||
}
|
}
|
||||||
start = line_break;
|
start = line_break;
|
||||||
}
|
}
|
||||||
s_write_str(scr, left_prompt.substr(start));
|
this->write_str(left_prompt.substr(start));
|
||||||
scr->actual_left_prompt = left_prompt;
|
this->actual_left_prompt = left_prompt;
|
||||||
scr->actual.cursor.x = static_cast<int>(left_prompt_width);
|
this->actual.cursor.x = static_cast<int>(left_prompt_width);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output all lines.
|
// Output all lines.
|
||||||
for (size_t i = 0; i < scr->desired.line_count(); i++) {
|
for (size_t i = 0; i < this->desired.line_count(); i++) {
|
||||||
const line_t &o_line = scr->desired.line(i);
|
const line_t &o_line = this->desired.line(i);
|
||||||
line_t &s_line = scr->actual.create_line(i);
|
line_t &s_line = this->actual.create_line(i);
|
||||||
size_t start_pos = i == 0 ? left_prompt_width : 0;
|
size_t start_pos = i == 0 ? left_prompt_width : 0;
|
||||||
int current_width = 0;
|
int current_width = 0;
|
||||||
bool has_cleared_line = false;
|
bool has_cleared_line = false;
|
||||||
|
@ -810,9 +795,9 @@ static void s_update(screen_t *scr, const wcstring &left_prompt, const wcstring
|
||||||
// If this is the last line, maybe we should clear the screen.
|
// If this is the last line, maybe we should clear the screen.
|
||||||
// Don't issue clr_eos if we think the cursor will end up in the last column - see #6951.
|
// Don't issue clr_eos if we think the cursor will end up in the last column - see #6951.
|
||||||
const bool should_clear_screen_this_line =
|
const bool should_clear_screen_this_line =
|
||||||
need_clear_screen && i + 1 == scr->desired.line_count() && clr_eos != nullptr &&
|
need_clear_screen && i + 1 == this->desired.line_count() && clr_eos != nullptr &&
|
||||||
!(scr->desired.cursor.x == 0 &&
|
!(this->desired.cursor.x == 0 &&
|
||||||
scr->desired.cursor.y == static_cast<int>(scr->desired.line_count()));
|
this->desired.cursor.y == static_cast<int>(this->desired.line_count()));
|
||||||
|
|
||||||
// skip_remaining is how many columns are unchanged on this line.
|
// skip_remaining is how many columns are unchanged on this line.
|
||||||
// Note that skip_remaining is a width, not a character count.
|
// Note that skip_remaining is a width, not a character count.
|
||||||
|
@ -824,8 +809,8 @@ static void s_update(screen_t *scr, const wcstring &left_prompt, const wcstring
|
||||||
if (o_line.indentation > s_line.indentation && !has_cleared_screen && clr_eol &&
|
if (o_line.indentation > s_line.indentation && !has_cleared_screen && clr_eol &&
|
||||||
clr_eos) {
|
clr_eos) {
|
||||||
set_color(highlight_spec_t{});
|
set_color(highlight_spec_t{});
|
||||||
s_move(scr, 0, static_cast<int>(i));
|
this->move(0, static_cast<int>(i));
|
||||||
s_write_mbs(scr, should_clear_screen_this_line ? clr_eos : clr_eol);
|
this->write_mbs(should_clear_screen_this_line ? clr_eos : clr_eol);
|
||||||
has_cleared_screen = should_clear_screen_this_line;
|
has_cleared_screen = should_clear_screen_this_line;
|
||||||
has_cleared_line = true;
|
has_cleared_line = true;
|
||||||
}
|
}
|
||||||
|
@ -844,16 +829,17 @@ static void s_update(screen_t *scr, const wcstring &left_prompt, const wcstring
|
||||||
if (!should_clear_screen_this_line) {
|
if (!should_clear_screen_this_line) {
|
||||||
// If we're soft wrapped, and if we're going to change the first character of the next
|
// If we're soft wrapped, and if we're going to change the first character of the next
|
||||||
// line, don't skip over the last two characters so that we maintain soft-wrapping.
|
// line, don't skip over the last two characters so that we maintain soft-wrapping.
|
||||||
if (o_line.is_soft_wrapped && i + 1 < scr->desired.line_count()) {
|
if (o_line.is_soft_wrapped && i + 1 < this->desired.line_count()) {
|
||||||
bool next_line_will_change = true;
|
bool next_line_will_change = true;
|
||||||
if (i + 1 < scr->actual.line_count()) { //!OCLINT
|
if (i + 1 < this->actual.line_count()) { //!OCLINT
|
||||||
if (line_shared_prefix(scr->desired.line(i + 1), scr->actual.line(i + 1)) > 0) {
|
if (line_shared_prefix(this->desired.line(i + 1), this->actual.line(i + 1)) >
|
||||||
|
0) {
|
||||||
next_line_will_change = false;
|
next_line_will_change = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (next_line_will_change) {
|
if (next_line_will_change) {
|
||||||
skip_remaining =
|
skip_remaining = std::min(skip_remaining,
|
||||||
std::min(skip_remaining, static_cast<size_t>(scr->actual.screen_width - 2));
|
static_cast<size_t>(this->actual.screen_width - 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -884,17 +870,17 @@ static void s_update(screen_t *scr, const wcstring &left_prompt, const wcstring
|
||||||
if (should_clear_screen_this_line && !has_cleared_screen &&
|
if (should_clear_screen_this_line && !has_cleared_screen &&
|
||||||
(done || j + 1 == static_cast<size_t>(screen_width))) {
|
(done || j + 1 == static_cast<size_t>(screen_width))) {
|
||||||
set_color(highlight_spec_t{});
|
set_color(highlight_spec_t{});
|
||||||
s_move(scr, current_width, static_cast<int>(i));
|
this->move(current_width, static_cast<int>(i));
|
||||||
s_write_mbs(scr, clr_eos);
|
this->write_mbs(clr_eos);
|
||||||
has_cleared_screen = true;
|
has_cleared_screen = true;
|
||||||
}
|
}
|
||||||
if (done) break;
|
if (done) break;
|
||||||
|
|
||||||
perform_any_impending_soft_wrap(scr, current_width, static_cast<int>(i));
|
this->handle_soft_wrap(current_width, static_cast<int>(i));
|
||||||
s_move(scr, current_width, static_cast<int>(i));
|
this->move(current_width, static_cast<int>(i));
|
||||||
set_color(o_line.color_at(j));
|
set_color(o_line.color_at(j));
|
||||||
auto width = fish_wcwidth_visible(o_line.char_at(j));
|
auto width = fish_wcwidth_visible(o_line.char_at(j));
|
||||||
s_write_char(scr, o_line.char_at(j), width);
|
this->write_char(o_line.char_at(j), width);
|
||||||
current_width += width;
|
current_width += width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -907,7 +893,7 @@ static void s_update(screen_t *scr, const wcstring &left_prompt, const wcstring
|
||||||
clear_remainder = false;
|
clear_remainder = false;
|
||||||
} else if (need_clear_lines && current_width < screen_width) {
|
} else if (need_clear_lines && current_width < screen_width) {
|
||||||
clear_remainder = true;
|
clear_remainder = true;
|
||||||
} else if (right_prompt_width < scr->last_right_prompt_width) {
|
} else if (right_prompt_width < this->last_right_prompt_width) {
|
||||||
clear_remainder = true;
|
clear_remainder = true;
|
||||||
} else {
|
} else {
|
||||||
// This wcswidth shows up strong in the profile.
|
// This wcswidth shows up strong in the profile.
|
||||||
|
@ -920,19 +906,19 @@ static void s_update(screen_t *scr, const wcstring &left_prompt, const wcstring
|
||||||
}
|
}
|
||||||
if (clear_remainder && clr_eol) {
|
if (clear_remainder && clr_eol) {
|
||||||
set_color(highlight_spec_t{});
|
set_color(highlight_spec_t{});
|
||||||
s_move(scr, current_width, static_cast<int>(i));
|
this->move(current_width, static_cast<int>(i));
|
||||||
s_write_mbs(scr, clr_eol);
|
this->write_mbs(clr_eol);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output any rprompt if this is the first line.
|
// Output any rprompt if this is the first line.
|
||||||
if (i == 0 && right_prompt_width > 0) { //!OCLINT(Use early exit/continue)
|
if (i == 0 && right_prompt_width > 0) { //!OCLINT(Use early exit/continue)
|
||||||
// Move the cursor to the beginning of the line first to be independent of the width.
|
// Move the cursor to the beginning of the line first to be independent of the width.
|
||||||
// This helps prevent staircase effects if fish and the terminal disagree.
|
// This helps prevent staircase effects if fish and the terminal disagree.
|
||||||
s_move(scr, 0, 0);
|
this->move(0, 0);
|
||||||
s_move(scr, static_cast<int>(screen_width - right_prompt_width), static_cast<int>(i));
|
this->move(static_cast<int>(screen_width - right_prompt_width), static_cast<int>(i));
|
||||||
set_color(highlight_spec_t{});
|
set_color(highlight_spec_t{});
|
||||||
s_write_str(scr, right_prompt);
|
this->write_str(right_prompt);
|
||||||
scr->actual.cursor.x += right_prompt_width;
|
this->actual.cursor.x += right_prompt_width;
|
||||||
|
|
||||||
// We output in the last column. Some terms (Linux) push the cursor further right, past
|
// We output in the last column. Some terms (Linux) push the cursor further right, past
|
||||||
// the window. Others make it "stick." Since we don't really know which is which, issue
|
// the window. Others make it "stick." Since we don't really know which is which, issue
|
||||||
|
@ -942,33 +928,33 @@ static void s_update(screen_t *scr, const wcstring &left_prompt, const wcstring
|
||||||
// wrapped. If so, then a cr will go to the beginning of the following line! So instead
|
// wrapped. If so, then a cr will go to the beginning of the following line! So instead
|
||||||
// issue a bunch of "move left" commands to get back onto the line, and then jump to the
|
// issue a bunch of "move left" commands to get back onto the line, and then jump to the
|
||||||
// front of it.
|
// front of it.
|
||||||
s_move(scr, scr->actual.cursor.x - static_cast<int>(right_prompt_width),
|
this->move(this->actual.cursor.x - static_cast<int>(right_prompt_width),
|
||||||
scr->actual.cursor.y);
|
this->actual.cursor.y);
|
||||||
s_write_str(scr, L"\r");
|
this->write_str(L"\r");
|
||||||
scr->actual.cursor.x = 0;
|
this->actual.cursor.x = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also move the cursor to the beginning of the line here,
|
// Also move the cursor to the beginning of the line here,
|
||||||
// in case we're wrong about the width anywhere.
|
// in case we're wrong about the width anywhere.
|
||||||
s_move(scr, 0, 0);
|
this->move(0, 0);
|
||||||
|
|
||||||
// Clear remaining lines (if any) if we haven't cleared the screen.
|
// Clear remaining lines (if any) if we haven't cleared the screen.
|
||||||
if (!has_cleared_screen && need_clear_screen && clr_eol) {
|
if (!has_cleared_screen && need_clear_screen && clr_eol) {
|
||||||
set_color(highlight_spec_t{});
|
set_color(highlight_spec_t{});
|
||||||
for (size_t i = scr->desired.line_count(); i < lines_with_stuff; i++) {
|
for (size_t i = this->desired.line_count(); i < lines_with_stuff; i++) {
|
||||||
s_move(scr, 0, static_cast<int>(i));
|
this->move(0, static_cast<int>(i));
|
||||||
s_write_mbs(scr, clr_eol);
|
this->write_mbs(clr_eol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s_move(scr, scr->desired.cursor.x, scr->desired.cursor.y);
|
this->move(this->desired.cursor.x, this->desired.cursor.y);
|
||||||
set_color(highlight_spec_t{});
|
set_color(highlight_spec_t{});
|
||||||
|
|
||||||
// We have now synced our actual screen against our desired screen. Note that this is a big
|
// We have now synced our actual screen against our desired screen. Note that this is a big
|
||||||
// assignment!
|
// assignment!
|
||||||
scr->actual = scr->desired;
|
this->actual = this->desired;
|
||||||
scr->last_right_prompt_width = right_prompt_width;
|
this->last_right_prompt_width = right_prompt_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if we are using a dumb terminal.
|
/// Returns true if we are using a dumb terminal.
|
||||||
|
@ -1156,11 +1142,11 @@ static screen_layout_t compute_layout(screen_t *s, size_t screen_width,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void s_write(screen_t *s, const wcstring &left_prompt, const wcstring &right_prompt,
|
void screen_t::write(const wcstring &left_prompt, const wcstring &right_prompt,
|
||||||
const wcstring &commandline, size_t explicit_len,
|
const wcstring &commandline, size_t explicit_len,
|
||||||
const std::vector<highlight_spec_t> &colors, const std::vector<int> &indent,
|
const std::vector<highlight_spec_t> &colors, const std::vector<int> &indent,
|
||||||
size_t cursor_pos, pager_t &pager, page_rendering_t &page_rendering,
|
size_t cursor_pos, pager_t &pager, page_rendering_t &page_rendering,
|
||||||
bool cursor_is_within_pager) {
|
bool cursor_is_within_pager) {
|
||||||
termsize_t curr_termsize = termsize_last();
|
termsize_t curr_termsize = termsize_last();
|
||||||
int screen_width = curr_termsize.width;
|
int screen_width = curr_termsize.width;
|
||||||
static relaxed_atomic_t<uint32_t> s_repaints{0};
|
static relaxed_atomic_t<uint32_t> s_repaints{0};
|
||||||
|
@ -1184,7 +1170,7 @@ void s_write(screen_t *s, const wcstring &left_prompt, const wcstring &right_pro
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
s_check_status(s);
|
this->check_status();
|
||||||
|
|
||||||
// Completely ignore impossibly small screens.
|
// Completely ignore impossibly small screens.
|
||||||
if (screen_width < 4) {
|
if (screen_width < 4) {
|
||||||
|
@ -1192,21 +1178,21 @@ void s_write(screen_t *s, const wcstring &left_prompt, const wcstring &right_pro
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute a layout.
|
// Compute a layout.
|
||||||
const screen_layout_t layout = compute_layout(s, screen_width, left_prompt, right_prompt,
|
const screen_layout_t layout = compute_layout(this, screen_width, left_prompt, right_prompt,
|
||||||
explicit_command_line, autosuggestion);
|
explicit_command_line, autosuggestion);
|
||||||
|
|
||||||
// Determine whether, if we have an autosuggestion, it was truncated.
|
// Determine whether, if we have an autosuggestion, it was truncated.
|
||||||
s->autosuggestion_is_truncated =
|
this->autosuggestion_is_truncated =
|
||||||
!autosuggestion.empty() && autosuggestion != layout.autosuggestion;
|
!autosuggestion.empty() && autosuggestion != layout.autosuggestion;
|
||||||
|
|
||||||
// Clear the desired screen and set its width.
|
// Clear the desired screen and set its width.
|
||||||
s->desired.screen_width = screen_width;
|
this->desired.screen_width = screen_width;
|
||||||
s->desired.resize(0);
|
this->desired.resize(0);
|
||||||
s->desired.cursor.x = s->desired.cursor.y = 0;
|
this->desired.cursor.x = this->desired.cursor.y = 0;
|
||||||
|
|
||||||
// Append spaces for the left prompt.
|
// Append spaces for the left prompt.
|
||||||
for (size_t i = 0; i < layout.left_prompt_space; i++) {
|
for (size_t i = 0; i < layout.left_prompt_space; i++) {
|
||||||
s_desired_append_char(s, L' ', highlight_spec_t{}, 0, layout.left_prompt_space, 1);
|
desired_append_char(L' ', highlight_spec_t{}, 0, layout.left_prompt_space, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If overflowing, give the prompt its own line to improve the situation.
|
// If overflowing, give the prompt its own line to improve the situation.
|
||||||
|
@ -1220,25 +1206,25 @@ void s_write(screen_t *s, const wcstring &left_prompt, const wcstring &right_pro
|
||||||
for (i = 0; i < effective_commandline.size(); i++) {
|
for (i = 0; i < effective_commandline.size(); i++) {
|
||||||
// Grab the current cursor's x,y position if this character matches the cursor's offset.
|
// Grab the current cursor's x,y position if this character matches the cursor's offset.
|
||||||
if (!cursor_is_within_pager && i == cursor_pos) {
|
if (!cursor_is_within_pager && i == cursor_pos) {
|
||||||
cursor_arr = s->desired.cursor;
|
cursor_arr = this->desired.cursor;
|
||||||
}
|
}
|
||||||
s_desired_append_char(s, effective_commandline.at(i), colors[i], indent[i],
|
desired_append_char(effective_commandline.at(i), colors[i], indent[i],
|
||||||
first_line_prompt_space,
|
first_line_prompt_space,
|
||||||
fish_wcwidth_visible(effective_commandline.at(i)));
|
fish_wcwidth_visible(effective_commandline.at(i)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cursor may have been at the end too.
|
// Cursor may have been at the end too.
|
||||||
if (!cursor_is_within_pager && i == cursor_pos) {
|
if (!cursor_is_within_pager && i == cursor_pos) {
|
||||||
cursor_arr = s->desired.cursor;
|
cursor_arr = this->desired.cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that we've output everything, set the cursor to the position that we saved in the loop
|
// Now that we've output everything, set the cursor to the position that we saved in the loop
|
||||||
// above.
|
// above.
|
||||||
s->desired.cursor = cursor_arr;
|
this->desired.cursor = cursor_arr;
|
||||||
|
|
||||||
if (cursor_is_within_pager) {
|
if (cursor_is_within_pager) {
|
||||||
s->desired.cursor.x = static_cast<int>(cursor_pos);
|
this->desired.cursor.x = static_cast<int>(cursor_pos);
|
||||||
s->desired.cursor.y = static_cast<int>(s->desired.line_count());
|
this->desired.cursor.y = static_cast<int>(this->desired.line_count());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Re-render our completions page if necessary. Limit the term size of the pager to the true
|
// Re-render our completions page if necessary. Limit the term size of the pager to the true
|
||||||
|
@ -1248,48 +1234,45 @@ void s_write(screen_t *s, const wcstring &left_prompt, const wcstring &right_pro
|
||||||
std::max(1, curr_termsize.height - full_line_count)});
|
std::max(1, curr_termsize.height - full_line_count)});
|
||||||
pager.update_rendering(&page_rendering);
|
pager.update_rendering(&page_rendering);
|
||||||
// Append pager_data (none if empty).
|
// Append pager_data (none if empty).
|
||||||
s->desired.append_lines(page_rendering.screen_data);
|
this->desired.append_lines(page_rendering.screen_data);
|
||||||
|
|
||||||
s_update(s, layout.left_prompt, layout.right_prompt);
|
this->update(layout.left_prompt, layout.right_prompt);
|
||||||
s_save_status(s);
|
this->save_status();
|
||||||
}
|
}
|
||||||
|
|
||||||
void s_reset_line(screen_t *s, bool repaint_prompt) {
|
void screen_t::reset_line(bool repaint_prompt) {
|
||||||
assert(s && "Null screen");
|
|
||||||
|
|
||||||
// Remember how many lines we had output to, so we can clear the remaining lines in the next
|
// Remember how many lines we had output to, so we can clear the remaining lines in the next
|
||||||
// call to s_update. This prevents leaving junk underneath the cursor when resizing a window
|
// call to s_update. This prevents leaving junk underneath the cursor when resizing a window
|
||||||
// wider such that it reduces our desired line count.
|
// wider such that it reduces our desired line count.
|
||||||
s->actual_lines_before_reset = std::max(s->actual_lines_before_reset, s->actual.line_count());
|
this->actual_lines_before_reset =
|
||||||
|
std::max(this->actual_lines_before_reset, this->actual.line_count());
|
||||||
|
|
||||||
if (repaint_prompt) {
|
if (repaint_prompt) {
|
||||||
// If the prompt is multi-line, we need to move up to the prompt's initial line. We do this
|
// If the prompt is multi-line, we need to move up to the prompt's initial line. We do this
|
||||||
// by lying to ourselves and claiming that we're really below what we consider "line 0"
|
// by lying to ourselves and claiming that we're really below what we consider "line 0"
|
||||||
// (which is the last line of the prompt). This will cause us to move up to try to get back
|
// (which is the last line of the prompt). This will cause us to move up to try to get back
|
||||||
// to line 0, but really we're getting back to the initial line of the prompt.
|
// to line 0, but really we're getting back to the initial line of the prompt.
|
||||||
const size_t prompt_line_count = calc_prompt_lines(s->actual_left_prompt);
|
const size_t prompt_line_count = calc_prompt_lines(this->actual_left_prompt);
|
||||||
assert(prompt_line_count >= 1);
|
assert(prompt_line_count >= 1);
|
||||||
s->actual.cursor.y += (prompt_line_count - 1);
|
this->actual.cursor.y += (prompt_line_count - 1);
|
||||||
s->actual_left_prompt.clear();
|
this->actual_left_prompt.clear();
|
||||||
}
|
}
|
||||||
s->actual.resize(0);
|
this->actual.resize(0);
|
||||||
s->need_clear_lines = true;
|
this->need_clear_lines = true;
|
||||||
|
|
||||||
// This should prevent resetting the cursor position during the next repaint.
|
// This should prevent resetting the cursor position during the next repaint.
|
||||||
write_loop(STDOUT_FILENO, "\r", 1);
|
write_loop(STDOUT_FILENO, "\r", 1);
|
||||||
s->actual.cursor.x = 0;
|
this->actual.cursor.x = 0;
|
||||||
|
|
||||||
fstat(STDOUT_FILENO, &s->prev_buff_1);
|
fstat(STDOUT_FILENO, &this->prev_buff_1);
|
||||||
fstat(STDERR_FILENO, &s->prev_buff_2);
|
fstat(STDERR_FILENO, &this->prev_buff_2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void s_reset_abandoning_line(screen_t *s, int screen_width) {
|
void screen_t::reset_abandoning_line(int screen_width) {
|
||||||
assert(s && "Null screen");
|
this->actual.cursor.y = 0;
|
||||||
|
this->actual.resize(0);
|
||||||
s->actual.cursor.y = 0;
|
this->actual_left_prompt.clear();
|
||||||
s->actual.resize(0);
|
this->need_clear_lines = true;
|
||||||
s->actual_left_prompt.clear();
|
|
||||||
s->need_clear_lines = true;
|
|
||||||
|
|
||||||
// Do the PROMPT_SP hack.
|
// Do the PROMPT_SP hack.
|
||||||
wcstring abandon_line_string;
|
wcstring abandon_line_string;
|
||||||
|
@ -1358,10 +1341,10 @@ void s_reset_abandoning_line(screen_t *s, int screen_width) {
|
||||||
const std::string narrow_abandon_line_string = wcs2string(abandon_line_string);
|
const std::string narrow_abandon_line_string = wcs2string(abandon_line_string);
|
||||||
write_loop(STDOUT_FILENO, narrow_abandon_line_string.c_str(),
|
write_loop(STDOUT_FILENO, narrow_abandon_line_string.c_str(),
|
||||||
narrow_abandon_line_string.size());
|
narrow_abandon_line_string.size());
|
||||||
s->actual.cursor.x = 0;
|
this->actual.cursor.x = 0;
|
||||||
|
|
||||||
fstat(STDOUT_FILENO, &s->prev_buff_1);
|
fstat(STDOUT_FILENO, &this->prev_buff_1);
|
||||||
fstat(STDERR_FILENO, &s->prev_buff_2);
|
fstat(STDERR_FILENO, &this->prev_buff_2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void screen_force_clear_to_end() {
|
void screen_force_clear_to_end() {
|
||||||
|
|
115
src/screen.h
115
src/screen.h
|
@ -136,6 +136,76 @@ class screen_t {
|
||||||
public:
|
public:
|
||||||
screen_t();
|
screen_t();
|
||||||
|
|
||||||
|
/// This is the main function for the screen output library. It is used to define the desired
|
||||||
|
/// contents of the screen. The screen command will use its knowledge of the current contents of
|
||||||
|
/// the screen in order to render the desired output using as few terminal commands as possible.
|
||||||
|
///
|
||||||
|
/// \param left_prompt the prompt to prepend to the command line
|
||||||
|
/// \param right_prompt the right prompt, or NULL if none
|
||||||
|
/// \param commandline the command line
|
||||||
|
/// \param explicit_len the number of characters of the "explicit" (non-autosuggestion) portion
|
||||||
|
/// of the command line \param colors the colors to use for the comand line \param indent the
|
||||||
|
/// indent to use for the command line \param cursor_pos where the cursor is \param pager the
|
||||||
|
/// pager to render below the command line \param page_rendering to cache the current pager view
|
||||||
|
/// \param cursor_is_within_pager whether the position is within the pager line (first line)
|
||||||
|
void write(const wcstring &left_prompt, const wcstring &right_prompt,
|
||||||
|
const wcstring &commandline, size_t explicit_len,
|
||||||
|
const std::vector<highlight_spec_t> &colors, const std::vector<int> &indent,
|
||||||
|
size_t cursor_pos, pager_t &pager, page_rendering_t &page_rendering,
|
||||||
|
bool cursor_is_within_pager);
|
||||||
|
|
||||||
|
/// Resets the screen buffer's internal knowledge about the contents of the screen,
|
||||||
|
/// optionally repainting the prompt as well.
|
||||||
|
/// This function assumes that the current line is still valid.
|
||||||
|
void reset_line(bool repaint_prompt = false);
|
||||||
|
|
||||||
|
/// Resets the screen buffer's internal knowldge about the contents of the screen,
|
||||||
|
/// abandoning the current line and going to the next line.
|
||||||
|
/// If clear_to_eos is set,
|
||||||
|
/// The screen width must be provided for the PROMPT_SP hack.
|
||||||
|
void reset_abandoning_line(int screen_width);
|
||||||
|
|
||||||
|
/// Stat stdout and stderr and save result as the current timestamp.
|
||||||
|
/// This is used to avoid reacting to changes that we ourselves made to the screen.
|
||||||
|
void save_status();
|
||||||
|
|
||||||
|
/// \return whether we believe the cursor is wrapped onto the last line, and that line is
|
||||||
|
/// otherwise empty. This includes both soft and hard wrapping.
|
||||||
|
bool cursor_is_wrapped_to_own_line() const;
|
||||||
|
|
||||||
|
/// Whether the last-drawn autosuggestion (if any) is truncated, or hidden entirely.
|
||||||
|
bool autosuggestion_is_truncated{false};
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// Appends a character to the end of the line that the output cursor is on. This function
|
||||||
|
/// automatically handles linebreaks and lines longer than the screen width.
|
||||||
|
void desired_append_char(wchar_t b, highlight_spec_t c, int indent, size_t prompt_width,
|
||||||
|
size_t bwidth);
|
||||||
|
|
||||||
|
/// Stat stdout and stderr and compare result to previous result in reader_save_status. Repaint
|
||||||
|
/// if modification time has changed.
|
||||||
|
void check_status();
|
||||||
|
|
||||||
|
/// Write the bytes needed to move screen cursor to the specified position to the specified
|
||||||
|
/// buffer. The actual_cursor field of the specified screen_t will be updated.
|
||||||
|
///
|
||||||
|
/// \param new_x the new x position
|
||||||
|
/// \param new_y the new y position
|
||||||
|
void move(int new_x, int new_y);
|
||||||
|
|
||||||
|
/// Convert a wide character to a multibyte string and append it to the buffer.
|
||||||
|
void write_char(wchar_t c, size_t width);
|
||||||
|
|
||||||
|
/// Send the specified string through tputs and append the output to the screen's outputter.
|
||||||
|
void write_mbs(const char *s);
|
||||||
|
|
||||||
|
/// Convert a wide string to a multibyte string and append it to the buffer.
|
||||||
|
void write_str(const wchar_t *s);
|
||||||
|
void write_str(const wcstring &s);
|
||||||
|
|
||||||
|
/// Update the cursor as if soft wrapping had been performed.
|
||||||
|
bool handle_soft_wrap(int x, int y);
|
||||||
|
|
||||||
/// The internal representation of the desired screen contents.
|
/// The internal representation of the desired screen contents.
|
||||||
screen_data_t desired{};
|
screen_data_t desired{};
|
||||||
/// The internal representation of the actual screen contents.
|
/// The internal representation of the actual screen contents.
|
||||||
|
@ -146,8 +216,6 @@ class screen_t {
|
||||||
size_t last_right_prompt_width{0};
|
size_t last_right_prompt_width{0};
|
||||||
/// If we support soft wrapping, we can output to this location without any cursor motion.
|
/// If we support soft wrapping, we can output to this location without any cursor motion.
|
||||||
maybe_t<screen_data_t::cursor_t> soft_wrap_location{};
|
maybe_t<screen_data_t::cursor_t> soft_wrap_location{};
|
||||||
/// Whether the last-drawn autosuggestion (if any) is truncated, or hidden entirely.
|
|
||||||
bool autosuggestion_is_truncated{false};
|
|
||||||
/// This flag is set to true when there is reason to suspect that the parts of the screen lines
|
/// This flag is set to true when there is reason to suspect that the parts of the screen lines
|
||||||
/// where the actual content is not filled in may be non-empty. This means that a clr_eol
|
/// where the actual content is not filled in may be non-empty. This means that a clr_eol
|
||||||
/// command has to be sent to the terminal at the end of each line, including
|
/// command has to be sent to the terminal at the end of each line, including
|
||||||
|
@ -167,47 +235,12 @@ class screen_t {
|
||||||
/// \return the outputter for this screen.
|
/// \return the outputter for this screen.
|
||||||
outputter_t &outp() { return outp_; }
|
outputter_t &outp() { return outp_; }
|
||||||
|
|
||||||
/// \return whether we believe the cursor is wrapped onto the last line, and that line is
|
/// Update the screen to match the desired output.
|
||||||
/// otherwise empty. This includes both soft and hard wrapping.
|
void update(const wcstring &left_prompt, const wcstring &right_prompt);
|
||||||
bool cursor_is_wrapped_to_own_line() const;
|
|
||||||
|
class scoped_buffer_t;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// This is the main function for the screen putput library. It is used to define the desired
|
|
||||||
/// contents of the screen. The screen command will use its knowledge of the current contents of the
|
|
||||||
/// screen in order to render the desired output using as few terminal commands as possible.
|
|
||||||
///
|
|
||||||
/// \param s the screen on which to write
|
|
||||||
/// \param left_prompt the prompt to prepend to the command line
|
|
||||||
/// \param right_prompt the right prompt, or NULL if none
|
|
||||||
/// \param commandline the command line
|
|
||||||
/// \param explicit_len the number of characters of the "explicit" (non-autosuggestion) portion of
|
|
||||||
/// the command line
|
|
||||||
/// \param colors the colors to use for the comand line
|
|
||||||
/// \param indent the indent to use for the command line
|
|
||||||
/// \param cursor_pos where the cursor is
|
|
||||||
/// \param pager the pager to render below the command line
|
|
||||||
/// \param page_rendering to cache the current pager view
|
|
||||||
/// \param cursor_is_within_pager whether the position is within the pager line (first line)
|
|
||||||
void s_write(screen_t *s, const wcstring &left_prompt, const wcstring &right_prompt,
|
|
||||||
const wcstring &commandline, size_t explicit_len,
|
|
||||||
const std::vector<highlight_spec_t> &colors, const std::vector<int> &indent,
|
|
||||||
size_t cursor_pos, pager_t &pager, page_rendering_t &page_rendering,
|
|
||||||
bool cursor_is_within_pager);
|
|
||||||
|
|
||||||
/// Resets the screen buffer's internal knowledge about the contents of the screen,
|
|
||||||
/// optionally repainting the prompt as well.
|
|
||||||
/// This function assumes that the current line is still valid.
|
|
||||||
void s_reset_line(screen_t *s, bool repaint_prompt = false);
|
|
||||||
|
|
||||||
/// Resets the screen buffer's internal knowldge about the contents of the screen,
|
|
||||||
/// abandoning the current line and going to the next line.
|
|
||||||
/// If clear_to_eos is set,
|
|
||||||
/// The screen width must be provided for the PROMPT_SP hack.
|
|
||||||
void s_reset_abandoning_line(screen_t *s, int screen_width);
|
|
||||||
|
|
||||||
/// Stat stdout and stderr and save result as the current timestamp.
|
|
||||||
void s_save_status(screen_t *s);
|
|
||||||
|
|
||||||
/// Issues an immediate clr_eos.
|
/// Issues an immediate clr_eos.
|
||||||
void screen_force_clear_to_end();
|
void screen_force_clear_to_end();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue