Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

sugarcraft/candy-mold

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

62 Commits

Repository files navigation

candy-mold

CandyMold

CI codecov Packagist Version License PHP

demo

Skeleton repo for bootstrapping a SugarCraft TUI app. Pour your model into the mold and you've got a working app.

composer create-project sugarcraft/candy-mold my-app
cd my-app
./bin/start

and you'll see a working counter. Replace src/Counter.php with your own Model, keep editing.

What you get

my-app/
β”œβ”€β”€ composer.json # requires candy-core + candy-sprinkles
β”œβ”€β”€ phpunit.xml
β”œβ”€β”€ bin/start # entry point β€” runs Program(new Counter())
β”œβ”€β”€ src/
β”‚ └── Counter.php # demo Model with up/down/quit, styled border
└── tests/
 └── CounterTest.php

bin/start is just three meaningful lines: load the autoloader, instantiate your Model, hand it to Program::run(). The Program harness owns the event loop, render tick, signal handling, raw-mode setup, and alt-screen lifecycle β€” you only write Models.

Anatomy of a SugarCraft Model

A Model is three pure methods:

public function init(): ?\Closure; // optional startup Cmd (timers, fetch...)
public function update(Msg $msg): array; // [nextModel, ?Cmd]
public function view(): string; // current frame

The shape is borrowed verbatim from Bubble Tea / The Elm Architecture. State lives on the value object, transitions are pure functions, side effects (timers, HTTP, file I/O) get scheduled as Cmds rather than executed inline.

update() always returns a new Model rather than mutating $this. That's why the demo declares public readonly int $n β€” the only way to "change" the count is to construct a fresh Counter with the new value.

Common next steps

Want to... Reach for...
Add a text input sugarcraft/sugar-bits β€” TextInput
Show a spinner while loading sugarcraft/sugar-bits β€” Spinner
Render Markdown help text sugarcraft/candy-shine β€” Renderer
Tail a log into a scrollable pane sugarcraft/sugar-bits β€” Viewport
Build a multi-page wizard sugarcraft/sugar-prompt β€” Group
Plot a sparkline sugarcraft/sugar-charts β€” Sparkline
Make it ssh-accessible sugarcraft/candy-wish

Add the dep, import its classes, return them from view(). They're all pure renderers on the same Style-based vocabulary.

Testing

composer install
vendor/bin/phpunit

The included tests/CounterTest.php shows how to test update() deterministically by constructing Msg objects directly. No event loop, no terminal, no mocking β€” just call methods and assert the returned tuple.

Panic Handler (Optional)

SugarCraft supports an opt-in panic handler that catches uncaught exceptions and displays a styled backtrace when the app crashes. To enable it, uncomment the panic handler block in bin/start:

// use SugarCraft\Log\Log;
// Log::installPanicHandler();

This feature requires sugarcraft/candy-log as a dependency.

License

MIT.

Releases

No releases published

Packages

Contributors

Languages

AltStyle γ«γ‚ˆγ£γ¦ε€‰ζ›γ•γ‚ŒγŸγƒšγƒΌγ‚Έ (->γ‚ͺγƒͺγ‚ΈγƒŠγƒ«) /