mirror of
https://github.com/SerenityOS/serenity.git
synced 2025-01-25 19:02:07 -05:00
LibLine: Check if operating on a TTY before using TTY features
This makes the line editor behave well when input is passed in from pipes as well.
This commit is contained in:
parent
a7ea7b3a66
commit
70eb7aa627
2 changed files with 36 additions and 13 deletions
|
@ -250,11 +250,18 @@ void Editor::initialize()
|
||||||
if (m_was_resized)
|
if (m_was_resized)
|
||||||
get_terminal_size();
|
get_terminal_size();
|
||||||
|
|
||||||
auto* term = getenv("TERM");
|
if (m_configuration.operation_mode == Configuration::Unset) {
|
||||||
if (StringView { term }.starts_with("xterm"))
|
auto istty = isatty(STDIN_FILENO) && isatty(STDOUT_FILENO);
|
||||||
m_configuration.set(Configuration::Full);
|
if (!istty) {
|
||||||
else
|
m_configuration.set(Configuration::NonInteractive);
|
||||||
m_configuration.set(Configuration::NoEscapeSequences);
|
} else {
|
||||||
|
auto* term = getenv("TERM");
|
||||||
|
if (StringView { term }.starts_with("xterm"))
|
||||||
|
m_configuration.set(Configuration::Full);
|
||||||
|
else
|
||||||
|
m_configuration.set(Configuration::NoEscapeSequences);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Because we use our own line discipline which includes echoing,
|
// Because we use our own line discipline which includes echoing,
|
||||||
// we disable ICANON and ECHO.
|
// we disable ICANON and ECHO.
|
||||||
|
@ -272,15 +279,26 @@ auto Editor::get_line(const String& prompt) -> Result<String, Editor::Error>
|
||||||
initialize();
|
initialize();
|
||||||
m_is_editing = true;
|
m_is_editing = true;
|
||||||
|
|
||||||
if (m_configuration.operation_mode == Configuration::NoEscapeSequences) {
|
if (m_configuration.operation_mode == Configuration::NoEscapeSequences || m_configuration.operation_mode == Configuration::NonInteractive) {
|
||||||
// Do not use escape sequences, instead, use LibC's getline.
|
// Do not use escape sequences, instead, use LibC's getline.
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
char* line = nullptr;
|
char* line = nullptr;
|
||||||
fputs(prompt.characters(), stderr);
|
// Show the prompt only on interactive mode (NoEscapeSequences in this case).
|
||||||
size_t line_length = getline(&line, &size, stdin);
|
if (m_configuration.operation_mode != Configuration::NonInteractive)
|
||||||
|
fputs(prompt.characters(), stderr);
|
||||||
|
auto line_length = getline(&line, &size, stdin);
|
||||||
|
// getline() returns -1 and sets errno=0 on EOF.
|
||||||
|
if (line_length == -1) {
|
||||||
|
if (line)
|
||||||
|
free(line);
|
||||||
|
if (errno == 0)
|
||||||
|
return Error::Eof;
|
||||||
|
|
||||||
|
return Error::ReadFailure;
|
||||||
|
}
|
||||||
restore();
|
restore();
|
||||||
if (line) {
|
if (line) {
|
||||||
String result { line, line_length, Chomp };
|
String result { line, (size_t)line_length, Chomp };
|
||||||
free(line);
|
free(line);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -429,7 +447,10 @@ void Editor::handle_read_event()
|
||||||
Utf8View input_view { StringView { m_incomplete_data.data(), valid_bytes } };
|
Utf8View input_view { StringView { m_incomplete_data.data(), valid_bytes } };
|
||||||
size_t consumed_code_pointss = 0;
|
size_t consumed_code_pointss = 0;
|
||||||
|
|
||||||
enum Amount { Character, Word };
|
enum Amount {
|
||||||
|
Character,
|
||||||
|
Word,
|
||||||
|
};
|
||||||
auto do_cursor_left = [&](Amount amount) {
|
auto do_cursor_left = [&](Amount amount) {
|
||||||
if (m_cursor > 0) {
|
if (m_cursor > 0) {
|
||||||
if (amount == Word) {
|
if (amount == Word) {
|
||||||
|
@ -565,12 +586,12 @@ void Editor::handle_read_event()
|
||||||
ctrl_held = false;
|
ctrl_held = false;
|
||||||
continue;
|
continue;
|
||||||
case 'D': // left
|
case 'D': // left
|
||||||
do_cursor_left(ctrl_held ? Word : Character);
|
do_cursor_left(ctrl_held ? Word : Character);
|
||||||
m_state = InputState::Free;
|
m_state = InputState::Free;
|
||||||
ctrl_held = false;
|
ctrl_held = false;
|
||||||
continue;
|
continue;
|
||||||
case 'C': // right
|
case 'C': // right
|
||||||
do_cursor_right(ctrl_held ? Word : Character);
|
do_cursor_right(ctrl_held ? Word : Character);
|
||||||
m_state = InputState::Free;
|
m_state = InputState::Free;
|
||||||
ctrl_held = false;
|
ctrl_held = false;
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -61,8 +61,10 @@ struct Configuration {
|
||||||
Eager,
|
Eager,
|
||||||
};
|
};
|
||||||
enum OperationMode {
|
enum OperationMode {
|
||||||
|
Unset,
|
||||||
Full,
|
Full,
|
||||||
NoEscapeSequences,
|
NoEscapeSequences,
|
||||||
|
NonInteractive,
|
||||||
};
|
};
|
||||||
|
|
||||||
Configuration()
|
Configuration()
|
||||||
|
@ -82,7 +84,7 @@ struct Configuration {
|
||||||
|
|
||||||
RefreshBehaviour refresh_behaviour { RefreshBehaviour::Lazy };
|
RefreshBehaviour refresh_behaviour { RefreshBehaviour::Lazy };
|
||||||
TokenSplitMechanism split_mechanism { TokenSplitMechanism::Spaces };
|
TokenSplitMechanism split_mechanism { TokenSplitMechanism::Spaces };
|
||||||
OperationMode operation_mode { OperationMode::Full };
|
OperationMode operation_mode { OperationMode::Unset };
|
||||||
};
|
};
|
||||||
|
|
||||||
class Editor : public Core::Object {
|
class Editor : public Core::Object {
|
||||||
|
|
Loading…
Add table
Reference in a new issue