mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2025-06-23 23:41:13 +08:00
Fix ScreenInteractive::FixedSize screen stomps on the history terminal output (#1064)
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
Co-authored-by: ArthurSonzogni <sonzogniarthur@gmail.com>
This commit is contained in:
parent
6440a88dc6
commit
68fc9b1212
@ -25,6 +25,10 @@ Next
|
||||
```
|
||||
Thanks @mikomikotaishi for PR #1015.
|
||||
|
||||
### Component
|
||||
- Fix ScreenInteractive::FixedSize screen stomps on the preceding terminal
|
||||
output. Thanks @zozowell in #1064.
|
||||
|
||||
|
||||
6.1.9 (2025-05-07)
|
||||
------------
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include <memory> // for shared_ptr
|
||||
#include <string> // for string
|
||||
#include <thread> // for thread
|
||||
#include <variant> // for variant
|
||||
|
||||
#include "ftxui/component/animation.hpp" // for TimePoint
|
||||
#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse
|
||||
@ -105,12 +104,12 @@ class ScreenInteractive : public Screen {
|
||||
Fullscreen,
|
||||
TerminalOutput,
|
||||
};
|
||||
Dimension dimension_ = Dimension::Fixed;
|
||||
bool use_alternative_screen_ = false;
|
||||
ScreenInteractive(int dimx,
|
||||
ScreenInteractive(Dimension dimension,
|
||||
int dimx,
|
||||
int dimy,
|
||||
Dimension dimension,
|
||||
bool use_alternative_screen);
|
||||
const Dimension dimension_;
|
||||
const bool use_alternative_screen_;
|
||||
|
||||
bool track_mouse_ = true;
|
||||
|
||||
@ -129,6 +128,7 @@ class ScreenInteractive : public Screen {
|
||||
int cursor_x_ = 1;
|
||||
int cursor_y_ = 1;
|
||||
|
||||
std::uint64_t frame_count_ = 0;
|
||||
bool mouse_captured = false;
|
||||
bool previous_frame_resized_ = false;
|
||||
|
||||
|
@ -346,9 +346,9 @@ void AnimationListener(std::atomic<bool>* quit, Sender<Task> out) {
|
||||
|
||||
} // namespace
|
||||
|
||||
ScreenInteractive::ScreenInteractive(int dimx,
|
||||
ScreenInteractive::ScreenInteractive(Dimension dimension,
|
||||
int dimx,
|
||||
int dimy,
|
||||
Dimension dimension,
|
||||
bool use_alternative_screen)
|
||||
: Screen(dimx, dimy),
|
||||
dimension_(dimension),
|
||||
@ -359,10 +359,10 @@ ScreenInteractive::ScreenInteractive(int dimx,
|
||||
// static
|
||||
ScreenInteractive ScreenInteractive::FixedSize(int dimx, int dimy) {
|
||||
return {
|
||||
Dimension::Fixed,
|
||||
dimx,
|
||||
dimy,
|
||||
Dimension::Fixed,
|
||||
false,
|
||||
/*use_alternative_screen=*/false,
|
||||
};
|
||||
}
|
||||
|
||||
@ -379,11 +379,12 @@ ScreenInteractive ScreenInteractive::Fullscreen() {
|
||||
/// content might mess up with the terminal content.
|
||||
// static
|
||||
ScreenInteractive ScreenInteractive::FullscreenPrimaryScreen() {
|
||||
auto terminal = Terminal::Size();
|
||||
return {
|
||||
0,
|
||||
0,
|
||||
Dimension::Fullscreen,
|
||||
false,
|
||||
terminal.dimx,
|
||||
terminal.dimy,
|
||||
/*use_alternative_screen=*/false,
|
||||
};
|
||||
}
|
||||
|
||||
@ -391,30 +392,37 @@ ScreenInteractive ScreenInteractive::FullscreenPrimaryScreen() {
|
||||
/// alternate screen buffer to avoid messing with the terminal content.
|
||||
// static
|
||||
ScreenInteractive ScreenInteractive::FullscreenAlternateScreen() {
|
||||
auto terminal = Terminal::Size();
|
||||
return {
|
||||
0,
|
||||
0,
|
||||
Dimension::Fullscreen,
|
||||
true,
|
||||
terminal.dimx,
|
||||
terminal.dimy,
|
||||
/*use_alternative_screen=*/true,
|
||||
};
|
||||
}
|
||||
|
||||
/// Create a ScreenInteractive whose width match the terminal output width and
|
||||
/// the height matches the component being drawn.
|
||||
// static
|
||||
ScreenInteractive ScreenInteractive::TerminalOutput() {
|
||||
auto terminal = Terminal::Size();
|
||||
return {
|
||||
0,
|
||||
0,
|
||||
Dimension::TerminalOutput,
|
||||
false,
|
||||
terminal.dimx,
|
||||
terminal.dimy, // Best guess.
|
||||
/*use_alternative_screen=*/false,
|
||||
};
|
||||
}
|
||||
|
||||
/// Create a ScreenInteractive whose width and height match the component being
|
||||
/// drawn.
|
||||
// static
|
||||
ScreenInteractive ScreenInteractive::FitComponent() {
|
||||
auto terminal = Terminal::Size();
|
||||
return {
|
||||
0,
|
||||
0,
|
||||
Dimension::FitComponent,
|
||||
terminal.dimx, // Best guess.
|
||||
terminal.dimy, // Best guess.
|
||||
false,
|
||||
};
|
||||
}
|
||||
@ -921,7 +929,7 @@ void ScreenInteractive::Draw(Component component) {
|
||||
break;
|
||||
}
|
||||
|
||||
const bool resized = (dimx != dimx_) || (dimy != dimy_);
|
||||
const bool resized = frame_count_ == 0 || (dimx != dimx_) || (dimy != dimy_);
|
||||
ResetCursorPosition();
|
||||
std::cout << ResetPosition(/*clear=*/resized);
|
||||
|
||||
@ -1004,6 +1012,7 @@ void ScreenInteractive::Draw(Component component) {
|
||||
Flush();
|
||||
Clear();
|
||||
frame_valid_ = true;
|
||||
frame_count_++;
|
||||
}
|
||||
|
||||
// private
|
||||
|
@ -10,9 +10,57 @@
|
||||
#include "ftxui/component/screen_interactive.hpp"
|
||||
#include "ftxui/dom/elements.hpp" // for text, Element
|
||||
|
||||
#if defined(__unix__)
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
#include <ftxui/component/loop.hpp>
|
||||
#include <string>
|
||||
#endif
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
namespace {
|
||||
#if defined(__unix__)
|
||||
|
||||
// Capture the standard output (stdout) to a string.
|
||||
class StdCapture {
|
||||
public:
|
||||
explicit StdCapture(std::string* captured)
|
||||
: captured_(captured) {
|
||||
if (pipe(pipefd_) != 0) return;
|
||||
old_stdout_ = dup(fileno(stdout));
|
||||
fflush(stdout);
|
||||
dup2(pipefd_[1], fileno(stdout));
|
||||
close(pipefd_[1]); // Close the write end in the parent
|
||||
}
|
||||
|
||||
~StdCapture() {
|
||||
fflush(stdout);
|
||||
dup2(old_stdout_, fileno(stdout));
|
||||
close(old_stdout_);
|
||||
|
||||
char buffer[1024];
|
||||
ssize_t count;
|
||||
while ((count = read(pipefd_[0], buffer, sizeof(buffer))) > 0) {
|
||||
captured_->append(buffer, count);
|
||||
}
|
||||
|
||||
close(pipefd_[0]);
|
||||
}
|
||||
|
||||
StdCapture(const StdCapture&) = delete;
|
||||
StdCapture& operator=(const StdCapture&) = delete;
|
||||
|
||||
private:
|
||||
int pipefd_[2]{-1, -1};
|
||||
int old_stdout_{-1};
|
||||
std::string* const captured_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
bool TestSignal(int signal) {
|
||||
int called = 0;
|
||||
// The tree of components. This defines how to navigate using the keyboard.
|
||||
@ -131,4 +179,69 @@ TEST(ScreenInteractive, CtrlC_NotForced) {
|
||||
ASSERT_GE(ctrl_c_count, 50);
|
||||
}
|
||||
|
||||
// Regression test for:
|
||||
// https://github.com/ArthurSonzogni/FTXUI/pull/1064/files
|
||||
TEST(ScreenInteractive, FixedSizeInitialFrame) {
|
||||
#if defined(__unix__)
|
||||
std::string output;
|
||||
{
|
||||
auto capture = StdCapture(&output);
|
||||
|
||||
auto screen = ScreenInteractive::FixedSize(2, 2);
|
||||
auto component = Renderer([&] {
|
||||
return text("AB");
|
||||
});
|
||||
|
||||
Loop loop(&screen, component);
|
||||
loop.RunOnce();
|
||||
}
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
auto expected =
|
||||
// Install the ScreenInteractive.
|
||||
"\0" // Flush stdout.
|
||||
"\x1BP$q q" // Set cursor shape to 1 (block).
|
||||
"\x1B\\" // Reset cursor position.
|
||||
"\x1B[?7l" // Disable line wrapping.
|
||||
"\x1B[?1000h" // Enable mouse tracking.
|
||||
"\x1B[?1003h" // Enable mouse motion tracking.
|
||||
"\x1B[?1015h" // Enable mouse wheel tracking.
|
||||
"\x1B[?1006h" // Enable SGR mouse tracking.
|
||||
"\0" // Flush stdout.
|
||||
|
||||
// Reset the screen.
|
||||
"\r" // Reset cursor position.
|
||||
"\x1B[2K" // Clear the line.
|
||||
"\x1B[1A" // Move cursor up one line.
|
||||
"\x1B[2K" // Clear the line.
|
||||
|
||||
// Print the document.
|
||||
"AB\r\n" // Print "AB" and move to the next line.
|
||||
" " // Print two spaces to fill the line.
|
||||
|
||||
// Set cursor position.
|
||||
"\x1B[1D" // Move cursor left one character.
|
||||
"\x1B[?25l" // Hide cursor.
|
||||
|
||||
// Flush
|
||||
"\0" // Flush stdout.
|
||||
|
||||
// Uninstall the ScreenInteractive.
|
||||
"\x1B[1C" // Move cursor right one character.
|
||||
"\x1B[?1006l" // Disable SGR mouse tracking.
|
||||
"\x1B[?1015l" // Disable mouse wheel tracking.
|
||||
"\x1B[?1003l" // Disable mouse motion tracking.
|
||||
"\x1B[?1000l" // Disable mouse tracking.
|
||||
"\x1B[?7h" // Enable line wrapping.
|
||||
"\x1B[?25h" // Show cursor.
|
||||
"\x1B[1 q" // Set cursor shape to 1 (block).
|
||||
"\0" // Flush stdout.
|
||||
|
||||
// Skip one line to avoid the prompt to be printed over the last drawing.
|
||||
"\r\n"sv;
|
||||
ASSERT_EQ(expected, output);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
} // namespace ftxui
|
||||
|
Loading…
Reference in New Issue
Block a user