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
18 changes: 3 additions & 15 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ name: build-and-test
on: [push]

env:
CMAKE_VERSION: 3.29.2
NINJA_VERSION: 1.9.0
CMAKE_VERSION: 4.0.3
NINJA_VERSION: 1.13.1

jobs:
build:
Expand All @@ -15,7 +15,7 @@ jobs:
matrix:
build_type: [ 'Debug', 'Release' ]
os: [ 'ubuntu-24.04' ]
compiler: [ 'gcc-14', 'clang-19', 'clang-20' ]
compiler: [ 'gcc-14', 'clang-20' ]

steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -62,18 +62,6 @@ jobs:
echo "CC=gcc-14" >> $GITHUB_ENV
echo "CXX=g++-14" >> $GITHUB_ENV

- name: install clang-19
id: install_clang_19
if: matrix.compiler == 'clang-19'
shell: bash
working-directory: ${{ env.HOME }}
run: |
curl -O -L https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 19
echo "CC=clang-19" >> $GITHUB_ENV
echo "CXX=clang++-19" >> $GITHUB_ENV

- name: install clang-20
id: install_clang_20
if: matrix.compiler == 'clang-20'
Expand Down
8 changes: 2 additions & 6 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
cmake_minimum_required(VERSION 3.24)
cmake_minimum_required(VERSION 3.31.6 FATAL_ERROR)

set(VersionString "0.0.5")

project(walng CXX)
project(walng LANGUAGES CXX VERSION 0.0.8)

include(cmake/CMakeUtils.cmake)

Expand All @@ -12,8 +10,6 @@ endif()

add_subdirectory(deps EXCLUDE_FROM_ALL)

set(TargetName walng)

enable_testing()

add_subdirectory(code)
Expand Down
46 changes: 26 additions & 20 deletions code/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,35 +1,41 @@
set(TargetName walng)

file(GLOB_RECURSE TargetModules "${CMAKE_CURRENT_SOURCE_DIR}/*.cppm")
file(GLOB_RECURSE TargetSources "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")

add_executable(${TargetName})
target_compile_features(${TargetName}
PRIVATE cxx_std_23)
set_target_properties(${TargetName}
PROPERTIES
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS OFF)
target_compile_features(${TargetName} PRIVATE cxx_std_23)
target_compile_options(${TargetName}
PRIVATE
-Wall -Wextra -Wattributes -Wpedantic -Wstrict-aliasing -Wcast-align -g
-fmacro-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}/=
-Wall -Wextra -Wnrvo -Wattributes -Wpedantic -Wstrict-aliasing -Wcast-align -g
)
target_compile_definitions(${TargetName}
PRIVATE -DWALNG_VERSION="${VersionString}"
PRIVATE
-DWALNG_VERSION="${CMAKE_PROJECT_VERSION}"
)
set_target_properties(${TargetName}
PROPERTIES
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS OFF
)
target_link_libraries(${TargetName}
PRIVATE cxxopts::cxxopts yaml-cpp::yaml-cpp 3rdparty::inja CURL::libcurl_static)

