diff --git a/.gitea/workflows/ci-image.yml b/.gitea/workflows/ci-image.yml index 3ee05f3..147a3df 100644 --- a/.gitea/workflows/ci-image.yml +++ b/.gitea/workflows/ci-image.yml @@ -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 diff --git a/.gitea/workflows/cpp.yml b/.gitea/workflows/cpp.yml index 90eb487..cca38ae 100644 --- a/.gitea/workflows/cpp.yml +++ b/.gitea/workflows/cpp.yml @@ -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 diff --git a/.gitea/workflows/js-ts.yml b/.gitea/workflows/js-ts.yml index 639adaf..ce8672f 100644 --- a/.gitea/workflows/js-ts.yml +++ b/.gitea/workflows/js-ts.yml @@ -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 diff --git a/.gitea/workflows/python.yml b/.gitea/workflows/python.yml index 06377a8..ac44cd9 100644 --- a/.gitea/workflows/python.yml +++ b/.gitea/workflows/python.yml @@ -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 @@ -64,4 +64,4 @@ jobs: - name: Nuitka module check run: | . .venv/bin/activate - nuitka --module --include-package=zshell cli/src/zshell/ \ No newline at end of file + nuitka --module --include-package=zshell cli/src/zshell/ diff --git a/.gitea/workflows/rust.yml b/.gitea/workflows/rust.yml index da2d4bf..a1e9e38 100644 --- a/.gitea/workflows/rust.yml +++ b/.gitea/workflows/rust.yml @@ -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 diff --git a/.gitignore b/.gitignore index c6ff3ec..7935e69 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/Plugins/ZShell/Blobs/blobinvertedrect.cpp b/Plugins/ZShell/Blobs/blobinvertedrect.cpp index 0e4336c..800d975 100644 --- a/Plugins/ZShell/Blobs/blobinvertedrect.cpp +++ b/Plugins/ZShell/Blobs/blobinvertedrect.cpp @@ -218,7 +218,7 @@ void BlobInvertedRect::outerCornerRadii(float out[4]) const { const auto base = std::min(static_cast(m_outerRadius), maxR); out[0] = std::min( m_outerTopRightRadius >= 0 ? static_cast(m_outerTopRightRadius) - : base, + : base, maxR); out[1] = std::min( m_outerBottomRightRadius >= 0 diff --git a/Plugins/ZShell/Blobs/blobinvertedrect.hpp b/Plugins/ZShell/Blobs/blobinvertedrect.hpp index 60121d0..d3e1fb9 100644 --- a/Plugins/ZShell/Blobs/blobinvertedrect.hpp +++ b/Plugins/ZShell/Blobs/blobinvertedrect.hpp @@ -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); diff --git a/Plugins/ZShell/Blobs/blobshape.cpp b/Plugins/ZShell/Blobs/blobshape.cpp index 33fd5b4..59978a3 100644 --- a/Plugins/ZShell/Blobs/blobshape.cpp +++ b/Plugins/ZShell/Blobs/blobshape.cpp @@ -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) { diff --git a/ci/Dockerfile b/ci/Dockerfile index d1b3965..a590ac3 100644 --- a/ci/Dockerfile +++ b/ci/Dockerfile @@ -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 diff --git a/makefile b/makefile new file mode 100644 index 0000000..a4ec05a --- /dev/null +++ b/makefile @@ -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