mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2025-09-21 19:48:16 +08:00
Stop using Sender/Receiver in TerminalInputParser. (#1073)
Some checks failed
Build / Bazel, ${{ matrix.cxx }}, ${{ matrix.os }} (cl, cl, windows-latest) (push) Has been cancelled
Build / Bazel, ${{ matrix.cxx }}, ${{ matrix.os }} (clang, clang++, macos-latest) (push) Has been cancelled
Build / Bazel, ${{ matrix.cxx }}, ${{ matrix.os }} (clang, clang++, ubuntu-latest) (push) Has been cancelled
Build / Bazel, ${{ matrix.cxx }}, ${{ matrix.os }} (gcc, g++, macos-latest) (push) Has been cancelled
Build / Bazel, ${{ matrix.cxx }}, ${{ matrix.os }} (gcc, g++, ubuntu-latest) (push) Has been cancelled
Build / CMake, ${{ matrix.compiler }}, ${{ matrix.os }} (cl, Windows MSVC, windows-latest) (push) Has been cancelled
Build / CMake, ${{ matrix.compiler }}, ${{ matrix.os }} (gcc, Linux GCC, ubuntu-latest) (push) Has been cancelled
Build / CMake, ${{ matrix.compiler }}, ${{ matrix.os }} (llvm, llvm-cov gcov, Linux Clang, ubuntu-latest) (push) Has been cancelled
Build / CMake, ${{ matrix.compiler }}, ${{ matrix.os }} (llvm, llvm-cov gcov, MacOS clang, macos-latest) (push) Has been cancelled
Build / Test modules (llvm, ubuntu-latest) (push) Has been cancelled
Documentation / documentation (push) Has been cancelled
Some checks failed
Build / Bazel, ${{ matrix.cxx }}, ${{ matrix.os }} (cl, cl, windows-latest) (push) Has been cancelled
Build / Bazel, ${{ matrix.cxx }}, ${{ matrix.os }} (clang, clang++, macos-latest) (push) Has been cancelled
Build / Bazel, ${{ matrix.cxx }}, ${{ matrix.os }} (clang, clang++, ubuntu-latest) (push) Has been cancelled
Build / Bazel, ${{ matrix.cxx }}, ${{ matrix.os }} (gcc, g++, macos-latest) (push) Has been cancelled
Build / Bazel, ${{ matrix.cxx }}, ${{ matrix.os }} (gcc, g++, ubuntu-latest) (push) Has been cancelled
Build / CMake, ${{ matrix.compiler }}, ${{ matrix.os }} (cl, Windows MSVC, windows-latest) (push) Has been cancelled
Build / CMake, ${{ matrix.compiler }}, ${{ matrix.os }} (gcc, Linux GCC, ubuntu-latest) (push) Has been cancelled
Build / CMake, ${{ matrix.compiler }}, ${{ matrix.os }} (llvm, llvm-cov gcov, Linux Clang, ubuntu-latest) (push) Has been cancelled
Build / CMake, ${{ matrix.compiler }}, ${{ matrix.os }} (llvm, llvm-cov gcov, MacOS clang, macos-latest) (push) Has been cancelled
Build / Test modules (llvm, ubuntu-latest) (push) Has been cancelled
Documentation / documentation (push) Has been cancelled
Stop using Sender/Receiver in TerminalInputParser. This will help removing usage of thread. At some point, my goal is to have an initialization step when installing the ScreenInteractive so that we can provide the terminal ID synchronously without losing some events. This will help with: https://github.com/ArthurSonzogni/FTXUI/pull/1069
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by the MIT license that can be found in
|
||||
// the LICENSE file.
|
||||
#include <cassert>
|
||||
#include <ftxui/component/event.hpp>
|
||||
#include <vector>
|
||||
#include "ftxui/component/component.hpp"
|
||||
#include "ftxui/component/terminal_input_parser.hpp"
|
||||
@@ -212,16 +213,17 @@ extern "C" int LLVMFuzzerTestOneInput(const char* data, size_t size) {
|
||||
auto screen =
|
||||
Screen::Create(Dimension::Fixed(width), Dimension::Fixed(height));
|
||||
|
||||
auto event_receiver = MakeReceiver<Task>();
|
||||
{
|
||||
auto parser = TerminalInputParser(event_receiver->MakeSender());
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
parser.Add(data[i]);
|
||||
// Generate some events.
|
||||
std::vector<Event> events;
|
||||
auto parser =
|
||||
TerminalInputParser([&](const Event& event) { events.push_back(event); });
|
||||
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
parser.Add(data[i]);
|
||||
}
|
||||
|
||||
Task event;
|
||||
while (event_receiver->Receive(&event)) {
|
||||
component->OnEvent(std::get<Event>(event));
|
||||
for (const auto& event : events) {
|
||||
component->OnEvent(event);
|
||||
auto document = component->Render();
|
||||
Render(screen, document);
|
||||
}
|
||||
|
@@ -84,7 +84,8 @@ constexpr int timeout_milliseconds = 20;
|
||||
|
||||
void EventListener(std::atomic<bool>* quit, Sender<Task> out) {
|
||||
auto console = GetStdHandle(STD_INPUT_HANDLE);
|
||||
auto parser = TerminalInputParser(out->Clone());
|
||||
auto parser =
|
||||
TerminalInputParser([&](Event event) { out->Send(std::move(event)); });
|
||||
while (!*quit) {
|
||||
// Throttle ReadConsoleInput by waiting 250ms, this wait function will
|
||||
// return if there is input in the console.
|
||||
@@ -137,7 +138,8 @@ void EventListener(std::atomic<bool>* quit, Sender<Task> out) {
|
||||
|
||||
// Read char from the terminal.
|
||||
void EventListener(std::atomic<bool>* quit, Sender<Task> out) {
|
||||
auto parser = TerminalInputParser(std::move(out));
|
||||
auto parser =
|
||||
TerminalInputParser([&](Event event) { out->Send(std::move(event)); });
|
||||
|
||||
char c;
|
||||
while (!*quit) {
|
||||
@@ -173,7 +175,8 @@ int CheckStdinReady(int usec_timeout) {
|
||||
|
||||
// Read char from the terminal.
|
||||
void EventListener(std::atomic<bool>* quit, Sender<Task> out) {
|
||||
auto parser = TerminalInputParser(std::move(out));
|
||||
auto parser =
|
||||
TerminalInputParser([&](Event event) { out->Send(std::move(event)); });
|
||||
|
||||
while (!*quit) {
|
||||
if (!CheckStdinReady(timeout_microseconds)) {
|
||||
@@ -381,10 +384,10 @@ ScreenInteractive ScreenInteractive::Fullscreen() {
|
||||
ScreenInteractive ScreenInteractive::FullscreenPrimaryScreen() {
|
||||
auto terminal = Terminal::Size();
|
||||
return {
|
||||
Dimension::Fullscreen,
|
||||
terminal.dimx,
|
||||
terminal.dimy,
|
||||
/*use_alternative_screen=*/false,
|
||||
Dimension::Fullscreen,
|
||||
terminal.dimx,
|
||||
terminal.dimy,
|
||||
/*use_alternative_screen=*/false,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -409,7 +412,7 @@ ScreenInteractive ScreenInteractive::TerminalOutput() {
|
||||
return {
|
||||
Dimension::TerminalOutput,
|
||||
terminal.dimx,
|
||||
terminal.dimy, // Best guess.
|
||||
terminal.dimy, // Best guess.
|
||||
/*use_alternative_screen=*/false,
|
||||
};
|
||||
}
|
||||
@@ -421,8 +424,8 @@ ScreenInteractive ScreenInteractive::FitComponent() {
|
||||
auto terminal = Terminal::Size();
|
||||
return {
|
||||
Dimension::FitComponent,
|
||||
terminal.dimx, // Best guess.
|
||||
terminal.dimy, // Best guess.
|
||||
terminal.dimx, // Best guess.
|
||||
terminal.dimy, // Best guess.
|
||||
false,
|
||||
};
|
||||
}
|
||||
|
@@ -27,9 +27,9 @@ namespace {
|
||||
// Capture the standard output (stdout) to a string.
|
||||
class StdCapture {
|
||||
public:
|
||||
explicit StdCapture(std::string* captured)
|
||||
: captured_(captured) {
|
||||
if (pipe(pipefd_) != 0) return;
|
||||
explicit StdCapture(std::string* captured) : captured_(captured) {
|
||||
if (pipe(pipefd_) != 0)
|
||||
return;
|
||||
old_stdout_ = dup(fileno(stdout));
|
||||
fflush(stdout);
|
||||
dup2(pipefd_[1], fileno(stdout));
|
||||
@@ -188,9 +188,7 @@ TEST(ScreenInteractive, FixedSizeInitialFrame) {
|
||||
auto capture = StdCapture(&output);
|
||||
|
||||
auto screen = ScreenInteractive::FixedSize(2, 2);
|
||||
auto component = Renderer([&] {
|
||||
return text("AB");
|
||||
});
|
||||
auto component = Renderer([&] { return text("AB"); });
|
||||
|
||||
Loop loop(&screen, component);
|
||||
loop.RunOnce();
|
||||
@@ -241,7 +239,6 @@ TEST(ScreenInteractive, FixedSizeInitialFrame) {
|
||||
"\r\n"sv;
|
||||
ASSERT_EQ(expected, output);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
} // namespace ftxui
|
||||
|
@@ -5,7 +5,7 @@
|
||||
|
||||
#include <cstdint> // for uint32_t
|
||||
#include <ftxui/component/mouse.hpp> // for Mouse, Mouse::Button, Mouse::Motion
|
||||
#include <ftxui/component/receiver.hpp> // for SenderImpl, Sender
|
||||
#include <functional> // for std::function
|
||||
#include <map>
|
||||
#include <memory> // for unique_ptr, allocator
|
||||
#include <utility> // for move
|
||||
@@ -90,7 +90,7 @@ const std::map<std::string, std::string> g_uniformize = {
|
||||
{"\x1B[X", "\x1B[24~"}, // F12
|
||||
};
|
||||
|
||||
TerminalInputParser::TerminalInputParser(Sender<Task> out)
|
||||
TerminalInputParser::TerminalInputParser(std::function<void(Event)> out)
|
||||
: out_(std::move(out)) {}
|
||||
|
||||
void TerminalInputParser::Timeout(int time) {
|
||||
@@ -131,7 +131,7 @@ void TerminalInputParser::Send(TerminalInputParser::Output output) {
|
||||
return;
|
||||
|
||||
case CHARACTER:
|
||||
out_->Send(Event::Character(std::move(pending_)));
|
||||
out_(Event::Character(std::move(pending_)));
|
||||
pending_.clear();
|
||||
return;
|
||||
|
||||
@@ -140,25 +140,25 @@ void TerminalInputParser::Send(TerminalInputParser::Output output) {
|
||||
if (it != g_uniformize.end()) {
|
||||
pending_ = it->second;
|
||||
}
|
||||
out_->Send(Event::Special(std::move(pending_)));
|
||||
out_(Event::Special(std::move(pending_)));
|
||||
pending_.clear();
|
||||
}
|
||||
return;
|
||||
|
||||
case MOUSE:
|
||||
out_->Send(Event::Mouse(std::move(pending_), output.mouse)); // NOLINT
|
||||
out_(Event::Mouse(std::move(pending_), output.mouse)); // NOLINT
|
||||
pending_.clear();
|
||||
return;
|
||||
|
||||
case CURSOR_POSITION:
|
||||
out_->Send(Event::CursorPosition(std::move(pending_), // NOLINT
|
||||
output.cursor.x, // NOLINT
|
||||
output.cursor.y)); // NOLINT
|
||||
out_(Event::CursorPosition(std::move(pending_), // NOLINT
|
||||
output.cursor.x, // NOLINT
|
||||
output.cursor.y)); // NOLINT
|
||||
pending_.clear();
|
||||
return;
|
||||
|
||||
case CURSOR_SHAPE:
|
||||
out_->Send(Event::CursorShape(std::move(pending_), output.cursor_shape));
|
||||
out_(Event::CursorShape(std::move(pending_), output.cursor_shape));
|
||||
pending_.clear();
|
||||
return;
|
||||
}
|
||||
|
@@ -4,12 +4,11 @@
|
||||
#ifndef FTXUI_COMPONENT_TERMINAL_INPUT_PARSER
|
||||
#define FTXUI_COMPONENT_TERMINAL_INPUT_PARSER
|
||||
|
||||
#include <functional>
|
||||
#include <string> // for string
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "ftxui/component/mouse.hpp" // for Mouse
|
||||
#include "ftxui/component/receiver.hpp" // for Sender
|
||||
#include "ftxui/component/task.hpp" // for Task
|
||||
#include "ftxui/component/mouse.hpp" // for Mouse
|
||||
|
||||
namespace ftxui {
|
||||
struct Event;
|
||||
@@ -17,7 +16,7 @@ struct Event;
|
||||
// Parse a sequence of |char| accross |time|. Produces |Event|.
|
||||
class TerminalInputParser {
|
||||
public:
|
||||
explicit TerminalInputParser(Sender<Task> out);
|
||||
explicit TerminalInputParser(std::function<void(Event)> out);
|
||||
void Timeout(int time);
|
||||
void Add(char c);
|
||||
|
||||
@@ -62,7 +61,7 @@ class TerminalInputParser {
|
||||
Output ParseMouse(bool altered, bool pressed, std::vector<int> arguments);
|
||||
Output ParseCursorPosition(std::vector<int> arguments);
|
||||
|
||||
Sender<Task> out_;
|
||||
std::function<void(Event)> out_;
|
||||
int position_ = -1;
|
||||
int timeout_ = 0;
|
||||
std::string pending_;
|
||||
|
@@ -2,12 +2,12 @@
|
||||
// Use of this source code is governed by the MIT license that can be found in
|
||||
// the LICENSE file.
|
||||
#include <ftxui/component/mouse.hpp> // for Mouse, Mouse::Left, Mouse::Middle, Mouse::Pressed, Mouse::Released, Mouse::Right
|
||||
#include <ftxui/component/task.hpp> // for Task
|
||||
#include <functional> // for function
|
||||
#include <initializer_list> // for initializer_list
|
||||
#include <memory> // for allocator, unique_ptr
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "ftxui/component/event.hpp" // for Event, Event::Return, Event::ArrowDown, Event::ArrowLeft, Event::ArrowRight, Event::ArrowUp, Event::Backspace, Event::End, Event::Home, Event::Custom, Event::Delete, Event::F1, Event::F10, Event::F11, Event::F12, Event::F2, Event::F3, Event::F4, Event::F5, Event::F6, Event::F7, Event::F8, Event::F9, Event::PageDown, Event::PageUp, Event::Tab, Event::TabReverse, Event::Escape
|
||||
#include "ftxui/component/receiver.hpp" // for MakeReceiver, ReceiverImpl
|
||||
#include "ftxui/component/terminal_input_parser.hpp"
|
||||
#include "gtest/gtest.h" // for AssertionResult, Test, Message, TestPartResult, EXPECT_EQ, EXPECT_TRUE, TEST, EXPECT_FALSE
|
||||
|
||||
@@ -22,228 +22,197 @@ TEST(Event, Character) {
|
||||
for (char c = 'A'; c <= 'Z'; ++c)
|
||||
basic_char.push_back(c);
|
||||
|
||||
auto event_receiver = MakeReceiver<Task>();
|
||||
{
|
||||
auto parser = TerminalInputParser(event_receiver->MakeSender());
|
||||
for (char c : basic_char)
|
||||
parser.Add(c);
|
||||
}
|
||||
std::vector<Event> received_events;
|
||||
auto parser = TerminalInputParser(
|
||||
[&](Event event) { received_events.push_back(std::move(event)); });
|
||||
for (char c : basic_char)
|
||||
parser.Add(c);
|
||||
|
||||
Task received;
|
||||
for (char c : basic_char) {
|
||||
EXPECT_TRUE(event_receiver->Receive(&received));
|
||||
EXPECT_TRUE(std::get<Event>(received).is_character());
|
||||
EXPECT_EQ(c, std::get<Event>(received).character()[0]);
|
||||
for (size_t i = 0; i < basic_char.size(); ++i) {
|
||||
EXPECT_TRUE(received_events[i].is_character());
|
||||
EXPECT_EQ(basic_char[i], received_events[i].character()[0]);
|
||||
}
|
||||
EXPECT_FALSE(event_receiver->Receive(&received));
|
||||
EXPECT_EQ(received_events.size(), basic_char.size());
|
||||
}
|
||||
|
||||
TEST(Event, EscapeKeyWithoutWaiting) {
|
||||
auto event_receiver = MakeReceiver<Task>();
|
||||
{
|
||||
auto parser = TerminalInputParser(event_receiver->MakeSender());
|
||||
parser.Add('\x1B');
|
||||
}
|
||||
std::vector<Event> received_events;
|
||||
auto parser = TerminalInputParser(
|
||||
[&](Event event) { received_events.push_back(std::move(event)); });
|
||||
parser.Add('');
|
||||
|
||||
Task received;
|
||||
EXPECT_FALSE(event_receiver->Receive(&received));
|
||||
EXPECT_TRUE(received_events.empty());
|
||||
}
|
||||
|
||||
TEST(Event, EscapeKeyNotEnoughWait) {
|
||||
auto event_receiver = MakeReceiver<Task>();
|
||||
{
|
||||
auto parser = TerminalInputParser(event_receiver->MakeSender());
|
||||
parser.Add('\x1B');
|
||||
parser.Timeout(49);
|
||||
}
|
||||
std::vector<Event> received_events;
|
||||
auto parser = TerminalInputParser(
|
||||
[&](Event event) { received_events.push_back(std::move(event)); });
|
||||
parser.Add('');
|
||||
parser.Timeout(49);
|
||||
|
||||
Task received;
|
||||
EXPECT_FALSE(event_receiver->Receive(&received));
|
||||
EXPECT_TRUE(received_events.empty());
|
||||
}
|
||||
|
||||
TEST(Event, EscapeKeyEnoughWait) {
|
||||
auto event_receiver = MakeReceiver<Task>();
|
||||
{
|
||||
auto parser = TerminalInputParser(event_receiver->MakeSender());
|
||||
parser.Add('\x1B');
|
||||
parser.Timeout(50);
|
||||
}
|
||||
std::vector<Event> received_events;
|
||||
auto parser = TerminalInputParser(
|
||||
[&](Event event) { received_events.push_back(std::move(event)); });
|
||||
parser.Add('');
|
||||
parser.Timeout(50);
|
||||
|
||||
Task received;
|
||||
EXPECT_TRUE(event_receiver->Receive(&received));
|
||||
EXPECT_EQ(std::get<Event>(received), Event::Escape);
|
||||
EXPECT_FALSE(event_receiver->Receive(&received));
|
||||
EXPECT_EQ(1, received_events.size());
|
||||
EXPECT_EQ(received_events[0], Event::Escape);
|
||||
}
|
||||
|
||||
TEST(Event, EscapeFast) {
|
||||
auto event_receiver = MakeReceiver<Task>();
|
||||
{
|
||||
auto parser = TerminalInputParser(event_receiver->MakeSender());
|
||||
parser.Add('\x1B');
|
||||
parser.Add('a');
|
||||
parser.Add('\x1B');
|
||||
parser.Add('b');
|
||||
parser.Timeout(49);
|
||||
}
|
||||
Task received;
|
||||
EXPECT_TRUE(event_receiver->Receive(&received));
|
||||
EXPECT_EQ(std::get<Event>(received), Event::AltA);
|
||||
EXPECT_TRUE(event_receiver->Receive(&received));
|
||||
EXPECT_EQ(std::get<Event>(received), Event::AltB);
|
||||
EXPECT_FALSE(event_receiver->Receive(&received));
|
||||
std::vector<Event> received_events;
|
||||
auto parser = TerminalInputParser(
|
||||
[&](Event event) { received_events.push_back(std::move(event)); });
|
||||
parser.Add('');
|
||||
parser.Add('a');
|
||||
parser.Add('');
|
||||
parser.Add('b');
|
||||
parser.Timeout(49);
|
||||
|
||||
EXPECT_EQ(2, received_events.size());
|
||||
EXPECT_EQ(received_events[0], Event::AltA);
|
||||
EXPECT_EQ(received_events[1], Event::AltB);
|
||||
}
|
||||
|
||||
TEST(Event, MouseLeftClickPressed) {
|
||||
auto event_receiver = MakeReceiver<Task>();
|
||||
{
|
||||
auto parser = TerminalInputParser(event_receiver->MakeSender());
|
||||
parser.Add('\x1B');
|
||||
parser.Add('[');
|
||||
parser.Add('0');
|
||||
parser.Add(';');
|
||||
parser.Add('1');
|
||||
parser.Add('2');
|
||||
parser.Add(';');
|
||||
parser.Add('4');
|
||||
parser.Add('2');
|
||||
parser.Add('M');
|
||||
}
|
||||
std::vector<Event> received_events;
|
||||
auto parser = TerminalInputParser(
|
||||
[&](Event event) { received_events.push_back(std::move(event)); });
|
||||
parser.Add('');
|
||||
parser.Add('[');
|
||||
parser.Add('0');
|
||||
parser.Add(';');
|
||||
parser.Add('1');
|
||||
parser.Add('2');
|
||||
parser.Add(';');
|
||||
parser.Add('4');
|
||||
parser.Add('2');
|
||||
parser.Add('M');
|
||||
|
||||
Task received;
|
||||
EXPECT_TRUE(event_receiver->Receive(&received));
|
||||
EXPECT_TRUE(std::get<Event>(received).is_mouse());
|
||||
EXPECT_EQ(Mouse::Left, std::get<Event>(received).mouse().button);
|
||||
EXPECT_EQ(12, std::get<Event>(received).mouse().x);
|
||||
EXPECT_EQ(42, std::get<Event>(received).mouse().y);
|
||||
EXPECT_EQ(std::get<Event>(received).mouse().motion, Mouse::Pressed);
|
||||
EXPECT_FALSE(event_receiver->Receive(&received));
|
||||
EXPECT_EQ(1, received_events.size());
|
||||
EXPECT_TRUE(received_events[0].is_mouse());
|
||||
EXPECT_EQ(Mouse::Left, received_events[0].mouse().button);
|
||||
EXPECT_EQ(12, received_events[0].mouse().x);
|
||||
EXPECT_EQ(42, received_events[0].mouse().y);
|
||||
EXPECT_EQ(received_events[0].mouse().motion, Mouse::Pressed);
|
||||
}
|
||||
|
||||
TEST(Event, MouseLeftMoved) {
|
||||
auto event_receiver = MakeReceiver<Task>();
|
||||
{
|
||||
auto parser = TerminalInputParser(event_receiver->MakeSender());
|
||||
parser.Add('\x1B');
|
||||
parser.Add('[');
|
||||
parser.Add('3');
|
||||
parser.Add('2');
|
||||
parser.Add(';');
|
||||
parser.Add('1');
|
||||
parser.Add('2');
|
||||
parser.Add(';');
|
||||
parser.Add('4');
|
||||
parser.Add('2');
|
||||
parser.Add('M');
|
||||
}
|
||||
std::vector<Event> received_events;
|
||||
auto parser = TerminalInputParser(
|
||||
[&](Event event) { received_events.push_back(std::move(event)); });
|
||||
parser.Add('');
|
||||
parser.Add('[');
|
||||
parser.Add('3');
|
||||
parser.Add('2');
|
||||
parser.Add(';');
|
||||
parser.Add('1');
|
||||
parser.Add('2');
|
||||
parser.Add(';');
|
||||
parser.Add('4');
|
||||
parser.Add('2');
|
||||
parser.Add('M');
|
||||
|
||||
Task received;
|
||||
EXPECT_TRUE(event_receiver->Receive(&received));
|
||||
EXPECT_TRUE(std::get<Event>(received).is_mouse());
|
||||
EXPECT_EQ(Mouse::Left, std::get<Event>(received).mouse().button);
|
||||
EXPECT_EQ(12, std::get<Event>(received).mouse().x);
|
||||
EXPECT_EQ(42, std::get<Event>(received).mouse().y);
|
||||
EXPECT_EQ(std::get<Event>(received).mouse().motion, Mouse::Moved);
|
||||
EXPECT_FALSE(event_receiver->Receive(&received));
|
||||
EXPECT_EQ(1, received_events.size());
|
||||
EXPECT_TRUE(received_events[0].is_mouse());
|
||||
EXPECT_EQ(Mouse::Left, received_events[0].mouse().button);
|
||||
EXPECT_EQ(12, received_events[0].mouse().x);
|
||||
EXPECT_EQ(42, received_events[0].mouse().y);
|
||||
EXPECT_EQ(received_events[0].mouse().motion, Mouse::Moved);
|
||||
}
|
||||
|
||||
TEST(Event, MouseLeftClickReleased) {
|
||||
auto event_receiver = MakeReceiver<Task>();
|
||||
{
|
||||
auto parser = TerminalInputParser(event_receiver->MakeSender());
|
||||
parser.Add('\x1B');
|
||||
parser.Add('[');
|
||||
parser.Add('0');
|
||||
parser.Add(';');
|
||||
parser.Add('1');
|
||||
parser.Add('2');
|
||||
parser.Add(';');
|
||||
parser.Add('4');
|
||||
parser.Add('2');
|
||||
parser.Add('m');
|
||||
}
|
||||
std::vector<Event> received_events;
|
||||
auto parser = TerminalInputParser(
|
||||
[&](Event event) { received_events.push_back(std::move(event)); });
|
||||
parser.Add('');
|
||||
parser.Add('[');
|
||||
parser.Add('0');
|
||||
parser.Add(';');
|
||||
parser.Add('1');
|
||||
parser.Add('2');
|
||||
parser.Add(';');
|
||||
parser.Add('4');
|
||||
parser.Add('2');
|
||||
parser.Add('m');
|
||||
|
||||
Task received;
|
||||
EXPECT_TRUE(event_receiver->Receive(&received));
|
||||
EXPECT_TRUE(std::get<Event>(received).is_mouse());
|
||||
EXPECT_EQ(Mouse::Left, std::get<Event>(received).mouse().button);
|
||||
EXPECT_EQ(12, std::get<Event>(received).mouse().x);
|
||||
EXPECT_EQ(42, std::get<Event>(received).mouse().y);
|
||||
EXPECT_EQ(std::get<Event>(received).mouse().motion, Mouse::Released);
|
||||
EXPECT_FALSE(event_receiver->Receive(&received));
|
||||
EXPECT_EQ(1, received_events.size());
|
||||
EXPECT_TRUE(received_events[0].is_mouse());
|
||||
EXPECT_EQ(Mouse::Left, received_events[0].mouse().button);
|
||||
EXPECT_EQ(12, received_events[0].mouse().x);
|
||||
EXPECT_EQ(42, received_events[0].mouse().y);
|
||||
EXPECT_EQ(received_events[0].mouse().motion, Mouse::Released);
|
||||
}
|
||||
|
||||
TEST(Event, MouseReporting) {
|
||||
auto event_receiver = MakeReceiver<Task>();
|
||||
{
|
||||
auto parser = TerminalInputParser(event_receiver->MakeSender());
|
||||
parser.Add('\x1B');
|
||||
parser.Add('[');
|
||||
parser.Add('1');
|
||||
parser.Add('2');
|
||||
parser.Add(';');
|
||||
parser.Add('4');
|
||||
parser.Add('2');
|
||||
parser.Add('R');
|
||||
}
|
||||
std::vector<Event> received_events;
|
||||
auto parser = TerminalInputParser(
|
||||
[&](Event event) { received_events.push_back(std::move(event)); });
|
||||
parser.Add('');
|
||||
parser.Add('[');
|
||||
parser.Add('1');
|
||||
parser.Add('2');
|
||||
parser.Add(';');
|
||||
parser.Add('4');
|
||||
parser.Add('2');
|
||||
parser.Add('R');
|
||||
|
||||
Task received;
|
||||
EXPECT_TRUE(event_receiver->Receive(&received));
|
||||
EXPECT_TRUE(std::get<Event>(received).is_cursor_position());
|
||||
EXPECT_EQ(42, std::get<Event>(received).cursor_x());
|
||||
EXPECT_EQ(12, std::get<Event>(received).cursor_y());
|
||||
EXPECT_FALSE(event_receiver->Receive(&received));
|
||||
EXPECT_EQ(1, received_events.size());
|
||||
EXPECT_TRUE(received_events[0].is_cursor_position());
|
||||
EXPECT_EQ(42, received_events[0].cursor_x());
|
||||
EXPECT_EQ(12, received_events[0].cursor_y());
|
||||
}
|
||||
|
||||
TEST(Event, MouseMiddleClick) {
|
||||
auto event_receiver = MakeReceiver<Task>();
|
||||
{
|
||||
auto parser = TerminalInputParser(event_receiver->MakeSender());
|
||||
parser.Add('\x1B');
|
||||
parser.Add('[');
|
||||
parser.Add('3');
|
||||
parser.Add('3');
|
||||
parser.Add(';');
|
||||
parser.Add('1');
|
||||
parser.Add('2');
|
||||
parser.Add(';');
|
||||
parser.Add('4');
|
||||
parser.Add('2');
|
||||
parser.Add('M');
|
||||
}
|
||||
std::vector<Event> received_events;
|
||||
auto parser = TerminalInputParser(
|
||||
[&](Event event) { received_events.push_back(std::move(event)); });
|
||||
parser.Add('');
|
||||
parser.Add('[');
|
||||
parser.Add('3');
|
||||
parser.Add('3');
|
||||
parser.Add(';');
|
||||
parser.Add('1');
|
||||
parser.Add('2');
|
||||
parser.Add(';');
|
||||
parser.Add('4');
|
||||
parser.Add('2');
|
||||
parser.Add('M');
|
||||
|
||||
Task received;
|
||||
EXPECT_TRUE(event_receiver->Receive(&received));
|
||||
EXPECT_TRUE(std::get<Event>(received).is_mouse());
|
||||
EXPECT_EQ(Mouse::Middle, std::get<Event>(received).mouse().button);
|
||||
EXPECT_EQ(12, std::get<Event>(received).mouse().x);
|
||||
EXPECT_EQ(42, std::get<Event>(received).mouse().y);
|
||||
EXPECT_FALSE(event_receiver->Receive(&received));
|
||||
EXPECT_EQ(1, received_events.size());
|
||||
EXPECT_TRUE(received_events[0].is_mouse());
|
||||
EXPECT_EQ(Mouse::Middle, received_events[0].mouse().button);
|
||||
EXPECT_EQ(12, received_events[0].mouse().x);
|
||||
EXPECT_EQ(42, received_events[0].mouse().y);
|
||||
}
|
||||
|
||||
TEST(Event, MouseRightClick) {
|
||||
auto event_receiver = MakeReceiver<Task>();
|
||||
{
|
||||
auto parser = TerminalInputParser(event_receiver->MakeSender());
|
||||
parser.Add('\x1B');
|
||||
parser.Add('[');
|
||||
parser.Add('3');
|
||||
parser.Add('4');
|
||||
parser.Add(';');
|
||||
parser.Add('1');
|
||||
parser.Add('2');
|
||||
parser.Add(';');
|
||||
parser.Add('4');
|
||||
parser.Add('2');
|
||||
parser.Add('M');
|
||||
}
|
||||
std::vector<Event> received_events;
|
||||
auto parser = TerminalInputParser(
|
||||
[&](Event event) { received_events.push_back(std::move(event)); });
|
||||
parser.Add('');
|
||||
parser.Add('[');
|
||||
parser.Add('3');
|
||||
parser.Add('4');
|
||||
parser.Add(';');
|
||||
parser.Add('1');
|
||||
parser.Add('2');
|
||||
parser.Add(';');
|
||||
parser.Add('4');
|
||||
parser.Add('2');
|
||||
parser.Add('M');
|
||||
|
||||
Task received;
|
||||
EXPECT_TRUE(event_receiver->Receive(&received));
|
||||
EXPECT_TRUE(std::get<Event>(received).is_mouse());
|
||||
EXPECT_EQ(Mouse::Right, std::get<Event>(received).mouse().button);
|
||||
EXPECT_EQ(12, std::get<Event>(received).mouse().x);
|
||||
EXPECT_EQ(42, std::get<Event>(received).mouse().y);
|
||||
EXPECT_FALSE(event_receiver->Receive(&received));
|
||||
EXPECT_EQ(1, received_events.size());
|
||||
EXPECT_TRUE(received_events[0].is_mouse());
|
||||
EXPECT_EQ(Mouse::Right, received_events[0].mouse().button);
|
||||
EXPECT_EQ(12, received_events[0].mouse().x);
|
||||
EXPECT_EQ(42, received_events[0].mouse().y);
|
||||
}
|
||||
|
||||
TEST(Event, UTF8) {
|
||||
@@ -313,31 +282,29 @@ TEST(Event, UTF8) {
|
||||
|
||||
};
|
||||
for (auto test : kTestCase) {
|
||||
auto event_receiver = MakeReceiver<Task>();
|
||||
{
|
||||
auto parser = TerminalInputParser(event_receiver->MakeSender());
|
||||
for (auto input : test.input)
|
||||
parser.Add(input);
|
||||
}
|
||||
Task received;
|
||||
std::vector<Event> received_events;
|
||||
auto parser = TerminalInputParser(
|
||||
[&](Event event) { received_events.push_back(std::move(event)); });
|
||||
for (auto input : test.input)
|
||||
parser.Add(input);
|
||||
|
||||
if (test.valid) {
|
||||
EXPECT_TRUE(event_receiver->Receive(&received));
|
||||
EXPECT_TRUE(std::get<Event>(received).is_character());
|
||||
EXPECT_EQ(1, received_events.size());
|
||||
EXPECT_TRUE(received_events[0].is_character());
|
||||
} else {
|
||||
EXPECT_TRUE(received_events.empty());
|
||||
}
|
||||
EXPECT_FALSE(event_receiver->Receive(&received));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Event, NewLine) {
|
||||
for (char newline : {'\r', '\n'}) {
|
||||
auto event_receiver = MakeReceiver<Task>();
|
||||
{
|
||||
auto parser = TerminalInputParser(event_receiver->MakeSender());
|
||||
parser.Add(newline);
|
||||
}
|
||||
Task received;
|
||||
EXPECT_TRUE(event_receiver->Receive(&received));
|
||||
EXPECT_TRUE(std::get<Event>(received) == Event::Return);
|
||||
std::vector<Event> received_events;
|
||||
auto parser = TerminalInputParser(
|
||||
[&](Event event) { received_events.push_back(std::move(event)); });
|
||||
parser.Add(newline);
|
||||
EXPECT_EQ(1, received_events.size());
|
||||
EXPECT_TRUE(received_events[0] == Event::Return);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,17 +324,16 @@ TEST(Event, Control) {
|
||||
cases.push_back({char(127), false});
|
||||
|
||||
for (auto test : cases) {
|
||||
auto event_receiver = MakeReceiver<Task>();
|
||||
{
|
||||
auto parser = TerminalInputParser(event_receiver->MakeSender());
|
||||
parser.Add(test.input);
|
||||
}
|
||||
Task received;
|
||||
std::vector<Event> received_events;
|
||||
auto parser = TerminalInputParser(
|
||||
[&](Event event) { received_events.push_back(std::move(event)); });
|
||||
parser.Add(test.input);
|
||||
|
||||
if (test.cancel) {
|
||||
EXPECT_FALSE(event_receiver->Receive(&received));
|
||||
EXPECT_TRUE(received_events.empty());
|
||||
} else {
|
||||
EXPECT_TRUE(event_receiver->Receive(&received));
|
||||
EXPECT_EQ(std::get<Event>(received), Event::Special({test.input}));
|
||||
EXPECT_EQ(1, received_events.size());
|
||||
EXPECT_EQ(received_events[0], Event::Special({test.input}));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -385,10 +351,9 @@ TEST(Event, Special) {
|
||||
Event expected;
|
||||
} kTestCase[] = {
|
||||
// Arrow (default cursor mode)
|
||||
{str("\x1B[A"), Event::ArrowUp}, {str("\x1B[B"), Event::ArrowDown},
|
||||
{str("\x1B[C"), Event::ArrowRight}, {str("\x1B[D"), Event::ArrowLeft},
|
||||
{str("\x1B[H"), Event::Home}, {str("\x1B[F"), Event::End},
|
||||
/*
|
||||
{str("[A"), Event::ArrowUp}, {str("[B"), Event::ArrowDown},
|
||||
{str("[C"), Event::ArrowRight}, {str("[D"), Event::ArrowLeft},
|
||||
{str("[H"), Event::Home}, {str("[F"), Event::End},
|
||||
|
||||
// Arrow (application cursor mode)
|
||||
{str("\x1BOA"), Event::ArrowUp},
|
||||
@@ -469,45 +434,38 @@ TEST(Event, Special) {
|
||||
|
||||
// Custom:
|
||||
{{0}, Event::Custom},
|
||||
*/
|
||||
};
|
||||
|
||||
for (auto test : kTestCase) {
|
||||
auto event_receiver = MakeReceiver<Task>();
|
||||
{
|
||||
auto parser = TerminalInputParser(event_receiver->MakeSender());
|
||||
for (auto input : test.input) {
|
||||
parser.Add(input);
|
||||
}
|
||||
std::vector<Event> received_events;
|
||||
auto parser = TerminalInputParser(
|
||||
[&](Event event) { received_events.push_back(std::move(event)); });
|
||||
for (auto input : test.input) {
|
||||
parser.Add(input);
|
||||
}
|
||||
Task received;
|
||||
EXPECT_TRUE(event_receiver->Receive(&received));
|
||||
EXPECT_EQ(std::get<Event>(received), test.expected);
|
||||
EXPECT_FALSE(event_receiver->Receive(&received));
|
||||
EXPECT_EQ(1, received_events.size());
|
||||
EXPECT_EQ(received_events[0], test.expected);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Event, DeviceControlString) {
|
||||
auto event_receiver = MakeReceiver<Task>();
|
||||
{
|
||||
auto parser = TerminalInputParser(event_receiver->MakeSender());
|
||||
parser.Add(27); // ESC
|
||||
parser.Add(80); // P
|
||||
parser.Add(49); // 1
|
||||
parser.Add(36); // $
|
||||
parser.Add(114); // r
|
||||
parser.Add(49); // 1
|
||||
parser.Add(32); // SP
|
||||
parser.Add(113); // q
|
||||
parser.Add(27); // ESC
|
||||
parser.Add(92); // (backslash)
|
||||
}
|
||||
std::vector<Event> received_events;
|
||||
auto parser = TerminalInputParser(
|
||||
[&](Event event) { received_events.push_back(std::move(event)); });
|
||||
parser.Add(27); // ESC
|
||||
parser.Add(80); // P
|
||||
parser.Add(49); // 1
|
||||
parser.Add(36); // $
|
||||
parser.Add(114); // r
|
||||
parser.Add(49); // 1
|
||||
parser.Add(32); // SP
|
||||
parser.Add(113); // q
|
||||
parser.Add(27); // ESC
|
||||
parser.Add(92); // (backslash)
|
||||
|
||||
Task received;
|
||||
EXPECT_TRUE(event_receiver->Receive(&received));
|
||||
EXPECT_TRUE(std::get<Event>(received).is_cursor_shape());
|
||||
EXPECT_EQ(1, std::get<Event>(received).cursor_shape());
|
||||
EXPECT_FALSE(event_receiver->Receive(&received));
|
||||
EXPECT_EQ(1, received_events.size());
|
||||
EXPECT_TRUE(received_events[0].is_cursor_shape());
|
||||
EXPECT_EQ(1, received_events[0].cursor_shape());
|
||||
}
|
||||
|
||||
} // namespace ftxui
|
||||
|
@@ -1,21 +1,16 @@
|
||||
// Copyright 2021 Arthur Sonzogni. All rights reserved.
|
||||
// Use of this source code is governed by the MIT license that can be found in
|
||||
// the LICENSE file.
|
||||
#include <cstddef>
|
||||
#include <ftxui/component/event.hpp>
|
||||
#include "ftxui/component/terminal_input_parser.hpp"
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const char* data, size_t size) {
|
||||
using namespace ftxui;
|
||||
auto event_receiver = MakeReceiver<Task>();
|
||||
{
|
||||
auto parser = TerminalInputParser(event_receiver->MakeSender());
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
parser.Add(data[i]);
|
||||
}
|
||||
auto parser = TerminalInputParser([&](Event) {});
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
parser.Add(data[i]);
|
||||
}
|
||||
|
||||
Task received;
|
||||
while (event_receiver->Receive(&received)) {
|
||||
// Do nothing.
|
||||
}
|
||||
return 0; // Non-zero return values are reserved for future use.
|
||||
}
|
||||
|
Reference in New Issue
Block a user