PHP port of charmbracelet/glow β a Markdown CLI viewer that composes CandyShine (rendering) and SugarBits Viewport (scrolling).
composer require sugarcraft/sugar-glowsugarglow README.md # render to stdout (default)
sugarglow -p README.md # open in a fullscreen pager
git log -1 --pretty=%B | sugarglow -p # pipe stdin
sugarglow --theme dracula README.md
sugarglow --width 80 --no-hyperlinks README.md
sugarglow --theme-config ./my-theme.json README.mdFlags:
--theme {ansi|plain|dark|light|notty|dracula|tokyo-night|pink|solarized|monokai|github}β picks a CandyShine preset.solarized,monokai, andgithubload JSON theme files fromthemes/.--style/-sβ alias for--theme(glamour-compat).--theme-config <path>β load a custom JSON theme viaTheme::fromJson. Overrides--theme.--width/-w <N>β word-wrap paragraphs / blockquotes / list bodies. 0 = no wrap.--no-hyperlinksβ disable OSC 8 link envelopes; render links astext (url)instead.--pager/-pβ open in a fullscreen pager.
Standard reader keys come from Viewport:
| Key | Action |
|---|---|
β / k |
line up |
β / j |
line down |
PgUp / b |
page up |
PgDn / space / f |
page down |
Ctrl+U / Ctrl+D |
half page |
Home / g |
top |
End / G |
bottom |
q / Esc / Ctrl+C |
exit |
Beyond the CLI, sugar-glow exposes three utility classes for integrating its behaviour into other PHP projects.
Loads and parses Glamour-style theme JSON files (block_prefix/suffix, indent_token, margin, chroma token mapping).
use SugarCraft\Glow\GlamourTheme;
// From a JSON string
$theme = GlamourTheme::fromJson(file_get_contents('./my-theme.json'));
// From a file path
$theme = GlamourTheme::fromFile('./my-theme.json');
// Resolve a chroma token to an SGR color code (e.g., "31" for red)
$sgr = $theme->resolve('emphasis'); // => "31" or nullFile watching via mtime polling β works cross-platform with no extensions.
use SugarCraft\Glow\FileWatcher;
$watcher = new FileWatcher('/path/to/file.md');
// Check if modified since a given mtime
if ($watcher->hasChangedSince($lastMtime)) {
// re-render
}
// Generator-based watch loop (e.g., in a ReactPHP stream)
foreach (FileWatcher::watch('/path/to/file.md', 500) as $changed) {
// $changed === true each time the file is modified
}CJK and emoji width handling lives in SugarCraft\Core\Util\Width. Use it
directly for visual truncation, padding, and ANSI-aware measurement:
use SugarCraft\Core\Util\Width;
Width::string('hello'); // 5
Width::string('δ½ ε₯½'); // 4 (full-width)
Width::string('π¦'); // 2 (emoji)
Width::padRight('hi', 8); // "hi "
Width::truncate('hello world', 8); // "hello wo"cd sugar-glow && composer install && vendor/bin/phpunit
