v/cmd/tools/vdoc/main.v

227 lines
5.9 KiB
V

module main
import os
import os.cmdline
import term
import document as doc
import v.vmod
const vexe = os.getenv_opt('VEXE') or { @VEXE }
const vroot = os.dir(vexe)
const allowed_formats = ['md', 'markdown', 'json', 'text', 'ansi', 'html', 'htm']
struct Config {
mut:
pub_only bool = true
show_loc bool // for plaintext
is_color bool
is_multi bool
is_vlib bool
is_verbose bool
include_readme bool
include_examples bool = true
include_comments bool // for plaintext
inline_assets bool
theme_dir string = default_theme
no_timestamp bool
output_path string
output_type OutputType = .unset
input_path string
symbol_name string
platform doc.Platform
run_examples bool // `-run-examples` will run all `// Example: assert mod.abc() == y` comments in the processed modules
// The options below are useful for generating a more stable HTML, that is easier to regression test:
html_only_contents bool // `-html-only-contents` will produce only the content of any given page, without styling tags etc.
html_no_vhash bool // `-html-no-vhash` will remove the version hash from the generated html
html_no_assets bool // `-html-no-assets` will not include CSS and JS asset tags in the generated html
html_no_right bool // `-html-no-right` will not add the doc-toc right panel in the generated html
html_no_toc_urls bool // `-html-no-toc-urls` will not add the toc_links panel in the generated html
html_no_footer bool // `-html-no-footer` will not add the footer panel in the generated html
}
fn main() {
if os.args.len < 2 || '-h' in os.args || '-help' in os.args || '--help' in os.args
|| os.args[1..] == ['doc', 'help'] {
os.system('${os.quoted_path(vexe)} help doc')
exit(0)
}
args := os.args[2..].clone()
cfg := parse_arguments(args)
if cfg.input_path == '' {
eprintln('vdoc: No input path found.')
exit(1)
}
// Config is immutable from this point on
mut vd := &VDoc{
cfg: cfg
manifest: vmod.Manifest{}
}
vd.vprintln('Setting output type to "${cfg.output_type}"')
vd.generate_docs_from_file()
if cfg.run_examples {
println('')
if vd.example_oks == 0 && vd.example_failures == 0 {
println(term.colorize(term.bright_yellow, 'Found NO examples.'))
} else {
println(term.colorize(term.gray, 'Found ${vd.example_oks} ok examples.'))
}
if vd.example_failures > 0 {
println(term.colorize(term.red, 'Found ${vd.example_failures} failing examples.'))
exit(1)
}
}
}
fn parse_arguments(args []string) Config {
mut cfg := Config{}
cfg.is_color = term.can_show_color_on_stdout()
mut is_color_was_set_explicitly := false
for i := 0; i < args.len; i++ {
arg := args[i]
current_args := args[i..]
match arg {
'-all' {
cfg.pub_only = false
}
'-f' {
format := cmdline.option(current_args, '-f', '')
if format !in allowed_formats {
allowed_str := allowed_formats.join(', ')
eprintln('vdoc: "${format}" is not a valid format. Only ${allowed_str} are allowed.')
exit(1)
}
cfg.output_type = set_output_type_from_str(format)
i++
}
'-color' {
cfg.is_color = true
is_color_was_set_explicitly = true
}
'-no-color' {
cfg.is_color = false
is_color_was_set_explicitly = true
}
'-inline-assets' {
cfg.inline_assets = true
}
'-theme-dir' {
cfg.theme_dir = cmdline.option(current_args, '-theme-dir', default_theme)
}
'-l' {
cfg.show_loc = true
}
'-comments' {
cfg.include_comments = true
}
'-m' {
cfg.is_multi = true
}
'-o' {
opath := cmdline.option(current_args, '-o', '')
cfg.output_path = if opath in ['stdout', '-'] { opath } else { os.real_path(opath) }
i++
}
'-os' {
platform_str := cmdline.option(current_args, '-os', '')
if platform_str == 'cross' {
eprintln('`v doc -os cross` is not supported yet.')
exit(1)
}
selected_platform := doc.platform_from_string(platform_str) or {
eprintln(err.msg())
exit(1)
}
cfg.platform = selected_platform
i++
}
'-run-examples' {
cfg.run_examples = true
}
'-no-timestamp' {
cfg.no_timestamp = true
}
'-no-examples' {
cfg.include_examples = false
}
//
'-html-only-contents' {
cfg.html_only_contents = true
}
'-html-no-vhash' {
cfg.html_no_vhash = true
}
'-html-no-assets' {
cfg.html_no_assets = true
}
'-html-no-right' {
cfg.html_no_right = true
}
'-html-no-toc-urls' {
cfg.html_no_toc_urls = true
}
'-html-no-footer' {
cfg.html_no_footer = true
}
//
'-readme' {
cfg.include_readme = true
}
'-v' {
cfg.is_verbose = true
}
else {
if cfg.input_path == '' {
cfg.input_path = arg
} else if !cfg.is_multi {
// Symbol name filtering should not be enabled
// in multi-module documentation mode.
cfg.symbol_name = arg
}
if i == args.len - 1 {
break
}
}
}
}
if cfg.output_type == .html {
// quirks specific to *just* the html output mode:
if cfg.output_path in ['stdout', '-'] {
cfg.inline_assets = true
}
}
if !is_color_was_set_explicitly {
if cfg.output_type == .plaintext {
cfg.is_color = false
} else if cfg.output_type == .ansi {
cfg.is_color = true
}
}
if cfg.is_color {
os.setenv('VCOLORS', 'always', true)
} else {
os.setenv('VCOLORS', 'never', true)
}
cfg.input_path = cfg.input_path.replace('\\', '/')
is_path := cfg.input_path.ends_with('.v') || cfg.input_path.split('/').len > 1
|| cfg.input_path == '.'
if cfg.input_path.trim_right('/') == 'vlib' {
cfg.is_vlib = true
cfg.is_multi = true
cfg.input_path = os.join_path(vroot, 'vlib')
} else if !is_path {
mod_path := doc.lookup_module(cfg.input_path) or {
eprintln('vdoc: ${err}')
exit(1)
}
cfg.input_path = mod_path
}
cfg.input_path = cfg.input_path.replace('/', os.path_separator)
return cfg
}