diff --git a/cmd/tools/vdoc-resources/doc.css b/cmd/tools/vdoc-resources/doc.css index 0a75d706e3..394ff870d5 100644 --- a/cmd/tools/vdoc-resources/doc.css +++ b/cmd/tools/vdoc-resources/doc.css @@ -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; } diff --git a/cmd/tools/vdoc.v b/cmd/tools/vdoc.v index 30df2d5a4c..968f11a756 100644 --- a/cmd/tools/vdoc.v +++ b/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 = ' + + + + + + + {{ title }} | vdoc + + {{ head_assets }} + + +
+ +
+
+ {{ contents }} + +
+ {{ right_content }} +
+
+ {{ footer_assets }} + + + ' ) 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 { ' #' } else { '' } dnw.writeln('
') - if dd.name != 'README' && dd.parent_type != 'Constants' { + if dd.name != 'README' && dd.attrs['parent'] != 'Constants' { dnw.write('
<$head_tag>$sym_name$hash_link') if link.len != 0 { dnw.write('$link_svg') @@ -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('
  • ${cn.name}') + toc_slug := if cn.content.len == 0 { '' } else { slug(cn.name) } + toc.write('
  • ${cn.name}') children := nodes.find_children_of(cn.name) - if children.len != 0 && cn.name != 'Constants' { + if cn.name != 'Constants' { toc.writeln('
      ') 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(' - - - - - - - ${dcs.head.name} | vdoc - ') - // write css - if cfg.inline_assets { - hw.write('\n ') - hw.write('\n ') - } else { - hw.write('\n ') - hw.write('\n ') - } - 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(' - -
      - ') - hw.write('
      \n
      \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\n
      \n') - if cfg.is_multi && cfg.docs.len > 1 && dcs.head.name != 'README' { - hw.write('
      \n\n
        \n${toc.str()}
      \n
      ') - } - hw.write('
      ') - if cfg.inline_assets { - hw.write('') - } else { - hw.write('') - } - hw.write(' - ') - 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 \n ' + } else { + '\n \n ' + }) + .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' { + '
        ' + toc.str() + '
      ' + } else { '' }) + .replace('{{ footer_content }}', 'Powered by vdoc. Generated on: $time_gen') + .replace('{{ footer_assets }}', if cfg.inline_assets { + '' + } else { + '' + }) } 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 diff --git a/cmd/v/help/doc.txt b/cmd/v/help/doc.txt index 77bb636bc8..00f1834f1d 100644 --- a/cmd/v/help/doc.txt +++ b/cmd/v/help/doc.txt @@ -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. \ No newline at end of file diff --git a/vlib/net/ftp/ftp.v b/vlib/net/ftp/ftp.v index cd5c51b791..6790293f90 100644 --- a/vlib/net/ftp/ftp.v +++ b/vlib/net/ftp/ftp.v @@ -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 } diff --git a/vlib/picoev/picoev.v b/vlib/picoev/picoev.v index 1b46f203ab..ffe5c6dac6 100644 --- a/vlib/picoev/picoev.v +++ b/vlib/picoev/picoev.v @@ -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) diff --git a/vlib/v/doc/doc.v b/vlib/v/doc/doc.v index 3d38486864..6842b21899 100644 --- a/vlib/v/doc/doc.v +++ b/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() } diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index 21ab29567d..c6f302ed1f 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -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 diff --git a/vlib/v/parser/comptime.v b/vlib/v/parser/comptime.v index 31e2628cb9..37c08be860 100644 --- a/vlib/v/parser/comptime.v +++ b/vlib/v/parser/comptime.v @@ -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 }