v.doc: parse multi-line examples (so they get highlighted) (#13894)

pull/13911/head
Nick Treleaven 2022-04-02 16:29:12 +01:00 committed by GitHub
parent faa55b46de
commit 42f92db0ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 63 additions and 11 deletions

View File

@ -175,7 +175,7 @@ pub struct WindowAttribute {
// - `size` - snapshot size // - `size` - snapshot size
// - `step` - gap size between each snapshot, default is 1. // - `step` - gap size between each snapshot, default is 1.
// //
// Example: arrays.window([1, 2, 3, 4], size: 2) => [[1, 2], [2, 3], [3, 4]] // Example: arrays.window([1, 2, 3, 4], size: 2) // => [[1, 2], [2, 3], [3, 4]]
// Example: arrays.window([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], size: 3, step: 2) // => [[1, 2, 3], [3, 4, 5], [5, 6, 7], [7, 8, 9]] // Example: arrays.window([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], size: 3, step: 2) // => [[1, 2, 3], [3, 4, 5], [5, 6, 7], [7, 8, 9]]
pub fn window<T>(list []T, attr WindowAttribute) [][]T { pub fn window<T>(list []T, attr WindowAttribute) [][]T {
// allocate snapshot array // allocate snapshot array

View File

@ -555,7 +555,6 @@ pub fn (s string) u64() u64 {
// This method directly exposes the `parse_uint` function from `strconv` // This method directly exposes the `parse_uint` function from `strconv`
// as a method on `string`. For more advanced features, // as a method on `string`. For more advanced features,
// consider calling `strconv.common_parse_uint` directly. // consider calling `strconv.common_parse_uint` directly.
// Example:
pub fn (s string) parse_uint(_base int, _bit_size int) ?u64 { pub fn (s string) parse_uint(_base int, _bit_size int) ?u64 {
return strconv.parse_uint(s, _base, _bit_size) return strconv.parse_uint(s, _base, _bit_size)
} }
@ -1823,13 +1822,15 @@ pub fn (s string) fields() []string {
// the value in ``. // the value in ``.
// //
// Example: // Example:
// ```v
// st := 'Hello there, // st := 'Hello there,
// |this is a string, // |this is a string,
// | Everything before the first | is removed'.strip_margin() // | Everything before the first | is removed'.strip_margin()
// Returns: //
// Hello there, // assert st == 'Hello there,
// this is a string, // this is a string,
// Everything before the first | is removed // Everything before the first | is removed'
// ```
pub fn (s string) strip_margin() string { pub fn (s string) strip_margin() string {
return s.strip_margin_custom(`|`) return s.strip_margin_custom(`|`)
} }

View File

@ -13,13 +13,23 @@ pub mut:
pos token.Pos pos token.Pos
} }
// is_example returns true if the contents of this comment is a doc example. // is_example returns true if the contents of this comment is an inline doc example.
// The current convention is '// Example: <content>' // The current convention is '// Example: <content>'
pub fn (dc DocComment) is_example() bool { pub fn (dc DocComment) is_example() bool {
return dc.text.starts_with(doc.example_pattern) return dc.text.trim_space().starts_with(doc.example_pattern)
} }
// example returns the content of the example body // example returns the content of the inline example body
pub fn (dc DocComment) example() string { pub fn (dc DocComment) example() string {
return dc.text.all_after(doc.example_pattern) return dc.text.all_after(doc.example_pattern)
} }
// is_multi_line_example returns true if an example line has no inline code
pub fn (dc DocComment) is_multi_line_example() bool {
return dc.text.trim_space() == '\x01 Example:'
}
// has_triple_backtick returns true if the comment starts or ends a markdown code block
pub fn (dc DocComment) has_triple_backtick() bool {
return dc.text.starts_with('\x01 ```')
}

View File

@ -54,16 +54,57 @@ pub fn (dc DocNode) merge_comments() string {
// merge_comments_without_examples returns a `string` with the // merge_comments_without_examples returns a `string` with the
// combined contents of `DocNode.comments` - excluding any examples. // combined contents of `DocNode.comments` - excluding any examples.
pub fn (dc DocNode) merge_comments_without_examples() string { pub fn (dc DocNode) merge_comments_without_examples() string {
sans_examples := dc.comments.filter(!it.is_example()) mut sans_examples := []DocComment{cap: dc.comments.len}
for i := 0; i < dc.comments.len; i++ {
if dc.comments[i].is_example() {
continue
}
if dc.comments[i].is_multi_line_example() {
i++
if i == dc.comments.len || !dc.comments[i].has_triple_backtick() {
eprintln('$dc.file_path:$dc.pos.line_nr: Expected code block after empty example line:')
eprintln('// ```')
if i < dc.comments.len {
eprintln('Found:')
eprintln('//' + dc.comments[i].text[1..])
}
exit(1)
}
i++
for i < dc.comments.len && !dc.comments[i].has_triple_backtick() {
i++
}
} else {
sans_examples << dc.comments[i]
}
}
return merge_doc_comments(sans_examples) return merge_doc_comments(sans_examples)
} }
// examples returns a `[]string` containing examples parsed from `DocNode.comments`. // examples returns a `[]string` containing examples parsed from `DocNode.comments`.
pub fn (dn DocNode) examples() []string { pub fn (dn DocNode) examples() []string {
mut output := []string{} mut output := []string{}
for comment in dn.comments { for i := 0; i < dn.comments.len; i++ {
comment := dn.comments[i]
if comment.is_example() { if comment.is_example() {
output << comment.example() output << comment.example()
} else if comment.is_multi_line_example() {
i++
if i + 2 < dn.comments.len && dn.comments[i].has_triple_backtick() {
i++
mut ml_ex := ''
for i < dn.comments.len && !dn.comments[i].has_triple_backtick() {
if ml_ex.len > 0 {
ml_ex += '\n'
}
s := dn.comments[i].text
if s.len > 2 {
ml_ex += s[2..]
}
i++
}
output << ml_ex
}
} }
} }
return output return output