v doc: implement color highlighting for the stdout format, enable it by default (#9312)
parent
2d2e4610e7
commit
26138f98af
|
@ -2,6 +2,12 @@ module main
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import v.doc
|
import v.doc
|
||||||
|
import term
|
||||||
|
import v.table
|
||||||
|
import v.scanner
|
||||||
|
import v.token
|
||||||
|
import strings
|
||||||
|
import v.pref
|
||||||
|
|
||||||
[inline]
|
[inline]
|
||||||
fn slug(title string) string {
|
fn slug(title string) string {
|
||||||
|
@ -130,3 +136,106 @@ fn gen_footer_text(d &doc.Doc, include_timestamp bool) string {
|
||||||
time_str := '$generated_time.day $generated_time.smonth() $generated_time.year $generated_time.hhmmss()'
|
time_str := '$generated_time.day $generated_time.smonth() $generated_time.year $generated_time.hhmmss()'
|
||||||
return '$footer_text Generated on: $time_str'
|
return '$footer_text Generated on: $time_str'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn color_highlight(code string, tb &table.Table) string {
|
||||||
|
builtin := ['bool', 'string', 'i8', 'i16', 'int', 'i64', 'i128', 'byte', 'u16', 'u32', 'u64',
|
||||||
|
'u128', 'rune', 'f32', 'f64', 'int_literal', 'float_literal', 'byteptr', 'voidptr', 'any']
|
||||||
|
highlight_code := fn (tok token.Token, typ HighlightTokenTyp) string {
|
||||||
|
lit := match typ {
|
||||||
|
.unone, .operator, .punctuation {
|
||||||
|
tok.kind.str()
|
||||||
|
}
|
||||||
|
.string {
|
||||||
|
term.yellow("'$tok.lit'")
|
||||||
|
}
|
||||||
|
.char {
|
||||||
|
term.yellow('`$tok.lit`')
|
||||||
|
}
|
||||||
|
.keyword {
|
||||||
|
term.blue(tok.lit)
|
||||||
|
}
|
||||||
|
.builtin, .symbol {
|
||||||
|
term.green(tok.lit)
|
||||||
|
}
|
||||||
|
.function {
|
||||||
|
term.cyan(tok.lit)
|
||||||
|
}
|
||||||
|
.number {
|
||||||
|
term.bright_blue(tok.lit)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tok.lit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lit
|
||||||
|
}
|
||||||
|
mut s := scanner.new_scanner(code, .parse_comments, &pref.Preferences{})
|
||||||
|
mut prev := token.Token{}
|
||||||
|
mut tok := s.scan()
|
||||||
|
mut next_tok := s.scan()
|
||||||
|
mut buf := strings.new_builder(200)
|
||||||
|
mut i := 0
|
||||||
|
for i < code.len {
|
||||||
|
if i == tok.pos {
|
||||||
|
mut tok_typ := HighlightTokenTyp.unone
|
||||||
|
match tok.kind {
|
||||||
|
.name {
|
||||||
|
if (tok.lit in builtin || tb.known_type(tok.lit))
|
||||||
|
&& (next_tok.kind != .lpar || prev.kind != .key_fn) {
|
||||||
|
tok_typ = .builtin
|
||||||
|
} else if next_tok.kind in [.lcbr, .rpar, .eof]
|
||||||
|
&& (next_tok.kind != .rpar || prev.kind in [.name, .amp]) {
|
||||||
|
tok_typ = .symbol
|
||||||
|
} else if next_tok.kind in [.lpar, .lt] {
|
||||||
|
tok_typ = .function
|
||||||
|
} else {
|
||||||
|
tok_typ = .name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.comment {
|
||||||
|
tok_typ = .comment
|
||||||
|
}
|
||||||
|
.chartoken {
|
||||||
|
tok_typ = .char
|
||||||
|
}
|
||||||
|
.string {
|
||||||
|
tok_typ = .string
|
||||||
|
}
|
||||||
|
.number {
|
||||||
|
tok_typ = .number
|
||||||
|
}
|
||||||
|
.key_true, .key_false {
|
||||||
|
tok_typ = .boolean
|
||||||
|
}
|
||||||
|
.lpar, .lcbr, .rpar, .rcbr, .lsbr, .rsbr, .semicolon, .colon, .comma, .dot {
|
||||||
|
tok_typ = .punctuation
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if token.is_key(tok.lit) || token.is_decl(tok.kind) {
|
||||||
|
tok_typ = .keyword
|
||||||
|
} else if tok.kind == .decl_assign || tok.kind.is_assign() || tok.is_unary()
|
||||||
|
|| tok.kind.is_relational() || tok.kind.is_infix() {
|
||||||
|
tok_typ = .operator
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf.write_string(highlight_code(tok, tok_typ))
|
||||||
|
if prev.kind != .eof {
|
||||||
|
prev = tok
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if next_tok.kind != .eof {
|
||||||
|
i = tok.pos + tok.len
|
||||||
|
tok = next_tok
|
||||||
|
next_tok = s.scan()
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
buf.write_b(code[i])
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf.str()
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import v.doc
|
||||||
import v.pref
|
import v.pref
|
||||||
import v.vmod
|
import v.vmod
|
||||||
import json
|
import json
|
||||||
|
import term
|
||||||
|
|
||||||
const (
|
const (
|
||||||
allowed_formats = ['md', 'markdown', 'json', 'text', 'stdout', 'html', 'htm']
|
allowed_formats = ['md', 'markdown', 'json', 'text', 'stdout', 'html', 'htm']
|
||||||
|
@ -44,6 +45,7 @@ struct Config {
|
||||||
mut:
|
mut:
|
||||||
pub_only bool = true
|
pub_only bool = true
|
||||||
show_loc bool // for plaintext
|
show_loc bool // for plaintext
|
||||||
|
is_color bool
|
||||||
is_multi bool
|
is_multi bool
|
||||||
is_vlib bool
|
is_vlib bool
|
||||||
is_verbose bool
|
is_verbose bool
|
||||||
|
@ -86,7 +88,12 @@ fn (vd VDoc) gen_json(d doc.Doc) string {
|
||||||
fn (vd VDoc) gen_plaintext(d doc.Doc) string {
|
fn (vd VDoc) gen_plaintext(d doc.Doc) string {
|
||||||
cfg := vd.cfg
|
cfg := vd.cfg
|
||||||
mut pw := strings.new_builder(200)
|
mut pw := strings.new_builder(200)
|
||||||
pw.writeln('$d.head.content\n')
|
if cfg.is_color {
|
||||||
|
content_arr := d.head.content.split(' ')
|
||||||
|
pw.writeln('${term.blue(content_arr[0])} ${term.green(content_arr[1])}\n')
|
||||||
|
} else {
|
||||||
|
pw.writeln('$d.head.content\n')
|
||||||
|
}
|
||||||
comments := if cfg.include_examples {
|
comments := if cfg.include_examples {
|
||||||
d.head.merge_comments()
|
d.head.merge_comments()
|
||||||
} else {
|
} else {
|
||||||
|
@ -103,7 +110,11 @@ fn (vd VDoc) write_plaintext_content(contents []doc.DocNode, mut pw strings.Buil
|
||||||
cfg := vd.cfg
|
cfg := vd.cfg
|
||||||
for cn in contents {
|
for cn in contents {
|
||||||
if cn.content.len > 0 {
|
if cn.content.len > 0 {
|
||||||
pw.writeln(cn.content)
|
if cfg.is_color {
|
||||||
|
pw.writeln(color_highlight(cn.content, vd.docs[0].table))
|
||||||
|
} else {
|
||||||
|
pw.writeln(cn.content)
|
||||||
|
}
|
||||||
if cn.comments.len > 0 && !cfg.pub_only {
|
if cn.comments.len > 0 && !cfg.pub_only {
|
||||||
comments := if cfg.include_examples {
|
comments := if cfg.include_examples {
|
||||||
cn.merge_comments()
|
cn.merge_comments()
|
||||||
|
@ -369,6 +380,7 @@ fn (vd VDoc) vprintln(str string) {
|
||||||
|
|
||||||
fn parse_arguments(args []string) Config {
|
fn parse_arguments(args []string) Config {
|
||||||
mut cfg := Config{}
|
mut cfg := Config{}
|
||||||
|
cfg.is_color = term.can_show_color_on_stdout()
|
||||||
for i := 0; i < args.len; i++ {
|
for i := 0; i < args.len; i++ {
|
||||||
arg := args[i]
|
arg := args[i]
|
||||||
current_args := args[i..]
|
current_args := args[i..]
|
||||||
|
@ -386,6 +398,12 @@ fn parse_arguments(args []string) Config {
|
||||||
cfg.output_type = set_output_type_from_str(format)
|
cfg.output_type = set_output_type_from_str(format)
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
'-color' {
|
||||||
|
cfg.is_color = true
|
||||||
|
}
|
||||||
|
'-no-color' {
|
||||||
|
cfg.is_color = false
|
||||||
|
}
|
||||||
'-inline-assets' {
|
'-inline-assets' {
|
||||||
cfg.inline_assets = true
|
cfg.inline_assets = true
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ Usage:
|
||||||
Examples:
|
Examples:
|
||||||
v doc os
|
v doc os
|
||||||
v doc os File
|
v doc os File
|
||||||
|
v doc -no-color os
|
||||||
v doc -o math.html math
|
v doc -o math.html math
|
||||||
v doc -m -f html vlib/
|
v doc -m -f html vlib/
|
||||||
|
|
||||||
|
@ -20,6 +21,8 @@ Options:
|
||||||
-o Specifies the output file/folder path where to store the generated docs.
|
-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
|
Set it to "stdout" to print the output instead of saving the contents
|
||||||
to a file.
|
to a file.
|
||||||
|
-color Force stdout colorize output.
|
||||||
|
-no-color Force plain text output, without ANSI colors.
|
||||||
-readme Include README.md to docs if present.
|
-readme Include README.md to docs if present.
|
||||||
-v Enables verbose logging. For debugging purposes.
|
-v Enables verbose logging. For debugging purposes.
|
||||||
-no-timestamp Omits the timestamp in the output file.
|
-no-timestamp Omits the timestamp in the output file.
|
||||||
|
|
Loading…
Reference in New Issue