vdoc: minor features + fixes

pull/5280/head
Ned Palacios 2020-06-08 16:28:46 +08:00 committed by GitHub
parent 6c9b2b8303
commit 721a3a24ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 80 additions and 34 deletions

View File

@ -6,7 +6,7 @@
active.scrollIntoView({ block: 'center', inline: 'nearest' }); active.scrollIntoView({ block: 'center', inline: 'nearest' });
} }
} }
setupScrollSpy(); // setupScrollSpy();
setupMobileToggle(); setupMobileToggle();
setupDarkMode(); setupDarkMode();
setupSearch(); setupSearch();

View File

@ -30,6 +30,7 @@ enum HighlightTokenTyp {
} }
const ( const (
css_js_assets = ['doc.css', 'normalize.css' 'doc.js']
allowed_formats = ['md', 'markdown', 'json', 'text', 'stdout', 'html', 'htm'] allowed_formats = ['md', 'markdown', 'json', 'text', 'stdout', 'html', 'htm']
exe_path = os.executable() exe_path = os.executable()
exe_dir = os.dir(exe_path) exe_dir = os.dir(exe_path)
@ -134,6 +135,22 @@ fn get_src_link(repo_url string, file_name string, line_nr int) string {
return url.str() return url.str()
} }
fn js_compress(str string) string {
mut js := strings.new_builder(200)
lines := str.split_into_lines()
rules := [') {', ' = ', ', ', '{ ', ' }', ' (', '; ', ' + ', ' < ']
clean := ['){', '=', ',', '{', '}', '(', ';', '+', '<']
for line in lines {
mut trimmed := line.trim_space()
if trimmed.starts_with('//') || (trimmed.starts_with('/*') && trimmed.ends_with('*/')) { continue }
for i, _ in rules {
trimmed = trimmed.replace(rules[i], clean[i])
}
js.write(trimmed)
}
return js.str()
}
fn escape(str string) string { fn escape(str string) string {
return str.replace_each(['"', '\\"', '\r\n', '\\n', '\n', '\\n']) return str.replace_each(['"', '\\"', '\r\n', '\\n', '\n', '\\n'])
} }
@ -159,7 +176,13 @@ fn (cfg DocConfig) gen_json(idx int) string {
fn html_highlight(code string, tb &table.Table) string { fn html_highlight(code string, tb &table.Table) string {
builtin := ['bool', 'string', 'i8', 'i16', 'int', 'i64', 'i128', 'byte', 'u16', 'u32', 'u64', 'u128', 'rune', 'f32', 'f64', 'any_int', 'any_float', 'byteptr', 'voidptr', 'any'] builtin := ['bool', 'string', 'i8', 'i16', 'int', 'i64', 'i128', 'byte', 'u16', 'u32', 'u64', 'u128', 'rune', 'f32', 'f64', 'any_int', 'any_float', 'byteptr', 'voidptr', 'any']
highlight_code := fn (tok token.Token, typ HighlightTokenTyp) string { highlight_code := fn (tok token.Token, typ HighlightTokenTyp) string {
lit := if typ in [.unone, .operator, .punctuation] { tok.kind.str() } else { tok.lit } lit := if typ in [.unone, .operator, .punctuation] {
tok.kind.str()
} else if typ == .string {
"'$tok.lit'"
} else if typ == .char {
'`$tok.lit`'
} else { tok.lit }
return if typ in [.unone, .name] { lit } else { '<span class="token $typ">$lit</span>' } return if typ in [.unone, .name] { lit } else { '<span class="token $typ">$lit</span>' }
} }
s := scanner.new_scanner(code, .parse_comments) s := scanner.new_scanner(code, .parse_comments)
@ -172,7 +195,7 @@ fn html_highlight(code string, tb &table.Table) string {
mut tok_typ := HighlightTokenTyp.unone mut tok_typ := HighlightTokenTyp.unone
match tok.kind { match tok.kind {
.name { .name {
if tok.lit in builtin { if tok.lit in builtin || tb.known_type(tok.lit) {
tok_typ = .builtin tok_typ = .builtin
} else if next_tok.kind == .lcbr { } else if next_tok.kind == .lcbr {
tok_typ = .symbol tok_typ = .symbol
@ -239,7 +262,7 @@ fn doc_node_html(dd doc.DocNode, link string, head bool, tb &table.Table) string
node_id := slug(sym_name) node_id := slug(sym_name)
hash_link := if !head { ' <a href="#$node_id">#</a>' } else { '' } hash_link := if !head { ' <a href="#$node_id">#</a>' } else { '' }
dnw.writeln('<section id="$node_id" class="doc-node$is_const_class">') dnw.writeln('<section id="$node_id" class="doc-node$is_const_class">')
if dd.name != 'README' { if dd.name != 'README' && dd.parent_type != 'Constants' {
dnw.write('<div class="title"><$head_tag>$sym_name$hash_link</$head_tag>') dnw.write('<div class="title"><$head_tag>$sym_name$hash_link</$head_tag>')
if link.len != 0 { if link.len != 0 {
dnw.write('<a class="link" rel="noreferrer" target="_blank" href="$link">$link_svg</a>') dnw.write('<a class="link" rel="noreferrer" target="_blank" href="$link">$link_svg</a>')
@ -256,31 +279,54 @@ fn doc_node_html(dd doc.DocNode, link string, head bool, tb &table.Table) string
return dnw.str() return dnw.str()
} }
fn write_toc(cn doc.DocNode, nodes []doc.DocNode, toc &strings.Builder) {
toc.write('<li><a href="#${slug(cn.name)}">${cn.name}</a>')
children := nodes.find_children_of(cn.name)
if children.len != 0 && cn.name != 'Constants' {
toc.writeln(' <ul>')
for child in children {
cname := cn.name + '.' + child.name
toc.writeln('<li><a href="#${slug(cname)}">${child.name}</a></li>')
}
toc.writeln('</ul>')
}
toc.writeln('</li>')
}
fn (cfg DocConfig) write_content(cn &doc.DocNode, dcs &doc.Doc, hw &strings.Builder) {
base_dir := os.base_dir(os.real_path(cfg.input_path))
file_path_name := cn.file_path.replace('$base_dir/', '')
src_link := get_src_link(cfg.manifest.repo_url, file_path_name, cn.pos.line)
children := dcs.contents.find_children_of(cn.name)
hw.write(doc_node_html(cn, src_link, false, dcs.table))
if children.len != 0 {
for child in children {
child_file_path_name := child.file_path.replace('$base_dir/', '')
child_src_link := get_src_link(cfg.manifest.repo_url, child_file_path_name, child.pos.line)
hw.write(doc_node_html(child, child_src_link, false, dcs.table))
}
}
}
fn (cfg DocConfig) gen_html(idx int) string { fn (cfg DocConfig) gen_html(idx int) string {
dcs := cfg.docs[idx] dcs := cfg.docs[idx]
time_gen := '$dcs.time_generated.day $dcs.time_generated.smonth() $dcs.time_generated.year $dcs.time_generated.hhmmss()' time_gen := '$dcs.time_generated.day $dcs.time_generated.smonth() $dcs.time_generated.year $dcs.time_generated.hhmmss()'
mut hw := strings.new_builder(200) mut hw := strings.new_builder(200)
mut toc := strings.new_builder(200) mut toc := strings.new_builder(200)
// generate toc first // generate toc first
const_node_idx := dcs.contents.index_by_name('Constants') or { -1 }
if const_node_idx != -1 {
write_toc(dcs.contents[const_node_idx], dcs.contents, &toc)
}
for cn in dcs.contents { for cn in dcs.contents {
if cn.parent_type !in ['void', ''] { continue } if cn.name == 'Constants' || cn.parent_type !in ['void', ''] { continue }
toc.write('<li><a href="#${slug(cn.name)}">${cn.name}</a>') write_toc(cn, dcs.contents, &toc)
children := dcs.contents.find_children_of(cn.name)
if children.len != 0 && cn.name != 'Constants' {
toc.writeln(' <ul>')
for child in children {
cname := cn.name + '.' + child.name
toc.writeln('<li><a href="#${slug(cname)}">${child.name}</a></li>')
}
toc.writeln('</ul>')
}
toc.writeln('</li>')
} // write head } // write head
// get resources // get resources
doc_css := cfg.get_resource('doc.css', true) doc_css := cfg.get_resource(css_js_assets[0], true)
normalize_css := cfg.get_resource('normalize.css', true) normalize_css := cfg.get_resource(css_js_assets[1], true)
doc_js := cfg.get_resource('doc.js', false) doc_js := cfg.get_resource(css_js_assets[2], !cfg.serve_http)
light_icon := cfg.get_resource('light.svg', true) light_icon := cfg.get_resource('light.svg', true)
dark_icon := cfg.get_resource('dark.svg', true) dark_icon := cfg.get_resource('dark.svg', true)
menu_icon := cfg.get_resource('menu.svg', true) menu_icon := cfg.get_resource('menu.svg', true)
@ -369,20 +415,12 @@ fn (cfg DocConfig) gen_html(idx int) string {
hw.write('</ul>\n</nav>\n</header>') hw.write('</ul>\n</nav>\n</header>')
hw.write('<div class="doc-container">\n<div class="doc-content">\n') hw.write('<div class="doc-container">\n<div class="doc-content">\n')
hw.write(doc_node_html(dcs.head, '', true, dcs.table)) hw.write(doc_node_html(dcs.head, '', true, dcs.table))
if const_node_idx != -1 {
cfg.write_content(&dcs.contents[const_node_idx], &dcs, &hw)
}
for cn in dcs.contents { for cn in dcs.contents {
if cn.parent_type !in ['void', ''] { continue } if cn.parent_type !in ['void', ''] || cn.name == 'Constants' { continue }
base_dir := os.base_dir(os.real_path(cfg.input_path)) cfg.write_content(&cn, &dcs, &hw)
file_path_name := cn.file_path.replace('$base_dir/', '')
hw.write(doc_node_html(cn, get_src_link(cfg.manifest.repo_url, file_path_name, cn.pos.line), false, dcs.table))
children := dcs.contents.find_children_of(cn.name)
if children.len != 0 {
for child in children {
child_file_path_name := child.file_path.replace('$base_dir/', '')
hw.write(doc_node_html(child, get_src_link(cfg.manifest.repo_url, child_file_path_name, child.pos.line), false, dcs.table))
}
}
} }
hw.write('\n<div class="footer">Powered by vdoc. Generated on: $time_gen</div>\n</div>\n') hw.write('\n<div class="footer">Powered by vdoc. Generated on: $time_gen</div>\n</div>\n')
if cfg.is_multi && cfg.docs.len > 1 && dcs.head.name != 'README' { if cfg.is_multi && cfg.docs.len > 1 && dcs.head.name != 'README' {
@ -573,7 +611,7 @@ fn (mut cfg DocConfig) generate_docs_from_file() {
panic(err) panic(err)
} }
} else { } else {
for fname in ['doc.css', 'normalize.css' 'doc.js'] { for fname in css_js_assets {
os.rm(os.join_path(cfg.output_path, fname)) os.rm(os.join_path(cfg.output_path, fname))
} }
} }
@ -645,7 +683,7 @@ fn (cfg DocConfig) get_resource(name string, minify bool) string {
path := os.join_path(res_path, name) path := os.join_path(res_path, name)
mut res := os.read_file(path) or { panic('could not read $path') } mut res := os.read_file(path) or { panic('could not read $path') }
if minify { if minify {
res = res.replace('\n', ' ') res = if name.ends_with('.js') { js_compress(res) } else { res.replace('\n', ' ') }
} }
// TODO: Make SVG inline for now // TODO: Make SVG inline for now
if cfg.inline_assets || path.ends_with('.svg') { if cfg.inline_assets || path.ends_with('.svg') {

View File

@ -178,6 +178,14 @@ pub fn new(input_path string) Doc {
} }
} }
pub fn (nodes []DocNode) index_by_name(node_name string) ?int {
for i, node in nodes {
if node.name != node_name { continue }
return i
}
return error('Node with the name "$node_name" was not found.')
}
pub fn (nodes []DocNode) find_children_of(parent_type string) []DocNode { pub fn (nodes []DocNode) find_children_of(parent_type string) []DocNode {
if parent_type.len == 0 { if parent_type.len == 0 {
return []DocNode{} return []DocNode{}