FTXUI/src/ftxui/component/terminal_input_parser.cpp

260 lines
5.9 KiB
C++
Raw Normal View History

#include "ftxui/component/terminal_input_parser.hpp"
namespace ftxui {
TerminalInputParser::TerminalInputParser(Sender<Event> out)
: out_(std::move(out)) {}
void TerminalInputParser::Timeout(int time) {
timeout_ += time;
if (timeout_ < 50)
return;
timeout_ = 0;
if (pending_.size())
Send(SPECIAL);
}
void TerminalInputParser::Add(char c) {
pending_ += c;
timeout_ = 0;
position_ = -1;
Send(Parse());
}
unsigned char TerminalInputParser::Current() {
return pending_[position_];
}
bool TerminalInputParser::Eat() {
position_++;
return position_ < (int)pending_.size();
}
2021-04-19 00:32:38 +08:00
void TerminalInputParser::Send(TerminalInputParser::Output output) {
switch (output.type) {
case UNCOMPLETED:
return;
case DROP:
2021-04-19 00:32:38 +08:00
break;
case CHARACTER:
out_->Send(Event::Character(std::move(pending_)));
2021-04-19 00:32:38 +08:00
break;
case SPECIAL:
out_->Send(Event::Special(std::move(pending_)));
2021-04-19 00:32:38 +08:00
break;
case MOUSE_MOVE:
out_->Send(
Event::MouseMove(std::move(pending_), output.mouse.x, output.mouse.y));
break;
case MOUSE_UP:
out_->Send(
Event::MouseUp(std::move(pending_), output.mouse.x, output.mouse.y));
break;
case MOUSE_LEFT_DOWN:
out_->Send(Event::MouseLeftDown(std::move(pending_), output.mouse.x,
output.mouse.y));
break;
case MOUSE_LEFT_MOVE:
out_->Send(Event::MouseLeftMove(std::move(pending_), output.mouse.x,
output.mouse.y));
break;
2021-04-19 00:42:42 +08:00
case MOUSE_MIDDLE_DOWN:
out_->Send(Event::MouseMiddleDown(std::move(pending_), output.mouse.x,
output.mouse.y));
break;
case MOUSE_MIDDLE_MOVE:
out_->Send(Event::MouseMiddleMove(std::move(pending_), output.mouse.x,
output.mouse.y));
break;
2021-04-19 00:32:38 +08:00
case MOUSE_RIGHT_DOWN:
out_->Send(Event::MouseRightDown(std::move(pending_), output.mouse.x,
output.mouse.y));
break;
case MOUSE_RIGHT_MOVE:
out_->Send(Event::MouseRightMove(std::move(pending_), output.mouse.x,
output.mouse.y));
break;
case CURSOR_REPORTING:
out_->Send(Event::CursorReporting(std::move(pending_), output.mouse.x,
output.mouse.y));
break;
}
2021-04-19 00:32:38 +08:00
pending_.clear();
}
2021-04-19 00:32:38 +08:00
TerminalInputParser::Output TerminalInputParser::Parse() {
if (!Eat())
return UNCOMPLETED;
switch (Current()) {
case 24: // CAN
case 26: // SUB
return DROP;
case '\x1B':
return ParseESC();
default:
break;
}
if (Current() < 32) // C0
return SPECIAL;
if (Current() == 127) // Delete
return SPECIAL;
return ParseUTF8();
}
2021-04-19 00:32:38 +08:00
TerminalInputParser::Output TerminalInputParser::ParseUTF8() {
unsigned char head = static_cast<unsigned char>(Current());
for (int i = 0; i < 3; ++i, head <<= 1) {
if ((head & 0b11000000) != 0b11000000)
break;
if (!Eat())
return UNCOMPLETED;
}
return CHARACTER;
}
2021-04-19 00:32:38 +08:00
TerminalInputParser::Output TerminalInputParser::ParseESC() {
if (!Eat())
return UNCOMPLETED;
switch (Current()) {
case 'P':
return ParseDCS();
case '[':
return ParseCSI();
case ']':
return ParseOSC();
default:
if (!Eat())
return UNCOMPLETED;
return SPECIAL;
}
}
2021-04-19 00:32:38 +08:00
TerminalInputParser::Output TerminalInputParser::ParseDCS() {
// Parse until the string terminator ST.
while (1) {
if (!Eat())
return UNCOMPLETED;
if (Current() != '\x1B')
continue;
if (!Eat())
return UNCOMPLETED;
if (Current() != '\\')
continue;
return SPECIAL;
}
}
2021-04-19 00:32:38 +08:00
TerminalInputParser::Output TerminalInputParser::ParseCSI() {
int argument;
std::vector<int> arguments;
while (true) {
if (!Eat())
return UNCOMPLETED;
2021-04-19 00:32:38 +08:00
if (Current() >= '0' && Current() <= '9') {
argument *= 10;
argument += int(Current() - '0');
continue;
2021-04-19 00:32:38 +08:00
}
2021-04-19 00:32:38 +08:00
if (Current() == ';') {
arguments.push_back(argument);
argument = 0;
continue;
2021-04-19 00:32:38 +08:00
}
if (Current() >= ' ' && Current() <= '~' && Current() != '<') {
2021-04-19 00:32:38 +08:00
arguments.push_back(argument);
argument = 0;
switch (Current()) {
case 'M':
return ParseMouse(std::move(arguments));
case 'R':
return ParseCursorReporting(std::move(arguments));
2021-04-19 00:32:38 +08:00
default:
return SPECIAL;
}
}
// Invalid ESC in CSI.
if (Current() == '\x1B')
return SPECIAL;
}
}
2021-04-19 00:32:38 +08:00
TerminalInputParser::Output TerminalInputParser::ParseOSC() {
// Parse until the string terminator ST.
while (true) {
if (!Eat())
return UNCOMPLETED;
if (Current() != '\x1B')
continue;
if (!Eat())
return UNCOMPLETED;
if (Current() != '\\')
continue;
return SPECIAL;
}
}
2021-04-19 00:32:38 +08:00
TerminalInputParser::Output TerminalInputParser::ParseMouse(
std::vector<int> arguments) {
if (arguments.size() != 3)
return SPECIAL;
switch(arguments[0]) {
case 32:
return Output(MOUSE_LEFT_DOWN, arguments[1], arguments[2]);
case 64:
return Output(MOUSE_LEFT_MOVE, arguments[1], arguments[2]);
2021-04-19 00:42:42 +08:00
case 33:
return Output(MOUSE_MIDDLE_DOWN, arguments[1], arguments[2]);
case 65:
return Output(MOUSE_MIDDLE_MOVE, arguments[1], arguments[2]);
2021-04-19 00:32:38 +08:00
case 34:
return Output(MOUSE_RIGHT_DOWN, arguments[1], arguments[2]);
case 66:
return Output(MOUSE_RIGHT_MOVE, arguments[1], arguments[2]);
case 35:
return Output(MOUSE_UP, arguments[1], arguments[2]);
case 67:
return Output(MOUSE_MOVE, arguments[1], arguments[2]);
default:
return Output(MOUSE_MOVE, arguments[1], arguments[2]);
2021-04-19 00:32:38 +08:00
}
return SPECIAL;
}
TerminalInputParser::Output TerminalInputParser::ParseCursorReporting(
std::vector<int> arguments) {
if (arguments.size() != 2)
return SPECIAL;
return Output(CURSOR_REPORTING, arguments[0], arguments[1]);
}
} // namespace ftxui