aboutsummaryrefslogtreecommitdiff
path: root/src/ui/terminal/line.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/terminal/line.h')
-rw-r--r--src/ui/terminal/line.h101
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_