Arguments

This commit is contained in:
2026-07-16 09:59:47 +02:00
parent 69e5c62382
commit 080e51526f
7 changed files with 182 additions and 49 deletions
-3
View File
@@ -3,9 +3,6 @@ all: build
build: build:
odin build src/ -out:TypoML odin build src/ -out:TypoML
run:
odin run src/
clean: clean:
rm -f TypoML rm -f TypoML
+25
View File
@@ -18,6 +18,31 @@ TypoML reads from stdin and outputs HTML to stdout:
cat input.tlm | ./TypoML > output.html cat input.tlm | ./TypoML > output.html
``` ```
It can also read one or more (added in the order of command line arguments) `.tlm` files:
```
./TypoML input.tlm > output.html
```
Run `./TypoML --help` for the full list of options.
!! Options
- `--title <text>` - Set the HTML document `<title>` (default: `TypoML`)
- `--plain` - Don't wrap the output in `<html>`, `<head>`, `<body>` and `<style>` tags
- `--no-js` - Don't include the JavaScript variable proxy
- `--no-wrapper` - Shortcut for `--plain` and `--no-js` at once
- `--print-tree` - Print the token tree instead of HTML
- `-h`, `--help` - Show the help text and exit
Examples:
```
./TypoML doc.tlm --title "TITLE" > doc.html
./TypoML doc.tlm --no-wrapper > fragment.html
./TypoML doc.tlm --print-tree
```
--- ---
!! Syntax !! Syntax
+1 -37
View File
@@ -1,39 +1,3 @@
#!/bin/sh #!/bin/sh
input=$(cat -) cat - > preview.html
input="${input#odin run src/}"
style="<style>$(cat styles.css)</style>"
doctype='<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">'
meta='<meta http-equiv="Content-Type" content="text/html; charset=utf-8">'
start="$doctype<html><head><title>TypoML Preview</title>$meta$style</head><body>"
script='
<script>
(function () {
var defs = {};
var spans = document.querySelectorAll("[data-tlm-def]");
for (var i = 0; i < spans.length; i++) {
var el = spans[i];
defs[el.dataset.tlmDef] = el.dataset.tlmValue;
}
var tlm = new Proxy({}, {
get: function (_, name) {
return defs[name];
},
set: function (_, name, value) {
defs[name] = value;
var refs = document.querySelectorAll("[data-tlm-var=\"" + name + "\"]");
for (var i = 0; i < refs.length; i++) {
refs[i].textContent = value;
}
return true;
},
ownKeys: function () {
return Object.keys(defs);
}
});
window.tlm = tlm;
})();
</script>'
end="$script</body></html>"
output="$start$input$end"
echo "$output" > preview.html
nohup xdg-open preview.html > /dev/null 2>&1 & nohup xdg-open preview.html > /dev/null 2>&1 &
+79 -5
View File
@@ -7,10 +7,26 @@ import "core:fmt"
import "core:os" import "core:os"
import "core:strings" import "core:strings"
read_stdin :: proc() -> []string { read_input :: proc(paths: []string) -> []string {
if len(paths) == 0 {
data, err := os.read_entire_file_from_file(os.stdin, context.allocator) data, err := os.read_entire_file_from_file(os.stdin, context.allocator)
content := string(data) content := string(data)
return strings.split_lines(content) return strings.split_lines(content)
}
b := strings.builder_make(context.allocator)
for path, i in paths {
data, err := os.read_entire_file(path, context.allocator)
if err != nil {
fmt.eprintf("typoml: cannot read file '%s': %v\n", path, err)
os.exit(1)
}
if i > 0 {
strings.write_string(&b, "\n")
}
strings.write_string(&b, string(data))
}
return strings.split_lines(strings.to_string(b))
} }
print_token :: proc(tok: ^token.Token, depth: int = 0) { print_token :: proc(tok: ^token.Token, depth: int = 0) {
@@ -116,8 +132,66 @@ print_token :: proc(tok: ^token.Token, depth: int = 0) {
} }
} }
main :: proc() { HELP_TEXT :: `Usage:
lines := read_stdin() TypoML [options] [file...]
parsed := parser.parse(lines)
renderer.print_html(&parsed) If there is no file provided, TypoML reads from stdin.
Options:
--title <text> Set the HTML document title (default: "TypoML")
--plain Don't wrap the output in <html>, <head>, <body> and <style> tags
--no-js Don't include the JavaScript variable proxy (<script>)
--no-wrapper Shortcut for --plain and --no-js at once
--print-tree Print the token tree instead of HTML
-h, --help Show this help and exit
`
parse_args :: proc(args: []string) -> (files: [dynamic]string, flags: renderer.DocumentFlags) {
for i := 0; i < len(args); i += 1 {
arg := args[i]
switch arg {
case "-h", "--help":
flags.help = true
case "--plain":
flags.plain = true
case "--no-js":
flags.no_js = true
case "--no-wrapper":
flags.plain = true
flags.no_js = true
case "--title":
if i + 1 < len(args) {
i += 1
flags.title = args[i]
}
case "--print-tree":
flags.print_tree = true
case:
if strings.has_prefix(arg, "--") {
fmt.eprintf("typoml: unknown option '%s'\n", arg)
os.exit(1)
}
append(&files, arg)
}
}
return
}
main :: proc() {
files, flags := parse_args(os.args[1:])
if flags.help {
fmt.print(HELP_TEXT)
return
}
lines := read_input(files[:])
parsed := parser.parse(lines)
if flags.print_tree {
print_token(&parsed)
return
}
renderer.print_document(&parsed, flags)
} }
+69
View File
@@ -66,6 +66,75 @@ render_media_object :: proc(tok: ^token.Token, mime_type: string) {
fmt.print("</object>\n") fmt.print("</object>\n")
} }
TEMPLATE_PROXY_SCRIPT :: `
<script>
(function () {
var defs = {};
var spans = document.querySelectorAll("[data-tlm-def]");
for (var i = 0; i < spans.length; i++) {
var el = spans[i];
defs[el.dataset.tlmDef] = el.dataset.tlmValue;
}
var tlm = new Proxy({}, {
get: function (_, name) {
return defs[name];
},
set: function (_, name, value) {
defs[name] = value;
var refs = document.querySelectorAll("[data-tlm-var=\"" + name + "\"]");
for (var i = 0; i < refs.length; i++) {
refs[i].textContent = value;
}
return true;
},
ownKeys: function () {
return Object.keys(defs);
}
});
window.tlm = tlm;
})();
</script>`
print_document :: proc(root: ^token.Token, flags: DocumentFlags) {
if flags.plain {
for child in root.children {
print_html(child)
}
return
}
doctype := "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">"
meta := "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">"
style := "<style>" + DEFAULT_STYLE + "</style>"
title := flags.title
if title == "" {
title = "TypoML"
}
fmt.printf(
"%s\n<html><head><title>%s</title>%s%s</head>\n<body>\n",
doctype,
escape_html(title),
meta,
style,
)
for child in root.children {
print_html(child)
}
if !flags.no_js {
fmt.print("\n" + TEMPLATE_PROXY_SCRIPT + "\n")
}
fmt.print("</body></html>\n")
}
DocumentFlags :: struct {
plain: bool,
no_js: bool,
title: string,
print_tree: bool,
help: bool,
}
print_html :: proc(tok: ^token.Token) { print_html :: proc(tok: ^token.Token) {
switch tok.type { switch tok.type {
case token.TokenType.Root: case token.TokenType.Root:
+4
View File
@@ -1,3 +1,6 @@
package renderer
DEFAULT_STYLE :: `
body { body {
font-family: Georgia, "Times New Roman", Times, serif; font-family: Georgia, "Times New Roman", Times, serif;
color: #e0e0e0; color: #e0e0e0;
@@ -72,3 +75,4 @@ hr.footnotes-sep {
.footnote a { .footnote a {
text-decoration: none; text-decoration: none;
} }
`
+1 -1
View File
@@ -1 +1 @@
clear && make format && cat README.tlm | make run | ./preview clear && make format && make build && ./TypoML README.tlm --title "TypoML Preview" | ./preview