From 7bffabbce2a2ad83d21f2fab9f747a4a5da7a551 Mon Sep 17 00:00:00 2001 From: Leo Developer Date: Thu, 19 Aug 2021 09:20:43 +0200 Subject: [PATCH] vdoc: add `-comments` and new comment merger (#11221) --- .../tests/testdata/basic/main.comments.out | 7 ++ cmd/tools/vdoc/tests/testdata/basic/main.out | 6 ++ .../tests/testdata/{project1 => basic}/main.v | 4 +- .../testdata/multiline/main.comments.out | 9 +++ .../vdoc/tests/testdata/multiline/main.out | 5 ++ .../vdoc/tests/testdata/multiline/main.v | 16 ++++ .../tests/testdata/newlines/main.comments.out | 22 ++++++ .../vdoc/tests/testdata/newlines/main.out | 3 + cmd/tools/vdoc/tests/testdata/newlines/main.v | 23 ++++++ .../vdoc/tests/testdata/project1/main.out | 1 - cmd/tools/vdoc/tests/vdoc_file_test.v | 46 ++++++++--- cmd/tools/vdoc/vdoc.v | 22 ++++-- cmd/v/help/doc.txt | 7 +- doc/docs.md | 11 +++ vlib/v/doc/utils.v | 79 +++++++++++++------ 15 files changed, 208 insertions(+), 53 deletions(-) create mode 100644 cmd/tools/vdoc/tests/testdata/basic/main.comments.out create mode 100644 cmd/tools/vdoc/tests/testdata/basic/main.out rename cmd/tools/vdoc/tests/testdata/{project1 => basic}/main.v (73%) create mode 100644 cmd/tools/vdoc/tests/testdata/multiline/main.comments.out create mode 100644 cmd/tools/vdoc/tests/testdata/multiline/main.out create mode 100644 cmd/tools/vdoc/tests/testdata/multiline/main.v create mode 100644 cmd/tools/vdoc/tests/testdata/newlines/main.comments.out create mode 100644 cmd/tools/vdoc/tests/testdata/newlines/main.out create mode 100644 cmd/tools/vdoc/tests/testdata/newlines/main.v delete mode 100644 cmd/tools/vdoc/tests/testdata/project1/main.out diff --git a/cmd/tools/vdoc/tests/testdata/basic/main.comments.out b/cmd/tools/vdoc/tests/testdata/basic/main.comments.out new file mode 100644 index 0000000000..326f0c5d0a --- /dev/null +++ b/cmd/tools/vdoc/tests/testdata/basic/main.comments.out @@ -0,0 +1,7 @@ +module main + +const ( + source_root = 'temp' +) +fn funky() + funky - comment for function below \ No newline at end of file diff --git a/cmd/tools/vdoc/tests/testdata/basic/main.out b/cmd/tools/vdoc/tests/testdata/basic/main.out new file mode 100644 index 0000000000..08fe504b85 --- /dev/null +++ b/cmd/tools/vdoc/tests/testdata/basic/main.out @@ -0,0 +1,6 @@ +module main + +const ( + source_root = 'temp' +) +fn funky() \ No newline at end of file diff --git a/cmd/tools/vdoc/tests/testdata/project1/main.v b/cmd/tools/vdoc/tests/testdata/basic/main.v similarity index 73% rename from cmd/tools/vdoc/tests/testdata/project1/main.v rename to cmd/tools/vdoc/tests/testdata/basic/main.v index 1a1b52796e..9cb66e3498 100644 --- a/cmd/tools/vdoc/tests/testdata/project1/main.v +++ b/cmd/tools/vdoc/tests/testdata/basic/main.v @@ -1,8 +1,8 @@ -const ( +pub const ( source_root = 'temp' ) // funky - comment for function below -fn funky() { +pub fn funky() { println('hi') } diff --git a/cmd/tools/vdoc/tests/testdata/multiline/main.comments.out b/cmd/tools/vdoc/tests/testdata/multiline/main.comments.out new file mode 100644 index 0000000000..793abf1320 --- /dev/null +++ b/cmd/tools/vdoc/tests/testdata/multiline/main.comments.out @@ -0,0 +1,9 @@ +module main + +fn a1() + normal comment +fn a2() + this should be merged into the same line +fn a3() + This should be its own parapgraph, because it ends with a dot. + This should be another paragraph. diff --git a/cmd/tools/vdoc/tests/testdata/multiline/main.out b/cmd/tools/vdoc/tests/testdata/multiline/main.out new file mode 100644 index 0000000000..4a3c36b9f1 --- /dev/null +++ b/cmd/tools/vdoc/tests/testdata/multiline/main.out @@ -0,0 +1,5 @@ +module main + +fn a1() +fn a2() +fn a3() diff --git a/cmd/tools/vdoc/tests/testdata/multiline/main.v b/cmd/tools/vdoc/tests/testdata/multiline/main.v new file mode 100644 index 0000000000..840ca43721 --- /dev/null +++ b/cmd/tools/vdoc/tests/testdata/multiline/main.v @@ -0,0 +1,16 @@ +// normal comment +pub fn a1() { + println('hi') +} + +// this should be merged +// into the same line +pub fn a2() { + println('hi') +} + +// This should be its own parapgraph, because it ends with a dot. +// This should be another paragraph. +pub fn a3() { + println('hi') +} diff --git a/cmd/tools/vdoc/tests/testdata/newlines/main.comments.out b/cmd/tools/vdoc/tests/testdata/newlines/main.comments.out new file mode 100644 index 0000000000..f3ee942970 --- /dev/null +++ b/cmd/tools/vdoc/tests/testdata/newlines/main.comments.out @@ -0,0 +1,22 @@ +module main + +fn funky() + hello + + empty line + newline using a full stop. + ```v + code + ``` + + test + ==== + - foo + - bar + # test + ########### deep test + #a shouldnt have a newline test + + | foo bar | yes | + |-----------|--------| + | working | yup | \ No newline at end of file diff --git a/cmd/tools/vdoc/tests/testdata/newlines/main.out b/cmd/tools/vdoc/tests/testdata/newlines/main.out new file mode 100644 index 0000000000..02bcce98fe --- /dev/null +++ b/cmd/tools/vdoc/tests/testdata/newlines/main.out @@ -0,0 +1,3 @@ +module main + +fn funky() \ No newline at end of file diff --git a/cmd/tools/vdoc/tests/testdata/newlines/main.v b/cmd/tools/vdoc/tests/testdata/newlines/main.v new file mode 100644 index 0000000000..8d2bf90119 --- /dev/null +++ b/cmd/tools/vdoc/tests/testdata/newlines/main.v @@ -0,0 +1,23 @@ +// hello +// +// empty line +// newline using a full stop. +// ```v +// code +// ``` +// +// test +// ==== +// - foo +// - bar +// # test +// ########### deep test +// #a shouldnt have a newline +// test +// +// | foo bar | yes | +// |-----------|--------| +// | working | yup | +pub fn funky() { + println('hi') +} diff --git a/cmd/tools/vdoc/tests/testdata/project1/main.out b/cmd/tools/vdoc/tests/testdata/project1/main.out deleted file mode 100644 index 41b75a2097..0000000000 --- a/cmd/tools/vdoc/tests/testdata/project1/main.out +++ /dev/null @@ -1 +0,0 @@ -vdoc: No documentation found for /v/vmaster/cmd/tools/vdoc/tests/testdata/project1/main.v diff --git a/cmd/tools/vdoc/tests/vdoc_file_test.v b/cmd/tools/vdoc/tests/vdoc_file_test.v index 49a0130389..cfee24bb9a 100644 --- a/cmd/tools/vdoc/tests/vdoc_file_test.v +++ b/cmd/tools/vdoc/tests/vdoc_file_test.v @@ -43,25 +43,45 @@ fn check_path(vexe string, dir string, tests []string) int { expected = clean_line_endings(expected) found := clean_line_endings(res.output) if expected != found { - println(term.red('FAIL')) - println('============') - println('expected:') - println(expected) - println('============') - println('found:') - println(found) - println('============\n') - println('diff:') - println(diff.color_compare_strings(diff_cmd, rand.ulid(), found, expected)) - println('============\n') - nb_fail++ - } else { + print_compare(expected, found) + } + + res_comments := os.execute('$vexe doc -comments $program') + if res_comments.exit_code < 0 { + panic(res_comments.output) + } + mut expected_comments := os.read_file(program.replace('main.v', 'main.comments.out')) or { + panic(err) + } + expected_comments = clean_line_endings(expected_comments) + found_comments := clean_line_endings(res_comments.output) + if expected_comments != found_comments { + print_compare(expected_comments, found_comments) + } + + if expected == found && expected_comments == found_comments { println(term.green('OK')) + } else { + nb_fail++ } } return nb_fail } +fn print_compare(expected string, found string) { + println(term.red('FAIL')) + println('============') + println('expected:') + println(expected) + println('============') + println('found:') + println(found) + println('============\n') + println('diff:') + println(diff.color_compare_strings(diff_cmd, rand.ulid(), found, expected)) + println('============\n') +} + fn clean_line_endings(s string) string { mut res := s.trim_space() res = res.replace(' \n', '\n') diff --git a/cmd/tools/vdoc/vdoc.v b/cmd/tools/vdoc/vdoc.v index f4f0264600..dc74001865 100644 --- a/cmd/tools/vdoc/vdoc.v +++ b/cmd/tools/vdoc/vdoc.v @@ -51,6 +51,7 @@ mut: is_verbose bool include_readme bool include_examples bool = true + include_comments bool // for plaintext inline_assets bool no_timestamp bool output_path string @@ -95,13 +96,15 @@ fn (vd VDoc) gen_plaintext(d doc.Doc) string { } else { pw.writeln('$d.head.content\n') } - comments := if cfg.include_examples { - d.head.merge_comments() - } else { - d.head.merge_comments_without_examples() - } - if comments.trim_space().len > 0 && !cfg.pub_only { - pw.writeln(comments.split_into_lines().map(' ' + it).join('\n')) + if cfg.include_comments { + comments := if cfg.include_examples { + d.head.merge_comments() + } else { + d.head.merge_comments_without_examples() + } + if comments.trim_space().len > 0 { + pw.writeln(comments.split_into_lines().map(' ' + it).join('\n')) + } } vd.write_plaintext_content(d.contents.arr(), mut pw) return pw.str() @@ -116,7 +119,7 @@ fn (vd VDoc) write_plaintext_content(contents []doc.DocNode, mut pw strings.Buil } else { pw.writeln(cn.content) } - if cn.comments.len > 0 && !cfg.pub_only { + if cn.comments.len > 0 && cfg.include_comments { comments := if cfg.include_examples { cn.merge_comments() } else { @@ -414,6 +417,9 @@ fn parse_arguments(args []string) Config { '-l' { cfg.show_loc = true } + '-comments' { + cfg.include_comments = true + } '-m' { cfg.is_multi = true } diff --git a/cmd/v/help/doc.txt b/cmd/v/help/doc.txt index 71f113a61b..afbc3968fd 100644 --- a/cmd/v/help/doc.txt +++ b/cmd/v/help/doc.txt @@ -21,8 +21,8 @@ Options: -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 Force stdout colorize output. - -no-color Force plain text output, without ANSI colors. + -color Forces stdout colorize output. + -no-color Forces plain text output, without ANSI colors. -readme Include README.md to docs if present. -v Enables verbose logging. For debugging purposes. -no-timestamp Omits the timestamp in the output file. @@ -31,4 +31,5 @@ For HTML mode: -inline-assets Embeds the contents of the CSS and JS assets into the webpage directly. For plain text mode: - -l Show the locations of the generated signatures. + -l Shows the locations of the generated signatures. + -comments Includes comments in the output. diff --git a/doc/docs.md b/doc/docs.md index 033fa7a0b4..41837dd763 100644 --- a/doc/docs.md +++ b/doc/docs.md @@ -4111,6 +4111,17 @@ An overview of the module must be placed in the first comment right after the mo To generate documentation use vdoc, for example `v doc net.http`. +### Newlines in Documentation Comments + +Comments spanning multiple lines are merged together using spaces, unless + +- the line is empty +- the line ends with a `.` (end of sentence) +- the line is contains purely of at least 3 of `-`, `=`, `_`, `*`, `~` (horizontal rule) +- the line starts with at least one `#` followed by a space (header) +- the line starts and ends with a `|` (table) +- the line starts with `- ` (list) + ## Tools ### v fmt diff --git a/vlib/v/doc/utils.v b/vlib/v/doc/utils.v index ee74113853..3fb3973ff0 100644 --- a/vlib/v/doc/utils.v +++ b/vlib/v/doc/utils.v @@ -43,44 +43,71 @@ pub fn merge_doc_comments(comments []DocComment) string { if comments.len == 0 { return '' } - mut comment := '' + mut commentlines := []string{} mut last_comment_line_nr := 0 for i := comments.len - 1; i >= 0; i-- { cmt := comments[i] - if last_comment_line_nr != 0 && cmt.pos.line_nr + 1 < last_comment_line_nr - 1 { + if (!cmt.is_multi && last_comment_line_nr != 0 + && cmt.pos.line_nr + 1 < last_comment_line_nr - 1) || (cmt.is_multi + && cmt.pos.line_nr + cmt.text.count('\n') + 1 < last_comment_line_nr - 1) { // skip comments that are not part of a continuous block, // located right above the top level statement. - // break + break } mut cmt_content := cmt.text.trim_left('\x01') if cmt.is_multi { - // ignore /* */ style comments for now + // /**/ comments are deliberately NOT supported as vdoc comments, + // so just ignore them: continue - // if cmt_content.len == 0 { - // continue - // } - // mut new_cmt_content := '' - // mut is_codeblock := false - // // println(cmt_content) - // lines := cmt_content.split_into_lines() - // for j, line in lines { - // trimmed := line.trim_space().trim_left(cmt_prefix) - // if trimmed.starts_with('- ') || (trimmed.len >= 2 && trimmed[0].is_digit() && trimmed[1] == `.`) || is_codeblock { - // new_cmt_content += line + '\n' - // } else if line.starts_with('```') { - // is_codeblock = !is_codeblock - // new_cmt_content += line + '\n' - // } else { - // new_cmt_content += trimmed + '\n' - // } - // } - // return new_cmt_content + } else { + if cmt_content.starts_with(' ') { + cmt_content = cmt_content[1..] + } + commentlines << cmt_content } - // eprintln('cmt: $cmt') - cseparator := if cmt_content.starts_with('```') { '\n' } else { ' ' } - comment = cmt_content + cseparator + comment last_comment_line_nr = cmt.pos.line_nr + 1 } + commentlines = commentlines.reverse() + mut is_codeblock := false + mut previously_newline := true + mut comment := '' + for line in commentlines { + if line.starts_with('```') { + is_codeblock = !is_codeblock + comment = comment + '\n' + line + continue + } else if is_codeblock { + comment = comment + '\n' + line + continue + } + + line_trimmed := line.trim(' ') + + mut is_horizontalrule := false + line_no_spaces := line_trimmed.replace(' ', '') + for char in ['-', '=', '*', '_', '~'] { + if line_no_spaces.starts_with(char.repeat(3)) + && line_no_spaces.count(char) == line_no_spaces.len { + is_horizontalrule = true + break + } + } + + if line_trimmed == '' || is_horizontalrule + || (line.starts_with('#') && line.before(' ').count('#') == line.before(' ').len) + || (line_trimmed.starts_with('|') && line_trimmed.ends_with('|')) + || line_trimmed.starts_with('- ') { + comment = comment + '\n' + line + previously_newline = true + } else if line.ends_with('.') { + comment = comment + '\n' + line + ' ' + previously_newline = true + } else { + sep := if previously_newline { '\n' } else { ' ' } + comment = comment + sep + line + previously_newline = false + } + } return comment }