diff options
| author | Paul Buetow <paul@buetow.org> | 2026-07-12 17:00:43 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-07-12 17:00:43 +0300 |
| commit | 78fa24a665002c01f0ea7ded8791c7e6af470305 (patch) | |
| tree | aaa5625337ff4cc97f40f855405c9091b3b3496a /docs/coding-conventions.md | |
Add ggaze implementation plan (docs/)
Diffstat (limited to 'docs/coding-conventions.md')
| -rw-r--r-- | docs/coding-conventions.md | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/docs/coding-conventions.md b/docs/coding-conventions.md new file mode 100644 index 0000000..e1d1d44 --- /dev/null +++ b/docs/coding-conventions.md @@ -0,0 +1,127 @@ +# Coding Conventions + +ggaze follows the **c-best-practices** skill +(`~/.agents/skills/c-best-practices/SKILL.md`). That skill and its references +are authoritative; this page summarizes the conventions as they apply to +ggaze so contributors don't have to context-switch. When in doubt, the skill +wins. + +## Source style + +- **Indentation**: 3 spaces, no tabs. +- **Line length**: max 80 chars. +- **Braces**: K&R — opening brace on the same line as the statement/condition. +- **Pointer asterisk**: on the variable, not the type — `Token *p_token`, not + `Token* p_token`. +- **Returns**: parenthesized — `return (p_token);`. Return type on its own + line above the function name. +- **Comments**: `/* ... */` for blocks, `//` for single lines; put notes on + their own line, not trailing. + +## Naming + +| Category | Convention | ggaze examples | +|-------------------|-----------------------------|------------------------------------------| +| Types | PascalCase | `GgazeWindow`, `GgazeViewer`, `GgazeGrid`, `Navigator`, `Loader`, `Thumbnail` | +| Functions | `module_action` (snake_case)| `navigator_new`, `navigator_next`, `viewer_set_texture`, `grid_get_selected`, `trash_bin`, `mover_move`, `opener_launch`, `runner_run`, `enhancer_apply`, `clipboard_copy_image` | +| Variables | `prefix_name` (type prefix) | `p_nav`, `p_texture`, `i_count`, `c_path`, `u_idx`, `b_wrapped` | +| Macros/constants | UPPER_SNAKE_CASE | `GGAZE_APP_ID`, `GGAZE_PREFETCH_N`, `NO_DEFAULT` | +| Enum values | `MODULE_PREFIX_NAME` | `GGAZE_SORT_NAME`, `GGAZE_SORT_TIME` | +| Callbacks | `name_cb` | `loader_ready_cb`, `navigator_changed_cb` | +| Static/private fns| `_prefix_name` | `_viewer_clamp_pan`, `_loader_pick_backend` | + +Variable prefixes: `p_` pointer, `i_` int, `c_` char/string, `u_` unsigned, +`b_` bool. Use them consistently. + +## Module layout (one module per file pair) + +Every module is a `foo.h` + `foo.c` pair named after its main type. Related +types (element, iterator, state) live in the same pair, not split out. + +``` +navigator.h / navigator.c → Navigator (+ NavigatorIterator if needed) +viewer.h / viewer.c → GgazeViewer +gridview.h / gridview.c → GgazeGrid +loader.h / loader.c → Loader (+ per-backend structs under loader/) +trash.h / trash.c → Trash +mover.h / mover.c → Mover (+ MoverDest) +opener.h / opener.c → Opener (+ OpenerProg) +runner.h / runner.c → Runner (+ RunnerScript) +enhancer.h / enhancer.c → Enhancer (+ EnhancerPreset) [GEGL, optional] +clipboard.h / clipboard.c → helpers (no type) — like settings +thumbnail.h / thumbnail.c → Thumbnail +settings.h / settings.c → wraps GSettings (no custom type, just helpers) +``` + +### Lifecycle: `_new` / `_delete` + +Every concrete type gets `Type *type_new(...)` and `void type_delete(Type *p)`. +Pair every `_new` with a `_delete`; never leave allocation unbalanced. + +```c +Navigator* +navigator_new(GFile *p_dir, GgazeSort sort); + +void +navigator_delete(Navigator *p_nav); +``` + +For types passed as `void*` to generic callbacks (e.g. `g_list_free_full`), +provide `void type_delete_cb(void *p_void)`. + +### Iterators + +When a module exposes traversal, follow +`TypeIterator *typeiterator_new(Container *p)`, +`void typeiterator_delete(TypeIterator *p)`, +`void *typeiterator_next(TypeIterator *p)`, +`_Bool typeiterator_has_next(TypeIterator *p)`. +The iterator type lives in the same file pair as its container. + +### Accessors + +`module_get_field(obj)`, `module_set_field(obj, val)` — macros for trivial +access, functions for non-trivial logic. Keep accessor macros side-effect-free. + +## Headers + +- **Header guards** UPPERCASE, derived from filename: + `#ifndef NAVIGATOR_H` / `#define NAVIGATOR_H`. +- **Header order** inside a header: guard, includes, macros, enums, structs, + `new`/`delete`, then the rest. +- **`.c` include order**: own header first, then system, then project headers. + Optional forward declarations between own header and the rest. + +## Errors + +- **Fatal** errors via the project's `ERROR(...)` (abort with a message). +- **Recoverable** errors via a documented return: a `RETCODE`, a `gboolean`, + or a `GError **` where GLib conventions apply (loader, file I/O). +- Decoders return `NULL` + set `GError **` on failure; the window shows a + placeholder and advances — never crash on a bad file. + +## Globals + +Minimal. Any global is named UPPER or `_prefix` and lives in the module that +owns it. No module reaches into another's globals — go through accessors. + +## GObject / GTK notes + +GTK/GObject types (`GgazeWindow`, `GgazeViewer`, `GgazeGrid`) use `G_DEFINE_TYPE` +and GObject conventions (constructed/dispose) for the GObject side; the +`_new`/`_delete` skill pattern still applies to the plain-C modules +(`Navigator`, `Loader`, `Trash`, `Mover`, `Opener`, `Runner`, `Enhancer`, `Thumbnail`) that have no GObject parent. +Keep the two worlds clean: plain-C modules own no GtkWidget and are unit-testable +without a display. + +## Testing + +Each plain-C module pair ships a `tests/test_<module>.c` using GLib's `GTest` +framework (or a tiny harness), run via `meson test`. Aim for **≥80% line +coverage** (gcov/lcov: `meson setup -Db_coverage=true && meson test && ninja -C +build coverage`), gated in CI. GObject/GTK widgets get smoke tests only; the +logic lives in the plain-C modules so it's testable without a display. +Beyond tests, run the `auditing-code-quality` skill (C-adapted: +`c-best-practices` + `find-code-bugs` + `solid-principles` + +`beyond-solid-principles`) at milestone boundaries and track findings via +`agent-task-management`.
\ No newline at end of file |
