Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
WarningsAsErrors: "*"
FormatStyle: none
HeaderFilterRegex: .*
ExcludeHeaderFilterRegex: ".*(ccpp)/.*|.*limine.h.*"
ExcludeHeaderFilterRegex: ".*glibc.*"
ExtraArgs: [-std=gnu++26, -fconstexpr-steps=10000000, -Wno-unknown-warning-option, -fsized-deallocation]
Checks: >
-*,
Expand Down
36 changes: 33 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,46 @@ endif()
# ---- Declare executable ----

if(NOT ttx_LIB_ONLY)

# ---- Ttx app object lib ----

file(
GLOB_RECURSE sources CONFIGURE_DEPENDS
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
"src/*.cpp"
)
add_executable(ttx_app ${sources})
list(FILTER sources EXCLUDE REGEX src/ttx.cpp)
file(
GLOB_RECURSE headers CONFIGURE_DEPENDS
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
"src/*.h"
)

set_property(TARGET ttx_app PROPERTY OUTPUT_NAME ttx)
add_library(ttx_ttx_app_lib OBJECT ${sources})
add_library(ttx::ttx_app_lib ALIAS ttx_ttx_app_lib)
set_property(TARGET ttx_ttx_app_lib PROPERTY EXPORT_NAME ttx_app_lib)

target_link_libraries(ttx_app PRIVATE ttx::ttx)
target_include_directories(
ttx_ttx_app_lib ${warning_guard} INTERFACE "\$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src>"
)
target_sources(
ttx_ttx_app_lib
INTERFACE FILE_SET
HEADERS
TYPE
HEADERS
BASE_DIRS
src
FILES
${headers}
)
target_link_libraries(ttx_ttx_app_lib PUBLIC ttx::ttx)

# ---- Ttx app ----

add_executable(ttx_app src/ttx.cpp)
set_property(TARGET ttx_app PROPERTY OUTPUT_NAME ttx)
target_link_libraries(ttx_app PRIVATE ttx::ttx_app_lib)
endif()

# ---- Install rules ----
Expand Down
24 changes: 12 additions & 12 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 23 additions & 4 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ alias c := configure
alias b := build
alias t := test
alias ut := unit_test
alias uta := unit_test_app
alias tt := terminal_test
alias gtt := generate_terminal_test
alias cb := configure_build
alias bt := build_test
alias but := build_unit_test
alias buta := build_unit_test_app
alias cbt := configure_build_test
alias r := run
alias br := build_run
Expand All @@ -32,7 +34,7 @@ build *args="": ensure_configured
test *args="": ensure_configured
ctest --preset {{ preset }} {{ args }}

# Run unit tests
# Run unit tests (library)
unit_test *args="": ensure_configured
#!/usr/bin/env bash
set -euo pipefail
Expand All @@ -42,7 +44,19 @@ unit_test *args="": ensure_configured
sed s/\${sourceDir}/./g
)

$build_directory/lib/test/ttx_test {{ args }}
$build_directory/lib/test/libttx_test {{ args }}

# Run unit tests (application)
unit_test_app *args="": ensure_configured
#!/usr/bin/env bash
set -euo pipefail

build_directory=$(
jq -rc '.configurePresets.[] | select(.name == "{{ preset }}") | .binaryDir' CMakePresets.json CMakeUserPresets.json |
sed s/\${sourceDir}/./g
)

$build_directory/test/ttx_test {{ args }}

# Run terminal tests
terminal_test *args="": ensure_configured
Expand Down Expand Up @@ -87,11 +101,16 @@ build_test *args="":
@just preset={{ preset }} build
@just preset={{ preset }} test {{ args }}

# Build and run unit tests
# Build and run unit tests (library)
build_unit_test *args="":
@just preset={{ preset }} build -t ttx_test
@just preset={{ preset }} build -t libttx_test
@just preset={{ preset }} unit_test {{ args }}

