Coding style + fix tests

This commit is contained in:
ArthurSonzogni
2025-06-24 14:31:51 +02:00
parent 2715503516
commit ce9964131d
9 changed files with 99 additions and 153 deletions

View File

@@ -25,6 +25,8 @@ class Loop;
struct Event; struct Event;
using Component = std::shared_ptr<ComponentBase>; using Component = std::shared_ptr<ComponentBase>;
using TerminalIDUpdateCallback = std::function<void (const TerminalID &)>;
class ScreenInteractivePrivate; class ScreenInteractivePrivate;
/// @brief ScreenInteractive is a `Screen` that can handle events, run a main /// @brief ScreenInteractive is a `Screen` that can handle events, run a main
@@ -75,10 +77,7 @@ class ScreenInteractive : public Screen {
TerminalID TerminalId() const; TerminalID TerminalId() const;
typedef std::function<void(TerminalID const& terminal_id)> TerminalIDUpdateCallback; void OnTerminalIDUpdate(const TerminalIDUpdateCallback& callback);
void OnTerminalIDUpdate(
TerminalIDUpdateCallback const& callback);
// Selection API. // Selection API.
std::string GetSelection(); std::string GetSelection();
@@ -164,10 +163,10 @@ class ScreenInteractive : public Screen {
std::unique_ptr<Selection> selection_; std::unique_ptr<Selection> selection_;
std::function<void()> selection_on_change_; std::function<void()> selection_on_change_;
TerminalID m_terminal_id; TerminalID m_terminal_id = TerminalID::Unknown;
typedef std::list<TerminalIDUpdateCallback> TerminalIDUpdateCallbackContainer; using TerminalIDUpdateCallbackContainer = std::list<TerminalIDUpdateCallback>;
TerminalIDUpdateCallbackContainer m_terminal_id_update_callbacks; TerminalIDUpdateCallbackContainer terminal_id_callback_;
friend class Loop; friend class Loop;

View File

@@ -10,20 +10,20 @@
namespace ftxui { namespace ftxui {
std::string const TERMINAL_ID_REQUEST("\x1b[0c"); /// @brief The TerminalID enum class represents different types of terminal
/// emulators that FTXUI can detect. It is used to identify the terminal
/// @brief A mouse event. It contains the coordinate of the mouse, the button /// emulator in use, which can affect how FTXUI renders its output and handles
/// pressed and the modifier (shift, ctrl, meta). /// input events.
/// @ingroup component /// @ingroup component
enum class TerminalID {
Unknown,
// --
enum class TerminalID Konsole,
{ LinuxVC,
UNKNOWN, Urxvt,
XTERM, Vte,
KONSOLE, Xterm,
URXVT,
VTE,
LINUXVC
}; };
std::ostream& operator<<( std::ostream& operator<<(

View File

@@ -3,7 +3,6 @@
// the LICENSE file. // the LICENSE file.
#include <iostream> #include <iostream>
#include "ftxui/component/loop.hpp" #include "ftxui/component/loop.hpp"
#include "ftxui/component/terminal_id.hpp"
#include <utility> // for move #include <utility> // for move
@@ -49,9 +48,6 @@ void Loop::RunOnceBlocking() {
/// Execute the loop, blocking the current thread, up until the loop has /// Execute the loop, blocking the current thread, up until the loop has
/// quitted. /// quitted.
void Loop::Run() { void Loop::Run() {
// Ensure we perform a single terminal id request before we are starting the loop itself.
std::cout << TERMINAL_ID_REQUEST;
while (!HasQuitted()) { while (!HasQuitted()) {
RunOnceBlocking(); RunOnceBlocking();
} }

View File

@@ -321,6 +321,8 @@ std::string DeviceStatusReport(DSRMode ps) {
return CSI + std::to_string(int(ps)) + "n"; return CSI + std::to_string(int(ps)) + "n";
} }
const std::string TerminalIdReport = "\x1b[0c";
class CapturedMouseImpl : public CapturedMouseInterface { class CapturedMouseImpl : public CapturedMouseInterface {
public: public:
explicit CapturedMouseImpl(std::function<void(void)> callback) explicit CapturedMouseImpl(std::function<void(void)> callback)
@@ -352,8 +354,7 @@ ScreenInteractive::ScreenInteractive(Dimension dimension,
bool use_alternative_screen) bool use_alternative_screen)
: Screen(dimx, dimy), : Screen(dimx, dimy),
dimension_(dimension), dimension_(dimension),
use_alternative_screen_(use_alternative_screen), use_alternative_screen_(use_alternative_screen) {
m_terminal_id(TerminalID::UNKNOWN) {
task_receiver_ = MakeReceiver<Task>(); task_receiver_ = MakeReceiver<Task>();
} }
@@ -382,10 +383,10 @@ ScreenInteractive ScreenInteractive::Fullscreen() {
ScreenInteractive ScreenInteractive::FullscreenPrimaryScreen() { ScreenInteractive ScreenInteractive::FullscreenPrimaryScreen() {
auto terminal = Terminal::Size(); auto terminal = Terminal::Size();
return { return {
Dimension::Fullscreen, Dimension::Fullscreen,
terminal.dimx, terminal.dimx,
terminal.dimy, terminal.dimy,
/*use_alternative_screen=*/false, /*use_alternative_screen=*/false,
}; };
} }
@@ -410,7 +411,7 @@ ScreenInteractive ScreenInteractive::TerminalOutput() {
return { return {
Dimension::TerminalOutput, Dimension::TerminalOutput,
terminal.dimx, terminal.dimx,
terminal.dimy, // Best guess. terminal.dimy, // Best guess.
/*use_alternative_screen=*/false, /*use_alternative_screen=*/false,
}; };
} }
@@ -422,8 +423,8 @@ ScreenInteractive ScreenInteractive::FitComponent() {
auto terminal = Terminal::Size(); auto terminal = Terminal::Size();
return { return {
Dimension::FitComponent, Dimension::FitComponent,
terminal.dimx, // Best guess. terminal.dimx, // Best guess.
terminal.dimy, // Best guess. terminal.dimy, // Best guess.
false, false,
}; };
} }
@@ -725,6 +726,9 @@ void ScreenInteractive::Install() {
enable({DECMode::kMouseSgrExtMode}); enable({DECMode::kMouseSgrExtMode});
} }
// Report the Terminal ID.
std::cout << TerminalIdReport;
// After installing the new configuration, flush it to the terminal to // After installing the new configuration, flush it to the terminal to
// ensure it is fully applied: // ensure it is fully applied:
Flush(); Flush();
@@ -795,34 +799,22 @@ void ScreenInteractive::HandleTask(Component component, Task& task) {
return; return;
} }
if (arg.is_terminal_id()) {
m_terminal_id = arg.terminal_id();
for(auto & callback : terminal_id_callback_) {
if (callback) {
callback(m_terminal_id);
}
}
return;
}
if (arg.is_mouse()) { if (arg.is_mouse()) {
arg.mouse().x -= cursor_x_; arg.mouse().x -= cursor_x_;
arg.mouse().y -= cursor_y_; arg.mouse().y -= cursor_y_;
} }
if (arg.is_terminal_id())
{
m_terminal_id =
arg.terminal_id();
for (auto itr = m_terminal_id_update_callbacks.begin(),
end_itr = m_terminal_id_update_callbacks.end();
(itr != end_itr);
++itr)
{
if (*itr)
{
(*itr)(m_terminal_id);
}
else
{
// The callback function is invalid and will be removed
m_terminal_id_update_callbacks.erase(
itr);
}
}
}
arg.screen_ = this; arg.screen_ = this;
bool handled = component->OnEvent(arg); bool handled = component->OnEvent(arg);
@@ -1108,16 +1100,13 @@ bool ScreenInteractive::SelectionData::operator!=(
return !(*this == other); return !(*this == other);
} }
TerminalID ScreenInteractive::TerminalId() const TerminalID ScreenInteractive::TerminalId() const {
{ return m_terminal_id;
return m_terminal_id;
} }
void ScreenInteractive::OnTerminalIDUpdate( void ScreenInteractive::OnTerminalIDUpdate(
TerminalIDUpdateCallback const& callback) const TerminalIDUpdateCallback& callback) {
{ terminal_id_callback_.push_back(callback);
m_terminal_id_update_callbacks.push_back(
callback);
} }
} // namespace ftxui. } // namespace ftxui.

View File

@@ -207,6 +207,7 @@ TEST(ScreenInteractive, FixedSizeInitialFrame) {
"\x1B[?1003h" // Enable mouse motion tracking. "\x1B[?1003h" // Enable mouse motion tracking.
"\x1B[?1015h" // Enable mouse wheel tracking. "\x1B[?1015h" // Enable mouse wheel tracking.
"\x1B[?1006h" // Enable SGR mouse tracking. "\x1B[?1006h" // Enable SGR mouse tracking.
"\x1B[0c" // Query terminal ID.
"\0" // Flush stdout. "\0" // Flush stdout.
// Reset the screen. // Reset the screen.

View File

@@ -7,45 +7,35 @@
namespace ftxui namespace ftxui
{ {
std::ostream& operator<<( std::ostream& operator<<(std::ostream& os, TerminalID terminal_id) {
std::ostream& os, switch (terminal_id) {
TerminalID terminal_id) case TerminalID::Unknown: {
{ os << "Unknown";
switch(terminal_id) break;
{ }
case TerminalID::UNKNOWN: case TerminalID::Urxvt: {
{ os << "Urxvt";
os << "UNKNOWN";
break; break;
} }
case TerminalID::XTERM: case TerminalID::LinuxVC: {
{ os << "LinuxVC";
os << "XTERM";
break; break;
} }
case TerminalID::KONSOLE: case TerminalID::Konsole: {
{ os << "Konsole";
os << "KONSOLE";
break; break;
} }
case TerminalID::URXVT: case TerminalID::Vte: {
{ os << "Vte";
os << "URXVT";
break; break;
} }
case TerminalID::VTE: case TerminalID::Xterm: {
{ os << "Xterm";
os << "VTE";
break; break;
} }
case TerminalID::LINUXVC: }
{
os << "LINUXVC";
break;
}
}
return os; return os;
} }
} // namespace ftxui } // namespace ftxui

View File

@@ -469,52 +469,21 @@ TerminalInputParser::Output TerminalInputParser::ParseCursorPosition(
} }
TerminalInputParser::Output TerminalInputParser::ParseTerminalID( TerminalInputParser::Output TerminalInputParser::ParseTerminalID(
std::vector<int> arguments) std::vector<int> arguments) {
{ if (arguments.empty()) {
Output output(TERMINAL_ID); return TerminalID::Unknown;
if (!arguments.empty())
{
switch(arguments[0])
{
case 1:
{
output.terminal_id =
TerminalID::URXVT;
break;
}
case 6:
{
output.terminal_id =
TerminalID::LINUXVC;
break;
}
case 62:
{
output.terminal_id =
TerminalID::KONSOLE;
break;
}
default:
{
output.terminal_id =
TerminalID::UNKNOWN;
break;
}
}
}
else
{
output.terminal_id =
TerminalID::UNKNOWN;
} }
return output; switch (arguments[0]) {
case 1:
return TerminalID::Xterm;
case 6:
return TerminalID::LinuxVC;
case 62:
return TerminalID::Konsole;
default:
return TerminalID::Unknown;
}
} }
} // namespace ftxui } // namespace ftxui

View File

@@ -53,6 +53,9 @@ class TerminalInputParser {
Output(Type t) // NOLINT Output(Type t) // NOLINT
: type(t) {} : type(t) {}
Output(TerminalID terminal_id) // NOLINT
: type(TERMINAL_ID), terminal_id(terminal_id) {}
}; };
void Send(Output output); void Send(Output output);

View File

@@ -511,26 +511,25 @@ TEST(Event, DeviceControlString) {
} }
TEST(Event, TerminalID) { TEST(Event, TerminalID) {
// Test terminal id for KDE konsole
auto event_receiver = MakeReceiver<Task>();
{
auto parser = TerminalInputParser(event_receiver->MakeSender());
parser.Add('\x1B');
parser.Add('[');
parser.Add('?');
parser.Add('6');
parser.Add('2');
parser.Add(';');
parser.Add('2');
parser.Add('c');
}
// Test terminal id for KDE konsole Task received;
auto event_receiver = MakeReceiver<Task>(); EXPECT_TRUE(event_receiver->Receive(&received));
{ EXPECT_TRUE(std::get<Event>(received).is_terminal_id());
auto parser = TerminalInputParser(event_receiver->MakeSender()); EXPECT_EQ(TerminalID::Konsole, std::get<Event>(received).terminal_id());
parser.Add('\x1B'); EXPECT_FALSE(event_receiver->Receive(&received));
parser.Add('[');
parser.Add('?');
parser.Add('6');
parser.Add('2');
parser.Add(';');
parser.Add('2');
parser.Add('c');
}
Task received;
EXPECT_TRUE(event_receiver->Receive(&received));
EXPECT_TRUE(std::get<Event>(received).is_terminal_id());
EXPECT_EQ(TerminalID::KONSOLE, std::get<Event>(received).terminal_id());
EXPECT_FALSE(event_receiver->Receive(&received));
} }
} // namespace ftxui } // namespace ftxui