7 Commits

Author SHA1 Message Date
Harri Pehkonen
5b50eed0c6 Merge e85d655b4d into 346f751527 2025-08-21 09:22:01 -07:00
ArthurSonzogni
e85d655b4d Fix stdin references. 2025-08-17 20:21:20 +02:00
ArthurSonzogni
4b0d0984a5 feat: Improve POSIX piped input handling
Refactored the POSIX piped input handling to avoid redirecting stdin.
Instead, it now directly opens and reads from /dev/tty for keyboard input
when stdin is piped, allowing applications to process piped data while
still receiving interactive keyboard events.

This addresses the TODO comment in ScreenInteractive::InstallPipedInputHandling().
2025-08-17 19:48:54 +02:00
ArthurSonzogni
b0ba518d85 docs: Update CHANGELOG.md for POSIX Piped Input Handling
Added an entry for the POSIX Piped Input Handling feature, including
details about its functionality, default state, and how to disable it.
Also attributed @HarryPehkonen for their contribution in PR #1094.
2025-08-17 19:32:28 +02:00
ArthurSonzogni
be39aed592 Tweak implementation and documentation. 2025-08-17 19:24:26 +02:00
ArthurSonzogni
587e7620f1 Update doc 2025-08-17 19:24:26 +02:00
Harri Pehkonen
def5c6d50c Add opt-in piped input support for POSIX systems
Enables applications to read piped data while maintaining interactive
keyboard input by redirecting stdin to /dev/tty when explicitly enabled.
2025-08-17 19:24:26 +02:00
103 changed files with 471 additions and 2259 deletions

View File

@@ -1 +0,0 @@
bazel/test/

View File

@@ -1,5 +1,4 @@
common --enable_bzlmod common --enable_bzlmod
common --enable_workspace
build --features=layering_check build --features=layering_check
build --enable_bzlmod build --enable_bzlmod
@@ -7,4 +6,4 @@ build --enable_bzlmod
build --enable_platform_specific_config build --enable_platform_specific_config
build:linux --cxxopt=-std=c++20 build:linux --cxxopt=-std=c++20
build:macos --cxxopt=-std=c++20 build:macos --cxxopt=-std=c++20
build:windows --cxxopt=/std:c++20 build:windows --cxxopt=-std:c++20

View File

@@ -1,212 +0,0 @@
# FTXUI - Functional Terminal (X) User Interface
FTXUI is a cross-platform C++ library for terminal-based user interfaces with a functional programming approach, inspired by React.
**ALWAYS reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the information here.**
## Working Effectively
### Build System Setup and Commands
- Bootstrap and build the repository:
```bash
# Basic build (library only) - fast
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --parallel $(nproc)
# Build time: ~30 seconds. NEVER CANCEL. Set timeout to 120+ seconds.
# Build with examples
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DFTXUI_BUILD_EXAMPLES=ON
cmake --build build --parallel $(nproc)
# Build time: ~70 seconds. NEVER CANCEL. Set timeout to 180+ seconds.
# Build with examples and tests
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DFTXUI_BUILD_EXAMPLES=ON -DFTXUI_BUILD_TESTS=ON
cmake --build build --parallel $(nproc)
# Build time: ~113 seconds (includes GoogleTest download). NEVER CANCEL. Set timeout to 300+ seconds.
```
- Alternative build with Ninja (faster):
```bash
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DFTXUI_BUILD_EXAMPLES=ON
ninja -C build
# Build time: ~62 seconds. NEVER CANCEL. Set timeout to 180+ seconds.
```
- Run unit tests:
```bash
# Configure with tests enabled first, then:
cd build && ctest --output-on-failure
# Test time: ~4 seconds (302 tests). NEVER CANCEL. Set timeout to 60+ seconds.
```
### Bazel Support
- FTXUI also supports Bazel build system
- **WARNING**: Bazel may fail due to network connectivity issues in sandboxed environments
- If Bazel is available:
```bash
bazel build //... # Build everything
bazel test //... # Run tests
```
## Validation
### Manual Testing After Changes
- **ALWAYS manually validate changes by building and running examples after making code modifications**
- Run example applications to verify functionality:
```bash
# Build an example first
cmake --build build --target ftxui_example_border
# Run examples (they are interactive, use timeout to terminate)
timeout 2s build/examples/dom/ftxui_example_border
timeout 2s build/examples/dom/ftxui_example_color_gallery
timeout 2s build/examples/component/ftxui_example_button
```
- Examples should produce visual terminal output with borders, colors, and UI components
- **CRITICAL**: Always run at least one DOM example and one Component example to verify both modules work
### Code Quality and Formatting
- Always run formatting before committing:
```bash
./tools/format.sh
# Format time: ~7 seconds. NEVER CANCEL. Set timeout to 60+ seconds.
```
- The format script adds license headers and runs clang-format on all source files
- **Required**: Run formatting or the CI (.github/workflows/build.yaml) will fail
### Build Validation Requirements
- ALWAYS build with both `-DFTXUI_BUILD_EXAMPLES=ON` and `-DFTXUI_BUILD_TESTS=ON` when making changes
- Run the complete test suite with `ctest --output-on-failure`
- All 302 tests must pass
- **Scenario Testing**: Run at least these validation scenarios:
1. Build library only (basic validation)
2. Build with examples and run 2-3 different examples
3. Build with tests and run complete test suite
4. Run formatting tool to ensure code style compliance
## Project Structure
### Key Directories
```
/home/runner/work/FTXUI/FTXUI/
├── include/ftxui/ # Public header files
│ ├── component/ # Interactive component headers
│ ├── dom/ # DOM element headers
│ ├── screen/ # Screen and rendering headers
│ └── util/ # Utility headers
├── src/ftxui/ # Implementation files
│ ├── component/ # Interactive components (buttons, menus, etc.)
│ ├── dom/ # DOM elements (layout, styling, text)
│ ├── screen/ # Screen rendering and terminal handling
│ └── util/ # Utilities
├── examples/ # Example applications
│ ├── component/ # Interactive component examples
│ └── dom/ # DOM element examples
├── cmake/ # CMake configuration files
├── tools/ # Development tools (formatting, etc.)
└── .github/workflows/ # CI/CD configuration
```
### Core Library Modules
FTXUI is organized into three main modules that depend on each other:
```
┌component──┐ (Interactive UI components)
│┌dom──────┐│ (Layout and styling elements)
││┌screen─┐││ (Terminal rendering and input)
└┴┴───────┴┴┘
```
1. **screen**: Low-level terminal handling, colors, pixels, input
2. **dom**: Layout elements (hbox, vbox, text, borders, etc.)
3. **component**: Interactive components (buttons, menus, input fields)
### CMake Build Options
| Option | Description | Default |
|-----------------------------------|----------------------------------|---------|
| FTXUI_BUILD_EXAMPLES | Build example applications | OFF |
| FTXUI_BUILD_DOCS | Build documentation | OFF |
| FTXUI_BUILD_TESTS | Build and enable tests | OFF |
| FTXUI_BUILD_MODULES | Build C++20 modules | OFF |
| FTXUI_ENABLE_INSTALL | Generate install targets | ON |
| FTXUI_MICROSOFT_TERMINAL_FALLBACK | Windows terminal compatibility | ON/OFF |
## Common Tasks
### Building Examples
```bash
# Build specific examples
cmake --build build --target ftxui_example_border
cmake --build build --target ftxui_example_button
cmake --build build --target ftxui_example_menu
# List all available examples
find build -name "ftxui_example_*" -type f
```
### Running Tests
```bash
# Run all tests
cd build && ctest
# Run tests with verbose output
cd build && ctest --verbose
# Run specific test pattern
cd build && ctest -R "Button" --verbose
```
### Working with Source Code
- **Component Development**: Modify files in `src/ftxui/component/` for interactive elements
- **DOM Development**: Modify files in `src/ftxui/dom/` for layout and styling
- **Screen Development**: Modify files in `src/ftxui/screen/` for terminal rendering
- **Adding Examples**: Add new `.cpp` files in `examples/component/` or `examples/dom/`
- **Header Files**: Public APIs are in `include/ftxui/[module]/`
### Integration Patterns
When adding FTXUI to a project, use CMake FetchContent (recommended):
```cmake
include(FetchContent)
FetchContent_Declare(ftxui
GIT_REPOSITORY https://github.com/ArthurSonzogni/ftxui
GIT_TAG v6.1.9
)
FetchContent_MakeAvailable(ftxui)
target_link_libraries(your_target PRIVATE
ftxui::component # For interactive components
ftxui::dom # For layout elements
ftxui::screen # For basic rendering
)
```
## Troubleshooting
### Build Issues
- If CMake configuration fails, ensure C++20 support: `cmake --version` (need 3.12+)
- If Ninja build fails, fall back to Make: `cmake -S . -B build` (without `-G Ninja`)
- If tests fail to build, GoogleTest download might have failed - check network connectivity
- Build artifacts are in `build/` directory - delete with `rm -rf build` to clean
### Example Issues
- Examples are interactive terminal applications - use `timeout` to terminate them
- If examples don't display correctly, terminal might not support colors/Unicode
- Examples require terminal size of at least 80x24 for proper display
### Formatting Issues
- Format script requires clang-format to be installed
- If format script fails, check that source files are not read-only
- Format script modifies files in-place - commit changes afterwards
## Critical Reminders
- **NEVER CANCEL long-running builds** - they may take 2-3 minutes
- **ALWAYS run the formatting tool** before committing changes
- **ALWAYS build and test examples** when making component/dom changes
- **SET APPROPRIATE TIMEOUTS**: 300+ seconds for builds, 60+ seconds for tests
- **BUILD TIMING EXPECTATIONS**:
- Basic library: ~30 seconds
- With examples: ~70 seconds
- With examples + tests: ~113 seconds (first time, includes GoogleTest download)
- Subsequent builds: ~60-70 seconds
- Tests execution: ~4 seconds
- Formatting: ~7 seconds

View File

@@ -56,13 +56,6 @@ jobs:
CXX: ${{ matrix.cxx }} CXX: ${{ matrix.cxx }}
run: bazel test --test_output=all ... run: bazel test --test_output=all ...
- name: "Bazel Smoke test"
env:
CC: ${{ matrix.cc }}
CXX: ${{ matrix.cxx }}
run: bazel build //... --enable_bzlmod --override_module=ftxui=../..
working-directory: bazel/test
test_cmake: test_cmake:
name: "CMake, ${{ matrix.compiler }}, ${{ matrix.os }}" name: "CMake, ${{ matrix.compiler }}, ${{ matrix.os }}"
strategy: strategy:

View File

@@ -12,10 +12,6 @@ jobs:
steps: steps:
- name: "Checkout repository" - name: "Checkout repository"
uses: actions/checkout@v3 uses: actions/checkout@v3
with:
fetch-depth: 0 # Need full history.
fetch-tags: true # Need tags.
- name: "Install cmake" - name: "Install cmake"
uses: lukka/get-cmake@latest uses: lukka/get-cmake@latest
@@ -34,12 +30,7 @@ jobs:
sudo apt-get install graphviz; sudo apt-get install graphviz;
- name: "Build documentation" - name: "Build documentation"
run: |
python3 ./tools/build_multiversion_doc.py
- name: "Build examples"
run: > run: >
mkdir -p multiversion_docs/main/examples;
mkdir build; mkdir build;
cd build; cd build;
emcmake cmake .. emcmake cmake ..
@@ -50,7 +41,8 @@ jobs:
-DFTXUI_BUILD_TESTS_FUZZER=OFF -DFTXUI_BUILD_TESTS_FUZZER=OFF
-DFTXUI_ENABLE_INSTALL=OFF -DFTXUI_ENABLE_INSTALL=OFF
-DFTXUI_DEV_WARNINGS=OFF; -DFTXUI_DEV_WARNINGS=OFF;
cmake --build .; cmake --build . --target doc;
cmake --build . ;
rsync -amv rsync -amv
--include='*/' --include='*/'
--include='*.html' --include='*.html'
@@ -60,13 +52,13 @@ jobs:
--include='*.wasm' --include='*.wasm'
--exclude='*' --exclude='*'
examples examples
../multiversion_docs/ doc/doxygen/html;
- name: "Deploy" - name: "Deploy"
uses: peaceiris/actions-gh-pages@v3 uses: peaceiris/actions-gh-pages@v3
with: with:
github_token: ${{ secrets.GITHUB_TOKEN }} github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: multiversion_docs publish_dir: build/doc/doxygen/html/
enable_jekyll: false enable_jekyll: false
allow_empty_commit: false allow_empty_commit: false
force_orphan: true force_orphan: true

8
.gitignore vendored
View File

@@ -24,12 +24,10 @@ out/
!BUILD.bazel !BUILD.bazel
!MODULE.bazel !MODULE.bazel
!.bazelrc !.bazelrc
!.bazelignore
# .github directory: # .github directory:
!.github/**/*.yaml !.github/**/*.yaml
!.github/**/*.yml !.github/**/*.yml
!.github/**/*.md
# cmake directory: # cmake directory:
!cmake/**/*.in !cmake/**/*.in
@@ -38,10 +36,6 @@ out/
# bazel directory: # bazel directory:
!bazel/**/*.bzl !bazel/**/*.bzl
!.bcr/* !.bcr/*
!bazel/test/*.bazel
!bazel/test/*.bazelrc
!bazel/test/*.cpp
!bazel/test/*.md
# doc directory: # doc directory:
!doc/**/Doxyfile.in !doc/**/Doxyfile.in
@@ -76,6 +70,4 @@ out/
# tools directory: # tools directory:
!tools/**/*.sh !tools/**/*.sh
!tools/**/*.py
!tools/**/*.cpp !tools/**/*.cpp
build/

View File

@@ -15,16 +15,13 @@ load(":bazel/ftxui.bzl", "generate_examples")
load(":bazel/ftxui.bzl", "windows_copts") load(":bazel/ftxui.bzl", "windows_copts")
# A meta target depending on all of the ftxui submodules. # A meta target depending on all of the ftxui submodules.
# Note that component depends on dom and screen, so ftxui re-exports all headers. # Note that component depends on dom and screen, so ftxui is just an alias for
# component.
# ┌component──┐ # ┌component──┐
# │┌dom──────┐│ # │┌dom──────┐│
# ││┌screen─┐││ # ││┌screen─┐││
# └┴┴───────┴┴┘ # └┴┴───────┴┴┘
ftxui_cc_library( alias(name = "ftxui", actual = ":component")
name = "ftxui",
hdrs = glob(["include/ftxui/**/*.hpp"]),
deps = [":component"],
)
# @ftxui:screen is a module that provides a screen buffer and color management # @ftxui:screen is a module that provides a screen buffer and color management
# for terminal applications. A screen is a 2D array of cells, each cell can # for terminal applications. A screen is a 2D array of cells, each cell can

View File

@@ -25,12 +25,6 @@ Next
``` ```
Thanks @mikomikotaishi for PR #1015. Thanks @mikomikotaishi for PR #1015.
- Remove dependency on 'pthread'. - Remove dependency on 'pthread'.
- Bugfix: Bazel target @ftxui is now visible. Thanks @dskkato in #1157.
### General
- Breaking. Move to `std::string_view` instead of `const std::string&` where
applicable. This yields better interoperability with string literals and
avoids unnecessary copies. Thanks @mikomikotaishi for PR #1154
### Component ### Component
- Feature: POSIX Piped Input Handling. - Feature: POSIX Piped Input Handling.
@@ -43,15 +37,7 @@ Next
output. Thanks @zozowell in #1064. output. Thanks @zozowell in #1064.
- Fix vertical `ftxui::Slider`. The "up" key was previously decreasing the - Fix vertical `ftxui::Slider`. The "up" key was previously decreasing the
value. Thanks @its-pablo in #1093 for reporting the issue. value. Thanks @its-pablo in #1093 for reporting the issue.
- Fix Windows UTF-16 key input handling. Emoji and other code points outside the
Basic Multilingual Plane (BMP) are now correctly processed. Thanks @739C1AE2
in #1160 for fixing the issue.
### Dom
- Fix integer overflow in `ComputeShrinkHard`. Thanks @its-pablo in #1137 for
reporting and fixing the issue.
- Add specialization for `vbox/hbox/dbox` to allow a container of Element as
as input. Thanks @nbusser in #1117.
6.1.9 (2025-05-07) 6.1.9 (2025-05-07)
------------ ------------

View File