# Build and run unit tests (application)
build_unit_test_app *args="":
@just preset={{ preset }} build -t ttx_test
@just preset={{ preset }} unit_test_app {{ args }}

# Configure and build and test
configure_build_test *args="":
@just preset={{ preset }} configure
Expand Down
23 changes: 19 additions & 4 deletions lib/include/ttx/layout.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
#include "di/reflect/prelude.h"
#include "di/vocab/pointer/box.h"
#include "direction.h"
#include "ttx/layout_json.h"
#include "ttx/pane.h"
#include "ttx/size.h"

namespace ttx {
struct LayoutNode;
struct LayoutPane;
class LayoutGroup;

// Represents the layout result for a single pane. The row and col
Expand All @@ -18,15 +20,16 @@ struct LayoutEntry {
u32 col { 0 };
Size size;
LayoutNode* parent { nullptr };
LayoutPane const* ref { nullptr };
Pane* pane { nullptr };

auto operator==(LayoutEntry const&) const -> bool = default;

constexpr friend auto tag_invoke(di::Tag<di::reflect>, di::InPlaceType<LayoutEntry>) {
return di::make_fields<"LayoutEntry">(di::field<"row", &LayoutEntry::row>, di::field<"col", &LayoutEntry::col>,
di::field<"size", &LayoutEntry::size>,
di::field<"parent", &LayoutEntry::parent>,
di::field<"pane", &LayoutEntry::pane>);
return di::make_fields<"LayoutEntry">(
di::field<"row", &LayoutEntry::row>, di::field<"col", &LayoutEntry::col>,
di::field<"size", &LayoutEntry::size>, di::field<"parent", &LayoutEntry::parent>,
di::field<"ref", &LayoutEntry::ref>, di::field<"pane", &LayoutEntry::pane>);
}
};

Expand All @@ -42,6 +45,7 @@ struct LayoutNode {
Direction direction { Direction::None };

auto find_pane(Pane* pane) -> di::Optional<LayoutEntry&>;
auto find_pane_by_id(u64 id) -> di::Optional<LayoutEntry&>;
auto hit_test(u32 row, u32 col) -> di::Optional<LayoutEntry&>;

auto hit_test_horizontal_line(u32 row, u32 col_start, u32 col_end) -> di::TreeSet<LayoutEntry*>;
Expand All @@ -63,6 +67,7 @@ constexpr inline auto max_layout_precision = i64(100'000);
// necessary for layout.
struct LayoutPane {
di::Box<Pane> pane {};
u64 pane_id { 0 };
i64 relative_size { max_layout_precision };
};

Expand All @@ -88,6 +93,11 @@ class LayoutGroup {
constexpr auto empty() const -> bool { return m_children.empty(); }
constexpr auto single() const -> bool { return m_children.size() == 1; }
constexpr auto relative_size() -> i64& { return m_relative_size; }
constexpr auto relative_size() const -> i64 { return m_relative_size; }

static auto from_json_v1(json::v1::PaneLayoutNode const& json, Size const& size,
di::FunctionRef<di::Result<di::Box<Pane>>(u64 id, Size const&)> make_pane)
-> di::Result<LayoutGroup>;

// NOTE: this method returns the correct size for the new pane, and a lvalue reference where
// the caller should store its newly created Pane. We need this akward API so that we can
Expand All @@ -106,8 +116,13 @@ class LayoutGroup {
// new size.
auto layout(Size const& size, u32 row_offset, u32 col_offset) -> di::Box<LayoutNode>;

auto as_json_v1() const -> json::v1::PaneLayoutNode;

private:
friend struct FindPaneInLayoutGroup;
friend struct ToJsonV1;
friend struct FromJsonV1;
friend struct MakePane;

void redistribute_space(di::Variant<di::Box<LayoutGroup>, di::Box<LayoutPane>>* new_child,
i64 original_size_available, i64 new_size_available);
Expand Down
107 changes: 107 additions & 0 deletions lib/include/ttx/layout_json.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#pragma once

#include "di/container/string/prelude.h"
#include "di/reflect/prelude.h"
#include "di/serialization/json_deserializer.h"
#include "di/serialization/json_serializer.h"
#include "ttx/direction.h"

namespace ttx::json::v1 {
struct Pane {
i64 relative_size { 0 };
u64 id { 0 };

auto operator==(Pane const&) const -> bool = default;

constexpr friend auto tag_invoke(di::Tag<di::reflect>, di::InPlaceType<Pane>) {
return di::make_fields<"json::v1::Pane">(di::field<"relative_size", &Pane::relative_size>,
di::field<"id", &Pane::id>);
}
};

struct PaneLayoutNode;

struct PaneLayoutVariant : di::Variant<di::Box<PaneLayoutNode>, Pane> {
using Base = di::Variant<di::Box<PaneLayoutNode>, Pane>;

using Base::Base;
using Base::operator=;

auto operator==(PaneLayoutVariant const& other) const -> bool;
};

struct PaneLayoutNode {
di::Vector<PaneLayoutVariant> children;
i64 relative_size { 0 };
Direction direction { Direction::None };

auto operator==(PaneLayoutNode const& other) const -> bool = default;

constexpr friend auto tag_invoke(di::Tag<di::reflect>, di::InPlaceType<PaneLayoutNode>) {
return di::make_fields<"json::v1::PaneLayoutNode">(di::field<"children", &PaneLayoutNode::children>,
di::field<"relative_size", &PaneLayoutNode::relative_size>,
di::field<"direction", &PaneLayoutNode::direction>);
}
};

inline auto PaneLayoutVariant::operator==(PaneLayoutVariant const& other) const -> bool {
if (index() != other.index()) {
return false;
}
if (index() == 0) {
return *di::get<di::Box<PaneLayoutNode>>(*this) == *di::get<di::Box<PaneLayoutNode>>(other);
}
return di::get<Pane>(*this) == di::get<Pane>(other);
}

struct Tab {
PaneLayoutNode pane_layout;
di::Vector<u64> pane_ids_by_recency;
di::Optional<u64> active_pane_id;
di::Optional<u64> full_screen_pane_id;
di::String name;
u64 id { 0 };

auto operator==(Tab const&) const -> bool = default;

constexpr friend auto tag_invoke(di::Tag<di::reflect>, di::InPlaceType<Tab>) {
return di::make_fields<"json::v1::Tab">(di::field<"pane_layout", &Tab::pane_layout>,
di::field<"pane_ids_by_recency", &Tab::pane_ids_by_recency>,
di::field<"active_pane_id", &Tab::active_pane_id>,
di::field<"full_screen_pane_id", &Tab::full_screen_pane_id>,
di::field<"name", &Tab::name>, di::field<"id", &Tab::id>);
}
};

struct Session {
di::Vector<Tab> tabs;
di::Optional<u64> active_tab_id;
di::String name;
u64 id { 0 };

auto operator==(Session const&) const -> bool = default;

constexpr friend auto tag_invoke(di::Tag<di::reflect>, di::InPlaceType<Session>) {
return di::make_fields<"json::v1::Session">(di::field<"tabs", &Session::tabs>,
di::field<"active_tab_id", &Session::active_tab_id>,
di::field<"name", &Session::name>, di::field<"id", &Session::id>);
}
};

struct LayoutState {
di::Vector<Session> sessions;
di::Optional<u64> active_session_id;

auto operator==(LayoutState const&) const -> bool = default;

constexpr friend auto tag_invoke(di::Tag<di::reflect>, di::InPlaceType<LayoutState>) {
return di::make_fields<"json::v1::LayoutState">(
di::field<"sessions", &LayoutState::sessions>,
di::field<"active_session_id", &LayoutState::active_session_id>);
}
};
}

namespace ttx::json {
using Layout = di::Variant<json::v1::LayoutState>;
}
Loading
Loading