diff --git a/cmd/tools/vdoc/html.v b/cmd/tools/vdoc/html.v
index 172bcbae0a..2f0f1fb3e3 100644
--- a/cmd/tools/vdoc/html.v
+++ b/cmd/tools/vdoc/html.v
@@ -222,14 +222,18 @@ fn (vd &VDoc) gen_html(d doc.Doc) string {
if cfg.is_multi || vd.docs.len > 1 {
mut used_submod_prefixes := map[string]bool{}
for dc in vd.docs {
- submod_prefix := dc.head.name.all_before('.')
+ mut submod_prefix := dc.head.name.all_before('.')
+ if index := dc.head.frontmatter['index'] {
+ if dc.head.name == 'index' {
+ submod_prefix = index
+ }
+ }
if used_submod_prefixes[submod_prefix] {
continue
}
used_submod_prefixes[submod_prefix] = true
mut href_name := './${dc.head.name}.html'
- if (cfg.is_vlib && dc.head.name == 'builtin' && !cfg.include_readme)
- || dc.head.name == 'README' {
+ if dc.head.name in ['README', 'index'] {
href_name = './index.html'
} else if submod_prefix !in vd.docs.map(it.head.name) {
href_name = '#'
diff --git a/cmd/tools/vdoc/utils.v b/cmd/tools/vdoc/utils.v
index f6909a96d0..3b6eafda0b 100644
--- a/cmd/tools/vdoc/utils.v
+++ b/cmd/tools/vdoc/utils.v
@@ -12,12 +12,15 @@ fn escape(str string) string {
}
fn get_sym_name(dn doc.DocNode) string {
- sym_name := if dn.parent_name.len > 0 && dn.parent_name != 'void' {
- '(${dn.parent_name}) ${dn.name}'
- } else {
- dn.name
+ if dn.is_readme {
+ if title := dn.frontmatter['title'] {
+ return title
+ }
}
- return sym_name
+ if dn.parent_name.len > 0 && dn.parent_name != 'void' {
+ return '(${dn.parent_name}) ${dn.name}'
+ }
+ return dn.name
}
fn get_node_id(dn doc.DocNode) string {
@@ -30,7 +33,7 @@ fn get_node_id(dn doc.DocNode) string {
}
fn is_module_readme(dn doc.DocNode) bool {
- return dn.comments.len > 0 && (dn.content == 'module ${dn.name}' || dn.name == 'README')
+ return dn.is_readme || (dn.comments.len > 0 && dn.content == 'module ${dn.name}')
}
// trim_doc_node_description returns the nodes trimmed description.
diff --git a/cmd/tools/vdoc/vdoc.v b/cmd/tools/vdoc/vdoc.v
index 00386f6e8e..4f7310ae8d 100644
--- a/cmd/tools/vdoc/vdoc.v
+++ b/cmd/tools/vdoc/vdoc.v
@@ -12,6 +12,11 @@ import v.util
import json
import term
+struct Readme {
+ frontmatter map[string]string
+ content string
+}
+
enum OutputType {
unset
html
@@ -159,8 +164,7 @@ fn (mut vd VDoc) render_doc(d doc.Doc, out Output) (string, string) {
fn (vd &VDoc) get_file_name(mod string, out Output) string {
cfg := vd.cfg
mut name := mod
- // since builtin is generated first, ignore it
- if (cfg.is_vlib && mod == 'builtin' && !cfg.include_readme) || mod == 'README' {
+ if mod == 'README' {
name = 'index'
} else if !cfg.is_multi && !os.is_dir(out.path) {
name = os.file_name(out.path)
@@ -220,10 +224,10 @@ fn (mut vd VDoc) render(out Output) map[string]string {
return docs
}
-fn (vd &VDoc) get_readme(path string) string {
+fn (vd &VDoc) get_readme(path string) Readme {
mut fname := ''
- for name in ['readme', 'README'] {
- if os.exists(os.join_path(path, '${name}.md')) {
+ for name in ['readme.md', 'README.md'] {
+ if os.exists(os.join_path(path, name)) {
fname = name
break
}
@@ -232,12 +236,28 @@ fn (vd &VDoc) get_readme(path string) string {
if path.all_after_last(os.path_separator) == 'src' {
return vd.get_readme(path.all_before_last(os.path_separator))
}
- return ''
+ return Readme{}
}
- readme_path := os.join_path(path, '${fname}.md')
+ readme_path := os.join_path(path, fname)
vd.vprintln('Reading README file from ${readme_path}')
- readme_contents := os.read_file(readme_path) or { '' }
- return readme_contents
+ mut readme_contents := os.read_file(readme_path) or { '' }
+ mut readme_frontmatter := map[string]string{}
+ if readme_contents.starts_with('---\n') {
+ if frontmatter_lines_end_idx := readme_contents.index('\n---\n') {
+ front_matter_lines := readme_contents#[4..frontmatter_lines_end_idx].trim_space().split_into_lines()
+ for line in front_matter_lines {
+ x := line.split(': ')
+ if x.len == 2 {
+ readme_frontmatter[x[0]] = x[1]
+ }
+ }
+ readme_contents = readme_contents#[5 + frontmatter_lines_end_idx..]
+ }
+ }
+ return Readme{
+ frontmatter: readme_frontmatter
+ content: readme_contents
+ }
}
fn (vd &VDoc) emit_generate_err(err IError) {
@@ -277,7 +297,7 @@ fn (mut vd VDoc) generate_docs_from_file() {
exit(1)
}
dir_path := if cfg.is_vlib {
- vroot
+ os.join_path(vroot, 'vlib')
} else if os.is_dir(cfg.input_path) {
cfg.input_path
} else {
@@ -290,18 +310,26 @@ fn (mut vd VDoc) generate_docs_from_file() {
vd.manifest = manifest
}
}
- if cfg.include_readme {
- readme_contents := vd.get_readme(dir_path)
+ if cfg.include_readme || cfg.is_vlib {
+ mut readme_name := 'README'
+ readme := vd.get_readme(dir_path)
+ if page := readme.frontmatter['page'] {
+ readme_name = page
+ }
comment := doc.DocComment{
- text: readme_contents
+ is_readme: true
+ frontmatter: readme.frontmatter
+ text: readme.content
}
if out.typ == .ansi {
- println(markdown.to_plain(readme_contents))
+ println(markdown.to_plain(readme.content))
} else if out.typ == .html && cfg.is_multi {
vd.docs << doc.Doc{
head: doc.DocNode{
- name: 'README'
- comments: [comment]
+ is_readme: true
+ name: readme_name
+ frontmatter: readme.frontmatter
+ comments: [comment]
}
time_generated: time.now()
}
@@ -327,9 +355,11 @@ fn (mut vd VDoc) generate_docs_from_file() {
continue
}
if cfg.is_multi || (!cfg.is_multi && cfg.include_readme) {
- readme_contents := vd.get_readme(dirpath)
+ readme := vd.get_readme(dirpath)
comment := doc.DocComment{
- text: readme_contents
+ is_readme: true
+ frontmatter: readme.frontmatter
+ text: readme.content
}
dcs.head.comments = [comment]
}
@@ -343,13 +373,6 @@ fn (mut vd VDoc) generate_docs_from_file() {
}
vd.docs << dcs
}
- // Important. Let builtin be in the top of the module list
- // if we are generating docs for vlib.
- if cfg.is_vlib {
- mut docs := vd.docs.filter(it.head.name == 'builtin')
- docs << vd.docs.filter(it.head.name != 'builtin')
- vd.docs = docs
- }
if dirs.len == 0 && cfg.is_multi {
eprintln('vdoc: -m requires at least 1 module folder')
exit(1)
diff --git a/vlib/README.md b/vlib/README.md
index f2f18533a7..19aa64ce7f 100644
--- a/vlib/README.md
+++ b/vlib/README.md
@@ -1,8 +1,21 @@
-# `vlib` Documentation
+---
+page: index
+title: V standard library documentation
+index: V stdlib
+---
+This site contains the documentation for the standard library of modules
+included with the [V language](https://vlang.io). Also commonly referred
+to as `vlib`, as that is the root directory for these modules in the V
+repository.
-`vlib` is the term for all modules included by default with V and
-maintained as part of the V source code repository.
+If you were looking for documentation for the language itself, the
+builtin types, operators, et. al., please use the
+[V documentation](https://docs.vlang.io/introduction.html) link.
Some included modules depend on third party libraries, and these are kept
separate in the `thirdparty` directory at the root level of the source
repository.
+
+Note that the [builtin](https://modules.vlang.io/builtin.html) module is
+implicitly imported by default in V, so you do not need to have a specific
+`import` statement to use any of the features of that module.
diff --git a/vlib/v/doc/comment.v b/vlib/v/doc/comment.v
index dfb19d024d..99616eac7f 100644
--- a/vlib/v/doc/comment.v
+++ b/vlib/v/doc/comment.v
@@ -6,9 +6,11 @@ const example_pattern = '\x01 Example: '
pub struct DocComment {
pub mut:
- text string // Raw text content of the comment, excluding the comment token chars ('//, /*, */')
- is_multi bool // Is a block / multi-line comment
- pos token.Pos
+ text string // Raw text content of the comment, excluding the comment token chars ('//, /*, */')
+ is_multi bool // Is a block / multi-line comment
+ pos token.Pos
+ is_readme bool
+ frontmatter map[string]string
}
// is_example returns true if the contents of this comment is an inline doc example.
diff --git a/vlib/v/doc/doc.v b/vlib/v/doc/doc.v
index f236ce1886..5cf27a91b6 100644
--- a/vlib/v/doc/doc.v
+++ b/vlib/v/doc/doc.v
@@ -143,6 +143,8 @@ pub mut:
from_scope bool
is_pub bool @[json: public]
platform Platform
+ is_readme bool
+ frontmatter map[string]string
}
// new_vdoc_preferences creates a new instance of pref.Preferences tailored for v.doc.