@@ -1,4 +1,3 @@
<p align="center"> <p align="center">
<img src="https://github.com/ArthurSonzogni/FTXUI/assets/4759106/6925b6da-0a7e-49d9-883c-c890e1f36007" alt="Demo image"></img> <img src="https://github.com/ArthurSonzogni/FTXUI/assets/4759106/6925b6da-0a7e-49d9-883c-c890e1f36007" alt="Demo image"></img>
<br/> <br/>
@@ -22,12 +21,6 @@
<a href="https://arthursonzogni.github.io/FTXUI/examples/">Examples</a> . <a href="https://arthursonzogni.github.io/FTXUI/examples/">Examples</a> .
<a href="https://github.com/ArthurSonzogni/FTXUI/issues">Request Feature</a> · <a href="https://github.com/ArthurSonzogni/FTXUI/issues">Request Feature</a> ·
<a href="https://github.com/ArthurSonzogni/FTXUI/pulls">Send a Pull Request</a> <a href="https://github.com/ArthurSonzogni/FTXUI/pulls">Send a Pull Request</a>
<br/>
<a href="https://github.com/ArthurSonzogni/">English</a> |
<a href="https://github.com/ArthurSonzogni/ftxui-translations/tree/zh-CH">中文翻译</a> |
<a href="https://github.com/ArthurSonzogni/ftxui-translations/tree/zh-CH">繁體中文</a> |
<a href="https://github.com/ArthurSonzogni/ftxui-translations/tree/ja">日本語</a>
</p> </p>
@@ -369,9 +362,6 @@ Feel free to add your projects here:
- [FTB - tertminal file browser](https://github.com/Cyxuan0311/FTB) - [FTB - tertminal file browser](https://github.com/Cyxuan0311/FTB)
- [openJuice](https://github.com/mikomikotaishi/openJuice) - [openJuice](https://github.com/mikomikotaishi/openJuice)
- [SHOOT!](https://github.com/ShingZhanho/ENGG1340-Project-25Spring) - [SHOOT!](https://github.com/ShingZhanho/ENGG1340-Project-25Spring)
- [VerifySN (Fast Hash Tool)](https://github.com/d06i/verifySN)
- [tic-tac-toe](https://github.com/birland/tic-tac-toe)
- [typing-speed-test](https://github.com/ymcx/typing-speed-test)
### [cpp-best-practices/game_jam](https://github.com/cpp-best-practices/game_jam) ### [cpp-best-practices/game_jam](https://github.com/cpp-best-practices/game_jam)
@@ -425,13 +415,9 @@ cc_binary(
name = "your_target", name = "your_target",
srcs = ["your_source.cc"], srcs = ["your_source.cc"],
deps = [ deps = [
# Choose submodules "@ftxui//:ftxui_component",
"@ftxui//:component", "@ftxui//:ftxui_dom",
"@ftxui//:dom", "@ftxui//:ftxui_screen",
"@ftxui//:screen",
# Or use the single ftxui target (includes all modules)
# "@ftxui//:ftxui",
], ],
) )
``` ```

View File

@@ -1 +0,0 @@
../../.bazelrc

View File

@@ -1,23 +0,0 @@
# Copyright 2025 Arthur Sonzogni. All rights reserved.
# Use of this source code is governed by the MIT license that can be found in
# the LICENSE file.
# Test using individual submodules
cc_binary(
name = "smoke",
srcs = ["smoke.cpp"],
deps = [
"@ftxui//:component",
"@ftxui//:dom",
"@ftxui//:screen",
],
)
# Test using the single ftxui target
cc_binary(
name = "smoke_single_dependency",
srcs = ["smoke.cpp"],
deps = [
"@ftxui",
],
)

View File

@@ -1,9 +0,0 @@
# Copyright 2025 Arthur Sonzogni. All rights reserved.
# Use of this source code is governed by the MIT license that can be found in
# the LICENSE file.
module(
name = "ftxui_integration_test",
version = "0.0.1",
)
bazel_dep(name = "ftxui", version = "6.1.9")

View File

@@ -1,38 +0,0 @@
# FTXUI Bazel Integration Test
This directory contains integration tests to verify that FTXUI can be properly consumed as an external dependency using Bazel with Bzlmod.
## Purpose
These tests ensure that:
- FTXUI's public API is correctly exposed to external projects
- Both single-target (`@ftxui//:ftxui`) and submodule-based dependencies work correctly
- Headers are properly re-exported and accessible from downstream projects
## Build Instructions
To build all targets:
```bash
bazel build //... --enable_bzlmod --override_module=ftxui=../..
```
To build individual targets:
```bash
# Test using individual submodules
bazel build //:smoke --enable_bzlmod --override_module=ftxui=../..
# Test using the single ftxui target
bazel build //:smoke_single_dependency --enable_bzlmod --override_module=ftxui=../..
```
## Run the Examples
```bash
# Run the submodules version
./bazel-bin/smoke
# Run the single-target version
./bazel-bin/smoke_single_dependency
```

View File

@@ -1,4 +0,0 @@
# Copyright 2025 Arthur Sonzogni. All rights reserved.
# Use of this source code is governed by the MIT license that can be found in
# the LICENSE file.
workspace(name = "ftxui_smoke_test")

View File

@@ -1,16 +0,0 @@
// Copyright 2025 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 <ftxui/dom/elements.hpp>
#include <ftxui/screen/screen.hpp>
#include <ftxui/component/component.hpp>
#include <ftxui/component/screen_interactive.hpp>
int main() {
using namespace ftxui;
auto screen = ScreenInteractive::TerminalOutput();
auto component = Button("Quit", screen.ExitLoopClosure());
screen.Loop(component);
return 0;
}

View File

@@ -13,7 +13,7 @@ include(FetchContent)
FetchContent_Declare(googletest FetchContent_Declare(googletest
GIT_REPOSITORY "https://github.com/google/googletest" GIT_REPOSITORY "https://github.com/google/googletest"
GIT_TAG 52eb8108c5bdec04579160ae17225d66034bd723 # v1.17.0 GIT_TAG 23ef29555ef4789f555f1ba8c51b4c52975f0907
GIT_PROGRESS TRUE GIT_PROGRESS TRUE
) )

View File

@@ -11,9 +11,6 @@ include(CMakePackageConfigHelpers)
install( install(
TARGETS screen dom component TARGETS screen dom component
EXPORT ftxui-targets EXPORT ftxui-targets
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
) )
install( install(

View File

@@ -4,15 +4,15 @@
> [!WARNING] > [!WARNING]
> This feature is still in development, and the API may change in future releases. > This feature is still in development, and the API may change in future releases.
> Your contribution is needed to help us improve the compatibility and usability > Your contribution is needed to help us improve the compatibility and usability
> of C++ modules in FTXUI. If you encounter any issues or have suggestions, > of C++20 modules in FTXUI. If you encounter any issues or have suggestions,
> please open an issue. > please open an issue.
FTXUI experimentally supports FTXUI experimentally supports
[C++20 modules](https://en.cppreference.com/w/cpp/language/modules) to reduce [C++20 modules](https://en.cppreference.com/w/cpp/language/modules) to reduce
compilation times and improve code organization. Each part of the library has a compilation times and improve code organization. Each header has a
corresponding module, split into partitions per each header. corresponding module.
Use the FTXUI_BUILD_MODULES option to build the FTXUI project itself to provide C++20 modules, Use the FTXUI_BUILD_MODULES option to build the FTXUI project itself to provide C++ 20 modules,
for example with CMake and Ninja: for example with CMake and Ninja:
```sh ```sh
@@ -25,7 +25,7 @@ ninja
``` ```
> [!NOTE] > [!NOTE]
> To use modules, you need a C++20 compatible compiler, CMake version 3.20 or > To use modules, you need a C++20 compatible compiler, CMake version 3.20 or
> higher, and use a compatible generator like Ninja. Note that Makefile > higher, and use a compatible generator like Ninja. Note that Makefile
> generators **do not support modules**. > generators **do not support modules**.
@@ -34,12 +34,9 @@ Then, in your own code you can consume the modules and code as normal:
```cpp ```cpp
import ftxui; import ftxui;
using ftxui::Button;
using ftxui::ScreenInteractive;
int main() { int main() {
auto screen = ScreenInteractive::TerminalOutput(); auto screen = ftxui::ScreenInteractive::TerminalOutput();
auto button = Button("Click me", screen.QuitClosure()); auto button = ftxui::Button("Click me", screen.QuitClosure());
screen.Loop(button); screen.Loop(button);
return 0; return 0;
} }
@@ -73,6 +70,38 @@ are available:
- `ftxui` - `ftxui`
- `ftxui.component` - `ftxui.component`
- `ftxui.dom` - `ftxui.component.Animation`
- `ftxui.screen` - `ftxui.component.CapturedMouse`
- `ftxui.util` - `ftxui.component.Component`
- `ftxui.component.ComponentBase`
- `ftxui.component.ComponentOptions`
- `ftxui.component.Event`
- `ftxui.component.Loop`
- `ftxui.component.Mouse`
- `ftxui.component.Receiver`
- `ftxui.component.ScreenInteractive`
- `ftxui.component.Task`
- `ftxui.dom`
- `ftxui.dom.Canvas`
- `ftxui.dom.Deprecated`
- `ftxui.dom.Direction`
- `ftxui.dom.Elements`
- `ftxui.dom.FlexboxConfig`
- `ftxui.dom.LinearGradient`
- `ftxui.dom.Node`
- `ftxui.dom.Requirement`
- `ftxui.dom.Selection`
- `ftxui.dom.Table`
- `ftxui.screen`
- `ftxui.screen.Box`
- `ftxui.screen.Color`
- `ftxui.screen.ColorInfo`
- `ftxui.screen.Deprecated`
- `ftxui.screen.Image`
- `ftxui.screen.Pixel`
- `ftxui.screen.Screen`
- `ftxui.screen.String`
- `ftxui.screen.Terminal`
- `ftxui.util`
- `ftxui.util.AutoReset`
- `ftxui.util.Ref`

View File

@@ -2,9 +2,16 @@
<!-- start footer part --> <!-- start footer part -->
<!--BEGIN GENERATE_TREEVIEW--> <!--BEGIN GENERATE_TREEVIEW-->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! --> <div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
<ul>
$navpath
<li class="footer">$generatedby <a href="https://www.doxygen.org/index.html"><img class="footer" src="$relpath^doxygen.svg" width="104" height="31" alt="doxygen"/></a> $doxygenversion </li>
</ul>
</div> </div>
<!--END GENERATE_TREEVIEW--> <!--END GENERATE_TREEVIEW-->
<!--BEGIN !GENERATE_TREEVIEW--> <!--BEGIN !GENERATE_TREEVIEW-->
<hr class="footer"/><address class="footer"><small>
$generatedby&#160;<a href="https://www.doxygen.org/index.html"><img class="footer" src="$relpath^doxygen.svg" width="104" height="31" alt="doxygen"/></a> $doxygenversion
</small></address>
<!--END !GENERATE_TREEVIEW--> <!--END !GENERATE_TREEVIEW-->
</body> </body>
</html> </html>

View File

@@ -92,24 +92,6 @@
</script> </script>
<script type="module"> <script type="module">
// Ignore non english pages and/or the main page.
const excluded_lang = [
"/de",
"/es",
"/fr",
"/it",
"/ja",
"/ja",
"/ko"
"/ru",
"/zh-CH",
"/zh-TW",
]
if (excluded_lang.some(lang => window.location.pathname.startsWith(lang)) ||
window.location.pathname.endsWith("index.html")) {
return;
}
// Click on the navtree, except for the main page where this is already done // Click on the navtree, except for the main page where this is already done
// automatically. // automatically.
let delay = 0; let delay = 0;

View File

@@ -1,104 +1,24 @@
@page installation_conan Conan @page installation_conan Conan
@tableofcontents
FTXUI can be easily obtained and integrated into your project using the Conan package manager. Unofficial recipe for FTXUI exists on Conan Center:
<https://conan.io/center/recipes/ftxui>
## Prerequisites
First, ensure that Conan is installed on your system. If not, you can install it via pip:
```powershell
pip install conan
```
Conan often works in tandem with CMake, so you will need to have CMake installed as well. Once you have confirmed both Conan and CMake are installed, create a project directory, for example, `ftxui-demo`:
```powershell
mkdir C:\ftxui-demo
cd C:\ftxui-demo
```
## Configuration
After ensuring your environment is set up correctly, create a Conan configuration file `conanfile.txt`. This file is used to declare your project's dependencies. The community-maintained package for FTXUI can be found on [Conan Center](https://conan.io/center/recipes/ftxui).
> [!note] > [!note]
> This is an unofficial build script. This means it is not maintained by the FTXUI > This is an unofficial recipe. That means it is not maintained by the FTXUI
> team but by the community. The package maintainer appears to actively update it > team, but by the community. The package maintainers seems to actively update
> to the latest releases. Many thanks to the maintainer for their work! > the package to the latest version. Thanks to the maintainers for their work!
@todo If you are familiar with the process, please consider adding an "official" build script to Conan Center.
This could be a GitHub Action that automatically updates Conan Center upon new releases.
```ini @todo Add instructions on how to use the conan recipe.
[requires]
ftxui/6.0.2
[generators] @todo Please consider adding an "official" recipe to Conan Center if know how.
CMakeDeps It could be a github action that will automatically update the conan center
CMakeToolchain when a new release is made.
[layout]
cmake_layout
```
## Install Dependencies and Build
Once configured, run the following command to install FTXUI and its dependencies:
```powershell
conan install . --output-folder=build --build=missing
```
This will download and install `ftxui/6.0.2` along with all its dependencies from Conan's remote repositories.
After the installation completes, you can test it by creating a `demo.cpp` file in your project directory:
```cpp
#include <ftxui/screen/screen.hpp>
#include <ftxui/dom/elements.hpp>
#include <iostream>
int main() {
using namespace ftxui;
auto document = hbox({
text(" Hello "),
text("FTXUI ") | bold | color(Color::Red),
text(" world! ")
});
auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document));
Render(screen, document);
std::cout << screen.ToString() << std::endl;
return 0;
}
```
If the test is successful, you can then create a `CMakeLists.txt` file in the project directory:
```cmake
cmake_minimum_required(VERSION 3.20)
project(ftxui-demo)
# Set the C++ standard
set(CMAKE_CXX_STANDARD 20)
# Find the FTXUI package installed via Conan
find_package(ftxui CONFIG REQUIRED)
# Create the executable
add_executable(demo demo.cpp)
# Link the executable to the FTXUI library
target_link_libraries(demo PRIVATE ftxui::component)
```
@todo 中国大陆在这方面的下载可能会受限制,需要一个替代的方案
---
<div class="section_buttons"> <div class="section_buttons">
| Previous | | Previous |
|:------------------| |:------------------|
| [Getting Started](getting-started.html) | | [Getting Started](getting-started.html) |
</div> </div>

View File

@@ -8,7 +8,7 @@ Clone and build the project using CMake:
```bash ```bash
git clone https://github.com/ArthurSonzogni/FTXUI.git git clone https://github.com/ArthurSonzogni/FTXUI.git
cd FTXUI cd FTXUI
cmake -S . -B build -D FTXUI_ENABLE_INSTALL=ON cmake -S . -B build -DFTXUI_ENABLE_INSTALL=ON -D
cmake --build build -j cmake --build build -j
sudo cmake --install build sudo cmake --install build
``` ```

View File

@@ -39,7 +39,6 @@ example(radiobox)
example(radiobox_in_frame) example(radiobox_in_frame)
example(renderer) example(renderer)
example(resizable_split) example(resizable_split)
example(resizable_split_clamp)
example(scrollbar) example(scrollbar)
example(selection) example(selection)
example(slider) example(slider)

View File

@@ -34,8 +34,8 @@ int main() {
int value = 50; int value = 50;
// clang-format off // clang-format off
auto btn_dec_01 = Button("-1", [&] { value -= 1; }, Style()); auto btn_dec_01 = Button("-1", [&] { value += 1; }, Style());
auto btn_inc_01 = Button("+1", [&] { value += 1; }, Style()); auto btn_inc_01 = Button("+1", [&] { value -= 1; }, Style());
auto btn_dec_10 = Button("-10", [&] { value -= 10; }, Style()); auto btn_dec_10 = Button("-10", [&] { value -= 10; }, Style());
auto btn_inc_10 = Button("+10", [&] { value += 10; }, Style()); auto btn_inc_10 = Button("+10", [&] { value += 10; }, Style());
// clang-format on // clang-format on

View File

@@ -3,6 +3,7 @@
// the LICENSE file. // the LICENSE file.
#include <memory> // for shared_ptr, allocator, __shared_ptr_access #include <memory> // for shared_ptr, allocator, __shared_ptr_access
#include "ftxui/component/captured_mouse.hpp" // for ftxui
#include "ftxui/component/component.hpp" // for Renderer, ResizableSplitBottom, ResizableSplitLeft, ResizableSplitRight, ResizableSplitTop #include "ftxui/component/component.hpp" // for Renderer, ResizableSplitBottom, ResizableSplitLeft, ResizableSplitRight, ResizableSplitTop
#include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive #include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive
@@ -13,24 +14,17 @@ using namespace ftxui;
int main() { int main() {
auto screen = ScreenInteractive::Fullscreen(); auto screen = ScreenInteractive::Fullscreen();
// State: auto middle = Renderer([] { return text("middle") | center; });
auto left = Renderer([] { return text("Left") | center; });
auto right = Renderer([] { return text("right") | center; });
auto top = Renderer([] { return text("top") | center; });
auto bottom = Renderer([] { return text("bottom") | center; });
int left_size = 20; int left_size = 20;
int right_size = 20; int right_size = 20;
int top_size = 10; int top_size = 10;
int bottom_size = 10; int bottom_size = 10;
// Renderers:
auto RendererInfo = [](const std::string& name, int* size) {
return Renderer([name, size] {
return text(name + ": " + std::to_string(*size)) | center;
});
};
auto middle = Renderer([] { return text("Middle") | center; });
auto left = RendererInfo("Left", &left_size);
auto right = RendererInfo("Right", &right_size);
auto top = RendererInfo("Top", &top_size);
auto bottom = RendererInfo("Bottom", &bottom_size);
auto container = middle; auto container = middle;
container = ResizableSplitLeft(left, container, &left_size); container = ResizableSplitLeft(left, container, &left_size);
container = ResizableSplitRight(right, container, &right_size); container = ResizableSplitRight(right, container, &right_size);

View File

@@ -1,43 +0,0 @@
// Copyright 2025 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 <memory> // for shared_ptr, allocator, __shared_ptr_access
#include "ftxui/component/component.hpp" // for Renderer, ResizableSplitBottom, ResizableSplitLeft, ResizableSplitRight, ResizableSplitTop
#include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive
#include "ftxui/dom/elements.hpp" // for Element, operator|, text, center, border
using namespace ftxui;
int main() {
auto screen = ScreenInteractive::Fullscreen();
// State:
int size = 40;
int size_min = 10;
int size_max = 80;
// Renderers:
auto split = ResizableSplit({
.main = Renderer([] { return text("Left") | center; }),
.back = Renderer([] { return text("Right") | center; }),
.direction = Direction::Left,
.main_size = &size,
.min = &size_min,
.max = &size_max,
});
auto renderer = Renderer(split, [&] {
return window(text("Drag the separator with the mouse"),
vbox({
text("Min: " + std::to_string(size_min)),
text("Max: " + std::to_string(size_max)),
text("Size: " + std::to_string(size)),
separator(),
split->Render() | flex,
}));
});
screen.Loop(renderer);
}

12
flake.lock generated
View File

@@ -5,11 +5,11 @@
"systems": "systems" "systems": "systems"
}, },
"locked": { "locked": {
"lastModified": 1731533236, "lastModified": 1694529238,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
"owner": "numtide", "owner": "numtide",
"repo": "flake-utils", "repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", "rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -20,11 +20,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1765644376, "lastModified": 1697915759,
"narHash": "sha256-yqHBL2wYGwjGL2GUF2w3tofWl8qO9tZEuI4wSqbCrtE=", "narHash": "sha256-WyMj5jGcecD+KC8gEs+wFth1J1wjisZf8kVZH13f1Zo=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "23735a82a828372c4ef92c660864e82fbe2f5fbe", "rev": "51d906d2341c9e866e48c2efcaac0f2d70bfd43e",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -12,9 +12,15 @@
let llvm = pkgs.llvmPackages_latest; in let llvm = pkgs.llvmPackages_latest; in
{ {
packages = rec { packages = rec {
default = pkgs.stdenv.mkDerivation { default = pkgs.stdenv.mkDerivation rec {
name = "ftxui"; pname = "ftxui";
src = ./.; version = "v4.0.0";
src = pkgs.fetchFromGitHub {
owner = "ArthurSonzogni";
repo = "FTXUI";
rev = version;
sha256 = "sha256-3kAhHDUwzwdvHc8JZAcA14tGqa6w69qrN1JXhSxNBQY=";
};
nativeBuildInputs = [ nativeBuildInputs = [
pkgs.cmake pkgs.cmake

View File

@@ -11,7 +11,6 @@
#include <ftxui/util/ref.hpp> // for Ref, ConstRef, StringRef #include <ftxui/util/ref.hpp> // for Ref, ConstRef, StringRef
#include <ftxui/util/warn_windows_macro.hpp> #include <ftxui/util/warn_windows_macro.hpp>
#include <functional> // for function #include <functional> // for function
#include <limits> // for numeric_limits
#include <string> // for string #include <string> // for string
#include "ftxui/component/component_base.hpp" // for Component #include "ftxui/component/component_base.hpp" // for Component
@@ -218,10 +217,6 @@ struct ResizableSplitOption {
(direction() == Direction::Left || direction() == Direction::Right) ? 20 (direction() == Direction::Left || direction() == Direction::Right) ? 20
: 10; : 10;
std::function<Element()> separator_func = [] { return ::ftxui::separator(); }; std::function<Element()> separator_func = [] { return ::ftxui::separator(); };
// Constraints on main_size:
Ref<int> min = 0;
Ref<int> max = std::numeric_limits<int>::max();
}; };
// @brief Option for the `Slider` component. // @brief Option for the `Slider` component.

View File

@@ -6,7 +6,6 @@
#include <ftxui/component/mouse.hpp> // for Mouse #include <ftxui/component/mouse.hpp> // for Mouse
#include <string> // for string, operator== #include <string> // for string, operator==
#include <string_view>
namespace ftxui { namespace ftxui {
@@ -29,13 +28,13 @@ class ComponentBase;
/// @ingroup component /// @ingroup component
struct Event { struct Event {
// --- Constructor section --------------------------------------------------- // --- Constructor section ---------------------------------------------------
static Event Character(std::string_view); static Event Character(std::string);
static Event Character(char); static Event Character(char);
static Event Character(wchar_t); static Event Character(wchar_t);
static Event Special(std::string_view); static Event Special(std::string);
static Event Mouse(std::string_view, Mouse mouse); static Event Mouse(std::string, Mouse mouse);
static Event CursorPosition(std::string_view, int x, int y); // Internal static Event CursorPosition(std::string, int x, int y); // Internal
static Event CursorShape(std::string_view, int shape); // Internal static Event CursorShape(std::string, int shape); // Internal
// --- Arrow --- // --- Arrow ---
static const Event ArrowLeft; static const Event ArrowLeft;

View File

@@ -4,14 +4,14 @@
#ifndef FTXUI_COMPONENT_RECEIVER_HPP_ #ifndef FTXUI_COMPONENT_RECEIVER_HPP_
#define FTXUI_COMPONENT_RECEIVER_HPP_ #define FTXUI_COMPONENT_RECEIVER_HPP_
#include <ftxui/util/warn_windows_macro.hpp>
#include <algorithm> // for copy, max #include <algorithm> // for copy, max
#include <atomic> // for atomic, __atomic_base #include <atomic> // for atomic, __atomic_base
#include <condition_variable> // for condition_variable #include <condition_variable> // for condition_variable
#include <ftxui/util/warn_windows_macro.hpp> #include <memory> // for unique_ptr, make_unique
#include <memory> // for unique_ptr, make_unique #include <mutex> // for mutex, unique_lock
#include <mutex> // for mutex, unique_lock #include <queue> // for queue
#include <queue> // for queue #include <utility> // for move
#include <utility> // for move
namespace ftxui { namespace ftxui {

View File

@@ -106,9 +106,9 @@ struct Canvas {
// Draw using character of size 2x4 at position (x,y) // Draw using character of size 2x4 at position (x,y)
// x is considered to be a multiple of 2. // x is considered to be a multiple of 2.
// y is considered to be a multiple of 4. // y is considered to be a multiple of 4.
void DrawText(int x, int y, std::string_view value); void DrawText(int x, int y, const std::string& value);
void DrawText(int x, int y, std::string_view value, const Color& color); void DrawText(int x, int y, const std::string& value, const Color& color);
void DrawText(int x, int y, std::string_view value, const Stylizer& style); void DrawText(int x, int y, const std::string& value, const Stylizer& style);
// Draw using directly pixels or images -------------------------------------- // Draw using directly pixels or images --------------------------------------
// x is considered to be a multiple of 2. // x is considered to be a multiple of 2.

View File

@@ -7,7 +7,6 @@
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <string_view>
#include "ftxui/dom/canvas.hpp" #include "ftxui/dom/canvas.hpp"
#include "ftxui/dom/direction.hpp" #include "ftxui/dom/direction.hpp"
#include "ftxui/dom/flexbox_config.hpp" #include "ftxui/dom/flexbox_config.hpp"
@@ -52,8 +51,8 @@ Elements operator|(Elements, Decorator);
Decorator operator|(Decorator, Decorator); Decorator operator|(Decorator, Decorator);
// --- Widget --- // --- Widget ---
Element text(std::string_view text); Element text(std::string text);
Element vtext(std::string_view text); Element vtext(std::string text);
Element separator(); Element separator();
Element separatorLight(); Element separatorLight();
Element separatorDashed(); Element separatorDashed();
@@ -62,7 +61,7 @@ Element separatorDouble();
Element separatorEmpty(); Element separatorEmpty();
Element separatorStyled(BorderStyle); Element separatorStyled(BorderStyle);
Element separator(Pixel); Element separator(Pixel);
Element separatorCharacter(std::string_view); Element separatorCharacter(std::string);
Element separatorHSelector(float left, Element separatorHSelector(float left,
float right, float right,
Color unselected_color, Color unselected_color,
@@ -90,11 +89,11 @@ Decorator borderStyled(Color);
Decorator borderWith(const Pixel&); Decorator borderWith(const Pixel&);
Element window(Element title, Element content, BorderStyle border = ROUNDED); Element window(Element title, Element content, BorderStyle border = ROUNDED);
Element spinner(int charset_index, size_t image_index); Element spinner(int charset_index, size_t image_index);
Element paragraph(std::string_view text); Element paragraph(const std::string& text);
Element paragraphAlignLeft(std::string_view text); Element paragraphAlignLeft(const std::string& text);
Element paragraphAlignRight(std::string_view text); Element paragraphAlignRight(const std::string& text);
Element paragraphAlignCenter(std::string_view text); Element paragraphAlignCenter(const std::string& text);
Element paragraphAlignJustify(std::string_view text); Element paragraphAlignJustify(const std::string& text);
Element graph(GraphFunction); Element graph(GraphFunction);
Element emptyElement(); Element emptyElement();
Element canvas(ConstRef<Canvas>); Element canvas(ConstRef<Canvas>);
@@ -121,8 +120,8 @@ Element bgcolor(const LinearGradient&, Element);
Decorator focusPosition(int x, int y); Decorator focusPosition(int x, int y);
Decorator focusPositionRelative(float x, float y); Decorator focusPositionRelative(float x, float y);
Element automerge(Element child); Element automerge(Element child);
Decorator hyperlink(std::string_view link); Decorator hyperlink(std::string link);
Element hyperlink(std::string_view link, Element child); Element hyperlink(std::string link, Element child);
Element selectionStyleReset(Element); Element selectionStyleReset(Element);
Decorator selectionColor(Color foreground); Decorator selectionColor(Color foreground);
Decorator selectionBackgroundColor(Color foreground); Decorator selectionBackgroundColor(Color foreground);

View File

@@ -30,7 +30,7 @@ class Selection {
Selection SaturateVertical(Box box); Selection SaturateVertical(Box box);
bool IsEmpty() const { return empty_; } bool IsEmpty() const { return empty_; }
void AddPart(std::string_view part, int y, int left, int right); void AddPart(const std::string& part, int y, int left, int right);
std::string GetParts() { return parts_.str(); } std::string GetParts() { return parts_.str(); }
private: private:

View File

@@ -5,18 +5,25 @@
#define FTXUI_DOM_TAKE_ANY_ARGS_HPP #define FTXUI_DOM_TAKE_ANY_ARGS_HPP
// IWYU pragma: private, include "ftxui/dom/elements.hpp" // IWYU pragma: private, include "ftxui/dom/elements.hpp"
#include <deque>
#include <ftxui/dom/node.hpp> #include <ftxui/dom/node.hpp>
#include <queue>
#include <stack>
#include <vector>
namespace ftxui { namespace ftxui {
template <class T>
void Merge(Elements& /*container*/, T /*element*/) {}
template <>
inline void Merge(Elements& container, Element element) { inline void Merge(Elements& container, Element element) {
container.push_back(std::move(element)); container.push_back(std::move(element));
} }
template <>
inline void Merge(Elements& container, Elements elements) {
for (auto& element : elements) {
container.push_back(std::move(element));
}
}
// Turn a set of arguments into a vector. // Turn a set of arguments into a vector.
template <class... Args> template <class... Args>
Elements unpack(Args... args) { Elements unpack(Args... args) {
@@ -25,50 +32,11 @@ Elements unpack(Args... args) {
return vec; return vec;
} }
// Make |container| able to take any number of arguments. // Make |container| able to take any number of argments.
#define TAKE_ANY_ARGS(container) \ #define TAKE_ANY_ARGS(container) \
inline Element container(Element child) { \
return container(unpack(std::move(child))); \
} \
\
template <class... Args> \ template <class... Args> \
inline Element container(Args... children) { \ Element container(Args... children) { \
return container(unpack(std::forward<Args>(children)...)); \ return container(unpack(std::forward<Args>(children)...)); \
} \
\
template <class Container> \
inline Element container(Container&& children) { \
Elements elements; \
for (auto& child : children) { \
elements.push_back(std::move(child)); \
} \
return container(std::move(elements)); \
} \
template <> \
inline Element container(std::stack<Element>&& children) { \
Elements elements; \
while (!children.empty()) { \
elements.push_back(std::move(children.top())); \
children.pop(); \
} \
return container(std::move(elements)); \
} \
template <> \
inline Element container(std::queue<Element>&& children) { \
Elements elements; \
while (!children.empty()) { \
elements.push_back(std::move(children.front())); \
children.pop(); \
} \
return container(std::move(elements)); \
} \
template <> \
inline Element container(std::deque<Element>&& children) { \
Elements elements; \
for (auto& child : children) { \
elements.push_back(std::move(child)); \
} \
return container(std::move(elements)); \
} }
TAKE_ANY_ARGS(vbox) TAKE_ANY_ARGS(vbox)

View File

@@ -60,7 +60,7 @@ class Screen : public Image {
BarBlinking = 5, BarBlinking = 5,
Bar = 6, Bar = 6,
}; };
Shape shape = Hidden; Shape shape;
}; };
Cursor cursor() const { return cursor_; } Cursor cursor() const { return cursor_; }
@@ -68,7 +68,7 @@ class Screen : public Image {
// Store an hyperlink in the screen. Return the id of the hyperlink. The id is // Store an hyperlink in the screen. Return the id of the hyperlink. The id is
// used to identify the hyperlink when the user click on it. // used to identify the hyperlink when the user click on it.
uint8_t RegisterHyperlink(std::string_view link); uint8_t RegisterHyperlink(const std::string& link);
const std::string& Hyperlink(uint8_t id) const; const std::string& Hyperlink(uint8_t id) const;
using SelectionStyle = std::function<void(Pixel&)>; using SelectionStyle = std::function<void(Pixel&)>;

View File

@@ -4,32 +4,27 @@
#ifndef FTXUI_SCREEN_STRING_HPP #ifndef FTXUI_SCREEN_STRING_HPP
#define FTXUI_SCREEN_STRING_HPP #define FTXUI_SCREEN_STRING_HPP
#include <string> // for string, wstring, to_string #include <string> // for string, wstring, to_string
#include <string_view> // for string_view #include <vector> // for vector
#include <vector> // for vector
namespace ftxui { namespace ftxui {
std::string to_string(std::wstring_view s); std::string to_string(const std::wstring& s);
std::wstring to_wstring(std::string_view s); std::wstring to_wstring(const std::string& s);
template <typename T> template <typename T>
std::wstring to_wstring(T s) { std::wstring to_wstring(T s) {
return to_wstring(std::string_view(std::to_string(s))); return to_wstring(std::to_string(s));
}
template <>
inline std::wstring to_wstring(const char* s) {
return to_wstring(std::string_view(s));
} }
int string_width(std::string_view); int string_width(const std::string&);
// Split the string into a its glyphs. An empty one is inserted ater fullwidth // Split the string into a its glyphs. An empty one is inserted ater fullwidth
// ones. // ones.
std::vector<std::string> Utf8ToGlyphs(std::string_view input); std::vector<std::string> Utf8ToGlyphs(const std::string& input);
// Map every cells drawn by |input| to their corresponding Glyphs. Half-size // Map every cells drawn by |input| to their corresponding Glyphs. Half-size
// Glyphs takes one cell, full-size Glyphs take two cells. // Glyphs takes one cell, full-size Glyphs take two cells.
std::vector<int> CellToGlyphIndex(std::string_view input); std::vector<int> CellToGlyphIndex(const std::string& input);
} // namespace ftxui } // namespace ftxui

View File

@@ -7,7 +7,6 @@
#include <ftxui/screen/string.hpp> #include <ftxui/screen/string.hpp>
#include <memory> #include <memory>
#include <string> #include <string>
#include <string_view>
#include <variant> #include <variant>
#include <vector> #include <vector>
@@ -18,13 +17,8 @@ template <typename T>
class ConstRef { class ConstRef {
public: public:
ConstRef() = default; ConstRef() = default;
// Owning constructors:
ConstRef(T t) : variant_(std::move(t)) {} // NOLINT ConstRef(T t) : variant_(std::move(t)) {} // NOLINT
// Referencing constructors:
ConstRef(const T* t) : variant_(t) {} // NOLINT ConstRef(const T* t) : variant_(t) {} // NOLINT
ConstRef& operator=(ConstRef&&) noexcept = default; ConstRef& operator=(ConstRef&&) noexcept = default;
ConstRef(const ConstRef<T>&) = default; ConstRef(const ConstRef<T>&) = default;
ConstRef(ConstRef<T>&&) noexcept = default; ConstRef(ConstRef<T>&&) noexcept = default;
@@ -52,13 +46,8 @@ template <typename T>
class Ref { class Ref {
public: public:
Ref() = default; Ref() = default;
// Owning constructors:
Ref(T t) : variant_(std::move(t)) {} // NOLINT Ref(T t) : variant_(std::move(t)) {} // NOLINT
//
// Referencing constructors:
Ref(T* t) : variant_(t) {} // NOLINT Ref(T* t) : variant_(t) {} // NOLINT
//
~Ref() = default; ~Ref() = default;
Ref& operator=(Ref&&) noexcept = default; Ref& operator=(Ref&&) noexcept = default;
Ref(const Ref<T>&) = default; Ref(const Ref<T>&) = default;
@@ -94,15 +83,10 @@ class StringRef : public Ref<std::string> {
public: public:
using Ref<std::string>::Ref; using Ref<std::string>::Ref;
// Owning constructors:
StringRef(const wchar_t* ref) // NOLINT StringRef(const wchar_t* ref) // NOLINT
: StringRef(to_string(std::wstring(ref))) {} : StringRef(to_string(std::wstring(ref))) {}
StringRef(const char* ref) // NOLINT StringRef(const char* ref) // NOLINT
: StringRef(std::string(ref)) {} : StringRef(std::string(ref)) {}
StringRef(std::string_view ref) // NOLINT
: StringRef(std::string(ref)) {}
StringRef(std::wstring_view ref) // NOLINT
: StringRef(to_string(ref)) {}
}; };
/// @brief An adapter. Own or reference a constant string. For convenience, this /// @brief An adapter. Own or reference a constant string. For convenience, this
@@ -111,21 +95,14 @@ class ConstStringRef : public ConstRef<std::string> {
public: public:
using ConstRef<std::string>::ConstRef; using ConstRef<std::string>::ConstRef;
// Referencing constructors:
ConstStringRef(const std::wstring* ref) // NOLINT ConstStringRef(const std::wstring* ref) // NOLINT
: ConstStringRef(to_string(*ref)) {} : ConstStringRef(to_string(*ref)) {}
// Owning constructors:
ConstStringRef(const std::wstring ref) // NOLINT ConstStringRef(const std::wstring ref) // NOLINT
: ConstStringRef(to_string(ref)) {} : ConstStringRef(to_string(ref)) {}
ConstStringRef(std::wstring_view ref) // NOLINT
: ConstStringRef(to_string(ref)) {}
ConstStringRef(const wchar_t* ref) // NOLINT ConstStringRef(const wchar_t* ref) // NOLINT
: ConstStringRef(to_string(std::wstring(ref))) {} : ConstStringRef(to_string(std::wstring(ref))) {}
ConstStringRef(const char* ref) // NOLINT ConstStringRef(const char* ref) // NOLINT
: ConstStringRef(std::string(ref)) {} : ConstStringRef(std::string(ref)) {}
ConstStringRef(std::string_view ref) // NOLINT
: ConstStringRef(std::string(ref)) {}
}; };
/// @brief An adapter. Reference a list of strings. /// @brief An adapter. Reference a list of strings.
@@ -148,15 +125,13 @@ class ConstStringListRef {
Adapter& operator=(Adapter&&) = default; Adapter& operator=(Adapter&&) = default;
virtual ~Adapter() = default; virtual ~Adapter() = default;
virtual size_t size() const = 0; virtual size_t size() const = 0;
virtual std::string_view operator[](size_t i) const = 0; virtual std::string operator[](size_t i) const = 0;
}; };
using Variant = std::variant<const std::vector<std::string>, // using Variant = std::variant<const std::vector<std::string>, //
const std::vector<std::string>*, // const std::vector<std::string>*, //
const std::vector<std::string_view>, // const std::vector<std::wstring>*, //
const std::vector<std::string_view>*, // Adapter*, //
const std::vector<std::wstring>*, // std::unique_ptr<Adapter> //
Adapter*, //
std::unique_ptr<Adapter> //
>; >;
ConstStringListRef() = default; ConstStringListRef() = default;
@@ -166,26 +141,25 @@ class ConstStringListRef {
ConstStringListRef(ConstStringListRef&&) = default; ConstStringListRef(ConstStringListRef&&) = default;
ConstStringListRef(const ConstStringListRef&) = default; ConstStringListRef(const ConstStringListRef&) = default;
ConstStringListRef(std::vector<std::string> value) { // NOLINT ConstStringListRef(std::vector<std::string> value) // NOLINT
{
variant_ = std::make_shared<Variant>(value); variant_ = std::make_shared<Variant>(value);
} }
ConstStringListRef(const std::vector<std::string>* value) {// NOLINT ConstStringListRef(const std::vector<std::string>* value) // NOLINT
{
variant_ = std::make_shared<Variant>(value); variant_ = std::make_shared<Variant>(value);
} }
ConstStringListRef(std::vector<std::string_view> value) { // NOLINT ConstStringListRef(const std::vector<std::wstring>* value) // NOLINT
{
variant_ = std::make_shared<Variant>(value); variant_ = std::make_shared<Variant>(value);
} }
ConstStringListRef(const std::vector<std::string_view>* value) { // NOLINT ConstStringListRef(Adapter* adapter) // NOLINT
variant_ = std::make_shared<Variant>(value); {
}
ConstStringListRef(const std::vector<std::wstring>* value) { // NOLINT
variant_ = std::make_shared<Variant>(value);
}
ConstStringListRef(Adapter* adapter) { // NOLINT
variant_ = std::make_shared<Variant>(adapter); variant_ = std::make_shared<Variant>(adapter);
} }
template <typename AdapterType> template <typename AdapterType>
ConstStringListRef(std::unique_ptr<AdapterType> adapter) { // NOLINT ConstStringListRef(std::unique_ptr<AdapterType> adapter) // NOLINT
{
variant_ = std::make_shared<Variant>( variant_ = std::make_shared<Variant>(
static_cast<std::unique_ptr<Adapter>>(std::move(adapter))); static_cast<std::unique_ptr<Adapter>>(std::move(adapter)));
} }
@@ -194,34 +168,11 @@ class ConstStringListRef {
return variant_ ? std::visit(SizeVisitor(), *variant_) : 0; return variant_ ? std::visit(SizeVisitor(), *variant_) : 0;
} }
std::string_view operator[](size_t i) const { std::string operator[](size_t i) const {
return variant_ ? std::visit(IndexedGetter{i}, *variant_) : ""; return variant_ ? std::visit(IndexedGetter(i), *variant_) : "";
} }
private: private:
struct IndexedGetter {
size_t i;
std::string_view operator()(const std::vector<std::string>& v) const {
return v[i];
}
std::string_view operator()(const std::vector<std::string>* v) const {
return (*v)[i];
}
std::string_view operator()(const std::vector<std::string_view>& v) const {
return std::string(v[i]);
}
std::string_view operator()(const std::vector<std::string_view>* v) const {
return std::string((*v)[i]);
}
std::string_view operator()(const std::vector<std::wstring>* v) const {
return to_string((*v)[i]);
}
std::string_view operator()(Adapter* v) const { return std::string((*v)[i]); }
std::string_view operator()(const std::unique_ptr<Adapter>& v) const {
return (*v)[i];
}
};
struct SizeVisitor { struct SizeVisitor {
size_t operator()(const std::vector<std::string>& v) const { size_t operator()(const std::vector<std::string>& v) const {
return v.size(); return v.size();
@@ -229,12 +180,6 @@ class ConstStringListRef {
size_t operator()(const std::vector<std::string>* v) const { size_t operator()(const std::vector<std::string>* v) const {
return v->size(); return v->size();
} }
size_t operator()(const std::vector<std::string_view>& v) const {
return v.size();
}
size_t operator()(const std::vector<std::string_view>* v) const {
return v->size();
}
size_t operator()(const std::vector<std::wstring>* v) const { size_t operator()(const std::vector<std::wstring>* v) const {
return v->size(); return v->size();
} }
@@ -244,6 +189,25 @@ class ConstStringListRef {
} }
}; };
struct IndexedGetter {
IndexedGetter(size_t index) // NOLINT
: index_(index) {}
size_t index_;
std::string operator()(const std::vector<std::string>& v) const {
return v[index_];
}
std::string operator()(const std::vector<std::string>* v) const {
return (*v)[index_];
}
std::string operator()(const std::vector<std::wstring>* v) const {
return to_string((*v)[index_]);
}
std::string operator()(const Adapter* v) const { return (*v)[index_]; }
std::string operator()(const std::unique_ptr<Adapter>& v) const {
return (*v)[index_];
}
};
std::shared_ptr<Variant> variant_; std::shared_ptr<Variant> variant_;
}; };

View File

@@ -3,14 +3,14 @@
export module ftxui.component; export module ftxui.component;
export import :Animation; export import ftxui.component.animation;
export import :CapturedMouse; export import ftxui.component.captured_mouse;
export import :Component; export import ftxui.component.component;
export import :ComponentBase; export import ftxui.component.component_base;
export import :ComponentOptions; export import ftxui.component.component_options;
export import :Event; export import ftxui.component.event;
export import :Loop; export import ftxui.component.loop;
export import :Mouse; export import ftxui.component.mouse;
export import :Receiver; export import ftxui.component.receiver;
export import :ScreenInteractive; export import ftxui.component.screen_interactive;
export import :Task; export import ftxui.component.task;

View File

@@ -1,4 +1,4 @@
/// @module ftxui.component:Animation /// @module ftxui.component.animation
/// @brief C++20 module interface for the Animation namespace of the Component module. /// @brief C++20 module interface for the Animation namespace of the Component module.
/// ///
@@ -6,7 +6,7 @@ module;
#include <ftxui/component/animation.hpp> #include <ftxui/component/animation.hpp>
export module ftxui.component:Animation; export module ftxui.component.animation;
/** /**
* @namespace ftxui::animation * @namespace ftxui::animation
@@ -23,7 +23,7 @@ export namespace ftxui::animation {
/** /**
* @namespace easing * @namespace easing
* @brief The FTXUI ftxui::animation::easing:: namespace * @brief The FTXUI sf::animation::easing:: namespace
*/ */
namespace easing { namespace easing {
using ftxui::animation::easing::Function; using ftxui::animation::easing::Function;

View File

@@ -48,7 +48,7 @@ class ButtonBase : public ComponentBase, public ButtonOption {
} }
const EntryState state{ const EntryState state{
std::string(*label), false, active, focused_or_hover, Index(), *label, false, active, focused_or_hover, Index(),
}; };
auto element = (transform ? transform : DefaultTransform) // auto element = (transform ? transform : DefaultTransform) //

View File

@@ -1,11 +1,11 @@
/// @module ftxui.component.CapturedMouse /// @module ftxui.component.captured_mouse
/// @brief Module file for the CapturedMouseInterface class of the Component module /// @brief Module file for the CapturedMouseInterface class of the Component module
module; module;
#include <ftxui/component/captured_mouse.hpp> #include <ftxui/component/captured_mouse.hpp>
export module ftxui.component:CapturedMouse; export module ftxui.component.captured_mouse;
/** /**
* @namespace ftxui * @namespace ftxui

View File

@@ -27,7 +27,7 @@ class CheckboxBase : public ComponentBase, public CheckboxOption {
const bool is_focused = Focused(); const bool is_focused = Focused();
const bool is_active = Active(); const bool is_active = Active();
auto entry_state = EntryState{ auto entry_state = EntryState{
std::string(*label), *checked, is_active, is_focused || hovered_, -1, *label, *checked, is_active, is_focused || hovered_, -1,
}; };
auto element = (transform ? transform : CheckboxOption::Simple().transform)( auto element = (transform ? transform : CheckboxOption::Simple().transform)(
entry_state); entry_state);

View File

@@ -1,11 +1,11 @@
/// @module ftxui.component:Component /// @module ftxui.component.component
/// @brief Module file for the Component classes of the Component module /// @brief Module file for the Component classes of the Component module
module; module;
#include <ftxui/component/component.hpp> #include <ftxui/component/component.hpp>
export module ftxui.component:Component; export module ftxui.component.component;
/** /**
* @namespace ftxui * @namespace ftxui
@@ -28,10 +28,6 @@ export namespace ftxui {
using ftxui::operator|; using ftxui::operator|;
using ftxui::operator|=; using ftxui::operator|=;
/**
* @namespace Container
* @brief The FTXUI ftxui::Container:: namespace
*/
namespace Container { namespace Container {
using ftxui::Container::Vertical; using ftxui::Container::Vertical;
using ftxui::Container::Horizontal; using ftxui::Container::Horizontal;

View File

@@ -1,11 +1,11 @@
/// @module ftxui.component:ComponentBase /// @module ftxui.component.component_base
/// @brief Module file for the ComponentBase class of the Component module /// @brief Module file for the ComponentBase class of the Component module
module; module;
#include <ftxui/component/component_base.hpp> #include <ftxui/component/component_base.hpp>
export module ftxui.component:ComponentBase; export module ftxui.component.component_base;
/** /**
* @namespace ftxui * @namespace ftxui
@@ -16,10 +16,6 @@ export namespace ftxui {
using ftxui::Focus; using ftxui::Focus;
using ftxui::Event; using ftxui::Event;
/**
* @namespace animation
* @brief The FTXUI ftxui::animation:: namespace
*/
namespace animation { namespace animation {
using ftxui::animation::Params; using ftxui::animation::Params;
} }

View File

@@ -1,11 +1,11 @@
/// @module ftxui.component:ComponentOptions /// @module ftxui.component.component_options
/// @brief Module file for options for the Component class of the Component module /// @brief Module file for options for the Component class of the Component module
module; module;
#include <ftxui/component/component_options.hpp> #include <ftxui/component/component_options.hpp>
export module ftxui.component:ComponentOptions; export module ftxui.component.component_options;
/** /**
* @namespace ftxui * @namespace ftxui

View File

@@ -25,9 +25,9 @@ namespace ftxui {
/// @brief An event corresponding to a given typed character. /// @brief An event corresponding to a given typed character.
/// @param input The character typed by the user. /// @param input The character typed by the user.
// static // static
Event Event::Character(std::string_view input) { Event Event::Character(std::string input) {
Event event; Event event;
event.input_ = std::string(input); event.input_ = std::move(input);
event.type_ = Type::Character; event.type_ = Type::Character;
return event; return event;
} }
@@ -50,9 +50,9 @@ Event Event::Character(wchar_t c) {
/// @param input The sequence of character send by the terminal. /// @param input The sequence of character send by the terminal.
/// @param mouse The mouse state. /// @param mouse The mouse state.
// static // static
Event Event::Mouse(std::string_view input, struct Mouse mouse) { Event Event::Mouse(std::string input, struct Mouse mouse) {
Event event; Event event;
event.input_ = std::string(input); event.input_ = std::move(input);
event.type_ = Type::Mouse; event.type_ = Type::Mouse;
event.data_.mouse = mouse; // NOLINT event.data_.mouse = mouse; // NOLINT
return event; return event;
@@ -60,9 +60,9 @@ Event Event::Mouse(std::string_view input, struct Mouse mouse) {
/// @brief An event corresponding to a terminal DCS (Device Control String). /// @brief An event corresponding to a terminal DCS (Device Control String).
// static // static
Event Event::CursorShape(std::string_view input, int shape) { Event Event::CursorShape(std::string input, int shape) {
Event event; Event event;
event.input_ = std::string(input); event.input_ = std::move(input);
event.type_ = Type::CursorShape; event.type_ = Type::CursorShape;
event.data_.cursor_shape = shape; // NOLINT event.data_.cursor_shape = shape; // NOLINT
return event; return event;
@@ -71,17 +71,17 @@ Event Event::CursorShape(std::string_view input, int shape) {
/// @brief An custom event whose meaning is defined by the user of the library. /// @brief An custom event whose meaning is defined by the user of the library.
/// @param input An arbitrary sequence of character defined by the developer. /// @param input An arbitrary sequence of character defined by the developer.
// static // static
Event Event::Special(std::string_view input) { Event Event::Special(std::string input) {
Event event; Event event;
event.input_ = std::string(input); event.input_ = std::move(input);
return event; return event;
} }
/// @internal /// @internal
// static // static
Event Event::CursorPosition(std::string_view input, int x, int y) { Event Event::CursorPosition(std::string input, int x, int y) {
Event event; Event event;
event.input_ = std::string(input); event.input_ = std::move(input);
event.type_ = Type::CursorPosition; event.type_ = Type::CursorPosition;
event.data_.cursor = {x, y}; // NOLINT event.data_.cursor = {x, y}; // NOLINT
return event; return event;
@@ -292,12 +292,12 @@ const Event Event::ArrowLeftCtrl = Event::Special("\x1B[1;5D");
const Event Event::ArrowRightCtrl = Event::Special("\x1B[1;5C"); const Event Event::ArrowRightCtrl = Event::Special("\x1B[1;5C");
const Event Event::ArrowUpCtrl = Event::Special("\x1B[1;5A"); const Event Event::ArrowUpCtrl = Event::Special("\x1B[1;5A");
const Event Event::ArrowDownCtrl = Event::Special("\x1B[1;5B"); const Event Event::ArrowDownCtrl = Event::Special("\x1B[1;5B");
const Event Event::Backspace = Event::Special(std::string({127})); const Event Event::Backspace = Event::Special({127});
const Event Event::Delete = Event::Special("\x1B[3~"); const Event Event::Delete = Event::Special("\x1B[3~");
const Event Event::Escape = Event::Special("\x1B"); const Event Event::Escape = Event::Special("\x1B");
const Event Event::Return = Event::Special(std::string({10})); const Event Event::Return = Event::Special({10});
const Event Event::Tab = Event::Special(std::string({9})); const Event Event::Tab = Event::Special({9});
const Event Event::TabReverse = Event::Special(std::string({27, 91, 90})); const Event Event::TabReverse = Event::Special({27, 91, 90});
// See https://invisible-island.net/xterm/xterm-function-keys.html // See https://invisible-island.net/xterm/xterm-function-keys.html
// We follow xterm-new / vterm-xf86-v4 / mgt / screen // We follow xterm-new / vterm-xf86-v4 / mgt / screen
@@ -315,11 +315,11 @@ const Event Event::F11 = Event::Special("\x1B[23~");
const Event Event::F12 = Event::Special("\x1B[24~"); const Event Event::F12 = Event::Special("\x1B[24~");
const Event Event::Insert = Event::Special("\x1B[2~"); const Event Event::Insert = Event::Special("\x1B[2~");
const Event Event::Home = Event::Special(std::string({27, 91, 72})); const Event Event::Home = Event::Special({27, 91, 72});
const Event Event::End = Event::Special(std::string({27, 91, 70})); const Event Event::End = Event::Special({27, 91, 70});
const Event Event::PageUp = Event::Special(std::string({27, 91, 53, 126})); const Event Event::PageUp = Event::Special({27, 91, 53, 126});
const Event Event::PageDown = Event::Special(std::string({27, 91, 54, 126})); const Event Event::PageDown = Event::Special({27, 91, 54, 126});
const Event Event::Custom = Event::Special(std::string({0})); const Event Event::Custom = Event::Special({0});
const Event Event::a = Event::Character("a"); const Event Event::a = Event::Character("a");
const Event Event::b = Event::Character("b"); const Event Event::b = Event::Character("b");

View File

@@ -1,11 +1,11 @@
/// @module ftxui.component:Event /// @module ftxui.component.event
/// @brief Module file for the Event struct of the Component module /// @brief Module file for the Event struct of the Component module
module; module;
#include <ftxui/component/event.hpp> #include <ftxui/component/event.hpp>
export module ftxui.component:Event; export module ftxui.component.event;
/** /**
* @namespace ftxui * @namespace ftxui

View File

@@ -173,7 +173,7 @@ class InputBase : public ComponentBase, public InputOption {
elements.push_back(element); elements.push_back(element);
} }
auto element = vbox(std::move(elements)) | frame; auto element = vbox(std::move(elements), cursor_line) | frame;
return transform_func({ return transform_func({
std::move(element), hovered_, is_focused, std::move(element), hovered_, is_focused,
false // placeholder false // placeholder

View File

@@ -1,11 +1,11 @@
/// @module ftxui.component:Loop /// @module ftxui.component.loop
/// @brief Module file for the Loop class of the Component module /// @brief Module file for the Loop class of the Component module
module; module;
#include <ftxui/component/loop.hpp> #include <ftxui/component/loop.hpp>
export module ftxui.component:Loop; export module ftxui.component.loop;
/** /**
* @namespace ftxui * @namespace ftxui

View File

@@ -123,7 +123,7 @@ class MenuBase : public ComponentBase, public MenuOption {
const bool is_selected = (selected() == i); const bool is_selected = (selected() == i);
const EntryState state = { const EntryState state = {
std::string(entries[i]), false, is_selected, is_focused, i, entries[i], false, is_selected, is_focused, i,
}; };
Element element = (entries_option.transform ? entries_option.transform Element element = (entries_option.transform ? entries_option.transform
@@ -144,8 +144,9 @@ class MenuBase : public ComponentBase, public MenuOption {
std::reverse(elements.begin(), elements.end()); std::reverse(elements.begin(), elements.end());
} }
const Element bar = const Element bar = IsHorizontal()
IsHorizontal() ? hbox(std::move(elements)) : vbox(std::move(elements)); ? hbox(std::move(elements), selected_focus_)
: vbox(std::move(elements), selected_focus_);
if (!underline.enabled) { if (!underline.enabled) {
return bar | reflect(box_); return bar | reflect(box_);
@@ -622,7 +623,7 @@ Component MenuEntry(MenuEntryOption option) {
UpdateAnimationTarget(); UpdateAnimationTarget();
const EntryState state{ const EntryState state{
std::string(label()), false, hovered_, is_focused, Index(), label(), false, hovered_, is_focused, Index(),
}; };
Element element = (transform ? transform : DefaultOptionTransform) // Element element = (transform ? transform : DefaultOptionTransform) //

View File

@@ -1,11 +1,11 @@
/// @module ftxui.component:Mouse /// @module ftxui.component.mouse
/// @brief Module file for the Mouse struct of the Component module /// @brief Module file for the Mouse struct of the Component module
module; module;
#include <ftxui/component/mouse.hpp> #include <ftxui/component/mouse.hpp>
export module ftxui.component:Mouse; export module ftxui.component.mouse;
/** /**
* @namespace ftxui * @namespace ftxui

View File

@@ -37,7 +37,7 @@ class RadioboxBase : public ComponentBase, public RadioboxOption {
const bool is_focused = (focused_entry() == i) && is_menu_focused; const bool is_focused = (focused_entry() == i) && is_menu_focused;
const bool is_selected = (hovered_ == i); const bool is_selected = (hovered_ == i);
auto state = EntryState{ auto state = EntryState{
std::string(entries[i]), selected() == i, is_selected, is_focused, i, entries[i], selected() == i, is_selected, is_focused, i,
}; };
auto element = auto element =
(transform ? transform : RadioboxOption::Simple().transform)(state); (transform ? transform : RadioboxOption::Simple().transform)(state);
@@ -46,7 +46,7 @@ class RadioboxBase : public ComponentBase, public RadioboxOption {
} }
elements.push_back(element | reflect(boxes_[i])); elements.push_back(element | reflect(boxes_[i]));
} }
return vbox(std::move(elements)) | reflect(box_); return vbox(std::move(elements), hovered_) | reflect(box_);
} }
// NOLINTNEXTLINE(readability-function-cognitive-complexity) // NOLINTNEXTLINE(readability-function-cognitive-complexity)

View File

@@ -1,11 +1,11 @@
/// @module ftxui.component:Receiver /// @module ftxui.component.receiver
/// @brief Module file for the Receiver class of the Component module /// @brief Module file for the Receiver class of the Component module
module; module;
#include <ftxui/component/receiver.hpp> #include <ftxui/component/receiver.hpp>
export module ftxui.component:Receiver; export module ftxui.component.receiver;
/** /**
* @namespace ftxui * @namespace ftxui

View File

@@ -1,7 +1,6 @@
// Copyright 2021 Arthur Sonzogni. All rights reserved. // Copyright 2021 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in // Use of this source code is governed by the MIT license that can be found in
// the LICENSE file. // the LICENSE file.
#include <algorithm> // for max
#include <ftxui/component/component_options.hpp> // for ResizableSplitOption #include <ftxui/component/component_options.hpp> // for ResizableSplitOption
#include <ftxui/dom/direction.hpp> // for Direction, Direction::Down, Direction::Left, Direction::Right, Direction::Up #include <ftxui/dom/direction.hpp> // for Direction, Direction::Down, Direction::Left, Direction::Right, Direction::Up
#include <ftxui/util/ref.hpp> // for Ref #include <ftxui/util/ref.hpp> // for Ref
@@ -19,22 +18,34 @@
namespace ftxui { namespace ftxui {
namespace { namespace {
class ResizableSplitBase : public ComponentBase, public ResizableSplitOption { class ResizableSplitBase : public ComponentBase {
public: public:
explicit ResizableSplitBase(ResizableSplitOption options) explicit ResizableSplitBase(ResizableSplitOption options)
: ResizableSplitOption(std::move(options)) { : options_(std::move(options)) {
switch (direction()) { switch (options_->direction()) {
case Direction::Left: case Direction::Left:
Add(Container::Horizontal({main, back})); Add(Container::Horizontal({
options_->main,
options_->back,
}));
break; break;
case Direction::Right: case Direction::Right:
Add(Container::Horizontal({back, main})); Add(Container::Horizontal({
options_->back,
options_->main,
}));
break; break;
case Direction::Up: case Direction::Up:
Add(Container::Vertical({main, back})); Add(Container::Vertical({
options_->main,
options_->back,
}));
break; break;
case Direction::Down: case Direction::Down:
Add(Container::Vertical({back, main})); Add(Container::Vertical({
options_->back,
options_->main,
}));
break; break;
} }
} }
@@ -64,27 +75,27 @@ class ResizableSplitBase : public ComponentBase, public ResizableSplitOption {
return ComponentBase::OnEvent(event); return ComponentBase::OnEvent(event);
} }
switch (direction()) { switch (options_->direction()) {
case Direction::Left: case Direction::Left:
main_size() = std::max(0, event.mouse().x - box_.x_min); options_->main_size() = std::max(0, event.mouse().x - box_.x_min);
break; return true;
case Direction::Right: case Direction::Right:
main_size() = std::max(0, box_.x_max - event.mouse().x); options_->main_size() = std::max(0, box_.x_max - event.mouse().x);
break; return true;
case Direction::Up: case Direction::Up:
main_size() = std::max(0, event.mouse().y - box_.y_min); options_->main_size() = std::max(0, event.mouse().y - box_.y_min);
break; return true;
case Direction::Down: case Direction::Down:
main_size() = std::max(0, box_.y_max - event.mouse().y); options_->main_size() = std::max(0, box_.y_max - event.mouse().y);
break; return true;
} }
main_size() = std::clamp(main_size(), min(), max()); // NOTREACHED()
return true; return false;
} }
Element OnRender() final { Element OnRender() final {
switch (direction()) { switch (options_->direction()) {
case Direction::Left: case Direction::Left:
return RenderLeft(); return RenderLeft();
case Direction::Right: case Direction::Right:
@@ -100,41 +111,46 @@ class ResizableSplitBase : public ComponentBase, public ResizableSplitOption {
Element RenderLeft() { Element RenderLeft() {
return hbox({ return hbox({
main->Render() | size(WIDTH, EQUAL, main_size()), options_->main->Render() |
separator_func() | reflect(separator_box_), size(WIDTH, EQUAL, options_->main_size()),
back->Render() | xflex, options_->separator_func() | reflect(separator_box_),
options_->back->Render() | xflex,
}) | }) |
reflect(box_); reflect(box_);
} }
Element RenderRight() { Element RenderRight() {
return hbox({ return hbox({
back->Render() | xflex, options_->back->Render() | xflex,
separator_func() | reflect(separator_box_), options_->separator_func() | reflect(separator_box_),
main->Render() | size(WIDTH, EQUAL, main_size()), options_->main->Render() |
size(WIDTH, EQUAL, options_->main_size()),
}) | }) |
reflect(box_); reflect(box_);
} }
Element RenderTop() { Element RenderTop() {
return vbox({ return vbox({
main->Render() | size(HEIGHT, EQUAL, main_size()), options_->main->Render() |
separator_func() | reflect(separator_box_), size(HEIGHT, EQUAL, options_->main_size()),
back->Render() | yflex, options_->separator_func() | reflect(separator_box_),
options_->back->Render() | yflex,
}) | }) |
reflect(box_); reflect(box_);
} }
Element RenderBottom() { Element RenderBottom() {
return vbox({ return vbox({
back->Render() | yflex, options_->back->Render() | yflex,
separator_func() | reflect(separator_box_), options_->separator_func() | reflect(separator_box_),
main->Render() | size(HEIGHT, EQUAL, main_size()), options_->main->Render() |
size(HEIGHT, EQUAL, options_->main_size()),
}) | }) |
reflect(box_); reflect(box_);
} }
private: private:
Ref<ResizableSplitOption> options_;
CapturedMouse captured_mouse_; CapturedMouse captured_mouse_;
Box separator_box_; Box separator_box_;
Box box_; Box box_;

View File

@@ -233,105 +233,5 @@ TEST(ResizableSplit, NavigationVertical) {
EXPECT_FALSE(component_bottom->Active()); EXPECT_FALSE(component_bottom->Active());
} }
TEST(ResizableSplit, MinMaxSizeLeft) {
int position = 5;
auto component = ResizableSplit({
.main = BasicComponent(),
.back = BasicComponent(),
.direction = Direction::Left,
.main_size = &position,
.separator_func = [] { return separatorDouble(); },
.min = 3,
.max = 8,
});
auto screen = Screen(20, 20);
Render(screen, component->Render());
EXPECT_EQ(position, 5);
EXPECT_TRUE(component->OnEvent(MousePressed(5, 1)));
EXPECT_EQ(position, 5);
// Try to resize below min
EXPECT_TRUE(component->OnEvent(MousePressed(2, 1)));
EXPECT_EQ(position, 3); // Clamped to min
// Try to resize above max
EXPECT_TRUE(component->OnEvent(MousePressed(10, 1)));
EXPECT_EQ(position, 8); // Clamped to max
EXPECT_TRUE(component->OnEvent(MouseReleased(10, 1)));
EXPECT_EQ(position, 8);
}
TEST(ResizableSplit, MinMaxSizeRight) {
int position = 5;
auto component = ResizableSplit({
.main = BasicComponent(),
.back = BasicComponent(),
.direction = Direction::Right,
.main_size = &position,
.separator_func = [] { return separatorDouble(); },
.min = 3,
.max = 8,
});
auto screen = Screen(20, 20);
Render(screen, component->Render());
EXPECT_EQ(position, 5);
EXPECT_TRUE(component->OnEvent(MousePressed(14, 1)));
EXPECT_EQ(position, 5);
// Try to resize below min
EXPECT_TRUE(component->OnEvent(MousePressed(18, 1)));
EXPECT_EQ(position, 3); // Clamped to min
// Try to resize above max
EXPECT_TRUE(component->OnEvent(MousePressed(10, 1)));
EXPECT_EQ(position, 8); // Clamped to max
EXPECT_TRUE(component->OnEvent(MouseReleased(10, 1)));
EXPECT_EQ(position, 8);
}
TEST(ResizableSplit, MinMaxSizeTop) {
int position = 5;
auto component = ResizableSplit({
.main = BasicComponent(),
.back = BasicComponent(),
.direction = Direction::Up,
.main_size = &position,
.separator_func = [] { return separatorDouble(); },
.min = 2,
.max = 10,
});
auto screen = Screen(20, 20);
Render(screen, component->Render());
EXPECT_EQ(position, 5);
EXPECT_TRUE(component->OnEvent(MousePressed(1, 5)));
EXPECT_EQ(position, 5);
// Try to resize below min
EXPECT_TRUE(component->OnEvent(MousePressed(1, 1)));
EXPECT_EQ(position, 2); // Clamped to min
// Try to resize above max
EXPECT_TRUE(component->OnEvent(MousePressed(1, 15)));
EXPECT_EQ(position, 10); // Clamped to max
}
TEST(ResizableSplit, MinMaxSizeBottom) {
int position = 5;
auto component = ResizableSplit({
.main = BasicComponent(),
.back = BasicComponent(),
.direction = Direction::Down,
.main_size = &position,
.separator_func = [] { return separatorDouble(); },
.min = 3,
.max = 12,
});
auto screen = Screen(20, 20);
Render(screen, component->Render());
EXPECT_EQ(position, 5);
EXPECT_TRUE(component->OnEvent(MousePressed(1, 14)));
EXPECT_EQ(position, 5);
// Try to resize below min
EXPECT_TRUE(component->OnEvent(MousePressed(1, 18)));
EXPECT_EQ(position, 3); // Clamped to min
// Try to resize above max
EXPECT_TRUE(component->OnEvent(MousePressed(1, 5)));
EXPECT_EQ(position, 12); // Clamped to max
}
} // namespace ftxui } // namespace ftxui
// NOLINTEND // NOLINTEND

View File

@@ -115,7 +115,7 @@ void ftxui_on_resize(int columns, int rows) {
int CheckStdinReady(int fd) { int CheckStdinReady(int fd) {
timeval tv = {0, 0}; // NOLINT timeval tv = {0, 0}; // NOLINT
fd_set fds; fd_set fds;
FD_ZERO(&fds); // NOLINT FD_ZERO(&fds); // NOLINT
FD_SET(fd, &fds); // NOLINT FD_SET(fd, &fds); // NOLINT
select(fd + 1, &fds, nullptr, nullptr, &tv); // NOLINT select(fd + 1, &fds, nullptr, nullptr, &tv); // NOLINT
return FD_ISSET(fd, &fds); // NOLINT return FD_ISSET(fd, &fds); // NOLINT
@@ -679,8 +679,8 @@ void ScreenInteractive::Install() {
} }
void ScreenInteractive::InstallPipedInputHandling() { void ScreenInteractive::InstallPipedInputHandling() {
tty_fd_ = fileno(stdin); // NOLINT
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) #if !defined(_WIN32) && !defined(__EMSCRIPTEN__)
tty_fd_ = STDIN_FILENO;
// Handle piped input redirection if explicitly enabled by the application. // Handle piped input redirection if explicitly enabled by the application.
// This allows applications to read data from stdin while still receiving // This allows applications to read data from stdin while still receiving
// keyboard input from the terminal for interactive use. // keyboard input from the terminal for interactive use.
@@ -689,7 +689,7 @@ void ScreenInteractive::InstallPipedInputHandling() {
} }
// If stdin is a terminal, we don't need to open /dev/tty. // If stdin is a terminal, we don't need to open /dev/tty.
if (isatty(STDIN_FILENO)) { if (isatty(fileno(stdin))) {
return; return;
} }
@@ -697,7 +697,7 @@ void ScreenInteractive::InstallPipedInputHandling() {
tty_fd_ = open("/dev/tty", O_RDONLY); tty_fd_ = open("/dev/tty", O_RDONLY);
if (tty_fd_ < 0) { if (tty_fd_ < 0) {
// Failed to open /dev/tty (containers, headless systems, etc.) // Failed to open /dev/tty (containers, headless systems, etc.)
tty_fd_ = STDIN_FILENO; // Fallback to stdin. tty_fd_ = fileno(stdin); // Fallback to stdin.
return; return;
} }
@@ -1054,7 +1054,7 @@ void ScreenInteractive::Signal(int signal) {
} }
if (signal == SIGWINCH) { if (signal == SIGWINCH) {
Post(Event::Special(std::string({0}))); Post(Event::Special({0}));
return; return;
} }
#endif #endif
@@ -1098,7 +1098,6 @@ void ScreenInteractive::FetchTerminalEvents() {
// Convert the input events to FTXUI events. // Convert the input events to FTXUI events.
// For each event, we call the terminal input parser to convert it to // For each event, we call the terminal input parser to convert it to
// Event. // Event.
std::wstring wstring;
for (const auto& r : records) { for (const auto& r : records) {
switch (r.EventType) { switch (r.EventType) {
case KEY_EVENT: { case KEY_EVENT: {
@@ -1107,16 +1106,11 @@ void ScreenInteractive::FetchTerminalEvents() {
if (key_event.bKeyDown == FALSE) { if (key_event.bKeyDown == FALSE) {
continue; continue;
} }
const wchar_t wc = key_event.uChar.UnicodeChar; std::wstring wstring;
wstring += wc; wstring += key_event.uChar.UnicodeChar;
if (wc >= 0xd800 && wc <= 0xdbff) {
// Wait for the Low Surrogate to arrive in the next record.
continue;
}
for (auto it : to_string(wstring)) { for (auto it : to_string(wstring)) {
internal_->terminal_input_parser.Add(it); internal_->terminal_input_parser.Add(it);
} }
wstring.clear();
} break; } break;
case WINDOW_BUFFER_SIZE_EVENT: case WINDOW_BUFFER_SIZE_EVENT:
Post(Event::Special({0})); Post(Event::Special({0}));

View File

@@ -1,11 +1,11 @@
/// @module ftxui.component:ScreenInteractive /// @module ftxui.component.screen_interactive
/// @brief Module file for the ScreenInteractive class of the Component module /// @brief Module file for the ScreenInteractive class of the Component module
module; module;
#include <ftxui/component/screen_interactive.hpp> #include <ftxui/component/screen_interactive.hpp>
export module ftxui.component:ScreenInteractive; export module ftxui.component.screen_interactive;
/** /**
* @namespace ftxui * @namespace ftxui

View File

@@ -1,11 +1,11 @@
// Copyright 2025 Arthur Sonzogni. All rights reserved. // Copyright 2025 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in // Use of this source code is governed by the MIT license that can be found in
// the LICENSE file. // the LICENSE file.
#include <fcntl.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h>
#include <cstdio> #include <cstdio>
#include <sys/stat.h>
#include "ftxui/component/component.hpp" #include "ftxui/component/component.hpp"
#include "ftxui/component/screen_interactive.hpp" #include "ftxui/component/screen_interactive.hpp"
@@ -47,7 +47,7 @@ class PipedInputTest : public ::testing::Test {
void WriteToPipedStdin(const std::string& data) { void WriteToPipedStdin(const std::string& data) {
if (piped_stdin_setup_) { if (piped_stdin_setup_) {
write(pipe_fds_[1], data.c_str(), data.length()); write(pipe_fds_[1], data.c_str(), data.length());
close(pipe_fds_[1]); // Close write end to signal EOF close(pipe_fds_[1]); // Close write end to signal EOF
} }
} }
@@ -94,10 +94,10 @@ TEST_F(PipedInputTest, ExplicitlyDisabled) {
WriteToPipedStdin("test data\n"); WriteToPipedStdin("test data\n");
screen.Install(); screen.Install();
// Stdin should still be the pipe since feature is disabled // Stdin should still be the pipe since feature is disabled
EXPECT_FALSE(isatty(STDIN_FILENO)); EXPECT_FALSE(isatty(STDIN_FILENO));
screen.Uninstall(); screen.Uninstall();
} }
@@ -107,7 +107,7 @@ TEST_F(PipedInputTest, ExplicitlyEnabled) {
} }
auto screen = ScreenInteractive::TerminalOutput(); auto screen = ScreenInteractive::TerminalOutput();
screen.HandlePipedInput(true); // Explicitly enable screen.HandlePipedInput(true); // Explicitly enable
auto component = Renderer([] { return text("test"); }); auto component = Renderer([] { return text("test"); });
SetupPipedStdin(); SetupPipedStdin();
@@ -117,12 +117,12 @@ TEST_F(PipedInputTest, ExplicitlyEnabled) {
EXPECT_FALSE(isatty(STDIN_FILENO)); EXPECT_FALSE(isatty(STDIN_FILENO));
screen.Install(); screen.Install();
// After install with piped input handling: stdin should be redirected to tty // After install with piped input handling: stdin should be redirected to tty
EXPECT_TRUE(isatty(STDIN_FILENO)); EXPECT_TRUE(isatty(STDIN_FILENO));
screen.Uninstall(); screen.Uninstall();
// After uninstall: stdin should be restored to original state // After uninstall: stdin should be restored to original state
// Note: This will be the pipe we set up, so it should be non-tty // Note: This will be the pipe we set up, so it should be non-tty
EXPECT_FALSE(isatty(STDIN_FILENO)); EXPECT_FALSE(isatty(STDIN_FILENO));
@@ -137,12 +137,12 @@ TEST_F(PipedInputTest, NormalStdinUnchanged) {
bool original_isatty = isatty(STDIN_FILENO); bool original_isatty = isatty(STDIN_FILENO);
screen.Install(); screen.Install();
// Stdin should remain unchanged // Stdin should remain unchanged
EXPECT_EQ(original_isatty, isatty(STDIN_FILENO)); EXPECT_EQ(original_isatty, isatty(STDIN_FILENO));
screen.Uninstall(); screen.Uninstall();
// Stdin should still be unchanged // Stdin should still be unchanged
EXPECT_EQ(original_isatty, isatty(STDIN_FILENO)); EXPECT_EQ(original_isatty, isatty(STDIN_FILENO));
} }
@@ -173,12 +173,12 @@ TEST_F(PipedInputTest, MultipleInstallUninstallCycles) {
TEST_F(PipedInputTest, HandlePipedInputMethodBehavior) { TEST_F(PipedInputTest, HandlePipedInputMethodBehavior) {
auto screen = ScreenInteractive::TerminalOutput(); auto screen = ScreenInteractive::TerminalOutput();
// Test method can be called multiple times // Test method can be called multiple times
screen.HandlePipedInput(true); screen.HandlePipedInput(true);
screen.HandlePipedInput(false); screen.HandlePipedInput(false);
screen.HandlePipedInput(true); screen.HandlePipedInput(true);
// Should be enabled after last call // Should be enabled after last call
SetupPipedStdin(); SetupPipedStdin();
WriteToPipedStdin("test data\n"); WriteToPipedStdin("test data\n");
@@ -191,8 +191,7 @@ TEST_F(PipedInputTest, HandlePipedInputMethodBehavior) {
} }
// Test the graceful fallback when /dev/tty is not available // Test the graceful fallback when /dev/tty is not available
// This test simulates environments like containers where /dev/tty might not // This test simulates environments like containers where /dev/tty might not exist
// exist
TEST_F(PipedInputTest, GracefulFallbackWhenTtyUnavailable) { TEST_F(PipedInputTest, GracefulFallbackWhenTtyUnavailable) {
auto screen = ScreenInteractive::TerminalOutput(); auto screen = ScreenInteractive::TerminalOutput();
auto component = Renderer([] { return text("test"); }); auto component = Renderer([] { return text("test"); });
@@ -200,23 +199,22 @@ TEST_F(PipedInputTest, GracefulFallbackWhenTtyUnavailable) {
SetupPipedStdin(); SetupPipedStdin();
WriteToPipedStdin("test data\n"); WriteToPipedStdin("test data\n");
// This test doesn't directly mock /dev/tty unavailability since that's hard // This test doesn't directly mock /dev/tty unavailability since that's hard to do
// to do in a unit test environment, but the code path handles freopen() // in a unit test environment, but the code path handles freopen() failure gracefully
// failure gracefully
screen.Install(); screen.Install();
// The behavior depends on whether /dev/tty is available // The behavior depends on whether /dev/tty is available
// If available, stdin gets redirected; if not, it remains piped // If available, stdin gets redirected; if not, it remains piped
// Both behaviors are correct // Both behaviors are correct
screen.Uninstall(); screen.Uninstall();
// After uninstall, stdin should be restored // After uninstall, stdin should be restored
EXPECT_FALSE(isatty(STDIN_FILENO)); // Should still be our test pipe EXPECT_FALSE(isatty(STDIN_FILENO)); // Should still be our test pipe
} }
} // namespace } // namespace
} // namespace ftxui } // namespace ftxui
#endif // !defined(_WIN32) && !defined(__EMSCRIPTEN__) #endif // !defined(_WIN32) && !defined(__EMSCRIPTEN__)

View File

@@ -1,11 +1,11 @@
/// @module ftxui.component:Task /// @module ftxui.component.task
/// @brief Module file for the Task class of the Component module /// @brief Module file for the Task class of the Component module
module; module;
#include <ftxui/component/task.hpp> #include <ftxui/component/task.hpp>
export module ftxui.component:Task; export module ftxui.component.task;
/** /**
* @namespace ftxui * @namespace ftxui

View File

@@ -338,7 +338,7 @@ TEST(Event, Control) {
EXPECT_TRUE(received_events.empty()); EXPECT_TRUE(received_events.empty());
} else { } else {
EXPECT_EQ(1, received_events.size()); EXPECT_EQ(1, received_events.size());
EXPECT_EQ(received_events[0], Event::Special(std::string({test.input}))); EXPECT_EQ(received_events[0], Event::Special({test.input}));
} }
} }
} }

View File

@@ -1,15 +1,15 @@
/// @module ftxui.dom /// @module ftxui.dom
/// @brief Module file for FTXUI DOM operations. /// @brief Module file for FTXUI main operations.
export module ftxui.dom; export module ftxui.dom;
export import :Canvas; export import ftxui.dom.canvas;
export import :Deprecated; export import ftxui.dom.deprecated;
export import :Direction; export import ftxui.dom.direction;
export import :Elements; export import ftxui.dom.elements;
export import :FlexboxConfig; export import ftxui.dom.flexbox_config;
export import :LinearGradient; export import ftxui.dom.linear_gradient;
export import :Node; export import ftxui.dom.node;
export import :Requirement; export import ftxui.dom.requirement;
export import :Selection; export import ftxui.dom.selection;
export import :Table; export import ftxui.dom.table;

View File

@@ -4,18 +4,11 @@
#include "ftxui/dom/box_helper.hpp" #include "ftxui/dom/box_helper.hpp"
#include <algorithm> // for max #include <algorithm> // for max
#include <cstdint> #include <vector> // for vector
#include <vector> // for vector
namespace ftxui::box_helper { namespace ftxui::box_helper {
namespace { namespace {
int SafeRatio(int value, int numerator, int denominator) {
return static_cast<int64_t>(value) * static_cast<int64_t>(numerator) /
std::max(static_cast<int64_t>(denominator), static_cast<int64_t>(1));
}
// Called when the size allowed is greater than the requested size. This // Called when the size allowed is greater than the requested size. This
// distributes the extra spaces toward the flexible elements, in relative // distributes the extra spaces toward the flexible elements, in relative
// proportions. // proportions.
@@ -24,7 +17,7 @@ void ComputeGrow(std::vector<Element>* elements,
int flex_grow_sum) { int flex_grow_sum) {
for (Element& element : *elements) { for (Element& element : *elements) {
const int added_space = const int added_space =
SafeRatio(extra_space, element.flex_grow, flex_grow_sum); extra_space * element.flex_grow / std::max(flex_grow_sum, 1);
extra_space -= added_space; extra_space -= added_space;
flex_grow_sum -= element.flex_grow; flex_grow_sum -= element.flex_grow;
element.size = element.min_size + added_space; element.size = element.min_size + added_space;
@@ -38,8 +31,8 @@ void ComputeShrinkEasy(std::vector<Element>* elements,
int extra_space, int extra_space,
int flex_shrink_sum) { int flex_shrink_sum) {
for (Element& element : *elements) { for (Element& element : *elements) {
const int added_space = SafeRatio( const int added_space = extra_space * element.min_size *
extra_space, element.min_size * element.flex_shrink, flex_shrink_sum); element.flex_shrink / std::max(flex_shrink_sum, 1);
extra_space -= added_space; extra_space -= added_space;
flex_shrink_sum -= element.flex_shrink * element.min_size; flex_shrink_sum -= element.flex_shrink * element.min_size;
element.size = element.min_size + added_space; element.size = element.min_size + added_space;
@@ -47,7 +40,7 @@ void ComputeShrinkEasy(std::vector<Element>* elements,
} }
// Called when the size allowed is lower than the requested size, and the // Called when the size allowed is lower than the requested size, and the
// shrinkable element can not absorb the (negative) extra_space. This assigns // shrinkable element can not absorbe the (negative) extra_space. This assign
// zero to shrinkable elements and distribute the remaining (negative) // zero to shrinkable elements and distribute the remaining (negative)
// extra_space toward the other non shrinkable elements. // extra_space toward the other non shrinkable elements.
void ComputeShrinkHard(std::vector<Element>* elements, void ComputeShrinkHard(std::vector<Element>* elements,
@@ -59,8 +52,7 @@ void ComputeShrinkHard(std::vector<Element>* elements,
continue; continue;
} }
const int added_space = SafeRatio(extra_space, element.min_size, size); const int added_space = extra_space * element.min_size / std::max(1, size);
extra_space -= added_space; extra_space -= added_space;
size -= element.min_size; size -= element.min_size;

View File

@@ -782,7 +782,7 @@ void Canvas::DrawBlockEllipseFilled(int x1,
/// @param x the x coordinate of the text. /// @param x the x coordinate of the text.
/// @param y the y coordinate of the text. /// @param y the y coordinate of the text.
/// @param value the text to draw. /// @param value the text to draw.
void Canvas::DrawText(int x, int y, std::string_view value) { void Canvas::DrawText(int x, int y, const std::string& value) {
DrawText(x, y, value, nostyle); DrawText(x, y, value, nostyle);
} }
@@ -793,7 +793,7 @@ void Canvas::DrawText(int x, int y, std::string_view value) {
/// @param color the color of the text. /// @param color the color of the text.
void Canvas::DrawText(int x, void Canvas::DrawText(int x,
int y, int y,
std::string_view value, const std::string& value,
const Color& color) { const Color& color) {
DrawText(x, y, value, [color](Pixel& p) { p.foreground_color = color; }); DrawText(x, y, value, [color](Pixel& p) { p.foreground_color = color; });
} }
@@ -805,7 +805,7 @@ void Canvas::DrawText(int x,
/// @param style the style of the text. /// @param style the style of the text.
void Canvas::DrawText(int x, void Canvas::DrawText(int x,
int y, int y,
std::string_view value, const std::string& value,
const Stylizer& style) { const Stylizer& style) {
for (const auto& it : Utf8ToGlyphs(value)) { for (const auto& it : Utf8ToGlyphs(value)) {
if (!IsIn(x, y)) { if (!IsIn(x, y)) {

View File

@@ -1,11 +1,11 @@
/// @module ftxui.dom:Canvas /// @module ftxui.dom.canvas
/// @brief Module file for the Canvas struct of the DOM module /// @brief Module file for the Canvas struct of the Dom module
module; module;
#include <ftxui/dom/canvas.hpp> #include <ftxui/dom/canvas.hpp>
export module ftxui.dom:Canvas; export module ftxui.dom.canvas;
/** /**
* @namespace ftxui * @namespace ftxui

View File

@@ -1,11 +1,11 @@
/// @module ftxui.dom:Deprecated /// @module ftxui.dom.deprecated
/// @brief Module file for deprecated parts of the DOM module /// @brief Module file for deprecated parts of the Dom module
module; module;
#include <ftxui/dom/deprecated.hpp> #include <ftxui/dom/deprecated.hpp>
export module ftxui.dom:Deprecated; export module ftxui.dom.deprecated;
/** /**
* @namespace ftxui * @namespace ftxui

View File

@@ -1,11 +1,11 @@
/// @module ftxui.dom:Direction /// @module ftxui.dom.direction
/// @brief Module file for the Direction enum of the Dom module /// @brief Module file for the Direction enum of the Dom module
module; module;
#include <ftxui/dom/direction.hpp> #include <ftxui/dom/direction.hpp>
export module ftxui.dom:Direction; export module ftxui.dom.direction;
/** /**
* @namespace ftxui * @namespace ftxui

View File

@@ -1,11 +1,11 @@
/// @module ftxui.dom:Elements /// @module ftxui.dom.elements
/// @brief Module file for the Element classes and functions of the DOM module /// @brief Module file for the Element classes and functions of the Dom module
module; module;
#include <ftxui/dom/elements.hpp> #include <ftxui/dom/elements.hpp>
export module ftxui.dom:Elements; export module ftxui.dom.elements;
/** /**
* @namespace ftxui * @namespace ftxui

View File

@@ -1,11 +1,11 @@
/// @module ftxui.dom:FlexboxConfig /// @module ftxui.dom.flexbox_config
/// @brief Module file for the FlexboxConfig struct of the DOM module /// @brief Module file for the FlexboxConfig struct of the Dom module
module; module;
#include <ftxui/dom/flexbox_config.hpp> #include <ftxui/dom/flexbox_config.hpp>
export module ftxui.dom:FlexboxConfig; export module ftxui.dom.flexbox_config;
/** /**
* @namespace ftxui * @namespace ftxui

View File

@@ -2,13 +2,9 @@
// Use of this source code is governed by the MIT license that can be found in // Use of this source code is governed by the MIT license that can be found in
// the LICENSE file. // the LICENSE file.
#include <gtest/gtest.h> // for Test, TestInfo (ptr only), EXPECT_EQ, Message, TEST, TestPartResult #include <gtest/gtest.h> // for Test, TestInfo (ptr only), EXPECT_EQ, Message, TEST, TestPartResult
#include <array> // for array
#include <cstddef> // for size_t #include <cstddef> // for size_t
#include <queue> #include <string> // for allocator, basic_string, string
#include <stack> // for stack #include <vector> // for vector
#include <string> // for allocator, basic_string, string
#include <unordered_set> // for unordered_set
#include <vector> // for vector
#include "ftxui/dom/elements.hpp" // for text, operator|, Element, flex_grow, flex_shrink, hbox #include "ftxui/dom/elements.hpp" // for text, operator|, Element, flex_grow, flex_shrink, hbox
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
@@ -362,39 +358,5 @@ TEST(HBoxTest, FlexGrow_NoFlex_FlewShrink) {
} }
} }
TEST(HBoxTest, FromElementsContainer) {
Elements elements_vector{text("0"), text("1")};
std::array<Element, 2> elements_array{text("0"), text("1")};
std::deque<Element> elements_deque{text("0"), text("1")};
std::stack<Element> elements_stack;
elements_stack.push(text("1"));
elements_stack.push(text("0"));
std::queue<Element> elements_queue;
elements_queue.emplace(text("0"));
elements_queue.emplace(text("1"));
const std::vector<Element> collection_hboxes{
hbox(std::move(elements_vector)), hbox(std::move(elements_array)),
hbox(std::move(elements_stack)), hbox(std::move(elements_deque)),
hbox(std::move(elements_queue)),
};
for (const Element& collection_hbox : collection_hboxes) {
Screen screen(2, 1);
Render(screen, collection_hbox);
EXPECT_EQ("01", screen.ToString());
}
// Exception: unordered set, which has no guaranteed order.
std::unordered_set<Element> elements_set{text("0"), text("0")};
Screen screen(2, 1);
Render(screen, hbox(elements_set));
EXPECT_EQ("00", screen.ToString());
};
} // namespace ftxui } // namespace ftxui
// NOLINTEND // NOLINTEND

View File

@@ -48,8 +48,8 @@ class Hyperlink : public NodeDecorator {
/// Element document = /// Element document =
/// hyperlink("https://github.com/ArthurSonzogni/FTXUI", "link"); /// hyperlink("https://github.com/ArthurSonzogni/FTXUI", "link");
/// ``` /// ```
Element hyperlink(std::string_view link, Element child) { Element hyperlink(std::string link, Element child) {
return std::make_shared<Hyperlink>(std::move(child), std::string(link)); return std::make_shared<Hyperlink>(std::move(child), std::move(link));
} }
/// @brief Decorate using a hyperlink. /// @brief Decorate using a hyperlink.
@@ -67,10 +67,8 @@ Element hyperlink(std::string_view link, Element child) {
/// text("red") | hyperlink("https://github.com/Arthursonzogni/FTXUI"); /// text("red") | hyperlink("https://github.com/Arthursonzogni/FTXUI");
/// ``` /// ```
// NOLINTNEXTLINE // NOLINTNEXTLINE
Decorator hyperlink(std::string_view link) { Decorator hyperlink(std::string link) {
return [link = std::string(link)](Element child) { return [link](Element child) { return hyperlink(link, std::move(child)); };
return hyperlink(link, std::move(child));
};
} }
} // namespace ftxui } // namespace ftxui

View File

@@ -1,11 +1,11 @@
/// @module ftxui.dom:LinearGradient /// @module ftxui.dom.linear_gradient
/// @brief Module file for the LinearGradient struct of the DOM module /// @brief Module file for the LinearGradient struct of the Dom module
module; module;
#include <ftxui/dom/linear_gradient.hpp> #include <ftxui/dom/linear_gradient.hpp>
export module ftxui.dom:LinearGradient; export module ftxui.dom.linear_gradient;
/** /**
* @namespace ftxui * @namespace ftxui

View File

@@ -1,11 +1,11 @@
/// @module ftxui.dom:Node /// @module ftxui.dom.node
/// @brief Module file for the Node class of the DOM module /// @brief Module file for the Node class of the Dom module
module; module;
#include <ftxui/dom/node.hpp> #include <ftxui/dom/node.hpp>
export module ftxui.dom:Node; export module ftxui.dom.node;
/** /**
* @namespace ftxui * @namespace ftxui

View File

@@ -38,7 +38,7 @@ Element Split(const std::string& paragraph,
/// @brief Return an element drawing the paragraph on multiple lines. /// @brief Return an element drawing the paragraph on multiple lines.
/// @ingroup dom /// @ingroup dom
/// @see flexbox. /// @see flexbox.
Element paragraph(std::string_view the_text) { Element paragraph(const std::string& the_text) {
return paragraphAlignLeft(the_text); return paragraphAlignLeft(the_text);
} }
@@ -46,8 +46,8 @@ Element paragraph(std::string_view the_text) {
/// the left. /// the left.
/// @ingroup dom /// @ingroup dom
/// @see flexbox. /// @see flexbox.
Element paragraphAlignLeft(std::string_view the_text) { Element paragraphAlignLeft(const std::string& the_text) {
return Split(std::string(the_text), [](const std::string& line) { return Split(the_text, [](const std::string& line) {
static const auto config = FlexboxConfig().SetGap(1, 0); static const auto config = FlexboxConfig().SetGap(1, 0);
return flexbox(Split(line), config); return flexbox(Split(line), config);
}); });
@@ -57,8 +57,8 @@ Element paragraphAlignLeft(std::string_view the_text) {
/// the right. /// the right.
/// @ingroup dom /// @ingroup dom
/// @see flexbox. /// @see flexbox.
Element paragraphAlignRight(std::string_view the_text) { Element paragraphAlignRight(const std::string& the_text) {
return Split(std::string(the_text), [](const std::string& line) { return Split(the_text, [](const std::string& line) {
static const auto config = FlexboxConfig().SetGap(1, 0).Set( static const auto config = FlexboxConfig().SetGap(1, 0).Set(
FlexboxConfig::JustifyContent::FlexEnd); FlexboxConfig::JustifyContent::FlexEnd);
return flexbox(Split(line), config); return flexbox(Split(line), config);
@@ -69,8 +69,8 @@ Element paragraphAlignRight(std::string_view the_text) {
/// the center. /// the center.
/// @ingroup dom /// @ingroup dom
/// @see flexbox. /// @see flexbox.
Element paragraphAlignCenter(std::string_view the_text) { Element paragraphAlignCenter(const std::string& the_text) {
return Split(std::string(the_text), [](const std::string& line) { return Split(the_text, [](const std::string& line) {
static const auto config = static const auto config =
FlexboxConfig().SetGap(1, 0).Set(FlexboxConfig::JustifyContent::Center); FlexboxConfig().SetGap(1, 0).Set(FlexboxConfig::JustifyContent::Center);
return flexbox(Split(line), config); return flexbox(Split(line), config);
@@ -82,8 +82,8 @@ Element paragraphAlignCenter(std::string_view the_text) {
/// the center. /// the center.
/// @ingroup dom /// @ingroup dom
/// @see flexbox. /// @see flexbox.
Element paragraphAlignJustify(std::string_view the_text) { Element paragraphAlignJustify(const std::string& the_text) {
return Split(std::string(the_text), [](const std::string& line) { return Split(the_text, [](const std::string& line) {
static const auto config = FlexboxConfig().SetGap(1, 0).Set( static const auto config = FlexboxConfig().SetGap(1, 0).Set(
FlexboxConfig::JustifyContent::SpaceBetween); FlexboxConfig::JustifyContent::SpaceBetween);
Elements words = Split(line); Elements words = Split(line);

View File

@@ -1,11 +1,11 @@
/// @module ftxui.dom:Requirement /// @module ftxui.dom.requirement
/// @brief Module file for the Requirement struct of the DOM module /// @brief Module file for the Requirement struct of the Dom module
module; module;
#include <ftxui/dom/requirement.hpp> #include <ftxui/dom/requirement.hpp>
export module ftxui.dom:Requirement; export module ftxui.dom.requirement;
/** /**
* @namespace ftxui * @namespace ftxui

View File

@@ -143,7 +143,7 @@ Selection Selection::SaturateVertical(Box box) {
return {start_x, start_y, end_x, end_y, parent_}; return {start_x, start_y, end_x, end_y, parent_};
} }
void Selection::AddPart(std::string_view part, int y, int left, int right) { void Selection::AddPart(const std::string& part, int y, int left, int right) {
if (parent_ != this) { if (parent_ != this) {
parent_->AddPart(part, y, left, right); parent_->AddPart(part, y, left, right);
return; return;

View File

@@ -1,11 +1,11 @@
/// @module ftxui.dom:Selection /// @module ftxui.dom.selection
/// @brief Module file for the Selection class of the DOM module /// @brief Module file for the Selection class of the Dom module
module; module;
#include <ftxui/dom/selection.hpp> #include <ftxui/dom/selection.hpp>
export module ftxui.dom:Selection; export module ftxui.dom.selection;
/** /**
* @namespace ftxui * @namespace ftxui

View File

@@ -392,8 +392,8 @@ Element separatorEmpty() {
/// ──── /// ────
/// down /// down
/// ``` /// ```
Element separatorCharacter(std::string_view value) { Element separatorCharacter(std::string value) {
return std::make_shared<Separator>(std::string(value)); return std::make_shared<Separator>(std::move(value));
} }
/// @brief Draw a separator in between two element filled with a given pixel. /// @brief Draw a separator in between two element filled with a given pixel.

View File

@@ -81,7 +81,7 @@ class Size : public Node {
} // namespace } // namespace
/// @brief Apply a constraint on the size of an element. /// @brief Apply a constraint on the size of an element.
/// @param direction Whether the WIDTH or the HEIGHT of the element must be /// @param direction Whether the WIDTH of the HEIGHT of the element must be
/// constrained. /// constrained.
/// @param constraint The type of constaint. /// @param constraint The type of constaint.
/// @param value The value. /// @param value The value.

View File

@@ -1,11 +1,11 @@
/// @module ftxui.dom:Table /// @module ftxui.dom.table
/// @brief Module file for the Table class of the DOM module /// @brief Module file for the Table class of the Dom module
module; module;
#include <ftxui/dom/table.hpp> #include <ftxui/dom/table.hpp>
export module ftxui.dom:Table; export module ftxui.dom.table;
/** /**
* @namespace ftxui * @namespace ftxui

View File

@@ -25,12 +25,12 @@ TEST(TableTest, Empty) {
} }
TEST(TableTest, Basic) { TEST(TableTest, Basic) {
auto table = Table(std::initializer_list<std::vector<std::string>>({ auto table = Table({
{"a", "b", "c", "d"}, {"a", "b", "c", "d"},
{"e", "f", "g", "h"}, {"e", "f", "g", "h"},
{"i", "j", "k", "l"}, {"i", "j", "k", "l"},
{"m", "n", "o", "p"}, {"m", "n", "o", "p"},
})); });
Screen screen(10, 10); Screen screen(10, 10);
Render(screen, table.Render()); Render(screen, table.Render());
EXPECT_EQ( EXPECT_EQ(

View File

@@ -4,9 +4,8 @@
#include <algorithm> // for min #include <algorithm> // for min
#include <memory> // for make_shared #include <memory> // for make_shared
#include <sstream> #include <sstream>
#include <string> // for string, wstring #include <string> // for string, wstring
#include <string_view> // for string_view #include <utility> // for move
#include <utility> // for move
#include "ftxui/dom/deprecated.hpp" // for text, vtext #include "ftxui/dom/deprecated.hpp" // for text, vtext
#include "ftxui/dom/elements.hpp" // for Element, text, vtext #include "ftxui/dom/elements.hpp" // for Element, text, vtext
@@ -25,7 +24,6 @@ using ftxui::Screen;
class Text : public Node { class Text : public Node {
public: public:
explicit Text(std::string text) : text_(std::move(text)) {} explicit Text(std::string text) : text_(std::move(text)) {}
explicit Text(std::string_view sv) : Text(std::string(sv)) {}
void ComputeRequirement() override { void ComputeRequirement() override {
requirement_.min_x = string_width(text_); requirement_.min_x = string_width(text_);
@@ -98,8 +96,6 @@ class VText : public Node {
explicit VText(std::string text) explicit VText(std::string text)
: text_(std::move(text)), width_{std::min(string_width(text_), 1)} {} : text_(std::move(text)), width_{std::min(string_width(text_), 1)} {}
explicit VText(std::string_view sv) : VText(std::string(sv)) {}
void ComputeRequirement() override { void ComputeRequirement() override {
requirement_.min_x = width_; requirement_.min_x = width_;
requirement_.min_y = string_width(text_); requirement_.min_y = string_width(text_);
@@ -142,8 +138,8 @@ class VText : public Node {
/// ```bash /// ```bash
/// Hello world! /// Hello world!
/// ``` /// ```
Element text(std::string_view text) { Element text(std::string text) {
return std::make_shared<Text>(std::string(text)); return std::make_shared<Text>(std::move(text));
} }
/// @brief Display a piece of unicode text. /// @brief Display a piece of unicode text.
@@ -165,25 +161,6 @@ Element text(std::wstring text) { // NOLINT
return std::make_shared<Text>(to_string(text)); return std::make_shared<Text>(to_string(text));
} }
/// @brief Display a piece of unicode text.
/// @ingroup dom
/// @see ftxui::to_wstring
///
/// ### Example
///
/// ```cpp
/// Element document = text(L"Hello world!");
/// ```
///
/// ### Output
///
/// ```bash
/// Hello world!
/// ```
Element text(std::wstring_view sv) {
return text(std::wstring(sv));
}
/// @brief Display a piece of unicode text vertically. /// @brief Display a piece of unicode text vertically.
/// @ingroup dom /// @ingroup dom
/// @see ftxui::to_wstring /// @see ftxui::to_wstring
@@ -210,8 +187,8 @@ Element text(std::wstring_view sv) {
/// d /// d
/// ! /// !
/// ``` /// ```
Element vtext(std::string_view text) { Element vtext(std::string text) {
return std::make_shared<VText>(std::string(text)); return std::make_shared<VText>(std::move(text));
} }
/// @brief Display a piece unicode text vertically. /// @brief Display a piece unicode text vertically.
@@ -244,34 +221,4 @@ Element vtext(std::wstring text) { // NOLINT
return std::make_shared<VText>(to_string(text)); return std::make_shared<VText>(to_string(text));
} }
/// @brief Display a piece unicode text vertically.
/// @ingroup dom
/// @see ftxui::to_wstring
///
/// ### Example
///
/// ```cpp
/// Element document = vtext(L"Hello world!");
/// ```
///
/// ### Output
///
/// ```bash
/// H
/// e
/// l
/// l
/// o
///
/// w
/// o
/// r
/// l
/// d
/// !
/// ```
Element vtext(std::wstring_view text) { // NOLINT
return vtext(std::wstring(text));
}
} // namespace ftxui } // namespace ftxui

View File

@@ -2,8 +2,7 @@
// Use of this source code is governed by the MIT license that can be found in // Use of this source code is governed by the MIT license that can be found in
// the LICENSE file. // the LICENSE file.
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <string> // for allocator, string #include <string> // for allocator, string
#include <string_view> // for string_view
#include "ftxui/dom/elements.hpp" // for text, operator|, border, Element #include "ftxui/dom/elements.hpp" // for text, operator|, border, Element
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
@@ -122,13 +121,5 @@ TEST(TextTest, CombiningCharactersWithSpace) {
EXPECT_EQ(t, screen.ToString()); EXPECT_EQ(t, screen.ToString());
} }
TEST(TextTest, WithStringViews) {
const std::string_view t = "Hello, world!";
auto element = text(t);
Screen screen(13, 1);
Render(screen, element);
EXPECT_EQ(t, screen.ToString());
}
} // namespace ftxui } // namespace ftxui
// NOLINTEND // NOLINTEND

View File

@@ -3,12 +3,12 @@
export module ftxui.screen; export module ftxui.screen;
export import :Box; export import ftxui.screen.box;
export import :Color; export import ftxui.screen.color;
export import :ColorInfo; export import ftxui.screen.color_info;
export import :Deprecated; export import ftxui.screen.deprecated;
export import :Image; export import ftxui.screen.image;
export import :Pixel; export import ftxui.screen.pixel;
export import :Screen; export import ftxui.screen.screen;
export import :String; export import ftxui.screen.string;
export import :Terminal; export import ftxui.screen.terminal;

View File

@@ -1,11 +1,11 @@
/// @module ftxui.screen:Box /// @module ftxui.screen.box
/// @brief Module file for the Box struct of the Screen module /// @brief Module file for the Box struct of the Screen module
module; module;
#include <ftxui/screen/box.hpp> #include <ftxui/screen/box.hpp>
export module ftxui.screen:Box; export module ftxui.screen.box;
/** /**
* @namespace ftxui * @namespace ftxui

View File

@@ -1,11 +1,11 @@
/// @module ftxui.screen:Color /// @module ftxui.screen.color
/// @brief Module file for the Color class of the Screen module /// @brief Module file for the Color class of the Screen module
module; module;
#include <ftxui/screen/color.hpp> #include <ftxui/screen/color.hpp>
export module ftxui.screen:Color; export module ftxui.screen.color;
/** /**
* @namespace ftxui * @namespace ftxui
@@ -14,10 +14,6 @@ export module ftxui.screen:Color;
export namespace ftxui { export namespace ftxui {
using ftxui::Color; using ftxui::Color;
/**
* @namespace literals
* @brief The FTXUI ftxui::literals:: namespace
*/
inline namespace literals { inline namespace literals {
using ftxui::literals::operator""_rgb; using ftxui::literals::operator""_rgb;
} }

View File

@@ -1,11 +1,11 @@
/// @module ftxui.screen:ColorInfo /// @module ftxui.screen.color_info
/// @brief Module file for the ColorInfo struct of the Screen module /// @brief Module file for the ColorInfo struct of the Screen module
module; module;
#include <ftxui/screen/color_info.hpp> #include <ftxui/screen/color_info.hpp>
export module ftxui.screen:ColorInfo; export module ftxui.screen.color_info;
/** /**
* @namespace ftxui * @namespace ftxui

View File

@@ -1,11 +1,11 @@
/// @module ftxui.screen:Deprecated /// @module ftxui.screen.deprecated
/// @brief Module file for the deprecated parts of the Screen module /// @brief Module file for the deprecated parts of the Screen module
module; module;
#include <ftxui/screen/deprecated.hpp> #include <ftxui/screen/deprecated.hpp>
export module ftxui.screen:Deprecated; export module ftxui.screen.deprecated;
/** /**
* @namespace ftxui * @namespace ftxui

View File

@@ -1,11 +1,11 @@
/// @module ftxui.screen:Image /// @module ftxui.screen.image
/// @brief Module file for the Image class of the Screen module /// @brief Module file for the Image class of the Screen module
module; module;
#include <ftxui/screen/image.hpp> #include <ftxui/screen/image.hpp>
export module ftxui.screen:Image; export module ftxui.screen.image;
/** /**
* @namespace ftxui * @namespace ftxui

View File

@@ -1,11 +1,11 @@
/// @module ftxui.screen:Pixel /// @module ftxui.screen.pixel
/// @brief Module file for the Pixel struct of the Screen module /// @brief Module file for the Pixel struct of the Screen module
module; module;
#include <ftxui/screen/pixel.hpp> #include <ftxui/screen/pixel.hpp>
export module ftxui.screen:Pixel; export module ftxui.screen.pixel;
/** /**
* @namespace ftxui * @namespace ftxui

View File

@@ -531,7 +531,7 @@ void Screen::ApplyShader() {
} }
// clang-format on // clang-format on
std::uint8_t Screen::RegisterHyperlink(std::string_view link) { std::uint8_t Screen::RegisterHyperlink(const std::string& link) {
for (std::size_t i = 0; i < hyperlinks_.size(); ++i) { for (std::size_t i = 0; i < hyperlinks_.size(); ++i) {
if (hyperlinks_[i] == link) { if (hyperlinks_[i] == link) {
return i; return i;
@@ -540,7 +540,7 @@ std::uint8_t Screen::RegisterHyperlink(std::string_view link) {
if (hyperlinks_.size() == std::numeric_limits<std::uint8_t>::max()) { if (hyperlinks_.size() == std::numeric_limits<std::uint8_t>::max()) {
return 0; return 0;
} }
hyperlinks_.push_back(std::string(link)); hyperlinks_.push_back(link);
return hyperlinks_.size() - 1; return hyperlinks_.size() - 1;
} }

View File

@@ -1,21 +1,17 @@
/// @module ftxui.screen:Screen /// @module ftxui.screen.screen
/// @brief Module file for the Screen class of the Screen module /// @brief Module file for the Screen class of the Screen module
module; module;
#include <ftxui/screen/screen.hpp> #include <ftxui/screen/screen.hpp>
export module ftxui.screen:Screen; export module ftxui.screen.screen;
/** /**
* @namespace ftxui * @namespace ftxui
* @brief The FTXUI ftxui:: namespace * @brief The FTXUI ftxui:: namespace
*/ */
export namespace ftxui { export namespace ftxui {
/**
* @namespace Dimension
* @brief The FTXUI ftxui::Dimension:: namespace
*/
namespace Dimension { namespace Dimension {
using ftxui::Dimension::Fixed; using ftxui::Dimension::Fixed;
using ftxui::Dimension::Full; using ftxui::Dimension::Full;

View File

@@ -1171,7 +1171,7 @@ namespace ftxui {
// one codepoint. Put the codepoint into |ucs|. Start at |start| and update // one codepoint. Put the codepoint into |ucs|. Start at |start| and update
// |end| to represent the beginning of the next byte to eat for consecutive // |end| to represent the beginning of the next byte to eat for consecutive
// executions. // executions.
bool EatCodePoint(std::string_view input, bool EatCodePoint(const std::string& input,
size_t start, size_t start,
size_t* end, size_t* end,
uint32_t* ucs) { uint32_t* ucs) {
@@ -1241,7 +1241,7 @@ bool EatCodePoint(std::string_view input,
// one codepoint. Put the codepoint into |ucs|. Start at |start| and update // one codepoint. Put the codepoint into |ucs|. Start at |start| and update
// |end| to represent the beginning of the next byte to eat for consecutive // |end| to represent the beginning of the next byte to eat for consecutive
// executions. // executions.
bool EatCodePoint(std::wstring_view input, bool EatCodePoint(const std::wstring& input,
size_t start, size_t start,
size_t* end, size_t* end,
uint32_t* ucs) { uint32_t* ucs) {
@@ -1328,7 +1328,7 @@ int wstring_width(const std::wstring& text) {
return width; return width;
} }
int string_width(std::string_view input) { int string_width(const std::string& input) {
int width = 0; int width = 0;
size_t start = 0; size_t start = 0;
while (start < input.size()) { while (start < input.size()) {
@@ -1355,7 +1355,7 @@ int string_width(std::string_view input) {
return width; return width;
} }
std::vector<std::string> Utf8ToGlyphs(std::string_view input) { std::vector<std::string> Utf8ToGlyphs(const std::string& input) {
std::vector<std::string> out; std::vector<std::string> out;
out.reserve(input.size()); out.reserve(input.size());
size_t start = 0; size_t start = 0;
@@ -1367,7 +1367,7 @@ std::vector<std::string> Utf8ToGlyphs(std::string_view input) {
continue; continue;
} }
const auto append = input.substr(start, end - start); const std::string append = input.substr(start, end - start);
start = end; start = end;
// Ignore control characters. // Ignore control characters.
@@ -1386,18 +1386,18 @@ std::vector<std::string> Utf8ToGlyphs(std::string_view input) {
// Fullwidth characters take two cells. The second is made of the empty // Fullwidth characters take two cells. The second is made of the empty
// string to reserve the space the first is taking. // string to reserve the space the first is taking.
if (IsFullWidth(codepoint)) { if (IsFullWidth(codepoint)) {
out.push_back(std::string(append)); out.push_back(append);
out.emplace_back(""); out.emplace_back("");
continue; continue;
} }
// Normal characters: // Normal characters:
out.push_back(std::string(append)); out.push_back(append);
} }
return out; return out;
} }
size_t GlyphPrevious(std::string_view input, size_t start) { size_t GlyphPrevious(const std::string& input, size_t start) {
while (true) { while (true) {
if (start == 0) { if (start == 0) {
return 0; return 0;
@@ -1422,7 +1422,7 @@ size_t GlyphPrevious(std::string_view input, size_t start) {
} }
} }
size_t GlyphNext(std::string_view input, size_t start) { size_t GlyphNext(const std::string& input, size_t start) {
bool glyph_found = false; bool glyph_found = false;
while (start < input.size()) { while (start < input.size()) {
size_t end = 0; size_t end = 0;
@@ -1448,7 +1448,7 @@ size_t GlyphNext(std::string_view input, size_t start) {
return static_cast<int>(input.size()); return static_cast<int>(input.size());
} }
size_t GlyphIterate(std::string_view input, int glyph_offset, size_t start) { size_t GlyphIterate(const std::string& input, int glyph_offset, size_t start) {
if (glyph_offset >= 0) { if (glyph_offset >= 0) {
for (int i = 0; i < glyph_offset; ++i) { for (int i = 0; i < glyph_offset; ++i) {
start = GlyphNext(input, start); start = GlyphNext(input, start);
@@ -1462,7 +1462,7 @@ size_t GlyphIterate(std::string_view input, int glyph_offset, size_t start) {
} }
} }
std::vector<int> CellToGlyphIndex(std::string_view input) { std::vector<int> CellToGlyphIndex(const std::string& input) {
int x = -1; int x = -1;
std::vector<int> out; std::vector<int> out;
out.reserve(input.size()); out.reserve(input.size());
@@ -1503,7 +1503,7 @@ std::vector<int> CellToGlyphIndex(std::string_view input) {
return out; return out;
} }
int GlyphCount(std::string_view input) { int GlyphCount(const std::string& input) {
int size = 0; int size = 0;
size_t start = 0; size_t start = 0;
size_t end = 0; size_t end = 0;
@@ -1531,7 +1531,8 @@ int GlyphCount(std::string_view input) {
return size; return size;
} }
std::vector<WordBreakProperty> Utf8ToWordBreakProperty(std::string_view input) { std::vector<WordBreakProperty> Utf8ToWordBreakProperty(
const std::string& input) {
std::vector<WordBreakProperty> out; std::vector<WordBreakProperty> out;
out.reserve(input.size()); out.reserve(input.size());
size_t start = 0; size_t start = 0;
@@ -1562,7 +1563,7 @@ std::vector<WordBreakProperty> Utf8ToWordBreakProperty(std::string_view input) {
} }
/// Convert a std::wstring into a UTF8 std::string. /// Convert a std::wstring into a UTF8 std::string.
std::string to_string(std::wstring_view s) { std::string to_string(const std::wstring& s) {
std::string out; std::string out;
size_t i = 0; size_t i = 0;
@@ -1634,7 +1635,7 @@ std::string to_string(std::wstring_view s) {
} }
/// Convert a UTF8 std::string into a std::wstring. /// Convert a UTF8 std::string into a std::wstring.
std::wstring to_wstring(std::string_view s) { std::wstring to_wstring(const std::string& s) {
std::wstring out; std::wstring out;
size_t i = 0; size_t i = 0;

View File

@@ -1,11 +1,11 @@
/// @module ftxui.screen:String /// @module ftxui.screen.string
/// @brief Module file for string functions of the Screen module /// @brief Module file for string functions of the Screen module
module; module;
#include <ftxui/screen/string.hpp> #include <ftxui/screen/string.hpp>
export module ftxui.screen:String; export module ftxui.screen.string;
/** /**
* @namespace ftxui * @namespace ftxui

View File

@@ -10,11 +10,11 @@
namespace ftxui { namespace ftxui {
bool EatCodePoint(std::string_view input, bool EatCodePoint(const std::string& input,
size_t start, size_t start,
size_t* end, size_t* end,
uint32_t* ucs); uint32_t* ucs);
bool EatCodePoint(std::wstring_view input, bool EatCodePoint(const std::wstring& input,
size_t start, size_t start,
size_t* end, size_t* end,
uint32_t* ucs); uint32_t* ucs);
@@ -23,15 +23,17 @@ bool IsCombining(uint32_t ucs);
bool IsFullWidth(uint32_t ucs); bool IsFullWidth(uint32_t ucs);
bool IsControl(uint32_t ucs); bool IsControl(uint32_t ucs);
size_t GlyphPrevious(std::string_view input, size_t start); size_t GlyphPrevious(const std::string& input, size_t start);
size_t GlyphNext(std::string_view input, size_t start); size_t GlyphNext(const std::string& input, size_t start);
// Return the index in the |input| string of the glyph at |glyph_offset|, // Return the index in the |input| string of the glyph at |glyph_offset|,
// starting at |start| // starting at |start|
size_t GlyphIterate(std::string_view input, int glyph_offset, size_t start = 0); size_t GlyphIterate(const std::string& input,
int glyph_offset,
size_t start = 0);
// Returns the number of glyphs in |input|. // Returns the number of glyphs in |input|.
int GlyphCount(std::string_view input); int GlyphCount(const std::string& input);
// Properties from: // Properties from:
// https://www.unicode.org/Public/UCD/latest/ucd/auxiliary/WordBreakProperty.txt // https://www.unicode.org/Public/UCD/latest/ucd/auxiliary/WordBreakProperty.txt
@@ -56,9 +58,10 @@ enum class WordBreakProperty : int8_t {
ZWJ, ZWJ,
}; };
WordBreakProperty CodepointToWordBreakProperty(uint32_t codepoint); WordBreakProperty CodepointToWordBreakProperty(uint32_t codepoint);
std::vector<WordBreakProperty> Utf8ToWordBreakProperty(std::string_view input); std::vector<WordBreakProperty> Utf8ToWordBreakProperty(
const std::string& input);
bool IsWordBreakingCharacter(std::string_view input, size_t glyph_index); bool IsWordBreakingCharacter(const std::string& input, size_t glyph_index);
} // namespace ftxui } // namespace ftxui
#endif /* end of include guard: FTXUI_SCREEN_STRING_INTERNAL_HPP */ #endif /* end of include guard: FTXUI_SCREEN_STRING_INTERNAL_HPP */

View File

@@ -154,14 +154,14 @@ TEST(StringTest, to_string) {
} }
TEST(StringTest, to_wstring) { TEST(StringTest, to_wstring) {
EXPECT_EQ(to_wstring("hello"), L"hello"); EXPECT_EQ(to_wstring(std::string("hello")), L"hello");
EXPECT_EQ(to_wstring(""), L""); EXPECT_EQ(to_wstring(std::string("")), L"");
EXPECT_EQ(to_wstring("ÿ"), L"ÿ"); EXPECT_EQ(to_wstring(std::string("ÿ")), L"ÿ");
EXPECT_EQ(to_wstring("߿"), L"߿"); EXPECT_EQ(to_wstring(std::string("߿")), L"߿");
EXPECT_EQ(to_wstring("ɰɱ"), L"ɰɱ"); EXPECT_EQ(to_wstring(std::string("ɰɱ")), L"ɰɱ");
EXPECT_EQ(to_wstring("«»"), L"«»"); EXPECT_EQ(to_wstring(std::string("«»")), L"«»");
EXPECT_EQ(to_wstring("嵰嵲嵫"), L"嵰嵲嵫"); EXPECT_EQ(to_wstring(std::string("嵰嵲嵫")), L"嵰嵲嵫");
EXPECT_EQ(to_wstring("🎅🎄"), L"🎅🎄"); EXPECT_EQ(to_wstring(std::string("🎅🎄")), L"🎅🎄");
} }
} // namespace ftxui } // namespace ftxui

View File

@@ -1,11 +1,11 @@
/// @module ftxui.screen:Terminal /// @module ftxui.screen.terminal
/// @brief Module file for the Terminal namespace of the Screen module /// @brief Module file for the Terminal namespace of the Screen module
module; module;
#include <ftxui/screen/terminal.hpp> #include <ftxui/screen/terminal.hpp>
export module ftxui.screen:Terminal; export module ftxui.screen.terminal;
/** /**
* @namespace ftxui * @namespace ftxui
@@ -14,10 +14,6 @@ export module ftxui.screen:Terminal;
export namespace ftxui { export namespace ftxui {
using ftxui::Dimensions; using ftxui::Dimensions;
/**
* @namespace Terminal
* @brief The FTXUI ftxui::Terminal:: namespace
*/
namespace Terminal { namespace Terminal {
using ftxui::Terminal::Size; using ftxui::Terminal::Size;
using ftxui::Terminal::SetFallbackSize; using ftxui::Terminal::SetFallbackSize;

View File

@@ -3,5 +3,5 @@
export module ftxui.util; export module ftxui.util;
export import :AutoReset; export import ftxui.util.autoreset;
export import :Ref; export import ftxui.util.ref;

View File

@@ -1,11 +1,11 @@
/// @module ftxui.util:AutoReset /// @module ftxui.util.autoreset
/// @brief Module file for the AutoReset class of the Util module /// @brief Module file for the AutoReset class of the Util module
module; module;
#include <ftxui/util/autoreset.hpp> #include <ftxui/util/autoreset.hpp>
export module ftxui.util:AutoReset; export module ftxui.util.autoreset;
/** /**
* @namespace ftxui * @namespace ftxui

View File

@@ -1,11 +1,11 @@
/// @module ftxui.util:Ref /// @module ftxui.util.ref
/// @brief Module file for the Ref classes of the Util module /// @brief Module file for the Ref classes of the Util module
module; module;
#include <ftxui/util/ref.hpp> #include <ftxui/util/ref.hpp>
export module ftxui.util:Ref; export module ftxui.util.ref;
/** /**
* @namespace ftxui * @namespace ftxui

Some files were not shown because too many files have changed in this diff Show More