Skip to content

Instantly share code, notes, and snippets.

@anthonyrisinger
Created September 26, 2025 03:44
Show Gist options
  • Save anthonyrisinger/dfcd8a534a974e38160b5d45cc0cc066 to your computer and use it in GitHub Desktop.
Save anthonyrisinger/dfcd8a534a974e38160b5d45cc0cc066 to your computer and use it in GitHub Desktop.
The `flow-tool.go` is a testing and development utility and fake-streaming markdown renderer that generates, processes, and analyzes markdown content through Glamour. It supports flexible markdown primitive generation with customizable repetition and spacing, simulates various streaming modes (unbuffered, buffered, windowed) with artificial dela…
package main
import (
"bufio"
"flag"
"fmt"
"io"
"math/rand"
"os"
"slices"
"strconv"
"strings"
"time"
"github.com/charmbracelet/glamour"
"github.com/pmezard/go-difflib/difflib"
)
const GlamourBlank = " \n"
type Config struct {
Raw, Hex, Blanks, Diffs bool
Style, Arg1, Arg2, Arg3 string
Width, Flow, Repeat int
}
type Tool struct {
renderer *glamour.TermRenderer
config Config
}
func NewTool(config Config) (*Tool, error) {
renderer, err := glamour.NewTermRenderer(
glamour.WithWordWrap(config.Width),
glamour.WithStylePath(config.Style),
)
if err != nil {
return nil, err
}
return &Tool{renderer: renderer, config: config}, nil
}
// Primitive content templates
func (t *Tool) primitiveContent() map[string]string {
return map[string]string{
"text": "Hello world %d_%d",
"paragraph": "This is a paragraph with multiple words and the number %d_%d.",
"header": "# Header %d_%d",
"header1": "# Header %d_%d",
"header2": "## Header %d_%d",
"list": "- List item %d_%d",
"olist": "1. List item %d_%d",
"code": "```go\nfunc test_%d_%d() { return nil }\n```",
"inline": "Text with `code%d_%d` inside",
"blockquote": "> Quote from %d_%d",
"table": "| A | B |\n|---|---|\n| 0 | %d_%d |",
"table2": "| Col%d | Col%d | ColN |\n|------|------|------|\n| A1 | B1 | C1 |\n| A2 | B2 | C2 |",
"link": "[ref%d_%d]: https://example.com/",
"hrule": "---",
"bold": "**Bold text %d_%d**",
"italic": "*Italic text %d_%d*",
"strike": "~~Strike text %d_%d~~",
"emoji": "🚀 Rocket emoji %d_%d",
"checklist": "- [x] Done (%d_%d)\n- [ ] Todo (0)",
"yaml": "---\nkey%d_%d: value\n---",
"json": "```json\n{\"key%d_%d\": \"value\"}\n```",
"longtext": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat (%d_%d).",
"mixedblock": "> Quote from %d_%d\n\n- List item\n\n```\ncode\n```",
"empty": "",
"arg1": t.config.Arg1,
"arg2": t.config.Arg2,
"arg3": t.config.Arg3,
}
}
// Parse primitive with modifiers: name@count with optional spacing modifiers (--)
func parsePrimitive(primitive string) (name string, count int, spacing int) {
name, count, spacing = primitive, 1, 2
// Handle spacing modifiers
for range 3 {
if !strings.HasSuffix(name, "-") {
break
}
name = strings.TrimSuffix(name, "-")
spacing--
}
// Handle count modifier
if parts := strings.Split(name, "@"); len(parts) == 2 {
if n, err := strconv.Atoi(parts[1]); err == nil && n > 0 {
name, count = parts[0], n
}
}
return
}
// Generate markdown content from primitives
func (t *Tool) generateMarkdown(primitives []string) (string, error) {
var result strings.Builder
templates := t.primitiveContent()
// Cap infinite mode at 10000 iterations to prevent infinite memory growth
maxRepeat := t.config.Repeat
if maxRepeat == -1 {
maxRepeat = 10000
}
for seqNum := range maxRepeat {
needsSeqSep := false
for _, primitive := range primitives {
name, count, spacing := parsePrimitive(primitive)
template, exists := templates[name]
if !exists {
return "", fmt.Errorf("Unknown primitive specified: %s", name)
}
for i := range count {
if name == "arg1" || name == "arg2" || name == "arg3" {
result.WriteString(template)
} else if strings.Contains(template, "%d") {
fmt.Fprintf(&result, template, seqNum+1, i+1)
} else {
result.WriteString(template)
}
// Add spacing between iterations within same primitive
if i < count-1 {
switch spacing {
case 2:
result.WriteString("\n\n")
case 1:
result.WriteString("\n")
case 0:
result.WriteString(" ")
}
}
needsSeqSep = true
}
// Add spacing after primitive
if spacing == 2 {
result.WriteString("\n\n")
} else {
result.WriteString("\n")
}
}
// Add spacing between sequence repetitions
if (t.config.Repeat == -1 || seqNum < t.config.Repeat-1) && needsSeqSep {
result.WriteString("\n\n")
}
}
return result.String(), nil
}
// Read input from file, stdin, or generate from primitives
func (t *Tool) getInput(args []string) (input, source string, err error) {
if len(args) > 0 && !t.isPrimitive(args[0]) {
// File input
content, err := os.ReadFile(args[0])
if err != nil {
return "", "", err
}
return string(content), "FILE", nil
}
if len(args) == 0 {
// No args provided - read from stdin (deadman switch handles timeout)
var result strings.Builder
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
result.WriteString(scanner.Text() + "\n")
}
return result.String(), "PIPED", scanner.Err()
}
if len(args) > 0 {
// Generated from primitives
output, err := t.generateMarkdown(args)
if err != nil {
return "", "", err
}
return output, "GENERATED", nil
}
return "", "", fmt.Errorf("no input provided")
}
// Process input: apply --raw flag decision
func (t *Tool) processInput(input string) (string, error) {
if t.config.Raw {
return input, nil
}
return t.renderer.Render(input)
}
// Stream output with flow control and delays
// NOTE: This implements "fake streaming" - content is pre-generated in memory,
// then artificially chunked and delayed to simulate real streaming for testing
func (t *Tool) streamOutput(w io.Writer, content string, keepalive chan<- struct{}) {
if t.config.Flow == 0 {
// Direct output (no streaming, no delay)
fmt.Fprint(w, content)
// Signal keepalive after successful write
sendKeepalive(keepalive)
return
}
if t.config.Flow == -1 {
// Line-by-line streaming with random microsecond delays
lines := strings.Split(content, "\n")
for i, line := range lines {
if i == len(lines)-1 && line == "" {
// Don't print final empty line from split
break
}
fmt.Fprint(w, line+"\n")
if flusher, ok := w.(interface{ Flush() error }); ok {
flusher.Flush()
}
// Signal keepalive after each successful line output
sendKeepalive(keepalive)
// Random delay like sleep 0.0$RANDOM (0-9999 microseconds)
if i < len(lines)-1 {
time.Sleep(time.Duration(rand.Intn(10000)) * time.Microsecond)
}
}
return
}
// Buffered streaming with proportional delays
data := []byte(content)
bufSize := t.config.Flow
for i := 0; i < len(data); i += bufSize {
end := min(i+bufSize, len(data))
fmt.Fprint(w, string(data[i:end]))
if flusher, ok := w.(interface{ Flush() error }); ok {
flusher.Flush()
}
// Signal keepalive after each successful chunk output
sendKeepalive(keepalive)
// Delay proportional to buffer size
if end < len(data) {
time.Sleep(time.Duration(t.config.Flow) * 50 * time.Microsecond)
}
}
}
// Show hex dump in xxd-style format
func (t *Tool) showHex(content string) {
data := []byte(content)
for i := 0; i < len(data); i += 16 {
// Address
fmt.Printf("%08x: ", i)
// Hex bytes (in groups of 2)
for j := range 16 {
if i+j < len(data) {
fmt.Printf("%02x", data[i+j])
} else {
fmt.Print(" ")
}
if j%2 == 1 {
fmt.Print(" ")
}
}
// ASCII representation
fmt.Print(" ")
for j := 0; j < 16 && i+j < len(data); j++ {
b := data[i+j]
if b >= 32 && b <= 126 {
fmt.Printf("%c", b)
} else {
fmt.Print(".")
}
}
fmt.Print("\n")
}
}
// Show unified diff
func (t *Tool) showDiff(label, input, output string) {
diff := difflib.UnifiedDiff{
A: difflib.SplitLines(input),
B: difflib.SplitLines(output),
FromFile: "a/" + label,
ToFile: "b/" + label,
Context: 3,
}
text, _ := difflib.GetUnifiedDiffString(diff)
if text != "" {
fmt.Print(text)
}
}
// Get hex string representation (like showHex but returns string)
func (t *Tool) getHexString(content string) string {
var result strings.Builder
data := []byte(content)
for i := 0; i < len(data); i += 16 {
// Address
result.WriteString(fmt.Sprintf("%08x: ", i))
// Hex bytes (in groups of 2)
for j := 0; j < 16; j++ {
if i+j < len(data) {
result.WriteString(fmt.Sprintf("%02x", data[i+j]))
} else {
result.WriteString(" ")
}
if j%2 == 1 {
result.WriteString(" ")
}
}
// ASCII representation
result.WriteString(" ")
for j := 0; j < 16 && i+j < len(data); j++ {
b := data[i+j]
if b >= 32 && b <= 126 {
result.WriteString(fmt.Sprintf("%c", b))
} else {
result.WriteString(".")
}
}
result.WriteString("\n")
}
return result.String()
}
// Generate analysis metrics
func (t *Tool) analyzeOutput(output string) (leading, trailing, blanks, lines int) {
if strings.HasPrefix(output, "\n") {
leading = 1
}
if strings.HasSuffix(output, "\n") {
trailing = 1
}
blanks = strings.Count(output, GlamourBlank)
lines = strings.Count(output, "\n")
return
}
// Check if string is a known primitive
func (t *Tool) isPrimitive(arg string) bool {
name := arg
for strings.HasSuffix(name, "-") {
name = strings.TrimRight(name, "-")
}
if parts := strings.Split(name, "@"); len(parts) > 0 {
name = parts[0]
}
primitives := []string{
"text", "paragraph", "header", "header1", "header2", "list", "olist",
"code", "inline", "blockquote", "table", "table2", "link", "hrule",
"bold", "italic", "strike", "emoji", "checklist", "yaml", "json",
"longtext", "mixedblock", "empty", "arg1", "arg2", "arg3",
}
return slices.Contains(primitives, name)
}
// Send keepalive signal to reset deadman switch timer
func sendKeepalive(ch chan<- struct{}) {
select {
case ch <- struct{}{}:
default:
}
}
// Initialize deadman switch that kills process after 2 seconds of no progress
func initDeadmanSwitch() chan<- struct{} {
keepalive := make(chan struct{}, 1)
go func() {
ticker := time.NewTicker(2 * time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
os.Exit(124)
case <-keepalive:
ticker.Reset(2 * time.Second)
}
}
}()
return keepalive
}
func main() {
// Initialize deadman switch for timeout protection
keepalive := initDeadmanSwitch()
// Flag definitions
blanks := flag.Bool("b", false, "Show blank count analysis only")
diffs := flag.Bool("d", false, "Show input/output differences only")
raw := flag.Bool("r", false, "Show raw markdown (skip glamour)")
hex := flag.Bool("x", false, "Show hex dump")
style := flag.String("s", "notty", "Glamour style (notty, dark, light, auto)")
repeat := flag.Int("n", 1, "Repeat sequence N times (-1 for infinite)")
width := flag.Int("w", 0, "Set render width")
flow := flag.Int("f", 0, "Stream output (0=direct, -1=lines, N=buffer size)")
arg1 := flag.String("1", "", "Custom argument 1")
arg2 := flag.String("2", "", "Custom argument 2")
arg3 := flag.String("3", "", "Custom argument 3")
help := flag.Bool("h", false, "Show help")
flag.Parse()
if *help {
fmt.Print(`GLOW FLOW STRESS TESTER - Generate markdown for glow streaming validation
MODES:
-r Show raw markdown (skip glamour)
-b Show blank count analysis only
-d Show input/output differences only
-x Show hex dump
-w=N Set render width (default: no wrap)
-n=N Repeat sequence N times (-1 for infinite)
-f=N Stream output (0=direct, -1=lines, N=buffer)
SPACING CONTROL:
primitive Normal spacing (\n\n between primitives)
primitive- Single spacing (\n between primitives)
primitive-- Space joiner within @N iterations
primitive--- No joiner within @N iterations
ITERATIONS:
primitive@N Generate N labeled iterations of primitive
text@5 → Hello world 1_1\n\nHello world 1_2\n\n... (double newlines)
text@5- → Hello world 1_1\nHello world 1_2\n... (single newlines)
text@5-- → Hello world 1_1 Hello world 1_2 ... (space joiners)
text@5--- → Hello world 1_1Hello world 1_2... (no joiners)
PRIMITIVES:
text, paragraph, header, header1, header2, list, olist
code, inline, blockquote, table, table2, link, hrule
bold, italic, strike, emoji, checklist, yaml, json
longtext, mixedblock, empty, arg1, arg2, arg3
EXAMPLES:
echo '#Test' | flow-tool -r -x
flow-tool header@1000 | glow --flow=100 -
flow-tool -n=-1 text@3-- header- | head -20
flow-tool text@100-- list@50-- | glow --flow=64 -
`)
return
}
// Validate analysis flags (only one allowed)
analysisCount := 0
for _, f := range []*bool{blanks, diffs} {
if *f {
analysisCount++
}
}
if analysisCount > 1 {
fmt.Println("Error: Multiple analysis filters specified (choose one of -b, -d)")
return
}
// Create tool
config := Config{
Raw: *raw, Hex: *hex, Blanks: *blanks, Diffs: *diffs,
Style: *style, Arg1: *arg1, Arg2: *arg2, Arg3: *arg3,
Width: *width, Flow: *flow, Repeat: *repeat,
}
tool, err := NewTool(config)
if err != nil {
fmt.Printf("Error creating tool: %v\n", err)
return
}
// PHASE 1: INPUT
input, source, err := tool.getInput(flag.Args())
if err != nil {
fmt.Printf("Error getting input: %v\n", err)
flag.Usage()
return
}
// PHASE 2: PROCESSING
output, err := tool.processInput(input)
if err != nil {
fmt.Printf("Error processing: %v\n", err)
return
}
// PHASE 3: OUTPUT
// Diffs mode - always compares input vs glamour (ignores --raw)
if *diffs {
glamourOutput, err := tool.renderer.Render(input)
if err != nil {
fmt.Printf("Error rendering for diff: %v\n", err)
return
}
if *hex {
// Hex diff mode - diff the hex representations
tool.showDiff(source+" (hex)", tool.getHexString(input), tool.getHexString(glamourOutput))
return
}
// Regular diff mode
tool.showDiff(source, input, glamourOutput)
}
// Hex mode - can work with any output (non-diff)
if *hex {
tool.showHex(output)
return
}
// Blanks mode - analyze blank metrics
if *blanks {
// Always analyze the processed output (raw or glamour as determined by Phase 2)
leading, trailing, blanks, lines := tool.analyzeOutput(output)
fmt.Printf("%d %d %d %d\n", leading, trailing, blanks, lines)
return
}
// Default: direct output mode
tool.streamOutput(os.Stdout, output, keepalive)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment