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" GITHUB_CORE_URL :: "https://github.com/odin-lang/Odin/tree/master/core" 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) } base_type :: proc(t: doc.Type) -> doc.Type { t := t for { if t.kind != .Named { break } t = types[array(t.types)[0]] } 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 "" } 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 } 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, `
| `, 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) } io.write_string(w, ` | `) 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 != "" { write_doc_line(w, line_doc) } } io.write_string(w, ` | `) fmt.wprintf(w, "
| `, str(child.pkg.name)) fmt.wprintf(w, `%s`, child.path, child.name) io.write_string(w, ` | `) line_doc, _, _ := strings.partition(str(child.pkg.docs), "\n") line_doc = strings.trim_space(line_doc) io.write_string(w, ``) if line_doc != "" { write_doc_line(w, line_doc) } io.write_string(w, ` | `) fmt.wprintf(w, "") fmt.wprintf(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
}
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, "")
continue
}
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 write_doc_line(w, text) io.write_byte(w, '\n') } if was_code { // assert(!was_paragraph, str(pkg.name)) was_code = false fmt.wprintln(w, "") } if was_paragraph { fmt.wprintln(w, "
") } } 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") } write_breadcrumbs(w, fmt.tprintf("core/%s", path)) fmt.wprintf(w, "This section is empty.
\n") } else { fmt.wprintln(w, "")
the_type := types[e.type]
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)
write_type(writer, the_type, {.Allow_Indent})
fmt.wprintf(w, " : ")
}
io.write_string(w, init_string)
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)
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)
the_type := types[e.type]
type_to_print := the_type
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
}
}
write_type(writer, type_to_print, {.Allow_Indent})
fmt.wprintln(w, "")
case .Procedure:
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.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)))
}
write_entities :: proc(w: io.Writer, title: string, entities: []^doc.Entity) {
fmt.wprintf(w, "This section is empty.
\n") } else { for e in entities { write_entity(w, e) } } fmt.wprintln(w, "