From 176898f8437c97be3c0fe526befac9c3133a9ba4 Mon Sep 17 00:00:00 2001 From: garopoulos Date: Thu, 19 Mar 2026 17:01:08 +0200 Subject: [PATCH] Fix weird issue with not update when deleting --- CLAUDE.md | 54 +++++++++++++++++++++++++++++++++++ ly-ui/src/components/Text.zig | 3 ++ 2 files changed, 57 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..511f887 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,54 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +Ly is a lightweight TUI display manager for Linux and BSD, written in Zig 0.15.x. It provides a terminal-based login screen supporting X11 and Wayland sessions, with no systemd dependency. It uses PAM for authentication and termbox2 for terminal rendering. + +## Build Commands + +```bash +zig build # Compile +zig build run # Run in terminal emulator (testing only, auth won't work outside a real TTY) +zig build -Dinit_system=systemd # Build targeting a specific init system +zig build installexe # Install binary + config +zig build installnoconf # Update binary without overwriting config +zig build uninstallexe # Uninstall +``` + +Build options: `-Dconfig_directory=`, `-Dprefix_directory=`, `-Dname=`, `-Denable_x11_support=`, `-Ddefault_tty=`. + +There are no test or lint commands configured. + +## Dependencies + +- **Build:** Zig 0.15.x, libc, libpam (libpam0g-dev), libxcb (libxcb-xkb-dev, optional) +- **Zig packages** (in build.zig.zon): clap (CLI args), zigini (INI parsing), termbox2 (terminal rendering), ly_core (local shared library) + +## Architecture + +**Main loop** (`src/main.zig`): `UiState` struct owns all UI state. The event loop is termbox2-based with timeout support for animations. Authentication triggers PAM, then forks a child process for the user session. + +**Widget system** (`src/tui/Widget.zig`): Type-erased vtable polymorphism. Each widget implements `deinit`, `realloc`, `draw`, `update`, `handle`, `calculate_timeout`. Widgets are registered with `TerminalBuffer` which dispatches events and manages drawing. + +**TerminalBuffer** (`src/tui/TerminalBuffer.zig`): Wraps termbox2. Manages widget registration, event dispatch, keybinding callbacks, and terminal styling. + +**UI components** (`src/tui/components/`): Text input, labels, big ASCII labels, user list dropdown, session selector, centered dialog box, info/status line. + +**Config** (`src/config/Config.zig`): ~100 options parsed from INI file (`/etc/ly/config.ini`). The template is at `res/config.ini`. + +**Authentication** (`src/auth.zig`): PAM integration with X11 xauth handling, environment setup, and session process forking. + +**Animations** (`src/animations/`): Doom fire, Matrix, ColorMix, Game of Life, Cascade, DUR file format. Each is a separate widget. + +**C FFI** (`ly-core/src/interop.zig`): Bindings for PAM, utmpx, XCB, pwd/grp, TTY/VT management. Platform-specific code for Linux vs FreeBSD. + +**Localization** (`res/lang/`): 20+ language files. Language strings loaded via `src/config/Lang.zig`. + +## Key Patterns + +- Zig's comptime features are used extensively in Config.zig for field iteration and INI parsing. +- The widget vtable pattern uses `@fieldParentPtr` for type erasure — understand this before modifying widget code. +- Platform differences (Linux vs FreeBSD) are handled via comptime `@import("builtin").os.tag` checks, primarily in interop.zig and auth.zig. +- Init system support is compile-time selected, with service files in `res/` for each system (systemd, openrc, runit, s6, dinit, sysvinit, freebsd). diff --git a/ly-ui/src/components/Text.zig b/ly-ui/src/components/Text.zig index 0ad2128..8565664 100644 --- a/ly-ui/src/components/Text.zig +++ b/ly-ui/src/components/Text.zig @@ -187,6 +187,7 @@ fn goLeft(ptr: *anyopaque) !bool { if (self.visible_start > 0) self.visible_start -= 1; self.cursor -= 1; + self.buffer.drawNextFrame(true); return false; } @@ -197,6 +198,7 @@ fn goRight(ptr: *anyopaque) !bool { if (self.cursor - self.visible_start == self.width - 1) self.visible_start += 1; self.cursor += 1; + self.buffer.drawNextFrame(true); return false; } @@ -208,6 +210,7 @@ fn delete(ptr: *anyopaque) !bool { _ = self.text.orderedRemove(self.cursor); self.end -= 1; + self.buffer.drawNextFrame(true); return false; }