scripts/pod_parse

pod-parser-0.0.2 source code

Package

Name
pod-parser
Version
0.0.2
Uploaded
2026-05-28 14:18:09
Dependencies
Metadata
zuzu-distribution.json
Archive
Download .tar.gz
#!/usr/bin/env zuzu

from pod/ansi import PodANSI;
from pod/html import PodHTML;
from pod/markdown import PodMarkdown;
from pod/parser import parse_pod;
from std/getopt import Getopt;
from std/io import Path, STDIN, STDOUT, STDERR;
from std/string import ends_with, join, split, substr;

function _usage () {
	return join( "\n", [
		"Usage: pod_parse [options] [file|-]",
		"",
		"Options:",
		"  -f, --format FORMAT  Output format: ansi, markdown, or html",
		"  -w, --width WIDTH    ANSI output width, default 80",
		"  -o, --output FILE    Write output to FILE instead of STDOUT",
		"  -I, --include PATH   Prepend a module search path",
		"  -M, --module         Read input as a module name from include paths",
		"  -h, --help           Show this help",
	] ) _ "\n";
}

function _read_stdin () {
	let chunks := [];
	while ( true ) {
		let line := STDIN.next_line();
		last if line == null;
		chunks.push(line);
	}
	return join( "", chunks );
}

function _is_windows_platform () {
	if ( "platform" in __system__ ) {
		let platform := lc( "" _ __system__.get("platform") );
		return platform eq "windows" or platform eq "mswin32";
	}
	return false;
}

function _preprocess_argv ( argv ) {
	let out := [];
	for ( let arg in argv ) {
		let text := "" _ arg;
		if ( length text > 2 and substr( text, 0, 2 ) eq "-I" ) {
			out.push("-I");
			out.push( substr( text, 2 ) );
		}
		else {
			out.push(text);
		}
	}
	return out;
}

function _system_include_paths () {
	if ( "inc" in __system__ ) {
		let inc := __system__.get("inc");
		return [] if inc == null;
		if ( typeof inc != "Array" ) {
			let separator := _is_windows_platform() ? ";" : ":";
			return split( "" _ inc, separator );
		}
		return inc;
	}
	return [];
}

function _include_paths ( extra ) {
	let out := [];
	if ( extra instanceof Array ) {
		for ( let path in extra ) {
			out.push( "" _ path );
		}
	}
	else if ( extra != null ) {
		out.push( "" _ extra );
	}

	for ( let path in _system_include_paths() ) {
		out.push( "" _ path );
	}
	return out;
}

function _module_path ( String module_name, includes ) {
	let relative := ends_with( module_name, ".zzm" )
		? module_name
		: module_name _ ".zzm";

	for ( let root in _include_paths(includes) ) {
		next if root eq "";
		let path := ( new Path(root) ).child(relative);
		return path if path.exists() and path.is_file();
	}
	return null;
}

function _read_module ( argv, includes ) {
	if ( argv.length() != 1 ) {
		die "pod_parse: -M expects exactly one module name";
	}

	let module_name := "" _ argv[0];
	let path := _module_path( module_name, includes );
	if ( path == null ) {
		die "pod_parse: module not found in module search paths: " _ module_name;
	}
	return path.slurp_utf8();
}

function _read_input ( argv, Boolean module_mode, includes ) {
	if ( module_mode ) {
		return _read_module( argv, includes );
	}
	if ( argv.length() == 0 or argv[0] eq "-" ) {
		return _read_stdin();
	}
	if ( argv.length() > 1 ) {
		die "pod_parse: expected at most one input file";
	}
	return ( new Path(argv[0]) ).slurp_utf8();
}

function _render ( doc, String format, Number width ) {
	if ( format eqi "ansi" or format eqi "text" ) {
		return ( new PodANSI( width: width ) ).render(doc) _ "\n";
	}
	if ( format eqi "markdown" or format eqi "md" ) {
		return ( new PodMarkdown() ).render(doc) _ "\n";
	}
	if ( format eqi "html" ) {
		return ( new PodHTML() ).render(doc) _ "\n";
	}
	die "pod_parse: format must be ansi, markdown, or html";
}

function _run ( argv ) {
	let parsed := Getopt.parse(
		_preprocess_argv(argv),
		[
			"help|h",
			"format|f=s",
			"width|w=i",
			"output|o=s",
			"include|I=s@",
			"module|M",
		],
	);
	if ( not parsed{ok} ) {
		STDERR.say(parsed{error});
		STDERR.print(_usage());
		return 2;
	}

	let opts := parsed{options};
	if ( opts{help} ) {
		STDOUT.print(_usage());
		return 0;
	}

	let format := opts{format} == null ? "ansi" : lc( "" _ opts{format} );
	let width := opts{width} == null ? 80 : opts{width};
	if ( width < 1 ) {
		die "pod_parse: width must be a positive integer";
	}

	let input := _read_input(
		parsed{argv},
		opts{module} ? true : false,
		opts{include},
	);
	let doc := parse_pod(input);
	let output := _render( doc, format, width );

	if ( opts{output} != null ) {
		( new Path( "" _ opts{output} ) ).spew_utf8(output);
	}
	else {
		STDOUT.print(output);
	}

	return 0;
}

function __main__ ( argv ) {
	try {
		return _run(argv);
	}
	catch ( Exception e ) {
		STDERR.say(e{message});
		return 1;
	};
}