blob: a90e2b75a367290637825497c6df84af45f587db (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
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_
|