3
3
4
4
namespace services
5
5
{
6
- Terminal::Terminal (infra::MemoryRange<uint8_t > bufferQueue, infra::BoundedDeque<infra::BoundedString::WithStorage<MaxBuffer>>& history, hal::SerialCommunication& communication, services::Tracer& tracer)
7
- : queue(bufferQueue, [this ]
8
- {
9
- HandleInput ();
10
- })
11
- , history(history)
12
- , tracer(tracer)
13
- {
14
- communication.ReceiveData ([this ](infra::ConstByteRange data)
15
- {
16
- queue.AddFromInterrupt (data);
17
- });
18
- Print (state.prompt );
19
- }
20
-
21
- void Terminal::Print (const char * message)
22
- {
23
- tracer.Continue () << message;
24
- }
25
-
26
- void Terminal::HandleInput ()
27
- {
28
- while (!queue.Empty ())
29
- HandleChar (static_cast <char >(queue.Get ()));
30
- }
31
-
32
- void Terminal::HandleChar (char c)
33
- {
34
- if (state.processingEscapeSequence )
35
- state.processingEscapeSequence = ProcessEscapeSequence (c);
36
- else
37
- HandleNonEscapeChar (c);
38
- }
39
-
40
- void Terminal::HandleNonEscapeChar (char c)
41
- {
42
- switch (c)
43
- {
44
- case ' \n ' :
45
- break ;
46
- case ' \r ' :
47
- ProcessEnter ();
48
- break ;
49
- case 27 :
50
- state.processingEscapeSequence = true ;
51
- break ;
52
- case ' \b ' :
53
- case ' \x7F ' :
54
- ProcessBackspace ();
55
- break ;
56
- case 1 : // ctrl-a
57
- MoveCursorHome ();
58
- break ;
59
- case 2 : // ctrl-b
60
- MoveCursorLeft ();
61
- break ;
62
- case 3 : // ctrl-c
63
- OverwriteBuffer (" " );
64
- break ;
65
- case 4 : // ctrl-d
66
- ProcessDelete ();
67
- break ;
68
- case 5 : // ctrl-e
69
- MoveCursorEnd ();
70
- break ;
71
- case 6 : // ctrl-f
72
- MoveCursorRight ();
73
- break ;
74
- case 14 : // ctrl-n
75
- HistoryForward ();
76
- break ;
77
- case 16 : // ctrl-p
78
- HistoryBackward ();
79
- break ;
80
- default :
81
- SendNonEscapeChar (c);
82
- break ;
83
- }
84
- }
85
-
86
- bool Terminal::ProcessEscapeSequence (char in)
87
- {
88
- static const infra::BoundedConstString ignoredEscapeCharacters = " ;[O0123456789" ;
89
- if (ignoredEscapeCharacters.find (in) != infra::BoundedConstString::npos)
90
- return true ;
91
-
92
- switch (in)
93
- {
94
- case ' A' :
95
- HistoryBackward ();
96
- break ;
97
- case ' B' :
98
- HistoryForward ();
99
- break ;
100
- case ' C' :
101
- MoveCursorRight ();
102
- break ;
103
- case ' D' :
104
- MoveCursorLeft ();
105
- break ;
106
- case ' F' :
107
- MoveCursorEnd ();
108
- break ;
109
- case ' H' :
110
- MoveCursorHome ();
111
- break ;
112
- default :
113
- SendBell ();
114
- break ;
115
- }
116
-
117
- return false ;
118
- }
119
-
120
- void Terminal::ProcessEnter ()
121
- {
122
- Print (" \r\n " );
123
-
124
- if (buffer.size () > 0 )
125
- {
126
- StoreHistory (buffer);
127
- OnData (buffer);
128
- }
129
-
130
- buffer.clear ();
131
- state.cursorPosition = 0 ;
132
- Print (state.prompt );
133
- }
134
-
135
- void Terminal::ProcessBackspace ()
136
- {
137
- MoveCursorLeft ();
138
- ProcessDelete ();
139
- }
140
-
141
- void Terminal::ProcessDelete ()
142
- {
143
- if (state.cursorPosition < buffer.size ())
144
- EraseCharacterUnderCursor ();
145
- else
146
- SendBell ();
147
- }
148
-
149
- void Terminal::EraseCharacterUnderCursor ()
150
- {
151
- assert (state.cursorPosition < buffer.size ());
152
-
153
- if (buffer.size () == state.cursorPosition + 1 )
154
- buffer.pop_back ();
155
- else
156
- {
157
- std::rotate (std::next (buffer.begin (), state.cursorPosition ), std::next (buffer.begin (), state.cursorPosition + 1 ), buffer.end ());
158
- buffer = buffer.substr (0 , buffer.size () - 1 );
159
- tracer.Continue () << ByteRangeAsString (infra::MakeRange (reinterpret_cast <const uint8_t *>(std::next (buffer.begin (), state.cursorPosition )), reinterpret_cast <const uint8_t *>(buffer.end ())));
160
- }
161
-
162
- Print (" \b " );
163
-
164
- for (uint32_t i = buffer.size (); i > state.cursorPosition ; --i)
165
- tracer.Continue () << ' \b ' ;
166
- }
167
-
168
- void Terminal::MoveCursorHome ()
169
- {
170
- state.cursorPosition = 0 ;
171
- tracer.Continue () << ' \r ' ;
172
- Print (state.prompt );
173
- }
174
-
175
- void Terminal::MoveCursorEnd ()
176
- {
177
- if (buffer.size () > 0 && state.cursorPosition < buffer.size ())
178
- tracer.Continue () << ByteRangeAsString (infra::MakeRange (reinterpret_cast <const uint8_t *>(std::next (buffer.begin (), state.cursorPosition )), reinterpret_cast <const uint8_t *>(buffer.end ())));
179
- state.cursorPosition = buffer.size ();
180
- }
181
-
182
- void Terminal::MoveCursorLeft ()
183
- {
184
- if (state.cursorPosition > 0 )
185
- {
186
- tracer.Continue () << ' \b ' ;
187
- --state.cursorPosition ;
188
- }
189
- else
190
- SendBell ();
191
- }
192
-
193
- void Terminal::MoveCursorRight ()
194
- {
195
- if (state.cursorPosition < buffer.size ())
196
- {
197
- tracer.Continue () << buffer[state.cursorPosition ];
198
- ++state.cursorPosition ;
199
- }
200
- else
201
- SendBell ();
202
- }
203
-
204
- void Terminal::StoreHistory (infra::BoundedString element)
205
- {
206
- if (history.full ())
207
- history.pop_front ();
208
-
209
- history.push_back (buffer);
210
- state.historyIndex = history.size ();
211
- }
212
-
213
- void Terminal::OverwriteBuffer (infra::BoundedConstString element)
214
- {
215
- std::size_t previousSize = buffer.size ();
216
- buffer.assign (element);
217
-
218
- tracer.Continue () << ' \r ' ;
219
- Print (state.prompt );
220
-
221
- if (buffer.size () > 0 )
222
- tracer.Continue () << buffer;
223
-
224
- for (std::size_t size = buffer.size (); size < previousSize; ++size)
225
- tracer.Continue () << ' ' ;
226
-
227
- for (std::size_t size = buffer.size (); size < previousSize; ++size)
228
- tracer.Continue () << ' \b ' ;
229
-
230
- state.cursorPosition = buffer.size ();
231
- }
232
-
233
- void Terminal::HistoryForward ()
234
- {
235
- if (!history.empty () && state.historyIndex < history.size () - 1 )
236
- OverwriteBuffer (history[++state.historyIndex ]);
237
- else
238
- OverwriteBuffer (" " );
239
- }
240
-
241
- void Terminal::HistoryBackward ()
242
- {
243
- if (state.historyIndex > 0 )
244
- OverwriteBuffer (history[--state.historyIndex ]);
245
- else
246
- SendBell ();
247
- }
248
-
249
- void Terminal::SendNonEscapeChar (char c)
250
- {
251
- if (c > 31 && c < 127 )
252
- {
253
- tracer.Continue () << c;
254
- buffer.push_back (c);
255
- state.cursorPosition ++;
256
- }
257
- else
258
- SendBell ();
259
- }
260
-
261
- void Terminal::SendBell ()
262
- {
263
- tracer.Continue () << ' \a ' ;
264
- }
265
-
266
6
bool TerminalCommands::ProcessCommand (infra::BoundedConstString data)
267
7
{
268
8
infra::Tokenizer tokenizer (data, ' ' );
@@ -283,19 +23,4 @@ namespace services
283
23
else
284
24
return false ;
285
25
}
286
-
287
- TerminalWithCommandsImpl::TerminalWithCommandsImpl (infra::MemoryRange<uint8_t > bufferQueue, infra::BoundedDeque<infra::BoundedString::WithStorage<MaxBuffer>>& history, hal::SerialCommunication& communication, services::Tracer& tracer)
288
- : services::Terminal(bufferQueue, history, communication, tracer)
289
- {}
290
-
291
- void TerminalWithCommandsImpl::OnData (infra::BoundedConstString data)
292
- {
293
- bool commandProcessed = NotifyObservers ([data](TerminalCommands& observer)
294
- {
295
- return observer.ProcessCommand (data);
296
- });
297
-
298
- if (!commandProcessed)
299
- Print (" Unrecognized command." );
300
- }
301
26
}
0 commit comments