file(GLOB_RECURSE Sources "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
file(GLOB_RECURSE Headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h")
PRIVATE
CURL::libcurl_static cxxopts::cxxopts yaml-cpp::yaml-cpp 3rdparty::inja
)

CMakeUtilsAddTestsFromSourceList(Sources
CMakeUtilsAddTestsFromSourceList(TargetSources
PREFIX ${TargetName}
COMPILE_FEATURES cxx_std_23
COMPILE_OPTIONS -Wall -Wextra -g
LINK_LIBS doctest::doctest_with_main CURL::libcurl_static)
CMakeUtilsExcludeTestsFromSourceList(TargetSources)

CMakeUtilsExcludeTestsFromSourceList(Sources)

target_sources(${TargetName} PUBLIC ${Headers} ${Sources})
target_sources(${TargetName}
PRIVATE
${TargetSources}
PRIVATE
FILE_SET CXX_MODULES FILES
${TargetModules}
)

file(COPY config.yaml DESTINATION ${CMAKE_CURRENT_BINARY_DIR})

include(GNUInstallDirs)
install(TARGETS ${TargetName} DESTINATION ${CMAKE_INSTALL_BINDIR})
84 changes: 84 additions & 0 deletions code/basexx_theme.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright (c) Sergey Kovalevich <inndie@gmail.com>
// SPDX-License-Identifier: AGPL-3.0

module;

#include <array>
#include <expected>
#include <filesystem>
#include <format>
#include <span>

#include <yaml-cpp/yaml.h>

import walng.color;
import walng.utils;

module walng.basexx_theme;

namespace walng {
namespace {

constexpr std::array base16_colors{"base00", "base01", "base02", "base03", "base04", "base05", "base06", "base07",
"base08", "base09", "base0A", "base0B", "base0C", "base0D", "base0E", "base0F"};

constexpr std::array base24_colors{"base00", "base01", "base02", "base03", "base04", "base05", "base06", "base07",
"base08", "base09", "base0A", "base0B", "base0C", "base0D", "base0E", "base0F", "base10", "base11", "base12",
"base13", "base14", "base15", "base16", "base17"};

} // namespace

auto basexx_theme_parse_from_yaml(YAML::Node const& yaml) -> std::expected<basexx_theme, std::string> {
basexx_theme result;

result.name = yaml["name"].as<std::string>();
result.author = yaml["author"].as<std::string>();
result.variant = yaml["variant"].as<std::string>();
if (result.variant != "dark" && result.variant != "light") {
return std::unexpected(std::format("unknown theme variant value ({})", result.variant));
}
result.system = yaml["system"].as<std::string>();

std::span<char const* const> colors;
if (result.system == "base16") {
colors = std::span(base16_colors);
result.palette.reserve(16);
} else if (result.system == "base24") {
colors = std::span(base24_colors);
result.palette.reserve(24);
} else {
return std::unexpected(std::format("unknown theme system value ({})", result.system));
}

auto const yaml_palette_node = yaml["palette"];
for (auto const& name : colors) {
auto const hex_color_str = yaml_palette_node[name].as<std::string>();
if (auto rc = parse_color_from_hex_str(hex_color_str); rc) {
result.palette.emplace_back(*rc);
} else {
return std::unexpected(std::format("can' parse color '{}', {}", hex_color_str, rc.error()));
}
}

return {std::move(result)};
}

auto basexx_theme_parse_from_yaml_content(std::string const& content) -> std::expected<basexx_theme, std::string> {
try {
return basexx_theme_parse_from_yaml(YAML::Load(content));
} catch (YAML::Exception const& e) {
return std::unexpected(e.what());
}
}

auto basexx_theme_parse_from_yaml_file(std::filesystem::path const& path) -> std::expected<basexx_theme, std::string> {
try {
std::filesystem::path expanded_path = path;
expand_tilda(expanded_path);
return basexx_theme_parse_from_yaml(YAML::LoadFile(expanded_path.string()));
} catch (YAML::Exception const& e) {
return std::unexpected(e.what());
}
}

} // namespace walng
38 changes: 38 additions & 0 deletions code/basexx_theme.cppm
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (c) Sergey Kovalevich <inndie@gmail.com>
// SPDX-License-Identifier: AGPL-3.0

module;

#include <expected>
#include <filesystem>
#include <string>
#include <vector>

import walng.color;

export module walng.basexx_theme;

namespace walng {

export struct basexx_theme {
/// theme name
std::string name;
/// theme author
std::string author;
/// dark or light
std::string variant;
/// base16 or base24
std::string system;
/// palette
std::vector<color> palette;
};

/// parse theme from yaml content
export [[nodiscard]] auto basexx_theme_parse_from_yaml_content(std::string const& content)
-> std::expected<basexx_theme, std::string>;

/// parse theme from file with yaml content
export [[nodiscard]] auto basexx_theme_parse_from_yaml_file(std::filesystem::path const& path)
-> std::expected<basexx_theme, std::string>;

} // namespace walng
100 changes: 100 additions & 0 deletions code/color.cppm
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Copyright (c) Sergey Kovalevich <inndie@gmail.com>
// SPDX-License-Identifier: AGPL-3.0

module;

#include <array>
#include <charconv>
#include <cstdint>
#include <expected>
#include <string_view>

export module walng.color;

namespace walng {

export struct color_hex_str {
char value[7] = {'\0'};

constexpr operator char const*() const noexcept {
return value;
}

constexpr operator std::string_view() const noexcept {
return value;
}

constexpr auto c_str() const noexcept -> char const* {
return value;
}

constexpr auto string() const noexcept -> std::string_view {
return value;
}
};

export struct color_rgb {
std::uint8_t r; ///< Red [0..255]
std::uint8_t g; ///< Green [0..255]
std::uint8_t b; ///< Blue [0..255]
};

export struct color {
/// 0xRRGGBB
std::uint32_t value = 0;

constexpr auto as_rgb() const noexcept -> color_rgb {
// clang-format off
return color_rgb{
static_cast<std::uint8_t>((value & 0x00FF0000) >> 16),
static_cast<std::uint8_t>((value & 0x0000FF00) >> 8),
static_cast<std::uint8_t>((value & 0x000000FF))
};
// clang-format on
}

constexpr auto as_hex_str() const noexcept -> color_hex_str {
constexpr std::array chars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

auto color = as_rgb();
color_hex_str result;

result.value[0] = chars[color.r >> 4];
result.value[1] = chars[color.r & 0x0F];
result.value[2] = chars[color.g >> 4];
result.value[3] = chars[color.g & 0x0F];
result.value[4] = chars[color.b >> 4];
result.value[5] = chars[color.b & 0x0F];

return result;
}

constexpr auto operator<=>(color const&) const = default;
};

/// Parse color from stripped hex-string
/// i.e. @c 99aef1
export [[nodiscard]] constexpr auto parse_color_from_stripped_hex_str(std::string_view str) noexcept
-> std::expected<color, std::string_view> {
if (str.size() != 6) {
return std::unexpected("invalid color string (size)");
}
std::uint32_t value;
auto const [ptr, ec] = std::from_chars(str.begin(), str.end(), value, 16);
if (ec != std::errc()) {
return std::unexpected("invalid color string (hex chars)");
}
return {color{value}};
}

/// Parse color from hex-string
/// i.e. @c #99aef1
export [[nodiscard]] constexpr auto parse_color_from_hex_str(std::string_view str) noexcept
-> std::expected<color, std::string_view> {
if (!str.starts_with('#')) {
return std::unexpected("invalid color string (# not found)");
}
return parse_color_from_stripped_hex_str(str.substr(1));
}

} // namespace walng
11 changes: 0 additions & 11 deletions code/colors.cpp

This file was deleted.

Loading