From 4590204701232f3bee50daf69a0d3e62b026c648 Mon Sep 17 00:00:00 2001 From: Benjamin Barenblat Date: Sun, 26 Dec 2021 15:57:13 -0500 Subject: goldfishterm: Don’t hard-code std::cout/STDOUT_FILENO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make terminal-handling code purer by requiring the user pass TERM, a termios struct, and an appropriate ostream rather than querying them from the environment. This eliminates some error-handling code and makes duplicate syscalls less likely. --- goldfishterm/internal/emit.cc | 8 +------- goldfishterm/simple.cc | 34 +++++++--------------------------- goldfishterm/simple.h | 18 +++++++++--------- src/ui/terminal/line.cc | 10 +++++++++- 4 files changed, 26 insertions(+), 44 deletions(-) diff --git a/goldfishterm/internal/emit.cc b/goldfishterm/internal/emit.cc index 2cc7609..608aa3c 100644 --- a/goldfishterm/internal/emit.cc +++ b/goldfishterm/internal/emit.cc @@ -14,15 +14,9 @@ #include "goldfishterm/internal/emit.h" -#include -#include -#include - #include -#include -#include +#include -#include "third_party/abseil/absl/strings/string_view.h" #include "third_party/abseil/absl/time/clock.h" #include "third_party/abseil/absl/types/span.h" diff --git a/goldfishterm/simple.cc b/goldfishterm/simple.cc index 88ceef0..0afa08f 100644 --- a/goldfishterm/simple.cc +++ b/goldfishterm/simple.cc @@ -14,9 +14,7 @@ #include "goldfishterm/simple.h" -#include #include -#include #include #include @@ -33,22 +31,6 @@ namespace { using ::goldfishterm_internal::InterpretStringCapability; using ::goldfishterm_internal::InterpretStringCapabilityInput; -termios StdoutTermios() { - termios tty; - if (tcgetattr(STDOUT_FILENO, &tty) < 0) { - throw std::system_error(errno, std::system_category(), "tcgetattr"); - } - return tty; -} - -absl::string_view TerminalNameFromEnvironment() { - const char* name = getenv("TERM"); - if (name == nullptr) { - throw std::runtime_error("TERM unset"); - } - return name; -} - StringCapability CursorVisibilityCapability(CursorVisibility v) { switch (v) { case CursorVisibility::kInvisible: @@ -64,14 +46,12 @@ StringCapability CursorVisibilityCapability(CursorVisibility v) { } // namespace -SimpleTerminalOutput::SimpleTerminalOutput() - : SimpleTerminalOutput(StdoutTermios()) {} - -SimpleTerminalOutput::SimpleTerminalOutput(const termios& tty) - : terminfo_( - TerminfoEntry::FromSystemDatabase(TerminalNameFromEnvironment())) { - baud_ = cfgetospeed(&tty); -} +SimpleTerminalOutput::SimpleTerminalOutput(absl::string_view terminal_name, + const termios& tty, + std::ostream& out) + : terminfo_(TerminfoEntry::FromSystemDatabase(terminal_name)), + baud_(cfgetospeed(&tty)), + out_(out) {} void SimpleTerminalOutput::SetCursorVisibility(CursorVisibility v) { return Emit(CursorVisibilityCapability(v)); @@ -86,7 +66,7 @@ void SimpleTerminalOutput::Emit( std::move(parameters), /*baud=*/baud_, /*lines_affected=*/1)) .terms, - std::cout); + out_); } } // namespace goldfishterm diff --git a/goldfishterm/simple.h b/goldfishterm/simple.h index 48a7789..0228749 100644 --- a/goldfishterm/simple.h +++ b/goldfishterm/simple.h @@ -17,7 +17,7 @@ #include -#include +#include #include #include "goldfishterm/internal/string_capability.h" @@ -33,15 +33,14 @@ enum class CursorVisibility { kVeryVisible, }; -// Looks up escape sequences for the terminal described in the TERM environment -// variable, and allows sending those escape sequences to standard output. +// Looks up escape sequences for the specified terminal and allows sending those +// escape sequences to the specified ostream. // -// This class is thread-safe, provided you don't mutate the TERM environment -// variable while its constructor is running. +// This class is thread-safe. class SimpleTerminalOutput final { public: - explicit SimpleTerminalOutput(); - explicit SimpleTerminalOutput(const termios&); + explicit SimpleTerminalOutput(absl::string_view terminal_name, const termios&, + std::ostream&); SimpleTerminalOutput(const SimpleTerminalOutput&) noexcept = default; SimpleTerminalOutput& operator=(const SimpleTerminalOutput&) noexcept = @@ -49,9 +48,9 @@ class SimpleTerminalOutput final { SimpleTerminalOutput(SimpleTerminalOutput&&) noexcept = default; SimpleTerminalOutput& operator=(SimpleTerminalOutput&&) noexcept = default; - void Write(absl::string_view s) { std::cout.write(s.data(), s.size()); } + void Write(absl::string_view s) { out_.write(s.data(), s.size()); } - void Flush() { std::cout.flush(); } + void Flush() { out_.flush(); } // Rings the bell. On some terminals, this may flash the screen instead. void Beep() { Emit(StringCapability::kBell); } @@ -74,6 +73,7 @@ class SimpleTerminalOutput final { TerminfoEntry terminfo_; int baud_; + std::ostream& out_; }; } // namespace goldfishterm diff --git a/src/ui/terminal/line.cc b/src/ui/terminal/line.cc index 962b692..e668b28 100644 --- a/src/ui/terminal/line.cc +++ b/src/ui/terminal/line.cc @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -78,7 +79,14 @@ TerminalLine::TerminalLine() { } EnterRawMode(); - tty_ = std::make_unique(current_termios_); + + const char* terminal_name = getenv("TERM"); + if (terminal_name == nullptr) { + // Fall back to a minimal subset of the ANSI capabilities. + terminal_name = "ansi-mini"; + } + tty_ = std::make_unique( + terminal_name, current_termios_, std::cout); sigwinch_watcher_ = std::thread([this] { sigset_t sigwinch = SigsetContaining(SIGWINCH); -- cgit v1.2.3