diff options
| author | gingerBill <bill@gingerbill.org> | 2022-01-22 17:07:24 +0000 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2022-01-22 17:07:24 +0000 |
| commit | fdcb9deaffed29f8b528cb4a8bf30693a7894b2c (patch) | |
| tree | 20320db9608f717be6ee9f096ef27e5563eaf6b5 | |
| parent | fe6539fad9e83f20d2e45b377e57353dfb6b3a96 (diff) | |
Generate core and vendor library collection; add package sidebar for the entire collection
| -rw-r--r-- | tools/odin-html-docs/odin_html_docs_main.odin | 262 | ||||
| -rw-r--r-- | tools/odin-html-docs/style.css | 27 |
2 files changed, 221 insertions, 68 deletions
diff --git a/tools/odin-html-docs/odin_html_docs_main.odin b/tools/odin-html-docs/odin_html_docs_main.odin index 7f2e7b59f..e5d46547a 100644 --- a/tools/odin-html-docs/odin_html_docs_main.odin +++ b/tools/odin-html-docs/odin_html_docs_main.odin @@ -8,10 +8,13 @@ import "core:strings" import "core:path/slashpath" import "core:sort" import "core:slice" +import "core:time" GITHUB_LICENSE_URL :: "https://github.com/odin-lang/Odin/tree/master/LICENSE" GITHUB_CORE_URL :: "https://github.com/odin-lang/Odin/tree/master/core" +GITHUB_VENDOR_URL :: "https://github.com/odin-lang/Odin/tree/master/vendor" BASE_CORE_URL :: "/core" +BASE_VENDOR_URL :: "/vendor" header: ^doc.Header files: []doc.File @@ -19,8 +22,18 @@ pkgs: []doc.Pkg entities: []doc.Entity types: []doc.Type -pkgs_to_use: map[string]^doc.Pkg // trimmed path +core_pkgs_to_use: map[string]^doc.Pkg // trimmed path +vendor_pkgs_to_use: map[string]^doc.Pkg // trimmed path pkg_to_path: map[^doc.Pkg]string // trimmed path +pkg_to_collection: map[^doc.Pkg]^Collection + +Collection :: struct { + name: string, + pkgs_to_use: ^map[string]^doc.Pkg, + github_url: string, + base_url: string, + root: ^Dir_Node, +} array :: proc(a: $A/doc.Array($T)) -> []T { return doc.from_array(header, a) @@ -175,6 +188,21 @@ main :: proc() { entities = array(header.entities) types = array(header.types) + core_collection := &Collection{ + "Core", + &core_pkgs_to_use, + GITHUB_CORE_URL, + BASE_CORE_URL, + nil, + } + vendor_collection := &Collection{ + "Vendor", + &vendor_pkgs_to_use, + GITHUB_VENDOR_URL, + BASE_VENDOR_URL, + nil, + } + { fullpaths: [dynamic]string defer delete(fullpaths) @@ -184,25 +212,38 @@ main :: proc() { } path_prefix := common_prefix(fullpaths[:]) - pkgs_to_use = make(map[string]^doc.Pkg) + core_pkgs_to_use = make(map[string]^doc.Pkg) + vendor_pkgs_to_use = make(map[string]^doc.Pkg) fullpath_loop: for fullpath, i in fullpaths { path := strings.trim_prefix(fullpath, path_prefix) - if !strings.has_prefix(path, "core/") { - continue fullpath_loop - } pkg := &pkgs[i+1] if len(array(pkg.entities)) == 0 { continue fullpath_loop } - trimmed_path := strings.trim_prefix(path, "core/") - if strings.has_prefix(trimmed_path, "sys") { - continue fullpath_loop - } - pkgs_to_use[trimmed_path] = pkg + switch { + case strings.has_prefix(path, "core/"): + trimmed_path := strings.trim_prefix(path, "core/") + if strings.has_prefix(trimmed_path, "sys") { + continue fullpath_loop + } + + core_pkgs_to_use[trimmed_path] = pkg + case strings.has_prefix(path, "vendor/"): + trimmed_path := strings.trim_prefix(path, "vendor/") + if strings.contains(trimmed_path, "/bindings") { + continue fullpath_loop + } + vendor_pkgs_to_use[trimmed_path] = pkg + } + } + for path, pkg in core_pkgs_to_use { + pkg_to_path[pkg] = path + pkg_to_collection[pkg] = core_collection } - for path, pkg in pkgs_to_use { + for path, pkg in vendor_pkgs_to_use { pkg_to_path[pkg] = path + pkg_to_collection[pkg] = vendor_collection } } @@ -218,42 +259,53 @@ main :: proc() { os.write_entire_file("index.html", b.buf[:]) } + core_collection.root = generate_directory_tree(core_pkgs_to_use) + vendor_collection.root = generate_directory_tree(vendor_pkgs_to_use) + + generate_packages(&b, core_collection, "core") + generate_packages(&b, vendor_collection, "vendor") +} + +generate_packages :: proc(b: ^strings.Builder, collection: ^Collection, dir: string) { + w := strings.to_writer(b) + { - strings.reset_builder(&b) - write_html_header(w, "core library - pkg.odin-lang.org") - write_core_directory(w) + strings.reset_builder(b) + write_html_header(w, fmt.tprintf("%s library - pkg.odin-lang.org", dir)) + write_collection_directory(w, collection) write_html_footer(w, true) - os.make_directory("core", 0) - os.write_entire_file("core/index.html", b.buf[:]) + os.make_directory(dir, 0) + os.write_entire_file(fmt.tprintf("%s/index.html", dir), b.buf[:]) } - for path, pkg in pkgs_to_use { - strings.reset_builder(&b) + for path, pkg in collection.pkgs_to_use { + strings.reset_builder(b) write_html_header(w, fmt.tprintf("package %s - pkg.odin-lang.org", path)) - write_pkg(w, path, pkg) + write_pkg(w, path, pkg, collection) write_html_footer(w, false) - recursive_make_directory(path, "core") - os.write_entire_file(fmt.tprintf("core/%s/index.html", path), b.buf[:]) + recursive_make_directory(path, dir) + os.write_entire_file(fmt.tprintf("%s/%s/index.html", dir, path), b.buf[:]) } } -write_home_page :: proc(w: io.Writer) { - fmt.wprintln(w, `<div class="row odin-main">`) - defer fmt.wprintln(w, `</div>`) - { - fmt.wprintln(w, `<nav class="col-lg-2 odin-sidebar-border navbar-light">`) - defer fmt.wprintln(w, `</nav>`) - fmt.wprintln(w, `<div class="sticky-top odin-below-navbar py-3">`) - defer fmt.wprintln(w, `</div>`) +write_home_sidebar :: proc(w: io.Writer) { + fmt.wprintln(w, `<nav class="col-lg-2 odin-sidebar-border navbar-light">`) + defer fmt.wprintln(w, `</nav>`) + fmt.wprintln(w, `<div class="sticky-top odin-below-navbar py-3">`) + defer fmt.wprintln(w, `</div>`) - fmt.wprintln(w, `<ul class="nav nav-pills d-flex flex-column">`) - fmt.wprintln(w, `<li class="nav-item"><a class="nav-link" href="/core">Core Library</a></li>`) - fmt.wprintln(w, `<li class="nav-item"><a class="nav-link" href="#">Vendor Library</a></li>`) - fmt.wprintln(w, `</ul>`) + fmt.wprintln(w, `<ul class="nav nav-pills d-flex flex-column">`) + fmt.wprintln(w, `<li class="nav-item"><a class="nav-link" href="/core">Core Library</a></li>`) + fmt.wprintln(w, `<li class="nav-item"><a class="nav-link" href="/vendor">Vendor Library</a></li>`) + fmt.wprintln(w, `</ul>`) +} - } +write_home_page :: proc(w: io.Writer) { + fmt.wprintln(w, `<div class="row odin-main">`) + defer fmt.wprintln(w, `</div>`) + write_home_sidebar(w) fmt.wprintln(w, `<article class="col-lg-8 p-4">`) defer fmt.wprintln(w, `</article>`) @@ -270,9 +322,8 @@ write_home_page :: proc(w: io.Writer) { fmt.wprintln(w, `</div>`) fmt.wprintln(w, `<div class="mt-5">`) - fmt.wprintln(w, `<a href="#" class="link-primary text-decoration-node"><h3>Vendor Library Collection</h3></a>`) + fmt.wprintln(w, `<a href="/vendor" class="link-primary text-decoration-node"><h3>Vendor Library Collection</h3></a>`) fmt.wprintln(w, `<p>Documentation for all the packages part of the <code>vendor</code> library collection.</p>`) - fmt.wprintln(w, `<p><em>Coming Soon.</em></p>`) fmt.wprintln(w, `</div>`) @@ -289,7 +340,7 @@ Dir_Node :: struct { children: [dynamic]^Dir_Node, } -generate_directory_tree :: proc() -> (root: ^Dir_Node) { +generate_directory_tree :: proc(pkgs_to_use: map[string]^doc.Pkg) -> (root: ^Dir_Node) { sort_tree :: proc(node: ^Dir_Node) { slice.sort_by_key(node.children[:], proc(node: ^Dir_Node) -> string {return node.name}) for child in node.children { @@ -342,25 +393,46 @@ generate_directory_tree :: proc() -> (root: ^Dir_Node) { return } -write_core_directory :: proc(w: io.Writer) { - root := generate_directory_tree() +write_collection_directory :: proc(w: io.Writer, collection: ^Collection) { + get_line_doc :: proc(pkg: ^doc.Pkg) -> (line_doc: string, ok: bool) { + if pkg == nil { + return + } + line_doc, _, _ = strings.partition(str(pkg.docs), "\n") + line_doc = strings.trim_space(line_doc) + if line_doc == "" { + return + } + switch { + case strings.has_prefix(line_doc, "*"): + return "", false + case strings.has_prefix(line_doc, "Copyright"): + return "", false + } + return line_doc, true + } + fmt.wprintln(w, `<div class="row odin-main">`) defer fmt.wprintln(w, `</div>`) + + + write_home_sidebar(w) + + fmt.wprintln(w, `<article class="col-lg-10 p-4">`) + defer fmt.wprintln(w, `</article>`) { - fmt.wprintln(w, `<article class="col-lg-12 p-4">`) + fmt.wprintln(w, `<article class="p-4">`) fmt.wprintln(w, `<header class="collection-header">`) - fmt.wprintln(w, "<h1>Core Library Collection</h1>") + fmt.wprintf(w, "<h1>%s Library Collection</h1>\n", collection.name) fmt.wprintln(w, "<ul>") fmt.wprintf(w, "<li>License: <a href=\"{0:s}\">BSD-3-Clause</a></li>\n", GITHUB_LICENSE_URL) - fmt.wprintf(w, "<li>Repository: <a href=\"{0:s}\">{0:s}</a></li>\n", GITHUB_CORE_URL) + fmt.wprintf(w, "<li>Repository: <a href=\"{0:s}\">{0:s}</a></li>\n", collection.github_url) fmt.wprintln(w, "</ul>") fmt.wprintln(w, "</header>") fmt.wprintln(w, "</article>") fmt.wprintln(w, `<hr class="collection-hr">`) } - fmt.wprintln(w, `<article class="col-lg-12 p-4">`) - defer fmt.wprintln(w, `</article>`) fmt.wprintln(w, "<header>") fmt.wprintln(w, `<h2><i class="bi bi-folder"></i>Directories</h2>`) @@ -370,7 +442,7 @@ write_core_directory :: proc(w: io.Writer) { fmt.wprintln(w, "\t<table class=\"doc-directory mt-4 mb-4\">") fmt.wprintln(w, "\t\t<tbody>") - for dir in root.children { + for dir in collection.root.children { if len(dir.children) != 0 { fmt.wprint(w, `<tr aria-controls="`) for child in dir.children { @@ -386,18 +458,16 @@ write_core_directory :: proc(w: io.Writer) { } if dir.pkg != nil { - fmt.wprintf(w, `<a href="%s/%s">%s</a>`, BASE_CORE_URL, dir.path, dir.name) + fmt.wprintf(w, `<a href="%s/%s">%s</a>`, collection.base_url, dir.path, dir.name) } else { fmt.wprintf(w, "%s", dir.name) } io.write_string(w, `</td>`) io.write_string(w, `<td class="pkg-line pkg-line-doc">`) - if dir.pkg != nil { - line_doc, _, _ := strings.partition(str(dir.pkg.docs), "\n") - line_doc = strings.trim_space(line_doc) - if line_doc != "" { - write_doc_line(w, line_doc) - } + if line_doc, ok := get_line_doc(dir.pkg); ok { + write_doc_line(w, line_doc) + } else { + io.write_string(w, ` `) } io.write_string(w, `</td>`) fmt.wprintf(w, "</tr>\n") @@ -405,14 +475,16 @@ write_core_directory :: proc(w: io.Writer) { for child in dir.children { assert(child.pkg != nil) fmt.wprintf(w, `<tr id="pkg-%s" class="directory-pkg directory-child"><td class="pkg-line pkg-name">`, str(child.pkg.name)) - fmt.wprintf(w, `<a href="%s/%s/">%s</a>`, BASE_CORE_URL, child.path, child.name) + fmt.wprintf(w, `<a href="%s/%s/">%s</a>`, collection.base_url, child.path, child.name) io.write_string(w, `</td>`) line_doc, _, _ := strings.partition(str(child.pkg.docs), "\n") line_doc = strings.trim_space(line_doc) io.write_string(w, `<td class="pkg-line pkg-line-doc">`) - if line_doc != "" { + if line_doc, ok := get_line_doc(dir.pkg); ok { write_doc_line(w, line_doc) + } else { + io.write_string(w, ` `) } io.write_string(w, `</td>`) @@ -606,6 +678,7 @@ write_type :: proc(using writer: ^Type_Writer, type: doc.Type, flags: Write_Type e := entities[type_entities[0]] name := str(type.name) tn_pkg := files[e.pos.file].pkg + collection: Collection // TODO determine this from package if tn_pkg != pkg { fmt.wprintf(w, `%s.`, str(pkgs[tn_pkg].name)) @@ -613,10 +686,10 @@ write_type :: proc(using writer: ^Type_Writer, type: doc.Type, flags: Write_Type if .Private in e.flags { io.write_string(w, name) } else if n := strings.contains_rune(name, '('); n >= 0 { - fmt.wprintf(w, `<a class="code-typename" href="{2:s}/{0:s}/#{1:s}">{1:s}</a>`, pkg_to_path[&pkgs[tn_pkg]], name[:n], BASE_CORE_URL) + fmt.wprintf(w, `<a class="code-typename" href="{2:s}/{0:s}/#{1:s}">{1:s}</a>`, pkg_to_path[&pkgs[tn_pkg]], name[:n], collection.base_url) io.write_string(w, name[n:]) } else { - fmt.wprintf(w, `<a class="code-typename" href="{2:s}/{0:s}/#{1:s}">{1:s}</a>`, pkg_to_path[&pkgs[tn_pkg]], name, BASE_CORE_URL) + fmt.wprintf(w, `<a class="code-typename" href="{2:s}/{0:s}/#{1:s}">{1:s}</a>`, pkg_to_path[&pkgs[tn_pkg]], name, collection.base_url) } case .Generic: name := str(type.name) @@ -870,6 +943,10 @@ write_doc_line :: proc(w: io.Writer, text: string) { } } +write_doc_sidebar :: proc(w: io.Writer) { + +} + write_docs :: proc(w: io.Writer, pkg: ^doc.Pkg, docs: string) { if docs == "" { return @@ -1002,13 +1079,55 @@ write_docs :: proc(w: io.Writer, pkg: ^doc.Pkg, docs: string) { } } -write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { +write_pkg_sidebar :: proc(w: io.Writer, curr_pkg: ^doc.Pkg, collection: ^Collection) { + + fmt.wprintln(w, `<nav id="pkg-sidebar" class="col-lg-2 odin-sidebar-border navbar-light">`) + defer fmt.wprintln(w, `</nav>`) + fmt.wprintln(w, `<div class="sticky-top odin-below-navbar py-3">`) + defer fmt.wprintln(w, `</div>`) + + fmt.wprintf(w, "<h4>%s Library</h4>\n", collection.name) + + fmt.wprintln(w, `<ul>`) + defer fmt.wprintln(w, `</ul>`) + + for dir in collection.root.children { + fmt.wprint(w, `<li class="nav-item">`) + defer fmt.wprintln(w, `</li>`) + if dir.pkg == curr_pkg { + fmt.wprintf(w, `<a class="active" href="%s/%s">%s</a>`, collection.base_url, dir.path, dir.name) + } else if dir.pkg != nil { + fmt.wprintf(w, `<a href="%s/%s">%s</a>`, collection.base_url, dir.path, dir.name) + } else { + fmt.wprintf(w, "%s", dir.name) + } + if len(dir.children) != 0 { + fmt.wprintln(w, "<ul>") + defer fmt.wprintln(w, "</ul>\n") + for child in dir.children { + fmt.wprint(w, `<li>`) + defer fmt.wprintln(w, `</li>`) + if child.pkg == curr_pkg { + fmt.wprintf(w, `<a class="active" href="%s/%s">%s</a>`, collection.base_url, child.path, child.name) + } else if child.pkg != nil { + fmt.wprintf(w, `<a href="%s/%s">%s</a>`, collection.base_url, child.path, child.name) + } else { + fmt.wprintf(w, "%s", child.name) + } + } + } + } +} + +write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg, collection: ^Collection) { fmt.wprintln(w, `<div class="row odin-main">`) defer fmt.wprintln(w, `</div>`) - fmt.wprintln(w, `<article class="col-lg-9 p-4 documentation odin-article">`) + write_pkg_sidebar(w, pkg, collection) - { // breadcrumbs + fmt.wprintln(w, `<article class="col-lg-8 p-4 documentation odin-article">`) + + if false { // breadcrumbs fmt.wprintln(w, `<div class="row">`) defer fmt.wprintln(w, `</div>`) @@ -1017,7 +1136,7 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { io.write_string(w, "<ol class=\"breadcrumb\">\n") defer io.write_string(w, "</ol>\n") - fmt.wprintf(w, `<li class="breadcrumb-item"><a class="breadcrumb-link" href="%s">core</a></li>`, BASE_CORE_URL) + fmt.wprintf(w, `<li class="breadcrumb-item"><a class="breadcrumb-link" href="%s">core</a></li>`, collection.base_url) dirs := strings.split(path, "/") for dir, i in dirs { @@ -1032,8 +1151,8 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { io.write_string(w, `<li class="breadcrumb-item">`) } - if !is_curr && (short_path in pkgs_to_use) { - fmt.wprintf(w, `<a href="%s/%s">%s</a>`, BASE_CORE_URL, url, dir) + if !is_curr && (short_path in collection.pkgs_to_use) { + fmt.wprintf(w, `<a href="%s/%s">%s</a>`, collection.base_url, url, dir) } else { io.write_string(w, dir) } @@ -1148,6 +1267,8 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { pkg = pkg_index, } defer delete(writer.generic_scope) + collection := pkg_to_collection[pkg] + github_url := collection.github_url if collection != nil else GITHUB_CORE_URL name := str(e.name) path := pkg_to_path[pkg] @@ -1155,7 +1276,7 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { fmt.wprintf(w, "<h3 id=\"{0:s}\"><span><a class=\"doc-id-link\" href=\"#{0:s}\">{0:s}", name) fmt.wprintf(w, "<span class=\"a-hidden\"> ΒΆ</span></a></span>") if e.pos.file != 0 && e.pos.line > 0 { - src_url := fmt.tprintf("%s/%s/%s#L%d", GITHUB_CORE_URL, path, filename, e.pos.line) + src_url := fmt.tprintf("%s/%s/%s#L%d", github_url, path, filename, e.pos.line) fmt.wprintf(w, "<div class=\"doc-source\"><a href=\"{0:s}\"><em>Source</em></a></div>", src_url) } fmt.wprintf(w, "</h3>\n") @@ -1240,8 +1361,10 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { if this_pkg != pkg_index { fmt.wprintf(w, "%s.", str(pkgs[this_pkg].name)) } + pkg := &pkgs[this_pkg] + collection := pkg_to_collection[pkg] name := str(this_proc.name) - fmt.wprintf(w, `<a class="code-procedure" href="{2:s}/{0:s}/#{1:s}">`, pkg_to_path[&pkgs[this_pkg]], name, BASE_CORE_URL) + fmt.wprintf(w, `<a class="code-procedure" href="{2:s}/{0:s}/#{1:s}">`, pkg_to_path[pkg], name, collection.base_url) io.write_string(w, name) io.write_string(w, `</a>`) io.write_byte(w, ',') @@ -1305,7 +1428,7 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { any_hidden = true continue source_file_loop } - fmt.wprintf(w, `<li><a href="%s/%s/%s">%s</a></li>`, GITHUB_CORE_URL, path, filename, filename) + fmt.wprintf(w, `<li><a href="%s/%s/%s">%s</a></li>`, collection.github_url, path, filename, filename) fmt.wprintln(w) } if any_hidden { @@ -1313,6 +1436,13 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { } fmt.wprintln(w, "</ul>") + { + fmt.wprintln(w, `<h2 id="pkg-generation-information">Generation Information</h2>`) + now := time.now() + fmt.wprintf(w, "<p>Generated with <code>odin version %s (vendor %q) %s_%s @ %v</code></p>\n", ODIN_VERSION, ODIN_VENDOR, ODIN_OS, ODIN_ARCH, now) + } + + fmt.wprintln(w, `</article>`) { @@ -1320,7 +1450,7 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { fmt.wprintf(w, `<li><a href="#%s">%s</a>`, id, text) } - fmt.wprintln(w, `<div class="col-lg-3 odin-toc-border navbar-light"><div class="sticky-top odin-below-navbar py-3">`) + fmt.wprintln(w, `<div class="col-lg-2 odin-toc-border navbar-light"><div class="sticky-top odin-below-navbar py-3">`) fmt.wprintln(w, `<nav id="TableOfContents">`) fmt.wprintln(w, `<ul>`) if overview_docs != "" { diff --git a/tools/odin-html-docs/style.css b/tools/odin-html-docs/style.css index cb06a8603..13db2f3c2 100644 --- a/tools/odin-html-docs/style.css +++ b/tools/odin-html-docs/style.css @@ -76,6 +76,7 @@ pre.doc-code a.code-procedure { .pkg-line-doc { color: #444; + width: 100%; } @@ -115,9 +116,7 @@ section.documentation h3 { } details.doc-index > summary { - position: relative; font-size: 1.75rem; - left: -1.75rem; } details.doc-index ul { list-style-type: none; @@ -138,3 +137,27 @@ details.odin-doc-toggle[open] > summary.hideme { details.code-example > summary { font-weight: 700; } + +@media only screen and (max-width: 991px) { + #pkg-sidebar { + display: none; + } +} + +#pkg-sidebar ul { + list-style-type: none; + padding: 0; +} + +#pkg-sidebar li:not(:last-child) { + margin-bottom: 0.25rem; +} + + +#pkg-sidebar li > ul { + padding-left: 1.25rem; +} + +#pkg-sidebar a.active { + font-style: italic; +}
\ No newline at end of file |