#!/usr/bin/env bash # Usage: scripts/view [file.mmd] [-- extra cargo run args...] # cat file.mmd | scripts/view [-- extra cargo run args...] # # Defaults: -f svg --edge-preset step # Override any default by passing it explicitly after -- # Set MMDFLUX_VIEW_RENDERER=chafa or MMDFLUX_VIEW_RENDERER=kitty to force a renderer. # Otherwise the script prefers chafa when installed, then falls back to kitten+rsvg-convert. # # Examples: # scripts/view tests/fixtures/flowchart/simple.mmd # scripts/view tests/fixtures/flowchart/simple.mmd -- --edge-preset basis # cat file.mmd | scripts/view set -euo pipefail # Keep view as the dev entrypoint, but let the CLI own terminal theme probing so # the rendering contract stays in one place. MMD_FORMAT_DEFAULT=(--format svg) MMD_EDGE_PRESET_DEFAULT=(--edge-preset step) MMD_THEME_DEFAULT=(--svg-theme-auto) # Split args: optional file, then optional -- extra-flags FILE="" EXTRA_ARGS=() if [[ $# -gt 0 && "$1" != "--" && -f "$1" ]]; then FILE="$1" shift fi if [[ $# -gt 0 && "$1" == "--" ]]; then shift EXTRA_ARGS=("$@") fi VIEW_RENDERER="${MMDFLUX_VIEW_RENDERER:-auto}" MERGED_ARGS=() has_any_flag() { local needle for needle in "$@"; do for extra in "${EXTRA_ARGS[@]+"${EXTRA_ARGS[@]}"}"; do if [[ "$extra" == "$needle" || "$extra" == "$needle="* ]]; then return 0 fi done done return 1 } if ! has_any_flag -f --format; then MERGED_ARGS+=("${MMD_FORMAT_DEFAULT[@]}") fi if ! has_any_flag --edge-preset; then MERGED_ARGS+=("${MMD_EDGE_PRESET_DEFAULT[@]}") fi if ! has_any_flag --svg-theme --svg-theme-auto; then MERGED_ARGS+=("${MMD_THEME_DEFAULT[@]}") fi # Run the pipeline if [[ -n "$FILE" ]]; then INPUT_CMD=(cat "$FILE") else INPUT_CMD=(cat) fi kitty_target_raster_size() { local window_size width height target_width target_height window_size="$(kitten icat --print-window-size 2>/dev/null || true)" width="${window_size%%x*}" height="${window_size##*x}" if [[ "$width" =~ ^[0-9]+$ ]] && [[ "$height" =~ ^[0-9]+$ ]] && (( width > 0 )) && (( height > 0 )); then # Oversample to give icat a denser raster to downscale. Cap the raster # size so very large HiDPI displays do not create excessive images. target_width=$(( width * 2 )) target_height=$(( height * 2 )) if (( target_width > 4096 )); then target_width=4096 fi if (( target_height > 4096 )); then target_height=4096 fi printf '%s %s\n' "$target_width" "$target_height" return 0 fi return 1 } command_exists() { command -v "$1" >/dev/null 2>&1 } resolve_view_renderer() { case "$VIEW_RENDERER" in auto) if command_exists chafa; then printf '%s\n' chafa elif command_exists kitten && command_exists rsvg-convert; then printf '%s\n' kitty else echo "scripts/view: no supported renderer found; install chafa or both kitten and rsvg-convert" >&2 exit 1 fi ;; chafa) if ! command_exists chafa; then echo "scripts/view: MMDFLUX_VIEW_RENDERER=chafa requires chafa to be installed" >&2 exit 1 fi printf '%s\n' chafa ;; kitty) if ! command_exists kitten || ! command_exists rsvg-convert; then echo "scripts/view: MMDFLUX_VIEW_RENDERER=kitty requires both kitten and rsvg-convert" >&2 exit 1 fi printf '%s\n' kitty ;; *) echo "scripts/view: unsupported MMDFLUX_VIEW_RENDERER=$VIEW_RENDERER (expected auto, chafa, or kitty)" >&2 exit 1 ;; esac } VIEW_RENDERER="$(resolve_view_renderer)" if [[ "$VIEW_RENDERER" == "kitty" ]]; then KITTEN_WIDTH="" KITTEN_HEIGHT="" if KITTEN_SIZE="$(kitty_target_raster_size || true)"; then KITTEN_WIDTH="${KITTEN_SIZE%% *}" KITTEN_HEIGHT="${KITTEN_SIZE##* }" fi RSVG_ARGS=() if [[ -n "$KITTEN_WIDTH" && -n "$KITTEN_HEIGHT" ]]; then RSVG_ARGS=(--width "$KITTEN_WIDTH" --height "$KITTEN_HEIGHT" --keep-aspect-ratio) fi "${INPUT_CMD[@]}" \ | cargo run -q -- "${MERGED_ARGS[@]}" ${EXTRA_ARGS[@]+"${EXTRA_ARGS[@]}"} \ | rsvg-convert "${RSVG_ARGS[@]}" \ | kitten icat --stdin=yes --fit=both --scale-up else "${INPUT_CMD[@]}" \ | cargo run -q -- "${MERGED_ARGS[@]}" ${EXTRA_ARGS[@]+"${EXTRA_ARGS[@]}"} \ | chafa fi