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, "
") }