From cd6898439e9de6fce42555e2bab5c27e206dbcde Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jan 2022 12:17:13 +0000 Subject: [PATCH 01/37] Comment out `link_section` on procedures --- core/runtime/entry_unix.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/runtime/entry_unix.odin b/core/runtime/entry_unix.odin index 67d2cbcb7..dd1e06625 100644 --- a/core/runtime/entry_unix.odin +++ b/core/runtime/entry_unix.odin @@ -5,13 +5,13 @@ package runtime import "core:intrinsics" when ODIN_BUILD_MODE == .Dynamic { - @(link_name="_odin_entry_point", linkage="strong", require, link_section=".init") + @(link_name="_odin_entry_point", linkage="strong", require/*, link_section=".init"*/) _odin_entry_point :: proc "c" () { context = default_context() #force_no_inline _startup_runtime() intrinsics.__entry_point() } - @(link_name="_odin_exit_point", linkage="strong", require, link_section=".fini") + @(link_name="_odin_exit_point", linkage="strong", require/*, link_section=".fini"*/) _odin_exit_point :: proc "c" () { context = default_context() #force_no_inline _cleanup_runtime() From 686dbb4421824f17164443b2538b587e91d400a5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jan 2022 14:43:42 +0000 Subject: [PATCH 02/37] Correct odin doc comment printing --- src/docs.cpp | 28 ++++++++++++++++++++++------ src/docs_writer.cpp | 5 +++-- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/docs.cpp b/src/docs.cpp index 8d65cb83a..3ea3cce1b 100644 --- a/src/docs.cpp +++ b/src/docs.cpp @@ -67,6 +67,14 @@ GB_COMPARE_PROC(cmp_ast_package_by_name) { #include "docs_format.cpp" #include "docs_writer.cpp" +void print_doc_line(i32 indent, String const &data) { + while (indent --> 0) { + gb_printf("\t"); + } + gb_file_write(gb_file_get_standard(gbFileStandard_Output), data.text, data.len); + gb_printf("\n"); +} + void print_doc_line(i32 indent, char const *fmt, ...) { while (indent --> 0) { gb_printf("\t"); @@ -86,6 +94,13 @@ void print_doc_line_no_newline(i32 indent, char const *fmt, ...) { gb_printf_va(fmt, va); va_end(va); } +void print_doc_line_no_newline(i32 indent, String const &data) { + while (indent --> 0) { + gb_printf("\t"); + } + gb_file_write(gb_file_get_standard(gbFileStandard_Output), data.text, data.len); +} + bool print_doc_comment_group_string(i32 indent, CommentGroup *g) { if (g == nullptr) { @@ -106,8 +121,9 @@ bool print_doc_comment_group_string(i32 indent, CommentGroup *g) { String comment = g->list[i].string; String original_comment = comment; - bool slash_slash = comment[1] == '/'; + bool slash_slash = false; if (comment[1] == '/') { + slash_slash = true; comment.text += 2; comment.len -= 2; } else if (comment[1] == '*') { @@ -131,7 +147,7 @@ bool print_doc_comment_group_string(i32 indent, CommentGroup *g) { } if (slash_slash) { - print_doc_line(indent, "%.*s", LIT(comment)); + print_doc_line(indent, comment); count += 1; } else { isize pos = 0; @@ -143,7 +159,7 @@ bool print_doc_comment_group_string(i32 indent, CommentGroup *g) { } } String line = substring(comment, pos, end); - pos = end+1; + pos = end; String trimmed_line = string_trim_whitespace(line); if (trimmed_line.len == 0) { if (count == 0) { @@ -159,7 +175,7 @@ bool print_doc_comment_group_string(i32 indent, CommentGroup *g) { line = substring(line, 2, line.len); } - print_doc_line(indent, "%.*s", LIT(line)); + print_doc_line(indent, line); count += 1; } } @@ -263,7 +279,7 @@ void print_doc_package(CheckerInfo *info, AstPackage *pkg) { } GB_ASSERT(type_expr != nullptr || init_expr != nullptr); - print_doc_line_no_newline(2, "%.*s", LIT(e->token.string)); + print_doc_line_no_newline(2, e->token.string); if (type_expr != nullptr) { gbString t = expr_to_string(type_expr); gb_printf(": %s ", t); @@ -298,7 +314,7 @@ void print_doc_package(CheckerInfo *info, AstPackage *pkg) { for_array(i, pkg->files) { AstFile *f = pkg->files[i]; String filename = remove_directory_from_path(f->fullpath); - print_doc_line(2, "%.*s", LIT(filename)); + print_doc_line(2, filename); } } diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index 56ad0561e..94b43be99 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -292,8 +292,9 @@ bool odin_doc_append_comment_group_string(Array *buf, CommentGroup *g) { String comment = g->list[i].string; String original_comment = comment; - bool slash_slash = comment[1] == '/'; + bool slash_slash = false; if (comment[1] == '/') { + slash_slash = true; comment.text += 2; comment.len -= 2; } else if (comment[1] == '*') { @@ -330,7 +331,7 @@ bool odin_doc_append_comment_group_string(Array *buf, CommentGroup *g) { } } String line = substring(comment, pos, end); - pos = end+1; + pos = end; String trimmed_line = string_trim_whitespace(line); if (trimmed_line.len == 0) { if (count == 0) { From 76ccce2942a0d527be5693ff5bedbf92a5de5eb2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jan 2022 17:57:55 +0000 Subject: [PATCH 03/37] Begin work on a html doc printer --- tools/odin-html-docs/odin_html_docs_main.odin | 609 ++++++++++++++++++ tools/odin-html-docs/style.css | 31 + 2 files changed, 640 insertions(+) create mode 100644 tools/odin-html-docs/odin_html_docs_main.odin create mode 100644 tools/odin-html-docs/style.css diff --git a/tools/odin-html-docs/odin_html_docs_main.odin b/tools/odin-html-docs/odin_html_docs_main.odin new file mode 100644 index 000000000..7c822e4a1 --- /dev/null +++ b/tools/odin-html-docs/odin_html_docs_main.odin @@ -0,0 +1,609 @@ +package odin_html_docs + +import doc "core:odin/doc-format" +import "core:fmt" +import "core:io" +import "core:os" +import "core:strings" +import "core:path/slashpath" +import "core:sort" +import "core:slice" + +header: ^doc.Header +files: []doc.File +pkgs: []doc.Pkg +entities: []doc.Entity +types: []doc.Type + +pkgs_to_use: map[string]^doc.Pkg // trimmed path +pkg_to_path: map[^doc.Pkg]string // trimmed path + +array :: proc(a: $A/doc.Array($T)) -> []T { + return doc.from_array(header, a) +} +str :: proc(s: $A/doc.String) -> string { + return doc.from_string(header, s) +} + +errorf :: proc(format: string, args: ..any) -> ! { + fmt.eprintf("%s ", os.args[0]) + fmt.eprintf(format, ..args) + fmt.eprintln() + os.exit(1) +} + +common_prefix :: proc(strs: []string) -> string { + if len(strs) == 0 { + return "" + } + n := max(int) + for str in strs { + n = min(n, len(str)) + } + + prefix := strs[0][:n] + for str in strs[1:] { + for len(prefix) != 0 && str[:len(prefix)] != prefix { + prefix = prefix[:len(prefix)-1] + } + if len(prefix) == 0 { + break + } + } + return prefix +} + + +write_html_header :: proc(w: io.Writer, title: string) { + fmt.wprintf(w, ` + + + + + %s + + + + + + +`, title) + fmt.wprintln(w, "\n
") + fmt.wprintln(w, "\nCore Directory") + +} + +write_html_footer :: proc(w: io.Writer) { + fmt.wprintf(w, "
\n\n") +} + +main :: proc() { + if len(os.args) != 2 { + errorf("expected 1 .odin-doc file") + } + data, ok := os.read_entire_file(os.args[1]) + if !ok { + errorf("unable to read file:", os.args[1]) + } + err: doc.Reader_Error + header, err = doc.read_from_bytes(data) + switch err { + case .None: + case .Header_Too_Small: + errorf("file is too small for the file format") + case .Invalid_Magic: + errorf("invalid magic for the file format") + case .Data_Too_Small: + errorf("data is too small for the file format") + case .Invalid_Version: + errorf("invalid file format version") + } + files = array(header.files) + pkgs = array(header.pkgs) + entities = array(header.entities) + types = array(header.types) + + fullpaths: [dynamic]string + defer delete(fullpaths) + + for pkg in pkgs[1:] { + append(&fullpaths, str(pkg.fullpath)) + } + path_prefix := common_prefix(fullpaths[:]) + + pkgs_to_use = make(map[string]^doc.Pkg) + for fullpath, i in fullpaths { + path := strings.trim_prefix(fullpath, path_prefix) + if strings.has_prefix(path, "core/") { + pkgs_to_use[strings.trim_prefix(path, "core/")] = &pkgs[i+1] + } + } + sort.map_entries_by_key(&pkgs_to_use) + for path, pkg in pkgs_to_use { + pkg_to_path[pkg] = path + } + + b := strings.make_builder() + w := strings.to_writer(&b) + { + strings.reset_builder(&b) + write_html_header(w, "core library - pkg.odin-lang.org") + write_core_directory(w) + write_html_footer(w) + os.make_directory("core", 0) + os.write_entire_file("core/index.html", b.buf[:]) + } + + for path, pkg in 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_html_footer(w) + os.make_directory(fmt.tprintf("core/%s", path), 0) + os.write_entire_file(fmt.tprintf("core/%s/index.html", path), b.buf[:]) + } +} + + +write_core_directory :: proc(w: io.Writer) { + Node :: struct { + dir: string, + path: string, + name: string, + pkg: ^doc.Pkg, + next: ^Node, + first_child: ^Node, + } + add_child :: proc(parent: ^Node, child: ^Node) -> ^Node { + assert(parent != nil) + end := &parent.first_child + for end^ != nil { + end = &end^.next + } + child.next = end^ + end^ = child + return child + } + + root: Node + for path, pkg in pkgs_to_use { + dir, _, inner := strings.partition(path, "/") + + node: ^Node = nil + for node = root.first_child; node != nil; node = node.next { + if node.dir == dir { + break + } + } + if inner == "" { + if node == nil { + add_child(&root, new_clone(Node{ + dir = dir, + name = dir, + path = path, + pkg = pkg, + })) + } else { + node.dir = dir + node.name = dir + node.path = path + node.pkg = pkg + } + } else { + if node == nil { + node = add_child(&root, new_clone(Node{ + dir = dir, + name = dir, + })) + } + assert(node != nil) + child := add_child(node, new_clone(Node{ + dir = dir, + name = inner, + path = path, + pkg = pkg, + })) + } + } + + + fmt.wprintln(w, "

Directories

") + + fmt.wprintln(w, "\t") + fmt.wprintln(w, "\t\t") + + for dir := root.first_child; dir != nil; dir = dir.next { + if dir.first_child != nil { + fmt.wprint(w, `") + if dir.pkg != nil { + line_doc, _, _ := strings.partition(str(dir.pkg.docs), "\n") + line_doc = strings.trim_space(line_doc) + if line_doc != "" { + fmt.wprintf(w, ``, line_doc) + } + } + fmt.wprintf(w, "\n") + + for child := dir.first_child; child != nil; child = child.next { + assert(child.pkg != nil) + fmt.wprintf(w, `") + + line_doc, _, _ := strings.partition(str(child.pkg.docs), "\n") + line_doc = strings.trim_space(line_doc) + if line_doc != "" { + fmt.wprintf(w, ``, line_doc) + } + + fmt.wprintf(w, "\n") + } + } + + fmt.wprintln(w, "\t\t") + fmt.wprintln(w, "\t
`, dir.dir) + } else { + fmt.wprintf(w, `
`, dir.dir) + } + + if dir.pkg != nil { + fmt.wprintf(w, `%s`, dir.path, dir.name) + } else { + fmt.wprintf(w, "%s", dir.name) + } + fmt.wprintf(w, "%s
`, str(child.pkg.name)) + fmt.wprintf(w, `%s`, child.path, child.name) + fmt.wprintf(w, "%s
") +} + +is_entity_blank :: proc(e: doc.Entity_Index) -> bool { + name := str(entities[e].name) + return name == "" || name == "_" +} + +Write_Type_Flag :: enum { + Is_Results, + Variadic, +} +Write_Type_Flags :: distinct bit_set[Write_Type_Flag] + +write_type :: proc(w: io.Writer, pkg: doc.Pkg_Index, type: doc.Type, flags: Write_Type_Flags) { + type_entites := array(type.entities) + type_types := array(type.types) + switch type.kind { + case .Invalid: + // ignore + case .Basic: + type_flags := transmute(doc.Type_Flags_Basic)type.flags + if .Untyped in type_flags { + io.write_string(w, str(type.name)) + } else { + fmt.wprintf(w, `%s`, str(type.name)) + } + case .Named: + e := entities[type_entites[0]] + name := str(type.name) + fmt.wprintf(w, ``) + tn_pkg := files[e.pos.file].pkg + if tn_pkg != pkg { + fmt.wprintf(w, `%s.`, str(pkgs[pkg].name)) + } + fmt.wprintf(w, `{1:s}`, pkg_to_path[&pkgs[tn_pkg]], name) + case .Generic: + name := str(type.name) + io.write_byte(w, '$') + io.write_string(w, name) + if len(array(type.types)) == 1 { + io.write_byte(w, '/') + write_type(w, pkg, types[type_types[0]], flags) + } + case .Pointer: + io.write_byte(w, '^') + write_type(w, pkg, types[type_types[0]], flags) + case .Array: + assert(type.elem_count_len == 1) + io.write_byte(w, '[') + io.write_uint(w, uint(type.elem_counts[0])) + io.write_byte(w, ']') + write_type(w, pkg, types[type_types[0]], flags) + case .Enumerated_Array: + io.write_byte(w, '[') + write_type(w, pkg, types[type_types[0]], flags) + io.write_byte(w, ']') + write_type(w, pkg, types[type_types[1]], flags) + case .Slice: + if .Variadic in flags { + io.write_string(w, "..") + } else { + io.write_string(w, "[]") + } + write_type(w, pkg, types[type_types[0]], flags - {.Variadic}) + case .Dynamic_Array: + io.write_string(w, "[dynamic]") + write_type(w, pkg, types[type_types[0]], flags) + case .Map: + io.write_string(w, "map[") + write_type(w, pkg, types[type_types[0]], flags) + io.write_byte(w, ']') + write_type(w, pkg, types[type_types[1]], flags) + case .Struct: + type_flags := transmute(doc.Type_Flags_Struct)type.flags + io.write_string(w, "struct {}") + case .Union: + type_flags := transmute(doc.Type_Flags_Union)type.flags + io.write_string(w, "union {}") + case .Enum: + io.write_string(w, "enum {}") + case .Tuple: + entity_indices := type_entites + if len(entity_indices) == 0 { + return + } + require_parens := (.Is_Results in flags) && (len(entity_indices) > 1 || !is_entity_blank(entity_indices[0])) + if require_parens { io.write_byte(w, '(') } + for entity_index, i in entity_indices { + e := &entities[entity_index] + name := str(e.name) + + if i > 0 { + io.write_string(w, ", ") + } + if .Param_Using in e.flags { io.write_string(w, "using ") } + if .Param_Const in e.flags { io.write_string(w, "#const ") } + if .Param_Auto_Cast in e.flags { io.write_string(w, "#auto_cast ") } + if .Param_CVararg in e.flags { io.write_string(w, "#c_vararg ") } + if .Param_No_Alias in e.flags { io.write_string(w, "#no_alias ") } + if .Param_Any_Int in e.flags { io.write_string(w, "#any_int ") } + + if name != "" { + io.write_string(w, name) + io.write_string(w, ": ") + } + param_flags := flags - {.Is_Results} + if .Param_Ellipsis in e.flags { + param_flags += {.Variadic} + } + write_type(w, pkg, types[e.type], param_flags) + } + if require_parens { io.write_byte(w, ')') } + + case .Proc: + type_flags := transmute(doc.Type_Flags_Proc)type.flags + io.write_string(w, "proc") + cc := str(type.calling_convention) + if cc != "" { + io.write_byte(w, ' ') + io.write_quoted_string(w, cc) + io.write_byte(w, ' ') + } + params := array(type.types)[0] + results := array(type.types)[1] + io.write_byte(w, '(') + write_type(w, pkg, types[params], flags) + io.write_byte(w, ')') + if results != 0 { + assert(.Diverging not_in type_flags) + io.write_string(w, " -> ") + write_type(w, pkg, types[results], flags+{.Is_Results}) + } + if .Diverging in type_flags { + io.write_string(w, " -> !") + } + if .Optional_Ok in type_flags { + io.write_string(w, " #optional_ok") + } + + case .Bit_Set: + type_flags := transmute(doc.Type_Flags_Bit_Set)type.flags + case .Simd_Vector: + io.write_string(w, "#simd[") + io.write_uint(w, uint(type.elem_counts[0])) + io.write_byte(w, ']') + case .SOA_Struct_Fixed: + io.write_string(w, "#soa[") + io.write_uint(w, uint(type.elem_counts[0])) + io.write_byte(w, ']') + case .SOA_Struct_Slice: + io.write_string(w, "#soa[]") + case .SOA_Struct_Dynamic: + io.write_string(w, "#soa[dynamic]") + case .Relative_Pointer: + io.write_string(w, "#relative(") + write_type(w, pkg, types[type_types[1]], flags) + io.write_string(w, ") ") + write_type(w, pkg, types[type_types[0]], flags) + case .Relative_Slice: + io.write_string(w, "#relative(") + write_type(w, pkg, types[type_types[1]], flags) + io.write_string(w, ") ") + write_type(w, pkg, types[type_types[0]], flags) + case .Multi_Pointer: + io.write_string(w, "[^]") + write_type(w, pkg, types[type_types[0]], flags) + case .Matrix: + io.write_string(w, "matrix[") + io.write_uint(w, uint(type.elem_counts[0])) + io.write_string(w, ", ") + io.write_uint(w, uint(type.elem_counts[1])) + io.write_string(w, "]") + write_type(w, pkg, types[type_types[0]], flags) + } +} + +write_docs :: proc(w: io.Writer, pkg: ^doc.Pkg, docs: string) { + if docs == "" { + return + } + it := docs + was_code := true + was_paragraph := true + for line in strings.split_iterator(&it, "\n") { + if strings.has_prefix(line, "\t") { + if !was_code { + was_code = true; + fmt.wprint(w, `
`)
+			}
+			fmt.wprintf(w, "%s\n", strings.trim_prefix(line, "\t"))
+			continue
+		} else if was_code {
+			was_code = false
+			fmt.wprintln(w, "
") + } + text := strings.trim_space(line) + if text == "" { + if was_paragraph { + was_paragraph = false + fmt.wprintln(w, "

") + } + continue + } + if !was_paragraph { + fmt.wprintln(w, "

") + } + assert(!was_code) + was_paragraph = true + fmt.wprintln(w, text) + } + if was_code { + // assert(!was_paragraph, str(pkg.name)) + was_code = false + fmt.wprintln(w, "") + } else if was_paragraph { + fmt.wprintln(w, "

") + } +} + +write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { + fmt.wprintf(w, "

package core:%s

\n", path) + fmt.wprintln(w, "

Documentation

") + docs := strings.trim_space(str(pkg.docs)) + if docs != "" { + fmt.wprintln(w, "

Overview

") + fmt.wprintln(w, "
") + defer fmt.wprintln(w, "
") + + write_docs(w, pkg, docs) + } + + fmt.wprintln(w, "

Index

") + fmt.wprintln(w, `
`) + pkg_procs: [dynamic]^doc.Entity + pkg_proc_groups: [dynamic]^doc.Entity + pkg_types: [dynamic]^doc.Entity + pkg_vars: [dynamic]^doc.Entity + pkg_consts: [dynamic]^doc.Entity + + for entity_index in array(pkg.entities) { + e := &entities[entity_index] + name := str(e.name) + if name == "" || name[0] == '_' { + continue + } + switch e.kind { + case .Invalid, .Import_Name, .Library_Name: + // ignore + case .Constant: append(&pkg_consts, e) + case .Variable: append(&pkg_vars, e) + case .Type_Name: append(&pkg_types, e) + case .Procedure: append(&pkg_procs, e) + case .Proc_Group: append(&pkg_proc_groups, e) + } + } + + entity_key :: proc(e: ^doc.Entity) -> string { + return str(e.name) + } + + slice.sort_by_key(pkg_procs[:], entity_key) + slice.sort_by_key(pkg_proc_groups[:], entity_key) + slice.sort_by_key(pkg_types[:], entity_key) + slice.sort_by_key(pkg_vars[:], entity_key) + slice.sort_by_key(pkg_consts[:], entity_key) + + print_index :: proc(w: io.Writer, name: string, entities: []^doc.Entity) { + fmt.wprintf(w, "

%s

\n", name) + fmt.wprintln(w, `
`) + fmt.wprintln(w, "
    ") + for e in entities { + name := str(e.name) + fmt.wprintf(w, "
  • {0:s}
  • \n", name) + } + fmt.wprintln(w, "
") + fmt.wprintln(w, "
") + } + + + print_index(w, "Procedures", pkg_procs[:]) + print_index(w, "Procedure Groups", pkg_proc_groups[:]) + print_index(w, "Types", pkg_types[:]) + print_index(w, "Variables", pkg_vars[:]) + print_index(w, "Constants", pkg_consts[:]) + + fmt.wprintln(w, "
") + + + print_entity :: proc(w: io.Writer, e: ^doc.Entity) { + pkg := &pkgs[files[e.pos.file].pkg] + name := str(e.name) + fmt.wprintf(w, "

{0:s}

\n", name) + switch e.kind { + case .Invalid, .Import_Name, .Library_Name: + // ignore + case .Constant: + case .Variable: + case .Type_Name: + case .Procedure: + fmt.wprint(w, "
")
+			fmt.wprintf(w, "%s :: ", name)
+			write_type(w, files[e.pos.file].pkg, types[e.type], nil)
+			where_clauses := array(e.where_clauses)
+			if len(where_clauses) != 0 {
+				io.write_string(w, " where ")
+				for clause, i in where_clauses {
+					if i > 0 {
+						io.write_string(w, ", ")
+					}
+					io.write_string(w, str(clause))
+				}
+			}
+
+			fmt.wprint(w, " {…}")
+			fmt.wprintln(w, "
") + case .Proc_Group: + } + + write_docs(w, pkg, strings.trim_space(str(e.docs))) + } + print_entities :: proc(w: io.Writer, title: string, entities: []^doc.Entity) { + fmt.wprintf(w, "

%s

\n", title) + fmt.wprintln(w, `
`) + for e in entities { + print_entity(w, e) + } + fmt.wprintln(w, "
") + } + + print_entities(w, "Procedures", pkg_procs[:]) + print_entities(w, "Procedure Groups", pkg_proc_groups[:]) + print_entities(w, "Types", pkg_types[:]) + print_entities(w, "Variables", pkg_vars[:]) + print_entities(w, "Constants", pkg_consts[:]) + + + fmt.wprintln(w, "

Source Files

") + fmt.wprintln(w, "
    ") + for file_index in array(pkg.files) { + file := files[file_index] + filename := slashpath.base(str(file.name)) + fmt.wprintf(w, `
  • %s
  • `, path, filename, filename) + fmt.wprintln(w) + } + fmt.wprintln(w, "
") + +} \ No newline at end of file diff --git a/tools/odin-html-docs/style.css b/tools/odin-html-docs/style.css new file mode 100644 index 000000000..7c23d0bc7 --- /dev/null +++ b/tools/odin-html-docs/style.css @@ -0,0 +1,31 @@ +.container { + max-width: 60em; + margin: 0 auto; + padding-left: 0.01em 1em; +} + +.directory-pkg { + width: 20em; +} + +.directory-child .pkg-name { + position: relative; + left: 2em; + width: 18em; +} + +pre { + white-space: pre; + tab-size: 8; + background-color: #f8f8f8; + color: #202224; + border: 1px solid #c6c8ca; + border-radius: 0.25rem; + padding: 0.625rem; +} + +.documentation pre a { + text-decoration: none; + font-weight: bold; + color: #00bfd5; +} \ No newline at end of file From 97922406fec4296ce0732d1eefa0b9d7c943086f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jan 2022 18:23:30 +0000 Subject: [PATCH 04/37] Improve printing for record types --- tools/odin-html-docs/odin_html_docs_main.odin | 253 ++++++++++++++---- 1 file changed, 200 insertions(+), 53 deletions(-) diff --git a/tools/odin-html-docs/odin_html_docs_main.odin b/tools/odin-html-docs/odin_html_docs_main.odin index 7c822e4a1..3cbc0d860 100644 --- a/tools/odin-html-docs/odin_html_docs_main.odin +++ b/tools/odin-html-docs/odin_html_docs_main.odin @@ -32,6 +32,17 @@ errorf :: proc(format: string, args: ..any) -> ! { os.exit(1) } +base_type :: proc(t: doc.Type) -> doc.Type { + t := t + for { + if t.kind != .Named { + break + } + t = types[array(t.types)[0]] + } + return t +} + common_prefix :: proc(strs: []string) -> string { if len(strs) == 0 { return "" @@ -270,10 +281,74 @@ is_entity_blank :: proc(e: doc.Entity_Index) -> bool { Write_Type_Flag :: enum { Is_Results, Variadic, + Allow_Indent, } Write_Type_Flags :: distinct bit_set[Write_Type_Flag] +Type_Writer :: struct { + w: io.Writer, + pkg: doc.Pkg_Index, + indent: int, +} + +write_type :: proc(using writer: ^Type_Writer, type: doc.Type, flags: Write_Type_Flags) { + write_param_entity :: proc(using writer: ^Type_Writer, e: ^doc.Entity, flags: Write_Type_Flags, name_width := 0) { + name := str(e.name) + + if .Param_Using in e.flags { io.write_string(w, "using ") } + if .Param_Const in e.flags { io.write_string(w, "#const ") } + if .Param_Auto_Cast in e.flags { io.write_string(w, "#auto_cast ") } + if .Param_CVararg in e.flags { io.write_string(w, "#c_vararg ") } + if .Param_No_Alias in e.flags { io.write_string(w, "#no_alias ") } + if .Param_Any_Int in e.flags { io.write_string(w, "#any_int ") } + + if name != "" { + io.write_string(w, name) + io.write_string(w, ": ") + } + padding := max(name_width-len(name), 0) + for _ in 0.. 0 { + io.write_string(w, ", ") + } + write_param_entity(writer, &entities[entity_index], flags) + } + io.write_byte(w, ')') + } + do_indent :: proc(using writer: ^Type_Writer, flags: Write_Type_Flags) { + if .Allow_Indent not_in flags { + return + } + for _ in 0.. (name_width: int) { + for entity_index in type_entites { + e := &entities[entity_index] + name := str(e.name) + name_width = max(len(name), name_width) + } + return + } + -write_type :: proc(w: io.Writer, pkg: doc.Pkg_Index, type: doc.Type, flags: Write_Type_Flags) { type_entites := array(type.entities) type_types := array(type.types) switch type.kind { @@ -301,75 +376,128 @@ write_type :: proc(w: io.Writer, pkg: doc.Pkg_Index, type: doc.Type, flags: Writ io.write_string(w, name) if len(array(type.types)) == 1 { io.write_byte(w, '/') - write_type(w, pkg, types[type_types[0]], flags) + write_type(writer, types[type_types[0]], flags) } case .Pointer: io.write_byte(w, '^') - write_type(w, pkg, types[type_types[0]], flags) + write_type(writer, types[type_types[0]], flags) case .Array: assert(type.elem_count_len == 1) io.write_byte(w, '[') io.write_uint(w, uint(type.elem_counts[0])) io.write_byte(w, ']') - write_type(w, pkg, types[type_types[0]], flags) + write_type(writer, types[type_types[0]], flags) case .Enumerated_Array: io.write_byte(w, '[') - write_type(w, pkg, types[type_types[0]], flags) + write_type(writer, types[type_types[0]], flags) io.write_byte(w, ']') - write_type(w, pkg, types[type_types[1]], flags) + write_type(writer, types[type_types[1]], flags) case .Slice: if .Variadic in flags { io.write_string(w, "..") } else { io.write_string(w, "[]") } - write_type(w, pkg, types[type_types[0]], flags - {.Variadic}) + write_type(writer, types[type_types[0]], flags - {.Variadic}) case .Dynamic_Array: io.write_string(w, "[dynamic]") - write_type(w, pkg, types[type_types[0]], flags) + write_type(writer, types[type_types[0]], flags) case .Map: io.write_string(w, "map[") - write_type(w, pkg, types[type_types[0]], flags) + write_type(writer, types[type_types[0]], flags) io.write_byte(w, ']') - write_type(w, pkg, types[type_types[1]], flags) + write_type(writer, types[type_types[1]], flags) case .Struct: type_flags := transmute(doc.Type_Flags_Struct)type.flags - io.write_string(w, "struct {}") + io.write_string(w, "struct") + if .Polymorphic in type_flags { + write_poly_params(writer, type, flags) + } + if .Packed in type_flags { io.write_string(w, " #packed") } + if .Raw_Union in type_flags { io.write_string(w, " #raw_union") } + if custom_align := str(type.custom_align); custom_align != "" { + io.write_string(w, " #align") + io.write_string(w, custom_align) + } + io.write_string(w, " {") + do_newline(writer, flags) + indent += 1 + name_width := calc_name_width(type_entites) + + for entity_index in type_entites { + e := &entities[entity_index] + do_indent(writer, flags) + write_param_entity(writer, e, flags, name_width) + io.write_byte(w, ',') + do_newline(writer, flags) + } + indent -= 1 + do_indent(writer, flags) + io.write_string(w, "}") case .Union: type_flags := transmute(doc.Type_Flags_Union)type.flags - io.write_string(w, "union {}") + io.write_string(w, "union") + if .Polymorphic in type_flags { + write_poly_params(writer, type, flags) + } + if .No_Nil in type_flags { io.write_string(w, " #no_nil") } + if .Maybe in type_flags { io.write_string(w, " #maybe") } + if custom_align := str(type.custom_align); custom_align != "" { + io.write_string(w, " #align") + io.write_string(w, custom_align) + } + io.write_string(w, " {") + if len(type_types) > 1 { + do_newline(writer, flags) + indent += 1 + for type_index in type_types { + do_indent(writer, flags) + write_type(writer, types[type_index], flags) + io.write_string(w, ", ") + do_newline(writer, flags) + } + indent -= 1 + do_indent(writer, flags) + } + io.write_string(w, "}") case .Enum: - io.write_string(w, "enum {}") + io.write_string(w, "enum") + io.write_string(w, " {") + do_newline(writer, flags) + indent += 1 + + name_width := calc_name_width(type_entites) + + for entity_index in type_entites { + e := &entities[entity_index] + + do_indent(writer, flags) + io.write_string(w, str(e.name)) + + if init_string := str(e.init_string); init_string != "" { + for _ in 0.. 1 || !is_entity_blank(entity_indices[0])) + require_parens := (.Is_Results in flags) && (len(type_entites) > 1 || !is_entity_blank(type_entites[0])) if require_parens { io.write_byte(w, '(') } - for entity_index, i in entity_indices { - e := &entities[entity_index] - name := str(e.name) - + for entity_index, i in type_entites { if i > 0 { io.write_string(w, ", ") } - if .Param_Using in e.flags { io.write_string(w, "using ") } - if .Param_Const in e.flags { io.write_string(w, "#const ") } - if .Param_Auto_Cast in e.flags { io.write_string(w, "#auto_cast ") } - if .Param_CVararg in e.flags { io.write_string(w, "#c_vararg ") } - if .Param_No_Alias in e.flags { io.write_string(w, "#no_alias ") } - if .Param_Any_Int in e.flags { io.write_string(w, "#any_int ") } - - if name != "" { - io.write_string(w, name) - io.write_string(w, ": ") - } - param_flags := flags - {.Is_Results} - if .Param_Ellipsis in e.flags { - param_flags += {.Variadic} - } - write_type(w, pkg, types[e.type], param_flags) + write_param_entity(writer, &entities[entity_index], flags) } if require_parens { io.write_byte(w, ')') } @@ -385,12 +513,12 @@ write_type :: proc(w: io.Writer, pkg: doc.Pkg_Index, type: doc.Type, flags: Writ params := array(type.types)[0] results := array(type.types)[1] io.write_byte(w, '(') - write_type(w, pkg, types[params], flags) + write_type(writer, types[params], flags) io.write_byte(w, ')') if results != 0 { assert(.Diverging not_in type_flags) io.write_string(w, " -> ") - write_type(w, pkg, types[results], flags+{.Is_Results}) + write_type(writer, types[results], flags+{.Is_Results}) } if .Diverging in type_flags { io.write_string(w, " -> !") @@ -415,24 +543,24 @@ write_type :: proc(w: io.Writer, pkg: doc.Pkg_Index, type: doc.Type, flags: Writ io.write_string(w, "#soa[dynamic]") case .Relative_Pointer: io.write_string(w, "#relative(") - write_type(w, pkg, types[type_types[1]], flags) + write_type(writer, types[type_types[1]], flags) io.write_string(w, ") ") - write_type(w, pkg, types[type_types[0]], flags) + write_type(writer, types[type_types[0]], flags) case .Relative_Slice: io.write_string(w, "#relative(") - write_type(w, pkg, types[type_types[1]], flags) + write_type(writer, types[type_types[1]], flags) io.write_string(w, ") ") - write_type(w, pkg, types[type_types[0]], flags) + write_type(writer, types[type_types[0]], flags) case .Multi_Pointer: io.write_string(w, "[^]") - write_type(w, pkg, types[type_types[0]], flags) + write_type(writer, types[type_types[0]], flags) case .Matrix: io.write_string(w, "matrix[") io.write_uint(w, uint(type.elem_counts[0])) io.write_string(w, ", ") io.write_uint(w, uint(type.elem_counts[1])) io.write_string(w, "]") - write_type(w, pkg, types[type_types[0]], flags) + write_type(writer, types[type_types[0]], flags) } } @@ -529,12 +657,16 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { print_index :: proc(w: io.Writer, name: string, entities: []^doc.Entity) { fmt.wprintf(w, "

%s

\n", name) fmt.wprintln(w, `
`) - fmt.wprintln(w, "
    ") - for e in entities { - name := str(e.name) - fmt.wprintf(w, "
  • {0:s}
  • \n", name) + if len(entities) == 0 { + io.write_string(w, "

    This section is empty.

    \n") + } else { + fmt.wprintln(w, "
      ") + for e in entities { + name := str(e.name) + fmt.wprintf(w, "
    • {0:s}
    • \n", name) + } + fmt.wprintln(w, "
    ") } - fmt.wprintln(w, "
") fmt.wprintln(w, "
") } @@ -549,7 +681,13 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { print_entity :: proc(w: io.Writer, e: ^doc.Entity) { - pkg := &pkgs[files[e.pos.file].pkg] + pkg_index := files[e.pos.file].pkg + pkg := &pkgs[pkg_index] + writer := &Type_Writer{ + w = w, + pkg = pkg_index, + } + name := str(e.name) fmt.wprintf(w, "

{0:s}

\n", name) switch e.kind { @@ -558,10 +696,15 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { case .Constant: case .Variable: case .Type_Name: + fmt.wprint(w, "
")
+			fmt.wprintf(w, "%s :: ", name)
+			tn := base_type(types[e.type])
+			write_type(writer, tn, {.Allow_Indent})
+			fmt.wprintln(w, "
") case .Procedure: fmt.wprint(w, "
")
 			fmt.wprintf(w, "%s :: ", name)
-			write_type(w, files[e.pos.file].pkg, types[e.type], nil)
+			write_type(writer, types[e.type], nil)
 			where_clauses := array(e.where_clauses)
 			if len(where_clauses) != 0 {
 				io.write_string(w, " where ")
@@ -583,8 +726,12 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) {
 	print_entities :: proc(w: io.Writer, title: string, entities: []^doc.Entity) {
 		fmt.wprintf(w, "

%s

\n", title) fmt.wprintln(w, `
`) - for e in entities { - print_entity(w, e) + if len(entities) == 0 { + io.write_string(w, "

This section is empty.

\n") + } else { + for e in entities { + print_entity(w, e) + } } fmt.wprintln(w, "
") } From c85ac955f798fefd149a5eeaecabf0713210b152 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jan 2022 19:00:47 +0000 Subject: [PATCH 05/37] Simplify docs to hide the copyright --- core/compress/common.odin | 3 +++ core/encoding/hxa/doc.odin | 12 ++++++------ core/fmt/doc.odin | 2 +- core/image/common.odin | 2 ++ core/image/png/png.odin | 5 +++++ core/math/big/api.odin | 6 ++---- core/math/big/common.odin | 6 ++---- core/math/big/doc.odin | 28 ++++++++++++++++++++++++++++ core/math/big/helpers.odin | 6 ++---- core/math/big/internal.odin | 28 ++-------------------------- core/math/big/logical.odin | 2 ++ core/math/big/prime.odin | 2 ++ core/math/big/private.odin | 2 ++ core/math/big/public.odin | 2 ++ core/math/big/radix.odin | 2 ++ core/math/big/tune.odin | 2 ++ 16 files changed, 65 insertions(+), 45 deletions(-) create mode 100644 core/math/big/doc.odin diff --git a/core/compress/common.odin b/core/compress/common.odin index 41f292b6f..5f5ef2413 100644 --- a/core/compress/common.odin +++ b/core/compress/common.odin @@ -5,6 +5,9 @@ List of contributors: Jeroen van Rijn: Initial implementation, optimization. */ + + +// package compress is a collection of utilities to aid with other compression packages package compress import "core:io" diff --git a/core/encoding/hxa/doc.odin b/core/encoding/hxa/doc.odin index 16b94a243..230d6ea66 100644 --- a/core/encoding/hxa/doc.odin +++ b/core/encoding/hxa/doc.odin @@ -27,7 +27,7 @@ // Construction history, or BSP trees would make the format too large to serve its purpose. // The facilities of the formats to store meta data should make the format flexible enough // for most uses. Adding HxA support should be something anyone can do in a days work. - +// // Structure: // ---------- // HxA is designed to be extremely simple to parse, and is therefore based around conventions. It has @@ -45,17 +45,17 @@ // of a number of named layers. All layers in the stack have the same number of elements. Each layer // describes one property of the primitive. Each layer can have multiple channels and each layer can // store data of a different type. - +// // HaX stores 3 kinds of nodes // - Pixel data. // - Polygon geometry data. // - Meta data only. - +// // Pixel Nodes stores pixels in a layer stack. A layer may store things like Albedo, Roughness, // Reflectance, Light maps, Masks, Normal maps, and Displacement. Layers use the channels of the // layers to store things like color. The length of the layer stack is determined by the type and // dimensions stored in the - +// // Geometry data is stored in 3 separate layer stacks for: vertex data, corner data and face data. The // vertex data stores things like verities, blend shapes, weight maps, and vertex colors. The first // layer in a vertex stack has to be a 3 channel layer named "position" describing the base position @@ -63,7 +63,7 @@ // for things like UV, normals, and adjacency. The first layer in a corner stack has to be a 1 channel // integer layer named "index" describing the vertices used to form polygons. The last value in each // polygon has a negative - 1 index to indicate the end of the polygon. - +// // Example: // A quad and a tri with the vertex index: // [0, 1, 2, 3] [1, 4, 2] @@ -72,7 +72,7 @@ // The face stack stores values per face. the length of the face stack has to match the number of // negative values in the index layer in the corner stack. The face stack can be used to store things // like material index. - +// // Storage // ------- // All data is stored in little endian byte order with no padding. The layout mirrors the structs diff --git a/core/fmt/doc.odin b/core/fmt/doc.odin index 5984da950..668fc9bc6 100644 --- a/core/fmt/doc.odin +++ b/core/fmt/doc.odin @@ -64,6 +64,7 @@ If not present, the width is whatever is necessary to represent the value. Precision is specified after the (optional) width followed by a period followed by a decimal number. If no period is present, a default precision is used. A period with no following number specifies a precision of 0. + Examples: %f default width, default precision %8f width 8, default precision @@ -84,7 +85,6 @@ Other flags: add leading 0z for dozenal (%#z) add leading 0x or 0X for hexadecimal (%#x or %#X) remove leading 0x for %p (%#p) - ' ' (space) leave a space for elided sign in numbers (% d) 0 pad with leading zeros rather than spaces diff --git a/core/image/common.odin b/core/image/common.odin index 3ec8e15be..d72b770d5 100644 --- a/core/image/common.odin +++ b/core/image/common.odin @@ -6,6 +6,8 @@ Jeroen van Rijn: Initial implementation, optimization. Ginger Bill: Cosmetic changes. */ + +// package image implements a general 2D image library to be used with other image related packages package image import "core:bytes" diff --git a/core/image/png/png.odin b/core/image/png/png.odin index da76a4588..bff0afde3 100644 --- a/core/image/png/png.odin +++ b/core/image/png/png.odin @@ -6,6 +6,11 @@ Jeroen van Rijn: Initial implementation. Ginger Bill: Cosmetic changes. */ + + +// package png implements a PNG image reader +// +// The PNG specification is at https://www.w3.org/TR/PNG/. package png import "core:compress" diff --git a/core/math/big/api.odin b/core/math/big/api.odin index c9be04da0..bf19e83b6 100644 --- a/core/math/big/api.odin +++ b/core/math/big/api.odin @@ -2,12 +2,10 @@ Copyright 2021 Jeroen van Rijn . Made available under Odin's BSD-3 license. - An arbitrary precision mathematics implementation in Odin. - For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3. - The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks. - This file collects public proc maps and their aliases. */ + + package math_big /* diff --git a/core/math/big/common.odin b/core/math/big/common.odin index 31ad54b14..2b34a9163 100644 --- a/core/math/big/common.odin +++ b/core/math/big/common.odin @@ -1,11 +1,9 @@ /* Copyright 2021 Jeroen van Rijn . Made available under Odin's BSD-3 license. - - An arbitrary precision mathematics implementation in Odin. - For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3. - The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks. */ + + package math_big import "core:intrinsics" diff --git a/core/math/big/doc.odin b/core/math/big/doc.odin new file mode 100644 index 000000000..f5e0900f5 --- /dev/null +++ b/core/math/big/doc.odin @@ -0,0 +1,28 @@ +/* +A BigInt implementation in Odin. +For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3. +The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks. + +========================== Low-level routines ========================== + +IMPORTANT: `internal_*` procedures make certain assumptions about their input. + +The public functions that call them are expected to satisfy their sanity check requirements. +This allows `internal_*` call `internal_*` without paying this overhead multiple times. + +Where errors can occur, they are of course still checked and returned as appropriate. + +When importing `math:core/big` to implement an involved algorithm of your own, you are welcome +to use these procedures instead of their public counterparts. + +Most inputs and outputs are expected to be passed an initialized `Int`, for example. +Exceptions include `quotient` and `remainder`, which are allowed to be `nil` when the calling code doesn't need them. + +Check the comments above each `internal_*` implementation to see what constraints it expects to have met. + +We pass the custom allocator to procedures by default using the pattern `context.allocator = allocator`. +This way we don't have to add `, allocator` at the end of each call. + +TODO: Handle +/- Infinity and NaN. +*/ +package math_big diff --git a/core/math/big/helpers.odin b/core/math/big/helpers.odin index 6d13d32bb..6c4b5dd01 100644 --- a/core/math/big/helpers.odin +++ b/core/math/big/helpers.odin @@ -1,11 +1,9 @@ /* Copyright 2021 Jeroen van Rijn . Made available under Odin's BSD-3 license. - - An arbitrary precision mathematics implementation in Odin. - For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3. - The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks. */ + + package math_big import "core:intrinsics" diff --git a/core/math/big/internal.odin b/core/math/big/internal.odin index 437f6e5fc..5085898e5 100644 --- a/core/math/big/internal.odin +++ b/core/math/big/internal.odin @@ -2,33 +2,9 @@ /* Copyright 2021 Jeroen van Rijn . Made available under Odin's BSD-3 license. - - A BigInt implementation in Odin. - For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3. - The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks. - - ========================== Low-level routines ========================== - - IMPORTANT: `internal_*` procedures make certain assumptions about their input. - - The public functions that call them are expected to satisfy their sanity check requirements. - This allows `internal_*` call `internal_*` without paying this overhead multiple times. - - Where errors can occur, they are of course still checked and returned as appropriate. - - When importing `math:core/big` to implement an involved algorithm of your own, you are welcome - to use these procedures instead of their public counterparts. - - Most inputs and outputs are expected to be passed an initialized `Int`, for example. - Exceptions include `quotient` and `remainder`, which are allowed to be `nil` when the calling code doesn't need them. - - Check the comments above each `internal_*` implementation to see what constraints it expects to have met. - - We pass the custom allocator to procedures by default using the pattern `context.allocator = allocator`. - This way we don't have to add `, allocator` at the end of each call. - - TODO: Handle +/- Infinity and NaN. */ + + package math_big import "core:mem" diff --git a/core/math/big/logical.odin b/core/math/big/logical.odin index e7e55cc47..b5de4cabf 100644 --- a/core/math/big/logical.odin +++ b/core/math/big/logical.odin @@ -8,6 +8,8 @@ This file contains logical operations like `and`, `or` and `xor`. */ + + package math_big /* diff --git a/core/math/big/prime.odin b/core/math/big/prime.odin index eb0cd644c..3cce69675 100644 --- a/core/math/big/prime.odin +++ b/core/math/big/prime.odin @@ -8,6 +8,8 @@ This file contains prime finding operations. */ + + package math_big import rnd "core:math/rand" diff --git a/core/math/big/private.odin b/core/math/big/private.odin index 9989a208a..419f2103f 100644 --- a/core/math/big/private.odin +++ b/core/math/big/private.odin @@ -15,6 +15,8 @@ These aren't exported for the same reasons. */ + + package math_big import "core:intrinsics" diff --git a/core/math/big/public.odin b/core/math/big/public.odin index 2673a262f..3227d7bc4 100644 --- a/core/math/big/public.odin +++ b/core/math/big/public.odin @@ -8,6 +8,8 @@ This file contains basic arithmetic operations like `add`, `sub`, `mul`, `div`, ... */ + + package math_big import "core:intrinsics" diff --git a/core/math/big/radix.odin b/core/math/big/radix.odin index 760c49d77..2b758dc35 100644 --- a/core/math/big/radix.odin +++ b/core/math/big/radix.odin @@ -12,6 +12,8 @@ - Use Barrett reduction for non-powers-of-two. - Also look at extracting and splatting several digits at once. */ + + package math_big import "core:intrinsics" diff --git a/core/math/big/tune.odin b/core/math/big/tune.odin index d67ff61b4..64a73b656 100644 --- a/core/math/big/tune.odin +++ b/core/math/big/tune.odin @@ -7,6 +7,8 @@ For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3. The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks. */ + + package math_big import "core:time" From 8eda7567141316627973d0018bfb7e80ebdf90aa Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jan 2022 19:01:16 +0000 Subject: [PATCH 06/37] Add printing for constants, variables, types, and procedure groups --- tools/odin-html-docs/odin_html_docs_main.odin | 97 +++++++++++++++---- tools/odin-html-docs/style.css | 6 +- 2 files changed, 83 insertions(+), 20 deletions(-) diff --git a/tools/odin-html-docs/odin_html_docs_main.odin b/tools/odin-html-docs/odin_html_docs_main.odin index 3cbc0d860..d1e4f4432 100644 --- a/tools/odin-html-docs/odin_html_docs_main.odin +++ b/tools/odin-html-docs/odin_html_docs_main.odin @@ -114,27 +114,30 @@ main :: proc() { entities = array(header.entities) types = array(header.types) - fullpaths: [dynamic]string - defer delete(fullpaths) + { + fullpaths: [dynamic]string + defer delete(fullpaths) - for pkg in pkgs[1:] { - append(&fullpaths, str(pkg.fullpath)) - } - path_prefix := common_prefix(fullpaths[:]) - - pkgs_to_use = make(map[string]^doc.Pkg) - for fullpath, i in fullpaths { - path := strings.trim_prefix(fullpath, path_prefix) - if strings.has_prefix(path, "core/") { - pkgs_to_use[strings.trim_prefix(path, "core/")] = &pkgs[i+1] + for pkg in pkgs[1:] { + append(&fullpaths, str(pkg.fullpath)) + } + path_prefix := common_prefix(fullpaths[:]) + + pkgs_to_use = make(map[string]^doc.Pkg) + for fullpath, i in fullpaths { + path := strings.trim_prefix(fullpath, path_prefix) + if strings.has_prefix(path, "core/") { + pkgs_to_use[strings.trim_prefix(path, "core/")] = &pkgs[i+1] + } + } + sort.map_entries_by_key(&pkgs_to_use) + for path, pkg in pkgs_to_use { + pkg_to_path[pkg] = path } - } - sort.map_entries_by_key(&pkgs_to_use) - for path, pkg in pkgs_to_use { - pkg_to_path[pkg] = path } b := strings.make_builder() + defer strings.destroy_builder(&b) w := strings.to_writer(&b) { strings.reset_builder(&b) @@ -369,7 +372,7 @@ write_type :: proc(using writer: ^Type_Writer, type: doc.Type, flags: Write_Type if tn_pkg != pkg { fmt.wprintf(w, `%s.`, str(pkgs[pkg].name)) } - fmt.wprintf(w, `{1:s}`, pkg_to_path[&pkgs[tn_pkg]], name) + fmt.wprintf(w, `{1:s}`, pkg_to_path[&pkgs[tn_pkg]], name) case .Generic: name := str(type.name) io.write_byte(w, '$') @@ -694,12 +697,49 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { case .Invalid, .Import_Name, .Library_Name: // ignore case .Constant: + fmt.wprint(w, "
")
+			the_type := types[e.type]
+			if the_type.kind == .Basic && .Untyped in (transmute(doc.Type_Flags_Basic)the_type.flags) {
+				fmt.wprintf(w, "%s :: ", name)
+			} else {
+				fmt.wprintf(w, "%s: ", name)
+				write_type(writer, the_type, {.Allow_Indent})
+				fmt.wprintf(w, " : ")
+			}
+
+			init_string := str(e.init_string)
+			assert(init_string != "")
+			io.write_string(w, init_string)
+			fmt.wprintln(w, "
") case .Variable: + fmt.wprint(w, "
")
+			fmt.wprintf(w, "%s: ", name)
+			write_type(writer, types[e.type], {.Allow_Indent})
+			init_string := str(e.init_string)
+			if init_string != "" {
+				io.write_string(w, " = ")
+				io.write_string(w, init_string)
+			}
+			fmt.wprintln(w, "
") + case .Type_Name: fmt.wprint(w, "
")
 			fmt.wprintf(w, "%s :: ", name)
-			tn := base_type(types[e.type])
-			write_type(writer, tn, {.Allow_Indent})
+			the_type := types[e.type]
+			type_to_print := the_type
+			if the_type.kind == .Named {
+				if e.pos != entities[array(the_type.entities)[0]].pos {
+					io.write_string(w, "distinct ")
+				} else {
+					bt := base_type(the_type)
+					#partial switch bt.kind {
+					case .Struct, .Union, .Proc, .Enum:
+						io.write_string(w, "distinct ")
+						type_to_print = bt
+					}
+				}
+			}
+			write_type(writer, type_to_print, {.Allow_Indent})
 			fmt.wprintln(w, "
") case .Procedure: fmt.wprint(w, "
")
@@ -719,6 +759,25 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) {
 			fmt.wprint(w, " {…}")
 			fmt.wprintln(w, "
") case .Proc_Group: + fmt.wprint(w, "
")
+			fmt.wprintf(w, "%s :: proc{{\n", name)
+			for entity_index in array(e.grouped_entities) {
+				this_proc := &entities[entity_index]
+				this_pkg := files[this_proc.pos.file].pkg
+				io.write_byte(w, '\t')
+				if this_pkg != pkg_index {
+					fmt.wprintf(w, "%s.", str(pkgs[this_pkg].name))
+				}
+				name := str(this_proc.name)
+				fmt.wprintf(w, ``, pkg_to_path[&pkgs[this_pkg]], name)
+				io.write_string(w, name)
+				io.write_string(w, ``)
+				io.write_byte(w, ',')
+				io.write_byte(w, '\n')
+			}
+			fmt.wprintln(w, "}")
+			fmt.wprintln(w, "
") + } write_docs(w, pkg, strings.trim_space(str(e.docs))) diff --git a/tools/odin-html-docs/style.css b/tools/odin-html-docs/style.css index 7c23d0bc7..1f334ad91 100644 --- a/tools/odin-html-docs/style.css +++ b/tools/odin-html-docs/style.css @@ -28,4 +28,8 @@ pre { text-decoration: none; font-weight: bold; color: #00bfd5; -} \ No newline at end of file +} + +pre a.code-procedure { + color: #079300; +} From 0d4642825fc0d9ad5009bb4e4cae467ee9900112 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jan 2022 19:07:25 +0000 Subject: [PATCH 07/37] Correct package docs parsing --- src/parser.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/parser.cpp b/src/parser.cpp index 5bf43cee9..7e7146244 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -5412,6 +5412,15 @@ bool parse_file(Parser *p, AstFile *f) { if (f->package_token.kind != Token_package) { return false; } + if (docs != nullptr) { + TokenPos end = token_pos_end(docs->list[docs->list.count-1]); + if (end.line == f->package_token.pos.line || end.line+1 == f->package_token.pos.line) { + // Okay + } else { + docs = nullptr; + } + } + Token package_name = expect_token_after(f, Token_Ident, "package"); if (package_name.kind == Token_Ident) { if (package_name.string == "_") { From 2ca2dbcc923a005b95459b1ad4c6f5b5600fd17c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jan 2022 19:23:24 +0000 Subject: [PATCH 08/37] Correct `distinct` printing --- tools/odin-html-docs/odin_html_docs_main.odin | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/odin-html-docs/odin_html_docs_main.odin b/tools/odin-html-docs/odin_html_docs_main.odin index d1e4f4432..90010369d 100644 --- a/tools/odin-html-docs/odin_html_docs_main.odin +++ b/tools/odin-html-docs/odin_html_docs_main.odin @@ -370,7 +370,7 @@ write_type :: proc(using writer: ^Type_Writer, type: doc.Type, flags: Write_Type fmt.wprintf(w, ``) tn_pkg := files[e.pos.file].pkg if tn_pkg != pkg { - fmt.wprintf(w, `%s.`, str(pkgs[pkg].name)) + fmt.wprintf(w, `%s.`, str(pkgs[tn_pkg].name)) } fmt.wprintf(w, `{1:s}`, pkg_to_path[&pkgs[tn_pkg]], name) case .Generic: @@ -727,16 +727,16 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { fmt.wprintf(w, "%s :: ", name) the_type := types[e.type] type_to_print := the_type - if the_type.kind == .Named { - if e.pos != entities[array(the_type.entities)[0]].pos { - io.write_string(w, "distinct ") - } else { + if the_type.kind == .Named && .Type_Alias not_in e.flags { + if e.pos == entities[array(the_type.entities)[0]].pos { bt := base_type(the_type) #partial switch bt.kind { case .Struct, .Union, .Proc, .Enum: + // Okay + case: io.write_string(w, "distinct ") - type_to_print = bt } + type_to_print = bt } } write_type(writer, type_to_print, {.Allow_Indent}) From e9ae6e20e859eb68b01f3e55ca955a2e08cf446b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jan 2022 20:50:40 +0000 Subject: [PATCH 09/37] Fix code, source code links, and add recursive make directory --- tools/odin-html-docs/odin_html_docs_main.odin | 179 ++++++++++++++---- tools/odin-html-docs/style.css | 32 +++- 2 files changed, 174 insertions(+), 37 deletions(-) diff --git a/tools/odin-html-docs/odin_html_docs_main.odin b/tools/odin-html-docs/odin_html_docs_main.odin index 90010369d..4260bd697 100644 --- a/tools/odin-html-docs/odin_html_docs_main.odin +++ b/tools/odin-html-docs/odin_html_docs_main.odin @@ -9,6 +9,8 @@ import "core:path/slashpath" import "core:sort" import "core:slice" +GITHUB_CORE_URL :: "https://github.com/odin-lang/Odin/tree/master/core" + header: ^doc.Header files: []doc.File pkgs: []doc.Pkg @@ -64,6 +66,18 @@ common_prefix :: proc(strs: []string) -> string { return prefix } +recursive_make_directory :: proc(path: string, prefix := "") { + head, _, tail := strings.partition(path, "/") + path_to_make := head + if prefix != "" { + path_to_make = fmt.tprintf("%s/%s", prefix, head) + } + os.make_directory(path_to_make, 0) + if tail != "" { + recursive_make_directory(tail, path_to_make) + } +} + write_html_header :: proc(w: io.Writer, title: string) { fmt.wprintf(w, ` @@ -124,11 +138,21 @@ main :: proc() { path_prefix := common_prefix(fullpaths[:]) pkgs_to_use = make(map[string]^doc.Pkg) - for fullpath, i in fullpaths { + fullpath_loop: for fullpath, i in fullpaths { path := strings.trim_prefix(fullpath, path_prefix) - if strings.has_prefix(path, "core/") { - pkgs_to_use[strings.trim_prefix(path, "core/")] = &pkgs[i+1] + 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 } sort.map_entries_by_key(&pkgs_to_use) for path, pkg in pkgs_to_use { @@ -153,7 +177,7 @@ main :: proc() { write_html_header(w, fmt.tprintf("package %s - pkg.odin-lang.org", path)) write_pkg(w, path, pkg) write_html_footer(w) - os.make_directory(fmt.tprintf("core/%s", path), 0) + recursive_make_directory(path, "core") os.write_entire_file(fmt.tprintf("core/%s/index.html", path), b.buf[:]) } } @@ -304,20 +328,37 @@ write_type :: proc(using writer: ^Type_Writer, type: doc.Type, flags: Write_Type if .Param_No_Alias in e.flags { io.write_string(w, "#no_alias ") } if .Param_Any_Int in e.flags { io.write_string(w, "#any_int ") } - if name != "" { + init_string := str(e.init_string) + switch init_string { + case "#caller_location": + assert(name != "") io.write_string(w, name) - io.write_string(w, ": ") - } - padding := max(name_width-len(name), 0) - for _ in 0..`) + io.write_string(w, init_string) + io.write_string(w, ``) - param_flags := flags - {.Is_Results} - if .Param_Ellipsis in e.flags { - param_flags += {.Variadic} + case: + if name != "" { + io.write_string(w, name) + io.write_string(w, ": ") + } + padding := max(name_width-len(name), 0) + for _ in 0..
") + continue } text := strings.trim_space(line) if text == "" { @@ -604,8 +669,9 @@ write_docs :: proc(w: io.Writer, pkg: ^doc.Pkg, docs: string) { if was_code { // assert(!was_paragraph, str(pkg.name)) was_code = false - fmt.wprintln(w, "") - } else if was_paragraph { + fmt.wprintln(w, "") + } + if was_paragraph { fmt.wprintln(w, "

") } } @@ -684,6 +750,21 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { print_entity :: proc(w: io.Writer, e: ^doc.Entity) { + write_attributes :: proc(w: io.Writer, e: ^doc.Entity) { + for attr in array(e.attributes) { + io.write_string(w, "@(") + name := str(attr.name) + value := str(attr.value) + io.write_string(w, name) + if value != "" { + io.write_string(w, "=") + io.write_string(w, value) + } + io.write_string(w, ")\n") + } + } + + pkg_index := files[e.pos.file].pkg pkg := &pkgs[pkg_index] writer := &Type_Writer{ @@ -692,7 +773,15 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { } name := str(e.name) - fmt.wprintf(w, "

{0:s}

\n", name) + path := pkg_to_path[pkg] + filename := slashpath.base(str(files[e.pos.file].name)) + fmt.wprintf(w, "

{0:s}", name) + fmt.wprintf(w, " ¶

\n") + defer 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) + fmt.wprintf(w, "Source: {0:s}", src_url) + } + switch e.kind { case .Invalid, .Import_Name, .Library_Name: // ignore @@ -713,6 +802,7 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { fmt.wprintln(w, "") case .Variable: fmt.wprint(w, "
")
+			write_attributes(w, e)
 			fmt.wprintf(w, "%s: ", name)
 			write_type(writer, types[e.type], {.Allow_Indent})
 			init_string := str(e.init_string)
@@ -804,12 +894,35 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) {
 
 	fmt.wprintln(w, "

Source Files

") fmt.wprintln(w, "
    ") - for file_index in array(pkg.files) { + any_hidden := false + source_file_loop: for file_index in array(pkg.files) { file := files[file_index] filename := slashpath.base(str(file.name)) - fmt.wprintf(w, `
  • %s
  • `, path, filename, filename) + switch { + case + strings.has_suffix(filename, "_windows.odin"), + strings.has_suffix(filename, "_darwin.odin"), + strings.has_suffix(filename, "_essence.odin"), + strings.has_suffix(filename, "_freebsd.odin"), + strings.has_suffix(filename, "_wasi.odin"), + strings.has_suffix(filename, "_js.odin"), + strings.has_suffix(filename, "_freestanding.odin"), + + strings.has_suffix(filename, "_amd64.odin"), + strings.has_suffix(filename, "_i386.odin"), + strings.has_suffix(filename, "_arch64.odin"), + strings.has_suffix(filename, "_wasm32.odin"), + strings.has_suffix(filename, "_wasm64.odin"), + false: + any_hidden = true + continue source_file_loop + } + fmt.wprintf(w, `
  • %s
  • `, GITHUB_CORE_URL, path, filename, filename) fmt.wprintln(w) } + if any_hidden { + fmt.wprintln(w, "
  • (hidden platform specific files)
  • ") + } fmt.wprintln(w, "
") } \ No newline at end of file diff --git a/tools/odin-html-docs/style.css b/tools/odin-html-docs/style.css index 1f334ad91..61cab3e8c 100644 --- a/tools/odin-html-docs/style.css +++ b/tools/odin-html-docs/style.css @@ -1,3 +1,8 @@ +* { + font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"; +} + + .container { max-width: 60em; margin: 0 auto; @@ -15,8 +20,11 @@ } pre { - white-space: pre; + white-space: pre-wrap; + word-break: break-all; + word-wrap: break-word; tab-size: 8; + font-family: Consolas,Liberation Mono,Menlo,monospace!important; background-color: #f8f8f8; color: #202224; border: 1px solid #c6c8ca; @@ -24,12 +32,28 @@ pre { padding: 0.625rem; } -.documentation pre a { +pre a { + font-family: Consolas,Liberation Mono,Menlo,monospace!important; text-decoration: none; - font-weight: bold; + /*font-weight: bold;*/ color: #00bfd5; } -pre a.code-procedure { +.documentation pre a.code-procedure { color: #079300; } + +.documentation-source { + text-decoration: none; + color: #666666; +} +.documentation-source:hover { + text-decoration: underline; +} + +a > .a-hidden { + opacity: 0; +} +a:hover > .a-hidden { + opacity: 100; +} \ No newline at end of file From cafb6e5587d4d3f5211b945bcb9d949a3980aa89 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jan 2022 21:33:20 +0000 Subject: [PATCH 10/37] Correct `//+private` for `odin doc` --- src/checker.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/checker.cpp b/src/checker.cpp index ddb73d33e..44dc90c67 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3446,6 +3446,13 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) { } } + if (entity_visibility_kind == EntityVisiblity_Public && + (c->scope->flags&ScopeFlag_File) && + c->scope->file && + (c->scope->file->flags & AstFile_IsPrivate)) { + entity_visibility_kind = EntityVisiblity_PrivateToPackage; + } + if (entity_visibility_kind != EntityVisiblity_Public && !(c->scope->flags&ScopeFlag_File)) { error(decl, "Attribute 'private' is not allowed on a non file scope entity"); } From c7a9c8274fc212ec421d46c2c58f36afdc949898 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jan 2022 22:16:32 +0000 Subject: [PATCH 11/37] Improve type printing --- tools/odin-html-docs/odin_html_docs_main.odin | 243 +++++++++++++----- tools/odin-html-docs/style.css | 32 ++- 2 files changed, 205 insertions(+), 70 deletions(-) diff --git a/tools/odin-html-docs/odin_html_docs_main.odin b/tools/odin-html-docs/odin_html_docs_main.odin index 4260bd697..988c54d9d 100644 --- a/tools/odin-html-docs/odin_html_docs_main.odin +++ b/tools/odin-html-docs/odin_html_docs_main.odin @@ -45,6 +45,14 @@ base_type :: proc(t: doc.Type) -> doc.Type { return t } +is_type_untyped :: proc(type: doc.Type) -> bool { + if type.kind == .Basic { + flags := transmute(doc.Type_Flags_Basic)type.flags + return .Untyped in flags + } + return false +} + common_prefix :: proc(strs: []string) -> string { if len(strs) == 0 { return "" @@ -275,7 +283,9 @@ write_core_directory :: proc(w: io.Writer) { line_doc, _, _ := strings.partition(str(dir.pkg.docs), "\n") line_doc = strings.trim_space(line_doc) if line_doc != "" { - fmt.wprintf(w, `%s`, line_doc) + io.write_string(w, ``) + write_doc_line(w, line_doc) + io.write_string(w, ``) } } fmt.wprintf(w, "\n") @@ -289,7 +299,9 @@ write_core_directory :: proc(w: io.Writer) { line_doc, _, _ := strings.partition(str(child.pkg.docs), "\n") line_doc = strings.trim_space(line_doc) if line_doc != "" { - fmt.wprintf(w, `%s`, line_doc) + io.write_string(w, ``) + write_doc_line(w, line_doc) + io.write_string(w, ``) } fmt.wprintf(w, "\n") @@ -305,16 +317,31 @@ is_entity_blank :: proc(e: doc.Entity_Index) -> bool { return name == "" || name == "_" } +write_where_clauses :: proc(w: io.Writer, where_clauses: []doc.String) { + if len(where_clauses) != 0 { + io.write_string(w, " where ") + for clause, i in where_clauses { + if i > 0 { + io.write_string(w, ", ") + } + io.write_string(w, str(clause)) + } + } +} + + Write_Type_Flag :: enum { Is_Results, Variadic, Allow_Indent, + Poly_Names, } Write_Type_Flags :: distinct bit_set[Write_Type_Flag] Type_Writer :: struct { w: io.Writer, pkg: doc.Pkg_Index, indent: int, + generic_scope: map[string]bool, } write_type :: proc(using writer: ^Type_Writer, type: doc.Type, flags: Write_Type_Flags) { @@ -329,30 +356,65 @@ write_type :: proc(using writer: ^Type_Writer, type: doc.Type, flags: Write_Type if .Param_Any_Int in e.flags { io.write_string(w, "#any_int ") } init_string := str(e.init_string) - switch init_string { - case "#caller_location": + switch { + case init_string == "#caller_location": assert(name != "") io.write_string(w, name) io.write_string(w, " := ") io.write_string(w, ``) io.write_string(w, init_string) io.write_string(w, ``) - + case strings.has_prefix(init_string, "context."): + io.write_string(w, name) + io.write_string(w, " := ") + io.write_string(w, ``) + io.write_string(w, init_string) + io.write_string(w, ``) case: - if name != "" { - io.write_string(w, name) - io.write_string(w, ": ") - } - padding := max(name_width-len(name), 0) - for _ in 0..%s`, str(type.name)) @@ -408,17 +469,23 @@ write_type :: proc(using writer: ^Type_Writer, type: doc.Type, flags: Write_Type case .Named: e := entities[type_entites[0]] name := str(type.name) - fmt.wprintf(w, ``) tn_pkg := files[e.pos.file].pkg if tn_pkg != pkg { fmt.wprintf(w, `%s.`, str(pkgs[tn_pkg].name)) } - fmt.wprintf(w, `{1:s}`, pkg_to_path[&pkgs[tn_pkg]], name) + if n := strings.contains_rune(name, '('); n >= 0 { + fmt.wprintf(w, `{1:s}`, pkg_to_path[&pkgs[tn_pkg]], name[:n]) + io.write_string(w, name[n:]) + } else { + fmt.wprintf(w, `{1:s}`, pkg_to_path[&pkgs[tn_pkg]], name) + } case .Generic: name := str(type.name) - io.write_byte(w, '$') + if name not_in generic_scope { + io.write_byte(w, '$') + } io.write_string(w, name) - if len(array(type.types)) == 1 { + if name not_in generic_scope && len(array(type.types)) == 1 { io.write_byte(w, '/') write_type(writer, types[type_types[0]], flags) } @@ -454,9 +521,7 @@ write_type :: proc(using writer: ^Type_Writer, type: doc.Type, flags: Write_Type case .Struct: type_flags := transmute(doc.Type_Flags_Struct)type.flags io.write_string(w, "struct") - if .Polymorphic in type_flags { - write_poly_params(writer, type, flags) - } + write_poly_params(writer, type, flags) if .Packed in type_flags { io.write_string(w, " #packed") } if .Raw_Union in type_flags { io.write_string(w, " #raw_union") } if custom_align := str(type.custom_align); custom_align != "" { @@ -483,9 +548,7 @@ write_type :: proc(using writer: ^Type_Writer, type: doc.Type, flags: Write_Type case .Union: type_flags := transmute(doc.Type_Flags_Union)type.flags io.write_string(w, "union") - if .Polymorphic in type_flags { - write_poly_params(writer, type, flags) - } + write_poly_params(writer, type, flags) if .No_Nil in type_flags { io.write_string(w, " #no_nil") } if .Maybe in type_flags { io.write_string(w, " #maybe") } if custom_align := str(type.custom_align); custom_align != "" { @@ -631,6 +694,25 @@ write_type :: proc(using writer: ^Type_Writer, type: doc.Type, flags: Write_Type } } +write_doc_line :: proc(w: io.Writer, text: string) { + text := text + for len(text) != 0 { + if strings.count(text, "`") >= 2 { + n := strings.index_byte(text, '`') + io.write_string(w, text[:n]) + io.write_string(w, "") + remaining := text[n+1:] + m := strings.index_byte(remaining, '`') + io.write_string(w, remaining[:m]) + io.write_string(w, "") + text = remaining[m+1:] + } else { + io.write_string(w, text) + return + } + } +} + write_docs :: proc(w: io.Writer, pkg: ^doc.Pkg, docs: string) { if docs == "" { return @@ -663,8 +745,11 @@ write_docs :: proc(w: io.Writer, pkg: ^doc.Pkg, docs: string) { fmt.wprintln(w, "

") } assert(!was_code) + was_paragraph = true - fmt.wprintln(w, text) + write_doc_line(w, text) + + io.write_byte(w, '\n') } if was_code { // assert(!was_paragraph, str(pkg.name)) @@ -677,6 +762,24 @@ write_docs :: proc(w: io.Writer, pkg: ^doc.Pkg, docs: string) { } write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { + write_breadcrumbs :: proc(w: io.Writer, path: string) { + dirs := strings.split(path, "/") + io.write_string(w, "

    \n") + for dir, i in dirs { + url := strings.join(dirs[:i+1], "/") + short_path := strings.join(dirs[1:i+1], "/") + if i == 0 || short_path in pkgs_to_use { + fmt.wprintf(w, "
  • %s
  • ", url, dir) + } else { + fmt.wprintf(w, "
  • %s
  • ", dir) + } + } + io.write_string(w, "
\n") + + } + write_breadcrumbs(w, fmt.tprintf("core/%s", path)) + + fmt.wprintf(w, "

package core:%s

\n", path) fmt.wprintln(w, "

Documentation

") docs := strings.trim_space(str(pkg.docs)) @@ -723,7 +826,7 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { slice.sort_by_key(pkg_vars[:], entity_key) slice.sort_by_key(pkg_consts[:], entity_key) - print_index :: proc(w: io.Writer, name: string, entities: []^doc.Entity) { + write_index :: proc(w: io.Writer, name: string, entities: []^doc.Entity) { fmt.wprintf(w, "

%s

\n", name) fmt.wprintln(w, `
`) if len(entities) == 0 { @@ -740,16 +843,16 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { } - print_index(w, "Procedures", pkg_procs[:]) - print_index(w, "Procedure Groups", pkg_proc_groups[:]) - print_index(w, "Types", pkg_types[:]) - print_index(w, "Variables", pkg_vars[:]) - print_index(w, "Constants", pkg_consts[:]) + write_index(w, "Procedures", pkg_procs[:]) + write_index(w, "Procedure Groups", pkg_proc_groups[:]) + write_index(w, "Types", pkg_types[:]) + write_index(w, "Variables", pkg_vars[:]) + write_index(w, "Constants", pkg_consts[:]) fmt.wprintln(w, "
") - print_entity :: proc(w: io.Writer, e: ^doc.Entity) { + write_entity :: proc(w: io.Writer, e: ^doc.Entity) { write_attributes :: proc(w: io.Writer, e: ^doc.Entity) { for attr in array(e.attributes) { io.write_string(w, "@(") @@ -764,23 +867,24 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { } } - pkg_index := files[e.pos.file].pkg pkg := &pkgs[pkg_index] writer := &Type_Writer{ w = w, pkg = pkg_index, } + defer delete(writer.generic_scope) name := str(e.name) path := pkg_to_path[pkg] filename := slashpath.base(str(files[e.pos.file].name)) - fmt.wprintf(w, "

{0:s}", name) - fmt.wprintf(w, " ¶

\n") - defer if e.pos.file != 0 && e.pos.line > 0 { + fmt.wprintf(w, "

{0:s}", name) + fmt.wprintf(w, " ¶") + 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) - fmt.wprintf(w, "Source: {0:s}", src_url) + fmt.wprintf(w, "", src_url) } + fmt.wprintf(w, "

\n") switch e.kind { case .Invalid, .Import_Name, .Library_Name: @@ -788,7 +892,21 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { case .Constant: fmt.wprint(w, "
")
 			the_type := types[e.type]
-			if the_type.kind == .Basic && .Untyped in (transmute(doc.Type_Flags_Basic)the_type.flags) {
+
+			init_string := str(e.init_string)
+			assert(init_string != "")
+
+			ignore_type := true
+			if the_type.kind == .Basic && is_type_untyped(the_type) {
+			} else {
+				ignore_type = false
+				type_name := str(the_type.name)
+				if type_name != "" && strings.has_prefix(init_string, type_name) {
+					ignore_type = true
+				}
+			}
+
+			if ignore_type {
 				fmt.wprintf(w, "%s :: ", name)
 			} else {
 				fmt.wprintf(w, "%s: ", name)
@@ -796,8 +914,7 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) {
 				fmt.wprintf(w, " : ")
 			}
 
-			init_string := str(e.init_string)
-			assert(init_string != "")
+
 			io.write_string(w, init_string)
 			fmt.wprintln(w, "
") case .Variable: @@ -835,17 +952,7 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { fmt.wprint(w, "
")
 			fmt.wprintf(w, "%s :: ", name)
 			write_type(writer, types[e.type], nil)
-			where_clauses := array(e.where_clauses)
-			if len(where_clauses) != 0 {
-				io.write_string(w, " where ")
-				for clause, i in where_clauses {
-					if i > 0 {
-						io.write_string(w, ", ")
-					}
-					io.write_string(w, str(clause))
-				}
-			}
-
+			write_where_clauses(w, array(e.where_clauses))
 			fmt.wprint(w, " {…}")
 			fmt.wprintln(w, "
") case .Proc_Group: @@ -872,24 +979,24 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { write_docs(w, pkg, strings.trim_space(str(e.docs))) } - print_entities :: proc(w: io.Writer, title: string, entities: []^doc.Entity) { + write_entities :: proc(w: io.Writer, title: string, entities: []^doc.Entity) { fmt.wprintf(w, "

%s

\n", title) fmt.wprintln(w, `
`) if len(entities) == 0 { io.write_string(w, "

This section is empty.

\n") } else { for e in entities { - print_entity(w, e) + write_entity(w, e) } } fmt.wprintln(w, "
") } - print_entities(w, "Procedures", pkg_procs[:]) - print_entities(w, "Procedure Groups", pkg_proc_groups[:]) - print_entities(w, "Types", pkg_types[:]) - print_entities(w, "Variables", pkg_vars[:]) - print_entities(w, "Constants", pkg_consts[:]) + write_entities(w, "Procedures", pkg_procs[:]) + write_entities(w, "Procedure Groups", pkg_proc_groups[:]) + write_entities(w, "Types", pkg_types[:]) + write_entities(w, "Variables", pkg_vars[:]) + write_entities(w, "Constants", pkg_consts[:]) fmt.wprintln(w, "

Source Files

") diff --git a/tools/odin-html-docs/style.css b/tools/odin-html-docs/style.css index 61cab3e8c..cf43a7199 100644 --- a/tools/odin-html-docs/style.css +++ b/tools/odin-html-docs/style.css @@ -21,7 +21,7 @@ pre { white-space: pre-wrap; - word-break: break-all; + word-break: keep-all; word-wrap: break-word; tab-size: 8; font-family: Consolas,Liberation Mono,Menlo,monospace!important; @@ -44,10 +44,15 @@ pre a { } .documentation-source { + display: inline; + float: right; +} + +.documentation-source a { text-decoration: none; color: #666666; } -.documentation-source:hover { +.documentation-source a:hover { text-decoration: underline; } @@ -56,4 +61,27 @@ a > .a-hidden { } a:hover > .a-hidden { opacity: 100; +} + +ul.documentation-breadcrumb { + list-style: none; +} + +ul.documentation-breadcrumb li { + display: inline; +} + +ul.documentation-breadcrumb li+li:before { + padding: 0.2rem; + color: black; + content: "/\00a0"; +} + +.code-inline { + font-family: Consolas,Liberation Mono,Menlo,monospace!important; + background-color: #f8f8f8; + color: #202224; + border: 1px solid #c6c8ca; + border-radius: 0.25rem; + padding: 0.125rem; } \ No newline at end of file From fb01dfe04845a489760956cea4f0019e1464b2e3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jan 2022 22:17:07 +0000 Subject: [PATCH 12/37] Improve docs_writer.cpp --- core/math/big/doc.odin | 22 ---------------------- core/math/big/internal.odin | 24 +++++++++++++++++++++++- core/math/big/tune.odin | 3 +-- src/docs_writer.cpp | 2 +- src/types.cpp | 14 +++++--------- 5 files changed, 30 insertions(+), 35 deletions(-) diff --git a/core/math/big/doc.odin b/core/math/big/doc.odin index f5e0900f5..0f9b88d01 100644 --- a/core/math/big/doc.odin +++ b/core/math/big/doc.odin @@ -2,27 +2,5 @@ A BigInt implementation in Odin. For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3. The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks. - -========================== Low-level routines ========================== - -IMPORTANT: `internal_*` procedures make certain assumptions about their input. - -The public functions that call them are expected to satisfy their sanity check requirements. -This allows `internal_*` call `internal_*` without paying this overhead multiple times. - -Where errors can occur, they are of course still checked and returned as appropriate. - -When importing `math:core/big` to implement an involved algorithm of your own, you are welcome -to use these procedures instead of their public counterparts. - -Most inputs and outputs are expected to be passed an initialized `Int`, for example. -Exceptions include `quotient` and `remainder`, which are allowed to be `nil` when the calling code doesn't need them. - -Check the comments above each `internal_*` implementation to see what constraints it expects to have met. - -We pass the custom allocator to procedures by default using the pattern `context.allocator = allocator`. -This way we don't have to add `, allocator` at the end of each call. - -TODO: Handle +/- Infinity and NaN. */ package math_big diff --git a/core/math/big/internal.odin b/core/math/big/internal.odin index 5085898e5..dbcd16509 100644 --- a/core/math/big/internal.odin +++ b/core/math/big/internal.odin @@ -1,10 +1,32 @@ -//+ignore /* Copyright 2021 Jeroen van Rijn . Made available under Odin's BSD-3 license. + + ========================== Low-level routines ========================== + + IMPORTANT: `internal_*` procedures make certain assumptions about their input. + + The public functions that call them are expected to satisfy their sanity check requirements. + This allows `internal_*` call `internal_*` without paying this overhead multiple times. + + Where errors can occur, they are of course still checked and returned as appropriate. + + When importing `math:core/big` to implement an involved algorithm of your own, you are welcome + to use these procedures instead of their public counterparts. + + Most inputs and outputs are expected to be passed an initialized `Int`, for example. + Exceptions include `quotient` and `remainder`, which are allowed to be `nil` when the calling code doesn't need them. + + Check the comments above each `internal_*` implementation to see what constraints it expects to have met. + + We pass the custom allocator to procedures by default using the pattern `context.allocator = allocator`. + This way we don't have to add `, allocator` at the end of each call. + + TODO: Handle +/- Infinity and NaN. */ +//+ignore package math_big import "core:mem" diff --git a/core/math/big/tune.odin b/core/math/big/tune.odin index 64a73b656..78a20c12b 100644 --- a/core/math/big/tune.odin +++ b/core/math/big/tune.odin @@ -1,4 +1,3 @@ -//+ignore /* Copyright 2021 Jeroen van Rijn . Made available under Odin's BSD-3 license. @@ -8,7 +7,7 @@ The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks. */ - +//+ignore package math_big import "core:time" diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index 94b43be99..762a2afe1 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -513,7 +513,7 @@ OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) { break; case Type_Generic: doc_type.kind = OdinDocType_Generic; - doc_type.name = odin_doc_write_string(w, type->Generic.name); + doc_type.name = odin_doc_write_string(w, type->Generic.entity->token.string); if (type->Generic.specialized) { doc_type.types = odin_doc_type_as_slice(w, type->Generic.specialized); } diff --git a/src/types.cpp b/src/types.cpp index f621d4346..6162a5aa8 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -3933,7 +3933,7 @@ gbString write_type_to_string(gbString str, Type *type) { str = gb_string_appendc(str, " = "); str = write_exact_value_to_string(str, var->Constant.value); } else { - str = gb_string_appendc(str, "="); + str = gb_string_appendc(str, " := "); str = write_exact_value_to_string(str, var->Constant.value); } continue; @@ -3961,14 +3961,10 @@ gbString write_type_to_string(gbString str, Type *type) { str = gb_string_appendc(str, "typeid/"); str = write_type_to_string(str, var->type); } else { - if (var->kind == Entity_TypeName) { - str = gb_string_appendc(str, "$"); - str = gb_string_append_length(str, name.text, name.len); - str = gb_string_appendc(str, "="); - str = write_type_to_string(str, var->type); - } else { - str = gb_string_appendc(str, "typeid"); - } + str = gb_string_appendc(str, "$"); + str = gb_string_append_length(str, name.text, name.len); + str = gb_string_appendc(str, "="); + str = write_type_to_string(str, var->type); } } } From 6b830f42b6a8baec77ee0c8d12333ca2ad4a296f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jan 2022 23:48:46 +0000 Subject: [PATCH 13/37] Improve stylization with collapsible directories; Fix name padding --- tools/odin-html-docs/odin_html_docs_main.odin | 75 ++++++++++++++++--- tools/odin-html-docs/style.css | 63 ++++++++++++++-- 2 files changed, 121 insertions(+), 17 deletions(-) diff --git a/tools/odin-html-docs/odin_html_docs_main.odin b/tools/odin-html-docs/odin_html_docs_main.odin index 988c54d9d..317d95a5a 100644 --- a/tools/odin-html-docs/odin_html_docs_main.odin +++ b/tools/odin-html-docs/odin_html_docs_main.odin @@ -107,6 +107,51 @@ write_html_header :: proc(w: io.Writer, title: string) { } write_html_footer :: proc(w: io.Writer) { + io.write_string(w, ` + +`) fmt.wprintf(w, "\n\n") } @@ -255,7 +300,7 @@ write_core_directory :: proc(w: io.Writer) { fmt.wprintln(w, "

Directories

") - fmt.wprintln(w, "\t") + fmt.wprintln(w, "\t
") fmt.wprintln(w, "\t\t") for dir := root.first_child; dir != nil; dir = dir.next { @@ -264,7 +309,7 @@ write_core_directory :: proc(w: io.Writer) { for child := dir.first_child; child != nil; child = child.next { fmt.wprintf(w, "pkg-%s ", str(child.pkg.name)) } - fmt.wprint(w, `" class="directory-pkg">`) + io.write_string(w, ``) } } + io.write_string(w, ``) fmt.wprintf(w, "\n") for child := dir.first_child; child != nil; child = child.next { assert(child.pkg != nil) - fmt.wprintf(w, `") + io.write_string(w, ``) line_doc, _, _ := strings.partition(str(child.pkg.docs), "\n") line_doc = strings.trim_space(line_doc) + io.write_string(w, ``) } + io.write_string(w, ``) + fmt.wprintf(w, "") fmt.wprintf(w, "\n") } } @@ -314,7 +360,7 @@ write_core_directory :: proc(w: io.Writer) { is_entity_blank :: proc(e: doc.Entity_Index) -> bool { name := str(entities[e].name) - return name == "" || name == "_" + return name == "" } write_where_clauses :: proc(w: io.Writer, where_clauses: []doc.String) { @@ -348,6 +394,12 @@ write_type :: proc(using writer: ^Type_Writer, type: doc.Type, flags: Write_Type write_param_entity :: proc(using writer: ^Type_Writer, e: ^doc.Entity, flags: Write_Type_Flags, name_width := 0) { name := str(e.name) + write_padding :: proc(w: io.Writer, name: string, name_width: int) { + for _ in 0.. Date: Wed, 19 Jan 2022 13:20:38 +0000 Subject: [PATCH 14/37] Improve rendering to match the main website's CSS --- tools/odin-html-docs/footer.txt.html | 43 ++++ tools/odin-html-docs/header.txt.html | 34 +++ tools/odin-html-docs/odin_html_docs_main.odin | 226 +++++++++++------- tools/odin-html-docs/style.css | 89 ++----- 4 files changed, 241 insertions(+), 151 deletions(-) create mode 100644 tools/odin-html-docs/footer.txt.html create mode 100644 tools/odin-html-docs/header.txt.html diff --git a/tools/odin-html-docs/footer.txt.html b/tools/odin-html-docs/footer.txt.html new file mode 100644 index 000000000..fbed3146a --- /dev/null +++ b/tools/odin-html-docs/footer.txt.html @@ -0,0 +1,43 @@ + + + + + + + \ No newline at end of file diff --git a/tools/odin-html-docs/header.txt.html b/tools/odin-html-docs/header.txt.html new file mode 100644 index 000000000..cfa1e0175 --- /dev/null +++ b/tools/odin-html-docs/header.txt.html @@ -0,0 +1,34 @@ + + + + + + {0:s} + + + + + + + + + + +
+ +
+
+
\ No newline at end of file diff --git a/tools/odin-html-docs/odin_html_docs_main.odin b/tools/odin-html-docs/odin_html_docs_main.odin index 317d95a5a..a6b5f428e 100644 --- a/tools/odin-html-docs/odin_html_docs_main.odin +++ b/tools/odin-html-docs/odin_html_docs_main.odin @@ -88,71 +88,62 @@ recursive_make_directory :: proc(path: string, prefix := "") { write_html_header :: proc(w: io.Writer, title: string) { - fmt.wprintf(w, ` - - - - - %s - - - - - - -`, title) - fmt.wprintln(w, "\n
") - fmt.wprintln(w, "\nCore Directory") - + fmt.wprintf(w, string(#load("header.txt.html")), title) } -write_html_footer :: proc(w: io.Writer) { - io.write_string(w, ` - -`) - fmt.wprintf(w, "
\n\n") + } + doc.addEventListener('click', toggle, false); +}(this, this.document)); +`) + } + + fmt.wprintf(w, "\n\n") } main :: proc() { @@ -220,7 +211,7 @@ main :: proc() { strings.reset_builder(&b) write_html_header(w, "core library - pkg.odin-lang.org") write_core_directory(w) - write_html_footer(w) + write_html_footer(w, true) os.make_directory("core", 0) os.write_entire_file("core/index.html", b.buf[:]) } @@ -229,7 +220,7 @@ main :: proc() { strings.reset_builder(&b) write_html_header(w, fmt.tprintf("package %s - pkg.odin-lang.org", path)) write_pkg(w, path, pkg) - write_html_footer(w) + write_html_footer(w, false) recursive_make_directory(path, "core") os.write_entire_file(fmt.tprintf("core/%s/index.html", path), b.buf[:]) } @@ -297,10 +288,19 @@ write_core_directory :: proc(w: io.Writer) { } } + fmt.wprintln(w, `
`) + defer fmt.wprintln(w, `
`) + fmt.wprintln(w, `
`) + defer fmt.wprintln(w, `
`) - fmt.wprintln(w, "

Directories

") + fmt.wprintln(w, "
") + fmt.wprintln(w, "
") + fmt.wprintln(w, "

Core Library Collection

") + fmt.wprintln(w, "
") + fmt.wprintln(w, "
") - fmt.wprintln(w, "\t
") + io.write_string(w, ``) if dir.pkg != nil { line_doc, _, _ := strings.partition(str(dir.pkg.docs), "\n") line_doc = strings.trim_space(line_doc) if line_doc != "" { - io.write_string(w, ``) write_doc_line(w, line_doc) - io.write_string(w, `
`, str(child.pkg.name)) + fmt.wprintf(w, `
`, str(child.pkg.name)) fmt.wprintf(w, `%s`, child.path, child.name) - fmt.wprintf(w, "`) if line_doc != "" { - io.write_string(w, ``) write_doc_line(w, line_doc) - io.write_string(w, `
") + fmt.wprintln(w, "
") + fmt.wprintln(w, "\t
") fmt.wprintln(w, "\t\t") for dir := root.first_child; dir != nil; dir = dir.next { @@ -356,6 +356,7 @@ write_core_directory :: proc(w: io.Writer) { fmt.wprintln(w, "\t\t") fmt.wprintln(w, "\t
") + fmt.wprintln(w, "") } is_entity_blank :: proc(e: doc.Entity_Index) -> bool { @@ -817,23 +818,42 @@ write_docs :: proc(w: io.Writer, pkg: ^doc.Pkg, docs: string) { } write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { - write_breadcrumbs :: proc(w: io.Writer, path: string) { - dirs := strings.split(path, "/") - io.write_string(w, "
    \n") - for dir, i in dirs { - url := strings.join(dirs[:i+1], "/") - short_path := strings.join(dirs[1:i+1], "/") - if i == 0 || short_path in pkgs_to_use { - fmt.wprintf(w, "
  • %s
  • ", url, dir) - } else { - fmt.wprintf(w, "
  • %s
  • ", dir) + + + fmt.wprintln(w, `
    `) + defer fmt.wprintln(w, `
    `) + + { // breadcrumbs + fmt.wprintln(w, `
\n") + fmt.wprintln(w, ``) + fmt.wprintln(w, ``) } - write_breadcrumbs(w, fmt.tprintf("core/%s", path)) + fmt.wprintln(w, `
`) fmt.wprintf(w, "

package core:%s

\n", path) fmt.wprintln(w, "

Documentation

") @@ -847,7 +867,7 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { } fmt.wprintln(w, "

Index

") - fmt.wprintln(w, `
`) + fmt.wprintln(w, `
`) pkg_procs: [dynamic]^doc.Entity pkg_proc_groups: [dynamic]^doc.Entity pkg_types: [dynamic]^doc.Entity @@ -883,7 +903,7 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { write_index :: proc(w: io.Writer, name: string, entities: []^doc.Entity) { fmt.wprintf(w, "

%s

\n", name) - fmt.wprintln(w, `
`) + fmt.wprintln(w, `
`) if len(entities) == 0 { io.write_string(w, "

This section is empty.

\n") } else { @@ -933,11 +953,11 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { name := str(e.name) path := pkg_to_path[pkg] filename := slashpath.base(str(files[e.pos.file].name)) - fmt.wprintf(w, "

{0:s}", name) + fmt.wprintf(w, "

{0:s}", name) fmt.wprintf(w, " ¶") 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) - fmt.wprintf(w, "", src_url) + fmt.wprintf(w, "", src_url) } fmt.wprintf(w, "

\n") @@ -945,7 +965,7 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { case .Invalid, .Import_Name, .Library_Name: // ignore case .Constant: - fmt.wprint(w, "
")
+			fmt.wprint(w, `
`)
 			the_type := types[e.type]
 
 			init_string := str(e.init_string)
@@ -973,7 +993,7 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) {
 			io.write_string(w, init_string)
 			fmt.wprintln(w, "
") case .Variable: - fmt.wprint(w, "
")
+			fmt.wprint(w, `
`)
 			write_attributes(w, e)
 			fmt.wprintf(w, "%s: ", name)
 			write_type(writer, types[e.type], {.Allow_Indent})
@@ -985,7 +1005,7 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) {
 			fmt.wprintln(w, "
") case .Type_Name: - fmt.wprint(w, "
")
+			fmt.wprint(w, `
`)
 			fmt.wprintf(w, "%s :: ", name)
 			the_type := types[e.type]
 			type_to_print := the_type
@@ -1004,14 +1024,14 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) {
 			write_type(writer, type_to_print, {.Allow_Indent})
 			fmt.wprintln(w, "
") case .Procedure: - fmt.wprint(w, "
")
+			fmt.wprint(w, `
`)
 			fmt.wprintf(w, "%s :: ", name)
 			write_type(writer, types[e.type], nil)
 			write_where_clauses(w, array(e.where_clauses))
 			fmt.wprint(w, " {…}")
 			fmt.wprintln(w, "
") case .Proc_Group: - fmt.wprint(w, "
")
+			fmt.wprint(w, `
`)
 			fmt.wprintf(w, "%s :: proc{{\n", name)
 			for entity_index in array(e.grouped_entities) {
 				this_proc := &entities[entity_index]
@@ -1035,7 +1055,7 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) {
 		write_docs(w, pkg, strings.trim_space(str(e.docs)))
 	}
 	write_entities :: proc(w: io.Writer, title: string, entities: []^doc.Entity) {
-		fmt.wprintf(w, "

%s

\n", title) + fmt.wprintf(w, "

{0:s}

\n", title) fmt.wprintln(w, `
`) if len(entities) == 0 { io.write_string(w, "

This section is empty.

\n") @@ -1054,7 +1074,7 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { write_entities(w, "Constants", pkg_consts[:]) - fmt.wprintln(w, "

Source Files

") + fmt.wprintln(w, `

Source Files

`) fmt.wprintln(w, "
    ") any_hidden := false source_file_loop: for file_index in array(pkg.files) { @@ -1087,4 +1107,38 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { } fmt.wprintln(w, "
") + + fmt.wprintln(w, `

`) + { + write_link :: proc(w: io.Writer, id, text: string) { + fmt.wprintf(w, `
  • %s`, id, text) + } + + write_index :: proc(w: io.Writer, name: string, entities: []^doc.Entity) { + fmt.wprintf(w, `
  • {0:s}`, name) + fmt.wprintln(w, `
      `) + for e in entities { + name := str(e.name) + fmt.wprintf(w, "
    • {0:s}
    • \n", name) + } + fmt.wprintln(w, "
    ") + fmt.wprintln(w, "
  • ") + } + + + fmt.wprintln(w, ``) + } + } \ No newline at end of file diff --git a/tools/odin-html-docs/style.css b/tools/odin-html-docs/style.css index c83a046a8..1972e99e1 100644 --- a/tools/odin-html-docs/style.css +++ b/tools/odin-html-docs/style.css @@ -1,26 +1,18 @@ -html { - font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"; -} +/* doc directories */ -.container { - max-width: 60em; - margin: 0 auto; - padding-left: 0.01em 1em; -} - -table.documentation-directory { +table.doc-directory { /*border: 1px solid #ccc!important;*/ table-layout: fixed; border-collapse: collapse; } -.documentation-directory tr { +.doc-directory tr { padding-left: 1em!important; border-top: 1px solid #ccc!important; border-bottom: 1px solid #ccc!important; } -.documentation-directory td { +.doc-directory td { padding: 0.25em 0.5em; } .directory-child td { @@ -32,59 +24,62 @@ table.documentation-directory { left: -1.5em!important; padding-right: 0; } -.pkg-line-doc { - color: #444; -} -.documentation-directory tr[aria-controls]:hover { +.doc-directory tr[aria-controls]:hover { background-color: #eee; } -.documentation-directory tr[aria-expanded=true] td.pkg-name:before { +.doc-directory tr[aria-expanded=true] td.pkg-name:before { content: "\2193"; } -.documentation-directory tr[aria-expanded=false] td.pkg-name:before { +.doc-directory tr[aria-expanded=false] td.pkg-name:before { content: "\2192"!important; } -.documentation-directory tr[aria-hidden=true] { +.doc-directory tr[aria-hidden=true] { display: none; } -pre { + +/* doc page */ + +pre.doc-code { white-space: pre-wrap; word-break: keep-all; word-wrap: break-word; tab-size: 8; - font-family: Consolas,Liberation Mono,Menlo,monospace!important; background-color: #f8f8f8; color: #202224; border: 1px solid #c6c8ca; border-radius: 0.25rem; padding: 0.625rem; } - -pre a { +pre.doc-code a { font-family: Consolas,Liberation Mono,Menlo,monospace!important; text-decoration: none; /*font-weight: bold;*/ color: #00bfd5; } -.documentation pre a.code-procedure { +pre.doc-code a.code-procedure { color: #079300; } -.documentation-source { +.pkg-line-doc { + color: #444; +} + + +.doc-source { display: inline; float: right; } -.documentation-source a { +.doc-source a { text-decoration: none; color: #666666; } -.documentation-source a:hover { +.doc-source a:hover { text-decoration: underline; } @@ -95,42 +90,6 @@ a:hover > .a-hidden { opacity: 100; } -ul.documentation-breadcrumb { - list-style: none; -} - -ul.documentation-breadcrumb li { - display: inline; -} - -ul.documentation-breadcrumb li+li:before { - padding: 0.2rem; - color: black; - content: "/\00a0"; -} - -.code-inline { - font-family: Consolas,Liberation Mono,Menlo,monospace!important; - background-color: #f8f8f8; - color: #202224; - border: 1px solid #c6c8ca; - border-radius: 0.25rem; - padding: 0.125rem; -} - -.documentation-directory { - width: 100%; -} - -.documentation-directory tr { - /*background-color: #999;*/ -} - - -.documentation-directory tr[aria-controls] { - cursor: pointer; -} - -.documentation-directory tr.hidden { - display: none; +.documentation h4 { + font-size: calc(1.1rem + .2vw); } \ No newline at end of file From 6bdb210ad8f827c93f0a903c8cdbea73555409ec Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 19 Jan 2022 13:34:54 +0000 Subject: [PATCH 15/37] More improvements to the styling --- tools/odin-html-docs/odin_html_docs_main.odin | 72 ++++++++++--------- tools/odin-html-docs/style.css | 3 +- 2 files changed, 41 insertions(+), 34 deletions(-) diff --git a/tools/odin-html-docs/odin_html_docs_main.odin b/tools/odin-html-docs/odin_html_docs_main.odin index a6b5f428e..a2d516812 100644 --- a/tools/odin-html-docs/odin_html_docs_main.odin +++ b/tools/odin-html-docs/odin_html_docs_main.odin @@ -818,56 +818,60 @@ write_docs :: proc(w: io.Writer, pkg: ^doc.Pkg, docs: string) { } write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { - - fmt.wprintln(w, `
    `) defer fmt.wprintln(w, `
    `) + fmt.wprintln(w, `
    `) + { // breadcrumbs - fmt.wprintln(w, ``) + if !is_curr && short_path in pkgs_to_use { + fmt.wprintf(w, `%s`, url, dir) + } else { + io.write_string(w, dir) + } + io.write_string(w, "\n") + } } - fmt.wprintln(w, `
    `) fmt.wprintf(w, "

    package core:%s

    \n", path) fmt.wprintln(w, "

    Documentation

    ") - docs := strings.trim_space(str(pkg.docs)) - if docs != "" { + overview_docs := strings.trim_space(str(pkg.docs)) + if overview_docs != "" { fmt.wprintln(w, "

    Overview

    ") fmt.wprintln(w, "
    ") defer fmt.wprintln(w, "
    ") - write_docs(w, pkg, docs) + write_docs(w, pkg, overview_docs) } - fmt.wprintln(w, "

    Index

    ") - fmt.wprintln(w, `
    `) + fmt.wprintln(w, `

    Index

    `) + fmt.wprintln(w, `
    `) + // fmt.wprintln(w, `

    Index

    `) + // fmt.wprintln(w, `
    `) pkg_procs: [dynamic]^doc.Entity pkg_proc_groups: [dynamic]^doc.Entity pkg_types: [dynamic]^doc.Entity @@ -1126,10 +1130,12 @@ write_pkg :: proc(w: io.Writer, path: string, pkg: ^doc.Pkg) { } - fmt.wprintln(w, `