Odin rewrite #1
@@ -1,8 +0,0 @@
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.v]
|
||||
indent_style = tab
|
||||
@@ -1,8 +0,0 @@
|
||||
* text=auto eol=lf
|
||||
*.bat eol=crlf
|
||||
|
||||
*.v linguist-language=V
|
||||
*.vv linguist-language=V
|
||||
*.vsh linguist-language=V
|
||||
v.mod linguist-language=V
|
||||
.vdocignore linguist-language=ignore
|
||||
+1
-26
@@ -1,27 +1,2 @@
|
||||
# Binaries for programs and plugins
|
||||
main
|
||||
TypoML
|
||||
*.exe
|
||||
*.exe~
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Ignore binary output folders
|
||||
bin/
|
||||
|
||||
# Ignore common editor/system specific metadata
|
||||
.DS_Store
|
||||
.idea/
|
||||
.vscode/
|
||||
*.iml
|
||||
|
||||
# ENV
|
||||
.env
|
||||
|
||||
# Web assets and local databases
|
||||
*.db
|
||||
*.js
|
||||
|
||||
# Ignore installed modules through `v install --local`:
|
||||
modules/
|
||||
src.bin
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
all: build
|
||||
|
||||
build:
|
||||
v src/
|
||||
odin build src/ -out:TypoML
|
||||
|
||||
run:
|
||||
v run src/
|
||||
odin run src/
|
||||
|
||||
clean:
|
||||
rm -f TypoML
|
||||
|
||||
format:
|
||||
v fmt -w src/
|
||||
odinfmt -w src/
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#!/bin/sh
|
||||
input=$(cat -)
|
||||
input="${input#v run src/}"
|
||||
input="${input#odin run src/}"
|
||||
style="<style>$(cat styles.css)</style>"
|
||||
start="<html><head><title>TypoML Preview</title>$style</head><body>"
|
||||
end="</body></html>"
|
||||
output="$start$input$end"
|
||||
echo "$output" > /tmp/preview.html
|
||||
xdg-open /tmp/preview.html
|
||||
|
||||
|
||||
+374
@@ -0,0 +1,374 @@
|
||||
package main
|
||||
|
||||
import "core:strings"
|
||||
|
||||
get_ext :: proc(url: string) -> string {
|
||||
clean := url
|
||||
if question := strings.index_byte(clean, '?'); question != -1 {
|
||||
clean = clean[:question]
|
||||
}
|
||||
if hash := strings.index_byte(clean, '#'); hash != -1 {
|
||||
clean = clean[:hash]
|
||||
}
|
||||
if dot := strings.last_index_byte(clean, '.'); dot != -1 {
|
||||
return strings.to_lower(clean[dot:], context.temp_allocator)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
detect_type :: proc(url: string) -> string {
|
||||
ext := get_ext(url)
|
||||
switch ext {
|
||||
case ".jpg",
|
||||
".jpeg",
|
||||
".jpe",
|
||||
".jfif",
|
||||
".jif",
|
||||
".pjpeg",
|
||||
".pjp",
|
||||
".png",
|
||||
".apng",
|
||||
".gif",
|
||||
".webp",
|
||||
".avif",
|
||||
".heic",
|
||||
".heif",
|
||||
".hif",
|
||||
".bmp",
|
||||
".dib",
|
||||
".tif",
|
||||
".tiff",
|
||||
".ico",
|
||||
".cur",
|
||||
".svg",
|
||||
".svgz",
|
||||
".raw",
|
||||
".cr2",
|
||||
".cr3",
|
||||
".nef",
|
||||
".nrw",
|
||||
".orf",
|
||||
".sr2",
|
||||
".arw",
|
||||
".srf",
|
||||
".rw2",
|
||||
".pef",
|
||||
".raf",
|
||||
".dng",
|
||||
".3fr",
|
||||
".ari",
|
||||
".bay",
|
||||
".cap",
|
||||
".dcr",
|
||||
".erf",
|
||||
".fff",
|
||||
".iiq",
|
||||
".k25",
|
||||
".kdc",
|
||||
".mdc",
|
||||
".mos",
|
||||
".mrw",
|
||||
".obm",
|
||||
".ptx",
|
||||
".pxn",
|
||||
".r3d",
|
||||
".rwl",
|
||||
".rwz",
|
||||
".srw",
|
||||
".x3f",
|
||||
".gpr",
|
||||
".pgm",
|
||||
".ppm",
|
||||
".pbm",
|
||||
".pnm",
|
||||
".pam",
|
||||
".pfm",
|
||||
".tga",
|
||||
".icb",
|
||||
".vda",
|
||||
".vst",
|
||||
".pcx",
|
||||
".xbm",
|
||||
".xpm",
|
||||
".xwd",
|
||||
".sgi",
|
||||
".rgb",
|
||||
".rgba",
|
||||
".bw",
|
||||
".jp2",
|
||||
".j2k",
|
||||
".j2c",
|
||||
".jpf",
|
||||
".jpx",
|
||||
".jpm",
|
||||
".mj2",
|
||||
".wbmp",
|
||||
".emf",
|
||||
".wmf",
|
||||
".eps",
|
||||
".epsi",
|
||||
".epsf",
|
||||
".psd",
|
||||
".psb",
|
||||
".ai",
|
||||
".cdr",
|
||||
".xcf",
|
||||
".gbr",
|
||||
".gih",
|
||||
".pat",
|
||||
".art",
|
||||
".jxl",
|
||||
".jxr",
|
||||
".wdp",
|
||||
".hdp",
|
||||
".exr",
|
||||
".hdr",
|
||||
".dpx",
|
||||
".cin",
|
||||
".fits",
|
||||
".fit",
|
||||
".fts",
|
||||
".icns",
|
||||
".flif",
|
||||
".dds",
|
||||
".ktx",
|
||||
".ktx2",
|
||||
".astc",
|
||||
".kodak",
|
||||
".fpx",
|
||||
".pcd",
|
||||
".cmx",
|
||||
".drw",
|
||||
".cgm",
|
||||
".plt",
|
||||
".hpgl",
|
||||
".iff",
|
||||
".ilbm",
|
||||
".lbm",
|
||||
".mac",
|
||||
".msp",
|
||||
".pct",
|
||||
".pic",
|
||||
".pict",
|
||||
".pntg",
|
||||
".qtif",
|
||||
".qti",
|
||||
".ras",
|
||||
".sun",
|
||||
".tpic",
|
||||
".wpg",
|
||||
".g3",
|
||||
".g4",
|
||||
".dcm",
|
||||
".dicom",
|
||||
".ora",
|
||||
".kra",
|
||||
".clip":
|
||||
return "image"
|
||||
case ".mp3",
|
||||
".mp2",
|
||||
".mp1",
|
||||
".mpa",
|
||||
".mpga",
|
||||
".ogg",
|
||||
".oga",
|
||||
".opus",
|
||||
".spx",
|
||||
".wav",
|
||||
".wave",
|
||||
".flac",
|
||||
".aac",
|
||||
".adts",
|
||||
".wma",
|
||||
".m4a",
|
||||
".m4b",
|
||||
".m4p",
|
||||
".m4r",
|
||||
".aif",
|
||||
".aiff",
|
||||
".aifc",
|
||||
".au",
|
||||
".snd",
|
||||
".mid",
|
||||
".midi",
|
||||
".rmi",
|
||||
".kar",
|
||||
".ra",
|
||||
".ram",
|
||||
".mka",
|
||||
".ape",
|
||||
".wv",
|
||||
".ac3",
|
||||
".ec3",
|
||||
".eac3",
|
||||
".dts",
|
||||
".dtshd",
|
||||
".amr",
|
||||
".awb",
|
||||
".caf",
|
||||
".gsm",
|
||||
".mpc",
|
||||
".shn",
|
||||
".tta",
|
||||
".voc",
|
||||
".vox",
|
||||
".8svx",
|
||||
".mod",
|
||||
".s3m",
|
||||
".xm",
|
||||
".it",
|
||||
".stm",
|
||||
".med",
|
||||
".mtm",
|
||||
".umx",
|
||||
".669",
|
||||
".far",
|
||||
".amf",
|
||||
".dsm",
|
||||
".gdm",
|
||||
".imf",
|
||||
".okt",
|
||||
".sfx",
|
||||
".ult",
|
||||
".uni",
|
||||
".psm",
|
||||
".j2b",
|
||||
".dbm",
|
||||
".digi",
|
||||
".dtm",
|
||||
".plm",
|
||||
".nsf",
|
||||
".nsfe",
|
||||
".spc",
|
||||
".gym",
|
||||
".vgm",
|
||||
".vgz",
|
||||
".gbs",
|
||||
".hes",
|
||||
".ay",
|
||||
".sid",
|
||||
".oma",
|
||||
".aa3",
|
||||
".at3",
|
||||
".at9",
|
||||
".qcp",
|
||||
".tak",
|
||||
".ofr",
|
||||
".ofs",
|
||||
".sox",
|
||||
".weba",
|
||||
".dss",
|
||||
".alac",
|
||||
".vqf",
|
||||
".vql",
|
||||
".mxmf",
|
||||
".ota",
|
||||
".imy",
|
||||
".rtttl",
|
||||
".rtx",
|
||||
".xmf",
|
||||
".w64",
|
||||
".rf64",
|
||||
".bwf",
|
||||
".cda",
|
||||
".aup":
|
||||
return "audio"
|
||||
case ".mp4",
|
||||
".m4v",
|
||||
".mp4v",
|
||||
".webm",
|
||||
".mov",
|
||||
".qt",
|
||||
".avi",
|
||||
".mkv",
|
||||
".flv",
|
||||
".f4v",
|
||||
".f4p",
|
||||
".f4a",
|
||||
".f4b",
|
||||
".wmv",
|
||||
".mpg",
|
||||
".mpeg",
|
||||
".mpe",
|
||||
".m1v",
|
||||
".m2v",
|
||||
".mpv",
|
||||
".mp2v",
|
||||
".mpv2",
|
||||
".ogv",
|
||||
".ogx",
|
||||
".3gp",
|
||||
".3g2",
|
||||
".3gpp",
|
||||
".3gpp2",
|
||||
".asf",
|
||||
".asx",
|
||||
".vob",
|
||||
".ts",
|
||||
".mts",
|
||||
".m2ts",
|
||||
".tsv",
|
||||
".tsa",
|
||||
".divx",
|
||||
".xvid",
|
||||
".rm",
|
||||
".rmvb",
|
||||
".swf",
|
||||
".dv",
|
||||
".dif",
|
||||
".gifv",
|
||||
".roq",
|
||||
".nsv",
|
||||
".svi",
|
||||
".annodex",
|
||||
".axv",
|
||||
".amv",
|
||||
".bik",
|
||||
".bk2",
|
||||
".smk",
|
||||
".ivf",
|
||||
".mxf",
|
||||
".nut",
|
||||
".ogm",
|
||||
".fli",
|
||||
".flc",
|
||||
".y4m",
|
||||
".264",
|
||||
".h264",
|
||||
".265",
|
||||
".h265",
|
||||
".hevc",
|
||||
".av1",
|
||||
".vc1",
|
||||
".vp8",
|
||||
".vp9",
|
||||
".wtv",
|
||||
".yuv",
|
||||
".str",
|
||||
".pva",
|
||||
".trp",
|
||||
".rec",
|
||||
".vid",
|
||||
".rv",
|
||||
".cpk",
|
||||
".film":
|
||||
return "video"
|
||||
case:
|
||||
return "iframe"
|
||||
}
|
||||
}
|
||||
|
||||
parse_type_hint :: proc(type_hint: string) -> string {
|
||||
switch type_hint {
|
||||
case "i", "image", "img":
|
||||
return "image"
|
||||
case "a", "audio":
|
||||
return "audio"
|
||||
case "v", "video":
|
||||
return "video"
|
||||
case "f", "iframe", "frame":
|
||||
return "iframe"
|
||||
case:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
-74
@@ -1,74 +0,0 @@
|
||||
fn get_ext(url string) string {
|
||||
mut clean := url
|
||||
if question := clean.index('?') {
|
||||
clean = clean[..question]
|
||||
}
|
||||
if hash := clean.index('#') {
|
||||
clean = clean[..hash]
|
||||
}
|
||||
if dot := clean.last_index('.') {
|
||||
return clean[dot..].to_lower()
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
fn detect_type(url string) string {
|
||||
ext := get_ext(url)
|
||||
return match ext {
|
||||
'.jpg', '.jpeg', '.jpe', '.jfif', '.jif', '.pjpeg', '.pjp', '.png', '.apng', '.gif',
|
||||
'.webp', '.avif', '.heic', '.heif', '.hif', '.bmp', '.dib', '.tif', '.tiff', '.ico',
|
||||
'.cur', '.svg', '.svgz', '.raw', '.cr2', '.cr3', '.nef', '.nrw', '.orf', '.sr2', '.arw',
|
||||
'.srf', '.rw2', '.pef', '.raf', '.dng', '.3fr', '.ari', '.bay', '.cap', '.dcr', '.erf',
|
||||
'.fff', '.iiq', '.k25', '.kdc', '.mdc', '.mos', '.mrw', '.obm', '.ptx', '.pxn', '.r3d',
|
||||
'.rwl', '.rwz', '.srw', '.x3f', '.gpr', '.pgm', '.ppm', '.pbm', '.pnm', '.pam', '.pfm',
|
||||
'.tga', '.icb', '.vda', '.vst', '.pcx', '.xbm', '.xpm', '.xwd', '.sgi', '.rgb', '.rgba',
|
||||
'.bw', '.jp2', '.j2k', '.j2c', '.jpf', '.jpx', '.jpm', '.mj2', '.wbmp', '.emf', '.wmf',
|
||||
'.eps', '.epsi', '.epsf', '.psd', '.psb', '.ai', '.cdr', '.xcf', '.gbr', '.gih', '.pat',
|
||||
'.art', '.jxl', '.jxr', '.wdp', '.hdp', '.exr', '.hdr', '.dpx', '.cin', '.fits', '.fit',
|
||||
'.fts', '.icns', '.flif', '.dds', '.ktx', '.ktx2', '.astc', '.kodak', '.fpx', '.pcd',
|
||||
'.cmx', '.drw', '.cgm', '.plt', '.hpgl', '.iff', '.ilbm', '.lbm', '.mac', '.msp', '.pct',
|
||||
'.pic', '.pict', '.pntg', '.qtif', '.qti', '.ras', '.sun', '.tpic', '.wpg', '.g3', '.g4',
|
||||
'.dcm', '.dicom', '.ora', '.kra', '.clip' {
|
||||
'image'
|
||||
}
|
||||
'.mp3', '.mp2', '.mp1', '.mpa', '.mpga', '.ogg', '.oga', '.opus', '.spx', '.wav', '.wave',
|
||||
'.flac', '.aac', '.adts', '.wma', '.m4a', '.m4b', '.m4p', '.m4r', '.aif', '.aiff', '.aifc',
|
||||
'.au', '.snd', '.mid', '.midi', '.rmi', '.kar', '.ra', '.ram', '.mka', '.ape', '.wv',
|
||||
'.ac3', '.ec3', '.eac3', '.dts', '.dtshd', '.amr', '.awb', '.caf', '.gsm', '.mpc', '.shn',
|
||||
'.tta', '.voc', '.vox', '.8svx', '.mod', '.s3m', '.xm', '.it', '.stm', '.med', '.mtm',
|
||||
'.umx', '.669', '.far', '.amf', '.dsm', '.gdm', '.imf', '.okt', '.sfx', '.ult', '.uni',
|
||||
'.psm', '.j2b', '.dbm', '.digi', '.dtm', '.plm', '.nsf', '.nsfe', '.spc', '.gym', '.vgm',
|
||||
'.vgz', '.gbs', '.hes', '.ay', '.sid', '.oma', '.aa3', '.at3', '.at9', '.qcp', '.tak',
|
||||
'.ofr', '.ofs', '.sox', '.weba', '.dss', '.alac', '.vqf', '.vql', '.mxmf', '.ota', '.imy',
|
||||
'.rtttl', '.rtx', '.xmf', '.w64', '.rf64', '.bwf', '.cda', '.aup' {
|
||||
'audio'
|
||||
}
|
||||
'.mp4', '.m4v', '.mp4v', '.webm', '.mov', '.qt', '.avi', '.mkv', '.flv', '.f4v', '.f4p',
|
||||
'.f4a', '.f4b', '.wmv', '.mpg', '.mpeg', '.mpe', '.m1v', '.m2v', '.mpv', '.mp2v', '.mpv2',
|
||||
'.ogv', '.ogx', '.3gp', '.3g2', '.3gpp', '.3gpp2', '.asf', '.asx', '.vob', '.ts', '.mts',
|
||||
'.m2ts', '.tsv', '.tsa', '.divx', '.xvid', '.rm', '.rmvb', '.swf', '.dv', '.dif', '.gifv',
|
||||
'.roq', '.nsv', '.svi', '.annodex', '.axv', '.amv', '.bik', '.bk2', '.smk', '.ivf', '.mxf',
|
||||
'.nut', '.ogm', '.fli', '.flc', '.y4m', '.264', '.h264', '.265', '.h265', '.hevc', '.av1',
|
||||
'.vc1', '.vp8', '.vp9', '.wtv', '.yuv', '.str', '.pva', '.trp', '.rec', '.vid', '.rv',
|
||||
'.cpk', '.film' {
|
||||
'video'
|
||||
}
|
||||
else {
|
||||
'iframe'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// will look like this:
|
||||
// $[https://krzak.org/krzak-icon.png|i]
|
||||
// $(https://krzak.org/krzak-icon.png|image)
|
||||
// $[Krzak.org icon](https://krzak.org/krzak-icon.png|i)
|
||||
fn parse_type_hint(type_hint string) string {
|
||||
return match type_hint {
|
||||
'i', 'image', 'img' { 'image' }
|
||||
'a', 'audio' { 'audio' }
|
||||
'v', 'video' { 'video' }
|
||||
'f', 'iframe' { 'iframe' }
|
||||
else { '' }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package main
|
||||
|
||||
import "core:fmt"
|
||||
import "core:os"
|
||||
import "core:strings"
|
||||
|
||||
read_stdin :: proc() -> []string {
|
||||
data, err := os.read_entire_file_from_file(os.stdin, context.allocator)
|
||||
content := string(data)
|
||||
return strings.split_lines(content)
|
||||
}
|
||||
|
||||
print_token :: proc(token: Token, depth: int = 0) {
|
||||
indent := strings.repeat(" ", depth, context.temp_allocator)
|
||||
|
||||
type_str := ""
|
||||
switch token.type {
|
||||
case TokenType.Root:
|
||||
type_str = "Root"
|
||||
case TokenType.Text:
|
||||
type_str = "Text"
|
||||
case TokenType.Italics:
|
||||
type_str = "Italics"
|
||||
case TokenType.Bold:
|
||||
type_str = "Bold"
|
||||
case TokenType.BreakLine:
|
||||
type_str = "BreakLine"
|
||||
case TokenType.Heading:
|
||||
type_str = "Heading"
|
||||
case TokenType.Paragraph:
|
||||
type_str = "Paragraph"
|
||||
}
|
||||
|
||||
value_str := ""
|
||||
switch v in token.value {
|
||||
case string:
|
||||
value_str = v
|
||||
case int:
|
||||
value_str = fmt.aprintf("%d", v, allocator = context.temp_allocator)
|
||||
}
|
||||
|
||||
if value_str != "" {
|
||||
fmt.printf("%s%s(%s)", indent, type_str, value_str)
|
||||
} else {
|
||||
fmt.printf("%s%s", indent, type_str)
|
||||
}
|
||||
fmt.println()
|
||||
|
||||
for child in token.children {
|
||||
print_token(child, depth + 1)
|
||||
}
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
lines := read_stdin()
|
||||
parsed := parse(lines)
|
||||
print_token(parsed)
|
||||
}
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
import os
|
||||
|
||||
fn read_stdin() []string {
|
||||
mut lines := []string{}
|
||||
for {
|
||||
line := os.get_line()
|
||||
if line.len == 0 && os.stdin().eof() {
|
||||
break
|
||||
}
|
||||
lines << line
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
fn main() {
|
||||
lines := read_stdin()
|
||||
println(parse(lines))
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package main
|
||||
|
||||
import "core:fmt"
|
||||
import "core:strings"
|
||||
|
||||
TokenType :: enum {
|
||||
Text,
|
||||
Italics,
|
||||
Bold,
|
||||
BreakLine,
|
||||
Heading,
|
||||
Paragraph,
|
||||
Root,
|
||||
}
|
||||
|
||||
TokenValue :: union {
|
||||
string,
|
||||
int,
|
||||
}
|
||||
|
||||
Token :: struct {
|
||||
type: TokenType,
|
||||
value: TokenValue,
|
||||
children: [dynamic]Token,
|
||||
parent: ^Token,
|
||||
}
|
||||
|
||||
current_token: ^Token
|
||||
|
||||
replace_text :: proc(text: string, start: int, len_: int, repl: string) -> string {
|
||||
builder := strings.builder_make(context.temp_allocator)
|
||||
strings.write_string(&builder, text[:start])
|
||||
strings.write_string(&builder, repl)
|
||||
strings.write_string(&builder, text[start + len_:])
|
||||
return strings.to_string(builder)
|
||||
}
|
||||
|
||||
parse_header :: proc(line: string) -> (int, string) {
|
||||
if len(line) == 0 {
|
||||
return 0, line
|
||||
}
|
||||
|
||||
lvl := 0
|
||||
for lvl < len(line) && line[lvl] == '!' {
|
||||
lvl += 1
|
||||
}
|
||||
if lvl == 0 || lvl >= len(line) || line[lvl] != ' ' {
|
||||
return 0, line
|
||||
}
|
||||
return lvl, line[lvl + 1:]
|
||||
}
|
||||
|
||||
parse :: proc(lines: []string, allocator := context.allocator) -> Token {
|
||||
root := Token{TokenType.Root, nil, nil, nil}
|
||||
current_token := &root
|
||||
append(¤t_token.children, Token{TokenType.Paragraph, nil, nil, current_token})
|
||||
current_token = ¤t_token.children[0]
|
||||
|
||||
for untrimmed_line, line_index in lines {
|
||||
line := strings.trim_space(untrimmed_line)
|
||||
|
||||
if len(line) == 0 && line_index != len(lines) - 1 {
|
||||
if current_token.parent != nil {
|
||||
current_token = current_token.parent
|
||||
}
|
||||
|
||||
append(¤t_token.children, Token{TokenType.Paragraph, nil, nil, current_token})
|
||||
current_token = ¤t_token.children[len(current_token.children) - 1]
|
||||
continue
|
||||
}
|
||||
|
||||
append(¤t_token.children, Token{TokenType.Text, line, nil, current_token})
|
||||
|
||||
// lvl, text := parse_header(trimmed)
|
||||
// is_header := lvl > 0
|
||||
|
||||
// if is_header {
|
||||
// fmt.sbprintf(&builder, "<h%d>", lvl)
|
||||
// strings.write_string(&builder, text)
|
||||
// fmt.sbprintf(&builder, "</h%d>", lvl)
|
||||
// } else {
|
||||
// strings.write_string(&builder, text)
|
||||
// strings.write_string(&builder, "<br>")
|
||||
// }
|
||||
|
||||
// strings.write_string(&builder, "\n")
|
||||
}
|
||||
|
||||
return root
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
fn replace(text string, start int, len int, repl string) string {
|
||||
return text[..start] + repl + text[start + len..]
|
||||
}
|
||||
|
||||
fn parse_header(line string) (int, string) {
|
||||
if line.len == 0 {
|
||||
return 0, line
|
||||
}
|
||||
|
||||
mut lvl := 0
|
||||
for lvl < line.len && line[lvl] == '!'.bytes()[0] {
|
||||
lvl++
|
||||
}
|
||||
if lvl == 0 || lvl >= line.len || line[lvl] != ' '.bytes()[0] {
|
||||
return 0, line
|
||||
}
|
||||
return lvl, line[lvl + 1..]
|
||||
}
|
||||
|
||||
fn parse(lines []string) string {
|
||||
mut output := '<p>'
|
||||
for line in lines {
|
||||
mut trimmed := line.trim_space()
|
||||
|
||||
if trimmed.len == 0 {
|
||||
output += '<br>\n'
|
||||
continue
|
||||
}
|
||||
|
||||
lvl, mut text := parse_header(trimmed)
|
||||
|
||||
is_header := lvl > 0
|
||||
|
||||
if is_header {
|
||||
output += '<h' + lvl.str() + '>'
|
||||
output += text + '</h' + lvl.str() + '>'
|
||||
} else {
|
||||
output += text
|
||||
output += '<br>'
|
||||
}
|
||||
|
||||
output += '\n'
|
||||
}
|
||||
|
||||
output += '</p>'
|
||||
return output
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
clear && make format && cat README.tlm | make run | ./preview
|
||||
clear && make format && cat README.tlm | make run # | ./preview
|
||||
|
||||
Reference in New Issue
Block a user