1 // Header file for the low level input library.
2 #ifndef INPUT_COMMON_H
3 #define INPUT_COMMON_H
4 
5 #include <stddef.h>
6 
7 #include <queue>
8 
9 #include "common.h"
10 #include "maybe.h"
11 
12 enum class readline_cmd_t {
13     beginning_of_line,
14     end_of_line,
15     forward_char,
16     backward_char,
17     forward_single_char,
18     forward_word,
19     backward_word,
20     forward_bigword,
21     backward_bigword,
22     history_search_backward,
23     history_search_forward,
24     history_prefix_search_backward,
25     history_prefix_search_forward,
26     delete_char,
27     backward_delete_char,
28     kill_line,
29     yank,
30     yank_pop,
31     complete,
32     complete_and_search,
33     pager_toggle_search,
34     beginning_of_history,
35     end_of_history,
36     backward_kill_line,
37     kill_whole_line,
38     kill_word,
39     kill_bigword,
40     backward_kill_word,
41     backward_kill_path_component,
42     backward_kill_bigword,
43     history_token_search_backward,
44     history_token_search_forward,
45     self_insert,
46     self_insert_notfirst,
47     transpose_chars,
48     transpose_words,
49     upcase_word,
50     downcase_word,
51     capitalize_word,
52     togglecase_char,
53     togglecase_selection,
54     execute,
55     beginning_of_buffer,
56     end_of_buffer,
57     repaint_mode,
58     repaint,
59     force_repaint,
60     up_line,
61     down_line,
62     suppress_autosuggestion,
63     accept_autosuggestion,
64     begin_selection,
65     swap_selection_start_stop,
66     end_selection,
67     kill_selection,
68     insert_line_under,
69     insert_line_over,
70     forward_jump,
71     backward_jump,
72     forward_jump_till,
73     backward_jump_till,
74     func_and,
75     func_or,
76     expand_abbr,
77     delete_or_exit,
78     exit,
79     cancel_commandline,
80     cancel,
81     undo,
82     redo,
83     begin_undo_group,
84     end_undo_group,
85     repeat_jump,
86     disable_mouse_tracking,
87     // NOTE: This one has to be last.
88     reverse_repeat_jump
89 };
90 
91 // The range of key codes for inputrc-style keyboard functions.
92 enum { R_END_INPUT_FUNCTIONS = static_cast<int>(readline_cmd_t::reverse_repeat_jump) + 1 };
93 
94 /// Represents an event on the character input stream.
95 enum class char_event_type_t : uint8_t {
96     /// A character was entered.
97     charc,
98 
99     /// A readline event.
100     readline,
101 
102     /// end-of-file was reached.
103     eof,
104 
105     /// An event was handled internally, or an interrupt was received. Check to see if the reader
106     /// loop should exit.
107     check_exit,
108 };
109 
110 /// Hackish: the input style, which describes how char events (only) are applied to the command
111 /// line. Note this is set only after applying bindings; it is not set from readb().
112 enum class char_input_style_t : uint8_t {
113     // Insert characters normally.
114     normal,
115 
116     // Insert characters only if the cursor is not at the beginning. Otherwise, discard them.
117     notfirst,
118 };
119 
120 class char_event_t {
121     union {
122         /// Set if the type is charc.
123         wchar_t c;
124 
125         /// Set if the type is readline.
126         readline_cmd_t rl;
127     } v_{};
128 
129    public:
130     /// The type of event.
131     char_event_type_t type;
132 
133     /// The style to use when inserting characters into the command line.
134     char_input_style_t input_style{char_input_style_t::normal};
135 
136     /// The sequence of characters in the input mapping which generated this event.
137     /// Note that the generic self-insert case does not have any characters, so this would be empty.
138     wcstring seq{};
139 
is_char()140     bool is_char() const { return type == char_event_type_t::charc; }
141 
is_eof()142     bool is_eof() const { return type == char_event_type_t::eof; }
143 
is_check_exit()144     bool is_check_exit() const { return type == char_event_type_t::check_exit; }
145 
is_readline()146     bool is_readline() const { return type == char_event_type_t::readline; }
147 
get_char()148     wchar_t get_char() const {
149         assert(type == char_event_type_t::charc && "Not a char type");
150         return v_.c;
151     }
152 
maybe_char()153     maybe_t<wchar_t> maybe_char() const {
154         if (type == char_event_type_t::charc) {
155             return v_.c;
156         } else {
157             return none();
158         }
159     }
160 
get_readline()161     readline_cmd_t get_readline() const {
162         assert(type == char_event_type_t::readline && "Not a readline type");
163         return v_.rl;
164     }
165 
char_event_t(wchar_t c)166     /* implicit */ char_event_t(wchar_t c) : type(char_event_type_t::charc) { v_.c = c; }
167 
168     /* implicit */ char_event_t(readline_cmd_t rl, wcstring seq = {})
type(char_event_type_t::readline)169         : type(char_event_type_t::readline), seq(std::move(seq)) {
170         v_.rl = rl;
171     }
172 
char_event_t(char_event_type_t type)173     /* implicit */ char_event_t(char_event_type_t type) : type(type) {
174         assert(type != char_event_type_t::charc && type != char_event_type_t::readline &&
175                "Cannot create a char event with this constructor");
176     }
177 };
178 
179 /// Adjust the escape timeout.
180 class environment_t;
181 void update_wait_on_escape_ms(const environment_t &vars);
182 
183 /// A class which knows how to produce a stream of input events.
184 /// This is a base class; you may subclass it for its override points.
185 class input_event_queue_t {
186    public:
187     /// Construct from a file descriptor \p in, and an interrupt handler \p handler.
188     explicit input_event_queue_t(int in = STDIN_FILENO);
189 
190     /// Function used by input_readch to read bytes from stdin until enough bytes have been read to
191     /// convert them to a wchar_t. Conversion is done using mbrtowc. If a character has previously
192     /// been read and then 'unread' using \c input_common_unreadch, that character is returned.
193     char_event_t readch();
194 
195     /// Like readch(), except it will wait at most WAIT_ON_ESCAPE milliseconds for a
196     /// character to be available for reading.
197     /// \return none on timeout, the event on success.
198     maybe_t<char_event_t> readch_timed();
199 
200     /// Enqueue a character or a readline function to the queue of unread characters that
201     /// readch will return before actually reading from fd 0.
202     void push_back(const char_event_t &ch);
203 
204     /// Add a character or a readline function to the front of the queue of unread characters.  This
205     /// will be the next character returned by readch.
206     void push_front(const char_event_t &ch);
207 
208     /// Add multiple characters or readline events to the front of the queue of unread characters.
209     /// The order of the provided events is not changed, i.e. they are not inserted in reverse
210     /// order.
211     template <typename Iterator>
insert_front(const Iterator begin,const Iterator end)212     void insert_front(const Iterator begin, const Iterator end) {
213         queue_.insert(queue_.begin(), begin, end);
214     }
215 
216     /// Override point for when we are about to (potentially) block in select(). The default does
217     /// nothing.
218     virtual void prepare_to_select();
219 
220     /// Override point for when when select() is interrupted by a signal. The default does nothing.
221     virtual void select_interrupted();
222 
223     virtual ~input_event_queue_t();
224 
225    private:
226     /// \return if we have any lookahead.
has_lookahead()227     bool has_lookahead() const { return !queue_.empty(); }
228 
229     /// \return the next event in the queue, or none if the queue is empty.
230     maybe_t<char_event_t> try_pop();
231 
232     int in_{0};
233     std::deque<char_event_t> queue_;
234 };
235 
236 #endif
237