14 Commits
Author SHA1 Message Date
AramJonghu b1ef587dd2 fix(ci): cpp clang-tidy now properly reads non-build files only
C++ / fmt (pull_request) Successful in 6s
JS/TS / fmt & lint (pull_request) Successful in 16s
Python / fmt & lint (pull_request) Successful in 48s
C++ / build & lint (pull_request) Failing after 2m33s
Python / test & nuitka build (pull_request) Failing after 1m38s
Rust / build, clippy & fmt (pull_request) Failing after 4m41s
2026-10-25 16:01:40 +01:00
AramJonghu 9ad94f1e3e feat(makefile): added no nuitka option for cpp-compile task 2026-10-25 16:01:40 +01:00
AramJonghu 856c78c380 chore(gitignore): ordering known files and directories 2026-10-25 16:01:40 +01:00
AramJonghu 0c4e8e805a chore(gitignore): nuitka compile files ignored and categorized 2026-10-25 16:01:40 +01:00
AramJonghu 18c474669b fix(clang-tidy): make cpp-lint has proper clang-tidy check 2026-10-25 16:01:40 +01:00
AramJonghu 5eb84285a4 chore(Dockerfile): add future dependencies 2026-10-25 16:01:40 +01:00
zachandAramJonghu 02fb847268 Merge branch 'main' into feat/task-runner-ci 2026-10-25 16:01:40 +01:00
AramJonghu a96211a5b5 feat(makefile): added qmlformat + install -> compile in cpp step 2026-10-25 16:01:40 +01:00
AramJonghu cbb108a6dd feat(makefile): C++, Python, and Rust checks included (incomplete) 2026-10-25 16:01:40 +01:00
AramJonghu 9f9d09bc5b feat(makefile): makefile build & install + progress on cpp and py 2026-10-25 16:01:40 +01:00
AramJonghu a2326dc641 format(clang): make cpp-fmt result 2026-10-25 16:01:39 +01:00
AramJonghu b4f0239e2a ci: rework Dockerfile image + buildx dep added 2026-10-25 16:01:39 +01:00
AramJonghu fd938d4e47 refactor(workflows): combined steps where it makes sense 2026-10-25 16:01:39 +01:00
AramJonghu c5dfb306dd fix(ci): missing dependency wayland-scanner 2026-10-25 16:01:39 +01:00
12 changed files with 245 additions and 214 deletions
+1 -1
View File
@@ -18,7 +18,7 @@ jobs:
uses: actions/checkout@v4
- name: Install Docker CLI
run: apk add --no-cache docker-cli
run: apk add --no-cache docker-cli docker-cli-buildx
- name: Login to registry
run: echo "${{ secrets.REGISTRY_TOKEN }}" | docker login git.aramjonghu.dev --username aramjonghu --password-stdin
+5 -21
View File
@@ -20,28 +20,10 @@ jobs:
-exec clang-format -i --style=file {} +
git diff --exit-code && echo "clang-format: passed"
build:
build & lint:
runs-on: alpine
container:
image: git.aramjonghu.dev/aramjonghu/zshell-ci:latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Configure
run: cmake -B build -G Ninja -DENABLE_MODULES=plugin -DCMAKE_BUILD_TYPE=Release
- name: Build
run: ninja -C build
clang-tidy:
runs-on: alpine
container:
image: git.aramjonghu.dev/aramjonghu/zshell-ci:latest
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -58,5 +40,7 @@ jobs:
run: |
sed -i 's/-mno-direct-extern-access //g' build/compile_commands.json
set -o pipefail
run-clang-tidy -p build -j $(nproc) -header-filter="Plugins/.*" 2>&1 | \
grep -v 'Suppressed\|non-user\|non-system\|unknown argument.*mno-direct\|Found compiler error\|warnings generated\.\|^Use -header-filter'
run-clang-tidy -p build -j "$(nproc)" \
-source-filter="^$(pwd)/Plugins/" \
-header-filter=".*Plugins/.*" \
-removed-arg=-mno-direct-extern-access
+1 -15
View File
@@ -4,7 +4,7 @@ on:
pull_request:
jobs:
fmt:
fmt & lint:
runs-on: alpine
container: node:26-alpine
@@ -24,20 +24,6 @@ jobs:
else
echo "No JS/TS files found"
fi
lint:
runs-on: alpine
container: node:26-alpine
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install tools
run: |
apk add --no-cache \
git
- name: ESLint
run: |
if [ -n "$(find . \( -iname "*.js" -o -iname "*.jsx" -o -iname "*.ts" -o -iname "*.tsx" -o -iname "*.mjs" -o -iname "*.cjs" \) -print -quit)" ]; then
+2 -2
View File
@@ -7,7 +7,7 @@ on:
pull_request:
jobs:
static:
fmt & lint:
runs-on: debian
container: node:26-trixie-slim
@@ -33,7 +33,7 @@ jobs:
. .venv/bin/activate
ruff check .
verify:
test & nuitka build:
if: always()
runs-on: debian
container: node:26-trixie-slim
+21 -86
View File
@@ -3,8 +3,9 @@ name: Rust
on:
pull_request:
# jobs can be separated if we integrate tests
jobs:
build:
build, clippy & fmt:
runs-on: alpine
container: node:26-alpine
env:
@@ -34,7 +35,9 @@ jobs:
apk add --no-cache \
git \
cargo \
rust
rust \
rust-clippy \
rustfmt
- name: Cargo check
run: |
@@ -50,90 +53,6 @@ jobs:
else
echo "No Rust project found"
fi
fmt:
runs-on: alpine
container: node:26-alpine
env:
CARGO_HOME: ${{ github.workspace }}/.cargo
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Cache cargo packages
uses: actions/cache@v4
env:
cache-name: cache-cargo-packages
with:
path: |
.cargo/registry
.cargo/git
target
key: rust-fmt-${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
rust-${{ runner.os }}-build-${{ env.cache-name }}-
rust-${{ runner.os }}-build-
rust-
- name: Install tools
run: |
apk add --no-cache \
git \
cargo \
rust \
rustfmt
- name: Format check
run: |
if [ -n "$(find . -name "Cargo.toml" -print -quit)" ]; then
status=0
for manifest in $(find . -name "Cargo.toml"); do
cargo fmt --manifest-path "$manifest" --check && \
echo "$manifest: formatting OK" || \
{ echo "$manifest: needs formatting"; status=1; }
done
exit $status
elif [ -n "$(find . -name "*.rs" -print -quit)" ]; then
echo "Rust files found but no Cargo.toml"
exit 1
else
echo "No Rust project found"
fi
clippy:
runs-on: alpine
container: node:26-alpine
env:
CARGO_HOME: ${{ github.workspace }}/.cargo
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Cache cargo packages
uses: actions/cache@v4
env:
cache-name: cache-cargo-packages
with:
path: |
.cargo/registry
.cargo/git
target
key: rust-clippy-${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
rust-${{ runner.os }}-build-${{ env.cache-name }}-
rust-${{ runner.os }}-build-
rust-
- name: Install tools
run: |
apk add --no-cache \
git \
cargo \
rust \
rust-clippy
- name: Clippy
run: |
if [ -n "$(find . -name "Cargo.toml" -print -quit)" ]; then
@@ -150,3 +69,19 @@ jobs:
else
echo "No Rust project found"
fi
- name: Format check
run: |
if [ -n "$(find . -name "Cargo.toml" -print -quit)" ]; then
status=0
for manifest in $(find . -name "Cargo.toml"); do
cargo fmt --manifest-path "$manifest" --check && \
echo "$manifest: formatting OK" || \
{ echo "$manifest: needs formatting"; status=1; }
done
exit $status
elif [ -n "$(find . -name "*.rs" -print -quit)" ]; then
echo "Rust files found but no Cargo.toml"
exit 1
else
echo "No Rust project found"
fi
+22 -10
View File
@@ -1,23 +1,35 @@
**/__pycache__/
./result/
.pyre/
.cache/
.venv/
.qmlls.ini
build/
compile_commands.json
testpython
pkg/
*.tar.*
uv.lock
.qtcreator/
dist/
**/target/
**/test-plugins/
**/Charts/
network-dev/
**/zshell.build/
**/zshell.dist/
# Qml
.qtcreator/
.qmlls.ini
# CMake compile artifacts
.cache/
compile_commands.json
build/
# Python
uv.lock
testpython
.venv/
**/__pycache__/
# Nuitka compile
**/zshell.pyi
**/zshell.cpython-*
**/zshell.build/
# Agents stuff
.opencode/
run-agent.sh
AGENTS.md
+1 -1
View File
@@ -218,7 +218,7 @@ void BlobInvertedRect::outerCornerRadii(float out[4]) const {
const auto base = std::min(static_cast<float>(m_outerRadius), maxR);
out[0] = std::min(
m_outerTopRightRadius >= 0 ? static_cast<float>(m_outerTopRightRadius)
: base,
: base,
maxR);
out[1] = std::min(
m_outerBottomRightRadius >= 0
+6 -2
View File
@@ -60,11 +60,15 @@ class BlobInvertedRect : public BlobShape {
void setOuterRadius(qreal v);
// Per-corner outer radii. -1 falls back to outerRadius (mirrors BlobRect).
[[nodiscard]] qreal outerTopLeftRadius() const { return m_outerTopLeftRadius; }
[[nodiscard]] qreal outerTopLeftRadius() const {
return m_outerTopLeftRadius;
}
void setOuterTopLeftRadius(qreal v);
[[nodiscard]] qreal outerTopRightRadius() const { return m_outerTopRightRadius; }
[[nodiscard]] qreal outerTopRightRadius() const {
return m_outerTopRightRadius;
}
void setOuterTopRightRadius(qreal v);
+1 -2
View File
@@ -240,8 +240,7 @@ void BlobShape::updatePolish() {
m_cachedInvertedRadius = 0;
memset(m_cachedInvertedOuter, 0, sizeof(m_cachedInvertedOuter));
memset(m_cachedInvertedInner, 0, sizeof(m_cachedInvertedInner));
memset(
m_cachedInvertedOuterRadii, 0, sizeof(m_cachedInvertedOuterRadii));
memset(m_cachedInvertedOuterRadii, 0, sizeof(m_cachedInvertedOuterRadii));
auto* inv = m_group->invertedRect();
if (inv) {
+53 -20
View File
@@ -14,10 +14,9 @@
#include <hyprland/src/plugins/PluginAPI.hpp>
#include <hyprland/src/render/OpenGL.hpp>
#include <hyprland/src/render/Renderer.hpp>
#include <hyprland/src/render/Context.hpp>
#undef private
#include <hyprland/src/ipc/s2/S2.hpp>
#include <hyprland/src/managers/EventManager.hpp>
extern "C" {
#include <lua.h>
@@ -28,7 +27,6 @@ extern "C" {
using ZShell::services::kelvinToGain;
using Render::CRenderContext;
using Render::IFramebuffer;
using Render::GL::CHyprOpenGLImpl;
using Render::GL::g_pHyprOpenGL;
@@ -151,14 +149,25 @@ static bool gainIsNeutral(const std::array<float, 3>& gain) {
}
static CFunctionHook* g_pBeginHook = nullptr;
using origBegin = bool (*)(
using origBegin = void (*)(
CHyprOpenGLImpl*,
CRenderContext&,
PHLMONITOR,
const CRegion&,
SP<IFramebuffer>,
std::optional<CRegion>);
static CFunctionHook* g_pSaveMirrorHook = nullptr;
using origSaveMirror = bool (*)(CHyprOpenGLImpl*, const CBox&);
static bool hkSaveBufferForMirror(CHyprOpenGLImpl* thisptr, const CBox& box) {
const bool saved = thisptr->m_applyFinalShader;
thisptr->m_applyFinalShader = false;
const bool result = (*reinterpret_cast<origSaveMirror>(
g_pSaveMirrorHook->m_original))(thisptr, box);
thisptr->m_applyFinalShader = saved;
return result;
}
static void installShader() {
auto* gl = g_pHyprOpenGL.get();
if (!gl) return;
@@ -189,33 +198,34 @@ static void setUniformGain(const std::array<float, 3>& gain) {
shader->setUniformFloat3(SHADER_TINT, gain[0], gain[1], gain[2]);
}
static bool hkBegin(
static void hkBegin(
CHyprOpenGLImpl* thisptr,
CRenderContext& ctx,
PHLMONITOR mon,
const CRegion& damage,
SP<IFramebuffer> fb,
std::optional<CRegion> finalDamage) {
const bool ok = (*reinterpret_cast<origBegin>(
g_pBeginHook->m_original))(thisptr, ctx, mon, damage, fb, finalDamage);
if (!ok) return false;
(*reinterpret_cast<origBegin>(
g_pBeginHook->m_original))(thisptr, mon, damage, fb, finalDamage);
if (fb) ctx.m_data.blockScreenShader = true;
if (fb) {
auto* renderer = g_pHyprRenderer.get();
if (renderer) renderer->m_renderData.blockScreenShader = true;
}
if (!g_active) return true;
if (!g_active) return;
auto* gl = g_pHyprOpenGL.get();
if (!gl) return true;
if (!gl) return;
if (gl->m_finalScreenShader.get() && gl->m_finalScreenShader->program() < 1)
installShader();
if (!gl->m_finalScreenShader.get() ||
gl->m_finalScreenShader->program() < 1)
return true;
return;
if (g_transition.active) {
auto* monPtr = mon.get();
if (!monPtr) return true;
if (!monPtr) return;
const float elapsed =
std::chrono::duration<float>(
std::chrono::steady_clock::now() - g_transition.start)
@@ -255,7 +265,6 @@ static bool hkBegin(
} else if (g_uniformMode) {
setUniformGain(g_currentGain);
}
return true;
}
static constexpr int KELVIN_MIN = 2000;
@@ -324,10 +333,9 @@ static int luaNightlightState(lua_State* L) {
}
static void postStateEvent(bool enabled, bool animating) {
auto& sock = IPC::Socket2::sock();
if (!sock) return;
sock->postEvent(
IPC::Socket2::SEvent{
if (!g_pEventManager) return;
g_pEventManager->postEvent(
SHyprIPCEvent{
.event = "zshell-nightlight",
.data = std::format(
"{},{},{},{}",
@@ -369,6 +377,31 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
throw std::runtime_error("[zshell-nightlight] version mismatch");
}
static const auto SAVEMIRROR_METHODS =
HyprlandAPI::findFunctionsByName(PHANDLE, "saveBufferForMirror");
const SFunctionMatch* saveMirrorTarget = findExactMethod(
SAVEMIRROR_METHODS,
manglePrefix("CHyprOpenGLImpl", "saveBufferForMirror"));
if (saveMirrorTarget) {
g_pSaveMirrorHook = HyprlandAPI::createFunctionHook(
PHANDLE,
saveMirrorTarget->address,
reinterpret_cast<void*>(&hkSaveBufferForMirror));
if (g_pSaveMirrorHook && g_pSaveMirrorHook->hook())
dlog(
"saveBufferForMirror hook installed: " +
saveMirrorTarget->signature);
}
if (!g_pSaveMirrorHook)
HyprlandAPI::addNotification(
PHANDLE,
"[zshell-nightlight] WARNING: couldn't hook saveBufferForMirror — "
"captures may still show the nightlight",
CHyprColor{1.f, 0.6f, 0.2f, 1.f},
8000);
static const auto METHODS =
HyprlandAPI::findFunctionsByName(PHANDLE, "begin");
const SFunctionMatch* target =
+25 -53
View File
@@ -1,56 +1,28 @@
FROM archlinux:latest
RUN pacman -Syyu --noconfirm
RUN pacman -Syu --noconfirm \
&& pacman -S --needed --noconfirm \
base-devel cmake ninja clang lld nodejs tree-sitter \
jkqtplotter cmark-gfm git wayland-protocols ffmpeg mpv \
qt6-base qt6-declarative qt6-shadertools qt6-5compat \
qt6-canvaspainter qt6-wayland qt5-wayland \
libqalculate pipewire aubio cava lm_sensors glib2 \
&& pacman -Scc --noconfirm
# Build toolchain
RUN pacman -S --noconfirm \
base-devel \
cmake \
ninja \
clang \
lld \
nodejs \
tree-sitter \
jkqtplotter \
cmark-gfm \
git
# Qt6
RUN pacman -S --noconfirm \
qt6-base \
qt6-declarative \
qt6-shadertools \
qt6-5compat \
qt6-canvaspainter
# Project-specific dependencies
RUN pacman -S --noconfirm \
libqalculate \
pipewire \
aubio \
cava \
lm_sensors \
glib2
# AUR: libcava (provides development headers for cava)
RUN pacman -Syu --noconfirm && \
pacman -S --needed --noconfirm \
sudo \
meson \
autoconf-archive \
python-tqdm && \
useradd -m builder && \
echo "builder ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
RUN for i in 1 2 3 4 5; do \
rm -rf /tmp/libcava && \
git clone --depth 1 https://aur.archlinux.org/libcava.git /tmp/libcava && \
break || sleep 5; \
done && \
test -d /tmp/libcava/.git && \
chown -R builder /tmp/libcava
RUN su builder -c "cd /tmp/libcava && makepkg -si --noconfirm" && \
rm -rf /tmp/libcava && \
userdel -r builder && \
sed -i '/^builder/d' /etc/sudoers
RUN pacman -Syu --noconfirm \
&& pacman -S --needed --noconfirm \
sudo meson autoconf-archive python-tqdm \
&& useradd -m builder \
&& printf '%s\n' 'builder ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/builder \
&& chmod 0440 /etc/sudoers.d/builder \
&& for i in 1 2 3 4 5; do \
rm -rf /tmp/libcava; \
if git clone --depth 1 https://aur.archlinux.org/libcava.git /tmp/libcava; then break; fi; \
sleep 5; \
done \
&& test -d /tmp/libcava/.git \
&& chown -R builder:builder /tmp/libcava \
&& su builder -c "cd /tmp/libcava && makepkg -si --noconfirm" \
&& rm -rf /tmp/libcava /etc/sudoers.d/builder \
&& userdel -r builder \
&& pacman -Scc --noconfirm
+106
View File
@@ -0,0 +1,106 @@
BUILD ?= cmake -B build -G Ninja
NONUITKA ?= cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DENABLE_MODULES="plugin;shell;m3shapes"
NINJA ?= ninja -C build
COMPILE ?= $(BUILD) && $(NINJA)
INSTALL ?= $(BUILD) && $(NINJA) && sudo ninja -C build install
CPPFMT ?= find . \( -name '*.cpp' -o -name '*.h' -o -name '*.hpp' \) -not -path './build/*' -exec clang-format -i --style=file {} +
CPPLINT ?= run-clang-tidy -p build -j "$$(nproc)" -source-filter="^$$(pwd)/Plugins/" -header-filter=".*Plugins/.*" -removed-arg=-mno-direct-extern-access
NUITKA ?= nuitka --module --include-package=zshell cli/src/zshell/ --output-dir=cli/
.DEFAULT_GOAL := help
# string is misaligned to align when run in terminal
help:
@echo "build cmake builds into build directory"
@echo "install cmake builds, compiles and installs into filesystem"
@echo "compile cmake builds and compiles C++ code"
@echo "cpp-fmt format C++ code with clang-format"
@echo "cpp-lint lint check C++ code with clang-tidy"
@echo "cpp-compile similar to make compile, but excludes Nuitka from compiling python"
@echo "py-fmt format Python code with ruff"
@echo "py-lint lint check Python code with ruff"
@echo "py-check lsp and typecheck all Python code using Basedpyright"
@echo "py-test run all Python tests using Pytest"
@echo "py-compile compiles Python code using Nuitka"
@echo "rs-compile compiles Rust code"
@echo "rs-format formats Rust code with Rustfmt"
@echo "rs-lint lint check Rust code with Clippy"
@echo "rs-test runs all Rust tests"
@echo "qml-fmt format QML code with qmlformat"
@echo "check-cpp runs all C++ checks"
@echo "check-py runs all Python checks"
@echo "check-rs runs all Rust checks"
build:
$(BUILD)
install:
$(INSTALL)
compile:
$(COMPILE)
# C++
cpp-fmt:
$(CPPFMT)
cpp-lint:
$(CPPLINT)
cpp-compile:
$(NONUITKA)
# Python
py-fmt:
ruff format --check
py-lint:
ruff check ./cli
py-check:
basedpyright
py-test:
python -m pytest ./cli/tests/ -v
# Want to use gcc, clang or zig C compiler instead? Output directory?
py-compile:
$(NUITKA)
# Rust
rs-compile:
cd ./zshell-img-tools/ && cargo run
rs-fmt:
cd ./zshell-img-tools/ && cargo fmt && echo "formatted!"
rs-lint:
cd ./zshell-img-tools/ && cargo clippy
rs-test:
cd ./zshell-img-tools/ && cargo test
# Qml
qml-fmt:
find -name '*.qml' -exec /usr/lib/qt6/bin/qmlformat -i {} +
# Full checks
check-cpp:
$(MAKE) cpp-fmt
$(MAKE) cpp-lint
$(MAKE) compile
check-rs:
$(MAKE) rs-fmt
$(MAKE) rs-lint
$(MAKE) rs-test
$(MAKE) rs-compile
check-py:
$(MAKE) py-fmt
$(MAKE) py-lint
$(MAKE) py-test
$(MAKE) py-check
$(MAKE) py-compile