From 4458e4965230f26a27d047c828264db5e9ace1c8 Mon Sep 17 00:00:00 2001 From: Swastik Baranwal Date: Thu, 16 Nov 2023 23:44:28 +0530 Subject: [PATCH] vdoc: fix syntax highlighting for symbols before `!` and between `(` and `,` (#19888) --- TESTS.md | 8 ++ cmd/tools/vdoc/.gitattributes | 3 + cmd/tools/vdoc/html.v | 83 +++++++++++----- cmd/tools/vdoc/main.v | 92 +++++++++++++++--- .../tests/testdata/newlines/main.comments.out | 2 +- .../vdoc/tests/testdata/newlines/main.out | 2 +- .../tests/testdata/output_formats/main.ansi | 36 +++++++ .../tests/testdata/output_formats/main.html | 96 +++++++++++++++++++ .../tests/testdata/output_formats/main.text | 35 +++++++ .../vdoc/tests/testdata/output_formats/main.v | 75 +++++++++++++++ .../src/main.comments.out | 2 +- .../src/main.readme.comments.out | 2 +- cmd/tools/vdoc/tests/vdoc_file_test.v | 25 ++++- cmd/tools/vdoc/utils.v | 17 ++-- cmd/tools/vdoc/vdoc.v | 32 +------ vlib/v/help/common/doc.txt | 31 +++--- 16 files changed, 453 insertions(+), 88 deletions(-) create mode 100644 cmd/tools/vdoc/.gitattributes create mode 100644 cmd/tools/vdoc/tests/testdata/output_formats/main.ansi create mode 100644 cmd/tools/vdoc/tests/testdata/output_formats/main.html create mode 100644 cmd/tools/vdoc/tests/testdata/output_formats/main.text create mode 100644 cmd/tools/vdoc/tests/testdata/output_formats/main.v diff --git a/TESTS.md b/TESTS.md index a2d20a1bce..c3803cdde1 100644 --- a/TESTS.md +++ b/TESTS.md @@ -185,3 +185,11 @@ tests in the main V repository, for example: * `v vet vlib/v` - run a style checker. * `v test-self` (run self tests) in various compilation modes. + +> **Note** +The VDOC test vdoc_file_test.v now also supports VAUTOFIX, which is +useful, if you change anything inside cmd/tools/vdoc or vlib/v/doc/, +or inside the modules that it depends on (like markdown). +After such changes, just run this command *2 times*, and commit the +resulting changes in `cmd/tools/vdoc/tests/testdata` as well: +`VAUTOFIX=1 ./v cmd/tools/vdoc/tests/vdoc_file_test.v` diff --git a/cmd/tools/vdoc/.gitattributes b/cmd/tools/vdoc/.gitattributes new file mode 100644 index 0000000000..c05b8c16fd --- /dev/null +++ b/cmd/tools/vdoc/.gitattributes @@ -0,0 +1,3 @@ +*.ansi text eol=lf +*.text text eol=lf +*.html text eol=lf diff --git a/cmd/tools/vdoc/html.v b/cmd/tools/vdoc/html.v index 2c7e60c325..677121827a 100644 --- a/cmd/tools/vdoc/html.v +++ b/cmd/tools/vdoc/html.v @@ -198,11 +198,14 @@ fn (vd VDoc) gen_html(d doc.Doc) string { } for cn in dcs_contents { vd.write_content(&cn, &d, mut contents) - write_toc(cn, mut symbols_toc) - } // write head + write_toc(cn, mut symbols_toc) // write head + } + if cfg.html_only_contents { + // no need for theming, styling etc, useful for testing and for external documentation generators + return contents.str() + } + // write css - mut version := if vd.manifest.version.len != 0 { vd.manifest.version } else { '' } - version = [version, @VCURRENTHASH].join(' ') header_name := if cfg.is_multi && vd.docs.len > 1 { os.file_name(os.real_path(cfg.input_path)) } else { @@ -249,33 +252,65 @@ fn (vd VDoc) gen_html(d doc.Doc) string { } modules_toc_str := modules_toc.str() symbols_toc_str := symbols_toc.str() - result := (os.read_file(os.join_path(cfg.theme_dir, 'index.html')) or { panic(err) }).replace('{{ title }}', - d.head.name).replace('{{ head_name }}', header_name).replace('{{ version }}', - version).replace('{{ light_icon }}', vd.assets['light_icon']).replace('{{ dark_icon }}', - vd.assets['dark_icon']).replace('{{ menu_icon }}', vd.assets['menu_icon']).replace('{{ head_assets }}', - if cfg.inline_assets { - ' + mut result := os.read_file(os.join_path(cfg.theme_dir, 'index.html')) or { panic(err) } + if cfg.html_no_vhash { + result = result.replace('{{ version }}', 'latest') + } else { + mut version := if vd.manifest.version.len != 0 { vd.manifest.version } else { '' } + version = [version, @VCURRENTHASH].join(' ') + result = result.replace('{{ version }}', version) + } + result = result.replace('{{ title }}', d.head.name) + result = result.replace('{{ head_name }}', header_name) + result = result.replace('{{ light_icon }}', vd.assets['light_icon']) + result = result.replace('{{ dark_icon }}', vd.assets['dark_icon']) + result = result.replace('{{ menu_icon }}', vd.assets['menu_icon']) + if cfg.html_no_assets { + result = result.replace('{{ head_assets }}', '') + } else { + result = result.replace('{{ head_assets }}', if cfg.inline_assets { + ' ${tabs(2)} ${tabs(2)}' - } else { - ' + } else { + ' ${tabs(2)} ${tabs(2)}' - }).replace('{{ toc_links }}', if cfg.is_multi || vd.docs.len > 1 { - modules_toc_str + }) + } + if cfg.html_no_toc_urls { + result = result.replace('{{ toc_links }}', '') } else { - symbols_toc_str - }).replace('{{ contents }}', contents.str()).replace('{{ right_content }}', if cfg.is_multi - && d.head.name != 'README' { - '
' + result = result.replace('{{ toc_links }}', if cfg.is_multi || vd.docs.len > 1 { + modules_toc_str + } else { + symbols_toc_str + }) + } + result = result.replace('{{ contents }}', contents.str()) + if cfg.html_no_right { + result = result.replace('{{ right_content }}', '') } else { - '' - }).replace('{{ footer_content }}', gen_footer_text(d, !cfg.no_timestamp)).replace('{{ footer_assets }}', - if cfg.inline_assets { - '' + result = result.replace('{{ right_content }}', if cfg.is_multi && d.head.name != 'README' { + '
' + } else { + '' + }) + } + if cfg.html_no_footer { + result = result.replace('{{ footer_content }}', '') } else { - '' - }) + result = result.replace('{{ footer_content }}', gen_footer_text(d, !cfg.no_timestamp)) + } + if cfg.html_no_assets { + result = result.replace('{{ footer_assets }}', '') + } else { + result = result.replace('{{ footer_assets }}', if cfg.inline_assets { + '' + } else { + '' + }) + } return result } diff --git a/cmd/tools/vdoc/main.v b/cmd/tools/vdoc/main.v index 14667faad0..ff12199d73 100644 --- a/cmd/tools/vdoc/main.v +++ b/cmd/tools/vdoc/main.v @@ -10,7 +10,36 @@ const vexe = os.getenv_opt('VEXE') or { @VEXE } const vroot = os.dir(vexe) -const allowed_formats = ['md', 'markdown', 'json', 'text', 'stdout', 'html', 'htm'] +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 HMTL, 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 @@ -27,9 +56,7 @@ fn main() { // Config is immutable from this point on mut vd := &VDoc{ cfg: cfg - manifest: vmod.Manifest{ - repo_url: '' - } + manifest: vmod.Manifest{} } vd.vprintln('Setting output type to "${cfg.output_type}"') vd.generate_docs_from_file() @@ -50,6 +77,7 @@ fn main() { 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..] @@ -69,9 +97,11 @@ fn parse_arguments(args []string) Config { } '-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 @@ -90,7 +120,7 @@ fn parse_arguments(args []string) Config { } '-o' { opath := cmdline.option(current_args, '-o', '') - cfg.output_path = if opath == 'stdout' { opath } else { os.real_path(opath) } + cfg.output_path = if opath in ['stdout', '-'] { opath } else { os.real_path(opath) } i++ } '-os' { @@ -115,6 +145,26 @@ fn parse_arguments(args []string) Config { '-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 } @@ -135,28 +185,42 @@ fn parse_arguments(args []string) Config { } } } - // Correct from configuration from user input - if cfg.output_path == 'stdout' && cfg.output_type == .html { - cfg.inline_assets = true + + if cfg.output_type == .html { + // quirks specific to *just* the html output mode: + if cfg.output_path in ['stdout', '-'] { + cfg.inline_assets = true + } } - $if windows { - cfg.input_path = cfg.input_path.replace('/', os.path_separator) - } $else { - cfg.input_path = cfg.input_path.replace('\\', os.path_separator) + + 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 + } } - is_path := cfg.input_path.ends_with('.v') || cfg.input_path.split(os.path_separator).len > 1 + + 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 { - // TODO vd.vprintln('Input "$cfg.input_path" is not a valid path. Looking for modules named "$cfg.input_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 } diff --git a/cmd/tools/vdoc/tests/testdata/newlines/main.comments.out b/cmd/tools/vdoc/tests/testdata/newlines/main.comments.out index a789d11bb6..d25b9bff24 100644 --- a/cmd/tools/vdoc/tests/testdata/newlines/main.comments.out +++ b/cmd/tools/vdoc/tests/testdata/newlines/main.comments.out @@ -19,4 +19,4 @@ fn funky() | foo bar | yes | |-----------|--------| - | working | yup | \ No newline at end of file + | working | yup | diff --git a/cmd/tools/vdoc/tests/testdata/newlines/main.out b/cmd/tools/vdoc/tests/testdata/newlines/main.out index 02bcce98fe..b8602997f7 100644 --- a/cmd/tools/vdoc/tests/testdata/newlines/main.out +++ b/cmd/tools/vdoc/tests/testdata/newlines/main.out @@ -1,3 +1,3 @@ module main -fn funky() \ No newline at end of file +fn funky() diff --git a/cmd/tools/vdoc/tests/testdata/output_formats/main.ansi b/cmd/tools/vdoc/tests/testdata/output_formats/main.ansi new file mode 100644 index 0000000000..16afcacf36 --- /dev/null +++ b/cmd/tools/vdoc/tests/testdata/output_formats/main.ansi @@ -0,0 +1,36 @@ + +module main + +const omega = 3 // should be first +const alpha = 5 // should be in the middle +const beta = 2 // should be at the end +fn abc() + abc - should be last +fn def() + def - should be first +fn xyz() + xyz - should be in the middle +fn MyXMLDocument.abc(text string) ?(string, int) + MyXMLDocument.abc does something too... I just do not know what. +fn MyXMLDocument.from_file(path string) !MyXMLDocument + MyXMLDocument.from_text processes the file path, and returns an error +fn MyXMLDocument.from_text(text string) ?MyXMLDocument + MyXMLDocument.from_text processes text and produces none +struct MyXMLDocument { + path string +} + MyXMLDocument is here just to test the different combinations of methods/output types +fn (x &MyXMLDocument) instance_from_file(path string) !MyXMLDocument + instance_from_file does stuff with path +fn (x &MyXMLDocument) instance_from_text(text string) ?MyXMLDocument + instance_from_text does stuff with text +fn (x &MyXMLDocument) instance_abc(text string) ?(string, int) + instance_abc does stuff too +fn (x &MyXMLDocument) instance_void() + instance_void does stuff too +fn (x &MyXMLDocument) instance_int() int + instance_int does stuff too +fn (x &MyXMLDocument) instance_result() ! + instance_error does stuff too +fn (x &MyXMLDocument) instance_option() ? + instance_option does stuff too diff --git a/cmd/tools/vdoc/tests/testdata/output_formats/main.html b/cmd/tools/vdoc/tests/testdata/output_formats/main.html new file mode 100644 index 0000000000..522ae1976b --- /dev/null +++ b/cmd/tools/vdoc/tests/testdata/output_formats/main.html @@ -0,0 +1,96 @@ +
+

main #

+ +
+ +
+

Constants #

+ +
+
+
const omega = 3 // should be first
+ + +
+
+
const alpha = 5 // should be in the middle
+ + +
+
+
const beta = 2 // should be at the end
+ + +
+
+

fn abc #

fn abc()
+

abc - should be last

+ +
+
+

fn def #

fn def()
+

def - should be first

+ +
+
+

fn xyz #

fn xyz()
+

xyz - should be in the middle

+ +
+
+

fn MyXMLDocument.abc #

fn MyXMLDocument.abc(text string) ?(string, int)
+

MyXMLDocument.abc does something too... I just do not know what.

+ +
+
+

fn MyXMLDocument.from_file #

fn MyXMLDocument.from_file(path string) !MyXMLDocument
+

MyXMLDocument.from_text processes the file path, and returns an error

+ +
+
+

fn MyXMLDocument.from_text #

fn MyXMLDocument.from_text(text string) ?MyXMLDocument
+

MyXMLDocument.from_text processes text and produces none

+ +
+
+

struct MyXMLDocument #

struct MyXMLDocument {
+	path string
+}
+

MyXMLDocument is here just to test the different combinations of methods/output types

+ +
+
+

fn (MyXMLDocument) instance_from_file #

fn (x &MyXMLDocument) instance_from_file(path string) !MyXMLDocument
+

instance_from_file does stuff with path

+ +
+
+

fn (MyXMLDocument) instance_from_text #

fn (x &MyXMLDocument) instance_from_text(text string) ?MyXMLDocument
+

instance_from_text does stuff with text

+ +
+
+

fn (MyXMLDocument) instance_abc #

fn (x &MyXMLDocument) instance_abc(text string) ?(string, int)
+

instance_abc does stuff too

+ +
+
+

fn (MyXMLDocument) instance_void #

fn (x &MyXMLDocument) instance_void()
+

instance_void does stuff too

+ +
+
+

fn (MyXMLDocument) instance_int #

fn (x &MyXMLDocument) instance_int() int
+

instance_int does stuff too

+ +
+
+

fn (MyXMLDocument) instance_result #

fn (x &MyXMLDocument) instance_result() !
+

instance_error does stuff too

+ +
+
+

fn (MyXMLDocument) instance_option #

fn (x &MyXMLDocument) instance_option() ?
+

instance_option does stuff too

+ +
diff --git a/cmd/tools/vdoc/tests/testdata/output_formats/main.text b/cmd/tools/vdoc/tests/testdata/output_formats/main.text new file mode 100644 index 0000000000..cf1cd8a93a --- /dev/null +++ b/cmd/tools/vdoc/tests/testdata/output_formats/main.text @@ -0,0 +1,35 @@ +module main + +const omega = 3 // should be first +const alpha = 5 // should be in the middle +const beta = 2 // should be at the end +fn abc() + abc - should be last +fn def() + def - should be first +fn xyz() + xyz - should be in the middle +fn MyXMLDocument.abc(text string) ?(string, int) + MyXMLDocument.abc does something too... I just do not know what. +fn MyXMLDocument.from_file(path string) !MyXMLDocument + MyXMLDocument.from_text processes the file path, and returns an error +fn MyXMLDocument.from_text(text string) ?MyXMLDocument + MyXMLDocument.from_text processes text and produces none +struct MyXMLDocument { + path string +} + MyXMLDocument is here just to test the different combinations of methods/output types +fn (x &MyXMLDocument) instance_from_file(path string) !MyXMLDocument + instance_from_file does stuff with path +fn (x &MyXMLDocument) instance_from_text(text string) ?MyXMLDocument + instance_from_text does stuff with text +fn (x &MyXMLDocument) instance_abc(text string) ?(string, int) + instance_abc does stuff too +fn (x &MyXMLDocument) instance_void() + instance_void does stuff too +fn (x &MyXMLDocument) instance_int() int + instance_int does stuff too +fn (x &MyXMLDocument) instance_result() ! + instance_error does stuff too +fn (x &MyXMLDocument) instance_option() ? + instance_option does stuff too diff --git a/cmd/tools/vdoc/tests/testdata/output_formats/main.v b/cmd/tools/vdoc/tests/testdata/output_formats/main.v new file mode 100644 index 0000000000..791928b382 --- /dev/null +++ b/cmd/tools/vdoc/tests/testdata/output_formats/main.v @@ -0,0 +1,75 @@ +pub const omega = 3 // should be first + +pub const alpha = 5 // should be in the middle + +pub const beta = 2 // should be at the end + +// def - should be first +pub fn def() { + println(1) +} + +// xyz - should be in the middle +pub fn xyz() { + println(2) +} + +// abc - should be last +pub fn abc() { + println(3) +} + +// MyXMLDocument is here just to test the different combinations of methods/output types +pub struct MyXMLDocument { + path string +} + +// MyXMLDocument.from_text processes the file path, and returns an error +pub fn MyXMLDocument.from_file(path string) !MyXMLDocument { + return error('TODO') +} + +// MyXMLDocument.from_text processes text and produces none +pub fn MyXMLDocument.from_text(text string) ?MyXMLDocument { + return none +} + +// MyXMLDocument.abc does something too... I just do not know what. +pub fn MyXMLDocument.abc(text string) ?(string, int) { + return 'xyz', 123 +} + +// instance_from_file does stuff with path +pub fn (x &MyXMLDocument) instance_from_file(path string) !MyXMLDocument { + return error('TODO') +} + +// instance_from_text does stuff with text +pub fn (x &MyXMLDocument) instance_from_text(text string) ?MyXMLDocument { + return none +} + +// instance_abc does stuff too +pub fn (x &MyXMLDocument) instance_abc(text string) ?(string, int) { + return 'xyz', 123 +} + +// instance_void does stuff too +pub fn (x &MyXMLDocument) instance_void() { + return 123 +} + +// instance_int does stuff too +pub fn (x &MyXMLDocument) instance_int() int { + return 123 +} + +// instance_error does stuff too +pub fn (x &MyXMLDocument) instance_result() ! { + return 123 +} + +// instance_option does stuff too +pub fn (x &MyXMLDocument) instance_option() ? { + return 123 +} diff --git a/cmd/tools/vdoc/tests/testdata/readme_in_project_root/src/main.comments.out b/cmd/tools/vdoc/tests/testdata/readme_in_project_root/src/main.comments.out index fd82920d6f..8b0207f2fa 100644 --- a/cmd/tools/vdoc/tests/testdata/readme_in_project_root/src/main.comments.out +++ b/cmd/tools/vdoc/tests/testdata/readme_in_project_root/src/main.comments.out @@ -1,3 +1,3 @@ module foo -fn bar() \ No newline at end of file +fn bar() diff --git a/cmd/tools/vdoc/tests/testdata/readme_in_project_root/src/main.readme.comments.out b/cmd/tools/vdoc/tests/testdata/readme_in_project_root/src/main.readme.comments.out index e4c69b8253..e426e3ec2f 100644 --- a/cmd/tools/vdoc/tests/testdata/readme_in_project_root/src/main.readme.comments.out +++ b/cmd/tools/vdoc/tests/testdata/readme_in_project_root/src/main.readme.comments.out @@ -1,4 +1,4 @@ hello from readme module foo -fn bar() \ No newline at end of file +fn bar() diff --git a/cmd/tools/vdoc/tests/vdoc_file_test.v b/cmd/tools/vdoc/tests/vdoc_file_test.v index a1a3ddfe72..7db54ff91c 100644 --- a/cmd/tools/vdoc/tests/vdoc_file_test.v +++ b/cmd/tools/vdoc/tests/vdoc_file_test.v @@ -10,6 +10,8 @@ const vroot = @VMODROOT const diff_cmd = find_diff_cmd() +const should_autofix = os.getenv('VAUTOFIX') != '' + fn find_diff_cmd() string { return diff.find_working_diff_command() or { '' } } @@ -82,6 +84,23 @@ fn check_path(vexe string, dir string, tests []string) int { cmd: '${os.quoted_path(vexe)} doc -readme -comments ${os.quoted_path(program)}' out_filename: 'main.readme.comments.out' ) + // test the main 3 different formats: + fails += check_output( + program: program + cmd: '${os.quoted_path(vexe)} doc -f html -o - -html-only-contents -readme -comments ${os.quoted_path(program)}' + out_filename: 'main.html' + ) + fails += check_output( + program: program + cmd: '${os.quoted_path(vexe)} doc -f ansi -o - -html-only-contents -readme -comments ${os.quoted_path(program)}' + out_filename: 'main.ansi' + ) + fails += check_output( + program: program + cmd: '${os.quoted_path(vexe)} doc -f text -o - -html-only-contents -readme -comments ${os.quoted_path(program)}' + out_filename: 'main.text' + ) + // total_fails += fails if fails == 0 { println(term.green('OK')) @@ -141,9 +160,13 @@ fn check_output(params CheckOutputParams) int { found := clean_line_endings(res.output) if expected != found { print_compare(expected, found) - eprintln('>>> out_file_path: ${out_file_path}') eprintln('>>> cmd: VDOC_SORT=${params.should_sort} ${params.cmd}') + eprintln('>>> out_file_path: `${out_file_path}`') + eprintln('>>> fix: VDOC_SORT=${params.should_sort} ${params.cmd} > ${out_file_path}') fails++ } + if should_autofix { + os.write_file(out_file_path, res.output) or {} + } return fails } diff --git a/cmd/tools/vdoc/utils.v b/cmd/tools/vdoc/utils.v index 5251af071d..1ab5bfbafb 100644 --- a/cmd/tools/vdoc/utils.v +++ b/cmd/tools/vdoc/utils.v @@ -60,14 +60,14 @@ fn trim_doc_node_description(description string) string { } fn set_output_type_from_str(format string) OutputType { - output_type := match format { + return match format { 'htm', 'html' { OutputType.html } - 'md', 'markdown' { OutputType.markdown } - 'json' { OutputType.json } - 'stdout' { OutputType.stdout } - else { OutputType.plaintext } + 'md', 'markdown' { .markdown } + 'json' { .json } + 'text' { .plaintext } + 'ansi' { .ansi } + else { .ansi } } - return output_type } fn get_ignore_paths(path string) ![]string { @@ -213,10 +213,13 @@ fn color_highlight(code string, tb &ast.Table) string { } else if (next_tok.kind in [.lcbr, .rpar, .eof, .comma, .pipe, .name, .rcbr, .assign, .key_pub, .key_mut, .pipe, .comma, .comment, .lt, .lsbr] && next_tok.lit !in builtin) - && (prev.kind in [.name, .amp, .lcbr, .rsbr, .key_type, .assign, .dot, .question, .rpar, .key_struct, .key_enum, .pipe, .key_interface, .comment, .ellipsis] + && (prev.kind in [.name, .amp, .lcbr, .rsbr, .key_type, .assign, .dot, .not, .question, .rpar, .key_struct, .key_enum, .pipe, .key_interface, .comment, .ellipsis, .comma] && prev.lit !in builtin) && ((tok.lit != '' && tok.lit[0].is_capital()) || prev_prev.lit in ['C', 'JS']) { tok_typ = .symbol + } else if tok.lit[0].is_capital() && prev.kind == .lpar + && next_tok.kind == .comma { + tok_typ = .symbol } else if next_tok.kind == .lpar || (!(tok.lit != '' && tok.lit[0].is_capital()) && next_tok.kind in [.lt, .lsbr] && next_tok.pos == tok.pos + tok.lit.len) { diff --git a/cmd/tools/vdoc/vdoc.v b/cmd/tools/vdoc/vdoc.v index 8189694575..3950867a7c 100644 --- a/cmd/tools/vdoc/vdoc.v +++ b/cmd/tools/vdoc/vdoc.v @@ -17,8 +17,8 @@ enum OutputType { html markdown json + ansi // text with ANSI color escapes plaintext - stdout } @[heap] @@ -36,28 +36,6 @@ mut: example_oks int // how many ok examples were found when `-run-examples` was passed, that compiled and finished with 0 exit code. } -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 -} - // struct Output { mut: @@ -279,7 +257,7 @@ fn (mut vd VDoc) generate_docs_from_file() { } if out.path.len == 0 { if cfg.output_type == .unset { - out.typ = .stdout + out.typ = .ansi } else { vd.vprintln('No output path has detected. Using input path instead.') out.path = cfg.input_path @@ -289,7 +267,7 @@ fn (mut vd VDoc) generate_docs_from_file() { ext := os.file_ext(out.path) out.typ = set_output_type_from_str(ext.all_after('.')) } - if cfg.include_readme && out.typ !in [.html, .stdout] { + if cfg.include_readme && out.typ !in [.html, .ansi, .plaintext] { eprintln('vdoc: Including README.md for doc generation is supported on HTML output, or when running directly in the terminal.') exit(1) } @@ -312,7 +290,7 @@ fn (mut vd VDoc) generate_docs_from_file() { comment := doc.DocComment{ text: readme_contents } - if out.typ == .stdout { + if out.typ == .ansi { println(markdown.to_plain(readme_contents)) } else if out.typ == .html && cfg.is_multi { vd.docs << doc.Doc{ @@ -365,7 +343,7 @@ fn (mut vd VDoc) generate_docs_from_file() { exit(1) } vd.vprintln('Rendering docs...') - if out.path.len == 0 || out.path == 'stdout' { + if out.path.len == 0 || out.path == 'stdout' || out.path == '-' { if out.typ == .html { vd.render_static_html(out) } diff --git a/vlib/v/help/common/doc.txt b/vlib/v/help/common/doc.txt index 7683f92b89..bbdf91d613 100644 --- a/vlib/v/help/common/doc.txt +++ b/vlib/v/help/common/doc.txt @@ -11,22 +11,20 @@ Examples: v doc -m -f html vlib/ Generates the documentation of a given MODULE, DIRECTORY, or FILE - and prints or saves them to its desired format. It can generate HTML, JSON, - or Markdown format. + and prints or saves them to its desired format: HTML, JSON, + TEXT, ANSI or Markdown. Options: -all Includes private and public functions/methods/structs/consts/enums. + -color Forces the use of ANSI escape sequences to make the output colorful. + -no-color Forces plain text output, without ANSI colors. + Note: -color is on for -f ansi . -f Specifies the output format to be used. - Available formats are: - md/markdown, json, text, stdout and html/htm + Available formats are: md/markdown, json, text, ansi and html/htm. -h, -help Prints this help text. -m Generate docs for modules listed in that folder. - -o Specifies the output file/folder path where to store the - generated docs. - Set it to "stdout" to print the output instead of saving - the contents to a file. - -color Forces stdout colorize output. - -no-color Forces plain text output, without ANSI colors. + -o The output file/folder path where to store the docs. Use `-o stdout` + or `-o -', to print the output instead of saving it to a file. -readme Include README.md to docs if present. -v Enables verbose logging. For debugging purposes. -no-timestamp Omits the timestamp in the output file. @@ -36,7 +34,18 @@ For HTML mode: webpage directly. -theme-dir The directory for doc theme template -For plain text mode: +The following options are useful for tests, that need stable output. +They will omit generating text that is prone to changes, due to styling, +but that otherwise do not affect the content. + -html-only-contents Produce just the main content of the page, + without theming, styling, CSS and JS tags etc. + -html-no-vhash Omits the version hash. + -html-no-assets Omits the CSS and JS asset tags. + -html-no-right Omits the doc-toc right panel. + -html-no-toc-urls Omits the toc_links panel + -html-no-footer Omits the footer panel. + +For the text and ansi modes: -l Shows the locations of the generated signatures. -comments Includes comments in the output.