diff options
Diffstat (limited to 'src/ui/terminal/line.h')
-rw-r--r-- | src/ui/terminal/line.h | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/src/ui/terminal/line.h b/src/ui/terminal/line.h new file mode 100644 index 0000000..a90e2b7 --- /dev/null +++ b/src/ui/terminal/line.h @@ -0,0 +1,101 @@ +// Copyright 2021 Benjamin Barenblat +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +// A terminal driver for single-line UIs. + +#ifndef EC_SRC_UI_TERMINAL_LINE_H_ +#define EC_SRC_UI_TERMINAL_LINE_H_ + +#include <termios.h> + +#include <thread> + +#include "third_party/abseil/absl/base/thread_annotations.h" +#include "third_party/abseil/absl/strings/string_view.h" +#include "third_party/abseil/absl/synchronization/mutex.h" + +namespace ec { + +// The driver itself. +// +// This class is thread-safe, but there are still some sharp edges. See the +// warning in the constructor documentation about additional steps required to +// use this class in a multi-threaded program. +class TerminalLine final { + public: + // Starts driving the standard input and standard output of the process. + // + // Multi-threading warning: You must block SIGWINCH in all your program's + // threads before constructing an instance of this class. This class detects + // failure to block SIGWINCH in the calling thread, but it cannot check all + // the threads. It is your responsibility to block SIGWINCH everywhere! + // (BlockSigwinch is a convenience function to do this in the current thread.) + explicit TerminalLine(); + + TerminalLine(const TerminalLine&) = delete; + TerminalLine& operator=(const TerminalLine&) = delete; + + ~TerminalLine() noexcept; + + void SetLine(std::string) ABSL_LOCKS_EXCLUDED(mu_); + void Refresh() ABSL_LOCKS_EXCLUDED(mu_); + + void SetLineImmediately(std::string text) { + SetLine(text); + Refresh(); + } + + char GetChar(); + char interrupt_char() const noexcept { return current_termios_.c_cc[VINTR]; } + char quit_char() const noexcept { return current_termios_.c_cc[VQUIT]; } + char suspend_char() const noexcept { return current_termios_.c_cc[VSUSP]; } +#ifdef VDSUSP + char delayed_suspend_char() const noexcept { + return current_termios_.c_cc[VDSUSP]; + } +#endif + + void Beep() ABSL_LOCKS_EXCLUDED(mu_); + + // Prints the specified message on a new line, and redisplays the original + // text on the line after that. + void PrintLine(absl::string_view) ABSL_LOCKS_EXCLUDED(mu_); + + private: + void EnterRawMode(); + void ExitRawMode() noexcept; + + void ReportSigwinch() ABSL_LOCKS_EXCLUDED(mu_); + + void WriteRaw(absl::string_view bytes) ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_); + + termios original_termios_, current_termios_; + + std::thread sigwinch_watcher_; + + absl::Mutex mu_; + int columns_ ABSL_GUARDED_BY(mu_); + std::string line_ ABSL_GUARDED_BY(mu_); +}; + +// Names for control characters. +constexpr char kControlD = '\x04'; +constexpr char kControlU = '\x15'; + +// A convenience function to block SIGWINCH in the calling thread. +void BlockSigwinch(); + +} // namespace ec + +#endif // EC_SRC_UI_TERMINAL_LINE_H_ |