[NaoixOS] NaoixSH v0.3.2 — refactored the shell command dispatcher
Posted: Tue Jul 28, 2026 7:08 am
[NaoixOS] NaoixSH v0.3.2 — refactored the shell command dispatcher (still 100% built from a phone)
Small update on **NaoixOS**, my hobby i686 kernel that I build entirely from an Android phone via Termux (no PC involved — Clang targeting `i686-elf`, `ld.lld`, QEMU/Limbo for testing). This one's shell-side only, no kernel changes.
**What changed (NaoixSH v0.3.2, kernel stays at v0.6.8-rc1)**
The embedded shell, NaoixSH, had grown its command handling into a single long `if/else if` chain inside `run_command()`. It worked, but adding a new command meant scrolling through one increasingly large function. Refactored it into a proper dispatch table:
```c
typedef struct {
const char *name;
void (*handler)(void);
} shell_command_t;
extern const shell_command_t shell_commands[];
```
Each command now lives in its own file under `shell/commands/` (`help.c`, `about.c`, `sysinfo.c`, `jackmasterdev.c`, etc.), registered in one central `table.c`:
```c
const shell_command_t shell_commands[] = {
{ "help", cmd_help },
{ "about", cmd_about },
{ "sysinfo", cmd_sysinfo },
{ "jackmasterdev", cmd_jackmasterdev },
...
{ NULL, NULL }
};
```
`run_command()` is now just a loop over that table. Adding a command is: write the `.c` file, declare it in `commands.h`, add one line to the table. No touching the dispatcher itself.
Shared state (`g_dev_mode`, previously a `static` local) moved to `shell_state.h` so command modules can read/write it without reaching into `naoixsh.c` internals. Shared effects code (a small matrix-rain animation, tick-based wait/skip logic, a `print_kv` helper for key/value output) got pulled out into `shell_fx.c` / `shell_fx.h` since more than one command used them.
Build system just needed the `SRC_C` wildcard in the Makefile extended to also pick up `shell/commands/*.c` — everything else fell into place automatically thanks to GNU Make's pattern rules handling the subdirectory paths fine.
**Also fixed:** one of the easter-egg commands (`easterg`) had light-grey text on a flat red background — worked, but read like an error/warning rather than a "you found something" moment. Recolored it per-phrase (white base text, highlighted keywords, distinct color for the developer name) to match the rest of the shell's palette instead of breaking it.
**Why bother refactoring a hobby shell this much?** Mostly because the command count keeps growing and I wanted the "add one command" workflow to stay a one-file-plus-one-line operation rather than an ever-longer function, especially since I'm doing all of this from a phone screen where scrolling through a giant function is more painful than on a real monitor.
Repo: https://github.com/jackidevz/NaoixOS (built with Clang + `ld.lld` in Termux, floppy-image boot path via a custom stage1, tested mainly in QEMU and Limbo).
Happy to answer questions about the phone-only toolchain setup if anyone's curious how that works in practice.
Small update on **NaoixOS**, my hobby i686 kernel that I build entirely from an Android phone via Termux (no PC involved — Clang targeting `i686-elf`, `ld.lld`, QEMU/Limbo for testing). This one's shell-side only, no kernel changes.
**What changed (NaoixSH v0.3.2, kernel stays at v0.6.8-rc1)**
The embedded shell, NaoixSH, had grown its command handling into a single long `if/else if` chain inside `run_command()`. It worked, but adding a new command meant scrolling through one increasingly large function. Refactored it into a proper dispatch table:
```c
typedef struct {
const char *name;
void (*handler)(void);
} shell_command_t;
extern const shell_command_t shell_commands[];
```
Each command now lives in its own file under `shell/commands/` (`help.c`, `about.c`, `sysinfo.c`, `jackmasterdev.c`, etc.), registered in one central `table.c`:
```c
const shell_command_t shell_commands[] = {
{ "help", cmd_help },
{ "about", cmd_about },
{ "sysinfo", cmd_sysinfo },
{ "jackmasterdev", cmd_jackmasterdev },
...
{ NULL, NULL }
};
```
`run_command()` is now just a loop over that table. Adding a command is: write the `.c` file, declare it in `commands.h`, add one line to the table. No touching the dispatcher itself.
Shared state (`g_dev_mode`, previously a `static` local) moved to `shell_state.h` so command modules can read/write it without reaching into `naoixsh.c` internals. Shared effects code (a small matrix-rain animation, tick-based wait/skip logic, a `print_kv` helper for key/value output) got pulled out into `shell_fx.c` / `shell_fx.h` since more than one command used them.
Build system just needed the `SRC_C` wildcard in the Makefile extended to also pick up `shell/commands/*.c` — everything else fell into place automatically thanks to GNU Make's pattern rules handling the subdirectory paths fine.
**Also fixed:** one of the easter-egg commands (`easterg`) had light-grey text on a flat red background — worked, but read like an error/warning rather than a "you found something" moment. Recolored it per-phrase (white base text, highlighted keywords, distinct color for the developer name) to match the rest of the shell's palette instead of breaking it.
**Why bother refactoring a hobby shell this much?** Mostly because the command count keeps growing and I wanted the "add one command" workflow to stay a one-file-plus-one-line operation rather than an ever-longer function, especially since I'm doing all of this from a phone screen where scrolling through a giant function is more painful than on a real monitor.
Repo: https://github.com/jackidevz/NaoixOS (built with Clang + `ld.lld` in Termux, floppy-image boot path via a custom stage1, tested mainly in QEMU and Limbo).
Happy to answer questions about the phone-only toolchain setup if anyone's curious how that works in practice.