mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
vdoc: fix sorting + other minor improvements
This commit is contained in:
parent
770132ff37
commit
5ff7d07138
@ -275,10 +275,10 @@ body {
|
||||
word-break: break-word;
|
||||
}
|
||||
.doc-content > .doc-node.const:not(:first-child) {
|
||||
padding-top: 0;
|
||||
padding-top: 4rem;
|
||||
}
|
||||
.doc-content > .doc-node.const:not(:last-child) {
|
||||
padding-bottom: 1rem;
|
||||
padding-bottom: 2rem;
|
||||
}
|
||||
.doc-content > .timestamp {
|
||||
font-size: 0.8rem;
|
||||
@ -556,7 +556,12 @@ pre {
|
||||
.doc-nav .content.hidden {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.doc-content > .doc-node.const:not(:first-child) {
|
||||
padding-top: 0;
|
||||
}
|
||||
.doc-content > .doc-node.const:not(:last-child) {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
.doc-container {
|
||||
margin-top: 0;
|
||||
margin-left: 300px;
|
||||
@ -565,7 +570,6 @@ pre {
|
||||
padding-top: 1rem !important;
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
.doc-toc {
|
||||
top: 0;
|
||||
}
|
||||
|
245
cmd/tools/vdoc.v
245
cmd/tools/vdoc.v
@ -36,6 +36,51 @@ const (
|
||||
exe_dir = os.dir(exe_path)
|
||||
res_path = os.join_path(exe_dir, 'vdoc-resources')
|
||||
vexe_path = os.base_dir(@VEXE)
|
||||
html_content = '
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="x-ua-compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{ title }} | vdoc</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">
|
||||
{{ head_assets }}
|
||||
</head>
|
||||
<body>
|
||||
<div id="page">
|
||||
<header class="doc-nav hidden">
|
||||
<div class="heading-container">
|
||||
<div class="heading">
|
||||
<input type="text" id="search" placeholder="Search...">
|
||||
<div class="module">{{ head_name }}</div>
|
||||
<div class="toggle-version-container">
|
||||
<span>{{ version }}</span>
|
||||
<div id="dark-mode-toggle" role="switch" aria-checked="false" aria-label="Toggle dark mode">{{ light_icon }}{{ dark_icon }}</div>
|
||||
</div>
|
||||
{{ menu_icon }}
|
||||
</div>
|
||||
</div>
|
||||
<nav class="content hidden">
|
||||
<ul>
|
||||
{{ toc_links }}
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
<div class="doc-container">
|
||||
<div class="doc-content">
|
||||
{{ contents }}
|
||||
<div class="footer">
|
||||
{{ footer_content }}
|
||||
</div>
|
||||
</div>
|
||||
{{ right_content }}
|
||||
</div>
|
||||
</div>
|
||||
{{ footer_assets }}
|
||||
</body>
|
||||
</html>
|
||||
'
|
||||
)
|
||||
|
||||
enum OutputType {
|
||||
@ -92,6 +137,12 @@ fn (mut cfg DocConfig) serve_html() {
|
||||
if cfg.open_docs {
|
||||
open_url(server_url)
|
||||
}
|
||||
content_type := match cfg.output_type {
|
||||
.html { 'text/html' }
|
||||
.markdown { 'text/markdown' }
|
||||
.json { 'application/json' }
|
||||
else { 'text/plain' }
|
||||
}
|
||||
for {
|
||||
con := server.accept() or {
|
||||
server.close() or { }
|
||||
@ -106,7 +157,7 @@ fn (mut cfg DocConfig) serve_html() {
|
||||
filename = if url.path == '/' { def_name } else { url.path.trim_left('/') }
|
||||
}
|
||||
html := docs[filename]
|
||||
con.write('HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n$html') or {
|
||||
con.write('HTTP/1.1 200 OK\r\nContent-Type: $content_type\r\n\r\n$html') or {
|
||||
con.close() or { return }
|
||||
return
|
||||
}
|
||||
@ -127,9 +178,6 @@ fn get_src_link(repo_url string, file_name string, line_nr int) string {
|
||||
'git.sir.ht' { '/tree/master/$file_name' }
|
||||
else { '' }
|
||||
}
|
||||
if repo_url.starts_with('https://github.com/vlang/v') && !url.path.contains('master/vlib') {
|
||||
url.path = url.path.replace('/blob/master/$file_name', '/blob/master/vlib/$file_name')
|
||||
}
|
||||
if url.path == '/' { return '' }
|
||||
url.fragment = 'L$line_nr'
|
||||
return url.str()
|
||||
@ -138,12 +186,12 @@ fn get_src_link(repo_url string, file_name string, line_nr int) string {
|
||||
fn js_compress(str string) string {
|
||||
mut js := strings.new_builder(200)
|
||||
lines := str.split_into_lines()
|
||||
rules := [') {', ' = ', ', ', '{ ', ' }', ' (', '; ', ' + ', ' < ']
|
||||
clean := ['){', '=', ',', '{', '}', '(', ';', '+', '<']
|
||||
rules := [') {', ' = ', ', ', '{ ', ' }', ' (', '; ', ' + ', ' < ', ' - ', ' || ', ' var', ': ', ' >= ', ' && ', ' else if', ' === ', ' !== ', ' else ']
|
||||
clean := ['){', '=', ',', '{', '}', '(', ';', '+', '<', '-', '||', 'var', ':', '>=', '&&', 'else if', '===', '!==', 'else']
|
||||
for line in lines {
|
||||
mut trimmed := line.trim_space()
|
||||
if trimmed.starts_with('//') || (trimmed.starts_with('/*') && trimmed.ends_with('*/')) { continue }
|
||||
for i, _ in rules {
|
||||
for i in 0..rules.len-1 {
|
||||
trimmed = trimmed.replace(rules[i], clean[i])
|
||||
}
|
||||
js.write(trimmed)
|
||||
@ -256,13 +304,13 @@ fn doc_node_html(dd doc.DocNode, link string, head bool, tb &table.Table) string
|
||||
hlighted_code := html_highlight(dd.content, tb)
|
||||
is_const_class := if dd.name == 'Constants' { ' const' } else { '' }
|
||||
mut sym_name := dd.name
|
||||
if dd.parent_type !in ['void', '', 'Constants'] {
|
||||
sym_name = '${dd.parent_type}.' + sym_name
|
||||
if dd.attrs.exists('parent') && dd.attrs['parent'] !in ['void', '', 'Constants'] {
|
||||
sym_name = dd.attrs['parent'] + '.' + sym_name
|
||||
}
|
||||
node_id := slug(sym_name)
|
||||
hash_link := if !head { ' <a href="#$node_id">#</a>' } else { '' }
|
||||
dnw.writeln('<section id="$node_id" class="doc-node$is_const_class">')
|
||||
if dd.name != 'README' && dd.parent_type != 'Constants' {
|
||||
if dd.name != 'README' && dd.attrs['parent'] != 'Constants' {
|
||||
dnw.write('<div class="title"><$head_tag>$sym_name$hash_link</$head_tag>')
|
||||
if link.len != 0 {
|
||||
dnw.write('<a class="link" rel="noreferrer" target="_blank" href="$link">$link_svg</a>')
|
||||
@ -279,10 +327,19 @@ fn doc_node_html(dd doc.DocNode, link string, head bool, tb &table.Table) string
|
||||
return dnw.str()
|
||||
}
|
||||
|
||||
fn (cfg DocConfig) readme_idx() int {
|
||||
for i, dc in cfg.docs {
|
||||
if dc.head.name != 'README' { continue }
|
||||
return i
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
fn write_toc(cn doc.DocNode, nodes []doc.DocNode, toc &strings.Builder) {
|
||||
toc.write('<li><a href="#${slug(cn.name)}">${cn.name}</a>')
|
||||
toc_slug := if cn.content.len == 0 { '' } else { slug(cn.name) }
|
||||
toc.write('<li class="open"><a href="#$toc_slug">${cn.name}</a>')
|
||||
children := nodes.find_children_of(cn.name)
|
||||
if children.len != 0 && cn.name != 'Constants' {
|
||||
if cn.name != 'Constants' {
|
||||
toc.writeln(' <ul>')
|
||||
for child in children {
|
||||
cname := cn.name + '.' + child.name
|
||||
@ -295,34 +352,32 @@ fn write_toc(cn doc.DocNode, nodes []doc.DocNode, toc &strings.Builder) {
|
||||
|
||||
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/', '')
|
||||
file_path_name := if cfg.is_multi { cn.file_path.replace('$base_dir/', '') } else { os.file_name(cn.file_path) }
|
||||
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))
|
||||
}
|
||||
if cn.content.len != 0 {
|
||||
hw.write(doc_node_html(cn, src_link, false, dcs.table))
|
||||
}
|
||||
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 {
|
||||
dcs := cfg.docs[idx]
|
||||
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 toc := strings.new_builder(200)
|
||||
mut toc2 := strings.new_builder(200)
|
||||
mut contents := strings.new_builder(200)
|
||||
// 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)
|
||||
}
|
||||
contents.writeln(doc_node_html(dcs.head, '', true, dcs.table))
|
||||
for cn in dcs.contents {
|
||||
if cn.name == 'Constants' || cn.parent_type !in ['void', ''] { continue }
|
||||
cfg.write_content(&cn, &dcs, &contents)
|
||||
if cn.attrs['parent'] == 'Constants' || cn.attrs['category'] == 'Methods' { continue }
|
||||
write_toc(cn, dcs.contents, &toc)
|
||||
} // write head
|
||||
|
||||
// get resources
|
||||
doc_css := cfg.get_resource(css_js_assets[0], true)
|
||||
normalize_css := cfg.get_resource(css_js_assets[1], true)
|
||||
@ -331,47 +386,17 @@ fn (cfg DocConfig) gen_html(idx int) string {
|
||||
dark_icon := cfg.get_resource('dark.svg', true)
|
||||
menu_icon := cfg.get_resource('menu.svg', true)
|
||||
arrow_icon := cfg.get_resource('arrow.svg', true)
|
||||
|
||||
hw.write('
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="x-ua-compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>${dcs.head.name} | vdoc</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">')
|
||||
|
||||
// write css
|
||||
if cfg.inline_assets {
|
||||
hw.write('\n <style>$doc_css</style>')
|
||||
hw.write('\n <style>$normalize_css</style>')
|
||||
} else {
|
||||
hw.write('\n <link rel="stylesheet" href="$doc_css" />')
|
||||
hw.write('\n <link rel="stylesheet" href="$normalize_css" />')
|
||||
}
|
||||
|
||||
version := if cfg.manifest.version.len != 0 { cfg.manifest.version } else { '' }
|
||||
header_name := if cfg.is_multi && cfg.docs.len > 1 { os.file_name(os.real_path(cfg.input_path)) } else { dcs.head.name }
|
||||
header_name := if cfg.is_multi && cfg.docs.len > 1 {
|
||||
os.file_name(os.real_path(cfg.input_path))
|
||||
} else if cfg.docs.len == 2 && idx+1 < cfg.docs.len && cfg.readme_idx() != -1 {
|
||||
cfg.docs[cfg.readme_idx()+1].head.name
|
||||
} else {
|
||||
dcs.head.name
|
||||
}
|
||||
// write nav1
|
||||
hw.write('
|
||||
<body>
|
||||
<div id="page">
|
||||
<header class="doc-nav hidden">
|
||||
<div class="heading-container">
|
||||
<div class="heading">
|
||||
<input type="text" id="search" placeholder="Search...">
|
||||
<div class="module">${header_name}</div>
|
||||
<div class="toggle-version-container">
|
||||
<span>${version}</span>
|
||||
<div id="dark-mode-toggle" role="switch" aria-checked="false" aria-label="Toggle dark mode">$light_icon $dark_icon</div>
|
||||
</div>
|
||||
$menu_icon
|
||||
</div>
|
||||
</div>
|
||||
<nav class="content hidden">
|
||||
<ul>')
|
||||
if cfg.is_multi && cfg.docs.len > 1 {
|
||||
if cfg.is_multi || cfg.docs.len > 1 {
|
||||
mut submod_prefix := ''
|
||||
mut docs := cfg.docs.filter(it.head.name == 'builtin')
|
||||
docs << cfg.docs.filter(it.head.name != 'builtin')
|
||||
@ -385,6 +410,8 @@ fn (cfg DocConfig) gen_html(idx int) string {
|
||||
'./index.html'
|
||||
} else if submod_prefix !in cfg.docs.map(it.head.name) {
|
||||
'#'
|
||||
} else if cfg.docs.len == 2 && cfg.readme_idx() == -1 {
|
||||
'./docs.html'
|
||||
} else {
|
||||
'./' + doc.head.name + '.html'
|
||||
}
|
||||
@ -397,46 +424,44 @@ fn (cfg DocConfig) gen_html(idx int) string {
|
||||
}
|
||||
}
|
||||
active_class := if doc.head.name == dcs.head.name { ' active' } else { '' }
|
||||
hw.write('<li class="open$active_class"><div class="menu-row">$dropdown<a href="$href_name">${submod_prefix}</a></div>')
|
||||
toc2.write('<li class="open$active_class"><div class="menu-row">$dropdown<a href="$href_name">${submod_prefix}</a></div>')
|
||||
for j, cdoc in submodules {
|
||||
if j == 0 {
|
||||
hw.write('<ul>')
|
||||
toc2.write('<ul>')
|
||||
}
|
||||
submod_name := cdoc.head.name.all_after(submod_prefix + '.')
|
||||
sub_selected_classes := if cdoc.head.name == dcs.head.name { ' class="active"' } else { '' }
|
||||
hw.write('<li$sub_selected_classes><a href="./${cdoc.head.name}.html">${submod_name}</a></li>')
|
||||
toc2.write('<li$sub_selected_classes><a href="./${cdoc.head.name}.html">${submod_name}</a></li>')
|
||||
if j == submodules.len - 1 {
|
||||
hw.write('</ul>')
|
||||
toc2.write('</ul>')
|
||||
}
|
||||
}
|
||||
hw.write('</li>')
|
||||
toc2.write('</li>')
|
||||
}
|
||||
} else {
|
||||
hw.writeln(toc.str())
|
||||
}
|
||||
hw.write('</ul>\n</nav>\n</header>')
|
||||
hw.write('<div class="doc-container">\n<div class="doc-content">\n')
|
||||
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 {
|
||||
if cn.parent_type !in ['void', ''] || cn.name == 'Constants' { continue }
|
||||
cfg.write_content(&cn, &dcs, &hw)
|
||||
}
|
||||
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' {
|
||||
hw.write('<div class="doc-toc">\n\n<ul>\n${toc.str()}</ul>\n</div>')
|
||||
}
|
||||
hw.write('</div></div>')
|
||||
if cfg.inline_assets {
|
||||
hw.write('<script>$doc_js</script>')
|
||||
} else {
|
||||
hw.write('<script src="$doc_js"></script>')
|
||||
}
|
||||
hw.write('</body>
|
||||
</html>')
|
||||
return hw.str()
|
||||
return html_content
|
||||
.replace('{{ title }}', dcs.head.name)
|
||||
.replace('{{ head_name }}', header_name)
|
||||
.replace('{{ version }}', version)
|
||||
.replace('{{ light_icon }}', light_icon)
|
||||
.replace('{{ dark_icon }}', dark_icon)
|
||||
.replace('{{ menu_icon }}', menu_icon)
|
||||
.replace('{{ head_assets }}', if cfg.inline_assets {
|
||||
'\n <style>$doc_css</style>\n <style>$normalize_css</style>'
|
||||
} else {
|
||||
'\n <link rel="stylesheet" href="$doc_css" />\n <link rel="stylesheet" href="$normalize_css" />'
|
||||
})
|
||||
.replace('{{ toc_links }}', if cfg.is_multi || cfg.docs.len > 1 { toc2.str() } else { toc.str() })
|
||||
.replace('{{ contents }}', contents.str())
|
||||
.replace('{{ right_content }}', if cfg.is_multi && cfg.docs.len > 1 && dcs.head.name != 'README' {
|
||||
'<div class="doc-toc"><ul>' + toc.str() + '</ul></div>'
|
||||
} else { '' })
|
||||
.replace('{{ footer_content }}', 'Powered by vdoc. Generated on: $time_gen')
|
||||
.replace('{{ footer_assets }}', if cfg.inline_assets {
|
||||
'<script>$doc_js</script>'
|
||||
} else {
|
||||
'<script src="$doc_js"></script>'
|
||||
})
|
||||
}
|
||||
|
||||
fn (cfg DocConfig) gen_plaintext(idx int) string {
|
||||
@ -482,13 +507,14 @@ fn (cfg DocConfig) gen_markdown(idx int, with_toc bool) string {
|
||||
|
||||
fn (cfg DocConfig) render() map[string]string {
|
||||
mut docs := map[string]string
|
||||
|
||||
for i, doc in cfg.docs {
|
||||
// since builtin is generated first, ignore it
|
||||
mut name := if doc.head.name == 'README' {
|
||||
mut name := if doc.head.name == 'README' || cfg.docs.len == 1 {
|
||||
'index'
|
||||
} else if !cfg.is_multi && !os.is_dir(cfg.output_path) {
|
||||
os.file_name(cfg.output_path)
|
||||
} else if i-1 >= 0 && cfg.readme_idx() != -1 && cfg.docs.len == 2 {
|
||||
'docs'
|
||||
} else {
|
||||
doc.head.name
|
||||
}
|
||||
@ -579,7 +605,12 @@ fn (mut cfg DocConfig) generate_docs_from_file() {
|
||||
mut dcs := doc.generate(dirpath, cfg.pub_only, true) or {
|
||||
mut err_msg := err
|
||||
if errcode == 1 {
|
||||
err_msg += ' Use the `-m` flag if you are generating docs of a directory with multiple modules inside.'
|
||||
mod_list := get_modules_list(cfg.input_path)
|
||||
println('Available modules:\n==================')
|
||||
for mod in mod_list {
|
||||
println(mod.all_after('vlib/').all_after('modules/').replace('/', '.'))
|
||||
}
|
||||
err_msg += ' Use the `-m` flag if you are generating docs of a directory containing multiple modules.'
|
||||
}
|
||||
eprintln(err_msg)
|
||||
exit(1)
|
||||
@ -613,6 +644,11 @@ fn (mut cfg DocConfig) generate_docs_from_file() {
|
||||
if !os.is_dir(cfg.output_path) {
|
||||
cfg.output_path = os.real_path('.')
|
||||
}
|
||||
if !os.exists(cfg.output_path) {
|
||||
os.mkdir(cfg.output_path) or {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
if cfg.is_multi {
|
||||
cfg.output_path = os.join_path(cfg.output_path, '_docs')
|
||||
if !os.exists(cfg.output_path) {
|
||||
@ -679,7 +715,7 @@ fn get_modules_list(path string) []string {
|
||||
files := os.walk_ext(path, 'v')
|
||||
mut dirs := []string{}
|
||||
for file in files {
|
||||
if 'test' in file || 'js' in file || 'x64' in file || 'bare' in file || 'uiold' in file || 'vweb' in file { continue }
|
||||
if 'vlib' in path && ('examples' in file || 'test' in file || 'js' in file || 'x64' in file || 'bare' in file || 'uiold' in file || 'vweb' in file) { continue }
|
||||
dirname := os.base_dir(file)
|
||||
if dirname in dirs { continue }
|
||||
dirs << dirname
|
||||
@ -766,9 +802,11 @@ fn main() {
|
||||
'-s' {
|
||||
cfg.inline_assets = true
|
||||
cfg.serve_http = true
|
||||
cfg.output_type = .html
|
||||
if cfg.output_type == .unset {
|
||||
cfg.output_type = .html
|
||||
}
|
||||
}
|
||||
'-r' {
|
||||
'-readme' {
|
||||
cfg.include_readme = true
|
||||
}
|
||||
'-v' {
|
||||
@ -784,6 +822,11 @@ fn main() {
|
||||
eprintln('vdoc: No input path found.')
|
||||
exit(1)
|
||||
}
|
||||
$if windows {
|
||||
cfg.input_path = cfg.input_path.replace('/', os.path_separator)
|
||||
} $else {
|
||||
cfg.input_path = cfg.input_path.replace('\\', os.path_separator)
|
||||
}
|
||||
is_path := cfg.input_path.ends_with('.v') || cfg.input_path.split(os.path_separator).len > 1 || cfg.input_path == '.'
|
||||
if cfg.input_path == 'vlib' {
|
||||
cfg.is_multi = true
|
||||
|
@ -20,6 +20,6 @@ Options:
|
||||
-open Launches the browser when the server docs has started.
|
||||
-p Specifies the port to be used for the docs server.
|
||||
-s Serve HTML-generated docs via HTTP.
|
||||
-r Include README.md to docs if present.
|
||||
-readme Include README.md to docs if present.
|
||||
-v Enables verbose logging. For debugging purposes.
|
||||
-h, -help Prints this help text.
|
@ -123,7 +123,7 @@ pub fn (ftp FTP) login(user, passwd string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
mut code, mut data := ftp.read()
|
||||
mut code, _ := ftp.read()
|
||||
if code == logged_in {
|
||||
return true
|
||||
}
|
||||
|
@ -19,11 +19,11 @@ import picohttpparser
|
||||
#include "src/picoev.h"
|
||||
|
||||
const (
|
||||
MAX_FDS = 1024
|
||||
TIMEOUT_SECS = 8
|
||||
MAX_TIMEOUT = 10
|
||||
MAX_READ = 4096
|
||||
MAX_WRITE = 8192
|
||||
max_fds = 1024
|
||||
timeout_secs = 8
|
||||
max_timeout = 10
|
||||
max_read = 4096
|
||||
max_write = 8192
|
||||
)
|
||||
|
||||
struct C.in_addr {
|
||||
@ -122,10 +122,10 @@ fn rw_callback(loop &C.picoev_loop, fd, events int, cb_arg voidptr) {
|
||||
return
|
||||
}
|
||||
else if (events & C.PICOEV_READ) != 0 {
|
||||
C.picoev_set_timeout(loop, fd, TIMEOUT_SECS)
|
||||
buf := (p.buf + fd * MAX_READ)
|
||||
C.picoev_set_timeout(loop, fd, timeout_secs)
|
||||
buf := (p.buf + fd * max_read)
|
||||
idx := p.idx[fd]
|
||||
mut r := myread(fd, buf, MAX_READ, idx)
|
||||
mut r := myread(fd, buf, max_read, idx)
|
||||
if r == 0 {
|
||||
close_conn(loop, fd)
|
||||
p.idx[fd] = 0
|
||||
@ -141,7 +141,7 @@ fn rw_callback(loop &C.picoev_loop, fd, events int, cb_arg voidptr) {
|
||||
} else {
|
||||
r += idx
|
||||
mut s := tos(buf, r)
|
||||
out := (p.out + fd * MAX_WRITE)
|
||||
out := (p.out + fd * max_write)
|
||||
mut res := picohttpparser.Response{
|
||||
fd: fd
|
||||
date: p.date
|
||||
@ -191,7 +191,7 @@ fn accept_callback(loop &C.picoev_loop, fd, events int, cb_arg voidptr) {
|
||||
newfd := C.accept(fd, 0, 0)
|
||||
if newfd != -1 {
|
||||
setup_sock(newfd)
|
||||
C.picoev_add(loop, newfd, C.PICOEV_READ, TIMEOUT_SECS, rw_callback, cb_arg)
|
||||
C.picoev_add(loop, newfd, C.PICOEV_READ, timeout_secs, rw_callback, cb_arg)
|
||||
}
|
||||
}
|
||||
|
||||
@ -223,14 +223,14 @@ pub fn new(port int, cb voidptr) &Picoev {
|
||||
|
||||
setup_sock(fd)
|
||||
|
||||
C.picoev_init(MAX_FDS)
|
||||
loop := C.picoev_create_loop(MAX_TIMEOUT)
|
||||
C.picoev_init(max_fds)
|
||||
loop := C.picoev_create_loop(max_timeout)
|
||||
pv := &Picoev{
|
||||
loop: loop
|
||||
cb: cb
|
||||
date: C.get_date()
|
||||
buf: malloc(MAX_FDS * MAX_READ + 1)
|
||||
out: malloc(MAX_FDS * MAX_WRITE + 1)
|
||||
buf: malloc(max_fds * max_read + 1)
|
||||
out: malloc(max_fds * max_write + 1)
|
||||
}
|
||||
C.picoev_add(loop, fd, C.PICOEV_READ, 0, accept_callback, pv)
|
||||
|
||||
|
158
vlib/v/doc/doc.v
158
vlib/v/doc/doc.v
@ -21,6 +21,7 @@ pub mut:
|
||||
head DocNode
|
||||
with_comments bool = true
|
||||
contents []DocNode
|
||||
fmt fmt.Fmt
|
||||
time_generated time.Time
|
||||
}
|
||||
|
||||
@ -37,7 +38,7 @@ pub mut:
|
||||
comment string
|
||||
pos DocPos = DocPos{-1, -1}
|
||||
file_path string = ''
|
||||
parent_type string = ''
|
||||
attrs map[string]string
|
||||
}
|
||||
|
||||
pub fn merge_comments(stmts []ast.Stmt) string {
|
||||
@ -112,65 +113,55 @@ fn convert_pos(file_path string, pos token.Position) DocPos {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (d Doc) get_signature(stmt ast.Stmt, file &ast.File) string {
|
||||
mut f := fmt.Fmt{
|
||||
out: strings.new_builder(1000)
|
||||
out_imports: strings.new_builder(200)
|
||||
table: d.table
|
||||
file: file
|
||||
cur_mod: d.head.name.split('.').last()
|
||||
indent: 0
|
||||
is_debug: false
|
||||
}
|
||||
f.process_file_imports(file)
|
||||
pub fn (mut d Doc) get_signature(stmt ast.Stmt, file &ast.File) string {
|
||||
match stmt {
|
||||
ast.Module {
|
||||
return 'module $it.name'
|
||||
return 'module $stmt.name'
|
||||
}
|
||||
ast.FnDecl {
|
||||
return it.str(d.table).replace(f.cur_mod + '.', '')
|
||||
return stmt.str(d.table).replace(d.fmt.cur_mod + '.', '')
|
||||
}
|
||||
else {
|
||||
f.stmt(stmt)
|
||||
return f.out.str().trim_space()
|
||||
d.fmt.out = strings.new_builder(1000)
|
||||
d.fmt.stmt(stmt)
|
||||
return d.fmt.out.str().trim_space()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (d Doc) get_pos(stmt ast.Stmt) token.Position {
|
||||
match stmt {
|
||||
ast.FnDecl { return it.pos }
|
||||
ast.StructDecl { return it.pos }
|
||||
ast.EnumDecl { return it.pos }
|
||||
ast.InterfaceDecl { return it.pos }
|
||||
ast.ConstDecl { return it.pos }
|
||||
ast.FnDecl { return stmt.pos }
|
||||
ast.StructDecl { return stmt.pos }
|
||||
ast.EnumDecl { return stmt.pos }
|
||||
ast.InterfaceDecl { return stmt.pos }
|
||||
ast.ConstDecl { return stmt.pos }
|
||||
else { return token.Position{} }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (d Doc) get_type_name(decl ast.TypeDecl) string {
|
||||
match decl {
|
||||
ast.SumTypeDecl { return it.name }
|
||||
ast.FnTypeDecl { return it.name }
|
||||
ast.AliasTypeDecl { return it.name }
|
||||
ast.SumTypeDecl { return decl.name }
|
||||
ast.FnTypeDecl { return decl.name }
|
||||
ast.AliasTypeDecl { return decl.name }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (d Doc) get_name(stmt ast.Stmt) string {
|
||||
cur_mod := d.head.name.split('.').last()
|
||||
match stmt {
|
||||
ast.FnDecl { return it.name }
|
||||
ast.StructDecl { return it.name }
|
||||
ast.EnumDecl { return it.name }
|
||||
ast.InterfaceDecl { return it.name }
|
||||
ast.TypeDecl { return d.get_type_name(it).replace('&' + cur_mod + '.', '').replace(cur_mod + '.', '') }
|
||||
ast.FnDecl { return stmt.name }
|
||||
ast.StructDecl { return stmt.name }
|
||||
ast.EnumDecl { return stmt.name }
|
||||
ast.InterfaceDecl { return stmt.name }
|
||||
ast.TypeDecl { return d.get_type_name(stmt) }
|
||||
ast.ConstDecl { return 'Constants' }
|
||||
else { return '' }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(input_path string) Doc {
|
||||
return Doc{
|
||||
mut d := Doc{
|
||||
input_path: os.real_path(input_path)
|
||||
prefs: &pref.Preferences{}
|
||||
table: table.new_table()
|
||||
@ -178,28 +169,59 @@ pub fn new(input_path string) Doc {
|
||||
contents: []DocNode{}
|
||||
time_generated: time.now()
|
||||
}
|
||||
d.fmt = fmt.Fmt{
|
||||
indent: 0
|
||||
is_debug: false
|
||||
table: d.table
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
pub fn (nodes []DocNode) index_by_name(node_name string) ?int {
|
||||
pub fn (mut nodes []DocNode) sort_by_name() {
|
||||
nodes.sort_with_compare(compare_nodes_by_name)
|
||||
}
|
||||
|
||||
pub fn (mut nodes []DocNode) sort_by_category() {
|
||||
nodes.sort_with_compare(compare_nodes_by_category)
|
||||
}
|
||||
|
||||
fn compare_nodes_by_name(a, b &DocNode) int {
|
||||
al := a.name.to_lower()
|
||||
bl := b.name.to_lower()
|
||||
return compare_strings(al, bl)
|
||||
}
|
||||
|
||||
fn compare_nodes_by_category(a, b &DocNode) int {
|
||||
al := a.attrs['category']
|
||||
bl := b.attrs['category']
|
||||
return compare_strings(al, bl)
|
||||
}
|
||||
|
||||
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.')
|
||||
return -1
|
||||
}
|
||||
|
||||
pub fn (nodes []DocNode) find_children_of(parent_type string) []DocNode {
|
||||
if parent_type.len == 0 {
|
||||
return []DocNode{}
|
||||
pub fn (nodes []DocNode) find_children_of(parent string) []DocNode {
|
||||
return nodes.find_nodes_with_attr('parent', parent)
|
||||
}
|
||||
|
||||
pub fn (nodes []DocNode) find_nodes_with_attr(attr_name string, value string) []DocNode {
|
||||
mut subgroup := []DocNode{}
|
||||
if attr_name.len == 0 {
|
||||
return subgroup
|
||||
}
|
||||
mut children := []DocNode{}
|
||||
for node in nodes {
|
||||
if node.parent_type != parent_type {
|
||||
if !node.attrs.exists(attr_name) || node.attrs[attr_name] != value {
|
||||
continue
|
||||
}
|
||||
children << node
|
||||
subgroup << node
|
||||
}
|
||||
return children
|
||||
subgroup.sort_by_name()
|
||||
return subgroup
|
||||
}
|
||||
|
||||
fn get_parent_mod(dir string) ?string {
|
||||
@ -242,7 +264,7 @@ fn get_parent_mod(dir string) ?string {
|
||||
return file_ast.mod.name
|
||||
}
|
||||
|
||||
pub fn (mut d Doc) generate() ?bool {
|
||||
fn (mut d Doc) generate() ?Doc {
|
||||
// get all files
|
||||
base_path := if os.is_dir(d.input_path) { d.input_path } else { os.real_path(os.base_dir(d.input_path)) }
|
||||
project_files := os.ls(base_path) or {
|
||||
@ -285,7 +307,9 @@ pub fn (mut d Doc) generate() ?bool {
|
||||
continue
|
||||
}
|
||||
stmts := file_ast.stmts
|
||||
//
|
||||
d.fmt.file = file_ast
|
||||
d.fmt.cur_mod = orig_mod_name
|
||||
d.fmt.process_file_imports(file_ast)
|
||||
mut last_import_stmt_idx := 0
|
||||
for sidx, stmt in stmts {
|
||||
if stmt is ast.Import {
|
||||
@ -306,10 +330,7 @@ pub fn (mut d Doc) generate() ?bool {
|
||||
module_comment := get_comment_block_right_before(prev_comments)
|
||||
prev_comments = []
|
||||
if 'vlib' !in base_path && !module_comment.starts_with('Copyright (c)') {
|
||||
if module_comment == '' {
|
||||
continue
|
||||
}
|
||||
if module_comment == d.head.comment {
|
||||
if module_comment in ['', d.head.comment] {
|
||||
continue
|
||||
}
|
||||
if d.head.comment != '' {
|
||||
@ -350,25 +371,45 @@ pub fn (mut d Doc) generate() ?bool {
|
||||
pos: convert_pos(v_files[i], pos)
|
||||
file_path: v_files[i]
|
||||
}
|
||||
if node.name.len == 0 && node.comment.len == 0 && node.content.len == 0 {
|
||||
continue
|
||||
}
|
||||
if stmt is ast.FnDecl {
|
||||
fnd := stmt as ast.FnDecl
|
||||
if fnd.receiver.typ != 0 {
|
||||
mut parent_type := d.table.get_type_name(fnd.receiver.typ)
|
||||
if parent_type.starts_with(module_name + '.') {
|
||||
parent_type = parent_type.all_after(module_name + '.')
|
||||
node.attrs['parent'] = d.fmt.type_to_str(fnd.receiver.typ).trim_left('&')
|
||||
p_idx := d.contents.index_by_name(node.attrs['parent'])
|
||||
if p_idx == -1 && node.attrs['parent'] != 'void' {
|
||||
d.contents << DocNode{
|
||||
name: node.attrs['parent']
|
||||
content: ''
|
||||
comment: ''
|
||||
attrs: {'category': 'Structs'}
|
||||
}
|
||||
}
|
||||
node.parent_type = parent_type
|
||||
}
|
||||
}
|
||||
if stmt is ast.ConstDecl {
|
||||
if const_idx == -1 {
|
||||
const_idx = sidx
|
||||
} else {
|
||||
node.parent_type = 'Constants'
|
||||
node.attrs['parent'] = 'Constants'
|
||||
}
|
||||
}
|
||||
if node.name.len == 0 && node.comment.len == 0 && node.content.len == 0 {
|
||||
continue
|
||||
match stmt {
|
||||
ast.ConstDecl { node.attrs['category'] = 'Constants' }
|
||||
ast.EnumDecl { node.attrs['category'] = 'Enums' }
|
||||
ast.InterfaceDecl { node.attrs['category'] = 'Interfaces' }
|
||||
ast.StructDecl { node.attrs['category'] = 'Structs' }
|
||||
ast.TypeDecl { node.attrs['category'] = 'Typedefs' }
|
||||
ast.FnDecl {
|
||||
node.attrs['category'] = if node.attrs['parent'] in ['void', ''] || !node.attrs.exists('parent') {
|
||||
'Functions'
|
||||
} else {
|
||||
'Methods'
|
||||
}
|
||||
}
|
||||
else {}
|
||||
}
|
||||
d.contents << node
|
||||
if d.with_comments && (prev_comments.len > 0) {
|
||||
@ -378,17 +419,18 @@ pub fn (mut d Doc) generate() ?bool {
|
||||
}
|
||||
prev_comments = []
|
||||
}
|
||||
|
||||
d.fmt.mod2alias = map[string]string{}
|
||||
}
|
||||
d.time_generated = time.now()
|
||||
return true
|
||||
d.contents.sort_by_name()
|
||||
d.contents.sort_by_category()
|
||||
return d
|
||||
}
|
||||
|
||||
pub fn generate(input_path string, pub_only, with_comments bool) ?Doc {
|
||||
mut doc := new(input_path)
|
||||
doc.pub_only = pub_only
|
||||
doc.with_comments = with_comments
|
||||
doc.generate() or {
|
||||
return error_with_code(err, errcode)
|
||||
}
|
||||
return doc
|
||||
return doc.generate()
|
||||
}
|
||||
|
@ -514,7 +514,7 @@ pub fn (mut f Fmt) struct_field_expr(fexpr ast.Expr) {
|
||||
}
|
||||
}
|
||||
|
||||
fn (f &Fmt) type_to_str(t table.Type) string {
|
||||
pub fn (f &Fmt) type_to_str(t table.Type) string {
|
||||
mut res := f.table.type_to_str(t)
|
||||
for res.ends_with('_ptr') {
|
||||
// type_ptr => &type
|
||||
|
@ -282,6 +282,7 @@ fn os_from_string(os string) pref.OS {
|
||||
|
||||
// Helper function to convert string names to CC enum
|
||||
pub fn cc_from_string(cc_str string) pref.CompilerType {
|
||||
if cc_str.len == 0 { return .gcc }
|
||||
cc := cc_str.replace('\\', '/').split('/').last().all_before('.')
|
||||
if 'tcc' in cc { return .tinyc }
|
||||
if 'tinyc' in cc { return .tinyc }
|
||||
|
Loading…
Reference in New Issue
Block a user