Let read read from fds other than 0

This allows

read </dev/tty

to work.

Fixes #7358
This commit is contained in:
Fabian Homborg
2020-09-30 18:29:00 +02:00
parent ca0f5686ff
commit 0951a706cf
7 changed files with 38 additions and 20 deletions

View File

@@ -609,7 +609,7 @@ class reader_data_t : public std::enable_shared_from_this<reader_data_t> {
reader_data_t(std::shared_ptr<parser_t> parser, history_t *hist, reader_config_t &&conf)
: conf(std::move(conf)),
parser_ref(std::move(parser)),
inputter(*parser_ref),
inputter(*parser_ref, conf.stdin),
history(hist) {}
void update_buff_pos(editable_line_t *el, maybe_t<size_t> new_pos = none_t());
@@ -2122,7 +2122,7 @@ static void reader_interactive_init(parser_t &parser) {
}
// Configure terminal attributes
if (tcsetattr(0, TCSANOW, &shell_modes) == -1) {
if (tcsetattr(STDIN_FILENO, TCSANOW, &shell_modes) == -1) {
if (errno == EIO) {
redirect_tty_output();
}
@@ -2700,7 +2700,7 @@ maybe_t<char_event_t> reader_data_t::read_normal_chars(readline_loop_state_t &rl
while (accumulated_chars.size() < limit) {
bool allow_commands = (accumulated_chars.empty());
auto evt = inputter.readch(allow_commands);
if (!event_is_normal_char(evt) || !can_read(STDIN_FILENO)) {
if (!event_is_normal_char(evt) || !can_read(conf.stdin)) {
event_needing_handling = std::move(evt);
break;
} else if (evt.input_style == char_input_style_t::notfirst && accumulated_chars.empty() &&
@@ -3636,8 +3636,10 @@ maybe_t<wcstring> reader_data_t::readline(int nchars_or_0) {
/// A helper that kicks off syntax highlighting, autosuggestion computing, and repaints.
auto color_suggest_repaint_now = [this] {
this->update_autosuggestion();
this->super_highlight_me_plenty();
if (conf.stdin == STDIN_FILENO) {
this->update_autosuggestion();
this->super_highlight_me_plenty();
}
if (this->is_repaint_needed()) this->layout_and_repaint(L"toplevel");
this->force_exec_prompt_and_repaint = false;
};
@@ -3646,10 +3648,10 @@ maybe_t<wcstring> reader_data_t::readline(int nchars_or_0) {
force_exec_prompt_and_repaint = true;
// Get the current terminal modes. These will be restored when the function returns.
if (tcgetattr(STDIN_FILENO, &old_modes) == -1 && errno == EIO) redirect_tty_output();
if (tcgetattr(conf.stdin, &old_modes) == -1 && errno == EIO) redirect_tty_output();
// Set the new modes.
if (tcsetattr(0, TCSANOW, &shell_modes) == -1) {
if (tcsetattr(conf.stdin, TCSANOW, &shell_modes) == -1) {
int err = errno;
if (err == EIO) {
redirect_tty_output();
@@ -3756,7 +3758,7 @@ maybe_t<wcstring> reader_data_t::readline(int nchars_or_0) {
// Redraw the command line. This is what ensures the autosuggestion is hidden, etc. after the
// user presses enter.
if (this->is_repaint_needed()) this->layout_and_repaint(L"prepare to execute");
if (this->is_repaint_needed() || conf.stdin != STDIN_FILENO) this->layout_and_repaint(L"prepare to execute");
// Emit a newline so that the output is on the line after the command.
// But do not emit a newline if the cursor has wrapped onto a new line all its own - see #6826.
@@ -3764,6 +3766,12 @@ maybe_t<wcstring> reader_data_t::readline(int nchars_or_0) {
ignore_result(write(STDOUT_FILENO, "\n", 1));
}
// HACK: If stdin isn't the same terminal as stdout, we just moved the cursor.
// For now, just reset it to the beginning of the line.
if (conf.stdin != STDIN_FILENO) {
ignore_result(write(STDOUT_FILENO, "\r", 1));
}
// Ensure we have no pager contents when we exit.
if (!pager.empty()) {
// Clear to end of screen to erase the pager contents.
@@ -3775,7 +3783,7 @@ maybe_t<wcstring> reader_data_t::readline(int nchars_or_0) {
if (s_exit_state != exit_state_t::finished_handlers) {
// The order of the two conditions below is important. Try to restore the mode
// in all cases, but only complain if interactive.
if (tcsetattr(0, TCSANOW, &old_modes) == -1 &&
if (tcsetattr(conf.stdin, TCSANOW, &old_modes) == -1 &&
session_interactivity() != session_interactivity_t::not_interactive) {
if (errno == EIO) redirect_tty_output();
wperror(L"tcsetattr"); // return to previous mode